diff options
author | David S. Miller <davem@davemloft.net> | 2009-03-01 01:32:16 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-03-01 01:32:16 -0500 |
commit | 8010dc306ba39a8cdb3993d1e809fcb7dfdf089a (patch) | |
tree | d1fa3fe2e1501a6780fc007f2f57b1fe0995e18e | |
parent | 5d242f1cee2c85721bbe9d8205e98c1c01f5d805 (diff) | |
parent | 2a07954b83a3d4dc93031d3ce030fb9380a8e15a (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6
126 files changed, 8007 insertions, 4142 deletions
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index fe819a785714..1294175cab20 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig | |||
@@ -228,6 +228,14 @@ config PCMCIA_ATMEL | |||
228 | Enable support for PCMCIA cards containing the | 228 | Enable support for PCMCIA cards containing the |
229 | Atmel at76c502 and at76c504 chips. | 229 | Atmel at76c502 and at76c504 chips. |
230 | 230 | ||
231 | config AT76C50X_USB | ||
232 | tristate "Atmel at76c503/at76c505/at76c505a USB cards" | ||
233 | depends on MAC80211 && WLAN_80211 && USB | ||
234 | select FW_LOADER | ||
235 | ---help--- | ||
236 | Enable support for USB Wireless devices using Atmel at76c503, | ||
237 | at76c505 or at76c505a chips. | ||
238 | |||
231 | config AIRO_CS | 239 | config AIRO_CS |
232 | tristate "Cisco/Aironet 34X/35X/4500/4800 PCMCIA cards" | 240 | tristate "Cisco/Aironet 34X/35X/4500/4800 PCMCIA cards" |
233 | depends on PCMCIA && (BROKEN || !M32R) && WLAN_80211 | 241 | depends on PCMCIA && (BROKEN || !M32R) && WLAN_80211 |
diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile index ac590e1ca8be..e2574cafe051 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile | |||
@@ -24,6 +24,8 @@ obj-$(CONFIG_ATMEL) += atmel.o | |||
24 | obj-$(CONFIG_PCI_ATMEL) += atmel_pci.o | 24 | obj-$(CONFIG_PCI_ATMEL) += atmel_pci.o |
25 | obj-$(CONFIG_PCMCIA_ATMEL) += atmel_cs.o | 25 | obj-$(CONFIG_PCMCIA_ATMEL) += atmel_cs.o |
26 | 26 | ||
27 | obj-$(CONFIG_AT76C50X_USB) += at76c50x-usb.o | ||
28 | |||
27 | obj-$(CONFIG_PRISM54) += prism54/ | 29 | obj-$(CONFIG_PRISM54) += prism54/ |
28 | 30 | ||
29 | obj-$(CONFIG_HOSTAP) += hostap/ | 31 | obj-$(CONFIG_HOSTAP) += hostap/ |
diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index c44f38895fbe..a3e324e0ca83 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c | |||
@@ -4727,7 +4727,7 @@ static int proc_stats_rid_open( struct inode *inode, | |||
4727 | StatsRid stats; | 4727 | StatsRid stats; |
4728 | int i, j; | 4728 | int i, j; |
4729 | __le32 *vals = stats.vals; | 4729 | __le32 *vals = stats.vals; |
4730 | int len = le16_to_cpu(stats.len); | 4730 | int len; |
4731 | 4731 | ||
4732 | if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL) | 4732 | if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL) |
4733 | return -ENOMEM; | 4733 | return -ENOMEM; |
@@ -4738,6 +4738,7 @@ static int proc_stats_rid_open( struct inode *inode, | |||
4738 | } | 4738 | } |
4739 | 4739 | ||
4740 | readStatsRid(apriv, &stats, rid, 1); | 4740 | readStatsRid(apriv, &stats, rid, 1); |
4741 | len = le16_to_cpu(stats.len); | ||
4741 | 4742 | ||
4742 | j = 0; | 4743 | j = 0; |
4743 | for(i=0; statsLabels[i]!=(char *)-1 && i*4<len; i++) { | 4744 | for(i=0; statsLabels[i]!=(char *)-1 && i*4<len; i++) { |
diff --git a/drivers/net/wireless/at76c50x-usb.c b/drivers/net/wireless/at76c50x-usb.c new file mode 100644 index 000000000000..0c02f1c2bd94 --- /dev/null +++ b/drivers/net/wireless/at76c50x-usb.c | |||
@@ -0,0 +1,2501 @@ | |||
1 | /* | ||
2 | * at76c503/at76c505 USB driver | ||
3 | * | ||
4 | * Copyright (c) 2002 - 2003 Oliver Kurth | ||
5 | * Copyright (c) 2004 Joerg Albert <joerg.albert@gmx.de> | ||
6 | * Copyright (c) 2004 Nick Jones | ||
7 | * Copyright (c) 2004 Balint Seeber <n0_5p4m_p13453@hotmail.com> | ||
8 | * Copyright (c) 2007 Guido Guenther <agx@sigxcpu.org> | ||
9 | * Copyright (c) 2007 Kalle Valo <kalle.valo@iki.fi> | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or | ||
12 | * modify it under the terms of the GNU General Public License as | ||
13 | * published by the Free Software Foundation; either version 2 of | ||
14 | * the License, or (at your option) any later version. | ||
15 | * | ||
16 | * This file is part of the Berlios driver for WLAN USB devices based on the | ||
17 | * Atmel AT76C503A/505/505A. | ||
18 | * | ||
19 | * Some iw_handler code was taken from airo.c, (C) 1999 Benjamin Reed | ||
20 | * | ||
21 | * TODO list is at the wiki: | ||
22 | * | ||
23 | * http://wireless.kernel.org/en/users/Drivers/at76c50x-usb#TODO | ||
24 | * | ||
25 | */ | ||
26 | |||
27 | #include <linux/init.h> | ||
28 | #include <linux/kernel.h> | ||
29 | #include <linux/sched.h> | ||
30 | #include <linux/errno.h> | ||
31 | #include <linux/slab.h> | ||
32 | #include <linux/module.h> | ||
33 | #include <linux/spinlock.h> | ||
34 | #include <linux/list.h> | ||
35 | #include <linux/usb.h> | ||
36 | #include <linux/netdevice.h> | ||
37 | #include <linux/if_arp.h> | ||
38 | #include <linux/etherdevice.h> | ||
39 | #include <linux/ethtool.h> | ||
40 | #include <linux/wireless.h> | ||
41 | #include <net/iw_handler.h> | ||
42 | #include <net/ieee80211_radiotap.h> | ||
43 | #include <linux/firmware.h> | ||
44 | #include <linux/leds.h> | ||
45 | #include <net/mac80211.h> | ||
46 | |||
47 | #include "at76c50x-usb.h" | ||
48 | |||
49 | /* Version information */ | ||
50 | #define DRIVER_NAME "at76c50x-usb" | ||
51 | #define DRIVER_VERSION "0.17" | ||
52 | #define DRIVER_DESC "Atmel at76x USB Wireless LAN Driver" | ||
53 | |||
54 | /* at76_debug bits */ | ||
55 | #define DBG_PROGRESS 0x00000001 /* authentication/accociation */ | ||
56 | #define DBG_BSS_TABLE 0x00000002 /* show BSS table after scans */ | ||
57 | #define DBG_IOCTL 0x00000004 /* ioctl calls / settings */ | ||
58 | #define DBG_MAC_STATE 0x00000008 /* MAC state transitions */ | ||
59 | #define DBG_TX_DATA 0x00000010 /* tx header */ | ||
60 | #define DBG_TX_DATA_CONTENT 0x00000020 /* tx content */ | ||
61 | #define DBG_TX_MGMT 0x00000040 /* tx management */ | ||
62 | #define DBG_RX_DATA 0x00000080 /* rx data header */ | ||
63 | #define DBG_RX_DATA_CONTENT 0x00000100 /* rx data content */ | ||
64 | #define DBG_RX_MGMT 0x00000200 /* rx mgmt frame headers */ | ||
65 | #define DBG_RX_BEACON 0x00000400 /* rx beacon */ | ||
66 | #define DBG_RX_CTRL 0x00000800 /* rx control */ | ||
67 | #define DBG_RX_MGMT_CONTENT 0x00001000 /* rx mgmt content */ | ||
68 | #define DBG_RX_FRAGS 0x00002000 /* rx data fragment handling */ | ||
69 | #define DBG_DEVSTART 0x00004000 /* fw download, device start */ | ||
70 | #define DBG_URB 0x00008000 /* rx urb status, ... */ | ||
71 | #define DBG_RX_ATMEL_HDR 0x00010000 /* Atmel-specific Rx headers */ | ||
72 | #define DBG_PROC_ENTRY 0x00020000 /* procedure entries/exits */ | ||
73 | #define DBG_PM 0x00040000 /* power management settings */ | ||
74 | #define DBG_BSS_MATCH 0x00080000 /* BSS match failures */ | ||
75 | #define DBG_PARAMS 0x00100000 /* show configured parameters */ | ||
76 | #define DBG_WAIT_COMPLETE 0x00200000 /* command completion */ | ||
77 | #define DBG_RX_FRAGS_SKB 0x00400000 /* skb header of Rx fragments */ | ||
78 | #define DBG_BSS_TABLE_RM 0x00800000 /* purging bss table entries */ | ||
79 | #define DBG_MONITOR_MODE 0x01000000 /* monitor mode */ | ||
80 | #define DBG_MIB 0x02000000 /* dump all MIBs on startup */ | ||
81 | #define DBG_MGMT_TIMER 0x04000000 /* dump mgmt_timer ops */ | ||
82 | #define DBG_WE_EVENTS 0x08000000 /* dump wireless events */ | ||
83 | #define DBG_FW 0x10000000 /* firmware download */ | ||
84 | #define DBG_DFU 0x20000000 /* device firmware upgrade */ | ||
85 | #define DBG_CMD 0x40000000 | ||
86 | #define DBG_MAC80211 0x80000000 | ||
87 | |||
88 | #define DBG_DEFAULTS 0 | ||
89 | |||
90 | /* Use our own dbg macro */ | ||
91 | #define at76_dbg(bits, format, arg...) \ | ||
92 | do { \ | ||
93 | if (at76_debug & (bits)) \ | ||
94 | printk(KERN_DEBUG DRIVER_NAME ": " format "\n" , \ | ||
95 | ## arg); \ | ||
96 | } while (0) | ||
97 | |||
98 | #define at76_dbg_dump(bits, buf, len, format, arg...) \ | ||
99 | do { \ | ||
100 | if (at76_debug & (bits)) { \ | ||
101 | printk(KERN_DEBUG DRIVER_NAME ": " format "\n" , \ | ||
102 | ## arg); \ | ||
103 | print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, \ | ||
104 | buf, len); \ | ||
105 | } \ | ||
106 | } while (0) | ||
107 | |||
108 | static uint at76_debug = DBG_DEFAULTS; | ||
109 | |||
110 | /* Protect against concurrent firmware loading and parsing */ | ||
111 | static struct mutex fw_mutex; | ||
112 | |||
113 | static struct fwentry firmwares[] = { | ||
114 | [0] = { "" }, | ||
115 | [BOARD_503_ISL3861] = { "atmel_at76c503-i3861.bin" }, | ||
116 | [BOARD_503_ISL3863] = { "atmel_at76c503-i3863.bin" }, | ||
117 | [BOARD_503] = { "atmel_at76c503-rfmd.bin" }, | ||
118 | [BOARD_503_ACC] = { "atmel_at76c503-rfmd-acc.bin" }, | ||
119 | [BOARD_505] = { "atmel_at76c505-rfmd.bin" }, | ||
120 | [BOARD_505_2958] = { "atmel_at76c505-rfmd2958.bin" }, | ||
121 | [BOARD_505A] = { "atmel_at76c505a-rfmd2958.bin" }, | ||
122 | [BOARD_505AMX] = { "atmel_at76c505amx-rfmd.bin" }, | ||
123 | }; | ||
124 | |||
125 | #define USB_DEVICE_DATA(__ops) .driver_info = (kernel_ulong_t)(__ops) | ||
126 | |||
127 | static struct usb_device_id dev_table[] = { | ||
128 | /* | ||
129 | * at76c503-i3861 | ||
130 | */ | ||
131 | /* Generic AT76C503/3861 device */ | ||
132 | { USB_DEVICE(0x03eb, 0x7603), USB_DEVICE_DATA(BOARD_503_ISL3861) }, | ||
133 | /* Linksys WUSB11 v2.1/v2.6 */ | ||
134 | { USB_DEVICE(0x066b, 0x2211), USB_DEVICE_DATA(BOARD_503_ISL3861) }, | ||
135 | /* Netgear MA101 rev. A */ | ||
136 | { USB_DEVICE(0x0864, 0x4100), USB_DEVICE_DATA(BOARD_503_ISL3861) }, | ||
137 | /* Tekram U300C / Allnet ALL0193 */ | ||
138 | { USB_DEVICE(0x0b3b, 0x1612), USB_DEVICE_DATA(BOARD_503_ISL3861) }, | ||
139 | /* HP HN210W J7801A */ | ||
140 | { USB_DEVICE(0x03f0, 0x011c), USB_DEVICE_DATA(BOARD_503_ISL3861) }, | ||
141 | /* Sitecom/Z-Com/Zyxel M4Y-750 */ | ||
142 | { USB_DEVICE(0x0cde, 0x0001), USB_DEVICE_DATA(BOARD_503_ISL3861) }, | ||
143 | /* Dynalink/Askey WLL013 (intersil) */ | ||
144 | { USB_DEVICE(0x069a, 0x0320), USB_DEVICE_DATA(BOARD_503_ISL3861) }, | ||
145 | /* EZ connect 11Mpbs Wireless USB Adapter SMC2662W v1 */ | ||
146 | { USB_DEVICE(0x0d5c, 0xa001), USB_DEVICE_DATA(BOARD_503_ISL3861) }, | ||
147 | /* BenQ AWL300 */ | ||
148 | { USB_DEVICE(0x04a5, 0x9000), USB_DEVICE_DATA(BOARD_503_ISL3861) }, | ||
149 | /* Addtron AWU-120, Compex WLU11 */ | ||
150 | { USB_DEVICE(0x05dd, 0xff31), USB_DEVICE_DATA(BOARD_503_ISL3861) }, | ||
151 | /* Intel AP310 AnyPoint II USB */ | ||
152 | { USB_DEVICE(0x8086, 0x0200), USB_DEVICE_DATA(BOARD_503_ISL3861) }, | ||
153 | /* Dynalink L11U */ | ||
154 | { USB_DEVICE(0x0d8e, 0x7100), USB_DEVICE_DATA(BOARD_503_ISL3861) }, | ||
155 | /* Arescom WL-210, FCC id 07J-GL2411USB */ | ||
156 | { USB_DEVICE(0x0d8e, 0x7110), USB_DEVICE_DATA(BOARD_503_ISL3861) }, | ||
157 | /* I-O DATA WN-B11/USB */ | ||
158 | { USB_DEVICE(0x04bb, 0x0919), USB_DEVICE_DATA(BOARD_503_ISL3861) }, | ||
159 | /* BT Voyager 1010 */ | ||
160 | { USB_DEVICE(0x069a, 0x0821), USB_DEVICE_DATA(BOARD_503_ISL3861) }, | ||
161 | /* | ||
162 | * at76c503-i3863 | ||
163 | */ | ||
164 | /* Generic AT76C503/3863 device */ | ||
165 | { USB_DEVICE(0x03eb, 0x7604), USB_DEVICE_DATA(BOARD_503_ISL3863) }, | ||
166 | /* Samsung SWL-2100U */ | ||
167 | { USB_DEVICE(0x055d, 0xa000), USB_DEVICE_DATA(BOARD_503_ISL3863) }, | ||
168 | /* | ||
169 | * at76c503-rfmd | ||
170 | */ | ||
171 | /* Generic AT76C503/RFMD device */ | ||
172 | { USB_DEVICE(0x03eb, 0x7605), USB_DEVICE_DATA(BOARD_503) }, | ||
173 | /* Dynalink/Askey WLL013 (rfmd) */ | ||
174 | { USB_DEVICE(0x069a, 0x0321), USB_DEVICE_DATA(BOARD_503) }, | ||
175 | /* Linksys WUSB11 v2.6 */ | ||
176 | { USB_DEVICE(0x077b, 0x2219), USB_DEVICE_DATA(BOARD_503) }, | ||
177 | /* Network Everywhere NWU11B */ | ||
178 | { USB_DEVICE(0x077b, 0x2227), USB_DEVICE_DATA(BOARD_503) }, | ||
179 | /* Netgear MA101 rev. B */ | ||
180 | { USB_DEVICE(0x0864, 0x4102), USB_DEVICE_DATA(BOARD_503) }, | ||
181 | /* D-Link DWL-120 rev. E */ | ||
182 | { USB_DEVICE(0x2001, 0x3200), USB_DEVICE_DATA(BOARD_503) }, | ||
183 | /* Actiontec 802UAT1, HWU01150-01UK */ | ||
184 | { USB_DEVICE(0x1668, 0x7605), USB_DEVICE_DATA(BOARD_503) }, | ||
185 | /* AirVast W-Buddie WN210 */ | ||
186 | { USB_DEVICE(0x03eb, 0x4102), USB_DEVICE_DATA(BOARD_503) }, | ||
187 | /* Dick Smith Electronics XH1153 802.11b USB adapter */ | ||
188 | { USB_DEVICE(0x1371, 0x5743), USB_DEVICE_DATA(BOARD_503) }, | ||
189 | /* CNet CNUSB611 */ | ||
190 | { USB_DEVICE(0x1371, 0x0001), USB_DEVICE_DATA(BOARD_503) }, | ||
191 | /* FiberLine FL-WL200U */ | ||
192 | { USB_DEVICE(0x1371, 0x0002), USB_DEVICE_DATA(BOARD_503) }, | ||
193 | /* BenQ AWL400 USB stick */ | ||
194 | { USB_DEVICE(0x04a5, 0x9001), USB_DEVICE_DATA(BOARD_503) }, | ||
195 | /* 3Com 3CRSHEW696 */ | ||
196 | { USB_DEVICE(0x0506, 0x0a01), USB_DEVICE_DATA(BOARD_503) }, | ||
197 | /* Siemens Santis ADSL WLAN USB adapter WLL 013 */ | ||
198 | { USB_DEVICE(0x0681, 0x001b), USB_DEVICE_DATA(BOARD_503) }, | ||
199 | /* Belkin F5D6050, version 2 */ | ||
200 | { USB_DEVICE(0x050d, 0x0050), USB_DEVICE_DATA(BOARD_503) }, | ||
201 | /* iBlitzz, BWU613 (not *B or *SB) */ | ||
202 | { USB_DEVICE(0x07b8, 0xb000), USB_DEVICE_DATA(BOARD_503) }, | ||
203 | /* Gigabyte GN-WLBM101 */ | ||
204 | { USB_DEVICE(0x1044, 0x8003), USB_DEVICE_DATA(BOARD_503) }, | ||
205 | /* Planex GW-US11S */ | ||
206 | { USB_DEVICE(0x2019, 0x3220), USB_DEVICE_DATA(BOARD_503) }, | ||
207 | /* Internal WLAN adapter in h5[4,5]xx series iPAQs */ | ||
208 | { USB_DEVICE(0x049f, 0x0032), USB_DEVICE_DATA(BOARD_503) }, | ||
209 | /* Corega Wireless LAN USB-11 mini */ | ||
210 | { USB_DEVICE(0x07aa, 0x0011), USB_DEVICE_DATA(BOARD_503) }, | ||
211 | /* Corega Wireless LAN USB-11 mini2 */ | ||
212 | { USB_DEVICE(0x07aa, 0x0018), USB_DEVICE_DATA(BOARD_503) }, | ||
213 | /* Uniden PCW100 */ | ||
214 | { USB_DEVICE(0x05dd, 0xff35), USB_DEVICE_DATA(BOARD_503) }, | ||
215 | /* | ||
216 | * at76c503-rfmd-acc | ||
217 | */ | ||
218 | /* SMC2664W */ | ||
219 | { USB_DEVICE(0x083a, 0x3501), USB_DEVICE_DATA(BOARD_503_ACC) }, | ||
220 | /* Belkin F5D6050, SMC2662W v2, SMC2662W-AR */ | ||
221 | { USB_DEVICE(0x0d5c, 0xa002), USB_DEVICE_DATA(BOARD_503_ACC) }, | ||
222 | /* | ||
223 | * at76c505-rfmd | ||
224 | */ | ||
225 | /* Generic AT76C505/RFMD */ | ||
226 | { USB_DEVICE(0x03eb, 0x7606), USB_DEVICE_DATA(BOARD_505) }, | ||
227 | /* | ||
228 | * at76c505-rfmd2958 | ||
229 | */ | ||
230 | /* Generic AT76C505/RFMD, OvisLink WL-1130USB */ | ||
231 | { USB_DEVICE(0x03eb, 0x7613), USB_DEVICE_DATA(BOARD_505_2958) }, | ||
232 | /* Fiberline FL-WL240U */ | ||
233 | { USB_DEVICE(0x1371, 0x0014), USB_DEVICE_DATA(BOARD_505_2958) }, | ||
234 | /* CNet CNUSB-611G */ | ||
235 | { USB_DEVICE(0x1371, 0x0013), USB_DEVICE_DATA(BOARD_505_2958) }, | ||
236 | /* Linksys WUSB11 v2.8 */ | ||
237 | { USB_DEVICE(0x1915, 0x2233), USB_DEVICE_DATA(BOARD_505_2958) }, | ||
238 | /* Xterasys XN-2122B, IBlitzz BWU613B/BWU613SB */ | ||
239 | { USB_DEVICE(0x12fd, 0x1001), USB_DEVICE_DATA(BOARD_505_2958) }, | ||
240 | /* Corega WLAN USB Stick 11 */ | ||
241 | { USB_DEVICE(0x07aa, 0x7613), USB_DEVICE_DATA(BOARD_505_2958) }, | ||
242 | /* Microstar MSI Box MS6978 */ | ||
243 | { USB_DEVICE(0x0db0, 0x1020), USB_DEVICE_DATA(BOARD_505_2958) }, | ||
244 | /* | ||
245 | * at76c505a-rfmd2958 | ||
246 | */ | ||
247 | /* Generic AT76C505A device */ | ||
248 | { USB_DEVICE(0x03eb, 0x7614), USB_DEVICE_DATA(BOARD_505A) }, | ||
249 | /* Generic AT76C505AS device */ | ||
250 | { USB_DEVICE(0x03eb, 0x7617), USB_DEVICE_DATA(BOARD_505A) }, | ||
251 | /* Siemens Gigaset USB WLAN Adapter 11 */ | ||
252 | { USB_DEVICE(0x1690, 0x0701), USB_DEVICE_DATA(BOARD_505A) }, | ||
253 | /* | ||
254 | * at76c505amx-rfmd | ||
255 | */ | ||
256 | /* Generic AT76C505AMX device */ | ||
257 | { USB_DEVICE(0x03eb, 0x7615), USB_DEVICE_DATA(BOARD_505AMX) }, | ||
258 | { } | ||
259 | }; | ||
260 | |||
261 | MODULE_DEVICE_TABLE(usb, dev_table); | ||
262 | |||
263 | /* Supported rates of this hardware, bit 7 marks basic rates */ | ||
264 | static const u8 hw_rates[] = { 0x82, 0x84, 0x0b, 0x16 }; | ||
265 | |||
266 | static const char *const preambles[] = { "long", "short", "auto" }; | ||
267 | |||
268 | /* Firmware download */ | ||
269 | /* DFU states */ | ||
270 | #define STATE_IDLE 0x00 | ||
271 | #define STATE_DETACH 0x01 | ||
272 | #define STATE_DFU_IDLE 0x02 | ||
273 | #define STATE_DFU_DOWNLOAD_SYNC 0x03 | ||
274 | #define STATE_DFU_DOWNLOAD_BUSY 0x04 | ||
275 | #define STATE_DFU_DOWNLOAD_IDLE 0x05 | ||
276 | #define STATE_DFU_MANIFEST_SYNC 0x06 | ||
277 | #define STATE_DFU_MANIFEST 0x07 | ||
278 | #define STATE_DFU_MANIFEST_WAIT_RESET 0x08 | ||
279 | #define STATE_DFU_UPLOAD_IDLE 0x09 | ||
280 | #define STATE_DFU_ERROR 0x0a | ||
281 | |||
282 | /* DFU commands */ | ||
283 | #define DFU_DETACH 0 | ||
284 | #define DFU_DNLOAD 1 | ||
285 | #define DFU_UPLOAD 2 | ||
286 | #define DFU_GETSTATUS 3 | ||
287 | #define DFU_CLRSTATUS 4 | ||
288 | #define DFU_GETSTATE 5 | ||
289 | #define DFU_ABORT 6 | ||
290 | |||
291 | #define FW_BLOCK_SIZE 1024 | ||
292 | |||
293 | struct dfu_status { | ||
294 | unsigned char status; | ||
295 | unsigned char poll_timeout[3]; | ||
296 | unsigned char state; | ||
297 | unsigned char string; | ||
298 | } __attribute__((packed)); | ||
299 | |||
300 | static inline int at76_is_intersil(enum board_type board) | ||
301 | { | ||
302 | return (board == BOARD_503_ISL3861 || board == BOARD_503_ISL3863); | ||
303 | } | ||
304 | |||
305 | static inline int at76_is_503rfmd(enum board_type board) | ||
306 | { | ||
307 | return (board == BOARD_503 || board == BOARD_503_ACC); | ||
308 | } | ||
309 | |||
310 | static inline int at76_is_505a(enum board_type board) | ||
311 | { | ||
312 | return (board == BOARD_505A || board == BOARD_505AMX); | ||
313 | } | ||
314 | |||
315 | /* Load a block of the first (internal) part of the firmware */ | ||
316 | static int at76_load_int_fw_block(struct usb_device *udev, int blockno, | ||
317 | void *block, int size) | ||
318 | { | ||
319 | return usb_control_msg(udev, usb_sndctrlpipe(udev, 0), DFU_DNLOAD, | ||
320 | USB_TYPE_CLASS | USB_DIR_OUT | | ||
321 | USB_RECIP_INTERFACE, blockno, 0, block, size, | ||
322 | USB_CTRL_GET_TIMEOUT); | ||
323 | } | ||
324 | |||
325 | static int at76_dfu_get_status(struct usb_device *udev, | ||
326 | struct dfu_status *status) | ||
327 | { | ||
328 | int ret; | ||
329 | |||
330 | ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), DFU_GETSTATUS, | ||
331 | USB_TYPE_CLASS | USB_DIR_IN | USB_RECIP_INTERFACE, | ||
332 | 0, 0, status, sizeof(struct dfu_status), | ||
333 | USB_CTRL_GET_TIMEOUT); | ||
334 | return ret; | ||
335 | } | ||
336 | |||
337 | static u8 at76_dfu_get_state(struct usb_device *udev, u8 *state) | ||
338 | { | ||
339 | int ret; | ||
340 | |||
341 | ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), DFU_GETSTATE, | ||
342 | USB_TYPE_CLASS | USB_DIR_IN | USB_RECIP_INTERFACE, | ||
343 | 0, 0, state, 1, USB_CTRL_GET_TIMEOUT); | ||
344 | return ret; | ||
345 | } | ||
346 | |||
347 | /* Convert timeout from the DFU status to jiffies */ | ||
348 | static inline unsigned long at76_get_timeout(struct dfu_status *s) | ||
349 | { | ||
350 | return msecs_to_jiffies((s->poll_timeout[2] << 16) | ||
351 | | (s->poll_timeout[1] << 8) | ||
352 | | (s->poll_timeout[0])); | ||
353 | } | ||
354 | |||
355 | /* Load internal firmware from the buffer. If manifest_sync_timeout > 0, use | ||
356 | * its value in jiffies in the MANIFEST_SYNC state. */ | ||
357 | static int at76_usbdfu_download(struct usb_device *udev, u8 *buf, u32 size, | ||
358 | int manifest_sync_timeout) | ||
359 | { | ||
360 | u8 *block; | ||
361 | struct dfu_status dfu_stat_buf; | ||
362 | int ret = 0; | ||
363 | int need_dfu_state = 1; | ||
364 | int is_done = 0; | ||
365 | u8 dfu_state = 0; | ||
366 | u32 dfu_timeout = 0; | ||
367 | int bsize = 0; | ||
368 | int blockno = 0; | ||
369 | |||
370 | at76_dbg(DBG_DFU, "%s( %p, %u, %d)", __func__, buf, size, | ||
371 | manifest_sync_timeout); | ||
372 | |||
373 | if (!size) { | ||
374 | dev_printk(KERN_ERR, &udev->dev, "FW buffer length invalid!\n"); | ||
375 | return -EINVAL; | ||
376 | } | ||
377 | |||
378 | block = kmalloc(FW_BLOCK_SIZE, GFP_KERNEL); | ||
379 | if (!block) | ||
380 | return -ENOMEM; | ||
381 | |||
382 | do { | ||
383 | if (need_dfu_state) { | ||
384 | ret = at76_dfu_get_state(udev, &dfu_state); | ||
385 | if (ret < 0) { | ||
386 | dev_printk(KERN_ERR, &udev->dev, | ||
387 | "cannot get DFU state: %d\n", ret); | ||
388 | goto exit; | ||
389 | } | ||
390 | need_dfu_state = 0; | ||
391 | } | ||
392 | |||
393 | switch (dfu_state) { | ||
394 | case STATE_DFU_DOWNLOAD_SYNC: | ||
395 | at76_dbg(DBG_DFU, "STATE_DFU_DOWNLOAD_SYNC"); | ||
396 | ret = at76_dfu_get_status(udev, &dfu_stat_buf); | ||
397 | if (ret >= 0) { | ||
398 | dfu_state = dfu_stat_buf.state; | ||
399 | dfu_timeout = at76_get_timeout(&dfu_stat_buf); | ||
400 | need_dfu_state = 0; | ||
401 | } else | ||
402 | dev_printk(KERN_ERR, &udev->dev, | ||
403 | "at76_dfu_get_status returned %d\n", | ||
404 | ret); | ||
405 | break; | ||
406 | |||
407 | case STATE_DFU_DOWNLOAD_BUSY: | ||
408 | at76_dbg(DBG_DFU, "STATE_DFU_DOWNLOAD_BUSY"); | ||
409 | need_dfu_state = 1; | ||
410 | |||
411 | at76_dbg(DBG_DFU, "DFU: Resetting device"); | ||
412 | schedule_timeout_interruptible(dfu_timeout); | ||
413 | break; | ||
414 | |||
415 | case STATE_DFU_DOWNLOAD_IDLE: | ||
416 | at76_dbg(DBG_DFU, "DOWNLOAD..."); | ||
417 | /* fall through */ | ||
418 | case STATE_DFU_IDLE: | ||
419 | at76_dbg(DBG_DFU, "DFU IDLE"); | ||
420 | |||
421 | bsize = min_t(int, size, FW_BLOCK_SIZE); | ||
422 | memcpy(block, buf, bsize); | ||
423 | at76_dbg(DBG_DFU, "int fw, size left = %5d, " | ||
424 | "bsize = %4d, blockno = %2d", size, bsize, | ||
425 | blockno); | ||
426 | ret = | ||
427 | at76_load_int_fw_block(udev, blockno, block, bsize); | ||
428 | buf += bsize; | ||
429 | size -= bsize; | ||
430 | blockno++; | ||
431 | |||
432 | if (ret != bsize) | ||
433 | dev_printk(KERN_ERR, &udev->dev, | ||
434 | "at76_load_int_fw_block " | ||
435 | "returned %d\n", ret); | ||
436 | need_dfu_state = 1; | ||
437 | break; | ||
438 | |||
439 | case STATE_DFU_MANIFEST_SYNC: | ||
440 | at76_dbg(DBG_DFU, "STATE_DFU_MANIFEST_SYNC"); | ||
441 | |||
442 | ret = at76_dfu_get_status(udev, &dfu_stat_buf); | ||
443 | if (ret < 0) | ||
444 | break; | ||
445 | |||
446 | dfu_state = dfu_stat_buf.state; | ||
447 | dfu_timeout = at76_get_timeout(&dfu_stat_buf); | ||
448 | need_dfu_state = 0; | ||
449 | |||
450 | /* override the timeout from the status response, | ||
451 | needed for AT76C505A */ | ||
452 | if (manifest_sync_timeout > 0) | ||
453 | dfu_timeout = manifest_sync_timeout; | ||
454 | |||
455 | at76_dbg(DBG_DFU, "DFU: Waiting for manifest phase"); | ||
456 | schedule_timeout_interruptible(dfu_timeout); | ||
457 | break; | ||
458 | |||
459 | case STATE_DFU_MANIFEST: | ||
460 | at76_dbg(DBG_DFU, "STATE_DFU_MANIFEST"); | ||
461 | is_done = 1; | ||
462 | break; | ||
463 | |||
464 | case STATE_DFU_MANIFEST_WAIT_RESET: | ||
465 | at76_dbg(DBG_DFU, "STATE_DFU_MANIFEST_WAIT_RESET"); | ||
466 | is_done = 1; | ||
467 | break; | ||
468 | |||
469 | case STATE_DFU_UPLOAD_IDLE: | ||
470 | at76_dbg(DBG_DFU, "STATE_DFU_UPLOAD_IDLE"); | ||
471 | break; | ||
472 | |||
473 | case STATE_DFU_ERROR: | ||
474 | at76_dbg(DBG_DFU, "STATE_DFU_ERROR"); | ||
475 | ret = -EPIPE; | ||
476 | break; | ||
477 | |||
478 | default: | ||
479 | at76_dbg(DBG_DFU, "DFU UNKNOWN STATE (%d)", dfu_state); | ||
480 | ret = -EINVAL; | ||
481 | break; | ||
482 | } | ||
483 | } while (!is_done && (ret >= 0)); | ||
484 | |||
485 | exit: | ||
486 | kfree(block); | ||
487 | if (ret >= 0) | ||
488 | ret = 0; | ||
489 | |||
490 | return ret; | ||
491 | } | ||
492 | |||
493 | #define HEX2STR_BUFFERS 4 | ||
494 | #define HEX2STR_MAX_LEN 64 | ||
495 | #define BIN2HEX(x) ((x) < 10 ? '0' + (x) : (x) + 'A' - 10) | ||
496 | |||
497 | /* Convert binary data into hex string */ | ||
498 | static char *hex2str(void *buf, int len) | ||
499 | { | ||
500 | static atomic_t a = ATOMIC_INIT(0); | ||
501 | static char bufs[HEX2STR_BUFFERS][3 * HEX2STR_MAX_LEN + 1]; | ||
502 | char *ret = bufs[atomic_inc_return(&a) & (HEX2STR_BUFFERS - 1)]; | ||
503 | char *obuf = ret; | ||
504 | u8 *ibuf = buf; | ||
505 | |||
506 | if (len > HEX2STR_MAX_LEN) | ||
507 | len = HEX2STR_MAX_LEN; | ||
508 | |||
509 | if (len <= 0) { | ||
510 | ret[0] = '\0'; | ||
511 | return ret; | ||
512 | } | ||
513 | |||
514 | while (len--) { | ||
515 | *obuf++ = BIN2HEX(*ibuf >> 4); | ||
516 | *obuf++ = BIN2HEX(*ibuf & 0xf); | ||
517 | *obuf++ = '-'; | ||
518 | ibuf++; | ||
519 | } | ||
520 | *(--obuf) = '\0'; | ||
521 | |||
522 | return ret; | ||
523 | } | ||
524 | |||
525 | #define MAC2STR_BUFFERS 4 | ||
526 | |||
527 | static inline char *mac2str(u8 *mac) | ||
528 | { | ||
529 | static atomic_t a = ATOMIC_INIT(0); | ||
530 | static char bufs[MAC2STR_BUFFERS][6 * 3]; | ||
531 | char *str; | ||
532 | |||
533 | str = bufs[atomic_inc_return(&a) & (MAC2STR_BUFFERS - 1)]; | ||
534 | sprintf(str, "%02x:%02x:%02x:%02x:%02x:%02x", | ||
535 | mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); | ||
536 | return str; | ||
537 | } | ||
538 | |||
539 | /* LED trigger */ | ||
540 | static int tx_activity; | ||
541 | static void at76_ledtrig_tx_timerfunc(unsigned long data); | ||
542 | static DEFINE_TIMER(ledtrig_tx_timer, at76_ledtrig_tx_timerfunc, 0, 0); | ||
543 | DEFINE_LED_TRIGGER(ledtrig_tx); | ||
544 | |||
545 | static void at76_ledtrig_tx_timerfunc(unsigned long data) | ||
546 | { | ||
547 | static int tx_lastactivity; | ||
548 | |||
549 | if (tx_lastactivity != tx_activity) { | ||
550 | tx_lastactivity = tx_activity; | ||
551 | led_trigger_event(ledtrig_tx, LED_FULL); | ||
552 | mod_timer(&ledtrig_tx_timer, jiffies + HZ / 4); | ||
553 | } else | ||
554 | led_trigger_event(ledtrig_tx, LED_OFF); | ||
555 | } | ||
556 | |||
557 | static void at76_ledtrig_tx_activity(void) | ||
558 | { | ||
559 | tx_activity++; | ||
560 | if (!timer_pending(&ledtrig_tx_timer)) | ||
561 | mod_timer(&ledtrig_tx_timer, jiffies + HZ / 4); | ||
562 | } | ||
563 | |||
564 | static int at76_remap(struct usb_device *udev) | ||
565 | { | ||
566 | int ret; | ||
567 | ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x0a, | ||
568 | USB_TYPE_VENDOR | USB_DIR_OUT | | ||
569 | USB_RECIP_INTERFACE, 0, 0, NULL, 0, | ||
570 | USB_CTRL_GET_TIMEOUT); | ||
571 | if (ret < 0) | ||
572 | return ret; | ||
573 | return 0; | ||
574 | } | ||
575 | |||
576 | static int at76_get_op_mode(struct usb_device *udev) | ||
577 | { | ||
578 | int ret; | ||
579 | u8 saved; | ||
580 | u8 *op_mode; | ||
581 | |||
582 | op_mode = kmalloc(1, GFP_NOIO); | ||
583 | if (!op_mode) | ||
584 | return -ENOMEM; | ||
585 | ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x33, | ||
586 | USB_TYPE_VENDOR | USB_DIR_IN | | ||
587 | USB_RECIP_INTERFACE, 0x01, 0, op_mode, 1, | ||
588 | USB_CTRL_GET_TIMEOUT); | ||
589 | saved = *op_mode; | ||
590 | kfree(op_mode); | ||
591 | |||
592 | if (ret < 0) | ||
593 | return ret; | ||
594 | else if (ret < 1) | ||
595 | return -EIO; | ||
596 | else | ||
597 | return saved; | ||
598 | } | ||
599 | |||
600 | /* Load a block of the second ("external") part of the firmware */ | ||
601 | static inline int at76_load_ext_fw_block(struct usb_device *udev, int blockno, | ||
602 | void *block, int size) | ||
603 | { | ||
604 | return usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x0e, | ||
605 | USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE, | ||
606 | 0x0802, blockno, block, size, | ||
607 | USB_CTRL_GET_TIMEOUT); | ||
608 | } | ||
609 | |||
610 | static inline int at76_get_hw_cfg(struct usb_device *udev, | ||
611 | union at76_hwcfg *buf, int buf_size) | ||
612 | { | ||
613 | return usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x33, | ||
614 | USB_TYPE_VENDOR | USB_DIR_IN | | ||
615 | USB_RECIP_INTERFACE, 0x0a02, 0, | ||
616 | buf, buf_size, USB_CTRL_GET_TIMEOUT); | ||
617 | } | ||
618 | |||
619 | /* Intersil boards use a different "value" for GetHWConfig requests */ | ||
620 | static inline int at76_get_hw_cfg_intersil(struct usb_device *udev, | ||
621 | union at76_hwcfg *buf, int buf_size) | ||
622 | { | ||
623 | return usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x33, | ||
624 | USB_TYPE_VENDOR | USB_DIR_IN | | ||
625 | USB_RECIP_INTERFACE, 0x0902, 0, | ||
626 | buf, buf_size, USB_CTRL_GET_TIMEOUT); | ||
627 | } | ||
628 | |||
629 | /* Get the hardware configuration for the adapter and put it to the appropriate | ||
630 | * fields of 'priv' (the GetHWConfig request and interpretation of the result | ||
631 | * depends on the board type) */ | ||
632 | static int at76_get_hw_config(struct at76_priv *priv) | ||
633 | { | ||
634 | int ret; | ||
635 | union at76_hwcfg *hwcfg = kmalloc(sizeof(*hwcfg), GFP_KERNEL); | ||
636 | |||
637 | if (!hwcfg) | ||
638 | return -ENOMEM; | ||
639 | |||
640 | if (at76_is_intersil(priv->board_type)) { | ||
641 | ret = at76_get_hw_cfg_intersil(priv->udev, hwcfg, | ||
642 | sizeof(hwcfg->i)); | ||
643 | if (ret < 0) | ||
644 | goto exit; | ||
645 | memcpy(priv->mac_addr, hwcfg->i.mac_addr, ETH_ALEN); | ||
646 | priv->regulatory_domain = hwcfg->i.regulatory_domain; | ||
647 | } else if (at76_is_503rfmd(priv->board_type)) { | ||
648 | ret = at76_get_hw_cfg(priv->udev, hwcfg, sizeof(hwcfg->r3)); | ||
649 | if (ret < 0) | ||
650 | goto exit; | ||
651 | memcpy(priv->mac_addr, hwcfg->r3.mac_addr, ETH_ALEN); | ||
652 | priv->regulatory_domain = hwcfg->r3.regulatory_domain; | ||
653 | } else { | ||
654 | ret = at76_get_hw_cfg(priv->udev, hwcfg, sizeof(hwcfg->r5)); | ||
655 | if (ret < 0) | ||
656 | goto exit; | ||
657 | memcpy(priv->mac_addr, hwcfg->r5.mac_addr, ETH_ALEN); | ||
658 | priv->regulatory_domain = hwcfg->r5.regulatory_domain; | ||
659 | } | ||
660 | |||
661 | exit: | ||
662 | kfree(hwcfg); | ||
663 | if (ret < 0) | ||
664 | printk(KERN_ERR "%s: cannot get HW Config (error %d)\n", | ||
665 | wiphy_name(priv->hw->wiphy), ret); | ||
666 | |||
667 | return ret; | ||
668 | } | ||
669 | |||
670 | static struct reg_domain const *at76_get_reg_domain(u16 code) | ||
671 | { | ||
672 | int i; | ||
673 | static struct reg_domain const fd_tab[] = { | ||
674 | { 0x10, "FCC (USA)", 0x7ff }, /* ch 1-11 */ | ||
675 | { 0x20, "IC (Canada)", 0x7ff }, /* ch 1-11 */ | ||
676 | { 0x30, "ETSI (most of Europe)", 0x1fff }, /* ch 1-13 */ | ||
677 | { 0x31, "Spain", 0x600 }, /* ch 10-11 */ | ||
678 | { 0x32, "France", 0x1e00 }, /* ch 10-13 */ | ||
679 | { 0x40, "MKK (Japan)", 0x2000 }, /* ch 14 */ | ||
680 | { 0x41, "MKK1 (Japan)", 0x3fff }, /* ch 1-14 */ | ||
681 | { 0x50, "Israel", 0x3fc }, /* ch 3-9 */ | ||
682 | { 0x00, "<unknown>", 0xffffffff } /* ch 1-32 */ | ||
683 | }; | ||
684 | |||
685 | /* Last entry is fallback for unknown domain code */ | ||
686 | for (i = 0; i < ARRAY_SIZE(fd_tab) - 1; i++) | ||
687 | if (code == fd_tab[i].code) | ||
688 | break; | ||
689 | |||
690 | return &fd_tab[i]; | ||
691 | } | ||
692 | |||
693 | static inline int at76_get_mib(struct usb_device *udev, u16 mib, void *buf, | ||
694 | int buf_size) | ||
695 | { | ||
696 | int ret; | ||
697 | |||
698 | ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x33, | ||
699 | USB_TYPE_VENDOR | USB_DIR_IN | | ||
700 | USB_RECIP_INTERFACE, mib << 8, 0, buf, buf_size, | ||
701 | USB_CTRL_GET_TIMEOUT); | ||
702 | if (ret >= 0 && ret != buf_size) | ||
703 | return -EIO; | ||
704 | return ret; | ||
705 | } | ||
706 | |||
707 | /* Return positive number for status, negative for an error */ | ||
708 | static inline int at76_get_cmd_status(struct usb_device *udev, u8 cmd) | ||
709 | { | ||
710 | u8 *stat_buf; | ||
711 | int ret; | ||
712 | |||
713 | stat_buf = kmalloc(40, GFP_NOIO); | ||
714 | if (!stat_buf) | ||
715 | return -ENOMEM; | ||
716 | |||
717 | ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x22, | ||
718 | USB_TYPE_VENDOR | USB_DIR_IN | | ||
719 | USB_RECIP_INTERFACE, cmd, 0, stat_buf, | ||
720 | 40, USB_CTRL_GET_TIMEOUT); | ||
721 | if (ret >= 0) | ||
722 | ret = stat_buf[5]; | ||
723 | kfree(stat_buf); | ||
724 | |||
725 | return ret; | ||
726 | } | ||
727 | |||
728 | #define MAKE_CMD_CASE(c) case (c): return #c | ||
729 | static const char *at76_get_cmd_string(u8 cmd_status) | ||
730 | { | ||
731 | switch (cmd_status) { | ||
732 | MAKE_CMD_CASE(CMD_SET_MIB); | ||
733 | MAKE_CMD_CASE(CMD_GET_MIB); | ||
734 | MAKE_CMD_CASE(CMD_SCAN); | ||
735 | MAKE_CMD_CASE(CMD_JOIN); | ||
736 | MAKE_CMD_CASE(CMD_START_IBSS); | ||
737 | MAKE_CMD_CASE(CMD_RADIO_ON); | ||
738 | MAKE_CMD_CASE(CMD_RADIO_OFF); | ||
739 | MAKE_CMD_CASE(CMD_STARTUP); | ||
740 | } | ||
741 | |||
742 | return "UNKNOWN"; | ||
743 | } | ||
744 | |||
745 | static int at76_set_card_command(struct usb_device *udev, u8 cmd, void *buf, | ||
746 | int buf_size) | ||
747 | { | ||
748 | int ret; | ||
749 | struct at76_command *cmd_buf = kmalloc(sizeof(struct at76_command) + | ||
750 | buf_size, GFP_KERNEL); | ||
751 | |||
752 | if (!cmd_buf) | ||
753 | return -ENOMEM; | ||
754 | |||
755 | cmd_buf->cmd = cmd; | ||
756 | cmd_buf->reserved = 0; | ||
757 | cmd_buf->size = cpu_to_le16(buf_size); | ||
758 | memcpy(cmd_buf->data, buf, buf_size); | ||
759 | |||
760 | at76_dbg_dump(DBG_CMD, cmd_buf, sizeof(struct at76_command) + buf_size, | ||
761 | "issuing command %s (0x%02x)", | ||
762 | at76_get_cmd_string(cmd), cmd); | ||
763 | |||
764 | ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x0e, | ||
765 | USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE, | ||
766 | 0, 0, cmd_buf, | ||
767 | sizeof(struct at76_command) + buf_size, | ||
768 | USB_CTRL_GET_TIMEOUT); | ||
769 | kfree(cmd_buf); | ||
770 | return ret; | ||
771 | } | ||
772 | |||
773 | #define MAKE_CMD_STATUS_CASE(c) case (c): return #c | ||
774 | static const char *at76_get_cmd_status_string(u8 cmd_status) | ||
775 | { | ||
776 | switch (cmd_status) { | ||
777 | MAKE_CMD_STATUS_CASE(CMD_STATUS_IDLE); | ||
778 | MAKE_CMD_STATUS_CASE(CMD_STATUS_COMPLETE); | ||
779 | MAKE_CMD_STATUS_CASE(CMD_STATUS_UNKNOWN); | ||
780 | MAKE_CMD_STATUS_CASE(CMD_STATUS_INVALID_PARAMETER); | ||
781 | MAKE_CMD_STATUS_CASE(CMD_STATUS_FUNCTION_NOT_SUPPORTED); | ||
782 | MAKE_CMD_STATUS_CASE(CMD_STATUS_TIME_OUT); | ||
783 | MAKE_CMD_STATUS_CASE(CMD_STATUS_IN_PROGRESS); | ||
784 | MAKE_CMD_STATUS_CASE(CMD_STATUS_HOST_FAILURE); | ||
785 | MAKE_CMD_STATUS_CASE(CMD_STATUS_SCAN_FAILED); | ||
786 | } | ||
787 | |||
788 | return "UNKNOWN"; | ||
789 | } | ||
790 | |||
791 | /* Wait until the command is completed */ | ||
792 | static int at76_wait_completion(struct at76_priv *priv, int cmd) | ||
793 | { | ||
794 | int status = 0; | ||
795 | unsigned long timeout = jiffies + CMD_COMPLETION_TIMEOUT; | ||
796 | |||
797 | do { | ||
798 | status = at76_get_cmd_status(priv->udev, cmd); | ||
799 | if (status < 0) { | ||
800 | printk(KERN_ERR "%s: at76_get_cmd_status failed: %d\n", | ||
801 | wiphy_name(priv->hw->wiphy), status); | ||
802 | break; | ||
803 | } | ||
804 | |||
805 | at76_dbg(DBG_WAIT_COMPLETE, | ||
806 | "%s: Waiting on cmd %d, status = %d (%s)", | ||
807 | wiphy_name(priv->hw->wiphy), cmd, status, | ||
808 | at76_get_cmd_status_string(status)); | ||
809 | |||
810 | if (status != CMD_STATUS_IN_PROGRESS | ||
811 | && status != CMD_STATUS_IDLE) | ||
812 | break; | ||
813 | |||
814 | schedule_timeout_interruptible(HZ / 10); /* 100 ms */ | ||
815 | if (time_after(jiffies, timeout)) { | ||
816 | printk(KERN_ERR | ||
817 | "%s: completion timeout for command %d\n", | ||
818 | wiphy_name(priv->hw->wiphy), cmd); | ||
819 | status = -ETIMEDOUT; | ||
820 | break; | ||
821 | } | ||
822 | } while (1); | ||
823 | |||
824 | return status; | ||
825 | } | ||
826 | |||
827 | static int at76_set_mib(struct at76_priv *priv, struct set_mib_buffer *buf) | ||
828 | { | ||
829 | int ret; | ||
830 | |||
831 | ret = at76_set_card_command(priv->udev, CMD_SET_MIB, buf, | ||
832 | offsetof(struct set_mib_buffer, | ||
833 | data) + buf->size); | ||
834 | if (ret < 0) | ||
835 | return ret; | ||
836 | |||
837 | ret = at76_wait_completion(priv, CMD_SET_MIB); | ||
838 | if (ret != CMD_STATUS_COMPLETE) { | ||
839 | printk(KERN_INFO | ||
840 | "%s: set_mib: at76_wait_completion failed " | ||
841 | "with %d\n", wiphy_name(priv->hw->wiphy), ret); | ||
842 | ret = -EIO; | ||
843 | } | ||
844 | |||
845 | return ret; | ||
846 | } | ||
847 | |||
848 | /* Return < 0 on error, == 0 if no command sent, == 1 if cmd sent */ | ||
849 | static int at76_set_radio(struct at76_priv *priv, int enable) | ||
850 | { | ||
851 | int ret; | ||
852 | int cmd; | ||
853 | |||
854 | if (priv->radio_on == enable) | ||
855 | return 0; | ||
856 | |||
857 | cmd = enable ? CMD_RADIO_ON : CMD_RADIO_OFF; | ||
858 | |||
859 | ret = at76_set_card_command(priv->udev, cmd, NULL, 0); | ||
860 | if (ret < 0) | ||
861 | printk(KERN_ERR "%s: at76_set_card_command(%d) failed: %d\n", | ||
862 | wiphy_name(priv->hw->wiphy), cmd, ret); | ||
863 | else | ||
864 | ret = 1; | ||
865 | |||
866 | priv->radio_on = enable; | ||
867 | return ret; | ||
868 | } | ||
869 | |||
870 | /* Set current power save mode (AT76_PM_OFF/AT76_PM_ON/AT76_PM_SMART) */ | ||
871 | static int at76_set_pm_mode(struct at76_priv *priv) | ||
872 | { | ||
873 | int ret = 0; | ||
874 | |||
875 | priv->mib_buf.type = MIB_MAC_MGMT; | ||
876 | priv->mib_buf.size = 1; | ||
877 | priv->mib_buf.index = offsetof(struct mib_mac_mgmt, power_mgmt_mode); | ||
878 | priv->mib_buf.data.byte = priv->pm_mode; | ||
879 | |||
880 | ret = at76_set_mib(priv, &priv->mib_buf); | ||
881 | if (ret < 0) | ||
882 | printk(KERN_ERR "%s: set_mib (pm_mode) failed: %d\n", | ||
883 | wiphy_name(priv->hw->wiphy), ret); | ||
884 | |||
885 | return ret; | ||
886 | } | ||
887 | |||
888 | static int at76_set_preamble(struct at76_priv *priv, u8 type) | ||
889 | { | ||
890 | int ret = 0; | ||
891 | |||
892 | priv->mib_buf.type = MIB_LOCAL; | ||
893 | priv->mib_buf.size = 1; | ||
894 | priv->mib_buf.index = offsetof(struct mib_local, preamble_type); | ||
895 | priv->mib_buf.data.byte = type; | ||
896 | |||
897 | ret = at76_set_mib(priv, &priv->mib_buf); | ||
898 | if (ret < 0) | ||
899 | printk(KERN_ERR "%s: set_mib (preamble) failed: %d\n", | ||
900 | wiphy_name(priv->hw->wiphy), ret); | ||
901 | |||
902 | return ret; | ||
903 | } | ||
904 | |||
905 | static int at76_set_frag(struct at76_priv *priv, u16 size) | ||
906 | { | ||
907 | int ret = 0; | ||
908 | |||
909 | priv->mib_buf.type = MIB_MAC; | ||
910 | priv->mib_buf.size = 2; | ||
911 | priv->mib_buf.index = offsetof(struct mib_mac, frag_threshold); | ||
912 | priv->mib_buf.data.word = cpu_to_le16(size); | ||
913 | |||
914 | ret = at76_set_mib(priv, &priv->mib_buf); | ||
915 | if (ret < 0) | ||
916 | printk(KERN_ERR "%s: set_mib (frag threshold) failed: %d\n", | ||
917 | wiphy_name(priv->hw->wiphy), ret); | ||
918 | |||
919 | return ret; | ||
920 | } | ||
921 | |||
922 | static int at76_set_rts(struct at76_priv *priv, u16 size) | ||
923 | { | ||
924 | int ret = 0; | ||
925 | |||
926 | priv->mib_buf.type = MIB_MAC; | ||
927 | priv->mib_buf.size = 2; | ||
928 | priv->mib_buf.index = offsetof(struct mib_mac, rts_threshold); | ||
929 | priv->mib_buf.data.word = cpu_to_le16(size); | ||
930 | |||
931 | ret = at76_set_mib(priv, &priv->mib_buf); | ||
932 | if (ret < 0) | ||
933 | printk(KERN_ERR "%s: set_mib (rts) failed: %d\n", | ||
934 | wiphy_name(priv->hw->wiphy), ret); | ||
935 | |||
936 | return ret; | ||
937 | } | ||
938 | |||
939 | static int at76_set_autorate_fallback(struct at76_priv *priv, int onoff) | ||
940 | { | ||
941 | int ret = 0; | ||
942 | |||
943 | priv->mib_buf.type = MIB_LOCAL; | ||
944 | priv->mib_buf.size = 1; | ||
945 | priv->mib_buf.index = offsetof(struct mib_local, txautorate_fallback); | ||
946 | priv->mib_buf.data.byte = onoff; | ||
947 | |||
948 | ret = at76_set_mib(priv, &priv->mib_buf); | ||
949 | if (ret < 0) | ||
950 | printk(KERN_ERR "%s: set_mib (autorate fallback) failed: %d\n", | ||
951 | wiphy_name(priv->hw->wiphy), ret); | ||
952 | |||
953 | return ret; | ||
954 | } | ||
955 | |||
956 | static void at76_dump_mib_mac_addr(struct at76_priv *priv) | ||
957 | { | ||
958 | int i; | ||
959 | int ret; | ||
960 | struct mib_mac_addr *m = kmalloc(sizeof(struct mib_mac_addr), | ||
961 | GFP_KERNEL); | ||
962 | |||
963 | if (!m) | ||
964 | return; | ||
965 | |||
966 | ret = at76_get_mib(priv->udev, MIB_MAC_ADDR, m, | ||
967 | sizeof(struct mib_mac_addr)); | ||
968 | if (ret < 0) { | ||
969 | printk(KERN_ERR "%s: at76_get_mib (MAC_ADDR) failed: %d\n", | ||
970 | wiphy_name(priv->hw->wiphy), ret); | ||
971 | goto exit; | ||
972 | } | ||
973 | |||
974 | at76_dbg(DBG_MIB, "%s: MIB MAC_ADDR: mac_addr %s res 0x%x 0x%x", | ||
975 | wiphy_name(priv->hw->wiphy), | ||
976 | mac2str(m->mac_addr), m->res[0], m->res[1]); | ||
977 | for (i = 0; i < ARRAY_SIZE(m->group_addr); i++) | ||
978 | at76_dbg(DBG_MIB, "%s: MIB MAC_ADDR: group addr %d: %s, " | ||
979 | "status %d", wiphy_name(priv->hw->wiphy), i, | ||
980 | mac2str(m->group_addr[i]), m->group_addr_status[i]); | ||
981 | exit: | ||
982 | kfree(m); | ||
983 | } | ||
984 | |||
985 | static void at76_dump_mib_mac_wep(struct at76_priv *priv) | ||
986 | { | ||
987 | int i; | ||
988 | int ret; | ||
989 | int key_len; | ||
990 | struct mib_mac_wep *m = kmalloc(sizeof(struct mib_mac_wep), GFP_KERNEL); | ||
991 | |||
992 | if (!m) | ||
993 | return; | ||
994 | |||
995 | ret = at76_get_mib(priv->udev, MIB_MAC_WEP, m, | ||
996 | sizeof(struct mib_mac_wep)); | ||
997 | if (ret < 0) { | ||
998 | printk(KERN_ERR "%s: at76_get_mib (MAC_WEP) failed: %d\n", | ||
999 | wiphy_name(priv->hw->wiphy), ret); | ||
1000 | goto exit; | ||
1001 | } | ||
1002 | |||
1003 | at76_dbg(DBG_MIB, "%s: MIB MAC_WEP: priv_invoked %u def_key_id %u " | ||
1004 | "key_len %u excl_unencr %u wep_icv_err %u wep_excluded %u " | ||
1005 | "encr_level %u key %d", wiphy_name(priv->hw->wiphy), | ||
1006 | m->privacy_invoked, m->wep_default_key_id, | ||
1007 | m->wep_key_mapping_len, m->exclude_unencrypted, | ||
1008 | le32_to_cpu(m->wep_icv_error_count), | ||
1009 | le32_to_cpu(m->wep_excluded_count), m->encryption_level, | ||
1010 | m->wep_default_key_id); | ||
1011 | |||
1012 | key_len = (m->encryption_level == 1) ? | ||
1013 | WEP_SMALL_KEY_LEN : WEP_LARGE_KEY_LEN; | ||
1014 | |||
1015 | for (i = 0; i < WEP_KEYS; i++) | ||
1016 | at76_dbg(DBG_MIB, "%s: MIB MAC_WEP: key %d: %s", | ||
1017 | wiphy_name(priv->hw->wiphy), i, | ||
1018 | hex2str(m->wep_default_keyvalue[i], key_len)); | ||
1019 | exit: | ||
1020 | kfree(m); | ||
1021 | } | ||
1022 | |||
1023 | static void at76_dump_mib_mac_mgmt(struct at76_priv *priv) | ||
1024 | { | ||
1025 | int ret; | ||
1026 | struct mib_mac_mgmt *m = kmalloc(sizeof(struct mib_mac_mgmt), | ||
1027 | GFP_KERNEL); | ||
1028 | |||
1029 | if (!m) | ||
1030 | return; | ||
1031 | |||
1032 | ret = at76_get_mib(priv->udev, MIB_MAC_MGMT, m, | ||
1033 | sizeof(struct mib_mac_mgmt)); | ||
1034 | if (ret < 0) { | ||
1035 | printk(KERN_ERR "%s: at76_get_mib (MAC_MGMT) failed: %d\n", | ||
1036 | wiphy_name(priv->hw->wiphy), ret); | ||
1037 | goto exit; | ||
1038 | } | ||
1039 | |||
1040 | at76_dbg(DBG_MIB, "%s: MIB MAC_MGMT: beacon_period %d CFP_max_duration " | ||
1041 | "%d medium_occupancy_limit %d station_id 0x%x ATIM_window %d " | ||
1042 | "CFP_mode %d privacy_opt_impl %d DTIM_period %d CFP_period %d " | ||
1043 | "current_bssid %s current_essid %s current_bss_type %d " | ||
1044 | "pm_mode %d ibss_change %d res %d " | ||
1045 | "multi_domain_capability_implemented %d " | ||
1046 | "international_roaming %d country_string %.3s", | ||
1047 | wiphy_name(priv->hw->wiphy), le16_to_cpu(m->beacon_period), | ||
1048 | le16_to_cpu(m->CFP_max_duration), | ||
1049 | le16_to_cpu(m->medium_occupancy_limit), | ||
1050 | le16_to_cpu(m->station_id), le16_to_cpu(m->ATIM_window), | ||
1051 | m->CFP_mode, m->privacy_option_implemented, m->DTIM_period, | ||
1052 | m->CFP_period, mac2str(m->current_bssid), | ||
1053 | hex2str(m->current_essid, IW_ESSID_MAX_SIZE), | ||
1054 | m->current_bss_type, m->power_mgmt_mode, m->ibss_change, | ||
1055 | m->res, m->multi_domain_capability_implemented, | ||
1056 | m->multi_domain_capability_enabled, m->country_string); | ||
1057 | exit: | ||
1058 | kfree(m); | ||
1059 | } | ||
1060 | |||
1061 | static void at76_dump_mib_mac(struct at76_priv *priv) | ||
1062 | { | ||
1063 | int ret; | ||
1064 | struct mib_mac *m = kmalloc(sizeof(struct mib_mac), GFP_KERNEL); | ||
1065 | |||
1066 | if (!m) | ||
1067 | return; | ||
1068 | |||
1069 | ret = at76_get_mib(priv->udev, MIB_MAC, m, sizeof(struct mib_mac)); | ||
1070 | if (ret < 0) { | ||
1071 | printk(KERN_ERR "%s: at76_get_mib (MAC) failed: %d\n", | ||
1072 | wiphy_name(priv->hw->wiphy), ret); | ||
1073 | goto exit; | ||
1074 | } | ||
1075 | |||
1076 | at76_dbg(DBG_MIB, "%s: MIB MAC: max_tx_msdu_lifetime %d " | ||
1077 | "max_rx_lifetime %d frag_threshold %d rts_threshold %d " | ||
1078 | "cwmin %d cwmax %d short_retry_time %d long_retry_time %d " | ||
1079 | "scan_type %d scan_channel %d probe_delay %u " | ||
1080 | "min_channel_time %d max_channel_time %d listen_int %d " | ||
1081 | "desired_ssid %s desired_bssid %s desired_bsstype %d", | ||
1082 | wiphy_name(priv->hw->wiphy), | ||
1083 | le32_to_cpu(m->max_tx_msdu_lifetime), | ||
1084 | le32_to_cpu(m->max_rx_lifetime), | ||
1085 | le16_to_cpu(m->frag_threshold), le16_to_cpu(m->rts_threshold), | ||
1086 | le16_to_cpu(m->cwmin), le16_to_cpu(m->cwmax), | ||
1087 | m->short_retry_time, m->long_retry_time, m->scan_type, | ||
1088 | m->scan_channel, le16_to_cpu(m->probe_delay), | ||
1089 | le16_to_cpu(m->min_channel_time), | ||
1090 | le16_to_cpu(m->max_channel_time), | ||
1091 | le16_to_cpu(m->listen_interval), | ||
1092 | hex2str(m->desired_ssid, IW_ESSID_MAX_SIZE), | ||
1093 | mac2str(m->desired_bssid), m->desired_bsstype); | ||
1094 | exit: | ||
1095 | kfree(m); | ||
1096 | } | ||
1097 | |||
1098 | static void at76_dump_mib_phy(struct at76_priv *priv) | ||
1099 | { | ||
1100 | int ret; | ||
1101 | struct mib_phy *m = kmalloc(sizeof(struct mib_phy), GFP_KERNEL); | ||
1102 | |||
1103 | if (!m) | ||
1104 | return; | ||
1105 | |||
1106 | ret = at76_get_mib(priv->udev, MIB_PHY, m, sizeof(struct mib_phy)); | ||
1107 | if (ret < 0) { | ||
1108 | printk(KERN_ERR "%s: at76_get_mib (PHY) failed: %d\n", | ||
1109 | wiphy_name(priv->hw->wiphy), ret); | ||
1110 | goto exit; | ||
1111 | } | ||
1112 | |||
1113 | at76_dbg(DBG_MIB, "%s: MIB PHY: ed_threshold %d slot_time %d " | ||
1114 | "sifs_time %d preamble_length %d plcp_header_length %d " | ||
1115 | "mpdu_max_length %d cca_mode_supported %d operation_rate_set " | ||
1116 | "0x%x 0x%x 0x%x 0x%x channel_id %d current_cca_mode %d " | ||
1117 | "phy_type %d current_reg_domain %d", | ||
1118 | wiphy_name(priv->hw->wiphy), le32_to_cpu(m->ed_threshold), | ||
1119 | le16_to_cpu(m->slot_time), le16_to_cpu(m->sifs_time), | ||
1120 | le16_to_cpu(m->preamble_length), | ||
1121 | le16_to_cpu(m->plcp_header_length), | ||
1122 | le16_to_cpu(m->mpdu_max_length), | ||
1123 | le16_to_cpu(m->cca_mode_supported), m->operation_rate_set[0], | ||
1124 | m->operation_rate_set[1], m->operation_rate_set[2], | ||
1125 | m->operation_rate_set[3], m->channel_id, m->current_cca_mode, | ||
1126 | m->phy_type, m->current_reg_domain); | ||
1127 | exit: | ||
1128 | kfree(m); | ||
1129 | } | ||
1130 | |||
1131 | static void at76_dump_mib_local(struct at76_priv *priv) | ||
1132 | { | ||
1133 | int ret; | ||
1134 | struct mib_local *m = kmalloc(sizeof(struct mib_phy), GFP_KERNEL); | ||
1135 | |||
1136 | if (!m) | ||
1137 | return; | ||
1138 | |||
1139 | ret = at76_get_mib(priv->udev, MIB_LOCAL, m, sizeof(struct mib_local)); | ||
1140 | if (ret < 0) { | ||
1141 | printk(KERN_ERR "%s: at76_get_mib (LOCAL) failed: %d\n", | ||
1142 | wiphy_name(priv->hw->wiphy), ret); | ||
1143 | goto exit; | ||
1144 | } | ||
1145 | |||
1146 | at76_dbg(DBG_MIB, "%s: MIB LOCAL: beacon_enable %d " | ||
1147 | "txautorate_fallback %d ssid_size %d promiscuous_mode %d " | ||
1148 | "preamble_type %d", wiphy_name(priv->hw->wiphy), | ||
1149 | m->beacon_enable, | ||
1150 | m->txautorate_fallback, m->ssid_size, m->promiscuous_mode, | ||
1151 | m->preamble_type); | ||
1152 | exit: | ||
1153 | kfree(m); | ||
1154 | } | ||
1155 | |||
1156 | static void at76_dump_mib_mdomain(struct at76_priv *priv) | ||
1157 | { | ||
1158 | int ret; | ||
1159 | struct mib_mdomain *m = kmalloc(sizeof(struct mib_mdomain), GFP_KERNEL); | ||
1160 | |||
1161 | if (!m) | ||
1162 | return; | ||
1163 | |||
1164 | ret = at76_get_mib(priv->udev, MIB_MDOMAIN, m, | ||
1165 | sizeof(struct mib_mdomain)); | ||
1166 | if (ret < 0) { | ||
1167 | printk(KERN_ERR "%s: at76_get_mib (MDOMAIN) failed: %d\n", | ||
1168 | wiphy_name(priv->hw->wiphy), ret); | ||
1169 | goto exit; | ||
1170 | } | ||
1171 | |||
1172 | at76_dbg(DBG_MIB, "%s: MIB MDOMAIN: channel_list %s", | ||
1173 | wiphy_name(priv->hw->wiphy), | ||
1174 | hex2str(m->channel_list, sizeof(m->channel_list))); | ||
1175 | |||
1176 | at76_dbg(DBG_MIB, "%s: MIB MDOMAIN: tx_powerlevel %s", | ||
1177 | wiphy_name(priv->hw->wiphy), | ||
1178 | hex2str(m->tx_powerlevel, sizeof(m->tx_powerlevel))); | ||
1179 | exit: | ||
1180 | kfree(m); | ||
1181 | } | ||
1182 | |||
1183 | /* Enable monitor mode */ | ||
1184 | static int at76_start_monitor(struct at76_priv *priv) | ||
1185 | { | ||
1186 | struct at76_req_scan scan; | ||
1187 | int ret; | ||
1188 | |||
1189 | memset(&scan, 0, sizeof(struct at76_req_scan)); | ||
1190 | memset(scan.bssid, 0xff, ETH_ALEN); | ||
1191 | |||
1192 | scan.channel = priv->channel; | ||
1193 | scan.scan_type = SCAN_TYPE_PASSIVE; | ||
1194 | scan.international_scan = 0; | ||
1195 | |||
1196 | ret = at76_set_card_command(priv->udev, CMD_SCAN, &scan, sizeof(scan)); | ||
1197 | if (ret >= 0) | ||
1198 | ret = at76_get_cmd_status(priv->udev, CMD_SCAN); | ||
1199 | |||
1200 | return ret; | ||
1201 | } | ||
1202 | |||
1203 | /* Calculate padding from txbuf->wlength (which excludes the USB TX header), | ||
1204 | likely to compensate a flaw in the AT76C503A USB part ... */ | ||
1205 | static inline int at76_calc_padding(int wlen) | ||
1206 | { | ||
1207 | /* add the USB TX header */ | ||
1208 | wlen += AT76_TX_HDRLEN; | ||
1209 | |||
1210 | wlen = wlen % 64; | ||
1211 | |||
1212 | if (wlen < 50) | ||
1213 | return 50 - wlen; | ||
1214 | |||
1215 | if (wlen >= 61) | ||
1216 | return 64 + 50 - wlen; | ||
1217 | |||
1218 | return 0; | ||
1219 | } | ||
1220 | |||
1221 | static void at76_rx_callback(struct urb *urb) | ||
1222 | { | ||
1223 | struct at76_priv *priv = urb->context; | ||
1224 | |||
1225 | priv->rx_tasklet.data = (unsigned long)urb; | ||
1226 | tasklet_schedule(&priv->rx_tasklet); | ||
1227 | return; | ||
1228 | } | ||
1229 | |||
1230 | static int at76_submit_rx_urb(struct at76_priv *priv) | ||
1231 | { | ||
1232 | int ret; | ||
1233 | int size; | ||
1234 | struct sk_buff *skb = priv->rx_skb; | ||
1235 | |||
1236 | if (!priv->rx_urb) { | ||
1237 | printk(KERN_ERR "%s: %s: priv->rx_urb is NULL\n", | ||
1238 | wiphy_name(priv->hw->wiphy), __func__); | ||
1239 | return -EFAULT; | ||
1240 | } | ||
1241 | |||
1242 | if (!skb) { | ||
1243 | skb = dev_alloc_skb(sizeof(struct at76_rx_buffer)); | ||
1244 | if (!skb) { | ||
1245 | printk(KERN_ERR "%s: cannot allocate rx skbuff\n", | ||
1246 | wiphy_name(priv->hw->wiphy)); | ||
1247 | ret = -ENOMEM; | ||
1248 | goto exit; | ||
1249 | } | ||
1250 | priv->rx_skb = skb; | ||
1251 | } else { | ||
1252 | skb_push(skb, skb_headroom(skb)); | ||
1253 | skb_trim(skb, 0); | ||
1254 | } | ||
1255 | |||
1256 | size = skb_tailroom(skb); | ||
1257 | usb_fill_bulk_urb(priv->rx_urb, priv->udev, priv->rx_pipe, | ||
1258 | skb_put(skb, size), size, at76_rx_callback, priv); | ||
1259 | ret = usb_submit_urb(priv->rx_urb, GFP_ATOMIC); | ||
1260 | if (ret < 0) { | ||
1261 | if (ret == -ENODEV) | ||
1262 | at76_dbg(DBG_DEVSTART, | ||
1263 | "usb_submit_urb returned -ENODEV"); | ||
1264 | else | ||
1265 | printk(KERN_ERR "%s: rx, usb_submit_urb failed: %d\n", | ||
1266 | wiphy_name(priv->hw->wiphy), ret); | ||
1267 | } | ||
1268 | |||
1269 | exit: | ||
1270 | if (ret < 0 && ret != -ENODEV) | ||
1271 | printk(KERN_ERR "%s: cannot submit rx urb - please unload the " | ||
1272 | "driver and/or power cycle the device\n", | ||
1273 | wiphy_name(priv->hw->wiphy)); | ||
1274 | |||
1275 | return ret; | ||
1276 | } | ||
1277 | |||
1278 | /* Download external firmware */ | ||
1279 | static int at76_load_external_fw(struct usb_device *udev, struct fwentry *fwe) | ||
1280 | { | ||
1281 | int ret; | ||
1282 | int op_mode; | ||
1283 | int blockno = 0; | ||
1284 | int bsize; | ||
1285 | u8 *block; | ||
1286 | u8 *buf = fwe->extfw; | ||
1287 | int size = fwe->extfw_size; | ||
1288 | |||
1289 | if (!buf || !size) | ||
1290 | return -ENOENT; | ||
1291 | |||
1292 | op_mode = at76_get_op_mode(udev); | ||
1293 | at76_dbg(DBG_DEVSTART, "opmode %d", op_mode); | ||
1294 | |||
1295 | if (op_mode != OPMODE_NORMAL_NIC_WITHOUT_FLASH) { | ||
1296 | dev_printk(KERN_ERR, &udev->dev, "unexpected opmode %d\n", | ||
1297 | op_mode); | ||
1298 | return -EINVAL; | ||
1299 | } | ||
1300 | |||
1301 | block = kmalloc(FW_BLOCK_SIZE, GFP_KERNEL); | ||
1302 | if (!block) | ||
1303 | return -ENOMEM; | ||
1304 | |||
1305 | at76_dbg(DBG_DEVSTART, "downloading external firmware"); | ||
1306 | |||
1307 | /* for fw >= 0.100, the device needs an extra empty block */ | ||
1308 | do { | ||
1309 | bsize = min_t(int, size, FW_BLOCK_SIZE); | ||
1310 | memcpy(block, buf, bsize); | ||
1311 | at76_dbg(DBG_DEVSTART, | ||
1312 | "ext fw, size left = %5d, bsize = %4d, blockno = %2d", | ||
1313 | size, bsize, blockno); | ||
1314 | ret = at76_load_ext_fw_block(udev, blockno, block, bsize); | ||
1315 | if (ret != bsize) { | ||
1316 | dev_printk(KERN_ERR, &udev->dev, | ||
1317 | "loading %dth firmware block failed: %d\n", | ||
1318 | blockno, ret); | ||
1319 | goto exit; | ||
1320 | } | ||
1321 | buf += bsize; | ||
1322 | size -= bsize; | ||
1323 | blockno++; | ||
1324 | } while (bsize > 0); | ||
1325 | |||
1326 | if (at76_is_505a(fwe->board_type)) { | ||
1327 | at76_dbg(DBG_DEVSTART, "200 ms delay for 505a"); | ||
1328 | schedule_timeout_interruptible(HZ / 5 + 1); | ||
1329 | } | ||
1330 | |||
1331 | exit: | ||
1332 | kfree(block); | ||
1333 | if (ret < 0) | ||
1334 | dev_printk(KERN_ERR, &udev->dev, | ||
1335 | "downloading external firmware failed: %d\n", ret); | ||
1336 | return ret; | ||
1337 | } | ||
1338 | |||
1339 | /* Download internal firmware */ | ||
1340 | static int at76_load_internal_fw(struct usb_device *udev, struct fwentry *fwe) | ||
1341 | { | ||
1342 | int ret; | ||
1343 | int need_remap = !at76_is_505a(fwe->board_type); | ||
1344 | |||
1345 | ret = at76_usbdfu_download(udev, fwe->intfw, fwe->intfw_size, | ||
1346 | need_remap ? 0 : 2 * HZ); | ||
1347 | |||
1348 | if (ret < 0) { | ||
1349 | dev_printk(KERN_ERR, &udev->dev, | ||
1350 | "downloading internal fw failed with %d\n", ret); | ||
1351 | goto exit; | ||
1352 | } | ||
1353 | |||
1354 | at76_dbg(DBG_DEVSTART, "sending REMAP"); | ||
1355 | |||
1356 | /* no REMAP for 505A (see SF driver) */ | ||
1357 | if (need_remap) { | ||
1358 | ret = at76_remap(udev); | ||
1359 | if (ret < 0) { | ||
1360 | dev_printk(KERN_ERR, &udev->dev, | ||
1361 | "sending REMAP failed with %d\n", ret); | ||
1362 | goto exit; | ||
1363 | } | ||
1364 | } | ||
1365 | |||
1366 | at76_dbg(DBG_DEVSTART, "sleeping for 2 seconds"); | ||
1367 | schedule_timeout_interruptible(2 * HZ + 1); | ||
1368 | usb_reset_device(udev); | ||
1369 | |||
1370 | exit: | ||
1371 | return ret; | ||
1372 | } | ||
1373 | |||
1374 | static int at76_startup_device(struct at76_priv *priv) | ||
1375 | { | ||
1376 | struct at76_card_config *ccfg = &priv->card_config; | ||
1377 | int ret; | ||
1378 | |||
1379 | at76_dbg(DBG_PARAMS, | ||
1380 | "%s param: ssid %.*s (%s) mode %s ch %d wep %s key %d " | ||
1381 | "keylen %d", wiphy_name(priv->hw->wiphy), priv->essid_size, | ||
1382 | priv->essid, hex2str(priv->essid, IW_ESSID_MAX_SIZE), | ||
1383 | priv->iw_mode == IW_MODE_ADHOC ? "adhoc" : "infra", | ||
1384 | priv->channel, priv->wep_enabled ? "enabled" : "disabled", | ||
1385 | priv->wep_key_id, priv->wep_keys_len[priv->wep_key_id]); | ||
1386 | at76_dbg(DBG_PARAMS, | ||
1387 | "%s param: preamble %s rts %d retry %d frag %d " | ||
1388 | "txrate %s auth_mode %d", wiphy_name(priv->hw->wiphy), | ||
1389 | preambles[priv->preamble_type], priv->rts_threshold, | ||
1390 | priv->short_retry_limit, priv->frag_threshold, | ||
1391 | priv->txrate == TX_RATE_1MBIT ? "1MBit" : priv->txrate == | ||
1392 | TX_RATE_2MBIT ? "2MBit" : priv->txrate == | ||
1393 | TX_RATE_5_5MBIT ? "5.5MBit" : priv->txrate == | ||
1394 | TX_RATE_11MBIT ? "11MBit" : priv->txrate == | ||
1395 | TX_RATE_AUTO ? "auto" : "<invalid>", priv->auth_mode); | ||
1396 | at76_dbg(DBG_PARAMS, | ||
1397 | "%s param: pm_mode %d pm_period %d auth_mode %s " | ||
1398 | "scan_times %d %d scan_mode %s", | ||
1399 | wiphy_name(priv->hw->wiphy), priv->pm_mode, priv->pm_period, | ||
1400 | priv->auth_mode == WLAN_AUTH_OPEN ? "open" : "shared_secret", | ||
1401 | priv->scan_min_time, priv->scan_max_time, | ||
1402 | priv->scan_mode == SCAN_TYPE_ACTIVE ? "active" : "passive"); | ||
1403 | |||
1404 | memset(ccfg, 0, sizeof(struct at76_card_config)); | ||
1405 | ccfg->promiscuous_mode = 0; | ||
1406 | ccfg->short_retry_limit = priv->short_retry_limit; | ||
1407 | |||
1408 | if (priv->wep_enabled) { | ||
1409 | if (priv->wep_keys_len[priv->wep_key_id] > WEP_SMALL_KEY_LEN) | ||
1410 | ccfg->encryption_type = 2; | ||
1411 | else | ||
1412 | ccfg->encryption_type = 1; | ||
1413 | |||
1414 | /* jal: always exclude unencrypted if WEP is active */ | ||
1415 | ccfg->exclude_unencrypted = 1; | ||
1416 | } else { | ||
1417 | ccfg->exclude_unencrypted = 0; | ||
1418 | ccfg->encryption_type = 0; | ||
1419 | } | ||
1420 | |||
1421 | ccfg->rts_threshold = cpu_to_le16(priv->rts_threshold); | ||
1422 | ccfg->fragmentation_threshold = cpu_to_le16(priv->frag_threshold); | ||
1423 | |||
1424 | memcpy(ccfg->basic_rate_set, hw_rates, 4); | ||
1425 | /* jal: really needed, we do a set_mib for autorate later ??? */ | ||
1426 | ccfg->auto_rate_fallback = (priv->txrate == TX_RATE_AUTO ? 1 : 0); | ||
1427 | ccfg->channel = priv->channel; | ||
1428 | ccfg->privacy_invoked = priv->wep_enabled; | ||
1429 | memcpy(ccfg->current_ssid, priv->essid, IW_ESSID_MAX_SIZE); | ||
1430 | ccfg->ssid_len = priv->essid_size; | ||
1431 | |||
1432 | ccfg->wep_default_key_id = priv->wep_key_id; | ||
1433 | memcpy(ccfg->wep_default_key_value, priv->wep_keys, | ||
1434 | sizeof(priv->wep_keys)); | ||
1435 | |||
1436 | ccfg->short_preamble = priv->preamble_type; | ||
1437 | ccfg->beacon_period = cpu_to_le16(priv->beacon_period); | ||
1438 | |||
1439 | ret = at76_set_card_command(priv->udev, CMD_STARTUP, &priv->card_config, | ||
1440 | sizeof(struct at76_card_config)); | ||
1441 | if (ret < 0) { | ||
1442 | printk(KERN_ERR "%s: at76_set_card_command failed: %d\n", | ||
1443 | wiphy_name(priv->hw->wiphy), ret); | ||
1444 | return ret; | ||
1445 | } | ||
1446 | |||
1447 | at76_wait_completion(priv, CMD_STARTUP); | ||
1448 | |||
1449 | /* remove BSSID from previous run */ | ||
1450 | memset(priv->bssid, 0, ETH_ALEN); | ||
1451 | |||
1452 | if (at76_set_radio(priv, 1) == 1) | ||
1453 | at76_wait_completion(priv, CMD_RADIO_ON); | ||
1454 | |||
1455 | ret = at76_set_preamble(priv, priv->preamble_type); | ||
1456 | if (ret < 0) | ||
1457 | return ret; | ||
1458 | |||
1459 | ret = at76_set_frag(priv, priv->frag_threshold); | ||
1460 | if (ret < 0) | ||
1461 | return ret; | ||
1462 | |||
1463 | ret = at76_set_rts(priv, priv->rts_threshold); | ||
1464 | if (ret < 0) | ||
1465 | return ret; | ||
1466 | |||
1467 | ret = at76_set_autorate_fallback(priv, | ||
1468 | priv->txrate == TX_RATE_AUTO ? 1 : 0); | ||
1469 | if (ret < 0) | ||
1470 | return ret; | ||
1471 | |||
1472 | ret = at76_set_pm_mode(priv); | ||
1473 | if (ret < 0) | ||
1474 | return ret; | ||
1475 | |||
1476 | if (at76_debug & DBG_MIB) { | ||
1477 | at76_dump_mib_mac(priv); | ||
1478 | at76_dump_mib_mac_addr(priv); | ||
1479 | at76_dump_mib_mac_mgmt(priv); | ||
1480 | at76_dump_mib_mac_wep(priv); | ||
1481 | at76_dump_mib_mdomain(priv); | ||
1482 | at76_dump_mib_phy(priv); | ||
1483 | at76_dump_mib_local(priv); | ||
1484 | } | ||
1485 | |||
1486 | return 0; | ||
1487 | } | ||
1488 | |||
1489 | /* Enable or disable promiscuous mode */ | ||
1490 | static void at76_work_set_promisc(struct work_struct *work) | ||
1491 | { | ||
1492 | struct at76_priv *priv = container_of(work, struct at76_priv, | ||
1493 | work_set_promisc); | ||
1494 | int ret = 0; | ||
1495 | |||
1496 | if (priv->device_unplugged) | ||
1497 | return; | ||
1498 | |||
1499 | mutex_lock(&priv->mtx); | ||
1500 | |||
1501 | priv->mib_buf.type = MIB_LOCAL; | ||
1502 | priv->mib_buf.size = 1; | ||
1503 | priv->mib_buf.index = offsetof(struct mib_local, promiscuous_mode); | ||
1504 | priv->mib_buf.data.byte = priv->promisc ? 1 : 0; | ||
1505 | |||
1506 | ret = at76_set_mib(priv, &priv->mib_buf); | ||
1507 | if (ret < 0) | ||
1508 | printk(KERN_ERR "%s: set_mib (promiscuous_mode) failed: %d\n", | ||
1509 | wiphy_name(priv->hw->wiphy), ret); | ||
1510 | |||
1511 | mutex_unlock(&priv->mtx); | ||
1512 | } | ||
1513 | |||
1514 | /* Submit Rx urb back to the device */ | ||
1515 | static void at76_work_submit_rx(struct work_struct *work) | ||
1516 | { | ||
1517 | struct at76_priv *priv = container_of(work, struct at76_priv, | ||
1518 | work_submit_rx); | ||
1519 | |||
1520 | mutex_lock(&priv->mtx); | ||
1521 | at76_submit_rx_urb(priv); | ||
1522 | mutex_unlock(&priv->mtx); | ||
1523 | } | ||
1524 | |||
1525 | static void at76_rx_tasklet(unsigned long param) | ||
1526 | { | ||
1527 | struct urb *urb = (struct urb *)param; | ||
1528 | struct at76_priv *priv = urb->context; | ||
1529 | struct at76_rx_buffer *buf; | ||
1530 | struct ieee80211_rx_status rx_status = { 0 }; | ||
1531 | |||
1532 | if (priv->device_unplugged) { | ||
1533 | at76_dbg(DBG_DEVSTART, "device unplugged"); | ||
1534 | if (urb) | ||
1535 | at76_dbg(DBG_DEVSTART, "urb status %d", urb->status); | ||
1536 | return; | ||
1537 | } | ||
1538 | |||
1539 | if (!priv->rx_skb || !priv->rx_skb->data) | ||
1540 | return; | ||
1541 | |||
1542 | buf = (struct at76_rx_buffer *)priv->rx_skb->data; | ||
1543 | |||
1544 | if (urb->status != 0) { | ||
1545 | if (urb->status != -ENOENT && urb->status != -ECONNRESET) | ||
1546 | at76_dbg(DBG_URB, | ||
1547 | "%s %s: - nonzero Rx bulk status received: %d", | ||
1548 | __func__, wiphy_name(priv->hw->wiphy), | ||
1549 | urb->status); | ||
1550 | return; | ||
1551 | } | ||
1552 | |||
1553 | at76_dbg(DBG_RX_ATMEL_HDR, | ||
1554 | "%s: rx frame: rate %d rssi %d noise %d link %d", | ||
1555 | wiphy_name(priv->hw->wiphy), buf->rx_rate, buf->rssi, | ||
1556 | buf->noise_level, buf->link_quality); | ||
1557 | |||
1558 | skb_pull(priv->rx_skb, AT76_RX_HDRLEN); | ||
1559 | skb_trim(priv->rx_skb, le16_to_cpu(buf->wlength)); | ||
1560 | at76_dbg_dump(DBG_RX_DATA, priv->rx_skb->data, | ||
1561 | priv->rx_skb->len, "RX: len=%d", priv->rx_skb->len); | ||
1562 | |||
1563 | rx_status.signal = buf->rssi; | ||
1564 | rx_status.flag |= RX_FLAG_DECRYPTED; | ||
1565 | rx_status.flag |= RX_FLAG_IV_STRIPPED; | ||
1566 | |||
1567 | at76_dbg(DBG_MAC80211, "calling ieee80211_rx_irqsafe(): %d/%d", | ||
1568 | priv->rx_skb->len, priv->rx_skb->data_len); | ||
1569 | ieee80211_rx_irqsafe(priv->hw, priv->rx_skb, &rx_status); | ||
1570 | |||
1571 | /* Use a new skb for the next receive */ | ||
1572 | priv->rx_skb = NULL; | ||
1573 | |||
1574 | at76_submit_rx_urb(priv); | ||
1575 | } | ||
1576 | |||
1577 | /* Load firmware into kernel memory and parse it */ | ||
1578 | static struct fwentry *at76_load_firmware(struct usb_device *udev, | ||
1579 | enum board_type board_type) | ||
1580 | { | ||
1581 | int ret; | ||
1582 | char *str; | ||
1583 | struct at76_fw_header *fwh; | ||
1584 | struct fwentry *fwe = &firmwares[board_type]; | ||
1585 | |||
1586 | mutex_lock(&fw_mutex); | ||
1587 | |||
1588 | if (fwe->loaded) { | ||
1589 | at76_dbg(DBG_FW, "re-using previously loaded fw"); | ||
1590 | goto exit; | ||
1591 | } | ||
1592 | |||
1593 | at76_dbg(DBG_FW, "downloading firmware %s", fwe->fwname); | ||
1594 | ret = request_firmware(&fwe->fw, fwe->fwname, &udev->dev); | ||
1595 | if (ret < 0) { | ||
1596 | dev_printk(KERN_ERR, &udev->dev, "firmware %s not found!\n", | ||
1597 | fwe->fwname); | ||
1598 | dev_printk(KERN_ERR, &udev->dev, | ||
1599 | "you may need to download the firmware from " | ||
1600 | "http://developer.berlios.de/projects/at76c503a/\n"); | ||
1601 | goto exit; | ||
1602 | } | ||
1603 | |||
1604 | at76_dbg(DBG_FW, "got it."); | ||
1605 | fwh = (struct at76_fw_header *)(fwe->fw->data); | ||
1606 | |||
1607 | if (fwe->fw->size <= sizeof(*fwh)) { | ||
1608 | dev_printk(KERN_ERR, &udev->dev, | ||
1609 | "firmware is too short (0x%zx)\n", fwe->fw->size); | ||
1610 | goto exit; | ||
1611 | } | ||
1612 | |||
1613 | /* CRC currently not checked */ | ||
1614 | fwe->board_type = le32_to_cpu(fwh->board_type); | ||
1615 | if (fwe->board_type != board_type) { | ||
1616 | dev_printk(KERN_ERR, &udev->dev, | ||
1617 | "board type mismatch, requested %u, got %u\n", | ||
1618 | board_type, fwe->board_type); | ||
1619 | goto exit; | ||
1620 | } | ||
1621 | |||
1622 | fwe->fw_version.major = fwh->major; | ||
1623 | fwe->fw_version.minor = fwh->minor; | ||
1624 | fwe->fw_version.patch = fwh->patch; | ||
1625 | fwe->fw_version.build = fwh->build; | ||
1626 | |||
1627 | str = (char *)fwh + le32_to_cpu(fwh->str_offset); | ||
1628 | fwe->intfw = (u8 *)fwh + le32_to_cpu(fwh->int_fw_offset); | ||
1629 | fwe->intfw_size = le32_to_cpu(fwh->int_fw_len); | ||
1630 | fwe->extfw = (u8 *)fwh + le32_to_cpu(fwh->ext_fw_offset); | ||
1631 | fwe->extfw_size = le32_to_cpu(fwh->ext_fw_len); | ||
1632 | |||
1633 | fwe->loaded = 1; | ||
1634 | |||
1635 | dev_printk(KERN_DEBUG, &udev->dev, | ||
1636 | "using firmware %s (version %d.%d.%d-%d)\n", | ||
1637 | fwe->fwname, fwh->major, fwh->minor, fwh->patch, fwh->build); | ||
1638 | |||
1639 | at76_dbg(DBG_DEVSTART, "board %u, int %d:%d, ext %d:%d", board_type, | ||
1640 | le32_to_cpu(fwh->int_fw_offset), le32_to_cpu(fwh->int_fw_len), | ||
1641 | le32_to_cpu(fwh->ext_fw_offset), le32_to_cpu(fwh->ext_fw_len)); | ||
1642 | at76_dbg(DBG_DEVSTART, "firmware id %s", str); | ||
1643 | |||
1644 | exit: | ||
1645 | mutex_unlock(&fw_mutex); | ||
1646 | |||
1647 | if (fwe->loaded) | ||
1648 | return fwe; | ||
1649 | else | ||
1650 | return NULL; | ||
1651 | } | ||
1652 | |||
1653 | static void at76_mac80211_tx_callback(struct urb *urb) | ||
1654 | { | ||
1655 | struct at76_priv *priv = urb->context; | ||
1656 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(priv->tx_skb); | ||
1657 | |||
1658 | at76_dbg(DBG_MAC80211, "%s()", __func__); | ||
1659 | |||
1660 | switch (urb->status) { | ||
1661 | case 0: | ||
1662 | /* success */ | ||
1663 | info->flags |= IEEE80211_TX_STAT_ACK; | ||
1664 | break; | ||
1665 | case -ENOENT: | ||
1666 | case -ECONNRESET: | ||
1667 | /* fail, urb has been unlinked */ | ||
1668 | /* FIXME: add error message */ | ||
1669 | break; | ||
1670 | default: | ||
1671 | at76_dbg(DBG_URB, "%s - nonzero tx status received: %d", | ||
1672 | __func__, urb->status); | ||
1673 | break; | ||
1674 | } | ||
1675 | |||
1676 | memset(&info->status, 0, sizeof(info->status)); | ||
1677 | |||
1678 | ieee80211_tx_status_irqsafe(priv->hw, priv->tx_skb); | ||
1679 | |||
1680 | priv->tx_skb = NULL; | ||
1681 | |||
1682 | ieee80211_wake_queues(priv->hw); | ||
1683 | } | ||
1684 | |||
1685 | static int at76_mac80211_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | ||
1686 | { | ||
1687 | struct at76_priv *priv = hw->priv; | ||
1688 | struct at76_tx_buffer *tx_buffer = priv->bulk_out_buffer; | ||
1689 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||
1690 | int padding, submit_len, ret; | ||
1691 | |||
1692 | at76_dbg(DBG_MAC80211, "%s()", __func__); | ||
1693 | |||
1694 | if (priv->tx_urb->status == -EINPROGRESS) { | ||
1695 | printk(KERN_ERR "%s: %s called while tx urb is pending\n", | ||
1696 | wiphy_name(priv->hw->wiphy), __func__); | ||
1697 | return NETDEV_TX_BUSY; | ||
1698 | } | ||
1699 | |||
1700 | ieee80211_stop_queues(hw); | ||
1701 | |||
1702 | at76_ledtrig_tx_activity(); /* tell ledtrigger we send a packet */ | ||
1703 | |||
1704 | WARN_ON(priv->tx_skb != NULL); | ||
1705 | |||
1706 | priv->tx_skb = skb; | ||
1707 | padding = at76_calc_padding(skb->len); | ||
1708 | submit_len = AT76_TX_HDRLEN + skb->len + padding; | ||
1709 | |||
1710 | /* setup 'Atmel' header */ | ||
1711 | memset(tx_buffer, 0, sizeof(*tx_buffer)); | ||
1712 | tx_buffer->padding = padding; | ||
1713 | tx_buffer->wlength = cpu_to_le16(skb->len); | ||
1714 | tx_buffer->tx_rate = ieee80211_get_tx_rate(hw, info)->hw_value; | ||
1715 | memset(tx_buffer->reserved, 0, sizeof(tx_buffer->reserved)); | ||
1716 | memcpy(tx_buffer->packet, skb->data, skb->len); | ||
1717 | |||
1718 | at76_dbg(DBG_TX_DATA, "%s tx: wlen 0x%x pad 0x%x rate %d hdr", | ||
1719 | wiphy_name(priv->hw->wiphy), le16_to_cpu(tx_buffer->wlength), | ||
1720 | tx_buffer->padding, tx_buffer->tx_rate); | ||
1721 | |||
1722 | /* send stuff */ | ||
1723 | at76_dbg_dump(DBG_TX_DATA_CONTENT, tx_buffer, submit_len, | ||
1724 | "%s(): tx_buffer %d bytes:", __func__, submit_len); | ||
1725 | usb_fill_bulk_urb(priv->tx_urb, priv->udev, priv->tx_pipe, tx_buffer, | ||
1726 | submit_len, at76_mac80211_tx_callback, priv); | ||
1727 | ret = usb_submit_urb(priv->tx_urb, GFP_ATOMIC); | ||
1728 | if (ret) { | ||
1729 | printk(KERN_ERR "%s: error in tx submit urb: %d\n", | ||
1730 | wiphy_name(priv->hw->wiphy), ret); | ||
1731 | if (ret == -EINVAL) | ||
1732 | printk(KERN_ERR | ||
1733 | "%s: -EINVAL: tx urb %p hcpriv %p complete %p\n", | ||
1734 | wiphy_name(priv->hw->wiphy), priv->tx_urb, | ||
1735 | priv->tx_urb->hcpriv, priv->tx_urb->complete); | ||
1736 | } | ||
1737 | |||
1738 | return 0; | ||
1739 | } | ||
1740 | |||
1741 | static int at76_mac80211_start(struct ieee80211_hw *hw) | ||
1742 | { | ||
1743 | struct at76_priv *priv = hw->priv; | ||
1744 | int ret; | ||
1745 | |||
1746 | at76_dbg(DBG_MAC80211, "%s()", __func__); | ||
1747 | |||
1748 | mutex_lock(&priv->mtx); | ||
1749 | |||
1750 | ret = at76_submit_rx_urb(priv); | ||
1751 | if (ret < 0) { | ||
1752 | printk(KERN_ERR "%s: open: submit_rx_urb failed: %d\n", | ||
1753 | wiphy_name(priv->hw->wiphy), ret); | ||
1754 | goto error; | ||
1755 | } | ||
1756 | |||
1757 | at76_startup_device(priv); | ||
1758 | |||
1759 | at76_start_monitor(priv); | ||
1760 | |||
1761 | error: | ||
1762 | mutex_unlock(&priv->mtx); | ||
1763 | |||
1764 | return 0; | ||
1765 | } | ||
1766 | |||
1767 | static void at76_mac80211_stop(struct ieee80211_hw *hw) | ||
1768 | { | ||
1769 | struct at76_priv *priv = hw->priv; | ||
1770 | |||
1771 | at76_dbg(DBG_MAC80211, "%s()", __func__); | ||
1772 | |||
1773 | mutex_lock(&priv->mtx); | ||
1774 | |||
1775 | if (!priv->device_unplugged) { | ||
1776 | /* We are called by "ifconfig ethX down", not because the | ||
1777 | * device is not available anymore. */ | ||
1778 | at76_set_radio(priv, 0); | ||
1779 | |||
1780 | /* We unlink rx_urb because at76_open() re-submits it. | ||
1781 | * If unplugged, at76_delete_device() takes care of it. */ | ||
1782 | usb_kill_urb(priv->rx_urb); | ||
1783 | } | ||
1784 | |||
1785 | mutex_unlock(&priv->mtx); | ||
1786 | } | ||
1787 | |||
1788 | static int at76_add_interface(struct ieee80211_hw *hw, | ||
1789 | struct ieee80211_if_init_conf *conf) | ||
1790 | { | ||
1791 | struct at76_priv *priv = hw->priv; | ||
1792 | int ret = 0; | ||
1793 | |||
1794 | at76_dbg(DBG_MAC80211, "%s()", __func__); | ||
1795 | |||
1796 | mutex_lock(&priv->mtx); | ||
1797 | |||
1798 | switch (conf->type) { | ||
1799 | case NL80211_IFTYPE_STATION: | ||
1800 | priv->iw_mode = IW_MODE_INFRA; | ||
1801 | break; | ||
1802 | default: | ||
1803 | ret = -EOPNOTSUPP; | ||
1804 | goto exit; | ||
1805 | } | ||
1806 | |||
1807 | exit: | ||
1808 | mutex_unlock(&priv->mtx); | ||
1809 | |||
1810 | return ret; | ||
1811 | } | ||
1812 | |||
1813 | static void at76_remove_interface(struct ieee80211_hw *hw, | ||
1814 | struct ieee80211_if_init_conf *conf) | ||
1815 | { | ||
1816 | at76_dbg(DBG_MAC80211, "%s()", __func__); | ||
1817 | } | ||
1818 | |||
1819 | static int at76_join(struct at76_priv *priv) | ||
1820 | { | ||
1821 | struct at76_req_join join; | ||
1822 | int ret; | ||
1823 | |||
1824 | memset(&join, 0, sizeof(struct at76_req_join)); | ||
1825 | memcpy(join.essid, priv->essid, priv->essid_size); | ||
1826 | join.essid_size = priv->essid_size; | ||
1827 | memcpy(join.bssid, priv->bssid, ETH_ALEN); | ||
1828 | join.bss_type = INFRASTRUCTURE_MODE; | ||
1829 | join.channel = priv->channel; | ||
1830 | join.timeout = cpu_to_le16(2000); | ||
1831 | |||
1832 | at76_dbg(DBG_MAC80211, "%s: sending CMD_JOIN", __func__); | ||
1833 | ret = at76_set_card_command(priv->udev, CMD_JOIN, &join, | ||
1834 | sizeof(struct at76_req_join)); | ||
1835 | |||
1836 | if (ret < 0) { | ||
1837 | printk(KERN_ERR "%s: at76_set_card_command failed: %d\n", | ||
1838 | wiphy_name(priv->hw->wiphy), ret); | ||
1839 | return 0; | ||
1840 | } | ||
1841 | |||
1842 | ret = at76_wait_completion(priv, CMD_JOIN); | ||
1843 | at76_dbg(DBG_MAC80211, "%s: CMD_JOIN returned: 0x%02x", __func__, ret); | ||
1844 | if (ret != CMD_STATUS_COMPLETE) { | ||
1845 | printk(KERN_ERR "%s: at76_wait_completion failed: %d\n", | ||
1846 | wiphy_name(priv->hw->wiphy), ret); | ||
1847 | return 0; | ||
1848 | } | ||
1849 | |||
1850 | at76_set_pm_mode(priv); | ||
1851 | |||
1852 | return 0; | ||
1853 | } | ||
1854 | |||
1855 | static void at76_dwork_hw_scan(struct work_struct *work) | ||
1856 | { | ||
1857 | struct at76_priv *priv = container_of(work, struct at76_priv, | ||
1858 | dwork_hw_scan.work); | ||
1859 | int ret; | ||
1860 | |||
1861 | if (priv->device_unplugged) | ||
1862 | return; | ||
1863 | |||
1864 | mutex_lock(&priv->mtx); | ||
1865 | |||
1866 | ret = at76_get_cmd_status(priv->udev, CMD_SCAN); | ||
1867 | at76_dbg(DBG_MAC80211, "%s: CMD_SCAN status 0x%02x", __func__, ret); | ||
1868 | |||
1869 | /* FIXME: add maximum time for scan to complete */ | ||
1870 | |||
1871 | if (ret != CMD_STATUS_COMPLETE) { | ||
1872 | queue_delayed_work(priv->hw->workqueue, &priv->dwork_hw_scan, | ||
1873 | SCAN_POLL_INTERVAL); | ||
1874 | goto exit; | ||
1875 | } | ||
1876 | |||
1877 | ieee80211_scan_completed(priv->hw, false); | ||
1878 | |||
1879 | if (is_valid_ether_addr(priv->bssid)) | ||
1880 | at76_join(priv); | ||
1881 | |||
1882 | ieee80211_wake_queues(priv->hw); | ||
1883 | |||
1884 | exit: | ||
1885 | mutex_unlock(&priv->mtx); | ||
1886 | } | ||
1887 | |||
1888 | static int at76_hw_scan(struct ieee80211_hw *hw, | ||
1889 | struct cfg80211_scan_request *req) | ||
1890 | { | ||
1891 | struct at76_priv *priv = hw->priv; | ||
1892 | struct at76_req_scan scan; | ||
1893 | u8 *ssid = NULL; | ||
1894 | int ret, len = 0; | ||
1895 | |||
1896 | at76_dbg(DBG_MAC80211, "%s():", __func__); | ||
1897 | |||
1898 | if (priv->device_unplugged) | ||
1899 | return 0; | ||
1900 | |||
1901 | mutex_lock(&priv->mtx); | ||
1902 | |||
1903 | ieee80211_stop_queues(hw); | ||
1904 | |||
1905 | memset(&scan, 0, sizeof(struct at76_req_scan)); | ||
1906 | memset(scan.bssid, 0xFF, ETH_ALEN); | ||
1907 | |||
1908 | if (req->n_ssids) { | ||
1909 | scan.scan_type = SCAN_TYPE_ACTIVE; | ||
1910 | ssid = req->ssids[0].ssid; | ||
1911 | len = req->ssids[0].ssid_len; | ||
1912 | } else { | ||
1913 | scan.scan_type = SCAN_TYPE_PASSIVE; | ||
1914 | } | ||
1915 | |||
1916 | if (len) { | ||
1917 | memcpy(scan.essid, ssid, len); | ||
1918 | scan.essid_size = len; | ||
1919 | } | ||
1920 | |||
1921 | scan.min_channel_time = cpu_to_le16(priv->scan_min_time); | ||
1922 | scan.max_channel_time = cpu_to_le16(priv->scan_max_time); | ||
1923 | scan.probe_delay = cpu_to_le16(priv->scan_min_time * 1000); | ||
1924 | scan.international_scan = 0; | ||
1925 | |||
1926 | at76_dbg(DBG_MAC80211, "%s: sending CMD_SCAN", __func__); | ||
1927 | ret = at76_set_card_command(priv->udev, CMD_SCAN, &scan, sizeof(scan)); | ||
1928 | |||
1929 | if (ret < 0) { | ||
1930 | err("CMD_SCAN failed: %d", ret); | ||
1931 | goto exit; | ||
1932 | } | ||
1933 | |||
1934 | queue_delayed_work(priv->hw->workqueue, &priv->dwork_hw_scan, | ||
1935 | SCAN_POLL_INTERVAL); | ||
1936 | |||
1937 | exit: | ||
1938 | mutex_unlock(&priv->mtx); | ||
1939 | |||
1940 | return 0; | ||
1941 | } | ||
1942 | |||
1943 | static int at76_config(struct ieee80211_hw *hw, u32 changed) | ||
1944 | { | ||
1945 | struct at76_priv *priv = hw->priv; | ||
1946 | |||
1947 | at76_dbg(DBG_MAC80211, "%s(): channel %d radio %d", | ||
1948 | __func__, hw->conf.channel->hw_value, | ||
1949 | hw->conf.radio_enabled); | ||
1950 | at76_dbg_dump(DBG_MAC80211, priv->bssid, ETH_ALEN, "bssid:"); | ||
1951 | |||
1952 | mutex_lock(&priv->mtx); | ||
1953 | |||
1954 | priv->channel = hw->conf.channel->hw_value; | ||
1955 | |||
1956 | if (is_valid_ether_addr(priv->bssid)) | ||
1957 | at76_join(priv); | ||
1958 | else | ||
1959 | at76_start_monitor(priv); | ||
1960 | |||
1961 | mutex_unlock(&priv->mtx); | ||
1962 | |||
1963 | return 0; | ||
1964 | } | ||
1965 | |||
1966 | static int at76_config_interface(struct ieee80211_hw *hw, | ||
1967 | struct ieee80211_vif *vif, | ||
1968 | struct ieee80211_if_conf *conf) | ||
1969 | { | ||
1970 | struct at76_priv *priv = hw->priv; | ||
1971 | |||
1972 | at76_dbg(DBG_MAC80211, "%s():", __func__); | ||
1973 | at76_dbg_dump(DBG_MAC80211, conf->bssid, ETH_ALEN, "bssid:"); | ||
1974 | |||
1975 | mutex_lock(&priv->mtx); | ||
1976 | |||
1977 | memcpy(priv->bssid, conf->bssid, ETH_ALEN); | ||
1978 | |||
1979 | if (is_valid_ether_addr(priv->bssid)) | ||
1980 | /* mac80211 is joining a bss */ | ||
1981 | at76_join(priv); | ||
1982 | |||
1983 | mutex_unlock(&priv->mtx); | ||
1984 | |||
1985 | return 0; | ||
1986 | } | ||
1987 | |||
1988 | /* must be atomic */ | ||
1989 | static void at76_configure_filter(struct ieee80211_hw *hw, | ||
1990 | unsigned int changed_flags, | ||
1991 | unsigned int *total_flags, int mc_count, | ||
1992 | struct dev_addr_list *mc_list) | ||
1993 | { | ||
1994 | struct at76_priv *priv = hw->priv; | ||
1995 | int flags; | ||
1996 | |||
1997 | at76_dbg(DBG_MAC80211, "%s(): changed_flags=0x%08x " | ||
1998 | "total_flags=0x%08x mc_count=%d", | ||
1999 | __func__, changed_flags, *total_flags, mc_count); | ||
2000 | |||
2001 | flags = changed_flags & AT76_SUPPORTED_FILTERS; | ||
2002 | *total_flags = AT76_SUPPORTED_FILTERS; | ||
2003 | |||
2004 | /* Bail out after updating flags to prevent a WARN_ON in mac80211. */ | ||
2005 | if (priv->device_unplugged) | ||
2006 | return; | ||
2007 | |||
2008 | /* FIXME: access to priv->promisc should be protected with | ||
2009 | * priv->mtx, but it's impossible because this function needs to be | ||
2010 | * atomic */ | ||
2011 | |||
2012 | if (flags && !priv->promisc) { | ||
2013 | /* mac80211 wants us to enable promiscuous mode */ | ||
2014 | priv->promisc = 1; | ||
2015 | } else if (!flags && priv->promisc) { | ||
2016 | /* we need to disable promiscuous mode */ | ||
2017 | priv->promisc = 0; | ||
2018 | } else | ||
2019 | return; | ||
2020 | |||
2021 | queue_work(hw->workqueue, &priv->work_set_promisc); | ||
2022 | } | ||
2023 | |||
2024 | static int at76_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, | ||
2025 | struct ieee80211_vif *vif, struct ieee80211_sta *sta, | ||
2026 | struct ieee80211_key_conf *key) | ||
2027 | { | ||
2028 | struct at76_priv *priv = hw->priv; | ||
2029 | |||
2030 | int i; | ||
2031 | |||
2032 | at76_dbg(DBG_MAC80211, "%s(): cmd %d key->alg %d key->keyidx %d " | ||
2033 | "key->keylen %d", | ||
2034 | __func__, cmd, key->alg, key->keyidx, key->keylen); | ||
2035 | |||
2036 | if (key->alg != ALG_WEP) | ||
2037 | return -EOPNOTSUPP; | ||
2038 | |||
2039 | key->hw_key_idx = key->keyidx; | ||
2040 | |||
2041 | mutex_lock(&priv->mtx); | ||
2042 | |||
2043 | switch (cmd) { | ||
2044 | case SET_KEY: | ||
2045 | memcpy(priv->wep_keys[key->keyidx], key->key, key->keylen); | ||
2046 | priv->wep_keys_len[key->keyidx] = key->keylen; | ||
2047 | |||
2048 | /* FIXME: find out how to do this properly */ | ||
2049 | priv->wep_key_id = key->keyidx; | ||
2050 | |||
2051 | break; | ||
2052 | case DISABLE_KEY: | ||
2053 | default: | ||
2054 | priv->wep_keys_len[key->keyidx] = 0; | ||
2055 | break; | ||
2056 | } | ||
2057 | |||
2058 | priv->wep_enabled = 0; | ||
2059 | |||
2060 | for (i = 0; i < WEP_KEYS; i++) { | ||
2061 | if (priv->wep_keys_len[i] != 0) | ||
2062 | priv->wep_enabled = 1; | ||
2063 | } | ||
2064 | |||
2065 | at76_startup_device(priv); | ||
2066 | |||
2067 | mutex_unlock(&priv->mtx); | ||
2068 | |||
2069 | return 0; | ||
2070 | } | ||
2071 | |||
2072 | static const struct ieee80211_ops at76_ops = { | ||
2073 | .tx = at76_mac80211_tx, | ||
2074 | .add_interface = at76_add_interface, | ||
2075 | .remove_interface = at76_remove_interface, | ||
2076 | .config = at76_config, | ||
2077 | .config_interface = at76_config_interface, | ||
2078 | .configure_filter = at76_configure_filter, | ||
2079 | .start = at76_mac80211_start, | ||
2080 | .stop = at76_mac80211_stop, | ||
2081 | .hw_scan = at76_hw_scan, | ||
2082 | .set_key = at76_set_key, | ||
2083 | }; | ||
2084 | |||
2085 | /* Allocate network device and initialize private data */ | ||
2086 | static struct at76_priv *at76_alloc_new_device(struct usb_device *udev) | ||
2087 | { | ||
2088 | struct ieee80211_hw *hw; | ||
2089 | struct at76_priv *priv; | ||
2090 | |||
2091 | hw = ieee80211_alloc_hw(sizeof(struct at76_priv), &at76_ops); | ||
2092 | if (!hw) { | ||
2093 | printk(KERN_ERR DRIVER_NAME ": could not register" | ||
2094 | " ieee80211_hw\n"); | ||
2095 | return NULL; | ||
2096 | } | ||
2097 | |||
2098 | priv = hw->priv; | ||
2099 | priv->hw = hw; | ||
2100 | |||
2101 | priv->udev = udev; | ||
2102 | |||
2103 | mutex_init(&priv->mtx); | ||
2104 | INIT_WORK(&priv->work_set_promisc, at76_work_set_promisc); | ||
2105 | INIT_WORK(&priv->work_submit_rx, at76_work_submit_rx); | ||
2106 | INIT_DELAYED_WORK(&priv->dwork_hw_scan, at76_dwork_hw_scan); | ||
2107 | |||
2108 | tasklet_init(&priv->rx_tasklet, at76_rx_tasklet, 0); | ||
2109 | |||
2110 | priv->pm_mode = AT76_PM_OFF; | ||
2111 | priv->pm_period = 0; | ||
2112 | |||
2113 | /* unit us */ | ||
2114 | priv->hw->channel_change_time = 100000; | ||
2115 | |||
2116 | return priv; | ||
2117 | } | ||
2118 | |||
2119 | static int at76_alloc_urbs(struct at76_priv *priv, | ||
2120 | struct usb_interface *interface) | ||
2121 | { | ||
2122 | struct usb_endpoint_descriptor *endpoint, *ep_in, *ep_out; | ||
2123 | int i; | ||
2124 | int buffer_size; | ||
2125 | struct usb_host_interface *iface_desc; | ||
2126 | |||
2127 | at76_dbg(DBG_PROC_ENTRY, "%s: ENTER", __func__); | ||
2128 | |||
2129 | at76_dbg(DBG_URB, "%s: NumEndpoints %d ", __func__, | ||
2130 | interface->altsetting[0].desc.bNumEndpoints); | ||
2131 | |||
2132 | ep_in = NULL; | ||
2133 | ep_out = NULL; | ||
2134 | iface_desc = interface->cur_altsetting; | ||
2135 | for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) { | ||
2136 | endpoint = &iface_desc->endpoint[i].desc; | ||
2137 | |||
2138 | at76_dbg(DBG_URB, "%s: %d. endpoint: addr 0x%x attr 0x%x", | ||
2139 | __func__, i, endpoint->bEndpointAddress, | ||
2140 | endpoint->bmAttributes); | ||
2141 | |||
2142 | if (!ep_in && usb_endpoint_is_bulk_in(endpoint)) | ||
2143 | ep_in = endpoint; | ||
2144 | |||
2145 | if (!ep_out && usb_endpoint_is_bulk_out(endpoint)) | ||
2146 | ep_out = endpoint; | ||
2147 | } | ||
2148 | |||
2149 | if (!ep_in || !ep_out) { | ||
2150 | dev_printk(KERN_ERR, &interface->dev, | ||
2151 | "bulk endpoints missing\n"); | ||
2152 | return -ENXIO; | ||
2153 | } | ||
2154 | |||
2155 | priv->rx_pipe = usb_rcvbulkpipe(priv->udev, ep_in->bEndpointAddress); | ||
2156 | priv->tx_pipe = usb_sndbulkpipe(priv->udev, ep_out->bEndpointAddress); | ||
2157 | |||
2158 | priv->rx_urb = usb_alloc_urb(0, GFP_KERNEL); | ||
2159 | priv->tx_urb = usb_alloc_urb(0, GFP_KERNEL); | ||
2160 | if (!priv->rx_urb || !priv->tx_urb) { | ||
2161 | dev_printk(KERN_ERR, &interface->dev, "cannot allocate URB\n"); | ||
2162 | return -ENOMEM; | ||
2163 | } | ||
2164 | |||
2165 | buffer_size = sizeof(struct at76_tx_buffer) + MAX_PADDING_SIZE; | ||
2166 | priv->bulk_out_buffer = kmalloc(buffer_size, GFP_KERNEL); | ||
2167 | if (!priv->bulk_out_buffer) { | ||
2168 | dev_printk(KERN_ERR, &interface->dev, | ||
2169 | "cannot allocate output buffer\n"); | ||
2170 | return -ENOMEM; | ||
2171 | } | ||
2172 | |||
2173 | at76_dbg(DBG_PROC_ENTRY, "%s: EXIT", __func__); | ||
2174 | |||
2175 | return 0; | ||
2176 | } | ||
2177 | |||
2178 | static struct ieee80211_rate at76_rates[] = { | ||
2179 | { .bitrate = 10, .hw_value = TX_RATE_1MBIT, }, | ||
2180 | { .bitrate = 20, .hw_value = TX_RATE_2MBIT, }, | ||
2181 | { .bitrate = 55, .hw_value = TX_RATE_5_5MBIT, }, | ||
2182 | { .bitrate = 110, .hw_value = TX_RATE_11MBIT, }, | ||
2183 | }; | ||
2184 | |||
2185 | static struct ieee80211_channel at76_channels[] = { | ||
2186 | { .center_freq = 2412, .hw_value = 1 }, | ||
2187 | { .center_freq = 2417, .hw_value = 2 }, | ||
2188 | { .center_freq = 2422, .hw_value = 3 }, | ||
2189 | { .center_freq = 2427, .hw_value = 4 }, | ||
2190 | { .center_freq = 2432, .hw_value = 5 }, | ||
2191 | { .center_freq = 2437, .hw_value = 6 }, | ||
2192 | { .center_freq = 2442, .hw_value = 7 }, | ||
2193 | { .center_freq = 2447, .hw_value = 8 }, | ||
2194 | { .center_freq = 2452, .hw_value = 9 }, | ||
2195 | { .center_freq = 2457, .hw_value = 10 }, | ||
2196 | { .center_freq = 2462, .hw_value = 11 }, | ||
2197 | { .center_freq = 2467, .hw_value = 12 }, | ||
2198 | { .center_freq = 2472, .hw_value = 13 }, | ||
2199 | { .center_freq = 2484, .hw_value = 14 } | ||
2200 | }; | ||
2201 | |||
2202 | static struct ieee80211_supported_band at76_supported_band = { | ||
2203 | .channels = at76_channels, | ||
2204 | .n_channels = ARRAY_SIZE(at76_channels), | ||
2205 | .bitrates = at76_rates, | ||
2206 | .n_bitrates = ARRAY_SIZE(at76_rates), | ||
2207 | }; | ||
2208 | |||
2209 | /* Register network device and initialize the hardware */ | ||
2210 | static int at76_init_new_device(struct at76_priv *priv, | ||
2211 | struct usb_interface *interface) | ||
2212 | { | ||
2213 | int ret; | ||
2214 | |||
2215 | /* set up the endpoint information */ | ||
2216 | /* check out the endpoints */ | ||
2217 | |||
2218 | at76_dbg(DBG_DEVSTART, "USB interface: %d endpoints", | ||
2219 | interface->cur_altsetting->desc.bNumEndpoints); | ||
2220 | |||
2221 | ret = at76_alloc_urbs(priv, interface); | ||
2222 | if (ret < 0) | ||
2223 | goto exit; | ||
2224 | |||
2225 | /* MAC address */ | ||
2226 | ret = at76_get_hw_config(priv); | ||
2227 | if (ret < 0) { | ||
2228 | dev_printk(KERN_ERR, &interface->dev, | ||
2229 | "cannot get MAC address\n"); | ||
2230 | goto exit; | ||
2231 | } | ||
2232 | |||
2233 | priv->domain = at76_get_reg_domain(priv->regulatory_domain); | ||
2234 | |||
2235 | priv->channel = DEF_CHANNEL; | ||
2236 | priv->iw_mode = IW_MODE_INFRA; | ||
2237 | priv->rts_threshold = DEF_RTS_THRESHOLD; | ||
2238 | priv->frag_threshold = DEF_FRAG_THRESHOLD; | ||
2239 | priv->short_retry_limit = DEF_SHORT_RETRY_LIMIT; | ||
2240 | priv->txrate = TX_RATE_AUTO; | ||
2241 | priv->preamble_type = PREAMBLE_TYPE_LONG; | ||
2242 | priv->beacon_period = 100; | ||
2243 | priv->auth_mode = WLAN_AUTH_OPEN; | ||
2244 | priv->scan_min_time = DEF_SCAN_MIN_TIME; | ||
2245 | priv->scan_max_time = DEF_SCAN_MAX_TIME; | ||
2246 | priv->scan_mode = SCAN_TYPE_ACTIVE; | ||
2247 | priv->device_unplugged = 0; | ||
2248 | |||
2249 | /* mac80211 initialisation */ | ||
2250 | priv->hw->wiphy->max_scan_ssids = 1; | ||
2251 | priv->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); | ||
2252 | priv->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &at76_supported_band; | ||
2253 | priv->hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | | ||
2254 | IEEE80211_HW_SIGNAL_UNSPEC; | ||
2255 | priv->hw->max_signal = 100; | ||
2256 | |||
2257 | SET_IEEE80211_DEV(priv->hw, &interface->dev); | ||
2258 | SET_IEEE80211_PERM_ADDR(priv->hw, priv->mac_addr); | ||
2259 | |||
2260 | ret = ieee80211_register_hw(priv->hw); | ||
2261 | if (ret) { | ||
2262 | printk(KERN_ERR "cannot register mac80211 hw (status %d)!\n", | ||
2263 | ret); | ||
2264 | goto exit; | ||
2265 | } | ||
2266 | |||
2267 | priv->mac80211_registered = 1; | ||
2268 | |||
2269 | printk(KERN_INFO "%s: USB %s, MAC %s, firmware %d.%d.%d-%d\n", | ||
2270 | wiphy_name(priv->hw->wiphy), | ||
2271 | dev_name(&interface->dev), mac2str(priv->mac_addr), | ||
2272 | priv->fw_version.major, priv->fw_version.minor, | ||
2273 | priv->fw_version.patch, priv->fw_version.build); | ||
2274 | printk(KERN_INFO "%s: regulatory domain 0x%02x: %s\n", | ||
2275 | wiphy_name(priv->hw->wiphy), | ||
2276 | priv->regulatory_domain, priv->domain->name); | ||
2277 | |||
2278 | exit: | ||
2279 | return ret; | ||
2280 | } | ||
2281 | |||
2282 | static void at76_delete_device(struct at76_priv *priv) | ||
2283 | { | ||
2284 | at76_dbg(DBG_PROC_ENTRY, "%s: ENTER", __func__); | ||
2285 | |||
2286 | /* The device is gone, don't bother turning it off */ | ||
2287 | priv->device_unplugged = 1; | ||
2288 | |||
2289 | tasklet_kill(&priv->rx_tasklet); | ||
2290 | |||
2291 | if (priv->mac80211_registered) { | ||
2292 | cancel_delayed_work(&priv->dwork_hw_scan); | ||
2293 | flush_workqueue(priv->hw->workqueue); | ||
2294 | ieee80211_unregister_hw(priv->hw); | ||
2295 | } | ||
2296 | |||
2297 | if (priv->tx_urb) { | ||
2298 | usb_kill_urb(priv->tx_urb); | ||
2299 | usb_free_urb(priv->tx_urb); | ||
2300 | } | ||
2301 | if (priv->rx_urb) { | ||
2302 | usb_kill_urb(priv->rx_urb); | ||
2303 | usb_free_urb(priv->rx_urb); | ||
2304 | } | ||
2305 | |||
2306 | at76_dbg(DBG_PROC_ENTRY, "%s: unlinked urbs", __func__); | ||
2307 | |||
2308 | kfree(priv->bulk_out_buffer); | ||
2309 | |||
2310 | del_timer_sync(&ledtrig_tx_timer); | ||
2311 | |||
2312 | if (priv->rx_skb) | ||
2313 | kfree_skb(priv->rx_skb); | ||
2314 | |||
2315 | usb_put_dev(priv->udev); | ||
2316 | |||
2317 | at76_dbg(DBG_PROC_ENTRY, "%s: before freeing priv/ieee80211_hw", | ||
2318 | __func__); | ||
2319 | ieee80211_free_hw(priv->hw); | ||
2320 | |||
2321 | at76_dbg(DBG_PROC_ENTRY, "%s: EXIT", __func__); | ||
2322 | } | ||
2323 | |||
2324 | static int at76_probe(struct usb_interface *interface, | ||
2325 | const struct usb_device_id *id) | ||
2326 | { | ||
2327 | int ret; | ||
2328 | struct at76_priv *priv; | ||
2329 | struct fwentry *fwe; | ||
2330 | struct usb_device *udev; | ||
2331 | int op_mode; | ||
2332 | int need_ext_fw = 0; | ||
2333 | struct mib_fw_version fwv; | ||
2334 | int board_type = (int)id->driver_info; | ||
2335 | |||
2336 | udev = usb_get_dev(interface_to_usbdev(interface)); | ||
2337 | |||
2338 | /* Load firmware into kernel memory */ | ||
2339 | fwe = at76_load_firmware(udev, board_type); | ||
2340 | if (!fwe) { | ||
2341 | ret = -ENOENT; | ||
2342 | goto error; | ||
2343 | } | ||
2344 | |||
2345 | op_mode = at76_get_op_mode(udev); | ||
2346 | |||
2347 | at76_dbg(DBG_DEVSTART, "opmode %d", op_mode); | ||
2348 | |||
2349 | /* we get OPMODE_NONE with 2.4.23, SMC2662W-AR ??? | ||
2350 | we get 204 with 2.4.23, Fiberline FL-WL240u (505A+RFMD2958) ??? */ | ||
2351 | |||
2352 | if (op_mode == OPMODE_HW_CONFIG_MODE) { | ||
2353 | dev_printk(KERN_ERR, &interface->dev, | ||
2354 | "cannot handle a device in HW_CONFIG_MODE\n"); | ||
2355 | ret = -EBUSY; | ||
2356 | goto error; | ||
2357 | } | ||
2358 | |||
2359 | if (op_mode != OPMODE_NORMAL_NIC_WITH_FLASH | ||
2360 | && op_mode != OPMODE_NORMAL_NIC_WITHOUT_FLASH) { | ||
2361 | /* download internal firmware part */ | ||
2362 | dev_printk(KERN_DEBUG, &interface->dev, | ||
2363 | "downloading internal firmware\n"); | ||
2364 | ret = at76_load_internal_fw(udev, fwe); | ||
2365 | if (ret < 0) { | ||
2366 | dev_printk(KERN_ERR, &interface->dev, | ||
2367 | "error %d downloading internal firmware\n", | ||
2368 | ret); | ||
2369 | goto error; | ||
2370 | } | ||
2371 | usb_put_dev(udev); | ||
2372 | return ret; | ||
2373 | } | ||
2374 | |||
2375 | /* Internal firmware already inside the device. Get firmware | ||
2376 | * version to test if external firmware is loaded. | ||
2377 | * This works only for newer firmware, e.g. the Intersil 0.90.x | ||
2378 | * says "control timeout on ep0in" and subsequent | ||
2379 | * at76_get_op_mode() fail too :-( */ | ||
2380 | |||
2381 | /* if version >= 0.100.x.y or device with built-in flash we can | ||
2382 | * query the device for the fw version */ | ||
2383 | if ((fwe->fw_version.major > 0 || fwe->fw_version.minor >= 100) | ||
2384 | || (op_mode == OPMODE_NORMAL_NIC_WITH_FLASH)) { | ||
2385 | ret = at76_get_mib(udev, MIB_FW_VERSION, &fwv, sizeof(fwv)); | ||
2386 | if (ret < 0 || (fwv.major | fwv.minor) == 0) | ||
2387 | need_ext_fw = 1; | ||
2388 | } else | ||
2389 | /* No way to check firmware version, reload to be sure */ | ||
2390 | need_ext_fw = 1; | ||
2391 | |||
2392 | if (need_ext_fw) { | ||
2393 | dev_printk(KERN_DEBUG, &interface->dev, | ||
2394 | "downloading external firmware\n"); | ||
2395 | |||
2396 | ret = at76_load_external_fw(udev, fwe); | ||
2397 | if (ret) | ||
2398 | goto error; | ||
2399 | |||
2400 | /* Re-check firmware version */ | ||
2401 | ret = at76_get_mib(udev, MIB_FW_VERSION, &fwv, sizeof(fwv)); | ||
2402 | if (ret < 0) { | ||
2403 | dev_printk(KERN_ERR, &interface->dev, | ||
2404 | "error %d getting firmware version\n", ret); | ||
2405 | goto error; | ||
2406 | } | ||
2407 | } | ||
2408 | |||
2409 | priv = at76_alloc_new_device(udev); | ||
2410 | if (!priv) { | ||
2411 | ret = -ENOMEM; | ||
2412 | goto error; | ||
2413 | } | ||
2414 | |||
2415 | usb_set_intfdata(interface, priv); | ||
2416 | |||
2417 | memcpy(&priv->fw_version, &fwv, sizeof(struct mib_fw_version)); | ||
2418 | priv->board_type = board_type; | ||
2419 | |||
2420 | ret = at76_init_new_device(priv, interface); | ||
2421 | if (ret < 0) | ||
2422 | at76_delete_device(priv); | ||
2423 | |||
2424 | return ret; | ||
2425 | |||
2426 | error: | ||
2427 | usb_put_dev(udev); | ||
2428 | return ret; | ||
2429 | } | ||
2430 | |||
2431 | static void at76_disconnect(struct usb_interface *interface) | ||
2432 | { | ||
2433 | struct at76_priv *priv; | ||
2434 | |||
2435 | priv = usb_get_intfdata(interface); | ||
2436 | usb_set_intfdata(interface, NULL); | ||
2437 | |||
2438 | /* Disconnect after loading internal firmware */ | ||
2439 | if (!priv) | ||
2440 | return; | ||
2441 | |||
2442 | printk(KERN_INFO "%s: disconnecting\n", wiphy_name(priv->hw->wiphy)); | ||
2443 | at76_delete_device(priv); | ||
2444 | dev_printk(KERN_INFO, &interface->dev, "disconnected\n"); | ||
2445 | } | ||
2446 | |||
2447 | /* Structure for registering this driver with the USB subsystem */ | ||
2448 | static struct usb_driver at76_driver = { | ||
2449 | .name = DRIVER_NAME, | ||
2450 | .probe = at76_probe, | ||
2451 | .disconnect = at76_disconnect, | ||
2452 | .id_table = dev_table, | ||
2453 | }; | ||
2454 | |||
2455 | static int __init at76_mod_init(void) | ||
2456 | { | ||
2457 | int result; | ||
2458 | |||
2459 | printk(KERN_INFO DRIVER_DESC " " DRIVER_VERSION " loading\n"); | ||
2460 | |||
2461 | mutex_init(&fw_mutex); | ||
2462 | |||
2463 | /* register this driver with the USB subsystem */ | ||
2464 | result = usb_register(&at76_driver); | ||
2465 | if (result < 0) | ||
2466 | printk(KERN_ERR DRIVER_NAME | ||
2467 | ": usb_register failed (status %d)\n", result); | ||
2468 | |||
2469 | led_trigger_register_simple("at76_usb-tx", &ledtrig_tx); | ||
2470 | return result; | ||
2471 | } | ||
2472 | |||
2473 | static void __exit at76_mod_exit(void) | ||
2474 | { | ||
2475 | int i; | ||
2476 | |||
2477 | printk(KERN_INFO DRIVER_DESC " " DRIVER_VERSION " unloading\n"); | ||
2478 | usb_deregister(&at76_driver); | ||
2479 | for (i = 0; i < ARRAY_SIZE(firmwares); i++) { | ||
2480 | if (firmwares[i].fw) | ||
2481 | release_firmware(firmwares[i].fw); | ||
2482 | } | ||
2483 | led_trigger_unregister_simple(ledtrig_tx); | ||
2484 | } | ||
2485 | |||
2486 | module_param_named(debug, at76_debug, uint, 0600); | ||
2487 | MODULE_PARM_DESC(debug, "Debugging level"); | ||
2488 | |||
2489 | module_init(at76_mod_init); | ||
2490 | module_exit(at76_mod_exit); | ||
2491 | |||
2492 | MODULE_AUTHOR("Oliver Kurth <oku@masqmail.cx>"); | ||
2493 | MODULE_AUTHOR("Joerg Albert <joerg.albert@gmx.de>"); | ||
2494 | MODULE_AUTHOR("Alex <alex@foogod.com>"); | ||
2495 | MODULE_AUTHOR("Nick Jones"); | ||
2496 | MODULE_AUTHOR("Balint Seeber <n0_5p4m_p13453@hotmail.com>"); | ||
2497 | MODULE_AUTHOR("Pavel Roskin <proski@gnu.org>"); | ||
2498 | MODULE_AUTHOR("Guido Guenther <agx@sigxcpu.org>"); | ||
2499 | MODULE_AUTHOR("Kalle Valo <kalle.valo@iki.fi>"); | ||
2500 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
2501 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/net/wireless/at76c50x-usb.h b/drivers/net/wireless/at76c50x-usb.h new file mode 100644 index 000000000000..1ec5ccffdbc0 --- /dev/null +++ b/drivers/net/wireless/at76c50x-usb.h | |||
@@ -0,0 +1,463 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2002,2003 Oliver Kurth | ||
3 | * (c) 2003,2004 Joerg Albert <joerg.albert@gmx.de> | ||
4 | * (c) 2007 Guido Guenther <agx@sigxcpu.org> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License as | ||
8 | * published by the Free Software Foundation; either version 2 of | ||
9 | * the License, or (at your option) any later version. | ||
10 | * | ||
11 | * This driver was based on information from the Sourceforge driver | ||
12 | * released and maintained by Atmel: | ||
13 | * | ||
14 | * http://sourceforge.net/projects/atmelwlandriver/ | ||
15 | * | ||
16 | * Although the code was completely re-written, | ||
17 | * it would have been impossible without Atmel's decision to | ||
18 | * release an Open Source driver (unfortunately the firmware was | ||
19 | * kept binary only). Thanks for that decision to Atmel! | ||
20 | */ | ||
21 | |||
22 | #ifndef _AT76_USB_H | ||
23 | #define _AT76_USB_H | ||
24 | |||
25 | /* Board types */ | ||
26 | enum board_type { | ||
27 | BOARD_503_ISL3861 = 1, | ||
28 | BOARD_503_ISL3863 = 2, | ||
29 | BOARD_503 = 3, | ||
30 | BOARD_503_ACC = 4, | ||
31 | BOARD_505 = 5, | ||
32 | BOARD_505_2958 = 6, | ||
33 | BOARD_505A = 7, | ||
34 | BOARD_505AMX = 8 | ||
35 | }; | ||
36 | |||
37 | #define CMD_STATUS_IDLE 0x00 | ||
38 | #define CMD_STATUS_COMPLETE 0x01 | ||
39 | #define CMD_STATUS_UNKNOWN 0x02 | ||
40 | #define CMD_STATUS_INVALID_PARAMETER 0x03 | ||
41 | #define CMD_STATUS_FUNCTION_NOT_SUPPORTED 0x04 | ||
42 | #define CMD_STATUS_TIME_OUT 0x07 | ||
43 | #define CMD_STATUS_IN_PROGRESS 0x08 | ||
44 | #define CMD_STATUS_HOST_FAILURE 0xff | ||
45 | #define CMD_STATUS_SCAN_FAILED 0xf0 | ||
46 | |||
47 | /* answers to get op mode */ | ||
48 | #define OPMODE_NONE 0x00 | ||
49 | #define OPMODE_NORMAL_NIC_WITH_FLASH 0x01 | ||
50 | #define OPMODE_HW_CONFIG_MODE 0x02 | ||
51 | #define OPMODE_DFU_MODE_WITH_FLASH 0x03 | ||
52 | #define OPMODE_NORMAL_NIC_WITHOUT_FLASH 0x04 | ||
53 | |||
54 | #define CMD_SET_MIB 0x01 | ||
55 | #define CMD_GET_MIB 0x02 | ||
56 | #define CMD_SCAN 0x03 | ||
57 | #define CMD_JOIN 0x04 | ||
58 | #define CMD_START_IBSS 0x05 | ||
59 | #define CMD_RADIO_ON 0x06 | ||
60 | #define CMD_RADIO_OFF 0x07 | ||
61 | #define CMD_STARTUP 0x0B | ||
62 | |||
63 | #define MIB_LOCAL 0x01 | ||
64 | #define MIB_MAC_ADDR 0x02 | ||
65 | #define MIB_MAC 0x03 | ||
66 | #define MIB_MAC_MGMT 0x05 | ||
67 | #define MIB_MAC_WEP 0x06 | ||
68 | #define MIB_PHY 0x07 | ||
69 | #define MIB_FW_VERSION 0x08 | ||
70 | #define MIB_MDOMAIN 0x09 | ||
71 | |||
72 | #define ADHOC_MODE 1 | ||
73 | #define INFRASTRUCTURE_MODE 2 | ||
74 | |||
75 | /* values for struct mib_local, field preamble_type */ | ||
76 | #define PREAMBLE_TYPE_LONG 0 | ||
77 | #define PREAMBLE_TYPE_SHORT 1 | ||
78 | #define PREAMBLE_TYPE_AUTO 2 | ||
79 | |||
80 | /* values for tx_rate */ | ||
81 | #define TX_RATE_1MBIT 0 | ||
82 | #define TX_RATE_2MBIT 1 | ||
83 | #define TX_RATE_5_5MBIT 2 | ||
84 | #define TX_RATE_11MBIT 3 | ||
85 | #define TX_RATE_AUTO 4 | ||
86 | |||
87 | /* power management modes */ | ||
88 | #define AT76_PM_OFF 1 | ||
89 | #define AT76_PM_ON 2 | ||
90 | #define AT76_PM_SMART 3 | ||
91 | |||
92 | struct hwcfg_r505 { | ||
93 | u8 cr39_values[14]; | ||
94 | u8 reserved1[14]; | ||
95 | u8 bb_cr[14]; | ||
96 | u8 pidvid[4]; | ||
97 | u8 mac_addr[ETH_ALEN]; | ||
98 | u8 regulatory_domain; | ||
99 | u8 reserved2[14]; | ||
100 | u8 cr15_values[14]; | ||
101 | u8 reserved3[3]; | ||
102 | } __attribute__((packed)); | ||
103 | |||
104 | struct hwcfg_rfmd { | ||
105 | u8 cr20_values[14]; | ||
106 | u8 cr21_values[14]; | ||
107 | u8 bb_cr[14]; | ||
108 | u8 pidvid[4]; | ||
109 | u8 mac_addr[ETH_ALEN]; | ||
110 | u8 regulatory_domain; | ||
111 | u8 low_power_values[14]; | ||
112 | u8 normal_power_values[14]; | ||
113 | u8 reserved1[3]; | ||
114 | } __attribute__((packed)); | ||
115 | |||
116 | struct hwcfg_intersil { | ||
117 | u8 mac_addr[ETH_ALEN]; | ||
118 | u8 cr31_values[14]; | ||
119 | u8 cr58_values[14]; | ||
120 | u8 pidvid[4]; | ||
121 | u8 regulatory_domain; | ||
122 | u8 reserved[1]; | ||
123 | } __attribute__((packed)); | ||
124 | |||
125 | union at76_hwcfg { | ||
126 | struct hwcfg_intersil i; | ||
127 | struct hwcfg_rfmd r3; | ||
128 | struct hwcfg_r505 r5; | ||
129 | }; | ||
130 | |||
131 | #define WEP_SMALL_KEY_LEN (40 / 8) | ||
132 | #define WEP_LARGE_KEY_LEN (104 / 8) | ||
133 | #define WEP_KEYS (4) | ||
134 | |||
135 | struct at76_card_config { | ||
136 | u8 exclude_unencrypted; | ||
137 | u8 promiscuous_mode; | ||
138 | u8 short_retry_limit; | ||
139 | u8 encryption_type; | ||
140 | __le16 rts_threshold; | ||
141 | __le16 fragmentation_threshold; /* 256..2346 */ | ||
142 | u8 basic_rate_set[4]; | ||
143 | u8 auto_rate_fallback; /* 0,1 */ | ||
144 | u8 channel; | ||
145 | u8 privacy_invoked; | ||
146 | u8 wep_default_key_id; /* 0..3 */ | ||
147 | u8 current_ssid[32]; | ||
148 | u8 wep_default_key_value[4][WEP_LARGE_KEY_LEN]; | ||
149 | u8 ssid_len; | ||
150 | u8 short_preamble; | ||
151 | __le16 beacon_period; | ||
152 | } __attribute__((packed)); | ||
153 | |||
154 | struct at76_command { | ||
155 | u8 cmd; | ||
156 | u8 reserved; | ||
157 | __le16 size; | ||
158 | u8 data[0]; | ||
159 | } __attribute__((packed)); | ||
160 | |||
161 | /* Length of Atmel-specific Rx header before 802.11 frame */ | ||
162 | #define AT76_RX_HDRLEN offsetof(struct at76_rx_buffer, packet) | ||
163 | |||
164 | struct at76_rx_buffer { | ||
165 | __le16 wlength; | ||
166 | u8 rx_rate; | ||
167 | u8 newbss; | ||
168 | u8 fragmentation; | ||
169 | u8 rssi; | ||
170 | u8 link_quality; | ||
171 | u8 noise_level; | ||
172 | __le32 rx_time; | ||
173 | u8 packet[IEEE80211_MAX_FRAG_THRESHOLD]; | ||
174 | } __attribute__((packed)); | ||
175 | |||
176 | /* Length of Atmel-specific Tx header before 802.11 frame */ | ||
177 | #define AT76_TX_HDRLEN offsetof(struct at76_tx_buffer, packet) | ||
178 | |||
179 | struct at76_tx_buffer { | ||
180 | __le16 wlength; | ||
181 | u8 tx_rate; | ||
182 | u8 padding; | ||
183 | u8 reserved[4]; | ||
184 | u8 packet[IEEE80211_MAX_FRAG_THRESHOLD]; | ||
185 | } __attribute__((packed)); | ||
186 | |||
187 | /* defines for scan_type below */ | ||
188 | #define SCAN_TYPE_ACTIVE 0 | ||
189 | #define SCAN_TYPE_PASSIVE 1 | ||
190 | |||
191 | struct at76_req_scan { | ||
192 | u8 bssid[ETH_ALEN]; | ||
193 | u8 essid[32]; | ||
194 | u8 scan_type; | ||
195 | u8 channel; | ||
196 | __le16 probe_delay; | ||
197 | __le16 min_channel_time; | ||
198 | __le16 max_channel_time; | ||
199 | u8 essid_size; | ||
200 | u8 international_scan; | ||
201 | } __attribute__((packed)); | ||
202 | |||
203 | struct at76_req_ibss { | ||
204 | u8 bssid[ETH_ALEN]; | ||
205 | u8 essid[32]; | ||
206 | u8 bss_type; | ||
207 | u8 channel; | ||
208 | u8 essid_size; | ||
209 | u8 reserved[3]; | ||
210 | } __attribute__((packed)); | ||
211 | |||
212 | struct at76_req_join { | ||
213 | u8 bssid[ETH_ALEN]; | ||
214 | u8 essid[32]; | ||
215 | u8 bss_type; | ||
216 | u8 channel; | ||
217 | __le16 timeout; | ||
218 | u8 essid_size; | ||
219 | u8 reserved; | ||
220 | } __attribute__((packed)); | ||
221 | |||
222 | struct set_mib_buffer { | ||
223 | u8 type; | ||
224 | u8 size; | ||
225 | u8 index; | ||
226 | u8 reserved; | ||
227 | union { | ||
228 | u8 byte; | ||
229 | __le16 word; | ||
230 | u8 addr[ETH_ALEN]; | ||
231 | } data; | ||
232 | } __attribute__((packed)); | ||
233 | |||
234 | struct mib_local { | ||
235 | u16 reserved0; | ||
236 | u8 beacon_enable; | ||
237 | u8 txautorate_fallback; | ||
238 | u8 reserved1; | ||
239 | u8 ssid_size; | ||
240 | u8 promiscuous_mode; | ||
241 | u16 reserved2; | ||
242 | u8 preamble_type; | ||
243 | u16 reserved3; | ||
244 | } __attribute__((packed)); | ||
245 | |||
246 | struct mib_mac_addr { | ||
247 | u8 mac_addr[ETH_ALEN]; | ||
248 | u8 res[2]; /* ??? */ | ||
249 | u8 group_addr[4][ETH_ALEN]; | ||
250 | u8 group_addr_status[4]; | ||
251 | } __attribute__((packed)); | ||
252 | |||
253 | struct mib_mac { | ||
254 | __le32 max_tx_msdu_lifetime; | ||
255 | __le32 max_rx_lifetime; | ||
256 | __le16 frag_threshold; | ||
257 | __le16 rts_threshold; | ||
258 | __le16 cwmin; | ||
259 | __le16 cwmax; | ||
260 | u8 short_retry_time; | ||
261 | u8 long_retry_time; | ||
262 | u8 scan_type; /* active or passive */ | ||
263 | u8 scan_channel; | ||
264 | __le16 probe_delay; /* delay before ProbeReq in active scan, RO */ | ||
265 | __le16 min_channel_time; | ||
266 | __le16 max_channel_time; | ||
267 | __le16 listen_interval; | ||
268 | u8 desired_ssid[32]; | ||
269 | u8 desired_bssid[ETH_ALEN]; | ||
270 | u8 desired_bsstype; /* ad-hoc or infrastructure */ | ||
271 | u8 reserved2; | ||
272 | } __attribute__((packed)); | ||
273 | |||
274 | struct mib_mac_mgmt { | ||
275 | __le16 beacon_period; | ||
276 | __le16 CFP_max_duration; | ||
277 | __le16 medium_occupancy_limit; | ||
278 | __le16 station_id; /* assoc id */ | ||
279 | __le16 ATIM_window; | ||
280 | u8 CFP_mode; | ||
281 | u8 privacy_option_implemented; | ||
282 | u8 DTIM_period; | ||
283 | u8 CFP_period; | ||
284 | u8 current_bssid[ETH_ALEN]; | ||
285 | u8 current_essid[32]; | ||
286 | u8 current_bss_type; | ||
287 | u8 power_mgmt_mode; | ||
288 | /* rfmd and 505 */ | ||
289 | u8 ibss_change; | ||
290 | u8 res; | ||
291 | u8 multi_domain_capability_implemented; | ||
292 | u8 multi_domain_capability_enabled; | ||
293 | u8 country_string[3]; | ||
294 | u8 reserved[3]; | ||
295 | } __attribute__((packed)); | ||
296 | |||
297 | struct mib_mac_wep { | ||
298 | u8 privacy_invoked; /* 0 disable encr., 1 enable encr */ | ||
299 | u8 wep_default_key_id; | ||
300 | u8 wep_key_mapping_len; | ||
301 | u8 exclude_unencrypted; | ||
302 | __le32 wep_icv_error_count; | ||
303 | __le32 wep_excluded_count; | ||
304 | u8 wep_default_keyvalue[WEP_KEYS][WEP_LARGE_KEY_LEN]; | ||
305 | u8 encryption_level; /* 1 for 40bit, 2 for 104bit encryption */ | ||
306 | } __attribute__((packed)); | ||
307 | |||
308 | struct mib_phy { | ||
309 | __le32 ed_threshold; | ||
310 | |||
311 | __le16 slot_time; | ||
312 | __le16 sifs_time; | ||
313 | __le16 preamble_length; | ||
314 | __le16 plcp_header_length; | ||
315 | __le16 mpdu_max_length; | ||
316 | __le16 cca_mode_supported; | ||
317 | |||
318 | u8 operation_rate_set[4]; | ||
319 | u8 channel_id; | ||
320 | u8 current_cca_mode; | ||
321 | u8 phy_type; | ||
322 | u8 current_reg_domain; | ||
323 | } __attribute__((packed)); | ||
324 | |||
325 | struct mib_fw_version { | ||
326 | u8 major; | ||
327 | u8 minor; | ||
328 | u8 patch; | ||
329 | u8 build; | ||
330 | } __attribute__((packed)); | ||
331 | |||
332 | struct mib_mdomain { | ||
333 | u8 tx_powerlevel[14]; | ||
334 | u8 channel_list[14]; /* 0 for invalid channels */ | ||
335 | } __attribute__((packed)); | ||
336 | |||
337 | struct at76_fw_header { | ||
338 | __le32 crc; /* CRC32 of the whole image */ | ||
339 | __le32 board_type; /* firmware compatibility code */ | ||
340 | u8 build; /* firmware build number */ | ||
341 | u8 patch; /* firmware patch level */ | ||
342 | u8 minor; /* firmware minor version */ | ||
343 | u8 major; /* firmware major version */ | ||
344 | __le32 str_offset; /* offset of the copyright string */ | ||
345 | __le32 int_fw_offset; /* internal firmware image offset */ | ||
346 | __le32 int_fw_len; /* internal firmware image length */ | ||
347 | __le32 ext_fw_offset; /* external firmware image offset */ | ||
348 | __le32 ext_fw_len; /* external firmware image length */ | ||
349 | } __attribute__((packed)); | ||
350 | |||
351 | /* a description of a regulatory domain and the allowed channels */ | ||
352 | struct reg_domain { | ||
353 | u16 code; | ||
354 | char const *name; | ||
355 | u32 channel_map; /* if bit N is set, channel (N+1) is allowed */ | ||
356 | }; | ||
357 | |||
358 | /* Data for one loaded firmware file */ | ||
359 | struct fwentry { | ||
360 | const char *const fwname; | ||
361 | const struct firmware *fw; | ||
362 | int extfw_size; | ||
363 | int intfw_size; | ||
364 | /* pointer to loaded firmware, no need to free */ | ||
365 | u8 *extfw; /* external firmware, extfw_size bytes long */ | ||
366 | u8 *intfw; /* internal firmware, intfw_size bytes long */ | ||
367 | enum board_type board_type; /* board type */ | ||
368 | struct mib_fw_version fw_version; | ||
369 | int loaded; /* Loaded and parsed successfully */ | ||
370 | }; | ||
371 | |||
372 | struct at76_priv { | ||
373 | struct usb_device *udev; /* USB device pointer */ | ||
374 | |||
375 | struct sk_buff *rx_skb; /* skbuff for receiving data */ | ||
376 | struct sk_buff *tx_skb; /* skbuff for transmitting data */ | ||
377 | void *bulk_out_buffer; /* buffer for sending data */ | ||
378 | |||
379 | struct urb *tx_urb; /* URB for sending data */ | ||
380 | struct urb *rx_urb; /* URB for receiving data */ | ||
381 | |||
382 | unsigned int tx_pipe; /* bulk out pipe */ | ||
383 | unsigned int rx_pipe; /* bulk in pipe */ | ||
384 | |||
385 | struct mutex mtx; /* locks this structure */ | ||
386 | |||
387 | /* work queues */ | ||
388 | struct work_struct work_set_promisc; | ||
389 | struct work_struct work_submit_rx; | ||
390 | struct delayed_work dwork_hw_scan; | ||
391 | |||
392 | struct tasklet_struct rx_tasklet; | ||
393 | |||
394 | /* the WEP stuff */ | ||
395 | int wep_enabled; /* 1 if WEP is enabled */ | ||
396 | int wep_key_id; /* key id to be used */ | ||
397 | u8 wep_keys[WEP_KEYS][WEP_LARGE_KEY_LEN]; /* WEP keys */ | ||
398 | u8 wep_keys_len[WEP_KEYS]; /* length of WEP keys */ | ||
399 | |||
400 | int channel; | ||
401 | int iw_mode; | ||
402 | u8 bssid[ETH_ALEN]; | ||
403 | u8 essid[IW_ESSID_MAX_SIZE]; | ||
404 | int essid_size; | ||
405 | int radio_on; | ||
406 | int promisc; | ||
407 | |||
408 | int preamble_type; /* 0 - long, 1 - short, 2 - auto */ | ||
409 | int auth_mode; /* authentication type: 0 open, 1 shared key */ | ||
410 | int txrate; /* 0,1,2,3 = 1,2,5.5,11 Mbps, 4 is auto */ | ||
411 | int frag_threshold; /* threshold for fragmentation of tx packets */ | ||
412 | int rts_threshold; /* threshold for RTS mechanism */ | ||
413 | int short_retry_limit; | ||
414 | |||
415 | int scan_min_time; /* scan min channel time */ | ||
416 | int scan_max_time; /* scan max channel time */ | ||
417 | int scan_mode; /* SCAN_TYPE_ACTIVE, SCAN_TYPE_PASSIVE */ | ||
418 | int scan_need_any; /* if set, need to scan for any ESSID */ | ||
419 | |||
420 | u16 assoc_id; /* current association ID, if associated */ | ||
421 | |||
422 | u8 pm_mode; /* power management mode */ | ||
423 | u32 pm_period; /* power management period in microseconds */ | ||
424 | |||
425 | struct reg_domain const *domain; /* reg domain description */ | ||
426 | |||
427 | /* These fields contain HW config provided by the device (not all of | ||
428 | * these fields are used by all board types) */ | ||
429 | u8 mac_addr[ETH_ALEN]; | ||
430 | u8 regulatory_domain; | ||
431 | |||
432 | struct at76_card_config card_config; | ||
433 | |||
434 | enum board_type board_type; | ||
435 | struct mib_fw_version fw_version; | ||
436 | |||
437 | unsigned int device_unplugged:1; | ||
438 | unsigned int netdev_registered:1; | ||
439 | struct set_mib_buffer mib_buf; /* global buffer for set_mib calls */ | ||
440 | |||
441 | int beacon_period; /* period of mgmt beacons, Kus */ | ||
442 | |||
443 | struct ieee80211_hw *hw; | ||
444 | int mac80211_registered; | ||
445 | }; | ||
446 | |||
447 | #define AT76_SUPPORTED_FILTERS FIF_PROMISC_IN_BSS | ||
448 | |||
449 | #define SCAN_POLL_INTERVAL (HZ / 4) | ||
450 | |||
451 | #define CMD_COMPLETION_TIMEOUT (5 * HZ) | ||
452 | |||
453 | #define DEF_RTS_THRESHOLD 1536 | ||
454 | #define DEF_FRAG_THRESHOLD 1536 | ||
455 | #define DEF_SHORT_RETRY_LIMIT 8 | ||
456 | #define DEF_CHANNEL 10 | ||
457 | #define DEF_SCAN_MIN_TIME 10 | ||
458 | #define DEF_SCAN_MAX_TIME 120 | ||
459 | |||
460 | /* the max padding size for tx in bytes (see calc_padding) */ | ||
461 | #define MAX_PADDING_SIZE 53 | ||
462 | |||
463 | #endif /* _AT76_USB_H */ | ||
diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index 6837ca9f3831..bce825b9ff1b 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c | |||
@@ -350,6 +350,7 @@ static int ath5k_beacon_setup(struct ath5k_softc *sc, | |||
350 | static void ath5k_beacon_send(struct ath5k_softc *sc); | 350 | static void ath5k_beacon_send(struct ath5k_softc *sc); |
351 | static void ath5k_beacon_config(struct ath5k_softc *sc); | 351 | static void ath5k_beacon_config(struct ath5k_softc *sc); |
352 | static void ath5k_beacon_update_timers(struct ath5k_softc *sc, u64 bc_tsf); | 352 | static void ath5k_beacon_update_timers(struct ath5k_softc *sc, u64 bc_tsf); |
353 | static void ath5k_tasklet_beacon(unsigned long data); | ||
353 | 354 | ||
354 | static inline u64 ath5k_extend_tsf(struct ath5k_hw *ah, u32 rstamp) | 355 | static inline u64 ath5k_extend_tsf(struct ath5k_hw *ah, u32 rstamp) |
355 | { | 356 | { |
@@ -789,6 +790,7 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw) | |||
789 | tasklet_init(&sc->rxtq, ath5k_tasklet_rx, (unsigned long)sc); | 790 | tasklet_init(&sc->rxtq, ath5k_tasklet_rx, (unsigned long)sc); |
790 | tasklet_init(&sc->txtq, ath5k_tasklet_tx, (unsigned long)sc); | 791 | tasklet_init(&sc->txtq, ath5k_tasklet_tx, (unsigned long)sc); |
791 | tasklet_init(&sc->restq, ath5k_tasklet_reset, (unsigned long)sc); | 792 | tasklet_init(&sc->restq, ath5k_tasklet_reset, (unsigned long)sc); |
793 | tasklet_init(&sc->beacontq, ath5k_tasklet_beacon, (unsigned long)sc); | ||
792 | setup_timer(&sc->calib_tim, ath5k_calibrate, (unsigned long)sc); | 794 | setup_timer(&sc->calib_tim, ath5k_calibrate, (unsigned long)sc); |
793 | 795 | ||
794 | ret = ath5k_eeprom_read_mac(ah, mac); | 796 | ret = ath5k_eeprom_read_mac(ah, mac); |
@@ -1218,6 +1220,10 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf) | |||
1218 | 1220 | ||
1219 | pktlen = skb->len; | 1221 | pktlen = skb->len; |
1220 | 1222 | ||
1223 | if (info->control.hw_key) { | ||
1224 | keyidx = info->control.hw_key->hw_key_idx; | ||
1225 | pktlen += info->control.hw_key->icv_len; | ||
1226 | } | ||
1221 | if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS) { | 1227 | if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS) { |
1222 | flags |= AR5K_TXDESC_RTSENA; | 1228 | flags |= AR5K_TXDESC_RTSENA; |
1223 | cts_rate = ieee80211_get_rts_cts_rate(sc->hw, info)->hw_value; | 1229 | cts_rate = ieee80211_get_rts_cts_rate(sc->hw, info)->hw_value; |
@@ -1230,11 +1236,6 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf) | |||
1230 | duration = le16_to_cpu(ieee80211_ctstoself_duration(sc->hw, | 1236 | duration = le16_to_cpu(ieee80211_ctstoself_duration(sc->hw, |
1231 | sc->vif, pktlen, info)); | 1237 | sc->vif, pktlen, info)); |
1232 | } | 1238 | } |
1233 | |||
1234 | if (info->control.hw_key) { | ||
1235 | keyidx = info->control.hw_key->hw_key_idx; | ||
1236 | pktlen += info->control.hw_key->icv_len; | ||
1237 | } | ||
1238 | ret = ah->ah_setup_tx_desc(ah, ds, pktlen, | 1239 | ret = ah->ah_setup_tx_desc(ah, ds, pktlen, |
1239 | ieee80211_get_hdrlen_from_skb(skb), AR5K_PKT_TYPE_NORMAL, | 1240 | ieee80211_get_hdrlen_from_skb(skb), AR5K_PKT_TYPE_NORMAL, |
1240 | (sc->power_level * 2), | 1241 | (sc->power_level * 2), |
@@ -1700,6 +1701,34 @@ ath5k_check_ibss_tsf(struct ath5k_softc *sc, struct sk_buff *skb, | |||
1700 | } | 1701 | } |
1701 | } | 1702 | } |
1702 | 1703 | ||
1704 | static void ath5k_tasklet_beacon(unsigned long data) | ||
1705 | { | ||
1706 | struct ath5k_softc *sc = (struct ath5k_softc *) data; | ||
1707 | |||
1708 | /* | ||
1709 | * Software beacon alert--time to send a beacon. | ||
1710 | * | ||
1711 | * In IBSS mode we use this interrupt just to | ||
1712 | * keep track of the next TBTT (target beacon | ||
1713 | * transmission time) in order to detect wether | ||
1714 | * automatic TSF updates happened. | ||
1715 | */ | ||
1716 | if (sc->opmode == NL80211_IFTYPE_ADHOC) { | ||
1717 | /* XXX: only if VEOL suppported */ | ||
1718 | u64 tsf = ath5k_hw_get_tsf64(sc->ah); | ||
1719 | sc->nexttbtt += sc->bintval; | ||
1720 | ATH5K_DBG(sc, ATH5K_DEBUG_BEACON, | ||
1721 | "SWBA nexttbtt: %x hw_tu: %x " | ||
1722 | "TSF: %llx\n", | ||
1723 | sc->nexttbtt, | ||
1724 | TSF_TO_TU(tsf), | ||
1725 | (unsigned long long) tsf); | ||
1726 | } else { | ||
1727 | spin_lock(&sc->block); | ||
1728 | ath5k_beacon_send(sc); | ||
1729 | spin_unlock(&sc->block); | ||
1730 | } | ||
1731 | } | ||
1703 | 1732 | ||
1704 | static void | 1733 | static void |
1705 | ath5k_tasklet_rx(unsigned long data) | 1734 | ath5k_tasklet_rx(unsigned long data) |
@@ -2040,9 +2069,8 @@ err_unmap: | |||
2040 | * frame contents are done as needed and the slot time is | 2069 | * frame contents are done as needed and the slot time is |
2041 | * also adjusted based on current state. | 2070 | * also adjusted based on current state. |
2042 | * | 2071 | * |
2043 | * this is usually called from interrupt context (ath5k_intr()) | 2072 | * This is called from software irq context (beacontq or restq |
2044 | * but also from ath5k_beacon_config() in IBSS mode which in turn | 2073 | * tasklets) or user context from ath5k_beacon_config. |
2045 | * can be called from a tasklet and user context | ||
2046 | */ | 2074 | */ |
2047 | static void | 2075 | static void |
2048 | ath5k_beacon_send(struct ath5k_softc *sc) | 2076 | ath5k_beacon_send(struct ath5k_softc *sc) |
@@ -2216,6 +2244,7 @@ static void | |||
2216 | ath5k_beacon_config(struct ath5k_softc *sc) | 2244 | ath5k_beacon_config(struct ath5k_softc *sc) |
2217 | { | 2245 | { |
2218 | struct ath5k_hw *ah = sc->ah; | 2246 | struct ath5k_hw *ah = sc->ah; |
2247 | unsigned long flags; | ||
2219 | 2248 | ||
2220 | ath5k_hw_set_imr(ah, 0); | 2249 | ath5k_hw_set_imr(ah, 0); |
2221 | sc->bmisscount = 0; | 2250 | sc->bmisscount = 0; |
@@ -2237,9 +2266,9 @@ ath5k_beacon_config(struct ath5k_softc *sc) | |||
2237 | 2266 | ||
2238 | if (sc->opmode == NL80211_IFTYPE_ADHOC) { | 2267 | if (sc->opmode == NL80211_IFTYPE_ADHOC) { |
2239 | if (ath5k_hw_hasveol(ah)) { | 2268 | if (ath5k_hw_hasveol(ah)) { |
2240 | spin_lock(&sc->block); | 2269 | spin_lock_irqsave(&sc->block, flags); |
2241 | ath5k_beacon_send(sc); | 2270 | ath5k_beacon_send(sc); |
2242 | spin_unlock(&sc->block); | 2271 | spin_unlock_irqrestore(&sc->block, flags); |
2243 | } | 2272 | } |
2244 | } else | 2273 | } else |
2245 | ath5k_beacon_update_timers(sc, -1); | 2274 | ath5k_beacon_update_timers(sc, -1); |
@@ -2391,6 +2420,7 @@ ath5k_stop_hw(struct ath5k_softc *sc) | |||
2391 | tasklet_kill(&sc->rxtq); | 2420 | tasklet_kill(&sc->rxtq); |
2392 | tasklet_kill(&sc->txtq); | 2421 | tasklet_kill(&sc->txtq); |
2393 | tasklet_kill(&sc->restq); | 2422 | tasklet_kill(&sc->restq); |
2423 | tasklet_kill(&sc->beacontq); | ||
2394 | 2424 | ||
2395 | return ret; | 2425 | return ret; |
2396 | } | 2426 | } |
@@ -2408,16 +2438,9 @@ ath5k_intr(int irq, void *dev_id) | |||
2408 | return IRQ_NONE; | 2438 | return IRQ_NONE; |
2409 | 2439 | ||
2410 | do { | 2440 | do { |
2411 | /* | ||
2412 | * Figure out the reason(s) for the interrupt. Note | ||
2413 | * that get_isr returns a pseudo-ISR that may include | ||
2414 | * bits we haven't explicitly enabled so we mask the | ||
2415 | * value to insure we only process bits we requested. | ||
2416 | */ | ||
2417 | ath5k_hw_get_isr(ah, &status); /* NB: clears IRQ too */ | 2441 | ath5k_hw_get_isr(ah, &status); /* NB: clears IRQ too */ |
2418 | ATH5K_DBG(sc, ATH5K_DEBUG_INTR, "status 0x%x/0x%x\n", | 2442 | ATH5K_DBG(sc, ATH5K_DEBUG_INTR, "status 0x%x/0x%x\n", |
2419 | status, sc->imask); | 2443 | status, sc->imask); |
2420 | status &= sc->imask; /* discard unasked for bits */ | ||
2421 | if (unlikely(status & AR5K_INT_FATAL)) { | 2444 | if (unlikely(status & AR5K_INT_FATAL)) { |
2422 | /* | 2445 | /* |
2423 | * Fatal errors are unrecoverable. | 2446 | * Fatal errors are unrecoverable. |
@@ -2428,32 +2451,7 @@ ath5k_intr(int irq, void *dev_id) | |||
2428 | tasklet_schedule(&sc->restq); | 2451 | tasklet_schedule(&sc->restq); |
2429 | } else { | 2452 | } else { |
2430 | if (status & AR5K_INT_SWBA) { | 2453 | if (status & AR5K_INT_SWBA) { |
2431 | /* | 2454 | tasklet_schedule(&sc->beacontq); |
2432 | * Software beacon alert--time to send a beacon. | ||
2433 | * Handle beacon transmission directly; deferring | ||
2434 | * this is too slow to meet timing constraints | ||
2435 | * under load. | ||
2436 | * | ||
2437 | * In IBSS mode we use this interrupt just to | ||
2438 | * keep track of the next TBTT (target beacon | ||
2439 | * transmission time) in order to detect wether | ||
2440 | * automatic TSF updates happened. | ||
2441 | */ | ||
2442 | if (sc->opmode == NL80211_IFTYPE_ADHOC) { | ||
2443 | /* XXX: only if VEOL suppported */ | ||
2444 | u64 tsf = ath5k_hw_get_tsf64(ah); | ||
2445 | sc->nexttbtt += sc->bintval; | ||
2446 | ATH5K_DBG(sc, ATH5K_DEBUG_BEACON, | ||
2447 | "SWBA nexttbtt: %x hw_tu: %x " | ||
2448 | "TSF: %llx\n", | ||
2449 | sc->nexttbtt, | ||
2450 | TSF_TO_TU(tsf), | ||
2451 | (unsigned long long) tsf); | ||
2452 | } else { | ||
2453 | spin_lock(&sc->block); | ||
2454 | ath5k_beacon_send(sc); | ||
2455 | spin_unlock(&sc->block); | ||
2456 | } | ||
2457 | } | 2455 | } |
2458 | if (status & AR5K_INT_RXEOL) { | 2456 | if (status & AR5K_INT_RXEOL) { |
2459 | /* | 2457 | /* |
diff --git a/drivers/net/wireless/ath5k/base.h b/drivers/net/wireless/ath5k/base.h index c0fb8b5c42fe..20e0d14b41ec 100644 --- a/drivers/net/wireless/ath5k/base.h +++ b/drivers/net/wireless/ath5k/base.h | |||
@@ -169,6 +169,7 @@ struct ath5k_softc { | |||
169 | struct ath5k_led tx_led; /* tx led */ | 169 | struct ath5k_led tx_led; /* tx led */ |
170 | 170 | ||
171 | spinlock_t block; /* protects beacon */ | 171 | spinlock_t block; /* protects beacon */ |
172 | struct tasklet_struct beacontq; /* beacon intr tasklet */ | ||
172 | struct ath5k_buf *bbuf; /* beacon buffer */ | 173 | struct ath5k_buf *bbuf; /* beacon buffer */ |
173 | unsigned int bhalq, /* SW q for outgoing beacons */ | 174 | unsigned int bhalq, /* SW q for outgoing beacons */ |
174 | bmisscount, /* missed beacon transmits */ | 175 | bmisscount, /* missed beacon transmits */ |
diff --git a/drivers/net/wireless/ath9k/ani.c b/drivers/net/wireless/ath9k/ani.c index d4df7e611df5..a39eb760cbb7 100644 --- a/drivers/net/wireless/ath9k/ani.c +++ b/drivers/net/wireless/ath9k/ani.c | |||
@@ -642,14 +642,13 @@ void ath9k_enable_mib_counters(struct ath_hw *ah) | |||
642 | REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); | 642 | REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); |
643 | } | 643 | } |
644 | 644 | ||
645 | /* Freeze the MIB counters, get the stats and then clear them */ | ||
645 | void ath9k_hw_disable_mib_counters(struct ath_hw *ah) | 646 | void ath9k_hw_disable_mib_counters(struct ath_hw *ah) |
646 | { | 647 | { |
647 | DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Disable MIB counters\n"); | 648 | DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Disable MIB counters\n"); |
648 | 649 | REG_WRITE(ah, AR_MIBC, AR_MIBC_FMC); | |
649 | REG_WRITE(ah, AR_MIBC, AR_MIBC_FMC | AR_MIBC_CMC); | ||
650 | |||
651 | ath9k_hw_update_mibstats(ah, &ah->ah_mibStats); | 650 | ath9k_hw_update_mibstats(ah, &ah->ah_mibStats); |
652 | 651 | REG_WRITE(ah, AR_MIBC, AR_MIBC_CMC); | |
653 | REG_WRITE(ah, AR_FILT_OFDM, 0); | 652 | REG_WRITE(ah, AR_FILT_OFDM, 0); |
654 | REG_WRITE(ah, AR_FILT_CCK, 0); | 653 | REG_WRITE(ah, AR_FILT_CCK, 0); |
655 | } | 654 | } |
diff --git a/drivers/net/wireless/ath9k/ath9k.h b/drivers/net/wireless/ath9k/ath9k.h index 0b0f82c83ffc..6481ea4bbc4e 100644 --- a/drivers/net/wireless/ath9k/ath9k.h +++ b/drivers/net/wireless/ath9k/ath9k.h | |||
@@ -464,13 +464,11 @@ void ath_beacon_sync(struct ath_softc *sc, int if_id); | |||
464 | /* ANI */ | 464 | /* ANI */ |
465 | /*******/ | 465 | /*******/ |
466 | 466 | ||
467 | /* ANI values for STA only. | 467 | #define ATH_STA_SHORT_CALINTERVAL 1000 /* 1 second */ |
468 | FIXME: Add appropriate values for AP later */ | 468 | #define ATH_AP_SHORT_CALINTERVAL 100 /* 100 ms */ |
469 | 469 | #define ATH_ANI_POLLINTERVAL 100 /* 100 ms */ | |
470 | #define ATH_ANI_POLLINTERVAL 100 /* 100 milliseconds between ANI poll */ | 470 | #define ATH_LONG_CALINTERVAL 30000 /* 30 seconds */ |
471 | #define ATH_SHORT_CALINTERVAL 1000 /* 1 second between calibrations */ | 471 | #define ATH_RESTART_CALINTERVAL 1200000 /* 20 minutes */ |
472 | #define ATH_LONG_CALINTERVAL 30000 /* 30 seconds between calibrations */ | ||
473 | #define ATH_RESTART_CALINTERVAL 1200000 /* 20 minutes between calibrations */ | ||
474 | 472 | ||
475 | struct ath_ani { | 473 | struct ath_ani { |
476 | bool caldone; | 474 | bool caldone; |
diff --git a/drivers/net/wireless/ath9k/beacon.c b/drivers/net/wireless/ath9k/beacon.c index 2e2ef3529135..18bda362d3ab 100644 --- a/drivers/net/wireless/ath9k/beacon.c +++ b/drivers/net/wireless/ath9k/beacon.c | |||
@@ -753,6 +753,9 @@ void ath_beacon_config(struct ath_softc *sc, int if_id) | |||
753 | if (bs.bs_sleepduration > bs.bs_dtimperiod) | 753 | if (bs.bs_sleepduration > bs.bs_dtimperiod) |
754 | bs.bs_sleepduration = bs.bs_dtimperiod; | 754 | bs.bs_sleepduration = bs.bs_dtimperiod; |
755 | 755 | ||
756 | /* TSF out of range threshold fixed at 1 second */ | ||
757 | bs.bs_tsfoor_threshold = ATH9K_TSFOOR_THRESHOLD; | ||
758 | |||
756 | DPRINTF(sc, ATH_DBG_BEACON, | 759 | DPRINTF(sc, ATH_DBG_BEACON, |
757 | "tsf %llu " | 760 | "tsf %llu " |
758 | "tsf:tu %u " | 761 | "tsf:tu %u " |
@@ -787,8 +790,6 @@ void ath_beacon_config(struct ath_softc *sc, int if_id) | |||
787 | u64 tsf; | 790 | u64 tsf; |
788 | u32 tsftu; | 791 | u32 tsftu; |
789 | ath9k_hw_set_interrupts(ah, 0); | 792 | ath9k_hw_set_interrupts(ah, 0); |
790 | if (nexttbtt == intval) | ||
791 | intval |= ATH9K_BEACON_RESET_TSF; | ||
792 | if (sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC) { | 793 | if (sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC) { |
793 | /* | 794 | /* |
794 | * Pull nexttbtt forward to reflect the current | 795 | * Pull nexttbtt forward to reflect the current |
@@ -822,6 +823,9 @@ void ath_beacon_config(struct ath_softc *sc, int if_id) | |||
822 | sc->imask |= ATH9K_INT_SWBA; | 823 | sc->imask |= ATH9K_INT_SWBA; |
823 | ath_beaconq_config(sc); | 824 | ath_beaconq_config(sc); |
824 | } else if (sc->sc_ah->opmode == NL80211_IFTYPE_AP) { | 825 | } else if (sc->sc_ah->opmode == NL80211_IFTYPE_AP) { |
826 | if (nexttbtt == intval) | ||
827 | intval |= ATH9K_BEACON_RESET_TSF; | ||
828 | |||
825 | /* | 829 | /* |
826 | * In AP mode we enable the beacon timers and | 830 | * In AP mode we enable the beacon timers and |
827 | * SWBA interrupts to prepare beacon frames. | 831 | * SWBA interrupts to prepare beacon frames. |
diff --git a/drivers/net/wireless/ath9k/calib.c b/drivers/net/wireless/ath9k/calib.c index 1fc3a08e85c6..1c074c059b5c 100644 --- a/drivers/net/wireless/ath9k/calib.c +++ b/drivers/net/wireless/ath9k/calib.c | |||
@@ -718,6 +718,33 @@ s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan) | |||
718 | return nf; | 718 | return nf; |
719 | } | 719 | } |
720 | 720 | ||
721 | static void ath9k_olc_temp_compensation(struct ath_hw *ah) | ||
722 | { | ||
723 | u32 rddata, i; | ||
724 | int delta, currPDADC, regval; | ||
725 | |||
726 | rddata = REG_READ(ah, AR_PHY_TX_PWRCTRL4); | ||
727 | |||
728 | currPDADC = MS(rddata, AR_PHY_TX_PWRCTRL_PD_AVG_OUT); | ||
729 | |||
730 | if (ah->eep_ops->get_eeprom(ah, EEP_DAC_HPWR_5G)) | ||
731 | delta = (currPDADC - ah->initPDADC + 4) / 8; | ||
732 | else | ||
733 | delta = (currPDADC - ah->initPDADC + 5) / 10; | ||
734 | |||
735 | if (delta != ah->PDADCdelta) { | ||
736 | ah->PDADCdelta = delta; | ||
737 | for (i = 1; i < AR9280_TX_GAIN_TABLE_SIZE; i++) { | ||
738 | regval = ah->originalGain[i] - delta; | ||
739 | if (regval < 0) | ||
740 | regval = 0; | ||
741 | |||
742 | REG_RMW_FIELD(ah, AR_PHY_TX_GAIN_TBL1 + i * 4, | ||
743 | AR_PHY_TX_GAIN, regval); | ||
744 | } | ||
745 | } | ||
746 | } | ||
747 | |||
721 | bool ath9k_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan, | 748 | bool ath9k_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan, |
722 | u8 rxchainmask, bool longcal, | 749 | u8 rxchainmask, bool longcal, |
723 | bool *isCalDone) | 750 | bool *isCalDone) |
@@ -742,6 +769,8 @@ bool ath9k_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan, | |||
742 | } | 769 | } |
743 | 770 | ||
744 | if (longcal) { | 771 | if (longcal) { |
772 | if (OLC_FOR_AR9280_20_LATER) | ||
773 | ath9k_olc_temp_compensation(ah); | ||
745 | ath9k_hw_getnf(ah, chan); | 774 | ath9k_hw_getnf(ah, chan); |
746 | ath9k_hw_loadnf(ah, ah->curchan); | 775 | ath9k_hw_loadnf(ah, ah->curchan); |
747 | ath9k_hw_start_nfcal(ah); | 776 | ath9k_hw_start_nfcal(ah); |
@@ -851,20 +880,53 @@ static inline void ath9k_hw_9285_pa_cal(struct ath_hw *ah) | |||
851 | bool ath9k_hw_init_cal(struct ath_hw *ah, | 880 | bool ath9k_hw_init_cal(struct ath_hw *ah, |
852 | struct ath9k_channel *chan) | 881 | struct ath9k_channel *chan) |
853 | { | 882 | { |
883 | if (AR_SREV_9280_10_OR_LATER(ah)) { | ||
884 | REG_CLR_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC); | ||
885 | REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL); | ||
886 | REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE); | ||
887 | |||
888 | /* Kick off the cal */ | ||
889 | REG_WRITE(ah, AR_PHY_AGC_CONTROL, | ||
890 | REG_READ(ah, AR_PHY_AGC_CONTROL) | | ||
891 | AR_PHY_AGC_CONTROL_CAL); | ||
892 | |||
893 | if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, | ||
894 | AR_PHY_AGC_CONTROL_CAL, 0, | ||
895 | AH_WAIT_TIMEOUT)) { | ||
896 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, | ||
897 | "offset calibration failed to complete in 1ms; " | ||
898 | "noisy environment?\n"); | ||
899 | return false; | ||
900 | } | ||
901 | |||
902 | REG_CLR_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC); | ||
903 | REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL); | ||
904 | REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE); | ||
905 | } | ||
906 | |||
907 | /* Calibrate the AGC */ | ||
854 | REG_WRITE(ah, AR_PHY_AGC_CONTROL, | 908 | REG_WRITE(ah, AR_PHY_AGC_CONTROL, |
855 | REG_READ(ah, AR_PHY_AGC_CONTROL) | | 909 | REG_READ(ah, AR_PHY_AGC_CONTROL) | |
856 | AR_PHY_AGC_CONTROL_CAL); | 910 | AR_PHY_AGC_CONTROL_CAL); |
857 | 911 | ||
858 | if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, 0)) { | 912 | if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, |
913 | 0, AH_WAIT_TIMEOUT)) { | ||
859 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, | 914 | DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, |
860 | "offset calibration failed to complete in 1ms; " | 915 | "offset calibration failed to complete in 1ms; " |
861 | "noisy environment?\n"); | 916 | "noisy environment?\n"); |
862 | return false; | 917 | return false; |
863 | } | 918 | } |
864 | 919 | ||
920 | if (AR_SREV_9280_10_OR_LATER(ah)) { | ||
921 | REG_SET_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC); | ||
922 | REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL); | ||
923 | } | ||
924 | |||
925 | /* Do PA Calibration */ | ||
865 | if (AR_SREV_9285(ah) && AR_SREV_9285_11_OR_LATER(ah)) | 926 | if (AR_SREV_9285(ah) && AR_SREV_9285_11_OR_LATER(ah)) |
866 | ath9k_hw_9285_pa_cal(ah); | 927 | ath9k_hw_9285_pa_cal(ah); |
867 | 928 | ||
929 | /* Do NF Calibration */ | ||
868 | REG_WRITE(ah, AR_PHY_AGC_CONTROL, | 930 | REG_WRITE(ah, AR_PHY_AGC_CONTROL, |
869 | REG_READ(ah, AR_PHY_AGC_CONTROL) | | 931 | REG_READ(ah, AR_PHY_AGC_CONTROL) | |
870 | AR_PHY_AGC_CONTROL_NF); | 932 | AR_PHY_AGC_CONTROL_NF); |
diff --git a/drivers/net/wireless/ath9k/calib.h b/drivers/net/wireless/ath9k/calib.h index d2448f049c1d..32589e0c5018 100644 --- a/drivers/net/wireless/ath9k/calib.h +++ b/drivers/net/wireless/ath9k/calib.h | |||
@@ -27,7 +27,7 @@ extern const struct hal_percal_data adc_init_dc_cal; | |||
27 | 27 | ||
28 | #define AR_PHY_CCA_MAX_GOOD_VALUE -85 | 28 | #define AR_PHY_CCA_MAX_GOOD_VALUE -85 |
29 | #define AR_PHY_CCA_MAX_HIGH_VALUE -62 | 29 | #define AR_PHY_CCA_MAX_HIGH_VALUE -62 |
30 | #define AR_PHY_CCA_MIN_BAD_VALUE -121 | 30 | #define AR_PHY_CCA_MIN_BAD_VALUE -140 |
31 | #define AR_PHY_CCA_FILTERWINDOW_LENGTH_INIT 3 | 31 | #define AR_PHY_CCA_FILTERWINDOW_LENGTH_INIT 3 |
32 | #define AR_PHY_CCA_FILTERWINDOW_LENGTH 5 | 32 | #define AR_PHY_CCA_FILTERWINDOW_LENGTH 5 |
33 | 33 | ||
diff --git a/drivers/net/wireless/ath9k/debug.c b/drivers/net/wireless/ath9k/debug.c index 800ad5926b6f..0c422c50e4f0 100644 --- a/drivers/net/wireless/ath9k/debug.c +++ b/drivers/net/wireless/ath9k/debug.c | |||
@@ -258,13 +258,14 @@ void ath_debug_stat_rc(struct ath_softc *sc, struct sk_buff *skb) | |||
258 | 258 | ||
259 | /* FIXME: legacy rates, later on .. */ | 259 | /* FIXME: legacy rates, later on .. */ |
260 | void ath_debug_stat_retries(struct ath_softc *sc, int rix, | 260 | void ath_debug_stat_retries(struct ath_softc *sc, int rix, |
261 | int xretries, int retries) | 261 | int xretries, int retries, u8 per) |
262 | { | 262 | { |
263 | if (conf_is_ht(&sc->hw->conf)) { | 263 | if (conf_is_ht(&sc->hw->conf)) { |
264 | int idx = sc->cur_rate_table->info[rix].dot11rate; | 264 | int idx = sc->cur_rate_table->info[rix].dot11rate; |
265 | 265 | ||
266 | sc->debug.stats.n_rcstats[idx].xretries += xretries; | 266 | sc->debug.stats.n_rcstats[idx].xretries += xretries; |
267 | sc->debug.stats.n_rcstats[idx].retries += retries; | 267 | sc->debug.stats.n_rcstats[idx].retries += retries; |
268 | sc->debug.stats.n_rcstats[idx].per = per; | ||
268 | } | 269 | } |
269 | } | 270 | } |
270 | 271 | ||
@@ -277,15 +278,16 @@ static ssize_t ath_read_file_stat_11n_rc(struct file *file, | |||
277 | unsigned int len = 0; | 278 | unsigned int len = 0; |
278 | int i = 0; | 279 | int i = 0; |
279 | 280 | ||
280 | len += sprintf(buf, "%7s %13s %8s %8s\n\n", "Rate", "Success", | 281 | len += sprintf(buf, "%7s %13s %8s %8s %6s\n\n", "Rate", "Success", |
281 | "Retries", "XRetries"); | 282 | "Retries", "XRetries", "PER"); |
282 | 283 | ||
283 | for (i = 0; i <= 15; i++) { | 284 | for (i = 0; i <= 15; i++) { |
284 | len += snprintf(buf + len, sizeof(buf) - len, | 285 | len += snprintf(buf + len, sizeof(buf) - len, |
285 | "%5s%3d: %8u %8u %8u\n", "MCS", i, | 286 | "%5s%3d: %8u %8u %8u %8u\n", "MCS", i, |
286 | sc->debug.stats.n_rcstats[i].success, | 287 | sc->debug.stats.n_rcstats[i].success, |
287 | sc->debug.stats.n_rcstats[i].retries, | 288 | sc->debug.stats.n_rcstats[i].retries, |
288 | sc->debug.stats.n_rcstats[i].xretries); | 289 | sc->debug.stats.n_rcstats[i].xretries, |
290 | sc->debug.stats.n_rcstats[i].per); | ||
289 | } | 291 | } |
290 | 292 | ||
291 | return simple_read_from_buffer(user_buf, count, ppos, buf, len); | 293 | return simple_read_from_buffer(user_buf, count, ppos, buf, len); |
diff --git a/drivers/net/wireless/ath9k/debug.h b/drivers/net/wireless/ath9k/debug.h index 61e969894c0a..01681f2d0549 100644 --- a/drivers/net/wireless/ath9k/debug.h +++ b/drivers/net/wireless/ath9k/debug.h | |||
@@ -91,12 +91,13 @@ struct ath_11n_rc_stats { | |||
91 | u32 success; | 91 | u32 success; |
92 | u32 retries; | 92 | u32 retries; |
93 | u32 xretries; | 93 | u32 xretries; |
94 | u8 per; | ||
94 | }; | 95 | }; |
95 | 96 | ||
96 | struct ath_stats { | 97 | struct ath_stats { |
97 | struct ath_interrupt_stats istats; | 98 | struct ath_interrupt_stats istats; |
98 | struct ath_legacy_rc_stats legacy_rcstats[12]; /* max(11a,11b,11g) */ | 99 | struct ath_legacy_rc_stats legacy_rcstats[12]; /* max(11a,11b,11g) */ |
99 | struct ath_11n_rc_stats n_rcstats[16]; /* 0..15 MCS rates */ | 100 | struct ath_11n_rc_stats n_rcstats[16]; /* 0..15 MCS rates */ |
100 | }; | 101 | }; |
101 | 102 | ||
102 | struct ath9k_debug { | 103 | struct ath9k_debug { |
@@ -115,7 +116,7 @@ void ath9k_exit_debug(struct ath_softc *sc); | |||
115 | void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status); | 116 | void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status); |
116 | void ath_debug_stat_rc(struct ath_softc *sc, struct sk_buff *skb); | 117 | void ath_debug_stat_rc(struct ath_softc *sc, struct sk_buff *skb); |
117 | void ath_debug_stat_retries(struct ath_softc *sc, int rix, | 118 | void ath_debug_stat_retries(struct ath_softc *sc, int rix, |
118 | int xretries, int retries); | 119 | int xretries, int retries, u8 per); |
119 | 120 | ||
120 | #else | 121 | #else |
121 | 122 | ||
@@ -144,7 +145,7 @@ static inline void ath_debug_stat_rc(struct ath_softc *sc, | |||
144 | } | 145 | } |
145 | 146 | ||
146 | static inline void ath_debug_stat_retries(struct ath_softc *sc, int rix, | 147 | static inline void ath_debug_stat_retries(struct ath_softc *sc, int rix, |
147 | int xretries, int retries) | 148 | int xretries, int retries, u8 per) |
148 | { | 149 | { |
149 | } | 150 | } |
150 | 151 | ||
diff --git a/drivers/net/wireless/ath9k/eeprom.c b/drivers/net/wireless/ath9k/eeprom.c index b55e9920a5d4..02d0b919ee3d 100644 --- a/drivers/net/wireless/ath9k/eeprom.c +++ b/drivers/net/wireless/ath9k/eeprom.c | |||
@@ -179,6 +179,69 @@ static void ath9k_hw_get_legacy_target_powers(struct ath_hw *ah, | |||
179 | } | 179 | } |
180 | } | 180 | } |
181 | 181 | ||
182 | static void ath9k_get_txgain_index(struct ath_hw *ah, | ||
183 | struct ath9k_channel *chan, | ||
184 | struct calDataPerFreqOpLoop *rawDatasetOpLoop, | ||
185 | u8 *calChans, u16 availPiers, u8 *pwr, u8 *pcdacIdx) | ||
186 | { | ||
187 | u8 pcdac, i = 0; | ||
188 | u16 idxL = 0, idxR = 0, numPiers; | ||
189 | bool match; | ||
190 | struct chan_centers centers; | ||
191 | |||
192 | ath9k_hw_get_channel_centers(ah, chan, ¢ers); | ||
193 | |||
194 | for (numPiers = 0; numPiers < availPiers; numPiers++) | ||
195 | if (calChans[numPiers] == AR5416_BCHAN_UNUSED) | ||
196 | break; | ||
197 | |||
198 | match = ath9k_hw_get_lower_upper_index( | ||
199 | (u8)FREQ2FBIN(centers.synth_center, IS_CHAN_2GHZ(chan)), | ||
200 | calChans, numPiers, &idxL, &idxR); | ||
201 | if (match) { | ||
202 | pcdac = rawDatasetOpLoop[idxL].pcdac[0][0]; | ||
203 | *pwr = rawDatasetOpLoop[idxL].pwrPdg[0][0]; | ||
204 | } else { | ||
205 | pcdac = rawDatasetOpLoop[idxR].pcdac[0][0]; | ||
206 | *pwr = (rawDatasetOpLoop[idxL].pwrPdg[0][0] + | ||
207 | rawDatasetOpLoop[idxR].pwrPdg[0][0])/2; | ||
208 | } | ||
209 | |||
210 | while (pcdac > ah->originalGain[i] && | ||
211 | i < (AR9280_TX_GAIN_TABLE_SIZE - 1)) | ||
212 | i++; | ||
213 | |||
214 | *pcdacIdx = i; | ||
215 | return; | ||
216 | } | ||
217 | |||
218 | static void ath9k_olc_get_pdadcs(struct ath_hw *ah, | ||
219 | u32 initTxGain, | ||
220 | int txPower, | ||
221 | u8 *pPDADCValues) | ||
222 | { | ||
223 | u32 i; | ||
224 | u32 offset; | ||
225 | |||
226 | REG_RMW_FIELD(ah, AR_PHY_TX_PWRCTRL6_0, | ||
227 | AR_PHY_TX_PWRCTRL_ERR_EST_MODE, 3); | ||
228 | REG_RMW_FIELD(ah, AR_PHY_TX_PWRCTRL6_1, | ||
229 | AR_PHY_TX_PWRCTRL_ERR_EST_MODE, 3); | ||
230 | |||
231 | REG_RMW_FIELD(ah, AR_PHY_TX_PWRCTRL7, | ||
232 | AR_PHY_TX_PWRCTRL_INIT_TX_GAIN, initTxGain); | ||
233 | |||
234 | offset = txPower; | ||
235 | for (i = 0; i < AR5416_NUM_PDADC_VALUES; i++) | ||
236 | if (i < offset) | ||
237 | pPDADCValues[i] = 0x0; | ||
238 | else | ||
239 | pPDADCValues[i] = 0xFF; | ||
240 | } | ||
241 | |||
242 | |||
243 | |||
244 | |||
182 | static void ath9k_hw_get_target_powers(struct ath_hw *ah, | 245 | static void ath9k_hw_get_target_powers(struct ath_hw *ah, |
183 | struct ath9k_channel *chan, | 246 | struct ath9k_channel *chan, |
184 | struct cal_target_power_ht *powInfo, | 247 | struct cal_target_power_ht *powInfo, |
@@ -439,7 +502,7 @@ static u32 ath9k_hw_4k_get_eeprom(struct ath_hw *ah, | |||
439 | 502 | ||
440 | switch (param) { | 503 | switch (param) { |
441 | case EEP_NFTHRESH_2: | 504 | case EEP_NFTHRESH_2: |
442 | return pModal[1].noiseFloorThreshCh[0]; | 505 | return pModal->noiseFloorThreshCh[0]; |
443 | case AR_EEPROM_MAC(0): | 506 | case AR_EEPROM_MAC(0): |
444 | return pBase->macAddr[0] << 8 | pBase->macAddr[1]; | 507 | return pBase->macAddr[0] << 8 | pBase->macAddr[1]; |
445 | case AR_EEPROM_MAC(1): | 508 | case AR_EEPROM_MAC(1): |
@@ -466,6 +529,8 @@ static u32 ath9k_hw_4k_get_eeprom(struct ath_hw *ah, | |||
466 | return pBase->txMask; | 529 | return pBase->txMask; |
467 | case EEP_RX_MASK: | 530 | case EEP_RX_MASK: |
468 | return pBase->rxMask; | 531 | return pBase->rxMask; |
532 | case EEP_FRAC_N_5G: | ||
533 | return 0; | ||
469 | default: | 534 | default: |
470 | return 0; | 535 | return 0; |
471 | } | 536 | } |
@@ -1594,11 +1659,26 @@ static u32 ath9k_hw_def_get_eeprom(struct ath_hw *ah, | |||
1594 | return pBase->rxGainType; | 1659 | return pBase->rxGainType; |
1595 | case EEP_TXGAIN_TYPE: | 1660 | case EEP_TXGAIN_TYPE: |
1596 | return pBase->txGainType; | 1661 | return pBase->txGainType; |
1662 | case EEP_OL_PWRCTRL: | ||
1663 | if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_19) | ||
1664 | return pBase->openLoopPwrCntl ? true : false; | ||
1665 | else | ||
1666 | return false; | ||
1667 | case EEP_RC_CHAIN_MASK: | ||
1668 | if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_19) | ||
1669 | return pBase->rcChainMask; | ||
1670 | else | ||
1671 | return 0; | ||
1597 | case EEP_DAC_HPWR_5G: | 1672 | case EEP_DAC_HPWR_5G: |
1598 | if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_20) | 1673 | if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_20) |
1599 | return pBase->dacHiPwrMode_5G; | 1674 | return pBase->dacHiPwrMode_5G; |
1600 | else | 1675 | else |
1601 | return 0; | 1676 | return 0; |
1677 | case EEP_FRAC_N_5G: | ||
1678 | if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_22) | ||
1679 | return pBase->frac_n_5g; | ||
1680 | else | ||
1681 | return 0; | ||
1602 | default: | 1682 | default: |
1603 | return 0; | 1683 | return 0; |
1604 | } | 1684 | } |
@@ -1832,8 +1912,15 @@ static bool ath9k_hw_def_set_board_values(struct ath_hw *ah, | |||
1832 | pModal->swSettleHt40); | 1912 | pModal->swSettleHt40); |
1833 | } | 1913 | } |
1834 | 1914 | ||
1915 | if (AR_SREV_9280_20_OR_LATER(ah) && | ||
1916 | AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_19) | ||
1917 | REG_RMW_FIELD(ah, AR_PHY_CCK_TX_CTRL, | ||
1918 | AR_PHY_CCK_TX_CTRL_TX_DAC_SCALE_CCK, | ||
1919 | pModal->miscBits); | ||
1920 | |||
1921 | |||
1835 | if (AR_SREV_9280_20(ah) && AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_20) { | 1922 | if (AR_SREV_9280_20(ah) && AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_20) { |
1836 | if (IS_CHAN_HT20(chan)) | 1923 | if (IS_CHAN_2GHZ(chan)) |
1837 | REG_RMW_FIELD(ah, AR_AN_TOP1, AR_AN_TOP1_DACIPMODE, | 1924 | REG_RMW_FIELD(ah, AR_AN_TOP1, AR_AN_TOP1_DACIPMODE, |
1838 | eep->baseEepHeader.dacLpMode); | 1925 | eep->baseEepHeader.dacLpMode); |
1839 | else if (eep->baseEepHeader.dacHiPwrMode_5G) | 1926 | else if (eep->baseEepHeader.dacHiPwrMode_5G) |
@@ -1844,6 +1931,10 @@ static bool ath9k_hw_def_set_board_values(struct ath_hw *ah, | |||
1844 | 1931 | ||
1845 | REG_RMW_FIELD(ah, AR_PHY_FRAME_CTL, AR_PHY_FRAME_CTL_TX_CLIP, | 1932 | REG_RMW_FIELD(ah, AR_PHY_FRAME_CTL, AR_PHY_FRAME_CTL_TX_CLIP, |
1846 | pModal->miscBits >> 2); | 1933 | pModal->miscBits >> 2); |
1934 | |||
1935 | REG_RMW_FIELD(ah, AR_PHY_TX_PWRCTRL9, | ||
1936 | AR_PHY_TX_DESIRED_SCALE_CCK, | ||
1937 | eep->baseEepHeader.desiredScaleCCK); | ||
1847 | } | 1938 | } |
1848 | 1939 | ||
1849 | return true; | 1940 | return true; |
@@ -2073,6 +2164,10 @@ static bool ath9k_hw_set_def_power_cal_table(struct ath_hw *ah, | |||
2073 | struct ath9k_channel *chan, | 2164 | struct ath9k_channel *chan, |
2074 | int16_t *pTxPowerIndexOffset) | 2165 | int16_t *pTxPowerIndexOffset) |
2075 | { | 2166 | { |
2167 | #define SM_PD_GAIN(x) SM(0x38, AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_##x) | ||
2168 | #define SM_PDGAIN_B(x, y) \ | ||
2169 | SM((gainBoundaries[x]), AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_##y) | ||
2170 | |||
2076 | struct ar5416_eeprom_def *pEepData = &ah->eeprom.def; | 2171 | struct ar5416_eeprom_def *pEepData = &ah->eeprom.def; |
2077 | struct cal_data_per_freq *pRawDataset; | 2172 | struct cal_data_per_freq *pRawDataset; |
2078 | u8 *pCalBChans = NULL; | 2173 | u8 *pCalBChans = NULL; |
@@ -2106,6 +2201,12 @@ static bool ath9k_hw_set_def_power_cal_table(struct ath_hw *ah, | |||
2106 | numPiers = AR5416_NUM_5G_CAL_PIERS; | 2201 | numPiers = AR5416_NUM_5G_CAL_PIERS; |
2107 | } | 2202 | } |
2108 | 2203 | ||
2204 | if (OLC_FOR_AR9280_20_LATER && IS_CHAN_2GHZ(chan)) { | ||
2205 | pRawDataset = pEepData->calPierData2G[0]; | ||
2206 | ah->initPDADC = ((struct calDataPerFreqOpLoop *) | ||
2207 | pRawDataset)->vpdPdg[0][0]; | ||
2208 | } | ||
2209 | |||
2109 | numXpdGain = 0; | 2210 | numXpdGain = 0; |
2110 | 2211 | ||
2111 | for (i = 1; i <= AR5416_PD_GAINS_IN_MASK; i++) { | 2212 | for (i = 1; i <= AR5416_PD_GAINS_IN_MASK; i++) { |
@@ -2141,25 +2242,45 @@ static bool ath9k_hw_set_def_power_cal_table(struct ath_hw *ah, | |||
2141 | else | 2242 | else |
2142 | pRawDataset = pEepData->calPierData5G[i]; | 2243 | pRawDataset = pEepData->calPierData5G[i]; |
2143 | 2244 | ||
2144 | ath9k_hw_get_def_gain_boundaries_pdadcs(ah, chan, | 2245 | |
2145 | pRawDataset, pCalBChans, | 2246 | if (OLC_FOR_AR9280_20_LATER) { |
2146 | numPiers, pdGainOverlap_t2, | 2247 | u8 pcdacIdx; |
2147 | &tMinCalPower, gainBoundaries, | 2248 | u8 txPower; |
2148 | pdadcValues, numXpdGain); | 2249 | |
2250 | ath9k_get_txgain_index(ah, chan, | ||
2251 | (struct calDataPerFreqOpLoop *)pRawDataset, | ||
2252 | pCalBChans, numPiers, &txPower, &pcdacIdx); | ||
2253 | ath9k_olc_get_pdadcs(ah, pcdacIdx, | ||
2254 | txPower/2, pdadcValues); | ||
2255 | } else { | ||
2256 | ath9k_hw_get_def_gain_boundaries_pdadcs(ah, | ||
2257 | chan, pRawDataset, | ||
2258 | pCalBChans, numPiers, | ||
2259 | pdGainOverlap_t2, | ||
2260 | &tMinCalPower, | ||
2261 | gainBoundaries, | ||
2262 | pdadcValues, | ||
2263 | numXpdGain); | ||
2264 | } | ||
2149 | 2265 | ||
2150 | if ((i == 0) || AR_SREV_5416_V20_OR_LATER(ah)) { | 2266 | if ((i == 0) || AR_SREV_5416_V20_OR_LATER(ah)) { |
2151 | REG_WRITE(ah, | 2267 | if (OLC_FOR_AR9280_20_LATER) { |
2152 | AR_PHY_TPCRG5 + regChainOffset, | 2268 | REG_WRITE(ah, |
2153 | SM(pdGainOverlap_t2, | 2269 | AR_PHY_TPCRG5 + regChainOffset, |
2154 | AR_PHY_TPCRG5_PD_GAIN_OVERLAP) | 2270 | SM(0x6, |
2155 | | SM(gainBoundaries[0], | 2271 | AR_PHY_TPCRG5_PD_GAIN_OVERLAP) | |
2156 | AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1) | 2272 | SM_PD_GAIN(1) | SM_PD_GAIN(2) | |
2157 | | SM(gainBoundaries[1], | 2273 | SM_PD_GAIN(3) | SM_PD_GAIN(4)); |
2158 | AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2) | 2274 | } else { |
2159 | | SM(gainBoundaries[2], | 2275 | REG_WRITE(ah, |
2160 | AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3) | 2276 | AR_PHY_TPCRG5 + regChainOffset, |
2161 | | SM(gainBoundaries[3], | 2277 | SM(pdGainOverlap_t2, |
2162 | AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4)); | 2278 | AR_PHY_TPCRG5_PD_GAIN_OVERLAP)| |
2279 | SM_PDGAIN_B(0, 1) | | ||
2280 | SM_PDGAIN_B(1, 2) | | ||
2281 | SM_PDGAIN_B(2, 3) | | ||
2282 | SM_PDGAIN_B(3, 4)); | ||
2283 | } | ||
2163 | } | 2284 | } |
2164 | 2285 | ||
2165 | regOffset = AR_PHY_BASE + (672 << 2) + regChainOffset; | 2286 | regOffset = AR_PHY_BASE + (672 << 2) + regChainOffset; |
@@ -2193,6 +2314,8 @@ static bool ath9k_hw_set_def_power_cal_table(struct ath_hw *ah, | |||
2193 | *pTxPowerIndexOffset = 0; | 2314 | *pTxPowerIndexOffset = 0; |
2194 | 2315 | ||
2195 | return true; | 2316 | return true; |
2317 | #undef SM_PD_GAIN | ||
2318 | #undef SM_PDGAIN_B | ||
2196 | } | 2319 | } |
2197 | 2320 | ||
2198 | static bool ath9k_hw_set_def_power_per_rate_table(struct ath_hw *ah, | 2321 | static bool ath9k_hw_set_def_power_per_rate_table(struct ath_hw *ah, |
@@ -2493,13 +2616,14 @@ static int ath9k_hw_def_set_txpower(struct ath_hw *ah, | |||
2493 | u8 twiceMaxRegulatoryPower, | 2616 | u8 twiceMaxRegulatoryPower, |
2494 | u8 powerLimit) | 2617 | u8 powerLimit) |
2495 | { | 2618 | { |
2619 | #define RT_AR_DELTA(x) (ratesArray[x] - cck_ofdm_delta) | ||
2496 | struct ar5416_eeprom_def *pEepData = &ah->eeprom.def; | 2620 | struct ar5416_eeprom_def *pEepData = &ah->eeprom.def; |
2497 | struct modal_eep_header *pModal = | 2621 | struct modal_eep_header *pModal = |
2498 | &(pEepData->modalHeader[IS_CHAN_2GHZ(chan)]); | 2622 | &(pEepData->modalHeader[IS_CHAN_2GHZ(chan)]); |
2499 | int16_t ratesArray[Ar5416RateSize]; | 2623 | int16_t ratesArray[Ar5416RateSize]; |
2500 | int16_t txPowerIndexOffset = 0; | 2624 | int16_t txPowerIndexOffset = 0; |
2501 | u8 ht40PowerIncForPdadc = 2; | 2625 | u8 ht40PowerIncForPdadc = 2; |
2502 | int i; | 2626 | int i, cck_ofdm_delta = 0; |
2503 | 2627 | ||
2504 | memset(ratesArray, 0, sizeof(ratesArray)); | 2628 | memset(ratesArray, 0, sizeof(ratesArray)); |
2505 | 2629 | ||
@@ -2548,16 +2672,30 @@ static int ath9k_hw_def_set_txpower(struct ath_hw *ah, | |||
2548 | | ATH9K_POW_SM(ratesArray[rate24mb], 0)); | 2672 | | ATH9K_POW_SM(ratesArray[rate24mb], 0)); |
2549 | 2673 | ||
2550 | if (IS_CHAN_2GHZ(chan)) { | 2674 | if (IS_CHAN_2GHZ(chan)) { |
2551 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE3, | 2675 | if (OLC_FOR_AR9280_20_LATER) { |
2552 | ATH9K_POW_SM(ratesArray[rate2s], 24) | 2676 | cck_ofdm_delta = 2; |
2553 | | ATH9K_POW_SM(ratesArray[rate2l], 16) | 2677 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE3, |
2554 | | ATH9K_POW_SM(ratesArray[rateXr], 8) | 2678 | ATH9K_POW_SM(RT_AR_DELTA(rate2s), 24) |
2555 | | ATH9K_POW_SM(ratesArray[rate1l], 0)); | 2679 | | ATH9K_POW_SM(RT_AR_DELTA(rate2l), 16) |
2556 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE4, | 2680 | | ATH9K_POW_SM(ratesArray[rateXr], 8) |
2557 | ATH9K_POW_SM(ratesArray[rate11s], 24) | 2681 | | ATH9K_POW_SM(RT_AR_DELTA(rate1l), 0)); |
2558 | | ATH9K_POW_SM(ratesArray[rate11l], 16) | 2682 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE4, |
2559 | | ATH9K_POW_SM(ratesArray[rate5_5s], 8) | 2683 | ATH9K_POW_SM(RT_AR_DELTA(rate11s), 24) |
2560 | | ATH9K_POW_SM(ratesArray[rate5_5l], 0)); | 2684 | | ATH9K_POW_SM(RT_AR_DELTA(rate11l), 16) |
2685 | | ATH9K_POW_SM(RT_AR_DELTA(rate5_5s), 8) | ||
2686 | | ATH9K_POW_SM(RT_AR_DELTA(rate5_5l), 0)); | ||
2687 | } else { | ||
2688 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE3, | ||
2689 | ATH9K_POW_SM(ratesArray[rate2s], 24) | ||
2690 | | ATH9K_POW_SM(ratesArray[rate2l], 16) | ||
2691 | | ATH9K_POW_SM(ratesArray[rateXr], 8) | ||
2692 | | ATH9K_POW_SM(ratesArray[rate1l], 0)); | ||
2693 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE4, | ||
2694 | ATH9K_POW_SM(ratesArray[rate11s], 24) | ||
2695 | | ATH9K_POW_SM(ratesArray[rate11l], 16) | ||
2696 | | ATH9K_POW_SM(ratesArray[rate5_5s], 8) | ||
2697 | | ATH9K_POW_SM(ratesArray[rate5_5l], 0)); | ||
2698 | } | ||
2561 | } | 2699 | } |
2562 | 2700 | ||
2563 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE5, | 2701 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE5, |
@@ -2590,12 +2728,19 @@ static int ath9k_hw_def_set_txpower(struct ath_hw *ah, | |||
2590 | ht40PowerIncForPdadc, 8) | 2728 | ht40PowerIncForPdadc, 8) |
2591 | | ATH9K_POW_SM(ratesArray[rateHt40_4] + | 2729 | | ATH9K_POW_SM(ratesArray[rateHt40_4] + |
2592 | ht40PowerIncForPdadc, 0)); | 2730 | ht40PowerIncForPdadc, 0)); |
2593 | 2731 | if (OLC_FOR_AR9280_20_LATER) { | |
2594 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE9, | 2732 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE9, |
2595 | ATH9K_POW_SM(ratesArray[rateExtOfdm], 24) | 2733 | ATH9K_POW_SM(ratesArray[rateExtOfdm], 24) |
2596 | | ATH9K_POW_SM(ratesArray[rateExtCck], 16) | 2734 | | ATH9K_POW_SM(RT_AR_DELTA(rateExtCck), 16) |
2597 | | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8) | 2735 | | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8) |
2598 | | ATH9K_POW_SM(ratesArray[rateDupCck], 0)); | 2736 | | ATH9K_POW_SM(RT_AR_DELTA(rateDupCck), 0)); |
2737 | } else { | ||
2738 | REG_WRITE(ah, AR_PHY_POWER_TX_RATE9, | ||
2739 | ATH9K_POW_SM(ratesArray[rateExtOfdm], 24) | ||
2740 | | ATH9K_POW_SM(ratesArray[rateExtCck], 16) | ||
2741 | | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8) | ||
2742 | | ATH9K_POW_SM(ratesArray[rateDupCck], 0)); | ||
2743 | } | ||
2599 | } | 2744 | } |
2600 | 2745 | ||
2601 | REG_WRITE(ah, AR_PHY_POWER_TX_SUB, | 2746 | REG_WRITE(ah, AR_PHY_POWER_TX_SUB, |
@@ -2615,6 +2760,21 @@ static int ath9k_hw_def_set_txpower(struct ath_hw *ah, | |||
2615 | else | 2760 | else |
2616 | ah->regulatory.max_power_level = ratesArray[i]; | 2761 | ah->regulatory.max_power_level = ratesArray[i]; |
2617 | 2762 | ||
2763 | switch(ar5416_get_ntxchains(ah->txchainmask)) { | ||
2764 | case 1: | ||
2765 | break; | ||
2766 | case 2: | ||
2767 | ah->regulatory.max_power_level += INCREASE_MAXPOW_BY_TWO_CHAIN; | ||
2768 | break; | ||
2769 | case 3: | ||
2770 | ah->regulatory.max_power_level += INCREASE_MAXPOW_BY_THREE_CHAIN; | ||
2771 | break; | ||
2772 | default: | ||
2773 | DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, | ||
2774 | "Invalid chainmask configuration\n"); | ||
2775 | break; | ||
2776 | } | ||
2777 | |||
2618 | return 0; | 2778 | return 0; |
2619 | } | 2779 | } |
2620 | 2780 | ||
diff --git a/drivers/net/wireless/ath9k/eeprom.h b/drivers/net/wireless/ath9k/eeprom.h index 99863b570441..6296e3eff10b 100644 --- a/drivers/net/wireless/ath9k/eeprom.h +++ b/drivers/net/wireless/ath9k/eeprom.h | |||
@@ -75,11 +75,29 @@ | |||
75 | #define SUB_NUM_CTL_MODES_AT_5G_40 2 | 75 | #define SUB_NUM_CTL_MODES_AT_5G_40 2 |
76 | #define SUB_NUM_CTL_MODES_AT_2G_40 3 | 76 | #define SUB_NUM_CTL_MODES_AT_2G_40 3 |
77 | 77 | ||
78 | #define INCREASE_MAXPOW_BY_TWO_CHAIN 6 /* 10*log10(2)*2 */ | ||
79 | #define INCREASE_MAXPOW_BY_THREE_CHAIN 10 /* 10*log10(3)*2 */ | ||
80 | |||
81 | /* | ||
82 | * For AR9285 and later chipsets, the following bits are not being programmed | ||
83 | * in EEPROM and so need to be enabled always. | ||
84 | * | ||
85 | * Bit 0: en_fcc_mid | ||
86 | * Bit 1: en_jap_mid | ||
87 | * Bit 2: en_fcc_dfs_ht40 | ||
88 | * Bit 3: en_jap_ht40 | ||
89 | * Bit 4: en_jap_dfs_ht40 | ||
90 | */ | ||
91 | #define AR9285_RDEXT_DEFAULT 0x1F | ||
92 | |||
78 | #define AR_EEPROM_MAC(i) (0x1d+(i)) | 93 | #define AR_EEPROM_MAC(i) (0x1d+(i)) |
79 | #define ATH9K_POW_SM(_r, _s) (((_r) & 0x3f) << (_s)) | 94 | #define ATH9K_POW_SM(_r, _s) (((_r) & 0x3f) << (_s)) |
80 | #define FREQ2FBIN(x, y) ((y) ? ((x) - 2300) : (((x) - 4800) / 5)) | 95 | #define FREQ2FBIN(x, y) ((y) ? ((x) - 2300) : (((x) - 4800) / 5)) |
81 | #define ath9k_hw_use_flash(_ah) (!(_ah->ah_flags & AH_USE_EEPROM)) | 96 | #define ath9k_hw_use_flash(_ah) (!(_ah->ah_flags & AH_USE_EEPROM)) |
82 | 97 | ||
98 | #define OLC_FOR_AR9280_20_LATER (AR_SREV_9280_20_OR_LATER(ah) && \ | ||
99 | ah->eep_ops->get_eeprom(ah, EEP_OL_PWRCTRL)) | ||
100 | |||
83 | #define AR_EEPROM_RFSILENT_GPIO_SEL 0x001c | 101 | #define AR_EEPROM_RFSILENT_GPIO_SEL 0x001c |
84 | #define AR_EEPROM_RFSILENT_GPIO_SEL_S 2 | 102 | #define AR_EEPROM_RFSILENT_GPIO_SEL_S 2 |
85 | #define AR_EEPROM_RFSILENT_POLARITY 0x0002 | 103 | #define AR_EEPROM_RFSILENT_POLARITY 0x0002 |
@@ -110,6 +128,7 @@ | |||
110 | #define AR5416_EEP_MINOR_VER_17 0x11 | 128 | #define AR5416_EEP_MINOR_VER_17 0x11 |
111 | #define AR5416_EEP_MINOR_VER_19 0x13 | 129 | #define AR5416_EEP_MINOR_VER_19 0x13 |
112 | #define AR5416_EEP_MINOR_VER_20 0x14 | 130 | #define AR5416_EEP_MINOR_VER_20 0x14 |
131 | #define AR5416_EEP_MINOR_VER_22 0x16 | ||
113 | 132 | ||
114 | #define AR5416_NUM_5G_CAL_PIERS 8 | 133 | #define AR5416_NUM_5G_CAL_PIERS 8 |
115 | #define AR5416_NUM_2G_CAL_PIERS 4 | 134 | #define AR5416_NUM_2G_CAL_PIERS 4 |
@@ -152,6 +171,8 @@ | |||
152 | #define AR5416_EEP4K_PD_GAIN_ICEPTS 5 | 171 | #define AR5416_EEP4K_PD_GAIN_ICEPTS 5 |
153 | #define AR5416_EEP4K_MAX_CHAINS 1 | 172 | #define AR5416_EEP4K_MAX_CHAINS 1 |
154 | 173 | ||
174 | #define AR9280_TX_GAIN_TABLE_SIZE 22 | ||
175 | |||
155 | enum eeprom_param { | 176 | enum eeprom_param { |
156 | EEP_NFTHRESH_5, | 177 | EEP_NFTHRESH_5, |
157 | EEP_NFTHRESH_2, | 178 | EEP_NFTHRESH_2, |
@@ -172,7 +193,10 @@ enum eeprom_param { | |||
172 | EEP_RX_MASK, | 193 | EEP_RX_MASK, |
173 | EEP_RXGAIN_TYPE, | 194 | EEP_RXGAIN_TYPE, |
174 | EEP_TXGAIN_TYPE, | 195 | EEP_TXGAIN_TYPE, |
196 | EEP_OL_PWRCTRL, | ||
197 | EEP_RC_CHAIN_MASK, | ||
175 | EEP_DAC_HPWR_5G, | 198 | EEP_DAC_HPWR_5G, |
199 | EEP_FRAC_N_5G | ||
176 | }; | 200 | }; |
177 | 201 | ||
178 | enum ar5416_rates { | 202 | enum ar5416_rates { |
@@ -212,12 +236,14 @@ struct base_eep_header { | |||
212 | u8 futureBase_1[2]; | 236 | u8 futureBase_1[2]; |
213 | u8 rxGainType; | 237 | u8 rxGainType; |
214 | u8 dacHiPwrMode_5G; | 238 | u8 dacHiPwrMode_5G; |
215 | u8 futureBase_2; | 239 | u8 openLoopPwrCntl; |
216 | u8 dacLpMode; | 240 | u8 dacLpMode; |
217 | u8 txGainType; | 241 | u8 txGainType; |
218 | u8 rcChainMask; | 242 | u8 rcChainMask; |
219 | u8 desiredScaleCCK; | 243 | u8 desiredScaleCCK; |
220 | u8 futureBase_3[23]; | 244 | u8 power_table_offset; |
245 | u8 frac_n_5g; | ||
246 | u8 futureBase_3[21]; | ||
221 | } __packed; | 247 | } __packed; |
222 | 248 | ||
223 | struct base_eep_header_4k { | 249 | struct base_eep_header_4k { |
@@ -291,6 +317,13 @@ struct modal_eep_header { | |||
291 | struct spur_chan spurChans[AR5416_EEPROM_MODAL_SPURS]; | 317 | struct spur_chan spurChans[AR5416_EEPROM_MODAL_SPURS]; |
292 | } __packed; | 318 | } __packed; |
293 | 319 | ||
320 | struct calDataPerFreqOpLoop { | ||
321 | u8 pwrPdg[2][5]; | ||
322 | u8 vpdPdg[2][5]; | ||
323 | u8 pcdac[2][5]; | ||
324 | u8 empty[2][5]; | ||
325 | } __packed; | ||
326 | |||
294 | struct modal_eep_4k_header { | 327 | struct modal_eep_4k_header { |
295 | u32 antCtrlChain[AR5416_EEP4K_MAX_CHAINS]; | 328 | u32 antCtrlChain[AR5416_EEP4K_MAX_CHAINS]; |
296 | u32 antCtrlCommon; | 329 | u32 antCtrlCommon; |
diff --git a/drivers/net/wireless/ath9k/hw.c b/drivers/net/wireless/ath9k/hw.c index cad8e39c201e..2acbb84dc2ba 100644 --- a/drivers/net/wireless/ath9k/hw.c +++ b/drivers/net/wireless/ath9k/hw.c | |||
@@ -84,11 +84,13 @@ static u32 ath9k_hw_mac_to_clks(struct ath_hw *ah, u32 usecs) | |||
84 | return ath9k_hw_mac_clks(ah, usecs); | 84 | return ath9k_hw_mac_clks(ah, usecs); |
85 | } | 85 | } |
86 | 86 | ||
87 | bool ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val) | 87 | bool ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val, u32 timeout) |
88 | { | 88 | { |
89 | int i; | 89 | int i; |
90 | 90 | ||
91 | for (i = 0; i < (AH_TIMEOUT / AH_TIME_QUANTUM); i++) { | 91 | BUG_ON(timeout < AH_TIME_QUANTUM); |
92 | |||
93 | for (i = 0; i < (timeout / AH_TIME_QUANTUM); i++) { | ||
92 | if ((REG_READ(ah, reg) & mask) == val) | 94 | if ((REG_READ(ah, reg) & mask) == val) |
93 | return true; | 95 | return true; |
94 | 96 | ||
@@ -96,8 +98,8 @@ bool ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val) | |||
96 | } | 98 | } |
97 | 99 | ||
98 | DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, | 100 | DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, |
99 | "timeout on reg 0x%x: 0x%08x & 0x%08x != 0x%08x\n", | 101 | "timeout (%d us) on reg 0x%x: 0x%08x & 0x%08x != 0x%08x\n", |
100 | reg, REG_READ(ah, reg), mask, val); | 102 | timeout, reg, REG_READ(ah, reg), mask, val); |
101 | 103 | ||
102 | return false; | 104 | return false; |
103 | } | 105 | } |
@@ -823,7 +825,16 @@ static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc, | |||
823 | if (AR_SREV_9280_20(ah)) | 825 | if (AR_SREV_9280_20(ah)) |
824 | ath9k_hw_init_txgain_ini(ah); | 826 | ath9k_hw_init_txgain_ini(ah); |
825 | 827 | ||
826 | if (ah->hw_version.devid == AR9280_DEVID_PCI) { | 828 | if (!ath9k_hw_fill_cap_info(ah)) { |
829 | DPRINTF(sc, ATH_DBG_RESET, "failed ath9k_hw_fill_cap_info\n"); | ||
830 | ecode = -EINVAL; | ||
831 | goto bad; | ||
832 | } | ||
833 | |||
834 | if ((ah->hw_version.devid == AR9280_DEVID_PCI) && | ||
835 | test_bit(ATH9K_MODE_11A, ah->caps.wireless_modes)) { | ||
836 | |||
837 | /* EEPROM Fixup */ | ||
827 | for (i = 0; i < ah->iniModes.ia_rows; i++) { | 838 | for (i = 0; i < ah->iniModes.ia_rows; i++) { |
828 | u32 reg = INI_RA(&ah->iniModes, i, 0); | 839 | u32 reg = INI_RA(&ah->iniModes, i, 0); |
829 | 840 | ||
@@ -838,13 +849,6 @@ static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc, | |||
838 | } | 849 | } |
839 | } | 850 | } |
840 | 851 | ||
841 | if (!ath9k_hw_fill_cap_info(ah)) { | ||
842 | DPRINTF(sc, ATH_DBG_RESET, | ||
843 | "failed ath9k_hw_fill_cap_info\n"); | ||
844 | ecode = -EINVAL; | ||
845 | goto bad; | ||
846 | } | ||
847 | |||
848 | ecode = ath9k_hw_init_macaddr(ah); | 852 | ecode = ath9k_hw_init_macaddr(ah); |
849 | if (ecode != 0) { | 853 | if (ecode != 0) { |
850 | DPRINTF(sc, ATH_DBG_RESET, | 854 | DPRINTF(sc, ATH_DBG_RESET, |
@@ -1200,6 +1204,17 @@ static u32 ath9k_hw_ini_fixup(struct ath_hw *ah, | |||
1200 | return ath9k_hw_def_ini_fixup(ah, pEepData, reg, value); | 1204 | return ath9k_hw_def_ini_fixup(ah, pEepData, reg, value); |
1201 | } | 1205 | } |
1202 | 1206 | ||
1207 | static void ath9k_olc_init(struct ath_hw *ah) | ||
1208 | { | ||
1209 | u32 i; | ||
1210 | |||
1211 | for (i = 0; i < AR9280_TX_GAIN_TABLE_SIZE; i++) | ||
1212 | ah->originalGain[i] = | ||
1213 | MS(REG_READ(ah, AR_PHY_TX_GAIN_TBL1 + i * 4), | ||
1214 | AR_PHY_TX_GAIN); | ||
1215 | ah->PDADCdelta = 0; | ||
1216 | } | ||
1217 | |||
1203 | static int ath9k_hw_process_ini(struct ath_hw *ah, | 1218 | static int ath9k_hw_process_ini(struct ath_hw *ah, |
1204 | struct ath9k_channel *chan, | 1219 | struct ath9k_channel *chan, |
1205 | enum ath9k_ht_macmode macmode) | 1220 | enum ath9k_ht_macmode macmode) |
@@ -1306,6 +1321,9 @@ static int ath9k_hw_process_ini(struct ath_hw *ah, | |||
1306 | ath9k_hw_set_regs(ah, chan, macmode); | 1321 | ath9k_hw_set_regs(ah, chan, macmode); |
1307 | ath9k_hw_init_chain_masks(ah); | 1322 | ath9k_hw_init_chain_masks(ah); |
1308 | 1323 | ||
1324 | if (OLC_FOR_AR9280_20_LATER) | ||
1325 | ath9k_olc_init(ah); | ||
1326 | |||
1309 | status = ah->eep_ops->set_txpower(ah, chan, | 1327 | status = ah->eep_ops->set_txpower(ah, chan, |
1310 | ath9k_regd_get_ctl(ah, chan), | 1328 | ath9k_regd_get_ctl(ah, chan), |
1311 | channel->max_antenna_gain * 2, | 1329 | channel->max_antenna_gain * 2, |
@@ -1464,6 +1482,14 @@ static bool ath9k_hw_set_reset(struct ath_hw *ah, int type) | |||
1464 | u32 rst_flags; | 1482 | u32 rst_flags; |
1465 | u32 tmpReg; | 1483 | u32 tmpReg; |
1466 | 1484 | ||
1485 | if (AR_SREV_9100(ah)) { | ||
1486 | u32 val = REG_READ(ah, AR_RTC_DERIVED_CLK); | ||
1487 | val &= ~AR_RTC_DERIVED_CLK_PERIOD; | ||
1488 | val |= SM(1, AR_RTC_DERIVED_CLK_PERIOD); | ||
1489 | REG_WRITE(ah, AR_RTC_DERIVED_CLK, val); | ||
1490 | (void)REG_READ(ah, AR_RTC_DERIVED_CLK); | ||
1491 | } | ||
1492 | |||
1467 | REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN | | 1493 | REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN | |
1468 | AR_RTC_FORCE_WAKE_ON_INT); | 1494 | AR_RTC_FORCE_WAKE_ON_INT); |
1469 | 1495 | ||
@@ -1490,7 +1516,7 @@ static bool ath9k_hw_set_reset(struct ath_hw *ah, int type) | |||
1490 | udelay(50); | 1516 | udelay(50); |
1491 | 1517 | ||
1492 | REG_WRITE(ah, AR_RTC_RC, 0); | 1518 | REG_WRITE(ah, AR_RTC_RC, 0); |
1493 | if (!ath9k_hw_wait(ah, AR_RTC_RC, AR_RTC_RC_M, 0)) { | 1519 | if (!ath9k_hw_wait(ah, AR_RTC_RC, AR_RTC_RC_M, 0, AH_WAIT_TIMEOUT)) { |
1494 | DPRINTF(ah->ah_sc, ATH_DBG_RESET, | 1520 | DPRINTF(ah->ah_sc, ATH_DBG_RESET, |
1495 | "RTC stuck in MAC reset\n"); | 1521 | "RTC stuck in MAC reset\n"); |
1496 | return false; | 1522 | return false; |
@@ -1513,12 +1539,14 @@ static bool ath9k_hw_set_reset_power_on(struct ath_hw *ah) | |||
1513 | AR_RTC_FORCE_WAKE_ON_INT); | 1539 | AR_RTC_FORCE_WAKE_ON_INT); |
1514 | 1540 | ||
1515 | REG_WRITE(ah, AR_RTC_RESET, 0); | 1541 | REG_WRITE(ah, AR_RTC_RESET, 0); |
1542 | udelay(2); | ||
1516 | REG_WRITE(ah, AR_RTC_RESET, 1); | 1543 | REG_WRITE(ah, AR_RTC_RESET, 1); |
1517 | 1544 | ||
1518 | if (!ath9k_hw_wait(ah, | 1545 | if (!ath9k_hw_wait(ah, |
1519 | AR_RTC_STATUS, | 1546 | AR_RTC_STATUS, |
1520 | AR_RTC_STATUS_M, | 1547 | AR_RTC_STATUS_M, |
1521 | AR_RTC_STATUS_ON)) { | 1548 | AR_RTC_STATUS_ON, |
1549 | AH_WAIT_TIMEOUT)) { | ||
1522 | DPRINTF(ah->ah_sc, ATH_DBG_RESET, "RTC not waking up\n"); | 1550 | DPRINTF(ah->ah_sc, ATH_DBG_RESET, "RTC not waking up\n"); |
1523 | return false; | 1551 | return false; |
1524 | } | 1552 | } |
@@ -1580,7 +1608,10 @@ static void ath9k_hw_set_regs(struct ath_hw *ah, struct ath9k_channel *chan, | |||
1580 | static bool ath9k_hw_chip_reset(struct ath_hw *ah, | 1608 | static bool ath9k_hw_chip_reset(struct ath_hw *ah, |
1581 | struct ath9k_channel *chan) | 1609 | struct ath9k_channel *chan) |
1582 | { | 1610 | { |
1583 | if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_WARM)) | 1611 | if (OLC_FOR_AR9280_20_LATER) { |
1612 | if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_POWER_ON)) | ||
1613 | return false; | ||
1614 | } else if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_WARM)) | ||
1584 | return false; | 1615 | return false; |
1585 | 1616 | ||
1586 | if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) | 1617 | if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) |
@@ -1610,7 +1641,7 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah, | |||
1610 | 1641 | ||
1611 | REG_WRITE(ah, AR_PHY_RFBUS_REQ, AR_PHY_RFBUS_REQ_EN); | 1642 | REG_WRITE(ah, AR_PHY_RFBUS_REQ, AR_PHY_RFBUS_REQ_EN); |
1612 | if (!ath9k_hw_wait(ah, AR_PHY_RFBUS_GRANT, AR_PHY_RFBUS_GRANT_EN, | 1643 | if (!ath9k_hw_wait(ah, AR_PHY_RFBUS_GRANT, AR_PHY_RFBUS_GRANT_EN, |
1613 | AR_PHY_RFBUS_GRANT_EN)) { | 1644 | AR_PHY_RFBUS_GRANT_EN, AH_WAIT_TIMEOUT)) { |
1614 | DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, | 1645 | DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, |
1615 | "Could not kill baseband RX\n"); | 1646 | "Could not kill baseband RX\n"); |
1616 | return false; | 1647 | return false; |
@@ -2801,6 +2832,8 @@ bool ath9k_hw_getisr(struct ath_hw *ah, enum ath9k_int *masked) | |||
2801 | mask2 |= ATH9K_INT_GTT; | 2832 | mask2 |= ATH9K_INT_GTT; |
2802 | if (isr2 & AR_ISR_S2_CST) | 2833 | if (isr2 & AR_ISR_S2_CST) |
2803 | mask2 |= ATH9K_INT_CST; | 2834 | mask2 |= ATH9K_INT_CST; |
2835 | if (isr2 & AR_ISR_S2_TSFOOR) | ||
2836 | mask2 |= ATH9K_INT_TSFOOR; | ||
2804 | } | 2837 | } |
2805 | 2838 | ||
2806 | isr = REG_READ(ah, AR_ISR_RAC); | 2839 | isr = REG_READ(ah, AR_ISR_RAC); |
@@ -2946,7 +2979,9 @@ enum ath9k_int ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints) | |||
2946 | if (ints & ATH9K_INT_DTIMSYNC) | 2979 | if (ints & ATH9K_INT_DTIMSYNC) |
2947 | mask2 |= AR_IMR_S2_DTIMSYNC; | 2980 | mask2 |= AR_IMR_S2_DTIMSYNC; |
2948 | if (ints & ATH9K_INT_CABEND) | 2981 | if (ints & ATH9K_INT_CABEND) |
2949 | mask2 |= (AR_IMR_S2_CABEND); | 2982 | mask2 |= AR_IMR_S2_CABEND; |
2983 | if (ints & ATH9K_INT_TSFOOR) | ||
2984 | mask2 |= AR_IMR_S2_TSFOOR; | ||
2950 | } | 2985 | } |
2951 | 2986 | ||
2952 | if (ints & (ATH9K_INT_GTT | ATH9K_INT_CST)) { | 2987 | if (ints & (ATH9K_INT_GTT | ATH9K_INT_CST)) { |
@@ -3116,6 +3151,8 @@ void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah, | |||
3116 | AR_TBTT_TIMER_EN | AR_TIM_TIMER_EN | | 3151 | AR_TBTT_TIMER_EN | AR_TIM_TIMER_EN | |
3117 | AR_DTIM_TIMER_EN); | 3152 | AR_DTIM_TIMER_EN); |
3118 | 3153 | ||
3154 | /* TSF Out of Range Threshold */ | ||
3155 | REG_WRITE(ah, AR_TSFOOR_THRESHOLD, bs->bs_tsfoor_threshold); | ||
3119 | } | 3156 | } |
3120 | 3157 | ||
3121 | /*******************/ | 3158 | /*******************/ |
@@ -3128,10 +3165,11 @@ bool ath9k_hw_fill_cap_info(struct ath_hw *ah) | |||
3128 | u16 capField = 0, eeval; | 3165 | u16 capField = 0, eeval; |
3129 | 3166 | ||
3130 | eeval = ah->eep_ops->get_eeprom(ah, EEP_REG_0); | 3167 | eeval = ah->eep_ops->get_eeprom(ah, EEP_REG_0); |
3131 | |||
3132 | ah->regulatory.current_rd = eeval; | 3168 | ah->regulatory.current_rd = eeval; |
3133 | 3169 | ||
3134 | eeval = ah->eep_ops->get_eeprom(ah, EEP_REG_1); | 3170 | eeval = ah->eep_ops->get_eeprom(ah, EEP_REG_1); |
3171 | if (AR_SREV_9285_10_OR_LATER(ah)) | ||
3172 | eeval |= AR9285_RDEXT_DEFAULT; | ||
3135 | ah->regulatory.current_rd_ext = eeval; | 3173 | ah->regulatory.current_rd_ext = eeval; |
3136 | 3174 | ||
3137 | capField = ah->eep_ops->get_eeprom(ah, EEP_OP_CAP); | 3175 | capField = ah->eep_ops->get_eeprom(ah, EEP_OP_CAP); |
@@ -3182,14 +3220,11 @@ bool ath9k_hw_fill_cap_info(struct ath_hw *ah) | |||
3182 | } | 3220 | } |
3183 | 3221 | ||
3184 | pCap->tx_chainmask = ah->eep_ops->get_eeprom(ah, EEP_TX_MASK); | 3222 | pCap->tx_chainmask = ah->eep_ops->get_eeprom(ah, EEP_TX_MASK); |
3185 | if ((ah->is_pciexpress) | 3223 | if ((ah->hw_version.devid == AR5416_DEVID_PCI) && |
3186 | || (eeval & AR5416_OPFLAGS_11A)) { | 3224 | !(eeval & AR5416_OPFLAGS_11A)) |
3187 | pCap->rx_chainmask = | 3225 | pCap->rx_chainmask = ath9k_hw_gpio_get(ah, 0) ? 0x5 : 0x7; |
3188 | ah->eep_ops->get_eeprom(ah, EEP_RX_MASK); | 3226 | else |
3189 | } else { | 3227 | pCap->rx_chainmask = ah->eep_ops->get_eeprom(ah, EEP_RX_MASK); |
3190 | pCap->rx_chainmask = | ||
3191 | (ath9k_hw_gpio_get(ah, 0)) ? 0x5 : 0x7; | ||
3192 | } | ||
3193 | 3228 | ||
3194 | if (!(AR_SREV_9280(ah) && (ah->hw_version.macRev == 0))) | 3229 | if (!(AR_SREV_9280(ah) && (ah->hw_version.macRev == 0))) |
3195 | ah->misc_mode |= AR_PCU_MIC_NEW_LOC_ENA; | 3230 | ah->misc_mode |= AR_PCU_MIC_NEW_LOC_ENA; |
@@ -3317,8 +3352,6 @@ bool ath9k_hw_fill_cap_info(struct ath_hw *ah) | |||
3317 | bool ath9k_hw_getcapability(struct ath_hw *ah, enum ath9k_capability_type type, | 3352 | bool ath9k_hw_getcapability(struct ath_hw *ah, enum ath9k_capability_type type, |
3318 | u32 capability, u32 *result) | 3353 | u32 capability, u32 *result) |
3319 | { | 3354 | { |
3320 | const struct ath9k_hw_capabilities *pCap = &ah->caps; | ||
3321 | |||
3322 | switch (type) { | 3355 | switch (type) { |
3323 | case ATH9K_CAP_CIPHER: | 3356 | case ATH9K_CAP_CIPHER: |
3324 | switch (capability) { | 3357 | switch (capability) { |
@@ -3344,16 +3377,10 @@ bool ath9k_hw_getcapability(struct ath_hw *ah, enum ath9k_capability_type type, | |||
3344 | case ATH9K_CAP_TKIP_SPLIT: | 3377 | case ATH9K_CAP_TKIP_SPLIT: |
3345 | return (ah->misc_mode & AR_PCU_MIC_NEW_LOC_ENA) ? | 3378 | return (ah->misc_mode & AR_PCU_MIC_NEW_LOC_ENA) ? |
3346 | false : true; | 3379 | false : true; |
3347 | case ATH9K_CAP_WME_TKIPMIC: | ||
3348 | return 0; | ||
3349 | case ATH9K_CAP_PHYCOUNTERS: | ||
3350 | return ah->has_hw_phycounters ? 0 : -ENXIO; | ||
3351 | case ATH9K_CAP_DIVERSITY: | 3380 | case ATH9K_CAP_DIVERSITY: |
3352 | return (REG_READ(ah, AR_PHY_CCK_DETECT) & | 3381 | return (REG_READ(ah, AR_PHY_CCK_DETECT) & |
3353 | AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV) ? | 3382 | AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV) ? |
3354 | true : false; | 3383 | true : false; |
3355 | case ATH9K_CAP_PHYDIAG: | ||
3356 | return true; | ||
3357 | case ATH9K_CAP_MCAST_KEYSRCH: | 3384 | case ATH9K_CAP_MCAST_KEYSRCH: |
3358 | switch (capability) { | 3385 | switch (capability) { |
3359 | case 0: | 3386 | case 0: |
@@ -3368,18 +3395,6 @@ bool ath9k_hw_getcapability(struct ath_hw *ah, enum ath9k_capability_type type, | |||
3368 | } | 3395 | } |
3369 | } | 3396 | } |
3370 | return false; | 3397 | return false; |
3371 | case ATH9K_CAP_TSF_ADJUST: | ||
3372 | return (ah->misc_mode & AR_PCU_TX_ADD_TSF) ? | ||
3373 | true : false; | ||
3374 | case ATH9K_CAP_RFSILENT: | ||
3375 | if (capability == 3) | ||
3376 | return false; | ||
3377 | case ATH9K_CAP_ANT_CFG_2GHZ: | ||
3378 | *result = pCap->num_antcfg_2ghz; | ||
3379 | return true; | ||
3380 | case ATH9K_CAP_ANT_CFG_5GHZ: | ||
3381 | *result = pCap->num_antcfg_5ghz; | ||
3382 | return true; | ||
3383 | case ATH9K_CAP_TXPOW: | 3398 | case ATH9K_CAP_TXPOW: |
3384 | switch (capability) { | 3399 | switch (capability) { |
3385 | case 0: | 3400 | case 0: |
@@ -3395,6 +3410,10 @@ bool ath9k_hw_getcapability(struct ath_hw *ah, enum ath9k_capability_type type, | |||
3395 | return 0; | 3410 | return 0; |
3396 | } | 3411 | } |
3397 | return false; | 3412 | return false; |
3413 | case ATH9K_CAP_DS: | ||
3414 | return (AR_SREV_9280_20_OR_LATER(ah) && | ||
3415 | (ah->eep_ops->get_eeprom(ah, EEP_RC_CHAIN_MASK) == 1)) | ||
3416 | ? false : true; | ||
3398 | default: | 3417 | default: |
3399 | return false; | 3418 | return false; |
3400 | } | 3419 | } |
@@ -3428,12 +3447,6 @@ bool ath9k_hw_setcapability(struct ath_hw *ah, enum ath9k_capability_type type, | |||
3428 | else | 3447 | else |
3429 | ah->sta_id1_defaults &= ~AR_STA_ID1_MCAST_KSRCH; | 3448 | ah->sta_id1_defaults &= ~AR_STA_ID1_MCAST_KSRCH; |
3430 | return true; | 3449 | return true; |
3431 | case ATH9K_CAP_TSF_ADJUST: | ||
3432 | if (setting) | ||
3433 | ah->misc_mode |= AR_PCU_TX_ADD_TSF; | ||
3434 | else | ||
3435 | ah->misc_mode &= ~AR_PCU_TX_ADD_TSF; | ||
3436 | return true; | ||
3437 | default: | 3450 | default: |
3438 | return false; | 3451 | return false; |
3439 | } | 3452 | } |
diff --git a/drivers/net/wireless/ath9k/hw.h b/drivers/net/wireless/ath9k/hw.h index 82111636c693..5ec416b3d7ec 100644 --- a/drivers/net/wireless/ath9k/hw.h +++ b/drivers/net/wireless/ath9k/hw.h | |||
@@ -93,7 +93,7 @@ | |||
93 | #define ATH9K_NUM_QUEUES 10 | 93 | #define ATH9K_NUM_QUEUES 10 |
94 | 94 | ||
95 | #define MAX_RATE_POWER 63 | 95 | #define MAX_RATE_POWER 63 |
96 | #define AH_TIMEOUT 100000 | 96 | #define AH_WAIT_TIMEOUT 100000 /* (us) */ |
97 | #define AH_TIME_QUANTUM 10 | 97 | #define AH_TIME_QUANTUM 10 |
98 | #define AR_KEYTABLE_SIZE 128 | 98 | #define AR_KEYTABLE_SIZE 128 |
99 | #define POWER_UP_TIME 200000 | 99 | #define POWER_UP_TIME 200000 |
@@ -153,16 +153,10 @@ enum ath9k_capability_type { | |||
153 | ATH9K_CAP_CIPHER = 0, | 153 | ATH9K_CAP_CIPHER = 0, |
154 | ATH9K_CAP_TKIP_MIC, | 154 | ATH9K_CAP_TKIP_MIC, |
155 | ATH9K_CAP_TKIP_SPLIT, | 155 | ATH9K_CAP_TKIP_SPLIT, |
156 | ATH9K_CAP_PHYCOUNTERS, | ||
157 | ATH9K_CAP_DIVERSITY, | 156 | ATH9K_CAP_DIVERSITY, |
158 | ATH9K_CAP_TXPOW, | 157 | ATH9K_CAP_TXPOW, |
159 | ATH9K_CAP_PHYDIAG, | ||
160 | ATH9K_CAP_MCAST_KEYSRCH, | 158 | ATH9K_CAP_MCAST_KEYSRCH, |
161 | ATH9K_CAP_TSF_ADJUST, | 159 | ATH9K_CAP_DS |
162 | ATH9K_CAP_WME_TKIPMIC, | ||
163 | ATH9K_CAP_RFSILENT, | ||
164 | ATH9K_CAP_ANT_CFG_2GHZ, | ||
165 | ATH9K_CAP_ANT_CFG_5GHZ | ||
166 | }; | 160 | }; |
167 | 161 | ||
168 | struct ath9k_hw_capabilities { | 162 | struct ath9k_hw_capabilities { |
@@ -249,6 +243,7 @@ enum ath9k_int { | |||
249 | ATH9K_INT_DTIMSYNC = 0x00800000, | 243 | ATH9K_INT_DTIMSYNC = 0x00800000, |
250 | ATH9K_INT_GPIO = 0x01000000, | 244 | ATH9K_INT_GPIO = 0x01000000, |
251 | ATH9K_INT_CABEND = 0x02000000, | 245 | ATH9K_INT_CABEND = 0x02000000, |
246 | ATH9K_INT_TSFOOR = 0x04000000, | ||
252 | ATH9K_INT_CST = 0x10000000, | 247 | ATH9K_INT_CST = 0x10000000, |
253 | ATH9K_INT_GTT = 0x20000000, | 248 | ATH9K_INT_GTT = 0x20000000, |
254 | ATH9K_INT_FATAL = 0x40000000, | 249 | ATH9K_INT_FATAL = 0x40000000, |
@@ -256,6 +251,7 @@ enum ath9k_int { | |||
256 | ATH9K_INT_BMISC = ATH9K_INT_TIM | | 251 | ATH9K_INT_BMISC = ATH9K_INT_TIM | |
257 | ATH9K_INT_DTIM | | 252 | ATH9K_INT_DTIM | |
258 | ATH9K_INT_DTIMSYNC | | 253 | ATH9K_INT_DTIMSYNC | |
254 | ATH9K_INT_TSFOOR | | ||
259 | ATH9K_INT_CABEND, | 255 | ATH9K_INT_CABEND, |
260 | ATH9K_INT_COMMON = ATH9K_INT_RXNOFRM | | 256 | ATH9K_INT_COMMON = ATH9K_INT_RXNOFRM | |
261 | ATH9K_INT_RXDESC | | 257 | ATH9K_INT_RXDESC | |
@@ -385,6 +381,7 @@ struct ath9k_beacon_state { | |||
385 | #define ATH9K_BEACON_PERIOD 0x0000ffff | 381 | #define ATH9K_BEACON_PERIOD 0x0000ffff |
386 | #define ATH9K_BEACON_ENA 0x00800000 | 382 | #define ATH9K_BEACON_ENA 0x00800000 |
387 | #define ATH9K_BEACON_RESET_TSF 0x01000000 | 383 | #define ATH9K_BEACON_RESET_TSF 0x01000000 |
384 | #define ATH9K_TSFOOR_THRESHOLD 0x00004240 /* 16k us */ | ||
388 | u32 bs_dtimperiod; | 385 | u32 bs_dtimperiod; |
389 | u16 bs_cfpperiod; | 386 | u16 bs_cfpperiod; |
390 | u16 bs_cfpmaxduration; | 387 | u16 bs_cfpmaxduration; |
@@ -392,6 +389,7 @@ struct ath9k_beacon_state { | |||
392 | u16 bs_timoffset; | 389 | u16 bs_timoffset; |
393 | u16 bs_bmissthreshold; | 390 | u16 bs_bmissthreshold; |
394 | u32 bs_sleepduration; | 391 | u32 bs_sleepduration; |
392 | u32 bs_tsfoor_threshold; | ||
395 | }; | 393 | }; |
396 | 394 | ||
397 | struct chan_centers { | 395 | struct chan_centers { |
@@ -547,6 +545,10 @@ struct ath_hw { | |||
547 | u8 txchainmask; | 545 | u8 txchainmask; |
548 | u8 rxchainmask; | 546 | u8 rxchainmask; |
549 | 547 | ||
548 | u32 originalGain[22]; | ||
549 | int initPDADC; | ||
550 | int PDADCdelta; | ||
551 | |||
550 | struct ar5416IniArray iniModes; | 552 | struct ar5416IniArray iniModes; |
551 | struct ar5416IniArray iniCommon; | 553 | struct ar5416IniArray iniCommon; |
552 | struct ar5416IniArray iniBank0; | 554 | struct ar5416IniArray iniBank0; |
@@ -603,7 +605,7 @@ bool ath9k_hw_setantennaswitch(struct ath_hw *ah, | |||
603 | u8 *antenna_cfgd); | 605 | u8 *antenna_cfgd); |
604 | 606 | ||
605 | /* General Operation */ | 607 | /* General Operation */ |
606 | bool ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val); | 608 | bool ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val, u32 timeout); |
607 | u32 ath9k_hw_reverse_bits(u32 val, u32 n); | 609 | u32 ath9k_hw_reverse_bits(u32 val, u32 n); |
608 | bool ath9k_get_channel_edges(struct ath_hw *ah, u16 flags, u16 *low, u16 *high); | 610 | bool ath9k_get_channel_edges(struct ath_hw *ah, u16 flags, u16 *low, u16 *high); |
609 | u16 ath9k_hw_computetxtime(struct ath_hw *ah, struct ath_rate_table *rates, | 611 | u16 ath9k_hw_computetxtime(struct ath_hw *ah, struct ath_rate_table *rates, |
diff --git a/drivers/net/wireless/ath9k/mac.c b/drivers/net/wireless/ath9k/mac.c index f32c622db6e7..f757bc7eec68 100644 --- a/drivers/net/wireless/ath9k/mac.c +++ b/drivers/net/wireless/ath9k/mac.c | |||
@@ -285,7 +285,7 @@ int ath9k_hw_txprocdesc(struct ath_hw *ah, struct ath_desc *ds) | |||
285 | ds->ds_txstat.ts_shortretry = MS(ads->ds_txstatus1, AR_RTSFailCnt); | 285 | ds->ds_txstat.ts_shortretry = MS(ads->ds_txstatus1, AR_RTSFailCnt); |
286 | ds->ds_txstat.ts_longretry = MS(ads->ds_txstatus1, AR_DataFailCnt); | 286 | ds->ds_txstat.ts_longretry = MS(ads->ds_txstatus1, AR_DataFailCnt); |
287 | ds->ds_txstat.ts_virtcol = MS(ads->ds_txstatus1, AR_VirtRetryCnt); | 287 | ds->ds_txstat.ts_virtcol = MS(ads->ds_txstatus1, AR_VirtRetryCnt); |
288 | ds->ds_txstat.ts_antenna = 1; | 288 | ds->ds_txstat.ts_antenna = 0; |
289 | 289 | ||
290 | return 0; | 290 | return 0; |
291 | } | 291 | } |
@@ -886,7 +886,8 @@ bool ath9k_hw_setrxabort(struct ath_hw *ah, bool set) | |||
886 | REG_SET_BIT(ah, AR_DIAG_SW, | 886 | REG_SET_BIT(ah, AR_DIAG_SW, |
887 | (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT)); | 887 | (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT)); |
888 | 888 | ||
889 | if (!ath9k_hw_wait(ah, AR_OBS_BUS_1, AR_OBS_BUS_1_RX_STATE, 0)) { | 889 | if (!ath9k_hw_wait(ah, AR_OBS_BUS_1, AR_OBS_BUS_1_RX_STATE, |
890 | 0, AH_WAIT_TIMEOUT)) { | ||
890 | REG_CLR_BIT(ah, AR_DIAG_SW, | 891 | REG_CLR_BIT(ah, AR_DIAG_SW, |
891 | (AR_DIAG_RX_DIS | | 892 | (AR_DIAG_RX_DIS | |
892 | AR_DIAG_RX_ABORT)); | 893 | AR_DIAG_RX_ABORT)); |
@@ -933,15 +934,32 @@ void ath9k_hw_stoppcurecv(struct ath_hw *ah) | |||
933 | 934 | ||
934 | bool ath9k_hw_stopdmarecv(struct ath_hw *ah) | 935 | bool ath9k_hw_stopdmarecv(struct ath_hw *ah) |
935 | { | 936 | { |
937 | #define AH_RX_STOP_DMA_TIMEOUT 10000 /* usec */ | ||
938 | #define AH_RX_TIME_QUANTUM 100 /* usec */ | ||
939 | |||
940 | int i; | ||
941 | |||
936 | REG_WRITE(ah, AR_CR, AR_CR_RXD); | 942 | REG_WRITE(ah, AR_CR, AR_CR_RXD); |
937 | 943 | ||
938 | if (!ath9k_hw_wait(ah, AR_CR, AR_CR_RXE, 0)) { | 944 | /* Wait for rx enable bit to go low */ |
945 | for (i = AH_RX_STOP_DMA_TIMEOUT / AH_TIME_QUANTUM; i != 0; i--) { | ||
946 | if ((REG_READ(ah, AR_CR) & AR_CR_RXE) == 0) | ||
947 | break; | ||
948 | udelay(AH_TIME_QUANTUM); | ||
949 | } | ||
950 | |||
951 | if (i == 0) { | ||
939 | DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, | 952 | DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, |
940 | "dma failed to stop in 10ms\n" | 953 | "dma failed to stop in %d ms " |
941 | "AR_CR=0x%08x\nAR_DIAG_SW=0x%08x\n", | 954 | "AR_CR=0x%08x AR_DIAG_SW=0x%08x\n", |
942 | REG_READ(ah, AR_CR), REG_READ(ah, AR_DIAG_SW)); | 955 | AH_RX_STOP_DMA_TIMEOUT / 1000, |
956 | REG_READ(ah, AR_CR), | ||
957 | REG_READ(ah, AR_DIAG_SW)); | ||
943 | return false; | 958 | return false; |
944 | } else { | 959 | } else { |
945 | return true; | 960 | return true; |
946 | } | 961 | } |
962 | |||
963 | #undef AH_RX_TIME_QUANTUM | ||
964 | #undef AH_RX_STOP_DMA_TIMEOUT | ||
947 | } | 965 | } |
diff --git a/drivers/net/wireless/ath9k/mac.h b/drivers/net/wireless/ath9k/mac.h index 74b660ae8add..862a63f7634b 100644 --- a/drivers/net/wireless/ath9k/mac.h +++ b/drivers/net/wireless/ath9k/mac.h | |||
@@ -566,8 +566,9 @@ enum ath9k_rx_filter { | |||
566 | ATH9K_RX_FILTER_BEACON = 0x00000010, | 566 | ATH9K_RX_FILTER_BEACON = 0x00000010, |
567 | ATH9K_RX_FILTER_PROM = 0x00000020, | 567 | ATH9K_RX_FILTER_PROM = 0x00000020, |
568 | ATH9K_RX_FILTER_PROBEREQ = 0x00000080, | 568 | ATH9K_RX_FILTER_PROBEREQ = 0x00000080, |
569 | ATH9K_RX_FILTER_PSPOLL = 0x00004000, | ||
570 | ATH9K_RX_FILTER_PHYERR = 0x00000100, | 569 | ATH9K_RX_FILTER_PHYERR = 0x00000100, |
570 | ATH9K_RX_FILTER_MYBEACON = 0x00000200, | ||
571 | ATH9K_RX_FILTER_PSPOLL = 0x00004000, | ||
571 | ATH9K_RX_FILTER_PHYRADAR = 0x00002000, | 572 | ATH9K_RX_FILTER_PHYRADAR = 0x00002000, |
572 | }; | 573 | }; |
573 | 574 | ||
diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index 7d7537e2738e..f5f5739a7a4b 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c | |||
@@ -308,23 +308,23 @@ static int ath_set_channel(struct ath_softc *sc, struct ath9k_channel *hchan) | |||
308 | */ | 308 | */ |
309 | static void ath_ani_calibrate(unsigned long data) | 309 | static void ath_ani_calibrate(unsigned long data) |
310 | { | 310 | { |
311 | struct ath_softc *sc; | 311 | struct ath_softc *sc = (struct ath_softc *)data; |
312 | struct ath_hw *ah; | 312 | struct ath_hw *ah = sc->sc_ah; |
313 | bool longcal = false; | 313 | bool longcal = false; |
314 | bool shortcal = false; | 314 | bool shortcal = false; |
315 | bool aniflag = false; | 315 | bool aniflag = false; |
316 | unsigned int timestamp = jiffies_to_msecs(jiffies); | 316 | unsigned int timestamp = jiffies_to_msecs(jiffies); |
317 | u32 cal_interval; | 317 | u32 cal_interval, short_cal_interval; |
318 | 318 | ||
319 | sc = (struct ath_softc *)data; | 319 | short_cal_interval = (ah->opmode == NL80211_IFTYPE_AP) ? |
320 | ah = sc->sc_ah; | 320 | ATH_AP_SHORT_CALINTERVAL : ATH_STA_SHORT_CALINTERVAL; |
321 | 321 | ||
322 | /* | 322 | /* |
323 | * don't calibrate when we're scanning. | 323 | * don't calibrate when we're scanning. |
324 | * we are most likely not on our home channel. | 324 | * we are most likely not on our home channel. |
325 | */ | 325 | */ |
326 | if (sc->rx.rxfilter & FIF_BCN_PRBRESP_PROMISC) | 326 | if (sc->rx.rxfilter & FIF_BCN_PRBRESP_PROMISC) |
327 | return; | 327 | goto set_timer; |
328 | 328 | ||
329 | /* Long calibration runs independently of short calibration. */ | 329 | /* Long calibration runs independently of short calibration. */ |
330 | if ((timestamp - sc->ani.longcal_timer) >= ATH_LONG_CALINTERVAL) { | 330 | if ((timestamp - sc->ani.longcal_timer) >= ATH_LONG_CALINTERVAL) { |
@@ -335,8 +335,7 @@ static void ath_ani_calibrate(unsigned long data) | |||
335 | 335 | ||
336 | /* Short calibration applies only while caldone is false */ | 336 | /* Short calibration applies only while caldone is false */ |
337 | if (!sc->ani.caldone) { | 337 | if (!sc->ani.caldone) { |
338 | if ((timestamp - sc->ani.shortcal_timer) >= | 338 | if ((timestamp - sc->ani.shortcal_timer) >= short_cal_interval) { |
339 | ATH_SHORT_CALINTERVAL) { | ||
340 | shortcal = true; | 339 | shortcal = true; |
341 | DPRINTF(sc, ATH_DBG_ANI, "shortcal @%lu\n", jiffies); | 340 | DPRINTF(sc, ATH_DBG_ANI, "shortcal @%lu\n", jiffies); |
342 | sc->ani.shortcal_timer = timestamp; | 341 | sc->ani.shortcal_timer = timestamp; |
@@ -352,8 +351,7 @@ static void ath_ani_calibrate(unsigned long data) | |||
352 | } | 351 | } |
353 | 352 | ||
354 | /* Verify whether we must check ANI */ | 353 | /* Verify whether we must check ANI */ |
355 | if ((timestamp - sc->ani.checkani_timer) >= | 354 | if ((timestamp - sc->ani.checkani_timer) >= ATH_ANI_POLLINTERVAL) { |
356 | ATH_ANI_POLLINTERVAL) { | ||
357 | aniflag = true; | 355 | aniflag = true; |
358 | sc->ani.checkani_timer = timestamp; | 356 | sc->ani.checkani_timer = timestamp; |
359 | } | 357 | } |
@@ -362,8 +360,7 @@ static void ath_ani_calibrate(unsigned long data) | |||
362 | if (longcal || shortcal || aniflag) { | 360 | if (longcal || shortcal || aniflag) { |
363 | /* Call ANI routine if necessary */ | 361 | /* Call ANI routine if necessary */ |
364 | if (aniflag) | 362 | if (aniflag) |
365 | ath9k_hw_ani_monitor(ah, &sc->nodestats, | 363 | ath9k_hw_ani_monitor(ah, &sc->nodestats, ah->curchan); |
366 | ah->curchan); | ||
367 | 364 | ||
368 | /* Perform calibration if necessary */ | 365 | /* Perform calibration if necessary */ |
369 | if (longcal || shortcal) { | 366 | if (longcal || shortcal) { |
@@ -392,6 +389,7 @@ static void ath_ani_calibrate(unsigned long data) | |||
392 | } | 389 | } |
393 | } | 390 | } |
394 | 391 | ||
392 | set_timer: | ||
395 | /* | 393 | /* |
396 | * Set timer interval based on previous results. | 394 | * Set timer interval based on previous results. |
397 | * The interval must be the shortest necessary to satisfy ANI, | 395 | * The interval must be the shortest necessary to satisfy ANI, |
@@ -401,7 +399,7 @@ static void ath_ani_calibrate(unsigned long data) | |||
401 | if (sc->sc_ah->config.enable_ani) | 399 | if (sc->sc_ah->config.enable_ani) |
402 | cal_interval = min(cal_interval, (u32)ATH_ANI_POLLINTERVAL); | 400 | cal_interval = min(cal_interval, (u32)ATH_ANI_POLLINTERVAL); |
403 | if (!sc->ani.caldone) | 401 | if (!sc->ani.caldone) |
404 | cal_interval = min(cal_interval, (u32)ATH_SHORT_CALINTERVAL); | 402 | cal_interval = min(cal_interval, (u32)short_cal_interval); |
405 | 403 | ||
406 | mod_timer(&sc->ani.timer, jiffies + msecs_to_jiffies(cal_interval)); | 404 | mod_timer(&sc->ani.timer, jiffies + msecs_to_jiffies(cal_interval)); |
407 | } | 405 | } |
@@ -574,6 +572,10 @@ irqreturn_t ath_isr(int irq, void *dev) | |||
574 | sc->sc_flags |= SC_OP_WAIT_FOR_BEACON; | 572 | sc->sc_flags |= SC_OP_WAIT_FOR_BEACON; |
575 | } | 573 | } |
576 | } | 574 | } |
575 | if (status & ATH9K_INT_TSFOOR) { | ||
576 | /* FIXME: Handle this interrupt for power save */ | ||
577 | sched = true; | ||
578 | } | ||
577 | } | 579 | } |
578 | } while (0); | 580 | } while (0); |
579 | 581 | ||
@@ -920,8 +922,7 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc, | |||
920 | 922 | ||
921 | /* Start ANI */ | 923 | /* Start ANI */ |
922 | mod_timer(&sc->ani.timer, | 924 | mod_timer(&sc->ani.timer, |
923 | jiffies + msecs_to_jiffies(ATH_ANI_POLLINTERVAL)); | 925 | jiffies + msecs_to_jiffies(ATH_ANI_POLLINTERVAL)); |
924 | |||
925 | } else { | 926 | } else { |
926 | DPRINTF(sc, ATH_DBG_CONFIG, "Bss Info DISSOC\n"); | 927 | DPRINTF(sc, ATH_DBG_CONFIG, "Bss Info DISSOC\n"); |
927 | sc->curaid = 0; | 928 | sc->curaid = 0; |
@@ -1566,6 +1567,7 @@ bad: | |||
1566 | int ath_attach(u16 devid, struct ath_softc *sc) | 1567 | int ath_attach(u16 devid, struct ath_softc *sc) |
1567 | { | 1568 | { |
1568 | struct ieee80211_hw *hw = sc->hw; | 1569 | struct ieee80211_hw *hw = sc->hw; |
1570 | const struct ieee80211_regdomain *regd; | ||
1569 | int error = 0, i; | 1571 | int error = 0, i; |
1570 | 1572 | ||
1571 | DPRINTF(sc, ATH_DBG_CONFIG, "Attach ATH hw\n"); | 1573 | DPRINTF(sc, ATH_DBG_CONFIG, "Attach ATH hw\n"); |
@@ -1598,6 +1600,7 @@ int ath_attach(u16 devid, struct ath_softc *sc) | |||
1598 | 1600 | ||
1599 | hw->queues = 4; | 1601 | hw->queues = 4; |
1600 | hw->max_rates = 4; | 1602 | hw->max_rates = 4; |
1603 | hw->channel_change_time = 5000; | ||
1601 | hw->max_rate_tries = ATH_11N_TXMAXTRY; | 1604 | hw->max_rate_tries = ATH_11N_TXMAXTRY; |
1602 | hw->sta_data_size = sizeof(struct ath_node); | 1605 | hw->sta_data_size = sizeof(struct ath_node); |
1603 | hw->vif_data_size = sizeof(struct ath_vif); | 1606 | hw->vif_data_size = sizeof(struct ath_vif); |
@@ -1636,30 +1639,29 @@ int ath_attach(u16 devid, struct ath_softc *sc) | |||
1636 | #endif | 1639 | #endif |
1637 | 1640 | ||
1638 | if (ath9k_is_world_regd(sc->sc_ah)) { | 1641 | if (ath9k_is_world_regd(sc->sc_ah)) { |
1639 | /* Anything applied here (prior to wiphy registratoin) gets | 1642 | /* Anything applied here (prior to wiphy registration) gets |
1640 | * saved on the wiphy orig_* parameters */ | 1643 | * saved on the wiphy orig_* parameters */ |
1641 | const struct ieee80211_regdomain *regd = | 1644 | regd = ath9k_world_regdomain(sc->sc_ah); |
1642 | ath9k_world_regdomain(sc->sc_ah); | ||
1643 | hw->wiphy->custom_regulatory = true; | 1645 | hw->wiphy->custom_regulatory = true; |
1644 | hw->wiphy->strict_regulatory = false; | 1646 | hw->wiphy->strict_regulatory = false; |
1645 | wiphy_apply_custom_regulatory(sc->hw->wiphy, regd); | ||
1646 | ath9k_reg_apply_radar_flags(hw->wiphy); | ||
1647 | ath9k_reg_apply_world_flags(hw->wiphy, REGDOM_SET_BY_INIT); | ||
1648 | } else { | 1647 | } else { |
1649 | /* This gets applied in the case of the absense of CRDA, | 1648 | /* This gets applied in the case of the absense of CRDA, |
1650 | * its our own custom world regulatory domain, similar to | 1649 | * it's our own custom world regulatory domain, similar to |
1651 | * cfg80211's but we enable passive scanning */ | 1650 | * cfg80211's but we enable passive scanning */ |
1652 | const struct ieee80211_regdomain *regd = | 1651 | regd = ath9k_default_world_regdomain(); |
1653 | ath9k_default_world_regdomain(); | ||
1654 | wiphy_apply_custom_regulatory(sc->hw->wiphy, regd); | ||
1655 | ath9k_reg_apply_radar_flags(hw->wiphy); | ||
1656 | ath9k_reg_apply_world_flags(hw->wiphy, REGDOM_SET_BY_INIT); | ||
1657 | } | 1652 | } |
1653 | wiphy_apply_custom_regulatory(hw->wiphy, regd); | ||
1654 | ath9k_reg_apply_radar_flags(hw->wiphy); | ||
1655 | ath9k_reg_apply_world_flags(hw->wiphy, REGDOM_SET_BY_INIT); | ||
1658 | 1656 | ||
1659 | error = ieee80211_register_hw(hw); | 1657 | error = ieee80211_register_hw(hw); |
1660 | 1658 | ||
1661 | if (!ath9k_is_world_regd(sc->sc_ah)) | 1659 | if (!ath9k_is_world_regd(sc->sc_ah)) { |
1662 | regulatory_hint(hw->wiphy, sc->sc_ah->regulatory.alpha2); | 1660 | error = regulatory_hint(hw->wiphy, |
1661 | sc->sc_ah->regulatory.alpha2); | ||
1662 | if (error) | ||
1663 | goto error_attach; | ||
1664 | } | ||
1663 | 1665 | ||
1664 | /* Initialize LED control */ | 1666 | /* Initialize LED control */ |
1665 | ath_init_leds(sc); | 1667 | ath_init_leds(sc); |
@@ -2143,6 +2145,7 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, | |||
2143 | default: | 2145 | default: |
2144 | DPRINTF(sc, ATH_DBG_FATAL, | 2146 | DPRINTF(sc, ATH_DBG_FATAL, |
2145 | "Interface type %d not yet supported\n", conf->type); | 2147 | "Interface type %d not yet supported\n", conf->type); |
2148 | mutex_unlock(&sc->mutex); | ||
2146 | return -EOPNOTSUPP; | 2149 | return -EOPNOTSUPP; |
2147 | } | 2150 | } |
2148 | 2151 | ||
@@ -2165,10 +2168,13 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, | |||
2165 | * Enable MIB interrupts when there are hardware phy counters. | 2168 | * Enable MIB interrupts when there are hardware phy counters. |
2166 | * Note we only do this (at the moment) for station mode. | 2169 | * Note we only do this (at the moment) for station mode. |
2167 | */ | 2170 | */ |
2168 | if (ath9k_hw_phycounters(sc->sc_ah) && | 2171 | if ((conf->type == NL80211_IFTYPE_STATION) || |
2169 | ((conf->type == NL80211_IFTYPE_STATION) || | 2172 | (conf->type == NL80211_IFTYPE_ADHOC)) { |
2170 | (conf->type == NL80211_IFTYPE_ADHOC))) | 2173 | if (ath9k_hw_phycounters(sc->sc_ah)) |
2171 | sc->imask |= ATH9K_INT_MIB; | 2174 | sc->imask |= ATH9K_INT_MIB; |
2175 | sc->imask |= ATH9K_INT_TSFOOR; | ||
2176 | } | ||
2177 | |||
2172 | /* | 2178 | /* |
2173 | * Some hardware processes the TIM IE and fires an | 2179 | * Some hardware processes the TIM IE and fires an |
2174 | * interrupt when the TIM bit is set. For hardware | 2180 | * interrupt when the TIM bit is set. For hardware |
diff --git a/drivers/net/wireless/ath9k/pci.c b/drivers/net/wireless/ath9k/pci.c index c28afe42b269..eea9d3a9d43c 100644 --- a/drivers/net/wireless/ath9k/pci.c +++ b/drivers/net/wireless/ath9k/pci.c | |||
@@ -52,8 +52,8 @@ static void ath_pci_cleanup(struct ath_softc *sc) | |||
52 | struct pci_dev *pdev = to_pci_dev(sc->dev); | 52 | struct pci_dev *pdev = to_pci_dev(sc->dev); |
53 | 53 | ||
54 | pci_iounmap(pdev, sc->mem); | 54 | pci_iounmap(pdev, sc->mem); |
55 | pci_release_region(pdev, 0); | ||
56 | pci_disable_device(pdev); | 55 | pci_disable_device(pdev); |
56 | pci_release_region(pdev, 0); | ||
57 | } | 57 | } |
58 | 58 | ||
59 | static bool ath_pci_eeprom_read(struct ath_hw *ah, u32 off, u16 *data) | 59 | static bool ath_pci_eeprom_read(struct ath_hw *ah, u32 off, u16 *data) |
@@ -63,7 +63,8 @@ static bool ath_pci_eeprom_read(struct ath_hw *ah, u32 off, u16 *data) | |||
63 | if (!ath9k_hw_wait(ah, | 63 | if (!ath9k_hw_wait(ah, |
64 | AR_EEPROM_STATUS_DATA, | 64 | AR_EEPROM_STATUS_DATA, |
65 | AR_EEPROM_STATUS_DATA_BUSY | | 65 | AR_EEPROM_STATUS_DATA_BUSY | |
66 | AR_EEPROM_STATUS_DATA_PROT_ACCESS, 0)) { | 66 | AR_EEPROM_STATUS_DATA_PROT_ACCESS, 0, |
67 | AH_WAIT_TIMEOUT)) { | ||
67 | return false; | 68 | return false; |
68 | } | 69 | } |
69 | 70 | ||
@@ -292,7 +293,7 @@ static struct pci_driver ath_pci_driver = { | |||
292 | #endif /* CONFIG_PM */ | 293 | #endif /* CONFIG_PM */ |
293 | }; | 294 | }; |
294 | 295 | ||
295 | int __init ath_pci_init(void) | 296 | int ath_pci_init(void) |
296 | { | 297 | { |
297 | return pci_register_driver(&ath_pci_driver); | 298 | return pci_register_driver(&ath_pci_driver); |
298 | } | 299 | } |
diff --git a/drivers/net/wireless/ath9k/phy.c b/drivers/net/wireless/ath9k/phy.c index 52aa2a7abe7a..e1494bae0f9f 100644 --- a/drivers/net/wireless/ath9k/phy.c +++ b/drivers/net/wireless/ath9k/phy.c | |||
@@ -132,20 +132,27 @@ ath9k_hw_ar9280_set_channel(struct ath_hw *ah, | |||
132 | bMode = 0; | 132 | bMode = 0; |
133 | fracMode = 0; | 133 | fracMode = 0; |
134 | 134 | ||
135 | if ((freq % 20) == 0) { | 135 | switch(ah->eep_ops->get_eeprom(ah, EEP_FRAC_N_5G)) { |
136 | aModeRefSel = 3; | 136 | case 0: |
137 | } else if ((freq % 10) == 0) { | 137 | if ((freq % 20) == 0) { |
138 | aModeRefSel = 2; | 138 | aModeRefSel = 3; |
139 | } else { | 139 | } else if ((freq % 10) == 0) { |
140 | aModeRefSel = 2; | ||
141 | } | ||
142 | if (aModeRefSel) | ||
143 | break; | ||
144 | case 1: | ||
145 | default: | ||
140 | aModeRefSel = 0; | 146 | aModeRefSel = 0; |
141 | |||
142 | fracMode = 1; | 147 | fracMode = 1; |
143 | refDivA = 1; | 148 | refDivA = 1; |
144 | channelSel = (freq * 0x8000) / 15; | 149 | channelSel = (freq * 0x8000) / 15; |
145 | 150 | ||
146 | REG_RMW_FIELD(ah, AR_AN_SYNTH9, | 151 | REG_RMW_FIELD(ah, AR_AN_SYNTH9, |
147 | AR_AN_SYNTH9_REFDIVA, refDivA); | 152 | AR_AN_SYNTH9_REFDIVA, refDivA); |
153 | |||
148 | } | 154 | } |
155 | |||
149 | if (!fracMode) { | 156 | if (!fracMode) { |
150 | ndiv = (freq * (refDivA >> aModeRefSel)) / 60; | 157 | ndiv = (freq * (refDivA >> aModeRefSel)) / 60; |
151 | channelSel = ndiv & 0x1ff; | 158 | channelSel = ndiv & 0x1ff; |
diff --git a/drivers/net/wireless/ath9k/phy.h b/drivers/net/wireless/ath9k/phy.h index 837a598a7ae5..3dbdd54be4e9 100644 --- a/drivers/net/wireless/ath9k/phy.h +++ b/drivers/net/wireless/ath9k/phy.h | |||
@@ -387,6 +387,8 @@ bool ath9k_hw_init_rf(struct ath_hw *ah, | |||
387 | 387 | ||
388 | #define AR_PHY_CCK_TX_CTRL 0xA204 | 388 | #define AR_PHY_CCK_TX_CTRL 0xA204 |
389 | #define AR_PHY_CCK_TX_CTRL_JAPAN 0x00000010 | 389 | #define AR_PHY_CCK_TX_CTRL_JAPAN 0x00000010 |
390 | #define AR_PHY_CCK_TX_CTRL_TX_DAC_SCALE_CCK 0x0000000C | ||
391 | #define AR_PHY_CCK_TX_CTRL_TX_DAC_SCALE_CCK_S 2 | ||
390 | 392 | ||
391 | #define AR_PHY_CCK_DETECT 0xA208 | 393 | #define AR_PHY_CCK_DETECT 0xA208 |
392 | #define AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK 0x0000003F | 394 | #define AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK 0x0000003F |
@@ -444,6 +446,29 @@ bool ath9k_hw_init_rf(struct ath_hw *ah, | |||
444 | #define AR_PHY_TPCRG1_PD_GAIN_3 0x00300000 | 446 | #define AR_PHY_TPCRG1_PD_GAIN_3 0x00300000 |
445 | #define AR_PHY_TPCRG1_PD_GAIN_3_S 20 | 447 | #define AR_PHY_TPCRG1_PD_GAIN_3_S 20 |
446 | 448 | ||
449 | #define AR_PHY_TX_PWRCTRL4 0xa264 | ||
450 | #define AR_PHY_TX_PWRCTRL_PD_AVG_VALID 0x00000001 | ||
451 | #define AR_PHY_TX_PWRCTRL_PD_AVG_VALID_S 0 | ||
452 | #define AR_PHY_TX_PWRCTRL_PD_AVG_OUT 0x000001FE | ||
453 | #define AR_PHY_TX_PWRCTRL_PD_AVG_OUT_S 1 | ||
454 | |||
455 | #define AR_PHY_TX_PWRCTRL6_0 0xa270 | ||
456 | #define AR_PHY_TX_PWRCTRL6_1 0xb270 | ||
457 | #define AR_PHY_TX_PWRCTRL_ERR_EST_MODE 0x03000000 | ||
458 | #define AR_PHY_TX_PWRCTRL_ERR_EST_MODE_S 24 | ||
459 | |||
460 | #define AR_PHY_TX_PWRCTRL7 0xa274 | ||
461 | #define AR_PHY_TX_PWRCTRL_INIT_TX_GAIN 0x01F80000 | ||
462 | #define AR_PHY_TX_PWRCTRL_INIT_TX_GAIN_S 19 | ||
463 | |||
464 | #define AR_PHY_TX_PWRCTRL9 0xa27C | ||
465 | #define AR_PHY_TX_DESIRED_SCALE_CCK 0x00007C00 | ||
466 | #define AR_PHY_TX_DESIRED_SCALE_CCK_S 10 | ||
467 | |||
468 | #define AR_PHY_TX_GAIN_TBL1 0xa300 | ||
469 | #define AR_PHY_TX_GAIN 0x0007F000 | ||
470 | #define AR_PHY_TX_GAIN_S 12 | ||
471 | |||
447 | #define AR_PHY_VIT_MASK2_M_46_61 0xa3a0 | 472 | #define AR_PHY_VIT_MASK2_M_46_61 0xa3a0 |
448 | #define AR_PHY_MASK2_M_31_45 0xa3a4 | 473 | #define AR_PHY_MASK2_M_31_45 0xa3a4 |
449 | #define AR_PHY_MASK2_M_16_30 0xa3a8 | 474 | #define AR_PHY_MASK2_M_16_30 0xa3a8 |
@@ -485,6 +510,10 @@ bool ath9k_hw_init_rf(struct ath_hw *ah, | |||
485 | #define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4 0x0FC00000 | 510 | #define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4 0x0FC00000 |
486 | #define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4_S 22 | 511 | #define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4_S 22 |
487 | 512 | ||
513 | /* Carrier leak calibration control, do it after AGC calibration */ | ||
514 | #define AR_PHY_CL_CAL_CTL 0xA358 | ||
515 | #define AR_PHY_CL_CAL_ENABLE 0x00000002 | ||
516 | |||
488 | #define AR_PHY_POWER_TX_RATE5 0xA38C | 517 | #define AR_PHY_POWER_TX_RATE5 0xA38C |
489 | #define AR_PHY_POWER_TX_RATE6 0xA390 | 518 | #define AR_PHY_POWER_TX_RATE6 0xA390 |
490 | 519 | ||
diff --git a/drivers/net/wireless/ath9k/rc.c b/drivers/net/wireless/ath9k/rc.c index a4e863191766..cf0559f183af 100644 --- a/drivers/net/wireless/ath9k/rc.c +++ b/drivers/net/wireless/ath9k/rc.c | |||
@@ -1267,7 +1267,8 @@ static void ath_rc_update_ht(struct ath_softc *sc, | |||
1267 | ath_rc_priv->per_down_time = now_msec; | 1267 | ath_rc_priv->per_down_time = now_msec; |
1268 | } | 1268 | } |
1269 | 1269 | ||
1270 | ath_debug_stat_retries(sc, tx_rate, xretries, retries); | 1270 | ath_debug_stat_retries(sc, tx_rate, xretries, retries, |
1271 | ath_rc_priv->state[tx_rate].per); | ||
1271 | 1272 | ||
1272 | #undef CHK_RSSI | 1273 | #undef CHK_RSSI |
1273 | } | 1274 | } |
@@ -1392,6 +1393,7 @@ static void ath_rc_init(struct ath_softc *sc, | |||
1392 | struct ath_rateset *rateset = &ath_rc_priv->neg_rates; | 1393 | struct ath_rateset *rateset = &ath_rc_priv->neg_rates; |
1393 | u8 *ht_mcs = (u8 *)&ath_rc_priv->neg_ht_rates; | 1394 | u8 *ht_mcs = (u8 *)&ath_rc_priv->neg_ht_rates; |
1394 | u8 i, j, k, hi = 0, hthi = 0; | 1395 | u8 i, j, k, hi = 0, hthi = 0; |
1396 | struct ath_hw *ah = sc->sc_ah; | ||
1395 | 1397 | ||
1396 | /* FIXME: Adhoc */ | 1398 | /* FIXME: Adhoc */ |
1397 | if ((sc->sc_ah->opmode == NL80211_IFTYPE_STATION) || | 1399 | if ((sc->sc_ah->opmode == NL80211_IFTYPE_STATION) || |
@@ -1412,7 +1414,8 @@ static void ath_rc_init(struct ath_softc *sc, | |||
1412 | 1414 | ||
1413 | if (sta->ht_cap.ht_supported) { | 1415 | if (sta->ht_cap.ht_supported) { |
1414 | ath_rc_priv->ht_cap = WLAN_RC_HT_FLAG; | 1416 | ath_rc_priv->ht_cap = WLAN_RC_HT_FLAG; |
1415 | if (sc->sc_ah->caps.tx_chainmask != 1) | 1417 | if (sc->sc_ah->caps.tx_chainmask != 1 && |
1418 | ath9k_hw_getcapability(ah, ATH9K_CAP_DS, 0, NULL)) | ||
1416 | ath_rc_priv->ht_cap |= WLAN_RC_DS_FLAG; | 1419 | ath_rc_priv->ht_cap |= WLAN_RC_DS_FLAG; |
1417 | if (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) | 1420 | if (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) |
1418 | ath_rc_priv->ht_cap |= WLAN_RC_40_FLAG; | 1421 | ath_rc_priv->ht_cap |= WLAN_RC_40_FLAG; |
@@ -1533,7 +1536,8 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband, | |||
1533 | tx_info_priv->tx.ts_longretry); | 1536 | tx_info_priv->tx.ts_longretry); |
1534 | 1537 | ||
1535 | /* Check if aggregation has to be enabled for this tid */ | 1538 | /* Check if aggregation has to be enabled for this tid */ |
1536 | if (conf_is_ht(&sc->hw->conf)) { | 1539 | if (conf_is_ht(&sc->hw->conf) && |
1540 | !(skb->protocol == cpu_to_be16(ETH_P_PAE))) { | ||
1537 | if (ieee80211_is_data_qos(fc)) { | 1541 | if (ieee80211_is_data_qos(fc)) { |
1538 | u8 *qc, tid; | 1542 | u8 *qc, tid; |
1539 | struct ath_node *an; | 1543 | struct ath_node *an; |
diff --git a/drivers/net/wireless/ath9k/recv.c b/drivers/net/wireless/ath9k/recv.c index 08f676af894f..23b6f54cde5c 100644 --- a/drivers/net/wireless/ath9k/recv.c +++ b/drivers/net/wireless/ath9k/recv.c | |||
@@ -375,14 +375,15 @@ u32 ath_calcrxfilter(struct ath_softc *sc) | |||
375 | if (sc->rx.rxfilter & FIF_CONTROL) | 375 | if (sc->rx.rxfilter & FIF_CONTROL) |
376 | rfilt |= ATH9K_RX_FILTER_CONTROL; | 376 | rfilt |= ATH9K_RX_FILTER_CONTROL; |
377 | 377 | ||
378 | if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION || | 378 | if ((sc->sc_ah->opmode == NL80211_IFTYPE_STATION) && |
379 | sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC) | 379 | !(sc->rx.rxfilter & FIF_BCN_PRBRESP_PROMISC)) |
380 | rfilt |= ATH9K_RX_FILTER_MYBEACON; | ||
381 | else | ||
380 | rfilt |= ATH9K_RX_FILTER_BEACON; | 382 | rfilt |= ATH9K_RX_FILTER_BEACON; |
381 | 383 | ||
382 | /* If in HOSTAP mode, want to enable reception of PSPOLL frames | 384 | /* If in HOSTAP mode, want to enable reception of PSPOLL frames */ |
383 | & beacon frames */ | ||
384 | if (sc->sc_ah->opmode == NL80211_IFTYPE_AP) | 385 | if (sc->sc_ah->opmode == NL80211_IFTYPE_AP) |
385 | rfilt |= (ATH9K_RX_FILTER_BEACON | ATH9K_RX_FILTER_PSPOLL); | 386 | rfilt |= ATH9K_RX_FILTER_PSPOLL; |
386 | 387 | ||
387 | return rfilt; | 388 | return rfilt; |
388 | 389 | ||
@@ -427,7 +428,6 @@ bool ath_stoprecv(struct ath_softc *sc) | |||
427 | ath9k_hw_stoppcurecv(ah); | 428 | ath9k_hw_stoppcurecv(ah); |
428 | ath9k_hw_setrxfilter(ah, 0); | 429 | ath9k_hw_setrxfilter(ah, 0); |
429 | stopped = ath9k_hw_stopdmarecv(ah); | 430 | stopped = ath9k_hw_stopdmarecv(ah); |
430 | mdelay(3); /* 3ms is long enough for 1 frame */ | ||
431 | sc->rx.rxlink = NULL; | 431 | sc->rx.rxlink = NULL; |
432 | 432 | ||
433 | return stopped; | 433 | return stopped; |
diff --git a/drivers/net/wireless/ath9k/reg.h b/drivers/net/wireless/ath9k/reg.h index 17ed190349a5..8d85106d6df2 100644 --- a/drivers/net/wireless/ath9k/reg.h +++ b/drivers/net/wireless/ath9k/reg.h | |||
@@ -977,8 +977,6 @@ enum { | |||
977 | #define AR_RTC_PLL_CLKSEL 0x00000300 | 977 | #define AR_RTC_PLL_CLKSEL 0x00000300 |
978 | #define AR_RTC_PLL_CLKSEL_S 8 | 978 | #define AR_RTC_PLL_CLKSEL_S 8 |
979 | 979 | ||
980 | |||
981 | |||
982 | #define AR_RTC_RESET \ | 980 | #define AR_RTC_RESET \ |
983 | ((AR_SREV_9100(ah)) ? (AR_RTC_BASE + 0x0040) : 0x7040) | 981 | ((AR_SREV_9100(ah)) ? (AR_RTC_BASE + 0x0040) : 0x7040) |
984 | #define AR_RTC_RESET_EN (0x00000001) | 982 | #define AR_RTC_RESET_EN (0x00000001) |
@@ -1015,6 +1013,12 @@ enum { | |||
1015 | #define AR_RTC_INTR_MASK \ | 1013 | #define AR_RTC_INTR_MASK \ |
1016 | ((AR_SREV_9100(ah)) ? (AR_RTC_BASE + 0x0058) : 0x7058) | 1014 | ((AR_SREV_9100(ah)) ? (AR_RTC_BASE + 0x0058) : 0x7058) |
1017 | 1015 | ||
1016 | /* RTC_DERIVED_* - only for AR9100 */ | ||
1017 | |||
1018 | #define AR_RTC_DERIVED_CLK (AR_RTC_BASE + 0x0038) | ||
1019 | #define AR_RTC_DERIVED_CLK_PERIOD 0x0000fffe | ||
1020 | #define AR_RTC_DERIVED_CLK_PERIOD_S 1 | ||
1021 | |||
1018 | #define AR_SEQ_MASK 0x8060 | 1022 | #define AR_SEQ_MASK 0x8060 |
1019 | 1023 | ||
1020 | #define AR_AN_RF2G1_CH0 0x7810 | 1024 | #define AR_AN_RF2G1_CH0 0x7810 |
@@ -1385,8 +1389,8 @@ enum { | |||
1385 | #define AR_PHY_COUNTMAX (3 << 22) | 1389 | #define AR_PHY_COUNTMAX (3 << 22) |
1386 | #define AR_MIBCNT_INTRMASK (3 << 22) | 1390 | #define AR_MIBCNT_INTRMASK (3 << 22) |
1387 | 1391 | ||
1388 | #define AR_TSF_THRESHOLD 0x813c | 1392 | #define AR_TSFOOR_THRESHOLD 0x813c |
1389 | #define AR_TSF_THRESHOLD_VAL 0x0000FFFF | 1393 | #define AR_TSFOOR_THRESHOLD_VAL 0x0000FFFF |
1390 | 1394 | ||
1391 | #define AR_PHY_ERR_EIFS_MASK 8144 | 1395 | #define AR_PHY_ERR_EIFS_MASK 8144 |
1392 | 1396 | ||
diff --git a/drivers/net/wireless/ath9k/regd.c b/drivers/net/wireless/ath9k/regd.c index 8c2b56ac55ff..f7d7cc24a129 100644 --- a/drivers/net/wireless/ath9k/regd.c +++ b/drivers/net/wireless/ath9k/regd.c | |||
@@ -106,19 +106,20 @@ static const struct ieee80211_regdomain ath9k_world_regdom_67_68_6A = { | |||
106 | } | 106 | } |
107 | }; | 107 | }; |
108 | 108 | ||
109 | static u16 ath9k_regd_get_eepromRD(struct ath_hw *ah) | 109 | static inline bool is_wwr_sku(u16 regd) |
110 | { | 110 | { |
111 | return ah->regulatory.current_rd & ~WORLDWIDE_ROAMING_FLAG; | 111 | return ((regd & WORLD_SKU_MASK) == WORLD_SKU_PREFIX) || |
112 | (regd == WORLD); | ||
112 | } | 113 | } |
113 | 114 | ||
114 | u16 ath9k_regd_get_rd(struct ath_hw *ah) | 115 | static u16 ath9k_regd_get_eepromRD(struct ath_hw *ah) |
115 | { | 116 | { |
116 | return ath9k_regd_get_eepromRD(ah); | 117 | return ah->regulatory.current_rd & ~WORLDWIDE_ROAMING_FLAG; |
117 | } | 118 | } |
118 | 119 | ||
119 | bool ath9k_is_world_regd(struct ath_hw *ah) | 120 | bool ath9k_is_world_regd(struct ath_hw *ah) |
120 | { | 121 | { |
121 | return isWwrSKU(ah); | 122 | return is_wwr_sku(ath9k_regd_get_eepromRD(ah)); |
122 | } | 123 | } |
123 | 124 | ||
124 | const struct ieee80211_regdomain *ath9k_default_world_regdomain(void) | 125 | const struct ieee80211_regdomain *ath9k_default_world_regdomain(void) |
@@ -159,13 +160,18 @@ static bool ath9k_is_radar_freq(u16 center_freq) | |||
159 | } | 160 | } |
160 | 161 | ||
161 | /* | 162 | /* |
162 | * Enable adhoc on 5 GHz if allowed by 11d. | 163 | * N.B: These exception rules do not apply radar freqs. |
163 | * Remove passive scan if channel is allowed by 11d, | 164 | * |
164 | * except when on radar frequencies. | 165 | * - We enable adhoc (or beaconing) if allowed by 11d |
166 | * - We enable active scan if the channel is allowed by 11d | ||
167 | * - If no country IE has been processed and a we determine we have | ||
168 | * received a beacon on a channel we can enable active scan and | ||
169 | * adhoc (or beaconing). | ||
165 | */ | 170 | */ |
166 | static void ath9k_reg_apply_5ghz_beaconing_flags(struct wiphy *wiphy, | 171 | static void ath9k_reg_apply_beaconing_flags(struct wiphy *wiphy, |
167 | enum reg_set_by setby) | 172 | enum reg_set_by setby) |
168 | { | 173 | { |
174 | enum ieee80211_band band; | ||
169 | struct ieee80211_supported_band *sband; | 175 | struct ieee80211_supported_band *sband; |
170 | const struct ieee80211_reg_rule *reg_rule; | 176 | const struct ieee80211_reg_rule *reg_rule; |
171 | struct ieee80211_channel *ch; | 177 | struct ieee80211_channel *ch; |
@@ -173,29 +179,50 @@ static void ath9k_reg_apply_5ghz_beaconing_flags(struct wiphy *wiphy, | |||
173 | u32 bandwidth = 0; | 179 | u32 bandwidth = 0; |
174 | int r; | 180 | int r; |
175 | 181 | ||
176 | if (setby != REGDOM_SET_BY_COUNTRY_IE) | 182 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { |
177 | return; | ||
178 | if (!wiphy->bands[IEEE80211_BAND_5GHZ]) | ||
179 | return; | ||
180 | 183 | ||
181 | sband = wiphy->bands[IEEE80211_BAND_5GHZ]; | 184 | if (!wiphy->bands[band]) |
182 | for (i = 0; i < sband->n_channels; i++) { | ||
183 | ch = &sband->channels[i]; | ||
184 | r = freq_reg_info(wiphy, ch->center_freq, | ||
185 | &bandwidth, ®_rule); | ||
186 | if (r) | ||
187 | continue; | 185 | continue; |
188 | /* If 11d had a rule for this channel ensure we enable adhoc | 186 | |
189 | * if it allows us to use it. Note that we would have disabled | 187 | sband = wiphy->bands[band]; |
190 | * it by applying our static world regdomain by default during | 188 | |
191 | * probe */ | 189 | for (i = 0; i < sband->n_channels; i++) { |
192 | if (!(reg_rule->flags & NL80211_RRF_NO_IBSS)) | 190 | |
193 | ch->flags &= ~IEEE80211_CHAN_NO_IBSS; | 191 | ch = &sband->channels[i]; |
194 | if (!ath9k_is_radar_freq(ch->center_freq)) | 192 | |
195 | continue; | 193 | if (ath9k_is_radar_freq(ch->center_freq) || |
196 | if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN)) | 194 | (ch->flags & IEEE80211_CHAN_RADAR)) |
197 | ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN; | 195 | continue; |
196 | |||
197 | if (setby == REGDOM_SET_BY_COUNTRY_IE) { | ||
198 | r = freq_reg_info(wiphy, ch->center_freq, | ||
199 | &bandwidth, ®_rule); | ||
200 | if (r) | ||
201 | continue; | ||
202 | /* | ||
203 | * If 11d had a rule for this channel ensure | ||
204 | * we enable adhoc/beaconing if it allows us to | ||
205 | * use it. Note that we would have disabled it | ||
206 | * by applying our static world regdomain by | ||
207 | * default during init, prior to calling our | ||
208 | * regulatory_hint(). | ||
209 | */ | ||
210 | if (!(reg_rule->flags & | ||
211 | NL80211_RRF_NO_IBSS)) | ||
212 | ch->flags &= | ||
213 | ~IEEE80211_CHAN_NO_IBSS; | ||
214 | if (!(reg_rule->flags & | ||
215 | NL80211_RRF_PASSIVE_SCAN)) | ||
216 | ch->flags &= | ||
217 | ~IEEE80211_CHAN_PASSIVE_SCAN; | ||
218 | } else { | ||
219 | if (ch->beacon_found) | ||
220 | ch->flags &= ~(IEEE80211_CHAN_NO_IBSS | | ||
221 | IEEE80211_CHAN_PASSIVE_SCAN); | ||
222 | } | ||
223 | } | ||
198 | } | 224 | } |
225 | |||
199 | } | 226 | } |
200 | 227 | ||
201 | /* Allows active scan scan on Ch 12 and 13 */ | 228 | /* Allows active scan scan on Ch 12 and 13 */ |
@@ -208,11 +235,12 @@ static void ath9k_reg_apply_active_scan_flags(struct wiphy *wiphy, | |||
208 | u32 bandwidth = 0; | 235 | u32 bandwidth = 0; |
209 | int r; | 236 | int r; |
210 | 237 | ||
211 | /* Force passive scan on Channels 12-13 */ | ||
212 | sband = wiphy->bands[IEEE80211_BAND_2GHZ]; | 238 | sband = wiphy->bands[IEEE80211_BAND_2GHZ]; |
213 | 239 | ||
214 | /* If no country IE has been received always enable active scan | 240 | /* |
215 | * on these channels */ | 241 | * If no country IE has been received always enable active scan |
242 | * on these channels. This is only done for specific regulatory SKUs | ||
243 | */ | ||
216 | if (setby != REGDOM_SET_BY_COUNTRY_IE) { | 244 | if (setby != REGDOM_SET_BY_COUNTRY_IE) { |
217 | ch = &sband->channels[11]; /* CH 12 */ | 245 | ch = &sband->channels[11]; /* CH 12 */ |
218 | if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN) | 246 | if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN) |
@@ -223,10 +251,12 @@ static void ath9k_reg_apply_active_scan_flags(struct wiphy *wiphy, | |||
223 | return; | 251 | return; |
224 | } | 252 | } |
225 | 253 | ||
226 | /* If a country IE has been recieved check its rule for this | 254 | /* |
255 | * If a country IE has been recieved check its rule for this | ||
227 | * channel first before enabling active scan. The passive scan | 256 | * channel first before enabling active scan. The passive scan |
228 | * would have been enforced by the initial probe processing on | 257 | * would have been enforced by the initial processing of our |
229 | * our custom regulatory domain. */ | 258 | * custom regulatory domain. |
259 | */ | ||
230 | 260 | ||
231 | ch = &sband->channels[11]; /* CH 12 */ | 261 | ch = &sband->channels[11]; /* CH 12 */ |
232 | r = freq_reg_info(wiphy, ch->center_freq, &bandwidth, ®_rule); | 262 | r = freq_reg_info(wiphy, ch->center_freq, &bandwidth, ®_rule); |
@@ -289,10 +319,10 @@ void ath9k_reg_apply_world_flags(struct wiphy *wiphy, enum reg_set_by setby) | |||
289 | case 0x63: | 319 | case 0x63: |
290 | case 0x66: | 320 | case 0x66: |
291 | case 0x67: | 321 | case 0x67: |
292 | ath9k_reg_apply_5ghz_beaconing_flags(wiphy, setby); | 322 | ath9k_reg_apply_beaconing_flags(wiphy, setby); |
293 | break; | 323 | break; |
294 | case 0x68: | 324 | case 0x68: |
295 | ath9k_reg_apply_5ghz_beaconing_flags(wiphy, setby); | 325 | ath9k_reg_apply_beaconing_flags(wiphy, setby); |
296 | ath9k_reg_apply_active_scan_flags(wiphy, setby); | 326 | ath9k_reg_apply_active_scan_flags(wiphy, setby); |
297 | break; | 327 | break; |
298 | } | 328 | } |
@@ -371,11 +401,8 @@ ath9k_regd_find_country_by_rd(int regdmn) | |||
371 | } | 401 | } |
372 | 402 | ||
373 | /* Returns the map of the EEPROM set RD to a country code */ | 403 | /* Returns the map of the EEPROM set RD to a country code */ |
374 | static u16 ath9k_regd_get_default_country(struct ath_hw *ah) | 404 | static u16 ath9k_regd_get_default_country(u16 rd) |
375 | { | 405 | { |
376 | u16 rd; | ||
377 | |||
378 | rd = ath9k_regd_get_eepromRD(ah); | ||
379 | if (rd & COUNTRY_ERD_FLAG) { | 406 | if (rd & COUNTRY_ERD_FLAG) { |
380 | struct country_code_to_enum_rd *country = NULL; | 407 | struct country_code_to_enum_rd *country = NULL; |
381 | u16 cc = rd & ~COUNTRY_ERD_FLAG; | 408 | u16 cc = rd & ~COUNTRY_ERD_FLAG; |
@@ -405,7 +432,7 @@ ath9k_get_regpair(int regdmn) | |||
405 | int ath9k_regd_init(struct ath_hw *ah) | 432 | int ath9k_regd_init(struct ath_hw *ah) |
406 | { | 433 | { |
407 | struct country_code_to_enum_rd *country = NULL; | 434 | struct country_code_to_enum_rd *country = NULL; |
408 | int regdmn; | 435 | u16 regdmn; |
409 | 436 | ||
410 | if (!ath9k_regd_is_eeprom_valid(ah)) { | 437 | if (!ath9k_regd_is_eeprom_valid(ah)) { |
411 | DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, | 438 | DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, |
@@ -413,14 +440,14 @@ int ath9k_regd_init(struct ath_hw *ah) | |||
413 | return -EINVAL; | 440 | return -EINVAL; |
414 | } | 441 | } |
415 | 442 | ||
416 | ah->regulatory.country_code = ath9k_regd_get_default_country(ah); | 443 | regdmn = ath9k_regd_get_eepromRD(ah); |
444 | ah->regulatory.country_code = ath9k_regd_get_default_country(regdmn); | ||
417 | 445 | ||
418 | if (ah->regulatory.country_code == CTRY_DEFAULT && | 446 | if (ah->regulatory.country_code == CTRY_DEFAULT && |
419 | ath9k_regd_get_eepromRD(ah) == CTRY_DEFAULT) | 447 | regdmn == CTRY_DEFAULT) |
420 | ah->regulatory.country_code = CTRY_UNITED_STATES; | 448 | ah->regulatory.country_code = CTRY_UNITED_STATES; |
421 | 449 | ||
422 | if (ah->regulatory.country_code == CTRY_DEFAULT) { | 450 | if (ah->regulatory.country_code == CTRY_DEFAULT) { |
423 | regdmn = ath9k_regd_get_eepromRD(ah); | ||
424 | country = NULL; | 451 | country = NULL; |
425 | } else { | 452 | } else { |
426 | country = ath9k_regd_find_country(ah->regulatory.country_code); | 453 | country = ath9k_regd_find_country(ah->regulatory.country_code); |
@@ -433,7 +460,6 @@ int ath9k_regd_init(struct ath_hw *ah) | |||
433 | regdmn = country->regDmnEnum; | 460 | regdmn = country->regDmnEnum; |
434 | } | 461 | } |
435 | 462 | ||
436 | ah->regulatory.current_rd_inuse = regdmn; | ||
437 | ah->regulatory.regpair = ath9k_get_regpair(regdmn); | 463 | ah->regulatory.regpair = ath9k_get_regpair(regdmn); |
438 | 464 | ||
439 | if (!ah->regulatory.regpair) { | 465 | if (!ah->regulatory.regpair) { |
@@ -467,7 +493,8 @@ u32 ath9k_regd_get_ctl(struct ath_hw *ah, struct ath9k_channel *chan) | |||
467 | u32 ctl = NO_CTL; | 493 | u32 ctl = NO_CTL; |
468 | 494 | ||
469 | if (!ah->regulatory.regpair || | 495 | if (!ah->regulatory.regpair || |
470 | (ah->regulatory.country_code == CTRY_DEFAULT && isWwrSKU(ah))) { | 496 | (ah->regulatory.country_code == CTRY_DEFAULT && |
497 | is_wwr_sku(ath9k_regd_get_eepromRD(ah)))) { | ||
471 | if (IS_CHAN_B(chan)) | 498 | if (IS_CHAN_B(chan)) |
472 | ctl = SD_NO_CTL | CTL_11B; | 499 | ctl = SD_NO_CTL | CTL_11B; |
473 | else if (IS_CHAN_G(chan)) | 500 | else if (IS_CHAN_G(chan)) |
@@ -480,7 +507,7 @@ u32 ath9k_regd_get_ctl(struct ath_hw *ah, struct ath9k_channel *chan) | |||
480 | if (IS_CHAN_B(chan)) | 507 | if (IS_CHAN_B(chan)) |
481 | ctl = ah->regulatory.regpair->reg_2ghz_ctl | CTL_11B; | 508 | ctl = ah->regulatory.regpair->reg_2ghz_ctl | CTL_11B; |
482 | else if (IS_CHAN_G(chan)) | 509 | else if (IS_CHAN_G(chan)) |
483 | ctl = ah->regulatory.regpair->reg_5ghz_ctl | CTL_11G; | 510 | ctl = ah->regulatory.regpair->reg_2ghz_ctl | CTL_11G; |
484 | else | 511 | else |
485 | ctl = ah->regulatory.regpair->reg_5ghz_ctl | CTL_11A; | 512 | ctl = ah->regulatory.regpair->reg_5ghz_ctl | CTL_11A; |
486 | 513 | ||
diff --git a/drivers/net/wireless/ath9k/regd.h b/drivers/net/wireless/ath9k/regd.h index 39420de818f8..d48160d0c0e9 100644 --- a/drivers/net/wireless/ath9k/regd.h +++ b/drivers/net/wireless/ath9k/regd.h | |||
@@ -20,11 +20,6 @@ | |||
20 | #define COUNTRY_ERD_FLAG 0x8000 | 20 | #define COUNTRY_ERD_FLAG 0x8000 |
21 | #define WORLDWIDE_ROAMING_FLAG 0x4000 | 21 | #define WORLDWIDE_ROAMING_FLAG 0x4000 |
22 | 22 | ||
23 | #define isWwrSKU(_ah) \ | ||
24 | (((ath9k_regd_get_eepromRD((_ah)) & WORLD_SKU_MASK) == \ | ||
25 | WORLD_SKU_PREFIX) || \ | ||
26 | (ath9k_regd_get_eepromRD(_ah) == WORLD)) | ||
27 | |||
28 | #define MULTI_DOMAIN_MASK 0xFF00 | 23 | #define MULTI_DOMAIN_MASK 0xFF00 |
29 | 24 | ||
30 | #define WORLD_SKU_MASK 0x00F0 | 25 | #define WORLD_SKU_MASK 0x00F0 |
@@ -52,7 +47,6 @@ struct ath9k_regulatory { | |||
52 | u32 tp_scale; | 47 | u32 tp_scale; |
53 | u16 current_rd; | 48 | u16 current_rd; |
54 | u16 current_rd_ext; | 49 | u16 current_rd_ext; |
55 | u16 current_rd_inuse; | ||
56 | int16_t power_limit; | 50 | int16_t power_limit; |
57 | struct reg_dmn_pair_mapping *regpair; | 51 | struct reg_dmn_pair_mapping *regpair; |
58 | }; | 52 | }; |
@@ -239,7 +233,6 @@ enum CountryCode { | |||
239 | CTRY_BELGIUM2 = 5002 | 233 | CTRY_BELGIUM2 = 5002 |
240 | }; | 234 | }; |
241 | 235 | ||
242 | u16 ath9k_regd_get_rd(struct ath_hw *ah); | ||
243 | bool ath9k_is_world_regd(struct ath_hw *ah); | 236 | bool ath9k_is_world_regd(struct ath_hw *ah); |
244 | const struct ieee80211_regdomain *ath9k_world_regdomain(struct ath_hw *ah); | 237 | const struct ieee80211_regdomain *ath9k_world_regdomain(struct ath_hw *ah); |
245 | const struct ieee80211_regdomain *ath9k_default_world_regdomain(void); | 238 | const struct ieee80211_regdomain *ath9k_default_world_regdomain(void); |
@@ -249,7 +242,5 @@ int ath9k_regd_init(struct ath_hw *ah); | |||
249 | bool ath9k_regd_is_eeprom_valid(struct ath_hw *ah); | 242 | bool ath9k_regd_is_eeprom_valid(struct ath_hw *ah); |
250 | u32 ath9k_regd_get_ctl(struct ath_hw *ah, struct ath9k_channel *chan); | 243 | u32 ath9k_regd_get_ctl(struct ath_hw *ah, struct ath9k_channel *chan); |
251 | int ath9k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request); | 244 | int ath9k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request); |
252 | void ath9k_regd_get_current_country(struct ath_hw *ah, | ||
253 | struct ath9k_country_entry *ctry); | ||
254 | 245 | ||
255 | #endif | 246 | #endif |
diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath9k/xmit.c index 3f70b1e58ae4..363bb2a94d99 100644 --- a/drivers/net/wireless/ath9k/xmit.c +++ b/drivers/net/wireless/ath9k/xmit.c | |||
@@ -772,24 +772,6 @@ bool ath_tx_aggr_check(struct ath_softc *sc, struct ath_node *an, u8 tidno) | |||
772 | /* Queue Management */ | 772 | /* Queue Management */ |
773 | /********************/ | 773 | /********************/ |
774 | 774 | ||
775 | static u32 ath_txq_depth(struct ath_softc *sc, int qnum) | ||
776 | { | ||
777 | return sc->tx.txq[qnum].axq_depth; | ||
778 | } | ||
779 | |||
780 | static void ath_get_beaconconfig(struct ath_softc *sc, int if_id, | ||
781 | struct ath_beacon_config *conf) | ||
782 | { | ||
783 | struct ieee80211_hw *hw = sc->hw; | ||
784 | |||
785 | /* fill in beacon config data */ | ||
786 | |||
787 | conf->beacon_interval = hw->conf.beacon_int; | ||
788 | conf->listen_interval = 100; | ||
789 | conf->dtim_count = 1; | ||
790 | conf->bmiss_timeout = ATH_DEFAULT_BMISS_LIMIT * conf->listen_interval; | ||
791 | } | ||
792 | |||
793 | static void ath_txq_drain_pending_buffers(struct ath_softc *sc, | 775 | static void ath_txq_drain_pending_buffers(struct ath_softc *sc, |
794 | struct ath_txq *txq) | 776 | struct ath_txq *txq) |
795 | { | 777 | { |
@@ -964,7 +946,6 @@ int ath_cabq_update(struct ath_softc *sc) | |||
964 | { | 946 | { |
965 | struct ath9k_tx_queue_info qi; | 947 | struct ath9k_tx_queue_info qi; |
966 | int qnum = sc->beacon.cabq->axq_qnum; | 948 | int qnum = sc->beacon.cabq->axq_qnum; |
967 | struct ath_beacon_config conf; | ||
968 | 949 | ||
969 | ath9k_hw_get_txq_props(sc->sc_ah, qnum, &qi); | 950 | ath9k_hw_get_txq_props(sc->sc_ah, qnum, &qi); |
970 | /* | 951 | /* |
@@ -975,9 +956,8 @@ int ath_cabq_update(struct ath_softc *sc) | |||
975 | else if (sc->config.cabqReadytime > ATH9K_READY_TIME_HI_BOUND) | 956 | else if (sc->config.cabqReadytime > ATH9K_READY_TIME_HI_BOUND) |
976 | sc->config.cabqReadytime = ATH9K_READY_TIME_HI_BOUND; | 957 | sc->config.cabqReadytime = ATH9K_READY_TIME_HI_BOUND; |
977 | 958 | ||
978 | ath_get_beaconconfig(sc, ATH_IF_ID_ANY, &conf); | 959 | qi.tqi_readyTime = (sc->hw->conf.beacon_int * |
979 | qi.tqi_readyTime = | 960 | sc->config.cabqReadytime) / 100; |
980 | (conf.beacon_interval * sc->config.cabqReadytime) / 100; | ||
981 | ath_txq_update(sc, qnum, &qi); | 961 | ath_txq_update(sc, qnum, &qi); |
982 | 962 | ||
983 | return 0; | 963 | return 0; |
@@ -1657,7 +1637,7 @@ int ath_tx_start(struct ath_softc *sc, struct sk_buff *skb, | |||
1657 | * we will at least have to run TX completionon one buffer | 1637 | * we will at least have to run TX completionon one buffer |
1658 | * on the queue */ | 1638 | * on the queue */ |
1659 | spin_lock_bh(&txq->axq_lock); | 1639 | spin_lock_bh(&txq->axq_lock); |
1660 | if (ath_txq_depth(sc, txq->axq_qnum) > 1) { | 1640 | if (sc->tx.txq[txq->axq_qnum].axq_depth > 1) { |
1661 | ieee80211_stop_queue(sc->hw, | 1641 | ieee80211_stop_queue(sc->hw, |
1662 | skb_get_queue_mapping(skb)); | 1642 | skb_get_queue_mapping(skb)); |
1663 | txq->stopped = 1; | 1643 | txq->stopped = 1; |
@@ -1867,7 +1847,7 @@ static void ath_wake_mac80211_queue(struct ath_softc *sc, struct ath_txq *txq) | |||
1867 | 1847 | ||
1868 | spin_lock_bh(&txq->axq_lock); | 1848 | spin_lock_bh(&txq->axq_lock); |
1869 | if (txq->stopped && | 1849 | if (txq->stopped && |
1870 | ath_txq_depth(sc, txq->axq_qnum) <= (ATH_TXBUF - 20)) { | 1850 | sc->tx.txq[txq->axq_qnum].axq_depth <= (ATH_TXBUF - 20)) { |
1871 | qnum = ath_get_mac80211_qnum(txq->axq_qnum, sc); | 1851 | qnum = ath_get_mac80211_qnum(txq->axq_qnum, sc); |
1872 | if (qnum != -1) { | 1852 | if (qnum != -1) { |
1873 | ieee80211_wake_queue(sc->hw, qnum); | 1853 | ieee80211_wake_queue(sc->hw, qnum); |
diff --git a/drivers/net/wireless/b43/debugfs.c b/drivers/net/wireless/b43/debugfs.c index bc2767da46e8..45e3d6af69f5 100644 --- a/drivers/net/wireless/b43/debugfs.c +++ b/drivers/net/wireless/b43/debugfs.c | |||
@@ -51,8 +51,8 @@ struct b43_debugfs_fops { | |||
51 | }; | 51 | }; |
52 | 52 | ||
53 | static inline | 53 | static inline |
54 | struct b43_dfs_file * fops_to_dfs_file(struct b43_wldev *dev, | 54 | struct b43_dfs_file *fops_to_dfs_file(struct b43_wldev *dev, |
55 | const struct b43_debugfs_fops *dfops) | 55 | const struct b43_debugfs_fops *dfops) |
56 | { | 56 | { |
57 | void *p; | 57 | void *p; |
58 | 58 | ||
diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c index 6d65a02b7052..92e1c0189a65 100644 --- a/drivers/net/wireless/b43/dma.c +++ b/drivers/net/wireless/b43/dma.c | |||
@@ -41,6 +41,12 @@ | |||
41 | #include <asm/div64.h> | 41 | #include <asm/div64.h> |
42 | 42 | ||
43 | 43 | ||
44 | /* Required number of TX DMA slots per TX frame. | ||
45 | * This currently is 2, because we put the header and the ieee80211 frame | ||
46 | * into separate slots. */ | ||
47 | #define TX_SLOTS_PER_FRAME 2 | ||
48 | |||
49 | |||
44 | /* 32bit DMA ops. */ | 50 | /* 32bit DMA ops. */ |
45 | static | 51 | static |
46 | struct b43_dmadesc_generic *op32_idx2desc(struct b43_dmaring *ring, | 52 | struct b43_dmadesc_generic *op32_idx2desc(struct b43_dmaring *ring, |
@@ -74,8 +80,7 @@ static void op32_fill_descriptor(struct b43_dmaring *ring, | |||
74 | addrext = (u32) (dmaaddr & SSB_DMA_TRANSLATION_MASK) | 80 | addrext = (u32) (dmaaddr & SSB_DMA_TRANSLATION_MASK) |
75 | >> SSB_DMA_TRANSLATION_SHIFT; | 81 | >> SSB_DMA_TRANSLATION_SHIFT; |
76 | addr |= ssb_dma_translation(ring->dev->dev); | 82 | addr |= ssb_dma_translation(ring->dev->dev); |
77 | ctl = (bufsize - ring->frameoffset) | 83 | ctl = bufsize & B43_DMA32_DCTL_BYTECNT; |
78 | & B43_DMA32_DCTL_BYTECNT; | ||
79 | if (slot == ring->nr_slots - 1) | 84 | if (slot == ring->nr_slots - 1) |
80 | ctl |= B43_DMA32_DCTL_DTABLEEND; | 85 | ctl |= B43_DMA32_DCTL_DTABLEEND; |
81 | if (start) | 86 | if (start) |
@@ -177,8 +182,7 @@ static void op64_fill_descriptor(struct b43_dmaring *ring, | |||
177 | ctl0 |= B43_DMA64_DCTL0_FRAMEEND; | 182 | ctl0 |= B43_DMA64_DCTL0_FRAMEEND; |
178 | if (irq) | 183 | if (irq) |
179 | ctl0 |= B43_DMA64_DCTL0_IRQ; | 184 | ctl0 |= B43_DMA64_DCTL0_IRQ; |
180 | ctl1 |= (bufsize - ring->frameoffset) | 185 | ctl1 |= bufsize & B43_DMA64_DCTL1_BYTECNT; |
181 | & B43_DMA64_DCTL1_BYTECNT; | ||
182 | ctl1 |= (addrext << B43_DMA64_DCTL1_ADDREXT_SHIFT) | 186 | ctl1 |= (addrext << B43_DMA64_DCTL1_ADDREXT_SHIFT) |
183 | & B43_DMA64_DCTL1_ADDREXT_MASK; | 187 | & B43_DMA64_DCTL1_ADDREXT_MASK; |
184 | 188 | ||
@@ -576,12 +580,11 @@ static int setup_rx_descbuffer(struct b43_dmaring *ring, | |||
576 | return -ENOMEM; | 580 | return -ENOMEM; |
577 | dmaaddr = map_descbuffer(ring, skb->data, | 581 | dmaaddr = map_descbuffer(ring, skb->data, |
578 | ring->rx_buffersize, 0); | 582 | ring->rx_buffersize, 0); |
579 | } | 583 | if (b43_dma_mapping_error(ring, dmaaddr, ring->rx_buffersize, 0)) { |
580 | 584 | b43err(ring->dev->wl, "RX DMA buffer allocation failed\n"); | |
581 | if (b43_dma_mapping_error(ring, dmaaddr, ring->rx_buffersize, 0)) { | 585 | dev_kfree_skb_any(skb); |
582 | b43err(ring->dev->wl, "RX DMA buffer allocation failed\n"); | 586 | return -EIO; |
583 | dev_kfree_skb_any(skb); | 587 | } |
584 | return -EIO; | ||
585 | } | 588 | } |
586 | 589 | ||
587 | meta->skb = skb; | 590 | meta->skb = skb; |
@@ -830,9 +833,6 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev, | |||
830 | if (ring->index == 0) { | 833 | if (ring->index == 0) { |
831 | ring->rx_buffersize = B43_DMA0_RX_BUFFERSIZE; | 834 | ring->rx_buffersize = B43_DMA0_RX_BUFFERSIZE; |
832 | ring->frameoffset = B43_DMA0_RX_FRAMEOFFSET; | 835 | ring->frameoffset = B43_DMA0_RX_FRAMEOFFSET; |
833 | } else if (ring->index == 3) { | ||
834 | ring->rx_buffersize = B43_DMA3_RX_BUFFERSIZE; | ||
835 | ring->frameoffset = B43_DMA3_RX_FRAMEOFFSET; | ||
836 | } else | 836 | } else |
837 | B43_WARN_ON(1); | 837 | B43_WARN_ON(1); |
838 | } | 838 | } |
@@ -842,7 +842,10 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev, | |||
842 | #endif | 842 | #endif |
843 | 843 | ||
844 | if (for_tx) { | 844 | if (for_tx) { |
845 | ring->txhdr_cache = kcalloc(ring->nr_slots, | 845 | /* Assumption: B43_TXRING_SLOTS can be divided by TX_SLOTS_PER_FRAME */ |
846 | BUILD_BUG_ON(B43_TXRING_SLOTS % TX_SLOTS_PER_FRAME != 0); | ||
847 | |||
848 | ring->txhdr_cache = kcalloc(ring->nr_slots / TX_SLOTS_PER_FRAME, | ||
846 | b43_txhdr_size(dev), | 849 | b43_txhdr_size(dev), |
847 | GFP_KERNEL); | 850 | GFP_KERNEL); |
848 | if (!ring->txhdr_cache) | 851 | if (!ring->txhdr_cache) |
@@ -858,7 +861,7 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev, | |||
858 | b43_txhdr_size(dev), 1)) { | 861 | b43_txhdr_size(dev), 1)) { |
859 | /* ugh realloc */ | 862 | /* ugh realloc */ |
860 | kfree(ring->txhdr_cache); | 863 | kfree(ring->txhdr_cache); |
861 | ring->txhdr_cache = kcalloc(ring->nr_slots, | 864 | ring->txhdr_cache = kcalloc(ring->nr_slots / TX_SLOTS_PER_FRAME, |
862 | b43_txhdr_size(dev), | 865 | b43_txhdr_size(dev), |
863 | GFP_KERNEL | GFP_DMA); | 866 | GFP_KERNEL | GFP_DMA); |
864 | if (!ring->txhdr_cache) | 867 | if (!ring->txhdr_cache) |
@@ -1149,7 +1152,10 @@ static int dma_tx_fragment(struct b43_dmaring *ring, | |||
1149 | u16 cookie; | 1152 | u16 cookie; |
1150 | size_t hdrsize = b43_txhdr_size(ring->dev); | 1153 | size_t hdrsize = b43_txhdr_size(ring->dev); |
1151 | 1154 | ||
1152 | #define SLOTS_PER_PACKET 2 | 1155 | /* Important note: If the number of used DMA slots per TX frame |
1156 | * is changed here, the TX_SLOTS_PER_FRAME definition at the top of | ||
1157 | * the file has to be updated, too! | ||
1158 | */ | ||
1153 | 1159 | ||
1154 | old_top_slot = ring->current_slot; | 1160 | old_top_slot = ring->current_slot; |
1155 | old_used_slots = ring->used_slots; | 1161 | old_used_slots = ring->used_slots; |
@@ -1159,7 +1165,7 @@ static int dma_tx_fragment(struct b43_dmaring *ring, | |||
1159 | desc = ops->idx2desc(ring, slot, &meta_hdr); | 1165 | desc = ops->idx2desc(ring, slot, &meta_hdr); |
1160 | memset(meta_hdr, 0, sizeof(*meta_hdr)); | 1166 | memset(meta_hdr, 0, sizeof(*meta_hdr)); |
1161 | 1167 | ||
1162 | header = &(ring->txhdr_cache[slot * hdrsize]); | 1168 | header = &(ring->txhdr_cache[(slot / TX_SLOTS_PER_FRAME) * hdrsize]); |
1163 | cookie = generate_cookie(ring, slot); | 1169 | cookie = generate_cookie(ring, slot); |
1164 | err = b43_generate_txhdr(ring->dev, header, | 1170 | err = b43_generate_txhdr(ring->dev, header, |
1165 | skb->data, skb->len, info, cookie); | 1171 | skb->data, skb->len, info, cookie); |
@@ -1254,8 +1260,8 @@ static inline int should_inject_overflow(struct b43_dmaring *ring) | |||
1254 | } | 1260 | } |
1255 | 1261 | ||
1256 | /* Static mapping of mac80211's queues (priorities) to b43 DMA rings. */ | 1262 | /* Static mapping of mac80211's queues (priorities) to b43 DMA rings. */ |
1257 | static struct b43_dmaring * select_ring_by_priority(struct b43_wldev *dev, | 1263 | static struct b43_dmaring *select_ring_by_priority(struct b43_wldev *dev, |
1258 | u8 queue_prio) | 1264 | u8 queue_prio) |
1259 | { | 1265 | { |
1260 | struct b43_dmaring *ring; | 1266 | struct b43_dmaring *ring; |
1261 | 1267 | ||
@@ -1306,17 +1312,19 @@ int b43_dma_tx(struct b43_wldev *dev, struct sk_buff *skb) | |||
1306 | } | 1312 | } |
1307 | 1313 | ||
1308 | spin_lock_irqsave(&ring->lock, flags); | 1314 | spin_lock_irqsave(&ring->lock, flags); |
1315 | |||
1309 | B43_WARN_ON(!ring->tx); | 1316 | B43_WARN_ON(!ring->tx); |
1310 | if (unlikely(free_slots(ring) < SLOTS_PER_PACKET)) { | ||
1311 | b43warn(dev->wl, "DMA queue overflow\n"); | ||
1312 | err = -ENOSPC; | ||
1313 | goto out_unlock; | ||
1314 | } | ||
1315 | /* Check if the queue was stopped in mac80211, | 1317 | /* Check if the queue was stopped in mac80211, |
1316 | * but we got called nevertheless. | 1318 | * but we got called nevertheless. |
1317 | * That would be a mac80211 bug. */ | 1319 | * That would be a mac80211 bug. */ |
1318 | B43_WARN_ON(ring->stopped); | 1320 | B43_WARN_ON(ring->stopped); |
1319 | 1321 | ||
1322 | if (unlikely(free_slots(ring) < TX_SLOTS_PER_FRAME)) { | ||
1323 | b43warn(dev->wl, "DMA queue overflow\n"); | ||
1324 | err = -ENOSPC; | ||
1325 | goto out_unlock; | ||
1326 | } | ||
1327 | |||
1320 | /* Assign the queue number to the ring (if not already done before) | 1328 | /* Assign the queue number to the ring (if not already done before) |
1321 | * so TX status handling can use it. The queue to ring mapping is | 1329 | * so TX status handling can use it. The queue to ring mapping is |
1322 | * static, so we don't need to store it per frame. */ | 1330 | * static, so we don't need to store it per frame. */ |
@@ -1335,7 +1343,7 @@ int b43_dma_tx(struct b43_wldev *dev, struct sk_buff *skb) | |||
1335 | goto out_unlock; | 1343 | goto out_unlock; |
1336 | } | 1344 | } |
1337 | ring->nr_tx_packets++; | 1345 | ring->nr_tx_packets++; |
1338 | if ((free_slots(ring) < SLOTS_PER_PACKET) || | 1346 | if ((free_slots(ring) < TX_SLOTS_PER_FRAME) || |
1339 | should_inject_overflow(ring)) { | 1347 | should_inject_overflow(ring)) { |
1340 | /* This TX ring is full. */ | 1348 | /* This TX ring is full. */ |
1341 | ieee80211_stop_queue(dev->wl->hw, skb_get_queue_mapping(skb)); | 1349 | ieee80211_stop_queue(dev->wl->hw, skb_get_queue_mapping(skb)); |
@@ -1419,7 +1427,7 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev, | |||
1419 | } | 1427 | } |
1420 | dev->stats.last_tx = jiffies; | 1428 | dev->stats.last_tx = jiffies; |
1421 | if (ring->stopped) { | 1429 | if (ring->stopped) { |
1422 | B43_WARN_ON(free_slots(ring) < SLOTS_PER_PACKET); | 1430 | B43_WARN_ON(free_slots(ring) < TX_SLOTS_PER_FRAME); |
1423 | ieee80211_wake_queue(dev->wl->hw, ring->queue_prio); | 1431 | ieee80211_wake_queue(dev->wl->hw, ring->queue_prio); |
1424 | ring->stopped = 0; | 1432 | ring->stopped = 0; |
1425 | if (b43_debug(dev, B43_DBG_DMAVERBOSE)) { | 1433 | if (b43_debug(dev, B43_DBG_DMAVERBOSE)) { |
@@ -1442,8 +1450,8 @@ void b43_dma_get_tx_stats(struct b43_wldev *dev, | |||
1442 | ring = select_ring_by_priority(dev, i); | 1450 | ring = select_ring_by_priority(dev, i); |
1443 | 1451 | ||
1444 | spin_lock_irqsave(&ring->lock, flags); | 1452 | spin_lock_irqsave(&ring->lock, flags); |
1445 | stats[i].len = ring->used_slots / SLOTS_PER_PACKET; | 1453 | stats[i].len = ring->used_slots / TX_SLOTS_PER_FRAME; |
1446 | stats[i].limit = ring->nr_slots / SLOTS_PER_PACKET; | 1454 | stats[i].limit = ring->nr_slots / TX_SLOTS_PER_FRAME; |
1447 | stats[i].count = ring->nr_tx_packets; | 1455 | stats[i].count = ring->nr_tx_packets; |
1448 | spin_unlock_irqrestore(&ring->lock, flags); | 1456 | spin_unlock_irqrestore(&ring->lock, flags); |
1449 | } | 1457 | } |
diff --git a/drivers/net/wireless/b43/dma.h b/drivers/net/wireless/b43/dma.h index d1eb5c0848a5..05dde646d831 100644 --- a/drivers/net/wireless/b43/dma.h +++ b/drivers/net/wireless/b43/dma.h | |||
@@ -1,14 +1,12 @@ | |||
1 | #ifndef B43_DMA_H_ | 1 | #ifndef B43_DMA_H_ |
2 | #define B43_DMA_H_ | 2 | #define B43_DMA_H_ |
3 | 3 | ||
4 | #include <linux/list.h> | 4 | #include <linux/ieee80211.h> |
5 | #include <linux/spinlock.h> | 5 | #include <linux/spinlock.h> |
6 | #include <linux/workqueue.h> | ||
7 | #include <linux/linkage.h> | ||
8 | #include <asm/atomic.h> | ||
9 | 6 | ||
10 | #include "b43.h" | 7 | #include "b43.h" |
11 | 8 | ||
9 | |||
12 | /* DMA-Interrupt reasons. */ | 10 | /* DMA-Interrupt reasons. */ |
13 | #define B43_DMAIRQ_FATALMASK ((1 << 10) | (1 << 11) | (1 << 12) \ | 11 | #define B43_DMAIRQ_FATALMASK ((1 << 10) | (1 << 11) | (1 << 12) \ |
14 | | (1 << 14) | (1 << 15)) | 12 | | (1 << 14) | (1 << 15)) |
@@ -161,14 +159,13 @@ struct b43_dmadesc_generic { | |||
161 | 159 | ||
162 | /* Misc DMA constants */ | 160 | /* Misc DMA constants */ |
163 | #define B43_DMA_RINGMEMSIZE PAGE_SIZE | 161 | #define B43_DMA_RINGMEMSIZE PAGE_SIZE |
164 | #define B43_DMA0_RX_FRAMEOFFSET 30 | 162 | #define B43_DMA0_RX_FRAMEOFFSET 30 |
165 | #define B43_DMA3_RX_FRAMEOFFSET 0 | ||
166 | 163 | ||
167 | /* DMA engine tuning knobs */ | 164 | /* DMA engine tuning knobs */ |
168 | #define B43_TXRING_SLOTS 128 | 165 | #define B43_TXRING_SLOTS 256 |
169 | #define B43_RXRING_SLOTS 64 | 166 | #define B43_RXRING_SLOTS 64 |
170 | #define B43_DMA0_RX_BUFFERSIZE (2304 + 100) | 167 | #define B43_DMA0_RX_BUFFERSIZE IEEE80211_MAX_FRAME_LEN |
171 | #define B43_DMA3_RX_BUFFERSIZE 16 | 168 | |
172 | 169 | ||
173 | struct sk_buff; | 170 | struct sk_buff; |
174 | struct b43_private; | 171 | struct b43_private; |
@@ -215,7 +212,7 @@ struct b43_dmaring { | |||
215 | void *descbase; | 212 | void *descbase; |
216 | /* Meta data about all descriptors. */ | 213 | /* Meta data about all descriptors. */ |
217 | struct b43_dmadesc_meta *meta; | 214 | struct b43_dmadesc_meta *meta; |
218 | /* Cache of TX headers for each slot. | 215 | /* Cache of TX headers for each TX frame. |
219 | * This is to avoid an allocation on each TX. | 216 | * This is to avoid an allocation on each TX. |
220 | * This is NULL for an RX ring. | 217 | * This is NULL for an RX ring. |
221 | */ | 218 | */ |
diff --git a/drivers/net/wireless/b43/lo.c b/drivers/net/wireless/b43/lo.c index 6a18a1470465..22d0fbd83a62 100644 --- a/drivers/net/wireless/b43/lo.c +++ b/drivers/net/wireless/b43/lo.c | |||
@@ -36,8 +36,8 @@ | |||
36 | #include <linux/sched.h> | 36 | #include <linux/sched.h> |
37 | 37 | ||
38 | 38 | ||
39 | static struct b43_lo_calib * b43_find_lo_calib(struct b43_txpower_lo_control *lo, | 39 | static struct b43_lo_calib *b43_find_lo_calib(struct b43_txpower_lo_control *lo, |
40 | const struct b43_bbatt *bbatt, | 40 | const struct b43_bbatt *bbatt, |
41 | const struct b43_rfatt *rfatt) | 41 | const struct b43_rfatt *rfatt) |
42 | { | 42 | { |
43 | struct b43_lo_calib *c; | 43 | struct b43_lo_calib *c; |
@@ -138,7 +138,7 @@ static u16 lo_measure_feedthrough(struct b43_wldev *dev, | |||
138 | * "pad_mix_gain" is the PAD Mixer Gain. | 138 | * "pad_mix_gain" is the PAD Mixer Gain. |
139 | */ | 139 | */ |
140 | static u16 lo_txctl_register_table(struct b43_wldev *dev, | 140 | static u16 lo_txctl_register_table(struct b43_wldev *dev, |
141 | u16 * value, u16 * pad_mix_gain) | 141 | u16 *value, u16 *pad_mix_gain) |
142 | { | 142 | { |
143 | struct b43_phy *phy = &dev->phy; | 143 | struct b43_phy *phy = &dev->phy; |
144 | u16 reg, v, padmix; | 144 | u16 reg, v, padmix; |
@@ -225,14 +225,12 @@ static void lo_measure_txctl_values(struct b43_wldev *dev) | |||
225 | radio_pctl_reg = tmp; | 225 | radio_pctl_reg = tmp; |
226 | } | 226 | } |
227 | } | 227 | } |
228 | b43_radio_write16(dev, 0x43, (b43_radio_read16(dev, 0x43) | 228 | b43_radio_maskset(dev, 0x43, 0xFFF0, radio_pctl_reg); |
229 | & 0xFFF0) | radio_pctl_reg); | ||
230 | b43_gphy_set_baseband_attenuation(dev, 2); | 229 | b43_gphy_set_baseband_attenuation(dev, 2); |
231 | 230 | ||
232 | reg = lo_txctl_register_table(dev, &mask, NULL); | 231 | reg = lo_txctl_register_table(dev, &mask, NULL); |
233 | mask = ~mask; | 232 | mask = ~mask; |
234 | b43_radio_write16(dev, reg, b43_radio_read16(dev, reg) | 233 | b43_radio_mask(dev, reg, mask); |
235 | & mask); | ||
236 | 234 | ||
237 | if (has_tx_magnification(phy)) { | 235 | if (has_tx_magnification(phy)) { |
238 | int i, j; | 236 | int i, j; |
@@ -242,14 +240,10 @@ static void lo_measure_txctl_values(struct b43_wldev *dev) | |||
242 | 240 | ||
243 | for (i = 0; i < ARRAY_SIZE(tx_magn_values); i++) { | 241 | for (i = 0; i < ARRAY_SIZE(tx_magn_values); i++) { |
244 | tx_magn = tx_magn_values[i]; | 242 | tx_magn = tx_magn_values[i]; |
245 | b43_radio_write16(dev, 0x52, | 243 | b43_radio_maskset(dev, 0x52, 0xFF0F, tx_magn); |
246 | (b43_radio_read16(dev, 0x52) | ||
247 | & 0xFF0F) | tx_magn); | ||
248 | for (j = 0; j < ARRAY_SIZE(tx_bias_values); j++) { | 244 | for (j = 0; j < ARRAY_SIZE(tx_bias_values); j++) { |
249 | tx_bias = tx_bias_values[j]; | 245 | tx_bias = tx_bias_values[j]; |
250 | b43_radio_write16(dev, 0x52, | 246 | b43_radio_maskset(dev, 0x52, 0xFFF0, tx_bias); |
251 | (b43_radio_read16(dev, 0x52) | ||
252 | & 0xFFF0) | tx_bias); | ||
253 | feedthrough = | 247 | feedthrough = |
254 | lo_measure_feedthrough(dev, 0, pga, | 248 | lo_measure_feedthrough(dev, 0, pga, |
255 | trsw_rx); | 249 | trsw_rx); |
@@ -269,8 +263,7 @@ static void lo_measure_txctl_values(struct b43_wldev *dev) | |||
269 | } else { | 263 | } else { |
270 | lo->tx_magn = 0; | 264 | lo->tx_magn = 0; |
271 | lo->tx_bias = 0; | 265 | lo->tx_bias = 0; |
272 | b43_radio_write16(dev, 0x52, b43_radio_read16(dev, 0x52) | 266 | b43_radio_mask(dev, 0x52, 0xFFF0); /* TX bias == 0 */ |
273 | & 0xFFF0); /* TX bias == 0 */ | ||
274 | } | 267 | } |
275 | lo->txctl_measured_time = jiffies; | 268 | lo->txctl_measured_time = jiffies; |
276 | } | 269 | } |
@@ -406,18 +399,10 @@ static void lo_measure_setup(struct b43_wldev *dev, | |||
406 | sav->phy_cck_14 = b43_phy_read(dev, B43_PHY_CCK(0x14)); | 399 | sav->phy_cck_14 = b43_phy_read(dev, B43_PHY_CCK(0x14)); |
407 | sav->phy_hpwr_tssictl = b43_phy_read(dev, B43_PHY_HPWR_TSSICTL); | 400 | sav->phy_hpwr_tssictl = b43_phy_read(dev, B43_PHY_HPWR_TSSICTL); |
408 | 401 | ||
409 | b43_phy_write(dev, B43_PHY_HPWR_TSSICTL, | 402 | b43_phy_set(dev, B43_PHY_HPWR_TSSICTL, 0x100); |
410 | b43_phy_read(dev, B43_PHY_HPWR_TSSICTL) | 403 | b43_phy_set(dev, B43_PHY_EXTG(0x01), 0x40); |
411 | | 0x100); | 404 | b43_phy_set(dev, B43_PHY_DACCTL, 0x40); |
412 | b43_phy_write(dev, B43_PHY_EXTG(0x01), | 405 | b43_phy_set(dev, B43_PHY_CCK(0x14), 0x200); |
413 | b43_phy_read(dev, B43_PHY_EXTG(0x01)) | ||
414 | | 0x40); | ||
415 | b43_phy_write(dev, B43_PHY_DACCTL, | ||
416 | b43_phy_read(dev, B43_PHY_DACCTL) | ||
417 | | 0x40); | ||
418 | b43_phy_write(dev, B43_PHY_CCK(0x14), | ||
419 | b43_phy_read(dev, B43_PHY_CCK(0x14)) | ||
420 | | 0x200); | ||
421 | } | 406 | } |
422 | if (phy->type == B43_PHYTYPE_B && | 407 | if (phy->type == B43_PHYTYPE_B && |
423 | phy->radio_ver == 0x2050 && phy->radio_rev < 6) { | 408 | phy->radio_ver == 0x2050 && phy->radio_rev < 6) { |
@@ -434,17 +419,10 @@ static void lo_measure_setup(struct b43_wldev *dev, | |||
434 | sav->phy_cck_3E = b43_phy_read(dev, B43_PHY_CCK(0x3E)); | 419 | sav->phy_cck_3E = b43_phy_read(dev, B43_PHY_CCK(0x3E)); |
435 | sav->phy_crs0 = b43_phy_read(dev, B43_PHY_CRS0); | 420 | sav->phy_crs0 = b43_phy_read(dev, B43_PHY_CRS0); |
436 | 421 | ||
437 | b43_phy_write(dev, B43_PHY_CLASSCTL, | 422 | b43_phy_mask(dev, B43_PHY_CLASSCTL, 0xFFFC); |
438 | b43_phy_read(dev, B43_PHY_CLASSCTL) | 423 | b43_phy_mask(dev, B43_PHY_CRS0, 0x7FFF); |
439 | & 0xFFFC); | 424 | b43_phy_set(dev, B43_PHY_ANALOGOVER, 0x0003); |
440 | b43_phy_write(dev, B43_PHY_CRS0, b43_phy_read(dev, B43_PHY_CRS0) | 425 | b43_phy_mask(dev, B43_PHY_ANALOGOVERVAL, 0xFFFC); |
441 | & 0x7FFF); | ||
442 | b43_phy_write(dev, B43_PHY_ANALOGOVER, | ||
443 | b43_phy_read(dev, B43_PHY_ANALOGOVER) | ||
444 | | 0x0003); | ||
445 | b43_phy_write(dev, B43_PHY_ANALOGOVERVAL, | ||
446 | b43_phy_read(dev, B43_PHY_ANALOGOVERVAL) | ||
447 | & 0xFFFC); | ||
448 | if (phy->type == B43_PHYTYPE_G) { | 426 | if (phy->type == B43_PHYTYPE_G) { |
449 | if ((phy->rev >= 7) && | 427 | if ((phy->rev >= 7) && |
450 | (sprom->boardflags_lo & B43_BFL_EXTLNA)) { | 428 | (sprom->boardflags_lo & B43_BFL_EXTLNA)) { |
@@ -558,8 +536,7 @@ static void lo_measure_restore(struct b43_wldev *dev, | |||
558 | b43_radio_write16(dev, 0x7A, sav->radio_7A); | 536 | b43_radio_write16(dev, 0x7A, sav->radio_7A); |
559 | if (!has_tx_magnification(phy)) { | 537 | if (!has_tx_magnification(phy)) { |
560 | tmp = sav->radio_52; | 538 | tmp = sav->radio_52; |
561 | b43_radio_write16(dev, 0x52, (b43_radio_read16(dev, 0x52) | 539 | b43_radio_maskset(dev, 0x52, 0xFF0F, tmp); |
562 | & 0xFF0F) | tmp); | ||
563 | } | 540 | } |
564 | b43_write16(dev, 0x3E2, sav->reg_3E2); | 541 | b43_write16(dev, 0x3E2, sav->reg_3E2); |
565 | if (phy->type == B43_PHYTYPE_B && | 542 | if (phy->type == B43_PHYTYPE_B && |
@@ -754,9 +731,9 @@ static void lo_probe_loctls_statemachine(struct b43_wldev *dev, | |||
754 | } | 731 | } |
755 | 732 | ||
756 | static | 733 | static |
757 | struct b43_lo_calib * b43_calibrate_lo_setting(struct b43_wldev *dev, | 734 | struct b43_lo_calib *b43_calibrate_lo_setting(struct b43_wldev *dev, |
758 | const struct b43_bbatt *bbatt, | 735 | const struct b43_bbatt *bbatt, |
759 | const struct b43_rfatt *rfatt) | 736 | const struct b43_rfatt *rfatt) |
760 | { | 737 | { |
761 | struct b43_phy *phy = &dev->phy; | 738 | struct b43_phy *phy = &dev->phy; |
762 | struct b43_phy_g *gphy = phy->g; | 739 | struct b43_phy_g *gphy = phy->g; |
@@ -778,12 +755,8 @@ struct b43_lo_calib * b43_calibrate_lo_setting(struct b43_wldev *dev, | |||
778 | 755 | ||
779 | txctl_reg = lo_txctl_register_table(dev, &txctl_value, &pad_mix_gain); | 756 | txctl_reg = lo_txctl_register_table(dev, &txctl_value, &pad_mix_gain); |
780 | 757 | ||
781 | b43_radio_write16(dev, 0x43, | 758 | b43_radio_maskset(dev, 0x43, 0xFFF0, rfatt->att); |
782 | (b43_radio_read16(dev, 0x43) & 0xFFF0) | 759 | b43_radio_maskset(dev, txctl_reg, ~txctl_value, (rfatt->with_padmix ? txctl_value :0)); |
783 | | rfatt->att); | ||
784 | b43_radio_write16(dev, txctl_reg, | ||
785 | (b43_radio_read16(dev, txctl_reg) & ~txctl_value) | ||
786 | | (rfatt->with_padmix) ? txctl_value : 0); | ||
787 | 760 | ||
788 | max_rx_gain = rfatt->att * 2; | 761 | max_rx_gain = rfatt->att * 2; |
789 | max_rx_gain += bbatt->att / 2; | 762 | max_rx_gain += bbatt->att / 2; |
@@ -824,9 +797,9 @@ struct b43_lo_calib * b43_calibrate_lo_setting(struct b43_wldev *dev, | |||
824 | /* Get a calibrated LO setting for the given attenuation values. | 797 | /* Get a calibrated LO setting for the given attenuation values. |
825 | * Might return a NULL pointer under OOM! */ | 798 | * Might return a NULL pointer under OOM! */ |
826 | static | 799 | static |
827 | struct b43_lo_calib * b43_get_calib_lo_settings(struct b43_wldev *dev, | 800 | struct b43_lo_calib *b43_get_calib_lo_settings(struct b43_wldev *dev, |
828 | const struct b43_bbatt *bbatt, | 801 | const struct b43_bbatt *bbatt, |
829 | const struct b43_rfatt *rfatt) | 802 | const struct b43_rfatt *rfatt) |
830 | { | 803 | { |
831 | struct b43_txpower_lo_control *lo = dev->phy.g->lo_control; | 804 | struct b43_txpower_lo_control *lo = dev->phy.g->lo_control; |
832 | struct b43_lo_calib *c; | 805 | struct b43_lo_calib *c; |
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 7116ab6eccfa..8e1126d99f4c 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c | |||
@@ -512,7 +512,7 @@ void b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value) | |||
512 | } | 512 | } |
513 | 513 | ||
514 | /* Read HostFlags */ | 514 | /* Read HostFlags */ |
515 | u64 b43_hf_read(struct b43_wldev * dev) | 515 | u64 b43_hf_read(struct b43_wldev *dev) |
516 | { | 516 | { |
517 | u64 ret; | 517 | u64 ret; |
518 | 518 | ||
@@ -600,7 +600,7 @@ void b43_tsf_write(struct b43_wldev *dev, u64 tsf) | |||
600 | } | 600 | } |
601 | 601 | ||
602 | static | 602 | static |
603 | void b43_macfilter_set(struct b43_wldev *dev, u16 offset, const u8 * mac) | 603 | void b43_macfilter_set(struct b43_wldev *dev, u16 offset, const u8 *mac) |
604 | { | 604 | { |
605 | static const u8 zero_addr[ETH_ALEN] = { 0 }; | 605 | static const u8 zero_addr[ETH_ALEN] = { 0 }; |
606 | u16 data; | 606 | u16 data; |
@@ -790,7 +790,7 @@ void b43_dummy_transmission(struct b43_wldev *dev) | |||
790 | } | 790 | } |
791 | 791 | ||
792 | static void key_write(struct b43_wldev *dev, | 792 | static void key_write(struct b43_wldev *dev, |
793 | u8 index, u8 algorithm, const u8 * key) | 793 | u8 index, u8 algorithm, const u8 *key) |
794 | { | 794 | { |
795 | unsigned int i; | 795 | unsigned int i; |
796 | u32 offset; | 796 | u32 offset; |
@@ -812,7 +812,7 @@ static void key_write(struct b43_wldev *dev, | |||
812 | } | 812 | } |
813 | } | 813 | } |
814 | 814 | ||
815 | static void keymac_write(struct b43_wldev *dev, u8 index, const u8 * addr) | 815 | static void keymac_write(struct b43_wldev *dev, u8 index, const u8 *addr) |
816 | { | 816 | { |
817 | u32 addrtmp[2] = { 0, 0, }; | 817 | u32 addrtmp[2] = { 0, 0, }; |
818 | u8 per_sta_keys_start = 8; | 818 | u8 per_sta_keys_start = 8; |
@@ -862,7 +862,7 @@ static void keymac_write(struct b43_wldev *dev, u8 index, const u8 * addr) | |||
862 | 862 | ||
863 | static void do_key_write(struct b43_wldev *dev, | 863 | static void do_key_write(struct b43_wldev *dev, |
864 | u8 index, u8 algorithm, | 864 | u8 index, u8 algorithm, |
865 | const u8 * key, size_t key_len, const u8 * mac_addr) | 865 | const u8 *key, size_t key_len, const u8 *mac_addr) |
866 | { | 866 | { |
867 | u8 buf[B43_SEC_KEYSIZE] = { 0, }; | 867 | u8 buf[B43_SEC_KEYSIZE] = { 0, }; |
868 | u8 per_sta_keys_start = 8; | 868 | u8 per_sta_keys_start = 8; |
@@ -886,8 +886,8 @@ static void do_key_write(struct b43_wldev *dev, | |||
886 | 886 | ||
887 | static int b43_key_write(struct b43_wldev *dev, | 887 | static int b43_key_write(struct b43_wldev *dev, |
888 | int index, u8 algorithm, | 888 | int index, u8 algorithm, |
889 | const u8 * key, size_t key_len, | 889 | const u8 *key, size_t key_len, |
890 | const u8 * mac_addr, | 890 | const u8 *mac_addr, |
891 | struct ieee80211_key_conf *keyconf) | 891 | struct ieee80211_key_conf *keyconf) |
892 | { | 892 | { |
893 | int i; | 893 | int i; |
@@ -1286,7 +1286,7 @@ static void handle_irq_pmq(struct b43_wldev *dev) | |||
1286 | } | 1286 | } |
1287 | 1287 | ||
1288 | static void b43_write_template_common(struct b43_wldev *dev, | 1288 | static void b43_write_template_common(struct b43_wldev *dev, |
1289 | const u8 * data, u16 size, | 1289 | const u8 *data, u16 size, |
1290 | u16 ram_offset, | 1290 | u16 ram_offset, |
1291 | u16 shm_size_offset, u8 rate) | 1291 | u16 shm_size_offset, u8 rate) |
1292 | { | 1292 | { |
@@ -1476,9 +1476,9 @@ static void b43_write_probe_resp_plcp(struct b43_wldev *dev, | |||
1476 | * 2) Patching duration field | 1476 | * 2) Patching duration field |
1477 | * 3) Stripping TIM | 1477 | * 3) Stripping TIM |
1478 | */ | 1478 | */ |
1479 | static const u8 * b43_generate_probe_resp(struct b43_wldev *dev, | 1479 | static const u8 *b43_generate_probe_resp(struct b43_wldev *dev, |
1480 | u16 *dest_size, | 1480 | u16 *dest_size, |
1481 | struct ieee80211_rate *rate) | 1481 | struct ieee80211_rate *rate) |
1482 | { | 1482 | { |
1483 | const u8 *src_data; | 1483 | const u8 *src_data; |
1484 | u8 *dest_data; | 1484 | u8 *dest_data; |
@@ -2980,7 +2980,7 @@ static void b43_security_init(struct b43_wldev *dev) | |||
2980 | b43_clear_keys(dev); | 2980 | b43_clear_keys(dev); |
2981 | } | 2981 | } |
2982 | 2982 | ||
2983 | static int b43_rng_read(struct hwrng *rng, u32 * data) | 2983 | static int b43_rng_read(struct hwrng *rng, u32 *data) |
2984 | { | 2984 | { |
2985 | struct b43_wl *wl = (struct b43_wl *)rng->priv; | 2985 | struct b43_wl *wl = (struct b43_wl *)rng->priv; |
2986 | unsigned long flags; | 2986 | unsigned long flags; |
@@ -3311,7 +3311,7 @@ static void b43_put_phy_into_reset(struct b43_wldev *dev) | |||
3311 | msleep(1); | 3311 | msleep(1); |
3312 | } | 3312 | } |
3313 | 3313 | ||
3314 | static const char * band_to_string(enum ieee80211_band band) | 3314 | static const char *band_to_string(enum ieee80211_band band) |
3315 | { | 3315 | { |
3316 | switch (band) { | 3316 | switch (band) { |
3317 | case IEEE80211_BAND_5GHZ: | 3317 | case IEEE80211_BAND_5GHZ: |
@@ -4170,11 +4170,19 @@ static int b43_wireless_core_init(struct b43_wldev *dev) | |||
4170 | hf |= B43_HF_GDCW; | 4170 | hf |= B43_HF_GDCW; |
4171 | if (sprom->boardflags_lo & B43_BFL_PACTRL) | 4171 | if (sprom->boardflags_lo & B43_BFL_PACTRL) |
4172 | hf |= B43_HF_OFDMPABOOST; | 4172 | hf |= B43_HF_OFDMPABOOST; |
4173 | } else if (phy->type == B43_PHYTYPE_B) { | ||
4174 | hf |= B43_HF_SYMW; | ||
4175 | if (phy->rev >= 2 && phy->radio_ver == 0x2050) | ||
4176 | hf &= ~B43_HF_GDCW; | ||
4177 | } | 4173 | } |
4174 | if (phy->radio_ver == 0x2050) { | ||
4175 | if (phy->radio_rev == 6) | ||
4176 | hf |= B43_HF_4318TSSI; | ||
4177 | if (phy->radio_rev < 6) | ||
4178 | hf |= B43_HF_VCORECALC; | ||
4179 | } | ||
4180 | if (sprom->boardflags_lo & B43_BFL_XTAL_NOSLOW) | ||
4181 | hf |= B43_HF_DSCRQ; /* Disable slowclock requests from ucode. */ | ||
4182 | if ((bus->bustype == SSB_BUSTYPE_PCI) && | ||
4183 | (bus->pcicore.dev->id.revision <= 10)) | ||
4184 | hf |= B43_HF_PCISCW; /* PCI slow clock workaround. */ | ||
4185 | hf &= ~B43_HF_SKCFPUP; | ||
4178 | b43_hf_write(dev, hf); | 4186 | b43_hf_write(dev, hf); |
4179 | 4187 | ||
4180 | b43_set_retry_limits(dev, B43_DEFAULT_SHORT_RETRY_LIMIT, | 4188 | b43_set_retry_limits(dev, B43_DEFAULT_SHORT_RETRY_LIMIT, |
@@ -4213,7 +4221,7 @@ static int b43_wireless_core_init(struct b43_wldev *dev) | |||
4213 | b43_set_synth_pu_delay(dev, 1); | 4221 | b43_set_synth_pu_delay(dev, 1); |
4214 | b43_bluetooth_coext_enable(dev); | 4222 | b43_bluetooth_coext_enable(dev); |
4215 | 4223 | ||
4216 | ssb_bus_powerup(bus, 1); /* Enable dynamic PCTL */ | 4224 | ssb_bus_powerup(bus, !(sprom->boardflags_lo & B43_BFL_XTAL_NOSLOW)); |
4217 | b43_upload_card_macaddress(dev); | 4225 | b43_upload_card_macaddress(dev); |
4218 | b43_security_init(dev); | 4226 | b43_security_init(dev); |
4219 | if (!dev->suspend_in_progress) | 4227 | if (!dev->suspend_in_progress) |
@@ -4397,6 +4405,34 @@ static void b43_op_sta_notify(struct ieee80211_hw *hw, | |||
4397 | B43_WARN_ON(!vif || wl->vif != vif); | 4405 | B43_WARN_ON(!vif || wl->vif != vif); |
4398 | } | 4406 | } |
4399 | 4407 | ||
4408 | static void b43_op_sw_scan_start_notifier(struct ieee80211_hw *hw) | ||
4409 | { | ||
4410 | struct b43_wl *wl = hw_to_b43_wl(hw); | ||
4411 | struct b43_wldev *dev; | ||
4412 | |||
4413 | mutex_lock(&wl->mutex); | ||
4414 | dev = wl->current_dev; | ||
4415 | if (dev && (b43_status(dev) >= B43_STAT_INITIALIZED)) { | ||
4416 | /* Disable CFP update during scan on other channels. */ | ||
4417 | b43_hf_write(dev, b43_hf_read(dev) | B43_HF_SKCFPUP); | ||
4418 | } | ||
4419 | mutex_unlock(&wl->mutex); | ||
4420 | } | ||
4421 | |||
4422 | static void b43_op_sw_scan_complete_notifier(struct ieee80211_hw *hw) | ||
4423 | { | ||
4424 | struct b43_wl *wl = hw_to_b43_wl(hw); | ||
4425 | struct b43_wldev *dev; | ||
4426 | |||
4427 | mutex_lock(&wl->mutex); | ||
4428 | dev = wl->current_dev; | ||
4429 | if (dev && (b43_status(dev) >= B43_STAT_INITIALIZED)) { | ||
4430 | /* Re-enable CFP update. */ | ||
4431 | b43_hf_write(dev, b43_hf_read(dev) & ~B43_HF_SKCFPUP); | ||
4432 | } | ||
4433 | mutex_unlock(&wl->mutex); | ||
4434 | } | ||
4435 | |||
4400 | static const struct ieee80211_ops b43_hw_ops = { | 4436 | static const struct ieee80211_ops b43_hw_ops = { |
4401 | .tx = b43_op_tx, | 4437 | .tx = b43_op_tx, |
4402 | .conf_tx = b43_op_conf_tx, | 4438 | .conf_tx = b43_op_conf_tx, |
@@ -4415,6 +4451,8 @@ static const struct ieee80211_ops b43_hw_ops = { | |||
4415 | .stop = b43_op_stop, | 4451 | .stop = b43_op_stop, |
4416 | .set_tim = b43_op_beacon_set_tim, | 4452 | .set_tim = b43_op_beacon_set_tim, |
4417 | .sta_notify = b43_op_sta_notify, | 4453 | .sta_notify = b43_op_sta_notify, |
4454 | .sw_scan_start = b43_op_sw_scan_start_notifier, | ||
4455 | .sw_scan_complete = b43_op_sw_scan_complete_notifier, | ||
4418 | }; | 4456 | }; |
4419 | 4457 | ||
4420 | /* Hard-reset the chip. Do not call this directly. | 4458 | /* Hard-reset the chip. Do not call this directly. |
diff --git a/drivers/net/wireless/b43/phy_a.c b/drivers/net/wireless/b43/phy_a.c index 7fe9d1701624..c836c077d51d 100644 --- a/drivers/net/wireless/b43/phy_a.c +++ b/drivers/net/wireless/b43/phy_a.c | |||
@@ -121,27 +121,18 @@ static void aphy_channel_switch(struct b43_wldev *dev, unsigned int channel) | |||
121 | b43_radio_write16(dev, 0x0007, (r8 << 4) | r8); | 121 | b43_radio_write16(dev, 0x0007, (r8 << 4) | r8); |
122 | b43_radio_write16(dev, 0x0020, (r8 << 4) | r8); | 122 | b43_radio_write16(dev, 0x0020, (r8 << 4) | r8); |
123 | b43_radio_write16(dev, 0x0021, (r8 << 4) | r8); | 123 | b43_radio_write16(dev, 0x0021, (r8 << 4) | r8); |
124 | b43_radio_write16(dev, 0x0022, (b43_radio_read16(dev, 0x0022) | 124 | b43_radio_maskset(dev, 0x0022, 0x000F, (r8 << 4)); |
125 | & 0x000F) | (r8 << 4)); | ||
126 | b43_radio_write16(dev, 0x002A, (r8 << 4)); | 125 | b43_radio_write16(dev, 0x002A, (r8 << 4)); |
127 | b43_radio_write16(dev, 0x002B, (r8 << 4)); | 126 | b43_radio_write16(dev, 0x002B, (r8 << 4)); |
128 | b43_radio_write16(dev, 0x0008, (b43_radio_read16(dev, 0x0008) | 127 | b43_radio_maskset(dev, 0x0008, 0x00F0, (r8 << 4)); |
129 | & 0x00F0) | (r8 << 4)); | 128 | b43_radio_maskset(dev, 0x0029, 0xFF0F, 0x00B0); |
130 | b43_radio_write16(dev, 0x0029, (b43_radio_read16(dev, 0x0029) | ||
131 | & 0xFF0F) | 0x00B0); | ||
132 | b43_radio_write16(dev, 0x0035, 0x00AA); | 129 | b43_radio_write16(dev, 0x0035, 0x00AA); |
133 | b43_radio_write16(dev, 0x0036, 0x0085); | 130 | b43_radio_write16(dev, 0x0036, 0x0085); |
134 | b43_radio_write16(dev, 0x003A, (b43_radio_read16(dev, 0x003A) | 131 | b43_radio_maskset(dev, 0x003A, 0xFF20, freq_r3A_value(freq)); |
135 | & 0xFF20) | | 132 | b43_radio_mask(dev, 0x003D, 0x00FF); |
136 | freq_r3A_value(freq)); | 133 | b43_radio_maskset(dev, 0x0081, 0xFF7F, 0x0080); |
137 | b43_radio_write16(dev, 0x003D, | 134 | b43_radio_mask(dev, 0x0035, 0xFFEF); |
138 | b43_radio_read16(dev, 0x003D) & 0x00FF); | 135 | b43_radio_maskset(dev, 0x0035, 0xFFEF, 0x0010); |
139 | b43_radio_write16(dev, 0x0081, (b43_radio_read16(dev, 0x0081) | ||
140 | & 0xFF7F) | 0x0080); | ||
141 | b43_radio_write16(dev, 0x0035, | ||
142 | b43_radio_read16(dev, 0x0035) & 0xFFEF); | ||
143 | b43_radio_write16(dev, 0x0035, (b43_radio_read16(dev, 0x0035) | ||
144 | & 0xFFEF) | 0x0010); | ||
145 | b43_radio_set_tx_iq(dev); | 136 | b43_radio_set_tx_iq(dev); |
146 | //TODO: TSSI2dbm workaround | 137 | //TODO: TSSI2dbm workaround |
147 | //FIXME b43_phy_xmitpower(dev); | 138 | //FIXME b43_phy_xmitpower(dev); |
@@ -160,23 +151,20 @@ static void b43_radio_init2060(struct b43_wldev *dev) | |||
160 | b43_radio_write16(dev, 0x0082, 0x0080); | 151 | b43_radio_write16(dev, 0x0082, 0x0080); |
161 | b43_radio_write16(dev, 0x0080, 0x0000); | 152 | b43_radio_write16(dev, 0x0080, 0x0000); |
162 | b43_radio_write16(dev, 0x003F, 0x00DA); | 153 | b43_radio_write16(dev, 0x003F, 0x00DA); |
163 | b43_radio_write16(dev, 0x0005, b43_radio_read16(dev, 0x0005) & ~0x0008); | 154 | b43_radio_mask(dev, 0x0005, ~0x0008); |
164 | b43_radio_write16(dev, 0x0081, b43_radio_read16(dev, 0x0081) & ~0x0010); | 155 | b43_radio_mask(dev, 0x0081, ~0x0010); |
165 | b43_radio_write16(dev, 0x0081, b43_radio_read16(dev, 0x0081) & ~0x0020); | 156 | b43_radio_mask(dev, 0x0081, ~0x0020); |
166 | b43_radio_write16(dev, 0x0081, b43_radio_read16(dev, 0x0081) & ~0x0020); | 157 | b43_radio_mask(dev, 0x0081, ~0x0020); |
167 | msleep(1); /* delay 400usec */ | 158 | msleep(1); /* delay 400usec */ |
168 | 159 | ||
169 | b43_radio_write16(dev, 0x0081, | 160 | b43_radio_maskset(dev, 0x0081, ~0x0020, 0x0010); |
170 | (b43_radio_read16(dev, 0x0081) & ~0x0020) | 0x0010); | ||
171 | msleep(1); /* delay 400usec */ | 161 | msleep(1); /* delay 400usec */ |
172 | 162 | ||
173 | b43_radio_write16(dev, 0x0005, | 163 | b43_radio_maskset(dev, 0x0005, ~0x0008, 0x0008); |
174 | (b43_radio_read16(dev, 0x0005) & ~0x0008) | 0x0008); | 164 | b43_radio_mask(dev, 0x0085, ~0x0010); |
175 | b43_radio_write16(dev, 0x0085, b43_radio_read16(dev, 0x0085) & ~0x0010); | 165 | b43_radio_mask(dev, 0x0005, ~0x0008); |
176 | b43_radio_write16(dev, 0x0005, b43_radio_read16(dev, 0x0005) & ~0x0008); | 166 | b43_radio_mask(dev, 0x0081, ~0x0040); |
177 | b43_radio_write16(dev, 0x0081, b43_radio_read16(dev, 0x0081) & ~0x0040); | 167 | b43_radio_maskset(dev, 0x0081, ~0x0040, 0x0040); |
178 | b43_radio_write16(dev, 0x0081, | ||
179 | (b43_radio_read16(dev, 0x0081) & ~0x0040) | 0x0040); | ||
180 | b43_radio_write16(dev, 0x0005, | 168 | b43_radio_write16(dev, 0x0005, |
181 | (b43_radio_read16(dev, 0x0081) & ~0x0008) | 0x0008); | 169 | (b43_radio_read16(dev, 0x0081) & ~0x0008) | 0x0008); |
182 | b43_phy_write(dev, 0x0063, 0xDDC6); | 170 | b43_phy_write(dev, 0x0063, 0xDDC6); |
@@ -224,22 +212,16 @@ static void b43_phy_ww(struct b43_wldev *dev) | |||
224 | u16 b, curr_s, best_s = 0xFFFF; | 212 | u16 b, curr_s, best_s = 0xFFFF; |
225 | int i; | 213 | int i; |
226 | 214 | ||
227 | b43_phy_write(dev, B43_PHY_CRS0, | 215 | b43_phy_mask(dev, B43_PHY_CRS0, ~B43_PHY_CRS0_EN); |
228 | b43_phy_read(dev, B43_PHY_CRS0) & ~B43_PHY_CRS0_EN); | 216 | b43_phy_set(dev, B43_PHY_OFDM(0x1B), 0x1000); |
229 | b43_phy_write(dev, B43_PHY_OFDM(0x1B), | 217 | b43_phy_maskset(dev, B43_PHY_OFDM(0x82), 0xF0FF, 0x0300); |
230 | b43_phy_read(dev, B43_PHY_OFDM(0x1B)) | 0x1000); | 218 | b43_radio_set(dev, 0x0009, 0x0080); |
231 | b43_phy_write(dev, B43_PHY_OFDM(0x82), | 219 | b43_radio_maskset(dev, 0x0012, 0xFFFC, 0x0002); |
232 | (b43_phy_read(dev, B43_PHY_OFDM(0x82)) & 0xF0FF) | 0x0300); | ||
233 | b43_radio_write16(dev, 0x0009, | ||
234 | b43_radio_read16(dev, 0x0009) | 0x0080); | ||
235 | b43_radio_write16(dev, 0x0012, | ||
236 | (b43_radio_read16(dev, 0x0012) & 0xFFFC) | 0x0002); | ||
237 | b43_wa_initgains(dev); | 220 | b43_wa_initgains(dev); |
238 | b43_phy_write(dev, B43_PHY_OFDM(0xBA), 0x3ED5); | 221 | b43_phy_write(dev, B43_PHY_OFDM(0xBA), 0x3ED5); |
239 | b = b43_phy_read(dev, B43_PHY_PWRDOWN); | 222 | b = b43_phy_read(dev, B43_PHY_PWRDOWN); |
240 | b43_phy_write(dev, B43_PHY_PWRDOWN, (b & 0xFFF8) | 0x0005); | 223 | b43_phy_write(dev, B43_PHY_PWRDOWN, (b & 0xFFF8) | 0x0005); |
241 | b43_radio_write16(dev, 0x0004, | 224 | b43_radio_set(dev, 0x0004, 0x0004); |
242 | b43_radio_read16(dev, 0x0004) | 0x0004); | ||
243 | for (i = 0x10; i <= 0x20; i++) { | 225 | for (i = 0x10; i <= 0x20; i++) { |
244 | b43_radio_write16(dev, 0x0013, i); | 226 | b43_radio_write16(dev, 0x0013, i); |
245 | curr_s = b43_phy_read(dev, B43_PHY_OTABLEQ) & 0x00FF; | 227 | curr_s = b43_phy_read(dev, B43_PHY_OTABLEQ) & 0x00FF; |
@@ -252,8 +234,7 @@ static void b43_phy_ww(struct b43_wldev *dev) | |||
252 | best_s = curr_s; | 234 | best_s = curr_s; |
253 | } | 235 | } |
254 | b43_phy_write(dev, B43_PHY_PWRDOWN, b); | 236 | b43_phy_write(dev, B43_PHY_PWRDOWN, b); |
255 | b43_radio_write16(dev, 0x0004, | 237 | b43_radio_mask(dev, 0x0004, 0xFFFB); |
256 | b43_radio_read16(dev, 0x0004) & 0xFFFB); | ||
257 | b43_radio_write16(dev, 0x0013, best_s); | 238 | b43_radio_write16(dev, 0x0013, best_s); |
258 | b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1_R1, 0, 0xFFEC); | 239 | b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1_R1, 0, 0xFFEC); |
259 | b43_phy_write(dev, B43_PHY_OFDM(0xB7), 0x1E80); | 240 | b43_phy_write(dev, B43_PHY_OFDM(0xB7), 0x1E80); |
@@ -261,14 +242,10 @@ static void b43_phy_ww(struct b43_wldev *dev) | |||
261 | b43_phy_write(dev, B43_PHY_OFDM(0xB5), 0x0EC0); | 242 | b43_phy_write(dev, B43_PHY_OFDM(0xB5), 0x0EC0); |
262 | b43_phy_write(dev, B43_PHY_OFDM(0xB2), 0x00C0); | 243 | b43_phy_write(dev, B43_PHY_OFDM(0xB2), 0x00C0); |
263 | b43_phy_write(dev, B43_PHY_OFDM(0xB9), 0x1FFF); | 244 | b43_phy_write(dev, B43_PHY_OFDM(0xB9), 0x1FFF); |
264 | b43_phy_write(dev, B43_PHY_OFDM(0xBB), | 245 | b43_phy_maskset(dev, B43_PHY_OFDM(0xBB), 0xF000, 0x0053); |
265 | (b43_phy_read(dev, B43_PHY_OFDM(0xBB)) & 0xF000) | 0x0053); | 246 | b43_phy_maskset(dev, B43_PHY_OFDM61, 0xFE1F, 0x0120); |
266 | b43_phy_write(dev, B43_PHY_OFDM61, | 247 | b43_phy_maskset(dev, B43_PHY_OFDM(0x13), 0x0FFF, 0x3000); |
267 | (b43_phy_read(dev, B43_PHY_OFDM61) & 0xFE1F) | 0x0120); | 248 | b43_phy_maskset(dev, B43_PHY_OFDM(0x14), 0x0FFF, 0x3000); |
268 | b43_phy_write(dev, B43_PHY_OFDM(0x13), | ||
269 | (b43_phy_read(dev, B43_PHY_OFDM(0x13)) & 0x0FFF) | 0x3000); | ||
270 | b43_phy_write(dev, B43_PHY_OFDM(0x14), | ||
271 | (b43_phy_read(dev, B43_PHY_OFDM(0x14)) & 0x0FFF) | 0x3000); | ||
272 | b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 6, 0x0017); | 249 | b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 6, 0x0017); |
273 | for (i = 0; i < 6; i++) | 250 | for (i = 0; i < 6; i++) |
274 | b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, i, 0x000F); | 251 | b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, i, 0x000F); |
@@ -276,8 +253,7 @@ static void b43_phy_ww(struct b43_wldev *dev) | |||
276 | b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 0x0E, 0x0011); | 253 | b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 0x0E, 0x0011); |
277 | b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 0x0F, 0x0013); | 254 | b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 0x0F, 0x0013); |
278 | b43_phy_write(dev, B43_PHY_OFDM(0x33), 0x5030); | 255 | b43_phy_write(dev, B43_PHY_OFDM(0x33), 0x5030); |
279 | b43_phy_write(dev, B43_PHY_CRS0, | 256 | b43_phy_set(dev, B43_PHY_CRS0, B43_PHY_CRS0_EN); |
280 | b43_phy_read(dev, B43_PHY_CRS0) | B43_PHY_CRS0_EN); | ||
281 | } | 257 | } |
282 | 258 | ||
283 | static void hardware_pctl_init_aphy(struct b43_wldev *dev) | 259 | static void hardware_pctl_init_aphy(struct b43_wldev *dev) |
@@ -300,26 +276,21 @@ void b43_phy_inita(struct b43_wldev *dev) | |||
300 | 276 | ||
301 | if (phy->rev >= 6) { | 277 | if (phy->rev >= 6) { |
302 | if (phy->type == B43_PHYTYPE_A) | 278 | if (phy->type == B43_PHYTYPE_A) |
303 | b43_phy_write(dev, B43_PHY_OFDM(0x1B), | 279 | b43_phy_mask(dev, B43_PHY_OFDM(0x1B), ~0x1000); |
304 | b43_phy_read(dev, B43_PHY_OFDM(0x1B)) & ~0x1000); | ||
305 | if (b43_phy_read(dev, B43_PHY_ENCORE) & B43_PHY_ENCORE_EN) | 280 | if (b43_phy_read(dev, B43_PHY_ENCORE) & B43_PHY_ENCORE_EN) |
306 | b43_phy_write(dev, B43_PHY_ENCORE, | 281 | b43_phy_set(dev, B43_PHY_ENCORE, 0x0010); |
307 | b43_phy_read(dev, B43_PHY_ENCORE) | 0x0010); | ||
308 | else | 282 | else |
309 | b43_phy_write(dev, B43_PHY_ENCORE, | 283 | b43_phy_mask(dev, B43_PHY_ENCORE, ~0x1010); |
310 | b43_phy_read(dev, B43_PHY_ENCORE) & ~0x1010); | ||
311 | } | 284 | } |
312 | 285 | ||
313 | b43_wa_all(dev); | 286 | b43_wa_all(dev); |
314 | 287 | ||
315 | if (phy->type == B43_PHYTYPE_A) { | 288 | if (phy->type == B43_PHYTYPE_A) { |
316 | if (phy->gmode && (phy->rev < 3)) | 289 | if (phy->gmode && (phy->rev < 3)) |
317 | b43_phy_write(dev, 0x0034, | 290 | b43_phy_set(dev, 0x0034, 0x0001); |
318 | b43_phy_read(dev, 0x0034) | 0x0001); | ||
319 | b43_phy_rssiagc(dev, 0); | 291 | b43_phy_rssiagc(dev, 0); |
320 | 292 | ||
321 | b43_phy_write(dev, B43_PHY_CRS0, | 293 | b43_phy_set(dev, B43_PHY_CRS0, B43_PHY_CRS0_EN); |
322 | b43_phy_read(dev, B43_PHY_CRS0) | B43_PHY_CRS0_EN); | ||
323 | 294 | ||
324 | b43_radio_init2060(dev); | 295 | b43_radio_init2060(dev); |
325 | 296 | ||
@@ -339,9 +310,7 @@ void b43_phy_inita(struct b43_wldev *dev) | |||
339 | 310 | ||
340 | if ((phy->type == B43_PHYTYPE_G) && | 311 | if ((phy->type == B43_PHYTYPE_G) && |
341 | (dev->dev->bus->sprom.boardflags_lo & B43_BFL_PACTRL)) { | 312 | (dev->dev->bus->sprom.boardflags_lo & B43_BFL_PACTRL)) { |
342 | b43_phy_write(dev, B43_PHY_OFDM(0x6E), | 313 | b43_phy_maskset(dev, B43_PHY_OFDM(0x6E), 0xE000, 0x3CF); |
343 | (b43_phy_read(dev, B43_PHY_OFDM(0x6E)) | ||
344 | & 0xE000) | 0x3CF); | ||
345 | } | 314 | } |
346 | } | 315 | } |
347 | 316 | ||
@@ -520,14 +489,14 @@ static void b43_aphy_op_software_rfkill(struct b43_wldev *dev, | |||
520 | return; | 489 | return; |
521 | b43_radio_write16(dev, 0x0004, 0x00C0); | 490 | b43_radio_write16(dev, 0x0004, 0x00C0); |
522 | b43_radio_write16(dev, 0x0005, 0x0008); | 491 | b43_radio_write16(dev, 0x0005, 0x0008); |
523 | b43_phy_write(dev, 0x0010, b43_phy_read(dev, 0x0010) & 0xFFF7); | 492 | b43_phy_mask(dev, 0x0010, 0xFFF7); |
524 | b43_phy_write(dev, 0x0011, b43_phy_read(dev, 0x0011) & 0xFFF7); | 493 | b43_phy_mask(dev, 0x0011, 0xFFF7); |
525 | b43_radio_init2060(dev); | 494 | b43_radio_init2060(dev); |
526 | } else { | 495 | } else { |
527 | b43_radio_write16(dev, 0x0004, 0x00FF); | 496 | b43_radio_write16(dev, 0x0004, 0x00FF); |
528 | b43_radio_write16(dev, 0x0005, 0x00FB); | 497 | b43_radio_write16(dev, 0x0005, 0x00FB); |
529 | b43_phy_write(dev, 0x0010, b43_phy_read(dev, 0x0010) | 0x0008); | 498 | b43_phy_set(dev, 0x0010, 0x0008); |
530 | b43_phy_write(dev, 0x0011, b43_phy_read(dev, 0x0011) | 0x0008); | 499 | b43_phy_set(dev, 0x0011, 0x0008); |
531 | } | 500 | } |
532 | } | 501 | } |
533 | 502 | ||
diff --git a/drivers/net/wireless/b43/phy_g.c b/drivers/net/wireless/b43/phy_g.c index 88bb303ae9d5..e7b98f013b0f 100644 --- a/drivers/net/wireless/b43/phy_g.c +++ b/drivers/net/wireless/b43/phy_g.c | |||
@@ -204,13 +204,9 @@ void b43_gphy_set_baseband_attenuation(struct b43_wldev *dev, | |||
204 | & 0xFFF0) | | 204 | & 0xFFF0) | |
205 | baseband_attenuation); | 205 | baseband_attenuation); |
206 | } else if (phy->analog > 1) { | 206 | } else if (phy->analog > 1) { |
207 | b43_phy_write(dev, B43_PHY_DACCTL, | 207 | b43_phy_maskset(dev, B43_PHY_DACCTL, 0xFFC3, (baseband_attenuation << 2)); |
208 | (b43_phy_read(dev, B43_PHY_DACCTL) | ||
209 | & 0xFFC3) | (baseband_attenuation << 2)); | ||
210 | } else { | 208 | } else { |
211 | b43_phy_write(dev, B43_PHY_DACCTL, | 209 | b43_phy_maskset(dev, B43_PHY_DACCTL, 0xFF87, (baseband_attenuation << 3)); |
212 | (b43_phy_read(dev, B43_PHY_DACCTL) | ||
213 | & 0xFF87) | (baseband_attenuation << 3)); | ||
214 | } | 210 | } |
215 | } | 211 | } |
216 | 212 | ||
@@ -252,17 +248,13 @@ static void b43_set_txpower_g(struct b43_wldev *dev, | |||
252 | b43_radio_write16(dev, 0x43, | 248 | b43_radio_write16(dev, 0x43, |
253 | (rf & 0x000F) | (tx_control & 0x0070)); | 249 | (rf & 0x000F) | (tx_control & 0x0070)); |
254 | } else { | 250 | } else { |
255 | b43_radio_write16(dev, 0x43, (b43_radio_read16(dev, 0x43) | 251 | b43_radio_maskset(dev, 0x43, 0xFFF0, (rf & 0x000F)); |
256 | & 0xFFF0) | (rf & 0x000F)); | 252 | b43_radio_maskset(dev, 0x52, ~0x0070, (tx_control & 0x0070)); |
257 | b43_radio_write16(dev, 0x52, (b43_radio_read16(dev, 0x52) | ||
258 | & ~0x0070) | (tx_control & | ||
259 | 0x0070)); | ||
260 | } | 253 | } |
261 | if (has_tx_magnification(phy)) { | 254 | if (has_tx_magnification(phy)) { |
262 | b43_radio_write16(dev, 0x52, tx_magn | tx_bias); | 255 | b43_radio_write16(dev, 0x52, tx_magn | tx_bias); |
263 | } else { | 256 | } else { |
264 | b43_radio_write16(dev, 0x52, (b43_radio_read16(dev, 0x52) | 257 | b43_radio_maskset(dev, 0x52, 0xFFF0, (tx_bias & 0x000F)); |
265 | & 0xFFF0) | (tx_bias & 0x000F)); | ||
266 | } | 258 | } |
267 | b43_lo_g_adjust(dev); | 259 | b43_lo_g_adjust(dev); |
268 | } | 260 | } |
@@ -337,12 +329,9 @@ static void b43_set_all_gains(struct b43_wldev *dev, | |||
337 | 329 | ||
338 | if (third != -1) { | 330 | if (third != -1) { |
339 | tmp = ((u16) third << 14) | ((u16) third << 6); | 331 | tmp = ((u16) third << 14) | ((u16) third << 6); |
340 | b43_phy_write(dev, 0x04A0, | 332 | b43_phy_maskset(dev, 0x04A0, 0xBFBF, tmp); |
341 | (b43_phy_read(dev, 0x04A0) & 0xBFBF) | tmp); | 333 | b43_phy_maskset(dev, 0x04A1, 0xBFBF, tmp); |
342 | b43_phy_write(dev, 0x04A1, | 334 | b43_phy_maskset(dev, 0x04A2, 0xBFBF, tmp); |
343 | (b43_phy_read(dev, 0x04A1) & 0xBFBF) | tmp); | ||
344 | b43_phy_write(dev, 0x04A2, | ||
345 | (b43_phy_read(dev, 0x04A2) & 0xBFBF) | tmp); | ||
346 | } | 335 | } |
347 | b43_dummy_transmission(dev); | 336 | b43_dummy_transmission(dev); |
348 | } | 337 | } |
@@ -373,12 +362,9 @@ static void b43_set_original_gains(struct b43_wldev *dev) | |||
373 | for (i = start; i < end; i++) | 362 | for (i = start; i < end; i++) |
374 | b43_ofdmtab_write16(dev, table, i, i - start); | 363 | b43_ofdmtab_write16(dev, table, i, i - start); |
375 | 364 | ||
376 | b43_phy_write(dev, 0x04A0, | 365 | b43_phy_maskset(dev, 0x04A0, 0xBFBF, 0x4040); |
377 | (b43_phy_read(dev, 0x04A0) & 0xBFBF) | 0x4040); | 366 | b43_phy_maskset(dev, 0x04A1, 0xBFBF, 0x4040); |
378 | b43_phy_write(dev, 0x04A1, | 367 | b43_phy_maskset(dev, 0x04A2, 0xBFBF, 0x4000); |
379 | (b43_phy_read(dev, 0x04A1) & 0xBFBF) | 0x4040); | ||
380 | b43_phy_write(dev, 0x04A2, | ||
381 | (b43_phy_read(dev, 0x04A2) & 0xBFBF) | 0x4000); | ||
382 | b43_dummy_transmission(dev); | 368 | b43_dummy_transmission(dev); |
383 | } | 369 | } |
384 | 370 | ||
@@ -454,13 +440,11 @@ static void b43_calc_nrssi_offset(struct b43_wldev *dev) | |||
454 | backup[10] = b43_radio_read16(dev, 0x007A); | 440 | backup[10] = b43_radio_read16(dev, 0x007A); |
455 | backup[11] = b43_radio_read16(dev, 0x0043); | 441 | backup[11] = b43_radio_read16(dev, 0x0043); |
456 | 442 | ||
457 | b43_phy_write(dev, 0x0429, b43_phy_read(dev, 0x0429) & 0x7FFF); | 443 | b43_phy_mask(dev, 0x0429, 0x7FFF); |
458 | b43_phy_write(dev, 0x0001, | 444 | b43_phy_maskset(dev, 0x0001, 0x3FFF, 0x4000); |
459 | (b43_phy_read(dev, 0x0001) & 0x3FFF) | 0x4000); | 445 | b43_phy_set(dev, 0x0811, 0x000C); |
460 | b43_phy_write(dev, 0x0811, b43_phy_read(dev, 0x0811) | 0x000C); | 446 | b43_phy_maskset(dev, 0x0812, 0xFFF3, 0x0004); |
461 | b43_phy_write(dev, 0x0812, | 447 | b43_phy_mask(dev, 0x0802, ~(0x1 | 0x2)); |
462 | (b43_phy_read(dev, 0x0812) & 0xFFF3) | 0x0004); | ||
463 | b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) & ~(0x1 | 0x2)); | ||
464 | if (phy->rev >= 6) { | 448 | if (phy->rev >= 6) { |
465 | backup[12] = b43_phy_read(dev, 0x002E); | 449 | backup[12] = b43_phy_read(dev, 0x002E); |
466 | backup[13] = b43_phy_read(dev, 0x002F); | 450 | backup[13] = b43_phy_read(dev, 0x002F); |
@@ -475,13 +459,13 @@ static void b43_calc_nrssi_offset(struct b43_wldev *dev) | |||
475 | b43_phy_write(dev, 0x002F, 0); | 459 | b43_phy_write(dev, 0x002F, 0); |
476 | b43_phy_write(dev, 0x080F, 0); | 460 | b43_phy_write(dev, 0x080F, 0); |
477 | b43_phy_write(dev, 0x0810, 0); | 461 | b43_phy_write(dev, 0x0810, 0); |
478 | b43_phy_write(dev, 0x0478, b43_phy_read(dev, 0x0478) | 0x0100); | 462 | b43_phy_set(dev, 0x0478, 0x0100); |
479 | b43_phy_write(dev, 0x0801, b43_phy_read(dev, 0x0801) | 0x0040); | 463 | b43_phy_set(dev, 0x0801, 0x0040); |
480 | b43_phy_write(dev, 0x0060, b43_phy_read(dev, 0x0060) | 0x0040); | 464 | b43_phy_set(dev, 0x0060, 0x0040); |
481 | b43_phy_write(dev, 0x0014, b43_phy_read(dev, 0x0014) | 0x0200); | 465 | b43_phy_set(dev, 0x0014, 0x0200); |
482 | } | 466 | } |
483 | b43_radio_write16(dev, 0x007A, b43_radio_read16(dev, 0x007A) | 0x0070); | 467 | b43_radio_set(dev, 0x007A, 0x0070); |
484 | b43_radio_write16(dev, 0x007A, b43_radio_read16(dev, 0x007A) | 0x0080); | 468 | b43_radio_set(dev, 0x007A, 0x0080); |
485 | udelay(30); | 469 | udelay(30); |
486 | 470 | ||
487 | v47F = (s16) ((b43_phy_read(dev, 0x047F) >> 8) & 0x003F); | 471 | v47F = (s16) ((b43_phy_read(dev, 0x047F) >> 8) & 0x003F); |
@@ -501,40 +485,31 @@ static void b43_calc_nrssi_offset(struct b43_wldev *dev) | |||
501 | if (saved == 0xFFFF) | 485 | if (saved == 0xFFFF) |
502 | saved = 4; | 486 | saved = 4; |
503 | } else { | 487 | } else { |
504 | b43_radio_write16(dev, 0x007A, | 488 | b43_radio_mask(dev, 0x007A, 0x007F); |
505 | b43_radio_read16(dev, 0x007A) & 0x007F); | ||
506 | if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */ | 489 | if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */ |
507 | b43_phy_write(dev, 0x0814, | 490 | b43_phy_set(dev, 0x0814, 0x0001); |
508 | b43_phy_read(dev, 0x0814) | 0x0001); | 491 | b43_phy_mask(dev, 0x0815, 0xFFFE); |
509 | b43_phy_write(dev, 0x0815, | ||
510 | b43_phy_read(dev, 0x0815) & 0xFFFE); | ||
511 | } | 492 | } |
512 | b43_phy_write(dev, 0x0811, b43_phy_read(dev, 0x0811) | 0x000C); | 493 | b43_phy_set(dev, 0x0811, 0x000C); |
513 | b43_phy_write(dev, 0x0812, b43_phy_read(dev, 0x0812) | 0x000C); | 494 | b43_phy_set(dev, 0x0812, 0x000C); |
514 | b43_phy_write(dev, 0x0811, b43_phy_read(dev, 0x0811) | 0x0030); | 495 | b43_phy_set(dev, 0x0811, 0x0030); |
515 | b43_phy_write(dev, 0x0812, b43_phy_read(dev, 0x0812) | 0x0030); | 496 | b43_phy_set(dev, 0x0812, 0x0030); |
516 | b43_phy_write(dev, 0x005A, 0x0480); | 497 | b43_phy_write(dev, 0x005A, 0x0480); |
517 | b43_phy_write(dev, 0x0059, 0x0810); | 498 | b43_phy_write(dev, 0x0059, 0x0810); |
518 | b43_phy_write(dev, 0x0058, 0x000D); | 499 | b43_phy_write(dev, 0x0058, 0x000D); |
519 | if (phy->rev == 0) { | 500 | if (phy->rev == 0) { |
520 | b43_phy_write(dev, 0x0003, 0x0122); | 501 | b43_phy_write(dev, 0x0003, 0x0122); |
521 | } else { | 502 | } else { |
522 | b43_phy_write(dev, 0x000A, b43_phy_read(dev, 0x000A) | 503 | b43_phy_set(dev, 0x000A, 0x2000); |
523 | | 0x2000); | ||
524 | } | 504 | } |
525 | if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */ | 505 | if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */ |
526 | b43_phy_write(dev, 0x0814, | 506 | b43_phy_set(dev, 0x0814, 0x0004); |
527 | b43_phy_read(dev, 0x0814) | 0x0004); | 507 | b43_phy_mask(dev, 0x0815, 0xFFFB); |
528 | b43_phy_write(dev, 0x0815, | ||
529 | b43_phy_read(dev, 0x0815) & 0xFFFB); | ||
530 | } | 508 | } |
531 | b43_phy_write(dev, 0x0003, (b43_phy_read(dev, 0x0003) & 0xFF9F) | 509 | b43_phy_maskset(dev, 0x0003, 0xFF9F, 0x0040); |
532 | | 0x0040); | 510 | b43_radio_set(dev, 0x007A, 0x000F); |
533 | b43_radio_write16(dev, 0x007A, | ||
534 | b43_radio_read16(dev, 0x007A) | 0x000F); | ||
535 | b43_set_all_gains(dev, 3, 0, 1); | 511 | b43_set_all_gains(dev, 3, 0, 1); |
536 | b43_radio_write16(dev, 0x0043, (b43_radio_read16(dev, 0x0043) | 512 | b43_radio_maskset(dev, 0x0043, 0x00F0, 0x000F); |
537 | & 0x00F0) | 0x000F); | ||
538 | udelay(30); | 513 | udelay(30); |
539 | v47F = (s16) ((b43_phy_read(dev, 0x047F) >> 8) & 0x003F); | 514 | v47F = (s16) ((b43_phy_read(dev, 0x047F) >> 8) & 0x003F); |
540 | if (v47F >= 0x20) | 515 | if (v47F >= 0x20) |
@@ -576,7 +551,7 @@ static void b43_calc_nrssi_offset(struct b43_wldev *dev) | |||
576 | b43_radio_write16(dev, 0x0043, backup[11]); | 551 | b43_radio_write16(dev, 0x0043, backup[11]); |
577 | b43_radio_write16(dev, 0x007A, backup[10]); | 552 | b43_radio_write16(dev, 0x007A, backup[10]); |
578 | b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) | 0x1 | 0x2); | 553 | b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) | 0x1 | 0x2); |
579 | b43_phy_write(dev, 0x0429, b43_phy_read(dev, 0x0429) | 0x8000); | 554 | b43_phy_set(dev, 0x0429, 0x8000); |
580 | b43_set_original_gains(dev); | 555 | b43_set_original_gains(dev); |
581 | if (phy->rev >= 6) { | 556 | if (phy->rev >= 6) { |
582 | b43_phy_write(dev, 0x0801, backup[16]); | 557 | b43_phy_write(dev, 0x0801, backup[16]); |
@@ -604,9 +579,8 @@ static void b43_calc_nrssi_slope(struct b43_wldev *dev) | |||
604 | if (phy->radio_rev == 8) | 579 | if (phy->radio_rev == 8) |
605 | b43_calc_nrssi_offset(dev); | 580 | b43_calc_nrssi_offset(dev); |
606 | 581 | ||
607 | b43_phy_write(dev, B43_PHY_G_CRS, | 582 | b43_phy_mask(dev, B43_PHY_G_CRS, 0x7FFF); |
608 | b43_phy_read(dev, B43_PHY_G_CRS) & 0x7FFF); | 583 | b43_phy_mask(dev, 0x0802, 0xFFFC); |
609 | b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) & 0xFFFC); | ||
610 | backup[7] = b43_read16(dev, 0x03E2); | 584 | backup[7] = b43_read16(dev, 0x03E2); |
611 | b43_write16(dev, 0x03E2, b43_read16(dev, 0x03E2) | 0x8000); | 585 | b43_write16(dev, 0x03E2, b43_read16(dev, 0x03E2) | 0x8000); |
612 | backup[0] = b43_radio_read16(dev, 0x007A); | 586 | backup[0] = b43_radio_read16(dev, 0x007A); |
@@ -633,66 +607,44 @@ static void b43_calc_nrssi_slope(struct b43_wldev *dev) | |||
633 | case 4: | 607 | case 4: |
634 | case 6: | 608 | case 6: |
635 | case 7: | 609 | case 7: |
636 | b43_phy_write(dev, 0x0478, | 610 | b43_phy_set(dev, 0x0478, 0x0100); |
637 | b43_phy_read(dev, 0x0478) | 611 | b43_phy_set(dev, 0x0801, 0x0040); |
638 | | 0x0100); | ||
639 | b43_phy_write(dev, 0x0801, | ||
640 | b43_phy_read(dev, 0x0801) | ||
641 | | 0x0040); | ||
642 | break; | 612 | break; |
643 | case 3: | 613 | case 3: |
644 | case 5: | 614 | case 5: |
645 | b43_phy_write(dev, 0x0801, | 615 | b43_phy_mask(dev, 0x0801, 0xFFBF); |
646 | b43_phy_read(dev, 0x0801) | ||
647 | & 0xFFBF); | ||
648 | break; | 616 | break; |
649 | } | 617 | } |
650 | b43_phy_write(dev, 0x0060, b43_phy_read(dev, 0x0060) | 618 | b43_phy_set(dev, 0x0060, 0x0040); |
651 | | 0x0040); | 619 | b43_phy_set(dev, 0x0014, 0x0200); |
652 | b43_phy_write(dev, 0x0014, b43_phy_read(dev, 0x0014) | ||
653 | | 0x0200); | ||
654 | } | 620 | } |
655 | b43_radio_write16(dev, 0x007A, | 621 | b43_radio_set(dev, 0x007A, 0x0070); |
656 | b43_radio_read16(dev, 0x007A) | 0x0070); | ||
657 | b43_set_all_gains(dev, 0, 8, 0); | 622 | b43_set_all_gains(dev, 0, 8, 0); |
658 | b43_radio_write16(dev, 0x007A, | 623 | b43_radio_mask(dev, 0x007A, 0x00F7); |
659 | b43_radio_read16(dev, 0x007A) & 0x00F7); | ||
660 | if (phy->rev >= 2) { | 624 | if (phy->rev >= 2) { |
661 | b43_phy_write(dev, 0x0811, | 625 | b43_phy_maskset(dev, 0x0811, 0xFFCF, 0x0030); |
662 | (b43_phy_read(dev, 0x0811) & 0xFFCF) | | 626 | b43_phy_maskset(dev, 0x0812, 0xFFCF, 0x0010); |
663 | 0x0030); | ||
664 | b43_phy_write(dev, 0x0812, | ||
665 | (b43_phy_read(dev, 0x0812) & 0xFFCF) | | ||
666 | 0x0010); | ||
667 | } | 627 | } |
668 | b43_radio_write16(dev, 0x007A, | 628 | b43_radio_set(dev, 0x007A, 0x0080); |
669 | b43_radio_read16(dev, 0x007A) | 0x0080); | ||
670 | udelay(20); | 629 | udelay(20); |
671 | 630 | ||
672 | nrssi0 = (s16) ((b43_phy_read(dev, 0x047F) >> 8) & 0x003F); | 631 | nrssi0 = (s16) ((b43_phy_read(dev, 0x047F) >> 8) & 0x003F); |
673 | if (nrssi0 >= 0x0020) | 632 | if (nrssi0 >= 0x0020) |
674 | nrssi0 -= 0x0040; | 633 | nrssi0 -= 0x0040; |
675 | 634 | ||
676 | b43_radio_write16(dev, 0x007A, | 635 | b43_radio_mask(dev, 0x007A, 0x007F); |
677 | b43_radio_read16(dev, 0x007A) & 0x007F); | ||
678 | if (phy->rev >= 2) { | 636 | if (phy->rev >= 2) { |
679 | b43_phy_write(dev, 0x0003, (b43_phy_read(dev, 0x0003) | 637 | b43_phy_maskset(dev, 0x0003, 0xFF9F, 0x0040); |
680 | & 0xFF9F) | 0x0040); | ||
681 | } | 638 | } |
682 | 639 | ||
683 | b43_write16(dev, B43_MMIO_CHANNEL_EXT, | 640 | b43_write16(dev, B43_MMIO_CHANNEL_EXT, |
684 | b43_read16(dev, B43_MMIO_CHANNEL_EXT) | 641 | b43_read16(dev, B43_MMIO_CHANNEL_EXT) |
685 | | 0x2000); | 642 | | 0x2000); |
686 | b43_radio_write16(dev, 0x007A, | 643 | b43_radio_set(dev, 0x007A, 0x000F); |
687 | b43_radio_read16(dev, 0x007A) | 0x000F); | ||
688 | b43_phy_write(dev, 0x0015, 0xF330); | 644 | b43_phy_write(dev, 0x0015, 0xF330); |
689 | if (phy->rev >= 2) { | 645 | if (phy->rev >= 2) { |
690 | b43_phy_write(dev, 0x0812, | 646 | b43_phy_maskset(dev, 0x0812, 0xFFCF, 0x0020); |
691 | (b43_phy_read(dev, 0x0812) & 0xFFCF) | | 647 | b43_phy_maskset(dev, 0x0811, 0xFFCF, 0x0020); |
692 | 0x0020); | ||
693 | b43_phy_write(dev, 0x0811, | ||
694 | (b43_phy_read(dev, 0x0811) & 0xFFCF) | | ||
695 | 0x0020); | ||
696 | } | 648 | } |
697 | 649 | ||
698 | b43_set_all_gains(dev, 3, 0, 1); | 650 | b43_set_all_gains(dev, 3, 0, 1); |
@@ -726,10 +678,8 @@ static void b43_calc_nrssi_slope(struct b43_wldev *dev) | |||
726 | b43_phy_write(dev, B43_PHY_G_LO_CONTROL, backup[13]); | 678 | b43_phy_write(dev, B43_PHY_G_LO_CONTROL, backup[13]); |
727 | } | 679 | } |
728 | if (phy->rev >= 2) { | 680 | if (phy->rev >= 2) { |
729 | b43_phy_write(dev, 0x0812, | 681 | b43_phy_mask(dev, 0x0812, 0xFFCF); |
730 | b43_phy_read(dev, 0x0812) & 0xFFCF); | 682 | b43_phy_mask(dev, 0x0811, 0xFFCF); |
731 | b43_phy_write(dev, 0x0811, | ||
732 | b43_phy_read(dev, 0x0811) & 0xFFCF); | ||
733 | } | 683 | } |
734 | 684 | ||
735 | b43_radio_write16(dev, 0x007A, backup[0]); | 685 | b43_radio_write16(dev, 0x007A, backup[0]); |
@@ -743,11 +693,9 @@ static void b43_calc_nrssi_slope(struct b43_wldev *dev) | |||
743 | b43_phy_write(dev, 0x0059, backup[5]); | 693 | b43_phy_write(dev, 0x0059, backup[5]); |
744 | b43_phy_write(dev, 0x0058, backup[6]); | 694 | b43_phy_write(dev, 0x0058, backup[6]); |
745 | b43_synth_pu_workaround(dev, phy->channel); | 695 | b43_synth_pu_workaround(dev, phy->channel); |
746 | b43_phy_write(dev, 0x0802, | 696 | b43_phy_set(dev, 0x0802, (0x0001 | 0x0002)); |
747 | b43_phy_read(dev, 0x0802) | (0x0001 | 0x0002)); | ||
748 | b43_set_original_gains(dev); | 697 | b43_set_original_gains(dev); |
749 | b43_phy_write(dev, B43_PHY_G_CRS, | 698 | b43_phy_set(dev, B43_PHY_G_CRS, 0x8000); |
750 | b43_phy_read(dev, B43_PHY_G_CRS) | 0x8000); | ||
751 | if (phy->rev >= 3) { | 699 | if (phy->rev >= 3) { |
752 | b43_phy_write(dev, 0x0801, backup[14]); | 700 | b43_phy_write(dev, 0x0801, backup[14]); |
753 | b43_phy_write(dev, 0x0060, backup[15]); | 701 | b43_phy_write(dev, 0x0060, backup[15]); |
@@ -774,13 +722,9 @@ static void b43_calc_nrssi_threshold(struct b43_wldev *dev) | |||
774 | if (tmp16 >= 0x20) | 722 | if (tmp16 >= 0x20) |
775 | tmp16 -= 0x40; | 723 | tmp16 -= 0x40; |
776 | if (tmp16 < 3) { | 724 | if (tmp16 < 3) { |
777 | b43_phy_write(dev, 0x048A, | 725 | b43_phy_maskset(dev, 0x048A, 0xF000, 0x09EB); |
778 | (b43_phy_read(dev, 0x048A) | ||
779 | & 0xF000) | 0x09EB); | ||
780 | } else { | 726 | } else { |
781 | b43_phy_write(dev, 0x048A, | 727 | b43_phy_maskset(dev, 0x048A, 0xF000, 0x0AED); |
782 | (b43_phy_read(dev, 0x048A) | ||
783 | & 0xF000) | 0x0AED); | ||
784 | } | 728 | } |
785 | } else { | 729 | } else { |
786 | if (gphy->interfmode == B43_INTERFMODE_NONWLAN) { | 730 | if (gphy->interfmode == B43_INTERFMODE_NONWLAN) { |
@@ -823,7 +767,7 @@ static void b43_calc_nrssi_threshold(struct b43_wldev *dev) | |||
823 | * interference mitigation code. | 767 | * interference mitigation code. |
824 | * It is save to restore values in random order. | 768 | * It is save to restore values in random order. |
825 | */ | 769 | */ |
826 | static void _stack_save(u32 * _stackptr, size_t * stackidx, | 770 | static void _stack_save(u32 *_stackptr, size_t *stackidx, |
827 | u8 id, u16 offset, u16 value) | 771 | u8 id, u16 offset, u16 value) |
828 | { | 772 | { |
829 | u32 *stackptr = &(_stackptr[*stackidx]); | 773 | u32 *stackptr = &(_stackptr[*stackidx]); |
@@ -837,7 +781,7 @@ static void _stack_save(u32 * _stackptr, size_t * stackidx, | |||
837 | B43_WARN_ON(*stackidx >= B43_INTERFSTACK_SIZE); | 781 | B43_WARN_ON(*stackidx >= B43_INTERFSTACK_SIZE); |
838 | } | 782 | } |
839 | 783 | ||
840 | static u16 _stack_restore(u32 * stackptr, u8 id, u16 offset) | 784 | static u16 _stack_restore(u32 *stackptr, u8 id, u16 offset) |
841 | { | 785 | { |
842 | size_t i; | 786 | size_t i; |
843 | 787 | ||
@@ -901,11 +845,8 @@ b43_radio_interference_mitigation_enable(struct b43_wldev *dev, int mode) | |||
901 | switch (mode) { | 845 | switch (mode) { |
902 | case B43_INTERFMODE_NONWLAN: | 846 | case B43_INTERFMODE_NONWLAN: |
903 | if (phy->rev != 1) { | 847 | if (phy->rev != 1) { |
904 | b43_phy_write(dev, 0x042B, | 848 | b43_phy_set(dev, 0x042B, 0x0800); |
905 | b43_phy_read(dev, 0x042B) | 0x0800); | 849 | b43_phy_mask(dev, B43_PHY_G_CRS, ~0x4000); |
906 | b43_phy_write(dev, B43_PHY_G_CRS, | ||
907 | b43_phy_read(dev, | ||
908 | B43_PHY_G_CRS) & ~0x4000); | ||
909 | break; | 850 | break; |
910 | } | 851 | } |
911 | radio_stacksave(0x0078); | 852 | radio_stacksave(0x0078); |
@@ -924,26 +865,19 @@ b43_radio_interference_mitigation_enable(struct b43_wldev *dev, int mode) | |||
924 | phy_stacksave(0x0406); | 865 | phy_stacksave(0x0406); |
925 | b43_phy_write(dev, 0x0406, 0x7E28); | 866 | b43_phy_write(dev, 0x0406, 0x7E28); |
926 | 867 | ||
927 | b43_phy_write(dev, 0x042B, b43_phy_read(dev, 0x042B) | 0x0800); | 868 | b43_phy_set(dev, 0x042B, 0x0800); |
928 | b43_phy_write(dev, B43_PHY_RADIO_BITFIELD, | 869 | b43_phy_set(dev, B43_PHY_RADIO_BITFIELD, 0x1000); |
929 | b43_phy_read(dev, | ||
930 | B43_PHY_RADIO_BITFIELD) | 0x1000); | ||
931 | 870 | ||
932 | phy_stacksave(0x04A0); | 871 | phy_stacksave(0x04A0); |
933 | b43_phy_write(dev, 0x04A0, | 872 | b43_phy_maskset(dev, 0x04A0, 0xC0C0, 0x0008); |
934 | (b43_phy_read(dev, 0x04A0) & 0xC0C0) | 0x0008); | ||
935 | phy_stacksave(0x04A1); | 873 | phy_stacksave(0x04A1); |
936 | b43_phy_write(dev, 0x04A1, | 874 | b43_phy_maskset(dev, 0x04A1, 0xC0C0, 0x0605); |
937 | (b43_phy_read(dev, 0x04A1) & 0xC0C0) | 0x0605); | ||
938 | phy_stacksave(0x04A2); | 875 | phy_stacksave(0x04A2); |
939 | b43_phy_write(dev, 0x04A2, | 876 | b43_phy_maskset(dev, 0x04A2, 0xC0C0, 0x0204); |
940 | (b43_phy_read(dev, 0x04A2) & 0xC0C0) | 0x0204); | ||
941 | phy_stacksave(0x04A8); | 877 | phy_stacksave(0x04A8); |
942 | b43_phy_write(dev, 0x04A8, | 878 | b43_phy_maskset(dev, 0x04A8, 0xC0C0, 0x0803); |
943 | (b43_phy_read(dev, 0x04A8) & 0xC0C0) | 0x0803); | ||
944 | phy_stacksave(0x04AB); | 879 | phy_stacksave(0x04AB); |
945 | b43_phy_write(dev, 0x04AB, | 880 | b43_phy_maskset(dev, 0x04AB, 0xC0C0, 0x0605); |
946 | (b43_phy_read(dev, 0x04AB) & 0xC0C0) | 0x0605); | ||
947 | 881 | ||
948 | phy_stacksave(0x04A7); | 882 | phy_stacksave(0x04A7); |
949 | b43_phy_write(dev, 0x04A7, 0x0002); | 883 | b43_phy_write(dev, 0x04A7, 0x0002); |
@@ -999,12 +933,8 @@ b43_radio_interference_mitigation_enable(struct b43_wldev *dev, int mode) | |||
999 | phy_stacksave(0x042B); | 933 | phy_stacksave(0x042B); |
1000 | phy_stacksave(0x048C); | 934 | phy_stacksave(0x048C); |
1001 | 935 | ||
1002 | b43_phy_write(dev, B43_PHY_RADIO_BITFIELD, | 936 | b43_phy_mask(dev, B43_PHY_RADIO_BITFIELD, ~0x1000); |
1003 | b43_phy_read(dev, B43_PHY_RADIO_BITFIELD) | 937 | b43_phy_maskset(dev, B43_PHY_G_CRS, 0xFFFC, 0x0002); |
1004 | & ~0x1000); | ||
1005 | b43_phy_write(dev, B43_PHY_G_CRS, | ||
1006 | (b43_phy_read(dev, B43_PHY_G_CRS) | ||
1007 | & 0xFFFC) | 0x0002); | ||
1008 | 938 | ||
1009 | b43_phy_write(dev, 0x0033, 0x0800); | 939 | b43_phy_write(dev, 0x0033, 0x0800); |
1010 | b43_phy_write(dev, 0x04A3, 0x2027); | 940 | b43_phy_write(dev, 0x04A3, 0x2027); |
@@ -1013,8 +943,7 @@ b43_radio_interference_mitigation_enable(struct b43_wldev *dev, int mode) | |||
1013 | b43_phy_write(dev, 0x04AA, 0x1CA8); | 943 | b43_phy_write(dev, 0x04AA, 0x1CA8); |
1014 | b43_phy_write(dev, 0x04AC, 0x287A); | 944 | b43_phy_write(dev, 0x04AC, 0x287A); |
1015 | 945 | ||
1016 | b43_phy_write(dev, 0x04A0, (b43_phy_read(dev, 0x04A0) | 946 | b43_phy_maskset(dev, 0x04A0, 0xFFC0, 0x001A); |
1017 | & 0xFFC0) | 0x001A); | ||
1018 | b43_phy_write(dev, 0x04A7, 0x000D); | 947 | b43_phy_write(dev, 0x04A7, 0x000D); |
1019 | 948 | ||
1020 | if (phy->rev < 2) { | 949 | if (phy->rev < 2) { |
@@ -1027,65 +956,41 @@ b43_radio_interference_mitigation_enable(struct b43_wldev *dev, int mode) | |||
1027 | b43_phy_write(dev, 0x04C1, 0x0059); | 956 | b43_phy_write(dev, 0x04C1, 0x0059); |
1028 | } | 957 | } |
1029 | 958 | ||
1030 | b43_phy_write(dev, 0x04A1, (b43_phy_read(dev, 0x04A1) | 959 | b43_phy_maskset(dev, 0x04A1, 0xC0FF, 0x1800); |
1031 | & 0xC0FF) | 0x1800); | 960 | b43_phy_maskset(dev, 0x04A1, 0xFFC0, 0x0015); |
1032 | b43_phy_write(dev, 0x04A1, (b43_phy_read(dev, 0x04A1) | 961 | b43_phy_maskset(dev, 0x04A8, 0xCFFF, 0x1000); |
1033 | & 0xFFC0) | 0x0015); | 962 | b43_phy_maskset(dev, 0x04A8, 0xF0FF, 0x0A00); |
1034 | b43_phy_write(dev, 0x04A8, (b43_phy_read(dev, 0x04A8) | 963 | b43_phy_maskset(dev, 0x04AB, 0xCFFF, 0x1000); |
1035 | & 0xCFFF) | 0x1000); | 964 | b43_phy_maskset(dev, 0x04AB, 0xF0FF, 0x0800); |
1036 | b43_phy_write(dev, 0x04A8, (b43_phy_read(dev, 0x04A8) | 965 | b43_phy_maskset(dev, 0x04AB, 0xFFCF, 0x0010); |
1037 | & 0xF0FF) | 0x0A00); | 966 | b43_phy_maskset(dev, 0x04AB, 0xFFF0, 0x0005); |
1038 | b43_phy_write(dev, 0x04AB, (b43_phy_read(dev, 0x04AB) | 967 | b43_phy_maskset(dev, 0x04A8, 0xFFCF, 0x0010); |
1039 | & 0xCFFF) | 0x1000); | 968 | b43_phy_maskset(dev, 0x04A8, 0xFFF0, 0x0006); |
1040 | b43_phy_write(dev, 0x04AB, (b43_phy_read(dev, 0x04AB) | 969 | b43_phy_maskset(dev, 0x04A2, 0xF0FF, 0x0800); |
1041 | & 0xF0FF) | 0x0800); | 970 | b43_phy_maskset(dev, 0x04A0, 0xF0FF, 0x0500); |
1042 | b43_phy_write(dev, 0x04AB, (b43_phy_read(dev, 0x04AB) | 971 | b43_phy_maskset(dev, 0x04A2, 0xFFF0, 0x000B); |
1043 | & 0xFFCF) | 0x0010); | ||
1044 | b43_phy_write(dev, 0x04AB, (b43_phy_read(dev, 0x04AB) | ||
1045 | & 0xFFF0) | 0x0005); | ||
1046 | b43_phy_write(dev, 0x04A8, (b43_phy_read(dev, 0x04A8) | ||
1047 | & 0xFFCF) | 0x0010); | ||
1048 | b43_phy_write(dev, 0x04A8, (b43_phy_read(dev, 0x04A8) | ||
1049 | & 0xFFF0) | 0x0006); | ||
1050 | b43_phy_write(dev, 0x04A2, (b43_phy_read(dev, 0x04A2) | ||
1051 | & 0xF0FF) | 0x0800); | ||
1052 | b43_phy_write(dev, 0x04A0, (b43_phy_read(dev, 0x04A0) | ||
1053 | & 0xF0FF) | 0x0500); | ||
1054 | b43_phy_write(dev, 0x04A2, (b43_phy_read(dev, 0x04A2) | ||
1055 | & 0xFFF0) | 0x000B); | ||
1056 | 972 | ||
1057 | if (phy->rev >= 3) { | 973 | if (phy->rev >= 3) { |
1058 | b43_phy_write(dev, 0x048A, b43_phy_read(dev, 0x048A) | 974 | b43_phy_mask(dev, 0x048A, (u16)~0x8000); |
1059 | & ~0x8000); | 975 | b43_phy_maskset(dev, 0x0415, 0x8000, 0x36D8); |
1060 | b43_phy_write(dev, 0x0415, (b43_phy_read(dev, 0x0415) | 976 | b43_phy_maskset(dev, 0x0416, 0x8000, 0x36D8); |
1061 | & 0x8000) | 0x36D8); | 977 | b43_phy_maskset(dev, 0x0417, 0xFE00, 0x016D); |
1062 | b43_phy_write(dev, 0x0416, (b43_phy_read(dev, 0x0416) | ||
1063 | & 0x8000) | 0x36D8); | ||
1064 | b43_phy_write(dev, 0x0417, (b43_phy_read(dev, 0x0417) | ||
1065 | & 0xFE00) | 0x016D); | ||
1066 | } else { | 978 | } else { |
1067 | b43_phy_write(dev, 0x048A, b43_phy_read(dev, 0x048A) | 979 | b43_phy_set(dev, 0x048A, 0x1000); |
1068 | | 0x1000); | 980 | b43_phy_maskset(dev, 0x048A, 0x9FFF, 0x2000); |
1069 | b43_phy_write(dev, 0x048A, (b43_phy_read(dev, 0x048A) | ||
1070 | & 0x9FFF) | 0x2000); | ||
1071 | b43_hf_write(dev, b43_hf_read(dev) | B43_HF_ACIW); | 981 | b43_hf_write(dev, b43_hf_read(dev) | B43_HF_ACIW); |
1072 | } | 982 | } |
1073 | if (phy->rev >= 2) { | 983 | if (phy->rev >= 2) { |
1074 | b43_phy_write(dev, 0x042B, b43_phy_read(dev, 0x042B) | 984 | b43_phy_set(dev, 0x042B, 0x0800); |
1075 | | 0x0800); | ||
1076 | } | 985 | } |
1077 | b43_phy_write(dev, 0x048C, (b43_phy_read(dev, 0x048C) | 986 | b43_phy_maskset(dev, 0x048C, 0xF0FF, 0x0200); |
1078 | & 0xF0FF) | 0x0200); | ||
1079 | if (phy->rev == 2) { | 987 | if (phy->rev == 2) { |
1080 | b43_phy_write(dev, 0x04AE, (b43_phy_read(dev, 0x04AE) | 988 | b43_phy_maskset(dev, 0x04AE, 0xFF00, 0x007F); |
1081 | & 0xFF00) | 0x007F); | 989 | b43_phy_maskset(dev, 0x04AD, 0x00FF, 0x1300); |
1082 | b43_phy_write(dev, 0x04AD, (b43_phy_read(dev, 0x04AD) | ||
1083 | & 0x00FF) | 0x1300); | ||
1084 | } else if (phy->rev >= 6) { | 990 | } else if (phy->rev >= 6) { |
1085 | b43_ofdmtab_write16(dev, 0x1A00, 0x3, 0x007F); | 991 | b43_ofdmtab_write16(dev, 0x1A00, 0x3, 0x007F); |
1086 | b43_ofdmtab_write16(dev, 0x1A00, 0x2, 0x007F); | 992 | b43_ofdmtab_write16(dev, 0x1A00, 0x2, 0x007F); |
1087 | b43_phy_write(dev, 0x04AD, b43_phy_read(dev, 0x04AD) | 993 | b43_phy_mask(dev, 0x04AD, 0x00FF); |
1088 | & 0x00FF); | ||
1089 | } | 994 | } |
1090 | b43_calc_nrssi_slope(dev); | 995 | b43_calc_nrssi_slope(dev); |
1091 | break; | 996 | break; |
@@ -1104,24 +1009,18 @@ b43_radio_interference_mitigation_disable(struct b43_wldev *dev, int mode) | |||
1104 | switch (mode) { | 1009 | switch (mode) { |
1105 | case B43_INTERFMODE_NONWLAN: | 1010 | case B43_INTERFMODE_NONWLAN: |
1106 | if (phy->rev != 1) { | 1011 | if (phy->rev != 1) { |
1107 | b43_phy_write(dev, 0x042B, | 1012 | b43_phy_mask(dev, 0x042B, ~0x0800); |
1108 | b43_phy_read(dev, 0x042B) & ~0x0800); | 1013 | b43_phy_set(dev, B43_PHY_G_CRS, 0x4000); |
1109 | b43_phy_write(dev, B43_PHY_G_CRS, | ||
1110 | b43_phy_read(dev, | ||
1111 | B43_PHY_G_CRS) | 0x4000); | ||
1112 | break; | 1014 | break; |
1113 | } | 1015 | } |
1114 | radio_stackrestore(0x0078); | 1016 | radio_stackrestore(0x0078); |
1115 | b43_calc_nrssi_threshold(dev); | 1017 | b43_calc_nrssi_threshold(dev); |
1116 | phy_stackrestore(0x0406); | 1018 | phy_stackrestore(0x0406); |
1117 | b43_phy_write(dev, 0x042B, b43_phy_read(dev, 0x042B) & ~0x0800); | 1019 | b43_phy_mask(dev, 0x042B, ~0x0800); |
1118 | if (!dev->bad_frames_preempt) { | 1020 | if (!dev->bad_frames_preempt) { |
1119 | b43_phy_write(dev, B43_PHY_RADIO_BITFIELD, | 1021 | b43_phy_mask(dev, B43_PHY_RADIO_BITFIELD, ~(1 << 11)); |
1120 | b43_phy_read(dev, B43_PHY_RADIO_BITFIELD) | ||
1121 | & ~(1 << 11)); | ||
1122 | } | 1022 | } |
1123 | b43_phy_write(dev, B43_PHY_G_CRS, | 1023 | b43_phy_set(dev, B43_PHY_G_CRS, 0x4000); |
1124 | b43_phy_read(dev, B43_PHY_G_CRS) | 0x4000); | ||
1125 | phy_stackrestore(0x04A0); | 1024 | phy_stackrestore(0x04A0); |
1126 | phy_stackrestore(0x04A1); | 1025 | phy_stackrestore(0x04A1); |
1127 | phy_stackrestore(0x04A2); | 1026 | phy_stackrestore(0x04A2); |
@@ -1389,17 +1288,10 @@ static u16 b43_radio_init2050(struct b43_wldev *dev) | |||
1389 | sav.phy_crs0 = b43_phy_read(dev, B43_PHY_CRS0); | 1288 | sav.phy_crs0 = b43_phy_read(dev, B43_PHY_CRS0); |
1390 | sav.phy_classctl = b43_phy_read(dev, B43_PHY_CLASSCTL); | 1289 | sav.phy_classctl = b43_phy_read(dev, B43_PHY_CLASSCTL); |
1391 | 1290 | ||
1392 | b43_phy_write(dev, B43_PHY_ANALOGOVER, | 1291 | b43_phy_set(dev, B43_PHY_ANALOGOVER, 0x0003); |
1393 | b43_phy_read(dev, B43_PHY_ANALOGOVER) | 1292 | b43_phy_mask(dev, B43_PHY_ANALOGOVERVAL, 0xFFFC); |
1394 | | 0x0003); | 1293 | b43_phy_mask(dev, B43_PHY_CRS0, 0x7FFF); |
1395 | b43_phy_write(dev, B43_PHY_ANALOGOVERVAL, | 1294 | b43_phy_mask(dev, B43_PHY_CLASSCTL, 0xFFFC); |
1396 | b43_phy_read(dev, B43_PHY_ANALOGOVERVAL) | ||
1397 | & 0xFFFC); | ||
1398 | b43_phy_write(dev, B43_PHY_CRS0, b43_phy_read(dev, B43_PHY_CRS0) | ||
1399 | & 0x7FFF); | ||
1400 | b43_phy_write(dev, B43_PHY_CLASSCTL, | ||
1401 | b43_phy_read(dev, B43_PHY_CLASSCTL) | ||
1402 | & 0xFFFC); | ||
1403 | if (has_loopback_gain(phy)) { | 1295 | if (has_loopback_gain(phy)) { |
1404 | sav.phy_lo_mask = b43_phy_read(dev, B43_PHY_LO_MASK); | 1296 | sav.phy_lo_mask = b43_phy_read(dev, B43_PHY_LO_MASK); |
1405 | sav.phy_lo_ctl = b43_phy_read(dev, B43_PHY_LO_CTL); | 1297 | sav.phy_lo_ctl = b43_phy_read(dev, B43_PHY_LO_CTL); |
@@ -1420,8 +1312,7 @@ static u16 b43_radio_init2050(struct b43_wldev *dev) | |||
1420 | b43_write16(dev, 0x3E2, b43_read16(dev, 0x3E2) | 0x8000); | 1312 | b43_write16(dev, 0x3E2, b43_read16(dev, 0x3E2) | 0x8000); |
1421 | 1313 | ||
1422 | sav.phy_syncctl = b43_phy_read(dev, B43_PHY_SYNCCTL); | 1314 | sav.phy_syncctl = b43_phy_read(dev, B43_PHY_SYNCCTL); |
1423 | b43_phy_write(dev, B43_PHY_SYNCCTL, b43_phy_read(dev, B43_PHY_SYNCCTL) | 1315 | b43_phy_mask(dev, B43_PHY_SYNCCTL, 0xFF7F); |
1424 | & 0xFF7F); | ||
1425 | sav.reg_3E6 = b43_read16(dev, 0x3E6); | 1316 | sav.reg_3E6 = b43_read16(dev, 0x3E6); |
1426 | sav.reg_3F4 = b43_read16(dev, 0x3F4); | 1317 | sav.reg_3F4 = b43_read16(dev, 0x3F4); |
1427 | 1318 | ||
@@ -1429,9 +1320,7 @@ static u16 b43_radio_init2050(struct b43_wldev *dev) | |||
1429 | b43_write16(dev, 0x03E6, 0x0122); | 1320 | b43_write16(dev, 0x03E6, 0x0122); |
1430 | } else { | 1321 | } else { |
1431 | if (phy->analog >= 2) { | 1322 | if (phy->analog >= 2) { |
1432 | b43_phy_write(dev, B43_PHY_CCK(0x03), | 1323 | b43_phy_maskset(dev, B43_PHY_CCK(0x03), 0xFFBF, 0x40); |
1433 | (b43_phy_read(dev, B43_PHY_CCK(0x03)) | ||
1434 | & 0xFFBF) | 0x40); | ||
1435 | } | 1324 | } |
1436 | b43_write16(dev, B43_MMIO_CHANNEL_EXT, | 1325 | b43_write16(dev, B43_MMIO_CHANNEL_EXT, |
1437 | (b43_read16(dev, B43_MMIO_CHANNEL_EXT) | 0x2000)); | 1326 | (b43_read16(dev, B43_MMIO_CHANNEL_EXT) | 0x2000)); |
@@ -1454,14 +1343,12 @@ static u16 b43_radio_init2050(struct b43_wldev *dev) | |||
1454 | LPD(0, 0, 1))); | 1343 | LPD(0, 0, 1))); |
1455 | } | 1344 | } |
1456 | b43_phy_write(dev, B43_PHY_PGACTL, 0xBFA0); | 1345 | b43_phy_write(dev, B43_PHY_PGACTL, 0xBFA0); |
1457 | b43_radio_write16(dev, 0x51, b43_radio_read16(dev, 0x51) | 1346 | b43_radio_set(dev, 0x51, 0x0004); |
1458 | | 0x0004); | ||
1459 | if (phy->radio_rev == 8) { | 1347 | if (phy->radio_rev == 8) { |
1460 | b43_radio_write16(dev, 0x43, 0x1F); | 1348 | b43_radio_write16(dev, 0x43, 0x1F); |
1461 | } else { | 1349 | } else { |
1462 | b43_radio_write16(dev, 0x52, 0); | 1350 | b43_radio_write16(dev, 0x52, 0); |
1463 | b43_radio_write16(dev, 0x43, (b43_radio_read16(dev, 0x43) | 1351 | b43_radio_maskset(dev, 0x43, 0xFFF0, 0x0009); |
1464 | & 0xFFF0) | 0x0009); | ||
1465 | } | 1352 | } |
1466 | b43_phy_write(dev, B43_PHY_CCK(0x58), 0); | 1353 | b43_phy_write(dev, B43_PHY_CCK(0x58), 0); |
1467 | 1354 | ||
@@ -1610,8 +1497,7 @@ static void b43_phy_initb5(struct b43_wldev *dev) | |||
1610 | u8 old_channel; | 1497 | u8 old_channel; |
1611 | 1498 | ||
1612 | if (phy->analog == 1) { | 1499 | if (phy->analog == 1) { |
1613 | b43_radio_write16(dev, 0x007A, b43_radio_read16(dev, 0x007A) | 1500 | b43_radio_set(dev, 0x007A, 0x0050); |
1614 | | 0x0050); | ||
1615 | } | 1501 | } |
1616 | if ((bus->boardinfo.vendor != SSB_BOARDVENDOR_BCM) && | 1502 | if ((bus->boardinfo.vendor != SSB_BOARDVENDOR_BCM) && |
1617 | (bus->boardinfo.type != SSB_BOARD_BU4306)) { | 1503 | (bus->boardinfo.type != SSB_BOARD_BU4306)) { |
@@ -1621,39 +1507,29 @@ static void b43_phy_initb5(struct b43_wldev *dev) | |||
1621 | value += 0x202; | 1507 | value += 0x202; |
1622 | } | 1508 | } |
1623 | } | 1509 | } |
1624 | b43_phy_write(dev, 0x0035, (b43_phy_read(dev, 0x0035) & 0xF0FF) | 1510 | b43_phy_maskset(dev, 0x0035, 0xF0FF, 0x0700); |
1625 | | 0x0700); | ||
1626 | if (phy->radio_ver == 0x2050) | 1511 | if (phy->radio_ver == 0x2050) |
1627 | b43_phy_write(dev, 0x0038, 0x0667); | 1512 | b43_phy_write(dev, 0x0038, 0x0667); |
1628 | 1513 | ||
1629 | if (phy->gmode || phy->rev >= 2) { | 1514 | if (phy->gmode || phy->rev >= 2) { |
1630 | if (phy->radio_ver == 0x2050) { | 1515 | if (phy->radio_ver == 0x2050) { |
1631 | b43_radio_write16(dev, 0x007A, | 1516 | b43_radio_set(dev, 0x007A, 0x0020); |
1632 | b43_radio_read16(dev, 0x007A) | 1517 | b43_radio_set(dev, 0x0051, 0x0004); |
1633 | | 0x0020); | ||
1634 | b43_radio_write16(dev, 0x0051, | ||
1635 | b43_radio_read16(dev, 0x0051) | ||
1636 | | 0x0004); | ||
1637 | } | 1518 | } |
1638 | b43_write16(dev, B43_MMIO_PHY_RADIO, 0x0000); | 1519 | b43_write16(dev, B43_MMIO_PHY_RADIO, 0x0000); |
1639 | 1520 | ||
1640 | b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) | 0x0100); | 1521 | b43_phy_set(dev, 0x0802, 0x0100); |
1641 | b43_phy_write(dev, 0x042B, b43_phy_read(dev, 0x042B) | 0x2000); | 1522 | b43_phy_set(dev, 0x042B, 0x2000); |
1642 | 1523 | ||
1643 | b43_phy_write(dev, 0x001C, 0x186A); | 1524 | b43_phy_write(dev, 0x001C, 0x186A); |
1644 | 1525 | ||
1645 | b43_phy_write(dev, 0x0013, | 1526 | b43_phy_maskset(dev, 0x0013, 0x00FF, 0x1900); |
1646 | (b43_phy_read(dev, 0x0013) & 0x00FF) | 0x1900); | 1527 | b43_phy_maskset(dev, 0x0035, 0xFFC0, 0x0064); |
1647 | b43_phy_write(dev, 0x0035, | 1528 | b43_phy_maskset(dev, 0x005D, 0xFF80, 0x000A); |
1648 | (b43_phy_read(dev, 0x0035) & 0xFFC0) | 0x0064); | ||
1649 | b43_phy_write(dev, 0x005D, | ||
1650 | (b43_phy_read(dev, 0x005D) & 0xFF80) | 0x000A); | ||
1651 | } | 1529 | } |
1652 | 1530 | ||
1653 | if (dev->bad_frames_preempt) { | 1531 | if (dev->bad_frames_preempt) { |
1654 | b43_phy_write(dev, B43_PHY_RADIO_BITFIELD, | 1532 | b43_phy_set(dev, B43_PHY_RADIO_BITFIELD, (1 << 11)); |
1655 | b43_phy_read(dev, | ||
1656 | B43_PHY_RADIO_BITFIELD) | (1 << 11)); | ||
1657 | } | 1533 | } |
1658 | 1534 | ||
1659 | if (phy->analog == 1) { | 1535 | if (phy->analog == 1) { |
@@ -1695,7 +1571,7 @@ static void b43_phy_initb5(struct b43_wldev *dev) | |||
1695 | b43_radio_write16(dev, 0x005B, 0x007B); | 1571 | b43_radio_write16(dev, 0x005B, 0x007B); |
1696 | b43_radio_write16(dev, 0x005C, 0x00B0); | 1572 | b43_radio_write16(dev, 0x005C, 0x00B0); |
1697 | 1573 | ||
1698 | b43_radio_write16(dev, 0x007A, b43_radio_read16(dev, 0x007A) | 0x0007); | 1574 | b43_radio_set(dev, 0x007A, 0x0007); |
1699 | 1575 | ||
1700 | b43_gphy_channel_switch(dev, old_channel, 0); | 1576 | b43_gphy_channel_switch(dev, old_channel, 0); |
1701 | 1577 | ||
@@ -1771,12 +1647,10 @@ static void b43_phy_initb6(struct b43_wldev *dev) | |||
1771 | val += 0x0202; | 1647 | val += 0x0202; |
1772 | } | 1648 | } |
1773 | if (phy->type == B43_PHYTYPE_G) { | 1649 | if (phy->type == B43_PHYTYPE_G) { |
1774 | b43_radio_write16(dev, 0x007A, | 1650 | b43_radio_set(dev, 0x007A, 0x0020); |
1775 | b43_radio_read16(dev, 0x007A) | 0x0020); | 1651 | b43_radio_set(dev, 0x0051, 0x0004); |
1776 | b43_radio_write16(dev, 0x0051, | 1652 | b43_phy_set(dev, 0x0802, 0x0100); |
1777 | b43_radio_read16(dev, 0x0051) | 0x0004); | 1653 | b43_phy_set(dev, 0x042B, 0x2000); |
1778 | b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) | 0x0100); | ||
1779 | b43_phy_write(dev, 0x042B, b43_phy_read(dev, 0x042B) | 0x2000); | ||
1780 | b43_phy_write(dev, 0x5B, 0); | 1654 | b43_phy_write(dev, 0x5B, 0); |
1781 | b43_phy_write(dev, 0x5C, 0); | 1655 | b43_phy_write(dev, 0x5C, 0); |
1782 | } | 1656 | } |
@@ -1801,8 +1675,7 @@ static void b43_phy_initb6(struct b43_wldev *dev) | |||
1801 | b43_radio_write16(dev, 0x5B, 0x7B); | 1675 | b43_radio_write16(dev, 0x5B, 0x7B); |
1802 | b43_radio_write16(dev, 0x5C, 0xB0); | 1676 | b43_radio_write16(dev, 0x5C, 0xB0); |
1803 | } | 1677 | } |
1804 | b43_radio_write16(dev, 0x007A, | 1678 | b43_radio_maskset(dev, 0x007A, 0x00F8, 0x0007); |
1805 | (b43_radio_read16(dev, 0x007A) & 0x00F8) | 0x0007); | ||
1806 | 1679 | ||
1807 | b43_gphy_channel_switch(dev, old_channel, 0); | 1680 | b43_gphy_channel_switch(dev, old_channel, 0); |
1808 | 1681 | ||
@@ -1814,19 +1687,16 @@ static void b43_phy_initb6(struct b43_wldev *dev) | |||
1814 | b43_phy_write(dev, 0x0038, 0x0668); | 1687 | b43_phy_write(dev, 0x0038, 0x0668); |
1815 | b43_set_txpower_g(dev, &gphy->bbatt, &gphy->rfatt, gphy->tx_control); | 1688 | b43_set_txpower_g(dev, &gphy->bbatt, &gphy->rfatt, gphy->tx_control); |
1816 | if (phy->radio_rev <= 5) { | 1689 | if (phy->radio_rev <= 5) { |
1817 | b43_phy_write(dev, 0x5D, (b43_phy_read(dev, 0x5D) | 1690 | b43_phy_maskset(dev, 0x5D, 0xFF80, 0x0003); |
1818 | & 0xFF80) | 0x0003); | ||
1819 | } | 1691 | } |
1820 | if (phy->radio_rev <= 2) | 1692 | if (phy->radio_rev <= 2) |
1821 | b43_radio_write16(dev, 0x005D, 0x000D); | 1693 | b43_radio_write16(dev, 0x005D, 0x000D); |
1822 | 1694 | ||
1823 | if (phy->analog == 4) { | 1695 | if (phy->analog == 4) { |
1824 | b43_write16(dev, 0x3E4, 9); | 1696 | b43_write16(dev, 0x3E4, 9); |
1825 | b43_phy_write(dev, 0x61, b43_phy_read(dev, 0x61) | 1697 | b43_phy_mask(dev, 0x61, 0x0FFF); |
1826 | & 0x0FFF); | ||
1827 | } else { | 1698 | } else { |
1828 | b43_phy_write(dev, 0x0002, (b43_phy_read(dev, 0x0002) & 0xFFC0) | 1699 | b43_phy_maskset(dev, 0x0002, 0xFFC0, 0x0004); |
1829 | | 0x0004); | ||
1830 | } | 1700 | } |
1831 | if (phy->type == B43_PHYTYPE_B) | 1701 | if (phy->type == B43_PHYTYPE_B) |
1832 | B43_WARN_ON(1); | 1702 | B43_WARN_ON(1); |
@@ -1868,63 +1738,39 @@ static void b43_calc_loopback_gain(struct b43_wldev *dev) | |||
1868 | backup_radio[1] = b43_radio_read16(dev, 0x43); | 1738 | backup_radio[1] = b43_radio_read16(dev, 0x43); |
1869 | backup_radio[2] = b43_radio_read16(dev, 0x7A); | 1739 | backup_radio[2] = b43_radio_read16(dev, 0x7A); |
1870 | 1740 | ||
1871 | b43_phy_write(dev, B43_PHY_CRS0, | 1741 | b43_phy_mask(dev, B43_PHY_CRS0, 0x3FFF); |
1872 | b43_phy_read(dev, B43_PHY_CRS0) & 0x3FFF); | 1742 | b43_phy_set(dev, B43_PHY_CCKBBANDCFG, 0x8000); |
1873 | b43_phy_write(dev, B43_PHY_CCKBBANDCFG, | 1743 | b43_phy_set(dev, B43_PHY_RFOVER, 0x0002); |
1874 | b43_phy_read(dev, B43_PHY_CCKBBANDCFG) | 0x8000); | 1744 | b43_phy_mask(dev, B43_PHY_RFOVERVAL, 0xFFFD); |
1875 | b43_phy_write(dev, B43_PHY_RFOVER, | 1745 | b43_phy_set(dev, B43_PHY_RFOVER, 0x0001); |
1876 | b43_phy_read(dev, B43_PHY_RFOVER) | 0x0002); | 1746 | b43_phy_mask(dev, B43_PHY_RFOVERVAL, 0xFFFE); |
1877 | b43_phy_write(dev, B43_PHY_RFOVERVAL, | ||
1878 | b43_phy_read(dev, B43_PHY_RFOVERVAL) & 0xFFFD); | ||
1879 | b43_phy_write(dev, B43_PHY_RFOVER, | ||
1880 | b43_phy_read(dev, B43_PHY_RFOVER) | 0x0001); | ||
1881 | b43_phy_write(dev, B43_PHY_RFOVERVAL, | ||
1882 | b43_phy_read(dev, B43_PHY_RFOVERVAL) & 0xFFFE); | ||
1883 | if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */ | 1747 | if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */ |
1884 | b43_phy_write(dev, B43_PHY_ANALOGOVER, | 1748 | b43_phy_set(dev, B43_PHY_ANALOGOVER, 0x0001); |
1885 | b43_phy_read(dev, B43_PHY_ANALOGOVER) | 0x0001); | 1749 | b43_phy_mask(dev, B43_PHY_ANALOGOVERVAL, 0xFFFE); |
1886 | b43_phy_write(dev, B43_PHY_ANALOGOVERVAL, | 1750 | b43_phy_set(dev, B43_PHY_ANALOGOVER, 0x0002); |
1887 | b43_phy_read(dev, | 1751 | b43_phy_mask(dev, B43_PHY_ANALOGOVERVAL, 0xFFFD); |
1888 | B43_PHY_ANALOGOVERVAL) & 0xFFFE); | 1752 | } |
1889 | b43_phy_write(dev, B43_PHY_ANALOGOVER, | 1753 | b43_phy_set(dev, B43_PHY_RFOVER, 0x000C); |
1890 | b43_phy_read(dev, B43_PHY_ANALOGOVER) | 0x0002); | 1754 | b43_phy_set(dev, B43_PHY_RFOVERVAL, 0x000C); |
1891 | b43_phy_write(dev, B43_PHY_ANALOGOVERVAL, | 1755 | b43_phy_set(dev, B43_PHY_RFOVER, 0x0030); |
1892 | b43_phy_read(dev, | 1756 | b43_phy_maskset(dev, B43_PHY_RFOVERVAL, 0xFFCF, 0x10); |
1893 | B43_PHY_ANALOGOVERVAL) & 0xFFFD); | ||
1894 | } | ||
1895 | b43_phy_write(dev, B43_PHY_RFOVER, | ||
1896 | b43_phy_read(dev, B43_PHY_RFOVER) | 0x000C); | ||
1897 | b43_phy_write(dev, B43_PHY_RFOVERVAL, | ||
1898 | b43_phy_read(dev, B43_PHY_RFOVERVAL) | 0x000C); | ||
1899 | b43_phy_write(dev, B43_PHY_RFOVER, | ||
1900 | b43_phy_read(dev, B43_PHY_RFOVER) | 0x0030); | ||
1901 | b43_phy_write(dev, B43_PHY_RFOVERVAL, | ||
1902 | (b43_phy_read(dev, B43_PHY_RFOVERVAL) | ||
1903 | & 0xFFCF) | 0x10); | ||
1904 | 1757 | ||
1905 | b43_phy_write(dev, B43_PHY_CCK(0x5A), 0x0780); | 1758 | b43_phy_write(dev, B43_PHY_CCK(0x5A), 0x0780); |
1906 | b43_phy_write(dev, B43_PHY_CCK(0x59), 0xC810); | 1759 | b43_phy_write(dev, B43_PHY_CCK(0x59), 0xC810); |
1907 | b43_phy_write(dev, B43_PHY_CCK(0x58), 0x000D); | 1760 | b43_phy_write(dev, B43_PHY_CCK(0x58), 0x000D); |
1908 | 1761 | ||
1909 | b43_phy_write(dev, B43_PHY_CCK(0x0A), | 1762 | b43_phy_set(dev, B43_PHY_CCK(0x0A), 0x2000); |
1910 | b43_phy_read(dev, B43_PHY_CCK(0x0A)) | 0x2000); | ||
1911 | if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */ | 1763 | if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */ |
1912 | b43_phy_write(dev, B43_PHY_ANALOGOVER, | 1764 | b43_phy_set(dev, B43_PHY_ANALOGOVER, 0x0004); |
1913 | b43_phy_read(dev, B43_PHY_ANALOGOVER) | 0x0004); | 1765 | b43_phy_mask(dev, B43_PHY_ANALOGOVERVAL, 0xFFFB); |
1914 | b43_phy_write(dev, B43_PHY_ANALOGOVERVAL, | ||
1915 | b43_phy_read(dev, | ||
1916 | B43_PHY_ANALOGOVERVAL) & 0xFFFB); | ||
1917 | } | 1766 | } |
1918 | b43_phy_write(dev, B43_PHY_CCK(0x03), | 1767 | b43_phy_maskset(dev, B43_PHY_CCK(0x03), 0xFF9F, 0x40); |
1919 | (b43_phy_read(dev, B43_PHY_CCK(0x03)) | ||
1920 | & 0xFF9F) | 0x40); | ||
1921 | 1768 | ||
1922 | if (phy->radio_rev == 8) { | 1769 | if (phy->radio_rev == 8) { |
1923 | b43_radio_write16(dev, 0x43, 0x000F); | 1770 | b43_radio_write16(dev, 0x43, 0x000F); |
1924 | } else { | 1771 | } else { |
1925 | b43_radio_write16(dev, 0x52, 0); | 1772 | b43_radio_write16(dev, 0x52, 0); |
1926 | b43_radio_write16(dev, 0x43, (b43_radio_read16(dev, 0x43) | 1773 | b43_radio_maskset(dev, 0x43, 0xFFF0, 0x9); |
1927 | & 0xFFF0) | 0x9); | ||
1928 | } | 1774 | } |
1929 | b43_gphy_set_baseband_attenuation(dev, 11); | 1775 | b43_gphy_set_baseband_attenuation(dev, 11); |
1930 | 1776 | ||
@@ -1934,45 +1780,28 @@ static void b43_calc_loopback_gain(struct b43_wldev *dev) | |||
1934 | b43_phy_write(dev, B43_PHY_LO_MASK, 0x8020); | 1780 | b43_phy_write(dev, B43_PHY_LO_MASK, 0x8020); |
1935 | b43_phy_write(dev, B43_PHY_LO_CTL, 0); | 1781 | b43_phy_write(dev, B43_PHY_LO_CTL, 0); |
1936 | 1782 | ||
1937 | b43_phy_write(dev, B43_PHY_CCK(0x2B), | 1783 | b43_phy_maskset(dev, B43_PHY_CCK(0x2B), 0xFFC0, 0x01); |
1938 | (b43_phy_read(dev, B43_PHY_CCK(0x2B)) | 1784 | b43_phy_maskset(dev, B43_PHY_CCK(0x2B), 0xC0FF, 0x800); |
1939 | & 0xFFC0) | 0x01); | ||
1940 | b43_phy_write(dev, B43_PHY_CCK(0x2B), | ||
1941 | (b43_phy_read(dev, B43_PHY_CCK(0x2B)) | ||
1942 | & 0xC0FF) | 0x800); | ||
1943 | 1785 | ||
1944 | b43_phy_write(dev, B43_PHY_RFOVER, | 1786 | b43_phy_set(dev, B43_PHY_RFOVER, 0x0100); |
1945 | b43_phy_read(dev, B43_PHY_RFOVER) | 0x0100); | 1787 | b43_phy_mask(dev, B43_PHY_RFOVERVAL, 0xCFFF); |
1946 | b43_phy_write(dev, B43_PHY_RFOVERVAL, | ||
1947 | b43_phy_read(dev, B43_PHY_RFOVERVAL) & 0xCFFF); | ||
1948 | 1788 | ||
1949 | if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_EXTLNA) { | 1789 | if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_EXTLNA) { |
1950 | if (phy->rev >= 7) { | 1790 | if (phy->rev >= 7) { |
1951 | b43_phy_write(dev, B43_PHY_RFOVER, | 1791 | b43_phy_set(dev, B43_PHY_RFOVER, 0x0800); |
1952 | b43_phy_read(dev, B43_PHY_RFOVER) | 1792 | b43_phy_set(dev, B43_PHY_RFOVERVAL, 0x8000); |
1953 | | 0x0800); | ||
1954 | b43_phy_write(dev, B43_PHY_RFOVERVAL, | ||
1955 | b43_phy_read(dev, B43_PHY_RFOVERVAL) | ||
1956 | | 0x8000); | ||
1957 | } | 1793 | } |
1958 | } | 1794 | } |
1959 | b43_radio_write16(dev, 0x7A, b43_radio_read16(dev, 0x7A) | 1795 | b43_radio_mask(dev, 0x7A, 0x00F7); |
1960 | & 0x00F7); | ||
1961 | 1796 | ||
1962 | j = 0; | 1797 | j = 0; |
1963 | loop_i_max = (phy->radio_rev == 8) ? 15 : 9; | 1798 | loop_i_max = (phy->radio_rev == 8) ? 15 : 9; |
1964 | for (i = 0; i < loop_i_max; i++) { | 1799 | for (i = 0; i < loop_i_max; i++) { |
1965 | for (j = 0; j < 16; j++) { | 1800 | for (j = 0; j < 16; j++) { |
1966 | b43_radio_write16(dev, 0x43, i); | 1801 | b43_radio_write16(dev, 0x43, i); |
1967 | b43_phy_write(dev, B43_PHY_RFOVERVAL, | 1802 | b43_phy_maskset(dev, B43_PHY_RFOVERVAL, 0xF0FF, (j << 8)); |
1968 | (b43_phy_read(dev, B43_PHY_RFOVERVAL) | 1803 | b43_phy_maskset(dev, B43_PHY_PGACTL, 0x0FFF, 0xA000); |
1969 | & 0xF0FF) | (j << 8)); | 1804 | b43_phy_set(dev, B43_PHY_PGACTL, 0xF000); |
1970 | b43_phy_write(dev, B43_PHY_PGACTL, | ||
1971 | (b43_phy_read(dev, B43_PHY_PGACTL) | ||
1972 | & 0x0FFF) | 0xA000); | ||
1973 | b43_phy_write(dev, B43_PHY_PGACTL, | ||
1974 | b43_phy_read(dev, B43_PHY_PGACTL) | ||
1975 | | 0xF000); | ||
1976 | udelay(20); | 1805 | udelay(20); |
1977 | if (b43_phy_read(dev, B43_PHY_LO_LEAKAGE) >= 0xDFC) | 1806 | if (b43_phy_read(dev, B43_PHY_LO_LEAKAGE) >= 0xDFC) |
1978 | goto exit_loop1; | 1807 | goto exit_loop1; |
@@ -1982,20 +1811,12 @@ static void b43_calc_loopback_gain(struct b43_wldev *dev) | |||
1982 | loop1_outer_done = i; | 1811 | loop1_outer_done = i; |
1983 | loop1_inner_done = j; | 1812 | loop1_inner_done = j; |
1984 | if (j >= 8) { | 1813 | if (j >= 8) { |
1985 | b43_phy_write(dev, B43_PHY_RFOVERVAL, | 1814 | b43_phy_set(dev, B43_PHY_RFOVERVAL, 0x30); |
1986 | b43_phy_read(dev, B43_PHY_RFOVERVAL) | ||
1987 | | 0x30); | ||
1988 | trsw_rx = 0x1B; | 1815 | trsw_rx = 0x1B; |
1989 | for (j = j - 8; j < 16; j++) { | 1816 | for (j = j - 8; j < 16; j++) { |
1990 | b43_phy_write(dev, B43_PHY_RFOVERVAL, | 1817 | b43_phy_maskset(dev, B43_PHY_RFOVERVAL, 0xF0FF, (j << 8)); |
1991 | (b43_phy_read(dev, B43_PHY_RFOVERVAL) | 1818 | b43_phy_maskset(dev, B43_PHY_PGACTL, 0x0FFF, 0xA000); |
1992 | & 0xF0FF) | (j << 8)); | 1819 | b43_phy_set(dev, B43_PHY_PGACTL, 0xF000); |
1993 | b43_phy_write(dev, B43_PHY_PGACTL, | ||
1994 | (b43_phy_read(dev, B43_PHY_PGACTL) | ||
1995 | & 0x0FFF) | 0xA000); | ||
1996 | b43_phy_write(dev, B43_PHY_PGACTL, | ||
1997 | b43_phy_read(dev, B43_PHY_PGACTL) | ||
1998 | | 0xF000); | ||
1999 | udelay(20); | 1820 | udelay(20); |
2000 | trsw_rx -= 3; | 1821 | trsw_rx -= 3; |
2001 | if (b43_phy_read(dev, B43_PHY_LO_LEAKAGE) >= 0xDFC) | 1822 | if (b43_phy_read(dev, B43_PHY_LO_LEAKAGE) >= 0xDFC) |
@@ -2046,34 +1867,24 @@ static void b43_hardware_pctl_early_init(struct b43_wldev *dev) | |||
2046 | return; | 1867 | return; |
2047 | } | 1868 | } |
2048 | 1869 | ||
2049 | b43_phy_write(dev, 0x0036, b43_phy_read(dev, 0x0036) & 0xFEFF); | 1870 | b43_phy_mask(dev, 0x0036, 0xFEFF); |
2050 | b43_phy_write(dev, 0x002F, 0x0202); | 1871 | b43_phy_write(dev, 0x002F, 0x0202); |
2051 | b43_phy_write(dev, 0x047C, b43_phy_read(dev, 0x047C) | 0x0002); | 1872 | b43_phy_set(dev, 0x047C, 0x0002); |
2052 | b43_phy_write(dev, 0x047A, b43_phy_read(dev, 0x047A) | 0xF000); | 1873 | b43_phy_set(dev, 0x047A, 0xF000); |
2053 | if (phy->radio_ver == 0x2050 && phy->radio_rev == 8) { | 1874 | if (phy->radio_ver == 0x2050 && phy->radio_rev == 8) { |
2054 | b43_phy_write(dev, 0x047A, (b43_phy_read(dev, 0x047A) | 1875 | b43_phy_maskset(dev, 0x047A, 0xFF0F, 0x0010); |
2055 | & 0xFF0F) | 0x0010); | 1876 | b43_phy_set(dev, 0x005D, 0x8000); |
2056 | b43_phy_write(dev, 0x005D, b43_phy_read(dev, 0x005D) | 1877 | b43_phy_maskset(dev, 0x004E, 0xFFC0, 0x0010); |
2057 | | 0x8000); | ||
2058 | b43_phy_write(dev, 0x004E, (b43_phy_read(dev, 0x004E) | ||
2059 | & 0xFFC0) | 0x0010); | ||
2060 | b43_phy_write(dev, 0x002E, 0xC07F); | 1878 | b43_phy_write(dev, 0x002E, 0xC07F); |
2061 | b43_phy_write(dev, 0x0036, b43_phy_read(dev, 0x0036) | 1879 | b43_phy_set(dev, 0x0036, 0x0400); |
2062 | | 0x0400); | ||
2063 | } else { | 1880 | } else { |
2064 | b43_phy_write(dev, 0x0036, b43_phy_read(dev, 0x0036) | 1881 | b43_phy_set(dev, 0x0036, 0x0200); |
2065 | | 0x0200); | 1882 | b43_phy_set(dev, 0x0036, 0x0400); |
2066 | b43_phy_write(dev, 0x0036, b43_phy_read(dev, 0x0036) | 1883 | b43_phy_mask(dev, 0x005D, 0x7FFF); |
2067 | | 0x0400); | 1884 | b43_phy_mask(dev, 0x004F, 0xFFFE); |
2068 | b43_phy_write(dev, 0x005D, b43_phy_read(dev, 0x005D) | 1885 | b43_phy_maskset(dev, 0x004E, 0xFFC0, 0x0010); |
2069 | & 0x7FFF); | ||
2070 | b43_phy_write(dev, 0x004F, b43_phy_read(dev, 0x004F) | ||
2071 | & 0xFFFE); | ||
2072 | b43_phy_write(dev, 0x004E, (b43_phy_read(dev, 0x004E) | ||
2073 | & 0xFFC0) | 0x0010); | ||
2074 | b43_phy_write(dev, 0x002E, 0xC07F); | 1886 | b43_phy_write(dev, 0x002E, 0xC07F); |
2075 | b43_phy_write(dev, 0x047A, (b43_phy_read(dev, 0x047A) | 1887 | b43_phy_maskset(dev, 0x047A, 0xFF0F, 0x0010); |
2076 | & 0xFF0F) | 0x0010); | ||
2077 | } | 1888 | } |
2078 | } | 1889 | } |
2079 | 1890 | ||
@@ -2089,22 +1900,17 @@ static void b43_hardware_pctl_init_gphy(struct b43_wldev *dev) | |||
2089 | return; | 1900 | return; |
2090 | } | 1901 | } |
2091 | 1902 | ||
2092 | b43_phy_write(dev, 0x0036, (b43_phy_read(dev, 0x0036) & 0xFFC0) | 1903 | b43_phy_maskset(dev, 0x0036, 0xFFC0, (gphy->tgt_idle_tssi - gphy->cur_idle_tssi)); |
2093 | | (gphy->tgt_idle_tssi - gphy->cur_idle_tssi)); | 1904 | b43_phy_maskset(dev, 0x0478, 0xFF00, (gphy->tgt_idle_tssi - gphy->cur_idle_tssi)); |
2094 | b43_phy_write(dev, 0x0478, (b43_phy_read(dev, 0x0478) & 0xFF00) | ||
2095 | | (gphy->tgt_idle_tssi - gphy->cur_idle_tssi)); | ||
2096 | b43_gphy_tssi_power_lt_init(dev); | 1905 | b43_gphy_tssi_power_lt_init(dev); |
2097 | b43_gphy_gain_lt_init(dev); | 1906 | b43_gphy_gain_lt_init(dev); |
2098 | b43_phy_write(dev, 0x0060, b43_phy_read(dev, 0x0060) & 0xFFBF); | 1907 | b43_phy_mask(dev, 0x0060, 0xFFBF); |
2099 | b43_phy_write(dev, 0x0014, 0x0000); | 1908 | b43_phy_write(dev, 0x0014, 0x0000); |
2100 | 1909 | ||
2101 | B43_WARN_ON(phy->rev < 6); | 1910 | B43_WARN_ON(phy->rev < 6); |
2102 | b43_phy_write(dev, 0x0478, b43_phy_read(dev, 0x0478) | 1911 | b43_phy_set(dev, 0x0478, 0x0800); |
2103 | | 0x0800); | 1912 | b43_phy_mask(dev, 0x0478, 0xFEFF); |
2104 | b43_phy_write(dev, 0x0478, b43_phy_read(dev, 0x0478) | 1913 | b43_phy_mask(dev, 0x0801, 0xFFBF); |
2105 | & 0xFEFF); | ||
2106 | b43_phy_write(dev, 0x0801, b43_phy_read(dev, 0x0801) | ||
2107 | & 0xFFBF); | ||
2108 | 1914 | ||
2109 | b43_gphy_dc_lt_init(dev, 1); | 1915 | b43_gphy_dc_lt_init(dev, 1); |
2110 | 1916 | ||
@@ -2139,9 +1945,7 @@ static void b43_phy_init_pctl(struct b43_wldev *dev) | |||
2139 | b43_hardware_pctl_early_init(dev); | 1945 | b43_hardware_pctl_early_init(dev); |
2140 | if (gphy->cur_idle_tssi == 0) { | 1946 | if (gphy->cur_idle_tssi == 0) { |
2141 | if (phy->radio_ver == 0x2050 && phy->analog == 0) { | 1947 | if (phy->radio_ver == 0x2050 && phy->analog == 0) { |
2142 | b43_radio_write16(dev, 0x0076, | 1948 | b43_radio_maskset(dev, 0x0076, 0x00F7, 0x0084); |
2143 | (b43_radio_read16(dev, 0x0076) | ||
2144 | & 0x00F7) | 0x0084); | ||
2145 | } else { | 1949 | } else { |
2146 | struct b43_rfatt rfatt; | 1950 | struct b43_rfatt rfatt; |
2147 | struct b43_bbatt bbatt; | 1951 | struct b43_bbatt bbatt; |
@@ -2174,9 +1978,7 @@ static void b43_phy_init_pctl(struct b43_wldev *dev) | |||
2174 | } | 1978 | } |
2175 | } | 1979 | } |
2176 | if (phy->radio_ver == 0x2050 && phy->analog == 0) { | 1980 | if (phy->radio_ver == 0x2050 && phy->analog == 0) { |
2177 | b43_radio_write16(dev, 0x0076, | 1981 | b43_radio_mask(dev, 0x0076, 0xFF7B); |
2178 | b43_radio_read16(dev, 0x0076) | ||
2179 | & 0xFF7B); | ||
2180 | } else { | 1982 | } else { |
2181 | b43_set_txpower_g(dev, &old_bbatt, | 1983 | b43_set_txpower_g(dev, &old_bbatt, |
2182 | &old_rfatt, old_tx_control); | 1984 | &old_rfatt, old_tx_control); |
@@ -2220,20 +2022,14 @@ static void b43_phy_initg(struct b43_wldev *dev) | |||
2220 | b43_phy_write(dev, B43_PHY_OFDM(0xC3), 0x8006); | 2022 | b43_phy_write(dev, B43_PHY_OFDM(0xC3), 0x8006); |
2221 | } | 2023 | } |
2222 | if (tmp == 5) { | 2024 | if (tmp == 5) { |
2223 | b43_phy_write(dev, B43_PHY_OFDM(0xCC), | 2025 | b43_phy_maskset(dev, B43_PHY_OFDM(0xCC), 0x00FF, 0x1F00); |
2224 | (b43_phy_read(dev, B43_PHY_OFDM(0xCC)) | ||
2225 | & 0x00FF) | 0x1F00); | ||
2226 | } | 2026 | } |
2227 | } | 2027 | } |
2228 | if ((phy->rev <= 2 && phy->gmode) || phy->rev >= 2) | 2028 | if ((phy->rev <= 2 && phy->gmode) || phy->rev >= 2) |
2229 | b43_phy_write(dev, B43_PHY_OFDM(0x7E), 0x78); | 2029 | b43_phy_write(dev, B43_PHY_OFDM(0x7E), 0x78); |
2230 | if (phy->radio_rev == 8) { | 2030 | if (phy->radio_rev == 8) { |
2231 | b43_phy_write(dev, B43_PHY_EXTG(0x01), | 2031 | b43_phy_set(dev, B43_PHY_EXTG(0x01), 0x80); |
2232 | b43_phy_read(dev, B43_PHY_EXTG(0x01)) | 2032 | b43_phy_set(dev, B43_PHY_OFDM(0x3E), 0x4); |
2233 | | 0x80); | ||
2234 | b43_phy_write(dev, B43_PHY_OFDM(0x3E), | ||
2235 | b43_phy_read(dev, B43_PHY_OFDM(0x3E)) | ||
2236 | | 0x4); | ||
2237 | } | 2033 | } |
2238 | if (has_loopback_gain(phy)) | 2034 | if (has_loopback_gain(phy)) |
2239 | b43_calc_loopback_gain(dev); | 2035 | b43_calc_loopback_gain(dev); |
@@ -2251,15 +2047,10 @@ static void b43_phy_initg(struct b43_wldev *dev) | |||
2251 | | gphy->lo_control->tx_bias | gphy-> | 2047 | | gphy->lo_control->tx_bias | gphy-> |
2252 | lo_control->tx_magn); | 2048 | lo_control->tx_magn); |
2253 | } else { | 2049 | } else { |
2254 | b43_radio_write16(dev, 0x52, | 2050 | b43_radio_maskset(dev, 0x52, 0xFFF0, gphy->lo_control->tx_bias); |
2255 | (b43_radio_read16(dev, 0x52) & 0xFFF0) | ||
2256 | | gphy->lo_control->tx_bias); | ||
2257 | } | 2051 | } |
2258 | if (phy->rev >= 6) { | 2052 | if (phy->rev >= 6) { |
2259 | b43_phy_write(dev, B43_PHY_CCK(0x36), | 2053 | b43_phy_maskset(dev, B43_PHY_CCK(0x36), 0x0FFF, (gphy->lo_control->tx_bias << 12)); |
2260 | (b43_phy_read(dev, B43_PHY_CCK(0x36)) | ||
2261 | & 0x0FFF) | (gphy->lo_control-> | ||
2262 | tx_bias << 12)); | ||
2263 | } | 2054 | } |
2264 | if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_PACTRL) | 2055 | if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_PACTRL) |
2265 | b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x8075); | 2056 | b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x8075); |
@@ -2298,11 +2089,8 @@ static void b43_phy_initg(struct b43_wldev *dev) | |||
2298 | but OFDM is legal everywhere */ | 2089 | but OFDM is legal everywhere */ |
2299 | if ((dev->dev->bus->chip_id == 0x4306 | 2090 | if ((dev->dev->bus->chip_id == 0x4306 |
2300 | && dev->dev->bus->chip_package == 2) || 0) { | 2091 | && dev->dev->bus->chip_package == 2) || 0) { |
2301 | b43_phy_write(dev, B43_PHY_CRS0, b43_phy_read(dev, B43_PHY_CRS0) | 2092 | b43_phy_mask(dev, B43_PHY_CRS0, 0xBFFF); |
2302 | & 0xBFFF); | 2093 | b43_phy_mask(dev, B43_PHY_OFDM(0xC3), 0x7FFF); |
2303 | b43_phy_write(dev, B43_PHY_OFDM(0xC3), | ||
2304 | b43_phy_read(dev, B43_PHY_OFDM(0xC3)) | ||
2305 | & 0x7FFF); | ||
2306 | } | 2094 | } |
2307 | } | 2095 | } |
2308 | 2096 | ||
@@ -2504,9 +2292,8 @@ static u8 b43_gphy_aci_scan(struct b43_wldev *dev) | |||
2504 | 2292 | ||
2505 | b43_phy_lock(dev); | 2293 | b43_phy_lock(dev); |
2506 | b43_radio_lock(dev); | 2294 | b43_radio_lock(dev); |
2507 | b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) & 0xFFFC); | 2295 | b43_phy_mask(dev, 0x0802, 0xFFFC); |
2508 | b43_phy_write(dev, B43_PHY_G_CRS, | 2296 | b43_phy_mask(dev, B43_PHY_G_CRS, 0x7FFF); |
2509 | b43_phy_read(dev, B43_PHY_G_CRS) & 0x7FFF); | ||
2510 | b43_set_all_gains(dev, 3, 8, 1); | 2297 | b43_set_all_gains(dev, 3, 8, 1); |
2511 | 2298 | ||
2512 | start = (channel - 5 > 0) ? channel - 5 : 1; | 2299 | start = (channel - 5 > 0) ? channel - 5 : 1; |
@@ -2517,11 +2304,9 @@ static u8 b43_gphy_aci_scan(struct b43_wldev *dev) | |||
2517 | ret[i - 1] = b43_gphy_aci_detect(dev, i); | 2304 | ret[i - 1] = b43_gphy_aci_detect(dev, i); |
2518 | } | 2305 | } |
2519 | b43_switch_channel(dev, channel); | 2306 | b43_switch_channel(dev, channel); |
2520 | b43_phy_write(dev, 0x0802, | 2307 | b43_phy_maskset(dev, 0x0802, 0xFFFC, 0x0003); |
2521 | (b43_phy_read(dev, 0x0802) & 0xFFFC) | 0x0003); | 2308 | b43_phy_mask(dev, 0x0403, 0xFFF8); |
2522 | b43_phy_write(dev, 0x0403, b43_phy_read(dev, 0x0403) & 0xFFF8); | 2309 | b43_phy_set(dev, B43_PHY_G_CRS, 0x8000); |
2523 | b43_phy_write(dev, B43_PHY_G_CRS, | ||
2524 | b43_phy_read(dev, B43_PHY_G_CRS) | 0x8000); | ||
2525 | b43_set_original_gains(dev); | 2310 | b43_set_original_gains(dev); |
2526 | for (i = 0; i < 13; i++) { | 2311 | for (i = 0; i < 13; i++) { |
2527 | if (!ret[i]) | 2312 | if (!ret[i]) |
@@ -2565,8 +2350,8 @@ static s8 b43_tssi2dbm_entry(s8 entry[], u8 index, | |||
2565 | return 0; | 2350 | return 0; |
2566 | } | 2351 | } |
2567 | 2352 | ||
2568 | u8 * b43_generate_dyn_tssi2dbm_tab(struct b43_wldev *dev, | 2353 | u8 *b43_generate_dyn_tssi2dbm_tab(struct b43_wldev *dev, |
2569 | s16 pab0, s16 pab1, s16 pab2) | 2354 | s16 pab0, s16 pab1, s16 pab2) |
2570 | { | 2355 | { |
2571 | unsigned int i; | 2356 | unsigned int i; |
2572 | u8 *tab; | 2357 | u8 *tab; |
diff --git a/drivers/net/wireless/b43/pio.c b/drivers/net/wireless/b43/pio.c index 1036bef8c4cc..8cd9776752e6 100644 --- a/drivers/net/wireless/b43/pio.c +++ b/drivers/net/wireless/b43/pio.c | |||
@@ -55,8 +55,8 @@ static u16 generate_cookie(struct b43_pio_txqueue *q, | |||
55 | } | 55 | } |
56 | 56 | ||
57 | static | 57 | static |
58 | struct b43_pio_txqueue * parse_cookie(struct b43_wldev *dev, | 58 | struct b43_pio_txqueue *parse_cookie(struct b43_wldev *dev, |
59 | u16 cookie, | 59 | u16 cookie, |
60 | struct b43_pio_txpacket **pack) | 60 | struct b43_pio_txpacket **pack) |
61 | { | 61 | { |
62 | struct b43_pio *pio = &dev->pio; | 62 | struct b43_pio *pio = &dev->pio; |
@@ -134,8 +134,8 @@ static u16 pio_rxqueue_offset(struct b43_wldev *dev) | |||
134 | return 8; | 134 | return 8; |
135 | } | 135 | } |
136 | 136 | ||
137 | static struct b43_pio_txqueue * b43_setup_pioqueue_tx(struct b43_wldev *dev, | 137 | static struct b43_pio_txqueue *b43_setup_pioqueue_tx(struct b43_wldev *dev, |
138 | unsigned int index) | 138 | unsigned int index) |
139 | { | 139 | { |
140 | struct b43_pio_txqueue *q; | 140 | struct b43_pio_txqueue *q; |
141 | struct b43_pio_txpacket *p; | 141 | struct b43_pio_txpacket *p; |
@@ -171,8 +171,8 @@ static struct b43_pio_txqueue * b43_setup_pioqueue_tx(struct b43_wldev *dev, | |||
171 | return q; | 171 | return q; |
172 | } | 172 | } |
173 | 173 | ||
174 | static struct b43_pio_rxqueue * b43_setup_pioqueue_rx(struct b43_wldev *dev, | 174 | static struct b43_pio_rxqueue *b43_setup_pioqueue_rx(struct b43_wldev *dev, |
175 | unsigned int index) | 175 | unsigned int index) |
176 | { | 176 | { |
177 | struct b43_pio_rxqueue *q; | 177 | struct b43_pio_rxqueue *q; |
178 | 178 | ||
@@ -308,8 +308,8 @@ err_destroy_bk: | |||
308 | } | 308 | } |
309 | 309 | ||
310 | /* Static mapping of mac80211's queues (priorities) to b43 PIO queues. */ | 310 | /* Static mapping of mac80211's queues (priorities) to b43 PIO queues. */ |
311 | static struct b43_pio_txqueue * select_queue_by_priority(struct b43_wldev *dev, | 311 | static struct b43_pio_txqueue *select_queue_by_priority(struct b43_wldev *dev, |
312 | u8 queue_prio) | 312 | u8 queue_prio) |
313 | { | 313 | { |
314 | struct b43_pio_txqueue *q; | 314 | struct b43_pio_txqueue *q; |
315 | 315 | ||
diff --git a/drivers/net/wireless/b43/rfkill.c b/drivers/net/wireless/b43/rfkill.c index 713753781f40..afad42358693 100644 --- a/drivers/net/wireless/b43/rfkill.c +++ b/drivers/net/wireless/b43/rfkill.c | |||
@@ -113,7 +113,7 @@ out_unlock: | |||
113 | return err; | 113 | return err; |
114 | } | 114 | } |
115 | 115 | ||
116 | char * b43_rfkill_led_name(struct b43_wldev *dev) | 116 | char *b43_rfkill_led_name(struct b43_wldev *dev) |
117 | { | 117 | { |
118 | struct b43_rfkill *rfk = &(dev->wl->rfkill); | 118 | struct b43_rfkill *rfk = &(dev->wl->rfkill); |
119 | 119 | ||
diff --git a/drivers/net/wireless/b43/wa.c b/drivers/net/wireless/b43/wa.c index 0c0fb15abb9f..e1e20f69f6d7 100644 --- a/drivers/net/wireless/b43/wa.c +++ b/drivers/net/wireless/b43/wa.c | |||
@@ -62,8 +62,7 @@ void b43_wa_initgains(struct b43_wldev *dev) | |||
62 | struct b43_phy *phy = &dev->phy; | 62 | struct b43_phy *phy = &dev->phy; |
63 | 63 | ||
64 | b43_phy_write(dev, B43_PHY_LNAHPFCTL, 0x1FF9); | 64 | b43_phy_write(dev, B43_PHY_LNAHPFCTL, 0x1FF9); |
65 | b43_phy_write(dev, B43_PHY_LPFGAINCTL, | 65 | b43_phy_mask(dev, B43_PHY_LPFGAINCTL, 0xFF0F); |
66 | b43_phy_read(dev, B43_PHY_LPFGAINCTL) & 0xFF0F); | ||
67 | if (phy->rev <= 2) | 66 | if (phy->rev <= 2) |
68 | b43_ofdmtab_write16(dev, B43_OFDMTAB_LPFGAIN, 0, 0x1FBF); | 67 | b43_ofdmtab_write16(dev, B43_OFDMTAB_LPFGAIN, 0, 0x1FBF); |
69 | b43_radio_write16(dev, 0x0002, 0x1FBF); | 68 | b43_radio_write16(dev, 0x0002, 0x1FBF); |
@@ -73,11 +72,9 @@ void b43_wa_initgains(struct b43_wldev *dev) | |||
73 | b43_phy_write(dev, 0x001D, 0x0F40); | 72 | b43_phy_write(dev, 0x001D, 0x0F40); |
74 | b43_phy_write(dev, 0x001F, 0x1C00); | 73 | b43_phy_write(dev, 0x001F, 0x1C00); |
75 | if (phy->rev <= 3) | 74 | if (phy->rev <= 3) |
76 | b43_phy_write(dev, 0x002A, | 75 | b43_phy_maskset(dev, 0x002A, 0x00FF, 0x0400); |
77 | (b43_phy_read(dev, 0x002A) & 0x00FF) | 0x0400); | ||
78 | else if (phy->rev == 5) { | 76 | else if (phy->rev == 5) { |
79 | b43_phy_write(dev, 0x002A, | 77 | b43_phy_maskset(dev, 0x002A, 0x00FF, 0x1A00); |
80 | (b43_phy_read(dev, 0x002A) & 0x00FF) | 0x1A00); | ||
81 | b43_phy_write(dev, 0x00CC, 0x2121); | 78 | b43_phy_write(dev, 0x00CC, 0x2121); |
82 | } | 79 | } |
83 | if (phy->rev >= 3) | 80 | if (phy->rev >= 3) |
@@ -86,7 +83,7 @@ void b43_wa_initgains(struct b43_wldev *dev) | |||
86 | 83 | ||
87 | static void b43_wa_divider(struct b43_wldev *dev) | 84 | static void b43_wa_divider(struct b43_wldev *dev) |
88 | { | 85 | { |
89 | b43_phy_write(dev, 0x002B, b43_phy_read(dev, 0x002B) & ~0x0100); | 86 | b43_phy_mask(dev, 0x002B, ~0x0100); |
90 | b43_phy_write(dev, 0x008E, 0x58C1); | 87 | b43_phy_write(dev, 0x008E, 0x58C1); |
91 | } | 88 | } |
92 | 89 | ||
@@ -272,8 +269,7 @@ static void b43_wa_2060txlna_gain(struct b43_wldev *dev) | |||
272 | 269 | ||
273 | static void b43_wa_lms(struct b43_wldev *dev) | 270 | static void b43_wa_lms(struct b43_wldev *dev) |
274 | { | 271 | { |
275 | b43_phy_write(dev, 0x0055, | 272 | b43_phy_maskset(dev, 0x0055, 0xFFC0, 0x0004); |
276 | (b43_phy_read(dev, 0x0055) & 0xFFC0) | 0x0004); | ||
277 | } | 273 | } |
278 | 274 | ||
279 | static void b43_wa_mixedsignal(struct b43_wldev *dev) | 275 | static void b43_wa_mixedsignal(struct b43_wldev *dev) |
@@ -318,23 +314,18 @@ static void b43_wa_crs_ed(struct b43_wldev *dev) | |||
318 | } else if (phy->rev == 2) { | 314 | } else if (phy->rev == 2) { |
319 | b43_phy_write(dev, B43_PHY_CRSTHRES1, 0x1861); | 315 | b43_phy_write(dev, B43_PHY_CRSTHRES1, 0x1861); |
320 | b43_phy_write(dev, B43_PHY_CRSTHRES2, 0x0271); | 316 | b43_phy_write(dev, B43_PHY_CRSTHRES2, 0x0271); |
321 | b43_phy_write(dev, B43_PHY_ANTDWELL, | 317 | b43_phy_set(dev, B43_PHY_ANTDWELL, 0x0800); |
322 | b43_phy_read(dev, B43_PHY_ANTDWELL) | ||
323 | | 0x0800); | ||
324 | } else { | 318 | } else { |
325 | b43_phy_write(dev, B43_PHY_CRSTHRES1, 0x0098); | 319 | b43_phy_write(dev, B43_PHY_CRSTHRES1, 0x0098); |
326 | b43_phy_write(dev, B43_PHY_CRSTHRES2, 0x0070); | 320 | b43_phy_write(dev, B43_PHY_CRSTHRES2, 0x0070); |
327 | b43_phy_write(dev, B43_PHY_OFDM(0xC9), 0x0080); | 321 | b43_phy_write(dev, B43_PHY_OFDM(0xC9), 0x0080); |
328 | b43_phy_write(dev, B43_PHY_ANTDWELL, | 322 | b43_phy_set(dev, B43_PHY_ANTDWELL, 0x0800); |
329 | b43_phy_read(dev, B43_PHY_ANTDWELL) | ||
330 | | 0x0800); | ||
331 | } | 323 | } |
332 | } | 324 | } |
333 | 325 | ||
334 | static void b43_wa_crs_thr(struct b43_wldev *dev) | 326 | static void b43_wa_crs_thr(struct b43_wldev *dev) |
335 | { | 327 | { |
336 | b43_phy_write(dev, B43_PHY_CRS0, | 328 | b43_phy_maskset(dev, B43_PHY_CRS0, ~0x03C0, 0xD000); |
337 | (b43_phy_read(dev, B43_PHY_CRS0) & ~0x03C0) | 0xD000); | ||
338 | } | 329 | } |
339 | 330 | ||
340 | static void b43_wa_crs_blank(struct b43_wldev *dev) | 331 | static void b43_wa_crs_blank(struct b43_wldev *dev) |
@@ -391,72 +382,45 @@ static void b43_wa_altagc(struct b43_wldev *dev) | |||
391 | b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 3, 25); | 382 | b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 3, 25); |
392 | } | 383 | } |
393 | 384 | ||
394 | b43_phy_write(dev, B43_PHY_CCKSHIFTBITS_WA, | 385 | b43_phy_maskset(dev, B43_PHY_CCKSHIFTBITS_WA, (u16)~0xFF00, 0x5700); |
395 | (b43_phy_read(dev, B43_PHY_CCKSHIFTBITS_WA) & ~0xFF00) | 0x5700); | 386 | b43_phy_maskset(dev, B43_PHY_OFDM(0x1A), ~0x007F, 0x000F); |
396 | b43_phy_write(dev, B43_PHY_OFDM(0x1A), | 387 | b43_phy_maskset(dev, B43_PHY_OFDM(0x1A), ~0x3F80, 0x2B80); |
397 | (b43_phy_read(dev, B43_PHY_OFDM(0x1A)) & ~0x007F) | 0x000F); | 388 | b43_phy_maskset(dev, B43_PHY_ANTWRSETT, 0xF0FF, 0x0300); |
398 | b43_phy_write(dev, B43_PHY_OFDM(0x1A), | 389 | b43_radio_set(dev, 0x7A, 0x0008); |
399 | (b43_phy_read(dev, B43_PHY_OFDM(0x1A)) & ~0x3F80) | 0x2B80); | 390 | b43_phy_maskset(dev, B43_PHY_N1P1GAIN, ~0x000F, 0x0008); |
400 | b43_phy_write(dev, B43_PHY_ANTWRSETT, | 391 | b43_phy_maskset(dev, B43_PHY_P1P2GAIN, ~0x0F00, 0x0600); |
401 | (b43_phy_read(dev, B43_PHY_ANTWRSETT) & 0xF0FF) | 0x0300); | 392 | b43_phy_maskset(dev, B43_PHY_N1N2GAIN, ~0x0F00, 0x0700); |
402 | b43_radio_write16(dev, 0x7A, | 393 | b43_phy_maskset(dev, B43_PHY_N1P1GAIN, ~0x0F00, 0x0100); |
403 | b43_radio_read16(dev, 0x7A) | 0x0008); | ||
404 | b43_phy_write(dev, B43_PHY_N1P1GAIN, | ||
405 | (b43_phy_read(dev, B43_PHY_N1P1GAIN) & ~0x000F) | 0x0008); | ||
406 | b43_phy_write(dev, B43_PHY_P1P2GAIN, | ||
407 | (b43_phy_read(dev, B43_PHY_P1P2GAIN) & ~0x0F00) | 0x0600); | ||
408 | b43_phy_write(dev, B43_PHY_N1N2GAIN, | ||
409 | (b43_phy_read(dev, B43_PHY_N1N2GAIN) & ~0x0F00) | 0x0700); | ||
410 | b43_phy_write(dev, B43_PHY_N1P1GAIN, | ||
411 | (b43_phy_read(dev, B43_PHY_N1P1GAIN) & ~0x0F00) | 0x0100); | ||
412 | if (phy->rev == 1) { | 394 | if (phy->rev == 1) { |
413 | b43_phy_write(dev, B43_PHY_N1N2GAIN, | 395 | b43_phy_maskset(dev, B43_PHY_N1N2GAIN, ~0x000F, 0x0007); |
414 | (b43_phy_read(dev, B43_PHY_N1N2GAIN) | ||
415 | & ~0x000F) | 0x0007); | ||
416 | } | 396 | } |
417 | b43_phy_write(dev, B43_PHY_OFDM(0x88), | 397 | b43_phy_maskset(dev, B43_PHY_OFDM(0x88), ~0x00FF, 0x001C); |
418 | (b43_phy_read(dev, B43_PHY_OFDM(0x88)) & ~0x00FF) | 0x001C); | 398 | b43_phy_maskset(dev, B43_PHY_OFDM(0x88), ~0x3F00, 0x0200); |
419 | b43_phy_write(dev, B43_PHY_OFDM(0x88), | 399 | b43_phy_maskset(dev, B43_PHY_OFDM(0x96), ~0x00FF, 0x001C); |
420 | (b43_phy_read(dev, B43_PHY_OFDM(0x88)) & ~0x3F00) | 0x0200); | 400 | b43_phy_maskset(dev, B43_PHY_OFDM(0x89), ~0x00FF, 0x0020); |
421 | b43_phy_write(dev, B43_PHY_OFDM(0x96), | 401 | b43_phy_maskset(dev, B43_PHY_OFDM(0x89), ~0x3F00, 0x0200); |
422 | (b43_phy_read(dev, B43_PHY_OFDM(0x96)) & ~0x00FF) | 0x001C); | 402 | b43_phy_maskset(dev, B43_PHY_OFDM(0x82), ~0x00FF, 0x002E); |
423 | b43_phy_write(dev, B43_PHY_OFDM(0x89), | 403 | b43_phy_maskset(dev, B43_PHY_OFDM(0x96), (u16)~0xFF00, 0x1A00); |
424 | (b43_phy_read(dev, B43_PHY_OFDM(0x89)) & ~0x00FF) | 0x0020); | 404 | b43_phy_maskset(dev, B43_PHY_OFDM(0x81), ~0x00FF, 0x0028); |
425 | b43_phy_write(dev, B43_PHY_OFDM(0x89), | 405 | b43_phy_maskset(dev, B43_PHY_OFDM(0x81), (u16)~0xFF00, 0x2C00); |
426 | (b43_phy_read(dev, B43_PHY_OFDM(0x89)) & ~0x3F00) | 0x0200); | ||
427 | b43_phy_write(dev, B43_PHY_OFDM(0x82), | ||
428 | (b43_phy_read(dev, B43_PHY_OFDM(0x82)) & ~0x00FF) | 0x002E); | ||
429 | b43_phy_write(dev, B43_PHY_OFDM(0x96), | ||
430 | (b43_phy_read(dev, B43_PHY_OFDM(0x96)) & ~0xFF00) | 0x1A00); | ||
431 | b43_phy_write(dev, B43_PHY_OFDM(0x81), | ||
432 | (b43_phy_read(dev, B43_PHY_OFDM(0x81)) & ~0x00FF) | 0x0028); | ||
433 | b43_phy_write(dev, B43_PHY_OFDM(0x81), | ||
434 | (b43_phy_read(dev, B43_PHY_OFDM(0x81)) & ~0xFF00) | 0x2C00); | ||
435 | if (phy->rev == 1) { | 406 | if (phy->rev == 1) { |
436 | b43_phy_write(dev, B43_PHY_PEAK_COUNT, 0x092B); | 407 | b43_phy_write(dev, B43_PHY_PEAK_COUNT, 0x092B); |
437 | b43_phy_write(dev, B43_PHY_OFDM(0x1B), | 408 | b43_phy_maskset(dev, B43_PHY_OFDM(0x1B), ~0x001E, 0x0002); |
438 | (b43_phy_read(dev, B43_PHY_OFDM(0x1B)) & ~0x001E) | 0x0002); | ||
439 | } else { | 409 | } else { |
440 | b43_phy_write(dev, B43_PHY_OFDM(0x1B), | 410 | b43_phy_mask(dev, B43_PHY_OFDM(0x1B), ~0x001E); |
441 | b43_phy_read(dev, B43_PHY_OFDM(0x1B)) & ~0x001E); | ||
442 | b43_phy_write(dev, B43_PHY_OFDM(0x1F), 0x287A); | 411 | b43_phy_write(dev, B43_PHY_OFDM(0x1F), 0x287A); |
443 | b43_phy_write(dev, B43_PHY_LPFGAINCTL, | 412 | b43_phy_maskset(dev, B43_PHY_LPFGAINCTL, ~0x000F, 0x0004); |
444 | (b43_phy_read(dev, B43_PHY_LPFGAINCTL) & ~0x000F) | 0x0004); | ||
445 | if (phy->rev >= 6) { | 413 | if (phy->rev >= 6) { |
446 | b43_phy_write(dev, B43_PHY_OFDM(0x22), 0x287A); | 414 | b43_phy_write(dev, B43_PHY_OFDM(0x22), 0x287A); |
447 | b43_phy_write(dev, B43_PHY_LPFGAINCTL, | 415 | b43_phy_maskset(dev, B43_PHY_LPFGAINCTL, (u16)~0xF000, 0x3000); |
448 | (b43_phy_read(dev, B43_PHY_LPFGAINCTL) & ~0xF000) | 0x3000); | ||
449 | } | 416 | } |
450 | } | 417 | } |
451 | b43_phy_write(dev, B43_PHY_DIVSRCHIDX, | 418 | b43_phy_maskset(dev, B43_PHY_DIVSRCHIDX, 0x8080, 0x7874); |
452 | (b43_phy_read(dev, B43_PHY_DIVSRCHIDX) & 0x8080) | 0x7874); | ||
453 | b43_phy_write(dev, B43_PHY_OFDM(0x8E), 0x1C00); | 419 | b43_phy_write(dev, B43_PHY_OFDM(0x8E), 0x1C00); |
454 | if (phy->rev == 1) { | 420 | if (phy->rev == 1) { |
455 | b43_phy_write(dev, B43_PHY_DIVP1P2GAIN, | 421 | b43_phy_maskset(dev, B43_PHY_DIVP1P2GAIN, ~0x0F00, 0x0600); |
456 | (b43_phy_read(dev, B43_PHY_DIVP1P2GAIN) & ~0x0F00) | 0x0600); | ||
457 | b43_phy_write(dev, B43_PHY_OFDM(0x8B), 0x005E); | 422 | b43_phy_write(dev, B43_PHY_OFDM(0x8B), 0x005E); |
458 | b43_phy_write(dev, B43_PHY_ANTWRSETT, | 423 | b43_phy_maskset(dev, B43_PHY_ANTWRSETT, ~0x00FF, 0x001E); |
459 | (b43_phy_read(dev, B43_PHY_ANTWRSETT) & ~0x00FF) | 0x001E); | ||
460 | b43_phy_write(dev, B43_PHY_OFDM(0x8D), 0x0002); | 424 | b43_phy_write(dev, B43_PHY_OFDM(0x8D), 0x0002); |
461 | b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC3_R1, 0, 0); | 425 | b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC3_R1, 0, 0); |
462 | b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC3_R1, 1, 7); | 426 | b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC3_R1, 1, 7); |
@@ -469,10 +433,8 @@ static void b43_wa_altagc(struct b43_wldev *dev) | |||
469 | b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC3, 3, 28); | 433 | b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC3, 3, 28); |
470 | } | 434 | } |
471 | if (phy->rev >= 6) { | 435 | if (phy->rev >= 6) { |
472 | b43_phy_write(dev, B43_PHY_OFDM(0x26), | 436 | b43_phy_mask(dev, B43_PHY_OFDM(0x26), ~0x0003); |
473 | b43_phy_read(dev, B43_PHY_OFDM(0x26)) & ~0x0003); | 437 | b43_phy_mask(dev, B43_PHY_OFDM(0x26), ~0x1000); |
474 | b43_phy_write(dev, B43_PHY_OFDM(0x26), | ||
475 | b43_phy_read(dev, B43_PHY_OFDM(0x26)) & ~0x1000); | ||
476 | } | 438 | } |
477 | b43_phy_read(dev, B43_PHY_VERSION_OFDM); /* Dummy read */ | 439 | b43_phy_read(dev, B43_PHY_VERSION_OFDM); /* Dummy read */ |
478 | } | 440 | } |
@@ -538,8 +500,7 @@ static void b43_wa_boards_g(struct b43_wldev *dev) | |||
538 | b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX, 2, 0x0001); | 500 | b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX, 2, 0x0001); |
539 | if ((bus->sprom.boardflags_lo & B43_BFL_EXTLNA) && | 501 | if ((bus->sprom.boardflags_lo & B43_BFL_EXTLNA) && |
540 | (phy->rev >= 7)) { | 502 | (phy->rev >= 7)) { |
541 | b43_phy_write(dev, B43_PHY_EXTG(0x11), | 503 | b43_phy_mask(dev, B43_PHY_EXTG(0x11), 0xF7FF); |
542 | b43_phy_read(dev, B43_PHY_EXTG(0x11)) & 0xF7FF); | ||
543 | b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX, 0x0020, 0x0001); | 504 | b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX, 0x0020, 0x0001); |
544 | b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX, 0x0021, 0x0001); | 505 | b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX, 0x0021, 0x0001); |
545 | b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX, 0x0022, 0x0001); | 506 | b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX, 0x0022, 0x0001); |
diff --git a/drivers/net/wireless/hostap/hostap.h b/drivers/net/wireless/hostap/hostap.h index 2453deaa3e00..ce8721fbc10e 100644 --- a/drivers/net/wireless/hostap/hostap.h +++ b/drivers/net/wireless/hostap/hostap.h | |||
@@ -31,7 +31,7 @@ void hostap_dump_rx_header(const char *name, | |||
31 | void hostap_dump_tx_header(const char *name, | 31 | void hostap_dump_tx_header(const char *name, |
32 | const struct hfa384x_tx_frame *tx); | 32 | const struct hfa384x_tx_frame *tx); |
33 | extern const struct header_ops hostap_80211_ops; | 33 | extern const struct header_ops hostap_80211_ops; |
34 | int hostap_80211_get_hdrlen(u16 fc); | 34 | int hostap_80211_get_hdrlen(__le16 fc); |
35 | struct net_device_stats *hostap_get_stats(struct net_device *dev); | 35 | struct net_device_stats *hostap_get_stats(struct net_device *dev); |
36 | void hostap_setup_dev(struct net_device *dev, local_info_t *local, | 36 | void hostap_setup_dev(struct net_device *dev, local_info_t *local, |
37 | int type); | 37 | int type); |
diff --git a/drivers/net/wireless/hostap/hostap_80211.h b/drivers/net/wireless/hostap/hostap_80211.h index 3a9474d9a907..2e9fb0f383fc 100644 --- a/drivers/net/wireless/hostap/hostap_80211.h +++ b/drivers/net/wireless/hostap/hostap_80211.h | |||
@@ -2,7 +2,7 @@ | |||
2 | #define HOSTAP_80211_H | 2 | #define HOSTAP_80211_H |
3 | 3 | ||
4 | #include <linux/types.h> | 4 | #include <linux/types.h> |
5 | #include <net/ieee80211.h> | 5 | #include <linux/skbuff.h> |
6 | 6 | ||
7 | struct hostap_ieee80211_mgmt { | 7 | struct hostap_ieee80211_mgmt { |
8 | __le16 frame_control; | 8 | __le16 frame_control; |
diff --git a/drivers/net/wireless/hostap/hostap_80211_rx.c b/drivers/net/wireless/hostap/hostap_80211_rx.c index 241756318da4..7ba318e84dec 100644 --- a/drivers/net/wireless/hostap/hostap_80211_rx.c +++ b/drivers/net/wireless/hostap/hostap_80211_rx.c | |||
@@ -1,5 +1,6 @@ | |||
1 | #include <linux/etherdevice.h> | 1 | #include <linux/etherdevice.h> |
2 | #include <net/lib80211.h> | 2 | #include <net/lib80211.h> |
3 | #include <linux/if_arp.h> | ||
3 | 4 | ||
4 | #include "hostap_80211.h" | 5 | #include "hostap_80211.h" |
5 | #include "hostap.h" | 6 | #include "hostap.h" |
@@ -17,10 +18,10 @@ static unsigned char bridge_tunnel_header[] = | |||
17 | void hostap_dump_rx_80211(const char *name, struct sk_buff *skb, | 18 | void hostap_dump_rx_80211(const char *name, struct sk_buff *skb, |
18 | struct hostap_80211_rx_status *rx_stats) | 19 | struct hostap_80211_rx_status *rx_stats) |
19 | { | 20 | { |
20 | struct ieee80211_hdr_4addr *hdr; | 21 | struct ieee80211_hdr *hdr; |
21 | u16 fc; | 22 | u16 fc; |
22 | 23 | ||
23 | hdr = (struct ieee80211_hdr_4addr *) skb->data; | 24 | hdr = (struct ieee80211_hdr *) skb->data; |
24 | 25 | ||
25 | printk(KERN_DEBUG "%s: RX signal=%d noise=%d rate=%d len=%d " | 26 | printk(KERN_DEBUG "%s: RX signal=%d noise=%d rate=%d len=%d " |
26 | "jiffies=%ld\n", | 27 | "jiffies=%ld\n", |
@@ -30,9 +31,10 @@ void hostap_dump_rx_80211(const char *name, struct sk_buff *skb, | |||
30 | if (skb->len < 2) | 31 | if (skb->len < 2) |
31 | return; | 32 | return; |
32 | 33 | ||
33 | fc = le16_to_cpu(hdr->frame_ctl); | 34 | fc = le16_to_cpu(hdr->frame_control); |
34 | printk(KERN_DEBUG " FC=0x%04x (type=%d:%d)%s%s", | 35 | printk(KERN_DEBUG " FC=0x%04x (type=%d:%d)%s%s", |
35 | fc, WLAN_FC_GET_TYPE(fc) >> 2, WLAN_FC_GET_STYPE(fc) >> 4, | 36 | fc, (fc & IEEE80211_FCTL_FTYPE) >> 2, |
37 | (fc & IEEE80211_FCTL_STYPE) >> 4, | ||
36 | fc & IEEE80211_FCTL_TODS ? " [ToDS]" : "", | 38 | fc & IEEE80211_FCTL_TODS ? " [ToDS]" : "", |
37 | fc & IEEE80211_FCTL_FROMDS ? " [FromDS]" : ""); | 39 | fc & IEEE80211_FCTL_FROMDS ? " [FromDS]" : ""); |
38 | 40 | ||
@@ -42,7 +44,7 @@ void hostap_dump_rx_80211(const char *name, struct sk_buff *skb, | |||
42 | } | 44 | } |
43 | 45 | ||
44 | printk(" dur=0x%04x seq=0x%04x\n", le16_to_cpu(hdr->duration_id), | 46 | printk(" dur=0x%04x seq=0x%04x\n", le16_to_cpu(hdr->duration_id), |
45 | le16_to_cpu(hdr->seq_ctl)); | 47 | le16_to_cpu(hdr->seq_ctrl)); |
46 | 48 | ||
47 | printk(KERN_DEBUG " A1=%pM", hdr->addr1); | 49 | printk(KERN_DEBUG " A1=%pM", hdr->addr1); |
48 | printk(" A2=%pM", hdr->addr2); | 50 | printk(" A2=%pM", hdr->addr2); |
@@ -63,7 +65,7 @@ int prism2_rx_80211(struct net_device *dev, struct sk_buff *skb, | |||
63 | int hdrlen, phdrlen, head_need, tail_need; | 65 | int hdrlen, phdrlen, head_need, tail_need; |
64 | u16 fc; | 66 | u16 fc; |
65 | int prism_header, ret; | 67 | int prism_header, ret; |
66 | struct ieee80211_hdr_4addr *fhdr; | 68 | struct ieee80211_hdr *fhdr; |
67 | 69 | ||
68 | iface = netdev_priv(dev); | 70 | iface = netdev_priv(dev); |
69 | local = iface->local; | 71 | local = iface->local; |
@@ -84,8 +86,8 @@ int prism2_rx_80211(struct net_device *dev, struct sk_buff *skb, | |||
84 | phdrlen = 0; | 86 | phdrlen = 0; |
85 | } | 87 | } |
86 | 88 | ||
87 | fhdr = (struct ieee80211_hdr_4addr *) skb->data; | 89 | fhdr = (struct ieee80211_hdr *) skb->data; |
88 | fc = le16_to_cpu(fhdr->frame_ctl); | 90 | fc = le16_to_cpu(fhdr->frame_control); |
89 | 91 | ||
90 | if (type == PRISM2_RX_MGMT && (fc & IEEE80211_FCTL_VERS)) { | 92 | if (type == PRISM2_RX_MGMT && (fc & IEEE80211_FCTL_VERS)) { |
91 | printk(KERN_DEBUG "%s: dropped management frame with header " | 93 | printk(KERN_DEBUG "%s: dropped management frame with header " |
@@ -94,7 +96,7 @@ int prism2_rx_80211(struct net_device *dev, struct sk_buff *skb, | |||
94 | return 0; | 96 | return 0; |
95 | } | 97 | } |
96 | 98 | ||
97 | hdrlen = hostap_80211_get_hdrlen(fc); | 99 | hdrlen = hostap_80211_get_hdrlen(fhdr->frame_control); |
98 | 100 | ||
99 | /* check if there is enough room for extra data; if not, expand skb | 101 | /* check if there is enough room for extra data; if not, expand skb |
100 | * buffer to be large enough for the changes */ | 102 | * buffer to be large enough for the changes */ |
@@ -247,21 +249,21 @@ prism2_frag_cache_find(local_info_t *local, unsigned int seq, | |||
247 | 249 | ||
248 | /* Called only as a tasklet (software IRQ) */ | 250 | /* Called only as a tasklet (software IRQ) */ |
249 | static struct sk_buff * | 251 | static struct sk_buff * |
250 | prism2_frag_cache_get(local_info_t *local, struct ieee80211_hdr_4addr *hdr) | 252 | prism2_frag_cache_get(local_info_t *local, struct ieee80211_hdr *hdr) |
251 | { | 253 | { |
252 | struct sk_buff *skb = NULL; | 254 | struct sk_buff *skb = NULL; |
253 | u16 sc; | 255 | u16 sc; |
254 | unsigned int frag, seq; | 256 | unsigned int frag, seq; |
255 | struct prism2_frag_entry *entry; | 257 | struct prism2_frag_entry *entry; |
256 | 258 | ||
257 | sc = le16_to_cpu(hdr->seq_ctl); | 259 | sc = le16_to_cpu(hdr->seq_ctrl); |
258 | frag = WLAN_GET_SEQ_FRAG(sc); | 260 | frag = sc & IEEE80211_SCTL_FRAG; |
259 | seq = WLAN_GET_SEQ_SEQ(sc) >> 4; | 261 | seq = (sc & IEEE80211_SCTL_SEQ) >> 4; |
260 | 262 | ||
261 | if (frag == 0) { | 263 | if (frag == 0) { |
262 | /* Reserve enough space to fit maximum frame length */ | 264 | /* Reserve enough space to fit maximum frame length */ |
263 | skb = dev_alloc_skb(local->dev->mtu + | 265 | skb = dev_alloc_skb(local->dev->mtu + |
264 | sizeof(struct ieee80211_hdr_4addr) + | 266 | sizeof(struct ieee80211_hdr) + |
265 | 8 /* LLC */ + | 267 | 8 /* LLC */ + |
266 | 2 /* alignment */ + | 268 | 2 /* alignment */ + |
267 | 8 /* WEP */ + ETH_ALEN /* WDS */); | 269 | 8 /* WEP */ + ETH_ALEN /* WDS */); |
@@ -299,14 +301,14 @@ prism2_frag_cache_get(local_info_t *local, struct ieee80211_hdr_4addr *hdr) | |||
299 | 301 | ||
300 | /* Called only as a tasklet (software IRQ) */ | 302 | /* Called only as a tasklet (software IRQ) */ |
301 | static int prism2_frag_cache_invalidate(local_info_t *local, | 303 | static int prism2_frag_cache_invalidate(local_info_t *local, |
302 | struct ieee80211_hdr_4addr *hdr) | 304 | struct ieee80211_hdr *hdr) |
303 | { | 305 | { |
304 | u16 sc; | 306 | u16 sc; |
305 | unsigned int seq; | 307 | unsigned int seq; |
306 | struct prism2_frag_entry *entry; | 308 | struct prism2_frag_entry *entry; |
307 | 309 | ||
308 | sc = le16_to_cpu(hdr->seq_ctl); | 310 | sc = le16_to_cpu(hdr->seq_ctrl); |
309 | seq = WLAN_GET_SEQ_SEQ(sc) >> 4; | 311 | seq = (sc & IEEE80211_SCTL_SEQ) >> 4; |
310 | 312 | ||
311 | entry = prism2_frag_cache_find(local, seq, -1, hdr->addr2, hdr->addr1); | 313 | entry = prism2_frag_cache_find(local, seq, -1, hdr->addr2, hdr->addr1); |
312 | 314 | ||
@@ -472,10 +474,8 @@ hostap_rx_frame_mgmt(local_info_t *local, struct sk_buff *skb, | |||
472 | struct hostap_80211_rx_status *rx_stats, u16 type, | 474 | struct hostap_80211_rx_status *rx_stats, u16 type, |
473 | u16 stype) | 475 | u16 stype) |
474 | { | 476 | { |
475 | if (local->iw_mode == IW_MODE_MASTER) { | 477 | if (local->iw_mode == IW_MODE_MASTER) |
476 | hostap_update_sta_ps(local, (struct ieee80211_hdr_4addr *) | 478 | hostap_update_sta_ps(local, (struct ieee80211_hdr *) skb->data); |
477 | skb->data); | ||
478 | } | ||
479 | 479 | ||
480 | if (local->hostapd && type == IEEE80211_FTYPE_MGMT) { | 480 | if (local->hostapd && type == IEEE80211_FTYPE_MGMT) { |
481 | if (stype == IEEE80211_STYPE_BEACON && | 481 | if (stype == IEEE80211_STYPE_BEACON && |
@@ -552,8 +552,8 @@ static struct net_device *prism2_rx_get_wds(local_info_t *local, | |||
552 | 552 | ||
553 | 553 | ||
554 | static int | 554 | static int |
555 | hostap_rx_frame_wds(local_info_t *local, struct ieee80211_hdr_4addr *hdr, | 555 | hostap_rx_frame_wds(local_info_t *local, struct ieee80211_hdr *hdr, u16 fc, |
556 | u16 fc, struct net_device **wds) | 556 | struct net_device **wds) |
557 | { | 557 | { |
558 | /* FIX: is this really supposed to accept WDS frames only in Master | 558 | /* FIX: is this really supposed to accept WDS frames only in Master |
559 | * mode? What about Repeater or Managed with WDS frames? */ | 559 | * mode? What about Repeater or Managed with WDS frames? */ |
@@ -611,14 +611,14 @@ static int hostap_is_eapol_frame(local_info_t *local, struct sk_buff *skb) | |||
611 | { | 611 | { |
612 | struct net_device *dev = local->dev; | 612 | struct net_device *dev = local->dev; |
613 | u16 fc, ethertype; | 613 | u16 fc, ethertype; |
614 | struct ieee80211_hdr_4addr *hdr; | 614 | struct ieee80211_hdr *hdr; |
615 | u8 *pos; | 615 | u8 *pos; |
616 | 616 | ||
617 | if (skb->len < 24) | 617 | if (skb->len < 24) |
618 | return 0; | 618 | return 0; |
619 | 619 | ||
620 | hdr = (struct ieee80211_hdr_4addr *) skb->data; | 620 | hdr = (struct ieee80211_hdr *) skb->data; |
621 | fc = le16_to_cpu(hdr->frame_ctl); | 621 | fc = le16_to_cpu(hdr->frame_control); |
622 | 622 | ||
623 | /* check that the frame is unicast frame to us */ | 623 | /* check that the frame is unicast frame to us */ |
624 | if ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) == | 624 | if ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) == |
@@ -651,14 +651,14 @@ static int | |||
651 | hostap_rx_frame_decrypt(local_info_t *local, struct sk_buff *skb, | 651 | hostap_rx_frame_decrypt(local_info_t *local, struct sk_buff *skb, |
652 | struct lib80211_crypt_data *crypt) | 652 | struct lib80211_crypt_data *crypt) |
653 | { | 653 | { |
654 | struct ieee80211_hdr_4addr *hdr; | 654 | struct ieee80211_hdr *hdr; |
655 | int res, hdrlen; | 655 | int res, hdrlen; |
656 | 656 | ||
657 | if (crypt == NULL || crypt->ops->decrypt_mpdu == NULL) | 657 | if (crypt == NULL || crypt->ops->decrypt_mpdu == NULL) |
658 | return 0; | 658 | return 0; |
659 | 659 | ||
660 | hdr = (struct ieee80211_hdr_4addr *) skb->data; | 660 | hdr = (struct ieee80211_hdr *) skb->data; |
661 | hdrlen = hostap_80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl)); | 661 | hdrlen = hostap_80211_get_hdrlen(hdr->frame_control); |
662 | 662 | ||
663 | if (local->tkip_countermeasures && | 663 | if (local->tkip_countermeasures && |
664 | strcmp(crypt->ops->name, "TKIP") == 0) { | 664 | strcmp(crypt->ops->name, "TKIP") == 0) { |
@@ -689,14 +689,14 @@ static int | |||
689 | hostap_rx_frame_decrypt_msdu(local_info_t *local, struct sk_buff *skb, | 689 | hostap_rx_frame_decrypt_msdu(local_info_t *local, struct sk_buff *skb, |
690 | int keyidx, struct lib80211_crypt_data *crypt) | 690 | int keyidx, struct lib80211_crypt_data *crypt) |
691 | { | 691 | { |
692 | struct ieee80211_hdr_4addr *hdr; | 692 | struct ieee80211_hdr *hdr; |
693 | int res, hdrlen; | 693 | int res, hdrlen; |
694 | 694 | ||
695 | if (crypt == NULL || crypt->ops->decrypt_msdu == NULL) | 695 | if (crypt == NULL || crypt->ops->decrypt_msdu == NULL) |
696 | return 0; | 696 | return 0; |
697 | 697 | ||
698 | hdr = (struct ieee80211_hdr_4addr *) skb->data; | 698 | hdr = (struct ieee80211_hdr *) skb->data; |
699 | hdrlen = hostap_80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl)); | 699 | hdrlen = hostap_80211_get_hdrlen(hdr->frame_control); |
700 | 700 | ||
701 | atomic_inc(&crypt->refcnt); | 701 | atomic_inc(&crypt->refcnt); |
702 | res = crypt->ops->decrypt_msdu(skb, keyidx, hdrlen, crypt->priv); | 702 | res = crypt->ops->decrypt_msdu(skb, keyidx, hdrlen, crypt->priv); |
@@ -720,7 +720,7 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb, | |||
720 | { | 720 | { |
721 | struct hostap_interface *iface; | 721 | struct hostap_interface *iface; |
722 | local_info_t *local; | 722 | local_info_t *local; |
723 | struct ieee80211_hdr_4addr *hdr; | 723 | struct ieee80211_hdr *hdr; |
724 | size_t hdrlen; | 724 | size_t hdrlen; |
725 | u16 fc, type, stype, sc; | 725 | u16 fc, type, stype, sc; |
726 | struct net_device *wds = NULL; | 726 | struct net_device *wds = NULL; |
@@ -747,18 +747,18 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb, | |||
747 | dev = local->ddev; | 747 | dev = local->ddev; |
748 | iface = netdev_priv(dev); | 748 | iface = netdev_priv(dev); |
749 | 749 | ||
750 | hdr = (struct ieee80211_hdr_4addr *) skb->data; | 750 | hdr = (struct ieee80211_hdr *) skb->data; |
751 | stats = hostap_get_stats(dev); | 751 | stats = hostap_get_stats(dev); |
752 | 752 | ||
753 | if (skb->len < 10) | 753 | if (skb->len < 10) |
754 | goto rx_dropped; | 754 | goto rx_dropped; |
755 | 755 | ||
756 | fc = le16_to_cpu(hdr->frame_ctl); | 756 | fc = le16_to_cpu(hdr->frame_control); |
757 | type = WLAN_FC_GET_TYPE(fc); | 757 | type = fc & IEEE80211_FCTL_FTYPE; |
758 | stype = WLAN_FC_GET_STYPE(fc); | 758 | stype = fc & IEEE80211_FCTL_STYPE; |
759 | sc = le16_to_cpu(hdr->seq_ctl); | 759 | sc = le16_to_cpu(hdr->seq_ctrl); |
760 | frag = WLAN_GET_SEQ_FRAG(sc); | 760 | frag = sc & IEEE80211_SCTL_FRAG; |
761 | hdrlen = hostap_80211_get_hdrlen(fc); | 761 | hdrlen = hostap_80211_get_hdrlen(hdr->frame_control); |
762 | 762 | ||
763 | /* Put this code here so that we avoid duplicating it in all | 763 | /* Put this code here so that we avoid duplicating it in all |
764 | * Rx paths. - Jean II */ | 764 | * Rx paths. - Jean II */ |
@@ -918,7 +918,7 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb, | |||
918 | if (local->host_decrypt && (fc & IEEE80211_FCTL_PROTECTED) && | 918 | if (local->host_decrypt && (fc & IEEE80211_FCTL_PROTECTED) && |
919 | (keyidx = hostap_rx_frame_decrypt(local, skb, crypt)) < 0) | 919 | (keyidx = hostap_rx_frame_decrypt(local, skb, crypt)) < 0) |
920 | goto rx_dropped; | 920 | goto rx_dropped; |
921 | hdr = (struct ieee80211_hdr_4addr *) skb->data; | 921 | hdr = (struct ieee80211_hdr *) skb->data; |
922 | 922 | ||
923 | /* skb: hdr + (possibly fragmented) plaintext payload */ | 923 | /* skb: hdr + (possibly fragmented) plaintext payload */ |
924 | 924 | ||
@@ -931,7 +931,7 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb, | |||
931 | printk(KERN_DEBUG "%s: Rx cannot get skb from " | 931 | printk(KERN_DEBUG "%s: Rx cannot get skb from " |
932 | "fragment cache (morefrag=%d seq=%u frag=%u)\n", | 932 | "fragment cache (morefrag=%d seq=%u frag=%u)\n", |
933 | dev->name, (fc & IEEE80211_FCTL_MOREFRAGS) != 0, | 933 | dev->name, (fc & IEEE80211_FCTL_MOREFRAGS) != 0, |
934 | WLAN_GET_SEQ_SEQ(sc) >> 4, frag); | 934 | (sc & IEEE80211_SCTL_SEQ) >> 4, frag); |
935 | goto rx_dropped; | 935 | goto rx_dropped; |
936 | } | 936 | } |
937 | 937 | ||
@@ -972,7 +972,7 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb, | |||
972 | /* this was the last fragment and the frame will be | 972 | /* this was the last fragment and the frame will be |
973 | * delivered, so remove skb from fragment cache */ | 973 | * delivered, so remove skb from fragment cache */ |
974 | skb = frag_skb; | 974 | skb = frag_skb; |
975 | hdr = (struct ieee80211_hdr_4addr *) skb->data; | 975 | hdr = (struct ieee80211_hdr *) skb->data; |
976 | prism2_frag_cache_invalidate(local, hdr); | 976 | prism2_frag_cache_invalidate(local, hdr); |
977 | } | 977 | } |
978 | 978 | ||
@@ -983,7 +983,7 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb, | |||
983 | hostap_rx_frame_decrypt_msdu(local, skb, keyidx, crypt)) | 983 | hostap_rx_frame_decrypt_msdu(local, skb, keyidx, crypt)) |
984 | goto rx_dropped; | 984 | goto rx_dropped; |
985 | 985 | ||
986 | hdr = (struct ieee80211_hdr_4addr *) skb->data; | 986 | hdr = (struct ieee80211_hdr *) skb->data; |
987 | if (crypt && !(fc & IEEE80211_FCTL_PROTECTED) && !local->open_wep) { | 987 | if (crypt && !(fc & IEEE80211_FCTL_PROTECTED) && !local->open_wep) { |
988 | if (local->ieee_802_1x && | 988 | if (local->ieee_802_1x && |
989 | hostap_is_eapol_frame(local, skb)) { | 989 | hostap_is_eapol_frame(local, skb)) { |
diff --git a/drivers/net/wireless/hostap/hostap_80211_tx.c b/drivers/net/wireless/hostap/hostap_80211_tx.c index 078a010f39a0..6693423f63fe 100644 --- a/drivers/net/wireless/hostap/hostap_80211_tx.c +++ b/drivers/net/wireless/hostap/hostap_80211_tx.c | |||
@@ -15,10 +15,10 @@ static unsigned char bridge_tunnel_header[] = | |||
15 | 15 | ||
16 | void hostap_dump_tx_80211(const char *name, struct sk_buff *skb) | 16 | void hostap_dump_tx_80211(const char *name, struct sk_buff *skb) |
17 | { | 17 | { |
18 | struct ieee80211_hdr_4addr *hdr; | 18 | struct ieee80211_hdr *hdr; |
19 | u16 fc; | 19 | u16 fc; |
20 | 20 | ||
21 | hdr = (struct ieee80211_hdr_4addr *) skb->data; | 21 | hdr = (struct ieee80211_hdr *) skb->data; |
22 | 22 | ||
23 | printk(KERN_DEBUG "%s: TX len=%d jiffies=%ld\n", | 23 | printk(KERN_DEBUG "%s: TX len=%d jiffies=%ld\n", |
24 | name, skb->len, jiffies); | 24 | name, skb->len, jiffies); |
@@ -26,9 +26,10 @@ void hostap_dump_tx_80211(const char *name, struct sk_buff *skb) | |||
26 | if (skb->len < 2) | 26 | if (skb->len < 2) |
27 | return; | 27 | return; |
28 | 28 | ||
29 | fc = le16_to_cpu(hdr->frame_ctl); | 29 | fc = le16_to_cpu(hdr->frame_control); |
30 | printk(KERN_DEBUG " FC=0x%04x (type=%d:%d)%s%s", | 30 | printk(KERN_DEBUG " FC=0x%04x (type=%d:%d)%s%s", |
31 | fc, WLAN_FC_GET_TYPE(fc) >> 2, WLAN_FC_GET_STYPE(fc) >> 4, | 31 | fc, (fc & IEEE80211_FCTL_FTYPE) >> 2, |
32 | (fc & IEEE80211_FCTL_STYPE) >> 4, | ||
32 | fc & IEEE80211_FCTL_TODS ? " [ToDS]" : "", | 33 | fc & IEEE80211_FCTL_TODS ? " [ToDS]" : "", |
33 | fc & IEEE80211_FCTL_FROMDS ? " [FromDS]" : ""); | 34 | fc & IEEE80211_FCTL_FROMDS ? " [FromDS]" : ""); |
34 | 35 | ||
@@ -38,7 +39,7 @@ void hostap_dump_tx_80211(const char *name, struct sk_buff *skb) | |||
38 | } | 39 | } |
39 | 40 | ||
40 | printk(" dur=0x%04x seq=0x%04x\n", le16_to_cpu(hdr->duration_id), | 41 | printk(" dur=0x%04x seq=0x%04x\n", le16_to_cpu(hdr->duration_id), |
41 | le16_to_cpu(hdr->seq_ctl)); | 42 | le16_to_cpu(hdr->seq_ctrl)); |
42 | 43 | ||
43 | printk(KERN_DEBUG " A1=%pM", hdr->addr1); | 44 | printk(KERN_DEBUG " A1=%pM", hdr->addr1); |
44 | printk(" A2=%pM", hdr->addr2); | 45 | printk(" A2=%pM", hdr->addr2); |
@@ -57,7 +58,7 @@ int hostap_data_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
57 | struct hostap_interface *iface; | 58 | struct hostap_interface *iface; |
58 | local_info_t *local; | 59 | local_info_t *local; |
59 | int need_headroom, need_tailroom = 0; | 60 | int need_headroom, need_tailroom = 0; |
60 | struct ieee80211_hdr_4addr hdr; | 61 | struct ieee80211_hdr hdr; |
61 | u16 fc, ethertype = 0; | 62 | u16 fc, ethertype = 0; |
62 | enum { | 63 | enum { |
63 | WDS_NO = 0, WDS_OWN_FRAME, WDS_COMPLIANT_FRAME | 64 | WDS_NO = 0, WDS_OWN_FRAME, WDS_COMPLIANT_FRAME |
@@ -201,7 +202,7 @@ int hostap_data_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
201 | memcpy(&hdr.addr3, local->bssid, ETH_ALEN); | 202 | memcpy(&hdr.addr3, local->bssid, ETH_ALEN); |
202 | } | 203 | } |
203 | 204 | ||
204 | hdr.frame_ctl = cpu_to_le16(fc); | 205 | hdr.frame_control = cpu_to_le16(fc); |
205 | 206 | ||
206 | skb_pull(skb, skip_header_bytes); | 207 | skb_pull(skb, skip_header_bytes); |
207 | need_headroom = local->func->need_tx_headroom + hdr_len + encaps_len; | 208 | need_headroom = local->func->need_tx_headroom + hdr_len + encaps_len; |
@@ -265,7 +266,7 @@ int hostap_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
265 | struct hostap_interface *iface; | 266 | struct hostap_interface *iface; |
266 | local_info_t *local; | 267 | local_info_t *local; |
267 | struct hostap_skb_tx_data *meta; | 268 | struct hostap_skb_tx_data *meta; |
268 | struct ieee80211_hdr_4addr *hdr; | 269 | struct ieee80211_hdr *hdr; |
269 | u16 fc; | 270 | u16 fc; |
270 | 271 | ||
271 | iface = netdev_priv(dev); | 272 | iface = netdev_priv(dev); |
@@ -287,10 +288,10 @@ int hostap_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
287 | meta->iface = iface; | 288 | meta->iface = iface; |
288 | 289 | ||
289 | if (skb->len >= IEEE80211_DATA_HDR3_LEN + sizeof(rfc1042_header) + 2) { | 290 | if (skb->len >= IEEE80211_DATA_HDR3_LEN + sizeof(rfc1042_header) + 2) { |
290 | hdr = (struct ieee80211_hdr_4addr *) skb->data; | 291 | hdr = (struct ieee80211_hdr *) skb->data; |
291 | fc = le16_to_cpu(hdr->frame_ctl); | 292 | fc = le16_to_cpu(hdr->frame_control); |
292 | if (WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_DATA && | 293 | if (ieee80211_is_data(hdr->frame_control) && |
293 | WLAN_FC_GET_STYPE(fc) == IEEE80211_STYPE_DATA) { | 294 | (fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_DATA) { |
294 | u8 *pos = &skb->data[IEEE80211_DATA_HDR3_LEN + | 295 | u8 *pos = &skb->data[IEEE80211_DATA_HDR3_LEN + |
295 | sizeof(rfc1042_header)]; | 296 | sizeof(rfc1042_header)]; |
296 | meta->ethertype = (pos[0] << 8) | pos[1]; | 297 | meta->ethertype = (pos[0] << 8) | pos[1]; |
@@ -310,8 +311,7 @@ static struct sk_buff * hostap_tx_encrypt(struct sk_buff *skb, | |||
310 | { | 311 | { |
311 | struct hostap_interface *iface; | 312 | struct hostap_interface *iface; |
312 | local_info_t *local; | 313 | local_info_t *local; |
313 | struct ieee80211_hdr_4addr *hdr; | 314 | struct ieee80211_hdr *hdr; |
314 | u16 fc; | ||
315 | int prefix_len, postfix_len, hdr_len, res; | 315 | int prefix_len, postfix_len, hdr_len, res; |
316 | 316 | ||
317 | iface = netdev_priv(skb->dev); | 317 | iface = netdev_priv(skb->dev); |
@@ -324,7 +324,7 @@ static struct sk_buff * hostap_tx_encrypt(struct sk_buff *skb, | |||
324 | 324 | ||
325 | if (local->tkip_countermeasures && | 325 | if (local->tkip_countermeasures && |
326 | strcmp(crypt->ops->name, "TKIP") == 0) { | 326 | strcmp(crypt->ops->name, "TKIP") == 0) { |
327 | hdr = (struct ieee80211_hdr_4addr *) skb->data; | 327 | hdr = (struct ieee80211_hdr *) skb->data; |
328 | if (net_ratelimit()) { | 328 | if (net_ratelimit()) { |
329 | printk(KERN_DEBUG "%s: TKIP countermeasures: dropped " | 329 | printk(KERN_DEBUG "%s: TKIP countermeasures: dropped " |
330 | "TX packet to %pM\n", | 330 | "TX packet to %pM\n", |
@@ -349,9 +349,8 @@ static struct sk_buff * hostap_tx_encrypt(struct sk_buff *skb, | |||
349 | return NULL; | 349 | return NULL; |
350 | } | 350 | } |
351 | 351 | ||
352 | hdr = (struct ieee80211_hdr_4addr *) skb->data; | 352 | hdr = (struct ieee80211_hdr *) skb->data; |
353 | fc = le16_to_cpu(hdr->frame_ctl); | 353 | hdr_len = hostap_80211_get_hdrlen(hdr->frame_control); |
354 | hdr_len = hostap_80211_get_hdrlen(fc); | ||
355 | 354 | ||
356 | /* Host-based IEEE 802.11 fragmentation for TX is not yet supported, so | 355 | /* Host-based IEEE 802.11 fragmentation for TX is not yet supported, so |
357 | * call both MSDU and MPDU encryption functions from here. */ | 356 | * call both MSDU and MPDU encryption functions from here. */ |
@@ -384,7 +383,7 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
384 | ap_tx_ret tx_ret; | 383 | ap_tx_ret tx_ret; |
385 | struct hostap_skb_tx_data *meta; | 384 | struct hostap_skb_tx_data *meta; |
386 | int no_encrypt = 0; | 385 | int no_encrypt = 0; |
387 | struct ieee80211_hdr_4addr *hdr; | 386 | struct ieee80211_hdr *hdr; |
388 | 387 | ||
389 | iface = netdev_priv(dev); | 388 | iface = netdev_priv(dev); |
390 | local = iface->local; | 389 | local = iface->local; |
@@ -427,14 +426,14 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
427 | tx_ret = hostap_handle_sta_tx(local, &tx); | 426 | tx_ret = hostap_handle_sta_tx(local, &tx); |
428 | skb = tx.skb; | 427 | skb = tx.skb; |
429 | meta = (struct hostap_skb_tx_data *) skb->cb; | 428 | meta = (struct hostap_skb_tx_data *) skb->cb; |
430 | hdr = (struct ieee80211_hdr_4addr *) skb->data; | 429 | hdr = (struct ieee80211_hdr *) skb->data; |
431 | fc = le16_to_cpu(hdr->frame_ctl); | 430 | fc = le16_to_cpu(hdr->frame_control); |
432 | switch (tx_ret) { | 431 | switch (tx_ret) { |
433 | case AP_TX_CONTINUE: | 432 | case AP_TX_CONTINUE: |
434 | break; | 433 | break; |
435 | case AP_TX_CONTINUE_NOT_AUTHORIZED: | 434 | case AP_TX_CONTINUE_NOT_AUTHORIZED: |
436 | if (local->ieee_802_1x && | 435 | if (local->ieee_802_1x && |
437 | WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_DATA && | 436 | ieee80211_is_data(hdr->frame_control) && |
438 | meta->ethertype != ETH_P_PAE && | 437 | meta->ethertype != ETH_P_PAE && |
439 | !(meta->flags & HOSTAP_TX_FLAGS_WDS)) { | 438 | !(meta->flags & HOSTAP_TX_FLAGS_WDS)) { |
440 | printk(KERN_DEBUG "%s: dropped frame to unauthorized " | 439 | printk(KERN_DEBUG "%s: dropped frame to unauthorized " |
@@ -469,10 +468,10 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
469 | 468 | ||
470 | /* remove special version from the frame header */ | 469 | /* remove special version from the frame header */ |
471 | fc &= ~IEEE80211_FCTL_VERS; | 470 | fc &= ~IEEE80211_FCTL_VERS; |
472 | hdr->frame_ctl = cpu_to_le16(fc); | 471 | hdr->frame_control = cpu_to_le16(fc); |
473 | } | 472 | } |
474 | 473 | ||
475 | if (WLAN_FC_GET_TYPE(fc) != IEEE80211_FTYPE_DATA) { | 474 | if (!ieee80211_is_data(hdr->frame_control)) { |
476 | no_encrypt = 1; | 475 | no_encrypt = 1; |
477 | tx.crypt = NULL; | 476 | tx.crypt = NULL; |
478 | } | 477 | } |
@@ -493,9 +492,9 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
493 | /* Add ISWEP flag both for firmware and host based encryption | 492 | /* Add ISWEP flag both for firmware and host based encryption |
494 | */ | 493 | */ |
495 | fc |= IEEE80211_FCTL_PROTECTED; | 494 | fc |= IEEE80211_FCTL_PROTECTED; |
496 | hdr->frame_ctl = cpu_to_le16(fc); | 495 | hdr->frame_control = cpu_to_le16(fc); |
497 | } else if (local->drop_unencrypted && | 496 | } else if (local->drop_unencrypted && |
498 | WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_DATA && | 497 | ieee80211_is_data(hdr->frame_control) && |
499 | meta->ethertype != ETH_P_PAE) { | 498 | meta->ethertype != ETH_P_PAE) { |
500 | if (net_ratelimit()) { | 499 | if (net_ratelimit()) { |
501 | printk(KERN_DEBUG "%s: dropped unencrypted TX data " | 500 | printk(KERN_DEBUG "%s: dropped unencrypted TX data " |
diff --git a/drivers/net/wireless/hostap/hostap_ap.c b/drivers/net/wireless/hostap/hostap_ap.c index 0a4bf94dddfb..645862fd37d1 100644 --- a/drivers/net/wireless/hostap/hostap_ap.c +++ b/drivers/net/wireless/hostap/hostap_ap.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/proc_fs.h> | 19 | #include <linux/proc_fs.h> |
20 | #include <linux/delay.h> | 20 | #include <linux/delay.h> |
21 | #include <linux/random.h> | 21 | #include <linux/random.h> |
22 | #include <linux/if_arp.h> | ||
22 | 23 | ||
23 | #include "hostap_wlan.h" | 24 | #include "hostap_wlan.h" |
24 | #include "hostap.h" | 25 | #include "hostap.h" |
@@ -588,26 +589,22 @@ void hostap_check_sta_fw_version(struct ap_data *ap, int sta_fw_ver) | |||
588 | static void hostap_ap_tx_cb(struct sk_buff *skb, int ok, void *data) | 589 | static void hostap_ap_tx_cb(struct sk_buff *skb, int ok, void *data) |
589 | { | 590 | { |
590 | struct ap_data *ap = data; | 591 | struct ap_data *ap = data; |
591 | u16 fc; | 592 | struct ieee80211_hdr *hdr; |
592 | struct ieee80211_hdr_4addr *hdr; | ||
593 | 593 | ||
594 | if (!ap->local->hostapd || !ap->local->apdev) { | 594 | if (!ap->local->hostapd || !ap->local->apdev) { |
595 | dev_kfree_skb(skb); | 595 | dev_kfree_skb(skb); |
596 | return; | 596 | return; |
597 | } | 597 | } |
598 | 598 | ||
599 | hdr = (struct ieee80211_hdr_4addr *) skb->data; | ||
600 | fc = le16_to_cpu(hdr->frame_ctl); | ||
601 | |||
602 | /* Pass the TX callback frame to the hostapd; use 802.11 header version | 599 | /* Pass the TX callback frame to the hostapd; use 802.11 header version |
603 | * 1 to indicate failure (no ACK) and 2 success (frame ACKed) */ | 600 | * 1 to indicate failure (no ACK) and 2 success (frame ACKed) */ |
604 | 601 | ||
605 | fc &= ~IEEE80211_FCTL_VERS; | 602 | hdr = (struct ieee80211_hdr *) skb->data; |
606 | fc |= ok ? BIT(1) : BIT(0); | 603 | hdr->frame_control &= cpu_to_le16(~IEEE80211_FCTL_VERS); |
607 | hdr->frame_ctl = cpu_to_le16(fc); | 604 | hdr->frame_control |= cpu_to_le16(ok ? BIT(1) : BIT(0)); |
608 | 605 | ||
609 | skb->dev = ap->local->apdev; | 606 | skb->dev = ap->local->apdev; |
610 | skb_pull(skb, hostap_80211_get_hdrlen(fc)); | 607 | skb_pull(skb, hostap_80211_get_hdrlen(hdr->frame_control)); |
611 | skb->pkt_type = PACKET_OTHERHOST; | 608 | skb->pkt_type = PACKET_OTHERHOST; |
612 | skb->protocol = cpu_to_be16(ETH_P_802_2); | 609 | skb->protocol = cpu_to_be16(ETH_P_802_2); |
613 | memset(skb->cb, 0, sizeof(skb->cb)); | 610 | memset(skb->cb, 0, sizeof(skb->cb)); |
@@ -621,8 +618,8 @@ static void hostap_ap_tx_cb_auth(struct sk_buff *skb, int ok, void *data) | |||
621 | { | 618 | { |
622 | struct ap_data *ap = data; | 619 | struct ap_data *ap = data; |
623 | struct net_device *dev = ap->local->dev; | 620 | struct net_device *dev = ap->local->dev; |
624 | struct ieee80211_hdr_4addr *hdr; | 621 | struct ieee80211_hdr *hdr; |
625 | u16 fc, auth_alg, auth_transaction, status; | 622 | u16 auth_alg, auth_transaction, status; |
626 | __le16 *pos; | 623 | __le16 *pos; |
627 | struct sta_info *sta = NULL; | 624 | struct sta_info *sta = NULL; |
628 | char *txt = NULL; | 625 | char *txt = NULL; |
@@ -632,10 +629,8 @@ static void hostap_ap_tx_cb_auth(struct sk_buff *skb, int ok, void *data) | |||
632 | return; | 629 | return; |
633 | } | 630 | } |
634 | 631 | ||
635 | hdr = (struct ieee80211_hdr_4addr *) skb->data; | 632 | hdr = (struct ieee80211_hdr *) skb->data; |
636 | fc = le16_to_cpu(hdr->frame_ctl); | 633 | if (!ieee80211_is_auth(hdr->frame_control) || |
637 | if (WLAN_FC_GET_TYPE(fc) != IEEE80211_FTYPE_MGMT || | ||
638 | WLAN_FC_GET_STYPE(fc) != IEEE80211_STYPE_AUTH || | ||
639 | skb->len < IEEE80211_MGMT_HDR_LEN + 6) { | 634 | skb->len < IEEE80211_MGMT_HDR_LEN + 6) { |
640 | printk(KERN_DEBUG "%s: hostap_ap_tx_cb_auth received invalid " | 635 | printk(KERN_DEBUG "%s: hostap_ap_tx_cb_auth received invalid " |
641 | "frame\n", dev->name); | 636 | "frame\n", dev->name); |
@@ -691,7 +686,7 @@ static void hostap_ap_tx_cb_assoc(struct sk_buff *skb, int ok, void *data) | |||
691 | { | 686 | { |
692 | struct ap_data *ap = data; | 687 | struct ap_data *ap = data; |
693 | struct net_device *dev = ap->local->dev; | 688 | struct net_device *dev = ap->local->dev; |
694 | struct ieee80211_hdr_4addr *hdr; | 689 | struct ieee80211_hdr *hdr; |
695 | u16 fc, status; | 690 | u16 fc, status; |
696 | __le16 *pos; | 691 | __le16 *pos; |
697 | struct sta_info *sta = NULL; | 692 | struct sta_info *sta = NULL; |
@@ -702,11 +697,10 @@ static void hostap_ap_tx_cb_assoc(struct sk_buff *skb, int ok, void *data) | |||
702 | return; | 697 | return; |
703 | } | 698 | } |
704 | 699 | ||
705 | hdr = (struct ieee80211_hdr_4addr *) skb->data; | 700 | hdr = (struct ieee80211_hdr *) skb->data; |
706 | fc = le16_to_cpu(hdr->frame_ctl); | 701 | fc = le16_to_cpu(hdr->frame_control); |
707 | if (WLAN_FC_GET_TYPE(fc) != IEEE80211_FTYPE_MGMT || | 702 | if ((!ieee80211_is_assoc_resp(hdr->frame_control) && |
708 | (WLAN_FC_GET_STYPE(fc) != IEEE80211_STYPE_ASSOC_RESP && | 703 | !ieee80211_is_reassoc_resp(hdr->frame_control)) || |
709 | WLAN_FC_GET_STYPE(fc) != IEEE80211_STYPE_REASSOC_RESP) || | ||
710 | skb->len < IEEE80211_MGMT_HDR_LEN + 4) { | 704 | skb->len < IEEE80211_MGMT_HDR_LEN + 4) { |
711 | printk(KERN_DEBUG "%s: hostap_ap_tx_cb_assoc received invalid " | 705 | printk(KERN_DEBUG "%s: hostap_ap_tx_cb_assoc received invalid " |
712 | "frame\n", dev->name); | 706 | "frame\n", dev->name); |
@@ -757,12 +751,12 @@ static void hostap_ap_tx_cb_assoc(struct sk_buff *skb, int ok, void *data) | |||
757 | static void hostap_ap_tx_cb_poll(struct sk_buff *skb, int ok, void *data) | 751 | static void hostap_ap_tx_cb_poll(struct sk_buff *skb, int ok, void *data) |
758 | { | 752 | { |
759 | struct ap_data *ap = data; | 753 | struct ap_data *ap = data; |
760 | struct ieee80211_hdr_4addr *hdr; | 754 | struct ieee80211_hdr *hdr; |
761 | struct sta_info *sta; | 755 | struct sta_info *sta; |
762 | 756 | ||
763 | if (skb->len < 24) | 757 | if (skb->len < 24) |
764 | goto fail; | 758 | goto fail; |
765 | hdr = (struct ieee80211_hdr_4addr *) skb->data; | 759 | hdr = (struct ieee80211_hdr *) skb->data; |
766 | if (ok) { | 760 | if (ok) { |
767 | spin_lock(&ap->sta_table_lock); | 761 | spin_lock(&ap->sta_table_lock); |
768 | sta = ap_get_sta(ap, hdr->addr1); | 762 | sta = ap_get_sta(ap, hdr->addr1); |
@@ -917,7 +911,7 @@ static void prism2_send_mgmt(struct net_device *dev, | |||
917 | { | 911 | { |
918 | struct hostap_interface *iface; | 912 | struct hostap_interface *iface; |
919 | local_info_t *local; | 913 | local_info_t *local; |
920 | struct ieee80211_hdr_4addr *hdr; | 914 | struct ieee80211_hdr *hdr; |
921 | u16 fc; | 915 | u16 fc; |
922 | struct sk_buff *skb; | 916 | struct sk_buff *skb; |
923 | struct hostap_skb_tx_data *meta; | 917 | struct hostap_skb_tx_data *meta; |
@@ -942,8 +936,8 @@ static void prism2_send_mgmt(struct net_device *dev, | |||
942 | } | 936 | } |
943 | 937 | ||
944 | fc = type_subtype; | 938 | fc = type_subtype; |
945 | hdrlen = hostap_80211_get_hdrlen(fc); | 939 | hdrlen = hostap_80211_get_hdrlen(cpu_to_le16(type_subtype)); |
946 | hdr = (struct ieee80211_hdr_4addr *) skb_put(skb, hdrlen); | 940 | hdr = (struct ieee80211_hdr *) skb_put(skb, hdrlen); |
947 | if (body) | 941 | if (body) |
948 | memcpy(skb_put(skb, body_len), body, body_len); | 942 | memcpy(skb_put(skb, body_len), body, body_len); |
949 | 943 | ||
@@ -954,11 +948,11 @@ static void prism2_send_mgmt(struct net_device *dev, | |||
954 | 948 | ||
955 | 949 | ||
956 | memcpy(hdr->addr1, addr, ETH_ALEN); /* DA / RA */ | 950 | memcpy(hdr->addr1, addr, ETH_ALEN); /* DA / RA */ |
957 | if (WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_DATA) { | 951 | if (ieee80211_is_data(hdr->frame_control)) { |
958 | fc |= IEEE80211_FCTL_FROMDS; | 952 | fc |= IEEE80211_FCTL_FROMDS; |
959 | memcpy(hdr->addr2, dev->dev_addr, ETH_ALEN); /* BSSID */ | 953 | memcpy(hdr->addr2, dev->dev_addr, ETH_ALEN); /* BSSID */ |
960 | memcpy(hdr->addr3, dev->dev_addr, ETH_ALEN); /* SA */ | 954 | memcpy(hdr->addr3, dev->dev_addr, ETH_ALEN); /* SA */ |
961 | } else if (WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_CTL) { | 955 | } else if (ieee80211_is_ctl(hdr->frame_control)) { |
962 | /* control:ACK does not have addr2 or addr3 */ | 956 | /* control:ACK does not have addr2 or addr3 */ |
963 | memset(hdr->addr2, 0, ETH_ALEN); | 957 | memset(hdr->addr2, 0, ETH_ALEN); |
964 | memset(hdr->addr3, 0, ETH_ALEN); | 958 | memset(hdr->addr3, 0, ETH_ALEN); |
@@ -967,7 +961,7 @@ static void prism2_send_mgmt(struct net_device *dev, | |||
967 | memcpy(hdr->addr3, dev->dev_addr, ETH_ALEN); /* BSSID */ | 961 | memcpy(hdr->addr3, dev->dev_addr, ETH_ALEN); /* BSSID */ |
968 | } | 962 | } |
969 | 963 | ||
970 | hdr->frame_ctl = cpu_to_le16(fc); | 964 | hdr->frame_control = cpu_to_le16(fc); |
971 | 965 | ||
972 | meta = (struct hostap_skb_tx_data *) skb->cb; | 966 | meta = (struct hostap_skb_tx_data *) skb->cb; |
973 | memset(meta, 0, sizeof(*meta)); | 967 | memset(meta, 0, sizeof(*meta)); |
@@ -1284,22 +1278,21 @@ static void handle_authen(local_info_t *local, struct sk_buff *skb, | |||
1284 | struct hostap_80211_rx_status *rx_stats) | 1278 | struct hostap_80211_rx_status *rx_stats) |
1285 | { | 1279 | { |
1286 | struct net_device *dev = local->dev; | 1280 | struct net_device *dev = local->dev; |
1287 | struct ieee80211_hdr_4addr *hdr = (struct ieee80211_hdr_4addr *) skb->data; | 1281 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; |
1288 | size_t hdrlen; | 1282 | size_t hdrlen; |
1289 | struct ap_data *ap = local->ap; | 1283 | struct ap_data *ap = local->ap; |
1290 | char body[8 + WLAN_AUTH_CHALLENGE_LEN], *challenge = NULL; | 1284 | char body[8 + WLAN_AUTH_CHALLENGE_LEN], *challenge = NULL; |
1291 | int len, olen; | 1285 | int len, olen; |
1292 | u16 auth_alg, auth_transaction, status_code; | 1286 | u16 auth_alg, auth_transaction, status_code; |
1293 | __le16 *pos; | 1287 | __le16 *pos; |
1294 | u16 resp = WLAN_STATUS_SUCCESS, fc; | 1288 | u16 resp = WLAN_STATUS_SUCCESS; |
1295 | struct sta_info *sta = NULL; | 1289 | struct sta_info *sta = NULL; |
1296 | struct lib80211_crypt_data *crypt; | 1290 | struct lib80211_crypt_data *crypt; |
1297 | char *txt = ""; | 1291 | char *txt = ""; |
1298 | 1292 | ||
1299 | len = skb->len - IEEE80211_MGMT_HDR_LEN; | 1293 | len = skb->len - IEEE80211_MGMT_HDR_LEN; |
1300 | 1294 | ||
1301 | fc = le16_to_cpu(hdr->frame_ctl); | 1295 | hdrlen = hostap_80211_get_hdrlen(hdr->frame_control); |
1302 | hdrlen = hostap_80211_get_hdrlen(fc); | ||
1303 | 1296 | ||
1304 | if (len < 6) { | 1297 | if (len < 6) { |
1305 | PDEBUG(DEBUG_AP, "%s: handle_authen - too short payload " | 1298 | PDEBUG(DEBUG_AP, "%s: handle_authen - too short payload " |
@@ -1435,7 +1428,7 @@ static void handle_authen(local_info_t *local, struct sk_buff *skb, | |||
1435 | challenge == NULL || | 1428 | challenge == NULL || |
1436 | memcmp(sta->u.sta.challenge, challenge, | 1429 | memcmp(sta->u.sta.challenge, challenge, |
1437 | WLAN_AUTH_CHALLENGE_LEN) != 0 || | 1430 | WLAN_AUTH_CHALLENGE_LEN) != 0 || |
1438 | !(fc & IEEE80211_FCTL_PROTECTED)) { | 1431 | !ieee80211_has_protected(hdr->frame_control)) { |
1439 | txt = "challenge response incorrect"; | 1432 | txt = "challenge response incorrect"; |
1440 | resp = WLAN_STATUS_CHALLENGE_FAIL; | 1433 | resp = WLAN_STATUS_CHALLENGE_FAIL; |
1441 | goto fail; | 1434 | goto fail; |
@@ -1488,7 +1481,7 @@ static void handle_authen(local_info_t *local, struct sk_buff *skb, | |||
1488 | "trans#=%d stat=%d len=%d fc=%04x) ==> %d (%s)\n", | 1481 | "trans#=%d stat=%d len=%d fc=%04x) ==> %d (%s)\n", |
1489 | dev->name, hdr->addr2, | 1482 | dev->name, hdr->addr2, |
1490 | auth_alg, auth_transaction, status_code, len, | 1483 | auth_alg, auth_transaction, status_code, len, |
1491 | fc, resp, txt); | 1484 | le16_to_cpu(hdr->frame_control), resp, txt); |
1492 | } | 1485 | } |
1493 | } | 1486 | } |
1494 | 1487 | ||
@@ -1498,7 +1491,7 @@ static void handle_assoc(local_info_t *local, struct sk_buff *skb, | |||
1498 | struct hostap_80211_rx_status *rx_stats, int reassoc) | 1491 | struct hostap_80211_rx_status *rx_stats, int reassoc) |
1499 | { | 1492 | { |
1500 | struct net_device *dev = local->dev; | 1493 | struct net_device *dev = local->dev; |
1501 | struct ieee80211_hdr_4addr *hdr = (struct ieee80211_hdr_4addr *) skb->data; | 1494 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; |
1502 | char body[12], *p, *lpos; | 1495 | char body[12], *p, *lpos; |
1503 | int len, left; | 1496 | int len, left; |
1504 | __le16 *pos; | 1497 | __le16 *pos; |
@@ -1707,7 +1700,7 @@ static void handle_deauth(local_info_t *local, struct sk_buff *skb, | |||
1707 | struct hostap_80211_rx_status *rx_stats) | 1700 | struct hostap_80211_rx_status *rx_stats) |
1708 | { | 1701 | { |
1709 | struct net_device *dev = local->dev; | 1702 | struct net_device *dev = local->dev; |
1710 | struct ieee80211_hdr_4addr *hdr = (struct ieee80211_hdr_4addr *) skb->data; | 1703 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; |
1711 | char *body = (char *) (skb->data + IEEE80211_MGMT_HDR_LEN); | 1704 | char *body = (char *) (skb->data + IEEE80211_MGMT_HDR_LEN); |
1712 | int len; | 1705 | int len; |
1713 | u16 reason_code; | 1706 | u16 reason_code; |
@@ -1749,7 +1742,7 @@ static void handle_disassoc(local_info_t *local, struct sk_buff *skb, | |||
1749 | struct hostap_80211_rx_status *rx_stats) | 1742 | struct hostap_80211_rx_status *rx_stats) |
1750 | { | 1743 | { |
1751 | struct net_device *dev = local->dev; | 1744 | struct net_device *dev = local->dev; |
1752 | struct ieee80211_hdr_4addr *hdr = (struct ieee80211_hdr_4addr *) skb->data; | 1745 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; |
1753 | char *body = skb->data + IEEE80211_MGMT_HDR_LEN; | 1746 | char *body = skb->data + IEEE80211_MGMT_HDR_LEN; |
1754 | int len; | 1747 | int len; |
1755 | u16 reason_code; | 1748 | u16 reason_code; |
@@ -1788,7 +1781,7 @@ static void handle_disassoc(local_info_t *local, struct sk_buff *skb, | |||
1788 | 1781 | ||
1789 | /* Called only as a scheduled task for pending AP frames. */ | 1782 | /* Called only as a scheduled task for pending AP frames. */ |
1790 | static void ap_handle_data_nullfunc(local_info_t *local, | 1783 | static void ap_handle_data_nullfunc(local_info_t *local, |
1791 | struct ieee80211_hdr_4addr *hdr) | 1784 | struct ieee80211_hdr *hdr) |
1792 | { | 1785 | { |
1793 | struct net_device *dev = local->dev; | 1786 | struct net_device *dev = local->dev; |
1794 | 1787 | ||
@@ -1805,7 +1798,7 @@ static void ap_handle_data_nullfunc(local_info_t *local, | |||
1805 | 1798 | ||
1806 | /* Called only as a scheduled task for pending AP frames. */ | 1799 | /* Called only as a scheduled task for pending AP frames. */ |
1807 | static void ap_handle_dropped_data(local_info_t *local, | 1800 | static void ap_handle_dropped_data(local_info_t *local, |
1808 | struct ieee80211_hdr_4addr *hdr) | 1801 | struct ieee80211_hdr *hdr) |
1809 | { | 1802 | { |
1810 | struct net_device *dev = local->dev; | 1803 | struct net_device *dev = local->dev; |
1811 | struct sta_info *sta; | 1804 | struct sta_info *sta; |
@@ -1863,7 +1856,7 @@ static void pspoll_send_buffered(local_info_t *local, struct sta_info *sta, | |||
1863 | 1856 | ||
1864 | /* Called only as a scheduled task for pending AP frames. */ | 1857 | /* Called only as a scheduled task for pending AP frames. */ |
1865 | static void handle_pspoll(local_info_t *local, | 1858 | static void handle_pspoll(local_info_t *local, |
1866 | struct ieee80211_hdr_4addr *hdr, | 1859 | struct ieee80211_hdr *hdr, |
1867 | struct hostap_80211_rx_status *rx_stats) | 1860 | struct hostap_80211_rx_status *rx_stats) |
1868 | { | 1861 | { |
1869 | struct net_device *dev = local->dev; | 1862 | struct net_device *dev = local->dev; |
@@ -1872,8 +1865,7 @@ static void handle_pspoll(local_info_t *local, | |||
1872 | struct sk_buff *skb; | 1865 | struct sk_buff *skb; |
1873 | 1866 | ||
1874 | PDEBUG(DEBUG_PS2, "handle_pspoll: BSSID=%pM, TA=%pM PWRMGT=%d\n", | 1867 | PDEBUG(DEBUG_PS2, "handle_pspoll: BSSID=%pM, TA=%pM PWRMGT=%d\n", |
1875 | hdr->addr1, hdr->addr2, | 1868 | hdr->addr1, hdr->addr2, !!ieee80211_has_pm(hdr->frame_control)); |
1876 | !!(le16_to_cpu(hdr->frame_ctl) & IEEE80211_FCTL_PM)); | ||
1877 | 1869 | ||
1878 | if (memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN)) { | 1870 | if (memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN)) { |
1879 | PDEBUG(DEBUG_AP, | 1871 | PDEBUG(DEBUG_AP, |
@@ -1984,7 +1976,7 @@ static void handle_wds_oper_queue(struct work_struct *work) | |||
1984 | static void handle_beacon(local_info_t *local, struct sk_buff *skb, | 1976 | static void handle_beacon(local_info_t *local, struct sk_buff *skb, |
1985 | struct hostap_80211_rx_status *rx_stats) | 1977 | struct hostap_80211_rx_status *rx_stats) |
1986 | { | 1978 | { |
1987 | struct ieee80211_hdr_4addr *hdr = (struct ieee80211_hdr_4addr *) skb->data; | 1979 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; |
1988 | char *body = skb->data + IEEE80211_MGMT_HDR_LEN; | 1980 | char *body = skb->data + IEEE80211_MGMT_HDR_LEN; |
1989 | int len, left; | 1981 | int len, left; |
1990 | u16 beacon_int, capability; | 1982 | u16 beacon_int, capability; |
@@ -2143,14 +2135,14 @@ static void handle_ap_item(local_info_t *local, struct sk_buff *skb, | |||
2143 | struct net_device *dev = local->dev; | 2135 | struct net_device *dev = local->dev; |
2144 | #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | 2136 | #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ |
2145 | u16 fc, type, stype; | 2137 | u16 fc, type, stype; |
2146 | struct ieee80211_hdr_4addr *hdr; | 2138 | struct ieee80211_hdr *hdr; |
2147 | 2139 | ||
2148 | /* FIX: should give skb->len to handler functions and check that the | 2140 | /* FIX: should give skb->len to handler functions and check that the |
2149 | * buffer is long enough */ | 2141 | * buffer is long enough */ |
2150 | hdr = (struct ieee80211_hdr_4addr *) skb->data; | 2142 | hdr = (struct ieee80211_hdr *) skb->data; |
2151 | fc = le16_to_cpu(hdr->frame_ctl); | 2143 | fc = le16_to_cpu(hdr->frame_control); |
2152 | type = WLAN_FC_GET_TYPE(fc); | 2144 | type = fc & IEEE80211_FCTL_FTYPE; |
2153 | stype = WLAN_FC_GET_STYPE(fc); | 2145 | stype = fc & IEEE80211_FCTL_STYPE; |
2154 | 2146 | ||
2155 | #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | 2147 | #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT |
2156 | if (!local->hostapd && type == IEEE80211_FTYPE_DATA) { | 2148 | if (!local->hostapd && type == IEEE80211_FTYPE_DATA) { |
@@ -2262,8 +2254,7 @@ void hostap_rx(struct net_device *dev, struct sk_buff *skb, | |||
2262 | { | 2254 | { |
2263 | struct hostap_interface *iface; | 2255 | struct hostap_interface *iface; |
2264 | local_info_t *local; | 2256 | local_info_t *local; |
2265 | u16 fc; | 2257 | struct ieee80211_hdr *hdr; |
2266 | struct ieee80211_hdr_4addr *hdr; | ||
2267 | 2258 | ||
2268 | iface = netdev_priv(dev); | 2259 | iface = netdev_priv(dev); |
2269 | local = iface->local; | 2260 | local = iface->local; |
@@ -2273,12 +2264,10 @@ void hostap_rx(struct net_device *dev, struct sk_buff *skb, | |||
2273 | 2264 | ||
2274 | local->stats.rx_packets++; | 2265 | local->stats.rx_packets++; |
2275 | 2266 | ||
2276 | hdr = (struct ieee80211_hdr_4addr *) skb->data; | 2267 | hdr = (struct ieee80211_hdr *) skb->data; |
2277 | fc = le16_to_cpu(hdr->frame_ctl); | ||
2278 | 2268 | ||
2279 | if (local->ap->ap_policy == AP_OTHER_AP_SKIP_ALL && | 2269 | if (local->ap->ap_policy == AP_OTHER_AP_SKIP_ALL && |
2280 | WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_MGMT && | 2270 | ieee80211_is_beacon(hdr->frame_control)) |
2281 | WLAN_FC_GET_STYPE(fc) == IEEE80211_STYPE_BEACON) | ||
2282 | goto drop; | 2271 | goto drop; |
2283 | 2272 | ||
2284 | skb->protocol = cpu_to_be16(ETH_P_HOSTAP); | 2273 | skb->protocol = cpu_to_be16(ETH_P_HOSTAP); |
@@ -2294,7 +2283,7 @@ void hostap_rx(struct net_device *dev, struct sk_buff *skb, | |||
2294 | static void schedule_packet_send(local_info_t *local, struct sta_info *sta) | 2283 | static void schedule_packet_send(local_info_t *local, struct sta_info *sta) |
2295 | { | 2284 | { |
2296 | struct sk_buff *skb; | 2285 | struct sk_buff *skb; |
2297 | struct ieee80211_hdr_4addr *hdr; | 2286 | struct ieee80211_hdr *hdr; |
2298 | struct hostap_80211_rx_status rx_stats; | 2287 | struct hostap_80211_rx_status rx_stats; |
2299 | 2288 | ||
2300 | if (skb_queue_empty(&sta->tx_buf)) | 2289 | if (skb_queue_empty(&sta->tx_buf)) |
@@ -2307,10 +2296,10 @@ static void schedule_packet_send(local_info_t *local, struct sta_info *sta) | |||
2307 | return; | 2296 | return; |
2308 | } | 2297 | } |
2309 | 2298 | ||
2310 | hdr = (struct ieee80211_hdr_4addr *) skb_put(skb, 16); | 2299 | hdr = (struct ieee80211_hdr *) skb_put(skb, 16); |
2311 | 2300 | ||
2312 | /* Generate a fake pspoll frame to start packet delivery */ | 2301 | /* Generate a fake pspoll frame to start packet delivery */ |
2313 | hdr->frame_ctl = cpu_to_le16( | 2302 | hdr->frame_control = cpu_to_le16( |
2314 | IEEE80211_FTYPE_CTL | IEEE80211_STYPE_PSPOLL); | 2303 | IEEE80211_FTYPE_CTL | IEEE80211_STYPE_PSPOLL); |
2315 | memcpy(hdr->addr1, local->dev->dev_addr, ETH_ALEN); | 2304 | memcpy(hdr->addr1, local->dev->dev_addr, ETH_ALEN); |
2316 | memcpy(hdr->addr2, sta->addr, ETH_ALEN); | 2305 | memcpy(hdr->addr2, sta->addr, ETH_ALEN); |
@@ -2689,7 +2678,7 @@ ap_tx_ret hostap_handle_sta_tx(local_info_t *local, struct hostap_tx_data *tx) | |||
2689 | struct sta_info *sta = NULL; | 2678 | struct sta_info *sta = NULL; |
2690 | struct sk_buff *skb = tx->skb; | 2679 | struct sk_buff *skb = tx->skb; |
2691 | int set_tim, ret; | 2680 | int set_tim, ret; |
2692 | struct ieee80211_hdr_4addr *hdr; | 2681 | struct ieee80211_hdr *hdr; |
2693 | struct hostap_skb_tx_data *meta; | 2682 | struct hostap_skb_tx_data *meta; |
2694 | 2683 | ||
2695 | meta = (struct hostap_skb_tx_data *) skb->cb; | 2684 | meta = (struct hostap_skb_tx_data *) skb->cb; |
@@ -2698,7 +2687,7 @@ ap_tx_ret hostap_handle_sta_tx(local_info_t *local, struct hostap_tx_data *tx) | |||
2698 | meta->iface->type == HOSTAP_INTERFACE_STA) | 2687 | meta->iface->type == HOSTAP_INTERFACE_STA) |
2699 | goto out; | 2688 | goto out; |
2700 | 2689 | ||
2701 | hdr = (struct ieee80211_hdr_4addr *) skb->data; | 2690 | hdr = (struct ieee80211_hdr *) skb->data; |
2702 | 2691 | ||
2703 | if (hdr->addr1[0] & 0x01) { | 2692 | if (hdr->addr1[0] & 0x01) { |
2704 | /* broadcast/multicast frame - no AP related processing */ | 2693 | /* broadcast/multicast frame - no AP related processing */ |
@@ -2753,7 +2742,7 @@ ap_tx_ret hostap_handle_sta_tx(local_info_t *local, struct hostap_tx_data *tx) | |||
2753 | 2742 | ||
2754 | if (meta->flags & HOSTAP_TX_FLAGS_ADD_MOREDATA) { | 2743 | if (meta->flags & HOSTAP_TX_FLAGS_ADD_MOREDATA) { |
2755 | /* indicate to STA that more frames follow */ | 2744 | /* indicate to STA that more frames follow */ |
2756 | hdr->frame_ctl |= | 2745 | hdr->frame_control |= |
2757 | cpu_to_le16(IEEE80211_FCTL_MOREDATA); | 2746 | cpu_to_le16(IEEE80211_FCTL_MOREDATA); |
2758 | } | 2747 | } |
2759 | 2748 | ||
@@ -2828,10 +2817,10 @@ void hostap_handle_sta_release(void *ptr) | |||
2828 | void hostap_handle_sta_tx_exc(local_info_t *local, struct sk_buff *skb) | 2817 | void hostap_handle_sta_tx_exc(local_info_t *local, struct sk_buff *skb) |
2829 | { | 2818 | { |
2830 | struct sta_info *sta; | 2819 | struct sta_info *sta; |
2831 | struct ieee80211_hdr_4addr *hdr; | 2820 | struct ieee80211_hdr *hdr; |
2832 | struct hostap_skb_tx_data *meta; | 2821 | struct hostap_skb_tx_data *meta; |
2833 | 2822 | ||
2834 | hdr = (struct ieee80211_hdr_4addr *) skb->data; | 2823 | hdr = (struct ieee80211_hdr *) skb->data; |
2835 | meta = (struct hostap_skb_tx_data *) skb->cb; | 2824 | meta = (struct hostap_skb_tx_data *) skb->cb; |
2836 | 2825 | ||
2837 | spin_lock(&local->ap->sta_table_lock); | 2826 | spin_lock(&local->ap->sta_table_lock); |
@@ -2898,8 +2887,8 @@ static void hostap_update_sta_ps2(local_info_t *local, struct sta_info *sta, | |||
2898 | 2887 | ||
2899 | 2888 | ||
2900 | /* Called only as a tasklet (software IRQ). Called for each RX frame to update | 2889 | /* Called only as a tasklet (software IRQ). Called for each RX frame to update |
2901 | * STA power saving state. pwrmgt is a flag from 802.11 frame_ctl field. */ | 2890 | * STA power saving state. pwrmgt is a flag from 802.11 frame_control field. */ |
2902 | int hostap_update_sta_ps(local_info_t *local, struct ieee80211_hdr_4addr *hdr) | 2891 | int hostap_update_sta_ps(local_info_t *local, struct ieee80211_hdr *hdr) |
2903 | { | 2892 | { |
2904 | struct sta_info *sta; | 2893 | struct sta_info *sta; |
2905 | u16 fc; | 2894 | u16 fc; |
@@ -2913,9 +2902,10 @@ int hostap_update_sta_ps(local_info_t *local, struct ieee80211_hdr_4addr *hdr) | |||
2913 | if (!sta) | 2902 | if (!sta) |
2914 | return -1; | 2903 | return -1; |
2915 | 2904 | ||
2916 | fc = le16_to_cpu(hdr->frame_ctl); | 2905 | fc = le16_to_cpu(hdr->frame_control); |
2917 | hostap_update_sta_ps2(local, sta, fc & IEEE80211_FCTL_PM, | 2906 | hostap_update_sta_ps2(local, sta, fc & IEEE80211_FCTL_PM, |
2918 | WLAN_FC_GET_TYPE(fc), WLAN_FC_GET_STYPE(fc)); | 2907 | fc & IEEE80211_FCTL_FTYPE, |
2908 | fc & IEEE80211_FCTL_STYPE); | ||
2919 | 2909 | ||
2920 | atomic_dec(&sta->users); | 2910 | atomic_dec(&sta->users); |
2921 | return 0; | 2911 | return 0; |
@@ -2932,16 +2922,16 @@ ap_rx_ret hostap_handle_sta_rx(local_info_t *local, struct net_device *dev, | |||
2932 | int ret; | 2922 | int ret; |
2933 | struct sta_info *sta; | 2923 | struct sta_info *sta; |
2934 | u16 fc, type, stype; | 2924 | u16 fc, type, stype; |
2935 | struct ieee80211_hdr_4addr *hdr; | 2925 | struct ieee80211_hdr *hdr; |
2936 | 2926 | ||
2937 | if (local->ap == NULL) | 2927 | if (local->ap == NULL) |
2938 | return AP_RX_CONTINUE; | 2928 | return AP_RX_CONTINUE; |
2939 | 2929 | ||
2940 | hdr = (struct ieee80211_hdr_4addr *) skb->data; | 2930 | hdr = (struct ieee80211_hdr *) skb->data; |
2941 | 2931 | ||
2942 | fc = le16_to_cpu(hdr->frame_ctl); | 2932 | fc = le16_to_cpu(hdr->frame_control); |
2943 | type = WLAN_FC_GET_TYPE(fc); | 2933 | type = fc & IEEE80211_FCTL_FTYPE; |
2944 | stype = WLAN_FC_GET_STYPE(fc); | 2934 | stype = fc & IEEE80211_FCTL_STYPE; |
2945 | 2935 | ||
2946 | spin_lock(&local->ap->sta_table_lock); | 2936 | spin_lock(&local->ap->sta_table_lock); |
2947 | sta = ap_get_sta(local->ap, hdr->addr2); | 2937 | sta = ap_get_sta(local->ap, hdr->addr2); |
@@ -3064,7 +3054,7 @@ ap_rx_ret hostap_handle_sta_rx(local_info_t *local, struct net_device *dev, | |||
3064 | 3054 | ||
3065 | /* Called only as a tasklet (software IRQ) */ | 3055 | /* Called only as a tasklet (software IRQ) */ |
3066 | int hostap_handle_sta_crypto(local_info_t *local, | 3056 | int hostap_handle_sta_crypto(local_info_t *local, |
3067 | struct ieee80211_hdr_4addr *hdr, | 3057 | struct ieee80211_hdr *hdr, |
3068 | struct lib80211_crypt_data **crypt, | 3058 | struct lib80211_crypt_data **crypt, |
3069 | void **sta_ptr) | 3059 | void **sta_ptr) |
3070 | { | 3060 | { |
@@ -3166,7 +3156,7 @@ int hostap_add_sta(struct ap_data *ap, u8 *sta_addr) | |||
3166 | 3156 | ||
3167 | /* Called only as a tasklet (software IRQ) */ | 3157 | /* Called only as a tasklet (software IRQ) */ |
3168 | int hostap_update_rx_stats(struct ap_data *ap, | 3158 | int hostap_update_rx_stats(struct ap_data *ap, |
3169 | struct ieee80211_hdr_4addr *hdr, | 3159 | struct ieee80211_hdr *hdr, |
3170 | struct hostap_80211_rx_status *rx_stats) | 3160 | struct hostap_80211_rx_status *rx_stats) |
3171 | { | 3161 | { |
3172 | struct sta_info *sta; | 3162 | struct sta_info *sta; |
diff --git a/drivers/net/wireless/hostap/hostap_ap.h b/drivers/net/wireless/hostap/hostap_ap.h index d36e4b175336..655ceeba9612 100644 --- a/drivers/net/wireless/hostap/hostap_ap.h +++ b/drivers/net/wireless/hostap/hostap_ap.h | |||
@@ -235,7 +235,7 @@ struct hostap_tx_data { | |||
235 | ap_tx_ret hostap_handle_sta_tx(local_info_t *local, struct hostap_tx_data *tx); | 235 | ap_tx_ret hostap_handle_sta_tx(local_info_t *local, struct hostap_tx_data *tx); |
236 | void hostap_handle_sta_release(void *ptr); | 236 | void hostap_handle_sta_release(void *ptr); |
237 | void hostap_handle_sta_tx_exc(local_info_t *local, struct sk_buff *skb); | 237 | void hostap_handle_sta_tx_exc(local_info_t *local, struct sk_buff *skb); |
238 | int hostap_update_sta_ps(local_info_t *local, struct ieee80211_hdr_4addr *hdr); | 238 | int hostap_update_sta_ps(local_info_t *local, struct ieee80211_hdr *hdr); |
239 | typedef enum { | 239 | typedef enum { |
240 | AP_RX_CONTINUE, AP_RX_DROP, AP_RX_EXIT, AP_RX_CONTINUE_NOT_AUTHORIZED | 240 | AP_RX_CONTINUE, AP_RX_DROP, AP_RX_EXIT, AP_RX_CONTINUE_NOT_AUTHORIZED |
241 | } ap_rx_ret; | 241 | } ap_rx_ret; |
@@ -243,13 +243,13 @@ ap_rx_ret hostap_handle_sta_rx(local_info_t *local, struct net_device *dev, | |||
243 | struct sk_buff *skb, | 243 | struct sk_buff *skb, |
244 | struct hostap_80211_rx_status *rx_stats, | 244 | struct hostap_80211_rx_status *rx_stats, |
245 | int wds); | 245 | int wds); |
246 | int hostap_handle_sta_crypto(local_info_t *local, struct ieee80211_hdr_4addr *hdr, | 246 | int hostap_handle_sta_crypto(local_info_t *local, struct ieee80211_hdr *hdr, |
247 | struct lib80211_crypt_data **crypt, | 247 | struct lib80211_crypt_data **crypt, |
248 | void **sta_ptr); | 248 | void **sta_ptr); |
249 | int hostap_is_sta_assoc(struct ap_data *ap, u8 *sta_addr); | 249 | int hostap_is_sta_assoc(struct ap_data *ap, u8 *sta_addr); |
250 | int hostap_is_sta_authorized(struct ap_data *ap, u8 *sta_addr); | 250 | int hostap_is_sta_authorized(struct ap_data *ap, u8 *sta_addr); |
251 | int hostap_add_sta(struct ap_data *ap, u8 *sta_addr); | 251 | int hostap_add_sta(struct ap_data *ap, u8 *sta_addr); |
252 | int hostap_update_rx_stats(struct ap_data *ap, struct ieee80211_hdr_4addr *hdr, | 252 | int hostap_update_rx_stats(struct ap_data *ap, struct ieee80211_hdr *hdr, |
253 | struct hostap_80211_rx_status *rx_stats); | 253 | struct hostap_80211_rx_status *rx_stats); |
254 | void hostap_update_rates(local_info_t *local); | 254 | void hostap_update_rates(local_info_t *local); |
255 | void hostap_add_wds_links(local_info_t *local); | 255 | void hostap_add_wds_links(local_info_t *local); |
diff --git a/drivers/net/wireless/hostap/hostap_hw.c b/drivers/net/wireless/hostap/hostap_hw.c index 0f27059bbe85..3d9e7b7a17b0 100644 --- a/drivers/net/wireless/hostap/hostap_hw.c +++ b/drivers/net/wireless/hostap/hostap_hw.c | |||
@@ -46,7 +46,6 @@ | |||
46 | #include <linux/rtnetlink.h> | 46 | #include <linux/rtnetlink.h> |
47 | #include <linux/wireless.h> | 47 | #include <linux/wireless.h> |
48 | #include <net/iw_handler.h> | 48 | #include <net/iw_handler.h> |
49 | #include <net/ieee80211.h> | ||
50 | #include <net/lib80211.h> | 49 | #include <net/lib80211.h> |
51 | #include <asm/irq.h> | 50 | #include <asm/irq.h> |
52 | 51 | ||
@@ -1840,8 +1839,8 @@ static int prism2_tx_80211(struct sk_buff *skb, struct net_device *dev) | |||
1840 | hdr_len = 24; | 1839 | hdr_len = 24; |
1841 | skb_copy_from_linear_data(skb, &txdesc.frame_control, hdr_len); | 1840 | skb_copy_from_linear_data(skb, &txdesc.frame_control, hdr_len); |
1842 | fc = le16_to_cpu(txdesc.frame_control); | 1841 | fc = le16_to_cpu(txdesc.frame_control); |
1843 | if (WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_DATA && | 1842 | if (ieee80211_is_data(txdesc.frame_control) && |
1844 | (fc & IEEE80211_FCTL_FROMDS) && (fc & IEEE80211_FCTL_TODS) && | 1843 | ieee80211_has_a4(txdesc.frame_control) && |
1845 | skb->len >= 30) { | 1844 | skb->len >= 30) { |
1846 | /* Addr4 */ | 1845 | /* Addr4 */ |
1847 | skb_copy_from_linear_data_offset(skb, hdr_len, txdesc.addr4, | 1846 | skb_copy_from_linear_data_offset(skb, hdr_len, txdesc.addr4, |
@@ -2082,7 +2081,7 @@ static void hostap_rx_skb(local_info_t *local, struct sk_buff *skb) | |||
2082 | stats.rate = rxdesc->rate; | 2081 | stats.rate = rxdesc->rate; |
2083 | 2082 | ||
2084 | /* Convert Prism2 RX structure into IEEE 802.11 header */ | 2083 | /* Convert Prism2 RX structure into IEEE 802.11 header */ |
2085 | hdrlen = hostap_80211_get_hdrlen(le16_to_cpu(rxdesc->frame_control)); | 2084 | hdrlen = hostap_80211_get_hdrlen(rxdesc->frame_control); |
2086 | if (hdrlen > rx_hdrlen) | 2085 | if (hdrlen > rx_hdrlen) |
2087 | hdrlen = rx_hdrlen; | 2086 | hdrlen = rx_hdrlen; |
2088 | 2087 | ||
@@ -2204,7 +2203,7 @@ static void hostap_tx_callback(local_info_t *local, | |||
2204 | return; | 2203 | return; |
2205 | } | 2204 | } |
2206 | 2205 | ||
2207 | hdrlen = hostap_80211_get_hdrlen(le16_to_cpu(txdesc->frame_control)); | 2206 | hdrlen = hostap_80211_get_hdrlen(txdesc->frame_control); |
2208 | len = le16_to_cpu(txdesc->data_len); | 2207 | len = le16_to_cpu(txdesc->data_len); |
2209 | skb = dev_alloc_skb(hdrlen + len); | 2208 | skb = dev_alloc_skb(hdrlen + len); |
2210 | if (skb == NULL) { | 2209 | if (skb == NULL) { |
@@ -2315,8 +2314,7 @@ static void hostap_sta_tx_exc_tasklet(unsigned long data) | |||
2315 | if (skb->len >= sizeof(*txdesc)) { | 2314 | if (skb->len >= sizeof(*txdesc)) { |
2316 | /* Convert Prism2 RX structure into IEEE 802.11 header | 2315 | /* Convert Prism2 RX structure into IEEE 802.11 header |
2317 | */ | 2316 | */ |
2318 | u16 fc = le16_to_cpu(txdesc->frame_control); | 2317 | int hdrlen = hostap_80211_get_hdrlen(txdesc->frame_control); |
2319 | int hdrlen = hostap_80211_get_hdrlen(fc); | ||
2320 | memmove(skb_pull(skb, sizeof(*txdesc) - hdrlen), | 2318 | memmove(skb_pull(skb, sizeof(*txdesc) - hdrlen), |
2321 | &txdesc->frame_control, hdrlen); | 2319 | &txdesc->frame_control, hdrlen); |
2322 | 2320 | ||
@@ -2394,12 +2392,12 @@ static void prism2_txexc(local_info_t *local) | |||
2394 | PDEBUG(DEBUG_EXTRA, " retry_count=%d tx_rate=%d fc=0x%04x " | 2392 | PDEBUG(DEBUG_EXTRA, " retry_count=%d tx_rate=%d fc=0x%04x " |
2395 | "(%s%s%s::%d%s%s)\n", | 2393 | "(%s%s%s::%d%s%s)\n", |
2396 | txdesc.retry_count, txdesc.tx_rate, fc, | 2394 | txdesc.retry_count, txdesc.tx_rate, fc, |
2397 | WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_MGMT ? "Mgmt" : "", | 2395 | ieee80211_is_mgmt(txdesc.frame_control) ? "Mgmt" : "", |
2398 | WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_CTL ? "Ctrl" : "", | 2396 | ieee80211_is_ctl(txdesc.frame_control) ? "Ctrl" : "", |
2399 | WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_DATA ? "Data" : "", | 2397 | ieee80211_is_data(txdesc.frame_control) ? "Data" : "", |
2400 | WLAN_FC_GET_STYPE(fc) >> 4, | 2398 | (fc & IEEE80211_FCTL_STYPE) >> 4, |
2401 | fc & IEEE80211_FCTL_TODS ? " ToDS" : "", | 2399 | ieee80211_has_tods(txdesc.frame_control) ? " ToDS" : "", |
2402 | fc & IEEE80211_FCTL_FROMDS ? " FromDS" : ""); | 2400 | ieee80211_has_fromds(txdesc.frame_control) ? " FromDS" : ""); |
2403 | PDEBUG(DEBUG_EXTRA, " A1=%pM A2=%pM A3=%pM A4=%pM\n", | 2401 | PDEBUG(DEBUG_EXTRA, " A1=%pM A2=%pM A3=%pM A4=%pM\n", |
2404 | txdesc.addr1, txdesc.addr2, | 2402 | txdesc.addr1, txdesc.addr2, |
2405 | txdesc.addr3, txdesc.addr4); | 2403 | txdesc.addr3, txdesc.addr4); |
diff --git a/drivers/net/wireless/hostap/hostap_info.c b/drivers/net/wireless/hostap/hostap_info.c index 99b4cf41edf2..6fa14a4e4b53 100644 --- a/drivers/net/wireless/hostap/hostap_info.c +++ b/drivers/net/wireless/hostap/hostap_info.c | |||
@@ -1,5 +1,6 @@ | |||
1 | /* Host AP driver Info Frame processing (part of hostap.o module) */ | 1 | /* Host AP driver Info Frame processing (part of hostap.o module) */ |
2 | 2 | ||
3 | #include <linux/if_arp.h> | ||
3 | #include "hostap_wlan.h" | 4 | #include "hostap_wlan.h" |
4 | #include "hostap.h" | 5 | #include "hostap.h" |
5 | #include "hostap_ap.h" | 6 | #include "hostap_ap.h" |
diff --git a/drivers/net/wireless/hostap/hostap_ioctl.c b/drivers/net/wireless/hostap/hostap_ioctl.c index 8618b3355eb4..3f2bda881a4f 100644 --- a/drivers/net/wireless/hostap/hostap_ioctl.c +++ b/drivers/net/wireless/hostap/hostap_ioctl.c | |||
@@ -2,6 +2,7 @@ | |||
2 | 2 | ||
3 | #include <linux/types.h> | 3 | #include <linux/types.h> |
4 | #include <linux/ethtool.h> | 4 | #include <linux/ethtool.h> |
5 | #include <linux/if_arp.h> | ||
5 | #include <net/lib80211.h> | 6 | #include <net/lib80211.h> |
6 | 7 | ||
7 | #include "hostap_wlan.h" | 8 | #include "hostap_wlan.h" |
diff --git a/drivers/net/wireless/hostap/hostap_main.c b/drivers/net/wireless/hostap/hostap_main.c index 02a312ca8607..5d55f92f654b 100644 --- a/drivers/net/wireless/hostap/hostap_main.c +++ b/drivers/net/wireless/hostap/hostap_main.c | |||
@@ -26,7 +26,6 @@ | |||
26 | #include <linux/etherdevice.h> | 26 | #include <linux/etherdevice.h> |
27 | #include <net/net_namespace.h> | 27 | #include <net/net_namespace.h> |
28 | #include <net/iw_handler.h> | 28 | #include <net/iw_handler.h> |
29 | #include <net/ieee80211.h> | ||
30 | #include <net/lib80211.h> | 29 | #include <net/lib80211.h> |
31 | #include <asm/uaccess.h> | 30 | #include <asm/uaccess.h> |
32 | 31 | ||
@@ -543,7 +542,8 @@ void hostap_dump_rx_header(const char *name, const struct hfa384x_rx_frame *rx) | |||
543 | fc = __le16_to_cpu(rx->frame_control); | 542 | fc = __le16_to_cpu(rx->frame_control); |
544 | printk(KERN_DEBUG " FC=0x%04x (type=%d:%d) dur=0x%04x seq=0x%04x " | 543 | printk(KERN_DEBUG " FC=0x%04x (type=%d:%d) dur=0x%04x seq=0x%04x " |
545 | "data_len=%d%s%s\n", | 544 | "data_len=%d%s%s\n", |
546 | fc, WLAN_FC_GET_TYPE(fc) >> 2, WLAN_FC_GET_STYPE(fc) >> 4, | 545 | fc, (fc & IEEE80211_FCTL_FTYPE) >> 2, |
546 | (fc & IEEE80211_FCTL_STYPE) >> 4, | ||
547 | __le16_to_cpu(rx->duration_id), __le16_to_cpu(rx->seq_ctrl), | 547 | __le16_to_cpu(rx->duration_id), __le16_to_cpu(rx->seq_ctrl), |
548 | __le16_to_cpu(rx->data_len), | 548 | __le16_to_cpu(rx->data_len), |
549 | fc & IEEE80211_FCTL_TODS ? " [ToDS]" : "", | 549 | fc & IEEE80211_FCTL_TODS ? " [ToDS]" : "", |
@@ -570,7 +570,8 @@ void hostap_dump_tx_header(const char *name, const struct hfa384x_tx_frame *tx) | |||
570 | fc = __le16_to_cpu(tx->frame_control); | 570 | fc = __le16_to_cpu(tx->frame_control); |
571 | printk(KERN_DEBUG " FC=0x%04x (type=%d:%d) dur=0x%04x seq=0x%04x " | 571 | printk(KERN_DEBUG " FC=0x%04x (type=%d:%d) dur=0x%04x seq=0x%04x " |
572 | "data_len=%d%s%s\n", | 572 | "data_len=%d%s%s\n", |
573 | fc, WLAN_FC_GET_TYPE(fc) >> 2, WLAN_FC_GET_STYPE(fc) >> 4, | 573 | fc, (fc & IEEE80211_FCTL_FTYPE) >> 2, |
574 | (fc & IEEE80211_FCTL_STYPE) >> 4, | ||
574 | __le16_to_cpu(tx->duration_id), __le16_to_cpu(tx->seq_ctrl), | 575 | __le16_to_cpu(tx->duration_id), __le16_to_cpu(tx->seq_ctrl), |
575 | __le16_to_cpu(tx->data_len), | 576 | __le16_to_cpu(tx->data_len), |
576 | fc & IEEE80211_FCTL_TODS ? " [ToDS]" : "", | 577 | fc & IEEE80211_FCTL_TODS ? " [ToDS]" : "", |
@@ -593,29 +594,16 @@ static int hostap_80211_header_parse(const struct sk_buff *skb, | |||
593 | } | 594 | } |
594 | 595 | ||
595 | 596 | ||
596 | int hostap_80211_get_hdrlen(u16 fc) | 597 | int hostap_80211_get_hdrlen(__le16 fc) |
597 | { | 598 | { |
598 | int hdrlen = 24; | 599 | if (ieee80211_is_data(fc) && ieee80211_has_a4 (fc)) |
599 | 600 | return 30; /* Addr4 */ | |
600 | switch (WLAN_FC_GET_TYPE(fc)) { | 601 | else if (ieee80211_is_cts(fc) || ieee80211_is_ack(fc)) |
601 | case IEEE80211_FTYPE_DATA: | 602 | return 10; |
602 | if ((fc & IEEE80211_FCTL_FROMDS) && (fc & IEEE80211_FCTL_TODS)) | 603 | else if (ieee80211_is_ctl(fc)) |
603 | hdrlen = 30; /* Addr4 */ | 604 | return 16; |
604 | break; | 605 | |
605 | case IEEE80211_FTYPE_CTL: | 606 | return 24; |
606 | switch (WLAN_FC_GET_STYPE(fc)) { | ||
607 | case IEEE80211_STYPE_CTS: | ||
608 | case IEEE80211_STYPE_ACK: | ||
609 | hdrlen = 10; | ||
610 | break; | ||
611 | default: | ||
612 | hdrlen = 16; | ||
613 | break; | ||
614 | } | ||
615 | break; | ||
616 | } | ||
617 | |||
618 | return hdrlen; | ||
619 | } | 607 | } |
620 | 608 | ||
621 | 609 | ||
diff --git a/drivers/net/wireless/ipw2x00/Kconfig b/drivers/net/wireless/ipw2x00/Kconfig index 1d5dc3e9c5fb..85cc79995f6f 100644 --- a/drivers/net/wireless/ipw2x00/Kconfig +++ b/drivers/net/wireless/ipw2x00/Kconfig | |||
@@ -186,7 +186,7 @@ config LIBIPW_DEBUG | |||
186 | % echo 0x00000FFO > /proc/net/ieee80211/debug_level | 186 | % echo 0x00000FFO > /proc/net/ieee80211/debug_level |
187 | 187 | ||
188 | For a list of values you can assign to debug_level, you | 188 | For a list of values you can assign to debug_level, you |
189 | can look at the bit mask values in <net/ieee80211.h> | 189 | can look at the bit mask values in ieee80211.h |
190 | 190 | ||
191 | If you are not trying to debug or develop the libipw | 191 | If you are not trying to debug or develop the libipw |
192 | component, you most likely want to say N here. | 192 | component, you most likely want to say N here. |
diff --git a/include/net/ieee80211.h b/drivers/net/wireless/ipw2x00/ieee80211.h index adb7cf31f781..7515fad00f92 100644 --- a/include/net/ieee80211.h +++ b/drivers/net/wireless/ipw2x00/ieee80211.h | |||
@@ -1119,6 +1119,9 @@ static inline int ieee80211_is_cck_rate(u8 rate) | |||
1119 | extern void free_ieee80211(struct net_device *dev); | 1119 | extern void free_ieee80211(struct net_device *dev); |
1120 | extern struct net_device *alloc_ieee80211(int sizeof_priv); | 1120 | extern struct net_device *alloc_ieee80211(int sizeof_priv); |
1121 | 1121 | ||
1122 | extern void ieee80211_networks_age(struct ieee80211_device *ieee, | ||
1123 | unsigned long age_secs); | ||
1124 | |||
1122 | extern int ieee80211_set_encryption(struct ieee80211_device *ieee); | 1125 | extern int ieee80211_set_encryption(struct ieee80211_device *ieee); |
1123 | 1126 | ||
1124 | /* ieee80211_tx.c */ | 1127 | /* ieee80211_tx.c */ |
diff --git a/drivers/net/wireless/ipw2x00/ipw2100.c b/drivers/net/wireless/ipw2x00/ipw2100.c index 52b1cf5160f7..3a6d810a7608 100644 --- a/drivers/net/wireless/ipw2x00/ipw2100.c +++ b/drivers/net/wireless/ipw2x00/ipw2100.c | |||
@@ -1692,7 +1692,13 @@ static int ipw2100_up(struct ipw2100_priv *priv, int deferred) | |||
1692 | u32 lock; | 1692 | u32 lock; |
1693 | u32 ord_len = sizeof(lock); | 1693 | u32 ord_len = sizeof(lock); |
1694 | 1694 | ||
1695 | /* Quite if manually disabled. */ | 1695 | /* Age scan list entries found before suspend */ |
1696 | if (priv->suspend_time) { | ||
1697 | ieee80211_networks_age(priv->ieee, priv->suspend_time); | ||
1698 | priv->suspend_time = 0; | ||
1699 | } | ||
1700 | |||
1701 | /* Quiet if manually disabled. */ | ||
1696 | if (priv->status & STATUS_RF_KILL_SW) { | 1702 | if (priv->status & STATUS_RF_KILL_SW) { |
1697 | IPW_DEBUG_INFO("%s: Radio is disabled by Manual Disable " | 1703 | IPW_DEBUG_INFO("%s: Radio is disabled by Manual Disable " |
1698 | "switch\n", priv->net_dev->name); | 1704 | "switch\n", priv->net_dev->name); |
@@ -6415,6 +6421,8 @@ static int ipw2100_suspend(struct pci_dev *pci_dev, pm_message_t state) | |||
6415 | pci_disable_device(pci_dev); | 6421 | pci_disable_device(pci_dev); |
6416 | pci_set_power_state(pci_dev, PCI_D3hot); | 6422 | pci_set_power_state(pci_dev, PCI_D3hot); |
6417 | 6423 | ||
6424 | priv->suspend_at = get_seconds(); | ||
6425 | |||
6418 | mutex_unlock(&priv->action_mutex); | 6426 | mutex_unlock(&priv->action_mutex); |
6419 | 6427 | ||
6420 | return 0; | 6428 | return 0; |
@@ -6458,6 +6466,8 @@ static int ipw2100_resume(struct pci_dev *pci_dev) | |||
6458 | * the queue of needed */ | 6466 | * the queue of needed */ |
6459 | netif_device_attach(dev); | 6467 | netif_device_attach(dev); |
6460 | 6468 | ||
6469 | priv->suspend_time = get_seconds() - priv->suspend_at; | ||
6470 | |||
6461 | /* Bring the device back up */ | 6471 | /* Bring the device back up */ |
6462 | if (!(priv->status & STATUS_RF_KILL_SW)) | 6472 | if (!(priv->status & STATUS_RF_KILL_SW)) |
6463 | ipw2100_up(priv, 0); | 6473 | ipw2100_up(priv, 0); |
diff --git a/drivers/net/wireless/ipw2x00/ipw2100.h b/drivers/net/wireless/ipw2x00/ipw2100.h index bbf1ddcafba8..f183d951cd32 100644 --- a/drivers/net/wireless/ipw2x00/ipw2100.h +++ b/drivers/net/wireless/ipw2x00/ipw2100.h | |||
@@ -39,8 +39,6 @@ | |||
39 | #include <linux/wireless.h> | 39 | #include <linux/wireless.h> |
40 | #include <net/iw_handler.h> // new driver API | 40 | #include <net/iw_handler.h> // new driver API |
41 | 41 | ||
42 | #include <net/ieee80211.h> | ||
43 | |||
44 | #ifdef CONFIG_IPW2100_MONITOR | 42 | #ifdef CONFIG_IPW2100_MONITOR |
45 | #include <net/ieee80211_radiotap.h> | 43 | #include <net/ieee80211_radiotap.h> |
46 | #endif | 44 | #endif |
@@ -48,6 +46,8 @@ | |||
48 | #include <linux/workqueue.h> | 46 | #include <linux/workqueue.h> |
49 | #include <linux/mutex.h> | 47 | #include <linux/mutex.h> |
50 | 48 | ||
49 | #include "ieee80211.h" | ||
50 | |||
51 | struct ipw2100_priv; | 51 | struct ipw2100_priv; |
52 | struct ipw2100_tx_packet; | 52 | struct ipw2100_tx_packet; |
53 | struct ipw2100_rx_packet; | 53 | struct ipw2100_rx_packet; |
@@ -591,6 +591,10 @@ struct ipw2100_priv { | |||
591 | 591 | ||
592 | int user_requested_scan; | 592 | int user_requested_scan; |
593 | 593 | ||
594 | /* Track time in suspend */ | ||
595 | unsigned long suspend_at; | ||
596 | unsigned long suspend_time; | ||
597 | |||
594 | u32 interrupts; | 598 | u32 interrupts; |
595 | int tx_interrupts; | 599 | int tx_interrupts; |
596 | int rx_interrupts; | 600 | int rx_interrupts; |
diff --git a/drivers/net/wireless/ipw2x00/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c index 0420d3d35dd4..a7fb08aecf3f 100644 --- a/drivers/net/wireless/ipw2x00/ipw2200.c +++ b/drivers/net/wireless/ipw2x00/ipw2200.c | |||
@@ -301,88 +301,102 @@ static inline void ipw_write_reg32(struct ipw_priv *a, u32 b, u32 c) | |||
301 | } | 301 | } |
302 | 302 | ||
303 | /* 8-bit direct write (low 4K) */ | 303 | /* 8-bit direct write (low 4K) */ |
304 | #define _ipw_write8(ipw, ofs, val) writeb((val), (ipw)->hw_base + (ofs)) | 304 | static inline void _ipw_write8(struct ipw_priv *ipw, unsigned long ofs, |
305 | u8 val) | ||
306 | { | ||
307 | writeb(val, ipw->hw_base + ofs); | ||
308 | } | ||
305 | 309 | ||
306 | /* 8-bit direct write (for low 4K of SRAM/regs), with debug wrapper */ | 310 | /* 8-bit direct write (for low 4K of SRAM/regs), with debug wrapper */ |
307 | #define ipw_write8(ipw, ofs, val) do { \ | 311 | #define ipw_write8(ipw, ofs, val) do { \ |
308 | IPW_DEBUG_IO("%s %d: write_direct8(0x%08X, 0x%08X)\n", __FILE__, __LINE__, (u32)(ofs), (u32)(val)); \ | 312 | IPW_DEBUG_IO("%s %d: write_direct8(0x%08X, 0x%08X)\n", __FILE__, \ |
309 | _ipw_write8(ipw, ofs, val); \ | 313 | __LINE__, (u32)(ofs), (u32)(val)); \ |
310 | } while (0) | 314 | _ipw_write8(ipw, ofs, val); \ |
315 | } while (0) | ||
311 | 316 | ||
312 | /* 16-bit direct write (low 4K) */ | 317 | /* 16-bit direct write (low 4K) */ |
313 | #define _ipw_write16(ipw, ofs, val) writew((val), (ipw)->hw_base + (ofs)) | 318 | static inline void _ipw_write16(struct ipw_priv *ipw, unsigned long ofs, |
319 | u16 val) | ||
320 | { | ||
321 | writew(val, ipw->hw_base + ofs); | ||
322 | } | ||
314 | 323 | ||
315 | /* 16-bit direct write (for low 4K of SRAM/regs), with debug wrapper */ | 324 | /* 16-bit direct write (for low 4K of SRAM/regs), with debug wrapper */ |
316 | #define ipw_write16(ipw, ofs, val) \ | 325 | #define ipw_write16(ipw, ofs, val) do { \ |
317 | IPW_DEBUG_IO("%s %d: write_direct16(0x%08X, 0x%08X)\n", __FILE__, __LINE__, (u32)(ofs), (u32)(val)); \ | 326 | IPW_DEBUG_IO("%s %d: write_direct16(0x%08X, 0x%08X)\n", __FILE__, \ |
318 | _ipw_write16(ipw, ofs, val) | 327 | __LINE__, (u32)(ofs), (u32)(val)); \ |
328 | _ipw_write16(ipw, ofs, val); \ | ||
329 | } while (0) | ||
319 | 330 | ||
320 | /* 32-bit direct write (low 4K) */ | 331 | /* 32-bit direct write (low 4K) */ |
321 | #define _ipw_write32(ipw, ofs, val) writel((val), (ipw)->hw_base + (ofs)) | 332 | static inline void _ipw_write32(struct ipw_priv *ipw, unsigned long ofs, |
333 | u32 val) | ||
334 | { | ||
335 | writel(val, ipw->hw_base + ofs); | ||
336 | } | ||
322 | 337 | ||
323 | /* 32-bit direct write (for low 4K of SRAM/regs), with debug wrapper */ | 338 | /* 32-bit direct write (for low 4K of SRAM/regs), with debug wrapper */ |
324 | #define ipw_write32(ipw, ofs, val) \ | 339 | #define ipw_write32(ipw, ofs, val) do { \ |
325 | IPW_DEBUG_IO("%s %d: write_direct32(0x%08X, 0x%08X)\n", __FILE__, __LINE__, (u32)(ofs), (u32)(val)); \ | 340 | IPW_DEBUG_IO("%s %d: write_direct32(0x%08X, 0x%08X)\n", __FILE__, \ |
326 | _ipw_write32(ipw, ofs, val) | 341 | __LINE__, (u32)(ofs), (u32)(val)); \ |
342 | _ipw_write32(ipw, ofs, val); \ | ||
343 | } while (0) | ||
327 | 344 | ||
328 | /* 8-bit direct read (low 4K) */ | 345 | /* 8-bit direct read (low 4K) */ |
329 | #define _ipw_read8(ipw, ofs) readb((ipw)->hw_base + (ofs)) | 346 | static inline u8 _ipw_read8(struct ipw_priv *ipw, unsigned long ofs) |
330 | |||
331 | /* 8-bit direct read (low 4K), with debug wrapper */ | ||
332 | static inline u8 __ipw_read8(char *f, u32 l, struct ipw_priv *ipw, u32 ofs) | ||
333 | { | 347 | { |
334 | IPW_DEBUG_IO("%s %d: read_direct8(0x%08X)\n", f, l, (u32) (ofs)); | 348 | return readb(ipw->hw_base + ofs); |
335 | return _ipw_read8(ipw, ofs); | ||
336 | } | 349 | } |
337 | 350 | ||
338 | /* alias to 8-bit direct read (low 4K of SRAM/regs), with debug wrapper */ | 351 | /* alias to 8-bit direct read (low 4K of SRAM/regs), with debug wrapper */ |
339 | #define ipw_read8(ipw, ofs) __ipw_read8(__FILE__, __LINE__, ipw, ofs) | 352 | #define ipw_read8(ipw, ofs) ({ \ |
353 | IPW_DEBUG_IO("%s %d: read_direct8(0x%08X)\n", __FILE__, __LINE__, \ | ||
354 | (u32)(ofs)); \ | ||
355 | _ipw_read8(ipw, ofs); \ | ||
356 | }) | ||
340 | 357 | ||
341 | /* 16-bit direct read (low 4K) */ | 358 | /* 16-bit direct read (low 4K) */ |
342 | #define _ipw_read16(ipw, ofs) readw((ipw)->hw_base + (ofs)) | 359 | static inline u16 _ipw_read16(struct ipw_priv *ipw, unsigned long ofs) |
343 | |||
344 | /* 16-bit direct read (low 4K), with debug wrapper */ | ||
345 | static inline u16 __ipw_read16(char *f, u32 l, struct ipw_priv *ipw, u32 ofs) | ||
346 | { | 360 | { |
347 | IPW_DEBUG_IO("%s %d: read_direct16(0x%08X)\n", f, l, (u32) (ofs)); | 361 | return readw(ipw->hw_base + ofs); |
348 | return _ipw_read16(ipw, ofs); | ||
349 | } | 362 | } |
350 | 363 | ||
351 | /* alias to 16-bit direct read (low 4K of SRAM/regs), with debug wrapper */ | 364 | /* alias to 16-bit direct read (low 4K of SRAM/regs), with debug wrapper */ |
352 | #define ipw_read16(ipw, ofs) __ipw_read16(__FILE__, __LINE__, ipw, ofs) | 365 | #define ipw_read16(ipw, ofs) ({ \ |
366 | IPW_DEBUG_IO("%s %d: read_direct16(0x%08X)\n", __FILE__, __LINE__, \ | ||
367 | (u32)(ofs)); \ | ||
368 | _ipw_read16(ipw, ofs); \ | ||
369 | }) | ||
353 | 370 | ||
354 | /* 32-bit direct read (low 4K) */ | 371 | /* 32-bit direct read (low 4K) */ |
355 | #define _ipw_read32(ipw, ofs) readl((ipw)->hw_base + (ofs)) | 372 | static inline u32 _ipw_read32(struct ipw_priv *ipw, unsigned long ofs) |
356 | |||
357 | /* 32-bit direct read (low 4K), with debug wrapper */ | ||
358 | static inline u32 __ipw_read32(char *f, u32 l, struct ipw_priv *ipw, u32 ofs) | ||
359 | { | 373 | { |
360 | IPW_DEBUG_IO("%s %d: read_direct32(0x%08X)\n", f, l, (u32) (ofs)); | 374 | return readl(ipw->hw_base + ofs); |
361 | return _ipw_read32(ipw, ofs); | ||
362 | } | 375 | } |
363 | 376 | ||
364 | /* alias to 32-bit direct read (low 4K of SRAM/regs), with debug wrapper */ | 377 | /* alias to 32-bit direct read (low 4K of SRAM/regs), with debug wrapper */ |
365 | #define ipw_read32(ipw, ofs) __ipw_read32(__FILE__, __LINE__, ipw, ofs) | 378 | #define ipw_read32(ipw, ofs) ({ \ |
379 | IPW_DEBUG_IO("%s %d: read_direct32(0x%08X)\n", __FILE__, __LINE__, \ | ||
380 | (u32)(ofs)); \ | ||
381 | _ipw_read32(ipw, ofs); \ | ||
382 | }) | ||
366 | 383 | ||
367 | /* multi-byte read (above 4K), with debug wrapper */ | ||
368 | static void _ipw_read_indirect(struct ipw_priv *, u32, u8 *, int); | 384 | static void _ipw_read_indirect(struct ipw_priv *, u32, u8 *, int); |
369 | static inline void __ipw_read_indirect(const char *f, int l, | ||
370 | struct ipw_priv *a, u32 b, u8 * c, int d) | ||
371 | { | ||
372 | IPW_DEBUG_IO("%s %d: read_indirect(0x%08X) %d bytes\n", f, l, (u32) (b), | ||
373 | d); | ||
374 | _ipw_read_indirect(a, b, c, d); | ||
375 | } | ||
376 | |||
377 | /* alias to multi-byte read (SRAM/regs above 4K), with debug wrapper */ | 385 | /* alias to multi-byte read (SRAM/regs above 4K), with debug wrapper */ |
378 | #define ipw_read_indirect(a, b, c, d) __ipw_read_indirect(__FILE__, __LINE__, a, b, c, d) | 386 | #define ipw_read_indirect(a, b, c, d) ({ \ |
387 | IPW_DEBUG_IO("%s %d: read_indirect(0x%08X) %u bytes\n", __FILE__, \ | ||
388 | __LINE__, (u32)(b), (u32)(d)); \ | ||
389 | _ipw_read_indirect(a, b, c, d); \ | ||
390 | }) | ||
379 | 391 | ||
380 | /* alias to multi-byte read (SRAM/regs above 4K), with debug wrapper */ | 392 | /* alias to multi-byte read (SRAM/regs above 4K), with debug wrapper */ |
381 | static void _ipw_write_indirect(struct ipw_priv *priv, u32 addr, u8 * data, | 393 | static void _ipw_write_indirect(struct ipw_priv *priv, u32 addr, u8 * data, |
382 | int num); | 394 | int num); |
383 | #define ipw_write_indirect(a, b, c, d) \ | 395 | #define ipw_write_indirect(a, b, c, d) do { \ |
384 | IPW_DEBUG_IO("%s %d: write_indirect(0x%08X) %d bytes\n", __FILE__, __LINE__, (u32)(b), d); \ | 396 | IPW_DEBUG_IO("%s %d: write_indirect(0x%08X) %u bytes\n", __FILE__, \ |
385 | _ipw_write_indirect(a, b, c, d) | 397 | __LINE__, (u32)(b), (u32)(d)); \ |
398 | _ipw_write_indirect(a, b, c, d); \ | ||
399 | } while (0) | ||
386 | 400 | ||
387 | /* 32-bit indirect write (above 4K) */ | 401 | /* 32-bit indirect write (above 4K) */ |
388 | static void _ipw_write_reg32(struct ipw_priv *priv, u32 reg, u32 value) | 402 | static void _ipw_write_reg32(struct ipw_priv *priv, u32 reg, u32 value) |
@@ -11224,6 +11238,12 @@ static int ipw_up(struct ipw_priv *priv) | |||
11224 | { | 11238 | { |
11225 | int rc, i, j; | 11239 | int rc, i, j; |
11226 | 11240 | ||
11241 | /* Age scan list entries found before suspend */ | ||
11242 | if (priv->suspend_time) { | ||
11243 | ieee80211_networks_age(priv->ieee, priv->suspend_time); | ||
11244 | priv->suspend_time = 0; | ||
11245 | } | ||
11246 | |||
11227 | if (priv->status & STATUS_EXIT_PENDING) | 11247 | if (priv->status & STATUS_EXIT_PENDING) |
11228 | return -EIO; | 11248 | return -EIO; |
11229 | 11249 | ||
@@ -11824,6 +11844,8 @@ static int ipw_pci_suspend(struct pci_dev *pdev, pm_message_t state) | |||
11824 | pci_disable_device(pdev); | 11844 | pci_disable_device(pdev); |
11825 | pci_set_power_state(pdev, pci_choose_state(pdev, state)); | 11845 | pci_set_power_state(pdev, pci_choose_state(pdev, state)); |
11826 | 11846 | ||
11847 | priv->suspend_at = get_seconds(); | ||
11848 | |||
11827 | return 0; | 11849 | return 0; |
11828 | } | 11850 | } |
11829 | 11851 | ||
@@ -11859,6 +11881,8 @@ static int ipw_pci_resume(struct pci_dev *pdev) | |||
11859 | * the queue of needed */ | 11881 | * the queue of needed */ |
11860 | netif_device_attach(dev); | 11882 | netif_device_attach(dev); |
11861 | 11883 | ||
11884 | priv->suspend_time = get_seconds() - priv->suspend_at; | ||
11885 | |||
11862 | /* Bring the device back up */ | 11886 | /* Bring the device back up */ |
11863 | queue_work(priv->workqueue, &priv->up); | 11887 | queue_work(priv->workqueue, &priv->up); |
11864 | 11888 | ||
diff --git a/drivers/net/wireless/ipw2x00/ipw2200.h b/drivers/net/wireless/ipw2x00/ipw2200.h index 277b274d4be5..05e8ccf01c5f 100644 --- a/drivers/net/wireless/ipw2x00/ipw2200.h +++ b/drivers/net/wireless/ipw2x00/ipw2200.h | |||
@@ -49,13 +49,14 @@ | |||
49 | #include <asm/io.h> | 49 | #include <asm/io.h> |
50 | 50 | ||
51 | #include <net/lib80211.h> | 51 | #include <net/lib80211.h> |
52 | #include <net/ieee80211.h> | ||
53 | #include <net/ieee80211_radiotap.h> | 52 | #include <net/ieee80211_radiotap.h> |
54 | 53 | ||
55 | #define DRV_NAME "ipw2200" | 54 | #define DRV_NAME "ipw2200" |
56 | 55 | ||
57 | #include <linux/workqueue.h> | 56 | #include <linux/workqueue.h> |
58 | 57 | ||
58 | #include "ieee80211.h" | ||
59 | |||
59 | /* Authentication and Association States */ | 60 | /* Authentication and Association States */ |
60 | enum connection_manager_assoc_states { | 61 | enum connection_manager_assoc_states { |
61 | CMAS_INIT = 0, | 62 | CMAS_INIT = 0, |
@@ -1346,6 +1347,10 @@ struct ipw_priv { | |||
1346 | 1347 | ||
1347 | s8 tx_power; | 1348 | s8 tx_power; |
1348 | 1349 | ||
1350 | /* Track time in suspend */ | ||
1351 | unsigned long suspend_at; | ||
1352 | unsigned long suspend_time; | ||
1353 | |||
1349 | #ifdef CONFIG_PM | 1354 | #ifdef CONFIG_PM |
1350 | u32 pm_state[16]; | 1355 | u32 pm_state[16]; |
1351 | #endif | 1356 | #endif |
diff --git a/drivers/net/wireless/ipw2x00/libipw_geo.c b/drivers/net/wireless/ipw2x00/libipw_geo.c index 960ad13f5e9f..9dfbb8760f67 100644 --- a/drivers/net/wireless/ipw2x00/libipw_geo.c +++ b/drivers/net/wireless/ipw2x00/libipw_geo.c | |||
@@ -41,7 +41,7 @@ | |||
41 | #include <linux/etherdevice.h> | 41 | #include <linux/etherdevice.h> |
42 | #include <asm/uaccess.h> | 42 | #include <asm/uaccess.h> |
43 | 43 | ||
44 | #include <net/ieee80211.h> | 44 | #include "ieee80211.h" |
45 | 45 | ||
46 | int ieee80211_is_valid_channel(struct ieee80211_device *ieee, u8 channel) | 46 | int ieee80211_is_valid_channel(struct ieee80211_device *ieee, u8 channel) |
47 | { | 47 | { |
diff --git a/drivers/net/wireless/ipw2x00/libipw_module.c b/drivers/net/wireless/ipw2x00/libipw_module.c index a2f5616d5b09..ec7753446bd3 100644 --- a/drivers/net/wireless/ipw2x00/libipw_module.c +++ b/drivers/net/wireless/ipw2x00/libipw_module.c | |||
@@ -50,7 +50,7 @@ | |||
50 | #include <net/net_namespace.h> | 50 | #include <net/net_namespace.h> |
51 | #include <net/arp.h> | 51 | #include <net/arp.h> |
52 | 52 | ||
53 | #include <net/ieee80211.h> | 53 | #include "ieee80211.h" |
54 | 54 | ||
55 | #define DRV_DESCRIPTION "802.11 data/management/control stack" | 55 | #define DRV_DESCRIPTION "802.11 data/management/control stack" |
56 | #define DRV_NAME "ieee80211" | 56 | #define DRV_NAME "ieee80211" |
@@ -105,6 +105,21 @@ static inline void ieee80211_networks_free(struct ieee80211_device *ieee) | |||
105 | ieee->networks = NULL; | 105 | ieee->networks = NULL; |
106 | } | 106 | } |
107 | 107 | ||
108 | void ieee80211_networks_age(struct ieee80211_device *ieee, | ||
109 | unsigned long age_secs) | ||
110 | { | ||
111 | struct ieee80211_network *network = NULL; | ||
112 | unsigned long flags; | ||
113 | unsigned long age_jiffies = msecs_to_jiffies(age_secs * MSEC_PER_SEC); | ||
114 | |||
115 | spin_lock_irqsave(&ieee->lock, flags); | ||
116 | list_for_each_entry(network, &ieee->network_list, list) { | ||
117 | network->last_scanned -= age_jiffies; | ||
118 | } | ||
119 | spin_unlock_irqrestore(&ieee->lock, flags); | ||
120 | } | ||
121 | EXPORT_SYMBOL(ieee80211_networks_age); | ||
122 | |||
108 | static void ieee80211_networks_initialize(struct ieee80211_device *ieee) | 123 | static void ieee80211_networks_initialize(struct ieee80211_device *ieee) |
109 | { | 124 | { |
110 | int i; | 125 | int i; |
diff --git a/drivers/net/wireless/ipw2x00/libipw_rx.c b/drivers/net/wireless/ipw2x00/libipw_rx.c index 9c67dfae4320..8d9e96f9eb28 100644 --- a/drivers/net/wireless/ipw2x00/libipw_rx.c +++ b/drivers/net/wireless/ipw2x00/libipw_rx.c | |||
@@ -33,7 +33,8 @@ | |||
33 | #include <linux/ctype.h> | 33 | #include <linux/ctype.h> |
34 | 34 | ||
35 | #include <net/lib80211.h> | 35 | #include <net/lib80211.h> |
36 | #include <net/ieee80211.h> | 36 | |
37 | #include "ieee80211.h" | ||
37 | 38 | ||
38 | static void ieee80211_monitor_rx(struct ieee80211_device *ieee, | 39 | static void ieee80211_monitor_rx(struct ieee80211_device *ieee, |
39 | struct sk_buff *skb, | 40 | struct sk_buff *skb, |
@@ -1615,7 +1616,7 @@ static void ieee80211_process_probe_response(struct ieee80211_device | |||
1615 | break; | 1616 | break; |
1616 | 1617 | ||
1617 | if ((oldest == NULL) || | 1618 | if ((oldest == NULL) || |
1618 | (target->last_scanned < oldest->last_scanned)) | 1619 | time_before(target->last_scanned, oldest->last_scanned)) |
1619 | oldest = target; | 1620 | oldest = target; |
1620 | } | 1621 | } |
1621 | 1622 | ||
diff --git a/drivers/net/wireless/ipw2x00/libipw_tx.c b/drivers/net/wireless/ipw2x00/libipw_tx.c index f78f57e8844a..a874e9091919 100644 --- a/drivers/net/wireless/ipw2x00/libipw_tx.c +++ b/drivers/net/wireless/ipw2x00/libipw_tx.c | |||
@@ -41,7 +41,7 @@ | |||
41 | #include <linux/etherdevice.h> | 41 | #include <linux/etherdevice.h> |
42 | #include <asm/uaccess.h> | 42 | #include <asm/uaccess.h> |
43 | 43 | ||
44 | #include <net/ieee80211.h> | 44 | #include "ieee80211.h" |
45 | 45 | ||
46 | /* | 46 | /* |
47 | 47 | ||
diff --git a/drivers/net/wireless/ipw2x00/libipw_wx.c b/drivers/net/wireless/ipw2x00/libipw_wx.c index 31ea3abfc327..3c0812db030a 100644 --- a/drivers/net/wireless/ipw2x00/libipw_wx.c +++ b/drivers/net/wireless/ipw2x00/libipw_wx.c | |||
@@ -35,13 +35,24 @@ | |||
35 | #include <linux/jiffies.h> | 35 | #include <linux/jiffies.h> |
36 | 36 | ||
37 | #include <net/lib80211.h> | 37 | #include <net/lib80211.h> |
38 | #include <net/ieee80211.h> | ||
39 | #include <linux/wireless.h> | 38 | #include <linux/wireless.h> |
40 | 39 | ||
40 | #include "ieee80211.h" | ||
41 | |||
41 | static const char *ieee80211_modes[] = { | 42 | static const char *ieee80211_modes[] = { |
42 | "?", "a", "b", "ab", "g", "ag", "bg", "abg" | 43 | "?", "a", "b", "ab", "g", "ag", "bg", "abg" |
43 | }; | 44 | }; |
44 | 45 | ||
46 | static inline unsigned int elapsed_jiffies_msecs(unsigned long start) | ||
47 | { | ||
48 | unsigned long end = jiffies; | ||
49 | |||
50 | if (end >= start) | ||
51 | return jiffies_to_msecs(end - start); | ||
52 | |||
53 | return jiffies_to_msecs(end + (MAX_JIFFY_OFFSET - start) + 1); | ||
54 | } | ||
55 | |||
45 | #define MAX_CUSTOM_LEN 64 | 56 | #define MAX_CUSTOM_LEN 64 |
46 | static char *ieee80211_translate_scan(struct ieee80211_device *ieee, | 57 | static char *ieee80211_translate_scan(struct ieee80211_device *ieee, |
47 | char *start, char *stop, | 58 | char *start, char *stop, |
@@ -215,8 +226,8 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee, | |||
215 | iwe.cmd = IWEVCUSTOM; | 226 | iwe.cmd = IWEVCUSTOM; |
216 | p = custom; | 227 | p = custom; |
217 | p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), | 228 | p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), |
218 | " Last beacon: %dms ago", | 229 | " Last beacon: %ums ago", |
219 | jiffies_to_msecs(jiffies - network->last_scanned)); | 230 | elapsed_jiffies_msecs(network->last_scanned)); |
220 | iwe.u.data.length = p - custom; | 231 | iwe.u.data.length = p - custom; |
221 | if (iwe.u.data.length) | 232 | if (iwe.u.data.length) |
222 | start = iwe_stream_add_point(info, start, stop, &iwe, custom); | 233 | start = iwe_stream_add_point(info, start, stop, &iwe, custom); |
@@ -276,15 +287,15 @@ int ieee80211_wx_get_scan(struct ieee80211_device *ieee, | |||
276 | time_after(network->last_scanned + ieee->scan_age, jiffies)) | 287 | time_after(network->last_scanned + ieee->scan_age, jiffies)) |
277 | ev = ieee80211_translate_scan(ieee, ev, stop, network, | 288 | ev = ieee80211_translate_scan(ieee, ev, stop, network, |
278 | info); | 289 | info); |
279 | else | 290 | else { |
280 | IEEE80211_DEBUG_SCAN("Not showing network '%s (" | 291 | IEEE80211_DEBUG_SCAN("Not showing network '%s (" |
281 | "%pM)' due to age (%dms).\n", | 292 | "%pM)' due to age (%ums).\n", |
282 | print_ssid(ssid, network->ssid, | 293 | print_ssid(ssid, network->ssid, |
283 | network->ssid_len), | 294 | network->ssid_len), |
284 | network->bssid, | 295 | network->bssid, |
285 | jiffies_to_msecs(jiffies - | 296 | elapsed_jiffies_msecs( |
286 | network-> | 297 | network->last_scanned)); |
287 | last_scanned)); | 298 | } |
288 | } | 299 | } |
289 | 300 | ||
290 | spin_unlock_irqrestore(&ieee->lock, flags); | 301 | spin_unlock_irqrestore(&ieee->lock, flags); |
diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig index 7b3bad1796c7..6cc5a54d35c5 100644 --- a/drivers/net/wireless/iwlwifi/Kconfig +++ b/drivers/net/wireless/iwlwifi/Kconfig | |||
@@ -1,27 +1,31 @@ | |||
1 | config IWLWIFI | 1 | config IWLWIFI |
2 | bool "Intel Wireless Wifi" | 2 | tristate "Intel Wireless Wifi" |
3 | depends on PCI && MAC80211 && WLAN_80211 && EXPERIMENTAL | 3 | depends on PCI && MAC80211 && WLAN_80211 && EXPERIMENTAL |
4 | default y | ||
5 | |||
6 | config IWLCORE | ||
7 | tristate "Intel Wireless Wifi Core" | ||
8 | depends on IWLWIFI | ||
9 | select LIB80211 | 4 | select LIB80211 |
5 | select FW_LOADER | ||
10 | select MAC80211_LEDS if IWLWIFI_LEDS | 6 | select MAC80211_LEDS if IWLWIFI_LEDS |
11 | select LEDS_CLASS if IWLWIFI_LEDS | 7 | select LEDS_CLASS if IWLWIFI_LEDS |
12 | select RFKILL if IWLWIFI_RFKILL | 8 | select RFKILL if IWLWIFI_RFKILL |
9 | select MAC80211_LEDS if IWL3945_LEDS | ||
10 | select LEDS_CLASS if IWL3945_LEDS | ||
13 | 11 | ||
14 | config IWLWIFI_LEDS | 12 | config IWLWIFI_LEDS |
15 | bool "Enable LED support in iwlagn driver" | 13 | bool "Enable LED support in iwlagn driver" |
16 | depends on IWLCORE | 14 | depends on IWLWIFI |
17 | 15 | ||
18 | config IWLWIFI_RFKILL | 16 | config IWLWIFI_RFKILL |
19 | bool "Enable RF kill support in iwlagn driver" | 17 | bool "Enable RF kill support in iwlagn and iwl3945 drivers" |
20 | depends on IWLCORE | 18 | depends on IWLWIFI |
19 | |||
20 | config IWLWIFI_SPECTRUM_MEASUREMENT | ||
21 | bool "Enable Spectrum Measurement in iwlagn driver" | ||
22 | depends on IWLWIFI | ||
23 | ---help--- | ||
24 | This option will enable spectrum measurement for the iwlagn driver. | ||
21 | 25 | ||
22 | config IWLWIFI_DEBUG | 26 | config IWLWIFI_DEBUG |
23 | bool "Enable full debugging output in iwlagn and iwl3945 drivers" | 27 | bool "Enable full debugging output in iwlagn and iwl3945 drivers" |
24 | depends on IWLCORE | 28 | depends on IWLWIFI |
25 | ---help--- | 29 | ---help--- |
26 | This option will enable debug tracing output for the iwlwifi drivers | 30 | This option will enable debug tracing output for the iwlwifi drivers |
27 | 31 | ||
@@ -45,16 +49,14 @@ config IWLWIFI_DEBUG | |||
45 | any problems you may encounter. | 49 | any problems you may encounter. |
46 | 50 | ||
47 | config IWLWIFI_DEBUGFS | 51 | config IWLWIFI_DEBUGFS |
48 | bool "Iwlwifi debugfs support" | 52 | bool "iwlagn debugfs support" |
49 | depends on IWLCORE && IWLWIFI_DEBUG && MAC80211_DEBUGFS | 53 | depends on IWLWIFI && IWLWIFI_DEBUG && MAC80211_DEBUGFS |
50 | ---help--- | 54 | ---help--- |
51 | Enable creation of debugfs files for the iwlwifi drivers. | 55 | Enable creation of debugfs files for the iwlwifi drivers. |
52 | 56 | ||
53 | config IWLAGN | 57 | config IWLAGN |
54 | tristate "Intel Wireless WiFi Next Gen AGN" | 58 | tristate "Intel Wireless WiFi Next Gen AGN (iwlagn)" |
55 | depends on IWLWIFI | 59 | depends on IWLWIFI |
56 | select FW_LOADER | ||
57 | select IWLCORE | ||
58 | ---help--- | 60 | ---help--- |
59 | Select to build the driver supporting the: | 61 | Select to build the driver supporting the: |
60 | 62 | ||
@@ -77,19 +79,6 @@ config IWLAGN | |||
77 | say M here and read <file:Documentation/kbuild/modules.txt>. The | 79 | say M here and read <file:Documentation/kbuild/modules.txt>. The |
78 | module will be called iwlagn.ko. | 80 | module will be called iwlagn.ko. |
79 | 81 | ||
80 | config IWLAGN_SPECTRUM_MEASUREMENT | ||
81 | bool "Enable Spectrum Measurement in iwlagn driver" | ||
82 | depends on IWLAGN | ||
83 | ---help--- | ||
84 | This option will enable spectrum measurement for the iwlagn driver. | ||
85 | |||
86 | config IWLAGN_LEDS | ||
87 | bool "Enable LEDS features in iwlagn driver" | ||
88 | depends on IWLAGN | ||
89 | select IWLWIFI_LEDS | ||
90 | ---help--- | ||
91 | This option enables LEDS for the iwlagn drivers | ||
92 | |||
93 | 82 | ||
94 | config IWL4965 | 83 | config IWL4965 |
95 | bool "Intel Wireless WiFi 4965AGN" | 84 | bool "Intel Wireless WiFi 4965AGN" |
@@ -98,19 +87,14 @@ config IWL4965 | |||
98 | This option enables support for Intel Wireless WiFi Link 4965AGN | 87 | This option enables support for Intel Wireless WiFi Link 4965AGN |
99 | 88 | ||
100 | config IWL5000 | 89 | config IWL5000 |
101 | bool "Intel Wireless WiFi 5000AGN" | 90 | bool "Intel Wireless WiFi 5000AGN; Intel WiFi Link 100, 6000, and 6050 Series" |
102 | depends on IWLAGN | 91 | depends on IWLAGN |
103 | ---help--- | 92 | ---help--- |
104 | This option enables support for Intel Wireless WiFi Link 5000AGN Family | 93 | This option enables support for Intel Wireless WiFi Link 5000AGN Family |
105 | 94 | ||
106 | config IWL3945 | 95 | config IWL3945 |
107 | tristate "Intel PRO/Wireless 3945ABG/BG Network Connection" | 96 | tristate "Intel PRO/Wireless 3945ABG/BG Network Connection (iwl3945)" |
108 | depends on IWLWIFI | 97 | depends on IWLWIFI |
109 | select FW_LOADER | ||
110 | select LIB80211 | ||
111 | select MAC80211_LEDS if IWL3945_LEDS | ||
112 | select LEDS_CLASS if IWL3945_LEDS | ||
113 | select RFKILL if IWLWIFI_RFKILL | ||
114 | ---help--- | 98 | ---help--- |
115 | Select to build the driver supporting the: | 99 | Select to build the driver supporting the: |
116 | 100 | ||
@@ -134,7 +118,7 @@ config IWL3945 | |||
134 | module will be called iwl3945.ko. | 118 | module will be called iwl3945.ko. |
135 | 119 | ||
136 | config IWL3945_SPECTRUM_MEASUREMENT | 120 | config IWL3945_SPECTRUM_MEASUREMENT |
137 | bool "Enable Spectrum Measurement in iwl3945 drivers" | 121 | bool "Enable Spectrum Measurement in iwl3945 driver" |
138 | depends on IWL3945 | 122 | depends on IWL3945 |
139 | ---help--- | 123 | ---help--- |
140 | This option will enable spectrum measurement for the iwl3945 driver. | 124 | This option will enable spectrum measurement for the iwl3945 driver. |
diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile index ddc8b31b2608..48af523ceab7 100644 --- a/drivers/net/wireless/iwlwifi/Makefile +++ b/drivers/net/wireless/iwlwifi/Makefile | |||
@@ -1,11 +1,11 @@ | |||
1 | obj-$(CONFIG_IWLCORE) += iwlcore.o | 1 | obj-$(CONFIG_IWLWIFI) += iwlcore.o |
2 | iwlcore-objs := iwl-core.o iwl-eeprom.o iwl-hcmd.o iwl-power.o | 2 | iwlcore-objs := iwl-core.o iwl-eeprom.o iwl-hcmd.o iwl-power.o |
3 | iwlcore-objs += iwl-rx.o iwl-tx.o iwl-sta.o iwl-calib.o | 3 | iwlcore-objs += iwl-rx.o iwl-tx.o iwl-sta.o iwl-calib.o |
4 | iwlcore-objs += iwl-scan.o | 4 | iwlcore-objs += iwl-scan.o |
5 | iwlcore-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-debugfs.o | 5 | iwlcore-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-debugfs.o |
6 | iwlcore-$(CONFIG_IWLWIFI_LEDS) += iwl-led.o | 6 | iwlcore-$(CONFIG_IWLWIFI_LEDS) += iwl-led.o |
7 | iwlcore-$(CONFIG_IWLWIFI_RFKILL) += iwl-rfkill.o | 7 | iwlcore-$(CONFIG_IWLWIFI_RFKILL) += iwl-rfkill.o |
8 | iwlcore-$(CONFIG_IWLAGN_SPECTRUM_MEASUREMENT) += iwl-spectrum.o | 8 | iwlcore-$(CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT) += iwl-spectrum.o |
9 | 9 | ||
10 | obj-$(CONFIG_IWLAGN) += iwlagn.o | 10 | obj-$(CONFIG_IWLAGN) += iwlagn.o |
11 | iwlagn-objs := iwl-agn.o iwl-agn-rs.o | 11 | iwlagn-objs := iwl-agn.o iwl-agn-rs.o |
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index d49e48b9b037..0a750534ddf2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c | |||
@@ -1073,7 +1073,7 @@ static int iwl3945_apm_init(struct iwl_priv *priv) | |||
1073 | * D0U* --> D0A* state */ | 1073 | * D0U* --> D0A* state */ |
1074 | iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); | 1074 | iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); |
1075 | 1075 | ||
1076 | iwl_poll_direct_bit(priv, CSR_GP_CNTRL, | 1076 | ret = iwl_poll_direct_bit(priv, CSR_GP_CNTRL, |
1077 | CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); | 1077 | CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); |
1078 | if (ret < 0) { | 1078 | if (ret < 0) { |
1079 | IWL_DEBUG_INFO(priv, "Failed to init the card\n"); | 1079 | IWL_DEBUG_INFO(priv, "Failed to init the card\n"); |
@@ -2747,6 +2747,7 @@ static struct iwl_lib_ops iwl3945_lib = { | |||
2747 | .query_addr = iwlcore_eeprom_query_addr, | 2747 | .query_addr = iwlcore_eeprom_query_addr, |
2748 | }, | 2748 | }, |
2749 | .send_tx_power = iwl3945_send_tx_power, | 2749 | .send_tx_power = iwl3945_send_tx_power, |
2750 | .is_valid_rtc_data_addr = iwl3945_hw_valid_rtc_data_addr, | ||
2750 | }; | 2751 | }; |
2751 | 2752 | ||
2752 | static struct iwl_hcmd_utils_ops iwl3945_hcmd_utils = { | 2753 | static struct iwl_hcmd_utils_ops iwl3945_hcmd_utils = { |
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 397577c06c92..b49f9f7a8a67 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c | |||
@@ -72,7 +72,7 @@ | |||
72 | #define VD | 72 | #define VD |
73 | #endif | 73 | #endif |
74 | 74 | ||
75 | #ifdef CONFIG_IWLAGN_SPECTRUM_MEASUREMENT | 75 | #ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT |
76 | #define VS "s" | 76 | #define VS "s" |
77 | #else | 77 | #else |
78 | #define VS | 78 | #define VS |
@@ -444,7 +444,7 @@ void iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq) | |||
444 | pci_unmap_single(dev, | 444 | pci_unmap_single(dev, |
445 | pci_unmap_addr(&txq->cmd[index]->meta, mapping), | 445 | pci_unmap_addr(&txq->cmd[index]->meta, mapping), |
446 | pci_unmap_len(&txq->cmd[index]->meta, len), | 446 | pci_unmap_len(&txq->cmd[index]->meta, len), |
447 | PCI_DMA_TODEVICE); | 447 | PCI_DMA_BIDIRECTIONAL); |
448 | 448 | ||
449 | /* Unmap chunks, if any. */ | 449 | /* Unmap chunks, if any. */ |
450 | for (i = 1; i < num_tbs; i++) { | 450 | for (i = 1; i < num_tbs; i++) { |
@@ -644,6 +644,9 @@ static u16 iwl_adjust_beacon_interval(u16 beacon_val) | |||
644 | / MAX_UCODE_BEACON_INTERVAL; | 644 | / MAX_UCODE_BEACON_INTERVAL; |
645 | new_val = beacon_val / beacon_factor; | 645 | new_val = beacon_val / beacon_factor; |
646 | 646 | ||
647 | if (!new_val) | ||
648 | new_val = MAX_UCODE_BEACON_INTERVAL; | ||
649 | |||
647 | return new_val; | 650 | return new_val; |
648 | } | 651 | } |
649 | 652 | ||
@@ -751,41 +754,6 @@ static void iwl_rx_reply_alive(struct iwl_priv *priv, | |||
751 | IWL_WARN(priv, "uCode did not respond OK.\n"); | 754 | IWL_WARN(priv, "uCode did not respond OK.\n"); |
752 | } | 755 | } |
753 | 756 | ||
754 | static void iwl_rx_reply_error(struct iwl_priv *priv, | ||
755 | struct iwl_rx_mem_buffer *rxb) | ||
756 | { | ||
757 | struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; | ||
758 | |||
759 | IWL_ERR(priv, "Error Reply type 0x%08X cmd %s (0x%02X) " | ||
760 | "seq 0x%04X ser 0x%08X\n", | ||
761 | le32_to_cpu(pkt->u.err_resp.error_type), | ||
762 | get_cmd_string(pkt->u.err_resp.cmd_id), | ||
763 | pkt->u.err_resp.cmd_id, | ||
764 | le16_to_cpu(pkt->u.err_resp.bad_cmd_seq_num), | ||
765 | le32_to_cpu(pkt->u.err_resp.error_info)); | ||
766 | } | ||
767 | |||
768 | static void iwl_rx_pm_sleep_notif(struct iwl_priv *priv, | ||
769 | struct iwl_rx_mem_buffer *rxb) | ||
770 | { | ||
771 | #ifdef CONFIG_IWLWIFI_DEBUG | ||
772 | struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; | ||
773 | struct iwl_sleep_notification *sleep = &(pkt->u.sleep_notif); | ||
774 | IWL_DEBUG_RX(priv, "sleep mode: %d, src: %d\n", | ||
775 | sleep->pm_sleep_mode, sleep->pm_wakeup_src); | ||
776 | #endif | ||
777 | } | ||
778 | |||
779 | static void iwl_rx_pm_debug_statistics_notif(struct iwl_priv *priv, | ||
780 | struct iwl_rx_mem_buffer *rxb) | ||
781 | { | ||
782 | struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; | ||
783 | IWL_DEBUG_RADIO(priv, "Dumping %d bytes of unhandled " | ||
784 | "notification for %s:\n", | ||
785 | le32_to_cpu(pkt->len), get_cmd_string(pkt->hdr.cmd)); | ||
786 | iwl_print_hex_dump(priv, IWL_DL_RADIO, pkt->u.raw, le32_to_cpu(pkt->len)); | ||
787 | } | ||
788 | |||
789 | static void iwl_bg_beacon_update(struct work_struct *work) | 757 | static void iwl_bg_beacon_update(struct work_struct *work) |
790 | { | 758 | { |
791 | struct iwl_priv *priv = | 759 | struct iwl_priv *priv = |
@@ -1312,64 +1280,6 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) | |||
1312 | spin_unlock_irqrestore(&priv->lock, flags); | 1280 | spin_unlock_irqrestore(&priv->lock, flags); |
1313 | } | 1281 | } |
1314 | 1282 | ||
1315 | static irqreturn_t iwl_isr(int irq, void *data) | ||
1316 | { | ||
1317 | struct iwl_priv *priv = data; | ||
1318 | u32 inta, inta_mask; | ||
1319 | u32 inta_fh; | ||
1320 | if (!priv) | ||
1321 | return IRQ_NONE; | ||
1322 | |||
1323 | spin_lock(&priv->lock); | ||
1324 | |||
1325 | /* Disable (but don't clear!) interrupts here to avoid | ||
1326 | * back-to-back ISRs and sporadic interrupts from our NIC. | ||
1327 | * If we have something to service, the tasklet will re-enable ints. | ||
1328 | * If we *don't* have something, we'll re-enable before leaving here. */ | ||
1329 | inta_mask = iwl_read32(priv, CSR_INT_MASK); /* just for debug */ | ||
1330 | iwl_write32(priv, CSR_INT_MASK, 0x00000000); | ||
1331 | |||
1332 | /* Discover which interrupts are active/pending */ | ||
1333 | inta = iwl_read32(priv, CSR_INT); | ||
1334 | inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS); | ||
1335 | |||
1336 | /* Ignore interrupt if there's nothing in NIC to service. | ||
1337 | * This may be due to IRQ shared with another device, | ||
1338 | * or due to sporadic interrupts thrown from our NIC. */ | ||
1339 | if (!inta && !inta_fh) { | ||
1340 | IWL_DEBUG_ISR(priv, "Ignore interrupt, inta == 0, inta_fh == 0\n"); | ||
1341 | goto none; | ||
1342 | } | ||
1343 | |||
1344 | if ((inta == 0xFFFFFFFF) || ((inta & 0xFFFFFFF0) == 0xa5a5a5a0)) { | ||
1345 | /* Hardware disappeared. It might have already raised | ||
1346 | * an interrupt */ | ||
1347 | IWL_WARN(priv, "HARDWARE GONE?? INTA == 0x%08x\n", inta); | ||
1348 | goto unplugged; | ||
1349 | } | ||
1350 | |||
1351 | IWL_DEBUG_ISR(priv, "ISR inta 0x%08x, enabled 0x%08x, fh 0x%08x\n", | ||
1352 | inta, inta_mask, inta_fh); | ||
1353 | |||
1354 | inta &= ~CSR_INT_BIT_SCD; | ||
1355 | |||
1356 | /* iwl_irq_tasklet() will service interrupts and re-enable them */ | ||
1357 | if (likely(inta || inta_fh)) | ||
1358 | tasklet_schedule(&priv->irq_tasklet); | ||
1359 | |||
1360 | unplugged: | ||
1361 | spin_unlock(&priv->lock); | ||
1362 | return IRQ_HANDLED; | ||
1363 | |||
1364 | none: | ||
1365 | /* re-enable interrupts here since we don't have anything to service. */ | ||
1366 | /* only Re-enable if diabled by irq */ | ||
1367 | if (test_bit(STATUS_INT_ENABLED, &priv->status)) | ||
1368 | iwl_enable_interrupts(priv); | ||
1369 | spin_unlock(&priv->lock); | ||
1370 | return IRQ_NONE; | ||
1371 | } | ||
1372 | |||
1373 | /****************************************************************************** | 1283 | /****************************************************************************** |
1374 | * | 1284 | * |
1375 | * uCode download functions | 1285 | * uCode download functions |
@@ -2674,71 +2584,6 @@ static void iwl_bss_info_changed(struct ieee80211_hw *hw, | |||
2674 | 2584 | ||
2675 | } | 2585 | } |
2676 | 2586 | ||
2677 | static int iwl_mac_hw_scan(struct ieee80211_hw *hw, | ||
2678 | struct cfg80211_scan_request *req) | ||
2679 | { | ||
2680 | unsigned long flags; | ||
2681 | struct iwl_priv *priv = hw->priv; | ||
2682 | int ret; | ||
2683 | u8 *ssid = NULL; | ||
2684 | size_t ssid_len = 0; | ||
2685 | |||
2686 | if (req->n_ssids) { | ||
2687 | ssid = req->ssids[0].ssid; | ||
2688 | ssid_len = req->ssids[0].ssid_len; | ||
2689 | } | ||
2690 | |||
2691 | IWL_DEBUG_MAC80211(priv, "enter\n"); | ||
2692 | |||
2693 | mutex_lock(&priv->mutex); | ||
2694 | spin_lock_irqsave(&priv->lock, flags); | ||
2695 | |||
2696 | if (!iwl_is_ready_rf(priv)) { | ||
2697 | ret = -EIO; | ||
2698 | IWL_DEBUG_MAC80211(priv, "leave - not ready or exit pending\n"); | ||
2699 | goto out_unlock; | ||
2700 | } | ||
2701 | |||
2702 | /* We don't schedule scan within next_scan_jiffies period. | ||
2703 | * Avoid scanning during possible EAPOL exchange, return | ||
2704 | * success immediately. | ||
2705 | */ | ||
2706 | if (priv->next_scan_jiffies && | ||
2707 | time_after(priv->next_scan_jiffies, jiffies)) { | ||
2708 | IWL_DEBUG_SCAN(priv, "scan rejected: within next scan period\n"); | ||
2709 | queue_work(priv->workqueue, &priv->scan_completed); | ||
2710 | ret = 0; | ||
2711 | goto out_unlock; | ||
2712 | } | ||
2713 | |||
2714 | /* if we just finished scan ask for delay */ | ||
2715 | if (iwl_is_associated(priv) && priv->last_scan_jiffies && | ||
2716 | time_after(priv->last_scan_jiffies + IWL_DELAY_NEXT_SCAN, jiffies)) { | ||
2717 | IWL_DEBUG_SCAN(priv, "scan rejected: within previous scan period\n"); | ||
2718 | queue_work(priv->workqueue, &priv->scan_completed); | ||
2719 | ret = 0; | ||
2720 | goto out_unlock; | ||
2721 | } | ||
2722 | |||
2723 | if (ssid_len) { | ||
2724 | priv->one_direct_scan = 1; | ||
2725 | priv->direct_ssid_len = ssid_len; | ||
2726 | memcpy(priv->direct_ssid, ssid, priv->direct_ssid_len); | ||
2727 | } else { | ||
2728 | priv->one_direct_scan = 0; | ||
2729 | } | ||
2730 | |||
2731 | ret = iwl_scan_initiate(priv); | ||
2732 | |||
2733 | IWL_DEBUG_MAC80211(priv, "leave\n"); | ||
2734 | |||
2735 | out_unlock: | ||
2736 | spin_unlock_irqrestore(&priv->lock, flags); | ||
2737 | mutex_unlock(&priv->mutex); | ||
2738 | |||
2739 | return ret; | ||
2740 | } | ||
2741 | |||
2742 | static void iwl_mac_update_tkip_key(struct ieee80211_hw *hw, | 2587 | static void iwl_mac_update_tkip_key(struct ieee80211_hw *hw, |
2743 | struct ieee80211_key_conf *keyconf, const u8 *addr, | 2588 | struct ieee80211_key_conf *keyconf, const u8 *addr, |
2744 | u32 iv32, u16 *phase1key) | 2589 | u32 iv32, u16 *phase1key) |
@@ -3370,7 +3215,7 @@ static DEVICE_ATTR(statistics, S_IRUGO, show_statistics, NULL); | |||
3370 | 3215 | ||
3371 | static void iwl_setup_deferred_work(struct iwl_priv *priv) | 3216 | static void iwl_setup_deferred_work(struct iwl_priv *priv) |
3372 | { | 3217 | { |
3373 | priv->workqueue = create_workqueue(DRV_NAME); | 3218 | priv->workqueue = create_singlethread_workqueue(DRV_NAME); |
3374 | 3219 | ||
3375 | init_waitqueue_head(&priv->wait_command_queue); | 3220 | init_waitqueue_head(&priv->wait_command_queue); |
3376 | 3221 | ||
@@ -3612,7 +3457,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
3612 | err = sysfs_create_group(&pdev->dev.kobj, &iwl_attribute_group); | 3457 | err = sysfs_create_group(&pdev->dev.kobj, &iwl_attribute_group); |
3613 | if (err) { | 3458 | if (err) { |
3614 | IWL_ERR(priv, "failed to create sysfs device attributes\n"); | 3459 | IWL_ERR(priv, "failed to create sysfs device attributes\n"); |
3615 | goto out_uninit_drv; | 3460 | goto out_free_irq; |
3616 | } | 3461 | } |
3617 | 3462 | ||
3618 | iwl_setup_deferred_work(priv); | 3463 | iwl_setup_deferred_work(priv); |
@@ -3657,10 +3502,10 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
3657 | 3502 | ||
3658 | out_remove_sysfs: | 3503 | out_remove_sysfs: |
3659 | sysfs_remove_group(&pdev->dev.kobj, &iwl_attribute_group); | 3504 | sysfs_remove_group(&pdev->dev.kobj, &iwl_attribute_group); |
3505 | out_free_irq: | ||
3506 | free_irq(priv->pci_dev->irq, priv); | ||
3660 | out_disable_msi: | 3507 | out_disable_msi: |
3661 | pci_disable_msi(priv->pci_dev); | 3508 | pci_disable_msi(priv->pci_dev); |
3662 | pci_disable_device(priv->pci_dev); | ||
3663 | out_uninit_drv: | ||
3664 | iwl_uninit_drv(priv); | 3509 | iwl_uninit_drv(priv); |
3665 | out_free_eeprom: | 3510 | out_free_eeprom: |
3666 | iwl_eeprom_free(priv); | 3511 | iwl_eeprom_free(priv); |
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 260bf903cb71..37069d4c6c9b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c | |||
@@ -1386,14 +1386,16 @@ int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force) | |||
1386 | { | 1386 | { |
1387 | int ret = 0; | 1387 | int ret = 0; |
1388 | if (tx_power < IWL_TX_POWER_TARGET_POWER_MIN) { | 1388 | if (tx_power < IWL_TX_POWER_TARGET_POWER_MIN) { |
1389 | IWL_WARN(priv, "Requested user TXPOWER %d below limit.\n", | 1389 | IWL_WARN(priv, "Requested user TXPOWER %d below lower limit %d.\n", |
1390 | priv->tx_power_user_lmt); | 1390 | tx_power, |
1391 | IWL_TX_POWER_TARGET_POWER_MIN); | ||
1391 | return -EINVAL; | 1392 | return -EINVAL; |
1392 | } | 1393 | } |
1393 | 1394 | ||
1394 | if (tx_power > IWL_TX_POWER_TARGET_POWER_MAX) { | 1395 | if (tx_power > IWL_TX_POWER_TARGET_POWER_MAX) { |
1395 | IWL_WARN(priv, "Requested user TXPOWER %d above limit.\n", | 1396 | IWL_WARN(priv, "Requested user TXPOWER %d above upper limit %d.\n", |
1396 | priv->tx_power_user_lmt); | 1397 | tx_power, |
1398 | IWL_TX_POWER_TARGET_POWER_MAX); | ||
1397 | return -EINVAL; | 1399 | return -EINVAL; |
1398 | } | 1400 | } |
1399 | 1401 | ||
@@ -1442,6 +1444,65 @@ void iwl_enable_interrupts(struct iwl_priv *priv) | |||
1442 | } | 1444 | } |
1443 | EXPORT_SYMBOL(iwl_enable_interrupts); | 1445 | EXPORT_SYMBOL(iwl_enable_interrupts); |
1444 | 1446 | ||
1447 | irqreturn_t iwl_isr(int irq, void *data) | ||
1448 | { | ||
1449 | struct iwl_priv *priv = data; | ||
1450 | u32 inta, inta_mask; | ||
1451 | u32 inta_fh; | ||
1452 | if (!priv) | ||
1453 | return IRQ_NONE; | ||
1454 | |||
1455 | spin_lock(&priv->lock); | ||
1456 | |||
1457 | /* Disable (but don't clear!) interrupts here to avoid | ||
1458 | * back-to-back ISRs and sporadic interrupts from our NIC. | ||
1459 | * If we have something to service, the tasklet will re-enable ints. | ||
1460 | * If we *don't* have something, we'll re-enable before leaving here. */ | ||
1461 | inta_mask = iwl_read32(priv, CSR_INT_MASK); /* just for debug */ | ||
1462 | iwl_write32(priv, CSR_INT_MASK, 0x00000000); | ||
1463 | |||
1464 | /* Discover which interrupts are active/pending */ | ||
1465 | inta = iwl_read32(priv, CSR_INT); | ||
1466 | inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS); | ||
1467 | |||
1468 | /* Ignore interrupt if there's nothing in NIC to service. | ||
1469 | * This may be due to IRQ shared with another device, | ||
1470 | * or due to sporadic interrupts thrown from our NIC. */ | ||
1471 | if (!inta && !inta_fh) { | ||
1472 | IWL_DEBUG_ISR(priv, "Ignore interrupt, inta == 0, inta_fh == 0\n"); | ||
1473 | goto none; | ||
1474 | } | ||
1475 | |||
1476 | if ((inta == 0xFFFFFFFF) || ((inta & 0xFFFFFFF0) == 0xa5a5a5a0)) { | ||
1477 | /* Hardware disappeared. It might have already raised | ||
1478 | * an interrupt */ | ||
1479 | IWL_WARN(priv, "HARDWARE GONE?? INTA == 0x%08x\n", inta); | ||
1480 | goto unplugged; | ||
1481 | } | ||
1482 | |||
1483 | IWL_DEBUG_ISR(priv, "ISR inta 0x%08x, enabled 0x%08x, fh 0x%08x\n", | ||
1484 | inta, inta_mask, inta_fh); | ||
1485 | |||
1486 | inta &= ~CSR_INT_BIT_SCD; | ||
1487 | |||
1488 | /* iwl_irq_tasklet() will service interrupts and re-enable them */ | ||
1489 | if (likely(inta || inta_fh)) | ||
1490 | tasklet_schedule(&priv->irq_tasklet); | ||
1491 | |||
1492 | unplugged: | ||
1493 | spin_unlock(&priv->lock); | ||
1494 | return IRQ_HANDLED; | ||
1495 | |||
1496 | none: | ||
1497 | /* re-enable interrupts here since we don't have anything to service. */ | ||
1498 | /* only Re-enable if diabled by irq */ | ||
1499 | if (test_bit(STATUS_INT_ENABLED, &priv->status)) | ||
1500 | iwl_enable_interrupts(priv); | ||
1501 | spin_unlock(&priv->lock); | ||
1502 | return IRQ_NONE; | ||
1503 | } | ||
1504 | EXPORT_SYMBOL(iwl_isr); | ||
1505 | |||
1445 | int iwl_send_bt_config(struct iwl_priv *priv) | 1506 | int iwl_send_bt_config(struct iwl_priv *priv) |
1446 | { | 1507 | { |
1447 | struct iwl_bt_cmd bt_cmd = { | 1508 | struct iwl_bt_cmd bt_cmd = { |
@@ -1977,3 +2038,42 @@ void iwl_bg_rf_kill(struct work_struct *work) | |||
1977 | iwl_rfkill_set_hw_state(priv); | 2038 | iwl_rfkill_set_hw_state(priv); |
1978 | } | 2039 | } |
1979 | EXPORT_SYMBOL(iwl_bg_rf_kill); | 2040 | EXPORT_SYMBOL(iwl_bg_rf_kill); |
2041 | |||
2042 | void iwl_rx_pm_sleep_notif(struct iwl_priv *priv, | ||
2043 | struct iwl_rx_mem_buffer *rxb) | ||
2044 | { | ||
2045 | #ifdef CONFIG_IWLWIFI_DEBUG | ||
2046 | struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; | ||
2047 | struct iwl_sleep_notification *sleep = &(pkt->u.sleep_notif); | ||
2048 | IWL_DEBUG_RX(priv, "sleep mode: %d, src: %d\n", | ||
2049 | sleep->pm_sleep_mode, sleep->pm_wakeup_src); | ||
2050 | #endif | ||
2051 | } | ||
2052 | EXPORT_SYMBOL(iwl_rx_pm_sleep_notif); | ||
2053 | |||
2054 | void iwl_rx_pm_debug_statistics_notif(struct iwl_priv *priv, | ||
2055 | struct iwl_rx_mem_buffer *rxb) | ||
2056 | { | ||
2057 | struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; | ||
2058 | IWL_DEBUG_RADIO(priv, "Dumping %d bytes of unhandled " | ||
2059 | "notification for %s:\n", | ||
2060 | le32_to_cpu(pkt->len), get_cmd_string(pkt->hdr.cmd)); | ||
2061 | iwl_print_hex_dump(priv, IWL_DL_RADIO, pkt->u.raw, le32_to_cpu(pkt->len)); | ||
2062 | } | ||
2063 | EXPORT_SYMBOL(iwl_rx_pm_debug_statistics_notif); | ||
2064 | |||
2065 | void iwl_rx_reply_error(struct iwl_priv *priv, | ||
2066 | struct iwl_rx_mem_buffer *rxb) | ||
2067 | { | ||
2068 | struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; | ||
2069 | |||
2070 | IWL_ERR(priv, "Error Reply type 0x%08X cmd %s (0x%02X) " | ||
2071 | "seq 0x%04X ser 0x%08X\n", | ||
2072 | le32_to_cpu(pkt->u.err_resp.error_type), | ||
2073 | get_cmd_string(pkt->u.err_resp.cmd_id), | ||
2074 | pkt->u.err_resp.cmd_id, | ||
2075 | le16_to_cpu(pkt->u.err_resp.bad_cmd_seq_num), | ||
2076 | le32_to_cpu(pkt->u.err_resp.error_info)); | ||
2077 | } | ||
2078 | EXPORT_SYMBOL(iwl_rx_reply_error); | ||
2079 | |||
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 9d464ec99dd5..7427d75b8c8c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h | |||
@@ -250,6 +250,16 @@ int iwl_init_drv(struct iwl_priv *priv); | |||
250 | void iwl_uninit_drv(struct iwl_priv *priv); | 250 | void iwl_uninit_drv(struct iwl_priv *priv); |
251 | 251 | ||
252 | /***************************************************** | 252 | /***************************************************** |
253 | * RX handlers. | ||
254 | * **************************************************/ | ||
255 | void iwl_rx_pm_sleep_notif(struct iwl_priv *priv, | ||
256 | struct iwl_rx_mem_buffer *rxb); | ||
257 | void iwl_rx_pm_debug_statistics_notif(struct iwl_priv *priv, | ||
258 | struct iwl_rx_mem_buffer *rxb); | ||
259 | void iwl_rx_reply_error(struct iwl_priv *priv, | ||
260 | struct iwl_rx_mem_buffer *rxb); | ||
261 | |||
262 | /***************************************************** | ||
253 | * RX | 263 | * RX |
254 | ******************************************************/ | 264 | ******************************************************/ |
255 | void iwl_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rxq); | 265 | void iwl_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rxq); |
@@ -345,6 +355,7 @@ void iwl_init_scan_params(struct iwl_priv *priv); | |||
345 | int iwl_scan_cancel(struct iwl_priv *priv); | 355 | int iwl_scan_cancel(struct iwl_priv *priv); |
346 | int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms); | 356 | int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms); |
347 | int iwl_scan_initiate(struct iwl_priv *priv); | 357 | int iwl_scan_initiate(struct iwl_priv *priv); |
358 | int iwl_mac_hw_scan(struct ieee80211_hw *hw, struct cfg80211_scan_request *req); | ||
348 | u16 iwl_fill_probe_req(struct iwl_priv *priv, enum ieee80211_band band, | 359 | u16 iwl_fill_probe_req(struct iwl_priv *priv, enum ieee80211_band band, |
349 | struct ieee80211_mgmt *frame, int left); | 360 | struct ieee80211_mgmt *frame, int left); |
350 | void iwl_setup_rx_scan_handlers(struct iwl_priv *priv); | 361 | void iwl_setup_rx_scan_handlers(struct iwl_priv *priv); |
@@ -379,7 +390,7 @@ void iwl_calib_free_results(struct iwl_priv *priv); | |||
379 | /******************************************************************************* | 390 | /******************************************************************************* |
380 | * Spectrum Measureemtns in iwl-spectrum.c | 391 | * Spectrum Measureemtns in iwl-spectrum.c |
381 | ******************************************************************************/ | 392 | ******************************************************************************/ |
382 | #ifdef CONFIG_IWLAGN_SPECTRUM_MEASUREMENT | 393 | #ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT |
383 | void iwl_setup_spectrum_handlers(struct iwl_priv *priv); | 394 | void iwl_setup_spectrum_handlers(struct iwl_priv *priv); |
384 | #else | 395 | #else |
385 | static inline void iwl_setup_spectrum_handlers(struct iwl_priv *priv) {} | 396 | static inline void iwl_setup_spectrum_handlers(struct iwl_priv *priv) {} |
@@ -410,6 +421,7 @@ int iwl_send_card_state(struct iwl_priv *priv, u32 flags, | |||
410 | *****************************************************/ | 421 | *****************************************************/ |
411 | void iwl_disable_interrupts(struct iwl_priv *priv); | 422 | void iwl_disable_interrupts(struct iwl_priv *priv); |
412 | void iwl_enable_interrupts(struct iwl_priv *priv); | 423 | void iwl_enable_interrupts(struct iwl_priv *priv); |
424 | irqreturn_t iwl_isr(int irq, void *data); | ||
413 | static inline u16 iwl_pcie_link_ctl(struct iwl_priv *priv) | 425 | static inline u16 iwl_pcie_link_ctl(struct iwl_priv *priv) |
414 | { | 426 | { |
415 | int pos; | 427 | int pos; |
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index afde713c806f..b3e23abb9117 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h | |||
@@ -841,7 +841,7 @@ struct iwl_priv { | |||
841 | 841 | ||
842 | struct ieee80211_supported_band bands[IEEE80211_NUM_BANDS]; | 842 | struct ieee80211_supported_band bands[IEEE80211_NUM_BANDS]; |
843 | 843 | ||
844 | #if defined(CONFIG_IWLAGN_SPECTRUM_MEASUREMENT) || defined(CONFIG_IWL3945_SPECTRUM_MEASUREMENT) | 844 | #if defined(CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT) || defined(CONFIG_IWL3945_SPECTRUM_MEASUREMENT) |
845 | /* spectrum measurement report caching */ | 845 | /* spectrum measurement report caching */ |
846 | struct iwl_spectrum_notification measure_report; | 846 | struct iwl_spectrum_notification measure_report; |
847 | u8 measurement_status; | 847 | u8 measurement_status; |
@@ -922,7 +922,7 @@ struct iwl_priv { | |||
922 | * 4965's initialize alive response contains some calibration data. */ | 922 | * 4965's initialize alive response contains some calibration data. */ |
923 | struct iwl_init_alive_resp card_alive_init; | 923 | struct iwl_init_alive_resp card_alive_init; |
924 | struct iwl_alive_resp card_alive; | 924 | struct iwl_alive_resp card_alive; |
925 | #if defined(CONFIG_IWLWIFI_RFKILL) || defined(CONFIG_IWL3945_RFKILL) | 925 | #if defined(CONFIG_IWLWIFI_RFKILL) |
926 | struct rfkill *rfkill; | 926 | struct rfkill *rfkill; |
927 | #endif | 927 | #endif |
928 | 928 | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index 1ec2b20eb37c..23644cf884f1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c | |||
@@ -440,6 +440,74 @@ int iwl_scan_initiate(struct iwl_priv *priv) | |||
440 | } | 440 | } |
441 | EXPORT_SYMBOL(iwl_scan_initiate); | 441 | EXPORT_SYMBOL(iwl_scan_initiate); |
442 | 442 | ||
443 | #define IWL_DELAY_NEXT_SCAN (HZ*2) | ||
444 | |||
445 | int iwl_mac_hw_scan(struct ieee80211_hw *hw, | ||
446 | struct cfg80211_scan_request *req) | ||
447 | { | ||
448 | unsigned long flags; | ||
449 | struct iwl_priv *priv = hw->priv; | ||
450 | int ret; | ||
451 | u8 *ssid = NULL; | ||
452 | size_t ssid_len = 0; | ||
453 | |||
454 | if (req->n_ssids) { | ||
455 | ssid = req->ssids[0].ssid; | ||
456 | ssid_len = req->ssids[0].ssid_len; | ||
457 | } | ||
458 | |||
459 | IWL_DEBUG_MAC80211(priv, "enter\n"); | ||
460 | |||
461 | mutex_lock(&priv->mutex); | ||
462 | spin_lock_irqsave(&priv->lock, flags); | ||
463 | |||
464 | if (!iwl_is_ready_rf(priv)) { | ||
465 | ret = -EIO; | ||
466 | IWL_DEBUG_MAC80211(priv, "leave - not ready or exit pending\n"); | ||
467 | goto out_unlock; | ||
468 | } | ||
469 | |||
470 | /* We don't schedule scan within next_scan_jiffies period. | ||
471 | * Avoid scanning during possible EAPOL exchange, return | ||
472 | * success immediately. | ||
473 | */ | ||
474 | if (priv->next_scan_jiffies && | ||
475 | time_after(priv->next_scan_jiffies, jiffies)) { | ||
476 | IWL_DEBUG_SCAN(priv, "scan rejected: within next scan period\n"); | ||
477 | queue_work(priv->workqueue, &priv->scan_completed); | ||
478 | ret = 0; | ||
479 | goto out_unlock; | ||
480 | } | ||
481 | |||
482 | /* if we just finished scan ask for delay */ | ||
483 | if (iwl_is_associated(priv) && priv->last_scan_jiffies && | ||
484 | time_after(priv->last_scan_jiffies + IWL_DELAY_NEXT_SCAN, jiffies)) { | ||
485 | IWL_DEBUG_SCAN(priv, "scan rejected: within previous scan period\n"); | ||
486 | queue_work(priv->workqueue, &priv->scan_completed); | ||
487 | ret = 0; | ||
488 | goto out_unlock; | ||
489 | } | ||
490 | |||
491 | if (ssid_len) { | ||
492 | priv->one_direct_scan = 1; | ||
493 | priv->direct_ssid_len = ssid_len; | ||
494 | memcpy(priv->direct_ssid, ssid, priv->direct_ssid_len); | ||
495 | } else { | ||
496 | priv->one_direct_scan = 0; | ||
497 | } | ||
498 | |||
499 | ret = iwl_scan_initiate(priv); | ||
500 | |||
501 | IWL_DEBUG_MAC80211(priv, "leave\n"); | ||
502 | |||
503 | out_unlock: | ||
504 | spin_unlock_irqrestore(&priv->lock, flags); | ||
505 | mutex_unlock(&priv->mutex); | ||
506 | |||
507 | return ret; | ||
508 | } | ||
509 | EXPORT_SYMBOL(iwl_mac_hw_scan); | ||
510 | |||
443 | #define IWL_SCAN_CHECK_WATCHDOG (7 * HZ) | 511 | #define IWL_SCAN_CHECK_WATCHDOG (7 * HZ) |
444 | 512 | ||
445 | void iwl_bg_scan_check(struct work_struct *data) | 513 | void iwl_bg_scan_check(struct work_struct *data) |
diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index ae04c2086f70..dff60fb70214 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c | |||
@@ -819,7 +819,7 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) | |||
819 | * within command buffer array. */ | 819 | * within command buffer array. */ |
820 | txcmd_phys = pci_map_single(priv->pci_dev, | 820 | txcmd_phys = pci_map_single(priv->pci_dev, |
821 | out_cmd, sizeof(struct iwl_cmd), | 821 | out_cmd, sizeof(struct iwl_cmd), |
822 | PCI_DMA_TODEVICE); | 822 | PCI_DMA_BIDIRECTIONAL); |
823 | pci_unmap_addr_set(&out_cmd->meta, mapping, txcmd_phys); | 823 | pci_unmap_addr_set(&out_cmd->meta, mapping, txcmd_phys); |
824 | pci_unmap_len_set(&out_cmd->meta, len, sizeof(struct iwl_cmd)); | 824 | pci_unmap_len_set(&out_cmd->meta, len, sizeof(struct iwl_cmd)); |
825 | /* Add buffer containing Tx command and MAC(!) header to TFD's | 825 | /* Add buffer containing Tx command and MAC(!) header to TFD's |
@@ -968,7 +968,7 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) | |||
968 | IWL_MAX_SCAN_SIZE : sizeof(struct iwl_cmd); | 968 | IWL_MAX_SCAN_SIZE : sizeof(struct iwl_cmd); |
969 | 969 | ||
970 | phys_addr = pci_map_single(priv->pci_dev, out_cmd, | 970 | phys_addr = pci_map_single(priv->pci_dev, out_cmd, |
971 | len, PCI_DMA_TODEVICE); | 971 | len, PCI_DMA_BIDIRECTIONAL); |
972 | pci_unmap_addr_set(&out_cmd->meta, mapping, phys_addr); | 972 | pci_unmap_addr_set(&out_cmd->meta, mapping, phys_addr); |
973 | pci_unmap_len_set(&out_cmd->meta, len, len); | 973 | pci_unmap_len_set(&out_cmd->meta, len, len); |
974 | phys_addr += offsetof(struct iwl_cmd, hdr); | 974 | phys_addr += offsetof(struct iwl_cmd, hdr); |
@@ -1068,7 +1068,7 @@ static void iwl_hcmd_queue_reclaim(struct iwl_priv *priv, int txq_id, | |||
1068 | pci_unmap_single(priv->pci_dev, | 1068 | pci_unmap_single(priv->pci_dev, |
1069 | pci_unmap_addr(&txq->cmd[cmd_idx]->meta, mapping), | 1069 | pci_unmap_addr(&txq->cmd[cmd_idx]->meta, mapping), |
1070 | pci_unmap_len(&txq->cmd[cmd_idx]->meta, len), | 1070 | pci_unmap_len(&txq->cmd[cmd_idx]->meta, len), |
1071 | PCI_DMA_TODEVICE); | 1071 | PCI_DMA_BIDIRECTIONAL); |
1072 | 1072 | ||
1073 | for (idx = iwl_queue_inc_wrap(idx, q->n_bd); q->read_ptr != idx; | 1073 | for (idx = iwl_queue_inc_wrap(idx, q->n_bd); q->read_ptr != idx; |
1074 | q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) { | 1074 | q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) { |
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 0cd8cb96a5ef..d0596e7f64e6 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c | |||
@@ -726,38 +726,6 @@ static void iwl3945_setup_rxon_timing(struct iwl_priv *priv) | |||
726 | le16_to_cpu(priv->rxon_timing.atim_window)); | 726 | le16_to_cpu(priv->rxon_timing.atim_window)); |
727 | } | 727 | } |
728 | 728 | ||
729 | static int iwl3945_scan_initiate(struct iwl_priv *priv) | ||
730 | { | ||
731 | if (!iwl_is_ready_rf(priv)) { | ||
732 | IWL_DEBUG_SCAN(priv, "Aborting scan due to not ready.\n"); | ||
733 | return -EIO; | ||
734 | } | ||
735 | |||
736 | if (test_bit(STATUS_SCANNING, &priv->status)) { | ||
737 | IWL_DEBUG_SCAN(priv, "Scan already in progress.\n"); | ||
738 | return -EAGAIN; | ||
739 | } | ||
740 | |||
741 | if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) { | ||
742 | IWL_DEBUG_SCAN(priv, "Scan request while abort pending. " | ||
743 | "Queuing.\n"); | ||
744 | return -EAGAIN; | ||
745 | } | ||
746 | |||
747 | IWL_DEBUG_INFO(priv, "Starting scan...\n"); | ||
748 | if (priv->cfg->sku & IWL_SKU_G) | ||
749 | priv->scan_bands |= BIT(IEEE80211_BAND_2GHZ); | ||
750 | if (priv->cfg->sku & IWL_SKU_A) | ||
751 | priv->scan_bands |= BIT(IEEE80211_BAND_5GHZ); | ||
752 | set_bit(STATUS_SCANNING, &priv->status); | ||
753 | priv->scan_start = jiffies; | ||
754 | priv->scan_pass_start = priv->scan_start; | ||
755 | |||
756 | queue_work(priv->workqueue, &priv->request_scan); | ||
757 | |||
758 | return 0; | ||
759 | } | ||
760 | |||
761 | static int iwl3945_set_mode(struct iwl_priv *priv, int mode) | 729 | static int iwl3945_set_mode(struct iwl_priv *priv, int mode) |
762 | { | 730 | { |
763 | if (mode == NL80211_IFTYPE_ADHOC) { | 731 | if (mode == NL80211_IFTYPE_ADHOC) { |
@@ -1188,56 +1156,6 @@ drop: | |||
1188 | return -1; | 1156 | return -1; |
1189 | } | 1157 | } |
1190 | 1158 | ||
1191 | static void iwl3945_radio_kill_sw(struct iwl_priv *priv, int disable_radio) | ||
1192 | { | ||
1193 | unsigned long flags; | ||
1194 | |||
1195 | if (!!disable_radio == test_bit(STATUS_RF_KILL_SW, &priv->status)) | ||
1196 | return; | ||
1197 | |||
1198 | IWL_DEBUG_RF_KILL(priv, "Manual SW RF KILL set to: RADIO %s\n", | ||
1199 | disable_radio ? "OFF" : "ON"); | ||
1200 | |||
1201 | if (disable_radio) { | ||
1202 | iwl_scan_cancel(priv); | ||
1203 | /* FIXME: This is a workaround for AP */ | ||
1204 | if (priv->iw_mode != NL80211_IFTYPE_AP) { | ||
1205 | spin_lock_irqsave(&priv->lock, flags); | ||
1206 | iwl_write32(priv, CSR_UCODE_DRV_GP1_SET, | ||
1207 | CSR_UCODE_SW_BIT_RFKILL); | ||
1208 | spin_unlock_irqrestore(&priv->lock, flags); | ||
1209 | iwl_send_card_state(priv, CARD_STATE_CMD_DISABLE, 0); | ||
1210 | set_bit(STATUS_RF_KILL_SW, &priv->status); | ||
1211 | } | ||
1212 | return; | ||
1213 | } | ||
1214 | |||
1215 | spin_lock_irqsave(&priv->lock, flags); | ||
1216 | iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); | ||
1217 | |||
1218 | clear_bit(STATUS_RF_KILL_SW, &priv->status); | ||
1219 | spin_unlock_irqrestore(&priv->lock, flags); | ||
1220 | |||
1221 | /* wake up ucode */ | ||
1222 | msleep(10); | ||
1223 | |||
1224 | spin_lock_irqsave(&priv->lock, flags); | ||
1225 | iwl_read32(priv, CSR_UCODE_DRV_GP1); | ||
1226 | if (!iwl_grab_nic_access(priv)) | ||
1227 | iwl_release_nic_access(priv); | ||
1228 | spin_unlock_irqrestore(&priv->lock, flags); | ||
1229 | |||
1230 | if (test_bit(STATUS_RF_KILL_HW, &priv->status)) { | ||
1231 | IWL_DEBUG_RF_KILL(priv, "Can not turn radio back on - " | ||
1232 | "disabled by HW switch\n"); | ||
1233 | return; | ||
1234 | } | ||
1235 | |||
1236 | if (priv->is_open) | ||
1237 | queue_work(priv->workqueue, &priv->restart); | ||
1238 | return; | ||
1239 | } | ||
1240 | |||
1241 | #ifdef CONFIG_IWL3945_SPECTRUM_MEASUREMENT | 1159 | #ifdef CONFIG_IWL3945_SPECTRUM_MEASUREMENT |
1242 | 1160 | ||
1243 | #include "iwl-spectrum.h" | 1161 | #include "iwl-spectrum.h" |
@@ -1417,60 +1335,6 @@ static void iwl3945_rx_reply_add_sta(struct iwl_priv *priv, | |||
1417 | return; | 1335 | return; |
1418 | } | 1336 | } |
1419 | 1337 | ||
1420 | static void iwl3945_rx_reply_error(struct iwl_priv *priv, | ||
1421 | struct iwl_rx_mem_buffer *rxb) | ||
1422 | { | ||
1423 | struct iwl_rx_packet *pkt = (void *)rxb->skb->data; | ||
1424 | |||
1425 | IWL_ERR(priv, "Error Reply type 0x%08X cmd %s (0x%02X) " | ||
1426 | "seq 0x%04X ser 0x%08X\n", | ||
1427 | le32_to_cpu(pkt->u.err_resp.error_type), | ||
1428 | get_cmd_string(pkt->u.err_resp.cmd_id), | ||
1429 | pkt->u.err_resp.cmd_id, | ||
1430 | le16_to_cpu(pkt->u.err_resp.bad_cmd_seq_num), | ||
1431 | le32_to_cpu(pkt->u.err_resp.error_info)); | ||
1432 | } | ||
1433 | |||
1434 | static void iwl3945_rx_spectrum_measure_notif(struct iwl_priv *priv, | ||
1435 | struct iwl_rx_mem_buffer *rxb) | ||
1436 | { | ||
1437 | #ifdef CONFIG_IWL3945_SPECTRUM_MEASUREMENT | ||
1438 | struct iwl_rx_packet *pkt = (void *)rxb->skb->data; | ||
1439 | struct iwl_spectrum_notification *report = &(pkt->u.spectrum_notif); | ||
1440 | |||
1441 | if (!report->state) { | ||
1442 | IWL_DEBUG(priv, IWL_DL_11H | IWL_DL_INFO, | ||
1443 | "Spectrum Measure Notification: Start\n"); | ||
1444 | return; | ||
1445 | } | ||
1446 | |||
1447 | memcpy(&priv->measure_report, report, sizeof(*report)); | ||
1448 | priv->measurement_status |= MEASUREMENT_READY; | ||
1449 | #endif | ||
1450 | } | ||
1451 | |||
1452 | static void iwl3945_rx_pm_sleep_notif(struct iwl_priv *priv, | ||
1453 | struct iwl_rx_mem_buffer *rxb) | ||
1454 | { | ||
1455 | #ifdef CONFIG_IWLWIFI_DEBUG | ||
1456 | struct iwl_rx_packet *pkt = (void *)rxb->skb->data; | ||
1457 | struct iwl_sleep_notification *sleep = &(pkt->u.sleep_notif); | ||
1458 | IWL_DEBUG_RX(priv, "sleep mode: %d, src: %d\n", | ||
1459 | sleep->pm_sleep_mode, sleep->pm_wakeup_src); | ||
1460 | #endif | ||
1461 | } | ||
1462 | |||
1463 | static void iwl3945_rx_pm_debug_statistics_notif(struct iwl_priv *priv, | ||
1464 | struct iwl_rx_mem_buffer *rxb) | ||
1465 | { | ||
1466 | struct iwl_rx_packet *pkt = (void *)rxb->skb->data; | ||
1467 | IWL_DEBUG_RADIO(priv, "Dumping %d bytes of unhandled " | ||
1468 | "notification for %s:\n", | ||
1469 | le32_to_cpu(pkt->len), get_cmd_string(pkt->hdr.cmd)); | ||
1470 | iwl_print_hex_dump(priv, IWL_DL_RADIO, pkt->u.raw, | ||
1471 | le32_to_cpu(pkt->len)); | ||
1472 | } | ||
1473 | |||
1474 | static void iwl3945_bg_beacon_update(struct work_struct *work) | 1338 | static void iwl3945_bg_beacon_update(struct work_struct *work) |
1475 | { | 1339 | { |
1476 | struct iwl_priv *priv = | 1340 | struct iwl_priv *priv = |
@@ -1518,127 +1382,6 @@ static void iwl3945_rx_beacon_notif(struct iwl_priv *priv, | |||
1518 | queue_work(priv->workqueue, &priv->beacon_update); | 1382 | queue_work(priv->workqueue, &priv->beacon_update); |
1519 | } | 1383 | } |
1520 | 1384 | ||
1521 | /* Service response to REPLY_SCAN_CMD (0x80) */ | ||
1522 | static void iwl3945_rx_reply_scan(struct iwl_priv *priv, | ||
1523 | struct iwl_rx_mem_buffer *rxb) | ||
1524 | { | ||
1525 | #ifdef CONFIG_IWLWIFI_DEBUG | ||
1526 | struct iwl_rx_packet *pkt = (void *)rxb->skb->data; | ||
1527 | struct iwl_scanreq_notification *notif = | ||
1528 | (struct iwl_scanreq_notification *)pkt->u.raw; | ||
1529 | |||
1530 | IWL_DEBUG_RX(priv, "Scan request status = 0x%x\n", notif->status); | ||
1531 | #endif | ||
1532 | } | ||
1533 | |||
1534 | /* Service SCAN_START_NOTIFICATION (0x82) */ | ||
1535 | static void iwl3945_rx_scan_start_notif(struct iwl_priv *priv, | ||
1536 | struct iwl_rx_mem_buffer *rxb) | ||
1537 | { | ||
1538 | struct iwl_rx_packet *pkt = (void *)rxb->skb->data; | ||
1539 | struct iwl_scanstart_notification *notif = | ||
1540 | (struct iwl_scanstart_notification *)pkt->u.raw; | ||
1541 | priv->scan_start_tsf = le32_to_cpu(notif->tsf_low); | ||
1542 | IWL_DEBUG_SCAN(priv, "Scan start: " | ||
1543 | "%d [802.11%s] " | ||
1544 | "(TSF: 0x%08X:%08X) - %d (beacon timer %u)\n", | ||
1545 | notif->channel, | ||
1546 | notif->band ? "bg" : "a", | ||
1547 | notif->tsf_high, | ||
1548 | notif->tsf_low, notif->status, notif->beacon_timer); | ||
1549 | } | ||
1550 | |||
1551 | /* Service SCAN_RESULTS_NOTIFICATION (0x83) */ | ||
1552 | static void iwl3945_rx_scan_results_notif(struct iwl_priv *priv, | ||
1553 | struct iwl_rx_mem_buffer *rxb) | ||
1554 | { | ||
1555 | #ifdef CONFIG_IWLWIFI_DEBUG | ||
1556 | struct iwl_rx_packet *pkt = (void *)rxb->skb->data; | ||
1557 | struct iwl_scanresults_notification *notif = | ||
1558 | (struct iwl_scanresults_notification *)pkt->u.raw; | ||
1559 | #endif | ||
1560 | |||
1561 | IWL_DEBUG_SCAN(priv, "Scan ch.res: " | ||
1562 | "%d [802.11%s] " | ||
1563 | "(TSF: 0x%08X:%08X) - %d " | ||
1564 | "elapsed=%lu usec (%dms since last)\n", | ||
1565 | notif->channel, | ||
1566 | notif->band ? "bg" : "a", | ||
1567 | le32_to_cpu(notif->tsf_high), | ||
1568 | le32_to_cpu(notif->tsf_low), | ||
1569 | le32_to_cpu(notif->statistics[0]), | ||
1570 | le32_to_cpu(notif->tsf_low) - priv->scan_start_tsf, | ||
1571 | jiffies_to_msecs(elapsed_jiffies | ||
1572 | (priv->last_scan_jiffies, jiffies))); | ||
1573 | |||
1574 | priv->last_scan_jiffies = jiffies; | ||
1575 | priv->next_scan_jiffies = 0; | ||
1576 | } | ||
1577 | |||
1578 | /* Service SCAN_COMPLETE_NOTIFICATION (0x84) */ | ||
1579 | static void iwl3945_rx_scan_complete_notif(struct iwl_priv *priv, | ||
1580 | struct iwl_rx_mem_buffer *rxb) | ||
1581 | { | ||
1582 | #ifdef CONFIG_IWLWIFI_DEBUG | ||
1583 | struct iwl_rx_packet *pkt = (void *)rxb->skb->data; | ||
1584 | struct iwl_scancomplete_notification *scan_notif = (void *)pkt->u.raw; | ||
1585 | #endif | ||
1586 | |||
1587 | IWL_DEBUG_SCAN(priv, "Scan complete: %d channels (TSF 0x%08X:%08X) - %d\n", | ||
1588 | scan_notif->scanned_channels, | ||
1589 | scan_notif->tsf_low, | ||
1590 | scan_notif->tsf_high, scan_notif->status); | ||
1591 | |||
1592 | /* The HW is no longer scanning */ | ||
1593 | clear_bit(STATUS_SCAN_HW, &priv->status); | ||
1594 | |||
1595 | /* The scan completion notification came in, so kill that timer... */ | ||
1596 | cancel_delayed_work(&priv->scan_check); | ||
1597 | |||
1598 | IWL_DEBUG_INFO(priv, "Scan pass on %sGHz took %dms\n", | ||
1599 | (priv->scan_bands & BIT(IEEE80211_BAND_2GHZ)) ? | ||
1600 | "2.4" : "5.2", | ||
1601 | jiffies_to_msecs(elapsed_jiffies | ||
1602 | (priv->scan_pass_start, jiffies))); | ||
1603 | |||
1604 | /* Remove this scanned band from the list of pending | ||
1605 | * bands to scan, band G precedes A in order of scanning | ||
1606 | * as seen in iwl3945_bg_request_scan */ | ||
1607 | if (priv->scan_bands & BIT(IEEE80211_BAND_2GHZ)) | ||
1608 | priv->scan_bands &= ~BIT(IEEE80211_BAND_2GHZ); | ||
1609 | else if (priv->scan_bands & BIT(IEEE80211_BAND_5GHZ)) | ||
1610 | priv->scan_bands &= ~BIT(IEEE80211_BAND_5GHZ); | ||
1611 | |||
1612 | /* If a request to abort was given, or the scan did not succeed | ||
1613 | * then we reset the scan state machine and terminate, | ||
1614 | * re-queuing another scan if one has been requested */ | ||
1615 | if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) { | ||
1616 | IWL_DEBUG_INFO(priv, "Aborted scan completed.\n"); | ||
1617 | clear_bit(STATUS_SCAN_ABORTING, &priv->status); | ||
1618 | } else { | ||
1619 | /* If there are more bands on this scan pass reschedule */ | ||
1620 | if (priv->scan_bands > 0) | ||
1621 | goto reschedule; | ||
1622 | } | ||
1623 | |||
1624 | priv->last_scan_jiffies = jiffies; | ||
1625 | priv->next_scan_jiffies = 0; | ||
1626 | IWL_DEBUG_INFO(priv, "Setting scan to off\n"); | ||
1627 | |||
1628 | clear_bit(STATUS_SCANNING, &priv->status); | ||
1629 | |||
1630 | IWL_DEBUG_INFO(priv, "Scan took %dms\n", | ||
1631 | jiffies_to_msecs(elapsed_jiffies(priv->scan_start, jiffies))); | ||
1632 | |||
1633 | queue_work(priv->workqueue, &priv->scan_completed); | ||
1634 | |||
1635 | return; | ||
1636 | |||
1637 | reschedule: | ||
1638 | priv->scan_pass_start = jiffies; | ||
1639 | queue_work(priv->workqueue, &priv->request_scan); | ||
1640 | } | ||
1641 | |||
1642 | /* Handle notification from uCode that card's power state is changing | 1385 | /* Handle notification from uCode that card's power state is changing |
1643 | * due to software, hardware, or critical temperature RFKILL */ | 1386 | * due to software, hardware, or critical temperature RFKILL */ |
1644 | static void iwl3945_rx_card_state_notif(struct iwl_priv *priv, | 1387 | static void iwl3945_rx_card_state_notif(struct iwl_priv *priv, |
@@ -1690,13 +1433,11 @@ static void iwl3945_setup_rx_handlers(struct iwl_priv *priv) | |||
1690 | { | 1433 | { |
1691 | priv->rx_handlers[REPLY_ALIVE] = iwl3945_rx_reply_alive; | 1434 | priv->rx_handlers[REPLY_ALIVE] = iwl3945_rx_reply_alive; |
1692 | priv->rx_handlers[REPLY_ADD_STA] = iwl3945_rx_reply_add_sta; | 1435 | priv->rx_handlers[REPLY_ADD_STA] = iwl3945_rx_reply_add_sta; |
1693 | priv->rx_handlers[REPLY_ERROR] = iwl3945_rx_reply_error; | 1436 | priv->rx_handlers[REPLY_ERROR] = iwl_rx_reply_error; |
1694 | priv->rx_handlers[CHANNEL_SWITCH_NOTIFICATION] = iwl_rx_csa; | 1437 | priv->rx_handlers[CHANNEL_SWITCH_NOTIFICATION] = iwl_rx_csa; |
1695 | priv->rx_handlers[SPECTRUM_MEASURE_NOTIFICATION] = | 1438 | priv->rx_handlers[PM_SLEEP_NOTIFICATION] = iwl_rx_pm_sleep_notif; |
1696 | iwl3945_rx_spectrum_measure_notif; | ||
1697 | priv->rx_handlers[PM_SLEEP_NOTIFICATION] = iwl3945_rx_pm_sleep_notif; | ||
1698 | priv->rx_handlers[PM_DEBUG_STATISTIC_NOTIFIC] = | 1439 | priv->rx_handlers[PM_DEBUG_STATISTIC_NOTIFIC] = |
1699 | iwl3945_rx_pm_debug_statistics_notif; | 1440 | iwl_rx_pm_debug_statistics_notif; |
1700 | priv->rx_handlers[BEACON_NOTIFICATION] = iwl3945_rx_beacon_notif; | 1441 | priv->rx_handlers[BEACON_NOTIFICATION] = iwl3945_rx_beacon_notif; |
1701 | 1442 | ||
1702 | /* | 1443 | /* |
@@ -1707,12 +1448,8 @@ static void iwl3945_setup_rx_handlers(struct iwl_priv *priv) | |||
1707 | priv->rx_handlers[REPLY_STATISTICS_CMD] = iwl3945_hw_rx_statistics; | 1448 | priv->rx_handlers[REPLY_STATISTICS_CMD] = iwl3945_hw_rx_statistics; |
1708 | priv->rx_handlers[STATISTICS_NOTIFICATION] = iwl3945_hw_rx_statistics; | 1449 | priv->rx_handlers[STATISTICS_NOTIFICATION] = iwl3945_hw_rx_statistics; |
1709 | 1450 | ||
1710 | priv->rx_handlers[REPLY_SCAN_CMD] = iwl3945_rx_reply_scan; | 1451 | iwl_setup_spectrum_handlers(priv); |
1711 | priv->rx_handlers[SCAN_START_NOTIFICATION] = iwl3945_rx_scan_start_notif; | 1452 | iwl_setup_rx_scan_handlers(priv); |
1712 | priv->rx_handlers[SCAN_RESULTS_NOTIFICATION] = | ||
1713 | iwl3945_rx_scan_results_notif; | ||
1714 | priv->rx_handlers[SCAN_COMPLETE_NOTIFICATION] = | ||
1715 | iwl3945_rx_scan_complete_notif; | ||
1716 | priv->rx_handlers[CARD_STATE_NOTIFICATION] = iwl3945_rx_card_state_notif; | 1453 | priv->rx_handlers[CARD_STATE_NOTIFICATION] = iwl3945_rx_card_state_notif; |
1717 | 1454 | ||
1718 | /* Set up hardware specific Rx handlers */ | 1455 | /* Set up hardware specific Rx handlers */ |
@@ -2195,14 +1932,6 @@ static void iwl3945_rx_handle(struct iwl_priv *priv) | |||
2195 | iwl3945_rx_queue_restock(priv); | 1932 | iwl3945_rx_queue_restock(priv); |
2196 | } | 1933 | } |
2197 | 1934 | ||
2198 | static void iwl3945_enable_interrupts(struct iwl_priv *priv) | ||
2199 | { | ||
2200 | IWL_DEBUG_ISR(priv, "Enabling interrupts\n"); | ||
2201 | set_bit(STATUS_INT_ENABLED, &priv->status); | ||
2202 | iwl_write32(priv, CSR_INT_MASK, CSR_INI_SET_MASK); | ||
2203 | } | ||
2204 | |||
2205 | |||
2206 | /* call this function to flush any scheduled tasklet */ | 1935 | /* call this function to flush any scheduled tasklet */ |
2207 | static inline void iwl_synchronize_irq(struct iwl_priv *priv) | 1936 | static inline void iwl_synchronize_irq(struct iwl_priv *priv) |
2208 | { | 1937 | { |
@@ -2211,21 +1940,6 @@ static inline void iwl_synchronize_irq(struct iwl_priv *priv) | |||
2211 | tasklet_kill(&priv->irq_tasklet); | 1940 | tasklet_kill(&priv->irq_tasklet); |
2212 | } | 1941 | } |
2213 | 1942 | ||
2214 | |||
2215 | static inline void iwl3945_disable_interrupts(struct iwl_priv *priv) | ||
2216 | { | ||
2217 | clear_bit(STATUS_INT_ENABLED, &priv->status); | ||
2218 | |||
2219 | /* disable interrupts from uCode/NIC to host */ | ||
2220 | iwl_write32(priv, CSR_INT_MASK, 0x00000000); | ||
2221 | |||
2222 | /* acknowledge/clear/reset any interrupts still pending | ||
2223 | * from uCode or flow handler (Rx/Tx DMA) */ | ||
2224 | iwl_write32(priv, CSR_INT, 0xffffffff); | ||
2225 | iwl_write32(priv, CSR_FH_INT_STATUS, 0xffffffff); | ||
2226 | IWL_DEBUG_ISR(priv, "Disabled interrupts\n"); | ||
2227 | } | ||
2228 | |||
2229 | static const char *desc_lookup(int i) | 1943 | static const char *desc_lookup(int i) |
2230 | { | 1944 | { |
2231 | switch (i) { | 1945 | switch (i) { |
@@ -2467,7 +2181,7 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv) | |||
2467 | IWL_ERR(priv, "Microcode HW error detected. Restarting.\n"); | 2181 | IWL_ERR(priv, "Microcode HW error detected. Restarting.\n"); |
2468 | 2182 | ||
2469 | /* Tell the device to stop sending interrupts */ | 2183 | /* Tell the device to stop sending interrupts */ |
2470 | iwl3945_disable_interrupts(priv); | 2184 | iwl_disable_interrupts(priv); |
2471 | 2185 | ||
2472 | iwl_irq_handle_error(priv); | 2186 | iwl_irq_handle_error(priv); |
2473 | 2187 | ||
@@ -2547,7 +2261,7 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv) | |||
2547 | /* Re-enable all interrupts */ | 2261 | /* Re-enable all interrupts */ |
2548 | /* only Re-enable if disabled by irq */ | 2262 | /* only Re-enable if disabled by irq */ |
2549 | if (test_bit(STATUS_INT_ENABLED, &priv->status)) | 2263 | if (test_bit(STATUS_INT_ENABLED, &priv->status)) |
2550 | iwl3945_enable_interrupts(priv); | 2264 | iwl_enable_interrupts(priv); |
2551 | 2265 | ||
2552 | #ifdef CONFIG_IWLWIFI_DEBUG | 2266 | #ifdef CONFIG_IWLWIFI_DEBUG |
2553 | if (priv->debug_level & (IWL_DL_ISR)) { | 2267 | if (priv->debug_level & (IWL_DL_ISR)) { |
@@ -2561,63 +2275,6 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv) | |||
2561 | spin_unlock_irqrestore(&priv->lock, flags); | 2275 | spin_unlock_irqrestore(&priv->lock, flags); |
2562 | } | 2276 | } |
2563 | 2277 | ||
2564 | static irqreturn_t iwl3945_isr(int irq, void *data) | ||
2565 | { | ||
2566 | struct iwl_priv *priv = data; | ||
2567 | u32 inta, inta_mask; | ||
2568 | u32 inta_fh; | ||
2569 | if (!priv) | ||
2570 | return IRQ_NONE; | ||
2571 | |||
2572 | spin_lock(&priv->lock); | ||
2573 | |||
2574 | /* Disable (but don't clear!) interrupts here to avoid | ||
2575 | * back-to-back ISRs and sporadic interrupts from our NIC. | ||
2576 | * If we have something to service, the tasklet will re-enable ints. | ||
2577 | * If we *don't* have something, we'll re-enable before leaving here. */ | ||
2578 | inta_mask = iwl_read32(priv, CSR_INT_MASK); /* just for debug */ | ||
2579 | iwl_write32(priv, CSR_INT_MASK, 0x00000000); | ||
2580 | |||
2581 | /* Discover which interrupts are active/pending */ | ||
2582 | inta = iwl_read32(priv, CSR_INT); | ||
2583 | inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS); | ||
2584 | |||
2585 | /* Ignore interrupt if there's nothing in NIC to service. | ||
2586 | * This may be due to IRQ shared with another device, | ||
2587 | * or due to sporadic interrupts thrown from our NIC. */ | ||
2588 | if (!inta && !inta_fh) { | ||
2589 | IWL_DEBUG_ISR(priv, "Ignore interrupt, inta == 0, inta_fh == 0\n"); | ||
2590 | goto none; | ||
2591 | } | ||
2592 | |||
2593 | if ((inta == 0xFFFFFFFF) || ((inta & 0xFFFFFFF0) == 0xa5a5a5a0)) { | ||
2594 | /* Hardware disappeared */ | ||
2595 | IWL_WARN(priv, "HARDWARE GONE?? INTA == 0x%08x\n", inta); | ||
2596 | goto unplugged; | ||
2597 | } | ||
2598 | |||
2599 | IWL_DEBUG_ISR(priv, "ISR inta 0x%08x, enabled 0x%08x, fh 0x%08x\n", | ||
2600 | inta, inta_mask, inta_fh); | ||
2601 | |||
2602 | inta &= ~CSR_INT_BIT_SCD; | ||
2603 | |||
2604 | /* iwl3945_irq_tasklet() will service interrupts and re-enable them */ | ||
2605 | if (likely(inta || inta_fh)) | ||
2606 | tasklet_schedule(&priv->irq_tasklet); | ||
2607 | unplugged: | ||
2608 | spin_unlock(&priv->lock); | ||
2609 | |||
2610 | return IRQ_HANDLED; | ||
2611 | |||
2612 | none: | ||
2613 | /* re-enable interrupts here since we don't have anything to service. */ | ||
2614 | /* only Re-enable if disabled by irq */ | ||
2615 | if (test_bit(STATUS_INT_ENABLED, &priv->status)) | ||
2616 | iwl3945_enable_interrupts(priv); | ||
2617 | spin_unlock(&priv->lock); | ||
2618 | return IRQ_NONE; | ||
2619 | } | ||
2620 | |||
2621 | static int iwl3945_get_channels_for_scan(struct iwl_priv *priv, | 2278 | static int iwl3945_get_channels_for_scan(struct iwl_priv *priv, |
2622 | enum ieee80211_band band, | 2279 | enum ieee80211_band band, |
2623 | u8 is_active, u8 n_probes, | 2280 | u8 is_active, u8 n_probes, |
@@ -3387,7 +3044,7 @@ static void __iwl3945_down(struct iwl_priv *priv) | |||
3387 | 3044 | ||
3388 | /* tell the device to stop sending interrupts */ | 3045 | /* tell the device to stop sending interrupts */ |
3389 | spin_lock_irqsave(&priv->lock, flags); | 3046 | spin_lock_irqsave(&priv->lock, flags); |
3390 | iwl3945_disable_interrupts(priv); | 3047 | iwl_disable_interrupts(priv); |
3391 | spin_unlock_irqrestore(&priv->lock, flags); | 3048 | spin_unlock_irqrestore(&priv->lock, flags); |
3392 | iwl_synchronize_irq(priv); | 3049 | iwl_synchronize_irq(priv); |
3393 | 3050 | ||
@@ -3517,7 +3174,7 @@ static int __iwl3945_up(struct iwl_priv *priv) | |||
3517 | 3174 | ||
3518 | /* clear (again), then enable host interrupts */ | 3175 | /* clear (again), then enable host interrupts */ |
3519 | iwl_write32(priv, CSR_INT, 0xFFFFFFFF); | 3176 | iwl_write32(priv, CSR_INT, 0xFFFFFFFF); |
3520 | iwl3945_enable_interrupts(priv); | 3177 | iwl_enable_interrupts(priv); |
3521 | 3178 | ||
3522 | /* really make sure rfkill handshake bits are cleared */ | 3179 | /* really make sure rfkill handshake bits are cleared */ |
3523 | iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); | 3180 | iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); |
@@ -4172,9 +3829,13 @@ static int iwl3945_mac_config(struct ieee80211_hw *hw, u32 changed) | |||
4172 | } | 3829 | } |
4173 | #endif | 3830 | #endif |
4174 | 3831 | ||
4175 | iwl3945_radio_kill_sw(priv, !conf->radio_enabled); | 3832 | if (conf->radio_enabled && iwl_radio_kill_sw_enable_radio(priv)) { |
3833 | IWL_DEBUG_MAC80211(priv, "leave - RF-KILL - waiting for uCode\n"); | ||
3834 | goto out; | ||
3835 | } | ||
4176 | 3836 | ||
4177 | if (!conf->radio_enabled) { | 3837 | if (!conf->radio_enabled) { |
3838 | iwl_radio_kill_sw_disable_radio(priv); | ||
4178 | IWL_DEBUG_MAC80211(priv, "leave - radio disabled\n"); | 3839 | IWL_DEBUG_MAC80211(priv, "leave - radio disabled\n"); |
4179 | goto out; | 3840 | goto out; |
4180 | } | 3841 | } |
@@ -4442,66 +4103,6 @@ static void iwl3945_bss_info_changed(struct ieee80211_hw *hw, | |||
4442 | 4103 | ||
4443 | } | 4104 | } |
4444 | 4105 | ||
4445 | static int iwl3945_mac_hw_scan(struct ieee80211_hw *hw, | ||
4446 | struct cfg80211_scan_request *req) | ||
4447 | { | ||
4448 | int rc = 0; | ||
4449 | unsigned long flags; | ||
4450 | struct iwl_priv *priv = hw->priv; | ||
4451 | size_t len = 0; | ||
4452 | u8 *ssid = NULL; | ||
4453 | DECLARE_SSID_BUF(ssid_buf); | ||
4454 | |||
4455 | IWL_DEBUG_MAC80211(priv, "enter\n"); | ||
4456 | |||
4457 | if (req->n_ssids) { | ||
4458 | ssid = req->ssids[0].ssid; | ||
4459 | len = req->ssids[0].ssid_len; | ||
4460 | } | ||
4461 | |||
4462 | mutex_lock(&priv->mutex); | ||
4463 | spin_lock_irqsave(&priv->lock, flags); | ||
4464 | |||
4465 | if (!iwl_is_ready_rf(priv)) { | ||
4466 | rc = -EIO; | ||
4467 | IWL_DEBUG_MAC80211(priv, "leave - not ready or exit pending\n"); | ||
4468 | goto out_unlock; | ||
4469 | } | ||
4470 | |||
4471 | /* we don't schedule scan within next_scan_jiffies period */ | ||
4472 | if (priv->next_scan_jiffies && | ||
4473 | time_after(priv->next_scan_jiffies, jiffies)) { | ||
4474 | rc = -EAGAIN; | ||
4475 | goto out_unlock; | ||
4476 | } | ||
4477 | /* if we just finished scan ask for delay for a broadcast scan */ | ||
4478 | if ((len == 0) && priv->last_scan_jiffies && | ||
4479 | time_after(priv->last_scan_jiffies + IWL_DELAY_NEXT_SCAN, | ||
4480 | jiffies)) { | ||
4481 | rc = -EAGAIN; | ||
4482 | goto out_unlock; | ||
4483 | } | ||
4484 | if (len) { | ||
4485 | IWL_DEBUG_SCAN(priv, "direct scan for %s [%zd]\n ", | ||
4486 | print_ssid(ssid_buf, ssid, len), len); | ||
4487 | |||
4488 | priv->one_direct_scan = 1; | ||
4489 | priv->direct_ssid_len = len; | ||
4490 | memcpy(priv->direct_ssid, ssid, len); | ||
4491 | } else | ||
4492 | priv->one_direct_scan = 0; | ||
4493 | |||
4494 | rc = iwl3945_scan_initiate(priv); | ||
4495 | |||
4496 | IWL_DEBUG_MAC80211(priv, "leave\n"); | ||
4497 | |||
4498 | out_unlock: | ||
4499 | spin_unlock_irqrestore(&priv->lock, flags); | ||
4500 | mutex_unlock(&priv->mutex); | ||
4501 | |||
4502 | return rc; | ||
4503 | } | ||
4504 | |||
4505 | static int iwl3945_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, | 4106 | static int iwl3945_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, |
4506 | struct ieee80211_vif *vif, | 4107 | struct ieee80211_vif *vif, |
4507 | struct ieee80211_sta *sta, | 4108 | struct ieee80211_sta *sta, |
@@ -5201,7 +4802,7 @@ static DEVICE_ATTR(dump_events, S_IWUSR, NULL, dump_event_log); | |||
5201 | 4802 | ||
5202 | static void iwl3945_setup_deferred_work(struct iwl_priv *priv) | 4803 | static void iwl3945_setup_deferred_work(struct iwl_priv *priv) |
5203 | { | 4804 | { |
5204 | priv->workqueue = create_workqueue(DRV_NAME); | 4805 | priv->workqueue = create_singlethread_workqueue(DRV_NAME); |
5205 | 4806 | ||
5206 | init_waitqueue_head(&priv->wait_command_queue); | 4807 | init_waitqueue_head(&priv->wait_command_queue); |
5207 | 4808 | ||
@@ -5275,7 +4876,7 @@ static struct ieee80211_ops iwl3945_hw_ops = { | |||
5275 | .conf_tx = iwl3945_mac_conf_tx, | 4876 | .conf_tx = iwl3945_mac_conf_tx, |
5276 | .reset_tsf = iwl3945_mac_reset_tsf, | 4877 | .reset_tsf = iwl3945_mac_reset_tsf, |
5277 | .bss_info_changed = iwl3945_bss_info_changed, | 4878 | .bss_info_changed = iwl3945_bss_info_changed, |
5278 | .hw_scan = iwl3945_mac_hw_scan | 4879 | .hw_scan = iwl_mac_hw_scan |
5279 | }; | 4880 | }; |
5280 | 4881 | ||
5281 | static int iwl3945_init_drv(struct iwl_priv *priv) | 4882 | static int iwl3945_init_drv(struct iwl_priv *priv) |
@@ -5526,12 +5127,12 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e | |||
5526 | * ********************/ | 5127 | * ********************/ |
5527 | 5128 | ||
5528 | spin_lock_irqsave(&priv->lock, flags); | 5129 | spin_lock_irqsave(&priv->lock, flags); |
5529 | iwl3945_disable_interrupts(priv); | 5130 | iwl_disable_interrupts(priv); |
5530 | spin_unlock_irqrestore(&priv->lock, flags); | 5131 | spin_unlock_irqrestore(&priv->lock, flags); |
5531 | 5132 | ||
5532 | pci_enable_msi(priv->pci_dev); | 5133 | pci_enable_msi(priv->pci_dev); |
5533 | 5134 | ||
5534 | err = request_irq(priv->pci_dev->irq, iwl3945_isr, IRQF_SHARED, | 5135 | err = request_irq(priv->pci_dev->irq, iwl_isr, IRQF_SHARED, |
5535 | DRV_NAME, priv); | 5136 | DRV_NAME, priv); |
5536 | if (err) { | 5137 | if (err) { |
5537 | IWL_ERR(priv, "Error allocating IRQ %d\n", priv->pci_dev->irq); | 5138 | IWL_ERR(priv, "Error allocating IRQ %d\n", priv->pci_dev->irq); |
@@ -5621,7 +5222,7 @@ static void __devexit iwl3945_pci_remove(struct pci_dev *pdev) | |||
5621 | * tasklet for the driver | 5222 | * tasklet for the driver |
5622 | */ | 5223 | */ |
5623 | spin_lock_irqsave(&priv->lock, flags); | 5224 | spin_lock_irqsave(&priv->lock, flags); |
5624 | iwl3945_disable_interrupts(priv); | 5225 | iwl_disable_interrupts(priv); |
5625 | spin_unlock_irqrestore(&priv->lock, flags); | 5226 | spin_unlock_irqrestore(&priv->lock, flags); |
5626 | 5227 | ||
5627 | iwl_synchronize_irq(priv); | 5228 | iwl_synchronize_irq(priv); |
diff --git a/drivers/net/wireless/libertas/defs.h b/drivers/net/wireless/libertas/defs.h index 6388b05df4fc..e8dfde39abfc 100644 --- a/drivers/net/wireless/libertas/defs.h +++ b/drivers/net/wireless/libertas/defs.h | |||
@@ -265,6 +265,7 @@ static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, in | |||
265 | 265 | ||
266 | #define CMD_F_HOSTCMD (1 << 0) | 266 | #define CMD_F_HOSTCMD (1 << 0) |
267 | #define FW_CAPINFO_WPA (1 << 0) | 267 | #define FW_CAPINFO_WPA (1 << 0) |
268 | #define FW_CAPINFO_PS (1 << 1) | ||
268 | #define FW_CAPINFO_FIRMWARE_UPGRADE (1 << 13) | 269 | #define FW_CAPINFO_FIRMWARE_UPGRADE (1 << 13) |
269 | #define FW_CAPINFO_BOOT2_UPGRADE (1<<14) | 270 | #define FW_CAPINFO_BOOT2_UPGRADE (1<<14) |
270 | #define FW_CAPINFO_PERSISTENT_CONFIG (1<<15) | 271 | #define FW_CAPINFO_PERSISTENT_CONFIG (1<<15) |
diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c index 4519d7314f47..76f4c653d641 100644 --- a/drivers/net/wireless/libertas/if_sdio.c +++ b/drivers/net/wireless/libertas/if_sdio.c | |||
@@ -95,6 +95,8 @@ struct if_sdio_card { | |||
95 | 95 | ||
96 | spinlock_t lock; | 96 | spinlock_t lock; |
97 | struct if_sdio_packet *packets; | 97 | struct if_sdio_packet *packets; |
98 | |||
99 | struct workqueue_struct *workqueue; | ||
98 | struct work_struct packet_worker; | 100 | struct work_struct packet_worker; |
99 | }; | 101 | }; |
100 | 102 | ||
@@ -209,6 +211,9 @@ static int if_sdio_handle_event(struct if_sdio_card *card, | |||
209 | event = sdio_readb(card->func, IF_SDIO_EVENT, &ret); | 211 | event = sdio_readb(card->func, IF_SDIO_EVENT, &ret); |
210 | if (ret) | 212 | if (ret) |
211 | goto out; | 213 | goto out; |
214 | |||
215 | /* right shift 3 bits to get the event id */ | ||
216 | event >>= 3; | ||
212 | } else { | 217 | } else { |
213 | if (size < 4) { | 218 | if (size < 4) { |
214 | lbs_deb_sdio("event packet too small (%d bytes)\n", | 219 | lbs_deb_sdio("event packet too small (%d bytes)\n", |
@@ -743,7 +748,7 @@ static int if_sdio_host_to_card(struct lbs_private *priv, | |||
743 | 748 | ||
744 | spin_unlock_irqrestore(&card->lock, flags); | 749 | spin_unlock_irqrestore(&card->lock, flags); |
745 | 750 | ||
746 | schedule_work(&card->packet_worker); | 751 | queue_work(card->workqueue, &card->packet_worker); |
747 | 752 | ||
748 | ret = 0; | 753 | ret = 0; |
749 | 754 | ||
@@ -833,6 +838,7 @@ static int if_sdio_probe(struct sdio_func *func, | |||
833 | card->func = func; | 838 | card->func = func; |
834 | card->model = model; | 839 | card->model = model; |
835 | spin_lock_init(&card->lock); | 840 | spin_lock_init(&card->lock); |
841 | card->workqueue = create_workqueue("libertas_sdio"); | ||
836 | INIT_WORK(&card->packet_worker, if_sdio_host_to_card_worker); | 842 | INIT_WORK(&card->packet_worker, if_sdio_host_to_card_worker); |
837 | 843 | ||
838 | for (i = 0;i < ARRAY_SIZE(if_sdio_models);i++) { | 844 | for (i = 0;i < ARRAY_SIZE(if_sdio_models);i++) { |
@@ -921,15 +927,17 @@ static int if_sdio_probe(struct sdio_func *func, | |||
921 | if (ret) | 927 | if (ret) |
922 | goto err_activate_card; | 928 | goto err_activate_card; |
923 | 929 | ||
930 | if (priv->fwcapinfo & FW_CAPINFO_PS) | ||
931 | priv->ps_supported = 1; | ||
932 | |||
924 | out: | 933 | out: |
925 | lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret); | 934 | lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret); |
926 | 935 | ||
927 | return ret; | 936 | return ret; |
928 | 937 | ||
929 | err_activate_card: | 938 | err_activate_card: |
930 | flush_scheduled_work(); | 939 | flush_workqueue(card->workqueue); |
931 | free_netdev(priv->dev); | 940 | lbs_remove_card(priv); |
932 | kfree(priv); | ||
933 | reclaim: | 941 | reclaim: |
934 | sdio_claim_host(func); | 942 | sdio_claim_host(func); |
935 | release_int: | 943 | release_int: |
@@ -939,6 +947,7 @@ disable: | |||
939 | release: | 947 | release: |
940 | sdio_release_host(func); | 948 | sdio_release_host(func); |
941 | free: | 949 | free: |
950 | destroy_workqueue(card->workqueue); | ||
942 | while (card->packets) { | 951 | while (card->packets) { |
943 | packet = card->packets; | 952 | packet = card->packets; |
944 | card->packets = card->packets->next; | 953 | card->packets = card->packets->next; |
@@ -965,7 +974,8 @@ static void if_sdio_remove(struct sdio_func *func) | |||
965 | lbs_stop_card(card->priv); | 974 | lbs_stop_card(card->priv); |
966 | lbs_remove_card(card->priv); | 975 | lbs_remove_card(card->priv); |
967 | 976 | ||
968 | flush_scheduled_work(); | 977 | flush_workqueue(card->workqueue); |
978 | destroy_workqueue(card->workqueue); | ||
969 | 979 | ||
970 | sdio_claim_host(func); | 980 | sdio_claim_host(func); |
971 | sdio_release_irq(func); | 981 | sdio_release_irq(func); |
diff --git a/drivers/net/wireless/orinoco/fw.c b/drivers/net/wireless/orinoco/fw.c index 7d2292d6ce09..e7abb45d6753 100644 --- a/drivers/net/wireless/orinoco/fw.c +++ b/drivers/net/wireless/orinoco/fw.c | |||
@@ -43,6 +43,33 @@ struct orinoco_fw_header { | |||
43 | char signature[0]; /* FW signature length headersize-20 */ | 43 | char signature[0]; /* FW signature length headersize-20 */ |
44 | } __attribute__ ((packed)); | 44 | } __attribute__ ((packed)); |
45 | 45 | ||
46 | /* Check the range of various header entries. Return a pointer to a | ||
47 | * description of the problem, or NULL if everything checks out. */ | ||
48 | static const char *validate_fw(const struct orinoco_fw_header *hdr, size_t len) | ||
49 | { | ||
50 | u16 hdrsize; | ||
51 | |||
52 | if (len < sizeof(*hdr)) | ||
53 | return "image too small"; | ||
54 | if (memcmp(hdr->hdr_vers, "HFW", 3) != 0) | ||
55 | return "format not recognised"; | ||
56 | |||
57 | hdrsize = le16_to_cpu(hdr->headersize); | ||
58 | if (hdrsize > len) | ||
59 | return "bad headersize"; | ||
60 | if ((hdrsize + le32_to_cpu(hdr->block_offset)) > len) | ||
61 | return "bad block offset"; | ||
62 | if ((hdrsize + le32_to_cpu(hdr->pdr_offset)) > len) | ||
63 | return "bad PDR offset"; | ||
64 | if ((hdrsize + le32_to_cpu(hdr->pri_offset)) > len) | ||
65 | return "bad PRI offset"; | ||
66 | if ((hdrsize + le32_to_cpu(hdr->compat_offset)) > len) | ||
67 | return "bad compat offset"; | ||
68 | |||
69 | /* TODO: consider adding a checksum or CRC to the firmware format */ | ||
70 | return NULL; | ||
71 | } | ||
72 | |||
46 | /* Download either STA or AP firmware into the card. */ | 73 | /* Download either STA or AP firmware into the card. */ |
47 | static int | 74 | static int |
48 | orinoco_dl_firmware(struct orinoco_private *priv, | 75 | orinoco_dl_firmware(struct orinoco_private *priv, |
@@ -56,8 +83,9 @@ orinoco_dl_firmware(struct orinoco_private *priv, | |||
56 | const struct firmware *fw_entry; | 83 | const struct firmware *fw_entry; |
57 | const struct orinoco_fw_header *hdr; | 84 | const struct orinoco_fw_header *hdr; |
58 | const unsigned char *first_block; | 85 | const unsigned char *first_block; |
59 | const unsigned char *end; | 86 | const void *end; |
60 | const char *firmware; | 87 | const char *firmware; |
88 | const char *fw_err; | ||
61 | struct net_device *dev = priv->ndev; | 89 | struct net_device *dev = priv->ndev; |
62 | int err = 0; | 90 | int err = 0; |
63 | 91 | ||
@@ -93,6 +121,15 @@ orinoco_dl_firmware(struct orinoco_private *priv, | |||
93 | 121 | ||
94 | hdr = (const struct orinoco_fw_header *) fw_entry->data; | 122 | hdr = (const struct orinoco_fw_header *) fw_entry->data; |
95 | 123 | ||
124 | fw_err = validate_fw(hdr, fw_entry->size); | ||
125 | if (fw_err) { | ||
126 | printk(KERN_WARNING "%s: Invalid firmware image detected (%s). " | ||
127 | "Aborting download\n", | ||
128 | dev->name, fw_err); | ||
129 | err = -EINVAL; | ||
130 | goto abort; | ||
131 | } | ||
132 | |||
96 | /* Enable aux port to allow programming */ | 133 | /* Enable aux port to allow programming */ |
97 | err = hermesi_program_init(hw, le32_to_cpu(hdr->entry_point)); | 134 | err = hermesi_program_init(hw, le32_to_cpu(hdr->entry_point)); |
98 | printk(KERN_DEBUG "%s: Program init returned %d\n", dev->name, err); | 135 | printk(KERN_DEBUG "%s: Program init returned %d\n", dev->name, err); |
@@ -115,7 +152,8 @@ orinoco_dl_firmware(struct orinoco_private *priv, | |||
115 | le16_to_cpu(hdr->headersize) + | 152 | le16_to_cpu(hdr->headersize) + |
116 | le32_to_cpu(hdr->pdr_offset)); | 153 | le32_to_cpu(hdr->pdr_offset)); |
117 | 154 | ||
118 | err = hermes_apply_pda_with_defaults(hw, first_block, pda); | 155 | err = hermes_apply_pda_with_defaults(hw, first_block, end, pda, |
156 | &pda[fw->pda_size / sizeof(*pda)]); | ||
119 | printk(KERN_DEBUG "%s: Apply PDA returned %d\n", dev->name, err); | 157 | printk(KERN_DEBUG "%s: Apply PDA returned %d\n", dev->name, err); |
120 | if (err) | 158 | if (err) |
121 | goto abort; | 159 | goto abort; |
@@ -147,7 +185,7 @@ free: | |||
147 | */ | 185 | */ |
148 | static int | 186 | static int |
149 | symbol_dl_image(struct orinoco_private *priv, const struct fw_info *fw, | 187 | symbol_dl_image(struct orinoco_private *priv, const struct fw_info *fw, |
150 | const unsigned char *image, const unsigned char *end, | 188 | const unsigned char *image, const void *end, |
151 | int secondary) | 189 | int secondary) |
152 | { | 190 | { |
153 | hermes_t *hw = &priv->hw; | 191 | hermes_t *hw = &priv->hw; |
@@ -188,9 +226,10 @@ symbol_dl_image(struct orinoco_private *priv, const struct fw_info *fw, | |||
188 | 226 | ||
189 | /* Write the PDA to the adapter */ | 227 | /* Write the PDA to the adapter */ |
190 | if (secondary) { | 228 | if (secondary) { |
191 | size_t len = hermes_blocks_length(first_block); | 229 | size_t len = hermes_blocks_length(first_block, end); |
192 | ptr = first_block + len; | 230 | ptr = first_block + len; |
193 | ret = hermes_apply_pda(hw, ptr, pda); | 231 | ret = hermes_apply_pda(hw, ptr, end, pda, |
232 | &pda[fw->pda_size / sizeof(*pda)]); | ||
194 | kfree(pda); | 233 | kfree(pda); |
195 | if (ret) | 234 | if (ret) |
196 | return ret; | 235 | return ret; |
diff --git a/drivers/net/wireless/orinoco/hermes_dld.c b/drivers/net/wireless/orinoco/hermes_dld.c index 5260ceb5cfec..a9ba195cdada 100644 --- a/drivers/net/wireless/orinoco/hermes_dld.c +++ b/drivers/net/wireless/orinoco/hermes_dld.c | |||
@@ -71,18 +71,6 @@ | |||
71 | #define BLOCK_END 0xFFFFFFFF /* Last image block */ | 71 | #define BLOCK_END 0xFFFFFFFF /* Last image block */ |
72 | #define TEXT_END 0x1A /* End of text header */ | 72 | #define TEXT_END 0x1A /* End of text header */ |
73 | 73 | ||
74 | /* | ||
75 | * PDA == Production Data Area | ||
76 | * | ||
77 | * In principle, the max. size of the PDA is is 4096 words. Currently, | ||
78 | * however, only about 500 bytes of this area are used. | ||
79 | * | ||
80 | * Some USB implementations can't handle sizes in excess of 1016. Note | ||
81 | * that PDA is not actually used in those USB environments, but may be | ||
82 | * retrieved by common code. | ||
83 | */ | ||
84 | #define MAX_PDA_SIZE 1000 | ||
85 | |||
86 | /* Limit the amout we try to download in a single shot. | 74 | /* Limit the amout we try to download in a single shot. |
87 | * Size is in bytes. | 75 | * Size is in bytes. |
88 | */ | 76 | */ |
@@ -218,13 +206,14 @@ hermes_aux_control(hermes_t *hw, int enabled) | |||
218 | * Scan PDR for the record with the specified RECORD_ID. | 206 | * Scan PDR for the record with the specified RECORD_ID. |
219 | * If it's not found, return NULL. | 207 | * If it's not found, return NULL. |
220 | */ | 208 | */ |
221 | static struct pdr * | 209 | static const struct pdr * |
222 | hermes_find_pdr(struct pdr *first_pdr, u32 record_id) | 210 | hermes_find_pdr(const struct pdr *first_pdr, u32 record_id, const void *end) |
223 | { | 211 | { |
224 | struct pdr *pdr = first_pdr; | 212 | const struct pdr *pdr = first_pdr; |
225 | void *end = (void *)first_pdr + MAX_PDA_SIZE; | ||
226 | 213 | ||
227 | while (((void *)pdr < end) && | 214 | end -= sizeof(struct pdr); |
215 | |||
216 | while (((void *) pdr <= end) && | ||
228 | (pdr_id(pdr) != PDI_END)) { | 217 | (pdr_id(pdr) != PDI_END)) { |
229 | /* | 218 | /* |
230 | * PDR area is currently not terminated by PDI_END. | 219 | * PDR area is currently not terminated by PDI_END. |
@@ -244,12 +233,15 @@ hermes_find_pdr(struct pdr *first_pdr, u32 record_id) | |||
244 | } | 233 | } |
245 | 234 | ||
246 | /* Scan production data items for a particular entry */ | 235 | /* Scan production data items for a particular entry */ |
247 | static struct pdi * | 236 | static const struct pdi * |
248 | hermes_find_pdi(struct pdi *first_pdi, u32 record_id) | 237 | hermes_find_pdi(const struct pdi *first_pdi, u32 record_id, const void *end) |
249 | { | 238 | { |
250 | struct pdi *pdi = first_pdi; | 239 | const struct pdi *pdi = first_pdi; |
240 | |||
241 | end -= sizeof(struct pdi); | ||
251 | 242 | ||
252 | while (pdi_id(pdi) != PDI_END) { | 243 | while (((void *) pdi <= end) && |
244 | (pdi_id(pdi) != PDI_END)) { | ||
253 | 245 | ||
254 | /* If the record ID matches, we are done */ | 246 | /* If the record ID matches, we are done */ |
255 | if (pdi_id(pdi) == record_id) | 247 | if (pdi_id(pdi) == record_id) |
@@ -262,12 +254,13 @@ hermes_find_pdi(struct pdi *first_pdi, u32 record_id) | |||
262 | 254 | ||
263 | /* Process one Plug Data Item - find corresponding PDR and plug it */ | 255 | /* Process one Plug Data Item - find corresponding PDR and plug it */ |
264 | static int | 256 | static int |
265 | hermes_plug_pdi(hermes_t *hw, struct pdr *first_pdr, const struct pdi *pdi) | 257 | hermes_plug_pdi(hermes_t *hw, const struct pdr *first_pdr, |
258 | const struct pdi *pdi, const void *pdr_end) | ||
266 | { | 259 | { |
267 | struct pdr *pdr; | 260 | const struct pdr *pdr; |
268 | 261 | ||
269 | /* Find the PDR corresponding to this PDI */ | 262 | /* Find the PDR corresponding to this PDI */ |
270 | pdr = hermes_find_pdr(first_pdr, pdi_id(pdi)); | 263 | pdr = hermes_find_pdr(first_pdr, pdi_id(pdi), pdr_end); |
271 | 264 | ||
272 | /* No match is found, safe to ignore */ | 265 | /* No match is found, safe to ignore */ |
273 | if (!pdr) | 266 | if (!pdr) |
@@ -345,18 +338,22 @@ int hermes_read_pda(hermes_t *hw, | |||
345 | */ | 338 | */ |
346 | int hermes_apply_pda(hermes_t *hw, | 339 | int hermes_apply_pda(hermes_t *hw, |
347 | const char *first_pdr, | 340 | const char *first_pdr, |
348 | const __le16 *pda) | 341 | const void *pdr_end, |
342 | const __le16 *pda, | ||
343 | const void *pda_end) | ||
349 | { | 344 | { |
350 | int ret; | 345 | int ret; |
351 | const struct pdi *pdi; | 346 | const struct pdi *pdi; |
352 | struct pdr *pdr; | 347 | const struct pdr *pdr; |
353 | 348 | ||
354 | pdr = (struct pdr *) first_pdr; | 349 | pdr = (const struct pdr *) first_pdr; |
350 | pda_end -= sizeof(struct pdi); | ||
355 | 351 | ||
356 | /* Go through every PDI and plug them into the adapter */ | 352 | /* Go through every PDI and plug them into the adapter */ |
357 | pdi = (const struct pdi *) (pda + 2); | 353 | pdi = (const struct pdi *) (pda + 2); |
358 | while (pdi_id(pdi) != PDI_END) { | 354 | while (((void *) pdi <= pda_end) && |
359 | ret = hermes_plug_pdi(hw, pdr, pdi); | 355 | (pdi_id(pdi) != PDI_END)) { |
356 | ret = hermes_plug_pdi(hw, pdr, pdi, pdr_end); | ||
360 | if (ret) | 357 | if (ret) |
361 | return ret; | 358 | return ret; |
362 | 359 | ||
@@ -370,15 +367,18 @@ int hermes_apply_pda(hermes_t *hw, | |||
370 | * including the header data. | 367 | * including the header data. |
371 | */ | 368 | */ |
372 | size_t | 369 | size_t |
373 | hermes_blocks_length(const char *first_block) | 370 | hermes_blocks_length(const char *first_block, const void *end) |
374 | { | 371 | { |
375 | const struct dblock *blk = (const struct dblock *) first_block; | 372 | const struct dblock *blk = (const struct dblock *) first_block; |
376 | int total_len = 0; | 373 | int total_len = 0; |
377 | int len; | 374 | int len; |
378 | 375 | ||
376 | end -= sizeof(*blk); | ||
377 | |||
379 | /* Skip all blocks to locate Plug Data References | 378 | /* Skip all blocks to locate Plug Data References |
380 | * (Spectrum CS) */ | 379 | * (Spectrum CS) */ |
381 | while (dblock_addr(blk) != BLOCK_END) { | 380 | while (((void *) blk <= end) && |
381 | (dblock_addr(blk) != BLOCK_END)) { | ||
382 | len = dblock_len(blk); | 382 | len = dblock_len(blk); |
383 | total_len += sizeof(*blk) + len; | 383 | total_len += sizeof(*blk) + len; |
384 | blk = (struct dblock *) &blk->data[len]; | 384 | blk = (struct dblock *) &blk->data[len]; |
@@ -476,7 +476,7 @@ int hermesi_program_end(hermes_t *hw) | |||
476 | } | 476 | } |
477 | 477 | ||
478 | /* Program the data blocks */ | 478 | /* Program the data blocks */ |
479 | int hermes_program(hermes_t *hw, const char *first_block, const char *end) | 479 | int hermes_program(hermes_t *hw, const char *first_block, const void *end) |
480 | { | 480 | { |
481 | const struct dblock *blk; | 481 | const struct dblock *blk; |
482 | u32 blkaddr; | 482 | u32 blkaddr; |
@@ -488,14 +488,14 @@ int hermes_program(hermes_t *hw, const char *first_block, const char *end) | |||
488 | 488 | ||
489 | blk = (const struct dblock *) first_block; | 489 | blk = (const struct dblock *) first_block; |
490 | 490 | ||
491 | if ((const char *) blk > (end - sizeof(*blk))) | 491 | if ((void *) blk > (end - sizeof(*blk))) |
492 | return -EIO; | 492 | return -EIO; |
493 | 493 | ||
494 | blkaddr = dblock_addr(blk); | 494 | blkaddr = dblock_addr(blk); |
495 | blklen = dblock_len(blk); | 495 | blklen = dblock_len(blk); |
496 | 496 | ||
497 | while ((blkaddr != BLOCK_END) && | 497 | while ((blkaddr != BLOCK_END) && |
498 | (((const char *) blk + blklen) <= end)) { | 498 | (((void *) blk + blklen) <= end)) { |
499 | printk(KERN_DEBUG PFX | 499 | printk(KERN_DEBUG PFX |
500 | "Programming block of length %d to address 0x%08x\n", | 500 | "Programming block of length %d to address 0x%08x\n", |
501 | blklen, blkaddr); | 501 | blklen, blkaddr); |
@@ -527,7 +527,7 @@ int hermes_program(hermes_t *hw, const char *first_block, const char *end) | |||
527 | #endif | 527 | #endif |
528 | blk = (const struct dblock *) &blk->data[blklen]; | 528 | blk = (const struct dblock *) &blk->data[blklen]; |
529 | 529 | ||
530 | if ((const char *) blk > (end - sizeof(*blk))) | 530 | if ((void *) blk > (end - sizeof(*blk))) |
531 | return -EIO; | 531 | return -EIO; |
532 | 532 | ||
533 | blkaddr = dblock_addr(blk); | 533 | blkaddr = dblock_addr(blk); |
@@ -545,9 +545,9 @@ static const struct { \ | |||
545 | __le16 id; \ | 545 | __le16 id; \ |
546 | u8 val[length]; \ | 546 | u8 val[length]; \ |
547 | } __attribute__ ((packed)) default_pdr_data_##pid = { \ | 547 | } __attribute__ ((packed)) default_pdr_data_##pid = { \ |
548 | cpu_to_le16((sizeof(default_pdr_data_##pid)/ \ | 548 | cpu_to_le16((sizeof(default_pdr_data_##pid)/ \ |
549 | sizeof(__le16)) - 1), \ | 549 | sizeof(__le16)) - 1), \ |
550 | cpu_to_le16(pid), \ | 550 | cpu_to_le16(pid), \ |
551 | data \ | 551 | data \ |
552 | } | 552 | } |
553 | 553 | ||
@@ -616,17 +616,20 @@ DEFINE_DEFAULT_PDR(0x0161, 256, | |||
616 | */ | 616 | */ |
617 | int hermes_apply_pda_with_defaults(hermes_t *hw, | 617 | int hermes_apply_pda_with_defaults(hermes_t *hw, |
618 | const char *first_pdr, | 618 | const char *first_pdr, |
619 | const __le16 *pda) | 619 | const void *pdr_end, |
620 | const __le16 *pda, | ||
621 | const void *pda_end) | ||
620 | { | 622 | { |
621 | const struct pdr *pdr = (const struct pdr *) first_pdr; | 623 | const struct pdr *pdr = (const struct pdr *) first_pdr; |
622 | struct pdi *first_pdi = (struct pdi *) &pda[2]; | 624 | const struct pdi *first_pdi = (const struct pdi *) &pda[2]; |
623 | struct pdi *pdi; | 625 | const struct pdi *pdi; |
624 | struct pdi *default_pdi = NULL; | 626 | const struct pdi *default_pdi = NULL; |
625 | struct pdi *outdoor_pdi; | 627 | const struct pdi *outdoor_pdi; |
626 | void *end = (void *)first_pdr + MAX_PDA_SIZE; | ||
627 | int record_id; | 628 | int record_id; |
628 | 629 | ||
629 | while (((void *)pdr < end) && | 630 | pdr_end -= sizeof(struct pdr); |
631 | |||
632 | while (((void *) pdr <= pdr_end) && | ||
630 | (pdr_id(pdr) != PDI_END)) { | 633 | (pdr_id(pdr) != PDI_END)) { |
631 | /* | 634 | /* |
632 | * For spectrum_cs firmwares, | 635 | * For spectrum_cs firmwares, |
@@ -638,7 +641,7 @@ int hermes_apply_pda_with_defaults(hermes_t *hw, | |||
638 | break; | 641 | break; |
639 | record_id = pdr_id(pdr); | 642 | record_id = pdr_id(pdr); |
640 | 643 | ||
641 | pdi = hermes_find_pdi(first_pdi, record_id); | 644 | pdi = hermes_find_pdi(first_pdi, record_id, pda_end); |
642 | if (pdi) | 645 | if (pdi) |
643 | printk(KERN_DEBUG PFX "Found record 0x%04x at %p\n", | 646 | printk(KERN_DEBUG PFX "Found record 0x%04x at %p\n", |
644 | record_id, pdi); | 647 | record_id, pdi); |
@@ -646,7 +649,8 @@ int hermes_apply_pda_with_defaults(hermes_t *hw, | |||
646 | switch (record_id) { | 649 | switch (record_id) { |
647 | case 0x110: /* Modem REFDAC values */ | 650 | case 0x110: /* Modem REFDAC values */ |
648 | case 0x120: /* Modem VGDAC values */ | 651 | case 0x120: /* Modem VGDAC values */ |
649 | outdoor_pdi = hermes_find_pdi(first_pdi, record_id + 1); | 652 | outdoor_pdi = hermes_find_pdi(first_pdi, record_id + 1, |
653 | pda_end); | ||
650 | default_pdi = NULL; | 654 | default_pdi = NULL; |
651 | if (outdoor_pdi) { | 655 | if (outdoor_pdi) { |
652 | pdi = outdoor_pdi; | 656 | pdi = outdoor_pdi; |
@@ -687,7 +691,8 @@ int hermes_apply_pda_with_defaults(hermes_t *hw, | |||
687 | 691 | ||
688 | if (pdi) { | 692 | if (pdi) { |
689 | /* Lengths of the data in PDI and PDR must match */ | 693 | /* Lengths of the data in PDI and PDR must match */ |
690 | if (pdi_len(pdi) == pdr_len(pdr)) { | 694 | if ((pdi_len(pdi) == pdr_len(pdr)) && |
695 | ((void *) pdi->data + pdi_len(pdi) < pda_end)) { | ||
691 | /* do the actual plugging */ | 696 | /* do the actual plugging */ |
692 | hermes_aux_setaddr(hw, pdr_addr(pdr)); | 697 | hermes_aux_setaddr(hw, pdr_addr(pdr)); |
693 | hermes_write_bytes(hw, HERMES_AUXDATA, | 698 | hermes_write_bytes(hw, HERMES_AUXDATA, |
diff --git a/drivers/net/wireless/orinoco/hermes_dld.h b/drivers/net/wireless/orinoco/hermes_dld.h index 6fcb26277999..583a5bcf9175 100644 --- a/drivers/net/wireless/orinoco/hermes_dld.h +++ b/drivers/net/wireless/orinoco/hermes_dld.h | |||
@@ -29,7 +29,7 @@ | |||
29 | 29 | ||
30 | int hermesi_program_init(hermes_t *hw, u32 offset); | 30 | int hermesi_program_init(hermes_t *hw, u32 offset); |
31 | int hermesi_program_end(hermes_t *hw); | 31 | int hermesi_program_end(hermes_t *hw); |
32 | int hermes_program(hermes_t *hw, const char *first_block, const char *end); | 32 | int hermes_program(hermes_t *hw, const char *first_block, const void *end); |
33 | 33 | ||
34 | int hermes_read_pda(hermes_t *hw, | 34 | int hermes_read_pda(hermes_t *hw, |
35 | __le16 *pda, | 35 | __le16 *pda, |
@@ -38,11 +38,15 @@ int hermes_read_pda(hermes_t *hw, | |||
38 | int use_eeprom); | 38 | int use_eeprom); |
39 | int hermes_apply_pda(hermes_t *hw, | 39 | int hermes_apply_pda(hermes_t *hw, |
40 | const char *first_pdr, | 40 | const char *first_pdr, |
41 | const __le16 *pda); | 41 | const void *pdr_end, |
42 | const __le16 *pda, | ||
43 | const void *pda_end); | ||
42 | int hermes_apply_pda_with_defaults(hermes_t *hw, | 44 | int hermes_apply_pda_with_defaults(hermes_t *hw, |
43 | const char *first_pdr, | 45 | const char *first_pdr, |
44 | const __le16 *pda); | 46 | const void *pdr_end, |
47 | const __le16 *pda, | ||
48 | const void *pda_end); | ||
45 | 49 | ||
46 | size_t hermes_blocks_length(const char *first_block); | 50 | size_t hermes_blocks_length(const char *first_block, const void *end); |
47 | 51 | ||
48 | #endif /* _HERMES_DLD_H */ | 52 | #endif /* _HERMES_DLD_H */ |
diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 45c2e7ad3acd..fcf43bcae979 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c | |||
@@ -2212,8 +2212,8 @@ static void p54_configure_filter(struct ieee80211_hw *dev, | |||
2212 | 2212 | ||
2213 | *total_flags &= FIF_PROMISC_IN_BSS | | 2213 | *total_flags &= FIF_PROMISC_IN_BSS | |
2214 | FIF_OTHER_BSS | | 2214 | FIF_OTHER_BSS | |
2215 | (*total_flags & FIF_PROMISC_IN_BSS) ? | 2215 | (*total_flags & FIF_PROMISC_IN_BSS ? |
2216 | FIF_FCSFAIL : 0; | 2216 | FIF_FCSFAIL : 0); |
2217 | 2217 | ||
2218 | priv->filter_flags = *total_flags; | 2218 | priv->filter_flags = *total_flags; |
2219 | 2219 | ||
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index b0848259b455..0f08773328c6 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c | |||
@@ -114,9 +114,6 @@ static void rt2400pci_rf_write(struct rt2x00_dev *rt2x00dev, | |||
114 | { | 114 | { |
115 | u32 reg; | 115 | u32 reg; |
116 | 116 | ||
117 | if (!word) | ||
118 | return; | ||
119 | |||
120 | mutex_lock(&rt2x00dev->csr_mutex); | 117 | mutex_lock(&rt2x00dev->csr_mutex); |
121 | 118 | ||
122 | /* | 119 | /* |
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.h b/drivers/net/wireless/rt2x00/rt2400pci.h index 72ac31c3cb75..ec3b004ddc3c 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.h +++ b/drivers/net/wireless/rt2x00/rt2400pci.h | |||
@@ -48,8 +48,8 @@ | |||
48 | #define EEPROM_SIZE 0x0100 | 48 | #define EEPROM_SIZE 0x0100 |
49 | #define BBP_BASE 0x0000 | 49 | #define BBP_BASE 0x0000 |
50 | #define BBP_SIZE 0x0020 | 50 | #define BBP_SIZE 0x0020 |
51 | #define RF_BASE 0x0000 | 51 | #define RF_BASE 0x0004 |
52 | #define RF_SIZE 0x0010 | 52 | #define RF_SIZE 0x000c |
53 | 53 | ||
54 | /* | 54 | /* |
55 | * Number of TX queues. | 55 | * Number of TX queues. |
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index eb82860c54f9..276a8232aaa0 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c | |||
@@ -114,9 +114,6 @@ static void rt2500pci_rf_write(struct rt2x00_dev *rt2x00dev, | |||
114 | { | 114 | { |
115 | u32 reg; | 115 | u32 reg; |
116 | 116 | ||
117 | if (!word) | ||
118 | return; | ||
119 | |||
120 | mutex_lock(&rt2x00dev->csr_mutex); | 117 | mutex_lock(&rt2x00dev->csr_mutex); |
121 | 118 | ||
122 | /* | 119 | /* |
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.h b/drivers/net/wireless/rt2x00/rt2500pci.h index 17a0c9c8c184..ce2f065c7486 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.h +++ b/drivers/net/wireless/rt2x00/rt2500pci.h | |||
@@ -59,8 +59,8 @@ | |||
59 | #define EEPROM_SIZE 0x0200 | 59 | #define EEPROM_SIZE 0x0200 |
60 | #define BBP_BASE 0x0000 | 60 | #define BBP_BASE 0x0000 |
61 | #define BBP_SIZE 0x0040 | 61 | #define BBP_SIZE 0x0040 |
62 | #define RF_BASE 0x0000 | 62 | #define RF_BASE 0x0004 |
63 | #define RF_SIZE 0x0014 | 63 | #define RF_SIZE 0x0010 |
64 | 64 | ||
65 | /* | 65 | /* |
66 | * Number of TX queues. | 66 | * Number of TX queues. |
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 270691ac2361..ca280674180e 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c | |||
@@ -204,9 +204,6 @@ static void rt2500usb_rf_write(struct rt2x00_dev *rt2x00dev, | |||
204 | { | 204 | { |
205 | u16 reg; | 205 | u16 reg; |
206 | 206 | ||
207 | if (!word) | ||
208 | return; | ||
209 | |||
210 | mutex_lock(&rt2x00dev->csr_mutex); | 207 | mutex_lock(&rt2x00dev->csr_mutex); |
211 | 208 | ||
212 | /* | 209 | /* |
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.h b/drivers/net/wireless/rt2x00/rt2500usb.h index afce0e0322c3..5bc46fe72179 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.h +++ b/drivers/net/wireless/rt2x00/rt2500usb.h | |||
@@ -59,8 +59,8 @@ | |||
59 | #define EEPROM_SIZE 0x006a | 59 | #define EEPROM_SIZE 0x006a |
60 | #define BBP_BASE 0x0000 | 60 | #define BBP_BASE 0x0000 |
61 | #define BBP_SIZE 0x0060 | 61 | #define BBP_SIZE 0x0060 |
62 | #define RF_BASE 0x0000 | 62 | #define RF_BASE 0x0004 |
63 | #define RF_SIZE 0x0014 | 63 | #define RF_SIZE 0x0010 |
64 | 64 | ||
65 | /* | 65 | /* |
66 | * Number of TX queues. | 66 | * Number of TX queues. |
diff --git a/drivers/net/wireless/rt2x00/rt2x00debug.c b/drivers/net/wireless/rt2x00/rt2x00debug.c index dcdce7f746b5..8d47389d8874 100644 --- a/drivers/net/wireless/rt2x00/rt2x00debug.c +++ b/drivers/net/wireless/rt2x00/rt2x00debug.c | |||
@@ -435,11 +435,12 @@ static ssize_t rt2x00debug_read_##__name(struct file *file, \ | |||
435 | if (index >= debug->__name.word_count) \ | 435 | if (index >= debug->__name.word_count) \ |
436 | return -EINVAL; \ | 436 | return -EINVAL; \ |
437 | \ | 437 | \ |
438 | index += (debug->__name.word_base / \ | ||
439 | debug->__name.word_size); \ | ||
440 | \ | ||
438 | if (debug->__name.flags & RT2X00DEBUGFS_OFFSET) \ | 441 | if (debug->__name.flags & RT2X00DEBUGFS_OFFSET) \ |
439 | index *= debug->__name.word_size; \ | 442 | index *= debug->__name.word_size; \ |
440 | \ | 443 | \ |
441 | index += debug->__name.word_base; \ | ||
442 | \ | ||
443 | debug->__name.read(intf->rt2x00dev, index, &value); \ | 444 | debug->__name.read(intf->rt2x00dev, index, &value); \ |
444 | \ | 445 | \ |
445 | size = sprintf(line, __format, value); \ | 446 | size = sprintf(line, __format, value); \ |
@@ -476,11 +477,12 @@ static ssize_t rt2x00debug_write_##__name(struct file *file, \ | |||
476 | size = strlen(line); \ | 477 | size = strlen(line); \ |
477 | value = simple_strtoul(line, NULL, 0); \ | 478 | value = simple_strtoul(line, NULL, 0); \ |
478 | \ | 479 | \ |
480 | index += (debug->__name.word_base / \ | ||
481 | debug->__name.word_size); \ | ||
482 | \ | ||
479 | if (debug->__name.flags & RT2X00DEBUGFS_OFFSET) \ | 483 | if (debug->__name.flags & RT2X00DEBUGFS_OFFSET) \ |
480 | index *= debug->__name.word_size; \ | 484 | index *= debug->__name.word_size; \ |
481 | \ | 485 | \ |
482 | index += debug->__name.word_base; \ | ||
483 | \ | ||
484 | debug->__name.write(intf->rt2x00dev, index, value); \ | 486 | debug->__name.write(intf->rt2x00dev, index, value); \ |
485 | \ | 487 | \ |
486 | *offset += size; \ | 488 | *offset += size; \ |
diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 0be147f364e7..2ca8b7a9722c 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c | |||
@@ -123,9 +123,6 @@ static void rt61pci_rf_write(struct rt2x00_dev *rt2x00dev, | |||
123 | { | 123 | { |
124 | u32 reg; | 124 | u32 reg; |
125 | 125 | ||
126 | if (!word) | ||
127 | return; | ||
128 | |||
129 | mutex_lock(&rt2x00dev->csr_mutex); | 126 | mutex_lock(&rt2x00dev->csr_mutex); |
130 | 127 | ||
131 | /* | 128 | /* |
diff --git a/drivers/net/wireless/rt2x00/rt61pci.h b/drivers/net/wireless/rt2x00/rt61pci.h index 2f97fee7a8de..41e8959919f6 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.h +++ b/drivers/net/wireless/rt2x00/rt61pci.h | |||
@@ -50,8 +50,8 @@ | |||
50 | #define EEPROM_SIZE 0x0100 | 50 | #define EEPROM_SIZE 0x0100 |
51 | #define BBP_BASE 0x0000 | 51 | #define BBP_BASE 0x0000 |
52 | #define BBP_SIZE 0x0080 | 52 | #define BBP_SIZE 0x0080 |
53 | #define RF_BASE 0x0000 | 53 | #define RF_BASE 0x0004 |
54 | #define RF_SIZE 0x0014 | 54 | #define RF_SIZE 0x0010 |
55 | 55 | ||
56 | /* | 56 | /* |
57 | * Number of TX queues. | 57 | * Number of TX queues. |
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 6521dac7ec4a..90ace51ab496 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c | |||
@@ -122,9 +122,6 @@ static void rt73usb_rf_write(struct rt2x00_dev *rt2x00dev, | |||
122 | { | 122 | { |
123 | u32 reg; | 123 | u32 reg; |
124 | 124 | ||
125 | if (!word) | ||
126 | return; | ||
127 | |||
128 | mutex_lock(&rt2x00dev->csr_mutex); | 125 | mutex_lock(&rt2x00dev->csr_mutex); |
129 | 126 | ||
130 | /* | 127 | /* |
@@ -2241,13 +2238,6 @@ static int rt73usb_conf_tx(struct ieee80211_hw *hw, u16 queue_idx, | |||
2241 | return 0; | 2238 | return 0; |
2242 | } | 2239 | } |
2243 | 2240 | ||
2244 | #if 0 | ||
2245 | /* | ||
2246 | * Mac80211 demands get_tsf must be atomic. | ||
2247 | * This is not possible for rt73usb since all register access | ||
2248 | * functions require sleeping. Untill mac80211 no longer needs | ||
2249 | * get_tsf to be atomic, this function should be disabled. | ||
2250 | */ | ||
2251 | static u64 rt73usb_get_tsf(struct ieee80211_hw *hw) | 2241 | static u64 rt73usb_get_tsf(struct ieee80211_hw *hw) |
2252 | { | 2242 | { |
2253 | struct rt2x00_dev *rt2x00dev = hw->priv; | 2243 | struct rt2x00_dev *rt2x00dev = hw->priv; |
@@ -2261,9 +2251,6 @@ static u64 rt73usb_get_tsf(struct ieee80211_hw *hw) | |||
2261 | 2251 | ||
2262 | return tsf; | 2252 | return tsf; |
2263 | } | 2253 | } |
2264 | #else | ||
2265 | #define rt73usb_get_tsf NULL | ||
2266 | #endif | ||
2267 | 2254 | ||
2268 | static const struct ieee80211_ops rt73usb_mac80211_ops = { | 2255 | static const struct ieee80211_ops rt73usb_mac80211_ops = { |
2269 | .tx = rt2x00mac_tx, | 2256 | .tx = rt2x00mac_tx, |
@@ -2355,6 +2342,9 @@ static const struct rt2x00_ops rt73usb_ops = { | |||
2355 | static struct usb_device_id rt73usb_device_table[] = { | 2342 | static struct usb_device_id rt73usb_device_table[] = { |
2356 | /* AboCom */ | 2343 | /* AboCom */ |
2357 | { USB_DEVICE(0x07b8, 0xb21d), USB_DEVICE_DATA(&rt73usb_ops) }, | 2344 | { USB_DEVICE(0x07b8, 0xb21d), USB_DEVICE_DATA(&rt73usb_ops) }, |
2345 | /* Amigo */ | ||
2346 | { USB_DEVICE(0x148f, 0x9021), USB_DEVICE_DATA(&rt73usb_ops) }, | ||
2347 | { USB_DEVICE(0x0eb0, 0x9021), USB_DEVICE_DATA(&rt73usb_ops) }, | ||
2358 | /* Askey */ | 2348 | /* Askey */ |
2359 | { USB_DEVICE(0x1690, 0x0722), USB_DEVICE_DATA(&rt73usb_ops) }, | 2349 | { USB_DEVICE(0x1690, 0x0722), USB_DEVICE_DATA(&rt73usb_ops) }, |
2360 | /* ASUS */ | 2350 | /* ASUS */ |
@@ -2402,6 +2392,7 @@ static struct usb_device_id rt73usb_device_table[] = { | |||
2402 | { USB_DEVICE(0x0db0, 0xa861), USB_DEVICE_DATA(&rt73usb_ops) }, | 2392 | { USB_DEVICE(0x0db0, 0xa861), USB_DEVICE_DATA(&rt73usb_ops) }, |
2403 | { USB_DEVICE(0x0db0, 0xa874), USB_DEVICE_DATA(&rt73usb_ops) }, | 2393 | { USB_DEVICE(0x0db0, 0xa874), USB_DEVICE_DATA(&rt73usb_ops) }, |
2404 | /* Ralink */ | 2394 | /* Ralink */ |
2395 | { USB_DEVICE(0x04bb, 0x093d), USB_DEVICE_DATA(&rt73usb_ops) }, | ||
2405 | { USB_DEVICE(0x148f, 0x2573), USB_DEVICE_DATA(&rt73usb_ops) }, | 2396 | { USB_DEVICE(0x148f, 0x2573), USB_DEVICE_DATA(&rt73usb_ops) }, |
2406 | { USB_DEVICE(0x148f, 0x2671), USB_DEVICE_DATA(&rt73usb_ops) }, | 2397 | { USB_DEVICE(0x148f, 0x2671), USB_DEVICE_DATA(&rt73usb_ops) }, |
2407 | /* Qcom */ | 2398 | /* Qcom */ |
@@ -2418,6 +2409,8 @@ static struct usb_device_id rt73usb_device_table[] = { | |||
2418 | /* Planex */ | 2409 | /* Planex */ |
2419 | { USB_DEVICE(0x2019, 0xab01), USB_DEVICE_DATA(&rt73usb_ops) }, | 2410 | { USB_DEVICE(0x2019, 0xab01), USB_DEVICE_DATA(&rt73usb_ops) }, |
2420 | { USB_DEVICE(0x2019, 0xab50), USB_DEVICE_DATA(&rt73usb_ops) }, | 2411 | { USB_DEVICE(0x2019, 0xab50), USB_DEVICE_DATA(&rt73usb_ops) }, |
2412 | /* ZyXEL */ | ||
2413 | { USB_DEVICE(0x0586, 0x3415), USB_DEVICE_DATA(&rt73usb_ops) }, | ||
2421 | { 0, } | 2414 | { 0, } |
2422 | }; | 2415 | }; |
2423 | 2416 | ||
diff --git a/drivers/net/wireless/rt2x00/rt73usb.h b/drivers/net/wireless/rt2x00/rt73usb.h index 834b28ce6cde..c8016f65b4bd 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.h +++ b/drivers/net/wireless/rt2x00/rt73usb.h | |||
@@ -50,8 +50,8 @@ | |||
50 | #define EEPROM_SIZE 0x0100 | 50 | #define EEPROM_SIZE 0x0100 |
51 | #define BBP_BASE 0x0000 | 51 | #define BBP_BASE 0x0000 |
52 | #define BBP_SIZE 0x0080 | 52 | #define BBP_SIZE 0x0080 |
53 | #define RF_BASE 0x0000 | 53 | #define RF_BASE 0x0004 |
54 | #define RF_SIZE 0x0014 | 54 | #define RF_SIZE 0x0010 |
55 | 55 | ||
56 | /* | 56 | /* |
57 | * Number of TX queues. | 57 | * Number of TX queues. |
diff --git a/drivers/net/wireless/wavelan.c b/drivers/net/wireless/wavelan.c index 688bdea8f13a..b728541f2fb5 100644 --- a/drivers/net/wireless/wavelan.c +++ b/drivers/net/wireless/wavelan.c | |||
@@ -4281,8 +4281,7 @@ int __init init_module(void) | |||
4281 | 4281 | ||
4282 | 4282 | ||
4283 | /* Loop on all possible base addresses. */ | 4283 | /* Loop on all possible base addresses. */ |
4284 | i = -1; | 4284 | for (i = 0; i < ARRAY_SIZE(io) && io[i] != 0; i++) { |
4285 | while ((io[++i] != 0) && (i < ARRAY_SIZE(io))) { | ||
4286 | struct net_device *dev = alloc_etherdev(sizeof(net_local)); | 4285 | struct net_device *dev = alloc_etherdev(sizeof(net_local)); |
4287 | if (!dev) | 4286 | if (!dev) |
4288 | break; | 4287 | break; |
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index 7579af27edbd..da9214e33a5f 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c | |||
@@ -170,10 +170,10 @@ int zd_mac_init_hw(struct ieee80211_hw *hw) | |||
170 | goto disable_int; | 170 | goto disable_int; |
171 | 171 | ||
172 | r = zd_reg2alpha2(mac->regdomain, alpha2); | 172 | r = zd_reg2alpha2(mac->regdomain, alpha2); |
173 | if (!r) | 173 | if (r) |
174 | regulatory_hint(hw->wiphy, alpha2); | 174 | goto disable_int; |
175 | 175 | ||
176 | r = 0; | 176 | r = regulatory_hint(hw->wiphy, alpha2); |
177 | disable_int: | 177 | disable_int: |
178 | zd_chip_disable_int(chip); | 178 | zd_chip_disable_int(chip); |
179 | out: | 179 | out: |
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index 8802d1bda382..f6e56370ea65 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h | |||
@@ -526,6 +526,9 @@ enum nl80211_rate_info { | |||
526 | * @NL80211_STA_INFO_SIGNAL: signal strength of last received PPDU (u8, dBm) | 526 | * @NL80211_STA_INFO_SIGNAL: signal strength of last received PPDU (u8, dBm) |
527 | * @NL80211_STA_INFO_TX_BITRATE: current unicast tx rate, nested attribute | 527 | * @NL80211_STA_INFO_TX_BITRATE: current unicast tx rate, nested attribute |
528 | * containing info as possible, see &enum nl80211_sta_info_txrate. | 528 | * containing info as possible, see &enum nl80211_sta_info_txrate. |
529 | * @NL80211_STA_INFO_RX_PACKETS: total received packet (u32, from this station) | ||
530 | * @NL80211_STA_INFO_TX_PACKETS: total transmitted packets (u32, to this | ||
531 | * station) | ||
529 | */ | 532 | */ |
530 | enum nl80211_sta_info { | 533 | enum nl80211_sta_info { |
531 | __NL80211_STA_INFO_INVALID, | 534 | __NL80211_STA_INFO_INVALID, |
@@ -537,6 +540,8 @@ enum nl80211_sta_info { | |||
537 | NL80211_STA_INFO_PLINK_STATE, | 540 | NL80211_STA_INFO_PLINK_STATE, |
538 | NL80211_STA_INFO_SIGNAL, | 541 | NL80211_STA_INFO_SIGNAL, |
539 | NL80211_STA_INFO_TX_BITRATE, | 542 | NL80211_STA_INFO_TX_BITRATE, |
543 | NL80211_STA_INFO_RX_PACKETS, | ||
544 | NL80211_STA_INFO_TX_PACKETS, | ||
540 | 545 | ||
541 | /* keep last */ | 546 | /* keep last */ |
542 | __NL80211_STA_INFO_AFTER_LAST, | 547 | __NL80211_STA_INFO_AFTER_LAST, |
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index c0d1f5b708c5..75fa556728ce 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h | |||
@@ -178,6 +178,8 @@ struct station_parameters { | |||
178 | * @STATION_INFO_SIGNAL: @signal filled | 178 | * @STATION_INFO_SIGNAL: @signal filled |
179 | * @STATION_INFO_TX_BITRATE: @tx_bitrate fields are filled | 179 | * @STATION_INFO_TX_BITRATE: @tx_bitrate fields are filled |
180 | * (tx_bitrate, tx_bitrate_flags and tx_bitrate_mcs) | 180 | * (tx_bitrate, tx_bitrate_flags and tx_bitrate_mcs) |
181 | * @STATION_INFO_RX_PACKETS: @rx_packets filled | ||
182 | * @STATION_INFO_TX_PACKETS: @tx_packets filled | ||
181 | */ | 183 | */ |
182 | enum station_info_flags { | 184 | enum station_info_flags { |
183 | STATION_INFO_INACTIVE_TIME = 1<<0, | 185 | STATION_INFO_INACTIVE_TIME = 1<<0, |
@@ -188,6 +190,8 @@ enum station_info_flags { | |||
188 | STATION_INFO_PLINK_STATE = 1<<5, | 190 | STATION_INFO_PLINK_STATE = 1<<5, |
189 | STATION_INFO_SIGNAL = 1<<6, | 191 | STATION_INFO_SIGNAL = 1<<6, |
190 | STATION_INFO_TX_BITRATE = 1<<7, | 192 | STATION_INFO_TX_BITRATE = 1<<7, |
193 | STATION_INFO_RX_PACKETS = 1<<8, | ||
194 | STATION_INFO_TX_PACKETS = 1<<9, | ||
191 | }; | 195 | }; |
192 | 196 | ||
193 | /** | 197 | /** |
@@ -235,6 +239,8 @@ struct rate_info { | |||
235 | * @plink_state: mesh peer link state | 239 | * @plink_state: mesh peer link state |
236 | * @signal: signal strength of last received packet in dBm | 240 | * @signal: signal strength of last received packet in dBm |
237 | * @txrate: current unicast bitrate to this station | 241 | * @txrate: current unicast bitrate to this station |
242 | * @rx_packets: packets received from this station | ||
243 | * @tx_packets: packets transmitted to this station | ||
238 | */ | 244 | */ |
239 | struct station_info { | 245 | struct station_info { |
240 | u32 filled; | 246 | u32 filled; |
@@ -246,6 +252,8 @@ struct station_info { | |||
246 | u8 plink_state; | 252 | u8 plink_state; |
247 | s8 signal; | 253 | s8 signal; |
248 | struct rate_info txrate; | 254 | struct rate_info txrate; |
255 | u32 rx_packets; | ||
256 | u32 tx_packets; | ||
249 | }; | 257 | }; |
250 | 258 | ||
251 | /** | 259 | /** |
@@ -375,9 +383,9 @@ enum environment_cap { | |||
375 | }; | 383 | }; |
376 | 384 | ||
377 | /** | 385 | /** |
378 | * struct regulatory_request - receipt of last regulatory request | 386 | * struct regulatory_request - used to keep track of regulatory requests |
379 | * | 387 | * |
380 | * @wiphy: this is set if this request's initiator is | 388 | * @wiphy_idx: this is set if this request's initiator is |
381 | * %REGDOM_SET_BY_COUNTRY_IE or %REGDOM_SET_BY_DRIVER. This | 389 | * %REGDOM_SET_BY_COUNTRY_IE or %REGDOM_SET_BY_DRIVER. This |
382 | * can be used by the wireless core to deal with conflicts | 390 | * can be used by the wireless core to deal with conflicts |
383 | * and potentially inform users of which devices specifically | 391 | * and potentially inform users of which devices specifically |
@@ -396,14 +404,16 @@ enum environment_cap { | |||
396 | * country IE | 404 | * country IE |
397 | * @country_ie_env: lets us know if the AP is telling us we are outdoor, | 405 | * @country_ie_env: lets us know if the AP is telling us we are outdoor, |
398 | * indoor, or if it doesn't matter | 406 | * indoor, or if it doesn't matter |
407 | * @list: used to insert into the reg_requests_list linked list | ||
399 | */ | 408 | */ |
400 | struct regulatory_request { | 409 | struct regulatory_request { |
401 | struct wiphy *wiphy; | 410 | int wiphy_idx; |
402 | enum reg_set_by initiator; | 411 | enum reg_set_by initiator; |
403 | char alpha2[2]; | 412 | char alpha2[2]; |
404 | bool intersect; | 413 | bool intersect; |
405 | u32 country_ie_checksum; | 414 | u32 country_ie_checksum; |
406 | enum environment_cap country_ie_env; | 415 | enum environment_cap country_ie_env; |
416 | struct list_head list; | ||
407 | }; | 417 | }; |
408 | 418 | ||
409 | struct ieee80211_freq_range { | 419 | struct ieee80211_freq_range { |
@@ -525,6 +535,8 @@ struct cfg80211_ssid { | |||
525 | * @n_ssids: number of SSIDs | 535 | * @n_ssids: number of SSIDs |
526 | * @channels: channels to scan on. | 536 | * @channels: channels to scan on. |
527 | * @n_channels: number of channels for each band | 537 | * @n_channels: number of channels for each band |
538 | * @ie: optional information element(s) to add into Probe Request or %NULL | ||
539 | * @ie_len: length of ie in octets | ||
528 | * @wiphy: the wiphy this was for | 540 | * @wiphy: the wiphy this was for |
529 | * @ifidx: the interface index | 541 | * @ifidx: the interface index |
530 | */ | 542 | */ |
@@ -533,6 +545,8 @@ struct cfg80211_scan_request { | |||
533 | int n_ssids; | 545 | int n_ssids; |
534 | struct ieee80211_channel **channels; | 546 | struct ieee80211_channel **channels; |
535 | u32 n_channels; | 547 | u32 n_channels; |
548 | u8 *ie; | ||
549 | size_t ie_len; | ||
536 | 550 | ||
537 | /* internal */ | 551 | /* internal */ |
538 | struct wiphy *wiphy; | 552 | struct wiphy *wiphy; |
@@ -565,8 +579,7 @@ enum cfg80211_signal_type { | |||
565 | * @information_elements: the information elements (Note that there | 579 | * @information_elements: the information elements (Note that there |
566 | * is no guarantee that these are well-formed!) | 580 | * is no guarantee that these are well-formed!) |
567 | * @len_information_elements: total length of the information elements | 581 | * @len_information_elements: total length of the information elements |
568 | * @signal: signal strength value | 582 | * @signal: signal strength value (type depends on the wiphy's signal_type) |
569 | * @signal_type: signal type | ||
570 | * @free_priv: function pointer to free private data | 583 | * @free_priv: function pointer to free private data |
571 | * @priv: private area for driver use, has at least wiphy->bss_priv_size bytes | 584 | * @priv: private area for driver use, has at least wiphy->bss_priv_size bytes |
572 | */ | 585 | */ |
@@ -581,7 +594,6 @@ struct cfg80211_bss { | |||
581 | size_t len_information_elements; | 594 | size_t len_information_elements; |
582 | 595 | ||
583 | s32 signal; | 596 | s32 signal; |
584 | enum cfg80211_signal_type signal_type; | ||
585 | 597 | ||
586 | void (*free_priv)(struct cfg80211_bss *bss); | 598 | void (*free_priv)(struct cfg80211_bss *bss); |
587 | u8 priv[0] __attribute__((__aligned__(sizeof(void *)))); | 599 | u8 priv[0] __attribute__((__aligned__(sizeof(void *)))); |
@@ -755,6 +767,9 @@ int cfg80211_wext_siwscan(struct net_device *dev, | |||
755 | int cfg80211_wext_giwscan(struct net_device *dev, | 767 | int cfg80211_wext_giwscan(struct net_device *dev, |
756 | struct iw_request_info *info, | 768 | struct iw_request_info *info, |
757 | struct iw_point *data, char *extra); | 769 | struct iw_point *data, char *extra); |
770 | int cfg80211_wext_giwrange(struct net_device *dev, | ||
771 | struct iw_request_info *info, | ||
772 | struct iw_point *data, char *extra); | ||
758 | 773 | ||
759 | /** | 774 | /** |
760 | * cfg80211_scan_done - notify that scan finished | 775 | * cfg80211_scan_done - notify that scan finished |
@@ -770,6 +785,7 @@ void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted); | |||
770 | * | 785 | * |
771 | * @wiphy: the wiphy reporting the BSS | 786 | * @wiphy: the wiphy reporting the BSS |
772 | * @bss: the found BSS | 787 | * @bss: the found BSS |
788 | * @signal: the signal strength, type depends on the wiphy's signal_type | ||
773 | * @gfp: context flags | 789 | * @gfp: context flags |
774 | * | 790 | * |
775 | * This informs cfg80211 that BSS information was found and | 791 | * This informs cfg80211 that BSS information was found and |
@@ -779,8 +795,7 @@ struct cfg80211_bss* | |||
779 | cfg80211_inform_bss_frame(struct wiphy *wiphy, | 795 | cfg80211_inform_bss_frame(struct wiphy *wiphy, |
780 | struct ieee80211_channel *channel, | 796 | struct ieee80211_channel *channel, |
781 | struct ieee80211_mgmt *mgmt, size_t len, | 797 | struct ieee80211_mgmt *mgmt, size_t len, |
782 | s32 signal, enum cfg80211_signal_type sigtype, | 798 | s32 signal, gfp_t gfp); |
783 | gfp_t gfp); | ||
784 | 799 | ||
785 | struct cfg80211_bss *cfg80211_get_bss(struct wiphy *wiphy, | 800 | struct cfg80211_bss *cfg80211_get_bss(struct wiphy *wiphy, |
786 | struct ieee80211_channel *channel, | 801 | struct ieee80211_channel *channel, |
diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 88fa3e03e3e9..12a52efcd0d1 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h | |||
@@ -1022,11 +1022,6 @@ static inline int ieee80211_num_regular_queues(struct ieee80211_hw *hw) | |||
1022 | return hw->queues; | 1022 | return hw->queues; |
1023 | } | 1023 | } |
1024 | 1024 | ||
1025 | static inline int ieee80211_num_queues(struct ieee80211_hw *hw) | ||
1026 | { | ||
1027 | return hw->queues + hw->ampdu_queues; | ||
1028 | } | ||
1029 | |||
1030 | static inline struct ieee80211_rate * | 1025 | static inline struct ieee80211_rate * |
1031 | ieee80211_get_tx_rate(const struct ieee80211_hw *hw, | 1026 | ieee80211_get_tx_rate(const struct ieee80211_hw *hw, |
1032 | const struct ieee80211_tx_info *c) | 1027 | const struct ieee80211_tx_info *c) |
@@ -1329,6 +1324,12 @@ enum ieee80211_ampdu_mlme_action { | |||
1329 | * because the hardware is turned off! Anything else is a bug! | 1324 | * because the hardware is turned off! Anything else is a bug! |
1330 | * Returns a negative error code which will be seen in userspace. | 1325 | * Returns a negative error code which will be seen in userspace. |
1331 | * | 1326 | * |
1327 | * @sw_scan_start: Notifier function that is called just before a software scan | ||
1328 | * is started. Can be NULL, if the driver doesn't need this notification. | ||
1329 | * | ||
1330 | * @sw_scan_complete: Notifier function that is called just after a software scan | ||
1331 | * finished. Can be NULL, if the driver doesn't need this notification. | ||
1332 | * | ||
1332 | * @get_stats: Return low-level statistics. | 1333 | * @get_stats: Return low-level statistics. |
1333 | * Returns zero if statistics are available. | 1334 | * Returns zero if statistics are available. |
1334 | * | 1335 | * |
@@ -1408,6 +1409,8 @@ struct ieee80211_ops { | |||
1408 | u32 iv32, u16 *phase1key); | 1409 | u32 iv32, u16 *phase1key); |
1409 | int (*hw_scan)(struct ieee80211_hw *hw, | 1410 | int (*hw_scan)(struct ieee80211_hw *hw, |
1410 | struct cfg80211_scan_request *req); | 1411 | struct cfg80211_scan_request *req); |
1412 | void (*sw_scan_start)(struct ieee80211_hw *hw); | ||
1413 | void (*sw_scan_complete)(struct ieee80211_hw *hw); | ||
1411 | int (*get_stats)(struct ieee80211_hw *hw, | 1414 | int (*get_stats)(struct ieee80211_hw *hw, |
1412 | struct ieee80211_low_level_stats *stats); | 1415 | struct ieee80211_low_level_stats *stats); |
1413 | void (*get_tkip_seq)(struct ieee80211_hw *hw, u8 hw_key_idx, | 1416 | void (*get_tkip_seq)(struct ieee80211_hw *hw, u8 hw_key_idx, |
@@ -1980,6 +1983,16 @@ struct ieee80211_sta *ieee80211_find_sta(struct ieee80211_hw *hw, | |||
1980 | /* Rate control API */ | 1983 | /* Rate control API */ |
1981 | 1984 | ||
1982 | /** | 1985 | /** |
1986 | * enum rate_control_changed - flags to indicate which parameter changed | ||
1987 | * | ||
1988 | * @IEEE80211_RC_HT_CHANGED: The HT parameters of the operating channel have | ||
1989 | * changed, rate control algorithm can update its internal state if needed. | ||
1990 | */ | ||
1991 | enum rate_control_changed { | ||
1992 | IEEE80211_RC_HT_CHANGED = BIT(0) | ||
1993 | }; | ||
1994 | |||
1995 | /** | ||
1983 | * struct ieee80211_tx_rate_control - rate control information for/from RC algo | 1996 | * struct ieee80211_tx_rate_control - rate control information for/from RC algo |
1984 | * | 1997 | * |
1985 | * @hw: The hardware the algorithm is invoked for. | 1998 | * @hw: The hardware the algorithm is invoked for. |
@@ -2015,6 +2028,9 @@ struct rate_control_ops { | |||
2015 | void *(*alloc_sta)(void *priv, struct ieee80211_sta *sta, gfp_t gfp); | 2028 | void *(*alloc_sta)(void *priv, struct ieee80211_sta *sta, gfp_t gfp); |
2016 | void (*rate_init)(void *priv, struct ieee80211_supported_band *sband, | 2029 | void (*rate_init)(void *priv, struct ieee80211_supported_band *sband, |
2017 | struct ieee80211_sta *sta, void *priv_sta); | 2030 | struct ieee80211_sta *sta, void *priv_sta); |
2031 | void (*rate_update)(void *priv, struct ieee80211_supported_band *sband, | ||
2032 | struct ieee80211_sta *sta, | ||
2033 | void *priv_sta, u32 changed); | ||
2018 | void (*free_sta)(void *priv, struct ieee80211_sta *sta, | 2034 | void (*free_sta)(void *priv, struct ieee80211_sta *sta, |
2019 | void *priv_sta); | 2035 | void *priv_sta); |
2020 | 2036 | ||
diff --git a/include/net/wireless.h b/include/net/wireless.h index 1c6285eb1666..64a76208580c 100644 --- a/include/net/wireless.h +++ b/include/net/wireless.h | |||
@@ -69,6 +69,9 @@ enum ieee80211_channel_flags { | |||
69 | * @band: band this channel belongs to. | 69 | * @band: band this channel belongs to. |
70 | * @max_antenna_gain: maximum antenna gain in dBi | 70 | * @max_antenna_gain: maximum antenna gain in dBi |
71 | * @max_power: maximum transmission power (in dBm) | 71 | * @max_power: maximum transmission power (in dBm) |
72 | * @beacon_found: helper to regulatory code to indicate when a beacon | ||
73 | * has been found on this channel. Use regulatory_hint_found_beacon() | ||
74 | * to enable this, this is is useful only on 5 GHz band. | ||
72 | * @orig_mag: internal use | 75 | * @orig_mag: internal use |
73 | * @orig_mpwr: internal use | 76 | * @orig_mpwr: internal use |
74 | */ | 77 | */ |
@@ -80,6 +83,7 @@ struct ieee80211_channel { | |||
80 | u32 flags; | 83 | u32 flags; |
81 | int max_antenna_gain; | 84 | int max_antenna_gain; |
82 | int max_power; | 85 | int max_power; |
86 | bool beacon_found; | ||
83 | u32 orig_flags; | 87 | u32 orig_flags; |
84 | int orig_mag, orig_mpwr; | 88 | int orig_mag, orig_mpwr; |
85 | }; | 89 | }; |
@@ -200,6 +204,7 @@ struct ieee80211_supported_band { | |||
200 | * the regulatory_hint() API. This can be used by the driver | 204 | * the regulatory_hint() API. This can be used by the driver |
201 | * on the reg_notifier() if it chooses to ignore future | 205 | * on the reg_notifier() if it chooses to ignore future |
202 | * regulatory domain changes caused by other drivers. | 206 | * regulatory domain changes caused by other drivers. |
207 | * @signal_type: signal type reported in &struct cfg80211_bss. | ||
203 | */ | 208 | */ |
204 | struct wiphy { | 209 | struct wiphy { |
205 | /* assign these fields before you register the wiphy */ | 210 | /* assign these fields before you register the wiphy */ |
@@ -213,6 +218,8 @@ struct wiphy { | |||
213 | bool custom_regulatory; | 218 | bool custom_regulatory; |
214 | bool strict_regulatory; | 219 | bool strict_regulatory; |
215 | 220 | ||
221 | enum cfg80211_signal_type signal_type; | ||
222 | |||
216 | int bss_priv_size; | 223 | int bss_priv_size; |
217 | u8 max_scan_ssids; | 224 | u8 max_scan_ssids; |
218 | 225 | ||
@@ -398,8 +405,15 @@ ieee80211_get_response_rate(struct ieee80211_supported_band *sband, | |||
398 | * domain should be in or by providing a completely build regulatory domain. | 405 | * domain should be in or by providing a completely build regulatory domain. |
399 | * If the driver provides an ISO/IEC 3166 alpha2 userspace will be queried | 406 | * If the driver provides an ISO/IEC 3166 alpha2 userspace will be queried |
400 | * for a regulatory domain structure for the respective country. | 407 | * for a regulatory domain structure for the respective country. |
408 | * | ||
409 | * The wiphy must have been registered to cfg80211 prior to this call. | ||
410 | * For cfg80211 drivers this means you must first use wiphy_register(), | ||
411 | * for mac80211 drivers you must first use ieee80211_register_hw(). | ||
412 | * | ||
413 | * Drivers should check the return value, its possible you can get | ||
414 | * an -ENOMEM. | ||
401 | */ | 415 | */ |
402 | extern void regulatory_hint(struct wiphy *wiphy, const char *alpha2); | 416 | extern int regulatory_hint(struct wiphy *wiphy, const char *alpha2); |
403 | 417 | ||
404 | /** | 418 | /** |
405 | * regulatory_hint_11d - hints a country IE as a regulatory domain | 419 | * regulatory_hint_11d - hints a country IE as a regulatory domain |
@@ -415,7 +429,6 @@ extern void regulatory_hint(struct wiphy *wiphy, const char *alpha2); | |||
415 | extern void regulatory_hint_11d(struct wiphy *wiphy, | 429 | extern void regulatory_hint_11d(struct wiphy *wiphy, |
416 | u8 *country_ie, | 430 | u8 *country_ie, |
417 | u8 country_ie_len); | 431 | u8 country_ie_len); |
418 | |||
419 | /** | 432 | /** |
420 | * wiphy_apply_custom_regulatory - apply a custom driver regulatory domain | 433 | * wiphy_apply_custom_regulatory - apply a custom driver regulatory domain |
421 | * @wiphy: the wireless device we want to process the regulatory domain on | 434 | * @wiphy: the wireless device we want to process the regulatory domain on |
diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile index 3503a3d21318..0e3ab88bb706 100644 --- a/net/mac80211/Makefile +++ b/net/mac80211/Makefile | |||
@@ -9,6 +9,7 @@ mac80211-y := \ | |||
9 | wpa.o \ | 9 | wpa.o \ |
10 | scan.o \ | 10 | scan.o \ |
11 | ht.o agg-tx.o agg-rx.o \ | 11 | ht.o agg-tx.o agg-rx.o \ |
12 | ibss.o \ | ||
12 | mlme.o \ | 13 | mlme.o \ |
13 | iface.o \ | 14 | iface.o \ |
14 | rate.o \ | 15 | rate.o \ |
diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c index 3112bfd441b6..a95affc94629 100644 --- a/net/mac80211/agg-rx.c +++ b/net/mac80211/agg-rx.c | |||
@@ -129,7 +129,6 @@ static void ieee80211_send_addba_resp(struct ieee80211_sub_if_data *sdata, u8 *d | |||
129 | u8 dialog_token, u16 status, u16 policy, | 129 | u8 dialog_token, u16 status, u16 policy, |
130 | u16 buf_size, u16 timeout) | 130 | u16 buf_size, u16 timeout) |
131 | { | 131 | { |
132 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | ||
133 | struct ieee80211_local *local = sdata->local; | 132 | struct ieee80211_local *local = sdata->local; |
134 | struct sk_buff *skb; | 133 | struct sk_buff *skb; |
135 | struct ieee80211_mgmt *mgmt; | 134 | struct ieee80211_mgmt *mgmt; |
@@ -151,8 +150,9 @@ static void ieee80211_send_addba_resp(struct ieee80211_sub_if_data *sdata, u8 *d | |||
151 | if (sdata->vif.type == NL80211_IFTYPE_AP || | 150 | if (sdata->vif.type == NL80211_IFTYPE_AP || |
152 | sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | 151 | sdata->vif.type == NL80211_IFTYPE_AP_VLAN) |
153 | memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN); | 152 | memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN); |
154 | else | 153 | else if (sdata->vif.type == NL80211_IFTYPE_STATION) |
155 | memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); | 154 | memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN); |
155 | |||
156 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | 156 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | |
157 | IEEE80211_STYPE_ACTION); | 157 | IEEE80211_STYPE_ACTION); |
158 | 158 | ||
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index 1232d9f01ca9..1df116d4d6e7 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c | |||
@@ -49,7 +49,6 @@ static void ieee80211_send_addba_request(struct ieee80211_sub_if_data *sdata, | |||
49 | u16 agg_size, u16 timeout) | 49 | u16 agg_size, u16 timeout) |
50 | { | 50 | { |
51 | struct ieee80211_local *local = sdata->local; | 51 | struct ieee80211_local *local = sdata->local; |
52 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | ||
53 | struct sk_buff *skb; | 52 | struct sk_buff *skb; |
54 | struct ieee80211_mgmt *mgmt; | 53 | struct ieee80211_mgmt *mgmt; |
55 | u16 capab; | 54 | u16 capab; |
@@ -69,8 +68,8 @@ static void ieee80211_send_addba_request(struct ieee80211_sub_if_data *sdata, | |||
69 | if (sdata->vif.type == NL80211_IFTYPE_AP || | 68 | if (sdata->vif.type == NL80211_IFTYPE_AP || |
70 | sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | 69 | sdata->vif.type == NL80211_IFTYPE_AP_VLAN) |
71 | memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN); | 70 | memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN); |
72 | else | 71 | else if (sdata->vif.type == NL80211_IFTYPE_STATION) |
73 | memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); | 72 | memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN); |
74 | 73 | ||
75 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | 74 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | |
76 | IEEE80211_STYPE_ACTION); | 75 | IEEE80211_STYPE_ACTION); |
@@ -132,9 +131,24 @@ static int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, | |||
132 | 131 | ||
133 | state = &sta->ampdu_mlme.tid_state_tx[tid]; | 132 | state = &sta->ampdu_mlme.tid_state_tx[tid]; |
134 | 133 | ||
135 | if (local->hw.ampdu_queues) | 134 | if (local->hw.ampdu_queues) { |
136 | ieee80211_stop_queue(&local->hw, sta->tid_to_tx_q[tid]); | 135 | if (initiator) { |
136 | /* | ||
137 | * Stop the AC queue to avoid issues where we send | ||
138 | * unaggregated frames already before the delba. | ||
139 | */ | ||
140 | ieee80211_stop_queue_by_reason(&local->hw, | ||
141 | local->hw.queues + sta->tid_to_tx_q[tid], | ||
142 | IEEE80211_QUEUE_STOP_REASON_AGGREGATION); | ||
143 | } | ||
137 | 144 | ||
145 | /* | ||
146 | * Pretend the driver woke the queue, just in case | ||
147 | * it disabled it before the session was stopped. | ||
148 | */ | ||
149 | ieee80211_wake_queue( | ||
150 | &local->hw, local->hw.queues + sta->tid_to_tx_q[tid]); | ||
151 | } | ||
138 | *state = HT_AGG_STATE_REQ_STOP_BA_MSK | | 152 | *state = HT_AGG_STATE_REQ_STOP_BA_MSK | |
139 | (initiator << HT_AGG_STATE_INITIATOR_SHIFT); | 153 | (initiator << HT_AGG_STATE_INITIATOR_SHIFT); |
140 | 154 | ||
@@ -144,8 +158,6 @@ static int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, | |||
144 | /* HW shall not deny going back to legacy */ | 158 | /* HW shall not deny going back to legacy */ |
145 | if (WARN_ON(ret)) { | 159 | if (WARN_ON(ret)) { |
146 | *state = HT_AGG_STATE_OPERATIONAL; | 160 | *state = HT_AGG_STATE_OPERATIONAL; |
147 | if (local->hw.ampdu_queues) | ||
148 | ieee80211_wake_queue(&local->hw, sta->tid_to_tx_q[tid]); | ||
149 | } | 161 | } |
150 | 162 | ||
151 | return ret; | 163 | return ret; |
@@ -189,14 +201,19 @@ static void sta_addba_resp_timer_expired(unsigned long data) | |||
189 | spin_unlock_bh(&sta->lock); | 201 | spin_unlock_bh(&sta->lock); |
190 | } | 202 | } |
191 | 203 | ||
204 | static inline int ieee80211_ac_from_tid(int tid) | ||
205 | { | ||
206 | return ieee802_1d_to_ac[tid & 7]; | ||
207 | } | ||
208 | |||
192 | int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) | 209 | int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) |
193 | { | 210 | { |
194 | struct ieee80211_local *local = hw_to_local(hw); | 211 | struct ieee80211_local *local = hw_to_local(hw); |
195 | struct sta_info *sta; | 212 | struct sta_info *sta; |
196 | struct ieee80211_sub_if_data *sdata; | 213 | struct ieee80211_sub_if_data *sdata; |
197 | u16 start_seq_num; | ||
198 | u8 *state; | 214 | u8 *state; |
199 | int ret = 0; | 215 | int i, qn = -1, ret = 0; |
216 | u16 start_seq_num; | ||
200 | 217 | ||
201 | if (WARN_ON(!local->ops->ampdu_action)) | 218 | if (WARN_ON(!local->ops->ampdu_action)) |
202 | return -EINVAL; | 219 | return -EINVAL; |
@@ -209,6 +226,13 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) | |||
209 | ra, tid); | 226 | ra, tid); |
210 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | 227 | #endif /* CONFIG_MAC80211_HT_DEBUG */ |
211 | 228 | ||
229 | if (hw->ampdu_queues && ieee80211_ac_from_tid(tid) == 0) { | ||
230 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
231 | printk(KERN_DEBUG "rejecting on voice AC\n"); | ||
232 | #endif | ||
233 | return -EINVAL; | ||
234 | } | ||
235 | |||
212 | rcu_read_lock(); | 236 | rcu_read_lock(); |
213 | 237 | ||
214 | sta = sta_info_get(local, ra); | 238 | sta = sta_info_get(local, ra); |
@@ -217,7 +241,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) | |||
217 | printk(KERN_DEBUG "Could not find the station\n"); | 241 | printk(KERN_DEBUG "Could not find the station\n"); |
218 | #endif | 242 | #endif |
219 | ret = -ENOENT; | 243 | ret = -ENOENT; |
220 | goto exit; | 244 | goto unlock; |
221 | } | 245 | } |
222 | 246 | ||
223 | /* | 247 | /* |
@@ -230,11 +254,13 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) | |||
230 | sta->sdata->vif.type != NL80211_IFTYPE_AP_VLAN && | 254 | sta->sdata->vif.type != NL80211_IFTYPE_AP_VLAN && |
231 | sta->sdata->vif.type != NL80211_IFTYPE_AP) { | 255 | sta->sdata->vif.type != NL80211_IFTYPE_AP) { |
232 | ret = -EINVAL; | 256 | ret = -EINVAL; |
233 | goto exit; | 257 | goto unlock; |
234 | } | 258 | } |
235 | 259 | ||
236 | spin_lock_bh(&sta->lock); | 260 | spin_lock_bh(&sta->lock); |
237 | 261 | ||
262 | sdata = sta->sdata; | ||
263 | |||
238 | /* we have tried too many times, receiver does not want A-MPDU */ | 264 | /* we have tried too many times, receiver does not want A-MPDU */ |
239 | if (sta->ampdu_mlme.addba_req_num[tid] > HT_AGG_MAX_RETRIES) { | 265 | if (sta->ampdu_mlme.addba_req_num[tid] > HT_AGG_MAX_RETRIES) { |
240 | ret = -EBUSY; | 266 | ret = -EBUSY; |
@@ -252,6 +278,42 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) | |||
252 | goto err_unlock_sta; | 278 | goto err_unlock_sta; |
253 | } | 279 | } |
254 | 280 | ||
281 | if (hw->ampdu_queues) { | ||
282 | spin_lock(&local->queue_stop_reason_lock); | ||
283 | /* reserve a new queue for this session */ | ||
284 | for (i = 0; i < local->hw.ampdu_queues; i++) { | ||
285 | if (local->ampdu_ac_queue[i] < 0) { | ||
286 | qn = i; | ||
287 | local->ampdu_ac_queue[qn] = | ||
288 | ieee80211_ac_from_tid(tid); | ||
289 | break; | ||
290 | } | ||
291 | } | ||
292 | spin_unlock(&local->queue_stop_reason_lock); | ||
293 | |||
294 | if (qn < 0) { | ||
295 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
296 | printk(KERN_DEBUG "BA request denied - " | ||
297 | "queue unavailable for tid %d\n", tid); | ||
298 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | ||
299 | ret = -ENOSPC; | ||
300 | goto err_unlock_sta; | ||
301 | } | ||
302 | |||
303 | /* | ||
304 | * If we successfully allocate the session, we can't have | ||
305 | * anything going on on the queue this TID maps into, so | ||
306 | * stop it for now. This is a "virtual" stop using the same | ||
307 | * mechanism that drivers will use. | ||
308 | * | ||
309 | * XXX: queue up frames for this session in the sta_info | ||
310 | * struct instead to avoid hitting all other STAs. | ||
311 | */ | ||
312 | ieee80211_stop_queue_by_reason( | ||
313 | &local->hw, hw->queues + qn, | ||
314 | IEEE80211_QUEUE_STOP_REASON_AGGREGATION); | ||
315 | } | ||
316 | |||
255 | /* prepare A-MPDU MLME for Tx aggregation */ | 317 | /* prepare A-MPDU MLME for Tx aggregation */ |
256 | sta->ampdu_mlme.tid_tx[tid] = | 318 | sta->ampdu_mlme.tid_tx[tid] = |
257 | kmalloc(sizeof(struct tid_ampdu_tx), GFP_ATOMIC); | 319 | kmalloc(sizeof(struct tid_ampdu_tx), GFP_ATOMIC); |
@@ -262,8 +324,9 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) | |||
262 | tid); | 324 | tid); |
263 | #endif | 325 | #endif |
264 | ret = -ENOMEM; | 326 | ret = -ENOMEM; |
265 | goto err_unlock_sta; | 327 | goto err_return_queue; |
266 | } | 328 | } |
329 | |||
267 | /* Tx timer */ | 330 | /* Tx timer */ |
268 | sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.function = | 331 | sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.function = |
269 | sta_addba_resp_timer_expired; | 332 | sta_addba_resp_timer_expired; |
@@ -271,49 +334,25 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) | |||
271 | (unsigned long)&sta->timer_to_tid[tid]; | 334 | (unsigned long)&sta->timer_to_tid[tid]; |
272 | init_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer); | 335 | init_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer); |
273 | 336 | ||
274 | if (hw->ampdu_queues) { | ||
275 | /* create a new queue for this aggregation */ | ||
276 | ret = ieee80211_ht_agg_queue_add(local, sta, tid); | ||
277 | |||
278 | /* case no queue is available to aggregation | ||
279 | * don't switch to aggregation */ | ||
280 | if (ret) { | ||
281 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
282 | printk(KERN_DEBUG "BA request denied - " | ||
283 | "queue unavailable for tid %d\n", tid); | ||
284 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | ||
285 | goto err_unlock_queue; | ||
286 | } | ||
287 | } | ||
288 | sdata = sta->sdata; | ||
289 | |||
290 | /* Ok, the Addba frame hasn't been sent yet, but if the driver calls the | 337 | /* Ok, the Addba frame hasn't been sent yet, but if the driver calls the |
291 | * call back right away, it must see that the flow has begun */ | 338 | * call back right away, it must see that the flow has begun */ |
292 | *state |= HT_ADDBA_REQUESTED_MSK; | 339 | *state |= HT_ADDBA_REQUESTED_MSK; |
293 | 340 | ||
294 | /* This is slightly racy because the queue isn't stopped */ | ||
295 | start_seq_num = sta->tid_seq[tid]; | 341 | start_seq_num = sta->tid_seq[tid]; |
296 | 342 | ||
297 | ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_TX_START, | 343 | ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_TX_START, |
298 | &sta->sta, tid, &start_seq_num); | 344 | &sta->sta, tid, &start_seq_num); |
299 | 345 | ||
300 | if (ret) { | 346 | if (ret) { |
301 | /* No need to requeue the packets in the agg queue, since we | ||
302 | * held the tx lock: no packet could be enqueued to the newly | ||
303 | * allocated queue */ | ||
304 | if (hw->ampdu_queues) | ||
305 | ieee80211_ht_agg_queue_remove(local, sta, tid, 0); | ||
306 | #ifdef CONFIG_MAC80211_HT_DEBUG | 347 | #ifdef CONFIG_MAC80211_HT_DEBUG |
307 | printk(KERN_DEBUG "BA request denied - HW unavailable for" | 348 | printk(KERN_DEBUG "BA request denied - HW unavailable for" |
308 | " tid %d\n", tid); | 349 | " tid %d\n", tid); |
309 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | 350 | #endif /* CONFIG_MAC80211_HT_DEBUG */ |
310 | *state = HT_AGG_STATE_IDLE; | 351 | *state = HT_AGG_STATE_IDLE; |
311 | goto err_unlock_queue; | 352 | goto err_free; |
312 | } | 353 | } |
354 | sta->tid_to_tx_q[tid] = qn; | ||
313 | 355 | ||
314 | /* Will put all the packets in the new SW queue */ | ||
315 | if (hw->ampdu_queues) | ||
316 | ieee80211_requeue(local, ieee802_1d_to_ac[tid]); | ||
317 | spin_unlock_bh(&sta->lock); | 356 | spin_unlock_bh(&sta->lock); |
318 | 357 | ||
319 | /* send an addBA request */ | 358 | /* send an addBA request */ |
@@ -322,7 +361,6 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) | |||
322 | sta->ampdu_mlme.dialog_token_allocator; | 361 | sta->ampdu_mlme.dialog_token_allocator; |
323 | sta->ampdu_mlme.tid_tx[tid]->ssn = start_seq_num; | 362 | sta->ampdu_mlme.tid_tx[tid]->ssn = start_seq_num; |
324 | 363 | ||
325 | |||
326 | ieee80211_send_addba_request(sta->sdata, ra, tid, | 364 | ieee80211_send_addba_request(sta->sdata, ra, tid, |
327 | sta->ampdu_mlme.tid_tx[tid]->dialog_token, | 365 | sta->ampdu_mlme.tid_tx[tid]->dialog_token, |
328 | sta->ampdu_mlme.tid_tx[tid]->ssn, | 366 | sta->ampdu_mlme.tid_tx[tid]->ssn, |
@@ -334,15 +372,24 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) | |||
334 | #ifdef CONFIG_MAC80211_HT_DEBUG | 372 | #ifdef CONFIG_MAC80211_HT_DEBUG |
335 | printk(KERN_DEBUG "activated addBA response timer on tid %d\n", tid); | 373 | printk(KERN_DEBUG "activated addBA response timer on tid %d\n", tid); |
336 | #endif | 374 | #endif |
337 | goto exit; | 375 | goto unlock; |
338 | 376 | ||
339 | err_unlock_queue: | 377 | err_free: |
340 | kfree(sta->ampdu_mlme.tid_tx[tid]); | 378 | kfree(sta->ampdu_mlme.tid_tx[tid]); |
341 | sta->ampdu_mlme.tid_tx[tid] = NULL; | 379 | sta->ampdu_mlme.tid_tx[tid] = NULL; |
342 | ret = -EBUSY; | 380 | err_return_queue: |
343 | err_unlock_sta: | 381 | if (qn >= 0) { |
382 | /* We failed, so start queue again right away. */ | ||
383 | ieee80211_wake_queue_by_reason(hw, hw->queues + qn, | ||
384 | IEEE80211_QUEUE_STOP_REASON_AGGREGATION); | ||
385 | /* give queue back to pool */ | ||
386 | spin_lock(&local->queue_stop_reason_lock); | ||
387 | local->ampdu_ac_queue[qn] = -1; | ||
388 | spin_unlock(&local->queue_stop_reason_lock); | ||
389 | } | ||
390 | err_unlock_sta: | ||
344 | spin_unlock_bh(&sta->lock); | 391 | spin_unlock_bh(&sta->lock); |
345 | exit: | 392 | unlock: |
346 | rcu_read_unlock(); | 393 | rcu_read_unlock(); |
347 | return ret; | 394 | return ret; |
348 | } | 395 | } |
@@ -375,7 +422,7 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid) | |||
375 | state = &sta->ampdu_mlme.tid_state_tx[tid]; | 422 | state = &sta->ampdu_mlme.tid_state_tx[tid]; |
376 | spin_lock_bh(&sta->lock); | 423 | spin_lock_bh(&sta->lock); |
377 | 424 | ||
378 | if (!(*state & HT_ADDBA_REQUESTED_MSK)) { | 425 | if (WARN_ON(!(*state & HT_ADDBA_REQUESTED_MSK))) { |
379 | #ifdef CONFIG_MAC80211_HT_DEBUG | 426 | #ifdef CONFIG_MAC80211_HT_DEBUG |
380 | printk(KERN_DEBUG "addBA was not requested yet, state is %d\n", | 427 | printk(KERN_DEBUG "addBA was not requested yet, state is %d\n", |
381 | *state); | 428 | *state); |
@@ -385,7 +432,8 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid) | |||
385 | return; | 432 | return; |
386 | } | 433 | } |
387 | 434 | ||
388 | WARN_ON_ONCE(*state & HT_ADDBA_DRV_READY_MSK); | 435 | if (WARN_ON(*state & HT_ADDBA_DRV_READY_MSK)) |
436 | goto out; | ||
389 | 437 | ||
390 | *state |= HT_ADDBA_DRV_READY_MSK; | 438 | *state |= HT_ADDBA_DRV_READY_MSK; |
391 | 439 | ||
@@ -393,9 +441,18 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid) | |||
393 | #ifdef CONFIG_MAC80211_HT_DEBUG | 441 | #ifdef CONFIG_MAC80211_HT_DEBUG |
394 | printk(KERN_DEBUG "Aggregation is on for tid %d \n", tid); | 442 | printk(KERN_DEBUG "Aggregation is on for tid %d \n", tid); |
395 | #endif | 443 | #endif |
396 | if (hw->ampdu_queues) | 444 | if (hw->ampdu_queues) { |
397 | ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]); | 445 | /* |
446 | * Wake up this queue, we stopped it earlier, | ||
447 | * this will in turn wake the entire AC. | ||
448 | */ | ||
449 | ieee80211_wake_queue_by_reason(hw, | ||
450 | hw->queues + sta->tid_to_tx_q[tid], | ||
451 | IEEE80211_QUEUE_STOP_REASON_AGGREGATION); | ||
452 | } | ||
398 | } | 453 | } |
454 | |||
455 | out: | ||
399 | spin_unlock_bh(&sta->lock); | 456 | spin_unlock_bh(&sta->lock); |
400 | rcu_read_unlock(); | 457 | rcu_read_unlock(); |
401 | } | 458 | } |
@@ -485,7 +542,6 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid) | |||
485 | struct ieee80211_local *local = hw_to_local(hw); | 542 | struct ieee80211_local *local = hw_to_local(hw); |
486 | struct sta_info *sta; | 543 | struct sta_info *sta; |
487 | u8 *state; | 544 | u8 *state; |
488 | int agg_queue; | ||
489 | 545 | ||
490 | if (tid >= STA_TID_NUM) { | 546 | if (tid >= STA_TID_NUM) { |
491 | #ifdef CONFIG_MAC80211_HT_DEBUG | 547 | #ifdef CONFIG_MAC80211_HT_DEBUG |
@@ -527,19 +583,19 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid) | |||
527 | ieee80211_send_delba(sta->sdata, ra, tid, | 583 | ieee80211_send_delba(sta->sdata, ra, tid, |
528 | WLAN_BACK_INITIATOR, WLAN_REASON_QSTA_NOT_USE); | 584 | WLAN_BACK_INITIATOR, WLAN_REASON_QSTA_NOT_USE); |
529 | 585 | ||
530 | if (hw->ampdu_queues) { | 586 | spin_lock_bh(&sta->lock); |
531 | agg_queue = sta->tid_to_tx_q[tid]; | ||
532 | ieee80211_ht_agg_queue_remove(local, sta, tid, 1); | ||
533 | 587 | ||
534 | /* We just requeued the all the frames that were in the | 588 | if (*state & HT_AGG_STATE_INITIATOR_MSK && |
535 | * removed queue, and since we might miss a softirq we do | 589 | hw->ampdu_queues) { |
536 | * netif_schedule_queue. ieee80211_wake_queue is not used | 590 | /* |
537 | * here as this queue is not necessarily stopped | 591 | * Wake up this queue, we stopped it earlier, |
592 | * this will in turn wake the entire AC. | ||
538 | */ | 593 | */ |
539 | netif_schedule_queue(netdev_get_tx_queue(local->mdev, | 594 | ieee80211_wake_queue_by_reason(hw, |
540 | agg_queue)); | 595 | hw->queues + sta->tid_to_tx_q[tid], |
596 | IEEE80211_QUEUE_STOP_REASON_AGGREGATION); | ||
541 | } | 597 | } |
542 | spin_lock_bh(&sta->lock); | 598 | |
543 | *state = HT_AGG_STATE_IDLE; | 599 | *state = HT_AGG_STATE_IDLE; |
544 | sta->ampdu_mlme.addba_req_num[tid] = 0; | 600 | sta->ampdu_mlme.addba_req_num[tid] = 0; |
545 | kfree(sta->ampdu_mlme.tid_tx[tid]); | 601 | kfree(sta->ampdu_mlme.tid_tx[tid]); |
@@ -613,12 +669,21 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local, | |||
613 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | 669 | #endif /* CONFIG_MAC80211_HT_DEBUG */ |
614 | if (le16_to_cpu(mgmt->u.action.u.addba_resp.status) | 670 | if (le16_to_cpu(mgmt->u.action.u.addba_resp.status) |
615 | == WLAN_STATUS_SUCCESS) { | 671 | == WLAN_STATUS_SUCCESS) { |
672 | u8 curstate = *state; | ||
673 | |||
616 | *state |= HT_ADDBA_RECEIVED_MSK; | 674 | *state |= HT_ADDBA_RECEIVED_MSK; |
617 | sta->ampdu_mlme.addba_req_num[tid] = 0; | ||
618 | 675 | ||
619 | if (*state == HT_AGG_STATE_OPERATIONAL && | 676 | if (hw->ampdu_queues && *state != curstate && |
620 | local->hw.ampdu_queues) | 677 | *state == HT_AGG_STATE_OPERATIONAL) { |
621 | ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]); | 678 | /* |
679 | * Wake up this queue, we stopped it earlier, | ||
680 | * this will in turn wake the entire AC. | ||
681 | */ | ||
682 | ieee80211_wake_queue_by_reason(hw, | ||
683 | hw->queues + sta->tid_to_tx_q[tid], | ||
684 | IEEE80211_QUEUE_STOP_REASON_AGGREGATION); | ||
685 | } | ||
686 | sta->ampdu_mlme.addba_req_num[tid] = 0; | ||
622 | 687 | ||
623 | if (local->ops->ampdu_action) { | 688 | if (local->ops->ampdu_action) { |
624 | (void)local->ops->ampdu_action(hw, | 689 | (void)local->ops->ampdu_action(hw, |
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index c8d969be440b..c43129efc3bf 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -341,11 +341,15 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) | |||
341 | sinfo->filled = STATION_INFO_INACTIVE_TIME | | 341 | sinfo->filled = STATION_INFO_INACTIVE_TIME | |
342 | STATION_INFO_RX_BYTES | | 342 | STATION_INFO_RX_BYTES | |
343 | STATION_INFO_TX_BYTES | | 343 | STATION_INFO_TX_BYTES | |
344 | STATION_INFO_RX_PACKETS | | ||
345 | STATION_INFO_TX_PACKETS | | ||
344 | STATION_INFO_TX_BITRATE; | 346 | STATION_INFO_TX_BITRATE; |
345 | 347 | ||
346 | sinfo->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx); | 348 | sinfo->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx); |
347 | sinfo->rx_bytes = sta->rx_bytes; | 349 | sinfo->rx_bytes = sta->rx_bytes; |
348 | sinfo->tx_bytes = sta->tx_bytes; | 350 | sinfo->tx_bytes = sta->tx_bytes; |
351 | sinfo->rx_packets = sta->rx_packets; | ||
352 | sinfo->tx_packets = sta->tx_packets; | ||
349 | 353 | ||
350 | if (sta->local->hw.flags & IEEE80211_HW_SIGNAL_DBM) { | 354 | if (sta->local->hw.flags & IEEE80211_HW_SIGNAL_DBM) { |
351 | sinfo->filled |= STATION_INFO_SIGNAL; | 355 | sinfo->filled |= STATION_INFO_SIGNAL; |
@@ -1180,45 +1184,45 @@ static int set_mgmt_extra_ie_sta(struct ieee80211_sub_if_data *sdata, | |||
1180 | u8 subtype, u8 *ies, size_t ies_len) | 1184 | u8 subtype, u8 *ies, size_t ies_len) |
1181 | { | 1185 | { |
1182 | struct ieee80211_local *local = sdata->local; | 1186 | struct ieee80211_local *local = sdata->local; |
1183 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | 1187 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
1184 | 1188 | ||
1185 | switch (subtype) { | 1189 | switch (subtype) { |
1186 | case IEEE80211_STYPE_PROBE_REQ >> 4: | 1190 | case IEEE80211_STYPE_PROBE_REQ >> 4: |
1187 | if (local->ops->hw_scan) | 1191 | if (local->ops->hw_scan) |
1188 | break; | 1192 | break; |
1189 | kfree(ifsta->ie_probereq); | 1193 | kfree(ifmgd->ie_probereq); |
1190 | ifsta->ie_probereq = ies; | 1194 | ifmgd->ie_probereq = ies; |
1191 | ifsta->ie_probereq_len = ies_len; | 1195 | ifmgd->ie_probereq_len = ies_len; |
1192 | return 0; | 1196 | return 0; |
1193 | case IEEE80211_STYPE_PROBE_RESP >> 4: | 1197 | case IEEE80211_STYPE_PROBE_RESP >> 4: |
1194 | kfree(ifsta->ie_proberesp); | 1198 | kfree(ifmgd->ie_proberesp); |
1195 | ifsta->ie_proberesp = ies; | 1199 | ifmgd->ie_proberesp = ies; |
1196 | ifsta->ie_proberesp_len = ies_len; | 1200 | ifmgd->ie_proberesp_len = ies_len; |
1197 | return 0; | 1201 | return 0; |
1198 | case IEEE80211_STYPE_AUTH >> 4: | 1202 | case IEEE80211_STYPE_AUTH >> 4: |
1199 | kfree(ifsta->ie_auth); | 1203 | kfree(ifmgd->ie_auth); |
1200 | ifsta->ie_auth = ies; | 1204 | ifmgd->ie_auth = ies; |
1201 | ifsta->ie_auth_len = ies_len; | 1205 | ifmgd->ie_auth_len = ies_len; |
1202 | return 0; | 1206 | return 0; |
1203 | case IEEE80211_STYPE_ASSOC_REQ >> 4: | 1207 | case IEEE80211_STYPE_ASSOC_REQ >> 4: |
1204 | kfree(ifsta->ie_assocreq); | 1208 | kfree(ifmgd->ie_assocreq); |
1205 | ifsta->ie_assocreq = ies; | 1209 | ifmgd->ie_assocreq = ies; |
1206 | ifsta->ie_assocreq_len = ies_len; | 1210 | ifmgd->ie_assocreq_len = ies_len; |
1207 | return 0; | 1211 | return 0; |
1208 | case IEEE80211_STYPE_REASSOC_REQ >> 4: | 1212 | case IEEE80211_STYPE_REASSOC_REQ >> 4: |
1209 | kfree(ifsta->ie_reassocreq); | 1213 | kfree(ifmgd->ie_reassocreq); |
1210 | ifsta->ie_reassocreq = ies; | 1214 | ifmgd->ie_reassocreq = ies; |
1211 | ifsta->ie_reassocreq_len = ies_len; | 1215 | ifmgd->ie_reassocreq_len = ies_len; |
1212 | return 0; | 1216 | return 0; |
1213 | case IEEE80211_STYPE_DEAUTH >> 4: | 1217 | case IEEE80211_STYPE_DEAUTH >> 4: |
1214 | kfree(ifsta->ie_deauth); | 1218 | kfree(ifmgd->ie_deauth); |
1215 | ifsta->ie_deauth = ies; | 1219 | ifmgd->ie_deauth = ies; |
1216 | ifsta->ie_deauth_len = ies_len; | 1220 | ifmgd->ie_deauth_len = ies_len; |
1217 | return 0; | 1221 | return 0; |
1218 | case IEEE80211_STYPE_DISASSOC >> 4: | 1222 | case IEEE80211_STYPE_DISASSOC >> 4: |
1219 | kfree(ifsta->ie_disassoc); | 1223 | kfree(ifmgd->ie_disassoc); |
1220 | ifsta->ie_disassoc = ies; | 1224 | ifmgd->ie_disassoc = ies; |
1221 | ifsta->ie_disassoc_len = ies_len; | 1225 | ifmgd->ie_disassoc_len = ies_len; |
1222 | return 0; | 1226 | return 0; |
1223 | } | 1227 | } |
1224 | 1228 | ||
@@ -1248,7 +1252,6 @@ static int ieee80211_set_mgmt_extra_ie(struct wiphy *wiphy, | |||
1248 | 1252 | ||
1249 | switch (sdata->vif.type) { | 1253 | switch (sdata->vif.type) { |
1250 | case NL80211_IFTYPE_STATION: | 1254 | case NL80211_IFTYPE_STATION: |
1251 | case NL80211_IFTYPE_ADHOC: | ||
1252 | ret = set_mgmt_extra_ie_sta(sdata, params->subtype, | 1255 | ret = set_mgmt_extra_ie_sta(sdata, params->subtype, |
1253 | ies, ies_len); | 1256 | ies, ies_len); |
1254 | break; | 1257 | break; |
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index c54219301724..e3420329f4e6 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c | |||
@@ -94,31 +94,31 @@ IEEE80211_IF_FILE(drop_unencrypted, drop_unencrypted, DEC); | |||
94 | IEEE80211_IF_FILE(force_unicast_rateidx, force_unicast_rateidx, DEC); | 94 | IEEE80211_IF_FILE(force_unicast_rateidx, force_unicast_rateidx, DEC); |
95 | IEEE80211_IF_FILE(max_ratectrl_rateidx, max_ratectrl_rateidx, DEC); | 95 | IEEE80211_IF_FILE(max_ratectrl_rateidx, max_ratectrl_rateidx, DEC); |
96 | 96 | ||
97 | /* STA/IBSS attributes */ | 97 | /* STA attributes */ |
98 | IEEE80211_IF_FILE(state, u.sta.state, DEC); | 98 | IEEE80211_IF_FILE(state, u.mgd.state, DEC); |
99 | IEEE80211_IF_FILE(bssid, u.sta.bssid, MAC); | 99 | IEEE80211_IF_FILE(bssid, u.mgd.bssid, MAC); |
100 | IEEE80211_IF_FILE(prev_bssid, u.sta.prev_bssid, MAC); | 100 | IEEE80211_IF_FILE(prev_bssid, u.mgd.prev_bssid, MAC); |
101 | IEEE80211_IF_FILE(ssid_len, u.sta.ssid_len, SIZE); | 101 | IEEE80211_IF_FILE(ssid_len, u.mgd.ssid_len, SIZE); |
102 | IEEE80211_IF_FILE(aid, u.sta.aid, DEC); | 102 | IEEE80211_IF_FILE(aid, u.mgd.aid, DEC); |
103 | IEEE80211_IF_FILE(ap_capab, u.sta.ap_capab, HEX); | 103 | IEEE80211_IF_FILE(ap_capab, u.mgd.ap_capab, HEX); |
104 | IEEE80211_IF_FILE(capab, u.sta.capab, HEX); | 104 | IEEE80211_IF_FILE(capab, u.mgd.capab, HEX); |
105 | IEEE80211_IF_FILE(extra_ie_len, u.sta.extra_ie_len, SIZE); | 105 | IEEE80211_IF_FILE(extra_ie_len, u.mgd.extra_ie_len, SIZE); |
106 | IEEE80211_IF_FILE(auth_tries, u.sta.auth_tries, DEC); | 106 | IEEE80211_IF_FILE(auth_tries, u.mgd.auth_tries, DEC); |
107 | IEEE80211_IF_FILE(assoc_tries, u.sta.assoc_tries, DEC); | 107 | IEEE80211_IF_FILE(assoc_tries, u.mgd.assoc_tries, DEC); |
108 | IEEE80211_IF_FILE(auth_algs, u.sta.auth_algs, HEX); | 108 | IEEE80211_IF_FILE(auth_algs, u.mgd.auth_algs, HEX); |
109 | IEEE80211_IF_FILE(auth_alg, u.sta.auth_alg, DEC); | 109 | IEEE80211_IF_FILE(auth_alg, u.mgd.auth_alg, DEC); |
110 | IEEE80211_IF_FILE(auth_transaction, u.sta.auth_transaction, DEC); | 110 | IEEE80211_IF_FILE(auth_transaction, u.mgd.auth_transaction, DEC); |
111 | 111 | ||
112 | static ssize_t ieee80211_if_fmt_flags( | 112 | static ssize_t ieee80211_if_fmt_flags( |
113 | const struct ieee80211_sub_if_data *sdata, char *buf, int buflen) | 113 | const struct ieee80211_sub_if_data *sdata, char *buf, int buflen) |
114 | { | 114 | { |
115 | return scnprintf(buf, buflen, "%s%s%s%s%s%s%s\n", | 115 | return scnprintf(buf, buflen, "%s%s%s%s%s%s%s\n", |
116 | sdata->u.sta.flags & IEEE80211_STA_SSID_SET ? "SSID\n" : "", | 116 | sdata->u.mgd.flags & IEEE80211_STA_SSID_SET ? "SSID\n" : "", |
117 | sdata->u.sta.flags & IEEE80211_STA_BSSID_SET ? "BSSID\n" : "", | 117 | sdata->u.mgd.flags & IEEE80211_STA_BSSID_SET ? "BSSID\n" : "", |
118 | sdata->u.sta.flags & IEEE80211_STA_PREV_BSSID_SET ? "prev BSSID\n" : "", | 118 | sdata->u.mgd.flags & IEEE80211_STA_PREV_BSSID_SET ? "prev BSSID\n" : "", |
119 | sdata->u.sta.flags & IEEE80211_STA_AUTHENTICATED ? "AUTH\n" : "", | 119 | sdata->u.mgd.flags & IEEE80211_STA_AUTHENTICATED ? "AUTH\n" : "", |
120 | sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED ? "ASSOC\n" : "", | 120 | sdata->u.mgd.flags & IEEE80211_STA_ASSOCIATED ? "ASSOC\n" : "", |
121 | sdata->u.sta.flags & IEEE80211_STA_PROBEREQ_POLL ? "PROBEREQ POLL\n" : "", | 121 | sdata->u.mgd.flags & IEEE80211_STA_PROBEREQ_POLL ? "PROBEREQ POLL\n" : "", |
122 | sdata->vif.bss_conf.use_cts_prot ? "CTS prot\n" : ""); | 122 | sdata->vif.bss_conf.use_cts_prot ? "CTS prot\n" : ""); |
123 | } | 123 | } |
124 | __IEEE80211_IF_FILE(flags); | 124 | __IEEE80211_IF_FILE(flags); |
@@ -283,9 +283,11 @@ static void add_files(struct ieee80211_sub_if_data *sdata) | |||
283 | #endif | 283 | #endif |
284 | break; | 284 | break; |
285 | case NL80211_IFTYPE_STATION: | 285 | case NL80211_IFTYPE_STATION: |
286 | case NL80211_IFTYPE_ADHOC: | ||
287 | add_sta_files(sdata); | 286 | add_sta_files(sdata); |
288 | break; | 287 | break; |
288 | case NL80211_IFTYPE_ADHOC: | ||
289 | /* XXX */ | ||
290 | break; | ||
289 | case NL80211_IFTYPE_AP: | 291 | case NL80211_IFTYPE_AP: |
290 | add_ap_files(sdata); | 292 | add_ap_files(sdata); |
291 | break; | 293 | break; |
@@ -418,9 +420,11 @@ static void del_files(struct ieee80211_sub_if_data *sdata) | |||
418 | #endif | 420 | #endif |
419 | break; | 421 | break; |
420 | case NL80211_IFTYPE_STATION: | 422 | case NL80211_IFTYPE_STATION: |
421 | case NL80211_IFTYPE_ADHOC: | ||
422 | del_sta_files(sdata); | 423 | del_sta_files(sdata); |
423 | break; | 424 | break; |
425 | case NL80211_IFTYPE_ADHOC: | ||
426 | /* XXX */ | ||
427 | break; | ||
424 | case NL80211_IFTYPE_AP: | 428 | case NL80211_IFTYPE_AP: |
425 | del_ap_files(sdata); | 429 | del_ap_files(sdata); |
426 | break; | 430 | break; |
diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c index 82ea0b63a386..4e3c72f20de7 100644 --- a/net/mac80211/ht.c +++ b/net/mac80211/ht.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <net/wireless.h> | 17 | #include <net/wireless.h> |
18 | #include <net/mac80211.h> | 18 | #include <net/mac80211.h> |
19 | #include "ieee80211_i.h" | 19 | #include "ieee80211_i.h" |
20 | #include "rate.h" | ||
20 | 21 | ||
21 | void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_supported_band *sband, | 22 | void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_supported_band *sband, |
22 | struct ieee80211_ht_cap *ht_cap_ie, | 23 | struct ieee80211_ht_cap *ht_cap_ie, |
@@ -93,7 +94,9 @@ u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata, | |||
93 | { | 94 | { |
94 | struct ieee80211_local *local = sdata->local; | 95 | struct ieee80211_local *local = sdata->local; |
95 | struct ieee80211_supported_band *sband; | 96 | struct ieee80211_supported_band *sband; |
97 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
96 | struct ieee80211_bss_ht_conf ht; | 98 | struct ieee80211_bss_ht_conf ht; |
99 | struct sta_info *sta; | ||
97 | u32 changed = 0; | 100 | u32 changed = 0; |
98 | bool enable_ht = true, ht_changed; | 101 | bool enable_ht = true, ht_changed; |
99 | enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; | 102 | enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; |
@@ -136,6 +139,16 @@ u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata, | |||
136 | if (ht_changed) { | 139 | if (ht_changed) { |
137 | /* channel_type change automatically detected */ | 140 | /* channel_type change automatically detected */ |
138 | ieee80211_hw_config(local, 0); | 141 | ieee80211_hw_config(local, 0); |
142 | |||
143 | rcu_read_lock(); | ||
144 | |||
145 | sta = sta_info_get(local, ifmgd->bssid); | ||
146 | if (sta) | ||
147 | rate_control_rate_update(local, sband, sta, | ||
148 | IEEE80211_RC_HT_CHANGED); | ||
149 | |||
150 | rcu_read_unlock(); | ||
151 | |||
139 | } | 152 | } |
140 | 153 | ||
141 | /* disable HT */ | 154 | /* disable HT */ |
@@ -169,7 +182,6 @@ void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata, | |||
169 | u16 initiator, u16 reason_code) | 182 | u16 initiator, u16 reason_code) |
170 | { | 183 | { |
171 | struct ieee80211_local *local = sdata->local; | 184 | struct ieee80211_local *local = sdata->local; |
172 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | ||
173 | struct sk_buff *skb; | 185 | struct sk_buff *skb; |
174 | struct ieee80211_mgmt *mgmt; | 186 | struct ieee80211_mgmt *mgmt; |
175 | u16 params; | 187 | u16 params; |
@@ -190,8 +202,9 @@ void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata, | |||
190 | if (sdata->vif.type == NL80211_IFTYPE_AP || | 202 | if (sdata->vif.type == NL80211_IFTYPE_AP || |
191 | sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | 203 | sdata->vif.type == NL80211_IFTYPE_AP_VLAN) |
192 | memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN); | 204 | memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN); |
193 | else | 205 | else if (sdata->vif.type == NL80211_IFTYPE_STATION) |
194 | memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); | 206 | memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN); |
207 | |||
195 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | 208 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | |
196 | IEEE80211_STYPE_ACTION); | 209 | IEEE80211_STYPE_ACTION); |
197 | 210 | ||
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c new file mode 100644 index 000000000000..a96ce9dfc6b5 --- /dev/null +++ b/net/mac80211/ibss.c | |||
@@ -0,0 +1,905 @@ | |||
1 | /* | ||
2 | * IBSS mode implementation | ||
3 | * Copyright 2003-2008, Jouni Malinen <j@w1.fi> | ||
4 | * Copyright 2004, Instant802 Networks, Inc. | ||
5 | * Copyright 2005, Devicescape Software, Inc. | ||
6 | * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> | ||
7 | * Copyright 2007, Michael Wu <flamingice@sourmilk.net> | ||
8 | * Copyright 2009, Johannes Berg <johannes@sipsolutions.net> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License version 2 as | ||
12 | * published by the Free Software Foundation. | ||
13 | */ | ||
14 | |||
15 | #include <linux/delay.h> | ||
16 | #include <linux/if_ether.h> | ||
17 | #include <linux/skbuff.h> | ||
18 | #include <linux/if_arp.h> | ||
19 | #include <linux/etherdevice.h> | ||
20 | #include <linux/rtnetlink.h> | ||
21 | #include <net/mac80211.h> | ||
22 | #include <asm/unaligned.h> | ||
23 | |||
24 | #include "ieee80211_i.h" | ||
25 | #include "rate.h" | ||
26 | |||
27 | #define IEEE80211_SCAN_INTERVAL (2 * HZ) | ||
28 | #define IEEE80211_SCAN_INTERVAL_SLOW (15 * HZ) | ||
29 | #define IEEE80211_IBSS_JOIN_TIMEOUT (7 * HZ) | ||
30 | |||
31 | #define IEEE80211_IBSS_MERGE_INTERVAL (30 * HZ) | ||
32 | #define IEEE80211_IBSS_MERGE_DELAY 0x400000 | ||
33 | #define IEEE80211_IBSS_INACTIVITY_LIMIT (60 * HZ) | ||
34 | |||
35 | #define IEEE80211_IBSS_MAX_STA_ENTRIES 128 | ||
36 | |||
37 | |||
38 | static void ieee80211_rx_mgmt_auth_ibss(struct ieee80211_sub_if_data *sdata, | ||
39 | struct ieee80211_mgmt *mgmt, | ||
40 | size_t len) | ||
41 | { | ||
42 | u16 auth_alg, auth_transaction, status_code; | ||
43 | |||
44 | if (len < 24 + 6) | ||
45 | return; | ||
46 | |||
47 | auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg); | ||
48 | auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction); | ||
49 | status_code = le16_to_cpu(mgmt->u.auth.status_code); | ||
50 | |||
51 | /* | ||
52 | * IEEE 802.11 standard does not require authentication in IBSS | ||
53 | * networks and most implementations do not seem to use it. | ||
54 | * However, try to reply to authentication attempts if someone | ||
55 | * has actually implemented this. | ||
56 | */ | ||
57 | if (auth_alg == WLAN_AUTH_OPEN && auth_transaction == 1) | ||
58 | ieee80211_send_auth(sdata, 2, WLAN_AUTH_OPEN, NULL, 0, | ||
59 | sdata->u.ibss.bssid, 0); | ||
60 | } | ||
61 | |||
62 | static int __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | ||
63 | const u8 *bssid, const int beacon_int, | ||
64 | const int freq, | ||
65 | const size_t supp_rates_len, | ||
66 | const u8 *supp_rates, | ||
67 | const u16 capability) | ||
68 | { | ||
69 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | ||
70 | struct ieee80211_local *local = sdata->local; | ||
71 | int res = 0, rates, i, j; | ||
72 | struct sk_buff *skb; | ||
73 | struct ieee80211_mgmt *mgmt; | ||
74 | u8 *pos; | ||
75 | struct ieee80211_supported_band *sband; | ||
76 | union iwreq_data wrqu; | ||
77 | |||
78 | if (local->ops->reset_tsf) { | ||
79 | /* Reset own TSF to allow time synchronization work. */ | ||
80 | local->ops->reset_tsf(local_to_hw(local)); | ||
81 | } | ||
82 | |||
83 | if ((ifibss->flags & IEEE80211_IBSS_PREV_BSSID_SET) && | ||
84 | memcmp(ifibss->bssid, bssid, ETH_ALEN) == 0) | ||
85 | return res; | ||
86 | |||
87 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400); | ||
88 | if (!skb) { | ||
89 | printk(KERN_DEBUG "%s: failed to allocate buffer for probe " | ||
90 | "response\n", sdata->dev->name); | ||
91 | return -ENOMEM; | ||
92 | } | ||
93 | |||
94 | if (!(ifibss->flags & IEEE80211_IBSS_PREV_BSSID_SET)) { | ||
95 | /* Remove possible STA entries from other IBSS networks. */ | ||
96 | sta_info_flush_delayed(sdata); | ||
97 | } | ||
98 | |||
99 | memcpy(ifibss->bssid, bssid, ETH_ALEN); | ||
100 | res = ieee80211_if_config(sdata, IEEE80211_IFCC_BSSID); | ||
101 | if (res) | ||
102 | return res; | ||
103 | |||
104 | local->hw.conf.beacon_int = beacon_int >= 10 ? beacon_int : 10; | ||
105 | |||
106 | sdata->drop_unencrypted = capability & | ||
107 | WLAN_CAPABILITY_PRIVACY ? 1 : 0; | ||
108 | |||
109 | res = ieee80211_set_freq(sdata, freq); | ||
110 | |||
111 | if (res) | ||
112 | return res; | ||
113 | |||
114 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | ||
115 | |||
116 | /* Build IBSS probe response */ | ||
117 | |||
118 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
119 | |||
120 | mgmt = (struct ieee80211_mgmt *) | ||
121 | skb_put(skb, 24 + sizeof(mgmt->u.beacon)); | ||
122 | memset(mgmt, 0, 24 + sizeof(mgmt->u.beacon)); | ||
123 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
124 | IEEE80211_STYPE_PROBE_RESP); | ||
125 | memset(mgmt->da, 0xff, ETH_ALEN); | ||
126 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | ||
127 | memcpy(mgmt->bssid, ifibss->bssid, ETH_ALEN); | ||
128 | mgmt->u.beacon.beacon_int = | ||
129 | cpu_to_le16(local->hw.conf.beacon_int); | ||
130 | mgmt->u.beacon.capab_info = cpu_to_le16(capability); | ||
131 | |||
132 | pos = skb_put(skb, 2 + ifibss->ssid_len); | ||
133 | *pos++ = WLAN_EID_SSID; | ||
134 | *pos++ = ifibss->ssid_len; | ||
135 | memcpy(pos, ifibss->ssid, ifibss->ssid_len); | ||
136 | |||
137 | rates = supp_rates_len; | ||
138 | if (rates > 8) | ||
139 | rates = 8; | ||
140 | pos = skb_put(skb, 2 + rates); | ||
141 | *pos++ = WLAN_EID_SUPP_RATES; | ||
142 | *pos++ = rates; | ||
143 | memcpy(pos, supp_rates, rates); | ||
144 | |||
145 | if (sband->band == IEEE80211_BAND_2GHZ) { | ||
146 | pos = skb_put(skb, 2 + 1); | ||
147 | *pos++ = WLAN_EID_DS_PARAMS; | ||
148 | *pos++ = 1; | ||
149 | *pos++ = ieee80211_frequency_to_channel(freq); | ||
150 | } | ||
151 | |||
152 | pos = skb_put(skb, 2 + 2); | ||
153 | *pos++ = WLAN_EID_IBSS_PARAMS; | ||
154 | *pos++ = 2; | ||
155 | /* FIX: set ATIM window based on scan results */ | ||
156 | *pos++ = 0; | ||
157 | *pos++ = 0; | ||
158 | |||
159 | if (supp_rates_len > 8) { | ||
160 | rates = supp_rates_len - 8; | ||
161 | pos = skb_put(skb, 2 + rates); | ||
162 | *pos++ = WLAN_EID_EXT_SUPP_RATES; | ||
163 | *pos++ = rates; | ||
164 | memcpy(pos, &supp_rates[8], rates); | ||
165 | } | ||
166 | |||
167 | ifibss->probe_resp = skb; | ||
168 | |||
169 | ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON | | ||
170 | IEEE80211_IFCC_BEACON_ENABLED); | ||
171 | |||
172 | |||
173 | rates = 0; | ||
174 | for (i = 0; i < supp_rates_len; i++) { | ||
175 | int bitrate = (supp_rates[i] & 0x7f) * 5; | ||
176 | for (j = 0; j < sband->n_bitrates; j++) | ||
177 | if (sband->bitrates[j].bitrate == bitrate) | ||
178 | rates |= BIT(j); | ||
179 | } | ||
180 | |||
181 | ieee80211_sta_def_wmm_params(sdata, supp_rates_len, supp_rates); | ||
182 | |||
183 | ifibss->flags |= IEEE80211_IBSS_PREV_BSSID_SET; | ||
184 | ifibss->state = IEEE80211_IBSS_MLME_JOINED; | ||
185 | mod_timer(&ifibss->timer, jiffies + IEEE80211_IBSS_MERGE_INTERVAL); | ||
186 | |||
187 | memset(&wrqu, 0, sizeof(wrqu)); | ||
188 | memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN); | ||
189 | wireless_send_event(sdata->dev, SIOCGIWAP, &wrqu, NULL); | ||
190 | |||
191 | return res; | ||
192 | } | ||
193 | |||
194 | static int ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | ||
195 | struct ieee80211_bss *bss) | ||
196 | { | ||
197 | return __ieee80211_sta_join_ibss(sdata, | ||
198 | bss->cbss.bssid, | ||
199 | bss->cbss.beacon_interval, | ||
200 | bss->cbss.channel->center_freq, | ||
201 | bss->supp_rates_len, bss->supp_rates, | ||
202 | bss->cbss.capability); | ||
203 | } | ||
204 | |||
205 | static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | ||
206 | struct ieee80211_mgmt *mgmt, | ||
207 | size_t len, | ||
208 | struct ieee80211_rx_status *rx_status, | ||
209 | struct ieee802_11_elems *elems, | ||
210 | bool beacon) | ||
211 | { | ||
212 | struct ieee80211_local *local = sdata->local; | ||
213 | int freq; | ||
214 | struct ieee80211_bss *bss; | ||
215 | struct sta_info *sta; | ||
216 | struct ieee80211_channel *channel; | ||
217 | u64 beacon_timestamp, rx_timestamp; | ||
218 | u32 supp_rates = 0; | ||
219 | enum ieee80211_band band = rx_status->band; | ||
220 | |||
221 | if (elems->ds_params && elems->ds_params_len == 1) | ||
222 | freq = ieee80211_channel_to_frequency(elems->ds_params[0]); | ||
223 | else | ||
224 | freq = rx_status->freq; | ||
225 | |||
226 | channel = ieee80211_get_channel(local->hw.wiphy, freq); | ||
227 | |||
228 | if (!channel || channel->flags & IEEE80211_CHAN_DISABLED) | ||
229 | return; | ||
230 | |||
231 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC && elems->supp_rates && | ||
232 | memcmp(mgmt->bssid, sdata->u.ibss.bssid, ETH_ALEN) == 0) { | ||
233 | supp_rates = ieee80211_sta_get_rates(local, elems, band); | ||
234 | |||
235 | rcu_read_lock(); | ||
236 | |||
237 | sta = sta_info_get(local, mgmt->sa); | ||
238 | if (sta) { | ||
239 | u32 prev_rates; | ||
240 | |||
241 | prev_rates = sta->sta.supp_rates[band]; | ||
242 | /* make sure mandatory rates are always added */ | ||
243 | sta->sta.supp_rates[band] = supp_rates | | ||
244 | ieee80211_mandatory_rates(local, band); | ||
245 | |||
246 | #ifdef CONFIG_MAC80211_IBSS_DEBUG | ||
247 | if (sta->sta.supp_rates[band] != prev_rates) | ||
248 | printk(KERN_DEBUG "%s: updated supp_rates set " | ||
249 | "for %pM based on beacon info (0x%llx | " | ||
250 | "0x%llx -> 0x%llx)\n", | ||
251 | sdata->dev->name, | ||
252 | sta->sta.addr, | ||
253 | (unsigned long long) prev_rates, | ||
254 | (unsigned long long) supp_rates, | ||
255 | (unsigned long long) sta->sta.supp_rates[band]); | ||
256 | #endif | ||
257 | } else | ||
258 | ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, supp_rates); | ||
259 | |||
260 | rcu_read_unlock(); | ||
261 | } | ||
262 | |||
263 | bss = ieee80211_bss_info_update(local, rx_status, mgmt, len, elems, | ||
264 | channel, beacon); | ||
265 | if (!bss) | ||
266 | return; | ||
267 | |||
268 | /* was just updated in ieee80211_bss_info_update */ | ||
269 | beacon_timestamp = bss->cbss.tsf; | ||
270 | |||
271 | /* check if we need to merge IBSS */ | ||
272 | |||
273 | /* merge only on beacons (???) */ | ||
274 | if (!beacon) | ||
275 | goto put_bss; | ||
276 | |||
277 | /* we use a fixed BSSID */ | ||
278 | if (sdata->u.ibss.flags & IEEE80211_IBSS_BSSID_SET) | ||
279 | goto put_bss; | ||
280 | |||
281 | /* not an IBSS */ | ||
282 | if (!(bss->cbss.capability & WLAN_CAPABILITY_IBSS)) | ||
283 | goto put_bss; | ||
284 | |||
285 | /* different channel */ | ||
286 | if (bss->cbss.channel != local->oper_channel) | ||
287 | goto put_bss; | ||
288 | |||
289 | /* different SSID */ | ||
290 | if (elems->ssid_len != sdata->u.ibss.ssid_len || | ||
291 | memcmp(elems->ssid, sdata->u.ibss.ssid, | ||
292 | sdata->u.ibss.ssid_len)) | ||
293 | goto put_bss; | ||
294 | |||
295 | /* same BSSID */ | ||
296 | if (memcmp(bss->cbss.bssid, sdata->u.ibss.bssid, ETH_ALEN) == 0) | ||
297 | goto put_bss; | ||
298 | |||
299 | if (rx_status->flag & RX_FLAG_TSFT) { | ||
300 | /* | ||
301 | * For correct IBSS merging we need mactime; since mactime is | ||
302 | * defined as the time the first data symbol of the frame hits | ||
303 | * the PHY, and the timestamp of the beacon is defined as "the | ||
304 | * time that the data symbol containing the first bit of the | ||
305 | * timestamp is transmitted to the PHY plus the transmitting | ||
306 | * STA's delays through its local PHY from the MAC-PHY | ||
307 | * interface to its interface with the WM" (802.11 11.1.2) | ||
308 | * - equals the time this bit arrives at the receiver - we have | ||
309 | * to take into account the offset between the two. | ||
310 | * | ||
311 | * E.g. at 1 MBit that means mactime is 192 usec earlier | ||
312 | * (=24 bytes * 8 usecs/byte) than the beacon timestamp. | ||
313 | */ | ||
314 | int rate; | ||
315 | |||
316 | if (rx_status->flag & RX_FLAG_HT) | ||
317 | rate = 65; /* TODO: HT rates */ | ||
318 | else | ||
319 | rate = local->hw.wiphy->bands[band]-> | ||
320 | bitrates[rx_status->rate_idx].bitrate; | ||
321 | |||
322 | rx_timestamp = rx_status->mactime + (24 * 8 * 10 / rate); | ||
323 | } else if (local && local->ops && local->ops->get_tsf) | ||
324 | /* second best option: get current TSF */ | ||
325 | rx_timestamp = local->ops->get_tsf(local_to_hw(local)); | ||
326 | else | ||
327 | /* can't merge without knowing the TSF */ | ||
328 | rx_timestamp = -1LLU; | ||
329 | |||
330 | #ifdef CONFIG_MAC80211_IBSS_DEBUG | ||
331 | printk(KERN_DEBUG "RX beacon SA=%pM BSSID=" | ||
332 | "%pM TSF=0x%llx BCN=0x%llx diff=%lld @%lu\n", | ||
333 | mgmt->sa, mgmt->bssid, | ||
334 | (unsigned long long)rx_timestamp, | ||
335 | (unsigned long long)beacon_timestamp, | ||
336 | (unsigned long long)(rx_timestamp - beacon_timestamp), | ||
337 | jiffies); | ||
338 | #endif | ||
339 | |||
340 | /* give slow hardware some time to do the TSF sync */ | ||
341 | if (rx_timestamp < IEEE80211_IBSS_MERGE_DELAY) | ||
342 | goto put_bss; | ||
343 | |||
344 | if (beacon_timestamp > rx_timestamp) { | ||
345 | #ifdef CONFIG_MAC80211_IBSS_DEBUG | ||
346 | printk(KERN_DEBUG "%s: beacon TSF higher than " | ||
347 | "local TSF - IBSS merge with BSSID %pM\n", | ||
348 | sdata->dev->name, mgmt->bssid); | ||
349 | #endif | ||
350 | ieee80211_sta_join_ibss(sdata, bss); | ||
351 | ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, supp_rates); | ||
352 | } | ||
353 | |||
354 | put_bss: | ||
355 | ieee80211_rx_bss_put(local, bss); | ||
356 | } | ||
357 | |||
358 | /* | ||
359 | * Add a new IBSS station, will also be called by the RX code when, | ||
360 | * in IBSS mode, receiving a frame from a yet-unknown station, hence | ||
361 | * must be callable in atomic context. | ||
362 | */ | ||
363 | struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, | ||
364 | u8 *bssid,u8 *addr, u32 supp_rates) | ||
365 | { | ||
366 | struct ieee80211_local *local = sdata->local; | ||
367 | struct sta_info *sta; | ||
368 | int band = local->hw.conf.channel->band; | ||
369 | |||
370 | /* TODO: Could consider removing the least recently used entry and | ||
371 | * allow new one to be added. */ | ||
372 | if (local->num_sta >= IEEE80211_IBSS_MAX_STA_ENTRIES) { | ||
373 | if (net_ratelimit()) { | ||
374 | printk(KERN_DEBUG "%s: No room for a new IBSS STA " | ||
375 | "entry %pM\n", sdata->dev->name, addr); | ||
376 | } | ||
377 | return NULL; | ||
378 | } | ||
379 | |||
380 | if (compare_ether_addr(bssid, sdata->u.ibss.bssid)) | ||
381 | return NULL; | ||
382 | |||
383 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | ||
384 | printk(KERN_DEBUG "%s: Adding new IBSS station %pM (dev=%s)\n", | ||
385 | wiphy_name(local->hw.wiphy), addr, sdata->dev->name); | ||
386 | #endif | ||
387 | |||
388 | sta = sta_info_alloc(sdata, addr, GFP_ATOMIC); | ||
389 | if (!sta) | ||
390 | return NULL; | ||
391 | |||
392 | set_sta_flags(sta, WLAN_STA_AUTHORIZED); | ||
393 | |||
394 | /* make sure mandatory rates are always added */ | ||
395 | sta->sta.supp_rates[band] = supp_rates | | ||
396 | ieee80211_mandatory_rates(local, band); | ||
397 | |||
398 | rate_control_rate_init(sta); | ||
399 | |||
400 | if (sta_info_insert(sta)) | ||
401 | return NULL; | ||
402 | |||
403 | return sta; | ||
404 | } | ||
405 | |||
406 | static int ieee80211_sta_active_ibss(struct ieee80211_sub_if_data *sdata) | ||
407 | { | ||
408 | struct ieee80211_local *local = sdata->local; | ||
409 | int active = 0; | ||
410 | struct sta_info *sta; | ||
411 | |||
412 | rcu_read_lock(); | ||
413 | |||
414 | list_for_each_entry_rcu(sta, &local->sta_list, list) { | ||
415 | if (sta->sdata == sdata && | ||
416 | time_after(sta->last_rx + IEEE80211_IBSS_MERGE_INTERVAL, | ||
417 | jiffies)) { | ||
418 | active++; | ||
419 | break; | ||
420 | } | ||
421 | } | ||
422 | |||
423 | rcu_read_unlock(); | ||
424 | |||
425 | return active; | ||
426 | } | ||
427 | |||
428 | |||
429 | static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata) | ||
430 | { | ||
431 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | ||
432 | |||
433 | mod_timer(&ifibss->timer, jiffies + IEEE80211_IBSS_MERGE_INTERVAL); | ||
434 | |||
435 | ieee80211_sta_expire(sdata, IEEE80211_IBSS_INACTIVITY_LIMIT); | ||
436 | if (ieee80211_sta_active_ibss(sdata)) | ||
437 | return; | ||
438 | |||
439 | if ((ifibss->flags & IEEE80211_IBSS_BSSID_SET) && | ||
440 | (!(ifibss->flags & IEEE80211_IBSS_AUTO_CHANNEL_SEL))) | ||
441 | return; | ||
442 | |||
443 | printk(KERN_DEBUG "%s: No active IBSS STAs - trying to scan for other " | ||
444 | "IBSS networks with same SSID (merge)\n", sdata->dev->name); | ||
445 | |||
446 | /* XXX maybe racy? */ | ||
447 | if (sdata->local->scan_req) | ||
448 | return; | ||
449 | |||
450 | memcpy(sdata->local->int_scan_req.ssids[0].ssid, | ||
451 | ifibss->ssid, IEEE80211_MAX_SSID_LEN); | ||
452 | sdata->local->int_scan_req.ssids[0].ssid_len = ifibss->ssid_len; | ||
453 | ieee80211_request_scan(sdata, &sdata->local->int_scan_req); | ||
454 | } | ||
455 | |||
456 | static int ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata) | ||
457 | { | ||
458 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | ||
459 | struct ieee80211_local *local = sdata->local; | ||
460 | struct ieee80211_supported_band *sband; | ||
461 | u8 *pos; | ||
462 | u8 bssid[ETH_ALEN]; | ||
463 | u8 supp_rates[IEEE80211_MAX_SUPP_RATES]; | ||
464 | u16 capability; | ||
465 | int i; | ||
466 | |||
467 | if (ifibss->flags & IEEE80211_IBSS_BSSID_SET) { | ||
468 | memcpy(bssid, ifibss->bssid, ETH_ALEN); | ||
469 | } else { | ||
470 | /* Generate random, not broadcast, locally administered BSSID. Mix in | ||
471 | * own MAC address to make sure that devices that do not have proper | ||
472 | * random number generator get different BSSID. */ | ||
473 | get_random_bytes(bssid, ETH_ALEN); | ||
474 | for (i = 0; i < ETH_ALEN; i++) | ||
475 | bssid[i] ^= sdata->dev->dev_addr[i]; | ||
476 | bssid[0] &= ~0x01; | ||
477 | bssid[0] |= 0x02; | ||
478 | } | ||
479 | |||
480 | printk(KERN_DEBUG "%s: Creating new IBSS network, BSSID %pM\n", | ||
481 | sdata->dev->name, bssid); | ||
482 | |||
483 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | ||
484 | |||
485 | if (local->hw.conf.beacon_int == 0) | ||
486 | local->hw.conf.beacon_int = 100; | ||
487 | |||
488 | capability = WLAN_CAPABILITY_IBSS; | ||
489 | |||
490 | if (sdata->default_key) | ||
491 | capability |= WLAN_CAPABILITY_PRIVACY; | ||
492 | else | ||
493 | sdata->drop_unencrypted = 0; | ||
494 | |||
495 | pos = supp_rates; | ||
496 | for (i = 0; i < sband->n_bitrates; i++) { | ||
497 | int rate = sband->bitrates[i].bitrate; | ||
498 | *pos++ = (u8) (rate / 5); | ||
499 | } | ||
500 | |||
501 | return __ieee80211_sta_join_ibss(sdata, | ||
502 | bssid, local->hw.conf.beacon_int, | ||
503 | local->hw.conf.channel->center_freq, | ||
504 | sband->n_bitrates, supp_rates, | ||
505 | capability); | ||
506 | } | ||
507 | |||
508 | static int ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) | ||
509 | { | ||
510 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | ||
511 | struct ieee80211_local *local = sdata->local; | ||
512 | struct ieee80211_bss *bss; | ||
513 | const u8 *bssid = NULL; | ||
514 | int active_ibss; | ||
515 | |||
516 | if (ifibss->ssid_len == 0) | ||
517 | return -EINVAL; | ||
518 | |||
519 | active_ibss = ieee80211_sta_active_ibss(sdata); | ||
520 | #ifdef CONFIG_MAC80211_IBSS_DEBUG | ||
521 | printk(KERN_DEBUG "%s: sta_find_ibss (active_ibss=%d)\n", | ||
522 | sdata->dev->name, active_ibss); | ||
523 | #endif /* CONFIG_MAC80211_IBSS_DEBUG */ | ||
524 | |||
525 | if (active_ibss) | ||
526 | return 0; | ||
527 | |||
528 | if (ifibss->flags & IEEE80211_IBSS_BSSID_SET) | ||
529 | bssid = ifibss->bssid; | ||
530 | bss = (void *)cfg80211_get_bss(local->hw.wiphy, NULL, bssid, | ||
531 | ifibss->ssid, ifibss->ssid_len, | ||
532 | WLAN_CAPABILITY_IBSS, | ||
533 | WLAN_CAPABILITY_IBSS); | ||
534 | |||
535 | #ifdef CONFIG_MAC80211_IBSS_DEBUG | ||
536 | if (bss) | ||
537 | printk(KERN_DEBUG " sta_find_ibss: selected %pM current " | ||
538 | "%pM\n", bss->cbss.bssid, ifibss->bssid); | ||
539 | #endif /* CONFIG_MAC80211_IBSS_DEBUG */ | ||
540 | |||
541 | if (bss && | ||
542 | (!(ifibss->flags & IEEE80211_IBSS_PREV_BSSID_SET) || | ||
543 | memcmp(ifibss->bssid, bss->cbss.bssid, ETH_ALEN))) { | ||
544 | int ret; | ||
545 | |||
546 | printk(KERN_DEBUG "%s: Selected IBSS BSSID %pM" | ||
547 | " based on configured SSID\n", | ||
548 | sdata->dev->name, bss->cbss.bssid); | ||
549 | |||
550 | ret = ieee80211_sta_join_ibss(sdata, bss); | ||
551 | ieee80211_rx_bss_put(local, bss); | ||
552 | return ret; | ||
553 | } else if (bss) | ||
554 | ieee80211_rx_bss_put(local, bss); | ||
555 | |||
556 | #ifdef CONFIG_MAC80211_IBSS_DEBUG | ||
557 | printk(KERN_DEBUG " did not try to join ibss\n"); | ||
558 | #endif /* CONFIG_MAC80211_IBSS_DEBUG */ | ||
559 | |||
560 | /* Selected IBSS not found in current scan results - try to scan */ | ||
561 | if (ifibss->state == IEEE80211_IBSS_MLME_JOINED && | ||
562 | !ieee80211_sta_active_ibss(sdata)) { | ||
563 | mod_timer(&ifibss->timer, jiffies + | ||
564 | IEEE80211_IBSS_MERGE_INTERVAL); | ||
565 | } else if (time_after(jiffies, local->last_scan_completed + | ||
566 | IEEE80211_SCAN_INTERVAL)) { | ||
567 | printk(KERN_DEBUG "%s: Trigger new scan to find an IBSS to " | ||
568 | "join\n", sdata->dev->name); | ||
569 | |||
570 | /* XXX maybe racy? */ | ||
571 | if (local->scan_req) | ||
572 | return -EBUSY; | ||
573 | |||
574 | memcpy(local->int_scan_req.ssids[0].ssid, | ||
575 | ifibss->ssid, IEEE80211_MAX_SSID_LEN); | ||
576 | local->int_scan_req.ssids[0].ssid_len = ifibss->ssid_len; | ||
577 | return ieee80211_request_scan(sdata, &local->int_scan_req); | ||
578 | } else if (ifibss->state != IEEE80211_IBSS_MLME_JOINED) { | ||
579 | int interval = IEEE80211_SCAN_INTERVAL; | ||
580 | |||
581 | if (time_after(jiffies, ifibss->ibss_join_req + | ||
582 | IEEE80211_IBSS_JOIN_TIMEOUT)) { | ||
583 | if (!(local->oper_channel->flags & | ||
584 | IEEE80211_CHAN_NO_IBSS)) | ||
585 | return ieee80211_sta_create_ibss(sdata); | ||
586 | printk(KERN_DEBUG "%s: IBSS not allowed on" | ||
587 | " %d MHz\n", sdata->dev->name, | ||
588 | local->hw.conf.channel->center_freq); | ||
589 | |||
590 | /* No IBSS found - decrease scan interval and continue | ||
591 | * scanning. */ | ||
592 | interval = IEEE80211_SCAN_INTERVAL_SLOW; | ||
593 | } | ||
594 | |||
595 | ifibss->state = IEEE80211_IBSS_MLME_SEARCH; | ||
596 | mod_timer(&ifibss->timer, jiffies + interval); | ||
597 | return 0; | ||
598 | } | ||
599 | |||
600 | return 0; | ||
601 | } | ||
602 | |||
603 | static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata, | ||
604 | struct ieee80211_mgmt *mgmt, | ||
605 | size_t len) | ||
606 | { | ||
607 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | ||
608 | struct ieee80211_local *local = sdata->local; | ||
609 | int tx_last_beacon; | ||
610 | struct sk_buff *skb; | ||
611 | struct ieee80211_mgmt *resp; | ||
612 | u8 *pos, *end; | ||
613 | |||
614 | if (ifibss->state != IEEE80211_IBSS_MLME_JOINED || | ||
615 | len < 24 + 2 || !ifibss->probe_resp) | ||
616 | return; | ||
617 | |||
618 | if (local->ops->tx_last_beacon) | ||
619 | tx_last_beacon = local->ops->tx_last_beacon(local_to_hw(local)); | ||
620 | else | ||
621 | tx_last_beacon = 1; | ||
622 | |||
623 | #ifdef CONFIG_MAC80211_IBSS_DEBUG | ||
624 | printk(KERN_DEBUG "%s: RX ProbeReq SA=%pM DA=%pM BSSID=%pM" | ||
625 | " (tx_last_beacon=%d)\n", | ||
626 | sdata->dev->name, mgmt->sa, mgmt->da, | ||
627 | mgmt->bssid, tx_last_beacon); | ||
628 | #endif /* CONFIG_MAC80211_IBSS_DEBUG */ | ||
629 | |||
630 | if (!tx_last_beacon) | ||
631 | return; | ||
632 | |||
633 | if (memcmp(mgmt->bssid, ifibss->bssid, ETH_ALEN) != 0 && | ||
634 | memcmp(mgmt->bssid, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) != 0) | ||
635 | return; | ||
636 | |||
637 | end = ((u8 *) mgmt) + len; | ||
638 | pos = mgmt->u.probe_req.variable; | ||
639 | if (pos[0] != WLAN_EID_SSID || | ||
640 | pos + 2 + pos[1] > end) { | ||
641 | #ifdef CONFIG_MAC80211_IBSS_DEBUG | ||
642 | printk(KERN_DEBUG "%s: Invalid SSID IE in ProbeReq " | ||
643 | "from %pM\n", | ||
644 | sdata->dev->name, mgmt->sa); | ||
645 | #endif | ||
646 | return; | ||
647 | } | ||
648 | if (pos[1] != 0 && | ||
649 | (pos[1] != ifibss->ssid_len || | ||
650 | memcmp(pos + 2, ifibss->ssid, ifibss->ssid_len) != 0)) { | ||
651 | /* Ignore ProbeReq for foreign SSID */ | ||
652 | return; | ||
653 | } | ||
654 | |||
655 | /* Reply with ProbeResp */ | ||
656 | skb = skb_copy(ifibss->probe_resp, GFP_KERNEL); | ||
657 | if (!skb) | ||
658 | return; | ||
659 | |||
660 | resp = (struct ieee80211_mgmt *) skb->data; | ||
661 | memcpy(resp->da, mgmt->sa, ETH_ALEN); | ||
662 | #ifdef CONFIG_MAC80211_IBSS_DEBUG | ||
663 | printk(KERN_DEBUG "%s: Sending ProbeResp to %pM\n", | ||
664 | sdata->dev->name, resp->da); | ||
665 | #endif /* CONFIG_MAC80211_IBSS_DEBUG */ | ||
666 | ieee80211_tx_skb(sdata, skb, 0); | ||
667 | } | ||
668 | |||
669 | static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata, | ||
670 | struct ieee80211_mgmt *mgmt, | ||
671 | size_t len, | ||
672 | struct ieee80211_rx_status *rx_status) | ||
673 | { | ||
674 | size_t baselen; | ||
675 | struct ieee802_11_elems elems; | ||
676 | |||
677 | if (memcmp(mgmt->da, sdata->dev->dev_addr, ETH_ALEN)) | ||
678 | return; /* ignore ProbeResp to foreign address */ | ||
679 | |||
680 | baselen = (u8 *) mgmt->u.probe_resp.variable - (u8 *) mgmt; | ||
681 | if (baselen > len) | ||
682 | return; | ||
683 | |||
684 | ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - baselen, | ||
685 | &elems); | ||
686 | |||
687 | ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, false); | ||
688 | } | ||
689 | |||
690 | static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | ||
691 | struct ieee80211_mgmt *mgmt, | ||
692 | size_t len, | ||
693 | struct ieee80211_rx_status *rx_status) | ||
694 | { | ||
695 | size_t baselen; | ||
696 | struct ieee802_11_elems elems; | ||
697 | |||
698 | /* Process beacon from the current BSS */ | ||
699 | baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt; | ||
700 | if (baselen > len) | ||
701 | return; | ||
702 | |||
703 | ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, &elems); | ||
704 | |||
705 | ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, true); | ||
706 | } | ||
707 | |||
708 | static void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | ||
709 | struct sk_buff *skb) | ||
710 | { | ||
711 | struct ieee80211_rx_status *rx_status; | ||
712 | struct ieee80211_mgmt *mgmt; | ||
713 | u16 fc; | ||
714 | |||
715 | rx_status = (struct ieee80211_rx_status *) skb->cb; | ||
716 | mgmt = (struct ieee80211_mgmt *) skb->data; | ||
717 | fc = le16_to_cpu(mgmt->frame_control); | ||
718 | |||
719 | switch (fc & IEEE80211_FCTL_STYPE) { | ||
720 | case IEEE80211_STYPE_PROBE_REQ: | ||
721 | ieee80211_rx_mgmt_probe_req(sdata, mgmt, skb->len); | ||
722 | break; | ||
723 | case IEEE80211_STYPE_PROBE_RESP: | ||
724 | ieee80211_rx_mgmt_probe_resp(sdata, mgmt, skb->len, | ||
725 | rx_status); | ||
726 | break; | ||
727 | case IEEE80211_STYPE_BEACON: | ||
728 | ieee80211_rx_mgmt_beacon(sdata, mgmt, skb->len, | ||
729 | rx_status); | ||
730 | break; | ||
731 | case IEEE80211_STYPE_AUTH: | ||
732 | ieee80211_rx_mgmt_auth_ibss(sdata, mgmt, skb->len); | ||
733 | break; | ||
734 | } | ||
735 | |||
736 | kfree_skb(skb); | ||
737 | } | ||
738 | |||
739 | static void ieee80211_ibss_work(struct work_struct *work) | ||
740 | { | ||
741 | struct ieee80211_sub_if_data *sdata = | ||
742 | container_of(work, struct ieee80211_sub_if_data, u.ibss.work); | ||
743 | struct ieee80211_local *local = sdata->local; | ||
744 | struct ieee80211_if_ibss *ifibss; | ||
745 | struct sk_buff *skb; | ||
746 | |||
747 | if (!netif_running(sdata->dev)) | ||
748 | return; | ||
749 | |||
750 | if (local->sw_scanning || local->hw_scanning) | ||
751 | return; | ||
752 | |||
753 | if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_ADHOC)) | ||
754 | return; | ||
755 | ifibss = &sdata->u.ibss; | ||
756 | |||
757 | while ((skb = skb_dequeue(&ifibss->skb_queue))) | ||
758 | ieee80211_ibss_rx_queued_mgmt(sdata, skb); | ||
759 | |||
760 | if (!test_and_clear_bit(IEEE80211_IBSS_REQ_RUN, &ifibss->request)) | ||
761 | return; | ||
762 | |||
763 | switch (ifibss->state) { | ||
764 | case IEEE80211_IBSS_MLME_SEARCH: | ||
765 | ieee80211_sta_find_ibss(sdata); | ||
766 | break; | ||
767 | case IEEE80211_IBSS_MLME_JOINED: | ||
768 | ieee80211_sta_merge_ibss(sdata); | ||
769 | break; | ||
770 | default: | ||
771 | WARN_ON(1); | ||
772 | break; | ||
773 | } | ||
774 | } | ||
775 | |||
776 | static void ieee80211_ibss_timer(unsigned long data) | ||
777 | { | ||
778 | struct ieee80211_sub_if_data *sdata = | ||
779 | (struct ieee80211_sub_if_data *) data; | ||
780 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | ||
781 | struct ieee80211_local *local = sdata->local; | ||
782 | |||
783 | set_bit(IEEE80211_IBSS_REQ_RUN, &ifibss->request); | ||
784 | queue_work(local->hw.workqueue, &ifibss->work); | ||
785 | } | ||
786 | |||
787 | void ieee80211_ibss_setup_sdata(struct ieee80211_sub_if_data *sdata) | ||
788 | { | ||
789 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | ||
790 | |||
791 | INIT_WORK(&ifibss->work, ieee80211_ibss_work); | ||
792 | setup_timer(&ifibss->timer, ieee80211_ibss_timer, | ||
793 | (unsigned long) sdata); | ||
794 | skb_queue_head_init(&ifibss->skb_queue); | ||
795 | |||
796 | ifibss->flags |= IEEE80211_IBSS_AUTO_BSSID_SEL | | ||
797 | IEEE80211_IBSS_AUTO_CHANNEL_SEL; | ||
798 | } | ||
799 | |||
800 | int ieee80211_ibss_commit(struct ieee80211_sub_if_data *sdata) | ||
801 | { | ||
802 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | ||
803 | |||
804 | ifibss->flags &= ~IEEE80211_IBSS_PREV_BSSID_SET; | ||
805 | |||
806 | if (ifibss->ssid_len) | ||
807 | ifibss->flags |= IEEE80211_IBSS_SSID_SET; | ||
808 | else | ||
809 | ifibss->flags &= ~IEEE80211_IBSS_SSID_SET; | ||
810 | |||
811 | ifibss->ibss_join_req = jiffies; | ||
812 | ifibss->state = IEEE80211_IBSS_MLME_SEARCH; | ||
813 | |||
814 | return ieee80211_sta_find_ibss(sdata); | ||
815 | } | ||
816 | |||
817 | int ieee80211_ibss_set_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t len) | ||
818 | { | ||
819 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | ||
820 | |||
821 | if (len > IEEE80211_MAX_SSID_LEN) | ||
822 | return -EINVAL; | ||
823 | |||
824 | if (ifibss->ssid_len != len || memcmp(ifibss->ssid, ssid, len) != 0) { | ||
825 | memset(ifibss->ssid, 0, sizeof(ifibss->ssid)); | ||
826 | memcpy(ifibss->ssid, ssid, len); | ||
827 | ifibss->ssid_len = len; | ||
828 | } | ||
829 | |||
830 | return ieee80211_ibss_commit(sdata); | ||
831 | } | ||
832 | |||
833 | int ieee80211_ibss_get_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t *len) | ||
834 | { | ||
835 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | ||
836 | |||
837 | memcpy(ssid, ifibss->ssid, ifibss->ssid_len); | ||
838 | *len = ifibss->ssid_len; | ||
839 | |||
840 | return 0; | ||
841 | } | ||
842 | |||
843 | int ieee80211_ibss_set_bssid(struct ieee80211_sub_if_data *sdata, u8 *bssid) | ||
844 | { | ||
845 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | ||
846 | |||
847 | if (is_valid_ether_addr(bssid)) { | ||
848 | memcpy(ifibss->bssid, bssid, ETH_ALEN); | ||
849 | ifibss->flags |= IEEE80211_IBSS_BSSID_SET; | ||
850 | } else { | ||
851 | memset(ifibss->bssid, 0, ETH_ALEN); | ||
852 | ifibss->flags &= ~IEEE80211_IBSS_BSSID_SET; | ||
853 | } | ||
854 | |||
855 | if (netif_running(sdata->dev)) { | ||
856 | if (ieee80211_if_config(sdata, IEEE80211_IFCC_BSSID)) { | ||
857 | printk(KERN_DEBUG "%s: Failed to config new BSSID to " | ||
858 | "the low-level driver\n", sdata->dev->name); | ||
859 | } | ||
860 | } | ||
861 | |||
862 | return ieee80211_ibss_commit(sdata); | ||
863 | } | ||
864 | |||
865 | /* scan finished notification */ | ||
866 | void ieee80211_ibss_notify_scan_completed(struct ieee80211_local *local) | ||
867 | { | ||
868 | struct ieee80211_sub_if_data *sdata = local->scan_sdata; | ||
869 | struct ieee80211_if_ibss *ifibss; | ||
870 | |||
871 | if (sdata && sdata->vif.type == NL80211_IFTYPE_ADHOC) { | ||
872 | ifibss = &sdata->u.ibss; | ||
873 | if ((!(ifibss->flags & IEEE80211_IBSS_PREV_BSSID_SET)) || | ||
874 | !ieee80211_sta_active_ibss(sdata)) | ||
875 | ieee80211_sta_find_ibss(sdata); | ||
876 | } | ||
877 | } | ||
878 | |||
879 | ieee80211_rx_result | ||
880 | ieee80211_ibss_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, | ||
881 | struct ieee80211_rx_status *rx_status) | ||
882 | { | ||
883 | struct ieee80211_local *local = sdata->local; | ||
884 | struct ieee80211_mgmt *mgmt; | ||
885 | u16 fc; | ||
886 | |||
887 | if (skb->len < 24) | ||
888 | return RX_DROP_MONITOR; | ||
889 | |||
890 | mgmt = (struct ieee80211_mgmt *) skb->data; | ||
891 | fc = le16_to_cpu(mgmt->frame_control); | ||
892 | |||
893 | switch (fc & IEEE80211_FCTL_STYPE) { | ||
894 | case IEEE80211_STYPE_PROBE_RESP: | ||
895 | case IEEE80211_STYPE_BEACON: | ||
896 | memcpy(skb->cb, rx_status, sizeof(*rx_status)); | ||
897 | case IEEE80211_STYPE_PROBE_REQ: | ||
898 | case IEEE80211_STYPE_AUTH: | ||
899 | skb_queue_tail(&sdata->u.ibss.skb_queue, skb); | ||
900 | queue_work(local->hw.workqueue, &sdata->u.ibss.work); | ||
901 | return RX_QUEUED; | ||
902 | } | ||
903 | |||
904 | return RX_DROP_MONITOR; | ||
905 | } | ||
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 2cb743ed9f9c..ecbc8e0cb3e7 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -239,7 +239,7 @@ struct mesh_preq_queue { | |||
239 | u8 flags; | 239 | u8 flags; |
240 | }; | 240 | }; |
241 | 241 | ||
242 | /* flags used in struct ieee80211_if_sta.flags */ | 242 | /* flags used in struct ieee80211_if_managed.flags */ |
243 | #define IEEE80211_STA_SSID_SET BIT(0) | 243 | #define IEEE80211_STA_SSID_SET BIT(0) |
244 | #define IEEE80211_STA_BSSID_SET BIT(1) | 244 | #define IEEE80211_STA_BSSID_SET BIT(1) |
245 | #define IEEE80211_STA_PREV_BSSID_SET BIT(2) | 245 | #define IEEE80211_STA_PREV_BSSID_SET BIT(2) |
@@ -262,31 +262,30 @@ struct mesh_preq_queue { | |||
262 | #define IEEE80211_STA_REQ_AUTH 2 | 262 | #define IEEE80211_STA_REQ_AUTH 2 |
263 | #define IEEE80211_STA_REQ_RUN 3 | 263 | #define IEEE80211_STA_REQ_RUN 3 |
264 | 264 | ||
265 | /* STA/IBSS MLME states */ | ||
266 | enum ieee80211_sta_mlme_state { | ||
267 | IEEE80211_STA_MLME_DISABLED, | ||
268 | IEEE80211_STA_MLME_DIRECT_PROBE, | ||
269 | IEEE80211_STA_MLME_AUTHENTICATE, | ||
270 | IEEE80211_STA_MLME_ASSOCIATE, | ||
271 | IEEE80211_STA_MLME_ASSOCIATED, | ||
272 | IEEE80211_STA_MLME_IBSS_SEARCH, | ||
273 | IEEE80211_STA_MLME_IBSS_JOINED, | ||
274 | }; | ||
275 | |||
276 | /* bitfield of allowed auth algs */ | 265 | /* bitfield of allowed auth algs */ |
277 | #define IEEE80211_AUTH_ALG_OPEN BIT(0) | 266 | #define IEEE80211_AUTH_ALG_OPEN BIT(0) |
278 | #define IEEE80211_AUTH_ALG_SHARED_KEY BIT(1) | 267 | #define IEEE80211_AUTH_ALG_SHARED_KEY BIT(1) |
279 | #define IEEE80211_AUTH_ALG_LEAP BIT(2) | 268 | #define IEEE80211_AUTH_ALG_LEAP BIT(2) |
280 | 269 | ||
281 | struct ieee80211_if_sta { | 270 | struct ieee80211_if_managed { |
282 | struct timer_list timer; | 271 | struct timer_list timer; |
283 | struct timer_list chswitch_timer; | 272 | struct timer_list chswitch_timer; |
284 | struct work_struct work; | 273 | struct work_struct work; |
285 | struct work_struct chswitch_work; | 274 | struct work_struct chswitch_work; |
275 | |||
286 | u8 bssid[ETH_ALEN], prev_bssid[ETH_ALEN]; | 276 | u8 bssid[ETH_ALEN], prev_bssid[ETH_ALEN]; |
277 | |||
287 | u8 ssid[IEEE80211_MAX_SSID_LEN]; | 278 | u8 ssid[IEEE80211_MAX_SSID_LEN]; |
288 | enum ieee80211_sta_mlme_state state; | ||
289 | size_t ssid_len; | 279 | size_t ssid_len; |
280 | |||
281 | enum { | ||
282 | IEEE80211_STA_MLME_DISABLED, | ||
283 | IEEE80211_STA_MLME_DIRECT_PROBE, | ||
284 | IEEE80211_STA_MLME_AUTHENTICATE, | ||
285 | IEEE80211_STA_MLME_ASSOCIATE, | ||
286 | IEEE80211_STA_MLME_ASSOCIATED, | ||
287 | } state; | ||
288 | |||
290 | u16 aid; | 289 | u16 aid; |
291 | u16 ap_capab, capab; | 290 | u16 ap_capab, capab; |
292 | u8 *extra_ie; /* to be added to the end of AssocReq */ | 291 | u8 *extra_ie; /* to be added to the end of AssocReq */ |
@@ -319,10 +318,6 @@ struct ieee80211_if_sta { | |||
319 | IEEE80211_MFP_REQUIRED | 318 | IEEE80211_MFP_REQUIRED |
320 | } mfp; /* management frame protection */ | 319 | } mfp; /* management frame protection */ |
321 | 320 | ||
322 | unsigned long ibss_join_req; | ||
323 | struct sk_buff *probe_resp; /* ProbeResp template for IBSS */ | ||
324 | u32 supp_rates_bits[IEEE80211_NUM_BANDS]; | ||
325 | |||
326 | int wmm_last_param_set; | 321 | int wmm_last_param_set; |
327 | 322 | ||
328 | /* Extra IE data for management frames */ | 323 | /* Extra IE data for management frames */ |
@@ -342,6 +337,42 @@ struct ieee80211_if_sta { | |||
342 | size_t ie_disassoc_len; | 337 | size_t ie_disassoc_len; |
343 | }; | 338 | }; |
344 | 339 | ||
340 | enum ieee80211_ibss_flags { | ||
341 | IEEE80211_IBSS_AUTO_CHANNEL_SEL = BIT(0), | ||
342 | IEEE80211_IBSS_AUTO_BSSID_SEL = BIT(1), | ||
343 | IEEE80211_IBSS_BSSID_SET = BIT(2), | ||
344 | IEEE80211_IBSS_PREV_BSSID_SET = BIT(3), | ||
345 | IEEE80211_IBSS_SSID_SET = BIT(4), | ||
346 | }; | ||
347 | |||
348 | enum ieee80211_ibss_request { | ||
349 | IEEE80211_IBSS_REQ_RUN = 0, | ||
350 | }; | ||
351 | |||
352 | struct ieee80211_if_ibss { | ||
353 | struct timer_list timer; | ||
354 | struct work_struct work; | ||
355 | |||
356 | struct sk_buff_head skb_queue; | ||
357 | |||
358 | u8 ssid[IEEE80211_MAX_SSID_LEN]; | ||
359 | u8 ssid_len; | ||
360 | |||
361 | u32 flags; | ||
362 | |||
363 | u8 bssid[ETH_ALEN]; | ||
364 | |||
365 | unsigned long request; | ||
366 | |||
367 | unsigned long ibss_join_req; | ||
368 | struct sk_buff *probe_resp; /* ProbeResp template for IBSS */ | ||
369 | |||
370 | enum { | ||
371 | IEEE80211_IBSS_MLME_SEARCH, | ||
372 | IEEE80211_IBSS_MLME_JOINED, | ||
373 | } state; | ||
374 | }; | ||
375 | |||
345 | struct ieee80211_if_mesh { | 376 | struct ieee80211_if_mesh { |
346 | struct work_struct work; | 377 | struct work_struct work; |
347 | struct timer_list housekeeping_timer; | 378 | struct timer_list housekeeping_timer; |
@@ -445,7 +476,8 @@ struct ieee80211_sub_if_data { | |||
445 | struct ieee80211_if_ap ap; | 476 | struct ieee80211_if_ap ap; |
446 | struct ieee80211_if_wds wds; | 477 | struct ieee80211_if_wds wds; |
447 | struct ieee80211_if_vlan vlan; | 478 | struct ieee80211_if_vlan vlan; |
448 | struct ieee80211_if_sta sta; | 479 | struct ieee80211_if_managed mgd; |
480 | struct ieee80211_if_ibss ibss; | ||
449 | #ifdef CONFIG_MAC80211_MESH | 481 | #ifdef CONFIG_MAC80211_MESH |
450 | struct ieee80211_if_mesh mesh; | 482 | struct ieee80211_if_mesh mesh; |
451 | #endif | 483 | #endif |
@@ -564,12 +596,10 @@ enum { | |||
564 | enum queue_stop_reason { | 596 | enum queue_stop_reason { |
565 | IEEE80211_QUEUE_STOP_REASON_DRIVER, | 597 | IEEE80211_QUEUE_STOP_REASON_DRIVER, |
566 | IEEE80211_QUEUE_STOP_REASON_PS, | 598 | IEEE80211_QUEUE_STOP_REASON_PS, |
567 | IEEE80211_QUEUE_STOP_REASON_CSA | 599 | IEEE80211_QUEUE_STOP_REASON_CSA, |
600 | IEEE80211_QUEUE_STOP_REASON_AGGREGATION, | ||
568 | }; | 601 | }; |
569 | 602 | ||
570 | /* maximum number of hardware queues we support. */ | ||
571 | #define QD_MAX_QUEUES (IEEE80211_MAX_AMPDU_QUEUES + IEEE80211_MAX_QUEUES) | ||
572 | |||
573 | struct ieee80211_master_priv { | 603 | struct ieee80211_master_priv { |
574 | struct ieee80211_local *local; | 604 | struct ieee80211_local *local; |
575 | }; | 605 | }; |
@@ -582,9 +612,15 @@ struct ieee80211_local { | |||
582 | 612 | ||
583 | const struct ieee80211_ops *ops; | 613 | const struct ieee80211_ops *ops; |
584 | 614 | ||
585 | unsigned long queue_pool[BITS_TO_LONGS(QD_MAX_QUEUES)]; | 615 | /* AC queue corresponding to each AMPDU queue */ |
586 | unsigned long queue_stop_reasons[IEEE80211_MAX_QUEUES]; | 616 | s8 ampdu_ac_queue[IEEE80211_MAX_AMPDU_QUEUES]; |
617 | unsigned int amdpu_ac_stop_refcnt[IEEE80211_MAX_AMPDU_QUEUES]; | ||
618 | |||
619 | unsigned long queue_stop_reasons[IEEE80211_MAX_QUEUES + | ||
620 | IEEE80211_MAX_AMPDU_QUEUES]; | ||
621 | /* also used to protect ampdu_ac_queue and amdpu_ac_stop_refcnt */ | ||
587 | spinlock_t queue_stop_reason_lock; | 622 | spinlock_t queue_stop_reason_lock; |
623 | |||
588 | struct net_device *mdev; /* wmaster# - "master" 802.11 device */ | 624 | struct net_device *mdev; /* wmaster# - "master" 802.11 device */ |
589 | int open_count; | 625 | int open_count; |
590 | int monitors, cooked_mntrs; | 626 | int monitors, cooked_mntrs; |
@@ -888,34 +924,41 @@ void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx); | |||
888 | void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, | 924 | void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, |
889 | u32 changed); | 925 | u32 changed); |
890 | void ieee80211_configure_filter(struct ieee80211_local *local); | 926 | void ieee80211_configure_filter(struct ieee80211_local *local); |
927 | u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata); | ||
891 | 928 | ||
892 | /* wireless extensions */ | 929 | /* wireless extensions */ |
893 | extern const struct iw_handler_def ieee80211_iw_handler_def; | 930 | extern const struct iw_handler_def ieee80211_iw_handler_def; |
894 | 931 | ||
895 | /* STA/IBSS code */ | 932 | /* STA code */ |
896 | void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata); | 933 | void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata); |
897 | void ieee80211_scan_work(struct work_struct *work); | 934 | ieee80211_rx_result ieee80211_sta_rx_mgmt(struct ieee80211_sub_if_data *sdata, |
898 | void ieee80211_sta_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, | 935 | struct sk_buff *skb, |
899 | struct ieee80211_rx_status *rx_status); | 936 | struct ieee80211_rx_status *rx_status); |
937 | int ieee80211_sta_commit(struct ieee80211_sub_if_data *sdata); | ||
900 | int ieee80211_sta_set_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t len); | 938 | int ieee80211_sta_set_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t len); |
901 | int ieee80211_sta_get_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t *len); | 939 | int ieee80211_sta_get_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t *len); |
902 | int ieee80211_sta_set_bssid(struct ieee80211_sub_if_data *sdata, u8 *bssid); | 940 | int ieee80211_sta_set_bssid(struct ieee80211_sub_if_data *sdata, u8 *bssid); |
903 | void ieee80211_sta_req_auth(struct ieee80211_sub_if_data *sdata, | 941 | void ieee80211_sta_req_auth(struct ieee80211_sub_if_data *sdata); |
904 | struct ieee80211_if_sta *ifsta); | ||
905 | struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, | ||
906 | u8 *bssid, u8 *addr, u32 supp_rates); | ||
907 | int ieee80211_sta_deauthenticate(struct ieee80211_sub_if_data *sdata, u16 reason); | 942 | int ieee80211_sta_deauthenticate(struct ieee80211_sub_if_data *sdata, u16 reason); |
908 | int ieee80211_sta_disassociate(struct ieee80211_sub_if_data *sdata, u16 reason); | 943 | int ieee80211_sta_disassociate(struct ieee80211_sub_if_data *sdata, u16 reason); |
909 | u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata); | ||
910 | u32 ieee80211_sta_get_rates(struct ieee80211_local *local, | ||
911 | struct ieee802_11_elems *elems, | ||
912 | enum ieee80211_band band); | ||
913 | void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, | ||
914 | u8 *ssid, size_t ssid_len); | ||
915 | void ieee80211_send_pspoll(struct ieee80211_local *local, | 944 | void ieee80211_send_pspoll(struct ieee80211_local *local, |
916 | struct ieee80211_sub_if_data *sdata); | 945 | struct ieee80211_sub_if_data *sdata); |
917 | 946 | ||
947 | /* IBSS code */ | ||
948 | int ieee80211_ibss_commit(struct ieee80211_sub_if_data *sdata); | ||
949 | int ieee80211_ibss_set_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t len); | ||
950 | int ieee80211_ibss_get_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t *len); | ||
951 | int ieee80211_ibss_set_bssid(struct ieee80211_sub_if_data *sdata, u8 *bssid); | ||
952 | void ieee80211_ibss_notify_scan_completed(struct ieee80211_local *local); | ||
953 | void ieee80211_ibss_setup_sdata(struct ieee80211_sub_if_data *sdata); | ||
954 | ieee80211_rx_result | ||
955 | ieee80211_ibss_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, | ||
956 | struct ieee80211_rx_status *rx_status); | ||
957 | struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, | ||
958 | u8 *bssid, u8 *addr, u32 supp_rates); | ||
959 | |||
918 | /* scan/BSS handling */ | 960 | /* scan/BSS handling */ |
961 | void ieee80211_scan_work(struct work_struct *work); | ||
919 | int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata, | 962 | int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata, |
920 | struct cfg80211_scan_request *req); | 963 | struct cfg80211_scan_request *req); |
921 | int ieee80211_scan_results(struct ieee80211_local *local, | 964 | int ieee80211_scan_results(struct ieee80211_local *local, |
@@ -1042,6 +1085,25 @@ void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw, | |||
1042 | enum queue_stop_reason reason); | 1085 | enum queue_stop_reason reason); |
1043 | void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw, | 1086 | void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw, |
1044 | enum queue_stop_reason reason); | 1087 | enum queue_stop_reason reason); |
1088 | void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue, | ||
1089 | enum queue_stop_reason reason); | ||
1090 | void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue, | ||
1091 | enum queue_stop_reason reason); | ||
1092 | |||
1093 | void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, | ||
1094 | u16 transaction, u16 auth_alg, | ||
1095 | u8 *extra, size_t extra_len, | ||
1096 | const u8 *bssid, int encrypt); | ||
1097 | void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, | ||
1098 | u8 *ssid, size_t ssid_len, | ||
1099 | u8 *ie, size_t ie_len); | ||
1100 | |||
1101 | void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata, | ||
1102 | const size_t supp_rates_len, | ||
1103 | const u8 *supp_rates); | ||
1104 | u32 ieee80211_sta_get_rates(struct ieee80211_local *local, | ||
1105 | struct ieee802_11_elems *elems, | ||
1106 | enum ieee80211_band band); | ||
1045 | 1107 | ||
1046 | #ifdef CONFIG_MAC80211_NOINLINE | 1108 | #ifdef CONFIG_MAC80211_NOINLINE |
1047 | #define debug_noinline noinline | 1109 | #define debug_noinline noinline |
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index df94b9365264..2acc416e77e1 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
@@ -236,7 +236,10 @@ static int ieee80211_open(struct net_device *dev) | |||
236 | break; | 236 | break; |
237 | case NL80211_IFTYPE_STATION: | 237 | case NL80211_IFTYPE_STATION: |
238 | case NL80211_IFTYPE_ADHOC: | 238 | case NL80211_IFTYPE_ADHOC: |
239 | sdata->u.sta.flags &= ~IEEE80211_STA_PREV_BSSID_SET; | 239 | if (sdata->vif.type == NL80211_IFTYPE_STATION) |
240 | sdata->u.mgd.flags &= ~IEEE80211_STA_PREV_BSSID_SET; | ||
241 | else | ||
242 | sdata->u.ibss.flags &= ~IEEE80211_IBSS_PREV_BSSID_SET; | ||
240 | /* fall through */ | 243 | /* fall through */ |
241 | default: | 244 | default: |
242 | conf.vif = &sdata->vif; | 245 | conf.vif = &sdata->vif; |
@@ -321,11 +324,10 @@ static int ieee80211_open(struct net_device *dev) | |||
321 | * yet be effective. Trigger execution of ieee80211_sta_work | 324 | * yet be effective. Trigger execution of ieee80211_sta_work |
322 | * to fix this. | 325 | * to fix this. |
323 | */ | 326 | */ |
324 | if (sdata->vif.type == NL80211_IFTYPE_STATION || | 327 | if (sdata->vif.type == NL80211_IFTYPE_STATION) |
325 | sdata->vif.type == NL80211_IFTYPE_ADHOC) { | 328 | queue_work(local->hw.workqueue, &sdata->u.mgd.work); |
326 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | 329 | else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) |
327 | queue_work(local->hw.workqueue, &ifsta->work); | 330 | queue_work(local->hw.workqueue, &sdata->u.ibss.work); |
328 | } | ||
329 | 331 | ||
330 | netif_tx_start_all_queues(dev); | 332 | netif_tx_start_all_queues(dev); |
331 | 333 | ||
@@ -452,15 +454,13 @@ static int ieee80211_stop(struct net_device *dev) | |||
452 | netif_addr_unlock_bh(local->mdev); | 454 | netif_addr_unlock_bh(local->mdev); |
453 | break; | 455 | break; |
454 | case NL80211_IFTYPE_STATION: | 456 | case NL80211_IFTYPE_STATION: |
455 | case NL80211_IFTYPE_ADHOC: | ||
456 | /* Announce that we are leaving the network. */ | 457 | /* Announce that we are leaving the network. */ |
457 | if (sdata->u.sta.state != IEEE80211_STA_MLME_DISABLED) | 458 | if (sdata->u.mgd.state != IEEE80211_STA_MLME_DISABLED) |
458 | ieee80211_sta_deauthenticate(sdata, | 459 | ieee80211_sta_deauthenticate(sdata, |
459 | WLAN_REASON_DEAUTH_LEAVING); | 460 | WLAN_REASON_DEAUTH_LEAVING); |
460 | 461 | memset(sdata->u.mgd.bssid, 0, ETH_ALEN); | |
461 | memset(sdata->u.sta.bssid, 0, ETH_ALEN); | 462 | del_timer_sync(&sdata->u.mgd.chswitch_timer); |
462 | del_timer_sync(&sdata->u.sta.chswitch_timer); | 463 | del_timer_sync(&sdata->u.mgd.timer); |
463 | del_timer_sync(&sdata->u.sta.timer); | ||
464 | /* | 464 | /* |
465 | * If the timer fired while we waited for it, it will have | 465 | * If the timer fired while we waited for it, it will have |
466 | * requeued the work. Now the work will be running again | 466 | * requeued the work. Now the work will be running again |
@@ -468,8 +468,8 @@ static int ieee80211_stop(struct net_device *dev) | |||
468 | * whether the interface is running, which, at this point, | 468 | * whether the interface is running, which, at this point, |
469 | * it no longer is. | 469 | * it no longer is. |
470 | */ | 470 | */ |
471 | cancel_work_sync(&sdata->u.sta.work); | 471 | cancel_work_sync(&sdata->u.mgd.work); |
472 | cancel_work_sync(&sdata->u.sta.chswitch_work); | 472 | cancel_work_sync(&sdata->u.mgd.chswitch_work); |
473 | /* | 473 | /* |
474 | * When we get here, the interface is marked down. | 474 | * When we get here, the interface is marked down. |
475 | * Call synchronize_rcu() to wait for the RX path | 475 | * Call synchronize_rcu() to wait for the RX path |
@@ -477,13 +477,22 @@ static int ieee80211_stop(struct net_device *dev) | |||
477 | * frames at this very time on another CPU. | 477 | * frames at this very time on another CPU. |
478 | */ | 478 | */ |
479 | synchronize_rcu(); | 479 | synchronize_rcu(); |
480 | skb_queue_purge(&sdata->u.sta.skb_queue); | 480 | skb_queue_purge(&sdata->u.mgd.skb_queue); |
481 | 481 | ||
482 | sdata->u.sta.flags &= ~(IEEE80211_STA_PRIVACY_INVOKED | | 482 | sdata->u.mgd.flags &= ~(IEEE80211_STA_PRIVACY_INVOKED | |
483 | IEEE80211_STA_TKIP_WEP_USED); | 483 | IEEE80211_STA_TKIP_WEP_USED); |
484 | kfree(sdata->u.sta.extra_ie); | 484 | kfree(sdata->u.mgd.extra_ie); |
485 | sdata->u.sta.extra_ie = NULL; | 485 | sdata->u.mgd.extra_ie = NULL; |
486 | sdata->u.sta.extra_ie_len = 0; | 486 | sdata->u.mgd.extra_ie_len = 0; |
487 | /* fall through */ | ||
488 | case NL80211_IFTYPE_ADHOC: | ||
489 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { | ||
490 | memset(sdata->u.ibss.bssid, 0, ETH_ALEN); | ||
491 | del_timer_sync(&sdata->u.ibss.timer); | ||
492 | cancel_work_sync(&sdata->u.ibss.work); | ||
493 | synchronize_rcu(); | ||
494 | skb_queue_purge(&sdata->u.ibss.skb_queue); | ||
495 | } | ||
487 | /* fall through */ | 496 | /* fall through */ |
488 | case NL80211_IFTYPE_MESH_POINT: | 497 | case NL80211_IFTYPE_MESH_POINT: |
489 | if (ieee80211_vif_is_mesh(&sdata->vif)) { | 498 | if (ieee80211_vif_is_mesh(&sdata->vif)) { |
@@ -629,19 +638,20 @@ static void ieee80211_teardown_sdata(struct net_device *dev) | |||
629 | if (ieee80211_vif_is_mesh(&sdata->vif)) | 638 | if (ieee80211_vif_is_mesh(&sdata->vif)) |
630 | mesh_rmc_free(sdata); | 639 | mesh_rmc_free(sdata); |
631 | break; | 640 | break; |
632 | case NL80211_IFTYPE_STATION: | ||
633 | case NL80211_IFTYPE_ADHOC: | 641 | case NL80211_IFTYPE_ADHOC: |
634 | kfree(sdata->u.sta.extra_ie); | 642 | kfree_skb(sdata->u.ibss.probe_resp); |
635 | kfree(sdata->u.sta.assocreq_ies); | 643 | break; |
636 | kfree(sdata->u.sta.assocresp_ies); | 644 | case NL80211_IFTYPE_STATION: |
637 | kfree_skb(sdata->u.sta.probe_resp); | 645 | kfree(sdata->u.mgd.extra_ie); |
638 | kfree(sdata->u.sta.ie_probereq); | 646 | kfree(sdata->u.mgd.assocreq_ies); |
639 | kfree(sdata->u.sta.ie_proberesp); | 647 | kfree(sdata->u.mgd.assocresp_ies); |
640 | kfree(sdata->u.sta.ie_auth); | 648 | kfree(sdata->u.mgd.ie_probereq); |
641 | kfree(sdata->u.sta.ie_assocreq); | 649 | kfree(sdata->u.mgd.ie_proberesp); |
642 | kfree(sdata->u.sta.ie_reassocreq); | 650 | kfree(sdata->u.mgd.ie_auth); |
643 | kfree(sdata->u.sta.ie_deauth); | 651 | kfree(sdata->u.mgd.ie_assocreq); |
644 | kfree(sdata->u.sta.ie_disassoc); | 652 | kfree(sdata->u.mgd.ie_reassocreq); |
653 | kfree(sdata->u.mgd.ie_deauth); | ||
654 | kfree(sdata->u.mgd.ie_disassoc); | ||
645 | break; | 655 | break; |
646 | case NL80211_IFTYPE_WDS: | 656 | case NL80211_IFTYPE_WDS: |
647 | case NL80211_IFTYPE_AP_VLAN: | 657 | case NL80211_IFTYPE_AP_VLAN: |
@@ -708,9 +718,11 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata, | |||
708 | INIT_LIST_HEAD(&sdata->u.ap.vlans); | 718 | INIT_LIST_HEAD(&sdata->u.ap.vlans); |
709 | break; | 719 | break; |
710 | case NL80211_IFTYPE_STATION: | 720 | case NL80211_IFTYPE_STATION: |
711 | case NL80211_IFTYPE_ADHOC: | ||
712 | ieee80211_sta_setup_sdata(sdata); | 721 | ieee80211_sta_setup_sdata(sdata); |
713 | break; | 722 | break; |
723 | case NL80211_IFTYPE_ADHOC: | ||
724 | ieee80211_ibss_setup_sdata(sdata); | ||
725 | break; | ||
714 | case NL80211_IFTYPE_MESH_POINT: | 726 | case NL80211_IFTYPE_MESH_POINT: |
715 | if (ieee80211_vif_is_mesh(&sdata->vif)) | 727 | if (ieee80211_vif_is_mesh(&sdata->vif)) |
716 | ieee80211_mesh_init_sdata(sdata); | 728 | ieee80211_mesh_init_sdata(sdata); |
@@ -798,6 +810,7 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, | |||
798 | 810 | ||
799 | memcpy(ndev->dev_addr, local->hw.wiphy->perm_addr, ETH_ALEN); | 811 | memcpy(ndev->dev_addr, local->hw.wiphy->perm_addr, ETH_ALEN); |
800 | SET_NETDEV_DEV(ndev, wiphy_dev(local->hw.wiphy)); | 812 | SET_NETDEV_DEV(ndev, wiphy_dev(local->hw.wiphy)); |
813 | ndev->features |= NETIF_F_NETNS_LOCAL; | ||
801 | 814 | ||
802 | /* don't use IEEE80211_DEV_TO_SUB_IF because it checks too much */ | 815 | /* don't use IEEE80211_DEV_TO_SUB_IF because it checks too much */ |
803 | sdata = netdev_priv(ndev); | 816 | sdata = netdev_priv(ndev); |
diff --git a/net/mac80211/key.c b/net/mac80211/key.c index 19b480de4bbc..687acf23054d 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c | |||
@@ -400,7 +400,7 @@ void ieee80211_key_link(struct ieee80211_key *key, | |||
400 | */ | 400 | */ |
401 | 401 | ||
402 | /* same here, the AP could be using QoS */ | 402 | /* same here, the AP could be using QoS */ |
403 | ap = sta_info_get(key->local, key->sdata->u.sta.bssid); | 403 | ap = sta_info_get(key->local, key->sdata->u.mgd.bssid); |
404 | if (ap) { | 404 | if (ap) { |
405 | if (test_sta_flags(ap, WLAN_STA_WME)) | 405 | if (test_sta_flags(ap, WLAN_STA_WME)) |
406 | key->conf.flags |= | 406 | key->conf.flags |= |
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 5667f4e8067f..f38db4d37e5d 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -169,9 +169,10 @@ int ieee80211_if_config(struct ieee80211_sub_if_data *sdata, u32 changed) | |||
169 | 169 | ||
170 | memset(&conf, 0, sizeof(conf)); | 170 | memset(&conf, 0, sizeof(conf)); |
171 | 171 | ||
172 | if (sdata->vif.type == NL80211_IFTYPE_STATION || | 172 | if (sdata->vif.type == NL80211_IFTYPE_STATION) |
173 | sdata->vif.type == NL80211_IFTYPE_ADHOC) | 173 | conf.bssid = sdata->u.mgd.bssid; |
174 | conf.bssid = sdata->u.sta.bssid; | 174 | else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) |
175 | conf.bssid = sdata->u.ibss.bssid; | ||
175 | else if (sdata->vif.type == NL80211_IFTYPE_AP) | 176 | else if (sdata->vif.type == NL80211_IFTYPE_AP) |
176 | conf.bssid = sdata->dev->dev_addr; | 177 | conf.bssid = sdata->dev->dev_addr; |
177 | else if (ieee80211_vif_is_mesh(&sdata->vif)) { | 178 | else if (ieee80211_vif_is_mesh(&sdata->vif)) { |
@@ -210,7 +211,7 @@ int ieee80211_if_config(struct ieee80211_sub_if_data *sdata, u32 changed) | |||
210 | !!rcu_dereference(sdata->u.ap.beacon); | 211 | !!rcu_dereference(sdata->u.ap.beacon); |
211 | break; | 212 | break; |
212 | case NL80211_IFTYPE_ADHOC: | 213 | case NL80211_IFTYPE_ADHOC: |
213 | conf.enable_beacon = !!sdata->u.sta.probe_resp; | 214 | conf.enable_beacon = !!sdata->u.ibss.probe_resp; |
214 | break; | 215 | break; |
215 | case NL80211_IFTYPE_MESH_POINT: | 216 | case NL80211_IFTYPE_MESH_POINT: |
216 | conf.enable_beacon = true; | 217 | conf.enable_beacon = true; |
@@ -705,7 +706,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
705 | const struct ieee80211_ops *ops) | 706 | const struct ieee80211_ops *ops) |
706 | { | 707 | { |
707 | struct ieee80211_local *local; | 708 | struct ieee80211_local *local; |
708 | int priv_size; | 709 | int priv_size, i; |
709 | struct wiphy *wiphy; | 710 | struct wiphy *wiphy; |
710 | 711 | ||
711 | /* Ensure 32-byte alignment of our private data and hw private data. | 712 | /* Ensure 32-byte alignment of our private data and hw private data. |
@@ -779,6 +780,11 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
779 | setup_timer(&local->dynamic_ps_timer, | 780 | setup_timer(&local->dynamic_ps_timer, |
780 | ieee80211_dynamic_ps_timer, (unsigned long) local); | 781 | ieee80211_dynamic_ps_timer, (unsigned long) local); |
781 | 782 | ||
783 | for (i = 0; i < IEEE80211_MAX_AMPDU_QUEUES; i++) | ||
784 | local->ampdu_ac_queue[i] = -1; | ||
785 | /* using an s8 won't work with more than that */ | ||
786 | BUILD_BUG_ON(IEEE80211_MAX_AMPDU_QUEUES > 127); | ||
787 | |||
782 | sta_info_init(local); | 788 | sta_info_init(local); |
783 | 789 | ||
784 | tasklet_init(&local->tx_pending_tasklet, ieee80211_tx_pending, | 790 | tasklet_init(&local->tx_pending_tasklet, ieee80211_tx_pending, |
@@ -855,6 +861,11 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
855 | /* mac80211 always supports monitor */ | 861 | /* mac80211 always supports monitor */ |
856 | local->hw.wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR); | 862 | local->hw.wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR); |
857 | 863 | ||
864 | if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) | ||
865 | local->hw.wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; | ||
866 | else if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC) | ||
867 | local->hw.wiphy->signal_type = CFG80211_SIGNAL_TYPE_UNSPEC; | ||
868 | |||
858 | result = wiphy_register(local->hw.wiphy); | 869 | result = wiphy_register(local->hw.wiphy); |
859 | if (result < 0) | 870 | if (result < 0) |
860 | goto fail_wiphy_register; | 871 | goto fail_wiphy_register; |
@@ -872,7 +883,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
872 | 883 | ||
873 | mdev = alloc_netdev_mq(sizeof(struct ieee80211_master_priv), | 884 | mdev = alloc_netdev_mq(sizeof(struct ieee80211_master_priv), |
874 | "wmaster%d", ieee80211_master_setup, | 885 | "wmaster%d", ieee80211_master_setup, |
875 | ieee80211_num_queues(hw)); | 886 | hw->queues); |
876 | if (!mdev) | 887 | if (!mdev) |
877 | goto fail_mdev_alloc; | 888 | goto fail_mdev_alloc; |
878 | 889 | ||
@@ -916,6 +927,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
916 | 927 | ||
917 | memcpy(local->mdev->dev_addr, local->hw.wiphy->perm_addr, ETH_ALEN); | 928 | memcpy(local->mdev->dev_addr, local->hw.wiphy->perm_addr, ETH_ALEN); |
918 | SET_NETDEV_DEV(local->mdev, wiphy_dev(local->hw.wiphy)); | 929 | SET_NETDEV_DEV(local->mdev, wiphy_dev(local->hw.wiphy)); |
930 | local->mdev->features |= NETIF_F_NETNS_LOCAL; | ||
919 | 931 | ||
920 | result = register_netdevice(local->mdev); | 932 | result = register_netdevice(local->mdev); |
921 | if (result < 0) | 933 | if (result < 0) |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index fbb766afe599..7f238589b6ff 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -15,11 +15,8 @@ | |||
15 | #include <linux/if_ether.h> | 15 | #include <linux/if_ether.h> |
16 | #include <linux/skbuff.h> | 16 | #include <linux/skbuff.h> |
17 | #include <linux/if_arp.h> | 17 | #include <linux/if_arp.h> |
18 | #include <linux/wireless.h> | ||
19 | #include <linux/random.h> | ||
20 | #include <linux/etherdevice.h> | 18 | #include <linux/etherdevice.h> |
21 | #include <linux/rtnetlink.h> | 19 | #include <linux/rtnetlink.h> |
22 | #include <net/iw_handler.h> | ||
23 | #include <net/mac80211.h> | 20 | #include <net/mac80211.h> |
24 | #include <asm/unaligned.h> | 21 | #include <asm/unaligned.h> |
25 | 22 | ||
@@ -35,15 +32,6 @@ | |||
35 | #define IEEE80211_MONITORING_INTERVAL (2 * HZ) | 32 | #define IEEE80211_MONITORING_INTERVAL (2 * HZ) |
36 | #define IEEE80211_PROBE_INTERVAL (60 * HZ) | 33 | #define IEEE80211_PROBE_INTERVAL (60 * HZ) |
37 | #define IEEE80211_RETRY_AUTH_INTERVAL (1 * HZ) | 34 | #define IEEE80211_RETRY_AUTH_INTERVAL (1 * HZ) |
38 | #define IEEE80211_SCAN_INTERVAL (2 * HZ) | ||
39 | #define IEEE80211_SCAN_INTERVAL_SLOW (15 * HZ) | ||
40 | #define IEEE80211_IBSS_JOIN_TIMEOUT (7 * HZ) | ||
41 | |||
42 | #define IEEE80211_IBSS_MERGE_INTERVAL (30 * HZ) | ||
43 | #define IEEE80211_IBSS_INACTIVITY_LIMIT (60 * HZ) | ||
44 | |||
45 | #define IEEE80211_IBSS_MAX_STA_ENTRIES 128 | ||
46 | |||
47 | 35 | ||
48 | /* utils */ | 36 | /* utils */ |
49 | static int ecw2cw(int ecw) | 37 | static int ecw2cw(int ecw) |
@@ -92,43 +80,6 @@ static int ieee80211_compatible_rates(struct ieee80211_bss *bss, | |||
92 | return count; | 80 | return count; |
93 | } | 81 | } |
94 | 82 | ||
95 | /* also used by mesh code */ | ||
96 | u32 ieee80211_sta_get_rates(struct ieee80211_local *local, | ||
97 | struct ieee802_11_elems *elems, | ||
98 | enum ieee80211_band band) | ||
99 | { | ||
100 | struct ieee80211_supported_band *sband; | ||
101 | struct ieee80211_rate *bitrates; | ||
102 | size_t num_rates; | ||
103 | u32 supp_rates; | ||
104 | int i, j; | ||
105 | sband = local->hw.wiphy->bands[band]; | ||
106 | |||
107 | if (!sband) { | ||
108 | WARN_ON(1); | ||
109 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | ||
110 | } | ||
111 | |||
112 | bitrates = sband->bitrates; | ||
113 | num_rates = sband->n_bitrates; | ||
114 | supp_rates = 0; | ||
115 | for (i = 0; i < elems->supp_rates_len + | ||
116 | elems->ext_supp_rates_len; i++) { | ||
117 | u8 rate = 0; | ||
118 | int own_rate; | ||
119 | if (i < elems->supp_rates_len) | ||
120 | rate = elems->supp_rates[i]; | ||
121 | else if (elems->ext_supp_rates) | ||
122 | rate = elems->ext_supp_rates | ||
123 | [i - elems->supp_rates_len]; | ||
124 | own_rate = 5 * (rate & 0x7f); | ||
125 | for (j = 0; j < num_rates; j++) | ||
126 | if (bitrates[j].bitrate == own_rate) | ||
127 | supp_rates |= BIT(j); | ||
128 | } | ||
129 | return supp_rates; | ||
130 | } | ||
131 | |||
132 | /* frame sending functions */ | 83 | /* frame sending functions */ |
133 | 84 | ||
134 | static void add_extra_ies(struct sk_buff *skb, u8 *ies, size_t ies_len) | 85 | static void add_extra_ies(struct sk_buff *skb, u8 *ies, size_t ies_len) |
@@ -137,113 +88,9 @@ static void add_extra_ies(struct sk_buff *skb, u8 *ies, size_t ies_len) | |||
137 | memcpy(skb_put(skb, ies_len), ies, ies_len); | 88 | memcpy(skb_put(skb, ies_len), ies, ies_len); |
138 | } | 89 | } |
139 | 90 | ||
140 | /* also used by scanning code */ | 91 | static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) |
141 | void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, | ||
142 | u8 *ssid, size_t ssid_len) | ||
143 | { | ||
144 | struct ieee80211_local *local = sdata->local; | ||
145 | struct ieee80211_supported_band *sband; | ||
146 | struct sk_buff *skb; | ||
147 | struct ieee80211_mgmt *mgmt; | ||
148 | u8 *pos, *supp_rates, *esupp_rates = NULL; | ||
149 | int i; | ||
150 | |||
151 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt) + 200 + | ||
152 | sdata->u.sta.ie_probereq_len); | ||
153 | if (!skb) { | ||
154 | printk(KERN_DEBUG "%s: failed to allocate buffer for probe " | ||
155 | "request\n", sdata->dev->name); | ||
156 | return; | ||
157 | } | ||
158 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
159 | |||
160 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); | ||
161 | memset(mgmt, 0, 24); | ||
162 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
163 | IEEE80211_STYPE_PROBE_REQ); | ||
164 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | ||
165 | if (dst) { | ||
166 | memcpy(mgmt->da, dst, ETH_ALEN); | ||
167 | memcpy(mgmt->bssid, dst, ETH_ALEN); | ||
168 | } else { | ||
169 | memset(mgmt->da, 0xff, ETH_ALEN); | ||
170 | memset(mgmt->bssid, 0xff, ETH_ALEN); | ||
171 | } | ||
172 | pos = skb_put(skb, 2 + ssid_len); | ||
173 | *pos++ = WLAN_EID_SSID; | ||
174 | *pos++ = ssid_len; | ||
175 | memcpy(pos, ssid, ssid_len); | ||
176 | |||
177 | supp_rates = skb_put(skb, 2); | ||
178 | supp_rates[0] = WLAN_EID_SUPP_RATES; | ||
179 | supp_rates[1] = 0; | ||
180 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | ||
181 | |||
182 | for (i = 0; i < sband->n_bitrates; i++) { | ||
183 | struct ieee80211_rate *rate = &sband->bitrates[i]; | ||
184 | if (esupp_rates) { | ||
185 | pos = skb_put(skb, 1); | ||
186 | esupp_rates[1]++; | ||
187 | } else if (supp_rates[1] == 8) { | ||
188 | esupp_rates = skb_put(skb, 3); | ||
189 | esupp_rates[0] = WLAN_EID_EXT_SUPP_RATES; | ||
190 | esupp_rates[1] = 1; | ||
191 | pos = &esupp_rates[2]; | ||
192 | } else { | ||
193 | pos = skb_put(skb, 1); | ||
194 | supp_rates[1]++; | ||
195 | } | ||
196 | *pos = rate->bitrate / 5; | ||
197 | } | ||
198 | |||
199 | add_extra_ies(skb, sdata->u.sta.ie_probereq, | ||
200 | sdata->u.sta.ie_probereq_len); | ||
201 | |||
202 | ieee80211_tx_skb(sdata, skb, 0); | ||
203 | } | ||
204 | |||
205 | static void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, | ||
206 | struct ieee80211_if_sta *ifsta, | ||
207 | int transaction, u8 *extra, size_t extra_len, | ||
208 | int encrypt) | ||
209 | { | ||
210 | struct ieee80211_local *local = sdata->local; | ||
211 | struct sk_buff *skb; | ||
212 | struct ieee80211_mgmt *mgmt; | ||
213 | |||
214 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + | ||
215 | sizeof(*mgmt) + 6 + extra_len + | ||
216 | sdata->u.sta.ie_auth_len); | ||
217 | if (!skb) { | ||
218 | printk(KERN_DEBUG "%s: failed to allocate buffer for auth " | ||
219 | "frame\n", sdata->dev->name); | ||
220 | return; | ||
221 | } | ||
222 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
223 | |||
224 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24 + 6); | ||
225 | memset(mgmt, 0, 24 + 6); | ||
226 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
227 | IEEE80211_STYPE_AUTH); | ||
228 | if (encrypt) | ||
229 | mgmt->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); | ||
230 | memcpy(mgmt->da, ifsta->bssid, ETH_ALEN); | ||
231 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | ||
232 | memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); | ||
233 | mgmt->u.auth.auth_alg = cpu_to_le16(ifsta->auth_alg); | ||
234 | mgmt->u.auth.auth_transaction = cpu_to_le16(transaction); | ||
235 | ifsta->auth_transaction = transaction + 1; | ||
236 | mgmt->u.auth.status_code = cpu_to_le16(0); | ||
237 | if (extra) | ||
238 | memcpy(skb_put(skb, extra_len), extra, extra_len); | ||
239 | add_extra_ies(skb, sdata->u.sta.ie_auth, sdata->u.sta.ie_auth_len); | ||
240 | |||
241 | ieee80211_tx_skb(sdata, skb, encrypt); | ||
242 | } | ||
243 | |||
244 | static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, | ||
245 | struct ieee80211_if_sta *ifsta) | ||
246 | { | 92 | { |
93 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
247 | struct ieee80211_local *local = sdata->local; | 94 | struct ieee80211_local *local = sdata->local; |
248 | struct sk_buff *skb; | 95 | struct sk_buff *skb; |
249 | struct ieee80211_mgmt *mgmt; | 96 | struct ieee80211_mgmt *mgmt; |
@@ -256,17 +103,17 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, | |||
256 | u32 rates = 0; | 103 | u32 rates = 0; |
257 | size_t e_ies_len; | 104 | size_t e_ies_len; |
258 | 105 | ||
259 | if (ifsta->flags & IEEE80211_STA_PREV_BSSID_SET) { | 106 | if (ifmgd->flags & IEEE80211_IBSS_PREV_BSSID_SET) { |
260 | e_ies = sdata->u.sta.ie_reassocreq; | 107 | e_ies = sdata->u.mgd.ie_reassocreq; |
261 | e_ies_len = sdata->u.sta.ie_reassocreq_len; | 108 | e_ies_len = sdata->u.mgd.ie_reassocreq_len; |
262 | } else { | 109 | } else { |
263 | e_ies = sdata->u.sta.ie_assocreq; | 110 | e_ies = sdata->u.mgd.ie_assocreq; |
264 | e_ies_len = sdata->u.sta.ie_assocreq_len; | 111 | e_ies_len = sdata->u.mgd.ie_assocreq_len; |
265 | } | 112 | } |
266 | 113 | ||
267 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + | 114 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + |
268 | sizeof(*mgmt) + 200 + ifsta->extra_ie_len + | 115 | sizeof(*mgmt) + 200 + ifmgd->extra_ie_len + |
269 | ifsta->ssid_len + e_ies_len); | 116 | ifmgd->ssid_len + e_ies_len); |
270 | if (!skb) { | 117 | if (!skb) { |
271 | printk(KERN_DEBUG "%s: failed to allocate buffer for assoc " | 118 | printk(KERN_DEBUG "%s: failed to allocate buffer for assoc " |
272 | "frame\n", sdata->dev->name); | 119 | "frame\n", sdata->dev->name); |
@@ -276,7 +123,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, | |||
276 | 123 | ||
277 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | 124 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; |
278 | 125 | ||
279 | capab = ifsta->capab; | 126 | capab = ifmgd->capab; |
280 | 127 | ||
281 | if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ) { | 128 | if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ) { |
282 | if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE)) | 129 | if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE)) |
@@ -285,9 +132,9 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, | |||
285 | capab |= WLAN_CAPABILITY_SHORT_PREAMBLE; | 132 | capab |= WLAN_CAPABILITY_SHORT_PREAMBLE; |
286 | } | 133 | } |
287 | 134 | ||
288 | bss = ieee80211_rx_bss_get(local, ifsta->bssid, | 135 | bss = ieee80211_rx_bss_get(local, ifmgd->bssid, |
289 | local->hw.conf.channel->center_freq, | 136 | local->hw.conf.channel->center_freq, |
290 | ifsta->ssid, ifsta->ssid_len); | 137 | ifmgd->ssid, ifmgd->ssid_len); |
291 | if (bss) { | 138 | if (bss) { |
292 | if (bss->cbss.capability & WLAN_CAPABILITY_PRIVACY) | 139 | if (bss->cbss.capability & WLAN_CAPABILITY_PRIVACY) |
293 | capab |= WLAN_CAPABILITY_PRIVACY; | 140 | capab |= WLAN_CAPABILITY_PRIVACY; |
@@ -312,18 +159,18 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, | |||
312 | 159 | ||
313 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); | 160 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); |
314 | memset(mgmt, 0, 24); | 161 | memset(mgmt, 0, 24); |
315 | memcpy(mgmt->da, ifsta->bssid, ETH_ALEN); | 162 | memcpy(mgmt->da, ifmgd->bssid, ETH_ALEN); |
316 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | 163 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); |
317 | memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); | 164 | memcpy(mgmt->bssid, ifmgd->bssid, ETH_ALEN); |
318 | 165 | ||
319 | if (ifsta->flags & IEEE80211_STA_PREV_BSSID_SET) { | 166 | if (ifmgd->flags & IEEE80211_STA_PREV_BSSID_SET) { |
320 | skb_put(skb, 10); | 167 | skb_put(skb, 10); |
321 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | 168 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | |
322 | IEEE80211_STYPE_REASSOC_REQ); | 169 | IEEE80211_STYPE_REASSOC_REQ); |
323 | mgmt->u.reassoc_req.capab_info = cpu_to_le16(capab); | 170 | mgmt->u.reassoc_req.capab_info = cpu_to_le16(capab); |
324 | mgmt->u.reassoc_req.listen_interval = | 171 | mgmt->u.reassoc_req.listen_interval = |
325 | cpu_to_le16(local->hw.conf.listen_interval); | 172 | cpu_to_le16(local->hw.conf.listen_interval); |
326 | memcpy(mgmt->u.reassoc_req.current_ap, ifsta->prev_bssid, | 173 | memcpy(mgmt->u.reassoc_req.current_ap, ifmgd->prev_bssid, |
327 | ETH_ALEN); | 174 | ETH_ALEN); |
328 | } else { | 175 | } else { |
329 | skb_put(skb, 4); | 176 | skb_put(skb, 4); |
@@ -335,10 +182,10 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, | |||
335 | } | 182 | } |
336 | 183 | ||
337 | /* SSID */ | 184 | /* SSID */ |
338 | ies = pos = skb_put(skb, 2 + ifsta->ssid_len); | 185 | ies = pos = skb_put(skb, 2 + ifmgd->ssid_len); |
339 | *pos++ = WLAN_EID_SSID; | 186 | *pos++ = WLAN_EID_SSID; |
340 | *pos++ = ifsta->ssid_len; | 187 | *pos++ = ifmgd->ssid_len; |
341 | memcpy(pos, ifsta->ssid, ifsta->ssid_len); | 188 | memcpy(pos, ifmgd->ssid, ifmgd->ssid_len); |
342 | 189 | ||
343 | /* add all rates which were marked to be used above */ | 190 | /* add all rates which were marked to be used above */ |
344 | supp_rates_len = rates_len; | 191 | supp_rates_len = rates_len; |
@@ -393,12 +240,12 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, | |||
393 | } | 240 | } |
394 | } | 241 | } |
395 | 242 | ||
396 | if (ifsta->extra_ie) { | 243 | if (ifmgd->extra_ie) { |
397 | pos = skb_put(skb, ifsta->extra_ie_len); | 244 | pos = skb_put(skb, ifmgd->extra_ie_len); |
398 | memcpy(pos, ifsta->extra_ie, ifsta->extra_ie_len); | 245 | memcpy(pos, ifmgd->extra_ie, ifmgd->extra_ie_len); |
399 | } | 246 | } |
400 | 247 | ||
401 | if (wmm && (ifsta->flags & IEEE80211_STA_WMM_ENABLED)) { | 248 | if (wmm && (ifmgd->flags & IEEE80211_STA_WMM_ENABLED)) { |
402 | pos = skb_put(skb, 9); | 249 | pos = skb_put(skb, 9); |
403 | *pos++ = WLAN_EID_VENDOR_SPECIFIC; | 250 | *pos++ = WLAN_EID_VENDOR_SPECIFIC; |
404 | *pos++ = 7; /* len */ | 251 | *pos++ = 7; /* len */ |
@@ -418,11 +265,11 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, | |||
418 | * mode (11a/b/g) if any one of these ciphers is | 265 | * mode (11a/b/g) if any one of these ciphers is |
419 | * configured as pairwise. | 266 | * configured as pairwise. |
420 | */ | 267 | */ |
421 | if (wmm && (ifsta->flags & IEEE80211_STA_WMM_ENABLED) && | 268 | if (wmm && (ifmgd->flags & IEEE80211_STA_WMM_ENABLED) && |
422 | sband->ht_cap.ht_supported && | 269 | sband->ht_cap.ht_supported && |
423 | (ht_ie = ieee80211_bss_get_ie(bss, WLAN_EID_HT_INFORMATION)) && | 270 | (ht_ie = ieee80211_bss_get_ie(bss, WLAN_EID_HT_INFORMATION)) && |
424 | ht_ie[1] >= sizeof(struct ieee80211_ht_info) && | 271 | ht_ie[1] >= sizeof(struct ieee80211_ht_info) && |
425 | (!(ifsta->flags & IEEE80211_STA_TKIP_WEP_USED))) { | 272 | (!(ifmgd->flags & IEEE80211_STA_TKIP_WEP_USED))) { |
426 | struct ieee80211_ht_info *ht_info = | 273 | struct ieee80211_ht_info *ht_info = |
427 | (struct ieee80211_ht_info *)(ht_ie + 2); | 274 | (struct ieee80211_ht_info *)(ht_ie + 2); |
428 | u16 cap = sband->ht_cap.cap; | 275 | u16 cap = sband->ht_cap.cap; |
@@ -459,11 +306,11 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, | |||
459 | 306 | ||
460 | add_extra_ies(skb, e_ies, e_ies_len); | 307 | add_extra_ies(skb, e_ies, e_ies_len); |
461 | 308 | ||
462 | kfree(ifsta->assocreq_ies); | 309 | kfree(ifmgd->assocreq_ies); |
463 | ifsta->assocreq_ies_len = (skb->data + skb->len) - ies; | 310 | ifmgd->assocreq_ies_len = (skb->data + skb->len) - ies; |
464 | ifsta->assocreq_ies = kmalloc(ifsta->assocreq_ies_len, GFP_KERNEL); | 311 | ifmgd->assocreq_ies = kmalloc(ifmgd->assocreq_ies_len, GFP_KERNEL); |
465 | if (ifsta->assocreq_ies) | 312 | if (ifmgd->assocreq_ies) |
466 | memcpy(ifsta->assocreq_ies, ies, ifsta->assocreq_ies_len); | 313 | memcpy(ifmgd->assocreq_ies, ies, ifmgd->assocreq_ies_len); |
467 | 314 | ||
468 | ieee80211_tx_skb(sdata, skb, 0); | 315 | ieee80211_tx_skb(sdata, skb, 0); |
469 | } | 316 | } |
@@ -473,18 +320,18 @@ static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, | |||
473 | u16 stype, u16 reason) | 320 | u16 stype, u16 reason) |
474 | { | 321 | { |
475 | struct ieee80211_local *local = sdata->local; | 322 | struct ieee80211_local *local = sdata->local; |
476 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | 323 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
477 | struct sk_buff *skb; | 324 | struct sk_buff *skb; |
478 | struct ieee80211_mgmt *mgmt; | 325 | struct ieee80211_mgmt *mgmt; |
479 | u8 *ies; | 326 | u8 *ies; |
480 | size_t ies_len; | 327 | size_t ies_len; |
481 | 328 | ||
482 | if (stype == IEEE80211_STYPE_DEAUTH) { | 329 | if (stype == IEEE80211_STYPE_DEAUTH) { |
483 | ies = sdata->u.sta.ie_deauth; | 330 | ies = sdata->u.mgd.ie_deauth; |
484 | ies_len = sdata->u.sta.ie_deauth_len; | 331 | ies_len = sdata->u.mgd.ie_deauth_len; |
485 | } else { | 332 | } else { |
486 | ies = sdata->u.sta.ie_disassoc; | 333 | ies = sdata->u.mgd.ie_disassoc; |
487 | ies_len = sdata->u.sta.ie_disassoc_len; | 334 | ies_len = sdata->u.mgd.ie_disassoc_len; |
488 | } | 335 | } |
489 | 336 | ||
490 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt) + | 337 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt) + |
@@ -498,9 +345,9 @@ static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, | |||
498 | 345 | ||
499 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); | 346 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); |
500 | memset(mgmt, 0, 24); | 347 | memset(mgmt, 0, 24); |
501 | memcpy(mgmt->da, ifsta->bssid, ETH_ALEN); | 348 | memcpy(mgmt->da, ifmgd->bssid, ETH_ALEN); |
502 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | 349 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); |
503 | memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); | 350 | memcpy(mgmt->bssid, ifmgd->bssid, ETH_ALEN); |
504 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | stype); | 351 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | stype); |
505 | skb_put(skb, 2); | 352 | skb_put(skb, 2); |
506 | /* u.deauth.reason_code == u.disassoc.reason_code */ | 353 | /* u.deauth.reason_code == u.disassoc.reason_code */ |
@@ -508,13 +355,13 @@ static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, | |||
508 | 355 | ||
509 | add_extra_ies(skb, ies, ies_len); | 356 | add_extra_ies(skb, ies, ies_len); |
510 | 357 | ||
511 | ieee80211_tx_skb(sdata, skb, ifsta->flags & IEEE80211_STA_MFP_ENABLED); | 358 | ieee80211_tx_skb(sdata, skb, ifmgd->flags & IEEE80211_STA_MFP_ENABLED); |
512 | } | 359 | } |
513 | 360 | ||
514 | void ieee80211_send_pspoll(struct ieee80211_local *local, | 361 | void ieee80211_send_pspoll(struct ieee80211_local *local, |
515 | struct ieee80211_sub_if_data *sdata) | 362 | struct ieee80211_sub_if_data *sdata) |
516 | { | 363 | { |
517 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | 364 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
518 | struct ieee80211_pspoll *pspoll; | 365 | struct ieee80211_pspoll *pspoll; |
519 | struct sk_buff *skb; | 366 | struct sk_buff *skb; |
520 | u16 fc; | 367 | u16 fc; |
@@ -531,43 +378,20 @@ void ieee80211_send_pspoll(struct ieee80211_local *local, | |||
531 | memset(pspoll, 0, sizeof(*pspoll)); | 378 | memset(pspoll, 0, sizeof(*pspoll)); |
532 | fc = IEEE80211_FTYPE_CTL | IEEE80211_STYPE_PSPOLL | IEEE80211_FCTL_PM; | 379 | fc = IEEE80211_FTYPE_CTL | IEEE80211_STYPE_PSPOLL | IEEE80211_FCTL_PM; |
533 | pspoll->frame_control = cpu_to_le16(fc); | 380 | pspoll->frame_control = cpu_to_le16(fc); |
534 | pspoll->aid = cpu_to_le16(ifsta->aid); | 381 | pspoll->aid = cpu_to_le16(ifmgd->aid); |
535 | 382 | ||
536 | /* aid in PS-Poll has its two MSBs each set to 1 */ | 383 | /* aid in PS-Poll has its two MSBs each set to 1 */ |
537 | pspoll->aid |= cpu_to_le16(1 << 15 | 1 << 14); | 384 | pspoll->aid |= cpu_to_le16(1 << 15 | 1 << 14); |
538 | 385 | ||
539 | memcpy(pspoll->bssid, ifsta->bssid, ETH_ALEN); | 386 | memcpy(pspoll->bssid, ifmgd->bssid, ETH_ALEN); |
540 | memcpy(pspoll->ta, sdata->dev->dev_addr, ETH_ALEN); | 387 | memcpy(pspoll->ta, sdata->dev->dev_addr, ETH_ALEN); |
541 | 388 | ||
542 | ieee80211_tx_skb(sdata, skb, 0); | 389 | ieee80211_tx_skb(sdata, skb, 0); |
543 | |||
544 | return; | ||
545 | } | 390 | } |
546 | 391 | ||
547 | /* MLME */ | 392 | /* MLME */ |
548 | static void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata, | ||
549 | const size_t supp_rates_len, | ||
550 | const u8 *supp_rates) | ||
551 | { | ||
552 | struct ieee80211_local *local = sdata->local; | ||
553 | int i, have_higher_than_11mbit = 0; | ||
554 | |||
555 | /* cf. IEEE 802.11 9.2.12 */ | ||
556 | for (i = 0; i < supp_rates_len; i++) | ||
557 | if ((supp_rates[i] & 0x7f) * 5 > 110) | ||
558 | have_higher_than_11mbit = 1; | ||
559 | |||
560 | if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ && | ||
561 | have_higher_than_11mbit) | ||
562 | sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE; | ||
563 | else | ||
564 | sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE; | ||
565 | |||
566 | ieee80211_set_wmm_default(sdata); | ||
567 | } | ||
568 | |||
569 | static void ieee80211_sta_wmm_params(struct ieee80211_local *local, | 393 | static void ieee80211_sta_wmm_params(struct ieee80211_local *local, |
570 | struct ieee80211_if_sta *ifsta, | 394 | struct ieee80211_if_managed *ifmgd, |
571 | u8 *wmm_param, size_t wmm_param_len) | 395 | u8 *wmm_param, size_t wmm_param_len) |
572 | { | 396 | { |
573 | struct ieee80211_tx_queue_params params; | 397 | struct ieee80211_tx_queue_params params; |
@@ -575,7 +399,7 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local, | |||
575 | int count; | 399 | int count; |
576 | u8 *pos; | 400 | u8 *pos; |
577 | 401 | ||
578 | if (!(ifsta->flags & IEEE80211_STA_WMM_ENABLED)) | 402 | if (!(ifmgd->flags & IEEE80211_STA_WMM_ENABLED)) |
579 | return; | 403 | return; |
580 | 404 | ||
581 | if (!wmm_param) | 405 | if (!wmm_param) |
@@ -584,9 +408,9 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local, | |||
584 | if (wmm_param_len < 8 || wmm_param[5] /* version */ != 1) | 408 | if (wmm_param_len < 8 || wmm_param[5] /* version */ != 1) |
585 | return; | 409 | return; |
586 | count = wmm_param[6] & 0x0f; | 410 | count = wmm_param[6] & 0x0f; |
587 | if (count == ifsta->wmm_last_param_set) | 411 | if (count == ifmgd->wmm_last_param_set) |
588 | return; | 412 | return; |
589 | ifsta->wmm_last_param_set = count; | 413 | ifmgd->wmm_last_param_set = count; |
590 | 414 | ||
591 | pos = wmm_param + 8; | 415 | pos = wmm_param + 8; |
592 | left = wmm_param_len - 8; | 416 | left = wmm_param_len - 8; |
@@ -671,7 +495,7 @@ static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata, | |||
671 | { | 495 | { |
672 | struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf; | 496 | struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf; |
673 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 497 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
674 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | 498 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
675 | #endif | 499 | #endif |
676 | u32 changed = 0; | 500 | u32 changed = 0; |
677 | bool use_protection; | 501 | bool use_protection; |
@@ -694,7 +518,7 @@ static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata, | |||
694 | printk(KERN_DEBUG "%s: CTS protection %s (BSSID=%pM)\n", | 518 | printk(KERN_DEBUG "%s: CTS protection %s (BSSID=%pM)\n", |
695 | sdata->dev->name, | 519 | sdata->dev->name, |
696 | use_protection ? "enabled" : "disabled", | 520 | use_protection ? "enabled" : "disabled", |
697 | ifsta->bssid); | 521 | ifmgd->bssid); |
698 | } | 522 | } |
699 | #endif | 523 | #endif |
700 | bss_conf->use_cts_prot = use_protection; | 524 | bss_conf->use_cts_prot = use_protection; |
@@ -708,7 +532,7 @@ static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata, | |||
708 | " (BSSID=%pM)\n", | 532 | " (BSSID=%pM)\n", |
709 | sdata->dev->name, | 533 | sdata->dev->name, |
710 | use_short_preamble ? "short" : "long", | 534 | use_short_preamble ? "short" : "long", |
711 | ifsta->bssid); | 535 | ifmgd->bssid); |
712 | } | 536 | } |
713 | #endif | 537 | #endif |
714 | bss_conf->use_short_preamble = use_short_preamble; | 538 | bss_conf->use_short_preamble = use_short_preamble; |
@@ -722,7 +546,7 @@ static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata, | |||
722 | " (BSSID=%pM)\n", | 546 | " (BSSID=%pM)\n", |
723 | sdata->dev->name, | 547 | sdata->dev->name, |
724 | use_short_slot ? "short" : "long", | 548 | use_short_slot ? "short" : "long", |
725 | ifsta->bssid); | 549 | ifmgd->bssid); |
726 | } | 550 | } |
727 | #endif | 551 | #endif |
728 | bss_conf->use_short_slot = use_short_slot; | 552 | bss_conf->use_short_slot = use_short_slot; |
@@ -732,57 +556,57 @@ static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata, | |||
732 | return changed; | 556 | return changed; |
733 | } | 557 | } |
734 | 558 | ||
735 | static void ieee80211_sta_send_apinfo(struct ieee80211_sub_if_data *sdata, | 559 | static void ieee80211_sta_send_apinfo(struct ieee80211_sub_if_data *sdata) |
736 | struct ieee80211_if_sta *ifsta) | ||
737 | { | 560 | { |
738 | union iwreq_data wrqu; | 561 | union iwreq_data wrqu; |
562 | |||
739 | memset(&wrqu, 0, sizeof(wrqu)); | 563 | memset(&wrqu, 0, sizeof(wrqu)); |
740 | if (ifsta->flags & IEEE80211_STA_ASSOCIATED) | 564 | if (sdata->u.mgd.flags & IEEE80211_STA_ASSOCIATED) |
741 | memcpy(wrqu.ap_addr.sa_data, sdata->u.sta.bssid, ETH_ALEN); | 565 | memcpy(wrqu.ap_addr.sa_data, sdata->u.mgd.bssid, ETH_ALEN); |
742 | wrqu.ap_addr.sa_family = ARPHRD_ETHER; | 566 | wrqu.ap_addr.sa_family = ARPHRD_ETHER; |
743 | wireless_send_event(sdata->dev, SIOCGIWAP, &wrqu, NULL); | 567 | wireless_send_event(sdata->dev, SIOCGIWAP, &wrqu, NULL); |
744 | } | 568 | } |
745 | 569 | ||
746 | static void ieee80211_sta_send_associnfo(struct ieee80211_sub_if_data *sdata, | 570 | static void ieee80211_sta_send_associnfo(struct ieee80211_sub_if_data *sdata) |
747 | struct ieee80211_if_sta *ifsta) | ||
748 | { | 571 | { |
572 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
749 | char *buf; | 573 | char *buf; |
750 | size_t len; | 574 | size_t len; |
751 | int i; | 575 | int i; |
752 | union iwreq_data wrqu; | 576 | union iwreq_data wrqu; |
753 | 577 | ||
754 | if (!ifsta->assocreq_ies && !ifsta->assocresp_ies) | 578 | if (!ifmgd->assocreq_ies && !ifmgd->assocresp_ies) |
755 | return; | 579 | return; |
756 | 580 | ||
757 | buf = kmalloc(50 + 2 * (ifsta->assocreq_ies_len + | 581 | buf = kmalloc(50 + 2 * (ifmgd->assocreq_ies_len + |
758 | ifsta->assocresp_ies_len), GFP_KERNEL); | 582 | ifmgd->assocresp_ies_len), GFP_KERNEL); |
759 | if (!buf) | 583 | if (!buf) |
760 | return; | 584 | return; |
761 | 585 | ||
762 | len = sprintf(buf, "ASSOCINFO("); | 586 | len = sprintf(buf, "ASSOCINFO("); |
763 | if (ifsta->assocreq_ies) { | 587 | if (ifmgd->assocreq_ies) { |
764 | len += sprintf(buf + len, "ReqIEs="); | 588 | len += sprintf(buf + len, "ReqIEs="); |
765 | for (i = 0; i < ifsta->assocreq_ies_len; i++) { | 589 | for (i = 0; i < ifmgd->assocreq_ies_len; i++) { |
766 | len += sprintf(buf + len, "%02x", | 590 | len += sprintf(buf + len, "%02x", |
767 | ifsta->assocreq_ies[i]); | 591 | ifmgd->assocreq_ies[i]); |
768 | } | 592 | } |
769 | } | 593 | } |
770 | if (ifsta->assocresp_ies) { | 594 | if (ifmgd->assocresp_ies) { |
771 | if (ifsta->assocreq_ies) | 595 | if (ifmgd->assocreq_ies) |
772 | len += sprintf(buf + len, " "); | 596 | len += sprintf(buf + len, " "); |
773 | len += sprintf(buf + len, "RespIEs="); | 597 | len += sprintf(buf + len, "RespIEs="); |
774 | for (i = 0; i < ifsta->assocresp_ies_len; i++) { | 598 | for (i = 0; i < ifmgd->assocresp_ies_len; i++) { |
775 | len += sprintf(buf + len, "%02x", | 599 | len += sprintf(buf + len, "%02x", |
776 | ifsta->assocresp_ies[i]); | 600 | ifmgd->assocresp_ies[i]); |
777 | } | 601 | } |
778 | } | 602 | } |
779 | len += sprintf(buf + len, ")"); | 603 | len += sprintf(buf + len, ")"); |
780 | 604 | ||
781 | if (len > IW_CUSTOM_MAX) { | 605 | if (len > IW_CUSTOM_MAX) { |
782 | len = sprintf(buf, "ASSOCRESPIE="); | 606 | len = sprintf(buf, "ASSOCRESPIE="); |
783 | for (i = 0; i < ifsta->assocresp_ies_len; i++) { | 607 | for (i = 0; i < ifmgd->assocresp_ies_len; i++) { |
784 | len += sprintf(buf + len, "%02x", | 608 | len += sprintf(buf + len, "%02x", |
785 | ifsta->assocresp_ies[i]); | 609 | ifmgd->assocresp_ies[i]); |
786 | } | 610 | } |
787 | } | 611 | } |
788 | 612 | ||
@@ -797,20 +621,20 @@ static void ieee80211_sta_send_associnfo(struct ieee80211_sub_if_data *sdata, | |||
797 | 621 | ||
798 | 622 | ||
799 | static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, | 623 | static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, |
800 | struct ieee80211_if_sta *ifsta, | ||
801 | u32 bss_info_changed) | 624 | u32 bss_info_changed) |
802 | { | 625 | { |
626 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
803 | struct ieee80211_local *local = sdata->local; | 627 | struct ieee80211_local *local = sdata->local; |
804 | struct ieee80211_conf *conf = &local_to_hw(local)->conf; | 628 | struct ieee80211_conf *conf = &local_to_hw(local)->conf; |
805 | 629 | ||
806 | struct ieee80211_bss *bss; | 630 | struct ieee80211_bss *bss; |
807 | 631 | ||
808 | bss_info_changed |= BSS_CHANGED_ASSOC; | 632 | bss_info_changed |= BSS_CHANGED_ASSOC; |
809 | ifsta->flags |= IEEE80211_STA_ASSOCIATED; | 633 | ifmgd->flags |= IEEE80211_STA_ASSOCIATED; |
810 | 634 | ||
811 | bss = ieee80211_rx_bss_get(local, ifsta->bssid, | 635 | bss = ieee80211_rx_bss_get(local, ifmgd->bssid, |
812 | conf->channel->center_freq, | 636 | conf->channel->center_freq, |
813 | ifsta->ssid, ifsta->ssid_len); | 637 | ifmgd->ssid, ifmgd->ssid_len); |
814 | if (bss) { | 638 | if (bss) { |
815 | /* set timing information */ | 639 | /* set timing information */ |
816 | sdata->vif.bss_conf.beacon_int = bss->cbss.beacon_interval; | 640 | sdata->vif.bss_conf.beacon_int = bss->cbss.beacon_interval; |
@@ -823,11 +647,11 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, | |||
823 | ieee80211_rx_bss_put(local, bss); | 647 | ieee80211_rx_bss_put(local, bss); |
824 | } | 648 | } |
825 | 649 | ||
826 | ifsta->flags |= IEEE80211_STA_PREV_BSSID_SET; | 650 | ifmgd->flags |= IEEE80211_STA_PREV_BSSID_SET; |
827 | memcpy(ifsta->prev_bssid, sdata->u.sta.bssid, ETH_ALEN); | 651 | memcpy(ifmgd->prev_bssid, sdata->u.mgd.bssid, ETH_ALEN); |
828 | ieee80211_sta_send_associnfo(sdata, ifsta); | 652 | ieee80211_sta_send_associnfo(sdata); |
829 | 653 | ||
830 | ifsta->last_probe = jiffies; | 654 | ifmgd->last_probe = jiffies; |
831 | ieee80211_led_assoc(local, 1); | 655 | ieee80211_led_assoc(local, 1); |
832 | 656 | ||
833 | sdata->vif.bss_conf.assoc = 1; | 657 | sdata->vif.bss_conf.assoc = 1; |
@@ -856,70 +680,74 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, | |||
856 | netif_tx_start_all_queues(sdata->dev); | 680 | netif_tx_start_all_queues(sdata->dev); |
857 | netif_carrier_on(sdata->dev); | 681 | netif_carrier_on(sdata->dev); |
858 | 682 | ||
859 | ieee80211_sta_send_apinfo(sdata, ifsta); | 683 | ieee80211_sta_send_apinfo(sdata); |
860 | } | 684 | } |
861 | 685 | ||
862 | static void ieee80211_direct_probe(struct ieee80211_sub_if_data *sdata, | 686 | static void ieee80211_direct_probe(struct ieee80211_sub_if_data *sdata) |
863 | struct ieee80211_if_sta *ifsta) | ||
864 | { | 687 | { |
865 | ifsta->direct_probe_tries++; | 688 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
866 | if (ifsta->direct_probe_tries > IEEE80211_AUTH_MAX_TRIES) { | 689 | |
690 | ifmgd->direct_probe_tries++; | ||
691 | if (ifmgd->direct_probe_tries > IEEE80211_AUTH_MAX_TRIES) { | ||
867 | printk(KERN_DEBUG "%s: direct probe to AP %pM timed out\n", | 692 | printk(KERN_DEBUG "%s: direct probe to AP %pM timed out\n", |
868 | sdata->dev->name, ifsta->bssid); | 693 | sdata->dev->name, ifmgd->bssid); |
869 | ifsta->state = IEEE80211_STA_MLME_DISABLED; | 694 | ifmgd->state = IEEE80211_STA_MLME_DISABLED; |
870 | ieee80211_sta_send_apinfo(sdata, ifsta); | 695 | ieee80211_sta_send_apinfo(sdata); |
871 | 696 | ||
872 | /* | 697 | /* |
873 | * Most likely AP is not in the range so remove the | 698 | * Most likely AP is not in the range so remove the |
874 | * bss information associated to the AP | 699 | * bss information associated to the AP |
875 | */ | 700 | */ |
876 | ieee80211_rx_bss_remove(sdata, ifsta->bssid, | 701 | ieee80211_rx_bss_remove(sdata, ifmgd->bssid, |
877 | sdata->local->hw.conf.channel->center_freq, | 702 | sdata->local->hw.conf.channel->center_freq, |
878 | ifsta->ssid, ifsta->ssid_len); | 703 | ifmgd->ssid, ifmgd->ssid_len); |
879 | return; | 704 | return; |
880 | } | 705 | } |
881 | 706 | ||
882 | printk(KERN_DEBUG "%s: direct probe to AP %pM try %d\n", | 707 | printk(KERN_DEBUG "%s: direct probe to AP %pM try %d\n", |
883 | sdata->dev->name, ifsta->bssid, | 708 | sdata->dev->name, ifmgd->bssid, |
884 | ifsta->direct_probe_tries); | 709 | ifmgd->direct_probe_tries); |
885 | 710 | ||
886 | ifsta->state = IEEE80211_STA_MLME_DIRECT_PROBE; | 711 | ifmgd->state = IEEE80211_STA_MLME_DIRECT_PROBE; |
887 | 712 | ||
888 | set_bit(IEEE80211_STA_REQ_DIRECT_PROBE, &ifsta->request); | 713 | set_bit(IEEE80211_STA_REQ_DIRECT_PROBE, &ifmgd->request); |
889 | 714 | ||
890 | /* Direct probe is sent to broadcast address as some APs | 715 | /* Direct probe is sent to broadcast address as some APs |
891 | * will not answer to direct packet in unassociated state. | 716 | * will not answer to direct packet in unassociated state. |
892 | */ | 717 | */ |
893 | ieee80211_send_probe_req(sdata, NULL, | 718 | ieee80211_send_probe_req(sdata, NULL, |
894 | ifsta->ssid, ifsta->ssid_len); | 719 | ifmgd->ssid, ifmgd->ssid_len, NULL, 0); |
895 | 720 | ||
896 | mod_timer(&ifsta->timer, jiffies + IEEE80211_AUTH_TIMEOUT); | 721 | mod_timer(&ifmgd->timer, jiffies + IEEE80211_AUTH_TIMEOUT); |
897 | } | 722 | } |
898 | 723 | ||
899 | 724 | ||
900 | static void ieee80211_authenticate(struct ieee80211_sub_if_data *sdata, | 725 | static void ieee80211_authenticate(struct ieee80211_sub_if_data *sdata) |
901 | struct ieee80211_if_sta *ifsta) | ||
902 | { | 726 | { |
903 | ifsta->auth_tries++; | 727 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
904 | if (ifsta->auth_tries > IEEE80211_AUTH_MAX_TRIES) { | 728 | |
729 | ifmgd->auth_tries++; | ||
730 | if (ifmgd->auth_tries > IEEE80211_AUTH_MAX_TRIES) { | ||
905 | printk(KERN_DEBUG "%s: authentication with AP %pM" | 731 | printk(KERN_DEBUG "%s: authentication with AP %pM" |
906 | " timed out\n", | 732 | " timed out\n", |
907 | sdata->dev->name, ifsta->bssid); | 733 | sdata->dev->name, ifmgd->bssid); |
908 | ifsta->state = IEEE80211_STA_MLME_DISABLED; | 734 | ifmgd->state = IEEE80211_STA_MLME_DISABLED; |
909 | ieee80211_sta_send_apinfo(sdata, ifsta); | 735 | ieee80211_sta_send_apinfo(sdata); |
910 | ieee80211_rx_bss_remove(sdata, ifsta->bssid, | 736 | ieee80211_rx_bss_remove(sdata, ifmgd->bssid, |
911 | sdata->local->hw.conf.channel->center_freq, | 737 | sdata->local->hw.conf.channel->center_freq, |
912 | ifsta->ssid, ifsta->ssid_len); | 738 | ifmgd->ssid, ifmgd->ssid_len); |
913 | return; | 739 | return; |
914 | } | 740 | } |
915 | 741 | ||
916 | ifsta->state = IEEE80211_STA_MLME_AUTHENTICATE; | 742 | ifmgd->state = IEEE80211_STA_MLME_AUTHENTICATE; |
917 | printk(KERN_DEBUG "%s: authenticate with AP %pM\n", | 743 | printk(KERN_DEBUG "%s: authenticate with AP %pM\n", |
918 | sdata->dev->name, ifsta->bssid); | 744 | sdata->dev->name, ifmgd->bssid); |
919 | 745 | ||
920 | ieee80211_send_auth(sdata, ifsta, 1, NULL, 0, 0); | 746 | ieee80211_send_auth(sdata, 1, ifmgd->auth_alg, NULL, 0, |
747 | ifmgd->bssid, 0); | ||
748 | ifmgd->auth_transaction = 2; | ||
921 | 749 | ||
922 | mod_timer(&ifsta->timer, jiffies + IEEE80211_AUTH_TIMEOUT); | 750 | mod_timer(&ifmgd->timer, jiffies + IEEE80211_AUTH_TIMEOUT); |
923 | } | 751 | } |
924 | 752 | ||
925 | /* | 753 | /* |
@@ -927,27 +755,28 @@ static void ieee80211_authenticate(struct ieee80211_sub_if_data *sdata, | |||
927 | * if self disconnected or a reason code from the AP. | 755 | * if self disconnected or a reason code from the AP. |
928 | */ | 756 | */ |
929 | static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | 757 | static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, |
930 | struct ieee80211_if_sta *ifsta, bool deauth, | 758 | bool deauth, bool self_disconnected, |
931 | bool self_disconnected, u16 reason) | 759 | u16 reason) |
932 | { | 760 | { |
761 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
933 | struct ieee80211_local *local = sdata->local; | 762 | struct ieee80211_local *local = sdata->local; |
934 | struct sta_info *sta; | 763 | struct sta_info *sta; |
935 | u32 changed = 0, config_changed = 0; | 764 | u32 changed = 0, config_changed = 0; |
936 | 765 | ||
937 | rcu_read_lock(); | 766 | rcu_read_lock(); |
938 | 767 | ||
939 | sta = sta_info_get(local, ifsta->bssid); | 768 | sta = sta_info_get(local, ifmgd->bssid); |
940 | if (!sta) { | 769 | if (!sta) { |
941 | rcu_read_unlock(); | 770 | rcu_read_unlock(); |
942 | return; | 771 | return; |
943 | } | 772 | } |
944 | 773 | ||
945 | if (deauth) { | 774 | if (deauth) { |
946 | ifsta->direct_probe_tries = 0; | 775 | ifmgd->direct_probe_tries = 0; |
947 | ifsta->auth_tries = 0; | 776 | ifmgd->auth_tries = 0; |
948 | } | 777 | } |
949 | ifsta->assoc_scan_tries = 0; | 778 | ifmgd->assoc_scan_tries = 0; |
950 | ifsta->assoc_tries = 0; | 779 | ifmgd->assoc_tries = 0; |
951 | 780 | ||
952 | netif_tx_stop_all_queues(sdata->dev); | 781 | netif_tx_stop_all_queues(sdata->dev); |
953 | netif_carrier_off(sdata->dev); | 782 | netif_carrier_off(sdata->dev); |
@@ -963,20 +792,20 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | |||
963 | IEEE80211_STYPE_DISASSOC, reason); | 792 | IEEE80211_STYPE_DISASSOC, reason); |
964 | } | 793 | } |
965 | 794 | ||
966 | ifsta->flags &= ~IEEE80211_STA_ASSOCIATED; | 795 | ifmgd->flags &= ~IEEE80211_STA_ASSOCIATED; |
967 | changed |= ieee80211_reset_erp_info(sdata); | 796 | changed |= ieee80211_reset_erp_info(sdata); |
968 | 797 | ||
969 | ieee80211_led_assoc(local, 0); | 798 | ieee80211_led_assoc(local, 0); |
970 | changed |= BSS_CHANGED_ASSOC; | 799 | changed |= BSS_CHANGED_ASSOC; |
971 | sdata->vif.bss_conf.assoc = false; | 800 | sdata->vif.bss_conf.assoc = false; |
972 | 801 | ||
973 | ieee80211_sta_send_apinfo(sdata, ifsta); | 802 | ieee80211_sta_send_apinfo(sdata); |
974 | 803 | ||
975 | if (self_disconnected || reason == WLAN_REASON_DISASSOC_STA_HAS_LEFT) { | 804 | if (self_disconnected || reason == WLAN_REASON_DISASSOC_STA_HAS_LEFT) { |
976 | ifsta->state = IEEE80211_STA_MLME_DISABLED; | 805 | ifmgd->state = IEEE80211_STA_MLME_DISABLED; |
977 | ieee80211_rx_bss_remove(sdata, ifsta->bssid, | 806 | ieee80211_rx_bss_remove(sdata, ifmgd->bssid, |
978 | sdata->local->hw.conf.channel->center_freq, | 807 | sdata->local->hw.conf.channel->center_freq, |
979 | ifsta->ssid, ifsta->ssid_len); | 808 | ifmgd->ssid, ifmgd->ssid_len); |
980 | } | 809 | } |
981 | 810 | ||
982 | rcu_read_unlock(); | 811 | rcu_read_unlock(); |
@@ -999,7 +828,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | |||
999 | 828 | ||
1000 | rcu_read_lock(); | 829 | rcu_read_lock(); |
1001 | 830 | ||
1002 | sta = sta_info_get(local, ifsta->bssid); | 831 | sta = sta_info_get(local, ifmgd->bssid); |
1003 | if (!sta) { | 832 | if (!sta) { |
1004 | rcu_read_unlock(); | 833 | rcu_read_unlock(); |
1005 | return; | 834 | return; |
@@ -1020,27 +849,27 @@ static int ieee80211_sta_wep_configured(struct ieee80211_sub_if_data *sdata) | |||
1020 | return 1; | 849 | return 1; |
1021 | } | 850 | } |
1022 | 851 | ||
1023 | static int ieee80211_privacy_mismatch(struct ieee80211_sub_if_data *sdata, | 852 | static int ieee80211_privacy_mismatch(struct ieee80211_sub_if_data *sdata) |
1024 | struct ieee80211_if_sta *ifsta) | ||
1025 | { | 853 | { |
854 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
1026 | struct ieee80211_local *local = sdata->local; | 855 | struct ieee80211_local *local = sdata->local; |
1027 | struct ieee80211_bss *bss; | 856 | struct ieee80211_bss *bss; |
1028 | int bss_privacy; | 857 | int bss_privacy; |
1029 | int wep_privacy; | 858 | int wep_privacy; |
1030 | int privacy_invoked; | 859 | int privacy_invoked; |
1031 | 860 | ||
1032 | if (!ifsta || (ifsta->flags & IEEE80211_STA_MIXED_CELL)) | 861 | if (!ifmgd || (ifmgd->flags & IEEE80211_STA_MIXED_CELL)) |
1033 | return 0; | 862 | return 0; |
1034 | 863 | ||
1035 | bss = ieee80211_rx_bss_get(local, ifsta->bssid, | 864 | bss = ieee80211_rx_bss_get(local, ifmgd->bssid, |
1036 | local->hw.conf.channel->center_freq, | 865 | local->hw.conf.channel->center_freq, |
1037 | ifsta->ssid, ifsta->ssid_len); | 866 | ifmgd->ssid, ifmgd->ssid_len); |
1038 | if (!bss) | 867 | if (!bss) |
1039 | return 0; | 868 | return 0; |
1040 | 869 | ||
1041 | bss_privacy = !!(bss->cbss.capability & WLAN_CAPABILITY_PRIVACY); | 870 | bss_privacy = !!(bss->cbss.capability & WLAN_CAPABILITY_PRIVACY); |
1042 | wep_privacy = !!ieee80211_sta_wep_configured(sdata); | 871 | wep_privacy = !!ieee80211_sta_wep_configured(sdata); |
1043 | privacy_invoked = !!(ifsta->flags & IEEE80211_STA_PRIVACY_INVOKED); | 872 | privacy_invoked = !!(ifmgd->flags & IEEE80211_STA_PRIVACY_INVOKED); |
1044 | 873 | ||
1045 | ieee80211_rx_bss_put(local, bss); | 874 | ieee80211_rx_bss_put(local, bss); |
1046 | 875 | ||
@@ -1050,41 +879,42 @@ static int ieee80211_privacy_mismatch(struct ieee80211_sub_if_data *sdata, | |||
1050 | return 1; | 879 | return 1; |
1051 | } | 880 | } |
1052 | 881 | ||
1053 | static void ieee80211_associate(struct ieee80211_sub_if_data *sdata, | 882 | static void ieee80211_associate(struct ieee80211_sub_if_data *sdata) |
1054 | struct ieee80211_if_sta *ifsta) | ||
1055 | { | 883 | { |
1056 | ifsta->assoc_tries++; | 884 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
1057 | if (ifsta->assoc_tries > IEEE80211_ASSOC_MAX_TRIES) { | 885 | |
886 | ifmgd->assoc_tries++; | ||
887 | if (ifmgd->assoc_tries > IEEE80211_ASSOC_MAX_TRIES) { | ||
1058 | printk(KERN_DEBUG "%s: association with AP %pM" | 888 | printk(KERN_DEBUG "%s: association with AP %pM" |
1059 | " timed out\n", | 889 | " timed out\n", |
1060 | sdata->dev->name, ifsta->bssid); | 890 | sdata->dev->name, ifmgd->bssid); |
1061 | ifsta->state = IEEE80211_STA_MLME_DISABLED; | 891 | ifmgd->state = IEEE80211_STA_MLME_DISABLED; |
1062 | ieee80211_sta_send_apinfo(sdata, ifsta); | 892 | ieee80211_sta_send_apinfo(sdata); |
1063 | ieee80211_rx_bss_remove(sdata, ifsta->bssid, | 893 | ieee80211_rx_bss_remove(sdata, ifmgd->bssid, |
1064 | sdata->local->hw.conf.channel->center_freq, | 894 | sdata->local->hw.conf.channel->center_freq, |
1065 | ifsta->ssid, ifsta->ssid_len); | 895 | ifmgd->ssid, ifmgd->ssid_len); |
1066 | return; | 896 | return; |
1067 | } | 897 | } |
1068 | 898 | ||
1069 | ifsta->state = IEEE80211_STA_MLME_ASSOCIATE; | 899 | ifmgd->state = IEEE80211_STA_MLME_ASSOCIATE; |
1070 | printk(KERN_DEBUG "%s: associate with AP %pM\n", | 900 | printk(KERN_DEBUG "%s: associate with AP %pM\n", |
1071 | sdata->dev->name, ifsta->bssid); | 901 | sdata->dev->name, ifmgd->bssid); |
1072 | if (ieee80211_privacy_mismatch(sdata, ifsta)) { | 902 | if (ieee80211_privacy_mismatch(sdata)) { |
1073 | printk(KERN_DEBUG "%s: mismatch in privacy configuration and " | 903 | printk(KERN_DEBUG "%s: mismatch in privacy configuration and " |
1074 | "mixed-cell disabled - abort association\n", sdata->dev->name); | 904 | "mixed-cell disabled - abort association\n", sdata->dev->name); |
1075 | ifsta->state = IEEE80211_STA_MLME_DISABLED; | 905 | ifmgd->state = IEEE80211_STA_MLME_DISABLED; |
1076 | return; | 906 | return; |
1077 | } | 907 | } |
1078 | 908 | ||
1079 | ieee80211_send_assoc(sdata, ifsta); | 909 | ieee80211_send_assoc(sdata); |
1080 | 910 | ||
1081 | mod_timer(&ifsta->timer, jiffies + IEEE80211_ASSOC_TIMEOUT); | 911 | mod_timer(&ifmgd->timer, jiffies + IEEE80211_ASSOC_TIMEOUT); |
1082 | } | 912 | } |
1083 | 913 | ||
1084 | 914 | ||
1085 | static void ieee80211_associated(struct ieee80211_sub_if_data *sdata, | 915 | static void ieee80211_associated(struct ieee80211_sub_if_data *sdata) |
1086 | struct ieee80211_if_sta *ifsta) | ||
1087 | { | 916 | { |
917 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
1088 | struct ieee80211_local *local = sdata->local; | 918 | struct ieee80211_local *local = sdata->local; |
1089 | struct sta_info *sta; | 919 | struct sta_info *sta; |
1090 | int disassoc; | 920 | int disassoc; |
@@ -1094,38 +924,40 @@ static void ieee80211_associated(struct ieee80211_sub_if_data *sdata, | |||
1094 | * for better APs. */ | 924 | * for better APs. */ |
1095 | /* TODO: remove expired BSSes */ | 925 | /* TODO: remove expired BSSes */ |
1096 | 926 | ||
1097 | ifsta->state = IEEE80211_STA_MLME_ASSOCIATED; | 927 | ifmgd->state = IEEE80211_STA_MLME_ASSOCIATED; |
1098 | 928 | ||
1099 | rcu_read_lock(); | 929 | rcu_read_lock(); |
1100 | 930 | ||
1101 | sta = sta_info_get(local, ifsta->bssid); | 931 | sta = sta_info_get(local, ifmgd->bssid); |
1102 | if (!sta) { | 932 | if (!sta) { |
1103 | printk(KERN_DEBUG "%s: No STA entry for own AP %pM\n", | 933 | printk(KERN_DEBUG "%s: No STA entry for own AP %pM\n", |
1104 | sdata->dev->name, ifsta->bssid); | 934 | sdata->dev->name, ifmgd->bssid); |
1105 | disassoc = 1; | 935 | disassoc = 1; |
1106 | } else { | 936 | } else { |
1107 | disassoc = 0; | 937 | disassoc = 0; |
1108 | if (time_after(jiffies, | 938 | if (time_after(jiffies, |
1109 | sta->last_rx + IEEE80211_MONITORING_INTERVAL)) { | 939 | sta->last_rx + IEEE80211_MONITORING_INTERVAL)) { |
1110 | if (ifsta->flags & IEEE80211_STA_PROBEREQ_POLL) { | 940 | if (ifmgd->flags & IEEE80211_STA_PROBEREQ_POLL) { |
1111 | printk(KERN_DEBUG "%s: No ProbeResp from " | 941 | printk(KERN_DEBUG "%s: No ProbeResp from " |
1112 | "current AP %pM - assume out of " | 942 | "current AP %pM - assume out of " |
1113 | "range\n", | 943 | "range\n", |
1114 | sdata->dev->name, ifsta->bssid); | 944 | sdata->dev->name, ifmgd->bssid); |
1115 | disassoc = 1; | 945 | disassoc = 1; |
1116 | } else | 946 | } else |
1117 | ieee80211_send_probe_req(sdata, ifsta->bssid, | 947 | ieee80211_send_probe_req(sdata, ifmgd->bssid, |
1118 | ifsta->ssid, | 948 | ifmgd->ssid, |
1119 | ifsta->ssid_len); | 949 | ifmgd->ssid_len, |
1120 | ifsta->flags ^= IEEE80211_STA_PROBEREQ_POLL; | 950 | NULL, 0); |
951 | ifmgd->flags ^= IEEE80211_STA_PROBEREQ_POLL; | ||
1121 | } else { | 952 | } else { |
1122 | ifsta->flags &= ~IEEE80211_STA_PROBEREQ_POLL; | 953 | ifmgd->flags &= ~IEEE80211_STA_PROBEREQ_POLL; |
1123 | if (time_after(jiffies, ifsta->last_probe + | 954 | if (time_after(jiffies, ifmgd->last_probe + |
1124 | IEEE80211_PROBE_INTERVAL)) { | 955 | IEEE80211_PROBE_INTERVAL)) { |
1125 | ifsta->last_probe = jiffies; | 956 | ifmgd->last_probe = jiffies; |
1126 | ieee80211_send_probe_req(sdata, ifsta->bssid, | 957 | ieee80211_send_probe_req(sdata, ifmgd->bssid, |
1127 | ifsta->ssid, | 958 | ifmgd->ssid, |
1128 | ifsta->ssid_len); | 959 | ifmgd->ssid_len, |
960 | NULL, 0); | ||
1129 | } | 961 | } |
1130 | } | 962 | } |
1131 | } | 963 | } |
@@ -1133,25 +965,25 @@ static void ieee80211_associated(struct ieee80211_sub_if_data *sdata, | |||
1133 | rcu_read_unlock(); | 965 | rcu_read_unlock(); |
1134 | 966 | ||
1135 | if (disassoc) | 967 | if (disassoc) |
1136 | ieee80211_set_disassoc(sdata, ifsta, true, true, | 968 | ieee80211_set_disassoc(sdata, true, true, |
1137 | WLAN_REASON_PREV_AUTH_NOT_VALID); | 969 | WLAN_REASON_PREV_AUTH_NOT_VALID); |
1138 | else | 970 | else |
1139 | mod_timer(&ifsta->timer, jiffies + | 971 | mod_timer(&ifmgd->timer, jiffies + |
1140 | IEEE80211_MONITORING_INTERVAL); | 972 | IEEE80211_MONITORING_INTERVAL); |
1141 | } | 973 | } |
1142 | 974 | ||
1143 | 975 | ||
1144 | static void ieee80211_auth_completed(struct ieee80211_sub_if_data *sdata, | 976 | static void ieee80211_auth_completed(struct ieee80211_sub_if_data *sdata) |
1145 | struct ieee80211_if_sta *ifsta) | ||
1146 | { | 977 | { |
978 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
979 | |||
1147 | printk(KERN_DEBUG "%s: authenticated\n", sdata->dev->name); | 980 | printk(KERN_DEBUG "%s: authenticated\n", sdata->dev->name); |
1148 | ifsta->flags |= IEEE80211_STA_AUTHENTICATED; | 981 | ifmgd->flags |= IEEE80211_STA_AUTHENTICATED; |
1149 | ieee80211_associate(sdata, ifsta); | 982 | ieee80211_associate(sdata); |
1150 | } | 983 | } |
1151 | 984 | ||
1152 | 985 | ||
1153 | static void ieee80211_auth_challenge(struct ieee80211_sub_if_data *sdata, | 986 | static void ieee80211_auth_challenge(struct ieee80211_sub_if_data *sdata, |
1154 | struct ieee80211_if_sta *ifsta, | ||
1155 | struct ieee80211_mgmt *mgmt, | 987 | struct ieee80211_mgmt *mgmt, |
1156 | size_t len) | 988 | size_t len) |
1157 | { | 989 | { |
@@ -1162,59 +994,37 @@ static void ieee80211_auth_challenge(struct ieee80211_sub_if_data *sdata, | |||
1162 | ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems); | 994 | ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems); |
1163 | if (!elems.challenge) | 995 | if (!elems.challenge) |
1164 | return; | 996 | return; |
1165 | ieee80211_send_auth(sdata, ifsta, 3, elems.challenge - 2, | 997 | ieee80211_send_auth(sdata, 3, sdata->u.mgd.auth_alg, |
1166 | elems.challenge_len + 2, 1); | 998 | elems.challenge - 2, elems.challenge_len + 2, |
1167 | } | 999 | sdata->u.mgd.bssid, 1); |
1168 | 1000 | sdata->u.mgd.auth_transaction = 4; | |
1169 | static void ieee80211_rx_mgmt_auth_ibss(struct ieee80211_sub_if_data *sdata, | ||
1170 | struct ieee80211_if_sta *ifsta, | ||
1171 | struct ieee80211_mgmt *mgmt, | ||
1172 | size_t len) | ||
1173 | { | ||
1174 | u16 auth_alg, auth_transaction, status_code; | ||
1175 | |||
1176 | if (len < 24 + 6) | ||
1177 | return; | ||
1178 | |||
1179 | auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg); | ||
1180 | auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction); | ||
1181 | status_code = le16_to_cpu(mgmt->u.auth.status_code); | ||
1182 | |||
1183 | /* | ||
1184 | * IEEE 802.11 standard does not require authentication in IBSS | ||
1185 | * networks and most implementations do not seem to use it. | ||
1186 | * However, try to reply to authentication attempts if someone | ||
1187 | * has actually implemented this. | ||
1188 | */ | ||
1189 | if (auth_alg == WLAN_AUTH_OPEN && auth_transaction == 1) | ||
1190 | ieee80211_send_auth(sdata, ifsta, 2, NULL, 0, 0); | ||
1191 | } | 1001 | } |
1192 | 1002 | ||
1193 | static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, | 1003 | static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, |
1194 | struct ieee80211_if_sta *ifsta, | ||
1195 | struct ieee80211_mgmt *mgmt, | 1004 | struct ieee80211_mgmt *mgmt, |
1196 | size_t len) | 1005 | size_t len) |
1197 | { | 1006 | { |
1007 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
1198 | u16 auth_alg, auth_transaction, status_code; | 1008 | u16 auth_alg, auth_transaction, status_code; |
1199 | 1009 | ||
1200 | if (ifsta->state != IEEE80211_STA_MLME_AUTHENTICATE) | 1010 | if (ifmgd->state != IEEE80211_STA_MLME_AUTHENTICATE) |
1201 | return; | 1011 | return; |
1202 | 1012 | ||
1203 | if (len < 24 + 6) | 1013 | if (len < 24 + 6) |
1204 | return; | 1014 | return; |
1205 | 1015 | ||
1206 | if (memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) != 0) | 1016 | if (memcmp(ifmgd->bssid, mgmt->sa, ETH_ALEN) != 0) |
1207 | return; | 1017 | return; |
1208 | 1018 | ||
1209 | if (memcmp(ifsta->bssid, mgmt->bssid, ETH_ALEN) != 0) | 1019 | if (memcmp(ifmgd->bssid, mgmt->bssid, ETH_ALEN) != 0) |
1210 | return; | 1020 | return; |
1211 | 1021 | ||
1212 | auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg); | 1022 | auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg); |
1213 | auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction); | 1023 | auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction); |
1214 | status_code = le16_to_cpu(mgmt->u.auth.status_code); | 1024 | status_code = le16_to_cpu(mgmt->u.auth.status_code); |
1215 | 1025 | ||
1216 | if (auth_alg != ifsta->auth_alg || | 1026 | if (auth_alg != ifmgd->auth_alg || |
1217 | auth_transaction != ifsta->auth_transaction) | 1027 | auth_transaction != ifmgd->auth_transaction) |
1218 | return; | 1028 | return; |
1219 | 1029 | ||
1220 | if (status_code != WLAN_STATUS_SUCCESS) { | 1030 | if (status_code != WLAN_STATUS_SUCCESS) { |
@@ -1223,15 +1033,15 @@ static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, | |||
1223 | const int num_algs = ARRAY_SIZE(algs); | 1033 | const int num_algs = ARRAY_SIZE(algs); |
1224 | int i, pos; | 1034 | int i, pos; |
1225 | algs[0] = algs[1] = algs[2] = 0xff; | 1035 | algs[0] = algs[1] = algs[2] = 0xff; |
1226 | if (ifsta->auth_algs & IEEE80211_AUTH_ALG_OPEN) | 1036 | if (ifmgd->auth_algs & IEEE80211_AUTH_ALG_OPEN) |
1227 | algs[0] = WLAN_AUTH_OPEN; | 1037 | algs[0] = WLAN_AUTH_OPEN; |
1228 | if (ifsta->auth_algs & IEEE80211_AUTH_ALG_SHARED_KEY) | 1038 | if (ifmgd->auth_algs & IEEE80211_AUTH_ALG_SHARED_KEY) |
1229 | algs[1] = WLAN_AUTH_SHARED_KEY; | 1039 | algs[1] = WLAN_AUTH_SHARED_KEY; |
1230 | if (ifsta->auth_algs & IEEE80211_AUTH_ALG_LEAP) | 1040 | if (ifmgd->auth_algs & IEEE80211_AUTH_ALG_LEAP) |
1231 | algs[2] = WLAN_AUTH_LEAP; | 1041 | algs[2] = WLAN_AUTH_LEAP; |
1232 | if (ifsta->auth_alg == WLAN_AUTH_OPEN) | 1042 | if (ifmgd->auth_alg == WLAN_AUTH_OPEN) |
1233 | pos = 0; | 1043 | pos = 0; |
1234 | else if (ifsta->auth_alg == WLAN_AUTH_SHARED_KEY) | 1044 | else if (ifmgd->auth_alg == WLAN_AUTH_SHARED_KEY) |
1235 | pos = 1; | 1045 | pos = 1; |
1236 | else | 1046 | else |
1237 | pos = 2; | 1047 | pos = 2; |
@@ -1239,101 +1049,101 @@ static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, | |||
1239 | pos++; | 1049 | pos++; |
1240 | if (pos >= num_algs) | 1050 | if (pos >= num_algs) |
1241 | pos = 0; | 1051 | pos = 0; |
1242 | if (algs[pos] == ifsta->auth_alg || | 1052 | if (algs[pos] == ifmgd->auth_alg || |
1243 | algs[pos] == 0xff) | 1053 | algs[pos] == 0xff) |
1244 | continue; | 1054 | continue; |
1245 | if (algs[pos] == WLAN_AUTH_SHARED_KEY && | 1055 | if (algs[pos] == WLAN_AUTH_SHARED_KEY && |
1246 | !ieee80211_sta_wep_configured(sdata)) | 1056 | !ieee80211_sta_wep_configured(sdata)) |
1247 | continue; | 1057 | continue; |
1248 | ifsta->auth_alg = algs[pos]; | 1058 | ifmgd->auth_alg = algs[pos]; |
1249 | break; | 1059 | break; |
1250 | } | 1060 | } |
1251 | } | 1061 | } |
1252 | return; | 1062 | return; |
1253 | } | 1063 | } |
1254 | 1064 | ||
1255 | switch (ifsta->auth_alg) { | 1065 | switch (ifmgd->auth_alg) { |
1256 | case WLAN_AUTH_OPEN: | 1066 | case WLAN_AUTH_OPEN: |
1257 | case WLAN_AUTH_LEAP: | 1067 | case WLAN_AUTH_LEAP: |
1258 | ieee80211_auth_completed(sdata, ifsta); | 1068 | ieee80211_auth_completed(sdata); |
1259 | break; | 1069 | break; |
1260 | case WLAN_AUTH_SHARED_KEY: | 1070 | case WLAN_AUTH_SHARED_KEY: |
1261 | if (ifsta->auth_transaction == 4) | 1071 | if (ifmgd->auth_transaction == 4) |
1262 | ieee80211_auth_completed(sdata, ifsta); | 1072 | ieee80211_auth_completed(sdata); |
1263 | else | 1073 | else |
1264 | ieee80211_auth_challenge(sdata, ifsta, mgmt, len); | 1074 | ieee80211_auth_challenge(sdata, mgmt, len); |
1265 | break; | 1075 | break; |
1266 | } | 1076 | } |
1267 | } | 1077 | } |
1268 | 1078 | ||
1269 | 1079 | ||
1270 | static void ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, | 1080 | static void ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, |
1271 | struct ieee80211_if_sta *ifsta, | ||
1272 | struct ieee80211_mgmt *mgmt, | 1081 | struct ieee80211_mgmt *mgmt, |
1273 | size_t len) | 1082 | size_t len) |
1274 | { | 1083 | { |
1084 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
1275 | u16 reason_code; | 1085 | u16 reason_code; |
1276 | 1086 | ||
1277 | if (len < 24 + 2) | 1087 | if (len < 24 + 2) |
1278 | return; | 1088 | return; |
1279 | 1089 | ||
1280 | if (memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN)) | 1090 | if (memcmp(ifmgd->bssid, mgmt->sa, ETH_ALEN)) |
1281 | return; | 1091 | return; |
1282 | 1092 | ||
1283 | reason_code = le16_to_cpu(mgmt->u.deauth.reason_code); | 1093 | reason_code = le16_to_cpu(mgmt->u.deauth.reason_code); |
1284 | 1094 | ||
1285 | if (ifsta->flags & IEEE80211_STA_AUTHENTICATED) | 1095 | if (ifmgd->flags & IEEE80211_STA_AUTHENTICATED) |
1286 | printk(KERN_DEBUG "%s: deauthenticated (Reason: %u)\n", | 1096 | printk(KERN_DEBUG "%s: deauthenticated (Reason: %u)\n", |
1287 | sdata->dev->name, reason_code); | 1097 | sdata->dev->name, reason_code); |
1288 | 1098 | ||
1289 | if (ifsta->state == IEEE80211_STA_MLME_AUTHENTICATE || | 1099 | if (ifmgd->state == IEEE80211_STA_MLME_AUTHENTICATE || |
1290 | ifsta->state == IEEE80211_STA_MLME_ASSOCIATE || | 1100 | ifmgd->state == IEEE80211_STA_MLME_ASSOCIATE || |
1291 | ifsta->state == IEEE80211_STA_MLME_ASSOCIATED) { | 1101 | ifmgd->state == IEEE80211_STA_MLME_ASSOCIATED) { |
1292 | ifsta->state = IEEE80211_STA_MLME_DIRECT_PROBE; | 1102 | ifmgd->state = IEEE80211_STA_MLME_DIRECT_PROBE; |
1293 | mod_timer(&ifsta->timer, jiffies + | 1103 | mod_timer(&ifmgd->timer, jiffies + |
1294 | IEEE80211_RETRY_AUTH_INTERVAL); | 1104 | IEEE80211_RETRY_AUTH_INTERVAL); |
1295 | } | 1105 | } |
1296 | 1106 | ||
1297 | ieee80211_set_disassoc(sdata, ifsta, true, false, 0); | 1107 | ieee80211_set_disassoc(sdata, true, false, 0); |
1298 | ifsta->flags &= ~IEEE80211_STA_AUTHENTICATED; | 1108 | ifmgd->flags &= ~IEEE80211_STA_AUTHENTICATED; |
1299 | } | 1109 | } |
1300 | 1110 | ||
1301 | 1111 | ||
1302 | static void ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata, | 1112 | static void ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata, |
1303 | struct ieee80211_if_sta *ifsta, | ||
1304 | struct ieee80211_mgmt *mgmt, | 1113 | struct ieee80211_mgmt *mgmt, |
1305 | size_t len) | 1114 | size_t len) |
1306 | { | 1115 | { |
1116 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
1307 | u16 reason_code; | 1117 | u16 reason_code; |
1308 | 1118 | ||
1309 | if (len < 24 + 2) | 1119 | if (len < 24 + 2) |
1310 | return; | 1120 | return; |
1311 | 1121 | ||
1312 | if (memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN)) | 1122 | if (memcmp(ifmgd->bssid, mgmt->sa, ETH_ALEN)) |
1313 | return; | 1123 | return; |
1314 | 1124 | ||
1315 | reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code); | 1125 | reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code); |
1316 | 1126 | ||
1317 | if (ifsta->flags & IEEE80211_STA_ASSOCIATED) | 1127 | if (ifmgd->flags & IEEE80211_STA_ASSOCIATED) |
1318 | printk(KERN_DEBUG "%s: disassociated (Reason: %u)\n", | 1128 | printk(KERN_DEBUG "%s: disassociated (Reason: %u)\n", |
1319 | sdata->dev->name, reason_code); | 1129 | sdata->dev->name, reason_code); |
1320 | 1130 | ||
1321 | if (ifsta->state == IEEE80211_STA_MLME_ASSOCIATED) { | 1131 | if (ifmgd->state == IEEE80211_STA_MLME_ASSOCIATED) { |
1322 | ifsta->state = IEEE80211_STA_MLME_ASSOCIATE; | 1132 | ifmgd->state = IEEE80211_STA_MLME_ASSOCIATE; |
1323 | mod_timer(&ifsta->timer, jiffies + | 1133 | mod_timer(&ifmgd->timer, jiffies + |
1324 | IEEE80211_RETRY_AUTH_INTERVAL); | 1134 | IEEE80211_RETRY_AUTH_INTERVAL); |
1325 | } | 1135 | } |
1326 | 1136 | ||
1327 | ieee80211_set_disassoc(sdata, ifsta, false, false, reason_code); | 1137 | ieee80211_set_disassoc(sdata, false, false, reason_code); |
1328 | } | 1138 | } |
1329 | 1139 | ||
1330 | 1140 | ||
1331 | static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | 1141 | static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, |
1332 | struct ieee80211_if_sta *ifsta, | ||
1333 | struct ieee80211_mgmt *mgmt, | 1142 | struct ieee80211_mgmt *mgmt, |
1334 | size_t len, | 1143 | size_t len, |
1335 | int reassoc) | 1144 | int reassoc) |
1336 | { | 1145 | { |
1146 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
1337 | struct ieee80211_local *local = sdata->local; | 1147 | struct ieee80211_local *local = sdata->local; |
1338 | struct ieee80211_supported_band *sband; | 1148 | struct ieee80211_supported_band *sband; |
1339 | struct sta_info *sta; | 1149 | struct sta_info *sta; |
@@ -1350,13 +1160,13 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | |||
1350 | /* AssocResp and ReassocResp have identical structure, so process both | 1160 | /* AssocResp and ReassocResp have identical structure, so process both |
1351 | * of them in this function. */ | 1161 | * of them in this function. */ |
1352 | 1162 | ||
1353 | if (ifsta->state != IEEE80211_STA_MLME_ASSOCIATE) | 1163 | if (ifmgd->state != IEEE80211_STA_MLME_ASSOCIATE) |
1354 | return; | 1164 | return; |
1355 | 1165 | ||
1356 | if (len < 24 + 6) | 1166 | if (len < 24 + 6) |
1357 | return; | 1167 | return; |
1358 | 1168 | ||
1359 | if (memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) != 0) | 1169 | if (memcmp(ifmgd->bssid, mgmt->sa, ETH_ALEN) != 0) |
1360 | return; | 1170 | return; |
1361 | 1171 | ||
1362 | capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info); | 1172 | capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info); |
@@ -1381,7 +1191,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | |||
1381 | "comeback duration %u TU (%u ms)\n", | 1191 | "comeback duration %u TU (%u ms)\n", |
1382 | sdata->dev->name, tu, ms); | 1192 | sdata->dev->name, tu, ms); |
1383 | if (ms > IEEE80211_ASSOC_TIMEOUT) | 1193 | if (ms > IEEE80211_ASSOC_TIMEOUT) |
1384 | mod_timer(&ifsta->timer, | 1194 | mod_timer(&ifmgd->timer, |
1385 | jiffies + msecs_to_jiffies(ms)); | 1195 | jiffies + msecs_to_jiffies(ms)); |
1386 | return; | 1196 | return; |
1387 | } | 1197 | } |
@@ -1392,7 +1202,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | |||
1392 | /* if this was a reassociation, ensure we try a "full" | 1202 | /* if this was a reassociation, ensure we try a "full" |
1393 | * association next time. This works around some broken APs | 1203 | * association next time. This works around some broken APs |
1394 | * which do not correctly reject reassociation requests. */ | 1204 | * which do not correctly reject reassociation requests. */ |
1395 | ifsta->flags &= ~IEEE80211_STA_PREV_BSSID_SET; | 1205 | ifmgd->flags &= ~IEEE80211_STA_PREV_BSSID_SET; |
1396 | return; | 1206 | return; |
1397 | } | 1207 | } |
1398 | 1208 | ||
@@ -1408,23 +1218,23 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | |||
1408 | } | 1218 | } |
1409 | 1219 | ||
1410 | printk(KERN_DEBUG "%s: associated\n", sdata->dev->name); | 1220 | printk(KERN_DEBUG "%s: associated\n", sdata->dev->name); |
1411 | ifsta->aid = aid; | 1221 | ifmgd->aid = aid; |
1412 | ifsta->ap_capab = capab_info; | 1222 | ifmgd->ap_capab = capab_info; |
1413 | 1223 | ||
1414 | kfree(ifsta->assocresp_ies); | 1224 | kfree(ifmgd->assocresp_ies); |
1415 | ifsta->assocresp_ies_len = len - (pos - (u8 *) mgmt); | 1225 | ifmgd->assocresp_ies_len = len - (pos - (u8 *) mgmt); |
1416 | ifsta->assocresp_ies = kmalloc(ifsta->assocresp_ies_len, GFP_KERNEL); | 1226 | ifmgd->assocresp_ies = kmalloc(ifmgd->assocresp_ies_len, GFP_KERNEL); |
1417 | if (ifsta->assocresp_ies) | 1227 | if (ifmgd->assocresp_ies) |
1418 | memcpy(ifsta->assocresp_ies, pos, ifsta->assocresp_ies_len); | 1228 | memcpy(ifmgd->assocresp_ies, pos, ifmgd->assocresp_ies_len); |
1419 | 1229 | ||
1420 | rcu_read_lock(); | 1230 | rcu_read_lock(); |
1421 | 1231 | ||
1422 | /* Add STA entry for the AP */ | 1232 | /* Add STA entry for the AP */ |
1423 | sta = sta_info_get(local, ifsta->bssid); | 1233 | sta = sta_info_get(local, ifmgd->bssid); |
1424 | if (!sta) { | 1234 | if (!sta) { |
1425 | newsta = true; | 1235 | newsta = true; |
1426 | 1236 | ||
1427 | sta = sta_info_alloc(sdata, ifsta->bssid, GFP_ATOMIC); | 1237 | sta = sta_info_alloc(sdata, ifmgd->bssid, GFP_ATOMIC); |
1428 | if (!sta) { | 1238 | if (!sta) { |
1429 | printk(KERN_DEBUG "%s: failed to alloc STA entry for" | 1239 | printk(KERN_DEBUG "%s: failed to alloc STA entry for" |
1430 | " the AP\n", sdata->dev->name); | 1240 | " the AP\n", sdata->dev->name); |
@@ -1505,7 +1315,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | |||
1505 | 1315 | ||
1506 | rate_control_rate_init(sta); | 1316 | rate_control_rate_init(sta); |
1507 | 1317 | ||
1508 | if (ifsta->flags & IEEE80211_STA_MFP_ENABLED) | 1318 | if (ifmgd->flags & IEEE80211_STA_MFP_ENABLED) |
1509 | set_sta_flags(sta, WLAN_STA_MFP); | 1319 | set_sta_flags(sta, WLAN_STA_MFP); |
1510 | 1320 | ||
1511 | if (elems.wmm_param) | 1321 | if (elems.wmm_param) |
@@ -1524,11 +1334,12 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | |||
1524 | rcu_read_unlock(); | 1334 | rcu_read_unlock(); |
1525 | 1335 | ||
1526 | if (elems.wmm_param) | 1336 | if (elems.wmm_param) |
1527 | ieee80211_sta_wmm_params(local, ifsta, elems.wmm_param, | 1337 | ieee80211_sta_wmm_params(local, ifmgd, elems.wmm_param, |
1528 | elems.wmm_param_len); | 1338 | elems.wmm_param_len); |
1529 | 1339 | ||
1530 | if (elems.ht_info_elem && elems.wmm_param && | 1340 | if (elems.ht_info_elem && elems.wmm_param && |
1531 | (ifsta->flags & IEEE80211_STA_WMM_ENABLED)) | 1341 | (ifmgd->flags & IEEE80211_STA_WMM_ENABLED) && |
1342 | !(ifmgd->flags & IEEE80211_STA_TKIP_WEP_USED)) | ||
1532 | changed |= ieee80211_enable_ht(sdata, elems.ht_info_elem, | 1343 | changed |= ieee80211_enable_ht(sdata, elems.ht_info_elem, |
1533 | ap_ht_cap_flags); | 1344 | ap_ht_cap_flags); |
1534 | 1345 | ||
@@ -1536,162 +1347,11 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | |||
1536 | * ieee80211_set_associated() will tell the driver */ | 1347 | * ieee80211_set_associated() will tell the driver */ |
1537 | bss_conf->aid = aid; | 1348 | bss_conf->aid = aid; |
1538 | bss_conf->assoc_capability = capab_info; | 1349 | bss_conf->assoc_capability = capab_info; |
1539 | ieee80211_set_associated(sdata, ifsta, changed); | 1350 | ieee80211_set_associated(sdata, changed); |
1540 | |||
1541 | ieee80211_associated(sdata, ifsta); | ||
1542 | } | ||
1543 | |||
1544 | 1351 | ||
1545 | static int __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | 1352 | ieee80211_associated(sdata); |
1546 | struct ieee80211_if_sta *ifsta, | ||
1547 | const u8 *bssid, const int beacon_int, | ||
1548 | const int freq, | ||
1549 | const size_t supp_rates_len, | ||
1550 | const u8 *supp_rates, | ||
1551 | const u16 capability) | ||
1552 | { | ||
1553 | struct ieee80211_local *local = sdata->local; | ||
1554 | int res = 0, rates, i, j; | ||
1555 | struct sk_buff *skb; | ||
1556 | struct ieee80211_mgmt *mgmt; | ||
1557 | u8 *pos; | ||
1558 | struct ieee80211_supported_band *sband; | ||
1559 | union iwreq_data wrqu; | ||
1560 | |||
1561 | if (local->ops->reset_tsf) { | ||
1562 | /* Reset own TSF to allow time synchronization work. */ | ||
1563 | local->ops->reset_tsf(local_to_hw(local)); | ||
1564 | } | ||
1565 | |||
1566 | if ((ifsta->flags & IEEE80211_STA_PREV_BSSID_SET) && | ||
1567 | memcmp(ifsta->bssid, bssid, ETH_ALEN) == 0) | ||
1568 | return res; | ||
1569 | |||
1570 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400 + | ||
1571 | sdata->u.sta.ie_proberesp_len); | ||
1572 | if (!skb) { | ||
1573 | printk(KERN_DEBUG "%s: failed to allocate buffer for probe " | ||
1574 | "response\n", sdata->dev->name); | ||
1575 | return -ENOMEM; | ||
1576 | } | ||
1577 | |||
1578 | if (!(ifsta->flags & IEEE80211_STA_PREV_BSSID_SET)) { | ||
1579 | /* Remove possible STA entries from other IBSS networks. */ | ||
1580 | sta_info_flush_delayed(sdata); | ||
1581 | } | ||
1582 | |||
1583 | memcpy(ifsta->bssid, bssid, ETH_ALEN); | ||
1584 | res = ieee80211_if_config(sdata, IEEE80211_IFCC_BSSID); | ||
1585 | if (res) | ||
1586 | return res; | ||
1587 | |||
1588 | local->hw.conf.beacon_int = beacon_int >= 10 ? beacon_int : 10; | ||
1589 | |||
1590 | sdata->drop_unencrypted = capability & | ||
1591 | WLAN_CAPABILITY_PRIVACY ? 1 : 0; | ||
1592 | |||
1593 | res = ieee80211_set_freq(sdata, freq); | ||
1594 | |||
1595 | if (res) | ||
1596 | return res; | ||
1597 | |||
1598 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | ||
1599 | |||
1600 | /* Build IBSS probe response */ | ||
1601 | |||
1602 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
1603 | |||
1604 | mgmt = (struct ieee80211_mgmt *) | ||
1605 | skb_put(skb, 24 + sizeof(mgmt->u.beacon)); | ||
1606 | memset(mgmt, 0, 24 + sizeof(mgmt->u.beacon)); | ||
1607 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
1608 | IEEE80211_STYPE_PROBE_RESP); | ||
1609 | memset(mgmt->da, 0xff, ETH_ALEN); | ||
1610 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | ||
1611 | memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); | ||
1612 | mgmt->u.beacon.beacon_int = | ||
1613 | cpu_to_le16(local->hw.conf.beacon_int); | ||
1614 | mgmt->u.beacon.capab_info = cpu_to_le16(capability); | ||
1615 | |||
1616 | pos = skb_put(skb, 2 + ifsta->ssid_len); | ||
1617 | *pos++ = WLAN_EID_SSID; | ||
1618 | *pos++ = ifsta->ssid_len; | ||
1619 | memcpy(pos, ifsta->ssid, ifsta->ssid_len); | ||
1620 | |||
1621 | rates = supp_rates_len; | ||
1622 | if (rates > 8) | ||
1623 | rates = 8; | ||
1624 | pos = skb_put(skb, 2 + rates); | ||
1625 | *pos++ = WLAN_EID_SUPP_RATES; | ||
1626 | *pos++ = rates; | ||
1627 | memcpy(pos, supp_rates, rates); | ||
1628 | |||
1629 | if (sband->band == IEEE80211_BAND_2GHZ) { | ||
1630 | pos = skb_put(skb, 2 + 1); | ||
1631 | *pos++ = WLAN_EID_DS_PARAMS; | ||
1632 | *pos++ = 1; | ||
1633 | *pos++ = ieee80211_frequency_to_channel(freq); | ||
1634 | } | ||
1635 | |||
1636 | pos = skb_put(skb, 2 + 2); | ||
1637 | *pos++ = WLAN_EID_IBSS_PARAMS; | ||
1638 | *pos++ = 2; | ||
1639 | /* FIX: set ATIM window based on scan results */ | ||
1640 | *pos++ = 0; | ||
1641 | *pos++ = 0; | ||
1642 | |||
1643 | if (supp_rates_len > 8) { | ||
1644 | rates = supp_rates_len - 8; | ||
1645 | pos = skb_put(skb, 2 + rates); | ||
1646 | *pos++ = WLAN_EID_EXT_SUPP_RATES; | ||
1647 | *pos++ = rates; | ||
1648 | memcpy(pos, &supp_rates[8], rates); | ||
1649 | } | ||
1650 | |||
1651 | add_extra_ies(skb, sdata->u.sta.ie_proberesp, | ||
1652 | sdata->u.sta.ie_proberesp_len); | ||
1653 | |||
1654 | ifsta->probe_resp = skb; | ||
1655 | |||
1656 | ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON | | ||
1657 | IEEE80211_IFCC_BEACON_ENABLED); | ||
1658 | |||
1659 | |||
1660 | rates = 0; | ||
1661 | for (i = 0; i < supp_rates_len; i++) { | ||
1662 | int bitrate = (supp_rates[i] & 0x7f) * 5; | ||
1663 | for (j = 0; j < sband->n_bitrates; j++) | ||
1664 | if (sband->bitrates[j].bitrate == bitrate) | ||
1665 | rates |= BIT(j); | ||
1666 | } | ||
1667 | ifsta->supp_rates_bits[local->hw.conf.channel->band] = rates; | ||
1668 | |||
1669 | ieee80211_sta_def_wmm_params(sdata, supp_rates_len, supp_rates); | ||
1670 | |||
1671 | ifsta->flags |= IEEE80211_STA_PREV_BSSID_SET; | ||
1672 | ifsta->state = IEEE80211_STA_MLME_IBSS_JOINED; | ||
1673 | mod_timer(&ifsta->timer, jiffies + IEEE80211_IBSS_MERGE_INTERVAL); | ||
1674 | |||
1675 | ieee80211_led_assoc(local, true); | ||
1676 | |||
1677 | memset(&wrqu, 0, sizeof(wrqu)); | ||
1678 | memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN); | ||
1679 | wireless_send_event(sdata->dev, SIOCGIWAP, &wrqu, NULL); | ||
1680 | |||
1681 | return res; | ||
1682 | } | 1353 | } |
1683 | 1354 | ||
1684 | static int ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | ||
1685 | struct ieee80211_if_sta *ifsta, | ||
1686 | struct ieee80211_bss *bss) | ||
1687 | { | ||
1688 | return __ieee80211_sta_join_ibss(sdata, ifsta, | ||
1689 | bss->cbss.bssid, | ||
1690 | bss->cbss.beacon_interval, | ||
1691 | bss->cbss.channel->center_freq, | ||
1692 | bss->supp_rates_len, bss->supp_rates, | ||
1693 | bss->cbss.capability); | ||
1694 | } | ||
1695 | 1355 | ||
1696 | static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | 1356 | static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, |
1697 | struct ieee80211_mgmt *mgmt, | 1357 | struct ieee80211_mgmt *mgmt, |
@@ -1703,11 +1363,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
1703 | struct ieee80211_local *local = sdata->local; | 1363 | struct ieee80211_local *local = sdata->local; |
1704 | int freq; | 1364 | int freq; |
1705 | struct ieee80211_bss *bss; | 1365 | struct ieee80211_bss *bss; |
1706 | struct sta_info *sta; | ||
1707 | struct ieee80211_channel *channel; | 1366 | struct ieee80211_channel *channel; |
1708 | u64 beacon_timestamp, rx_timestamp; | ||
1709 | u32 supp_rates = 0; | ||
1710 | enum ieee80211_band band = rx_status->band; | ||
1711 | 1367 | ||
1712 | if (elems->ds_params && elems->ds_params_len == 1) | 1368 | if (elems->ds_params && elems->ds_params_len == 1) |
1713 | freq = ieee80211_channel_to_frequency(elems->ds_params[0]); | 1369 | freq = ieee80211_channel_to_frequency(elems->ds_params[0]); |
@@ -1719,133 +1375,18 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
1719 | if (!channel || channel->flags & IEEE80211_CHAN_DISABLED) | 1375 | if (!channel || channel->flags & IEEE80211_CHAN_DISABLED) |
1720 | return; | 1376 | return; |
1721 | 1377 | ||
1722 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC && elems->supp_rates && | ||
1723 | memcmp(mgmt->bssid, sdata->u.sta.bssid, ETH_ALEN) == 0) { | ||
1724 | supp_rates = ieee80211_sta_get_rates(local, elems, band); | ||
1725 | |||
1726 | rcu_read_lock(); | ||
1727 | |||
1728 | sta = sta_info_get(local, mgmt->sa); | ||
1729 | if (sta) { | ||
1730 | u32 prev_rates; | ||
1731 | |||
1732 | prev_rates = sta->sta.supp_rates[band]; | ||
1733 | /* make sure mandatory rates are always added */ | ||
1734 | sta->sta.supp_rates[band] = supp_rates | | ||
1735 | ieee80211_mandatory_rates(local, band); | ||
1736 | |||
1737 | #ifdef CONFIG_MAC80211_IBSS_DEBUG | ||
1738 | if (sta->sta.supp_rates[band] != prev_rates) | ||
1739 | printk(KERN_DEBUG "%s: updated supp_rates set " | ||
1740 | "for %pM based on beacon info (0x%llx | " | ||
1741 | "0x%llx -> 0x%llx)\n", | ||
1742 | sdata->dev->name, | ||
1743 | sta->sta.addr, | ||
1744 | (unsigned long long) prev_rates, | ||
1745 | (unsigned long long) supp_rates, | ||
1746 | (unsigned long long) sta->sta.supp_rates[band]); | ||
1747 | #endif | ||
1748 | } else { | ||
1749 | ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, supp_rates); | ||
1750 | } | ||
1751 | |||
1752 | rcu_read_unlock(); | ||
1753 | } | ||
1754 | |||
1755 | bss = ieee80211_bss_info_update(local, rx_status, mgmt, len, elems, | 1378 | bss = ieee80211_bss_info_update(local, rx_status, mgmt, len, elems, |
1756 | channel, beacon); | 1379 | channel, beacon); |
1757 | if (!bss) | 1380 | if (!bss) |
1758 | return; | 1381 | return; |
1759 | 1382 | ||
1760 | if (elems->ch_switch_elem && (elems->ch_switch_elem_len == 3) && | 1383 | if (elems->ch_switch_elem && (elems->ch_switch_elem_len == 3) && |
1761 | (memcmp(mgmt->bssid, sdata->u.sta.bssid, ETH_ALEN) == 0)) { | 1384 | (memcmp(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN) == 0)) { |
1762 | struct ieee80211_channel_sw_ie *sw_elem = | 1385 | struct ieee80211_channel_sw_ie *sw_elem = |
1763 | (struct ieee80211_channel_sw_ie *)elems->ch_switch_elem; | 1386 | (struct ieee80211_channel_sw_ie *)elems->ch_switch_elem; |
1764 | ieee80211_process_chanswitch(sdata, sw_elem, bss); | 1387 | ieee80211_process_chanswitch(sdata, sw_elem, bss); |
1765 | } | 1388 | } |
1766 | 1389 | ||
1767 | /* was just updated in ieee80211_bss_info_update */ | ||
1768 | beacon_timestamp = bss->cbss.tsf; | ||
1769 | |||
1770 | if (sdata->vif.type != NL80211_IFTYPE_ADHOC) | ||
1771 | goto put_bss; | ||
1772 | |||
1773 | /* check if we need to merge IBSS */ | ||
1774 | |||
1775 | /* merge only on beacons (???) */ | ||
1776 | if (!beacon) | ||
1777 | goto put_bss; | ||
1778 | |||
1779 | /* we use a fixed BSSID */ | ||
1780 | if (sdata->u.sta.flags & IEEE80211_STA_BSSID_SET) | ||
1781 | goto put_bss; | ||
1782 | |||
1783 | /* not an IBSS */ | ||
1784 | if (!(bss->cbss.capability & WLAN_CAPABILITY_IBSS)) | ||
1785 | goto put_bss; | ||
1786 | |||
1787 | /* different channel */ | ||
1788 | if (bss->cbss.channel != local->oper_channel) | ||
1789 | goto put_bss; | ||
1790 | |||
1791 | /* different SSID */ | ||
1792 | if (elems->ssid_len != sdata->u.sta.ssid_len || | ||
1793 | memcmp(elems->ssid, sdata->u.sta.ssid, | ||
1794 | sdata->u.sta.ssid_len)) | ||
1795 | goto put_bss; | ||
1796 | |||
1797 | if (rx_status->flag & RX_FLAG_TSFT) { | ||
1798 | /* | ||
1799 | * For correct IBSS merging we need mactime; since mactime is | ||
1800 | * defined as the time the first data symbol of the frame hits | ||
1801 | * the PHY, and the timestamp of the beacon is defined as "the | ||
1802 | * time that the data symbol containing the first bit of the | ||
1803 | * timestamp is transmitted to the PHY plus the transmitting | ||
1804 | * STA's delays through its local PHY from the MAC-PHY | ||
1805 | * interface to its interface with the WM" (802.11 11.1.2) | ||
1806 | * - equals the time this bit arrives at the receiver - we have | ||
1807 | * to take into account the offset between the two. | ||
1808 | * | ||
1809 | * E.g. at 1 MBit that means mactime is 192 usec earlier | ||
1810 | * (=24 bytes * 8 usecs/byte) than the beacon timestamp. | ||
1811 | */ | ||
1812 | int rate; | ||
1813 | |||
1814 | if (rx_status->flag & RX_FLAG_HT) | ||
1815 | rate = 65; /* TODO: HT rates */ | ||
1816 | else | ||
1817 | rate = local->hw.wiphy->bands[band]-> | ||
1818 | bitrates[rx_status->rate_idx].bitrate; | ||
1819 | |||
1820 | rx_timestamp = rx_status->mactime + (24 * 8 * 10 / rate); | ||
1821 | } else if (local && local->ops && local->ops->get_tsf) | ||
1822 | /* second best option: get current TSF */ | ||
1823 | rx_timestamp = local->ops->get_tsf(local_to_hw(local)); | ||
1824 | else | ||
1825 | /* can't merge without knowing the TSF */ | ||
1826 | rx_timestamp = -1LLU; | ||
1827 | |||
1828 | #ifdef CONFIG_MAC80211_IBSS_DEBUG | ||
1829 | printk(KERN_DEBUG "RX beacon SA=%pM BSSID=" | ||
1830 | "%pM TSF=0x%llx BCN=0x%llx diff=%lld @%lu\n", | ||
1831 | mgmt->sa, mgmt->bssid, | ||
1832 | (unsigned long long)rx_timestamp, | ||
1833 | (unsigned long long)beacon_timestamp, | ||
1834 | (unsigned long long)(rx_timestamp - beacon_timestamp), | ||
1835 | jiffies); | ||
1836 | #endif | ||
1837 | |||
1838 | if (beacon_timestamp > rx_timestamp) { | ||
1839 | #ifdef CONFIG_MAC80211_IBSS_DEBUG | ||
1840 | printk(KERN_DEBUG "%s: beacon TSF higher than " | ||
1841 | "local TSF - IBSS merge with BSSID %pM\n", | ||
1842 | sdata->dev->name, mgmt->bssid); | ||
1843 | #endif | ||
1844 | ieee80211_sta_join_ibss(sdata, &sdata->u.sta, bss); | ||
1845 | ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, supp_rates); | ||
1846 | } | ||
1847 | |||
1848 | put_bss: | ||
1849 | ieee80211_rx_bss_put(local, bss); | 1390 | ieee80211_rx_bss_put(local, bss); |
1850 | } | 1391 | } |
1851 | 1392 | ||
@@ -1857,7 +1398,6 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata, | |||
1857 | { | 1398 | { |
1858 | size_t baselen; | 1399 | size_t baselen; |
1859 | struct ieee802_11_elems elems; | 1400 | struct ieee802_11_elems elems; |
1860 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | ||
1861 | 1401 | ||
1862 | if (memcmp(mgmt->da, sdata->dev->dev_addr, ETH_ALEN)) | 1402 | if (memcmp(mgmt->da, sdata->dev->dev_addr, ETH_ALEN)) |
1863 | return; /* ignore ProbeResp to foreign address */ | 1403 | return; /* ignore ProbeResp to foreign address */ |
@@ -1873,20 +1413,19 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata, | |||
1873 | 1413 | ||
1874 | /* direct probe may be part of the association flow */ | 1414 | /* direct probe may be part of the association flow */ |
1875 | if (test_and_clear_bit(IEEE80211_STA_REQ_DIRECT_PROBE, | 1415 | if (test_and_clear_bit(IEEE80211_STA_REQ_DIRECT_PROBE, |
1876 | &ifsta->request)) { | 1416 | &sdata->u.mgd.request)) { |
1877 | printk(KERN_DEBUG "%s direct probe responded\n", | 1417 | printk(KERN_DEBUG "%s direct probe responded\n", |
1878 | sdata->dev->name); | 1418 | sdata->dev->name); |
1879 | ieee80211_authenticate(sdata, ifsta); | 1419 | ieee80211_authenticate(sdata); |
1880 | } | 1420 | } |
1881 | } | 1421 | } |
1882 | 1422 | ||
1883 | |||
1884 | static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | 1423 | static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, |
1885 | struct ieee80211_mgmt *mgmt, | 1424 | struct ieee80211_mgmt *mgmt, |
1886 | size_t len, | 1425 | size_t len, |
1887 | struct ieee80211_rx_status *rx_status) | 1426 | struct ieee80211_rx_status *rx_status) |
1888 | { | 1427 | { |
1889 | struct ieee80211_if_sta *ifsta; | 1428 | struct ieee80211_if_managed *ifmgd; |
1890 | size_t baselen; | 1429 | size_t baselen; |
1891 | struct ieee802_11_elems elems; | 1430 | struct ieee802_11_elems elems; |
1892 | struct ieee80211_local *local = sdata->local; | 1431 | struct ieee80211_local *local = sdata->local; |
@@ -1905,21 +1444,22 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
1905 | 1444 | ||
1906 | if (sdata->vif.type != NL80211_IFTYPE_STATION) | 1445 | if (sdata->vif.type != NL80211_IFTYPE_STATION) |
1907 | return; | 1446 | return; |
1908 | ifsta = &sdata->u.sta; | ||
1909 | 1447 | ||
1910 | if (!(ifsta->flags & IEEE80211_STA_ASSOCIATED) || | 1448 | ifmgd = &sdata->u.mgd; |
1911 | memcmp(ifsta->bssid, mgmt->bssid, ETH_ALEN) != 0) | 1449 | |
1450 | if (!(ifmgd->flags & IEEE80211_STA_ASSOCIATED) || | ||
1451 | memcmp(ifmgd->bssid, mgmt->bssid, ETH_ALEN) != 0) | ||
1912 | return; | 1452 | return; |
1913 | 1453 | ||
1914 | if (rx_status->freq != local->hw.conf.channel->center_freq) | 1454 | if (rx_status->freq != local->hw.conf.channel->center_freq) |
1915 | return; | 1455 | return; |
1916 | 1456 | ||
1917 | ieee80211_sta_wmm_params(local, ifsta, elems.wmm_param, | 1457 | ieee80211_sta_wmm_params(local, ifmgd, elems.wmm_param, |
1918 | elems.wmm_param_len); | 1458 | elems.wmm_param_len); |
1919 | 1459 | ||
1920 | if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK && | 1460 | if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK && |
1921 | local->hw.conf.flags & IEEE80211_CONF_PS) { | 1461 | local->hw.conf.flags & IEEE80211_CONF_PS) { |
1922 | directed_tim = ieee80211_check_tim(&elems, ifsta->aid); | 1462 | directed_tim = ieee80211_check_tim(&elems, ifmgd->aid); |
1923 | 1463 | ||
1924 | if (directed_tim) { | 1464 | if (directed_tim) { |
1925 | if (local->hw.conf.dynamic_ps_timeout > 0) { | 1465 | if (local->hw.conf.dynamic_ps_timeout > 0) { |
@@ -1954,14 +1494,15 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
1954 | erp_valid, erp_value); | 1494 | erp_valid, erp_value); |
1955 | 1495 | ||
1956 | 1496 | ||
1957 | if (elems.ht_cap_elem && elems.ht_info_elem && elems.wmm_param) { | 1497 | if (elems.ht_cap_elem && elems.ht_info_elem && elems.wmm_param && |
1498 | !(ifmgd->flags & IEEE80211_STA_TKIP_WEP_USED)) { | ||
1958 | struct sta_info *sta; | 1499 | struct sta_info *sta; |
1959 | struct ieee80211_supported_band *sband; | 1500 | struct ieee80211_supported_band *sband; |
1960 | u16 ap_ht_cap_flags; | 1501 | u16 ap_ht_cap_flags; |
1961 | 1502 | ||
1962 | rcu_read_lock(); | 1503 | rcu_read_lock(); |
1963 | 1504 | ||
1964 | sta = sta_info_get(local, ifsta->bssid); | 1505 | sta = sta_info_get(local, ifmgd->bssid); |
1965 | if (!sta) { | 1506 | if (!sta) { |
1966 | rcu_read_unlock(); | 1507 | rcu_read_unlock(); |
1967 | return; | 1508 | return; |
@@ -1997,85 +1538,16 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
1997 | ieee80211_bss_info_change_notify(sdata, changed); | 1538 | ieee80211_bss_info_change_notify(sdata, changed); |
1998 | } | 1539 | } |
1999 | 1540 | ||
2000 | 1541 | ieee80211_rx_result ieee80211_sta_rx_mgmt(struct ieee80211_sub_if_data *sdata, | |
2001 | static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata, | 1542 | struct sk_buff *skb, |
2002 | struct ieee80211_if_sta *ifsta, | 1543 | struct ieee80211_rx_status *rx_status) |
2003 | struct ieee80211_mgmt *mgmt, | ||
2004 | size_t len) | ||
2005 | { | 1544 | { |
2006 | struct ieee80211_local *local = sdata->local; | 1545 | struct ieee80211_local *local = sdata->local; |
2007 | int tx_last_beacon; | ||
2008 | struct sk_buff *skb; | ||
2009 | struct ieee80211_mgmt *resp; | ||
2010 | u8 *pos, *end; | ||
2011 | |||
2012 | if (ifsta->state != IEEE80211_STA_MLME_IBSS_JOINED || | ||
2013 | len < 24 + 2 || !ifsta->probe_resp) | ||
2014 | return; | ||
2015 | |||
2016 | if (local->ops->tx_last_beacon) | ||
2017 | tx_last_beacon = local->ops->tx_last_beacon(local_to_hw(local)); | ||
2018 | else | ||
2019 | tx_last_beacon = 1; | ||
2020 | |||
2021 | #ifdef CONFIG_MAC80211_IBSS_DEBUG | ||
2022 | printk(KERN_DEBUG "%s: RX ProbeReq SA=%pM DA=%pM BSSID=%pM" | ||
2023 | " (tx_last_beacon=%d)\n", | ||
2024 | sdata->dev->name, mgmt->sa, mgmt->da, | ||
2025 | mgmt->bssid, tx_last_beacon); | ||
2026 | #endif /* CONFIG_MAC80211_IBSS_DEBUG */ | ||
2027 | |||
2028 | if (!tx_last_beacon) | ||
2029 | return; | ||
2030 | |||
2031 | if (memcmp(mgmt->bssid, ifsta->bssid, ETH_ALEN) != 0 && | ||
2032 | memcmp(mgmt->bssid, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) != 0) | ||
2033 | return; | ||
2034 | |||
2035 | end = ((u8 *) mgmt) + len; | ||
2036 | pos = mgmt->u.probe_req.variable; | ||
2037 | if (pos[0] != WLAN_EID_SSID || | ||
2038 | pos + 2 + pos[1] > end) { | ||
2039 | #ifdef CONFIG_MAC80211_IBSS_DEBUG | ||
2040 | printk(KERN_DEBUG "%s: Invalid SSID IE in ProbeReq " | ||
2041 | "from %pM\n", | ||
2042 | sdata->dev->name, mgmt->sa); | ||
2043 | #endif | ||
2044 | return; | ||
2045 | } | ||
2046 | if (pos[1] != 0 && | ||
2047 | (pos[1] != ifsta->ssid_len || | ||
2048 | memcmp(pos + 2, ifsta->ssid, ifsta->ssid_len) != 0)) { | ||
2049 | /* Ignore ProbeReq for foreign SSID */ | ||
2050 | return; | ||
2051 | } | ||
2052 | |||
2053 | /* Reply with ProbeResp */ | ||
2054 | skb = skb_copy(ifsta->probe_resp, GFP_KERNEL); | ||
2055 | if (!skb) | ||
2056 | return; | ||
2057 | |||
2058 | resp = (struct ieee80211_mgmt *) skb->data; | ||
2059 | memcpy(resp->da, mgmt->sa, ETH_ALEN); | ||
2060 | #ifdef CONFIG_MAC80211_IBSS_DEBUG | ||
2061 | printk(KERN_DEBUG "%s: Sending ProbeResp to %pM\n", | ||
2062 | sdata->dev->name, resp->da); | ||
2063 | #endif /* CONFIG_MAC80211_IBSS_DEBUG */ | ||
2064 | ieee80211_tx_skb(sdata, skb, 0); | ||
2065 | } | ||
2066 | |||
2067 | void ieee80211_sta_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, | ||
2068 | struct ieee80211_rx_status *rx_status) | ||
2069 | { | ||
2070 | struct ieee80211_local *local = sdata->local; | ||
2071 | struct ieee80211_if_sta *ifsta; | ||
2072 | struct ieee80211_mgmt *mgmt; | 1546 | struct ieee80211_mgmt *mgmt; |
2073 | u16 fc; | 1547 | u16 fc; |
2074 | 1548 | ||
2075 | if (skb->len < 24) | 1549 | if (skb->len < 24) |
2076 | goto fail; | 1550 | return RX_DROP_MONITOR; |
2077 | |||
2078 | ifsta = &sdata->u.sta; | ||
2079 | 1551 | ||
2080 | mgmt = (struct ieee80211_mgmt *) skb->data; | 1552 | mgmt = (struct ieee80211_mgmt *) skb->data; |
2081 | fc = le16_to_cpu(mgmt->frame_control); | 1553 | fc = le16_to_cpu(mgmt->frame_control); |
@@ -2090,147 +1562,68 @@ void ieee80211_sta_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff * | |||
2090 | case IEEE80211_STYPE_REASSOC_RESP: | 1562 | case IEEE80211_STYPE_REASSOC_RESP: |
2091 | case IEEE80211_STYPE_DEAUTH: | 1563 | case IEEE80211_STYPE_DEAUTH: |
2092 | case IEEE80211_STYPE_DISASSOC: | 1564 | case IEEE80211_STYPE_DISASSOC: |
2093 | skb_queue_tail(&ifsta->skb_queue, skb); | 1565 | skb_queue_tail(&sdata->u.mgd.skb_queue, skb); |
2094 | queue_work(local->hw.workqueue, &ifsta->work); | 1566 | queue_work(local->hw.workqueue, &sdata->u.mgd.work); |
2095 | return; | 1567 | return RX_QUEUED; |
2096 | } | 1568 | } |
2097 | 1569 | ||
2098 | fail: | 1570 | return RX_DROP_MONITOR; |
2099 | kfree_skb(skb); | ||
2100 | } | 1571 | } |
2101 | 1572 | ||
2102 | static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | 1573 | static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, |
2103 | struct sk_buff *skb) | 1574 | struct sk_buff *skb) |
2104 | { | 1575 | { |
2105 | struct ieee80211_rx_status *rx_status; | 1576 | struct ieee80211_rx_status *rx_status; |
2106 | struct ieee80211_if_sta *ifsta; | ||
2107 | struct ieee80211_mgmt *mgmt; | 1577 | struct ieee80211_mgmt *mgmt; |
2108 | u16 fc; | 1578 | u16 fc; |
2109 | 1579 | ||
2110 | ifsta = &sdata->u.sta; | ||
2111 | |||
2112 | rx_status = (struct ieee80211_rx_status *) skb->cb; | 1580 | rx_status = (struct ieee80211_rx_status *) skb->cb; |
2113 | mgmt = (struct ieee80211_mgmt *) skb->data; | 1581 | mgmt = (struct ieee80211_mgmt *) skb->data; |
2114 | fc = le16_to_cpu(mgmt->frame_control); | 1582 | fc = le16_to_cpu(mgmt->frame_control); |
2115 | 1583 | ||
2116 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { | 1584 | switch (fc & IEEE80211_FCTL_STYPE) { |
2117 | switch (fc & IEEE80211_FCTL_STYPE) { | 1585 | case IEEE80211_STYPE_PROBE_RESP: |
2118 | case IEEE80211_STYPE_PROBE_REQ: | 1586 | ieee80211_rx_mgmt_probe_resp(sdata, mgmt, skb->len, |
2119 | ieee80211_rx_mgmt_probe_req(sdata, ifsta, mgmt, | 1587 | rx_status); |
2120 | skb->len); | 1588 | break; |
2121 | break; | 1589 | case IEEE80211_STYPE_BEACON: |
2122 | case IEEE80211_STYPE_PROBE_RESP: | 1590 | ieee80211_rx_mgmt_beacon(sdata, mgmt, skb->len, |
2123 | ieee80211_rx_mgmt_probe_resp(sdata, mgmt, skb->len, | 1591 | rx_status); |
2124 | rx_status); | 1592 | break; |
2125 | break; | 1593 | case IEEE80211_STYPE_AUTH: |
2126 | case IEEE80211_STYPE_BEACON: | 1594 | ieee80211_rx_mgmt_auth(sdata, mgmt, skb->len); |
2127 | ieee80211_rx_mgmt_beacon(sdata, mgmt, skb->len, | 1595 | break; |
2128 | rx_status); | 1596 | case IEEE80211_STYPE_ASSOC_RESP: |
2129 | break; | 1597 | ieee80211_rx_mgmt_assoc_resp(sdata, mgmt, skb->len, 0); |
2130 | case IEEE80211_STYPE_AUTH: | 1598 | break; |
2131 | ieee80211_rx_mgmt_auth_ibss(sdata, ifsta, mgmt, | 1599 | case IEEE80211_STYPE_REASSOC_RESP: |
2132 | skb->len); | 1600 | ieee80211_rx_mgmt_assoc_resp(sdata, mgmt, skb->len, 1); |
2133 | break; | 1601 | break; |
2134 | } | 1602 | case IEEE80211_STYPE_DEAUTH: |
2135 | } else { /* NL80211_IFTYPE_STATION */ | 1603 | ieee80211_rx_mgmt_deauth(sdata, mgmt, skb->len); |
2136 | switch (fc & IEEE80211_FCTL_STYPE) { | 1604 | break; |
2137 | case IEEE80211_STYPE_PROBE_RESP: | 1605 | case IEEE80211_STYPE_DISASSOC: |
2138 | ieee80211_rx_mgmt_probe_resp(sdata, mgmt, skb->len, | 1606 | ieee80211_rx_mgmt_disassoc(sdata, mgmt, skb->len); |
2139 | rx_status); | 1607 | break; |
2140 | break; | ||
2141 | case IEEE80211_STYPE_BEACON: | ||
2142 | ieee80211_rx_mgmt_beacon(sdata, mgmt, skb->len, | ||
2143 | rx_status); | ||
2144 | break; | ||
2145 | case IEEE80211_STYPE_AUTH: | ||
2146 | ieee80211_rx_mgmt_auth(sdata, ifsta, mgmt, skb->len); | ||
2147 | break; | ||
2148 | case IEEE80211_STYPE_ASSOC_RESP: | ||
2149 | ieee80211_rx_mgmt_assoc_resp(sdata, ifsta, mgmt, | ||
2150 | skb->len, 0); | ||
2151 | break; | ||
2152 | case IEEE80211_STYPE_REASSOC_RESP: | ||
2153 | ieee80211_rx_mgmt_assoc_resp(sdata, ifsta, mgmt, | ||
2154 | skb->len, 1); | ||
2155 | break; | ||
2156 | case IEEE80211_STYPE_DEAUTH: | ||
2157 | ieee80211_rx_mgmt_deauth(sdata, ifsta, mgmt, skb->len); | ||
2158 | break; | ||
2159 | case IEEE80211_STYPE_DISASSOC: | ||
2160 | ieee80211_rx_mgmt_disassoc(sdata, ifsta, mgmt, | ||
2161 | skb->len); | ||
2162 | break; | ||
2163 | } | ||
2164 | } | 1608 | } |
2165 | 1609 | ||
2166 | kfree_skb(skb); | 1610 | kfree_skb(skb); |
2167 | } | 1611 | } |
2168 | 1612 | ||
2169 | |||
2170 | static int ieee80211_sta_active_ibss(struct ieee80211_sub_if_data *sdata) | ||
2171 | { | ||
2172 | struct ieee80211_local *local = sdata->local; | ||
2173 | int active = 0; | ||
2174 | struct sta_info *sta; | ||
2175 | |||
2176 | rcu_read_lock(); | ||
2177 | |||
2178 | list_for_each_entry_rcu(sta, &local->sta_list, list) { | ||
2179 | if (sta->sdata == sdata && | ||
2180 | time_after(sta->last_rx + IEEE80211_IBSS_MERGE_INTERVAL, | ||
2181 | jiffies)) { | ||
2182 | active++; | ||
2183 | break; | ||
2184 | } | ||
2185 | } | ||
2186 | |||
2187 | rcu_read_unlock(); | ||
2188 | |||
2189 | return active; | ||
2190 | } | ||
2191 | |||
2192 | |||
2193 | static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata, | ||
2194 | struct ieee80211_if_sta *ifsta) | ||
2195 | { | ||
2196 | mod_timer(&ifsta->timer, jiffies + IEEE80211_IBSS_MERGE_INTERVAL); | ||
2197 | |||
2198 | ieee80211_sta_expire(sdata, IEEE80211_IBSS_INACTIVITY_LIMIT); | ||
2199 | if (ieee80211_sta_active_ibss(sdata)) | ||
2200 | return; | ||
2201 | |||
2202 | if ((sdata->u.sta.flags & IEEE80211_STA_BSSID_SET) && | ||
2203 | (!(sdata->u.sta.flags & IEEE80211_STA_AUTO_CHANNEL_SEL))) | ||
2204 | return; | ||
2205 | |||
2206 | printk(KERN_DEBUG "%s: No active IBSS STAs - trying to scan for other " | ||
2207 | "IBSS networks with same SSID (merge)\n", sdata->dev->name); | ||
2208 | |||
2209 | /* XXX maybe racy? */ | ||
2210 | if (sdata->local->scan_req) | ||
2211 | return; | ||
2212 | |||
2213 | memcpy(sdata->local->int_scan_req.ssids[0].ssid, | ||
2214 | ifsta->ssid, IEEE80211_MAX_SSID_LEN); | ||
2215 | sdata->local->int_scan_req.ssids[0].ssid_len = ifsta->ssid_len; | ||
2216 | ieee80211_request_scan(sdata, &sdata->local->int_scan_req); | ||
2217 | } | ||
2218 | |||
2219 | |||
2220 | static void ieee80211_sta_timer(unsigned long data) | 1613 | static void ieee80211_sta_timer(unsigned long data) |
2221 | { | 1614 | { |
2222 | struct ieee80211_sub_if_data *sdata = | 1615 | struct ieee80211_sub_if_data *sdata = |
2223 | (struct ieee80211_sub_if_data *) data; | 1616 | (struct ieee80211_sub_if_data *) data; |
2224 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | 1617 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
2225 | struct ieee80211_local *local = sdata->local; | 1618 | struct ieee80211_local *local = sdata->local; |
2226 | 1619 | ||
2227 | set_bit(IEEE80211_STA_REQ_RUN, &ifsta->request); | 1620 | set_bit(IEEE80211_STA_REQ_RUN, &ifmgd->request); |
2228 | queue_work(local->hw.workqueue, &ifsta->work); | 1621 | queue_work(local->hw.workqueue, &ifmgd->work); |
2229 | } | 1622 | } |
2230 | 1623 | ||
2231 | static void ieee80211_sta_reset_auth(struct ieee80211_sub_if_data *sdata, | 1624 | static void ieee80211_sta_reset_auth(struct ieee80211_sub_if_data *sdata) |
2232 | struct ieee80211_if_sta *ifsta) | ||
2233 | { | 1625 | { |
1626 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
2234 | struct ieee80211_local *local = sdata->local; | 1627 | struct ieee80211_local *local = sdata->local; |
2235 | 1628 | ||
2236 | if (local->ops->reset_tsf) { | 1629 | if (local->ops->reset_tsf) { |
@@ -2238,191 +1631,39 @@ static void ieee80211_sta_reset_auth(struct ieee80211_sub_if_data *sdata, | |||
2238 | local->ops->reset_tsf(local_to_hw(local)); | 1631 | local->ops->reset_tsf(local_to_hw(local)); |
2239 | } | 1632 | } |
2240 | 1633 | ||
2241 | ifsta->wmm_last_param_set = -1; /* allow any WMM update */ | 1634 | ifmgd->wmm_last_param_set = -1; /* allow any WMM update */ |
2242 | 1635 | ||
2243 | 1636 | ||
2244 | if (ifsta->auth_algs & IEEE80211_AUTH_ALG_OPEN) | 1637 | if (ifmgd->auth_algs & IEEE80211_AUTH_ALG_OPEN) |
2245 | ifsta->auth_alg = WLAN_AUTH_OPEN; | 1638 | ifmgd->auth_alg = WLAN_AUTH_OPEN; |
2246 | else if (ifsta->auth_algs & IEEE80211_AUTH_ALG_SHARED_KEY) | 1639 | else if (ifmgd->auth_algs & IEEE80211_AUTH_ALG_SHARED_KEY) |
2247 | ifsta->auth_alg = WLAN_AUTH_SHARED_KEY; | 1640 | ifmgd->auth_alg = WLAN_AUTH_SHARED_KEY; |
2248 | else if (ifsta->auth_algs & IEEE80211_AUTH_ALG_LEAP) | 1641 | else if (ifmgd->auth_algs & IEEE80211_AUTH_ALG_LEAP) |
2249 | ifsta->auth_alg = WLAN_AUTH_LEAP; | 1642 | ifmgd->auth_alg = WLAN_AUTH_LEAP; |
2250 | else | 1643 | else |
2251 | ifsta->auth_alg = WLAN_AUTH_OPEN; | 1644 | ifmgd->auth_alg = WLAN_AUTH_OPEN; |
2252 | ifsta->auth_transaction = -1; | 1645 | ifmgd->auth_transaction = -1; |
2253 | ifsta->flags &= ~IEEE80211_STA_ASSOCIATED; | 1646 | ifmgd->flags &= ~IEEE80211_STA_ASSOCIATED; |
2254 | ifsta->assoc_scan_tries = 0; | 1647 | ifmgd->assoc_scan_tries = 0; |
2255 | ifsta->direct_probe_tries = 0; | 1648 | ifmgd->direct_probe_tries = 0; |
2256 | ifsta->auth_tries = 0; | 1649 | ifmgd->auth_tries = 0; |
2257 | ifsta->assoc_tries = 0; | 1650 | ifmgd->assoc_tries = 0; |
2258 | netif_tx_stop_all_queues(sdata->dev); | 1651 | netif_tx_stop_all_queues(sdata->dev); |
2259 | netif_carrier_off(sdata->dev); | 1652 | netif_carrier_off(sdata->dev); |
2260 | } | 1653 | } |
2261 | 1654 | ||
2262 | static int ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata, | 1655 | static int ieee80211_sta_config_auth(struct ieee80211_sub_if_data *sdata) |
2263 | struct ieee80211_if_sta *ifsta) | ||
2264 | { | ||
2265 | struct ieee80211_local *local = sdata->local; | ||
2266 | struct ieee80211_supported_band *sband; | ||
2267 | u8 *pos; | ||
2268 | u8 bssid[ETH_ALEN]; | ||
2269 | u8 supp_rates[IEEE80211_MAX_SUPP_RATES]; | ||
2270 | u16 capability; | ||
2271 | int i; | ||
2272 | |||
2273 | if (sdata->u.sta.flags & IEEE80211_STA_BSSID_SET) { | ||
2274 | memcpy(bssid, ifsta->bssid, ETH_ALEN); | ||
2275 | } else { | ||
2276 | /* Generate random, not broadcast, locally administered BSSID. Mix in | ||
2277 | * own MAC address to make sure that devices that do not have proper | ||
2278 | * random number generator get different BSSID. */ | ||
2279 | get_random_bytes(bssid, ETH_ALEN); | ||
2280 | for (i = 0; i < ETH_ALEN; i++) | ||
2281 | bssid[i] ^= sdata->dev->dev_addr[i]; | ||
2282 | bssid[0] &= ~0x01; | ||
2283 | bssid[0] |= 0x02; | ||
2284 | } | ||
2285 | |||
2286 | printk(KERN_DEBUG "%s: Creating new IBSS network, BSSID %pM\n", | ||
2287 | sdata->dev->name, bssid); | ||
2288 | |||
2289 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | ||
2290 | |||
2291 | if (local->hw.conf.beacon_int == 0) | ||
2292 | local->hw.conf.beacon_int = 100; | ||
2293 | |||
2294 | capability = WLAN_CAPABILITY_IBSS; | ||
2295 | |||
2296 | if (sdata->default_key) | ||
2297 | capability |= WLAN_CAPABILITY_PRIVACY; | ||
2298 | else | ||
2299 | sdata->drop_unencrypted = 0; | ||
2300 | |||
2301 | pos = supp_rates; | ||
2302 | for (i = 0; i < sband->n_bitrates; i++) { | ||
2303 | int rate = sband->bitrates[i].bitrate; | ||
2304 | *pos++ = (u8) (rate / 5); | ||
2305 | } | ||
2306 | |||
2307 | return __ieee80211_sta_join_ibss(sdata, ifsta, | ||
2308 | bssid, local->hw.conf.beacon_int, | ||
2309 | local->hw.conf.channel->center_freq, | ||
2310 | sband->n_bitrates, supp_rates, | ||
2311 | capability); | ||
2312 | } | ||
2313 | |||
2314 | |||
2315 | static int ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata, | ||
2316 | struct ieee80211_if_sta *ifsta) | ||
2317 | { | 1656 | { |
1657 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
2318 | struct ieee80211_local *local = sdata->local; | 1658 | struct ieee80211_local *local = sdata->local; |
2319 | struct ieee80211_bss *bss; | 1659 | struct ieee80211_bss *bss; |
2320 | int active_ibss; | 1660 | u8 *bssid = ifmgd->bssid, *ssid = ifmgd->ssid; |
2321 | 1661 | u8 ssid_len = ifmgd->ssid_len; | |
2322 | if (ifsta->ssid_len == 0) | ||
2323 | return -EINVAL; | ||
2324 | |||
2325 | active_ibss = ieee80211_sta_active_ibss(sdata); | ||
2326 | #ifdef CONFIG_MAC80211_IBSS_DEBUG | ||
2327 | printk(KERN_DEBUG "%s: sta_find_ibss (active_ibss=%d)\n", | ||
2328 | sdata->dev->name, active_ibss); | ||
2329 | #endif /* CONFIG_MAC80211_IBSS_DEBUG */ | ||
2330 | |||
2331 | if (active_ibss) | ||
2332 | return 0; | ||
2333 | |||
2334 | if (ifsta->flags & IEEE80211_STA_BSSID_SET) | ||
2335 | bss = ieee80211_rx_bss_get(local, ifsta->bssid, 0, | ||
2336 | ifsta->ssid, ifsta->ssid_len); | ||
2337 | else | ||
2338 | bss = (void *)cfg80211_get_ibss(local->hw.wiphy, | ||
2339 | NULL, | ||
2340 | ifsta->ssid, ifsta->ssid_len); | ||
2341 | |||
2342 | #ifdef CONFIG_MAC80211_IBSS_DEBUG | ||
2343 | if (bss) | ||
2344 | printk(KERN_DEBUG " sta_find_ibss: selected %pM current " | ||
2345 | "%pM\n", bss->cbss.bssid, ifsta->bssid); | ||
2346 | #endif /* CONFIG_MAC80211_IBSS_DEBUG */ | ||
2347 | |||
2348 | if (bss && | ||
2349 | (!(ifsta->flags & IEEE80211_STA_PREV_BSSID_SET) || | ||
2350 | memcmp(ifsta->bssid, bss->cbss.bssid, ETH_ALEN))) { | ||
2351 | int ret; | ||
2352 | |||
2353 | printk(KERN_DEBUG "%s: Selected IBSS BSSID %pM" | ||
2354 | " based on configured SSID\n", | ||
2355 | sdata->dev->name, bss->cbss.bssid); | ||
2356 | |||
2357 | ret = ieee80211_sta_join_ibss(sdata, ifsta, bss); | ||
2358 | ieee80211_rx_bss_put(local, bss); | ||
2359 | return ret; | ||
2360 | } else if (bss) | ||
2361 | ieee80211_rx_bss_put(local, bss); | ||
2362 | |||
2363 | #ifdef CONFIG_MAC80211_IBSS_DEBUG | ||
2364 | printk(KERN_DEBUG " did not try to join ibss\n"); | ||
2365 | #endif /* CONFIG_MAC80211_IBSS_DEBUG */ | ||
2366 | |||
2367 | /* Selected IBSS not found in current scan results - try to scan */ | ||
2368 | if (ifsta->state == IEEE80211_STA_MLME_IBSS_JOINED && | ||
2369 | !ieee80211_sta_active_ibss(sdata)) { | ||
2370 | mod_timer(&ifsta->timer, jiffies + | ||
2371 | IEEE80211_IBSS_MERGE_INTERVAL); | ||
2372 | } else if (time_after(jiffies, local->last_scan_completed + | ||
2373 | IEEE80211_SCAN_INTERVAL)) { | ||
2374 | printk(KERN_DEBUG "%s: Trigger new scan to find an IBSS to " | ||
2375 | "join\n", sdata->dev->name); | ||
2376 | |||
2377 | /* XXX maybe racy? */ | ||
2378 | if (local->scan_req) | ||
2379 | return -EBUSY; | ||
2380 | |||
2381 | memcpy(local->int_scan_req.ssids[0].ssid, | ||
2382 | ifsta->ssid, IEEE80211_MAX_SSID_LEN); | ||
2383 | local->int_scan_req.ssids[0].ssid_len = ifsta->ssid_len; | ||
2384 | return ieee80211_request_scan(sdata, &local->int_scan_req); | ||
2385 | } else if (ifsta->state != IEEE80211_STA_MLME_IBSS_JOINED) { | ||
2386 | int interval = IEEE80211_SCAN_INTERVAL; | ||
2387 | |||
2388 | if (time_after(jiffies, ifsta->ibss_join_req + | ||
2389 | IEEE80211_IBSS_JOIN_TIMEOUT)) { | ||
2390 | if ((ifsta->flags & IEEE80211_STA_CREATE_IBSS) && | ||
2391 | (!(local->oper_channel->flags & | ||
2392 | IEEE80211_CHAN_NO_IBSS))) | ||
2393 | return ieee80211_sta_create_ibss(sdata, ifsta); | ||
2394 | if (ifsta->flags & IEEE80211_STA_CREATE_IBSS) { | ||
2395 | printk(KERN_DEBUG "%s: IBSS not allowed on" | ||
2396 | " %d MHz\n", sdata->dev->name, | ||
2397 | local->hw.conf.channel->center_freq); | ||
2398 | } | ||
2399 | |||
2400 | /* No IBSS found - decrease scan interval and continue | ||
2401 | * scanning. */ | ||
2402 | interval = IEEE80211_SCAN_INTERVAL_SLOW; | ||
2403 | } | ||
2404 | |||
2405 | ifsta->state = IEEE80211_STA_MLME_IBSS_SEARCH; | ||
2406 | mod_timer(&ifsta->timer, jiffies + interval); | ||
2407 | return 0; | ||
2408 | } | ||
2409 | |||
2410 | return 0; | ||
2411 | } | ||
2412 | |||
2413 | |||
2414 | static int ieee80211_sta_config_auth(struct ieee80211_sub_if_data *sdata, | ||
2415 | struct ieee80211_if_sta *ifsta) | ||
2416 | { | ||
2417 | struct ieee80211_local *local = sdata->local; | ||
2418 | struct ieee80211_bss *bss; | ||
2419 | u8 *bssid = ifsta->bssid, *ssid = ifsta->ssid; | ||
2420 | u8 ssid_len = ifsta->ssid_len; | ||
2421 | u16 capa_mask = WLAN_CAPABILITY_ESS; | 1662 | u16 capa_mask = WLAN_CAPABILITY_ESS; |
2422 | u16 capa_val = WLAN_CAPABILITY_ESS; | 1663 | u16 capa_val = WLAN_CAPABILITY_ESS; |
2423 | struct ieee80211_channel *chan = local->oper_channel; | 1664 | struct ieee80211_channel *chan = local->oper_channel; |
2424 | 1665 | ||
2425 | if (ifsta->flags & (IEEE80211_STA_AUTO_SSID_SEL | | 1666 | if (ifmgd->flags & (IEEE80211_STA_AUTO_SSID_SEL | |
2426 | IEEE80211_STA_AUTO_BSSID_SEL | | 1667 | IEEE80211_STA_AUTO_BSSID_SEL | |
2427 | IEEE80211_STA_AUTO_CHANNEL_SEL)) { | 1668 | IEEE80211_STA_AUTO_CHANNEL_SEL)) { |
2428 | capa_mask |= WLAN_CAPABILITY_PRIVACY; | 1669 | capa_mask |= WLAN_CAPABILITY_PRIVACY; |
@@ -2430,13 +1671,13 @@ static int ieee80211_sta_config_auth(struct ieee80211_sub_if_data *sdata, | |||
2430 | capa_val |= WLAN_CAPABILITY_PRIVACY; | 1671 | capa_val |= WLAN_CAPABILITY_PRIVACY; |
2431 | } | 1672 | } |
2432 | 1673 | ||
2433 | if (ifsta->flags & IEEE80211_STA_AUTO_CHANNEL_SEL) | 1674 | if (ifmgd->flags & IEEE80211_STA_AUTO_CHANNEL_SEL) |
2434 | chan = NULL; | 1675 | chan = NULL; |
2435 | 1676 | ||
2436 | if (ifsta->flags & IEEE80211_STA_AUTO_BSSID_SEL) | 1677 | if (ifmgd->flags & IEEE80211_STA_AUTO_BSSID_SEL) |
2437 | bssid = NULL; | 1678 | bssid = NULL; |
2438 | 1679 | ||
2439 | if (ifsta->flags & IEEE80211_STA_AUTO_SSID_SEL) { | 1680 | if (ifmgd->flags & IEEE80211_STA_AUTO_SSID_SEL) { |
2440 | ssid = NULL; | 1681 | ssid = NULL; |
2441 | ssid_len = 0; | 1682 | ssid_len = 0; |
2442 | } | 1683 | } |
@@ -2447,16 +1688,16 @@ static int ieee80211_sta_config_auth(struct ieee80211_sub_if_data *sdata, | |||
2447 | 1688 | ||
2448 | if (bss) { | 1689 | if (bss) { |
2449 | ieee80211_set_freq(sdata, bss->cbss.channel->center_freq); | 1690 | ieee80211_set_freq(sdata, bss->cbss.channel->center_freq); |
2450 | if (!(ifsta->flags & IEEE80211_STA_SSID_SET)) | 1691 | if (!(ifmgd->flags & IEEE80211_STA_SSID_SET)) |
2451 | ieee80211_sta_set_ssid(sdata, bss->ssid, | 1692 | ieee80211_sta_set_ssid(sdata, bss->ssid, |
2452 | bss->ssid_len); | 1693 | bss->ssid_len); |
2453 | ieee80211_sta_set_bssid(sdata, bss->cbss.bssid); | 1694 | ieee80211_sta_set_bssid(sdata, bss->cbss.bssid); |
2454 | ieee80211_sta_def_wmm_params(sdata, bss->supp_rates_len, | 1695 | ieee80211_sta_def_wmm_params(sdata, bss->supp_rates_len, |
2455 | bss->supp_rates); | 1696 | bss->supp_rates); |
2456 | if (sdata->u.sta.mfp == IEEE80211_MFP_REQUIRED) | 1697 | if (sdata->u.mgd.mfp == IEEE80211_MFP_REQUIRED) |
2457 | sdata->u.sta.flags |= IEEE80211_STA_MFP_ENABLED; | 1698 | sdata->u.mgd.flags |= IEEE80211_STA_MFP_ENABLED; |
2458 | else | 1699 | else |
2459 | sdata->u.sta.flags &= ~IEEE80211_STA_MFP_ENABLED; | 1700 | sdata->u.mgd.flags &= ~IEEE80211_STA_MFP_ENABLED; |
2460 | 1701 | ||
2461 | /* Send out direct probe if no probe resp was received or | 1702 | /* Send out direct probe if no probe resp was received or |
2462 | * the one we have is outdated | 1703 | * the one we have is outdated |
@@ -2464,31 +1705,31 @@ static int ieee80211_sta_config_auth(struct ieee80211_sub_if_data *sdata, | |||
2464 | if (!bss->last_probe_resp || | 1705 | if (!bss->last_probe_resp || |
2465 | time_after(jiffies, bss->last_probe_resp | 1706 | time_after(jiffies, bss->last_probe_resp |
2466 | + IEEE80211_SCAN_RESULT_EXPIRE)) | 1707 | + IEEE80211_SCAN_RESULT_EXPIRE)) |
2467 | ifsta->state = IEEE80211_STA_MLME_DIRECT_PROBE; | 1708 | ifmgd->state = IEEE80211_STA_MLME_DIRECT_PROBE; |
2468 | else | 1709 | else |
2469 | ifsta->state = IEEE80211_STA_MLME_AUTHENTICATE; | 1710 | ifmgd->state = IEEE80211_STA_MLME_AUTHENTICATE; |
2470 | 1711 | ||
2471 | ieee80211_rx_bss_put(local, bss); | 1712 | ieee80211_rx_bss_put(local, bss); |
2472 | ieee80211_sta_reset_auth(sdata, ifsta); | 1713 | ieee80211_sta_reset_auth(sdata); |
2473 | return 0; | 1714 | return 0; |
2474 | } else { | 1715 | } else { |
2475 | if (ifsta->assoc_scan_tries < IEEE80211_ASSOC_SCANS_MAX_TRIES) { | 1716 | if (ifmgd->assoc_scan_tries < IEEE80211_ASSOC_SCANS_MAX_TRIES) { |
2476 | ifsta->assoc_scan_tries++; | 1717 | ifmgd->assoc_scan_tries++; |
2477 | /* XXX maybe racy? */ | 1718 | /* XXX maybe racy? */ |
2478 | if (local->scan_req) | 1719 | if (local->scan_req) |
2479 | return -1; | 1720 | return -1; |
2480 | memcpy(local->int_scan_req.ssids[0].ssid, | 1721 | memcpy(local->int_scan_req.ssids[0].ssid, |
2481 | ifsta->ssid, IEEE80211_MAX_SSID_LEN); | 1722 | ifmgd->ssid, IEEE80211_MAX_SSID_LEN); |
2482 | if (ifsta->flags & IEEE80211_STA_AUTO_SSID_SEL) | 1723 | if (ifmgd->flags & IEEE80211_STA_AUTO_SSID_SEL) |
2483 | local->int_scan_req.ssids[0].ssid_len = 0; | 1724 | local->int_scan_req.ssids[0].ssid_len = 0; |
2484 | else | 1725 | else |
2485 | local->int_scan_req.ssids[0].ssid_len = ifsta->ssid_len; | 1726 | local->int_scan_req.ssids[0].ssid_len = ifmgd->ssid_len; |
2486 | ieee80211_start_scan(sdata, &local->int_scan_req); | 1727 | ieee80211_start_scan(sdata, &local->int_scan_req); |
2487 | ifsta->state = IEEE80211_STA_MLME_AUTHENTICATE; | 1728 | ifmgd->state = IEEE80211_STA_MLME_AUTHENTICATE; |
2488 | set_bit(IEEE80211_STA_REQ_AUTH, &ifsta->request); | 1729 | set_bit(IEEE80211_STA_REQ_AUTH, &ifmgd->request); |
2489 | } else { | 1730 | } else { |
2490 | ifsta->assoc_scan_tries = 0; | 1731 | ifmgd->assoc_scan_tries = 0; |
2491 | ifsta->state = IEEE80211_STA_MLME_DISABLED; | 1732 | ifmgd->state = IEEE80211_STA_MLME_DISABLED; |
2492 | } | 1733 | } |
2493 | } | 1734 | } |
2494 | return -1; | 1735 | return -1; |
@@ -2498,9 +1739,9 @@ static int ieee80211_sta_config_auth(struct ieee80211_sub_if_data *sdata, | |||
2498 | static void ieee80211_sta_work(struct work_struct *work) | 1739 | static void ieee80211_sta_work(struct work_struct *work) |
2499 | { | 1740 | { |
2500 | struct ieee80211_sub_if_data *sdata = | 1741 | struct ieee80211_sub_if_data *sdata = |
2501 | container_of(work, struct ieee80211_sub_if_data, u.sta.work); | 1742 | container_of(work, struct ieee80211_sub_if_data, u.mgd.work); |
2502 | struct ieee80211_local *local = sdata->local; | 1743 | struct ieee80211_local *local = sdata->local; |
2503 | struct ieee80211_if_sta *ifsta; | 1744 | struct ieee80211_if_managed *ifmgd; |
2504 | struct sk_buff *skb; | 1745 | struct sk_buff *skb; |
2505 | 1746 | ||
2506 | if (!netif_running(sdata->dev)) | 1747 | if (!netif_running(sdata->dev)) |
@@ -2509,60 +1750,53 @@ static void ieee80211_sta_work(struct work_struct *work) | |||
2509 | if (local->sw_scanning || local->hw_scanning) | 1750 | if (local->sw_scanning || local->hw_scanning) |
2510 | return; | 1751 | return; |
2511 | 1752 | ||
2512 | if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION && | 1753 | if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION)) |
2513 | sdata->vif.type != NL80211_IFTYPE_ADHOC)) | ||
2514 | return; | 1754 | return; |
2515 | ifsta = &sdata->u.sta; | 1755 | ifmgd = &sdata->u.mgd; |
2516 | 1756 | ||
2517 | while ((skb = skb_dequeue(&ifsta->skb_queue))) | 1757 | while ((skb = skb_dequeue(&ifmgd->skb_queue))) |
2518 | ieee80211_sta_rx_queued_mgmt(sdata, skb); | 1758 | ieee80211_sta_rx_queued_mgmt(sdata, skb); |
2519 | 1759 | ||
2520 | if (ifsta->state != IEEE80211_STA_MLME_DIRECT_PROBE && | 1760 | if (ifmgd->state != IEEE80211_STA_MLME_DIRECT_PROBE && |
2521 | ifsta->state != IEEE80211_STA_MLME_AUTHENTICATE && | 1761 | ifmgd->state != IEEE80211_STA_MLME_AUTHENTICATE && |
2522 | ifsta->state != IEEE80211_STA_MLME_ASSOCIATE && | 1762 | ifmgd->state != IEEE80211_STA_MLME_ASSOCIATE && |
2523 | test_and_clear_bit(IEEE80211_STA_REQ_SCAN, &ifsta->request)) { | 1763 | test_and_clear_bit(IEEE80211_STA_REQ_SCAN, &ifmgd->request)) { |
2524 | ieee80211_start_scan(sdata, local->scan_req); | 1764 | ieee80211_start_scan(sdata, local->scan_req); |
2525 | return; | 1765 | return; |
2526 | } | 1766 | } |
2527 | 1767 | ||
2528 | if (test_and_clear_bit(IEEE80211_STA_REQ_AUTH, &ifsta->request)) { | 1768 | if (test_and_clear_bit(IEEE80211_STA_REQ_AUTH, &ifmgd->request)) { |
2529 | if (ieee80211_sta_config_auth(sdata, ifsta)) | 1769 | if (ieee80211_sta_config_auth(sdata)) |
2530 | return; | 1770 | return; |
2531 | clear_bit(IEEE80211_STA_REQ_RUN, &ifsta->request); | 1771 | clear_bit(IEEE80211_STA_REQ_RUN, &ifmgd->request); |
2532 | } else if (!test_and_clear_bit(IEEE80211_STA_REQ_RUN, &ifsta->request)) | 1772 | } else if (!test_and_clear_bit(IEEE80211_STA_REQ_RUN, &ifmgd->request)) |
2533 | return; | 1773 | return; |
2534 | 1774 | ||
2535 | switch (ifsta->state) { | 1775 | switch (ifmgd->state) { |
2536 | case IEEE80211_STA_MLME_DISABLED: | 1776 | case IEEE80211_STA_MLME_DISABLED: |
2537 | break; | 1777 | break; |
2538 | case IEEE80211_STA_MLME_DIRECT_PROBE: | 1778 | case IEEE80211_STA_MLME_DIRECT_PROBE: |
2539 | ieee80211_direct_probe(sdata, ifsta); | 1779 | ieee80211_direct_probe(sdata); |
2540 | break; | 1780 | break; |
2541 | case IEEE80211_STA_MLME_AUTHENTICATE: | 1781 | case IEEE80211_STA_MLME_AUTHENTICATE: |
2542 | ieee80211_authenticate(sdata, ifsta); | 1782 | ieee80211_authenticate(sdata); |
2543 | break; | 1783 | break; |
2544 | case IEEE80211_STA_MLME_ASSOCIATE: | 1784 | case IEEE80211_STA_MLME_ASSOCIATE: |
2545 | ieee80211_associate(sdata, ifsta); | 1785 | ieee80211_associate(sdata); |
2546 | break; | 1786 | break; |
2547 | case IEEE80211_STA_MLME_ASSOCIATED: | 1787 | case IEEE80211_STA_MLME_ASSOCIATED: |
2548 | ieee80211_associated(sdata, ifsta); | 1788 | ieee80211_associated(sdata); |
2549 | break; | ||
2550 | case IEEE80211_STA_MLME_IBSS_SEARCH: | ||
2551 | ieee80211_sta_find_ibss(sdata, ifsta); | ||
2552 | break; | ||
2553 | case IEEE80211_STA_MLME_IBSS_JOINED: | ||
2554 | ieee80211_sta_merge_ibss(sdata, ifsta); | ||
2555 | break; | 1789 | break; |
2556 | default: | 1790 | default: |
2557 | WARN_ON(1); | 1791 | WARN_ON(1); |
2558 | break; | 1792 | break; |
2559 | } | 1793 | } |
2560 | 1794 | ||
2561 | if (ieee80211_privacy_mismatch(sdata, ifsta)) { | 1795 | if (ieee80211_privacy_mismatch(sdata)) { |
2562 | printk(KERN_DEBUG "%s: privacy configuration mismatch and " | 1796 | printk(KERN_DEBUG "%s: privacy configuration mismatch and " |
2563 | "mixed-cell disabled - disassociate\n", sdata->dev->name); | 1797 | "mixed-cell disabled - disassociate\n", sdata->dev->name); |
2564 | 1798 | ||
2565 | ieee80211_set_disassoc(sdata, ifsta, false, true, | 1799 | ieee80211_set_disassoc(sdata, false, true, |
2566 | WLAN_REASON_UNSPECIFIED); | 1800 | WLAN_REASON_UNSPECIFIED); |
2567 | } | 1801 | } |
2568 | } | 1802 | } |
@@ -2571,155 +1805,106 @@ static void ieee80211_restart_sta_timer(struct ieee80211_sub_if_data *sdata) | |||
2571 | { | 1805 | { |
2572 | if (sdata->vif.type == NL80211_IFTYPE_STATION) | 1806 | if (sdata->vif.type == NL80211_IFTYPE_STATION) |
2573 | queue_work(sdata->local->hw.workqueue, | 1807 | queue_work(sdata->local->hw.workqueue, |
2574 | &sdata->u.sta.work); | 1808 | &sdata->u.mgd.work); |
2575 | } | 1809 | } |
2576 | 1810 | ||
2577 | /* interface setup */ | 1811 | /* interface setup */ |
2578 | void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) | 1812 | void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) |
2579 | { | 1813 | { |
2580 | struct ieee80211_if_sta *ifsta; | 1814 | struct ieee80211_if_managed *ifmgd; |
2581 | 1815 | ||
2582 | ifsta = &sdata->u.sta; | 1816 | ifmgd = &sdata->u.mgd; |
2583 | INIT_WORK(&ifsta->work, ieee80211_sta_work); | 1817 | INIT_WORK(&ifmgd->work, ieee80211_sta_work); |
2584 | INIT_WORK(&ifsta->chswitch_work, ieee80211_chswitch_work); | 1818 | INIT_WORK(&ifmgd->chswitch_work, ieee80211_chswitch_work); |
2585 | setup_timer(&ifsta->timer, ieee80211_sta_timer, | 1819 | setup_timer(&ifmgd->timer, ieee80211_sta_timer, |
2586 | (unsigned long) sdata); | 1820 | (unsigned long) sdata); |
2587 | setup_timer(&ifsta->chswitch_timer, ieee80211_chswitch_timer, | 1821 | setup_timer(&ifmgd->chswitch_timer, ieee80211_chswitch_timer, |
2588 | (unsigned long) sdata); | 1822 | (unsigned long) sdata); |
2589 | skb_queue_head_init(&ifsta->skb_queue); | 1823 | skb_queue_head_init(&ifmgd->skb_queue); |
2590 | 1824 | ||
2591 | ifsta->capab = WLAN_CAPABILITY_ESS; | 1825 | ifmgd->capab = WLAN_CAPABILITY_ESS; |
2592 | ifsta->auth_algs = IEEE80211_AUTH_ALG_OPEN | | 1826 | ifmgd->auth_algs = IEEE80211_AUTH_ALG_OPEN | |
2593 | IEEE80211_AUTH_ALG_SHARED_KEY; | 1827 | IEEE80211_AUTH_ALG_SHARED_KEY; |
2594 | ifsta->flags |= IEEE80211_STA_CREATE_IBSS | | 1828 | ifmgd->flags |= IEEE80211_STA_CREATE_IBSS | |
2595 | IEEE80211_STA_AUTO_BSSID_SEL | | 1829 | IEEE80211_STA_AUTO_BSSID_SEL | |
2596 | IEEE80211_STA_AUTO_CHANNEL_SEL; | 1830 | IEEE80211_STA_AUTO_CHANNEL_SEL; |
2597 | if (ieee80211_num_regular_queues(&sdata->local->hw) >= 4) | 1831 | if (ieee80211_num_regular_queues(&sdata->local->hw) >= 4) |
2598 | ifsta->flags |= IEEE80211_STA_WMM_ENABLED; | 1832 | ifmgd->flags |= IEEE80211_STA_WMM_ENABLED; |
2599 | } | ||
2600 | |||
2601 | /* | ||
2602 | * Add a new IBSS station, will also be called by the RX code when, | ||
2603 | * in IBSS mode, receiving a frame from a yet-unknown station, hence | ||
2604 | * must be callable in atomic context. | ||
2605 | */ | ||
2606 | struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, | ||
2607 | u8 *bssid,u8 *addr, u32 supp_rates) | ||
2608 | { | ||
2609 | struct ieee80211_local *local = sdata->local; | ||
2610 | struct sta_info *sta; | ||
2611 | int band = local->hw.conf.channel->band; | ||
2612 | |||
2613 | /* TODO: Could consider removing the least recently used entry and | ||
2614 | * allow new one to be added. */ | ||
2615 | if (local->num_sta >= IEEE80211_IBSS_MAX_STA_ENTRIES) { | ||
2616 | if (net_ratelimit()) { | ||
2617 | printk(KERN_DEBUG "%s: No room for a new IBSS STA " | ||
2618 | "entry %pM\n", sdata->dev->name, addr); | ||
2619 | } | ||
2620 | return NULL; | ||
2621 | } | ||
2622 | |||
2623 | if (compare_ether_addr(bssid, sdata->u.sta.bssid)) | ||
2624 | return NULL; | ||
2625 | |||
2626 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | ||
2627 | printk(KERN_DEBUG "%s: Adding new IBSS station %pM (dev=%s)\n", | ||
2628 | wiphy_name(local->hw.wiphy), addr, sdata->dev->name); | ||
2629 | #endif | ||
2630 | |||
2631 | sta = sta_info_alloc(sdata, addr, GFP_ATOMIC); | ||
2632 | if (!sta) | ||
2633 | return NULL; | ||
2634 | |||
2635 | set_sta_flags(sta, WLAN_STA_AUTHORIZED); | ||
2636 | |||
2637 | /* make sure mandatory rates are always added */ | ||
2638 | sta->sta.supp_rates[band] = supp_rates | | ||
2639 | ieee80211_mandatory_rates(local, band); | ||
2640 | |||
2641 | rate_control_rate_init(sta); | ||
2642 | |||
2643 | if (sta_info_insert(sta)) | ||
2644 | return NULL; | ||
2645 | |||
2646 | return sta; | ||
2647 | } | 1833 | } |
2648 | 1834 | ||
2649 | /* configuration hooks */ | 1835 | /* configuration hooks */ |
2650 | void ieee80211_sta_req_auth(struct ieee80211_sub_if_data *sdata, | 1836 | void ieee80211_sta_req_auth(struct ieee80211_sub_if_data *sdata) |
2651 | struct ieee80211_if_sta *ifsta) | ||
2652 | { | 1837 | { |
1838 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
2653 | struct ieee80211_local *local = sdata->local; | 1839 | struct ieee80211_local *local = sdata->local; |
2654 | 1840 | ||
2655 | if (sdata->vif.type != NL80211_IFTYPE_STATION) | 1841 | if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION)) |
2656 | return; | 1842 | return; |
2657 | 1843 | ||
2658 | if ((ifsta->flags & (IEEE80211_STA_BSSID_SET | | 1844 | if ((ifmgd->flags & (IEEE80211_STA_BSSID_SET | |
2659 | IEEE80211_STA_AUTO_BSSID_SEL)) && | 1845 | IEEE80211_STA_AUTO_BSSID_SEL)) && |
2660 | (ifsta->flags & (IEEE80211_STA_SSID_SET | | 1846 | (ifmgd->flags & (IEEE80211_STA_SSID_SET | |
2661 | IEEE80211_STA_AUTO_SSID_SEL))) { | 1847 | IEEE80211_STA_AUTO_SSID_SEL))) { |
2662 | 1848 | ||
2663 | if (ifsta->state == IEEE80211_STA_MLME_ASSOCIATED) | 1849 | if (ifmgd->state == IEEE80211_STA_MLME_ASSOCIATED) |
2664 | ieee80211_set_disassoc(sdata, ifsta, true, true, | 1850 | ieee80211_set_disassoc(sdata, true, true, |
2665 | WLAN_REASON_DEAUTH_LEAVING); | 1851 | WLAN_REASON_DEAUTH_LEAVING); |
2666 | 1852 | ||
2667 | set_bit(IEEE80211_STA_REQ_AUTH, &ifsta->request); | 1853 | set_bit(IEEE80211_STA_REQ_AUTH, &ifmgd->request); |
2668 | queue_work(local->hw.workqueue, &ifsta->work); | 1854 | queue_work(local->hw.workqueue, &ifmgd->work); |
2669 | } | 1855 | } |
2670 | } | 1856 | } |
2671 | 1857 | ||
2672 | int ieee80211_sta_set_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t len) | 1858 | int ieee80211_sta_commit(struct ieee80211_sub_if_data *sdata) |
2673 | { | 1859 | { |
2674 | struct ieee80211_if_sta *ifsta; | 1860 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
2675 | 1861 | ||
2676 | if (len > IEEE80211_MAX_SSID_LEN) | 1862 | ifmgd->flags &= ~IEEE80211_STA_PREV_BSSID_SET; |
2677 | return -EINVAL; | ||
2678 | 1863 | ||
2679 | ifsta = &sdata->u.sta; | 1864 | if (ifmgd->ssid_len) |
1865 | ifmgd->flags |= IEEE80211_STA_SSID_SET; | ||
1866 | else | ||
1867 | ifmgd->flags &= ~IEEE80211_STA_SSID_SET; | ||
2680 | 1868 | ||
2681 | if (ifsta->ssid_len != len || memcmp(ifsta->ssid, ssid, len) != 0) { | 1869 | return 0; |
2682 | memset(ifsta->ssid, 0, sizeof(ifsta->ssid)); | 1870 | } |
2683 | memcpy(ifsta->ssid, ssid, len); | ||
2684 | ifsta->ssid_len = len; | ||
2685 | } | ||
2686 | 1871 | ||
2687 | ifsta->flags &= ~IEEE80211_STA_PREV_BSSID_SET; | 1872 | int ieee80211_sta_set_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t len) |
1873 | { | ||
1874 | struct ieee80211_if_managed *ifmgd; | ||
2688 | 1875 | ||
2689 | if (len) | 1876 | if (len > IEEE80211_MAX_SSID_LEN) |
2690 | ifsta->flags |= IEEE80211_STA_SSID_SET; | 1877 | return -EINVAL; |
2691 | else | 1878 | |
2692 | ifsta->flags &= ~IEEE80211_STA_SSID_SET; | 1879 | ifmgd = &sdata->u.mgd; |
2693 | 1880 | ||
2694 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { | 1881 | if (ifmgd->ssid_len != len || memcmp(ifmgd->ssid, ssid, len) != 0) { |
2695 | ifsta->ibss_join_req = jiffies; | 1882 | memset(ifmgd->ssid, 0, sizeof(ifmgd->ssid)); |
2696 | ifsta->state = IEEE80211_STA_MLME_IBSS_SEARCH; | 1883 | memcpy(ifmgd->ssid, ssid, len); |
2697 | return ieee80211_sta_find_ibss(sdata, ifsta); | 1884 | ifmgd->ssid_len = len; |
2698 | } | 1885 | } |
2699 | 1886 | ||
2700 | return 0; | 1887 | return ieee80211_sta_commit(sdata); |
2701 | } | 1888 | } |
2702 | 1889 | ||
2703 | int ieee80211_sta_get_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t *len) | 1890 | int ieee80211_sta_get_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t *len) |
2704 | { | 1891 | { |
2705 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | 1892 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
2706 | memcpy(ssid, ifsta->ssid, ifsta->ssid_len); | 1893 | memcpy(ssid, ifmgd->ssid, ifmgd->ssid_len); |
2707 | *len = ifsta->ssid_len; | 1894 | *len = ifmgd->ssid_len; |
2708 | return 0; | 1895 | return 0; |
2709 | } | 1896 | } |
2710 | 1897 | ||
2711 | int ieee80211_sta_set_bssid(struct ieee80211_sub_if_data *sdata, u8 *bssid) | 1898 | int ieee80211_sta_set_bssid(struct ieee80211_sub_if_data *sdata, u8 *bssid) |
2712 | { | 1899 | { |
2713 | struct ieee80211_if_sta *ifsta; | 1900 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
2714 | |||
2715 | ifsta = &sdata->u.sta; | ||
2716 | 1901 | ||
2717 | if (is_valid_ether_addr(bssid)) { | 1902 | if (is_valid_ether_addr(bssid)) { |
2718 | memcpy(ifsta->bssid, bssid, ETH_ALEN); | 1903 | memcpy(ifmgd->bssid, bssid, ETH_ALEN); |
2719 | ifsta->flags |= IEEE80211_STA_BSSID_SET; | 1904 | ifmgd->flags |= IEEE80211_STA_BSSID_SET; |
2720 | } else { | 1905 | } else { |
2721 | memset(ifsta->bssid, 0, ETH_ALEN); | 1906 | memset(ifmgd->bssid, 0, ETH_ALEN); |
2722 | ifsta->flags &= ~IEEE80211_STA_BSSID_SET; | 1907 | ifmgd->flags &= ~IEEE80211_STA_BSSID_SET; |
2723 | } | 1908 | } |
2724 | 1909 | ||
2725 | if (netif_running(sdata->dev)) { | 1910 | if (netif_running(sdata->dev)) { |
@@ -2729,47 +1914,44 @@ int ieee80211_sta_set_bssid(struct ieee80211_sub_if_data *sdata, u8 *bssid) | |||
2729 | } | 1914 | } |
2730 | } | 1915 | } |
2731 | 1916 | ||
2732 | return ieee80211_sta_set_ssid(sdata, ifsta->ssid, ifsta->ssid_len); | 1917 | return ieee80211_sta_commit(sdata); |
2733 | } | 1918 | } |
2734 | 1919 | ||
2735 | int ieee80211_sta_set_extra_ie(struct ieee80211_sub_if_data *sdata, char *ie, size_t len) | 1920 | int ieee80211_sta_set_extra_ie(struct ieee80211_sub_if_data *sdata, char *ie, size_t len) |
2736 | { | 1921 | { |
2737 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | 1922 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
2738 | 1923 | ||
2739 | kfree(ifsta->extra_ie); | 1924 | kfree(ifmgd->extra_ie); |
2740 | if (len == 0) { | 1925 | if (len == 0) { |
2741 | ifsta->extra_ie = NULL; | 1926 | ifmgd->extra_ie = NULL; |
2742 | ifsta->extra_ie_len = 0; | 1927 | ifmgd->extra_ie_len = 0; |
2743 | return 0; | 1928 | return 0; |
2744 | } | 1929 | } |
2745 | ifsta->extra_ie = kmalloc(len, GFP_KERNEL); | 1930 | ifmgd->extra_ie = kmalloc(len, GFP_KERNEL); |
2746 | if (!ifsta->extra_ie) { | 1931 | if (!ifmgd->extra_ie) { |
2747 | ifsta->extra_ie_len = 0; | 1932 | ifmgd->extra_ie_len = 0; |
2748 | return -ENOMEM; | 1933 | return -ENOMEM; |
2749 | } | 1934 | } |
2750 | memcpy(ifsta->extra_ie, ie, len); | 1935 | memcpy(ifmgd->extra_ie, ie, len); |
2751 | ifsta->extra_ie_len = len; | 1936 | ifmgd->extra_ie_len = len; |
2752 | return 0; | 1937 | return 0; |
2753 | } | 1938 | } |
2754 | 1939 | ||
2755 | int ieee80211_sta_deauthenticate(struct ieee80211_sub_if_data *sdata, u16 reason) | 1940 | int ieee80211_sta_deauthenticate(struct ieee80211_sub_if_data *sdata, u16 reason) |
2756 | { | 1941 | { |
2757 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | ||
2758 | |||
2759 | printk(KERN_DEBUG "%s: deauthenticating by local choice (reason=%d)\n", | 1942 | printk(KERN_DEBUG "%s: deauthenticating by local choice (reason=%d)\n", |
2760 | sdata->dev->name, reason); | 1943 | sdata->dev->name, reason); |
2761 | 1944 | ||
2762 | if (sdata->vif.type != NL80211_IFTYPE_STATION && | 1945 | if (sdata->vif.type != NL80211_IFTYPE_STATION) |
2763 | sdata->vif.type != NL80211_IFTYPE_ADHOC) | ||
2764 | return -EINVAL; | 1946 | return -EINVAL; |
2765 | 1947 | ||
2766 | ieee80211_set_disassoc(sdata, ifsta, true, true, reason); | 1948 | ieee80211_set_disassoc(sdata, true, true, reason); |
2767 | return 0; | 1949 | return 0; |
2768 | } | 1950 | } |
2769 | 1951 | ||
2770 | int ieee80211_sta_disassociate(struct ieee80211_sub_if_data *sdata, u16 reason) | 1952 | int ieee80211_sta_disassociate(struct ieee80211_sub_if_data *sdata, u16 reason) |
2771 | { | 1953 | { |
2772 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | 1954 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
2773 | 1955 | ||
2774 | printk(KERN_DEBUG "%s: disassociating by local choice (reason=%d)\n", | 1956 | printk(KERN_DEBUG "%s: disassociating by local choice (reason=%d)\n", |
2775 | sdata->dev->name, reason); | 1957 | sdata->dev->name, reason); |
@@ -2777,10 +1959,10 @@ int ieee80211_sta_disassociate(struct ieee80211_sub_if_data *sdata, u16 reason) | |||
2777 | if (sdata->vif.type != NL80211_IFTYPE_STATION) | 1959 | if (sdata->vif.type != NL80211_IFTYPE_STATION) |
2778 | return -EINVAL; | 1960 | return -EINVAL; |
2779 | 1961 | ||
2780 | if (!(ifsta->flags & IEEE80211_STA_ASSOCIATED)) | 1962 | if (!(ifmgd->flags & IEEE80211_STA_ASSOCIATED)) |
2781 | return -1; | 1963 | return -ENOLINK; |
2782 | 1964 | ||
2783 | ieee80211_set_disassoc(sdata, ifsta, false, true, reason); | 1965 | ieee80211_set_disassoc(sdata, false, true, reason); |
2784 | return 0; | 1966 | return 0; |
2785 | } | 1967 | } |
2786 | 1968 | ||
@@ -2788,14 +1970,6 @@ int ieee80211_sta_disassociate(struct ieee80211_sub_if_data *sdata, u16 reason) | |||
2788 | void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local) | 1970 | void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local) |
2789 | { | 1971 | { |
2790 | struct ieee80211_sub_if_data *sdata = local->scan_sdata; | 1972 | struct ieee80211_sub_if_data *sdata = local->scan_sdata; |
2791 | struct ieee80211_if_sta *ifsta; | ||
2792 | |||
2793 | if (sdata && sdata->vif.type == NL80211_IFTYPE_ADHOC) { | ||
2794 | ifsta = &sdata->u.sta; | ||
2795 | if ((!(ifsta->flags & IEEE80211_STA_PREV_BSSID_SET)) || | ||
2796 | !ieee80211_sta_active_ibss(sdata)) | ||
2797 | ieee80211_sta_find_ibss(sdata, ifsta); | ||
2798 | } | ||
2799 | 1973 | ||
2800 | /* Restart STA timers */ | 1974 | /* Restart STA timers */ |
2801 | rcu_read_lock(); | 1975 | rcu_read_lock(); |
@@ -2842,3 +2016,36 @@ void ieee80211_dynamic_ps_timer(unsigned long data) | |||
2842 | 2016 | ||
2843 | queue_work(local->hw.workqueue, &local->dynamic_ps_enable_work); | 2017 | queue_work(local->hw.workqueue, &local->dynamic_ps_enable_work); |
2844 | } | 2018 | } |
2019 | |||
2020 | void ieee80211_send_nullfunc(struct ieee80211_local *local, | ||
2021 | struct ieee80211_sub_if_data *sdata, | ||
2022 | int powersave) | ||
2023 | { | ||
2024 | struct sk_buff *skb; | ||
2025 | struct ieee80211_hdr *nullfunc; | ||
2026 | __le16 fc; | ||
2027 | |||
2028 | if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION)) | ||
2029 | return; | ||
2030 | |||
2031 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + 24); | ||
2032 | if (!skb) { | ||
2033 | printk(KERN_DEBUG "%s: failed to allocate buffer for nullfunc " | ||
2034 | "frame\n", sdata->dev->name); | ||
2035 | return; | ||
2036 | } | ||
2037 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
2038 | |||
2039 | nullfunc = (struct ieee80211_hdr *) skb_put(skb, 24); | ||
2040 | memset(nullfunc, 0, 24); | ||
2041 | fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC | | ||
2042 | IEEE80211_FCTL_TODS); | ||
2043 | if (powersave) | ||
2044 | fc |= cpu_to_le16(IEEE80211_FCTL_PM); | ||
2045 | nullfunc->frame_control = fc; | ||
2046 | memcpy(nullfunc->addr1, sdata->u.mgd.bssid, ETH_ALEN); | ||
2047 | memcpy(nullfunc->addr2, sdata->dev->dev_addr, ETH_ALEN); | ||
2048 | memcpy(nullfunc->addr3, sdata->u.mgd.bssid, ETH_ALEN); | ||
2049 | |||
2050 | ieee80211_tx_skb(sdata, skb, 0); | ||
2051 | } | ||
diff --git a/net/mac80211/rate.h b/net/mac80211/rate.h index 928da625e281..b9164c9a9563 100644 --- a/net/mac80211/rate.h +++ b/net/mac80211/rate.h | |||
@@ -62,6 +62,18 @@ static inline void rate_control_rate_init(struct sta_info *sta) | |||
62 | ref->ops->rate_init(ref->priv, sband, ista, priv_sta); | 62 | ref->ops->rate_init(ref->priv, sband, ista, priv_sta); |
63 | } | 63 | } |
64 | 64 | ||
65 | static inline void rate_control_rate_update(struct ieee80211_local *local, | ||
66 | struct ieee80211_supported_band *sband, | ||
67 | struct sta_info *sta, u32 changed) | ||
68 | { | ||
69 | struct rate_control_ref *ref = local->rate_ctrl; | ||
70 | struct ieee80211_sta *ista = &sta->sta; | ||
71 | void *priv_sta = sta->rate_ctrl_priv; | ||
72 | |||
73 | if (ref->ops->rate_update) | ||
74 | ref->ops->rate_update(ref->priv, sband, ista, | ||
75 | priv_sta, changed); | ||
76 | } | ||
65 | 77 | ||
66 | static inline void *rate_control_alloc_sta(struct rate_control_ref *ref, | 78 | static inline void *rate_control_alloc_sta(struct rate_control_ref *ref, |
67 | struct ieee80211_sta *sta, | 79 | struct ieee80211_sta *sta, |
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 1327d424bf31..66f7ecf51b92 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -838,7 +838,7 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx) | |||
838 | if (rx->sdata->vif.type == NL80211_IFTYPE_ADHOC) { | 838 | if (rx->sdata->vif.type == NL80211_IFTYPE_ADHOC) { |
839 | u8 *bssid = ieee80211_get_bssid(hdr, rx->skb->len, | 839 | u8 *bssid = ieee80211_get_bssid(hdr, rx->skb->len, |
840 | NL80211_IFTYPE_ADHOC); | 840 | NL80211_IFTYPE_ADHOC); |
841 | if (compare_ether_addr(bssid, rx->sdata->u.sta.bssid) == 0) | 841 | if (compare_ether_addr(bssid, rx->sdata->u.ibss.bssid) == 0) |
842 | sta->last_rx = jiffies; | 842 | sta->last_rx = jiffies; |
843 | } else | 843 | } else |
844 | if (!is_multicast_ether_addr(hdr->addr1) || | 844 | if (!is_multicast_ether_addr(hdr->addr1) || |
@@ -1702,13 +1702,13 @@ static void ieee80211_process_sa_query_req(struct ieee80211_sub_if_data *sdata, | |||
1702 | return; | 1702 | return; |
1703 | } | 1703 | } |
1704 | 1704 | ||
1705 | if (compare_ether_addr(mgmt->sa, sdata->u.sta.bssid) != 0 || | 1705 | if (compare_ether_addr(mgmt->sa, sdata->u.mgd.bssid) != 0 || |
1706 | compare_ether_addr(mgmt->bssid, sdata->u.sta.bssid) != 0) { | 1706 | compare_ether_addr(mgmt->bssid, sdata->u.mgd.bssid) != 0) { |
1707 | /* Not from the current AP. */ | 1707 | /* Not from the current AP. */ |
1708 | return; | 1708 | return; |
1709 | } | 1709 | } |
1710 | 1710 | ||
1711 | if (sdata->u.sta.state == IEEE80211_STA_MLME_ASSOCIATE) { | 1711 | if (sdata->u.mgd.state == IEEE80211_STA_MLME_ASSOCIATE) { |
1712 | /* Association in progress; ignore SA Query */ | 1712 | /* Association in progress; ignore SA Query */ |
1713 | return; | 1713 | return; |
1714 | } | 1714 | } |
@@ -1727,7 +1727,7 @@ static void ieee80211_process_sa_query_req(struct ieee80211_sub_if_data *sdata, | |||
1727 | memset(resp, 0, 24); | 1727 | memset(resp, 0, 24); |
1728 | memcpy(resp->da, mgmt->sa, ETH_ALEN); | 1728 | memcpy(resp->da, mgmt->sa, ETH_ALEN); |
1729 | memcpy(resp->sa, sdata->dev->dev_addr, ETH_ALEN); | 1729 | memcpy(resp->sa, sdata->dev->dev_addr, ETH_ALEN); |
1730 | memcpy(resp->bssid, sdata->u.sta.bssid, ETH_ALEN); | 1730 | memcpy(resp->bssid, sdata->u.mgd.bssid, ETH_ALEN); |
1731 | resp->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | 1731 | resp->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | |
1732 | IEEE80211_STYPE_ACTION); | 1732 | IEEE80211_STYPE_ACTION); |
1733 | skb_put(skb, 1 + sizeof(resp->u.action.u.sa_query)); | 1733 | skb_put(skb, 1 + sizeof(resp->u.action.u.sa_query)); |
@@ -1745,7 +1745,6 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) | |||
1745 | { | 1745 | { |
1746 | struct ieee80211_local *local = rx->local; | 1746 | struct ieee80211_local *local = rx->local; |
1747 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev); | 1747 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev); |
1748 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | ||
1749 | struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data; | 1748 | struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data; |
1750 | struct ieee80211_bss *bss; | 1749 | struct ieee80211_bss *bss; |
1751 | int len = rx->skb->len; | 1750 | int len = rx->skb->len; |
@@ -1803,6 +1802,10 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) | |||
1803 | case WLAN_CATEGORY_SPECTRUM_MGMT: | 1802 | case WLAN_CATEGORY_SPECTRUM_MGMT: |
1804 | if (local->hw.conf.channel->band != IEEE80211_BAND_5GHZ) | 1803 | if (local->hw.conf.channel->band != IEEE80211_BAND_5GHZ) |
1805 | return RX_DROP_MONITOR; | 1804 | return RX_DROP_MONITOR; |
1805 | |||
1806 | if (sdata->vif.type != NL80211_IFTYPE_STATION) | ||
1807 | return RX_DROP_MONITOR; | ||
1808 | |||
1806 | switch (mgmt->u.action.u.measurement.action_code) { | 1809 | switch (mgmt->u.action.u.measurement.action_code) { |
1807 | case WLAN_ACTION_SPCT_MSR_REQ: | 1810 | case WLAN_ACTION_SPCT_MSR_REQ: |
1808 | if (len < (IEEE80211_MIN_ACTION_SIZE + | 1811 | if (len < (IEEE80211_MIN_ACTION_SIZE + |
@@ -1815,12 +1818,13 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) | |||
1815 | sizeof(mgmt->u.action.u.chan_switch))) | 1818 | sizeof(mgmt->u.action.u.chan_switch))) |
1816 | return RX_DROP_MONITOR; | 1819 | return RX_DROP_MONITOR; |
1817 | 1820 | ||
1818 | if (memcmp(mgmt->bssid, ifsta->bssid, ETH_ALEN) != 0) | 1821 | if (memcmp(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN)) |
1819 | return RX_DROP_MONITOR; | 1822 | return RX_DROP_MONITOR; |
1820 | 1823 | ||
1821 | bss = ieee80211_rx_bss_get(local, ifsta->bssid, | 1824 | bss = ieee80211_rx_bss_get(local, sdata->u.mgd.bssid, |
1822 | local->hw.conf.channel->center_freq, | 1825 | local->hw.conf.channel->center_freq, |
1823 | ifsta->ssid, ifsta->ssid_len); | 1826 | sdata->u.mgd.ssid, |
1827 | sdata->u.mgd.ssid_len); | ||
1824 | if (!bss) | 1828 | if (!bss) |
1825 | return RX_DROP_MONITOR; | 1829 | return RX_DROP_MONITOR; |
1826 | 1830 | ||
@@ -1876,11 +1880,14 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx) | |||
1876 | sdata->vif.type != NL80211_IFTYPE_ADHOC) | 1880 | sdata->vif.type != NL80211_IFTYPE_ADHOC) |
1877 | return RX_DROP_MONITOR; | 1881 | return RX_DROP_MONITOR; |
1878 | 1882 | ||
1879 | if (sdata->flags & IEEE80211_SDATA_USERSPACE_MLME) | ||
1880 | return RX_DROP_MONITOR; | ||
1881 | 1883 | ||
1882 | ieee80211_sta_rx_mgmt(sdata, rx->skb, rx->status); | 1884 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { |
1883 | return RX_QUEUED; | 1885 | if (sdata->flags & IEEE80211_SDATA_USERSPACE_MLME) |
1886 | return RX_DROP_MONITOR; | ||
1887 | return ieee80211_sta_rx_mgmt(sdata, rx->skb, rx->status); | ||
1888 | } | ||
1889 | |||
1890 | return ieee80211_ibss_rx_mgmt(sdata, rx->skb, rx->status); | ||
1884 | } | 1891 | } |
1885 | 1892 | ||
1886 | static void ieee80211_rx_michael_mic_report(struct net_device *dev, | 1893 | static void ieee80211_rx_michael_mic_report(struct net_device *dev, |
@@ -2083,7 +2090,7 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata, | |||
2083 | case NL80211_IFTYPE_STATION: | 2090 | case NL80211_IFTYPE_STATION: |
2084 | if (!bssid) | 2091 | if (!bssid) |
2085 | return 0; | 2092 | return 0; |
2086 | if (!ieee80211_bssid_match(bssid, sdata->u.sta.bssid)) { | 2093 | if (!ieee80211_bssid_match(bssid, sdata->u.mgd.bssid)) { |
2087 | if (!(rx->flags & IEEE80211_RX_IN_SCAN)) | 2094 | if (!(rx->flags & IEEE80211_RX_IN_SCAN)) |
2088 | return 0; | 2095 | return 0; |
2089 | rx->flags &= ~IEEE80211_RX_RA_MATCH; | 2096 | rx->flags &= ~IEEE80211_RX_RA_MATCH; |
@@ -2101,7 +2108,7 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata, | |||
2101 | if (ieee80211_is_beacon(hdr->frame_control)) { | 2108 | if (ieee80211_is_beacon(hdr->frame_control)) { |
2102 | return 1; | 2109 | return 1; |
2103 | } | 2110 | } |
2104 | else if (!ieee80211_bssid_match(bssid, sdata->u.sta.bssid)) { | 2111 | else if (!ieee80211_bssid_match(bssid, sdata->u.ibss.bssid)) { |
2105 | if (!(rx->flags & IEEE80211_RX_IN_SCAN)) | 2112 | if (!(rx->flags & IEEE80211_RX_IN_SCAN)) |
2106 | return 0; | 2113 | return 0; |
2107 | rx->flags &= ~IEEE80211_RX_RA_MATCH; | 2114 | rx->flags &= ~IEEE80211_RX_RA_MATCH; |
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index f883ab9f1e6e..0e81e1633a66 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c | |||
@@ -63,20 +63,15 @@ ieee80211_bss_info_update(struct ieee80211_local *local, | |||
63 | { | 63 | { |
64 | struct ieee80211_bss *bss; | 64 | struct ieee80211_bss *bss; |
65 | int clen; | 65 | int clen; |
66 | enum cfg80211_signal_type sigtype = CFG80211_SIGNAL_TYPE_NONE; | ||
67 | s32 signal = 0; | 66 | s32 signal = 0; |
68 | 67 | ||
69 | if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) { | 68 | if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) |
70 | sigtype = CFG80211_SIGNAL_TYPE_MBM; | ||
71 | signal = rx_status->signal * 100; | 69 | signal = rx_status->signal * 100; |
72 | } else if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC) { | 70 | else if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC) |
73 | sigtype = CFG80211_SIGNAL_TYPE_UNSPEC; | ||
74 | signal = (rx_status->signal * 100) / local->hw.max_signal; | 71 | signal = (rx_status->signal * 100) / local->hw.max_signal; |
75 | } | ||
76 | 72 | ||
77 | bss = (void *)cfg80211_inform_bss_frame(local->hw.wiphy, channel, | 73 | bss = (void *)cfg80211_inform_bss_frame(local->hw.wiphy, channel, |
78 | mgmt, len, signal, sigtype, | 74 | mgmt, len, signal, GFP_ATOMIC); |
79 | GFP_ATOMIC); | ||
80 | 75 | ||
81 | if (!bss) | 76 | if (!bss) |
82 | return NULL; | 77 | return NULL; |
@@ -207,36 +202,6 @@ ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, | |||
207 | return RX_QUEUED; | 202 | return RX_QUEUED; |
208 | } | 203 | } |
209 | 204 | ||
210 | void ieee80211_send_nullfunc(struct ieee80211_local *local, | ||
211 | struct ieee80211_sub_if_data *sdata, | ||
212 | int powersave) | ||
213 | { | ||
214 | struct sk_buff *skb; | ||
215 | struct ieee80211_hdr *nullfunc; | ||
216 | __le16 fc; | ||
217 | |||
218 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + 24); | ||
219 | if (!skb) { | ||
220 | printk(KERN_DEBUG "%s: failed to allocate buffer for nullfunc " | ||
221 | "frame\n", sdata->dev->name); | ||
222 | return; | ||
223 | } | ||
224 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
225 | |||
226 | nullfunc = (struct ieee80211_hdr *) skb_put(skb, 24); | ||
227 | memset(nullfunc, 0, 24); | ||
228 | fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC | | ||
229 | IEEE80211_FCTL_TODS); | ||
230 | if (powersave) | ||
231 | fc |= cpu_to_le16(IEEE80211_FCTL_PM); | ||
232 | nullfunc->frame_control = fc; | ||
233 | memcpy(nullfunc->addr1, sdata->u.sta.bssid, ETH_ALEN); | ||
234 | memcpy(nullfunc->addr2, sdata->dev->dev_addr, ETH_ALEN); | ||
235 | memcpy(nullfunc->addr3, sdata->u.sta.bssid, ETH_ALEN); | ||
236 | |||
237 | ieee80211_tx_skb(sdata, skb, 0); | ||
238 | } | ||
239 | |||
240 | void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) | 205 | void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) |
241 | { | 206 | { |
242 | struct ieee80211_local *local = hw_to_local(hw); | 207 | struct ieee80211_local *local = hw_to_local(hw); |
@@ -280,6 +245,9 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) | |||
280 | netif_addr_unlock(local->mdev); | 245 | netif_addr_unlock(local->mdev); |
281 | netif_tx_unlock_bh(local->mdev); | 246 | netif_tx_unlock_bh(local->mdev); |
282 | 247 | ||
248 | if (local->ops->sw_scan_complete) | ||
249 | local->ops->sw_scan_complete(local_to_hw(local)); | ||
250 | |||
283 | mutex_lock(&local->iflist_mtx); | 251 | mutex_lock(&local->iflist_mtx); |
284 | list_for_each_entry(sdata, &local->interfaces, list) { | 252 | list_for_each_entry(sdata, &local->interfaces, list) { |
285 | if (!netif_running(sdata->dev)) | 253 | if (!netif_running(sdata->dev)) |
@@ -287,7 +255,7 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) | |||
287 | 255 | ||
288 | /* Tell AP we're back */ | 256 | /* Tell AP we're back */ |
289 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { | 257 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { |
290 | if (sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED) { | 258 | if (sdata->u.mgd.flags & IEEE80211_STA_ASSOCIATED) { |
291 | ieee80211_send_nullfunc(local, sdata, 0); | 259 | ieee80211_send_nullfunc(local, sdata, 0); |
292 | netif_tx_wake_all_queues(sdata->dev); | 260 | netif_tx_wake_all_queues(sdata->dev); |
293 | } | 261 | } |
@@ -305,6 +273,7 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) | |||
305 | 273 | ||
306 | done: | 274 | done: |
307 | ieee80211_mlme_notify_scan_completed(local); | 275 | ieee80211_mlme_notify_scan_completed(local); |
276 | ieee80211_ibss_notify_scan_completed(local); | ||
308 | ieee80211_mesh_notify_scan_completed(local); | 277 | ieee80211_mesh_notify_scan_completed(local); |
309 | } | 278 | } |
310 | EXPORT_SYMBOL(ieee80211_scan_completed); | 279 | EXPORT_SYMBOL(ieee80211_scan_completed); |
@@ -367,7 +336,8 @@ void ieee80211_scan_work(struct work_struct *work) | |||
367 | ieee80211_send_probe_req( | 336 | ieee80211_send_probe_req( |
368 | sdata, NULL, | 337 | sdata, NULL, |
369 | local->scan_req->ssids[i].ssid, | 338 | local->scan_req->ssids[i].ssid, |
370 | local->scan_req->ssids[i].ssid_len); | 339 | local->scan_req->ssids[i].ssid_len, |
340 | local->scan_req->ie, local->scan_req->ie_len); | ||
371 | next_delay = IEEE80211_CHANNEL_TIME; | 341 | next_delay = IEEE80211_CHANNEL_TIME; |
372 | break; | 342 | break; |
373 | } | 343 | } |
@@ -428,6 +398,8 @@ int ieee80211_start_scan(struct ieee80211_sub_if_data *scan_sdata, | |||
428 | } | 398 | } |
429 | 399 | ||
430 | local->sw_scanning = true; | 400 | local->sw_scanning = true; |
401 | if (local->ops->sw_scan_start) | ||
402 | local->ops->sw_scan_start(local_to_hw(local)); | ||
431 | 403 | ||
432 | mutex_lock(&local->iflist_mtx); | 404 | mutex_lock(&local->iflist_mtx); |
433 | list_for_each_entry(sdata, &local->interfaces, list) { | 405 | list_for_each_entry(sdata, &local->interfaces, list) { |
@@ -442,7 +414,7 @@ int ieee80211_start_scan(struct ieee80211_sub_if_data *scan_sdata, | |||
442 | IEEE80211_IFCC_BEACON_ENABLED); | 414 | IEEE80211_IFCC_BEACON_ENABLED); |
443 | 415 | ||
444 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { | 416 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { |
445 | if (sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED) { | 417 | if (sdata->u.mgd.flags & IEEE80211_STA_ASSOCIATED) { |
446 | netif_tx_stop_all_queues(sdata->dev); | 418 | netif_tx_stop_all_queues(sdata->dev); |
447 | ieee80211_send_nullfunc(local, sdata, 1); | 419 | ieee80211_send_nullfunc(local, sdata, 1); |
448 | } | 420 | } |
@@ -477,7 +449,7 @@ int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata, | |||
477 | struct cfg80211_scan_request *req) | 449 | struct cfg80211_scan_request *req) |
478 | { | 450 | { |
479 | struct ieee80211_local *local = sdata->local; | 451 | struct ieee80211_local *local = sdata->local; |
480 | struct ieee80211_if_sta *ifsta; | 452 | struct ieee80211_if_managed *ifmgd; |
481 | 453 | ||
482 | if (!req) | 454 | if (!req) |
483 | return -EINVAL; | 455 | return -EINVAL; |
@@ -502,9 +474,9 @@ int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata, | |||
502 | return -EBUSY; | 474 | return -EBUSY; |
503 | } | 475 | } |
504 | 476 | ||
505 | ifsta = &sdata->u.sta; | 477 | ifmgd = &sdata->u.mgd; |
506 | set_bit(IEEE80211_STA_REQ_SCAN, &ifsta->request); | 478 | set_bit(IEEE80211_STA_REQ_SCAN, &ifmgd->request); |
507 | queue_work(local->hw.workqueue, &ifsta->work); | 479 | queue_work(local->hw.workqueue, &ifmgd->work); |
508 | 480 | ||
509 | return 0; | 481 | return 0; |
510 | } | 482 | } |
diff --git a/net/mac80211/spectmgmt.c b/net/mac80211/spectmgmt.c index 47bb2aed2813..5f7a2624ed74 100644 --- a/net/mac80211/spectmgmt.c +++ b/net/mac80211/spectmgmt.c | |||
@@ -88,16 +88,16 @@ void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata, | |||
88 | void ieee80211_chswitch_work(struct work_struct *work) | 88 | void ieee80211_chswitch_work(struct work_struct *work) |
89 | { | 89 | { |
90 | struct ieee80211_sub_if_data *sdata = | 90 | struct ieee80211_sub_if_data *sdata = |
91 | container_of(work, struct ieee80211_sub_if_data, u.sta.chswitch_work); | 91 | container_of(work, struct ieee80211_sub_if_data, u.mgd.chswitch_work); |
92 | struct ieee80211_bss *bss; | 92 | struct ieee80211_bss *bss; |
93 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | 93 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
94 | 94 | ||
95 | if (!netif_running(sdata->dev)) | 95 | if (!netif_running(sdata->dev)) |
96 | return; | 96 | return; |
97 | 97 | ||
98 | bss = ieee80211_rx_bss_get(sdata->local, ifsta->bssid, | 98 | bss = ieee80211_rx_bss_get(sdata->local, ifmgd->bssid, |
99 | sdata->local->hw.conf.channel->center_freq, | 99 | sdata->local->hw.conf.channel->center_freq, |
100 | ifsta->ssid, ifsta->ssid_len); | 100 | ifmgd->ssid, ifmgd->ssid_len); |
101 | if (!bss) | 101 | if (!bss) |
102 | goto exit; | 102 | goto exit; |
103 | 103 | ||
@@ -108,7 +108,7 @@ void ieee80211_chswitch_work(struct work_struct *work) | |||
108 | 108 | ||
109 | ieee80211_rx_bss_put(sdata->local, bss); | 109 | ieee80211_rx_bss_put(sdata->local, bss); |
110 | exit: | 110 | exit: |
111 | ifsta->flags &= ~IEEE80211_STA_CSA_RECEIVED; | 111 | ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED; |
112 | ieee80211_wake_queues_by_reason(&sdata->local->hw, | 112 | ieee80211_wake_queues_by_reason(&sdata->local->hw, |
113 | IEEE80211_QUEUE_STOP_REASON_CSA); | 113 | IEEE80211_QUEUE_STOP_REASON_CSA); |
114 | } | 114 | } |
@@ -117,9 +117,9 @@ void ieee80211_chswitch_timer(unsigned long data) | |||
117 | { | 117 | { |
118 | struct ieee80211_sub_if_data *sdata = | 118 | struct ieee80211_sub_if_data *sdata = |
119 | (struct ieee80211_sub_if_data *) data; | 119 | (struct ieee80211_sub_if_data *) data; |
120 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | 120 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
121 | 121 | ||
122 | queue_work(sdata->local->hw.workqueue, &ifsta->chswitch_work); | 122 | queue_work(sdata->local->hw.workqueue, &ifmgd->chswitch_work); |
123 | } | 123 | } |
124 | 124 | ||
125 | void ieee80211_process_chanswitch(struct ieee80211_sub_if_data *sdata, | 125 | void ieee80211_process_chanswitch(struct ieee80211_sub_if_data *sdata, |
@@ -127,14 +127,14 @@ void ieee80211_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
127 | struct ieee80211_bss *bss) | 127 | struct ieee80211_bss *bss) |
128 | { | 128 | { |
129 | struct ieee80211_channel *new_ch; | 129 | struct ieee80211_channel *new_ch; |
130 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | 130 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
131 | int new_freq = ieee80211_channel_to_frequency(sw_elem->new_ch_num); | 131 | int new_freq = ieee80211_channel_to_frequency(sw_elem->new_ch_num); |
132 | 132 | ||
133 | /* FIXME: Handle ADHOC later */ | 133 | /* FIXME: Handle ADHOC later */ |
134 | if (sdata->vif.type != NL80211_IFTYPE_STATION) | 134 | if (sdata->vif.type != NL80211_IFTYPE_STATION) |
135 | return; | 135 | return; |
136 | 136 | ||
137 | if (ifsta->state != IEEE80211_STA_MLME_ASSOCIATED) | 137 | if (ifmgd->state != IEEE80211_STA_MLME_ASSOCIATED) |
138 | return; | 138 | return; |
139 | 139 | ||
140 | if (sdata->local->sw_scanning || sdata->local->hw_scanning) | 140 | if (sdata->local->sw_scanning || sdata->local->hw_scanning) |
@@ -143,7 +143,7 @@ void ieee80211_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
143 | /* Disregard subsequent beacons if we are already running a timer | 143 | /* Disregard subsequent beacons if we are already running a timer |
144 | processing a CSA */ | 144 | processing a CSA */ |
145 | 145 | ||
146 | if (ifsta->flags & IEEE80211_STA_CSA_RECEIVED) | 146 | if (ifmgd->flags & IEEE80211_STA_CSA_RECEIVED) |
147 | return; | 147 | return; |
148 | 148 | ||
149 | new_ch = ieee80211_get_channel(sdata->local->hw.wiphy, new_freq); | 149 | new_ch = ieee80211_get_channel(sdata->local->hw.wiphy, new_freq); |
@@ -153,12 +153,12 @@ void ieee80211_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
153 | sdata->local->csa_channel = new_ch; | 153 | sdata->local->csa_channel = new_ch; |
154 | 154 | ||
155 | if (sw_elem->count <= 1) { | 155 | if (sw_elem->count <= 1) { |
156 | queue_work(sdata->local->hw.workqueue, &ifsta->chswitch_work); | 156 | queue_work(sdata->local->hw.workqueue, &ifmgd->chswitch_work); |
157 | } else { | 157 | } else { |
158 | ieee80211_stop_queues_by_reason(&sdata->local->hw, | 158 | ieee80211_stop_queues_by_reason(&sdata->local->hw, |
159 | IEEE80211_QUEUE_STOP_REASON_CSA); | 159 | IEEE80211_QUEUE_STOP_REASON_CSA); |
160 | ifsta->flags |= IEEE80211_STA_CSA_RECEIVED; | 160 | ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED; |
161 | mod_timer(&ifsta->chswitch_timer, | 161 | mod_timer(&ifmgd->chswitch_timer, |
162 | jiffies + | 162 | jiffies + |
163 | msecs_to_jiffies(sw_elem->count * | 163 | msecs_to_jiffies(sw_elem->count * |
164 | bss->cbss.beacon_interval)); | 164 | bss->cbss.beacon_interval)); |
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 634f65c0130e..4ba3c540fcf3 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
@@ -202,6 +202,18 @@ void sta_info_destroy(struct sta_info *sta) | |||
202 | /* Make sure timer won't free the tid_rx struct, see below */ | 202 | /* Make sure timer won't free the tid_rx struct, see below */ |
203 | if (tid_rx) | 203 | if (tid_rx) |
204 | tid_rx->shutdown = true; | 204 | tid_rx->shutdown = true; |
205 | |||
206 | /* | ||
207 | * The stop callback cannot find this station any more, but | ||
208 | * it didn't complete its work -- start the queue if necessary | ||
209 | */ | ||
210 | if (sta->ampdu_mlme.tid_state_tx[i] & HT_AGG_STATE_INITIATOR_MSK && | ||
211 | sta->ampdu_mlme.tid_state_tx[i] & HT_AGG_STATE_REQ_STOP_BA_MSK && | ||
212 | local->hw.ampdu_queues) | ||
213 | ieee80211_wake_queue_by_reason(&local->hw, | ||
214 | local->hw.queues + sta->tid_to_tx_q[i], | ||
215 | IEEE80211_QUEUE_STOP_REASON_AGGREGATION); | ||
216 | |||
205 | spin_unlock_bh(&sta->lock); | 217 | spin_unlock_bh(&sta->lock); |
206 | 218 | ||
207 | /* | 219 | /* |
@@ -275,8 +287,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, | |||
275 | * enable session_timer's data differentiation. refer to | 287 | * enable session_timer's data differentiation. refer to |
276 | * sta_rx_agg_session_timer_expired for useage */ | 288 | * sta_rx_agg_session_timer_expired for useage */ |
277 | sta->timer_to_tid[i] = i; | 289 | sta->timer_to_tid[i] = i; |
278 | /* tid to tx queue: initialize according to HW (0 is valid) */ | 290 | sta->tid_to_tx_q[i] = -1; |
279 | sta->tid_to_tx_q[i] = ieee80211_num_queues(&local->hw); | ||
280 | /* rx */ | 291 | /* rx */ |
281 | sta->ampdu_mlme.tid_state_rx[i] = HT_AGG_STATE_IDLE; | 292 | sta->ampdu_mlme.tid_state_rx[i] = HT_AGG_STATE_IDLE; |
282 | sta->ampdu_mlme.tid_rx[i] = NULL; | 293 | sta->ampdu_mlme.tid_rx[i] = NULL; |
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index d9653231992f..1f45573c580c 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h | |||
@@ -90,6 +90,7 @@ struct tid_ampdu_tx { | |||
90 | * @buf_size: buffer size for incoming A-MPDUs | 90 | * @buf_size: buffer size for incoming A-MPDUs |
91 | * @timeout: reset timer value (in TUs). | 91 | * @timeout: reset timer value (in TUs). |
92 | * @dialog_token: dialog token for aggregation session | 92 | * @dialog_token: dialog token for aggregation session |
93 | * @shutdown: this session is being shut down due to STA removal | ||
93 | */ | 94 | */ |
94 | struct tid_ampdu_rx { | 95 | struct tid_ampdu_rx { |
95 | struct sk_buff **reorder_buf; | 96 | struct sk_buff **reorder_buf; |
@@ -200,7 +201,7 @@ struct sta_ampdu_mlme { | |||
200 | * @tid_seq: per-TID sequence numbers for sending to this STA | 201 | * @tid_seq: per-TID sequence numbers for sending to this STA |
201 | * @ampdu_mlme: A-MPDU state machine state | 202 | * @ampdu_mlme: A-MPDU state machine state |
202 | * @timer_to_tid: identity mapping to ID timers | 203 | * @timer_to_tid: identity mapping to ID timers |
203 | * @tid_to_tx_q: map tid to tx queue | 204 | * @tid_to_tx_q: map tid to tx queue (invalid == negative values) |
204 | * @llid: Local link ID | 205 | * @llid: Local link ID |
205 | * @plid: Peer link ID | 206 | * @plid: Peer link ID |
206 | * @reason: Cancel reason on PLINK_HOLDING state | 207 | * @reason: Cancel reason on PLINK_HOLDING state |
@@ -275,7 +276,7 @@ struct sta_info { | |||
275 | */ | 276 | */ |
276 | struct sta_ampdu_mlme ampdu_mlme; | 277 | struct sta_ampdu_mlme ampdu_mlme; |
277 | u8 timer_to_tid[STA_TID_NUM]; | 278 | u8 timer_to_tid[STA_TID_NUM]; |
278 | u8 tid_to_tx_q[STA_TID_NUM]; | 279 | s8 tid_to_tx_q[STA_TID_NUM]; |
279 | 280 | ||
280 | #ifdef CONFIG_MAC80211_MESH | 281 | #ifdef CONFIG_MAC80211_MESH |
281 | /* | 282 | /* |
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 33926831c648..c3f0e950125b 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -876,7 +876,6 @@ ieee80211_tx_h_stats(struct ieee80211_tx_data *tx) | |||
876 | return TX_CONTINUE; | 876 | return TX_CONTINUE; |
877 | } | 877 | } |
878 | 878 | ||
879 | |||
880 | /* actual transmit path */ | 879 | /* actual transmit path */ |
881 | 880 | ||
882 | /* | 881 | /* |
@@ -1016,12 +1015,20 @@ __ieee80211_tx_prepare(struct ieee80211_tx_data *tx, | |||
1016 | tx->sta = sta_info_get(local, hdr->addr1); | 1015 | tx->sta = sta_info_get(local, hdr->addr1); |
1017 | 1016 | ||
1018 | if (tx->sta && ieee80211_is_data_qos(hdr->frame_control)) { | 1017 | if (tx->sta && ieee80211_is_data_qos(hdr->frame_control)) { |
1018 | unsigned long flags; | ||
1019 | qc = ieee80211_get_qos_ctl(hdr); | 1019 | qc = ieee80211_get_qos_ctl(hdr); |
1020 | tid = *qc & IEEE80211_QOS_CTL_TID_MASK; | 1020 | tid = *qc & IEEE80211_QOS_CTL_TID_MASK; |
1021 | 1021 | ||
1022 | spin_lock_irqsave(&tx->sta->lock, flags); | ||
1022 | state = &tx->sta->ampdu_mlme.tid_state_tx[tid]; | 1023 | state = &tx->sta->ampdu_mlme.tid_state_tx[tid]; |
1023 | if (*state == HT_AGG_STATE_OPERATIONAL) | 1024 | if (*state == HT_AGG_STATE_OPERATIONAL) { |
1024 | info->flags |= IEEE80211_TX_CTL_AMPDU; | 1025 | info->flags |= IEEE80211_TX_CTL_AMPDU; |
1026 | if (local->hw.ampdu_queues) | ||
1027 | skb_set_queue_mapping( | ||
1028 | skb, tx->local->hw.queues + | ||
1029 | tx->sta->tid_to_tx_q[tid]); | ||
1030 | } | ||
1031 | spin_unlock_irqrestore(&tx->sta->lock, flags); | ||
1025 | } | 1032 | } |
1026 | 1033 | ||
1027 | if (is_multicast_ether_addr(hdr->addr1)) { | 1034 | if (is_multicast_ether_addr(hdr->addr1)) { |
@@ -1085,7 +1092,8 @@ static int __ieee80211_tx(struct ieee80211_local *local, struct sk_buff *skb, | |||
1085 | int ret, i; | 1092 | int ret, i; |
1086 | 1093 | ||
1087 | if (skb) { | 1094 | if (skb) { |
1088 | if (netif_subqueue_stopped(local->mdev, skb)) | 1095 | if (ieee80211_queue_stopped(&local->hw, |
1096 | skb_get_queue_mapping(skb))) | ||
1089 | return IEEE80211_TX_PENDING; | 1097 | return IEEE80211_TX_PENDING; |
1090 | 1098 | ||
1091 | ret = local->ops->tx(local_to_hw(local), skb); | 1099 | ret = local->ops->tx(local_to_hw(local), skb); |
@@ -1101,8 +1109,8 @@ static int __ieee80211_tx(struct ieee80211_local *local, struct sk_buff *skb, | |||
1101 | info = IEEE80211_SKB_CB(tx->extra_frag[i]); | 1109 | info = IEEE80211_SKB_CB(tx->extra_frag[i]); |
1102 | info->flags &= ~(IEEE80211_TX_CTL_CLEAR_PS_FILT | | 1110 | info->flags &= ~(IEEE80211_TX_CTL_CLEAR_PS_FILT | |
1103 | IEEE80211_TX_CTL_FIRST_FRAGMENT); | 1111 | IEEE80211_TX_CTL_FIRST_FRAGMENT); |
1104 | if (netif_subqueue_stopped(local->mdev, | 1112 | if (ieee80211_queue_stopped(&local->hw, |
1105 | tx->extra_frag[i])) | 1113 | skb_get_queue_mapping(tx->extra_frag[i]))) |
1106 | return IEEE80211_TX_FRAG_AGAIN; | 1114 | return IEEE80211_TX_FRAG_AGAIN; |
1107 | 1115 | ||
1108 | ret = local->ops->tx(local_to_hw(local), | 1116 | ret = local->ops->tx(local_to_hw(local), |
@@ -1625,7 +1633,7 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1625 | case NL80211_IFTYPE_STATION: | 1633 | case NL80211_IFTYPE_STATION: |
1626 | fc |= cpu_to_le16(IEEE80211_FCTL_TODS); | 1634 | fc |= cpu_to_le16(IEEE80211_FCTL_TODS); |
1627 | /* BSSID SA DA */ | 1635 | /* BSSID SA DA */ |
1628 | memcpy(hdr.addr1, sdata->u.sta.bssid, ETH_ALEN); | 1636 | memcpy(hdr.addr1, sdata->u.mgd.bssid, ETH_ALEN); |
1629 | memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN); | 1637 | memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN); |
1630 | memcpy(hdr.addr3, skb->data, ETH_ALEN); | 1638 | memcpy(hdr.addr3, skb->data, ETH_ALEN); |
1631 | hdrlen = 24; | 1639 | hdrlen = 24; |
@@ -1634,7 +1642,7 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1634 | /* DA SA BSSID */ | 1642 | /* DA SA BSSID */ |
1635 | memcpy(hdr.addr1, skb->data, ETH_ALEN); | 1643 | memcpy(hdr.addr1, skb->data, ETH_ALEN); |
1636 | memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN); | 1644 | memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN); |
1637 | memcpy(hdr.addr3, sdata->u.sta.bssid, ETH_ALEN); | 1645 | memcpy(hdr.addr3, sdata->u.ibss.bssid, ETH_ALEN); |
1638 | hdrlen = 24; | 1646 | hdrlen = 24; |
1639 | break; | 1647 | break; |
1640 | default: | 1648 | default: |
@@ -1920,7 +1928,6 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, | |||
1920 | struct ieee80211_tx_info *info; | 1928 | struct ieee80211_tx_info *info; |
1921 | struct ieee80211_sub_if_data *sdata = NULL; | 1929 | struct ieee80211_sub_if_data *sdata = NULL; |
1922 | struct ieee80211_if_ap *ap = NULL; | 1930 | struct ieee80211_if_ap *ap = NULL; |
1923 | struct ieee80211_if_sta *ifsta = NULL; | ||
1924 | struct beacon_data *beacon; | 1931 | struct beacon_data *beacon; |
1925 | struct ieee80211_supported_band *sband; | 1932 | struct ieee80211_supported_band *sband; |
1926 | enum ieee80211_band band = local->hw.conf.channel->band; | 1933 | enum ieee80211_band band = local->hw.conf.channel->band; |
@@ -1972,13 +1979,13 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, | |||
1972 | } else | 1979 | } else |
1973 | goto out; | 1980 | goto out; |
1974 | } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { | 1981 | } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { |
1982 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | ||
1975 | struct ieee80211_hdr *hdr; | 1983 | struct ieee80211_hdr *hdr; |
1976 | ifsta = &sdata->u.sta; | ||
1977 | 1984 | ||
1978 | if (!ifsta->probe_resp) | 1985 | if (!ifibss->probe_resp) |
1979 | goto out; | 1986 | goto out; |
1980 | 1987 | ||
1981 | skb = skb_copy(ifsta->probe_resp, GFP_ATOMIC); | 1988 | skb = skb_copy(ifibss->probe_resp, GFP_ATOMIC); |
1982 | if (!skb) | 1989 | if (!skb) |
1983 | goto out; | 1990 | goto out; |
1984 | 1991 | ||
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 73c7d7345abd..e0431a1d218b 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -344,15 +344,36 @@ static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue, | |||
344 | { | 344 | { |
345 | struct ieee80211_local *local = hw_to_local(hw); | 345 | struct ieee80211_local *local = hw_to_local(hw); |
346 | 346 | ||
347 | /* we don't need to track ampdu queues */ | 347 | if (queue >= hw->queues) { |
348 | if (queue < ieee80211_num_regular_queues(hw)) { | 348 | if (local->ampdu_ac_queue[queue - hw->queues] < 0) |
349 | __clear_bit(reason, &local->queue_stop_reasons[queue]); | 349 | return; |
350 | |||
351 | /* | ||
352 | * for virtual aggregation queues, we need to refcount the | ||
353 | * internal mac80211 disable (multiple times!), keep track of | ||
354 | * driver disable _and_ make sure the regular queue is | ||
355 | * actually enabled. | ||
356 | */ | ||
357 | if (reason == IEEE80211_QUEUE_STOP_REASON_AGGREGATION) | ||
358 | local->amdpu_ac_stop_refcnt[queue - hw->queues]--; | ||
359 | else | ||
360 | __clear_bit(reason, &local->queue_stop_reasons[queue]); | ||
350 | 361 | ||
351 | if (local->queue_stop_reasons[queue] != 0) | 362 | if (local->queue_stop_reasons[queue] || |
352 | /* someone still has this queue stopped */ | 363 | local->amdpu_ac_stop_refcnt[queue - hw->queues]) |
353 | return; | 364 | return; |
365 | |||
366 | /* now go on to treat the corresponding regular queue */ | ||
367 | queue = local->ampdu_ac_queue[queue - hw->queues]; | ||
368 | reason = IEEE80211_QUEUE_STOP_REASON_AGGREGATION; | ||
354 | } | 369 | } |
355 | 370 | ||
371 | __clear_bit(reason, &local->queue_stop_reasons[queue]); | ||
372 | |||
373 | if (local->queue_stop_reasons[queue] != 0) | ||
374 | /* someone still has this queue stopped */ | ||
375 | return; | ||
376 | |||
356 | if (test_bit(queue, local->queues_pending)) { | 377 | if (test_bit(queue, local->queues_pending)) { |
357 | set_bit(queue, local->queues_pending_run); | 378 | set_bit(queue, local->queues_pending_run); |
358 | tasklet_schedule(&local->tx_pending_tasklet); | 379 | tasklet_schedule(&local->tx_pending_tasklet); |
@@ -361,8 +382,8 @@ static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue, | |||
361 | } | 382 | } |
362 | } | 383 | } |
363 | 384 | ||
364 | static void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue, | 385 | void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue, |
365 | enum queue_stop_reason reason) | 386 | enum queue_stop_reason reason) |
366 | { | 387 | { |
367 | struct ieee80211_local *local = hw_to_local(hw); | 388 | struct ieee80211_local *local = hw_to_local(hw); |
368 | unsigned long flags; | 389 | unsigned long flags; |
@@ -384,15 +405,33 @@ static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue, | |||
384 | { | 405 | { |
385 | struct ieee80211_local *local = hw_to_local(hw); | 406 | struct ieee80211_local *local = hw_to_local(hw); |
386 | 407 | ||
387 | /* we don't need to track ampdu queues */ | 408 | if (queue >= hw->queues) { |
388 | if (queue < ieee80211_num_regular_queues(hw)) | 409 | if (local->ampdu_ac_queue[queue - hw->queues] < 0) |
389 | __set_bit(reason, &local->queue_stop_reasons[queue]); | 410 | return; |
411 | |||
412 | /* | ||
413 | * for virtual aggregation queues, we need to refcount the | ||
414 | * internal mac80211 disable (multiple times!), keep track of | ||
415 | * driver disable _and_ make sure the regular queue is | ||
416 | * actually enabled. | ||
417 | */ | ||
418 | if (reason == IEEE80211_QUEUE_STOP_REASON_AGGREGATION) | ||
419 | local->amdpu_ac_stop_refcnt[queue - hw->queues]++; | ||
420 | else | ||
421 | __set_bit(reason, &local->queue_stop_reasons[queue]); | ||
422 | |||
423 | /* now go on to treat the corresponding regular queue */ | ||
424 | queue = local->ampdu_ac_queue[queue - hw->queues]; | ||
425 | reason = IEEE80211_QUEUE_STOP_REASON_AGGREGATION; | ||
426 | } | ||
427 | |||
428 | __set_bit(reason, &local->queue_stop_reasons[queue]); | ||
390 | 429 | ||
391 | netif_stop_subqueue(local->mdev, queue); | 430 | netif_stop_subqueue(local->mdev, queue); |
392 | } | 431 | } |
393 | 432 | ||
394 | static void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue, | 433 | void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue, |
395 | enum queue_stop_reason reason) | 434 | enum queue_stop_reason reason) |
396 | { | 435 | { |
397 | struct ieee80211_local *local = hw_to_local(hw); | 436 | struct ieee80211_local *local = hw_to_local(hw); |
398 | unsigned long flags; | 437 | unsigned long flags; |
@@ -418,7 +457,7 @@ void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw, | |||
418 | 457 | ||
419 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); | 458 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); |
420 | 459 | ||
421 | for (i = 0; i < ieee80211_num_queues(hw); i++) | 460 | for (i = 0; i < hw->queues; i++) |
422 | __ieee80211_stop_queue(hw, i, reason); | 461 | __ieee80211_stop_queue(hw, i, reason); |
423 | 462 | ||
424 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); | 463 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); |
@@ -434,6 +473,16 @@ EXPORT_SYMBOL(ieee80211_stop_queues); | |||
434 | int ieee80211_queue_stopped(struct ieee80211_hw *hw, int queue) | 473 | int ieee80211_queue_stopped(struct ieee80211_hw *hw, int queue) |
435 | { | 474 | { |
436 | struct ieee80211_local *local = hw_to_local(hw); | 475 | struct ieee80211_local *local = hw_to_local(hw); |
476 | unsigned long flags; | ||
477 | |||
478 | if (queue >= hw->queues) { | ||
479 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); | ||
480 | queue = local->ampdu_ac_queue[queue - hw->queues]; | ||
481 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); | ||
482 | if (queue < 0) | ||
483 | return true; | ||
484 | } | ||
485 | |||
437 | return __netif_subqueue_stopped(local->mdev, queue); | 486 | return __netif_subqueue_stopped(local->mdev, queue); |
438 | } | 487 | } |
439 | EXPORT_SYMBOL(ieee80211_queue_stopped); | 488 | EXPORT_SYMBOL(ieee80211_queue_stopped); |
@@ -701,6 +750,27 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata) | |||
701 | local->ops->conf_tx(local_to_hw(local), i, &qparam); | 750 | local->ops->conf_tx(local_to_hw(local), i, &qparam); |
702 | } | 751 | } |
703 | 752 | ||
753 | void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata, | ||
754 | const size_t supp_rates_len, | ||
755 | const u8 *supp_rates) | ||
756 | { | ||
757 | struct ieee80211_local *local = sdata->local; | ||
758 | int i, have_higher_than_11mbit = 0; | ||
759 | |||
760 | /* cf. IEEE 802.11 9.2.12 */ | ||
761 | for (i = 0; i < supp_rates_len; i++) | ||
762 | if ((supp_rates[i] & 0x7f) * 5 > 110) | ||
763 | have_higher_than_11mbit = 1; | ||
764 | |||
765 | if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ && | ||
766 | have_higher_than_11mbit) | ||
767 | sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE; | ||
768 | else | ||
769 | sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE; | ||
770 | |||
771 | ieee80211_set_wmm_default(sdata); | ||
772 | } | ||
773 | |||
704 | void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, | 774 | void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, |
705 | int encrypt) | 775 | int encrypt) |
706 | { | 776 | { |
@@ -767,3 +837,161 @@ u32 ieee80211_mandatory_rates(struct ieee80211_local *local, | |||
767 | mandatory_rates |= BIT(i); | 837 | mandatory_rates |= BIT(i); |
768 | return mandatory_rates; | 838 | return mandatory_rates; |
769 | } | 839 | } |
840 | |||
841 | void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, | ||
842 | u16 transaction, u16 auth_alg, | ||
843 | u8 *extra, size_t extra_len, | ||
844 | const u8 *bssid, int encrypt) | ||
845 | { | ||
846 | struct ieee80211_local *local = sdata->local; | ||
847 | struct sk_buff *skb; | ||
848 | struct ieee80211_mgmt *mgmt; | ||
849 | const u8 *ie_auth = NULL; | ||
850 | int ie_auth_len = 0; | ||
851 | |||
852 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { | ||
853 | ie_auth_len = sdata->u.mgd.ie_auth_len; | ||
854 | ie_auth = sdata->u.mgd.ie_auth; | ||
855 | } | ||
856 | |||
857 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + | ||
858 | sizeof(*mgmt) + 6 + extra_len + ie_auth_len); | ||
859 | if (!skb) { | ||
860 | printk(KERN_DEBUG "%s: failed to allocate buffer for auth " | ||
861 | "frame\n", sdata->dev->name); | ||
862 | return; | ||
863 | } | ||
864 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
865 | |||
866 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24 + 6); | ||
867 | memset(mgmt, 0, 24 + 6); | ||
868 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
869 | IEEE80211_STYPE_AUTH); | ||
870 | if (encrypt) | ||
871 | mgmt->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); | ||
872 | memcpy(mgmt->da, bssid, ETH_ALEN); | ||
873 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | ||
874 | memcpy(mgmt->bssid, bssid, ETH_ALEN); | ||
875 | mgmt->u.auth.auth_alg = cpu_to_le16(auth_alg); | ||
876 | mgmt->u.auth.auth_transaction = cpu_to_le16(transaction); | ||
877 | mgmt->u.auth.status_code = cpu_to_le16(0); | ||
878 | if (extra) | ||
879 | memcpy(skb_put(skb, extra_len), extra, extra_len); | ||
880 | if (ie_auth) | ||
881 | memcpy(skb_put(skb, ie_auth_len), ie_auth, ie_auth_len); | ||
882 | |||
883 | ieee80211_tx_skb(sdata, skb, encrypt); | ||
884 | } | ||
885 | |||
886 | void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, | ||
887 | u8 *ssid, size_t ssid_len, | ||
888 | u8 *ie, size_t ie_len) | ||
889 | { | ||
890 | struct ieee80211_local *local = sdata->local; | ||
891 | struct ieee80211_supported_band *sband; | ||
892 | struct sk_buff *skb; | ||
893 | struct ieee80211_mgmt *mgmt; | ||
894 | u8 *pos, *supp_rates, *esupp_rates = NULL, *extra_preq_ie = NULL; | ||
895 | int i, extra_preq_ie_len = 0; | ||
896 | |||
897 | switch (sdata->vif.type) { | ||
898 | case NL80211_IFTYPE_STATION: | ||
899 | extra_preq_ie_len = sdata->u.mgd.ie_probereq_len; | ||
900 | extra_preq_ie = sdata->u.mgd.ie_probereq; | ||
901 | break; | ||
902 | default: | ||
903 | break; | ||
904 | } | ||
905 | |||
906 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt) + 200 + | ||
907 | ie_len + extra_preq_ie_len); | ||
908 | if (!skb) { | ||
909 | printk(KERN_DEBUG "%s: failed to allocate buffer for probe " | ||
910 | "request\n", sdata->dev->name); | ||
911 | return; | ||
912 | } | ||
913 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
914 | |||
915 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); | ||
916 | memset(mgmt, 0, 24); | ||
917 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
918 | IEEE80211_STYPE_PROBE_REQ); | ||
919 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | ||
920 | if (dst) { | ||
921 | memcpy(mgmt->da, dst, ETH_ALEN); | ||
922 | memcpy(mgmt->bssid, dst, ETH_ALEN); | ||
923 | } else { | ||
924 | memset(mgmt->da, 0xff, ETH_ALEN); | ||
925 | memset(mgmt->bssid, 0xff, ETH_ALEN); | ||
926 | } | ||
927 | pos = skb_put(skb, 2 + ssid_len); | ||
928 | *pos++ = WLAN_EID_SSID; | ||
929 | *pos++ = ssid_len; | ||
930 | memcpy(pos, ssid, ssid_len); | ||
931 | |||
932 | supp_rates = skb_put(skb, 2); | ||
933 | supp_rates[0] = WLAN_EID_SUPP_RATES; | ||
934 | supp_rates[1] = 0; | ||
935 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | ||
936 | |||
937 | for (i = 0; i < sband->n_bitrates; i++) { | ||
938 | struct ieee80211_rate *rate = &sband->bitrates[i]; | ||
939 | if (esupp_rates) { | ||
940 | pos = skb_put(skb, 1); | ||
941 | esupp_rates[1]++; | ||
942 | } else if (supp_rates[1] == 8) { | ||
943 | esupp_rates = skb_put(skb, 3); | ||
944 | esupp_rates[0] = WLAN_EID_EXT_SUPP_RATES; | ||
945 | esupp_rates[1] = 1; | ||
946 | pos = &esupp_rates[2]; | ||
947 | } else { | ||
948 | pos = skb_put(skb, 1); | ||
949 | supp_rates[1]++; | ||
950 | } | ||
951 | *pos = rate->bitrate / 5; | ||
952 | } | ||
953 | |||
954 | if (ie) | ||
955 | memcpy(skb_put(skb, ie_len), ie, ie_len); | ||
956 | if (extra_preq_ie) | ||
957 | memcpy(skb_put(skb, extra_preq_ie_len), extra_preq_ie, | ||
958 | extra_preq_ie_len); | ||
959 | |||
960 | ieee80211_tx_skb(sdata, skb, 0); | ||
961 | } | ||
962 | |||
963 | u32 ieee80211_sta_get_rates(struct ieee80211_local *local, | ||
964 | struct ieee802_11_elems *elems, | ||
965 | enum ieee80211_band band) | ||
966 | { | ||
967 | struct ieee80211_supported_band *sband; | ||
968 | struct ieee80211_rate *bitrates; | ||
969 | size_t num_rates; | ||
970 | u32 supp_rates; | ||
971 | int i, j; | ||
972 | sband = local->hw.wiphy->bands[band]; | ||
973 | |||
974 | if (!sband) { | ||
975 | WARN_ON(1); | ||
976 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | ||
977 | } | ||
978 | |||
979 | bitrates = sband->bitrates; | ||
980 | num_rates = sband->n_bitrates; | ||
981 | supp_rates = 0; | ||
982 | for (i = 0; i < elems->supp_rates_len + | ||
983 | elems->ext_supp_rates_len; i++) { | ||
984 | u8 rate = 0; | ||
985 | int own_rate; | ||
986 | if (i < elems->supp_rates_len) | ||
987 | rate = elems->supp_rates[i]; | ||
988 | else if (elems->ext_supp_rates) | ||
989 | rate = elems->ext_supp_rates | ||
990 | [i - elems->supp_rates_len]; | ||
991 | own_rate = 5 * (rate & 0x7f); | ||
992 | for (j = 0; j < num_rates; j++) | ||
993 | if (bitrates[j].bitrate == own_rate) | ||
994 | supp_rates |= BIT(j); | ||
995 | } | ||
996 | return supp_rates; | ||
997 | } | ||
diff --git a/net/mac80211/wext.c b/net/mac80211/wext.c index 2b023dce8b24..f6924fc065d3 100644 --- a/net/mac80211/wext.c +++ b/net/mac80211/wext.c | |||
@@ -132,139 +132,37 @@ static int ieee80211_ioctl_siwgenie(struct net_device *dev, | |||
132 | if (sdata->flags & IEEE80211_SDATA_USERSPACE_MLME) | 132 | if (sdata->flags & IEEE80211_SDATA_USERSPACE_MLME) |
133 | return -EOPNOTSUPP; | 133 | return -EOPNOTSUPP; |
134 | 134 | ||
135 | if (sdata->vif.type == NL80211_IFTYPE_STATION || | 135 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { |
136 | sdata->vif.type == NL80211_IFTYPE_ADHOC) { | ||
137 | int ret = ieee80211_sta_set_extra_ie(sdata, extra, data->length); | 136 | int ret = ieee80211_sta_set_extra_ie(sdata, extra, data->length); |
138 | if (ret) | 137 | if (ret) |
139 | return ret; | 138 | return ret; |
140 | sdata->u.sta.flags &= ~IEEE80211_STA_AUTO_BSSID_SEL; | 139 | sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_BSSID_SEL; |
141 | ieee80211_sta_req_auth(sdata, &sdata->u.sta); | 140 | ieee80211_sta_req_auth(sdata); |
142 | return 0; | 141 | return 0; |
143 | } | 142 | } |
144 | 143 | ||
145 | return -EOPNOTSUPP; | 144 | return -EOPNOTSUPP; |
146 | } | 145 | } |
147 | 146 | ||
148 | static u8 ieee80211_get_wstats_flags(struct ieee80211_local *local) | ||
149 | { | ||
150 | u8 wstats_flags = 0; | ||
151 | |||
152 | wstats_flags |= local->hw.flags & (IEEE80211_HW_SIGNAL_UNSPEC | | ||
153 | IEEE80211_HW_SIGNAL_DBM) ? | ||
154 | IW_QUAL_QUAL_UPDATED : IW_QUAL_QUAL_INVALID; | ||
155 | wstats_flags |= local->hw.flags & IEEE80211_HW_NOISE_DBM ? | ||
156 | IW_QUAL_NOISE_UPDATED : IW_QUAL_NOISE_INVALID; | ||
157 | if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) | ||
158 | wstats_flags |= IW_QUAL_DBM; | ||
159 | |||
160 | return wstats_flags; | ||
161 | } | ||
162 | |||
163 | static int ieee80211_ioctl_giwrange(struct net_device *dev, | ||
164 | struct iw_request_info *info, | ||
165 | struct iw_point *data, char *extra) | ||
166 | { | ||
167 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | ||
168 | struct iw_range *range = (struct iw_range *) extra; | ||
169 | enum ieee80211_band band; | ||
170 | int c = 0; | ||
171 | |||
172 | data->length = sizeof(struct iw_range); | ||
173 | memset(range, 0, sizeof(struct iw_range)); | ||
174 | |||
175 | range->we_version_compiled = WIRELESS_EXT; | ||
176 | range->we_version_source = 21; | ||
177 | range->retry_capa = IW_RETRY_LIMIT; | ||
178 | range->retry_flags = IW_RETRY_LIMIT; | ||
179 | range->min_retry = 0; | ||
180 | range->max_retry = 255; | ||
181 | range->min_rts = 0; | ||
182 | range->max_rts = 2347; | ||
183 | range->min_frag = 256; | ||
184 | range->max_frag = 2346; | ||
185 | |||
186 | range->encoding_size[0] = 5; | ||
187 | range->encoding_size[1] = 13; | ||
188 | range->num_encoding_sizes = 2; | ||
189 | range->max_encoding_tokens = NUM_DEFAULT_KEYS; | ||
190 | |||
191 | /* cfg80211 requires this, and enforces 0..100 */ | ||
192 | if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC) | ||
193 | range->max_qual.level = 100; | ||
194 | else if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) | ||
195 | range->max_qual.level = -110; | ||
196 | else | ||
197 | range->max_qual.level = 0; | ||
198 | |||
199 | if (local->hw.flags & IEEE80211_HW_NOISE_DBM) | ||
200 | range->max_qual.noise = -110; | ||
201 | else | ||
202 | range->max_qual.noise = 0; | ||
203 | |||
204 | range->max_qual.qual = 100; | ||
205 | range->max_qual.updated = ieee80211_get_wstats_flags(local); | ||
206 | |||
207 | range->avg_qual.qual = 50; | ||
208 | /* not always true but better than nothing */ | ||
209 | range->avg_qual.level = range->max_qual.level / 2; | ||
210 | range->avg_qual.noise = range->max_qual.noise / 2; | ||
211 | range->avg_qual.updated = ieee80211_get_wstats_flags(local); | ||
212 | |||
213 | range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 | | ||
214 | IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP; | ||
215 | |||
216 | |||
217 | for (band = 0; band < IEEE80211_NUM_BANDS; band ++) { | ||
218 | int i; | ||
219 | struct ieee80211_supported_band *sband; | ||
220 | |||
221 | sband = local->hw.wiphy->bands[band]; | ||
222 | |||
223 | if (!sband) | ||
224 | continue; | ||
225 | |||
226 | for (i = 0; i < sband->n_channels && c < IW_MAX_FREQUENCIES; i++) { | ||
227 | struct ieee80211_channel *chan = &sband->channels[i]; | ||
228 | |||
229 | if (!(chan->flags & IEEE80211_CHAN_DISABLED)) { | ||
230 | range->freq[c].i = | ||
231 | ieee80211_frequency_to_channel( | ||
232 | chan->center_freq); | ||
233 | range->freq[c].m = chan->center_freq; | ||
234 | range->freq[c].e = 6; | ||
235 | c++; | ||
236 | } | ||
237 | } | ||
238 | } | ||
239 | range->num_channels = c; | ||
240 | range->num_frequency = c; | ||
241 | |||
242 | IW_EVENT_CAPA_SET_KERNEL(range->event_capa); | ||
243 | IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWAP); | ||
244 | IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWSCAN); | ||
245 | |||
246 | range->scan_capa |= IW_SCAN_CAPA_ESSID; | ||
247 | |||
248 | return 0; | ||
249 | } | ||
250 | |||
251 | |||
252 | static int ieee80211_ioctl_siwfreq(struct net_device *dev, | 147 | static int ieee80211_ioctl_siwfreq(struct net_device *dev, |
253 | struct iw_request_info *info, | 148 | struct iw_request_info *info, |
254 | struct iw_freq *freq, char *extra) | 149 | struct iw_freq *freq, char *extra) |
255 | { | 150 | { |
256 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 151 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
257 | 152 | ||
258 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC || | 153 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC) |
259 | sdata->vif.type == NL80211_IFTYPE_STATION) | 154 | sdata->u.ibss.flags &= ~IEEE80211_IBSS_AUTO_CHANNEL_SEL; |
260 | sdata->u.sta.flags &= ~IEEE80211_STA_AUTO_CHANNEL_SEL; | 155 | else if (sdata->vif.type == NL80211_IFTYPE_STATION) |
156 | sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_CHANNEL_SEL; | ||
261 | 157 | ||
262 | /* freq->e == 0: freq->m = channel; otherwise freq = m * 10^e */ | 158 | /* freq->e == 0: freq->m = channel; otherwise freq = m * 10^e */ |
263 | if (freq->e == 0) { | 159 | if (freq->e == 0) { |
264 | if (freq->m < 0) { | 160 | if (freq->m < 0) { |
265 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC || | 161 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC) |
266 | sdata->vif.type == NL80211_IFTYPE_STATION) | 162 | sdata->u.ibss.flags |= |
267 | sdata->u.sta.flags |= | 163 | IEEE80211_IBSS_AUTO_CHANNEL_SEL; |
164 | else if (sdata->vif.type == NL80211_IFTYPE_STATION) | ||
165 | sdata->u.mgd.flags |= | ||
268 | IEEE80211_STA_AUTO_CHANNEL_SEL; | 166 | IEEE80211_STA_AUTO_CHANNEL_SEL; |
269 | return 0; | 167 | return 0; |
270 | } else | 168 | } else |
@@ -301,32 +199,35 @@ static int ieee80211_ioctl_siwessid(struct net_device *dev, | |||
301 | { | 199 | { |
302 | struct ieee80211_sub_if_data *sdata; | 200 | struct ieee80211_sub_if_data *sdata; |
303 | size_t len = data->length; | 201 | size_t len = data->length; |
202 | int ret; | ||
304 | 203 | ||
305 | /* iwconfig uses nul termination in SSID.. */ | 204 | /* iwconfig uses nul termination in SSID.. */ |
306 | if (len > 0 && ssid[len - 1] == '\0') | 205 | if (len > 0 && ssid[len - 1] == '\0') |
307 | len--; | 206 | len--; |
308 | 207 | ||
309 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 208 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
310 | if (sdata->vif.type == NL80211_IFTYPE_STATION || | 209 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { |
311 | sdata->vif.type == NL80211_IFTYPE_ADHOC) { | ||
312 | int ret; | ||
313 | if (sdata->flags & IEEE80211_SDATA_USERSPACE_MLME) { | 210 | if (sdata->flags & IEEE80211_SDATA_USERSPACE_MLME) { |
314 | if (len > IEEE80211_MAX_SSID_LEN) | 211 | if (len > IEEE80211_MAX_SSID_LEN) |
315 | return -EINVAL; | 212 | return -EINVAL; |
316 | memcpy(sdata->u.sta.ssid, ssid, len); | 213 | memcpy(sdata->u.mgd.ssid, ssid, len); |
317 | sdata->u.sta.ssid_len = len; | 214 | sdata->u.mgd.ssid_len = len; |
318 | return 0; | 215 | return 0; |
319 | } | 216 | } |
217 | |||
320 | if (data->flags) | 218 | if (data->flags) |
321 | sdata->u.sta.flags &= ~IEEE80211_STA_AUTO_SSID_SEL; | 219 | sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_SSID_SEL; |
322 | else | 220 | else |
323 | sdata->u.sta.flags |= IEEE80211_STA_AUTO_SSID_SEL; | 221 | sdata->u.mgd.flags |= IEEE80211_STA_AUTO_SSID_SEL; |
222 | |||
324 | ret = ieee80211_sta_set_ssid(sdata, ssid, len); | 223 | ret = ieee80211_sta_set_ssid(sdata, ssid, len); |
325 | if (ret) | 224 | if (ret) |
326 | return ret; | 225 | return ret; |
327 | ieee80211_sta_req_auth(sdata, &sdata->u.sta); | 226 | |
227 | ieee80211_sta_req_auth(sdata); | ||
328 | return 0; | 228 | return 0; |
329 | } | 229 | } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) |
230 | return ieee80211_ibss_set_ssid(sdata, ssid, len); | ||
330 | 231 | ||
331 | return -EOPNOTSUPP; | 232 | return -EOPNOTSUPP; |
332 | } | 233 | } |
@@ -340,8 +241,7 @@ static int ieee80211_ioctl_giwessid(struct net_device *dev, | |||
340 | 241 | ||
341 | struct ieee80211_sub_if_data *sdata; | 242 | struct ieee80211_sub_if_data *sdata; |
342 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 243 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
343 | if (sdata->vif.type == NL80211_IFTYPE_STATION || | 244 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { |
344 | sdata->vif.type == NL80211_IFTYPE_ADHOC) { | ||
345 | int res = ieee80211_sta_get_ssid(sdata, ssid, &len); | 245 | int res = ieee80211_sta_get_ssid(sdata, ssid, &len); |
346 | if (res == 0) { | 246 | if (res == 0) { |
347 | data->length = len; | 247 | data->length = len; |
@@ -349,6 +249,14 @@ static int ieee80211_ioctl_giwessid(struct net_device *dev, | |||
349 | } else | 249 | } else |
350 | data->flags = 0; | 250 | data->flags = 0; |
351 | return res; | 251 | return res; |
252 | } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { | ||
253 | int res = ieee80211_ibss_get_ssid(sdata, ssid, &len); | ||
254 | if (res == 0) { | ||
255 | data->length = len; | ||
256 | data->flags = 1; | ||
257 | } else | ||
258 | data->flags = 0; | ||
259 | return res; | ||
352 | } | 260 | } |
353 | 261 | ||
354 | return -EOPNOTSUPP; | 262 | return -EOPNOTSUPP; |
@@ -362,26 +270,35 @@ static int ieee80211_ioctl_siwap(struct net_device *dev, | |||
362 | struct ieee80211_sub_if_data *sdata; | 270 | struct ieee80211_sub_if_data *sdata; |
363 | 271 | ||
364 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 272 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
365 | if (sdata->vif.type == NL80211_IFTYPE_STATION || | 273 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { |
366 | sdata->vif.type == NL80211_IFTYPE_ADHOC) { | ||
367 | int ret; | 274 | int ret; |
368 | if (sdata->flags & IEEE80211_SDATA_USERSPACE_MLME) { | 275 | if (sdata->flags & IEEE80211_SDATA_USERSPACE_MLME) { |
369 | memcpy(sdata->u.sta.bssid, (u8 *) &ap_addr->sa_data, | 276 | memcpy(sdata->u.mgd.bssid, (u8 *) &ap_addr->sa_data, |
370 | ETH_ALEN); | 277 | ETH_ALEN); |
371 | return 0; | 278 | return 0; |
372 | } | 279 | } |
373 | if (is_zero_ether_addr((u8 *) &ap_addr->sa_data)) | 280 | if (is_zero_ether_addr((u8 *) &ap_addr->sa_data)) |
374 | sdata->u.sta.flags |= IEEE80211_STA_AUTO_BSSID_SEL | | 281 | sdata->u.mgd.flags |= IEEE80211_STA_AUTO_BSSID_SEL | |
375 | IEEE80211_STA_AUTO_CHANNEL_SEL; | 282 | IEEE80211_STA_AUTO_CHANNEL_SEL; |
376 | else if (is_broadcast_ether_addr((u8 *) &ap_addr->sa_data)) | 283 | else if (is_broadcast_ether_addr((u8 *) &ap_addr->sa_data)) |
377 | sdata->u.sta.flags |= IEEE80211_STA_AUTO_BSSID_SEL; | 284 | sdata->u.mgd.flags |= IEEE80211_STA_AUTO_BSSID_SEL; |
378 | else | 285 | else |
379 | sdata->u.sta.flags &= ~IEEE80211_STA_AUTO_BSSID_SEL; | 286 | sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_BSSID_SEL; |
380 | ret = ieee80211_sta_set_bssid(sdata, (u8 *) &ap_addr->sa_data); | 287 | ret = ieee80211_sta_set_bssid(sdata, (u8 *) &ap_addr->sa_data); |
381 | if (ret) | 288 | if (ret) |
382 | return ret; | 289 | return ret; |
383 | ieee80211_sta_req_auth(sdata, &sdata->u.sta); | 290 | ieee80211_sta_req_auth(sdata); |
384 | return 0; | 291 | return 0; |
292 | } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { | ||
293 | if (is_zero_ether_addr((u8 *) &ap_addr->sa_data)) | ||
294 | sdata->u.ibss.flags |= IEEE80211_IBSS_AUTO_BSSID_SEL | | ||
295 | IEEE80211_IBSS_AUTO_CHANNEL_SEL; | ||
296 | else if (is_broadcast_ether_addr((u8 *) &ap_addr->sa_data)) | ||
297 | sdata->u.ibss.flags |= IEEE80211_IBSS_AUTO_BSSID_SEL; | ||
298 | else | ||
299 | sdata->u.ibss.flags &= ~IEEE80211_IBSS_AUTO_BSSID_SEL; | ||
300 | |||
301 | return ieee80211_ibss_set_bssid(sdata, (u8 *) &ap_addr->sa_data); | ||
385 | } else if (sdata->vif.type == NL80211_IFTYPE_WDS) { | 302 | } else if (sdata->vif.type == NL80211_IFTYPE_WDS) { |
386 | /* | 303 | /* |
387 | * If it is necessary to update the WDS peer address | 304 | * If it is necessary to update the WDS peer address |
@@ -410,17 +327,20 @@ static int ieee80211_ioctl_giwap(struct net_device *dev, | |||
410 | struct ieee80211_sub_if_data *sdata; | 327 | struct ieee80211_sub_if_data *sdata; |
411 | 328 | ||
412 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 329 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
413 | if (sdata->vif.type == NL80211_IFTYPE_STATION || | 330 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { |
414 | sdata->vif.type == NL80211_IFTYPE_ADHOC) { | 331 | if (sdata->u.mgd.state == IEEE80211_STA_MLME_ASSOCIATED) { |
415 | if (sdata->u.sta.state == IEEE80211_STA_MLME_ASSOCIATED || | ||
416 | sdata->u.sta.state == IEEE80211_STA_MLME_IBSS_JOINED) { | ||
417 | ap_addr->sa_family = ARPHRD_ETHER; | 332 | ap_addr->sa_family = ARPHRD_ETHER; |
418 | memcpy(&ap_addr->sa_data, sdata->u.sta.bssid, ETH_ALEN); | 333 | memcpy(&ap_addr->sa_data, sdata->u.mgd.bssid, ETH_ALEN); |
419 | return 0; | 334 | } else |
420 | } else { | ||
421 | memset(&ap_addr->sa_data, 0, ETH_ALEN); | 335 | memset(&ap_addr->sa_data, 0, ETH_ALEN); |
422 | return 0; | 336 | return 0; |
423 | } | 337 | } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { |
338 | if (sdata->u.ibss.state == IEEE80211_IBSS_MLME_JOINED) { | ||
339 | ap_addr->sa_family = ARPHRD_ETHER; | ||
340 | memcpy(&ap_addr->sa_data, sdata->u.ibss.bssid, ETH_ALEN); | ||
341 | } else | ||
342 | memset(&ap_addr->sa_data, 0, ETH_ALEN); | ||
343 | return 0; | ||
424 | } else if (sdata->vif.type == NL80211_IFTYPE_WDS) { | 344 | } else if (sdata->vif.type == NL80211_IFTYPE_WDS) { |
425 | ap_addr->sa_family = ARPHRD_ETHER; | 345 | ap_addr->sa_family = ARPHRD_ETHER; |
426 | memcpy(&ap_addr->sa_data, sdata->u.wds.remote_addr, ETH_ALEN); | 346 | memcpy(&ap_addr->sa_data, sdata->u.wds.remote_addr, ETH_ALEN); |
@@ -486,7 +406,7 @@ static int ieee80211_ioctl_giwrate(struct net_device *dev, | |||
486 | 406 | ||
487 | rcu_read_lock(); | 407 | rcu_read_lock(); |
488 | 408 | ||
489 | sta = sta_info_get(local, sdata->u.sta.bssid); | 409 | sta = sta_info_get(local, sdata->u.mgd.bssid); |
490 | 410 | ||
491 | if (sta && !(sta->last_tx_rate.flags & IEEE80211_TX_RC_MCS)) | 411 | if (sta && !(sta->last_tx_rate.flags & IEEE80211_TX_RC_MCS)) |
492 | rate->value = sband->bitrates[sta->last_tx_rate.idx].bitrate; | 412 | rate->value = sband->bitrates[sta->last_tx_rate.idx].bitrate; |
@@ -687,8 +607,7 @@ static int ieee80211_ioctl_siwmlme(struct net_device *dev, | |||
687 | struct iw_mlme *mlme = (struct iw_mlme *) extra; | 607 | struct iw_mlme *mlme = (struct iw_mlme *) extra; |
688 | 608 | ||
689 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 609 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
690 | if (sdata->vif.type != NL80211_IFTYPE_STATION && | 610 | if (!(sdata->vif.type == NL80211_IFTYPE_STATION)) |
691 | sdata->vif.type != NL80211_IFTYPE_ADHOC) | ||
692 | return -EINVAL; | 611 | return -EINVAL; |
693 | 612 | ||
694 | switch (mlme->cmd) { | 613 | switch (mlme->cmd) { |
@@ -784,8 +703,7 @@ static int ieee80211_ioctl_giwencode(struct net_device *dev, | |||
784 | erq->flags |= IW_ENCODE_ENABLED; | 703 | erq->flags |= IW_ENCODE_ENABLED; |
785 | 704 | ||
786 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { | 705 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { |
787 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | 706 | switch (sdata->u.mgd.auth_alg) { |
788 | switch (ifsta->auth_alg) { | ||
789 | case WLAN_AUTH_OPEN: | 707 | case WLAN_AUTH_OPEN: |
790 | case WLAN_AUTH_LEAP: | 708 | case WLAN_AUTH_LEAP: |
791 | erq->flags |= IW_ENCODE_OPEN; | 709 | erq->flags |= IW_ENCODE_OPEN; |
@@ -849,7 +767,7 @@ static int ieee80211_ioctl_siwpower(struct net_device *dev, | |||
849 | ret = ieee80211_hw_config(local, | 767 | ret = ieee80211_hw_config(local, |
850 | IEEE80211_CONF_CHANGE_DYNPS_TIMEOUT); | 768 | IEEE80211_CONF_CHANGE_DYNPS_TIMEOUT); |
851 | 769 | ||
852 | if (!(sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED)) | 770 | if (!(sdata->u.mgd.flags & IEEE80211_STA_ASSOCIATED)) |
853 | return ret; | 771 | return ret; |
854 | 772 | ||
855 | if (conf->dynamic_ps_timeout > 0 && | 773 | if (conf->dynamic_ps_timeout > 0 && |
@@ -908,10 +826,10 @@ static int ieee80211_ioctl_siwauth(struct net_device *dev, | |||
908 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { | 826 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { |
909 | if (data->value & (IW_AUTH_CIPHER_WEP40 | | 827 | if (data->value & (IW_AUTH_CIPHER_WEP40 | |
910 | IW_AUTH_CIPHER_WEP104 | IW_AUTH_CIPHER_TKIP)) | 828 | IW_AUTH_CIPHER_WEP104 | IW_AUTH_CIPHER_TKIP)) |
911 | sdata->u.sta.flags |= | 829 | sdata->u.mgd.flags |= |
912 | IEEE80211_STA_TKIP_WEP_USED; | 830 | IEEE80211_STA_TKIP_WEP_USED; |
913 | else | 831 | else |
914 | sdata->u.sta.flags &= | 832 | sdata->u.mgd.flags &= |
915 | ~IEEE80211_STA_TKIP_WEP_USED; | 833 | ~IEEE80211_STA_TKIP_WEP_USED; |
916 | } | 834 | } |
917 | break; | 835 | break; |
@@ -922,21 +840,20 @@ static int ieee80211_ioctl_siwauth(struct net_device *dev, | |||
922 | if (sdata->vif.type != NL80211_IFTYPE_STATION) | 840 | if (sdata->vif.type != NL80211_IFTYPE_STATION) |
923 | ret = -EINVAL; | 841 | ret = -EINVAL; |
924 | else { | 842 | else { |
925 | sdata->u.sta.flags &= ~IEEE80211_STA_PRIVACY_INVOKED; | 843 | sdata->u.mgd.flags &= ~IEEE80211_STA_PRIVACY_INVOKED; |
926 | /* | 844 | /* |
927 | * Privacy invoked by wpa_supplicant, store the | 845 | * Privacy invoked by wpa_supplicant, store the |
928 | * value and allow associating to a protected | 846 | * value and allow associating to a protected |
929 | * network without having a key up front. | 847 | * network without having a key up front. |
930 | */ | 848 | */ |
931 | if (data->value) | 849 | if (data->value) |
932 | sdata->u.sta.flags |= | 850 | sdata->u.mgd.flags |= |
933 | IEEE80211_STA_PRIVACY_INVOKED; | 851 | IEEE80211_STA_PRIVACY_INVOKED; |
934 | } | 852 | } |
935 | break; | 853 | break; |
936 | case IW_AUTH_80211_AUTH_ALG: | 854 | case IW_AUTH_80211_AUTH_ALG: |
937 | if (sdata->vif.type == NL80211_IFTYPE_STATION || | 855 | if (sdata->vif.type == NL80211_IFTYPE_STATION) |
938 | sdata->vif.type == NL80211_IFTYPE_ADHOC) | 856 | sdata->u.mgd.auth_algs = data->value; |
939 | sdata->u.sta.auth_algs = data->value; | ||
940 | else | 857 | else |
941 | ret = -EOPNOTSUPP; | 858 | ret = -EOPNOTSUPP; |
942 | break; | 859 | break; |
@@ -945,17 +862,16 @@ static int ieee80211_ioctl_siwauth(struct net_device *dev, | |||
945 | ret = -EOPNOTSUPP; | 862 | ret = -EOPNOTSUPP; |
946 | break; | 863 | break; |
947 | } | 864 | } |
948 | if (sdata->vif.type == NL80211_IFTYPE_STATION || | 865 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { |
949 | sdata->vif.type == NL80211_IFTYPE_ADHOC) { | ||
950 | switch (data->value) { | 866 | switch (data->value) { |
951 | case IW_AUTH_MFP_DISABLED: | 867 | case IW_AUTH_MFP_DISABLED: |
952 | sdata->u.sta.mfp = IEEE80211_MFP_DISABLED; | 868 | sdata->u.mgd.mfp = IEEE80211_MFP_DISABLED; |
953 | break; | 869 | break; |
954 | case IW_AUTH_MFP_OPTIONAL: | 870 | case IW_AUTH_MFP_OPTIONAL: |
955 | sdata->u.sta.mfp = IEEE80211_MFP_OPTIONAL; | 871 | sdata->u.mgd.mfp = IEEE80211_MFP_OPTIONAL; |
956 | break; | 872 | break; |
957 | case IW_AUTH_MFP_REQUIRED: | 873 | case IW_AUTH_MFP_REQUIRED: |
958 | sdata->u.sta.mfp = IEEE80211_MFP_REQUIRED; | 874 | sdata->u.mgd.mfp = IEEE80211_MFP_REQUIRED; |
959 | break; | 875 | break; |
960 | default: | 876 | default: |
961 | ret = -EINVAL; | 877 | ret = -EINVAL; |
@@ -970,6 +886,21 @@ static int ieee80211_ioctl_siwauth(struct net_device *dev, | |||
970 | return ret; | 886 | return ret; |
971 | } | 887 | } |
972 | 888 | ||
889 | static u8 ieee80211_get_wstats_flags(struct ieee80211_local *local) | ||
890 | { | ||
891 | u8 wstats_flags = 0; | ||
892 | |||
893 | wstats_flags |= local->hw.flags & (IEEE80211_HW_SIGNAL_UNSPEC | | ||
894 | IEEE80211_HW_SIGNAL_DBM) ? | ||
895 | IW_QUAL_QUAL_UPDATED : IW_QUAL_QUAL_INVALID; | ||
896 | wstats_flags |= local->hw.flags & IEEE80211_HW_NOISE_DBM ? | ||
897 | IW_QUAL_NOISE_UPDATED : IW_QUAL_NOISE_INVALID; | ||
898 | if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) | ||
899 | wstats_flags |= IW_QUAL_DBM; | ||
900 | |||
901 | return wstats_flags; | ||
902 | } | ||
903 | |||
973 | /* Get wireless statistics. Called by /proc/net/wireless and by SIOCGIWSTATS */ | 904 | /* Get wireless statistics. Called by /proc/net/wireless and by SIOCGIWSTATS */ |
974 | static struct iw_statistics *ieee80211_get_wireless_stats(struct net_device *dev) | 905 | static struct iw_statistics *ieee80211_get_wireless_stats(struct net_device *dev) |
975 | { | 906 | { |
@@ -980,9 +911,9 @@ static struct iw_statistics *ieee80211_get_wireless_stats(struct net_device *dev | |||
980 | 911 | ||
981 | rcu_read_lock(); | 912 | rcu_read_lock(); |
982 | 913 | ||
983 | if (sdata->vif.type == NL80211_IFTYPE_STATION || | 914 | if (sdata->vif.type == NL80211_IFTYPE_STATION) |
984 | sdata->vif.type == NL80211_IFTYPE_ADHOC) | 915 | sta = sta_info_get(local, sdata->u.mgd.bssid); |
985 | sta = sta_info_get(local, sdata->u.sta.bssid); | 916 | |
986 | if (!sta) { | 917 | if (!sta) { |
987 | wstats->discard.fragment = 0; | 918 | wstats->discard.fragment = 0; |
988 | wstats->discard.misc = 0; | 919 | wstats->discard.misc = 0; |
@@ -1011,9 +942,8 @@ static int ieee80211_ioctl_giwauth(struct net_device *dev, | |||
1011 | 942 | ||
1012 | switch (data->flags & IW_AUTH_INDEX) { | 943 | switch (data->flags & IW_AUTH_INDEX) { |
1013 | case IW_AUTH_80211_AUTH_ALG: | 944 | case IW_AUTH_80211_AUTH_ALG: |
1014 | if (sdata->vif.type == NL80211_IFTYPE_STATION || | 945 | if (sdata->vif.type == NL80211_IFTYPE_STATION) |
1015 | sdata->vif.type == NL80211_IFTYPE_ADHOC) | 946 | data->value = sdata->u.mgd.auth_algs; |
1016 | data->value = sdata->u.sta.auth_algs; | ||
1017 | else | 947 | else |
1018 | ret = -EOPNOTSUPP; | 948 | ret = -EOPNOTSUPP; |
1019 | break; | 949 | break; |
@@ -1116,7 +1046,7 @@ static const iw_handler ieee80211_handler[] = | |||
1116 | (iw_handler) NULL, /* SIOCSIWSENS */ | 1046 | (iw_handler) NULL, /* SIOCSIWSENS */ |
1117 | (iw_handler) NULL, /* SIOCGIWSENS */ | 1047 | (iw_handler) NULL, /* SIOCGIWSENS */ |
1118 | (iw_handler) NULL /* not used */, /* SIOCSIWRANGE */ | 1048 | (iw_handler) NULL /* not used */, /* SIOCSIWRANGE */ |
1119 | (iw_handler) ieee80211_ioctl_giwrange, /* SIOCGIWRANGE */ | 1049 | (iw_handler) cfg80211_wext_giwrange, /* SIOCGIWRANGE */ |
1120 | (iw_handler) NULL /* not used */, /* SIOCSIWPRIV */ | 1050 | (iw_handler) NULL /* not used */, /* SIOCSIWPRIV */ |
1121 | (iw_handler) NULL /* kernel code */, /* SIOCGIWPRIV */ | 1051 | (iw_handler) NULL /* kernel code */, /* SIOCGIWPRIV */ |
1122 | (iw_handler) NULL /* not used */, /* SIOCSIWSTATS */ | 1052 | (iw_handler) NULL /* not used */, /* SIOCSIWSTATS */ |
diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c index ac71b38f7cb5..093a4ab7f28b 100644 --- a/net/mac80211/wme.c +++ b/net/mac80211/wme.c | |||
@@ -114,9 +114,7 @@ u16 ieee80211_select_queue(struct net_device *dev, struct sk_buff *skb) | |||
114 | { | 114 | { |
115 | struct ieee80211_master_priv *mpriv = netdev_priv(dev); | 115 | struct ieee80211_master_priv *mpriv = netdev_priv(dev); |
116 | struct ieee80211_local *local = mpriv->local; | 116 | struct ieee80211_local *local = mpriv->local; |
117 | struct ieee80211_hw *hw = &local->hw; | ||
118 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | 117 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; |
119 | struct sta_info *sta; | ||
120 | u16 queue; | 118 | u16 queue; |
121 | u8 tid; | 119 | u8 tid; |
122 | 120 | ||
@@ -124,29 +122,11 @@ u16 ieee80211_select_queue(struct net_device *dev, struct sk_buff *skb) | |||
124 | if (unlikely(queue >= local->hw.queues)) | 122 | if (unlikely(queue >= local->hw.queues)) |
125 | queue = local->hw.queues - 1; | 123 | queue = local->hw.queues - 1; |
126 | 124 | ||
127 | if (skb->requeue) { | 125 | /* |
128 | if (!hw->ampdu_queues) | 126 | * Now we know the 1d priority, fill in the QoS header if |
129 | return queue; | 127 | * there is one (and we haven't done this before). |
130 | |||
131 | rcu_read_lock(); | ||
132 | sta = sta_info_get(local, hdr->addr1); | ||
133 | tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK; | ||
134 | if (sta) { | ||
135 | int ampdu_queue = sta->tid_to_tx_q[tid]; | ||
136 | |||
137 | if ((ampdu_queue < ieee80211_num_queues(hw)) && | ||
138 | test_bit(ampdu_queue, local->queue_pool)) | ||
139 | queue = ampdu_queue; | ||
140 | } | ||
141 | rcu_read_unlock(); | ||
142 | |||
143 | return queue; | ||
144 | } | ||
145 | |||
146 | /* Now we know the 1d priority, fill in the QoS header if | ||
147 | * there is one. | ||
148 | */ | 128 | */ |
149 | if (ieee80211_is_data_qos(hdr->frame_control)) { | 129 | if (!skb->requeue && ieee80211_is_data_qos(hdr->frame_control)) { |
150 | u8 *p = ieee80211_get_qos_ctl(hdr); | 130 | u8 *p = ieee80211_get_qos_ctl(hdr); |
151 | u8 ack_policy = 0; | 131 | u8 ack_policy = 0; |
152 | tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK; | 132 | tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK; |
@@ -156,140 +136,7 @@ u16 ieee80211_select_queue(struct net_device *dev, struct sk_buff *skb) | |||
156 | /* qos header is 2 bytes, second reserved */ | 136 | /* qos header is 2 bytes, second reserved */ |
157 | *p++ = ack_policy | tid; | 137 | *p++ = ack_policy | tid; |
158 | *p = 0; | 138 | *p = 0; |
159 | |||
160 | if (!hw->ampdu_queues) | ||
161 | return queue; | ||
162 | |||
163 | rcu_read_lock(); | ||
164 | |||
165 | sta = sta_info_get(local, hdr->addr1); | ||
166 | if (sta) { | ||
167 | int ampdu_queue = sta->tid_to_tx_q[tid]; | ||
168 | |||
169 | if ((ampdu_queue < ieee80211_num_queues(hw)) && | ||
170 | test_bit(ampdu_queue, local->queue_pool)) | ||
171 | queue = ampdu_queue; | ||
172 | } | ||
173 | |||
174 | rcu_read_unlock(); | ||
175 | } | 139 | } |
176 | 140 | ||
177 | return queue; | 141 | return queue; |
178 | } | 142 | } |
179 | |||
180 | int ieee80211_ht_agg_queue_add(struct ieee80211_local *local, | ||
181 | struct sta_info *sta, u16 tid) | ||
182 | { | ||
183 | int i; | ||
184 | |||
185 | /* XXX: currently broken due to cb/requeue use */ | ||
186 | return -EPERM; | ||
187 | |||
188 | /* prepare the filter and save it for the SW queue | ||
189 | * matching the received HW queue */ | ||
190 | |||
191 | if (!local->hw.ampdu_queues) | ||
192 | return -EPERM; | ||
193 | |||
194 | /* try to get a Qdisc from the pool */ | ||
195 | for (i = local->hw.queues; i < ieee80211_num_queues(&local->hw); i++) | ||
196 | if (!test_and_set_bit(i, local->queue_pool)) { | ||
197 | ieee80211_stop_queue(local_to_hw(local), i); | ||
198 | sta->tid_to_tx_q[tid] = i; | ||
199 | |||
200 | /* IF there are already pending packets | ||
201 | * on this tid first we need to drain them | ||
202 | * on the previous queue | ||
203 | * since HT is strict in order */ | ||
204 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
205 | if (net_ratelimit()) | ||
206 | printk(KERN_DEBUG "allocated aggregation queue" | ||
207 | " %d tid %d addr %pM pool=0x%lX\n", | ||
208 | i, tid, sta->sta.addr, | ||
209 | local->queue_pool[0]); | ||
210 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | ||
211 | return 0; | ||
212 | } | ||
213 | |||
214 | return -EAGAIN; | ||
215 | } | ||
216 | |||
217 | /** | ||
218 | * the caller needs to hold netdev_get_tx_queue(local->mdev, X)->lock | ||
219 | */ | ||
220 | void ieee80211_ht_agg_queue_remove(struct ieee80211_local *local, | ||
221 | struct sta_info *sta, u16 tid, | ||
222 | u8 requeue) | ||
223 | { | ||
224 | int agg_queue = sta->tid_to_tx_q[tid]; | ||
225 | struct ieee80211_hw *hw = &local->hw; | ||
226 | |||
227 | /* return the qdisc to the pool */ | ||
228 | clear_bit(agg_queue, local->queue_pool); | ||
229 | sta->tid_to_tx_q[tid] = ieee80211_num_queues(hw); | ||
230 | |||
231 | if (requeue) { | ||
232 | ieee80211_requeue(local, agg_queue); | ||
233 | } else { | ||
234 | struct netdev_queue *txq; | ||
235 | spinlock_t *root_lock; | ||
236 | struct Qdisc *q; | ||
237 | |||
238 | txq = netdev_get_tx_queue(local->mdev, agg_queue); | ||
239 | q = rcu_dereference(txq->qdisc); | ||
240 | root_lock = qdisc_lock(q); | ||
241 | |||
242 | spin_lock_bh(root_lock); | ||
243 | qdisc_reset(q); | ||
244 | spin_unlock_bh(root_lock); | ||
245 | } | ||
246 | } | ||
247 | |||
248 | void ieee80211_requeue(struct ieee80211_local *local, int queue) | ||
249 | { | ||
250 | struct netdev_queue *txq = netdev_get_tx_queue(local->mdev, queue); | ||
251 | struct sk_buff_head list; | ||
252 | spinlock_t *root_lock; | ||
253 | struct Qdisc *qdisc; | ||
254 | u32 len; | ||
255 | |||
256 | rcu_read_lock_bh(); | ||
257 | |||
258 | qdisc = rcu_dereference(txq->qdisc); | ||
259 | if (!qdisc || !qdisc->dequeue) | ||
260 | goto out_unlock; | ||
261 | |||
262 | skb_queue_head_init(&list); | ||
263 | |||
264 | root_lock = qdisc_root_lock(qdisc); | ||
265 | spin_lock(root_lock); | ||
266 | for (len = qdisc->q.qlen; len > 0; len--) { | ||
267 | struct sk_buff *skb = qdisc->dequeue(qdisc); | ||
268 | |||
269 | if (skb) | ||
270 | __skb_queue_tail(&list, skb); | ||
271 | } | ||
272 | spin_unlock(root_lock); | ||
273 | |||
274 | for (len = list.qlen; len > 0; len--) { | ||
275 | struct sk_buff *skb = __skb_dequeue(&list); | ||
276 | u16 new_queue; | ||
277 | |||
278 | BUG_ON(!skb); | ||
279 | new_queue = ieee80211_select_queue(local->mdev, skb); | ||
280 | skb_set_queue_mapping(skb, new_queue); | ||
281 | |||
282 | txq = netdev_get_tx_queue(local->mdev, new_queue); | ||
283 | |||
284 | |||
285 | qdisc = rcu_dereference(txq->qdisc); | ||
286 | root_lock = qdisc_root_lock(qdisc); | ||
287 | |||
288 | spin_lock(root_lock); | ||
289 | qdisc_enqueue_root(skb, qdisc); | ||
290 | spin_unlock(root_lock); | ||
291 | } | ||
292 | |||
293 | out_unlock: | ||
294 | rcu_read_unlock_bh(); | ||
295 | } | ||
diff --git a/net/mac80211/wme.h b/net/mac80211/wme.h index bc62f28a4d3d..7520d2e014dc 100644 --- a/net/mac80211/wme.h +++ b/net/mac80211/wme.h | |||
@@ -21,11 +21,5 @@ | |||
21 | extern const int ieee802_1d_to_ac[8]; | 21 | extern const int ieee802_1d_to_ac[8]; |
22 | 22 | ||
23 | u16 ieee80211_select_queue(struct net_device *dev, struct sk_buff *skb); | 23 | u16 ieee80211_select_queue(struct net_device *dev, struct sk_buff *skb); |
24 | int ieee80211_ht_agg_queue_add(struct ieee80211_local *local, | ||
25 | struct sta_info *sta, u16 tid); | ||
26 | void ieee80211_ht_agg_queue_remove(struct ieee80211_local *local, | ||
27 | struct sta_info *sta, u16 tid, | ||
28 | u8 requeue); | ||
29 | void ieee80211_requeue(struct ieee80211_local *local, int queue); | ||
30 | 24 | ||
31 | #endif /* _WME_H */ | 25 | #endif /* _WME_H */ |
diff --git a/net/wireless/core.c b/net/wireless/core.c index 0668b2bfc1da..dd7f222919fe 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c | |||
@@ -7,7 +7,6 @@ | |||
7 | #include <linux/if.h> | 7 | #include <linux/if.h> |
8 | #include <linux/module.h> | 8 | #include <linux/module.h> |
9 | #include <linux/err.h> | 9 | #include <linux/err.h> |
10 | #include <linux/mutex.h> | ||
11 | #include <linux/list.h> | 10 | #include <linux/list.h> |
12 | #include <linux/nl80211.h> | 11 | #include <linux/nl80211.h> |
13 | #include <linux/debugfs.h> | 12 | #include <linux/debugfs.h> |
@@ -31,18 +30,29 @@ MODULE_DESCRIPTION("wireless configuration support"); | |||
31 | * only read the list, and that can happen quite | 30 | * only read the list, and that can happen quite |
32 | * often because we need to do it for each command */ | 31 | * often because we need to do it for each command */ |
33 | LIST_HEAD(cfg80211_drv_list); | 32 | LIST_HEAD(cfg80211_drv_list); |
34 | DEFINE_MUTEX(cfg80211_drv_mutex); | 33 | |
34 | /* | ||
35 | * This is used to protect the cfg80211_drv_list, cfg80211_regdomain, | ||
36 | * country_ie_regdomain, the reg_beacon_list and the the last regulatory | ||
37 | * request receipt (last_request). | ||
38 | */ | ||
39 | DEFINE_MUTEX(cfg80211_mutex); | ||
35 | 40 | ||
36 | /* for debugfs */ | 41 | /* for debugfs */ |
37 | static struct dentry *ieee80211_debugfs_dir; | 42 | static struct dentry *ieee80211_debugfs_dir; |
38 | 43 | ||
39 | /* requires cfg80211_drv_mutex to be held! */ | 44 | /* requires cfg80211_mutex to be held! */ |
40 | static struct cfg80211_registered_device *cfg80211_drv_by_wiphy(int wiphy) | 45 | struct cfg80211_registered_device *cfg80211_drv_by_wiphy_idx(int wiphy_idx) |
41 | { | 46 | { |
42 | struct cfg80211_registered_device *result = NULL, *drv; | 47 | struct cfg80211_registered_device *result = NULL, *drv; |
43 | 48 | ||
49 | if (!wiphy_idx_valid(wiphy_idx)) | ||
50 | return NULL; | ||
51 | |||
52 | assert_cfg80211_lock(); | ||
53 | |||
44 | list_for_each_entry(drv, &cfg80211_drv_list, list) { | 54 | list_for_each_entry(drv, &cfg80211_drv_list, list) { |
45 | if (drv->idx == wiphy) { | 55 | if (drv->wiphy_idx == wiphy_idx) { |
46 | result = drv; | 56 | result = drv; |
47 | break; | 57 | break; |
48 | } | 58 | } |
@@ -51,17 +61,44 @@ static struct cfg80211_registered_device *cfg80211_drv_by_wiphy(int wiphy) | |||
51 | return result; | 61 | return result; |
52 | } | 62 | } |
53 | 63 | ||
64 | int get_wiphy_idx(struct wiphy *wiphy) | ||
65 | { | ||
66 | struct cfg80211_registered_device *drv; | ||
67 | if (!wiphy) | ||
68 | return WIPHY_IDX_STALE; | ||
69 | drv = wiphy_to_dev(wiphy); | ||
70 | return drv->wiphy_idx; | ||
71 | } | ||
72 | |||
54 | /* requires cfg80211_drv_mutex to be held! */ | 73 | /* requires cfg80211_drv_mutex to be held! */ |
74 | struct wiphy *wiphy_idx_to_wiphy(int wiphy_idx) | ||
75 | { | ||
76 | struct cfg80211_registered_device *drv; | ||
77 | |||
78 | if (!wiphy_idx_valid(wiphy_idx)) | ||
79 | return NULL; | ||
80 | |||
81 | assert_cfg80211_lock(); | ||
82 | |||
83 | drv = cfg80211_drv_by_wiphy_idx(wiphy_idx); | ||
84 | if (!drv) | ||
85 | return NULL; | ||
86 | return &drv->wiphy; | ||
87 | } | ||
88 | |||
89 | /* requires cfg80211_mutex to be held! */ | ||
55 | static struct cfg80211_registered_device * | 90 | static struct cfg80211_registered_device * |
56 | __cfg80211_drv_from_info(struct genl_info *info) | 91 | __cfg80211_drv_from_info(struct genl_info *info) |
57 | { | 92 | { |
58 | int ifindex; | 93 | int ifindex; |
59 | struct cfg80211_registered_device *bywiphy = NULL, *byifidx = NULL; | 94 | struct cfg80211_registered_device *bywiphyidx = NULL, *byifidx = NULL; |
60 | struct net_device *dev; | 95 | struct net_device *dev; |
61 | int err = -EINVAL; | 96 | int err = -EINVAL; |
62 | 97 | ||
98 | assert_cfg80211_lock(); | ||
99 | |||
63 | if (info->attrs[NL80211_ATTR_WIPHY]) { | 100 | if (info->attrs[NL80211_ATTR_WIPHY]) { |
64 | bywiphy = cfg80211_drv_by_wiphy( | 101 | bywiphyidx = cfg80211_drv_by_wiphy_idx( |
65 | nla_get_u32(info->attrs[NL80211_ATTR_WIPHY])); | 102 | nla_get_u32(info->attrs[NL80211_ATTR_WIPHY])); |
66 | err = -ENODEV; | 103 | err = -ENODEV; |
67 | } | 104 | } |
@@ -78,14 +115,14 @@ __cfg80211_drv_from_info(struct genl_info *info) | |||
78 | err = -ENODEV; | 115 | err = -ENODEV; |
79 | } | 116 | } |
80 | 117 | ||
81 | if (bywiphy && byifidx) { | 118 | if (bywiphyidx && byifidx) { |
82 | if (bywiphy != byifidx) | 119 | if (bywiphyidx != byifidx) |
83 | return ERR_PTR(-EINVAL); | 120 | return ERR_PTR(-EINVAL); |
84 | else | 121 | else |
85 | return bywiphy; /* == byifidx */ | 122 | return bywiphyidx; /* == byifidx */ |
86 | } | 123 | } |
87 | if (bywiphy) | 124 | if (bywiphyidx) |
88 | return bywiphy; | 125 | return bywiphyidx; |
89 | 126 | ||
90 | if (byifidx) | 127 | if (byifidx) |
91 | return byifidx; | 128 | return byifidx; |
@@ -98,7 +135,7 @@ cfg80211_get_dev_from_info(struct genl_info *info) | |||
98 | { | 135 | { |
99 | struct cfg80211_registered_device *drv; | 136 | struct cfg80211_registered_device *drv; |
100 | 137 | ||
101 | mutex_lock(&cfg80211_drv_mutex); | 138 | mutex_lock(&cfg80211_mutex); |
102 | drv = __cfg80211_drv_from_info(info); | 139 | drv = __cfg80211_drv_from_info(info); |
103 | 140 | ||
104 | /* if it is not an error we grab the lock on | 141 | /* if it is not an error we grab the lock on |
@@ -107,7 +144,7 @@ cfg80211_get_dev_from_info(struct genl_info *info) | |||
107 | if (!IS_ERR(drv)) | 144 | if (!IS_ERR(drv)) |
108 | mutex_lock(&drv->mtx); | 145 | mutex_lock(&drv->mtx); |
109 | 146 | ||
110 | mutex_unlock(&cfg80211_drv_mutex); | 147 | mutex_unlock(&cfg80211_mutex); |
111 | 148 | ||
112 | return drv; | 149 | return drv; |
113 | } | 150 | } |
@@ -118,7 +155,7 @@ cfg80211_get_dev_from_ifindex(int ifindex) | |||
118 | struct cfg80211_registered_device *drv = ERR_PTR(-ENODEV); | 155 | struct cfg80211_registered_device *drv = ERR_PTR(-ENODEV); |
119 | struct net_device *dev; | 156 | struct net_device *dev; |
120 | 157 | ||
121 | mutex_lock(&cfg80211_drv_mutex); | 158 | mutex_lock(&cfg80211_mutex); |
122 | dev = dev_get_by_index(&init_net, ifindex); | 159 | dev = dev_get_by_index(&init_net, ifindex); |
123 | if (!dev) | 160 | if (!dev) |
124 | goto out; | 161 | goto out; |
@@ -129,7 +166,7 @@ cfg80211_get_dev_from_ifindex(int ifindex) | |||
129 | drv = ERR_PTR(-ENODEV); | 166 | drv = ERR_PTR(-ENODEV); |
130 | dev_put(dev); | 167 | dev_put(dev); |
131 | out: | 168 | out: |
132 | mutex_unlock(&cfg80211_drv_mutex); | 169 | mutex_unlock(&cfg80211_mutex); |
133 | return drv; | 170 | return drv; |
134 | } | 171 | } |
135 | 172 | ||
@@ -143,16 +180,16 @@ int cfg80211_dev_rename(struct cfg80211_registered_device *rdev, | |||
143 | char *newname) | 180 | char *newname) |
144 | { | 181 | { |
145 | struct cfg80211_registered_device *drv; | 182 | struct cfg80211_registered_device *drv; |
146 | int idx, taken = -1, result, digits; | 183 | int wiphy_idx, taken = -1, result, digits; |
147 | 184 | ||
148 | mutex_lock(&cfg80211_drv_mutex); | 185 | mutex_lock(&cfg80211_mutex); |
149 | 186 | ||
150 | /* prohibit calling the thing phy%d when %d is not its number */ | 187 | /* prohibit calling the thing phy%d when %d is not its number */ |
151 | sscanf(newname, PHY_NAME "%d%n", &idx, &taken); | 188 | sscanf(newname, PHY_NAME "%d%n", &wiphy_idx, &taken); |
152 | if (taken == strlen(newname) && idx != rdev->idx) { | 189 | if (taken == strlen(newname) && wiphy_idx != rdev->wiphy_idx) { |
153 | /* count number of places needed to print idx */ | 190 | /* count number of places needed to print wiphy_idx */ |
154 | digits = 1; | 191 | digits = 1; |
155 | while (idx /= 10) | 192 | while (wiphy_idx /= 10) |
156 | digits++; | 193 | digits++; |
157 | /* | 194 | /* |
158 | * deny the name if it is phy<idx> where <idx> is printed | 195 | * deny the name if it is phy<idx> where <idx> is printed |
@@ -193,7 +230,7 @@ int cfg80211_dev_rename(struct cfg80211_registered_device *rdev, | |||
193 | 230 | ||
194 | result = 0; | 231 | result = 0; |
195 | out_unlock: | 232 | out_unlock: |
196 | mutex_unlock(&cfg80211_drv_mutex); | 233 | mutex_unlock(&cfg80211_mutex); |
197 | if (result == 0) | 234 | if (result == 0) |
198 | nl80211_notify_dev_rename(rdev); | 235 | nl80211_notify_dev_rename(rdev); |
199 | 236 | ||
@@ -220,22 +257,22 @@ struct wiphy *wiphy_new(struct cfg80211_ops *ops, int sizeof_priv) | |||
220 | 257 | ||
221 | drv->ops = ops; | 258 | drv->ops = ops; |
222 | 259 | ||
223 | mutex_lock(&cfg80211_drv_mutex); | 260 | mutex_lock(&cfg80211_mutex); |
224 | 261 | ||
225 | drv->idx = wiphy_counter++; | 262 | drv->wiphy_idx = wiphy_counter++; |
226 | 263 | ||
227 | if (unlikely(drv->idx < 0)) { | 264 | if (unlikely(!wiphy_idx_valid(drv->wiphy_idx))) { |
228 | wiphy_counter--; | 265 | wiphy_counter--; |
229 | mutex_unlock(&cfg80211_drv_mutex); | 266 | mutex_unlock(&cfg80211_mutex); |
230 | /* ugh, wrapped! */ | 267 | /* ugh, wrapped! */ |
231 | kfree(drv); | 268 | kfree(drv); |
232 | return NULL; | 269 | return NULL; |
233 | } | 270 | } |
234 | 271 | ||
235 | mutex_unlock(&cfg80211_drv_mutex); | 272 | mutex_unlock(&cfg80211_mutex); |
236 | 273 | ||
237 | /* give it a proper name */ | 274 | /* give it a proper name */ |
238 | dev_set_name(&drv->wiphy.dev, PHY_NAME "%d", drv->idx); | 275 | dev_set_name(&drv->wiphy.dev, PHY_NAME "%d", drv->wiphy_idx); |
239 | 276 | ||
240 | mutex_init(&drv->mtx); | 277 | mutex_init(&drv->mtx); |
241 | mutex_init(&drv->devlist_mtx); | 278 | mutex_init(&drv->devlist_mtx); |
@@ -310,7 +347,7 @@ int wiphy_register(struct wiphy *wiphy) | |||
310 | /* check and set up bitrates */ | 347 | /* check and set up bitrates */ |
311 | ieee80211_set_bitrate_flags(wiphy); | 348 | ieee80211_set_bitrate_flags(wiphy); |
312 | 349 | ||
313 | mutex_lock(&cfg80211_drv_mutex); | 350 | mutex_lock(&cfg80211_mutex); |
314 | 351 | ||
315 | /* set up regulatory info */ | 352 | /* set up regulatory info */ |
316 | wiphy_update_regulatory(wiphy, REGDOM_SET_BY_CORE); | 353 | wiphy_update_regulatory(wiphy, REGDOM_SET_BY_CORE); |
@@ -330,7 +367,7 @@ int wiphy_register(struct wiphy *wiphy) | |||
330 | 367 | ||
331 | res = 0; | 368 | res = 0; |
332 | out_unlock: | 369 | out_unlock: |
333 | mutex_unlock(&cfg80211_drv_mutex); | 370 | mutex_unlock(&cfg80211_mutex); |
334 | return res; | 371 | return res; |
335 | } | 372 | } |
336 | EXPORT_SYMBOL(wiphy_register); | 373 | EXPORT_SYMBOL(wiphy_register); |
@@ -340,7 +377,7 @@ void wiphy_unregister(struct wiphy *wiphy) | |||
340 | struct cfg80211_registered_device *drv = wiphy_to_dev(wiphy); | 377 | struct cfg80211_registered_device *drv = wiphy_to_dev(wiphy); |
341 | 378 | ||
342 | /* protect the device list */ | 379 | /* protect the device list */ |
343 | mutex_lock(&cfg80211_drv_mutex); | 380 | mutex_lock(&cfg80211_mutex); |
344 | 381 | ||
345 | BUG_ON(!list_empty(&drv->netdev_list)); | 382 | BUG_ON(!list_empty(&drv->netdev_list)); |
346 | 383 | ||
@@ -366,7 +403,7 @@ void wiphy_unregister(struct wiphy *wiphy) | |||
366 | device_del(&drv->wiphy.dev); | 403 | device_del(&drv->wiphy.dev); |
367 | debugfs_remove(drv->wiphy.debugfsdir); | 404 | debugfs_remove(drv->wiphy.debugfsdir); |
368 | 405 | ||
369 | mutex_unlock(&cfg80211_drv_mutex); | 406 | mutex_unlock(&cfg80211_mutex); |
370 | } | 407 | } |
371 | EXPORT_SYMBOL(wiphy_unregister); | 408 | EXPORT_SYMBOL(wiphy_unregister); |
372 | 409 | ||
diff --git a/net/wireless/core.h b/net/wireless/core.h index e29ad4cd464f..f6c53f5807f4 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h | |||
@@ -10,6 +10,7 @@ | |||
10 | #include <linux/netdevice.h> | 10 | #include <linux/netdevice.h> |
11 | #include <linux/kref.h> | 11 | #include <linux/kref.h> |
12 | #include <linux/rbtree.h> | 12 | #include <linux/rbtree.h> |
13 | #include <linux/mutex.h> | ||
13 | #include <net/genetlink.h> | 14 | #include <net/genetlink.h> |
14 | #include <net/wireless.h> | 15 | #include <net/wireless.h> |
15 | #include <net/cfg80211.h> | 16 | #include <net/cfg80211.h> |
@@ -37,7 +38,7 @@ struct cfg80211_registered_device { | |||
37 | enum environment_cap env; | 38 | enum environment_cap env; |
38 | 39 | ||
39 | /* wiphy index, internal only */ | 40 | /* wiphy index, internal only */ |
40 | int idx; | 41 | int wiphy_idx; |
41 | 42 | ||
42 | /* associate netdev list */ | 43 | /* associate netdev list */ |
43 | struct mutex devlist_mtx; | 44 | struct mutex devlist_mtx; |
@@ -49,6 +50,7 @@ struct cfg80211_registered_device { | |||
49 | struct rb_root bss_tree; | 50 | struct rb_root bss_tree; |
50 | u32 bss_generation; | 51 | u32 bss_generation; |
51 | struct cfg80211_scan_request *scan_req; /* protected by RTNL */ | 52 | struct cfg80211_scan_request *scan_req; /* protected by RTNL */ |
53 | unsigned long suspend_at; | ||
52 | 54 | ||
53 | /* must be last because of the way we do wiphy_priv(), | 55 | /* must be last because of the way we do wiphy_priv(), |
54 | * and it should at least be aligned to NETDEV_ALIGN */ | 56 | * and it should at least be aligned to NETDEV_ALIGN */ |
@@ -62,9 +64,27 @@ struct cfg80211_registered_device *wiphy_to_dev(struct wiphy *wiphy) | |||
62 | return container_of(wiphy, struct cfg80211_registered_device, wiphy); | 64 | return container_of(wiphy, struct cfg80211_registered_device, wiphy); |
63 | } | 65 | } |
64 | 66 | ||
65 | extern struct mutex cfg80211_drv_mutex; | 67 | /* Note 0 is valid, hence phy0 */ |
68 | static inline | ||
69 | bool wiphy_idx_valid(int wiphy_idx) | ||
70 | { | ||
71 | return (wiphy_idx >= 0); | ||
72 | } | ||
73 | |||
74 | extern struct mutex cfg80211_mutex; | ||
66 | extern struct list_head cfg80211_drv_list; | 75 | extern struct list_head cfg80211_drv_list; |
67 | 76 | ||
77 | static inline void assert_cfg80211_lock(void) | ||
78 | { | ||
79 | WARN_ON(!mutex_is_locked(&cfg80211_mutex)); | ||
80 | } | ||
81 | |||
82 | /* | ||
83 | * You can use this to mark a wiphy_idx as not having an associated wiphy. | ||
84 | * It guarantees cfg80211_drv_by_wiphy_idx(wiphy_idx) will return NULL | ||
85 | */ | ||
86 | #define WIPHY_IDX_STALE -1 | ||
87 | |||
68 | struct cfg80211_internal_bss { | 88 | struct cfg80211_internal_bss { |
69 | struct list_head list; | 89 | struct list_head list; |
70 | struct rb_node rbn; | 90 | struct rb_node rbn; |
@@ -74,6 +94,9 @@ struct cfg80211_internal_bss { | |||
74 | struct cfg80211_bss pub; | 94 | struct cfg80211_bss pub; |
75 | }; | 95 | }; |
76 | 96 | ||
97 | struct cfg80211_registered_device *cfg80211_drv_by_wiphy_idx(int wiphy_idx); | ||
98 | int get_wiphy_idx(struct wiphy *wiphy); | ||
99 | |||
77 | /* | 100 | /* |
78 | * This function returns a pointer to the driver | 101 | * This function returns a pointer to the driver |
79 | * that the genl_info item that is passed refers to. | 102 | * that the genl_info item that is passed refers to. |
@@ -81,13 +104,13 @@ struct cfg80211_internal_bss { | |||
81 | * the driver's mutex! | 104 | * the driver's mutex! |
82 | * | 105 | * |
83 | * This means that you need to call cfg80211_put_dev() | 106 | * This means that you need to call cfg80211_put_dev() |
84 | * before being allowed to acquire &cfg80211_drv_mutex! | 107 | * before being allowed to acquire &cfg80211_mutex! |
85 | * | 108 | * |
86 | * This is necessary because we need to lock the global | 109 | * This is necessary because we need to lock the global |
87 | * mutex to get an item off the list safely, and then | 110 | * mutex to get an item off the list safely, and then |
88 | * we lock the drv mutex so it doesn't go away under us. | 111 | * we lock the drv mutex so it doesn't go away under us. |
89 | * | 112 | * |
90 | * We don't want to keep cfg80211_drv_mutex locked | 113 | * We don't want to keep cfg80211_mutex locked |
91 | * for all the time in order to allow requests on | 114 | * for all the time in order to allow requests on |
92 | * other interfaces to go through at the same time. | 115 | * other interfaces to go through at the same time. |
93 | * | 116 | * |
@@ -97,6 +120,9 @@ struct cfg80211_internal_bss { | |||
97 | extern struct cfg80211_registered_device * | 120 | extern struct cfg80211_registered_device * |
98 | cfg80211_get_dev_from_info(struct genl_info *info); | 121 | cfg80211_get_dev_from_info(struct genl_info *info); |
99 | 122 | ||
123 | /* requires cfg80211_drv_mutex to be held! */ | ||
124 | struct wiphy *wiphy_idx_to_wiphy(int wiphy_idx); | ||
125 | |||
100 | /* identical to cfg80211_get_dev_from_info but only operate on ifindex */ | 126 | /* identical to cfg80211_get_dev_from_info but only operate on ifindex */ |
101 | extern struct cfg80211_registered_device * | 127 | extern struct cfg80211_registered_device * |
102 | cfg80211_get_dev_from_ifindex(int ifindex); | 128 | cfg80211_get_dev_from_ifindex(int ifindex); |
@@ -113,5 +139,7 @@ void ieee80211_set_bitrate_flags(struct wiphy *wiphy); | |||
113 | void wiphy_update_regulatory(struct wiphy *wiphy, enum reg_set_by setby); | 139 | void wiphy_update_regulatory(struct wiphy *wiphy, enum reg_set_by setby); |
114 | 140 | ||
115 | void cfg80211_bss_expire(struct cfg80211_registered_device *dev); | 141 | void cfg80211_bss_expire(struct cfg80211_registered_device *dev); |
142 | void cfg80211_bss_age(struct cfg80211_registered_device *dev, | ||
143 | unsigned long age_secs); | ||
116 | 144 | ||
117 | #endif /* __NET_WIRELESS_CORE_H */ | 145 | #endif /* __NET_WIRELESS_CORE_H */ |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 298a4de59948..531bb67cf502 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -7,7 +7,6 @@ | |||
7 | #include <linux/if.h> | 7 | #include <linux/if.h> |
8 | #include <linux/module.h> | 8 | #include <linux/module.h> |
9 | #include <linux/err.h> | 9 | #include <linux/err.h> |
10 | #include <linux/mutex.h> | ||
11 | #include <linux/list.h> | 10 | #include <linux/list.h> |
12 | #include <linux/if_ether.h> | 11 | #include <linux/if_ether.h> |
13 | #include <linux/ieee80211.h> | 12 | #include <linux/ieee80211.h> |
@@ -142,7 +141,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
142 | if (!hdr) | 141 | if (!hdr) |
143 | return -1; | 142 | return -1; |
144 | 143 | ||
145 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, dev->idx); | 144 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, dev->wiphy_idx); |
146 | NLA_PUT_STRING(msg, NL80211_ATTR_WIPHY_NAME, wiphy_name(&dev->wiphy)); | 145 | NLA_PUT_STRING(msg, NL80211_ATTR_WIPHY_NAME, wiphy_name(&dev->wiphy)); |
147 | NLA_PUT_U8(msg, NL80211_ATTR_MAX_NUM_SCAN_SSIDS, | 146 | NLA_PUT_U8(msg, NL80211_ATTR_MAX_NUM_SCAN_SSIDS, |
148 | dev->wiphy.max_scan_ssids); | 147 | dev->wiphy.max_scan_ssids); |
@@ -256,7 +255,7 @@ static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb) | |||
256 | int start = cb->args[0]; | 255 | int start = cb->args[0]; |
257 | struct cfg80211_registered_device *dev; | 256 | struct cfg80211_registered_device *dev; |
258 | 257 | ||
259 | mutex_lock(&cfg80211_drv_mutex); | 258 | mutex_lock(&cfg80211_mutex); |
260 | list_for_each_entry(dev, &cfg80211_drv_list, list) { | 259 | list_for_each_entry(dev, &cfg80211_drv_list, list) { |
261 | if (++idx <= start) | 260 | if (++idx <= start) |
262 | continue; | 261 | continue; |
@@ -267,7 +266,7 @@ static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb) | |||
267 | break; | 266 | break; |
268 | } | 267 | } |
269 | } | 268 | } |
270 | mutex_unlock(&cfg80211_drv_mutex); | 269 | mutex_unlock(&cfg80211_mutex); |
271 | 270 | ||
272 | cb->args[0] = idx; | 271 | cb->args[0] = idx; |
273 | 272 | ||
@@ -470,7 +469,7 @@ static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback * | |||
470 | struct cfg80211_registered_device *dev; | 469 | struct cfg80211_registered_device *dev; |
471 | struct wireless_dev *wdev; | 470 | struct wireless_dev *wdev; |
472 | 471 | ||
473 | mutex_lock(&cfg80211_drv_mutex); | 472 | mutex_lock(&cfg80211_mutex); |
474 | list_for_each_entry(dev, &cfg80211_drv_list, list) { | 473 | list_for_each_entry(dev, &cfg80211_drv_list, list) { |
475 | if (wp_idx < wp_start) { | 474 | if (wp_idx < wp_start) { |
476 | wp_idx++; | 475 | wp_idx++; |
@@ -497,7 +496,7 @@ static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback * | |||
497 | wp_idx++; | 496 | wp_idx++; |
498 | } | 497 | } |
499 | out: | 498 | out: |
500 | mutex_unlock(&cfg80211_drv_mutex); | 499 | mutex_unlock(&cfg80211_mutex); |
501 | 500 | ||
502 | cb->args[0] = wp_idx; | 501 | cb->args[0] = wp_idx; |
503 | cb->args[1] = if_idx; | 502 | cb->args[1] = if_idx; |
@@ -1206,6 +1205,12 @@ static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq, | |||
1206 | 1205 | ||
1207 | nla_nest_end(msg, txrate); | 1206 | nla_nest_end(msg, txrate); |
1208 | } | 1207 | } |
1208 | if (sinfo->filled & STATION_INFO_RX_PACKETS) | ||
1209 | NLA_PUT_U32(msg, NL80211_STA_INFO_RX_PACKETS, | ||
1210 | sinfo->rx_packets); | ||
1211 | if (sinfo->filled & STATION_INFO_TX_PACKETS) | ||
1212 | NLA_PUT_U32(msg, NL80211_STA_INFO_TX_PACKETS, | ||
1213 | sinfo->tx_packets); | ||
1209 | nla_nest_end(msg, sinfoattr); | 1214 | nla_nest_end(msg, sinfoattr); |
1210 | 1215 | ||
1211 | return genlmsg_end(msg, hdr); | 1216 | return genlmsg_end(msg, hdr); |
@@ -1900,6 +1905,19 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info) | |||
1900 | int r; | 1905 | int r; |
1901 | char *data = NULL; | 1906 | char *data = NULL; |
1902 | 1907 | ||
1908 | /* | ||
1909 | * You should only get this when cfg80211 hasn't yet initialized | ||
1910 | * completely when built-in to the kernel right between the time | ||
1911 | * window between nl80211_init() and regulatory_init(), if that is | ||
1912 | * even possible. | ||
1913 | */ | ||
1914 | mutex_lock(&cfg80211_mutex); | ||
1915 | if (unlikely(!cfg80211_regdomain)) { | ||
1916 | mutex_unlock(&cfg80211_mutex); | ||
1917 | return -EINPROGRESS; | ||
1918 | } | ||
1919 | mutex_unlock(&cfg80211_mutex); | ||
1920 | |||
1903 | if (!info->attrs[NL80211_ATTR_REG_ALPHA2]) | 1921 | if (!info->attrs[NL80211_ATTR_REG_ALPHA2]) |
1904 | return -EINVAL; | 1922 | return -EINVAL; |
1905 | 1923 | ||
@@ -1910,14 +1928,9 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info) | |||
1910 | if (is_world_regdom(data)) | 1928 | if (is_world_regdom(data)) |
1911 | return -EINVAL; | 1929 | return -EINVAL; |
1912 | #endif | 1930 | #endif |
1913 | mutex_lock(&cfg80211_drv_mutex); | 1931 | |
1914 | r = __regulatory_hint(NULL, REGDOM_SET_BY_USER, data, 0, ENVIRON_ANY); | 1932 | r = regulatory_hint_user(data); |
1915 | mutex_unlock(&cfg80211_drv_mutex); | 1933 | |
1916 | /* This means the regulatory domain was already set, however | ||
1917 | * we don't want to confuse userspace with a "successful error" | ||
1918 | * message so lets just treat it as a success */ | ||
1919 | if (r == -EALREADY) | ||
1920 | r = 0; | ||
1921 | return r; | 1934 | return r; |
1922 | } | 1935 | } |
1923 | 1936 | ||
@@ -2106,7 +2119,7 @@ static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info) | |||
2106 | unsigned int i; | 2119 | unsigned int i; |
2107 | int err = -EINVAL; | 2120 | int err = -EINVAL; |
2108 | 2121 | ||
2109 | mutex_lock(&cfg80211_drv_mutex); | 2122 | mutex_lock(&cfg80211_mutex); |
2110 | 2123 | ||
2111 | if (!cfg80211_regdomain) | 2124 | if (!cfg80211_regdomain) |
2112 | goto out; | 2125 | goto out; |
@@ -2169,7 +2182,7 @@ nla_put_failure: | |||
2169 | genlmsg_cancel(msg, hdr); | 2182 | genlmsg_cancel(msg, hdr); |
2170 | err = -EMSGSIZE; | 2183 | err = -EMSGSIZE; |
2171 | out: | 2184 | out: |
2172 | mutex_unlock(&cfg80211_drv_mutex); | 2185 | mutex_unlock(&cfg80211_mutex); |
2173 | return err; | 2186 | return err; |
2174 | } | 2187 | } |
2175 | 2188 | ||
@@ -2228,9 +2241,9 @@ static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info) | |||
2228 | 2241 | ||
2229 | BUG_ON(rule_idx != num_rules); | 2242 | BUG_ON(rule_idx != num_rules); |
2230 | 2243 | ||
2231 | mutex_lock(&cfg80211_drv_mutex); | 2244 | mutex_lock(&cfg80211_mutex); |
2232 | r = set_regdom(rd); | 2245 | r = set_regdom(rd); |
2233 | mutex_unlock(&cfg80211_drv_mutex); | 2246 | mutex_unlock(&cfg80211_mutex); |
2234 | return r; | 2247 | return r; |
2235 | 2248 | ||
2236 | bad_reg: | 2249 | bad_reg: |
@@ -2286,6 +2299,7 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | |||
2286 | struct wiphy *wiphy; | 2299 | struct wiphy *wiphy; |
2287 | int err, tmp, n_ssids = 0, n_channels = 0, i; | 2300 | int err, tmp, n_ssids = 0, n_channels = 0, i; |
2288 | enum ieee80211_band band; | 2301 | enum ieee80211_band band; |
2302 | size_t ie_len; | ||
2289 | 2303 | ||
2290 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | 2304 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
2291 | if (err) | 2305 | if (err) |
@@ -2327,9 +2341,15 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | |||
2327 | goto out_unlock; | 2341 | goto out_unlock; |
2328 | } | 2342 | } |
2329 | 2343 | ||
2344 | if (info->attrs[NL80211_ATTR_IE]) | ||
2345 | ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); | ||
2346 | else | ||
2347 | ie_len = 0; | ||
2348 | |||
2330 | request = kzalloc(sizeof(*request) | 2349 | request = kzalloc(sizeof(*request) |
2331 | + sizeof(*ssid) * n_ssids | 2350 | + sizeof(*ssid) * n_ssids |
2332 | + sizeof(channel) * n_channels, GFP_KERNEL); | 2351 | + sizeof(channel) * n_channels |
2352 | + ie_len, GFP_KERNEL); | ||
2333 | if (!request) { | 2353 | if (!request) { |
2334 | err = -ENOMEM; | 2354 | err = -ENOMEM; |
2335 | goto out_unlock; | 2355 | goto out_unlock; |
@@ -2340,6 +2360,12 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | |||
2340 | if (n_ssids) | 2360 | if (n_ssids) |
2341 | request->ssids = (void *)(request->channels + n_channels); | 2361 | request->ssids = (void *)(request->channels + n_channels); |
2342 | request->n_ssids = n_ssids; | 2362 | request->n_ssids = n_ssids; |
2363 | if (ie_len) { | ||
2364 | if (request->ssids) | ||
2365 | request->ie = (void *)(request->ssids + n_ssids); | ||
2366 | else | ||
2367 | request->ie = (void *)(request->channels + n_channels); | ||
2368 | } | ||
2343 | 2369 | ||
2344 | if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) { | 2370 | if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) { |
2345 | /* user specified, bail out if channel not found */ | 2371 | /* user specified, bail out if channel not found */ |
@@ -2380,6 +2406,12 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | |||
2380 | } | 2406 | } |
2381 | } | 2407 | } |
2382 | 2408 | ||
2409 | if (info->attrs[NL80211_ATTR_IE]) { | ||
2410 | request->ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); | ||
2411 | memcpy(request->ie, nla_data(info->attrs[NL80211_ATTR_IE]), | ||
2412 | request->ie_len); | ||
2413 | } | ||
2414 | |||
2383 | request->ifidx = dev->ifindex; | 2415 | request->ifidx = dev->ifindex; |
2384 | request->wiphy = &drv->wiphy; | 2416 | request->wiphy = &drv->wiphy; |
2385 | 2417 | ||
@@ -2432,7 +2464,7 @@ static int nl80211_send_bss(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
2432 | NLA_PUT_U16(msg, NL80211_BSS_CAPABILITY, res->capability); | 2464 | NLA_PUT_U16(msg, NL80211_BSS_CAPABILITY, res->capability); |
2433 | NLA_PUT_U32(msg, NL80211_BSS_FREQUENCY, res->channel->center_freq); | 2465 | NLA_PUT_U32(msg, NL80211_BSS_FREQUENCY, res->channel->center_freq); |
2434 | 2466 | ||
2435 | switch (res->signal_type) { | 2467 | switch (rdev->wiphy.signal_type) { |
2436 | case CFG80211_SIGNAL_TYPE_MBM: | 2468 | case CFG80211_SIGNAL_TYPE_MBM: |
2437 | NLA_PUT_U32(msg, NL80211_BSS_SIGNAL_MBM, res->signal); | 2469 | NLA_PUT_U32(msg, NL80211_BSS_SIGNAL_MBM, res->signal); |
2438 | break; | 2470 | break; |
@@ -2601,7 +2633,6 @@ static struct genl_ops nl80211_ops[] = { | |||
2601 | .doit = nl80211_get_station, | 2633 | .doit = nl80211_get_station, |
2602 | .dumpit = nl80211_dump_station, | 2634 | .dumpit = nl80211_dump_station, |
2603 | .policy = nl80211_policy, | 2635 | .policy = nl80211_policy, |
2604 | .flags = GENL_ADMIN_PERM, | ||
2605 | }, | 2636 | }, |
2606 | { | 2637 | { |
2607 | .cmd = NL80211_CMD_SET_STATION, | 2638 | .cmd = NL80211_CMD_SET_STATION, |
@@ -2739,7 +2770,7 @@ static int nl80211_send_scan_donemsg(struct sk_buff *msg, | |||
2739 | if (!hdr) | 2770 | if (!hdr) |
2740 | return -1; | 2771 | return -1; |
2741 | 2772 | ||
2742 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->idx); | 2773 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); |
2743 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); | 2774 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); |
2744 | 2775 | ||
2745 | /* XXX: we should probably bounce back the request? */ | 2776 | /* XXX: we should probably bounce back the request? */ |
diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h index b565a5f84e97..69787b621365 100644 --- a/net/wireless/nl80211.h +++ b/net/wireless/nl80211.h | |||
@@ -27,6 +27,10 @@ static inline void | |||
27 | nl80211_send_scan_done(struct cfg80211_registered_device *rdev, | 27 | nl80211_send_scan_done(struct cfg80211_registered_device *rdev, |
28 | struct net_device *netdev) | 28 | struct net_device *netdev) |
29 | {} | 29 | {} |
30 | static inline void nl80211_send_scan_aborted( | ||
31 | struct cfg80211_registered_device *rdev, | ||
32 | struct net_device *netdev) | ||
33 | {} | ||
30 | #endif /* CONFIG_NL80211 */ | 34 | #endif /* CONFIG_NL80211 */ |
31 | 35 | ||
32 | #endif /* __NET_WIRELESS_NL80211_H */ | 36 | #endif /* __NET_WIRELESS_NL80211_H */ |
diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 2323644330cd..ce66bfdf57ec 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c | |||
@@ -54,22 +54,52 @@ static u32 supported_bandwidths[] = { | |||
54 | MHZ_TO_KHZ(20), | 54 | MHZ_TO_KHZ(20), |
55 | }; | 55 | }; |
56 | 56 | ||
57 | /* Central wireless core regulatory domains, we only need two, | 57 | /* |
58 | * Central wireless core regulatory domains, we only need two, | ||
58 | * the current one and a world regulatory domain in case we have no | 59 | * the current one and a world regulatory domain in case we have no |
59 | * information to give us an alpha2 */ | 60 | * information to give us an alpha2 |
61 | */ | ||
60 | const struct ieee80211_regdomain *cfg80211_regdomain; | 62 | const struct ieee80211_regdomain *cfg80211_regdomain; |
61 | 63 | ||
62 | /* We use this as a place for the rd structure built from the | 64 | /* |
65 | * We use this as a place for the rd structure built from the | ||
63 | * last parsed country IE to rest until CRDA gets back to us with | 66 | * last parsed country IE to rest until CRDA gets back to us with |
64 | * what it thinks should apply for the same country */ | 67 | * what it thinks should apply for the same country |
68 | */ | ||
65 | static const struct ieee80211_regdomain *country_ie_regdomain; | 69 | static const struct ieee80211_regdomain *country_ie_regdomain; |
66 | 70 | ||
71 | /* Used to queue up regulatory hints */ | ||
72 | static LIST_HEAD(reg_requests_list); | ||
73 | static spinlock_t reg_requests_lock; | ||
74 | |||
75 | /* Used to queue up beacon hints for review */ | ||
76 | static LIST_HEAD(reg_pending_beacons); | ||
77 | static spinlock_t reg_pending_beacons_lock; | ||
78 | |||
79 | /* Used to keep track of processed beacon hints */ | ||
80 | static LIST_HEAD(reg_beacon_list); | ||
81 | |||
82 | struct reg_beacon { | ||
83 | struct list_head list; | ||
84 | struct ieee80211_channel chan; | ||
85 | }; | ||
86 | |||
67 | /* We keep a static world regulatory domain in case of the absence of CRDA */ | 87 | /* We keep a static world regulatory domain in case of the absence of CRDA */ |
68 | static const struct ieee80211_regdomain world_regdom = { | 88 | static const struct ieee80211_regdomain world_regdom = { |
69 | .n_reg_rules = 1, | 89 | .n_reg_rules = 3, |
70 | .alpha2 = "00", | 90 | .alpha2 = "00", |
71 | .reg_rules = { | 91 | .reg_rules = { |
72 | REG_RULE(2412-10, 2462+10, 40, 6, 20, | 92 | /* IEEE 802.11b/g, channels 1..11 */ |
93 | REG_RULE(2412-10, 2462+10, 40, 6, 20, 0), | ||
94 | /* IEEE 802.11a, channel 36..48 */ | ||
95 | REG_RULE(5180-10, 5240+10, 40, 6, 23, | ||
96 | NL80211_RRF_PASSIVE_SCAN | | ||
97 | NL80211_RRF_NO_IBSS), | ||
98 | |||
99 | /* NB: 5260 MHz - 5700 MHz requies DFS */ | ||
100 | |||
101 | /* IEEE 802.11a, channel 149..165 */ | ||
102 | REG_RULE(5745-10, 5825+10, 40, 6, 23, | ||
73 | NL80211_RRF_PASSIVE_SCAN | | 103 | NL80211_RRF_PASSIVE_SCAN | |
74 | NL80211_RRF_NO_IBSS), | 104 | NL80211_RRF_NO_IBSS), |
75 | } | 105 | } |
@@ -83,9 +113,11 @@ static char *ieee80211_regdom = "US"; | |||
83 | module_param(ieee80211_regdom, charp, 0444); | 113 | module_param(ieee80211_regdom, charp, 0444); |
84 | MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code"); | 114 | MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code"); |
85 | 115 | ||
86 | /* We assume 40 MHz bandwidth for the old regulatory work. | 116 | /* |
117 | * We assume 40 MHz bandwidth for the old regulatory work. | ||
87 | * We make emphasis we are using the exact same frequencies | 118 | * We make emphasis we are using the exact same frequencies |
88 | * as before */ | 119 | * as before |
120 | */ | ||
89 | 121 | ||
90 | static const struct ieee80211_regdomain us_regdom = { | 122 | static const struct ieee80211_regdomain us_regdom = { |
91 | .n_reg_rules = 6, | 123 | .n_reg_rules = 6, |
@@ -124,8 +156,10 @@ static const struct ieee80211_regdomain jp_regdom = { | |||
124 | 156 | ||
125 | static const struct ieee80211_regdomain eu_regdom = { | 157 | static const struct ieee80211_regdomain eu_regdom = { |
126 | .n_reg_rules = 6, | 158 | .n_reg_rules = 6, |
127 | /* This alpha2 is bogus, we leave it here just for stupid | 159 | /* |
128 | * backward compatibility */ | 160 | * This alpha2 is bogus, we leave it here just for stupid |
161 | * backward compatibility | ||
162 | */ | ||
129 | .alpha2 = "EU", | 163 | .alpha2 = "EU", |
130 | .reg_rules = { | 164 | .reg_rules = { |
131 | /* IEEE 802.11b/g, channels 1..13 */ | 165 | /* IEEE 802.11b/g, channels 1..13 */ |
@@ -194,8 +228,10 @@ static void reset_regdomains(void) | |||
194 | cfg80211_regdomain = NULL; | 228 | cfg80211_regdomain = NULL; |
195 | } | 229 | } |
196 | 230 | ||
197 | /* Dynamic world regulatory domain requested by the wireless | 231 | /* |
198 | * core upon initialization */ | 232 | * Dynamic world regulatory domain requested by the wireless |
233 | * core upon initialization | ||
234 | */ | ||
199 | static void update_world_regdomain(const struct ieee80211_regdomain *rd) | 235 | static void update_world_regdomain(const struct ieee80211_regdomain *rd) |
200 | { | 236 | { |
201 | BUG_ON(!last_request); | 237 | BUG_ON(!last_request); |
@@ -236,8 +272,10 @@ static bool is_unknown_alpha2(const char *alpha2) | |||
236 | { | 272 | { |
237 | if (!alpha2) | 273 | if (!alpha2) |
238 | return false; | 274 | return false; |
239 | /* Special case where regulatory domain was built by driver | 275 | /* |
240 | * but a specific alpha2 cannot be determined */ | 276 | * Special case where regulatory domain was built by driver |
277 | * but a specific alpha2 cannot be determined | ||
278 | */ | ||
241 | if (alpha2[0] == '9' && alpha2[1] == '9') | 279 | if (alpha2[0] == '9' && alpha2[1] == '9') |
242 | return true; | 280 | return true; |
243 | return false; | 281 | return false; |
@@ -247,9 +285,11 @@ static bool is_intersected_alpha2(const char *alpha2) | |||
247 | { | 285 | { |
248 | if (!alpha2) | 286 | if (!alpha2) |
249 | return false; | 287 | return false; |
250 | /* Special case where regulatory domain is the | 288 | /* |
289 | * Special case where regulatory domain is the | ||
251 | * result of an intersection between two regulatory domain | 290 | * result of an intersection between two regulatory domain |
252 | * structures */ | 291 | * structures |
292 | */ | ||
253 | if (alpha2[0] == '9' && alpha2[1] == '8') | 293 | if (alpha2[0] == '9' && alpha2[1] == '8') |
254 | return true; | 294 | return true; |
255 | return false; | 295 | return false; |
@@ -274,8 +314,10 @@ static bool alpha2_equal(const char *alpha2_x, const char *alpha2_y) | |||
274 | return false; | 314 | return false; |
275 | } | 315 | } |
276 | 316 | ||
277 | static bool regdom_changed(const char *alpha2) | 317 | static bool regdom_changes(const char *alpha2) |
278 | { | 318 | { |
319 | assert_cfg80211_lock(); | ||
320 | |||
279 | if (!cfg80211_regdomain) | 321 | if (!cfg80211_regdomain) |
280 | return true; | 322 | return true; |
281 | if (alpha2_equal(cfg80211_regdomain->alpha2, alpha2)) | 323 | if (alpha2_equal(cfg80211_regdomain->alpha2, alpha2)) |
@@ -302,8 +344,10 @@ static bool country_ie_integrity_changes(u32 checksum) | |||
302 | return false; | 344 | return false; |
303 | } | 345 | } |
304 | 346 | ||
305 | /* This lets us keep regulatory code which is updated on a regulatory | 347 | /* |
306 | * basis in userspace. */ | 348 | * This lets us keep regulatory code which is updated on a regulatory |
349 | * basis in userspace. | ||
350 | */ | ||
307 | static int call_crda(const char *alpha2) | 351 | static int call_crda(const char *alpha2) |
308 | { | 352 | { |
309 | char country_env[9 + 2] = "COUNTRY="; | 353 | char country_env[9 + 2] = "COUNTRY="; |
@@ -414,10 +458,12 @@ static bool freq_in_rule_band(const struct ieee80211_freq_range *freq_range, | |||
414 | #undef ONE_GHZ_IN_KHZ | 458 | #undef ONE_GHZ_IN_KHZ |
415 | } | 459 | } |
416 | 460 | ||
417 | /* Converts a country IE to a regulatory domain. A regulatory domain | 461 | /* |
462 | * Converts a country IE to a regulatory domain. A regulatory domain | ||
418 | * structure has a lot of information which the IE doesn't yet have, | 463 | * structure has a lot of information which the IE doesn't yet have, |
419 | * so for the other values we use upper max values as we will intersect | 464 | * so for the other values we use upper max values as we will intersect |
420 | * with our userspace regulatory agent to get lower bounds. */ | 465 | * with our userspace regulatory agent to get lower bounds. |
466 | */ | ||
421 | static struct ieee80211_regdomain *country_ie_2_rd( | 467 | static struct ieee80211_regdomain *country_ie_2_rd( |
422 | u8 *country_ie, | 468 | u8 *country_ie, |
423 | u8 country_ie_len, | 469 | u8 country_ie_len, |
@@ -462,9 +508,11 @@ static struct ieee80211_regdomain *country_ie_2_rd( | |||
462 | 508 | ||
463 | *checksum ^= ((flags ^ alpha2[0] ^ alpha2[1]) << 8); | 509 | *checksum ^= ((flags ^ alpha2[0] ^ alpha2[1]) << 8); |
464 | 510 | ||
465 | /* We need to build a reg rule for each triplet, but first we must | 511 | /* |
512 | * We need to build a reg rule for each triplet, but first we must | ||
466 | * calculate the number of reg rules we will need. We will need one | 513 | * calculate the number of reg rules we will need. We will need one |
467 | * for each channel subband */ | 514 | * for each channel subband |
515 | */ | ||
468 | while (country_ie_len >= 3) { | 516 | while (country_ie_len >= 3) { |
469 | int end_channel = 0; | 517 | int end_channel = 0; |
470 | struct ieee80211_country_ie_triplet *triplet = | 518 | struct ieee80211_country_ie_triplet *triplet = |
@@ -502,9 +550,11 @@ static struct ieee80211_regdomain *country_ie_2_rd( | |||
502 | if (cur_sub_max_channel < cur_channel) | 550 | if (cur_sub_max_channel < cur_channel) |
503 | return NULL; | 551 | return NULL; |
504 | 552 | ||
505 | /* Do not allow overlapping channels. Also channels | 553 | /* |
554 | * Do not allow overlapping channels. Also channels | ||
506 | * passed in each subband must be monotonically | 555 | * passed in each subband must be monotonically |
507 | * increasing */ | 556 | * increasing |
557 | */ | ||
508 | if (last_sub_max_channel) { | 558 | if (last_sub_max_channel) { |
509 | if (cur_channel <= last_sub_max_channel) | 559 | if (cur_channel <= last_sub_max_channel) |
510 | return NULL; | 560 | return NULL; |
@@ -512,10 +562,12 @@ static struct ieee80211_regdomain *country_ie_2_rd( | |||
512 | return NULL; | 562 | return NULL; |
513 | } | 563 | } |
514 | 564 | ||
515 | /* When dot11RegulatoryClassesRequired is supported | 565 | /* |
566 | * When dot11RegulatoryClassesRequired is supported | ||
516 | * we can throw ext triplets as part of this soup, | 567 | * we can throw ext triplets as part of this soup, |
517 | * for now we don't care when those change as we | 568 | * for now we don't care when those change as we |
518 | * don't support them */ | 569 | * don't support them |
570 | */ | ||
519 | *checksum ^= ((cur_channel ^ cur_sub_max_channel) << 8) | | 571 | *checksum ^= ((cur_channel ^ cur_sub_max_channel) << 8) | |
520 | ((cur_sub_max_channel ^ cur_sub_max_channel) << 16) | | 572 | ((cur_sub_max_channel ^ cur_sub_max_channel) << 16) | |
521 | ((triplet->chans.max_power ^ cur_sub_max_channel) << 24); | 573 | ((triplet->chans.max_power ^ cur_sub_max_channel) << 24); |
@@ -526,8 +578,10 @@ static struct ieee80211_regdomain *country_ie_2_rd( | |||
526 | country_ie_len -= 3; | 578 | country_ie_len -= 3; |
527 | num_rules++; | 579 | num_rules++; |
528 | 580 | ||
529 | /* Note: this is not a IEEE requirement but | 581 | /* |
530 | * simply a memory requirement */ | 582 | * Note: this is not a IEEE requirement but |
583 | * simply a memory requirement | ||
584 | */ | ||
531 | if (num_rules > NL80211_MAX_SUPP_REG_RULES) | 585 | if (num_rules > NL80211_MAX_SUPP_REG_RULES) |
532 | return NULL; | 586 | return NULL; |
533 | } | 587 | } |
@@ -555,8 +609,10 @@ static struct ieee80211_regdomain *country_ie_2_rd( | |||
555 | struct ieee80211_freq_range *freq_range = NULL; | 609 | struct ieee80211_freq_range *freq_range = NULL; |
556 | struct ieee80211_power_rule *power_rule = NULL; | 610 | struct ieee80211_power_rule *power_rule = NULL; |
557 | 611 | ||
558 | /* Must parse if dot11RegulatoryClassesRequired is true, | 612 | /* |
559 | * we don't support this yet */ | 613 | * Must parse if dot11RegulatoryClassesRequired is true, |
614 | * we don't support this yet | ||
615 | */ | ||
560 | if (triplet->ext.reg_extension_id >= | 616 | if (triplet->ext.reg_extension_id >= |
561 | IEEE80211_COUNTRY_EXTENSION_ID) { | 617 | IEEE80211_COUNTRY_EXTENSION_ID) { |
562 | country_ie += 3; | 618 | country_ie += 3; |
@@ -578,10 +634,12 @@ static struct ieee80211_regdomain *country_ie_2_rd( | |||
578 | end_channel = triplet->chans.first_channel + | 634 | end_channel = triplet->chans.first_channel + |
579 | (4 * (triplet->chans.num_channels - 1)); | 635 | (4 * (triplet->chans.num_channels - 1)); |
580 | 636 | ||
581 | /* The +10 is since the regulatory domain expects | 637 | /* |
638 | * The +10 is since the regulatory domain expects | ||
582 | * the actual band edge, not the center of freq for | 639 | * the actual band edge, not the center of freq for |
583 | * its start and end freqs, assuming 20 MHz bandwidth on | 640 | * its start and end freqs, assuming 20 MHz bandwidth on |
584 | * the channels passed */ | 641 | * the channels passed |
642 | */ | ||
585 | freq_range->start_freq_khz = | 643 | freq_range->start_freq_khz = |
586 | MHZ_TO_KHZ(ieee80211_channel_to_frequency( | 644 | MHZ_TO_KHZ(ieee80211_channel_to_frequency( |
587 | triplet->chans.first_channel) - 10); | 645 | triplet->chans.first_channel) - 10); |
@@ -589,9 +647,11 @@ static struct ieee80211_regdomain *country_ie_2_rd( | |||
589 | MHZ_TO_KHZ(ieee80211_channel_to_frequency( | 647 | MHZ_TO_KHZ(ieee80211_channel_to_frequency( |
590 | end_channel) + 10); | 648 | end_channel) + 10); |
591 | 649 | ||
592 | /* Large arbitrary values, we intersect later */ | 650 | /* |
593 | /* Increment this if we ever support >= 40 MHz channels | 651 | * These are large arbitrary values we use to intersect later. |
594 | * in IEEE 802.11 */ | 652 | * Increment this if we ever support >= 40 MHz channels |
653 | * in IEEE 802.11 | ||
654 | */ | ||
595 | freq_range->max_bandwidth_khz = MHZ_TO_KHZ(40); | 655 | freq_range->max_bandwidth_khz = MHZ_TO_KHZ(40); |
596 | power_rule->max_antenna_gain = DBI_TO_MBI(100); | 656 | power_rule->max_antenna_gain = DBI_TO_MBI(100); |
597 | power_rule->max_eirp = DBM_TO_MBM(100); | 657 | power_rule->max_eirp = DBM_TO_MBM(100); |
@@ -607,8 +667,10 @@ static struct ieee80211_regdomain *country_ie_2_rd( | |||
607 | } | 667 | } |
608 | 668 | ||
609 | 669 | ||
610 | /* Helper for regdom_intersect(), this does the real | 670 | /* |
611 | * mathematical intersection fun */ | 671 | * Helper for regdom_intersect(), this does the real |
672 | * mathematical intersection fun | ||
673 | */ | ||
612 | static int reg_rules_intersect( | 674 | static int reg_rules_intersect( |
613 | const struct ieee80211_reg_rule *rule1, | 675 | const struct ieee80211_reg_rule *rule1, |
614 | const struct ieee80211_reg_rule *rule2, | 676 | const struct ieee80211_reg_rule *rule2, |
@@ -686,11 +748,13 @@ static struct ieee80211_regdomain *regdom_intersect( | |||
686 | if (!rd1 || !rd2) | 748 | if (!rd1 || !rd2) |
687 | return NULL; | 749 | return NULL; |
688 | 750 | ||
689 | /* First we get a count of the rules we'll need, then we actually | 751 | /* |
752 | * First we get a count of the rules we'll need, then we actually | ||
690 | * build them. This is to so we can malloc() and free() a | 753 | * build them. This is to so we can malloc() and free() a |
691 | * regdomain once. The reason we use reg_rules_intersect() here | 754 | * regdomain once. The reason we use reg_rules_intersect() here |
692 | * is it will return -EINVAL if the rule computed makes no sense. | 755 | * is it will return -EINVAL if the rule computed makes no sense. |
693 | * All rules that do check out OK are valid. */ | 756 | * All rules that do check out OK are valid. |
757 | */ | ||
694 | 758 | ||
695 | for (x = 0; x < rd1->n_reg_rules; x++) { | 759 | for (x = 0; x < rd1->n_reg_rules; x++) { |
696 | rule1 = &rd1->reg_rules[x]; | 760 | rule1 = &rd1->reg_rules[x]; |
@@ -718,14 +782,18 @@ static struct ieee80211_regdomain *regdom_intersect( | |||
718 | rule1 = &rd1->reg_rules[x]; | 782 | rule1 = &rd1->reg_rules[x]; |
719 | for (y = 0; y < rd2->n_reg_rules; y++) { | 783 | for (y = 0; y < rd2->n_reg_rules; y++) { |
720 | rule2 = &rd2->reg_rules[y]; | 784 | rule2 = &rd2->reg_rules[y]; |
721 | /* This time around instead of using the stack lets | 785 | /* |
786 | * This time around instead of using the stack lets | ||
722 | * write to the target rule directly saving ourselves | 787 | * write to the target rule directly saving ourselves |
723 | * a memcpy() */ | 788 | * a memcpy() |
789 | */ | ||
724 | intersected_rule = &rd->reg_rules[rule_idx]; | 790 | intersected_rule = &rd->reg_rules[rule_idx]; |
725 | r = reg_rules_intersect(rule1, rule2, | 791 | r = reg_rules_intersect(rule1, rule2, |
726 | intersected_rule); | 792 | intersected_rule); |
727 | /* No need to memset here the intersected rule here as | 793 | /* |
728 | * we're not using the stack anymore */ | 794 | * No need to memset here the intersected rule here as |
795 | * we're not using the stack anymore | ||
796 | */ | ||
729 | if (r) | 797 | if (r) |
730 | continue; | 798 | continue; |
731 | rule_idx++; | 799 | rule_idx++; |
@@ -744,8 +812,10 @@ static struct ieee80211_regdomain *regdom_intersect( | |||
744 | return rd; | 812 | return rd; |
745 | } | 813 | } |
746 | 814 | ||
747 | /* XXX: add support for the rest of enum nl80211_reg_rule_flags, we may | 815 | /* |
748 | * want to just have the channel structure use these */ | 816 | * XXX: add support for the rest of enum nl80211_reg_rule_flags, we may |
817 | * want to just have the channel structure use these | ||
818 | */ | ||
749 | static u32 map_regdom_flags(u32 rd_flags) | 819 | static u32 map_regdom_flags(u32 rd_flags) |
750 | { | 820 | { |
751 | u32 channel_flags = 0; | 821 | u32 channel_flags = 0; |
@@ -771,8 +841,10 @@ static int freq_reg_info_regd(struct wiphy *wiphy, | |||
771 | 841 | ||
772 | regd = custom_regd ? custom_regd : cfg80211_regdomain; | 842 | regd = custom_regd ? custom_regd : cfg80211_regdomain; |
773 | 843 | ||
774 | /* Follow the driver's regulatory domain, if present, unless a country | 844 | /* |
775 | * IE has been processed or a user wants to help complaince further */ | 845 | * Follow the driver's regulatory domain, if present, unless a country |
846 | * IE has been processed or a user wants to help complaince further | ||
847 | */ | ||
776 | if (last_request->initiator != REGDOM_SET_BY_COUNTRY_IE && | 848 | if (last_request->initiator != REGDOM_SET_BY_COUNTRY_IE && |
777 | last_request->initiator != REGDOM_SET_BY_USER && | 849 | last_request->initiator != REGDOM_SET_BY_USER && |
778 | wiphy->regd) | 850 | wiphy->regd) |
@@ -790,9 +862,11 @@ static int freq_reg_info_regd(struct wiphy *wiphy, | |||
790 | fr = &rr->freq_range; | 862 | fr = &rr->freq_range; |
791 | pr = &rr->power_rule; | 863 | pr = &rr->power_rule; |
792 | 864 | ||
793 | /* We only need to know if one frequency rule was | 865 | /* |
866 | * We only need to know if one frequency rule was | ||
794 | * was in center_freq's band, that's enough, so lets | 867 | * was in center_freq's band, that's enough, so lets |
795 | * not overwrite it once found */ | 868 | * not overwrite it once found |
869 | */ | ||
796 | if (!band_rule_found) | 870 | if (!band_rule_found) |
797 | band_rule_found = freq_in_rule_band(fr, center_freq); | 871 | band_rule_found = freq_in_rule_band(fr, center_freq); |
798 | 872 | ||
@@ -829,6 +903,11 @@ static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band, | |||
829 | const struct ieee80211_power_rule *power_rule = NULL; | 903 | const struct ieee80211_power_rule *power_rule = NULL; |
830 | struct ieee80211_supported_band *sband; | 904 | struct ieee80211_supported_band *sband; |
831 | struct ieee80211_channel *chan; | 905 | struct ieee80211_channel *chan; |
906 | struct wiphy *request_wiphy = NULL; | ||
907 | |||
908 | assert_cfg80211_lock(); | ||
909 | |||
910 | request_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx); | ||
832 | 911 | ||
833 | sband = wiphy->bands[band]; | 912 | sband = wiphy->bands[band]; |
834 | BUG_ON(chan_idx >= sband->n_channels); | 913 | BUG_ON(chan_idx >= sband->n_channels); |
@@ -840,7 +919,8 @@ static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band, | |||
840 | &max_bandwidth, ®_rule); | 919 | &max_bandwidth, ®_rule); |
841 | 920 | ||
842 | if (r) { | 921 | if (r) { |
843 | /* This means no regulatory rule was found in the country IE | 922 | /* |
923 | * This means no regulatory rule was found in the country IE | ||
844 | * with a frequency range on the center_freq's band, since | 924 | * with a frequency range on the center_freq's band, since |
845 | * IEEE-802.11 allows for a country IE to have a subset of the | 925 | * IEEE-802.11 allows for a country IE to have a subset of the |
846 | * regulatory information provided in a country we ignore | 926 | * regulatory information provided in a country we ignore |
@@ -859,8 +939,10 @@ static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band, | |||
859 | chan->center_freq, wiphy_name(wiphy)); | 939 | chan->center_freq, wiphy_name(wiphy)); |
860 | #endif | 940 | #endif |
861 | } else { | 941 | } else { |
862 | /* In this case we know the country IE has at least one reg rule | 942 | /* |
863 | * for the band so we respect its band definitions */ | 943 | * In this case we know the country IE has at least one reg rule |
944 | * for the band so we respect its band definitions | ||
945 | */ | ||
864 | #ifdef CONFIG_CFG80211_REG_DEBUG | 946 | #ifdef CONFIG_CFG80211_REG_DEBUG |
865 | if (last_request->initiator == REGDOM_SET_BY_COUNTRY_IE) | 947 | if (last_request->initiator == REGDOM_SET_BY_COUNTRY_IE) |
866 | printk(KERN_DEBUG "cfg80211: Disabling " | 948 | printk(KERN_DEBUG "cfg80211: Disabling " |
@@ -877,11 +959,13 @@ static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band, | |||
877 | power_rule = ®_rule->power_rule; | 959 | power_rule = ®_rule->power_rule; |
878 | 960 | ||
879 | if (last_request->initiator == REGDOM_SET_BY_DRIVER && | 961 | if (last_request->initiator == REGDOM_SET_BY_DRIVER && |
880 | last_request->wiphy && last_request->wiphy == wiphy && | 962 | request_wiphy && request_wiphy == wiphy && |
881 | last_request->wiphy->strict_regulatory) { | 963 | request_wiphy->strict_regulatory) { |
882 | /* This gaurantees the driver's requested regulatory domain | 964 | /* |
965 | * This gaurantees the driver's requested regulatory domain | ||
883 | * will always be used as a base for further regulatory | 966 | * will always be used as a base for further regulatory |
884 | * settings */ | 967 | * settings |
968 | */ | ||
885 | chan->flags = chan->orig_flags = | 969 | chan->flags = chan->orig_flags = |
886 | map_regdom_flags(reg_rule->flags); | 970 | map_regdom_flags(reg_rule->flags); |
887 | chan->max_antenna_gain = chan->orig_mag = | 971 | chan->max_antenna_gain = chan->orig_mag = |
@@ -922,8 +1006,10 @@ static bool ignore_reg_update(struct wiphy *wiphy, enum reg_set_by setby) | |||
922 | if (setby == REGDOM_SET_BY_CORE && | 1006 | if (setby == REGDOM_SET_BY_CORE && |
923 | wiphy->custom_regulatory) | 1007 | wiphy->custom_regulatory) |
924 | return true; | 1008 | return true; |
925 | /* wiphy->regd will be set once the device has its own | 1009 | /* |
926 | * desired regulatory domain set */ | 1010 | * wiphy->regd will be set once the device has its own |
1011 | * desired regulatory domain set | ||
1012 | */ | ||
927 | if (wiphy->strict_regulatory && !wiphy->regd && | 1013 | if (wiphy->strict_regulatory && !wiphy->regd && |
928 | !is_world_regdom(last_request->alpha2)) | 1014 | !is_world_regdom(last_request->alpha2)) |
929 | return true; | 1015 | return true; |
@@ -938,16 +1024,120 @@ static void update_all_wiphy_regulatory(enum reg_set_by setby) | |||
938 | wiphy_update_regulatory(&drv->wiphy, setby); | 1024 | wiphy_update_regulatory(&drv->wiphy, setby); |
939 | } | 1025 | } |
940 | 1026 | ||
1027 | static void handle_reg_beacon(struct wiphy *wiphy, | ||
1028 | unsigned int chan_idx, | ||
1029 | struct reg_beacon *reg_beacon) | ||
1030 | { | ||
1031 | #ifdef CONFIG_CFG80211_REG_DEBUG | ||
1032 | #define REG_DEBUG_BEACON_FLAG(desc) \ | ||
1033 | printk(KERN_DEBUG "cfg80211: Enabling " desc " on " \ | ||
1034 | "frequency: %d MHz (Ch %d) on %s\n", \ | ||
1035 | reg_beacon->chan.center_freq, \ | ||
1036 | ieee80211_frequency_to_channel(reg_beacon->chan.center_freq), \ | ||
1037 | wiphy_name(wiphy)); | ||
1038 | #else | ||
1039 | #define REG_DEBUG_BEACON_FLAG(desc) do {} while (0) | ||
1040 | #endif | ||
1041 | struct ieee80211_supported_band *sband; | ||
1042 | struct ieee80211_channel *chan; | ||
1043 | |||
1044 | assert_cfg80211_lock(); | ||
1045 | |||
1046 | sband = wiphy->bands[reg_beacon->chan.band]; | ||
1047 | chan = &sband->channels[chan_idx]; | ||
1048 | |||
1049 | if (likely(chan->center_freq != reg_beacon->chan.center_freq)) | ||
1050 | return; | ||
1051 | |||
1052 | if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN) { | ||
1053 | chan->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN; | ||
1054 | REG_DEBUG_BEACON_FLAG("active scanning"); | ||
1055 | } | ||
1056 | |||
1057 | if (chan->flags & IEEE80211_CHAN_NO_IBSS) { | ||
1058 | chan->flags &= ~IEEE80211_CHAN_NO_IBSS; | ||
1059 | REG_DEBUG_BEACON_FLAG("beaconing"); | ||
1060 | } | ||
1061 | |||
1062 | chan->beacon_found = true; | ||
1063 | #undef REG_DEBUG_BEACON_FLAG | ||
1064 | } | ||
1065 | |||
1066 | /* | ||
1067 | * Called when a scan on a wiphy finds a beacon on | ||
1068 | * new channel | ||
1069 | */ | ||
1070 | static void wiphy_update_new_beacon(struct wiphy *wiphy, | ||
1071 | struct reg_beacon *reg_beacon) | ||
1072 | { | ||
1073 | unsigned int i; | ||
1074 | struct ieee80211_supported_band *sband; | ||
1075 | |||
1076 | assert_cfg80211_lock(); | ||
1077 | |||
1078 | if (!wiphy->bands[reg_beacon->chan.band]) | ||
1079 | return; | ||
1080 | |||
1081 | sband = wiphy->bands[reg_beacon->chan.band]; | ||
1082 | |||
1083 | for (i = 0; i < sband->n_channels; i++) | ||
1084 | handle_reg_beacon(wiphy, i, reg_beacon); | ||
1085 | } | ||
1086 | |||
1087 | /* | ||
1088 | * Called upon reg changes or a new wiphy is added | ||
1089 | */ | ||
1090 | static void wiphy_update_beacon_reg(struct wiphy *wiphy) | ||
1091 | { | ||
1092 | unsigned int i; | ||
1093 | struct ieee80211_supported_band *sband; | ||
1094 | struct reg_beacon *reg_beacon; | ||
1095 | |||
1096 | assert_cfg80211_lock(); | ||
1097 | |||
1098 | if (list_empty(®_beacon_list)) | ||
1099 | return; | ||
1100 | |||
1101 | list_for_each_entry(reg_beacon, ®_beacon_list, list) { | ||
1102 | if (!wiphy->bands[reg_beacon->chan.band]) | ||
1103 | continue; | ||
1104 | sband = wiphy->bands[reg_beacon->chan.band]; | ||
1105 | for (i = 0; i < sband->n_channels; i++) | ||
1106 | handle_reg_beacon(wiphy, i, reg_beacon); | ||
1107 | } | ||
1108 | } | ||
1109 | |||
1110 | static bool reg_is_world_roaming(struct wiphy *wiphy) | ||
1111 | { | ||
1112 | if (is_world_regdom(cfg80211_regdomain->alpha2) || | ||
1113 | (wiphy->regd && is_world_regdom(wiphy->regd->alpha2))) | ||
1114 | return true; | ||
1115 | if (last_request->initiator != REGDOM_SET_BY_COUNTRY_IE && | ||
1116 | wiphy->custom_regulatory) | ||
1117 | return true; | ||
1118 | return false; | ||
1119 | } | ||
1120 | |||
1121 | /* Reap the advantages of previously found beacons */ | ||
1122 | static void reg_process_beacons(struct wiphy *wiphy) | ||
1123 | { | ||
1124 | if (!reg_is_world_roaming(wiphy)) | ||
1125 | return; | ||
1126 | wiphy_update_beacon_reg(wiphy); | ||
1127 | } | ||
1128 | |||
941 | void wiphy_update_regulatory(struct wiphy *wiphy, enum reg_set_by setby) | 1129 | void wiphy_update_regulatory(struct wiphy *wiphy, enum reg_set_by setby) |
942 | { | 1130 | { |
943 | enum ieee80211_band band; | 1131 | enum ieee80211_band band; |
944 | 1132 | ||
945 | if (ignore_reg_update(wiphy, setby)) | 1133 | if (ignore_reg_update(wiphy, setby)) |
946 | return; | 1134 | goto out; |
947 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { | 1135 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { |
948 | if (wiphy->bands[band]) | 1136 | if (wiphy->bands[band]) |
949 | handle_band(wiphy, band); | 1137 | handle_band(wiphy, band); |
950 | } | 1138 | } |
1139 | out: | ||
1140 | reg_process_beacons(wiphy); | ||
951 | if (wiphy->reg_notifier) | 1141 | if (wiphy->reg_notifier) |
952 | wiphy->reg_notifier(wiphy, last_request); | 1142 | wiphy->reg_notifier(wiphy, last_request); |
953 | } | 1143 | } |
@@ -1033,48 +1223,53 @@ static int reg_copy_regd(const struct ieee80211_regdomain **dst_regd, | |||
1033 | return 0; | 1223 | return 0; |
1034 | } | 1224 | } |
1035 | 1225 | ||
1036 | /* Return value which can be used by ignore_request() to indicate | 1226 | /* |
1037 | * it has been determined we should intersect two regulatory domains */ | 1227 | * Return value which can be used by ignore_request() to indicate |
1228 | * it has been determined we should intersect two regulatory domains | ||
1229 | */ | ||
1038 | #define REG_INTERSECT 1 | 1230 | #define REG_INTERSECT 1 |
1039 | 1231 | ||
1040 | /* This has the logic which determines when a new request | 1232 | /* This has the logic which determines when a new request |
1041 | * should be ignored. */ | 1233 | * should be ignored. */ |
1042 | static int ignore_request(struct wiphy *wiphy, enum reg_set_by set_by, | 1234 | static int ignore_request(struct wiphy *wiphy, |
1043 | const char *alpha2) | 1235 | struct regulatory_request *pending_request) |
1044 | { | 1236 | { |
1237 | struct wiphy *last_wiphy = NULL; | ||
1238 | |||
1239 | assert_cfg80211_lock(); | ||
1240 | |||
1045 | /* All initial requests are respected */ | 1241 | /* All initial requests are respected */ |
1046 | if (!last_request) | 1242 | if (!last_request) |
1047 | return 0; | 1243 | return 0; |
1048 | 1244 | ||
1049 | switch (set_by) { | 1245 | switch (pending_request->initiator) { |
1050 | case REGDOM_SET_BY_INIT: | 1246 | case REGDOM_SET_BY_INIT: |
1051 | return -EINVAL; | 1247 | return -EINVAL; |
1052 | case REGDOM_SET_BY_CORE: | 1248 | case REGDOM_SET_BY_CORE: |
1053 | /* | 1249 | return -EINVAL; |
1054 | * Always respect new wireless core hints, should only happen | ||
1055 | * when updating the world regulatory domain at init. | ||
1056 | */ | ||
1057 | return 0; | ||
1058 | case REGDOM_SET_BY_COUNTRY_IE: | 1250 | case REGDOM_SET_BY_COUNTRY_IE: |
1059 | if (unlikely(!is_an_alpha2(alpha2))) | 1251 | |
1252 | last_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx); | ||
1253 | |||
1254 | if (unlikely(!is_an_alpha2(pending_request->alpha2))) | ||
1060 | return -EINVAL; | 1255 | return -EINVAL; |
1061 | if (last_request->initiator == REGDOM_SET_BY_COUNTRY_IE) { | 1256 | if (last_request->initiator == REGDOM_SET_BY_COUNTRY_IE) { |
1062 | if (last_request->wiphy != wiphy) { | 1257 | if (last_wiphy != wiphy) { |
1063 | /* | 1258 | /* |
1064 | * Two cards with two APs claiming different | 1259 | * Two cards with two APs claiming different |
1065 | * different Country IE alpha2s. We could | 1260 | * different Country IE alpha2s. We could |
1066 | * intersect them, but that seems unlikely | 1261 | * intersect them, but that seems unlikely |
1067 | * to be correct. Reject second one for now. | 1262 | * to be correct. Reject second one for now. |
1068 | */ | 1263 | */ |
1069 | if (!alpha2_equal(alpha2, | 1264 | if (regdom_changes(pending_request->alpha2)) |
1070 | cfg80211_regdomain->alpha2)) | ||
1071 | return -EOPNOTSUPP; | 1265 | return -EOPNOTSUPP; |
1072 | return -EALREADY; | 1266 | return -EALREADY; |
1073 | } | 1267 | } |
1074 | /* Two consecutive Country IE hints on the same wiphy. | 1268 | /* |
1075 | * This should be picked up early by the driver/stack */ | 1269 | * Two consecutive Country IE hints on the same wiphy. |
1076 | if (WARN_ON(!alpha2_equal(cfg80211_regdomain->alpha2, | 1270 | * This should be picked up early by the driver/stack |
1077 | alpha2))) | 1271 | */ |
1272 | if (WARN_ON(regdom_changes(pending_request->alpha2))) | ||
1078 | return 0; | 1273 | return 0; |
1079 | return -EALREADY; | 1274 | return -EALREADY; |
1080 | } | 1275 | } |
@@ -1083,31 +1278,44 @@ static int ignore_request(struct wiphy *wiphy, enum reg_set_by set_by, | |||
1083 | if (last_request->initiator == REGDOM_SET_BY_CORE) { | 1278 | if (last_request->initiator == REGDOM_SET_BY_CORE) { |
1084 | if (is_old_static_regdom(cfg80211_regdomain)) | 1279 | if (is_old_static_regdom(cfg80211_regdomain)) |
1085 | return 0; | 1280 | return 0; |
1086 | if (!alpha2_equal(cfg80211_regdomain->alpha2, alpha2)) | 1281 | if (regdom_changes(pending_request->alpha2)) |
1087 | return 0; | 1282 | return 0; |
1088 | return -EALREADY; | 1283 | return -EALREADY; |
1089 | } | 1284 | } |
1285 | |||
1286 | /* | ||
1287 | * This would happen if you unplug and plug your card | ||
1288 | * back in or if you add a new device for which the previously | ||
1289 | * loaded card also agrees on the regulatory domain. | ||
1290 | */ | ||
1291 | if (last_request->initiator == REGDOM_SET_BY_DRIVER && | ||
1292 | !regdom_changes(pending_request->alpha2)) | ||
1293 | return -EALREADY; | ||
1294 | |||
1090 | return REG_INTERSECT; | 1295 | return REG_INTERSECT; |
1091 | case REGDOM_SET_BY_USER: | 1296 | case REGDOM_SET_BY_USER: |
1092 | if (last_request->initiator == REGDOM_SET_BY_COUNTRY_IE) | 1297 | if (last_request->initiator == REGDOM_SET_BY_COUNTRY_IE) |
1093 | return REG_INTERSECT; | 1298 | return REG_INTERSECT; |
1094 | /* If the user knows better the user should set the regdom | 1299 | /* |
1095 | * to their country before the IE is picked up */ | 1300 | * If the user knows better the user should set the regdom |
1301 | * to their country before the IE is picked up | ||
1302 | */ | ||
1096 | if (last_request->initiator == REGDOM_SET_BY_USER && | 1303 | if (last_request->initiator == REGDOM_SET_BY_USER && |
1097 | last_request->intersect) | 1304 | last_request->intersect) |
1098 | return -EOPNOTSUPP; | 1305 | return -EOPNOTSUPP; |
1099 | /* Process user requests only after previous user/driver/core | 1306 | /* |
1100 | * requests have been processed */ | 1307 | * Process user requests only after previous user/driver/core |
1308 | * requests have been processed | ||
1309 | */ | ||
1101 | if (last_request->initiator == REGDOM_SET_BY_CORE || | 1310 | if (last_request->initiator == REGDOM_SET_BY_CORE || |
1102 | last_request->initiator == REGDOM_SET_BY_DRIVER || | 1311 | last_request->initiator == REGDOM_SET_BY_DRIVER || |
1103 | last_request->initiator == REGDOM_SET_BY_USER) { | 1312 | last_request->initiator == REGDOM_SET_BY_USER) { |
1104 | if (!alpha2_equal(last_request->alpha2, | 1313 | if (regdom_changes(last_request->alpha2)) |
1105 | cfg80211_regdomain->alpha2)) | ||
1106 | return -EAGAIN; | 1314 | return -EAGAIN; |
1107 | } | 1315 | } |
1108 | 1316 | ||
1109 | if (!is_old_static_regdom(cfg80211_regdomain) && | 1317 | if (!is_old_static_regdom(cfg80211_regdomain) && |
1110 | alpha2_equal(cfg80211_regdomain->alpha2, alpha2)) | 1318 | !regdom_changes(pending_request->alpha2)) |
1111 | return -EALREADY; | 1319 | return -EALREADY; |
1112 | 1320 | ||
1113 | return 0; | 1321 | return 0; |
@@ -1116,55 +1324,66 @@ static int ignore_request(struct wiphy *wiphy, enum reg_set_by set_by, | |||
1116 | return -EINVAL; | 1324 | return -EINVAL; |
1117 | } | 1325 | } |
1118 | 1326 | ||
1119 | /* Caller must hold &cfg80211_drv_mutex */ | 1327 | /** |
1120 | int __regulatory_hint(struct wiphy *wiphy, enum reg_set_by set_by, | 1328 | * __regulatory_hint - hint to the wireless core a regulatory domain |
1121 | const char *alpha2, | 1329 | * @wiphy: if the hint comes from country information from an AP, this |
1122 | u32 country_ie_checksum, | 1330 | * is required to be set to the wiphy that received the information |
1123 | enum environment_cap env) | 1331 | * @pending_request: the regulatory request currently being processed |
1332 | * | ||
1333 | * The Wireless subsystem can use this function to hint to the wireless core | ||
1334 | * what it believes should be the current regulatory domain. | ||
1335 | * | ||
1336 | * Returns zero if all went fine, %-EALREADY if a regulatory domain had | ||
1337 | * already been set or other standard error codes. | ||
1338 | * | ||
1339 | * Caller must hold &cfg80211_mutex | ||
1340 | */ | ||
1341 | static int __regulatory_hint(struct wiphy *wiphy, | ||
1342 | struct regulatory_request *pending_request) | ||
1124 | { | 1343 | { |
1125 | struct regulatory_request *request; | ||
1126 | bool intersect = false; | 1344 | bool intersect = false; |
1127 | int r = 0; | 1345 | int r = 0; |
1128 | 1346 | ||
1129 | r = ignore_request(wiphy, set_by, alpha2); | 1347 | assert_cfg80211_lock(); |
1348 | |||
1349 | r = ignore_request(wiphy, pending_request); | ||
1130 | 1350 | ||
1131 | if (r == REG_INTERSECT) { | 1351 | if (r == REG_INTERSECT) { |
1132 | if (set_by == REGDOM_SET_BY_DRIVER) { | 1352 | if (pending_request->initiator == REGDOM_SET_BY_DRIVER) { |
1133 | r = reg_copy_regd(&wiphy->regd, cfg80211_regdomain); | 1353 | r = reg_copy_regd(&wiphy->regd, cfg80211_regdomain); |
1134 | if (r) | 1354 | if (r) { |
1355 | kfree(pending_request); | ||
1135 | return r; | 1356 | return r; |
1357 | } | ||
1136 | } | 1358 | } |
1137 | intersect = true; | 1359 | intersect = true; |
1138 | } else if (r) { | 1360 | } else if (r) { |
1139 | /* If the regulatory domain being requested by the | 1361 | /* |
1362 | * If the regulatory domain being requested by the | ||
1140 | * driver has already been set just copy it to the | 1363 | * driver has already been set just copy it to the |
1141 | * wiphy */ | 1364 | * wiphy |
1142 | if (r == -EALREADY && set_by == REGDOM_SET_BY_DRIVER) { | 1365 | */ |
1366 | if (r == -EALREADY && | ||
1367 | pending_request->initiator == REGDOM_SET_BY_DRIVER) { | ||
1143 | r = reg_copy_regd(&wiphy->regd, cfg80211_regdomain); | 1368 | r = reg_copy_regd(&wiphy->regd, cfg80211_regdomain); |
1144 | if (r) | 1369 | if (r) { |
1370 | kfree(pending_request); | ||
1145 | return r; | 1371 | return r; |
1372 | } | ||
1146 | r = -EALREADY; | 1373 | r = -EALREADY; |
1147 | goto new_request; | 1374 | goto new_request; |
1148 | } | 1375 | } |
1376 | kfree(pending_request); | ||
1149 | return r; | 1377 | return r; |
1150 | } | 1378 | } |
1151 | 1379 | ||
1152 | new_request: | 1380 | new_request: |
1153 | request = kzalloc(sizeof(struct regulatory_request), | 1381 | kfree(last_request); |
1154 | GFP_KERNEL); | ||
1155 | if (!request) | ||
1156 | return -ENOMEM; | ||
1157 | 1382 | ||
1158 | request->alpha2[0] = alpha2[0]; | 1383 | last_request = pending_request; |
1159 | request->alpha2[1] = alpha2[1]; | 1384 | last_request->intersect = intersect; |
1160 | request->initiator = set_by; | ||
1161 | request->wiphy = wiphy; | ||
1162 | request->intersect = intersect; | ||
1163 | request->country_ie_checksum = country_ie_checksum; | ||
1164 | request->country_ie_env = env; | ||
1165 | 1385 | ||
1166 | kfree(last_request); | 1386 | pending_request = NULL; |
1167 | last_request = request; | ||
1168 | 1387 | ||
1169 | /* When r == REG_INTERSECT we do need to call CRDA */ | 1388 | /* When r == REG_INTERSECT we do need to call CRDA */ |
1170 | if (r < 0) | 1389 | if (r < 0) |
@@ -1180,34 +1399,194 @@ new_request: | |||
1180 | * | 1399 | * |
1181 | * to intersect with the static rd | 1400 | * to intersect with the static rd |
1182 | */ | 1401 | */ |
1183 | return call_crda(alpha2); | 1402 | return call_crda(last_request->alpha2); |
1184 | } | 1403 | } |
1185 | 1404 | ||
1186 | void regulatory_hint(struct wiphy *wiphy, const char *alpha2) | 1405 | /* This currently only processes user and driver regulatory hints */ |
1406 | static void reg_process_hint(struct regulatory_request *reg_request) | ||
1187 | { | 1407 | { |
1188 | int r; | 1408 | int r = 0; |
1189 | BUG_ON(!alpha2); | 1409 | struct wiphy *wiphy = NULL; |
1410 | |||
1411 | BUG_ON(!reg_request->alpha2); | ||
1412 | |||
1413 | mutex_lock(&cfg80211_mutex); | ||
1414 | |||
1415 | if (wiphy_idx_valid(reg_request->wiphy_idx)) | ||
1416 | wiphy = wiphy_idx_to_wiphy(reg_request->wiphy_idx); | ||
1417 | |||
1418 | if (reg_request->initiator == REGDOM_SET_BY_DRIVER && | ||
1419 | !wiphy) { | ||
1420 | kfree(reg_request); | ||
1421 | goto out; | ||
1422 | } | ||
1190 | 1423 | ||
1191 | mutex_lock(&cfg80211_drv_mutex); | 1424 | r = __regulatory_hint(wiphy, reg_request); |
1192 | r = __regulatory_hint(wiphy, REGDOM_SET_BY_DRIVER, | ||
1193 | alpha2, 0, ENVIRON_ANY); | ||
1194 | /* This is required so that the orig_* parameters are saved */ | 1425 | /* This is required so that the orig_* parameters are saved */ |
1195 | if (r == -EALREADY && wiphy->strict_regulatory) | 1426 | if (r == -EALREADY && wiphy && wiphy->strict_regulatory) |
1196 | wiphy_update_regulatory(wiphy, REGDOM_SET_BY_DRIVER); | 1427 | wiphy_update_regulatory(wiphy, reg_request->initiator); |
1197 | mutex_unlock(&cfg80211_drv_mutex); | 1428 | out: |
1429 | mutex_unlock(&cfg80211_mutex); | ||
1430 | } | ||
1431 | |||
1432 | /* Processes regulatory hints, this is all the REGDOM_SET_BY_* */ | ||
1433 | static void reg_process_pending_hints(void) | ||
1434 | { | ||
1435 | struct regulatory_request *reg_request; | ||
1436 | |||
1437 | spin_lock(®_requests_lock); | ||
1438 | while (!list_empty(®_requests_list)) { | ||
1439 | reg_request = list_first_entry(®_requests_list, | ||
1440 | struct regulatory_request, | ||
1441 | list); | ||
1442 | list_del_init(®_request->list); | ||
1443 | |||
1444 | spin_unlock(®_requests_lock); | ||
1445 | reg_process_hint(reg_request); | ||
1446 | spin_lock(®_requests_lock); | ||
1447 | } | ||
1448 | spin_unlock(®_requests_lock); | ||
1449 | } | ||
1450 | |||
1451 | /* Processes beacon hints -- this has nothing to do with country IEs */ | ||
1452 | static void reg_process_pending_beacon_hints(void) | ||
1453 | { | ||
1454 | struct cfg80211_registered_device *drv; | ||
1455 | struct reg_beacon *pending_beacon, *tmp; | ||
1456 | |||
1457 | mutex_lock(&cfg80211_mutex); | ||
1458 | |||
1459 | /* This goes through the _pending_ beacon list */ | ||
1460 | spin_lock_bh(®_pending_beacons_lock); | ||
1461 | |||
1462 | if (list_empty(®_pending_beacons)) { | ||
1463 | spin_unlock_bh(®_pending_beacons_lock); | ||
1464 | goto out; | ||
1465 | } | ||
1466 | |||
1467 | list_for_each_entry_safe(pending_beacon, tmp, | ||
1468 | ®_pending_beacons, list) { | ||
1469 | |||
1470 | list_del_init(&pending_beacon->list); | ||
1471 | |||
1472 | /* Applies the beacon hint to current wiphys */ | ||
1473 | list_for_each_entry(drv, &cfg80211_drv_list, list) | ||
1474 | wiphy_update_new_beacon(&drv->wiphy, pending_beacon); | ||
1475 | |||
1476 | /* Remembers the beacon hint for new wiphys or reg changes */ | ||
1477 | list_add_tail(&pending_beacon->list, ®_beacon_list); | ||
1478 | } | ||
1479 | |||
1480 | spin_unlock_bh(®_pending_beacons_lock); | ||
1481 | out: | ||
1482 | mutex_unlock(&cfg80211_mutex); | ||
1483 | } | ||
1484 | |||
1485 | static void reg_todo(struct work_struct *work) | ||
1486 | { | ||
1487 | reg_process_pending_hints(); | ||
1488 | reg_process_pending_beacon_hints(); | ||
1489 | } | ||
1490 | |||
1491 | static DECLARE_WORK(reg_work, reg_todo); | ||
1492 | |||
1493 | static void queue_regulatory_request(struct regulatory_request *request) | ||
1494 | { | ||
1495 | spin_lock(®_requests_lock); | ||
1496 | list_add_tail(&request->list, ®_requests_list); | ||
1497 | spin_unlock(®_requests_lock); | ||
1498 | |||
1499 | schedule_work(®_work); | ||
1500 | } | ||
1501 | |||
1502 | /* Core regulatory hint -- happens once during cfg80211_init() */ | ||
1503 | static int regulatory_hint_core(const char *alpha2) | ||
1504 | { | ||
1505 | struct regulatory_request *request; | ||
1506 | |||
1507 | BUG_ON(last_request); | ||
1508 | |||
1509 | request = kzalloc(sizeof(struct regulatory_request), | ||
1510 | GFP_KERNEL); | ||
1511 | if (!request) | ||
1512 | return -ENOMEM; | ||
1513 | |||
1514 | request->alpha2[0] = alpha2[0]; | ||
1515 | request->alpha2[1] = alpha2[1]; | ||
1516 | request->initiator = REGDOM_SET_BY_CORE; | ||
1517 | |||
1518 | queue_regulatory_request(request); | ||
1519 | |||
1520 | return 0; | ||
1521 | } | ||
1522 | |||
1523 | /* User hints */ | ||
1524 | int regulatory_hint_user(const char *alpha2) | ||
1525 | { | ||
1526 | struct regulatory_request *request; | ||
1527 | |||
1528 | BUG_ON(!alpha2); | ||
1529 | |||
1530 | request = kzalloc(sizeof(struct regulatory_request), GFP_KERNEL); | ||
1531 | if (!request) | ||
1532 | return -ENOMEM; | ||
1533 | |||
1534 | request->wiphy_idx = WIPHY_IDX_STALE; | ||
1535 | request->alpha2[0] = alpha2[0]; | ||
1536 | request->alpha2[1] = alpha2[1]; | ||
1537 | request->initiator = REGDOM_SET_BY_USER, | ||
1538 | |||
1539 | queue_regulatory_request(request); | ||
1540 | |||
1541 | return 0; | ||
1542 | } | ||
1543 | |||
1544 | /* Driver hints */ | ||
1545 | int regulatory_hint(struct wiphy *wiphy, const char *alpha2) | ||
1546 | { | ||
1547 | struct regulatory_request *request; | ||
1548 | |||
1549 | BUG_ON(!alpha2); | ||
1550 | BUG_ON(!wiphy); | ||
1551 | |||
1552 | request = kzalloc(sizeof(struct regulatory_request), GFP_KERNEL); | ||
1553 | if (!request) | ||
1554 | return -ENOMEM; | ||
1555 | |||
1556 | request->wiphy_idx = get_wiphy_idx(wiphy); | ||
1557 | |||
1558 | /* Must have registered wiphy first */ | ||
1559 | BUG_ON(!wiphy_idx_valid(request->wiphy_idx)); | ||
1560 | |||
1561 | request->alpha2[0] = alpha2[0]; | ||
1562 | request->alpha2[1] = alpha2[1]; | ||
1563 | request->initiator = REGDOM_SET_BY_DRIVER; | ||
1564 | |||
1565 | queue_regulatory_request(request); | ||
1566 | |||
1567 | return 0; | ||
1198 | } | 1568 | } |
1199 | EXPORT_SYMBOL(regulatory_hint); | 1569 | EXPORT_SYMBOL(regulatory_hint); |
1200 | 1570 | ||
1201 | static bool reg_same_country_ie_hint(struct wiphy *wiphy, | 1571 | static bool reg_same_country_ie_hint(struct wiphy *wiphy, |
1202 | u32 country_ie_checksum) | 1572 | u32 country_ie_checksum) |
1203 | { | 1573 | { |
1204 | if (!last_request->wiphy) | 1574 | struct wiphy *request_wiphy; |
1575 | |||
1576 | assert_cfg80211_lock(); | ||
1577 | |||
1578 | request_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx); | ||
1579 | |||
1580 | if (!request_wiphy) | ||
1205 | return false; | 1581 | return false; |
1206 | if (likely(last_request->wiphy != wiphy)) | 1582 | |
1583 | if (likely(request_wiphy != wiphy)) | ||
1207 | return !country_ie_integrity_changes(country_ie_checksum); | 1584 | return !country_ie_integrity_changes(country_ie_checksum); |
1208 | /* We should not have let these through at this point, they | 1585 | /* |
1586 | * We should not have let these through at this point, they | ||
1209 | * should have been picked up earlier by the first alpha2 check | 1587 | * should have been picked up earlier by the first alpha2 check |
1210 | * on the device */ | 1588 | * on the device |
1589 | */ | ||
1211 | if (WARN_ON(!country_ie_integrity_changes(country_ie_checksum))) | 1590 | if (WARN_ON(!country_ie_integrity_changes(country_ie_checksum))) |
1212 | return true; | 1591 | return true; |
1213 | return false; | 1592 | return false; |
@@ -1221,11 +1600,14 @@ void regulatory_hint_11d(struct wiphy *wiphy, | |||
1221 | char alpha2[2]; | 1600 | char alpha2[2]; |
1222 | u32 checksum = 0; | 1601 | u32 checksum = 0; |
1223 | enum environment_cap env = ENVIRON_ANY; | 1602 | enum environment_cap env = ENVIRON_ANY; |
1603 | struct regulatory_request *request; | ||
1224 | 1604 | ||
1225 | if (!last_request) | 1605 | mutex_lock(&cfg80211_mutex); |
1226 | return; | ||
1227 | 1606 | ||
1228 | mutex_lock(&cfg80211_drv_mutex); | 1607 | if (unlikely(!last_request)) { |
1608 | mutex_unlock(&cfg80211_mutex); | ||
1609 | return; | ||
1610 | } | ||
1229 | 1611 | ||
1230 | /* IE len must be evenly divisible by 2 */ | 1612 | /* IE len must be evenly divisible by 2 */ |
1231 | if (country_ie_len & 0x01) | 1613 | if (country_ie_len & 0x01) |
@@ -1234,9 +1616,11 @@ void regulatory_hint_11d(struct wiphy *wiphy, | |||
1234 | if (country_ie_len < IEEE80211_COUNTRY_IE_MIN_LEN) | 1616 | if (country_ie_len < IEEE80211_COUNTRY_IE_MIN_LEN) |
1235 | goto out; | 1617 | goto out; |
1236 | 1618 | ||
1237 | /* Pending country IE processing, this can happen after we | 1619 | /* |
1620 | * Pending country IE processing, this can happen after we | ||
1238 | * call CRDA and wait for a response if a beacon was received before | 1621 | * call CRDA and wait for a response if a beacon was received before |
1239 | * we were able to process the last regulatory_hint_11d() call */ | 1622 | * we were able to process the last regulatory_hint_11d() call |
1623 | */ | ||
1240 | if (country_ie_regdomain) | 1624 | if (country_ie_regdomain) |
1241 | goto out; | 1625 | goto out; |
1242 | 1626 | ||
@@ -1248,33 +1632,44 @@ void regulatory_hint_11d(struct wiphy *wiphy, | |||
1248 | else if (country_ie[2] == 'O') | 1632 | else if (country_ie[2] == 'O') |
1249 | env = ENVIRON_OUTDOOR; | 1633 | env = ENVIRON_OUTDOOR; |
1250 | 1634 | ||
1251 | /* We will run this for *every* beacon processed for the BSSID, so | 1635 | /* |
1636 | * We will run this for *every* beacon processed for the BSSID, so | ||
1252 | * we optimize an early check to exit out early if we don't have to | 1637 | * we optimize an early check to exit out early if we don't have to |
1253 | * do anything */ | 1638 | * do anything |
1254 | if (likely(last_request->wiphy)) { | 1639 | */ |
1640 | if (likely(wiphy_idx_valid(last_request->wiphy_idx))) { | ||
1255 | struct cfg80211_registered_device *drv_last_ie; | 1641 | struct cfg80211_registered_device *drv_last_ie; |
1256 | 1642 | ||
1257 | drv_last_ie = wiphy_to_dev(last_request->wiphy); | 1643 | drv_last_ie = |
1644 | cfg80211_drv_by_wiphy_idx(last_request->wiphy_idx); | ||
1258 | 1645 | ||
1259 | /* Lets keep this simple -- we trust the first AP | 1646 | /* |
1260 | * after we intersect with CRDA */ | 1647 | * Lets keep this simple -- we trust the first AP |
1261 | if (likely(last_request->wiphy == wiphy)) { | 1648 | * after we intersect with CRDA |
1262 | /* Ignore IEs coming in on this wiphy with | 1649 | */ |
1263 | * the same alpha2 and environment cap */ | 1650 | if (likely(&drv_last_ie->wiphy == wiphy)) { |
1651 | /* | ||
1652 | * Ignore IEs coming in on this wiphy with | ||
1653 | * the same alpha2 and environment cap | ||
1654 | */ | ||
1264 | if (likely(alpha2_equal(drv_last_ie->country_ie_alpha2, | 1655 | if (likely(alpha2_equal(drv_last_ie->country_ie_alpha2, |
1265 | alpha2) && | 1656 | alpha2) && |
1266 | env == drv_last_ie->env)) { | 1657 | env == drv_last_ie->env)) { |
1267 | goto out; | 1658 | goto out; |
1268 | } | 1659 | } |
1269 | /* the wiphy moved on to another BSSID or the AP | 1660 | /* |
1661 | * the wiphy moved on to another BSSID or the AP | ||
1270 | * was reconfigured. XXX: We need to deal with the | 1662 | * was reconfigured. XXX: We need to deal with the |
1271 | * case where the user suspends and goes to goes | 1663 | * case where the user suspends and goes to goes |
1272 | * to another country, and then gets IEs from an | 1664 | * to another country, and then gets IEs from an |
1273 | * AP with different settings */ | 1665 | * AP with different settings |
1666 | */ | ||
1274 | goto out; | 1667 | goto out; |
1275 | } else { | 1668 | } else { |
1276 | /* Ignore IEs coming in on two separate wiphys with | 1669 | /* |
1277 | * the same alpha2 and environment cap */ | 1670 | * Ignore IEs coming in on two separate wiphys with |
1671 | * the same alpha2 and environment cap | ||
1672 | */ | ||
1278 | if (likely(alpha2_equal(drv_last_ie->country_ie_alpha2, | 1673 | if (likely(alpha2_equal(drv_last_ie->country_ie_alpha2, |
1279 | alpha2) && | 1674 | alpha2) && |
1280 | env == drv_last_ie->env)) { | 1675 | env == drv_last_ie->env)) { |
@@ -1289,28 +1684,97 @@ void regulatory_hint_11d(struct wiphy *wiphy, | |||
1289 | if (!rd) | 1684 | if (!rd) |
1290 | goto out; | 1685 | goto out; |
1291 | 1686 | ||
1292 | /* This will not happen right now but we leave it here for the | 1687 | /* |
1688 | * This will not happen right now but we leave it here for the | ||
1293 | * the future when we want to add suspend/resume support and having | 1689 | * the future when we want to add suspend/resume support and having |
1294 | * the user move to another country after doing so, or having the user | 1690 | * the user move to another country after doing so, or having the user |
1295 | * move to another AP. Right now we just trust the first AP. This is why | 1691 | * move to another AP. Right now we just trust the first AP. |
1296 | * this is marked as likley(). If we hit this before we add this support | 1692 | * |
1297 | * we want to be informed of it as it would indicate a mistake in the | 1693 | * If we hit this before we add this support we want to be informed of |
1298 | * current design */ | 1694 | * it as it would indicate a mistake in the current design |
1299 | if (likely(WARN_ON(reg_same_country_ie_hint(wiphy, checksum)))) | 1695 | */ |
1300 | goto out; | 1696 | if (WARN_ON(reg_same_country_ie_hint(wiphy, checksum))) |
1697 | goto free_rd_out; | ||
1698 | |||
1699 | request = kzalloc(sizeof(struct regulatory_request), GFP_KERNEL); | ||
1700 | if (!request) | ||
1701 | goto free_rd_out; | ||
1301 | 1702 | ||
1302 | /* We keep this around for when CRDA comes back with a response so | 1703 | /* |
1303 | * we can intersect with that */ | 1704 | * We keep this around for when CRDA comes back with a response so |
1705 | * we can intersect with that | ||
1706 | */ | ||
1304 | country_ie_regdomain = rd; | 1707 | country_ie_regdomain = rd; |
1305 | 1708 | ||
1306 | __regulatory_hint(wiphy, REGDOM_SET_BY_COUNTRY_IE, | 1709 | request->wiphy_idx = get_wiphy_idx(wiphy); |
1307 | country_ie_regdomain->alpha2, checksum, env); | 1710 | request->alpha2[0] = rd->alpha2[0]; |
1711 | request->alpha2[1] = rd->alpha2[1]; | ||
1712 | request->initiator = REGDOM_SET_BY_COUNTRY_IE; | ||
1713 | request->country_ie_checksum = checksum; | ||
1714 | request->country_ie_env = env; | ||
1715 | |||
1716 | mutex_unlock(&cfg80211_mutex); | ||
1717 | |||
1718 | queue_regulatory_request(request); | ||
1308 | 1719 | ||
1720 | return; | ||
1721 | |||
1722 | free_rd_out: | ||
1723 | kfree(rd); | ||
1309 | out: | 1724 | out: |
1310 | mutex_unlock(&cfg80211_drv_mutex); | 1725 | mutex_unlock(&cfg80211_mutex); |
1311 | } | 1726 | } |
1312 | EXPORT_SYMBOL(regulatory_hint_11d); | 1727 | EXPORT_SYMBOL(regulatory_hint_11d); |
1313 | 1728 | ||
1729 | static bool freq_is_chan_12_13_14(u16 freq) | ||
1730 | { | ||
1731 | if (freq == ieee80211_channel_to_frequency(12) || | ||
1732 | freq == ieee80211_channel_to_frequency(13) || | ||
1733 | freq == ieee80211_channel_to_frequency(14)) | ||
1734 | return true; | ||
1735 | return false; | ||
1736 | } | ||
1737 | |||
1738 | int regulatory_hint_found_beacon(struct wiphy *wiphy, | ||
1739 | struct ieee80211_channel *beacon_chan, | ||
1740 | gfp_t gfp) | ||
1741 | { | ||
1742 | struct reg_beacon *reg_beacon; | ||
1743 | |||
1744 | if (likely((beacon_chan->beacon_found || | ||
1745 | (beacon_chan->flags & IEEE80211_CHAN_RADAR) || | ||
1746 | (beacon_chan->band == IEEE80211_BAND_2GHZ && | ||
1747 | !freq_is_chan_12_13_14(beacon_chan->center_freq))))) | ||
1748 | return 0; | ||
1749 | |||
1750 | reg_beacon = kzalloc(sizeof(struct reg_beacon), gfp); | ||
1751 | if (!reg_beacon) | ||
1752 | return -ENOMEM; | ||
1753 | |||
1754 | #ifdef CONFIG_CFG80211_REG_DEBUG | ||
1755 | printk(KERN_DEBUG "cfg80211: Found new beacon on " | ||
1756 | "frequency: %d MHz (Ch %d) on %s\n", | ||
1757 | beacon_chan->center_freq, | ||
1758 | ieee80211_frequency_to_channel(beacon_chan->center_freq), | ||
1759 | wiphy_name(wiphy)); | ||
1760 | #endif | ||
1761 | memcpy(®_beacon->chan, beacon_chan, | ||
1762 | sizeof(struct ieee80211_channel)); | ||
1763 | |||
1764 | |||
1765 | /* | ||
1766 | * Since we can be called from BH or and non-BH context | ||
1767 | * we must use spin_lock_bh() | ||
1768 | */ | ||
1769 | spin_lock_bh(®_pending_beacons_lock); | ||
1770 | list_add_tail(®_beacon->list, ®_pending_beacons); | ||
1771 | spin_unlock_bh(®_pending_beacons_lock); | ||
1772 | |||
1773 | schedule_work(®_work); | ||
1774 | |||
1775 | return 0; | ||
1776 | } | ||
1777 | |||
1314 | static void print_rd_rules(const struct ieee80211_regdomain *rd) | 1778 | static void print_rd_rules(const struct ieee80211_regdomain *rd) |
1315 | { | 1779 | { |
1316 | unsigned int i; | 1780 | unsigned int i; |
@@ -1326,8 +1790,10 @@ static void print_rd_rules(const struct ieee80211_regdomain *rd) | |||
1326 | freq_range = ®_rule->freq_range; | 1790 | freq_range = ®_rule->freq_range; |
1327 | power_rule = ®_rule->power_rule; | 1791 | power_rule = ®_rule->power_rule; |
1328 | 1792 | ||
1329 | /* There may not be documentation for max antenna gain | 1793 | /* |
1330 | * in certain regions */ | 1794 | * There may not be documentation for max antenna gain |
1795 | * in certain regions | ||
1796 | */ | ||
1331 | if (power_rule->max_antenna_gain) | 1797 | if (power_rule->max_antenna_gain) |
1332 | printk(KERN_INFO "\t(%d KHz - %d KHz @ %d KHz), " | 1798 | printk(KERN_INFO "\t(%d KHz - %d KHz @ %d KHz), " |
1333 | "(%d mBi, %d mBm)\n", | 1799 | "(%d mBi, %d mBm)\n", |
@@ -1350,13 +1816,12 @@ static void print_regdomain(const struct ieee80211_regdomain *rd) | |||
1350 | { | 1816 | { |
1351 | 1817 | ||
1352 | if (is_intersected_alpha2(rd->alpha2)) { | 1818 | if (is_intersected_alpha2(rd->alpha2)) { |
1353 | struct wiphy *wiphy = NULL; | ||
1354 | struct cfg80211_registered_device *drv; | ||
1355 | 1819 | ||
1356 | if (last_request->initiator == REGDOM_SET_BY_COUNTRY_IE) { | 1820 | if (last_request->initiator == REGDOM_SET_BY_COUNTRY_IE) { |
1357 | if (last_request->wiphy) { | 1821 | struct cfg80211_registered_device *drv; |
1358 | wiphy = last_request->wiphy; | 1822 | drv = cfg80211_drv_by_wiphy_idx( |
1359 | drv = wiphy_to_dev(wiphy); | 1823 | last_request->wiphy_idx); |
1824 | if (drv) { | ||
1360 | printk(KERN_INFO "cfg80211: Current regulatory " | 1825 | printk(KERN_INFO "cfg80211: Current regulatory " |
1361 | "domain updated by AP to: %c%c\n", | 1826 | "domain updated by AP to: %c%c\n", |
1362 | drv->country_ie_alpha2[0], | 1827 | drv->country_ie_alpha2[0], |
@@ -1422,7 +1887,7 @@ static int __set_regdom(const struct ieee80211_regdomain *rd) | |||
1422 | { | 1887 | { |
1423 | const struct ieee80211_regdomain *intersected_rd = NULL; | 1888 | const struct ieee80211_regdomain *intersected_rd = NULL; |
1424 | struct cfg80211_registered_device *drv = NULL; | 1889 | struct cfg80211_registered_device *drv = NULL; |
1425 | struct wiphy *wiphy = NULL; | 1890 | struct wiphy *request_wiphy; |
1426 | /* Some basic sanity checks first */ | 1891 | /* Some basic sanity checks first */ |
1427 | 1892 | ||
1428 | if (is_world_regdom(rd->alpha2)) { | 1893 | if (is_world_regdom(rd->alpha2)) { |
@@ -1439,23 +1904,27 @@ static int __set_regdom(const struct ieee80211_regdomain *rd) | |||
1439 | if (!last_request) | 1904 | if (!last_request) |
1440 | return -EINVAL; | 1905 | return -EINVAL; |
1441 | 1906 | ||
1442 | /* Lets only bother proceeding on the same alpha2 if the current | 1907 | /* |
1908 | * Lets only bother proceeding on the same alpha2 if the current | ||
1443 | * rd is non static (it means CRDA was present and was used last) | 1909 | * rd is non static (it means CRDA was present and was used last) |
1444 | * and the pending request came in from a country IE */ | 1910 | * and the pending request came in from a country IE |
1911 | */ | ||
1445 | if (last_request->initiator != REGDOM_SET_BY_COUNTRY_IE) { | 1912 | if (last_request->initiator != REGDOM_SET_BY_COUNTRY_IE) { |
1446 | /* If someone else asked us to change the rd lets only bother | 1913 | /* |
1447 | * checking if the alpha2 changes if CRDA was already called */ | 1914 | * If someone else asked us to change the rd lets only bother |
1915 | * checking if the alpha2 changes if CRDA was already called | ||
1916 | */ | ||
1448 | if (!is_old_static_regdom(cfg80211_regdomain) && | 1917 | if (!is_old_static_regdom(cfg80211_regdomain) && |
1449 | !regdom_changed(rd->alpha2)) | 1918 | !regdom_changes(rd->alpha2)) |
1450 | return -EINVAL; | 1919 | return -EINVAL; |
1451 | } | 1920 | } |
1452 | 1921 | ||
1453 | wiphy = last_request->wiphy; | 1922 | /* |
1454 | 1923 | * Now lets set the regulatory domain, update all driver channels | |
1455 | /* Now lets set the regulatory domain, update all driver channels | ||
1456 | * and finally inform them of what we have done, in case they want | 1924 | * and finally inform them of what we have done, in case they want |
1457 | * to review or adjust their own settings based on their own | 1925 | * to review or adjust their own settings based on their own |
1458 | * internal EEPROM data */ | 1926 | * internal EEPROM data |
1927 | */ | ||
1459 | 1928 | ||
1460 | if (WARN_ON(!reg_is_valid_request(rd->alpha2))) | 1929 | if (WARN_ON(!reg_is_valid_request(rd->alpha2))) |
1461 | return -EINVAL; | 1930 | return -EINVAL; |
@@ -1467,6 +1936,8 @@ static int __set_regdom(const struct ieee80211_regdomain *rd) | |||
1467 | return -EINVAL; | 1936 | return -EINVAL; |
1468 | } | 1937 | } |
1469 | 1938 | ||
1939 | request_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx); | ||
1940 | |||
1470 | if (!last_request->intersect) { | 1941 | if (!last_request->intersect) { |
1471 | int r; | 1942 | int r; |
1472 | 1943 | ||
@@ -1476,12 +1947,14 @@ static int __set_regdom(const struct ieee80211_regdomain *rd) | |||
1476 | return 0; | 1947 | return 0; |
1477 | } | 1948 | } |
1478 | 1949 | ||
1479 | /* For a driver hint, lets copy the regulatory domain the | 1950 | /* |
1480 | * driver wanted to the wiphy to deal with conflicts */ | 1951 | * For a driver hint, lets copy the regulatory domain the |
1952 | * driver wanted to the wiphy to deal with conflicts | ||
1953 | */ | ||
1481 | 1954 | ||
1482 | BUG_ON(last_request->wiphy->regd); | 1955 | BUG_ON(request_wiphy->regd); |
1483 | 1956 | ||
1484 | r = reg_copy_regd(&last_request->wiphy->regd, rd); | 1957 | r = reg_copy_regd(&request_wiphy->regd, rd); |
1485 | if (r) | 1958 | if (r) |
1486 | return r; | 1959 | return r; |
1487 | 1960 | ||
@@ -1498,11 +1971,13 @@ static int __set_regdom(const struct ieee80211_regdomain *rd) | |||
1498 | if (!intersected_rd) | 1971 | if (!intersected_rd) |
1499 | return -EINVAL; | 1972 | return -EINVAL; |
1500 | 1973 | ||
1501 | /* We can trash what CRDA provided now. | 1974 | /* |
1975 | * We can trash what CRDA provided now. | ||
1502 | * However if a driver requested this specific regulatory | 1976 | * However if a driver requested this specific regulatory |
1503 | * domain we keep it for its private use */ | 1977 | * domain we keep it for its private use |
1978 | */ | ||
1504 | if (last_request->initiator == REGDOM_SET_BY_DRIVER) | 1979 | if (last_request->initiator == REGDOM_SET_BY_DRIVER) |
1505 | last_request->wiphy->regd = rd; | 1980 | request_wiphy->regd = rd; |
1506 | else | 1981 | else |
1507 | kfree(rd); | 1982 | kfree(rd); |
1508 | 1983 | ||
@@ -1522,8 +1997,10 @@ static int __set_regdom(const struct ieee80211_regdomain *rd) | |||
1522 | BUG_ON(!country_ie_regdomain); | 1997 | BUG_ON(!country_ie_regdomain); |
1523 | 1998 | ||
1524 | if (rd != country_ie_regdomain) { | 1999 | if (rd != country_ie_regdomain) { |
1525 | /* Intersect what CRDA returned and our what we | 2000 | /* |
1526 | * had built from the Country IE received */ | 2001 | * Intersect what CRDA returned and our what we |
2002 | * had built from the Country IE received | ||
2003 | */ | ||
1527 | 2004 | ||
1528 | intersected_rd = regdom_intersect(rd, country_ie_regdomain); | 2005 | intersected_rd = regdom_intersect(rd, country_ie_regdomain); |
1529 | 2006 | ||
@@ -1533,16 +2010,18 @@ static int __set_regdom(const struct ieee80211_regdomain *rd) | |||
1533 | kfree(country_ie_regdomain); | 2010 | kfree(country_ie_regdomain); |
1534 | country_ie_regdomain = NULL; | 2011 | country_ie_regdomain = NULL; |
1535 | } else { | 2012 | } else { |
1536 | /* This would happen when CRDA was not present and | 2013 | /* |
2014 | * This would happen when CRDA was not present and | ||
1537 | * OLD_REGULATORY was enabled. We intersect our Country | 2015 | * OLD_REGULATORY was enabled. We intersect our Country |
1538 | * IE rd and what was set on cfg80211 originally */ | 2016 | * IE rd and what was set on cfg80211 originally |
2017 | */ | ||
1539 | intersected_rd = regdom_intersect(rd, cfg80211_regdomain); | 2018 | intersected_rd = regdom_intersect(rd, cfg80211_regdomain); |
1540 | } | 2019 | } |
1541 | 2020 | ||
1542 | if (!intersected_rd) | 2021 | if (!intersected_rd) |
1543 | return -EINVAL; | 2022 | return -EINVAL; |
1544 | 2023 | ||
1545 | drv = wiphy_to_dev(wiphy); | 2024 | drv = wiphy_to_dev(request_wiphy); |
1546 | 2025 | ||
1547 | drv->country_ie_alpha2[0] = rd->alpha2[0]; | 2026 | drv->country_ie_alpha2[0] = rd->alpha2[0]; |
1548 | drv->country_ie_alpha2[1] = rd->alpha2[1]; | 2027 | drv->country_ie_alpha2[1] = rd->alpha2[1]; |
@@ -1560,13 +2039,17 @@ static int __set_regdom(const struct ieee80211_regdomain *rd) | |||
1560 | } | 2039 | } |
1561 | 2040 | ||
1562 | 2041 | ||
1563 | /* Use this call to set the current regulatory domain. Conflicts with | 2042 | /* |
2043 | * Use this call to set the current regulatory domain. Conflicts with | ||
1564 | * multiple drivers can be ironed out later. Caller must've already | 2044 | * multiple drivers can be ironed out later. Caller must've already |
1565 | * kmalloc'd the rd structure. Caller must hold cfg80211_drv_mutex */ | 2045 | * kmalloc'd the rd structure. Caller must hold cfg80211_mutex |
2046 | */ | ||
1566 | int set_regdom(const struct ieee80211_regdomain *rd) | 2047 | int set_regdom(const struct ieee80211_regdomain *rd) |
1567 | { | 2048 | { |
1568 | int r; | 2049 | int r; |
1569 | 2050 | ||
2051 | assert_cfg80211_lock(); | ||
2052 | |||
1570 | /* Note that this doesn't update the wiphys, this is done below */ | 2053 | /* Note that this doesn't update the wiphys, this is done below */ |
1571 | r = __set_regdom(rd); | 2054 | r = __set_regdom(rd); |
1572 | if (r) { | 2055 | if (r) { |
@@ -1586,54 +2069,82 @@ int set_regdom(const struct ieee80211_regdomain *rd) | |||
1586 | return r; | 2069 | return r; |
1587 | } | 2070 | } |
1588 | 2071 | ||
1589 | /* Caller must hold cfg80211_drv_mutex */ | 2072 | /* Caller must hold cfg80211_mutex */ |
1590 | void reg_device_remove(struct wiphy *wiphy) | 2073 | void reg_device_remove(struct wiphy *wiphy) |
1591 | { | 2074 | { |
2075 | struct wiphy *request_wiphy; | ||
2076 | |||
2077 | assert_cfg80211_lock(); | ||
2078 | |||
2079 | request_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx); | ||
2080 | |||
1592 | kfree(wiphy->regd); | 2081 | kfree(wiphy->regd); |
1593 | if (!last_request || !last_request->wiphy) | 2082 | if (!last_request || !request_wiphy) |
1594 | return; | 2083 | return; |
1595 | if (last_request->wiphy != wiphy) | 2084 | if (request_wiphy != wiphy) |
1596 | return; | 2085 | return; |
1597 | last_request->wiphy = NULL; | 2086 | last_request->wiphy_idx = WIPHY_IDX_STALE; |
1598 | last_request->country_ie_env = ENVIRON_ANY; | 2087 | last_request->country_ie_env = ENVIRON_ANY; |
1599 | } | 2088 | } |
1600 | 2089 | ||
1601 | int regulatory_init(void) | 2090 | int regulatory_init(void) |
1602 | { | 2091 | { |
1603 | int err; | 2092 | int err = 0; |
1604 | 2093 | ||
1605 | reg_pdev = platform_device_register_simple("regulatory", 0, NULL, 0); | 2094 | reg_pdev = platform_device_register_simple("regulatory", 0, NULL, 0); |
1606 | if (IS_ERR(reg_pdev)) | 2095 | if (IS_ERR(reg_pdev)) |
1607 | return PTR_ERR(reg_pdev); | 2096 | return PTR_ERR(reg_pdev); |
1608 | 2097 | ||
2098 | spin_lock_init(®_requests_lock); | ||
2099 | spin_lock_init(®_pending_beacons_lock); | ||
2100 | |||
1609 | #ifdef CONFIG_WIRELESS_OLD_REGULATORY | 2101 | #ifdef CONFIG_WIRELESS_OLD_REGULATORY |
1610 | cfg80211_regdomain = static_regdom(ieee80211_regdom); | 2102 | cfg80211_regdomain = static_regdom(ieee80211_regdom); |
1611 | 2103 | ||
1612 | printk(KERN_INFO "cfg80211: Using static regulatory domain info\n"); | 2104 | printk(KERN_INFO "cfg80211: Using static regulatory domain info\n"); |
1613 | print_regdomain_info(cfg80211_regdomain); | 2105 | print_regdomain_info(cfg80211_regdomain); |
1614 | /* The old code still requests for a new regdomain and if | 2106 | /* |
2107 | * The old code still requests for a new regdomain and if | ||
1615 | * you have CRDA you get it updated, otherwise you get | 2108 | * you have CRDA you get it updated, otherwise you get |
1616 | * stuck with the static values. We ignore "EU" code as | 2109 | * stuck with the static values. We ignore "EU" code as |
1617 | * that is not a valid ISO / IEC 3166 alpha2 */ | 2110 | * that is not a valid ISO / IEC 3166 alpha2 |
2111 | */ | ||
1618 | if (ieee80211_regdom[0] != 'E' || ieee80211_regdom[1] != 'U') | 2112 | if (ieee80211_regdom[0] != 'E' || ieee80211_regdom[1] != 'U') |
1619 | err = __regulatory_hint(NULL, REGDOM_SET_BY_CORE, | 2113 | err = regulatory_hint_core(ieee80211_regdom); |
1620 | ieee80211_regdom, 0, ENVIRON_ANY); | ||
1621 | #else | 2114 | #else |
1622 | cfg80211_regdomain = cfg80211_world_regdom; | 2115 | cfg80211_regdomain = cfg80211_world_regdom; |
1623 | 2116 | ||
1624 | err = __regulatory_hint(NULL, REGDOM_SET_BY_CORE, "00", 0, ENVIRON_ANY); | 2117 | err = regulatory_hint_core("00"); |
1625 | if (err) | ||
1626 | printk(KERN_ERR "cfg80211: calling CRDA failed - " | ||
1627 | "unable to update world regulatory domain, " | ||
1628 | "using static definition\n"); | ||
1629 | #endif | 2118 | #endif |
2119 | if (err) { | ||
2120 | if (err == -ENOMEM) | ||
2121 | return err; | ||
2122 | /* | ||
2123 | * N.B. kobject_uevent_env() can fail mainly for when we're out | ||
2124 | * memory which is handled and propagated appropriately above | ||
2125 | * but it can also fail during a netlink_broadcast() or during | ||
2126 | * early boot for call_usermodehelper(). For now treat these | ||
2127 | * errors as non-fatal. | ||
2128 | */ | ||
2129 | printk(KERN_ERR "cfg80211: kobject_uevent_env() was unable " | ||
2130 | "to call CRDA during init"); | ||
2131 | #ifdef CONFIG_CFG80211_REG_DEBUG | ||
2132 | /* We want to find out exactly why when debugging */ | ||
2133 | WARN_ON(err); | ||
2134 | #endif | ||
2135 | } | ||
1630 | 2136 | ||
1631 | return 0; | 2137 | return 0; |
1632 | } | 2138 | } |
1633 | 2139 | ||
1634 | void regulatory_exit(void) | 2140 | void regulatory_exit(void) |
1635 | { | 2141 | { |
1636 | mutex_lock(&cfg80211_drv_mutex); | 2142 | struct regulatory_request *reg_request, *tmp; |
2143 | struct reg_beacon *reg_beacon, *btmp; | ||
2144 | |||
2145 | cancel_work_sync(®_work); | ||
2146 | |||
2147 | mutex_lock(&cfg80211_mutex); | ||
1637 | 2148 | ||
1638 | reset_regdomains(); | 2149 | reset_regdomains(); |
1639 | 2150 | ||
@@ -1644,5 +2155,33 @@ void regulatory_exit(void) | |||
1644 | 2155 | ||
1645 | platform_device_unregister(reg_pdev); | 2156 | platform_device_unregister(reg_pdev); |
1646 | 2157 | ||
1647 | mutex_unlock(&cfg80211_drv_mutex); | 2158 | spin_lock_bh(®_pending_beacons_lock); |
2159 | if (!list_empty(®_pending_beacons)) { | ||
2160 | list_for_each_entry_safe(reg_beacon, btmp, | ||
2161 | ®_pending_beacons, list) { | ||
2162 | list_del(®_beacon->list); | ||
2163 | kfree(reg_beacon); | ||
2164 | } | ||
2165 | } | ||
2166 | spin_unlock_bh(®_pending_beacons_lock); | ||
2167 | |||
2168 | if (!list_empty(®_beacon_list)) { | ||
2169 | list_for_each_entry_safe(reg_beacon, btmp, | ||
2170 | ®_beacon_list, list) { | ||
2171 | list_del(®_beacon->list); | ||
2172 | kfree(reg_beacon); | ||
2173 | } | ||
2174 | } | ||
2175 | |||
2176 | spin_lock(®_requests_lock); | ||
2177 | if (!list_empty(®_requests_list)) { | ||
2178 | list_for_each_entry_safe(reg_request, tmp, | ||
2179 | ®_requests_list, list) { | ||
2180 | list_del(®_request->list); | ||
2181 | kfree(reg_request); | ||
2182 | } | ||
2183 | } | ||
2184 | spin_unlock(®_requests_lock); | ||
2185 | |||
2186 | mutex_unlock(&cfg80211_mutex); | ||
1648 | } | 2187 | } |
diff --git a/net/wireless/reg.h b/net/wireless/reg.h index fe8c83f34fb7..e37829a49dc4 100644 --- a/net/wireless/reg.h +++ b/net/wireless/reg.h | |||
@@ -6,6 +6,8 @@ extern const struct ieee80211_regdomain *cfg80211_regdomain; | |||
6 | bool is_world_regdom(const char *alpha2); | 6 | bool is_world_regdom(const char *alpha2); |
7 | bool reg_is_valid_request(const char *alpha2); | 7 | bool reg_is_valid_request(const char *alpha2); |
8 | 8 | ||
9 | int regulatory_hint_user(const char *alpha2); | ||
10 | |||
9 | void reg_device_remove(struct wiphy *wiphy); | 11 | void reg_device_remove(struct wiphy *wiphy); |
10 | 12 | ||
11 | int regulatory_init(void); | 13 | int regulatory_init(void); |
@@ -14,26 +16,24 @@ void regulatory_exit(void); | |||
14 | int set_regdom(const struct ieee80211_regdomain *rd); | 16 | int set_regdom(const struct ieee80211_regdomain *rd); |
15 | 17 | ||
16 | /** | 18 | /** |
17 | * __regulatory_hint - hint to the wireless core a regulatory domain | 19 | * regulatory_hint_found_beacon - hints a beacon was found on a channel |
18 | * @wiphy: if the hint comes from country information from an AP, this | 20 | * @wiphy: the wireless device where the beacon was found on |
19 | * is required to be set to the wiphy that received the information | 21 | * @beacon_chan: the channel on which the beacon was found on |
20 | * @alpha2: the ISO/IEC 3166 alpha2 being claimed the regulatory domain | 22 | * @gfp: context flags |
21 | * should be in. | ||
22 | * @country_ie_checksum: checksum of processed country IE, set this to 0 | ||
23 | * if the hint did not come from a country IE | ||
24 | * @country_ie_env: the environment the IE told us we are in, %ENVIRON_* | ||
25 | * | ||
26 | * The Wireless subsystem can use this function to hint to the wireless core | ||
27 | * what it believes should be the current regulatory domain by giving it an | ||
28 | * ISO/IEC 3166 alpha2 country code it knows its regulatory domain should be | ||
29 | * in. | ||
30 | * | 23 | * |
31 | * Returns zero if all went fine, %-EALREADY if a regulatory domain had | 24 | * This informs the wireless core that a beacon from an AP was found on |
32 | * already been set or other standard error codes. | 25 | * the channel provided. This allows the wireless core to make educated |
26 | * guesses on regulatory to help with world roaming. This is only used for | ||
27 | * world roaming -- when we do not know our current location. This is | ||
28 | * only useful on channels 12, 13 and 14 on the 2 GHz band as channels | ||
29 | * 1-11 are already enabled by the world regulatory domain; and on | ||
30 | * non-radar 5 GHz channels. | ||
33 | * | 31 | * |
32 | * Drivers do not need to call this, cfg80211 will do it for after a scan | ||
33 | * on a newly found BSS. | ||
34 | */ | 34 | */ |
35 | extern int __regulatory_hint(struct wiphy *wiphy, enum reg_set_by set_by, | 35 | int regulatory_hint_found_beacon(struct wiphy *wiphy, |
36 | const char *alpha2, u32 country_ie_checksum, | 36 | struct ieee80211_channel *beacon_chan, |
37 | enum environment_cap country_ie_env); | 37 | gfp_t gfp); |
38 | 38 | ||
39 | #endif /* __NET_WIRELESS_REG_H */ | 39 | #endif /* __NET_WIRELESS_REG_H */ |
diff --git a/net/wireless/scan.c b/net/wireless/scan.c index b1893c863b97..280dbcd02c15 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c | |||
@@ -62,6 +62,18 @@ static void bss_release(struct kref *ref) | |||
62 | } | 62 | } |
63 | 63 | ||
64 | /* must hold dev->bss_lock! */ | 64 | /* must hold dev->bss_lock! */ |
65 | void cfg80211_bss_age(struct cfg80211_registered_device *dev, | ||
66 | unsigned long age_secs) | ||
67 | { | ||
68 | struct cfg80211_internal_bss *bss; | ||
69 | unsigned long age_jiffies = msecs_to_jiffies(age_secs * MSEC_PER_SEC); | ||
70 | |||
71 | list_for_each_entry(bss, &dev->bss_list, list) { | ||
72 | bss->ts -= age_jiffies; | ||
73 | } | ||
74 | } | ||
75 | |||
76 | /* must hold dev->bss_lock! */ | ||
65 | void cfg80211_bss_expire(struct cfg80211_registered_device *dev) | 77 | void cfg80211_bss_expire(struct cfg80211_registered_device *dev) |
66 | { | 78 | { |
67 | struct cfg80211_internal_bss *bss, *tmp; | 79 | struct cfg80211_internal_bss *bss, *tmp; |
@@ -358,7 +370,6 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev, | |||
358 | found->pub.beacon_interval = res->pub.beacon_interval; | 370 | found->pub.beacon_interval = res->pub.beacon_interval; |
359 | found->pub.tsf = res->pub.tsf; | 371 | found->pub.tsf = res->pub.tsf; |
360 | found->pub.signal = res->pub.signal; | 372 | found->pub.signal = res->pub.signal; |
361 | found->pub.signal_type = res->pub.signal_type; | ||
362 | found->pub.capability = res->pub.capability; | 373 | found->pub.capability = res->pub.capability; |
363 | found->ts = res->ts; | 374 | found->ts = res->ts; |
364 | kref_put(&res->ref, bss_release); | 375 | kref_put(&res->ref, bss_release); |
@@ -380,8 +391,7 @@ struct cfg80211_bss * | |||
380 | cfg80211_inform_bss_frame(struct wiphy *wiphy, | 391 | cfg80211_inform_bss_frame(struct wiphy *wiphy, |
381 | struct ieee80211_channel *channel, | 392 | struct ieee80211_channel *channel, |
382 | struct ieee80211_mgmt *mgmt, size_t len, | 393 | struct ieee80211_mgmt *mgmt, size_t len, |
383 | s32 signal, enum cfg80211_signal_type sigtype, | 394 | s32 signal, gfp_t gfp) |
384 | gfp_t gfp) | ||
385 | { | 395 | { |
386 | struct cfg80211_internal_bss *res; | 396 | struct cfg80211_internal_bss *res; |
387 | size_t ielen = len - offsetof(struct ieee80211_mgmt, | 397 | size_t ielen = len - offsetof(struct ieee80211_mgmt, |
@@ -389,7 +399,7 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy, | |||
389 | bool overwrite; | 399 | bool overwrite; |
390 | size_t privsz = wiphy->bss_priv_size; | 400 | size_t privsz = wiphy->bss_priv_size; |
391 | 401 | ||
392 | if (WARN_ON(sigtype == NL80211_BSS_SIGNAL_UNSPEC && | 402 | if (WARN_ON(wiphy->signal_type == NL80211_BSS_SIGNAL_UNSPEC && |
393 | (signal < 0 || signal > 100))) | 403 | (signal < 0 || signal > 100))) |
394 | return NULL; | 404 | return NULL; |
395 | 405 | ||
@@ -403,7 +413,6 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy, | |||
403 | 413 | ||
404 | memcpy(res->pub.bssid, mgmt->bssid, ETH_ALEN); | 414 | memcpy(res->pub.bssid, mgmt->bssid, ETH_ALEN); |
405 | res->pub.channel = channel; | 415 | res->pub.channel = channel; |
406 | res->pub.signal_type = sigtype; | ||
407 | res->pub.signal = signal; | 416 | res->pub.signal = signal; |
408 | res->pub.tsf = le64_to_cpu(mgmt->u.probe_resp.timestamp); | 417 | res->pub.tsf = le64_to_cpu(mgmt->u.probe_resp.timestamp); |
409 | res->pub.beacon_interval = le16_to_cpu(mgmt->u.probe_resp.beacon_int); | 418 | res->pub.beacon_interval = le16_to_cpu(mgmt->u.probe_resp.beacon_int); |
@@ -421,6 +430,9 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy, | |||
421 | if (!res) | 430 | if (!res) |
422 | return NULL; | 431 | return NULL; |
423 | 432 | ||
433 | if (res->pub.capability & WLAN_CAPABILITY_ESS) | ||
434 | regulatory_hint_found_beacon(wiphy, channel, gfp); | ||
435 | |||
424 | /* cfg80211_bss_update gives us a referenced result */ | 436 | /* cfg80211_bss_update gives us a referenced result */ |
425 | return &res->pub; | 437 | return &res->pub; |
426 | } | 438 | } |
@@ -584,16 +596,25 @@ static void ieee80211_scan_add_ies(struct iw_request_info *info, | |||
584 | } | 596 | } |
585 | } | 597 | } |
586 | 598 | ||
599 | static inline unsigned int elapsed_jiffies_msecs(unsigned long start) | ||
600 | { | ||
601 | unsigned long end = jiffies; | ||
602 | |||
603 | if (end >= start) | ||
604 | return jiffies_to_msecs(end - start); | ||
605 | |||
606 | return jiffies_to_msecs(end + (MAX_JIFFY_OFFSET - start) + 1); | ||
607 | } | ||
587 | 608 | ||
588 | static char * | 609 | static char * |
589 | ieee80211_bss(struct iw_request_info *info, | 610 | ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info, |
590 | struct cfg80211_internal_bss *bss, | 611 | struct cfg80211_internal_bss *bss, char *current_ev, |
591 | char *current_ev, char *end_buf) | 612 | char *end_buf) |
592 | { | 613 | { |
593 | struct iw_event iwe; | 614 | struct iw_event iwe; |
594 | u8 *buf, *cfg, *p; | 615 | u8 *buf, *cfg, *p; |
595 | u8 *ie = bss->pub.information_elements; | 616 | u8 *ie = bss->pub.information_elements; |
596 | int rem = bss->pub.len_information_elements, i; | 617 | int rem = bss->pub.len_information_elements, i, sig; |
597 | bool ismesh = false; | 618 | bool ismesh = false; |
598 | 619 | ||
599 | memset(&iwe, 0, sizeof(iwe)); | 620 | memset(&iwe, 0, sizeof(iwe)); |
@@ -617,19 +638,28 @@ ieee80211_bss(struct iw_request_info *info, | |||
617 | current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, | 638 | current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, |
618 | IW_EV_FREQ_LEN); | 639 | IW_EV_FREQ_LEN); |
619 | 640 | ||
620 | if (bss->pub.signal_type != CFG80211_SIGNAL_TYPE_NONE) { | 641 | if (wiphy->signal_type != CFG80211_SIGNAL_TYPE_NONE) { |
621 | memset(&iwe, 0, sizeof(iwe)); | 642 | memset(&iwe, 0, sizeof(iwe)); |
622 | iwe.cmd = IWEVQUAL; | 643 | iwe.cmd = IWEVQUAL; |
623 | iwe.u.qual.updated = IW_QUAL_LEVEL_UPDATED | | 644 | iwe.u.qual.updated = IW_QUAL_LEVEL_UPDATED | |
624 | IW_QUAL_NOISE_INVALID | | 645 | IW_QUAL_NOISE_INVALID | |
625 | IW_QUAL_QUAL_INVALID; | 646 | IW_QUAL_QUAL_UPDATED; |
626 | switch (bss->pub.signal_type) { | 647 | switch (wiphy->signal_type) { |
627 | case CFG80211_SIGNAL_TYPE_MBM: | 648 | case CFG80211_SIGNAL_TYPE_MBM: |
628 | iwe.u.qual.level = bss->pub.signal / 100; | 649 | sig = bss->pub.signal / 100; |
650 | iwe.u.qual.level = sig; | ||
629 | iwe.u.qual.updated |= IW_QUAL_DBM; | 651 | iwe.u.qual.updated |= IW_QUAL_DBM; |
652 | if (sig < -110) /* rather bad */ | ||
653 | sig = -110; | ||
654 | else if (sig > -40) /* perfect */ | ||
655 | sig = -40; | ||
656 | /* will give a range of 0 .. 70 */ | ||
657 | iwe.u.qual.qual = sig + 110; | ||
630 | break; | 658 | break; |
631 | case CFG80211_SIGNAL_TYPE_UNSPEC: | 659 | case CFG80211_SIGNAL_TYPE_UNSPEC: |
632 | iwe.u.qual.level = bss->pub.signal; | 660 | iwe.u.qual.level = bss->pub.signal; |
661 | /* will give range 0 .. 100 */ | ||
662 | iwe.u.qual.qual = bss->pub.signal; | ||
633 | break; | 663 | break; |
634 | default: | 664 | default: |
635 | /* not reached */ | 665 | /* not reached */ |
@@ -763,8 +793,8 @@ ieee80211_bss(struct iw_request_info *info, | |||
763 | &iwe, buf); | 793 | &iwe, buf); |
764 | memset(&iwe, 0, sizeof(iwe)); | 794 | memset(&iwe, 0, sizeof(iwe)); |
765 | iwe.cmd = IWEVCUSTOM; | 795 | iwe.cmd = IWEVCUSTOM; |
766 | sprintf(buf, " Last beacon: %dms ago", | 796 | sprintf(buf, " Last beacon: %ums ago", |
767 | jiffies_to_msecs(jiffies - bss->ts)); | 797 | elapsed_jiffies_msecs(bss->ts)); |
768 | iwe.u.data.length = strlen(buf); | 798 | iwe.u.data.length = strlen(buf); |
769 | current_ev = iwe_stream_add_point(info, current_ev, | 799 | current_ev = iwe_stream_add_point(info, current_ev, |
770 | end_buf, &iwe, buf); | 800 | end_buf, &iwe, buf); |
@@ -793,8 +823,8 @@ static int ieee80211_scan_results(struct cfg80211_registered_device *dev, | |||
793 | spin_unlock_bh(&dev->bss_lock); | 823 | spin_unlock_bh(&dev->bss_lock); |
794 | return -E2BIG; | 824 | return -E2BIG; |
795 | } | 825 | } |
796 | current_ev = ieee80211_bss(info, bss, | 826 | current_ev = ieee80211_bss(&dev->wiphy, info, bss, |
797 | current_ev, end_buf); | 827 | current_ev, end_buf); |
798 | } | 828 | } |
799 | spin_unlock_bh(&dev->bss_lock); | 829 | spin_unlock_bh(&dev->bss_lock); |
800 | return current_ev - buf; | 830 | return current_ev - buf; |
diff --git a/net/wireless/sysfs.c b/net/wireless/sysfs.c index 26a72b0797a0..efe3c5c92b2d 100644 --- a/net/wireless/sysfs.c +++ b/net/wireless/sysfs.c | |||
@@ -31,7 +31,7 @@ static ssize_t name ## _show(struct device *dev, \ | |||
31 | return sprintf(buf, fmt "\n", dev_to_rdev(dev)->member); \ | 31 | return sprintf(buf, fmt "\n", dev_to_rdev(dev)->member); \ |
32 | } | 32 | } |
33 | 33 | ||
34 | SHOW_FMT(index, "%d", idx); | 34 | SHOW_FMT(index, "%d", wiphy_idx); |
35 | SHOW_FMT(macaddress, "%pM", wiphy.perm_addr); | 35 | SHOW_FMT(macaddress, "%pM", wiphy.perm_addr); |
36 | 36 | ||
37 | static struct device_attribute ieee80211_dev_attrs[] = { | 37 | static struct device_attribute ieee80211_dev_attrs[] = { |
@@ -60,6 +60,8 @@ static int wiphy_suspend(struct device *dev, pm_message_t state) | |||
60 | struct cfg80211_registered_device *rdev = dev_to_rdev(dev); | 60 | struct cfg80211_registered_device *rdev = dev_to_rdev(dev); |
61 | int ret = 0; | 61 | int ret = 0; |
62 | 62 | ||
63 | rdev->suspend_at = get_seconds(); | ||
64 | |||
63 | if (rdev->ops->suspend) { | 65 | if (rdev->ops->suspend) { |
64 | rtnl_lock(); | 66 | rtnl_lock(); |
65 | ret = rdev->ops->suspend(&rdev->wiphy); | 67 | ret = rdev->ops->suspend(&rdev->wiphy); |
@@ -74,6 +76,11 @@ static int wiphy_resume(struct device *dev) | |||
74 | struct cfg80211_registered_device *rdev = dev_to_rdev(dev); | 76 | struct cfg80211_registered_device *rdev = dev_to_rdev(dev); |
75 | int ret = 0; | 77 | int ret = 0; |
76 | 78 | ||
79 | /* Age scan results with time spent in suspend */ | ||
80 | spin_lock_bh(&rdev->bss_lock); | ||
81 | cfg80211_bss_age(rdev, get_seconds() - rdev->suspend_at); | ||
82 | spin_unlock_bh(&rdev->bss_lock); | ||
83 | |||
77 | if (rdev->ops->resume) { | 84 | if (rdev->ops->resume) { |
78 | rtnl_lock(); | 85 | rtnl_lock(); |
79 | ret = rdev->ops->resume(&rdev->wiphy); | 86 | ret = rdev->ops->resume(&rdev->wiphy); |
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index 58e489fd4aed..b84a9b4fe96a 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c | |||
@@ -137,3 +137,100 @@ int cfg80211_wext_giwmode(struct net_device *dev, struct iw_request_info *info, | |||
137 | return 0; | 137 | return 0; |
138 | } | 138 | } |
139 | EXPORT_SYMBOL(cfg80211_wext_giwmode); | 139 | EXPORT_SYMBOL(cfg80211_wext_giwmode); |
140 | |||
141 | |||
142 | int cfg80211_wext_giwrange(struct net_device *dev, | ||
143 | struct iw_request_info *info, | ||
144 | struct iw_point *data, char *extra) | ||
145 | { | ||
146 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
147 | struct iw_range *range = (struct iw_range *) extra; | ||
148 | enum ieee80211_band band; | ||
149 | int c = 0; | ||
150 | |||
151 | if (!wdev) | ||
152 | return -EOPNOTSUPP; | ||
153 | |||
154 | data->length = sizeof(struct iw_range); | ||
155 | memset(range, 0, sizeof(struct iw_range)); | ||
156 | |||
157 | range->we_version_compiled = WIRELESS_EXT; | ||
158 | range->we_version_source = 21; | ||
159 | range->retry_capa = IW_RETRY_LIMIT; | ||
160 | range->retry_flags = IW_RETRY_LIMIT; | ||
161 | range->min_retry = 0; | ||
162 | range->max_retry = 255; | ||
163 | range->min_rts = 0; | ||
164 | range->max_rts = 2347; | ||
165 | range->min_frag = 256; | ||
166 | range->max_frag = 2346; | ||
167 | |||
168 | range->encoding_size[0] = 5; | ||
169 | range->encoding_size[1] = 13; | ||
170 | range->num_encoding_sizes = 2; | ||
171 | range->max_encoding_tokens = 4; | ||
172 | |||
173 | range->max_qual.updated = IW_QUAL_NOISE_INVALID; | ||
174 | |||
175 | switch (wdev->wiphy->signal_type) { | ||
176 | case CFG80211_SIGNAL_TYPE_NONE: | ||
177 | break; | ||
178 | case CFG80211_SIGNAL_TYPE_MBM: | ||
179 | range->max_qual.level = -110; | ||
180 | range->max_qual.qual = 70; | ||
181 | range->avg_qual.qual = 35; | ||
182 | range->max_qual.updated |= IW_QUAL_DBM; | ||
183 | range->max_qual.updated |= IW_QUAL_QUAL_UPDATED; | ||
184 | range->max_qual.updated |= IW_QUAL_LEVEL_UPDATED; | ||
185 | break; | ||
186 | case CFG80211_SIGNAL_TYPE_UNSPEC: | ||
187 | range->max_qual.level = 100; | ||
188 | range->max_qual.qual = 100; | ||
189 | range->avg_qual.qual = 50; | ||
190 | range->max_qual.updated |= IW_QUAL_QUAL_UPDATED; | ||
191 | range->max_qual.updated |= IW_QUAL_LEVEL_UPDATED; | ||
192 | break; | ||
193 | } | ||
194 | |||
195 | range->avg_qual.level = range->max_qual.level / 2; | ||
196 | range->avg_qual.noise = range->max_qual.noise / 2; | ||
197 | range->avg_qual.updated = range->max_qual.updated; | ||
198 | |||
199 | range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 | | ||
200 | IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP; | ||
201 | |||
202 | |||
203 | for (band = 0; band < IEEE80211_NUM_BANDS; band ++) { | ||
204 | int i; | ||
205 | struct ieee80211_supported_band *sband; | ||
206 | |||
207 | sband = wdev->wiphy->bands[band]; | ||
208 | |||
209 | if (!sband) | ||
210 | continue; | ||
211 | |||
212 | for (i = 0; i < sband->n_channels && c < IW_MAX_FREQUENCIES; i++) { | ||
213 | struct ieee80211_channel *chan = &sband->channels[i]; | ||
214 | |||
215 | if (!(chan->flags & IEEE80211_CHAN_DISABLED)) { | ||
216 | range->freq[c].i = | ||
217 | ieee80211_frequency_to_channel( | ||
218 | chan->center_freq); | ||
219 | range->freq[c].m = chan->center_freq; | ||
220 | range->freq[c].e = 6; | ||
221 | c++; | ||
222 | } | ||
223 | } | ||
224 | } | ||
225 | range->num_channels = c; | ||
226 | range->num_frequency = c; | ||
227 | |||
228 | IW_EVENT_CAPA_SET_KERNEL(range->event_capa); | ||
229 | IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWAP); | ||
230 | IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWSCAN); | ||
231 | |||
232 | range->scan_capa |= IW_SCAN_CAPA_ESSID; | ||
233 | |||
234 | return 0; | ||
235 | } | ||
236 | EXPORT_SYMBOL(cfg80211_wext_giwrange); | ||