aboutsummaryrefslogtreecommitdiff
path: root/website/static/security/patches/SA-04:04/tcp51.patch
blob: 2e1d969087c47e9d6acee4fbbe7a10c6ee1ae637 (plain) (blame)
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
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
Index: sys/netinet/tcp_input.c
===================================================================
RCS file: /home/ncvs/src/sys/netinet/tcp_input.c,v
retrieving revision 1.205
retrieving revision 1.205.2.1
diff -c -r1.205 -r1.205.2.1
*** sys/netinet/tcp_input.c	7 May 2003 05:26:27 -0000	1.205
--- sys/netinet/tcp_input.c	15 Mar 2004 20:02:07 -0000	1.205.2.1
***************
*** 57,62 ****
--- 57,64 ----
  
  #include <machine/cpu.h>	/* before tcp_seq.h, for tcp_random18() */
  
+ #include <vm/uma.h>
+ 
  #include <net/if.h>
  #include <net/route.h>
  
***************
*** 97,104 ****
  
  #include <machine/in_cksum.h>
  
- MALLOC_DEFINE(M_TSEGQ, "tseg_qent", "TCP segment queue entry");
- 
  static const int tcprexmtthresh = 3;
  tcp_cc	tcp_ccgen;
  
--- 99,104 ----
***************
*** 134,139 ****
--- 134,157 ----
      &tcp_do_rfc3390, 0,
      "Enable RFC 3390 (Increasing TCP's Initial Congestion Window)");
  
+ SYSCTL_NODE(_net_inet_tcp, OID_AUTO, reass, CTLFLAG_RW, 0,
+     "TCP Segment Reassembly Queue");
+ 
+ static int tcp_reass_maxseg = 0;
+ SYSCTL_INT(_net_inet_tcp_reass, OID_AUTO, maxsegments, CTLFLAG_RD,
+     &tcp_reass_maxseg, 0,
+     "Global maximum number of TCP Segments in Reassembly Queue");
+ 
+ int tcp_reass_qsize = 0;
+ SYSCTL_INT(_net_inet_tcp_reass, OID_AUTO, cursegments, CTLFLAG_RD,
+     &tcp_reass_qsize, 0,
+     "Global number of TCP Segments currently in Reassembly Queue");
+ 
+ static int tcp_reass_overflows = 0;
+ SYSCTL_INT(_net_inet_tcp_reass, OID_AUTO, overflows, CTLFLAG_RD,
+     &tcp_reass_overflows, 0,
+     "Global number of TCP Segment Reassembly Queue Overflows");
+ 
  struct inpcbhead tcb;
  #define	tcb6	tcb  /* for KAME src sync over BSD*'s */
  struct inpcbinfo tcbinfo;
***************
*** 175,180 ****
--- 193,211 ----
  	    (tp->t_flags & TF_RXWIN0SENT) == 0) &&			\
  	    (tcp_delack_enabled || (tp->t_flags & TF_NEEDSYN)))
  
+ /* Initialize TCP reassembly queue */
+ uma_zone_t	tcp_reass_zone;
+ void
+ tcp_reass_init()
+ {
+ 	tcp_reass_maxseg = nmbclusters / 16;
+ 	TUNABLE_INT_FETCH("net.inet.tcp.reass.maxsegments",
+ 	    &tcp_reass_maxseg);
+ 	tcp_reass_zone = uma_zcreate("tcpreass", sizeof (struct tseg_qent),
+ 	    NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_NOFREE);
+ 	uma_zone_set_max(tcp_reass_zone, tcp_reass_maxseg);
+ }
+ 
  static int
  tcp_reass(tp, th, tlenp, m)
  	register struct tcpcb *tp;
***************
*** 185,191 ****
  	struct tseg_qent *q;
  	struct tseg_qent *p = NULL;
  	struct tseg_qent *nq;
! 	struct tseg_qent *te;
  	struct socket *so = tp->t_inpcb->inp_socket;
  	int flags;
  
--- 216,222 ----
  	struct tseg_qent *q;
  	struct tseg_qent *p = NULL;
  	struct tseg_qent *nq;
! 	struct tseg_qent *te = NULL;
  	struct socket *so = tp->t_inpcb->inp_socket;
  	int flags;
  
***************
*** 196,209 ****
  	if (th == 0)
  		goto present;
  
! 	/* Allocate a new queue entry. If we can't, just drop the pkt. XXX */
! 	MALLOC(te, struct tseg_qent *, sizeof (struct tseg_qent), M_TSEGQ,
! 	       M_NOWAIT);
  	if (te == NULL) {
  		tcpstat.tcps_rcvmemdrop++;
  		m_freem(m);
  		return (0);
  	}
  
  	/*
  	 * Find a segment which begins after this one does.
--- 227,258 ----
  	if (th == 0)
  		goto present;
  
! 	/*
! 	 * Limit the number of segments in the reassembly queue to prevent
! 	 * holding on to too many segments (and thus running out of mbufs).
! 	 * Make sure to let the missing segment through which caused this
! 	 * queue.  Always keep one global queue entry spare to be able to
! 	 * process the missing segment.
! 	 */
! 	if (th->th_seq != tp->rcv_nxt &&
! 	    tcp_reass_qsize + 1 >= tcp_reass_maxseg) {
! 		tcp_reass_overflows++;
! 		tcpstat.tcps_rcvmemdrop++;
! 		m_freem(m);
! 		return (0);
! 	}
! 
! 	/*
! 	 * Allocate a new queue entry. If we can't, or hit the zone limit
! 	 * just drop the pkt.
! 	 */
! 	te = uma_zalloc(tcp_reass_zone, M_NOWAIT);
  	if (te == NULL) {
  		tcpstat.tcps_rcvmemdrop++;
  		m_freem(m);
  		return (0);
  	}
+ 	tcp_reass_qsize++;
  
  	/*
  	 * Find a segment which begins after this one does.
***************
*** 228,234 ****
  				tcpstat.tcps_rcvduppack++;
  				tcpstat.tcps_rcvdupbyte += *tlenp;
  				m_freem(m);
! 				FREE(te, M_TSEGQ);
  				/*
  				 * Try to present any queued data
  				 * at the left window edge to the user.
--- 277,284 ----
  				tcpstat.tcps_rcvduppack++;
  				tcpstat.tcps_rcvdupbyte += *tlenp;
  				m_freem(m);
! 				uma_zfree(tcp_reass_zone, te);
! 				tcp_reass_qsize--;
  				/*
  				 * Try to present any queued data
  				 * at the left window edge to the user.
***************
*** 263,269 ****
  		nq = LIST_NEXT(q, tqe_q);
  		LIST_REMOVE(q, tqe_q);
  		m_freem(q->tqe_m);
! 		FREE(q, M_TSEGQ);
  		q = nq;
  	}
  
--- 313,320 ----
  		nq = LIST_NEXT(q, tqe_q);
  		LIST_REMOVE(q, tqe_q);
  		m_freem(q->tqe_m);
! 		uma_zfree(tcp_reass_zone, q);
! 		tcp_reass_qsize--;
  		q = nq;
  	}
  
***************
*** 297,303 ****
  			m_freem(q->tqe_m);
  		else
  			sbappend(&so->so_rcv, q->tqe_m);
! 		FREE(q, M_TSEGQ);
  		q = nq;
  	} while (q && q->tqe_th->th_seq == tp->rcv_nxt);
  	ND6_HINT(tp);
--- 348,355 ----
  			m_freem(q->tqe_m);
  		else
  			sbappend(&so->so_rcv, q->tqe_m);
! 		uma_zfree(tcp_reass_zone, q);
! 		tcp_reass_qsize--;
  		q = nq;
  	} while (q && q->tqe_th->th_seq == tp->rcv_nxt);
  	ND6_HINT(tp);
Index: sys/netinet/tcp_subr.c
===================================================================
RCS file: /home/ncvs/src/sys/netinet/tcp_subr.c,v
retrieving revision 1.160
retrieving revision 1.160.2.1
diff -c -r1.160 -r1.160.2.1
*** sys/netinet/tcp_subr.c	7 May 2003 05:26:27 -0000	1.160
--- sys/netinet/tcp_subr.c	15 Mar 2004 20:02:07 -0000	1.160.2.1
***************
*** 262,267 ****
--- 262,268 ----
  	uma_zone_set_max(tcptw_zone, maxsockets);
  	tcp_timer_init();
  	syncache_init();
+ 	tcp_reass_init();
  }
  
  /*
***************
*** 763,769 ****
  	while ((q = LIST_FIRST(&tp->t_segq)) != NULL) {
  		LIST_REMOVE(q, tqe_q);
  		m_freem(q->tqe_m);
! 		FREE(q, M_TSEGQ);
  	}
  	inp->inp_ppcb = NULL;
  	tp->t_inpcb = NULL;
--- 764,771 ----
  	while ((q = LIST_FIRST(&tp->t_segq)) != NULL) {
  		LIST_REMOVE(q, tqe_q);
  		m_freem(q->tqe_m);
! 		uma_zfree(tcp_reass_zone, q);
! 		tcp_reass_qsize--;
  	}
  	inp->inp_ppcb = NULL;
  	tp->t_inpcb = NULL;
***************
*** 824,830 ****
  			            != NULL) {
  					LIST_REMOVE(te, tqe_q);
  					m_freem(te->tqe_m);
! 					FREE(te, M_TSEGQ);
  				}
  			}
  			INP_UNLOCK(inpb);
--- 826,833 ----
  			            != NULL) {
  					LIST_REMOVE(te, tqe_q);
  					m_freem(te->tqe_m);
! 					uma_zfree(tcp_reass_zone, te);
! 					tcp_reass_qsize--;
  				}
  			}
  			INP_UNLOCK(inpb);
Index: sys/netinet/tcp_var.h
===================================================================
RCS file: /home/ncvs/src/sys/netinet/tcp_var.h,v
retrieving revision 1.89
retrieving revision 1.89.2.1
diff -c -r1.89 -r1.89.2.1
*** sys/netinet/tcp_var.h	7 May 2003 05:26:27 -0000	1.89
--- sys/netinet/tcp_var.h	15 Mar 2004 20:02:07 -0000	1.89.2.1
***************
*** 54,62 ****
  	struct	mbuf	*tqe_m;		/* mbuf contains packet */
  };
  LIST_HEAD(tsegqe_head, tseg_qent);
! #ifdef MALLOC_DECLARE
! MALLOC_DECLARE(M_TSEGQ);
! #endif
  
  struct tcptemp {
  	u_char	tt_ipgen[40]; /* the size must be of max ip header, now IPv6 */
--- 54,61 ----
  	struct	mbuf	*tqe_m;		/* mbuf contains packet */
  };
  LIST_HEAD(tsegqe_head, tseg_qent);
! extern int	tcp_reass_qsize;
! extern struct uma_zone	*tcp_reass_zone;
  
  struct tcptemp {
  	u_char	tt_ipgen[40]; /* the size must be of max ip header, now IPv6 */
***************
*** 489,494 ****
--- 488,494 ----
  int	 tcp_output(struct tcpcb *);
  struct inpcb *
  	 tcp_quench(struct inpcb *, int);
+ void	 tcp_reass_init(void);
  void	 tcp_respond(struct tcpcb *, void *,
  	    struct tcphdr *, struct mbuf *, tcp_seq, tcp_seq, int);
  int	 tcp_twrespond(struct tcptw *, struct socket *, struct mbuf *, int);