diff options
Diffstat (limited to 'net')
| -rw-r--r-- | net/8021q/vlan_core.c | 4 | ||||
| -rw-r--r-- | net/caif/cfrfml.c | 2 | ||||
| -rw-r--r-- | net/caif/cfveil.c | 2 | ||||
| -rw-r--r-- | net/core/dev.c | 25 | ||||
| -rw-r--r-- | net/core/gen_estimator.c | 15 | ||||
| -rw-r--r-- | net/core/pktgen.c | 2 | ||||
| -rw-r--r-- | net/ipv4/ipmr.c | 4 | ||||
| -rw-r--r-- | net/ipv6/icmp.c | 4 | ||||
| -rw-r--r-- | net/ipv6/ip6mr.c | 6 | ||||
| -rw-r--r-- | net/ipv6/mcast.c | 5 | ||||
| -rw-r--r-- | net/mac80211/driver-ops.h | 2 | ||||
| -rw-r--r-- | net/mac80211/mlme.c | 92 | ||||
| -rw-r--r-- | net/mac80211/rx.c | 3 |
13 files changed, 134 insertions, 32 deletions
diff --git a/net/8021q/vlan_core.c b/net/8021q/vlan_core.c index bd537fc10254..50f58f5f1c34 100644 --- a/net/8021q/vlan_core.c +++ b/net/8021q/vlan_core.c | |||
| @@ -12,7 +12,7 @@ int __vlan_hwaccel_rx(struct sk_buff *skb, struct vlan_group *grp, | |||
| 12 | return NET_RX_DROP; | 12 | return NET_RX_DROP; |
| 13 | 13 | ||
| 14 | if (skb_bond_should_drop(skb, ACCESS_ONCE(skb->dev->master))) | 14 | if (skb_bond_should_drop(skb, ACCESS_ONCE(skb->dev->master))) |
| 15 | goto drop; | 15 | skb->deliver_no_wcard = 1; |
| 16 | 16 | ||
| 17 | skb->skb_iif = skb->dev->ifindex; | 17 | skb->skb_iif = skb->dev->ifindex; |
| 18 | __vlan_hwaccel_put_tag(skb, vlan_tci); | 18 | __vlan_hwaccel_put_tag(skb, vlan_tci); |
| @@ -84,7 +84,7 @@ vlan_gro_common(struct napi_struct *napi, struct vlan_group *grp, | |||
| 84 | struct sk_buff *p; | 84 | struct sk_buff *p; |
| 85 | 85 | ||
| 86 | if (skb_bond_should_drop(skb, ACCESS_ONCE(skb->dev->master))) | 86 | if (skb_bond_should_drop(skb, ACCESS_ONCE(skb->dev->master))) |
| 87 | goto drop; | 87 | skb->deliver_no_wcard = 1; |
| 88 | 88 | ||
| 89 | skb->skb_iif = skb->dev->ifindex; | 89 | skb->skb_iif = skb->dev->ifindex; |
| 90 | __vlan_hwaccel_put_tag(skb, vlan_tci); | 90 | __vlan_hwaccel_put_tag(skb, vlan_tci); |
diff --git a/net/caif/cfrfml.c b/net/caif/cfrfml.c index cd2830fec935..fd27b172fb5d 100644 --- a/net/caif/cfrfml.c +++ b/net/caif/cfrfml.c | |||
| @@ -83,7 +83,7 @@ static int cfrfml_transmit(struct cflayer *layr, struct cfpkt *pkt) | |||
| 83 | if (!cfsrvl_ready(service, &ret)) | 83 | if (!cfsrvl_ready(service, &ret)) |
| 84 | return ret; | 84 | return ret; |
| 85 | 85 | ||
| 86 | if (!cfpkt_getlen(pkt) > CAIF_MAX_PAYLOAD_SIZE) { | 86 | if (cfpkt_getlen(pkt) > CAIF_MAX_PAYLOAD_SIZE) { |
| 87 | pr_err("CAIF: %s():Packet too large - size=%d\n", | 87 | pr_err("CAIF: %s():Packet too large - size=%d\n", |
| 88 | __func__, cfpkt_getlen(pkt)); | 88 | __func__, cfpkt_getlen(pkt)); |
| 89 | return -EOVERFLOW; | 89 | return -EOVERFLOW; |
diff --git a/net/caif/cfveil.c b/net/caif/cfveil.c index 0fd827f49491..e04f7d964e83 100644 --- a/net/caif/cfveil.c +++ b/net/caif/cfveil.c | |||
| @@ -84,7 +84,7 @@ static int cfvei_transmit(struct cflayer *layr, struct cfpkt *pkt) | |||
| 84 | return ret; | 84 | return ret; |
| 85 | caif_assert(layr->dn != NULL); | 85 | caif_assert(layr->dn != NULL); |
| 86 | caif_assert(layr->dn->transmit != NULL); | 86 | caif_assert(layr->dn->transmit != NULL); |
| 87 | if (!cfpkt_getlen(pkt) > CAIF_MAX_PAYLOAD_SIZE) { | 87 | if (cfpkt_getlen(pkt) > CAIF_MAX_PAYLOAD_SIZE) { |
| 88 | pr_warning("CAIF: %s(): Packet too large - size=%d\n", | 88 | pr_warning("CAIF: %s(): Packet too large - size=%d\n", |
| 89 | __func__, cfpkt_getlen(pkt)); | 89 | __func__, cfpkt_getlen(pkt)); |
| 90 | return -EOVERFLOW; | 90 | return -EOVERFLOW; |
diff --git a/net/core/dev.c b/net/core/dev.c index d03470f5260a..2b3bf53bc687 100644 --- a/net/core/dev.c +++ b/net/core/dev.c | |||
| @@ -2253,11 +2253,9 @@ static int get_rps_cpu(struct net_device *dev, struct sk_buff *skb, | |||
| 2253 | if (skb_rx_queue_recorded(skb)) { | 2253 | if (skb_rx_queue_recorded(skb)) { |
| 2254 | u16 index = skb_get_rx_queue(skb); | 2254 | u16 index = skb_get_rx_queue(skb); |
| 2255 | if (unlikely(index >= dev->num_rx_queues)) { | 2255 | if (unlikely(index >= dev->num_rx_queues)) { |
| 2256 | if (net_ratelimit()) { | 2256 | WARN_ONCE(dev->num_rx_queues > 1, "%s received packet " |
| 2257 | pr_warning("%s received packet on queue " | 2257 | "on queue %u, but number of RX queues is %u\n", |
| 2258 | "%u, but number of RX queues is %u\n", | 2258 | dev->name, index, dev->num_rx_queues); |
| 2259 | dev->name, index, dev->num_rx_queues); | ||
| 2260 | } | ||
| 2261 | goto done; | 2259 | goto done; |
| 2262 | } | 2260 | } |
| 2263 | rxqueue = dev->_rx + index; | 2261 | rxqueue = dev->_rx + index; |
| @@ -2812,13 +2810,24 @@ static int __netif_receive_skb(struct sk_buff *skb) | |||
| 2812 | if (!skb->skb_iif) | 2810 | if (!skb->skb_iif) |
| 2813 | skb->skb_iif = skb->dev->ifindex; | 2811 | skb->skb_iif = skb->dev->ifindex; |
| 2814 | 2812 | ||
| 2813 | /* | ||
| 2814 | * bonding note: skbs received on inactive slaves should only | ||
| 2815 | * be delivered to pkt handlers that are exact matches. Also | ||
| 2816 | * the deliver_no_wcard flag will be set. If packet handlers | ||
| 2817 | * are sensitive to duplicate packets these skbs will need to | ||
| 2818 | * be dropped at the handler. The vlan accel path may have | ||
| 2819 | * already set the deliver_no_wcard flag. | ||
| 2820 | */ | ||
| 2815 | null_or_orig = NULL; | 2821 | null_or_orig = NULL; |
| 2816 | orig_dev = skb->dev; | 2822 | orig_dev = skb->dev; |
| 2817 | master = ACCESS_ONCE(orig_dev->master); | 2823 | master = ACCESS_ONCE(orig_dev->master); |
| 2818 | if (master) { | 2824 | if (skb->deliver_no_wcard) |
| 2819 | if (skb_bond_should_drop(skb, master)) | 2825 | null_or_orig = orig_dev; |
| 2826 | else if (master) { | ||
| 2827 | if (skb_bond_should_drop(skb, master)) { | ||
| 2828 | skb->deliver_no_wcard = 1; | ||
| 2820 | null_or_orig = orig_dev; /* deliver only exact match */ | 2829 | null_or_orig = orig_dev; /* deliver only exact match */ |
| 2821 | else | 2830 | } else |
| 2822 | skb->dev = master; | 2831 | skb->dev = master; |
| 2823 | } | 2832 | } |
| 2824 | 2833 | ||
diff --git a/net/core/gen_estimator.c b/net/core/gen_estimator.c index cf8e70392fe0..785e5276a300 100644 --- a/net/core/gen_estimator.c +++ b/net/core/gen_estimator.c | |||
| @@ -107,6 +107,7 @@ static DEFINE_RWLOCK(est_lock); | |||
| 107 | 107 | ||
| 108 | /* Protects against soft lockup during large deletion */ | 108 | /* Protects against soft lockup during large deletion */ |
| 109 | static struct rb_root est_root = RB_ROOT; | 109 | static struct rb_root est_root = RB_ROOT; |
| 110 | static DEFINE_SPINLOCK(est_tree_lock); | ||
| 110 | 111 | ||
| 111 | static void est_timer(unsigned long arg) | 112 | static void est_timer(unsigned long arg) |
| 112 | { | 113 | { |
| @@ -201,7 +202,6 @@ struct gen_estimator *gen_find_node(const struct gnet_stats_basic_packed *bstats | |||
| 201 | * | 202 | * |
| 202 | * Returns 0 on success or a negative error code. | 203 | * Returns 0 on success or a negative error code. |
| 203 | * | 204 | * |
| 204 | * NOTE: Called under rtnl_mutex | ||
| 205 | */ | 205 | */ |
| 206 | int gen_new_estimator(struct gnet_stats_basic_packed *bstats, | 206 | int gen_new_estimator(struct gnet_stats_basic_packed *bstats, |
| 207 | struct gnet_stats_rate_est *rate_est, | 207 | struct gnet_stats_rate_est *rate_est, |
| @@ -232,6 +232,7 @@ int gen_new_estimator(struct gnet_stats_basic_packed *bstats, | |||
| 232 | est->last_packets = bstats->packets; | 232 | est->last_packets = bstats->packets; |
| 233 | est->avpps = rate_est->pps<<10; | 233 | est->avpps = rate_est->pps<<10; |
| 234 | 234 | ||
| 235 | spin_lock(&est_tree_lock); | ||
| 235 | if (!elist[idx].timer.function) { | 236 | if (!elist[idx].timer.function) { |
| 236 | INIT_LIST_HEAD(&elist[idx].list); | 237 | INIT_LIST_HEAD(&elist[idx].list); |
| 237 | setup_timer(&elist[idx].timer, est_timer, idx); | 238 | setup_timer(&elist[idx].timer, est_timer, idx); |
| @@ -242,6 +243,7 @@ int gen_new_estimator(struct gnet_stats_basic_packed *bstats, | |||
| 242 | 243 | ||
| 243 | list_add_rcu(&est->list, &elist[idx].list); | 244 | list_add_rcu(&est->list, &elist[idx].list); |
| 244 | gen_add_node(est); | 245 | gen_add_node(est); |
| 246 | spin_unlock(&est_tree_lock); | ||
| 245 | 247 | ||
| 246 | return 0; | 248 | return 0; |
| 247 | } | 249 | } |
| @@ -261,13 +263,13 @@ static void __gen_kill_estimator(struct rcu_head *head) | |||
| 261 | * | 263 | * |
| 262 | * Removes the rate estimator specified by &bstats and &rate_est. | 264 | * Removes the rate estimator specified by &bstats and &rate_est. |
| 263 | * | 265 | * |
| 264 | * NOTE: Called under rtnl_mutex | ||
| 265 | */ | 266 | */ |
| 266 | void gen_kill_estimator(struct gnet_stats_basic_packed *bstats, | 267 | void gen_kill_estimator(struct gnet_stats_basic_packed *bstats, |
| 267 | struct gnet_stats_rate_est *rate_est) | 268 | struct gnet_stats_rate_est *rate_est) |
| 268 | { | 269 | { |
| 269 | struct gen_estimator *e; | 270 | struct gen_estimator *e; |
| 270 | 271 | ||
| 272 | spin_lock(&est_tree_lock); | ||
| 271 | while ((e = gen_find_node(bstats, rate_est))) { | 273 | while ((e = gen_find_node(bstats, rate_est))) { |
| 272 | rb_erase(&e->node, &est_root); | 274 | rb_erase(&e->node, &est_root); |
| 273 | 275 | ||
| @@ -278,6 +280,7 @@ void gen_kill_estimator(struct gnet_stats_basic_packed *bstats, | |||
| 278 | list_del_rcu(&e->list); | 280 | list_del_rcu(&e->list); |
| 279 | call_rcu(&e->e_rcu, __gen_kill_estimator); | 281 | call_rcu(&e->e_rcu, __gen_kill_estimator); |
| 280 | } | 282 | } |
| 283 | spin_unlock(&est_tree_lock); | ||
| 281 | } | 284 | } |
| 282 | EXPORT_SYMBOL(gen_kill_estimator); | 285 | EXPORT_SYMBOL(gen_kill_estimator); |
| 283 | 286 | ||
| @@ -312,8 +315,14 @@ EXPORT_SYMBOL(gen_replace_estimator); | |||
| 312 | bool gen_estimator_active(const struct gnet_stats_basic_packed *bstats, | 315 | bool gen_estimator_active(const struct gnet_stats_basic_packed *bstats, |
| 313 | const struct gnet_stats_rate_est *rate_est) | 316 | const struct gnet_stats_rate_est *rate_est) |
| 314 | { | 317 | { |
| 318 | bool res; | ||
| 319 | |||
| 315 | ASSERT_RTNL(); | 320 | ASSERT_RTNL(); |
| 316 | 321 | ||
| 317 | return gen_find_node(bstats, rate_est) != NULL; | 322 | spin_lock(&est_tree_lock); |
| 323 | res = gen_find_node(bstats, rate_est) != NULL; | ||
| 324 | spin_unlock(&est_tree_lock); | ||
| 325 | |||
| 326 | return res; | ||
| 318 | } | 327 | } |
| 319 | EXPORT_SYMBOL(gen_estimator_active); | 328 | EXPORT_SYMBOL(gen_estimator_active); |
diff --git a/net/core/pktgen.c b/net/core/pktgen.c index 2ad68da418df..1dacd7ba8dbb 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c | |||
| @@ -2170,7 +2170,7 @@ static void spin(struct pktgen_dev *pkt_dev, ktime_t spin_until) | |||
| 2170 | end_time = ktime_now(); | 2170 | end_time = ktime_now(); |
| 2171 | 2171 | ||
| 2172 | pkt_dev->idle_acc += ktime_to_ns(ktime_sub(end_time, start_time)); | 2172 | pkt_dev->idle_acc += ktime_to_ns(ktime_sub(end_time, start_time)); |
| 2173 | pkt_dev->next_tx = ktime_add_ns(end_time, pkt_dev->delay); | 2173 | pkt_dev->next_tx = ktime_add_ns(spin_until, pkt_dev->delay); |
| 2174 | } | 2174 | } |
| 2175 | 2175 | ||
| 2176 | static inline void set_pkt_overhead(struct pktgen_dev *pkt_dev) | 2176 | static inline void set_pkt_overhead(struct pktgen_dev *pkt_dev) |
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index 856123fe32f9..757f25eb9b4b 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c | |||
| @@ -267,8 +267,10 @@ static void __net_exit ipmr_rules_exit(struct net *net) | |||
| 267 | { | 267 | { |
| 268 | struct mr_table *mrt, *next; | 268 | struct mr_table *mrt, *next; |
| 269 | 269 | ||
| 270 | list_for_each_entry_safe(mrt, next, &net->ipv4.mr_tables, list) | 270 | list_for_each_entry_safe(mrt, next, &net->ipv4.mr_tables, list) { |
| 271 | list_del(&mrt->list); | ||
| 271 | kfree(mrt); | 272 | kfree(mrt); |
| 273 | } | ||
| 272 | fib_rules_unregister(net->ipv4.mr_rules_ops); | 274 | fib_rules_unregister(net->ipv4.mr_rules_ops); |
| 273 | } | 275 | } |
| 274 | #else | 276 | #else |
diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index ce7992982557..03e62f94ff8e 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c | |||
| @@ -483,7 +483,7 @@ route_done: | |||
| 483 | np->tclass, NULL, &fl, (struct rt6_info*)dst, | 483 | np->tclass, NULL, &fl, (struct rt6_info*)dst, |
| 484 | MSG_DONTWAIT, np->dontfrag); | 484 | MSG_DONTWAIT, np->dontfrag); |
| 485 | if (err) { | 485 | if (err) { |
| 486 | ICMP6_INC_STATS_BH(net, idev, ICMP6_MIB_OUTMSGS); | 486 | ICMP6_INC_STATS_BH(net, idev, ICMP6_MIB_OUTERRORS); |
| 487 | ip6_flush_pending_frames(sk); | 487 | ip6_flush_pending_frames(sk); |
| 488 | goto out_put; | 488 | goto out_put; |
| 489 | } | 489 | } |
| @@ -565,7 +565,7 @@ static void icmpv6_echo_reply(struct sk_buff *skb) | |||
| 565 | np->dontfrag); | 565 | np->dontfrag); |
| 566 | 566 | ||
| 567 | if (err) { | 567 | if (err) { |
| 568 | ICMP6_INC_STATS_BH(net, idev, ICMP6_MIB_OUTMSGS); | 568 | ICMP6_INC_STATS_BH(net, idev, ICMP6_MIB_OUTERRORS); |
| 569 | ip6_flush_pending_frames(sk); | 569 | ip6_flush_pending_frames(sk); |
| 570 | goto out_put; | 570 | goto out_put; |
| 571 | } | 571 | } |
diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index 073071f2b75b..66078dad7fe8 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c | |||
| @@ -120,7 +120,7 @@ static void mroute_clean_tables(struct mr6_table *mrt); | |||
| 120 | static void ipmr_expire_process(unsigned long arg); | 120 | static void ipmr_expire_process(unsigned long arg); |
| 121 | 121 | ||
| 122 | #ifdef CONFIG_IPV6_MROUTE_MULTIPLE_TABLES | 122 | #ifdef CONFIG_IPV6_MROUTE_MULTIPLE_TABLES |
| 123 | #define ip6mr_for_each_table(mrt, met) \ | 123 | #define ip6mr_for_each_table(mrt, net) \ |
| 124 | list_for_each_entry_rcu(mrt, &net->ipv6.mr6_tables, list) | 124 | list_for_each_entry_rcu(mrt, &net->ipv6.mr6_tables, list) |
| 125 | 125 | ||
| 126 | static struct mr6_table *ip6mr_get_table(struct net *net, u32 id) | 126 | static struct mr6_table *ip6mr_get_table(struct net *net, u32 id) |
| @@ -254,8 +254,10 @@ static void __net_exit ip6mr_rules_exit(struct net *net) | |||
| 254 | { | 254 | { |
| 255 | struct mr6_table *mrt, *next; | 255 | struct mr6_table *mrt, *next; |
| 256 | 256 | ||
| 257 | list_for_each_entry_safe(mrt, next, &net->ipv6.mr6_tables, list) | 257 | list_for_each_entry_safe(mrt, next, &net->ipv6.mr6_tables, list) { |
| 258 | list_del(&mrt->list); | ||
| 258 | ip6mr_free_table(mrt); | 259 | ip6mr_free_table(mrt); |
| 260 | } | ||
| 259 | fib_rules_unregister(net->ipv6.mr6_rules_ops); | 261 | fib_rules_unregister(net->ipv6.mr6_rules_ops); |
| 260 | } | 262 | } |
| 261 | #else | 263 | #else |
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index 59f1881968c7..ab1622d7d409 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c | |||
| @@ -1356,7 +1356,10 @@ static struct sk_buff *mld_newpack(struct net_device *dev, int size) | |||
| 1356 | IPV6_TLV_PADN, 0 }; | 1356 | IPV6_TLV_PADN, 0 }; |
| 1357 | 1357 | ||
| 1358 | /* we assume size > sizeof(ra) here */ | 1358 | /* we assume size > sizeof(ra) here */ |
| 1359 | skb = sock_alloc_send_skb(sk, size + LL_ALLOCATED_SPACE(dev), 1, &err); | 1359 | size += LL_ALLOCATED_SPACE(dev); |
| 1360 | /* limit our allocations to order-0 page */ | ||
| 1361 | size = min_t(int, size, SKB_MAX_ORDER(0, 0)); | ||
| 1362 | skb = sock_alloc_send_skb(sk, size, 1, &err); | ||
| 1360 | 1363 | ||
| 1361 | if (!skb) | 1364 | if (!skb) |
| 1362 | return NULL; | 1365 | return NULL; |
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 4f2271316650..9c1da0809160 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h | |||
| @@ -349,7 +349,7 @@ static inline int drv_get_survey(struct ieee80211_local *local, int idx, | |||
| 349 | struct survey_info *survey) | 349 | struct survey_info *survey) |
| 350 | { | 350 | { |
| 351 | int ret = -EOPNOTSUPP; | 351 | int ret = -EOPNOTSUPP; |
| 352 | if (local->ops->conf_tx) | 352 | if (local->ops->get_survey) |
| 353 | ret = local->ops->get_survey(&local->hw, idx, survey); | 353 | ret = local->ops->get_survey(&local->hw, idx, survey); |
| 354 | /* trace_drv_get_survey(local, idx, survey, ret); */ | 354 | /* trace_drv_get_survey(local, idx, survey, ret); */ |
| 355 | return ret; | 355 | return ret; |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 0839c4e8fd2e..f803f8b72a93 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
| @@ -1692,14 +1692,52 @@ static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | |||
| 1692 | rma = ieee80211_rx_mgmt_disassoc(sdata, mgmt, skb->len); | 1692 | rma = ieee80211_rx_mgmt_disassoc(sdata, mgmt, skb->len); |
| 1693 | break; | 1693 | break; |
| 1694 | case IEEE80211_STYPE_ACTION: | 1694 | case IEEE80211_STYPE_ACTION: |
| 1695 | if (mgmt->u.action.category != WLAN_CATEGORY_SPECTRUM_MGMT) | 1695 | switch (mgmt->u.action.category) { |
| 1696 | case WLAN_CATEGORY_BACK: { | ||
| 1697 | struct ieee80211_local *local = sdata->local; | ||
| 1698 | int len = skb->len; | ||
| 1699 | struct sta_info *sta; | ||
| 1700 | |||
| 1701 | rcu_read_lock(); | ||
| 1702 | sta = sta_info_get(sdata, mgmt->sa); | ||
| 1703 | if (!sta) { | ||
| 1704 | rcu_read_unlock(); | ||
| 1705 | break; | ||
| 1706 | } | ||
| 1707 | |||
| 1708 | local_bh_disable(); | ||
| 1709 | |||
| 1710 | switch (mgmt->u.action.u.addba_req.action_code) { | ||
| 1711 | case WLAN_ACTION_ADDBA_REQ: | ||
| 1712 | if (len < (IEEE80211_MIN_ACTION_SIZE + | ||
| 1713 | sizeof(mgmt->u.action.u.addba_req))) | ||
| 1714 | break; | ||
| 1715 | ieee80211_process_addba_request(local, sta, mgmt, len); | ||
| 1716 | break; | ||
| 1717 | case WLAN_ACTION_ADDBA_RESP: | ||
| 1718 | if (len < (IEEE80211_MIN_ACTION_SIZE + | ||
| 1719 | sizeof(mgmt->u.action.u.addba_resp))) | ||
| 1720 | break; | ||
| 1721 | ieee80211_process_addba_resp(local, sta, mgmt, len); | ||
| 1722 | break; | ||
| 1723 | case WLAN_ACTION_DELBA: | ||
| 1724 | if (len < (IEEE80211_MIN_ACTION_SIZE + | ||
| 1725 | sizeof(mgmt->u.action.u.delba))) | ||
| 1726 | break; | ||
| 1727 | ieee80211_process_delba(sdata, sta, mgmt, len); | ||
| 1728 | break; | ||
| 1729 | } | ||
| 1730 | local_bh_enable(); | ||
| 1731 | rcu_read_unlock(); | ||
| 1696 | break; | 1732 | break; |
| 1697 | 1733 | } | |
| 1698 | ieee80211_sta_process_chanswitch(sdata, | 1734 | case WLAN_CATEGORY_SPECTRUM_MGMT: |
| 1699 | &mgmt->u.action.u.chan_switch.sw_elem, | 1735 | ieee80211_sta_process_chanswitch(sdata, |
| 1700 | (void *)ifmgd->associated->priv, | 1736 | &mgmt->u.action.u.chan_switch.sw_elem, |
| 1701 | rx_status->mactime); | 1737 | (void *)ifmgd->associated->priv, |
| 1702 | break; | 1738 | rx_status->mactime); |
| 1739 | break; | ||
| 1740 | } | ||
| 1703 | } | 1741 | } |
| 1704 | mutex_unlock(&ifmgd->mtx); | 1742 | mutex_unlock(&ifmgd->mtx); |
| 1705 | 1743 | ||
| @@ -1722,9 +1760,45 @@ static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | |||
| 1722 | mutex_unlock(&ifmgd->mtx); | 1760 | mutex_unlock(&ifmgd->mtx); |
| 1723 | 1761 | ||
| 1724 | if (skb->len >= 24 + 2 /* mgmt + deauth reason */ && | 1762 | if (skb->len >= 24 + 2 /* mgmt + deauth reason */ && |
| 1725 | (fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_DEAUTH) | 1763 | (fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_DEAUTH) { |
| 1726 | cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len); | 1764 | struct ieee80211_local *local = sdata->local; |
| 1765 | struct ieee80211_work *wk; | ||
| 1766 | |||
| 1767 | mutex_lock(&local->work_mtx); | ||
| 1768 | list_for_each_entry(wk, &local->work_list, list) { | ||
| 1769 | if (wk->sdata != sdata) | ||
| 1770 | continue; | ||
| 1771 | |||
| 1772 | if (wk->type != IEEE80211_WORK_ASSOC) | ||
| 1773 | continue; | ||
| 1774 | |||
| 1775 | if (memcmp(mgmt->bssid, wk->filter_ta, ETH_ALEN)) | ||
| 1776 | continue; | ||
| 1777 | if (memcmp(mgmt->sa, wk->filter_ta, ETH_ALEN)) | ||
| 1778 | continue; | ||
| 1727 | 1779 | ||
| 1780 | /* | ||
| 1781 | * Printing the message only here means we can't | ||
| 1782 | * spuriously print it, but it also means that it | ||
| 1783 | * won't be printed when the frame comes in before | ||
| 1784 | * we even tried to associate or in similar cases. | ||
| 1785 | * | ||
| 1786 | * Ultimately, I suspect cfg80211 should print the | ||
| 1787 | * messages instead. | ||
| 1788 | */ | ||
| 1789 | printk(KERN_DEBUG | ||
| 1790 | "%s: deauthenticated from %pM (Reason: %u)\n", | ||
| 1791 | sdata->name, mgmt->bssid, | ||
| 1792 | le16_to_cpu(mgmt->u.deauth.reason_code)); | ||
| 1793 | |||
| 1794 | list_del_rcu(&wk->list); | ||
| 1795 | free_work(wk); | ||
| 1796 | break; | ||
| 1797 | } | ||
| 1798 | mutex_unlock(&local->work_mtx); | ||
| 1799 | |||
| 1800 | cfg80211_send_deauth(sdata->dev, (u8 *)mgmt, skb->len); | ||
| 1801 | } | ||
| 1728 | out: | 1802 | out: |
| 1729 | kfree_skb(skb); | 1803 | kfree_skb(skb); |
| 1730 | } | 1804 | } |
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 5e0b65406c44..be9abc2e6348 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
| @@ -1944,6 +1944,9 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) | |||
| 1944 | if (len < IEEE80211_MIN_ACTION_SIZE + 1) | 1944 | if (len < IEEE80211_MIN_ACTION_SIZE + 1) |
| 1945 | break; | 1945 | break; |
| 1946 | 1946 | ||
| 1947 | if (sdata->vif.type == NL80211_IFTYPE_STATION) | ||
| 1948 | return ieee80211_sta_rx_mgmt(sdata, rx->skb); | ||
| 1949 | |||
| 1947 | switch (mgmt->u.action.u.addba_req.action_code) { | 1950 | switch (mgmt->u.action.u.addba_req.action_code) { |
| 1948 | case WLAN_ACTION_ADDBA_REQ: | 1951 | case WLAN_ACTION_ADDBA_REQ: |
| 1949 | if (len < (IEEE80211_MIN_ACTION_SIZE + | 1952 | if (len < (IEEE80211_MIN_ACTION_SIZE + |
