diff options
Diffstat (limited to 'net/ipv4/tcp_output.c')
-rw-r--r-- | net/ipv4/tcp_output.c | 111 |
1 files changed, 106 insertions, 5 deletions
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 6a8581ab9a23..32c1a972fa31 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c | |||
@@ -270,7 +270,7 @@ static u16 tcp_select_window(struct sock *sk) | |||
270 | } | 270 | } |
271 | 271 | ||
272 | static void tcp_build_and_update_options(__be32 *ptr, struct tcp_sock *tp, | 272 | static void tcp_build_and_update_options(__be32 *ptr, struct tcp_sock *tp, |
273 | __u32 tstamp) | 273 | __u32 tstamp, __u8 **md5_hash) |
274 | { | 274 | { |
275 | if (tp->rx_opt.tstamp_ok) { | 275 | if (tp->rx_opt.tstamp_ok) { |
276 | *ptr++ = htonl((TCPOPT_NOP << 24) | | 276 | *ptr++ = htonl((TCPOPT_NOP << 24) | |
@@ -298,16 +298,29 @@ static void tcp_build_and_update_options(__be32 *ptr, struct tcp_sock *tp, | |||
298 | tp->rx_opt.eff_sacks--; | 298 | tp->rx_opt.eff_sacks--; |
299 | } | 299 | } |
300 | } | 300 | } |
301 | #ifdef CONFIG_TCP_MD5SIG | ||
302 | if (md5_hash) { | ||
303 | *ptr++ = htonl((TCPOPT_NOP << 24) | | ||
304 | (TCPOPT_NOP << 16) | | ||
305 | (TCPOPT_MD5SIG << 8) | | ||
306 | TCPOLEN_MD5SIG); | ||
307 | *md5_hash = (__u8 *)ptr; | ||
308 | } | ||
309 | #endif | ||
301 | } | 310 | } |
302 | 311 | ||
303 | /* Construct a tcp options header for a SYN or SYN_ACK packet. | 312 | /* Construct a tcp options header for a SYN or SYN_ACK packet. |
304 | * If this is every changed make sure to change the definition of | 313 | * If this is every changed make sure to change the definition of |
305 | * MAX_SYN_SIZE to match the new maximum number of options that you | 314 | * MAX_SYN_SIZE to match the new maximum number of options that you |
306 | * can generate. | 315 | * can generate. |
316 | * | ||
317 | * Note - that with the RFC2385 TCP option, we make room for the | ||
318 | * 16 byte MD5 hash. This will be filled in later, so the pointer for the | ||
319 | * location to be filled is passed back up. | ||
307 | */ | 320 | */ |
308 | static void tcp_syn_build_options(__be32 *ptr, int mss, int ts, int sack, | 321 | static void tcp_syn_build_options(__be32 *ptr, int mss, int ts, int sack, |
309 | int offer_wscale, int wscale, __u32 tstamp, | 322 | int offer_wscale, int wscale, __u32 tstamp, |
310 | __u32 ts_recent) | 323 | __u32 ts_recent, __u8 **md5_hash) |
311 | { | 324 | { |
312 | /* We always get an MSS option. | 325 | /* We always get an MSS option. |
313 | * The option bytes which will be seen in normal data | 326 | * The option bytes which will be seen in normal data |
@@ -346,6 +359,20 @@ static void tcp_syn_build_options(__be32 *ptr, int mss, int ts, int sack, | |||
346 | (TCPOPT_WINDOW << 16) | | 359 | (TCPOPT_WINDOW << 16) | |
347 | (TCPOLEN_WINDOW << 8) | | 360 | (TCPOLEN_WINDOW << 8) | |
348 | (wscale)); | 361 | (wscale)); |
362 | #ifdef CONFIG_TCP_MD5SIG | ||
363 | /* | ||
364 | * If MD5 is enabled, then we set the option, and include the size | ||
365 | * (always 18). The actual MD5 hash is added just before the | ||
366 | * packet is sent. | ||
367 | */ | ||
368 | if (md5_hash) { | ||
369 | *ptr++ = htonl((TCPOPT_NOP << 24) | | ||
370 | (TCPOPT_NOP << 16) | | ||
371 | (TCPOPT_MD5SIG << 8) | | ||
372 | TCPOLEN_MD5SIG); | ||
373 | *md5_hash = (__u8 *) ptr; | ||
374 | } | ||
375 | #endif | ||
349 | } | 376 | } |
350 | 377 | ||
351 | /* This routine actually transmits TCP packets queued in by | 378 | /* This routine actually transmits TCP packets queued in by |
@@ -366,6 +393,10 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it, | |||
366 | struct tcp_sock *tp; | 393 | struct tcp_sock *tp; |
367 | struct tcp_skb_cb *tcb; | 394 | struct tcp_skb_cb *tcb; |
368 | int tcp_header_size; | 395 | int tcp_header_size; |
396 | #ifdef CONFIG_TCP_MD5SIG | ||
397 | struct tcp_md5sig_key *md5; | ||
398 | __u8 *md5_hash_location; | ||
399 | #endif | ||
369 | struct tcphdr *th; | 400 | struct tcphdr *th; |
370 | int sysctl_flags; | 401 | int sysctl_flags; |
371 | int err; | 402 | int err; |
@@ -424,6 +455,16 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it, | |||
424 | if (tcp_packets_in_flight(tp) == 0) | 455 | if (tcp_packets_in_flight(tp) == 0) |
425 | tcp_ca_event(sk, CA_EVENT_TX_START); | 456 | tcp_ca_event(sk, CA_EVENT_TX_START); |
426 | 457 | ||
458 | #ifdef CONFIG_TCP_MD5SIG | ||
459 | /* | ||
460 | * Are we doing MD5 on this segment? If so - make | ||
461 | * room for it. | ||
462 | */ | ||
463 | md5 = tp->af_specific->md5_lookup(sk, sk); | ||
464 | if (md5) | ||
465 | tcp_header_size += TCPOLEN_MD5SIG_ALIGNED; | ||
466 | #endif | ||
467 | |||
427 | th = (struct tcphdr *) skb_push(skb, tcp_header_size); | 468 | th = (struct tcphdr *) skb_push(skb, tcp_header_size); |
428 | skb->h.th = th; | 469 | skb->h.th = th; |
429 | 470 | ||
@@ -460,13 +501,34 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it, | |||
460 | (sysctl_flags & SYSCTL_FLAG_WSCALE), | 501 | (sysctl_flags & SYSCTL_FLAG_WSCALE), |
461 | tp->rx_opt.rcv_wscale, | 502 | tp->rx_opt.rcv_wscale, |
462 | tcb->when, | 503 | tcb->when, |
463 | tp->rx_opt.ts_recent); | 504 | tp->rx_opt.ts_recent, |
505 | |||
506 | #ifdef CONFIG_TCP_MD5SIG | ||
507 | md5 ? &md5_hash_location : | ||
508 | #endif | ||
509 | NULL); | ||
464 | } else { | 510 | } else { |
465 | tcp_build_and_update_options((__be32 *)(th + 1), | 511 | tcp_build_and_update_options((__be32 *)(th + 1), |
466 | tp, tcb->when); | 512 | tp, tcb->when, |
513 | #ifdef CONFIG_TCP_MD5SIG | ||
514 | md5 ? &md5_hash_location : | ||
515 | #endif | ||
516 | NULL); | ||
467 | TCP_ECN_send(sk, tp, skb, tcp_header_size); | 517 | TCP_ECN_send(sk, tp, skb, tcp_header_size); |
468 | } | 518 | } |
469 | 519 | ||
520 | #ifdef CONFIG_TCP_MD5SIG | ||
521 | /* Calculate the MD5 hash, as we have all we need now */ | ||
522 | if (md5) { | ||
523 | tp->af_specific->calc_md5_hash(md5_hash_location, | ||
524 | md5, | ||
525 | sk, NULL, NULL, | ||
526 | skb->h.th, | ||
527 | sk->sk_protocol, | ||
528 | skb->len); | ||
529 | } | ||
530 | #endif | ||
531 | |||
470 | icsk->icsk_af_ops->send_check(sk, skb->len, skb); | 532 | icsk->icsk_af_ops->send_check(sk, skb->len, skb); |
471 | 533 | ||
472 | if (likely(tcb->flags & TCPCB_FLAG_ACK)) | 534 | if (likely(tcb->flags & TCPCB_FLAG_ACK)) |
@@ -840,6 +902,11 @@ unsigned int tcp_current_mss(struct sock *sk, int large_allowed) | |||
840 | mss_now -= (TCPOLEN_SACK_BASE_ALIGNED + | 902 | mss_now -= (TCPOLEN_SACK_BASE_ALIGNED + |
841 | (tp->rx_opt.eff_sacks * TCPOLEN_SACK_PERBLOCK)); | 903 | (tp->rx_opt.eff_sacks * TCPOLEN_SACK_PERBLOCK)); |
842 | 904 | ||
905 | #ifdef CONFIG_TCP_MD5SIG | ||
906 | if (tp->af_specific->md5_lookup(sk, sk)) | ||
907 | mss_now -= TCPOLEN_MD5SIG_ALIGNED; | ||
908 | #endif | ||
909 | |||
843 | xmit_size_goal = mss_now; | 910 | xmit_size_goal = mss_now; |
844 | 911 | ||
845 | if (doing_tso) { | 912 | if (doing_tso) { |
@@ -2033,6 +2100,10 @@ struct sk_buff * tcp_make_synack(struct sock *sk, struct dst_entry *dst, | |||
2033 | struct tcphdr *th; | 2100 | struct tcphdr *th; |
2034 | int tcp_header_size; | 2101 | int tcp_header_size; |
2035 | struct sk_buff *skb; | 2102 | struct sk_buff *skb; |
2103 | #ifdef CONFIG_TCP_MD5SIG | ||
2104 | struct tcp_md5sig_key *md5; | ||
2105 | __u8 *md5_hash_location; | ||
2106 | #endif | ||
2036 | 2107 | ||
2037 | skb = sock_wmalloc(sk, MAX_TCP_HEADER + 15, 1, GFP_ATOMIC); | 2108 | skb = sock_wmalloc(sk, MAX_TCP_HEADER + 15, 1, GFP_ATOMIC); |
2038 | if (skb == NULL) | 2109 | if (skb == NULL) |
@@ -2048,6 +2119,13 @@ struct sk_buff * tcp_make_synack(struct sock *sk, struct dst_entry *dst, | |||
2048 | (ireq->wscale_ok ? TCPOLEN_WSCALE_ALIGNED : 0) + | 2119 | (ireq->wscale_ok ? TCPOLEN_WSCALE_ALIGNED : 0) + |
2049 | /* SACK_PERM is in the place of NOP NOP of TS */ | 2120 | /* SACK_PERM is in the place of NOP NOP of TS */ |
2050 | ((ireq->sack_ok && !ireq->tstamp_ok) ? TCPOLEN_SACKPERM_ALIGNED : 0)); | 2121 | ((ireq->sack_ok && !ireq->tstamp_ok) ? TCPOLEN_SACKPERM_ALIGNED : 0)); |
2122 | |||
2123 | #ifdef CONFIG_TCP_MD5SIG | ||
2124 | /* Are we doing MD5 on this segment? If so - make room for it */ | ||
2125 | md5 = tcp_rsk(req)->af_specific->md5_lookup(sk, req); | ||
2126 | if (md5) | ||
2127 | tcp_header_size += TCPOLEN_MD5SIG_ALIGNED; | ||
2128 | #endif | ||
2051 | skb->h.th = th = (struct tcphdr *) skb_push(skb, tcp_header_size); | 2129 | skb->h.th = th = (struct tcphdr *) skb_push(skb, tcp_header_size); |
2052 | 2130 | ||
2053 | memset(th, 0, sizeof(struct tcphdr)); | 2131 | memset(th, 0, sizeof(struct tcphdr)); |
@@ -2085,11 +2163,29 @@ struct sk_buff * tcp_make_synack(struct sock *sk, struct dst_entry *dst, | |||
2085 | tcp_syn_build_options((__be32 *)(th + 1), dst_metric(dst, RTAX_ADVMSS), ireq->tstamp_ok, | 2163 | tcp_syn_build_options((__be32 *)(th + 1), dst_metric(dst, RTAX_ADVMSS), ireq->tstamp_ok, |
2086 | ireq->sack_ok, ireq->wscale_ok, ireq->rcv_wscale, | 2164 | ireq->sack_ok, ireq->wscale_ok, ireq->rcv_wscale, |
2087 | TCP_SKB_CB(skb)->when, | 2165 | TCP_SKB_CB(skb)->when, |
2088 | req->ts_recent); | 2166 | req->ts_recent, |
2167 | ( | ||
2168 | #ifdef CONFIG_TCP_MD5SIG | ||
2169 | md5 ? &md5_hash_location : | ||
2170 | #endif | ||
2171 | NULL) | ||
2172 | ); | ||
2089 | 2173 | ||
2090 | skb->csum = 0; | 2174 | skb->csum = 0; |
2091 | th->doff = (tcp_header_size >> 2); | 2175 | th->doff = (tcp_header_size >> 2); |
2092 | TCP_INC_STATS(TCP_MIB_OUTSEGS); | 2176 | TCP_INC_STATS(TCP_MIB_OUTSEGS); |
2177 | |||
2178 | #ifdef CONFIG_TCP_MD5SIG | ||
2179 | /* Okay, we have all we need - do the md5 hash if needed */ | ||
2180 | if (md5) { | ||
2181 | tp->af_specific->calc_md5_hash(md5_hash_location, | ||
2182 | md5, | ||
2183 | NULL, dst, req, | ||
2184 | skb->h.th, sk->sk_protocol, | ||
2185 | skb->len); | ||
2186 | } | ||
2187 | #endif | ||
2188 | |||
2093 | return skb; | 2189 | return skb; |
2094 | } | 2190 | } |
2095 | 2191 | ||
@@ -2108,6 +2204,11 @@ static void tcp_connect_init(struct sock *sk) | |||
2108 | tp->tcp_header_len = sizeof(struct tcphdr) + | 2204 | tp->tcp_header_len = sizeof(struct tcphdr) + |
2109 | (sysctl_tcp_timestamps ? TCPOLEN_TSTAMP_ALIGNED : 0); | 2205 | (sysctl_tcp_timestamps ? TCPOLEN_TSTAMP_ALIGNED : 0); |
2110 | 2206 | ||
2207 | #ifdef CONFIG_TCP_MD5SIG | ||
2208 | if (tp->af_specific->md5_lookup(sk, sk) != NULL) | ||
2209 | tp->tcp_header_len += TCPOLEN_MD5SIG_ALIGNED; | ||
2210 | #endif | ||
2211 | |||
2111 | /* If user gave his TCP_MAXSEG, record it to clamp */ | 2212 | /* If user gave his TCP_MAXSEG, record it to clamp */ |
2112 | if (tp->rx_opt.user_mss) | 2213 | if (tp->rx_opt.user_mss) |
2113 | tp->rx_opt.mss_clamp = tp->rx_opt.user_mss; | 2214 | tp->rx_opt.mss_clamp = tp->rx_opt.user_mss; |