localize header files
[unix-history] / usr / src / sys / netinet / tcp_input.c
CommitLineData
fcfe450e 1/* tcp_input.c 1.76 82/10/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"
fcfe450e 9#include "../netinet/in.h"
c124e997 10#include "../net/route.h"
fcfe450e
BJ
11#include "../netinet/in_pcb.h"
12#include "../netinet/in_systm.h"
8a13b737 13#include "../net/if.h"
fcfe450e
BJ
14#include "../netinet/ip.h"
15#include "../netinet/ip_var.h"
16#include "../netinet/tcp.h"
17#include "../netinet/tcp_fsm.h"
18#include "../netinet/tcp_seq.h"
19#include "../netinet/tcp_timer.h"
20#include "../netinet/tcp_var.h"
21#include "../netinet/tcpip.h"
22#include "../netinet/tcp_debug.h"
c47a5909 23#include <errno.h>
87e78f19 24
22856bb8 25int tcpprintfs = 0;
60b16fa9 26int tcpcksum = 1;
8075bb0e 27struct mbuf tcp_mb;
4b935108 28struct tcpiphdr tcp_saveti;
8b5a83bb 29extern tcpnodelack;
87e78f19 30
4b935108 31struct tcpcb *tcp_newtcpcb();
2ff61f9d
BJ
32/*
33 * TCP input routine, follows pages 65-76 of the
34 * protocol specification dated September, 1981 very closely.
35 */
2b4b57cd
BJ
36tcp_input(m0)
37 struct mbuf *m0;
87e78f19 38{
2b4b57cd 39 register struct tcpiphdr *ti;
53a5409e 40 struct inpcb *inp;
2b4b57cd 41 register struct mbuf *m;
8b5a83bb 42 struct mbuf *om = 0;
2b4b57cd 43 int len, tlen, off;
8e65fd66 44 register struct tcpcb *tp = 0;
2b4b57cd 45 register int tiflags;
d52566dd 46 struct socket *so;
f1b2fa5b 47 int todrop, acked;
4b935108 48 short ostate;
ebcadd38 49 struct in_addr laddr;
87e78f19
BJ
50
51 /*
4aed14e3
BJ
52 * Get IP and TCP header together in first mbuf.
53 * Note: IP leaves IP header in first mbuf.
87e78f19 54 */
2b4b57cd 55 m = m0;
20790db4 56 ti = mtod(m, struct tcpiphdr *);
4aed14e3 57 if (((struct ip *)ti)->ip_hl > (sizeof (struct ip) >> 2))
d63599ac 58 ip_stripoptions((struct ip *)ti, (struct mbuf *)0);
6703c41f
BJ
59 if (m->m_off > MMAXOFF || m->m_len < sizeof (struct tcpiphdr)) {
60 if ((m = m_pullup(m, sizeof (struct tcpiphdr))) == 0) {
8a13b737 61 tcpstat.tcps_hdrops++;
6703c41f 62 return;
8a13b737
BJ
63 }
64 ti = mtod(m, struct tcpiphdr *);
65 }
87e78f19 66
2b4b57cd 67 /*
4aed14e3 68 * Checksum extended TCP header and data.
2b4b57cd
BJ
69 */
70 tlen = ((struct ip *)ti)->ip_len;
71 len = sizeof (struct ip) + tlen;
60b16fa9 72 if (tcpcksum) {
2b4b57cd
BJ
73 ti->ti_next = ti->ti_prev = 0;
74 ti->ti_x1 = 0;
ac83b17a 75 ti->ti_len = (u_short)tlen;
93f92b1d 76#if vax || pdp11
668cc26d 77 ti->ti_len = htons((u_short)ti->ti_len);
ac83b17a 78#endif
4b6b94ca 79 if (ti->ti_sum = in_cksum(m, len)) {
2b4b57cd 80 tcpstat.tcps_badsum++;
1e977657
BJ
81 if (tcpprintfs)
82 printf("tcp cksum %x\n", ti->ti_sum);
8a13b737 83 goto drop;
87e78f19
BJ
84 }
85 }
86
87 /*
4aed14e3 88 * Check that TCP offset makes sense,
8b5a83bb 89 * pull out TCP options and adjust length.
87e78f19 90 */
2b4b57cd 91 off = ti->ti_off << 2;
4b6b94ca 92 if (off < sizeof (struct tcphdr) || off > tlen) {
2b4b57cd 93 tcpstat.tcps_badoff++;
8a13b737 94 goto drop;
2b4b57cd 95 }
1e977657
BJ
96 tlen -= off;
97 ti->ti_len = tlen;
8b5a83bb
BJ
98 if (off > sizeof (struct tcphdr)) {
99 if ((m = m_pullup(m, sizeof (struct ip) + off)) == 0) {
100 tcpstat.tcps_hdrops++;
101 goto drop;
102 }
103 ti = mtod(m, struct tcpiphdr *);
104 om = m_get(M_DONTWAIT);
105 if (om == 0)
106 goto drop;
8b5a83bb
BJ
107 om->m_len = off - sizeof (struct tcphdr);
108 { caddr_t op = mtod(m, caddr_t) + sizeof (struct tcpiphdr);
668cc26d 109 bcopy(op, mtod(om, caddr_t), (unsigned)om->m_len);
8b5a83bb 110 m->m_len -= om->m_len;
668cc26d
SL
111 bcopy(op+om->m_len, op,
112 (unsigned)(m->m_len-sizeof (struct tcpiphdr)));
8b5a83bb
BJ
113 }
114 }
2ff61f9d 115 tiflags = ti->ti_flags;
2b4b57cd 116
795e0416 117 /*
1e977657 118 * Drop TCP and IP headers.
795e0416
BJ
119 */
120 off += sizeof (struct ip);
121 m->m_off += off;
122 m->m_len -= off;
123
93f92b1d 124#if vax || pdp11
8a13b737 125 /*
4aed14e3 126 * Convert TCP protocol specific fields to host format.
8a13b737
BJ
127 */
128 ti->ti_seq = ntohl(ti->ti_seq);
129 ti->ti_ack = ntohl(ti->ti_ack);
130 ti->ti_win = ntohs(ti->ti_win);
131 ti->ti_urp = ntohs(ti->ti_urp);
4b6b94ca 132#endif
8a13b737 133
2b4b57cd 134 /*
8075bb0e 135 * Locate pcb for segment.
2b4b57cd 136 */
2ff61f9d 137 inp = in_pcblookup
ebcadd38
BJ
138 (&tcb, ti->ti_src, ti->ti_sport, ti->ti_dst, ti->ti_dport,
139 INPLOOKUP_WILDCARD);
2ff61f9d
BJ
140
141 /*
142 * If the state is CLOSED (i.e., TCB does not exist) then
4aed14e3 143 * all data in the incoming segment is discarded.
2ff61f9d 144 */
22856bb8 145 if (inp == 0)
8a13b737 146 goto dropwithreset;
2ff61f9d 147 tp = intotcpcb(inp);
22856bb8 148 if (tp == 0)
8a13b737 149 goto dropwithreset;
f1b2fa5b 150 so = inp->inp_socket;
4b935108
BJ
151 if (so->so_options & SO_DEBUG) {
152 ostate = tp->t_state;
153 tcp_saveti = *ti;
154 }
ebf42a75
BJ
155 if (so->so_options & SO_ACCEPTCONN) {
156 so = sonewconn(so);
157 if (so == 0)
158 goto drop;
159 inp = (struct inpcb *)so->so_pcb;
160 inp->inp_laddr = ti->ti_dst;
161 inp->inp_lport = ti->ti_dport;
162 tp = intotcpcb(inp);
163 tp->t_state = TCPS_LISTEN;
164 }
87e78f19 165
405c9168
BJ
166 /*
167 * Segment received on connection.
168 * Reset idle time and keep-alive timer.
169 */
170 tp->t_idle = 0;
171 tp->t_timer[TCPT_KEEP] = TCPTV_KEEP;
172
8b5a83bb
BJ
173 /*
174 * Process options.
175 */
176 if (om) {
177 tcp_dooptions(tp, om);
178 om = 0;
179 }
180
87e78f19 181 /*
8a13b737
BJ
182 * Calculate amount of space in receive window,
183 * and then do TCP input processing.
87e78f19 184 */
8a13b737 185 tp->rcv_wnd = sbspace(&so->so_rcv);
4b6b94ca
BJ
186 if (tp->rcv_wnd < 0)
187 tp->rcv_wnd = 0;
2ff61f9d 188
87e78f19
BJ
189 switch (tp->t_state) {
190
2ff61f9d
BJ
191 /*
192 * If the state is LISTEN then ignore segment if it contains an RST.
193 * If the segment contains an ACK then it is bad and send a RST.
194 * If it does not contain a SYN then it is not interesting; drop it.
8a13b737 195 * Otherwise initialize tp->rcv_nxt, and tp->irs, select an initial
2ff61f9d 196 * tp->iss, and send a segment:
8a13b737 197 * <SEQ=ISS><ACK=RCV_NXT><CTL=SYN,ACK>
2ff61f9d
BJ
198 * Also initialize tp->snd_nxt to tp->iss+1 and tp->snd_una to tp->iss.
199 * Fill in remote peer address fields if not previously specified.
200 * Enter SYN_RECEIVED state, and process any other fields of this
4aed14e3 201 * segment in this state.
2ff61f9d 202 */
8075bb0e
BJ
203 case TCPS_LISTEN: {
204 struct mbuf *m = m_get(M_DONTWAIT);
205 register struct sockaddr_in *sin;
206
207 if (m == 0)
208 goto drop;
8075bb0e 209 m->m_len = sizeof (struct sockaddr_in);
2ff61f9d
BJ
210 if (tiflags & TH_RST)
211 goto drop;
22856bb8 212 if (tiflags & TH_ACK)
8a13b737 213 goto dropwithreset;
22856bb8 214 if ((tiflags & TH_SYN) == 0)
2ff61f9d 215 goto drop;
8075bb0e
BJ
216 sin = mtod(m, struct sockaddr_in *);
217 sin->sin_family = AF_INET;
218 sin->sin_addr = ti->ti_src;
219 sin->sin_port = ti->ti_sport;
ebcadd38
BJ
220 laddr = inp->inp_laddr;
221 if (inp->inp_laddr.s_addr == 0)
222 inp->inp_laddr = ti->ti_dst;
8075bb0e 223 if (in_pcbconnect(inp, m)) {
ebcadd38 224 inp->inp_laddr = laddr;
8075bb0e 225 m_free(m);
4aed14e3 226 goto drop;
ebcadd38 227 }
8075bb0e 228 m_free(m);
4aed14e3
BJ
229 tp->t_template = tcp_template(tp);
230 if (tp->t_template == 0) {
231 in_pcbdisconnect(inp);
ebcadd38 232 inp->inp_laddr = laddr;
93f92b1d 233 tp = 0;
4aed14e3
BJ
234 goto drop;
235 }
8a13b737 236 tp->iss = tcp_iss; tcp_iss += TCP_ISSINCR/2;
2ff61f9d 237 tp->irs = ti->ti_seq;
8a13b737
BJ
238 tcp_sendseqinit(tp);
239 tcp_rcvseqinit(tp);
2ff61f9d 240 tp->t_state = TCPS_SYN_RECEIVED;
4aed14e3 241 tp->t_timer[TCPT_KEEP] = TCPTV_KEEP;
8a13b737 242 goto trimthenstep6;
8075bb0e 243 }
87e78f19 244
2ff61f9d
BJ
245 /*
246 * If the state is SYN_SENT:
247 * if seg contains an ACK, but not for our SYN, drop the input.
248 * if seg contains a RST, then drop the connection.
249 * if seg does not contain SYN, then drop it.
250 * Otherwise this is an acceptable SYN segment
251 * initialize tp->rcv_nxt and tp->irs
252 * if seg contains ack then advance tp->snd_una
253 * if SYN has been acked change to ESTABLISHED else SYN_RCVD state
254 * arrange for segment to be acked (eventually)
255 * continue processing rest of data/controls, beginning with URG
256 */
257 case TCPS_SYN_SENT:
258 if ((tiflags & TH_ACK) &&
22856bb8
BJ
259/* this should be SEQ_LT; is SEQ_LEQ for BBN vax TCP only */
260 (SEQ_LT(ti->ti_ack, tp->iss) ||
4b6b94ca 261 SEQ_GT(ti->ti_ack, tp->snd_max)))
8a13b737 262 goto dropwithreset;
2ff61f9d 263 if (tiflags & TH_RST) {
93f92b1d 264 if (tiflags & TH_ACK) {
4b935108 265 tcp_drop(tp, ECONNREFUSED);
93f92b1d
BJ
266 tp = 0;
267 }
2ff61f9d 268 goto drop;
87e78f19 269 }
2ff61f9d
BJ
270 if ((tiflags & TH_SYN) == 0)
271 goto drop;
4b6b94ca 272 tp->snd_una = ti->ti_ack;
b8977237
BJ
273 if (SEQ_LT(tp->snd_nxt, tp->snd_una))
274 tp->snd_nxt = tp->snd_una;
4aed14e3 275 tp->t_timer[TCPT_REXMT] = 0;
2ff61f9d 276 tp->irs = ti->ti_seq;
8a13b737
BJ
277 tcp_rcvseqinit(tp);
278 tp->t_flags |= TF_ACKNOW;
405c9168 279 if (SEQ_GT(tp->snd_una, tp->iss)) {
4aed14e3 280 soisconnected(so);
2ff61f9d 281 tp->t_state = TCPS_ESTABLISHED;
405c9168
BJ
282 (void) tcp_reass(tp, (struct tcpiphdr *)0);
283 } else
8a13b737
BJ
284 tp->t_state = TCPS_SYN_RECEIVED;
285 goto trimthenstep6;
286
287trimthenstep6:
288 /*
4b6b94ca 289 * Advance ti->ti_seq to correspond to first data byte.
8a13b737
BJ
290 * If data, trim to stay within window,
291 * dropping FIN if necessary.
292 */
4b6b94ca 293 ti->ti_seq++;
8a13b737
BJ
294 if (ti->ti_len > tp->rcv_wnd) {
295 todrop = ti->ti_len - tp->rcv_wnd;
296 m_adj(m, -todrop);
297 ti->ti_len = tp->rcv_wnd;
298 ti->ti_flags &= ~TH_FIN;
87e78f19 299 }
e832edbc 300 tp->snd_wl1 = ti->ti_seq - 1;
8a13b737 301 goto step6;
2ff61f9d 302 }
87e78f19 303
2ff61f9d
BJ
304 /*
305 * States other than LISTEN or SYN_SENT.
306 * First check that at least some bytes of segment are within
307 * receive window.
308 */
309 if (tp->rcv_wnd == 0) {
310 /*
311 * If window is closed can only take segments at
4b6b94ca 312 * window edge, and have to drop data and PUSH from
2ff61f9d
BJ
313 * incoming segments.
314 */
22856bb8 315 if (tp->rcv_nxt != ti->ti_seq)
2ff61f9d 316 goto dropafterack;
8a13b737 317 if (ti->ti_len > 0) {
fd5dc5f0 318 m_adj(m, ti->ti_len);
8a13b737
BJ
319 ti->ti_len = 0;
320 ti->ti_flags &= ~(TH_PUSH|TH_FIN);
87e78f19 321 }
2ff61f9d
BJ
322 } else {
323 /*
4b6b94ca 324 * If segment begins before rcv_nxt, drop leading
2ff61f9d
BJ
325 * data (and SYN); if nothing left, just ack.
326 */
fd5dc5f0
BJ
327 todrop = tp->rcv_nxt - ti->ti_seq;
328 if (todrop > 0) {
8a13b737 329 if (tiflags & TH_SYN) {
22856bb8 330 tiflags &= ~TH_SYN;
fd5dc5f0 331 ti->ti_flags &= ~TH_SYN;
8a13b737
BJ
332 ti->ti_seq++;
333 if (ti->ti_urp > 1)
334 ti->ti_urp--;
335 else
336 tiflags &= ~TH_URG;
337 todrop--;
338 }
1e977657
BJ
339 if (todrop > ti->ti_len ||
340 todrop == ti->ti_len && (tiflags&TH_FIN) == 0)
2ff61f9d
BJ
341 goto dropafterack;
342 m_adj(m, todrop);
343 ti->ti_seq += todrop;
344 ti->ti_len -= todrop;
8a13b737
BJ
345 if (ti->ti_urp > todrop)
346 ti->ti_urp -= todrop;
347 else {
348 tiflags &= ~TH_URG;
fd5dc5f0
BJ
349 ti->ti_flags &= ~TH_URG;
350 ti->ti_urp = 0;
8a13b737 351 }
2ff61f9d
BJ
352 }
353 /*
354 * If segment ends after window, drop trailing data
8a13b737 355 * (and PUSH and FIN); if nothing left, just ACK.
2ff61f9d 356 */
fd5dc5f0
BJ
357 todrop = (ti->ti_seq+ti->ti_len) - (tp->rcv_nxt+tp->rcv_wnd);
358 if (todrop > 0) {
1e977657 359 if (todrop >= ti->ti_len)
2ff61f9d
BJ
360 goto dropafterack;
361 m_adj(m, -todrop);
362 ti->ti_len -= todrop;
8a13b737 363 ti->ti_flags &= ~(TH_PUSH|TH_FIN);
87e78f19 364 }
87e78f19 365 }
87e78f19 366
dd020fc8
BJ
367 /*
368 * If a segment is received on a connection after the
369 * user processes are gone, then RST the other end.
370 */
ebf42a75 371 if (so->so_state & SS_NOFDREF) {
dd020fc8 372 tcp_close(tp);
9d0b428a 373 tp = 0;
dd020fc8
BJ
374 goto dropwithreset;
375 }
376
87e78f19 377 /*
2ff61f9d
BJ
378 * If the RST bit is set examine the state:
379 * SYN_RECEIVED STATE:
380 * If passive open, return to LISTEN state.
381 * If active open, inform user that connection was refused.
382 * ESTABLISHED, FIN_WAIT_1, FIN_WAIT2, CLOSE_WAIT STATES:
383 * Inform user that connection was reset, and close tcb.
384 * CLOSING, LAST_ACK, TIME_WAIT STATES
385 * Close the tcb.
87e78f19 386 */
2ff61f9d 387 if (tiflags&TH_RST) switch (tp->t_state) {
4b935108 388
2ff61f9d 389 case TCPS_SYN_RECEIVED:
8a13b737 390 tcp_drop(tp, ECONNREFUSED);
93f92b1d 391 tp = 0;
2ff61f9d
BJ
392 goto drop;
393
394 case TCPS_ESTABLISHED:
395 case TCPS_FIN_WAIT_1:
396 case TCPS_FIN_WAIT_2:
397 case TCPS_CLOSE_WAIT:
398 tcp_drop(tp, ECONNRESET);
93f92b1d 399 tp = 0;
2ff61f9d
BJ
400 goto drop;
401
402 case TCPS_CLOSING:
403 case TCPS_LAST_ACK:
404 case TCPS_TIME_WAIT:
405 tcp_close(tp);
93f92b1d 406 tp = 0;
2ff61f9d 407 goto drop;
87e78f19 408 }
87e78f19
BJ
409
410 /*
2ff61f9d
BJ
411 * If a SYN is in the window, then this is an
412 * error and we send an RST and drop the connection.
413 */
414 if (tiflags & TH_SYN) {
4b6b94ca 415 tcp_drop(tp, ECONNRESET);
9d0b428a 416 tp = 0;
8a13b737 417 goto dropwithreset;
2ff61f9d
BJ
418 }
419
420 /*
421 * If the ACK bit is off we drop the segment and return.
422 */
8a13b737 423 if ((tiflags & TH_ACK) == 0)
2ff61f9d
BJ
424 goto drop;
425
426 /*
427 * Ack processing.
87e78f19 428 */
87e78f19
BJ
429 switch (tp->t_state) {
430
2ff61f9d
BJ
431 /*
432 * In SYN_RECEIVED state if the ack ACKs our SYN then enter
433 * ESTABLISHED state and continue processing, othewise
434 * send an RST.
435 */
436 case TCPS_SYN_RECEIVED:
8a13b737 437 if (SEQ_GT(tp->snd_una, ti->ti_ack) ||
4b6b94ca 438 SEQ_GT(ti->ti_ack, tp->snd_max))
8a13b737 439 goto dropwithreset;
4aed14e3 440 tp->snd_una++; /* SYN acked */
b8977237
BJ
441 if (SEQ_LT(tp->snd_nxt, tp->snd_una))
442 tp->snd_nxt = tp->snd_una;
4aed14e3 443 tp->t_timer[TCPT_REXMT] = 0;
8a13b737
BJ
444 soisconnected(so);
445 tp->t_state = TCPS_ESTABLISHED;
405c9168 446 (void) tcp_reass(tp, (struct tcpiphdr *)0);
4aed14e3 447 tp->snd_wl1 = ti->ti_seq - 1;
8a13b737 448 /* fall into ... */
87e78f19 449
2ff61f9d
BJ
450 /*
451 * In ESTABLISHED state: drop duplicate ACKs; ACK out of range
452 * ACKs. If the ack is in the range
4b6b94ca 453 * tp->snd_una < ti->ti_ack <= tp->snd_max
2ff61f9d
BJ
454 * then advance tp->snd_una to ti->ti_ack and drop
455 * data from the retransmission queue. If this ACK reflects
456 * more up to date window information we update our window information.
457 */
458 case TCPS_ESTABLISHED:
459 case TCPS_FIN_WAIT_1:
460 case TCPS_FIN_WAIT_2:
461 case TCPS_CLOSE_WAIT:
462 case TCPS_CLOSING:
4aed14e3
BJ
463 case TCPS_LAST_ACK:
464 case TCPS_TIME_WAIT:
8a13b737
BJ
465#define ourfinisacked (acked > 0)
466
4aed14e3 467 if (SEQ_LEQ(ti->ti_ack, tp->snd_una))
2ff61f9d 468 break;
22856bb8 469 if (SEQ_GT(ti->ti_ack, tp->snd_max))
2ff61f9d 470 goto dropafterack;
8a13b737 471 acked = ti->ti_ack - tp->snd_una;
dd020fc8
BJ
472
473 /*
474 * If transmit timer is running and timed sequence
475 * number was acked, update smoothed round trip time.
476 */
477 if (tp->t_rtt && SEQ_GT(ti->ti_ack, tp->t_rtseq)) {
478 if (tp->t_srtt == 0)
479 tp->t_srtt = tp->t_rtt;
480 else
481 tp->t_srtt =
482 tcp_alpha * tp->t_srtt +
483 (1 - tcp_alpha) * tp->t_rtt;
484/* printf("rtt %d srtt*100 now %d\n", tp->t_rtt, (int)(tp->t_srtt*100)); */
485 tp->t_rtt = 0;
486 }
487
6703c41f 488 if (ti->ti_ack == tp->snd_max)
4aed14e3 489 tp->t_timer[TCPT_REXMT] = 0;
6703c41f 490 else {
4aed14e3
BJ
491 TCPT_RANGESET(tp->t_timer[TCPT_REXMT],
492 tcp_beta * tp->t_srtt, TCPTV_MIN, TCPTV_MAX);
dd020fc8 493 tp->t_rtt = 1;
22856bb8 494 tp->t_rxtshift = 0;
8a13b737 495 }
6703c41f
BJ
496 if (acked > so->so_snd.sb_cc) {
497 sbdrop(&so->so_snd, so->so_snd.sb_cc);
498 tp->snd_wnd -= so->so_snd.sb_cc;
499 } else {
668cc26d 500 sbdrop(&so->so_snd, acked);
6703c41f
BJ
501 tp->snd_wnd -= acked;
502 acked = 0;
503 }
5744ed2b 504 if ((so->so_snd.sb_flags & SB_WAIT) || so->so_snd.sb_sel)
22856bb8 505 sowwakeup(so);
4b6b94ca 506 tp->snd_una = ti->ti_ack;
b8977237
BJ
507 if (SEQ_LT(tp->snd_nxt, tp->snd_una))
508 tp->snd_nxt = tp->snd_una;
405c9168 509
87e78f19
BJ
510 switch (tp->t_state) {
511
2ff61f9d
BJ
512 /*
513 * In FIN_WAIT_1 STATE in addition to the processing
514 * for the ESTABLISHED state if our FIN is now acknowledged
8a13b737 515 * then enter FIN_WAIT_2.
2ff61f9d
BJ
516 */
517 case TCPS_FIN_WAIT_1:
fdae4427
BJ
518 if (ourfinisacked) {
519 /*
520 * If we can't receive any more
521 * data, then closing user can proceed.
522 */
523 if (so->so_state & SS_CANTRCVMORE)
524 soisdisconnected(so);
8a13b737 525 tp->t_state = TCPS_FIN_WAIT_2;
fdae4427 526 }
87e78f19
BJ
527 break;
528
2ff61f9d
BJ
529 /*
530 * In CLOSING STATE in addition to the processing for
531 * the ESTABLISHED state if the ACK acknowledges our FIN
532 * then enter the TIME-WAIT state, otherwise ignore
533 * the segment.
534 */
535 case TCPS_CLOSING:
4aed14e3 536 if (ourfinisacked) {
2ff61f9d 537 tp->t_state = TCPS_TIME_WAIT;
4aed14e3
BJ
538 tcp_canceltimers(tp);
539 tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL;
540 soisdisconnected(so);
541 }
542 break;
87e78f19 543
2ff61f9d 544 /*
8a13b737
BJ
545 * The only thing that can arrive in LAST_ACK state
546 * is an acknowledgment of our FIN. If our FIN is now
547 * acknowledged, delete the TCB, enter the closed state
548 * and return.
2ff61f9d
BJ
549 */
550 case TCPS_LAST_ACK:
93f92b1d 551 if (ourfinisacked) {
2ff61f9d 552 tcp_close(tp);
93f92b1d
BJ
553 tp = 0;
554 }
2ff61f9d 555 goto drop;
87e78f19 556
2ff61f9d
BJ
557 /*
558 * In TIME_WAIT state the only thing that should arrive
559 * is a retransmission of the remote FIN. Acknowledge
560 * it and restart the finack timer.
561 */
562 case TCPS_TIME_WAIT:
405c9168 563 tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL;
2ff61f9d 564 goto dropafterack;
87e78f19 565 }
8a13b737
BJ
566#undef ourfinisacked
567 }
87e78f19 568
2ff61f9d 569step6:
4aed14e3
BJ
570 /*
571 * Update window information.
572 */
22856bb8 573 if (SEQ_LT(tp->snd_wl1, ti->ti_seq) || tp->snd_wl1 == ti->ti_seq &&
8e65fd66 574 (SEQ_LT(tp->snd_wl2, ti->ti_ack) ||
22856bb8 575 tp->snd_wl2 == ti->ti_ack && ti->ti_win > tp->snd_wnd)) {
4aed14e3
BJ
576 tp->snd_wnd = ti->ti_win;
577 tp->snd_wl1 = ti->ti_seq;
578 tp->snd_wl2 = ti->ti_ack;
579 if (tp->snd_wnd > 0)
580 tp->t_timer[TCPT_PERSIST] = 0;
581 }
4aed14e3 582
2ff61f9d 583 /*
b2db9217 584 * Process segments with URG.
2ff61f9d 585 */
9c811062
BJ
586 if ((tiflags & TH_URG) && ti->ti_urp &&
587 TCPS_HAVERCVDFIN(tp->t_state) == 0) {
b2db9217
BJ
588 /*
589 * If this segment advances the known urgent pointer,
590 * then mark the data stream. This should not happen
591 * in CLOSE_WAIT, CLOSING, LAST_ACK or TIME_WAIT STATES since
592 * a FIN has been received from the remote side.
593 * In these states we ignore the URG.
594 */
595 if (SEQ_GT(ti->ti_seq+ti->ti_urp, tp->rcv_up)) {
596 tp->rcv_up = ti->ti_seq + ti->ti_urp;
597 so->so_oobmark = so->so_rcv.sb_cc +
598 (tp->rcv_up - tp->rcv_nxt) - 1;
599 if (so->so_oobmark == 0)
600 so->so_state |= SS_RCVATMARK;
77a4e3ca 601 sohasoutofband(so);
b2db9217
BJ
602 tp->t_oobflags &= ~TCPOOB_HAVEDATA;
603 }
604 /*
605 * Remove out of band data so doesn't get presented to user.
606 * This can happen independent of advancing the URG pointer,
607 * but if two URG's are pending at once, some out-of-band
608 * data may creep in... ick.
609 */
ebf42a75 610 if (ti->ti_urp <= ti->ti_len)
b2db9217 611 tcp_pulloutofband(so, ti);
5e74df82 612 }
87e78f19
BJ
613
614 /*
2ff61f9d
BJ
615 * Process the segment text, merging it into the TCP sequencing queue,
616 * and arranging for acknowledgment of receipt if necessary.
617 * This process logically involves adjusting tp->rcv_wnd as data
618 * is presented to the user (this happens in tcp_usrreq.c,
619 * case PRU_RCVD). If a FIN has already been received on this
620 * connection then we just ignore the text.
87e78f19 621 */
e832edbc
BJ
622 if ((ti->ti_len || (tiflags&TH_FIN)) &&
623 TCPS_HAVERCVDFIN(tp->t_state) == 0) {
2ff61f9d 624 tiflags = tcp_reass(tp, ti);
8b5a83bb
BJ
625 if (tcpnodelack == 0)
626 tp->t_flags |= TF_DELACK;
627 else
628 tp->t_flags |= TF_ACKNOW;
4aed14e3 629 } else {
2b4b57cd 630 m_freem(m);
e832edbc 631 tiflags &= ~TH_FIN;
4aed14e3 632 }
87e78f19
BJ
633
634 /*
e832edbc
BJ
635 * If FIN is received ACK the FIN and let the user know
636 * that the connection is closing.
87e78f19 637 */
e832edbc 638 if (tiflags & TH_FIN) {
4aed14e3
BJ
639 if (TCPS_HAVERCVDFIN(tp->t_state) == 0) {
640 socantrcvmore(so);
641 tp->t_flags |= TF_ACKNOW;
642 tp->rcv_nxt++;
643 }
2ff61f9d 644 switch (tp->t_state) {
87e78f19 645
2ff61f9d
BJ
646 /*
647 * In SYN_RECEIVED and ESTABLISHED STATES
648 * enter the CLOSE_WAIT state.
53a5409e 649 */
2ff61f9d
BJ
650 case TCPS_SYN_RECEIVED:
651 case TCPS_ESTABLISHED:
652 tp->t_state = TCPS_CLOSE_WAIT;
653 break;
53a5409e 654
2ff61f9d 655 /*
8a13b737
BJ
656 * If still in FIN_WAIT_1 STATE FIN has not been acked so
657 * enter the CLOSING state.
53a5409e 658 */
2ff61f9d 659 case TCPS_FIN_WAIT_1:
8a13b737 660 tp->t_state = TCPS_CLOSING;
2ff61f9d 661 break;
87e78f19 662
2ff61f9d
BJ
663 /*
664 * In FIN_WAIT_2 state enter the TIME_WAIT state,
665 * starting the time-wait timer, turning off the other
666 * standard timers.
667 */
668 case TCPS_FIN_WAIT_2:
4aed14e3 669 tp->t_state = TCPS_TIME_WAIT;
a6503abf 670 tcp_canceltimers(tp);
405c9168 671 tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL;
4aed14e3 672 soisdisconnected(so);
2ff61f9d
BJ
673 break;
674
53a5409e 675 /*
2ff61f9d 676 * In TIME_WAIT state restart the 2 MSL time_wait timer.
53a5409e 677 */
2ff61f9d 678 case TCPS_TIME_WAIT:
405c9168 679 tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL;
2ff61f9d 680 break;
8a13b737 681 }
87e78f19 682 }
4b935108
BJ
683 if (so->so_options & SO_DEBUG)
684 tcp_trace(TA_INPUT, ostate, tp, &tcp_saveti, 0);
8a13b737
BJ
685
686 /*
687 * Return any desired output.
688 */
668cc26d 689 (void) tcp_output(tp);
2ff61f9d 690 return;
8a13b737 691
2ff61f9d 692dropafterack:
8a13b737 693 /*
1e977657
BJ
694 * Generate an ACK dropping incoming segment if it occupies
695 * sequence space, where the ACK reflects our state.
8a13b737 696 */
1e977657
BJ
697 if ((tiflags&TH_RST) ||
698 tlen == 0 && (tiflags&(TH_SYN|TH_FIN)) == 0)
8a13b737 699 goto drop;
f3cdd721
BJ
700 if (tp->t_inpcb->inp_socket->so_options & SO_DEBUG)
701 tcp_trace(TA_RESPOND, ostate, tp, &tcp_saveti, 0);
8e65fd66 702 tcp_respond(tp, ti, tp->rcv_nxt, tp->snd_nxt, TH_ACK);
4b6b94ca 703 return;
8a13b737
BJ
704
705dropwithreset:
8b5a83bb 706 if (om)
668cc26d 707 (void) m_free(om);
8a13b737 708 /*
4aed14e3 709 * Generate a RST, dropping incoming segment.
8a13b737
BJ
710 * Make ACK acceptable to originator of segment.
711 */
712 if (tiflags & TH_RST)
713 goto drop;
714 if (tiflags & TH_ACK)
8e65fd66 715 tcp_respond(tp, ti, (tcp_seq)0, ti->ti_ack, TH_RST);
8a13b737
BJ
716 else {
717 if (tiflags & TH_SYN)
718 ti->ti_len++;
1e977657
BJ
719 tcp_respond(tp, ti, ti->ti_seq+ti->ti_len, (tcp_seq)0,
720 TH_RST|TH_ACK);
8a13b737 721 }
4b6b94ca 722 return;
8a13b737 723
2ff61f9d 724drop:
8a13b737
BJ
725 /*
726 * Drop space held by incoming segment and return.
727 */
f3cdd721
BJ
728 if (tp && (tp->t_inpcb->inp_socket->so_options & SO_DEBUG))
729 tcp_trace(TA_DROP, ostate, tp, &tcp_saveti, 0);
2ff61f9d 730 m_freem(m);
4b935108 731 return;
2ff61f9d
BJ
732}
733
8b5a83bb
BJ
734tcp_dooptions(tp, om)
735 struct tcpcb *tp;
736 struct mbuf *om;
5e74df82 737{
8b5a83bb
BJ
738 register u_char *cp;
739 int opt, optlen, cnt;
740
741 cp = mtod(om, u_char *);
742 cnt = om->m_len;
743 for (; cnt > 0; cnt -= optlen, cp += optlen) {
744 opt = cp[0];
745 if (opt == TCPOPT_EOL)
746 break;
747 if (opt == TCPOPT_NOP)
748 optlen = 1;
749 else
750 optlen = cp[1];
751 switch (opt) {
752
753 default:
754 break;
755
756 case TCPOPT_MAXSEG:
757 if (optlen != 4)
758 continue;
759 tp->t_maxseg = *(u_short *)(cp + 2);
93f92b1d 760#if vax || pdp11
668cc26d 761 tp->t_maxseg = ntohs((u_short)tp->t_maxseg);
8b5a83bb
BJ
762#endif
763 break;
8b5a83bb 764 }
5e74df82 765 }
668cc26d 766 (void) m_free(om);
5e74df82
BJ
767}
768
b2db9217
BJ
769/*
770 * Pull out of band byte out of a segment so
771 * it doesn't appear in the user's data queue.
772 * It is still reflected in the segment length for
773 * sequencing purposes.
774 */
775tcp_pulloutofband(so, ti)
776 struct socket *so;
777 struct tcpiphdr *ti;
778{
779 register struct mbuf *m;
1acff8ec 780 int cnt = ti->ti_urp - 1;
b2db9217
BJ
781
782 m = dtom(ti);
783 while (cnt >= 0) {
784 if (m->m_len > cnt) {
785 char *cp = mtod(m, caddr_t) + cnt;
786 struct tcpcb *tp = sototcpcb(so);
787
788 tp->t_iobc = *cp;
789 tp->t_oobflags |= TCPOOB_HAVEDATA;
668cc26d 790 bcopy(cp+1, cp, (unsigned)(m->m_len - cnt - 1));
b2db9217
BJ
791 m->m_len--;
792 return;
793 }
794 cnt -= m->m_len;
795 m = m->m_next;
796 if (m == 0)
797 break;
798 }
799 panic("tcp_pulloutofband");
800}
801
2ff61f9d
BJ
802/*
803 * Insert segment ti into reassembly queue of tcp with
804 * control block tp. Return TH_FIN if reassembly now includes
805 * a segment with FIN.
806 */
f1b2fa5b 807tcp_reass(tp, ti)
2ff61f9d
BJ
808 register struct tcpcb *tp;
809 register struct tcpiphdr *ti;
2ff61f9d
BJ
810{
811 register struct tcpiphdr *q;
8a13b737 812 struct socket *so = tp->t_inpcb->inp_socket;
e832edbc
BJ
813 struct mbuf *m;
814 int flags;
2ff61f9d
BJ
815
816 /*
405c9168
BJ
817 * Call with ti==0 after become established to
818 * force pre-ESTABLISHED data up to user socket.
2ff61f9d 819 */
405c9168 820 if (ti == 0)
2ff61f9d 821 goto present;
87e78f19 822
2ff61f9d
BJ
823 /*
824 * Find a segment which begins after this one does.
825 */
826 for (q = tp->seg_next; q != (struct tcpiphdr *)tp;
827 q = (struct tcpiphdr *)q->ti_next)
828 if (SEQ_GT(q->ti_seq, ti->ti_seq))
829 break;
830
831 /*
832 * If there is a preceding segment, it may provide some of
833 * our data already. If so, drop the data from the incoming
834 * segment. If it provides all of our data, drop us.
835 */
836 if ((struct tcpiphdr *)q->ti_prev != (struct tcpiphdr *)tp) {
837 register int i;
fd5dc5f0 838 q = (struct tcpiphdr *)q->ti_prev;
2ff61f9d
BJ
839 /* conversion to int (in i) handles seq wraparound */
840 i = q->ti_seq + q->ti_len - ti->ti_seq;
841 if (i > 0) {
2b4b57cd 842 if (i >= ti->ti_len)
2ff61f9d 843 goto drop;
4ab1a5c3 844 m_adj(dtom(ti), i);
2b4b57cd 845 ti->ti_len -= i;
2ff61f9d 846 ti->ti_seq += i;
53a5409e 847 }
2ff61f9d
BJ
848 q = (struct tcpiphdr *)(q->ti_next);
849 }
87e78f19 850
2ff61f9d
BJ
851 /*
852 * While we overlap succeeding segments trim them or,
853 * if they are completely covered, dequeue them.
854 */
fd5dc5f0 855 while (q != (struct tcpiphdr *)tp) {
2ff61f9d 856 register int i = (ti->ti_seq + ti->ti_len) - q->ti_seq;
fd5dc5f0
BJ
857 if (i <= 0)
858 break;
2ff61f9d 859 if (i < q->ti_len) {
fd5dc5f0 860 q->ti_seq += i;
2ff61f9d
BJ
861 q->ti_len -= i;
862 m_adj(dtom(q), i);
863 break;
ac5e71a1 864 }
2ff61f9d 865 q = (struct tcpiphdr *)q->ti_next;
473a17a5 866 m = dtom(q->ti_prev);
2ff61f9d 867 remque(q->ti_prev);
473a17a5 868 m_freem(m);
2ff61f9d 869 }
87e78f19 870
2ff61f9d
BJ
871 /*
872 * Stick new segment in its place.
873 */
874 insque(ti, q->ti_prev);
2ff61f9d 875
2ff61f9d
BJ
876present:
877 /*
4aed14e3
BJ
878 * Present data to user, advancing rcv_nxt through
879 * completed sequence space.
2ff61f9d 880 */
e832edbc 881 if (TCPS_HAVERCVDSYN(tp->t_state) == 0)
4aed14e3 882 return (0);
2b4b57cd 883 ti = tp->seg_next;
e832edbc
BJ
884 if (ti == (struct tcpiphdr *)tp || ti->ti_seq != tp->rcv_nxt)
885 return (0);
886 if (tp->t_state == TCPS_SYN_RECEIVED && ti->ti_len)
887 return (0);
888 do {
4aed14e3
BJ
889 tp->rcv_nxt += ti->ti_len;
890 flags = ti->ti_flags & TH_FIN;
2b4b57cd 891 remque(ti);
e832edbc 892 m = dtom(ti);
2b4b57cd 893 ti = (struct tcpiphdr *)ti->ti_next;
e832edbc 894 if (so->so_state & SS_CANTRCVMORE)
668cc26d 895 m_freem(m);
e832edbc
BJ
896 else
897 sbappend(&so->so_rcv, m);
898 } while (ti != (struct tcpiphdr *)tp && ti->ti_seq == tp->rcv_nxt);
899 sorwakeup(so);
2ff61f9d
BJ
900 return (flags);
901drop:
902 m_freem(dtom(ti));
e832edbc 903 return (0);
d52566dd 904}