source: mainline/uspace/srv/net/tcp/conn.c@ 0a1e7e4

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

Connection can still be mapped when being deleted, must be unmapped before it is freed.

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