diff options
author | Dave Airlie <airlied@redhat.com> | 2017-04-10 17:40:42 -0400 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2017-04-10 17:40:42 -0400 |
commit | b769fefb68cd70385d68220ae341e5a10723fbc0 (patch) | |
tree | a2881410c9dc5a3474619d155fac981cfbd4ee8f /net | |
parent | 1420f63b8207e966f54caec26d08abdc2ff37193 (diff) | |
parent | 39da7c509acff13fc8cb12ec1bb20337c988ed36 (diff) |
Backmerge tag 'v4.11-rc6' into drm-next
Linux 4.11-rc6
drm-misc needs 4.11-rc5, may as well fix conflicts with rc6.
Diffstat (limited to 'net')
43 files changed, 673 insertions, 376 deletions
diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c index c35aae13c8d2..d98d4998213d 100644 --- a/net/core/flow_dissector.c +++ b/net/core/flow_dissector.c | |||
@@ -390,7 +390,7 @@ mpls: | |||
390 | unsigned char ar_tip[4]; | 390 | unsigned char ar_tip[4]; |
391 | } *arp_eth, _arp_eth; | 391 | } *arp_eth, _arp_eth; |
392 | const struct arphdr *arp; | 392 | const struct arphdr *arp; |
393 | struct arphdr *_arp; | 393 | struct arphdr _arp; |
394 | 394 | ||
395 | arp = __skb_header_pointer(skb, nhoff, sizeof(_arp), data, | 395 | arp = __skb_header_pointer(skb, nhoff, sizeof(_arp), data, |
396 | hlen, &_arp); | 396 | hlen, &_arp); |
diff --git a/net/core/neighbour.c b/net/core/neighbour.c index e7c12caa20c8..4526cbd7e28a 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c | |||
@@ -860,7 +860,8 @@ static void neigh_probe(struct neighbour *neigh) | |||
860 | if (skb) | 860 | if (skb) |
861 | skb = skb_clone(skb, GFP_ATOMIC); | 861 | skb = skb_clone(skb, GFP_ATOMIC); |
862 | write_unlock(&neigh->lock); | 862 | write_unlock(&neigh->lock); |
863 | neigh->ops->solicit(neigh, skb); | 863 | if (neigh->ops->solicit) |
864 | neigh->ops->solicit(neigh, skb); | ||
864 | atomic_inc(&neigh->probes); | 865 | atomic_inc(&neigh->probes); |
865 | kfree_skb(skb); | 866 | kfree_skb(skb); |
866 | } | 867 | } |
diff --git a/net/core/secure_seq.c b/net/core/secure_seq.c index 758f140b6bed..d28da7d363f1 100644 --- a/net/core/secure_seq.c +++ b/net/core/secure_seq.c | |||
@@ -20,9 +20,11 @@ | |||
20 | #include <net/tcp.h> | 20 | #include <net/tcp.h> |
21 | 21 | ||
22 | static siphash_key_t net_secret __read_mostly; | 22 | static siphash_key_t net_secret __read_mostly; |
23 | static siphash_key_t ts_secret __read_mostly; | ||
23 | 24 | ||
24 | static __always_inline void net_secret_init(void) | 25 | static __always_inline void net_secret_init(void) |
25 | { | 26 | { |
27 | net_get_random_once(&ts_secret, sizeof(ts_secret)); | ||
26 | net_get_random_once(&net_secret, sizeof(net_secret)); | 28 | net_get_random_once(&net_secret, sizeof(net_secret)); |
27 | } | 29 | } |
28 | #endif | 30 | #endif |
@@ -45,6 +47,23 @@ static u32 seq_scale(u32 seq) | |||
45 | #endif | 47 | #endif |
46 | 48 | ||
47 | #if IS_ENABLED(CONFIG_IPV6) | 49 | #if IS_ENABLED(CONFIG_IPV6) |
50 | static u32 secure_tcpv6_ts_off(const __be32 *saddr, const __be32 *daddr) | ||
51 | { | ||
52 | const struct { | ||
53 | struct in6_addr saddr; | ||
54 | struct in6_addr daddr; | ||
55 | } __aligned(SIPHASH_ALIGNMENT) combined = { | ||
56 | .saddr = *(struct in6_addr *)saddr, | ||
57 | .daddr = *(struct in6_addr *)daddr, | ||
58 | }; | ||
59 | |||
60 | if (sysctl_tcp_timestamps != 1) | ||
61 | return 0; | ||
62 | |||
63 | return siphash(&combined, offsetofend(typeof(combined), daddr), | ||
64 | &ts_secret); | ||
65 | } | ||
66 | |||
48 | u32 secure_tcpv6_sequence_number(const __be32 *saddr, const __be32 *daddr, | 67 | u32 secure_tcpv6_sequence_number(const __be32 *saddr, const __be32 *daddr, |
49 | __be16 sport, __be16 dport, u32 *tsoff) | 68 | __be16 sport, __be16 dport, u32 *tsoff) |
50 | { | 69 | { |
@@ -63,7 +82,7 @@ u32 secure_tcpv6_sequence_number(const __be32 *saddr, const __be32 *daddr, | |||
63 | net_secret_init(); | 82 | net_secret_init(); |
64 | hash = siphash(&combined, offsetofend(typeof(combined), dport), | 83 | hash = siphash(&combined, offsetofend(typeof(combined), dport), |
65 | &net_secret); | 84 | &net_secret); |
66 | *tsoff = sysctl_tcp_timestamps == 1 ? (hash >> 32) : 0; | 85 | *tsoff = secure_tcpv6_ts_off(saddr, daddr); |
67 | return seq_scale(hash); | 86 | return seq_scale(hash); |
68 | } | 87 | } |
69 | EXPORT_SYMBOL(secure_tcpv6_sequence_number); | 88 | EXPORT_SYMBOL(secure_tcpv6_sequence_number); |
@@ -88,6 +107,14 @@ EXPORT_SYMBOL(secure_ipv6_port_ephemeral); | |||
88 | #endif | 107 | #endif |
89 | 108 | ||
90 | #ifdef CONFIG_INET | 109 | #ifdef CONFIG_INET |
110 | static u32 secure_tcp_ts_off(__be32 saddr, __be32 daddr) | ||
111 | { | ||
112 | if (sysctl_tcp_timestamps != 1) | ||
113 | return 0; | ||
114 | |||
115 | return siphash_2u32((__force u32)saddr, (__force u32)daddr, | ||
116 | &ts_secret); | ||
117 | } | ||
91 | 118 | ||
92 | /* secure_tcp_sequence_number(a, b, 0, d) == secure_ipv4_port_ephemeral(a, b, d), | 119 | /* secure_tcp_sequence_number(a, b, 0, d) == secure_ipv4_port_ephemeral(a, b, d), |
93 | * but fortunately, `sport' cannot be 0 in any circumstances. If this changes, | 120 | * but fortunately, `sport' cannot be 0 in any circumstances. If this changes, |
@@ -103,7 +130,7 @@ u32 secure_tcp_sequence_number(__be32 saddr, __be32 daddr, | |||
103 | hash = siphash_3u32((__force u32)saddr, (__force u32)daddr, | 130 | hash = siphash_3u32((__force u32)saddr, (__force u32)daddr, |
104 | (__force u32)sport << 16 | (__force u32)dport, | 131 | (__force u32)sport << 16 | (__force u32)dport, |
105 | &net_secret); | 132 | &net_secret); |
106 | *tsoff = sysctl_tcp_timestamps == 1 ? (hash >> 32) : 0; | 133 | *tsoff = secure_tcp_ts_off(saddr, daddr); |
107 | return seq_scale(hash); | 134 | return seq_scale(hash); |
108 | } | 135 | } |
109 | 136 | ||
diff --git a/net/core/sysctl_net_core.c b/net/core/sysctl_net_core.c index 4ead336e14ea..7f9cc400eca0 100644 --- a/net/core/sysctl_net_core.c +++ b/net/core/sysctl_net_core.c | |||
@@ -408,14 +408,16 @@ static struct ctl_table net_core_table[] = { | |||
408 | .data = &sysctl_net_busy_poll, | 408 | .data = &sysctl_net_busy_poll, |
409 | .maxlen = sizeof(unsigned int), | 409 | .maxlen = sizeof(unsigned int), |
410 | .mode = 0644, | 410 | .mode = 0644, |
411 | .proc_handler = proc_dointvec | 411 | .proc_handler = proc_dointvec_minmax, |
412 | .extra1 = &zero, | ||
412 | }, | 413 | }, |
413 | { | 414 | { |
414 | .procname = "busy_read", | 415 | .procname = "busy_read", |
415 | .data = &sysctl_net_busy_read, | 416 | .data = &sysctl_net_busy_read, |
416 | .maxlen = sizeof(unsigned int), | 417 | .maxlen = sizeof(unsigned int), |
417 | .mode = 0644, | 418 | .mode = 0644, |
418 | .proc_handler = proc_dointvec | 419 | .proc_handler = proc_dointvec_minmax, |
420 | .extra1 = &zero, | ||
419 | }, | 421 | }, |
420 | #endif | 422 | #endif |
421 | #ifdef CONFIG_NET_SCHED | 423 | #ifdef CONFIG_NET_SCHED |
diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c index fd9f34bbd740..dfb2ab2dd3c8 100644 --- a/net/ipv4/ipconfig.c +++ b/net/ipv4/ipconfig.c | |||
@@ -306,7 +306,7 @@ static void __init ic_close_devs(void) | |||
306 | while ((d = next)) { | 306 | while ((d = next)) { |
307 | next = d->next; | 307 | next = d->next; |
308 | dev = d->dev; | 308 | dev = d->dev; |
309 | if ((!ic_dev || dev != ic_dev->dev) && !netdev_uses_dsa(dev)) { | 309 | if (d != ic_dev && !netdev_uses_dsa(dev)) { |
310 | pr_debug("IP-Config: Downing %s\n", dev->name); | 310 | pr_debug("IP-Config: Downing %s\n", dev->name); |
311 | dev_change_flags(dev, d->flags); | 311 | dev_change_flags(dev, d->flags); |
312 | } | 312 | } |
diff --git a/net/ipv4/netfilter/nf_nat_snmp_basic.c b/net/ipv4/netfilter/nf_nat_snmp_basic.c index c9b52c361da2..53e49f5011d3 100644 --- a/net/ipv4/netfilter/nf_nat_snmp_basic.c +++ b/net/ipv4/netfilter/nf_nat_snmp_basic.c | |||
@@ -1260,16 +1260,6 @@ static const struct nf_conntrack_expect_policy snmp_exp_policy = { | |||
1260 | .timeout = 180, | 1260 | .timeout = 180, |
1261 | }; | 1261 | }; |
1262 | 1262 | ||
1263 | static struct nf_conntrack_helper snmp_helper __read_mostly = { | ||
1264 | .me = THIS_MODULE, | ||
1265 | .help = help, | ||
1266 | .expect_policy = &snmp_exp_policy, | ||
1267 | .name = "snmp", | ||
1268 | .tuple.src.l3num = AF_INET, | ||
1269 | .tuple.src.u.udp.port = cpu_to_be16(SNMP_PORT), | ||
1270 | .tuple.dst.protonum = IPPROTO_UDP, | ||
1271 | }; | ||
1272 | |||
1273 | static struct nf_conntrack_helper snmp_trap_helper __read_mostly = { | 1263 | static struct nf_conntrack_helper snmp_trap_helper __read_mostly = { |
1274 | .me = THIS_MODULE, | 1264 | .me = THIS_MODULE, |
1275 | .help = help, | 1265 | .help = help, |
@@ -1288,22 +1278,16 @@ static struct nf_conntrack_helper snmp_trap_helper __read_mostly = { | |||
1288 | 1278 | ||
1289 | static int __init nf_nat_snmp_basic_init(void) | 1279 | static int __init nf_nat_snmp_basic_init(void) |
1290 | { | 1280 | { |
1291 | int ret = 0; | ||
1292 | |||
1293 | BUG_ON(nf_nat_snmp_hook != NULL); | 1281 | BUG_ON(nf_nat_snmp_hook != NULL); |
1294 | RCU_INIT_POINTER(nf_nat_snmp_hook, help); | 1282 | RCU_INIT_POINTER(nf_nat_snmp_hook, help); |
1295 | 1283 | ||
1296 | ret = nf_conntrack_helper_register(&snmp_trap_helper); | 1284 | return nf_conntrack_helper_register(&snmp_trap_helper); |
1297 | if (ret < 0) { | ||
1298 | nf_conntrack_helper_unregister(&snmp_helper); | ||
1299 | return ret; | ||
1300 | } | ||
1301 | return ret; | ||
1302 | } | 1285 | } |
1303 | 1286 | ||
1304 | static void __exit nf_nat_snmp_basic_fini(void) | 1287 | static void __exit nf_nat_snmp_basic_fini(void) |
1305 | { | 1288 | { |
1306 | RCU_INIT_POINTER(nf_nat_snmp_hook, NULL); | 1289 | RCU_INIT_POINTER(nf_nat_snmp_hook, NULL); |
1290 | synchronize_rcu(); | ||
1307 | nf_conntrack_helper_unregister(&snmp_trap_helper); | 1291 | nf_conntrack_helper_unregister(&snmp_trap_helper); |
1308 | } | 1292 | } |
1309 | 1293 | ||
diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c index 2af6244b83e2..ccfbce13a633 100644 --- a/net/ipv4/ping.c +++ b/net/ipv4/ping.c | |||
@@ -156,17 +156,18 @@ int ping_hash(struct sock *sk) | |||
156 | void ping_unhash(struct sock *sk) | 156 | void ping_unhash(struct sock *sk) |
157 | { | 157 | { |
158 | struct inet_sock *isk = inet_sk(sk); | 158 | struct inet_sock *isk = inet_sk(sk); |
159 | |||
159 | pr_debug("ping_unhash(isk=%p,isk->num=%u)\n", isk, isk->inet_num); | 160 | pr_debug("ping_unhash(isk=%p,isk->num=%u)\n", isk, isk->inet_num); |
161 | write_lock_bh(&ping_table.lock); | ||
160 | if (sk_hashed(sk)) { | 162 | if (sk_hashed(sk)) { |
161 | write_lock_bh(&ping_table.lock); | ||
162 | hlist_nulls_del(&sk->sk_nulls_node); | 163 | hlist_nulls_del(&sk->sk_nulls_node); |
163 | sk_nulls_node_init(&sk->sk_nulls_node); | 164 | sk_nulls_node_init(&sk->sk_nulls_node); |
164 | sock_put(sk); | 165 | sock_put(sk); |
165 | isk->inet_num = 0; | 166 | isk->inet_num = 0; |
166 | isk->inet_sport = 0; | 167 | isk->inet_sport = 0; |
167 | sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1); | 168 | sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1); |
168 | write_unlock_bh(&ping_table.lock); | ||
169 | } | 169 | } |
170 | write_unlock_bh(&ping_table.lock); | ||
170 | } | 171 | } |
171 | EXPORT_SYMBOL_GPL(ping_unhash); | 172 | EXPORT_SYMBOL_GPL(ping_unhash); |
172 | 173 | ||
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index c43119726a62..2c1f59386a7b 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c | |||
@@ -126,7 +126,8 @@ int sysctl_tcp_invalid_ratelimit __read_mostly = HZ/2; | |||
126 | #define REXMIT_LOST 1 /* retransmit packets marked lost */ | 126 | #define REXMIT_LOST 1 /* retransmit packets marked lost */ |
127 | #define REXMIT_NEW 2 /* FRTO-style transmit of unsent/new packets */ | 127 | #define REXMIT_NEW 2 /* FRTO-style transmit of unsent/new packets */ |
128 | 128 | ||
129 | static void tcp_gro_dev_warn(struct sock *sk, const struct sk_buff *skb) | 129 | static void tcp_gro_dev_warn(struct sock *sk, const struct sk_buff *skb, |
130 | unsigned int len) | ||
130 | { | 131 | { |
131 | static bool __once __read_mostly; | 132 | static bool __once __read_mostly; |
132 | 133 | ||
@@ -137,8 +138,9 @@ static void tcp_gro_dev_warn(struct sock *sk, const struct sk_buff *skb) | |||
137 | 138 | ||
138 | rcu_read_lock(); | 139 | rcu_read_lock(); |
139 | dev = dev_get_by_index_rcu(sock_net(sk), skb->skb_iif); | 140 | dev = dev_get_by_index_rcu(sock_net(sk), skb->skb_iif); |
140 | pr_warn("%s: Driver has suspect GRO implementation, TCP performance may be compromised.\n", | 141 | if (!dev || len >= dev->mtu) |
141 | dev ? dev->name : "Unknown driver"); | 142 | pr_warn("%s: Driver has suspect GRO implementation, TCP performance may be compromised.\n", |
143 | dev ? dev->name : "Unknown driver"); | ||
142 | rcu_read_unlock(); | 144 | rcu_read_unlock(); |
143 | } | 145 | } |
144 | } | 146 | } |
@@ -161,8 +163,10 @@ static void tcp_measure_rcv_mss(struct sock *sk, const struct sk_buff *skb) | |||
161 | if (len >= icsk->icsk_ack.rcv_mss) { | 163 | if (len >= icsk->icsk_ack.rcv_mss) { |
162 | icsk->icsk_ack.rcv_mss = min_t(unsigned int, len, | 164 | icsk->icsk_ack.rcv_mss = min_t(unsigned int, len, |
163 | tcp_sk(sk)->advmss); | 165 | tcp_sk(sk)->advmss); |
164 | if (unlikely(icsk->icsk_ack.rcv_mss != len)) | 166 | /* Account for possibly-removed options */ |
165 | tcp_gro_dev_warn(sk, skb); | 167 | if (unlikely(len > icsk->icsk_ack.rcv_mss + |
168 | MAX_TCP_OPTION_SPACE)) | ||
169 | tcp_gro_dev_warn(sk, skb, len); | ||
166 | } else { | 170 | } else { |
167 | /* Otherwise, we make more careful check taking into account, | 171 | /* Otherwise, we make more careful check taking into account, |
168 | * that SACKs block is variable. | 172 | * that SACKs block is variable. |
@@ -874,22 +878,11 @@ static void tcp_update_reordering(struct sock *sk, const int metric, | |||
874 | const int ts) | 878 | const int ts) |
875 | { | 879 | { |
876 | struct tcp_sock *tp = tcp_sk(sk); | 880 | struct tcp_sock *tp = tcp_sk(sk); |
877 | if (metric > tp->reordering) { | 881 | int mib_idx; |
878 | int mib_idx; | ||
879 | 882 | ||
883 | if (metric > tp->reordering) { | ||
880 | tp->reordering = min(sysctl_tcp_max_reordering, metric); | 884 | tp->reordering = min(sysctl_tcp_max_reordering, metric); |
881 | 885 | ||
882 | /* This exciting event is worth to be remembered. 8) */ | ||
883 | if (ts) | ||
884 | mib_idx = LINUX_MIB_TCPTSREORDER; | ||
885 | else if (tcp_is_reno(tp)) | ||
886 | mib_idx = LINUX_MIB_TCPRENOREORDER; | ||
887 | else if (tcp_is_fack(tp)) | ||
888 | mib_idx = LINUX_MIB_TCPFACKREORDER; | ||
889 | else | ||
890 | mib_idx = LINUX_MIB_TCPSACKREORDER; | ||
891 | |||
892 | NET_INC_STATS(sock_net(sk), mib_idx); | ||
893 | #if FASTRETRANS_DEBUG > 1 | 886 | #if FASTRETRANS_DEBUG > 1 |
894 | pr_debug("Disorder%d %d %u f%u s%u rr%d\n", | 887 | pr_debug("Disorder%d %d %u f%u s%u rr%d\n", |
895 | tp->rx_opt.sack_ok, inet_csk(sk)->icsk_ca_state, | 888 | tp->rx_opt.sack_ok, inet_csk(sk)->icsk_ca_state, |
@@ -902,6 +895,18 @@ static void tcp_update_reordering(struct sock *sk, const int metric, | |||
902 | } | 895 | } |
903 | 896 | ||
904 | tp->rack.reord = 1; | 897 | tp->rack.reord = 1; |
898 | |||
899 | /* This exciting event is worth to be remembered. 8) */ | ||
900 | if (ts) | ||
901 | mib_idx = LINUX_MIB_TCPTSREORDER; | ||
902 | else if (tcp_is_reno(tp)) | ||
903 | mib_idx = LINUX_MIB_TCPRENOREORDER; | ||
904 | else if (tcp_is_fack(tp)) | ||
905 | mib_idx = LINUX_MIB_TCPFACKREORDER; | ||
906 | else | ||
907 | mib_idx = LINUX_MIB_TCPSACKREORDER; | ||
908 | |||
909 | NET_INC_STATS(sock_net(sk), mib_idx); | ||
905 | } | 910 | } |
906 | 911 | ||
907 | /* This must be called before lost_out is incremented */ | 912 | /* This must be called before lost_out is incremented */ |
diff --git a/net/ipv4/tcp_recovery.c b/net/ipv4/tcp_recovery.c index 4ecb38ae8504..d8acbd9f477a 100644 --- a/net/ipv4/tcp_recovery.c +++ b/net/ipv4/tcp_recovery.c | |||
@@ -12,7 +12,8 @@ static void tcp_rack_mark_skb_lost(struct sock *sk, struct sk_buff *skb) | |||
12 | /* Account for retransmits that are lost again */ | 12 | /* Account for retransmits that are lost again */ |
13 | TCP_SKB_CB(skb)->sacked &= ~TCPCB_SACKED_RETRANS; | 13 | TCP_SKB_CB(skb)->sacked &= ~TCPCB_SACKED_RETRANS; |
14 | tp->retrans_out -= tcp_skb_pcount(skb); | 14 | tp->retrans_out -= tcp_skb_pcount(skb); |
15 | NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPLOSTRETRANSMIT); | 15 | NET_ADD_STATS(sock_net(sk), LINUX_MIB_TCPLOSTRETRANSMIT, |
16 | tcp_skb_pcount(skb)); | ||
16 | } | 17 | } |
17 | } | 18 | } |
18 | 19 | ||
diff --git a/net/kcm/kcmsock.c b/net/kcm/kcmsock.c index 309062f3debe..31762f76cdb5 100644 --- a/net/kcm/kcmsock.c +++ b/net/kcm/kcmsock.c | |||
@@ -1687,7 +1687,7 @@ static int kcm_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) | |||
1687 | struct kcm_attach info; | 1687 | struct kcm_attach info; |
1688 | 1688 | ||
1689 | if (copy_from_user(&info, (void __user *)arg, sizeof(info))) | 1689 | if (copy_from_user(&info, (void __user *)arg, sizeof(info))) |
1690 | err = -EFAULT; | 1690 | return -EFAULT; |
1691 | 1691 | ||
1692 | err = kcm_attach_ioctl(sock, &info); | 1692 | err = kcm_attach_ioctl(sock, &info); |
1693 | 1693 | ||
@@ -1697,7 +1697,7 @@ static int kcm_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) | |||
1697 | struct kcm_unattach info; | 1697 | struct kcm_unattach info; |
1698 | 1698 | ||
1699 | if (copy_from_user(&info, (void __user *)arg, sizeof(info))) | 1699 | if (copy_from_user(&info, (void __user *)arg, sizeof(info))) |
1700 | err = -EFAULT; | 1700 | return -EFAULT; |
1701 | 1701 | ||
1702 | err = kcm_unattach_ioctl(sock, &info); | 1702 | err = kcm_unattach_ioctl(sock, &info); |
1703 | 1703 | ||
@@ -1708,7 +1708,7 @@ static int kcm_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) | |||
1708 | struct socket *newsock = NULL; | 1708 | struct socket *newsock = NULL; |
1709 | 1709 | ||
1710 | if (copy_from_user(&info, (void __user *)arg, sizeof(info))) | 1710 | if (copy_from_user(&info, (void __user *)arg, sizeof(info))) |
1711 | err = -EFAULT; | 1711 | return -EFAULT; |
1712 | 1712 | ||
1713 | err = kcm_clone(sock, &info, &newsock); | 1713 | err = kcm_clone(sock, &info, &newsock); |
1714 | 1714 | ||
diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c index 8adab6335ced..e37d9554da7b 100644 --- a/net/l2tp/l2tp_core.c +++ b/net/l2tp/l2tp_core.c | |||
@@ -278,7 +278,57 @@ struct l2tp_session *l2tp_session_find(struct net *net, struct l2tp_tunnel *tunn | |||
278 | } | 278 | } |
279 | EXPORT_SYMBOL_GPL(l2tp_session_find); | 279 | EXPORT_SYMBOL_GPL(l2tp_session_find); |
280 | 280 | ||
281 | struct l2tp_session *l2tp_session_find_nth(struct l2tp_tunnel *tunnel, int nth) | 281 | /* Like l2tp_session_find() but takes a reference on the returned session. |
282 | * Optionally calls session->ref() too if do_ref is true. | ||
283 | */ | ||
284 | struct l2tp_session *l2tp_session_get(struct net *net, | ||
285 | struct l2tp_tunnel *tunnel, | ||
286 | u32 session_id, bool do_ref) | ||
287 | { | ||
288 | struct hlist_head *session_list; | ||
289 | struct l2tp_session *session; | ||
290 | |||
291 | if (!tunnel) { | ||
292 | struct l2tp_net *pn = l2tp_pernet(net); | ||
293 | |||
294 | session_list = l2tp_session_id_hash_2(pn, session_id); | ||
295 | |||
296 | rcu_read_lock_bh(); | ||
297 | hlist_for_each_entry_rcu(session, session_list, global_hlist) { | ||
298 | if (session->session_id == session_id) { | ||
299 | l2tp_session_inc_refcount(session); | ||
300 | if (do_ref && session->ref) | ||
301 | session->ref(session); | ||
302 | rcu_read_unlock_bh(); | ||
303 | |||
304 | return session; | ||
305 | } | ||
306 | } | ||
307 | rcu_read_unlock_bh(); | ||
308 | |||
309 | return NULL; | ||
310 | } | ||
311 | |||
312 | session_list = l2tp_session_id_hash(tunnel, session_id); | ||
313 | read_lock_bh(&tunnel->hlist_lock); | ||
314 | hlist_for_each_entry(session, session_list, hlist) { | ||
315 | if (session->session_id == session_id) { | ||
316 | l2tp_session_inc_refcount(session); | ||
317 | if (do_ref && session->ref) | ||
318 | session->ref(session); | ||
319 | read_unlock_bh(&tunnel->hlist_lock); | ||
320 | |||
321 | return session; | ||
322 | } | ||
323 | } | ||
324 | read_unlock_bh(&tunnel->hlist_lock); | ||
325 | |||
326 | return NULL; | ||
327 | } | ||
328 | EXPORT_SYMBOL_GPL(l2tp_session_get); | ||
329 | |||
330 | struct l2tp_session *l2tp_session_get_nth(struct l2tp_tunnel *tunnel, int nth, | ||
331 | bool do_ref) | ||
282 | { | 332 | { |
283 | int hash; | 333 | int hash; |
284 | struct l2tp_session *session; | 334 | struct l2tp_session *session; |
@@ -288,6 +338,9 @@ struct l2tp_session *l2tp_session_find_nth(struct l2tp_tunnel *tunnel, int nth) | |||
288 | for (hash = 0; hash < L2TP_HASH_SIZE; hash++) { | 338 | for (hash = 0; hash < L2TP_HASH_SIZE; hash++) { |
289 | hlist_for_each_entry(session, &tunnel->session_hlist[hash], hlist) { | 339 | hlist_for_each_entry(session, &tunnel->session_hlist[hash], hlist) { |
290 | if (++count > nth) { | 340 | if (++count > nth) { |
341 | l2tp_session_inc_refcount(session); | ||
342 | if (do_ref && session->ref) | ||
343 | session->ref(session); | ||
291 | read_unlock_bh(&tunnel->hlist_lock); | 344 | read_unlock_bh(&tunnel->hlist_lock); |
292 | return session; | 345 | return session; |
293 | } | 346 | } |
@@ -298,12 +351,13 @@ struct l2tp_session *l2tp_session_find_nth(struct l2tp_tunnel *tunnel, int nth) | |||
298 | 351 | ||
299 | return NULL; | 352 | return NULL; |
300 | } | 353 | } |
301 | EXPORT_SYMBOL_GPL(l2tp_session_find_nth); | 354 | EXPORT_SYMBOL_GPL(l2tp_session_get_nth); |
302 | 355 | ||
303 | /* Lookup a session by interface name. | 356 | /* Lookup a session by interface name. |
304 | * This is very inefficient but is only used by management interfaces. | 357 | * This is very inefficient but is only used by management interfaces. |
305 | */ | 358 | */ |
306 | struct l2tp_session *l2tp_session_find_by_ifname(struct net *net, char *ifname) | 359 | struct l2tp_session *l2tp_session_get_by_ifname(struct net *net, char *ifname, |
360 | bool do_ref) | ||
307 | { | 361 | { |
308 | struct l2tp_net *pn = l2tp_pernet(net); | 362 | struct l2tp_net *pn = l2tp_pernet(net); |
309 | int hash; | 363 | int hash; |
@@ -313,7 +367,11 @@ struct l2tp_session *l2tp_session_find_by_ifname(struct net *net, char *ifname) | |||
313 | for (hash = 0; hash < L2TP_HASH_SIZE_2; hash++) { | 367 | for (hash = 0; hash < L2TP_HASH_SIZE_2; hash++) { |
314 | hlist_for_each_entry_rcu(session, &pn->l2tp_session_hlist[hash], global_hlist) { | 368 | hlist_for_each_entry_rcu(session, &pn->l2tp_session_hlist[hash], global_hlist) { |
315 | if (!strcmp(session->ifname, ifname)) { | 369 | if (!strcmp(session->ifname, ifname)) { |
370 | l2tp_session_inc_refcount(session); | ||
371 | if (do_ref && session->ref) | ||
372 | session->ref(session); | ||
316 | rcu_read_unlock_bh(); | 373 | rcu_read_unlock_bh(); |
374 | |||
317 | return session; | 375 | return session; |
318 | } | 376 | } |
319 | } | 377 | } |
@@ -323,7 +381,49 @@ struct l2tp_session *l2tp_session_find_by_ifname(struct net *net, char *ifname) | |||
323 | 381 | ||
324 | return NULL; | 382 | return NULL; |
325 | } | 383 | } |
326 | EXPORT_SYMBOL_GPL(l2tp_session_find_by_ifname); | 384 | EXPORT_SYMBOL_GPL(l2tp_session_get_by_ifname); |
385 | |||
386 | static int l2tp_session_add_to_tunnel(struct l2tp_tunnel *tunnel, | ||
387 | struct l2tp_session *session) | ||
388 | { | ||
389 | struct l2tp_session *session_walk; | ||
390 | struct hlist_head *g_head; | ||
391 | struct hlist_head *head; | ||
392 | struct l2tp_net *pn; | ||
393 | |||
394 | head = l2tp_session_id_hash(tunnel, session->session_id); | ||
395 | |||
396 | write_lock_bh(&tunnel->hlist_lock); | ||
397 | hlist_for_each_entry(session_walk, head, hlist) | ||
398 | if (session_walk->session_id == session->session_id) | ||
399 | goto exist; | ||
400 | |||
401 | if (tunnel->version == L2TP_HDR_VER_3) { | ||
402 | pn = l2tp_pernet(tunnel->l2tp_net); | ||
403 | g_head = l2tp_session_id_hash_2(l2tp_pernet(tunnel->l2tp_net), | ||
404 | session->session_id); | ||
405 | |||
406 | spin_lock_bh(&pn->l2tp_session_hlist_lock); | ||
407 | hlist_for_each_entry(session_walk, g_head, global_hlist) | ||
408 | if (session_walk->session_id == session->session_id) | ||
409 | goto exist_glob; | ||
410 | |||
411 | hlist_add_head_rcu(&session->global_hlist, g_head); | ||
412 | spin_unlock_bh(&pn->l2tp_session_hlist_lock); | ||
413 | } | ||
414 | |||
415 | hlist_add_head(&session->hlist, head); | ||
416 | write_unlock_bh(&tunnel->hlist_lock); | ||
417 | |||
418 | return 0; | ||
419 | |||
420 | exist_glob: | ||
421 | spin_unlock_bh(&pn->l2tp_session_hlist_lock); | ||
422 | exist: | ||
423 | write_unlock_bh(&tunnel->hlist_lock); | ||
424 | |||
425 | return -EEXIST; | ||
426 | } | ||
327 | 427 | ||
328 | /* Lookup a tunnel by id | 428 | /* Lookup a tunnel by id |
329 | */ | 429 | */ |
@@ -633,6 +733,9 @@ discard: | |||
633 | * a data (not control) frame before coming here. Fields up to the | 733 | * a data (not control) frame before coming here. Fields up to the |
634 | * session-id have already been parsed and ptr points to the data | 734 | * session-id have already been parsed and ptr points to the data |
635 | * after the session-id. | 735 | * after the session-id. |
736 | * | ||
737 | * session->ref() must have been called prior to l2tp_recv_common(). | ||
738 | * session->deref() will be called automatically after skb is processed. | ||
636 | */ | 739 | */ |
637 | void l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb, | 740 | void l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb, |
638 | unsigned char *ptr, unsigned char *optr, u16 hdrflags, | 741 | unsigned char *ptr, unsigned char *optr, u16 hdrflags, |
@@ -642,14 +745,6 @@ void l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb, | |||
642 | int offset; | 745 | int offset; |
643 | u32 ns, nr; | 746 | u32 ns, nr; |
644 | 747 | ||
645 | /* The ref count is increased since we now hold a pointer to | ||
646 | * the session. Take care to decrement the refcnt when exiting | ||
647 | * this function from now on... | ||
648 | */ | ||
649 | l2tp_session_inc_refcount(session); | ||
650 | if (session->ref) | ||
651 | (*session->ref)(session); | ||
652 | |||
653 | /* Parse and check optional cookie */ | 748 | /* Parse and check optional cookie */ |
654 | if (session->peer_cookie_len > 0) { | 749 | if (session->peer_cookie_len > 0) { |
655 | if (memcmp(ptr, &session->peer_cookie[0], session->peer_cookie_len)) { | 750 | if (memcmp(ptr, &session->peer_cookie[0], session->peer_cookie_len)) { |
@@ -802,8 +897,6 @@ void l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb, | |||
802 | /* Try to dequeue as many skbs from reorder_q as we can. */ | 897 | /* Try to dequeue as many skbs from reorder_q as we can. */ |
803 | l2tp_recv_dequeue(session); | 898 | l2tp_recv_dequeue(session); |
804 | 899 | ||
805 | l2tp_session_dec_refcount(session); | ||
806 | |||
807 | return; | 900 | return; |
808 | 901 | ||
809 | discard: | 902 | discard: |
@@ -812,8 +905,6 @@ discard: | |||
812 | 905 | ||
813 | if (session->deref) | 906 | if (session->deref) |
814 | (*session->deref)(session); | 907 | (*session->deref)(session); |
815 | |||
816 | l2tp_session_dec_refcount(session); | ||
817 | } | 908 | } |
818 | EXPORT_SYMBOL(l2tp_recv_common); | 909 | EXPORT_SYMBOL(l2tp_recv_common); |
819 | 910 | ||
@@ -920,8 +1011,14 @@ static int l2tp_udp_recv_core(struct l2tp_tunnel *tunnel, struct sk_buff *skb, | |||
920 | } | 1011 | } |
921 | 1012 | ||
922 | /* Find the session context */ | 1013 | /* Find the session context */ |
923 | session = l2tp_session_find(tunnel->l2tp_net, tunnel, session_id); | 1014 | session = l2tp_session_get(tunnel->l2tp_net, tunnel, session_id, true); |
924 | if (!session || !session->recv_skb) { | 1015 | if (!session || !session->recv_skb) { |
1016 | if (session) { | ||
1017 | if (session->deref) | ||
1018 | session->deref(session); | ||
1019 | l2tp_session_dec_refcount(session); | ||
1020 | } | ||
1021 | |||
925 | /* Not found? Pass to userspace to deal with */ | 1022 | /* Not found? Pass to userspace to deal with */ |
926 | l2tp_info(tunnel, L2TP_MSG_DATA, | 1023 | l2tp_info(tunnel, L2TP_MSG_DATA, |
927 | "%s: no session found (%u/%u). Passing up.\n", | 1024 | "%s: no session found (%u/%u). Passing up.\n", |
@@ -930,6 +1027,7 @@ static int l2tp_udp_recv_core(struct l2tp_tunnel *tunnel, struct sk_buff *skb, | |||
930 | } | 1027 | } |
931 | 1028 | ||
932 | l2tp_recv_common(session, skb, ptr, optr, hdrflags, length, payload_hook); | 1029 | l2tp_recv_common(session, skb, ptr, optr, hdrflags, length, payload_hook); |
1030 | l2tp_session_dec_refcount(session); | ||
933 | 1031 | ||
934 | return 0; | 1032 | return 0; |
935 | 1033 | ||
@@ -1738,6 +1836,7 @@ EXPORT_SYMBOL_GPL(l2tp_session_set_header_len); | |||
1738 | struct l2tp_session *l2tp_session_create(int priv_size, struct l2tp_tunnel *tunnel, u32 session_id, u32 peer_session_id, struct l2tp_session_cfg *cfg) | 1836 | struct l2tp_session *l2tp_session_create(int priv_size, struct l2tp_tunnel *tunnel, u32 session_id, u32 peer_session_id, struct l2tp_session_cfg *cfg) |
1739 | { | 1837 | { |
1740 | struct l2tp_session *session; | 1838 | struct l2tp_session *session; |
1839 | int err; | ||
1741 | 1840 | ||
1742 | session = kzalloc(sizeof(struct l2tp_session) + priv_size, GFP_KERNEL); | 1841 | session = kzalloc(sizeof(struct l2tp_session) + priv_size, GFP_KERNEL); |
1743 | if (session != NULL) { | 1842 | if (session != NULL) { |
@@ -1793,6 +1892,13 @@ struct l2tp_session *l2tp_session_create(int priv_size, struct l2tp_tunnel *tunn | |||
1793 | 1892 | ||
1794 | l2tp_session_set_header_len(session, tunnel->version); | 1893 | l2tp_session_set_header_len(session, tunnel->version); |
1795 | 1894 | ||
1895 | err = l2tp_session_add_to_tunnel(tunnel, session); | ||
1896 | if (err) { | ||
1897 | kfree(session); | ||
1898 | |||
1899 | return ERR_PTR(err); | ||
1900 | } | ||
1901 | |||
1796 | /* Bump the reference count. The session context is deleted | 1902 | /* Bump the reference count. The session context is deleted |
1797 | * only when this drops to zero. | 1903 | * only when this drops to zero. |
1798 | */ | 1904 | */ |
@@ -1802,28 +1908,14 @@ struct l2tp_session *l2tp_session_create(int priv_size, struct l2tp_tunnel *tunn | |||
1802 | /* Ensure tunnel socket isn't deleted */ | 1908 | /* Ensure tunnel socket isn't deleted */ |
1803 | sock_hold(tunnel->sock); | 1909 | sock_hold(tunnel->sock); |
1804 | 1910 | ||
1805 | /* Add session to the tunnel's hash list */ | ||
1806 | write_lock_bh(&tunnel->hlist_lock); | ||
1807 | hlist_add_head(&session->hlist, | ||
1808 | l2tp_session_id_hash(tunnel, session_id)); | ||
1809 | write_unlock_bh(&tunnel->hlist_lock); | ||
1810 | |||
1811 | /* And to the global session list if L2TPv3 */ | ||
1812 | if (tunnel->version != L2TP_HDR_VER_2) { | ||
1813 | struct l2tp_net *pn = l2tp_pernet(tunnel->l2tp_net); | ||
1814 | |||
1815 | spin_lock_bh(&pn->l2tp_session_hlist_lock); | ||
1816 | hlist_add_head_rcu(&session->global_hlist, | ||
1817 | l2tp_session_id_hash_2(pn, session_id)); | ||
1818 | spin_unlock_bh(&pn->l2tp_session_hlist_lock); | ||
1819 | } | ||
1820 | |||
1821 | /* Ignore management session in session count value */ | 1911 | /* Ignore management session in session count value */ |
1822 | if (session->session_id != 0) | 1912 | if (session->session_id != 0) |
1823 | atomic_inc(&l2tp_session_count); | 1913 | atomic_inc(&l2tp_session_count); |
1914 | |||
1915 | return session; | ||
1824 | } | 1916 | } |
1825 | 1917 | ||
1826 | return session; | 1918 | return ERR_PTR(-ENOMEM); |
1827 | } | 1919 | } |
1828 | EXPORT_SYMBOL_GPL(l2tp_session_create); | 1920 | EXPORT_SYMBOL_GPL(l2tp_session_create); |
1829 | 1921 | ||
diff --git a/net/l2tp/l2tp_core.h b/net/l2tp/l2tp_core.h index aebf281d09ee..8ce7818c7a9d 100644 --- a/net/l2tp/l2tp_core.h +++ b/net/l2tp/l2tp_core.h | |||
@@ -230,11 +230,16 @@ out: | |||
230 | return tunnel; | 230 | return tunnel; |
231 | } | 231 | } |
232 | 232 | ||
233 | struct l2tp_session *l2tp_session_get(struct net *net, | ||
234 | struct l2tp_tunnel *tunnel, | ||
235 | u32 session_id, bool do_ref); | ||
233 | struct l2tp_session *l2tp_session_find(struct net *net, | 236 | struct l2tp_session *l2tp_session_find(struct net *net, |
234 | struct l2tp_tunnel *tunnel, | 237 | struct l2tp_tunnel *tunnel, |
235 | u32 session_id); | 238 | u32 session_id); |
236 | struct l2tp_session *l2tp_session_find_nth(struct l2tp_tunnel *tunnel, int nth); | 239 | struct l2tp_session *l2tp_session_get_nth(struct l2tp_tunnel *tunnel, int nth, |
237 | struct l2tp_session *l2tp_session_find_by_ifname(struct net *net, char *ifname); | 240 | bool do_ref); |
241 | struct l2tp_session *l2tp_session_get_by_ifname(struct net *net, char *ifname, | ||
242 | bool do_ref); | ||
238 | struct l2tp_tunnel *l2tp_tunnel_find(struct net *net, u32 tunnel_id); | 243 | struct l2tp_tunnel *l2tp_tunnel_find(struct net *net, u32 tunnel_id); |
239 | struct l2tp_tunnel *l2tp_tunnel_find_nth(struct net *net, int nth); | 244 | struct l2tp_tunnel *l2tp_tunnel_find_nth(struct net *net, int nth); |
240 | 245 | ||
diff --git a/net/l2tp/l2tp_debugfs.c b/net/l2tp/l2tp_debugfs.c index 2d6760a2ae34..d100aed3d06f 100644 --- a/net/l2tp/l2tp_debugfs.c +++ b/net/l2tp/l2tp_debugfs.c | |||
@@ -53,7 +53,7 @@ static void l2tp_dfs_next_tunnel(struct l2tp_dfs_seq_data *pd) | |||
53 | 53 | ||
54 | static void l2tp_dfs_next_session(struct l2tp_dfs_seq_data *pd) | 54 | static void l2tp_dfs_next_session(struct l2tp_dfs_seq_data *pd) |
55 | { | 55 | { |
56 | pd->session = l2tp_session_find_nth(pd->tunnel, pd->session_idx); | 56 | pd->session = l2tp_session_get_nth(pd->tunnel, pd->session_idx, true); |
57 | pd->session_idx++; | 57 | pd->session_idx++; |
58 | 58 | ||
59 | if (pd->session == NULL) { | 59 | if (pd->session == NULL) { |
@@ -238,10 +238,14 @@ static int l2tp_dfs_seq_show(struct seq_file *m, void *v) | |||
238 | } | 238 | } |
239 | 239 | ||
240 | /* Show the tunnel or session context */ | 240 | /* Show the tunnel or session context */ |
241 | if (pd->session == NULL) | 241 | if (!pd->session) { |
242 | l2tp_dfs_seq_tunnel_show(m, pd->tunnel); | 242 | l2tp_dfs_seq_tunnel_show(m, pd->tunnel); |
243 | else | 243 | } else { |
244 | l2tp_dfs_seq_session_show(m, pd->session); | 244 | l2tp_dfs_seq_session_show(m, pd->session); |
245 | if (pd->session->deref) | ||
246 | pd->session->deref(pd->session); | ||
247 | l2tp_session_dec_refcount(pd->session); | ||
248 | } | ||
245 | 249 | ||
246 | out: | 250 | out: |
247 | return 0; | 251 | return 0; |
diff --git a/net/l2tp/l2tp_eth.c b/net/l2tp/l2tp_eth.c index 8bf18a5f66e0..6fd41d7afe1e 100644 --- a/net/l2tp/l2tp_eth.c +++ b/net/l2tp/l2tp_eth.c | |||
@@ -221,12 +221,6 @@ static int l2tp_eth_create(struct net *net, u32 tunnel_id, u32 session_id, u32 p | |||
221 | goto out; | 221 | goto out; |
222 | } | 222 | } |
223 | 223 | ||
224 | session = l2tp_session_find(net, tunnel, session_id); | ||
225 | if (session) { | ||
226 | rc = -EEXIST; | ||
227 | goto out; | ||
228 | } | ||
229 | |||
230 | if (cfg->ifname) { | 224 | if (cfg->ifname) { |
231 | dev = dev_get_by_name(net, cfg->ifname); | 225 | dev = dev_get_by_name(net, cfg->ifname); |
232 | if (dev) { | 226 | if (dev) { |
@@ -240,8 +234,8 @@ static int l2tp_eth_create(struct net *net, u32 tunnel_id, u32 session_id, u32 p | |||
240 | 234 | ||
241 | session = l2tp_session_create(sizeof(*spriv), tunnel, session_id, | 235 | session = l2tp_session_create(sizeof(*spriv), tunnel, session_id, |
242 | peer_session_id, cfg); | 236 | peer_session_id, cfg); |
243 | if (!session) { | 237 | if (IS_ERR(session)) { |
244 | rc = -ENOMEM; | 238 | rc = PTR_ERR(session); |
245 | goto out; | 239 | goto out; |
246 | } | 240 | } |
247 | 241 | ||
diff --git a/net/l2tp/l2tp_ip.c b/net/l2tp/l2tp_ip.c index d25038cfd64e..4d322c1b7233 100644 --- a/net/l2tp/l2tp_ip.c +++ b/net/l2tp/l2tp_ip.c | |||
@@ -143,19 +143,19 @@ static int l2tp_ip_recv(struct sk_buff *skb) | |||
143 | } | 143 | } |
144 | 144 | ||
145 | /* Ok, this is a data packet. Lookup the session. */ | 145 | /* Ok, this is a data packet. Lookup the session. */ |
146 | session = l2tp_session_find(net, NULL, session_id); | 146 | session = l2tp_session_get(net, NULL, session_id, true); |
147 | if (session == NULL) | 147 | if (!session) |
148 | goto discard; | 148 | goto discard; |
149 | 149 | ||
150 | tunnel = session->tunnel; | 150 | tunnel = session->tunnel; |
151 | if (tunnel == NULL) | 151 | if (!tunnel) |
152 | goto discard; | 152 | goto discard_sess; |
153 | 153 | ||
154 | /* Trace packet contents, if enabled */ | 154 | /* Trace packet contents, if enabled */ |
155 | if (tunnel->debug & L2TP_MSG_DATA) { | 155 | if (tunnel->debug & L2TP_MSG_DATA) { |
156 | length = min(32u, skb->len); | 156 | length = min(32u, skb->len); |
157 | if (!pskb_may_pull(skb, length)) | 157 | if (!pskb_may_pull(skb, length)) |
158 | goto discard; | 158 | goto discard_sess; |
159 | 159 | ||
160 | /* Point to L2TP header */ | 160 | /* Point to L2TP header */ |
161 | optr = ptr = skb->data; | 161 | optr = ptr = skb->data; |
@@ -165,6 +165,7 @@ static int l2tp_ip_recv(struct sk_buff *skb) | |||
165 | } | 165 | } |
166 | 166 | ||
167 | l2tp_recv_common(session, skb, ptr, optr, 0, skb->len, tunnel->recv_payload_hook); | 167 | l2tp_recv_common(session, skb, ptr, optr, 0, skb->len, tunnel->recv_payload_hook); |
168 | l2tp_session_dec_refcount(session); | ||
168 | 169 | ||
169 | return 0; | 170 | return 0; |
170 | 171 | ||
@@ -178,9 +179,10 @@ pass_up: | |||
178 | 179 | ||
179 | tunnel_id = ntohl(*(__be32 *) &skb->data[4]); | 180 | tunnel_id = ntohl(*(__be32 *) &skb->data[4]); |
180 | tunnel = l2tp_tunnel_find(net, tunnel_id); | 181 | tunnel = l2tp_tunnel_find(net, tunnel_id); |
181 | if (tunnel != NULL) | 182 | if (tunnel) { |
182 | sk = tunnel->sock; | 183 | sk = tunnel->sock; |
183 | else { | 184 | sock_hold(sk); |
185 | } else { | ||
184 | struct iphdr *iph = (struct iphdr *) skb_network_header(skb); | 186 | struct iphdr *iph = (struct iphdr *) skb_network_header(skb); |
185 | 187 | ||
186 | read_lock_bh(&l2tp_ip_lock); | 188 | read_lock_bh(&l2tp_ip_lock); |
@@ -202,6 +204,12 @@ pass_up: | |||
202 | 204 | ||
203 | return sk_receive_skb(sk, skb, 1); | 205 | return sk_receive_skb(sk, skb, 1); |
204 | 206 | ||
207 | discard_sess: | ||
208 | if (session->deref) | ||
209 | session->deref(session); | ||
210 | l2tp_session_dec_refcount(session); | ||
211 | goto discard; | ||
212 | |||
205 | discard_put: | 213 | discard_put: |
206 | sock_put(sk); | 214 | sock_put(sk); |
207 | 215 | ||
diff --git a/net/l2tp/l2tp_ip6.c b/net/l2tp/l2tp_ip6.c index a4abcbc4c09a..88b397c30d86 100644 --- a/net/l2tp/l2tp_ip6.c +++ b/net/l2tp/l2tp_ip6.c | |||
@@ -156,19 +156,19 @@ static int l2tp_ip6_recv(struct sk_buff *skb) | |||
156 | } | 156 | } |
157 | 157 | ||
158 | /* Ok, this is a data packet. Lookup the session. */ | 158 | /* Ok, this is a data packet. Lookup the session. */ |
159 | session = l2tp_session_find(net, NULL, session_id); | 159 | session = l2tp_session_get(net, NULL, session_id, true); |
160 | if (session == NULL) | 160 | if (!session) |
161 | goto discard; | 161 | goto discard; |
162 | 162 | ||
163 | tunnel = session->tunnel; | 163 | tunnel = session->tunnel; |
164 | if (tunnel == NULL) | 164 | if (!tunnel) |
165 | goto discard; | 165 | goto discard_sess; |
166 | 166 | ||
167 | /* Trace packet contents, if enabled */ | 167 | /* Trace packet contents, if enabled */ |
168 | if (tunnel->debug & L2TP_MSG_DATA) { | 168 | if (tunnel->debug & L2TP_MSG_DATA) { |
169 | length = min(32u, skb->len); | 169 | length = min(32u, skb->len); |
170 | if (!pskb_may_pull(skb, length)) | 170 | if (!pskb_may_pull(skb, length)) |
171 | goto discard; | 171 | goto discard_sess; |
172 | 172 | ||
173 | /* Point to L2TP header */ | 173 | /* Point to L2TP header */ |
174 | optr = ptr = skb->data; | 174 | optr = ptr = skb->data; |
@@ -179,6 +179,8 @@ static int l2tp_ip6_recv(struct sk_buff *skb) | |||
179 | 179 | ||
180 | l2tp_recv_common(session, skb, ptr, optr, 0, skb->len, | 180 | l2tp_recv_common(session, skb, ptr, optr, 0, skb->len, |
181 | tunnel->recv_payload_hook); | 181 | tunnel->recv_payload_hook); |
182 | l2tp_session_dec_refcount(session); | ||
183 | |||
182 | return 0; | 184 | return 0; |
183 | 185 | ||
184 | pass_up: | 186 | pass_up: |
@@ -191,9 +193,10 @@ pass_up: | |||
191 | 193 | ||
192 | tunnel_id = ntohl(*(__be32 *) &skb->data[4]); | 194 | tunnel_id = ntohl(*(__be32 *) &skb->data[4]); |
193 | tunnel = l2tp_tunnel_find(net, tunnel_id); | 195 | tunnel = l2tp_tunnel_find(net, tunnel_id); |
194 | if (tunnel != NULL) | 196 | if (tunnel) { |
195 | sk = tunnel->sock; | 197 | sk = tunnel->sock; |
196 | else { | 198 | sock_hold(sk); |
199 | } else { | ||
197 | struct ipv6hdr *iph = ipv6_hdr(skb); | 200 | struct ipv6hdr *iph = ipv6_hdr(skb); |
198 | 201 | ||
199 | read_lock_bh(&l2tp_ip6_lock); | 202 | read_lock_bh(&l2tp_ip6_lock); |
@@ -215,6 +218,12 @@ pass_up: | |||
215 | 218 | ||
216 | return sk_receive_skb(sk, skb, 1); | 219 | return sk_receive_skb(sk, skb, 1); |
217 | 220 | ||
221 | discard_sess: | ||
222 | if (session->deref) | ||
223 | session->deref(session); | ||
224 | l2tp_session_dec_refcount(session); | ||
225 | goto discard; | ||
226 | |||
218 | discard_put: | 227 | discard_put: |
219 | sock_put(sk); | 228 | sock_put(sk); |
220 | 229 | ||
diff --git a/net/l2tp/l2tp_netlink.c b/net/l2tp/l2tp_netlink.c index 3620fba31786..7e3e669baac4 100644 --- a/net/l2tp/l2tp_netlink.c +++ b/net/l2tp/l2tp_netlink.c | |||
@@ -48,7 +48,8 @@ static int l2tp_nl_session_send(struct sk_buff *skb, u32 portid, u32 seq, | |||
48 | /* Accessed under genl lock */ | 48 | /* Accessed under genl lock */ |
49 | static const struct l2tp_nl_cmd_ops *l2tp_nl_cmd_ops[__L2TP_PWTYPE_MAX]; | 49 | static const struct l2tp_nl_cmd_ops *l2tp_nl_cmd_ops[__L2TP_PWTYPE_MAX]; |
50 | 50 | ||
51 | static struct l2tp_session *l2tp_nl_session_find(struct genl_info *info) | 51 | static struct l2tp_session *l2tp_nl_session_get(struct genl_info *info, |
52 | bool do_ref) | ||
52 | { | 53 | { |
53 | u32 tunnel_id; | 54 | u32 tunnel_id; |
54 | u32 session_id; | 55 | u32 session_id; |
@@ -59,14 +60,15 @@ static struct l2tp_session *l2tp_nl_session_find(struct genl_info *info) | |||
59 | 60 | ||
60 | if (info->attrs[L2TP_ATTR_IFNAME]) { | 61 | if (info->attrs[L2TP_ATTR_IFNAME]) { |
61 | ifname = nla_data(info->attrs[L2TP_ATTR_IFNAME]); | 62 | ifname = nla_data(info->attrs[L2TP_ATTR_IFNAME]); |
62 | session = l2tp_session_find_by_ifname(net, ifname); | 63 | session = l2tp_session_get_by_ifname(net, ifname, do_ref); |
63 | } else if ((info->attrs[L2TP_ATTR_SESSION_ID]) && | 64 | } else if ((info->attrs[L2TP_ATTR_SESSION_ID]) && |
64 | (info->attrs[L2TP_ATTR_CONN_ID])) { | 65 | (info->attrs[L2TP_ATTR_CONN_ID])) { |
65 | tunnel_id = nla_get_u32(info->attrs[L2TP_ATTR_CONN_ID]); | 66 | tunnel_id = nla_get_u32(info->attrs[L2TP_ATTR_CONN_ID]); |
66 | session_id = nla_get_u32(info->attrs[L2TP_ATTR_SESSION_ID]); | 67 | session_id = nla_get_u32(info->attrs[L2TP_ATTR_SESSION_ID]); |
67 | tunnel = l2tp_tunnel_find(net, tunnel_id); | 68 | tunnel = l2tp_tunnel_find(net, tunnel_id); |
68 | if (tunnel) | 69 | if (tunnel) |
69 | session = l2tp_session_find(net, tunnel, session_id); | 70 | session = l2tp_session_get(net, tunnel, session_id, |
71 | do_ref); | ||
70 | } | 72 | } |
71 | 73 | ||
72 | return session; | 74 | return session; |
@@ -642,10 +644,12 @@ static int l2tp_nl_cmd_session_create(struct sk_buff *skb, struct genl_info *inf | |||
642 | session_id, peer_session_id, &cfg); | 644 | session_id, peer_session_id, &cfg); |
643 | 645 | ||
644 | if (ret >= 0) { | 646 | if (ret >= 0) { |
645 | session = l2tp_session_find(net, tunnel, session_id); | 647 | session = l2tp_session_get(net, tunnel, session_id, false); |
646 | if (session) | 648 | if (session) { |
647 | ret = l2tp_session_notify(&l2tp_nl_family, info, session, | 649 | ret = l2tp_session_notify(&l2tp_nl_family, info, session, |
648 | L2TP_CMD_SESSION_CREATE); | 650 | L2TP_CMD_SESSION_CREATE); |
651 | l2tp_session_dec_refcount(session); | ||
652 | } | ||
649 | } | 653 | } |
650 | 654 | ||
651 | out: | 655 | out: |
@@ -658,7 +662,7 @@ static int l2tp_nl_cmd_session_delete(struct sk_buff *skb, struct genl_info *inf | |||
658 | struct l2tp_session *session; | 662 | struct l2tp_session *session; |
659 | u16 pw_type; | 663 | u16 pw_type; |
660 | 664 | ||
661 | session = l2tp_nl_session_find(info); | 665 | session = l2tp_nl_session_get(info, true); |
662 | if (session == NULL) { | 666 | if (session == NULL) { |
663 | ret = -ENODEV; | 667 | ret = -ENODEV; |
664 | goto out; | 668 | goto out; |
@@ -672,6 +676,10 @@ static int l2tp_nl_cmd_session_delete(struct sk_buff *skb, struct genl_info *inf | |||
672 | if (l2tp_nl_cmd_ops[pw_type] && l2tp_nl_cmd_ops[pw_type]->session_delete) | 676 | if (l2tp_nl_cmd_ops[pw_type] && l2tp_nl_cmd_ops[pw_type]->session_delete) |
673 | ret = (*l2tp_nl_cmd_ops[pw_type]->session_delete)(session); | 677 | ret = (*l2tp_nl_cmd_ops[pw_type]->session_delete)(session); |
674 | 678 | ||
679 | if (session->deref) | ||
680 | session->deref(session); | ||
681 | l2tp_session_dec_refcount(session); | ||
682 | |||
675 | out: | 683 | out: |
676 | return ret; | 684 | return ret; |
677 | } | 685 | } |
@@ -681,7 +689,7 @@ static int l2tp_nl_cmd_session_modify(struct sk_buff *skb, struct genl_info *inf | |||
681 | int ret = 0; | 689 | int ret = 0; |
682 | struct l2tp_session *session; | 690 | struct l2tp_session *session; |
683 | 691 | ||
684 | session = l2tp_nl_session_find(info); | 692 | session = l2tp_nl_session_get(info, false); |
685 | if (session == NULL) { | 693 | if (session == NULL) { |
686 | ret = -ENODEV; | 694 | ret = -ENODEV; |
687 | goto out; | 695 | goto out; |
@@ -716,6 +724,8 @@ static int l2tp_nl_cmd_session_modify(struct sk_buff *skb, struct genl_info *inf | |||
716 | ret = l2tp_session_notify(&l2tp_nl_family, info, | 724 | ret = l2tp_session_notify(&l2tp_nl_family, info, |
717 | session, L2TP_CMD_SESSION_MODIFY); | 725 | session, L2TP_CMD_SESSION_MODIFY); |
718 | 726 | ||
727 | l2tp_session_dec_refcount(session); | ||
728 | |||
719 | out: | 729 | out: |
720 | return ret; | 730 | return ret; |
721 | } | 731 | } |
@@ -811,29 +821,34 @@ static int l2tp_nl_cmd_session_get(struct sk_buff *skb, struct genl_info *info) | |||
811 | struct sk_buff *msg; | 821 | struct sk_buff *msg; |
812 | int ret; | 822 | int ret; |
813 | 823 | ||
814 | session = l2tp_nl_session_find(info); | 824 | session = l2tp_nl_session_get(info, false); |
815 | if (session == NULL) { | 825 | if (session == NULL) { |
816 | ret = -ENODEV; | 826 | ret = -ENODEV; |
817 | goto out; | 827 | goto err; |
818 | } | 828 | } |
819 | 829 | ||
820 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | 830 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
821 | if (!msg) { | 831 | if (!msg) { |
822 | ret = -ENOMEM; | 832 | ret = -ENOMEM; |
823 | goto out; | 833 | goto err_ref; |
824 | } | 834 | } |
825 | 835 | ||
826 | ret = l2tp_nl_session_send(msg, info->snd_portid, info->snd_seq, | 836 | ret = l2tp_nl_session_send(msg, info->snd_portid, info->snd_seq, |
827 | 0, session, L2TP_CMD_SESSION_GET); | 837 | 0, session, L2TP_CMD_SESSION_GET); |
828 | if (ret < 0) | 838 | if (ret < 0) |
829 | goto err_out; | 839 | goto err_ref_msg; |
830 | 840 | ||
831 | return genlmsg_unicast(genl_info_net(info), msg, info->snd_portid); | 841 | ret = genlmsg_unicast(genl_info_net(info), msg, info->snd_portid); |
832 | 842 | ||
833 | err_out: | 843 | l2tp_session_dec_refcount(session); |
834 | nlmsg_free(msg); | ||
835 | 844 | ||
836 | out: | 845 | return ret; |
846 | |||
847 | err_ref_msg: | ||
848 | nlmsg_free(msg); | ||
849 | err_ref: | ||
850 | l2tp_session_dec_refcount(session); | ||
851 | err: | ||
837 | return ret; | 852 | return ret; |
838 | } | 853 | } |
839 | 854 | ||
@@ -852,7 +867,7 @@ static int l2tp_nl_cmd_session_dump(struct sk_buff *skb, struct netlink_callback | |||
852 | goto out; | 867 | goto out; |
853 | } | 868 | } |
854 | 869 | ||
855 | session = l2tp_session_find_nth(tunnel, si); | 870 | session = l2tp_session_get_nth(tunnel, si, false); |
856 | if (session == NULL) { | 871 | if (session == NULL) { |
857 | ti++; | 872 | ti++; |
858 | tunnel = NULL; | 873 | tunnel = NULL; |
@@ -862,8 +877,11 @@ static int l2tp_nl_cmd_session_dump(struct sk_buff *skb, struct netlink_callback | |||
862 | 877 | ||
863 | if (l2tp_nl_session_send(skb, NETLINK_CB(cb->skb).portid, | 878 | if (l2tp_nl_session_send(skb, NETLINK_CB(cb->skb).portid, |
864 | cb->nlh->nlmsg_seq, NLM_F_MULTI, | 879 | cb->nlh->nlmsg_seq, NLM_F_MULTI, |
865 | session, L2TP_CMD_SESSION_GET) < 0) | 880 | session, L2TP_CMD_SESSION_GET) < 0) { |
881 | l2tp_session_dec_refcount(session); | ||
866 | break; | 882 | break; |
883 | } | ||
884 | l2tp_session_dec_refcount(session); | ||
867 | 885 | ||
868 | si++; | 886 | si++; |
869 | } | 887 | } |
diff --git a/net/l2tp/l2tp_ppp.c b/net/l2tp/l2tp_ppp.c index 36cc56fd0418..861b255a2d51 100644 --- a/net/l2tp/l2tp_ppp.c +++ b/net/l2tp/l2tp_ppp.c | |||
@@ -450,6 +450,10 @@ static void pppol2tp_session_close(struct l2tp_session *session) | |||
450 | static void pppol2tp_session_destruct(struct sock *sk) | 450 | static void pppol2tp_session_destruct(struct sock *sk) |
451 | { | 451 | { |
452 | struct l2tp_session *session = sk->sk_user_data; | 452 | struct l2tp_session *session = sk->sk_user_data; |
453 | |||
454 | skb_queue_purge(&sk->sk_receive_queue); | ||
455 | skb_queue_purge(&sk->sk_write_queue); | ||
456 | |||
453 | if (session) { | 457 | if (session) { |
454 | sk->sk_user_data = NULL; | 458 | sk->sk_user_data = NULL; |
455 | BUG_ON(session->magic != L2TP_SESSION_MAGIC); | 459 | BUG_ON(session->magic != L2TP_SESSION_MAGIC); |
@@ -488,9 +492,6 @@ static int pppol2tp_release(struct socket *sock) | |||
488 | l2tp_session_queue_purge(session); | 492 | l2tp_session_queue_purge(session); |
489 | sock_put(sk); | 493 | sock_put(sk); |
490 | } | 494 | } |
491 | skb_queue_purge(&sk->sk_receive_queue); | ||
492 | skb_queue_purge(&sk->sk_write_queue); | ||
493 | |||
494 | release_sock(sk); | 495 | release_sock(sk); |
495 | 496 | ||
496 | /* This will delete the session context via | 497 | /* This will delete the session context via |
@@ -582,6 +583,7 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr, | |||
582 | int error = 0; | 583 | int error = 0; |
583 | u32 tunnel_id, peer_tunnel_id; | 584 | u32 tunnel_id, peer_tunnel_id; |
584 | u32 session_id, peer_session_id; | 585 | u32 session_id, peer_session_id; |
586 | bool drop_refcnt = false; | ||
585 | int ver = 2; | 587 | int ver = 2; |
586 | int fd; | 588 | int fd; |
587 | 589 | ||
@@ -683,36 +685,36 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr, | |||
683 | if (tunnel->peer_tunnel_id == 0) | 685 | if (tunnel->peer_tunnel_id == 0) |
684 | tunnel->peer_tunnel_id = peer_tunnel_id; | 686 | tunnel->peer_tunnel_id = peer_tunnel_id; |
685 | 687 | ||
686 | /* Create session if it doesn't already exist. We handle the | 688 | session = l2tp_session_get(sock_net(sk), tunnel, session_id, false); |
687 | * case where a session was previously created by the netlink | 689 | if (session) { |
688 | * interface by checking that the session doesn't already have | 690 | drop_refcnt = true; |
689 | * a socket and its tunnel socket are what we expect. If any | 691 | ps = l2tp_session_priv(session); |
690 | * of those checks fail, return EEXIST to the caller. | 692 | |
691 | */ | 693 | /* Using a pre-existing session is fine as long as it hasn't |
692 | session = l2tp_session_find(sock_net(sk), tunnel, session_id); | 694 | * been connected yet. |
693 | if (session == NULL) { | ||
694 | /* Default MTU must allow space for UDP/L2TP/PPP | ||
695 | * headers. | ||
696 | */ | 695 | */ |
697 | cfg.mtu = cfg.mru = 1500 - PPPOL2TP_HEADER_OVERHEAD; | 696 | if (ps->sock) { |
697 | error = -EEXIST; | ||
698 | goto end; | ||
699 | } | ||
698 | 700 | ||
699 | /* Allocate and initialize a new session context. */ | 701 | /* consistency checks */ |
700 | session = l2tp_session_create(sizeof(struct pppol2tp_session), | 702 | if (ps->tunnel_sock != tunnel->sock) { |
701 | tunnel, session_id, | 703 | error = -EEXIST; |
702 | peer_session_id, &cfg); | ||
703 | if (session == NULL) { | ||
704 | error = -ENOMEM; | ||
705 | goto end; | 704 | goto end; |
706 | } | 705 | } |
707 | } else { | 706 | } else { |
708 | ps = l2tp_session_priv(session); | 707 | /* Default MTU must allow space for UDP/L2TP/PPP headers */ |
709 | error = -EEXIST; | 708 | cfg.mtu = 1500 - PPPOL2TP_HEADER_OVERHEAD; |
710 | if (ps->sock != NULL) | 709 | cfg.mru = cfg.mtu; |
711 | goto end; | ||
712 | 710 | ||
713 | /* consistency checks */ | 711 | session = l2tp_session_create(sizeof(struct pppol2tp_session), |
714 | if (ps->tunnel_sock != tunnel->sock) | 712 | tunnel, session_id, |
713 | peer_session_id, &cfg); | ||
714 | if (IS_ERR(session)) { | ||
715 | error = PTR_ERR(session); | ||
715 | goto end; | 716 | goto end; |
717 | } | ||
716 | } | 718 | } |
717 | 719 | ||
718 | /* Associate session with its PPPoL2TP socket */ | 720 | /* Associate session with its PPPoL2TP socket */ |
@@ -777,6 +779,8 @@ out_no_ppp: | |||
777 | session->name); | 779 | session->name); |
778 | 780 | ||
779 | end: | 781 | end: |
782 | if (drop_refcnt) | ||
783 | l2tp_session_dec_refcount(session); | ||
780 | release_sock(sk); | 784 | release_sock(sk); |
781 | 785 | ||
782 | return error; | 786 | return error; |
@@ -804,12 +808,6 @@ static int pppol2tp_session_create(struct net *net, u32 tunnel_id, u32 session_i | |||
804 | if (tunnel->sock == NULL) | 808 | if (tunnel->sock == NULL) |
805 | goto out; | 809 | goto out; |
806 | 810 | ||
807 | /* Check that this session doesn't already exist */ | ||
808 | error = -EEXIST; | ||
809 | session = l2tp_session_find(net, tunnel, session_id); | ||
810 | if (session != NULL) | ||
811 | goto out; | ||
812 | |||
813 | /* Default MTU values. */ | 811 | /* Default MTU values. */ |
814 | if (cfg->mtu == 0) | 812 | if (cfg->mtu == 0) |
815 | cfg->mtu = 1500 - PPPOL2TP_HEADER_OVERHEAD; | 813 | cfg->mtu = 1500 - PPPOL2TP_HEADER_OVERHEAD; |
@@ -817,12 +815,13 @@ static int pppol2tp_session_create(struct net *net, u32 tunnel_id, u32 session_i | |||
817 | cfg->mru = cfg->mtu; | 815 | cfg->mru = cfg->mtu; |
818 | 816 | ||
819 | /* Allocate and initialize a new session context. */ | 817 | /* Allocate and initialize a new session context. */ |
820 | error = -ENOMEM; | ||
821 | session = l2tp_session_create(sizeof(struct pppol2tp_session), | 818 | session = l2tp_session_create(sizeof(struct pppol2tp_session), |
822 | tunnel, session_id, | 819 | tunnel, session_id, |
823 | peer_session_id, cfg); | 820 | peer_session_id, cfg); |
824 | if (session == NULL) | 821 | if (IS_ERR(session)) { |
822 | error = PTR_ERR(session); | ||
825 | goto out; | 823 | goto out; |
824 | } | ||
826 | 825 | ||
827 | ps = l2tp_session_priv(session); | 826 | ps = l2tp_session_priv(session); |
828 | ps->tunnel_sock = tunnel->sock; | 827 | ps->tunnel_sock = tunnel->sock; |
@@ -1140,11 +1139,18 @@ static int pppol2tp_tunnel_ioctl(struct l2tp_tunnel *tunnel, | |||
1140 | if (stats.session_id != 0) { | 1139 | if (stats.session_id != 0) { |
1141 | /* resend to session ioctl handler */ | 1140 | /* resend to session ioctl handler */ |
1142 | struct l2tp_session *session = | 1141 | struct l2tp_session *session = |
1143 | l2tp_session_find(sock_net(sk), tunnel, stats.session_id); | 1142 | l2tp_session_get(sock_net(sk), tunnel, |
1144 | if (session != NULL) | 1143 | stats.session_id, true); |
1145 | err = pppol2tp_session_ioctl(session, cmd, arg); | 1144 | |
1146 | else | 1145 | if (session) { |
1146 | err = pppol2tp_session_ioctl(session, cmd, | ||
1147 | arg); | ||
1148 | if (session->deref) | ||
1149 | session->deref(session); | ||
1150 | l2tp_session_dec_refcount(session); | ||
1151 | } else { | ||
1147 | err = -EBADR; | 1152 | err = -EBADR; |
1153 | } | ||
1148 | break; | 1154 | break; |
1149 | } | 1155 | } |
1150 | #ifdef CONFIG_XFRM | 1156 | #ifdef CONFIG_XFRM |
@@ -1554,7 +1560,7 @@ static void pppol2tp_next_tunnel(struct net *net, struct pppol2tp_seq_data *pd) | |||
1554 | 1560 | ||
1555 | static void pppol2tp_next_session(struct net *net, struct pppol2tp_seq_data *pd) | 1561 | static void pppol2tp_next_session(struct net *net, struct pppol2tp_seq_data *pd) |
1556 | { | 1562 | { |
1557 | pd->session = l2tp_session_find_nth(pd->tunnel, pd->session_idx); | 1563 | pd->session = l2tp_session_get_nth(pd->tunnel, pd->session_idx, true); |
1558 | pd->session_idx++; | 1564 | pd->session_idx++; |
1559 | 1565 | ||
1560 | if (pd->session == NULL) { | 1566 | if (pd->session == NULL) { |
@@ -1681,10 +1687,14 @@ static int pppol2tp_seq_show(struct seq_file *m, void *v) | |||
1681 | 1687 | ||
1682 | /* Show the tunnel or session context. | 1688 | /* Show the tunnel or session context. |
1683 | */ | 1689 | */ |
1684 | if (pd->session == NULL) | 1690 | if (!pd->session) { |
1685 | pppol2tp_seq_tunnel_show(m, pd->tunnel); | 1691 | pppol2tp_seq_tunnel_show(m, pd->tunnel); |
1686 | else | 1692 | } else { |
1687 | pppol2tp_seq_session_show(m, pd->session); | 1693 | pppol2tp_seq_session_show(m, pd->session); |
1694 | if (pd->session->deref) | ||
1695 | pd->session->deref(pd->session); | ||
1696 | l2tp_session_dec_refcount(pd->session); | ||
1697 | } | ||
1688 | 1698 | ||
1689 | out: | 1699 | out: |
1690 | return 0; | 1700 | return 0; |
@@ -1843,4 +1853,4 @@ MODULE_DESCRIPTION("PPP over L2TP over UDP"); | |||
1843 | MODULE_LICENSE("GPL"); | 1853 | MODULE_LICENSE("GPL"); |
1844 | MODULE_VERSION(PPPOL2TP_DRV_VERSION); | 1854 | MODULE_VERSION(PPPOL2TP_DRV_VERSION); |
1845 | MODULE_ALIAS_NET_PF_PROTO(PF_PPPOX, PX_PROTO_OL2TP); | 1855 | MODULE_ALIAS_NET_PF_PROTO(PF_PPPOX, PX_PROTO_OL2TP); |
1846 | MODULE_ALIAS_L2TP_PWTYPE(11); | 1856 | MODULE_ALIAS_L2TP_PWTYPE(7); |
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 40813dd3301c..5bb0c5012819 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
@@ -718,7 +718,8 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up) | |||
718 | ieee80211_recalc_ps(local); | 718 | ieee80211_recalc_ps(local); |
719 | 719 | ||
720 | if (sdata->vif.type == NL80211_IFTYPE_MONITOR || | 720 | if (sdata->vif.type == NL80211_IFTYPE_MONITOR || |
721 | sdata->vif.type == NL80211_IFTYPE_AP_VLAN) { | 721 | sdata->vif.type == NL80211_IFTYPE_AP_VLAN || |
722 | local->ops->wake_tx_queue) { | ||
722 | /* XXX: for AP_VLAN, actually track AP queues */ | 723 | /* XXX: for AP_VLAN, actually track AP queues */ |
723 | netif_tx_start_all_queues(dev); | 724 | netif_tx_start_all_queues(dev); |
724 | } else if (dev) { | 725 | } else if (dev) { |
diff --git a/net/netfilter/nf_conntrack_ecache.c b/net/netfilter/nf_conntrack_ecache.c index da9df2d56e66..22fc32143e9c 100644 --- a/net/netfilter/nf_conntrack_ecache.c +++ b/net/netfilter/nf_conntrack_ecache.c | |||
@@ -290,6 +290,7 @@ void nf_conntrack_unregister_notifier(struct net *net, | |||
290 | BUG_ON(notify != new); | 290 | BUG_ON(notify != new); |
291 | RCU_INIT_POINTER(net->ct.nf_conntrack_event_cb, NULL); | 291 | RCU_INIT_POINTER(net->ct.nf_conntrack_event_cb, NULL); |
292 | mutex_unlock(&nf_ct_ecache_mutex); | 292 | mutex_unlock(&nf_ct_ecache_mutex); |
293 | /* synchronize_rcu() is called from ctnetlink_exit. */ | ||
293 | } | 294 | } |
294 | EXPORT_SYMBOL_GPL(nf_conntrack_unregister_notifier); | 295 | EXPORT_SYMBOL_GPL(nf_conntrack_unregister_notifier); |
295 | 296 | ||
@@ -326,6 +327,7 @@ void nf_ct_expect_unregister_notifier(struct net *net, | |||
326 | BUG_ON(notify != new); | 327 | BUG_ON(notify != new); |
327 | RCU_INIT_POINTER(net->ct.nf_expect_event_cb, NULL); | 328 | RCU_INIT_POINTER(net->ct.nf_expect_event_cb, NULL); |
328 | mutex_unlock(&nf_ct_ecache_mutex); | 329 | mutex_unlock(&nf_ct_ecache_mutex); |
330 | /* synchronize_rcu() is called from ctnetlink_exit. */ | ||
329 | } | 331 | } |
330 | EXPORT_SYMBOL_GPL(nf_ct_expect_unregister_notifier); | 332 | EXPORT_SYMBOL_GPL(nf_ct_expect_unregister_notifier); |
331 | 333 | ||
diff --git a/net/netfilter/nf_conntrack_extend.c b/net/netfilter/nf_conntrack_extend.c index 02bcf00c2492..008299b7f78f 100644 --- a/net/netfilter/nf_conntrack_extend.c +++ b/net/netfilter/nf_conntrack_extend.c | |||
@@ -53,7 +53,11 @@ nf_ct_ext_create(struct nf_ct_ext **ext, enum nf_ct_ext_id id, | |||
53 | 53 | ||
54 | rcu_read_lock(); | 54 | rcu_read_lock(); |
55 | t = rcu_dereference(nf_ct_ext_types[id]); | 55 | t = rcu_dereference(nf_ct_ext_types[id]); |
56 | BUG_ON(t == NULL); | 56 | if (!t) { |
57 | rcu_read_unlock(); | ||
58 | return NULL; | ||
59 | } | ||
60 | |||
57 | off = ALIGN(sizeof(struct nf_ct_ext), t->align); | 61 | off = ALIGN(sizeof(struct nf_ct_ext), t->align); |
58 | len = off + t->len + var_alloc_len; | 62 | len = off + t->len + var_alloc_len; |
59 | alloc_size = t->alloc_size + var_alloc_len; | 63 | alloc_size = t->alloc_size + var_alloc_len; |
@@ -88,7 +92,10 @@ void *__nf_ct_ext_add_length(struct nf_conn *ct, enum nf_ct_ext_id id, | |||
88 | 92 | ||
89 | rcu_read_lock(); | 93 | rcu_read_lock(); |
90 | t = rcu_dereference(nf_ct_ext_types[id]); | 94 | t = rcu_dereference(nf_ct_ext_types[id]); |
91 | BUG_ON(t == NULL); | 95 | if (!t) { |
96 | rcu_read_unlock(); | ||
97 | return NULL; | ||
98 | } | ||
92 | 99 | ||
93 | newoff = ALIGN(old->len, t->align); | 100 | newoff = ALIGN(old->len, t->align); |
94 | newlen = newoff + t->len + var_alloc_len; | 101 | newlen = newoff + t->len + var_alloc_len; |
@@ -175,6 +182,6 @@ void nf_ct_extend_unregister(struct nf_ct_ext_type *type) | |||
175 | RCU_INIT_POINTER(nf_ct_ext_types[type->id], NULL); | 182 | RCU_INIT_POINTER(nf_ct_ext_types[type->id], NULL); |
176 | update_alloc_size(type); | 183 | update_alloc_size(type); |
177 | mutex_unlock(&nf_ct_ext_type_mutex); | 184 | mutex_unlock(&nf_ct_ext_type_mutex); |
178 | rcu_barrier(); /* Wait for completion of call_rcu()'s */ | 185 | synchronize_rcu(); |
179 | } | 186 | } |
180 | EXPORT_SYMBOL_GPL(nf_ct_extend_unregister); | 187 | EXPORT_SYMBOL_GPL(nf_ct_extend_unregister); |
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 6806b5e73567..908d858034e4 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c | |||
@@ -3442,6 +3442,7 @@ static void __exit ctnetlink_exit(void) | |||
3442 | #ifdef CONFIG_NETFILTER_NETLINK_GLUE_CT | 3442 | #ifdef CONFIG_NETFILTER_NETLINK_GLUE_CT |
3443 | RCU_INIT_POINTER(nfnl_ct_hook, NULL); | 3443 | RCU_INIT_POINTER(nfnl_ct_hook, NULL); |
3444 | #endif | 3444 | #endif |
3445 | synchronize_rcu(); | ||
3445 | } | 3446 | } |
3446 | 3447 | ||
3447 | module_init(ctnetlink_init); | 3448 | module_init(ctnetlink_init); |
diff --git a/net/netfilter/nf_nat_core.c b/net/netfilter/nf_nat_core.c index 94b14c5a8b17..82802e4a6640 100644 --- a/net/netfilter/nf_nat_core.c +++ b/net/netfilter/nf_nat_core.c | |||
@@ -903,6 +903,8 @@ static void __exit nf_nat_cleanup(void) | |||
903 | #ifdef CONFIG_XFRM | 903 | #ifdef CONFIG_XFRM |
904 | RCU_INIT_POINTER(nf_nat_decode_session_hook, NULL); | 904 | RCU_INIT_POINTER(nf_nat_decode_session_hook, NULL); |
905 | #endif | 905 | #endif |
906 | synchronize_rcu(); | ||
907 | |||
906 | for (i = 0; i < NFPROTO_NUMPROTO; i++) | 908 | for (i = 0; i < NFPROTO_NUMPROTO; i++) |
907 | kfree(nf_nat_l4protos[i]); | 909 | kfree(nf_nat_l4protos[i]); |
908 | 910 | ||
diff --git a/net/netfilter/nfnetlink_cthelper.c b/net/netfilter/nfnetlink_cthelper.c index de8782345c86..d45558178da5 100644 --- a/net/netfilter/nfnetlink_cthelper.c +++ b/net/netfilter/nfnetlink_cthelper.c | |||
@@ -32,6 +32,13 @@ MODULE_LICENSE("GPL"); | |||
32 | MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>"); | 32 | MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>"); |
33 | MODULE_DESCRIPTION("nfnl_cthelper: User-space connection tracking helpers"); | 33 | MODULE_DESCRIPTION("nfnl_cthelper: User-space connection tracking helpers"); |
34 | 34 | ||
35 | struct nfnl_cthelper { | ||
36 | struct list_head list; | ||
37 | struct nf_conntrack_helper helper; | ||
38 | }; | ||
39 | |||
40 | static LIST_HEAD(nfnl_cthelper_list); | ||
41 | |||
35 | static int | 42 | static int |
36 | nfnl_userspace_cthelper(struct sk_buff *skb, unsigned int protoff, | 43 | nfnl_userspace_cthelper(struct sk_buff *skb, unsigned int protoff, |
37 | struct nf_conn *ct, enum ip_conntrack_info ctinfo) | 44 | struct nf_conn *ct, enum ip_conntrack_info ctinfo) |
@@ -161,6 +168,7 @@ nfnl_cthelper_parse_expect_policy(struct nf_conntrack_helper *helper, | |||
161 | int i, ret; | 168 | int i, ret; |
162 | struct nf_conntrack_expect_policy *expect_policy; | 169 | struct nf_conntrack_expect_policy *expect_policy; |
163 | struct nlattr *tb[NFCTH_POLICY_SET_MAX+1]; | 170 | struct nlattr *tb[NFCTH_POLICY_SET_MAX+1]; |
171 | unsigned int class_max; | ||
164 | 172 | ||
165 | ret = nla_parse_nested(tb, NFCTH_POLICY_SET_MAX, attr, | 173 | ret = nla_parse_nested(tb, NFCTH_POLICY_SET_MAX, attr, |
166 | nfnl_cthelper_expect_policy_set); | 174 | nfnl_cthelper_expect_policy_set); |
@@ -170,19 +178,18 @@ nfnl_cthelper_parse_expect_policy(struct nf_conntrack_helper *helper, | |||
170 | if (!tb[NFCTH_POLICY_SET_NUM]) | 178 | if (!tb[NFCTH_POLICY_SET_NUM]) |
171 | return -EINVAL; | 179 | return -EINVAL; |
172 | 180 | ||
173 | helper->expect_class_max = | 181 | class_max = ntohl(nla_get_be32(tb[NFCTH_POLICY_SET_NUM])); |
174 | ntohl(nla_get_be32(tb[NFCTH_POLICY_SET_NUM])); | 182 | if (class_max == 0) |
175 | 183 | return -EINVAL; | |
176 | if (helper->expect_class_max != 0 && | 184 | if (class_max > NF_CT_MAX_EXPECT_CLASSES) |
177 | helper->expect_class_max > NF_CT_MAX_EXPECT_CLASSES) | ||
178 | return -EOVERFLOW; | 185 | return -EOVERFLOW; |
179 | 186 | ||
180 | expect_policy = kzalloc(sizeof(struct nf_conntrack_expect_policy) * | 187 | expect_policy = kzalloc(sizeof(struct nf_conntrack_expect_policy) * |
181 | helper->expect_class_max, GFP_KERNEL); | 188 | class_max, GFP_KERNEL); |
182 | if (expect_policy == NULL) | 189 | if (expect_policy == NULL) |
183 | return -ENOMEM; | 190 | return -ENOMEM; |
184 | 191 | ||
185 | for (i=0; i<helper->expect_class_max; i++) { | 192 | for (i = 0; i < class_max; i++) { |
186 | if (!tb[NFCTH_POLICY_SET+i]) | 193 | if (!tb[NFCTH_POLICY_SET+i]) |
187 | goto err; | 194 | goto err; |
188 | 195 | ||
@@ -191,6 +198,8 @@ nfnl_cthelper_parse_expect_policy(struct nf_conntrack_helper *helper, | |||
191 | if (ret < 0) | 198 | if (ret < 0) |
192 | goto err; | 199 | goto err; |
193 | } | 200 | } |
201 | |||
202 | helper->expect_class_max = class_max - 1; | ||
194 | helper->expect_policy = expect_policy; | 203 | helper->expect_policy = expect_policy; |
195 | return 0; | 204 | return 0; |
196 | err: | 205 | err: |
@@ -203,18 +212,20 @@ nfnl_cthelper_create(const struct nlattr * const tb[], | |||
203 | struct nf_conntrack_tuple *tuple) | 212 | struct nf_conntrack_tuple *tuple) |
204 | { | 213 | { |
205 | struct nf_conntrack_helper *helper; | 214 | struct nf_conntrack_helper *helper; |
215 | struct nfnl_cthelper *nfcth; | ||
206 | int ret; | 216 | int ret; |
207 | 217 | ||
208 | if (!tb[NFCTH_TUPLE] || !tb[NFCTH_POLICY] || !tb[NFCTH_PRIV_DATA_LEN]) | 218 | if (!tb[NFCTH_TUPLE] || !tb[NFCTH_POLICY] || !tb[NFCTH_PRIV_DATA_LEN]) |
209 | return -EINVAL; | 219 | return -EINVAL; |
210 | 220 | ||
211 | helper = kzalloc(sizeof(struct nf_conntrack_helper), GFP_KERNEL); | 221 | nfcth = kzalloc(sizeof(*nfcth), GFP_KERNEL); |
212 | if (helper == NULL) | 222 | if (nfcth == NULL) |
213 | return -ENOMEM; | 223 | return -ENOMEM; |
224 | helper = &nfcth->helper; | ||
214 | 225 | ||
215 | ret = nfnl_cthelper_parse_expect_policy(helper, tb[NFCTH_POLICY]); | 226 | ret = nfnl_cthelper_parse_expect_policy(helper, tb[NFCTH_POLICY]); |
216 | if (ret < 0) | 227 | if (ret < 0) |
217 | goto err; | 228 | goto err1; |
218 | 229 | ||
219 | strncpy(helper->name, nla_data(tb[NFCTH_NAME]), NF_CT_HELPER_NAME_LEN); | 230 | strncpy(helper->name, nla_data(tb[NFCTH_NAME]), NF_CT_HELPER_NAME_LEN); |
220 | helper->data_len = ntohl(nla_get_be32(tb[NFCTH_PRIV_DATA_LEN])); | 231 | helper->data_len = ntohl(nla_get_be32(tb[NFCTH_PRIV_DATA_LEN])); |
@@ -245,15 +256,101 @@ nfnl_cthelper_create(const struct nlattr * const tb[], | |||
245 | 256 | ||
246 | ret = nf_conntrack_helper_register(helper); | 257 | ret = nf_conntrack_helper_register(helper); |
247 | if (ret < 0) | 258 | if (ret < 0) |
248 | goto err; | 259 | goto err2; |
249 | 260 | ||
261 | list_add_tail(&nfcth->list, &nfnl_cthelper_list); | ||
250 | return 0; | 262 | return 0; |
251 | err: | 263 | err2: |
252 | kfree(helper); | 264 | kfree(helper->expect_policy); |
265 | err1: | ||
266 | kfree(nfcth); | ||
253 | return ret; | 267 | return ret; |
254 | } | 268 | } |
255 | 269 | ||
256 | static int | 270 | static int |
271 | nfnl_cthelper_update_policy_one(const struct nf_conntrack_expect_policy *policy, | ||
272 | struct nf_conntrack_expect_policy *new_policy, | ||
273 | const struct nlattr *attr) | ||
274 | { | ||
275 | struct nlattr *tb[NFCTH_POLICY_MAX + 1]; | ||
276 | int err; | ||
277 | |||
278 | err = nla_parse_nested(tb, NFCTH_POLICY_MAX, attr, | ||
279 | nfnl_cthelper_expect_pol); | ||
280 | if (err < 0) | ||
281 | return err; | ||
282 | |||
283 | if (!tb[NFCTH_POLICY_NAME] || | ||
284 | !tb[NFCTH_POLICY_EXPECT_MAX] || | ||
285 | !tb[NFCTH_POLICY_EXPECT_TIMEOUT]) | ||
286 | return -EINVAL; | ||
287 | |||
288 | if (nla_strcmp(tb[NFCTH_POLICY_NAME], policy->name)) | ||
289 | return -EBUSY; | ||
290 | |||
291 | new_policy->max_expected = | ||
292 | ntohl(nla_get_be32(tb[NFCTH_POLICY_EXPECT_MAX])); | ||
293 | new_policy->timeout = | ||
294 | ntohl(nla_get_be32(tb[NFCTH_POLICY_EXPECT_TIMEOUT])); | ||
295 | |||
296 | return 0; | ||
297 | } | ||
298 | |||
299 | static int nfnl_cthelper_update_policy_all(struct nlattr *tb[], | ||
300 | struct nf_conntrack_helper *helper) | ||
301 | { | ||
302 | struct nf_conntrack_expect_policy new_policy[helper->expect_class_max + 1]; | ||
303 | struct nf_conntrack_expect_policy *policy; | ||
304 | int i, err; | ||
305 | |||
306 | /* Check first that all policy attributes are well-formed, so we don't | ||
307 | * leave things in inconsistent state on errors. | ||
308 | */ | ||
309 | for (i = 0; i < helper->expect_class_max + 1; i++) { | ||
310 | |||
311 | if (!tb[NFCTH_POLICY_SET + i]) | ||
312 | return -EINVAL; | ||
313 | |||
314 | err = nfnl_cthelper_update_policy_one(&helper->expect_policy[i], | ||
315 | &new_policy[i], | ||
316 | tb[NFCTH_POLICY_SET + i]); | ||
317 | if (err < 0) | ||
318 | return err; | ||
319 | } | ||
320 | /* Now we can safely update them. */ | ||
321 | for (i = 0; i < helper->expect_class_max + 1; i++) { | ||
322 | policy = (struct nf_conntrack_expect_policy *) | ||
323 | &helper->expect_policy[i]; | ||
324 | policy->max_expected = new_policy->max_expected; | ||
325 | policy->timeout = new_policy->timeout; | ||
326 | } | ||
327 | |||
328 | return 0; | ||
329 | } | ||
330 | |||
331 | static int nfnl_cthelper_update_policy(struct nf_conntrack_helper *helper, | ||
332 | const struct nlattr *attr) | ||
333 | { | ||
334 | struct nlattr *tb[NFCTH_POLICY_SET_MAX + 1]; | ||
335 | unsigned int class_max; | ||
336 | int err; | ||
337 | |||
338 | err = nla_parse_nested(tb, NFCTH_POLICY_SET_MAX, attr, | ||
339 | nfnl_cthelper_expect_policy_set); | ||
340 | if (err < 0) | ||
341 | return err; | ||
342 | |||
343 | if (!tb[NFCTH_POLICY_SET_NUM]) | ||
344 | return -EINVAL; | ||
345 | |||
346 | class_max = ntohl(nla_get_be32(tb[NFCTH_POLICY_SET_NUM])); | ||
347 | if (helper->expect_class_max + 1 != class_max) | ||
348 | return -EBUSY; | ||
349 | |||
350 | return nfnl_cthelper_update_policy_all(tb, helper); | ||
351 | } | ||
352 | |||
353 | static int | ||
257 | nfnl_cthelper_update(const struct nlattr * const tb[], | 354 | nfnl_cthelper_update(const struct nlattr * const tb[], |
258 | struct nf_conntrack_helper *helper) | 355 | struct nf_conntrack_helper *helper) |
259 | { | 356 | { |
@@ -263,8 +360,7 @@ nfnl_cthelper_update(const struct nlattr * const tb[], | |||
263 | return -EBUSY; | 360 | return -EBUSY; |
264 | 361 | ||
265 | if (tb[NFCTH_POLICY]) { | 362 | if (tb[NFCTH_POLICY]) { |
266 | ret = nfnl_cthelper_parse_expect_policy(helper, | 363 | ret = nfnl_cthelper_update_policy(helper, tb[NFCTH_POLICY]); |
267 | tb[NFCTH_POLICY]); | ||
268 | if (ret < 0) | 364 | if (ret < 0) |
269 | return ret; | 365 | return ret; |
270 | } | 366 | } |
@@ -293,7 +389,8 @@ static int nfnl_cthelper_new(struct net *net, struct sock *nfnl, | |||
293 | const char *helper_name; | 389 | const char *helper_name; |
294 | struct nf_conntrack_helper *cur, *helper = NULL; | 390 | struct nf_conntrack_helper *cur, *helper = NULL; |
295 | struct nf_conntrack_tuple tuple; | 391 | struct nf_conntrack_tuple tuple; |
296 | int ret = 0, i; | 392 | struct nfnl_cthelper *nlcth; |
393 | int ret = 0; | ||
297 | 394 | ||
298 | if (!tb[NFCTH_NAME] || !tb[NFCTH_TUPLE]) | 395 | if (!tb[NFCTH_NAME] || !tb[NFCTH_TUPLE]) |
299 | return -EINVAL; | 396 | return -EINVAL; |
@@ -304,31 +401,22 @@ static int nfnl_cthelper_new(struct net *net, struct sock *nfnl, | |||
304 | if (ret < 0) | 401 | if (ret < 0) |
305 | return ret; | 402 | return ret; |
306 | 403 | ||
307 | rcu_read_lock(); | 404 | list_for_each_entry(nlcth, &nfnl_cthelper_list, list) { |
308 | for (i = 0; i < nf_ct_helper_hsize && !helper; i++) { | 405 | cur = &nlcth->helper; |
309 | hlist_for_each_entry_rcu(cur, &nf_ct_helper_hash[i], hnode) { | ||
310 | 406 | ||
311 | /* skip non-userspace conntrack helpers. */ | 407 | if (strncmp(cur->name, helper_name, NF_CT_HELPER_NAME_LEN)) |
312 | if (!(cur->flags & NF_CT_HELPER_F_USERSPACE)) | 408 | continue; |
313 | continue; | ||
314 | 409 | ||
315 | if (strncmp(cur->name, helper_name, | 410 | if ((tuple.src.l3num != cur->tuple.src.l3num || |
316 | NF_CT_HELPER_NAME_LEN) != 0) | 411 | tuple.dst.protonum != cur->tuple.dst.protonum)) |
317 | continue; | 412 | continue; |
318 | 413 | ||
319 | if ((tuple.src.l3num != cur->tuple.src.l3num || | 414 | if (nlh->nlmsg_flags & NLM_F_EXCL) |
320 | tuple.dst.protonum != cur->tuple.dst.protonum)) | 415 | return -EEXIST; |
321 | continue; | ||
322 | 416 | ||
323 | if (nlh->nlmsg_flags & NLM_F_EXCL) { | 417 | helper = cur; |
324 | ret = -EEXIST; | 418 | break; |
325 | goto err; | ||
326 | } | ||
327 | helper = cur; | ||
328 | break; | ||
329 | } | ||
330 | } | 419 | } |
331 | rcu_read_unlock(); | ||
332 | 420 | ||
333 | if (helper == NULL) | 421 | if (helper == NULL) |
334 | ret = nfnl_cthelper_create(tb, &tuple); | 422 | ret = nfnl_cthelper_create(tb, &tuple); |
@@ -336,9 +424,6 @@ static int nfnl_cthelper_new(struct net *net, struct sock *nfnl, | |||
336 | ret = nfnl_cthelper_update(tb, helper); | 424 | ret = nfnl_cthelper_update(tb, helper); |
337 | 425 | ||
338 | return ret; | 426 | return ret; |
339 | err: | ||
340 | rcu_read_unlock(); | ||
341 | return ret; | ||
342 | } | 427 | } |
343 | 428 | ||
344 | static int | 429 | static int |
@@ -377,10 +462,10 @@ nfnl_cthelper_dump_policy(struct sk_buff *skb, | |||
377 | goto nla_put_failure; | 462 | goto nla_put_failure; |
378 | 463 | ||
379 | if (nla_put_be32(skb, NFCTH_POLICY_SET_NUM, | 464 | if (nla_put_be32(skb, NFCTH_POLICY_SET_NUM, |
380 | htonl(helper->expect_class_max))) | 465 | htonl(helper->expect_class_max + 1))) |
381 | goto nla_put_failure; | 466 | goto nla_put_failure; |
382 | 467 | ||
383 | for (i=0; i<helper->expect_class_max; i++) { | 468 | for (i = 0; i < helper->expect_class_max + 1; i++) { |
384 | nest_parms2 = nla_nest_start(skb, | 469 | nest_parms2 = nla_nest_start(skb, |
385 | (NFCTH_POLICY_SET+i) | NLA_F_NESTED); | 470 | (NFCTH_POLICY_SET+i) | NLA_F_NESTED); |
386 | if (nest_parms2 == NULL) | 471 | if (nest_parms2 == NULL) |
@@ -502,11 +587,12 @@ static int nfnl_cthelper_get(struct net *net, struct sock *nfnl, | |||
502 | struct sk_buff *skb, const struct nlmsghdr *nlh, | 587 | struct sk_buff *skb, const struct nlmsghdr *nlh, |
503 | const struct nlattr * const tb[]) | 588 | const struct nlattr * const tb[]) |
504 | { | 589 | { |
505 | int ret = -ENOENT, i; | 590 | int ret = -ENOENT; |
506 | struct nf_conntrack_helper *cur; | 591 | struct nf_conntrack_helper *cur; |
507 | struct sk_buff *skb2; | 592 | struct sk_buff *skb2; |
508 | char *helper_name = NULL; | 593 | char *helper_name = NULL; |
509 | struct nf_conntrack_tuple tuple; | 594 | struct nf_conntrack_tuple tuple; |
595 | struct nfnl_cthelper *nlcth; | ||
510 | bool tuple_set = false; | 596 | bool tuple_set = false; |
511 | 597 | ||
512 | if (nlh->nlmsg_flags & NLM_F_DUMP) { | 598 | if (nlh->nlmsg_flags & NLM_F_DUMP) { |
@@ -527,45 +613,39 @@ static int nfnl_cthelper_get(struct net *net, struct sock *nfnl, | |||
527 | tuple_set = true; | 613 | tuple_set = true; |
528 | } | 614 | } |
529 | 615 | ||
530 | for (i = 0; i < nf_ct_helper_hsize; i++) { | 616 | list_for_each_entry(nlcth, &nfnl_cthelper_list, list) { |
531 | hlist_for_each_entry_rcu(cur, &nf_ct_helper_hash[i], hnode) { | 617 | cur = &nlcth->helper; |
618 | if (helper_name && | ||
619 | strncmp(cur->name, helper_name, NF_CT_HELPER_NAME_LEN)) | ||
620 | continue; | ||
532 | 621 | ||
533 | /* skip non-userspace conntrack helpers. */ | 622 | if (tuple_set && |
534 | if (!(cur->flags & NF_CT_HELPER_F_USERSPACE)) | 623 | (tuple.src.l3num != cur->tuple.src.l3num || |
535 | continue; | 624 | tuple.dst.protonum != cur->tuple.dst.protonum)) |
625 | continue; | ||
536 | 626 | ||
537 | if (helper_name && strncmp(cur->name, helper_name, | 627 | skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); |
538 | NF_CT_HELPER_NAME_LEN) != 0) { | 628 | if (skb2 == NULL) { |
539 | continue; | 629 | ret = -ENOMEM; |
540 | } | 630 | break; |
541 | if (tuple_set && | 631 | } |
542 | (tuple.src.l3num != cur->tuple.src.l3num || | ||
543 | tuple.dst.protonum != cur->tuple.dst.protonum)) | ||
544 | continue; | ||
545 | |||
546 | skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | ||
547 | if (skb2 == NULL) { | ||
548 | ret = -ENOMEM; | ||
549 | break; | ||
550 | } | ||
551 | 632 | ||
552 | ret = nfnl_cthelper_fill_info(skb2, NETLINK_CB(skb).portid, | 633 | ret = nfnl_cthelper_fill_info(skb2, NETLINK_CB(skb).portid, |
553 | nlh->nlmsg_seq, | 634 | nlh->nlmsg_seq, |
554 | NFNL_MSG_TYPE(nlh->nlmsg_type), | 635 | NFNL_MSG_TYPE(nlh->nlmsg_type), |
555 | NFNL_MSG_CTHELPER_NEW, cur); | 636 | NFNL_MSG_CTHELPER_NEW, cur); |
556 | if (ret <= 0) { | 637 | if (ret <= 0) { |
557 | kfree_skb(skb2); | 638 | kfree_skb(skb2); |
558 | break; | 639 | break; |
559 | } | 640 | } |
560 | 641 | ||
561 | ret = netlink_unicast(nfnl, skb2, NETLINK_CB(skb).portid, | 642 | ret = netlink_unicast(nfnl, skb2, NETLINK_CB(skb).portid, |
562 | MSG_DONTWAIT); | 643 | MSG_DONTWAIT); |
563 | if (ret > 0) | 644 | if (ret > 0) |
564 | ret = 0; | 645 | ret = 0; |
565 | 646 | ||
566 | /* this avoids a loop in nfnetlink. */ | 647 | /* this avoids a loop in nfnetlink. */ |
567 | return ret == -EAGAIN ? -ENOBUFS : ret; | 648 | return ret == -EAGAIN ? -ENOBUFS : ret; |
568 | } | ||
569 | } | 649 | } |
570 | return ret; | 650 | return ret; |
571 | } | 651 | } |
@@ -576,10 +656,10 @@ static int nfnl_cthelper_del(struct net *net, struct sock *nfnl, | |||
576 | { | 656 | { |
577 | char *helper_name = NULL; | 657 | char *helper_name = NULL; |
578 | struct nf_conntrack_helper *cur; | 658 | struct nf_conntrack_helper *cur; |
579 | struct hlist_node *tmp; | ||
580 | struct nf_conntrack_tuple tuple; | 659 | struct nf_conntrack_tuple tuple; |
581 | bool tuple_set = false, found = false; | 660 | bool tuple_set = false, found = false; |
582 | int i, j = 0, ret; | 661 | struct nfnl_cthelper *nlcth, *n; |
662 | int j = 0, ret; | ||
583 | 663 | ||
584 | if (tb[NFCTH_NAME]) | 664 | if (tb[NFCTH_NAME]) |
585 | helper_name = nla_data(tb[NFCTH_NAME]); | 665 | helper_name = nla_data(tb[NFCTH_NAME]); |
@@ -592,28 +672,27 @@ static int nfnl_cthelper_del(struct net *net, struct sock *nfnl, | |||
592 | tuple_set = true; | 672 | tuple_set = true; |
593 | } | 673 | } |
594 | 674 | ||
595 | for (i = 0; i < nf_ct_helper_hsize; i++) { | 675 | list_for_each_entry_safe(nlcth, n, &nfnl_cthelper_list, list) { |
596 | hlist_for_each_entry_safe(cur, tmp, &nf_ct_helper_hash[i], | 676 | cur = &nlcth->helper; |
597 | hnode) { | 677 | j++; |
598 | /* skip non-userspace conntrack helpers. */ | ||
599 | if (!(cur->flags & NF_CT_HELPER_F_USERSPACE)) | ||
600 | continue; | ||
601 | 678 | ||
602 | j++; | 679 | if (helper_name && |
680 | strncmp(cur->name, helper_name, NF_CT_HELPER_NAME_LEN)) | ||
681 | continue; | ||
603 | 682 | ||
604 | if (helper_name && strncmp(cur->name, helper_name, | 683 | if (tuple_set && |
605 | NF_CT_HELPER_NAME_LEN) != 0) { | 684 | (tuple.src.l3num != cur->tuple.src.l3num || |
606 | continue; | 685 | tuple.dst.protonum != cur->tuple.dst.protonum)) |
607 | } | 686 | continue; |
608 | if (tuple_set && | ||
609 | (tuple.src.l3num != cur->tuple.src.l3num || | ||
610 | tuple.dst.protonum != cur->tuple.dst.protonum)) | ||
611 | continue; | ||
612 | 687 | ||
613 | found = true; | 688 | found = true; |
614 | nf_conntrack_helper_unregister(cur); | 689 | nf_conntrack_helper_unregister(cur); |
615 | } | 690 | kfree(cur->expect_policy); |
691 | |||
692 | list_del(&nlcth->list); | ||
693 | kfree(nlcth); | ||
616 | } | 694 | } |
695 | |||
617 | /* Make sure we return success if we flush and there is no helpers */ | 696 | /* Make sure we return success if we flush and there is no helpers */ |
618 | return (found || j == 0) ? 0 : -ENOENT; | 697 | return (found || j == 0) ? 0 : -ENOENT; |
619 | } | 698 | } |
@@ -662,20 +741,16 @@ err_out: | |||
662 | static void __exit nfnl_cthelper_exit(void) | 741 | static void __exit nfnl_cthelper_exit(void) |
663 | { | 742 | { |
664 | struct nf_conntrack_helper *cur; | 743 | struct nf_conntrack_helper *cur; |
665 | struct hlist_node *tmp; | 744 | struct nfnl_cthelper *nlcth, *n; |
666 | int i; | ||
667 | 745 | ||
668 | nfnetlink_subsys_unregister(&nfnl_cthelper_subsys); | 746 | nfnetlink_subsys_unregister(&nfnl_cthelper_subsys); |
669 | 747 | ||
670 | for (i=0; i<nf_ct_helper_hsize; i++) { | 748 | list_for_each_entry_safe(nlcth, n, &nfnl_cthelper_list, list) { |
671 | hlist_for_each_entry_safe(cur, tmp, &nf_ct_helper_hash[i], | 749 | cur = &nlcth->helper; |
672 | hnode) { | ||
673 | /* skip non-userspace conntrack helpers. */ | ||
674 | if (!(cur->flags & NF_CT_HELPER_F_USERSPACE)) | ||
675 | continue; | ||
676 | 750 | ||
677 | nf_conntrack_helper_unregister(cur); | 751 | nf_conntrack_helper_unregister(cur); |
678 | } | 752 | kfree(cur->expect_policy); |
753 | kfree(nlcth); | ||
679 | } | 754 | } |
680 | } | 755 | } |
681 | 756 | ||
diff --git a/net/netfilter/nfnetlink_cttimeout.c b/net/netfilter/nfnetlink_cttimeout.c index 139e0867e56e..47d6656c9119 100644 --- a/net/netfilter/nfnetlink_cttimeout.c +++ b/net/netfilter/nfnetlink_cttimeout.c | |||
@@ -646,8 +646,8 @@ static void __exit cttimeout_exit(void) | |||
646 | #ifdef CONFIG_NF_CONNTRACK_TIMEOUT | 646 | #ifdef CONFIG_NF_CONNTRACK_TIMEOUT |
647 | RCU_INIT_POINTER(nf_ct_timeout_find_get_hook, NULL); | 647 | RCU_INIT_POINTER(nf_ct_timeout_find_get_hook, NULL); |
648 | RCU_INIT_POINTER(nf_ct_timeout_put_hook, NULL); | 648 | RCU_INIT_POINTER(nf_ct_timeout_put_hook, NULL); |
649 | synchronize_rcu(); | ||
649 | #endif /* CONFIG_NF_CONNTRACK_TIMEOUT */ | 650 | #endif /* CONFIG_NF_CONNTRACK_TIMEOUT */ |
650 | rcu_barrier(); | ||
651 | } | 651 | } |
652 | 652 | ||
653 | module_init(cttimeout_init); | 653 | module_init(cttimeout_init); |
diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c index 3ee0b8a000a4..933509ebf3d3 100644 --- a/net/netfilter/nfnetlink_queue.c +++ b/net/netfilter/nfnetlink_queue.c | |||
@@ -443,7 +443,7 @@ nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue, | |||
443 | skb = alloc_skb(size, GFP_ATOMIC); | 443 | skb = alloc_skb(size, GFP_ATOMIC); |
444 | if (!skb) { | 444 | if (!skb) { |
445 | skb_tx_error(entskb); | 445 | skb_tx_error(entskb); |
446 | return NULL; | 446 | goto nlmsg_failure; |
447 | } | 447 | } |
448 | 448 | ||
449 | nlh = nlmsg_put(skb, 0, 0, | 449 | nlh = nlmsg_put(skb, 0, 0, |
@@ -452,7 +452,7 @@ nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue, | |||
452 | if (!nlh) { | 452 | if (!nlh) { |
453 | skb_tx_error(entskb); | 453 | skb_tx_error(entskb); |
454 | kfree_skb(skb); | 454 | kfree_skb(skb); |
455 | return NULL; | 455 | goto nlmsg_failure; |
456 | } | 456 | } |
457 | nfmsg = nlmsg_data(nlh); | 457 | nfmsg = nlmsg_data(nlh); |
458 | nfmsg->nfgen_family = entry->state.pf; | 458 | nfmsg->nfgen_family = entry->state.pf; |
@@ -598,12 +598,17 @@ nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue, | |||
598 | } | 598 | } |
599 | 599 | ||
600 | nlh->nlmsg_len = skb->len; | 600 | nlh->nlmsg_len = skb->len; |
601 | if (seclen) | ||
602 | security_release_secctx(secdata, seclen); | ||
601 | return skb; | 603 | return skb; |
602 | 604 | ||
603 | nla_put_failure: | 605 | nla_put_failure: |
604 | skb_tx_error(entskb); | 606 | skb_tx_error(entskb); |
605 | kfree_skb(skb); | 607 | kfree_skb(skb); |
606 | net_err_ratelimited("nf_queue: error creating packet message\n"); | 608 | net_err_ratelimited("nf_queue: error creating packet message\n"); |
609 | nlmsg_failure: | ||
610 | if (seclen) | ||
611 | security_release_secctx(secdata, seclen); | ||
607 | return NULL; | 612 | return NULL; |
608 | } | 613 | } |
609 | 614 | ||
diff --git a/net/openvswitch/conntrack.c b/net/openvswitch/conntrack.c index e0a87776a010..7b2c2fce408a 100644 --- a/net/openvswitch/conntrack.c +++ b/net/openvswitch/conntrack.c | |||
@@ -643,8 +643,8 @@ static bool skb_nfct_cached(struct net *net, | |||
643 | */ | 643 | */ |
644 | if (nf_ct_is_confirmed(ct)) | 644 | if (nf_ct_is_confirmed(ct)) |
645 | nf_ct_delete(ct, 0, 0); | 645 | nf_ct_delete(ct, 0, 0); |
646 | else | 646 | |
647 | nf_conntrack_put(&ct->ct_general); | 647 | nf_conntrack_put(&ct->ct_general); |
648 | nf_ct_set(skb, NULL, 0); | 648 | nf_ct_set(skb, NULL, 0); |
649 | return false; | 649 | return false; |
650 | } | 650 | } |
diff --git a/net/openvswitch/flow.c b/net/openvswitch/flow.c index 9d4bb8eb63f2..3f76cb765e5b 100644 --- a/net/openvswitch/flow.c +++ b/net/openvswitch/flow.c | |||
@@ -527,7 +527,7 @@ static int key_extract(struct sk_buff *skb, struct sw_flow_key *key) | |||
527 | 527 | ||
528 | /* Link layer. */ | 528 | /* Link layer. */ |
529 | clear_vlan(key); | 529 | clear_vlan(key); |
530 | if (key->mac_proto == MAC_PROTO_NONE) { | 530 | if (ovs_key_mac_proto(key) == MAC_PROTO_NONE) { |
531 | if (unlikely(eth_type_vlan(skb->protocol))) | 531 | if (unlikely(eth_type_vlan(skb->protocol))) |
532 | return -EINVAL; | 532 | return -EINVAL; |
533 | 533 | ||
@@ -745,7 +745,13 @@ static int key_extract(struct sk_buff *skb, struct sw_flow_key *key) | |||
745 | 745 | ||
746 | int ovs_flow_key_update(struct sk_buff *skb, struct sw_flow_key *key) | 746 | int ovs_flow_key_update(struct sk_buff *skb, struct sw_flow_key *key) |
747 | { | 747 | { |
748 | return key_extract(skb, key); | 748 | int res; |
749 | |||
750 | res = key_extract(skb, key); | ||
751 | if (!res) | ||
752 | key->mac_proto &= ~SW_FLOW_KEY_INVALID; | ||
753 | |||
754 | return res; | ||
749 | } | 755 | } |
750 | 756 | ||
751 | static int key_extract_mac_proto(struct sk_buff *skb) | 757 | static int key_extract_mac_proto(struct sk_buff *skb) |
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index a0dbe7ca8f72..8489beff5c25 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c | |||
@@ -3665,6 +3665,8 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv | |||
3665 | return -EBUSY; | 3665 | return -EBUSY; |
3666 | if (copy_from_user(&val, optval, sizeof(val))) | 3666 | if (copy_from_user(&val, optval, sizeof(val))) |
3667 | return -EFAULT; | 3667 | return -EFAULT; |
3668 | if (val > INT_MAX) | ||
3669 | return -EINVAL; | ||
3668 | po->tp_reserve = val; | 3670 | po->tp_reserve = val; |
3669 | return 0; | 3671 | return 0; |
3670 | } | 3672 | } |
@@ -4193,8 +4195,8 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u, | |||
4193 | if (unlikely(!PAGE_ALIGNED(req->tp_block_size))) | 4195 | if (unlikely(!PAGE_ALIGNED(req->tp_block_size))) |
4194 | goto out; | 4196 | goto out; |
4195 | if (po->tp_version >= TPACKET_V3 && | 4197 | if (po->tp_version >= TPACKET_V3 && |
4196 | (int)(req->tp_block_size - | 4198 | req->tp_block_size <= |
4197 | BLK_PLUS_PRIV(req_u->req3.tp_sizeof_priv)) <= 0) | 4199 | BLK_PLUS_PRIV((u64)req_u->req3.tp_sizeof_priv)) |
4198 | goto out; | 4200 | goto out; |
4199 | if (unlikely(req->tp_frame_size < po->tp_hdrlen + | 4201 | if (unlikely(req->tp_frame_size < po->tp_hdrlen + |
4200 | po->tp_reserve)) | 4202 | po->tp_reserve)) |
@@ -4205,6 +4207,8 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u, | |||
4205 | rb->frames_per_block = req->tp_block_size / req->tp_frame_size; | 4207 | rb->frames_per_block = req->tp_block_size / req->tp_frame_size; |
4206 | if (unlikely(rb->frames_per_block == 0)) | 4208 | if (unlikely(rb->frames_per_block == 0)) |
4207 | goto out; | 4209 | goto out; |
4210 | if (unlikely(req->tp_block_size > UINT_MAX / req->tp_block_nr)) | ||
4211 | goto out; | ||
4208 | if (unlikely((rb->frames_per_block * req->tp_block_nr) != | 4212 | if (unlikely((rb->frames_per_block * req->tp_block_nr) != |
4209 | req->tp_frame_nr)) | 4213 | req->tp_frame_nr)) |
4210 | goto out; | 4214 | goto out; |
diff --git a/net/sctp/associola.c b/net/sctp/associola.c index 0439a1a68367..a9708da28eb5 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c | |||
@@ -246,6 +246,9 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a | |||
246 | if (!sctp_ulpq_init(&asoc->ulpq, asoc)) | 246 | if (!sctp_ulpq_init(&asoc->ulpq, asoc)) |
247 | goto fail_init; | 247 | goto fail_init; |
248 | 248 | ||
249 | if (sctp_stream_new(asoc, gfp)) | ||
250 | goto fail_init; | ||
251 | |||
249 | /* Assume that peer would support both address types unless we are | 252 | /* Assume that peer would support both address types unless we are |
250 | * told otherwise. | 253 | * told otherwise. |
251 | */ | 254 | */ |
@@ -264,7 +267,7 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a | |||
264 | /* AUTH related initializations */ | 267 | /* AUTH related initializations */ |
265 | INIT_LIST_HEAD(&asoc->endpoint_shared_keys); | 268 | INIT_LIST_HEAD(&asoc->endpoint_shared_keys); |
266 | if (sctp_auth_asoc_copy_shkeys(ep, asoc, gfp)) | 269 | if (sctp_auth_asoc_copy_shkeys(ep, asoc, gfp)) |
267 | goto fail_init; | 270 | goto stream_free; |
268 | 271 | ||
269 | asoc->active_key_id = ep->active_key_id; | 272 | asoc->active_key_id = ep->active_key_id; |
270 | asoc->prsctp_enable = ep->prsctp_enable; | 273 | asoc->prsctp_enable = ep->prsctp_enable; |
@@ -287,6 +290,8 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a | |||
287 | 290 | ||
288 | return asoc; | 291 | return asoc; |
289 | 292 | ||
293 | stream_free: | ||
294 | sctp_stream_free(asoc->stream); | ||
290 | fail_init: | 295 | fail_init: |
291 | sock_put(asoc->base.sk); | 296 | sock_put(asoc->base.sk); |
292 | sctp_endpoint_put(asoc->ep); | 297 | sctp_endpoint_put(asoc->ep); |
@@ -1407,7 +1412,7 @@ sctp_assoc_choose_alter_transport(struct sctp_association *asoc, | |||
1407 | /* Update the association's pmtu and frag_point by going through all the | 1412 | /* Update the association's pmtu and frag_point by going through all the |
1408 | * transports. This routine is called when a transport's PMTU has changed. | 1413 | * transports. This routine is called when a transport's PMTU has changed. |
1409 | */ | 1414 | */ |
1410 | void sctp_assoc_sync_pmtu(struct sock *sk, struct sctp_association *asoc) | 1415 | void sctp_assoc_sync_pmtu(struct sctp_association *asoc) |
1411 | { | 1416 | { |
1412 | struct sctp_transport *t; | 1417 | struct sctp_transport *t; |
1413 | __u32 pmtu = 0; | 1418 | __u32 pmtu = 0; |
@@ -1419,8 +1424,8 @@ void sctp_assoc_sync_pmtu(struct sock *sk, struct sctp_association *asoc) | |||
1419 | list_for_each_entry(t, &asoc->peer.transport_addr_list, | 1424 | list_for_each_entry(t, &asoc->peer.transport_addr_list, |
1420 | transports) { | 1425 | transports) { |
1421 | if (t->pmtu_pending && t->dst) { | 1426 | if (t->pmtu_pending && t->dst) { |
1422 | sctp_transport_update_pmtu(sk, t, | 1427 | sctp_transport_update_pmtu( |
1423 | SCTP_TRUNC4(dst_mtu(t->dst))); | 1428 | t, SCTP_TRUNC4(dst_mtu(t->dst))); |
1424 | t->pmtu_pending = 0; | 1429 | t->pmtu_pending = 0; |
1425 | } | 1430 | } |
1426 | if (!pmtu || (t->pathmtu < pmtu)) | 1431 | if (!pmtu || (t->pathmtu < pmtu)) |
diff --git a/net/sctp/input.c b/net/sctp/input.c index 2a28ab20487f..0e06a278d2a9 100644 --- a/net/sctp/input.c +++ b/net/sctp/input.c | |||
@@ -401,10 +401,10 @@ void sctp_icmp_frag_needed(struct sock *sk, struct sctp_association *asoc, | |||
401 | 401 | ||
402 | if (t->param_flags & SPP_PMTUD_ENABLE) { | 402 | if (t->param_flags & SPP_PMTUD_ENABLE) { |
403 | /* Update transports view of the MTU */ | 403 | /* Update transports view of the MTU */ |
404 | sctp_transport_update_pmtu(sk, t, pmtu); | 404 | sctp_transport_update_pmtu(t, pmtu); |
405 | 405 | ||
406 | /* Update association pmtu. */ | 406 | /* Update association pmtu. */ |
407 | sctp_assoc_sync_pmtu(sk, asoc); | 407 | sctp_assoc_sync_pmtu(asoc); |
408 | } | 408 | } |
409 | 409 | ||
410 | /* Retransmit with the new pmtu setting. | 410 | /* Retransmit with the new pmtu setting. |
diff --git a/net/sctp/output.c b/net/sctp/output.c index 1224421036b3..1409a875ad8e 100644 --- a/net/sctp/output.c +++ b/net/sctp/output.c | |||
@@ -86,43 +86,53 @@ void sctp_packet_config(struct sctp_packet *packet, __u32 vtag, | |||
86 | { | 86 | { |
87 | struct sctp_transport *tp = packet->transport; | 87 | struct sctp_transport *tp = packet->transport; |
88 | struct sctp_association *asoc = tp->asoc; | 88 | struct sctp_association *asoc = tp->asoc; |
89 | struct sock *sk; | ||
89 | 90 | ||
90 | pr_debug("%s: packet:%p vtag:0x%x\n", __func__, packet, vtag); | 91 | pr_debug("%s: packet:%p vtag:0x%x\n", __func__, packet, vtag); |
91 | |||
92 | packet->vtag = vtag; | 92 | packet->vtag = vtag; |
93 | 93 | ||
94 | if (asoc && tp->dst) { | 94 | /* do the following jobs only once for a flush schedule */ |
95 | struct sock *sk = asoc->base.sk; | 95 | if (!sctp_packet_empty(packet)) |
96 | 96 | return; | |
97 | rcu_read_lock(); | ||
98 | if (__sk_dst_get(sk) != tp->dst) { | ||
99 | dst_hold(tp->dst); | ||
100 | sk_setup_caps(sk, tp->dst); | ||
101 | } | ||
102 | |||
103 | if (sk_can_gso(sk)) { | ||
104 | struct net_device *dev = tp->dst->dev; | ||
105 | 97 | ||
106 | packet->max_size = dev->gso_max_size; | 98 | /* set packet max_size with pathmtu */ |
107 | } else { | 99 | packet->max_size = tp->pathmtu; |
108 | packet->max_size = asoc->pathmtu; | 100 | if (!asoc) |
109 | } | 101 | return; |
110 | rcu_read_unlock(); | ||
111 | 102 | ||
112 | } else { | 103 | /* update dst or transport pathmtu if in need */ |
113 | packet->max_size = tp->pathmtu; | 104 | sk = asoc->base.sk; |
105 | if (!sctp_transport_dst_check(tp)) { | ||
106 | sctp_transport_route(tp, NULL, sctp_sk(sk)); | ||
107 | if (asoc->param_flags & SPP_PMTUD_ENABLE) | ||
108 | sctp_assoc_sync_pmtu(asoc); | ||
109 | } else if (!sctp_transport_pmtu_check(tp)) { | ||
110 | if (asoc->param_flags & SPP_PMTUD_ENABLE) | ||
111 | sctp_assoc_sync_pmtu(asoc); | ||
114 | } | 112 | } |
115 | 113 | ||
116 | if (ecn_capable && sctp_packet_empty(packet)) { | 114 | /* If there a is a prepend chunk stick it on the list before |
117 | struct sctp_chunk *chunk; | 115 | * any other chunks get appended. |
116 | */ | ||
117 | if (ecn_capable) { | ||
118 | struct sctp_chunk *chunk = sctp_get_ecne_prepend(asoc); | ||
118 | 119 | ||
119 | /* If there a is a prepend chunk stick it on the list before | ||
120 | * any other chunks get appended. | ||
121 | */ | ||
122 | chunk = sctp_get_ecne_prepend(asoc); | ||
123 | if (chunk) | 120 | if (chunk) |
124 | sctp_packet_append_chunk(packet, chunk); | 121 | sctp_packet_append_chunk(packet, chunk); |
125 | } | 122 | } |
123 | |||
124 | if (!tp->dst) | ||
125 | return; | ||
126 | |||
127 | /* set packet max_size with gso_max_size if gso is enabled*/ | ||
128 | rcu_read_lock(); | ||
129 | if (__sk_dst_get(sk) != tp->dst) { | ||
130 | dst_hold(tp->dst); | ||
131 | sk_setup_caps(sk, tp->dst); | ||
132 | } | ||
133 | packet->max_size = sk_can_gso(sk) ? tp->dst->dev->gso_max_size | ||
134 | : asoc->pathmtu; | ||
135 | rcu_read_unlock(); | ||
126 | } | 136 | } |
127 | 137 | ||
128 | /* Initialize the packet structure. */ | 138 | /* Initialize the packet structure. */ |
@@ -582,12 +592,7 @@ int sctp_packet_transmit(struct sctp_packet *packet, gfp_t gfp) | |||
582 | sh->vtag = htonl(packet->vtag); | 592 | sh->vtag = htonl(packet->vtag); |
583 | sh->checksum = 0; | 593 | sh->checksum = 0; |
584 | 594 | ||
585 | /* update dst if in need */ | 595 | /* drop packet if no dst */ |
586 | if (!sctp_transport_dst_check(tp)) { | ||
587 | sctp_transport_route(tp, NULL, sctp_sk(sk)); | ||
588 | if (asoc && asoc->param_flags & SPP_PMTUD_ENABLE) | ||
589 | sctp_assoc_sync_pmtu(sk, asoc); | ||
590 | } | ||
591 | dst = dst_clone(tp->dst); | 596 | dst = dst_clone(tp->dst); |
592 | if (!dst) { | 597 | if (!dst) { |
593 | IP_INC_STATS(sock_net(sk), IPSTATS_MIB_OUTNOROUTES); | 598 | IP_INC_STATS(sock_net(sk), IPSTATS_MIB_OUTNOROUTES); |
@@ -704,7 +709,7 @@ static sctp_xmit_t sctp_packet_can_append_data(struct sctp_packet *packet, | |||
704 | */ | 709 | */ |
705 | 710 | ||
706 | if ((sctp_sk(asoc->base.sk)->nodelay || inflight == 0) && | 711 | if ((sctp_sk(asoc->base.sk)->nodelay || inflight == 0) && |
707 | !chunk->msg->force_delay) | 712 | !asoc->force_delay) |
708 | /* Nothing unacked */ | 713 | /* Nothing unacked */ |
709 | return SCTP_XMIT_OK; | 714 | return SCTP_XMIT_OK; |
710 | 715 | ||
diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c index 025ccff67072..8081476ed313 100644 --- a/net/sctp/outqueue.c +++ b/net/sctp/outqueue.c | |||
@@ -1026,8 +1026,7 @@ static void sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp) | |||
1026 | /* RFC 2960 6.5 Every DATA chunk MUST carry a valid | 1026 | /* RFC 2960 6.5 Every DATA chunk MUST carry a valid |
1027 | * stream identifier. | 1027 | * stream identifier. |
1028 | */ | 1028 | */ |
1029 | if (chunk->sinfo.sinfo_stream >= | 1029 | if (chunk->sinfo.sinfo_stream >= asoc->stream->outcnt) { |
1030 | asoc->c.sinit_num_ostreams) { | ||
1031 | 1030 | ||
1032 | /* Mark as failed send. */ | 1031 | /* Mark as failed send. */ |
1033 | sctp_chunk_fail(chunk, SCTP_ERROR_INV_STRM); | 1032 | sctp_chunk_fail(chunk, SCTP_ERROR_INV_STRM); |
diff --git a/net/sctp/proc.c b/net/sctp/proc.c index 206377fe91ec..a0b29d43627f 100644 --- a/net/sctp/proc.c +++ b/net/sctp/proc.c | |||
@@ -361,8 +361,8 @@ static int sctp_assocs_seq_show(struct seq_file *seq, void *v) | |||
361 | sctp_seq_dump_remote_addrs(seq, assoc); | 361 | sctp_seq_dump_remote_addrs(seq, assoc); |
362 | seq_printf(seq, "\t%8lu %5d %5d %4d %4d %4d %8d " | 362 | seq_printf(seq, "\t%8lu %5d %5d %4d %4d %4d %8d " |
363 | "%8d %8d %8d %8d", | 363 | "%8d %8d %8d %8d", |
364 | assoc->hbinterval, assoc->c.sinit_max_instreams, | 364 | assoc->hbinterval, assoc->stream->incnt, |
365 | assoc->c.sinit_num_ostreams, assoc->max_retrans, | 365 | assoc->stream->outcnt, assoc->max_retrans, |
366 | assoc->init_retries, assoc->shutdown_retries, | 366 | assoc->init_retries, assoc->shutdown_retries, |
367 | assoc->rtx_data_chunks, | 367 | assoc->rtx_data_chunks, |
368 | atomic_read(&sk->sk_wmem_alloc), | 368 | atomic_read(&sk->sk_wmem_alloc), |
diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index 969a30c7bb54..118faff6a332 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c | |||
@@ -2460,15 +2460,10 @@ int sctp_process_init(struct sctp_association *asoc, struct sctp_chunk *chunk, | |||
2460 | * association. | 2460 | * association. |
2461 | */ | 2461 | */ |
2462 | if (!asoc->temp) { | 2462 | if (!asoc->temp) { |
2463 | int error; | 2463 | if (sctp_stream_init(asoc, gfp)) |
2464 | |||
2465 | asoc->stream = sctp_stream_new(asoc->c.sinit_max_instreams, | ||
2466 | asoc->c.sinit_num_ostreams, gfp); | ||
2467 | if (!asoc->stream) | ||
2468 | goto clean_up; | 2464 | goto clean_up; |
2469 | 2465 | ||
2470 | error = sctp_assoc_set_id(asoc, gfp); | 2466 | if (sctp_assoc_set_id(asoc, gfp)) |
2471 | if (error) | ||
2472 | goto clean_up; | 2467 | goto clean_up; |
2473 | } | 2468 | } |
2474 | 2469 | ||
diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index e03bb1aab4d0..24c6ccce7539 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c | |||
@@ -3946,7 +3946,7 @@ sctp_disposition_t sctp_sf_eat_fwd_tsn(struct net *net, | |||
3946 | 3946 | ||
3947 | /* Silently discard the chunk if stream-id is not valid */ | 3947 | /* Silently discard the chunk if stream-id is not valid */ |
3948 | sctp_walk_fwdtsn(skip, chunk) { | 3948 | sctp_walk_fwdtsn(skip, chunk) { |
3949 | if (ntohs(skip->stream) >= asoc->c.sinit_max_instreams) | 3949 | if (ntohs(skip->stream) >= asoc->stream->incnt) |
3950 | goto discard_noforce; | 3950 | goto discard_noforce; |
3951 | } | 3951 | } |
3952 | 3952 | ||
@@ -4017,7 +4017,7 @@ sctp_disposition_t sctp_sf_eat_fwd_tsn_fast( | |||
4017 | 4017 | ||
4018 | /* Silently discard the chunk if stream-id is not valid */ | 4018 | /* Silently discard the chunk if stream-id is not valid */ |
4019 | sctp_walk_fwdtsn(skip, chunk) { | 4019 | sctp_walk_fwdtsn(skip, chunk) { |
4020 | if (ntohs(skip->stream) >= asoc->c.sinit_max_instreams) | 4020 | if (ntohs(skip->stream) >= asoc->stream->incnt) |
4021 | goto gen_shutdown; | 4021 | goto gen_shutdown; |
4022 | } | 4022 | } |
4023 | 4023 | ||
@@ -6353,7 +6353,7 @@ static int sctp_eat_data(const struct sctp_association *asoc, | |||
6353 | * and discard the DATA chunk. | 6353 | * and discard the DATA chunk. |
6354 | */ | 6354 | */ |
6355 | sid = ntohs(data_hdr->stream); | 6355 | sid = ntohs(data_hdr->stream); |
6356 | if (sid >= asoc->c.sinit_max_instreams) { | 6356 | if (sid >= asoc->stream->incnt) { |
6357 | /* Mark tsn as received even though we drop it */ | 6357 | /* Mark tsn as received even though we drop it */ |
6358 | sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_TSN, SCTP_U32(tsn)); | 6358 | sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_TSN, SCTP_U32(tsn)); |
6359 | 6359 | ||
diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 0f378ea2ae38..c1401f43d40f 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c | |||
@@ -1907,7 +1907,7 @@ static int sctp_sendmsg(struct sock *sk, struct msghdr *msg, size_t msg_len) | |||
1907 | } | 1907 | } |
1908 | 1908 | ||
1909 | if (asoc->pmtu_pending) | 1909 | if (asoc->pmtu_pending) |
1910 | sctp_assoc_pending_pmtu(sk, asoc); | 1910 | sctp_assoc_pending_pmtu(asoc); |
1911 | 1911 | ||
1912 | /* If fragmentation is disabled and the message length exceeds the | 1912 | /* If fragmentation is disabled and the message length exceeds the |
1913 | * association fragmentation point, return EMSGSIZE. The I-D | 1913 | * association fragmentation point, return EMSGSIZE. The I-D |
@@ -1920,7 +1920,7 @@ static int sctp_sendmsg(struct sock *sk, struct msghdr *msg, size_t msg_len) | |||
1920 | } | 1920 | } |
1921 | 1921 | ||
1922 | /* Check for invalid stream. */ | 1922 | /* Check for invalid stream. */ |
1923 | if (sinfo->sinfo_stream >= asoc->c.sinit_num_ostreams) { | 1923 | if (sinfo->sinfo_stream >= asoc->stream->outcnt) { |
1924 | err = -EINVAL; | 1924 | err = -EINVAL; |
1925 | goto out_free; | 1925 | goto out_free; |
1926 | } | 1926 | } |
@@ -1965,7 +1965,7 @@ static int sctp_sendmsg(struct sock *sk, struct msghdr *msg, size_t msg_len) | |||
1965 | err = PTR_ERR(datamsg); | 1965 | err = PTR_ERR(datamsg); |
1966 | goto out_free; | 1966 | goto out_free; |
1967 | } | 1967 | } |
1968 | datamsg->force_delay = !!(msg->msg_flags & MSG_MORE); | 1968 | asoc->force_delay = !!(msg->msg_flags & MSG_MORE); |
1969 | 1969 | ||
1970 | /* Now send the (possibly) fragmented message. */ | 1970 | /* Now send the (possibly) fragmented message. */ |
1971 | list_for_each_entry(chunk, &datamsg->chunks, frag_list) { | 1971 | list_for_each_entry(chunk, &datamsg->chunks, frag_list) { |
@@ -2435,7 +2435,7 @@ static int sctp_apply_peer_addr_params(struct sctp_paddrparams *params, | |||
2435 | if ((params->spp_flags & SPP_PMTUD_DISABLE) && params->spp_pathmtu) { | 2435 | if ((params->spp_flags & SPP_PMTUD_DISABLE) && params->spp_pathmtu) { |
2436 | if (trans) { | 2436 | if (trans) { |
2437 | trans->pathmtu = params->spp_pathmtu; | 2437 | trans->pathmtu = params->spp_pathmtu; |
2438 | sctp_assoc_sync_pmtu(sctp_opt2sk(sp), asoc); | 2438 | sctp_assoc_sync_pmtu(asoc); |
2439 | } else if (asoc) { | 2439 | } else if (asoc) { |
2440 | asoc->pathmtu = params->spp_pathmtu; | 2440 | asoc->pathmtu = params->spp_pathmtu; |
2441 | } else { | 2441 | } else { |
@@ -2451,7 +2451,7 @@ static int sctp_apply_peer_addr_params(struct sctp_paddrparams *params, | |||
2451 | (trans->param_flags & ~SPP_PMTUD) | pmtud_change; | 2451 | (trans->param_flags & ~SPP_PMTUD) | pmtud_change; |
2452 | if (update) { | 2452 | if (update) { |
2453 | sctp_transport_pmtu(trans, sctp_opt2sk(sp)); | 2453 | sctp_transport_pmtu(trans, sctp_opt2sk(sp)); |
2454 | sctp_assoc_sync_pmtu(sctp_opt2sk(sp), asoc); | 2454 | sctp_assoc_sync_pmtu(asoc); |
2455 | } | 2455 | } |
2456 | } else if (asoc) { | 2456 | } else if (asoc) { |
2457 | asoc->param_flags = | 2457 | asoc->param_flags = |
@@ -4461,8 +4461,8 @@ int sctp_get_sctp_info(struct sock *sk, struct sctp_association *asoc, | |||
4461 | info->sctpi_rwnd = asoc->a_rwnd; | 4461 | info->sctpi_rwnd = asoc->a_rwnd; |
4462 | info->sctpi_unackdata = asoc->unack_data; | 4462 | info->sctpi_unackdata = asoc->unack_data; |
4463 | info->sctpi_penddata = sctp_tsnmap_pending(&asoc->peer.tsn_map); | 4463 | info->sctpi_penddata = sctp_tsnmap_pending(&asoc->peer.tsn_map); |
4464 | info->sctpi_instrms = asoc->c.sinit_max_instreams; | 4464 | info->sctpi_instrms = asoc->stream->incnt; |
4465 | info->sctpi_outstrms = asoc->c.sinit_num_ostreams; | 4465 | info->sctpi_outstrms = asoc->stream->outcnt; |
4466 | list_for_each(pos, &asoc->base.inqueue.in_chunk_list) | 4466 | list_for_each(pos, &asoc->base.inqueue.in_chunk_list) |
4467 | info->sctpi_inqueue++; | 4467 | info->sctpi_inqueue++; |
4468 | list_for_each(pos, &asoc->outqueue.out_chunk_list) | 4468 | list_for_each(pos, &asoc->outqueue.out_chunk_list) |
@@ -4691,8 +4691,8 @@ static int sctp_getsockopt_sctp_status(struct sock *sk, int len, | |||
4691 | status.sstat_unackdata = asoc->unack_data; | 4691 | status.sstat_unackdata = asoc->unack_data; |
4692 | 4692 | ||
4693 | status.sstat_penddata = sctp_tsnmap_pending(&asoc->peer.tsn_map); | 4693 | status.sstat_penddata = sctp_tsnmap_pending(&asoc->peer.tsn_map); |
4694 | status.sstat_instrms = asoc->c.sinit_max_instreams; | 4694 | status.sstat_instrms = asoc->stream->incnt; |
4695 | status.sstat_outstrms = asoc->c.sinit_num_ostreams; | 4695 | status.sstat_outstrms = asoc->stream->outcnt; |
4696 | status.sstat_fragmentation_point = asoc->frag_point; | 4696 | status.sstat_fragmentation_point = asoc->frag_point; |
4697 | status.sstat_primary.spinfo_assoc_id = sctp_assoc2id(transport->asoc); | 4697 | status.sstat_primary.spinfo_assoc_id = sctp_assoc2id(transport->asoc); |
4698 | memcpy(&status.sstat_primary.spinfo_address, &transport->ipaddr, | 4698 | memcpy(&status.sstat_primary.spinfo_address, &transport->ipaddr, |
diff --git a/net/sctp/stream.c b/net/sctp/stream.c index 1c6cc04fa3a4..bbed997e1c5f 100644 --- a/net/sctp/stream.c +++ b/net/sctp/stream.c | |||
@@ -35,33 +35,60 @@ | |||
35 | #include <net/sctp/sctp.h> | 35 | #include <net/sctp/sctp.h> |
36 | #include <net/sctp/sm.h> | 36 | #include <net/sctp/sm.h> |
37 | 37 | ||
38 | struct sctp_stream *sctp_stream_new(__u16 incnt, __u16 outcnt, gfp_t gfp) | 38 | int sctp_stream_new(struct sctp_association *asoc, gfp_t gfp) |
39 | { | 39 | { |
40 | struct sctp_stream *stream; | 40 | struct sctp_stream *stream; |
41 | int i; | 41 | int i; |
42 | 42 | ||
43 | stream = kzalloc(sizeof(*stream), gfp); | 43 | stream = kzalloc(sizeof(*stream), gfp); |
44 | if (!stream) | 44 | if (!stream) |
45 | return NULL; | 45 | return -ENOMEM; |
46 | 46 | ||
47 | stream->outcnt = outcnt; | 47 | stream->outcnt = asoc->c.sinit_num_ostreams; |
48 | stream->out = kcalloc(stream->outcnt, sizeof(*stream->out), gfp); | 48 | stream->out = kcalloc(stream->outcnt, sizeof(*stream->out), gfp); |
49 | if (!stream->out) { | 49 | if (!stream->out) { |
50 | kfree(stream); | 50 | kfree(stream); |
51 | return NULL; | 51 | return -ENOMEM; |
52 | } | 52 | } |
53 | for (i = 0; i < stream->outcnt; i++) | 53 | for (i = 0; i < stream->outcnt; i++) |
54 | stream->out[i].state = SCTP_STREAM_OPEN; | 54 | stream->out[i].state = SCTP_STREAM_OPEN; |
55 | 55 | ||
56 | stream->incnt = incnt; | 56 | asoc->stream = stream; |
57 | |||
58 | return 0; | ||
59 | } | ||
60 | |||
61 | int sctp_stream_init(struct sctp_association *asoc, gfp_t gfp) | ||
62 | { | ||
63 | struct sctp_stream *stream = asoc->stream; | ||
64 | int i; | ||
65 | |||
66 | /* Initial stream->out size may be very big, so free it and alloc | ||
67 | * a new one with new outcnt to save memory. | ||
68 | */ | ||
69 | kfree(stream->out); | ||
70 | stream->outcnt = asoc->c.sinit_num_ostreams; | ||
71 | stream->out = kcalloc(stream->outcnt, sizeof(*stream->out), gfp); | ||
72 | if (!stream->out) | ||
73 | goto nomem; | ||
74 | |||
75 | for (i = 0; i < stream->outcnt; i++) | ||
76 | stream->out[i].state = SCTP_STREAM_OPEN; | ||
77 | |||
78 | stream->incnt = asoc->c.sinit_max_instreams; | ||
57 | stream->in = kcalloc(stream->incnt, sizeof(*stream->in), gfp); | 79 | stream->in = kcalloc(stream->incnt, sizeof(*stream->in), gfp); |
58 | if (!stream->in) { | 80 | if (!stream->in) { |
59 | kfree(stream->out); | 81 | kfree(stream->out); |
60 | kfree(stream); | 82 | goto nomem; |
61 | return NULL; | ||
62 | } | 83 | } |
63 | 84 | ||
64 | return stream; | 85 | return 0; |
86 | |||
87 | nomem: | ||
88 | asoc->stream = NULL; | ||
89 | kfree(stream); | ||
90 | |||
91 | return -ENOMEM; | ||
65 | } | 92 | } |
66 | 93 | ||
67 | void sctp_stream_free(struct sctp_stream *stream) | 94 | void sctp_stream_free(struct sctp_stream *stream) |
diff --git a/net/sctp/transport.c b/net/sctp/transport.c index 3379668af368..721eeebfcd8a 100644 --- a/net/sctp/transport.c +++ b/net/sctp/transport.c | |||
@@ -251,14 +251,13 @@ void sctp_transport_pmtu(struct sctp_transport *transport, struct sock *sk) | |||
251 | transport->pathmtu = SCTP_DEFAULT_MAXSEGMENT; | 251 | transport->pathmtu = SCTP_DEFAULT_MAXSEGMENT; |
252 | } | 252 | } |
253 | 253 | ||
254 | void sctp_transport_update_pmtu(struct sock *sk, struct sctp_transport *t, u32 pmtu) | 254 | void sctp_transport_update_pmtu(struct sctp_transport *t, u32 pmtu) |
255 | { | 255 | { |
256 | struct dst_entry *dst; | 256 | struct dst_entry *dst = sctp_transport_dst_check(t); |
257 | 257 | ||
258 | if (unlikely(pmtu < SCTP_DEFAULT_MINSEGMENT)) { | 258 | if (unlikely(pmtu < SCTP_DEFAULT_MINSEGMENT)) { |
259 | pr_warn("%s: Reported pmtu %d too low, using default minimum of %d\n", | 259 | pr_warn("%s: Reported pmtu %d too low, using default minimum of %d\n", |
260 | __func__, pmtu, | 260 | __func__, pmtu, SCTP_DEFAULT_MINSEGMENT); |
261 | SCTP_DEFAULT_MINSEGMENT); | ||
262 | /* Use default minimum segment size and disable | 261 | /* Use default minimum segment size and disable |
263 | * pmtu discovery on this transport. | 262 | * pmtu discovery on this transport. |
264 | */ | 263 | */ |
@@ -267,17 +266,13 @@ void sctp_transport_update_pmtu(struct sock *sk, struct sctp_transport *t, u32 p | |||
267 | t->pathmtu = pmtu; | 266 | t->pathmtu = pmtu; |
268 | } | 267 | } |
269 | 268 | ||
270 | dst = sctp_transport_dst_check(t); | ||
271 | if (!dst) | ||
272 | t->af_specific->get_dst(t, &t->saddr, &t->fl, sk); | ||
273 | |||
274 | if (dst) { | 269 | if (dst) { |
275 | dst->ops->update_pmtu(dst, sk, NULL, pmtu); | 270 | dst->ops->update_pmtu(dst, t->asoc->base.sk, NULL, pmtu); |
276 | |||
277 | dst = sctp_transport_dst_check(t); | 271 | dst = sctp_transport_dst_check(t); |
278 | if (!dst) | ||
279 | t->af_specific->get_dst(t, &t->saddr, &t->fl, sk); | ||
280 | } | 272 | } |
273 | |||
274 | if (!dst) | ||
275 | t->af_specific->get_dst(t, &t->saddr, &t->fl, t->asoc->base.sk); | ||
281 | } | 276 | } |
282 | 277 | ||
283 | /* Caches the dst entry and source address for a transport's destination | 278 | /* Caches the dst entry and source address for a transport's destination |
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index 8931e33b6541..2b720fa35c4f 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c | |||
@@ -1635,6 +1635,7 @@ static struct svc_xprt *svc_bc_create_socket(struct svc_serv *serv, | |||
1635 | 1635 | ||
1636 | xprt = &svsk->sk_xprt; | 1636 | xprt = &svsk->sk_xprt; |
1637 | svc_xprt_init(net, &svc_tcp_bc_class, xprt, serv); | 1637 | svc_xprt_init(net, &svc_tcp_bc_class, xprt, serv); |
1638 | set_bit(XPT_CONG_CTRL, &svsk->sk_xprt.xpt_flags); | ||
1638 | 1639 | ||
1639 | serv->sv_bc_xprt = xprt; | 1640 | serv->sv_bc_xprt = xprt; |
1640 | 1641 | ||
diff --git a/net/sunrpc/xprtrdma/svc_rdma_transport.c b/net/sunrpc/xprtrdma/svc_rdma_transport.c index c13a5c35ce14..fc8f14c7bfec 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_transport.c +++ b/net/sunrpc/xprtrdma/svc_rdma_transport.c | |||
@@ -127,6 +127,7 @@ static struct svc_xprt *svc_rdma_bc_create(struct svc_serv *serv, | |||
127 | xprt = &cma_xprt->sc_xprt; | 127 | xprt = &cma_xprt->sc_xprt; |
128 | 128 | ||
129 | svc_xprt_init(net, &svc_rdma_bc_class, xprt, serv); | 129 | svc_xprt_init(net, &svc_rdma_bc_class, xprt, serv); |
130 | set_bit(XPT_CONG_CTRL, &xprt->xpt_flags); | ||
130 | serv->sv_bc_xprt = xprt; | 131 | serv->sv_bc_xprt = xprt; |
131 | 132 | ||
132 | dprintk("svcrdma: %s(%p)\n", __func__, xprt); | 133 | dprintk("svcrdma: %s(%p)\n", __func__, xprt); |
diff --git a/net/wireless/sysfs.c b/net/wireless/sysfs.c index 16b6b5988be9..570a2b67ca10 100644 --- a/net/wireless/sysfs.c +++ b/net/wireless/sysfs.c | |||
@@ -132,12 +132,10 @@ static int wiphy_resume(struct device *dev) | |||
132 | /* Age scan results with time spent in suspend */ | 132 | /* Age scan results with time spent in suspend */ |
133 | cfg80211_bss_age(rdev, get_seconds() - rdev->suspend_at); | 133 | cfg80211_bss_age(rdev, get_seconds() - rdev->suspend_at); |
134 | 134 | ||
135 | if (rdev->ops->resume) { | 135 | rtnl_lock(); |
136 | rtnl_lock(); | 136 | if (rdev->wiphy.registered && rdev->ops->resume) |
137 | if (rdev->wiphy.registered) | 137 | ret = rdev_resume(rdev); |
138 | ret = rdev_resume(rdev); | 138 | rtnl_unlock(); |
139 | rtnl_unlock(); | ||
140 | } | ||
141 | 139 | ||
142 | return ret; | 140 | return ret; |
143 | } | 141 | } |
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 9705c279494b..40a8aa39220d 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c | |||
@@ -412,7 +412,14 @@ static inline int xfrm_replay_verify_len(struct xfrm_replay_state_esn *replay_es | |||
412 | up = nla_data(rp); | 412 | up = nla_data(rp); |
413 | ulen = xfrm_replay_state_esn_len(up); | 413 | ulen = xfrm_replay_state_esn_len(up); |
414 | 414 | ||
415 | if (nla_len(rp) < ulen || xfrm_replay_state_esn_len(replay_esn) != ulen) | 415 | /* Check the overall length and the internal bitmap length to avoid |
416 | * potential overflow. */ | ||
417 | if (nla_len(rp) < ulen || | ||
418 | xfrm_replay_state_esn_len(replay_esn) != ulen || | ||
419 | replay_esn->bmp_len != up->bmp_len) | ||
420 | return -EINVAL; | ||
421 | |||
422 | if (up->replay_window > up->bmp_len * sizeof(__u32) * 8) | ||
416 | return -EINVAL; | 423 | return -EINVAL; |
417 | 424 | ||
418 | return 0; | 425 | return 0; |