Free (GPLv2) TCP/IP stack developed by TASS Belgium

Fork of PicoTCP by Daniele Lacamera

Committer:
daniele
Date:
Fri May 24 15:25:25 2013 +0000
Revision:
3:b4047e8a0123
Updated from main repo + fixed Mutexes;

Who changed what in which revision?

UserRevisionLine numberNew contents of line
daniele 3:b4047e8a0123 1 /*********************************************************************
daniele 3:b4047e8a0123 2 PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved.
daniele 3:b4047e8a0123 3 See LICENSE and COPYING for usage.
daniele 3:b4047e8a0123 4
daniele 3:b4047e8a0123 5 .
daniele 3:b4047e8a0123 6
daniele 3:b4047e8a0123 7 Authors: Daniele Lacamera, Philippe Mariman
daniele 3:b4047e8a0123 8 *********************************************************************/
daniele 3:b4047e8a0123 9
daniele 3:b4047e8a0123 10 #include "pico_tcp.h"
daniele 3:b4047e8a0123 11 #include "pico_config.h"
daniele 3:b4047e8a0123 12 #include "pico_eth.h"
daniele 3:b4047e8a0123 13 #include "pico_socket.h"
daniele 3:b4047e8a0123 14 #include "pico_stack.h"
daniele 3:b4047e8a0123 15 #include "pico_socket.h"
daniele 3:b4047e8a0123 16 #include "pico_queue.h"
daniele 3:b4047e8a0123 17 #include "pico_tree.h"
daniele 3:b4047e8a0123 18
daniele 3:b4047e8a0123 19 #define TCP_SOCK(s) ((struct pico_socket_tcp *)s)
daniele 3:b4047e8a0123 20 #define SEQN(f) (f?(long_be(((struct pico_tcp_hdr *)(f->transport_hdr))->seq)):0)
daniele 3:b4047e8a0123 21 #define ACKN(f) (f?(long_be(((struct pico_tcp_hdr *)(f->transport_hdr))->ack)):0)
daniele 3:b4047e8a0123 22
daniele 3:b4047e8a0123 23 #define PICO_TCP_RTO_MIN 1000
daniele 3:b4047e8a0123 24 #define PICO_TCP_RTO_MAX 120000
daniele 3:b4047e8a0123 25 #define PICO_TCP_IW 2
daniele 3:b4047e8a0123 26
daniele 3:b4047e8a0123 27 #define PICO_TCP_MAX_CONNECT_RETRIES 7
daniele 3:b4047e8a0123 28
daniele 3:b4047e8a0123 29 #define PICO_TCP_LOOKAHEAD 0x00
daniele 3:b4047e8a0123 30 #define PICO_TCP_FIRST_DUPACK 0x01
daniele 3:b4047e8a0123 31 #define PICO_TCP_SECOND_DUPACK 0x02
daniele 3:b4047e8a0123 32 #define PICO_TCP_RECOVER 0x03
daniele 3:b4047e8a0123 33 #define PICO_TCP_BLACKOUT 0x04
daniele 3:b4047e8a0123 34 #define PICO_TCP_UNREACHABLE 0x05
daniele 3:b4047e8a0123 35 #define PICO_TCP_WINDOW_FULL 0x06
daniele 3:b4047e8a0123 36
daniele 3:b4047e8a0123 37 /* check if the Nagle algorithm is enabled on the socket */
daniele 3:b4047e8a0123 38 #define IS_NAGLE_ENABLED(s) (!(!(!(s->opt_flags & (1 << PICO_SOCKET_OPT_TCPNODELAY)))))
daniele 3:b4047e8a0123 39 /* check if tcp connection is "idle" according to Nagle (RFC 896) */
daniele 3:b4047e8a0123 40 #define IS_TCP_IDLE(t) ((t->in_flight == 0) && (t->tcpq_out.size == 0))
daniele 3:b4047e8a0123 41 /* check if the hold queue contains data (again Nagle) */
daniele 3:b4047e8a0123 42 #define IS_TCP_HOLDQ_EMPTY(t) (t->tcpq_hold.size == 0)
daniele 3:b4047e8a0123 43
daniele 3:b4047e8a0123 44 #ifdef PICO_SUPPORT_TCP
daniele 3:b4047e8a0123 45 #define tcp_dbg(...) do{}while(0)
daniele 3:b4047e8a0123 46 //#define tcp_dbg dbg
daniele 3:b4047e8a0123 47
daniele 3:b4047e8a0123 48 static inline int seq_compare(uint32_t a, uint32_t b)
daniele 3:b4047e8a0123 49 {
daniele 3:b4047e8a0123 50 uint32_t thresh = ((uint32_t)(-1))>>1;
daniele 3:b4047e8a0123 51 if (((a > thresh) && (b > thresh)) || ((a <= thresh) && (b <= thresh))) {
daniele 3:b4047e8a0123 52 if (a > b)
daniele 3:b4047e8a0123 53 return 1;
daniele 3:b4047e8a0123 54 if (b > a)
daniele 3:b4047e8a0123 55 return -1;
daniele 3:b4047e8a0123 56 } else {
daniele 3:b4047e8a0123 57 if (a > b)
daniele 3:b4047e8a0123 58 return -2;
daniele 3:b4047e8a0123 59 if (b > a)
daniele 3:b4047e8a0123 60 return 2;
daniele 3:b4047e8a0123 61 }
daniele 3:b4047e8a0123 62 return 0;
daniele 3:b4047e8a0123 63 }
daniele 3:b4047e8a0123 64
daniele 3:b4047e8a0123 65 static int segment_compare(void * ka, void * kb)
daniele 3:b4047e8a0123 66 {
daniele 3:b4047e8a0123 67 struct pico_frame *a = ka, *b = kb;
daniele 3:b4047e8a0123 68 return seq_compare(SEQN(a), SEQN(b));
daniele 3:b4047e8a0123 69 }
daniele 3:b4047e8a0123 70
daniele 3:b4047e8a0123 71 struct pico_tcp_queue
daniele 3:b4047e8a0123 72 {
daniele 3:b4047e8a0123 73 struct pico_tree pool;
daniele 3:b4047e8a0123 74 uint32_t max_size;
daniele 3:b4047e8a0123 75 uint32_t size;
daniele 3:b4047e8a0123 76 uint32_t frames;
daniele 3:b4047e8a0123 77 };
daniele 3:b4047e8a0123 78
daniele 3:b4047e8a0123 79 static struct pico_frame *peek_segment(struct pico_tcp_queue *tq, uint32_t seq)
daniele 3:b4047e8a0123 80 {
daniele 3:b4047e8a0123 81 struct pico_tcp_hdr H;
daniele 3:b4047e8a0123 82 struct pico_frame f = {};
daniele 3:b4047e8a0123 83 f.transport_hdr = (uint8_t *) (&H);
daniele 3:b4047e8a0123 84 H.seq = long_be(seq);
daniele 3:b4047e8a0123 85
daniele 3:b4047e8a0123 86 return pico_tree_findKey(&tq->pool,&f);
daniele 3:b4047e8a0123 87 }
daniele 3:b4047e8a0123 88
daniele 3:b4047e8a0123 89 static struct pico_frame *first_segment(struct pico_tcp_queue *tq)
daniele 3:b4047e8a0123 90 {
daniele 3:b4047e8a0123 91 return pico_tree_first(&tq->pool);
daniele 3:b4047e8a0123 92 }
daniele 3:b4047e8a0123 93
daniele 3:b4047e8a0123 94 static struct pico_frame *next_segment(struct pico_tcp_queue *tq, struct pico_frame *cur)
daniele 3:b4047e8a0123 95 {
daniele 3:b4047e8a0123 96 if (!cur)
daniele 3:b4047e8a0123 97 return NULL;
daniele 3:b4047e8a0123 98 return peek_segment(tq, SEQN(cur) + cur->payload_len);
daniele 3:b4047e8a0123 99 }
daniele 3:b4047e8a0123 100
daniele 3:b4047e8a0123 101 static int pico_enqueue_segment(struct pico_tcp_queue *tq, struct pico_frame *f)
daniele 3:b4047e8a0123 102 {
daniele 3:b4047e8a0123 103 if (f->payload_len <= 0) {
daniele 3:b4047e8a0123 104 tcp_dbg("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! TRIED TO ENQUEUE INVALID SEGMENT!\n");
daniele 3:b4047e8a0123 105 //abort();
daniele 3:b4047e8a0123 106 return -1;
daniele 3:b4047e8a0123 107 }
daniele 3:b4047e8a0123 108
daniele 3:b4047e8a0123 109 if ((tq->size + f->payload_len) > tq->max_size)
daniele 3:b4047e8a0123 110 return 0;
daniele 3:b4047e8a0123 111 if (pico_tree_insert(&tq->pool,f) != 0)
daniele 3:b4047e8a0123 112 return 0;
daniele 3:b4047e8a0123 113 tq->size += f->payload_len;
daniele 3:b4047e8a0123 114 if (f->payload_len > 0)
daniele 3:b4047e8a0123 115 tq->frames++;
daniele 3:b4047e8a0123 116 return f->payload_len;
daniele 3:b4047e8a0123 117 }
daniele 3:b4047e8a0123 118
daniele 3:b4047e8a0123 119 static void pico_discard_segment(struct pico_tcp_queue *tq, struct pico_frame *f)
daniele 3:b4047e8a0123 120 {
daniele 3:b4047e8a0123 121 struct pico_frame *f1;
daniele 3:b4047e8a0123 122 f1 = pico_tree_delete(&tq->pool,f);
daniele 3:b4047e8a0123 123 if (f1) {
daniele 3:b4047e8a0123 124 tq->size -= f->payload_len;
daniele 3:b4047e8a0123 125 if (f->payload_len > 0)
daniele 3:b4047e8a0123 126 tq->frames--;
daniele 3:b4047e8a0123 127 }
daniele 3:b4047e8a0123 128 pico_frame_discard(f);
daniele 3:b4047e8a0123 129 }
daniele 3:b4047e8a0123 130
daniele 3:b4047e8a0123 131 /* Structure for TCP socket */
daniele 3:b4047e8a0123 132 struct tcp_sack_block {
daniele 3:b4047e8a0123 133 uint32_t left;
daniele 3:b4047e8a0123 134 uint32_t right;
daniele 3:b4047e8a0123 135 struct tcp_sack_block *next;
daniele 3:b4047e8a0123 136 };
daniele 3:b4047e8a0123 137
daniele 3:b4047e8a0123 138 struct pico_socket_tcp {
daniele 3:b4047e8a0123 139 struct pico_socket sock;
daniele 3:b4047e8a0123 140
daniele 3:b4047e8a0123 141 /* Tree/queues */
daniele 3:b4047e8a0123 142 struct pico_tcp_queue tcpq_in;
daniele 3:b4047e8a0123 143 struct pico_tcp_queue tcpq_out;
daniele 3:b4047e8a0123 144 struct pico_tcp_queue tcpq_hold; /* buffer to hold delayed frames according to Nagle */
daniele 3:b4047e8a0123 145
daniele 3:b4047e8a0123 146 /* tcp_output */
daniele 3:b4047e8a0123 147 uint32_t snd_nxt;
daniele 3:b4047e8a0123 148 uint32_t snd_last;
daniele 3:b4047e8a0123 149 uint32_t snd_old_ack;
daniele 3:b4047e8a0123 150 uint32_t snd_retry;
daniele 3:b4047e8a0123 151 uint32_t snd_last_out;
daniele 3:b4047e8a0123 152
daniele 3:b4047e8a0123 153 /* congestion control */
daniele 3:b4047e8a0123 154 uint32_t avg_rtt;
daniele 3:b4047e8a0123 155 uint32_t rttvar;
daniele 3:b4047e8a0123 156 uint32_t rto;
daniele 3:b4047e8a0123 157 uint32_t in_flight;
daniele 3:b4047e8a0123 158 uint8_t timer_running;
daniele 3:b4047e8a0123 159 uint8_t keepalive_timer_running;
daniele 3:b4047e8a0123 160 uint16_t cwnd_counter;
daniele 3:b4047e8a0123 161 uint16_t cwnd;
daniele 3:b4047e8a0123 162 uint16_t ssthresh;
daniele 3:b4047e8a0123 163 uint16_t recv_wnd;
daniele 3:b4047e8a0123 164 uint16_t recv_wnd_scale;
daniele 3:b4047e8a0123 165
daniele 3:b4047e8a0123 166 /* tcp_input */
daniele 3:b4047e8a0123 167 uint32_t rcv_nxt;
daniele 3:b4047e8a0123 168 uint32_t rcv_ackd;
daniele 3:b4047e8a0123 169 uint32_t rcv_processed;
daniele 3:b4047e8a0123 170 uint16_t wnd;
daniele 3:b4047e8a0123 171 uint16_t wnd_scale;
daniele 3:b4047e8a0123 172
daniele 3:b4047e8a0123 173 /* options */
daniele 3:b4047e8a0123 174 uint32_t ts_nxt;
daniele 3:b4047e8a0123 175 uint16_t mss;
daniele 3:b4047e8a0123 176 uint8_t sack_ok;
daniele 3:b4047e8a0123 177 uint8_t ts_ok;
daniele 3:b4047e8a0123 178 uint8_t mss_ok;
daniele 3:b4047e8a0123 179 uint8_t scale_ok;
daniele 3:b4047e8a0123 180 struct tcp_sack_block *sacks;
daniele 3:b4047e8a0123 181 uint8_t jumbo;
daniele 3:b4047e8a0123 182
daniele 3:b4047e8a0123 183 /* Transmission */
daniele 3:b4047e8a0123 184 uint8_t x_mode;
daniele 3:b4047e8a0123 185 uint8_t dupacks;
daniele 3:b4047e8a0123 186 uint8_t backoff;
daniele 3:b4047e8a0123 187
daniele 3:b4047e8a0123 188 };
daniele 3:b4047e8a0123 189
daniele 3:b4047e8a0123 190 /* Queues */
daniele 3:b4047e8a0123 191 static struct pico_queue tcp_in = {};
daniele 3:b4047e8a0123 192 static struct pico_queue tcp_out = {};
daniele 3:b4047e8a0123 193
daniele 3:b4047e8a0123 194 /* If Nagle enabled, this function can make 1 new segment from smaller segments in hold queue */
daniele 3:b4047e8a0123 195 static struct pico_frame * pico_hold_segment_make(struct pico_socket_tcp *t);
daniele 3:b4047e8a0123 196
daniele 3:b4047e8a0123 197 /* checks if tcpq_in is empty */
daniele 3:b4047e8a0123 198 int pico_tcp_queue_in_is_empty(struct pico_socket *s)
daniele 3:b4047e8a0123 199 {
daniele 3:b4047e8a0123 200 struct pico_socket_tcp *t = (struct pico_socket_tcp *) s;
daniele 3:b4047e8a0123 201
daniele 3:b4047e8a0123 202 if (t->tcpq_in.frames == 0)
daniele 3:b4047e8a0123 203 return 1;
daniele 3:b4047e8a0123 204 else
daniele 3:b4047e8a0123 205 return 0;
daniele 3:b4047e8a0123 206 }
daniele 3:b4047e8a0123 207
daniele 3:b4047e8a0123 208 /* Useful for getting rid of the beginning of the buffer (read() op) */
daniele 3:b4047e8a0123 209 static int release_until(struct pico_tcp_queue *q, uint32_t seq)
daniele 3:b4047e8a0123 210 {
daniele 3:b4047e8a0123 211 struct pico_frame *head = first_segment(q);
daniele 3:b4047e8a0123 212 int ret = 0;
daniele 3:b4047e8a0123 213 while (head && (seq_compare(SEQN(head) + head->payload_len, seq) <= 0)) {
daniele 3:b4047e8a0123 214 struct pico_frame *cur = head;
daniele 3:b4047e8a0123 215 head = next_segment(q, cur);
daniele 3:b4047e8a0123 216 tcp_dbg("Releasing %p\n", q);
daniele 3:b4047e8a0123 217 pico_discard_segment(q, cur);
daniele 3:b4047e8a0123 218 ret++;
daniele 3:b4047e8a0123 219 }
daniele 3:b4047e8a0123 220 return ret;
daniele 3:b4047e8a0123 221 }
daniele 3:b4047e8a0123 222
daniele 3:b4047e8a0123 223 static int release_all_until(struct pico_tcp_queue *q, uint32_t seq)
daniele 3:b4047e8a0123 224 {
daniele 3:b4047e8a0123 225 struct pico_frame *f = NULL, *tmp __attribute__((unused));
daniele 3:b4047e8a0123 226 struct pico_tree_node * idx, * temp;
daniele 3:b4047e8a0123 227 int ret = 0;
daniele 3:b4047e8a0123 228
daniele 3:b4047e8a0123 229 pico_tree_foreach_safe(idx,&q->pool,temp){
daniele 3:b4047e8a0123 230 f = idx->keyValue;
daniele 3:b4047e8a0123 231 if (seq_compare(SEQN(f) + f->payload_len, seq) <= 0) {
daniele 3:b4047e8a0123 232 tcp_dbg("Releasing %p\n", f);
daniele 3:b4047e8a0123 233 pico_discard_segment(q, f);
daniele 3:b4047e8a0123 234 ret++;
daniele 3:b4047e8a0123 235 } else
daniele 3:b4047e8a0123 236 return ret;
daniele 3:b4047e8a0123 237 }
daniele 3:b4047e8a0123 238 return ret;
daniele 3:b4047e8a0123 239 }
daniele 3:b4047e8a0123 240
daniele 3:b4047e8a0123 241 /* API calls */
daniele 3:b4047e8a0123 242
daniele 3:b4047e8a0123 243 uint16_t pico_tcp_checksum_ipv4(struct pico_frame *f)
daniele 3:b4047e8a0123 244 {
daniele 3:b4047e8a0123 245 struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *) f->net_hdr;
daniele 3:b4047e8a0123 246 struct pico_tcp_hdr *tcp_hdr = (struct pico_tcp_hdr *) f->transport_hdr;
daniele 3:b4047e8a0123 247 struct pico_socket *s = f->sock;
daniele 3:b4047e8a0123 248 struct pico_ipv4_pseudo_hdr pseudo;
daniele 3:b4047e8a0123 249
daniele 3:b4047e8a0123 250 if (s) {
daniele 3:b4047e8a0123 251 /* Case of outgoing frame */
daniele 3:b4047e8a0123 252 //dbg("TCP CRC: on outgoing frame\n");
daniele 3:b4047e8a0123 253 pseudo.src.addr = s->local_addr.ip4.addr;
daniele 3:b4047e8a0123 254 pseudo.dst.addr = s->remote_addr.ip4.addr;
daniele 3:b4047e8a0123 255 } else {
daniele 3:b4047e8a0123 256 /* Case of incomming frame */
daniele 3:b4047e8a0123 257 //dbg("TCP CRC: on incomming frame\n");
daniele 3:b4047e8a0123 258 pseudo.src.addr = hdr->src.addr;
daniele 3:b4047e8a0123 259 pseudo.dst.addr = hdr->dst.addr;
daniele 3:b4047e8a0123 260 }
daniele 3:b4047e8a0123 261 pseudo.zeros = 0;
daniele 3:b4047e8a0123 262 pseudo.proto = PICO_PROTO_TCP;
daniele 3:b4047e8a0123 263 pseudo.len = short_be(f->transport_len);
daniele 3:b4047e8a0123 264
daniele 3:b4047e8a0123 265 return pico_dualbuffer_checksum(&pseudo, sizeof(struct pico_ipv4_pseudo_hdr), tcp_hdr, f->transport_len);
daniele 3:b4047e8a0123 266 }
daniele 3:b4047e8a0123 267
daniele 3:b4047e8a0123 268 static int pico_tcp_process_out(struct pico_protocol *self, struct pico_frame *f)
daniele 3:b4047e8a0123 269 {
daniele 3:b4047e8a0123 270 struct pico_tcp_hdr *hdr;
daniele 3:b4047e8a0123 271 struct pico_socket_tcp *t = (struct pico_socket_tcp *)f->sock;
daniele 3:b4047e8a0123 272 hdr = (struct pico_tcp_hdr *)f->transport_hdr;
daniele 3:b4047e8a0123 273
daniele 3:b4047e8a0123 274 if (f->payload_len > 0) {
daniele 3:b4047e8a0123 275 tcp_dbg("Process out: sending %p (%d bytes)\n",f, f->payload_len);
daniele 3:b4047e8a0123 276 } else {
daniele 3:b4047e8a0123 277 tcp_dbg("Sending empty packet\n");
daniele 3:b4047e8a0123 278 }
daniele 3:b4047e8a0123 279
daniele 3:b4047e8a0123 280 if (f->payload_len > 0) {
daniele 3:b4047e8a0123 281 if (seq_compare(SEQN(f) + f->payload_len, t->snd_nxt) > 0) {
daniele 3:b4047e8a0123 282 t->snd_nxt = SEQN(f) + f->payload_len;
daniele 3:b4047e8a0123 283 tcp_dbg("%s: snd_nxt is now %08x\n", __FUNCTION__, t->snd_nxt);
daniele 3:b4047e8a0123 284 }
daniele 3:b4047e8a0123 285 } else if (hdr->flags == PICO_TCP_ACK) { /* pure ack */
daniele 3:b4047e8a0123 286 hdr->seq = long_be(t->snd_nxt);
daniele 3:b4047e8a0123 287 } else {
daniele 3:b4047e8a0123 288 tcp_dbg("%s: non-pure ACK with len=0, fl:%04x\n", __FUNCTION__, hdr->flags);
daniele 3:b4047e8a0123 289 }
daniele 3:b4047e8a0123 290 pico_network_send(f);
daniele 3:b4047e8a0123 291 return 0;
daniele 3:b4047e8a0123 292 }
daniele 3:b4047e8a0123 293
daniele 3:b4047e8a0123 294 int pico_tcp_push(struct pico_protocol *self, struct pico_frame *data);
daniele 3:b4047e8a0123 295
daniele 3:b4047e8a0123 296 /* Interface: protocol definition */
daniele 3:b4047e8a0123 297 struct pico_protocol pico_proto_tcp = {
daniele 3:b4047e8a0123 298 .name = "tcp",
daniele 3:b4047e8a0123 299 .proto_number = PICO_PROTO_TCP,
daniele 3:b4047e8a0123 300 .layer = PICO_LAYER_TRANSPORT,
daniele 3:b4047e8a0123 301 .process_in = pico_transport_process_in,
daniele 3:b4047e8a0123 302 .process_out = pico_tcp_process_out,
daniele 3:b4047e8a0123 303 .push = pico_tcp_push,
daniele 3:b4047e8a0123 304 .q_in = &tcp_in,
daniele 3:b4047e8a0123 305 .q_out = &tcp_out,
daniele 3:b4047e8a0123 306 };
daniele 3:b4047e8a0123 307
daniele 3:b4047e8a0123 308 static uint32_t pico_paws(void)
daniele 3:b4047e8a0123 309 {
daniele 3:b4047e8a0123 310 static unsigned long _paws = 0;
daniele 3:b4047e8a0123 311 _paws = pico_rand();
daniele 3:b4047e8a0123 312 return long_be(_paws); /*XXX: implement paws */
daniele 3:b4047e8a0123 313 }
daniele 3:b4047e8a0123 314
daniele 3:b4047e8a0123 315 static void tcp_add_options(struct pico_socket_tcp *ts, struct pico_frame *f, uint16_t flags, int optsiz)
daniele 3:b4047e8a0123 316 {
daniele 3:b4047e8a0123 317 uint32_t tsval = long_be(pico_tick);
daniele 3:b4047e8a0123 318 uint32_t tsecr = long_be(ts->ts_nxt);
daniele 3:b4047e8a0123 319 int i = 0;
daniele 3:b4047e8a0123 320 f->start = f->transport_hdr + PICO_SIZE_TCPHDR;
daniele 3:b4047e8a0123 321
daniele 3:b4047e8a0123 322 memset(f->start, PICO_TCP_OPTION_NOOP, optsiz); /* fill blanks with noop */
daniele 3:b4047e8a0123 323
daniele 3:b4047e8a0123 324 if (flags & PICO_TCP_SYN) {
daniele 3:b4047e8a0123 325 f->start[i++] = PICO_TCP_OPTION_MSS;
daniele 3:b4047e8a0123 326 f->start[i++] = PICO_TCPOPTLEN_MSS;
daniele 3:b4047e8a0123 327 f->start[i++] = (ts->mss >> 8) & 0xFF;
daniele 3:b4047e8a0123 328 f->start[i++] = ts->mss & 0xFF;
daniele 3:b4047e8a0123 329 f->start[i++] = PICO_TCP_OPTION_SACK_OK;
daniele 3:b4047e8a0123 330 f->start[i++] = PICO_TCPOPTLEN_SACK_OK;
daniele 3:b4047e8a0123 331 }
daniele 3:b4047e8a0123 332
daniele 3:b4047e8a0123 333 f->start[i++] = PICO_TCP_OPTION_WS;
daniele 3:b4047e8a0123 334 f->start[i++] = PICO_TCPOPTLEN_WS;
daniele 3:b4047e8a0123 335 f->start[i++] = ts->wnd_scale;
daniele 3:b4047e8a0123 336
daniele 3:b4047e8a0123 337 if (optsiz >= 12) {
daniele 3:b4047e8a0123 338 f->start[i++] = PICO_TCP_OPTION_TIMESTAMP;
daniele 3:b4047e8a0123 339 f->start[i++] = PICO_TCPOPTLEN_TIMESTAMP;
daniele 3:b4047e8a0123 340 memcpy(f->start + i, &tsval, 4);
daniele 3:b4047e8a0123 341 i += 4;
daniele 3:b4047e8a0123 342 memcpy(f->start + i, &tsecr, 4);
daniele 3:b4047e8a0123 343 i += 4;
daniele 3:b4047e8a0123 344 }
daniele 3:b4047e8a0123 345
daniele 3:b4047e8a0123 346 if (flags & PICO_TCP_ACK) {
daniele 3:b4047e8a0123 347 struct tcp_sack_block *sb;
daniele 3:b4047e8a0123 348 int len_off;
daniele 3:b4047e8a0123 349
daniele 3:b4047e8a0123 350 if (ts->sack_ok && ts->sacks) {
daniele 3:b4047e8a0123 351 f->start[i++] = PICO_TCP_OPTION_SACK;
daniele 3:b4047e8a0123 352 len_off = i;
daniele 3:b4047e8a0123 353 f->start[i++] = PICO_TCPOPTLEN_SACK;
daniele 3:b4047e8a0123 354 while(ts->sacks) {
daniele 3:b4047e8a0123 355 sb = ts->sacks;
daniele 3:b4047e8a0123 356 ts->sacks = sb->next;
daniele 3:b4047e8a0123 357 memcpy(f->start + i, sb, 2 * sizeof(uint32_t));
daniele 3:b4047e8a0123 358 i += (2 * sizeof(uint32_t));
daniele 3:b4047e8a0123 359 f->start[len_off] += (2 * sizeof(uint32_t));
daniele 3:b4047e8a0123 360 pico_free(sb);
daniele 3:b4047e8a0123 361 }
daniele 3:b4047e8a0123 362 }
daniele 3:b4047e8a0123 363 }
daniele 3:b4047e8a0123 364 if (i < optsiz)
daniele 3:b4047e8a0123 365 f->start[ optsiz - 1 ] = PICO_TCP_OPTION_END;
daniele 3:b4047e8a0123 366 }
daniele 3:b4047e8a0123 367
daniele 3:b4047e8a0123 368 static void tcp_send_ack(struct pico_socket_tcp *t);
daniele 3:b4047e8a0123 369
daniele 3:b4047e8a0123 370 static void tcp_set_space(struct pico_socket_tcp *t)
daniele 3:b4047e8a0123 371 {
daniele 3:b4047e8a0123 372 int mtu, space;
daniele 3:b4047e8a0123 373 int shift = 0;
daniele 3:b4047e8a0123 374
daniele 3:b4047e8a0123 375 mtu = t->mss + PICO_SIZE_TCPHDR + PICO_SIZE_TCPOPT_SYN ;
daniele 3:b4047e8a0123 376 if (t->tcpq_in.max_size == 0) {
daniele 3:b4047e8a0123 377 space = 1024 * 1024 * 1024; /* One Gigabyte, for unlimited sockets. */
daniele 3:b4047e8a0123 378 } else {
daniele 3:b4047e8a0123 379 space = ((t->tcpq_in.max_size - t->tcpq_in.size) / mtu) * t->mss;
daniele 3:b4047e8a0123 380 }
daniele 3:b4047e8a0123 381 if (space < 0)
daniele 3:b4047e8a0123 382 space = 0;
daniele 3:b4047e8a0123 383 while(space > 0xFFFF) {
daniele 3:b4047e8a0123 384 space >>= 1;
daniele 3:b4047e8a0123 385 shift++;
daniele 3:b4047e8a0123 386 }
daniele 3:b4047e8a0123 387 if ((space != t->wnd) || (shift != t->wnd_scale) || ((space - t->wnd) > (space>>2))) {
daniele 3:b4047e8a0123 388 t->wnd = space;
daniele 3:b4047e8a0123 389 t->wnd_scale = shift;
daniele 3:b4047e8a0123 390 }
daniele 3:b4047e8a0123 391 }
daniele 3:b4047e8a0123 392
daniele 3:b4047e8a0123 393 /* Return 32-bit aligned option size */
daniele 3:b4047e8a0123 394 static int tcp_options_size(struct pico_socket_tcp *t, uint16_t flags)
daniele 3:b4047e8a0123 395 {
daniele 3:b4047e8a0123 396 int size = 0;
daniele 3:b4047e8a0123 397 struct tcp_sack_block *sb = t->sacks;
daniele 3:b4047e8a0123 398
daniele 3:b4047e8a0123 399 if (flags & PICO_TCP_SYN) { /* Full options */
daniele 3:b4047e8a0123 400 size = PICO_TCPOPTLEN_MSS + PICO_TCP_OPTION_SACK_OK + PICO_TCPOPTLEN_WS + PICO_TCPOPTLEN_TIMESTAMP;
daniele 3:b4047e8a0123 401 } else {
daniele 3:b4047e8a0123 402
daniele 3:b4047e8a0123 403 /* Always update window scale. */
daniele 3:b4047e8a0123 404 size += PICO_TCPOPTLEN_WS;
daniele 3:b4047e8a0123 405
daniele 3:b4047e8a0123 406 if (t->ts_ok)
daniele 3:b4047e8a0123 407 size += PICO_TCPOPTLEN_TIMESTAMP;
daniele 3:b4047e8a0123 408
daniele 3:b4047e8a0123 409 size+= PICO_TCPOPTLEN_END;
daniele 3:b4047e8a0123 410 }
daniele 3:b4047e8a0123 411 if ((flags & PICO_TCP_ACK) && (t->sack_ok && sb)) {
daniele 3:b4047e8a0123 412 size += 2;
daniele 3:b4047e8a0123 413 while(sb) {
daniele 3:b4047e8a0123 414 size += (2 * sizeof(uint32_t));
daniele 3:b4047e8a0123 415 sb = sb->next;
daniele 3:b4047e8a0123 416 }
daniele 3:b4047e8a0123 417 }
daniele 3:b4047e8a0123 418 size = (((size + 3) >> 2) << 2);
daniele 3:b4047e8a0123 419 return size;
daniele 3:b4047e8a0123 420 }
daniele 3:b4047e8a0123 421
daniele 3:b4047e8a0123 422 int pico_tcp_overhead(struct pico_socket *s)
daniele 3:b4047e8a0123 423 {
daniele 3:b4047e8a0123 424 if (!s)
daniele 3:b4047e8a0123 425 return 0;
daniele 3:b4047e8a0123 426
daniele 3:b4047e8a0123 427 return PICO_SIZE_TCPHDR + tcp_options_size((struct pico_socket_tcp *)s, 0); /* hdr + Options size for data pkt */
daniele 3:b4047e8a0123 428
daniele 3:b4047e8a0123 429 }
daniele 3:b4047e8a0123 430
daniele 3:b4047e8a0123 431 static void tcp_process_sack(struct pico_socket_tcp *t, uint32_t start, uint32_t end)
daniele 3:b4047e8a0123 432 {
daniele 3:b4047e8a0123 433 struct pico_frame *f;
daniele 3:b4047e8a0123 434 struct pico_tree_node * index, * temp;
daniele 3:b4047e8a0123 435 int cmp;
daniele 3:b4047e8a0123 436 int count = 0;
daniele 3:b4047e8a0123 437
daniele 3:b4047e8a0123 438 pico_tree_foreach_safe(index,&t->tcpq_out.pool,temp){
daniele 3:b4047e8a0123 439 f = index->keyValue;
daniele 3:b4047e8a0123 440 cmp = seq_compare(SEQN(f), start);
daniele 3:b4047e8a0123 441 if (cmp > 0)
daniele 3:b4047e8a0123 442 goto done;
daniele 3:b4047e8a0123 443
daniele 3:b4047e8a0123 444 if (cmp == 0) {
daniele 3:b4047e8a0123 445 cmp = seq_compare(SEQN(f) + f->payload_len, end);
daniele 3:b4047e8a0123 446 if (cmp > 0) {
daniele 3:b4047e8a0123 447 tcp_dbg("Invalid SACK: ignoring.\n");
daniele 3:b4047e8a0123 448 }
daniele 3:b4047e8a0123 449
daniele 3:b4047e8a0123 450 tcp_dbg("Marking (by SACK) segment %08x BLK:[%08x::%08x]\n", SEQN(f), start, end);
daniele 3:b4047e8a0123 451 f->flags |= PICO_FRAME_FLAG_SACKED;
daniele 3:b4047e8a0123 452 count++;
daniele 3:b4047e8a0123 453
daniele 3:b4047e8a0123 454 if (cmp == 0) {
daniele 3:b4047e8a0123 455 /* that was last segment sacked. Job done */
daniele 3:b4047e8a0123 456 goto done;
daniele 3:b4047e8a0123 457 }
daniele 3:b4047e8a0123 458 }
daniele 3:b4047e8a0123 459 }
daniele 3:b4047e8a0123 460
daniele 3:b4047e8a0123 461 done:
daniele 3:b4047e8a0123 462 if (t->x_mode > PICO_TCP_LOOKAHEAD) {
daniele 3:b4047e8a0123 463 if (t->in_flight > (count))
daniele 3:b4047e8a0123 464 t->in_flight -= (count);
daniele 3:b4047e8a0123 465 else
daniele 3:b4047e8a0123 466 t->in_flight = 0;
daniele 3:b4047e8a0123 467 }
daniele 3:b4047e8a0123 468 }
daniele 3:b4047e8a0123 469
daniele 3:b4047e8a0123 470 static void tcp_rcv_sack(struct pico_socket_tcp *t, uint8_t *opt, int len)
daniele 3:b4047e8a0123 471 {
daniele 3:b4047e8a0123 472 uint32_t *start, *end;
daniele 3:b4047e8a0123 473 int i = 0;
daniele 3:b4047e8a0123 474 if (len % 8) {
daniele 3:b4047e8a0123 475 tcp_dbg("SACK: Invalid len.\n");
daniele 3:b4047e8a0123 476 return;
daniele 3:b4047e8a0123 477 }
daniele 3:b4047e8a0123 478 while (i < len) {
daniele 3:b4047e8a0123 479 start = (uint32_t *)(opt + i);
daniele 3:b4047e8a0123 480 i += 4;
daniele 3:b4047e8a0123 481 end = (uint32_t *)(opt + i);
daniele 3:b4047e8a0123 482 i += 4;
daniele 3:b4047e8a0123 483 tcp_process_sack(t, long_be(*start), long_be(*end));
daniele 3:b4047e8a0123 484 }
daniele 3:b4047e8a0123 485 }
daniele 3:b4047e8a0123 486
daniele 3:b4047e8a0123 487 static void tcp_parse_options(struct pico_frame *f)
daniele 3:b4047e8a0123 488 {
daniele 3:b4047e8a0123 489 struct pico_socket_tcp *t = (struct pico_socket_tcp *)f->sock;
daniele 3:b4047e8a0123 490 uint8_t *opt = f->transport_hdr + PICO_SIZE_TCPHDR;
daniele 3:b4047e8a0123 491 int i = 0;
daniele 3:b4047e8a0123 492 while (i < (f->transport_len - PICO_SIZE_TCPHDR)) {
daniele 3:b4047e8a0123 493 uint8_t type = opt[i++];
daniele 3:b4047e8a0123 494 uint8_t len;
daniele 3:b4047e8a0123 495 if(i < (f->transport_len - PICO_SIZE_TCPHDR) && (type > 1))
daniele 3:b4047e8a0123 496 len = opt[i++];
daniele 3:b4047e8a0123 497 else
daniele 3:b4047e8a0123 498 len = 1;
daniele 3:b4047e8a0123 499 if (f->payload && ((opt + i) > f->payload))
daniele 3:b4047e8a0123 500 break;
daniele 3:b4047e8a0123 501 tcp_dbg("Received option '%d', len = %d \n", type, len);
daniele 3:b4047e8a0123 502 switch (type) {
daniele 3:b4047e8a0123 503 case PICO_TCP_OPTION_NOOP:
daniele 3:b4047e8a0123 504 case PICO_TCP_OPTION_END:
daniele 3:b4047e8a0123 505 break;
daniele 3:b4047e8a0123 506 case PICO_TCP_OPTION_WS:
daniele 3:b4047e8a0123 507 if (len != PICO_TCPOPTLEN_WS) {
daniele 3:b4047e8a0123 508 tcp_dbg("TCP Window scale: bad len received (%d).\n", len);
daniele 3:b4047e8a0123 509 i += len - 2;
daniele 3:b4047e8a0123 510 break;
daniele 3:b4047e8a0123 511 }
daniele 3:b4047e8a0123 512 t->recv_wnd_scale = opt[i++];
daniele 3:b4047e8a0123 513 tcp_dbg("TCP Window scale: received %d\n", t->recv_wnd_scale);
daniele 3:b4047e8a0123 514 break;
daniele 3:b4047e8a0123 515 case PICO_TCP_OPTION_SACK_OK:
daniele 3:b4047e8a0123 516 if (len != PICO_TCPOPTLEN_SACK_OK) {
daniele 3:b4047e8a0123 517 tcp_dbg("TCP option sack: bad len received.\n");
daniele 3:b4047e8a0123 518 i += len - 2;
daniele 3:b4047e8a0123 519 break;
daniele 3:b4047e8a0123 520 }
daniele 3:b4047e8a0123 521 t->sack_ok = 1;
daniele 3:b4047e8a0123 522 break;
daniele 3:b4047e8a0123 523 case PICO_TCP_OPTION_MSS: {
daniele 3:b4047e8a0123 524 uint16_t *mss;
daniele 3:b4047e8a0123 525 if (len != PICO_TCPOPTLEN_MSS) {
daniele 3:b4047e8a0123 526 tcp_dbg("TCP option mss: bad len received.\n");
daniele 3:b4047e8a0123 527 i += len - 2;
daniele 3:b4047e8a0123 528 break;
daniele 3:b4047e8a0123 529 }
daniele 3:b4047e8a0123 530 t->mss_ok = 1;
daniele 3:b4047e8a0123 531 mss = (uint16_t *)(opt + i);
daniele 3:b4047e8a0123 532 i += sizeof(uint16_t);
daniele 3:b4047e8a0123 533 if (t->mss > short_be(*mss))
daniele 3:b4047e8a0123 534 t->mss = short_be(*mss);
daniele 3:b4047e8a0123 535 break;
daniele 3:b4047e8a0123 536 }
daniele 3:b4047e8a0123 537 case PICO_TCP_OPTION_TIMESTAMP: {
daniele 3:b4047e8a0123 538 uint32_t *tsval, *tsecr;
daniele 3:b4047e8a0123 539 if (len != PICO_TCPOPTLEN_TIMESTAMP) {
daniele 3:b4047e8a0123 540 tcp_dbg("TCP option timestamp: bad len received.\n");
daniele 3:b4047e8a0123 541 i += len - 2;
daniele 3:b4047e8a0123 542 break;
daniele 3:b4047e8a0123 543 }
daniele 3:b4047e8a0123 544 t->ts_ok = 1;
daniele 3:b4047e8a0123 545 tsval = (uint32_t *)(opt + i);
daniele 3:b4047e8a0123 546 i += sizeof(uint32_t);
daniele 3:b4047e8a0123 547 tsecr = (uint32_t *)(opt + i);
daniele 3:b4047e8a0123 548 f->timestamp = long_be(*tsecr);
daniele 3:b4047e8a0123 549 i += sizeof(uint32_t);
daniele 3:b4047e8a0123 550
daniele 3:b4047e8a0123 551 t->ts_nxt = long_be(*tsval);
daniele 3:b4047e8a0123 552 break;
daniele 3:b4047e8a0123 553 }
daniele 3:b4047e8a0123 554 case PICO_TCP_OPTION_SACK:
daniele 3:b4047e8a0123 555 {
daniele 3:b4047e8a0123 556 tcp_rcv_sack(t, opt + i, len - 2);
daniele 3:b4047e8a0123 557 i += len - 2;
daniele 3:b4047e8a0123 558 break;
daniele 3:b4047e8a0123 559 }
daniele 3:b4047e8a0123 560 default:
daniele 3:b4047e8a0123 561 tcp_dbg("TCP: received unsupported option %u\n", type);
daniele 3:b4047e8a0123 562 i += len - 2;
daniele 3:b4047e8a0123 563 }
daniele 3:b4047e8a0123 564 }
daniele 3:b4047e8a0123 565 }
daniele 3:b4047e8a0123 566
daniele 3:b4047e8a0123 567 static int tcp_send(struct pico_socket_tcp *ts, struct pico_frame *f)
daniele 3:b4047e8a0123 568 {
daniele 3:b4047e8a0123 569 struct pico_tcp_hdr *hdr= (struct pico_tcp_hdr *) f->transport_hdr;
daniele 3:b4047e8a0123 570 struct pico_frame *cpy;
daniele 3:b4047e8a0123 571 hdr->trans.sport = ts->sock.local_port;
daniele 3:b4047e8a0123 572 hdr->trans.dport = ts->sock.remote_port;
daniele 3:b4047e8a0123 573 if (!hdr->seq)
daniele 3:b4047e8a0123 574 hdr->seq = long_be(ts->snd_nxt);
daniele 3:b4047e8a0123 575
daniele 3:b4047e8a0123 576 if (ts->rcv_nxt != 0) {
daniele 3:b4047e8a0123 577 if ( (ts->rcv_ackd == 0) || (seq_compare(ts->rcv_ackd, ts->rcv_nxt) != 0) || (hdr->flags & PICO_TCP_ACK)) {
daniele 3:b4047e8a0123 578 hdr->flags |= PICO_TCP_ACK;
daniele 3:b4047e8a0123 579 hdr->ack = long_be(ts->rcv_nxt);
daniele 3:b4047e8a0123 580 ts->rcv_ackd = ts->rcv_nxt;
daniele 3:b4047e8a0123 581 }
daniele 3:b4047e8a0123 582 }
daniele 3:b4047e8a0123 583
daniele 3:b4047e8a0123 584 if (hdr->flags & PICO_TCP_SYN) {
daniele 3:b4047e8a0123 585 ts->snd_nxt++;
daniele 3:b4047e8a0123 586 }
daniele 3:b4047e8a0123 587 if (f->payload_len > 0) {
daniele 3:b4047e8a0123 588 hdr->flags |= PICO_TCP_PSH | PICO_TCP_ACK;
daniele 3:b4047e8a0123 589 hdr->ack = long_be(ts->rcv_nxt);
daniele 3:b4047e8a0123 590 ts->rcv_ackd = ts->rcv_nxt;
daniele 3:b4047e8a0123 591 }
daniele 3:b4047e8a0123 592
daniele 3:b4047e8a0123 593 f->start = f->transport_hdr + PICO_SIZE_TCPHDR;
daniele 3:b4047e8a0123 594 hdr->rwnd = short_be(ts->wnd);
daniele 3:b4047e8a0123 595 hdr->crc = 0;
daniele 3:b4047e8a0123 596 hdr->crc = short_be(pico_tcp_checksum_ipv4(f));
daniele 3:b4047e8a0123 597
daniele 3:b4047e8a0123 598 /* TCP: ENQUEUE to PROTO ( Transmit ) */
daniele 3:b4047e8a0123 599 cpy = pico_frame_copy(f);
daniele 3:b4047e8a0123 600 if (pico_enqueue(&tcp_out, cpy) > 0) {
daniele 3:b4047e8a0123 601 if (f->payload_len > 0)
daniele 3:b4047e8a0123 602 ts->in_flight++;
daniele 3:b4047e8a0123 603 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",
daniele 3:b4047e8a0123 604 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 );
daniele 3:b4047e8a0123 605 } else {
daniele 3:b4047e8a0123 606 pico_frame_discard(cpy);
daniele 3:b4047e8a0123 607 }
daniele 3:b4047e8a0123 608 return 0;
daniele 3:b4047e8a0123 609 }
daniele 3:b4047e8a0123 610
daniele 3:b4047e8a0123 611 //#define PICO_TCP_SUPPORT_SOCKET_STATS
daniele 3:b4047e8a0123 612
daniele 3:b4047e8a0123 613 #ifdef PICO_TCP_SUPPORT_SOCKET_STATS
daniele 3:b4047e8a0123 614 static void sock_stats(unsigned long when, void *arg)
daniele 3:b4047e8a0123 615 {
daniele 3:b4047e8a0123 616 struct pico_socket_tcp *t = (struct pico_socket_tcp *)arg;
daniele 3:b4047e8a0123 617 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",
daniele 3:b4047e8a0123 618 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);
daniele 3:b4047e8a0123 619 pico_timer_add(2000, sock_stats, t);
daniele 3:b4047e8a0123 620 }
daniele 3:b4047e8a0123 621 #endif
daniele 3:b4047e8a0123 622
daniele 3:b4047e8a0123 623 struct pico_socket *pico_tcp_open(void)
daniele 3:b4047e8a0123 624 {
daniele 3:b4047e8a0123 625 struct pico_socket_tcp *t = pico_zalloc(sizeof(struct pico_socket_tcp));
daniele 3:b4047e8a0123 626 if (!t)
daniele 3:b4047e8a0123 627 return NULL;
daniele 3:b4047e8a0123 628 t->mss = PICO_TCP_DEFAULT_MSS;
daniele 3:b4047e8a0123 629
daniele 3:b4047e8a0123 630 t->tcpq_in.pool.root = t->tcpq_hold.pool.root = t->tcpq_out.pool.root = &LEAF;
daniele 3:b4047e8a0123 631 t->tcpq_hold.pool.compare = t->tcpq_in.pool.compare = t->tcpq_out.pool.compare = segment_compare;
daniele 3:b4047e8a0123 632
daniele 3:b4047e8a0123 633 t->tcpq_in.max_size = PICO_DEFAULT_SOCKETQ;
daniele 3:b4047e8a0123 634 t->tcpq_out.max_size = PICO_DEFAULT_SOCKETQ;
daniele 3:b4047e8a0123 635 t->tcpq_hold.max_size = 2*PICO_TCP_DEFAULT_MSS;
daniele 3:b4047e8a0123 636
daniele 3:b4047e8a0123 637 /* enable Nagle by default */
daniele 3:b4047e8a0123 638 t->sock.opt_flags &= (~(1 << PICO_SOCKET_OPT_TCPNODELAY));
daniele 3:b4047e8a0123 639
daniele 3:b4047e8a0123 640 #ifdef PICO_TCP_SUPPORT_SOCKET_STATS
daniele 3:b4047e8a0123 641 pico_timer_add(2000, sock_stats, t);
daniele 3:b4047e8a0123 642 #endif
daniele 3:b4047e8a0123 643 tcp_set_space(t);
daniele 3:b4047e8a0123 644
daniele 3:b4047e8a0123 645 return &t->sock;
daniele 3:b4047e8a0123 646 }
daniele 3:b4047e8a0123 647
daniele 3:b4047e8a0123 648 int pico_tcp_read(struct pico_socket *s, void *buf, int len)
daniele 3:b4047e8a0123 649 {
daniele 3:b4047e8a0123 650 struct pico_socket_tcp *t = TCP_SOCK(s);
daniele 3:b4047e8a0123 651 struct pico_frame *f;
daniele 3:b4047e8a0123 652 uint32_t in_frame_off, in_frame_len;
daniele 3:b4047e8a0123 653 int tot_rd_len = 0;
daniele 3:b4047e8a0123 654
daniele 3:b4047e8a0123 655 while (tot_rd_len < len) {
daniele 3:b4047e8a0123 656 /* To be sure we don't have garbage at the beginning */
daniele 3:b4047e8a0123 657 release_until(&t->tcpq_in, t->rcv_processed);
daniele 3:b4047e8a0123 658 f = first_segment(&t->tcpq_in);
daniele 3:b4047e8a0123 659 if (!f) {
daniele 3:b4047e8a0123 660 tcp_set_space(t);
daniele 3:b4047e8a0123 661 goto out;
daniele 3:b4047e8a0123 662 }
daniele 3:b4047e8a0123 663
daniele 3:b4047e8a0123 664 /* Hole at the beginning of data, awaiting retransmissions. */
daniele 3:b4047e8a0123 665 if (seq_compare(t->rcv_processed, SEQN(f)) < 0) {
daniele 3:b4047e8a0123 666 tcp_dbg("TCP> read hole beginning of data, %08x - %08x. rcv_nxt is %08x\n",t->rcv_processed, SEQN(f), t->rcv_nxt);
daniele 3:b4047e8a0123 667 goto out;
daniele 3:b4047e8a0123 668 }
daniele 3:b4047e8a0123 669
daniele 3:b4047e8a0123 670 if(seq_compare(t->rcv_processed, SEQN(f)) > 0) {
daniele 3:b4047e8a0123 671 in_frame_off = t->rcv_processed - SEQN(f);
daniele 3:b4047e8a0123 672 in_frame_len = f->payload_len - in_frame_off;
daniele 3:b4047e8a0123 673 } else {
daniele 3:b4047e8a0123 674 in_frame_off = 0;
daniele 3:b4047e8a0123 675 in_frame_len = f->payload_len;
daniele 3:b4047e8a0123 676 }
daniele 3:b4047e8a0123 677 if ((in_frame_len + tot_rd_len) > len) {
daniele 3:b4047e8a0123 678 in_frame_len = len - tot_rd_len;
daniele 3:b4047e8a0123 679 }
daniele 3:b4047e8a0123 680
daniele 3:b4047e8a0123 681 if (in_frame_len > f->payload_len - in_frame_off)
daniele 3:b4047e8a0123 682 in_frame_len = f->payload_len - in_frame_off;
daniele 3:b4047e8a0123 683
daniele 3:b4047e8a0123 684 memcpy(buf + tot_rd_len, f->payload + in_frame_off, in_frame_len);
daniele 3:b4047e8a0123 685 tot_rd_len += in_frame_len;
daniele 3:b4047e8a0123 686 t->rcv_processed += in_frame_len;
daniele 3:b4047e8a0123 687
daniele 3:b4047e8a0123 688 if ((in_frame_len == 0) || (in_frame_len == f->payload_len)) {
daniele 3:b4047e8a0123 689 pico_discard_segment(&t->tcpq_in, f);
daniele 3:b4047e8a0123 690 }
daniele 3:b4047e8a0123 691 }
daniele 3:b4047e8a0123 692
daniele 3:b4047e8a0123 693 out:
daniele 3:b4047e8a0123 694 tcp_set_space(t);
daniele 3:b4047e8a0123 695 if (t->tcpq_in.size == 0) {
daniele 3:b4047e8a0123 696 s->ev_pending &= (~PICO_SOCK_EV_RD);
daniele 3:b4047e8a0123 697 }
daniele 3:b4047e8a0123 698 return tot_rd_len;
daniele 3:b4047e8a0123 699 }
daniele 3:b4047e8a0123 700
daniele 3:b4047e8a0123 701 int pico_tcp_initconn(struct pico_socket *s);
daniele 3:b4047e8a0123 702 static void initconn_retry(unsigned long when, void *arg)
daniele 3:b4047e8a0123 703 {
daniele 3:b4047e8a0123 704 struct pico_socket_tcp *t = (struct pico_socket_tcp *)arg;
daniele 3:b4047e8a0123 705 if (TCPSTATE(&t->sock) == PICO_SOCKET_STATE_TCP_SYN_SENT) {
daniele 3:b4047e8a0123 706 if (t->backoff > PICO_TCP_MAX_CONNECT_RETRIES) {
daniele 3:b4047e8a0123 707 tcp_dbg("TCP> Connection timeout. \n");
daniele 3:b4047e8a0123 708 if (t->sock.wakeup)
daniele 3:b4047e8a0123 709 t->sock.wakeup(PICO_SOCK_EV_ERR, &t->sock);
daniele 3:b4047e8a0123 710 return;
daniele 3:b4047e8a0123 711 }
daniele 3:b4047e8a0123 712 tcp_dbg("TCP> SYN retry %d...\n", t->backoff);
daniele 3:b4047e8a0123 713 t->backoff++;
daniele 3:b4047e8a0123 714 pico_tcp_initconn(&t->sock);
daniele 3:b4047e8a0123 715 } else {
daniele 3:b4047e8a0123 716 tcp_dbg("TCP> Connection is already established: no retry needed. good.\n");
daniele 3:b4047e8a0123 717 }
daniele 3:b4047e8a0123 718 }
daniele 3:b4047e8a0123 719
daniele 3:b4047e8a0123 720 int pico_tcp_initconn(struct pico_socket *s)
daniele 3:b4047e8a0123 721 {
daniele 3:b4047e8a0123 722 struct pico_socket_tcp *ts = TCP_SOCK(s);
daniele 3:b4047e8a0123 723 struct pico_frame *syn;
daniele 3:b4047e8a0123 724 struct pico_tcp_hdr *hdr;
daniele 3:b4047e8a0123 725 int opt_len = tcp_options_size(ts, PICO_TCP_SYN);
daniele 3:b4047e8a0123 726
daniele 3:b4047e8a0123 727 syn = s->net->alloc(s->net, PICO_SIZE_TCPHDR + opt_len);
daniele 3:b4047e8a0123 728 if (!syn)
daniele 3:b4047e8a0123 729 return -1;
daniele 3:b4047e8a0123 730 hdr = (struct pico_tcp_hdr *) syn->transport_hdr;
daniele 3:b4047e8a0123 731
daniele 3:b4047e8a0123 732 if (!ts->snd_nxt)
daniele 3:b4047e8a0123 733 ts->snd_nxt = long_be(pico_paws());
daniele 3:b4047e8a0123 734 ts->snd_last = ts->snd_nxt;
daniele 3:b4047e8a0123 735 ts->cwnd = PICO_TCP_IW;
daniele 3:b4047e8a0123 736 ts->ssthresh = 40;
daniele 3:b4047e8a0123 737 syn->sock = s;
daniele 3:b4047e8a0123 738 hdr->seq = long_be(ts->snd_nxt);
daniele 3:b4047e8a0123 739 hdr->len = (PICO_SIZE_TCPHDR + opt_len) << 2 | ts->jumbo;
daniele 3:b4047e8a0123 740 hdr->flags = PICO_TCP_SYN;
daniele 3:b4047e8a0123 741 tcp_set_space(ts);
daniele 3:b4047e8a0123 742 hdr->rwnd = short_be(ts->wnd);
daniele 3:b4047e8a0123 743 tcp_add_options(ts,syn, PICO_TCP_SYN, opt_len);
daniele 3:b4047e8a0123 744 hdr->trans.sport = ts->sock.local_port;
daniele 3:b4047e8a0123 745 hdr->trans.dport = ts->sock.remote_port;
daniele 3:b4047e8a0123 746
daniele 3:b4047e8a0123 747 hdr->crc = 0;
daniele 3:b4047e8a0123 748 hdr->crc = short_be(pico_tcp_checksum_ipv4(syn));
daniele 3:b4047e8a0123 749
daniele 3:b4047e8a0123 750 /* TCP: ENQUEUE to PROTO ( SYN ) */
daniele 3:b4047e8a0123 751 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);
daniele 3:b4047e8a0123 752 pico_enqueue(&tcp_out, syn);
daniele 3:b4047e8a0123 753 pico_timer_add(PICO_TCP_RTO_MIN << ts->backoff, initconn_retry, ts);
daniele 3:b4047e8a0123 754 return 0;
daniele 3:b4047e8a0123 755 }
daniele 3:b4047e8a0123 756
daniele 3:b4047e8a0123 757 static int tcp_send_synack(struct pico_socket *s)
daniele 3:b4047e8a0123 758 {
daniele 3:b4047e8a0123 759 struct pico_socket_tcp *ts = TCP_SOCK(s);
daniele 3:b4047e8a0123 760 struct pico_frame *synack;
daniele 3:b4047e8a0123 761 struct pico_tcp_hdr *hdr;
daniele 3:b4047e8a0123 762 int opt_len = tcp_options_size(ts, PICO_TCP_SYN | PICO_TCP_ACK);
daniele 3:b4047e8a0123 763
daniele 3:b4047e8a0123 764 synack = s->net->alloc(s->net, PICO_SIZE_TCPHDR + opt_len);
daniele 3:b4047e8a0123 765 if (!synack)
daniele 3:b4047e8a0123 766 return -1;
daniele 3:b4047e8a0123 767 hdr = (struct pico_tcp_hdr *) synack->transport_hdr;
daniele 3:b4047e8a0123 768
daniele 3:b4047e8a0123 769 synack->sock = s;
daniele 3:b4047e8a0123 770 hdr->len = (PICO_SIZE_TCPHDR + opt_len) << 2 | ts->jumbo;
daniele 3:b4047e8a0123 771 hdr->flags = PICO_TCP_SYN | PICO_TCP_ACK;
daniele 3:b4047e8a0123 772 hdr->rwnd = short_be(ts->wnd);
daniele 3:b4047e8a0123 773 hdr->seq = long_be(ts->snd_nxt);
daniele 3:b4047e8a0123 774 ts->rcv_processed = long_be(hdr->seq);
daniele 3:b4047e8a0123 775 ts->snd_last = ts->snd_nxt;
daniele 3:b4047e8a0123 776 tcp_set_space(ts);
daniele 3:b4047e8a0123 777 tcp_add_options(ts,synack, hdr->flags, opt_len);
daniele 3:b4047e8a0123 778 synack->payload_len = 0;
daniele 3:b4047e8a0123 779 synack->timestamp = pico_tick;
daniele 3:b4047e8a0123 780 tcp_send(ts, synack);
daniele 3:b4047e8a0123 781 pico_frame_discard(synack);
daniele 3:b4047e8a0123 782 return 0;
daniele 3:b4047e8a0123 783 }
daniele 3:b4047e8a0123 784
daniele 3:b4047e8a0123 785 static void tcp_send_empty(struct pico_socket_tcp *t, uint16_t flags)
daniele 3:b4047e8a0123 786 {
daniele 3:b4047e8a0123 787 struct pico_frame *f;
daniele 3:b4047e8a0123 788 struct pico_tcp_hdr *hdr;
daniele 3:b4047e8a0123 789 int opt_len = tcp_options_size(t, flags);
daniele 3:b4047e8a0123 790 f = t->sock.net->alloc(t->sock.net, PICO_SIZE_TCPHDR + opt_len);
daniele 3:b4047e8a0123 791 if (!f) {
daniele 3:b4047e8a0123 792 return;
daniele 3:b4047e8a0123 793 }
daniele 3:b4047e8a0123 794 f->sock = &t->sock;
daniele 3:b4047e8a0123 795 hdr = (struct pico_tcp_hdr *) f->transport_hdr;
daniele 3:b4047e8a0123 796 hdr->len = (PICO_SIZE_TCPHDR + opt_len) << 2 | t->jumbo;
daniele 3:b4047e8a0123 797 hdr->flags = flags;
daniele 3:b4047e8a0123 798 hdr->rwnd = short_be(t->wnd);
daniele 3:b4047e8a0123 799 tcp_set_space(t);
daniele 3:b4047e8a0123 800 tcp_add_options(t,f, flags, opt_len);
daniele 3:b4047e8a0123 801 hdr->trans.sport = t->sock.local_port;
daniele 3:b4047e8a0123 802 hdr->trans.dport = t->sock.remote_port;
daniele 3:b4047e8a0123 803 hdr->seq = long_be(t->snd_nxt);
daniele 3:b4047e8a0123 804 if ((flags & PICO_TCP_ACK) != 0)
daniele 3:b4047e8a0123 805 hdr->ack = long_be(t->rcv_nxt);
daniele 3:b4047e8a0123 806 t->rcv_ackd = t->rcv_nxt;
daniele 3:b4047e8a0123 807
daniele 3:b4047e8a0123 808 f->start = f->transport_hdr + PICO_SIZE_TCPHDR;
daniele 3:b4047e8a0123 809 hdr->rwnd = short_be(t->wnd);
daniele 3:b4047e8a0123 810 hdr->crc = 0;
daniele 3:b4047e8a0123 811 hdr->crc = short_be(pico_tcp_checksum_ipv4(f));
daniele 3:b4047e8a0123 812
daniele 3:b4047e8a0123 813 /* TCP: ENQUEUE to PROTO */
daniele 3:b4047e8a0123 814 pico_enqueue(&tcp_out, f);
daniele 3:b4047e8a0123 815 }
daniele 3:b4047e8a0123 816
daniele 3:b4047e8a0123 817 static void tcp_send_ack(struct pico_socket_tcp *t)
daniele 3:b4047e8a0123 818 {
daniele 3:b4047e8a0123 819 return tcp_send_empty(t, PICO_TCP_ACK);
daniele 3:b4047e8a0123 820 }
daniele 3:b4047e8a0123 821
daniele 3:b4047e8a0123 822 static int tcp_send_rst(struct pico_socket *s, struct pico_frame *fr)
daniele 3:b4047e8a0123 823 {
daniele 3:b4047e8a0123 824 struct pico_socket_tcp *t = (struct pico_socket_tcp *) s;
daniele 3:b4047e8a0123 825 struct pico_frame *f;
daniele 3:b4047e8a0123 826 struct pico_tcp_hdr *hdr, *hdr_rcv;
daniele 3:b4047e8a0123 827 int opt_len = tcp_options_size(t, PICO_TCP_RST);
daniele 3:b4047e8a0123 828
daniele 3:b4047e8a0123 829 tcp_dbg("TCP SEND_RST >>>>>>>>>>>>>>> START\n");
daniele 3:b4047e8a0123 830 /* go to CLOSED here to prevent timer callback to go on after timeout */
daniele 3:b4047e8a0123 831 (t->sock).state &= 0x00FFU;
daniele 3:b4047e8a0123 832 (t->sock).state |= PICO_SOCKET_STATE_TCP_CLOSED;
daniele 3:b4047e8a0123 833
daniele 3:b4047e8a0123 834 f = t->sock.net->alloc(t->sock.net, PICO_SIZE_TCPHDR + opt_len);
daniele 3:b4047e8a0123 835
daniele 3:b4047e8a0123 836 if (!f) {
daniele 3:b4047e8a0123 837 return -1;
daniele 3:b4047e8a0123 838 }
daniele 3:b4047e8a0123 839
daniele 3:b4047e8a0123 840 hdr_rcv = (struct pico_tcp_hdr *) fr->transport_hdr;
daniele 3:b4047e8a0123 841
daniele 3:b4047e8a0123 842 f->sock = &t->sock;
daniele 3:b4047e8a0123 843 hdr = (struct pico_tcp_hdr *) f->transport_hdr;
daniele 3:b4047e8a0123 844 hdr->len = (PICO_SIZE_TCPHDR + opt_len) << 2 | t->jumbo;
daniele 3:b4047e8a0123 845 hdr->flags = PICO_TCP_RST;
daniele 3:b4047e8a0123 846 hdr->rwnd = short_be(t->wnd);
daniele 3:b4047e8a0123 847 tcp_set_space(t);
daniele 3:b4047e8a0123 848 tcp_add_options(t,f, PICO_TCP_RST, opt_len);
daniele 3:b4047e8a0123 849 hdr->trans.sport = t->sock.local_port;
daniele 3:b4047e8a0123 850 hdr->trans.dport = t->sock.remote_port;
daniele 3:b4047e8a0123 851 hdr->seq = long_be(t->snd_nxt);
daniele 3:b4047e8a0123 852
daniele 3:b4047e8a0123 853 /* check if state is synchronized */
daniele 3:b4047e8a0123 854 if (((s->state & PICO_SOCKET_STATE_TCP) > PICO_SOCKET_STATE_TCP_SYN_RECV)) {
daniele 3:b4047e8a0123 855 /* in synchronized state: send RST with seq = ack from previous segment */
daniele 3:b4047e8a0123 856 hdr->seq = hdr_rcv->ack;
daniele 3:b4047e8a0123 857 } else {
daniele 3:b4047e8a0123 858 /* non-synchronized state */
daniele 3:b4047e8a0123 859 }
daniele 3:b4047e8a0123 860
daniele 3:b4047e8a0123 861 hdr->ack = long_be(t->rcv_nxt);
daniele 3:b4047e8a0123 862 t->rcv_ackd = t->rcv_nxt;
daniele 3:b4047e8a0123 863 f->start = f->transport_hdr + PICO_SIZE_TCPHDR;
daniele 3:b4047e8a0123 864 hdr->rwnd = short_be(t->wnd);
daniele 3:b4047e8a0123 865 hdr->crc = 0;
daniele 3:b4047e8a0123 866 hdr->crc = short_be(pico_tcp_checksum_ipv4(f));
daniele 3:b4047e8a0123 867
daniele 3:b4047e8a0123 868 /* TCP: ENQUEUE to PROTO */
daniele 3:b4047e8a0123 869 pico_enqueue(&tcp_out, f);
daniele 3:b4047e8a0123 870
daniele 3:b4047e8a0123 871 /* goto CLOSED */
daniele 3:b4047e8a0123 872 //(t->sock).state &= 0x00FFU;
daniele 3:b4047e8a0123 873 //(t->sock).state |= PICO_SOCKET_STATE_TCP_CLOSED;
daniele 3:b4047e8a0123 874 (t->sock).state &= 0xFF00U;
daniele 3:b4047e8a0123 875 (t->sock).state |= PICO_SOCKET_STATE_CLOSED;
daniele 3:b4047e8a0123 876
daniele 3:b4047e8a0123 877 /* call EV_FIN wakeup before deleting */
daniele 3:b4047e8a0123 878 if ((t->sock).wakeup)
daniele 3:b4047e8a0123 879 (t->sock).wakeup(PICO_SOCK_EV_FIN, &(t->sock));
daniele 3:b4047e8a0123 880
daniele 3:b4047e8a0123 881 /* delete socket */
daniele 3:b4047e8a0123 882 pico_socket_del(&t->sock);
daniele 3:b4047e8a0123 883
daniele 3:b4047e8a0123 884 tcp_dbg("TCP SEND_RST >>>>>>>>>>>>>>> DONE, deleted socket\n");
daniele 3:b4047e8a0123 885
daniele 3:b4047e8a0123 886 return 0;
daniele 3:b4047e8a0123 887 }
daniele 3:b4047e8a0123 888
daniele 3:b4047e8a0123 889 int pico_tcp_reply_rst(struct pico_frame *fr)
daniele 3:b4047e8a0123 890 {
daniele 3:b4047e8a0123 891 struct pico_tcp_hdr *hdr;
daniele 3:b4047e8a0123 892 struct pico_frame *f;
daniele 3:b4047e8a0123 893 int size = PICO_SIZE_TCPHDR;
daniele 3:b4047e8a0123 894
daniele 3:b4047e8a0123 895 tcp_dbg("TCP>>>>>>>>>>>>>>>> sending RST ... <<<<<<<<<<<<<<<<<<\n");
daniele 3:b4047e8a0123 896
daniele 3:b4047e8a0123 897 f = fr->sock->net->alloc(fr->sock->net, size);
daniele 3:b4047e8a0123 898
daniele 3:b4047e8a0123 899 /* fill in IP data from original frame */
daniele 3:b4047e8a0123 900 // TODO if IPv4
daniele 3:b4047e8a0123 901 ((struct pico_ipv4_hdr *)(f->net_hdr))->dst.addr = ((struct pico_ipv4_hdr *)(fr->net_hdr))->src.addr;
daniele 3:b4047e8a0123 902 ((struct pico_ipv4_hdr *)(f->net_hdr))->src.addr = ((struct pico_ipv4_hdr *)(fr->net_hdr))->dst.addr;
daniele 3:b4047e8a0123 903
daniele 3:b4047e8a0123 904 /* fill in TCP data from original frame */
daniele 3:b4047e8a0123 905 ((struct pico_tcp_hdr *)(f->transport_hdr))->trans.dport = ((struct pico_tcp_hdr *)(fr->transport_hdr))->trans.sport;
daniele 3:b4047e8a0123 906 ((struct pico_tcp_hdr *)(f->transport_hdr))->trans.sport = ((struct pico_tcp_hdr *)(fr->transport_hdr))->trans.dport;
daniele 3:b4047e8a0123 907 hdr = (struct pico_tcp_hdr *) f->transport_hdr;
daniele 3:b4047e8a0123 908 hdr->len = size << 2;
daniele 3:b4047e8a0123 909 hdr->flags = PICO_TCP_RST | PICO_TCP_ACK;
daniele 3:b4047e8a0123 910 hdr->rwnd = 0;
daniele 3:b4047e8a0123 911 if (((struct pico_tcp_hdr *)(fr->transport_hdr))->flags & PICO_TCP_ACK) {
daniele 3:b4047e8a0123 912 hdr->seq = ((struct pico_tcp_hdr *)(fr->transport_hdr))->ack;
daniele 3:b4047e8a0123 913 } else {
daniele 3:b4047e8a0123 914 hdr->seq = 0U;
daniele 3:b4047e8a0123 915 }
daniele 3:b4047e8a0123 916
daniele 3:b4047e8a0123 917 hdr->ack = ((struct pico_tcp_hdr *)(fr->transport_hdr))->seq + short_be(fr->payload_len);
daniele 3:b4047e8a0123 918
daniele 3:b4047e8a0123 919 /* enqueue for transmission */
daniele 3:b4047e8a0123 920 pico_ipv4_frame_push(f,&(((struct pico_ipv4_hdr *)(f->net_hdr))->dst),PICO_PROTO_TCP);
daniele 3:b4047e8a0123 921
daniele 3:b4047e8a0123 922 return 0;
daniele 3:b4047e8a0123 923 }
daniele 3:b4047e8a0123 924
daniele 3:b4047e8a0123 925 static int tcp_nosync_rst(struct pico_socket *s, struct pico_frame *fr)
daniele 3:b4047e8a0123 926 {
daniele 3:b4047e8a0123 927 struct pico_socket_tcp *t = (struct pico_socket_tcp *) s;
daniele 3:b4047e8a0123 928 struct pico_frame *f;
daniele 3:b4047e8a0123 929 struct pico_tcp_hdr *hdr, *hdr_rcv;
daniele 3:b4047e8a0123 930 int opt_len = tcp_options_size(t, PICO_TCP_RST | PICO_TCP_ACK);
daniele 3:b4047e8a0123 931
daniele 3:b4047e8a0123 932 tcp_dbg("TCP SEND RST (NON-SYNC) >>>>>>>>>>>>>>>>>> state %x\n",(s->state & PICO_SOCKET_STATE_TCP));
daniele 3:b4047e8a0123 933 if (((s->state & PICO_SOCKET_STATE_TCP) == PICO_SOCKET_STATE_TCP_LISTEN)) {
daniele 3:b4047e8a0123 934 /* XXX TODO NOTE: to prevent the parent socket from trying to send, because this socket has no knowledge of dst IP !!! */
daniele 3:b4047e8a0123 935 return pico_tcp_reply_rst(fr);
daniele 3:b4047e8a0123 936 }
daniele 3:b4047e8a0123 937
daniele 3:b4047e8a0123 938 /***************************************************************************/
daniele 3:b4047e8a0123 939 /* sending RST */
daniele 3:b4047e8a0123 940 f = t->sock.net->alloc(t->sock.net, PICO_SIZE_TCPHDR + opt_len);
daniele 3:b4047e8a0123 941
daniele 3:b4047e8a0123 942 if (!f) {
daniele 3:b4047e8a0123 943 return -1;
daniele 3:b4047e8a0123 944 }
daniele 3:b4047e8a0123 945
daniele 3:b4047e8a0123 946 hdr_rcv = (struct pico_tcp_hdr *) fr->transport_hdr;
daniele 3:b4047e8a0123 947
daniele 3:b4047e8a0123 948 f->sock = &t->sock;
daniele 3:b4047e8a0123 949 hdr = (struct pico_tcp_hdr *) f->transport_hdr;
daniele 3:b4047e8a0123 950 hdr->len = (PICO_SIZE_TCPHDR + opt_len) << 2 | t->jumbo;
daniele 3:b4047e8a0123 951 hdr->flags = PICO_TCP_RST | PICO_TCP_ACK;
daniele 3:b4047e8a0123 952 hdr->rwnd = short_be(t->wnd);
daniele 3:b4047e8a0123 953 tcp_set_space(t);
daniele 3:b4047e8a0123 954 tcp_add_options(t,f, PICO_TCP_RST | PICO_TCP_ACK, opt_len);
daniele 3:b4047e8a0123 955 hdr->trans.sport = t->sock.local_port;
daniele 3:b4047e8a0123 956 hdr->trans.dport = t->sock.remote_port;
daniele 3:b4047e8a0123 957
daniele 3:b4047e8a0123 958 /* non-synchronized state */
daniele 3:b4047e8a0123 959 if (hdr_rcv->flags & PICO_TCP_ACK) {
daniele 3:b4047e8a0123 960 hdr->seq = hdr_rcv->ack;
daniele 3:b4047e8a0123 961 } else {
daniele 3:b4047e8a0123 962 hdr->seq = 0U;
daniele 3:b4047e8a0123 963 }
daniele 3:b4047e8a0123 964
daniele 3:b4047e8a0123 965 hdr->ack = hdr_rcv->seq + short_be(fr->payload_len);
daniele 3:b4047e8a0123 966
daniele 3:b4047e8a0123 967 t->rcv_ackd = t->rcv_nxt;
daniele 3:b4047e8a0123 968 f->start = f->transport_hdr + PICO_SIZE_TCPHDR;
daniele 3:b4047e8a0123 969 hdr->rwnd = short_be(t->wnd);
daniele 3:b4047e8a0123 970 hdr->crc = 0;
daniele 3:b4047e8a0123 971 hdr->crc = short_be(pico_tcp_checksum_ipv4(f));
daniele 3:b4047e8a0123 972
daniele 3:b4047e8a0123 973 /* TCP: ENQUEUE to PROTO */
daniele 3:b4047e8a0123 974 pico_enqueue(&tcp_out, f);
daniele 3:b4047e8a0123 975
daniele 3:b4047e8a0123 976 /***************************************************************************/
daniele 3:b4047e8a0123 977
daniele 3:b4047e8a0123 978 tcp_dbg("TCP SEND_RST (NON_SYNC) >>>>>>>>>>>>>>> DONE, ...\n");
daniele 3:b4047e8a0123 979
daniele 3:b4047e8a0123 980 return 0;
daniele 3:b4047e8a0123 981 }
daniele 3:b4047e8a0123 982
daniele 3:b4047e8a0123 983 static void tcp_send_fin(struct pico_socket_tcp *t)
daniele 3:b4047e8a0123 984 {
daniele 3:b4047e8a0123 985 struct pico_frame *f;
daniele 3:b4047e8a0123 986 struct pico_tcp_hdr *hdr;
daniele 3:b4047e8a0123 987 int opt_len = tcp_options_size(t, PICO_TCP_FIN);
daniele 3:b4047e8a0123 988 f = t->sock.net->alloc(t->sock.net, PICO_SIZE_TCPHDR + opt_len);
daniele 3:b4047e8a0123 989 if (!f) {
daniele 3:b4047e8a0123 990 return;
daniele 3:b4047e8a0123 991 }
daniele 3:b4047e8a0123 992 f->sock = &t->sock;
daniele 3:b4047e8a0123 993 hdr = (struct pico_tcp_hdr *) f->transport_hdr;
daniele 3:b4047e8a0123 994 hdr->len = (PICO_SIZE_TCPHDR + opt_len) << 2 | t->jumbo;
daniele 3:b4047e8a0123 995 hdr->flags = PICO_TCP_FIN | PICO_TCP_ACK;
daniele 3:b4047e8a0123 996 hdr->ack = long_be(t->rcv_nxt);
daniele 3:b4047e8a0123 997 t->rcv_ackd = t->rcv_nxt;
daniele 3:b4047e8a0123 998 hdr->rwnd = short_be(t->wnd);
daniele 3:b4047e8a0123 999 tcp_set_space(t);
daniele 3:b4047e8a0123 1000 tcp_add_options(t,f, PICO_TCP_FIN, opt_len);
daniele 3:b4047e8a0123 1001 hdr->trans.sport = t->sock.local_port;
daniele 3:b4047e8a0123 1002 hdr->trans.dport = t->sock.remote_port;
daniele 3:b4047e8a0123 1003 hdr->seq = long_be(t->snd_nxt);
daniele 3:b4047e8a0123 1004
daniele 3:b4047e8a0123 1005 f->start = f->transport_hdr + PICO_SIZE_TCPHDR;
daniele 3:b4047e8a0123 1006 hdr->rwnd = short_be(t->wnd);
daniele 3:b4047e8a0123 1007 hdr->crc = 0;
daniele 3:b4047e8a0123 1008 hdr->crc = short_be(pico_tcp_checksum_ipv4(f));
daniele 3:b4047e8a0123 1009 //tcp_dbg("SENDING FIN...\n");
daniele 3:b4047e8a0123 1010 /* TCP: ENQUEUE to PROTO ( Pure ACK ) */
daniele 3:b4047e8a0123 1011 pico_enqueue(&tcp_out, f);
daniele 3:b4047e8a0123 1012 t->snd_nxt++;
daniele 3:b4047e8a0123 1013 }
daniele 3:b4047e8a0123 1014
daniele 3:b4047e8a0123 1015 static void tcp_sack_prepare(struct pico_socket_tcp *t)
daniele 3:b4047e8a0123 1016 {
daniele 3:b4047e8a0123 1017 struct pico_frame *pkt;
daniele 3:b4047e8a0123 1018 uint32_t left=0, right=0;
daniele 3:b4047e8a0123 1019 struct tcp_sack_block *sb;
daniele 3:b4047e8a0123 1020 int n = 0;
daniele 3:b4047e8a0123 1021 if (t->sacks) /* previous sacks are pending */
daniele 3:b4047e8a0123 1022 return;
daniele 3:b4047e8a0123 1023
daniele 3:b4047e8a0123 1024 pkt = first_segment(&t->tcpq_in);
daniele 3:b4047e8a0123 1025 while(n < 3) {
daniele 3:b4047e8a0123 1026 if (!pkt) {
daniele 3:b4047e8a0123 1027 if(left) {
daniele 3:b4047e8a0123 1028 sb = pico_zalloc(sizeof(struct tcp_sack_block));
daniele 3:b4047e8a0123 1029 if (!sb)
daniele 3:b4047e8a0123 1030 break;
daniele 3:b4047e8a0123 1031 sb->left = long_be(left);
daniele 3:b4047e8a0123 1032 sb->right = long_be(right);
daniele 3:b4047e8a0123 1033 n++;
daniele 3:b4047e8a0123 1034 sb->next = t->sacks;
daniele 3:b4047e8a0123 1035 t->sacks = sb;
daniele 3:b4047e8a0123 1036 left = 0;
daniele 3:b4047e8a0123 1037 right = 0;
daniele 3:b4047e8a0123 1038 }
daniele 3:b4047e8a0123 1039 break;
daniele 3:b4047e8a0123 1040 }
daniele 3:b4047e8a0123 1041 if ((SEQN(pkt) < t->rcv_nxt)) {
daniele 3:b4047e8a0123 1042 pkt = next_segment(&t->tcpq_in, pkt);
daniele 3:b4047e8a0123 1043 continue;
daniele 3:b4047e8a0123 1044 }
daniele 3:b4047e8a0123 1045 if (!left) {
daniele 3:b4047e8a0123 1046 left = SEQN(pkt);
daniele 3:b4047e8a0123 1047 right = SEQN(pkt) + pkt->payload_len;
daniele 3:b4047e8a0123 1048 pkt = next_segment(&t->tcpq_in, pkt);
daniele 3:b4047e8a0123 1049 continue;
daniele 3:b4047e8a0123 1050 }
daniele 3:b4047e8a0123 1051 if(SEQN(pkt) == (right + 1)) {
daniele 3:b4047e8a0123 1052 right += pkt->payload_len;
daniele 3:b4047e8a0123 1053 pkt = next_segment(&t->tcpq_in, pkt);
daniele 3:b4047e8a0123 1054 continue;
daniele 3:b4047e8a0123 1055 } else {
daniele 3:b4047e8a0123 1056 sb = pico_zalloc(sizeof(struct tcp_sack_block));
daniele 3:b4047e8a0123 1057 if (!sb)
daniele 3:b4047e8a0123 1058 break;
daniele 3:b4047e8a0123 1059 sb->left = long_be(left);
daniele 3:b4047e8a0123 1060 sb->right = long_be(right);
daniele 3:b4047e8a0123 1061 n++;
daniele 3:b4047e8a0123 1062 sb->next = t->sacks;
daniele 3:b4047e8a0123 1063 t->sacks = sb;
daniele 3:b4047e8a0123 1064 left = 0;
daniele 3:b4047e8a0123 1065 right = 0;
daniele 3:b4047e8a0123 1066 pkt = next_segment(&t->tcpq_in, pkt);
daniele 3:b4047e8a0123 1067 }
daniele 3:b4047e8a0123 1068 }
daniele 3:b4047e8a0123 1069 }
daniele 3:b4047e8a0123 1070
daniele 3:b4047e8a0123 1071 static int tcp_data_in(struct pico_socket *s, struct pico_frame *f)
daniele 3:b4047e8a0123 1072 {
daniele 3:b4047e8a0123 1073 struct pico_socket_tcp *t = (struct pico_socket_tcp *)s;
daniele 3:b4047e8a0123 1074 struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *) f->transport_hdr;
daniele 3:b4047e8a0123 1075
daniele 3:b4047e8a0123 1076 if (((hdr->len & 0xf0) >> 2) <= f->transport_len) {
daniele 3:b4047e8a0123 1077 tcp_parse_options(f);
daniele 3:b4047e8a0123 1078 f->payload = f->transport_hdr + ((hdr->len & 0xf0) >>2);
daniele 3:b4047e8a0123 1079 f->payload_len = f->transport_len - ((hdr->len & 0xf0) >>2);
daniele 3:b4047e8a0123 1080
daniele 3:b4047e8a0123 1081 if (seq_compare(SEQN(f), t->rcv_nxt) >= 0) {
daniele 3:b4047e8a0123 1082 struct pico_frame *cpy = pico_frame_copy(f);
daniele 3:b4047e8a0123 1083 struct pico_frame *nxt;
daniele 3:b4047e8a0123 1084 /* Enqueue: try to put into RCV buffer */
daniele 3:b4047e8a0123 1085 if (pico_enqueue_segment(&t->tcpq_in, cpy) <= 0) {
daniele 3:b4047e8a0123 1086 pico_frame_discard(cpy);
daniele 3:b4047e8a0123 1087 return -1;
daniele 3:b4047e8a0123 1088 }
daniele 3:b4047e8a0123 1089 if (seq_compare(SEQN(f), t->rcv_nxt) == 0) { /* Exactly what we expected */
daniele 3:b4047e8a0123 1090 t->rcv_nxt = SEQN(f) + f->payload_len;
daniele 3:b4047e8a0123 1091 nxt = peek_segment(&t->tcpq_in, t->rcv_nxt);
daniele 3:b4047e8a0123 1092 while(nxt) {
daniele 3:b4047e8a0123 1093 tcp_dbg("scrolling rcv_nxt...%08x\n", t->rcv_nxt);
daniele 3:b4047e8a0123 1094 t->rcv_nxt += f->payload_len;
daniele 3:b4047e8a0123 1095 nxt = peek_segment(&t->tcpq_in, t->rcv_nxt);
daniele 3:b4047e8a0123 1096 }
daniele 3:b4047e8a0123 1097 t->sock.ev_pending |= PICO_SOCK_EV_RD;
daniele 3:b4047e8a0123 1098 t->rcv_nxt = SEQN(f) + f->payload_len;
daniele 3:b4047e8a0123 1099 } else {
daniele 3:b4047e8a0123 1100 tcp_dbg("TCP> lo segment. Possible retransmission. (exp: %x got: %x)\n", t->rcv_nxt, SEQN(f));
daniele 3:b4047e8a0123 1101 }
daniele 3:b4047e8a0123 1102 } else {
daniele 3:b4047e8a0123 1103 tcp_dbg("TCP> hi segment. Possible packet loss. I'll dupack this. (exp: %x got: %x)\n", t->rcv_nxt, SEQN(f));
daniele 3:b4047e8a0123 1104 if (t->sack_ok) {
daniele 3:b4047e8a0123 1105 tcp_sack_prepare(t);
daniele 3:b4047e8a0123 1106 }
daniele 3:b4047e8a0123 1107 }
daniele 3:b4047e8a0123 1108 /* In either case, ack til recv_nxt. */
daniele 3:b4047e8a0123 1109 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)) {
daniele 3:b4047e8a0123 1110 //tcp_dbg("SENDACK CALLED FROM OUTSIDE tcp_synack, state %x\n",t->sock.state);
daniele 3:b4047e8a0123 1111 tcp_send_ack(t);
daniele 3:b4047e8a0123 1112 } else {
daniele 3:b4047e8a0123 1113 //tcp_dbg("SENDACK PREVENTED IN SYNSENT STATE\n");
daniele 3:b4047e8a0123 1114 }
daniele 3:b4047e8a0123 1115 return 0;
daniele 3:b4047e8a0123 1116 } else {
daniele 3:b4047e8a0123 1117 tcp_dbg("TCP: invalid data in pkt len, exp: %d, got %d\n", (hdr->len & 0xf0) >> 2, f->transport_len);
daniele 3:b4047e8a0123 1118 return -1;
daniele 3:b4047e8a0123 1119 }
daniele 3:b4047e8a0123 1120 }
daniele 3:b4047e8a0123 1121
daniele 3:b4047e8a0123 1122 static int tcp_ack_advance_una(struct pico_socket_tcp *t, struct pico_frame *f)
daniele 3:b4047e8a0123 1123 {
daniele 3:b4047e8a0123 1124 int ret = release_all_until(&t->tcpq_out, ACKN(f));
daniele 3:b4047e8a0123 1125 if (ret > 0)
daniele 3:b4047e8a0123 1126 t->sock.ev_pending |= PICO_SOCK_EV_WR;
daniele 3:b4047e8a0123 1127 return ret;
daniele 3:b4047e8a0123 1128 }
daniele 3:b4047e8a0123 1129
daniele 3:b4047e8a0123 1130 static uint16_t time_diff(unsigned long a, unsigned long b)
daniele 3:b4047e8a0123 1131 {
daniele 3:b4047e8a0123 1132 if (a >= b)
daniele 3:b4047e8a0123 1133 return (a - b);
daniele 3:b4047e8a0123 1134 else
daniele 3:b4047e8a0123 1135 return (b - a);
daniele 3:b4047e8a0123 1136 }
daniele 3:b4047e8a0123 1137
daniele 3:b4047e8a0123 1138 static void tcp_rtt(struct pico_socket_tcp *t, uint32_t rtt)
daniele 3:b4047e8a0123 1139 {
daniele 3:b4047e8a0123 1140
daniele 3:b4047e8a0123 1141 uint32_t avg = t->avg_rtt;
daniele 3:b4047e8a0123 1142 uint32_t rvar = t->rttvar;
daniele 3:b4047e8a0123 1143 if (!avg) {
daniele 3:b4047e8a0123 1144 /* This follows RFC2988
daniele 3:b4047e8a0123 1145 * (2.2) When the first RTT measurement R is made, the host MUST set
daniele 3:b4047e8a0123 1146 *
daniele 3:b4047e8a0123 1147 * SRTT <- R
daniele 3:b4047e8a0123 1148 * RTTVAR <- R/2
daniele 3:b4047e8a0123 1149 * RTO <- SRTT + max (G, K*RTTVAR)
daniele 3:b4047e8a0123 1150 */
daniele 3:b4047e8a0123 1151 t->avg_rtt = rtt;
daniele 3:b4047e8a0123 1152 t->rttvar = rtt >> 1;
daniele 3:b4047e8a0123 1153 t->rto = t->avg_rtt + (t->rttvar << 4);
daniele 3:b4047e8a0123 1154 } else {
daniele 3:b4047e8a0123 1155 int var = (t->avg_rtt - rtt);
daniele 3:b4047e8a0123 1156 if (var < 0)
daniele 3:b4047e8a0123 1157 var = 0-var;
daniele 3:b4047e8a0123 1158 /* RFC2988, section (2.3). Alpha and beta are the ones suggested. */
daniele 3:b4047e8a0123 1159
daniele 3:b4047e8a0123 1160 /* First, evaluate a new value for the rttvar */
daniele 3:b4047e8a0123 1161 t->rttvar <<= 2;
daniele 3:b4047e8a0123 1162 t->rttvar -= rvar;
daniele 3:b4047e8a0123 1163 t->rttvar += var;
daniele 3:b4047e8a0123 1164 t->rttvar >>= 2;
daniele 3:b4047e8a0123 1165
daniele 3:b4047e8a0123 1166 /* Then, calculate the new avg_rtt */
daniele 3:b4047e8a0123 1167 t->avg_rtt <<= 3;
daniele 3:b4047e8a0123 1168 t->avg_rtt -= avg;
daniele 3:b4047e8a0123 1169 t->avg_rtt += rtt;
daniele 3:b4047e8a0123 1170 t->avg_rtt >>= 3;
daniele 3:b4047e8a0123 1171
daniele 3:b4047e8a0123 1172 /* Finally, assign a new value for the RTO, as specified in the RFC, with K=4 */
daniele 3:b4047e8a0123 1173 t->rto = t->avg_rtt + (t->rttvar << 2);
daniele 3:b4047e8a0123 1174 }
daniele 3:b4047e8a0123 1175 tcp_dbg(" -----=============== RTT AVG: %u RTTVAR: %u RTO: %u ======================----\n", t->avg_rtt, t->rttvar, t->rto);
daniele 3:b4047e8a0123 1176 }
daniele 3:b4047e8a0123 1177
daniele 3:b4047e8a0123 1178 static void tcp_congestion_control(struct pico_socket_tcp *t)
daniele 3:b4047e8a0123 1179 {
daniele 3:b4047e8a0123 1180 if (t->x_mode > PICO_TCP_LOOKAHEAD)
daniele 3:b4047e8a0123 1181 return;
daniele 3:b4047e8a0123 1182 if (t->cwnd > t->tcpq_out.frames) {
daniele 3:b4047e8a0123 1183 tcp_dbg("Limited by app: %d\n", t->cwnd);
daniele 3:b4047e8a0123 1184 return;
daniele 3:b4047e8a0123 1185 }
daniele 3:b4047e8a0123 1186 tcp_dbg("Doing congestion control\n");
daniele 3:b4047e8a0123 1187 if (t->cwnd < t->ssthresh) {
daniele 3:b4047e8a0123 1188 t->cwnd++;
daniele 3:b4047e8a0123 1189 } else {
daniele 3:b4047e8a0123 1190 t->cwnd_counter++;
daniele 3:b4047e8a0123 1191 if (t->cwnd_counter >= t->cwnd) {
daniele 3:b4047e8a0123 1192 t->cwnd++;
daniele 3:b4047e8a0123 1193 t->cwnd_counter = 0;
daniele 3:b4047e8a0123 1194 }
daniele 3:b4047e8a0123 1195 }
daniele 3:b4047e8a0123 1196 tcp_dbg("TCP_CWND, %lu, %u, %u, %u\n", pico_tick, t->cwnd, t->ssthresh, t->in_flight);
daniele 3:b4047e8a0123 1197 }
daniele 3:b4047e8a0123 1198
daniele 3:b4047e8a0123 1199 static void add_retransmission_timer(struct pico_socket_tcp *t, unsigned long next_ts);
daniele 3:b4047e8a0123 1200 static void tcp_retrans_timeout(unsigned long val, void *sock)
daniele 3:b4047e8a0123 1201 {
daniele 3:b4047e8a0123 1202 struct pico_socket_tcp *t = (struct pico_socket_tcp *) sock;
daniele 3:b4047e8a0123 1203 struct pico_frame *f = NULL;
daniele 3:b4047e8a0123 1204 unsigned long limit = val - t->rto;
daniele 3:b4047e8a0123 1205 struct pico_tcp_hdr *hdr;
daniele 3:b4047e8a0123 1206 if(t->sock.net && ((t->sock.state & 0xFF00) == PICO_SOCKET_STATE_TCP_ESTABLISHED))
daniele 3:b4047e8a0123 1207 {
daniele 3:b4047e8a0123 1208 tcp_dbg("\n\nTIMEOUT! backoff = %d\n", t->backoff);
daniele 3:b4047e8a0123 1209 /* was timer cancelled? */
daniele 3:b4047e8a0123 1210 if (t->timer_running == 0) {
daniele 3:b4047e8a0123 1211 add_retransmission_timer(t, 0);
daniele 3:b4047e8a0123 1212 return;
daniele 3:b4047e8a0123 1213 }
daniele 3:b4047e8a0123 1214 t->timer_running--;
daniele 3:b4047e8a0123 1215
daniele 3:b4047e8a0123 1216 f = first_segment(&t->tcpq_out);
daniele 3:b4047e8a0123 1217 while (f) {
daniele 3:b4047e8a0123 1218 if ((t->x_mode == PICO_TCP_WINDOW_FULL) ||
daniele 3:b4047e8a0123 1219 ((f->timestamp != 0) && (f->timestamp <= limit))) {
daniele 3:b4047e8a0123 1220 struct pico_frame *cpy;
daniele 3:b4047e8a0123 1221 hdr = (struct pico_tcp_hdr *)f->transport_hdr;
daniele 3:b4047e8a0123 1222 tcp_dbg("TCP BLACKOUT> TIMED OUT (output) frame %08x, len= %d rto=%d\n", SEQN(f), f->payload_len, t->rto);
daniele 3:b4047e8a0123 1223 if ((t->x_mode != PICO_TCP_WINDOW_FULL) ) {
daniele 3:b4047e8a0123 1224 t->x_mode = PICO_TCP_BLACKOUT;
daniele 3:b4047e8a0123 1225 tcp_dbg("Mode: Blackout.\n");
daniele 3:b4047e8a0123 1226 t->cwnd = PICO_TCP_IW;
daniele 3:b4047e8a0123 1227 t->in_flight = 0;
daniele 3:b4047e8a0123 1228 }
daniele 3:b4047e8a0123 1229 f->timestamp = pico_tick;
daniele 3:b4047e8a0123 1230 tcp_add_options(t, f, 0, f->transport_len - f->payload_len - PICO_SIZE_TCPHDR);
daniele 3:b4047e8a0123 1231 hdr->rwnd = short_be(t->wnd);
daniele 3:b4047e8a0123 1232 hdr->flags |= PICO_TCP_PSH;
daniele 3:b4047e8a0123 1233 hdr->ack = long_be(t->rcv_nxt);
daniele 3:b4047e8a0123 1234 hdr->crc = 0;
daniele 3:b4047e8a0123 1235 hdr->crc = short_be(pico_tcp_checksum_ipv4(f));
daniele 3:b4047e8a0123 1236 /* TCP: ENQUEUE to PROTO ( retransmit )*/
daniele 3:b4047e8a0123 1237 cpy = pico_frame_copy(f);
daniele 3:b4047e8a0123 1238 if (pico_enqueue(&tcp_out, cpy) > 0) {
daniele 3:b4047e8a0123 1239 t->backoff++;
daniele 3:b4047e8a0123 1240 add_retransmission_timer(t, (t->rto << t->backoff) + pico_tick);
daniele 3:b4047e8a0123 1241 tcp_dbg("TCP_CWND, %lu, %u, %u, %u\n", pico_tick, t->cwnd, t->ssthresh, t->in_flight);
daniele 3:b4047e8a0123 1242 return;
daniele 3:b4047e8a0123 1243 } else {
daniele 3:b4047e8a0123 1244 add_retransmission_timer(t, (t->rto << t->backoff) + pico_tick);
daniele 3:b4047e8a0123 1245 pico_frame_discard(cpy);
daniele 3:b4047e8a0123 1246 }
daniele 3:b4047e8a0123 1247 }
daniele 3:b4047e8a0123 1248 f = next_segment(&t->tcpq_out, f);
daniele 3:b4047e8a0123 1249 }
daniele 3:b4047e8a0123 1250 t->backoff = 0;
daniele 3:b4047e8a0123 1251 add_retransmission_timer(t, 0);
daniele 3:b4047e8a0123 1252 if (t->tcpq_out.size < t->tcpq_out.max_size)
daniele 3:b4047e8a0123 1253 t->sock.ev_pending |= PICO_SOCK_EV_WR;
daniele 3:b4047e8a0123 1254 return;
daniele 3:b4047e8a0123 1255 }
daniele 3:b4047e8a0123 1256 }
daniele 3:b4047e8a0123 1257
daniele 3:b4047e8a0123 1258 static void add_retransmission_timer(struct pico_socket_tcp *t, unsigned long next_ts)
daniele 3:b4047e8a0123 1259 {
daniele 3:b4047e8a0123 1260 struct pico_tree_node * index;
daniele 3:b4047e8a0123 1261
daniele 3:b4047e8a0123 1262 if (t->timer_running > 0)
daniele 3:b4047e8a0123 1263 return;
daniele 3:b4047e8a0123 1264
daniele 3:b4047e8a0123 1265 if (next_ts == 0) {
daniele 3:b4047e8a0123 1266 struct pico_frame *f;
daniele 3:b4047e8a0123 1267
daniele 3:b4047e8a0123 1268 pico_tree_foreach(index,&t->tcpq_out.pool){
daniele 3:b4047e8a0123 1269 f = index->keyValue;
daniele 3:b4047e8a0123 1270 if (((next_ts == 0) || (f->timestamp < next_ts)) && (f->timestamp > 0)) {
daniele 3:b4047e8a0123 1271 next_ts = f->timestamp;
daniele 3:b4047e8a0123 1272 }
daniele 3:b4047e8a0123 1273 }
daniele 3:b4047e8a0123 1274 }
daniele 3:b4047e8a0123 1275 if (next_ts > 0) {
daniele 3:b4047e8a0123 1276 if ((next_ts + t->rto) > pico_tick) {
daniele 3:b4047e8a0123 1277 pico_timer_add(next_ts + t->rto - pico_tick, tcp_retrans_timeout, t);
daniele 3:b4047e8a0123 1278 } else {
daniele 3:b4047e8a0123 1279 pico_timer_add(1, tcp_retrans_timeout, t);
daniele 3:b4047e8a0123 1280 }
daniele 3:b4047e8a0123 1281 t->timer_running++;
daniele 3:b4047e8a0123 1282 }
daniele 3:b4047e8a0123 1283 }
daniele 3:b4047e8a0123 1284
daniele 3:b4047e8a0123 1285 static int tcp_retrans(struct pico_socket_tcp *t, struct pico_frame *f)
daniele 3:b4047e8a0123 1286 {
daniele 3:b4047e8a0123 1287 struct pico_frame *cpy;
daniele 3:b4047e8a0123 1288 struct pico_tcp_hdr *hdr;
daniele 3:b4047e8a0123 1289 if (f) {
daniele 3:b4047e8a0123 1290 hdr = (struct pico_tcp_hdr *)f->transport_hdr;
daniele 3:b4047e8a0123 1291 tcp_dbg("TCP> RETRANS (by dupack) frame %08x, len= %d\n", SEQN(f), f->payload_len);
daniele 3:b4047e8a0123 1292 f->timestamp = pico_tick;
daniele 3:b4047e8a0123 1293 tcp_add_options(t, f, 0, f->transport_len - f->payload_len - PICO_SIZE_TCPHDR);
daniele 3:b4047e8a0123 1294 hdr->rwnd = short_be(t->wnd);
daniele 3:b4047e8a0123 1295 hdr->flags |= PICO_TCP_PSH;
daniele 3:b4047e8a0123 1296 hdr->ack = long_be(t->rcv_nxt);
daniele 3:b4047e8a0123 1297 hdr->crc = 0;
daniele 3:b4047e8a0123 1298 hdr->crc = short_be(pico_tcp_checksum_ipv4(f));
daniele 3:b4047e8a0123 1299 /* TCP: ENQUEUE to PROTO ( retransmit )*/
daniele 3:b4047e8a0123 1300 cpy = pico_frame_copy(f);
daniele 3:b4047e8a0123 1301 if (pico_enqueue(&tcp_out, cpy) > 0) {
daniele 3:b4047e8a0123 1302 t->in_flight++;
daniele 3:b4047e8a0123 1303 t->snd_last_out = SEQN(cpy);
daniele 3:b4047e8a0123 1304 add_retransmission_timer(t, pico_tick + t->rto);
daniele 3:b4047e8a0123 1305 } else {
daniele 3:b4047e8a0123 1306 pico_frame_discard(cpy);
daniele 3:b4047e8a0123 1307 }
daniele 3:b4047e8a0123 1308 return(f->payload_len);
daniele 3:b4047e8a0123 1309 }
daniele 3:b4047e8a0123 1310 return 0;
daniele 3:b4047e8a0123 1311 }
daniele 3:b4047e8a0123 1312
daniele 3:b4047e8a0123 1313 #ifdef TCP_ACK_DBG
daniele 3:b4047e8a0123 1314 static void tcp_ack_dbg(struct pico_socket *s, struct pico_frame *f)
daniele 3:b4047e8a0123 1315 {
daniele 3:b4047e8a0123 1316 uint32_t una, nxt, ack, cur;
daniele 3:b4047e8a0123 1317 struct pico_frame *una_f = NULL, *cur_f;
daniele 3:b4047e8a0123 1318 struct pico_tree_node *idx;
daniele 3:b4047e8a0123 1319 struct pico_socket_tcp *t = (struct pico_socket_tcp *)s;
daniele 3:b4047e8a0123 1320 char info[64];
daniele 3:b4047e8a0123 1321 char tmp[64];
daniele 3:b4047e8a0123 1322 ack = ACKN(f);
daniele 3:b4047e8a0123 1323 nxt = t->snd_nxt;
daniele 3:b4047e8a0123 1324 tcp_dbg("===================================\n");
daniele 3:b4047e8a0123 1325 tcp_dbg("Queue out (%d/%d). ACKED=%08x\n", t->tcpq_out.size, t->tcpq_out.max_size, ack);
daniele 3:b4047e8a0123 1326
daniele 3:b4047e8a0123 1327 pico_tree_foreach(idx, &t->tcpq_out.pool) {
daniele 3:b4047e8a0123 1328 info[0] = 0;
daniele 3:b4047e8a0123 1329 cur_f = idx->keyValue;
daniele 3:b4047e8a0123 1330 cur = SEQN(cur_f);
daniele 3:b4047e8a0123 1331 if (!una_f) {
daniele 3:b4047e8a0123 1332 una_f = cur_f;
daniele 3:b4047e8a0123 1333 una = SEQN(una_f);
daniele 3:b4047e8a0123 1334 }
daniele 3:b4047e8a0123 1335
daniele 3:b4047e8a0123 1336 if (cur == nxt) {
daniele 3:b4047e8a0123 1337 strncpy(tmp, info, strlen(info));
daniele 3:b4047e8a0123 1338 snprintf(info,64, "%s SND_NXT", tmp);
daniele 3:b4047e8a0123 1339 }
daniele 3:b4047e8a0123 1340 if (cur == ack) {
daniele 3:b4047e8a0123 1341 strncpy(tmp, info, strlen(info));
daniele 3:b4047e8a0123 1342 snprintf(info,64, "%s ACK", tmp);
daniele 3:b4047e8a0123 1343 }
daniele 3:b4047e8a0123 1344 if (cur == una) {
daniele 3:b4047e8a0123 1345 strncpy(tmp, info, strlen(info));
daniele 3:b4047e8a0123 1346 snprintf(info,64, "%s SND_UNA", tmp);
daniele 3:b4047e8a0123 1347 }
daniele 3:b4047e8a0123 1348 if (cur == t->snd_last) {
daniele 3:b4047e8a0123 1349 strncpy(tmp, info, strlen(info));
daniele 3:b4047e8a0123 1350 snprintf(info,64, "%s SND_LAST", tmp);
daniele 3:b4047e8a0123 1351 }
daniele 3:b4047e8a0123 1352 tcp_dbg("%08x %d%s\n", cur, cur_f->payload_len, info);
daniele 3:b4047e8a0123 1353
daniele 3:b4047e8a0123 1354 }
daniele 3:b4047e8a0123 1355 tcp_dbg("SND_NXT is %08x, snd_LAST is %08x", nxt, t->snd_last);
daniele 3:b4047e8a0123 1356 tcp_dbg("===================================\n");
daniele 3:b4047e8a0123 1357 tcp_dbg("\n\n");
daniele 3:b4047e8a0123 1358 }
daniele 3:b4047e8a0123 1359 #endif
daniele 3:b4047e8a0123 1360
daniele 3:b4047e8a0123 1361 static int tcp_ack(struct pico_socket *s, struct pico_frame *f)
daniele 3:b4047e8a0123 1362 {
daniele 3:b4047e8a0123 1363 struct pico_frame *f_new; /* use with Nagle to push to out queue */
daniele 3:b4047e8a0123 1364 struct pico_socket_tcp *t = (struct pico_socket_tcp *)s;
daniele 3:b4047e8a0123 1365 struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *) f->transport_hdr;
daniele 3:b4047e8a0123 1366 uint32_t rtt = 0;
daniele 3:b4047e8a0123 1367 int acked = 0;
daniele 3:b4047e8a0123 1368 struct pico_frame *una = NULL;
daniele 3:b4047e8a0123 1369 if ((hdr->flags & PICO_TCP_ACK) == 0)
daniele 3:b4047e8a0123 1370 return -1;
daniele 3:b4047e8a0123 1371
daniele 3:b4047e8a0123 1372 #ifdef TCP_ACK_DBG
daniele 3:b4047e8a0123 1373 tcp_ack_dbg(s,f);
daniele 3:b4047e8a0123 1374 #endif
daniele 3:b4047e8a0123 1375
daniele 3:b4047e8a0123 1376 tcp_parse_options(f);
daniele 3:b4047e8a0123 1377 t->recv_wnd = short_be(hdr->rwnd);
daniele 3:b4047e8a0123 1378
daniele 3:b4047e8a0123 1379 acked = tcp_ack_advance_una(t, f);
daniele 3:b4047e8a0123 1380 una = first_segment(&t->tcpq_out);
daniele 3:b4047e8a0123 1381
daniele 3:b4047e8a0123 1382 if ((t->x_mode == PICO_TCP_BLACKOUT) ||
daniele 3:b4047e8a0123 1383 ((t->x_mode == PICO_TCP_WINDOW_FULL) && ((t->recv_wnd << t->recv_wnd_scale) > t->mss))) {
daniele 3:b4047e8a0123 1384 tcp_dbg("Re-entering look-ahead...\n\n\n");
daniele 3:b4047e8a0123 1385 t->x_mode = PICO_TCP_LOOKAHEAD;
daniele 3:b4047e8a0123 1386 t->backoff = 0;
daniele 3:b4047e8a0123 1387 }
daniele 3:b4047e8a0123 1388
daniele 3:b4047e8a0123 1389 /* One should be acked. */
daniele 3:b4047e8a0123 1390 // if ((acked == 0) && (t->in_flight > 0))
daniele 3:b4047e8a0123 1391 if ((acked == 0) && (f->payload_len == 0) && (t->in_flight > 0))
daniele 3:b4047e8a0123 1392 t->in_flight--;
daniele 3:b4047e8a0123 1393 if (!una || acked > 0) {
daniele 3:b4047e8a0123 1394 t->x_mode = PICO_TCP_LOOKAHEAD;
daniele 3:b4047e8a0123 1395 tcp_dbg("Mode: Look-ahead. In flight: %d/%d buf: %d\n", t->in_flight, t->cwnd, t->tcpq_out.frames);
daniele 3:b4047e8a0123 1396 t->backoff = 0;
daniele 3:b4047e8a0123 1397
daniele 3:b4047e8a0123 1398 /* Do rtt/rttvar/rto calculations */
daniele 3:b4047e8a0123 1399 if(una && (una->timestamp != 0)) {
daniele 3:b4047e8a0123 1400 rtt = time_diff(pico_tick, una->timestamp);
daniele 3:b4047e8a0123 1401 if (rtt)
daniele 3:b4047e8a0123 1402 tcp_rtt(t, rtt);
daniele 3:b4047e8a0123 1403 }
daniele 3:b4047e8a0123 1404
daniele 3:b4047e8a0123 1405 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));
daniele 3:b4047e8a0123 1406 if (acked > t->in_flight) {
daniele 3:b4047e8a0123 1407 tcp_dbg("WARNING: in flight < 0\n");
daniele 3:b4047e8a0123 1408 t->in_flight = 0;
daniele 3:b4047e8a0123 1409 } else
daniele 3:b4047e8a0123 1410 t->in_flight -= (acked);
daniele 3:b4047e8a0123 1411
daniele 3:b4047e8a0123 1412 } else if ((t->snd_old_ack == ACKN(f)) && /* We've just seen this ack, and... */
daniele 3:b4047e8a0123 1413 ((0 == (hdr->flags & (PICO_TCP_PSH | PICO_TCP_SYN))) &&
daniele 3:b4047e8a0123 1414 (f->payload_len == 0)) && /* This is a pure ack, and... */
daniele 3:b4047e8a0123 1415 (ACKN(f) != t->snd_nxt)) /* There is something in flight awaiting to be acked... */
daniele 3:b4047e8a0123 1416 {
daniele 3:b4047e8a0123 1417 /* Process incoming duplicate ack. */
daniele 3:b4047e8a0123 1418 if (t->x_mode < PICO_TCP_RECOVER) {
daniele 3:b4047e8a0123 1419 t->x_mode++;
daniele 3:b4047e8a0123 1420 tcp_dbg("Mode: DUPACK %d, due to PURE ACK %0x, len = %d\n", t->x_mode, SEQN(f), f->payload_len);
daniele 3:b4047e8a0123 1421 tcp_dbg("ACK: %x - QUEUE: %x\n",ACKN(f), SEQN(first_segment(&t->tcpq_out)));
daniele 3:b4047e8a0123 1422 if (t->x_mode == PICO_TCP_RECOVER) { /* Switching mode */
daniele 3:b4047e8a0123 1423 t->snd_retry = SEQN(first_segment(&t->tcpq_out));
daniele 3:b4047e8a0123 1424 if (t->ssthresh > t->cwnd)
daniele 3:b4047e8a0123 1425 t->ssthresh >>=2;
daniele 3:b4047e8a0123 1426 else
daniele 3:b4047e8a0123 1427 t->ssthresh = (t->cwnd >> 1);
daniele 3:b4047e8a0123 1428 if (t->ssthresh < 2)
daniele 3:b4047e8a0123 1429 t->ssthresh = 2;
daniele 3:b4047e8a0123 1430 }
daniele 3:b4047e8a0123 1431 } else if (t->x_mode == PICO_TCP_RECOVER) {
daniele 3:b4047e8a0123 1432 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));
daniele 3:b4047e8a0123 1433 if (t->in_flight <= t->cwnd) {
daniele 3:b4047e8a0123 1434 struct pico_frame *nxt = peek_segment(&t->tcpq_out, t->snd_retry);
daniele 3:b4047e8a0123 1435 if (!nxt)
daniele 3:b4047e8a0123 1436 nxt = first_segment(&t->tcpq_out);
daniele 3:b4047e8a0123 1437
daniele 3:b4047e8a0123 1438 while (nxt && (nxt->flags & PICO_FRAME_FLAG_SACKED) && (nxt != first_segment(&t->tcpq_out))) {
daniele 3:b4047e8a0123 1439 tcp_dbg("Skipping %08x because it is sacked.\n", SEQN(nxt));
daniele 3:b4047e8a0123 1440 nxt = next_segment(&t->tcpq_out, nxt);
daniele 3:b4047e8a0123 1441 }
daniele 3:b4047e8a0123 1442
daniele 3:b4047e8a0123 1443 if (nxt && (seq_compare(SEQN(nxt), t->snd_nxt)) > 0)
daniele 3:b4047e8a0123 1444 nxt = NULL;
daniele 3:b4047e8a0123 1445 if (nxt && (seq_compare(SEQN(nxt), SEQN(first_segment(&t->tcpq_out))) > (t->recv_wnd << t->recv_wnd_scale)))
daniele 3:b4047e8a0123 1446 nxt = NULL;
daniele 3:b4047e8a0123 1447
daniele 3:b4047e8a0123 1448 if(!nxt)
daniele 3:b4047e8a0123 1449 nxt = first_segment(&t->tcpq_out);
daniele 3:b4047e8a0123 1450 if (nxt) {
daniele 3:b4047e8a0123 1451 tcp_retrans(t, peek_segment(&t->tcpq_out, t->snd_retry));
daniele 3:b4047e8a0123 1452 t->snd_retry = SEQN(nxt);
daniele 3:b4047e8a0123 1453 }
daniele 3:b4047e8a0123 1454 }
daniele 3:b4047e8a0123 1455
daniele 3:b4047e8a0123 1456 if (++t->cwnd_counter > 1) {
daniele 3:b4047e8a0123 1457 t->cwnd--;
daniele 3:b4047e8a0123 1458 if (t->cwnd < 2)
daniele 3:b4047e8a0123 1459 t->cwnd = 2;
daniele 3:b4047e8a0123 1460 t->cwnd_counter = 0;
daniele 3:b4047e8a0123 1461 }
daniele 3:b4047e8a0123 1462 } else {
daniele 3:b4047e8a0123 1463 tcp_dbg("DUPACK in mode %d \n", t->x_mode);
daniele 3:b4047e8a0123 1464
daniele 3:b4047e8a0123 1465 }
daniele 3:b4047e8a0123 1466 } /* End case duplicate ack detection */
daniele 3:b4047e8a0123 1467
daniele 3:b4047e8a0123 1468 /* Do congestion control */
daniele 3:b4047e8a0123 1469 tcp_congestion_control(t);
daniele 3:b4047e8a0123 1470 if ((acked > 0) && t->sock.wakeup) {
daniele 3:b4047e8a0123 1471 if (t->tcpq_out.size < t->tcpq_out.max_size)
daniele 3:b4047e8a0123 1472 t->sock.wakeup(PICO_SOCK_EV_WR, &(t->sock));
daniele 3:b4047e8a0123 1473 //t->sock.ev_pending |= PICO_SOCK_EV_WR;
daniele 3:b4047e8a0123 1474 }
daniele 3:b4047e8a0123 1475
daniele 3:b4047e8a0123 1476 /* if Nagle enabled, check if no unack'ed data and fill out queue (till window) */
daniele 3:b4047e8a0123 1477 if (IS_NAGLE_ENABLED((&(t->sock)))) {
daniele 3:b4047e8a0123 1478 while (!IS_TCP_HOLDQ_EMPTY(t) && ((t->tcpq_out.max_size - t->tcpq_out.size) >= PICO_TCP_DEFAULT_MSS)) {
daniele 3:b4047e8a0123 1479 tcp_dbg("TCP_ACK - NAGLE add new segment\n");
daniele 3:b4047e8a0123 1480 f_new = pico_hold_segment_make(t);
daniele 3:b4047e8a0123 1481 if (f_new == NULL)
daniele 3:b4047e8a0123 1482 break; /* XXX corrupt !!! (or no memory) */
daniele 3:b4047e8a0123 1483 if (pico_enqueue_segment(&t->tcpq_out,f_new) <= 0)
daniele 3:b4047e8a0123 1484 // handle error
daniele 3:b4047e8a0123 1485 tcp_dbg("TCP_ACK - NAGLE FAILED to enqueue in out\n");
daniele 3:b4047e8a0123 1486 }
daniele 3:b4047e8a0123 1487 }
daniele 3:b4047e8a0123 1488
daniele 3:b4047e8a0123 1489 /* If some space was created, put a few segments out. */
daniele 3:b4047e8a0123 1490 tcp_dbg("TCP_CWND, %lu, %u, %u, %u\n", pico_tick, t->cwnd, t->ssthresh, t->in_flight);
daniele 3:b4047e8a0123 1491 if (t->x_mode == PICO_TCP_LOOKAHEAD) {
daniele 3:b4047e8a0123 1492 if ((t->cwnd >= t->in_flight) && (t->snd_nxt > t->snd_last_out)) {
daniele 3:b4047e8a0123 1493 pico_tcp_output(&t->sock, t->cwnd - t->in_flight);
daniele 3:b4047e8a0123 1494 }
daniele 3:b4047e8a0123 1495 }
daniele 3:b4047e8a0123 1496
daniele 3:b4047e8a0123 1497 t->snd_old_ack = ACKN(f);
daniele 3:b4047e8a0123 1498 return 0;
daniele 3:b4047e8a0123 1499 }
daniele 3:b4047e8a0123 1500
daniele 3:b4047e8a0123 1501 static int tcp_finwaitack(struct pico_socket *s, struct pico_frame *f)
daniele 3:b4047e8a0123 1502 {
daniele 3:b4047e8a0123 1503 tcp_dbg("RECEIVED ACK IN FIN_WAIT1\nTCP> IN STATE FIN_WAIT2\n");
daniele 3:b4047e8a0123 1504
daniele 3:b4047e8a0123 1505 /* acking part */
daniele 3:b4047e8a0123 1506 tcp_ack(s,f);
daniele 3:b4047e8a0123 1507 /* update TCP state */
daniele 3:b4047e8a0123 1508 s->state &= 0x00FFU;
daniele 3:b4047e8a0123 1509 s->state |= PICO_SOCKET_STATE_TCP_FIN_WAIT2;
daniele 3:b4047e8a0123 1510
daniele 3:b4047e8a0123 1511 return 0;
daniele 3:b4047e8a0123 1512 }
daniele 3:b4047e8a0123 1513
daniele 3:b4047e8a0123 1514 static void tcp_deltcb(unsigned long when, void *arg)
daniele 3:b4047e8a0123 1515 {
daniele 3:b4047e8a0123 1516 struct pico_socket_tcp *t = (struct pico_socket_tcp *)arg;
daniele 3:b4047e8a0123 1517 if (TCPSTATE(&t->sock) == PICO_SOCKET_STATE_TCP_TIME_WAIT) {
daniele 3:b4047e8a0123 1518 tcp_dbg("TCP> state: time_wait, final timer expired, going to closed state\n");
daniele 3:b4047e8a0123 1519 /* update state */
daniele 3:b4047e8a0123 1520 (t->sock).state &= 0x00FFU;
daniele 3:b4047e8a0123 1521 (t->sock).state |= PICO_SOCKET_STATE_TCP_CLOSED;
daniele 3:b4047e8a0123 1522 (t->sock).state &= 0xFF00U;
daniele 3:b4047e8a0123 1523 (t->sock).state |= PICO_SOCKET_STATE_CLOSED;
daniele 3:b4047e8a0123 1524 /* call EV_FIN wakeup before deleting */
daniele 3:b4047e8a0123 1525 if (t->sock.wakeup) {
daniele 3:b4047e8a0123 1526 (t->sock).wakeup(PICO_SOCK_EV_FIN, &(t->sock));
daniele 3:b4047e8a0123 1527 }
daniele 3:b4047e8a0123 1528 /* delete socket */
daniele 3:b4047e8a0123 1529 pico_socket_del(&t->sock);
daniele 3:b4047e8a0123 1530 } else {
daniele 3:b4047e8a0123 1531 tcp_dbg("TCP> trying to go to closed, wrong state\n");
daniele 3:b4047e8a0123 1532 }
daniele 3:b4047e8a0123 1533 }
daniele 3:b4047e8a0123 1534
daniele 3:b4047e8a0123 1535 static int tcp_finwaitfin(struct pico_socket *s, struct pico_frame *f)
daniele 3:b4047e8a0123 1536 {
daniele 3:b4047e8a0123 1537 struct pico_socket_tcp *t = (struct pico_socket_tcp *)s;
daniele 3:b4047e8a0123 1538 struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *) (f->transport_hdr);
daniele 3:b4047e8a0123 1539 tcp_dbg("TCP> received fin in FIN_WAIT2\n");
daniele 3:b4047e8a0123 1540 /* received FIN, increase ACK nr */
daniele 3:b4047e8a0123 1541 t->rcv_nxt = long_be(hdr->seq) + 1;
daniele 3:b4047e8a0123 1542 s->state &= 0x00FFU;
daniele 3:b4047e8a0123 1543 s->state |= PICO_SOCKET_STATE_TCP_TIME_WAIT;
daniele 3:b4047e8a0123 1544 /* set SHUT_REMOTE */
daniele 3:b4047e8a0123 1545 s->state |= PICO_SOCKET_STATE_SHUT_REMOTE;
daniele 3:b4047e8a0123 1546 if (s->wakeup)
daniele 3:b4047e8a0123 1547 s->wakeup(PICO_SOCK_EV_CLOSE, s);
daniele 3:b4047e8a0123 1548 if (f->payload_len > 0) /* needed?? */
daniele 3:b4047e8a0123 1549 tcp_data_in(s,f);
daniele 3:b4047e8a0123 1550 /* send ACK */
daniele 3:b4047e8a0123 1551 tcp_send_ack(t);
daniele 3:b4047e8a0123 1552 /* set timer */
daniele 3:b4047e8a0123 1553 pico_timer_add(200, tcp_deltcb, t);
daniele 3:b4047e8a0123 1554 return 0;
daniele 3:b4047e8a0123 1555 }
daniele 3:b4047e8a0123 1556
daniele 3:b4047e8a0123 1557 static int tcp_closewaitack(struct pico_socket *s, struct pico_frame *f)
daniele 3:b4047e8a0123 1558 {
daniele 3:b4047e8a0123 1559 struct pico_socket_tcp *t = (struct pico_socket_tcp *)s;
daniele 3:b4047e8a0123 1560 tcp_dbg("TCP> received ack in CLOSING\n");
daniele 3:b4047e8a0123 1561 /* acking part */
daniele 3:b4047e8a0123 1562 tcp_ack(s,f);
daniele 3:b4047e8a0123 1563 /* update TCP state */
daniele 3:b4047e8a0123 1564 s->state &= 0x00FFU;
daniele 3:b4047e8a0123 1565 s->state |= PICO_SOCKET_STATE_TCP_TIME_WAIT;
daniele 3:b4047e8a0123 1566 /* set timer */
daniele 3:b4047e8a0123 1567 pico_timer_add(200, tcp_deltcb, t);
daniele 3:b4047e8a0123 1568 return 0;
daniele 3:b4047e8a0123 1569 }
daniele 3:b4047e8a0123 1570
daniele 3:b4047e8a0123 1571 static int tcp_lastackwait(struct pico_socket *s, struct pico_frame *f)
daniele 3:b4047e8a0123 1572 {
daniele 3:b4047e8a0123 1573 tcp_dbg("TCP> state: last_ack, received ack, to closed\n");
daniele 3:b4047e8a0123 1574 s->state &= 0x00FFU;
daniele 3:b4047e8a0123 1575 s->state |= PICO_SOCKET_STATE_TCP_CLOSED;
daniele 3:b4047e8a0123 1576 s->state &= 0xFF00U;
daniele 3:b4047e8a0123 1577 s->state |= PICO_SOCKET_STATE_CLOSED;
daniele 3:b4047e8a0123 1578 /* call socket wakeup with EV_FIN */
daniele 3:b4047e8a0123 1579 if (s->wakeup)
daniele 3:b4047e8a0123 1580 s->wakeup(PICO_SOCK_EV_FIN, s);
daniele 3:b4047e8a0123 1581 /* delete socket */
daniele 3:b4047e8a0123 1582 pico_socket_del(s);
daniele 3:b4047e8a0123 1583 return 0;
daniele 3:b4047e8a0123 1584 }
daniele 3:b4047e8a0123 1585
daniele 3:b4047e8a0123 1586 static int tcp_syn(struct pico_socket *s, struct pico_frame *f)
daniele 3:b4047e8a0123 1587 {
daniele 3:b4047e8a0123 1588 /* TODO: Check against backlog length */
daniele 3:b4047e8a0123 1589 struct pico_socket_tcp *new = (struct pico_socket_tcp *)pico_socket_clone(s);
daniele 3:b4047e8a0123 1590 struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *)f->transport_hdr;
daniele 3:b4047e8a0123 1591 if (!new)
daniele 3:b4047e8a0123 1592 return -1;
daniele 3:b4047e8a0123 1593
daniele 3:b4047e8a0123 1594 #ifdef PICO_TCP_SUPPORT_SOCKET_STATS
daniele 3:b4047e8a0123 1595 pico_timer_add(2000, sock_stats, s);
daniele 3:b4047e8a0123 1596 #endif
daniele 3:b4047e8a0123 1597
daniele 3:b4047e8a0123 1598 new->sock.remote_port = ((struct pico_trans *)f->transport_hdr)->sport;
daniele 3:b4047e8a0123 1599 #ifdef PICO_SUPPORT_IPV4
daniele 3:b4047e8a0123 1600 if (IS_IPV4(f)) {
daniele 3:b4047e8a0123 1601 new->sock.remote_addr.ip4.addr = ((struct pico_ipv4_hdr *)(f->net_hdr))->src.addr;
daniele 3:b4047e8a0123 1602 new->sock.local_addr.ip4.addr = ((struct pico_ipv4_hdr *)(f->net_hdr))->dst.addr;
daniele 3:b4047e8a0123 1603 }
daniele 3:b4047e8a0123 1604 #endif
daniele 3:b4047e8a0123 1605 #ifdef PICO_SUPPORT_IPV6
daniele 3:b4047e8a0123 1606 if (IS_IPV6(f)) {
daniele 3:b4047e8a0123 1607 memcpy(new->sock.remote_addr.ip6.addr, ((struct pico_ipv6_hdr *)(f->net_hdr))->src, PICO_SIZE_IP6);
daniele 3:b4047e8a0123 1608 memcpy(new->sock.remote_addr.ip6.addr, ((struct pico_ipv6_hdr *)(f->net_hdr))->src, PICO_SIZE_IP6);
daniele 3:b4047e8a0123 1609 }
daniele 3:b4047e8a0123 1610 #endif
daniele 3:b4047e8a0123 1611
daniele 3:b4047e8a0123 1612 /* Set socket limits */
daniele 3:b4047e8a0123 1613 new->tcpq_in.max_size = PICO_DEFAULT_SOCKETQ;
daniele 3:b4047e8a0123 1614 new->tcpq_out.max_size = PICO_DEFAULT_SOCKETQ;
daniele 3:b4047e8a0123 1615 new->tcpq_hold.max_size = 2*PICO_TCP_DEFAULT_MSS;
daniele 3:b4047e8a0123 1616
daniele 3:b4047e8a0123 1617 f->sock = &new->sock;
daniele 3:b4047e8a0123 1618 tcp_parse_options(f);
daniele 3:b4047e8a0123 1619 new->mss = PICO_TCP_DEFAULT_MSS;
daniele 3:b4047e8a0123 1620 new->rcv_nxt = long_be(hdr->seq) + 1;
daniele 3:b4047e8a0123 1621 new->snd_nxt = long_be(pico_paws());
daniele 3:b4047e8a0123 1622 new->snd_last = new->snd_nxt;
daniele 3:b4047e8a0123 1623 new->cwnd = PICO_TCP_IW;
daniele 3:b4047e8a0123 1624 new->ssthresh = 40;
daniele 3:b4047e8a0123 1625 new->recv_wnd = short_be(hdr->rwnd);
daniele 3:b4047e8a0123 1626 new->jumbo = hdr->len & 0x07;
daniele 3:b4047e8a0123 1627 new->sock.parent = s;
daniele 3:b4047e8a0123 1628 new->sock.wakeup = s->wakeup;
daniele 3:b4047e8a0123 1629 /* Initialize timestamp values */
daniele 3:b4047e8a0123 1630 new->sock.state = PICO_SOCKET_STATE_BOUND | PICO_SOCKET_STATE_CONNECTED | PICO_SOCKET_STATE_TCP_SYN_RECV;
daniele 3:b4047e8a0123 1631 pico_socket_add(&new->sock);
daniele 3:b4047e8a0123 1632 tcp_send_synack(&new->sock);
daniele 3:b4047e8a0123 1633 tcp_dbg("SYNACK sent, socket added. snd_nxt is %08x\n", new->snd_nxt);
daniele 3:b4047e8a0123 1634 return 0;
daniele 3:b4047e8a0123 1635 }
daniele 3:b4047e8a0123 1636
daniele 3:b4047e8a0123 1637 static void tcp_set_init_point(struct pico_socket *s)
daniele 3:b4047e8a0123 1638 {
daniele 3:b4047e8a0123 1639 struct pico_socket_tcp *t = (struct pico_socket_tcp *)s;
daniele 3:b4047e8a0123 1640 t->rcv_processed = t->rcv_nxt;
daniele 3:b4047e8a0123 1641 }
daniele 3:b4047e8a0123 1642
daniele 3:b4047e8a0123 1643 static int tcp_synack(struct pico_socket *s, struct pico_frame *f)
daniele 3:b4047e8a0123 1644 {
daniele 3:b4047e8a0123 1645 struct pico_socket_tcp *t = (struct pico_socket_tcp *) s;
daniele 3:b4047e8a0123 1646 struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *)f->transport_hdr;
daniele 3:b4047e8a0123 1647
daniele 3:b4047e8a0123 1648 if (ACKN(f) == (1 + t->snd_nxt)) {
daniele 3:b4047e8a0123 1649 t->rcv_nxt = long_be(hdr->seq);
daniele 3:b4047e8a0123 1650 t->rcv_processed = t->rcv_nxt + 1;
daniele 3:b4047e8a0123 1651 tcp_ack(s, f);
daniele 3:b4047e8a0123 1652
daniele 3:b4047e8a0123 1653 s->state &= 0x00FFU;
daniele 3:b4047e8a0123 1654 s->state |= PICO_SOCKET_STATE_TCP_ESTABLISHED;
daniele 3:b4047e8a0123 1655 tcp_dbg("TCP> Established. State: %x\n", s->state);
daniele 3:b4047e8a0123 1656
daniele 3:b4047e8a0123 1657 if (s->wakeup)
daniele 3:b4047e8a0123 1658 s->wakeup(PICO_SOCK_EV_CONN, s);
daniele 3:b4047e8a0123 1659 s->ev_pending |= PICO_SOCK_EV_WR;
daniele 3:b4047e8a0123 1660
daniele 3:b4047e8a0123 1661 t->rcv_nxt++;
daniele 3:b4047e8a0123 1662 t->snd_nxt++;
daniele 3:b4047e8a0123 1663 tcp_send_ack(t); /* return ACK */
daniele 3:b4047e8a0123 1664
daniele 3:b4047e8a0123 1665 return 0;
daniele 3:b4047e8a0123 1666
daniele 3:b4047e8a0123 1667 } else {
daniele 3:b4047e8a0123 1668 tcp_dbg("TCP> Not established, RST sent.\n");
daniele 3:b4047e8a0123 1669 tcp_nosync_rst(s,f);
daniele 3:b4047e8a0123 1670 return 0;
daniele 3:b4047e8a0123 1671 }
daniele 3:b4047e8a0123 1672 }
daniele 3:b4047e8a0123 1673
daniele 3:b4047e8a0123 1674 static int tcp_first_ack(struct pico_socket *s, struct pico_frame *f)
daniele 3:b4047e8a0123 1675 {
daniele 3:b4047e8a0123 1676 struct pico_socket_tcp *t = (struct pico_socket_tcp *)s;
daniele 3:b4047e8a0123 1677 tcp_dbg("ACK in SYN_RECV: expecting %08x got %08x\n", t->snd_nxt, ACKN(f));
daniele 3:b4047e8a0123 1678 if (t->snd_nxt == ACKN(f)) {
daniele 3:b4047e8a0123 1679 tcp_set_init_point(s);
daniele 3:b4047e8a0123 1680 tcp_ack(s, f);
daniele 3:b4047e8a0123 1681 s->state &= 0x00FFU;
daniele 3:b4047e8a0123 1682 s->state |= PICO_SOCKET_STATE_TCP_ESTABLISHED;
daniele 3:b4047e8a0123 1683 tcp_dbg("TCP: Established. State now: %04x\n", s->state);
daniele 3:b4047e8a0123 1684 if( !s->parent && s->wakeup) { /* If the socket has no parent, -> sending socket that has a sim_open */
daniele 3:b4047e8a0123 1685 tcp_dbg("FIRST ACK - No parent found -> sending socket\n");
daniele 3:b4047e8a0123 1686 s->wakeup(PICO_SOCK_EV_CONN, s);
daniele 3:b4047e8a0123 1687 }
daniele 3:b4047e8a0123 1688 if (s->parent && s->parent->wakeup) {
daniele 3:b4047e8a0123 1689 tcp_dbg("FIRST ACK - Parent found -> listening socket\n");
daniele 3:b4047e8a0123 1690 s->wakeup = s->parent->wakeup;
daniele 3:b4047e8a0123 1691 s->parent->wakeup(PICO_SOCK_EV_CONN, s->parent);
daniele 3:b4047e8a0123 1692 }
daniele 3:b4047e8a0123 1693 s->ev_pending |= PICO_SOCK_EV_WR;
daniele 3:b4047e8a0123 1694 tcp_dbg("%s: snd_nxt is now %08x\n", __FUNCTION__, t->snd_nxt);
daniele 3:b4047e8a0123 1695 return 0;
daniele 3:b4047e8a0123 1696 } else {
daniele 3:b4047e8a0123 1697 tcp_nosync_rst(s,f);
daniele 3:b4047e8a0123 1698 return 0;
daniele 3:b4047e8a0123 1699 }
daniele 3:b4047e8a0123 1700 }
daniele 3:b4047e8a0123 1701
daniele 3:b4047e8a0123 1702 static int tcp_closewait(struct pico_socket *s, struct pico_frame *f)
daniele 3:b4047e8a0123 1703 {
daniele 3:b4047e8a0123 1704
daniele 3:b4047e8a0123 1705 struct pico_socket_tcp *t = (struct pico_socket_tcp *)s;
daniele 3:b4047e8a0123 1706 struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *) (f->transport_hdr);
daniele 3:b4047e8a0123 1707
daniele 3:b4047e8a0123 1708 if (f->payload_len > 0)
daniele 3:b4047e8a0123 1709 tcp_data_in(s,f);
daniele 3:b4047e8a0123 1710 if (f->flags & PICO_TCP_ACK)
daniele 3:b4047e8a0123 1711 tcp_ack(s,f);
daniele 3:b4047e8a0123 1712 if (seq_compare(SEQN(f), t->rcv_nxt) == 0) {
daniele 3:b4047e8a0123 1713 /* received FIN, increase ACK nr */
daniele 3:b4047e8a0123 1714 t->rcv_nxt = long_be(hdr->seq) + 1;
daniele 3:b4047e8a0123 1715 s->state &= 0x00FFU;
daniele 3:b4047e8a0123 1716 s->state |= PICO_SOCKET_STATE_TCP_CLOSE_WAIT;
daniele 3:b4047e8a0123 1717 /* set SHUT_REMOTE */
daniele 3:b4047e8a0123 1718 s->state |= PICO_SOCKET_STATE_SHUT_REMOTE;
daniele 3:b4047e8a0123 1719 tcp_dbg("TCP> Close-wait\n");
daniele 3:b4047e8a0123 1720 if (s->wakeup){
daniele 3:b4047e8a0123 1721 if(f->payload_len>0){
daniele 3:b4047e8a0123 1722 struct pico_socket_tcp *t = (struct pico_socket_tcp *)s;
daniele 3:b4047e8a0123 1723 t->sock.ev_pending |=PICO_SOCK_EV_CLOSE;
daniele 3:b4047e8a0123 1724 }else
daniele 3:b4047e8a0123 1725 s->wakeup(PICO_SOCK_EV_CLOSE, s);
daniele 3:b4047e8a0123 1726 }
daniele 3:b4047e8a0123 1727 } else {
daniele 3:b4047e8a0123 1728 tcp_send_ack(t); /* return ACK */
daniele 3:b4047e8a0123 1729 }
daniele 3:b4047e8a0123 1730 return 0;
daniele 3:b4047e8a0123 1731 }
daniele 3:b4047e8a0123 1732
daniele 3:b4047e8a0123 1733 /*static int tcp_fin(struct pico_socket *s, struct pico_frame *f)
daniele 3:b4047e8a0123 1734 {
daniele 3:b4047e8a0123 1735 return 0;
daniele 3:b4047e8a0123 1736 }*/
daniele 3:b4047e8a0123 1737
daniele 3:b4047e8a0123 1738 static int tcp_rcvfin(struct pico_socket *s, struct pico_frame *f)
daniele 3:b4047e8a0123 1739 {
daniele 3:b4047e8a0123 1740 struct pico_socket_tcp *t = (struct pico_socket_tcp *)s;
daniele 3:b4047e8a0123 1741 tcp_dbg("TCP> Received FIN in FIN_WAIT1\n");
daniele 3:b4047e8a0123 1742 s->state &= 0x00FFU;
daniele 3:b4047e8a0123 1743 s->state |= PICO_SOCKET_STATE_TCP_CLOSING;
daniele 3:b4047e8a0123 1744 t->rcv_processed = t->rcv_nxt + 1;
daniele 3:b4047e8a0123 1745 t->rcv_nxt++;
daniele 3:b4047e8a0123 1746 /* send ACK */
daniele 3:b4047e8a0123 1747 tcp_send_ack(t);
daniele 3:b4047e8a0123 1748 return 0;
daniele 3:b4047e8a0123 1749 }
daniele 3:b4047e8a0123 1750
daniele 3:b4047e8a0123 1751 static int tcp_finack(struct pico_socket *s, struct pico_frame *f)
daniele 3:b4047e8a0123 1752 {
daniele 3:b4047e8a0123 1753 struct pico_socket_tcp *t = (struct pico_socket_tcp *)s;
daniele 3:b4047e8a0123 1754 tcp_dbg("TCP> ENTERED finack\n");
daniele 3:b4047e8a0123 1755 t->rcv_nxt++;
daniele 3:b4047e8a0123 1756 /* send ACK */
daniele 3:b4047e8a0123 1757 tcp_send_ack(t);
daniele 3:b4047e8a0123 1758
daniele 3:b4047e8a0123 1759 /* call socket wakeup with EV_FIN */
daniele 3:b4047e8a0123 1760 if (s->wakeup)
daniele 3:b4047e8a0123 1761 s->wakeup(PICO_SOCK_EV_FIN, s);
daniele 3:b4047e8a0123 1762 s->state &= 0x00FFU;
daniele 3:b4047e8a0123 1763 s->state |= PICO_SOCKET_STATE_TCP_TIME_WAIT;
daniele 3:b4047e8a0123 1764 /* set SHUT_REMOTE */
daniele 3:b4047e8a0123 1765 s->state |= PICO_SOCKET_STATE_SHUT_REMOTE;
daniele 3:b4047e8a0123 1766 pico_timer_add(2000, tcp_deltcb, t);
daniele 3:b4047e8a0123 1767
daniele 3:b4047e8a0123 1768 return 0;
daniele 3:b4047e8a0123 1769 }
daniele 3:b4047e8a0123 1770
daniele 3:b4047e8a0123 1771 static int tcp_rst(struct pico_socket *s, struct pico_frame *f)
daniele 3:b4047e8a0123 1772 {
daniele 3:b4047e8a0123 1773 struct pico_socket_tcp *t = (struct pico_socket_tcp *) s;
daniele 3:b4047e8a0123 1774 struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *) (f->transport_hdr);
daniele 3:b4047e8a0123 1775
daniele 3:b4047e8a0123 1776 tcp_dbg("TCP >>>>>>>>>>>>>> received RST <<<<<<<<<<<<<<<<<<<<\n");
daniele 3:b4047e8a0123 1777 if ((s->state & PICO_SOCKET_STATE_TCP) == PICO_SOCKET_STATE_TCP_SYN_SENT) {
daniele 3:b4047e8a0123 1778 /* the RST is acceptable if the ACK field acknowledges the SYN */
daniele 3:b4047e8a0123 1779 if ((t->snd_nxt + 1) == ACKN(f)) { /* valid, got to closed state */
daniele 3:b4047e8a0123 1780 /* update state */
daniele 3:b4047e8a0123 1781 (t->sock).state &= 0x00FFU;
daniele 3:b4047e8a0123 1782 (t->sock).state |= PICO_SOCKET_STATE_TCP_CLOSED;
daniele 3:b4047e8a0123 1783 (t->sock).state &= 0xFF00U;
daniele 3:b4047e8a0123 1784 (t->sock).state |= PICO_SOCKET_STATE_CLOSED;
daniele 3:b4047e8a0123 1785
daniele 3:b4047e8a0123 1786 /* call EV_FIN wakeup before deleting */
daniele 3:b4047e8a0123 1787 if ((t->sock).wakeup)
daniele 3:b4047e8a0123 1788 (t->sock).wakeup(PICO_SOCK_EV_FIN, &(t->sock));
daniele 3:b4047e8a0123 1789
daniele 3:b4047e8a0123 1790 /* call EV_ERR wakeup before deleting */
daniele 3:b4047e8a0123 1791 pico_err = PICO_ERR_ECONNRESET;
daniele 3:b4047e8a0123 1792 if ((t->sock).wakeup)
daniele 3:b4047e8a0123 1793 (t->sock).wakeup(PICO_SOCK_EV_ERR, &(t->sock));
daniele 3:b4047e8a0123 1794
daniele 3:b4047e8a0123 1795 /* delete socket */
daniele 3:b4047e8a0123 1796 pico_socket_del(&t->sock);
daniele 3:b4047e8a0123 1797 } else { /* not valid, ignore */
daniele 3:b4047e8a0123 1798 tcp_dbg("TCP RST> IGNORE\n");
daniele 3:b4047e8a0123 1799 return 0;
daniele 3:b4047e8a0123 1800 }
daniele 3:b4047e8a0123 1801 } else { /* all other states */
daniele 3:b4047e8a0123 1802 /* all reset (RST) segments are validated by checking their SEQ-fields,
daniele 3:b4047e8a0123 1803 a reset is valid if its sequence number is in the window */
daniele 3:b4047e8a0123 1804 if ((long_be(hdr->seq) >= t->rcv_ackd) && (long_be(hdr->seq) <= ((short_be(hdr->rwnd)<<(t->wnd_scale)) + t->rcv_ackd))) {
daniele 3:b4047e8a0123 1805 if ((s->state & PICO_SOCKET_STATE_TCP) == PICO_SOCKET_STATE_TCP_SYN_RECV) {
daniele 3:b4047e8a0123 1806 /* go to closed */
daniele 3:b4047e8a0123 1807 (t->sock).state &= 0x00FFU;
daniele 3:b4047e8a0123 1808 (t->sock).state |= PICO_SOCKET_STATE_TCP_CLOSED;
daniele 3:b4047e8a0123 1809 (t->sock).state &= 0xFF00U;
daniele 3:b4047e8a0123 1810 (t->sock).state |= PICO_SOCKET_STATE_CLOSED;
daniele 3:b4047e8a0123 1811 /* call EV_ERR wakeup */
daniele 3:b4047e8a0123 1812 pico_err = PICO_ERR_ECONNRESET;
daniele 3:b4047e8a0123 1813 if ((t->sock).wakeup)
daniele 3:b4047e8a0123 1814 (t->sock).wakeup(PICO_SOCK_EV_ERR, &(t->sock));
daniele 3:b4047e8a0123 1815 tcp_dbg("TCP RST> SOCKET BACK TO LISTEN\n");
daniele 3:b4047e8a0123 1816 pico_socket_del(s);
daniele 3:b4047e8a0123 1817 } else {
daniele 3:b4047e8a0123 1818 /* go to closed */
daniele 3:b4047e8a0123 1819 (t->sock).state &= 0x00FFU;
daniele 3:b4047e8a0123 1820 (t->sock).state |= PICO_SOCKET_STATE_TCP_CLOSED;
daniele 3:b4047e8a0123 1821 (t->sock).state &= 0xFF00U;
daniele 3:b4047e8a0123 1822 (t->sock).state |= PICO_SOCKET_STATE_CLOSED;
daniele 3:b4047e8a0123 1823
daniele 3:b4047e8a0123 1824 /* call EV_FIN wakeup before deleting */
daniele 3:b4047e8a0123 1825 if ((t->sock).wakeup)
daniele 3:b4047e8a0123 1826 (t->sock).wakeup(PICO_SOCK_EV_FIN, &(t->sock));
daniele 3:b4047e8a0123 1827 /* call EV_ERR wakeup before deleting */
daniele 3:b4047e8a0123 1828 pico_err = PICO_ERR_ECONNRESET;
daniele 3:b4047e8a0123 1829 if ((t->sock).wakeup)
daniele 3:b4047e8a0123 1830 (t->sock).wakeup(PICO_SOCK_EV_ERR, &(t->sock));
daniele 3:b4047e8a0123 1831
daniele 3:b4047e8a0123 1832 /* delete socket */
daniele 3:b4047e8a0123 1833 pico_socket_del(&t->sock);
daniele 3:b4047e8a0123 1834 }
daniele 3:b4047e8a0123 1835 } else { /* not valid, ignore */
daniele 3:b4047e8a0123 1836 tcp_dbg("TCP RST> IGNORE\n");
daniele 3:b4047e8a0123 1837 return 0;
daniele 3:b4047e8a0123 1838 }
daniele 3:b4047e8a0123 1839 }
daniele 3:b4047e8a0123 1840
daniele 3:b4047e8a0123 1841 return 0;
daniele 3:b4047e8a0123 1842 }
daniele 3:b4047e8a0123 1843
daniele 3:b4047e8a0123 1844 struct tcp_action_entry {
daniele 3:b4047e8a0123 1845 uint16_t tcpstate;
daniele 3:b4047e8a0123 1846 int (*syn)(struct pico_socket *s, struct pico_frame *f);
daniele 3:b4047e8a0123 1847 int (*synack)(struct pico_socket *s, struct pico_frame *f);
daniele 3:b4047e8a0123 1848 int (*ack)(struct pico_socket *s, struct pico_frame *f);
daniele 3:b4047e8a0123 1849 int (*data)(struct pico_socket *s, struct pico_frame *f);
daniele 3:b4047e8a0123 1850 int (*fin)(struct pico_socket *s, struct pico_frame *f);
daniele 3:b4047e8a0123 1851 int (*finack)(struct pico_socket *s, struct pico_frame *f);
daniele 3:b4047e8a0123 1852 int (*rst)(struct pico_socket *s, struct pico_frame *f);
daniele 3:b4047e8a0123 1853 };
daniele 3:b4047e8a0123 1854
daniele 3:b4047e8a0123 1855 static struct tcp_action_entry tcp_fsm[] = {
daniele 3:b4047e8a0123 1856 /* State syn synack ack data fin finack rst*/
daniele 3:b4047e8a0123 1857 { PICO_SOCKET_STATE_TCP_UNDEF, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
daniele 3:b4047e8a0123 1858 { PICO_SOCKET_STATE_TCP_CLOSED, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
daniele 3:b4047e8a0123 1859 { PICO_SOCKET_STATE_TCP_LISTEN, &tcp_syn, &tcp_nosync_rst, &tcp_nosync_rst, &tcp_nosync_rst, &tcp_nosync_rst, &tcp_nosync_rst, NULL },
daniele 3:b4047e8a0123 1860 { PICO_SOCKET_STATE_TCP_SYN_SENT, &tcp_nosync_rst, &tcp_synack, &tcp_nosync_rst, &tcp_nosync_rst, &tcp_nosync_rst, &tcp_nosync_rst, &tcp_rst },
daniele 3:b4047e8a0123 1861 { PICO_SOCKET_STATE_TCP_SYN_RECV, &tcp_nosync_rst, &tcp_nosync_rst, &tcp_first_ack, &tcp_nosync_rst, &tcp_nosync_rst, &tcp_nosync_rst, &tcp_rst },
daniele 3:b4047e8a0123 1862 { PICO_SOCKET_STATE_TCP_ESTABLISHED, &tcp_send_rst, &tcp_send_rst, &tcp_ack, &tcp_data_in, &tcp_closewait, &tcp_closewait, &tcp_rst },
daniele 3:b4047e8a0123 1863 { PICO_SOCKET_STATE_TCP_CLOSE_WAIT, &tcp_send_rst, &tcp_send_rst, &tcp_ack, &tcp_send_rst, &tcp_send_rst, &tcp_send_rst, &tcp_rst },
daniele 3:b4047e8a0123 1864 { PICO_SOCKET_STATE_TCP_LAST_ACK, &tcp_send_rst, &tcp_send_rst, &tcp_lastackwait, &tcp_send_rst, &tcp_send_rst, &tcp_send_rst, &tcp_rst },
daniele 3:b4047e8a0123 1865 { PICO_SOCKET_STATE_TCP_FIN_WAIT1, &tcp_send_rst, &tcp_send_rst, &tcp_finwaitack, &tcp_data_in, &tcp_rcvfin, &tcp_finack, &tcp_rst },
daniele 3:b4047e8a0123 1866 { PICO_SOCKET_STATE_TCP_FIN_WAIT2, &tcp_send_rst, &tcp_send_rst, &tcp_ack, &tcp_data_in, &tcp_finwaitfin, &tcp_finack, &tcp_rst },
daniele 3:b4047e8a0123 1867 { PICO_SOCKET_STATE_TCP_CLOSING, &tcp_send_rst, &tcp_send_rst, &tcp_closewaitack, &tcp_send_rst, &tcp_send_rst, &tcp_send_rst, &tcp_rst },
daniele 3:b4047e8a0123 1868 { PICO_SOCKET_STATE_TCP_TIME_WAIT, &tcp_send_rst, &tcp_send_rst, &tcp_send_rst, &tcp_send_rst, &tcp_send_rst, &tcp_send_rst, &tcp_rst }
daniele 3:b4047e8a0123 1869 };
daniele 3:b4047e8a0123 1870
daniele 3:b4047e8a0123 1871 /*
daniele 3:b4047e8a0123 1872 NOTE: in SYN-RECV receiving syn when cloned by default (see yellow pos-it), should send reset.
daniele 3:b4047e8a0123 1873 */
daniele 3:b4047e8a0123 1874
daniele 3:b4047e8a0123 1875 int pico_tcp_input(struct pico_socket *s, struct pico_frame *f)
daniele 3:b4047e8a0123 1876 {
daniele 3:b4047e8a0123 1877 struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *) (f->transport_hdr);
daniele 3:b4047e8a0123 1878 int ret = 0;
daniele 3:b4047e8a0123 1879 uint8_t flags = hdr->flags;
daniele 3:b4047e8a0123 1880 struct tcp_action_entry *action = &tcp_fsm[s->state >> 8];
daniele 3:b4047e8a0123 1881
daniele 3:b4047e8a0123 1882 f->payload = (f->transport_hdr + ((hdr->len & 0xf0) >> 2));
daniele 3:b4047e8a0123 1883 f->payload_len = f->transport_len - ((hdr->len & 0xf0) >> 2);
daniele 3:b4047e8a0123 1884
daniele 3:b4047e8a0123 1885 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,
daniele 3:b4047e8a0123 1886 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 );
daniele 3:b4047e8a0123 1887
daniele 3:b4047e8a0123 1888 /* This copy of the frame has the current socket as owner */
daniele 3:b4047e8a0123 1889 f->sock = s;
daniele 3:b4047e8a0123 1890
daniele 3:b4047e8a0123 1891 /* Those are not supported at this time. */
daniele 3:b4047e8a0123 1892 flags &= ~(PICO_TCP_CWR | PICO_TCP_URG | PICO_TCP_ECN);
daniele 3:b4047e8a0123 1893 if (flags == PICO_TCP_SYN) {
daniele 3:b4047e8a0123 1894 if (action->syn)
daniele 3:b4047e8a0123 1895 action->syn(s,f);
daniele 3:b4047e8a0123 1896 } else if (flags == (PICO_TCP_SYN | PICO_TCP_ACK)) {
daniele 3:b4047e8a0123 1897 if (action->synack)
daniele 3:b4047e8a0123 1898 action->synack(s,f);
daniele 3:b4047e8a0123 1899 } else {
daniele 3:b4047e8a0123 1900 if ((flags == PICO_TCP_ACK) || (flags == (PICO_TCP_ACK | PICO_TCP_PSH))) {
daniele 3:b4047e8a0123 1901 if (action->ack) {
daniele 3:b4047e8a0123 1902 action->ack(s,f);
daniele 3:b4047e8a0123 1903 }
daniele 3:b4047e8a0123 1904 }
daniele 3:b4047e8a0123 1905 if (f->payload_len > 0) {
daniele 3:b4047e8a0123 1906 ret = f->payload_len;
daniele 3:b4047e8a0123 1907 if (action->data)
daniele 3:b4047e8a0123 1908 action->data(s,f);
daniele 3:b4047e8a0123 1909 }
daniele 3:b4047e8a0123 1910 if (flags == PICO_TCP_FIN) {
daniele 3:b4047e8a0123 1911 if (action->fin)
daniele 3:b4047e8a0123 1912 action->fin(s,f);
daniele 3:b4047e8a0123 1913 }
daniele 3:b4047e8a0123 1914 if ((flags == (PICO_TCP_FIN | PICO_TCP_ACK)) || (flags == (PICO_TCP_FIN | PICO_TCP_ACK | PICO_TCP_PSH))) {
daniele 3:b4047e8a0123 1915 if (action->finack)
daniele 3:b4047e8a0123 1916 action->finack(s,f);
daniele 3:b4047e8a0123 1917 }
daniele 3:b4047e8a0123 1918 if (flags & PICO_TCP_RST) {
daniele 3:b4047e8a0123 1919 if (action->rst)
daniele 3:b4047e8a0123 1920 action->rst(s,f);
daniele 3:b4047e8a0123 1921 }
daniele 3:b4047e8a0123 1922 }
daniele 3:b4047e8a0123 1923
daniele 3:b4047e8a0123 1924 //discard:
daniele 3:b4047e8a0123 1925 pico_frame_discard(f);
daniele 3:b4047e8a0123 1926 return ret;
daniele 3:b4047e8a0123 1927 }
daniele 3:b4047e8a0123 1928
daniele 3:b4047e8a0123 1929 static void tcp_send_keepalive(unsigned long when, void *_t)
daniele 3:b4047e8a0123 1930 {
daniele 3:b4047e8a0123 1931 struct pico_socket_tcp *t = (struct pico_socket_tcp *)_t;
daniele 3:b4047e8a0123 1932 tcp_dbg("\n\nSending keepalive (%d), [State = %d]...\n", t->backoff,t->sock.state );
daniele 3:b4047e8a0123 1933 if( t->sock.net && ((t->sock.state & 0xFF00) == PICO_SOCKET_STATE_TCP_ESTABLISHED) )
daniele 3:b4047e8a0123 1934 {
daniele 3:b4047e8a0123 1935 tcp_send_ack(t);
daniele 3:b4047e8a0123 1936
daniele 3:b4047e8a0123 1937 if (t->keepalive_timer_running > 0) {
daniele 3:b4047e8a0123 1938 t->keepalive_timer_running--;
daniele 3:b4047e8a0123 1939 }
daniele 3:b4047e8a0123 1940
daniele 3:b4047e8a0123 1941 if (t->keepalive_timer_running == 0) {
daniele 3:b4047e8a0123 1942 t->keepalive_timer_running++;
daniele 3:b4047e8a0123 1943 tcp_dbg("[Self] Adding timer(retransmit keepalive)\n");
daniele 3:b4047e8a0123 1944 pico_timer_add(t->rto << (++t->backoff), tcp_send_keepalive, t);
daniele 3:b4047e8a0123 1945 }
daniele 3:b4047e8a0123 1946 }
daniele 3:b4047e8a0123 1947 }
daniele 3:b4047e8a0123 1948
daniele 3:b4047e8a0123 1949 int pico_tcp_output(struct pico_socket *s, int loop_score)
daniele 3:b4047e8a0123 1950 {
daniele 3:b4047e8a0123 1951 struct pico_socket_tcp *t = (struct pico_socket_tcp *)s;
daniele 3:b4047e8a0123 1952 struct pico_frame *f, *una;
daniele 3:b4047e8a0123 1953 struct pico_tcp_hdr *hdr;
daniele 3:b4047e8a0123 1954 int sent = 0;
daniele 3:b4047e8a0123 1955
daniele 3:b4047e8a0123 1956 una = first_segment(&t->tcpq_out);
daniele 3:b4047e8a0123 1957
daniele 3:b4047e8a0123 1958 f = peek_segment(&t->tcpq_out, t->snd_nxt);
daniele 3:b4047e8a0123 1959 while((f) && (t->cwnd >= t->in_flight)) {
daniele 3:b4047e8a0123 1960 hdr = (struct pico_tcp_hdr *)f->transport_hdr;
daniele 3:b4047e8a0123 1961 f->timestamp = pico_tick;
daniele 3:b4047e8a0123 1962 tcp_add_options(t, f, hdr->flags, tcp_options_size(t, hdr->flags));
daniele 3:b4047e8a0123 1963 if (seq_compare(SEQN(f) + f->payload_len, SEQN(una) + (t->recv_wnd << t->recv_wnd_scale)) > 0) {
daniele 3:b4047e8a0123 1964 t->cwnd = t->in_flight;
daniele 3:b4047e8a0123 1965 if (t->cwnd < 1)
daniele 3:b4047e8a0123 1966 t->cwnd = 1;
daniele 3:b4047e8a0123 1967 if (t->x_mode != PICO_TCP_WINDOW_FULL) {
daniele 3:b4047e8a0123 1968 tcp_dbg("TCP> RIGHT SIZING (rwnd: %d, frame len: %d\n",t->recv_wnd << t->recv_wnd_scale, f->payload_len);
daniele 3:b4047e8a0123 1969 tcp_dbg("In window full...\n");
daniele 3:b4047e8a0123 1970 t->snd_nxt = SEQN(una);
daniele 3:b4047e8a0123 1971
daniele 3:b4047e8a0123 1972 /* Alternative to the line above: (better performance, but seems to lock anyway with larger buffers)
daniele 3:b4047e8a0123 1973 if (seq_compare(t->snd_nxt, SEQN(una)) > 0)
daniele 3:b4047e8a0123 1974 t->snd_nxt -= f->payload_len;
daniele 3:b4047e8a0123 1975 */
daniele 3:b4047e8a0123 1976
daniele 3:b4047e8a0123 1977 t->x_mode = PICO_TCP_WINDOW_FULL;
daniele 3:b4047e8a0123 1978 if (t->keepalive_timer_running == 0) {
daniele 3:b4047e8a0123 1979 tcp_dbg("[Window full] Adding timer(send keepalive)\n");
daniele 3:b4047e8a0123 1980 tcp_send_keepalive(0, t);
daniele 3:b4047e8a0123 1981 }
daniele 3:b4047e8a0123 1982 }
daniele 3:b4047e8a0123 1983 break;
daniele 3:b4047e8a0123 1984 }
daniele 3:b4047e8a0123 1985 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);
daniele 3:b4047e8a0123 1986 tcp_send(t, f);
daniele 3:b4047e8a0123 1987 sent++;
daniele 3:b4047e8a0123 1988 loop_score--;
daniele 3:b4047e8a0123 1989 t->snd_last_out = SEQN(f);
daniele 3:b4047e8a0123 1990 if (loop_score < 1)
daniele 3:b4047e8a0123 1991 break;
daniele 3:b4047e8a0123 1992 if (f->payload_len > 0) {
daniele 3:b4047e8a0123 1993 f = next_segment(&t->tcpq_out, f);
daniele 3:b4047e8a0123 1994 } else {
daniele 3:b4047e8a0123 1995 f = NULL;
daniele 3:b4047e8a0123 1996 }
daniele 3:b4047e8a0123 1997 }
daniele 3:b4047e8a0123 1998 if (sent > 0) {
daniele 3:b4047e8a0123 1999 if (t->rto < PICO_TCP_RTO_MIN)
daniele 3:b4047e8a0123 2000 t->rto = PICO_TCP_RTO_MIN;
daniele 3:b4047e8a0123 2001 add_retransmission_timer(t, pico_tick + t->rto);
daniele 3:b4047e8a0123 2002 } else {
daniele 3:b4047e8a0123 2003 // no packets in queue ??
daniele 3:b4047e8a0123 2004 }
daniele 3:b4047e8a0123 2005
daniele 3:b4047e8a0123 2006 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 */
daniele 3:b4047e8a0123 2007 if ((s->state & PICO_SOCKET_STATE_TCP) == PICO_SOCKET_STATE_TCP_ESTABLISHED) {
daniele 3:b4047e8a0123 2008 tcp_dbg("TCP> buffer empty, shutdown established ...\n");
daniele 3:b4047e8a0123 2009 /* send fin if queue empty and in state shut local (write) */
daniele 3:b4047e8a0123 2010 tcp_send_fin(t);
daniele 3:b4047e8a0123 2011 /* change tcp state to FIN_WAIT1 */
daniele 3:b4047e8a0123 2012 s->state &= 0x00FFU;
daniele 3:b4047e8a0123 2013 s->state |= PICO_SOCKET_STATE_TCP_FIN_WAIT1;
daniele 3:b4047e8a0123 2014 } else if ((s->state & PICO_SOCKET_STATE_TCP) == PICO_SOCKET_STATE_TCP_CLOSE_WAIT) {
daniele 3:b4047e8a0123 2015 /* send fin if queue empty and in state shut local (write) */
daniele 3:b4047e8a0123 2016 tcp_send_fin(t);
daniele 3:b4047e8a0123 2017 /* change tcp state to LAST_ACK */
daniele 3:b4047e8a0123 2018 s->state &= 0x00FFU;
daniele 3:b4047e8a0123 2019 s->state |= PICO_SOCKET_STATE_TCP_LAST_ACK;
daniele 3:b4047e8a0123 2020 tcp_dbg("TCP> STATE: LAST_ACK.\n");
daniele 3:b4047e8a0123 2021 }
daniele 3:b4047e8a0123 2022 }
daniele 3:b4047e8a0123 2023 return loop_score;
daniele 3:b4047e8a0123 2024 }
daniele 3:b4047e8a0123 2025
daniele 3:b4047e8a0123 2026 /* function to make new segment from hold queue with specific size (mss) */
daniele 3:b4047e8a0123 2027 static struct pico_frame * pico_hold_segment_make(struct pico_socket_tcp *t)
daniele 3:b4047e8a0123 2028 {
daniele 3:b4047e8a0123 2029 struct pico_frame *f_temp,*f_new;
daniele 3:b4047e8a0123 2030 struct pico_socket *s = (struct pico_socket *) &t->sock;
daniele 3:b4047e8a0123 2031 struct pico_tcp_hdr *hdr;
daniele 3:b4047e8a0123 2032 int total_len = 0, total_payload_len = 0;
daniele 3:b4047e8a0123 2033 int off = 0, test = 0;
daniele 3:b4047e8a0123 2034
daniele 3:b4047e8a0123 2035 off = pico_tcp_overhead(s);
daniele 3:b4047e8a0123 2036
daniele 3:b4047e8a0123 2037 /* init with first frame in hold queue */
daniele 3:b4047e8a0123 2038 f_temp = first_segment(&t->tcpq_hold);
daniele 3:b4047e8a0123 2039 total_len = f_temp->payload_len;
daniele 3:b4047e8a0123 2040 f_temp = next_segment(&t->tcpq_hold, f_temp);
daniele 3:b4047e8a0123 2041
daniele 3:b4047e8a0123 2042 /* check till total_len <= MSS */
daniele 3:b4047e8a0123 2043 while ((f_temp != NULL) && ((total_len+f_temp->payload_len) <= PICO_TCP_DEFAULT_MSS)) {
daniele 3:b4047e8a0123 2044 total_len += f_temp->payload_len;
daniele 3:b4047e8a0123 2045 f_temp = next_segment(&t->tcpq_hold, f_temp);
daniele 3:b4047e8a0123 2046 if (f_temp == NULL)
daniele 3:b4047e8a0123 2047 break;
daniele 3:b4047e8a0123 2048 }
daniele 3:b4047e8a0123 2049 /* alloc new frame with payload size = off + total_len */
daniele 3:b4047e8a0123 2050 f_new = pico_socket_frame_alloc(s, off + total_len);
daniele 3:b4047e8a0123 2051 if (!f_new) {
daniele 3:b4047e8a0123 2052 pico_err = PICO_ERR_ENOMEM;
daniele 3:b4047e8a0123 2053 return f_new;
daniele 3:b4047e8a0123 2054 }
daniele 3:b4047e8a0123 2055
daniele 3:b4047e8a0123 2056 hdr = (struct pico_tcp_hdr *) f_new->transport_hdr;
daniele 3:b4047e8a0123 2057 /* init new frame */
daniele 3:b4047e8a0123 2058 f_new->payload += off;
daniele 3:b4047e8a0123 2059 f_new->payload_len -= off;
daniele 3:b4047e8a0123 2060 f_new->sock = s;
daniele 3:b4047e8a0123 2061
daniele 3:b4047e8a0123 2062 f_temp = first_segment(&t->tcpq_hold);
daniele 3:b4047e8a0123 2063 hdr->seq = ((struct pico_tcp_hdr *)(f_temp->transport_hdr))->seq; /* get sequence number of first frame */
daniele 3:b4047e8a0123 2064 hdr->trans.sport = t->sock.local_port;
daniele 3:b4047e8a0123 2065 hdr->trans.dport = t->sock.remote_port;
daniele 3:b4047e8a0123 2066
daniele 3:b4047e8a0123 2067 /* check till total_payload_len <= MSS */
daniele 3:b4047e8a0123 2068 while ((f_temp != NULL) && ((total_payload_len + f_temp->payload_len) <= PICO_TCP_DEFAULT_MSS)) {
daniele 3:b4047e8a0123 2069 /* cpy data and discard frame */
daniele 3:b4047e8a0123 2070 test++;
daniele 3:b4047e8a0123 2071 memcpy(f_new->payload + total_payload_len, f_temp->payload, f_temp->payload_len);
daniele 3:b4047e8a0123 2072 total_payload_len += f_temp->payload_len;
daniele 3:b4047e8a0123 2073 pico_discard_segment(&t->tcpq_hold, f_temp);
daniele 3:b4047e8a0123 2074 f_temp = first_segment(&t->tcpq_hold);
daniele 3:b4047e8a0123 2075 }
daniele 3:b4047e8a0123 2076
daniele 3:b4047e8a0123 2077 hdr->len = (f_new->payload - f_new->transport_hdr) << 2 | t->jumbo;
daniele 3:b4047e8a0123 2078
daniele 3:b4047e8a0123 2079 tcp_dbg("NAGLE make - joined %d segments, len %d bytes\n",test,total_payload_len);
daniele 3:b4047e8a0123 2080
daniele 3:b4047e8a0123 2081 return f_new;
daniele 3:b4047e8a0123 2082 }
daniele 3:b4047e8a0123 2083
daniele 3:b4047e8a0123 2084 /* original behavior kept when Nagle disabled;
daniele 3:b4047e8a0123 2085 Nagle algorithm added here, keeping hold frame queue instead of eg linked list of data */
daniele 3:b4047e8a0123 2086 int pico_tcp_push(struct pico_protocol *self, struct pico_frame *f)
daniele 3:b4047e8a0123 2087 {
daniele 3:b4047e8a0123 2088 struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *)f->transport_hdr;
daniele 3:b4047e8a0123 2089 struct pico_socket_tcp *t = (struct pico_socket_tcp *) f->sock;
daniele 3:b4047e8a0123 2090 struct pico_frame *f_new;
daniele 3:b4047e8a0123 2091 int total_len = 0;
daniele 3:b4047e8a0123 2092
daniele 3:b4047e8a0123 2093 hdr->trans.sport = t->sock.local_port;
daniele 3:b4047e8a0123 2094 hdr->trans.dport = t->sock.remote_port;
daniele 3:b4047e8a0123 2095 hdr->seq = long_be(t->snd_last + 1);
daniele 3:b4047e8a0123 2096 hdr->len = (f->payload - f->transport_hdr) << 2 | t->jumbo;
daniele 3:b4047e8a0123 2097
daniele 3:b4047e8a0123 2098 if (f->payload_len > (t->tcpq_out.max_size - t->tcpq_out.size))
daniele 3:b4047e8a0123 2099 t->sock.ev_pending &= (~PICO_SOCK_EV_WR);
daniele 3:b4047e8a0123 2100
daniele 3:b4047e8a0123 2101 /***************************************************************************/
daniele 3:b4047e8a0123 2102
daniele 3:b4047e8a0123 2103 if (!IS_NAGLE_ENABLED((&(t->sock)))) {
daniele 3:b4047e8a0123 2104 /* TCP_NODELAY enabled, original behavior */
daniele 3:b4047e8a0123 2105 if (pico_enqueue_segment(&t->tcpq_out,f) > 0) {
daniele 3:b4047e8a0123 2106 tcp_dbg("TCP_PUSH - NO NAGLE - Pushing segment %08x, len %08x to socket %p\n", t->snd_last + 1, f->payload_len, t);
daniele 3:b4047e8a0123 2107 t->snd_last += f->payload_len;
daniele 3:b4047e8a0123 2108 return f->payload_len;
daniele 3:b4047e8a0123 2109 } else {
daniele 3:b4047e8a0123 2110 tcp_dbg("Enqueue failed.\n");
daniele 3:b4047e8a0123 2111 return 0;
daniele 3:b4047e8a0123 2112 }
daniele 3:b4047e8a0123 2113 }
daniele 3:b4047e8a0123 2114 /***************************************************************************/
daniele 3:b4047e8a0123 2115 else {
daniele 3:b4047e8a0123 2116 /* Nagle's algorithm enabled, check if ready to send, or put frame in hold queue */
daniele 3:b4047e8a0123 2117 if (IS_TCP_IDLE(t) && IS_TCP_HOLDQ_EMPTY(t)) { /* opt 1. send frame */
daniele 3:b4047e8a0123 2118 if (pico_enqueue_segment(&t->tcpq_out,f) > 0) {
daniele 3:b4047e8a0123 2119 tcp_dbg("TCP_PUSH - NAGLE - Pushing segment %08x, len %08x to socket %p\n", t->snd_last + 1, f->payload_len, t);
daniele 3:b4047e8a0123 2120 t->snd_last += f->payload_len;
daniele 3:b4047e8a0123 2121 return f->payload_len;
daniele 3:b4047e8a0123 2122 } else {
daniele 3:b4047e8a0123 2123 tcp_dbg("Enqueue failed.\n");
daniele 3:b4047e8a0123 2124 return 0;
daniele 3:b4047e8a0123 2125 }
daniele 3:b4047e8a0123 2126 } else { /* opt 2. hold data back */
daniele 3:b4047e8a0123 2127 total_len = f->payload_len + t->tcpq_hold.size;
daniele 3:b4047e8a0123 2128 if ((total_len >= PICO_TCP_DEFAULT_MSS) && ((t->tcpq_out.max_size - t->tcpq_out.size) >= PICO_TCP_DEFAULT_MSS)) {/* TODO check mss socket */
daniele 3:b4047e8a0123 2129 /* IF enough data in hold (>mss) AND space in out queue (>mss) */
daniele 3:b4047e8a0123 2130 /* add current frame in hold and make new segment */
daniele 3:b4047e8a0123 2131 if (pico_enqueue_segment(&t->tcpq_hold,f) > 0 ) {
daniele 3:b4047e8a0123 2132 tcp_dbg("TCP_PUSH - NAGLE - Pushed into hold, make new (enqueued frames out %d)\n",t->tcpq_out.frames);
daniele 3:b4047e8a0123 2133 t->snd_last += f->payload_len; /* XXX WATCH OUT */
daniele 3:b4047e8a0123 2134 f_new = pico_hold_segment_make(t);
daniele 3:b4047e8a0123 2135 } else {
daniele 3:b4047e8a0123 2136 tcp_dbg("TCP_PUSH - NAGLE - enqueue hold failed 1\n");
daniele 3:b4047e8a0123 2137 return 0;
daniele 3:b4047e8a0123 2138 }
daniele 3:b4047e8a0123 2139 /* and put new frame in out queue */
daniele 3:b4047e8a0123 2140 if ((f_new != NULL) && (pico_enqueue_segment(&t->tcpq_out,f_new) > 0)) {
daniele 3:b4047e8a0123 2141 return f_new->payload_len;
daniele 3:b4047e8a0123 2142 } else {
daniele 3:b4047e8a0123 2143 tcp_dbg("TCP_PUSH - NAGLE - enqueue out failed, f_new = %p\n",f_new);
daniele 3:b4047e8a0123 2144 return -1; /* XXX something seriously wrong */
daniele 3:b4047e8a0123 2145 }
daniele 3:b4047e8a0123 2146 } else {
daniele 3:b4047e8a0123 2147 /* ELSE put frame in hold queue */
daniele 3:b4047e8a0123 2148 if (pico_enqueue_segment(&t->tcpq_hold,f) > 0) {
daniele 3:b4047e8a0123 2149 tcp_dbg("TCP_PUSH - NAGLE - Pushed into hold (enqueued frames out %d)\n",t->tcpq_out.frames);
daniele 3:b4047e8a0123 2150 t->snd_last += f->payload_len; /* XXX WATCH OUT */
daniele 3:b4047e8a0123 2151 return f->payload_len;
daniele 3:b4047e8a0123 2152 } else {
daniele 3:b4047e8a0123 2153 tcp_dbg("TCP_PUSH - NAGLE - enqueue hold failed 2\n");
daniele 3:b4047e8a0123 2154 return 0;
daniele 3:b4047e8a0123 2155 }
daniele 3:b4047e8a0123 2156 }
daniele 3:b4047e8a0123 2157 }
daniele 3:b4047e8a0123 2158 }
daniele 3:b4047e8a0123 2159 /***************************************************************************/
daniele 3:b4047e8a0123 2160 }
daniele 3:b4047e8a0123 2161 #endif //PICO_SUPPORT_TCP