net/tcp: Add TCP_AO_REPAIR
[linux-2.6-microblaze.git] / net / ipv4 / tcp.c
index ce33eee..53bcc17 100644 (file)
@@ -3593,20 +3593,28 @@ int do_tcp_setsockopt(struct sock *sk, int level, int optname,
                __tcp_sock_set_quickack(sk, val);
                break;
 
+       case TCP_AO_REPAIR:
+               err = tcp_ao_set_repair(sk, optval, optlen);
+               break;
 #ifdef CONFIG_TCP_AO
        case TCP_AO_ADD_KEY:
        case TCP_AO_DEL_KEY:
        case TCP_AO_INFO: {
                /* If this is the first TCP-AO setsockopt() on the socket,
-                * sk_state has to be LISTEN or CLOSE
+                * sk_state has to be LISTEN or CLOSE. Allow TCP_REPAIR
+                * in any state.
                 */
-               if (((1 << sk->sk_state) & (TCPF_LISTEN | TCPF_CLOSE)) ||
-                   rcu_dereference_protected(tcp_sk(sk)->ao_info,
+               if ((1 << sk->sk_state) & (TCPF_LISTEN | TCPF_CLOSE))
+                       goto ao_parse;
+               if (rcu_dereference_protected(tcp_sk(sk)->ao_info,
                                              lockdep_sock_is_held(sk)))
-                       err = tp->af_specific->ao_parse(sk, optname, optval,
-                                                       optlen);
-               else
-                       err = -EISCONN;
+                       goto ao_parse;
+               if (tp->repair)
+                       goto ao_parse;
+               err = -EISCONN;
+               break;
+ao_parse:
+               err = tp->af_specific->ao_parse(sk, optname, optval, optlen);
                break;
        }
 #endif
@@ -4284,6 +4292,8 @@ zerocopy_rcv_out:
                return err;
        }
 #endif
+       case TCP_AO_REPAIR:
+               return tcp_ao_get_repair(sk, optval, optlen);
        case TCP_AO_GET_KEYS:
        case TCP_AO_INFO: {
                int err;