source: mainline/uspace/srv/net/tcp/seq_no.c@ ca48672

Last change on this file since ca48672 was 3bacee1, checked in by Jiri Svoboda <jiri@…>, 7 years ago

Make ccheck-fix again and commit more good files.

  • Property mode set to 100644
File size: 7.7 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 Sequence number computations
[c5808b41]35 */
36
37#include <assert.h>
[3e6a98c5]38#include <stdbool.h>
[8d2dd7f2]39#include <stdint.h>
[c5808b41]40#include "seq_no.h"
41#include "tcp_type.h"
42
43/** a <= b < c modulo sequence space */
44static bool seq_no_le_lt(uint32_t a, uint32_t b, uint32_t c)
45{
46 if (a <= c) {
47 return (a <= b) && (b < c);
48 } else {
49 return (b < c) || (a <= b);
50 }
51}
52
53/** a < b <= c modulo sequence space */
54static bool seq_no_lt_le(uint32_t a, uint32_t b, uint32_t c)
55{
56 if (a <= c) {
57 return (a < b) && (b <= c);
58 } else {
59 return (b <= c) || (a < b);
60 }
61}
62
63/** Determine wheter ack is acceptable (new acknowledgement) */
64bool seq_no_ack_acceptable(tcp_conn_t *conn, uint32_t seg_ack)
65{
66 /* SND.UNA < SEG.ACK <= SND.NXT */
67 return seq_no_lt_le(conn->snd_una, seg_ack, conn->snd_nxt);
68}
69
[4c55a64]70/** Determine wheter ack is duplicate.
71 *
72 * ACK is duplicate if it refers to a sequence number that has
[0093ab6]73 * aleady been acked (SEG.ACK <= SND.UNA).
[4c55a64]74 */
75bool seq_no_ack_duplicate(tcp_conn_t *conn, uint32_t seg_ack)
76{
77 uint32_t diff;
78
79 /*
80 * There does not seem to be a three-point comparison
81 * equivalent of SEG.ACK < SND.UNA. Thus we do it
82 * on a best-effort basis, based on the difference.
[0093ab6]83 * [-2^31, 0) means less-than, 0 means equal, [0, 2^31)
84 * means greater-than. Less-than or equal means duplicate.
[4c55a64]85 */
86 diff = seg_ack - conn->snd_una;
[0093ab6]87 return diff == 0 || (diff & (0x1 << 31)) != 0;
[4c55a64]88}
89
[7cf7ded]90/** Determine if sequence number is in receive window. */
91bool seq_no_in_rcv_wnd(tcp_conn_t *conn, uint32_t sn)
92{
93 return seq_no_le_lt(conn->rcv_nxt, sn, conn->rcv_nxt + conn->rcv_wnd);
94}
95
[4c55a64]96/** Determine segment has new window update.
97 *
98 * Window update is new if either SND.WL1 < SEG.SEQ or
99 * (SND.WL1 = SEG.SEQ and SND.WL2 <= SEG.ACK).
100 */
101bool seq_no_new_wnd_update(tcp_conn_t *conn, tcp_segment_t *seg)
102{
103 bool n_seq, n_ack;
104
105 assert(seq_no_segment_acceptable(conn, seg));
106
107 /*
108 * We make use of the fact that the peer should not ACK anything
109 * beyond our send window (we surely haven't sent that yet)
110 * as we should have filtered those acks out.
111 * We use SND.UNA+SND.WND as the third point of comparison.
112 */
113
114 n_seq = seq_no_lt_le(conn->snd_wl1, seg->seq,
115 conn->snd_una + conn->snd_wnd);
116
117 n_ack = conn->snd_wl1 == seg->seq &&
118 seq_no_le_lt(conn->snd_wl2, seg->ack,
119 conn->snd_una + conn->snd_wnd + 1);
120
121 return n_seq || n_ack;
122}
123
[c5808b41]124/** Determine if segment is ready for processing.
125 *
126 * Assuming segment is acceptable, a segment is ready if it intersects
127 * RCV.NXT, that is we can process it immediately.
128 */
129bool seq_no_segment_ready(tcp_conn_t *conn, tcp_segment_t *seg)
130{
131 assert(seq_no_segment_acceptable(conn, seg));
132
133 return seq_no_le_lt(seg->seq, conn->rcv_nxt, seg->seq + seg->len + 1);
134}
135
[e73dbc1]136/** Determine whether segment is fully acked.
137 *
138 * @param conn Connection
139 * @param seg Segment
140 * @param ack Last received ACK (i.e. SND.UNA)
141 *
142 * @return @c true if segment is fully acked, @c false otherwise
143 */
[c5808b41]144bool seq_no_segment_acked(tcp_conn_t *conn, tcp_segment_t *seg, uint32_t ack)
145{
146 assert(seg->len > 0);
147 return seq_no_lt_le(seg->seq, seg->seq + seg->len, ack);
148}
149
[e73dbc1]150/** Determine whether initial SYN is acked.
151 *
152 * @param conn Connection
153 * @return @c true if initial SYN is acked, @c false otherwise
154 */
[c5808b41]155bool seq_no_syn_acked(tcp_conn_t *conn)
156{
157 return seq_no_lt_le(conn->iss, conn->snd_una, conn->snd_nxt);
158}
159
[e73dbc1]160/** Determine whether segment overlaps the receive window.
161 *
162 * @param conn Connection
163 * @param seg Segment
164 * @return @c true if segment overlaps the receive window, @c false otherwise
165 */
[c5808b41]166bool seq_no_segment_acceptable(tcp_conn_t *conn, tcp_segment_t *seg)
167{
168 bool b_in, e_in;
[e73dbc1]169 bool wb_in, we_in;
[c5808b41]170
[e73dbc1]171 /* Beginning of segment is inside window */
[3bacee1]172 b_in = seq_no_le_lt(conn->rcv_nxt, seg->seq, conn->rcv_nxt +
173 conn->rcv_wnd);
[c5808b41]174
[e73dbc1]175 /* End of segment is inside window */
[c5808b41]176 e_in = seq_no_le_lt(conn->rcv_nxt, seg->seq + seg->len - 1,
177 conn->rcv_nxt + conn->rcv_wnd);
178
[e73dbc1]179 /* Beginning of window is inside segment */
180 wb_in = seq_no_le_lt(seg->seq, conn->rcv_nxt,
181 seg->seq + seg->len);
182
183 /* End of window is inside segment */
184 we_in = seq_no_le_lt(seg->seq, conn->rcv_nxt + conn->rcv_wnd - 1,
185 seg->seq + seg->len);
186
[c5808b41]187 if (seg->len == 0 && conn->rcv_wnd == 0) {
188 return seg->seq == conn->rcv_nxt;
189 } else if (seg->len == 0 && conn->rcv_wnd != 0) {
190 return b_in;
191 } else if (seg->len > 0 && conn->rcv_wnd == 0) {
192 return false;
193 } else {
[e73dbc1]194 return b_in || e_in || wb_in || we_in;
[c5808b41]195 }
196}
197
[e73dbc1]198/** Determine size that control bits occupy in sequence space.
199 *
200 * @param ctrl Control bits combination
201 * @return Number of sequence space units occupied
202 */
[c5808b41]203uint32_t seq_no_control_len(tcp_control_t ctrl)
204{
205 uint32_t len = 0;
206
207 if ((ctrl & CTL_SYN) != 0)
208 ++len;
209
210 if ((ctrl & CTL_FIN) != 0)
211 ++len;
212
213 return len;
214}
215
[e73dbc1]216/** Calculate the amount of trim needed to fit segment in receive window.
217 *
218 * @param conn Connection
219 * @param seg Segment
220 * @param left Place to store number of units to trim at the beginning
221 * @param right Place to store number of units to trim at the end
222 */
[32aea9f4]223void seq_no_seg_trim_calc(tcp_conn_t *conn, tcp_segment_t *seg,
[0093ab6]224 uint32_t *left, uint32_t *right)
225{
226 assert(seq_no_segment_acceptable(conn, seg));
227
228 /*
229 * If RCV.NXT is between SEG.SEQ and RCV.NXT+RCV.WND, then
230 * left trim amount is positive
231 */
232 if (seq_no_lt_le(seg->seq, conn->rcv_nxt,
233 conn->rcv_nxt + conn->rcv_wnd)) {
234 *left = conn->rcv_nxt - seg->seq;
235 } else {
236 *left = 0;
237 }
238
239 /*
240 * If SEG.SEQ+SEG.LEN is between SEG.SEQ and RCV.NXT+RCV.WND,
241 * then right trim is zero.
242 */
243 if (seq_no_lt_le(seg->seq - 1, seg->seq + seg->len,
244 conn->rcv_nxt + conn->rcv_wnd)) {
245 *right = 0;
246 } else {
247 *right = (seg->seq + seg->len) -
248 (conn->rcv_nxt + conn->rcv_wnd);
249 }
250}
251
[32aea9f4]252/** Segment order comparison.
253 *
254 * Compare sequence order of two acceptable segments.
255 *
256 * @param conn Connection
257 * @param sa Segment A
258 * @param sb Segment B
259 *
260 * @return -1, 0, 1, resp. if A < B, A == B, A > B in terms
261 * of sequence order of the beginning of the segment.
262 */
263int seq_no_seg_cmp(tcp_conn_t *conn, tcp_segment_t *sa, tcp_segment_t *sb)
264{
265 assert(seq_no_segment_acceptable(conn, sa));
266 assert(seq_no_segment_acceptable(conn, sb));
267
268 if (seq_no_lt_le(sa->seq, sb->seq, conn->rcv_nxt + conn->rcv_wnd))
269 return -1;
270
271 if (seq_no_lt_le(sb->seq, sa->seq, conn->rcv_nxt + conn->rcv_wnd))
272 return +1;
273
274 assert(sa->seq == sb->seq);
275 return 0;
276}
277
[c5808b41]278/**
279 * @}
280 */
Note: See TracBrowser for help on using the repository browser.