Contents of /trunk/kernel-magellan/patches-3.9/0108-3.9.9-all-fixes.patch
Parent Directory | Revision Log
Revision 2234 -
(show annotations)
(download)
Thu Jul 11 17:29:27 2013 UTC (11 years, 2 months ago) by niro
File size: 35022 byte(s)
Thu Jul 11 17:29:27 2013 UTC (11 years, 2 months ago) by niro
File size: 35022 byte(s)
-linux-3.9.9
1 | diff --git a/arch/arm/include/asm/cacheflush.h b/arch/arm/include/asm/cacheflush.h |
2 | index e1489c5..738fcba 100644 |
3 | --- a/arch/arm/include/asm/cacheflush.h |
4 | +++ b/arch/arm/include/asm/cacheflush.h |
5 | @@ -320,9 +320,7 @@ static inline void flush_anon_page(struct vm_area_struct *vma, |
6 | } |
7 | |
8 | #define ARCH_HAS_FLUSH_KERNEL_DCACHE_PAGE |
9 | -static inline void flush_kernel_dcache_page(struct page *page) |
10 | -{ |
11 | -} |
12 | +extern void flush_kernel_dcache_page(struct page *); |
13 | |
14 | #define flush_dcache_mmap_lock(mapping) \ |
15 | spin_lock_irq(&(mapping)->tree_lock) |
16 | diff --git a/arch/arm/mm/flush.c b/arch/arm/mm/flush.c |
17 | index 1c8f7f5..b5ae9fd 100644 |
18 | --- a/arch/arm/mm/flush.c |
19 | +++ b/arch/arm/mm/flush.c |
20 | @@ -298,6 +298,39 @@ void flush_dcache_page(struct page *page) |
21 | EXPORT_SYMBOL(flush_dcache_page); |
22 | |
23 | /* |
24 | + * Ensure cache coherency for the kernel mapping of this page. We can |
25 | + * assume that the page is pinned via kmap. |
26 | + * |
27 | + * If the page only exists in the page cache and there are no user |
28 | + * space mappings, this is a no-op since the page was already marked |
29 | + * dirty at creation. Otherwise, we need to flush the dirty kernel |
30 | + * cache lines directly. |
31 | + */ |
32 | +void flush_kernel_dcache_page(struct page *page) |
33 | +{ |
34 | + if (cache_is_vivt() || cache_is_vipt_aliasing()) { |
35 | + struct address_space *mapping; |
36 | + |
37 | + mapping = page_mapping(page); |
38 | + |
39 | + if (!mapping || mapping_mapped(mapping)) { |
40 | + void *addr; |
41 | + |
42 | + addr = page_address(page); |
43 | + /* |
44 | + * kmap_atomic() doesn't set the page virtual |
45 | + * address for highmem pages, and |
46 | + * kunmap_atomic() takes care of cache |
47 | + * flushing already. |
48 | + */ |
49 | + if (!IS_ENABLED(CONFIG_HIGHMEM) || addr) |
50 | + __cpuc_flush_dcache_area(addr, PAGE_SIZE); |
51 | + } |
52 | + } |
53 | +} |
54 | +EXPORT_SYMBOL(flush_kernel_dcache_page); |
55 | + |
56 | +/* |
57 | * Flush an anonymous page so that users of get_user_pages() |
58 | * can safely access the data. The expected sequence is: |
59 | * |
60 | diff --git a/arch/arm/mm/nommu.c b/arch/arm/mm/nommu.c |
61 | index d51225f..eb5293a 100644 |
62 | --- a/arch/arm/mm/nommu.c |
63 | +++ b/arch/arm/mm/nommu.c |
64 | @@ -57,6 +57,12 @@ void flush_dcache_page(struct page *page) |
65 | } |
66 | EXPORT_SYMBOL(flush_dcache_page); |
67 | |
68 | +void flush_kernel_dcache_page(struct page *page) |
69 | +{ |
70 | + __cpuc_flush_dcache_area(page_address(page), PAGE_SIZE); |
71 | +} |
72 | +EXPORT_SYMBOL(flush_kernel_dcache_page); |
73 | + |
74 | void copy_to_user_page(struct vm_area_struct *vma, struct page *page, |
75 | unsigned long uaddr, void *dst, const void *src, |
76 | unsigned long len) |
77 | diff --git a/arch/powerpc/platforms/pseries/eeh_pe.c b/arch/powerpc/platforms/pseries/eeh_pe.c |
78 | index fe43d1a..9d4a9e8 100644 |
79 | --- a/arch/powerpc/platforms/pseries/eeh_pe.c |
80 | +++ b/arch/powerpc/platforms/pseries/eeh_pe.c |
81 | @@ -639,7 +639,8 @@ struct pci_bus *eeh_pe_bus_get(struct eeh_pe *pe) |
82 | |
83 | if (pe->type & EEH_PE_PHB) { |
84 | bus = pe->phb->bus; |
85 | - } else if (pe->type & EEH_PE_BUS) { |
86 | + } else if (pe->type & EEH_PE_BUS || |
87 | + pe->type & EEH_PE_DEVICE) { |
88 | edev = list_first_entry(&pe->edevs, struct eeh_dev, list); |
89 | pdev = eeh_dev_to_pci_dev(edev); |
90 | if (pdev) |
91 | diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c |
92 | index d8a6a38..feb719d 100644 |
93 | --- a/arch/s390/kernel/ipl.c |
94 | +++ b/arch/s390/kernel/ipl.c |
95 | @@ -754,9 +754,9 @@ static struct bin_attribute sys_reipl_fcp_scp_data_attr = { |
96 | .write = reipl_fcp_scpdata_write, |
97 | }; |
98 | |
99 | -DEFINE_IPL_ATTR_RW(reipl_fcp, wwpn, "0x%016llx\n", "%016llx\n", |
100 | +DEFINE_IPL_ATTR_RW(reipl_fcp, wwpn, "0x%016llx\n", "%llx\n", |
101 | reipl_block_fcp->ipl_info.fcp.wwpn); |
102 | -DEFINE_IPL_ATTR_RW(reipl_fcp, lun, "0x%016llx\n", "%016llx\n", |
103 | +DEFINE_IPL_ATTR_RW(reipl_fcp, lun, "0x%016llx\n", "%llx\n", |
104 | reipl_block_fcp->ipl_info.fcp.lun); |
105 | DEFINE_IPL_ATTR_RW(reipl_fcp, bootprog, "%lld\n", "%lld\n", |
106 | reipl_block_fcp->ipl_info.fcp.bootprog); |
107 | @@ -1323,9 +1323,9 @@ static struct shutdown_action __refdata reipl_action = { |
108 | |
109 | /* FCP dump device attributes */ |
110 | |
111 | -DEFINE_IPL_ATTR_RW(dump_fcp, wwpn, "0x%016llx\n", "%016llx\n", |
112 | +DEFINE_IPL_ATTR_RW(dump_fcp, wwpn, "0x%016llx\n", "%llx\n", |
113 | dump_block_fcp->ipl_info.fcp.wwpn); |
114 | -DEFINE_IPL_ATTR_RW(dump_fcp, lun, "0x%016llx\n", "%016llx\n", |
115 | +DEFINE_IPL_ATTR_RW(dump_fcp, lun, "0x%016llx\n", "%llx\n", |
116 | dump_block_fcp->ipl_info.fcp.lun); |
117 | DEFINE_IPL_ATTR_RW(dump_fcp, bootprog, "%lld\n", "%lld\n", |
118 | dump_block_fcp->ipl_info.fcp.bootprog); |
119 | diff --git a/arch/s390/kernel/irq.c b/arch/s390/kernel/irq.c |
120 | index 1630f43..1d95be9 100644 |
121 | --- a/arch/s390/kernel/irq.c |
122 | +++ b/arch/s390/kernel/irq.c |
123 | @@ -313,3 +313,69 @@ void measurement_alert_subclass_unregister(void) |
124 | spin_unlock(&ma_subclass_lock); |
125 | } |
126 | EXPORT_SYMBOL(measurement_alert_subclass_unregister); |
127 | + |
128 | +#ifdef CONFIG_SMP |
129 | +void synchronize_irq(unsigned int irq) |
130 | +{ |
131 | + /* |
132 | + * Not needed, the handler is protected by a lock and IRQs that occur |
133 | + * after the handler is deleted are just NOPs. |
134 | + */ |
135 | +} |
136 | +EXPORT_SYMBOL_GPL(synchronize_irq); |
137 | +#endif |
138 | + |
139 | +#ifndef CONFIG_PCI |
140 | + |
141 | +/* Only PCI devices have dynamically-defined IRQ handlers */ |
142 | + |
143 | +int request_irq(unsigned int irq, irq_handler_t handler, |
144 | + unsigned long irqflags, const char *devname, void *dev_id) |
145 | +{ |
146 | + return -EINVAL; |
147 | +} |
148 | +EXPORT_SYMBOL_GPL(request_irq); |
149 | + |
150 | +void free_irq(unsigned int irq, void *dev_id) |
151 | +{ |
152 | + WARN_ON(1); |
153 | +} |
154 | +EXPORT_SYMBOL_GPL(free_irq); |
155 | + |
156 | +void enable_irq(unsigned int irq) |
157 | +{ |
158 | + WARN_ON(1); |
159 | +} |
160 | +EXPORT_SYMBOL_GPL(enable_irq); |
161 | + |
162 | +void disable_irq(unsigned int irq) |
163 | +{ |
164 | + WARN_ON(1); |
165 | +} |
166 | +EXPORT_SYMBOL_GPL(disable_irq); |
167 | + |
168 | +#endif /* !CONFIG_PCI */ |
169 | + |
170 | +void disable_irq_nosync(unsigned int irq) |
171 | +{ |
172 | + disable_irq(irq); |
173 | +} |
174 | +EXPORT_SYMBOL_GPL(disable_irq_nosync); |
175 | + |
176 | +unsigned long probe_irq_on(void) |
177 | +{ |
178 | + return 0; |
179 | +} |
180 | +EXPORT_SYMBOL_GPL(probe_irq_on); |
181 | + |
182 | +int probe_irq_off(unsigned long val) |
183 | +{ |
184 | + return 0; |
185 | +} |
186 | +EXPORT_SYMBOL_GPL(probe_irq_off); |
187 | + |
188 | +unsigned int probe_irq_mask(unsigned long val) |
189 | +{ |
190 | + return val; |
191 | +} |
192 | +EXPORT_SYMBOL_GPL(probe_irq_mask); |
193 | diff --git a/arch/s390/pci/pci.c b/arch/s390/pci/pci.c |
194 | index 27b4c17..4fd5b5a 100644 |
195 | --- a/arch/s390/pci/pci.c |
196 | +++ b/arch/s390/pci/pci.c |
197 | @@ -306,15 +306,6 @@ static int zpci_cfg_store(struct zpci_dev *zdev, int offset, u32 val, u8 len) |
198 | return rc; |
199 | } |
200 | |
201 | -void synchronize_irq(unsigned int irq) |
202 | -{ |
203 | - /* |
204 | - * Not needed, the handler is protected by a lock and IRQs that occur |
205 | - * after the handler is deleted are just NOPs. |
206 | - */ |
207 | -} |
208 | -EXPORT_SYMBOL_GPL(synchronize_irq); |
209 | - |
210 | void enable_irq(unsigned int irq) |
211 | { |
212 | struct msi_desc *msi = irq_get_msi_desc(irq); |
213 | @@ -331,30 +322,6 @@ void disable_irq(unsigned int irq) |
214 | } |
215 | EXPORT_SYMBOL_GPL(disable_irq); |
216 | |
217 | -void disable_irq_nosync(unsigned int irq) |
218 | -{ |
219 | - disable_irq(irq); |
220 | -} |
221 | -EXPORT_SYMBOL_GPL(disable_irq_nosync); |
222 | - |
223 | -unsigned long probe_irq_on(void) |
224 | -{ |
225 | - return 0; |
226 | -} |
227 | -EXPORT_SYMBOL_GPL(probe_irq_on); |
228 | - |
229 | -int probe_irq_off(unsigned long val) |
230 | -{ |
231 | - return 0; |
232 | -} |
233 | -EXPORT_SYMBOL_GPL(probe_irq_off); |
234 | - |
235 | -unsigned int probe_irq_mask(unsigned long val) |
236 | -{ |
237 | - return val; |
238 | -} |
239 | -EXPORT_SYMBOL_GPL(probe_irq_mask); |
240 | - |
241 | void pcibios_fixup_bus(struct pci_bus *bus) |
242 | { |
243 | } |
244 | diff --git a/arch/x86/include/asm/irq_remapping.h b/arch/x86/include/asm/irq_remapping.h |
245 | index 95fd352..b00bf09 100644 |
246 | --- a/arch/x86/include/asm/irq_remapping.h |
247 | +++ b/arch/x86/include/asm/irq_remapping.h |
248 | @@ -23,11 +23,13 @@ |
249 | #define __X86_IRQ_REMAPPING_H |
250 | |
251 | #include <asm/io_apic.h> |
252 | +#include <linux/irq.h> |
253 | |
254 | #ifdef CONFIG_IRQ_REMAP |
255 | |
256 | extern void setup_irq_remapping_ops(void); |
257 | extern int irq_remapping_supported(void); |
258 | +extern void set_irq_remapping_broken(void); |
259 | extern int irq_remapping_prepare(void); |
260 | extern int irq_remapping_enable(void); |
261 | extern void irq_remapping_disable(void); |
262 | @@ -54,6 +56,7 @@ void irq_remap_modify_chip_defaults(struct irq_chip *chip); |
263 | |
264 | static inline void setup_irq_remapping_ops(void) { } |
265 | static inline int irq_remapping_supported(void) { return 0; } |
266 | +static inline void set_irq_remapping_broken(void) { } |
267 | static inline int irq_remapping_prepare(void) { return -ENODEV; } |
268 | static inline int irq_remapping_enable(void) { return -ENODEV; } |
269 | static inline void irq_remapping_disable(void) { } |
270 | diff --git a/arch/x86/kernel/early-quirks.c b/arch/x86/kernel/early-quirks.c |
271 | index 3755ef4..94ab6b9 100644 |
272 | --- a/arch/x86/kernel/early-quirks.c |
273 | +++ b/arch/x86/kernel/early-quirks.c |
274 | @@ -18,6 +18,7 @@ |
275 | #include <asm/apic.h> |
276 | #include <asm/iommu.h> |
277 | #include <asm/gart.h> |
278 | +#include <asm/irq_remapping.h> |
279 | |
280 | static void __init fix_hypertransport_config(int num, int slot, int func) |
281 | { |
282 | @@ -192,6 +193,21 @@ static void __init ati_bugs_contd(int num, int slot, int func) |
283 | } |
284 | #endif |
285 | |
286 | +static void __init intel_remapping_check(int num, int slot, int func) |
287 | +{ |
288 | + u8 revision; |
289 | + |
290 | + revision = read_pci_config_byte(num, slot, func, PCI_REVISION_ID); |
291 | + |
292 | + /* |
293 | + * Revision 0x13 of this chipset supports irq remapping |
294 | + * but has an erratum that breaks its behavior, flag it as such |
295 | + */ |
296 | + if (revision == 0x13) |
297 | + set_irq_remapping_broken(); |
298 | + |
299 | +} |
300 | + |
301 | #define QFLAG_APPLY_ONCE 0x1 |
302 | #define QFLAG_APPLIED 0x2 |
303 | #define QFLAG_DONE (QFLAG_APPLY_ONCE|QFLAG_APPLIED) |
304 | @@ -221,6 +237,10 @@ static struct chipset early_qrk[] __initdata = { |
305 | PCI_CLASS_SERIAL_SMBUS, PCI_ANY_ID, 0, ati_bugs }, |
306 | { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_SBX00_SMBUS, |
307 | PCI_CLASS_SERIAL_SMBUS, PCI_ANY_ID, 0, ati_bugs_contd }, |
308 | + { PCI_VENDOR_ID_INTEL, 0x3403, PCI_CLASS_BRIDGE_HOST, |
309 | + PCI_BASE_CLASS_BRIDGE, 0, intel_remapping_check }, |
310 | + { PCI_VENDOR_ID_INTEL, 0x3406, PCI_CLASS_BRIDGE_HOST, |
311 | + PCI_BASE_CLASS_BRIDGE, 0, intel_remapping_check }, |
312 | {} |
313 | }; |
314 | |
315 | diff --git a/crypto/algboss.c b/crypto/algboss.c |
316 | index 769219b..76fc0b2 100644 |
317 | --- a/crypto/algboss.c |
318 | +++ b/crypto/algboss.c |
319 | @@ -45,10 +45,9 @@ struct cryptomgr_param { |
320 | } nu32; |
321 | } attrs[CRYPTO_MAX_ATTRS]; |
322 | |
323 | - char larval[CRYPTO_MAX_ALG_NAME]; |
324 | char template[CRYPTO_MAX_ALG_NAME]; |
325 | |
326 | - struct completion *completion; |
327 | + struct crypto_larval *larval; |
328 | |
329 | u32 otype; |
330 | u32 omask; |
331 | @@ -87,7 +86,8 @@ static int cryptomgr_probe(void *data) |
332 | crypto_tmpl_put(tmpl); |
333 | |
334 | out: |
335 | - complete_all(param->completion); |
336 | + complete_all(¶m->larval->completion); |
337 | + crypto_alg_put(¶m->larval->alg); |
338 | kfree(param); |
339 | module_put_and_exit(0); |
340 | } |
341 | @@ -187,18 +187,19 @@ static int cryptomgr_schedule_probe(struct crypto_larval *larval) |
342 | param->otype = larval->alg.cra_flags; |
343 | param->omask = larval->mask; |
344 | |
345 | - memcpy(param->larval, larval->alg.cra_name, CRYPTO_MAX_ALG_NAME); |
346 | - |
347 | - param->completion = &larval->completion; |
348 | + crypto_alg_get(&larval->alg); |
349 | + param->larval = larval; |
350 | |
351 | thread = kthread_run(cryptomgr_probe, param, "cryptomgr_probe"); |
352 | if (IS_ERR(thread)) |
353 | - goto err_free_param; |
354 | + goto err_put_larval; |
355 | |
356 | wait_for_completion_interruptible(&larval->completion); |
357 | |
358 | return NOTIFY_STOP; |
359 | |
360 | +err_put_larval: |
361 | + crypto_alg_put(&larval->alg); |
362 | err_free_param: |
363 | kfree(param); |
364 | err_put_module: |
365 | diff --git a/crypto/api.c b/crypto/api.c |
366 | index 033a714..3b61803 100644 |
367 | --- a/crypto/api.c |
368 | +++ b/crypto/api.c |
369 | @@ -34,12 +34,6 @@ EXPORT_SYMBOL_GPL(crypto_alg_sem); |
370 | BLOCKING_NOTIFIER_HEAD(crypto_chain); |
371 | EXPORT_SYMBOL_GPL(crypto_chain); |
372 | |
373 | -static inline struct crypto_alg *crypto_alg_get(struct crypto_alg *alg) |
374 | -{ |
375 | - atomic_inc(&alg->cra_refcnt); |
376 | - return alg; |
377 | -} |
378 | - |
379 | struct crypto_alg *crypto_mod_get(struct crypto_alg *alg) |
380 | { |
381 | return try_module_get(alg->cra_module) ? crypto_alg_get(alg) : NULL; |
382 | diff --git a/crypto/internal.h b/crypto/internal.h |
383 | index 9ebedae..bd39bfc 100644 |
384 | --- a/crypto/internal.h |
385 | +++ b/crypto/internal.h |
386 | @@ -103,6 +103,12 @@ int crypto_register_notifier(struct notifier_block *nb); |
387 | int crypto_unregister_notifier(struct notifier_block *nb); |
388 | int crypto_probing_notify(unsigned long val, void *v); |
389 | |
390 | +static inline struct crypto_alg *crypto_alg_get(struct crypto_alg *alg) |
391 | +{ |
392 | + atomic_inc(&alg->cra_refcnt); |
393 | + return alg; |
394 | +} |
395 | + |
396 | static inline void crypto_alg_put(struct crypto_alg *alg) |
397 | { |
398 | if (atomic_dec_and_test(&alg->cra_refcnt) && alg->cra_destroy) |
399 | diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c |
400 | index 3badf18..3ce078c 100644 |
401 | --- a/drivers/ata/libata-acpi.c |
402 | +++ b/drivers/ata/libata-acpi.c |
403 | @@ -157,8 +157,10 @@ static void ata_acpi_handle_hotplug(struct ata_port *ap, struct ata_device *dev, |
404 | |
405 | spin_unlock_irqrestore(ap->lock, flags); |
406 | |
407 | - if (wait) |
408 | + if (wait) { |
409 | ata_port_wait_eh(ap); |
410 | + flush_work(&ap->hotplug_task.work); |
411 | + } |
412 | } |
413 | |
414 | static void ata_acpi_dev_notify_dock(acpi_handle handle, u32 event, void *data) |
415 | @@ -215,6 +217,38 @@ static const struct acpi_dock_ops ata_acpi_ap_dock_ops = { |
416 | .uevent = ata_acpi_ap_uevent, |
417 | }; |
418 | |
419 | +void ata_acpi_hotplug_init(struct ata_host *host) |
420 | +{ |
421 | + int i; |
422 | + |
423 | + for (i = 0; i < host->n_ports; i++) { |
424 | + struct ata_port *ap = host->ports[i]; |
425 | + acpi_handle handle; |
426 | + struct ata_device *dev; |
427 | + |
428 | + if (!ap) |
429 | + continue; |
430 | + |
431 | + handle = ata_ap_acpi_handle(ap); |
432 | + if (handle) { |
433 | + /* we might be on a docking station */ |
434 | + register_hotplug_dock_device(handle, |
435 | + &ata_acpi_ap_dock_ops, ap); |
436 | + } |
437 | + |
438 | + ata_for_each_dev(dev, &ap->link, ALL) { |
439 | + handle = ata_dev_acpi_handle(dev); |
440 | + if (!handle) |
441 | + continue; |
442 | + |
443 | + /* we might be on a docking station */ |
444 | + register_hotplug_dock_device(handle, |
445 | + &ata_acpi_dev_dock_ops, |
446 | + dev); |
447 | + } |
448 | + } |
449 | +} |
450 | + |
451 | /** |
452 | * ata_acpi_dissociate - dissociate ATA host from ACPI objects |
453 | * @host: target ATA host |
454 | diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c |
455 | index cf15aee..8038ee3 100644 |
456 | --- a/drivers/ata/libata-core.c |
457 | +++ b/drivers/ata/libata-core.c |
458 | @@ -6148,6 +6148,8 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht) |
459 | if (rc) |
460 | goto err_tadd; |
461 | |
462 | + ata_acpi_hotplug_init(host); |
463 | + |
464 | /* set cable, sata_spd_limit and report */ |
465 | for (i = 0; i < host->n_ports; i++) { |
466 | struct ata_port *ap = host->ports[i]; |
467 | diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h |
468 | index c949dd3..577d902b 100644 |
469 | --- a/drivers/ata/libata.h |
470 | +++ b/drivers/ata/libata.h |
471 | @@ -122,6 +122,7 @@ extern int ata_acpi_register(void); |
472 | extern void ata_acpi_unregister(void); |
473 | extern void ata_acpi_bind(struct ata_device *dev); |
474 | extern void ata_acpi_unbind(struct ata_device *dev); |
475 | +extern void ata_acpi_hotplug_init(struct ata_host *host); |
476 | #else |
477 | static inline void ata_acpi_dissociate(struct ata_host *host) { } |
478 | static inline int ata_acpi_on_suspend(struct ata_port *ap) { return 0; } |
479 | @@ -134,6 +135,7 @@ static inline int ata_acpi_register(void) { return 0; } |
480 | static inline void ata_acpi_unregister(void) { } |
481 | static inline void ata_acpi_bind(struct ata_device *dev) { } |
482 | static inline void ata_acpi_unbind(struct ata_device *dev) { } |
483 | +static inline void ata_acpi_hotplug_init(struct ata_host *host) {} |
484 | #endif |
485 | |
486 | /* libata-scsi.c */ |
487 | diff --git a/drivers/iommu/intel_irq_remapping.c b/drivers/iommu/intel_irq_remapping.c |
488 | index f3b8f23..5b19b2d 100644 |
489 | --- a/drivers/iommu/intel_irq_remapping.c |
490 | +++ b/drivers/iommu/intel_irq_remapping.c |
491 | @@ -524,6 +524,16 @@ static int __init intel_irq_remapping_supported(void) |
492 | |
493 | if (disable_irq_remap) |
494 | return 0; |
495 | + if (irq_remap_broken) { |
496 | + WARN_TAINT(1, TAINT_FIRMWARE_WORKAROUND, |
497 | + "This system BIOS has enabled interrupt remapping\n" |
498 | + "on a chipset that contains an erratum making that\n" |
499 | + "feature unstable. To maintain system stability\n" |
500 | + "interrupt remapping is being disabled. Please\n" |
501 | + "contact your BIOS vendor for an update\n"); |
502 | + disable_irq_remap = 1; |
503 | + return 0; |
504 | + } |
505 | |
506 | if (!dmar_ir_support()) |
507 | return 0; |
508 | diff --git a/drivers/iommu/irq_remapping.c b/drivers/iommu/irq_remapping.c |
509 | index 7c11ff3..dcfea4e 100644 |
510 | --- a/drivers/iommu/irq_remapping.c |
511 | +++ b/drivers/iommu/irq_remapping.c |
512 | @@ -18,6 +18,7 @@ |
513 | int irq_remapping_enabled; |
514 | |
515 | int disable_irq_remap; |
516 | +int irq_remap_broken; |
517 | int disable_sourceid_checking; |
518 | int no_x2apic_optout; |
519 | |
520 | @@ -210,6 +211,11 @@ void __init setup_irq_remapping_ops(void) |
521 | #endif |
522 | } |
523 | |
524 | +void set_irq_remapping_broken(void) |
525 | +{ |
526 | + irq_remap_broken = 1; |
527 | +} |
528 | + |
529 | int irq_remapping_supported(void) |
530 | { |
531 | if (disable_irq_remap) |
532 | diff --git a/drivers/iommu/irq_remapping.h b/drivers/iommu/irq_remapping.h |
533 | index ecb6376..90c4dae 100644 |
534 | --- a/drivers/iommu/irq_remapping.h |
535 | +++ b/drivers/iommu/irq_remapping.h |
536 | @@ -32,6 +32,7 @@ struct pci_dev; |
537 | struct msi_msg; |
538 | |
539 | extern int disable_irq_remap; |
540 | +extern int irq_remap_broken; |
541 | extern int disable_sourceid_checking; |
542 | extern int no_x2apic_optout; |
543 | extern int irq_remapping_enabled; |
544 | @@ -89,6 +90,7 @@ extern struct irq_remap_ops amd_iommu_irq_ops; |
545 | |
546 | #define irq_remapping_enabled 0 |
547 | #define disable_irq_remap 1 |
548 | +#define irq_remap_broken 0 |
549 | |
550 | #endif /* CONFIG_IRQ_REMAP */ |
551 | |
552 | diff --git a/drivers/net/can/usb/usb_8dev.c b/drivers/net/can/usb/usb_8dev.c |
553 | index 6e15ef0..cbd388e 100644 |
554 | --- a/drivers/net/can/usb/usb_8dev.c |
555 | +++ b/drivers/net/can/usb/usb_8dev.c |
556 | @@ -977,7 +977,7 @@ static int usb_8dev_probe(struct usb_interface *intf, |
557 | err = usb_8dev_cmd_version(priv, &version); |
558 | if (err) { |
559 | netdev_err(netdev, "can't get firmware version\n"); |
560 | - goto cleanup_cmd_msg_buffer; |
561 | + goto cleanup_unregister_candev; |
562 | } else { |
563 | netdev_info(netdev, |
564 | "firmware: %d.%d, hardware: %d.%d\n", |
565 | @@ -989,6 +989,9 @@ static int usb_8dev_probe(struct usb_interface *intf, |
566 | |
567 | return 0; |
568 | |
569 | +cleanup_unregister_candev: |
570 | + unregister_netdev(priv->netdev); |
571 | + |
572 | cleanup_cmd_msg_buffer: |
573 | kfree(priv->cmd_msg_buffer); |
574 | |
575 | diff --git a/drivers/net/wan/dlci.c b/drivers/net/wan/dlci.c |
576 | index 147614e..6a8a382 100644 |
577 | --- a/drivers/net/wan/dlci.c |
578 | +++ b/drivers/net/wan/dlci.c |
579 | @@ -384,21 +384,37 @@ static int dlci_del(struct dlci_add *dlci) |
580 | struct frad_local *flp; |
581 | struct net_device *master, *slave; |
582 | int err; |
583 | + bool found = false; |
584 | + |
585 | + rtnl_lock(); |
586 | |
587 | /* validate slave device */ |
588 | master = __dev_get_by_name(&init_net, dlci->devname); |
589 | - if (!master) |
590 | - return -ENODEV; |
591 | + if (!master) { |
592 | + err = -ENODEV; |
593 | + goto out; |
594 | + } |
595 | + |
596 | + list_for_each_entry(dlp, &dlci_devs, list) { |
597 | + if (dlp->master == master) { |
598 | + found = true; |
599 | + break; |
600 | + } |
601 | + } |
602 | + if (!found) { |
603 | + err = -ENODEV; |
604 | + goto out; |
605 | + } |
606 | |
607 | if (netif_running(master)) { |
608 | - return -EBUSY; |
609 | + err = -EBUSY; |
610 | + goto out; |
611 | } |
612 | |
613 | dlp = netdev_priv(master); |
614 | slave = dlp->slave; |
615 | flp = netdev_priv(slave); |
616 | |
617 | - rtnl_lock(); |
618 | err = (*flp->deassoc)(slave, master); |
619 | if (!err) { |
620 | list_del(&dlp->list); |
621 | @@ -407,8 +423,8 @@ static int dlci_del(struct dlci_add *dlci) |
622 | |
623 | dev_put(slave); |
624 | } |
625 | +out: |
626 | rtnl_unlock(); |
627 | - |
628 | return err; |
629 | } |
630 | |
631 | diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c |
632 | index a8016d7..305bed8 100644 |
633 | --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c |
634 | +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c |
635 | @@ -1174,7 +1174,7 @@ static int ath9k_htc_config(struct ieee80211_hw *hw, u32 changed) |
636 | mutex_lock(&priv->htc_pm_lock); |
637 | |
638 | priv->ps_idle = !!(conf->flags & IEEE80211_CONF_IDLE); |
639 | - if (priv->ps_idle) |
640 | + if (!priv->ps_idle) |
641 | chip_reset = true; |
642 | |
643 | mutex_unlock(&priv->htc_pm_lock); |
644 | diff --git a/drivers/net/wireless/iwlwifi/dvm/rxon.c b/drivers/net/wireless/iwlwifi/dvm/rxon.c |
645 | index a82b6b3..5c36c21 100644 |
646 | --- a/drivers/net/wireless/iwlwifi/dvm/rxon.c |
647 | +++ b/drivers/net/wireless/iwlwifi/dvm/rxon.c |
648 | @@ -1377,7 +1377,7 @@ static void iwlagn_chain_noise_reset(struct iwl_priv *priv) |
649 | struct iwl_chain_noise_data *data = &priv->chain_noise_data; |
650 | int ret; |
651 | |
652 | - if (!(priv->calib_disabled & IWL_CHAIN_NOISE_CALIB_DISABLED)) |
653 | + if (priv->calib_disabled & IWL_CHAIN_NOISE_CALIB_DISABLED) |
654 | return; |
655 | |
656 | if ((data->state == IWL_CHAIN_NOISE_ALIVE) && |
657 | diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c |
658 | index 92849e5..d420c53 100644 |
659 | --- a/drivers/net/wireless/rt2x00/rt2800lib.c |
660 | +++ b/drivers/net/wireless/rt2x00/rt2800lib.c |
661 | @@ -2634,19 +2634,26 @@ static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev, |
662 | * TODO: we do not use +6 dBm option to do not increase power beyond |
663 | * regulatory limit, however this could be utilized for devices with |
664 | * CAPABILITY_POWER_LIMIT. |
665 | + * |
666 | + * TODO: add different temperature compensation code for RT3290 & RT5390 |
667 | + * to allow to use BBP_R1 for those chips. |
668 | */ |
669 | - rt2800_bbp_read(rt2x00dev, 1, &r1); |
670 | - if (delta <= -12) { |
671 | - power_ctrl = 2; |
672 | - delta += 12; |
673 | - } else if (delta <= -6) { |
674 | - power_ctrl = 1; |
675 | - delta += 6; |
676 | - } else { |
677 | - power_ctrl = 0; |
678 | + if (!rt2x00_rt(rt2x00dev, RT3290) && |
679 | + !rt2x00_rt(rt2x00dev, RT5390)) { |
680 | + rt2800_bbp_read(rt2x00dev, 1, &r1); |
681 | + if (delta <= -12) { |
682 | + power_ctrl = 2; |
683 | + delta += 12; |
684 | + } else if (delta <= -6) { |
685 | + power_ctrl = 1; |
686 | + delta += 6; |
687 | + } else { |
688 | + power_ctrl = 0; |
689 | + } |
690 | + rt2x00_set_field8(&r1, BBP1_TX_POWER_CTRL, power_ctrl); |
691 | + rt2800_bbp_write(rt2x00dev, 1, r1); |
692 | } |
693 | - rt2x00_set_field8(&r1, BBP1_TX_POWER_CTRL, power_ctrl); |
694 | - rt2800_bbp_write(rt2x00dev, 1, r1); |
695 | + |
696 | offset = TX_PWR_CFG_0; |
697 | |
698 | for (i = 0; i < EEPROM_TXPOWER_BYRATE_SIZE; i += 2) { |
699 | diff --git a/drivers/of/base.c b/drivers/of/base.c |
700 | index 321d3ef..e77e719 100644 |
701 | --- a/drivers/of/base.c |
702 | +++ b/drivers/of/base.c |
703 | @@ -1166,11 +1166,11 @@ static int __of_parse_phandle_with_args(const struct device_node *np, |
704 | out_args->args_count = count; |
705 | for (i = 0; i < count; i++) |
706 | out_args->args[i] = be32_to_cpup(list++); |
707 | + } else { |
708 | + of_node_put(node); |
709 | } |
710 | |
711 | /* Found it! return success */ |
712 | - if (node) |
713 | - of_node_put(node); |
714 | return 0; |
715 | } |
716 | |
717 | diff --git a/fs/exec.c b/fs/exec.c |
718 | index 6d56ff2..0d5c76f 100644 |
719 | --- a/fs/exec.c |
720 | +++ b/fs/exec.c |
721 | @@ -1136,13 +1136,6 @@ void setup_new_exec(struct linux_binprm * bprm) |
722 | set_dumpable(current->mm, suid_dumpable); |
723 | } |
724 | |
725 | - /* |
726 | - * Flush performance counters when crossing a |
727 | - * security domain: |
728 | - */ |
729 | - if (!get_dumpable(current->mm)) |
730 | - perf_event_exit_task(current); |
731 | - |
732 | /* An exec changes our domain. We are no longer part of the thread |
733 | group */ |
734 | |
735 | @@ -1206,6 +1199,15 @@ void install_exec_creds(struct linux_binprm *bprm) |
736 | |
737 | commit_creds(bprm->cred); |
738 | bprm->cred = NULL; |
739 | + |
740 | + /* |
741 | + * Disable monitoring for regular users |
742 | + * when executing setuid binaries. Must |
743 | + * wait until new credentials are committed |
744 | + * by commit_creds() above |
745 | + */ |
746 | + if (get_dumpable(current->mm) != SUID_DUMP_USER) |
747 | + perf_event_exit_task(current); |
748 | /* |
749 | * cred_guard_mutex must be held at least to this point to prevent |
750 | * ptrace_attach() from altering our determination of the task's |
751 | diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c |
752 | index de08c92f..605af51 100644 |
753 | --- a/fs/ubifs/dir.c |
754 | +++ b/fs/ubifs/dir.c |
755 | @@ -349,31 +349,50 @@ static unsigned int vfs_dent_type(uint8_t type) |
756 | static int ubifs_readdir(struct file *file, void *dirent, filldir_t filldir) |
757 | { |
758 | int err, over = 0; |
759 | + loff_t pos = file->f_pos; |
760 | struct qstr nm; |
761 | union ubifs_key key; |
762 | struct ubifs_dent_node *dent; |
763 | struct inode *dir = file_inode(file); |
764 | struct ubifs_info *c = dir->i_sb->s_fs_info; |
765 | |
766 | - dbg_gen("dir ino %lu, f_pos %#llx", dir->i_ino, file->f_pos); |
767 | + dbg_gen("dir ino %lu, f_pos %#llx", dir->i_ino, pos); |
768 | |
769 | - if (file->f_pos > UBIFS_S_KEY_HASH_MASK || file->f_pos == 2) |
770 | + if (pos > UBIFS_S_KEY_HASH_MASK || pos == 2) |
771 | /* |
772 | * The directory was seek'ed to a senseless position or there |
773 | * are no more entries. |
774 | */ |
775 | return 0; |
776 | |
777 | + if (file->f_version == 0) { |
778 | + /* |
779 | + * The file was seek'ed, which means that @file->private_data |
780 | + * is now invalid. This may also be just the first |
781 | + * 'ubifs_readdir()' invocation, in which case |
782 | + * @file->private_data is NULL, and the below code is |
783 | + * basically a no-op. |
784 | + */ |
785 | + kfree(file->private_data); |
786 | + file->private_data = NULL; |
787 | + } |
788 | + |
789 | + /* |
790 | + * 'generic_file_llseek()' unconditionally sets @file->f_version to |
791 | + * zero, and we use this for detecting whether the file was seek'ed. |
792 | + */ |
793 | + file->f_version = 1; |
794 | + |
795 | /* File positions 0 and 1 correspond to "." and ".." */ |
796 | - if (file->f_pos == 0) { |
797 | + if (pos == 0) { |
798 | ubifs_assert(!file->private_data); |
799 | over = filldir(dirent, ".", 1, 0, dir->i_ino, DT_DIR); |
800 | if (over) |
801 | return 0; |
802 | - file->f_pos = 1; |
803 | + file->f_pos = pos = 1; |
804 | } |
805 | |
806 | - if (file->f_pos == 1) { |
807 | + if (pos == 1) { |
808 | ubifs_assert(!file->private_data); |
809 | over = filldir(dirent, "..", 2, 1, |
810 | parent_ino(file->f_path.dentry), DT_DIR); |
811 | @@ -389,7 +408,7 @@ static int ubifs_readdir(struct file *file, void *dirent, filldir_t filldir) |
812 | goto out; |
813 | } |
814 | |
815 | - file->f_pos = key_hash_flash(c, &dent->key); |
816 | + file->f_pos = pos = key_hash_flash(c, &dent->key); |
817 | file->private_data = dent; |
818 | } |
819 | |
820 | @@ -397,17 +416,16 @@ static int ubifs_readdir(struct file *file, void *dirent, filldir_t filldir) |
821 | if (!dent) { |
822 | /* |
823 | * The directory was seek'ed to and is now readdir'ed. |
824 | - * Find the entry corresponding to @file->f_pos or the |
825 | - * closest one. |
826 | + * Find the entry corresponding to @pos or the closest one. |
827 | */ |
828 | - dent_key_init_hash(c, &key, dir->i_ino, file->f_pos); |
829 | + dent_key_init_hash(c, &key, dir->i_ino, pos); |
830 | nm.name = NULL; |
831 | dent = ubifs_tnc_next_ent(c, &key, &nm); |
832 | if (IS_ERR(dent)) { |
833 | err = PTR_ERR(dent); |
834 | goto out; |
835 | } |
836 | - file->f_pos = key_hash_flash(c, &dent->key); |
837 | + file->f_pos = pos = key_hash_flash(c, &dent->key); |
838 | file->private_data = dent; |
839 | } |
840 | |
841 | @@ -419,7 +437,7 @@ static int ubifs_readdir(struct file *file, void *dirent, filldir_t filldir) |
842 | ubifs_inode(dir)->creat_sqnum); |
843 | |
844 | nm.len = le16_to_cpu(dent->nlen); |
845 | - over = filldir(dirent, dent->name, nm.len, file->f_pos, |
846 | + over = filldir(dirent, dent->name, nm.len, pos, |
847 | le64_to_cpu(dent->inum), |
848 | vfs_dent_type(dent->type)); |
849 | if (over) |
850 | @@ -435,9 +453,17 @@ static int ubifs_readdir(struct file *file, void *dirent, filldir_t filldir) |
851 | } |
852 | |
853 | kfree(file->private_data); |
854 | - file->f_pos = key_hash_flash(c, &dent->key); |
855 | + file->f_pos = pos = key_hash_flash(c, &dent->key); |
856 | file->private_data = dent; |
857 | cond_resched(); |
858 | + |
859 | + if (file->f_version == 0) |
860 | + /* |
861 | + * The file was seek'ed meanwhile, lets return and start |
862 | + * reading direntries from the new position on the next |
863 | + * invocation. |
864 | + */ |
865 | + return 0; |
866 | } |
867 | |
868 | out: |
869 | @@ -448,15 +474,13 @@ out: |
870 | |
871 | kfree(file->private_data); |
872 | file->private_data = NULL; |
873 | + /* 2 is a special value indicating that there are no more direntries */ |
874 | file->f_pos = 2; |
875 | return 0; |
876 | } |
877 | |
878 | -/* If a directory is seeked, we have to free saved readdir() state */ |
879 | static loff_t ubifs_dir_llseek(struct file *file, loff_t offset, int whence) |
880 | { |
881 | - kfree(file->private_data); |
882 | - file->private_data = NULL; |
883 | return generic_file_llseek(file, offset, whence); |
884 | } |
885 | |
886 | diff --git a/kernel/events/hw_breakpoint.c b/kernel/events/hw_breakpoint.c |
887 | index a64f8ae..20185ea 100644 |
888 | --- a/kernel/events/hw_breakpoint.c |
889 | +++ b/kernel/events/hw_breakpoint.c |
890 | @@ -120,7 +120,7 @@ static int task_bp_pinned(int cpu, struct perf_event *bp, enum bp_type_idx type) |
891 | list_for_each_entry(iter, &bp_task_head, hw.bp_list) { |
892 | if (iter->hw.bp_target == tsk && |
893 | find_slot_idx(iter) == type && |
894 | - cpu == iter->cpu) |
895 | + (iter->cpu < 0 || cpu == iter->cpu)) |
896 | count += hw_breakpoint_weight(iter); |
897 | } |
898 | |
899 | @@ -149,7 +149,7 @@ fetch_bp_busy_slots(struct bp_busy_slots *slots, struct perf_event *bp, |
900 | return; |
901 | } |
902 | |
903 | - for_each_online_cpu(cpu) { |
904 | + for_each_possible_cpu(cpu) { |
905 | unsigned int nr; |
906 | |
907 | nr = per_cpu(nr_cpu_bp_pinned[type], cpu); |
908 | @@ -235,7 +235,7 @@ toggle_bp_slot(struct perf_event *bp, bool enable, enum bp_type_idx type, |
909 | if (cpu >= 0) { |
910 | toggle_bp_task_slot(bp, cpu, enable, type, weight); |
911 | } else { |
912 | - for_each_online_cpu(cpu) |
913 | + for_each_possible_cpu(cpu) |
914 | toggle_bp_task_slot(bp, cpu, enable, type, weight); |
915 | } |
916 | |
917 | diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c |
918 | index c5f9cd6..04b32e1 100644 |
919 | --- a/net/bluetooth/l2cap_core.c |
920 | +++ b/net/bluetooth/l2cap_core.c |
921 | @@ -2743,6 +2743,9 @@ static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn, u8 code, |
922 | BT_DBG("conn %p, code 0x%2.2x, ident 0x%2.2x, len %u", |
923 | conn, code, ident, dlen); |
924 | |
925 | + if (conn->mtu < L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE) |
926 | + return NULL; |
927 | + |
928 | len = L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE + dlen; |
929 | count = min_t(unsigned int, conn->mtu, len); |
930 | |
931 | @@ -4221,7 +4224,7 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn, |
932 | struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) data; |
933 | u16 type, result; |
934 | |
935 | - if (cmd_len != sizeof(*rsp)) |
936 | + if (cmd_len < sizeof(*rsp)) |
937 | return -EPROTO; |
938 | |
939 | type = __le16_to_cpu(rsp->type); |
940 | diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c |
941 | index 2b6c226..a560ae0 100644 |
942 | --- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c |
943 | +++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c |
944 | @@ -204,7 +204,7 @@ static unsigned int __ipv6_conntrack_in(struct net *net, |
945 | if (ct != NULL && !nf_ct_is_untracked(ct)) { |
946 | help = nfct_help(ct); |
947 | if ((help && help->helper) || !nf_ct_is_confirmed(ct)) { |
948 | - nf_conntrack_get_reasm(skb); |
949 | + nf_conntrack_get_reasm(reasm); |
950 | NF_HOOK_THRESH(NFPROTO_IPV6, hooknum, reasm, |
951 | (struct net_device *)in, |
952 | (struct net_device *)out, |
953 | diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h |
954 | index 5672533..4e74cd6 100644 |
955 | --- a/net/mac80211/ieee80211_i.h |
956 | +++ b/net/mac80211/ieee80211_i.h |
957 | @@ -1520,9 +1520,9 @@ static inline void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, |
958 | ieee80211_tx_skb_tid(sdata, skb, 7); |
959 | } |
960 | |
961 | -void ieee802_11_parse_elems(u8 *start, size_t len, |
962 | +void ieee802_11_parse_elems(const u8 *start, size_t len, |
963 | struct ieee802_11_elems *elems); |
964 | -u32 ieee802_11_parse_elems_crc(u8 *start, size_t len, |
965 | +u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, |
966 | struct ieee802_11_elems *elems, |
967 | u64 filter, u32 crc); |
968 | u32 ieee80211_mandatory_rates(struct ieee80211_local *local, |
969 | diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c |
970 | index 0a60f40..9726603 100644 |
971 | --- a/net/mac80211/mlme.c |
972 | +++ b/net/mac80211/mlme.c |
973 | @@ -2422,8 +2422,11 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, |
974 | u16 capab_info, aid; |
975 | struct ieee802_11_elems elems; |
976 | struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf; |
977 | + const struct cfg80211_bss_ies *bss_ies = NULL; |
978 | + struct ieee80211_mgd_assoc_data *assoc_data = ifmgd->assoc_data; |
979 | u32 changed = 0; |
980 | int err; |
981 | + bool ret; |
982 | |
983 | /* AssocResp and ReassocResp have identical structure */ |
984 | |
985 | @@ -2455,21 +2458,86 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, |
986 | ifmgd->aid = aid; |
987 | |
988 | /* |
989 | + * Some APs are erroneously not including some information in their |
990 | + * (re)association response frames. Try to recover by using the data |
991 | + * from the beacon or probe response. This seems to afflict mobile |
992 | + * 2G/3G/4G wifi routers, reported models include the "Onda PN51T", |
993 | + * "Vodafone PocketWiFi 2", "ZTE MF60" and a similar T-Mobile device. |
994 | + */ |
995 | + if ((assoc_data->wmm && !elems.wmm_param) || |
996 | + (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT) && |
997 | + (!elems.ht_cap_elem || !elems.ht_operation)) || |
998 | + (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT) && |
999 | + (!elems.vht_cap_elem || !elems.vht_operation))) { |
1000 | + const struct cfg80211_bss_ies *ies; |
1001 | + struct ieee802_11_elems bss_elems; |
1002 | + |
1003 | + rcu_read_lock(); |
1004 | + ies = rcu_dereference(cbss->ies); |
1005 | + if (ies) |
1006 | + bss_ies = kmemdup(ies, sizeof(*ies) + ies->len, |
1007 | + GFP_ATOMIC); |
1008 | + rcu_read_unlock(); |
1009 | + if (!bss_ies) |
1010 | + return false; |
1011 | + |
1012 | + ieee802_11_parse_elems(bss_ies->data, bss_ies->len, |
1013 | + &bss_elems); |
1014 | + if (assoc_data->wmm && |
1015 | + !elems.wmm_param && bss_elems.wmm_param) { |
1016 | + elems.wmm_param = bss_elems.wmm_param; |
1017 | + sdata_info(sdata, |
1018 | + "AP bug: WMM param missing from AssocResp\n"); |
1019 | + } |
1020 | + |
1021 | + /* |
1022 | + * Also check if we requested HT/VHT, otherwise the AP doesn't |
1023 | + * have to include the IEs in the (re)association response. |
1024 | + */ |
1025 | + if (!elems.ht_cap_elem && bss_elems.ht_cap_elem && |
1026 | + !(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) { |
1027 | + elems.ht_cap_elem = bss_elems.ht_cap_elem; |
1028 | + sdata_info(sdata, |
1029 | + "AP bug: HT capability missing from AssocResp\n"); |
1030 | + } |
1031 | + if (!elems.ht_operation && bss_elems.ht_operation && |
1032 | + !(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) { |
1033 | + elems.ht_operation = bss_elems.ht_operation; |
1034 | + sdata_info(sdata, |
1035 | + "AP bug: HT operation missing from AssocResp\n"); |
1036 | + } |
1037 | + if (!elems.vht_cap_elem && bss_elems.vht_cap_elem && |
1038 | + !(ifmgd->flags & IEEE80211_STA_DISABLE_VHT)) { |
1039 | + elems.vht_cap_elem = bss_elems.vht_cap_elem; |
1040 | + sdata_info(sdata, |
1041 | + "AP bug: VHT capa missing from AssocResp\n"); |
1042 | + } |
1043 | + if (!elems.vht_operation && bss_elems.vht_operation && |
1044 | + !(ifmgd->flags & IEEE80211_STA_DISABLE_VHT)) { |
1045 | + elems.vht_operation = bss_elems.vht_operation; |
1046 | + sdata_info(sdata, |
1047 | + "AP bug: VHT operation missing from AssocResp\n"); |
1048 | + } |
1049 | + } |
1050 | + |
1051 | + /* |
1052 | * We previously checked these in the beacon/probe response, so |
1053 | * they should be present here. This is just a safety net. |
1054 | */ |
1055 | if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT) && |
1056 | (!elems.wmm_param || !elems.ht_cap_elem || !elems.ht_operation)) { |
1057 | sdata_info(sdata, |
1058 | - "HT AP is missing WMM params or HT capability/operation in AssocResp\n"); |
1059 | - return false; |
1060 | + "HT AP is missing WMM params or HT capability/operation\n"); |
1061 | + ret = false; |
1062 | + goto out; |
1063 | } |
1064 | |
1065 | if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT) && |
1066 | (!elems.vht_cap_elem || !elems.vht_operation)) { |
1067 | sdata_info(sdata, |
1068 | - "VHT AP is missing VHT capability/operation in AssocResp\n"); |
1069 | - return false; |
1070 | + "VHT AP is missing VHT capability/operation\n"); |
1071 | + ret = false; |
1072 | + goto out; |
1073 | } |
1074 | |
1075 | mutex_lock(&sdata->local->sta_mtx); |
1076 | @@ -2480,7 +2548,8 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, |
1077 | sta = sta_info_get(sdata, cbss->bssid); |
1078 | if (WARN_ON(!sta)) { |
1079 | mutex_unlock(&sdata->local->sta_mtx); |
1080 | - return false; |
1081 | + ret = false; |
1082 | + goto out; |
1083 | } |
1084 | |
1085 | sband = local->hw.wiphy->bands[ieee80211_get_sdata_band(sdata)]; |
1086 | @@ -2533,7 +2602,8 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, |
1087 | sta->sta.addr); |
1088 | WARN_ON(__sta_info_destroy(sta)); |
1089 | mutex_unlock(&sdata->local->sta_mtx); |
1090 | - return false; |
1091 | + ret = false; |
1092 | + goto out; |
1093 | } |
1094 | |
1095 | mutex_unlock(&sdata->local->sta_mtx); |
1096 | @@ -2573,7 +2643,10 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, |
1097 | ieee80211_sta_rx_notify(sdata, (struct ieee80211_hdr *)mgmt); |
1098 | ieee80211_sta_reset_beacon_monitor(sdata); |
1099 | |
1100 | - return true; |
1101 | + ret = true; |
1102 | + out: |
1103 | + kfree(bss_ies); |
1104 | + return ret; |
1105 | } |
1106 | |
1107 | static enum rx_mgmt_action __must_check |
1108 | diff --git a/net/mac80211/util.c b/net/mac80211/util.c |
1109 | index 0f38f43..1f4b908 100644 |
1110 | --- a/net/mac80211/util.c |
1111 | +++ b/net/mac80211/util.c |
1112 | @@ -626,12 +626,12 @@ void ieee80211_queue_delayed_work(struct ieee80211_hw *hw, |
1113 | } |
1114 | EXPORT_SYMBOL(ieee80211_queue_delayed_work); |
1115 | |
1116 | -u32 ieee802_11_parse_elems_crc(u8 *start, size_t len, |
1117 | +u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, |
1118 | struct ieee802_11_elems *elems, |
1119 | u64 filter, u32 crc) |
1120 | { |
1121 | size_t left = len; |
1122 | - u8 *pos = start; |
1123 | + const u8 *pos = start; |
1124 | bool calc_crc = filter != 0; |
1125 | DECLARE_BITMAP(seen_elems, 256); |
1126 | |
1127 | @@ -877,7 +877,7 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len, |
1128 | return crc; |
1129 | } |
1130 | |
1131 | -void ieee802_11_parse_elems(u8 *start, size_t len, |
1132 | +void ieee802_11_parse_elems(const u8 *start, size_t len, |
1133 | struct ieee802_11_elems *elems) |
1134 | { |
1135 | ieee802_11_parse_elems_crc(start, len, elems, 0, 0); |