summaryrefslogtreecommitdiffstats
path: root/net/sctp/protocol.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/sctp/protocol.c')
-rw-r--r--net/sctp/protocol.c43
1 files changed, 43 insertions, 0 deletions
diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c
index a24cde236330..d685f8456762 100644
--- a/net/sctp/protocol.c
+++ b/net/sctp/protocol.c
@@ -187,6 +187,45 @@ int sctp_copy_local_addr_list(struct net *net, struct sctp_bind_addr *bp,
187 return error; 187 return error;
188} 188}
189 189
190/* Copy over any ip options */
191static void sctp_v4_copy_ip_options(struct sock *sk, struct sock *newsk)
192{
193 struct inet_sock *newinet, *inet = inet_sk(sk);
194 struct ip_options_rcu *inet_opt, *newopt = NULL;
195
196 newinet = inet_sk(newsk);
197
198 rcu_read_lock();
199 inet_opt = rcu_dereference(inet->inet_opt);
200 if (inet_opt) {
201 newopt = sock_kmalloc(newsk, sizeof(*inet_opt) +
202 inet_opt->opt.optlen, GFP_ATOMIC);
203 if (newopt)
204 memcpy(newopt, inet_opt, sizeof(*inet_opt) +
205 inet_opt->opt.optlen);
206 else
207 pr_err("%s: Failed to copy ip options\n", __func__);
208 }
209 RCU_INIT_POINTER(newinet->inet_opt, newopt);
210 rcu_read_unlock();
211}
212
213/* Account for the IP options */
214static int sctp_v4_ip_options_len(struct sock *sk)
215{
216 struct inet_sock *inet = inet_sk(sk);
217 struct ip_options_rcu *inet_opt;
218 int len = 0;
219
220 rcu_read_lock();
221 inet_opt = rcu_dereference(inet->inet_opt);
222 if (inet_opt)
223 len = inet_opt->opt.optlen;
224
225 rcu_read_unlock();
226 return len;
227}
228
190/* Initialize a sctp_addr from in incoming skb. */ 229/* Initialize a sctp_addr from in incoming skb. */
191static void sctp_v4_from_skb(union sctp_addr *addr, struct sk_buff *skb, 230static void sctp_v4_from_skb(union sctp_addr *addr, struct sk_buff *skb,
192 int is_saddr) 231 int is_saddr)
@@ -538,6 +577,8 @@ static struct sock *sctp_v4_create_accept_sk(struct sock *sk,
538 sctp_copy_sock(newsk, sk, asoc); 577 sctp_copy_sock(newsk, sk, asoc);
539 sock_reset_flag(newsk, SOCK_ZAPPED); 578 sock_reset_flag(newsk, SOCK_ZAPPED);
540 579
580 sctp_v4_copy_ip_options(sk, newsk);
581
541 newinet = inet_sk(newsk); 582 newinet = inet_sk(newsk);
542 583
543 newinet->inet_daddr = asoc->peer.primary_addr.v4.sin_addr.s_addr; 584 newinet->inet_daddr = asoc->peer.primary_addr.v4.sin_addr.s_addr;
@@ -956,6 +997,7 @@ static struct sctp_pf sctp_pf_inet = {
956 .addr_to_user = sctp_v4_addr_to_user, 997 .addr_to_user = sctp_v4_addr_to_user,
957 .to_sk_saddr = sctp_v4_to_sk_saddr, 998 .to_sk_saddr = sctp_v4_to_sk_saddr,
958 .to_sk_daddr = sctp_v4_to_sk_daddr, 999 .to_sk_daddr = sctp_v4_to_sk_daddr,
1000 .copy_ip_options = sctp_v4_copy_ip_options,
959 .af = &sctp_af_inet 1001 .af = &sctp_af_inet
960}; 1002};
961 1003
@@ -1040,6 +1082,7 @@ static struct sctp_af sctp_af_inet = {
1040 .ecn_capable = sctp_v4_ecn_capable, 1082 .ecn_capable = sctp_v4_ecn_capable,
1041 .net_header_len = sizeof(struct iphdr), 1083 .net_header_len = sizeof(struct iphdr),
1042 .sockaddr_len = sizeof(struct sockaddr_in), 1084 .sockaddr_len = sizeof(struct sockaddr_in),
1085 .ip_options_len = sctp_v4_ip_options_len,
1043#ifdef CONFIG_COMPAT 1086#ifdef CONFIG_COMPAT
1044 .compat_setsockopt = compat_ip_setsockopt, 1087 .compat_setsockopt = compat_ip_setsockopt,
1045 .compat_getsockopt = compat_ip_getsockopt, 1088 .compat_getsockopt = compat_ip_getsockopt,