source: mainline/uspace/srv/net/tcp/conn.c@ 7c912b6

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

Fix delivery of end-of-connection condition.

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