aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/ipv4/tcp.c71
1 files changed, 71 insertions, 0 deletions
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index b4e690ddb08c..3ce3bd031f33 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -2218,6 +2218,68 @@ static inline int tcp_can_repair_sock(struct sock *sk)
2218 ((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_ESTABLISHED)); 2218 ((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_ESTABLISHED));
2219} 2219}
2220 2220
2221static int tcp_repair_options_est(struct tcp_sock *tp, char __user *optbuf, unsigned int len)
2222{
2223 /*
2224 * Options are stored in CODE:VALUE form where CODE is 8bit and VALUE
2225 * fits the respective TCPOLEN_ size
2226 */
2227
2228 while (len > 0) {
2229 u8 opcode;
2230
2231 if (get_user(opcode, optbuf))
2232 return -EFAULT;
2233
2234 optbuf++;
2235 len--;
2236
2237 switch (opcode) {
2238 case TCPOPT_MSS: {
2239 u16 in_mss;
2240
2241 if (len < sizeof(in_mss))
2242 return -ENODATA;
2243 if (get_user(in_mss, optbuf))
2244 return -EFAULT;
2245
2246 tp->rx_opt.mss_clamp = in_mss;
2247
2248 optbuf += sizeof(in_mss);
2249 len -= sizeof(in_mss);
2250 break;
2251 }
2252 case TCPOPT_WINDOW: {
2253 u8 wscale;
2254
2255 if (len < sizeof(wscale))
2256 return -ENODATA;
2257 if (get_user(wscale, optbuf))
2258 return -EFAULT;
2259
2260 if (wscale > 14)
2261 return -EFBIG;
2262
2263 tp->rx_opt.snd_wscale = wscale;
2264
2265 optbuf += sizeof(wscale);
2266 len -= sizeof(wscale);
2267 break;
2268 }
2269 case TCPOPT_SACK_PERM:
2270 tp->rx_opt.sack_ok |= TCP_SACK_SEEN;
2271 if (sysctl_tcp_fack)
2272 tcp_enable_fack(tp);
2273 break;
2274 case TCPOPT_TIMESTAMP:
2275 tp->rx_opt.tstamp_ok = 1;
2276 break;
2277 }
2278 }
2279
2280 return 0;
2281}
2282
2221/* 2283/*
2222 * Socket option code for TCP. 2284 * Socket option code for TCP.
2223 */ 2285 */
@@ -2426,6 +2488,15 @@ static int do_tcp_setsockopt(struct sock *sk, int level,
2426 err = -EINVAL; 2488 err = -EINVAL;
2427 break; 2489 break;
2428 2490
2491 case TCP_REPAIR_OPTIONS:
2492 if (!tp->repair)
2493 err = -EINVAL;
2494 else if (sk->sk_state == TCP_ESTABLISHED)
2495 err = tcp_repair_options_est(tp, optval, optlen);
2496 else
2497 err = -EPERM;
2498 break;
2499
2429 case TCP_CORK: 2500 case TCP_CORK:
2430 /* When set indicates to always queue non-full frames. 2501 /* When set indicates to always queue non-full frames.
2431 * Later the user clears this option and we transmit 2502 * Later the user clears this option and we transmit