source: mainline/uspace/srv/net/tl/tcp/tqueue.c@ 2a3214e

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

Retransmission queue, detect ACK of FIN.

  • Property mode set to 100644
File size: 5.6 KB
Line 
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/**
34 * @file TCP transmission queue
35 */
36
37#include <adt/list.h>
38#include <byteorder.h>
39#include <io/log.h>
40#include <macros.h>
41#include <mem.h>
42#include <stdlib.h>
43#include "conn.h"
44#include "header.h"
45#include "rqueue.h"
46#include "segment.h"
47#include "seq_no.h"
48#include "tqueue.h"
49#include "tcp_type.h"
50
51void tcp_tqueue_init(tcp_tqueue_t *tqueue, tcp_conn_t *conn)
52{
53 tqueue->conn = conn;
54 list_initialize(&tqueue->list);
55}
56
57void tcp_tqueue_ctrl_seg(tcp_conn_t *conn, tcp_control_t ctrl)
58{
59 tcp_segment_t *seg;
60
61 log_msg(LVL_DEBUG, "tcp_tqueue_ctrl_seg(%p, %u)", conn, ctrl);
62
63 seg = tcp_segment_make_ctrl(ctrl);
64 tcp_tqueue_seg(conn, seg);
65}
66
67void tcp_tqueue_seg(tcp_conn_t *conn, tcp_segment_t *seg)
68{
69 tcp_segment_t *rt_seg;
70 tcp_tqueue_entry_t *tqe;
71
72 log_msg(LVL_DEBUG, "tcp_tqueue_seg(%p, %p)", conn, seg);
73
74 /*
75 * Add segment to retransmission queue
76 */
77
78 if (seg->len > 0) {
79 rt_seg = tcp_segment_dup(seg);
80 if (rt_seg == NULL) {
81 log_msg(LVL_ERROR, "Memory allocation failed.");
82 /* XXX Handle properly */
83 return;
84 }
85
86 tqe = calloc(1, sizeof(tcp_tqueue_entry_t));
87 if (tqe == NULL) {
88 log_msg(LVL_ERROR, "Memory allocation failed.");
89 /* XXX Handle properly */
90 return;
91 }
92
93 tqe->seg = rt_seg;
94 list_append(&tqe->link, &conn->retransmit.list);
95 }
96
97 /*
98 * Always send ACK once we have received SYN, except for RST segments.
99 * (Spec says we should always send ACK once connection has been
100 * established.)
101 */
102 if (tcp_conn_got_syn(conn) && (seg->ctrl & CTL_RST) == 0)
103 seg->ctrl |= CTL_ACK;
104
105 seg->seq = conn->snd_nxt;
106 seg->wnd = conn->rcv_wnd;
107
108 log_msg(LVL_DEBUG, "SEG.SEQ=%" PRIu32 ", SEG.WND=%" PRIu32,
109 seg->seq, seg->wnd);
110
111 if ((seg->ctrl & CTL_ACK) != 0)
112 seg->ack = conn->rcv_nxt;
113 else
114 seg->ack = 0;
115
116 conn->snd_nxt += seg->len;
117
118 tcp_transmit_segment(&conn->ident, seg);
119}
120
121/** Transmit data from the send buffer.
122 *
123 * @param conn Connection
124 */
125void tcp_tqueue_new_data(tcp_conn_t *conn)
126{
127 size_t avail_wnd;
128 size_t xfer_seqlen;
129 size_t snd_buf_seqlen;
130 size_t data_size;
131 tcp_control_t ctrl;
132
133 tcp_segment_t *seg;
134
135 log_msg(LVL_DEBUG, "tcp_tqueue_new_data()");
136
137 /* Number of free sequence numbers in send window */
138 avail_wnd = (conn->snd_una + conn->snd_wnd) - conn->snd_nxt;
139 snd_buf_seqlen = conn->snd_buf_used + (conn->snd_buf_fin ? 1 : 0);
140
141 xfer_seqlen = min(snd_buf_seqlen, avail_wnd);
142 log_msg(LVL_DEBUG, "snd_buf_seqlen = %zu, SND.WND = %zu, "
143 "xfer_seqlen = %zu", snd_buf_seqlen, conn->snd_wnd,
144 xfer_seqlen);
145
146 if (xfer_seqlen == 0)
147 return;
148
149 /* XXX Do not always send immediately */
150
151 data_size = xfer_seqlen - (conn->snd_buf_fin ? 1 : 0);
152 if (conn->snd_buf_fin && data_size + 1 == xfer_seqlen) {
153 /* We are sending out FIN */
154 ctrl = CTL_FIN;
155 tcp_conn_fin_sent(conn);
156 } else {
157 ctrl = 0;
158 }
159
160 seg = tcp_segment_make_data(ctrl, conn->snd_buf, data_size);
161 if (seg == NULL) {
162 log_msg(LVL_ERROR, "Memory allocation failure.");
163 return;
164 }
165
166 /* Remove data from send buffer */
167 memmove(conn->snd_buf, conn->snd_buf + data_size,
168 conn->snd_buf_used - data_size);
169 conn->snd_buf_used -= data_size;
170 conn->snd_buf_fin = false;
171
172 tcp_tqueue_seg(conn, seg);
173}
174
175/** Remove ACKed segments from retransmission queue and possibly transmit
176 * more data.
177 *
178 * This should be called when SND.UNA is updated due to incoming ACK.
179 */
180void tcp_tqueue_ack_received(tcp_conn_t *conn)
181{
182 link_t *cur, *next;
183
184 log_msg(LVL_DEBUG, "tcp_tqueue_ack_received(%p)", conn);
185
186 cur = conn->retransmit.list.head.next;
187
188 while (cur != &conn->retransmit.list.head) {
189 next = cur->next;
190
191 tcp_tqueue_entry_t *tqe = list_get_instance(cur,
192 tcp_tqueue_entry_t, link);
193
194 if (seq_no_segment_acked(conn, tqe->seg, conn->snd_una)) {
195 /* Remove acknowledged segment */
196 list_remove(cur);
197
198 if ((tqe->seg->ctrl & CTL_FIN) != 0) {
199 /* Our FIN has been acked */
200 conn->fin_is_acked = true;
201 }
202
203 tcp_segment_delete(tqe->seg);
204 free(tqe);
205 }
206
207 cur = next;
208 }
209
210 /* Possibly transmit more data */
211 tcp_tqueue_new_data(conn);
212}
213
214void tcp_transmit_segment(tcp_sockpair_t *sp, tcp_segment_t *seg)
215{
216 log_msg(LVL_DEBUG, "tcp_transmit_segment(%p, %p)", sp, seg);
217/*
218 tcp_pdu_prepare(conn, seg, &data, &len);
219 tcp_pdu_transmit(data, len);
220*/
221 tcp_rqueue_bounce_seg(sp, seg);
222}
223
224/**
225 * @}
226 */
Note: See TracBrowser for help on using the repository browser.