minor bugs
[unix-history] / usr / src / sys / netinet / tcp_input.c
CommitLineData
ac83b17a 1/* tcp_input.c 1.37 81/12/09 */
87e78f19
BJ
2
3#include "../h/param.h"
4#include "../h/systm.h"
dad64fdf 5#include "../h/mbuf.h"
8a13b737 6#include "../h/protosw.h"
dad64fdf 7#include "../h/socket.h"
d52566dd 8#include "../h/socketvar.h"
8a13b737
BJ
9#include "../net/in.h"
10#include "../net/in_pcb.h"
11#include "../net/in_systm.h"
12#include "../net/if.h"
d52566dd 13#include "../net/ip.h"
eb44bfb2 14#include "../net/ip_var.h"
d52566dd
BJ
15#include "../net/tcp.h"
16#include "../net/tcp_fsm.h"
8a13b737
BJ
17#include "../net/tcp_seq.h"
18#include "../net/tcp_timer.h"
d52566dd 19#include "../net/tcp_var.h"
8a13b737 20#include "../net/tcpip.h"
f1b2fa5b 21#include "../errno.h"
87e78f19 22
60b16fa9 23int tcpcksum = 1;
87e78f19 24
2ff61f9d
BJ
25/*
26 * TCP input routine, follows pages 65-76 of the
27 * protocol specification dated September, 1981 very closely.
28 */
2b4b57cd
BJ
29tcp_input(m0)
30 struct mbuf *m0;
87e78f19 31{
2b4b57cd 32 register struct tcpiphdr *ti;
53a5409e 33 struct inpcb *inp;
2b4b57cd
BJ
34 register struct mbuf *m;
35 int len, tlen, off;
2b4b57cd 36 register struct tcpcb *tp;
2b4b57cd 37 register int tiflags;
d52566dd 38 struct socket *so;
f1b2fa5b 39 int todrop, acked;
87e78f19 40
2b4b57cd 41COUNT(TCP_INPUT);
87e78f19 42 /*
2b4b57cd 43 * Get ip and tcp header together in first mbuf.
ac83b17a 44 * Note: ip leaves ip header in first mbuf.
87e78f19 45 */
2b4b57cd 46 m = m0;
20790db4 47 ti = mtod(m, struct tcpiphdr *);
ac83b17a 48 if (((struct ip *)ti)->ip_len > sizeof (struct ip))
d63599ac 49 ip_stripoptions((struct ip *)ti, (struct mbuf *)0);
8a13b737
BJ
50 if (m->m_len < sizeof (struct tcpiphdr)) {
51 if (m_pullup(m, sizeof (struct tcpiphdr)) == 0) {
52 tcpstat.tcps_hdrops++;
53 goto drop;
54 }
55 ti = mtod(m, struct tcpiphdr *);
56 }
87e78f19 57
2b4b57cd
BJ
58 /*
59 * Checksum extended tcp header and data.
60 */
61 tlen = ((struct ip *)ti)->ip_len;
62 len = sizeof (struct ip) + tlen;
60b16fa9 63 if (tcpcksum) {
2b4b57cd
BJ
64 ti->ti_next = ti->ti_prev = 0;
65 ti->ti_x1 = 0;
ac83b17a
BJ
66 ti->ti_len = (u_short)tlen;
67#if vax
68 ti->ti_len = htons(ti->ti_len);
69#endif
8a13b737 70 if ((ti->ti_sum = in_cksum(m, len)) != 0xffff) {
2b4b57cd 71 tcpstat.tcps_badsum++;
2ff61f9d 72 printf("tcp cksum %x\n", ti->ti_sum);
8a13b737 73 goto drop;
87e78f19
BJ
74 }
75 }
76
77 /*
2b4b57cd
BJ
78 * Check that tcp offset makes sense,
79 * process tcp options and adjust length.
87e78f19 80 */
2b4b57cd
BJ
81 off = ti->ti_off << 2;
82 if (off < sizeof (struct tcphdr) || off > ti->ti_len) {
83 tcpstat.tcps_badoff++;
8a13b737 84 goto drop;
2b4b57cd
BJ
85 }
86 ti->ti_len = tlen - off;
8a13b737
BJ
87#if 0
88 if (off > sizeof (struct tcphdr) >> 2)
89 tcp_options(ti);
90#endif
2ff61f9d 91 tiflags = ti->ti_flags;
2b4b57cd 92
8a13b737
BJ
93 /*
94 * Convert tcp protocol specific fields to host format.
95 */
96 ti->ti_seq = ntohl(ti->ti_seq);
97 ti->ti_ack = ntohl(ti->ti_ack);
98 ti->ti_win = ntohs(ti->ti_win);
99 ti->ti_urp = ntohs(ti->ti_urp);
100
2b4b57cd 101 /*
2b4b57cd
BJ
102 * Locate pcb for segment.
103 */
2ff61f9d
BJ
104 inp = in_pcblookup
105 (&tcb, ti->ti_src, ti->ti_sport, ti->ti_dst, ti->ti_dport);
106
107 /*
108 * If the state is CLOSED (i.e., TCB does not exist) then
109 * all data in the incoming segment is discarded. (p. 65).
110 */
53a5409e 111 if (inp == 0)
8a13b737 112 goto dropwithreset;
2ff61f9d
BJ
113 tp = intotcpcb(inp);
114 if (tp == 0)
8a13b737 115 goto dropwithreset;
f1b2fa5b 116 so = inp->inp_socket;
87e78f19 117
405c9168
BJ
118 /*
119 * Segment received on connection.
120 * Reset idle time and keep-alive timer.
121 */
122 tp->t_idle = 0;
123 tp->t_timer[TCPT_KEEP] = TCPTV_KEEP;
124
87e78f19 125 /*
8a13b737
BJ
126 * Calculate amount of space in receive window,
127 * and then do TCP input processing.
87e78f19 128 */
8a13b737 129 tp->rcv_wnd = sbspace(&so->so_rcv);
2ff61f9d 130
87e78f19
BJ
131 switch (tp->t_state) {
132
2ff61f9d
BJ
133 /*
134 * If the state is LISTEN then ignore segment if it contains an RST.
135 * If the segment contains an ACK then it is bad and send a RST.
136 * If it does not contain a SYN then it is not interesting; drop it.
8a13b737 137 * Otherwise initialize tp->rcv_nxt, and tp->irs, select an initial
2ff61f9d 138 * tp->iss, and send a segment:
8a13b737 139 * <SEQ=ISS><ACK=RCV_NXT><CTL=SYN,ACK>
2ff61f9d
BJ
140 * Also initialize tp->snd_nxt to tp->iss+1 and tp->snd_una to tp->iss.
141 * Fill in remote peer address fields if not previously specified.
142 * Enter SYN_RECEIVED state, and process any other fields of this
143 * segment in this state. (p. 65)
144 */
145 case TCPS_LISTEN:
146 if (tiflags & TH_RST)
147 goto drop;
148 if (tiflags & TH_ACK)
8a13b737 149 goto dropwithreset;
2ff61f9d
BJ
150 if ((tiflags & TH_SYN) == 0)
151 goto drop;
8a13b737 152 tp->iss = tcp_iss; tcp_iss += TCP_ISSINCR/2;
2ff61f9d 153 tp->irs = ti->ti_seq;
8a13b737
BJ
154 tcp_sendseqinit(tp);
155 tcp_rcvseqinit(tp);
2ff61f9d 156 tp->t_state = TCPS_SYN_RECEIVED;
2ff61f9d
BJ
157 if (inp->inp_faddr.s_addr == 0) {
158 inp->inp_faddr = ti->ti_src;
159 inp->inp_fport = ti->ti_sport;
87e78f19 160 }
8a13b737 161 goto trimthenstep6;
87e78f19 162
2ff61f9d
BJ
163 /*
164 * If the state is SYN_SENT:
165 * if seg contains an ACK, but not for our SYN, drop the input.
166 * if seg contains a RST, then drop the connection.
167 * if seg does not contain SYN, then drop it.
168 * Otherwise this is an acceptable SYN segment
169 * initialize tp->rcv_nxt and tp->irs
170 * if seg contains ack then advance tp->snd_una
171 * if SYN has been acked change to ESTABLISHED else SYN_RCVD state
172 * arrange for segment to be acked (eventually)
173 * continue processing rest of data/controls, beginning with URG
174 */
175 case TCPS_SYN_SENT:
176 if ((tiflags & TH_ACK) &&
177 (SEQ_LEQ(ti->ti_ack, tp->iss) ||
8a13b737
BJ
178 SEQ_GT(ti->ti_ack, tp->snd_nxt)))
179 goto dropwithreset;
2ff61f9d
BJ
180 if (tiflags & TH_RST) {
181 if (tiflags & TH_ACK)
8a13b737 182 tcp_drop(tp, ECONNRESET);
2ff61f9d 183 goto drop;
87e78f19 184 }
2ff61f9d
BJ
185 if ((tiflags & TH_SYN) == 0)
186 goto drop;
8a13b737
BJ
187 tp->iss = ti->ti_ack;
188 tcp_sendseqinit(tp);
2ff61f9d 189 tp->irs = ti->ti_seq;
8a13b737
BJ
190 tcp_rcvseqinit(tp);
191 tp->t_flags |= TF_ACKNOW;
405c9168 192 if (SEQ_GT(tp->snd_una, tp->iss)) {
2ff61f9d 193 tp->t_state = TCPS_ESTABLISHED;
405c9168
BJ
194 (void) tcp_reass(tp, (struct tcpiphdr *)0);
195 } else
8a13b737
BJ
196 tp->t_state = TCPS_SYN_RECEIVED;
197 goto trimthenstep6;
198
199trimthenstep6:
200 /*
201 * If had syn, advance ti->ti_seq to correspond
202 * to first data byte.
203 */
204 if (tiflags & TH_SYN)
205 ti->ti_seq++;
206
207 /*
208 * If data, trim to stay within window,
209 * dropping FIN if necessary.
210 */
211 if (ti->ti_len > tp->rcv_wnd) {
212 todrop = ti->ti_len - tp->rcv_wnd;
213 m_adj(m, -todrop);
214 ti->ti_len = tp->rcv_wnd;
215 ti->ti_flags &= ~TH_FIN;
87e78f19 216 }
8a13b737 217 goto step6;
2ff61f9d 218 }
87e78f19 219
2ff61f9d
BJ
220 /*
221 * States other than LISTEN or SYN_SENT.
222 * First check that at least some bytes of segment are within
223 * receive window.
224 */
225 if (tp->rcv_wnd == 0) {
226 /*
227 * If window is closed can only take segments at
228 * window edge, and have to drop data and EOL from
229 * incoming segments.
230 */
231 if (tp->rcv_nxt != ti->ti_seq)
232 goto dropafterack;
8a13b737
BJ
233 if (ti->ti_len > 0) {
234 ti->ti_len = 0;
235 ti->ti_flags &= ~(TH_PUSH|TH_FIN);
87e78f19 236 }
2ff61f9d
BJ
237 } else {
238 /*
239 * If segment begins before rcv_next, drop leading
240 * data (and SYN); if nothing left, just ack.
241 */
242 if (SEQ_GT(tp->rcv_nxt, ti->ti_seq)) {
8a13b737
BJ
243 todrop = tp->rcv_nxt - ti->ti_seq;
244 if (tiflags & TH_SYN) {
245 ti->ti_seq++;
246 if (ti->ti_urp > 1)
247 ti->ti_urp--;
248 else
249 tiflags &= ~TH_URG;
250 todrop--;
251 }
2ff61f9d
BJ
252 if (todrop > ti->ti_len)
253 goto dropafterack;
254 m_adj(m, todrop);
255 ti->ti_seq += todrop;
256 ti->ti_len -= todrop;
8a13b737
BJ
257 if (ti->ti_urp > todrop)
258 ti->ti_urp -= todrop;
259 else {
260 tiflags &= ~TH_URG;
261 /* ti->ti_flags &= ~TH_URG; */
262 /* ti->ti_urp = 0; */
263 }
264 /* tiflags &= ~TH_SYN; */
265 /* ti->ti_flags &= ~TH_SYN; */
2ff61f9d
BJ
266 }
267 /*
268 * If segment ends after window, drop trailing data
8a13b737 269 * (and PUSH and FIN); if nothing left, just ACK.
2ff61f9d
BJ
270 */
271 if (SEQ_GT(ti->ti_seq+ti->ti_len, tp->rcv_nxt+tp->rcv_wnd)) {
8a13b737 272 todrop =
2ff61f9d
BJ
273 ti->ti_seq+ti->ti_len - (tp->rcv_nxt+tp->rcv_wnd);
274 if (todrop > ti->ti_len)
275 goto dropafterack;
276 m_adj(m, -todrop);
277 ti->ti_len -= todrop;
8a13b737 278 ti->ti_flags &= ~(TH_PUSH|TH_FIN);
87e78f19 279 }
87e78f19 280 }
87e78f19 281
87e78f19 282 /*
2ff61f9d
BJ
283 * If the RST bit is set examine the state:
284 * SYN_RECEIVED STATE:
285 * If passive open, return to LISTEN state.
286 * If active open, inform user that connection was refused.
287 * ESTABLISHED, FIN_WAIT_1, FIN_WAIT2, CLOSE_WAIT STATES:
288 * Inform user that connection was reset, and close tcb.
289 * CLOSING, LAST_ACK, TIME_WAIT STATES
290 * Close the tcb.
87e78f19 291 */
2ff61f9d
BJ
292 if (tiflags&TH_RST) switch (tp->t_state) {
293
294 case TCPS_SYN_RECEIVED:
295 if (inp->inp_socket->so_options & SO_ACCEPTCONN) {
8a13b737
BJ
296 tp->t_state = TCPS_LISTEN;
297 inp->inp_faddr.s_addr = 0;
2ff61f9d
BJ
298 goto drop;
299 }
8a13b737 300 tcp_drop(tp, ECONNREFUSED);
2ff61f9d
BJ
301 goto drop;
302
303 case TCPS_ESTABLISHED:
304 case TCPS_FIN_WAIT_1:
305 case TCPS_FIN_WAIT_2:
306 case TCPS_CLOSE_WAIT:
307 tcp_drop(tp, ECONNRESET);
308 goto drop;
309
310 case TCPS_CLOSING:
311 case TCPS_LAST_ACK:
312 case TCPS_TIME_WAIT:
313 tcp_close(tp);
314 goto drop;
87e78f19 315 }
87e78f19
BJ
316
317 /*
2ff61f9d
BJ
318 * If a SYN is in the window, then this is an
319 * error and we send an RST and drop the connection.
320 */
321 if (tiflags & TH_SYN) {
8a13b737
BJ
322 tcp_drop(tp, ECONNABORTED);
323 goto dropwithreset;
2ff61f9d
BJ
324 }
325
326 /*
327 * If the ACK bit is off we drop the segment and return.
328 */
8a13b737 329 if ((tiflags & TH_ACK) == 0)
2ff61f9d
BJ
330 goto drop;
331
332 /*
333 * Ack processing.
87e78f19 334 */
87e78f19
BJ
335 switch (tp->t_state) {
336
2ff61f9d
BJ
337 /*
338 * In SYN_RECEIVED state if the ack ACKs our SYN then enter
339 * ESTABLISHED state and continue processing, othewise
340 * send an RST.
341 */
342 case TCPS_SYN_RECEIVED:
8a13b737
BJ
343 if (SEQ_GT(tp->snd_una, ti->ti_ack) ||
344 SEQ_GT(ti->ti_ack, tp->snd_nxt))
345 goto dropwithreset;
346 soisconnected(so);
347 tp->t_state = TCPS_ESTABLISHED;
405c9168 348 (void) tcp_reass(tp, (struct tcpiphdr *)0);
8a13b737 349 /* fall into ... */
87e78f19 350
2ff61f9d
BJ
351 /*
352 * In ESTABLISHED state: drop duplicate ACKs; ACK out of range
353 * ACKs. If the ack is in the range
354 * tp->snd_una < ti->ti_ack <= tp->snd_nxt
355 * then advance tp->snd_una to ti->ti_ack and drop
356 * data from the retransmission queue. If this ACK reflects
357 * more up to date window information we update our window information.
358 */
359 case TCPS_ESTABLISHED:
360 case TCPS_FIN_WAIT_1:
361 case TCPS_FIN_WAIT_2:
362 case TCPS_CLOSE_WAIT:
363 case TCPS_CLOSING:
8a13b737
BJ
364#define ourfinisacked (acked > 0)
365
2ff61f9d
BJ
366 if (SEQ_LT(ti->ti_ack, tp->snd_una))
367 break;
368 if (SEQ_GT(ti->ti_ack, tp->snd_nxt))
369 goto dropafterack;
8a13b737
BJ
370 acked = ti->ti_ack - tp->snd_una;
371 if (acked > so->so_snd.sb_cc) {
372 sbflush(&so->so_snd);
373 acked -= so->so_snd.sb_cc;
405c9168 374 /* if acked our FIN is acked */
8a13b737
BJ
375 } else {
376 sbdrop(&so->so_snd, acked);
377 acked = 0;
378 }
405c9168
BJ
379
380 /*
381 * If transmit timer is running and timed sequence
382 * number was acked, update smoothed round trip time.
383 */
384 if (tp->t_rtt && SEQ_GT(ti->ti_ack, tp->t_rtseq)) {
385 tp->t_srtt =
386 tcp_beta * tp->t_srtt +
387 (1 - tcp_beta) * tp->t_rtt;
388 tp->t_rtt = 0;
389 }
390
2ff61f9d 391 tp->snd_una = ti->ti_ack;
8a13b737
BJ
392
393 /*
394 * Update window information.
395 */
2ff61f9d 396 if (SEQ_LT(tp->snd_wl1, ti->ti_seq) ||
8a13b737 397 tp->snd_wl1==ti->ti_seq && SEQ_LEQ(tp->snd_wl2,ti->ti_seq)) {
2ff61f9d
BJ
398 tp->snd_wnd = ti->ti_win;
399 tp->snd_wl1 = ti->ti_seq;
400 tp->snd_wl2 = ti->ti_ack;
87e78f19 401 }
2ff61f9d 402
87e78f19
BJ
403 switch (tp->t_state) {
404
2ff61f9d
BJ
405 /*
406 * In FIN_WAIT_1 STATE in addition to the processing
407 * for the ESTABLISHED state if our FIN is now acknowledged
8a13b737 408 * then enter FIN_WAIT_2.
2ff61f9d
BJ
409 */
410 case TCPS_FIN_WAIT_1:
8a13b737
BJ
411 if (ourfinisacked)
412 tp->t_state = TCPS_FIN_WAIT_2;
87e78f19
BJ
413 break;
414
2ff61f9d
BJ
415 /*
416 * In CLOSING STATE in addition to the processing for
417 * the ESTABLISHED state if the ACK acknowledges our FIN
418 * then enter the TIME-WAIT state, otherwise ignore
419 * the segment.
420 */
421 case TCPS_CLOSING:
8a13b737 422 if (ourfinisacked)
2ff61f9d 423 tp->t_state = TCPS_TIME_WAIT;
8a13b737 424 goto drop;
87e78f19 425
2ff61f9d 426 /*
8a13b737
BJ
427 * The only thing that can arrive in LAST_ACK state
428 * is an acknowledgment of our FIN. If our FIN is now
429 * acknowledged, delete the TCB, enter the closed state
430 * and return.
2ff61f9d
BJ
431 */
432 case TCPS_LAST_ACK:
8a13b737 433 if (ourfinisacked)
2ff61f9d
BJ
434 tcp_close(tp);
435 goto drop;
87e78f19 436
2ff61f9d
BJ
437 /*
438 * In TIME_WAIT state the only thing that should arrive
439 * is a retransmission of the remote FIN. Acknowledge
440 * it and restart the finack timer.
441 */
442 case TCPS_TIME_WAIT:
405c9168 443 tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL;
2ff61f9d 444 goto dropafterack;
87e78f19 445 }
8a13b737
BJ
446#undef ourfinisacked
447 }
87e78f19 448
2ff61f9d
BJ
449step6:
450 /*
451 * If an URG bit is set in the segment and is greater than the
452 * current known urgent pointer, then signal the user that the
453 * remote side has urgent data. This should not happen
454 * in CLOSE_WAIT, CLOSING, LAST-ACK or TIME_WAIT STATES since
455 * a FIN has been received from the remote side. In these states
456 * we ignore the URG.
457 */
8a13b737
BJ
458 if ((tiflags & TH_URG) == 0 && TCPS_HAVERCVDFIN(tp->t_state) == 0)
459 if (SEQ_GT(ti->ti_urp, tp->rcv_up)) {
2ff61f9d 460 tp->rcv_up = ti->ti_urp;
8a13b737 461#if 0
2ff61f9d 462 soisurgendata(so); /* XXX */
8a13b737 463#endif
87e78f19 464 }
87e78f19
BJ
465
466 /*
2ff61f9d
BJ
467 * Process the segment text, merging it into the TCP sequencing queue,
468 * and arranging for acknowledgment of receipt if necessary.
469 * This process logically involves adjusting tp->rcv_wnd as data
470 * is presented to the user (this happens in tcp_usrreq.c,
471 * case PRU_RCVD). If a FIN has already been received on this
472 * connection then we just ignore the text.
87e78f19 473 */
2ff61f9d 474 if (ti->ti_len) {
8a13b737 475 if (TCPS_HAVERCVDFIN(tp->t_state))
2ff61f9d 476 goto drop;
8a13b737
BJ
477 off += sizeof (struct ip); /* drop IP header */
478 m->m_off += off;
479 m->m_len -= off;
2ff61f9d 480 tiflags = tcp_reass(tp, ti);
8a13b737
BJ
481 tp->t_flags |= TF_ACKNOW; /* XXX TF_DELACK */
482 } else
2b4b57cd 483 m_freem(m);
87e78f19
BJ
484
485 /*
2ff61f9d
BJ
486 * If FIN is received then if we haven't received SYN and
487 * therefore can't validate drop the segment. Otherwise ACK
488 * the FIN and let the user know that the connection is closing.
87e78f19 489 */
8a13b737 490 if ((tiflags & TH_FIN)) {
a6503abf
BJ
491 if (TCPS_HAVERCVDSYN(tp->t_state) == 0)
492 goto drop;
493 socantrcvmore(so);
2ff61f9d
BJ
494 tp->t_flags |= TF_ACKNOW;
495 tp->rcv_nxt++;
496 switch (tp->t_state) {
87e78f19 497
2ff61f9d
BJ
498 /*
499 * In SYN_RECEIVED and ESTABLISHED STATES
500 * enter the CLOSE_WAIT state.
53a5409e 501 */
2ff61f9d
BJ
502 case TCPS_SYN_RECEIVED:
503 case TCPS_ESTABLISHED:
504 tp->t_state = TCPS_CLOSE_WAIT;
505 break;
53a5409e 506
2ff61f9d 507 /*
8a13b737
BJ
508 * If still in FIN_WAIT_1 STATE FIN has not been acked so
509 * enter the CLOSING state.
53a5409e 510 */
2ff61f9d 511 case TCPS_FIN_WAIT_1:
8a13b737 512 tp->t_state = TCPS_CLOSING;
2ff61f9d 513 break;
87e78f19 514
2ff61f9d
BJ
515 /*
516 * In FIN_WAIT_2 state enter the TIME_WAIT state,
517 * starting the time-wait timer, turning off the other
518 * standard timers.
519 */
520 case TCPS_FIN_WAIT_2:
8a13b737 521 tp->t_state = TCPS_TIME_WAIT;;
a6503abf 522 tcp_canceltimers(tp);
405c9168 523 tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL;
2ff61f9d
BJ
524 break;
525
53a5409e 526 /*
2ff61f9d 527 * In TIME_WAIT state restart the 2 MSL time_wait timer.
53a5409e 528 */
2ff61f9d 529 case TCPS_TIME_WAIT:
405c9168 530 tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL;
2ff61f9d 531 break;
8a13b737 532 }
87e78f19 533 }
8a13b737
BJ
534
535 /*
536 * Return any desired output.
537 */
538 tcp_output(tp);
2ff61f9d 539 return;
8a13b737 540
2ff61f9d 541dropafterack:
8a13b737
BJ
542 /*
543 * Generate an ACK, then drop incoming segment.
544 * Make ACK reflect our state.
545 */
546 if (tiflags & TH_RST)
547 goto drop;
548 tcp_respond(ti, tp->rcv_nxt, tp->snd_nxt, TH_ACK);
549 goto drop;
550
551dropwithreset:
552 /*
553 * Generate a RST, then drop incoming segment.
554 * Make ACK acceptable to originator of segment.
555 */
556 if (tiflags & TH_RST)
557 goto drop;
558 if (tiflags & TH_ACK)
f1b2fa5b 559 tcp_respond(ti, (tcp_seq)0, ti->ti_ack, TH_RST);
8a13b737
BJ
560 else {
561 if (tiflags & TH_SYN)
562 ti->ti_len++;
f1b2fa5b 563 tcp_respond(ti, ti->ti_seq+ti->ti_len, (tcp_seq)0, TH_RST|TH_ACK);
8a13b737
BJ
564 }
565 goto drop;
566
2ff61f9d 567drop:
8a13b737
BJ
568 /*
569 * Drop space held by incoming segment and return.
570 */
2ff61f9d 571 m_freem(m);
2ff61f9d
BJ
572}
573
574/*
575 * Insert segment ti into reassembly queue of tcp with
576 * control block tp. Return TH_FIN if reassembly now includes
577 * a segment with FIN.
578 */
f1b2fa5b 579tcp_reass(tp, ti)
2ff61f9d
BJ
580 register struct tcpcb *tp;
581 register struct tcpiphdr *ti;
2ff61f9d
BJ
582{
583 register struct tcpiphdr *q;
8a13b737 584 struct socket *so = tp->t_inpcb->inp_socket;
2ff61f9d 585 int flags = 0; /* no FIN */
8a13b737 586COUNT(TCP_REASS);
2ff61f9d
BJ
587
588 /*
405c9168
BJ
589 * Call with ti==0 after become established to
590 * force pre-ESTABLISHED data up to user socket.
2ff61f9d 591 */
405c9168 592 if (ti == 0)
2ff61f9d 593 goto present;
87e78f19 594
2ff61f9d
BJ
595 /*
596 * Find a segment which begins after this one does.
597 */
598 for (q = tp->seg_next; q != (struct tcpiphdr *)tp;
599 q = (struct tcpiphdr *)q->ti_next)
600 if (SEQ_GT(q->ti_seq, ti->ti_seq))
601 break;
602
603 /*
604 * If there is a preceding segment, it may provide some of
605 * our data already. If so, drop the data from the incoming
606 * segment. If it provides all of our data, drop us.
607 */
608 if ((struct tcpiphdr *)q->ti_prev != (struct tcpiphdr *)tp) {
609 register int i;
610 q = (struct tcpiphdr *)(q->ti_prev);
611 /* conversion to int (in i) handles seq wraparound */
612 i = q->ti_seq + q->ti_len - ti->ti_seq;
613 if (i > 0) {
2b4b57cd 614 if (i >= ti->ti_len)
2ff61f9d
BJ
615 goto drop;
616 m_adj(dtom(tp), i);
2b4b57cd 617 ti->ti_len -= i;
2ff61f9d 618 ti->ti_seq += i;
53a5409e 619 }
2ff61f9d
BJ
620 q = (struct tcpiphdr *)(q->ti_next);
621 }
87e78f19 622
2ff61f9d
BJ
623 /*
624 * While we overlap succeeding segments trim them or,
625 * if they are completely covered, dequeue them.
626 */
627 while (q != (struct tcpiphdr *)tp &&
628 SEQ_GT(ti->ti_seq + ti->ti_len, q->ti_seq)) {
629 register int i = (ti->ti_seq + ti->ti_len) - q->ti_seq;
630 if (i < q->ti_len) {
631 q->ti_len -= i;
632 m_adj(dtom(q), i);
633 break;
ac5e71a1 634 }
2ff61f9d
BJ
635 q = (struct tcpiphdr *)q->ti_next;
636 m_freem(dtom(q->ti_prev));
637 remque(q->ti_prev);
638 }
87e78f19 639
2ff61f9d
BJ
640 /*
641 * Stick new segment in its place.
642 */
643 insque(ti, q->ti_prev);
2ff61f9d
BJ
644
645 /*
646 * Advance rcv_next through newly completed sequence space.
647 */
648 while (ti->ti_seq == tp->rcv_nxt) {
649 tp->rcv_nxt += ti->ti_len;
650 flags = ti->ti_flags & TH_FIN;
651 ti = (struct tcpiphdr *)ti->ti_next;
652 if (ti == (struct tcpiphdr *)tp)
653 break;
60b16fa9 654 }
2ff61f9d
BJ
655
656present:
657 /*
658 * Present data to user.
659 */
8a13b737 660 if (tp->t_state < TCPS_ESTABLISHED)
2ff61f9d 661 return (flags);
2b4b57cd
BJ
662 ti = tp->seg_next;
663 while (ti != (struct tcpiphdr *)tp && ti->ti_seq < tp->rcv_nxt) {
664 remque(ti);
665 sbappend(&so->so_rcv, dtom(ti));
2b4b57cd 666 ti = (struct tcpiphdr *)ti->ti_next;
2a4921ab 667 }
a6503abf
BJ
668 if (so->so_state & SS_CANTRCVMORE)
669 sbflush(&so->so_rcv);
670 else
671 sorwakeup(so);
2ff61f9d
BJ
672 return (flags);
673drop:
674 m_freem(dtom(ti));
675 return (flags);
d52566dd 676}