| 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; | 
| Michael Chan | b0da8537 | 2006-06-29 12:30:00 -0700 | [diff] [blame] | 34 | if (sysctl_tcp_ecn) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 35 | TCP_SKB_CB(skb)->flags |= TCPCB_FLAG_ECE|TCPCB_FLAG_CWR; | 
|  | 36 | tp->ecn_flags = TCP_ECN_OK; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 37 | } | 
|  | 38 | } | 
|  | 39 |  | 
|  | 40 | static __inline__ void | 
| Arnaldo Carvalho de Melo | 60236fd | 2005-06-18 22:47:21 -0700 | [diff] [blame] | 41 | TCP_ECN_make_synack(struct request_sock *req, struct tcphdr *th) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 42 | { | 
| Arnaldo Carvalho de Melo | 2e6599c | 2005-06-18 22:46:52 -0700 | [diff] [blame] | 43 | if (inet_rsk(req)->ecn_ok) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 44 | th->ece = 1; | 
|  | 45 | } | 
|  | 46 |  | 
|  | 47 | static inline void TCP_ECN_send(struct sock *sk, struct tcp_sock *tp, | 
|  | 48 | struct sk_buff *skb, int tcp_header_len) | 
|  | 49 | { | 
|  | 50 | if (tp->ecn_flags & TCP_ECN_OK) { | 
|  | 51 | /* Not-retransmitted data segment: set ECT and inject CWR. */ | 
|  | 52 | if (skb->len != tcp_header_len && | 
|  | 53 | !before(TCP_SKB_CB(skb)->seq, tp->snd_nxt)) { | 
|  | 54 | INET_ECN_xmit(sk); | 
|  | 55 | if (tp->ecn_flags&TCP_ECN_QUEUE_CWR) { | 
|  | 56 | tp->ecn_flags &= ~TCP_ECN_QUEUE_CWR; | 
|  | 57 | skb->h.th->cwr = 1; | 
| Herbert Xu | f83ef8c | 2006-06-30 13:37:03 -0700 | [diff] [blame] | 58 | skb_shinfo(skb)->gso_type |= SKB_GSO_TCP_ECN; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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 |