aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/tcp.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv4/tcp.c')
-rw-r--r--net/ipv4/tcp.c67
1 files changed, 67 insertions, 0 deletions
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 5c7ed147449c..032a96d78c99 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -2277,6 +2277,38 @@ static inline bool tcp_can_repair_sock(const struct sock *sk)
2277 ((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_ESTABLISHED)); 2277 ((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_ESTABLISHED));
2278} 2278}
2279 2279
2280static int tcp_repair_set_window(struct tcp_sock *tp, char __user *optbuf, int len)
2281{
2282 struct tcp_repair_window opt;
2283
2284 if (!tp->repair)
2285 return -EPERM;
2286
2287 if (len != sizeof(opt))
2288 return -EINVAL;
2289
2290 if (copy_from_user(&opt, optbuf, sizeof(opt)))
2291 return -EFAULT;
2292
2293 if (opt.max_window < opt.snd_wnd)
2294 return -EINVAL;
2295
2296 if (after(opt.snd_wl1, tp->rcv_nxt + opt.rcv_wnd))
2297 return -EINVAL;
2298
2299 if (after(opt.rcv_wup, tp->rcv_nxt))
2300 return -EINVAL;
2301
2302 tp->snd_wl1 = opt.snd_wl1;
2303 tp->snd_wnd = opt.snd_wnd;
2304 tp->max_window = opt.max_window;
2305
2306 tp->rcv_wnd = opt.rcv_wnd;
2307 tp->rcv_wup = opt.rcv_wup;
2308
2309 return 0;
2310}
2311
2280static int tcp_repair_options_est(struct tcp_sock *tp, 2312static int tcp_repair_options_est(struct tcp_sock *tp,
2281 struct tcp_repair_opt __user *optbuf, unsigned int len) 2313 struct tcp_repair_opt __user *optbuf, unsigned int len)
2282{ 2314{
@@ -2604,6 +2636,9 @@ static int do_tcp_setsockopt(struct sock *sk, int level,
2604 else 2636 else
2605 tp->tsoffset = val - tcp_time_stamp; 2637 tp->tsoffset = val - tcp_time_stamp;
2606 break; 2638 break;
2639 case TCP_REPAIR_WINDOW:
2640 err = tcp_repair_set_window(tp, optval, optlen);
2641 break;
2607 case TCP_NOTSENT_LOWAT: 2642 case TCP_NOTSENT_LOWAT:
2608 tp->notsent_lowat = val; 2643 tp->notsent_lowat = val;
2609 sk->sk_write_space(sk); 2644 sk->sk_write_space(sk);
@@ -2860,6 +2895,28 @@ static int do_tcp_getsockopt(struct sock *sk, int level,
2860 return -EINVAL; 2895 return -EINVAL;
2861 break; 2896 break;
2862 2897
2898 case TCP_REPAIR_WINDOW: {
2899 struct tcp_repair_window opt;
2900
2901 if (get_user(len, optlen))
2902 return -EFAULT;
2903
2904 if (len != sizeof(opt))
2905 return -EINVAL;
2906
2907 if (!tp->repair)
2908 return -EPERM;
2909
2910 opt.snd_wl1 = tp->snd_wl1;
2911 opt.snd_wnd = tp->snd_wnd;
2912 opt.max_window = tp->max_window;
2913 opt.rcv_wnd = tp->rcv_wnd;
2914 opt.rcv_wup = tp->rcv_wup;
2915
2916 if (copy_to_user(optval, &opt, len))
2917 return -EFAULT;
2918 return 0;
2919 }
2863 case TCP_QUEUE_SEQ: 2920 case TCP_QUEUE_SEQ:
2864 if (tp->repair_queue == TCP_SEND_QUEUE) 2921 if (tp->repair_queue == TCP_SEND_QUEUE)
2865 val = tp->write_seq; 2922 val = tp->write_seq;
@@ -2969,8 +3026,18 @@ static void __tcp_alloc_md5sig_pool(void)
2969 return; 3026 return;
2970 3027
2971 for_each_possible_cpu(cpu) { 3028 for_each_possible_cpu(cpu) {
3029 void *scratch = per_cpu(tcp_md5sig_pool, cpu).scratch;
2972 struct ahash_request *req; 3030 struct ahash_request *req;
2973 3031
3032 if (!scratch) {
3033 scratch = kmalloc_node(sizeof(union tcp_md5sum_block) +
3034 sizeof(struct tcphdr),
3035 GFP_KERNEL,
3036 cpu_to_node(cpu));
3037 if (!scratch)
3038 return;
3039 per_cpu(tcp_md5sig_pool, cpu).scratch = scratch;
3040 }
2974 if (per_cpu(tcp_md5sig_pool, cpu).md5_req) 3041 if (per_cpu(tcp_md5sig_pool, cpu).md5_req)
2975 continue; 3042 continue;
2976 3043