ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / include / net / tcp_ecn.h
1 #ifndef _NET_TCP_ECN_H_
2 #define _NET_TCP_ECN_H_ 1
3
4 #include <net/inet_ecn.h>
5
6 #define TCP_HP_BITS (~(TCP_RESERVED_BITS|TCP_FLAG_PSH))
7
8 #define TCP_ECN_OK              1
9 #define TCP_ECN_QUEUE_CWR       2
10 #define TCP_ECN_DEMAND_CWR      4
11
12 static __inline__ void
13 TCP_ECN_queue_cwr(struct tcp_opt *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
23 TCP_ECN_send_synack(struct tcp_opt *tp, 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
31 TCP_ECN_send_syn(struct sock *sk, struct tcp_opt *tp, 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                 sk->sk_no_largesend = 1;
38         }
39 }
40
41 static __inline__ void
42 TCP_ECN_make_synack(struct open_request *req, struct tcphdr *th)
43 {
44         if (req->ecn_ok)
45                 th->ece = 1;
46 }
47
48 static __inline__ void
49 TCP_ECN_send(struct sock *sk, struct tcp_opt *tp, 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
72 TCP_ECN_accept_cwr(struct tcp_opt *tp, struct sk_buff *skb)
73 {
74         if (skb->h.th->cwr)
75                 tp->ecn_flags &= ~TCP_ECN_DEMAND_CWR;
76 }
77
78 static __inline__ void
79 TCP_ECN_withdraw_cwr(struct tcp_opt *tp)
80 {
81         tp->ecn_flags &= ~TCP_ECN_DEMAND_CWR;
82 }
83
84 static __inline__ void
85 TCP_ECN_check_ce(struct tcp_opt *tp, struct sk_buff *skb)
86 {
87         if (tp->ecn_flags&TCP_ECN_OK) {
88                 if (INET_ECN_is_ce(TCP_SKB_CB(skb)->flags))
89                         tp->ecn_flags |= TCP_ECN_DEMAND_CWR;
90                 /* Funny extension: if ECT is not set on a segment,
91                  * it is surely retransmit. It is not in ECN RFC,
92                  * but Linux follows this rule. */
93                 else if (!INET_ECN_is_capable((TCP_SKB_CB(skb)->flags)))
94                         tcp_enter_quickack_mode(tp);
95         }
96 }
97
98 static __inline__ void
99 TCP_ECN_rcv_synack(struct tcp_opt *tp, struct tcphdr *th)
100 {
101         if ((tp->ecn_flags&TCP_ECN_OK) && (!th->ece || th->cwr))
102                 tp->ecn_flags &= ~TCP_ECN_OK;
103 }
104
105 static __inline__ void
106 TCP_ECN_rcv_syn(struct tcp_opt *tp, struct tcphdr *th)
107 {
108         if ((tp->ecn_flags&TCP_ECN_OK) && (!th->ece || !th->cwr))
109                 tp->ecn_flags &= ~TCP_ECN_OK;
110 }
111
112 static __inline__ int
113 TCP_ECN_rcv_ecn_echo(struct tcp_opt *tp, struct tcphdr *th)
114 {
115         if (th->ece && !th->syn && (tp->ecn_flags&TCP_ECN_OK))
116                 return 1;
117         return 0;
118 }
119
120 static __inline__ void
121 TCP_ECN_openreq_child(struct tcp_opt *tp, struct open_request *req)
122 {
123         tp->ecn_flags = req->ecn_ok ? TCP_ECN_OK : 0;
124 }
125
126 static __inline__ void
127 TCP_ECN_create_request(struct open_request *req, struct tcphdr *th)
128 {
129         if (sysctl_tcp_ecn && th->ece && th->cwr)
130                 req->ecn_ok = 1;
131 }
132
133 #endif