Skip to content

Commit 3df523a

Browse files
Peter Krystaddavem330
authored andcommitted
mptcp: Add ADD_ADDR handling
Add handling for sending and receiving the ADD_ADDR, ADD_ADDR6, and RM_ADDR suboptions. Co-developed-by: Matthieu Baerts <[email protected]> Signed-off-by: Matthieu Baerts <[email protected]> Co-developed-by: Paolo Abeni <[email protected]> Signed-off-by: Paolo Abeni <[email protected]> Signed-off-by: Peter Krystad <[email protected]> Signed-off-by: Mat Martineau <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 41b1450 commit 3df523a

File tree

5 files changed

+262
-18
lines changed

5 files changed

+262
-18
lines changed

include/linux/tcp.h

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,16 +86,30 @@ struct mptcp_options_received {
8686
u64 data_seq;
8787
u32 subflow_seq;
8888
u16 data_len;
89-
u8 mp_capable : 1,
89+
u16 mp_capable : 1,
9090
mp_join : 1,
91-
dss : 1;
91+
dss : 1,
92+
add_addr : 1,
93+
rm_addr : 1,
94+
family : 4,
95+
echo : 1;
9296
u8 use_map:1,
9397
dsn64:1,
9498
data_fin:1,
9599
use_ack:1,
96100
ack64:1,
97101
mpc_map:1,
98102
__unused:2;
103+
u8 addr_id;
104+
u8 rm_id;
105+
union {
106+
struct in_addr addr;
107+
#if IS_ENABLED(CONFIG_MPTCP_IPV6)
108+
struct in6_addr addr6;
109+
#endif
110+
};
111+
u64 ahmac;
112+
u16 port;
99113
};
100114
#endif
101115

@@ -131,6 +145,8 @@ static inline void tcp_clear_options(struct tcp_options_received *rx_opt)
131145
#if IS_ENABLED(CONFIG_MPTCP)
132146
rx_opt->mptcp.mp_capable = 0;
133147
rx_opt->mptcp.mp_join = 0;
148+
rx_opt->mptcp.add_addr = 0;
149+
rx_opt->mptcp.rm_addr = 0;
134150
rx_opt->mptcp.dss = 0;
135151
#endif
136152
}

include/net/mptcp.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,15 @@ struct mptcp_out_options {
3333
u16 suboptions;
3434
u64 sndr_key;
3535
u64 rcvr_key;
36+
union {
37+
struct in_addr addr;
38+
#if IS_ENABLED(CONFIG_MPTCP_IPV6)
39+
struct in6_addr addr6;
40+
#endif
41+
};
42+
u8 addr_id;
43+
u64 ahmac;
44+
u8 rm_id;
3645
struct mptcp_ext ext_copy;
3746
#endif
3847
};

net/mptcp/crypto.c

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,7 @@ void mptcp_crypto_key_sha(u64 key, u32 *token, u64 *idsn)
4444
*idsn = be64_to_cpu(*((__be64 *)&mptcp_hashed_key[6]));
4545
}
4646

47-
void mptcp_crypto_hmac_sha(u64 key1, u64 key2, u32 nonce1, u32 nonce2,
48-
void *hmac)
47+
void mptcp_crypto_hmac_sha(u64 key1, u64 key2, u8 *msg, int len, void *hmac)
4948
{
5049
u8 input[SHA256_BLOCK_SIZE + SHA256_DIGEST_SIZE];
5150
__be32 mptcp_hashed_key[SHA256_DIGEST_WORDS];
@@ -55,6 +54,9 @@ void mptcp_crypto_hmac_sha(u64 key1, u64 key2, u32 nonce1, u32 nonce2,
5554
u8 key2be[8];
5655
int i;
5756

57+
if (WARN_ON_ONCE(len > SHA256_DIGEST_SIZE))
58+
len = SHA256_DIGEST_SIZE;
59+
5860
put_unaligned_be64(key1, key1be);
5961
put_unaligned_be64(key2, key2be);
6062

@@ -65,11 +67,10 @@ void mptcp_crypto_hmac_sha(u64 key1, u64 key2, u32 nonce1, u32 nonce2,
6567
for (i = 0; i < 8; i++)
6668
input[i + 8] ^= key2be[i];
6769

68-
put_unaligned_be32(nonce1, &input[SHA256_BLOCK_SIZE]);
69-
put_unaligned_be32(nonce2, &input[SHA256_BLOCK_SIZE + 4]);
70+
memcpy(&input[SHA256_BLOCK_SIZE], msg, len);
7071

7172
sha256_init(&state);
72-
sha256_update(&state, input, SHA256_BLOCK_SIZE + 8);
73+
sha256_update(&state, input, SHA256_BLOCK_SIZE + len);
7374

7475
/* emit sha256(K1 || msg) on the second input block, so we can
7576
* reuse 'input' for the last hashing
@@ -125,6 +126,7 @@ static int __init test_mptcp_crypto(void)
125126
char hmac[20], hmac_hex[41];
126127
u32 nonce1, nonce2;
127128
u64 key1, key2;
129+
u8 msg[8];
128130
int i, j;
129131

130132
for (i = 0; i < ARRAY_SIZE(tests); ++i) {
@@ -134,7 +136,10 @@ static int __init test_mptcp_crypto(void)
134136
nonce1 = be32_to_cpu(*((__be32 *)&tests[i].msg[0]));
135137
nonce2 = be32_to_cpu(*((__be32 *)&tests[i].msg[4]));
136138

137-
mptcp_crypto_hmac_sha(key1, key2, nonce1, nonce2, hmac);
139+
put_unaligned_be32(nonce1, &msg[0]);
140+
put_unaligned_be32(nonce2, &msg[4]);
141+
142+
mptcp_crypto_hmac_sha(key1, key2, msg, 8, hmac);
138143
for (j = 0; j < 20; ++j)
139144
sprintf(&hmac_hex[j << 1], "%02x", hmac[j] & 0xff);
140145
hmac_hex[40] = 0;

net/mptcp/options.c

Lines changed: 198 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,71 @@ void mptcp_parse_option(const struct sk_buff *skb, const unsigned char *ptr,
178178

179179
break;
180180

181+
case MPTCPOPT_ADD_ADDR:
182+
mp_opt->echo = (*ptr++) & MPTCP_ADDR_ECHO;
183+
if (!mp_opt->echo) {
184+
if (opsize == TCPOLEN_MPTCP_ADD_ADDR ||
185+
opsize == TCPOLEN_MPTCP_ADD_ADDR_PORT)
186+
mp_opt->family = MPTCP_ADDR_IPVERSION_4;
187+
#if IS_ENABLED(CONFIG_MPTCP_IPV6)
188+
else if (opsize == TCPOLEN_MPTCP_ADD_ADDR6 ||
189+
opsize == TCPOLEN_MPTCP_ADD_ADDR6_PORT)
190+
mp_opt->family = MPTCP_ADDR_IPVERSION_6;
191+
#endif
192+
else
193+
break;
194+
} else {
195+
if (opsize == TCPOLEN_MPTCP_ADD_ADDR_BASE ||
196+
opsize == TCPOLEN_MPTCP_ADD_ADDR_BASE_PORT)
197+
mp_opt->family = MPTCP_ADDR_IPVERSION_4;
198+
#if IS_ENABLED(CONFIG_MPTCP_IPV6)
199+
else if (opsize == TCPOLEN_MPTCP_ADD_ADDR6_BASE ||
200+
opsize == TCPOLEN_MPTCP_ADD_ADDR6_BASE_PORT)
201+
mp_opt->family = MPTCP_ADDR_IPVERSION_6;
202+
#endif
203+
else
204+
break;
205+
}
206+
207+
mp_opt->add_addr = 1;
208+
mp_opt->port = 0;
209+
mp_opt->addr_id = *ptr++;
210+
pr_debug("ADD_ADDR: id=%d", mp_opt->addr_id);
211+
if (mp_opt->family == MPTCP_ADDR_IPVERSION_4) {
212+
memcpy((u8 *)&mp_opt->addr.s_addr, (u8 *)ptr, 4);
213+
ptr += 4;
214+
if (opsize == TCPOLEN_MPTCP_ADD_ADDR_PORT ||
215+
opsize == TCPOLEN_MPTCP_ADD_ADDR_BASE_PORT) {
216+
mp_opt->port = get_unaligned_be16(ptr);
217+
ptr += 2;
218+
}
219+
}
220+
#if IS_ENABLED(CONFIG_MPTCP_IPV6)
221+
else {
222+
memcpy(mp_opt->addr6.s6_addr, (u8 *)ptr, 16);
223+
ptr += 16;
224+
if (opsize == TCPOLEN_MPTCP_ADD_ADDR6_PORT ||
225+
opsize == TCPOLEN_MPTCP_ADD_ADDR6_BASE_PORT) {
226+
mp_opt->port = get_unaligned_be16(ptr);
227+
ptr += 2;
228+
}
229+
}
230+
#endif
231+
if (!mp_opt->echo) {
232+
mp_opt->ahmac = get_unaligned_be64(ptr);
233+
ptr += 8;
234+
}
235+
break;
236+
237+
case MPTCPOPT_RM_ADDR:
238+
if (opsize != TCPOLEN_MPTCP_RM_ADDR_BASE)
239+
break;
240+
241+
mp_opt->rm_addr = 1;
242+
mp_opt->rm_id = *ptr++;
243+
pr_debug("RM_ADDR: id=%d", mp_opt->rm_id);
244+
break;
245+
181246
default:
182247
break;
183248
}
@@ -386,13 +451,93 @@ static bool mptcp_established_options_dss(struct sock *sk, struct sk_buff *skb,
386451
return true;
387452
}
388453

454+
static u64 add_addr_generate_hmac(u64 key1, u64 key2, u8 addr_id,
455+
struct in_addr *addr)
456+
{
457+
u8 hmac[MPTCP_ADDR_HMAC_LEN];
458+
u8 msg[7];
459+
460+
msg[0] = addr_id;
461+
memcpy(&msg[1], &addr->s_addr, 4);
462+
msg[5] = 0;
463+
msg[6] = 0;
464+
465+
mptcp_crypto_hmac_sha(key1, key2, msg, 7, hmac);
466+
467+
return get_unaligned_be64(hmac);
468+
}
469+
470+
#if IS_ENABLED(CONFIG_MPTCP_IPV6)
471+
static u64 add_addr6_generate_hmac(u64 key1, u64 key2, u8 addr_id,
472+
struct in6_addr *addr)
473+
{
474+
u8 hmac[MPTCP_ADDR_HMAC_LEN];
475+
u8 msg[19];
476+
477+
msg[0] = addr_id;
478+
memcpy(&msg[1], &addr->s6_addr, 16);
479+
msg[17] = 0;
480+
msg[18] = 0;
481+
482+
mptcp_crypto_hmac_sha(key1, key2, msg, 19, hmac);
483+
484+
return get_unaligned_be64(hmac);
485+
}
486+
#endif
487+
488+
static bool mptcp_established_options_addr(struct sock *sk,
489+
unsigned int *size,
490+
unsigned int remaining,
491+
struct mptcp_out_options *opts)
492+
{
493+
struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk);
494+
struct mptcp_sock *msk = mptcp_sk(subflow->conn);
495+
struct sockaddr_storage saddr;
496+
u8 id;
497+
498+
id = 0;
499+
memset(&saddr, 0, sizeof(saddr));
500+
501+
if (saddr.ss_family == AF_INET) {
502+
if (remaining < TCPOLEN_MPTCP_ADD_ADDR)
503+
return false;
504+
opts->suboptions |= OPTION_MPTCP_ADD_ADDR;
505+
opts->addr_id = id;
506+
opts->addr = ((struct sockaddr_in *)&saddr)->sin_addr;
507+
opts->ahmac = add_addr_generate_hmac(msk->local_key,
508+
msk->remote_key,
509+
opts->addr_id,
510+
&opts->addr);
511+
*size = TCPOLEN_MPTCP_ADD_ADDR;
512+
}
513+
#if IS_ENABLED(CONFIG_MPTCP_IPV6)
514+
else if (saddr.ss_family == AF_INET6) {
515+
if (remaining < TCPOLEN_MPTCP_ADD_ADDR6)
516+
return false;
517+
opts->suboptions |= OPTION_MPTCP_ADD_ADDR6;
518+
opts->addr_id = id;
519+
opts->ahmac = add_addr6_generate_hmac(msk->local_key,
520+
msk->remote_key,
521+
opts->addr_id,
522+
&opts->addr6);
523+
opts->addr6 = ((struct sockaddr_in6 *)&saddr)->sin6_addr;
524+
*size = TCPOLEN_MPTCP_ADD_ADDR6;
525+
}
526+
#endif
527+
pr_debug("addr_id=%d, ahmac=%llu", opts->addr_id, opts->ahmac);
528+
529+
return true;
530+
}
531+
389532
bool mptcp_established_options(struct sock *sk, struct sk_buff *skb,
390533
unsigned int *size, unsigned int remaining,
391534
struct mptcp_out_options *opts)
392535
{
393536
unsigned int opt_size = 0;
394537
bool ret = false;
395538

539+
opts->suboptions = 0;
540+
396541
if (mptcp_established_options_mp(sk, skb, &opt_size, remaining, opts))
397542
ret = true;
398543
else if (mptcp_established_options_dss(sk, skb, &opt_size, remaining,
@@ -407,6 +552,11 @@ bool mptcp_established_options(struct sock *sk, struct sk_buff *skb,
407552

408553
*size += opt_size;
409554
remaining -= opt_size;
555+
if (mptcp_established_options_addr(sk, &opt_size, remaining, opts)) {
556+
*size += opt_size;
557+
remaining -= opt_size;
558+
ret = true;
559+
}
410560

411561
return ret;
412562
}
@@ -521,10 +671,9 @@ void mptcp_write_options(__be32 *ptr, struct mptcp_out_options *opts)
521671
else
522672
len = TCPOLEN_MPTCP_MPC_ACK;
523673

524-
*ptr++ = htonl((TCPOPT_MPTCP << 24) | (len << 16) |
525-
(MPTCPOPT_MP_CAPABLE << 12) |
526-
(MPTCP_SUPPORTED_VERSION << 8) |
527-
MPTCP_CAP_HMAC_SHA256);
674+
*ptr++ = mptcp_option(MPTCPOPT_MP_CAPABLE, len,
675+
MPTCP_SUPPORTED_VERSION,
676+
MPTCP_CAP_HMAC_SHA256);
528677

529678
if (!((OPTION_MPTCP_MPC_SYNACK | OPTION_MPTCP_MPC_ACK) &
530679
opts->suboptions))
@@ -546,6 +695,50 @@ void mptcp_write_options(__be32 *ptr, struct mptcp_out_options *opts)
546695
}
547696

548697
mp_capable_done:
698+
if (OPTION_MPTCP_ADD_ADDR & opts->suboptions) {
699+
if (opts->ahmac)
700+
*ptr++ = mptcp_option(MPTCPOPT_ADD_ADDR,
701+
TCPOLEN_MPTCP_ADD_ADDR, 0,
702+
opts->addr_id);
703+
else
704+
*ptr++ = mptcp_option(MPTCPOPT_ADD_ADDR,
705+
TCPOLEN_MPTCP_ADD_ADDR_BASE,
706+
MPTCP_ADDR_ECHO,
707+
opts->addr_id);
708+
memcpy((u8 *)ptr, (u8 *)&opts->addr.s_addr, 4);
709+
ptr += 1;
710+
if (opts->ahmac) {
711+
put_unaligned_be64(opts->ahmac, ptr);
712+
ptr += 2;
713+
}
714+
}
715+
716+
#if IS_ENABLED(CONFIG_MPTCP_IPV6)
717+
if (OPTION_MPTCP_ADD_ADDR6 & opts->suboptions) {
718+
if (opts->ahmac)
719+
*ptr++ = mptcp_option(MPTCPOPT_ADD_ADDR,
720+
TCPOLEN_MPTCP_ADD_ADDR6, 0,
721+
opts->addr_id);
722+
else
723+
*ptr++ = mptcp_option(MPTCPOPT_ADD_ADDR,
724+
TCPOLEN_MPTCP_ADD_ADDR6_BASE,
725+
MPTCP_ADDR_ECHO,
726+
opts->addr_id);
727+
memcpy((u8 *)ptr, opts->addr6.s6_addr, 16);
728+
ptr += 4;
729+
if (opts->ahmac) {
730+
put_unaligned_be64(opts->ahmac, ptr);
731+
ptr += 2;
732+
}
733+
}
734+
#endif
735+
736+
if (OPTION_MPTCP_RM_ADDR & opts->suboptions) {
737+
*ptr++ = mptcp_option(MPTCPOPT_RM_ADDR,
738+
TCPOLEN_MPTCP_RM_ADDR_BASE,
739+
0, opts->rm_id);
740+
}
741+
549742
if (opts->ext_copy.use_ack || opts->ext_copy.use_map) {
550743
struct mptcp_ext *mpext = &opts->ext_copy;
551744
u8 len = TCPOLEN_MPTCP_DSS_BASE;
@@ -567,10 +760,7 @@ void mptcp_write_options(__be32 *ptr, struct mptcp_out_options *opts)
567760
flags |= MPTCP_DSS_DATA_FIN;
568761
}
569762

570-
*ptr++ = htonl((TCPOPT_MPTCP << 24) |
571-
(len << 16) |
572-
(MPTCPOPT_DSS << 12) |
573-
(flags));
763+
*ptr++ = mptcp_option(MPTCPOPT_DSS, len, 0, flags);
574764

575765
if (mpext->use_ack) {
576766
put_unaligned_be64(mpext->data_ack, ptr);

0 commit comments

Comments
 (0)