Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | #ifndef _NET_TCP_ECN_H_ |
| 2 | #define _NET_TCP_ECN_H_ 1 |
| 3 | |
| 4 | #include <net/inet_ecn.h> |
Arnaldo Carvalho de Melo | 2e6599c | 2005-06-18 22:46:52 -0700 | [diff] [blame] | 5 | #include <net/request_sock.h> |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 6 | |
| 7 | #define TCP_HP_BITS (~(TCP_RESERVED_BITS|TCP_FLAG_PSH)) |
| 8 | |
| 9 | #define TCP_ECN_OK 1 |
| 10 | #define TCP_ECN_QUEUE_CWR 2 |
| 11 | #define TCP_ECN_DEMAND_CWR 4 |
| 12 | |
| 13 | static inline void TCP_ECN_queue_cwr(struct tcp_sock *tp) |
| 14 | { |
| 15 | if (tp->ecn_flags&TCP_ECN_OK) |
| 16 | tp->ecn_flags |= TCP_ECN_QUEUE_CWR; |
| 17 | } |
| 18 | |
| 19 | |
| 20 | /* Output functions */ |
| 21 | |
| 22 | static inline void TCP_ECN_send_synack(struct tcp_sock *tp, |
| 23 | struct sk_buff *skb) |
| 24 | { |
| 25 | TCP_SKB_CB(skb)->flags &= ~TCPCB_FLAG_CWR; |
| 26 | if (!(tp->ecn_flags&TCP_ECN_OK)) |
| 27 | TCP_SKB_CB(skb)->flags &= ~TCPCB_FLAG_ECE; |
| 28 | } |
| 29 | |
| 30 | static inline void TCP_ECN_send_syn(struct sock *sk, struct tcp_sock *tp, |
| 31 | struct sk_buff *skb) |
| 32 | { |
| 33 | tp->ecn_flags = 0; |
| 34 | if (sysctl_tcp_ecn && !(sk->sk_route_caps & NETIF_F_TSO)) { |
| 35 | TCP_SKB_CB(skb)->flags |= TCPCB_FLAG_ECE|TCPCB_FLAG_CWR; |
| 36 | tp->ecn_flags = TCP_ECN_OK; |
| 37 | sock_set_flag(sk, SOCK_NO_LARGESEND); |
| 38 | } |
| 39 | } |
| 40 | |
| 41 | static __inline__ void |
Arnaldo Carvalho de Melo | 60236fd | 2005-06-18 22:47:21 -0700 | [diff] [blame] | 42 | TCP_ECN_make_synack(struct request_sock *req, struct tcphdr *th) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 43 | { |
Arnaldo Carvalho de Melo | 2e6599c | 2005-06-18 22:46:52 -0700 | [diff] [blame] | 44 | if (inet_rsk(req)->ecn_ok) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 45 | th->ece = 1; |
| 46 | } |
| 47 | |
| 48 | static inline void TCP_ECN_send(struct sock *sk, struct tcp_sock *tp, |
| 49 | struct sk_buff *skb, int tcp_header_len) |
| 50 | { |
| 51 | if (tp->ecn_flags & TCP_ECN_OK) { |
| 52 | /* Not-retransmitted data segment: set ECT and inject CWR. */ |
| 53 | if (skb->len != tcp_header_len && |
| 54 | !before(TCP_SKB_CB(skb)->seq, tp->snd_nxt)) { |
| 55 | INET_ECN_xmit(sk); |
| 56 | if (tp->ecn_flags&TCP_ECN_QUEUE_CWR) { |
| 57 | tp->ecn_flags &= ~TCP_ECN_QUEUE_CWR; |
| 58 | skb->h.th->cwr = 1; |
| 59 | } |
| 60 | } else { |
| 61 | /* ACK or retransmitted segment: clear ECT|CE */ |
| 62 | INET_ECN_dontxmit(sk); |
| 63 | } |
| 64 | if (tp->ecn_flags & TCP_ECN_DEMAND_CWR) |
| 65 | skb->h.th->ece = 1; |
| 66 | } |
| 67 | } |
| 68 | |
| 69 | /* Input functions */ |
| 70 | |
| 71 | static inline void TCP_ECN_accept_cwr(struct tcp_sock *tp, struct sk_buff *skb) |
| 72 | { |
| 73 | if (skb->h.th->cwr) |
| 74 | tp->ecn_flags &= ~TCP_ECN_DEMAND_CWR; |
| 75 | } |
| 76 | |
| 77 | static inline void TCP_ECN_withdraw_cwr(struct tcp_sock *tp) |
| 78 | { |
| 79 | tp->ecn_flags &= ~TCP_ECN_DEMAND_CWR; |
| 80 | } |
| 81 | |
| 82 | static inline void TCP_ECN_check_ce(struct tcp_sock *tp, struct sk_buff *skb) |
| 83 | { |
| 84 | if (tp->ecn_flags&TCP_ECN_OK) { |
| 85 | if (INET_ECN_is_ce(TCP_SKB_CB(skb)->flags)) |
| 86 | tp->ecn_flags |= TCP_ECN_DEMAND_CWR; |
| 87 | /* Funny extension: if ECT is not set on a segment, |
| 88 | * it is surely retransmit. It is not in ECN RFC, |
| 89 | * but Linux follows this rule. */ |
| 90 | else if (INET_ECN_is_not_ect((TCP_SKB_CB(skb)->flags))) |
Arnaldo Carvalho de Melo | 463c84b | 2005-08-09 20:10:42 -0700 | [diff] [blame] | 91 | tcp_enter_quickack_mode((struct sock *)tp); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 92 | } |
| 93 | } |
| 94 | |
| 95 | static inline void TCP_ECN_rcv_synack(struct tcp_sock *tp, struct tcphdr *th) |
| 96 | { |
| 97 | if ((tp->ecn_flags&TCP_ECN_OK) && (!th->ece || th->cwr)) |
| 98 | tp->ecn_flags &= ~TCP_ECN_OK; |
| 99 | } |
| 100 | |
| 101 | static inline void TCP_ECN_rcv_syn(struct tcp_sock *tp, struct tcphdr *th) |
| 102 | { |
| 103 | if ((tp->ecn_flags&TCP_ECN_OK) && (!th->ece || !th->cwr)) |
| 104 | tp->ecn_flags &= ~TCP_ECN_OK; |
| 105 | } |
| 106 | |
| 107 | static inline int TCP_ECN_rcv_ecn_echo(struct tcp_sock *tp, struct tcphdr *th) |
| 108 | { |
| 109 | if (th->ece && !th->syn && (tp->ecn_flags&TCP_ECN_OK)) |
| 110 | return 1; |
| 111 | return 0; |
| 112 | } |
| 113 | |
| 114 | static inline void TCP_ECN_openreq_child(struct tcp_sock *tp, |
Arnaldo Carvalho de Melo | 60236fd | 2005-06-18 22:47:21 -0700 | [diff] [blame] | 115 | struct request_sock *req) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 116 | { |
Arnaldo Carvalho de Melo | 2e6599c | 2005-06-18 22:46:52 -0700 | [diff] [blame] | 117 | tp->ecn_flags = inet_rsk(req)->ecn_ok ? TCP_ECN_OK : 0; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 118 | } |
| 119 | |
| 120 | static __inline__ void |
Arnaldo Carvalho de Melo | 60236fd | 2005-06-18 22:47:21 -0700 | [diff] [blame] | 121 | TCP_ECN_create_request(struct request_sock *req, struct tcphdr *th) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 122 | { |
| 123 | if (sysctl_tcp_ecn && th->ece && th->cwr) |
Arnaldo Carvalho de Melo | 2e6599c | 2005-06-18 22:46:52 -0700 | [diff] [blame] | 124 | inet_rsk(req)->ecn_ok = 1; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 125 | } |
| 126 | |
| 127 | #endif |