Commit | Line | Data |
---|---|---|
77b2c695 | 1 | /* tcp_input.c 1.28 81/11/23 */ |
87e78f19 BJ |
2 | |
3 | #include "../h/param.h" | |
4 | #include "../h/systm.h" | |
dad64fdf BJ |
5 | #include "../h/mbuf.h" |
6 | #include "../h/socket.h" | |
d52566dd | 7 | #include "../h/socketvar.h" |
d52566dd | 8 | #include "../net/inet.h" |
53a5409e | 9 | #include "../net/inet_pcb.h" |
d52566dd BJ |
10 | #include "../net/inet_systm.h" |
11 | #include "../net/imp.h" | |
d52566dd | 12 | #include "../net/ip.h" |
eb44bfb2 | 13 | #include "../net/ip_var.h" |
d52566dd BJ |
14 | #include "../net/tcp.h" |
15 | #include "../net/tcp_fsm.h" | |
16 | #include "../net/tcp_var.h" | |
17 | #include "/usr/include/errno.h" | |
87e78f19 | 18 | |
60b16fa9 | 19 | int tcpcksum = 1; |
87e78f19 | 20 | |
53a5409e BJ |
21 | tcp_drain() |
22 | { | |
23 | register struct inpcb *ip; | |
24 | ||
4ad99bae | 25 | COUNT(TCP_DRAIN); |
53a5409e BJ |
26 | for (ip = tcb.inp_next; ip != &tcb; ip = ip->inp_next) |
27 | tcp_drainunack(intotcpcb(ip)); | |
28 | } | |
29 | ||
30 | tcp_drainunack(tp) | |
31 | register struct tcpcb *tp; | |
32 | { | |
33 | register struct mbuf *m; | |
34 | ||
4ad99bae | 35 | COUNT(TCP_DRAINUNACK); |
53a5409e BJ |
36 | for (m = tp->seg_unack; m; m = m->m_act) |
37 | m_freem(m); | |
38 | tp->seg_unack = 0; | |
39 | } | |
40 | ||
41 | tcp_ctlinput(m) | |
42 | struct mbuf *m; | |
d52566dd BJ |
43 | { |
44 | ||
4ad99bae | 45 | COUNT(TCP_CTLINPUT); |
53a5409e | 46 | m_freem(m); |
d52566dd BJ |
47 | } |
48 | ||
4ad99bae BJ |
49 | struct sockaddr_in tcp_sockaddr = { AF_INET }; |
50 | ||
2b4b57cd BJ |
51 | tcp_input(m0) |
52 | struct mbuf *m0; | |
87e78f19 | 53 | { |
2b4b57cd | 54 | register struct tcpiphdr *ti; |
53a5409e | 55 | struct inpcb *inp; |
2b4b57cd BJ |
56 | register struct mbuf *m; |
57 | int len, tlen, off; | |
58 | ||
59 | register struct tcpcb *tp; | |
60 | register int j; | |
61 | register int tiflags; | |
87e78f19 | 62 | int nstate; |
d52566dd | 63 | struct socket *so; |
87e78f19 BJ |
64 | #ifdef TCPDEBUG |
65 | struct tcp_debug tdb; | |
66 | #endif | |
87e78f19 | 67 | |
2b4b57cd | 68 | COUNT(TCP_INPUT); |
87e78f19 | 69 | /* |
2b4b57cd | 70 | * Get ip and tcp header together in first mbuf. |
87e78f19 | 71 | */ |
2b4b57cd | 72 | m = m0; |
2b4b57cd BJ |
73 | if (m->m_len < sizeof (struct tcpiphdr) && |
74 | m_pullup(m, sizeof (struct tcpiphdr)) == 0) { | |
75 | tcpstat.tcps_hdrops++; | |
76 | goto bad; | |
77 | } | |
20790db4 BJ |
78 | ti = mtod(m, struct tcpiphdr *); |
79 | if (ti->ti_len > sizeof (struct ip)) | |
80 | ip_stripoptions((struct ip *)ti, (char *)0); | |
87e78f19 | 81 | |
2b4b57cd BJ |
82 | /* |
83 | * Checksum extended tcp header and data. | |
84 | */ | |
85 | tlen = ((struct ip *)ti)->ip_len; | |
86 | len = sizeof (struct ip) + tlen; | |
60b16fa9 | 87 | if (tcpcksum) { |
2b4b57cd BJ |
88 | ti->ti_next = ti->ti_prev = 0; |
89 | ti->ti_x1 = 0; | |
4ad99bae | 90 | ti->ti_len = htons((u_short)tlen); |
77b2c695 | 91 | if ((ti->ti_sum = inet_cksum(m, len)) != 0xffff) { |
2b4b57cd BJ |
92 | tcpstat.tcps_badsum++; |
93 | printf("tcp cksum %x\ti", ti->ti_sum); | |
94 | goto bad; | |
87e78f19 BJ |
95 | } |
96 | } | |
97 | ||
98 | /* | |
2b4b57cd BJ |
99 | * Check that tcp offset makes sense, |
100 | * process tcp options and adjust length. | |
87e78f19 | 101 | */ |
2b4b57cd BJ |
102 | off = ti->ti_off << 2; |
103 | if (off < sizeof (struct tcphdr) || off > ti->ti_len) { | |
104 | tcpstat.tcps_badoff++; | |
105 | goto bad; | |
106 | } | |
107 | ti->ti_len = tlen - off; | |
108 | /* PROCESS OPTIONS */ | |
109 | ||
110 | /* | |
2b4b57cd BJ |
111 | * Locate pcb for segment. |
112 | */ | |
4ad99bae | 113 | inp = in_pcblookup(&tcb, ti->ti_src, ti->ti_sport, ti->ti_dst, ti->ti_dport); |
53a5409e BJ |
114 | if (inp == 0) |
115 | goto notwanted; | |
2b4b57cd BJ |
116 | tp = intotcpcb(inp); /* ??? */ |
117 | if (tp == 0) /* ??? */ | |
118 | goto notwanted; /* ??? */ | |
87e78f19 BJ |
119 | |
120 | /* | |
2b4b57cd | 121 | * Convert tcp protocol specific fields to host format. |
87e78f19 | 122 | */ |
2b4b57cd BJ |
123 | ti->ti_seq = ntohl(ti->ti_seq); |
124 | ti->ti_ackno = ntohl((n_long)ti->ti_ackno); | |
125 | ti->ti_win = ntohs(ti->ti_win); | |
126 | ti->ti_urp = ntohs(ti->ti_urp); | |
87e78f19 BJ |
127 | |
128 | /* | |
129 | * Check segment seq # and do rst processing | |
130 | */ | |
2b4b57cd | 131 | tiflags = ti->ti_flags; |
87e78f19 BJ |
132 | switch (tp->t_state) { |
133 | ||
134 | case LISTEN: | |
2b4b57cd BJ |
135 | if ((tiflags&TH_ACK) || (tiflags&TH_SYN) == 0) { |
136 | tcp_sndrst(tp, ti); | |
137 | goto bad; | |
87e78f19 | 138 | } |
2b4b57cd BJ |
139 | if (tiflags&TH_RST) |
140 | goto bad; | |
141 | goto good; | |
87e78f19 BJ |
142 | |
143 | case SYN_SENT: | |
2b4b57cd BJ |
144 | if (!ack_ok(tp, ti) || (tiflags&TH_SYN) == 0) { |
145 | tcp_sndrst(tp, ti); /* 71,72,75 */ | |
146 | goto bad; | |
87e78f19 | 147 | } |
2b4b57cd | 148 | if (tiflags&TH_RST) { |
d52566dd BJ |
149 | tcp_error(tp, ENETRESET); |
150 | tcp_detach(tp); /* 70 */ | |
87e78f19 | 151 | tp->t_state = CLOSED; |
2b4b57cd | 152 | goto bad; |
87e78f19 | 153 | } |
2b4b57cd | 154 | goto good; |
87e78f19 BJ |
155 | |
156 | default: | |
2b4b57cd | 157 | if ((tiflags&TH_RST) == 0) |
87e78f19 | 158 | goto common; |
2b4b57cd BJ |
159 | if (ti->ti_seq < tp->rcv_nxt) /* bad rst */ |
160 | goto bad; /* 69 */ | |
87e78f19 BJ |
161 | switch (tp->t_state) { |
162 | ||
163 | case L_SYN_RCVD: | |
2b4b57cd BJ |
164 | if (ack_ok(tp, ti) == 0) |
165 | goto bad; /* 69 */ | |
87e78f19 BJ |
166 | tp->t_rexmt = 0; |
167 | tp->t_rexmttl = 0; | |
168 | tp->t_persist = 0; | |
4ad99bae | 169 | inp->inp_faddr.s_addr = 0; |
87e78f19 | 170 | tp->t_state = LISTEN; |
2b4b57cd | 171 | goto bad; |
87e78f19 BJ |
172 | |
173 | default: | |
d52566dd BJ |
174 | tcp_error(tp, ENETRESET); |
175 | tcp_detach(tp); /* 66 */ | |
87e78f19 | 176 | tp->t_state = CLOSED; |
2b4b57cd | 177 | goto bad; |
87e78f19 BJ |
178 | } |
179 | /*NOTREACHED*/ | |
180 | ||
181 | case SYN_RCVD: | |
182 | common: | |
2b4b57cd BJ |
183 | if (ack_ok(tp, ti) == 0) { |
184 | tcp_sndrst(tp, ti); /* 74 */ | |
185 | goto bad; | |
87e78f19 | 186 | } |
2b4b57cd | 187 | if ((tiflags&TH_SYN) == 0 && ti->ti_seq != tp->irs) { |
60b16fa9 | 188 | tcp_sndnull(tp); /* 74 */ |
2b4b57cd | 189 | goto bad; |
87e78f19 | 190 | } |
2b4b57cd | 191 | goto good; |
87e78f19 | 192 | } |
2b4b57cd BJ |
193 | bad: |
194 | m_freem(m); | |
87e78f19 BJ |
195 | return; |
196 | ||
2b4b57cd | 197 | good: |
87e78f19 BJ |
198 | /* |
199 | * Defer processing if no buffer space for this connection. | |
200 | */ | |
53a5409e | 201 | so = inp->inp_socket; |
d52566dd | 202 | if (so->so_rcv.sb_cc >= so->so_rcv.sb_hiwat && |
2b4b57cd | 203 | ti->ti_len != 0 && mbstat.m_bufs < mbstat.m_lowat) { |
d52566dd | 204 | /* |
2b4b57cd | 205 | m->m_act = (struct mbuf *)0; |
d52566dd | 206 | if ((m = tp->seg_unack) != NULL) { |
87e78f19 BJ |
207 | while (m->m_act != NULL) |
208 | m = m->m_act; | |
2b4b57cd | 209 | m->m_act = m0; |
87e78f19 | 210 | } else |
2b4b57cd | 211 | tp->seg_unack = m0; |
d52566dd | 212 | */ |
2b4b57cd | 213 | m_freem(m0); |
87e78f19 BJ |
214 | return; |
215 | } | |
87e78f19 BJ |
216 | |
217 | /* | |
218 | * Discard ip header, and do tcp input processing. | |
219 | */ | |
2b4b57cd BJ |
220 | off += sizeof (struct ip); |
221 | m->m_off += off; | |
222 | m->m_len -= off; | |
87e78f19 BJ |
223 | nstate = tp->t_state; |
224 | tp->tc_flags &= ~TC_NET_KEEP; | |
a1de2d92 | 225 | #ifdef KPROF |
87e78f19 | 226 | acounts[tp->t_state][INRECV]++; |
a1de2d92 | 227 | #endif |
87e78f19 | 228 | #ifdef TCPDEBUG |
d52566dd | 229 | if ((tp->t_socket->so_options & SO_DEBUG) || tcpconsdebug) { |
2b4b57cd | 230 | tdb_setup(tp, ti, INRECV, &tdb); |
87e78f19 BJ |
231 | } else |
232 | tdb.td_tod = 0; | |
233 | #endif | |
234 | switch (tp->t_state) { | |
235 | ||
236 | case LISTEN: | |
4ad99bae BJ |
237 | tcp_sockaddr.sin_addr = ti->ti_src; |
238 | tcp_sockaddr.sin_port = ti->ti_sport; | |
239 | if ((tiflags&TH_SYN) == 0 || in_pcbsetpeer(inp, &tcp_sockaddr)) { | |
87e78f19 BJ |
240 | nstate = EFAILEC; |
241 | goto done; | |
242 | } | |
e1506033 | 243 | tp->t_template = tcp_template(tp); |
2b4b57cd | 244 | tcp_ctldat(tp, ti, 1); |
87e78f19 BJ |
245 | if (tp->tc_flags&TC_FIN_RCVD) { |
246 | tp->t_finack = T_2ML; /* 3 */ | |
247 | tp->tc_flags &= ~TC_WAITED_2_ML; | |
248 | nstate = CLOSE_WAIT; | |
249 | } else { | |
53a5409e | 250 | tp->t_init = T_INIT / 2; /* 4 */ |
87e78f19 BJ |
251 | nstate = L_SYN_RCVD; |
252 | } | |
253 | goto done; | |
254 | ||
255 | case SYN_SENT: | |
2b4b57cd | 256 | if (!syn_ok(tp, ti)) { |
87e78f19 BJ |
257 | nstate = EFAILEC; |
258 | goto done; | |
259 | } | |
2b4b57cd | 260 | tcp_ctldat(tp, ti, 1); |
87e78f19 | 261 | if (tp->tc_flags&TC_FIN_RCVD) { |
2b4b57cd | 262 | if ((tiflags&TH_ACK) == 0) { |
87e78f19 BJ |
263 | tp->t_finack = T_2ML; /* 9 */ |
264 | tp->tc_flags &= ~TC_WAITED_2_ML; | |
265 | } | |
266 | nstate = CLOSE_WAIT; | |
267 | goto done; | |
268 | } | |
2b4b57cd | 269 | nstate = (tiflags&TH_ACK) ? ESTAB : SYN_RCVD; /* 11:8 */ |
87e78f19 BJ |
270 | goto done; |
271 | ||
272 | case SYN_RCVD: | |
273 | case L_SYN_RCVD: | |
2b4b57cd BJ |
274 | if ((tiflags&TH_ACK) == 0 || |
275 | (tiflags&TH_ACK) && ti->ti_ackno <= tp->iss) { | |
87e78f19 BJ |
276 | nstate = EFAILEC; |
277 | goto done; | |
278 | } | |
279 | goto input; | |
280 | ||
281 | case ESTAB: | |
282 | case FIN_W1: | |
283 | case FIN_W2: | |
284 | case TIME_WAIT: | |
285 | input: | |
2b4b57cd | 286 | tcp_ctldat(tp, ti, 1); /* 39 */ |
87e78f19 BJ |
287 | switch (tp->t_state) { |
288 | ||
289 | case ESTAB: | |
290 | if (tp->tc_flags&TC_FIN_RCVD) | |
291 | nstate = CLOSE_WAIT; | |
292 | break; | |
293 | ||
294 | case SYN_RCVD: | |
295 | case L_SYN_RCVD: | |
296 | nstate = (tp->tc_flags&TC_FIN_RCVD) ? | |
297 | CLOSE_WAIT : ESTAB; /* 33:5 */ | |
298 | break; | |
299 | ||
300 | case FIN_W1: | |
2b4b57cd | 301 | j = ack_fin(tp, ti); |
87e78f19 BJ |
302 | if ((tp->tc_flags & TC_FIN_RCVD) == 0) { |
303 | if (j) | |
304 | nstate = FIN_W2; /* 27 */ | |
305 | break; | |
306 | } | |
307 | tp->t_finack = T_2ML; | |
308 | tp->tc_flags &= ~TC_WAITED_2_ML; | |
9c5022e3 | 309 | nstate = j ? TIME_WAIT : CLOSING; /* 28:26 */ |
87e78f19 BJ |
310 | break; |
311 | ||
312 | case FIN_W2: | |
313 | if (tp->tc_flags&TC_FIN_RCVD) { | |
314 | tp->t_finack = T_2ML; /* 29 */ | |
315 | tp->tc_flags &= ~TC_WAITED_2_ML; | |
316 | nstate = TIME_WAIT; | |
317 | break; | |
318 | } | |
319 | break; | |
320 | } | |
321 | goto done; | |
322 | ||
323 | case CLOSE_WAIT: | |
2b4b57cd BJ |
324 | if (tiflags&TH_FIN) { |
325 | if ((tiflags&TH_ACK) && | |
326 | ti->ti_ackno <= tp->seq_fin) { | |
327 | tcp_ctldat(tp, ti, 0); /* 30 */ | |
87e78f19 BJ |
328 | tp->t_finack = T_2ML; |
329 | tp->tc_flags &= ~TC_WAITED_2_ML; | |
330 | } else | |
cdad2eb1 | 331 | (void) tcp_sndctl(tp); /* 31 */ |
87e78f19 BJ |
332 | goto done; |
333 | } | |
334 | goto input; | |
335 | ||
9c5022e3 | 336 | case CLOSING: |
2b4b57cd BJ |
337 | j = ack_fin(tp, ti); |
338 | if (tiflags&TH_FIN) { | |
339 | tcp_ctldat(tp, ti, 0); | |
87e78f19 BJ |
340 | tp->t_finack = T_2ML; |
341 | tp->tc_flags &= ~TC_WAITED_2_ML; | |
342 | if (j) | |
343 | nstate = TIME_WAIT; /* 23 */ | |
344 | goto done; | |
345 | } | |
346 | if (j) { | |
347 | if (tp->tc_flags&TC_WAITED_2_ML) | |
348 | if (rcv_empty(tp)) { | |
53a5409e | 349 | sorwakeup(inp->inp_socket); |
d52566dd | 350 | nstate = CLOSED; /* 15 */ |
87e78f19 BJ |
351 | } else |
352 | nstate = RCV_WAIT; /* 18 */ | |
353 | else | |
354 | nstate = TIME_WAIT; | |
355 | goto done; | |
356 | } | |
357 | goto input; | |
358 | ||
9c5022e3 | 359 | case LAST_ACK: |
2b4b57cd | 360 | if (ack_fin(tp, ti)) { |
53a5409e BJ |
361 | if (rcv_empty(tp)) { /* 16 */ |
362 | sorwakeup(inp->inp_socket); | |
87e78f19 BJ |
363 | nstate = CLOSED; |
364 | } else | |
365 | nstate = RCV_WAIT; /* 19 */ | |
366 | goto done; | |
367 | } | |
2b4b57cd | 368 | if (tiflags&TH_FIN) { |
cdad2eb1 | 369 | (void) tcp_sndctl(tp); /* 31 */ |
87e78f19 BJ |
370 | goto done; |
371 | } | |
372 | goto input; | |
373 | ||
374 | case RCV_WAIT: | |
2b4b57cd BJ |
375 | if ((tiflags&TH_FIN) && (tiflags&TH_ACK) && |
376 | ti->ti_ackno <= tp->seq_fin) { | |
377 | tcp_ctldat(tp, ti, 0); | |
87e78f19 BJ |
378 | tp->t_finack = T_2ML; |
379 | tp->tc_flags &= ~TC_WAITED_2_ML; /* 30 */ | |
380 | } | |
381 | goto done; | |
382 | } | |
383 | panic("tcp_input"); | |
384 | done: | |
385 | ||
386 | /* | |
387 | * Done with state*input specific processing. | |
388 | * Form trace records, free input if not needed, | |
389 | * and enter new state. | |
390 | */ | |
391 | #ifdef TCPDEBUG | |
8f5a3361 BJ |
392 | if (tdb.td_tod) |
393 | tdb_stuff(&tdb, nstate); | |
87e78f19 BJ |
394 | #endif |
395 | switch (nstate) { | |
396 | ||
397 | case EFAILEC: | |
2b4b57cd | 398 | m_freem(m); |
87e78f19 BJ |
399 | return; |
400 | ||
401 | default: | |
402 | tp->t_state = nstate; | |
403 | /* fall into ... */ | |
404 | ||
405 | case CLOSED: | |
406 | /* IF CLOSED CANT LOOK AT tc_flags */ | |
2b4b57cd BJ |
407 | if ((tp->tc_flags&TC_NET_KEEP) == 0) { |
408 | register struct mbuf *n; | |
2a4921ab | 409 | /* inline expansion of m_freem */ |
2b4b57cd | 410 | while (m) { |
4ad99bae | 411 | MFREE(m, n); |
2b4b57cd | 412 | m = n; |
2a4921ab | 413 | } |
2b4b57cd | 414 | } |
87e78f19 BJ |
415 | return; |
416 | } | |
417 | /* NOTREACHED */ | |
418 | ||
419 | /* | |
420 | * Unwanted packed; free everything | |
421 | * but the header and return an rst. | |
422 | */ | |
423 | notwanted: | |
2b4b57cd BJ |
424 | m_freem(m->m_next); |
425 | m->m_next = NULL; | |
426 | m->m_len = sizeof(struct tcpiphdr); | |
87e78f19 | 427 | #define xchg(a,b) j=a; a=b; b=j |
2b4b57cd BJ |
428 | xchg(ti->ti_dst.s_addr, ti->ti_src.s_addr); |
429 | xchg(ti->ti_dport, ti->ti_sport); | |
87e78f19 | 430 | #undef xchg |
2b4b57cd BJ |
431 | if (tiflags&TH_ACK) |
432 | ti->ti_seq = ti->ti_ackno; | |
87e78f19 | 433 | else { |
4ad99bae | 434 | ti->ti_ackno = htonl((unsigned)(ntohl(ti->ti_seq) + ti->ti_len)); |
2b4b57cd | 435 | ti->ti_seq = 0; |
87e78f19 | 436 | } |
2b4b57cd BJ |
437 | ti->ti_flags = ((tiflags & TH_ACK) ? 0 : TH_ACK) | TH_RST; |
438 | ti->ti_len = htons(TCPSIZE); | |
439 | ti->ti_off = 5; | |
440 | ti->ti_sum = inet_cksum(m, sizeof(struct tcpiphdr)); | |
441 | ((struct ip *)ti)->ip_len = sizeof(struct tcpiphdr); | |
77b2c695 | 442 | ((struct ip *)ti)->ip_ttl = MAXTTL; |
2b4b57cd BJ |
443 | ip_output(m); |
444 | tcpstat.tcps_badsegs++; | |
87e78f19 BJ |
445 | } |
446 | ||
53a5409e BJ |
447 | tcp_ctldat(tp, n0, dataok) |
448 | register struct tcpcb *tp; | |
449 | struct tcpiphdr *n0; | |
450 | int dataok; | |
87e78f19 | 451 | { |
2b4b57cd BJ |
452 | register struct tcpiphdr *ti = n0; |
453 | register int tiflags = ti->ti_flags; | |
53a5409e | 454 | struct socket *so = tp->t_inpcb->inp_socket; |
2b4b57cd | 455 | seq_t past = ti->ti_seq + ti->ti_len; |
53a5409e | 456 | seq_t urgent; |
60b16fa9 BJ |
457 | int sent; |
458 | COUNT(TCP_CTLDAT); | |
87e78f19 | 459 | |
2b4b57cd BJ |
460 | if (tiflags & TH_URG) |
461 | urgent = ti->ti_seq + ti->ti_urp; | |
53a5409e | 462 | tp->tc_flags &= ~(TC_ACK_DUE|TC_NEW_WINDOW); |
87e78f19 | 463 | /* syn */ |
2b4b57cd BJ |
464 | if ((tp->tc_flags&TC_SYN_RCVD) == 0 && (tiflags&TH_SYN)) { |
465 | tp->irs = ti->ti_seq; | |
466 | tp->rcv_nxt = ti->ti_seq + 1; | |
87e78f19 BJ |
467 | tp->snd_wl = tp->rcv_urp = tp->irs; |
468 | tp->tc_flags |= (TC_SYN_RCVD|TC_ACK_DUE); | |
469 | } | |
470 | /* ack */ | |
2b4b57cd BJ |
471 | if ((tiflags&TH_ACK) && (tp->tc_flags&TC_SYN_RCVD) && |
472 | ti->ti_ackno > tp->snd_una) { | |
53a5409e BJ |
473 | /* |
474 | * Reflect newly acknowledged data. | |
475 | */ | |
2b4b57cd | 476 | tp->snd_una = ti->ti_ackno; |
87e78f19 BJ |
477 | if (tp->snd_una > tp->snd_nxt) |
478 | tp->snd_nxt = tp->snd_una; | |
53a5409e BJ |
479 | |
480 | /* | |
481 | * If timed msg acked, update retransmit time value. | |
482 | */ | |
87e78f19 BJ |
483 | if ((tp->tc_flags&TC_SYN_ACKED) && |
484 | tp->snd_una > tp->t_xmt_val) { | |
53a5409e | 485 | /* NEED SMOOTHING HERE */ |
87e78f19 BJ |
486 | tp->t_xmtime = (tp->t_xmt != 0 ? tp->t_xmt : T_REXMT); |
487 | if (tp->t_xmtime > T_REMAX) | |
488 | tp->t_xmtime = T_REMAX; | |
489 | } | |
490 | ||
53a5409e BJ |
491 | /* |
492 | * Remove acked data from send buf | |
493 | */ | |
cdad2eb1 | 494 | sbdrop(&so->so_snd, (int)(tp->snd_una - tp->snd_off)); |
87e78f19 BJ |
495 | tp->snd_off = tp->snd_una; |
496 | if ((tp->tc_flags&TC_SYN_ACKED) == 0 && | |
497 | (tp->snd_una > tp->iss)) { | |
498 | tp->tc_flags |= TC_SYN_ACKED; | |
499 | tp->t_init = 0; | |
500 | } | |
501 | if (tp->seq_fin != tp->iss && tp->snd_una > tp->seq_fin) | |
502 | tp->tc_flags &= ~TC_SND_FIN; | |
503 | tp->t_rexmt = 0; | |
504 | tp->t_rexmttl = 0; | |
505 | tp->tc_flags |= TC_CANCELLED; | |
53a5409e | 506 | sowwakeup(tp->t_inpcb->inp_socket); |
87e78f19 BJ |
507 | } |
508 | /* win */ | |
2b4b57cd BJ |
509 | if ((tp->tc_flags & TC_SYN_RCVD) && ti->ti_seq >= tp->snd_wl) { |
510 | tp->snd_wl = ti->ti_seq; | |
511 | tp->snd_wnd = ti->ti_win; | |
87e78f19 BJ |
512 | tp->tc_flags |= TC_NEW_WINDOW; |
513 | tp->t_persist = 0; | |
514 | } | |
87e78f19 | 515 | /* text */ |
2b4b57cd | 516 | if (dataok && ti->ti_len) { |
cdad2eb1 | 517 | register struct tcpiphdr *q; |
53a5409e | 518 | int overage; |
87e78f19 | 519 | |
53a5409e | 520 | /* eol */ |
2b4b57cd | 521 | if ((tiflags&TH_EOL)) { |
53a5409e | 522 | register struct mbuf *m; |
2b4b57cd | 523 | for (m = dtom(ti); m->m_next; m = m->m_next) |
53a5409e BJ |
524 | ; |
525 | m->m_act = (struct mbuf *)(mtod(m, caddr_t) - 1); | |
526 | } | |
87e78f19 | 527 | |
53a5409e BJ |
528 | /* text */ |
529 | /* | |
530 | * Discard duplicate data already passed to user. | |
531 | */ | |
2b4b57cd BJ |
532 | if (SEQ_LT(ti->ti_seq, tp->rcv_nxt)) { |
533 | register int i = tp->rcv_nxt - ti->ti_seq; | |
534 | if (i >= ti->ti_len) | |
53a5409e | 535 | goto notext; |
2b4b57cd BJ |
536 | ti->ti_seq += i; |
537 | ti->ti_len -= i; | |
538 | m_adj(dtom(ti), i); | |
87e78f19 | 539 | } |
87e78f19 | 540 | |
53a5409e BJ |
541 | /* |
542 | * Find a segment which begins after this one does. | |
543 | */ | |
544 | for (q = tp->seg_next; q != (struct tcpiphdr *)tp; | |
eb44bfb2 | 545 | q = (struct tcpiphdr *)q->ti_next) |
2b4b57cd | 546 | if (SEQ_GT(q->ti_seq, ti->ti_seq)) |
53a5409e | 547 | break; |
87e78f19 | 548 | |
53a5409e BJ |
549 | /* |
550 | * If there is a preceding segment, it may provide some of | |
551 | * our data already. If so, drop the data from the incoming | |
552 | * segment. If it provides all of our data, drop us. | |
553 | */ | |
eb44bfb2 BJ |
554 | if ((struct tcpiphdr *)q->ti_prev != (struct tcpiphdr *)tp) { |
555 | register int i; | |
556 | q = (struct tcpiphdr *)(q->ti_prev); | |
53a5409e | 557 | /* conversion to int (in i) handles seq wraparound */ |
2b4b57cd | 558 | i = q->ti_seq + q->ti_len - ti->ti_seq; |
53a5409e | 559 | if (i > 0) { |
2b4b57cd | 560 | if (i >= ti->ti_len) |
53a5409e BJ |
561 | goto notext; |
562 | /* w/o setting TC_NET_KEEP */ | |
563 | m_adj(dtom(tp), i); | |
2b4b57cd BJ |
564 | ti->ti_len -= i; |
565 | ti->ti_seq += i; | |
53a5409e | 566 | } |
eb44bfb2 | 567 | q = (struct tcpiphdr *)(q->ti_next); |
53a5409e | 568 | } |
87e78f19 | 569 | |
53a5409e BJ |
570 | /* |
571 | * While we overlap succeeding segments trim them or, | |
572 | * if they are completely covered, dequeue them. | |
573 | */ | |
574 | while (q != (struct tcpiphdr *)tp && | |
2b4b57cd BJ |
575 | SEQ_GT(ti->ti_seq + ti->ti_len, q->ti_seq)) { |
576 | register int i = (ti->ti_seq + ti->ti_len) - q->ti_seq; | |
eb44bfb2 BJ |
577 | if (i < q->ti_len) { |
578 | q->ti_len -= i; | |
53a5409e | 579 | m_adj(dtom(q), i); |
ac5e71a1 | 580 | break; |
53a5409e | 581 | } |
eb44bfb2 BJ |
582 | q = (struct tcpiphdr *)q->ti_next; |
583 | m_freem(dtom(q->ti_prev)); | |
584 | remque(q->ti_prev); | |
ac5e71a1 | 585 | } |
87e78f19 | 586 | |
53a5409e BJ |
587 | /* |
588 | * Stick new segment in its place. | |
589 | */ | |
2b4b57cd BJ |
590 | insque(ti, q->ti_prev); |
591 | tp->seqcnt += ti->ti_len; | |
d52566dd | 592 | |
53a5409e BJ |
593 | /* |
594 | * Calculate available space and discard segments for | |
595 | * which there is too much. | |
596 | */ | |
597 | overage = | |
598 | (so->so_rcv.sb_cc /*XXX+tp->rcv_seqcnt*/) - so->so_rcv.sb_hiwat; | |
599 | if (overage > 0) { | |
600 | q = tp->seg_prev; | |
601 | for (;;) { | |
eb44bfb2 | 602 | register int i = MIN(q->ti_len, overage); |
53a5409e | 603 | overage -= i; |
eb44bfb2 | 604 | q->ti_len -= i; |
cdad2eb1 | 605 | m_adj(dtom(q), -i); |
eb44bfb2 | 606 | if (q->ti_len) |
53a5409e | 607 | break; |
2b4b57cd | 608 | if (q == ti) |
53a5409e | 609 | panic("tcp_text dropall"); |
eb44bfb2 BJ |
610 | q = (struct tcpiphdr *)q->ti_prev; |
611 | remque(q->ti_next); | |
d52566dd | 612 | } |
60b16fa9 | 613 | } |
53a5409e BJ |
614 | |
615 | /* | |
616 | * Advance rcv_next through newly completed sequence space. | |
617 | */ | |
2b4b57cd BJ |
618 | while (ti->ti_seq == tp->rcv_nxt) { |
619 | tp->rcv_nxt += ti->ti_len; | |
620 | ti = (struct tcpiphdr *)ti->ti_next; | |
621 | if (ti == (struct tcpiphdr *)tp) | |
53a5409e BJ |
622 | break; |
623 | } | |
624 | /* urg */ | |
2b4b57cd | 625 | if (tiflags&TH_URG) { |
53a5409e BJ |
626 | /* ... */ |
627 | if (SEQ_GT(urgent, tp->rcv_urp)) | |
628 | tp->rcv_urp = urgent; | |
60b16fa9 | 629 | } |
53a5409e BJ |
630 | tp->tc_flags |= (TC_ACK_DUE|TC_NET_KEEP); |
631 | } | |
632 | notext: | |
60b16fa9 | 633 | /* fin */ |
2b4b57cd | 634 | if ((tiflags&TH_FIN) && past == tp->rcv_nxt) { |
53a5409e BJ |
635 | if ((tp->tc_flags&TC_FIN_RCVD) == 0) { |
636 | tp->tc_flags |= TC_FIN_RCVD; | |
637 | sorwakeup(so); | |
638 | tp->rcv_nxt++; | |
d52566dd | 639 | } |
53a5409e | 640 | tp->tc_flags |= TC_ACK_DUE; |
60b16fa9 | 641 | } |
60b16fa9 BJ |
642 | /* respond */ |
643 | sent = 0; | |
644 | if (tp->tc_flags&TC_ACK_DUE) | |
645 | sent = tcp_sndctl(tp); | |
d52566dd | 646 | else if ((tp->tc_flags&TC_NEW_WINDOW)) |
53a5409e | 647 | if (tp->snd_nxt <= tp->snd_off + so->so_snd.sb_cc || |
d52566dd | 648 | (tp->tc_flags&TC_SND_FIN)) |
60b16fa9 | 649 | sent = tcp_send(tp); |
60b16fa9 BJ |
650 | |
651 | /* set for retrans */ | |
652 | if (!sent && tp->snd_una < tp->snd_nxt && | |
653 | (tp->tc_flags&TC_CANCELLED)) { | |
654 | tp->t_rexmt = tp->t_xmtime; | |
655 | tp->t_rexmttl = T_REXMTTL; | |
656 | tp->t_rexmt_val = tp->t_rtl_val = tp->snd_lst; | |
657 | tp->tc_flags &= ~TC_CANCELLED; | |
658 | } | |
2a4921ab | 659 | /* present data to user */ |
2de49286 | 660 | if ((tp->tc_flags&TC_SYN_ACKED) == 0) |
87e78f19 | 661 | return; |
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)); | |
666 | tp->seqcnt -= ti->ti_len; | |
53a5409e BJ |
667 | if (tp->seqcnt < 0) |
668 | panic("tcp_input present"); | |
2b4b57cd | 669 | ti = (struct tcpiphdr *)ti->ti_next; |
2a4921ab | 670 | } |
53a5409e | 671 | sorwakeup(so); |
d52566dd | 672 | } |