summaryrefslogtreecommitdiffstats
path: root/include/net/tcp_ecn.h
blob: 01894cd3b5878d2d860e77550c55103f5ceface8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
#ifndef _NET_TCP_ECN_H_
#define _NET_TCP_ECN_H_ 1

#include <linux/config.h>

#ifdef CONFIG_INET_ECN

#include <net/inet_ecn.h>

#define TCP_HP_BITS (~(TCP_RESERVED_BITS|TCP_FLAG_PSH)|TCP_FLAG_ECE|TCP_FLAG_CWR)

#define	TCP_ECN_OK		1
#define TCP_ECN_QUEUE_CWR	2
#define TCP_ECN_DEMAND_CWR	4

static __inline__ void
TCP_ECN_queue_cwr(struct tcp_opt *tp)
{
	if (tp->ecn_flags&TCP_ECN_OK)
		tp->ecn_flags |= TCP_ECN_QUEUE_CWR;
}


/* Output functions */

static __inline__ void
TCP_ECN_send_synack(struct tcp_opt *tp, struct sk_buff *skb)
{
	TCP_SKB_CB(skb)->flags &= ~TCPCB_FLAG_CWR;
	if (!(tp->ecn_flags&TCP_ECN_OK))
		TCP_SKB_CB(skb)->flags &= ~TCPCB_FLAG_ECE;
}

static __inline__ void
TCP_ECN_send_syn(struct tcp_opt *tp, struct sk_buff *skb)
{
	tp->ecn_flags = 0;
	if (sysctl_tcp_ecn) {
		TCP_SKB_CB(skb)->flags |= TCPCB_FLAG_ECE|TCPCB_FLAG_CWR;
		tp->ecn_flags = TCP_ECN_OK;
	}
}

static __inline__ void
TCP_ECN_make_synack(struct open_request *req, struct tcphdr *th)
{
	if (req->ecn_ok)
		th->ece = 1;
}

static __inline__ void
TCP_ECN_send(struct sock *sk, struct tcp_opt *tp, struct sk_buff *skb, int tcp_header_len)
{
	if (tp->ecn_flags & TCP_ECN_OK) {
		/* Not-retransmitted data segment: set ECT and inject CWR. */
		if (skb->len != tcp_header_len &&
		    !before(TCP_SKB_CB(skb)->seq, tp->snd_nxt)) {
			INET_ECN_xmit(sk);
			if (tp->ecn_flags&TCP_ECN_QUEUE_CWR) {
				tp->ecn_flags &= ~TCP_ECN_QUEUE_CWR;
				skb->h.th->cwr = 1;
			}
		} else {
			/* ACK or retransmitted segment: clear ECT|CE */
			INET_ECN_dontxmit(sk);
		}
		if (tp->ecn_flags & TCP_ECN_DEMAND_CWR)
			skb->h.th->ece = 1;
	}
}

/* Input functions */

static __inline__ void
TCP_ECN_accept_cwr(struct tcp_opt *tp, struct sk_buff *skb)
{
	if (skb->h.th->cwr)
		tp->ecn_flags &= ~TCP_ECN_DEMAND_CWR;
}

static __inline__ void
TCP_ECN_withdraw_cwr(struct tcp_opt *tp)
{
	tp->ecn_flags &= ~TCP_ECN_DEMAND_CWR;
}

static __inline__ void
TCP_ECN_check_ce(struct tcp_opt *tp, struct sk_buff *skb)
{
	if (tp->ecn_flags&TCP_ECN_OK) {
		if (INET_ECN_is_ce(TCP_SKB_CB(skb)->flags))
			tp->ecn_flags |= TCP_ECN_DEMAND_CWR;
		/* Funny extension: if ECT is not set on a segment,
		 * it is surely retransmit. It is not in ECN RFC,
		 * but Linux follows this rule. */
		else if (!INET_ECN_is_capable((TCP_SKB_CB(skb)->flags)))
			tcp_enter_quickack_mode(tp);
	}
}

static __inline__ void
TCP_ECN_rcv_synack(struct tcp_opt *tp, struct tcphdr *th)
{
	if ((tp->ecn_flags&TCP_ECN_OK) && (!th->ece || th->cwr))
		tp->ecn_flags &= ~TCP_ECN_OK;
}

static __inline__ void
TCP_ECN_rcv_syn(struct tcp_opt *tp, struct tcphdr *th)
{
	if ((tp->ecn_flags&TCP_ECN_OK) && (!th->ece || !th->cwr))
		tp->ecn_flags &= ~TCP_ECN_OK;
}

static __inline__ int
TCP_ECN_rcv_ecn_echo(struct tcp_opt *tp, struct tcphdr *th)
{
	if (th->ece && !th->syn && (tp->ecn_flags&TCP_ECN_OK))
		return 1;
	return 0;
}

static __inline__ void
TCP_ECN_openreq_child(struct tcp_opt *tp, struct open_request *req)
{
	tp->ecn_flags = req->ecn_ok ? TCP_ECN_OK : 0;
}

static __inline__ void
TCP_ECN_create_request(struct open_request *req, struct tcphdr *th)
{
	if (sysctl_tcp_ecn && th->ece && th->cwr)
		req->ecn_ok = 1;
}



#else

#define TCP_HP_BITS (~(TCP_RESERVED_BITS|TCP_FLAG_PSH))


#define TCP_ECN_send_syn(x...)		do { } while (0)
#define TCP_ECN_send_synack(x...)	do { } while (0)
#define TCP_ECN_make_synack(x...)	do { } while (0)
#define TCP_ECN_send(x...)		do { } while (0)

#define TCP_ECN_queue_cwr(x...)		do { } while (0)

#define TCP_ECN_accept_cwr(x...)	do { } while (0)
#define TCP_ECN_check_ce(x...)		do { } while (0)
#define TCP_ECN_rcv_synack(x...)	do { } while (0)
#define TCP_ECN_rcv_syn(x...)		do { } while (0)
#define TCP_ECN_rcv_ecn_echo(x...)	(0)
#define TCP_ECN_openreq_child(x...)	do { } while (0)
#define TCP_ECN_create_request(x...)	do { } while (0)
#define TCP_ECN_withdraw_cwr(x...)	do { } while (0)


#endif

#endif