CDC/ECM driver for mbed, based on USBDevice by mbed-official. Uses PicoTCP to access Ethernet USB device. License: GPLv2

Dependents:   USBEthernet_TEST

Fork of USB_Ethernet by Daniele Lacamera

Committer:
daniele
Date:
Sat Aug 03 13:16:14 2013 +0000
Revision:
2:540f6e142d59
Moved to single package

Who changed what in which revision?

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