source: mainline/uspace/srv/net/tcp/conn.c@ 8d48c7e

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 8d48c7e was 8d48c7e, checked in by Jiri Svoboda <jiri@…>, 10 years ago

Find the association to deliver the datagram using amap.

  • Property mode set to 100644
File size: 33.0 KB
RevLine 
[c5808b41]1/*
[2f19103]2 * Copyright (c) 2015 Jiri Svoboda
[c5808b41]3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup tcp
30 * @{
31 */
32
33/**
[032bbe7]34 * @file TCP connection processing and state machine
[c5808b41]35 */
36
37#include <adt/list.h>
38#include <errno.h>
[2f19103]39#include <inet/endpoint.h>
[c5808b41]40#include <io/log.h>
[0093ab6]41#include <macros.h>
[2989c7e]42#include <nettl/amap.h>
43#include <stdbool.h>
[c5808b41]44#include <stdlib.h>
45#include "conn.h"
46#include "iqueue.h"
47#include "segment.h"
48#include "seq_no.h"
49#include "tcp_type.h"
50#include "tqueue.h"
[762b48a]51#include "ucall.h"
[c5808b41]52
[a52de0e]53#define RCV_BUF_SIZE 4096/*2*/
[32105348]54#define SND_BUF_SIZE 4096
[0093ab6]55
[2a3214e]56#define MAX_SEGMENT_LIFETIME (15*1000*1000) //(2*60*1000*1000)
57#define TIME_WAIT_TIMEOUT (2*MAX_SEGMENT_LIFETIME)
58
[2989c7e]59static LIST_INITIALIZE(conn_list);
60static FIBRIL_MUTEX_INITIALIZE(conn_list_lock);
61static amap_t *amap;
[c5808b41]62
63static void tcp_conn_seg_process(tcp_conn_t *conn, tcp_segment_t *seg);
[2a3214e]64static void tcp_conn_tw_timer_set(tcp_conn_t *conn);
[704586fb]65static void tcp_conn_tw_timer_clear(tcp_conn_t *conn);
[c5808b41]66
[2989c7e]67/** Initialize connections. */
68int tcp_conns_init(void)
69{
70 int rc;
71
72 rc = amap_create(&amap);
73 if (rc != EOK) {
74 assert(rc == ENOMEM);
75 return ENOMEM;
76 }
77
78 return EOK;
79}
80
[7a8c1c4e]81/** Create new connection structure.
[032bbe7]82 *
[2f19103]83 * @param epp Endpoint pair (will be deeply copied)
[7a8c1c4e]84 * @return New connection or NULL
[032bbe7]85 */
[2f19103]86tcp_conn_t *tcp_conn_new(inet_ep2_t *epp)
[c5808b41]87{
[2a3214e]88 tcp_conn_t *conn = NULL;
[7cf7ded]89 bool tqueue_inited = false;
[c5808b41]90
[0093ab6]91 /* Allocate connection structure */
[c5808b41]92 conn = calloc(1, sizeof(tcp_conn_t));
93 if (conn == NULL)
[2a3214e]94 goto error;
95
[78192cc7]96 fibril_mutex_initialize(&conn->lock);
97
98 conn->tw_timer = fibril_timer_create(&conn->lock);
[2a3214e]99 if (conn->tw_timer == NULL)
100 goto error;
[c5808b41]101
[0edaf0f6]102 /* One for the user, one for not being in closed state */
103 atomic_set(&conn->refcnt, 2);
104
[0093ab6]105 /* Allocate receive buffer */
[d9ce049]106 fibril_condvar_initialize(&conn->rcv_buf_cv);
[0093ab6]107 conn->rcv_buf_size = RCV_BUF_SIZE;
108 conn->rcv_buf_used = 0;
[8c7a054]109 conn->rcv_buf_fin = false;
[d9ce049]110
[0093ab6]111 conn->rcv_buf = calloc(1, conn->rcv_buf_size);
[2a3214e]112 if (conn->rcv_buf == NULL)
113 goto error;
[0093ab6]114
[32105348]115 /** Allocate send buffer */
[bbf159a]116 fibril_condvar_initialize(&conn->snd_buf_cv);
[32105348]117 conn->snd_buf_size = SND_BUF_SIZE;
118 conn->snd_buf_used = 0;
[8c7a054]119 conn->snd_buf_fin = false;
[32105348]120 conn->snd_buf = calloc(1, conn->snd_buf_size);
[2a3214e]121 if (conn->snd_buf == NULL)
122 goto error;
[32105348]123
[0093ab6]124 /* Set up receive window. */
125 conn->rcv_wnd = conn->rcv_buf_size;
126
127 /* Initialize incoming segment queue */
[c5808b41]128 tcp_iqueue_init(&conn->incoming, conn);
129
[6df418c4]130 /* Initialize retransmission queue */
[7cf7ded]131 if (tcp_tqueue_init(&conn->retransmit, conn) != EOK)
132 goto error;
133
134 tqueue_inited = true;
[6df418c4]135
[004a5fe]136 /* Connection state change signalling */
137 fibril_condvar_initialize(&conn->cstate_cv);
138
[779541b]139 conn->cb = NULL;
[ae481e0]140
[c5808b41]141 conn->cstate = st_listen;
[d9e14fa4]142 conn->reset = false;
[7a8c1c4e]143 conn->deleted = false;
[d9e14fa4]144 conn->ap = ap_passive;
[6df418c4]145 conn->fin_is_acked = false;
[2f19103]146 if (epp != NULL)
147 conn->ident = *epp;
[c5808b41]148
149 return conn;
[2a3214e]150
151error:
[7cf7ded]152 if (tqueue_inited)
153 tcp_tqueue_fini(&conn->retransmit);
[2a3214e]154 if (conn != NULL && conn->rcv_buf != NULL)
155 free(conn->rcv_buf);
156 if (conn != NULL && conn->snd_buf != NULL)
157 free(conn->snd_buf);
158 if (conn != NULL && conn->tw_timer != NULL)
159 fibril_timer_destroy(conn->tw_timer);
160 if (conn != NULL)
161 free(conn);
162
163 return NULL;
[c5808b41]164}
165
[7a8c1c4e]166/** Destroy connection structure.
167 *
[0edaf0f6]168 * Connection structure should be destroyed when the folowing condtitions
169 * are met:
170 * (1) user has deleted the connection
171 * (2) the connection has entered closed state
172 * (3) nobody is holding references to the connection
173 *
174 * This happens when @a conn->refcnt is zero as we count (1) and (2)
175 * as special references.
[7a8c1c4e]176 *
177 * @param conn Connection
178 */
179static void tcp_conn_free(tcp_conn_t *conn)
180{
[a1a101d]181 log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: tcp_conn_free(%p)", conn->name, conn);
[7a8c1c4e]182 tcp_tqueue_fini(&conn->retransmit);
183
184 if (conn->rcv_buf != NULL)
185 free(conn->rcv_buf);
186 if (conn->snd_buf != NULL)
187 free(conn->snd_buf);
188 if (conn->tw_timer != NULL)
189 fibril_timer_destroy(conn->tw_timer);
190 free(conn);
191}
192
[0edaf0f6]193/** Add reference to connection.
194 *
195 * Increase connection reference count by one.
196 *
197 * @param conn Connection
198 */
199void tcp_conn_addref(tcp_conn_t *conn)
200{
[8d48c7e]201 log_msg(LOG_DEFAULT, LVL_DEBUG2, "%s: tcp_conn_addref(%p) before=%zu",
202 conn->name, conn, atomic_get(&conn->refcnt));
[0edaf0f6]203 atomic_inc(&conn->refcnt);
204}
205
206/** Remove reference from connection.
207 *
208 * Decrease connection reference count by one.
209 *
210 * @param conn Connection
211 */
212void tcp_conn_delref(tcp_conn_t *conn)
213{
[8d48c7e]214 log_msg(LOG_DEFAULT, LVL_DEBUG2, "%s: tcp_conn_delref(%p) before=%zu",
215 conn->name, conn, atomic_get(&conn->refcnt));
[0edaf0f6]216
217 if (atomic_predec(&conn->refcnt) == 0)
218 tcp_conn_free(conn);
219}
220
[78192cc7]221/** Lock connection.
222 *
223 * Must be called before any other connection-manipulating function,
224 * except tcp_conn_{add|del}ref(). Locks the connection including
225 * its timers. Must not be called inside any of the connection
226 * timer handlers.
227 *
228 * @param conn Connection
229 */
230void tcp_conn_lock(tcp_conn_t *conn)
231{
232 fibril_mutex_lock(&conn->lock);
233}
234
235/** Unlock connection.
236 *
237 * @param conn Connection
238 */
239void tcp_conn_unlock(tcp_conn_t *conn)
240{
241 fibril_mutex_unlock(&conn->lock);
242}
243
[7a8c1c4e]244/** Delete connection.
245 *
246 * The caller promises not make no further references to @a conn.
247 * TCP will free @a conn eventually.
248 *
249 * @param conn Connection
250 */
251void tcp_conn_delete(tcp_conn_t *conn)
252{
[a1a101d]253 log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: tcp_conn_delete(%p)", conn->name, conn);
[7a8c1c4e]254
[0edaf0f6]255 assert(conn->deleted == false);
[bf7587b0]256 conn->deleted = true;
257 conn->cb = NULL;
258 conn->cb_arg = NULL;
[0edaf0f6]259 tcp_conn_delref(conn);
[7a8c1c4e]260}
261
[032bbe7]262/** Enlist connection.
263 *
264 * Add connection to the connection map.
265 */
[2989c7e]266int tcp_conn_add(tcp_conn_t *conn)
[c5808b41]267{
[2989c7e]268 inet_ep2_t aepp;
269 int rc;
270
[e1c6dde9]271 tcp_conn_addref(conn);
[0edaf0f6]272 fibril_mutex_lock(&conn_list_lock);
[2989c7e]273
[8d48c7e]274 log_msg(LOG_DEFAULT, LVL_NOTE, "tcp_conn_add: conn=%p", conn);
275
[2989c7e]276 rc = amap_insert(amap, &conn->ident, conn, af_allow_system, &aepp);
277 if (rc != EOK) {
278 tcp_conn_delref(conn);
279 fibril_mutex_unlock(&conn_list_lock);
280 return rc;
281 }
282
283 conn->ident = aepp;
[c5808b41]284 list_append(&conn->link, &conn_list);
[0edaf0f6]285 fibril_mutex_unlock(&conn_list_lock);
[2989c7e]286
287 return EOK;
[c5808b41]288}
289
[6e88fea]290/** Delist connection.
291 *
292 * Remove connection from the connection map.
293 */
294void tcp_conn_remove(tcp_conn_t *conn)
295{
[0edaf0f6]296 fibril_mutex_lock(&conn_list_lock);
[2989c7e]297 amap_remove(amap, &conn->ident);
[6e88fea]298 list_remove(&conn->link);
[0edaf0f6]299 fibril_mutex_unlock(&conn_list_lock);
[e1c6dde9]300 tcp_conn_delref(conn);
[6e88fea]301}
302
[004a5fe]303static void tcp_conn_state_set(tcp_conn_t *conn, tcp_cstate_t nstate)
304{
[0edaf0f6]305 tcp_cstate_t old_state;
306
[a1a101d]307 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_state_set(%p)", conn);
[ae481e0]308
[0edaf0f6]309 old_state = conn->cstate;
[004a5fe]310 conn->cstate = nstate;
311 fibril_condvar_broadcast(&conn->cstate_cv);
[7a8c1c4e]312
[ae481e0]313 /* Run user callback function */
[779541b]314 if (conn->cb != NULL && conn->cb->cstate_change != NULL) {
[a1a101d]315 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_state_set() - run user CB");
[1d4b815]316 conn->cb->cstate_change(conn, conn->cb_arg, old_state);
[ae481e0]317 } else {
[a1a101d]318 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_state_set() - no user CB");
[ae481e0]319 }
320
[0edaf0f6]321 assert(old_state != st_closed);
322 if (nstate == st_closed) {
323 /* Drop one reference for now being in closed state */
324 tcp_conn_delref(conn);
[7a8c1c4e]325 }
[004a5fe]326}
327
[032bbe7]328/** Synchronize connection.
329 *
330 * This is the first step of an active connection attempt,
331 * sends out SYN and sets up ISS and SND.xxx.
332 */
[c5808b41]333void tcp_conn_sync(tcp_conn_t *conn)
334{
335 /* XXX select ISS */
336 conn->iss = 1;
337 conn->snd_nxt = conn->iss;
338 conn->snd_una = conn->iss;
[d9e14fa4]339 conn->ap = ap_active;
[c5808b41]340
341 tcp_tqueue_ctrl_seg(conn, CTL_SYN);
[004a5fe]342 tcp_conn_state_set(conn, st_syn_sent);
[c5808b41]343}
344
[f343a16]345/** FIN has been sent.
346 *
347 * This function should be called when FIN is sent over the connection,
348 * as a result the connection state is changed appropriately.
349 */
350void tcp_conn_fin_sent(tcp_conn_t *conn)
351{
352 switch (conn->cstate) {
353 case st_syn_received:
354 case st_established:
[a1a101d]355 log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: FIN sent -> Fin-Wait-1", conn->name);
[004a5fe]356 tcp_conn_state_set(conn, st_fin_wait_1);
[f343a16]357 break;
358 case st_close_wait:
[a1a101d]359 log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: FIN sent -> Last-Ack", conn->name);
[004a5fe]360 tcp_conn_state_set(conn, st_last_ack);
[f343a16]361 break;
362 default:
[a1a101d]363 log_msg(LOG_DEFAULT, LVL_ERROR, "%s: Connection state %d", conn->name,
[6896409c]364 conn->cstate);
[f343a16]365 assert(false);
366 }
[6df418c4]367
368 conn->fin_is_acked = false;
[f343a16]369}
370
[2f19103]371/** Find connection structure for specified endpoint pair.
[032bbe7]372 *
[2f19103]373 * A connection is uniquely identified by a endpoint pair. Look up our
374 * connection map and return connection structure based on endpoint pair.
[0edaf0f6]375 * The connection reference count is bumped by one.
[032bbe7]376 *
[2f19103]377 * @param epp Endpoint pair
[032bbe7]378 * @return Connection structure or NULL if not found.
379 */
[2f19103]380tcp_conn_t *tcp_conn_find_ref(inet_ep2_t *epp)
[c5808b41]381{
[8d48c7e]382 int rc;
383 void *arg;
384 tcp_conn_t *conn;
[2f19103]385
[8d48c7e]386 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_find_ref(%p)", epp);
[2f19103]387
[0edaf0f6]388 fibril_mutex_lock(&conn_list_lock);
[2f19103]389
[8d48c7e]390 rc = amap_find_match(amap, epp, &arg);
391 if (rc != EOK) {
392 assert(rc == ENOENT);
393 fibril_mutex_unlock(&conn_list_lock);
394 return NULL;
[c5808b41]395 }
[2f19103]396
[8d48c7e]397 conn = (tcp_conn_t *)arg;
398 tcp_conn_addref(conn);
399
[0edaf0f6]400 fibril_mutex_unlock(&conn_list_lock);
[8d48c7e]401 log_msg(LOG_DEFAULT, LVL_NOTE, "tcp_conn_find_ref: got conn=%p",
402 conn);
403 return conn;
[c5808b41]404}
405
[704586fb]406/** Reset connection.
407 *
408 * @param conn Connection
409 */
[b243da3]410void tcp_conn_reset(tcp_conn_t *conn)
[704586fb]411{
[a1a101d]412 log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: tcp_conn_reset()", conn->name);
[704586fb]413 tcp_conn_state_set(conn, st_closed);
[d9e14fa4]414 conn->reset = true;
415
[704586fb]416 tcp_conn_tw_timer_clear(conn);
417 tcp_tqueue_clear(&conn->retransmit);
[d9e14fa4]418
419 fibril_condvar_broadcast(&conn->rcv_buf_cv);
[bbf159a]420 fibril_condvar_broadcast(&conn->snd_buf_cv);
[d9e14fa4]421}
422
423/** Signal to the user that connection has been reset.
424 *
425 * Send an out-of-band signal to the user.
426 */
427static void tcp_reset_signal(tcp_conn_t *conn)
428{
429 /* TODO */
[a1a101d]430 log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: tcp_reset_signal()", conn->name);
[704586fb]431}
432
[32105348]433/** Determine if SYN has been received.
434 *
435 * @param conn Connection
436 * @return @c true if SYN has been received, @c false otherwise.
437 */
438bool tcp_conn_got_syn(tcp_conn_t *conn)
439{
440 switch (conn->cstate) {
441 case st_listen:
442 case st_syn_sent:
443 return false;
444 case st_syn_received:
445 case st_established:
446 case st_fin_wait_1:
447 case st_fin_wait_2:
448 case st_close_wait:
449 case st_closing:
450 case st_last_ack:
451 case st_time_wait:
452 return true;
453 case st_closed:
[a1a101d]454 log_msg(LOG_DEFAULT, LVL_WARN, "state=%d", (int) conn->cstate);
[32105348]455 assert(false);
456 }
457
458 assert(false);
459}
460
[032bbe7]461/** Segment arrived in Listen state.
462 *
463 * @param conn Connection
464 * @param seg Segment
465 */
[c5808b41]466static void tcp_conn_sa_listen(tcp_conn_t *conn, tcp_segment_t *seg)
467{
[a1a101d]468 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_sa_listen(%p, %p)", conn, seg);
[c5808b41]469
470 if ((seg->ctrl & CTL_RST) != 0) {
[a1a101d]471 log_msg(LOG_DEFAULT, LVL_DEBUG, "Ignoring incoming RST.");
[c5808b41]472 return;
473 }
474
475 if ((seg->ctrl & CTL_ACK) != 0) {
[a1a101d]476 log_msg(LOG_DEFAULT, LVL_DEBUG, "Incoming ACK, send acceptable RST.");
[c5808b41]477 tcp_reply_rst(&conn->ident, seg);
478 return;
479 }
480
481 if ((seg->ctrl & CTL_SYN) == 0) {
[a1a101d]482 log_msg(LOG_DEFAULT, LVL_DEBUG, "SYN not present. Ignoring segment.");
[c5808b41]483 return;
484 }
485
[a1a101d]486 log_msg(LOG_DEFAULT, LVL_DEBUG, "Got SYN, sending SYN, ACK.");
[c5808b41]487
488 conn->rcv_nxt = seg->seq + 1;
489 conn->irs = seg->seq;
490
[4c55a64]491
[a1a101d]492 log_msg(LOG_DEFAULT, LVL_DEBUG, "rcv_nxt=%u", conn->rcv_nxt);
[c5808b41]493
494 if (seg->len > 1)
[a1a101d]495 log_msg(LOG_DEFAULT, LVL_WARN, "SYN combined with data, ignoring data.");
[c5808b41]496
497 /* XXX select ISS */
498 conn->iss = 1;
499 conn->snd_nxt = conn->iss;
500 conn->snd_una = conn->iss;
501
[4c55a64]502 /*
503 * Surprisingly the spec does not deal with initial window setting.
504 * Set SND.WND = SEG.WND and set SND.WL1 so that next segment
505 * will always be accepted as new window setting.
506 */
507 conn->snd_wnd = seg->wnd;
508 conn->snd_wl1 = seg->seq;
509 conn->snd_wl2 = seg->seq;
510
[004a5fe]511 tcp_conn_state_set(conn, st_syn_received);
[c5808b41]512
513 tcp_tqueue_ctrl_seg(conn, CTL_SYN | CTL_ACK /* XXX */);
[0093ab6]514
515 tcp_segment_delete(seg);
[c5808b41]516}
517
[032bbe7]518/** Segment arrived in Syn-Sent state.
519 *
520 * @param conn Connection
521 * @param seg Segment
522 */
[c5808b41]523static void tcp_conn_sa_syn_sent(tcp_conn_t *conn, tcp_segment_t *seg)
524{
[a1a101d]525 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_sa_syn_sent(%p, %p)", conn, seg);
[c5808b41]526
527 if ((seg->ctrl & CTL_ACK) != 0) {
[a1a101d]528 log_msg(LOG_DEFAULT, LVL_DEBUG, "snd_una=%u, seg.ack=%u, snd_nxt=%u",
[c5808b41]529 conn->snd_una, seg->ack, conn->snd_nxt);
530 if (!seq_no_ack_acceptable(conn, seg->ack)) {
[2f0dd2a]531 if ((seg->ctrl & CTL_RST) == 0) {
[a1a101d]532 log_msg(LOG_DEFAULT, LVL_WARN, "ACK not acceptable, send RST");
[2f0dd2a]533 tcp_reply_rst(&conn->ident, seg);
534 } else {
[a1a101d]535 log_msg(LOG_DEFAULT, LVL_WARN, "RST,ACK not acceptable, drop");
[2f0dd2a]536 }
[c5808b41]537 return;
538 }
539 }
540
541 if ((seg->ctrl & CTL_RST) != 0) {
[2f0dd2a]542 /* If we get here, we have either an acceptable ACK or no ACK */
543 if ((seg->ctrl & CTL_ACK) != 0) {
[a1a101d]544 log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: Connection reset. -> Closed",
[2f0dd2a]545 conn->name);
546 /* Reset connection */
547 tcp_conn_reset(conn);
548 return;
549 } else {
[a1a101d]550 log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: RST without ACK, drop",
[2f0dd2a]551 conn->name);
552 return;
553 }
[c5808b41]554 }
555
556 /* XXX precedence */
557
558 if ((seg->ctrl & CTL_SYN) == 0) {
[a1a101d]559 log_msg(LOG_DEFAULT, LVL_DEBUG, "No SYN bit, ignoring segment.");
[c5808b41]560 return;
561 }
562
563 conn->rcv_nxt = seg->seq + 1;
564 conn->irs = seg->seq;
565
566 if ((seg->ctrl & CTL_ACK) != 0) {
567 conn->snd_una = seg->ack;
[d9ce049]568
569 /*
570 * Prune acked segments from retransmission queue and
571 * possibly transmit more data.
572 */
573 tcp_tqueue_ack_received(conn);
[c5808b41]574 }
575
[a1a101d]576 log_msg(LOG_DEFAULT, LVL_DEBUG, "Sent SYN, got SYN.");
[c5808b41]577
[32105348]578 /*
579 * Surprisingly the spec does not deal with initial window setting.
580 * Set SND.WND = SEG.WND and set SND.WL1 so that next segment
581 * will always be accepted as new window setting.
582 */
[a1a101d]583 log_msg(LOG_DEFAULT, LVL_DEBUG, "SND.WND := %" PRIu32 ", SND.WL1 := %" PRIu32 ", "
[32105348]584 "SND.WL2 = %" PRIu32, seg->wnd, seg->seq, seg->seq);
585 conn->snd_wnd = seg->wnd;
586 conn->snd_wl1 = seg->seq;
587 conn->snd_wl2 = seg->seq;
588
[c5808b41]589 if (seq_no_syn_acked(conn)) {
[a1a101d]590 log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: syn acked -> Established", conn->name);
[004a5fe]591 tcp_conn_state_set(conn, st_established);
[c5808b41]592 tcp_tqueue_ctrl_seg(conn, CTL_ACK /* XXX */);
593 } else {
[a1a101d]594 log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: syn not acked -> Syn-Received",
[6896409c]595 conn->name);
[004a5fe]596 tcp_conn_state_set(conn, st_syn_received);
[c5808b41]597 tcp_tqueue_ctrl_seg(conn, CTL_SYN | CTL_ACK /* XXX */);
598 }
[0093ab6]599
600 tcp_segment_delete(seg);
[c5808b41]601}
602
[032bbe7]603/** Segment arrived in state where segments are processed in sequence order.
604 *
605 * Queue segment in incoming segments queue for processing.
606 *
607 * @param conn Connection
608 * @param seg Segment
609 */
[c5808b41]610static void tcp_conn_sa_queue(tcp_conn_t *conn, tcp_segment_t *seg)
611{
612 tcp_segment_t *pseg;
613
[a1a101d]614 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_sa_seq(%p, %p)", conn, seg);
[c5808b41]615
[7cf7ded]616 /* Discard unacceptable segments ("old duplicates") */
617 if (!seq_no_segment_acceptable(conn, seg)) {
[a1a101d]618 log_msg(LOG_DEFAULT, LVL_DEBUG, "Replying ACK to unacceptable segment.");
[7cf7ded]619 tcp_tqueue_ctrl_seg(conn, CTL_ACK);
620 tcp_segment_delete(seg);
621 return;
622 }
[c5808b41]623
624 /* Queue for processing */
625 tcp_iqueue_insert_seg(&conn->incoming, seg);
626
627 /*
628 * Process all segments from incoming queue that are ready.
629 * Unacceptable segments are discarded by tcp_iqueue_get_ready_seg().
630 *
631 * XXX Need to return ACK for unacceptable segments
632 */
633 while (tcp_iqueue_get_ready_seg(&conn->incoming, &pseg) == EOK)
634 tcp_conn_seg_process(conn, pseg);
635}
636
[032bbe7]637/** Process segment RST field.
638 *
639 * @param conn Connection
640 * @param seg Segment
641 * @return cp_done if we are done with this segment, cp_continue
642 * if not
643 */
[c5808b41]644static cproc_t tcp_conn_seg_proc_rst(tcp_conn_t *conn, tcp_segment_t *seg)
645{
[03be171]646 if ((seg->ctrl & CTL_RST) == 0)
647 return cp_continue;
648
[d9e14fa4]649 switch (conn->cstate) {
650 case st_syn_received:
651 /* XXX In case of passive open, revert to Listen state */
652 if (conn->ap == ap_passive) {
653 tcp_conn_state_set(conn, st_listen);
654 /* XXX Revert conn->ident */
655 tcp_conn_tw_timer_clear(conn);
656 tcp_tqueue_clear(&conn->retransmit);
657 } else {
658 tcp_conn_reset(conn);
659 }
660 break;
661 case st_established:
662 case st_fin_wait_1:
663 case st_fin_wait_2:
664 case st_close_wait:
665 /* General "connection reset" signal */
666 tcp_reset_signal(conn);
667 tcp_conn_reset(conn);
668 break;
669 case st_closing:
670 case st_last_ack:
671 case st_time_wait:
672 tcp_conn_reset(conn);
673 break;
674 case st_listen:
675 case st_syn_sent:
676 case st_closed:
677 assert(false);
678 }
679
680 return cp_done;
[c5808b41]681}
682
[032bbe7]683/** Process segment security and precedence fields.
684 *
685 * @param conn Connection
686 * @param seg Segment
687 * @return cp_done if we are done with this segment, cp_continue
688 * if not
689 */
[c5808b41]690static cproc_t tcp_conn_seg_proc_sp(tcp_conn_t *conn, tcp_segment_t *seg)
691{
[4c55a64]692 /* TODO */
[c5808b41]693 return cp_continue;
694}
695
[032bbe7]696/** Process segment SYN field.
697 *
698 * @param conn Connection
699 * @param seg Segment
700 * @return cp_done if we are done with this segment, cp_continue
701 * if not
702 */
[c5808b41]703static cproc_t tcp_conn_seg_proc_syn(tcp_conn_t *conn, tcp_segment_t *seg)
704{
[7cf7ded]705 if ((seg->ctrl & CTL_SYN) == 0)
706 return cp_continue;
707
708 /*
709 * Assert SYN is in receive window, otherwise this step should not
710 * be reached.
711 */
712 assert(seq_no_in_rcv_wnd(conn, seg->seq));
713
[a1a101d]714 log_msg(LOG_DEFAULT, LVL_WARN, "SYN is in receive window, should send reset. XXX");
[7cf7ded]715
716 /*
717 * TODO
718 *
719 * Send a reset, resond "reset" to all outstanding RECEIVEs and SEND,
720 * flush segment queues. Send unsolicited "connection reset" signal
721 * to user, connection -> closed state, delete TCB, return.
722 */
723 return cp_done;
[c5808b41]724}
725
[032bbe7]726/** Process segment ACK field in Syn-Received state.
727 *
728 * @param conn Connection
729 * @param seg Segment
730 * @return cp_done if we are done with this segment, cp_continue
731 * if not
732 */
[c5808b41]733static cproc_t tcp_conn_seg_proc_ack_sr(tcp_conn_t *conn, tcp_segment_t *seg)
734{
735 if (!seq_no_ack_acceptable(conn, seg->ack)) {
736 /* ACK is not acceptable, send RST. */
[a1a101d]737 log_msg(LOG_DEFAULT, LVL_WARN, "Segment ACK not acceptable, sending RST.");
[c5808b41]738 tcp_reply_rst(&conn->ident, seg);
[4c55a64]739 tcp_segment_delete(seg);
740 return cp_done;
[c5808b41]741 }
742
[a1a101d]743 log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: SYN ACKed -> Established", conn->name);
[c5808b41]744
[004a5fe]745 tcp_conn_state_set(conn, st_established);
[c5808b41]746
747 /* XXX Not mentioned in spec?! */
748 conn->snd_una = seg->ack;
749
750 return cp_continue;
751}
752
[032bbe7]753/** Process segment ACK field in Established state.
754 *
755 * @param conn Connection
756 * @param seg Segment
757 * @return cp_done if we are done with this segment, cp_continue
758 * if not
759 */
[c5808b41]760static cproc_t tcp_conn_seg_proc_ack_est(tcp_conn_t *conn, tcp_segment_t *seg)
761{
[a1a101d]762 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_seg_proc_ack_est(%p, %p)", conn, seg);
[0093ab6]763
[a1a101d]764 log_msg(LOG_DEFAULT, LVL_DEBUG, "SEG.ACK=%u, SND.UNA=%u, SND.NXT=%u",
[0093ab6]765 (unsigned)seg->ack, (unsigned)conn->snd_una,
766 (unsigned)conn->snd_nxt);
767
[4c55a64]768 if (!seq_no_ack_acceptable(conn, seg->ack)) {
[a1a101d]769 log_msg(LOG_DEFAULT, LVL_DEBUG, "ACK not acceptable.");
[4c55a64]770 if (!seq_no_ack_duplicate(conn, seg->ack)) {
[a1a101d]771 log_msg(LOG_DEFAULT, LVL_WARN, "Not acceptable, not duplicate. "
[0093ab6]772 "Send ACK and drop.");
[4c55a64]773 /* Not acceptable, not duplicate. Send ACK and drop. */
774 tcp_tqueue_ctrl_seg(conn, CTL_ACK);
775 tcp_segment_delete(seg);
776 return cp_done;
[0093ab6]777 } else {
[a1a101d]778 log_msg(LOG_DEFAULT, LVL_DEBUG, "Ignoring duplicate ACK.");
[4c55a64]779 }
780 } else {
781 /* Update SND.UNA */
782 conn->snd_una = seg->ack;
783 }
784
785 if (seq_no_new_wnd_update(conn, seg)) {
786 conn->snd_wnd = seg->wnd;
787 conn->snd_wl1 = seg->seq;
788 conn->snd_wl2 = seg->ack;
[d9ce049]789
[a1a101d]790 log_msg(LOG_DEFAULT, LVL_DEBUG, "Updating send window, SND.WND=%" PRIu32
[d9ce049]791 ", SND.WL1=%" PRIu32 ", SND.WL2=%" PRIu32,
792 conn->snd_wnd, conn->snd_wl1, conn->snd_wl2);
[4c55a64]793 }
794
[d9ce049]795 /*
796 * Prune acked segments from retransmission queue and
797 * possibly transmit more data.
798 */
799 tcp_tqueue_ack_received(conn);
800
[c5808b41]801 return cp_continue;
802}
803
[032bbe7]804/** Process segment ACK field in Fin-Wait-1 state.
805 *
806 * @param conn Connection
807 * @param seg Segment
808 * @return cp_done if we are done with this segment, cp_continue
809 * if not
810 */
[c5808b41]811static cproc_t tcp_conn_seg_proc_ack_fw1(tcp_conn_t *conn, tcp_segment_t *seg)
812{
[4c55a64]813 if (tcp_conn_seg_proc_ack_est(conn, seg) == cp_done)
814 return cp_done;
815
[6df418c4]816 if (conn->fin_is_acked) {
[a1a101d]817 log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: FIN acked -> Fin-Wait-2", conn->name);
[004a5fe]818 tcp_conn_state_set(conn, st_fin_wait_2);
[6df418c4]819 }
820
[c5808b41]821 return cp_continue;
822}
823
[032bbe7]824/** Process segment ACK field in Fin-Wait-2 state.
825 *
826 * @param conn Connection
827 * @param seg Segment
828 * @return cp_done if we are done with this segment, cp_continue
829 * if not
830 */
[c5808b41]831static cproc_t tcp_conn_seg_proc_ack_fw2(tcp_conn_t *conn, tcp_segment_t *seg)
832{
[4c55a64]833 if (tcp_conn_seg_proc_ack_est(conn, seg) == cp_done)
834 return cp_done;
835
836 /* TODO */
[c5808b41]837 return cp_continue;
838}
839
[032bbe7]840/** Process segment ACK field in Close-Wait state.
841 *
842 * @param conn Connection
843 * @param seg Segment
844 * @return cp_done if we are done with this segment, cp_continue
845 * if not
846 */
[c5808b41]847static cproc_t tcp_conn_seg_proc_ack_cw(tcp_conn_t *conn, tcp_segment_t *seg)
848{
[4c55a64]849 /* The same processing as in Established state */
850 return tcp_conn_seg_proc_ack_est(conn, seg);
[c5808b41]851}
852
[032bbe7]853/** Process segment ACK field in Closing state.
854 *
855 * @param conn Connection
856 * @param seg Segment
857 * @return cp_done if we are done with this segment, cp_continue
858 * if not
859 */
[c5808b41]860static cproc_t tcp_conn_seg_proc_ack_cls(tcp_conn_t *conn, tcp_segment_t *seg)
861{
[4c55a64]862 if (tcp_conn_seg_proc_ack_est(conn, seg) == cp_done)
863 return cp_done;
864
865 /* TODO */
[c5808b41]866 return cp_continue;
867}
868
[032bbe7]869/** Process segment ACK field in Last-Ack state.
870 *
871 * @param conn Connection
872 * @param seg Segment
873 * @return cp_done if we are done with this segment, cp_continue
874 * if not
875 */
[c5808b41]876static cproc_t tcp_conn_seg_proc_ack_la(tcp_conn_t *conn, tcp_segment_t *seg)
877{
[4c55a64]878 if (tcp_conn_seg_proc_ack_est(conn, seg) == cp_done)
879 return cp_done;
880
[6e88fea]881 if (conn->fin_is_acked) {
[a1a101d]882 log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: FIN acked -> Closed", conn->name);
[6e88fea]883 tcp_conn_remove(conn);
[004a5fe]884 tcp_conn_state_set(conn, st_closed);
[6e88fea]885 return cp_done;
886 }
887
[c5808b41]888 return cp_continue;
889}
890
[032bbe7]891/** Process segment ACK field in Time-Wait state.
892 *
893 * @param conn Connection
894 * @param seg Segment
895 * @return cp_done if we are done with this segment, cp_continue
896 * if not
897 */
[c5808b41]898static cproc_t tcp_conn_seg_proc_ack_tw(tcp_conn_t *conn, tcp_segment_t *seg)
899{
[4c55a64]900 /* Nothing to do */
[c5808b41]901 return cp_continue;
902}
903
[032bbe7]904/** Process segment ACK field.
905 *
906 * @param conn Connection
907 * @param seg Segment
908 * @return cp_done if we are done with this segment, cp_continue
909 * if not
910 */
[c5808b41]911static cproc_t tcp_conn_seg_proc_ack(tcp_conn_t *conn, tcp_segment_t *seg)
912{
[a1a101d]913 log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: tcp_conn_seg_proc_ack(%p, %p)",
[23fe06c]914 conn->name, conn, seg);
[c5808b41]915
916 if ((seg->ctrl & CTL_ACK) == 0) {
[a1a101d]917 log_msg(LOG_DEFAULT, LVL_WARN, "Segment has no ACK. Dropping.");
[4c55a64]918 tcp_segment_delete(seg);
[c5808b41]919 return cp_done;
920 }
921
922 switch (conn->cstate) {
923 case st_syn_received:
924 return tcp_conn_seg_proc_ack_sr(conn, seg);
925 case st_established:
926 return tcp_conn_seg_proc_ack_est(conn, seg);
927 case st_fin_wait_1:
928 return tcp_conn_seg_proc_ack_fw1(conn, seg);
929 case st_fin_wait_2:
930 return tcp_conn_seg_proc_ack_fw2(conn, seg);
931 case st_close_wait:
932 return tcp_conn_seg_proc_ack_cw(conn, seg);
933 case st_closing:
934 return tcp_conn_seg_proc_ack_cls(conn, seg);
935 case st_last_ack:
936 return tcp_conn_seg_proc_ack_la(conn, seg);
937 case st_time_wait:
938 return tcp_conn_seg_proc_ack_tw(conn, seg);
939 case st_listen:
940 case st_syn_sent:
941 case st_closed:
942 assert(false);
943 }
944
945 assert(false);
946}
947
[032bbe7]948/** Process segment URG field.
949 *
950 * @param conn Connection
951 * @param seg Segment
952 * @return cp_done if we are done with this segment, cp_continue
953 * if not
954 */
[c5808b41]955static cproc_t tcp_conn_seg_proc_urg(tcp_conn_t *conn, tcp_segment_t *seg)
956{
957 return cp_continue;
958}
959
[032bbe7]960/** Process segment text.
961 *
962 * @param conn Connection
963 * @param seg Segment
964 * @return cp_done if we are done with this segment, cp_continue
965 * if not
966 */
[c5808b41]967static cproc_t tcp_conn_seg_proc_text(tcp_conn_t *conn, tcp_segment_t *seg)
968{
[0093ab6]969 size_t text_size;
970 size_t xfer_size;
971
[a1a101d]972 log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: tcp_conn_seg_proc_text(%p, %p)",
[23fe06c]973 conn->name, conn, seg);
[0093ab6]974
[4c55a64]975 switch (conn->cstate) {
976 case st_established:
977 case st_fin_wait_1:
978 case st_fin_wait_2:
979 /* OK */
980 break;
981 case st_close_wait:
982 case st_closing:
983 case st_last_ack:
984 case st_time_wait:
985 /* Invalid since FIN has been received. Ignore text. */
986 return cp_continue;
987 case st_listen:
988 case st_syn_sent:
989 case st_syn_received:
990 case st_closed:
991 assert(false);
992 }
993
[0093ab6]994 /*
995 * Process segment text
996 */
997 assert(seq_no_segment_ready(conn, seg));
998
999 /* Trim anything outside our receive window */
1000 tcp_conn_trim_seg_to_wnd(conn, seg);
1001
1002 /* Determine how many bytes to copy */
1003 text_size = tcp_segment_text_size(seg);
1004 xfer_size = min(text_size, conn->rcv_buf_size - conn->rcv_buf_used);
1005
1006 /* Copy data to receive buffer */
[d9ce049]1007 tcp_segment_text_copy(seg, conn->rcv_buf + conn->rcv_buf_used,
1008 xfer_size);
1009 conn->rcv_buf_used += xfer_size;
1010
1011 /* Signal to the receive function that new data has arrived */
1012 fibril_condvar_broadcast(&conn->rcv_buf_cv);
[779541b]1013 if (conn->cb != NULL && conn->cb->recv_data != NULL)
1014 conn->cb->recv_data(conn, conn->cb_arg);
[0093ab6]1015
[a1a101d]1016 log_msg(LOG_DEFAULT, LVL_DEBUG, "Received %zu bytes of data.", xfer_size);
[32105348]1017
[0093ab6]1018 /* Advance RCV.NXT */
1019 conn->rcv_nxt += xfer_size;
1020
1021 /* Update receive window. XXX Not an efficient strategy. */
1022 conn->rcv_wnd -= xfer_size;
1023
1024 /* Send ACK */
1025 if (xfer_size > 0)
1026 tcp_tqueue_ctrl_seg(conn, CTL_ACK);
1027
1028 if (xfer_size < seg->len) {
[8c7a054]1029 /* Trim part of segment which we just received */
[0093ab6]1030 tcp_conn_trim_seg_to_wnd(conn, seg);
[8c7a054]1031 } else {
[a1a101d]1032 log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: Nothing left in segment, dropping "
[f0a2720]1033 "(xfer_size=%zu, SEG.LEN=%" PRIu32 ", seg->ctrl=%u)",
1034 conn->name, xfer_size, seg->len, (unsigned int) seg->ctrl);
[8c7a054]1035 /* Nothing left in segment */
1036 tcp_segment_delete(seg);
[0093ab6]1037 return cp_done;
1038 }
1039
[c5808b41]1040 return cp_continue;
1041}
1042
[032bbe7]1043/** Process segment FIN field.
1044 *
1045 * @param conn Connection
1046 * @param seg Segment
1047 * @return cp_done if we are done with this segment, cp_continue
1048 * if not
1049 */
[c5808b41]1050static cproc_t tcp_conn_seg_proc_fin(tcp_conn_t *conn, tcp_segment_t *seg)
1051{
[a1a101d]1052 log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: tcp_conn_seg_proc_fin(%p, %p)",
[23fe06c]1053 conn->name, conn, seg);
[a1a101d]1054 log_msg(LOG_DEFAULT, LVL_DEBUG, " seg->len=%zu, seg->ctl=%u", (size_t) seg->len,
[7cf7ded]1055 (unsigned) seg->ctrl);
[8c7a054]1056
1057 /* Only process FIN if no text is left in segment. */
1058 if (tcp_segment_text_size(seg) == 0 && (seg->ctrl & CTL_FIN) != 0) {
[a1a101d]1059 log_msg(LOG_DEFAULT, LVL_DEBUG, " - FIN found in segment.");
[8c7a054]1060
[6e88fea]1061 /* Send ACK */
1062 tcp_tqueue_ctrl_seg(conn, CTL_ACK);
1063
[8c7a054]1064 conn->rcv_nxt++;
1065 conn->rcv_wnd--;
1066
[f343a16]1067 /* Change connection state */
1068 switch (conn->cstate) {
1069 case st_listen:
1070 case st_syn_sent:
1071 case st_closed:
1072 /* Connection not synchronized */
1073 assert(false);
1074 case st_syn_received:
1075 case st_established:
[a1a101d]1076 log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: FIN received -> Close-Wait",
[6896409c]1077 conn->name);
[004a5fe]1078 tcp_conn_state_set(conn, st_close_wait);
[f343a16]1079 break;
1080 case st_fin_wait_1:
[a1a101d]1081 log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: FIN received -> Closing",
[6896409c]1082 conn->name);
[004a5fe]1083 tcp_conn_state_set(conn, st_closing);
[f343a16]1084 break;
1085 case st_fin_wait_2:
[a1a101d]1086 log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: FIN received -> Time-Wait",
[6896409c]1087 conn->name);
[004a5fe]1088 tcp_conn_state_set(conn, st_time_wait);
[2a3214e]1089 /* Start the Time-Wait timer */
1090 tcp_conn_tw_timer_set(conn);
[f343a16]1091 break;
1092 case st_close_wait:
1093 case st_closing:
1094 case st_last_ack:
1095 /* Do nothing */
1096 break;
1097 case st_time_wait:
[2a3214e]1098 /* Restart the Time-Wait timer */
1099 tcp_conn_tw_timer_set(conn);
[f343a16]1100 break;
1101 }
[8c7a054]1102
1103 /* Add FIN to the receive buffer */
1104 conn->rcv_buf_fin = true;
1105 fibril_condvar_broadcast(&conn->rcv_buf_cv);
[779541b]1106 if (conn->cb != NULL && conn->cb->recv_data != NULL)
1107 conn->cb->recv_data(conn, conn->cb_arg);
[8c7a054]1108
1109 tcp_segment_delete(seg);
1110 return cp_done;
1111 }
1112
[c5808b41]1113 return cp_continue;
1114}
1115
1116/** Process incoming segment.
1117 *
1118 * We are in connection state where segments are processed in order
1119 * of sequence number. This processes one segment taken from the
1120 * connection incoming segments queue.
[032bbe7]1121 *
1122 * @param conn Connection
1123 * @param seg Segment
[c5808b41]1124 */
1125static void tcp_conn_seg_process(tcp_conn_t *conn, tcp_segment_t *seg)
1126{
[a1a101d]1127 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_conn_seg_process(%p, %p)", conn, seg);
[6896409c]1128 tcp_segment_dump(seg);
[c5808b41]1129
1130 /* Check whether segment is acceptable */
1131 /* XXX Permit valid ACKs, URGs and RSTs */
1132/* if (!seq_no_segment_acceptable(conn, seg)) {
[a1a101d]1133 log_msg(LOG_DEFAULT, LVL_WARN, "Segment not acceptable, dropping.");
[c5808b41]1134 if ((seg->ctrl & CTL_RST) == 0) {
1135 tcp_tqueue_ctrl_seg(conn, CTL_ACK);
1136 }
1137 return;
1138 }
1139*/
1140
1141 if (tcp_conn_seg_proc_rst(conn, seg) == cp_done)
1142 return;
1143
1144 if (tcp_conn_seg_proc_sp(conn, seg) == cp_done)
1145 return;
1146
1147 if (tcp_conn_seg_proc_syn(conn, seg) == cp_done)
1148 return;
1149
1150 if (tcp_conn_seg_proc_ack(conn, seg) == cp_done)
1151 return;
1152
1153 if (tcp_conn_seg_proc_urg(conn, seg) == cp_done)
1154 return;
1155
1156 if (tcp_conn_seg_proc_text(conn, seg) == cp_done)
1157 return;
1158
1159 if (tcp_conn_seg_proc_fin(conn, seg) == cp_done)
1160 return;
[0093ab6]1161
[8c7a054]1162 /*
1163 * If anything is left from the segment, insert it back into the
1164 * incoming segments queue.
1165 */
[7cf7ded]1166 if (seg->len > 0) {
[a1a101d]1167 log_msg(LOG_DEFAULT, LVL_DEBUG, "Re-insert segment %p. seg->len=%zu",
[7cf7ded]1168 seg, (size_t) seg->len);
[8c7a054]1169 tcp_iqueue_insert_seg(&conn->incoming, seg);
[7cf7ded]1170 } else {
[8c7a054]1171 tcp_segment_delete(seg);
[7cf7ded]1172 }
[c5808b41]1173}
1174
[032bbe7]1175/** Segment arrived on a connection.
1176 *
1177 * @param conn Connection
1178 * @param seg Segment
1179 */
[c5808b41]1180void tcp_conn_segment_arrived(tcp_conn_t *conn, tcp_segment_t *seg)
1181{
[8d48c7e]1182 log_msg(LOG_DEFAULT, LVL_NOTE, "conn=%p", conn);
1183 log_msg(LOG_DEFAULT, LVL_NOTE, "conn->name=%p", conn->name);
1184 log_msg(LOG_DEFAULT, LVL_NOTE, "%s: tcp_conn_segment_arrived(%p)",
[23fe06c]1185 conn->name, seg);
[c5808b41]1186
1187 switch (conn->cstate) {
1188 case st_listen:
1189 tcp_conn_sa_listen(conn, seg); break;
1190 case st_syn_sent:
1191 tcp_conn_sa_syn_sent(conn, seg); break;
1192 case st_syn_received:
1193 case st_established:
1194 case st_fin_wait_1:
1195 case st_fin_wait_2:
1196 case st_close_wait:
1197 case st_closing:
1198 case st_last_ack:
1199 case st_time_wait:
1200 /* Process segments in order of sequence number */
1201 tcp_conn_sa_queue(conn, seg); break;
1202 case st_closed:
[a1a101d]1203 log_msg(LOG_DEFAULT, LVL_DEBUG, "state=%d", (int) conn->cstate);
[c5808b41]1204 assert(false);
1205 }
1206}
1207
[2a3214e]1208/** Time-Wait timeout handler.
1209 *
1210 * @param arg Connection
1211 */
1212static void tw_timeout_func(void *arg)
1213{
1214 tcp_conn_t *conn = (tcp_conn_t *) arg;
1215
[a1a101d]1216 log_msg(LOG_DEFAULT, LVL_DEBUG, "tw_timeout_func(%p)", conn);
[2a3214e]1217
[78192cc7]1218 tcp_conn_lock(conn);
[0edaf0f6]1219
[704586fb]1220 if (conn->cstate == st_closed) {
[a1a101d]1221 log_msg(LOG_DEFAULT, LVL_DEBUG, "Connection already closed.");
[78192cc7]1222 tcp_conn_unlock(conn);
[0edaf0f6]1223 tcp_conn_delref(conn);
[704586fb]1224 return;
1225 }
1226
[a1a101d]1227 log_msg(LOG_DEFAULT, LVL_DEBUG, "%s: TW Timeout -> Closed", conn->name);
[2a3214e]1228 tcp_conn_remove(conn);
[004a5fe]1229 tcp_conn_state_set(conn, st_closed);
[0edaf0f6]1230
[78192cc7]1231 tcp_conn_unlock(conn);
[0edaf0f6]1232 tcp_conn_delref(conn);
[78192cc7]1233
1234 log_msg(LOG_DEFAULT, LVL_DEBUG, "tw_timeout_func(%p) end", conn);
[2a3214e]1235}
1236
1237/** Start or restart the Time-Wait timeout.
1238 *
1239 * @param conn Connection
1240 */
1241void tcp_conn_tw_timer_set(tcp_conn_t *conn)
1242{
[78192cc7]1243 log_msg(LOG_DEFAULT, LVL_DEBUG2, "tcp_conn_tw_timer_set() begin");
[0edaf0f6]1244 tcp_conn_addref(conn);
[78192cc7]1245 fibril_timer_set_locked(conn->tw_timer, TIME_WAIT_TIMEOUT,
1246 tw_timeout_func, (void *)conn);
1247 log_msg(LOG_DEFAULT, LVL_DEBUG2, "tcp_conn_tw_timer_set() end");
[2a3214e]1248}
1249
[704586fb]1250/** Clear the Time-Wait timeout.
1251 *
1252 * @param conn Connection
1253 */
1254void tcp_conn_tw_timer_clear(tcp_conn_t *conn)
1255{
[78192cc7]1256 log_msg(LOG_DEFAULT, LVL_DEBUG2, "tcp_conn_tw_timer_clear() begin");
1257 if (fibril_timer_clear_locked(conn->tw_timer) == fts_active)
[0edaf0f6]1258 tcp_conn_delref(conn);
[78192cc7]1259 log_msg(LOG_DEFAULT, LVL_DEBUG2, "tcp_conn_tw_timer_clear() end");
[704586fb]1260}
1261
[032bbe7]1262/** Trim segment to the receive window.
1263 *
1264 * @param conn Connection
1265 * @param seg Segment
1266 */
[0093ab6]1267void tcp_conn_trim_seg_to_wnd(tcp_conn_t *conn, tcp_segment_t *seg)
1268{
1269 uint32_t left, right;
1270
1271 seq_no_seg_trim_calc(conn, seg, &left, &right);
1272 tcp_segment_trim(seg, left, right);
1273}
1274
[2f19103]1275/** Handle unexpected segment received on an endpoint pair.
[032bbe7]1276 *
1277 * We reply with an RST unless the received segment has RST.
1278 *
[2f19103]1279 * @param sp Endpoint pair which received the segment
[032bbe7]1280 * @param seg Unexpected segment
1281 */
[2f19103]1282void tcp_unexpected_segment(inet_ep2_t *epp, tcp_segment_t *seg)
[c5808b41]1283{
[2f19103]1284 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_unexpected_segment(%p, %p)", epp,
1285 seg);
[c5808b41]1286
1287 if ((seg->ctrl & CTL_RST) == 0)
[2f19103]1288 tcp_reply_rst(epp, seg);
[c5808b41]1289}
1290
[2f19103]1291/** Compute flipped endpoint pair for response.
[032bbe7]1292 *
[2f19103]1293 * Flipped endpoint pair has local and remote endpoints exchanged.
[032bbe7]1294 *
[2f19103]1295 * @param epp Endpoint pair
1296 * @param fepp Place to store flipped endpoint pair
[032bbe7]1297 */
[2f19103]1298void tcp_ep2_flipped(inet_ep2_t *epp, inet_ep2_t *fepp)
[c5808b41]1299{
[2f19103]1300 fepp->local = epp->remote;
1301 fepp->remote = epp->local;
[c5808b41]1302}
1303
[032bbe7]1304/** Send RST in response to an incoming segment.
1305 *
[2f19103]1306 * @param epp Endpoint pair which received the segment
[032bbe7]1307 * @param seg Incoming segment
1308 */
[2f19103]1309void tcp_reply_rst(inet_ep2_t *epp, tcp_segment_t *seg)
[c5808b41]1310{
1311 tcp_segment_t *rseg;
1312
[2f19103]1313 log_msg(LOG_DEFAULT, LVL_DEBUG, "tcp_reply_rst(%p, %p)", epp, seg);
[c5808b41]1314
1315 rseg = tcp_segment_make_rst(seg);
[2f19103]1316 tcp_transmit_segment(epp, rseg);
[c5808b41]1317}
1318
1319/**
1320 * @}
1321 */
Note: See TracBrowser for help on using the repository browser.