diff options
Diffstat (limited to 'net/sctp/protocol.c')
-rw-r--r-- | net/sctp/protocol.c | 43 |
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 */ | ||
191 | static 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 */ | ||
214 | static 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. */ |
191 | static void sctp_v4_from_skb(union sctp_addr *addr, struct sk_buff *skb, | 230 | static 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, |