((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_ESTABLISHED));
 }
 
-static int tcp_repair_options_est(struct tcp_sock *tp, char __user *optbuf, unsigned int len)
+static int tcp_repair_options_est(struct tcp_sock *tp,
+               struct tcp_repair_opt __user *optbuf, unsigned int len)
 {
-       /*
-        * Options are stored in CODE:VALUE form where CODE is 8bit and VALUE
-        * fits the respective TCPOLEN_ size
-        */
+       struct tcp_repair_opt opt;
 
-       while (len > 0) {
-               u8 opcode;
-
-               if (get_user(opcode, optbuf))
+       while (len >= sizeof(opt)) {
+               if (copy_from_user(&opt, optbuf, sizeof(opt)))
                        return -EFAULT;
 
                optbuf++;
-               len--;
-
-               switch (opcode) {
-               case TCPOPT_MSS: {
-                       u16 in_mss;
+               len -= sizeof(opt);
 
-                       if (len < sizeof(in_mss))
-                               return -ENODATA;
-                       if (get_user(in_mss, optbuf))
-                               return -EFAULT;
-
-                       tp->rx_opt.mss_clamp = in_mss;
-
-                       optbuf += sizeof(in_mss);
-                       len -= sizeof(in_mss);
+               switch (opt.opt_code) {
+               case TCPOPT_MSS:
+                       tp->rx_opt.mss_clamp = opt.opt_val;
                        break;
-               }
-               case TCPOPT_WINDOW: {
-                       u8 wscale;
-
-                       if (len < sizeof(wscale))
-                               return -ENODATA;
-                       if (get_user(wscale, optbuf))
-                               return -EFAULT;
-
-                       if (wscale > 14)
+               case TCPOPT_WINDOW:
+                       if (opt.opt_val > 14)
                                return -EFBIG;
 
-                       tp->rx_opt.snd_wscale = wscale;
-
-                       optbuf += sizeof(wscale);
-                       len -= sizeof(wscale);
+                       tp->rx_opt.snd_wscale = opt.opt_val;
                        break;
-               }
                case TCPOPT_SACK_PERM:
+                       if (opt.opt_val != 0)
+                               return -EINVAL;
+
                        tp->rx_opt.sack_ok |= TCP_SACK_SEEN;
                        if (sysctl_tcp_fack)
                                tcp_enable_fack(tp);
                        break;
                case TCPOPT_TIMESTAMP:
+                       if (opt.opt_val != 0)
+                               return -EINVAL;
+
                        tp->rx_opt.tstamp_ok = 1;
                        break;
                }
                if (!tp->repair)
                        err = -EINVAL;
                else if (sk->sk_state == TCP_ESTABLISHED)
-                       err = tcp_repair_options_est(tp, optval, optlen);
+                       err = tcp_repair_options_est(tp,
+                                       (struct tcp_repair_opt __user *)optval,
+                                       optlen);
                else
                        err = -EPERM;
                break;