| 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))) | 
 | 91 | 			tcp_enter_quickack_mode(tp); | 
 | 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 |