diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-03-27 21:35:03 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-03-27 21:35:03 -0400 |
commit | 5d80f8e5a9dc9c9a94d4aeaa567e219a808b8a4a (patch) | |
tree | 357258d77e2153ef7409926773655c5f8775a1f3 /net | |
parent | 7b616c8a2f5c8507b4aed6907336ec5b85803a39 (diff) | |
parent | 0870352bc6e0dee485c86a0c99dd60e7089c8917 (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6: (166 commits)
Revert "ax25: zero length frame filtering in AX25"
Revert "netrom: zero length frame filtering in NetRom"
cfg80211: default CONFIG_WIRELESS_OLD_REGULATORY to n
mac80211/iwlwifi: move virtual A-MDPU queue bookkeeping to iwlwifi
mac80211: fix aggregation to not require queue stop
mac80211: add skb length sanity checking
mac80211: unify and fix TX aggregation start
mac80211: clean up __ieee80211_tx args
mac80211: rework the pending packets code
mac80211: fix A-MPDU queue assignment
mac80211: rewrite fragmentation
iwlwifi: show current driver status in user readable format
b43: Add BCM4307 PCI-ID
cfg80211: fix locking in nl80211_set_wiphy
mac80211: fix RX path
ath5k: properly drop packets from ops->tx
ar9170: single module build
ath9k: fix dma mapping leak of rx buffer upon rmmod
rt2x00: New USB ID for rt73usb
ath5k: warn and correct rate for unknown hw rate indexes
...
Diffstat (limited to 'net')
63 files changed, 2246 insertions, 1340 deletions
diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c index 3e0671df3a3f..d6a9243641af 100644 --- a/net/appletalk/ddp.c +++ b/net/appletalk/ddp.c | |||
@@ -1571,14 +1571,10 @@ static int atalk_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr | |||
1571 | usat->sat_family != AF_APPLETALK) | 1571 | usat->sat_family != AF_APPLETALK) |
1572 | return -EINVAL; | 1572 | return -EINVAL; |
1573 | 1573 | ||
1574 | /* netatalk doesn't implement this check */ | 1574 | /* netatalk didn't implement this check */ |
1575 | if (usat->sat_addr.s_node == ATADDR_BCAST && | 1575 | if (usat->sat_addr.s_node == ATADDR_BCAST && |
1576 | !sock_flag(sk, SOCK_BROADCAST)) { | 1576 | !sock_flag(sk, SOCK_BROADCAST)) { |
1577 | printk(KERN_INFO "SO_BROADCAST: Fix your netatalk as " | ||
1578 | "it will break before 2.2\n"); | ||
1579 | #if 0 | ||
1580 | return -EPERM; | 1577 | return -EPERM; |
1581 | #endif | ||
1582 | } | 1578 | } |
1583 | } else { | 1579 | } else { |
1584 | if (sk->sk_state != TCP_ESTABLISHED) | 1580 | if (sk->sk_state != TCP_ESTABLISHED) |
diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c index 7da5ebb84e97..fd9d06f291dc 100644 --- a/net/ax25/af_ax25.c +++ b/net/ax25/af_ax25.c | |||
@@ -1435,11 +1435,6 @@ static int ax25_sendmsg(struct kiocb *iocb, struct socket *sock, | |||
1435 | size_t size; | 1435 | size_t size; |
1436 | int lv, err, addr_len = msg->msg_namelen; | 1436 | int lv, err, addr_len = msg->msg_namelen; |
1437 | 1437 | ||
1438 | /* AX.25 empty data frame has no meaning : don't send */ | ||
1439 | if (len == 0) { | ||
1440 | return (0); | ||
1441 | } | ||
1442 | |||
1443 | if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_EOR|MSG_CMSG_COMPAT)) | 1438 | if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_EOR|MSG_CMSG_COMPAT)) |
1444 | return -EINVAL; | 1439 | return -EINVAL; |
1445 | 1440 | ||
@@ -1639,13 +1634,6 @@ static int ax25_recvmsg(struct kiocb *iocb, struct socket *sock, | |||
1639 | skb_reset_transport_header(skb); | 1634 | skb_reset_transport_header(skb); |
1640 | copied = skb->len; | 1635 | copied = skb->len; |
1641 | 1636 | ||
1642 | /* AX.25 empty data frame has no meaning : ignore it */ | ||
1643 | if (copied == 0) { | ||
1644 | err = copied; | ||
1645 | skb_free_datagram(sk, skb); | ||
1646 | goto out; | ||
1647 | } | ||
1648 | |||
1649 | if (copied > size) { | 1637 | if (copied > size) { |
1650 | copied = size; | 1638 | copied = size; |
1651 | msg->msg_flags |= MSG_TRUNC; | 1639 | msg->msg_flags |= MSG_TRUNC; |
diff --git a/net/core/dev.c b/net/core/dev.c index 052dd478d3e1..63ec4bf89b29 100644 --- a/net/core/dev.c +++ b/net/core/dev.c | |||
@@ -2627,18 +2627,15 @@ static int process_backlog(struct napi_struct *napi, int quota) | |||
2627 | local_irq_disable(); | 2627 | local_irq_disable(); |
2628 | skb = __skb_dequeue(&queue->input_pkt_queue); | 2628 | skb = __skb_dequeue(&queue->input_pkt_queue); |
2629 | if (!skb) { | 2629 | if (!skb) { |
2630 | __napi_complete(napi); | ||
2630 | local_irq_enable(); | 2631 | local_irq_enable(); |
2631 | napi_complete(napi); | 2632 | break; |
2632 | goto out; | ||
2633 | } | 2633 | } |
2634 | local_irq_enable(); | 2634 | local_irq_enable(); |
2635 | 2635 | ||
2636 | napi_gro_receive(napi, skb); | 2636 | netif_receive_skb(skb); |
2637 | } while (++work < quota && jiffies == start_time); | 2637 | } while (++work < quota && jiffies == start_time); |
2638 | 2638 | ||
2639 | napi_gro_flush(napi); | ||
2640 | |||
2641 | out: | ||
2642 | return work; | 2639 | return work; |
2643 | } | 2640 | } |
2644 | 2641 | ||
diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c index 84b9c179df51..35c5f6a5cb7c 100644 --- a/net/ipv4/netfilter/arp_tables.c +++ b/net/ipv4/netfilter/arp_tables.c | |||
@@ -81,19 +81,7 @@ static inline int arp_devaddr_compare(const struct arpt_devaddr_info *ap, | |||
81 | static unsigned long ifname_compare(const char *_a, const char *_b, const char *_mask) | 81 | static unsigned long ifname_compare(const char *_a, const char *_b, const char *_mask) |
82 | { | 82 | { |
83 | #ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS | 83 | #ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS |
84 | const unsigned long *a = (const unsigned long *)_a; | 84 | unsigned long ret = ifname_compare_aligned(_a, _b, _mask); |
85 | const unsigned long *b = (const unsigned long *)_b; | ||
86 | const unsigned long *mask = (const unsigned long *)_mask; | ||
87 | unsigned long ret; | ||
88 | |||
89 | ret = (a[0] ^ b[0]) & mask[0]; | ||
90 | if (IFNAMSIZ > sizeof(unsigned long)) | ||
91 | ret |= (a[1] ^ b[1]) & mask[1]; | ||
92 | if (IFNAMSIZ > 2 * sizeof(unsigned long)) | ||
93 | ret |= (a[2] ^ b[2]) & mask[2]; | ||
94 | if (IFNAMSIZ > 3 * sizeof(unsigned long)) | ||
95 | ret |= (a[3] ^ b[3]) & mask[3]; | ||
96 | BUILD_BUG_ON(IFNAMSIZ > 4 * sizeof(unsigned long)); | ||
97 | #else | 85 | #else |
98 | unsigned long ret = 0; | 86 | unsigned long ret = 0; |
99 | const u16 *a = (const u16 *)_a; | 87 | const u16 *a = (const u16 *)_a; |
@@ -404,7 +392,9 @@ static int mark_source_chains(struct xt_table_info *newinfo, | |||
404 | && unconditional(&e->arp)) || visited) { | 392 | && unconditional(&e->arp)) || visited) { |
405 | unsigned int oldpos, size; | 393 | unsigned int oldpos, size; |
406 | 394 | ||
407 | if (t->verdict < -NF_MAX_VERDICT - 1) { | 395 | if ((strcmp(t->target.u.user.name, |
396 | ARPT_STANDARD_TARGET) == 0) && | ||
397 | t->verdict < -NF_MAX_VERDICT - 1) { | ||
408 | duprintf("mark_source_chains: bad " | 398 | duprintf("mark_source_chains: bad " |
409 | "negative verdict (%i)\n", | 399 | "negative verdict (%i)\n", |
410 | t->verdict); | 400 | t->verdict); |
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index e5294aec967d..82ee7c9049ff 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c | |||
@@ -74,25 +74,6 @@ do { \ | |||
74 | 74 | ||
75 | Hence the start of any table is given by get_table() below. */ | 75 | Hence the start of any table is given by get_table() below. */ |
76 | 76 | ||
77 | static unsigned long ifname_compare(const char *_a, const char *_b, | ||
78 | const unsigned char *_mask) | ||
79 | { | ||
80 | const unsigned long *a = (const unsigned long *)_a; | ||
81 | const unsigned long *b = (const unsigned long *)_b; | ||
82 | const unsigned long *mask = (const unsigned long *)_mask; | ||
83 | unsigned long ret; | ||
84 | |||
85 | ret = (a[0] ^ b[0]) & mask[0]; | ||
86 | if (IFNAMSIZ > sizeof(unsigned long)) | ||
87 | ret |= (a[1] ^ b[1]) & mask[1]; | ||
88 | if (IFNAMSIZ > 2 * sizeof(unsigned long)) | ||
89 | ret |= (a[2] ^ b[2]) & mask[2]; | ||
90 | if (IFNAMSIZ > 3 * sizeof(unsigned long)) | ||
91 | ret |= (a[3] ^ b[3]) & mask[3]; | ||
92 | BUILD_BUG_ON(IFNAMSIZ > 4 * sizeof(unsigned long)); | ||
93 | return ret; | ||
94 | } | ||
95 | |||
96 | /* Returns whether matches rule or not. */ | 77 | /* Returns whether matches rule or not. */ |
97 | /* Performance critical - called for every packet */ | 78 | /* Performance critical - called for every packet */ |
98 | static inline bool | 79 | static inline bool |
@@ -121,7 +102,7 @@ ip_packet_match(const struct iphdr *ip, | |||
121 | return false; | 102 | return false; |
122 | } | 103 | } |
123 | 104 | ||
124 | ret = ifname_compare(indev, ipinfo->iniface, ipinfo->iniface_mask); | 105 | ret = ifname_compare_aligned(indev, ipinfo->iniface, ipinfo->iniface_mask); |
125 | 106 | ||
126 | if (FWINV(ret != 0, IPT_INV_VIA_IN)) { | 107 | if (FWINV(ret != 0, IPT_INV_VIA_IN)) { |
127 | dprintf("VIA in mismatch (%s vs %s).%s\n", | 108 | dprintf("VIA in mismatch (%s vs %s).%s\n", |
@@ -130,7 +111,7 @@ ip_packet_match(const struct iphdr *ip, | |||
130 | return false; | 111 | return false; |
131 | } | 112 | } |
132 | 113 | ||
133 | ret = ifname_compare(outdev, ipinfo->outiface, ipinfo->outiface_mask); | 114 | ret = ifname_compare_aligned(outdev, ipinfo->outiface, ipinfo->outiface_mask); |
134 | 115 | ||
135 | if (FWINV(ret != 0, IPT_INV_VIA_OUT)) { | 116 | if (FWINV(ret != 0, IPT_INV_VIA_OUT)) { |
136 | dprintf("VIA out mismatch (%s vs %s).%s\n", | 117 | dprintf("VIA out mismatch (%s vs %s).%s\n", |
@@ -507,7 +488,9 @@ mark_source_chains(struct xt_table_info *newinfo, | |||
507 | && unconditional(&e->ip)) || visited) { | 488 | && unconditional(&e->ip)) || visited) { |
508 | unsigned int oldpos, size; | 489 | unsigned int oldpos, size; |
509 | 490 | ||
510 | if (t->verdict < -NF_MAX_VERDICT - 1) { | 491 | if ((strcmp(t->target.u.user.name, |
492 | IPT_STANDARD_TARGET) == 0) && | ||
493 | t->verdict < -NF_MAX_VERDICT - 1) { | ||
511 | duprintf("mark_source_chains: bad " | 494 | duprintf("mark_source_chains: bad " |
512 | "negative verdict (%i)\n", | 495 | "negative verdict (%i)\n", |
513 | t->verdict); | 496 | t->verdict); |
diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c index 8b681f24e271..7d2ead7228ac 100644 --- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c +++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c | |||
@@ -328,6 +328,11 @@ static int ipv4_nlattr_to_tuple(struct nlattr *tb[], | |||
328 | 328 | ||
329 | return 0; | 329 | return 0; |
330 | } | 330 | } |
331 | |||
332 | static int ipv4_nlattr_tuple_size(void) | ||
333 | { | ||
334 | return nla_policy_len(ipv4_nla_policy, CTA_IP_MAX + 1); | ||
335 | } | ||
331 | #endif | 336 | #endif |
332 | 337 | ||
333 | static struct nf_sockopt_ops so_getorigdst = { | 338 | static struct nf_sockopt_ops so_getorigdst = { |
@@ -347,6 +352,7 @@ struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv4 __read_mostly = { | |||
347 | .get_l4proto = ipv4_get_l4proto, | 352 | .get_l4proto = ipv4_get_l4proto, |
348 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) | 353 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) |
349 | .tuple_to_nlattr = ipv4_tuple_to_nlattr, | 354 | .tuple_to_nlattr = ipv4_tuple_to_nlattr, |
355 | .nlattr_tuple_size = ipv4_nlattr_tuple_size, | ||
350 | .nlattr_to_tuple = ipv4_nlattr_to_tuple, | 356 | .nlattr_to_tuple = ipv4_nlattr_to_tuple, |
351 | .nla_policy = ipv4_nla_policy, | 357 | .nla_policy = ipv4_nla_policy, |
352 | #endif | 358 | #endif |
diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c index 6ba5c557690c..8668a3defda6 100644 --- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c +++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c | |||
@@ -25,40 +25,42 @@ struct ct_iter_state { | |||
25 | unsigned int bucket; | 25 | unsigned int bucket; |
26 | }; | 26 | }; |
27 | 27 | ||
28 | static struct hlist_node *ct_get_first(struct seq_file *seq) | 28 | static struct hlist_nulls_node *ct_get_first(struct seq_file *seq) |
29 | { | 29 | { |
30 | struct net *net = seq_file_net(seq); | 30 | struct net *net = seq_file_net(seq); |
31 | struct ct_iter_state *st = seq->private; | 31 | struct ct_iter_state *st = seq->private; |
32 | struct hlist_node *n; | 32 | struct hlist_nulls_node *n; |
33 | 33 | ||
34 | for (st->bucket = 0; | 34 | for (st->bucket = 0; |
35 | st->bucket < nf_conntrack_htable_size; | 35 | st->bucket < nf_conntrack_htable_size; |
36 | st->bucket++) { | 36 | st->bucket++) { |
37 | n = rcu_dereference(net->ct.hash[st->bucket].first); | 37 | n = rcu_dereference(net->ct.hash[st->bucket].first); |
38 | if (n) | 38 | if (!is_a_nulls(n)) |
39 | return n; | 39 | return n; |
40 | } | 40 | } |
41 | return NULL; | 41 | return NULL; |
42 | } | 42 | } |
43 | 43 | ||
44 | static struct hlist_node *ct_get_next(struct seq_file *seq, | 44 | static struct hlist_nulls_node *ct_get_next(struct seq_file *seq, |
45 | struct hlist_node *head) | 45 | struct hlist_nulls_node *head) |
46 | { | 46 | { |
47 | struct net *net = seq_file_net(seq); | 47 | struct net *net = seq_file_net(seq); |
48 | struct ct_iter_state *st = seq->private; | 48 | struct ct_iter_state *st = seq->private; |
49 | 49 | ||
50 | head = rcu_dereference(head->next); | 50 | head = rcu_dereference(head->next); |
51 | while (head == NULL) { | 51 | while (is_a_nulls(head)) { |
52 | if (++st->bucket >= nf_conntrack_htable_size) | 52 | if (likely(get_nulls_value(head) == st->bucket)) { |
53 | return NULL; | 53 | if (++st->bucket >= nf_conntrack_htable_size) |
54 | return NULL; | ||
55 | } | ||
54 | head = rcu_dereference(net->ct.hash[st->bucket].first); | 56 | head = rcu_dereference(net->ct.hash[st->bucket].first); |
55 | } | 57 | } |
56 | return head; | 58 | return head; |
57 | } | 59 | } |
58 | 60 | ||
59 | static struct hlist_node *ct_get_idx(struct seq_file *seq, loff_t pos) | 61 | static struct hlist_nulls_node *ct_get_idx(struct seq_file *seq, loff_t pos) |
60 | { | 62 | { |
61 | struct hlist_node *head = ct_get_first(seq); | 63 | struct hlist_nulls_node *head = ct_get_first(seq); |
62 | 64 | ||
63 | if (head) | 65 | if (head) |
64 | while (pos && (head = ct_get_next(seq, head))) | 66 | while (pos && (head = ct_get_next(seq, head))) |
@@ -87,69 +89,76 @@ static void ct_seq_stop(struct seq_file *s, void *v) | |||
87 | 89 | ||
88 | static int ct_seq_show(struct seq_file *s, void *v) | 90 | static int ct_seq_show(struct seq_file *s, void *v) |
89 | { | 91 | { |
90 | const struct nf_conntrack_tuple_hash *hash = v; | 92 | struct nf_conntrack_tuple_hash *hash = v; |
91 | const struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(hash); | 93 | struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(hash); |
92 | const struct nf_conntrack_l3proto *l3proto; | 94 | const struct nf_conntrack_l3proto *l3proto; |
93 | const struct nf_conntrack_l4proto *l4proto; | 95 | const struct nf_conntrack_l4proto *l4proto; |
96 | int ret = 0; | ||
94 | 97 | ||
95 | NF_CT_ASSERT(ct); | 98 | NF_CT_ASSERT(ct); |
99 | if (unlikely(!atomic_inc_not_zero(&ct->ct_general.use))) | ||
100 | return 0; | ||
101 | |||
96 | 102 | ||
97 | /* we only want to print DIR_ORIGINAL */ | 103 | /* we only want to print DIR_ORIGINAL */ |
98 | if (NF_CT_DIRECTION(hash)) | 104 | if (NF_CT_DIRECTION(hash)) |
99 | return 0; | 105 | goto release; |
100 | if (nf_ct_l3num(ct) != AF_INET) | 106 | if (nf_ct_l3num(ct) != AF_INET) |
101 | return 0; | 107 | goto release; |
102 | 108 | ||
103 | l3proto = __nf_ct_l3proto_find(nf_ct_l3num(ct)); | 109 | l3proto = __nf_ct_l3proto_find(nf_ct_l3num(ct)); |
104 | NF_CT_ASSERT(l3proto); | 110 | NF_CT_ASSERT(l3proto); |
105 | l4proto = __nf_ct_l4proto_find(nf_ct_l3num(ct), nf_ct_protonum(ct)); | 111 | l4proto = __nf_ct_l4proto_find(nf_ct_l3num(ct), nf_ct_protonum(ct)); |
106 | NF_CT_ASSERT(l4proto); | 112 | NF_CT_ASSERT(l4proto); |
107 | 113 | ||
114 | ret = -ENOSPC; | ||
108 | if (seq_printf(s, "%-8s %u %ld ", | 115 | if (seq_printf(s, "%-8s %u %ld ", |
109 | l4proto->name, nf_ct_protonum(ct), | 116 | l4proto->name, nf_ct_protonum(ct), |
110 | timer_pending(&ct->timeout) | 117 | timer_pending(&ct->timeout) |
111 | ? (long)(ct->timeout.expires - jiffies)/HZ : 0) != 0) | 118 | ? (long)(ct->timeout.expires - jiffies)/HZ : 0) != 0) |
112 | return -ENOSPC; | 119 | goto release; |
113 | 120 | ||
114 | if (l4proto->print_conntrack && l4proto->print_conntrack(s, ct)) | 121 | if (l4proto->print_conntrack && l4proto->print_conntrack(s, ct)) |
115 | return -ENOSPC; | 122 | goto release; |
116 | 123 | ||
117 | if (print_tuple(s, &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple, | 124 | if (print_tuple(s, &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple, |
118 | l3proto, l4proto)) | 125 | l3proto, l4proto)) |
119 | return -ENOSPC; | 126 | goto release; |
120 | 127 | ||
121 | if (seq_print_acct(s, ct, IP_CT_DIR_ORIGINAL)) | 128 | if (seq_print_acct(s, ct, IP_CT_DIR_ORIGINAL)) |
122 | return -ENOSPC; | 129 | goto release; |
123 | 130 | ||
124 | if (!(test_bit(IPS_SEEN_REPLY_BIT, &ct->status))) | 131 | if (!(test_bit(IPS_SEEN_REPLY_BIT, &ct->status))) |
125 | if (seq_printf(s, "[UNREPLIED] ")) | 132 | if (seq_printf(s, "[UNREPLIED] ")) |
126 | return -ENOSPC; | 133 | goto release; |
127 | 134 | ||
128 | if (print_tuple(s, &ct->tuplehash[IP_CT_DIR_REPLY].tuple, | 135 | if (print_tuple(s, &ct->tuplehash[IP_CT_DIR_REPLY].tuple, |
129 | l3proto, l4proto)) | 136 | l3proto, l4proto)) |
130 | return -ENOSPC; | 137 | goto release; |
131 | 138 | ||
132 | if (seq_print_acct(s, ct, IP_CT_DIR_REPLY)) | 139 | if (seq_print_acct(s, ct, IP_CT_DIR_REPLY)) |
133 | return -ENOSPC; | 140 | goto release; |
134 | 141 | ||
135 | if (test_bit(IPS_ASSURED_BIT, &ct->status)) | 142 | if (test_bit(IPS_ASSURED_BIT, &ct->status)) |
136 | if (seq_printf(s, "[ASSURED] ")) | 143 | if (seq_printf(s, "[ASSURED] ")) |
137 | return -ENOSPC; | 144 | goto release; |
138 | 145 | ||
139 | #ifdef CONFIG_NF_CONNTRACK_MARK | 146 | #ifdef CONFIG_NF_CONNTRACK_MARK |
140 | if (seq_printf(s, "mark=%u ", ct->mark)) | 147 | if (seq_printf(s, "mark=%u ", ct->mark)) |
141 | return -ENOSPC; | 148 | goto release; |
142 | #endif | 149 | #endif |
143 | 150 | ||
144 | #ifdef CONFIG_NF_CONNTRACK_SECMARK | 151 | #ifdef CONFIG_NF_CONNTRACK_SECMARK |
145 | if (seq_printf(s, "secmark=%u ", ct->secmark)) | 152 | if (seq_printf(s, "secmark=%u ", ct->secmark)) |
146 | return -ENOSPC; | 153 | goto release; |
147 | #endif | 154 | #endif |
148 | 155 | ||
149 | if (seq_printf(s, "use=%u\n", atomic_read(&ct->ct_general.use))) | 156 | if (seq_printf(s, "use=%u\n", atomic_read(&ct->ct_general.use))) |
150 | return -ENOSPC; | 157 | goto release; |
151 | 158 | ret = 0; | |
152 | return 0; | 159 | release: |
160 | nf_ct_put(ct); | ||
161 | return ret; | ||
153 | } | 162 | } |
154 | 163 | ||
155 | static const struct seq_operations ct_seq_ops = { | 164 | static const struct seq_operations ct_seq_ops = { |
diff --git a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c index 2a8bee26f43d..23b2c2ee869a 100644 --- a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c +++ b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c | |||
@@ -262,6 +262,11 @@ static int icmp_nlattr_to_tuple(struct nlattr *tb[], | |||
262 | 262 | ||
263 | return 0; | 263 | return 0; |
264 | } | 264 | } |
265 | |||
266 | static int icmp_nlattr_tuple_size(void) | ||
267 | { | ||
268 | return nla_policy_len(icmp_nla_policy, CTA_PROTO_MAX + 1); | ||
269 | } | ||
265 | #endif | 270 | #endif |
266 | 271 | ||
267 | #ifdef CONFIG_SYSCTL | 272 | #ifdef CONFIG_SYSCTL |
@@ -309,6 +314,7 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_icmp __read_mostly = | |||
309 | .me = NULL, | 314 | .me = NULL, |
310 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) | 315 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) |
311 | .tuple_to_nlattr = icmp_tuple_to_nlattr, | 316 | .tuple_to_nlattr = icmp_tuple_to_nlattr, |
317 | .nlattr_tuple_size = icmp_nlattr_tuple_size, | ||
312 | .nlattr_to_tuple = icmp_nlattr_to_tuple, | 318 | .nlattr_to_tuple = icmp_nlattr_to_tuple, |
313 | .nla_policy = icmp_nla_policy, | 319 | .nla_policy = icmp_nla_policy, |
314 | #endif | 320 | #endif |
diff --git a/net/ipv4/netfilter/nf_nat_core.c b/net/ipv4/netfilter/nf_nat_core.c index a65cf692359f..fe65187810f0 100644 --- a/net/ipv4/netfilter/nf_nat_core.c +++ b/net/ipv4/netfilter/nf_nat_core.c | |||
@@ -679,7 +679,7 @@ nfnetlink_parse_nat_setup(struct nf_conn *ct, | |||
679 | static int __net_init nf_nat_net_init(struct net *net) | 679 | static int __net_init nf_nat_net_init(struct net *net) |
680 | { | 680 | { |
681 | net->ipv4.nat_bysource = nf_ct_alloc_hashtable(&nf_nat_htable_size, | 681 | net->ipv4.nat_bysource = nf_ct_alloc_hashtable(&nf_nat_htable_size, |
682 | &net->ipv4.nat_vmalloced); | 682 | &net->ipv4.nat_vmalloced, 0); |
683 | if (!net->ipv4.nat_bysource) | 683 | if (!net->ipv4.nat_bysource) |
684 | return -ENOMEM; | 684 | return -ENOMEM; |
685 | return 0; | 685 | return 0; |
diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c index f171e8dbac91..8f04bd9da274 100644 --- a/net/ipv6/ip6_input.c +++ b/net/ipv6/ip6_input.c | |||
@@ -75,8 +75,7 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt | |||
75 | if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL || | 75 | if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL || |
76 | !idev || unlikely(idev->cnf.disable_ipv6)) { | 76 | !idev || unlikely(idev->cnf.disable_ipv6)) { |
77 | IP6_INC_STATS_BH(net, idev, IPSTATS_MIB_INDISCARDS); | 77 | IP6_INC_STATS_BH(net, idev, IPSTATS_MIB_INDISCARDS); |
78 | rcu_read_unlock(); | 78 | goto drop; |
79 | goto out; | ||
80 | } | 79 | } |
81 | 80 | ||
82 | memset(IP6CB(skb), 0, sizeof(struct inet6_skb_parm)); | 81 | memset(IP6CB(skb), 0, sizeof(struct inet6_skb_parm)); |
@@ -147,7 +146,6 @@ err: | |||
147 | drop: | 146 | drop: |
148 | rcu_read_unlock(); | 147 | rcu_read_unlock(); |
149 | kfree_skb(skb); | 148 | kfree_skb(skb); |
150 | out: | ||
151 | return 0; | 149 | return 0; |
152 | } | 150 | } |
153 | 151 | ||
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index 34af7bb8df5f..e89cfa3a8f25 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c | |||
@@ -89,25 +89,6 @@ ip6t_ext_hdr(u8 nexthdr) | |||
89 | (nexthdr == IPPROTO_DSTOPTS) ); | 89 | (nexthdr == IPPROTO_DSTOPTS) ); |
90 | } | 90 | } |
91 | 91 | ||
92 | static unsigned long ifname_compare(const char *_a, const char *_b, | ||
93 | const unsigned char *_mask) | ||
94 | { | ||
95 | const unsigned long *a = (const unsigned long *)_a; | ||
96 | const unsigned long *b = (const unsigned long *)_b; | ||
97 | const unsigned long *mask = (const unsigned long *)_mask; | ||
98 | unsigned long ret; | ||
99 | |||
100 | ret = (a[0] ^ b[0]) & mask[0]; | ||
101 | if (IFNAMSIZ > sizeof(unsigned long)) | ||
102 | ret |= (a[1] ^ b[1]) & mask[1]; | ||
103 | if (IFNAMSIZ > 2 * sizeof(unsigned long)) | ||
104 | ret |= (a[2] ^ b[2]) & mask[2]; | ||
105 | if (IFNAMSIZ > 3 * sizeof(unsigned long)) | ||
106 | ret |= (a[3] ^ b[3]) & mask[3]; | ||
107 | BUILD_BUG_ON(IFNAMSIZ > 4 * sizeof(unsigned long)); | ||
108 | return ret; | ||
109 | } | ||
110 | |||
111 | /* Returns whether matches rule or not. */ | 92 | /* Returns whether matches rule or not. */ |
112 | /* Performance critical - called for every packet */ | 93 | /* Performance critical - called for every packet */ |
113 | static inline bool | 94 | static inline bool |
@@ -138,7 +119,7 @@ ip6_packet_match(const struct sk_buff *skb, | |||
138 | return false; | 119 | return false; |
139 | } | 120 | } |
140 | 121 | ||
141 | ret = ifname_compare(indev, ip6info->iniface, ip6info->iniface_mask); | 122 | ret = ifname_compare_aligned(indev, ip6info->iniface, ip6info->iniface_mask); |
142 | 123 | ||
143 | if (FWINV(ret != 0, IP6T_INV_VIA_IN)) { | 124 | if (FWINV(ret != 0, IP6T_INV_VIA_IN)) { |
144 | dprintf("VIA in mismatch (%s vs %s).%s\n", | 125 | dprintf("VIA in mismatch (%s vs %s).%s\n", |
@@ -147,7 +128,7 @@ ip6_packet_match(const struct sk_buff *skb, | |||
147 | return false; | 128 | return false; |
148 | } | 129 | } |
149 | 130 | ||
150 | ret = ifname_compare(outdev, ip6info->outiface, ip6info->outiface_mask); | 131 | ret = ifname_compare_aligned(outdev, ip6info->outiface, ip6info->outiface_mask); |
151 | 132 | ||
152 | if (FWINV(ret != 0, IP6T_INV_VIA_OUT)) { | 133 | if (FWINV(ret != 0, IP6T_INV_VIA_OUT)) { |
153 | dprintf("VIA out mismatch (%s vs %s).%s\n", | 134 | dprintf("VIA out mismatch (%s vs %s).%s\n", |
@@ -536,7 +517,9 @@ mark_source_chains(struct xt_table_info *newinfo, | |||
536 | && unconditional(&e->ipv6)) || visited) { | 517 | && unconditional(&e->ipv6)) || visited) { |
537 | unsigned int oldpos, size; | 518 | unsigned int oldpos, size; |
538 | 519 | ||
539 | if (t->verdict < -NF_MAX_VERDICT - 1) { | 520 | if ((strcmp(t->target.u.user.name, |
521 | IP6T_STANDARD_TARGET) == 0) && | ||
522 | t->verdict < -NF_MAX_VERDICT - 1) { | ||
540 | duprintf("mark_source_chains: bad " | 523 | duprintf("mark_source_chains: bad " |
541 | "negative verdict (%i)\n", | 524 | "negative verdict (%i)\n", |
542 | t->verdict); | 525 | t->verdict); |
diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c index e6852f617217..2a15c2d66c69 100644 --- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c +++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c | |||
@@ -342,6 +342,11 @@ static int ipv6_nlattr_to_tuple(struct nlattr *tb[], | |||
342 | 342 | ||
343 | return 0; | 343 | return 0; |
344 | } | 344 | } |
345 | |||
346 | static int ipv6_nlattr_tuple_size(void) | ||
347 | { | ||
348 | return nla_policy_len(ipv6_nla_policy, CTA_IP_MAX + 1); | ||
349 | } | ||
345 | #endif | 350 | #endif |
346 | 351 | ||
347 | struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv6 __read_mostly = { | 352 | struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv6 __read_mostly = { |
@@ -353,6 +358,7 @@ struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv6 __read_mostly = { | |||
353 | .get_l4proto = ipv6_get_l4proto, | 358 | .get_l4proto = ipv6_get_l4proto, |
354 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) | 359 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) |
355 | .tuple_to_nlattr = ipv6_tuple_to_nlattr, | 360 | .tuple_to_nlattr = ipv6_tuple_to_nlattr, |
361 | .nlattr_tuple_size = ipv6_nlattr_tuple_size, | ||
356 | .nlattr_to_tuple = ipv6_nlattr_to_tuple, | 362 | .nlattr_to_tuple = ipv6_nlattr_to_tuple, |
357 | .nla_policy = ipv6_nla_policy, | 363 | .nla_policy = ipv6_nla_policy, |
358 | #endif | 364 | #endif |
diff --git a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c index 41b8a956e1be..9903227bf37c 100644 --- a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c +++ b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c | |||
@@ -269,6 +269,11 @@ static int icmpv6_nlattr_to_tuple(struct nlattr *tb[], | |||
269 | 269 | ||
270 | return 0; | 270 | return 0; |
271 | } | 271 | } |
272 | |||
273 | static int icmpv6_nlattr_tuple_size(void) | ||
274 | { | ||
275 | return nla_policy_len(icmpv6_nla_policy, CTA_PROTO_MAX + 1); | ||
276 | } | ||
272 | #endif | 277 | #endif |
273 | 278 | ||
274 | #ifdef CONFIG_SYSCTL | 279 | #ifdef CONFIG_SYSCTL |
@@ -300,6 +305,7 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_icmpv6 __read_mostly = | |||
300 | .error = icmpv6_error, | 305 | .error = icmpv6_error, |
301 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) | 306 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) |
302 | .tuple_to_nlattr = icmpv6_tuple_to_nlattr, | 307 | .tuple_to_nlattr = icmpv6_tuple_to_nlattr, |
308 | .nlattr_tuple_size = icmpv6_nlattr_tuple_size, | ||
303 | .nlattr_to_tuple = icmpv6_nlattr_to_tuple, | 309 | .nlattr_to_tuple = icmpv6_nlattr_to_tuple, |
304 | .nla_policy = icmpv6_nla_policy, | 310 | .nla_policy = icmpv6_nla_policy, |
305 | #endif | 311 | #endif |
diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c index a95affc94629..07656d830bc4 100644 --- a/net/mac80211/agg-rx.c +++ b/net/mac80211/agg-rx.c | |||
@@ -197,6 +197,14 @@ void ieee80211_process_addba_request(struct ieee80211_local *local, | |||
197 | 197 | ||
198 | status = WLAN_STATUS_REQUEST_DECLINED; | 198 | status = WLAN_STATUS_REQUEST_DECLINED; |
199 | 199 | ||
200 | if (test_sta_flags(sta, WLAN_STA_SUSPEND)) { | ||
201 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
202 | printk(KERN_DEBUG "Suspend in progress. " | ||
203 | "Denying ADDBA request\n"); | ||
204 | #endif | ||
205 | goto end_no_lock; | ||
206 | } | ||
207 | |||
200 | /* sanity check for incoming parameters: | 208 | /* sanity check for incoming parameters: |
201 | * check if configuration can support the BA policy | 209 | * check if configuration can support the BA policy |
202 | * and if buffer size does not exceeds max value */ | 210 | * and if buffer size does not exceeds max value */ |
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index 1df116d4d6e7..947aaaad35d2 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c | |||
@@ -131,24 +131,6 @@ static int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, | |||
131 | 131 | ||
132 | state = &sta->ampdu_mlme.tid_state_tx[tid]; | 132 | state = &sta->ampdu_mlme.tid_state_tx[tid]; |
133 | 133 | ||
134 | if (local->hw.ampdu_queues) { | ||
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 | } | ||
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 | } | ||
152 | *state = HT_AGG_STATE_REQ_STOP_BA_MSK | | 134 | *state = HT_AGG_STATE_REQ_STOP_BA_MSK | |
153 | (initiator << HT_AGG_STATE_INITIATOR_SHIFT); | 135 | (initiator << HT_AGG_STATE_INITIATOR_SHIFT); |
154 | 136 | ||
@@ -158,6 +140,10 @@ static int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, | |||
158 | /* HW shall not deny going back to legacy */ | 140 | /* HW shall not deny going back to legacy */ |
159 | if (WARN_ON(ret)) { | 141 | if (WARN_ON(ret)) { |
160 | *state = HT_AGG_STATE_OPERATIONAL; | 142 | *state = HT_AGG_STATE_OPERATIONAL; |
143 | /* | ||
144 | * We may have pending packets get stuck in this case... | ||
145 | * Not bothering with a workaround for now. | ||
146 | */ | ||
161 | } | 147 | } |
162 | 148 | ||
163 | return ret; | 149 | return ret; |
@@ -212,7 +198,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) | |||
212 | struct sta_info *sta; | 198 | struct sta_info *sta; |
213 | struct ieee80211_sub_if_data *sdata; | 199 | struct ieee80211_sub_if_data *sdata; |
214 | u8 *state; | 200 | u8 *state; |
215 | int i, qn = -1, ret = 0; | 201 | int ret = 0; |
216 | u16 start_seq_num; | 202 | u16 start_seq_num; |
217 | 203 | ||
218 | if (WARN_ON(!local->ops->ampdu_action)) | 204 | if (WARN_ON(!local->ops->ampdu_action)) |
@@ -226,13 +212,6 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) | |||
226 | ra, tid); | 212 | ra, tid); |
227 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | 213 | #endif /* CONFIG_MAC80211_HT_DEBUG */ |
228 | 214 | ||
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 | |||
236 | rcu_read_lock(); | 215 | rcu_read_lock(); |
237 | 216 | ||
238 | sta = sta_info_get(local, ra); | 217 | sta = sta_info_get(local, ra); |
@@ -257,7 +236,17 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) | |||
257 | goto unlock; | 236 | goto unlock; |
258 | } | 237 | } |
259 | 238 | ||
239 | if (test_sta_flags(sta, WLAN_STA_SUSPEND)) { | ||
240 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
241 | printk(KERN_DEBUG "Suspend in progress. " | ||
242 | "Denying BA session request\n"); | ||
243 | #endif | ||
244 | ret = -EINVAL; | ||
245 | goto unlock; | ||
246 | } | ||
247 | |||
260 | spin_lock_bh(&sta->lock); | 248 | spin_lock_bh(&sta->lock); |
249 | spin_lock(&local->ampdu_lock); | ||
261 | 250 | ||
262 | sdata = sta->sdata; | 251 | sdata = sta->sdata; |
263 | 252 | ||
@@ -278,41 +267,16 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) | |||
278 | goto err_unlock_sta; | 267 | goto err_unlock_sta; |
279 | } | 268 | } |
280 | 269 | ||
281 | if (hw->ampdu_queues) { | 270 | /* |
282 | spin_lock(&local->queue_stop_reason_lock); | 271 | * While we're asking the driver about the aggregation, |
283 | /* reserve a new queue for this session */ | 272 | * stop the AC queue so that we don't have to worry |
284 | for (i = 0; i < local->hw.ampdu_queues; i++) { | 273 | * about frames that came in while we were doing that, |
285 | if (local->ampdu_ac_queue[i] < 0) { | 274 | * which would require us to put them to the AC pending |
286 | qn = i; | 275 | * afterwards which just makes the code more complex. |
287 | local->ampdu_ac_queue[qn] = | 276 | */ |
288 | ieee80211_ac_from_tid(tid); | 277 | ieee80211_stop_queue_by_reason( |
289 | break; | 278 | &local->hw, ieee80211_ac_from_tid(tid), |
290 | } | 279 | IEEE80211_QUEUE_STOP_REASON_AGGREGATION); |
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 | 280 | ||
317 | /* prepare A-MPDU MLME for Tx aggregation */ | 281 | /* prepare A-MPDU MLME for Tx aggregation */ |
318 | sta->ampdu_mlme.tid_tx[tid] = | 282 | sta->ampdu_mlme.tid_tx[tid] = |
@@ -324,9 +288,11 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) | |||
324 | tid); | 288 | tid); |
325 | #endif | 289 | #endif |
326 | ret = -ENOMEM; | 290 | ret = -ENOMEM; |
327 | goto err_return_queue; | 291 | goto err_wake_queue; |
328 | } | 292 | } |
329 | 293 | ||
294 | skb_queue_head_init(&sta->ampdu_mlme.tid_tx[tid]->pending); | ||
295 | |||
330 | /* Tx timer */ | 296 | /* Tx timer */ |
331 | sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.function = | 297 | sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.function = |
332 | sta_addba_resp_timer_expired; | 298 | sta_addba_resp_timer_expired; |
@@ -351,8 +317,13 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) | |||
351 | *state = HT_AGG_STATE_IDLE; | 317 | *state = HT_AGG_STATE_IDLE; |
352 | goto err_free; | 318 | goto err_free; |
353 | } | 319 | } |
354 | sta->tid_to_tx_q[tid] = qn; | ||
355 | 320 | ||
321 | /* Driver vetoed or OKed, but we can take packets again now */ | ||
322 | ieee80211_wake_queue_by_reason( | ||
323 | &local->hw, ieee80211_ac_from_tid(tid), | ||
324 | IEEE80211_QUEUE_STOP_REASON_AGGREGATION); | ||
325 | |||
326 | spin_unlock(&local->ampdu_lock); | ||
356 | spin_unlock_bh(&sta->lock); | 327 | spin_unlock_bh(&sta->lock); |
357 | 328 | ||
358 | /* send an addBA request */ | 329 | /* send an addBA request */ |
@@ -377,17 +348,12 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) | |||
377 | err_free: | 348 | err_free: |
378 | kfree(sta->ampdu_mlme.tid_tx[tid]); | 349 | kfree(sta->ampdu_mlme.tid_tx[tid]); |
379 | sta->ampdu_mlme.tid_tx[tid] = NULL; | 350 | sta->ampdu_mlme.tid_tx[tid] = NULL; |
380 | err_return_queue: | 351 | err_wake_queue: |
381 | if (qn >= 0) { | 352 | ieee80211_wake_queue_by_reason( |
382 | /* We failed, so start queue again right away. */ | 353 | &local->hw, ieee80211_ac_from_tid(tid), |
383 | ieee80211_wake_queue_by_reason(hw, hw->queues + qn, | 354 | IEEE80211_QUEUE_STOP_REASON_AGGREGATION); |
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: | 355 | err_unlock_sta: |
356 | spin_unlock(&local->ampdu_lock); | ||
391 | spin_unlock_bh(&sta->lock); | 357 | spin_unlock_bh(&sta->lock); |
392 | unlock: | 358 | unlock: |
393 | rcu_read_unlock(); | 359 | rcu_read_unlock(); |
@@ -395,6 +361,67 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) | |||
395 | } | 361 | } |
396 | EXPORT_SYMBOL(ieee80211_start_tx_ba_session); | 362 | EXPORT_SYMBOL(ieee80211_start_tx_ba_session); |
397 | 363 | ||
364 | /* | ||
365 | * splice packets from the STA's pending to the local pending, | ||
366 | * requires a call to ieee80211_agg_splice_finish and holding | ||
367 | * local->ampdu_lock across both calls. | ||
368 | */ | ||
369 | static void ieee80211_agg_splice_packets(struct ieee80211_local *local, | ||
370 | struct sta_info *sta, u16 tid) | ||
371 | { | ||
372 | unsigned long flags; | ||
373 | u16 queue = ieee80211_ac_from_tid(tid); | ||
374 | |||
375 | ieee80211_stop_queue_by_reason( | ||
376 | &local->hw, queue, | ||
377 | IEEE80211_QUEUE_STOP_REASON_AGGREGATION); | ||
378 | |||
379 | if (!skb_queue_empty(&sta->ampdu_mlme.tid_tx[tid]->pending)) { | ||
380 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); | ||
381 | /* mark queue as pending, it is stopped already */ | ||
382 | __set_bit(IEEE80211_QUEUE_STOP_REASON_PENDING, | ||
383 | &local->queue_stop_reasons[queue]); | ||
384 | /* copy over remaining packets */ | ||
385 | skb_queue_splice_tail_init( | ||
386 | &sta->ampdu_mlme.tid_tx[tid]->pending, | ||
387 | &local->pending[queue]); | ||
388 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); | ||
389 | } | ||
390 | } | ||
391 | |||
392 | static void ieee80211_agg_splice_finish(struct ieee80211_local *local, | ||
393 | struct sta_info *sta, u16 tid) | ||
394 | { | ||
395 | u16 queue = ieee80211_ac_from_tid(tid); | ||
396 | |||
397 | ieee80211_wake_queue_by_reason( | ||
398 | &local->hw, queue, | ||
399 | IEEE80211_QUEUE_STOP_REASON_AGGREGATION); | ||
400 | } | ||
401 | |||
402 | /* caller must hold sta->lock */ | ||
403 | static void ieee80211_agg_tx_operational(struct ieee80211_local *local, | ||
404 | struct sta_info *sta, u16 tid) | ||
405 | { | ||
406 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
407 | printk(KERN_DEBUG "Aggregation is on for tid %d \n", tid); | ||
408 | #endif | ||
409 | |||
410 | spin_lock(&local->ampdu_lock); | ||
411 | ieee80211_agg_splice_packets(local, sta, tid); | ||
412 | /* | ||
413 | * NB: we rely on sta->lock being taken in the TX | ||
414 | * processing here when adding to the pending queue, | ||
415 | * otherwise we could only change the state of the | ||
416 | * session to OPERATIONAL _here_. | ||
417 | */ | ||
418 | ieee80211_agg_splice_finish(local, sta, tid); | ||
419 | spin_unlock(&local->ampdu_lock); | ||
420 | |||
421 | local->ops->ampdu_action(&local->hw, IEEE80211_AMPDU_TX_OPERATIONAL, | ||
422 | &sta->sta, tid, NULL); | ||
423 | } | ||
424 | |||
398 | void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid) | 425 | void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid) |
399 | { | 426 | { |
400 | struct ieee80211_local *local = hw_to_local(hw); | 427 | struct ieee80211_local *local = hw_to_local(hw); |
@@ -437,20 +464,8 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid) | |||
437 | 464 | ||
438 | *state |= HT_ADDBA_DRV_READY_MSK; | 465 | *state |= HT_ADDBA_DRV_READY_MSK; |
439 | 466 | ||
440 | if (*state == HT_AGG_STATE_OPERATIONAL) { | 467 | if (*state == HT_AGG_STATE_OPERATIONAL) |
441 | #ifdef CONFIG_MAC80211_HT_DEBUG | 468 | ieee80211_agg_tx_operational(local, sta, tid); |
442 | printk(KERN_DEBUG "Aggregation is on for tid %d \n", tid); | ||
443 | #endif | ||
444 | if (hw->ampdu_queues) { | ||
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 | } | ||
453 | } | ||
454 | 469 | ||
455 | out: | 470 | out: |
456 | spin_unlock_bh(&sta->lock); | 471 | spin_unlock_bh(&sta->lock); |
@@ -584,22 +599,19 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid) | |||
584 | WLAN_BACK_INITIATOR, WLAN_REASON_QSTA_NOT_USE); | 599 | WLAN_BACK_INITIATOR, WLAN_REASON_QSTA_NOT_USE); |
585 | 600 | ||
586 | spin_lock_bh(&sta->lock); | 601 | spin_lock_bh(&sta->lock); |
602 | spin_lock(&local->ampdu_lock); | ||
587 | 603 | ||
588 | if (*state & HT_AGG_STATE_INITIATOR_MSK && | 604 | ieee80211_agg_splice_packets(local, sta, tid); |
589 | hw->ampdu_queues) { | ||
590 | /* | ||
591 | * Wake up this queue, we stopped it earlier, | ||
592 | * this will in turn wake the entire AC. | ||
593 | */ | ||
594 | ieee80211_wake_queue_by_reason(hw, | ||
595 | hw->queues + sta->tid_to_tx_q[tid], | ||
596 | IEEE80211_QUEUE_STOP_REASON_AGGREGATION); | ||
597 | } | ||
598 | 605 | ||
599 | *state = HT_AGG_STATE_IDLE; | 606 | *state = HT_AGG_STATE_IDLE; |
607 | /* from now on packets are no longer put onto sta->pending */ | ||
600 | sta->ampdu_mlme.addba_req_num[tid] = 0; | 608 | sta->ampdu_mlme.addba_req_num[tid] = 0; |
601 | kfree(sta->ampdu_mlme.tid_tx[tid]); | 609 | kfree(sta->ampdu_mlme.tid_tx[tid]); |
602 | sta->ampdu_mlme.tid_tx[tid] = NULL; | 610 | sta->ampdu_mlme.tid_tx[tid] = NULL; |
611 | |||
612 | ieee80211_agg_splice_finish(local, sta, tid); | ||
613 | |||
614 | spin_unlock(&local->ampdu_lock); | ||
603 | spin_unlock_bh(&sta->lock); | 615 | spin_unlock_bh(&sta->lock); |
604 | 616 | ||
605 | rcu_read_unlock(); | 617 | rcu_read_unlock(); |
@@ -637,9 +649,7 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local, | |||
637 | struct ieee80211_mgmt *mgmt, | 649 | struct ieee80211_mgmt *mgmt, |
638 | size_t len) | 650 | size_t len) |
639 | { | 651 | { |
640 | struct ieee80211_hw *hw = &local->hw; | 652 | u16 capab, tid; |
641 | u16 capab; | ||
642 | u16 tid, start_seq_num; | ||
643 | u8 *state; | 653 | u8 *state; |
644 | 654 | ||
645 | capab = le16_to_cpu(mgmt->u.action.u.addba_resp.capab); | 655 | capab = le16_to_cpu(mgmt->u.action.u.addba_resp.capab); |
@@ -673,26 +683,10 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local, | |||
673 | 683 | ||
674 | *state |= HT_ADDBA_RECEIVED_MSK; | 684 | *state |= HT_ADDBA_RECEIVED_MSK; |
675 | 685 | ||
676 | if (hw->ampdu_queues && *state != curstate && | 686 | if (*state != curstate && *state == HT_AGG_STATE_OPERATIONAL) |
677 | *state == HT_AGG_STATE_OPERATIONAL) { | 687 | ieee80211_agg_tx_operational(local, sta, 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; | ||
687 | 688 | ||
688 | if (local->ops->ampdu_action) { | 689 | sta->ampdu_mlme.addba_req_num[tid] = 0; |
689 | (void)local->ops->ampdu_action(hw, | ||
690 | IEEE80211_AMPDU_TX_RESUME, | ||
691 | &sta->sta, tid, &start_seq_num); | ||
692 | } | ||
693 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
694 | printk(KERN_DEBUG "Resuming TX aggregation for tid %d\n", tid); | ||
695 | #endif /* CONFIG_MAC80211_HT_DEBUG */ | ||
696 | } else { | 690 | } else { |
697 | sta->ampdu_mlme.addba_req_num[tid]++; | 691 | sta->ampdu_mlme.addba_req_num[tid]++; |
698 | ___ieee80211_stop_tx_ba_session(sta, tid, WLAN_BACK_INITIATOR); | 692 | ___ieee80211_stop_tx_ba_session(sta, tid, WLAN_BACK_INITIATOR); |
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 58693e52d458..e677b751d468 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -540,9 +540,6 @@ static int ieee80211_add_beacon(struct wiphy *wiphy, struct net_device *dev, | |||
540 | 540 | ||
541 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 541 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
542 | 542 | ||
543 | if (sdata->vif.type != NL80211_IFTYPE_AP) | ||
544 | return -EINVAL; | ||
545 | |||
546 | old = sdata->u.ap.beacon; | 543 | old = sdata->u.ap.beacon; |
547 | 544 | ||
548 | if (old) | 545 | if (old) |
@@ -559,9 +556,6 @@ static int ieee80211_set_beacon(struct wiphy *wiphy, struct net_device *dev, | |||
559 | 556 | ||
560 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 557 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
561 | 558 | ||
562 | if (sdata->vif.type != NL80211_IFTYPE_AP) | ||
563 | return -EINVAL; | ||
564 | |||
565 | old = sdata->u.ap.beacon; | 559 | old = sdata->u.ap.beacon; |
566 | 560 | ||
567 | if (!old) | 561 | if (!old) |
@@ -577,9 +571,6 @@ static int ieee80211_del_beacon(struct wiphy *wiphy, struct net_device *dev) | |||
577 | 571 | ||
578 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 572 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
579 | 573 | ||
580 | if (sdata->vif.type != NL80211_IFTYPE_AP) | ||
581 | return -EINVAL; | ||
582 | |||
583 | old = sdata->u.ap.beacon; | 574 | old = sdata->u.ap.beacon; |
584 | 575 | ||
585 | if (!old) | 576 | if (!old) |
@@ -728,10 +719,6 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev, | |||
728 | int err; | 719 | int err; |
729 | int layer2_update; | 720 | int layer2_update; |
730 | 721 | ||
731 | /* Prevent a race with changing the rate control algorithm */ | ||
732 | if (!netif_running(dev)) | ||
733 | return -ENETDOWN; | ||
734 | |||
735 | if (params->vlan) { | 722 | if (params->vlan) { |
736 | sdata = IEEE80211_DEV_TO_SUB_IF(params->vlan); | 723 | sdata = IEEE80211_DEV_TO_SUB_IF(params->vlan); |
737 | 724 | ||
@@ -860,14 +847,8 @@ static int ieee80211_add_mpath(struct wiphy *wiphy, struct net_device *dev, | |||
860 | struct sta_info *sta; | 847 | struct sta_info *sta; |
861 | int err; | 848 | int err; |
862 | 849 | ||
863 | if (!netif_running(dev)) | ||
864 | return -ENETDOWN; | ||
865 | |||
866 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 850 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
867 | 851 | ||
868 | if (sdata->vif.type != NL80211_IFTYPE_MESH_POINT) | ||
869 | return -ENOTSUPP; | ||
870 | |||
871 | rcu_read_lock(); | 852 | rcu_read_lock(); |
872 | sta = sta_info_get(local, next_hop); | 853 | sta = sta_info_get(local, next_hop); |
873 | if (!sta) { | 854 | if (!sta) { |
@@ -913,14 +894,8 @@ static int ieee80211_change_mpath(struct wiphy *wiphy, | |||
913 | struct mesh_path *mpath; | 894 | struct mesh_path *mpath; |
914 | struct sta_info *sta; | 895 | struct sta_info *sta; |
915 | 896 | ||
916 | if (!netif_running(dev)) | ||
917 | return -ENETDOWN; | ||
918 | |||
919 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 897 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
920 | 898 | ||
921 | if (sdata->vif.type != NL80211_IFTYPE_MESH_POINT) | ||
922 | return -ENOTSUPP; | ||
923 | |||
924 | rcu_read_lock(); | 899 | rcu_read_lock(); |
925 | 900 | ||
926 | sta = sta_info_get(local, next_hop); | 901 | sta = sta_info_get(local, next_hop); |
@@ -989,9 +964,6 @@ static int ieee80211_get_mpath(struct wiphy *wiphy, struct net_device *dev, | |||
989 | 964 | ||
990 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 965 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
991 | 966 | ||
992 | if (sdata->vif.type != NL80211_IFTYPE_MESH_POINT) | ||
993 | return -ENOTSUPP; | ||
994 | |||
995 | rcu_read_lock(); | 967 | rcu_read_lock(); |
996 | mpath = mesh_path_lookup(dst, sdata); | 968 | mpath = mesh_path_lookup(dst, sdata); |
997 | if (!mpath) { | 969 | if (!mpath) { |
@@ -1013,9 +985,6 @@ static int ieee80211_dump_mpath(struct wiphy *wiphy, struct net_device *dev, | |||
1013 | 985 | ||
1014 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 986 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
1015 | 987 | ||
1016 | if (sdata->vif.type != NL80211_IFTYPE_MESH_POINT) | ||
1017 | return -ENOTSUPP; | ||
1018 | |||
1019 | rcu_read_lock(); | 988 | rcu_read_lock(); |
1020 | mpath = mesh_path_lookup_by_idx(idx, sdata); | 989 | mpath = mesh_path_lookup_by_idx(idx, sdata); |
1021 | if (!mpath) { | 990 | if (!mpath) { |
@@ -1035,8 +1004,6 @@ static int ieee80211_get_mesh_params(struct wiphy *wiphy, | |||
1035 | struct ieee80211_sub_if_data *sdata; | 1004 | struct ieee80211_sub_if_data *sdata; |
1036 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 1005 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
1037 | 1006 | ||
1038 | if (sdata->vif.type != NL80211_IFTYPE_MESH_POINT) | ||
1039 | return -ENOTSUPP; | ||
1040 | memcpy(conf, &(sdata->u.mesh.mshcfg), sizeof(struct mesh_config)); | 1007 | memcpy(conf, &(sdata->u.mesh.mshcfg), sizeof(struct mesh_config)); |
1041 | return 0; | 1008 | return 0; |
1042 | } | 1009 | } |
@@ -1054,9 +1021,6 @@ static int ieee80211_set_mesh_params(struct wiphy *wiphy, | |||
1054 | struct ieee80211_sub_if_data *sdata; | 1021 | struct ieee80211_sub_if_data *sdata; |
1055 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 1022 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
1056 | 1023 | ||
1057 | if (sdata->vif.type != NL80211_IFTYPE_MESH_POINT) | ||
1058 | return -ENOTSUPP; | ||
1059 | |||
1060 | /* Set the config options which we are interested in setting */ | 1024 | /* Set the config options which we are interested in setting */ |
1061 | conf = &(sdata->u.mesh.mshcfg); | 1025 | conf = &(sdata->u.mesh.mshcfg); |
1062 | if (_chg_mesh_attr(NL80211_MESHCONF_RETRY_TIMEOUT, mask)) | 1026 | if (_chg_mesh_attr(NL80211_MESHCONF_RETRY_TIMEOUT, mask)) |
@@ -1104,9 +1068,6 @@ static int ieee80211_change_bss(struct wiphy *wiphy, | |||
1104 | 1068 | ||
1105 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 1069 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
1106 | 1070 | ||
1107 | if (sdata->vif.type != NL80211_IFTYPE_AP) | ||
1108 | return -EINVAL; | ||
1109 | |||
1110 | if (params->use_cts_prot >= 0) { | 1071 | if (params->use_cts_prot >= 0) { |
1111 | sdata->vif.bss_conf.use_cts_prot = params->use_cts_prot; | 1072 | sdata->vif.bss_conf.use_cts_prot = params->use_cts_prot; |
1112 | changed |= BSS_CHANGED_ERP_CTS_PROT; | 1073 | changed |= BSS_CHANGED_ERP_CTS_PROT; |
@@ -1181,91 +1142,6 @@ static int ieee80211_set_channel(struct wiphy *wiphy, | |||
1181 | return ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); | 1142 | return ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); |
1182 | } | 1143 | } |
1183 | 1144 | ||
1184 | static int set_mgmt_extra_ie_sta(struct ieee80211_sub_if_data *sdata, | ||
1185 | u8 subtype, u8 *ies, size_t ies_len) | ||
1186 | { | ||
1187 | struct ieee80211_local *local = sdata->local; | ||
1188 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
1189 | |||
1190 | switch (subtype) { | ||
1191 | case IEEE80211_STYPE_PROBE_REQ >> 4: | ||
1192 | if (local->ops->hw_scan) | ||
1193 | break; | ||
1194 | kfree(ifmgd->ie_probereq); | ||
1195 | ifmgd->ie_probereq = ies; | ||
1196 | ifmgd->ie_probereq_len = ies_len; | ||
1197 | return 0; | ||
1198 | case IEEE80211_STYPE_PROBE_RESP >> 4: | ||
1199 | kfree(ifmgd->ie_proberesp); | ||
1200 | ifmgd->ie_proberesp = ies; | ||
1201 | ifmgd->ie_proberesp_len = ies_len; | ||
1202 | return 0; | ||
1203 | case IEEE80211_STYPE_AUTH >> 4: | ||
1204 | kfree(ifmgd->ie_auth); | ||
1205 | ifmgd->ie_auth = ies; | ||
1206 | ifmgd->ie_auth_len = ies_len; | ||
1207 | return 0; | ||
1208 | case IEEE80211_STYPE_ASSOC_REQ >> 4: | ||
1209 | kfree(ifmgd->ie_assocreq); | ||
1210 | ifmgd->ie_assocreq = ies; | ||
1211 | ifmgd->ie_assocreq_len = ies_len; | ||
1212 | return 0; | ||
1213 | case IEEE80211_STYPE_REASSOC_REQ >> 4: | ||
1214 | kfree(ifmgd->ie_reassocreq); | ||
1215 | ifmgd->ie_reassocreq = ies; | ||
1216 | ifmgd->ie_reassocreq_len = ies_len; | ||
1217 | return 0; | ||
1218 | case IEEE80211_STYPE_DEAUTH >> 4: | ||
1219 | kfree(ifmgd->ie_deauth); | ||
1220 | ifmgd->ie_deauth = ies; | ||
1221 | ifmgd->ie_deauth_len = ies_len; | ||
1222 | return 0; | ||
1223 | case IEEE80211_STYPE_DISASSOC >> 4: | ||
1224 | kfree(ifmgd->ie_disassoc); | ||
1225 | ifmgd->ie_disassoc = ies; | ||
1226 | ifmgd->ie_disassoc_len = ies_len; | ||
1227 | return 0; | ||
1228 | } | ||
1229 | |||
1230 | return -EOPNOTSUPP; | ||
1231 | } | ||
1232 | |||
1233 | static int ieee80211_set_mgmt_extra_ie(struct wiphy *wiphy, | ||
1234 | struct net_device *dev, | ||
1235 | struct mgmt_extra_ie_params *params) | ||
1236 | { | ||
1237 | struct ieee80211_sub_if_data *sdata; | ||
1238 | u8 *ies; | ||
1239 | size_t ies_len; | ||
1240 | int ret = -EOPNOTSUPP; | ||
1241 | |||
1242 | if (params->ies) { | ||
1243 | ies = kmemdup(params->ies, params->ies_len, GFP_KERNEL); | ||
1244 | if (ies == NULL) | ||
1245 | return -ENOMEM; | ||
1246 | ies_len = params->ies_len; | ||
1247 | } else { | ||
1248 | ies = NULL; | ||
1249 | ies_len = 0; | ||
1250 | } | ||
1251 | |||
1252 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
1253 | |||
1254 | switch (sdata->vif.type) { | ||
1255 | case NL80211_IFTYPE_STATION: | ||
1256 | ret = set_mgmt_extra_ie_sta(sdata, params->subtype, | ||
1257 | ies, ies_len); | ||
1258 | break; | ||
1259 | default: | ||
1260 | ret = -EOPNOTSUPP; | ||
1261 | break; | ||
1262 | } | ||
1263 | |||
1264 | if (ret) | ||
1265 | kfree(ies); | ||
1266 | return ret; | ||
1267 | } | ||
1268 | |||
1269 | #ifdef CONFIG_PM | 1145 | #ifdef CONFIG_PM |
1270 | static int ieee80211_suspend(struct wiphy *wiphy) | 1146 | static int ieee80211_suspend(struct wiphy *wiphy) |
1271 | { | 1147 | { |
@@ -1287,9 +1163,6 @@ static int ieee80211_scan(struct wiphy *wiphy, | |||
1287 | { | 1163 | { |
1288 | struct ieee80211_sub_if_data *sdata; | 1164 | struct ieee80211_sub_if_data *sdata; |
1289 | 1165 | ||
1290 | if (!netif_running(dev)) | ||
1291 | return -ENETDOWN; | ||
1292 | |||
1293 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 1166 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
1294 | 1167 | ||
1295 | if (sdata->vif.type != NL80211_IFTYPE_STATION && | 1168 | if (sdata->vif.type != NL80211_IFTYPE_STATION && |
@@ -1300,6 +1173,119 @@ static int ieee80211_scan(struct wiphy *wiphy, | |||
1300 | return ieee80211_request_scan(sdata, req); | 1173 | return ieee80211_request_scan(sdata, req); |
1301 | } | 1174 | } |
1302 | 1175 | ||
1176 | static int ieee80211_auth(struct wiphy *wiphy, struct net_device *dev, | ||
1177 | struct cfg80211_auth_request *req) | ||
1178 | { | ||
1179 | struct ieee80211_sub_if_data *sdata; | ||
1180 | |||
1181 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
1182 | |||
1183 | switch (req->auth_type) { | ||
1184 | case NL80211_AUTHTYPE_OPEN_SYSTEM: | ||
1185 | sdata->u.mgd.auth_algs = IEEE80211_AUTH_ALG_OPEN; | ||
1186 | break; | ||
1187 | case NL80211_AUTHTYPE_SHARED_KEY: | ||
1188 | sdata->u.mgd.auth_algs = IEEE80211_AUTH_ALG_SHARED_KEY; | ||
1189 | break; | ||
1190 | case NL80211_AUTHTYPE_FT: | ||
1191 | sdata->u.mgd.auth_algs = IEEE80211_AUTH_ALG_FT; | ||
1192 | break; | ||
1193 | case NL80211_AUTHTYPE_NETWORK_EAP: | ||
1194 | sdata->u.mgd.auth_algs = IEEE80211_AUTH_ALG_LEAP; | ||
1195 | break; | ||
1196 | default: | ||
1197 | return -EOPNOTSUPP; | ||
1198 | } | ||
1199 | |||
1200 | memcpy(sdata->u.mgd.bssid, req->peer_addr, ETH_ALEN); | ||
1201 | sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_BSSID_SEL; | ||
1202 | sdata->u.mgd.flags |= IEEE80211_STA_BSSID_SET; | ||
1203 | |||
1204 | /* TODO: req->chan */ | ||
1205 | sdata->u.mgd.flags |= IEEE80211_STA_AUTO_CHANNEL_SEL; | ||
1206 | |||
1207 | if (req->ssid) { | ||
1208 | sdata->u.mgd.flags |= IEEE80211_STA_SSID_SET; | ||
1209 | memcpy(sdata->u.mgd.ssid, req->ssid, req->ssid_len); | ||
1210 | sdata->u.mgd.ssid_len = req->ssid_len; | ||
1211 | sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_SSID_SEL; | ||
1212 | } | ||
1213 | |||
1214 | kfree(sdata->u.mgd.sme_auth_ie); | ||
1215 | sdata->u.mgd.sme_auth_ie = NULL; | ||
1216 | sdata->u.mgd.sme_auth_ie_len = 0; | ||
1217 | if (req->ie) { | ||
1218 | sdata->u.mgd.sme_auth_ie = kmalloc(req->ie_len, GFP_KERNEL); | ||
1219 | if (sdata->u.mgd.sme_auth_ie == NULL) | ||
1220 | return -ENOMEM; | ||
1221 | memcpy(sdata->u.mgd.sme_auth_ie, req->ie, req->ie_len); | ||
1222 | sdata->u.mgd.sme_auth_ie_len = req->ie_len; | ||
1223 | } | ||
1224 | |||
1225 | sdata->u.mgd.flags |= IEEE80211_STA_EXT_SME; | ||
1226 | sdata->u.mgd.state = IEEE80211_STA_MLME_DIRECT_PROBE; | ||
1227 | ieee80211_sta_req_auth(sdata); | ||
1228 | return 0; | ||
1229 | } | ||
1230 | |||
1231 | static int ieee80211_assoc(struct wiphy *wiphy, struct net_device *dev, | ||
1232 | struct cfg80211_assoc_request *req) | ||
1233 | { | ||
1234 | struct ieee80211_sub_if_data *sdata; | ||
1235 | int ret; | ||
1236 | |||
1237 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
1238 | |||
1239 | if (memcmp(sdata->u.mgd.bssid, req->peer_addr, ETH_ALEN) != 0 || | ||
1240 | !(sdata->u.mgd.flags & IEEE80211_STA_AUTHENTICATED)) | ||
1241 | return -ENOLINK; /* not authenticated */ | ||
1242 | |||
1243 | sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_BSSID_SEL; | ||
1244 | sdata->u.mgd.flags |= IEEE80211_STA_BSSID_SET; | ||
1245 | |||
1246 | /* TODO: req->chan */ | ||
1247 | sdata->u.mgd.flags |= IEEE80211_STA_AUTO_CHANNEL_SEL; | ||
1248 | |||
1249 | if (req->ssid) { | ||
1250 | sdata->u.mgd.flags |= IEEE80211_STA_SSID_SET; | ||
1251 | memcpy(sdata->u.mgd.ssid, req->ssid, req->ssid_len); | ||
1252 | sdata->u.mgd.ssid_len = req->ssid_len; | ||
1253 | sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_SSID_SEL; | ||
1254 | } else | ||
1255 | sdata->u.mgd.flags |= IEEE80211_STA_AUTO_SSID_SEL; | ||
1256 | |||
1257 | ret = ieee80211_sta_set_extra_ie(sdata, req->ie, req->ie_len); | ||
1258 | if (ret) | ||
1259 | return ret; | ||
1260 | |||
1261 | sdata->u.mgd.flags |= IEEE80211_STA_EXT_SME; | ||
1262 | sdata->u.mgd.state = IEEE80211_STA_MLME_ASSOCIATE; | ||
1263 | ieee80211_sta_req_auth(sdata); | ||
1264 | return 0; | ||
1265 | } | ||
1266 | |||
1267 | static int ieee80211_deauth(struct wiphy *wiphy, struct net_device *dev, | ||
1268 | struct cfg80211_deauth_request *req) | ||
1269 | { | ||
1270 | struct ieee80211_sub_if_data *sdata; | ||
1271 | |||
1272 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
1273 | |||
1274 | /* TODO: req->ie */ | ||
1275 | return ieee80211_sta_deauthenticate(sdata, req->reason_code); | ||
1276 | } | ||
1277 | |||
1278 | static int ieee80211_disassoc(struct wiphy *wiphy, struct net_device *dev, | ||
1279 | struct cfg80211_disassoc_request *req) | ||
1280 | { | ||
1281 | struct ieee80211_sub_if_data *sdata; | ||
1282 | |||
1283 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
1284 | |||
1285 | /* TODO: req->ie */ | ||
1286 | return ieee80211_sta_disassociate(sdata, req->reason_code); | ||
1287 | } | ||
1288 | |||
1303 | struct cfg80211_ops mac80211_config_ops = { | 1289 | struct cfg80211_ops mac80211_config_ops = { |
1304 | .add_virtual_intf = ieee80211_add_iface, | 1290 | .add_virtual_intf = ieee80211_add_iface, |
1305 | .del_virtual_intf = ieee80211_del_iface, | 1291 | .del_virtual_intf = ieee80211_del_iface, |
@@ -1329,8 +1315,11 @@ struct cfg80211_ops mac80211_config_ops = { | |||
1329 | .change_bss = ieee80211_change_bss, | 1315 | .change_bss = ieee80211_change_bss, |
1330 | .set_txq_params = ieee80211_set_txq_params, | 1316 | .set_txq_params = ieee80211_set_txq_params, |
1331 | .set_channel = ieee80211_set_channel, | 1317 | .set_channel = ieee80211_set_channel, |
1332 | .set_mgmt_extra_ie = ieee80211_set_mgmt_extra_ie, | ||
1333 | .suspend = ieee80211_suspend, | 1318 | .suspend = ieee80211_suspend, |
1334 | .resume = ieee80211_resume, | 1319 | .resume = ieee80211_resume, |
1335 | .scan = ieee80211_scan, | 1320 | .scan = ieee80211_scan, |
1321 | .auth = ieee80211_auth, | ||
1322 | .assoc = ieee80211_assoc, | ||
1323 | .deauth = ieee80211_deauth, | ||
1324 | .disassoc = ieee80211_disassoc, | ||
1336 | }; | 1325 | }; |
diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index e37f557de3f3..210b9b6fecd2 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c | |||
@@ -40,6 +40,10 @@ static const struct file_operations name## _ops = { \ | |||
40 | local->debugfs.name = debugfs_create_file(#name, 0400, phyd, \ | 40 | local->debugfs.name = debugfs_create_file(#name, 0400, phyd, \ |
41 | local, &name## _ops); | 41 | local, &name## _ops); |
42 | 42 | ||
43 | #define DEBUGFS_ADD_MODE(name, mode) \ | ||
44 | local->debugfs.name = debugfs_create_file(#name, mode, phyd, \ | ||
45 | local, &name## _ops); | ||
46 | |||
43 | #define DEBUGFS_DEL(name) \ | 47 | #define DEBUGFS_DEL(name) \ |
44 | debugfs_remove(local->debugfs.name); \ | 48 | debugfs_remove(local->debugfs.name); \ |
45 | local->debugfs.name = NULL; | 49 | local->debugfs.name = NULL; |
@@ -113,6 +117,24 @@ static const struct file_operations tsf_ops = { | |||
113 | .open = mac80211_open_file_generic | 117 | .open = mac80211_open_file_generic |
114 | }; | 118 | }; |
115 | 119 | ||
120 | static ssize_t reset_write(struct file *file, const char __user *user_buf, | ||
121 | size_t count, loff_t *ppos) | ||
122 | { | ||
123 | struct ieee80211_local *local = file->private_data; | ||
124 | |||
125 | rtnl_lock(); | ||
126 | __ieee80211_suspend(&local->hw); | ||
127 | __ieee80211_resume(&local->hw); | ||
128 | rtnl_unlock(); | ||
129 | |||
130 | return count; | ||
131 | } | ||
132 | |||
133 | static const struct file_operations reset_ops = { | ||
134 | .write = reset_write, | ||
135 | .open = mac80211_open_file_generic, | ||
136 | }; | ||
137 | |||
116 | /* statistics stuff */ | 138 | /* statistics stuff */ |
117 | 139 | ||
118 | #define DEBUGFS_STATS_FILE(name, buflen, fmt, value...) \ | 140 | #define DEBUGFS_STATS_FILE(name, buflen, fmt, value...) \ |
@@ -254,6 +276,7 @@ void debugfs_hw_add(struct ieee80211_local *local) | |||
254 | DEBUGFS_ADD(total_ps_buffered); | 276 | DEBUGFS_ADD(total_ps_buffered); |
255 | DEBUGFS_ADD(wep_iv); | 277 | DEBUGFS_ADD(wep_iv); |
256 | DEBUGFS_ADD(tsf); | 278 | DEBUGFS_ADD(tsf); |
279 | DEBUGFS_ADD_MODE(reset, 0200); | ||
257 | 280 | ||
258 | statsd = debugfs_create_dir("statistics", phyd); | 281 | statsd = debugfs_create_dir("statistics", phyd); |
259 | local->debugfs.statistics = statsd; | 282 | local->debugfs.statistics = statsd; |
@@ -308,6 +331,7 @@ void debugfs_hw_del(struct ieee80211_local *local) | |||
308 | DEBUGFS_DEL(total_ps_buffered); | 331 | DEBUGFS_DEL(total_ps_buffered); |
309 | DEBUGFS_DEL(wep_iv); | 332 | DEBUGFS_DEL(wep_iv); |
310 | DEBUGFS_DEL(tsf); | 333 | DEBUGFS_DEL(tsf); |
334 | DEBUGFS_DEL(reset); | ||
311 | 335 | ||
312 | DEBUGFS_STATS_DEL(transmitted_fragment_count); | 336 | DEBUGFS_STATS_DEL(transmitted_fragment_count); |
313 | DEBUGFS_STATS_DEL(multicast_transmitted_frame_count); | 337 | DEBUGFS_STATS_DEL(multicast_transmitted_frame_count); |
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index f4becc12904e..3201e1f96365 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c | |||
@@ -812,8 +812,9 @@ int ieee80211_ibss_commit(struct ieee80211_sub_if_data *sdata) | |||
812 | 812 | ||
813 | ifibss->ibss_join_req = jiffies; | 813 | ifibss->ibss_join_req = jiffies; |
814 | ifibss->state = IEEE80211_IBSS_MLME_SEARCH; | 814 | ifibss->state = IEEE80211_IBSS_MLME_SEARCH; |
815 | set_bit(IEEE80211_IBSS_REQ_RUN, &ifibss->request); | ||
815 | 816 | ||
816 | return ieee80211_sta_find_ibss(sdata); | 817 | return 0; |
817 | } | 818 | } |
818 | 819 | ||
819 | int ieee80211_ibss_set_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t len) | 820 | int ieee80211_ibss_set_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t len) |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index fbb91f1aebb2..e6ed78cb16b3 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -149,11 +149,6 @@ struct ieee80211_tx_data { | |||
149 | 149 | ||
150 | struct ieee80211_channel *channel; | 150 | struct ieee80211_channel *channel; |
151 | 151 | ||
152 | /* Extra fragments (in addition to the first fragment | ||
153 | * in skb) */ | ||
154 | struct sk_buff **extra_frag; | ||
155 | int num_extra_frag; | ||
156 | |||
157 | u16 ethertype; | 152 | u16 ethertype; |
158 | unsigned int flags; | 153 | unsigned int flags; |
159 | }; | 154 | }; |
@@ -189,12 +184,6 @@ struct ieee80211_rx_data { | |||
189 | u16 tkip_iv16; | 184 | u16 tkip_iv16; |
190 | }; | 185 | }; |
191 | 186 | ||
192 | struct ieee80211_tx_stored_packet { | ||
193 | struct sk_buff *skb; | ||
194 | struct sk_buff **extra_frag; | ||
195 | int num_extra_frag; | ||
196 | }; | ||
197 | |||
198 | struct beacon_data { | 187 | struct beacon_data { |
199 | u8 *head, *tail; | 188 | u8 *head, *tail; |
200 | int head_len, tail_len; | 189 | int head_len, tail_len; |
@@ -247,8 +236,9 @@ struct mesh_preq_queue { | |||
247 | #define IEEE80211_STA_ASSOCIATED BIT(4) | 236 | #define IEEE80211_STA_ASSOCIATED BIT(4) |
248 | #define IEEE80211_STA_PROBEREQ_POLL BIT(5) | 237 | #define IEEE80211_STA_PROBEREQ_POLL BIT(5) |
249 | #define IEEE80211_STA_CREATE_IBSS BIT(6) | 238 | #define IEEE80211_STA_CREATE_IBSS BIT(6) |
250 | #define IEEE80211_STA_MIXED_CELL BIT(7) | 239 | /* hole at 7, please re-use */ |
251 | #define IEEE80211_STA_WMM_ENABLED BIT(8) | 240 | #define IEEE80211_STA_WMM_ENABLED BIT(8) |
241 | /* hole at 9, please re-use */ | ||
252 | #define IEEE80211_STA_AUTO_SSID_SEL BIT(10) | 242 | #define IEEE80211_STA_AUTO_SSID_SEL BIT(10) |
253 | #define IEEE80211_STA_AUTO_BSSID_SEL BIT(11) | 243 | #define IEEE80211_STA_AUTO_BSSID_SEL BIT(11) |
254 | #define IEEE80211_STA_AUTO_CHANNEL_SEL BIT(12) | 244 | #define IEEE80211_STA_AUTO_CHANNEL_SEL BIT(12) |
@@ -256,6 +246,7 @@ struct mesh_preq_queue { | |||
256 | #define IEEE80211_STA_TKIP_WEP_USED BIT(14) | 246 | #define IEEE80211_STA_TKIP_WEP_USED BIT(14) |
257 | #define IEEE80211_STA_CSA_RECEIVED BIT(15) | 247 | #define IEEE80211_STA_CSA_RECEIVED BIT(15) |
258 | #define IEEE80211_STA_MFP_ENABLED BIT(16) | 248 | #define IEEE80211_STA_MFP_ENABLED BIT(16) |
249 | #define IEEE80211_STA_EXT_SME BIT(17) | ||
259 | /* flags for MLME request */ | 250 | /* flags for MLME request */ |
260 | #define IEEE80211_STA_REQ_SCAN 0 | 251 | #define IEEE80211_STA_REQ_SCAN 0 |
261 | #define IEEE80211_STA_REQ_DIRECT_PROBE 1 | 252 | #define IEEE80211_STA_REQ_DIRECT_PROBE 1 |
@@ -266,12 +257,14 @@ struct mesh_preq_queue { | |||
266 | #define IEEE80211_AUTH_ALG_OPEN BIT(0) | 257 | #define IEEE80211_AUTH_ALG_OPEN BIT(0) |
267 | #define IEEE80211_AUTH_ALG_SHARED_KEY BIT(1) | 258 | #define IEEE80211_AUTH_ALG_SHARED_KEY BIT(1) |
268 | #define IEEE80211_AUTH_ALG_LEAP BIT(2) | 259 | #define IEEE80211_AUTH_ALG_LEAP BIT(2) |
260 | #define IEEE80211_AUTH_ALG_FT BIT(3) | ||
269 | 261 | ||
270 | struct ieee80211_if_managed { | 262 | struct ieee80211_if_managed { |
271 | struct timer_list timer; | 263 | struct timer_list timer; |
272 | struct timer_list chswitch_timer; | 264 | struct timer_list chswitch_timer; |
273 | struct work_struct work; | 265 | struct work_struct work; |
274 | struct work_struct chswitch_work; | 266 | struct work_struct chswitch_work; |
267 | struct work_struct beacon_loss_work; | ||
275 | 268 | ||
276 | u8 bssid[ETH_ALEN], prev_bssid[ETH_ALEN]; | 269 | u8 bssid[ETH_ALEN], prev_bssid[ETH_ALEN]; |
277 | 270 | ||
@@ -305,6 +298,7 @@ struct ieee80211_if_managed { | |||
305 | unsigned long request; | 298 | unsigned long request; |
306 | 299 | ||
307 | unsigned long last_probe; | 300 | unsigned long last_probe; |
301 | unsigned long last_beacon; | ||
308 | 302 | ||
309 | unsigned int flags; | 303 | unsigned int flags; |
310 | 304 | ||
@@ -321,20 +315,8 @@ struct ieee80211_if_managed { | |||
321 | int wmm_last_param_set; | 315 | int wmm_last_param_set; |
322 | 316 | ||
323 | /* Extra IE data for management frames */ | 317 | /* Extra IE data for management frames */ |
324 | u8 *ie_probereq; | 318 | u8 *sme_auth_ie; |
325 | size_t ie_probereq_len; | 319 | size_t sme_auth_ie_len; |
326 | u8 *ie_proberesp; | ||
327 | size_t ie_proberesp_len; | ||
328 | u8 *ie_auth; | ||
329 | size_t ie_auth_len; | ||
330 | u8 *ie_assocreq; | ||
331 | size_t ie_assocreq_len; | ||
332 | u8 *ie_reassocreq; | ||
333 | size_t ie_reassocreq_len; | ||
334 | u8 *ie_deauth; | ||
335 | size_t ie_deauth_len; | ||
336 | u8 *ie_disassoc; | ||
337 | size_t ie_disassoc_len; | ||
338 | }; | 320 | }; |
339 | 321 | ||
340 | enum ieee80211_ibss_flags { | 322 | enum ieee80211_ibss_flags { |
@@ -421,7 +403,6 @@ struct ieee80211_if_mesh { | |||
421 | * | 403 | * |
422 | * @IEEE80211_SDATA_ALLMULTI: interface wants all multicast packets | 404 | * @IEEE80211_SDATA_ALLMULTI: interface wants all multicast packets |
423 | * @IEEE80211_SDATA_PROMISC: interface is promisc | 405 | * @IEEE80211_SDATA_PROMISC: interface is promisc |
424 | * @IEEE80211_SDATA_USERSPACE_MLME: userspace MLME is active | ||
425 | * @IEEE80211_SDATA_OPERATING_GMODE: operating in G-only mode | 406 | * @IEEE80211_SDATA_OPERATING_GMODE: operating in G-only mode |
426 | * @IEEE80211_SDATA_DONT_BRIDGE_PACKETS: bridge packets between | 407 | * @IEEE80211_SDATA_DONT_BRIDGE_PACKETS: bridge packets between |
427 | * associated stations and deliver multicast frames both | 408 | * associated stations and deliver multicast frames both |
@@ -430,9 +411,8 @@ struct ieee80211_if_mesh { | |||
430 | enum ieee80211_sub_if_data_flags { | 411 | enum ieee80211_sub_if_data_flags { |
431 | IEEE80211_SDATA_ALLMULTI = BIT(0), | 412 | IEEE80211_SDATA_ALLMULTI = BIT(0), |
432 | IEEE80211_SDATA_PROMISC = BIT(1), | 413 | IEEE80211_SDATA_PROMISC = BIT(1), |
433 | IEEE80211_SDATA_USERSPACE_MLME = BIT(2), | 414 | IEEE80211_SDATA_OPERATING_GMODE = BIT(2), |
434 | IEEE80211_SDATA_OPERATING_GMODE = BIT(3), | 415 | IEEE80211_SDATA_DONT_BRIDGE_PACKETS = BIT(3), |
435 | IEEE80211_SDATA_DONT_BRIDGE_PACKETS = BIT(4), | ||
436 | }; | 416 | }; |
437 | 417 | ||
438 | struct ieee80211_sub_if_data { | 418 | struct ieee80211_sub_if_data { |
@@ -598,6 +578,8 @@ enum queue_stop_reason { | |||
598 | IEEE80211_QUEUE_STOP_REASON_PS, | 578 | IEEE80211_QUEUE_STOP_REASON_PS, |
599 | IEEE80211_QUEUE_STOP_REASON_CSA, | 579 | IEEE80211_QUEUE_STOP_REASON_CSA, |
600 | IEEE80211_QUEUE_STOP_REASON_AGGREGATION, | 580 | IEEE80211_QUEUE_STOP_REASON_AGGREGATION, |
581 | IEEE80211_QUEUE_STOP_REASON_SUSPEND, | ||
582 | IEEE80211_QUEUE_STOP_REASON_PENDING, | ||
601 | }; | 583 | }; |
602 | 584 | ||
603 | struct ieee80211_master_priv { | 585 | struct ieee80211_master_priv { |
@@ -612,12 +594,7 @@ struct ieee80211_local { | |||
612 | 594 | ||
613 | const struct ieee80211_ops *ops; | 595 | const struct ieee80211_ops *ops; |
614 | 596 | ||
615 | /* AC queue corresponding to each AMPDU queue */ | 597 | 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 */ | 598 | /* also used to protect ampdu_ac_queue and amdpu_ac_stop_refcnt */ |
622 | spinlock_t queue_stop_reason_lock; | 599 | spinlock_t queue_stop_reason_lock; |
623 | 600 | ||
@@ -654,11 +631,17 @@ struct ieee80211_local { | |||
654 | struct sta_info *sta_hash[STA_HASH_SIZE]; | 631 | struct sta_info *sta_hash[STA_HASH_SIZE]; |
655 | struct timer_list sta_cleanup; | 632 | struct timer_list sta_cleanup; |
656 | 633 | ||
657 | unsigned long queues_pending[BITS_TO_LONGS(IEEE80211_MAX_QUEUES)]; | 634 | struct sk_buff_head pending[IEEE80211_MAX_QUEUES]; |
658 | unsigned long queues_pending_run[BITS_TO_LONGS(IEEE80211_MAX_QUEUES)]; | ||
659 | struct ieee80211_tx_stored_packet pending_packet[IEEE80211_MAX_QUEUES]; | ||
660 | struct tasklet_struct tx_pending_tasklet; | 635 | struct tasklet_struct tx_pending_tasklet; |
661 | 636 | ||
637 | /* | ||
638 | * This lock is used to prevent concurrent A-MPDU | ||
639 | * session start/stop processing, this thus also | ||
640 | * synchronises the ->ampdu_action() callback to | ||
641 | * drivers and limits it to one at a time. | ||
642 | */ | ||
643 | spinlock_t ampdu_lock; | ||
644 | |||
662 | /* number of interfaces with corresponding IFF_ flags */ | 645 | /* number of interfaces with corresponding IFF_ flags */ |
663 | atomic_t iff_allmultis, iff_promiscs; | 646 | atomic_t iff_allmultis, iff_promiscs; |
664 | 647 | ||
@@ -774,6 +757,7 @@ struct ieee80211_local { | |||
774 | struct dentry *total_ps_buffered; | 757 | struct dentry *total_ps_buffered; |
775 | struct dentry *wep_iv; | 758 | struct dentry *wep_iv; |
776 | struct dentry *tsf; | 759 | struct dentry *tsf; |
760 | struct dentry *reset; | ||
777 | struct dentry *statistics; | 761 | struct dentry *statistics; |
778 | struct local_debugfsdentries_statsdentries { | 762 | struct local_debugfsdentries_statsdentries { |
779 | struct dentry *transmitted_fragment_count; | 763 | struct dentry *transmitted_fragment_count; |
@@ -969,7 +953,7 @@ ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, | |||
969 | struct sk_buff *skb, | 953 | struct sk_buff *skb, |
970 | struct ieee80211_rx_status *rx_status); | 954 | struct ieee80211_rx_status *rx_status); |
971 | int ieee80211_sta_set_extra_ie(struct ieee80211_sub_if_data *sdata, | 955 | int ieee80211_sta_set_extra_ie(struct ieee80211_sub_if_data *sdata, |
972 | char *ie, size_t len); | 956 | const char *ie, size_t len); |
973 | 957 | ||
974 | void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local); | 958 | void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local); |
975 | void ieee80211_scan_failed(struct ieee80211_local *local); | 959 | void ieee80211_scan_failed(struct ieee80211_local *local); |
@@ -1053,8 +1037,19 @@ void ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata, | |||
1053 | u8 pwr_constr_elem_len); | 1037 | u8 pwr_constr_elem_len); |
1054 | 1038 | ||
1055 | /* Suspend/resume */ | 1039 | /* Suspend/resume */ |
1040 | #ifdef CONFIG_PM | ||
1056 | int __ieee80211_suspend(struct ieee80211_hw *hw); | 1041 | int __ieee80211_suspend(struct ieee80211_hw *hw); |
1057 | int __ieee80211_resume(struct ieee80211_hw *hw); | 1042 | int __ieee80211_resume(struct ieee80211_hw *hw); |
1043 | #else | ||
1044 | static inline int __ieee80211_suspend(struct ieee80211_hw *hw) | ||
1045 | { | ||
1046 | return 0; | ||
1047 | } | ||
1048 | static inline int __ieee80211_resume(struct ieee80211_hw *hw) | ||
1049 | { | ||
1050 | return 0; | ||
1051 | } | ||
1052 | #endif | ||
1058 | 1053 | ||
1059 | /* utility functions/constants */ | 1054 | /* utility functions/constants */ |
1060 | extern void *mac80211_wiphy_privid; /* for wiphy privid */ | 1055 | extern void *mac80211_wiphy_privid; /* for wiphy privid */ |
@@ -1081,6 +1076,9 @@ void ieee80211_dynamic_ps_timer(unsigned long data); | |||
1081 | void ieee80211_send_nullfunc(struct ieee80211_local *local, | 1076 | void ieee80211_send_nullfunc(struct ieee80211_local *local, |
1082 | struct ieee80211_sub_if_data *sdata, | 1077 | struct ieee80211_sub_if_data *sdata, |
1083 | int powersave); | 1078 | int powersave); |
1079 | void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata, | ||
1080 | struct ieee80211_hdr *hdr); | ||
1081 | void ieee80211_beacon_loss_work(struct work_struct *work); | ||
1084 | 1082 | ||
1085 | void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw, | 1083 | void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw, |
1086 | enum queue_stop_reason reason); | 1084 | enum queue_stop_reason reason); |
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index f9f27b9cadbe..91e8e1bacaaa 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
@@ -261,8 +261,7 @@ static int ieee80211_open(struct net_device *dev) | |||
261 | ieee80211_bss_info_change_notify(sdata, changed); | 261 | ieee80211_bss_info_change_notify(sdata, changed); |
262 | ieee80211_enable_keys(sdata); | 262 | ieee80211_enable_keys(sdata); |
263 | 263 | ||
264 | if (sdata->vif.type == NL80211_IFTYPE_STATION && | 264 | if (sdata->vif.type == NL80211_IFTYPE_STATION) |
265 | !(sdata->flags & IEEE80211_SDATA_USERSPACE_MLME)) | ||
266 | netif_carrier_off(dev); | 265 | netif_carrier_off(dev); |
267 | else | 266 | else |
268 | netif_carrier_on(dev); | 267 | netif_carrier_on(dev); |
@@ -478,6 +477,9 @@ static int ieee80211_stop(struct net_device *dev) | |||
478 | */ | 477 | */ |
479 | cancel_work_sync(&sdata->u.mgd.work); | 478 | cancel_work_sync(&sdata->u.mgd.work); |
480 | cancel_work_sync(&sdata->u.mgd.chswitch_work); | 479 | cancel_work_sync(&sdata->u.mgd.chswitch_work); |
480 | |||
481 | cancel_work_sync(&sdata->u.mgd.beacon_loss_work); | ||
482 | |||
481 | /* | 483 | /* |
482 | * When we get here, the interface is marked down. | 484 | * When we get here, the interface is marked down. |
483 | * Call synchronize_rcu() to wait for the RX path | 485 | * Call synchronize_rcu() to wait for the RX path |
@@ -653,13 +655,7 @@ static void ieee80211_teardown_sdata(struct net_device *dev) | |||
653 | kfree(sdata->u.mgd.extra_ie); | 655 | kfree(sdata->u.mgd.extra_ie); |
654 | kfree(sdata->u.mgd.assocreq_ies); | 656 | kfree(sdata->u.mgd.assocreq_ies); |
655 | kfree(sdata->u.mgd.assocresp_ies); | 657 | kfree(sdata->u.mgd.assocresp_ies); |
656 | kfree(sdata->u.mgd.ie_probereq); | 658 | kfree(sdata->u.mgd.sme_auth_ie); |
657 | kfree(sdata->u.mgd.ie_proberesp); | ||
658 | kfree(sdata->u.mgd.ie_auth); | ||
659 | kfree(sdata->u.mgd.ie_assocreq); | ||
660 | kfree(sdata->u.mgd.ie_reassocreq); | ||
661 | kfree(sdata->u.mgd.ie_deauth); | ||
662 | kfree(sdata->u.mgd.ie_disassoc); | ||
663 | break; | 659 | break; |
664 | case NL80211_IFTYPE_WDS: | 660 | case NL80211_IFTYPE_WDS: |
665 | case NL80211_IFTYPE_AP_VLAN: | 661 | case NL80211_IFTYPE_AP_VLAN: |
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index f38db4d37e5d..a6f1d8a869bc 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -161,12 +161,6 @@ int ieee80211_if_config(struct ieee80211_sub_if_data *sdata, u32 changed) | |||
161 | if (WARN_ON(!netif_running(sdata->dev))) | 161 | if (WARN_ON(!netif_running(sdata->dev))) |
162 | return 0; | 162 | return 0; |
163 | 163 | ||
164 | if (WARN_ON(sdata->vif.type == NL80211_IFTYPE_AP_VLAN)) | ||
165 | return -EINVAL; | ||
166 | |||
167 | if (!local->ops->config_interface) | ||
168 | return 0; | ||
169 | |||
170 | memset(&conf, 0, sizeof(conf)); | 164 | memset(&conf, 0, sizeof(conf)); |
171 | 165 | ||
172 | if (sdata->vif.type == NL80211_IFTYPE_STATION) | 166 | if (sdata->vif.type == NL80211_IFTYPE_STATION) |
@@ -183,6 +177,9 @@ int ieee80211_if_config(struct ieee80211_sub_if_data *sdata, u32 changed) | |||
183 | return -EINVAL; | 177 | return -EINVAL; |
184 | } | 178 | } |
185 | 179 | ||
180 | if (!local->ops->config_interface) | ||
181 | return 0; | ||
182 | |||
186 | switch (sdata->vif.type) { | 183 | switch (sdata->vif.type) { |
187 | case NL80211_IFTYPE_AP: | 184 | case NL80211_IFTYPE_AP: |
188 | case NL80211_IFTYPE_ADHOC: | 185 | case NL80211_IFTYPE_ADHOC: |
@@ -224,9 +221,6 @@ int ieee80211_if_config(struct ieee80211_sub_if_data *sdata, u32 changed) | |||
224 | } | 221 | } |
225 | } | 222 | } |
226 | 223 | ||
227 | if (WARN_ON(!conf.bssid && (changed & IEEE80211_IFCC_BSSID))) | ||
228 | return -EINVAL; | ||
229 | |||
230 | conf.changed = changed; | 224 | conf.changed = changed; |
231 | 225 | ||
232 | return local->ops->config_interface(local_to_hw(local), | 226 | return local->ops->config_interface(local_to_hw(local), |
@@ -780,13 +774,10 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
780 | setup_timer(&local->dynamic_ps_timer, | 774 | setup_timer(&local->dynamic_ps_timer, |
781 | ieee80211_dynamic_ps_timer, (unsigned long) local); | 775 | ieee80211_dynamic_ps_timer, (unsigned long) local); |
782 | 776 | ||
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 | |||
788 | sta_info_init(local); | 777 | sta_info_init(local); |
789 | 778 | ||
779 | for (i = 0; i < IEEE80211_MAX_QUEUES; i++) | ||
780 | skb_queue_head_init(&local->pending[i]); | ||
790 | tasklet_init(&local->tx_pending_tasklet, ieee80211_tx_pending, | 781 | tasklet_init(&local->tx_pending_tasklet, ieee80211_tx_pending, |
791 | (unsigned long)local); | 782 | (unsigned long)local); |
792 | tasklet_disable(&local->tx_pending_tasklet); | 783 | tasklet_disable(&local->tx_pending_tasklet); |
@@ -799,6 +790,8 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | |||
799 | skb_queue_head_init(&local->skb_queue); | 790 | skb_queue_head_init(&local->skb_queue); |
800 | skb_queue_head_init(&local->skb_queue_unreliable); | 791 | skb_queue_head_init(&local->skb_queue_unreliable); |
801 | 792 | ||
793 | spin_lock_init(&local->ampdu_lock); | ||
794 | |||
802 | return local_to_hw(local); | 795 | return local_to_hw(local); |
803 | } | 796 | } |
804 | EXPORT_SYMBOL(ieee80211_alloc_hw); | 797 | EXPORT_SYMBOL(ieee80211_alloc_hw); |
@@ -876,10 +869,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) | |||
876 | */ | 869 | */ |
877 | if (hw->queues > IEEE80211_MAX_QUEUES) | 870 | if (hw->queues > IEEE80211_MAX_QUEUES) |
878 | hw->queues = IEEE80211_MAX_QUEUES; | 871 | hw->queues = IEEE80211_MAX_QUEUES; |
879 | if (hw->ampdu_queues > IEEE80211_MAX_AMPDU_QUEUES) | ||
880 | hw->ampdu_queues = IEEE80211_MAX_AMPDU_QUEUES; | ||
881 | if (hw->queues < 4) | ||
882 | hw->ampdu_queues = 0; | ||
883 | 872 | ||
884 | mdev = alloc_netdev_mq(sizeof(struct ieee80211_master_priv), | 873 | mdev = alloc_netdev_mq(sizeof(struct ieee80211_master_priv), |
885 | "wmaster%d", ieee80211_master_setup, | 874 | "wmaster%d", ieee80211_master_setup, |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 841b8450b3de..7ecda9d59d8a 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -30,7 +30,7 @@ | |||
30 | #define IEEE80211_ASSOC_TIMEOUT (HZ / 5) | 30 | #define IEEE80211_ASSOC_TIMEOUT (HZ / 5) |
31 | #define IEEE80211_ASSOC_MAX_TRIES 3 | 31 | #define IEEE80211_ASSOC_MAX_TRIES 3 |
32 | #define IEEE80211_MONITORING_INTERVAL (2 * HZ) | 32 | #define IEEE80211_MONITORING_INTERVAL (2 * HZ) |
33 | #define IEEE80211_PROBE_INTERVAL (60 * HZ) | 33 | #define IEEE80211_PROBE_IDLE_TIME (60 * HZ) |
34 | #define IEEE80211_RETRY_AUTH_INTERVAL (1 * HZ) | 34 | #define IEEE80211_RETRY_AUTH_INTERVAL (1 * HZ) |
35 | 35 | ||
36 | /* utils */ | 36 | /* utils */ |
@@ -82,38 +82,23 @@ static int ieee80211_compatible_rates(struct ieee80211_bss *bss, | |||
82 | 82 | ||
83 | /* frame sending functions */ | 83 | /* frame sending functions */ |
84 | 84 | ||
85 | static void add_extra_ies(struct sk_buff *skb, u8 *ies, size_t ies_len) | ||
86 | { | ||
87 | if (ies) | ||
88 | memcpy(skb_put(skb, ies_len), ies, ies_len); | ||
89 | } | ||
90 | |||
91 | static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) | 85 | static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) |
92 | { | 86 | { |
93 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 87 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
94 | struct ieee80211_local *local = sdata->local; | 88 | struct ieee80211_local *local = sdata->local; |
95 | struct sk_buff *skb; | 89 | struct sk_buff *skb; |
96 | struct ieee80211_mgmt *mgmt; | 90 | struct ieee80211_mgmt *mgmt; |
97 | u8 *pos, *ies, *ht_ie, *e_ies; | 91 | u8 *pos, *ies, *ht_ie; |
98 | int i, len, count, rates_len, supp_rates_len; | 92 | int i, len, count, rates_len, supp_rates_len; |
99 | u16 capab; | 93 | u16 capab; |
100 | struct ieee80211_bss *bss; | 94 | struct ieee80211_bss *bss; |
101 | int wmm = 0; | 95 | int wmm = 0; |
102 | struct ieee80211_supported_band *sband; | 96 | struct ieee80211_supported_band *sband; |
103 | u32 rates = 0; | 97 | u32 rates = 0; |
104 | size_t e_ies_len; | ||
105 | |||
106 | if (ifmgd->flags & IEEE80211_IBSS_PREV_BSSID_SET) { | ||
107 | e_ies = sdata->u.mgd.ie_reassocreq; | ||
108 | e_ies_len = sdata->u.mgd.ie_reassocreq_len; | ||
109 | } else { | ||
110 | e_ies = sdata->u.mgd.ie_assocreq; | ||
111 | e_ies_len = sdata->u.mgd.ie_assocreq_len; | ||
112 | } | ||
113 | 98 | ||
114 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + | 99 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + |
115 | sizeof(*mgmt) + 200 + ifmgd->extra_ie_len + | 100 | sizeof(*mgmt) + 200 + ifmgd->extra_ie_len + |
116 | ifmgd->ssid_len + e_ies_len); | 101 | ifmgd->ssid_len); |
117 | if (!skb) { | 102 | if (!skb) { |
118 | printk(KERN_DEBUG "%s: failed to allocate buffer for assoc " | 103 | printk(KERN_DEBUG "%s: failed to allocate buffer for assoc " |
119 | "frame\n", sdata->dev->name); | 104 | "frame\n", sdata->dev->name); |
@@ -304,8 +289,6 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) | |||
304 | memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs)); | 289 | memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs)); |
305 | } | 290 | } |
306 | 291 | ||
307 | add_extra_ies(skb, e_ies, e_ies_len); | ||
308 | |||
309 | kfree(ifmgd->assocreq_ies); | 292 | kfree(ifmgd->assocreq_ies); |
310 | ifmgd->assocreq_ies_len = (skb->data + skb->len) - ies; | 293 | ifmgd->assocreq_ies_len = (skb->data + skb->len) - ies; |
311 | ifmgd->assocreq_ies = kmalloc(ifmgd->assocreq_ies_len, GFP_KERNEL); | 294 | ifmgd->assocreq_ies = kmalloc(ifmgd->assocreq_ies_len, GFP_KERNEL); |
@@ -323,19 +306,8 @@ static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, | |||
323 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 306 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
324 | struct sk_buff *skb; | 307 | struct sk_buff *skb; |
325 | struct ieee80211_mgmt *mgmt; | 308 | struct ieee80211_mgmt *mgmt; |
326 | u8 *ies; | ||
327 | size_t ies_len; | ||
328 | |||
329 | if (stype == IEEE80211_STYPE_DEAUTH) { | ||
330 | ies = sdata->u.mgd.ie_deauth; | ||
331 | ies_len = sdata->u.mgd.ie_deauth_len; | ||
332 | } else { | ||
333 | ies = sdata->u.mgd.ie_disassoc; | ||
334 | ies_len = sdata->u.mgd.ie_disassoc_len; | ||
335 | } | ||
336 | 309 | ||
337 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt) + | 310 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt)); |
338 | ies_len); | ||
339 | if (!skb) { | 311 | if (!skb) { |
340 | printk(KERN_DEBUG "%s: failed to allocate buffer for " | 312 | printk(KERN_DEBUG "%s: failed to allocate buffer for " |
341 | "deauth/disassoc frame\n", sdata->dev->name); | 313 | "deauth/disassoc frame\n", sdata->dev->name); |
@@ -353,8 +325,6 @@ static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, | |||
353 | /* u.deauth.reason_code == u.disassoc.reason_code */ | 325 | /* u.deauth.reason_code == u.disassoc.reason_code */ |
354 | mgmt->u.deauth.reason_code = cpu_to_le16(reason); | 326 | mgmt->u.deauth.reason_code = cpu_to_le16(reason); |
355 | 327 | ||
356 | add_extra_ies(skb, ies, ies_len); | ||
357 | |||
358 | ieee80211_tx_skb(sdata, skb, ifmgd->flags & IEEE80211_STA_MFP_ENABLED); | 328 | ieee80211_tx_skb(sdata, skb, ifmgd->flags & IEEE80211_STA_MFP_ENABLED); |
359 | } | 329 | } |
360 | 330 | ||
@@ -640,6 +610,8 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, | |||
640 | bss_info_changed |= ieee80211_handle_bss_capability(sdata, | 610 | bss_info_changed |= ieee80211_handle_bss_capability(sdata, |
641 | bss->cbss.capability, bss->has_erp_value, bss->erp_value); | 611 | bss->cbss.capability, bss->has_erp_value, bss->erp_value); |
642 | 612 | ||
613 | cfg80211_hold_bss(&bss->cbss); | ||
614 | |||
643 | ieee80211_rx_bss_put(local, bss); | 615 | ieee80211_rx_bss_put(local, bss); |
644 | } | 616 | } |
645 | 617 | ||
@@ -682,6 +654,7 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, | |||
682 | static void ieee80211_direct_probe(struct ieee80211_sub_if_data *sdata) | 654 | static void ieee80211_direct_probe(struct ieee80211_sub_if_data *sdata) |
683 | { | 655 | { |
684 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 656 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
657 | struct ieee80211_local *local = sdata->local; | ||
685 | 658 | ||
686 | ifmgd->direct_probe_tries++; | 659 | ifmgd->direct_probe_tries++; |
687 | if (ifmgd->direct_probe_tries > IEEE80211_AUTH_MAX_TRIES) { | 660 | if (ifmgd->direct_probe_tries > IEEE80211_AUTH_MAX_TRIES) { |
@@ -697,6 +670,13 @@ static void ieee80211_direct_probe(struct ieee80211_sub_if_data *sdata) | |||
697 | ieee80211_rx_bss_remove(sdata, ifmgd->bssid, | 670 | ieee80211_rx_bss_remove(sdata, ifmgd->bssid, |
698 | sdata->local->hw.conf.channel->center_freq, | 671 | sdata->local->hw.conf.channel->center_freq, |
699 | ifmgd->ssid, ifmgd->ssid_len); | 672 | ifmgd->ssid, ifmgd->ssid_len); |
673 | |||
674 | /* | ||
675 | * We might have a pending scan which had no chance to run yet | ||
676 | * due to state == IEEE80211_STA_MLME_DIRECT_PROBE. | ||
677 | * Hence, queue the STAs work again | ||
678 | */ | ||
679 | queue_work(local->hw.workqueue, &ifmgd->work); | ||
700 | return; | 680 | return; |
701 | } | 681 | } |
702 | 682 | ||
@@ -721,6 +701,9 @@ static void ieee80211_direct_probe(struct ieee80211_sub_if_data *sdata) | |||
721 | static void ieee80211_authenticate(struct ieee80211_sub_if_data *sdata) | 701 | static void ieee80211_authenticate(struct ieee80211_sub_if_data *sdata) |
722 | { | 702 | { |
723 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 703 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
704 | struct ieee80211_local *local = sdata->local; | ||
705 | u8 *ies; | ||
706 | size_t ies_len; | ||
724 | 707 | ||
725 | ifmgd->auth_tries++; | 708 | ifmgd->auth_tries++; |
726 | if (ifmgd->auth_tries > IEEE80211_AUTH_MAX_TRIES) { | 709 | if (ifmgd->auth_tries > IEEE80211_AUTH_MAX_TRIES) { |
@@ -732,6 +715,13 @@ static void ieee80211_authenticate(struct ieee80211_sub_if_data *sdata) | |||
732 | ieee80211_rx_bss_remove(sdata, ifmgd->bssid, | 715 | ieee80211_rx_bss_remove(sdata, ifmgd->bssid, |
733 | sdata->local->hw.conf.channel->center_freq, | 716 | sdata->local->hw.conf.channel->center_freq, |
734 | ifmgd->ssid, ifmgd->ssid_len); | 717 | ifmgd->ssid, ifmgd->ssid_len); |
718 | |||
719 | /* | ||
720 | * We might have a pending scan which had no chance to run yet | ||
721 | * due to state == IEEE80211_STA_MLME_AUTHENTICATE. | ||
722 | * Hence, queue the STAs work again | ||
723 | */ | ||
724 | queue_work(local->hw.workqueue, &ifmgd->work); | ||
735 | return; | 725 | return; |
736 | } | 726 | } |
737 | 727 | ||
@@ -739,7 +729,14 @@ static void ieee80211_authenticate(struct ieee80211_sub_if_data *sdata) | |||
739 | printk(KERN_DEBUG "%s: authenticate with AP %pM\n", | 729 | printk(KERN_DEBUG "%s: authenticate with AP %pM\n", |
740 | sdata->dev->name, ifmgd->bssid); | 730 | sdata->dev->name, ifmgd->bssid); |
741 | 731 | ||
742 | ieee80211_send_auth(sdata, 1, ifmgd->auth_alg, NULL, 0, | 732 | if (ifmgd->flags & IEEE80211_STA_EXT_SME) { |
733 | ies = ifmgd->sme_auth_ie; | ||
734 | ies_len = ifmgd->sme_auth_ie_len; | ||
735 | } else { | ||
736 | ies = NULL; | ||
737 | ies_len = 0; | ||
738 | } | ||
739 | ieee80211_send_auth(sdata, 1, ifmgd->auth_alg, ies, ies_len, | ||
743 | ifmgd->bssid, 0); | 740 | ifmgd->bssid, 0); |
744 | ifmgd->auth_transaction = 2; | 741 | ifmgd->auth_transaction = 2; |
745 | 742 | ||
@@ -756,6 +753,8 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | |||
756 | { | 753 | { |
757 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 754 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
758 | struct ieee80211_local *local = sdata->local; | 755 | struct ieee80211_local *local = sdata->local; |
756 | struct ieee80211_conf *conf = &local_to_hw(local)->conf; | ||
757 | struct ieee80211_bss *bss; | ||
759 | struct sta_info *sta; | 758 | struct sta_info *sta; |
760 | u32 changed = 0, config_changed = 0; | 759 | u32 changed = 0, config_changed = 0; |
761 | 760 | ||
@@ -779,6 +778,15 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, | |||
779 | 778 | ||
780 | ieee80211_sta_tear_down_BA_sessions(sta); | 779 | ieee80211_sta_tear_down_BA_sessions(sta); |
781 | 780 | ||
781 | bss = ieee80211_rx_bss_get(local, ifmgd->bssid, | ||
782 | conf->channel->center_freq, | ||
783 | ifmgd->ssid, ifmgd->ssid_len); | ||
784 | |||
785 | if (bss) { | ||
786 | cfg80211_unhold_bss(&bss->cbss); | ||
787 | ieee80211_rx_bss_put(local, bss); | ||
788 | } | ||
789 | |||
782 | if (self_disconnected) { | 790 | if (self_disconnected) { |
783 | if (deauth) | 791 | if (deauth) |
784 | ieee80211_send_deauth_disassoc(sdata, | 792 | ieee80211_send_deauth_disassoc(sdata, |
@@ -854,7 +862,7 @@ static int ieee80211_privacy_mismatch(struct ieee80211_sub_if_data *sdata) | |||
854 | int wep_privacy; | 862 | int wep_privacy; |
855 | int privacy_invoked; | 863 | int privacy_invoked; |
856 | 864 | ||
857 | if (!ifmgd || (ifmgd->flags & IEEE80211_STA_MIXED_CELL)) | 865 | if (!ifmgd || (ifmgd->flags & IEEE80211_STA_EXT_SME)) |
858 | return 0; | 866 | return 0; |
859 | 867 | ||
860 | bss = ieee80211_rx_bss_get(local, ifmgd->bssid, | 868 | bss = ieee80211_rx_bss_get(local, ifmgd->bssid, |
@@ -878,6 +886,7 @@ static int ieee80211_privacy_mismatch(struct ieee80211_sub_if_data *sdata) | |||
878 | static void ieee80211_associate(struct ieee80211_sub_if_data *sdata) | 886 | static void ieee80211_associate(struct ieee80211_sub_if_data *sdata) |
879 | { | 887 | { |
880 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 888 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
889 | struct ieee80211_local *local = sdata->local; | ||
881 | 890 | ||
882 | ifmgd->assoc_tries++; | 891 | ifmgd->assoc_tries++; |
883 | if (ifmgd->assoc_tries > IEEE80211_ASSOC_MAX_TRIES) { | 892 | if (ifmgd->assoc_tries > IEEE80211_ASSOC_MAX_TRIES) { |
@@ -889,6 +898,12 @@ static void ieee80211_associate(struct ieee80211_sub_if_data *sdata) | |||
889 | ieee80211_rx_bss_remove(sdata, ifmgd->bssid, | 898 | ieee80211_rx_bss_remove(sdata, ifmgd->bssid, |
890 | sdata->local->hw.conf.channel->center_freq, | 899 | sdata->local->hw.conf.channel->center_freq, |
891 | ifmgd->ssid, ifmgd->ssid_len); | 900 | ifmgd->ssid, ifmgd->ssid_len); |
901 | /* | ||
902 | * We might have a pending scan which had no chance to run yet | ||
903 | * due to state == IEEE80211_STA_MLME_ASSOCIATE. | ||
904 | * Hence, queue the STAs work again | ||
905 | */ | ||
906 | queue_work(local->hw.workqueue, &ifmgd->work); | ||
892 | return; | 907 | return; |
893 | } | 908 | } |
894 | 909 | ||
@@ -907,13 +922,55 @@ static void ieee80211_associate(struct ieee80211_sub_if_data *sdata) | |||
907 | mod_timer(&ifmgd->timer, jiffies + IEEE80211_ASSOC_TIMEOUT); | 922 | mod_timer(&ifmgd->timer, jiffies + IEEE80211_ASSOC_TIMEOUT); |
908 | } | 923 | } |
909 | 924 | ||
925 | void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata, | ||
926 | struct ieee80211_hdr *hdr) | ||
927 | { | ||
928 | /* | ||
929 | * We can postpone the mgd.timer whenever receiving unicast frames | ||
930 | * from AP because we know that the connection is working both ways | ||
931 | * at that time. But multicast frames (and hence also beacons) must | ||
932 | * be ignored here, because we need to trigger the timer during | ||
933 | * data idle periods for sending the periodical probe request to | ||
934 | * the AP. | ||
935 | */ | ||
936 | if (!is_multicast_ether_addr(hdr->addr1)) | ||
937 | mod_timer(&sdata->u.mgd.timer, | ||
938 | jiffies + IEEE80211_MONITORING_INTERVAL); | ||
939 | } | ||
940 | |||
941 | void ieee80211_beacon_loss_work(struct work_struct *work) | ||
942 | { | ||
943 | struct ieee80211_sub_if_data *sdata = | ||
944 | container_of(work, struct ieee80211_sub_if_data, | ||
945 | u.mgd.beacon_loss_work); | ||
946 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
947 | |||
948 | printk(KERN_DEBUG "%s: driver reports beacon loss from AP %pM " | ||
949 | "- sending probe request\n", sdata->dev->name, | ||
950 | sdata->u.mgd.bssid); | ||
951 | |||
952 | ifmgd->flags |= IEEE80211_STA_PROBEREQ_POLL; | ||
953 | ieee80211_send_probe_req(sdata, ifmgd->bssid, ifmgd->ssid, | ||
954 | ifmgd->ssid_len, NULL, 0); | ||
955 | |||
956 | mod_timer(&ifmgd->timer, jiffies + IEEE80211_MONITORING_INTERVAL); | ||
957 | } | ||
958 | |||
959 | void ieee80211_beacon_loss(struct ieee80211_vif *vif) | ||
960 | { | ||
961 | struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); | ||
962 | |||
963 | queue_work(sdata->local->hw.workqueue, | ||
964 | &sdata->u.mgd.beacon_loss_work); | ||
965 | } | ||
966 | EXPORT_SYMBOL(ieee80211_beacon_loss); | ||
910 | 967 | ||
911 | static void ieee80211_associated(struct ieee80211_sub_if_data *sdata) | 968 | static void ieee80211_associated(struct ieee80211_sub_if_data *sdata) |
912 | { | 969 | { |
913 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 970 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
914 | struct ieee80211_local *local = sdata->local; | 971 | struct ieee80211_local *local = sdata->local; |
915 | struct sta_info *sta; | 972 | struct sta_info *sta; |
916 | int disassoc; | 973 | bool disassoc = false; |
917 | 974 | ||
918 | /* TODO: start monitoring current AP signal quality and number of | 975 | /* TODO: start monitoring current AP signal quality and number of |
919 | * missed beacons. Scan other channels every now and then and search | 976 | * missed beacons. Scan other channels every now and then and search |
@@ -928,36 +985,45 @@ static void ieee80211_associated(struct ieee80211_sub_if_data *sdata) | |||
928 | if (!sta) { | 985 | if (!sta) { |
929 | printk(KERN_DEBUG "%s: No STA entry for own AP %pM\n", | 986 | printk(KERN_DEBUG "%s: No STA entry for own AP %pM\n", |
930 | sdata->dev->name, ifmgd->bssid); | 987 | sdata->dev->name, ifmgd->bssid); |
931 | disassoc = 1; | 988 | disassoc = true; |
932 | } else { | 989 | goto unlock; |
933 | disassoc = 0; | ||
934 | if (time_after(jiffies, | ||
935 | sta->last_rx + IEEE80211_MONITORING_INTERVAL)) { | ||
936 | if (ifmgd->flags & IEEE80211_STA_PROBEREQ_POLL) { | ||
937 | printk(KERN_DEBUG "%s: No ProbeResp from " | ||
938 | "current AP %pM - assume out of " | ||
939 | "range\n", | ||
940 | sdata->dev->name, ifmgd->bssid); | ||
941 | disassoc = 1; | ||
942 | } else | ||
943 | ieee80211_send_probe_req(sdata, ifmgd->bssid, | ||
944 | ifmgd->ssid, | ||
945 | ifmgd->ssid_len, | ||
946 | NULL, 0); | ||
947 | ifmgd->flags ^= IEEE80211_STA_PROBEREQ_POLL; | ||
948 | } else { | ||
949 | ifmgd->flags &= ~IEEE80211_STA_PROBEREQ_POLL; | ||
950 | if (time_after(jiffies, ifmgd->last_probe + | ||
951 | IEEE80211_PROBE_INTERVAL)) { | ||
952 | ifmgd->last_probe = jiffies; | ||
953 | ieee80211_send_probe_req(sdata, ifmgd->bssid, | ||
954 | ifmgd->ssid, | ||
955 | ifmgd->ssid_len, | ||
956 | NULL, 0); | ||
957 | } | ||
958 | } | ||
959 | } | 990 | } |
960 | 991 | ||
992 | if ((ifmgd->flags & IEEE80211_STA_PROBEREQ_POLL) && | ||
993 | time_after(jiffies, sta->last_rx + IEEE80211_MONITORING_INTERVAL)) { | ||
994 | printk(KERN_DEBUG "%s: no probe response from AP %pM " | ||
995 | "- disassociating\n", | ||
996 | sdata->dev->name, ifmgd->bssid); | ||
997 | disassoc = true; | ||
998 | ifmgd->flags &= ~IEEE80211_STA_PROBEREQ_POLL; | ||
999 | goto unlock; | ||
1000 | } | ||
1001 | |||
1002 | /* | ||
1003 | * Beacon filtering is only enabled with power save and then the | ||
1004 | * stack should not check for beacon loss. | ||
1005 | */ | ||
1006 | if (!((local->hw.flags & IEEE80211_HW_BEACON_FILTER) && | ||
1007 | (local->hw.conf.flags & IEEE80211_CONF_PS)) && | ||
1008 | time_after(jiffies, | ||
1009 | ifmgd->last_beacon + IEEE80211_MONITORING_INTERVAL)) { | ||
1010 | printk(KERN_DEBUG "%s: beacon loss from AP %pM " | ||
1011 | "- sending probe request\n", | ||
1012 | sdata->dev->name, ifmgd->bssid); | ||
1013 | ifmgd->flags |= IEEE80211_STA_PROBEREQ_POLL; | ||
1014 | ieee80211_send_probe_req(sdata, ifmgd->bssid, ifmgd->ssid, | ||
1015 | ifmgd->ssid_len, NULL, 0); | ||
1016 | goto unlock; | ||
1017 | |||
1018 | } | ||
1019 | |||
1020 | if (time_after(jiffies, sta->last_rx + IEEE80211_PROBE_IDLE_TIME)) { | ||
1021 | ifmgd->flags |= IEEE80211_STA_PROBEREQ_POLL; | ||
1022 | ieee80211_send_probe_req(sdata, ifmgd->bssid, ifmgd->ssid, | ||
1023 | ifmgd->ssid_len, NULL, 0); | ||
1024 | } | ||
1025 | |||
1026 | unlock: | ||
961 | rcu_read_unlock(); | 1027 | rcu_read_unlock(); |
962 | 1028 | ||
963 | if (disassoc) | 1029 | if (disassoc) |
@@ -975,7 +1041,11 @@ static void ieee80211_auth_completed(struct ieee80211_sub_if_data *sdata) | |||
975 | 1041 | ||
976 | printk(KERN_DEBUG "%s: authenticated\n", sdata->dev->name); | 1042 | printk(KERN_DEBUG "%s: authenticated\n", sdata->dev->name); |
977 | ifmgd->flags |= IEEE80211_STA_AUTHENTICATED; | 1043 | ifmgd->flags |= IEEE80211_STA_AUTHENTICATED; |
978 | ieee80211_associate(sdata); | 1044 | if (ifmgd->flags & IEEE80211_STA_EXT_SME) { |
1045 | /* Wait for SME to request association */ | ||
1046 | ifmgd->state = IEEE80211_STA_MLME_DISABLED; | ||
1047 | } else | ||
1048 | ieee80211_associate(sdata); | ||
979 | } | 1049 | } |
980 | 1050 | ||
981 | 1051 | ||
@@ -1061,12 +1131,15 @@ static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, | |||
1061 | switch (ifmgd->auth_alg) { | 1131 | switch (ifmgd->auth_alg) { |
1062 | case WLAN_AUTH_OPEN: | 1132 | case WLAN_AUTH_OPEN: |
1063 | case WLAN_AUTH_LEAP: | 1133 | case WLAN_AUTH_LEAP: |
1134 | case WLAN_AUTH_FT: | ||
1064 | ieee80211_auth_completed(sdata); | 1135 | ieee80211_auth_completed(sdata); |
1136 | cfg80211_send_rx_auth(sdata->dev, (u8 *) mgmt, len); | ||
1065 | break; | 1137 | break; |
1066 | case WLAN_AUTH_SHARED_KEY: | 1138 | case WLAN_AUTH_SHARED_KEY: |
1067 | if (ifmgd->auth_transaction == 4) | 1139 | if (ifmgd->auth_transaction == 4) { |
1068 | ieee80211_auth_completed(sdata); | 1140 | ieee80211_auth_completed(sdata); |
1069 | else | 1141 | cfg80211_send_rx_auth(sdata->dev, (u8 *) mgmt, len); |
1142 | } else | ||
1070 | ieee80211_auth_challenge(sdata, mgmt, len); | 1143 | ieee80211_auth_challenge(sdata, mgmt, len); |
1071 | break; | 1144 | break; |
1072 | } | 1145 | } |
@@ -1092,9 +1165,10 @@ static void ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, | |||
1092 | printk(KERN_DEBUG "%s: deauthenticated (Reason: %u)\n", | 1165 | printk(KERN_DEBUG "%s: deauthenticated (Reason: %u)\n", |
1093 | sdata->dev->name, reason_code); | 1166 | sdata->dev->name, reason_code); |
1094 | 1167 | ||
1095 | if (ifmgd->state == IEEE80211_STA_MLME_AUTHENTICATE || | 1168 | if (!(ifmgd->flags & IEEE80211_STA_EXT_SME) && |
1096 | ifmgd->state == IEEE80211_STA_MLME_ASSOCIATE || | 1169 | (ifmgd->state == IEEE80211_STA_MLME_AUTHENTICATE || |
1097 | ifmgd->state == IEEE80211_STA_MLME_ASSOCIATED) { | 1170 | ifmgd->state == IEEE80211_STA_MLME_ASSOCIATE || |
1171 | ifmgd->state == IEEE80211_STA_MLME_ASSOCIATED)) { | ||
1098 | ifmgd->state = IEEE80211_STA_MLME_DIRECT_PROBE; | 1172 | ifmgd->state = IEEE80211_STA_MLME_DIRECT_PROBE; |
1099 | mod_timer(&ifmgd->timer, jiffies + | 1173 | mod_timer(&ifmgd->timer, jiffies + |
1100 | IEEE80211_RETRY_AUTH_INTERVAL); | 1174 | IEEE80211_RETRY_AUTH_INTERVAL); |
@@ -1102,6 +1176,7 @@ static void ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, | |||
1102 | 1176 | ||
1103 | ieee80211_set_disassoc(sdata, true, false, 0); | 1177 | ieee80211_set_disassoc(sdata, true, false, 0); |
1104 | ifmgd->flags &= ~IEEE80211_STA_AUTHENTICATED; | 1178 | ifmgd->flags &= ~IEEE80211_STA_AUTHENTICATED; |
1179 | cfg80211_send_rx_deauth(sdata->dev, (u8 *) mgmt, len); | ||
1105 | } | 1180 | } |
1106 | 1181 | ||
1107 | 1182 | ||
@@ -1124,13 +1199,15 @@ static void ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata, | |||
1124 | printk(KERN_DEBUG "%s: disassociated (Reason: %u)\n", | 1199 | printk(KERN_DEBUG "%s: disassociated (Reason: %u)\n", |
1125 | sdata->dev->name, reason_code); | 1200 | sdata->dev->name, reason_code); |
1126 | 1201 | ||
1127 | if (ifmgd->state == IEEE80211_STA_MLME_ASSOCIATED) { | 1202 | if (!(ifmgd->flags & IEEE80211_STA_EXT_SME) && |
1203 | ifmgd->state == IEEE80211_STA_MLME_ASSOCIATED) { | ||
1128 | ifmgd->state = IEEE80211_STA_MLME_ASSOCIATE; | 1204 | ifmgd->state = IEEE80211_STA_MLME_ASSOCIATE; |
1129 | mod_timer(&ifmgd->timer, jiffies + | 1205 | mod_timer(&ifmgd->timer, jiffies + |
1130 | IEEE80211_RETRY_AUTH_INTERVAL); | 1206 | IEEE80211_RETRY_AUTH_INTERVAL); |
1131 | } | 1207 | } |
1132 | 1208 | ||
1133 | ieee80211_set_disassoc(sdata, false, false, reason_code); | 1209 | ieee80211_set_disassoc(sdata, false, false, reason_code); |
1210 | cfg80211_send_rx_disassoc(sdata->dev, (u8 *) mgmt, len); | ||
1134 | } | 1211 | } |
1135 | 1212 | ||
1136 | 1213 | ||
@@ -1346,7 +1423,14 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, | |||
1346 | bss_conf->assoc_capability = capab_info; | 1423 | bss_conf->assoc_capability = capab_info; |
1347 | ieee80211_set_associated(sdata, changed); | 1424 | ieee80211_set_associated(sdata, changed); |
1348 | 1425 | ||
1426 | /* | ||
1427 | * initialise the time of last beacon to be the association time, | ||
1428 | * otherwise beacon loss check will trigger immediately | ||
1429 | */ | ||
1430 | ifmgd->last_beacon = jiffies; | ||
1431 | |||
1349 | ieee80211_associated(sdata); | 1432 | ieee80211_associated(sdata); |
1433 | cfg80211_send_rx_assoc(sdata->dev, (u8 *) mgmt, len); | ||
1350 | } | 1434 | } |
1351 | 1435 | ||
1352 | 1436 | ||
@@ -1393,9 +1477,12 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata, | |||
1393 | size_t len, | 1477 | size_t len, |
1394 | struct ieee80211_rx_status *rx_status) | 1478 | struct ieee80211_rx_status *rx_status) |
1395 | { | 1479 | { |
1480 | struct ieee80211_if_managed *ifmgd; | ||
1396 | size_t baselen; | 1481 | size_t baselen; |
1397 | struct ieee802_11_elems elems; | 1482 | struct ieee802_11_elems elems; |
1398 | 1483 | ||
1484 | ifmgd = &sdata->u.mgd; | ||
1485 | |||
1399 | if (memcmp(mgmt->da, sdata->dev->dev_addr, ETH_ALEN)) | 1486 | if (memcmp(mgmt->da, sdata->dev->dev_addr, ETH_ALEN)) |
1400 | return; /* ignore ProbeResp to foreign address */ | 1487 | return; /* ignore ProbeResp to foreign address */ |
1401 | 1488 | ||
@@ -1410,11 +1497,14 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata, | |||
1410 | 1497 | ||
1411 | /* direct probe may be part of the association flow */ | 1498 | /* direct probe may be part of the association flow */ |
1412 | if (test_and_clear_bit(IEEE80211_STA_REQ_DIRECT_PROBE, | 1499 | if (test_and_clear_bit(IEEE80211_STA_REQ_DIRECT_PROBE, |
1413 | &sdata->u.mgd.request)) { | 1500 | &ifmgd->request)) { |
1414 | printk(KERN_DEBUG "%s direct probe responded\n", | 1501 | printk(KERN_DEBUG "%s direct probe responded\n", |
1415 | sdata->dev->name); | 1502 | sdata->dev->name); |
1416 | ieee80211_authenticate(sdata); | 1503 | ieee80211_authenticate(sdata); |
1417 | } | 1504 | } |
1505 | |||
1506 | if (ifmgd->flags & IEEE80211_STA_PROBEREQ_POLL) | ||
1507 | ifmgd->flags &= ~IEEE80211_STA_PROBEREQ_POLL; | ||
1418 | } | 1508 | } |
1419 | 1509 | ||
1420 | static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | 1510 | static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, |
@@ -1636,6 +1726,8 @@ static void ieee80211_sta_reset_auth(struct ieee80211_sub_if_data *sdata) | |||
1636 | ifmgd->auth_alg = WLAN_AUTH_SHARED_KEY; | 1726 | ifmgd->auth_alg = WLAN_AUTH_SHARED_KEY; |
1637 | else if (ifmgd->auth_algs & IEEE80211_AUTH_ALG_LEAP) | 1727 | else if (ifmgd->auth_algs & IEEE80211_AUTH_ALG_LEAP) |
1638 | ifmgd->auth_alg = WLAN_AUTH_LEAP; | 1728 | ifmgd->auth_alg = WLAN_AUTH_LEAP; |
1729 | else if (ifmgd->auth_algs & IEEE80211_AUTH_ALG_FT) | ||
1730 | ifmgd->auth_alg = WLAN_AUTH_FT; | ||
1639 | else | 1731 | else |
1640 | ifmgd->auth_alg = WLAN_AUTH_OPEN; | 1732 | ifmgd->auth_alg = WLAN_AUTH_OPEN; |
1641 | ifmgd->auth_transaction = -1; | 1733 | ifmgd->auth_transaction = -1; |
@@ -1659,7 +1751,8 @@ static int ieee80211_sta_config_auth(struct ieee80211_sub_if_data *sdata) | |||
1659 | u16 capa_val = WLAN_CAPABILITY_ESS; | 1751 | u16 capa_val = WLAN_CAPABILITY_ESS; |
1660 | struct ieee80211_channel *chan = local->oper_channel; | 1752 | struct ieee80211_channel *chan = local->oper_channel; |
1661 | 1753 | ||
1662 | if (ifmgd->flags & (IEEE80211_STA_AUTO_SSID_SEL | | 1754 | if (!(ifmgd->flags & IEEE80211_STA_EXT_SME) && |
1755 | ifmgd->flags & (IEEE80211_STA_AUTO_SSID_SEL | | ||
1663 | IEEE80211_STA_AUTO_BSSID_SEL | | 1756 | IEEE80211_STA_AUTO_BSSID_SEL | |
1664 | IEEE80211_STA_AUTO_CHANNEL_SEL)) { | 1757 | IEEE80211_STA_AUTO_CHANNEL_SEL)) { |
1665 | capa_mask |= WLAN_CAPABILITY_PRIVACY; | 1758 | capa_mask |= WLAN_CAPABILITY_PRIVACY; |
@@ -1822,6 +1915,7 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) | |||
1822 | ifmgd = &sdata->u.mgd; | 1915 | ifmgd = &sdata->u.mgd; |
1823 | INIT_WORK(&ifmgd->work, ieee80211_sta_work); | 1916 | INIT_WORK(&ifmgd->work, ieee80211_sta_work); |
1824 | INIT_WORK(&ifmgd->chswitch_work, ieee80211_chswitch_work); | 1917 | INIT_WORK(&ifmgd->chswitch_work, ieee80211_chswitch_work); |
1918 | INIT_WORK(&ifmgd->beacon_loss_work, ieee80211_beacon_loss_work); | ||
1825 | setup_timer(&ifmgd->timer, ieee80211_sta_timer, | 1919 | setup_timer(&ifmgd->timer, ieee80211_sta_timer, |
1826 | (unsigned long) sdata); | 1920 | (unsigned long) sdata); |
1827 | setup_timer(&ifmgd->chswitch_timer, ieee80211_chswitch_timer, | 1921 | setup_timer(&ifmgd->chswitch_timer, ieee80211_chswitch_timer, |
@@ -1834,7 +1928,7 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) | |||
1834 | ifmgd->flags |= IEEE80211_STA_CREATE_IBSS | | 1928 | ifmgd->flags |= IEEE80211_STA_CREATE_IBSS | |
1835 | IEEE80211_STA_AUTO_BSSID_SEL | | 1929 | IEEE80211_STA_AUTO_BSSID_SEL | |
1836 | IEEE80211_STA_AUTO_CHANNEL_SEL; | 1930 | IEEE80211_STA_AUTO_CHANNEL_SEL; |
1837 | if (ieee80211_num_regular_queues(&sdata->local->hw) >= 4) | 1931 | if (sdata->local->hw.queues >= 4) |
1838 | ifmgd->flags |= IEEE80211_STA_WMM_ENABLED; | 1932 | ifmgd->flags |= IEEE80211_STA_WMM_ENABLED; |
1839 | } | 1933 | } |
1840 | 1934 | ||
@@ -1856,7 +1950,11 @@ void ieee80211_sta_req_auth(struct ieee80211_sub_if_data *sdata) | |||
1856 | ieee80211_set_disassoc(sdata, true, true, | 1950 | ieee80211_set_disassoc(sdata, true, true, |
1857 | WLAN_REASON_DEAUTH_LEAVING); | 1951 | WLAN_REASON_DEAUTH_LEAVING); |
1858 | 1952 | ||
1859 | set_bit(IEEE80211_STA_REQ_AUTH, &ifmgd->request); | 1953 | if (!(ifmgd->flags & IEEE80211_STA_EXT_SME) || |
1954 | ifmgd->state != IEEE80211_STA_MLME_ASSOCIATE) | ||
1955 | set_bit(IEEE80211_STA_REQ_AUTH, &ifmgd->request); | ||
1956 | else if (ifmgd->flags & IEEE80211_STA_EXT_SME) | ||
1957 | set_bit(IEEE80211_STA_REQ_RUN, &ifmgd->request); | ||
1860 | queue_work(local->hw.workqueue, &ifmgd->work); | 1958 | queue_work(local->hw.workqueue, &ifmgd->work); |
1861 | } | 1959 | } |
1862 | } | 1960 | } |
@@ -1865,8 +1963,6 @@ int ieee80211_sta_commit(struct ieee80211_sub_if_data *sdata) | |||
1865 | { | 1963 | { |
1866 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 1964 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
1867 | 1965 | ||
1868 | ifmgd->flags &= ~IEEE80211_STA_PREV_BSSID_SET; | ||
1869 | |||
1870 | if (ifmgd->ssid_len) | 1966 | if (ifmgd->ssid_len) |
1871 | ifmgd->flags |= IEEE80211_STA_SSID_SET; | 1967 | ifmgd->flags |= IEEE80211_STA_SSID_SET; |
1872 | else | 1968 | else |
@@ -1885,6 +1981,10 @@ int ieee80211_sta_set_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size | |||
1885 | ifmgd = &sdata->u.mgd; | 1981 | ifmgd = &sdata->u.mgd; |
1886 | 1982 | ||
1887 | if (ifmgd->ssid_len != len || memcmp(ifmgd->ssid, ssid, len) != 0) { | 1983 | if (ifmgd->ssid_len != len || memcmp(ifmgd->ssid, ssid, len) != 0) { |
1984 | /* | ||
1985 | * Do not use reassociation if SSID is changed (different ESS). | ||
1986 | */ | ||
1987 | ifmgd->flags &= ~IEEE80211_STA_PREV_BSSID_SET; | ||
1888 | memset(ifmgd->ssid, 0, sizeof(ifmgd->ssid)); | 1988 | memset(ifmgd->ssid, 0, sizeof(ifmgd->ssid)); |
1889 | memcpy(ifmgd->ssid, ssid, len); | 1989 | memcpy(ifmgd->ssid, ssid, len); |
1890 | ifmgd->ssid_len = len; | 1990 | ifmgd->ssid_len = len; |
@@ -1923,7 +2023,8 @@ int ieee80211_sta_set_bssid(struct ieee80211_sub_if_data *sdata, u8 *bssid) | |||
1923 | return ieee80211_sta_commit(sdata); | 2023 | return ieee80211_sta_commit(sdata); |
1924 | } | 2024 | } |
1925 | 2025 | ||
1926 | int ieee80211_sta_set_extra_ie(struct ieee80211_sub_if_data *sdata, char *ie, size_t len) | 2026 | int ieee80211_sta_set_extra_ie(struct ieee80211_sub_if_data *sdata, |
2027 | const char *ie, size_t len) | ||
1927 | { | 2028 | { |
1928 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 2029 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
1929 | 2030 | ||
diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c index 44525f517077..027302326498 100644 --- a/net/mac80211/pm.c +++ b/net/mac80211/pm.c | |||
@@ -10,6 +10,10 @@ int __ieee80211_suspend(struct ieee80211_hw *hw) | |||
10 | struct ieee80211_sub_if_data *sdata; | 10 | struct ieee80211_sub_if_data *sdata; |
11 | struct ieee80211_if_init_conf conf; | 11 | struct ieee80211_if_init_conf conf; |
12 | struct sta_info *sta; | 12 | struct sta_info *sta; |
13 | unsigned long flags; | ||
14 | |||
15 | ieee80211_stop_queues_by_reason(hw, | ||
16 | IEEE80211_QUEUE_STOP_REASON_SUSPEND); | ||
13 | 17 | ||
14 | flush_workqueue(local->hw.workqueue); | 18 | flush_workqueue(local->hw.workqueue); |
15 | 19 | ||
@@ -17,10 +21,23 @@ int __ieee80211_suspend(struct ieee80211_hw *hw) | |||
17 | list_for_each_entry(sdata, &local->interfaces, list) | 21 | list_for_each_entry(sdata, &local->interfaces, list) |
18 | ieee80211_disable_keys(sdata); | 22 | ieee80211_disable_keys(sdata); |
19 | 23 | ||
20 | /* remove STAs */ | 24 | /* Tear down aggregation sessions */ |
21 | list_for_each_entry(sta, &local->sta_list, list) { | 25 | |
26 | rcu_read_lock(); | ||
27 | |||
28 | if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) { | ||
29 | list_for_each_entry_rcu(sta, &local->sta_list, list) { | ||
30 | set_sta_flags(sta, WLAN_STA_SUSPEND); | ||
31 | ieee80211_sta_tear_down_BA_sessions(sta); | ||
32 | } | ||
33 | } | ||
22 | 34 | ||
23 | if (local->ops->sta_notify) { | 35 | rcu_read_unlock(); |
36 | |||
37 | /* remove STAs */ | ||
38 | if (local->ops->sta_notify) { | ||
39 | spin_lock_irqsave(&local->sta_lock, flags); | ||
40 | list_for_each_entry(sta, &local->sta_list, list) { | ||
24 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | 41 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) |
25 | sdata = container_of(sdata->bss, | 42 | sdata = container_of(sdata->bss, |
26 | struct ieee80211_sub_if_data, | 43 | struct ieee80211_sub_if_data, |
@@ -29,11 +46,11 @@ int __ieee80211_suspend(struct ieee80211_hw *hw) | |||
29 | local->ops->sta_notify(hw, &sdata->vif, | 46 | local->ops->sta_notify(hw, &sdata->vif, |
30 | STA_NOTIFY_REMOVE, &sta->sta); | 47 | STA_NOTIFY_REMOVE, &sta->sta); |
31 | } | 48 | } |
49 | spin_unlock_irqrestore(&local->sta_lock, flags); | ||
32 | } | 50 | } |
33 | 51 | ||
34 | /* remove all interfaces */ | 52 | /* remove all interfaces */ |
35 | list_for_each_entry(sdata, &local->interfaces, list) { | 53 | list_for_each_entry(sdata, &local->interfaces, list) { |
36 | |||
37 | if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN && | 54 | if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN && |
38 | sdata->vif.type != NL80211_IFTYPE_MONITOR && | 55 | sdata->vif.type != NL80211_IFTYPE_MONITOR && |
39 | netif_running(sdata->dev)) { | 56 | netif_running(sdata->dev)) { |
@@ -61,6 +78,7 @@ int __ieee80211_resume(struct ieee80211_hw *hw) | |||
61 | struct ieee80211_sub_if_data *sdata; | 78 | struct ieee80211_sub_if_data *sdata; |
62 | struct ieee80211_if_init_conf conf; | 79 | struct ieee80211_if_init_conf conf; |
63 | struct sta_info *sta; | 80 | struct sta_info *sta; |
81 | unsigned long flags; | ||
64 | int res; | 82 | int res; |
65 | 83 | ||
66 | /* restart hardware */ | 84 | /* restart hardware */ |
@@ -72,7 +90,6 @@ int __ieee80211_resume(struct ieee80211_hw *hw) | |||
72 | 90 | ||
73 | /* add interfaces */ | 91 | /* add interfaces */ |
74 | list_for_each_entry(sdata, &local->interfaces, list) { | 92 | list_for_each_entry(sdata, &local->interfaces, list) { |
75 | |||
76 | if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN && | 93 | if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN && |
77 | sdata->vif.type != NL80211_IFTYPE_MONITOR && | 94 | sdata->vif.type != NL80211_IFTYPE_MONITOR && |
78 | netif_running(sdata->dev)) { | 95 | netif_running(sdata->dev)) { |
@@ -84,9 +101,9 @@ int __ieee80211_resume(struct ieee80211_hw *hw) | |||
84 | } | 101 | } |
85 | 102 | ||
86 | /* add STAs back */ | 103 | /* add STAs back */ |
87 | list_for_each_entry(sta, &local->sta_list, list) { | 104 | if (local->ops->sta_notify) { |
88 | 105 | spin_lock_irqsave(&local->sta_lock, flags); | |
89 | if (local->ops->sta_notify) { | 106 | list_for_each_entry(sta, &local->sta_list, list) { |
90 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | 107 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) |
91 | sdata = container_of(sdata->bss, | 108 | sdata = container_of(sdata->bss, |
92 | struct ieee80211_sub_if_data, | 109 | struct ieee80211_sub_if_data, |
@@ -95,8 +112,21 @@ int __ieee80211_resume(struct ieee80211_hw *hw) | |||
95 | local->ops->sta_notify(hw, &sdata->vif, | 112 | local->ops->sta_notify(hw, &sdata->vif, |
96 | STA_NOTIFY_ADD, &sta->sta); | 113 | STA_NOTIFY_ADD, &sta->sta); |
97 | } | 114 | } |
115 | spin_unlock_irqrestore(&local->sta_lock, flags); | ||
98 | } | 116 | } |
99 | 117 | ||
118 | /* Clear Suspend state so that ADDBA requests can be processed */ | ||
119 | |||
120 | rcu_read_lock(); | ||
121 | |||
122 | if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) { | ||
123 | list_for_each_entry_rcu(sta, &local->sta_list, list) { | ||
124 | clear_sta_flags(sta, WLAN_STA_SUSPEND); | ||
125 | } | ||
126 | } | ||
127 | |||
128 | rcu_read_unlock(); | ||
129 | |||
100 | /* add back keys */ | 130 | /* add back keys */ |
101 | list_for_each_entry(sdata, &local->interfaces, list) | 131 | list_for_each_entry(sdata, &local->interfaces, list) |
102 | if (netif_running(sdata->dev)) | 132 | if (netif_running(sdata->dev)) |
@@ -113,5 +143,37 @@ int __ieee80211_resume(struct ieee80211_hw *hw) | |||
113 | ieee80211_configure_filter(local); | 143 | ieee80211_configure_filter(local); |
114 | netif_addr_unlock_bh(local->mdev); | 144 | netif_addr_unlock_bh(local->mdev); |
115 | 145 | ||
146 | /* Finally also reconfigure all the BSS information */ | ||
147 | list_for_each_entry(sdata, &local->interfaces, list) { | ||
148 | u32 changed = ~0; | ||
149 | if (!netif_running(sdata->dev)) | ||
150 | continue; | ||
151 | switch (sdata->vif.type) { | ||
152 | case NL80211_IFTYPE_STATION: | ||
153 | /* disable beacon change bits */ | ||
154 | changed &= ~IEEE80211_IFCC_BEACON; | ||
155 | /* fall through */ | ||
156 | case NL80211_IFTYPE_ADHOC: | ||
157 | case NL80211_IFTYPE_AP: | ||
158 | case NL80211_IFTYPE_MESH_POINT: | ||
159 | WARN_ON(ieee80211_if_config(sdata, changed)); | ||
160 | ieee80211_bss_info_change_notify(sdata, ~0); | ||
161 | break; | ||
162 | case NL80211_IFTYPE_WDS: | ||
163 | break; | ||
164 | case NL80211_IFTYPE_AP_VLAN: | ||
165 | case NL80211_IFTYPE_MONITOR: | ||
166 | /* ignore virtual */ | ||
167 | break; | ||
168 | case NL80211_IFTYPE_UNSPECIFIED: | ||
169 | case __NL80211_IFTYPE_AFTER_LAST: | ||
170 | WARN_ON(1); | ||
171 | break; | ||
172 | } | ||
173 | } | ||
174 | |||
175 | ieee80211_wake_queues_by_reason(hw, | ||
176 | IEEE80211_QUEUE_STOP_REASON_SUSPEND); | ||
177 | |||
116 | return 0; | 178 | return 0; |
117 | } | 179 | } |
diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c index 3fa7ab285066..4641f00a1e5c 100644 --- a/net/mac80211/rate.c +++ b/net/mac80211/rate.c | |||
@@ -219,10 +219,12 @@ void rate_control_get_rate(struct ieee80211_sub_if_data *sdata, | |||
219 | info->control.rates[i].count = 1; | 219 | info->control.rates[i].count = 1; |
220 | } | 220 | } |
221 | 221 | ||
222 | if (sta && sdata->force_unicast_rateidx > -1) | 222 | if (sta && sdata->force_unicast_rateidx > -1) { |
223 | info->control.rates[0].idx = sdata->force_unicast_rateidx; | 223 | info->control.rates[0].idx = sdata->force_unicast_rateidx; |
224 | else | 224 | } else { |
225 | ref->ops->get_rate(ref->priv, ista, priv_sta, txrc); | 225 | ref->ops->get_rate(ref->priv, ista, priv_sta, txrc); |
226 | info->flags |= IEEE80211_TX_INTFL_RCALGO; | ||
227 | } | ||
226 | 228 | ||
227 | /* | 229 | /* |
228 | * try to enforce the maximum rate the user wanted | 230 | * try to enforce the maximum rate the user wanted |
diff --git a/net/mac80211/rate.h b/net/mac80211/rate.h index b9164c9a9563..2ab5ad9e71ce 100644 --- a/net/mac80211/rate.h +++ b/net/mac80211/rate.h | |||
@@ -44,8 +44,10 @@ static inline void rate_control_tx_status(struct ieee80211_local *local, | |||
44 | struct rate_control_ref *ref = local->rate_ctrl; | 44 | struct rate_control_ref *ref = local->rate_ctrl; |
45 | struct ieee80211_sta *ista = &sta->sta; | 45 | struct ieee80211_sta *ista = &sta->sta; |
46 | void *priv_sta = sta->rate_ctrl_priv; | 46 | void *priv_sta = sta->rate_ctrl_priv; |
47 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||
47 | 48 | ||
48 | ref->ops->tx_status(ref->priv, sband, ista, priv_sta, skb); | 49 | if (likely(info->flags & IEEE80211_TX_INTFL_RCALGO)) |
50 | ref->ops->tx_status(ref->priv, sband, ista, priv_sta, skb); | ||
49 | } | 51 | } |
50 | 52 | ||
51 | 53 | ||
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 66f7ecf51b92..64ebe664effc 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -142,6 +142,8 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, | |||
142 | /* IEEE80211_RADIOTAP_FLAGS */ | 142 | /* IEEE80211_RADIOTAP_FLAGS */ |
143 | if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) | 143 | if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) |
144 | *pos |= IEEE80211_RADIOTAP_F_FCS; | 144 | *pos |= IEEE80211_RADIOTAP_F_FCS; |
145 | if (status->flag & (RX_FLAG_FAILED_FCS_CRC | RX_FLAG_FAILED_PLCP_CRC)) | ||
146 | *pos |= IEEE80211_RADIOTAP_F_BADFCS; | ||
145 | if (status->flag & RX_FLAG_SHORTPRE) | 147 | if (status->flag & RX_FLAG_SHORTPRE) |
146 | *pos |= IEEE80211_RADIOTAP_F_SHORTPRE; | 148 | *pos |= IEEE80211_RADIOTAP_F_SHORTPRE; |
147 | pos++; | 149 | pos++; |
@@ -204,9 +206,8 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, | |||
204 | /* ensure 2 byte alignment for the 2 byte field as required */ | 206 | /* ensure 2 byte alignment for the 2 byte field as required */ |
205 | if ((pos - (unsigned char *)rthdr) & 1) | 207 | if ((pos - (unsigned char *)rthdr) & 1) |
206 | pos++; | 208 | pos++; |
207 | /* FIXME: when radiotap gets a 'bad PLCP' flag use it here */ | 209 | if (status->flag & RX_FLAG_FAILED_PLCP_CRC) |
208 | if (status->flag & (RX_FLAG_FAILED_FCS_CRC | RX_FLAG_FAILED_PLCP_CRC)) | 210 | *(__le16 *)pos |= cpu_to_le16(IEEE80211_RADIOTAP_F_RX_BADPLCP); |
209 | *(__le16 *)pos |= cpu_to_le16(IEEE80211_RADIOTAP_F_RX_BADFCS); | ||
210 | pos += 2; | 211 | pos += 2; |
211 | } | 212 | } |
212 | 213 | ||
@@ -849,12 +850,19 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx) | |||
849 | * Mesh beacons will update last_rx when if they are found to | 850 | * Mesh beacons will update last_rx when if they are found to |
850 | * match the current local configuration when processed. | 851 | * match the current local configuration when processed. |
851 | */ | 852 | */ |
852 | sta->last_rx = jiffies; | 853 | if (rx->sdata->vif.type == NL80211_IFTYPE_STATION && |
854 | ieee80211_is_beacon(hdr->frame_control)) { | ||
855 | rx->sdata->u.mgd.last_beacon = jiffies; | ||
856 | } else | ||
857 | sta->last_rx = jiffies; | ||
853 | } | 858 | } |
854 | 859 | ||
855 | if (!(rx->flags & IEEE80211_RX_RA_MATCH)) | 860 | if (!(rx->flags & IEEE80211_RX_RA_MATCH)) |
856 | return RX_CONTINUE; | 861 | return RX_CONTINUE; |
857 | 862 | ||
863 | if (rx->sdata->vif.type == NL80211_IFTYPE_STATION) | ||
864 | ieee80211_sta_rx_notify(rx->sdata, hdr); | ||
865 | |||
858 | sta->rx_fragments++; | 866 | sta->rx_fragments++; |
859 | sta->rx_bytes += rx->skb->len; | 867 | sta->rx_bytes += rx->skb->len; |
860 | sta->last_signal = rx->status->signal; | 868 | sta->last_signal = rx->status->signal; |
@@ -1876,18 +1884,13 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx) | |||
1876 | if (ieee80211_vif_is_mesh(&sdata->vif)) | 1884 | if (ieee80211_vif_is_mesh(&sdata->vif)) |
1877 | return ieee80211_mesh_rx_mgmt(sdata, rx->skb, rx->status); | 1885 | return ieee80211_mesh_rx_mgmt(sdata, rx->skb, rx->status); |
1878 | 1886 | ||
1879 | if (sdata->vif.type != NL80211_IFTYPE_STATION && | 1887 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC) |
1880 | sdata->vif.type != NL80211_IFTYPE_ADHOC) | 1888 | return ieee80211_ibss_rx_mgmt(sdata, rx->skb, rx->status); |
1881 | return RX_DROP_MONITOR; | ||
1882 | |||
1883 | 1889 | ||
1884 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { | 1890 | if (sdata->vif.type == NL80211_IFTYPE_STATION) |
1885 | if (sdata->flags & IEEE80211_SDATA_USERSPACE_MLME) | ||
1886 | return RX_DROP_MONITOR; | ||
1887 | return ieee80211_sta_rx_mgmt(sdata, rx->skb, rx->status); | 1891 | return ieee80211_sta_rx_mgmt(sdata, rx->skb, rx->status); |
1888 | } | ||
1889 | 1892 | ||
1890 | return ieee80211_ibss_rx_mgmt(sdata, rx->skb, rx->status); | 1893 | return RX_DROP_MONITOR; |
1891 | } | 1894 | } |
1892 | 1895 | ||
1893 | static void ieee80211_rx_michael_mic_report(struct net_device *dev, | 1896 | static void ieee80211_rx_michael_mic_report(struct net_device *dev, |
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 5030a3c87509..3bf9839f5916 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c | |||
@@ -214,6 +214,66 @@ void ieee80211_scan_failed(struct ieee80211_local *local) | |||
214 | local->scan_req = NULL; | 214 | local->scan_req = NULL; |
215 | } | 215 | } |
216 | 216 | ||
217 | /* | ||
218 | * inform AP that we will go to sleep so that it will buffer the frames | ||
219 | * while we scan | ||
220 | */ | ||
221 | static void ieee80211_scan_ps_enable(struct ieee80211_sub_if_data *sdata) | ||
222 | { | ||
223 | struct ieee80211_local *local = sdata->local; | ||
224 | bool ps = false; | ||
225 | |||
226 | /* FIXME: what to do when local->pspolling is true? */ | ||
227 | |||
228 | del_timer_sync(&local->dynamic_ps_timer); | ||
229 | cancel_work_sync(&local->dynamic_ps_enable_work); | ||
230 | |||
231 | if (local->hw.conf.flags & IEEE80211_CONF_PS) { | ||
232 | ps = true; | ||
233 | local->hw.conf.flags &= ~IEEE80211_CONF_PS; | ||
234 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); | ||
235 | } | ||
236 | |||
237 | if (!ps || !(local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK)) | ||
238 | /* | ||
239 | * If power save was enabled, no need to send a nullfunc | ||
240 | * frame because AP knows that we are sleeping. But if the | ||
241 | * hardware is creating the nullfunc frame for power save | ||
242 | * status (ie. IEEE80211_HW_PS_NULLFUNC_STACK is not | ||
243 | * enabled) and power save was enabled, the firmware just | ||
244 | * sent a null frame with power save disabled. So we need | ||
245 | * to send a new nullfunc frame to inform the AP that we | ||
246 | * are again sleeping. | ||
247 | */ | ||
248 | ieee80211_send_nullfunc(local, sdata, 1); | ||
249 | } | ||
250 | |||
251 | /* inform AP that we are awake again, unless power save is enabled */ | ||
252 | static void ieee80211_scan_ps_disable(struct ieee80211_sub_if_data *sdata) | ||
253 | { | ||
254 | struct ieee80211_local *local = sdata->local; | ||
255 | |||
256 | if (!local->powersave) | ||
257 | ieee80211_send_nullfunc(local, sdata, 0); | ||
258 | else { | ||
259 | /* | ||
260 | * In !IEEE80211_HW_PS_NULLFUNC_STACK case the hardware | ||
261 | * will send a nullfunc frame with the powersave bit set | ||
262 | * even though the AP already knows that we are sleeping. | ||
263 | * This could be avoided by sending a null frame with power | ||
264 | * save bit disabled before enabling the power save, but | ||
265 | * this doesn't gain anything. | ||
266 | * | ||
267 | * When IEEE80211_HW_PS_NULLFUNC_STACK is enabled, no need | ||
268 | * to send a nullfunc frame because AP already knows that | ||
269 | * we are sleeping, let's just enable power save mode in | ||
270 | * hardware. | ||
271 | */ | ||
272 | local->hw.conf.flags |= IEEE80211_CONF_PS; | ||
273 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); | ||
274 | } | ||
275 | } | ||
276 | |||
217 | void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) | 277 | void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) |
218 | { | 278 | { |
219 | struct ieee80211_local *local = hw_to_local(hw); | 279 | struct ieee80211_local *local = hw_to_local(hw); |
@@ -268,7 +328,7 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) | |||
268 | /* Tell AP we're back */ | 328 | /* Tell AP we're back */ |
269 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { | 329 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { |
270 | if (sdata->u.mgd.flags & IEEE80211_STA_ASSOCIATED) { | 330 | if (sdata->u.mgd.flags & IEEE80211_STA_ASSOCIATED) { |
271 | ieee80211_send_nullfunc(local, sdata, 0); | 331 | ieee80211_scan_ps_disable(sdata); |
272 | netif_tx_wake_all_queues(sdata->dev); | 332 | netif_tx_wake_all_queues(sdata->dev); |
273 | } | 333 | } |
274 | } else | 334 | } else |
@@ -409,6 +469,19 @@ int ieee80211_start_scan(struct ieee80211_sub_if_data *scan_sdata, | |||
409 | return 0; | 469 | return 0; |
410 | } | 470 | } |
411 | 471 | ||
472 | /* | ||
473 | * Hardware/driver doesn't support hw_scan, so use software | ||
474 | * scanning instead. First send a nullfunc frame with power save | ||
475 | * bit on so that AP will buffer the frames for us while we are not | ||
476 | * listening, then send probe requests to each channel and wait for | ||
477 | * the responses. After all channels are scanned, tune back to the | ||
478 | * original channel and send a nullfunc frame with power save bit | ||
479 | * off to trigger the AP to send us all the buffered frames. | ||
480 | * | ||
481 | * Note that while local->sw_scanning is true everything else but | ||
482 | * nullfunc frames and probe requests will be dropped in | ||
483 | * ieee80211_tx_h_check_assoc(). | ||
484 | */ | ||
412 | local->sw_scanning = true; | 485 | local->sw_scanning = true; |
413 | if (local->ops->sw_scan_start) | 486 | if (local->ops->sw_scan_start) |
414 | local->ops->sw_scan_start(local_to_hw(local)); | 487 | local->ops->sw_scan_start(local_to_hw(local)); |
@@ -428,7 +501,7 @@ int ieee80211_start_scan(struct ieee80211_sub_if_data *scan_sdata, | |||
428 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { | 501 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { |
429 | if (sdata->u.mgd.flags & IEEE80211_STA_ASSOCIATED) { | 502 | if (sdata->u.mgd.flags & IEEE80211_STA_ASSOCIATED) { |
430 | netif_tx_stop_all_queues(sdata->dev); | 503 | netif_tx_stop_all_queues(sdata->dev); |
431 | ieee80211_send_nullfunc(local, sdata, 1); | 504 | ieee80211_scan_ps_enable(sdata); |
432 | } | 505 | } |
433 | } else | 506 | } else |
434 | netif_tx_stop_all_queues(sdata->dev); | 507 | netif_tx_stop_all_queues(sdata->dev); |
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 4ba3c540fcf3..c5f14e6bbde2 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
@@ -203,17 +203,6 @@ void sta_info_destroy(struct sta_info *sta) | |||
203 | if (tid_rx) | 203 | if (tid_rx) |
204 | tid_rx->shutdown = true; | 204 | tid_rx->shutdown = true; |
205 | 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 | |||
217 | spin_unlock_bh(&sta->lock); | 206 | spin_unlock_bh(&sta->lock); |
218 | 207 | ||
219 | /* | 208 | /* |
@@ -239,6 +228,11 @@ void sta_info_destroy(struct sta_info *sta) | |||
239 | tid_tx = sta->ampdu_mlme.tid_tx[i]; | 228 | tid_tx = sta->ampdu_mlme.tid_tx[i]; |
240 | if (tid_tx) { | 229 | if (tid_tx) { |
241 | del_timer_sync(&tid_tx->addba_resp_timer); | 230 | del_timer_sync(&tid_tx->addba_resp_timer); |
231 | /* | ||
232 | * STA removed while aggregation session being | ||
233 | * started? Bit odd, but purge frames anyway. | ||
234 | */ | ||
235 | skb_queue_purge(&tid_tx->pending); | ||
242 | kfree(tid_tx); | 236 | kfree(tid_tx); |
243 | } | 237 | } |
244 | } | 238 | } |
@@ -287,7 +281,6 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, | |||
287 | * enable session_timer's data differentiation. refer to | 281 | * enable session_timer's data differentiation. refer to |
288 | * sta_rx_agg_session_timer_expired for useage */ | 282 | * sta_rx_agg_session_timer_expired for useage */ |
289 | sta->timer_to_tid[i] = i; | 283 | sta->timer_to_tid[i] = i; |
290 | sta->tid_to_tx_q[i] = -1; | ||
291 | /* rx */ | 284 | /* rx */ |
292 | sta->ampdu_mlme.tid_state_rx[i] = HT_AGG_STATE_IDLE; | 285 | sta->ampdu_mlme.tid_state_rx[i] = HT_AGG_STATE_IDLE; |
293 | sta->ampdu_mlme.tid_rx[i] = NULL; | 286 | sta->ampdu_mlme.tid_rx[i] = NULL; |
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 1f45573c580c..5534d489f506 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h | |||
@@ -35,6 +35,8 @@ | |||
35 | * IEEE80211_TX_CTL_CLEAR_PS_FILT control flag) when the next | 35 | * IEEE80211_TX_CTL_CLEAR_PS_FILT control flag) when the next |
36 | * frame to this station is transmitted. | 36 | * frame to this station is transmitted. |
37 | * @WLAN_STA_MFP: Management frame protection is used with this STA. | 37 | * @WLAN_STA_MFP: Management frame protection is used with this STA. |
38 | * @WLAN_STA_SUSPEND: Set/cleared during a suspend/resume cycle. | ||
39 | * Used to deny ADDBA requests (both TX and RX). | ||
38 | */ | 40 | */ |
39 | enum ieee80211_sta_info_flags { | 41 | enum ieee80211_sta_info_flags { |
40 | WLAN_STA_AUTH = 1<<0, | 42 | WLAN_STA_AUTH = 1<<0, |
@@ -48,6 +50,7 @@ enum ieee80211_sta_info_flags { | |||
48 | WLAN_STA_PSPOLL = 1<<8, | 50 | WLAN_STA_PSPOLL = 1<<8, |
49 | WLAN_STA_CLEAR_PS_FILT = 1<<9, | 51 | WLAN_STA_CLEAR_PS_FILT = 1<<9, |
50 | WLAN_STA_MFP = 1<<10, | 52 | WLAN_STA_MFP = 1<<10, |
53 | WLAN_STA_SUSPEND = 1<<11 | ||
51 | }; | 54 | }; |
52 | 55 | ||
53 | #define STA_TID_NUM 16 | 56 | #define STA_TID_NUM 16 |
@@ -70,11 +73,13 @@ enum ieee80211_sta_info_flags { | |||
70 | * struct tid_ampdu_tx - TID aggregation information (Tx). | 73 | * struct tid_ampdu_tx - TID aggregation information (Tx). |
71 | * | 74 | * |
72 | * @addba_resp_timer: timer for peer's response to addba request | 75 | * @addba_resp_timer: timer for peer's response to addba request |
76 | * @pending: pending frames queue -- use sta's spinlock to protect | ||
73 | * @ssn: Starting Sequence Number expected to be aggregated. | 77 | * @ssn: Starting Sequence Number expected to be aggregated. |
74 | * @dialog_token: dialog token for aggregation session | 78 | * @dialog_token: dialog token for aggregation session |
75 | */ | 79 | */ |
76 | struct tid_ampdu_tx { | 80 | struct tid_ampdu_tx { |
77 | struct timer_list addba_resp_timer; | 81 | struct timer_list addba_resp_timer; |
82 | struct sk_buff_head pending; | ||
78 | u16 ssn; | 83 | u16 ssn; |
79 | u8 dialog_token; | 84 | u8 dialog_token; |
80 | }; | 85 | }; |
@@ -201,7 +206,6 @@ struct sta_ampdu_mlme { | |||
201 | * @tid_seq: per-TID sequence numbers for sending to this STA | 206 | * @tid_seq: per-TID sequence numbers for sending to this STA |
202 | * @ampdu_mlme: A-MPDU state machine state | 207 | * @ampdu_mlme: A-MPDU state machine state |
203 | * @timer_to_tid: identity mapping to ID timers | 208 | * @timer_to_tid: identity mapping to ID timers |
204 | * @tid_to_tx_q: map tid to tx queue (invalid == negative values) | ||
205 | * @llid: Local link ID | 209 | * @llid: Local link ID |
206 | * @plid: Peer link ID | 210 | * @plid: Peer link ID |
207 | * @reason: Cancel reason on PLINK_HOLDING state | 211 | * @reason: Cancel reason on PLINK_HOLDING state |
@@ -276,7 +280,6 @@ struct sta_info { | |||
276 | */ | 280 | */ |
277 | struct sta_ampdu_mlme ampdu_mlme; | 281 | struct sta_ampdu_mlme ampdu_mlme; |
278 | u8 timer_to_tid[STA_TID_NUM]; | 282 | u8 timer_to_tid[STA_TID_NUM]; |
279 | s8 tid_to_tx_q[STA_TID_NUM]; | ||
280 | 283 | ||
281 | #ifdef CONFIG_MAC80211_MESH | 284 | #ifdef CONFIG_MAC80211_MESH |
282 | /* | 285 | /* |
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 457238a2f3fc..3fb04a86444d 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -34,8 +34,7 @@ | |||
34 | 34 | ||
35 | #define IEEE80211_TX_OK 0 | 35 | #define IEEE80211_TX_OK 0 |
36 | #define IEEE80211_TX_AGAIN 1 | 36 | #define IEEE80211_TX_AGAIN 1 |
37 | #define IEEE80211_TX_FRAG_AGAIN 2 | 37 | #define IEEE80211_TX_PENDING 2 |
38 | #define IEEE80211_TX_PENDING 3 | ||
39 | 38 | ||
40 | /* misc utils */ | 39 | /* misc utils */ |
41 | 40 | ||
@@ -193,7 +192,19 @@ ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx) | |||
193 | return TX_CONTINUE; | 192 | return TX_CONTINUE; |
194 | 193 | ||
195 | if (unlikely(tx->local->sw_scanning) && | 194 | if (unlikely(tx->local->sw_scanning) && |
196 | !ieee80211_is_probe_req(hdr->frame_control)) | 195 | !ieee80211_is_probe_req(hdr->frame_control) && |
196 | !ieee80211_is_nullfunc(hdr->frame_control)) | ||
197 | /* | ||
198 | * When software scanning only nullfunc frames (to notify | ||
199 | * the sleep state to the AP) and probe requests (for the | ||
200 | * active scan) are allowed, all other frames should not be | ||
201 | * sent and we should not get here, but if we do | ||
202 | * nonetheless, drop them to avoid sending them | ||
203 | * off-channel. See the link below and | ||
204 | * ieee80211_start_scan() for more. | ||
205 | * | ||
206 | * http://article.gmane.org/gmane.linux.kernel.wireless.general/30089 | ||
207 | */ | ||
197 | return TX_DROP; | 208 | return TX_DROP; |
198 | 209 | ||
199 | if (tx->sdata->vif.type == NL80211_IFTYPE_MESH_POINT) | 210 | if (tx->sdata->vif.type == NL80211_IFTYPE_MESH_POINT) |
@@ -690,17 +701,62 @@ ieee80211_tx_h_sequence(struct ieee80211_tx_data *tx) | |||
690 | return TX_CONTINUE; | 701 | return TX_CONTINUE; |
691 | } | 702 | } |
692 | 703 | ||
704 | static int ieee80211_fragment(struct ieee80211_local *local, | ||
705 | struct sk_buff *skb, int hdrlen, | ||
706 | int frag_threshold) | ||
707 | { | ||
708 | struct sk_buff *tail = skb, *tmp; | ||
709 | int per_fragm = frag_threshold - hdrlen - FCS_LEN; | ||
710 | int pos = hdrlen + per_fragm; | ||
711 | int rem = skb->len - hdrlen - per_fragm; | ||
712 | |||
713 | if (WARN_ON(rem < 0)) | ||
714 | return -EINVAL; | ||
715 | |||
716 | while (rem) { | ||
717 | int fraglen = per_fragm; | ||
718 | |||
719 | if (fraglen > rem) | ||
720 | fraglen = rem; | ||
721 | rem -= fraglen; | ||
722 | tmp = dev_alloc_skb(local->tx_headroom + | ||
723 | frag_threshold + | ||
724 | IEEE80211_ENCRYPT_HEADROOM + | ||
725 | IEEE80211_ENCRYPT_TAILROOM); | ||
726 | if (!tmp) | ||
727 | return -ENOMEM; | ||
728 | tail->next = tmp; | ||
729 | tail = tmp; | ||
730 | skb_reserve(tmp, local->tx_headroom + | ||
731 | IEEE80211_ENCRYPT_HEADROOM); | ||
732 | /* copy control information */ | ||
733 | memcpy(tmp->cb, skb->cb, sizeof(tmp->cb)); | ||
734 | skb_copy_queue_mapping(tmp, skb); | ||
735 | tmp->priority = skb->priority; | ||
736 | tmp->do_not_encrypt = skb->do_not_encrypt; | ||
737 | tmp->dev = skb->dev; | ||
738 | tmp->iif = skb->iif; | ||
739 | |||
740 | /* copy header and data */ | ||
741 | memcpy(skb_put(tmp, hdrlen), skb->data, hdrlen); | ||
742 | memcpy(skb_put(tmp, fraglen), skb->data + pos, fraglen); | ||
743 | |||
744 | pos += fraglen; | ||
745 | } | ||
746 | |||
747 | skb->len = hdrlen + per_fragm; | ||
748 | return 0; | ||
749 | } | ||
750 | |||
693 | static ieee80211_tx_result debug_noinline | 751 | static ieee80211_tx_result debug_noinline |
694 | ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx) | 752 | ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx) |
695 | { | 753 | { |
696 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); | 754 | struct sk_buff *skb = tx->skb; |
697 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data; | 755 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
698 | size_t hdrlen, per_fragm, num_fragm, payload_len, left; | 756 | struct ieee80211_hdr *hdr = (void *)skb->data; |
699 | struct sk_buff **frags, *first, *frag; | ||
700 | int i; | ||
701 | u16 seq; | ||
702 | u8 *pos; | ||
703 | int frag_threshold = tx->local->fragmentation_threshold; | 757 | int frag_threshold = tx->local->fragmentation_threshold; |
758 | int hdrlen; | ||
759 | int fragnum; | ||
704 | 760 | ||
705 | if (!(tx->flags & IEEE80211_TX_FRAGMENTED)) | 761 | if (!(tx->flags & IEEE80211_TX_FRAGMENTED)) |
706 | return TX_CONTINUE; | 762 | return TX_CONTINUE; |
@@ -713,58 +769,35 @@ ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx) | |||
713 | if (WARN_ON(info->flags & IEEE80211_TX_CTL_AMPDU)) | 769 | if (WARN_ON(info->flags & IEEE80211_TX_CTL_AMPDU)) |
714 | return TX_DROP; | 770 | return TX_DROP; |
715 | 771 | ||
716 | first = tx->skb; | ||
717 | |||
718 | hdrlen = ieee80211_hdrlen(hdr->frame_control); | 772 | hdrlen = ieee80211_hdrlen(hdr->frame_control); |
719 | payload_len = first->len - hdrlen; | ||
720 | per_fragm = frag_threshold - hdrlen - FCS_LEN; | ||
721 | num_fragm = DIV_ROUND_UP(payload_len, per_fragm); | ||
722 | |||
723 | frags = kzalloc(num_fragm * sizeof(struct sk_buff *), GFP_ATOMIC); | ||
724 | if (!frags) | ||
725 | goto fail; | ||
726 | |||
727 | hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREFRAGS); | ||
728 | seq = le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ; | ||
729 | pos = first->data + hdrlen + per_fragm; | ||
730 | left = payload_len - per_fragm; | ||
731 | for (i = 0; i < num_fragm - 1; i++) { | ||
732 | struct ieee80211_hdr *fhdr; | ||
733 | size_t copylen; | ||
734 | |||
735 | if (left <= 0) | ||
736 | goto fail; | ||
737 | 773 | ||
738 | /* reserve enough extra head and tail room for possible | 774 | /* internal error, why is TX_FRAGMENTED set? */ |
739 | * encryption */ | 775 | if (WARN_ON(skb->len <= frag_threshold)) |
740 | frag = frags[i] = | 776 | return TX_DROP; |
741 | dev_alloc_skb(tx->local->tx_headroom + | ||
742 | frag_threshold + | ||
743 | IEEE80211_ENCRYPT_HEADROOM + | ||
744 | IEEE80211_ENCRYPT_TAILROOM); | ||
745 | if (!frag) | ||
746 | goto fail; | ||
747 | |||
748 | /* Make sure that all fragments use the same priority so | ||
749 | * that they end up using the same TX queue */ | ||
750 | frag->priority = first->priority; | ||
751 | 777 | ||
752 | skb_reserve(frag, tx->local->tx_headroom + | 778 | /* |
753 | IEEE80211_ENCRYPT_HEADROOM); | 779 | * Now fragment the frame. This will allocate all the fragments and |
780 | * chain them (using skb as the first fragment) to skb->next. | ||
781 | * During transmission, we will remove the successfully transmitted | ||
782 | * fragments from this list. When the low-level driver rejects one | ||
783 | * of the fragments then we will simply pretend to accept the skb | ||
784 | * but store it away as pending. | ||
785 | */ | ||
786 | if (ieee80211_fragment(tx->local, skb, hdrlen, frag_threshold)) | ||
787 | return TX_DROP; | ||
754 | 788 | ||
755 | /* copy TX information */ | 789 | /* update duration/seq/flags of fragments */ |
756 | info = IEEE80211_SKB_CB(frag); | 790 | fragnum = 0; |
757 | memcpy(info, first->cb, sizeof(frag->cb)); | 791 | do { |
792 | int next_len; | ||
793 | const __le16 morefrags = cpu_to_le16(IEEE80211_FCTL_MOREFRAGS); | ||
758 | 794 | ||
759 | /* copy/fill in 802.11 header */ | 795 | hdr = (void *)skb->data; |
760 | fhdr = (struct ieee80211_hdr *) skb_put(frag, hdrlen); | 796 | info = IEEE80211_SKB_CB(skb); |
761 | memcpy(fhdr, first->data, hdrlen); | ||
762 | fhdr->seq_ctrl = cpu_to_le16(seq | ((i + 1) & IEEE80211_SCTL_FRAG)); | ||
763 | 797 | ||
764 | if (i == num_fragm - 2) { | 798 | if (skb->next) { |
765 | /* clear MOREFRAGS bit for the last fragment */ | 799 | hdr->frame_control |= morefrags; |
766 | fhdr->frame_control &= cpu_to_le16(~IEEE80211_FCTL_MOREFRAGS); | 800 | next_len = skb->next->len; |
767 | } else { | ||
768 | /* | 801 | /* |
769 | * No multi-rate retries for fragmented frames, that | 802 | * No multi-rate retries for fragmented frames, that |
770 | * would completely throw off the NAV at other STAs. | 803 | * would completely throw off the NAV at other STAs. |
@@ -775,37 +808,16 @@ ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx) | |||
775 | info->control.rates[4].idx = -1; | 808 | info->control.rates[4].idx = -1; |
776 | BUILD_BUG_ON(IEEE80211_TX_MAX_RATES != 5); | 809 | BUILD_BUG_ON(IEEE80211_TX_MAX_RATES != 5); |
777 | info->flags &= ~IEEE80211_TX_CTL_RATE_CTRL_PROBE; | 810 | info->flags &= ~IEEE80211_TX_CTL_RATE_CTRL_PROBE; |
811 | } else { | ||
812 | hdr->frame_control &= ~morefrags; | ||
813 | next_len = 0; | ||
778 | } | 814 | } |
779 | 815 | hdr->duration_id = ieee80211_duration(tx, 0, next_len); | |
780 | /* copy data */ | 816 | hdr->seq_ctrl |= cpu_to_le16(fragnum & IEEE80211_SCTL_FRAG); |
781 | copylen = left > per_fragm ? per_fragm : left; | 817 | fragnum++; |
782 | memcpy(skb_put(frag, copylen), pos, copylen); | 818 | } while ((skb = skb->next)); |
783 | |||
784 | skb_copy_queue_mapping(frag, first); | ||
785 | |||
786 | frag->do_not_encrypt = first->do_not_encrypt; | ||
787 | frag->dev = first->dev; | ||
788 | frag->iif = first->iif; | ||
789 | |||
790 | pos += copylen; | ||
791 | left -= copylen; | ||
792 | } | ||
793 | skb_trim(first, hdrlen + per_fragm); | ||
794 | |||
795 | tx->num_extra_frag = num_fragm - 1; | ||
796 | tx->extra_frag = frags; | ||
797 | 819 | ||
798 | return TX_CONTINUE; | 820 | return TX_CONTINUE; |
799 | |||
800 | fail: | ||
801 | if (frags) { | ||
802 | for (i = 0; i < num_fragm - 1; i++) | ||
803 | if (frags[i]) | ||
804 | dev_kfree_skb(frags[i]); | ||
805 | kfree(frags); | ||
806 | } | ||
807 | I802_DEBUG_INC(tx->local->tx_handlers_drop_fragment); | ||
808 | return TX_DROP; | ||
809 | } | 821 | } |
810 | 822 | ||
811 | static ieee80211_tx_result debug_noinline | 823 | static ieee80211_tx_result debug_noinline |
@@ -833,27 +845,19 @@ ieee80211_tx_h_encrypt(struct ieee80211_tx_data *tx) | |||
833 | static ieee80211_tx_result debug_noinline | 845 | static ieee80211_tx_result debug_noinline |
834 | ieee80211_tx_h_calculate_duration(struct ieee80211_tx_data *tx) | 846 | ieee80211_tx_h_calculate_duration(struct ieee80211_tx_data *tx) |
835 | { | 847 | { |
836 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data; | 848 | struct sk_buff *skb = tx->skb; |
837 | int next_len, i; | 849 | struct ieee80211_hdr *hdr; |
838 | int group_addr = is_multicast_ether_addr(hdr->addr1); | 850 | int next_len; |
839 | 851 | bool group_addr; | |
840 | if (!(tx->flags & IEEE80211_TX_FRAGMENTED)) { | ||
841 | hdr->duration_id = ieee80211_duration(tx, group_addr, 0); | ||
842 | return TX_CONTINUE; | ||
843 | } | ||
844 | 852 | ||
845 | hdr->duration_id = ieee80211_duration(tx, group_addr, | 853 | do { |
846 | tx->extra_frag[0]->len); | 854 | hdr = (void *) skb->data; |
855 | next_len = skb->next ? skb->next->len : 0; | ||
856 | group_addr = is_multicast_ether_addr(hdr->addr1); | ||
847 | 857 | ||
848 | for (i = 0; i < tx->num_extra_frag; i++) { | 858 | hdr->duration_id = |
849 | if (i + 1 < tx->num_extra_frag) | 859 | ieee80211_duration(tx, group_addr, next_len); |
850 | next_len = tx->extra_frag[i + 1]->len; | 860 | } while ((skb = skb->next)); |
851 | else | ||
852 | next_len = 0; | ||
853 | |||
854 | hdr = (struct ieee80211_hdr *)tx->extra_frag[i]->data; | ||
855 | hdr->duration_id = ieee80211_duration(tx, 0, next_len); | ||
856 | } | ||
857 | 861 | ||
858 | return TX_CONTINUE; | 862 | return TX_CONTINUE; |
859 | } | 863 | } |
@@ -861,19 +865,16 @@ ieee80211_tx_h_calculate_duration(struct ieee80211_tx_data *tx) | |||
861 | static ieee80211_tx_result debug_noinline | 865 | static ieee80211_tx_result debug_noinline |
862 | ieee80211_tx_h_stats(struct ieee80211_tx_data *tx) | 866 | ieee80211_tx_h_stats(struct ieee80211_tx_data *tx) |
863 | { | 867 | { |
864 | int i; | 868 | struct sk_buff *skb = tx->skb; |
865 | 869 | ||
866 | if (!tx->sta) | 870 | if (!tx->sta) |
867 | return TX_CONTINUE; | 871 | return TX_CONTINUE; |
868 | 872 | ||
869 | tx->sta->tx_packets++; | 873 | tx->sta->tx_packets++; |
870 | tx->sta->tx_fragments++; | 874 | do { |
871 | tx->sta->tx_bytes += tx->skb->len; | 875 | tx->sta->tx_fragments++; |
872 | if (tx->extra_frag) { | 876 | tx->sta->tx_bytes += skb->len; |
873 | tx->sta->tx_fragments += tx->num_extra_frag; | 877 | } while ((skb = skb->next)); |
874 | for (i = 0; i < tx->num_extra_frag; i++) | ||
875 | tx->sta->tx_bytes += tx->extra_frag[i]->len; | ||
876 | } | ||
877 | 878 | ||
878 | return TX_CONTINUE; | 879 | return TX_CONTINUE; |
879 | } | 880 | } |
@@ -983,9 +984,9 @@ __ieee80211_tx_prepare(struct ieee80211_tx_data *tx, | |||
983 | struct ieee80211_hdr *hdr; | 984 | struct ieee80211_hdr *hdr; |
984 | struct ieee80211_sub_if_data *sdata; | 985 | struct ieee80211_sub_if_data *sdata; |
985 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 986 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
986 | |||
987 | int hdrlen, tid; | 987 | int hdrlen, tid; |
988 | u8 *qc, *state; | 988 | u8 *qc, *state; |
989 | bool queued = false; | ||
989 | 990 | ||
990 | memset(tx, 0, sizeof(*tx)); | 991 | memset(tx, 0, sizeof(*tx)); |
991 | tx->skb = skb; | 992 | tx->skb = skb; |
@@ -1012,25 +1013,53 @@ __ieee80211_tx_prepare(struct ieee80211_tx_data *tx, | |||
1012 | */ | 1013 | */ |
1013 | } | 1014 | } |
1014 | 1015 | ||
1016 | /* | ||
1017 | * If this flag is set to true anywhere, and we get here, | ||
1018 | * we are doing the needed processing, so remove the flag | ||
1019 | * now. | ||
1020 | */ | ||
1021 | info->flags &= ~IEEE80211_TX_INTFL_NEED_TXPROCESSING; | ||
1022 | |||
1015 | hdr = (struct ieee80211_hdr *) skb->data; | 1023 | hdr = (struct ieee80211_hdr *) skb->data; |
1016 | 1024 | ||
1017 | tx->sta = sta_info_get(local, hdr->addr1); | 1025 | tx->sta = sta_info_get(local, hdr->addr1); |
1018 | 1026 | ||
1019 | if (tx->sta && ieee80211_is_data_qos(hdr->frame_control)) { | 1027 | if (tx->sta && ieee80211_is_data_qos(hdr->frame_control) && |
1028 | (local->hw.flags & IEEE80211_HW_AMPDU_AGGREGATION)) { | ||
1020 | unsigned long flags; | 1029 | unsigned long flags; |
1030 | struct tid_ampdu_tx *tid_tx; | ||
1031 | |||
1021 | qc = ieee80211_get_qos_ctl(hdr); | 1032 | qc = ieee80211_get_qos_ctl(hdr); |
1022 | tid = *qc & IEEE80211_QOS_CTL_TID_MASK; | 1033 | tid = *qc & IEEE80211_QOS_CTL_TID_MASK; |
1023 | 1034 | ||
1024 | spin_lock_irqsave(&tx->sta->lock, flags); | 1035 | spin_lock_irqsave(&tx->sta->lock, flags); |
1036 | /* | ||
1037 | * XXX: This spinlock could be fairly expensive, but see the | ||
1038 | * comment in agg-tx.c:ieee80211_agg_tx_operational(). | ||
1039 | * One way to solve this would be to do something RCU-like | ||
1040 | * for managing the tid_tx struct and using atomic bitops | ||
1041 | * for the actual state -- by introducing an actual | ||
1042 | * 'operational' bit that would be possible. It would | ||
1043 | * require changing ieee80211_agg_tx_operational() to | ||
1044 | * set that bit, and changing the way tid_tx is managed | ||
1045 | * everywhere, including races between that bit and | ||
1046 | * tid_tx going away (tid_tx being added can be easily | ||
1047 | * committed to memory before the 'operational' bit). | ||
1048 | */ | ||
1049 | tid_tx = tx->sta->ampdu_mlme.tid_tx[tid]; | ||
1025 | state = &tx->sta->ampdu_mlme.tid_state_tx[tid]; | 1050 | state = &tx->sta->ampdu_mlme.tid_state_tx[tid]; |
1026 | if (*state == HT_AGG_STATE_OPERATIONAL) { | 1051 | if (*state == HT_AGG_STATE_OPERATIONAL) { |
1027 | info->flags |= IEEE80211_TX_CTL_AMPDU; | 1052 | info->flags |= IEEE80211_TX_CTL_AMPDU; |
1028 | if (local->hw.ampdu_queues) | 1053 | } else if (*state != HT_AGG_STATE_IDLE) { |
1029 | skb_set_queue_mapping( | 1054 | /* in progress */ |
1030 | skb, tx->local->hw.queues + | 1055 | queued = true; |
1031 | tx->sta->tid_to_tx_q[tid]); | 1056 | info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; |
1057 | __skb_queue_tail(&tid_tx->pending, skb); | ||
1032 | } | 1058 | } |
1033 | spin_unlock_irqrestore(&tx->sta->lock, flags); | 1059 | spin_unlock_irqrestore(&tx->sta->lock, flags); |
1060 | |||
1061 | if (unlikely(queued)) | ||
1062 | return TX_QUEUED; | ||
1034 | } | 1063 | } |
1035 | 1064 | ||
1036 | if (is_multicast_ether_addr(hdr->addr1)) { | 1065 | if (is_multicast_ether_addr(hdr->addr1)) { |
@@ -1081,51 +1110,55 @@ static int ieee80211_tx_prepare(struct ieee80211_local *local, | |||
1081 | } | 1110 | } |
1082 | if (unlikely(!dev)) | 1111 | if (unlikely(!dev)) |
1083 | return -ENODEV; | 1112 | return -ENODEV; |
1084 | /* initialises tx with control */ | 1113 | /* |
1114 | * initialises tx with control | ||
1115 | * | ||
1116 | * return value is safe to ignore here because this function | ||
1117 | * can only be invoked for multicast frames | ||
1118 | * | ||
1119 | * XXX: clean up | ||
1120 | */ | ||
1085 | __ieee80211_tx_prepare(tx, skb, dev); | 1121 | __ieee80211_tx_prepare(tx, skb, dev); |
1086 | dev_put(dev); | 1122 | dev_put(dev); |
1087 | return 0; | 1123 | return 0; |
1088 | } | 1124 | } |
1089 | 1125 | ||
1090 | static int __ieee80211_tx(struct ieee80211_local *local, struct sk_buff *skb, | 1126 | static int __ieee80211_tx(struct ieee80211_local *local, |
1091 | struct ieee80211_tx_data *tx) | 1127 | struct sk_buff **skbp, |
1128 | struct sta_info *sta) | ||
1092 | { | 1129 | { |
1130 | struct sk_buff *skb = *skbp, *next; | ||
1093 | struct ieee80211_tx_info *info; | 1131 | struct ieee80211_tx_info *info; |
1094 | int ret, i; | 1132 | int ret, len; |
1133 | bool fragm = false; | ||
1095 | 1134 | ||
1096 | if (skb) { | 1135 | local->mdev->trans_start = jiffies; |
1136 | |||
1137 | while (skb) { | ||
1097 | if (ieee80211_queue_stopped(&local->hw, | 1138 | if (ieee80211_queue_stopped(&local->hw, |
1098 | skb_get_queue_mapping(skb))) | 1139 | skb_get_queue_mapping(skb))) |
1099 | return IEEE80211_TX_PENDING; | 1140 | return IEEE80211_TX_PENDING; |
1100 | 1141 | ||
1101 | ret = local->ops->tx(local_to_hw(local), skb); | 1142 | info = IEEE80211_SKB_CB(skb); |
1102 | if (ret) | 1143 | |
1103 | return IEEE80211_TX_AGAIN; | 1144 | if (fragm) |
1104 | local->mdev->trans_start = jiffies; | ||
1105 | ieee80211_led_tx(local, 1); | ||
1106 | } | ||
1107 | if (tx->extra_frag) { | ||
1108 | for (i = 0; i < tx->num_extra_frag; i++) { | ||
1109 | if (!tx->extra_frag[i]) | ||
1110 | continue; | ||
1111 | info = IEEE80211_SKB_CB(tx->extra_frag[i]); | ||
1112 | info->flags &= ~(IEEE80211_TX_CTL_CLEAR_PS_FILT | | 1145 | info->flags &= ~(IEEE80211_TX_CTL_CLEAR_PS_FILT | |
1113 | IEEE80211_TX_CTL_FIRST_FRAGMENT); | 1146 | IEEE80211_TX_CTL_FIRST_FRAGMENT); |
1114 | if (ieee80211_queue_stopped(&local->hw, | 1147 | |
1115 | skb_get_queue_mapping(tx->extra_frag[i]))) | 1148 | next = skb->next; |
1116 | return IEEE80211_TX_FRAG_AGAIN; | 1149 | len = skb->len; |
1117 | 1150 | ret = local->ops->tx(local_to_hw(local), skb); | |
1118 | ret = local->ops->tx(local_to_hw(local), | 1151 | if (WARN_ON(ret != NETDEV_TX_OK && skb->len != len)) { |
1119 | tx->extra_frag[i]); | 1152 | dev_kfree_skb(skb); |
1120 | if (ret) | 1153 | ret = NETDEV_TX_OK; |
1121 | return IEEE80211_TX_FRAG_AGAIN; | ||
1122 | local->mdev->trans_start = jiffies; | ||
1123 | ieee80211_led_tx(local, 1); | ||
1124 | tx->extra_frag[i] = NULL; | ||
1125 | } | 1154 | } |
1126 | kfree(tx->extra_frag); | 1155 | if (ret != NETDEV_TX_OK) |
1127 | tx->extra_frag = NULL; | 1156 | return IEEE80211_TX_AGAIN; |
1157 | *skbp = skb = next; | ||
1158 | ieee80211_led_tx(local, 1); | ||
1159 | fragm = true; | ||
1128 | } | 1160 | } |
1161 | |||
1129 | return IEEE80211_TX_OK; | 1162 | return IEEE80211_TX_OK; |
1130 | } | 1163 | } |
1131 | 1164 | ||
@@ -1137,7 +1170,6 @@ static int invoke_tx_handlers(struct ieee80211_tx_data *tx) | |||
1137 | { | 1170 | { |
1138 | struct sk_buff *skb = tx->skb; | 1171 | struct sk_buff *skb = tx->skb; |
1139 | ieee80211_tx_result res = TX_DROP; | 1172 | ieee80211_tx_result res = TX_DROP; |
1140 | int i; | ||
1141 | 1173 | ||
1142 | #define CALL_TXH(txh) \ | 1174 | #define CALL_TXH(txh) \ |
1143 | res = txh(tx); \ | 1175 | res = txh(tx); \ |
@@ -1161,11 +1193,13 @@ static int invoke_tx_handlers(struct ieee80211_tx_data *tx) | |||
1161 | txh_done: | 1193 | txh_done: |
1162 | if (unlikely(res == TX_DROP)) { | 1194 | if (unlikely(res == TX_DROP)) { |
1163 | I802_DEBUG_INC(tx->local->tx_handlers_drop); | 1195 | I802_DEBUG_INC(tx->local->tx_handlers_drop); |
1164 | dev_kfree_skb(skb); | 1196 | while (skb) { |
1165 | for (i = 0; i < tx->num_extra_frag; i++) | 1197 | struct sk_buff *next; |
1166 | if (tx->extra_frag[i]) | 1198 | |
1167 | dev_kfree_skb(tx->extra_frag[i]); | 1199 | next = skb->next; |
1168 | kfree(tx->extra_frag); | 1200 | dev_kfree_skb(skb); |
1201 | skb = next; | ||
1202 | } | ||
1169 | return -1; | 1203 | return -1; |
1170 | } else if (unlikely(res == TX_QUEUED)) { | 1204 | } else if (unlikely(res == TX_QUEUED)) { |
1171 | I802_DEBUG_INC(tx->local->tx_handlers_queued); | 1205 | I802_DEBUG_INC(tx->local->tx_handlers_queued); |
@@ -1175,23 +1209,26 @@ static int invoke_tx_handlers(struct ieee80211_tx_data *tx) | |||
1175 | return 0; | 1209 | return 0; |
1176 | } | 1210 | } |
1177 | 1211 | ||
1178 | static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb) | 1212 | static void ieee80211_tx(struct net_device *dev, struct sk_buff *skb, |
1213 | bool txpending) | ||
1179 | { | 1214 | { |
1180 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 1215 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); |
1181 | struct sta_info *sta; | 1216 | struct sta_info *sta; |
1182 | struct ieee80211_tx_data tx; | 1217 | struct ieee80211_tx_data tx; |
1183 | ieee80211_tx_result res_prepare; | 1218 | ieee80211_tx_result res_prepare; |
1184 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 1219 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
1185 | int ret, i; | 1220 | struct sk_buff *next; |
1221 | unsigned long flags; | ||
1222 | int ret, retries; | ||
1186 | u16 queue; | 1223 | u16 queue; |
1187 | 1224 | ||
1188 | queue = skb_get_queue_mapping(skb); | 1225 | queue = skb_get_queue_mapping(skb); |
1189 | 1226 | ||
1190 | WARN_ON(test_bit(queue, local->queues_pending)); | 1227 | WARN_ON(!txpending && !skb_queue_empty(&local->pending[queue])); |
1191 | 1228 | ||
1192 | if (unlikely(skb->len < 10)) { | 1229 | if (unlikely(skb->len < 10)) { |
1193 | dev_kfree_skb(skb); | 1230 | dev_kfree_skb(skb); |
1194 | return 0; | 1231 | return; |
1195 | } | 1232 | } |
1196 | 1233 | ||
1197 | rcu_read_lock(); | 1234 | rcu_read_lock(); |
@@ -1199,10 +1236,13 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb) | |||
1199 | /* initialises tx */ | 1236 | /* initialises tx */ |
1200 | res_prepare = __ieee80211_tx_prepare(&tx, skb, dev); | 1237 | res_prepare = __ieee80211_tx_prepare(&tx, skb, dev); |
1201 | 1238 | ||
1202 | if (res_prepare == TX_DROP) { | 1239 | if (unlikely(res_prepare == TX_DROP)) { |
1203 | dev_kfree_skb(skb); | 1240 | dev_kfree_skb(skb); |
1204 | rcu_read_unlock(); | 1241 | rcu_read_unlock(); |
1205 | return 0; | 1242 | return; |
1243 | } else if (unlikely(res_prepare == TX_QUEUED)) { | ||
1244 | rcu_read_unlock(); | ||
1245 | return; | ||
1206 | } | 1246 | } |
1207 | 1247 | ||
1208 | sta = tx.sta; | 1248 | sta = tx.sta; |
@@ -1212,59 +1252,71 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb) | |||
1212 | if (invoke_tx_handlers(&tx)) | 1252 | if (invoke_tx_handlers(&tx)) |
1213 | goto out; | 1253 | goto out; |
1214 | 1254 | ||
1215 | retry: | 1255 | retries = 0; |
1216 | ret = __ieee80211_tx(local, skb, &tx); | 1256 | retry: |
1217 | if (ret) { | 1257 | ret = __ieee80211_tx(local, &tx.skb, tx.sta); |
1218 | struct ieee80211_tx_stored_packet *store; | 1258 | switch (ret) { |
1219 | 1259 | case IEEE80211_TX_OK: | |
1260 | break; | ||
1261 | case IEEE80211_TX_AGAIN: | ||
1220 | /* | 1262 | /* |
1221 | * Since there are no fragmented frames on A-MPDU | 1263 | * Since there are no fragmented frames on A-MPDU |
1222 | * queues, there's no reason for a driver to reject | 1264 | * queues, there's no reason for a driver to reject |
1223 | * a frame there, warn and drop it. | 1265 | * a frame there, warn and drop it. |
1224 | */ | 1266 | */ |
1225 | if (ret != IEEE80211_TX_PENDING) | 1267 | if (WARN_ON(info->flags & IEEE80211_TX_CTL_AMPDU)) |
1226 | if (WARN_ON(info->flags & IEEE80211_TX_CTL_AMPDU)) | 1268 | goto drop; |
1227 | goto drop; | 1269 | /* fall through */ |
1270 | case IEEE80211_TX_PENDING: | ||
1271 | skb = tx.skb; | ||
1272 | |||
1273 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); | ||
1274 | |||
1275 | if (__netif_subqueue_stopped(local->mdev, queue)) { | ||
1276 | do { | ||
1277 | next = skb->next; | ||
1278 | skb->next = NULL; | ||
1279 | if (unlikely(txpending)) | ||
1280 | skb_queue_head(&local->pending[queue], | ||
1281 | skb); | ||
1282 | else | ||
1283 | skb_queue_tail(&local->pending[queue], | ||
1284 | skb); | ||
1285 | } while ((skb = next)); | ||
1228 | 1286 | ||
1229 | store = &local->pending_packet[queue]; | 1287 | /* |
1288 | * Make sure nobody will enable the queue on us | ||
1289 | * (without going through the tasklet) nor disable the | ||
1290 | * netdev queue underneath the pending handling code. | ||
1291 | */ | ||
1292 | __set_bit(IEEE80211_QUEUE_STOP_REASON_PENDING, | ||
1293 | &local->queue_stop_reasons[queue]); | ||
1230 | 1294 | ||
1231 | if (ret == IEEE80211_TX_FRAG_AGAIN) | 1295 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, |
1232 | skb = NULL; | 1296 | flags); |
1297 | } else { | ||
1298 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, | ||
1299 | flags); | ||
1233 | 1300 | ||
1234 | set_bit(queue, local->queues_pending); | 1301 | retries++; |
1235 | smp_mb(); | 1302 | if (WARN(retries > 10, "tx refused but queue active")) |
1236 | /* | 1303 | goto drop; |
1237 | * When the driver gets out of buffers during sending of | ||
1238 | * fragments and calls ieee80211_stop_queue, the netif | ||
1239 | * subqueue is stopped. There is, however, a small window | ||
1240 | * in which the PENDING bit is not yet set. If a buffer | ||
1241 | * gets available in that window (i.e. driver calls | ||
1242 | * ieee80211_wake_queue), we would end up with ieee80211_tx | ||
1243 | * called with the PENDING bit still set. Prevent this by | ||
1244 | * continuing transmitting here when that situation is | ||
1245 | * possible to have happened. | ||
1246 | */ | ||
1247 | if (!__netif_subqueue_stopped(local->mdev, queue)) { | ||
1248 | clear_bit(queue, local->queues_pending); | ||
1249 | goto retry; | 1304 | goto retry; |
1250 | } | 1305 | } |
1251 | store->skb = skb; | ||
1252 | store->extra_frag = tx.extra_frag; | ||
1253 | store->num_extra_frag = tx.num_extra_frag; | ||
1254 | } | 1306 | } |
1255 | out: | 1307 | out: |
1256 | rcu_read_unlock(); | 1308 | rcu_read_unlock(); |
1257 | return 0; | 1309 | return; |
1258 | 1310 | ||
1259 | drop: | 1311 | drop: |
1260 | if (skb) | ||
1261 | dev_kfree_skb(skb); | ||
1262 | for (i = 0; i < tx.num_extra_frag; i++) | ||
1263 | if (tx.extra_frag[i]) | ||
1264 | dev_kfree_skb(tx.extra_frag[i]); | ||
1265 | kfree(tx.extra_frag); | ||
1266 | rcu_read_unlock(); | 1312 | rcu_read_unlock(); |
1267 | return 0; | 1313 | |
1314 | skb = tx.skb; | ||
1315 | while (skb) { | ||
1316 | next = skb->next; | ||
1317 | dev_kfree_skb(skb); | ||
1318 | skb = next; | ||
1319 | } | ||
1268 | } | 1320 | } |
1269 | 1321 | ||
1270 | /* device xmit handlers */ | 1322 | /* device xmit handlers */ |
@@ -1323,7 +1375,6 @@ int ieee80211_master_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
1323 | FOUND_SDATA, | 1375 | FOUND_SDATA, |
1324 | UNKNOWN_ADDRESS, | 1376 | UNKNOWN_ADDRESS, |
1325 | } monitor_iface = NOT_MONITOR; | 1377 | } monitor_iface = NOT_MONITOR; |
1326 | int ret; | ||
1327 | 1378 | ||
1328 | if (skb->iif) | 1379 | if (skb->iif) |
1329 | odev = dev_get_by_index(&init_net, skb->iif); | 1380 | odev = dev_get_by_index(&init_net, skb->iif); |
@@ -1337,7 +1388,7 @@ int ieee80211_master_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
1337 | "originating device\n", dev->name); | 1388 | "originating device\n", dev->name); |
1338 | #endif | 1389 | #endif |
1339 | dev_kfree_skb(skb); | 1390 | dev_kfree_skb(skb); |
1340 | return 0; | 1391 | return NETDEV_TX_OK; |
1341 | } | 1392 | } |
1342 | 1393 | ||
1343 | if ((local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) && | 1394 | if ((local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) && |
@@ -1366,7 +1417,7 @@ int ieee80211_master_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
1366 | else | 1417 | else |
1367 | if (mesh_nexthop_lookup(skb, osdata)) { | 1418 | if (mesh_nexthop_lookup(skb, osdata)) { |
1368 | dev_put(odev); | 1419 | dev_put(odev); |
1369 | return 0; | 1420 | return NETDEV_TX_OK; |
1370 | } | 1421 | } |
1371 | if (memcmp(odev->dev_addr, hdr->addr4, ETH_ALEN) != 0) | 1422 | if (memcmp(odev->dev_addr, hdr->addr4, ETH_ALEN) != 0) |
1372 | IEEE80211_IFSTA_MESH_CTR_INC(&osdata->u.mesh, | 1423 | IEEE80211_IFSTA_MESH_CTR_INC(&osdata->u.mesh, |
@@ -1428,7 +1479,7 @@ int ieee80211_master_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
1428 | if (ieee80211_skb_resize(osdata->local, skb, headroom, may_encrypt)) { | 1479 | if (ieee80211_skb_resize(osdata->local, skb, headroom, may_encrypt)) { |
1429 | dev_kfree_skb(skb); | 1480 | dev_kfree_skb(skb); |
1430 | dev_put(odev); | 1481 | dev_put(odev); |
1431 | return 0; | 1482 | return NETDEV_TX_OK; |
1432 | } | 1483 | } |
1433 | 1484 | ||
1434 | if (osdata->vif.type == NL80211_IFTYPE_AP_VLAN) | 1485 | if (osdata->vif.type == NL80211_IFTYPE_AP_VLAN) |
@@ -1437,10 +1488,11 @@ int ieee80211_master_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
1437 | u.ap); | 1488 | u.ap); |
1438 | if (likely(monitor_iface != UNKNOWN_ADDRESS)) | 1489 | if (likely(monitor_iface != UNKNOWN_ADDRESS)) |
1439 | info->control.vif = &osdata->vif; | 1490 | info->control.vif = &osdata->vif; |
1440 | ret = ieee80211_tx(odev, skb); | 1491 | |
1492 | ieee80211_tx(odev, skb, false); | ||
1441 | dev_put(odev); | 1493 | dev_put(odev); |
1442 | 1494 | ||
1443 | return ret; | 1495 | return NETDEV_TX_OK; |
1444 | } | 1496 | } |
1445 | 1497 | ||
1446 | int ieee80211_monitor_start_xmit(struct sk_buff *skb, | 1498 | int ieee80211_monitor_start_xmit(struct sk_buff *skb, |
@@ -1666,8 +1718,7 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1666 | } | 1718 | } |
1667 | 1719 | ||
1668 | /* receiver and we are QoS enabled, use a QoS type frame */ | 1720 | /* receiver and we are QoS enabled, use a QoS type frame */ |
1669 | if (sta_flags & WLAN_STA_WME && | 1721 | if ((sta_flags & WLAN_STA_WME) && local->hw.queues >= 4) { |
1670 | ieee80211_num_regular_queues(&local->hw) >= 4) { | ||
1671 | fc |= cpu_to_le16(IEEE80211_STYPE_QOS_DATA); | 1722 | fc |= cpu_to_le16(IEEE80211_STYPE_QOS_DATA); |
1672 | hdrlen += 2; | 1723 | hdrlen += 2; |
1673 | } | 1724 | } |
@@ -1799,19 +1850,58 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, | |||
1799 | */ | 1850 | */ |
1800 | void ieee80211_clear_tx_pending(struct ieee80211_local *local) | 1851 | void ieee80211_clear_tx_pending(struct ieee80211_local *local) |
1801 | { | 1852 | { |
1802 | int i, j; | 1853 | int i; |
1803 | struct ieee80211_tx_stored_packet *store; | ||
1804 | 1854 | ||
1805 | for (i = 0; i < ieee80211_num_regular_queues(&local->hw); i++) { | 1855 | for (i = 0; i < local->hw.queues; i++) |
1806 | if (!test_bit(i, local->queues_pending)) | 1856 | skb_queue_purge(&local->pending[i]); |
1807 | continue; | 1857 | } |
1808 | store = &local->pending_packet[i]; | 1858 | |
1809 | kfree_skb(store->skb); | 1859 | static bool ieee80211_tx_pending_skb(struct ieee80211_local *local, |
1810 | for (j = 0; j < store->num_extra_frag; j++) | 1860 | struct sk_buff *skb) |
1811 | kfree_skb(store->extra_frag[j]); | 1861 | { |
1812 | kfree(store->extra_frag); | 1862 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
1813 | clear_bit(i, local->queues_pending); | 1863 | struct ieee80211_sub_if_data *sdata; |
1864 | struct sta_info *sta; | ||
1865 | struct ieee80211_hdr *hdr; | ||
1866 | struct net_device *dev; | ||
1867 | int ret; | ||
1868 | bool result = true; | ||
1869 | |||
1870 | /* does interface still exist? */ | ||
1871 | dev = dev_get_by_index(&init_net, skb->iif); | ||
1872 | if (!dev) { | ||
1873 | dev_kfree_skb(skb); | ||
1874 | return true; | ||
1814 | } | 1875 | } |
1876 | |||
1877 | /* validate info->control.vif against skb->iif */ | ||
1878 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
1879 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | ||
1880 | sdata = container_of(sdata->bss, | ||
1881 | struct ieee80211_sub_if_data, | ||
1882 | u.ap); | ||
1883 | |||
1884 | if (unlikely(info->control.vif && info->control.vif != &sdata->vif)) { | ||
1885 | dev_kfree_skb(skb); | ||
1886 | result = true; | ||
1887 | goto out; | ||
1888 | } | ||
1889 | |||
1890 | if (info->flags & IEEE80211_TX_INTFL_NEED_TXPROCESSING) { | ||
1891 | ieee80211_tx(dev, skb, true); | ||
1892 | } else { | ||
1893 | hdr = (struct ieee80211_hdr *)skb->data; | ||
1894 | sta = sta_info_get(local, hdr->addr1); | ||
1895 | |||
1896 | ret = __ieee80211_tx(local, &skb, sta); | ||
1897 | if (ret != IEEE80211_TX_OK) | ||
1898 | result = false; | ||
1899 | } | ||
1900 | |||
1901 | out: | ||
1902 | dev_put(dev); | ||
1903 | |||
1904 | return result; | ||
1815 | } | 1905 | } |
1816 | 1906 | ||
1817 | /* | 1907 | /* |
@@ -1822,40 +1912,53 @@ void ieee80211_tx_pending(unsigned long data) | |||
1822 | { | 1912 | { |
1823 | struct ieee80211_local *local = (struct ieee80211_local *)data; | 1913 | struct ieee80211_local *local = (struct ieee80211_local *)data; |
1824 | struct net_device *dev = local->mdev; | 1914 | struct net_device *dev = local->mdev; |
1825 | struct ieee80211_tx_stored_packet *store; | 1915 | unsigned long flags; |
1826 | struct ieee80211_tx_data tx; | 1916 | int i; |
1827 | int i, ret; | 1917 | bool next; |
1828 | 1918 | ||
1919 | rcu_read_lock(); | ||
1829 | netif_tx_lock_bh(dev); | 1920 | netif_tx_lock_bh(dev); |
1830 | for (i = 0; i < ieee80211_num_regular_queues(&local->hw); i++) { | ||
1831 | /* Check that this queue is ok */ | ||
1832 | if (__netif_subqueue_stopped(local->mdev, i) && | ||
1833 | !test_bit(i, local->queues_pending_run)) | ||
1834 | continue; | ||
1835 | 1921 | ||
1836 | if (!test_bit(i, local->queues_pending)) { | 1922 | for (i = 0; i < local->hw.queues; i++) { |
1837 | clear_bit(i, local->queues_pending_run); | 1923 | /* |
1838 | ieee80211_wake_queue(&local->hw, i); | 1924 | * If queue is stopped by something other than due to pending |
1925 | * frames, or we have no pending frames, proceed to next queue. | ||
1926 | */ | ||
1927 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); | ||
1928 | next = false; | ||
1929 | if (local->queue_stop_reasons[i] != | ||
1930 | BIT(IEEE80211_QUEUE_STOP_REASON_PENDING) || | ||
1931 | skb_queue_empty(&local->pending[i])) | ||
1932 | next = true; | ||
1933 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); | ||
1934 | |||
1935 | if (next) | ||
1839 | continue; | 1936 | continue; |
1840 | } | ||
1841 | 1937 | ||
1842 | clear_bit(i, local->queues_pending_run); | 1938 | /* |
1939 | * start the queue now to allow processing our packets, | ||
1940 | * we're under the tx lock here anyway so nothing will | ||
1941 | * happen as a result of this | ||
1942 | */ | ||
1843 | netif_start_subqueue(local->mdev, i); | 1943 | netif_start_subqueue(local->mdev, i); |
1844 | 1944 | ||
1845 | store = &local->pending_packet[i]; | 1945 | while (!skb_queue_empty(&local->pending[i])) { |
1846 | tx.extra_frag = store->extra_frag; | 1946 | struct sk_buff *skb = skb_dequeue(&local->pending[i]); |
1847 | tx.num_extra_frag = store->num_extra_frag; | 1947 | |
1848 | tx.flags = 0; | 1948 | if (!ieee80211_tx_pending_skb(local, skb)) { |
1849 | ret = __ieee80211_tx(local, store->skb, &tx); | 1949 | skb_queue_head(&local->pending[i], skb); |
1850 | if (ret) { | 1950 | break; |
1851 | if (ret == IEEE80211_TX_FRAG_AGAIN) | 1951 | } |
1852 | store->skb = NULL; | ||
1853 | } else { | ||
1854 | clear_bit(i, local->queues_pending); | ||
1855 | ieee80211_wake_queue(&local->hw, i); | ||
1856 | } | 1952 | } |
1953 | |||
1954 | /* Start regular packet processing again. */ | ||
1955 | if (skb_queue_empty(&local->pending[i])) | ||
1956 | ieee80211_wake_queue_by_reason(&local->hw, i, | ||
1957 | IEEE80211_QUEUE_STOP_REASON_PENDING); | ||
1857 | } | 1958 | } |
1959 | |||
1858 | netif_tx_unlock_bh(dev); | 1960 | netif_tx_unlock_bh(dev); |
1961 | rcu_read_unlock(); | ||
1859 | } | 1962 | } |
1860 | 1963 | ||
1861 | /* functions for drivers to get certain frames */ | 1964 | /* functions for drivers to get certain frames */ |
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index e0431a1d218b..fdf432f14554 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -166,18 +166,13 @@ int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr) | |||
166 | 166 | ||
167 | void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx) | 167 | void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx) |
168 | { | 168 | { |
169 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data; | 169 | struct sk_buff *skb = tx->skb; |
170 | 170 | struct ieee80211_hdr *hdr; | |
171 | hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); | 171 | |
172 | if (tx->extra_frag) { | 172 | do { |
173 | struct ieee80211_hdr *fhdr; | 173 | hdr = (struct ieee80211_hdr *) skb->data; |
174 | int i; | 174 | hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); |
175 | for (i = 0; i < tx->num_extra_frag; i++) { | 175 | } while ((skb = skb->next)); |
176 | fhdr = (struct ieee80211_hdr *) | ||
177 | tx->extra_frag[i]->data; | ||
178 | fhdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); | ||
179 | } | ||
180 | } | ||
181 | } | 176 | } |
182 | 177 | ||
183 | int ieee80211_frame_duration(struct ieee80211_local *local, size_t len, | 178 | int ieee80211_frame_duration(struct ieee80211_local *local, size_t len, |
@@ -344,42 +339,21 @@ static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue, | |||
344 | { | 339 | { |
345 | struct ieee80211_local *local = hw_to_local(hw); | 340 | struct ieee80211_local *local = hw_to_local(hw); |
346 | 341 | ||
347 | if (queue >= hw->queues) { | 342 | if (WARN_ON(queue >= hw->queues)) |
348 | if (local->ampdu_ac_queue[queue - hw->queues] < 0) | 343 | return; |
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]); | ||
361 | |||
362 | if (local->queue_stop_reasons[queue] || | ||
363 | local->amdpu_ac_stop_refcnt[queue - hw->queues]) | ||
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; | ||
369 | } | ||
370 | 344 | ||
371 | __clear_bit(reason, &local->queue_stop_reasons[queue]); | 345 | __clear_bit(reason, &local->queue_stop_reasons[queue]); |
372 | 346 | ||
347 | if (!skb_queue_empty(&local->pending[queue]) && | ||
348 | local->queue_stop_reasons[queue] == | ||
349 | BIT(IEEE80211_QUEUE_STOP_REASON_PENDING)) | ||
350 | tasklet_schedule(&local->tx_pending_tasklet); | ||
351 | |||
373 | if (local->queue_stop_reasons[queue] != 0) | 352 | if (local->queue_stop_reasons[queue] != 0) |
374 | /* someone still has this queue stopped */ | 353 | /* someone still has this queue stopped */ |
375 | return; | 354 | return; |
376 | 355 | ||
377 | if (test_bit(queue, local->queues_pending)) { | 356 | netif_wake_subqueue(local->mdev, queue); |
378 | set_bit(queue, local->queues_pending_run); | ||
379 | tasklet_schedule(&local->tx_pending_tasklet); | ||
380 | } else { | ||
381 | netif_wake_subqueue(local->mdev, queue); | ||
382 | } | ||
383 | } | 357 | } |
384 | 358 | ||
385 | void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue, | 359 | void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue, |
@@ -405,29 +379,18 @@ static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue, | |||
405 | { | 379 | { |
406 | struct ieee80211_local *local = hw_to_local(hw); | 380 | struct ieee80211_local *local = hw_to_local(hw); |
407 | 381 | ||
408 | if (queue >= hw->queues) { | 382 | if (WARN_ON(queue >= hw->queues)) |
409 | if (local->ampdu_ac_queue[queue - hw->queues] < 0) | 383 | return; |
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 | 384 | ||
423 | /* now go on to treat the corresponding regular queue */ | 385 | /* |
424 | queue = local->ampdu_ac_queue[queue - hw->queues]; | 386 | * Only stop if it was previously running, this is necessary |
425 | reason = IEEE80211_QUEUE_STOP_REASON_AGGREGATION; | 387 | * for correct pending packets handling because there we may |
426 | } | 388 | * start (but not wake) the queue and rely on that. |
389 | */ | ||
390 | if (!local->queue_stop_reasons[queue]) | ||
391 | netif_stop_subqueue(local->mdev, queue); | ||
427 | 392 | ||
428 | __set_bit(reason, &local->queue_stop_reasons[queue]); | 393 | __set_bit(reason, &local->queue_stop_reasons[queue]); |
429 | |||
430 | netif_stop_subqueue(local->mdev, queue); | ||
431 | } | 394 | } |
432 | 395 | ||
433 | void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue, | 396 | void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue, |
@@ -473,15 +436,9 @@ EXPORT_SYMBOL(ieee80211_stop_queues); | |||
473 | int ieee80211_queue_stopped(struct ieee80211_hw *hw, int queue) | 436 | int ieee80211_queue_stopped(struct ieee80211_hw *hw, int queue) |
474 | { | 437 | { |
475 | struct ieee80211_local *local = hw_to_local(hw); | 438 | struct ieee80211_local *local = hw_to_local(hw); |
476 | unsigned long flags; | ||
477 | 439 | ||
478 | if (queue >= hw->queues) { | 440 | if (WARN_ON(queue >= hw->queues)) |
479 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); | 441 | return true; |
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 | 442 | ||
486 | return __netif_subqueue_stopped(local->mdev, queue); | 443 | return __netif_subqueue_stopped(local->mdev, queue); |
487 | } | 444 | } |
@@ -496,7 +453,7 @@ void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw, | |||
496 | 453 | ||
497 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); | 454 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); |
498 | 455 | ||
499 | for (i = 0; i < hw->queues + hw->ampdu_queues; i++) | 456 | for (i = 0; i < hw->queues; i++) |
500 | __ieee80211_wake_queue(hw, i, reason); | 457 | __ieee80211_wake_queue(hw, i, reason); |
501 | 458 | ||
502 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); | 459 | spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); |
@@ -846,16 +803,9 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, | |||
846 | struct ieee80211_local *local = sdata->local; | 803 | struct ieee80211_local *local = sdata->local; |
847 | struct sk_buff *skb; | 804 | struct sk_buff *skb; |
848 | struct ieee80211_mgmt *mgmt; | 805 | 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 | 806 | ||
857 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + | 807 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + |
858 | sizeof(*mgmt) + 6 + extra_len + ie_auth_len); | 808 | sizeof(*mgmt) + 6 + extra_len); |
859 | if (!skb) { | 809 | if (!skb) { |
860 | printk(KERN_DEBUG "%s: failed to allocate buffer for auth " | 810 | printk(KERN_DEBUG "%s: failed to allocate buffer for auth " |
861 | "frame\n", sdata->dev->name); | 811 | "frame\n", sdata->dev->name); |
@@ -877,8 +827,6 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, | |||
877 | mgmt->u.auth.status_code = cpu_to_le16(0); | 827 | mgmt->u.auth.status_code = cpu_to_le16(0); |
878 | if (extra) | 828 | if (extra) |
879 | memcpy(skb_put(skb, extra_len), extra, extra_len); | 829 | 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 | 830 | ||
883 | ieee80211_tx_skb(sdata, skb, encrypt); | 831 | ieee80211_tx_skb(sdata, skb, encrypt); |
884 | } | 832 | } |
@@ -891,20 +839,11 @@ void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, | |||
891 | struct ieee80211_supported_band *sband; | 839 | struct ieee80211_supported_band *sband; |
892 | struct sk_buff *skb; | 840 | struct sk_buff *skb; |
893 | struct ieee80211_mgmt *mgmt; | 841 | struct ieee80211_mgmt *mgmt; |
894 | u8 *pos, *supp_rates, *esupp_rates = NULL, *extra_preq_ie = NULL; | 842 | u8 *pos, *supp_rates, *esupp_rates = NULL; |
895 | int i, extra_preq_ie_len = 0; | 843 | int i; |
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 | 844 | ||
906 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt) + 200 + | 845 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt) + 200 + |
907 | ie_len + extra_preq_ie_len); | 846 | ie_len); |
908 | if (!skb) { | 847 | if (!skb) { |
909 | printk(KERN_DEBUG "%s: failed to allocate buffer for probe " | 848 | printk(KERN_DEBUG "%s: failed to allocate buffer for probe " |
910 | "request\n", sdata->dev->name); | 849 | "request\n", sdata->dev->name); |
@@ -953,9 +892,6 @@ void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, | |||
953 | 892 | ||
954 | if (ie) | 893 | if (ie) |
955 | memcpy(skb_put(skb, ie_len), ie, ie_len); | 894 | 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 | 895 | ||
960 | ieee80211_tx_skb(sdata, skb, 0); | 896 | ieee80211_tx_skb(sdata, skb, 0); |
961 | } | 897 | } |
diff --git a/net/mac80211/wep.c b/net/mac80211/wep.c index 7043ddc75498..ef73105b3061 100644 --- a/net/mac80211/wep.c +++ b/net/mac80211/wep.c | |||
@@ -329,24 +329,17 @@ static int wep_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) | |||
329 | ieee80211_tx_result | 329 | ieee80211_tx_result |
330 | ieee80211_crypto_wep_encrypt(struct ieee80211_tx_data *tx) | 330 | ieee80211_crypto_wep_encrypt(struct ieee80211_tx_data *tx) |
331 | { | 331 | { |
332 | int i; | 332 | struct sk_buff *skb; |
333 | 333 | ||
334 | ieee80211_tx_set_protected(tx); | 334 | ieee80211_tx_set_protected(tx); |
335 | 335 | ||
336 | if (wep_encrypt_skb(tx, tx->skb) < 0) { | 336 | skb = tx->skb; |
337 | I802_DEBUG_INC(tx->local->tx_handlers_drop_wep); | 337 | do { |
338 | return TX_DROP; | 338 | if (wep_encrypt_skb(tx, skb) < 0) { |
339 | } | 339 | I802_DEBUG_INC(tx->local->tx_handlers_drop_wep); |
340 | 340 | return TX_DROP; | |
341 | if (tx->extra_frag) { | ||
342 | for (i = 0; i < tx->num_extra_frag; i++) { | ||
343 | if (wep_encrypt_skb(tx, tx->extra_frag[i])) { | ||
344 | I802_DEBUG_INC(tx->local-> | ||
345 | tx_handlers_drop_wep); | ||
346 | return TX_DROP; | ||
347 | } | ||
348 | } | 341 | } |
349 | } | 342 | } while ((skb = skb->next)); |
350 | 343 | ||
351 | return TX_CONTINUE; | 344 | return TX_CONTINUE; |
352 | } | 345 | } |
diff --git a/net/mac80211/wext.c b/net/mac80211/wext.c index 935c63ed3dfa..deb4ecec122a 100644 --- a/net/mac80211/wext.c +++ b/net/mac80211/wext.c | |||
@@ -129,14 +129,12 @@ static int ieee80211_ioctl_siwgenie(struct net_device *dev, | |||
129 | 129 | ||
130 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 130 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
131 | 131 | ||
132 | if (sdata->flags & IEEE80211_SDATA_USERSPACE_MLME) | ||
133 | return -EOPNOTSUPP; | ||
134 | |||
135 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { | 132 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { |
136 | int ret = ieee80211_sta_set_extra_ie(sdata, extra, data->length); | 133 | int ret = ieee80211_sta_set_extra_ie(sdata, extra, data->length); |
137 | if (ret) | 134 | if (ret) |
138 | return ret; | 135 | return ret; |
139 | sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_BSSID_SEL; | 136 | sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_BSSID_SEL; |
137 | sdata->u.mgd.flags &= ~IEEE80211_STA_EXT_SME; | ||
140 | ieee80211_sta_req_auth(sdata); | 138 | ieee80211_sta_req_auth(sdata); |
141 | return 0; | 139 | return 0; |
142 | } | 140 | } |
@@ -207,14 +205,6 @@ static int ieee80211_ioctl_siwessid(struct net_device *dev, | |||
207 | 205 | ||
208 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 206 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
209 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { | 207 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { |
210 | if (sdata->flags & IEEE80211_SDATA_USERSPACE_MLME) { | ||
211 | if (len > IEEE80211_MAX_SSID_LEN) | ||
212 | return -EINVAL; | ||
213 | memcpy(sdata->u.mgd.ssid, ssid, len); | ||
214 | sdata->u.mgd.ssid_len = len; | ||
215 | return 0; | ||
216 | } | ||
217 | |||
218 | if (data->flags) | 208 | if (data->flags) |
219 | sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_SSID_SEL; | 209 | sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_SSID_SEL; |
220 | else | 210 | else |
@@ -224,6 +214,7 @@ static int ieee80211_ioctl_siwessid(struct net_device *dev, | |||
224 | if (ret) | 214 | if (ret) |
225 | return ret; | 215 | return ret; |
226 | 216 | ||
217 | sdata->u.mgd.flags &= ~IEEE80211_STA_EXT_SME; | ||
227 | ieee80211_sta_req_auth(sdata); | 218 | ieee80211_sta_req_auth(sdata); |
228 | return 0; | 219 | return 0; |
229 | } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) | 220 | } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) |
@@ -272,11 +263,7 @@ static int ieee80211_ioctl_siwap(struct net_device *dev, | |||
272 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 263 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
273 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { | 264 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { |
274 | int ret; | 265 | int ret; |
275 | if (sdata->flags & IEEE80211_SDATA_USERSPACE_MLME) { | 266 | |
276 | memcpy(sdata->u.mgd.bssid, (u8 *) &ap_addr->sa_data, | ||
277 | ETH_ALEN); | ||
278 | return 0; | ||
279 | } | ||
280 | if (is_zero_ether_addr((u8 *) &ap_addr->sa_data)) | 267 | if (is_zero_ether_addr((u8 *) &ap_addr->sa_data)) |
281 | sdata->u.mgd.flags |= IEEE80211_STA_AUTO_BSSID_SEL | | 268 | sdata->u.mgd.flags |= IEEE80211_STA_AUTO_BSSID_SEL | |
282 | IEEE80211_STA_AUTO_CHANNEL_SEL; | 269 | IEEE80211_STA_AUTO_CHANNEL_SEL; |
@@ -287,6 +274,7 @@ static int ieee80211_ioctl_siwap(struct net_device *dev, | |||
287 | ret = ieee80211_sta_set_bssid(sdata, (u8 *) &ap_addr->sa_data); | 274 | ret = ieee80211_sta_set_bssid(sdata, (u8 *) &ap_addr->sa_data); |
288 | if (ret) | 275 | if (ret) |
289 | return ret; | 276 | return ret; |
277 | sdata->u.mgd.flags &= ~IEEE80211_STA_EXT_SME; | ||
290 | ieee80211_sta_req_auth(sdata); | 278 | ieee80211_sta_req_auth(sdata); |
291 | return 0; | 279 | return 0; |
292 | } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { | 280 | } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { |
@@ -630,7 +618,7 @@ static int ieee80211_ioctl_siwencode(struct net_device *dev, | |||
630 | struct ieee80211_sub_if_data *sdata; | 618 | struct ieee80211_sub_if_data *sdata; |
631 | int idx, i, alg = ALG_WEP; | 619 | int idx, i, alg = ALG_WEP; |
632 | u8 bcaddr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; | 620 | u8 bcaddr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; |
633 | int remove = 0; | 621 | int remove = 0, ret; |
634 | 622 | ||
635 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 623 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
636 | 624 | ||
@@ -656,11 +644,20 @@ static int ieee80211_ioctl_siwencode(struct net_device *dev, | |||
656 | return 0; | 644 | return 0; |
657 | } | 645 | } |
658 | 646 | ||
659 | return ieee80211_set_encryption( | 647 | ret = ieee80211_set_encryption( |
660 | sdata, bcaddr, | 648 | sdata, bcaddr, |
661 | idx, alg, remove, | 649 | idx, alg, remove, |
662 | !sdata->default_key, | 650 | !sdata->default_key, |
663 | keybuf, erq->length); | 651 | keybuf, erq->length); |
652 | |||
653 | if (!ret) { | ||
654 | if (remove) | ||
655 | sdata->u.mgd.flags &= ~IEEE80211_STA_TKIP_WEP_USED; | ||
656 | else | ||
657 | sdata->u.mgd.flags |= IEEE80211_STA_TKIP_WEP_USED; | ||
658 | } | ||
659 | |||
660 | return ret; | ||
664 | } | 661 | } |
665 | 662 | ||
666 | 663 | ||
diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index 9101b48ec2ae..4f8bfea278f2 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c | |||
@@ -196,19 +196,13 @@ ieee80211_tx_result | |||
196 | ieee80211_crypto_tkip_encrypt(struct ieee80211_tx_data *tx) | 196 | ieee80211_crypto_tkip_encrypt(struct ieee80211_tx_data *tx) |
197 | { | 197 | { |
198 | struct sk_buff *skb = tx->skb; | 198 | struct sk_buff *skb = tx->skb; |
199 | int i; | ||
200 | 199 | ||
201 | ieee80211_tx_set_protected(tx); | 200 | ieee80211_tx_set_protected(tx); |
202 | 201 | ||
203 | if (tkip_encrypt_skb(tx, skb) < 0) | 202 | do { |
204 | return TX_DROP; | 203 | if (tkip_encrypt_skb(tx, skb) < 0) |
205 | 204 | return TX_DROP; | |
206 | if (tx->extra_frag) { | 205 | } while ((skb = skb->next)); |
207 | for (i = 0; i < tx->num_extra_frag; i++) { | ||
208 | if (tkip_encrypt_skb(tx, tx->extra_frag[i])) | ||
209 | return TX_DROP; | ||
210 | } | ||
211 | } | ||
212 | 206 | ||
213 | return TX_CONTINUE; | 207 | return TX_CONTINUE; |
214 | } | 208 | } |
@@ -428,19 +422,13 @@ ieee80211_tx_result | |||
428 | ieee80211_crypto_ccmp_encrypt(struct ieee80211_tx_data *tx) | 422 | ieee80211_crypto_ccmp_encrypt(struct ieee80211_tx_data *tx) |
429 | { | 423 | { |
430 | struct sk_buff *skb = tx->skb; | 424 | struct sk_buff *skb = tx->skb; |
431 | int i; | ||
432 | 425 | ||
433 | ieee80211_tx_set_protected(tx); | 426 | ieee80211_tx_set_protected(tx); |
434 | 427 | ||
435 | if (ccmp_encrypt_skb(tx, skb) < 0) | 428 | do { |
436 | return TX_DROP; | 429 | if (ccmp_encrypt_skb(tx, skb) < 0) |
437 | 430 | return TX_DROP; | |
438 | if (tx->extra_frag) { | 431 | } while ((skb = skb->next)); |
439 | for (i = 0; i < tx->num_extra_frag; i++) { | ||
440 | if (ccmp_encrypt_skb(tx, tx->extra_frag[i])) | ||
441 | return TX_DROP; | ||
442 | } | ||
443 | } | ||
444 | 432 | ||
445 | return TX_CONTINUE; | 433 | return TX_CONTINUE; |
446 | } | 434 | } |
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index 2562d05dbaf5..2c967e4f706c 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig | |||
@@ -374,7 +374,7 @@ config NETFILTER_XT_TARGET_HL | |||
374 | 374 | ||
375 | config NETFILTER_XT_TARGET_LED | 375 | config NETFILTER_XT_TARGET_LED |
376 | tristate '"LED" target support' | 376 | tristate '"LED" target support' |
377 | depends on LEDS_CLASS | 377 | depends on LEDS_CLASS && LED_TRIGGERS |
378 | depends on NETFILTER_ADVANCED | 378 | depends on NETFILTER_ADVANCED |
379 | help | 379 | help |
380 | This option adds a `LED' target, which allows you to blink LEDs in | 380 | This option adds a `LED' target, which allows you to blink LEDs in |
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index dfb447b584da..8020db6274b8 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <linux/netdevice.h> | 29 | #include <linux/netdevice.h> |
30 | #include <linux/socket.h> | 30 | #include <linux/socket.h> |
31 | #include <linux/mm.h> | 31 | #include <linux/mm.h> |
32 | #include <linux/rculist_nulls.h> | ||
32 | 33 | ||
33 | #include <net/netfilter/nf_conntrack.h> | 34 | #include <net/netfilter/nf_conntrack.h> |
34 | #include <net/netfilter/nf_conntrack_l3proto.h> | 35 | #include <net/netfilter/nf_conntrack_l3proto.h> |
@@ -163,8 +164,8 @@ static void | |||
163 | clean_from_lists(struct nf_conn *ct) | 164 | clean_from_lists(struct nf_conn *ct) |
164 | { | 165 | { |
165 | pr_debug("clean_from_lists(%p)\n", ct); | 166 | pr_debug("clean_from_lists(%p)\n", ct); |
166 | hlist_del_rcu(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnode); | 167 | hlist_nulls_del_rcu(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode); |
167 | hlist_del_rcu(&ct->tuplehash[IP_CT_DIR_REPLY].hnode); | 168 | hlist_nulls_del_rcu(&ct->tuplehash[IP_CT_DIR_REPLY].hnnode); |
168 | 169 | ||
169 | /* Destroy all pending expectations */ | 170 | /* Destroy all pending expectations */ |
170 | nf_ct_remove_expectations(ct); | 171 | nf_ct_remove_expectations(ct); |
@@ -204,8 +205,8 @@ destroy_conntrack(struct nf_conntrack *nfct) | |||
204 | 205 | ||
205 | /* We overload first tuple to link into unconfirmed list. */ | 206 | /* We overload first tuple to link into unconfirmed list. */ |
206 | if (!nf_ct_is_confirmed(ct)) { | 207 | if (!nf_ct_is_confirmed(ct)) { |
207 | BUG_ON(hlist_unhashed(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnode)); | 208 | BUG_ON(hlist_nulls_unhashed(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode)); |
208 | hlist_del(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnode); | 209 | hlist_nulls_del_rcu(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode); |
209 | } | 210 | } |
210 | 211 | ||
211 | NF_CT_STAT_INC(net, delete); | 212 | NF_CT_STAT_INC(net, delete); |
@@ -242,18 +243,26 @@ static void death_by_timeout(unsigned long ul_conntrack) | |||
242 | nf_ct_put(ct); | 243 | nf_ct_put(ct); |
243 | } | 244 | } |
244 | 245 | ||
246 | /* | ||
247 | * Warning : | ||
248 | * - Caller must take a reference on returned object | ||
249 | * and recheck nf_ct_tuple_equal(tuple, &h->tuple) | ||
250 | * OR | ||
251 | * - Caller must lock nf_conntrack_lock before calling this function | ||
252 | */ | ||
245 | struct nf_conntrack_tuple_hash * | 253 | struct nf_conntrack_tuple_hash * |
246 | __nf_conntrack_find(struct net *net, const struct nf_conntrack_tuple *tuple) | 254 | __nf_conntrack_find(struct net *net, const struct nf_conntrack_tuple *tuple) |
247 | { | 255 | { |
248 | struct nf_conntrack_tuple_hash *h; | 256 | struct nf_conntrack_tuple_hash *h; |
249 | struct hlist_node *n; | 257 | struct hlist_nulls_node *n; |
250 | unsigned int hash = hash_conntrack(tuple); | 258 | unsigned int hash = hash_conntrack(tuple); |
251 | 259 | ||
252 | /* Disable BHs the entire time since we normally need to disable them | 260 | /* Disable BHs the entire time since we normally need to disable them |
253 | * at least once for the stats anyway. | 261 | * at least once for the stats anyway. |
254 | */ | 262 | */ |
255 | local_bh_disable(); | 263 | local_bh_disable(); |
256 | hlist_for_each_entry_rcu(h, n, &net->ct.hash[hash], hnode) { | 264 | begin: |
265 | hlist_nulls_for_each_entry_rcu(h, n, &net->ct.hash[hash], hnnode) { | ||
257 | if (nf_ct_tuple_equal(tuple, &h->tuple)) { | 266 | if (nf_ct_tuple_equal(tuple, &h->tuple)) { |
258 | NF_CT_STAT_INC(net, found); | 267 | NF_CT_STAT_INC(net, found); |
259 | local_bh_enable(); | 268 | local_bh_enable(); |
@@ -261,6 +270,13 @@ __nf_conntrack_find(struct net *net, const struct nf_conntrack_tuple *tuple) | |||
261 | } | 270 | } |
262 | NF_CT_STAT_INC(net, searched); | 271 | NF_CT_STAT_INC(net, searched); |
263 | } | 272 | } |
273 | /* | ||
274 | * if the nulls value we got at the end of this lookup is | ||
275 | * not the expected one, we must restart lookup. | ||
276 | * We probably met an item that was moved to another chain. | ||
277 | */ | ||
278 | if (get_nulls_value(n) != hash) | ||
279 | goto begin; | ||
264 | local_bh_enable(); | 280 | local_bh_enable(); |
265 | 281 | ||
266 | return NULL; | 282 | return NULL; |
@@ -275,11 +291,18 @@ nf_conntrack_find_get(struct net *net, const struct nf_conntrack_tuple *tuple) | |||
275 | struct nf_conn *ct; | 291 | struct nf_conn *ct; |
276 | 292 | ||
277 | rcu_read_lock(); | 293 | rcu_read_lock(); |
294 | begin: | ||
278 | h = __nf_conntrack_find(net, tuple); | 295 | h = __nf_conntrack_find(net, tuple); |
279 | if (h) { | 296 | if (h) { |
280 | ct = nf_ct_tuplehash_to_ctrack(h); | 297 | ct = nf_ct_tuplehash_to_ctrack(h); |
281 | if (unlikely(!atomic_inc_not_zero(&ct->ct_general.use))) | 298 | if (unlikely(!atomic_inc_not_zero(&ct->ct_general.use))) |
282 | h = NULL; | 299 | h = NULL; |
300 | else { | ||
301 | if (unlikely(!nf_ct_tuple_equal(tuple, &h->tuple))) { | ||
302 | nf_ct_put(ct); | ||
303 | goto begin; | ||
304 | } | ||
305 | } | ||
283 | } | 306 | } |
284 | rcu_read_unlock(); | 307 | rcu_read_unlock(); |
285 | 308 | ||
@@ -293,9 +316,9 @@ static void __nf_conntrack_hash_insert(struct nf_conn *ct, | |||
293 | { | 316 | { |
294 | struct net *net = nf_ct_net(ct); | 317 | struct net *net = nf_ct_net(ct); |
295 | 318 | ||
296 | hlist_add_head_rcu(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnode, | 319 | hlist_nulls_add_head_rcu(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode, |
297 | &net->ct.hash[hash]); | 320 | &net->ct.hash[hash]); |
298 | hlist_add_head_rcu(&ct->tuplehash[IP_CT_DIR_REPLY].hnode, | 321 | hlist_nulls_add_head_rcu(&ct->tuplehash[IP_CT_DIR_REPLY].hnnode, |
299 | &net->ct.hash[repl_hash]); | 322 | &net->ct.hash[repl_hash]); |
300 | } | 323 | } |
301 | 324 | ||
@@ -318,7 +341,7 @@ __nf_conntrack_confirm(struct sk_buff *skb) | |||
318 | struct nf_conntrack_tuple_hash *h; | 341 | struct nf_conntrack_tuple_hash *h; |
319 | struct nf_conn *ct; | 342 | struct nf_conn *ct; |
320 | struct nf_conn_help *help; | 343 | struct nf_conn_help *help; |
321 | struct hlist_node *n; | 344 | struct hlist_nulls_node *n; |
322 | enum ip_conntrack_info ctinfo; | 345 | enum ip_conntrack_info ctinfo; |
323 | struct net *net; | 346 | struct net *net; |
324 | 347 | ||
@@ -350,17 +373,17 @@ __nf_conntrack_confirm(struct sk_buff *skb) | |||
350 | /* See if there's one in the list already, including reverse: | 373 | /* See if there's one in the list already, including reverse: |
351 | NAT could have grabbed it without realizing, since we're | 374 | NAT could have grabbed it without realizing, since we're |
352 | not in the hash. If there is, we lost race. */ | 375 | not in the hash. If there is, we lost race. */ |
353 | hlist_for_each_entry(h, n, &net->ct.hash[hash], hnode) | 376 | hlist_nulls_for_each_entry(h, n, &net->ct.hash[hash], hnnode) |
354 | if (nf_ct_tuple_equal(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple, | 377 | if (nf_ct_tuple_equal(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple, |
355 | &h->tuple)) | 378 | &h->tuple)) |
356 | goto out; | 379 | goto out; |
357 | hlist_for_each_entry(h, n, &net->ct.hash[repl_hash], hnode) | 380 | hlist_nulls_for_each_entry(h, n, &net->ct.hash[repl_hash], hnnode) |
358 | if (nf_ct_tuple_equal(&ct->tuplehash[IP_CT_DIR_REPLY].tuple, | 381 | if (nf_ct_tuple_equal(&ct->tuplehash[IP_CT_DIR_REPLY].tuple, |
359 | &h->tuple)) | 382 | &h->tuple)) |
360 | goto out; | 383 | goto out; |
361 | 384 | ||
362 | /* Remove from unconfirmed list */ | 385 | /* Remove from unconfirmed list */ |
363 | hlist_del(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnode); | 386 | hlist_nulls_del_rcu(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode); |
364 | 387 | ||
365 | __nf_conntrack_hash_insert(ct, hash, repl_hash); | 388 | __nf_conntrack_hash_insert(ct, hash, repl_hash); |
366 | /* Timer relative to confirmation time, not original | 389 | /* Timer relative to confirmation time, not original |
@@ -399,14 +422,14 @@ nf_conntrack_tuple_taken(const struct nf_conntrack_tuple *tuple, | |||
399 | { | 422 | { |
400 | struct net *net = nf_ct_net(ignored_conntrack); | 423 | struct net *net = nf_ct_net(ignored_conntrack); |
401 | struct nf_conntrack_tuple_hash *h; | 424 | struct nf_conntrack_tuple_hash *h; |
402 | struct hlist_node *n; | 425 | struct hlist_nulls_node *n; |
403 | unsigned int hash = hash_conntrack(tuple); | 426 | unsigned int hash = hash_conntrack(tuple); |
404 | 427 | ||
405 | /* Disable BHs the entire time since we need to disable them at | 428 | /* Disable BHs the entire time since we need to disable them at |
406 | * least once for the stats anyway. | 429 | * least once for the stats anyway. |
407 | */ | 430 | */ |
408 | rcu_read_lock_bh(); | 431 | rcu_read_lock_bh(); |
409 | hlist_for_each_entry_rcu(h, n, &net->ct.hash[hash], hnode) { | 432 | hlist_nulls_for_each_entry_rcu(h, n, &net->ct.hash[hash], hnnode) { |
410 | if (nf_ct_tuplehash_to_ctrack(h) != ignored_conntrack && | 433 | if (nf_ct_tuplehash_to_ctrack(h) != ignored_conntrack && |
411 | nf_ct_tuple_equal(tuple, &h->tuple)) { | 434 | nf_ct_tuple_equal(tuple, &h->tuple)) { |
412 | NF_CT_STAT_INC(net, found); | 435 | NF_CT_STAT_INC(net, found); |
@@ -430,14 +453,14 @@ static noinline int early_drop(struct net *net, unsigned int hash) | |||
430 | /* Use oldest entry, which is roughly LRU */ | 453 | /* Use oldest entry, which is roughly LRU */ |
431 | struct nf_conntrack_tuple_hash *h; | 454 | struct nf_conntrack_tuple_hash *h; |
432 | struct nf_conn *ct = NULL, *tmp; | 455 | struct nf_conn *ct = NULL, *tmp; |
433 | struct hlist_node *n; | 456 | struct hlist_nulls_node *n; |
434 | unsigned int i, cnt = 0; | 457 | unsigned int i, cnt = 0; |
435 | int dropped = 0; | 458 | int dropped = 0; |
436 | 459 | ||
437 | rcu_read_lock(); | 460 | rcu_read_lock(); |
438 | for (i = 0; i < nf_conntrack_htable_size; i++) { | 461 | for (i = 0; i < nf_conntrack_htable_size; i++) { |
439 | hlist_for_each_entry_rcu(h, n, &net->ct.hash[hash], | 462 | hlist_nulls_for_each_entry_rcu(h, n, &net->ct.hash[hash], |
440 | hnode) { | 463 | hnnode) { |
441 | tmp = nf_ct_tuplehash_to_ctrack(h); | 464 | tmp = nf_ct_tuplehash_to_ctrack(h); |
442 | if (!test_bit(IPS_ASSURED_BIT, &tmp->status)) | 465 | if (!test_bit(IPS_ASSURED_BIT, &tmp->status)) |
443 | ct = tmp; | 466 | ct = tmp; |
@@ -508,27 +531,19 @@ struct nf_conn *nf_conntrack_alloc(struct net *net, | |||
508 | #ifdef CONFIG_NET_NS | 531 | #ifdef CONFIG_NET_NS |
509 | ct->ct_net = net; | 532 | ct->ct_net = net; |
510 | #endif | 533 | #endif |
511 | INIT_RCU_HEAD(&ct->rcu); | ||
512 | 534 | ||
513 | return ct; | 535 | return ct; |
514 | } | 536 | } |
515 | EXPORT_SYMBOL_GPL(nf_conntrack_alloc); | 537 | EXPORT_SYMBOL_GPL(nf_conntrack_alloc); |
516 | 538 | ||
517 | static void nf_conntrack_free_rcu(struct rcu_head *head) | ||
518 | { | ||
519 | struct nf_conn *ct = container_of(head, struct nf_conn, rcu); | ||
520 | |||
521 | nf_ct_ext_free(ct); | ||
522 | kmem_cache_free(nf_conntrack_cachep, ct); | ||
523 | } | ||
524 | |||
525 | void nf_conntrack_free(struct nf_conn *ct) | 539 | void nf_conntrack_free(struct nf_conn *ct) |
526 | { | 540 | { |
527 | struct net *net = nf_ct_net(ct); | 541 | struct net *net = nf_ct_net(ct); |
528 | 542 | ||
529 | nf_ct_ext_destroy(ct); | 543 | nf_ct_ext_destroy(ct); |
530 | atomic_dec(&net->ct.count); | 544 | atomic_dec(&net->ct.count); |
531 | call_rcu(&ct->rcu, nf_conntrack_free_rcu); | 545 | nf_ct_ext_free(ct); |
546 | kmem_cache_free(nf_conntrack_cachep, ct); | ||
532 | } | 547 | } |
533 | EXPORT_SYMBOL_GPL(nf_conntrack_free); | 548 | EXPORT_SYMBOL_GPL(nf_conntrack_free); |
534 | 549 | ||
@@ -594,7 +609,7 @@ init_conntrack(struct net *net, | |||
594 | } | 609 | } |
595 | 610 | ||
596 | /* Overload tuple linked list to put us in unconfirmed list. */ | 611 | /* Overload tuple linked list to put us in unconfirmed list. */ |
597 | hlist_add_head(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnode, | 612 | hlist_nulls_add_head_rcu(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode, |
598 | &net->ct.unconfirmed); | 613 | &net->ct.unconfirmed); |
599 | 614 | ||
600 | spin_unlock_bh(&nf_conntrack_lock); | 615 | spin_unlock_bh(&nf_conntrack_lock); |
@@ -906,6 +921,12 @@ int nf_ct_port_nlattr_to_tuple(struct nlattr *tb[], | |||
906 | return 0; | 921 | return 0; |
907 | } | 922 | } |
908 | EXPORT_SYMBOL_GPL(nf_ct_port_nlattr_to_tuple); | 923 | EXPORT_SYMBOL_GPL(nf_ct_port_nlattr_to_tuple); |
924 | |||
925 | int nf_ct_port_nlattr_tuple_size(void) | ||
926 | { | ||
927 | return nla_policy_len(nf_ct_port_nla_policy, CTA_PROTO_MAX + 1); | ||
928 | } | ||
929 | EXPORT_SYMBOL_GPL(nf_ct_port_nlattr_tuple_size); | ||
909 | #endif | 930 | #endif |
910 | 931 | ||
911 | /* Used by ipt_REJECT and ip6t_REJECT. */ | 932 | /* Used by ipt_REJECT and ip6t_REJECT. */ |
@@ -934,17 +955,17 @@ get_next_corpse(struct net *net, int (*iter)(struct nf_conn *i, void *data), | |||
934 | { | 955 | { |
935 | struct nf_conntrack_tuple_hash *h; | 956 | struct nf_conntrack_tuple_hash *h; |
936 | struct nf_conn *ct; | 957 | struct nf_conn *ct; |
937 | struct hlist_node *n; | 958 | struct hlist_nulls_node *n; |
938 | 959 | ||
939 | spin_lock_bh(&nf_conntrack_lock); | 960 | spin_lock_bh(&nf_conntrack_lock); |
940 | for (; *bucket < nf_conntrack_htable_size; (*bucket)++) { | 961 | for (; *bucket < nf_conntrack_htable_size; (*bucket)++) { |
941 | hlist_for_each_entry(h, n, &net->ct.hash[*bucket], hnode) { | 962 | hlist_nulls_for_each_entry(h, n, &net->ct.hash[*bucket], hnnode) { |
942 | ct = nf_ct_tuplehash_to_ctrack(h); | 963 | ct = nf_ct_tuplehash_to_ctrack(h); |
943 | if (iter(ct, data)) | 964 | if (iter(ct, data)) |
944 | goto found; | 965 | goto found; |
945 | } | 966 | } |
946 | } | 967 | } |
947 | hlist_for_each_entry(h, n, &net->ct.unconfirmed, hnode) { | 968 | hlist_nulls_for_each_entry(h, n, &net->ct.unconfirmed, hnnode) { |
948 | ct = nf_ct_tuplehash_to_ctrack(h); | 969 | ct = nf_ct_tuplehash_to_ctrack(h); |
949 | if (iter(ct, data)) | 970 | if (iter(ct, data)) |
950 | set_bit(IPS_DYING_BIT, &ct->status); | 971 | set_bit(IPS_DYING_BIT, &ct->status); |
@@ -992,7 +1013,7 @@ static int kill_all(struct nf_conn *i, void *data) | |||
992 | return 1; | 1013 | return 1; |
993 | } | 1014 | } |
994 | 1015 | ||
995 | void nf_ct_free_hashtable(struct hlist_head *hash, int vmalloced, unsigned int size) | 1016 | void nf_ct_free_hashtable(void *hash, int vmalloced, unsigned int size) |
996 | { | 1017 | { |
997 | if (vmalloced) | 1018 | if (vmalloced) |
998 | vfree(hash); | 1019 | vfree(hash); |
@@ -1060,26 +1081,28 @@ void nf_conntrack_cleanup(struct net *net) | |||
1060 | } | 1081 | } |
1061 | } | 1082 | } |
1062 | 1083 | ||
1063 | struct hlist_head *nf_ct_alloc_hashtable(unsigned int *sizep, int *vmalloced) | 1084 | void *nf_ct_alloc_hashtable(unsigned int *sizep, int *vmalloced, int nulls) |
1064 | { | 1085 | { |
1065 | struct hlist_head *hash; | 1086 | struct hlist_nulls_head *hash; |
1066 | unsigned int size, i; | 1087 | unsigned int nr_slots, i; |
1088 | size_t sz; | ||
1067 | 1089 | ||
1068 | *vmalloced = 0; | 1090 | *vmalloced = 0; |
1069 | 1091 | ||
1070 | size = *sizep = roundup(*sizep, PAGE_SIZE / sizeof(struct hlist_head)); | 1092 | BUILD_BUG_ON(sizeof(struct hlist_nulls_head) != sizeof(struct hlist_head)); |
1071 | hash = (void*)__get_free_pages(GFP_KERNEL|__GFP_NOWARN, | 1093 | nr_slots = *sizep = roundup(*sizep, PAGE_SIZE / sizeof(struct hlist_nulls_head)); |
1072 | get_order(sizeof(struct hlist_head) | 1094 | sz = nr_slots * sizeof(struct hlist_nulls_head); |
1073 | * size)); | 1095 | hash = (void *)__get_free_pages(GFP_KERNEL | __GFP_NOWARN | __GFP_ZERO, |
1096 | get_order(sz)); | ||
1074 | if (!hash) { | 1097 | if (!hash) { |
1075 | *vmalloced = 1; | 1098 | *vmalloced = 1; |
1076 | printk(KERN_WARNING "nf_conntrack: falling back to vmalloc.\n"); | 1099 | printk(KERN_WARNING "nf_conntrack: falling back to vmalloc.\n"); |
1077 | hash = vmalloc(sizeof(struct hlist_head) * size); | 1100 | hash = __vmalloc(sz, GFP_KERNEL | __GFP_ZERO, PAGE_KERNEL); |
1078 | } | 1101 | } |
1079 | 1102 | ||
1080 | if (hash) | 1103 | if (hash && nulls) |
1081 | for (i = 0; i < size; i++) | 1104 | for (i = 0; i < nr_slots; i++) |
1082 | INIT_HLIST_HEAD(&hash[i]); | 1105 | INIT_HLIST_NULLS_HEAD(&hash[i], i); |
1083 | 1106 | ||
1084 | return hash; | 1107 | return hash; |
1085 | } | 1108 | } |
@@ -1090,7 +1113,7 @@ int nf_conntrack_set_hashsize(const char *val, struct kernel_param *kp) | |||
1090 | int i, bucket, vmalloced, old_vmalloced; | 1113 | int i, bucket, vmalloced, old_vmalloced; |
1091 | unsigned int hashsize, old_size; | 1114 | unsigned int hashsize, old_size; |
1092 | int rnd; | 1115 | int rnd; |
1093 | struct hlist_head *hash, *old_hash; | 1116 | struct hlist_nulls_head *hash, *old_hash; |
1094 | struct nf_conntrack_tuple_hash *h; | 1117 | struct nf_conntrack_tuple_hash *h; |
1095 | 1118 | ||
1096 | /* On boot, we can set this without any fancy locking. */ | 1119 | /* On boot, we can set this without any fancy locking. */ |
@@ -1101,7 +1124,7 @@ int nf_conntrack_set_hashsize(const char *val, struct kernel_param *kp) | |||
1101 | if (!hashsize) | 1124 | if (!hashsize) |
1102 | return -EINVAL; | 1125 | return -EINVAL; |
1103 | 1126 | ||
1104 | hash = nf_ct_alloc_hashtable(&hashsize, &vmalloced); | 1127 | hash = nf_ct_alloc_hashtable(&hashsize, &vmalloced, 1); |
1105 | if (!hash) | 1128 | if (!hash) |
1106 | return -ENOMEM; | 1129 | return -ENOMEM; |
1107 | 1130 | ||
@@ -1116,12 +1139,12 @@ int nf_conntrack_set_hashsize(const char *val, struct kernel_param *kp) | |||
1116 | */ | 1139 | */ |
1117 | spin_lock_bh(&nf_conntrack_lock); | 1140 | spin_lock_bh(&nf_conntrack_lock); |
1118 | for (i = 0; i < nf_conntrack_htable_size; i++) { | 1141 | for (i = 0; i < nf_conntrack_htable_size; i++) { |
1119 | while (!hlist_empty(&init_net.ct.hash[i])) { | 1142 | while (!hlist_nulls_empty(&init_net.ct.hash[i])) { |
1120 | h = hlist_entry(init_net.ct.hash[i].first, | 1143 | h = hlist_nulls_entry(init_net.ct.hash[i].first, |
1121 | struct nf_conntrack_tuple_hash, hnode); | 1144 | struct nf_conntrack_tuple_hash, hnnode); |
1122 | hlist_del_rcu(&h->hnode); | 1145 | hlist_nulls_del_rcu(&h->hnnode); |
1123 | bucket = __hash_conntrack(&h->tuple, hashsize, rnd); | 1146 | bucket = __hash_conntrack(&h->tuple, hashsize, rnd); |
1124 | hlist_add_head(&h->hnode, &hash[bucket]); | 1147 | hlist_nulls_add_head_rcu(&h->hnnode, &hash[bucket]); |
1125 | } | 1148 | } |
1126 | } | 1149 | } |
1127 | old_size = nf_conntrack_htable_size; | 1150 | old_size = nf_conntrack_htable_size; |
@@ -1172,7 +1195,7 @@ static int nf_conntrack_init_init_net(void) | |||
1172 | 1195 | ||
1173 | nf_conntrack_cachep = kmem_cache_create("nf_conntrack", | 1196 | nf_conntrack_cachep = kmem_cache_create("nf_conntrack", |
1174 | sizeof(struct nf_conn), | 1197 | sizeof(struct nf_conn), |
1175 | 0, 0, NULL); | 1198 | 0, SLAB_DESTROY_BY_RCU, NULL); |
1176 | if (!nf_conntrack_cachep) { | 1199 | if (!nf_conntrack_cachep) { |
1177 | printk(KERN_ERR "Unable to create nf_conn slab cache\n"); | 1200 | printk(KERN_ERR "Unable to create nf_conn slab cache\n"); |
1178 | ret = -ENOMEM; | 1201 | ret = -ENOMEM; |
@@ -1202,7 +1225,7 @@ static int nf_conntrack_init_net(struct net *net) | |||
1202 | int ret; | 1225 | int ret; |
1203 | 1226 | ||
1204 | atomic_set(&net->ct.count, 0); | 1227 | atomic_set(&net->ct.count, 0); |
1205 | INIT_HLIST_HEAD(&net->ct.unconfirmed); | 1228 | INIT_HLIST_NULLS_HEAD(&net->ct.unconfirmed, 0); |
1206 | net->ct.stat = alloc_percpu(struct ip_conntrack_stat); | 1229 | net->ct.stat = alloc_percpu(struct ip_conntrack_stat); |
1207 | if (!net->ct.stat) { | 1230 | if (!net->ct.stat) { |
1208 | ret = -ENOMEM; | 1231 | ret = -ENOMEM; |
@@ -1212,7 +1235,7 @@ static int nf_conntrack_init_net(struct net *net) | |||
1212 | if (ret < 0) | 1235 | if (ret < 0) |
1213 | goto err_ecache; | 1236 | goto err_ecache; |
1214 | net->ct.hash = nf_ct_alloc_hashtable(&nf_conntrack_htable_size, | 1237 | net->ct.hash = nf_ct_alloc_hashtable(&nf_conntrack_htable_size, |
1215 | &net->ct.hash_vmalloc); | 1238 | &net->ct.hash_vmalloc, 1); |
1216 | if (!net->ct.hash) { | 1239 | if (!net->ct.hash) { |
1217 | ret = -ENOMEM; | 1240 | ret = -ENOMEM; |
1218 | printk(KERN_ERR "Unable to create nf_conntrack_hash\n"); | 1241 | printk(KERN_ERR "Unable to create nf_conntrack_hash\n"); |
diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c index 357ba39d4c8d..3940f996a2e4 100644 --- a/net/netfilter/nf_conntrack_expect.c +++ b/net/netfilter/nf_conntrack_expect.c | |||
@@ -604,7 +604,7 @@ int nf_conntrack_expect_init(struct net *net) | |||
604 | 604 | ||
605 | net->ct.expect_count = 0; | 605 | net->ct.expect_count = 0; |
606 | net->ct.expect_hash = nf_ct_alloc_hashtable(&nf_ct_expect_hsize, | 606 | net->ct.expect_hash = nf_ct_alloc_hashtable(&nf_ct_expect_hsize, |
607 | &net->ct.expect_vmalloc); | 607 | &net->ct.expect_vmalloc, 0); |
608 | if (net->ct.expect_hash == NULL) | 608 | if (net->ct.expect_hash == NULL) |
609 | goto err1; | 609 | goto err1; |
610 | 610 | ||
diff --git a/net/netfilter/nf_conntrack_helper.c b/net/netfilter/nf_conntrack_helper.c index a51bdac9f3a0..30b8e9009f99 100644 --- a/net/netfilter/nf_conntrack_helper.c +++ b/net/netfilter/nf_conntrack_helper.c | |||
@@ -142,6 +142,7 @@ int nf_conntrack_helper_register(struct nf_conntrack_helper *me) | |||
142 | 142 | ||
143 | BUG_ON(me->expect_policy == NULL); | 143 | BUG_ON(me->expect_policy == NULL); |
144 | BUG_ON(me->expect_class_max >= NF_CT_MAX_EXPECT_CLASSES); | 144 | BUG_ON(me->expect_class_max >= NF_CT_MAX_EXPECT_CLASSES); |
145 | BUG_ON(strlen(me->name) > NF_CT_HELPER_NAME_LEN - 1); | ||
145 | 146 | ||
146 | mutex_lock(&nf_ct_helper_mutex); | 147 | mutex_lock(&nf_ct_helper_mutex); |
147 | hlist_add_head_rcu(&me->hnode, &nf_ct_helper_hash[h]); | 148 | hlist_add_head_rcu(&me->hnode, &nf_ct_helper_hash[h]); |
@@ -158,6 +159,7 @@ static void __nf_conntrack_helper_unregister(struct nf_conntrack_helper *me, | |||
158 | struct nf_conntrack_tuple_hash *h; | 159 | struct nf_conntrack_tuple_hash *h; |
159 | struct nf_conntrack_expect *exp; | 160 | struct nf_conntrack_expect *exp; |
160 | const struct hlist_node *n, *next; | 161 | const struct hlist_node *n, *next; |
162 | const struct hlist_nulls_node *nn; | ||
161 | unsigned int i; | 163 | unsigned int i; |
162 | 164 | ||
163 | /* Get rid of expectations */ | 165 | /* Get rid of expectations */ |
@@ -174,10 +176,10 @@ static void __nf_conntrack_helper_unregister(struct nf_conntrack_helper *me, | |||
174 | } | 176 | } |
175 | 177 | ||
176 | /* Get rid of expecteds, set helpers to NULL. */ | 178 | /* Get rid of expecteds, set helpers to NULL. */ |
177 | hlist_for_each_entry(h, n, &net->ct.unconfirmed, hnode) | 179 | hlist_for_each_entry(h, nn, &net->ct.unconfirmed, hnnode) |
178 | unhelp(h, me); | 180 | unhelp(h, me); |
179 | for (i = 0; i < nf_conntrack_htable_size; i++) { | 181 | for (i = 0; i < nf_conntrack_htable_size; i++) { |
180 | hlist_for_each_entry(h, n, &net->ct.hash[i], hnode) | 182 | hlist_nulls_for_each_entry(h, nn, &net->ct.hash[i], hnnode) |
181 | unhelp(h, me); | 183 | unhelp(h, me); |
182 | } | 184 | } |
183 | } | 185 | } |
@@ -217,7 +219,7 @@ int nf_conntrack_helper_init(void) | |||
217 | 219 | ||
218 | nf_ct_helper_hsize = 1; /* gets rounded up to use one page */ | 220 | nf_ct_helper_hsize = 1; /* gets rounded up to use one page */ |
219 | nf_ct_helper_hash = nf_ct_alloc_hashtable(&nf_ct_helper_hsize, | 221 | nf_ct_helper_hash = nf_ct_alloc_hashtable(&nf_ct_helper_hsize, |
220 | &nf_ct_helper_vmalloc); | 222 | &nf_ct_helper_vmalloc, 0); |
221 | if (!nf_ct_helper_hash) | 223 | if (!nf_ct_helper_hash) |
222 | return -ENOMEM; | 224 | return -ENOMEM; |
223 | 225 | ||
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 7a16bd462f82..c6439c77953c 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/module.h> | 19 | #include <linux/module.h> |
20 | #include <linux/kernel.h> | 20 | #include <linux/kernel.h> |
21 | #include <linux/rculist.h> | 21 | #include <linux/rculist.h> |
22 | #include <linux/rculist_nulls.h> | ||
22 | #include <linux/types.h> | 23 | #include <linux/types.h> |
23 | #include <linux/timer.h> | 24 | #include <linux/timer.h> |
24 | #include <linux/skbuff.h> | 25 | #include <linux/skbuff.h> |
@@ -404,6 +405,78 @@ nla_put_failure: | |||
404 | } | 405 | } |
405 | 406 | ||
406 | #ifdef CONFIG_NF_CONNTRACK_EVENTS | 407 | #ifdef CONFIG_NF_CONNTRACK_EVENTS |
408 | /* | ||
409 | * The general structure of a ctnetlink event is | ||
410 | * | ||
411 | * CTA_TUPLE_ORIG | ||
412 | * <l3/l4-proto-attributes> | ||
413 | * CTA_TUPLE_REPLY | ||
414 | * <l3/l4-proto-attributes> | ||
415 | * CTA_ID | ||
416 | * ... | ||
417 | * CTA_PROTOINFO | ||
418 | * <l4-proto-attributes> | ||
419 | * CTA_TUPLE_MASTER | ||
420 | * <l3/l4-proto-attributes> | ||
421 | * | ||
422 | * Therefore the formular is | ||
423 | * | ||
424 | * size = sizeof(headers) + sizeof(generic_nlas) + 3 * sizeof(tuple_nlas) | ||
425 | * + sizeof(protoinfo_nlas) | ||
426 | */ | ||
427 | static struct sk_buff * | ||
428 | ctnetlink_alloc_skb(const struct nf_conntrack_tuple *tuple, gfp_t gfp) | ||
429 | { | ||
430 | struct nf_conntrack_l3proto *l3proto; | ||
431 | struct nf_conntrack_l4proto *l4proto; | ||
432 | int len; | ||
433 | |||
434 | #define NLA_TYPE_SIZE(type) nla_total_size(sizeof(type)) | ||
435 | |||
436 | /* proto independant part */ | ||
437 | len = NLMSG_SPACE(sizeof(struct nfgenmsg)) | ||
438 | + 3 * nla_total_size(0) /* CTA_TUPLE_ORIG|REPL|MASTER */ | ||
439 | + 3 * nla_total_size(0) /* CTA_TUPLE_IP */ | ||
440 | + 3 * nla_total_size(0) /* CTA_TUPLE_PROTO */ | ||
441 | + 3 * NLA_TYPE_SIZE(u_int8_t) /* CTA_PROTO_NUM */ | ||
442 | + NLA_TYPE_SIZE(u_int32_t) /* CTA_ID */ | ||
443 | + NLA_TYPE_SIZE(u_int32_t) /* CTA_STATUS */ | ||
444 | #ifdef CONFIG_NF_CT_ACCT | ||
445 | + 2 * nla_total_size(0) /* CTA_COUNTERS_ORIG|REPL */ | ||
446 | + 2 * NLA_TYPE_SIZE(uint64_t) /* CTA_COUNTERS_PACKETS */ | ||
447 | + 2 * NLA_TYPE_SIZE(uint64_t) /* CTA_COUNTERS_BYTES */ | ||
448 | #endif | ||
449 | + NLA_TYPE_SIZE(u_int32_t) /* CTA_TIMEOUT */ | ||
450 | + nla_total_size(0) /* CTA_PROTOINFO */ | ||
451 | + nla_total_size(0) /* CTA_HELP */ | ||
452 | + nla_total_size(NF_CT_HELPER_NAME_LEN) /* CTA_HELP_NAME */ | ||
453 | #ifdef CONFIG_NF_CONNTRACK_SECMARK | ||
454 | + NLA_TYPE_SIZE(u_int32_t) /* CTA_SECMARK */ | ||
455 | #endif | ||
456 | #ifdef CONFIG_NF_NAT_NEEDED | ||
457 | + 2 * nla_total_size(0) /* CTA_NAT_SEQ_ADJ_ORIG|REPL */ | ||
458 | + 2 * NLA_TYPE_SIZE(u_int32_t) /* CTA_NAT_SEQ_CORRECTION_POS */ | ||
459 | + 2 * NLA_TYPE_SIZE(u_int32_t) /* CTA_NAT_SEQ_CORRECTION_BEFORE */ | ||
460 | + 2 * NLA_TYPE_SIZE(u_int32_t) /* CTA_NAT_SEQ_CORRECTION_AFTER */ | ||
461 | #endif | ||
462 | #ifdef CONFIG_NF_CONNTRACK_MARK | ||
463 | + NLA_TYPE_SIZE(u_int32_t) /* CTA_MARK */ | ||
464 | #endif | ||
465 | ; | ||
466 | |||
467 | #undef NLA_TYPE_SIZE | ||
468 | |||
469 | rcu_read_lock(); | ||
470 | l3proto = __nf_ct_l3proto_find(tuple->src.l3num); | ||
471 | len += l3proto->nla_size; | ||
472 | |||
473 | l4proto = __nf_ct_l4proto_find(tuple->src.l3num, tuple->dst.protonum); | ||
474 | len += l4proto->nla_size; | ||
475 | rcu_read_unlock(); | ||
476 | |||
477 | return alloc_skb(len, gfp); | ||
478 | } | ||
479 | |||
407 | static int ctnetlink_conntrack_event(struct notifier_block *this, | 480 | static int ctnetlink_conntrack_event(struct notifier_block *this, |
408 | unsigned long events, void *ptr) | 481 | unsigned long events, void *ptr) |
409 | { | 482 | { |
@@ -437,7 +510,7 @@ static int ctnetlink_conntrack_event(struct notifier_block *this, | |||
437 | if (!item->report && !nfnetlink_has_listeners(group)) | 510 | if (!item->report && !nfnetlink_has_listeners(group)) |
438 | return NOTIFY_DONE; | 511 | return NOTIFY_DONE; |
439 | 512 | ||
440 | skb = alloc_skb(NLMSG_GOODSIZE, GFP_ATOMIC); | 513 | skb = ctnetlink_alloc_skb(tuple(ct, IP_CT_DIR_ORIGINAL), GFP_ATOMIC); |
441 | if (!skb) | 514 | if (!skb) |
442 | return NOTIFY_DONE; | 515 | return NOTIFY_DONE; |
443 | 516 | ||
@@ -536,7 +609,7 @@ ctnetlink_dump_table(struct sk_buff *skb, struct netlink_callback *cb) | |||
536 | { | 609 | { |
537 | struct nf_conn *ct, *last; | 610 | struct nf_conn *ct, *last; |
538 | struct nf_conntrack_tuple_hash *h; | 611 | struct nf_conntrack_tuple_hash *h; |
539 | struct hlist_node *n; | 612 | struct hlist_nulls_node *n; |
540 | struct nfgenmsg *nfmsg = NLMSG_DATA(cb->nlh); | 613 | struct nfgenmsg *nfmsg = NLMSG_DATA(cb->nlh); |
541 | u_int8_t l3proto = nfmsg->nfgen_family; | 614 | u_int8_t l3proto = nfmsg->nfgen_family; |
542 | 615 | ||
@@ -544,27 +617,27 @@ ctnetlink_dump_table(struct sk_buff *skb, struct netlink_callback *cb) | |||
544 | last = (struct nf_conn *)cb->args[1]; | 617 | last = (struct nf_conn *)cb->args[1]; |
545 | for (; cb->args[0] < nf_conntrack_htable_size; cb->args[0]++) { | 618 | for (; cb->args[0] < nf_conntrack_htable_size; cb->args[0]++) { |
546 | restart: | 619 | restart: |
547 | hlist_for_each_entry_rcu(h, n, &init_net.ct.hash[cb->args[0]], | 620 | hlist_nulls_for_each_entry_rcu(h, n, &init_net.ct.hash[cb->args[0]], |
548 | hnode) { | 621 | hnnode) { |
549 | if (NF_CT_DIRECTION(h) != IP_CT_DIR_ORIGINAL) | 622 | if (NF_CT_DIRECTION(h) != IP_CT_DIR_ORIGINAL) |
550 | continue; | 623 | continue; |
551 | ct = nf_ct_tuplehash_to_ctrack(h); | 624 | ct = nf_ct_tuplehash_to_ctrack(h); |
625 | if (!atomic_inc_not_zero(&ct->ct_general.use)) | ||
626 | continue; | ||
552 | /* Dump entries of a given L3 protocol number. | 627 | /* Dump entries of a given L3 protocol number. |
553 | * If it is not specified, ie. l3proto == 0, | 628 | * If it is not specified, ie. l3proto == 0, |
554 | * then dump everything. */ | 629 | * then dump everything. */ |
555 | if (l3proto && nf_ct_l3num(ct) != l3proto) | 630 | if (l3proto && nf_ct_l3num(ct) != l3proto) |
556 | continue; | 631 | goto releasect; |
557 | if (cb->args[1]) { | 632 | if (cb->args[1]) { |
558 | if (ct != last) | 633 | if (ct != last) |
559 | continue; | 634 | goto releasect; |
560 | cb->args[1] = 0; | 635 | cb->args[1] = 0; |
561 | } | 636 | } |
562 | if (ctnetlink_fill_info(skb, NETLINK_CB(cb->skb).pid, | 637 | if (ctnetlink_fill_info(skb, NETLINK_CB(cb->skb).pid, |
563 | cb->nlh->nlmsg_seq, | 638 | cb->nlh->nlmsg_seq, |
564 | IPCTNL_MSG_CT_NEW, | 639 | IPCTNL_MSG_CT_NEW, |
565 | 1, ct) < 0) { | 640 | 1, ct) < 0) { |
566 | if (!atomic_inc_not_zero(&ct->ct_general.use)) | ||
567 | continue; | ||
568 | cb->args[1] = (unsigned long)ct; | 641 | cb->args[1] = (unsigned long)ct; |
569 | goto out; | 642 | goto out; |
570 | } | 643 | } |
@@ -577,6 +650,8 @@ restart: | |||
577 | if (acct) | 650 | if (acct) |
578 | memset(acct, 0, sizeof(struct nf_conn_counter[IP_CT_DIR_MAX])); | 651 | memset(acct, 0, sizeof(struct nf_conn_counter[IP_CT_DIR_MAX])); |
579 | } | 652 | } |
653 | releasect: | ||
654 | nf_ct_put(ct); | ||
580 | } | 655 | } |
581 | if (cb->args[1]) { | 656 | if (cb->args[1]) { |
582 | cb->args[1] = 0; | 657 | cb->args[1] = 0; |
@@ -1242,13 +1317,12 @@ ctnetlink_create_conntrack(struct nlattr *cda[], | |||
1242 | if (err < 0) | 1317 | if (err < 0) |
1243 | goto err2; | 1318 | goto err2; |
1244 | 1319 | ||
1245 | master_h = __nf_conntrack_find(&init_net, &master); | 1320 | master_h = nf_conntrack_find_get(&init_net, &master); |
1246 | if (master_h == NULL) { | 1321 | if (master_h == NULL) { |
1247 | err = -ENOENT; | 1322 | err = -ENOENT; |
1248 | goto err2; | 1323 | goto err2; |
1249 | } | 1324 | } |
1250 | master_ct = nf_ct_tuplehash_to_ctrack(master_h); | 1325 | master_ct = nf_ct_tuplehash_to_ctrack(master_h); |
1251 | nf_conntrack_get(&master_ct->ct_general); | ||
1252 | __set_bit(IPS_EXPECTED_BIT, &ct->status); | 1326 | __set_bit(IPS_EXPECTED_BIT, &ct->status); |
1253 | ct->master = master_ct; | 1327 | ct->master = master_ct; |
1254 | } | 1328 | } |
diff --git a/net/netfilter/nf_conntrack_proto.c b/net/netfilter/nf_conntrack_proto.c index 9a62b4efa0e1..1a4568bf7ea5 100644 --- a/net/netfilter/nf_conntrack_proto.c +++ b/net/netfilter/nf_conntrack_proto.c | |||
@@ -167,6 +167,9 @@ int nf_conntrack_l3proto_register(struct nf_conntrack_l3proto *proto) | |||
167 | if (proto->l3proto >= AF_MAX) | 167 | if (proto->l3proto >= AF_MAX) |
168 | return -EBUSY; | 168 | return -EBUSY; |
169 | 169 | ||
170 | if (proto->tuple_to_nlattr && !proto->nlattr_tuple_size) | ||
171 | return -EINVAL; | ||
172 | |||
170 | mutex_lock(&nf_ct_proto_mutex); | 173 | mutex_lock(&nf_ct_proto_mutex); |
171 | if (nf_ct_l3protos[proto->l3proto] != &nf_conntrack_l3proto_generic) { | 174 | if (nf_ct_l3protos[proto->l3proto] != &nf_conntrack_l3proto_generic) { |
172 | ret = -EBUSY; | 175 | ret = -EBUSY; |
@@ -177,6 +180,9 @@ int nf_conntrack_l3proto_register(struct nf_conntrack_l3proto *proto) | |||
177 | if (ret < 0) | 180 | if (ret < 0) |
178 | goto out_unlock; | 181 | goto out_unlock; |
179 | 182 | ||
183 | if (proto->nlattr_tuple_size) | ||
184 | proto->nla_size = 3 * proto->nlattr_tuple_size(); | ||
185 | |||
180 | rcu_assign_pointer(nf_ct_l3protos[proto->l3proto], proto); | 186 | rcu_assign_pointer(nf_ct_l3protos[proto->l3proto], proto); |
181 | 187 | ||
182 | out_unlock: | 188 | out_unlock: |
@@ -263,6 +269,10 @@ int nf_conntrack_l4proto_register(struct nf_conntrack_l4proto *l4proto) | |||
263 | if (l4proto->l3proto >= PF_MAX) | 269 | if (l4proto->l3proto >= PF_MAX) |
264 | return -EBUSY; | 270 | return -EBUSY; |
265 | 271 | ||
272 | if ((l4proto->to_nlattr && !l4proto->nlattr_size) | ||
273 | || (l4proto->tuple_to_nlattr && !l4proto->nlattr_tuple_size)) | ||
274 | return -EINVAL; | ||
275 | |||
266 | mutex_lock(&nf_ct_proto_mutex); | 276 | mutex_lock(&nf_ct_proto_mutex); |
267 | if (!nf_ct_protos[l4proto->l3proto]) { | 277 | if (!nf_ct_protos[l4proto->l3proto]) { |
268 | /* l3proto may be loaded latter. */ | 278 | /* l3proto may be loaded latter. */ |
@@ -290,6 +300,12 @@ int nf_conntrack_l4proto_register(struct nf_conntrack_l4proto *l4proto) | |||
290 | if (ret < 0) | 300 | if (ret < 0) |
291 | goto out_unlock; | 301 | goto out_unlock; |
292 | 302 | ||
303 | l4proto->nla_size = 0; | ||
304 | if (l4proto->nlattr_size) | ||
305 | l4proto->nla_size += l4proto->nlattr_size(); | ||
306 | if (l4proto->nlattr_tuple_size) | ||
307 | l4proto->nla_size += 3 * l4proto->nlattr_tuple_size(); | ||
308 | |||
293 | rcu_assign_pointer(nf_ct_protos[l4proto->l3proto][l4proto->l4proto], | 309 | rcu_assign_pointer(nf_ct_protos[l4proto->l3proto][l4proto->l4proto], |
294 | l4proto); | 310 | l4proto); |
295 | 311 | ||
diff --git a/net/netfilter/nf_conntrack_proto_dccp.c b/net/netfilter/nf_conntrack_proto_dccp.c index d3d5a7fd73ce..50dac8dbe7d8 100644 --- a/net/netfilter/nf_conntrack_proto_dccp.c +++ b/net/netfilter/nf_conntrack_proto_dccp.c | |||
@@ -669,6 +669,12 @@ static int nlattr_to_dccp(struct nlattr *cda[], struct nf_conn *ct) | |||
669 | write_unlock_bh(&dccp_lock); | 669 | write_unlock_bh(&dccp_lock); |
670 | return 0; | 670 | return 0; |
671 | } | 671 | } |
672 | |||
673 | static int dccp_nlattr_size(void) | ||
674 | { | ||
675 | return nla_total_size(0) /* CTA_PROTOINFO_DCCP */ | ||
676 | + nla_policy_len(dccp_nla_policy, CTA_PROTOINFO_DCCP_MAX + 1); | ||
677 | } | ||
672 | #endif | 678 | #endif |
673 | 679 | ||
674 | #ifdef CONFIG_SYSCTL | 680 | #ifdef CONFIG_SYSCTL |
@@ -749,8 +755,10 @@ static struct nf_conntrack_l4proto dccp_proto4 __read_mostly = { | |||
749 | .print_conntrack = dccp_print_conntrack, | 755 | .print_conntrack = dccp_print_conntrack, |
750 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) | 756 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) |
751 | .to_nlattr = dccp_to_nlattr, | 757 | .to_nlattr = dccp_to_nlattr, |
758 | .nlattr_size = dccp_nlattr_size, | ||
752 | .from_nlattr = nlattr_to_dccp, | 759 | .from_nlattr = nlattr_to_dccp, |
753 | .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, | 760 | .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, |
761 | .nlattr_tuple_size = nf_ct_port_nlattr_tuple_size, | ||
754 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, | 762 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, |
755 | .nla_policy = nf_ct_port_nla_policy, | 763 | .nla_policy = nf_ct_port_nla_policy, |
756 | #endif | 764 | #endif |
@@ -771,6 +779,7 @@ static struct nf_conntrack_l4proto dccp_proto6 __read_mostly = { | |||
771 | .to_nlattr = dccp_to_nlattr, | 779 | .to_nlattr = dccp_to_nlattr, |
772 | .from_nlattr = nlattr_to_dccp, | 780 | .from_nlattr = nlattr_to_dccp, |
773 | .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, | 781 | .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, |
782 | .nlattr_tuple_size = nf_ct_port_nlattr_tuple_size, | ||
774 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, | 783 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, |
775 | .nla_policy = nf_ct_port_nla_policy, | 784 | .nla_policy = nf_ct_port_nla_policy, |
776 | #endif | 785 | #endif |
diff --git a/net/netfilter/nf_conntrack_proto_gre.c b/net/netfilter/nf_conntrack_proto_gre.c index 1b279f9d6bf3..117b80112fcb 100644 --- a/net/netfilter/nf_conntrack_proto_gre.c +++ b/net/netfilter/nf_conntrack_proto_gre.c | |||
@@ -293,6 +293,7 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_gre4 __read_mostly = { | |||
293 | .me = THIS_MODULE, | 293 | .me = THIS_MODULE, |
294 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) | 294 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) |
295 | .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, | 295 | .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, |
296 | .nlattr_tuple_size = nf_ct_port_nlattr_tuple_size, | ||
296 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, | 297 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, |
297 | .nla_policy = nf_ct_port_nla_policy, | 298 | .nla_policy = nf_ct_port_nla_policy, |
298 | #endif | 299 | #endif |
diff --git a/net/netfilter/nf_conntrack_proto_sctp.c b/net/netfilter/nf_conntrack_proto_sctp.c index 74e037901199..101b4ad9e817 100644 --- a/net/netfilter/nf_conntrack_proto_sctp.c +++ b/net/netfilter/nf_conntrack_proto_sctp.c | |||
@@ -537,6 +537,12 @@ static int nlattr_to_sctp(struct nlattr *cda[], struct nf_conn *ct) | |||
537 | 537 | ||
538 | return 0; | 538 | return 0; |
539 | } | 539 | } |
540 | |||
541 | static int sctp_nlattr_size(void) | ||
542 | { | ||
543 | return nla_total_size(0) /* CTA_PROTOINFO_SCTP */ | ||
544 | + nla_policy_len(sctp_nla_policy, CTA_PROTOINFO_SCTP_MAX + 1); | ||
545 | } | ||
540 | #endif | 546 | #endif |
541 | 547 | ||
542 | #ifdef CONFIG_SYSCTL | 548 | #ifdef CONFIG_SYSCTL |
@@ -668,8 +674,10 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp4 __read_mostly = { | |||
668 | .me = THIS_MODULE, | 674 | .me = THIS_MODULE, |
669 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) | 675 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) |
670 | .to_nlattr = sctp_to_nlattr, | 676 | .to_nlattr = sctp_to_nlattr, |
677 | .nlattr_size = sctp_nlattr_size, | ||
671 | .from_nlattr = nlattr_to_sctp, | 678 | .from_nlattr = nlattr_to_sctp, |
672 | .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, | 679 | .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, |
680 | .nlattr_tuple_size = nf_ct_port_nlattr_tuple_size, | ||
673 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, | 681 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, |
674 | .nla_policy = nf_ct_port_nla_policy, | 682 | .nla_policy = nf_ct_port_nla_policy, |
675 | #endif | 683 | #endif |
@@ -696,8 +704,10 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp6 __read_mostly = { | |||
696 | .me = THIS_MODULE, | 704 | .me = THIS_MODULE, |
697 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) | 705 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) |
698 | .to_nlattr = sctp_to_nlattr, | 706 | .to_nlattr = sctp_to_nlattr, |
707 | .nlattr_size = sctp_nlattr_size, | ||
699 | .from_nlattr = nlattr_to_sctp, | 708 | .from_nlattr = nlattr_to_sctp, |
700 | .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, | 709 | .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, |
710 | .nlattr_tuple_size = nf_ct_port_nlattr_tuple_size, | ||
701 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, | 711 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, |
702 | .nla_policy = nf_ct_port_nla_policy, | 712 | .nla_policy = nf_ct_port_nla_policy, |
703 | #endif | 713 | #endif |
diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c index 0aeb8b09a1f7..b5ccf2b4b2e7 100644 --- a/net/netfilter/nf_conntrack_proto_tcp.c +++ b/net/netfilter/nf_conntrack_proto_tcp.c | |||
@@ -1184,6 +1184,17 @@ static int nlattr_to_tcp(struct nlattr *cda[], struct nf_conn *ct) | |||
1184 | 1184 | ||
1185 | return 0; | 1185 | return 0; |
1186 | } | 1186 | } |
1187 | |||
1188 | static int tcp_nlattr_size(void) | ||
1189 | { | ||
1190 | return nla_total_size(0) /* CTA_PROTOINFO_TCP */ | ||
1191 | + nla_policy_len(tcp_nla_policy, CTA_PROTOINFO_TCP_MAX + 1); | ||
1192 | } | ||
1193 | |||
1194 | static int tcp_nlattr_tuple_size(void) | ||
1195 | { | ||
1196 | return nla_policy_len(nf_ct_port_nla_policy, CTA_PROTO_MAX + 1); | ||
1197 | } | ||
1187 | #endif | 1198 | #endif |
1188 | 1199 | ||
1189 | #ifdef CONFIG_SYSCTL | 1200 | #ifdef CONFIG_SYSCTL |
@@ -1399,9 +1410,11 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp4 __read_mostly = | |||
1399 | .error = tcp_error, | 1410 | .error = tcp_error, |
1400 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) | 1411 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) |
1401 | .to_nlattr = tcp_to_nlattr, | 1412 | .to_nlattr = tcp_to_nlattr, |
1413 | .nlattr_size = tcp_nlattr_size, | ||
1402 | .from_nlattr = nlattr_to_tcp, | 1414 | .from_nlattr = nlattr_to_tcp, |
1403 | .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, | 1415 | .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, |
1404 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, | 1416 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, |
1417 | .nlattr_tuple_size = tcp_nlattr_tuple_size, | ||
1405 | .nla_policy = nf_ct_port_nla_policy, | 1418 | .nla_policy = nf_ct_port_nla_policy, |
1406 | #endif | 1419 | #endif |
1407 | #ifdef CONFIG_SYSCTL | 1420 | #ifdef CONFIG_SYSCTL |
@@ -1429,9 +1442,11 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp6 __read_mostly = | |||
1429 | .error = tcp_error, | 1442 | .error = tcp_error, |
1430 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) | 1443 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) |
1431 | .to_nlattr = tcp_to_nlattr, | 1444 | .to_nlattr = tcp_to_nlattr, |
1445 | .nlattr_size = tcp_nlattr_size, | ||
1432 | .from_nlattr = nlattr_to_tcp, | 1446 | .from_nlattr = nlattr_to_tcp, |
1433 | .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, | 1447 | .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, |
1434 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, | 1448 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, |
1449 | .nlattr_tuple_size = tcp_nlattr_tuple_size, | ||
1435 | .nla_policy = nf_ct_port_nla_policy, | 1450 | .nla_policy = nf_ct_port_nla_policy, |
1436 | #endif | 1451 | #endif |
1437 | #ifdef CONFIG_SYSCTL | 1452 | #ifdef CONFIG_SYSCTL |
diff --git a/net/netfilter/nf_conntrack_proto_udp.c b/net/netfilter/nf_conntrack_proto_udp.c index d4021179e24e..70809d117b91 100644 --- a/net/netfilter/nf_conntrack_proto_udp.c +++ b/net/netfilter/nf_conntrack_proto_udp.c | |||
@@ -195,6 +195,7 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_udp4 __read_mostly = | |||
195 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) | 195 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) |
196 | .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, | 196 | .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, |
197 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, | 197 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, |
198 | .nlattr_tuple_size = nf_ct_port_nlattr_tuple_size, | ||
198 | .nla_policy = nf_ct_port_nla_policy, | 199 | .nla_policy = nf_ct_port_nla_policy, |
199 | #endif | 200 | #endif |
200 | #ifdef CONFIG_SYSCTL | 201 | #ifdef CONFIG_SYSCTL |
@@ -222,6 +223,7 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_udp6 __read_mostly = | |||
222 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) | 223 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) |
223 | .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, | 224 | .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, |
224 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, | 225 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, |
226 | .nlattr_tuple_size = nf_ct_port_nlattr_tuple_size, | ||
225 | .nla_policy = nf_ct_port_nla_policy, | 227 | .nla_policy = nf_ct_port_nla_policy, |
226 | #endif | 228 | #endif |
227 | #ifdef CONFIG_SYSCTL | 229 | #ifdef CONFIG_SYSCTL |
diff --git a/net/netfilter/nf_conntrack_proto_udplite.c b/net/netfilter/nf_conntrack_proto_udplite.c index 4579d8de13b1..4614696c1b88 100644 --- a/net/netfilter/nf_conntrack_proto_udplite.c +++ b/net/netfilter/nf_conntrack_proto_udplite.c | |||
@@ -180,6 +180,7 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_udplite4 __read_mostly = | |||
180 | .error = udplite_error, | 180 | .error = udplite_error, |
181 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) | 181 | #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) |
182 | .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, | 182 | .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, |
183 | .nlattr_tuple_size = nf_ct_port_nlattr_tuple_size, | ||
183 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, | 184 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, |
184 | .nla_policy = nf_ct_port_nla_policy, | 185 | .nla_policy = nf_ct_port_nla_policy, |
185 | #endif | 186 | #endif |
diff --git a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c index 4da54b0b9233..193515381970 100644 --- a/net/netfilter/nf_conntrack_standalone.c +++ b/net/netfilter/nf_conntrack_standalone.c | |||
@@ -44,40 +44,42 @@ struct ct_iter_state { | |||
44 | unsigned int bucket; | 44 | unsigned int bucket; |
45 | }; | 45 | }; |
46 | 46 | ||
47 | static struct hlist_node *ct_get_first(struct seq_file *seq) | 47 | static struct hlist_nulls_node *ct_get_first(struct seq_file *seq) |
48 | { | 48 | { |
49 | struct net *net = seq_file_net(seq); | 49 | struct net *net = seq_file_net(seq); |
50 | struct ct_iter_state *st = seq->private; | 50 | struct ct_iter_state *st = seq->private; |
51 | struct hlist_node *n; | 51 | struct hlist_nulls_node *n; |
52 | 52 | ||
53 | for (st->bucket = 0; | 53 | for (st->bucket = 0; |
54 | st->bucket < nf_conntrack_htable_size; | 54 | st->bucket < nf_conntrack_htable_size; |
55 | st->bucket++) { | 55 | st->bucket++) { |
56 | n = rcu_dereference(net->ct.hash[st->bucket].first); | 56 | n = rcu_dereference(net->ct.hash[st->bucket].first); |
57 | if (n) | 57 | if (!is_a_nulls(n)) |
58 | return n; | 58 | return n; |
59 | } | 59 | } |
60 | return NULL; | 60 | return NULL; |
61 | } | 61 | } |
62 | 62 | ||
63 | static struct hlist_node *ct_get_next(struct seq_file *seq, | 63 | static struct hlist_nulls_node *ct_get_next(struct seq_file *seq, |
64 | struct hlist_node *head) | 64 | struct hlist_nulls_node *head) |
65 | { | 65 | { |
66 | struct net *net = seq_file_net(seq); | 66 | struct net *net = seq_file_net(seq); |
67 | struct ct_iter_state *st = seq->private; | 67 | struct ct_iter_state *st = seq->private; |
68 | 68 | ||
69 | head = rcu_dereference(head->next); | 69 | head = rcu_dereference(head->next); |
70 | while (head == NULL) { | 70 | while (is_a_nulls(head)) { |
71 | if (++st->bucket >= nf_conntrack_htable_size) | 71 | if (likely(get_nulls_value(head) == st->bucket)) { |
72 | return NULL; | 72 | if (++st->bucket >= nf_conntrack_htable_size) |
73 | return NULL; | ||
74 | } | ||
73 | head = rcu_dereference(net->ct.hash[st->bucket].first); | 75 | head = rcu_dereference(net->ct.hash[st->bucket].first); |
74 | } | 76 | } |
75 | return head; | 77 | return head; |
76 | } | 78 | } |
77 | 79 | ||
78 | static struct hlist_node *ct_get_idx(struct seq_file *seq, loff_t pos) | 80 | static struct hlist_nulls_node *ct_get_idx(struct seq_file *seq, loff_t pos) |
79 | { | 81 | { |
80 | struct hlist_node *head = ct_get_first(seq); | 82 | struct hlist_nulls_node *head = ct_get_first(seq); |
81 | 83 | ||
82 | if (head) | 84 | if (head) |
83 | while (pos && (head = ct_get_next(seq, head))) | 85 | while (pos && (head = ct_get_next(seq, head))) |
@@ -107,67 +109,74 @@ static void ct_seq_stop(struct seq_file *s, void *v) | |||
107 | /* return 0 on success, 1 in case of error */ | 109 | /* return 0 on success, 1 in case of error */ |
108 | static int ct_seq_show(struct seq_file *s, void *v) | 110 | static int ct_seq_show(struct seq_file *s, void *v) |
109 | { | 111 | { |
110 | const struct nf_conntrack_tuple_hash *hash = v; | 112 | struct nf_conntrack_tuple_hash *hash = v; |
111 | const struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(hash); | 113 | struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(hash); |
112 | const struct nf_conntrack_l3proto *l3proto; | 114 | const struct nf_conntrack_l3proto *l3proto; |
113 | const struct nf_conntrack_l4proto *l4proto; | 115 | const struct nf_conntrack_l4proto *l4proto; |
116 | int ret = 0; | ||
114 | 117 | ||
115 | NF_CT_ASSERT(ct); | 118 | NF_CT_ASSERT(ct); |
119 | if (unlikely(!atomic_inc_not_zero(&ct->ct_general.use))) | ||
120 | return 0; | ||
116 | 121 | ||
117 | /* we only want to print DIR_ORIGINAL */ | 122 | /* we only want to print DIR_ORIGINAL */ |
118 | if (NF_CT_DIRECTION(hash)) | 123 | if (NF_CT_DIRECTION(hash)) |
119 | return 0; | 124 | goto release; |
120 | 125 | ||
121 | l3proto = __nf_ct_l3proto_find(nf_ct_l3num(ct)); | 126 | l3proto = __nf_ct_l3proto_find(nf_ct_l3num(ct)); |
122 | NF_CT_ASSERT(l3proto); | 127 | NF_CT_ASSERT(l3proto); |
123 | l4proto = __nf_ct_l4proto_find(nf_ct_l3num(ct), nf_ct_protonum(ct)); | 128 | l4proto = __nf_ct_l4proto_find(nf_ct_l3num(ct), nf_ct_protonum(ct)); |
124 | NF_CT_ASSERT(l4proto); | 129 | NF_CT_ASSERT(l4proto); |
125 | 130 | ||
131 | ret = -ENOSPC; | ||
126 | if (seq_printf(s, "%-8s %u %-8s %u %ld ", | 132 | if (seq_printf(s, "%-8s %u %-8s %u %ld ", |
127 | l3proto->name, nf_ct_l3num(ct), | 133 | l3proto->name, nf_ct_l3num(ct), |
128 | l4proto->name, nf_ct_protonum(ct), | 134 | l4proto->name, nf_ct_protonum(ct), |
129 | timer_pending(&ct->timeout) | 135 | timer_pending(&ct->timeout) |
130 | ? (long)(ct->timeout.expires - jiffies)/HZ : 0) != 0) | 136 | ? (long)(ct->timeout.expires - jiffies)/HZ : 0) != 0) |
131 | return -ENOSPC; | 137 | goto release; |
132 | 138 | ||
133 | if (l4proto->print_conntrack && l4proto->print_conntrack(s, ct)) | 139 | if (l4proto->print_conntrack && l4proto->print_conntrack(s, ct)) |
134 | return -ENOSPC; | 140 | goto release; |
135 | 141 | ||
136 | if (print_tuple(s, &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple, | 142 | if (print_tuple(s, &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple, |
137 | l3proto, l4proto)) | 143 | l3proto, l4proto)) |
138 | return -ENOSPC; | 144 | goto release; |
139 | 145 | ||
140 | if (seq_print_acct(s, ct, IP_CT_DIR_ORIGINAL)) | 146 | if (seq_print_acct(s, ct, IP_CT_DIR_ORIGINAL)) |
141 | return -ENOSPC; | 147 | goto release; |
142 | 148 | ||
143 | if (!(test_bit(IPS_SEEN_REPLY_BIT, &ct->status))) | 149 | if (!(test_bit(IPS_SEEN_REPLY_BIT, &ct->status))) |
144 | if (seq_printf(s, "[UNREPLIED] ")) | 150 | if (seq_printf(s, "[UNREPLIED] ")) |
145 | return -ENOSPC; | 151 | goto release; |
146 | 152 | ||
147 | if (print_tuple(s, &ct->tuplehash[IP_CT_DIR_REPLY].tuple, | 153 | if (print_tuple(s, &ct->tuplehash[IP_CT_DIR_REPLY].tuple, |
148 | l3proto, l4proto)) | 154 | l3proto, l4proto)) |
149 | return -ENOSPC; | 155 | goto release; |
150 | 156 | ||
151 | if (seq_print_acct(s, ct, IP_CT_DIR_REPLY)) | 157 | if (seq_print_acct(s, ct, IP_CT_DIR_REPLY)) |
152 | return -ENOSPC; | 158 | goto release; |
153 | 159 | ||
154 | if (test_bit(IPS_ASSURED_BIT, &ct->status)) | 160 | if (test_bit(IPS_ASSURED_BIT, &ct->status)) |
155 | if (seq_printf(s, "[ASSURED] ")) | 161 | if (seq_printf(s, "[ASSURED] ")) |
156 | return -ENOSPC; | 162 | goto release; |
157 | 163 | ||
158 | #if defined(CONFIG_NF_CONNTRACK_MARK) | 164 | #if defined(CONFIG_NF_CONNTRACK_MARK) |
159 | if (seq_printf(s, "mark=%u ", ct->mark)) | 165 | if (seq_printf(s, "mark=%u ", ct->mark)) |
160 | return -ENOSPC; | 166 | goto release; |
161 | #endif | 167 | #endif |
162 | 168 | ||
163 | #ifdef CONFIG_NF_CONNTRACK_SECMARK | 169 | #ifdef CONFIG_NF_CONNTRACK_SECMARK |
164 | if (seq_printf(s, "secmark=%u ", ct->secmark)) | 170 | if (seq_printf(s, "secmark=%u ", ct->secmark)) |
165 | return -ENOSPC; | 171 | goto release; |
166 | #endif | 172 | #endif |
167 | 173 | ||
168 | if (seq_printf(s, "use=%u\n", atomic_read(&ct->ct_general.use))) | 174 | if (seq_printf(s, "use=%u\n", atomic_read(&ct->ct_general.use))) |
169 | return -ENOSPC; | 175 | goto release; |
170 | 176 | ||
177 | ret = 0; | ||
178 | release: | ||
179 | nf_ct_put(ct); | ||
171 | return 0; | 180 | return 0; |
172 | } | 181 | } |
173 | 182 | ||
diff --git a/net/netfilter/xt_connlimit.c b/net/netfilter/xt_connlimit.c index 7f404cc64c83..680980954395 100644 --- a/net/netfilter/xt_connlimit.c +++ b/net/netfilter/xt_connlimit.c | |||
@@ -108,7 +108,7 @@ static int count_them(struct xt_connlimit_data *data, | |||
108 | const struct nf_conntrack_tuple_hash *found; | 108 | const struct nf_conntrack_tuple_hash *found; |
109 | struct xt_connlimit_conn *conn; | 109 | struct xt_connlimit_conn *conn; |
110 | struct xt_connlimit_conn *tmp; | 110 | struct xt_connlimit_conn *tmp; |
111 | const struct nf_conn *found_ct; | 111 | struct nf_conn *found_ct; |
112 | struct list_head *hash; | 112 | struct list_head *hash; |
113 | bool addit = true; | 113 | bool addit = true; |
114 | int matches = 0; | 114 | int matches = 0; |
@@ -123,7 +123,7 @@ static int count_them(struct xt_connlimit_data *data, | |||
123 | 123 | ||
124 | /* check the saved connections */ | 124 | /* check the saved connections */ |
125 | list_for_each_entry_safe(conn, tmp, hash, list) { | 125 | list_for_each_entry_safe(conn, tmp, hash, list) { |
126 | found = __nf_conntrack_find(&init_net, &conn->tuple); | 126 | found = nf_conntrack_find_get(&init_net, &conn->tuple); |
127 | found_ct = NULL; | 127 | found_ct = NULL; |
128 | 128 | ||
129 | if (found != NULL) | 129 | if (found != NULL) |
@@ -151,6 +151,7 @@ static int count_them(struct xt_connlimit_data *data, | |||
151 | * we do not care about connections which are | 151 | * we do not care about connections which are |
152 | * closed already -> ditch it | 152 | * closed already -> ditch it |
153 | */ | 153 | */ |
154 | nf_ct_put(found_ct); | ||
154 | list_del(&conn->list); | 155 | list_del(&conn->list); |
155 | kfree(conn); | 156 | kfree(conn); |
156 | continue; | 157 | continue; |
@@ -160,6 +161,7 @@ static int count_them(struct xt_connlimit_data *data, | |||
160 | match->family)) | 161 | match->family)) |
161 | /* same source network -> be counted! */ | 162 | /* same source network -> be counted! */ |
162 | ++matches; | 163 | ++matches; |
164 | nf_ct_put(found_ct); | ||
163 | } | 165 | } |
164 | 166 | ||
165 | rcu_read_unlock(); | 167 | rcu_read_unlock(); |
diff --git a/net/netfilter/xt_physdev.c b/net/netfilter/xt_physdev.c index 44a234ef4439..8d28ca5848bc 100644 --- a/net/netfilter/xt_physdev.c +++ b/net/netfilter/xt_physdev.c | |||
@@ -20,23 +20,6 @@ MODULE_DESCRIPTION("Xtables: Bridge physical device match"); | |||
20 | MODULE_ALIAS("ipt_physdev"); | 20 | MODULE_ALIAS("ipt_physdev"); |
21 | MODULE_ALIAS("ip6t_physdev"); | 21 | MODULE_ALIAS("ip6t_physdev"); |
22 | 22 | ||
23 | static unsigned long ifname_compare(const char *_a, const char *_b, const char *_mask) | ||
24 | { | ||
25 | const unsigned long *a = (const unsigned long *)_a; | ||
26 | const unsigned long *b = (const unsigned long *)_b; | ||
27 | const unsigned long *mask = (const unsigned long *)_mask; | ||
28 | unsigned long ret; | ||
29 | |||
30 | ret = (a[0] ^ b[0]) & mask[0]; | ||
31 | if (IFNAMSIZ > sizeof(unsigned long)) | ||
32 | ret |= (a[1] ^ b[1]) & mask[1]; | ||
33 | if (IFNAMSIZ > 2 * sizeof(unsigned long)) | ||
34 | ret |= (a[2] ^ b[2]) & mask[2]; | ||
35 | if (IFNAMSIZ > 3 * sizeof(unsigned long)) | ||
36 | ret |= (a[3] ^ b[3]) & mask[3]; | ||
37 | BUILD_BUG_ON(IFNAMSIZ > 4 * sizeof(unsigned long)); | ||
38 | return ret; | ||
39 | } | ||
40 | 23 | ||
41 | static bool | 24 | static bool |
42 | physdev_mt(const struct sk_buff *skb, const struct xt_match_param *par) | 25 | physdev_mt(const struct sk_buff *skb, const struct xt_match_param *par) |
@@ -85,7 +68,7 @@ physdev_mt(const struct sk_buff *skb, const struct xt_match_param *par) | |||
85 | if (!(info->bitmask & XT_PHYSDEV_OP_IN)) | 68 | if (!(info->bitmask & XT_PHYSDEV_OP_IN)) |
86 | goto match_outdev; | 69 | goto match_outdev; |
87 | indev = nf_bridge->physindev ? nf_bridge->physindev->name : nulldevname; | 70 | indev = nf_bridge->physindev ? nf_bridge->physindev->name : nulldevname; |
88 | ret = ifname_compare(indev, info->physindev, info->in_mask); | 71 | ret = ifname_compare_aligned(indev, info->physindev, info->in_mask); |
89 | 72 | ||
90 | if (!ret ^ !(info->invert & XT_PHYSDEV_OP_IN)) | 73 | if (!ret ^ !(info->invert & XT_PHYSDEV_OP_IN)) |
91 | return false; | 74 | return false; |
@@ -95,7 +78,7 @@ match_outdev: | |||
95 | return true; | 78 | return true; |
96 | outdev = nf_bridge->physoutdev ? | 79 | outdev = nf_bridge->physoutdev ? |
97 | nf_bridge->physoutdev->name : nulldevname; | 80 | nf_bridge->physoutdev->name : nulldevname; |
98 | ret = ifname_compare(outdev, info->physoutdev, info->out_mask); | 81 | ret = ifname_compare_aligned(outdev, info->physoutdev, info->out_mask); |
99 | 82 | ||
100 | return (!!ret ^ !(info->invert & XT_PHYSDEV_OP_OUT)); | 83 | return (!!ret ^ !(info->invert & XT_PHYSDEV_OP_OUT)); |
101 | } | 84 | } |
diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c index 6d9c58ec56ac..4e705f87969f 100644 --- a/net/netrom/af_netrom.c +++ b/net/netrom/af_netrom.c | |||
@@ -1037,10 +1037,6 @@ static int nr_sendmsg(struct kiocb *iocb, struct socket *sock, | |||
1037 | unsigned char *asmptr; | 1037 | unsigned char *asmptr; |
1038 | int size; | 1038 | int size; |
1039 | 1039 | ||
1040 | /* Netrom empty data frame has no meaning : don't send */ | ||
1041 | if (len == 0) | ||
1042 | return 0; | ||
1043 | |||
1044 | if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_EOR|MSG_CMSG_COMPAT)) | 1040 | if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_EOR|MSG_CMSG_COMPAT)) |
1045 | return -EINVAL; | 1041 | return -EINVAL; |
1046 | 1042 | ||
@@ -1086,7 +1082,11 @@ static int nr_sendmsg(struct kiocb *iocb, struct socket *sock, | |||
1086 | 1082 | ||
1087 | SOCK_DEBUG(sk, "NET/ROM: sendto: Addresses built.\n"); | 1083 | SOCK_DEBUG(sk, "NET/ROM: sendto: Addresses built.\n"); |
1088 | 1084 | ||
1089 | /* Build a packet */ | 1085 | /* Build a packet - the conventional user limit is 236 bytes. We can |
1086 | do ludicrously large NetROM frames but must not overflow */ | ||
1087 | if (len > 65536) | ||
1088 | return -EMSGSIZE; | ||
1089 | |||
1090 | SOCK_DEBUG(sk, "NET/ROM: sendto: building packet.\n"); | 1090 | SOCK_DEBUG(sk, "NET/ROM: sendto: building packet.\n"); |
1091 | size = len + NR_NETWORK_LEN + NR_TRANSPORT_LEN; | 1091 | size = len + NR_NETWORK_LEN + NR_TRANSPORT_LEN; |
1092 | 1092 | ||
@@ -1171,11 +1171,6 @@ static int nr_recvmsg(struct kiocb *iocb, struct socket *sock, | |||
1171 | skb_reset_transport_header(skb); | 1171 | skb_reset_transport_header(skb); |
1172 | copied = skb->len; | 1172 | copied = skb->len; |
1173 | 1173 | ||
1174 | /* NetRom empty data frame has no meaning : ignore it */ | ||
1175 | if (copied == 0) { | ||
1176 | goto out; | ||
1177 | } | ||
1178 | |||
1179 | if (copied > size) { | 1174 | if (copied > size) { |
1180 | copied = size; | 1175 | copied = size; |
1181 | msg->msg_flags |= MSG_TRUNC; | 1176 | msg->msg_flags |= MSG_TRUNC; |
@@ -1191,7 +1186,7 @@ static int nr_recvmsg(struct kiocb *iocb, struct socket *sock, | |||
1191 | 1186 | ||
1192 | msg->msg_namelen = sizeof(*sax); | 1187 | msg->msg_namelen = sizeof(*sax); |
1193 | 1188 | ||
1194 | out: skb_free_datagram(sk, skb); | 1189 | skb_free_datagram(sk, skb); |
1195 | 1190 | ||
1196 | release_sock(sk); | 1191 | release_sock(sk); |
1197 | return copied; | 1192 | return copied; |
diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c index 650139626581..0f36e8d59b29 100644 --- a/net/rose/af_rose.c +++ b/net/rose/af_rose.c | |||
@@ -1124,6 +1124,10 @@ static int rose_sendmsg(struct kiocb *iocb, struct socket *sock, | |||
1124 | 1124 | ||
1125 | /* Build a packet */ | 1125 | /* Build a packet */ |
1126 | SOCK_DEBUG(sk, "ROSE: sendto: building packet.\n"); | 1126 | SOCK_DEBUG(sk, "ROSE: sendto: building packet.\n"); |
1127 | /* Sanity check the packet size */ | ||
1128 | if (len > 65535) | ||
1129 | return -EMSGSIZE; | ||
1130 | |||
1127 | size = len + AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + ROSE_MIN_LEN; | 1131 | size = len + AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + ROSE_MIN_LEN; |
1128 | 1132 | ||
1129 | if ((skb = sock_alloc_send_skb(sk, size, msg->msg_flags & MSG_DONTWAIT, &err)) == NULL) | 1133 | if ((skb = sock_alloc_send_skb(sk, size, msg->msg_flags & MSG_DONTWAIT, &err)) == NULL) |
diff --git a/net/wireless/Kconfig b/net/wireless/Kconfig index 092ae6faccca..3c3bc9e579ed 100644 --- a/net/wireless/Kconfig +++ b/net/wireless/Kconfig | |||
@@ -10,51 +10,19 @@ config CFG80211_REG_DEBUG | |||
10 | 10 | ||
11 | If unsure, say N. | 11 | If unsure, say N. |
12 | 12 | ||
13 | config NL80211 | ||
14 | bool "nl80211 new netlink interface support" | ||
15 | depends on CFG80211 | ||
16 | default y | ||
17 | ---help--- | ||
18 | This option turns on the new netlink interface | ||
19 | (nl80211) support in cfg80211. | ||
20 | |||
21 | If =n, drivers using mac80211 will be configured via | ||
22 | wireless extension support provided by that subsystem. | ||
23 | |||
24 | If unsure, say Y. | ||
25 | |||
26 | config WIRELESS_OLD_REGULATORY | 13 | config WIRELESS_OLD_REGULATORY |
27 | bool "Old wireless static regulatory definitions" | 14 | bool "Old wireless static regulatory definitions" |
28 | default y | 15 | default n |
29 | ---help--- | 16 | ---help--- |
30 | This option enables the old static regulatory information | 17 | This option enables the old static regulatory information |
31 | and uses it within the new framework. This is available | 18 | and uses it within the new framework. This option is available |
32 | temporarily as an option to help prevent immediate issues | 19 | for historical reasons and it is advised to leave it off. |
33 | due to the switch to the new regulatory framework which | 20 | |
34 | does require a new userspace application which has the | 21 | For details see: |
35 | database of regulatory information (CRDA) and another for | 22 | |
36 | setting regulatory domains (iw). | 23 | http://wireless.kernel.org/en/developers/Regulatory |
37 | 24 | ||
38 | For more information see: | 25 | Say N and if you say Y, please tell us why. The default is N. |
39 | |||
40 | http://wireless.kernel.org/en/developers/Regulatory/CRDA | ||
41 | http://wireless.kernel.org/en/users/Documentation/iw | ||
42 | |||
43 | It is important to note though that if you *do* have CRDA present | ||
44 | and if this option is enabled CRDA *will* be called to update the | ||
45 | regulatory domain (for US and JP only). Support for letting the user | ||
46 | set the regulatory domain through iw is also supported. This option | ||
47 | mainly exists to leave around for a kernel release some old static | ||
48 | regulatory domains that were defined and to keep around the old | ||
49 | ieee80211_regdom module parameter. This is being phased out and you | ||
50 | should stop using them ASAP. | ||
51 | |||
52 | Note: You will need CRDA if you want 802.11d support | ||
53 | |||
54 | Say Y unless you have installed a new userspace application. | ||
55 | Also say Y if have one currently depending on the ieee80211_regdom | ||
56 | module parameter and cannot port it to use the new userspace | ||
57 | interfaces. | ||
58 | 26 | ||
59 | config WIRELESS_EXT | 27 | config WIRELESS_EXT |
60 | bool "Wireless extensions" | 28 | bool "Wireless extensions" |
diff --git a/net/wireless/Makefile b/net/wireless/Makefile index dad43c24f695..6d1e7b27b752 100644 --- a/net/wireless/Makefile +++ b/net/wireless/Makefile | |||
@@ -5,8 +5,7 @@ obj-$(CONFIG_LIB80211_CRYPT_WEP) += lib80211_crypt_wep.o | |||
5 | obj-$(CONFIG_LIB80211_CRYPT_CCMP) += lib80211_crypt_ccmp.o | 5 | obj-$(CONFIG_LIB80211_CRYPT_CCMP) += lib80211_crypt_ccmp.o |
6 | obj-$(CONFIG_LIB80211_CRYPT_TKIP) += lib80211_crypt_tkip.o | 6 | obj-$(CONFIG_LIB80211_CRYPT_TKIP) += lib80211_crypt_tkip.o |
7 | 7 | ||
8 | cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o | 8 | cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o mlme.o |
9 | cfg80211-$(CONFIG_WIRELESS_EXT) += wext-compat.o | 9 | cfg80211-$(CONFIG_WIRELESS_EXT) += wext-compat.o |
10 | cfg80211-$(CONFIG_NL80211) += nl80211.o | ||
11 | 10 | ||
12 | ccflags-y += -D__CHECK_ENDIAN__ | 11 | ccflags-y += -D__CHECK_ENDIAN__ |
diff --git a/net/wireless/core.c b/net/wireless/core.c index 17fe39049740..d1f556535f6d 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c | |||
@@ -87,7 +87,7 @@ struct wiphy *wiphy_idx_to_wiphy(int wiphy_idx) | |||
87 | } | 87 | } |
88 | 88 | ||
89 | /* requires cfg80211_mutex to be held! */ | 89 | /* requires cfg80211_mutex to be held! */ |
90 | static struct cfg80211_registered_device * | 90 | struct cfg80211_registered_device * |
91 | __cfg80211_drv_from_info(struct genl_info *info) | 91 | __cfg80211_drv_from_info(struct genl_info *info) |
92 | { | 92 | { |
93 | int ifindex; | 93 | int ifindex; |
@@ -176,13 +176,14 @@ void cfg80211_put_dev(struct cfg80211_registered_device *drv) | |||
176 | mutex_unlock(&drv->mtx); | 176 | mutex_unlock(&drv->mtx); |
177 | } | 177 | } |
178 | 178 | ||
179 | /* requires cfg80211_mutex to be held */ | ||
179 | int cfg80211_dev_rename(struct cfg80211_registered_device *rdev, | 180 | int cfg80211_dev_rename(struct cfg80211_registered_device *rdev, |
180 | char *newname) | 181 | char *newname) |
181 | { | 182 | { |
182 | struct cfg80211_registered_device *drv; | 183 | struct cfg80211_registered_device *drv; |
183 | int wiphy_idx, taken = -1, result, digits; | 184 | int wiphy_idx, taken = -1, result, digits; |
184 | 185 | ||
185 | mutex_lock(&cfg80211_mutex); | 186 | assert_cfg80211_lock(); |
186 | 187 | ||
187 | /* prohibit calling the thing phy%d when %d is not its number */ | 188 | /* prohibit calling the thing phy%d when %d is not its number */ |
188 | sscanf(newname, PHY_NAME "%d%n", &wiphy_idx, &taken); | 189 | sscanf(newname, PHY_NAME "%d%n", &wiphy_idx, &taken); |
@@ -195,30 +196,23 @@ int cfg80211_dev_rename(struct cfg80211_registered_device *rdev, | |||
195 | * deny the name if it is phy<idx> where <idx> is printed | 196 | * deny the name if it is phy<idx> where <idx> is printed |
196 | * without leading zeroes. taken == strlen(newname) here | 197 | * without leading zeroes. taken == strlen(newname) here |
197 | */ | 198 | */ |
198 | result = -EINVAL; | ||
199 | if (taken == strlen(PHY_NAME) + digits) | 199 | if (taken == strlen(PHY_NAME) + digits) |
200 | goto out_unlock; | 200 | return -EINVAL; |
201 | } | 201 | } |
202 | 202 | ||
203 | 203 | ||
204 | /* Ignore nop renames */ | 204 | /* Ignore nop renames */ |
205 | result = 0; | ||
206 | if (strcmp(newname, dev_name(&rdev->wiphy.dev)) == 0) | 205 | if (strcmp(newname, dev_name(&rdev->wiphy.dev)) == 0) |
207 | goto out_unlock; | 206 | return 0; |
208 | 207 | ||
209 | /* Ensure another device does not already have this name. */ | 208 | /* Ensure another device does not already have this name. */ |
210 | list_for_each_entry(drv, &cfg80211_drv_list, list) { | 209 | list_for_each_entry(drv, &cfg80211_drv_list, list) |
211 | result = -EINVAL; | ||
212 | if (strcmp(newname, dev_name(&drv->wiphy.dev)) == 0) | 210 | if (strcmp(newname, dev_name(&drv->wiphy.dev)) == 0) |
213 | goto out_unlock; | 211 | return -EINVAL; |
214 | } | ||
215 | 212 | ||
216 | /* this will only check for collisions in sysfs | ||
217 | * which is not even always compiled in. | ||
218 | */ | ||
219 | result = device_rename(&rdev->wiphy.dev, newname); | 213 | result = device_rename(&rdev->wiphy.dev, newname); |
220 | if (result) | 214 | if (result) |
221 | goto out_unlock; | 215 | return result; |
222 | 216 | ||
223 | if (rdev->wiphy.debugfsdir && | 217 | if (rdev->wiphy.debugfsdir && |
224 | !debugfs_rename(rdev->wiphy.debugfsdir->d_parent, | 218 | !debugfs_rename(rdev->wiphy.debugfsdir->d_parent, |
@@ -228,13 +222,9 @@ int cfg80211_dev_rename(struct cfg80211_registered_device *rdev, | |||
228 | printk(KERN_ERR "cfg80211: failed to rename debugfs dir to %s!\n", | 222 | printk(KERN_ERR "cfg80211: failed to rename debugfs dir to %s!\n", |
229 | newname); | 223 | newname); |
230 | 224 | ||
231 | result = 0; | 225 | nl80211_notify_dev_rename(rdev); |
232 | out_unlock: | ||
233 | mutex_unlock(&cfg80211_mutex); | ||
234 | if (result == 0) | ||
235 | nl80211_notify_dev_rename(rdev); | ||
236 | 226 | ||
237 | return result; | 227 | return 0; |
238 | } | 228 | } |
239 | 229 | ||
240 | /* exported functions */ | 230 | /* exported functions */ |
diff --git a/net/wireless/core.h b/net/wireless/core.h index 6acd483a61f8..d43daa236ef9 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h | |||
@@ -90,6 +90,8 @@ struct cfg80211_internal_bss { | |||
90 | struct rb_node rbn; | 90 | struct rb_node rbn; |
91 | unsigned long ts; | 91 | unsigned long ts; |
92 | struct kref ref; | 92 | struct kref ref; |
93 | bool hold; | ||
94 | |||
93 | /* must be last because of priv member */ | 95 | /* must be last because of priv member */ |
94 | struct cfg80211_bss pub; | 96 | struct cfg80211_bss pub; |
95 | }; | 97 | }; |
@@ -97,6 +99,9 @@ struct cfg80211_internal_bss { | |||
97 | struct cfg80211_registered_device *cfg80211_drv_by_wiphy_idx(int wiphy_idx); | 99 | struct cfg80211_registered_device *cfg80211_drv_by_wiphy_idx(int wiphy_idx); |
98 | int get_wiphy_idx(struct wiphy *wiphy); | 100 | int get_wiphy_idx(struct wiphy *wiphy); |
99 | 101 | ||
102 | struct cfg80211_registered_device * | ||
103 | __cfg80211_drv_from_info(struct genl_info *info); | ||
104 | |||
100 | /* | 105 | /* |
101 | * This function returns a pointer to the driver | 106 | * This function returns a pointer to the driver |
102 | * that the genl_info item that is passed refers to. | 107 | * that the genl_info item that is passed refers to. |
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c new file mode 100644 index 000000000000..bec5721b6f99 --- /dev/null +++ b/net/wireless/mlme.c | |||
@@ -0,0 +1,46 @@ | |||
1 | /* | ||
2 | * cfg80211 MLME SAP interface | ||
3 | * | ||
4 | * Copyright (c) 2009, Jouni Malinen <j@w1.fi> | ||
5 | */ | ||
6 | |||
7 | #include <linux/kernel.h> | ||
8 | #include <linux/module.h> | ||
9 | #include <linux/netdevice.h> | ||
10 | #include <linux/nl80211.h> | ||
11 | #include <net/cfg80211.h> | ||
12 | #include "core.h" | ||
13 | #include "nl80211.h" | ||
14 | |||
15 | void cfg80211_send_rx_auth(struct net_device *dev, const u8 *buf, size_t len) | ||
16 | { | ||
17 | struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; | ||
18 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
19 | nl80211_send_rx_auth(rdev, dev, buf, len); | ||
20 | } | ||
21 | EXPORT_SYMBOL(cfg80211_send_rx_auth); | ||
22 | |||
23 | void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len) | ||
24 | { | ||
25 | struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; | ||
26 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
27 | nl80211_send_rx_assoc(rdev, dev, buf, len); | ||
28 | } | ||
29 | EXPORT_SYMBOL(cfg80211_send_rx_assoc); | ||
30 | |||
31 | void cfg80211_send_rx_deauth(struct net_device *dev, const u8 *buf, size_t len) | ||
32 | { | ||
33 | struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; | ||
34 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
35 | nl80211_send_rx_deauth(rdev, dev, buf, len); | ||
36 | } | ||
37 | EXPORT_SYMBOL(cfg80211_send_rx_deauth); | ||
38 | |||
39 | void cfg80211_send_rx_disassoc(struct net_device *dev, const u8 *buf, | ||
40 | size_t len) | ||
41 | { | ||
42 | struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; | ||
43 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||
44 | nl80211_send_rx_disassoc(rdev, dev, buf, len); | ||
45 | } | ||
46 | EXPORT_SYMBOL(cfg80211_send_rx_disassoc); | ||
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index ab9d8f14e151..353e1a4ece83 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -111,6 +111,11 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = { | |||
111 | .len = IEEE80211_MAX_DATA_LEN }, | 111 | .len = IEEE80211_MAX_DATA_LEN }, |
112 | [NL80211_ATTR_SCAN_FREQUENCIES] = { .type = NLA_NESTED }, | 112 | [NL80211_ATTR_SCAN_FREQUENCIES] = { .type = NLA_NESTED }, |
113 | [NL80211_ATTR_SCAN_SSIDS] = { .type = NLA_NESTED }, | 113 | [NL80211_ATTR_SCAN_SSIDS] = { .type = NLA_NESTED }, |
114 | |||
115 | [NL80211_ATTR_SSID] = { .type = NLA_BINARY, | ||
116 | .len = IEEE80211_MAX_SSID_LEN }, | ||
117 | [NL80211_ATTR_AUTH_TYPE] = { .type = NLA_U32 }, | ||
118 | [NL80211_ATTR_REASON_CODE] = { .type = NLA_U16 }, | ||
114 | }; | 119 | }; |
115 | 120 | ||
116 | /* message building helper */ | 121 | /* message building helper */ |
@@ -131,6 +136,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
131 | struct nlattr *nl_freqs, *nl_freq; | 136 | struct nlattr *nl_freqs, *nl_freq; |
132 | struct nlattr *nl_rates, *nl_rate; | 137 | struct nlattr *nl_rates, *nl_rate; |
133 | struct nlattr *nl_modes; | 138 | struct nlattr *nl_modes; |
139 | struct nlattr *nl_cmds; | ||
134 | enum ieee80211_band band; | 140 | enum ieee80211_band band; |
135 | struct ieee80211_channel *chan; | 141 | struct ieee80211_channel *chan; |
136 | struct ieee80211_rate *rate; | 142 | struct ieee80211_rate *rate; |
@@ -242,6 +248,35 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
242 | } | 248 | } |
243 | nla_nest_end(msg, nl_bands); | 249 | nla_nest_end(msg, nl_bands); |
244 | 250 | ||
251 | nl_cmds = nla_nest_start(msg, NL80211_ATTR_SUPPORTED_COMMANDS); | ||
252 | if (!nl_cmds) | ||
253 | goto nla_put_failure; | ||
254 | |||
255 | i = 0; | ||
256 | #define CMD(op, n) \ | ||
257 | do { \ | ||
258 | if (dev->ops->op) { \ | ||
259 | i++; \ | ||
260 | NLA_PUT_U32(msg, i, NL80211_CMD_ ## n); \ | ||
261 | } \ | ||
262 | } while (0) | ||
263 | |||
264 | CMD(add_virtual_intf, NEW_INTERFACE); | ||
265 | CMD(change_virtual_intf, SET_INTERFACE); | ||
266 | CMD(add_key, NEW_KEY); | ||
267 | CMD(add_beacon, NEW_BEACON); | ||
268 | CMD(add_station, NEW_STATION); | ||
269 | CMD(add_mpath, NEW_MPATH); | ||
270 | CMD(set_mesh_params, SET_MESH_PARAMS); | ||
271 | CMD(change_bss, SET_BSS); | ||
272 | CMD(auth, AUTHENTICATE); | ||
273 | CMD(assoc, ASSOCIATE); | ||
274 | CMD(deauth, DEAUTHENTICATE); | ||
275 | CMD(disassoc, DISASSOCIATE); | ||
276 | |||
277 | #undef CMD | ||
278 | nla_nest_end(msg, nl_cmds); | ||
279 | |||
245 | return genlmsg_end(msg, hdr); | 280 | return genlmsg_end(msg, hdr); |
246 | 281 | ||
247 | nla_put_failure: | 282 | nla_put_failure: |
@@ -331,16 +366,26 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
331 | int result = 0, rem_txq_params = 0; | 366 | int result = 0, rem_txq_params = 0; |
332 | struct nlattr *nl_txq_params; | 367 | struct nlattr *nl_txq_params; |
333 | 368 | ||
334 | rdev = cfg80211_get_dev_from_info(info); | 369 | rtnl_lock(); |
335 | if (IS_ERR(rdev)) | 370 | |
336 | return PTR_ERR(rdev); | 371 | mutex_lock(&cfg80211_mutex); |
337 | 372 | ||
338 | if (info->attrs[NL80211_ATTR_WIPHY_NAME]) { | 373 | rdev = __cfg80211_drv_from_info(info); |
374 | if (IS_ERR(rdev)) { | ||
375 | result = PTR_ERR(rdev); | ||
376 | goto unlock; | ||
377 | } | ||
378 | |||
379 | mutex_lock(&rdev->mtx); | ||
380 | |||
381 | if (info->attrs[NL80211_ATTR_WIPHY_NAME]) | ||
339 | result = cfg80211_dev_rename( | 382 | result = cfg80211_dev_rename( |
340 | rdev, nla_data(info->attrs[NL80211_ATTR_WIPHY_NAME])); | 383 | rdev, nla_data(info->attrs[NL80211_ATTR_WIPHY_NAME])); |
341 | if (result) | 384 | |
342 | goto bad_res; | 385 | mutex_unlock(&cfg80211_mutex); |
343 | } | 386 | |
387 | if (result) | ||
388 | goto bad_res; | ||
344 | 389 | ||
345 | if (info->attrs[NL80211_ATTR_WIPHY_TXQ_PARAMS]) { | 390 | if (info->attrs[NL80211_ATTR_WIPHY_TXQ_PARAMS]) { |
346 | struct ieee80211_txq_params txq_params; | 391 | struct ieee80211_txq_params txq_params; |
@@ -436,7 +481,9 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) | |||
436 | 481 | ||
437 | 482 | ||
438 | bad_res: | 483 | bad_res: |
439 | cfg80211_put_dev(rdev); | 484 | mutex_unlock(&rdev->mtx); |
485 | unlock: | ||
486 | rtnl_unlock(); | ||
440 | return result; | 487 | return result; |
441 | } | 488 | } |
442 | 489 | ||
@@ -572,21 +619,31 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) | |||
572 | enum nl80211_iftype type; | 619 | enum nl80211_iftype type; |
573 | struct net_device *dev; | 620 | struct net_device *dev; |
574 | u32 _flags, *flags = NULL; | 621 | u32 _flags, *flags = NULL; |
622 | bool change = false; | ||
575 | 623 | ||
576 | memset(¶ms, 0, sizeof(params)); | 624 | memset(¶ms, 0, sizeof(params)); |
577 | 625 | ||
626 | rtnl_lock(); | ||
627 | |||
578 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | 628 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
579 | if (err) | 629 | if (err) |
580 | return err; | 630 | goto unlock_rtnl; |
631 | |||
581 | ifindex = dev->ifindex; | 632 | ifindex = dev->ifindex; |
582 | type = dev->ieee80211_ptr->iftype; | 633 | type = dev->ieee80211_ptr->iftype; |
583 | dev_put(dev); | 634 | dev_put(dev); |
584 | 635 | ||
585 | err = -EINVAL; | ||
586 | if (info->attrs[NL80211_ATTR_IFTYPE]) { | 636 | if (info->attrs[NL80211_ATTR_IFTYPE]) { |
587 | type = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]); | 637 | enum nl80211_iftype ntype; |
588 | if (type > NL80211_IFTYPE_MAX) | 638 | |
639 | ntype = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]); | ||
640 | if (type != ntype) | ||
641 | change = true; | ||
642 | type = ntype; | ||
643 | if (type > NL80211_IFTYPE_MAX) { | ||
644 | err = -EINVAL; | ||
589 | goto unlock; | 645 | goto unlock; |
646 | } | ||
590 | } | 647 | } |
591 | 648 | ||
592 | if (!drv->ops->change_virtual_intf || | 649 | if (!drv->ops->change_virtual_intf || |
@@ -602,6 +659,7 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) | |||
602 | } | 659 | } |
603 | params.mesh_id = nla_data(info->attrs[NL80211_ATTR_MESH_ID]); | 660 | params.mesh_id = nla_data(info->attrs[NL80211_ATTR_MESH_ID]); |
604 | params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]); | 661 | params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]); |
662 | change = true; | ||
605 | } | 663 | } |
606 | 664 | ||
607 | if (info->attrs[NL80211_ATTR_MNTR_FLAGS]) { | 665 | if (info->attrs[NL80211_ATTR_MNTR_FLAGS]) { |
@@ -611,20 +669,26 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) | |||
611 | } | 669 | } |
612 | err = parse_monitor_flags(info->attrs[NL80211_ATTR_MNTR_FLAGS], | 670 | err = parse_monitor_flags(info->attrs[NL80211_ATTR_MNTR_FLAGS], |
613 | &_flags); | 671 | &_flags); |
614 | if (!err) | 672 | if (err) |
615 | flags = &_flags; | 673 | goto unlock; |
674 | |||
675 | flags = &_flags; | ||
676 | change = true; | ||
616 | } | 677 | } |
617 | rtnl_lock(); | 678 | |
618 | err = drv->ops->change_virtual_intf(&drv->wiphy, ifindex, | 679 | if (change) |
619 | type, flags, ¶ms); | 680 | err = drv->ops->change_virtual_intf(&drv->wiphy, ifindex, |
681 | type, flags, ¶ms); | ||
682 | else | ||
683 | err = 0; | ||
620 | 684 | ||
621 | dev = __dev_get_by_index(&init_net, ifindex); | 685 | dev = __dev_get_by_index(&init_net, ifindex); |
622 | WARN_ON(!dev || (!err && dev->ieee80211_ptr->iftype != type)); | 686 | WARN_ON(!dev || (!err && dev->ieee80211_ptr->iftype != type)); |
623 | 687 | ||
624 | rtnl_unlock(); | ||
625 | |||
626 | unlock: | 688 | unlock: |
627 | cfg80211_put_dev(drv); | 689 | cfg80211_put_dev(drv); |
690 | unlock_rtnl: | ||
691 | rtnl_unlock(); | ||
628 | return err; | 692 | return err; |
629 | } | 693 | } |
630 | 694 | ||
@@ -647,9 +711,13 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) | |||
647 | return -EINVAL; | 711 | return -EINVAL; |
648 | } | 712 | } |
649 | 713 | ||
714 | rtnl_lock(); | ||
715 | |||
650 | drv = cfg80211_get_dev_from_info(info); | 716 | drv = cfg80211_get_dev_from_info(info); |
651 | if (IS_ERR(drv)) | 717 | if (IS_ERR(drv)) { |
652 | return PTR_ERR(drv); | 718 | err = PTR_ERR(drv); |
719 | goto unlock_rtnl; | ||
720 | } | ||
653 | 721 | ||
654 | if (!drv->ops->add_virtual_intf || | 722 | if (!drv->ops->add_virtual_intf || |
655 | !(drv->wiphy.interface_modes & (1 << type))) { | 723 | !(drv->wiphy.interface_modes & (1 << type))) { |
@@ -663,18 +731,17 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) | |||
663 | params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]); | 731 | params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]); |
664 | } | 732 | } |
665 | 733 | ||
666 | rtnl_lock(); | ||
667 | err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ? | 734 | err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ? |
668 | info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL, | 735 | info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL, |
669 | &flags); | 736 | &flags); |
670 | err = drv->ops->add_virtual_intf(&drv->wiphy, | 737 | err = drv->ops->add_virtual_intf(&drv->wiphy, |
671 | nla_data(info->attrs[NL80211_ATTR_IFNAME]), | 738 | nla_data(info->attrs[NL80211_ATTR_IFNAME]), |
672 | type, err ? NULL : &flags, ¶ms); | 739 | type, err ? NULL : &flags, ¶ms); |
673 | rtnl_unlock(); | ||
674 | |||
675 | 740 | ||
676 | unlock: | 741 | unlock: |
677 | cfg80211_put_dev(drv); | 742 | cfg80211_put_dev(drv); |
743 | unlock_rtnl: | ||
744 | rtnl_unlock(); | ||
678 | return err; | 745 | return err; |
679 | } | 746 | } |
680 | 747 | ||
@@ -684,9 +751,11 @@ static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info) | |||
684 | int ifindex, err; | 751 | int ifindex, err; |
685 | struct net_device *dev; | 752 | struct net_device *dev; |
686 | 753 | ||
754 | rtnl_lock(); | ||
755 | |||
687 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | 756 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
688 | if (err) | 757 | if (err) |
689 | return err; | 758 | goto unlock_rtnl; |
690 | ifindex = dev->ifindex; | 759 | ifindex = dev->ifindex; |
691 | dev_put(dev); | 760 | dev_put(dev); |
692 | 761 | ||
@@ -695,12 +764,12 @@ static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info) | |||
695 | goto out; | 764 | goto out; |
696 | } | 765 | } |
697 | 766 | ||
698 | rtnl_lock(); | ||
699 | err = drv->ops->del_virtual_intf(&drv->wiphy, ifindex); | 767 | err = drv->ops->del_virtual_intf(&drv->wiphy, ifindex); |
700 | rtnl_unlock(); | ||
701 | 768 | ||
702 | out: | 769 | out: |
703 | cfg80211_put_dev(drv); | 770 | cfg80211_put_dev(drv); |
771 | unlock_rtnl: | ||
772 | rtnl_unlock(); | ||
704 | return err; | 773 | return err; |
705 | } | 774 | } |
706 | 775 | ||
@@ -752,9 +821,11 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info) | |||
752 | if (info->attrs[NL80211_ATTR_MAC]) | 821 | if (info->attrs[NL80211_ATTR_MAC]) |
753 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | 822 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); |
754 | 823 | ||
824 | rtnl_lock(); | ||
825 | |||
755 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | 826 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
756 | if (err) | 827 | if (err) |
757 | return err; | 828 | goto unlock_rtnl; |
758 | 829 | ||
759 | if (!drv->ops->get_key) { | 830 | if (!drv->ops->get_key) { |
760 | err = -EOPNOTSUPP; | 831 | err = -EOPNOTSUPP; |
@@ -782,10 +853,8 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info) | |||
782 | if (mac_addr) | 853 | if (mac_addr) |
783 | NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr); | 854 | NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr); |
784 | 855 | ||
785 | rtnl_lock(); | ||
786 | err = drv->ops->get_key(&drv->wiphy, dev, key_idx, mac_addr, | 856 | err = drv->ops->get_key(&drv->wiphy, dev, key_idx, mac_addr, |
787 | &cookie, get_key_callback); | 857 | &cookie, get_key_callback); |
788 | rtnl_unlock(); | ||
789 | 858 | ||
790 | if (err) | 859 | if (err) |
791 | goto out; | 860 | goto out; |
@@ -803,6 +872,9 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info) | |||
803 | out: | 872 | out: |
804 | cfg80211_put_dev(drv); | 873 | cfg80211_put_dev(drv); |
805 | dev_put(dev); | 874 | dev_put(dev); |
875 | unlock_rtnl: | ||
876 | rtnl_unlock(); | ||
877 | |||
806 | return err; | 878 | return err; |
807 | } | 879 | } |
808 | 880 | ||
@@ -831,9 +903,11 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info) | |||
831 | !info->attrs[NL80211_ATTR_KEY_DEFAULT_MGMT]) | 903 | !info->attrs[NL80211_ATTR_KEY_DEFAULT_MGMT]) |
832 | return -EINVAL; | 904 | return -EINVAL; |
833 | 905 | ||
906 | rtnl_lock(); | ||
907 | |||
834 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | 908 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
835 | if (err) | 909 | if (err) |
836 | return err; | 910 | goto unlock_rtnl; |
837 | 911 | ||
838 | if (info->attrs[NL80211_ATTR_KEY_DEFAULT]) | 912 | if (info->attrs[NL80211_ATTR_KEY_DEFAULT]) |
839 | func = drv->ops->set_default_key; | 913 | func = drv->ops->set_default_key; |
@@ -845,13 +919,15 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info) | |||
845 | goto out; | 919 | goto out; |
846 | } | 920 | } |
847 | 921 | ||
848 | rtnl_lock(); | ||
849 | err = func(&drv->wiphy, dev, key_idx); | 922 | err = func(&drv->wiphy, dev, key_idx); |
850 | rtnl_unlock(); | ||
851 | 923 | ||
852 | out: | 924 | out: |
853 | cfg80211_put_dev(drv); | 925 | cfg80211_put_dev(drv); |
854 | dev_put(dev); | 926 | dev_put(dev); |
927 | |||
928 | unlock_rtnl: | ||
929 | rtnl_unlock(); | ||
930 | |||
855 | return err; | 931 | return err; |
856 | } | 932 | } |
857 | 933 | ||
@@ -921,22 +997,25 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info) | |||
921 | return -EINVAL; | 997 | return -EINVAL; |
922 | } | 998 | } |
923 | 999 | ||
1000 | rtnl_lock(); | ||
1001 | |||
924 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | 1002 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
925 | if (err) | 1003 | if (err) |
926 | return err; | 1004 | goto unlock_rtnl; |
927 | 1005 | ||
928 | if (!drv->ops->add_key) { | 1006 | if (!drv->ops->add_key) { |
929 | err = -EOPNOTSUPP; | 1007 | err = -EOPNOTSUPP; |
930 | goto out; | 1008 | goto out; |
931 | } | 1009 | } |
932 | 1010 | ||
933 | rtnl_lock(); | ||
934 | err = drv->ops->add_key(&drv->wiphy, dev, key_idx, mac_addr, ¶ms); | 1011 | err = drv->ops->add_key(&drv->wiphy, dev, key_idx, mac_addr, ¶ms); |
935 | rtnl_unlock(); | ||
936 | 1012 | ||
937 | out: | 1013 | out: |
938 | cfg80211_put_dev(drv); | 1014 | cfg80211_put_dev(drv); |
939 | dev_put(dev); | 1015 | dev_put(dev); |
1016 | unlock_rtnl: | ||
1017 | rtnl_unlock(); | ||
1018 | |||
940 | return err; | 1019 | return err; |
941 | } | 1020 | } |
942 | 1021 | ||
@@ -957,22 +1036,26 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info) | |||
957 | if (info->attrs[NL80211_ATTR_MAC]) | 1036 | if (info->attrs[NL80211_ATTR_MAC]) |
958 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | 1037 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); |
959 | 1038 | ||
1039 | rtnl_lock(); | ||
1040 | |||
960 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | 1041 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
961 | if (err) | 1042 | if (err) |
962 | return err; | 1043 | goto unlock_rtnl; |
963 | 1044 | ||
964 | if (!drv->ops->del_key) { | 1045 | if (!drv->ops->del_key) { |
965 | err = -EOPNOTSUPP; | 1046 | err = -EOPNOTSUPP; |
966 | goto out; | 1047 | goto out; |
967 | } | 1048 | } |
968 | 1049 | ||
969 | rtnl_lock(); | ||
970 | err = drv->ops->del_key(&drv->wiphy, dev, key_idx, mac_addr); | 1050 | err = drv->ops->del_key(&drv->wiphy, dev, key_idx, mac_addr); |
971 | rtnl_unlock(); | ||
972 | 1051 | ||
973 | out: | 1052 | out: |
974 | cfg80211_put_dev(drv); | 1053 | cfg80211_put_dev(drv); |
975 | dev_put(dev); | 1054 | dev_put(dev); |
1055 | |||
1056 | unlock_rtnl: | ||
1057 | rtnl_unlock(); | ||
1058 | |||
976 | return err; | 1059 | return err; |
977 | } | 1060 | } |
978 | 1061 | ||
@@ -986,9 +1069,16 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info) | |||
986 | struct beacon_parameters params; | 1069 | struct beacon_parameters params; |
987 | int haveinfo = 0; | 1070 | int haveinfo = 0; |
988 | 1071 | ||
1072 | rtnl_lock(); | ||
1073 | |||
989 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | 1074 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
990 | if (err) | 1075 | if (err) |
991 | return err; | 1076 | goto unlock_rtnl; |
1077 | |||
1078 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP) { | ||
1079 | err = -EOPNOTSUPP; | ||
1080 | goto out; | ||
1081 | } | ||
992 | 1082 | ||
993 | switch (info->genlhdr->cmd) { | 1083 | switch (info->genlhdr->cmd) { |
994 | case NL80211_CMD_NEW_BEACON: | 1084 | case NL80211_CMD_NEW_BEACON: |
@@ -1049,13 +1139,14 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info) | |||
1049 | goto out; | 1139 | goto out; |
1050 | } | 1140 | } |
1051 | 1141 | ||
1052 | rtnl_lock(); | ||
1053 | err = call(&drv->wiphy, dev, ¶ms); | 1142 | err = call(&drv->wiphy, dev, ¶ms); |
1054 | rtnl_unlock(); | ||
1055 | 1143 | ||
1056 | out: | 1144 | out: |
1057 | cfg80211_put_dev(drv); | 1145 | cfg80211_put_dev(drv); |
1058 | dev_put(dev); | 1146 | dev_put(dev); |
1147 | unlock_rtnl: | ||
1148 | rtnl_unlock(); | ||
1149 | |||
1059 | return err; | 1150 | return err; |
1060 | } | 1151 | } |
1061 | 1152 | ||
@@ -1065,22 +1156,29 @@ static int nl80211_del_beacon(struct sk_buff *skb, struct genl_info *info) | |||
1065 | int err; | 1156 | int err; |
1066 | struct net_device *dev; | 1157 | struct net_device *dev; |
1067 | 1158 | ||
1159 | rtnl_lock(); | ||
1160 | |||
1068 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | 1161 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
1069 | if (err) | 1162 | if (err) |
1070 | return err; | 1163 | goto unlock_rtnl; |
1071 | 1164 | ||
1072 | if (!drv->ops->del_beacon) { | 1165 | if (!drv->ops->del_beacon) { |
1073 | err = -EOPNOTSUPP; | 1166 | err = -EOPNOTSUPP; |
1074 | goto out; | 1167 | goto out; |
1075 | } | 1168 | } |
1076 | 1169 | ||
1077 | rtnl_lock(); | 1170 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP) { |
1171 | err = -EOPNOTSUPP; | ||
1172 | goto out; | ||
1173 | } | ||
1078 | err = drv->ops->del_beacon(&drv->wiphy, dev); | 1174 | err = drv->ops->del_beacon(&drv->wiphy, dev); |
1079 | rtnl_unlock(); | ||
1080 | 1175 | ||
1081 | out: | 1176 | out: |
1082 | cfg80211_put_dev(drv); | 1177 | cfg80211_put_dev(drv); |
1083 | dev_put(dev); | 1178 | dev_put(dev); |
1179 | unlock_rtnl: | ||
1180 | rtnl_unlock(); | ||
1181 | |||
1084 | return err; | 1182 | return err; |
1085 | } | 1183 | } |
1086 | 1184 | ||
@@ -1246,30 +1344,32 @@ static int nl80211_dump_station(struct sk_buff *skb, | |||
1246 | return -EINVAL; | 1344 | return -EINVAL; |
1247 | } | 1345 | } |
1248 | 1346 | ||
1249 | netdev = dev_get_by_index(&init_net, ifidx); | 1347 | rtnl_lock(); |
1250 | if (!netdev) | 1348 | |
1251 | return -ENODEV; | 1349 | netdev = __dev_get_by_index(&init_net, ifidx); |
1350 | if (!netdev) { | ||
1351 | err = -ENODEV; | ||
1352 | goto out_rtnl; | ||
1353 | } | ||
1252 | 1354 | ||
1253 | dev = cfg80211_get_dev_from_ifindex(ifidx); | 1355 | dev = cfg80211_get_dev_from_ifindex(ifidx); |
1254 | if (IS_ERR(dev)) { | 1356 | if (IS_ERR(dev)) { |
1255 | err = PTR_ERR(dev); | 1357 | err = PTR_ERR(dev); |
1256 | goto out_put_netdev; | 1358 | goto out_rtnl; |
1257 | } | 1359 | } |
1258 | 1360 | ||
1259 | if (!dev->ops->dump_station) { | 1361 | if (!dev->ops->dump_station) { |
1260 | err = -ENOSYS; | 1362 | err = -EOPNOTSUPP; |
1261 | goto out_err; | 1363 | goto out_err; |
1262 | } | 1364 | } |
1263 | 1365 | ||
1264 | rtnl_lock(); | ||
1265 | |||
1266 | while (1) { | 1366 | while (1) { |
1267 | err = dev->ops->dump_station(&dev->wiphy, netdev, sta_idx, | 1367 | err = dev->ops->dump_station(&dev->wiphy, netdev, sta_idx, |
1268 | mac_addr, &sinfo); | 1368 | mac_addr, &sinfo); |
1269 | if (err == -ENOENT) | 1369 | if (err == -ENOENT) |
1270 | break; | 1370 | break; |
1271 | if (err) | 1371 | if (err) |
1272 | goto out_err_rtnl; | 1372 | goto out_err; |
1273 | 1373 | ||
1274 | if (nl80211_send_station(skb, | 1374 | if (nl80211_send_station(skb, |
1275 | NETLINK_CB(cb->skb).pid, | 1375 | NETLINK_CB(cb->skb).pid, |
@@ -1285,12 +1385,10 @@ static int nl80211_dump_station(struct sk_buff *skb, | |||
1285 | out: | 1385 | out: |
1286 | cb->args[1] = sta_idx; | 1386 | cb->args[1] = sta_idx; |
1287 | err = skb->len; | 1387 | err = skb->len; |
1288 | out_err_rtnl: | ||
1289 | rtnl_unlock(); | ||
1290 | out_err: | 1388 | out_err: |
1291 | cfg80211_put_dev(dev); | 1389 | cfg80211_put_dev(dev); |
1292 | out_put_netdev: | 1390 | out_rtnl: |
1293 | dev_put(netdev); | 1391 | rtnl_unlock(); |
1294 | 1392 | ||
1295 | return err; | 1393 | return err; |
1296 | } | 1394 | } |
@@ -1311,19 +1409,18 @@ static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info) | |||
1311 | 1409 | ||
1312 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | 1410 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); |
1313 | 1411 | ||
1412 | rtnl_lock(); | ||
1413 | |||
1314 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | 1414 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
1315 | if (err) | 1415 | if (err) |
1316 | return err; | 1416 | goto out_rtnl; |
1317 | 1417 | ||
1318 | if (!drv->ops->get_station) { | 1418 | if (!drv->ops->get_station) { |
1319 | err = -EOPNOTSUPP; | 1419 | err = -EOPNOTSUPP; |
1320 | goto out; | 1420 | goto out; |
1321 | } | 1421 | } |
1322 | 1422 | ||
1323 | rtnl_lock(); | ||
1324 | err = drv->ops->get_station(&drv->wiphy, dev, mac_addr, &sinfo); | 1423 | err = drv->ops->get_station(&drv->wiphy, dev, mac_addr, &sinfo); |
1325 | rtnl_unlock(); | ||
1326 | |||
1327 | if (err) | 1424 | if (err) |
1328 | goto out; | 1425 | goto out; |
1329 | 1426 | ||
@@ -1340,10 +1437,12 @@ static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info) | |||
1340 | 1437 | ||
1341 | out_free: | 1438 | out_free: |
1342 | nlmsg_free(msg); | 1439 | nlmsg_free(msg); |
1343 | |||
1344 | out: | 1440 | out: |
1345 | cfg80211_put_dev(drv); | 1441 | cfg80211_put_dev(drv); |
1346 | dev_put(dev); | 1442 | dev_put(dev); |
1443 | out_rtnl: | ||
1444 | rtnl_unlock(); | ||
1445 | |||
1347 | return err; | 1446 | return err; |
1348 | } | 1447 | } |
1349 | 1448 | ||
@@ -1411,9 +1510,11 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) | |||
1411 | params.plink_action = | 1510 | params.plink_action = |
1412 | nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]); | 1511 | nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]); |
1413 | 1512 | ||
1513 | rtnl_lock(); | ||
1514 | |||
1414 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | 1515 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
1415 | if (err) | 1516 | if (err) |
1416 | return err; | 1517 | goto out_rtnl; |
1417 | 1518 | ||
1418 | err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], drv, ¶ms.vlan); | 1519 | err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], drv, ¶ms.vlan); |
1419 | if (err) | 1520 | if (err) |
@@ -1424,15 +1525,16 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) | |||
1424 | goto out; | 1525 | goto out; |
1425 | } | 1526 | } |
1426 | 1527 | ||
1427 | rtnl_lock(); | ||
1428 | err = drv->ops->change_station(&drv->wiphy, dev, mac_addr, ¶ms); | 1528 | err = drv->ops->change_station(&drv->wiphy, dev, mac_addr, ¶ms); |
1429 | rtnl_unlock(); | ||
1430 | 1529 | ||
1431 | out: | 1530 | out: |
1432 | if (params.vlan) | 1531 | if (params.vlan) |
1433 | dev_put(params.vlan); | 1532 | dev_put(params.vlan); |
1434 | cfg80211_put_dev(drv); | 1533 | cfg80211_put_dev(drv); |
1435 | dev_put(dev); | 1534 | dev_put(dev); |
1535 | out_rtnl: | ||
1536 | rtnl_unlock(); | ||
1537 | |||
1436 | return err; | 1538 | return err; |
1437 | } | 1539 | } |
1438 | 1540 | ||
@@ -1474,9 +1576,11 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) | |||
1474 | ¶ms.station_flags)) | 1576 | ¶ms.station_flags)) |
1475 | return -EINVAL; | 1577 | return -EINVAL; |
1476 | 1578 | ||
1579 | rtnl_lock(); | ||
1580 | |||
1477 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | 1581 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
1478 | if (err) | 1582 | if (err) |
1479 | return err; | 1583 | goto out_rtnl; |
1480 | 1584 | ||
1481 | err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], drv, ¶ms.vlan); | 1585 | err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], drv, ¶ms.vlan); |
1482 | if (err) | 1586 | if (err) |
@@ -1487,15 +1591,21 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) | |||
1487 | goto out; | 1591 | goto out; |
1488 | } | 1592 | } |
1489 | 1593 | ||
1490 | rtnl_lock(); | 1594 | if (!netif_running(dev)) { |
1595 | err = -ENETDOWN; | ||
1596 | goto out; | ||
1597 | } | ||
1598 | |||
1491 | err = drv->ops->add_station(&drv->wiphy, dev, mac_addr, ¶ms); | 1599 | err = drv->ops->add_station(&drv->wiphy, dev, mac_addr, ¶ms); |
1492 | rtnl_unlock(); | ||
1493 | 1600 | ||
1494 | out: | 1601 | out: |
1495 | if (params.vlan) | 1602 | if (params.vlan) |
1496 | dev_put(params.vlan); | 1603 | dev_put(params.vlan); |
1497 | cfg80211_put_dev(drv); | 1604 | cfg80211_put_dev(drv); |
1498 | dev_put(dev); | 1605 | dev_put(dev); |
1606 | out_rtnl: | ||
1607 | rtnl_unlock(); | ||
1608 | |||
1499 | return err; | 1609 | return err; |
1500 | } | 1610 | } |
1501 | 1611 | ||
@@ -1509,22 +1619,25 @@ static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info) | |||
1509 | if (info->attrs[NL80211_ATTR_MAC]) | 1619 | if (info->attrs[NL80211_ATTR_MAC]) |
1510 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | 1620 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); |
1511 | 1621 | ||
1622 | rtnl_lock(); | ||
1623 | |||
1512 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | 1624 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
1513 | if (err) | 1625 | if (err) |
1514 | return err; | 1626 | goto out_rtnl; |
1515 | 1627 | ||
1516 | if (!drv->ops->del_station) { | 1628 | if (!drv->ops->del_station) { |
1517 | err = -EOPNOTSUPP; | 1629 | err = -EOPNOTSUPP; |
1518 | goto out; | 1630 | goto out; |
1519 | } | 1631 | } |
1520 | 1632 | ||
1521 | rtnl_lock(); | ||
1522 | err = drv->ops->del_station(&drv->wiphy, dev, mac_addr); | 1633 | err = drv->ops->del_station(&drv->wiphy, dev, mac_addr); |
1523 | rtnl_unlock(); | ||
1524 | 1634 | ||
1525 | out: | 1635 | out: |
1526 | cfg80211_put_dev(drv); | 1636 | cfg80211_put_dev(drv); |
1527 | dev_put(dev); | 1637 | dev_put(dev); |
1638 | out_rtnl: | ||
1639 | rtnl_unlock(); | ||
1640 | |||
1528 | return err; | 1641 | return err; |
1529 | } | 1642 | } |
1530 | 1643 | ||
@@ -1605,22 +1718,29 @@ static int nl80211_dump_mpath(struct sk_buff *skb, | |||
1605 | return -EINVAL; | 1718 | return -EINVAL; |
1606 | } | 1719 | } |
1607 | 1720 | ||
1608 | netdev = dev_get_by_index(&init_net, ifidx); | 1721 | rtnl_lock(); |
1609 | if (!netdev) | 1722 | |
1610 | return -ENODEV; | 1723 | netdev = __dev_get_by_index(&init_net, ifidx); |
1724 | if (!netdev) { | ||
1725 | err = -ENODEV; | ||
1726 | goto out_rtnl; | ||
1727 | } | ||
1611 | 1728 | ||
1612 | dev = cfg80211_get_dev_from_ifindex(ifidx); | 1729 | dev = cfg80211_get_dev_from_ifindex(ifidx); |
1613 | if (IS_ERR(dev)) { | 1730 | if (IS_ERR(dev)) { |
1614 | err = PTR_ERR(dev); | 1731 | err = PTR_ERR(dev); |
1615 | goto out_put_netdev; | 1732 | goto out_rtnl; |
1616 | } | 1733 | } |
1617 | 1734 | ||
1618 | if (!dev->ops->dump_mpath) { | 1735 | if (!dev->ops->dump_mpath) { |
1619 | err = -ENOSYS; | 1736 | err = -EOPNOTSUPP; |
1620 | goto out_err; | 1737 | goto out_err; |
1621 | } | 1738 | } |
1622 | 1739 | ||
1623 | rtnl_lock(); | 1740 | if (netdev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) { |
1741 | err = -EOPNOTSUPP; | ||
1742 | goto out; | ||
1743 | } | ||
1624 | 1744 | ||
1625 | while (1) { | 1745 | while (1) { |
1626 | err = dev->ops->dump_mpath(&dev->wiphy, netdev, path_idx, | 1746 | err = dev->ops->dump_mpath(&dev->wiphy, netdev, path_idx, |
@@ -1628,7 +1748,7 @@ static int nl80211_dump_mpath(struct sk_buff *skb, | |||
1628 | if (err == -ENOENT) | 1748 | if (err == -ENOENT) |
1629 | break; | 1749 | break; |
1630 | if (err) | 1750 | if (err) |
1631 | goto out_err_rtnl; | 1751 | goto out_err; |
1632 | 1752 | ||
1633 | if (nl80211_send_mpath(skb, NETLINK_CB(cb->skb).pid, | 1753 | if (nl80211_send_mpath(skb, NETLINK_CB(cb->skb).pid, |
1634 | cb->nlh->nlmsg_seq, NLM_F_MULTI, | 1754 | cb->nlh->nlmsg_seq, NLM_F_MULTI, |
@@ -1643,12 +1763,10 @@ static int nl80211_dump_mpath(struct sk_buff *skb, | |||
1643 | out: | 1763 | out: |
1644 | cb->args[1] = path_idx; | 1764 | cb->args[1] = path_idx; |
1645 | err = skb->len; | 1765 | err = skb->len; |
1646 | out_err_rtnl: | ||
1647 | rtnl_unlock(); | ||
1648 | out_err: | 1766 | out_err: |
1649 | cfg80211_put_dev(dev); | 1767 | cfg80211_put_dev(dev); |
1650 | out_put_netdev: | 1768 | out_rtnl: |
1651 | dev_put(netdev); | 1769 | rtnl_unlock(); |
1652 | 1770 | ||
1653 | return err; | 1771 | return err; |
1654 | } | 1772 | } |
@@ -1670,19 +1788,23 @@ static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info) | |||
1670 | 1788 | ||
1671 | dst = nla_data(info->attrs[NL80211_ATTR_MAC]); | 1789 | dst = nla_data(info->attrs[NL80211_ATTR_MAC]); |
1672 | 1790 | ||
1791 | rtnl_lock(); | ||
1792 | |||
1673 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | 1793 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
1674 | if (err) | 1794 | if (err) |
1675 | return err; | 1795 | goto out_rtnl; |
1676 | 1796 | ||
1677 | if (!drv->ops->get_mpath) { | 1797 | if (!drv->ops->get_mpath) { |
1678 | err = -EOPNOTSUPP; | 1798 | err = -EOPNOTSUPP; |
1679 | goto out; | 1799 | goto out; |
1680 | } | 1800 | } |
1681 | 1801 | ||
1682 | rtnl_lock(); | 1802 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) { |
1683 | err = drv->ops->get_mpath(&drv->wiphy, dev, dst, next_hop, &pinfo); | 1803 | err = -EOPNOTSUPP; |
1684 | rtnl_unlock(); | 1804 | goto out; |
1805 | } | ||
1685 | 1806 | ||
1807 | err = drv->ops->get_mpath(&drv->wiphy, dev, dst, next_hop, &pinfo); | ||
1686 | if (err) | 1808 | if (err) |
1687 | goto out; | 1809 | goto out; |
1688 | 1810 | ||
@@ -1699,10 +1821,12 @@ static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info) | |||
1699 | 1821 | ||
1700 | out_free: | 1822 | out_free: |
1701 | nlmsg_free(msg); | 1823 | nlmsg_free(msg); |
1702 | |||
1703 | out: | 1824 | out: |
1704 | cfg80211_put_dev(drv); | 1825 | cfg80211_put_dev(drv); |
1705 | dev_put(dev); | 1826 | dev_put(dev); |
1827 | out_rtnl: | ||
1828 | rtnl_unlock(); | ||
1829 | |||
1706 | return err; | 1830 | return err; |
1707 | } | 1831 | } |
1708 | 1832 | ||
@@ -1723,22 +1847,35 @@ static int nl80211_set_mpath(struct sk_buff *skb, struct genl_info *info) | |||
1723 | dst = nla_data(info->attrs[NL80211_ATTR_MAC]); | 1847 | dst = nla_data(info->attrs[NL80211_ATTR_MAC]); |
1724 | next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]); | 1848 | next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]); |
1725 | 1849 | ||
1850 | rtnl_lock(); | ||
1851 | |||
1726 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | 1852 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
1727 | if (err) | 1853 | if (err) |
1728 | return err; | 1854 | goto out_rtnl; |
1729 | 1855 | ||
1730 | if (!drv->ops->change_mpath) { | 1856 | if (!drv->ops->change_mpath) { |
1731 | err = -EOPNOTSUPP; | 1857 | err = -EOPNOTSUPP; |
1732 | goto out; | 1858 | goto out; |
1733 | } | 1859 | } |
1734 | 1860 | ||
1735 | rtnl_lock(); | 1861 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) { |
1862 | err = -EOPNOTSUPP; | ||
1863 | goto out; | ||
1864 | } | ||
1865 | |||
1866 | if (!netif_running(dev)) { | ||
1867 | err = -ENETDOWN; | ||
1868 | goto out; | ||
1869 | } | ||
1870 | |||
1736 | err = drv->ops->change_mpath(&drv->wiphy, dev, dst, next_hop); | 1871 | err = drv->ops->change_mpath(&drv->wiphy, dev, dst, next_hop); |
1737 | rtnl_unlock(); | ||
1738 | 1872 | ||
1739 | out: | 1873 | out: |
1740 | cfg80211_put_dev(drv); | 1874 | cfg80211_put_dev(drv); |
1741 | dev_put(dev); | 1875 | dev_put(dev); |
1876 | out_rtnl: | ||
1877 | rtnl_unlock(); | ||
1878 | |||
1742 | return err; | 1879 | return err; |
1743 | } | 1880 | } |
1744 | static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info) | 1881 | static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info) |
@@ -1758,22 +1895,35 @@ static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info) | |||
1758 | dst = nla_data(info->attrs[NL80211_ATTR_MAC]); | 1895 | dst = nla_data(info->attrs[NL80211_ATTR_MAC]); |
1759 | next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]); | 1896 | next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]); |
1760 | 1897 | ||
1898 | rtnl_lock(); | ||
1899 | |||
1761 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | 1900 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
1762 | if (err) | 1901 | if (err) |
1763 | return err; | 1902 | goto out_rtnl; |
1764 | 1903 | ||
1765 | if (!drv->ops->add_mpath) { | 1904 | if (!drv->ops->add_mpath) { |
1766 | err = -EOPNOTSUPP; | 1905 | err = -EOPNOTSUPP; |
1767 | goto out; | 1906 | goto out; |
1768 | } | 1907 | } |
1769 | 1908 | ||
1770 | rtnl_lock(); | 1909 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) { |
1910 | err = -EOPNOTSUPP; | ||
1911 | goto out; | ||
1912 | } | ||
1913 | |||
1914 | if (!netif_running(dev)) { | ||
1915 | err = -ENETDOWN; | ||
1916 | goto out; | ||
1917 | } | ||
1918 | |||
1771 | err = drv->ops->add_mpath(&drv->wiphy, dev, dst, next_hop); | 1919 | err = drv->ops->add_mpath(&drv->wiphy, dev, dst, next_hop); |
1772 | rtnl_unlock(); | ||
1773 | 1920 | ||
1774 | out: | 1921 | out: |
1775 | cfg80211_put_dev(drv); | 1922 | cfg80211_put_dev(drv); |
1776 | dev_put(dev); | 1923 | dev_put(dev); |
1924 | out_rtnl: | ||
1925 | rtnl_unlock(); | ||
1926 | |||
1777 | return err; | 1927 | return err; |
1778 | } | 1928 | } |
1779 | 1929 | ||
@@ -1787,22 +1937,25 @@ static int nl80211_del_mpath(struct sk_buff *skb, struct genl_info *info) | |||
1787 | if (info->attrs[NL80211_ATTR_MAC]) | 1937 | if (info->attrs[NL80211_ATTR_MAC]) |
1788 | dst = nla_data(info->attrs[NL80211_ATTR_MAC]); | 1938 | dst = nla_data(info->attrs[NL80211_ATTR_MAC]); |
1789 | 1939 | ||
1940 | rtnl_lock(); | ||
1941 | |||
1790 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | 1942 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
1791 | if (err) | 1943 | if (err) |
1792 | return err; | 1944 | goto out_rtnl; |
1793 | 1945 | ||
1794 | if (!drv->ops->del_mpath) { | 1946 | if (!drv->ops->del_mpath) { |
1795 | err = -EOPNOTSUPP; | 1947 | err = -EOPNOTSUPP; |
1796 | goto out; | 1948 | goto out; |
1797 | } | 1949 | } |
1798 | 1950 | ||
1799 | rtnl_lock(); | ||
1800 | err = drv->ops->del_mpath(&drv->wiphy, dev, dst); | 1951 | err = drv->ops->del_mpath(&drv->wiphy, dev, dst); |
1801 | rtnl_unlock(); | ||
1802 | 1952 | ||
1803 | out: | 1953 | out: |
1804 | cfg80211_put_dev(drv); | 1954 | cfg80211_put_dev(drv); |
1805 | dev_put(dev); | 1955 | dev_put(dev); |
1956 | out_rtnl: | ||
1957 | rtnl_unlock(); | ||
1958 | |||
1806 | return err; | 1959 | return err; |
1807 | } | 1960 | } |
1808 | 1961 | ||
@@ -1835,22 +1988,30 @@ static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info) | |||
1835 | nla_len(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]); | 1988 | nla_len(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]); |
1836 | } | 1989 | } |
1837 | 1990 | ||
1991 | rtnl_lock(); | ||
1992 | |||
1838 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | 1993 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
1839 | if (err) | 1994 | if (err) |
1840 | return err; | 1995 | goto out_rtnl; |
1841 | 1996 | ||
1842 | if (!drv->ops->change_bss) { | 1997 | if (!drv->ops->change_bss) { |
1843 | err = -EOPNOTSUPP; | 1998 | err = -EOPNOTSUPP; |
1844 | goto out; | 1999 | goto out; |
1845 | } | 2000 | } |
1846 | 2001 | ||
1847 | rtnl_lock(); | 2002 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP) { |
2003 | err = -EOPNOTSUPP; | ||
2004 | goto out; | ||
2005 | } | ||
2006 | |||
1848 | err = drv->ops->change_bss(&drv->wiphy, dev, ¶ms); | 2007 | err = drv->ops->change_bss(&drv->wiphy, dev, ¶ms); |
1849 | rtnl_unlock(); | ||
1850 | 2008 | ||
1851 | out: | 2009 | out: |
1852 | cfg80211_put_dev(drv); | 2010 | cfg80211_put_dev(drv); |
1853 | dev_put(dev); | 2011 | dev_put(dev); |
2012 | out_rtnl: | ||
2013 | rtnl_unlock(); | ||
2014 | |||
1854 | return err; | 2015 | return err; |
1855 | } | 2016 | } |
1856 | 2017 | ||
@@ -1945,10 +2106,12 @@ static int nl80211_get_mesh_params(struct sk_buff *skb, | |||
1945 | struct nlattr *pinfoattr; | 2106 | struct nlattr *pinfoattr; |
1946 | struct sk_buff *msg; | 2107 | struct sk_buff *msg; |
1947 | 2108 | ||
2109 | rtnl_lock(); | ||
2110 | |||
1948 | /* Look up our device */ | 2111 | /* Look up our device */ |
1949 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | 2112 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
1950 | if (err) | 2113 | if (err) |
1951 | return err; | 2114 | goto out_rtnl; |
1952 | 2115 | ||
1953 | if (!drv->ops->get_mesh_params) { | 2116 | if (!drv->ops->get_mesh_params) { |
1954 | err = -EOPNOTSUPP; | 2117 | err = -EOPNOTSUPP; |
@@ -1956,9 +2119,7 @@ static int nl80211_get_mesh_params(struct sk_buff *skb, | |||
1956 | } | 2119 | } |
1957 | 2120 | ||
1958 | /* Get the mesh params */ | 2121 | /* Get the mesh params */ |
1959 | rtnl_lock(); | ||
1960 | err = drv->ops->get_mesh_params(&drv->wiphy, dev, &cur_params); | 2122 | err = drv->ops->get_mesh_params(&drv->wiphy, dev, &cur_params); |
1961 | rtnl_unlock(); | ||
1962 | if (err) | 2123 | if (err) |
1963 | goto out; | 2124 | goto out; |
1964 | 2125 | ||
@@ -2007,13 +2168,16 @@ static int nl80211_get_mesh_params(struct sk_buff *skb, | |||
2007 | err = genlmsg_unicast(msg, info->snd_pid); | 2168 | err = genlmsg_unicast(msg, info->snd_pid); |
2008 | goto out; | 2169 | goto out; |
2009 | 2170 | ||
2010 | nla_put_failure: | 2171 | nla_put_failure: |
2011 | genlmsg_cancel(msg, hdr); | 2172 | genlmsg_cancel(msg, hdr); |
2012 | err = -EMSGSIZE; | 2173 | err = -EMSGSIZE; |
2013 | out: | 2174 | out: |
2014 | /* Cleanup */ | 2175 | /* Cleanup */ |
2015 | cfg80211_put_dev(drv); | 2176 | cfg80211_put_dev(drv); |
2016 | dev_put(dev); | 2177 | dev_put(dev); |
2178 | out_rtnl: | ||
2179 | rtnl_unlock(); | ||
2180 | |||
2017 | return err; | 2181 | return err; |
2018 | } | 2182 | } |
2019 | 2183 | ||
@@ -2060,9 +2224,11 @@ static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info) | |||
2060 | parent_attr, nl80211_meshconf_params_policy)) | 2224 | parent_attr, nl80211_meshconf_params_policy)) |
2061 | return -EINVAL; | 2225 | return -EINVAL; |
2062 | 2226 | ||
2227 | rtnl_lock(); | ||
2228 | |||
2063 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | 2229 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
2064 | if (err) | 2230 | if (err) |
2065 | return err; | 2231 | goto out_rtnl; |
2066 | 2232 | ||
2067 | if (!drv->ops->set_mesh_params) { | 2233 | if (!drv->ops->set_mesh_params) { |
2068 | err = -EOPNOTSUPP; | 2234 | err = -EOPNOTSUPP; |
@@ -2109,14 +2275,15 @@ static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info) | |||
2109 | nla_get_u16); | 2275 | nla_get_u16); |
2110 | 2276 | ||
2111 | /* Apply changes */ | 2277 | /* Apply changes */ |
2112 | rtnl_lock(); | ||
2113 | err = drv->ops->set_mesh_params(&drv->wiphy, dev, &cfg, mask); | 2278 | err = drv->ops->set_mesh_params(&drv->wiphy, dev, &cfg, mask); |
2114 | rtnl_unlock(); | ||
2115 | 2279 | ||
2116 | out: | 2280 | out: |
2117 | /* cleanup */ | 2281 | /* cleanup */ |
2118 | cfg80211_put_dev(drv); | 2282 | cfg80211_put_dev(drv); |
2119 | dev_put(dev); | 2283 | dev_put(dev); |
2284 | out_rtnl: | ||
2285 | rtnl_unlock(); | ||
2286 | |||
2120 | return err; | 2287 | return err; |
2121 | } | 2288 | } |
2122 | 2289 | ||
@@ -2262,43 +2429,6 @@ static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info) | |||
2262 | return -EINVAL; | 2429 | return -EINVAL; |
2263 | } | 2430 | } |
2264 | 2431 | ||
2265 | static int nl80211_set_mgmt_extra_ie(struct sk_buff *skb, | ||
2266 | struct genl_info *info) | ||
2267 | { | ||
2268 | struct cfg80211_registered_device *drv; | ||
2269 | int err; | ||
2270 | struct net_device *dev; | ||
2271 | struct mgmt_extra_ie_params params; | ||
2272 | |||
2273 | memset(¶ms, 0, sizeof(params)); | ||
2274 | |||
2275 | if (!info->attrs[NL80211_ATTR_MGMT_SUBTYPE]) | ||
2276 | return -EINVAL; | ||
2277 | params.subtype = nla_get_u8(info->attrs[NL80211_ATTR_MGMT_SUBTYPE]); | ||
2278 | if (params.subtype > 15) | ||
2279 | return -EINVAL; /* FC Subtype field is 4 bits (0..15) */ | ||
2280 | |||
2281 | if (info->attrs[NL80211_ATTR_IE]) { | ||
2282 | params.ies = nla_data(info->attrs[NL80211_ATTR_IE]); | ||
2283 | params.ies_len = nla_len(info->attrs[NL80211_ATTR_IE]); | ||
2284 | } | ||
2285 | |||
2286 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | ||
2287 | if (err) | ||
2288 | return err; | ||
2289 | |||
2290 | if (drv->ops->set_mgmt_extra_ie) { | ||
2291 | rtnl_lock(); | ||
2292 | err = drv->ops->set_mgmt_extra_ie(&drv->wiphy, dev, ¶ms); | ||
2293 | rtnl_unlock(); | ||
2294 | } else | ||
2295 | err = -EOPNOTSUPP; | ||
2296 | |||
2297 | cfg80211_put_dev(drv); | ||
2298 | dev_put(dev); | ||
2299 | return err; | ||
2300 | } | ||
2301 | |||
2302 | static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | 2432 | static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) |
2303 | { | 2433 | { |
2304 | struct cfg80211_registered_device *drv; | 2434 | struct cfg80211_registered_device *drv; |
@@ -2312,9 +2442,11 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | |||
2312 | enum ieee80211_band band; | 2442 | enum ieee80211_band band; |
2313 | size_t ie_len; | 2443 | size_t ie_len; |
2314 | 2444 | ||
2445 | rtnl_lock(); | ||
2446 | |||
2315 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | 2447 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); |
2316 | if (err) | 2448 | if (err) |
2317 | return err; | 2449 | goto out_rtnl; |
2318 | 2450 | ||
2319 | wiphy = &drv->wiphy; | 2451 | wiphy = &drv->wiphy; |
2320 | 2452 | ||
@@ -2323,11 +2455,14 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | |||
2323 | goto out; | 2455 | goto out; |
2324 | } | 2456 | } |
2325 | 2457 | ||
2326 | rtnl_lock(); | 2458 | if (!netif_running(dev)) { |
2459 | err = -ENETDOWN; | ||
2460 | goto out; | ||
2461 | } | ||
2327 | 2462 | ||
2328 | if (drv->scan_req) { | 2463 | if (drv->scan_req) { |
2329 | err = -EBUSY; | 2464 | err = -EBUSY; |
2330 | goto out_unlock; | 2465 | goto out; |
2331 | } | 2466 | } |
2332 | 2467 | ||
2333 | if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) { | 2468 | if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) { |
@@ -2335,7 +2470,7 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | |||
2335 | n_channels++; | 2470 | n_channels++; |
2336 | if (!n_channels) { | 2471 | if (!n_channels) { |
2337 | err = -EINVAL; | 2472 | err = -EINVAL; |
2338 | goto out_unlock; | 2473 | goto out; |
2339 | } | 2474 | } |
2340 | } else { | 2475 | } else { |
2341 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) | 2476 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) |
@@ -2349,7 +2484,7 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | |||
2349 | 2484 | ||
2350 | if (n_ssids > wiphy->max_scan_ssids) { | 2485 | if (n_ssids > wiphy->max_scan_ssids) { |
2351 | err = -EINVAL; | 2486 | err = -EINVAL; |
2352 | goto out_unlock; | 2487 | goto out; |
2353 | } | 2488 | } |
2354 | 2489 | ||
2355 | if (info->attrs[NL80211_ATTR_IE]) | 2490 | if (info->attrs[NL80211_ATTR_IE]) |
@@ -2363,7 +2498,7 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | |||
2363 | + ie_len, GFP_KERNEL); | 2498 | + ie_len, GFP_KERNEL); |
2364 | if (!request) { | 2499 | if (!request) { |
2365 | err = -ENOMEM; | 2500 | err = -ENOMEM; |
2366 | goto out_unlock; | 2501 | goto out; |
2367 | } | 2502 | } |
2368 | 2503 | ||
2369 | request->channels = (void *)((char *)request + sizeof(*request)); | 2504 | request->channels = (void *)((char *)request + sizeof(*request)); |
@@ -2434,11 +2569,12 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) | |||
2434 | drv->scan_req = NULL; | 2569 | drv->scan_req = NULL; |
2435 | kfree(request); | 2570 | kfree(request); |
2436 | } | 2571 | } |
2437 | out_unlock: | ||
2438 | rtnl_unlock(); | ||
2439 | out: | 2572 | out: |
2440 | cfg80211_put_dev(drv); | 2573 | cfg80211_put_dev(drv); |
2441 | dev_put(dev); | 2574 | dev_put(dev); |
2575 | out_rtnl: | ||
2576 | rtnl_unlock(); | ||
2577 | |||
2442 | return err; | 2578 | return err; |
2443 | } | 2579 | } |
2444 | 2580 | ||
@@ -2558,6 +2694,288 @@ static int nl80211_dump_scan(struct sk_buff *skb, | |||
2558 | return err; | 2694 | return err; |
2559 | } | 2695 | } |
2560 | 2696 | ||
2697 | static bool nl80211_valid_auth_type(enum nl80211_auth_type auth_type) | ||
2698 | { | ||
2699 | return auth_type == NL80211_AUTHTYPE_OPEN_SYSTEM || | ||
2700 | auth_type == NL80211_AUTHTYPE_SHARED_KEY || | ||
2701 | auth_type == NL80211_AUTHTYPE_FT || | ||
2702 | auth_type == NL80211_AUTHTYPE_NETWORK_EAP; | ||
2703 | } | ||
2704 | |||
2705 | static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) | ||
2706 | { | ||
2707 | struct cfg80211_registered_device *drv; | ||
2708 | struct net_device *dev; | ||
2709 | struct cfg80211_auth_request req; | ||
2710 | struct wiphy *wiphy; | ||
2711 | int err; | ||
2712 | |||
2713 | rtnl_lock(); | ||
2714 | |||
2715 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | ||
2716 | if (err) | ||
2717 | goto unlock_rtnl; | ||
2718 | |||
2719 | if (!drv->ops->auth) { | ||
2720 | err = -EOPNOTSUPP; | ||
2721 | goto out; | ||
2722 | } | ||
2723 | |||
2724 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) { | ||
2725 | err = -EOPNOTSUPP; | ||
2726 | goto out; | ||
2727 | } | ||
2728 | |||
2729 | if (!netif_running(dev)) { | ||
2730 | err = -ENETDOWN; | ||
2731 | goto out; | ||
2732 | } | ||
2733 | |||
2734 | if (!info->attrs[NL80211_ATTR_MAC]) { | ||
2735 | err = -EINVAL; | ||
2736 | goto out; | ||
2737 | } | ||
2738 | |||
2739 | wiphy = &drv->wiphy; | ||
2740 | memset(&req, 0, sizeof(req)); | ||
2741 | |||
2742 | req.peer_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | ||
2743 | |||
2744 | if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) { | ||
2745 | req.chan = ieee80211_get_channel( | ||
2746 | wiphy, | ||
2747 | nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); | ||
2748 | if (!req.chan) { | ||
2749 | err = -EINVAL; | ||
2750 | goto out; | ||
2751 | } | ||
2752 | } | ||
2753 | |||
2754 | if (info->attrs[NL80211_ATTR_SSID]) { | ||
2755 | req.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); | ||
2756 | req.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]); | ||
2757 | } | ||
2758 | |||
2759 | if (info->attrs[NL80211_ATTR_IE]) { | ||
2760 | req.ie = nla_data(info->attrs[NL80211_ATTR_IE]); | ||
2761 | req.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); | ||
2762 | } | ||
2763 | |||
2764 | if (info->attrs[NL80211_ATTR_AUTH_TYPE]) { | ||
2765 | req.auth_type = | ||
2766 | nla_get_u32(info->attrs[NL80211_ATTR_AUTH_TYPE]); | ||
2767 | if (!nl80211_valid_auth_type(req.auth_type)) { | ||
2768 | err = -EINVAL; | ||
2769 | goto out; | ||
2770 | } | ||
2771 | } | ||
2772 | |||
2773 | err = drv->ops->auth(&drv->wiphy, dev, &req); | ||
2774 | |||
2775 | out: | ||
2776 | cfg80211_put_dev(drv); | ||
2777 | dev_put(dev); | ||
2778 | unlock_rtnl: | ||
2779 | rtnl_unlock(); | ||
2780 | return err; | ||
2781 | } | ||
2782 | |||
2783 | static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) | ||
2784 | { | ||
2785 | struct cfg80211_registered_device *drv; | ||
2786 | struct net_device *dev; | ||
2787 | struct cfg80211_assoc_request req; | ||
2788 | struct wiphy *wiphy; | ||
2789 | int err; | ||
2790 | |||
2791 | rtnl_lock(); | ||
2792 | |||
2793 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | ||
2794 | if (err) | ||
2795 | goto unlock_rtnl; | ||
2796 | |||
2797 | if (!drv->ops->assoc) { | ||
2798 | err = -EOPNOTSUPP; | ||
2799 | goto out; | ||
2800 | } | ||
2801 | |||
2802 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) { | ||
2803 | err = -EOPNOTSUPP; | ||
2804 | goto out; | ||
2805 | } | ||
2806 | |||
2807 | if (!netif_running(dev)) { | ||
2808 | err = -ENETDOWN; | ||
2809 | goto out; | ||
2810 | } | ||
2811 | |||
2812 | if (!info->attrs[NL80211_ATTR_MAC] || | ||
2813 | !info->attrs[NL80211_ATTR_SSID]) { | ||
2814 | err = -EINVAL; | ||
2815 | goto out; | ||
2816 | } | ||
2817 | |||
2818 | wiphy = &drv->wiphy; | ||
2819 | memset(&req, 0, sizeof(req)); | ||
2820 | |||
2821 | req.peer_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | ||
2822 | |||
2823 | if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) { | ||
2824 | req.chan = ieee80211_get_channel( | ||
2825 | wiphy, | ||
2826 | nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); | ||
2827 | if (!req.chan) { | ||
2828 | err = -EINVAL; | ||
2829 | goto out; | ||
2830 | } | ||
2831 | } | ||
2832 | |||
2833 | req.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); | ||
2834 | req.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]); | ||
2835 | |||
2836 | if (info->attrs[NL80211_ATTR_IE]) { | ||
2837 | req.ie = nla_data(info->attrs[NL80211_ATTR_IE]); | ||
2838 | req.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); | ||
2839 | } | ||
2840 | |||
2841 | err = drv->ops->assoc(&drv->wiphy, dev, &req); | ||
2842 | |||
2843 | out: | ||
2844 | cfg80211_put_dev(drv); | ||
2845 | dev_put(dev); | ||
2846 | unlock_rtnl: | ||
2847 | rtnl_unlock(); | ||
2848 | return err; | ||
2849 | } | ||
2850 | |||
2851 | static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info) | ||
2852 | { | ||
2853 | struct cfg80211_registered_device *drv; | ||
2854 | struct net_device *dev; | ||
2855 | struct cfg80211_deauth_request req; | ||
2856 | struct wiphy *wiphy; | ||
2857 | int err; | ||
2858 | |||
2859 | rtnl_lock(); | ||
2860 | |||
2861 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | ||
2862 | if (err) | ||
2863 | goto unlock_rtnl; | ||
2864 | |||
2865 | if (!drv->ops->deauth) { | ||
2866 | err = -EOPNOTSUPP; | ||
2867 | goto out; | ||
2868 | } | ||
2869 | |||
2870 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) { | ||
2871 | err = -EOPNOTSUPP; | ||
2872 | goto out; | ||
2873 | } | ||
2874 | |||
2875 | if (!netif_running(dev)) { | ||
2876 | err = -ENETDOWN; | ||
2877 | goto out; | ||
2878 | } | ||
2879 | |||
2880 | if (!info->attrs[NL80211_ATTR_MAC]) { | ||
2881 | err = -EINVAL; | ||
2882 | goto out; | ||
2883 | } | ||
2884 | |||
2885 | wiphy = &drv->wiphy; | ||
2886 | memset(&req, 0, sizeof(req)); | ||
2887 | |||
2888 | req.peer_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | ||
2889 | |||
2890 | if (info->attrs[NL80211_ATTR_REASON_CODE]) { | ||
2891 | req.reason_code = | ||
2892 | nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]); | ||
2893 | if (req.reason_code == 0) { | ||
2894 | /* Reason Code 0 is reserved */ | ||
2895 | err = -EINVAL; | ||
2896 | goto out; | ||
2897 | } | ||
2898 | } | ||
2899 | |||
2900 | if (info->attrs[NL80211_ATTR_IE]) { | ||
2901 | req.ie = nla_data(info->attrs[NL80211_ATTR_IE]); | ||
2902 | req.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); | ||
2903 | } | ||
2904 | |||
2905 | err = drv->ops->deauth(&drv->wiphy, dev, &req); | ||
2906 | |||
2907 | out: | ||
2908 | cfg80211_put_dev(drv); | ||
2909 | dev_put(dev); | ||
2910 | unlock_rtnl: | ||
2911 | rtnl_unlock(); | ||
2912 | return err; | ||
2913 | } | ||
2914 | |||
2915 | static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info) | ||
2916 | { | ||
2917 | struct cfg80211_registered_device *drv; | ||
2918 | struct net_device *dev; | ||
2919 | struct cfg80211_disassoc_request req; | ||
2920 | struct wiphy *wiphy; | ||
2921 | int err; | ||
2922 | |||
2923 | rtnl_lock(); | ||
2924 | |||
2925 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | ||
2926 | if (err) | ||
2927 | goto unlock_rtnl; | ||
2928 | |||
2929 | if (!drv->ops->disassoc) { | ||
2930 | err = -EOPNOTSUPP; | ||
2931 | goto out; | ||
2932 | } | ||
2933 | |||
2934 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) { | ||
2935 | err = -EOPNOTSUPP; | ||
2936 | goto out; | ||
2937 | } | ||
2938 | |||
2939 | if (!netif_running(dev)) { | ||
2940 | err = -ENETDOWN; | ||
2941 | goto out; | ||
2942 | } | ||
2943 | |||
2944 | if (!info->attrs[NL80211_ATTR_MAC]) { | ||
2945 | err = -EINVAL; | ||
2946 | goto out; | ||
2947 | } | ||
2948 | |||
2949 | wiphy = &drv->wiphy; | ||
2950 | memset(&req, 0, sizeof(req)); | ||
2951 | |||
2952 | req.peer_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | ||
2953 | |||
2954 | if (info->attrs[NL80211_ATTR_REASON_CODE]) { | ||
2955 | req.reason_code = | ||
2956 | nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]); | ||
2957 | if (req.reason_code == 0) { | ||
2958 | /* Reason Code 0 is reserved */ | ||
2959 | err = -EINVAL; | ||
2960 | goto out; | ||
2961 | } | ||
2962 | } | ||
2963 | |||
2964 | if (info->attrs[NL80211_ATTR_IE]) { | ||
2965 | req.ie = nla_data(info->attrs[NL80211_ATTR_IE]); | ||
2966 | req.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); | ||
2967 | } | ||
2968 | |||
2969 | err = drv->ops->disassoc(&drv->wiphy, dev, &req); | ||
2970 | |||
2971 | out: | ||
2972 | cfg80211_put_dev(drv); | ||
2973 | dev_put(dev); | ||
2974 | unlock_rtnl: | ||
2975 | rtnl_unlock(); | ||
2976 | return err; | ||
2977 | } | ||
2978 | |||
2561 | static struct genl_ops nl80211_ops[] = { | 2979 | static struct genl_ops nl80211_ops[] = { |
2562 | { | 2980 | { |
2563 | .cmd = NL80211_CMD_GET_WIPHY, | 2981 | .cmd = NL80211_CMD_GET_WIPHY, |
@@ -2725,12 +3143,6 @@ static struct genl_ops nl80211_ops[] = { | |||
2725 | .flags = GENL_ADMIN_PERM, | 3143 | .flags = GENL_ADMIN_PERM, |
2726 | }, | 3144 | }, |
2727 | { | 3145 | { |
2728 | .cmd = NL80211_CMD_SET_MGMT_EXTRA_IE, | ||
2729 | .doit = nl80211_set_mgmt_extra_ie, | ||
2730 | .policy = nl80211_policy, | ||
2731 | .flags = GENL_ADMIN_PERM, | ||
2732 | }, | ||
2733 | { | ||
2734 | .cmd = NL80211_CMD_TRIGGER_SCAN, | 3146 | .cmd = NL80211_CMD_TRIGGER_SCAN, |
2735 | .doit = nl80211_trigger_scan, | 3147 | .doit = nl80211_trigger_scan, |
2736 | .policy = nl80211_policy, | 3148 | .policy = nl80211_policy, |
@@ -2741,6 +3153,33 @@ static struct genl_ops nl80211_ops[] = { | |||
2741 | .policy = nl80211_policy, | 3153 | .policy = nl80211_policy, |
2742 | .dumpit = nl80211_dump_scan, | 3154 | .dumpit = nl80211_dump_scan, |
2743 | }, | 3155 | }, |
3156 | { | ||
3157 | .cmd = NL80211_CMD_AUTHENTICATE, | ||
3158 | .doit = nl80211_authenticate, | ||
3159 | .policy = nl80211_policy, | ||
3160 | .flags = GENL_ADMIN_PERM, | ||
3161 | }, | ||
3162 | { | ||
3163 | .cmd = NL80211_CMD_ASSOCIATE, | ||
3164 | .doit = nl80211_associate, | ||
3165 | .policy = nl80211_policy, | ||
3166 | .flags = GENL_ADMIN_PERM, | ||
3167 | }, | ||
3168 | { | ||
3169 | .cmd = NL80211_CMD_DEAUTHENTICATE, | ||
3170 | .doit = nl80211_deauthenticate, | ||
3171 | .policy = nl80211_policy, | ||
3172 | .flags = GENL_ADMIN_PERM, | ||
3173 | }, | ||
3174 | { | ||
3175 | .cmd = NL80211_CMD_DISASSOCIATE, | ||
3176 | .doit = nl80211_disassociate, | ||
3177 | .policy = nl80211_policy, | ||
3178 | .flags = GENL_ADMIN_PERM, | ||
3179 | }, | ||
3180 | }; | ||
3181 | static struct genl_multicast_group nl80211_mlme_mcgrp = { | ||
3182 | .name = "mlme", | ||
2744 | }; | 3183 | }; |
2745 | 3184 | ||
2746 | /* multicast groups */ | 3185 | /* multicast groups */ |
@@ -2887,6 +3326,71 @@ nla_put_failure: | |||
2887 | nlmsg_free(msg); | 3326 | nlmsg_free(msg); |
2888 | } | 3327 | } |
2889 | 3328 | ||
3329 | static void nl80211_send_mlme_event(struct cfg80211_registered_device *rdev, | ||
3330 | struct net_device *netdev, | ||
3331 | const u8 *buf, size_t len, | ||
3332 | enum nl80211_commands cmd) | ||
3333 | { | ||
3334 | struct sk_buff *msg; | ||
3335 | void *hdr; | ||
3336 | |||
3337 | msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); | ||
3338 | if (!msg) | ||
3339 | return; | ||
3340 | |||
3341 | hdr = nl80211hdr_put(msg, 0, 0, 0, cmd); | ||
3342 | if (!hdr) { | ||
3343 | nlmsg_free(msg); | ||
3344 | return; | ||
3345 | } | ||
3346 | |||
3347 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); | ||
3348 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); | ||
3349 | NLA_PUT(msg, NL80211_ATTR_FRAME, len, buf); | ||
3350 | |||
3351 | if (genlmsg_end(msg, hdr) < 0) { | ||
3352 | nlmsg_free(msg); | ||
3353 | return; | ||
3354 | } | ||
3355 | |||
3356 | genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, GFP_KERNEL); | ||
3357 | return; | ||
3358 | |||
3359 | nla_put_failure: | ||
3360 | genlmsg_cancel(msg, hdr); | ||
3361 | nlmsg_free(msg); | ||
3362 | } | ||
3363 | |||
3364 | void nl80211_send_rx_auth(struct cfg80211_registered_device *rdev, | ||
3365 | struct net_device *netdev, const u8 *buf, size_t len) | ||
3366 | { | ||
3367 | nl80211_send_mlme_event(rdev, netdev, buf, len, | ||
3368 | NL80211_CMD_AUTHENTICATE); | ||
3369 | } | ||
3370 | |||
3371 | void nl80211_send_rx_assoc(struct cfg80211_registered_device *rdev, | ||
3372 | struct net_device *netdev, const u8 *buf, | ||
3373 | size_t len) | ||
3374 | { | ||
3375 | nl80211_send_mlme_event(rdev, netdev, buf, len, NL80211_CMD_ASSOCIATE); | ||
3376 | } | ||
3377 | |||
3378 | void nl80211_send_rx_deauth(struct cfg80211_registered_device *rdev, | ||
3379 | struct net_device *netdev, const u8 *buf, | ||
3380 | size_t len) | ||
3381 | { | ||
3382 | nl80211_send_mlme_event(rdev, netdev, buf, len, | ||
3383 | NL80211_CMD_DEAUTHENTICATE); | ||
3384 | } | ||
3385 | |||
3386 | void nl80211_send_rx_disassoc(struct cfg80211_registered_device *rdev, | ||
3387 | struct net_device *netdev, const u8 *buf, | ||
3388 | size_t len) | ||
3389 | { | ||
3390 | nl80211_send_mlme_event(rdev, netdev, buf, len, | ||
3391 | NL80211_CMD_DISASSOCIATE); | ||
3392 | } | ||
3393 | |||
2890 | /* initialisation/exit functions */ | 3394 | /* initialisation/exit functions */ |
2891 | 3395 | ||
2892 | int nl80211_init(void) | 3396 | int nl80211_init(void) |
@@ -2915,6 +3419,10 @@ int nl80211_init(void) | |||
2915 | if (err) | 3419 | if (err) |
2916 | goto err_out; | 3420 | goto err_out; |
2917 | 3421 | ||
3422 | err = genl_register_mc_group(&nl80211_fam, &nl80211_mlme_mcgrp); | ||
3423 | if (err) | ||
3424 | goto err_out; | ||
3425 | |||
2918 | return 0; | 3426 | return 0; |
2919 | err_out: | 3427 | err_out: |
2920 | genl_unregister_family(&nl80211_fam); | 3428 | genl_unregister_family(&nl80211_fam); |
diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h index e65a3c38c52f..b77af4ab80be 100644 --- a/net/wireless/nl80211.h +++ b/net/wireless/nl80211.h | |||
@@ -3,7 +3,6 @@ | |||
3 | 3 | ||
4 | #include "core.h" | 4 | #include "core.h" |
5 | 5 | ||
6 | #ifdef CONFIG_NL80211 | ||
7 | extern int nl80211_init(void); | 6 | extern int nl80211_init(void); |
8 | extern void nl80211_exit(void); | 7 | extern void nl80211_exit(void); |
9 | extern void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev); | 8 | extern void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev); |
@@ -12,30 +11,17 @@ extern void nl80211_send_scan_done(struct cfg80211_registered_device *rdev, | |||
12 | extern void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev, | 11 | extern void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev, |
13 | struct net_device *netdev); | 12 | struct net_device *netdev); |
14 | extern void nl80211_send_reg_change_event(struct regulatory_request *request); | 13 | extern void nl80211_send_reg_change_event(struct regulatory_request *request); |
15 | #else | 14 | extern void nl80211_send_rx_auth(struct cfg80211_registered_device *rdev, |
16 | static inline int nl80211_init(void) | 15 | struct net_device *netdev, |
17 | { | 16 | const u8 *buf, size_t len); |
18 | return 0; | 17 | extern void nl80211_send_rx_assoc(struct cfg80211_registered_device *rdev, |
19 | } | 18 | struct net_device *netdev, |
20 | static inline void nl80211_exit(void) | 19 | const u8 *buf, size_t len); |
21 | { | 20 | extern void nl80211_send_rx_deauth(struct cfg80211_registered_device *rdev, |
22 | } | 21 | struct net_device *netdev, |
23 | static inline void nl80211_notify_dev_rename( | 22 | const u8 *buf, size_t len); |
24 | struct cfg80211_registered_device *rdev) | 23 | extern void nl80211_send_rx_disassoc(struct cfg80211_registered_device *rdev, |
25 | { | 24 | struct net_device *netdev, |
26 | } | 25 | const u8 *buf, size_t len); |
27 | static inline void | ||
28 | nl80211_send_scan_done(struct cfg80211_registered_device *rdev, | ||
29 | struct net_device *netdev) | ||
30 | {} | ||
31 | static inline void nl80211_send_scan_aborted( | ||
32 | struct cfg80211_registered_device *rdev, | ||
33 | struct net_device *netdev) | ||
34 | {} | ||
35 | static inline void | ||
36 | nl80211_send_reg_change_event(struct regulatory_request *request) | ||
37 | { | ||
38 | } | ||
39 | #endif /* CONFIG_NL80211 */ | ||
40 | 26 | ||
41 | #endif /* __NET_WIRELESS_NL80211_H */ | 27 | #endif /* __NET_WIRELESS_NL80211_H */ |
diff --git a/net/wireless/reg.c b/net/wireless/reg.c index eb8b8ed16155..6327e1617acb 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c | |||
@@ -122,9 +122,14 @@ static const struct ieee80211_regdomain *cfg80211_world_regdom = | |||
122 | 122 | ||
123 | #ifdef CONFIG_WIRELESS_OLD_REGULATORY | 123 | #ifdef CONFIG_WIRELESS_OLD_REGULATORY |
124 | static char *ieee80211_regdom = "US"; | 124 | static char *ieee80211_regdom = "US"; |
125 | #else | ||
126 | static char *ieee80211_regdom = "00"; | ||
127 | #endif | ||
128 | |||
125 | module_param(ieee80211_regdom, charp, 0444); | 129 | module_param(ieee80211_regdom, charp, 0444); |
126 | MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code"); | 130 | MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code"); |
127 | 131 | ||
132 | #ifdef CONFIG_WIRELESS_OLD_REGULATORY | ||
128 | /* | 133 | /* |
129 | * We assume 40 MHz bandwidth for the old regulatory work. | 134 | * We assume 40 MHz bandwidth for the old regulatory work. |
130 | * We make emphasis we are using the exact same frequencies | 135 | * We make emphasis we are using the exact same frequencies |
@@ -1415,16 +1420,6 @@ new_request: | |||
1415 | return r; | 1420 | return r; |
1416 | } | 1421 | } |
1417 | 1422 | ||
1418 | /* | ||
1419 | * Note: When CONFIG_WIRELESS_OLD_REGULATORY is enabled | ||
1420 | * AND if CRDA is NOT present nothing will happen, if someone | ||
1421 | * wants to bother with 11d with OLD_REG you can add a timer. | ||
1422 | * If after x amount of time nothing happens you can call: | ||
1423 | * | ||
1424 | * return set_regdom(country_ie_regdomain); | ||
1425 | * | ||
1426 | * to intersect with the static rd | ||
1427 | */ | ||
1428 | return call_crda(last_request->alpha2); | 1423 | return call_crda(last_request->alpha2); |
1429 | } | 1424 | } |
1430 | 1425 | ||
@@ -1601,6 +1596,10 @@ static bool reg_same_country_ie_hint(struct wiphy *wiphy, | |||
1601 | 1596 | ||
1602 | assert_cfg80211_lock(); | 1597 | assert_cfg80211_lock(); |
1603 | 1598 | ||
1599 | if (unlikely(last_request->initiator != | ||
1600 | NL80211_REGDOM_SET_BY_COUNTRY_IE)) | ||
1601 | return false; | ||
1602 | |||
1604 | request_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx); | 1603 | request_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx); |
1605 | 1604 | ||
1606 | if (!request_wiphy) | 1605 | if (!request_wiphy) |
@@ -1663,7 +1662,9 @@ void regulatory_hint_11d(struct wiphy *wiphy, | |||
1663 | * we optimize an early check to exit out early if we don't have to | 1662 | * we optimize an early check to exit out early if we don't have to |
1664 | * do anything | 1663 | * do anything |
1665 | */ | 1664 | */ |
1666 | if (likely(wiphy_idx_valid(last_request->wiphy_idx))) { | 1665 | if (likely(last_request->initiator == |
1666 | NL80211_REGDOM_SET_BY_COUNTRY_IE && | ||
1667 | wiphy_idx_valid(last_request->wiphy_idx))) { | ||
1667 | struct cfg80211_registered_device *drv_last_ie; | 1668 | struct cfg80211_registered_device *drv_last_ie; |
1668 | 1669 | ||
1669 | drv_last_ie = | 1670 | drv_last_ie = |
@@ -2022,28 +2023,21 @@ static int __set_regdom(const struct ieee80211_regdomain *rd) | |||
2022 | */ | 2023 | */ |
2023 | 2024 | ||
2024 | BUG_ON(!country_ie_regdomain); | 2025 | BUG_ON(!country_ie_regdomain); |
2026 | BUG_ON(rd == country_ie_regdomain); | ||
2025 | 2027 | ||
2026 | if (rd != country_ie_regdomain) { | 2028 | /* |
2027 | /* | 2029 | * Intersect what CRDA returned and our what we |
2028 | * Intersect what CRDA returned and our what we | 2030 | * had built from the Country IE received |
2029 | * had built from the Country IE received | 2031 | */ |
2030 | */ | ||
2031 | 2032 | ||
2032 | intersected_rd = regdom_intersect(rd, country_ie_regdomain); | 2033 | intersected_rd = regdom_intersect(rd, country_ie_regdomain); |
2033 | 2034 | ||
2034 | reg_country_ie_process_debug(rd, country_ie_regdomain, | 2035 | reg_country_ie_process_debug(rd, |
2035 | intersected_rd); | 2036 | country_ie_regdomain, |
2037 | intersected_rd); | ||
2036 | 2038 | ||
2037 | kfree(country_ie_regdomain); | 2039 | kfree(country_ie_regdomain); |
2038 | country_ie_regdomain = NULL; | 2040 | country_ie_regdomain = NULL; |
2039 | } else { | ||
2040 | /* | ||
2041 | * This would happen when CRDA was not present and | ||
2042 | * OLD_REGULATORY was enabled. We intersect our Country | ||
2043 | * IE rd and what was set on cfg80211 originally | ||
2044 | */ | ||
2045 | intersected_rd = regdom_intersect(rd, cfg80211_regdomain); | ||
2046 | } | ||
2047 | 2041 | ||
2048 | if (!intersected_rd) | 2042 | if (!intersected_rd) |
2049 | return -EINVAL; | 2043 | return -EINVAL; |
@@ -2135,15 +2129,18 @@ int regulatory_init(void) | |||
2135 | /* | 2129 | /* |
2136 | * The old code still requests for a new regdomain and if | 2130 | * The old code still requests for a new regdomain and if |
2137 | * you have CRDA you get it updated, otherwise you get | 2131 | * you have CRDA you get it updated, otherwise you get |
2138 | * stuck with the static values. We ignore "EU" code as | 2132 | * stuck with the static values. Since "EU" is not a valid |
2139 | * that is not a valid ISO / IEC 3166 alpha2 | 2133 | * ISO / IEC 3166 alpha2 code we can't expect userpace to |
2134 | * give us a regulatory domain for it. We need last_request | ||
2135 | * iniitalized though so lets just send a request which we | ||
2136 | * know will be ignored... this crap will be removed once | ||
2137 | * OLD_REG dies. | ||
2140 | */ | 2138 | */ |
2141 | if (ieee80211_regdom[0] != 'E' || ieee80211_regdom[1] != 'U') | 2139 | err = regulatory_hint_core(ieee80211_regdom); |
2142 | err = regulatory_hint_core(ieee80211_regdom); | ||
2143 | #else | 2140 | #else |
2144 | cfg80211_regdomain = cfg80211_world_regdom; | 2141 | cfg80211_regdomain = cfg80211_world_regdom; |
2145 | 2142 | ||
2146 | err = regulatory_hint_core("00"); | 2143 | err = regulatory_hint_core(ieee80211_regdom); |
2147 | #endif | 2144 | #endif |
2148 | if (err) { | 2145 | if (err) { |
2149 | if (err == -ENOMEM) | 2146 | if (err == -ENOMEM) |
diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 280dbcd02c15..2a00e362f5fe 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c | |||
@@ -80,7 +80,8 @@ void cfg80211_bss_expire(struct cfg80211_registered_device *dev) | |||
80 | bool expired = false; | 80 | bool expired = false; |
81 | 81 | ||
82 | list_for_each_entry_safe(bss, tmp, &dev->bss_list, list) { | 82 | list_for_each_entry_safe(bss, tmp, &dev->bss_list, list) { |
83 | if (!time_after(jiffies, bss->ts + IEEE80211_SCAN_RESULT_EXPIRE)) | 83 | if (bss->hold || |
84 | !time_after(jiffies, bss->ts + IEEE80211_SCAN_RESULT_EXPIRE)) | ||
84 | continue; | 85 | continue; |
85 | list_del(&bss->list); | 86 | list_del(&bss->list); |
86 | rb_erase(&bss->rbn, &dev->bss_tree); | 87 | rb_erase(&bss->rbn, &dev->bss_tree); |
@@ -471,6 +472,30 @@ void cfg80211_unlink_bss(struct wiphy *wiphy, struct cfg80211_bss *pub) | |||
471 | } | 472 | } |
472 | EXPORT_SYMBOL(cfg80211_unlink_bss); | 473 | EXPORT_SYMBOL(cfg80211_unlink_bss); |
473 | 474 | ||
475 | void cfg80211_hold_bss(struct cfg80211_bss *pub) | ||
476 | { | ||
477 | struct cfg80211_internal_bss *bss; | ||
478 | |||
479 | if (!pub) | ||
480 | return; | ||
481 | |||
482 | bss = container_of(pub, struct cfg80211_internal_bss, pub); | ||
483 | bss->hold = true; | ||
484 | } | ||
485 | EXPORT_SYMBOL(cfg80211_hold_bss); | ||
486 | |||
487 | void cfg80211_unhold_bss(struct cfg80211_bss *pub) | ||
488 | { | ||
489 | struct cfg80211_internal_bss *bss; | ||
490 | |||
491 | if (!pub) | ||
492 | return; | ||
493 | |||
494 | bss = container_of(pub, struct cfg80211_internal_bss, pub); | ||
495 | bss->hold = false; | ||
496 | } | ||
497 | EXPORT_SYMBOL(cfg80211_unhold_bss); | ||
498 | |||
474 | #ifdef CONFIG_WIRELESS_EXT | 499 | #ifdef CONFIG_WIRELESS_EXT |
475 | int cfg80211_wext_siwscan(struct net_device *dev, | 500 | int cfg80211_wext_siwscan(struct net_device *dev, |
476 | struct iw_request_info *info, | 501 | struct iw_request_info *info, |
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index b84a9b4fe96a..0fd1db6e95bb 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c | |||
@@ -66,6 +66,7 @@ int cfg80211_wext_siwmode(struct net_device *dev, struct iw_request_info *info, | |||
66 | struct cfg80211_registered_device *rdev; | 66 | struct cfg80211_registered_device *rdev; |
67 | struct vif_params vifparams; | 67 | struct vif_params vifparams; |
68 | enum nl80211_iftype type; | 68 | enum nl80211_iftype type; |
69 | int ret; | ||
69 | 70 | ||
70 | if (!wdev) | 71 | if (!wdev) |
71 | return -EOPNOTSUPP; | 72 | return -EOPNOTSUPP; |
@@ -96,10 +97,16 @@ int cfg80211_wext_siwmode(struct net_device *dev, struct iw_request_info *info, | |||
96 | return -EINVAL; | 97 | return -EINVAL; |
97 | } | 98 | } |
98 | 99 | ||
100 | if (type == wdev->iftype) | ||
101 | return 0; | ||
102 | |||
99 | memset(&vifparams, 0, sizeof(vifparams)); | 103 | memset(&vifparams, 0, sizeof(vifparams)); |
100 | 104 | ||
101 | return rdev->ops->change_virtual_intf(wdev->wiphy, dev->ifindex, type, | 105 | ret = rdev->ops->change_virtual_intf(wdev->wiphy, dev->ifindex, type, |
102 | NULL, &vifparams); | 106 | NULL, &vifparams); |
107 | WARN_ON(!ret && wdev->iftype != type); | ||
108 | |||
109 | return ret; | ||
103 | } | 110 | } |
104 | EXPORT_SYMBOL(cfg80211_wext_siwmode); | 111 | EXPORT_SYMBOL(cfg80211_wext_siwmode); |
105 | 112 | ||
diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c index 9ca17b1ce52e..ed80af8ca5fb 100644 --- a/net/x25/af_x25.c +++ b/net/x25/af_x25.c | |||
@@ -1035,6 +1035,12 @@ static int x25_sendmsg(struct kiocb *iocb, struct socket *sock, | |||
1035 | sx25.sx25_addr = x25->dest_addr; | 1035 | sx25.sx25_addr = x25->dest_addr; |
1036 | } | 1036 | } |
1037 | 1037 | ||
1038 | /* Sanity check the packet size */ | ||
1039 | if (len > 65535) { | ||
1040 | rc = -EMSGSIZE; | ||
1041 | goto out; | ||
1042 | } | ||
1043 | |||
1038 | SOCK_DEBUG(sk, "x25_sendmsg: sendto: Addresses built.\n"); | 1044 | SOCK_DEBUG(sk, "x25_sendmsg: sendto: Addresses built.\n"); |
1039 | 1045 | ||
1040 | /* Build a packet */ | 1046 | /* Build a packet */ |
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index 62a5425cc6aa..82271720d970 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c | |||
@@ -1615,7 +1615,7 @@ void xfrm_state_walk_done(struct xfrm_state_walk *walk) | |||
1615 | 1615 | ||
1616 | spin_lock_bh(&xfrm_state_lock); | 1616 | spin_lock_bh(&xfrm_state_lock); |
1617 | list_del(&walk->all); | 1617 | list_del(&walk->all); |
1618 | spin_lock_bh(&xfrm_state_lock); | 1618 | spin_unlock_bh(&xfrm_state_lock); |
1619 | } | 1619 | } |
1620 | EXPORT_SYMBOL(xfrm_state_walk_done); | 1620 | EXPORT_SYMBOL(xfrm_state_walk_done); |
1621 | 1621 | ||