AquilaOS documentation
How it works, and its code
Loading...
Searching...
No Matches
tcp_input.c
Go to the documentation of this file.
1
14
15#include <core/system.h>
16#include <core/arch.h>
17#include <core/string.h>
18#include <net/byteorder.h>
19#include <net/inet.h>
20#include <net/netif.h>
21#include <net/tcp.h>
22
23#include <aquila/errno.h>
24
26struct seg {
29 int flags;
30 uint16_t mss; /* its MSS option, 0 if none */
33};
34
36static void options(const struct tcp_hdr *th, size_t hlen, struct seg *s)
37{
38 const uint8_t *o = (const uint8_t *) (th + 1);
39 const uint8_t *end = (const uint8_t *) th + hlen;
40
41 while (o < end) {
42 if (*o == 0) /* the end of the options */
43 break;
44
45 if (*o == 1) { /* no operation */
46 ++o;
47 continue;
48 }
49
50 if (end - o < 2 || o[1] < 2 || o[1] > end - o)
51 break;
52
53 if (o[0] == 2 && o[1] == 4)
54 s->mss = o[2] << 8 | o[3];
55
56 o += o[1];
57 }
58}
59
62static void set_mss(struct tcp_pcb *pcb, uint16_t peer)
63{
64 struct netif *netif = ipv4_route(pcb->raddr);
65 uint16_t ours = netif ? netif->mtu - sizeof(struct ipv4_hdr) - sizeof(struct tcp_hdr) :
67
68 pcb->mss = MIN(peer ? peer : TCP_MSS_DEFAULT, ours);
69}
70
73static void rtt_sample(struct tcp_pcb *pcb, uint32_t ack)
74{
75 if (pcb->rtt_timing && SEQ_GT(ack, pcb->rtt_seq)) {
76 tcp_rtt_update(pcb, arch_rtime_ns() - pcb->rtt_start);
77 pcb->rtt_timing = 0;
78 }
79}
80
84static void listen_input(struct tcp_pcb *l, const struct ipv4_hdr *ih, const struct tcp_hdr *th,
85 struct seg *s, struct netif *netif)
86{
87 if (s->flags & TH_RST)
88 return;
89
90 if (s->flags & TH_ACK) {
91 tcp_reply_rst(netif, ih, th, s->len);
92 return;
93 }
94
95 /* if the backlog is full, the SYN is ignored: the peer tries again */
96 if (!(s->flags & TH_SYN) || l->qlen >= l->backlog)
97 return;
98
99 struct tcp_pcb *pcb = tcp_pcb_new();
100
101 if (!pcb)
102 return;
103
104 pcb->laddr = ih->dst;
105 pcb->lport = th->dst;
106 pcb->raddr = ih->src;
107 pcb->rport = th->src;
108 pcb->state = TCP_SYN_RECEIVED;
109
110 pcb->irs = s->seq;
111 pcb->rcv_nxt = s->seq + 1;
112 pcb->snd_wnd = s->win;
113 pcb->snd_wl1 = s->seq;
114 set_mss(pcb, s->mss);
115
116 pcb->iss = tcp_iss(pcb);
117 pcb->snd_una = pcb->iss;
118
119 /* the connection inherits the listener's options */
120 pcb->nodelay = l->nodelay;
121 pcb->keepalive = l->keepalive;
122
123 if (tcp_insert(pcb)) {
124 tcp_pcb_free(pcb);
125 return;
126 }
127
128 pcb->parent = l;
129 l->qlen++;
130
131 tcp_send_syn(pcb);
132}
133
136static void syn_sent_input(struct tcp_pcb *pcb, const struct ipv4_hdr *ih, const struct tcp_hdr *th,
137 struct seg *s, struct netif *netif)
138{
139 if (s->flags & TH_ACK) {
140 if (SEQ_LEQ(s->ack, pcb->iss) || SEQ_GT(s->ack, pcb->snd_max)) {
141 tcp_reply_rst(netif, ih, th, s->len);
142 return;
143 }
144 }
145
146 if (s->flags & TH_RST) {
147 if (s->flags & TH_ACK)
148 tcp_drop(pcb, ECONNREFUSED);
149 return;
150 }
151
152 if (!(s->flags & TH_SYN))
153 return;
154
155 pcb->irs = s->seq;
156 pcb->rcv_nxt = s->seq + 1;
157 set_mss(pcb, s->mss);
158
159 pcb->snd_wnd = s->win;
160 pcb->snd_wl1 = s->seq;
161 pcb->snd_wl2 = s->ack;
162
163 if (!(s->flags & TH_ACK)) {
164 /* both sides opened at once: send SYN and ACK for theirs */
165 pcb->state = TCP_SYN_RECEIVED;
166 pcb->retries = 0;
167 tcp_send_syn(pcb);
168 return;
169 }
170
171 /* our SYN was acknowledged (data that came with it is left for the
172 * peer to send again) */
173 if (!pcb->retries)
174 rtt_sample(pcb, s->ack);
175
176 pcb->snd_una = s->ack;
177 pcb->retries = 0;
178 callout_stop(&pcb->rexmt);
179
180 tcp_established(pcb);
181 tcp_send_ack(pcb);
182}
183
186static int acceptable(struct tcp_pcb *pcb, struct seg *s, uint32_t wnd)
187{
188 uint32_t seglen = s->len + !!(s->flags & TH_SYN) + !!(s->flags & TH_FIN);
189 uint32_t nxt = pcb->rcv_nxt;
190
191#define IN_WINDOW(x) (SEQ_GEQ(x, nxt) && SEQ_LT(x, nxt + wnd))
192
193 if (!seglen)
194 return wnd ? IN_WINDOW(s->seq) : s->seq == nxt;
195
196 return wnd && (IN_WINDOW(s->seq) || IN_WINDOW(s->seq + seglen - 1));
197
198#undef IN_WINDOW
199}
200
203static void retransmit_first(struct tcp_pcb *pcb)
204{
205 uint32_t nxt = pcb->snd_nxt;
206
207 pcb->snd_nxt = pcb->snd_una;
208 pcb->rtt_timing = 0;
209
210 uint32_t cwnd = pcb->cwnd;
211 int nodelay = pcb->nodelay;
212
213 /* send one segment, whatever the windows and Nagle say */
214 pcb->cwnd = pcb->mss;
215 pcb->nodelay = 1;
216 tcp_output(pcb);
217 pcb->cwnd = cwnd;
218 pcb->nodelay = nodelay;
219
220 if (SEQ_GT(nxt, pcb->snd_nxt))
221 pcb->snd_nxt = nxt;
222}
223
227static int ack_input(struct tcp_pcb *pcb, struct seg *s)
228{
229 if (SEQ_GT(s->ack, pcb->snd_max)) {
230 /* it acknowledges what we didn't send */
231 tcp_send_ack(pcb);
232 return -1;
233 }
234
235 if (SEQ_GT(s->ack, pcb->snd_una)) {
236 uint32_t acked = s->ack - pcb->snd_una;
237 uint32_t buffered = ringbuf_available(pcb->sndbuf);
238 int fin_acked = pcb->fin_queued && acked > buffered;
239
240 /* drop the acknowledged data (the FIN comes after it) */
241 ringbuf_discard(pcb->sndbuf, MIN(acked, buffered));
242
243 pcb->snd_una = s->ack;
244
245 if (SEQ_LT(pcb->snd_nxt, pcb->snd_una))
246 pcb->snd_nxt = pcb->snd_una;
247
248 rtt_sample(pcb, s->ack);
249 pcb->retries = 0;
250
251 if (pcb->in_recovery) {
252 if (SEQ_GEQ(s->ack, pcb->recover)) {
253 /* everything that was in flight at the loss is
254 * acknowledged: the recovery is over */
255 pcb->in_recovery = 0;
256 pcb->cwnd = pcb->ssthresh;
257 } else {
258 /* a partial ACK: retransmit the next hole */
259 retransmit_first(pcb);
260 pcb->cwnd = pcb->cwnd > acked ? pcb->cwnd - acked + pcb->mss : pcb->mss;
261 }
262 } else if (pcb->cwnd < pcb->ssthresh) {
263 pcb->cwnd += MIN(acked, (uint32_t) pcb->mss); /* slow start */
264 } else {
265 pcb->cwnd += MAX(1U, (uint32_t) pcb->mss * pcb->mss / pcb->cwnd); /* congestion avoidance */
266 }
267
268 pcb->dupacks = 0;
269
270 /* restart the timer for what is still in flight */
271 callout_stop(&pcb->rexmt);
272 pcb->persist = 0;
273
274 if (pcb->snd_una != pcb->snd_max)
275 tcp_rexmt_start(pcb);
276
277 tcp_wakeup(pcb);
278
279 if (fin_acked) {
280 switch (pcb->state) {
281 case TCP_FIN_WAIT_1:
282 pcb->state = TCP_FIN_WAIT_2;
283 tcp_fin_wait_2(pcb);
284 break;
285 case TCP_CLOSING:
286 tcp_time_wait(pcb);
287 break;
288 case TCP_LAST_ACK:
289 tcp_closed(pcb);
290 return -1;
291 }
292 }
293 } else if (s->ack == pcb->snd_una && !s->len && !(s->flags & TH_FIN) &&
294 s->win == pcb->snd_wnd && pcb->snd_una != pcb->snd_max) {
295 /* a duplicate ACK: a segment was lost, and those after it got
296 * there */
297 if (++pcb->dupacks == 3 && !pcb->in_recovery) {
298 uint32_t flight = pcb->snd_max - pcb->snd_una;
299
300 pcb->ssthresh = MAX(flight / 2, 2U * pcb->mss);
301 pcb->recover = pcb->snd_max;
302 pcb->in_recovery = 1;
303
304 retransmit_first(pcb);
305 pcb->cwnd = pcb->ssthresh + 3 * pcb->mss;
306 } else if (pcb->dupacks > 3 && pcb->in_recovery) {
307 pcb->cwnd += pcb->mss;
308 tcp_output(pcb);
309 }
310 }
311
312 /* update the peer's window from its latest segment */
313 if (SEQ_LT(pcb->snd_wl1, s->seq) || (pcb->snd_wl1 == s->seq && SEQ_LEQ(pcb->snd_wl2, s->ack))) {
314 int opened = !pcb->snd_wnd && s->win;
315
316 pcb->snd_wnd = s->win;
317 pcb->snd_wl1 = s->seq;
318 pcb->snd_wl2 = s->ack;
319
320 if (opened && pcb->persist) {
321 pcb->persist = 0;
322 callout_stop(&pcb->rexmt);
323 pcb->snd_nxt = pcb->snd_una;
324 }
325 }
326
327 return 0;
328}
329
332static void ooo_insert(struct tcp_pcb *pcb, struct netbuf *nb, struct seg *s, int fin)
333{
334 nb->data = s->data;
335 nb->len = s->len;
336 nb->seq = s->seq;
337 nb->fin = fin;
338
339 struct netbuf **p = &pcb->ooo;
340
341 while (*p && SEQ_LT((*p)->seq, s->seq))
342 p = &(*p)->next;
343
344 /* the same segment again */
345 if (*p && (*p)->seq == s->seq && (*p)->len >= s->len) {
346 netbuf_free(nb);
347 return;
348 }
349
350 nb->next = *p;
351 *p = nb;
352}
353
358static void ooo_purge(struct tcp_pcb *pcb)
359{
360 while (pcb->ooo) {
361 struct netbuf *nb = pcb->ooo;
362 pcb->ooo = nb->next;
363 netbuf_free(nb);
364 }
365}
366
369static int ooo_drain(struct tcp_pcb *pcb)
370{
371 int fin = 0;
372
373 while (pcb->ooo && SEQ_LEQ(pcb->ooo->seq, pcb->rcv_nxt)) {
374 struct netbuf *nb = pcb->ooo;
375 uint32_t skip = pcb->rcv_nxt - nb->seq;
376
377 pcb->ooo = nb->next;
378
379 if (skip < nb->len) {
380 uint32_t n = ringbuf_write(pcb->rcvbuf, nb->len - skip, (char *) nb->data + skip);
381
382 pcb->rcv_nxt += n;
383
384 if (n < nb->len - skip)
385 nb->fin = 0;
386 }
387
388 if (nb->fin && nb->seq + nb->len == pcb->rcv_nxt)
389 fin = 1;
390
391 netbuf_free(nb);
392
393 if (fin) {
394 ooo_purge(pcb);
395 break;
396 }
397 }
398
399 return fin;
400}
401
404static void fin_input(struct tcp_pcb *pcb)
405{
406 pcb->rcv_nxt++;
407 pcb->fin_received = 1;
408 tcp_send_ack(pcb);
409 tcp_wakeup(pcb);
410
411 switch (pcb->state) {
412 case TCP_SYN_RECEIVED:
413 case TCP_ESTABLISHED:
414 pcb->state = TCP_CLOSE_WAIT;
415 break;
416 case TCP_FIN_WAIT_1:
417 /* our FIN isn't acknowledged yet */
418 pcb->state = TCP_CLOSING;
419 break;
420 case TCP_FIN_WAIT_2:
421 case TCP_TIME_WAIT:
422 tcp_time_wait(pcb);
423 break;
424 }
425}
426
430static void segment_input(struct tcp_pcb *pcb, struct netbuf *nb, struct seg *s,
431 const struct ipv4_hdr *ih, const struct tcp_hdr *th, struct netif *netif)
432{
433 uint32_t wnd = SEQ_GT(pcb->rcv_adv, pcb->rcv_nxt) ? pcb->rcv_adv - pcb->rcv_nxt : 0;
434
435 if (!acceptable(pcb, s, wnd)) {
436 if (!(s->flags & TH_RST))
437 tcp_send_ack(pcb);
438 goto done;
439 }
440
441 /* RFC 5961: accept a reset only at rcv_nxt, and answer any other with
442 * a challenge ACK */
443 if (s->flags & TH_RST) {
444 if (s->seq != pcb->rcv_nxt) {
445 tcp_send_ack(pcb);
446 goto done;
447 }
448
449 switch (pcb->state) {
450 case TCP_SYN_RECEIVED:
451 tcp_drop(pcb, ECONNREFUSED);
452 break;
453 case TCP_CLOSING:
454 case TCP_LAST_ACK:
455 case TCP_TIME_WAIT:
456 tcp_closed(pcb);
457 break;
458 default:
459 tcp_drop(pcb, ECONNRESET);
460 }
461
462 goto done;
463 }
464
465 /* a SYN in a connection gets a challenge ACK (RFC 5961) */
466 if (s->flags & TH_SYN) {
467 tcp_send_ack(pcb);
468 goto done;
469 }
470
471 if (!(s->flags & TH_ACK))
472 goto done;
473
475
476 /* trim the data to what we take: from rcv_nxt, within the window */
477 int fin = !!(s->flags & TH_FIN);
478
479 if (SEQ_LT(s->seq, pcb->rcv_nxt)) {
480 uint32_t skip = pcb->rcv_nxt - s->seq;
481
482 if (skip > s->len) {
483 skip = s->len;
484 fin = 0;
485 }
486
487 s->data += skip;
488 s->len -= skip;
489 s->seq += skip;
490 }
491
492 if (SEQ_GT(s->seq + s->len, pcb->rcv_nxt + wnd)) {
493 s->len = SEQ_GT(pcb->rcv_nxt + wnd, s->seq) ? pcb->rcv_nxt + wnd - s->seq : 0;
494 fin = 0;
495 }
496
497 if (pcb->state == TCP_SYN_RECEIVED) {
498 if (SEQ_LEQ(s->ack, pcb->snd_una) || SEQ_GT(s->ack, pcb->snd_max)) {
499 tcp_reply_rst(netif, ih, th, s->len);
500 goto done;
501 }
502
503 if (!pcb->retries)
504 rtt_sample(pcb, s->ack);
505
506 pcb->snd_una = s->ack;
507 pcb->snd_wnd = s->win;
508 pcb->snd_wl1 = s->seq;
509 pcb->snd_wl2 = s->ack;
510 pcb->retries = 0;
511 callout_stop(&pcb->rexmt);
512
513 tcp_established(pcb);
514 } else if (ack_input(pcb, s)) {
515 goto done;
516 }
517
518 int fin_now = 0;
519
520 /* take the data, in the states where it may come */
521 if ((s->len || fin) && (pcb->state == TCP_ESTABLISHED || pcb->state == TCP_FIN_WAIT_1 ||
522 pcb->state == TCP_FIN_WAIT_2)) {
523 /* no one reads the socket anymore: reset (RFC 2525) */
524 if (s->len && pcb->detached) {
525 tcp_send_rst(pcb);
526 tcp_drop(pcb, 0);
527 goto done;
528 }
529
530 if (s->seq == pcb->rcv_nxt) {
531 uint32_t n = ringbuf_write(pcb->rcvbuf, s->len, (char *) s->data);
532 int waiting = pcb->ooo != NULL;
533
534 pcb->rcv_nxt += n;
535 fin_now = fin && n == s->len;
536
537 if (!fin_now && waiting)
538 fin_now = ooo_drain(pcb);
539 else if (fin_now)
540 ooo_purge(pcb);
541
542 /* acknowledge a filled hole now; the FIN is acknowledged by
543 * fin_input() */
544 if (n && !fin_now) {
545 if (waiting)
546 tcp_send_ack(pcb);
547 else
548 tcp_dack(pcb);
549 }
550
551 if (n)
552 tcp_wakeup(pcb);
553 } else {
554 /* ahead of rcv_nxt: it waits, and the duplicate ACK tells
555 * the peer what is missing */
556 ooo_insert(pcb, nb, s, fin);
557 nb = NULL;
558 tcp_send_ack(pcb);
559 }
560 } else if (fin && s->seq == pcb->rcv_nxt) {
561 fin_now = 1;
562 }
563
564 if (fin_now)
565 fin_input(pcb);
566
567 /* data was acknowledged or the window moved: send more */
568 if (pcb->state != TCP_CLOSED)
569 tcp_output(pcb);
570
571done:
572 if (nb)
573 netbuf_free(nb);
574}
575
585void tcp_input(struct netif *netif, struct netbuf *nb, const struct ipv4_hdr *ih)
586{
587 struct tcp_hdr *th = (struct tcp_hdr *) nb->data;
588 size_t hlen;
589
590 if (nb->len < sizeof(*th) || (hlen = (th->off >> 4) * 4) < sizeof(*th) || hlen > nb->len ||
591 inet_checksum_pseudo(ih->src, ih->dst, IP_PROTO_TCP, th, nb->len)) {
592 netif->stats.rx_errors++;
593 netbuf_free(nb);
594 return;
595 }
596
597 /* only segments to one of our addresses, not to a broadcast */
598 if (!ipv4_is_local(ih->dst)) {
599 netbuf_free(nb);
600 return;
601 }
602
603 struct seg s = {
604 .seq = ntohl(th->seq),
605 .ack = ntohl(th->ack),
606 .win = ntohs(th->win),
607 .flags = th->flags,
608 .data = nb->data + hlen,
609 .len = nb->len - hlen,
610 };
611
612 options(th, hlen, &s);
613
614 struct tcp_pcb *pcb = tcp_lookup(ih->dst, th->dst, ih->src, th->src);
615
616 if (!pcb) {
617 struct tcp_pcb *l = tcp_listener(ih->dst, th->dst);
618
619 if (l)
620 listen_input(l, ih, th, &s, netif);
621 else
622 tcp_reply_rst(netif, ih, th, s.len);
623
624 netbuf_free(nb);
625 return;
626 }
627
628 if (pcb->state == TCP_SYN_SENT) {
629 syn_sent_input(pcb, ih, th, &s, netif);
630 netbuf_free(nb);
631 return;
632 }
633
634 segment_input(pcb, nb, &s, ih, th, netif);
635}
#define ntohl(x)
Definition byteorder.h:18
#define ntohs(x)
Definition byteorder.h:17
void callout_stop(struct callout *c)
Cancels a callout, if it is pending.
Definition callout.c:23
#define MIN(a, b)
Definition system.h:11
#define MAX(a, b)
Definition system.h:10
struct netif * ipv4_route(uint32_t dst)
Chooses the interface to send a packet to dst through: the one whose link it is on,...
Definition ipv4.c:142
#define IP_PROTO_TCP
Definition inet.h:42
int ipv4_is_local(uint32_t ip)
Says whether an address is one of ours: a loopback address, or an interface's.
Definition ipv4.c:48
uint16_t inet_checksum_pseudo(uint32_t src, uint32_t dst, uint8_t proto, const void *data, size_t len)
Computes the Internet checksum of data with the IPv4 pseudo-header before it (the addresses,...
Definition ether.c:106
void netbuf_free(struct netbuf *nb)
Frees a netbuf.
Definition netbuf.c:99
static int skip
Definition ps2mouse.c:48
static void ringbuf_discard(struct ringbuf *ring, size_t n)
Throws away the first n bytes of the ring, unread (at most what it holds).
Definition ringbuf.h:113
#define NULL
Definition stddef.h:27
unsigned int uint32_t
Definition stddef.h:22
unsigned char uint8_t
Definition stddef.h:20
unsigned short int uint16_t
Definition stddef.h:21
An IPv4 packet's header.
Definition inet.h:46
uint32_t dst
Definition inet.h:56
uint32_t src
Definition inet.h:55
A packet (net/netbuf.c).
Definition netbuf.h:16
int fin
Definition netbuf.h:31
uint32_t seq
Definition netbuf.h:30
struct netbuf * next
Definition netbuf.h:17
uint8_t * data
Definition netbuf.h:19
size_t len
Definition netbuf.h:20
A network interface (net/netif.c): a device that sends and receives Ethernet frames,...
Definition netif.h:16
struct netif::@020302303320120142126121344055047003105154122231 stats
uint16_t mtu
Definition netif.h:19
A received segment, with its header in host byte order.
Definition tcp_input.c:26
uint32_t len
Definition tcp_input.c:32
uint32_t seq
Definition tcp_input.c:27
uint16_t mss
Definition tcp_input.c:30
uint32_t ack
Definition tcp_input.c:27
int flags
Definition tcp_input.c:29
uint16_t win
Definition tcp_input.c:28
uint8_t * data
Definition tcp_input.c:31
A TCP segment's header.
Definition tcp.h:16
uint32_t seq
Definition tcp.h:18
uint16_t dst
Definition tcp.h:17
uint16_t src
Definition tcp.h:17
uint16_t win
Definition tcp.h:21
uint8_t flags
Definition tcp.h:20
uint32_t ack
Definition tcp.h:18
uint8_t off
Definition tcp.h:19
A connection (its control block, or PCB).
Definition tcp.h:66
int nodelay
Definition tcp.h:106
uint32_t laddr
Definition tcp.h:70
uint16_t mss
Definition tcp.h:80
int in_recovery
Definition tcp.h:102
struct callout rexmt
Definition tcp.h:111
uint32_t cwnd
Definition tcp.h:100
int detached
Definition tcp.h:122
uint32_t snd_wl1
Definition tcp.h:79
int backlog
Definition tcp.h:120
struct tcp_pcb * parent
Definition tcp.h:118
uint32_t snd_una
Definition tcp.h:78
uint32_t iss
Definition tcp.h:78
int retries
Definition tcp.h:96
uint32_t snd_wl2
Definition tcp.h:79
uint32_t snd_nxt
Definition tcp.h:78
uint32_t irs
Definition tcp.h:86
int fin_received
Definition tcp.h:89
uint32_t rcv_adv
Definition tcp.h:86
uint16_t rport
Definition tcp.h:71
uint16_t lport
Definition tcp.h:71
int qlen
Definition tcp.h:120
uint32_t snd_wnd
Definition tcp.h:79
struct netbuf * ooo
Definition tcp.h:88
int rtt_timing
Definition tcp.h:93
uint32_t ssthresh
Definition tcp.h:100
struct ringbuf * rcvbuf
Definition tcp.h:87
int state
Definition tcp.h:67
uint32_t rtt_seq
Definition tcp.h:94
int dupacks
Definition tcp.h:101
int fin_queued
Definition tcp.h:82
uint32_t rcv_nxt
Definition tcp.h:86
int persist
Definition tcp.h:97
int keepalive
Definition tcp.h:107
struct ringbuf * sndbuf
Definition tcp.h:81
uint32_t raddr
Definition tcp.h:70
uint32_t recover
Definition tcp.h:103
uint32_t snd_max
Definition tcp.h:78
void tcp_established(struct tcp_pcb *pcb)
Moves a connection to ESTABLISHED: its congestion window starts, and a listener's connection is queue...
Definition tcp_socket.c:335
#define SEQ_GEQ(a, b)
Definition tcp.h:53
#define TH_FIN
Definition tcp.h:27
struct tcp_pcb * tcp_lookup(uint32_t laddr, uint16_t lport, uint32_t raddr, uint16_t rport)
Finds a connection by both ends' addresses and ports.
Definition tcp_socket.c:96
void tcp_send_syn(struct tcp_pcb *pcb)
Sends the SYN (or, in SYN_RECEIVED, the SYN and ACK), the first time or again, and starts the retrans...
Definition tcp_output.c:135
#define SEQ_GT(a, b)
Definition tcp.h:52
void tcp_dack(struct tcp_pcb *pcb)
Acknowledges a received segment: at once if it's the second one not acknowledged yet,...
Definition tcp_output.c:344
struct tcp_pcb * tcp_pcb_new(void)
Makes a connection, CLOSED, with its send and receive buffers, on the list of connections.
Definition tcp_socket.c:162
void tcp_reply_rst(struct netif *netif, const struct ipv4_hdr *ih, const struct tcp_hdr *th, size_t len)
Answers a segment that is for no connection with a reset (RFC 9293 3.10.7.1).
Definition tcp_output.c:192
#define TH_ACK
Definition tcp.h:31
void tcp_closed(struct tcp_pcb *pcb)
Moves a connection to CLOSED: it leaves the hashmap, its timers stop, and its waiters wake up.
Definition tcp_socket.c:295
struct tcp_pcb * tcp_listener(uint32_t laddr, uint16_t lport)
Finds the listener for a local address and port: one bound to that address, or else one bound to any ...
Definition tcp_socket.c:138
void tcp_output(struct tcp_pcb *pcb)
Sends as much of the send buffer as the windows allow, in segments of at most mss bytes.
Definition tcp_output.c:249
#define TCP_MSS_DEFAULT
Definition tcp.h:59
void tcp_wakeup(struct tcp_pcb *pcb)
Wakes up the threads waiting on a connection (in accept(), connect(), recv() or send()).
Definition tcp_socket.c:257
#define SEQ_LEQ(a, b)
Definition tcp.h:51
void tcp_fin_wait_2(struct tcp_pcb *pcb)
Handles our FIN being acknowledged (FIN_WAIT_2): if the socket is closed, the connection waits for th...
Definition tcp_socket.c:387
void tcp_send_rst(struct tcp_pcb *pcb)
Sends a reset on a connection.
Definition tcp_output.c:178
void tcp_send_ack(struct tcp_pcb *pcb)
Sends an ACK, now.
Definition tcp_output.c:157
#define TH_RST
Definition tcp.h:29
void tcp_time_wait(struct tcp_pcb *pcb)
Moves a connection to TIME_WAIT, which it leaves after 2 MSL.
Definition tcp_socket.c:373
#define TH_SYN
Definition tcp.h:28
int tcp_insert(struct tcp_pcb *pcb)
Adds a connection to the hashmap of connections, by its addresses and ports, which it must have now.
Definition tcp_socket.c:112
void tcp_input(struct netif *netif, struct netbuf *nb, const struct ipv4_hdr *ih)
Takes in a TCP segment that IPv4 received, and passes it to its connection or listener.
Definition tcp_input.c:585
@ TCP_ESTABLISHED
Definition tcp.h:40
@ TCP_LAST_ACK
Definition tcp.h:45
@ TCP_FIN_WAIT_1
Definition tcp.h:41
@ TCP_CLOSE_WAIT
Definition tcp.h:43
@ TCP_CLOSING
Definition tcp.h:44
@ TCP_CLOSED
Definition tcp.h:36
@ TCP_FIN_WAIT_2
Definition tcp.h:42
@ TCP_TIME_WAIT
Definition tcp.h:46
@ TCP_SYN_SENT
Definition tcp.h:38
@ TCP_SYN_RECEIVED
Definition tcp.h:39
void tcp_rexmt_start(struct tcp_pcb *pcb)
Starts the retransmission timer, if it isn't running.
Definition tcp_output.c:122
uint32_t tcp_iss(struct tcp_pcb *pcb)
Chooses a connection's initial sequence number (RFC 6528): a clock that ticks every 4 us,...
Definition tcp_socket.c:231
void tcp_drop(struct tcp_pcb *pcb, int err)
Drops a connection that is lost, giving its socket an error.
Definition tcp_socket.c:323
void tcp_keepalive_reset(struct tcp_pcb *pcb)
Restarts the keepalive timer, when the peer was heard from.
Definition tcp_socket.c:417
#define SEQ_LT(a, b)
Definition tcp.h:50
void tcp_pcb_free(struct tcp_pcb *pcb)
Frees a connection: its timers stop, it leaves the lists, and its buffers and waiting segments are fr...
Definition tcp_socket.c:196
static int ooo_drain(struct tcp_pcb *pcb)
Takes the waiting segments that now follow rcv_nxt into the receive buffer.
Definition tcp_input.c:369
#define IN_WINDOW(x)
static void fin_input(struct tcp_pcb *pcb)
Handles the peer's FIN, once all the data before it is in: the end of its data, and a change of state...
Definition tcp_input.c:404
static void rtt_sample(struct tcp_pcb *pcb, uint32_t ack)
Takes a round trip measurement, if ack acknowledges the segment that is being timed.
Definition tcp_input.c:73
static void syn_sent_input(struct tcp_pcb *pcb, const struct ipv4_hdr *ih, const struct tcp_hdr *th, struct seg *s, struct netif *netif)
Handles a segment for a connection in SYN_SENT (RFC 9293 3.10.7.3): the peer's SYN and ACK establish ...
Definition tcp_input.c:136
static void listen_input(struct tcp_pcb *l, const struct ipv4_hdr *ih, const struct tcp_hdr *th, struct seg *s, struct netif *netif)
Handles a segment for a listening socket.
Definition tcp_input.c:84
static void ooo_insert(struct tcp_pcb *pcb, struct netbuf *nb, struct seg *s, int fin)
Queues a segment that came ahead of rcv_nxt, sorted by sequence number; its netbuf now holds just its...
Definition tcp_input.c:332
static int acceptable(struct tcp_pcb *pcb, struct seg *s, uint32_t wnd)
Returns whether a segment is acceptable (RFC 9293 3.10.7.4): it falls within the window we advertised...
Definition tcp_input.c:186
static void ooo_purge(struct tcp_pcb *pcb)
Drops the segments that still wait, once the FIN is in: nothing follows the FIN, so they are only cop...
Definition tcp_input.c:358
static void segment_input(struct tcp_pcb *pcb, struct netbuf *nb, struct seg *s, const struct ipv4_hdr *ih, const struct tcp_hdr *th, struct netif *netif)
Handles a segment for a connection in a synchronized state (RFC 9293 3.10.7.4).
Definition tcp_input.c:430
static void retransmit_first(struct tcp_pcb *pcb)
Retransmits the first unacknowledged segment, for a fast retransmit or a partial ACK.
Definition tcp_input.c:203
static void options(const struct tcp_hdr *th, size_t hlen, struct seg *s)
Reads a segment's options; the only one used is the MSS.
Definition tcp_input.c:36
static int ack_input(struct tcp_pcb *pcb, struct seg *s)
Handles a segment's acknowledgment of what we sent: the send buffer, the congestion window,...
Definition tcp_input.c:227
static void set_mss(struct tcp_pcb *pcb, uint16_t peer)
Sets the connection's segment size: the peer's MSS (536 if it didn't send one), but no more than ours...
Definition tcp_input.c:62