Free (GPLv2) TCP/IP stack developed by TASS Belgium
Dependents: lpc1768-picotcp-demo ZeroMQ_PicoTCP_Publisher_demo TCPSocket_HelloWorld_PicoTCP Pico_TCP_UDP_Test ... more
PicoTCP. Copyright (c) 2013 TASS Belgium NV.
Released under the GNU General Public License, version 2.
Different licensing models may exist, at the sole discretion of the Copyright holders.
Official homepage: http://www.picotcp.com
Bug tracker: https://github.com/tass-belgium/picotcp/issues
Development steps:
initial integration with mbed RTOSgeneric mbed Ethernet driverhigh performance NXP LPC1768 specific Ethernet driverMulti-threading support for mbed RTOSBerkeley sockets and integration with the New Socket APIFork of the apps running on top of the New Socket APIScheduling optimizations- Debugging/benchmarking/testing
Demo application (measuring TCP sender performance):
Import programlpc1768-picotcp-demo
A PicoTCP demo app testing the ethernet throughput on the lpc1768 mbed board.
modules/pico_tcp.c@133:5b075f5e141a, 2014-01-16 (annotated)
- Committer:
- tass picotcp@tass.be
- Date:
- Thu Jan 16 10:13:37 2014 +0100
- Revision:
- 133:5b075f5e141a
- Parent:
- 131:4758606c9316
- Child:
- 137:a1c8bfa9d691
Update from master branch
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
daniele | 29:1a47b7151851 | 1 | /********************************************************************* |
TASS Belgium NV |
131:4758606c9316 | 2 | PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. |
TASS Belgium NV |
131:4758606c9316 | 3 | See LICENSE and COPYING for usage. |
TASS Belgium NV |
131:4758606c9316 | 4 | |
TASS Belgium NV |
131:4758606c9316 | 5 | . |
TASS Belgium NV |
131:4758606c9316 | 6 | |
TASS Belgium NV |
131:4758606c9316 | 7 | Authors: Daniele Lacamera, Philippe Mariman |
TASS Belgium NV |
131:4758606c9316 | 8 | *********************************************************************/ |
daniele | 29:1a47b7151851 | 9 | |
daniele | 29:1a47b7151851 | 10 | #include "pico_tcp.h" |
daniele | 29:1a47b7151851 | 11 | #include "pico_config.h" |
daniele | 29:1a47b7151851 | 12 | #include "pico_eth.h" |
daniele | 29:1a47b7151851 | 13 | #include "pico_socket.h" |
daniele | 29:1a47b7151851 | 14 | #include "pico_stack.h" |
daniele | 29:1a47b7151851 | 15 | #include "pico_socket.h" |
daniele | 29:1a47b7151851 | 16 | #include "pico_queue.h" |
daniele | 29:1a47b7151851 | 17 | #include "pico_tree.h" |
daniele | 29:1a47b7151851 | 18 | |
TASS Belgium NV |
131:4758606c9316 | 19 | #define TCP_IS_STATE(s, st) (s->state & st) |
daniele | 29:1a47b7151851 | 20 | #define TCP_SOCK(s) ((struct pico_socket_tcp *)s) |
TASS Belgium NV |
131:4758606c9316 | 21 | #define SEQN(f) ((f) ? (long_be(((struct pico_tcp_hdr *)((f)->transport_hdr))->seq)) : 0) |
TASS Belgium NV |
131:4758606c9316 | 22 | #define ACKN(f) ((f) ? (long_be(((struct pico_tcp_hdr *)((f)->transport_hdr))->ack)) : 0) |
daniele | 29:1a47b7151851 | 23 | |
tass | 122:5b1e9de8bf7f | 24 | #define PICO_TCP_RTO_MIN 50 |
daniele | 29:1a47b7151851 | 25 | #define PICO_TCP_RTO_MAX 120000 |
TASS Belgium NV |
131:4758606c9316 | 26 | #define PICO_TCP_IW 2 |
TASS Belgium NV |
131:4758606c9316 | 27 | #define PICO_TCP_SYN_TO 1000u |
tass | 48:40fc4462265c | 28 | #define PICO_TCP_ZOMBIE_TO 30000 |
daniele | 29:1a47b7151851 | 29 | |
TASS Belgium NV |
131:4758606c9316 | 30 | #define PICO_TCP_MAX_RETRANS 10 |
daniele | 29:1a47b7151851 | 31 | #define PICO_TCP_MAX_CONNECT_RETRIES 7 |
daniele | 29:1a47b7151851 | 32 | |
daniele | 29:1a47b7151851 | 33 | #define PICO_TCP_LOOKAHEAD 0x00 |
daniele | 29:1a47b7151851 | 34 | #define PICO_TCP_FIRST_DUPACK 0x01 |
daniele | 29:1a47b7151851 | 35 | #define PICO_TCP_SECOND_DUPACK 0x02 |
daniele | 29:1a47b7151851 | 36 | #define PICO_TCP_RECOVER 0x03 |
daniele | 29:1a47b7151851 | 37 | #define PICO_TCP_BLACKOUT 0x04 |
daniele | 29:1a47b7151851 | 38 | #define PICO_TCP_UNREACHABLE 0x05 |
daniele | 29:1a47b7151851 | 39 | #define PICO_TCP_WINDOW_FULL 0x06 |
daniele | 29:1a47b7151851 | 40 | |
daniele | 29:1a47b7151851 | 41 | /* check if the Nagle algorithm is enabled on the socket */ |
daniele | 29:1a47b7151851 | 42 | #define IS_NAGLE_ENABLED(s) (!(!(!(s->opt_flags & (1 << PICO_SOCKET_OPT_TCPNODELAY))))) |
daniele | 29:1a47b7151851 | 43 | /* check if tcp connection is "idle" according to Nagle (RFC 896) */ |
daniele | 29:1a47b7151851 | 44 | #define IS_TCP_IDLE(t) ((t->in_flight == 0) && (t->tcpq_out.size == 0)) |
daniele | 29:1a47b7151851 | 45 | /* check if the hold queue contains data (again Nagle) */ |
daniele | 29:1a47b7151851 | 46 | #define IS_TCP_HOLDQ_EMPTY(t) (t->tcpq_hold.size == 0) |
daniele | 29:1a47b7151851 | 47 | |
TASS Belgium NV |
131:4758606c9316 | 48 | #define IS_INPUT_QUEUE(q) (q->pool.compare == input_segment_compare) |
TASS Belgium NV |
131:4758606c9316 | 49 | #define TCP_INPUT_OVERHEAD (sizeof(struct tcp_input_segment) + sizeof(struct pico_tree_node)) |
tass | 110:0ece1bbbd36e | 50 | |
tass | 123:dd26752a4538 | 51 | |
daniele | 29:1a47b7151851 | 52 | #ifdef PICO_SUPPORT_TCP |
TASS Belgium NV |
131:4758606c9316 | 53 | #define tcp_dbg_nagle(...) do {} while(0) |
TASS Belgium NV |
131:4758606c9316 | 54 | #define tcp_dbg_options(...) do {} while(0) |
TASS Belgium NV |
131:4758606c9316 | 55 | |
TASS Belgium NV |
131:4758606c9316 | 56 | |
TASS Belgium NV |
131:4758606c9316 | 57 | #define tcp_dbg(...) do {} while(0) |
TASS Belgium NV |
131:4758606c9316 | 58 | /* #define tcp_dbg dbg */ |
daniele | 29:1a47b7151851 | 59 | |
daniele | 29:1a47b7151851 | 60 | #ifdef PICO_SUPPORT_MUTEX |
TASS Belgium NV |
131:4758606c9316 | 61 | static void *Mutex = NULL; |
TASS Belgium NV |
131:4758606c9316 | 62 | #define LOCK(x) { \ |
TASS Belgium NV |
131:4758606c9316 | 63 | if (x == NULL) \ |
TASS Belgium NV |
131:4758606c9316 | 64 | x = pico_mutex_init(); \ |
TASS Belgium NV |
131:4758606c9316 | 65 | pico_mutex_lock(x); \ |
daniele | 29:1a47b7151851 | 66 | } |
TASS Belgium NV |
131:4758606c9316 | 67 | #define UNLOCK(x) pico_mutex_unlock(x) |
daniele | 29:1a47b7151851 | 68 | |
daniele | 29:1a47b7151851 | 69 | #else |
TASS Belgium NV |
131:4758606c9316 | 70 | #define LOCK(x) do {} while(0) |
TASS Belgium NV |
131:4758606c9316 | 71 | #define UNLOCK(x) do {} while(0) |
daniele | 29:1a47b7151851 | 72 | #endif |
daniele | 29:1a47b7151851 | 73 | |
daniele | 29:1a47b7151851 | 74 | |
daniele | 29:1a47b7151851 | 75 | static inline int seq_compare(uint32_t a, uint32_t b) |
daniele | 29:1a47b7151851 | 76 | { |
TASS Belgium NV |
131:4758606c9316 | 77 | uint32_t thresh = ((uint32_t)(-1)) >> 1; |
TASS Belgium NV |
131:4758606c9316 | 78 | if (((a > thresh) && (b > thresh)) || ((a <= thresh) && (b <= thresh))) { |
TASS Belgium NV |
131:4758606c9316 | 79 | if (a > b) |
TASS Belgium NV |
131:4758606c9316 | 80 | return 1; |
TASS Belgium NV |
131:4758606c9316 | 81 | |
TASS Belgium NV |
131:4758606c9316 | 82 | if (b > a) |
TASS Belgium NV |
131:4758606c9316 | 83 | return -1; |
TASS Belgium NV |
131:4758606c9316 | 84 | } else { |
TASS Belgium NV |
131:4758606c9316 | 85 | if (a > b) |
TASS Belgium NV |
131:4758606c9316 | 86 | return -2; |
TASS Belgium NV |
131:4758606c9316 | 87 | |
TASS Belgium NV |
131:4758606c9316 | 88 | if (b > a) |
TASS Belgium NV |
131:4758606c9316 | 89 | return 2; |
TASS Belgium NV |
131:4758606c9316 | 90 | } |
TASS Belgium NV |
131:4758606c9316 | 91 | |
TASS Belgium NV |
131:4758606c9316 | 92 | return 0; |
daniele | 29:1a47b7151851 | 93 | } |
daniele | 29:1a47b7151851 | 94 | |
TASS Belgium NV |
131:4758606c9316 | 95 | /* Input segment, used to keep only needed data, not the full frame */ |
tass | 110:0ece1bbbd36e | 96 | struct tcp_input_segment |
tass | 110:0ece1bbbd36e | 97 | { |
TASS Belgium NV |
131:4758606c9316 | 98 | uint32_t seq; |
TASS Belgium NV |
131:4758606c9316 | 99 | /* Pointer to payload */ |
TASS Belgium NV |
131:4758606c9316 | 100 | unsigned char *payload; |
TASS Belgium NV |
131:4758606c9316 | 101 | uint16_t payload_len; |
tass | 110:0ece1bbbd36e | 102 | }; |
tass | 110:0ece1bbbd36e | 103 | |
TASS Belgium NV |
131:4758606c9316 | 104 | /* Function to compare input segments */ |
tass | 110:0ece1bbbd36e | 105 | static int input_segment_compare(void *ka, void *kb) |
tass | 110:0ece1bbbd36e | 106 | { |
TASS Belgium NV |
131:4758606c9316 | 107 | struct tcp_input_segment *a = ka, *b = kb; |
TASS Belgium NV |
131:4758606c9316 | 108 | return seq_compare(a->seq, b->seq); |
tass | 110:0ece1bbbd36e | 109 | } |
tass | 110:0ece1bbbd36e | 110 | |
TASS Belgium NV |
131:4758606c9316 | 111 | static struct tcp_input_segment *segment_from_frame(struct pico_frame *f) |
tass | 110:0ece1bbbd36e | 112 | { |
TASS Belgium NV |
131:4758606c9316 | 113 | struct tcp_input_segment *seg = pico_zalloc(sizeof(struct tcp_input_segment)); |
TASS Belgium NV |
131:4758606c9316 | 114 | if(!seg) |
TASS Belgium NV |
131:4758606c9316 | 115 | return NULL; |
TASS Belgium NV |
131:4758606c9316 | 116 | |
TASS Belgium NV |
131:4758606c9316 | 117 | seg->payload = pico_zalloc(f->payload_len); |
TASS Belgium NV |
131:4758606c9316 | 118 | if(!seg->payload) |
TASS Belgium NV |
131:4758606c9316 | 119 | { |
TASS Belgium NV |
131:4758606c9316 | 120 | pico_free(seg); |
TASS Belgium NV |
131:4758606c9316 | 121 | return NULL; |
TASS Belgium NV |
131:4758606c9316 | 122 | } |
TASS Belgium NV |
131:4758606c9316 | 123 | |
TASS Belgium NV |
131:4758606c9316 | 124 | seg->seq = SEQN(f); |
TASS Belgium NV |
131:4758606c9316 | 125 | seg->payload_len = f->payload_len; |
TASS Belgium NV |
131:4758606c9316 | 126 | memcpy(seg->payload, f->payload, seg->payload_len); |
TASS Belgium NV |
131:4758606c9316 | 127 | return seg; |
tass | 110:0ece1bbbd36e | 128 | } |
tass | 110:0ece1bbbd36e | 129 | |
TASS Belgium NV |
131:4758606c9316 | 130 | static int segment_compare(void *ka, void *kb) |
daniele | 29:1a47b7151851 | 131 | { |
TASS Belgium NV |
131:4758606c9316 | 132 | struct pico_frame *a = ka, *b = kb; |
TASS Belgium NV |
131:4758606c9316 | 133 | return seq_compare(SEQN(a), SEQN(b)); |
daniele | 29:1a47b7151851 | 134 | } |
daniele | 29:1a47b7151851 | 135 | |
daniele | 29:1a47b7151851 | 136 | struct pico_tcp_queue |
daniele | 29:1a47b7151851 | 137 | { |
TASS Belgium NV |
131:4758606c9316 | 138 | struct pico_tree pool; |
TASS Belgium NV |
131:4758606c9316 | 139 | uint32_t max_size; |
TASS Belgium NV |
131:4758606c9316 | 140 | uint32_t size; |
TASS Belgium NV |
131:4758606c9316 | 141 | uint32_t frames; |
TASS Belgium NV |
131:4758606c9316 | 142 | uint16_t overhead; |
daniele | 29:1a47b7151851 | 143 | }; |
TASS Belgium NV |
131:4758606c9316 | 144 | |
tass | 97:e73b01cb3147 | 145 | static void tcp_discard_all_segments(struct pico_tcp_queue *tq); |
tass | 110:0ece1bbbd36e | 146 | static void *peek_segment(struct pico_tcp_queue *tq, uint32_t seq) |
daniele | 29:1a47b7151851 | 147 | { |
TASS Belgium NV |
131:4758606c9316 | 148 | if(!IS_INPUT_QUEUE(tq)) |
TASS Belgium NV |
131:4758606c9316 | 149 | { |
TASS Belgium NV |
131:4758606c9316 | 150 | struct pico_tcp_hdr H; |
TASS Belgium NV |
131:4758606c9316 | 151 | struct pico_frame f = { |
TASS Belgium NV |
131:4758606c9316 | 152 | 0 |
TASS Belgium NV |
131:4758606c9316 | 153 | }; |
TASS Belgium NV |
131:4758606c9316 | 154 | f.transport_hdr = (uint8_t *) (&H); |
TASS Belgium NV |
131:4758606c9316 | 155 | H.seq = long_be(seq); |
TASS Belgium NV |
131:4758606c9316 | 156 | |
TASS Belgium NV |
131:4758606c9316 | 157 | return pico_tree_findKey(&tq->pool, &f); |
TASS Belgium NV |
131:4758606c9316 | 158 | } |
TASS Belgium NV |
131:4758606c9316 | 159 | else |
TASS Belgium NV |
131:4758606c9316 | 160 | { |
TASS Belgium NV |
131:4758606c9316 | 161 | struct tcp_input_segment dummy = { |
TASS Belgium NV |
131:4758606c9316 | 162 | .seq = seq |
TASS Belgium NV |
131:4758606c9316 | 163 | }; |
TASS Belgium NV |
131:4758606c9316 | 164 | |
TASS Belgium NV |
131:4758606c9316 | 165 | return pico_tree_findKey(&tq->pool, &dummy); |
TASS Belgium NV |
131:4758606c9316 | 166 | } |
tass | 110:0ece1bbbd36e | 167 | |
daniele | 29:1a47b7151851 | 168 | } |
daniele | 29:1a47b7151851 | 169 | |
tass | 110:0ece1bbbd36e | 170 | static void *first_segment(struct pico_tcp_queue *tq) |
daniele | 29:1a47b7151851 | 171 | { |
TASS Belgium NV |
131:4758606c9316 | 172 | return pico_tree_first(&tq->pool); |
daniele | 29:1a47b7151851 | 173 | } |
daniele | 29:1a47b7151851 | 174 | |
tass | 110:0ece1bbbd36e | 175 | static void *next_segment(struct pico_tcp_queue *tq, void *cur) |
daniele | 29:1a47b7151851 | 176 | { |
TASS Belgium NV |
131:4758606c9316 | 177 | if (!cur) |
TASS Belgium NV |
131:4758606c9316 | 178 | return NULL; |
TASS Belgium NV |
131:4758606c9316 | 179 | |
TASS Belgium NV |
131:4758606c9316 | 180 | if(IS_INPUT_QUEUE(tq)) |
TASS Belgium NV |
131:4758606c9316 | 181 | { |
TASS Belgium NV |
131:4758606c9316 | 182 | return peek_segment(tq, ((struct tcp_input_segment *)cur)->seq + ((struct tcp_input_segment *)cur)->payload_len); |
TASS Belgium NV |
131:4758606c9316 | 183 | } |
TASS Belgium NV |
131:4758606c9316 | 184 | else |
TASS Belgium NV |
131:4758606c9316 | 185 | { |
TASS Belgium NV |
131:4758606c9316 | 186 | return peek_segment(tq, SEQN((struct pico_frame *)cur) + ((struct pico_frame *)cur)->payload_len); |
TASS Belgium NV |
131:4758606c9316 | 187 | } |
daniele | 29:1a47b7151851 | 188 | } |
daniele | 29:1a47b7151851 | 189 | |
tass | 110:0ece1bbbd36e | 190 | static int32_t pico_enqueue_segment(struct pico_tcp_queue *tq, void *f) |
daniele | 29:1a47b7151851 | 191 | { |
TASS Belgium NV |
131:4758606c9316 | 192 | int32_t ret = -1; |
TASS Belgium NV |
131:4758606c9316 | 193 | uint16_t payload_len = (uint16_t)(IS_INPUT_QUEUE(tq) ? |
TASS Belgium NV |
131:4758606c9316 | 194 | ((struct tcp_input_segment *)f)->payload_len : |
TASS Belgium NV |
131:4758606c9316 | 195 | ((struct pico_frame *)f)->buffer_len); |
TASS Belgium NV |
131:4758606c9316 | 196 | |
TASS Belgium NV |
131:4758606c9316 | 197 | if (payload_len <= 0) { |
TASS Belgium NV |
131:4758606c9316 | 198 | tcp_dbg("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! TRIED TO ENQUEUE INVALID SEGMENT!\n"); |
TASS Belgium NV |
131:4758606c9316 | 199 | /* abort(); */ |
TASS Belgium NV |
131:4758606c9316 | 200 | return -1; |
TASS Belgium NV |
131:4758606c9316 | 201 | } |
TASS Belgium NV |
131:4758606c9316 | 202 | |
TASS Belgium NV |
131:4758606c9316 | 203 | LOCK(Mutex); |
TASS Belgium NV |
131:4758606c9316 | 204 | if ((tq->size + payload_len) > tq->max_size) |
TASS Belgium NV |
131:4758606c9316 | 205 | { |
TASS Belgium NV |
131:4758606c9316 | 206 | ret = 0; |
TASS Belgium NV |
131:4758606c9316 | 207 | goto out; |
TASS Belgium NV |
131:4758606c9316 | 208 | } |
TASS Belgium NV |
131:4758606c9316 | 209 | |
TASS Belgium NV |
131:4758606c9316 | 210 | if (pico_tree_insert(&tq->pool, f) != 0) |
TASS Belgium NV |
131:4758606c9316 | 211 | { |
TASS Belgium NV |
131:4758606c9316 | 212 | ret = 0; |
TASS Belgium NV |
131:4758606c9316 | 213 | goto out; |
TASS Belgium NV |
131:4758606c9316 | 214 | } |
TASS Belgium NV |
131:4758606c9316 | 215 | |
TASS Belgium NV |
131:4758606c9316 | 216 | tq->size += (uint16_t)(payload_len + tq->overhead); |
TASS Belgium NV |
131:4758606c9316 | 217 | if (payload_len > 0) |
TASS Belgium NV |
131:4758606c9316 | 218 | tq->frames++; |
TASS Belgium NV |
131:4758606c9316 | 219 | |
TASS Belgium NV |
131:4758606c9316 | 220 | ret = (int32_t)payload_len; |
TASS Belgium NV |
131:4758606c9316 | 221 | |
TASS Belgium NV |
131:4758606c9316 | 222 | out: |
TASS Belgium NV |
131:4758606c9316 | 223 | UNLOCK(Mutex); |
TASS Belgium NV |
131:4758606c9316 | 224 | return ret; |
daniele | 29:1a47b7151851 | 225 | } |
daniele | 29:1a47b7151851 | 226 | |
tass | 110:0ece1bbbd36e | 227 | static void pico_discard_segment(struct pico_tcp_queue *tq, void *f) |
daniele | 29:1a47b7151851 | 228 | { |
TASS Belgium NV |
131:4758606c9316 | 229 | void *f1; |
TASS Belgium NV |
131:4758606c9316 | 230 | uint16_t payload_len = (uint16_t)(IS_INPUT_QUEUE(tq) ? |
TASS Belgium NV |
131:4758606c9316 | 231 | ((struct tcp_input_segment *)f)->payload_len : |
TASS Belgium NV |
131:4758606c9316 | 232 | ((struct pico_frame *)f)->buffer_len); |
TASS Belgium NV |
131:4758606c9316 | 233 | LOCK(Mutex); |
TASS Belgium NV |
131:4758606c9316 | 234 | f1 = pico_tree_delete(&tq->pool, f); |
TASS Belgium NV |
131:4758606c9316 | 235 | if (f1) { |
TASS Belgium NV |
131:4758606c9316 | 236 | tq->size -= (uint16_t)(payload_len + tq->overhead); |
TASS Belgium NV |
131:4758606c9316 | 237 | if (payload_len > 0) |
TASS Belgium NV |
131:4758606c9316 | 238 | tq->frames--; |
TASS Belgium NV |
131:4758606c9316 | 239 | } |
TASS Belgium NV |
131:4758606c9316 | 240 | |
TASS Belgium NV |
131:4758606c9316 | 241 | if(IS_INPUT_QUEUE(tq)) |
TASS Belgium NV |
131:4758606c9316 | 242 | { |
TASS Belgium NV |
131:4758606c9316 | 243 | struct tcp_input_segment *inp = f1; |
TASS Belgium NV |
131:4758606c9316 | 244 | pico_free(inp->payload); |
TASS Belgium NV |
131:4758606c9316 | 245 | pico_free(inp); |
TASS Belgium NV |
131:4758606c9316 | 246 | } |
TASS Belgium NV |
131:4758606c9316 | 247 | else |
TASS Belgium NV |
131:4758606c9316 | 248 | pico_frame_discard(f); |
TASS Belgium NV |
131:4758606c9316 | 249 | |
TASS Belgium NV |
131:4758606c9316 | 250 | UNLOCK(Mutex); |
daniele | 29:1a47b7151851 | 251 | } |
daniele | 29:1a47b7151851 | 252 | |
daniele | 29:1a47b7151851 | 253 | /* Structure for TCP socket */ |
daniele | 29:1a47b7151851 | 254 | struct tcp_sack_block { |
TASS Belgium NV |
131:4758606c9316 | 255 | uint32_t left; |
TASS Belgium NV |
131:4758606c9316 | 256 | uint32_t right; |
TASS Belgium NV |
131:4758606c9316 | 257 | struct tcp_sack_block *next; |
daniele | 29:1a47b7151851 | 258 | }; |
daniele | 29:1a47b7151851 | 259 | |
daniele | 29:1a47b7151851 | 260 | struct pico_socket_tcp { |
TASS Belgium NV |
131:4758606c9316 | 261 | struct pico_socket sock; |
TASS Belgium NV |
131:4758606c9316 | 262 | |
TASS Belgium NV |
131:4758606c9316 | 263 | /* Tree/queues */ |
TASS Belgium NV |
131:4758606c9316 | 264 | struct pico_tcp_queue tcpq_in; /* updated the input queue to hold input segments not the full frame. */ |
TASS Belgium NV |
131:4758606c9316 | 265 | struct pico_tcp_queue tcpq_out; |
TASS Belgium NV |
131:4758606c9316 | 266 | struct pico_tcp_queue tcpq_hold; /* buffer to hold delayed frames according to Nagle */ |
TASS Belgium NV |
131:4758606c9316 | 267 | |
TASS Belgium NV |
131:4758606c9316 | 268 | /* tcp_output */ |
TASS Belgium NV |
131:4758606c9316 | 269 | uint32_t snd_nxt; |
TASS Belgium NV |
131:4758606c9316 | 270 | uint32_t snd_last; |
TASS Belgium NV |
131:4758606c9316 | 271 | uint32_t snd_old_ack; |
TASS Belgium NV |
131:4758606c9316 | 272 | uint32_t snd_retry; |
TASS Belgium NV |
131:4758606c9316 | 273 | uint32_t snd_last_out; |
TASS Belgium NV |
131:4758606c9316 | 274 | |
TASS Belgium NV |
131:4758606c9316 | 275 | /* congestion control */ |
TASS Belgium NV |
131:4758606c9316 | 276 | uint32_t avg_rtt; |
TASS Belgium NV |
131:4758606c9316 | 277 | uint32_t rttvar; |
TASS Belgium NV |
131:4758606c9316 | 278 | uint32_t rto; |
TASS Belgium NV |
131:4758606c9316 | 279 | uint32_t in_flight; |
TASS Belgium NV |
131:4758606c9316 | 280 | uint8_t timer_running; |
TASS Belgium NV |
131:4758606c9316 | 281 | struct pico_timer *retrans_tmr; |
TASS Belgium NV |
131:4758606c9316 | 282 | uint8_t keepalive_timer_running; |
TASS Belgium NV |
131:4758606c9316 | 283 | uint16_t cwnd_counter; |
TASS Belgium NV |
131:4758606c9316 | 284 | uint16_t cwnd; |
TASS Belgium NV |
131:4758606c9316 | 285 | uint16_t ssthresh; |
TASS Belgium NV |
131:4758606c9316 | 286 | uint16_t recv_wnd; |
TASS Belgium NV |
131:4758606c9316 | 287 | uint16_t recv_wnd_scale; |
TASS Belgium NV |
131:4758606c9316 | 288 | |
TASS Belgium NV |
131:4758606c9316 | 289 | /* tcp_input */ |
TASS Belgium NV |
131:4758606c9316 | 290 | uint32_t rcv_nxt; |
TASS Belgium NV |
131:4758606c9316 | 291 | uint32_t rcv_ackd; |
TASS Belgium NV |
131:4758606c9316 | 292 | uint32_t rcv_processed; |
TASS Belgium NV |
131:4758606c9316 | 293 | uint16_t wnd; |
TASS Belgium NV |
131:4758606c9316 | 294 | uint16_t wnd_scale; |
TASS Belgium NV |
131:4758606c9316 | 295 | |
TASS Belgium NV |
131:4758606c9316 | 296 | /* options */ |
TASS Belgium NV |
131:4758606c9316 | 297 | uint32_t ts_nxt; |
TASS Belgium NV |
131:4758606c9316 | 298 | uint16_t mss; |
TASS Belgium NV |
131:4758606c9316 | 299 | uint8_t sack_ok; |
TASS Belgium NV |
131:4758606c9316 | 300 | uint8_t ts_ok; |
TASS Belgium NV |
131:4758606c9316 | 301 | uint8_t mss_ok; |
TASS Belgium NV |
131:4758606c9316 | 302 | uint8_t scale_ok; |
TASS Belgium NV |
131:4758606c9316 | 303 | struct tcp_sack_block *sacks; |
TASS Belgium NV |
131:4758606c9316 | 304 | uint8_t jumbo; |
TASS Belgium NV |
131:4758606c9316 | 305 | |
TASS Belgium NV |
131:4758606c9316 | 306 | /* Transmission */ |
TASS Belgium NV |
131:4758606c9316 | 307 | uint8_t x_mode; |
TASS Belgium NV |
131:4758606c9316 | 308 | uint8_t dupacks; |
TASS Belgium NV |
131:4758606c9316 | 309 | uint8_t backoff; |
TASS Belgium NV |
131:4758606c9316 | 310 | uint8_t localZeroWindow; |
daniele | 29:1a47b7151851 | 311 | }; |
daniele | 29:1a47b7151851 | 312 | |
daniele | 29:1a47b7151851 | 313 | /* Queues */ |
TASS Belgium NV |
131:4758606c9316 | 314 | static struct pico_queue tcp_in = { |
TASS Belgium NV |
131:4758606c9316 | 315 | 0 |
TASS Belgium NV |
131:4758606c9316 | 316 | }; |
TASS Belgium NV |
131:4758606c9316 | 317 | static struct pico_queue tcp_out = { |
TASS Belgium NV |
131:4758606c9316 | 318 | 0 |
TASS Belgium NV |
131:4758606c9316 | 319 | }; |
daniele | 29:1a47b7151851 | 320 | |
daniele | 29:1a47b7151851 | 321 | /* If Nagle enabled, this function can make 1 new segment from smaller segments in hold queue */ |
TASS Belgium NV |
131:4758606c9316 | 322 | static struct pico_frame *pico_hold_segment_make(struct pico_socket_tcp *t); |
daniele | 29:1a47b7151851 | 323 | |
daniele | 29:1a47b7151851 | 324 | /* checks if tcpq_in is empty */ |
daniele | 29:1a47b7151851 | 325 | int pico_tcp_queue_in_is_empty(struct pico_socket *s) |
daniele | 29:1a47b7151851 | 326 | { |
TASS Belgium NV |
131:4758606c9316 | 327 | struct pico_socket_tcp *t = (struct pico_socket_tcp *) s; |
TASS Belgium NV |
131:4758606c9316 | 328 | |
TASS Belgium NV |
131:4758606c9316 | 329 | if (t->tcpq_in.frames == 0) |
TASS Belgium NV |
131:4758606c9316 | 330 | return 1; |
TASS Belgium NV |
131:4758606c9316 | 331 | else |
TASS Belgium NV |
131:4758606c9316 | 332 | return 0; |
daniele | 29:1a47b7151851 | 333 | } |
daniele | 29:1a47b7151851 | 334 | |
daniele | 29:1a47b7151851 | 335 | /* Useful for getting rid of the beginning of the buffer (read() op) */ |
daniele | 29:1a47b7151851 | 336 | static int release_until(struct pico_tcp_queue *q, uint32_t seq) |
daniele | 29:1a47b7151851 | 337 | { |
TASS Belgium NV |
131:4758606c9316 | 338 | void *head = first_segment(q); |
TASS Belgium NV |
131:4758606c9316 | 339 | int ret = 0; |
TASS Belgium NV |
131:4758606c9316 | 340 | int seq_result = 0; |
tass | 110:0ece1bbbd36e | 341 | if(head) |
TASS Belgium NV |
131:4758606c9316 | 342 | seq_result = IS_INPUT_QUEUE(q) ? |
TASS Belgium NV |
131:4758606c9316 | 343 | seq_compare(((struct tcp_input_segment *)head)->seq + ((struct tcp_input_segment *)head)->payload_len, seq) : |
TASS Belgium NV |
131:4758606c9316 | 344 | seq_compare(SEQN((struct pico_frame *)head) + ((struct pico_frame *)head)->payload_len, seq); |
TASS Belgium NV |
131:4758606c9316 | 345 | |
TASS Belgium NV |
131:4758606c9316 | 346 | while (head && (seq_result <= 0)) { |
TASS Belgium NV |
131:4758606c9316 | 347 | void *cur = head; |
TASS Belgium NV |
131:4758606c9316 | 348 | head = next_segment(q, cur); |
TASS Belgium NV |
131:4758606c9316 | 349 | tcp_dbg("Releasing %p\n", q); |
TASS Belgium NV |
131:4758606c9316 | 350 | pico_discard_segment(q, cur); |
TASS Belgium NV |
131:4758606c9316 | 351 | ret++; |
TASS Belgium NV |
131:4758606c9316 | 352 | if(head) |
TASS Belgium NV |
131:4758606c9316 | 353 | seq_result = IS_INPUT_QUEUE(q) ? |
TASS Belgium NV |
131:4758606c9316 | 354 | seq_compare(((struct tcp_input_segment *)head)->seq + ((struct tcp_input_segment *)head)->payload_len, seq) : |
TASS Belgium NV |
131:4758606c9316 | 355 | seq_compare(SEQN((struct pico_frame *)head) + ((struct pico_frame *)head)->payload_len, seq); |
TASS Belgium NV |
131:4758606c9316 | 356 | } |
TASS Belgium NV |
131:4758606c9316 | 357 | return ret; |
daniele | 29:1a47b7151851 | 358 | } |
daniele | 29:1a47b7151851 | 359 | |
TASS Belgium NV |
131:4758606c9316 | 360 | static int release_all_until(struct pico_tcp_queue *q, uint32_t seq, pico_time *timestamp) |
daniele | 29:1a47b7151851 | 361 | { |
TASS Belgium NV |
131:4758606c9316 | 362 | void *f = NULL, *tmp __attribute__((unused)); |
TASS Belgium NV |
131:4758606c9316 | 363 | struct pico_tree_node *idx, *temp; |
TASS Belgium NV |
131:4758606c9316 | 364 | int seq_result; |
TASS Belgium NV |
131:4758606c9316 | 365 | int ret = 0; |
TASS Belgium NV |
131:4758606c9316 | 366 | *timestamp = 0; |
TASS Belgium NV |
131:4758606c9316 | 367 | |
TASS Belgium NV |
131:4758606c9316 | 368 | pico_tree_foreach_safe(idx, &q->pool, temp){ |
TASS Belgium NV |
131:4758606c9316 | 369 | f = idx->keyValue; |
TASS Belgium NV |
131:4758606c9316 | 370 | seq_result = IS_INPUT_QUEUE(q) ? |
TASS Belgium NV |
131:4758606c9316 | 371 | seq_compare(((struct tcp_input_segment *)f)->seq + ((struct tcp_input_segment *)f)->payload_len, seq) : |
TASS Belgium NV |
131:4758606c9316 | 372 | seq_compare(SEQN((struct pico_frame *)f) + ((struct pico_frame *)f)->payload_len, seq); |
TASS Belgium NV |
131:4758606c9316 | 373 | if (seq_result <= 0) { |
TASS Belgium NV |
131:4758606c9316 | 374 | tcp_dbg("Releasing %p\n", f); |
TASS Belgium NV |
131:4758606c9316 | 375 | if(seq_result == 0) |
TASS Belgium NV |
131:4758606c9316 | 376 | *timestamp = ((struct pico_frame *)f)->timestamp; |
TASS Belgium NV |
131:4758606c9316 | 377 | |
TASS Belgium NV |
131:4758606c9316 | 378 | pico_discard_segment(q, f); |
TASS Belgium NV |
131:4758606c9316 | 379 | ret++; |
TASS Belgium NV |
131:4758606c9316 | 380 | } else |
TASS Belgium NV |
131:4758606c9316 | 381 | return ret; |
TASS Belgium NV |
131:4758606c9316 | 382 | } |
TASS Belgium NV |
131:4758606c9316 | 383 | return ret; |
daniele | 29:1a47b7151851 | 384 | } |
daniele | 29:1a47b7151851 | 385 | |
daniele | 29:1a47b7151851 | 386 | /* API calls */ |
daniele | 29:1a47b7151851 | 387 | |
daniele | 29:1a47b7151851 | 388 | uint16_t pico_tcp_checksum_ipv4(struct pico_frame *f) |
daniele | 29:1a47b7151851 | 389 | { |
TASS Belgium NV |
131:4758606c9316 | 390 | struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *) f->net_hdr; |
TASS Belgium NV |
131:4758606c9316 | 391 | struct pico_tcp_hdr *tcp_hdr = (struct pico_tcp_hdr *) f->transport_hdr; |
TASS Belgium NV |
131:4758606c9316 | 392 | struct pico_socket *s = f->sock; |
TASS Belgium NV |
131:4758606c9316 | 393 | struct pico_ipv4_pseudo_hdr pseudo; |
TASS Belgium NV |
131:4758606c9316 | 394 | |
TASS Belgium NV |
131:4758606c9316 | 395 | if (s) { |
TASS Belgium NV |
131:4758606c9316 | 396 | /* Case of outgoing frame */ |
TASS Belgium NV |
131:4758606c9316 | 397 | /* dbg("TCP CRC: on outgoing frame\n"); */ |
TASS Belgium NV |
131:4758606c9316 | 398 | pseudo.src.addr = s->local_addr.ip4.addr; |
TASS Belgium NV |
131:4758606c9316 | 399 | pseudo.dst.addr = s->remote_addr.ip4.addr; |
TASS Belgium NV |
131:4758606c9316 | 400 | } else { |
TASS Belgium NV |
131:4758606c9316 | 401 | /* Case of incomming frame */ |
TASS Belgium NV |
131:4758606c9316 | 402 | /* dbg("TCP CRC: on incomming frame\n"); */ |
TASS Belgium NV |
131:4758606c9316 | 403 | pseudo.src.addr = hdr->src.addr; |
TASS Belgium NV |
131:4758606c9316 | 404 | pseudo.dst.addr = hdr->dst.addr; |
TASS Belgium NV |
131:4758606c9316 | 405 | } |
TASS Belgium NV |
131:4758606c9316 | 406 | |
TASS Belgium NV |
131:4758606c9316 | 407 | pseudo.zeros = 0; |
TASS Belgium NV |
131:4758606c9316 | 408 | pseudo.proto = PICO_PROTO_TCP; |
TASS Belgium NV |
131:4758606c9316 | 409 | pseudo.len = (uint16_t)short_be(f->transport_len); |
TASS Belgium NV |
131:4758606c9316 | 410 | |
TASS Belgium NV |
131:4758606c9316 | 411 | return pico_dualbuffer_checksum(&pseudo, sizeof(struct pico_ipv4_pseudo_hdr), tcp_hdr, f->transport_len); |
daniele | 29:1a47b7151851 | 412 | } |
daniele | 29:1a47b7151851 | 413 | |
tass | 32:865c101e0874 | 414 | static void tcp_send_fin(struct pico_socket_tcp *t); |
daniele | 29:1a47b7151851 | 415 | static int pico_tcp_process_out(struct pico_protocol *self, struct pico_frame *f) |
daniele | 29:1a47b7151851 | 416 | { |
TASS Belgium NV |
131:4758606c9316 | 417 | struct pico_tcp_hdr *hdr; |
TASS Belgium NV |
131:4758606c9316 | 418 | struct pico_socket_tcp *t = (struct pico_socket_tcp *)f->sock; |
TASS Belgium NV |
131:4758606c9316 | 419 | IGNORE_PARAMETER(self); |
TASS Belgium NV |
131:4758606c9316 | 420 | hdr = (struct pico_tcp_hdr *)f->transport_hdr; |
TASS Belgium NV |
131:4758606c9316 | 421 | f->sock->timestamp = PICO_TIME_MS(); |
TASS Belgium NV |
131:4758606c9316 | 422 | if (f->payload_len > 0) { |
TASS Belgium NV |
131:4758606c9316 | 423 | tcp_dbg("Process out: sending %p (%d bytes)\n", f, f->payload_len); |
TASS Belgium NV |
131:4758606c9316 | 424 | } else { |
TASS Belgium NV |
131:4758606c9316 | 425 | tcp_dbg("Sending empty packet\n"); |
daniele | 29:1a47b7151851 | 426 | } |
TASS Belgium NV |
131:4758606c9316 | 427 | |
TASS Belgium NV |
131:4758606c9316 | 428 | if (f->payload_len > 0) { |
TASS Belgium NV |
131:4758606c9316 | 429 | if (seq_compare(SEQN(f) + f->payload_len, t->snd_nxt) > 0) { |
TASS Belgium NV |
131:4758606c9316 | 430 | t->snd_nxt = SEQN(f) + f->payload_len; |
TASS Belgium NV |
131:4758606c9316 | 431 | tcp_dbg("%s: snd_nxt is now %08x\n", __FUNCTION__, t->snd_nxt); |
TASS Belgium NV |
131:4758606c9316 | 432 | } |
TASS Belgium NV |
131:4758606c9316 | 433 | } else if (hdr->flags == PICO_TCP_ACK) { /* pure ack */ |
TASS Belgium NV |
131:4758606c9316 | 434 | /* hdr->seq = long_be(t->snd_nxt); / * XXX disabled this to not to mess with seq nrs of ACKs anymore * / */ |
TASS Belgium NV |
131:4758606c9316 | 435 | } else { |
TASS Belgium NV |
131:4758606c9316 | 436 | tcp_dbg("%s: non-pure ACK with len=0, fl:%04x\n", __FUNCTION__, hdr->flags); |
TASS Belgium NV |
131:4758606c9316 | 437 | } |
TASS Belgium NV |
131:4758606c9316 | 438 | |
TASS Belgium NV |
131:4758606c9316 | 439 | pico_network_send(f); |
TASS Belgium NV |
131:4758606c9316 | 440 | return 0; |
daniele | 29:1a47b7151851 | 441 | } |
daniele | 29:1a47b7151851 | 442 | |
tass | 95:f4ca916a26fe | 443 | int32_t pico_tcp_push(struct pico_protocol *self, struct pico_frame *data); |
daniele | 29:1a47b7151851 | 444 | |
daniele | 29:1a47b7151851 | 445 | /* Interface: protocol definition */ |
daniele | 29:1a47b7151851 | 446 | struct pico_protocol pico_proto_tcp = { |
TASS Belgium NV |
131:4758606c9316 | 447 | .name = "tcp", |
TASS Belgium NV |
131:4758606c9316 | 448 | .proto_number = PICO_PROTO_TCP, |
TASS Belgium NV |
131:4758606c9316 | 449 | .layer = PICO_LAYER_TRANSPORT, |
TASS Belgium NV |
131:4758606c9316 | 450 | .process_in = pico_transport_process_in, |
TASS Belgium NV |
131:4758606c9316 | 451 | .process_out = pico_tcp_process_out, |
TASS Belgium NV |
131:4758606c9316 | 452 | .push = pico_tcp_push, |
TASS Belgium NV |
131:4758606c9316 | 453 | .q_in = &tcp_in, |
TASS Belgium NV |
131:4758606c9316 | 454 | .q_out = &tcp_out, |
daniele | 29:1a47b7151851 | 455 | }; |
daniele | 29:1a47b7151851 | 456 | |
daniele | 29:1a47b7151851 | 457 | static uint32_t pico_paws(void) |
daniele | 29:1a47b7151851 | 458 | { |
TASS Belgium NV |
131:4758606c9316 | 459 | static uint32_t _paws = 0; |
TASS Belgium NV |
131:4758606c9316 | 460 | _paws = pico_rand(); |
TASS Belgium NV |
131:4758606c9316 | 461 | return long_be(_paws); /*XXX: implement paws */ |
daniele | 29:1a47b7151851 | 462 | } |
daniele | 29:1a47b7151851 | 463 | |
tass | 70:cd218dd180e5 | 464 | static void tcp_add_options(struct pico_socket_tcp *ts, struct pico_frame *f, uint16_t flags, uint16_t optsiz) |
daniele | 29:1a47b7151851 | 465 | { |
TASS Belgium NV |
131:4758606c9316 | 466 | uint32_t tsval = long_be((uint32_t)pico_tick); |
TASS Belgium NV |
131:4758606c9316 | 467 | uint32_t tsecr = long_be(ts->ts_nxt); |
TASS Belgium NV |
131:4758606c9316 | 468 | uint32_t i = 0; |
TASS Belgium NV |
131:4758606c9316 | 469 | f->start = f->transport_hdr + PICO_SIZE_TCPHDR; |
TASS Belgium NV |
131:4758606c9316 | 470 | |
TASS Belgium NV |
131:4758606c9316 | 471 | memset(f->start, PICO_TCP_OPTION_NOOP, optsiz); /* fill blanks with noop */ |
TASS Belgium NV |
131:4758606c9316 | 472 | |
TASS Belgium NV |
131:4758606c9316 | 473 | if (flags & PICO_TCP_SYN) { |
TASS Belgium NV |
131:4758606c9316 | 474 | f->start[i++] = PICO_TCP_OPTION_MSS; |
TASS Belgium NV |
131:4758606c9316 | 475 | f->start[i++] = PICO_TCPOPTLEN_MSS; |
TASS Belgium NV |
131:4758606c9316 | 476 | f->start[i++] = (uint8_t)((ts->mss >> 8) & 0xFF); |
TASS Belgium NV |
131:4758606c9316 | 477 | f->start[i++] = (uint8_t)(ts->mss & 0xFF); |
TASS Belgium NV |
131:4758606c9316 | 478 | f->start[i++] = PICO_TCP_OPTION_SACK_OK; |
TASS Belgium NV |
131:4758606c9316 | 479 | f->start[i++] = PICO_TCPOPTLEN_SACK_OK; |
TASS Belgium NV |
131:4758606c9316 | 480 | } |
TASS Belgium NV |
131:4758606c9316 | 481 | |
TASS Belgium NV |
131:4758606c9316 | 482 | f->start[i++] = PICO_TCP_OPTION_WS; |
TASS Belgium NV |
131:4758606c9316 | 483 | f->start[i++] = PICO_TCPOPTLEN_WS; |
TASS Belgium NV |
131:4758606c9316 | 484 | f->start[i++] = (uint8_t)(ts->wnd_scale); |
TASS Belgium NV |
131:4758606c9316 | 485 | |
TASS Belgium NV |
131:4758606c9316 | 486 | if ((flags & PICO_TCP_SYN) || ts->ts_ok) { |
TASS Belgium NV |
131:4758606c9316 | 487 | f->start[i++] = PICO_TCP_OPTION_TIMESTAMP; |
TASS Belgium NV |
131:4758606c9316 | 488 | f->start[i++] = PICO_TCPOPTLEN_TIMESTAMP; |
TASS Belgium NV |
131:4758606c9316 | 489 | memcpy(f->start + i, &tsval, 4); |
TASS Belgium NV |
131:4758606c9316 | 490 | i += 4; |
TASS Belgium NV |
131:4758606c9316 | 491 | memcpy(f->start + i, &tsecr, 4); |
TASS Belgium NV |
131:4758606c9316 | 492 | i += 4; |
TASS Belgium NV |
131:4758606c9316 | 493 | } |
TASS Belgium NV |
131:4758606c9316 | 494 | |
TASS Belgium NV |
131:4758606c9316 | 495 | if (flags & PICO_TCP_ACK) { |
TASS Belgium NV |
131:4758606c9316 | 496 | struct tcp_sack_block *sb; |
TASS Belgium NV |
131:4758606c9316 | 497 | uint32_t len_off; |
TASS Belgium NV |
131:4758606c9316 | 498 | |
TASS Belgium NV |
131:4758606c9316 | 499 | if (ts->sack_ok && ts->sacks) { |
TASS Belgium NV |
131:4758606c9316 | 500 | f->start[i++] = PICO_TCP_OPTION_SACK; |
TASS Belgium NV |
131:4758606c9316 | 501 | len_off = i; |
TASS Belgium NV |
131:4758606c9316 | 502 | f->start[i++] = PICO_TCPOPTLEN_SACK; |
TASS Belgium NV |
131:4758606c9316 | 503 | while(ts->sacks) { |
TASS Belgium NV |
131:4758606c9316 | 504 | sb = ts->sacks; |
TASS Belgium NV |
131:4758606c9316 | 505 | ts->sacks = sb->next; |
TASS Belgium NV |
131:4758606c9316 | 506 | memcpy(f->start + i, sb, 2 * sizeof(uint32_t)); |
TASS Belgium NV |
131:4758606c9316 | 507 | i += (2 * (uint32_t)sizeof(uint32_t)); |
TASS Belgium NV |
131:4758606c9316 | 508 | f->start[len_off] = (uint8_t)(f->start[len_off] + (2 * sizeof(uint32_t))); |
TASS Belgium NV |
131:4758606c9316 | 509 | pico_free(sb); |
TASS Belgium NV |
131:4758606c9316 | 510 | } |
TASS Belgium NV |
131:4758606c9316 | 511 | } |
daniele | 29:1a47b7151851 | 512 | } |
TASS Belgium NV |
131:4758606c9316 | 513 | |
TASS Belgium NV |
131:4758606c9316 | 514 | if (i < optsiz) |
TASS Belgium NV |
131:4758606c9316 | 515 | f->start[ optsiz - 1 ] = PICO_TCP_OPTION_END; |
TASS Belgium NV |
131:4758606c9316 | 516 | } |
TASS Belgium NV |
131:4758606c9316 | 517 | |
TASS Belgium NV |
131:4758606c9316 | 518 | static uint16_t tcp_options_size_frame(struct pico_frame *f) |
TASS Belgium NV |
131:4758606c9316 | 519 | { |
TASS Belgium NV |
131:4758606c9316 | 520 | uint16_t size = 0; |
TASS Belgium NV |
131:4758606c9316 | 521 | |
TASS Belgium NV |
131:4758606c9316 | 522 | /* Always update window scale. */ |
TASS Belgium NV |
131:4758606c9316 | 523 | size = (uint16_t)(size + PICO_TCPOPTLEN_WS); |
TASS Belgium NV |
131:4758606c9316 | 524 | if (f->transport_flags_saved) |
TASS Belgium NV |
131:4758606c9316 | 525 | size = (uint16_t)(size + PICO_TCPOPTLEN_TIMESTAMP); |
TASS Belgium NV |
131:4758606c9316 | 526 | |
TASS Belgium NV |
131:4758606c9316 | 527 | size = (uint16_t)(size + PICO_TCPOPTLEN_END); |
TASS Belgium NV |
131:4758606c9316 | 528 | size = (uint16_t)(((size + 3) >> 2) << 2); |
TASS Belgium NV |
131:4758606c9316 | 529 | return size; |
TASS Belgium NV |
131:4758606c9316 | 530 | } |
TASS Belgium NV |
131:4758606c9316 | 531 | |
TASS Belgium NV |
131:4758606c9316 | 532 | static void tcp_add_options_frame(struct pico_socket_tcp *ts, struct pico_frame *f) |
TASS Belgium NV |
131:4758606c9316 | 533 | { |
TASS Belgium NV |
131:4758606c9316 | 534 | uint32_t tsval = long_be((uint32_t)pico_tick); |
TASS Belgium NV |
131:4758606c9316 | 535 | uint32_t tsecr = long_be(ts->ts_nxt); |
TASS Belgium NV |
131:4758606c9316 | 536 | uint32_t i = 0; |
TASS Belgium NV |
131:4758606c9316 | 537 | uint16_t optsiz = tcp_options_size_frame(f); |
TASS Belgium NV |
131:4758606c9316 | 538 | |
TASS Belgium NV |
131:4758606c9316 | 539 | f->start = f->transport_hdr + PICO_SIZE_TCPHDR; |
TASS Belgium NV |
131:4758606c9316 | 540 | |
TASS Belgium NV |
131:4758606c9316 | 541 | memset(f->start, PICO_TCP_OPTION_NOOP, optsiz); /* fill blanks with noop */ |
TASS Belgium NV |
131:4758606c9316 | 542 | |
TASS Belgium NV |
131:4758606c9316 | 543 | |
TASS Belgium NV |
131:4758606c9316 | 544 | f->start[i++] = PICO_TCP_OPTION_WS; |
TASS Belgium NV |
131:4758606c9316 | 545 | f->start[i++] = PICO_TCPOPTLEN_WS; |
TASS Belgium NV |
131:4758606c9316 | 546 | f->start[i++] = (uint8_t)(ts->wnd_scale); |
TASS Belgium NV |
131:4758606c9316 | 547 | |
TASS Belgium NV |
131:4758606c9316 | 548 | if (f->transport_flags_saved) { |
TASS Belgium NV |
131:4758606c9316 | 549 | f->start[i++] = PICO_TCP_OPTION_TIMESTAMP; |
TASS Belgium NV |
131:4758606c9316 | 550 | f->start[i++] = PICO_TCPOPTLEN_TIMESTAMP; |
TASS Belgium NV |
131:4758606c9316 | 551 | memcpy(f->start + i, &tsval, 4); |
TASS Belgium NV |
131:4758606c9316 | 552 | i += 4; |
TASS Belgium NV |
131:4758606c9316 | 553 | memcpy(f->start + i, &tsecr, 4); |
TASS Belgium NV |
131:4758606c9316 | 554 | i += 4; |
TASS Belgium NV |
131:4758606c9316 | 555 | } |
TASS Belgium NV |
131:4758606c9316 | 556 | |
TASS Belgium NV |
131:4758606c9316 | 557 | if (i < optsiz) |
TASS Belgium NV |
131:4758606c9316 | 558 | f->start[ optsiz - 1 ] = PICO_TCP_OPTION_END; |
daniele | 29:1a47b7151851 | 559 | } |
daniele | 29:1a47b7151851 | 560 | |
daniele | 29:1a47b7151851 | 561 | static void tcp_send_ack(struct pico_socket_tcp *t); |
tass | 75:a9abf10138d6 | 562 | #define tcp_send_windowUpdate(t) (tcp_send_ack(t)) |
daniele | 29:1a47b7151851 | 563 | |
daniele | 29:1a47b7151851 | 564 | static void tcp_set_space(struct pico_socket_tcp *t) |
daniele | 29:1a47b7151851 | 565 | { |
TASS Belgium NV |
131:4758606c9316 | 566 | uint32_t mtu; |
TASS Belgium NV |
131:4758606c9316 | 567 | int32_t space; |
TASS Belgium NV |
131:4758606c9316 | 568 | uint32_t shift = 0; |
TASS Belgium NV |
131:4758606c9316 | 569 | |
TASS Belgium NV |
131:4758606c9316 | 570 | mtu = t->mss + PICO_SIZE_TCPHDR + PICO_SIZE_TCPOPT_SYN; |
TASS Belgium NV |
131:4758606c9316 | 571 | if (t->tcpq_in.max_size == 0) { |
TASS Belgium NV |
131:4758606c9316 | 572 | space = 1024 * 1024 * 1024; /* One Gigabyte, for unlimited sockets. */ |
TASS Belgium NV |
131:4758606c9316 | 573 | } else { |
TASS Belgium NV |
131:4758606c9316 | 574 | space = (int32_t)(((t->tcpq_in.max_size - t->tcpq_in.size) / mtu) * t->mss); |
tass | 75:a9abf10138d6 | 575 | } |
TASS Belgium NV |
131:4758606c9316 | 576 | |
TASS Belgium NV |
131:4758606c9316 | 577 | if (space < 0) |
TASS Belgium NV |
131:4758606c9316 | 578 | space = 0; |
TASS Belgium NV |
131:4758606c9316 | 579 | |
TASS Belgium NV |
131:4758606c9316 | 580 | while(space > 0xFFFF) { |
TASS Belgium NV |
131:4758606c9316 | 581 | space >>= 1; |
TASS Belgium NV |
131:4758606c9316 | 582 | shift++; |
TASS Belgium NV |
131:4758606c9316 | 583 | } |
TASS Belgium NV |
131:4758606c9316 | 584 | if ((space != t->wnd) || (shift != t->wnd_scale) || ((space - t->wnd) > (space >> 2))) { |
TASS Belgium NV |
131:4758606c9316 | 585 | t->wnd = (uint16_t)space; |
TASS Belgium NV |
131:4758606c9316 | 586 | t->wnd_scale = (uint16_t)shift; |
TASS Belgium NV |
131:4758606c9316 | 587 | |
TASS Belgium NV |
131:4758606c9316 | 588 | if(t->wnd == 0) /* mark the entering to zero window state */ |
TASS Belgium NV |
131:4758606c9316 | 589 | t->localZeroWindow = 1u; |
TASS Belgium NV |
131:4758606c9316 | 590 | else if(t->localZeroWindow) |
TASS Belgium NV |
131:4758606c9316 | 591 | { |
TASS Belgium NV |
131:4758606c9316 | 592 | t->localZeroWindow = 0u; |
TASS Belgium NV |
131:4758606c9316 | 593 | tcp_send_windowUpdate(t); |
TASS Belgium NV |
131:4758606c9316 | 594 | } |
TASS Belgium NV |
131:4758606c9316 | 595 | } |
daniele | 29:1a47b7151851 | 596 | } |
daniele | 29:1a47b7151851 | 597 | |
daniele | 29:1a47b7151851 | 598 | /* Return 32-bit aligned option size */ |
tass | 70:cd218dd180e5 | 599 | static uint16_t tcp_options_size(struct pico_socket_tcp *t, uint16_t flags) |
daniele | 29:1a47b7151851 | 600 | { |
TASS Belgium NV |
131:4758606c9316 | 601 | uint16_t size = 0; |
TASS Belgium NV |
131:4758606c9316 | 602 | struct tcp_sack_block *sb = t->sacks; |
TASS Belgium NV |
131:4758606c9316 | 603 | |
TASS Belgium NV |
131:4758606c9316 | 604 | if (flags & PICO_TCP_SYN) { /* Full options */ |
TASS Belgium NV |
131:4758606c9316 | 605 | size = PICO_TCPOPTLEN_MSS + PICO_TCP_OPTION_SACK_OK + PICO_TCPOPTLEN_WS + PICO_TCPOPTLEN_TIMESTAMP; |
TASS Belgium NV |
131:4758606c9316 | 606 | } else { |
TASS Belgium NV |
131:4758606c9316 | 607 | |
TASS Belgium NV |
131:4758606c9316 | 608 | /* Always update window scale. */ |
TASS Belgium NV |
131:4758606c9316 | 609 | size = (uint16_t)(size + PICO_TCPOPTLEN_WS); |
TASS Belgium NV |
131:4758606c9316 | 610 | |
TASS Belgium NV |
131:4758606c9316 | 611 | if (t->ts_ok) |
TASS Belgium NV |
131:4758606c9316 | 612 | size = (uint16_t)(size + PICO_TCPOPTLEN_TIMESTAMP); |
TASS Belgium NV |
131:4758606c9316 | 613 | |
TASS Belgium NV |
131:4758606c9316 | 614 | size = (uint16_t)(size + PICO_TCPOPTLEN_END); |
daniele | 29:1a47b7151851 | 615 | } |
TASS Belgium NV |
131:4758606c9316 | 616 | |
TASS Belgium NV |
131:4758606c9316 | 617 | if ((flags & PICO_TCP_ACK) && (t->sack_ok && sb)) { |
TASS Belgium NV |
131:4758606c9316 | 618 | size = (uint16_t)(size + 2); |
TASS Belgium NV |
131:4758606c9316 | 619 | while(sb) { |
TASS Belgium NV |
131:4758606c9316 | 620 | size = (uint16_t)(size + (2 * sizeof(uint32_t))); |
TASS Belgium NV |
131:4758606c9316 | 621 | sb = sb->next; |
TASS Belgium NV |
131:4758606c9316 | 622 | } |
TASS Belgium NV |
131:4758606c9316 | 623 | } |
TASS Belgium NV |
131:4758606c9316 | 624 | |
TASS Belgium NV |
131:4758606c9316 | 625 | size = (uint16_t)(((size + 3) >> 2) << 2); |
TASS Belgium NV |
131:4758606c9316 | 626 | return size; |
daniele | 29:1a47b7151851 | 627 | } |
daniele | 29:1a47b7151851 | 628 | |
tass | 70:cd218dd180e5 | 629 | uint16_t pico_tcp_overhead(struct pico_socket *s) |
daniele | 29:1a47b7151851 | 630 | { |
TASS Belgium NV |
131:4758606c9316 | 631 | if (!s) |
TASS Belgium NV |
131:4758606c9316 | 632 | return 0; |
TASS Belgium NV |
131:4758606c9316 | 633 | |
TASS Belgium NV |
131:4758606c9316 | 634 | return (uint16_t)(PICO_SIZE_TCPHDR + tcp_options_size((struct pico_socket_tcp *)s, (uint16_t)0)); /* hdr + Options size for data pkt */ |
daniele | 29:1a47b7151851 | 635 | |
daniele | 29:1a47b7151851 | 636 | } |
daniele | 29:1a47b7151851 | 637 | |
daniele | 29:1a47b7151851 | 638 | static void tcp_process_sack(struct pico_socket_tcp *t, uint32_t start, uint32_t end) |
daniele | 29:1a47b7151851 | 639 | { |
TASS Belgium NV |
131:4758606c9316 | 640 | struct pico_frame *f; |
TASS Belgium NV |
131:4758606c9316 | 641 | struct pico_tree_node *index, *temp; |
TASS Belgium NV |
131:4758606c9316 | 642 | int cmp; |
TASS Belgium NV |
131:4758606c9316 | 643 | uint16_t count = 0; |
TASS Belgium NV |
131:4758606c9316 | 644 | |
TASS Belgium NV |
131:4758606c9316 | 645 | pico_tree_foreach_safe(index, &t->tcpq_out.pool, temp){ |
TASS Belgium NV |
131:4758606c9316 | 646 | f = index->keyValue; |
TASS Belgium NV |
131:4758606c9316 | 647 | cmp = seq_compare(SEQN(f), start); |
TASS Belgium NV |
131:4758606c9316 | 648 | if (cmp > 0) |
TASS Belgium NV |
131:4758606c9316 | 649 | goto done; |
TASS Belgium NV |
131:4758606c9316 | 650 | |
TASS Belgium NV |
131:4758606c9316 | 651 | if (cmp == 0) { |
TASS Belgium NV |
131:4758606c9316 | 652 | cmp = seq_compare(SEQN(f) + f->payload_len, end); |
TASS Belgium NV |
131:4758606c9316 | 653 | if (cmp > 0) { |
TASS Belgium NV |
131:4758606c9316 | 654 | tcp_dbg("Invalid SACK: ignoring.\n"); |
TASS Belgium NV |
131:4758606c9316 | 655 | } |
TASS Belgium NV |
131:4758606c9316 | 656 | |
TASS Belgium NV |
131:4758606c9316 | 657 | tcp_dbg("Marking (by SACK) segment %08x BLK:[%08x::%08x]\n", SEQN(f), start, end); |
TASS Belgium NV |
131:4758606c9316 | 658 | f->flags |= PICO_FRAME_FLAG_SACKED; |
TASS Belgium NV |
131:4758606c9316 | 659 | count++; |
TASS Belgium NV |
131:4758606c9316 | 660 | |
TASS Belgium NV |
131:4758606c9316 | 661 | if (cmp == 0) { |
TASS Belgium NV |
131:4758606c9316 | 662 | /* that was last segment sacked. Job done */ |
TASS Belgium NV |
131:4758606c9316 | 663 | goto done; |
TASS Belgium NV |
131:4758606c9316 | 664 | } |
TASS Belgium NV |
131:4758606c9316 | 665 | } |
daniele | 29:1a47b7151851 | 666 | } |
daniele | 29:1a47b7151851 | 667 | |
daniele | 29:1a47b7151851 | 668 | done: |
TASS Belgium NV |
131:4758606c9316 | 669 | if (t->x_mode > PICO_TCP_LOOKAHEAD) { |
TASS Belgium NV |
131:4758606c9316 | 670 | if (t->in_flight > (count)) |
TASS Belgium NV |
131:4758606c9316 | 671 | t->in_flight -= (count); |
TASS Belgium NV |
131:4758606c9316 | 672 | else |
TASS Belgium NV |
131:4758606c9316 | 673 | t->in_flight = 0; |
TASS Belgium NV |
131:4758606c9316 | 674 | } |
daniele | 29:1a47b7151851 | 675 | } |
daniele | 29:1a47b7151851 | 676 | |
TASS Belgium NV |
131:4758606c9316 | 677 | inline static void tcp_add_header(struct pico_socket_tcp *t, struct pico_frame *f) |
tass | 70:cd218dd180e5 | 678 | { |
TASS Belgium NV |
131:4758606c9316 | 679 | struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *)f->transport_hdr; |
TASS Belgium NV |
131:4758606c9316 | 680 | f->timestamp = pico_tick; |
TASS Belgium NV |
131:4758606c9316 | 681 | tcp_add_options(t, f, 0, (uint16_t)(f->transport_len - f->payload_len - (uint16_t)PICO_SIZE_TCPHDR)); |
TASS Belgium NV |
131:4758606c9316 | 682 | hdr->rwnd = short_be(t->wnd); |
TASS Belgium NV |
131:4758606c9316 | 683 | hdr->flags |= PICO_TCP_PSH; |
TASS Belgium NV |
131:4758606c9316 | 684 | hdr->ack = long_be(t->rcv_nxt); |
TASS Belgium NV |
131:4758606c9316 | 685 | hdr->crc = 0; |
TASS Belgium NV |
131:4758606c9316 | 686 | hdr->crc = short_be(pico_tcp_checksum_ipv4(f)); |
tass | 70:cd218dd180e5 | 687 | } |
tass | 70:cd218dd180e5 | 688 | |
daniele | 29:1a47b7151851 | 689 | static void tcp_rcv_sack(struct pico_socket_tcp *t, uint8_t *opt, int len) |
daniele | 29:1a47b7151851 | 690 | { |
TASS Belgium NV |
131:4758606c9316 | 691 | uint32_t start, end; |
TASS Belgium NV |
131:4758606c9316 | 692 | int i = 0; |
TASS Belgium NV |
131:4758606c9316 | 693 | if (len % 8) { |
TASS Belgium NV |
131:4758606c9316 | 694 | tcp_dbg("SACK: Invalid len.\n"); |
TASS Belgium NV |
131:4758606c9316 | 695 | return; |
TASS Belgium NV |
131:4758606c9316 | 696 | } |
TASS Belgium NV |
131:4758606c9316 | 697 | |
TASS Belgium NV |
131:4758606c9316 | 698 | while (i < len) { |
TASS Belgium NV |
131:4758606c9316 | 699 | start = long_from(opt + i); |
TASS Belgium NV |
131:4758606c9316 | 700 | i += 4; |
TASS Belgium NV |
131:4758606c9316 | 701 | end = long_from(opt + i); |
TASS Belgium NV |
131:4758606c9316 | 702 | i += 4; |
TASS Belgium NV |
131:4758606c9316 | 703 | tcp_process_sack(t, long_be(start), long_be(end)); |
TASS Belgium NV |
131:4758606c9316 | 704 | } |
daniele | 29:1a47b7151851 | 705 | } |
daniele | 29:1a47b7151851 | 706 | |
daniele | 29:1a47b7151851 | 707 | static void tcp_parse_options(struct pico_frame *f) |
daniele | 29:1a47b7151851 | 708 | { |
TASS Belgium NV |
131:4758606c9316 | 709 | struct pico_socket_tcp *t = (struct pico_socket_tcp *)f->sock; |
TASS Belgium NV |
131:4758606c9316 | 710 | uint8_t *opt = f->transport_hdr + PICO_SIZE_TCPHDR; |
TASS Belgium NV |
131:4758606c9316 | 711 | uint32_t i = 0; |
TASS Belgium NV |
131:4758606c9316 | 712 | f->timestamp = 0; |
TASS Belgium NV |
131:4758606c9316 | 713 | while (i < (f->transport_len - PICO_SIZE_TCPHDR)) { |
TASS Belgium NV |
131:4758606c9316 | 714 | uint8_t type = opt[i++]; |
TASS Belgium NV |
131:4758606c9316 | 715 | uint8_t len; |
TASS Belgium NV |
131:4758606c9316 | 716 | if(i < (f->transport_len - PICO_SIZE_TCPHDR) && (type > 1)) |
TASS Belgium NV |
131:4758606c9316 | 717 | len = opt[i++]; |
TASS Belgium NV |
131:4758606c9316 | 718 | else |
TASS Belgium NV |
131:4758606c9316 | 719 | len = 1; |
TASS Belgium NV |
131:4758606c9316 | 720 | |
TASS Belgium NV |
131:4758606c9316 | 721 | if (f->payload && ((opt + i) > f->payload)) |
TASS Belgium NV |
131:4758606c9316 | 722 | break; |
TASS Belgium NV |
131:4758606c9316 | 723 | |
TASS Belgium NV |
131:4758606c9316 | 724 | tcp_dbg_options("Received option '%d', len = %d \n", type, len); |
TASS Belgium NV |
131:4758606c9316 | 725 | switch (type) { |
TASS Belgium NV |
131:4758606c9316 | 726 | case PICO_TCP_OPTION_NOOP: |
TASS Belgium NV |
131:4758606c9316 | 727 | case PICO_TCP_OPTION_END: |
TASS Belgium NV |
131:4758606c9316 | 728 | break; |
TASS Belgium NV |
131:4758606c9316 | 729 | case PICO_TCP_OPTION_WS: |
TASS Belgium NV |
131:4758606c9316 | 730 | if (len != PICO_TCPOPTLEN_WS) { |
TASS Belgium NV |
131:4758606c9316 | 731 | tcp_dbg_options("TCP Window scale: bad len received (%d).\n", len); |
TASS Belgium NV |
131:4758606c9316 | 732 | i = i + len - 2; |
TASS Belgium NV |
131:4758606c9316 | 733 | break; |
TASS Belgium NV |
131:4758606c9316 | 734 | } |
TASS Belgium NV |
131:4758606c9316 | 735 | |
TASS Belgium NV |
131:4758606c9316 | 736 | t->recv_wnd_scale = opt[i++]; |
TASS Belgium NV |
131:4758606c9316 | 737 | tcp_dbg_options("TCP Window scale: received %d\n", t->recv_wnd_scale); |
TASS Belgium NV |
131:4758606c9316 | 738 | break; |
TASS Belgium NV |
131:4758606c9316 | 739 | case PICO_TCP_OPTION_SACK_OK: |
TASS Belgium NV |
131:4758606c9316 | 740 | if (len != PICO_TCPOPTLEN_SACK_OK) { |
TASS Belgium NV |
131:4758606c9316 | 741 | tcp_dbg_options("TCP option sack: bad len received.\n"); |
TASS Belgium NV |
131:4758606c9316 | 742 | i = i + len - 2; |
TASS Belgium NV |
131:4758606c9316 | 743 | break; |
TASS Belgium NV |
131:4758606c9316 | 744 | } |
TASS Belgium NV |
131:4758606c9316 | 745 | |
TASS Belgium NV |
131:4758606c9316 | 746 | if(((struct pico_tcp_hdr *)(f->transport_hdr))->flags & PICO_TCP_SYN ) |
TASS Belgium NV |
131:4758606c9316 | 747 | t->sack_ok = 1; |
TASS Belgium NV |
131:4758606c9316 | 748 | |
TASS Belgium NV |
131:4758606c9316 | 749 | break; |
TASS Belgium NV |
131:4758606c9316 | 750 | case PICO_TCP_OPTION_MSS: { |
TASS Belgium NV |
131:4758606c9316 | 751 | uint16_t mss; |
TASS Belgium NV |
131:4758606c9316 | 752 | if (len != PICO_TCPOPTLEN_MSS) { |
TASS Belgium NV |
131:4758606c9316 | 753 | tcp_dbg_options("TCP option mss: bad len received.\n"); |
TASS Belgium NV |
131:4758606c9316 | 754 | i = i + len - 2; |
TASS Belgium NV |
131:4758606c9316 | 755 | break; |
TASS Belgium NV |
131:4758606c9316 | 756 | } |
TASS Belgium NV |
131:4758606c9316 | 757 | |
TASS Belgium NV |
131:4758606c9316 | 758 | t->mss_ok = 1; |
TASS Belgium NV |
131:4758606c9316 | 759 | mss = short_from(opt + i); |
TASS Belgium NV |
131:4758606c9316 | 760 | i += (uint32_t)sizeof(uint16_t); |
TASS Belgium NV |
131:4758606c9316 | 761 | if (t->mss > short_be(mss)) |
TASS Belgium NV |
131:4758606c9316 | 762 | t->mss = short_be(mss); |
TASS Belgium NV |
131:4758606c9316 | 763 | |
TASS Belgium NV |
131:4758606c9316 | 764 | break; |
daniele | 29:1a47b7151851 | 765 | } |
TASS Belgium NV |
131:4758606c9316 | 766 | case PICO_TCP_OPTION_TIMESTAMP: { |
TASS Belgium NV |
131:4758606c9316 | 767 | uint32_t tsval, tsecr; |
TASS Belgium NV |
131:4758606c9316 | 768 | if (len != PICO_TCPOPTLEN_TIMESTAMP) { |
TASS Belgium NV |
131:4758606c9316 | 769 | tcp_dbg_options("TCP option timestamp: bad len received.\n"); |
TASS Belgium NV |
131:4758606c9316 | 770 | i = i + len - 2; |
TASS Belgium NV |
131:4758606c9316 | 771 | break; |
TASS Belgium NV |
131:4758606c9316 | 772 | } |
TASS Belgium NV |
131:4758606c9316 | 773 | |
TASS Belgium NV |
131:4758606c9316 | 774 | t->ts_ok = 1; |
TASS Belgium NV |
131:4758606c9316 | 775 | tsval = long_from(opt + i); |
TASS Belgium NV |
131:4758606c9316 | 776 | i += (uint32_t)sizeof(uint32_t); |
TASS Belgium NV |
131:4758606c9316 | 777 | tsecr = long_from(opt + i); |
TASS Belgium NV |
131:4758606c9316 | 778 | f->timestamp = long_be(tsecr); |
TASS Belgium NV |
131:4758606c9316 | 779 | i += (uint32_t)sizeof(uint32_t); |
TASS Belgium NV |
131:4758606c9316 | 780 | t->ts_nxt = long_be(tsval); |
TASS Belgium NV |
131:4758606c9316 | 781 | break; |
daniele | 29:1a47b7151851 | 782 | } |
TASS Belgium NV |
131:4758606c9316 | 783 | case PICO_TCP_OPTION_SACK: |
TASS Belgium NV |
131:4758606c9316 | 784 | { |
TASS Belgium NV |
131:4758606c9316 | 785 | tcp_rcv_sack(t, opt + i, len - 2); |
TASS Belgium NV |
131:4758606c9316 | 786 | i = i + len - 2; |
TASS Belgium NV |
131:4758606c9316 | 787 | break; |
daniele | 29:1a47b7151851 | 788 | } |
TASS Belgium NV |
131:4758606c9316 | 789 | default: |
TASS Belgium NV |
131:4758606c9316 | 790 | tcp_dbg_options("TCP: received unsupported option %u\n", type); |
TASS Belgium NV |
131:4758606c9316 | 791 | i = i + len - 2; |
TASS Belgium NV |
131:4758606c9316 | 792 | } |
daniele | 29:1a47b7151851 | 793 | } |
daniele | 29:1a47b7151851 | 794 | } |
daniele | 29:1a47b7151851 | 795 | |
daniele | 29:1a47b7151851 | 796 | static int tcp_send(struct pico_socket_tcp *ts, struct pico_frame *f) |
daniele | 29:1a47b7151851 | 797 | { |
TASS Belgium NV |
131:4758606c9316 | 798 | struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *) f->transport_hdr; |
TASS Belgium NV |
131:4758606c9316 | 799 | struct pico_frame *cpy; |
TASS Belgium NV |
131:4758606c9316 | 800 | hdr->trans.sport = ts->sock.local_port; |
TASS Belgium NV |
131:4758606c9316 | 801 | hdr->trans.dport = ts->sock.remote_port; |
TASS Belgium NV |
131:4758606c9316 | 802 | if (!hdr->seq) |
TASS Belgium NV |
131:4758606c9316 | 803 | hdr->seq = long_be(ts->snd_nxt); |
TASS Belgium NV |
131:4758606c9316 | 804 | |
TASS Belgium NV |
131:4758606c9316 | 805 | if (ts->rcv_nxt != 0) { |
TASS Belgium NV |
131:4758606c9316 | 806 | if ((ts->rcv_ackd == 0) || (seq_compare(ts->rcv_ackd, ts->rcv_nxt) != 0) || (hdr->flags & PICO_TCP_ACK)) { |
TASS Belgium NV |
131:4758606c9316 | 807 | hdr->flags |= PICO_TCP_ACK; |
TASS Belgium NV |
131:4758606c9316 | 808 | hdr->ack = long_be(ts->rcv_nxt); |
TASS Belgium NV |
131:4758606c9316 | 809 | ts->rcv_ackd = ts->rcv_nxt; |
TASS Belgium NV |
131:4758606c9316 | 810 | } |
TASS Belgium NV |
131:4758606c9316 | 811 | } |
TASS Belgium NV |
131:4758606c9316 | 812 | |
TASS Belgium NV |
131:4758606c9316 | 813 | if (hdr->flags & PICO_TCP_SYN) { |
TASS Belgium NV |
131:4758606c9316 | 814 | ts->snd_nxt++; |
TASS Belgium NV |
131:4758606c9316 | 815 | } |
TASS Belgium NV |
131:4758606c9316 | 816 | |
TASS Belgium NV |
131:4758606c9316 | 817 | if (f->payload_len > 0) { |
TASS Belgium NV |
131:4758606c9316 | 818 | hdr->flags |= PICO_TCP_PSH | PICO_TCP_ACK; |
TASS Belgium NV |
131:4758606c9316 | 819 | hdr->ack = long_be(ts->rcv_nxt); |
TASS Belgium NV |
131:4758606c9316 | 820 | ts->rcv_ackd = ts->rcv_nxt; |
TASS Belgium NV |
131:4758606c9316 | 821 | ts->keepalive_timer_running = 2; /* XXX TODO check fix: added 1 to counter to postpone sending keepalive, ACK is in data segments */ |
daniele | 29:1a47b7151851 | 822 | } |
TASS Belgium NV |
131:4758606c9316 | 823 | |
TASS Belgium NV |
131:4758606c9316 | 824 | f->start = f->transport_hdr + PICO_SIZE_TCPHDR; |
TASS Belgium NV |
131:4758606c9316 | 825 | hdr->rwnd = short_be(ts->wnd); |
TASS Belgium NV |
131:4758606c9316 | 826 | hdr->crc = 0; |
TASS Belgium NV |
131:4758606c9316 | 827 | hdr->crc = short_be(pico_tcp_checksum_ipv4(f)); |
TASS Belgium NV |
131:4758606c9316 | 828 | |
TASS Belgium NV |
131:4758606c9316 | 829 | /* TCP: ENQUEUE to PROTO ( Transmit ) */ |
TASS Belgium NV |
131:4758606c9316 | 830 | cpy = pico_frame_copy(f); |
TASS Belgium NV |
131:4758606c9316 | 831 | if ((pico_enqueue(&tcp_out, cpy) > 0)) { |
TASS Belgium NV |
131:4758606c9316 | 832 | if (f->payload_len > 0) { |
TASS Belgium NV |
131:4758606c9316 | 833 | ts->in_flight++; |
TASS Belgium NV |
131:4758606c9316 | 834 | ts->snd_nxt += f->payload_len; /* update next pointer here to prevent sending same segment twice when called twice in same tick */ |
TASS Belgium NV |
131:4758606c9316 | 835 | } |
TASS Belgium NV |
131:4758606c9316 | 836 | |
TASS Belgium NV |
131:4758606c9316 | 837 | tcp_dbg("DBG> [tcp output] state: %02x --> local port:%d remote port: %d seq: %08x ack: %08x flags: %02x = t_len: %d, hdr: %u payload: %d\n", |
TASS Belgium NV |
131:4758606c9316 | 838 | TCPSTATE(&ts->sock) >> 8, short_be(hdr->trans.sport), short_be(hdr->trans.dport), SEQN(f), ACKN(f), hdr->flags, f->transport_len, (hdr->len & 0xf0) >> 2, f->payload_len ); |
TASS Belgium NV |
131:4758606c9316 | 839 | } else { |
TASS Belgium NV |
131:4758606c9316 | 840 | pico_frame_discard(cpy); |
tass | 40:c8ab0d2bba0b | 841 | } |
TASS Belgium NV |
131:4758606c9316 | 842 | |
TASS Belgium NV |
131:4758606c9316 | 843 | return 0; |
daniele | 29:1a47b7151851 | 844 | } |
daniele | 29:1a47b7151851 | 845 | |
TASS Belgium NV |
131:4758606c9316 | 846 | /* #define PICO_TCP_SUPPORT_SOCKET_STATS */ |
daniele | 29:1a47b7151851 | 847 | |
daniele | 29:1a47b7151851 | 848 | #ifdef PICO_TCP_SUPPORT_SOCKET_STATS |
tass | 73:dfb737147f6e | 849 | static void sock_stats(uint32_t when, void *arg) |
daniele | 29:1a47b7151851 | 850 | { |
TASS Belgium NV |
131:4758606c9316 | 851 | struct pico_socket_tcp *t = (struct pico_socket_tcp *)arg; |
TASS Belgium NV |
131:4758606c9316 | 852 | tcp_dbg("STATISTIC> [%lu] socket state: %02x --> local port:%d remote port: %d queue size: %d snd_una: %08x snd_nxt: %08x timer: %d cwnd: %d\n", |
TASS Belgium NV |
131:4758606c9316 | 853 | when, t->sock.state, short_be(t->sock.local_port), short_be(t->sock.remote_port), t->tcpq_out.size, SEQN(first_segment(&t->tcpq_out)), t->snd_nxt, t->timer_running, t->cwnd); |
TASS Belgium NV |
131:4758606c9316 | 854 | pico_timer_add(2000, sock_stats, t); |
daniele | 29:1a47b7151851 | 855 | } |
daniele | 29:1a47b7151851 | 856 | #endif |
daniele | 29:1a47b7151851 | 857 | |
daniele | 29:1a47b7151851 | 858 | struct pico_socket *pico_tcp_open(void) |
daniele | 29:1a47b7151851 | 859 | { |
TASS Belgium NV |
131:4758606c9316 | 860 | struct pico_socket_tcp *t = pico_zalloc(sizeof(struct pico_socket_tcp)); |
TASS Belgium NV |
131:4758606c9316 | 861 | if (!t) |
TASS Belgium NV |
131:4758606c9316 | 862 | return NULL; |
TASS Belgium NV |
131:4758606c9316 | 863 | |
TASS Belgium NV |
131:4758606c9316 | 864 | t->sock.timestamp = PICO_TIME_MS(); |
TASS Belgium NV |
131:4758606c9316 | 865 | t->mss = PICO_TCP_DEFAULT_MSS; |
TASS Belgium NV |
131:4758606c9316 | 866 | |
TASS Belgium NV |
131:4758606c9316 | 867 | t->tcpq_in.pool.root = t->tcpq_hold.pool.root = t->tcpq_out.pool.root = &LEAF; |
TASS Belgium NV |
131:4758606c9316 | 868 | t->tcpq_hold.pool.compare = t->tcpq_out.pool.compare = segment_compare; |
TASS Belgium NV |
131:4758606c9316 | 869 | t->tcpq_in.pool.compare = input_segment_compare; |
TASS Belgium NV |
131:4758606c9316 | 870 | t->tcpq_in.max_size = PICO_DEFAULT_SOCKETQ; |
TASS Belgium NV |
131:4758606c9316 | 871 | t->tcpq_out.max_size = PICO_DEFAULT_SOCKETQ; |
TASS Belgium NV |
131:4758606c9316 | 872 | t->tcpq_hold.max_size = 2 * PICO_TCP_DEFAULT_MSS; |
TASS Belgium NV |
131:4758606c9316 | 873 | t->tcpq_in.overhead = (sizeof(struct tcp_input_segment) + sizeof(struct pico_tree_node)); |
TASS Belgium NV |
131:4758606c9316 | 874 | t->tcpq_out.overhead = t->tcpq_hold.overhead = sizeof(struct pico_frame) + sizeof(struct pico_tree_node); |
TASS Belgium NV |
131:4758606c9316 | 875 | /* disable Nagle by default */ |
TASS Belgium NV |
131:4758606c9316 | 876 | /* t->sock.opt_flags |= (1 << PICO_SOCKET_OPT_TCPNODELAY); */ |
TASS Belgium NV |
131:4758606c9316 | 877 | /* Nagle is enabled by default */ |
TASS Belgium NV |
131:4758606c9316 | 878 | t->sock.opt_flags &= (uint16_t) ~(1 << PICO_SOCKET_OPT_TCPNODELAY); |
daniele | 29:1a47b7151851 | 879 | |
daniele | 29:1a47b7151851 | 880 | #ifdef PICO_TCP_SUPPORT_SOCKET_STATS |
TASS Belgium NV |
131:4758606c9316 | 881 | pico_timer_add(2000, sock_stats, t); |
daniele | 29:1a47b7151851 | 882 | #endif |
TASS Belgium NV |
131:4758606c9316 | 883 | tcp_set_space(t); |
TASS Belgium NV |
131:4758606c9316 | 884 | |
TASS Belgium NV |
131:4758606c9316 | 885 | return &t->sock; |
daniele | 29:1a47b7151851 | 886 | } |
daniele | 29:1a47b7151851 | 887 | |
tass | 70:cd218dd180e5 | 888 | uint32_t pico_tcp_read(struct pico_socket *s, void *buf, uint32_t len) |
daniele | 29:1a47b7151851 | 889 | { |
TASS Belgium NV |
131:4758606c9316 | 890 | struct pico_socket_tcp *t = TCP_SOCK(s); |
TASS Belgium NV |
131:4758606c9316 | 891 | struct tcp_input_segment *f; |
TASS Belgium NV |
131:4758606c9316 | 892 | uint32_t in_frame_off, in_frame_len; |
TASS Belgium NV |
131:4758606c9316 | 893 | uint32_t tot_rd_len = 0; |
TASS Belgium NV |
131:4758606c9316 | 894 | |
TASS Belgium NV |
131:4758606c9316 | 895 | while (tot_rd_len < len) { |
TASS Belgium NV |
131:4758606c9316 | 896 | /* To be sure we don't have garbage at the beginning */ |
TASS Belgium NV |
131:4758606c9316 | 897 | release_until(&t->tcpq_in, t->rcv_processed); |
TASS Belgium NV |
131:4758606c9316 | 898 | f = first_segment(&t->tcpq_in); |
TASS Belgium NV |
131:4758606c9316 | 899 | if (!f) { |
TASS Belgium NV |
131:4758606c9316 | 900 | tcp_set_space(t); |
TASS Belgium NV |
131:4758606c9316 | 901 | goto out; |
TASS Belgium NV |
131:4758606c9316 | 902 | } |
TASS Belgium NV |
131:4758606c9316 | 903 | |
TASS Belgium NV |
131:4758606c9316 | 904 | /* Hole at the beginning of data, awaiting retransmissions. */ |
TASS Belgium NV |
131:4758606c9316 | 905 | if (seq_compare(t->rcv_processed, f->seq) < 0) { |
TASS Belgium NV |
131:4758606c9316 | 906 | tcp_dbg("TCP> read hole beginning of data, %08x - %08x. rcv_nxt is %08x\n", t->rcv_processed, f->seq, t->rcv_nxt); |
TASS Belgium NV |
131:4758606c9316 | 907 | goto out; |
TASS Belgium NV |
131:4758606c9316 | 908 | } |
TASS Belgium NV |
131:4758606c9316 | 909 | |
TASS Belgium NV |
131:4758606c9316 | 910 | if(seq_compare(t->rcv_processed, f->seq) > 0) { |
TASS Belgium NV |
131:4758606c9316 | 911 | in_frame_off = t->rcv_processed - f->seq; |
TASS Belgium NV |
131:4758606c9316 | 912 | in_frame_len = f->payload_len - in_frame_off; |
TASS Belgium NV |
131:4758606c9316 | 913 | } else { |
TASS Belgium NV |
131:4758606c9316 | 914 | in_frame_off = 0; |
TASS Belgium NV |
131:4758606c9316 | 915 | in_frame_len = f->payload_len; |
TASS Belgium NV |
131:4758606c9316 | 916 | } |
TASS Belgium NV |
131:4758606c9316 | 917 | |
TASS Belgium NV |
131:4758606c9316 | 918 | if ((in_frame_len + tot_rd_len) > (uint32_t)len) { |
TASS Belgium NV |
131:4758606c9316 | 919 | in_frame_len = len - tot_rd_len; |
TASS Belgium NV |
131:4758606c9316 | 920 | } |
TASS Belgium NV |
131:4758606c9316 | 921 | |
TASS Belgium NV |
131:4758606c9316 | 922 | if (in_frame_len > f->payload_len - in_frame_off) |
TASS Belgium NV |
131:4758606c9316 | 923 | in_frame_len = f->payload_len - in_frame_off; |
TASS Belgium NV |
131:4758606c9316 | 924 | |
TASS Belgium NV |
131:4758606c9316 | 925 | memcpy((uint8_t *)buf + tot_rd_len, f->payload + in_frame_off, in_frame_len); |
TASS Belgium NV |
131:4758606c9316 | 926 | tot_rd_len += in_frame_len; |
TASS Belgium NV |
131:4758606c9316 | 927 | t->rcv_processed += in_frame_len; |
TASS Belgium NV |
131:4758606c9316 | 928 | |
TASS Belgium NV |
131:4758606c9316 | 929 | if ((in_frame_len == 0u) || (in_frame_len == (uint32_t)f->payload_len)) { |
TASS Belgium NV |
131:4758606c9316 | 930 | pico_discard_segment(&t->tcpq_in, f); |
TASS Belgium NV |
131:4758606c9316 | 931 | } |
daniele | 29:1a47b7151851 | 932 | } |
TASS Belgium NV |
131:4758606c9316 | 933 | out: |
TASS Belgium NV |
131:4758606c9316 | 934 | tcp_set_space(t); |
TASS Belgium NV |
131:4758606c9316 | 935 | if (t->tcpq_in.size == 0) { |
TASS Belgium NV |
131:4758606c9316 | 936 | s->ev_pending &= (uint16_t)(~PICO_SOCK_EV_RD); |
daniele | 29:1a47b7151851 | 937 | } |
daniele | 29:1a47b7151851 | 938 | |
TASS Belgium NV |
131:4758606c9316 | 939 | return tot_rd_len; |
daniele | 29:1a47b7151851 | 940 | } |
daniele | 29:1a47b7151851 | 941 | |
daniele | 29:1a47b7151851 | 942 | int pico_tcp_initconn(struct pico_socket *s); |
tass | 128:ae39e6e81531 | 943 | static void initconn_retry(pico_time when, void *arg) |
daniele | 29:1a47b7151851 | 944 | { |
TASS Belgium NV |
131:4758606c9316 | 945 | struct pico_socket_tcp *t = (struct pico_socket_tcp *)arg; |
TASS Belgium NV |
131:4758606c9316 | 946 | IGNORE_PARAMETER(when); |
TASS Belgium NV |
131:4758606c9316 | 947 | if (TCPSTATE(&t->sock) == PICO_SOCKET_STATE_TCP_SYN_SENT |
TASS Belgium NV |
131:4758606c9316 | 948 | && !(t->sock.state & PICO_SOCKET_STATE_SHUT_LOCAL) |
TASS Belgium NV |
131:4758606c9316 | 949 | && !(t->sock.state & PICO_SOCKET_STATE_SHUT_REMOTE)) { |
TASS Belgium NV |
131:4758606c9316 | 950 | if (t->backoff > PICO_TCP_MAX_CONNECT_RETRIES) { |
TASS Belgium NV |
131:4758606c9316 | 951 | tcp_dbg("TCP> Connection timeout. \n"); |
TASS Belgium NV |
131:4758606c9316 | 952 | if (t->sock.wakeup) |
TASS Belgium NV |
131:4758606c9316 | 953 | t->sock.wakeup(PICO_SOCK_EV_ERR, &t->sock); |
TASS Belgium NV |
131:4758606c9316 | 954 | |
TASS Belgium NV |
131:4758606c9316 | 955 | return; |
TASS Belgium NV |
131:4758606c9316 | 956 | } |
TASS Belgium NV |
131:4758606c9316 | 957 | |
TASS Belgium NV |
131:4758606c9316 | 958 | tcp_dbg("TCP> SYN retry %d...\n", t->backoff); |
TASS Belgium NV |
131:4758606c9316 | 959 | t->backoff++; |
TASS Belgium NV |
131:4758606c9316 | 960 | pico_tcp_initconn(&t->sock); |
TASS Belgium NV |
131:4758606c9316 | 961 | } else { |
TASS Belgium NV |
131:4758606c9316 | 962 | tcp_dbg("TCP> Connection is already established: no retry needed. good.\n"); |
daniele | 29:1a47b7151851 | 963 | } |
daniele | 29:1a47b7151851 | 964 | } |
daniele | 29:1a47b7151851 | 965 | |
daniele | 29:1a47b7151851 | 966 | int pico_tcp_initconn(struct pico_socket *s) |
daniele | 29:1a47b7151851 | 967 | { |
TASS Belgium NV |
131:4758606c9316 | 968 | struct pico_socket_tcp *ts = TCP_SOCK(s); |
TASS Belgium NV |
131:4758606c9316 | 969 | struct pico_frame *syn; |
TASS Belgium NV |
131:4758606c9316 | 970 | struct pico_tcp_hdr *hdr; |
TASS Belgium NV |
131:4758606c9316 | 971 | uint16_t opt_len = tcp_options_size(ts, PICO_TCP_SYN); |
TASS Belgium NV |
131:4758606c9316 | 972 | |
TASS Belgium NV |
131:4758606c9316 | 973 | syn = s->net->alloc(s->net, (uint16_t)(PICO_SIZE_TCPHDR + opt_len)); |
TASS Belgium NV |
131:4758606c9316 | 974 | if (!syn) |
TASS Belgium NV |
131:4758606c9316 | 975 | return -1; |
TASS Belgium NV |
131:4758606c9316 | 976 | |
TASS Belgium NV |
131:4758606c9316 | 977 | hdr = (struct pico_tcp_hdr *) syn->transport_hdr; |
TASS Belgium NV |
131:4758606c9316 | 978 | |
TASS Belgium NV |
131:4758606c9316 | 979 | if (!ts->snd_nxt) |
TASS Belgium NV |
131:4758606c9316 | 980 | ts->snd_nxt = long_be(pico_paws()); |
TASS Belgium NV |
131:4758606c9316 | 981 | |
TASS Belgium NV |
131:4758606c9316 | 982 | ts->snd_last = ts->snd_nxt; |
TASS Belgium NV |
131:4758606c9316 | 983 | ts->cwnd = PICO_TCP_IW; |
TASS Belgium NV |
131:4758606c9316 | 984 | ts->ssthresh = 40; |
TASS Belgium NV |
131:4758606c9316 | 985 | syn->sock = s; |
TASS Belgium NV |
131:4758606c9316 | 986 | hdr->seq = long_be(ts->snd_nxt); |
TASS Belgium NV |
131:4758606c9316 | 987 | hdr->len = (uint8_t)((PICO_SIZE_TCPHDR + opt_len) << 2 | ts->jumbo); |
TASS Belgium NV |
131:4758606c9316 | 988 | hdr->flags = PICO_TCP_SYN; |
TASS Belgium NV |
131:4758606c9316 | 989 | tcp_set_space(ts); |
TASS Belgium NV |
131:4758606c9316 | 990 | hdr->rwnd = short_be(ts->wnd); |
TASS Belgium NV |
131:4758606c9316 | 991 | tcp_add_options(ts, syn, PICO_TCP_SYN, opt_len); |
TASS Belgium NV |
131:4758606c9316 | 992 | hdr->trans.sport = ts->sock.local_port; |
TASS Belgium NV |
131:4758606c9316 | 993 | hdr->trans.dport = ts->sock.remote_port; |
TASS Belgium NV |
131:4758606c9316 | 994 | |
TASS Belgium NV |
131:4758606c9316 | 995 | hdr->crc = 0; |
TASS Belgium NV |
131:4758606c9316 | 996 | hdr->crc = short_be(pico_tcp_checksum_ipv4(syn)); |
TASS Belgium NV |
131:4758606c9316 | 997 | |
TASS Belgium NV |
131:4758606c9316 | 998 | /* TCP: ENQUEUE to PROTO ( SYN ) */ |
TASS Belgium NV |
131:4758606c9316 | 999 | tcp_dbg("Sending SYN... (ports: %d - %d) size: %d\n", short_be(ts->sock.local_port), short_be(ts->sock.remote_port), syn->buffer_len); |
TASS Belgium NV |
131:4758606c9316 | 1000 | pico_enqueue(&tcp_out, syn); |
TASS Belgium NV |
131:4758606c9316 | 1001 | pico_timer_add(PICO_TCP_SYN_TO << ts->backoff, initconn_retry, ts); |
TASS Belgium NV |
131:4758606c9316 | 1002 | return 0; |
daniele | 29:1a47b7151851 | 1003 | } |
daniele | 29:1a47b7151851 | 1004 | |
daniele | 29:1a47b7151851 | 1005 | static int tcp_send_synack(struct pico_socket *s) |
daniele | 29:1a47b7151851 | 1006 | { |
TASS Belgium NV |
131:4758606c9316 | 1007 | struct pico_socket_tcp *ts = TCP_SOCK(s); |
TASS Belgium NV |
131:4758606c9316 | 1008 | struct pico_frame *synack; |
TASS Belgium NV |
131:4758606c9316 | 1009 | struct pico_tcp_hdr *hdr; |
TASS Belgium NV |
131:4758606c9316 | 1010 | uint16_t opt_len = tcp_options_size(ts, PICO_TCP_SYN | PICO_TCP_ACK); |
TASS Belgium NV |
131:4758606c9316 | 1011 | |
TASS Belgium NV |
131:4758606c9316 | 1012 | synack = s->net->alloc(s->net, (uint16_t)(PICO_SIZE_TCPHDR + opt_len)); |
TASS Belgium NV |
131:4758606c9316 | 1013 | if (!synack) |
TASS Belgium NV |
131:4758606c9316 | 1014 | return -1; |
TASS Belgium NV |
131:4758606c9316 | 1015 | |
TASS Belgium NV |
131:4758606c9316 | 1016 | hdr = (struct pico_tcp_hdr *) synack->transport_hdr; |
TASS Belgium NV |
131:4758606c9316 | 1017 | |
TASS Belgium NV |
131:4758606c9316 | 1018 | synack->sock = s; |
TASS Belgium NV |
131:4758606c9316 | 1019 | hdr->len = (uint8_t)((PICO_SIZE_TCPHDR + opt_len) << 2 | ts->jumbo); |
TASS Belgium NV |
131:4758606c9316 | 1020 | hdr->flags = PICO_TCP_SYN | PICO_TCP_ACK; |
TASS Belgium NV |
131:4758606c9316 | 1021 | hdr->rwnd = short_be(ts->wnd); |
TASS Belgium NV |
131:4758606c9316 | 1022 | hdr->seq = long_be(ts->snd_nxt); |
TASS Belgium NV |
131:4758606c9316 | 1023 | ts->rcv_processed = long_be(hdr->seq); |
TASS Belgium NV |
131:4758606c9316 | 1024 | ts->snd_last = ts->snd_nxt; |
TASS Belgium NV |
131:4758606c9316 | 1025 | tcp_set_space(ts); |
TASS Belgium NV |
131:4758606c9316 | 1026 | tcp_add_options(ts, synack, hdr->flags, opt_len); |
TASS Belgium NV |
131:4758606c9316 | 1027 | synack->payload_len = 0; |
TASS Belgium NV |
131:4758606c9316 | 1028 | synack->timestamp = pico_tick; |
TASS Belgium NV |
131:4758606c9316 | 1029 | tcp_send(ts, synack); |
TASS Belgium NV |
131:4758606c9316 | 1030 | pico_frame_discard(synack); |
TASS Belgium NV |
131:4758606c9316 | 1031 | return 0; |
daniele | 29:1a47b7151851 | 1032 | } |
daniele | 29:1a47b7151851 | 1033 | |
daniele | 29:1a47b7151851 | 1034 | static void tcp_send_empty(struct pico_socket_tcp *t, uint16_t flags) |
daniele | 29:1a47b7151851 | 1035 | { |
TASS Belgium NV |
131:4758606c9316 | 1036 | struct pico_frame *f; |
TASS Belgium NV |
131:4758606c9316 | 1037 | struct pico_tcp_hdr *hdr; |
TASS Belgium NV |
131:4758606c9316 | 1038 | uint16_t opt_len = tcp_options_size(t, flags); |
TASS Belgium NV |
131:4758606c9316 | 1039 | f = t->sock.net->alloc(t->sock.net, (uint16_t)(PICO_SIZE_TCPHDR + opt_len)); |
TASS Belgium NV |
131:4758606c9316 | 1040 | if (!f) { |
TASS Belgium NV |
131:4758606c9316 | 1041 | return; |
TASS Belgium NV |
131:4758606c9316 | 1042 | } |
TASS Belgium NV |
131:4758606c9316 | 1043 | |
TASS Belgium NV |
131:4758606c9316 | 1044 | f->sock = &t->sock; |
TASS Belgium NV |
131:4758606c9316 | 1045 | hdr = (struct pico_tcp_hdr *) f->transport_hdr; |
TASS Belgium NV |
131:4758606c9316 | 1046 | hdr->len = (uint8_t)((PICO_SIZE_TCPHDR + opt_len) << 2 | t->jumbo); |
TASS Belgium NV |
131:4758606c9316 | 1047 | hdr->flags = (uint8_t)flags; |
TASS Belgium NV |
131:4758606c9316 | 1048 | hdr->rwnd = short_be(t->wnd); |
TASS Belgium NV |
131:4758606c9316 | 1049 | tcp_set_space(t); |
TASS Belgium NV |
131:4758606c9316 | 1050 | tcp_add_options(t, f, flags, opt_len); |
TASS Belgium NV |
131:4758606c9316 | 1051 | hdr->trans.sport = t->sock.local_port; |
TASS Belgium NV |
131:4758606c9316 | 1052 | hdr->trans.dport = t->sock.remote_port; |
TASS Belgium NV |
131:4758606c9316 | 1053 | hdr->seq = long_be(t->snd_nxt); |
TASS Belgium NV |
131:4758606c9316 | 1054 | if ((flags & PICO_TCP_ACK) != 0) |
TASS Belgium NV |
131:4758606c9316 | 1055 | hdr->ack = long_be(t->rcv_nxt); |
TASS Belgium NV |
131:4758606c9316 | 1056 | |
TASS Belgium NV |
131:4758606c9316 | 1057 | t->rcv_ackd = t->rcv_nxt; |
TASS Belgium NV |
131:4758606c9316 | 1058 | |
TASS Belgium NV |
131:4758606c9316 | 1059 | f->start = f->transport_hdr + PICO_SIZE_TCPHDR; |
TASS Belgium NV |
131:4758606c9316 | 1060 | hdr->rwnd = short_be(t->wnd); |
TASS Belgium NV |
131:4758606c9316 | 1061 | hdr->crc = 0; |
TASS Belgium NV |
131:4758606c9316 | 1062 | hdr->crc = short_be(pico_tcp_checksum_ipv4(f)); |
TASS Belgium NV |
131:4758606c9316 | 1063 | |
TASS Belgium NV |
131:4758606c9316 | 1064 | /* TCP: ENQUEUE to PROTO */ |
TASS Belgium NV |
131:4758606c9316 | 1065 | pico_enqueue(&tcp_out, f); |
daniele | 29:1a47b7151851 | 1066 | } |
daniele | 29:1a47b7151851 | 1067 | |
daniele | 29:1a47b7151851 | 1068 | static void tcp_send_ack(struct pico_socket_tcp *t) |
daniele | 29:1a47b7151851 | 1069 | { |
TASS Belgium NV |
131:4758606c9316 | 1070 | return tcp_send_empty(t, PICO_TCP_ACK); |
daniele | 29:1a47b7151851 | 1071 | } |
daniele | 29:1a47b7151851 | 1072 | |
daniele | 29:1a47b7151851 | 1073 | static int tcp_send_rst(struct pico_socket *s, struct pico_frame *fr) |
daniele | 29:1a47b7151851 | 1074 | { |
TASS Belgium NV |
131:4758606c9316 | 1075 | struct pico_socket_tcp *t = (struct pico_socket_tcp *) s; |
TASS Belgium NV |
131:4758606c9316 | 1076 | struct pico_frame *f; |
TASS Belgium NV |
131:4758606c9316 | 1077 | struct pico_tcp_hdr *hdr, *hdr_rcv; |
TASS Belgium NV |
131:4758606c9316 | 1078 | uint16_t opt_len = tcp_options_size(t, PICO_TCP_RST); |
TASS Belgium NV |
131:4758606c9316 | 1079 | int close; |
TASS Belgium NV |
131:4758606c9316 | 1080 | |
TASS Belgium NV |
131:4758606c9316 | 1081 | tcp_dbg("TCP SEND_RST >>>>>>>>>>>>>>> START\n"); |
TASS Belgium NV |
131:4758606c9316 | 1082 | |
TASS Belgium NV |
131:4758606c9316 | 1083 | f = t->sock.net->alloc(t->sock.net, (uint16_t)(PICO_SIZE_TCPHDR + opt_len)); |
TASS Belgium NV |
131:4758606c9316 | 1084 | |
TASS Belgium NV |
131:4758606c9316 | 1085 | if (!f) { |
TASS Belgium NV |
131:4758606c9316 | 1086 | return -1; |
TASS Belgium NV |
131:4758606c9316 | 1087 | } |
TASS Belgium NV |
131:4758606c9316 | 1088 | |
TASS Belgium NV |
131:4758606c9316 | 1089 | hdr_rcv = (struct pico_tcp_hdr *) fr->transport_hdr; |
TASS Belgium NV |
131:4758606c9316 | 1090 | |
TASS Belgium NV |
131:4758606c9316 | 1091 | f->sock = &t->sock; |
TASS Belgium NV |
131:4758606c9316 | 1092 | hdr = (struct pico_tcp_hdr *) f->transport_hdr; |
TASS Belgium NV |
131:4758606c9316 | 1093 | hdr->len = (uint8_t)((PICO_SIZE_TCPHDR + opt_len) << 2 | t->jumbo); |
TASS Belgium NV |
131:4758606c9316 | 1094 | hdr->flags = PICO_TCP_RST; |
TASS Belgium NV |
131:4758606c9316 | 1095 | hdr->rwnd = short_be(t->wnd); |
TASS Belgium NV |
131:4758606c9316 | 1096 | tcp_set_space(t); |
TASS Belgium NV |
131:4758606c9316 | 1097 | tcp_add_options(t, f, PICO_TCP_RST, opt_len); |
TASS Belgium NV |
131:4758606c9316 | 1098 | hdr->trans.sport = t->sock.local_port; |
TASS Belgium NV |
131:4758606c9316 | 1099 | hdr->trans.dport = t->sock.remote_port; |
TASS Belgium NV |
131:4758606c9316 | 1100 | hdr->seq = long_be(t->snd_nxt); |
TASS Belgium NV |
131:4758606c9316 | 1101 | |
TASS Belgium NV |
131:4758606c9316 | 1102 | /* check if state is synchronized */ |
TASS Belgium NV |
131:4758606c9316 | 1103 | if (((s->state & PICO_SOCKET_STATE_TCP) > PICO_SOCKET_STATE_TCP_SYN_RECV)) { |
TASS Belgium NV |
131:4758606c9316 | 1104 | /* in synchronized state: send RST with seq = ack from previous segment */ |
TASS Belgium NV |
131:4758606c9316 | 1105 | hdr->seq = hdr_rcv->ack; |
TASS Belgium NV |
131:4758606c9316 | 1106 | close = 0; |
TASS Belgium NV |
131:4758606c9316 | 1107 | } else { |
TASS Belgium NV |
131:4758606c9316 | 1108 | /* non-synchronized state */ |
TASS Belgium NV |
131:4758606c9316 | 1109 | /* go to CLOSED here to prevent timer callback to go on after timeout */ |
TASS Belgium NV |
131:4758606c9316 | 1110 | (t->sock).state &= 0x00FFU; |
TASS Belgium NV |
131:4758606c9316 | 1111 | (t->sock).state |= PICO_SOCKET_STATE_TCP_CLOSED; |
TASS Belgium NV |
131:4758606c9316 | 1112 | close = 1; |
TASS Belgium NV |
131:4758606c9316 | 1113 | } |
TASS Belgium NV |
131:4758606c9316 | 1114 | |
TASS Belgium NV |
131:4758606c9316 | 1115 | hdr->ack = long_be(t->rcv_nxt); |
TASS Belgium NV |
131:4758606c9316 | 1116 | t->rcv_ackd = t->rcv_nxt; |
TASS Belgium NV |
131:4758606c9316 | 1117 | f->start = f->transport_hdr + PICO_SIZE_TCPHDR; |
TASS Belgium NV |
131:4758606c9316 | 1118 | hdr->rwnd = short_be(t->wnd); |
TASS Belgium NV |
131:4758606c9316 | 1119 | hdr->crc = 0; |
TASS Belgium NV |
131:4758606c9316 | 1120 | hdr->crc = short_be(pico_tcp_checksum_ipv4(f)); |
TASS Belgium NV |
131:4758606c9316 | 1121 | |
TASS Belgium NV |
131:4758606c9316 | 1122 | /* TCP: ENQUEUE to PROTO */ |
TASS Belgium NV |
131:4758606c9316 | 1123 | pico_enqueue(&tcp_out, f); |
TASS Belgium NV |
131:4758606c9316 | 1124 | |
TASS Belgium NV |
131:4758606c9316 | 1125 | /* goto CLOSED */ |
TASS Belgium NV |
131:4758606c9316 | 1126 | if (close) { |
TASS Belgium NV |
131:4758606c9316 | 1127 | (t->sock).state &= 0xFF00U; |
TASS Belgium NV |
131:4758606c9316 | 1128 | (t->sock).state |= PICO_SOCKET_STATE_CLOSED; |
TASS Belgium NV |
131:4758606c9316 | 1129 | |
TASS Belgium NV |
131:4758606c9316 | 1130 | /* call EV_FIN wakeup before deleting */ |
TASS Belgium NV |
131:4758606c9316 | 1131 | if ((t->sock).wakeup) |
TASS Belgium NV |
131:4758606c9316 | 1132 | (t->sock).wakeup(PICO_SOCK_EV_FIN, &(t->sock)); |
TASS Belgium NV |
131:4758606c9316 | 1133 | |
TASS Belgium NV |
131:4758606c9316 | 1134 | /* delete socket */ |
TASS Belgium NV |
131:4758606c9316 | 1135 | pico_socket_del(&t->sock); |
TASS Belgium NV |
131:4758606c9316 | 1136 | |
TASS Belgium NV |
131:4758606c9316 | 1137 | tcp_dbg("TCP SEND_RST >>>>>>>>>>>>>>> DONE, deleted socket\n"); |
TASS Belgium NV |
131:4758606c9316 | 1138 | } |
TASS Belgium NV |
131:4758606c9316 | 1139 | |
TASS Belgium NV |
131:4758606c9316 | 1140 | return 0; |
daniele | 29:1a47b7151851 | 1141 | } |
daniele | 29:1a47b7151851 | 1142 | |
daniele | 29:1a47b7151851 | 1143 | int pico_tcp_reply_rst(struct pico_frame *fr) |
daniele | 29:1a47b7151851 | 1144 | { |
TASS Belgium NV |
131:4758606c9316 | 1145 | struct pico_tcp_hdr *hdr, *hdr1; |
TASS Belgium NV |
131:4758606c9316 | 1146 | struct pico_frame *f; |
TASS Belgium NV |
131:4758606c9316 | 1147 | uint16_t size = PICO_SIZE_TCPHDR; |
TASS Belgium NV |
131:4758606c9316 | 1148 | |
TASS Belgium NV |
131:4758606c9316 | 1149 | tcp_dbg("TCP>>>>>>>>>>>>>>>> sending RST ... <<<<<<<<<<<<<<<<<<\n"); |
TASS Belgium NV |
131:4758606c9316 | 1150 | |
TASS Belgium NV |
131:4758606c9316 | 1151 | hdr1 = (struct pico_tcp_hdr *) (fr->transport_hdr); |
TASS Belgium NV |
131:4758606c9316 | 1152 | f = fr->sock->net->alloc(fr->sock->net, size); |
TASS Belgium NV |
131:4758606c9316 | 1153 | |
TASS Belgium NV |
131:4758606c9316 | 1154 | /* fill in IP data from original frame */ |
TASS Belgium NV |
131:4758606c9316 | 1155 | /* TODO if IPv4 */ |
TASS Belgium NV |
131:4758606c9316 | 1156 | ((struct pico_ipv4_hdr *)(f->net_hdr))->dst.addr = ((struct pico_ipv4_hdr *)(fr->net_hdr))->src.addr; |
TASS Belgium NV |
131:4758606c9316 | 1157 | ((struct pico_ipv4_hdr *)(f->net_hdr))->src.addr = ((struct pico_ipv4_hdr *)(fr->net_hdr))->dst.addr; |
TASS Belgium NV |
131:4758606c9316 | 1158 | |
TASS Belgium NV |
131:4758606c9316 | 1159 | /* fill in TCP data from original frame */ |
TASS Belgium NV |
131:4758606c9316 | 1160 | ((struct pico_tcp_hdr *)(f->transport_hdr))->trans.dport = ((struct pico_tcp_hdr *)(fr->transport_hdr))->trans.sport; |
TASS Belgium NV |
131:4758606c9316 | 1161 | ((struct pico_tcp_hdr *)(f->transport_hdr))->trans.sport = ((struct pico_tcp_hdr *)(fr->transport_hdr))->trans.dport; |
TASS Belgium NV |
131:4758606c9316 | 1162 | hdr = (struct pico_tcp_hdr *) f->transport_hdr; |
TASS Belgium NV |
131:4758606c9316 | 1163 | hdr->len = (uint8_t)(size << 2); |
TASS Belgium NV |
131:4758606c9316 | 1164 | hdr->flags = PICO_TCP_RST; |
TASS Belgium NV |
131:4758606c9316 | 1165 | if(!(hdr1->flags & PICO_TCP_ACK)) |
TASS Belgium NV |
131:4758606c9316 | 1166 | hdr->flags |= PICO_TCP_ACK; |
TASS Belgium NV |
131:4758606c9316 | 1167 | |
TASS Belgium NV |
131:4758606c9316 | 1168 | hdr->rwnd = 0; |
TASS Belgium NV |
131:4758606c9316 | 1169 | if (((struct pico_tcp_hdr *)(fr->transport_hdr))->flags & PICO_TCP_ACK) { |
TASS Belgium NV |
131:4758606c9316 | 1170 | hdr->seq = ((struct pico_tcp_hdr *)(fr->transport_hdr))->ack; |
TASS Belgium NV |
131:4758606c9316 | 1171 | } else { |
TASS Belgium NV |
131:4758606c9316 | 1172 | hdr->seq = 0U; |
TASS Belgium NV |
131:4758606c9316 | 1173 | } |
TASS Belgium NV |
131:4758606c9316 | 1174 | |
TASS Belgium NV |
131:4758606c9316 | 1175 | hdr->ack = 0; |
TASS Belgium NV |
131:4758606c9316 | 1176 | if(!(hdr1->flags & PICO_TCP_ACK)) |
TASS Belgium NV |
131:4758606c9316 | 1177 | hdr->ack = long_be(long_be(((struct pico_tcp_hdr *)(fr->transport_hdr))->seq) + fr->payload_len); |
TASS Belgium NV |
131:4758606c9316 | 1178 | |
TASS Belgium NV |
131:4758606c9316 | 1179 | hdr->crc = short_be(pico_tcp_checksum_ipv4(f)); |
TASS Belgium NV |
131:4758606c9316 | 1180 | /* enqueue for transmission */ |
TASS Belgium NV |
131:4758606c9316 | 1181 | pico_ipv4_frame_push(f, &(((struct pico_ipv4_hdr *)(f->net_hdr))->dst), PICO_PROTO_TCP); |
TASS Belgium NV |
131:4758606c9316 | 1182 | |
TASS Belgium NV |
131:4758606c9316 | 1183 | return 0; |
daniele | 29:1a47b7151851 | 1184 | } |
daniele | 29:1a47b7151851 | 1185 | |
daniele | 29:1a47b7151851 | 1186 | static int tcp_nosync_rst(struct pico_socket *s, struct pico_frame *fr) |
daniele | 29:1a47b7151851 | 1187 | { |
TASS Belgium NV |
131:4758606c9316 | 1188 | struct pico_socket_tcp *t = (struct pico_socket_tcp *) s; |
TASS Belgium NV |
131:4758606c9316 | 1189 | struct pico_frame *f; |
TASS Belgium NV |
131:4758606c9316 | 1190 | struct pico_tcp_hdr *hdr, *hdr_rcv; |
TASS Belgium NV |
131:4758606c9316 | 1191 | uint16_t opt_len = tcp_options_size(t, PICO_TCP_RST | PICO_TCP_ACK); |
TASS Belgium NV |
131:4758606c9316 | 1192 | |
TASS Belgium NV |
131:4758606c9316 | 1193 | tcp_dbg("TCP SEND RST (NON-SYNC) >>>>>>>>>>>>>>>>>> state %x\n", (s->state & PICO_SOCKET_STATE_TCP)); |
TASS Belgium NV |
131:4758606c9316 | 1194 | if (((s->state & PICO_SOCKET_STATE_TCP) == PICO_SOCKET_STATE_TCP_LISTEN)) { |
TASS Belgium NV |
131:4758606c9316 | 1195 | /* XXX TODO NOTE: to prevent the parent socket from trying to send, because this socket has no knowledge of dst IP !!! */ |
TASS Belgium NV |
131:4758606c9316 | 1196 | return pico_tcp_reply_rst(fr); |
TASS Belgium NV |
131:4758606c9316 | 1197 | } |
TASS Belgium NV |
131:4758606c9316 | 1198 | |
TASS Belgium NV |
131:4758606c9316 | 1199 | /***************************************************************************/ |
TASS Belgium NV |
131:4758606c9316 | 1200 | /* sending RST */ |
TASS Belgium NV |
131:4758606c9316 | 1201 | f = t->sock.net->alloc(t->sock.net, (uint16_t)(PICO_SIZE_TCPHDR + opt_len)); |
TASS Belgium NV |
131:4758606c9316 | 1202 | |
TASS Belgium NV |
131:4758606c9316 | 1203 | if (!f) { |
TASS Belgium NV |
131:4758606c9316 | 1204 | return -1; |
TASS Belgium NV |
131:4758606c9316 | 1205 | } |
TASS Belgium NV |
131:4758606c9316 | 1206 | |
TASS Belgium NV |
131:4758606c9316 | 1207 | hdr_rcv = (struct pico_tcp_hdr *) fr->transport_hdr; |
TASS Belgium NV |
131:4758606c9316 | 1208 | |
TASS Belgium NV |
131:4758606c9316 | 1209 | f->sock = &t->sock; |
TASS Belgium NV |
131:4758606c9316 | 1210 | hdr = (struct pico_tcp_hdr *) f->transport_hdr; |
TASS Belgium NV |
131:4758606c9316 | 1211 | hdr->len = (uint8_t)((PICO_SIZE_TCPHDR + opt_len) << 2 | t->jumbo); |
TASS Belgium NV |
131:4758606c9316 | 1212 | hdr->flags = PICO_TCP_RST | PICO_TCP_ACK; |
TASS Belgium NV |
131:4758606c9316 | 1213 | hdr->rwnd = short_be(t->wnd); |
TASS Belgium NV |
131:4758606c9316 | 1214 | tcp_set_space(t); |
TASS Belgium NV |
131:4758606c9316 | 1215 | tcp_add_options(t, f, PICO_TCP_RST | PICO_TCP_ACK, opt_len); |
TASS Belgium NV |
131:4758606c9316 | 1216 | hdr->trans.sport = t->sock.local_port; |
TASS Belgium NV |
131:4758606c9316 | 1217 | hdr->trans.dport = t->sock.remote_port; |
TASS Belgium NV |
131:4758606c9316 | 1218 | |
TASS Belgium NV |
131:4758606c9316 | 1219 | /* non-synchronized state */ |
TASS Belgium NV |
131:4758606c9316 | 1220 | if (hdr_rcv->flags & PICO_TCP_ACK) { |
TASS Belgium NV |
131:4758606c9316 | 1221 | hdr->seq = hdr_rcv->ack; |
TASS Belgium NV |
131:4758606c9316 | 1222 | } else { |
TASS Belgium NV |
131:4758606c9316 | 1223 | hdr->seq = 0U; |
TASS Belgium NV |
131:4758606c9316 | 1224 | } |
TASS Belgium NV |
131:4758606c9316 | 1225 | |
TASS Belgium NV |
131:4758606c9316 | 1226 | hdr->ack = long_be(SEQN(fr) + fr->payload_len); |
TASS Belgium NV |
131:4758606c9316 | 1227 | |
TASS Belgium NV |
131:4758606c9316 | 1228 | t->rcv_ackd = t->rcv_nxt; |
TASS Belgium NV |
131:4758606c9316 | 1229 | f->start = f->transport_hdr + PICO_SIZE_TCPHDR; |
TASS Belgium NV |
131:4758606c9316 | 1230 | hdr->rwnd = short_be(t->wnd); |
TASS Belgium NV |
131:4758606c9316 | 1231 | hdr->crc = 0; |
TASS Belgium NV |
131:4758606c9316 | 1232 | hdr->crc = short_be(pico_tcp_checksum_ipv4(f)); |
TASS Belgium NV |
131:4758606c9316 | 1233 | |
TASS Belgium NV |
131:4758606c9316 | 1234 | /* TCP: ENQUEUE to PROTO */ |
TASS Belgium NV |
131:4758606c9316 | 1235 | pico_enqueue(&tcp_out, f); |
TASS Belgium NV |
131:4758606c9316 | 1236 | |
TASS Belgium NV |
131:4758606c9316 | 1237 | /***************************************************************************/ |
TASS Belgium NV |
131:4758606c9316 | 1238 | |
TASS Belgium NV |
131:4758606c9316 | 1239 | tcp_dbg("TCP SEND_RST (NON_SYNC) >>>>>>>>>>>>>>> DONE, ...\n"); |
TASS Belgium NV |
131:4758606c9316 | 1240 | |
TASS Belgium NV |
131:4758606c9316 | 1241 | return 0; |
daniele | 29:1a47b7151851 | 1242 | } |
daniele | 29:1a47b7151851 | 1243 | |
daniele | 29:1a47b7151851 | 1244 | static void tcp_send_fin(struct pico_socket_tcp *t) |
daniele | 29:1a47b7151851 | 1245 | { |
TASS Belgium NV |
131:4758606c9316 | 1246 | struct pico_frame *f; |
TASS Belgium NV |
131:4758606c9316 | 1247 | struct pico_tcp_hdr *hdr; |
TASS Belgium NV |
131:4758606c9316 | 1248 | uint16_t opt_len = tcp_options_size(t, PICO_TCP_FIN); |
TASS Belgium NV |
131:4758606c9316 | 1249 | f = t->sock.net->alloc(t->sock.net, (uint16_t)(PICO_SIZE_TCPHDR + opt_len)); |
TASS Belgium NV |
131:4758606c9316 | 1250 | if (!f) { |
TASS Belgium NV |
131:4758606c9316 | 1251 | return; |
TASS Belgium NV |
131:4758606c9316 | 1252 | } |
TASS Belgium NV |
131:4758606c9316 | 1253 | |
TASS Belgium NV |
131:4758606c9316 | 1254 | f->sock = &t->sock; |
TASS Belgium NV |
131:4758606c9316 | 1255 | hdr = (struct pico_tcp_hdr *) f->transport_hdr; |
TASS Belgium NV |
131:4758606c9316 | 1256 | hdr->len = (uint8_t)((PICO_SIZE_TCPHDR + opt_len) << 2 | t->jumbo); |
TASS Belgium NV |
131:4758606c9316 | 1257 | hdr->flags = PICO_TCP_FIN | PICO_TCP_ACK; |
TASS Belgium NV |
131:4758606c9316 | 1258 | hdr->ack = long_be(t->rcv_nxt); |
TASS Belgium NV |
131:4758606c9316 | 1259 | t->rcv_ackd = t->rcv_nxt; |
TASS Belgium NV |
131:4758606c9316 | 1260 | hdr->rwnd = short_be(t->wnd); |
TASS Belgium NV |
131:4758606c9316 | 1261 | tcp_set_space(t); |
TASS Belgium NV |
131:4758606c9316 | 1262 | tcp_add_options(t, f, PICO_TCP_FIN, opt_len); |
TASS Belgium NV |
131:4758606c9316 | 1263 | hdr->trans.sport = t->sock.local_port; |
TASS Belgium NV |
131:4758606c9316 | 1264 | hdr->trans.dport = t->sock.remote_port; |
TASS Belgium NV |
131:4758606c9316 | 1265 | hdr->seq = long_be(t->snd_nxt); /* XXX TODO check correct ?? --> snd_last? otherwise maybe data after FIN */ |
TASS Belgium NV |
131:4758606c9316 | 1266 | |
TASS Belgium NV |
131:4758606c9316 | 1267 | f->start = f->transport_hdr + PICO_SIZE_TCPHDR; |
TASS Belgium NV |
131:4758606c9316 | 1268 | hdr->rwnd = short_be(t->wnd); |
TASS Belgium NV |
131:4758606c9316 | 1269 | hdr->crc = 0; |
TASS Belgium NV |
131:4758606c9316 | 1270 | hdr->crc = short_be(pico_tcp_checksum_ipv4(f)); |
TASS Belgium NV |
131:4758606c9316 | 1271 | /* tcp_dbg("SENDING FIN...\n"); */ |
TASS Belgium NV |
131:4758606c9316 | 1272 | /* TCP: ENQUEUE to PROTO ( Pure ACK ) */ |
TASS Belgium NV |
131:4758606c9316 | 1273 | pico_enqueue(&tcp_out, f); |
TASS Belgium NV |
131:4758606c9316 | 1274 | t->snd_nxt++; |
daniele | 29:1a47b7151851 | 1275 | } |
daniele | 29:1a47b7151851 | 1276 | |
daniele | 29:1a47b7151851 | 1277 | static void tcp_sack_prepare(struct pico_socket_tcp *t) |
daniele | 29:1a47b7151851 | 1278 | { |
TASS Belgium NV |
131:4758606c9316 | 1279 | struct tcp_input_segment *pkt; |
TASS Belgium NV |
131:4758606c9316 | 1280 | uint32_t left = 0, right = 0; |
TASS Belgium NV |
131:4758606c9316 | 1281 | struct tcp_sack_block *sb; |
TASS Belgium NV |
131:4758606c9316 | 1282 | int n = 0; |
TASS Belgium NV |
131:4758606c9316 | 1283 | if (t->sacks) /* previous sacks are pending */ |
TASS Belgium NV |
131:4758606c9316 | 1284 | return; |
TASS Belgium NV |
131:4758606c9316 | 1285 | |
TASS Belgium NV |
131:4758606c9316 | 1286 | pkt = first_segment(&t->tcpq_in); |
TASS Belgium NV |
131:4758606c9316 | 1287 | while(n < 3) { |
TASS Belgium NV |
131:4758606c9316 | 1288 | if (!pkt) { |
TASS Belgium NV |
131:4758606c9316 | 1289 | if(left) { |
TASS Belgium NV |
131:4758606c9316 | 1290 | sb = pico_zalloc(sizeof(struct tcp_sack_block)); |
TASS Belgium NV |
131:4758606c9316 | 1291 | if (!sb) |
TASS Belgium NV |
131:4758606c9316 | 1292 | break; |
TASS Belgium NV |
131:4758606c9316 | 1293 | |
TASS Belgium NV |
131:4758606c9316 | 1294 | sb->left = long_be(left); |
TASS Belgium NV |
131:4758606c9316 | 1295 | sb->right = long_be(right); |
TASS Belgium NV |
131:4758606c9316 | 1296 | n++; |
TASS Belgium NV |
131:4758606c9316 | 1297 | sb->next = t->sacks; |
TASS Belgium NV |
131:4758606c9316 | 1298 | t->sacks = sb; |
TASS Belgium NV |
131:4758606c9316 | 1299 | left = 0; |
TASS Belgium NV |
131:4758606c9316 | 1300 | right = 0; |
TASS Belgium NV |
131:4758606c9316 | 1301 | } |
TASS Belgium NV |
131:4758606c9316 | 1302 | |
TASS Belgium NV |
131:4758606c9316 | 1303 | break; |
TASS Belgium NV |
131:4758606c9316 | 1304 | } |
TASS Belgium NV |
131:4758606c9316 | 1305 | |
TASS Belgium NV |
131:4758606c9316 | 1306 | if (pkt->seq < t->rcv_nxt) { |
TASS Belgium NV |
131:4758606c9316 | 1307 | pkt = next_segment(&t->tcpq_in, pkt); |
TASS Belgium NV |
131:4758606c9316 | 1308 | continue; |
TASS Belgium NV |
131:4758606c9316 | 1309 | } |
TASS Belgium NV |
131:4758606c9316 | 1310 | |
TASS Belgium NV |
131:4758606c9316 | 1311 | if (!left) { |
TASS Belgium NV |
131:4758606c9316 | 1312 | left = pkt->seq; |
TASS Belgium NV |
131:4758606c9316 | 1313 | right = pkt->seq + pkt->payload_len; |
TASS Belgium NV |
131:4758606c9316 | 1314 | pkt = next_segment(&t->tcpq_in, pkt); |
TASS Belgium NV |
131:4758606c9316 | 1315 | continue; |
TASS Belgium NV |
131:4758606c9316 | 1316 | } |
TASS Belgium NV |
131:4758606c9316 | 1317 | |
TASS Belgium NV |
131:4758606c9316 | 1318 | if(pkt->seq == right) { |
TASS Belgium NV |
131:4758606c9316 | 1319 | right += pkt->payload_len; |
TASS Belgium NV |
131:4758606c9316 | 1320 | pkt = next_segment(&t->tcpq_in, pkt); |
TASS Belgium NV |
131:4758606c9316 | 1321 | continue; |
TASS Belgium NV |
131:4758606c9316 | 1322 | } else { |
TASS Belgium NV |
131:4758606c9316 | 1323 | sb = pico_zalloc(sizeof(struct tcp_sack_block)); |
TASS Belgium NV |
131:4758606c9316 | 1324 | if (!sb) |
TASS Belgium NV |
131:4758606c9316 | 1325 | break; |
TASS Belgium NV |
131:4758606c9316 | 1326 | |
TASS Belgium NV |
131:4758606c9316 | 1327 | sb->left = long_be(left); |
TASS Belgium NV |
131:4758606c9316 | 1328 | sb->right = long_be(right); |
TASS Belgium NV |
131:4758606c9316 | 1329 | n++; |
TASS Belgium NV |
131:4758606c9316 | 1330 | sb->next = t->sacks; |
TASS Belgium NV |
131:4758606c9316 | 1331 | t->sacks = sb; |
TASS Belgium NV |
131:4758606c9316 | 1332 | left = 0; |
TASS Belgium NV |
131:4758606c9316 | 1333 | right = 0; |
TASS Belgium NV |
131:4758606c9316 | 1334 | pkt = next_segment(&t->tcpq_in, pkt); |
TASS Belgium NV |
131:4758606c9316 | 1335 | } |
daniele | 29:1a47b7151851 | 1336 | } |
daniele | 29:1a47b7151851 | 1337 | } |
daniele | 29:1a47b7151851 | 1338 | |
daniele | 29:1a47b7151851 | 1339 | static int tcp_data_in(struct pico_socket *s, struct pico_frame *f) |
daniele | 29:1a47b7151851 | 1340 | { |
TASS Belgium NV |
131:4758606c9316 | 1341 | struct pico_socket_tcp *t = (struct pico_socket_tcp *)s; |
TASS Belgium NV |
131:4758606c9316 | 1342 | struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *) f->transport_hdr; |
TASS Belgium NV |
131:4758606c9316 | 1343 | |
TASS Belgium NV |
131:4758606c9316 | 1344 | if (((hdr->len & 0xf0) >> 2) <= f->transport_len) { |
TASS Belgium NV |
131:4758606c9316 | 1345 | tcp_parse_options(f); |
TASS Belgium NV |
131:4758606c9316 | 1346 | f->payload = f->transport_hdr + ((hdr->len & 0xf0) >> 2); |
TASS Belgium NV |
131:4758606c9316 | 1347 | f->payload_len = (uint16_t)(f->transport_len - ((hdr->len & 0xf0) >> 2)); |
TASS Belgium NV |
131:4758606c9316 | 1348 | tcp_dbg("TCP> Received segment. (exp: %x got: %x)\n", t->rcv_nxt, SEQN(f)); |
TASS Belgium NV |
131:4758606c9316 | 1349 | |
TASS Belgium NV |
131:4758606c9316 | 1350 | if (seq_compare(SEQN(f), t->rcv_nxt) <= 0) { |
TASS Belgium NV |
131:4758606c9316 | 1351 | struct tcp_input_segment *nxt; |
TASS Belgium NV |
131:4758606c9316 | 1352 | if (seq_compare(SEQN(f), t->rcv_nxt) == 0) { /* Exactly what we expected */ |
TASS Belgium NV |
131:4758606c9316 | 1353 | /* Create new segment and enqueue it */ |
TASS Belgium NV |
131:4758606c9316 | 1354 | struct tcp_input_segment *input = segment_from_frame(f); |
TASS Belgium NV |
131:4758606c9316 | 1355 | if(input && pico_enqueue_segment(&t->tcpq_in, input) <= 0) |
TASS Belgium NV |
131:4758606c9316 | 1356 | { |
TASS Belgium NV |
131:4758606c9316 | 1357 | /* failed to enqueue, destroy segment */ |
TASS Belgium NV |
131:4758606c9316 | 1358 | pico_free(input->payload); |
TASS Belgium NV |
131:4758606c9316 | 1359 | pico_free(input); |
TASS Belgium NV |
131:4758606c9316 | 1360 | } |
TASS Belgium NV |
131:4758606c9316 | 1361 | |
TASS Belgium NV |
131:4758606c9316 | 1362 | t->rcv_nxt = SEQN(f) + f->payload_len; |
TASS Belgium NV |
131:4758606c9316 | 1363 | nxt = peek_segment(&t->tcpq_in, t->rcv_nxt); |
TASS Belgium NV |
131:4758606c9316 | 1364 | while(nxt) { |
TASS Belgium NV |
131:4758606c9316 | 1365 | tcp_dbg("scrolling rcv_nxt...%08x\n", t->rcv_nxt); |
TASS Belgium NV |
131:4758606c9316 | 1366 | t->rcv_nxt += nxt->payload_len; |
TASS Belgium NV |
131:4758606c9316 | 1367 | nxt = peek_segment(&t->tcpq_in, t->rcv_nxt); |
TASS Belgium NV |
131:4758606c9316 | 1368 | } |
TASS Belgium NV |
131:4758606c9316 | 1369 | t->sock.ev_pending |= PICO_SOCK_EV_RD; |
TASS Belgium NV |
131:4758606c9316 | 1370 | } else { |
TASS Belgium NV |
131:4758606c9316 | 1371 | tcp_dbg("TCP> lo segment. Uninteresting retransmission. (exp: %x got: %x)\n", t->rcv_nxt, SEQN(f)); |
TASS Belgium NV |
131:4758606c9316 | 1372 | } |
TASS Belgium NV |
131:4758606c9316 | 1373 | } else { |
TASS Belgium NV |
131:4758606c9316 | 1374 | tcp_dbg("TCP> hi segment. Possible packet loss. I'll dupack this. (exp: %x got: %x)\n", t->rcv_nxt, SEQN(f)); |
TASS Belgium NV |
131:4758606c9316 | 1375 | if (t->sack_ok) { |
TASS Belgium NV |
131:4758606c9316 | 1376 | struct tcp_input_segment *input = segment_from_frame(f); |
TASS Belgium NV |
131:4758606c9316 | 1377 | if(input && pico_enqueue_segment(&t->tcpq_in, input) <= 0) { |
TASS Belgium NV |
131:4758606c9316 | 1378 | /* failed to enqueue, destroy segment */ |
TASS Belgium NV |
131:4758606c9316 | 1379 | pico_free(input->payload); |
TASS Belgium NV |
131:4758606c9316 | 1380 | pico_free(input); |
TASS Belgium NV |
131:4758606c9316 | 1381 | } |
TASS Belgium NV |
131:4758606c9316 | 1382 | |
TASS Belgium NV |
131:4758606c9316 | 1383 | tcp_sack_prepare(t); |
TASS Belgium NV |
131:4758606c9316 | 1384 | } |
daniele | 29:1a47b7151851 | 1385 | } |
TASS Belgium NV |
131:4758606c9316 | 1386 | |
TASS Belgium NV |
131:4758606c9316 | 1387 | /* In either case, ack til recv_nxt. */ |
TASS Belgium NV |
131:4758606c9316 | 1388 | if (((t->sock.state & PICO_SOCKET_STATE_TCP) != PICO_SOCKET_STATE_TCP_CLOSE_WAIT) && ((t->sock.state & PICO_SOCKET_STATE_TCP) != PICO_SOCKET_STATE_TCP_SYN_SENT) && ((t->sock.state & PICO_SOCKET_STATE_TCP) != PICO_SOCKET_STATE_TCP_SYN_RECV)) { |
TASS Belgium NV |
131:4758606c9316 | 1389 | /* tcp_dbg("SENDACK CALLED FROM OUTSIDE tcp_synack, state %x\n",t->sock.state); */ |
TASS Belgium NV |
131:4758606c9316 | 1390 | tcp_send_ack(t); |
TASS Belgium NV |
131:4758606c9316 | 1391 | } else { |
TASS Belgium NV |
131:4758606c9316 | 1392 | /* tcp_dbg("SENDACK PREVENTED IN SYNSENT STATE\n"); */ |
TASS Belgium NV |
131:4758606c9316 | 1393 | } |
TASS Belgium NV |
131:4758606c9316 | 1394 | |
TASS Belgium NV |
131:4758606c9316 | 1395 | return 0; |
daniele | 29:1a47b7151851 | 1396 | } else { |
TASS Belgium NV |
131:4758606c9316 | 1397 | tcp_dbg("TCP: invalid data in pkt len, exp: %d, got %d\n", (hdr->len & 0xf0) >> 2, f->transport_len); |
TASS Belgium NV |
131:4758606c9316 | 1398 | return -1; |
daniele | 29:1a47b7151851 | 1399 | } |
daniele | 29:1a47b7151851 | 1400 | } |
daniele | 29:1a47b7151851 | 1401 | |
TASS Belgium NV |
131:4758606c9316 | 1402 | static int tcp_ack_advance_una(struct pico_socket_tcp *t, struct pico_frame *f, pico_time *timestamp) |
daniele | 29:1a47b7151851 | 1403 | { |
TASS Belgium NV |
131:4758606c9316 | 1404 | int ret = release_all_until(&t->tcpq_out, ACKN(f), timestamp); |
TASS Belgium NV |
131:4758606c9316 | 1405 | if (ret > 0) |
TASS Belgium NV |
131:4758606c9316 | 1406 | t->sock.ev_pending |= PICO_SOCK_EV_WR; |
TASS Belgium NV |
131:4758606c9316 | 1407 | |
TASS Belgium NV |
131:4758606c9316 | 1408 | return ret; |
daniele | 29:1a47b7151851 | 1409 | } |
daniele | 29:1a47b7151851 | 1410 | |
tass | 128:ae39e6e81531 | 1411 | static uint16_t time_diff(pico_time a, pico_time b) |
daniele | 29:1a47b7151851 | 1412 | { |
TASS Belgium NV |
131:4758606c9316 | 1413 | if (a >= b) |
TASS Belgium NV |
131:4758606c9316 | 1414 | return (uint16_t)(a - b); |
TASS Belgium NV |
131:4758606c9316 | 1415 | else |
TASS Belgium NV |
131:4758606c9316 | 1416 | return (uint16_t)(b - a); |
daniele | 29:1a47b7151851 | 1417 | } |
daniele | 29:1a47b7151851 | 1418 | |
daniele | 29:1a47b7151851 | 1419 | static void tcp_rtt(struct pico_socket_tcp *t, uint32_t rtt) |
daniele | 29:1a47b7151851 | 1420 | { |
daniele | 29:1a47b7151851 | 1421 | |
TASS Belgium NV |
131:4758606c9316 | 1422 | uint32_t avg = t->avg_rtt; |
TASS Belgium NV |
131:4758606c9316 | 1423 | uint32_t rvar = t->rttvar; |
TASS Belgium NV |
131:4758606c9316 | 1424 | if (!avg) { |
TASS Belgium NV |
131:4758606c9316 | 1425 | /* This follows RFC2988 |
TASS Belgium NV |
131:4758606c9316 | 1426 | * (2.2) When the first RTT measurement R is made, the host MUST set |
TASS Belgium NV |
131:4758606c9316 | 1427 | * |
TASS Belgium NV |
131:4758606c9316 | 1428 | * SRTT <- R |
TASS Belgium NV |
131:4758606c9316 | 1429 | * RTTVAR <- R/2 |
TASS Belgium NV |
131:4758606c9316 | 1430 | * RTO <- SRTT + max (G, K*RTTVAR) |
TASS Belgium NV |
131:4758606c9316 | 1431 | */ |
TASS Belgium NV |
131:4758606c9316 | 1432 | t->avg_rtt = rtt; |
TASS Belgium NV |
131:4758606c9316 | 1433 | t->rttvar = rtt >> 1; |
TASS Belgium NV |
131:4758606c9316 | 1434 | t->rto = t->avg_rtt + (t->rttvar << 4); |
TASS Belgium NV |
131:4758606c9316 | 1435 | } else { |
TASS Belgium NV |
131:4758606c9316 | 1436 | int32_t var = (int32_t)(t->avg_rtt - rtt); |
TASS Belgium NV |
131:4758606c9316 | 1437 | if (var < 0) |
TASS Belgium NV |
131:4758606c9316 | 1438 | var = 0 - var; |
TASS Belgium NV |
131:4758606c9316 | 1439 | |
TASS Belgium NV |
131:4758606c9316 | 1440 | /* RFC2988, section (2.3). Alpha and beta are the ones suggested. */ |
TASS Belgium NV |
131:4758606c9316 | 1441 | |
TASS Belgium NV |
131:4758606c9316 | 1442 | /* First, evaluate a new value for the rttvar */ |
TASS Belgium NV |
131:4758606c9316 | 1443 | t->rttvar <<= 2; |
TASS Belgium NV |
131:4758606c9316 | 1444 | t->rttvar -= rvar; |
TASS Belgium NV |
131:4758606c9316 | 1445 | t->rttvar += (uint32_t)var; |
TASS Belgium NV |
131:4758606c9316 | 1446 | t->rttvar >>= 2; |
TASS Belgium NV |
131:4758606c9316 | 1447 | |
TASS Belgium NV |
131:4758606c9316 | 1448 | /* Then, calculate the new avg_rtt */ |
TASS Belgium NV |
131:4758606c9316 | 1449 | t->avg_rtt <<= 3; |
TASS Belgium NV |
131:4758606c9316 | 1450 | t->avg_rtt -= avg; |
TASS Belgium NV |
131:4758606c9316 | 1451 | t->avg_rtt += rtt; |
TASS Belgium NV |
131:4758606c9316 | 1452 | t->avg_rtt >>= 3; |
TASS Belgium NV |
131:4758606c9316 | 1453 | |
TASS Belgium NV |
131:4758606c9316 | 1454 | /* Finally, assign a new value for the RTO, as specified in the RFC, with K=4 */ |
TASS Belgium NV |
131:4758606c9316 | 1455 | t->rto = t->avg_rtt + (t->rttvar << 2); |
TASS Belgium NV |
131:4758606c9316 | 1456 | } |
TASS Belgium NV |
131:4758606c9316 | 1457 | |
TASS Belgium NV |
131:4758606c9316 | 1458 | tcp_dbg(" -----=============== RTT CUR: %u AVG: %u RTTVAR: %u RTO: %u ======================----\n", rtt, t->avg_rtt, t->rttvar, t->rto); |
daniele | 29:1a47b7151851 | 1459 | } |
daniele | 29:1a47b7151851 | 1460 | |
daniele | 29:1a47b7151851 | 1461 | static void tcp_congestion_control(struct pico_socket_tcp *t) |
daniele | 29:1a47b7151851 | 1462 | { |
TASS Belgium NV |
131:4758606c9316 | 1463 | if (t->x_mode > PICO_TCP_LOOKAHEAD) |
TASS Belgium NV |
131:4758606c9316 | 1464 | return; |
TASS Belgium NV |
131:4758606c9316 | 1465 | |
TASS Belgium NV |
131:4758606c9316 | 1466 | if (t->cwnd > t->tcpq_out.frames) { |
TASS Belgium NV |
131:4758606c9316 | 1467 | tcp_dbg("Limited by app: %d\n", t->cwnd); |
TASS Belgium NV |
131:4758606c9316 | 1468 | if (t->sock.wakeup) |
TASS Belgium NV |
131:4758606c9316 | 1469 | t->sock.wakeup(PICO_SOCK_EV_WR, &t->sock); |
TASS Belgium NV |
131:4758606c9316 | 1470 | |
TASS Belgium NV |
131:4758606c9316 | 1471 | return; |
daniele | 29:1a47b7151851 | 1472 | } |
TASS Belgium NV |
131:4758606c9316 | 1473 | |
TASS Belgium NV |
131:4758606c9316 | 1474 | tcp_dbg("Doing congestion control\n"); |
TASS Belgium NV |
131:4758606c9316 | 1475 | if (t->cwnd < t->ssthresh) { |
TASS Belgium NV |
131:4758606c9316 | 1476 | t->cwnd++; |
TASS Belgium NV |
131:4758606c9316 | 1477 | } else { |
TASS Belgium NV |
131:4758606c9316 | 1478 | t->cwnd_counter++; |
TASS Belgium NV |
131:4758606c9316 | 1479 | if (t->cwnd_counter >= t->cwnd) { |
TASS Belgium NV |
131:4758606c9316 | 1480 | t->cwnd++; |
TASS Belgium NV |
131:4758606c9316 | 1481 | t->cwnd_counter = 0; |
TASS Belgium NV |
131:4758606c9316 | 1482 | } |
TASS Belgium NV |
131:4758606c9316 | 1483 | } |
TASS Belgium NV |
131:4758606c9316 | 1484 | |
TASS Belgium NV |
131:4758606c9316 | 1485 | tcp_dbg("TCP_CWND, %lu, %u, %u, %u\n", pico_tick, t->cwnd, t->ssthresh, t->in_flight); |
daniele | 29:1a47b7151851 | 1486 | } |
daniele | 29:1a47b7151851 | 1487 | |
tass | 128:ae39e6e81531 | 1488 | static void add_retransmission_timer(struct pico_socket_tcp *t, pico_time next_ts); |
tass | 128:ae39e6e81531 | 1489 | static void tcp_retrans_timeout(pico_time val, void *sock) |
daniele | 29:1a47b7151851 | 1490 | { |
TASS Belgium NV |
131:4758606c9316 | 1491 | struct pico_socket_tcp *t = (struct pico_socket_tcp *) sock; |
TASS Belgium NV |
131:4758606c9316 | 1492 | struct pico_frame *f = NULL; |
TASS Belgium NV |
131:4758606c9316 | 1493 | pico_time limit = val - t->rto; |
TASS Belgium NV |
131:4758606c9316 | 1494 | if( t->sock.net && ((t->sock.state & 0xFF00) == PICO_SOCKET_STATE_TCP_ESTABLISHED |
TASS Belgium NV |
131:4758606c9316 | 1495 | || (t->sock.state & 0xFF00) == PICO_SOCKET_STATE_TCP_CLOSE_WAIT) && t->backoff < PICO_TCP_MAX_RETRANS) |
TASS Belgium NV |
131:4758606c9316 | 1496 | { |
TASS Belgium NV |
131:4758606c9316 | 1497 | tcp_dbg("TIMEOUT! backoff = %d\n", t->backoff); |
TASS Belgium NV |
131:4758606c9316 | 1498 | /* was timer cancelled? */ |
TASS Belgium NV |
131:4758606c9316 | 1499 | if (t->timer_running == 0) { |
TASS Belgium NV |
131:4758606c9316 | 1500 | add_retransmission_timer(t, 0); |
TASS Belgium NV |
131:4758606c9316 | 1501 | return; |
TASS Belgium NV |
131:4758606c9316 | 1502 | } |
TASS Belgium NV |
131:4758606c9316 | 1503 | |
TASS Belgium NV |
131:4758606c9316 | 1504 | t->timer_running--; |
TASS Belgium NV |
131:4758606c9316 | 1505 | |
TASS Belgium NV |
131:4758606c9316 | 1506 | f = first_segment(&t->tcpq_out); |
TASS Belgium NV |
131:4758606c9316 | 1507 | while (f) { |
TASS Belgium NV |
131:4758606c9316 | 1508 | if ((t->x_mode == PICO_TCP_WINDOW_FULL) || |
TASS Belgium NV |
131:4758606c9316 | 1509 | ((f->timestamp != 0) && (f->timestamp <= limit))) { |
TASS Belgium NV |
131:4758606c9316 | 1510 | struct pico_frame *cpy; |
TASS Belgium NV |
131:4758606c9316 | 1511 | tcp_dbg("TCP BLACKOUT> TIMED OUT (output) frame %08x, len= %d rto=%d Win full: %d frame flags: %04x\n", SEQN(f), f->payload_len, t->rto, t->x_mode == PICO_TCP_WINDOW_FULL, f->flags); |
TASS Belgium NV |
131:4758606c9316 | 1512 | if ((t->x_mode != PICO_TCP_WINDOW_FULL)) { |
TASS Belgium NV |
131:4758606c9316 | 1513 | t->x_mode = PICO_TCP_BLACKOUT; |
TASS Belgium NV |
131:4758606c9316 | 1514 | tcp_dbg("Mode: Blackout.\n"); |
TASS Belgium NV |
131:4758606c9316 | 1515 | t->cwnd = PICO_TCP_IW; |
TASS Belgium NV |
131:4758606c9316 | 1516 | t->in_flight = 0; |
TASS Belgium NV |
131:4758606c9316 | 1517 | } |
TASS Belgium NV |
131:4758606c9316 | 1518 | |
TASS Belgium NV |
131:4758606c9316 | 1519 | tcp_add_header(t, f); |
TASS Belgium NV |
131:4758606c9316 | 1520 | /* TCP: ENQUEUE to PROTO ( retransmit )*/ |
TASS Belgium NV |
131:4758606c9316 | 1521 | cpy = pico_frame_copy(f); |
TASS Belgium NV |
131:4758606c9316 | 1522 | if (pico_enqueue(&tcp_out, cpy) > 0) { |
TASS Belgium NV |
131:4758606c9316 | 1523 | t->backoff++; |
TASS Belgium NV |
131:4758606c9316 | 1524 | t->snd_last_out = SEQN(cpy); |
TASS Belgium NV |
131:4758606c9316 | 1525 | add_retransmission_timer(t, (t->rto << t->backoff) + pico_tick); |
TASS Belgium NV |
131:4758606c9316 | 1526 | tcp_dbg("TCP_CWND, %lu, %u, %u, %u\n", pico_tick, t->cwnd, t->ssthresh, t->in_flight); |
TASS Belgium NV |
131:4758606c9316 | 1527 | return; |
TASS Belgium NV |
131:4758606c9316 | 1528 | } else { |
TASS Belgium NV |
131:4758606c9316 | 1529 | add_retransmission_timer(t, (t->rto << t->backoff) + pico_tick); |
TASS Belgium NV |
131:4758606c9316 | 1530 | pico_frame_discard(cpy); |
TASS Belgium NV |
131:4758606c9316 | 1531 | } |
TASS Belgium NV |
131:4758606c9316 | 1532 | } |
TASS Belgium NV |
131:4758606c9316 | 1533 | |
TASS Belgium NV |
131:4758606c9316 | 1534 | f = next_segment(&t->tcpq_out, f); |
TASS Belgium NV |
131:4758606c9316 | 1535 | } |
TASS Belgium NV |
131:4758606c9316 | 1536 | t->backoff = 0; |
TASS Belgium NV |
131:4758606c9316 | 1537 | add_retransmission_timer(t, 0); |
TASS Belgium NV |
131:4758606c9316 | 1538 | if (t->tcpq_out.size < t->tcpq_out.max_size) |
TASS Belgium NV |
131:4758606c9316 | 1539 | t->sock.ev_pending |= PICO_SOCK_EV_WR; |
TASS Belgium NV |
131:4758606c9316 | 1540 | |
TASS Belgium NV |
131:4758606c9316 | 1541 | return; |
TASS Belgium NV |
131:4758606c9316 | 1542 | } |
tass | 97:e73b01cb3147 | 1543 | else if(t->backoff >= PICO_TCP_MAX_RETRANS && (t->sock.state & 0xFF00) == PICO_SOCKET_STATE_TCP_ESTABLISHED ) |
TASS Belgium NV |
131:4758606c9316 | 1544 | { |
TASS Belgium NV |
131:4758606c9316 | 1545 | /* the retransmission timer, failed to get an ack for a frame, giving up on the connection */ |
TASS Belgium NV |
131:4758606c9316 | 1546 | tcp_discard_all_segments(&t->tcpq_out); |
TASS Belgium NV |
131:4758606c9316 | 1547 | if(t->sock.wakeup) |
TASS Belgium NV |
131:4758606c9316 | 1548 | t->sock.wakeup(PICO_SOCK_EV_FIN, &t->sock); |
TASS Belgium NV |
131:4758606c9316 | 1549 | } |
daniele | 29:1a47b7151851 | 1550 | } |
daniele | 29:1a47b7151851 | 1551 | |
tass | 128:ae39e6e81531 | 1552 | static void add_retransmission_timer(struct pico_socket_tcp *t, pico_time next_ts) |
daniele | 29:1a47b7151851 | 1553 | { |
TASS Belgium NV |
131:4758606c9316 | 1554 | struct pico_tree_node *index; |
TASS Belgium NV |
131:4758606c9316 | 1555 | |
TASS Belgium NV |
131:4758606c9316 | 1556 | if (t->timer_running > 0) |
TASS Belgium NV |
131:4758606c9316 | 1557 | return; |
TASS Belgium NV |
131:4758606c9316 | 1558 | |
TASS Belgium NV |
131:4758606c9316 | 1559 | if (next_ts == 0) { |
TASS Belgium NV |
131:4758606c9316 | 1560 | struct pico_frame *f; |
TASS Belgium NV |
131:4758606c9316 | 1561 | |
TASS Belgium NV |
131:4758606c9316 | 1562 | pico_tree_foreach(index, &t->tcpq_out.pool){ |
TASS Belgium NV |
131:4758606c9316 | 1563 | f = index->keyValue; |
TASS Belgium NV |
131:4758606c9316 | 1564 | if (((next_ts == 0) || (f->timestamp < next_ts)) && (f->timestamp > 0)) { |
TASS Belgium NV |
131:4758606c9316 | 1565 | next_ts = f->timestamp; |
TASS Belgium NV |
131:4758606c9316 | 1566 | } |
TASS Belgium NV |
131:4758606c9316 | 1567 | } |
daniele | 29:1a47b7151851 | 1568 | } |
TASS Belgium NV |
131:4758606c9316 | 1569 | |
TASS Belgium NV |
131:4758606c9316 | 1570 | if (next_ts > 0) { |
TASS Belgium NV |
131:4758606c9316 | 1571 | if ((next_ts + t->rto) > pico_tick) { |
TASS Belgium NV |
131:4758606c9316 | 1572 | t->retrans_tmr = pico_timer_add(next_ts + t->rto - pico_tick, tcp_retrans_timeout, t); |
TASS Belgium NV |
131:4758606c9316 | 1573 | } else { |
TASS Belgium NV |
131:4758606c9316 | 1574 | t->retrans_tmr = pico_timer_add(1, tcp_retrans_timeout, t); |
TASS Belgium NV |
131:4758606c9316 | 1575 | } |
TASS Belgium NV |
131:4758606c9316 | 1576 | |
TASS Belgium NV |
131:4758606c9316 | 1577 | t->timer_running++; |
daniele | 29:1a47b7151851 | 1578 | } |
daniele | 29:1a47b7151851 | 1579 | } |
daniele | 29:1a47b7151851 | 1580 | |
daniele | 29:1a47b7151851 | 1581 | static int tcp_retrans(struct pico_socket_tcp *t, struct pico_frame *f) |
daniele | 29:1a47b7151851 | 1582 | { |
TASS Belgium NV |
131:4758606c9316 | 1583 | struct pico_frame *cpy; |
TASS Belgium NV |
131:4758606c9316 | 1584 | if (f) { |
TASS Belgium NV |
131:4758606c9316 | 1585 | tcp_dbg("TCP> RETRANS (by dupack) frame %08x, len= %d\n", SEQN(f), f->payload_len); |
TASS Belgium NV |
131:4758606c9316 | 1586 | tcp_add_header(t, f); |
TASS Belgium NV |
131:4758606c9316 | 1587 | /* TCP: ENQUEUE to PROTO ( retransmit )*/ |
TASS Belgium NV |
131:4758606c9316 | 1588 | cpy = pico_frame_copy(f); |
TASS Belgium NV |
131:4758606c9316 | 1589 | if (pico_enqueue(&tcp_out, cpy) > 0) { |
TASS Belgium NV |
131:4758606c9316 | 1590 | t->in_flight++; |
TASS Belgium NV |
131:4758606c9316 | 1591 | t->snd_last_out = SEQN(cpy); |
TASS Belgium NV |
131:4758606c9316 | 1592 | add_retransmission_timer(t, pico_tick + t->rto); |
TASS Belgium NV |
131:4758606c9316 | 1593 | } else { |
TASS Belgium NV |
131:4758606c9316 | 1594 | pico_frame_discard(cpy); |
TASS Belgium NV |
131:4758606c9316 | 1595 | } |
TASS Belgium NV |
131:4758606c9316 | 1596 | |
TASS Belgium NV |
131:4758606c9316 | 1597 | return(f->payload_len); |
daniele | 29:1a47b7151851 | 1598 | } |
TASS Belgium NV |
131:4758606c9316 | 1599 | |
TASS Belgium NV |
131:4758606c9316 | 1600 | return 0; |
daniele | 29:1a47b7151851 | 1601 | } |
daniele | 29:1a47b7151851 | 1602 | |
daniele | 29:1a47b7151851 | 1603 | #ifdef TCP_ACK_DBG |
daniele | 29:1a47b7151851 | 1604 | static void tcp_ack_dbg(struct pico_socket *s, struct pico_frame *f) |
daniele | 29:1a47b7151851 | 1605 | { |
TASS Belgium NV |
131:4758606c9316 | 1606 | uint32_t una, nxt, ack, cur; |
TASS Belgium NV |
131:4758606c9316 | 1607 | struct pico_frame *una_f = NULL, *cur_f; |
TASS Belgium NV |
131:4758606c9316 | 1608 | struct pico_tree_node *idx; |
TASS Belgium NV |
131:4758606c9316 | 1609 | struct pico_socket_tcp *t = (struct pico_socket_tcp *)s; |
TASS Belgium NV |
131:4758606c9316 | 1610 | char info[64]; |
TASS Belgium NV |
131:4758606c9316 | 1611 | char tmp[64]; |
TASS Belgium NV |
131:4758606c9316 | 1612 | ack = ACKN(f); |
TASS Belgium NV |
131:4758606c9316 | 1613 | nxt = t->snd_nxt; |
TASS Belgium NV |
131:4758606c9316 | 1614 | tcp_dbg("===================================\n"); |
TASS Belgium NV |
131:4758606c9316 | 1615 | tcp_dbg("Queue out (%d/%d). ACKED=%08x\n", t->tcpq_out.size, t->tcpq_out.max_size, ack); |
TASS Belgium NV |
131:4758606c9316 | 1616 | |
TASS Belgium NV |
131:4758606c9316 | 1617 | pico_tree_foreach(idx, &t->tcpq_out.pool) { |
TASS Belgium NV |
131:4758606c9316 | 1618 | info[0] = 0; |
TASS Belgium NV |
131:4758606c9316 | 1619 | cur_f = idx->keyValue; |
TASS Belgium NV |
131:4758606c9316 | 1620 | cur = SEQN(cur_f); |
TASS Belgium NV |
131:4758606c9316 | 1621 | if (!una_f) { |
TASS Belgium NV |
131:4758606c9316 | 1622 | una_f = cur_f; |
TASS Belgium NV |
131:4758606c9316 | 1623 | una = SEQN(una_f); |
TASS Belgium NV |
131:4758606c9316 | 1624 | } |
TASS Belgium NV |
131:4758606c9316 | 1625 | |
TASS Belgium NV |
131:4758606c9316 | 1626 | if (cur == nxt) { |
TASS Belgium NV |
131:4758606c9316 | 1627 | strncpy(tmp, info, strlen(info)); |
TASS Belgium NV |
131:4758606c9316 | 1628 | snprintf(info, 64, "%s SND_NXT", tmp); |
TASS Belgium NV |
131:4758606c9316 | 1629 | } |
TASS Belgium NV |
131:4758606c9316 | 1630 | |
TASS Belgium NV |
131:4758606c9316 | 1631 | if (cur == ack) { |
TASS Belgium NV |
131:4758606c9316 | 1632 | strncpy(tmp, info, strlen(info)); |
TASS Belgium NV |
131:4758606c9316 | 1633 | snprintf(info, 64, "%s ACK", tmp); |
TASS Belgium NV |
131:4758606c9316 | 1634 | } |
TASS Belgium NV |
131:4758606c9316 | 1635 | |
TASS Belgium NV |
131:4758606c9316 | 1636 | if (cur == una) { |
TASS Belgium NV |
131:4758606c9316 | 1637 | strncpy(tmp, info, strlen(info)); |
TASS Belgium NV |
131:4758606c9316 | 1638 | snprintf(info, 64, "%s SND_UNA", tmp); |
TASS Belgium NV |
131:4758606c9316 | 1639 | } |
TASS Belgium NV |
131:4758606c9316 | 1640 | |
TASS Belgium NV |
131:4758606c9316 | 1641 | if (cur == t->snd_last) { |
TASS Belgium NV |
131:4758606c9316 | 1642 | strncpy(tmp, info, strlen(info)); |
TASS Belgium NV |
131:4758606c9316 | 1643 | snprintf(info, 64, "%s SND_LAST", tmp); |
TASS Belgium NV |
131:4758606c9316 | 1644 | } |
TASS Belgium NV |
131:4758606c9316 | 1645 | |
TASS Belgium NV |
131:4758606c9316 | 1646 | tcp_dbg("%08x %d%s\n", cur, cur_f->payload_len, info); |
TASS Belgium NV |
131:4758606c9316 | 1647 | |
daniele | 29:1a47b7151851 | 1648 | } |
TASS Belgium NV |
131:4758606c9316 | 1649 | tcp_dbg("SND_NXT is %08x, snd_LAST is %08x\n", nxt, t->snd_last); |
TASS Belgium NV |
131:4758606c9316 | 1650 | tcp_dbg("===================================\n"); |
TASS Belgium NV |
131:4758606c9316 | 1651 | tcp_dbg("\n\n"); |
daniele | 29:1a47b7151851 | 1652 | } |
daniele | 29:1a47b7151851 | 1653 | #endif |
daniele | 29:1a47b7151851 | 1654 | |
daniele | 29:1a47b7151851 | 1655 | static int tcp_ack(struct pico_socket *s, struct pico_frame *f) |
daniele | 29:1a47b7151851 | 1656 | { |
TASS Belgium NV |
131:4758606c9316 | 1657 | struct pico_frame *f_new; /* use with Nagle to push to out queue */ |
TASS Belgium NV |
131:4758606c9316 | 1658 | struct pico_socket_tcp *t = (struct pico_socket_tcp *)s; |
TASS Belgium NV |
131:4758606c9316 | 1659 | struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *) f->transport_hdr; |
TASS Belgium NV |
131:4758606c9316 | 1660 | uint32_t rtt = 0; |
TASS Belgium NV |
131:4758606c9316 | 1661 | uint16_t acked = 0; |
TASS Belgium NV |
131:4758606c9316 | 1662 | pico_time acked_timestamp = 0; |
TASS Belgium NV |
131:4758606c9316 | 1663 | uint8_t restart_tmr = 0; |
TASS Belgium NV |
131:4758606c9316 | 1664 | |
TASS Belgium NV |
131:4758606c9316 | 1665 | struct pico_frame *una = NULL; |
TASS Belgium NV |
131:4758606c9316 | 1666 | if ((hdr->flags & PICO_TCP_ACK) == 0) |
TASS Belgium NV |
131:4758606c9316 | 1667 | return -1; |
daniele | 29:1a47b7151851 | 1668 | |
daniele | 29:1a47b7151851 | 1669 | #ifdef TCP_ACK_DBG |
TASS Belgium NV |
131:4758606c9316 | 1670 | tcp_ack_dbg(s, f); |
daniele | 29:1a47b7151851 | 1671 | #endif |
daniele | 29:1a47b7151851 | 1672 | |
TASS Belgium NV |
131:4758606c9316 | 1673 | tcp_parse_options(f); |
TASS Belgium NV |
131:4758606c9316 | 1674 | t->recv_wnd = short_be(hdr->rwnd); |
TASS Belgium NV |
131:4758606c9316 | 1675 | |
TASS Belgium NV |
131:4758606c9316 | 1676 | acked = (uint16_t)tcp_ack_advance_una(t, f, &acked_timestamp); |
TASS Belgium NV |
131:4758606c9316 | 1677 | una = first_segment(&t->tcpq_out); |
TASS Belgium NV |
131:4758606c9316 | 1678 | |
TASS Belgium NV |
131:4758606c9316 | 1679 | if ((t->x_mode == PICO_TCP_BLACKOUT) || |
TASS Belgium NV |
131:4758606c9316 | 1680 | ((t->x_mode == PICO_TCP_WINDOW_FULL) && ((t->recv_wnd << t->recv_wnd_scale) > t->mss))) { |
TASS Belgium NV |
131:4758606c9316 | 1681 | int prev_mode = t->x_mode; |
TASS Belgium NV |
131:4758606c9316 | 1682 | tcp_dbg("Re-entering look-ahead...\n\n\n"); |
TASS Belgium NV |
131:4758606c9316 | 1683 | t->x_mode = PICO_TCP_LOOKAHEAD; |
TASS Belgium NV |
131:4758606c9316 | 1684 | t->backoff = 0; |
TASS Belgium NV |
131:4758606c9316 | 1685 | |
TASS Belgium NV |
131:4758606c9316 | 1686 | if((prev_mode == PICO_TCP_BLACKOUT) && (acked > 0) && una) |
TASS Belgium NV |
131:4758606c9316 | 1687 | { |
TASS Belgium NV |
131:4758606c9316 | 1688 | t->snd_nxt = SEQN(una); |
TASS Belgium NV |
131:4758606c9316 | 1689 | /* restart the retrans timer */ |
TASS Belgium NV |
131:4758606c9316 | 1690 | pico_timer_cancel(t->retrans_tmr); |
TASS Belgium NV |
131:4758606c9316 | 1691 | t->timer_running = 0; |
TASS Belgium NV |
131:4758606c9316 | 1692 | restart_tmr = 1u; |
TASS Belgium NV |
131:4758606c9316 | 1693 | } |
daniele | 29:1a47b7151851 | 1694 | } |
daniele | 29:1a47b7151851 | 1695 | |
TASS Belgium NV |
131:4758606c9316 | 1696 | /* One should be acked. */ |
TASS Belgium NV |
131:4758606c9316 | 1697 | if ((acked == 0) && (f->payload_len == 0) && (t->in_flight > 0)) |
TASS Belgium NV |
131:4758606c9316 | 1698 | t->in_flight--; |
TASS Belgium NV |
131:4758606c9316 | 1699 | |
TASS Belgium NV |
131:4758606c9316 | 1700 | if (!una || acked > 0) { |
TASS Belgium NV |
131:4758606c9316 | 1701 | t->x_mode = PICO_TCP_LOOKAHEAD; |
TASS Belgium NV |
131:4758606c9316 | 1702 | tcp_dbg("Mode: Look-ahead. In flight: %d/%d buf: %d\n", t->in_flight, t->cwnd, t->tcpq_out.frames); |
TASS Belgium NV |
131:4758606c9316 | 1703 | t->backoff = 0; |
TASS Belgium NV |
131:4758606c9316 | 1704 | |
TASS Belgium NV |
131:4758606c9316 | 1705 | /* Do rtt/rttvar/rto calculations */ |
TASS Belgium NV |
131:4758606c9316 | 1706 | /* First, try with timestamps, using the value from options */ |
TASS Belgium NV |
131:4758606c9316 | 1707 | if(f && (f->timestamp != 0)) { |
TASS Belgium NV |
131:4758606c9316 | 1708 | rtt = time_diff(pico_tick, f->timestamp); |
TASS Belgium NV |
131:4758606c9316 | 1709 | if (rtt) |
TASS Belgium NV |
131:4758606c9316 | 1710 | tcp_rtt(t, rtt); |
TASS Belgium NV |
131:4758606c9316 | 1711 | } else if(acked_timestamp) { |
TASS Belgium NV |
131:4758606c9316 | 1712 | /* If no timestamps are there, use conservatve estimation on the una */ |
TASS Belgium NV |
131:4758606c9316 | 1713 | rtt = time_diff(pico_tick, acked_timestamp); |
TASS Belgium NV |
131:4758606c9316 | 1714 | if (rtt) |
TASS Belgium NV |
131:4758606c9316 | 1715 | tcp_rtt(t, rtt); |
daniele | 29:1a47b7151851 | 1716 | } |
TASS Belgium NV |
131:4758606c9316 | 1717 | |
TASS Belgium NV |
131:4758606c9316 | 1718 | tcp_dbg("TCP ACK> FRESH ACK %08x (acked %d) Queue size: %u/%u frames: %u cwnd: %u in_flight: %u snd_una: %u\n", ACKN(f), acked, t->tcpq_out.size, t->tcpq_out.max_size, t->tcpq_out.frames, t->cwnd, t->in_flight, SEQN(una)); |
TASS Belgium NV |
131:4758606c9316 | 1719 | if (acked > t->in_flight) { |
TASS Belgium NV |
131:4758606c9316 | 1720 | tcp_dbg("WARNING: in flight < 0\n"); |
TASS Belgium NV |
131:4758606c9316 | 1721 | t->in_flight = 0; |
TASS Belgium NV |
131:4758606c9316 | 1722 | } else |
TASS Belgium NV |
131:4758606c9316 | 1723 | t->in_flight -= (acked); |
TASS Belgium NV |
131:4758606c9316 | 1724 | |
TASS Belgium NV |
131:4758606c9316 | 1725 | } else if ((t->snd_old_ack == ACKN(f)) && /* We've just seen this ack, and... */ |
TASS Belgium NV |
131:4758606c9316 | 1726 | ((0 == (hdr->flags & (PICO_TCP_PSH | PICO_TCP_SYN))) && |
TASS Belgium NV |
131:4758606c9316 | 1727 | (f->payload_len == 0)) && /* This is a pure ack, and... */ |
TASS Belgium NV |
131:4758606c9316 | 1728 | (ACKN(f) != t->snd_nxt)) /* There is something in flight awaiting to be acked... */ |
TASS Belgium NV |
131:4758606c9316 | 1729 | { |
TASS Belgium NV |
131:4758606c9316 | 1730 | /* Process incoming duplicate ack. */ |
TASS Belgium NV |
131:4758606c9316 | 1731 | if (t->x_mode < PICO_TCP_RECOVER) { |
TASS Belgium NV |
131:4758606c9316 | 1732 | t->x_mode++; |
TASS Belgium NV |
131:4758606c9316 | 1733 | tcp_dbg("Mode: DUPACK %d, due to PURE ACK %0x, len = %d\n", t->x_mode, SEQN(f), f->payload_len); |
TASS Belgium NV |
131:4758606c9316 | 1734 | tcp_dbg("ACK: %x - QUEUE: %x\n", ACKN(f), SEQN(first_segment(&t->tcpq_out))); |
TASS Belgium NV |
131:4758606c9316 | 1735 | if (t->x_mode == PICO_TCP_RECOVER) { /* Switching mode */ |
TASS Belgium NV |
131:4758606c9316 | 1736 | t->snd_retry = SEQN((struct pico_frame *)first_segment(&t->tcpq_out)); |
TASS Belgium NV |
131:4758606c9316 | 1737 | if (t->ssthresh > t->cwnd) |
TASS Belgium NV |
131:4758606c9316 | 1738 | t->ssthresh >>= 2; |
TASS Belgium NV |
131:4758606c9316 | 1739 | else |
TASS Belgium NV |
131:4758606c9316 | 1740 | t->ssthresh = (t->cwnd >> 1); |
TASS Belgium NV |
131:4758606c9316 | 1741 | |
TASS Belgium NV |
131:4758606c9316 | 1742 | if (t->ssthresh < 2) |
TASS Belgium NV |
131:4758606c9316 | 1743 | t->ssthresh = 2; |
TASS Belgium NV |
131:4758606c9316 | 1744 | } |
TASS Belgium NV |
131:4758606c9316 | 1745 | } else if (t->x_mode == PICO_TCP_RECOVER) { |
TASS Belgium NV |
131:4758606c9316 | 1746 | tcp_dbg("TCP RECOVER> DUPACK! snd_una: %08x, snd_nxt: %08x, acked now: %08x\n", SEQN(first_segment(&t->tcpq_out)), t->snd_nxt, ACKN(f)); |
TASS Belgium NV |
131:4758606c9316 | 1747 | if (t->in_flight <= t->cwnd) { |
TASS Belgium NV |
131:4758606c9316 | 1748 | struct pico_frame *nxt = peek_segment(&t->tcpq_out, t->snd_retry); |
TASS Belgium NV |
131:4758606c9316 | 1749 | if (!nxt) |
TASS Belgium NV |
131:4758606c9316 | 1750 | nxt = first_segment(&t->tcpq_out); |
TASS Belgium NV |
131:4758606c9316 | 1751 | |
TASS Belgium NV |
131:4758606c9316 | 1752 | while (nxt && (nxt->flags & PICO_FRAME_FLAG_SACKED) && (nxt != first_segment(&t->tcpq_out))) { |
TASS Belgium NV |
131:4758606c9316 | 1753 | tcp_dbg("Skipping %08x because it is sacked.\n", SEQN(nxt)); |
TASS Belgium NV |
131:4758606c9316 | 1754 | nxt = next_segment(&t->tcpq_out, nxt); |
TASS Belgium NV |
131:4758606c9316 | 1755 | } |
TASS Belgium NV |
131:4758606c9316 | 1756 | if (nxt && (seq_compare(SEQN(nxt), t->snd_nxt)) > 0) |
TASS Belgium NV |
131:4758606c9316 | 1757 | nxt = NULL; |
TASS Belgium NV |
131:4758606c9316 | 1758 | |
TASS Belgium NV |
131:4758606c9316 | 1759 | if (nxt && (seq_compare(SEQN(nxt), SEQN((struct pico_frame *)first_segment(&t->tcpq_out))) > (t->recv_wnd << t->recv_wnd_scale))) |
TASS Belgium NV |
131:4758606c9316 | 1760 | nxt = NULL; |
TASS Belgium NV |
131:4758606c9316 | 1761 | |
TASS Belgium NV |
131:4758606c9316 | 1762 | if(!nxt) |
TASS Belgium NV |
131:4758606c9316 | 1763 | nxt = first_segment(&t->tcpq_out); |
TASS Belgium NV |
131:4758606c9316 | 1764 | |
TASS Belgium NV |
131:4758606c9316 | 1765 | if (nxt) { |
TASS Belgium NV |
131:4758606c9316 | 1766 | tcp_retrans(t, peek_segment(&t->tcpq_out, t->snd_retry)); |
TASS Belgium NV |
131:4758606c9316 | 1767 | t->snd_retry = SEQN(nxt); |
TASS Belgium NV |
131:4758606c9316 | 1768 | } |
TASS Belgium NV |
131:4758606c9316 | 1769 | } |
TASS Belgium NV |
131:4758606c9316 | 1770 | |
TASS Belgium NV |
131:4758606c9316 | 1771 | if (++t->cwnd_counter > 1) { |
TASS Belgium NV |
131:4758606c9316 | 1772 | t->cwnd--; |
TASS Belgium NV |
131:4758606c9316 | 1773 | if (t->cwnd < 2) |
TASS Belgium NV |
131:4758606c9316 | 1774 | t->cwnd = 2; |
TASS Belgium NV |
131:4758606c9316 | 1775 | |
TASS Belgium NV |
131:4758606c9316 | 1776 | t->cwnd_counter = 0; |
TASS Belgium NV |
131:4758606c9316 | 1777 | } |
TASS Belgium NV |
131:4758606c9316 | 1778 | } else { |
TASS Belgium NV |
131:4758606c9316 | 1779 | tcp_dbg("DUPACK in mode %d \n", t->x_mode); |
TASS Belgium NV |
131:4758606c9316 | 1780 | |
TASS Belgium NV |
131:4758606c9316 | 1781 | } |
TASS Belgium NV |
131:4758606c9316 | 1782 | } /* End case duplicate ack detection */ |
TASS Belgium NV |
131:4758606c9316 | 1783 | |
TASS Belgium NV |
131:4758606c9316 | 1784 | /* Do congestion control */ |
TASS Belgium NV |
131:4758606c9316 | 1785 | tcp_congestion_control(t); |
TASS Belgium NV |
131:4758606c9316 | 1786 | if ((acked > 0) && t->sock.wakeup) { |
TASS Belgium NV |
131:4758606c9316 | 1787 | if (t->tcpq_out.size < t->tcpq_out.max_size) |
TASS Belgium NV |
131:4758606c9316 | 1788 | t->sock.wakeup(PICO_SOCK_EV_WR, &(t->sock)); |
TASS Belgium NV |
131:4758606c9316 | 1789 | |
TASS Belgium NV |
131:4758606c9316 | 1790 | /* t->sock.ev_pending |= PICO_SOCK_EV_WR; */ |
daniele | 29:1a47b7151851 | 1791 | } |
TASS Belgium NV |
131:4758606c9316 | 1792 | |
TASS Belgium NV |
131:4758606c9316 | 1793 | /* if Nagle enabled, check if no unack'ed data and fill out queue (till window) */ |
TASS Belgium NV |
131:4758606c9316 | 1794 | if (IS_NAGLE_ENABLED((&(t->sock)))) { |
TASS Belgium NV |
131:4758606c9316 | 1795 | while (!IS_TCP_HOLDQ_EMPTY(t) && ((t->tcpq_out.max_size - t->tcpq_out.size) >= PICO_TCP_DEFAULT_MSS)) { |
TASS Belgium NV |
131:4758606c9316 | 1796 | tcp_dbg_nagle("TCP_ACK - NAGLE add new segment\n"); |
TASS Belgium NV |
131:4758606c9316 | 1797 | f_new = pico_hold_segment_make(t); |
TASS Belgium NV |
131:4758606c9316 | 1798 | if (f_new == NULL) |
TASS Belgium NV |
131:4758606c9316 | 1799 | break; /* XXX corrupt !!! (or no memory) */ |
TASS Belgium NV |
131:4758606c9316 | 1800 | |
TASS Belgium NV |
131:4758606c9316 | 1801 | if (pico_enqueue_segment(&t->tcpq_out, f_new) <= 0) |
TASS Belgium NV |
131:4758606c9316 | 1802 | /* handle error */ |
TASS Belgium NV |
131:4758606c9316 | 1803 | tcp_dbg_nagle("TCP_ACK - NAGLE FAILED to enqueue in out\n"); |
TASS Belgium NV |
131:4758606c9316 | 1804 | } |
daniele | 29:1a47b7151851 | 1805 | } |
TASS Belgium NV |
131:4758606c9316 | 1806 | |
TASS Belgium NV |
131:4758606c9316 | 1807 | /* If some space was created, put a few segments out. */ |
TASS Belgium NV |
131:4758606c9316 | 1808 | tcp_dbg("TCP_CWND, %lu, %u, %u, %u\n", pico_tick, t->cwnd, t->ssthresh, t->in_flight); |
TASS Belgium NV |
131:4758606c9316 | 1809 | if (t->x_mode == PICO_TCP_LOOKAHEAD) { |
TASS Belgium NV |
131:4758606c9316 | 1810 | if ((t->cwnd >= t->in_flight) && (t->snd_nxt > t->snd_last_out)) { |
TASS Belgium NV |
131:4758606c9316 | 1811 | pico_tcp_output(&t->sock, (int)t->cwnd - (int)t->in_flight); |
TASS Belgium NV |
131:4758606c9316 | 1812 | } |
daniele | 29:1a47b7151851 | 1813 | } |
TASS Belgium NV |
131:4758606c9316 | 1814 | |
TASS Belgium NV |
131:4758606c9316 | 1815 | if(restart_tmr) |
TASS Belgium NV |
131:4758606c9316 | 1816 | { |
TASS Belgium NV |
131:4758606c9316 | 1817 | add_retransmission_timer(t, pico_tick + t->rto); |
TASS Belgium NV |
131:4758606c9316 | 1818 | } |
TASS Belgium NV |
131:4758606c9316 | 1819 | |
TASS Belgium NV |
131:4758606c9316 | 1820 | t->snd_old_ack = ACKN(f); |
TASS Belgium NV |
131:4758606c9316 | 1821 | return 0; |
daniele | 29:1a47b7151851 | 1822 | } |
daniele | 29:1a47b7151851 | 1823 | |
daniele | 29:1a47b7151851 | 1824 | static int tcp_finwaitack(struct pico_socket *s, struct pico_frame *f) |
daniele | 29:1a47b7151851 | 1825 | { |
TASS Belgium NV |
131:4758606c9316 | 1826 | tcp_dbg("RECEIVED ACK IN FIN_WAIT1\n"); |
TASS Belgium NV |
131:4758606c9316 | 1827 | tcp_dbg("TCP> IN STATE FIN_WAIT2\n"); |
TASS Belgium NV |
131:4758606c9316 | 1828 | |
TASS Belgium NV |
131:4758606c9316 | 1829 | /* acking part */ |
TASS Belgium NV |
131:4758606c9316 | 1830 | tcp_ack(s, f); |
TASS Belgium NV |
131:4758606c9316 | 1831 | /* update TCP state */ |
TASS Belgium NV |
131:4758606c9316 | 1832 | s->state &= 0x00FFU; |
TASS Belgium NV |
131:4758606c9316 | 1833 | s->state |= PICO_SOCKET_STATE_TCP_FIN_WAIT2; |
TASS Belgium NV |
131:4758606c9316 | 1834 | |
TASS Belgium NV |
131:4758606c9316 | 1835 | return 0; |
daniele | 29:1a47b7151851 | 1836 | } |
daniele | 29:1a47b7151851 | 1837 | |
tass | 128:ae39e6e81531 | 1838 | static void tcp_deltcb(pico_time when, void *arg) |
daniele | 29:1a47b7151851 | 1839 | { |
TASS Belgium NV |
131:4758606c9316 | 1840 | struct pico_socket_tcp *t = (struct pico_socket_tcp *)arg; |
TASS Belgium NV |
131:4758606c9316 | 1841 | IGNORE_PARAMETER(when); |
TASS Belgium NV |
131:4758606c9316 | 1842 | |
TASS Belgium NV |
131:4758606c9316 | 1843 | if (TCPSTATE(&t->sock) == PICO_SOCKET_STATE_TCP_TIME_WAIT) { |
TASS Belgium NV |
131:4758606c9316 | 1844 | tcp_dbg("TCP> state: time_wait, final timer expired, going to closed state\n"); |
TASS Belgium NV |
131:4758606c9316 | 1845 | /* update state */ |
TASS Belgium NV |
131:4758606c9316 | 1846 | (t->sock).state &= 0x00FFU; |
TASS Belgium NV |
131:4758606c9316 | 1847 | (t->sock).state |= PICO_SOCKET_STATE_TCP_CLOSED; |
TASS Belgium NV |
131:4758606c9316 | 1848 | (t->sock).state &= 0xFF00U; |
TASS Belgium NV |
131:4758606c9316 | 1849 | (t->sock).state |= PICO_SOCKET_STATE_CLOSED; |
TASS Belgium NV |
131:4758606c9316 | 1850 | /* call EV_FIN wakeup before deleting */ |
TASS Belgium NV |
131:4758606c9316 | 1851 | if (t->sock.wakeup) { |
TASS Belgium NV |
131:4758606c9316 | 1852 | (t->sock).wakeup(PICO_SOCK_EV_FIN, &(t->sock)); |
TASS Belgium NV |
131:4758606c9316 | 1853 | } |
TASS Belgium NV |
131:4758606c9316 | 1854 | |
TASS Belgium NV |
131:4758606c9316 | 1855 | /* delete socket */ |
TASS Belgium NV |
131:4758606c9316 | 1856 | pico_socket_del(&t->sock); |
TASS Belgium NV |
131:4758606c9316 | 1857 | } else { |
TASS Belgium NV |
131:4758606c9316 | 1858 | tcp_dbg("TCP> trying to go to closed, wrong state\n"); |
TASS Belgium NV |
131:4758606c9316 | 1859 | } |
TASS Belgium NV |
131:4758606c9316 | 1860 | } |
TASS Belgium NV |
131:4758606c9316 | 1861 | |
TASS Belgium NV |
131:4758606c9316 | 1862 | static int tcp_finwaitfin(struct pico_socket *s, struct pico_frame *f) |
TASS Belgium NV |
131:4758606c9316 | 1863 | { |
TASS Belgium NV |
131:4758606c9316 | 1864 | struct pico_socket_tcp *t = (struct pico_socket_tcp *)s; |
TASS Belgium NV |
131:4758606c9316 | 1865 | struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *) (f->transport_hdr); |
TASS Belgium NV |
131:4758606c9316 | 1866 | tcp_dbg("TCP> received fin in FIN_WAIT2\n"); |
TASS Belgium NV |
131:4758606c9316 | 1867 | /* received FIN, increase ACK nr */ |
TASS Belgium NV |
131:4758606c9316 | 1868 | t->rcv_nxt = long_be(hdr->seq) + 1; |
TASS Belgium NV |
131:4758606c9316 | 1869 | s->state &= 0x00FFU; |
TASS Belgium NV |
131:4758606c9316 | 1870 | s->state |= PICO_SOCKET_STATE_TCP_TIME_WAIT; |
TASS Belgium NV |
131:4758606c9316 | 1871 | /* set SHUT_REMOTE */ |
TASS Belgium NV |
131:4758606c9316 | 1872 | s->state |= PICO_SOCKET_STATE_SHUT_REMOTE; |
TASS Belgium NV |
131:4758606c9316 | 1873 | if (s->wakeup) |
TASS Belgium NV |
131:4758606c9316 | 1874 | s->wakeup(PICO_SOCK_EV_CLOSE, s); |
TASS Belgium NV |
131:4758606c9316 | 1875 | |
TASS Belgium NV |
131:4758606c9316 | 1876 | if (f->payload_len > 0) /* needed?? */ |
TASS Belgium NV |
131:4758606c9316 | 1877 | tcp_data_in(s, f); |
TASS Belgium NV |
131:4758606c9316 | 1878 | |
TASS Belgium NV |
131:4758606c9316 | 1879 | /* send ACK */ |
TASS Belgium NV |
131:4758606c9316 | 1880 | tcp_send_ack(t); |
TASS Belgium NV |
131:4758606c9316 | 1881 | /* set timer */ |
TASS Belgium NV |
131:4758606c9316 | 1882 | pico_timer_add(200, tcp_deltcb, t); |
TASS Belgium NV |
131:4758606c9316 | 1883 | return 0; |
TASS Belgium NV |
131:4758606c9316 | 1884 | } |
TASS Belgium NV |
131:4758606c9316 | 1885 | |
TASS Belgium NV |
131:4758606c9316 | 1886 | static int tcp_closewaitack(struct pico_socket *s, struct pico_frame *f) |
TASS Belgium NV |
131:4758606c9316 | 1887 | { |
TASS Belgium NV |
131:4758606c9316 | 1888 | struct pico_socket_tcp *t = (struct pico_socket_tcp *)s; |
TASS Belgium NV |
131:4758606c9316 | 1889 | tcp_dbg("TCP> received ack in CLOSING\n"); |
TASS Belgium NV |
131:4758606c9316 | 1890 | /* acking part */ |
TASS Belgium NV |
131:4758606c9316 | 1891 | tcp_ack(s, f); |
TASS Belgium NV |
131:4758606c9316 | 1892 | /* update TCP state */ |
TASS Belgium NV |
131:4758606c9316 | 1893 | s->state &= 0x00FFU; |
TASS Belgium NV |
131:4758606c9316 | 1894 | s->state |= PICO_SOCKET_STATE_TCP_TIME_WAIT; |
TASS Belgium NV |
131:4758606c9316 | 1895 | /* set timer */ |
TASS Belgium NV |
131:4758606c9316 | 1896 | pico_timer_add(200, tcp_deltcb, t); |
TASS Belgium NV |
131:4758606c9316 | 1897 | return 0; |
TASS Belgium NV |
131:4758606c9316 | 1898 | } |
TASS Belgium NV |
131:4758606c9316 | 1899 | |
TASS Belgium NV |
131:4758606c9316 | 1900 | static int tcp_lastackwait(struct pico_socket *s, struct pico_frame *f) |
TASS Belgium NV |
131:4758606c9316 | 1901 | { |
TASS Belgium NV |
131:4758606c9316 | 1902 | IGNORE_PARAMETER(f); |
TASS Belgium NV |
131:4758606c9316 | 1903 | tcp_dbg("TCP> state: last_ack, received ack, to closed\n"); |
TASS Belgium NV |
131:4758606c9316 | 1904 | s->state &= 0x00FFU; |
TASS Belgium NV |
131:4758606c9316 | 1905 | s->state |= PICO_SOCKET_STATE_TCP_CLOSED; |
TASS Belgium NV |
131:4758606c9316 | 1906 | s->state &= 0xFF00U; |
TASS Belgium NV |
131:4758606c9316 | 1907 | s->state |= PICO_SOCKET_STATE_CLOSED; |
TASS Belgium NV |
131:4758606c9316 | 1908 | /* call socket wakeup with EV_FIN */ |
TASS Belgium NV |
131:4758606c9316 | 1909 | if (s->wakeup) |
TASS Belgium NV |
131:4758606c9316 | 1910 | s->wakeup(PICO_SOCK_EV_FIN, s); |
TASS Belgium NV |
131:4758606c9316 | 1911 | |
TASS Belgium NV |
131:4758606c9316 | 1912 | /* delete socket */ |
TASS Belgium NV |
131:4758606c9316 | 1913 | pico_socket_del(s); |
TASS Belgium NV |
131:4758606c9316 | 1914 | return 0; |
TASS Belgium NV |
131:4758606c9316 | 1915 | } |
TASS Belgium NV |
131:4758606c9316 | 1916 | |
TASS Belgium NV |
131:4758606c9316 | 1917 | static int tcp_syn(struct pico_socket *s, struct pico_frame *f) |
TASS Belgium NV |
131:4758606c9316 | 1918 | { |
TASS Belgium NV |
131:4758606c9316 | 1919 | struct pico_socket_tcp *new = NULL; |
TASS Belgium NV |
131:4758606c9316 | 1920 | struct pico_tcp_hdr *hdr = NULL; |
TASS Belgium NV |
131:4758606c9316 | 1921 | if(s->number_of_pending_conn >= s->max_backlog) |
TASS Belgium NV |
131:4758606c9316 | 1922 | return -1; |
TASS Belgium NV |
131:4758606c9316 | 1923 | |
TASS Belgium NV |
131:4758606c9316 | 1924 | new = (struct pico_socket_tcp *)pico_socket_clone(s); |
TASS Belgium NV |
131:4758606c9316 | 1925 | hdr = (struct pico_tcp_hdr *)f->transport_hdr; |
TASS Belgium NV |
131:4758606c9316 | 1926 | if (!new) |
TASS Belgium NV |
131:4758606c9316 | 1927 | return -1; |
TASS Belgium NV |
131:4758606c9316 | 1928 | |
TASS Belgium NV |
131:4758606c9316 | 1929 | #ifdef PICO_TCP_SUPPORT_SOCKET_STATS |
TASS Belgium NV |
131:4758606c9316 | 1930 | pico_timer_add(2000, sock_stats, s); |
TASS Belgium NV |
131:4758606c9316 | 1931 | #endif |
TASS Belgium NV |
131:4758606c9316 | 1932 | |
TASS Belgium NV |
131:4758606c9316 | 1933 | new->sock.remote_port = ((struct pico_trans *)f->transport_hdr)->sport; |
TASS Belgium NV |
131:4758606c9316 | 1934 | #ifdef PICO_SUPPORT_IPV4 |
TASS Belgium NV |
131:4758606c9316 | 1935 | if (IS_IPV4(f)) { |
TASS Belgium NV |
131:4758606c9316 | 1936 | new->sock.remote_addr.ip4.addr = ((struct pico_ipv4_hdr *)(f->net_hdr))->src.addr; |
TASS Belgium NV |
131:4758606c9316 | 1937 | new->sock.local_addr.ip4.addr = ((struct pico_ipv4_hdr *)(f->net_hdr))->dst.addr; |
TASS Belgium NV |
131:4758606c9316 | 1938 | } |
TASS Belgium NV |
131:4758606c9316 | 1939 | |
TASS Belgium NV |
131:4758606c9316 | 1940 | #endif |
TASS Belgium NV |
131:4758606c9316 | 1941 | #ifdef PICO_SUPPORT_IPV6 |
TASS Belgium NV |
131:4758606c9316 | 1942 | if (IS_IPV6(f)) { |
TASS Belgium NV |
131:4758606c9316 | 1943 | new->sock.remote_addr.ip6 = ((struct pico_ipv6_hdr *)(f->net_hdr))->src; |
TASS Belgium NV |
131:4758606c9316 | 1944 | new->sock.local_addr.ip6 = ((struct pico_ipv6_hdr *)(f->net_hdr))->dst; |
TASS Belgium NV |
131:4758606c9316 | 1945 | } |
TASS Belgium NV |
131:4758606c9316 | 1946 | |
TASS Belgium NV |
131:4758606c9316 | 1947 | #endif |
TASS Belgium NV |
131:4758606c9316 | 1948 | |
TASS Belgium NV |
131:4758606c9316 | 1949 | /* Set socket limits */ |
TASS Belgium NV |
131:4758606c9316 | 1950 | new->tcpq_in.max_size = PICO_DEFAULT_SOCKETQ; |
TASS Belgium NV |
131:4758606c9316 | 1951 | new->tcpq_out.max_size = PICO_DEFAULT_SOCKETQ; |
TASS Belgium NV |
131:4758606c9316 | 1952 | new->tcpq_hold.max_size = 2 * PICO_TCP_DEFAULT_MSS; |
TASS Belgium NV |
131:4758606c9316 | 1953 | new->tcpq_in.overhead = (sizeof(struct tcp_input_segment) + sizeof(struct pico_tree_node)); |
TASS Belgium NV |
131:4758606c9316 | 1954 | new->tcpq_out.overhead = new->tcpq_hold.overhead = sizeof(struct pico_frame) + sizeof(struct pico_tree_node); |
TASS Belgium NV |
131:4758606c9316 | 1955 | |
TASS Belgium NV |
131:4758606c9316 | 1956 | f->sock = &new->sock; |
TASS Belgium NV |
131:4758606c9316 | 1957 | tcp_parse_options(f); |
TASS Belgium NV |
131:4758606c9316 | 1958 | new->mss = PICO_TCP_DEFAULT_MSS; |
TASS Belgium NV |
131:4758606c9316 | 1959 | new->rcv_nxt = long_be(hdr->seq) + 1; |
TASS Belgium NV |
131:4758606c9316 | 1960 | new->snd_nxt = long_be(pico_paws()); |
TASS Belgium NV |
131:4758606c9316 | 1961 | new->snd_last = new->snd_nxt; |
TASS Belgium NV |
131:4758606c9316 | 1962 | new->cwnd = PICO_TCP_IW; |
TASS Belgium NV |
131:4758606c9316 | 1963 | new->ssthresh = 40; |
TASS Belgium NV |
131:4758606c9316 | 1964 | new->recv_wnd = short_be(hdr->rwnd); |
TASS Belgium NV |
131:4758606c9316 | 1965 | new->jumbo = hdr->len & 0x07; |
TASS Belgium NV |
131:4758606c9316 | 1966 | s->number_of_pending_conn++; |
TASS Belgium NV |
131:4758606c9316 | 1967 | new->sock.parent = s; |
TASS Belgium NV |
131:4758606c9316 | 1968 | new->sock.wakeup = s->wakeup; |
TASS Belgium NV |
131:4758606c9316 | 1969 | /* Initialize timestamp values */ |
TASS Belgium NV |
131:4758606c9316 | 1970 | new->sock.state = PICO_SOCKET_STATE_BOUND | PICO_SOCKET_STATE_CONNECTED | PICO_SOCKET_STATE_TCP_SYN_RECV; |
TASS Belgium NV |
131:4758606c9316 | 1971 | pico_socket_add(&new->sock); |
TASS Belgium NV |
131:4758606c9316 | 1972 | tcp_send_synack(&new->sock); |
TASS Belgium NV |
131:4758606c9316 | 1973 | tcp_dbg("SYNACK sent, socket added. snd_nxt is %08x\n", new->snd_nxt); |
TASS Belgium NV |
131:4758606c9316 | 1974 | return 0; |
TASS Belgium NV |
131:4758606c9316 | 1975 | } |
TASS Belgium NV |
131:4758606c9316 | 1976 | |
TASS Belgium NV |
131:4758606c9316 | 1977 | static void tcp_set_init_point(struct pico_socket *s) |
TASS Belgium NV |
131:4758606c9316 | 1978 | { |
TASS Belgium NV |
131:4758606c9316 | 1979 | struct pico_socket_tcp *t = (struct pico_socket_tcp *)s; |
TASS Belgium NV |
131:4758606c9316 | 1980 | t->rcv_processed = t->rcv_nxt; |
TASS Belgium NV |
131:4758606c9316 | 1981 | } |
TASS Belgium NV |
131:4758606c9316 | 1982 | |
TASS Belgium NV |
131:4758606c9316 | 1983 | static int tcp_synack(struct pico_socket *s, struct pico_frame *f) |
TASS Belgium NV |
131:4758606c9316 | 1984 | { |
TASS Belgium NV |
131:4758606c9316 | 1985 | struct pico_socket_tcp *t = (struct pico_socket_tcp *) s; |
TASS Belgium NV |
131:4758606c9316 | 1986 | struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *)f->transport_hdr; |
TASS Belgium NV |
131:4758606c9316 | 1987 | |
TASS Belgium NV |
131:4758606c9316 | 1988 | if (ACKN(f) == (1 + t->snd_nxt)) { |
TASS Belgium NV |
131:4758606c9316 | 1989 | t->rcv_nxt = long_be(hdr->seq); |
TASS Belgium NV |
131:4758606c9316 | 1990 | t->rcv_processed = t->rcv_nxt + 1; |
TASS Belgium NV |
131:4758606c9316 | 1991 | tcp_ack(s, f); |
TASS Belgium NV |
131:4758606c9316 | 1992 | |
TASS Belgium NV |
131:4758606c9316 | 1993 | s->state &= 0x00FFU; |
TASS Belgium NV |
131:4758606c9316 | 1994 | s->state |= PICO_SOCKET_STATE_TCP_ESTABLISHED; |
TASS Belgium NV |
131:4758606c9316 | 1995 | tcp_dbg("TCP> Established. State: %x\n", s->state); |
TASS Belgium NV |
131:4758606c9316 | 1996 | |
TASS Belgium NV |
131:4758606c9316 | 1997 | if (s->wakeup) |
TASS Belgium NV |
131:4758606c9316 | 1998 | s->wakeup(PICO_SOCK_EV_CONN, s); |
TASS Belgium NV |
131:4758606c9316 | 1999 | |
TASS Belgium NV |
131:4758606c9316 | 2000 | s->ev_pending |= PICO_SOCK_EV_WR; |
TASS Belgium NV |
131:4758606c9316 | 2001 | |
TASS Belgium NV |
131:4758606c9316 | 2002 | t->rcv_nxt++; |
TASS Belgium NV |
131:4758606c9316 | 2003 | t->snd_nxt++; |
TASS Belgium NV |
131:4758606c9316 | 2004 | tcp_send_ack(t); /* return ACK */ |
TASS Belgium NV |
131:4758606c9316 | 2005 | |
TASS Belgium NV |
131:4758606c9316 | 2006 | return 0; |
TASS Belgium NV |
131:4758606c9316 | 2007 | |
TASS Belgium NV |
131:4758606c9316 | 2008 | } else { |
TASS Belgium NV |
131:4758606c9316 | 2009 | tcp_dbg("TCP> Not established, RST sent.\n"); |
TASS Belgium NV |
131:4758606c9316 | 2010 | tcp_nosync_rst(s, f); |
TASS Belgium NV |
131:4758606c9316 | 2011 | return 0; |
TASS Belgium NV |
131:4758606c9316 | 2012 | } |
TASS Belgium NV |
131:4758606c9316 | 2013 | } |
TASS Belgium NV |
131:4758606c9316 | 2014 | |
TASS Belgium NV |
131:4758606c9316 | 2015 | static int tcp_first_ack(struct pico_socket *s, struct pico_frame *f) |
TASS Belgium NV |
131:4758606c9316 | 2016 | { |
TASS Belgium NV |
131:4758606c9316 | 2017 | struct pico_socket_tcp *t = (struct pico_socket_tcp *)s; |
TASS Belgium NV |
131:4758606c9316 | 2018 | tcp_dbg("ACK in SYN_RECV: expecting %08x got %08x\n", t->snd_nxt, ACKN(f)); |
TASS Belgium NV |
131:4758606c9316 | 2019 | if (t->snd_nxt == ACKN(f)) { |
TASS Belgium NV |
131:4758606c9316 | 2020 | tcp_set_init_point(s); |
TASS Belgium NV |
131:4758606c9316 | 2021 | tcp_ack(s, f); |
TASS Belgium NV |
131:4758606c9316 | 2022 | s->state &= 0x00FFU; |
TASS Belgium NV |
131:4758606c9316 | 2023 | s->state |= PICO_SOCKET_STATE_TCP_ESTABLISHED; |
TASS Belgium NV |
131:4758606c9316 | 2024 | tcp_dbg("TCP: Established. State now: %04x\n", s->state); |
TASS Belgium NV |
131:4758606c9316 | 2025 | if( !s->parent && s->wakeup) { /* If the socket has no parent, -> sending socket that has a sim_open */ |
TASS Belgium NV |
131:4758606c9316 | 2026 | tcp_dbg("FIRST ACK - No parent found -> sending socket\n"); |
TASS Belgium NV |
131:4758606c9316 | 2027 | s->wakeup(PICO_SOCK_EV_CONN, s); |
TASS Belgium NV |
131:4758606c9316 | 2028 | } |
TASS Belgium NV |
131:4758606c9316 | 2029 | |
TASS Belgium NV |
131:4758606c9316 | 2030 | if (s->parent && s->parent->wakeup) { |
TASS Belgium NV |
131:4758606c9316 | 2031 | tcp_dbg("FIRST ACK - Parent found -> listening socket\n"); |
TASS Belgium NV |
131:4758606c9316 | 2032 | s->wakeup = s->parent->wakeup; |
TASS Belgium NV |
131:4758606c9316 | 2033 | s->parent->wakeup(PICO_SOCK_EV_CONN, s->parent); |
TASS Belgium NV |
131:4758606c9316 | 2034 | } |
TASS Belgium NV |
131:4758606c9316 | 2035 | |
TASS Belgium NV |
131:4758606c9316 | 2036 | s->ev_pending |= PICO_SOCK_EV_WR; |
TASS Belgium NV |
131:4758606c9316 | 2037 | tcp_dbg("%s: snd_nxt is now %08x\n", __FUNCTION__, t->snd_nxt); |
TASS Belgium NV |
131:4758606c9316 | 2038 | return 0; |
TASS Belgium NV |
131:4758606c9316 | 2039 | } else { |
TASS Belgium NV |
131:4758606c9316 | 2040 | tcp_nosync_rst(s, f); |
TASS Belgium NV |
131:4758606c9316 | 2041 | return 0; |
TASS Belgium NV |
131:4758606c9316 | 2042 | } |
TASS Belgium NV |
131:4758606c9316 | 2043 | } |
TASS Belgium NV |
131:4758606c9316 | 2044 | |
TASS Belgium NV |
131:4758606c9316 | 2045 | static int tcp_closewait(struct pico_socket *s, struct pico_frame *f) |
TASS Belgium NV |
131:4758606c9316 | 2046 | { |
TASS Belgium NV |
131:4758606c9316 | 2047 | |
TASS Belgium NV |
131:4758606c9316 | 2048 | struct pico_socket_tcp *t = (struct pico_socket_tcp *)s; |
TASS Belgium NV |
131:4758606c9316 | 2049 | struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *) (f->transport_hdr); |
TASS Belgium NV |
131:4758606c9316 | 2050 | |
TASS Belgium NV |
131:4758606c9316 | 2051 | |
TASS Belgium NV |
131:4758606c9316 | 2052 | if (f->payload_len > 0) |
TASS Belgium NV |
131:4758606c9316 | 2053 | tcp_data_in(s, f); |
TASS Belgium NV |
131:4758606c9316 | 2054 | |
TASS Belgium NV |
131:4758606c9316 | 2055 | if (f->flags & PICO_TCP_ACK) |
TASS Belgium NV |
131:4758606c9316 | 2056 | tcp_ack(s, f); |
TASS Belgium NV |
131:4758606c9316 | 2057 | |
TASS Belgium NV |
131:4758606c9316 | 2058 | if (seq_compare(SEQN(f), t->rcv_nxt) == 0) { |
TASS Belgium NV |
131:4758606c9316 | 2059 | /* received FIN, increase ACK nr */ |
TASS Belgium NV |
131:4758606c9316 | 2060 | t->rcv_nxt = long_be(hdr->seq) + 1; |
TASS Belgium NV |
131:4758606c9316 | 2061 | s->state &= 0x00FFU; |
TASS Belgium NV |
131:4758606c9316 | 2062 | s->state |= PICO_SOCKET_STATE_TCP_CLOSE_WAIT; |
TASS Belgium NV |
131:4758606c9316 | 2063 | /* set SHUT_REMOTE */ |
TASS Belgium NV |
131:4758606c9316 | 2064 | s->state |= PICO_SOCKET_STATE_SHUT_REMOTE; |
TASS Belgium NV |
131:4758606c9316 | 2065 | tcp_dbg("TCP> Close-wait\n"); |
TASS Belgium NV |
131:4758606c9316 | 2066 | |
TASS Belgium NV |
131:4758606c9316 | 2067 | if (s->wakeup) { |
TASS Belgium NV |
131:4758606c9316 | 2068 | if(f->payload_len > 0) { |
TASS Belgium NV |
131:4758606c9316 | 2069 | struct pico_socket_tcp *_t = (struct pico_socket_tcp *)s; |
TASS Belgium NV |
131:4758606c9316 | 2070 | _t->sock.ev_pending |= PICO_SOCK_EV_CLOSE; |
TASS Belgium NV |
131:4758606c9316 | 2071 | }else |
TASS Belgium NV |
131:4758606c9316 | 2072 | s->wakeup(PICO_SOCK_EV_CLOSE, s); |
TASS Belgium NV |
131:4758606c9316 | 2073 | } |
TASS Belgium NV |
131:4758606c9316 | 2074 | } else { |
TASS Belgium NV |
131:4758606c9316 | 2075 | tcp_send_ack(t); /* return ACK */ |
TASS Belgium NV |
131:4758606c9316 | 2076 | } |
TASS Belgium NV |
131:4758606c9316 | 2077 | |
TASS Belgium NV |
131:4758606c9316 | 2078 | return 0; |
TASS Belgium NV |
131:4758606c9316 | 2079 | } |
TASS Belgium NV |
131:4758606c9316 | 2080 | |
TASS Belgium NV |
131:4758606c9316 | 2081 | /*static int tcp_fin(struct pico_socket *s, struct pico_frame *f) |
TASS Belgium NV |
131:4758606c9316 | 2082 | { |
TASS Belgium NV |
131:4758606c9316 | 2083 | return 0; |
TASS Belgium NV |
131:4758606c9316 | 2084 | }*/ |
TASS Belgium NV |
131:4758606c9316 | 2085 | |
TASS Belgium NV |
131:4758606c9316 | 2086 | static int tcp_rcvfin(struct pico_socket *s, struct pico_frame *f) |
TASS Belgium NV |
131:4758606c9316 | 2087 | { |
TASS Belgium NV |
131:4758606c9316 | 2088 | struct pico_socket_tcp *t = (struct pico_socket_tcp *)s; |
TASS Belgium NV |
131:4758606c9316 | 2089 | IGNORE_PARAMETER(f); |
TASS Belgium NV |
131:4758606c9316 | 2090 | tcp_dbg("TCP> Received FIN in FIN_WAIT1\n"); |
TASS Belgium NV |
131:4758606c9316 | 2091 | s->state &= 0x00FFU; |
TASS Belgium NV |
131:4758606c9316 | 2092 | s->state |= PICO_SOCKET_STATE_TCP_CLOSING; |
TASS Belgium NV |
131:4758606c9316 | 2093 | t->rcv_processed = t->rcv_nxt + 1; |
TASS Belgium NV |
131:4758606c9316 | 2094 | t->rcv_nxt++; |
TASS Belgium NV |
131:4758606c9316 | 2095 | /* send ACK */ |
TASS Belgium NV |
131:4758606c9316 | 2096 | tcp_send_ack(t); |
TASS Belgium NV |
131:4758606c9316 | 2097 | return 0; |
TASS Belgium NV |
131:4758606c9316 | 2098 | } |
TASS Belgium NV |
131:4758606c9316 | 2099 | |
TASS Belgium NV |
131:4758606c9316 | 2100 | static int tcp_finack(struct pico_socket *s, struct pico_frame *f) |
TASS Belgium NV |
131:4758606c9316 | 2101 | { |
TASS Belgium NV |
131:4758606c9316 | 2102 | struct pico_socket_tcp *t = (struct pico_socket_tcp *)s; |
TASS Belgium NV |
131:4758606c9316 | 2103 | IGNORE_PARAMETER(f); |
TASS Belgium NV |
131:4758606c9316 | 2104 | |
TASS Belgium NV |
131:4758606c9316 | 2105 | tcp_dbg("TCP> ENTERED finack\n"); |
TASS Belgium NV |
131:4758606c9316 | 2106 | t->rcv_nxt++; |
TASS Belgium NV |
131:4758606c9316 | 2107 | /* send ACK */ |
TASS Belgium NV |
131:4758606c9316 | 2108 | tcp_send_ack(t); |
TASS Belgium NV |
131:4758606c9316 | 2109 | |
TASS Belgium NV |
131:4758606c9316 | 2110 | /* call socket wakeup with EV_FIN */ |
TASS Belgium NV |
131:4758606c9316 | 2111 | if (s->wakeup) |
TASS Belgium NV |
131:4758606c9316 | 2112 | s->wakeup(PICO_SOCK_EV_FIN, s); |
TASS Belgium NV |
131:4758606c9316 | 2113 | |
TASS Belgium NV |
131:4758606c9316 | 2114 | s->state &= 0x00FFU; |
TASS Belgium NV |
131:4758606c9316 | 2115 | s->state |= PICO_SOCKET_STATE_TCP_TIME_WAIT; |
TASS Belgium NV |
131:4758606c9316 | 2116 | /* set SHUT_REMOTE */ |
TASS Belgium NV |
131:4758606c9316 | 2117 | s->state |= PICO_SOCKET_STATE_SHUT_REMOTE; |
TASS Belgium NV |
131:4758606c9316 | 2118 | pico_timer_add(2000, tcp_deltcb, t); |
TASS Belgium NV |
131:4758606c9316 | 2119 | |
TASS Belgium NV |
131:4758606c9316 | 2120 | return 0; |
TASS Belgium NV |
131:4758606c9316 | 2121 | } |
TASS Belgium NV |
131:4758606c9316 | 2122 | |
TASS Belgium NV |
131:4758606c9316 | 2123 | static void tcp_force_closed(struct pico_socket *s) |
TASS Belgium NV |
131:4758606c9316 | 2124 | { |
TASS Belgium NV |
131:4758606c9316 | 2125 | struct pico_socket_tcp *t = (struct pico_socket_tcp *) s; |
daniele | 29:1a47b7151851 | 2126 | /* update state */ |
daniele | 29:1a47b7151851 | 2127 | (t->sock).state &= 0x00FFU; |
daniele | 29:1a47b7151851 | 2128 | (t->sock).state |= PICO_SOCKET_STATE_TCP_CLOSED; |
daniele | 29:1a47b7151851 | 2129 | (t->sock).state &= 0xFF00U; |
daniele | 29:1a47b7151851 | 2130 | (t->sock).state |= PICO_SOCKET_STATE_CLOSED; |
tass | 70:cd218dd180e5 | 2131 | } |
tass | 70:cd218dd180e5 | 2132 | |
tass | 70:cd218dd180e5 | 2133 | static void tcp_wakeup_pending(struct pico_socket *s, uint16_t ev) |
tass | 70:cd218dd180e5 | 2134 | { |
TASS Belgium NV |
131:4758606c9316 | 2135 | struct pico_socket_tcp *t = (struct pico_socket_tcp *) s; |
TASS Belgium NV |
131:4758606c9316 | 2136 | if ((t->sock).wakeup) |
TASS Belgium NV |
131:4758606c9316 | 2137 | (t->sock).wakeup(ev, &(t->sock)); |
tass | 70:cd218dd180e5 | 2138 | } |
tass | 70:cd218dd180e5 | 2139 | |
daniele | 29:1a47b7151851 | 2140 | static int tcp_rst(struct pico_socket *s, struct pico_frame *f) |
daniele | 29:1a47b7151851 | 2141 | { |
TASS Belgium NV |
131:4758606c9316 | 2142 | struct pico_socket_tcp *t = (struct pico_socket_tcp *) s; |
TASS Belgium NV |
131:4758606c9316 | 2143 | struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *) (f->transport_hdr); |
TASS Belgium NV |
131:4758606c9316 | 2144 | |
TASS Belgium NV |
131:4758606c9316 | 2145 | tcp_dbg("TCP >>>>>>>>>>>>>> received RST <<<<<<<<<<<<<<<<<<<<\n"); |
TASS Belgium NV |
131:4758606c9316 | 2146 | if ((s->state & PICO_SOCKET_STATE_TCP) == PICO_SOCKET_STATE_TCP_SYN_SENT) { |
TASS Belgium NV |
131:4758606c9316 | 2147 | /* the RST is acceptable if the ACK field acknowledges the SYN */ |
TASS Belgium NV |
131:4758606c9316 | 2148 | if ((t->snd_nxt + 1) == ACKN(f)) { /* valid, got to closed state */ |
TASS Belgium NV |
131:4758606c9316 | 2149 | tcp_force_closed(s); |
TASS Belgium NV |
131:4758606c9316 | 2150 | pico_err = PICO_ERR_ECONNRESET; |
TASS Belgium NV |
131:4758606c9316 | 2151 | tcp_wakeup_pending(s, PICO_SOCK_EV_ERR); |
TASS Belgium NV |
131:4758606c9316 | 2152 | pico_socket_del(&t->sock); /* delete socket */ |
TASS Belgium NV |
131:4758606c9316 | 2153 | } else { /* not valid, ignore */ |
TASS Belgium NV |
131:4758606c9316 | 2154 | tcp_dbg("TCP RST> IGNORE\n"); |
TASS Belgium NV |
131:4758606c9316 | 2155 | return 0; |
TASS Belgium NV |
131:4758606c9316 | 2156 | } |
TASS Belgium NV |
131:4758606c9316 | 2157 | } else { /* all other states */ |
TASS Belgium NV |
131:4758606c9316 | 2158 | /* all reset (RST) segments are validated by checking their SEQ-fields, |
TASS Belgium NV |
131:4758606c9316 | 2159 | a reset is valid if its sequence number is in the window */ |
TASS Belgium NV |
131:4758606c9316 | 2160 | if ((long_be(hdr->seq) >= t->rcv_ackd) && (long_be(hdr->seq) <= ((uint32_t)(short_be(hdr->rwnd) << (t->wnd_scale)) + t->rcv_ackd))) { |
TASS Belgium NV |
131:4758606c9316 | 2161 | if ((s->state & PICO_SOCKET_STATE_TCP) == PICO_SOCKET_STATE_TCP_SYN_RECV) { |
TASS Belgium NV |
131:4758606c9316 | 2162 | tcp_force_closed(s); |
TASS Belgium NV |
131:4758606c9316 | 2163 | pico_err = PICO_ERR_ECONNRESET; |
TASS Belgium NV |
131:4758606c9316 | 2164 | tcp_wakeup_pending(s, PICO_SOCK_EV_ERR); |
TASS Belgium NV |
131:4758606c9316 | 2165 | pico_socket_del(&t->sock); /* delete socket */ |
TASS Belgium NV |
131:4758606c9316 | 2166 | tcp_dbg("TCP RST> SOCKET BACK TO LISTEN\n"); |
TASS Belgium NV |
131:4758606c9316 | 2167 | /* pico_socket_del(s); */ |
TASS Belgium NV |
131:4758606c9316 | 2168 | } else { |
TASS Belgium NV |
131:4758606c9316 | 2169 | tcp_force_closed(s); |
TASS Belgium NV |
131:4758606c9316 | 2170 | tcp_wakeup_pending(s, PICO_SOCK_EV_FIN); |
TASS Belgium NV |
131:4758606c9316 | 2171 | pico_err = PICO_ERR_ECONNRESET; |
TASS Belgium NV |
131:4758606c9316 | 2172 | tcp_wakeup_pending(s, PICO_SOCK_EV_ERR); |
TASS Belgium NV |
131:4758606c9316 | 2173 | pico_socket_del(&t->sock); /* delete socket */ |
TASS Belgium NV |
131:4758606c9316 | 2174 | } |
TASS Belgium NV |
131:4758606c9316 | 2175 | } else { /* not valid, ignore */ |
TASS Belgium NV |
131:4758606c9316 | 2176 | tcp_dbg("TCP RST> IGNORE\n"); |
TASS Belgium NV |
131:4758606c9316 | 2177 | return 0; |
TASS Belgium NV |
131:4758606c9316 | 2178 | } |
daniele | 29:1a47b7151851 | 2179 | } |
TASS Belgium NV |
131:4758606c9316 | 2180 | |
TASS Belgium NV |
131:4758606c9316 | 2181 | return 0; |
daniele | 29:1a47b7151851 | 2182 | } |
tass | 79:6d1cb906043d | 2183 | static int tcp_halfopencon(struct pico_socket *s, struct pico_frame *fr) |
tass | 79:6d1cb906043d | 2184 | { |
TASS Belgium NV |
131:4758606c9316 | 2185 | struct pico_socket_tcp *t = (struct pico_socket_tcp *) s; |
TASS Belgium NV |
131:4758606c9316 | 2186 | IGNORE_PARAMETER(fr); |
TASS Belgium NV |
131:4758606c9316 | 2187 | tcp_send_ack(t); |
TASS Belgium NV |
131:4758606c9316 | 2188 | return 0; |
tass | 79:6d1cb906043d | 2189 | } |
tass | 110:0ece1bbbd36e | 2190 | |
tass | 109:f630e6230063 | 2191 | static int tcp_closeconn(struct pico_socket *s, struct pico_frame *fr) |
tass | 109:f630e6230063 | 2192 | { |
TASS Belgium NV |
131:4758606c9316 | 2193 | struct pico_socket_tcp *t = (struct pico_socket_tcp *) s; |
TASS Belgium NV |
131:4758606c9316 | 2194 | struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *) (fr->transport_hdr); |
TASS Belgium NV |
131:4758606c9316 | 2195 | |
TASS Belgium NV |
131:4758606c9316 | 2196 | if (seq_compare(SEQN(fr), t->rcv_nxt) == 0) { |
TASS Belgium NV |
131:4758606c9316 | 2197 | /* received FIN, increase ACK nr */ |
TASS Belgium NV |
131:4758606c9316 | 2198 | t->rcv_nxt = long_be(hdr->seq) + 1; |
TASS Belgium NV |
131:4758606c9316 | 2199 | s->state &= 0x00FFU; |
TASS Belgium NV |
131:4758606c9316 | 2200 | s->state |= PICO_SOCKET_STATE_TCP_CLOSE_WAIT; |
TASS Belgium NV |
131:4758606c9316 | 2201 | /* set SHUT_LOCAL */ |
TASS Belgium NV |
131:4758606c9316 | 2202 | s->state |= PICO_SOCKET_STATE_SHUT_LOCAL; |
TASS Belgium NV |
131:4758606c9316 | 2203 | pico_socket_close(s); |
TASS Belgium NV |
131:4758606c9316 | 2204 | return 1; |
TASS Belgium NV |
131:4758606c9316 | 2205 | } |
TASS Belgium NV |
131:4758606c9316 | 2206 | |
TASS Belgium NV |
131:4758606c9316 | 2207 | return 0; |
tass | 109:f630e6230063 | 2208 | } |
tass | 110:0ece1bbbd36e | 2209 | |
daniele | 29:1a47b7151851 | 2210 | struct tcp_action_entry { |
TASS Belgium NV |
131:4758606c9316 | 2211 | uint16_t tcpstate; |
TASS Belgium NV |
131:4758606c9316 | 2212 | int (*syn)(struct pico_socket *s, struct pico_frame *f); |
TASS Belgium NV |
131:4758606c9316 | 2213 | int (*synack)(struct pico_socket *s, struct pico_frame *f); |
TASS Belgium NV |
131:4758606c9316 | 2214 | int (*ack)(struct pico_socket *s, struct pico_frame *f); |
TASS Belgium NV |
131:4758606c9316 | 2215 | int (*data)(struct pico_socket *s, struct pico_frame *f); |
TASS Belgium NV |
131:4758606c9316 | 2216 | int (*fin)(struct pico_socket *s, struct pico_frame *f); |
TASS Belgium NV |
131:4758606c9316 | 2217 | int (*finack)(struct pico_socket *s, struct pico_frame *f); |
TASS Belgium NV |
131:4758606c9316 | 2218 | int (*rst)(struct pico_socket *s, struct pico_frame *f); |
daniele | 29:1a47b7151851 | 2219 | }; |
daniele | 29:1a47b7151851 | 2220 | |
daniele | 29:1a47b7151851 | 2221 | static struct tcp_action_entry tcp_fsm[] = { |
TASS Belgium NV |
131:4758606c9316 | 2222 | /* State syn synack ack data fin finack rst*/ |
TASS Belgium NV |
131:4758606c9316 | 2223 | { PICO_SOCKET_STATE_TCP_UNDEF, NULL, NULL, NULL, NULL, NULL, NULL, NULL }, |
TASS Belgium NV |
131:4758606c9316 | 2224 | { PICO_SOCKET_STATE_TCP_CLOSED, NULL, NULL, NULL, NULL, NULL, NULL, NULL }, |
TASS Belgium NV |
131:4758606c9316 | 2225 | { PICO_SOCKET_STATE_TCP_LISTEN, &tcp_syn, NULL, NULL, NULL, NULL, NULL, NULL }, |
TASS Belgium NV |
131:4758606c9316 | 2226 | { PICO_SOCKET_STATE_TCP_SYN_SENT, NULL, &tcp_synack, NULL, NULL, NULL, NULL, &tcp_rst }, |
TASS Belgium NV |
131:4758606c9316 | 2227 | { PICO_SOCKET_STATE_TCP_SYN_RECV, NULL, NULL, &tcp_first_ack, &tcp_data_in, NULL, &tcp_closeconn, &tcp_rst }, |
TASS Belgium NV |
131:4758606c9316 | 2228 | { PICO_SOCKET_STATE_TCP_ESTABLISHED, &tcp_halfopencon, &tcp_ack, &tcp_ack, &tcp_data_in, &tcp_closewait, &tcp_closewait, &tcp_rst }, |
TASS Belgium NV |
131:4758606c9316 | 2229 | { PICO_SOCKET_STATE_TCP_CLOSE_WAIT, NULL, &tcp_ack, &tcp_ack, &tcp_send_rst, &tcp_closewait, &tcp_closewait, &tcp_rst }, |
TASS Belgium NV |
131:4758606c9316 | 2230 | { PICO_SOCKET_STATE_TCP_LAST_ACK, NULL, &tcp_ack, &tcp_lastackwait, &tcp_send_rst, &tcp_send_rst, &tcp_send_rst, &tcp_rst }, |
TASS Belgium NV |
131:4758606c9316 | 2231 | { PICO_SOCKET_STATE_TCP_FIN_WAIT1, NULL, &tcp_ack, &tcp_finwaitack, &tcp_data_in, &tcp_rcvfin, &tcp_finack, &tcp_rst }, |
TASS Belgium NV |
131:4758606c9316 | 2232 | { PICO_SOCKET_STATE_TCP_FIN_WAIT2, NULL, &tcp_ack, &tcp_ack, &tcp_data_in, &tcp_finwaitfin, &tcp_finack, &tcp_rst }, |
TASS Belgium NV |
131:4758606c9316 | 2233 | { PICO_SOCKET_STATE_TCP_CLOSING, NULL, &tcp_ack, &tcp_closewaitack, &tcp_send_rst, &tcp_send_rst, &tcp_send_rst, &tcp_rst }, |
TASS Belgium NV |
131:4758606c9316 | 2234 | { PICO_SOCKET_STATE_TCP_TIME_WAIT, NULL, &tcp_ack, &tcp_send_rst, &tcp_send_rst, &tcp_send_rst, &tcp_send_rst, &tcp_rst } |
daniele | 29:1a47b7151851 | 2235 | }; |
daniele | 29:1a47b7151851 | 2236 | |
daniele | 29:1a47b7151851 | 2237 | /* |
daniele | 29:1a47b7151851 | 2238 | NOTE: in SYN-RECV receiving syn when cloned by default (see yellow pos-it), should send reset. |
TASS Belgium NV |
131:4758606c9316 | 2239 | */ |
TASS Belgium NV |
131:4758606c9316 | 2240 | #define MAX_VALID_FLAGS 9 /* Maximum number of valid flag combinations */ |
TASS Belgium NV |
131:4758606c9316 | 2241 | static uint8_t invalid_flags(struct pico_socket *s, uint8_t flags) |
TASS Belgium NV |
131:4758606c9316 | 2242 | { |
TASS Belgium NV |
131:4758606c9316 | 2243 | uint8_t i; |
TASS Belgium NV |
131:4758606c9316 | 2244 | static uint8_t valid_flags[PICO_SOCKET_STATE_TCP_ARRAYSIZ][MAX_VALID_FLAGS] = { |
TASS Belgium NV |
131:4758606c9316 | 2245 | { /* PICO_SOCKET_STATE_TCP_UNDEF */ }, |
TASS Belgium NV |
131:4758606c9316 | 2246 | { /* PICO_SOCKET_STATE_TCP_CLOSED */ }, |
TASS Belgium NV |
131:4758606c9316 | 2247 | { /* PICO_SOCKET_STATE_TCP_LISTEN */ PICO_TCP_SYN }, |
tass picotcp@tass.be | 133:5b075f5e141a | 2248 | { /* PICO_SOCKET_STATE_TCP_SYN_SENT */ PICO_TCP_SYNACK, PICO_TCP_RST, PICO_TCP_RSTACK}, |
TASS Belgium NV |
131:4758606c9316 | 2249 | { /* PICO_SOCKET_STATE_TCP_SYN_RECV */ PICO_TCP_ACK, PICO_TCP_PSH, PICO_TCP_PSHACK, PICO_TCP_FINACK, PICO_TCP_FINPSHACK, PICO_TCP_RST}, |
TASS Belgium NV |
131:4758606c9316 | 2250 | { /* PICO_SOCKET_STATE_TCP_ESTABLISHED*/ PICO_TCP_SYN, PICO_TCP_SYNACK, PICO_TCP_ACK, PICO_TCP_PSH, PICO_TCP_PSHACK, PICO_TCP_FIN, PICO_TCP_FINACK, PICO_TCP_FINPSHACK, PICO_TCP_RST}, |
TASS Belgium NV |
131:4758606c9316 | 2251 | { /* PICO_SOCKET_STATE_TCP_CLOSE_WAIT */ PICO_TCP_SYNACK, PICO_TCP_ACK, PICO_TCP_PSH, PICO_TCP_PSHACK, PICO_TCP_FIN, PICO_TCP_FINACK, PICO_TCP_FINPSHACK, PICO_TCP_RST}, |
TASS Belgium NV |
131:4758606c9316 | 2252 | { /* PICO_SOCKET_STATE_TCP_LAST_ACK */ PICO_TCP_SYNACK, PICO_TCP_ACK, PICO_TCP_PSH, PICO_TCP_PSHACK, PICO_TCP_FIN, PICO_TCP_FINACK, PICO_TCP_FINPSHACK, PICO_TCP_RST}, |
TASS Belgium NV |
131:4758606c9316 | 2253 | { /* PICO_SOCKET_STATE_TCP_FIN_WAIT1 */ PICO_TCP_SYNACK, PICO_TCP_ACK, PICO_TCP_PSH, PICO_TCP_PSHACK, PICO_TCP_FIN, PICO_TCP_FINACK, PICO_TCP_FINPSHACK, PICO_TCP_RST}, |
TASS Belgium NV |
131:4758606c9316 | 2254 | { /* PICO_SOCKET_STATE_TCP_FIN_WAIT2 */ PICO_TCP_SYNACK, PICO_TCP_ACK, PICO_TCP_PSH, PICO_TCP_PSHACK, PICO_TCP_FIN, PICO_TCP_FINACK, PICO_TCP_FINPSHACK, PICO_TCP_RST}, |
TASS Belgium NV |
131:4758606c9316 | 2255 | { /* PICO_SOCKET_STATE_TCP_CLOSING */ PICO_TCP_SYNACK, PICO_TCP_ACK, PICO_TCP_PSH, PICO_TCP_PSHACK, PICO_TCP_FIN, PICO_TCP_FINACK, PICO_TCP_FINPSHACK, PICO_TCP_RST}, |
TASS Belgium NV |
131:4758606c9316 | 2256 | { /* PICO_SOCKET_STATE_TCP_TIME_WAIT */ PICO_TCP_SYNACK, PICO_TCP_ACK, PICO_TCP_PSH, PICO_TCP_PSHACK, PICO_TCP_FIN, PICO_TCP_FINACK, PICO_TCP_FINPSHACK, PICO_TCP_RST}, |
TASS Belgium NV |
131:4758606c9316 | 2257 | }; |
TASS Belgium NV |
131:4758606c9316 | 2258 | if(!flags) |
TASS Belgium NV |
131:4758606c9316 | 2259 | return 1; |
TASS Belgium NV |
131:4758606c9316 | 2260 | |
TASS Belgium NV |
131:4758606c9316 | 2261 | for(i = 0; i < MAX_VALID_FLAGS; i++) |
TASS Belgium NV |
131:4758606c9316 | 2262 | if(valid_flags[s->state >> 8u][i] == flags) |
TASS Belgium NV |
131:4758606c9316 | 2263 | return 0; |
TASS Belgium NV |
131:4758606c9316 | 2264 | |
TASS Belgium NV |
131:4758606c9316 | 2265 | return 1; |
TASS Belgium NV |
131:4758606c9316 | 2266 | } |
daniele | 29:1a47b7151851 | 2267 | int pico_tcp_input(struct pico_socket *s, struct pico_frame *f) |
daniele | 29:1a47b7151851 | 2268 | { |
TASS Belgium NV |
131:4758606c9316 | 2269 | struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *) (f->transport_hdr); |
TASS Belgium NV |
131:4758606c9316 | 2270 | int ret = 0; |
TASS Belgium NV |
131:4758606c9316 | 2271 | uint8_t flags = hdr->flags; |
TASS Belgium NV |
131:4758606c9316 | 2272 | struct tcp_action_entry *action = &tcp_fsm[s->state >> 8]; |
TASS Belgium NV |
131:4758606c9316 | 2273 | |
TASS Belgium NV |
131:4758606c9316 | 2274 | f->payload = (f->transport_hdr + ((hdr->len & 0xf0) >> 2)); |
TASS Belgium NV |
131:4758606c9316 | 2275 | f->payload_len = (uint16_t)(f->transport_len - ((hdr->len & 0xf0) >> 2)); |
TASS Belgium NV |
131:4758606c9316 | 2276 | |
TASS Belgium NV |
131:4758606c9316 | 2277 | tcp_dbg("[%lu] TCP> [tcp input] socket: %p state: %d <-- local port:%d remote port: %d seq: %08x ack: %08x flags: %02x = t_len: %d, hdr: %u payload: %d\n", pico_tick, |
TASS Belgium NV |
131:4758606c9316 | 2278 | s, s->state >> 8, short_be(hdr->trans.dport), short_be(hdr->trans.sport), SEQN(f), ACKN(f), hdr->flags, f->transport_len, (hdr->len & 0xf0) >> 2, f->payload_len ); |
TASS Belgium NV |
131:4758606c9316 | 2279 | |
TASS Belgium NV |
131:4758606c9316 | 2280 | /* This copy of the frame has the current socket as owner */ |
TASS Belgium NV |
131:4758606c9316 | 2281 | f->sock = s; |
TASS Belgium NV |
131:4758606c9316 | 2282 | s->timestamp = PICO_TIME_MS(); |
TASS Belgium NV |
131:4758606c9316 | 2283 | /* Those are not supported at this time. */ |
TASS Belgium NV |
131:4758606c9316 | 2284 | /* flags &= (uint8_t) ~(PICO_TCP_CWR | PICO_TCP_URG | PICO_TCP_ECN); */ |
TASS Belgium NV |
131:4758606c9316 | 2285 | if(invalid_flags(s, flags)) |
TASS Belgium NV |
131:4758606c9316 | 2286 | pico_tcp_reply_rst(f); |
TASS Belgium NV |
131:4758606c9316 | 2287 | else if (flags == PICO_TCP_SYN) { |
TASS Belgium NV |
131:4758606c9316 | 2288 | if (action->syn) |
TASS Belgium NV |
131:4758606c9316 | 2289 | action->syn(s, f); |
TASS Belgium NV |
131:4758606c9316 | 2290 | } else if (flags == (PICO_TCP_SYN | PICO_TCP_ACK)) { |
TASS Belgium NV |
131:4758606c9316 | 2291 | if (action->synack) |
TASS Belgium NV |
131:4758606c9316 | 2292 | action->synack(s, f); |
TASS Belgium NV |
131:4758606c9316 | 2293 | } else { |
TASS Belgium NV |
131:4758606c9316 | 2294 | if ((flags == PICO_TCP_ACK) || (flags == (PICO_TCP_ACK | PICO_TCP_PSH))) { |
TASS Belgium NV |
131:4758606c9316 | 2295 | if (action->ack) { |
TASS Belgium NV |
131:4758606c9316 | 2296 | action->ack(s, f); |
TASS Belgium NV |
131:4758606c9316 | 2297 | } |
TASS Belgium NV |
131:4758606c9316 | 2298 | } |
TASS Belgium NV |
131:4758606c9316 | 2299 | |
TASS Belgium NV |
131:4758606c9316 | 2300 | if (f->payload_len > 0 && !(s->state & PICO_SOCKET_STATE_CLOSED) && !TCP_IS_STATE(s, PICO_SOCKET_STATE_TCP_LISTEN)) |
TASS Belgium NV |
131:4758606c9316 | 2301 | { |
TASS Belgium NV |
131:4758606c9316 | 2302 | ret = f->payload_len; |
TASS Belgium NV |
131:4758606c9316 | 2303 | if (action->data) |
TASS Belgium NV |
131:4758606c9316 | 2304 | action->data(s, f); |
TASS Belgium NV |
131:4758606c9316 | 2305 | } |
TASS Belgium NV |
131:4758606c9316 | 2306 | |
TASS Belgium NV |
131:4758606c9316 | 2307 | if (flags == PICO_TCP_FIN) { |
TASS Belgium NV |
131:4758606c9316 | 2308 | if (action->fin) |
TASS Belgium NV |
131:4758606c9316 | 2309 | action->fin(s, f); |
TASS Belgium NV |
131:4758606c9316 | 2310 | } |
TASS Belgium NV |
131:4758606c9316 | 2311 | |
TASS Belgium NV |
131:4758606c9316 | 2312 | if ((flags == (PICO_TCP_FIN | PICO_TCP_ACK)) || (flags == (PICO_TCP_FIN | PICO_TCP_ACK | PICO_TCP_PSH))) { |
TASS Belgium NV |
131:4758606c9316 | 2313 | if (action->finack) |
TASS Belgium NV |
131:4758606c9316 | 2314 | action->finack(s, f); |
TASS Belgium NV |
131:4758606c9316 | 2315 | } |
TASS Belgium NV |
131:4758606c9316 | 2316 | |
TASS Belgium NV |
131:4758606c9316 | 2317 | if (flags & PICO_TCP_RST) { |
TASS Belgium NV |
131:4758606c9316 | 2318 | if (action->rst) |
TASS Belgium NV |
131:4758606c9316 | 2319 | action->rst(s, f); |
TASS Belgium NV |
131:4758606c9316 | 2320 | } |
daniele | 29:1a47b7151851 | 2321 | } |
TASS Belgium NV |
131:4758606c9316 | 2322 | |
TASS Belgium NV |
131:4758606c9316 | 2323 | /* discard: */ |
TASS Belgium NV |
131:4758606c9316 | 2324 | pico_frame_discard(f); |
TASS Belgium NV |
131:4758606c9316 | 2325 | return ret; |
daniele | 29:1a47b7151851 | 2326 | } |
daniele | 29:1a47b7151851 | 2327 | |
tass | 128:ae39e6e81531 | 2328 | static void tcp_send_keepalive(pico_time when, void *_t) |
daniele | 29:1a47b7151851 | 2329 | { |
TASS Belgium NV |
131:4758606c9316 | 2330 | struct pico_socket_tcp *t = (struct pico_socket_tcp *)_t; |
TASS Belgium NV |
131:4758606c9316 | 2331 | IGNORE_PARAMETER(when); |
TASS Belgium NV |
131:4758606c9316 | 2332 | tcp_dbg("Sending keepalive (%d), [State = %d]...\n", t->backoff, t->sock.state ); |
TASS Belgium NV |
131:4758606c9316 | 2333 | if( t->sock.net && ((t->sock.state & 0xFF00) == PICO_SOCKET_STATE_TCP_ESTABLISHED)) |
TASS Belgium NV |
131:4758606c9316 | 2334 | { |
TASS Belgium NV |
131:4758606c9316 | 2335 | tcp_send_ack(t); |
TASS Belgium NV |
131:4758606c9316 | 2336 | |
TASS Belgium NV |
131:4758606c9316 | 2337 | if (t->keepalive_timer_running > 0) { |
TASS Belgium NV |
131:4758606c9316 | 2338 | t->keepalive_timer_running--; |
TASS Belgium NV |
131:4758606c9316 | 2339 | } |
TASS Belgium NV |
131:4758606c9316 | 2340 | |
TASS Belgium NV |
131:4758606c9316 | 2341 | if (t->keepalive_timer_running == 0) { |
TASS Belgium NV |
131:4758606c9316 | 2342 | t->keepalive_timer_running++; |
TASS Belgium NV |
131:4758606c9316 | 2343 | tcp_dbg("[Self] Adding timer(retransmit keepalive)\n"); |
TASS Belgium NV |
131:4758606c9316 | 2344 | pico_timer_add(t->rto << (++t->backoff), tcp_send_keepalive, t); |
TASS Belgium NV |
131:4758606c9316 | 2345 | } |
TASS Belgium NV |
131:4758606c9316 | 2346 | } |
daniele | 29:1a47b7151851 | 2347 | } |
daniele | 29:1a47b7151851 | 2348 | |
tass | 76:938a140caf12 | 2349 | inline static int checkLocalClosing(struct pico_socket *s); |
tass | 76:938a140caf12 | 2350 | inline static int checkRemoteClosing(struct pico_socket *s); |
tass | 76:938a140caf12 | 2351 | |
tass | 48:40fc4462265c | 2352 | |
daniele | 29:1a47b7151851 | 2353 | int pico_tcp_output(struct pico_socket *s, int loop_score) |
daniele | 29:1a47b7151851 | 2354 | { |
TASS Belgium NV |
131:4758606c9316 | 2355 | struct pico_socket_tcp *t = (struct pico_socket_tcp *)s; |
TASS Belgium NV |
131:4758606c9316 | 2356 | struct pico_frame *f, *una; |
TASS Belgium NV |
131:4758606c9316 | 2357 | int sent = 0; |
TASS Belgium NV |
131:4758606c9316 | 2358 | |
TASS Belgium NV |
131:4758606c9316 | 2359 | una = first_segment(&t->tcpq_out); |
TASS Belgium NV |
131:4758606c9316 | 2360 | f = peek_segment(&t->tcpq_out, t->snd_nxt); |
TASS Belgium NV |
131:4758606c9316 | 2361 | |
TASS Belgium NV |
131:4758606c9316 | 2362 | while((f) && (t->cwnd >= t->in_flight)) { |
TASS Belgium NV |
131:4758606c9316 | 2363 | f->timestamp = pico_tick; |
TASS Belgium NV |
131:4758606c9316 | 2364 | tcp_add_options_frame(t, f); |
TASS Belgium NV |
131:4758606c9316 | 2365 | if (seq_compare((SEQN(f) + f->payload_len), (SEQN(una) + (uint32_t)(t->recv_wnd << t->recv_wnd_scale))) > 0) { |
TASS Belgium NV |
131:4758606c9316 | 2366 | t->cwnd = (uint16_t)t->in_flight; |
TASS Belgium NV |
131:4758606c9316 | 2367 | if (t->cwnd < 1) |
TASS Belgium NV |
131:4758606c9316 | 2368 | t->cwnd = 1; |
TASS Belgium NV |
131:4758606c9316 | 2369 | |
TASS Belgium NV |
131:4758606c9316 | 2370 | if (t->x_mode != PICO_TCP_WINDOW_FULL) { |
TASS Belgium NV |
131:4758606c9316 | 2371 | tcp_dbg("TCP> RIGHT SIZING (rwnd: %d, frame len: %d\n", t->recv_wnd << t->recv_wnd_scale, f->payload_len); |
TASS Belgium NV |
131:4758606c9316 | 2372 | tcp_dbg("In window full...\n"); |
TASS Belgium NV |
131:4758606c9316 | 2373 | t->snd_nxt = SEQN(una); /* XXX prevent out-of-order-packets ! */ /*DLA re-enabled.*/ |
TASS Belgium NV |
131:4758606c9316 | 2374 | t->snd_retry = SEQN(una); /* XXX replace by retry pointer? */ |
TASS Belgium NV |
131:4758606c9316 | 2375 | |
TASS Belgium NV |
131:4758606c9316 | 2376 | /* Alternative to the line above: (better performance, but seems to lock anyway with larger buffers) |
TASS Belgium NV |
131:4758606c9316 | 2377 | if (seq_compare(t->snd_nxt, SEQN(una)) > 0) |
TASS Belgium NV |
131:4758606c9316 | 2378 | t->snd_nxt -= f->payload_len; |
TASS Belgium NV |
131:4758606c9316 | 2379 | */ |
TASS Belgium NV |
131:4758606c9316 | 2380 | |
TASS Belgium NV |
131:4758606c9316 | 2381 | t->x_mode = PICO_TCP_WINDOW_FULL; |
TASS Belgium NV |
131:4758606c9316 | 2382 | if (t->keepalive_timer_running == 0) { |
TASS Belgium NV |
131:4758606c9316 | 2383 | tcp_dbg("[Window full] Adding timer(send keepalive)\n"); |
TASS Belgium NV |
131:4758606c9316 | 2384 | tcp_send_keepalive(0, t); |
TASS Belgium NV |
131:4758606c9316 | 2385 | } |
TASS Belgium NV |
131:4758606c9316 | 2386 | } |
TASS Belgium NV |
131:4758606c9316 | 2387 | |
TASS Belgium NV |
131:4758606c9316 | 2388 | break; |
daniele | 29:1a47b7151851 | 2389 | } |
TASS Belgium NV |
131:4758606c9316 | 2390 | |
TASS Belgium NV |
131:4758606c9316 | 2391 | tcp_dbg("TCP> DEQUEUED (for output) frame %08x, acks %08x len= %d, remaining frames %d\n", SEQN(f), ACKN(f), f->payload_len, t->tcpq_out.frames); |
TASS Belgium NV |
131:4758606c9316 | 2392 | tcp_send(t, f); |
TASS Belgium NV |
131:4758606c9316 | 2393 | sent++; |
TASS Belgium NV |
131:4758606c9316 | 2394 | loop_score--; |
TASS Belgium NV |
131:4758606c9316 | 2395 | t->snd_last_out = SEQN(f); |
TASS Belgium NV |
131:4758606c9316 | 2396 | if (loop_score < 1) |
TASS Belgium NV |
131:4758606c9316 | 2397 | break; |
TASS Belgium NV |
131:4758606c9316 | 2398 | |
TASS Belgium NV |
131:4758606c9316 | 2399 | if (f->payload_len > 0) { |
TASS Belgium NV |
131:4758606c9316 | 2400 | f = next_segment(&t->tcpq_out, f); |
TASS Belgium NV |
131:4758606c9316 | 2401 | } else { |
TASS Belgium NV |
131:4758606c9316 | 2402 | f = NULL; |
TASS Belgium NV |
131:4758606c9316 | 2403 | } |
daniele | 29:1a47b7151851 | 2404 | } |
TASS Belgium NV |
131:4758606c9316 | 2405 | if (sent > 0) { |
TASS Belgium NV |
131:4758606c9316 | 2406 | if (t->rto < PICO_TCP_RTO_MIN) |
TASS Belgium NV |
131:4758606c9316 | 2407 | t->rto = PICO_TCP_RTO_MIN; |
TASS Belgium NV |
131:4758606c9316 | 2408 | |
TASS Belgium NV |
131:4758606c9316 | 2409 | /* if (s->wakeup) */ |
TASS Belgium NV |
131:4758606c9316 | 2410 | /* t->sock.wakeup(PICO_SOCK_EV_WR, &t->sock); */ |
TASS Belgium NV |
131:4758606c9316 | 2411 | add_retransmission_timer(t, pico_tick + t->rto); |
TASS Belgium NV |
131:4758606c9316 | 2412 | } else { |
TASS Belgium NV |
131:4758606c9316 | 2413 | /* Nothing to transmit. */ |
TASS Belgium NV |
131:4758606c9316 | 2414 | } |
TASS Belgium NV |
131:4758606c9316 | 2415 | |
TASS Belgium NV |
131:4758606c9316 | 2416 | if ((t->tcpq_out.frames == 0) && (s->state & PICO_SOCKET_STATE_SHUT_LOCAL)) { /* if no more packets in queue, XXX replacled !f by tcpq check */ |
TASS Belgium NV |
131:4758606c9316 | 2417 | if(!checkLocalClosing(&t->sock)) /* check if local closing started and send fin */ |
TASS Belgium NV |
131:4758606c9316 | 2418 | { |
TASS Belgium NV |
131:4758606c9316 | 2419 | checkRemoteClosing(&t->sock); /* check if remote closing started and send fin */ |
TASS Belgium NV |
131:4758606c9316 | 2420 | } |
TASS Belgium NV |
131:4758606c9316 | 2421 | } |
TASS Belgium NV |
131:4758606c9316 | 2422 | |
TASS Belgium NV |
131:4758606c9316 | 2423 | return loop_score; |
daniele | 29:1a47b7151851 | 2424 | } |
daniele | 29:1a47b7151851 | 2425 | |
daniele | 29:1a47b7151851 | 2426 | /* function to make new segment from hold queue with specific size (mss) */ |
TASS Belgium NV |
131:4758606c9316 | 2427 | static struct pico_frame *pico_hold_segment_make(struct pico_socket_tcp *t) |
daniele | 29:1a47b7151851 | 2428 | { |
TASS Belgium NV |
131:4758606c9316 | 2429 | struct pico_frame *f_temp, *f_new; |
TASS Belgium NV |
131:4758606c9316 | 2430 | struct pico_socket *s = (struct pico_socket *) &t->sock; |
TASS Belgium NV |
131:4758606c9316 | 2431 | struct pico_tcp_hdr *hdr; |
TASS Belgium NV |
131:4758606c9316 | 2432 | uint16_t total_len = 0, total_payload_len = 0; |
TASS Belgium NV |
131:4758606c9316 | 2433 | uint16_t off = 0, test = 0; |
TASS Belgium NV |
131:4758606c9316 | 2434 | |
TASS Belgium NV |
131:4758606c9316 | 2435 | off = pico_tcp_overhead(s); |
TASS Belgium NV |
131:4758606c9316 | 2436 | |
TASS Belgium NV |
131:4758606c9316 | 2437 | /* init with first frame in hold queue */ |
TASS Belgium NV |
131:4758606c9316 | 2438 | f_temp = first_segment(&t->tcpq_hold); |
TASS Belgium NV |
131:4758606c9316 | 2439 | total_len = f_temp->payload_len; |
daniele | 29:1a47b7151851 | 2440 | f_temp = next_segment(&t->tcpq_hold, f_temp); |
TASS Belgium NV |
131:4758606c9316 | 2441 | |
TASS Belgium NV |
131:4758606c9316 | 2442 | /* check till total_len <= MSS */ |
TASS Belgium NV |
131:4758606c9316 | 2443 | while ((f_temp != NULL) && ((total_len + f_temp->payload_len) <= PICO_TCP_DEFAULT_MSS)) { |
TASS Belgium NV |
131:4758606c9316 | 2444 | total_len = (uint16_t)(total_len + f_temp->payload_len); |
TASS Belgium NV |
131:4758606c9316 | 2445 | f_temp = next_segment(&t->tcpq_hold, f_temp); |
TASS Belgium NV |
131:4758606c9316 | 2446 | if (f_temp == NULL) |
TASS Belgium NV |
131:4758606c9316 | 2447 | break; |
TASS Belgium NV |
131:4758606c9316 | 2448 | } |
TASS Belgium NV |
131:4758606c9316 | 2449 | /* alloc new frame with payload size = off + total_len */ |
TASS Belgium NV |
131:4758606c9316 | 2450 | f_new = pico_socket_frame_alloc(s, (uint16_t)(off + total_len)); |
TASS Belgium NV |
131:4758606c9316 | 2451 | if (!f_new) { |
TASS Belgium NV |
131:4758606c9316 | 2452 | pico_err = PICO_ERR_ENOMEM; |
TASS Belgium NV |
131:4758606c9316 | 2453 | return f_new; |
TASS Belgium NV |
131:4758606c9316 | 2454 | } |
TASS Belgium NV |
131:4758606c9316 | 2455 | |
TASS Belgium NV |
131:4758606c9316 | 2456 | hdr = (struct pico_tcp_hdr *) f_new->transport_hdr; |
TASS Belgium NV |
131:4758606c9316 | 2457 | /* init new frame */ |
TASS Belgium NV |
131:4758606c9316 | 2458 | f_new->payload += off; |
TASS Belgium NV |
131:4758606c9316 | 2459 | f_new->payload_len = (uint16_t)(f_new->payload_len - off); |
TASS Belgium NV |
131:4758606c9316 | 2460 | f_new->sock = s; |
TASS Belgium NV |
131:4758606c9316 | 2461 | |
TASS Belgium NV |
131:4758606c9316 | 2462 | f_temp = first_segment(&t->tcpq_hold); |
TASS Belgium NV |
131:4758606c9316 | 2463 | hdr->seq = ((struct pico_tcp_hdr *)(f_temp->transport_hdr))->seq; /* get sequence number of first frame */ |
TASS Belgium NV |
131:4758606c9316 | 2464 | hdr->trans.sport = t->sock.local_port; |
TASS Belgium NV |
131:4758606c9316 | 2465 | hdr->trans.dport = t->sock.remote_port; |
TASS Belgium NV |
131:4758606c9316 | 2466 | |
TASS Belgium NV |
131:4758606c9316 | 2467 | /* check till total_payload_len <= MSS */ |
TASS Belgium NV |
131:4758606c9316 | 2468 | while ((f_temp != NULL) && ((total_payload_len + f_temp->payload_len) <= PICO_TCP_DEFAULT_MSS)) { |
TASS Belgium NV |
131:4758606c9316 | 2469 | /* cpy data and discard frame */ |
TASS Belgium NV |
131:4758606c9316 | 2470 | test++; |
TASS Belgium NV |
131:4758606c9316 | 2471 | memcpy(f_new->payload + total_payload_len, f_temp->payload, f_temp->payload_len); |
TASS Belgium NV |
131:4758606c9316 | 2472 | total_payload_len = (uint16_t)(total_payload_len + f_temp->payload_len); |
TASS Belgium NV |
131:4758606c9316 | 2473 | pico_discard_segment(&t->tcpq_hold, f_temp); |
TASS Belgium NV |
131:4758606c9316 | 2474 | f_temp = first_segment(&t->tcpq_hold); |
TASS Belgium NV |
131:4758606c9316 | 2475 | } |
TASS Belgium NV |
131:4758606c9316 | 2476 | hdr->len = (uint8_t)((f_new->payload - f_new->transport_hdr) << 2 | t->jumbo); |
TASS Belgium NV |
131:4758606c9316 | 2477 | |
TASS Belgium NV |
131:4758606c9316 | 2478 | tcp_dbg_nagle("NAGLE make - joined %d segments, len %d bytes\n", test, total_payload_len); |
TASS Belgium NV |
131:4758606c9316 | 2479 | |
daniele | 29:1a47b7151851 | 2480 | return f_new; |
daniele | 29:1a47b7151851 | 2481 | } |
daniele | 29:1a47b7151851 | 2482 | |
daniele | 29:1a47b7151851 | 2483 | /* original behavior kept when Nagle disabled; |
daniele | 29:1a47b7151851 | 2484 | Nagle algorithm added here, keeping hold frame queue instead of eg linked list of data */ |
tass | 70:cd218dd180e5 | 2485 | int32_t pico_tcp_push(struct pico_protocol *self, struct pico_frame *f) |
daniele | 29:1a47b7151851 | 2486 | { |
TASS Belgium NV |
131:4758606c9316 | 2487 | struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *)f->transport_hdr; |
TASS Belgium NV |
131:4758606c9316 | 2488 | struct pico_socket_tcp *t = (struct pico_socket_tcp *) f->sock; |
TASS Belgium NV |
131:4758606c9316 | 2489 | struct pico_frame *f_new; |
TASS Belgium NV |
131:4758606c9316 | 2490 | uint32_t total_len = 0; |
TASS Belgium NV |
131:4758606c9316 | 2491 | IGNORE_PARAMETER(self); |
TASS Belgium NV |
131:4758606c9316 | 2492 | pico_err = PICO_ERR_NOERR; |
TASS Belgium NV |
131:4758606c9316 | 2493 | hdr->trans.sport = t->sock.local_port; |
TASS Belgium NV |
131:4758606c9316 | 2494 | hdr->trans.dport = t->sock.remote_port; |
TASS Belgium NV |
131:4758606c9316 | 2495 | hdr->seq = long_be(t->snd_last + 1); |
TASS Belgium NV |
131:4758606c9316 | 2496 | hdr->len = (uint8_t)((f->payload - f->transport_hdr) << 2 | t->jumbo); |
TASS Belgium NV |
131:4758606c9316 | 2497 | |
TASS Belgium NV |
131:4758606c9316 | 2498 | if ((uint32_t)f->payload_len > (uint32_t)(t->tcpq_out.max_size - t->tcpq_out.size)) |
TASS Belgium NV |
131:4758606c9316 | 2499 | t->sock.ev_pending &= (uint16_t)(~PICO_SOCK_EV_WR); |
TASS Belgium NV |
131:4758606c9316 | 2500 | |
TASS Belgium NV |
131:4758606c9316 | 2501 | /***************************************************************************/ |
TASS Belgium NV |
131:4758606c9316 | 2502 | |
TASS Belgium NV |
131:4758606c9316 | 2503 | if (!IS_NAGLE_ENABLED((&(t->sock)))) { |
TASS Belgium NV |
131:4758606c9316 | 2504 | /* TCP_NODELAY enabled, original behavior */ |
TASS Belgium NV |
131:4758606c9316 | 2505 | if (pico_enqueue_segment(&t->tcpq_out, f) > 0) { |
TASS Belgium NV |
131:4758606c9316 | 2506 | tcp_dbg_nagle("TCP_PUSH - NO NAGLE - Pushing segment %08x, len %08x to socket %p\n", t->snd_last + 1, f->payload_len, t); |
TASS Belgium NV |
131:4758606c9316 | 2507 | t->snd_last += f->payload_len; |
TASS Belgium NV |
131:4758606c9316 | 2508 | return f->payload_len; |
daniele | 29:1a47b7151851 | 2509 | } else { |
TASS Belgium NV |
131:4758606c9316 | 2510 | tcp_dbg("Enqueue failed.\n"); |
TASS Belgium NV |
131:4758606c9316 | 2511 | return 0; |
daniele | 29:1a47b7151851 | 2512 | } |
daniele | 29:1a47b7151851 | 2513 | } |
TASS Belgium NV |
131:4758606c9316 | 2514 | /***************************************************************************/ |
TASS Belgium NV |
131:4758606c9316 | 2515 | else { |
TASS Belgium NV |
131:4758606c9316 | 2516 | /* Nagle's algorithm enabled, check if ready to send, or put frame in hold queue */ |
TASS Belgium NV |
131:4758606c9316 | 2517 | if (IS_TCP_IDLE(t) && IS_TCP_HOLDQ_EMPTY(t)) { /* opt 1. send frame */ |
TASS Belgium NV |
131:4758606c9316 | 2518 | if (pico_enqueue_segment(&t->tcpq_out, f) > 0) { |
TASS Belgium NV |
131:4758606c9316 | 2519 | tcp_dbg_nagle("TCP_PUSH - NAGLE - Pushing segment %08x, len %08x to socket %p\n", t->snd_last + 1, f->payload_len, t); |
TASS Belgium NV |
131:4758606c9316 | 2520 | t->snd_last += f->payload_len; |
TASS Belgium NV |
131:4758606c9316 | 2521 | return f->payload_len; |
TASS Belgium NV |
131:4758606c9316 | 2522 | } else { |
TASS Belgium NV |
131:4758606c9316 | 2523 | tcp_dbg("Enqueue failed.\n"); |
TASS Belgium NV |
131:4758606c9316 | 2524 | return 0; |
TASS Belgium NV |
131:4758606c9316 | 2525 | } |
TASS Belgium NV |
131:4758606c9316 | 2526 | } else { /* opt 2. hold data back */ |
TASS Belgium NV |
131:4758606c9316 | 2527 | total_len = f->payload_len + t->tcpq_hold.size; |
TASS Belgium NV |
131:4758606c9316 | 2528 | if ((total_len >= PICO_TCP_DEFAULT_MSS) && ((t->tcpq_out.max_size - t->tcpq_out.size) >= PICO_TCP_DEFAULT_MSS)) { /* TODO check mss socket */ |
TASS Belgium NV |
131:4758606c9316 | 2529 | /* IF enough data in hold (>mss) AND space in out queue (>mss) */ |
TASS Belgium NV |
131:4758606c9316 | 2530 | /* add current frame in hold and make new segment */ |
TASS Belgium NV |
131:4758606c9316 | 2531 | if (pico_enqueue_segment(&t->tcpq_hold, f) > 0 ) { |
TASS Belgium NV |
131:4758606c9316 | 2532 | tcp_dbg_nagle("TCP_PUSH - NAGLE - Pushed into hold, make new (enqueued frames out %d)\n", t->tcpq_out.frames); |
TASS Belgium NV |
131:4758606c9316 | 2533 | t->snd_last += f->payload_len; /* XXX WATCH OUT */ |
TASS Belgium NV |
131:4758606c9316 | 2534 | f_new = pico_hold_segment_make(t); |
TASS Belgium NV |
131:4758606c9316 | 2535 | } else { |
TASS Belgium NV |
131:4758606c9316 | 2536 | tcp_dbg_nagle("TCP_PUSH - NAGLE - enqueue hold failed 1\n"); |
TASS Belgium NV |
131:4758606c9316 | 2537 | return 0; |
TASS Belgium NV |
131:4758606c9316 | 2538 | } |
TASS Belgium NV |
131:4758606c9316 | 2539 | |
TASS Belgium NV |
131:4758606c9316 | 2540 | /* and put new frame in out queue */ |
TASS Belgium NV |
131:4758606c9316 | 2541 | if ((f_new != NULL) && (pico_enqueue_segment(&t->tcpq_out, f_new) > 0)) { |
TASS Belgium NV |
131:4758606c9316 | 2542 | return f_new->payload_len; |
TASS Belgium NV |
131:4758606c9316 | 2543 | } else { |
TASS Belgium NV |
131:4758606c9316 | 2544 | tcp_dbg_nagle("TCP_PUSH - NAGLE - enqueue out failed, f_new = %p\n", f_new); |
TASS Belgium NV |
131:4758606c9316 | 2545 | return -1; /* XXX something seriously wrong */ |
TASS Belgium NV |
131:4758606c9316 | 2546 | } |
TASS Belgium NV |
131:4758606c9316 | 2547 | } else { |
TASS Belgium NV |
131:4758606c9316 | 2548 | /* ELSE put frame in hold queue */ |
TASS Belgium NV |
131:4758606c9316 | 2549 | if (pico_enqueue_segment(&t->tcpq_hold, f) > 0) { |
TASS Belgium NV |
131:4758606c9316 | 2550 | tcp_dbg_nagle("TCP_PUSH - NAGLE - Pushed into hold (enqueued frames out %d)\n", t->tcpq_out.frames); |
TASS Belgium NV |
131:4758606c9316 | 2551 | t->snd_last += f->payload_len; /* XXX WATCH OUT */ |
TASS Belgium NV |
131:4758606c9316 | 2552 | return f->payload_len; |
TASS Belgium NV |
131:4758606c9316 | 2553 | } else { |
TASS Belgium NV |
131:4758606c9316 | 2554 | pico_err = PICO_ERR_EAGAIN; |
TASS Belgium NV |
131:4758606c9316 | 2555 | tcp_dbg_nagle("TCP_PUSH - NAGLE - enqueue hold failed 2\n"); |
TASS Belgium NV |
131:4758606c9316 | 2556 | return 0; |
TASS Belgium NV |
131:4758606c9316 | 2557 | } |
TASS Belgium NV |
131:4758606c9316 | 2558 | } |
TASS Belgium NV |
131:4758606c9316 | 2559 | } |
TASS Belgium NV |
131:4758606c9316 | 2560 | } |
TASS Belgium NV |
131:4758606c9316 | 2561 | |
TASS Belgium NV |
131:4758606c9316 | 2562 | /***************************************************************************/ |
daniele | 29:1a47b7151851 | 2563 | } |
tass | 68:0847e35d08a6 | 2564 | |
tass | 68:0847e35d08a6 | 2565 | inline static void tcp_discard_all_segments(struct pico_tcp_queue *tq) |
tass | 68:0847e35d08a6 | 2566 | { |
TASS Belgium NV |
131:4758606c9316 | 2567 | struct pico_tree_node *index = NULL, *index_safe = NULL; |
TASS Belgium NV |
131:4758606c9316 | 2568 | LOCK(Mutex); |
TASS Belgium NV |
131:4758606c9316 | 2569 | pico_tree_foreach_safe(index, &tq->pool, index_safe) |
TASS Belgium NV |
131:4758606c9316 | 2570 | { |
TASS Belgium NV |
131:4758606c9316 | 2571 | void *f = index->keyValue; |
TASS Belgium NV |
131:4758606c9316 | 2572 | if(!f) |
TASS Belgium NV |
131:4758606c9316 | 2573 | break; |
TASS Belgium NV |
131:4758606c9316 | 2574 | |
TASS Belgium NV |
131:4758606c9316 | 2575 | pico_tree_delete(&tq->pool, f); |
TASS Belgium NV |
131:4758606c9316 | 2576 | if(IS_INPUT_QUEUE(tq)) |
TASS Belgium NV |
131:4758606c9316 | 2577 | { |
TASS Belgium NV |
131:4758606c9316 | 2578 | struct tcp_input_segment *inp = (struct tcp_input_segment *)f; |
TASS Belgium NV |
131:4758606c9316 | 2579 | pico_free(inp->payload); |
TASS Belgium NV |
131:4758606c9316 | 2580 | pico_free(inp); |
TASS Belgium NV |
131:4758606c9316 | 2581 | } |
TASS Belgium NV |
131:4758606c9316 | 2582 | else |
TASS Belgium NV |
131:4758606c9316 | 2583 | pico_frame_discard(f); |
TASS Belgium NV |
131:4758606c9316 | 2584 | } |
TASS Belgium NV |
131:4758606c9316 | 2585 | tq->frames = 0; |
TASS Belgium NV |
131:4758606c9316 | 2586 | tq->size = 0; |
TASS Belgium NV |
131:4758606c9316 | 2587 | UNLOCK(Mutex); |
tass | 68:0847e35d08a6 | 2588 | } |
tass | 68:0847e35d08a6 | 2589 | |
tass | 68:0847e35d08a6 | 2590 | void pico_tcp_cleanup_queues(struct pico_socket *sck) |
tass | 68:0847e35d08a6 | 2591 | { |
TASS Belgium NV |
131:4758606c9316 | 2592 | struct pico_socket_tcp *tcp = (struct pico_socket_tcp *)sck; |
TASS Belgium NV |
131:4758606c9316 | 2593 | if(tcp->retrans_tmr) |
TASS Belgium NV |
131:4758606c9316 | 2594 | pico_timer_cancel(tcp->retrans_tmr); |
TASS Belgium NV |
131:4758606c9316 | 2595 | |
TASS Belgium NV |
131:4758606c9316 | 2596 | tcp_discard_all_segments(&tcp->tcpq_in); |
TASS Belgium NV |
131:4758606c9316 | 2597 | tcp_discard_all_segments(&tcp->tcpq_out); |
TASS Belgium NV |
131:4758606c9316 | 2598 | tcp_discard_all_segments(&tcp->tcpq_hold); |
tass | 68:0847e35d08a6 | 2599 | } |
tass | 68:0847e35d08a6 | 2600 | |
tass | 76:938a140caf12 | 2601 | static int checkLocalClosing(struct pico_socket *s) |
tass | 76:938a140caf12 | 2602 | { |
TASS Belgium NV |
131:4758606c9316 | 2603 | struct pico_socket_tcp *t = (struct pico_socket_tcp *)s; |
TASS Belgium NV |
131:4758606c9316 | 2604 | if ((s->state & PICO_SOCKET_STATE_TCP) == PICO_SOCKET_STATE_TCP_ESTABLISHED) { |
TASS Belgium NV |
131:4758606c9316 | 2605 | tcp_dbg("TCP> buffer empty, shutdown established ...\n"); |
TASS Belgium NV |
131:4758606c9316 | 2606 | /* send fin if queue empty and in state shut local (write) */ |
TASS Belgium NV |
131:4758606c9316 | 2607 | tcp_send_fin(t); |
TASS Belgium NV |
131:4758606c9316 | 2608 | /* change tcp state to FIN_WAIT1 */ |
TASS Belgium NV |
131:4758606c9316 | 2609 | s->state &= 0x00FFU; |
TASS Belgium NV |
131:4758606c9316 | 2610 | s->state |= PICO_SOCKET_STATE_TCP_FIN_WAIT1; |
TASS Belgium NV |
131:4758606c9316 | 2611 | return 1; |
TASS Belgium NV |
131:4758606c9316 | 2612 | } |
TASS Belgium NV |
131:4758606c9316 | 2613 | |
TASS Belgium NV |
131:4758606c9316 | 2614 | return 0; |
tass | 76:938a140caf12 | 2615 | } |
tass | 76:938a140caf12 | 2616 | |
tass | 76:938a140caf12 | 2617 | static int checkRemoteClosing(struct pico_socket *s) |
tass | 76:938a140caf12 | 2618 | { |
TASS Belgium NV |
131:4758606c9316 | 2619 | struct pico_socket_tcp *t = (struct pico_socket_tcp *)s; |
TASS Belgium NV |
131:4758606c9316 | 2620 | if ((s->state & PICO_SOCKET_STATE_TCP) == PICO_SOCKET_STATE_TCP_CLOSE_WAIT) { |
TASS Belgium NV |
131:4758606c9316 | 2621 | /* send fin if queue empty and in state shut local (write) */ |
TASS Belgium NV |
131:4758606c9316 | 2622 | tcp_send_fin(t); |
TASS Belgium NV |
131:4758606c9316 | 2623 | /* change tcp state to LAST_ACK */ |
TASS Belgium NV |
131:4758606c9316 | 2624 | s->state &= 0x00FFU; |
TASS Belgium NV |
131:4758606c9316 | 2625 | s->state |= PICO_SOCKET_STATE_TCP_LAST_ACK; |
TASS Belgium NV |
131:4758606c9316 | 2626 | tcp_dbg("TCP> STATE: LAST_ACK.\n"); |
TASS Belgium NV |
131:4758606c9316 | 2627 | return 1; |
tass | 76:938a140caf12 | 2628 | } |
TASS Belgium NV |
131:4758606c9316 | 2629 | |
TASS Belgium NV |
131:4758606c9316 | 2630 | return 0; |
tass | 76:938a140caf12 | 2631 | } |
tass | 76:938a140caf12 | 2632 | |
tass | 76:938a140caf12 | 2633 | void pico_tcp_notify_closing(struct pico_socket *sck) |
tass | 76:938a140caf12 | 2634 | { |
TASS Belgium NV |
131:4758606c9316 | 2635 | struct pico_socket_tcp *t = (struct pico_socket_tcp *)sck; |
TASS Belgium NV |
131:4758606c9316 | 2636 | if(t->tcpq_out.frames == 0) |
TASS Belgium NV |
131:4758606c9316 | 2637 | { |
TASS Belgium NV |
131:4758606c9316 | 2638 | /* canceling retrans timer when closing */ |
TASS Belgium NV |
131:4758606c9316 | 2639 | if(t->retrans_tmr) |
TASS Belgium NV |
131:4758606c9316 | 2640 | { |
TASS Belgium NV |
131:4758606c9316 | 2641 | pico_timer_cancel(t->retrans_tmr); |
TASS Belgium NV |
131:4758606c9316 | 2642 | t->retrans_tmr = NULL; |
TASS Belgium NV |
131:4758606c9316 | 2643 | } |
TASS Belgium NV |
131:4758606c9316 | 2644 | |
TASS Belgium NV |
131:4758606c9316 | 2645 | if(!checkLocalClosing(sck)) |
TASS Belgium NV |
131:4758606c9316 | 2646 | checkRemoteClosing(sck); |
TASS Belgium NV |
131:4758606c9316 | 2647 | } |
tass | 76:938a140caf12 | 2648 | } |
tass | 76:938a140caf12 | 2649 | |
TASS Belgium NV |
131:4758606c9316 | 2650 | void transport_flags_update(struct pico_frame *f, struct pico_socket *s) |
TASS Belgium NV |
131:4758606c9316 | 2651 | { |
TASS Belgium NV |
131:4758606c9316 | 2652 | f->transport_flags_saved = ((struct pico_socket_tcp *)s)->ts_ok; |
TASS Belgium NV |
131:4758606c9316 | 2653 | } |
TASS Belgium NV |
131:4758606c9316 | 2654 | #endif /* PICO_SUPPORT_TCP */ |