History

net/tcp: Add TCP_AO_REPAIR

Add TCP_AO_REPAIR setsockopt(), getsockopt(). They let a user to repair TCP-AO ISNs/SNEs. Also let the user hack around when (tp->repair) is on and add ao_info on a socket in any supported state. As SNEs now can be read/written at any moment, use WRITE_ONCE()/READ_ONCE() to set/read them.

Dmitry Safonov committed 3 years ago

Commit faadfab1 parent 248411b4 files · +125 −11Browse files

Unified · Split

4 files
  1. include/net/tcp_ao.h +14 −0
  2. include/uapi/linux/tcp.h +8 −0
  3. net/ipv4/tcp.c +17 −7
  4. net/ipv4/tcp_ao.c +86 −4
include/net/tcp_ao.h+14−0
@@ -199,6 +199,8 @@ void tcp_ao_time_wait(struct tcp_timewait_sock *tcptw, struct tcp_sock *tp); · 198 unmodified lines
199bool tcp_ao_ignore_icmp(const struct sock *sk, int family, int type, int code);199bool tcp_ao_ignore_icmp(const struct sock *sk, int family, int type, int code);
200int tcp_ao_get_mkts(struct sock *sk, sockptr_t optval, sockptr_t optlen);200int tcp_ao_get_mkts(struct sock *sk, sockptr_t optval, sockptr_t optlen);
201int tcp_ao_get_sock_info(struct sock *sk, sockptr_t optval, sockptr_t optlen);201int tcp_ao_get_sock_info(struct sock *sk, sockptr_t optval, sockptr_t optlen);
202int tcp_ao_get_repair(struct sock *sk, sockptr_t optval, sockptr_t optlen);
203int tcp_ao_set_repair(struct sock *sk, sockptr_t optval, unsigned int optlen);
202enum skb_drop_reason tcp_inbound_ao_hash(struct sock *sk,204enum skb_drop_reason tcp_inbound_ao_hash(struct sock *sk,
203 const struct sk_buff *skb, unsigned short int family,205 const struct sk_buff *skb, unsigned short int family,
204 const struct request_sock *req, int l3index,206 const struct request_sock *req, int l3index,
@@ -330,6 +332,18 @@ static inline int tcp_ao_get_sock_info(struct sock *sk, sockptr_t optval, sockpt · 125 unmodified lines
330{332{
331 return -ENOPROTOOPT;333 return -ENOPROTOOPT;
332}334}
335
336static inline int tcp_ao_get_repair(struct sock *sk,
337 sockptr_t optval, sockptr_t optlen)
338{
339 return -ENOPROTOOPT;
340}
341
342static inline int tcp_ao_set_repair(struct sock *sk,
343 sockptr_t optval, unsigned int optlen)
344{
345 return -ENOPROTOOPT;
346}
333#endif347#endif
334 348
335#if defined(CONFIG_TCP_MD5SIG) || defined(CONFIG_TCP_AO)349#if defined(CONFIG_TCP_MD5SIG) || defined(CONFIG_TCP_AO)
include/uapi/linux/tcp.h+8−0
@@ -133,6 +133,7 @@ enum { · 132 unmodified lines
133#define TCP_AO_DEL_KEY 39 /* Delete MKT */133#define TCP_AO_DEL_KEY 39 /* Delete MKT */
134#define TCP_AO_INFO 40 /* Set/list TCP-AO per-socket options */134#define TCP_AO_INFO 40 /* Set/list TCP-AO per-socket options */
135#define TCP_AO_GET_KEYS 41 /* List MKT(s) */135#define TCP_AO_GET_KEYS 41 /* List MKT(s) */
136#define TCP_AO_REPAIR 42 /* Get/Set SNEs and ISNs */
136 137
137#define TCP_REPAIR_ON 1138#define TCP_REPAIR_ON 1
138#define TCP_REPAIR_OFF 0139#define TCP_REPAIR_OFF 0
@@ -458,6 +459,13 @@ struct tcp_ao_getsockopt { /* getsockopt(TCP_AO_GET_KEYS) */ · 319 unmodified lines
458 __u64 pkt_bad; /* out: segments that failed verification */459 __u64 pkt_bad; /* out: segments that failed verification */
459} __attribute__((aligned(8)));460} __attribute__((aligned(8)));
460 461
462struct tcp_ao_repair { /* {s,g}etsockopt(TCP_AO_REPAIR) */
463 __be32 snt_isn;
464 __be32 rcv_isn;
465 __u32 snd_sne;
466 __u32 rcv_sne;
467} __attribute__((aligned(8)));
468
461/* setsockopt(fd, IPPROTO_TCP, TCP_ZEROCOPY_RECEIVE, ...) */469/* setsockopt(fd, IPPROTO_TCP, TCP_ZEROCOPY_RECEIVE, ...) */
462 470
463#define TCP_RECEIVE_ZEROCOPY_FLAG_TLB_CLEAN_HINT 0x1471#define TCP_RECEIVE_ZEROCOPY_FLAG_TLB_CLEAN_HINT 0x1
net/ipv4/tcp.c+17−7
@@ -3593,20 +3593,28 @@ int do_tcp_setsockopt(struct sock *sk, int level, int optname, · 3592 unmodified lines
3593 __tcp_sock_set_quickack(sk, val);3593 __tcp_sock_set_quickack(sk, val);
3594 break;3594 break;
3595 3595
3596 case TCP_AO_REPAIR:
3597 err = tcp_ao_set_repair(sk, optval, optlen);
3598 break;
3596#ifdef CONFIG_TCP_AO3599#ifdef CONFIG_TCP_AO
3597 case TCP_AO_ADD_KEY:3600 case TCP_AO_ADD_KEY:
3598 case TCP_AO_DEL_KEY:3601 case TCP_AO_DEL_KEY:
3599 case TCP_AO_INFO: {3602 case TCP_AO_INFO: {
3600 /* If this is the first TCP-AO setsockopt() on the socket,3603 /* If this is the first TCP-AO setsockopt() on the socket,
3601 * sk_state has to be LISTEN or CLOSE3604 * sk_state has to be LISTEN or CLOSE. Allow TCP_REPAIR
3605 * in any state.
3602 */3606 */
3603 if (((1 << sk->sk_state) & (TCPF_LISTEN | TCPF_CLOSE)) ||3607 if ((1 << sk->sk_state) & (TCPF_LISTEN | TCPF_CLOSE))
3604 rcu_dereference_protected(tcp_sk(sk)->ao_info,3608 goto ao_parse;
3609 if (rcu_dereference_protected(tcp_sk(sk)->ao_info,
3605 lockdep_sock_is_held(sk)))3610 lockdep_sock_is_held(sk)))
3606 err = tp->af_specific->ao_parse(sk, optname, optval,3611 goto ao_parse;
3607 optlen);3612 if (tp->repair)
3608 else3613 goto ao_parse;
3609 err = -EISCONN;3614 err = -EISCONN;
3615 break;
3616ao_parse:
3617 err = tp->af_specific->ao_parse(sk, optname, optval, optlen);
3610 break;3618 break;
3611 }3619 }
3612#endif3620#endif
@@ -4284,6 +4292,8 @@ zerocopy_rcv_out: · 671 unmodified lines
4284 return err;4292 return err;
4285 }4293 }
4286#endif4294#endif
4295 case TCP_AO_REPAIR:
4296 return tcp_ao_get_repair(sk, optval, optlen);
4287 case TCP_AO_GET_KEYS:4297 case TCP_AO_GET_KEYS:
4288 case TCP_AO_INFO: {4298 case TCP_AO_INFO: {
4289 int err;4299 int err;
net/ipv4/tcp_ao.c+86−4
@@ -1490,6 +1490,16 @@ static struct tcp_ao_info *setsockopt_ao_info(struct sock *sk) · 1489 unmodified lines
1490 return ERR_PTR(-ESOCKTNOSUPPORT);1490 return ERR_PTR(-ESOCKTNOSUPPORT);
1491}1491}
1492 1492
1493static struct tcp_ao_info *getsockopt_ao_info(struct sock *sk)
1494{
1495 if (sk_fullsock(sk))
1496 return rcu_dereference(tcp_sk(sk)->ao_info);
1497 else if (sk->sk_state == TCP_TIME_WAIT)
1498 return rcu_dereference(tcp_twsk(sk)->ao_info);
1499
1500 return ERR_PTR(-ESOCKTNOSUPPORT);
1501}
1502
1493#define TCP_AO_KEYF_ALL (TCP_AO_KEYF_IFINDEX | TCP_AO_KEYF_EXCLUDE_OPT)1503#define TCP_AO_KEYF_ALL (TCP_AO_KEYF_IFINDEX | TCP_AO_KEYF_EXCLUDE_OPT)
1494#define TCP_AO_GET_KEYF_VALID (TCP_AO_KEYF_IFINDEX)1504#define TCP_AO_GET_KEYF_VALID (TCP_AO_KEYF_IFINDEX)
1495 1505
@@ -1671,11 +1681,13 @@ static int tcp_ao_add_cmd(struct sock *sk, unsigned short int family, · 175 unmodified lines
1671 if (ret < 0)1681 if (ret < 0)
1672 goto err_free_sock;1682 goto err_free_sock;
1673 1683
1674 /* Change this condition if we allow adding keys in states1684 if (!((1 << sk->sk_state) & (TCPF_LISTEN | TCPF_CLOSE))) {
1675 * like close_wait, syn_sent or fin_wait...
1676 */
1677 if (sk->sk_state == TCP_ESTABLISHED)
1678 tcp_ao_cache_traffic_keys(sk, ao_info, key);1685 tcp_ao_cache_traffic_keys(sk, ao_info, key);
1686 if (first) {
1687 ao_info->current_key = key;
1688 ao_info->rnext_key = key;
1689 }
1690 }
1679 1691
1680 tcp_ao_link_mkt(ao_info, key);1692 tcp_ao_link_mkt(ao_info, key);
1681 if (first) {1693 if (first) {
@@ -1926,6 +1938,8 @@ static int tcp_ao_info_cmd(struct sock *sk, unsigned short int family, · 244 unmodified lines
1926 if (IS_ERR(ao_info))1938 if (IS_ERR(ao_info))
1927 return PTR_ERR(ao_info);1939 return PTR_ERR(ao_info);
1928 if (!ao_info) {1940 if (!ao_info) {
1941 if (!((1 << sk->sk_state) & (TCPF_LISTEN | TCPF_CLOSE)))
1942 return -EINVAL;
1929 ao_info = tcp_ao_alloc_info(GFP_KERNEL);1943 ao_info = tcp_ao_alloc_info(GFP_KERNEL);
1930 if (!ao_info)1944 if (!ao_info)
1931 return -ENOMEM;1945 return -ENOMEM;
@@ -2308,3 +2322,71 @@ int tcp_ao_get_sock_info(struct sock *sk, sockptr_t optval, sockptr_t optlen) · 376 unmodified lines
2308 return 0;2322 return 0;
2309}2323}
2310 2324
2325int tcp_ao_set_repair(struct sock *sk, sockptr_t optval, unsigned int optlen)
2326{
2327 struct tcp_sock *tp = tcp_sk(sk);
2328 struct tcp_ao_repair cmd;
2329 struct tcp_ao_key *key;
2330 struct tcp_ao_info *ao;
2331 int err;
2332
2333 if (optlen < sizeof(cmd))
2334 return -EINVAL;
2335
2336 err = copy_struct_from_sockptr(&cmd, sizeof(cmd), optval, optlen);
2337 if (err)
2338 return err;
2339
2340 if (!tp->repair)
2341 return -EPERM;
2342
2343 ao = setsockopt_ao_info(sk);
2344 if (IS_ERR(ao))
2345 return PTR_ERR(ao);
2346 if (!ao)
2347 return -ENOENT;
2348
2349 WRITE_ONCE(ao->lisn, cmd.snt_isn);
2350 WRITE_ONCE(ao->risn, cmd.rcv_isn);
2351 WRITE_ONCE(ao->snd_sne, cmd.snd_sne);
2352 WRITE_ONCE(ao->rcv_sne, cmd.rcv_sne);
2353
2354 hlist_for_each_entry_rcu(key, &ao->head, node)
2355 tcp_ao_cache_traffic_keys(sk, ao, key);
2356
2357 return 0;
2358}
2359
2360int tcp_ao_get_repair(struct sock *sk, sockptr_t optval, sockptr_t optlen)
2361{
2362 struct tcp_sock *tp = tcp_sk(sk);
2363 struct tcp_ao_repair opt;
2364 struct tcp_ao_info *ao;
2365 int len;
2366
2367 if (copy_from_sockptr(&len, optlen, sizeof(int)))
2368 return -EFAULT;
2369
2370 if (len <= 0)
2371 return -EINVAL;
2372
2373 if (!tp->repair)
2374 return -EPERM;
2375
2376 rcu_read_lock();
2377 ao = getsockopt_ao_info(sk);
2378 if (IS_ERR_OR_NULL(ao)) {
2379 rcu_read_unlock();
2380 return ao ? PTR_ERR(ao) : -ENOENT;
2381 }
2382
2383 opt.snt_isn = ao->lisn;
2384 opt.rcv_isn = ao->risn;
2385 opt.snd_sne = READ_ONCE(ao->snd_sne);
2386 opt.rcv_sne = READ_ONCE(ao->rcv_sne);
2387 rcu_read_unlock();
2388
2389 if (copy_to_sockptr(optval, &opt, min_t(int, len, sizeof(opt))))
2390 return -EFAULT;
2391 return 0;
2392}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t