Skip to content

Commit f5fff5d

Browse files
Tom Quetchenbachdavem330
authored andcommitted
tcp: advertise MSS requested by user
I'm trying to use the TCP_MAXSEG option to setsockopt() to set the MSS for both sides of a bidirectional connection. man tcp says: "If this option is set before connection establishment, it also changes the MSS value announced to the other end in the initial packet." However, the kernel only uses the MTU/route cache to set the advertised MSS. That means if I set the MSS to, say, 500 before calling connect(), I will send at most 500-byte packets, but I will still receive 1500-byte packets in reply. This is a bug, either in the kernel or the documentation. This patch (applies to latest net-2.6) reduces the advertised value to that requested by the user as long as setsockopt() is called before connect() or accept(). This seems like the behavior that one would expect as well as that which is documented. I've tried to make sure that things that depend on the advertised MSS are set correctly. Signed-off-by: Tom Quetchenbach <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 6067804 commit f5fff5d

File tree

2 files changed

+14
-3
lines changed

2 files changed

+14
-3
lines changed

net/ipv4/tcp_ipv4.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1364,6 +1364,10 @@ struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
13641364
tcp_mtup_init(newsk);
13651365
tcp_sync_mss(newsk, dst_mtu(dst));
13661366
newtp->advmss = dst_metric(dst, RTAX_ADVMSS);
1367+
if (tcp_sk(sk)->rx_opt.user_mss &&
1368+
tcp_sk(sk)->rx_opt.user_mss < newtp->advmss)
1369+
newtp->advmss = tcp_sk(sk)->rx_opt.user_mss;
1370+
13671371
tcp_initialize_rcv_mss(newsk);
13681372

13691373
#ifdef CONFIG_TCP_MD5SIG

net/ipv4/tcp_output.c

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2232,6 +2232,7 @@ struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst,
22322232
struct sk_buff *skb;
22332233
struct tcp_md5sig_key *md5;
22342234
__u8 *md5_hash_location;
2235+
int mss;
22352236

22362237
skb = sock_wmalloc(sk, MAX_TCP_HEADER + 15, 1, GFP_ATOMIC);
22372238
if (skb == NULL)
@@ -2242,13 +2243,17 @@ struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst,
22422243

22432244
skb->dst = dst_clone(dst);
22442245

2246+
mss = dst_metric(dst, RTAX_ADVMSS);
2247+
if (tp->rx_opt.user_mss && tp->rx_opt.user_mss < mss)
2248+
mss = tp->rx_opt.user_mss;
2249+
22452250
if (req->rcv_wnd == 0) { /* ignored for retransmitted syns */
22462251
__u8 rcv_wscale;
22472252
/* Set this up on the first call only */
22482253
req->window_clamp = tp->window_clamp ? : dst_metric(dst, RTAX_WINDOW);
22492254
/* tcp_full_space because it is guaranteed to be the first packet */
22502255
tcp_select_initial_window(tcp_full_space(sk),
2251-
dst_metric(dst, RTAX_ADVMSS) - (ireq->tstamp_ok ? TCPOLEN_TSTAMP_ALIGNED : 0),
2256+
mss - (ireq->tstamp_ok ? TCPOLEN_TSTAMP_ALIGNED : 0),
22522257
&req->rcv_wnd,
22532258
&req->window_clamp,
22542259
ireq->wscale_ok,
@@ -2258,8 +2263,7 @@ struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst,
22582263

22592264
memset(&opts, 0, sizeof(opts));
22602265
TCP_SKB_CB(skb)->when = tcp_time_stamp;
2261-
tcp_header_size = tcp_synack_options(sk, req,
2262-
dst_metric(dst, RTAX_ADVMSS),
2266+
tcp_header_size = tcp_synack_options(sk, req, mss,
22632267
skb, &opts, &md5) +
22642268
sizeof(struct tcphdr);
22652269

@@ -2333,6 +2337,9 @@ static void tcp_connect_init(struct sock *sk)
23332337
if (!tp->window_clamp)
23342338
tp->window_clamp = dst_metric(dst, RTAX_WINDOW);
23352339
tp->advmss = dst_metric(dst, RTAX_ADVMSS);
2340+
if (tp->rx_opt.user_mss && tp->rx_opt.user_mss < tp->advmss)
2341+
tp->advmss = tp->rx_opt.user_mss;
2342+
23362343
tcp_initialize_rcv_mss(sk);
23372344

23382345
tcp_select_initial_window(tcp_full_space(sk),

0 commit comments

Comments
 (0)