CDC/ECM driver for mbed, based on USBDevice by mbed-official. Uses PicoTCP to access Ethernet USB device. License: GPLv2
Fork of USB_Ethernet by
pico_tcp.c
00001 /********************************************************************* 00002 PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. 00003 See LICENSE and COPYING for usage. 00004 00005 . 00006 00007 Authors: Daniele Lacamera, Philippe Mariman 00008 *********************************************************************/ 00009 00010 #include "pico_tcp.h" 00011 #include "pico_config.h" 00012 #include "pico_eth.h" 00013 #include "pico_socket.h" 00014 #include "pico_stack.h" 00015 #include "pico_socket.h" 00016 #include "pico_queue.h" 00017 #include "pico_tree.h" 00018 00019 #define TCP_SOCK(s) ((struct pico_socket_tcp *)s) 00020 #define SEQN(f) (f?(long_be(((struct pico_tcp_hdr *)(f->transport_hdr))->seq)):0) 00021 #define ACKN(f) (f?(long_be(((struct pico_tcp_hdr *)(f->transport_hdr))->ack)):0) 00022 00023 #define PICO_TCP_RTO_MIN 10 00024 #define PICO_TCP_RTO_MAX 120000 00025 #define PICO_TCP_IW 2 00026 #define PICO_TCP_SYN_TO 1000 00027 00028 #define PICO_TCP_MAX_CONNECT_RETRIES 7 00029 00030 #define PICO_TCP_LOOKAHEAD 0x00 00031 #define PICO_TCP_FIRST_DUPACK 0x01 00032 #define PICO_TCP_SECOND_DUPACK 0x02 00033 #define PICO_TCP_RECOVER 0x03 00034 #define PICO_TCP_BLACKOUT 0x04 00035 #define PICO_TCP_UNREACHABLE 0x05 00036 #define PICO_TCP_WINDOW_FULL 0x06 00037 00038 /* check if the Nagle algorithm is enabled on the socket */ 00039 #define IS_NAGLE_ENABLED(s) (!(!(!(s->opt_flags & (1 << PICO_SOCKET_OPT_TCPNODELAY))))) 00040 /* check if tcp connection is "idle" according to Nagle (RFC 896) */ 00041 #define IS_TCP_IDLE(t) ((t->in_flight == 0) && (t->tcpq_out.size == 0)) 00042 /* check if the hold queue contains data (again Nagle) */ 00043 #define IS_TCP_HOLDQ_EMPTY(t) (t->tcpq_hold.size == 0) 00044 00045 #ifdef PICO_SUPPORT_TCP 00046 #define tcp_dbg_nagle(...) do{}while(0) 00047 #define tcp_dbg_options(...) do{}while(0) 00048 00049 00050 #define tcp_dbg(...) do{}while(0) 00051 //#define tcp_dbg dbg 00052 00053 00054 #ifdef PICO_SUPPORT_MUTEX 00055 static void * Mutex = NULL; 00056 #define LOCK(x) {\ 00057 if (x == NULL) \ 00058 x = pico_mutex_init(); \ 00059 pico_mutex_lock(x); \ 00060 } 00061 #define UNLOCK(x) pico_mutex_unlock(x); 00062 00063 #else 00064 #define LOCK(x) do{}while(0) 00065 #define UNLOCK(x) do{}while(0) 00066 #endif 00067 00068 00069 static inline int seq_compare(uint32_t a, uint32_t b) 00070 { 00071 uint32_t thresh = ((uint32_t)(-1))>>1; 00072 if (((a > thresh) && (b > thresh)) || ((a <= thresh) && (b <= thresh))) { 00073 if (a > b) 00074 return 1; 00075 if (b > a) 00076 return -1; 00077 } else { 00078 if (a > b) 00079 return -2; 00080 if (b > a) 00081 return 2; 00082 } 00083 return 0; 00084 } 00085 00086 static int segment_compare(void * ka, void * kb) 00087 { 00088 struct pico_frame *a = ka, *b = kb; 00089 return seq_compare(SEQN(a), SEQN(b)); 00090 } 00091 00092 struct pico_tcp_queue 00093 { 00094 struct pico_tree pool; 00095 uint32_t max_size; 00096 uint32_t size; 00097 uint32_t frames; 00098 }; 00099 00100 static struct pico_frame *peek_segment(struct pico_tcp_queue *tq, uint32_t seq) 00101 { 00102 struct pico_tcp_hdr H; 00103 struct pico_frame f = {}; 00104 f.transport_hdr = (uint8_t *) (&H); 00105 H.seq = long_be(seq); 00106 00107 return pico_tree_findKey(&tq->pool,&f); 00108 } 00109 00110 static struct pico_frame *first_segment(struct pico_tcp_queue *tq) 00111 { 00112 return pico_tree_first(&tq->pool); 00113 } 00114 00115 static struct pico_frame *next_segment(struct pico_tcp_queue *tq, struct pico_frame *cur) 00116 { 00117 if (!cur) 00118 return NULL; 00119 return peek_segment(tq, SEQN(cur) + cur->payload_len); 00120 } 00121 00122 static int pico_enqueue_segment(struct pico_tcp_queue *tq, struct pico_frame *f) 00123 { 00124 int ret = -1; 00125 if (f->payload_len <= 0) { 00126 tcp_dbg("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! TRIED TO ENQUEUE INVALID SEGMENT!\n"); 00127 //abort(); 00128 return -1; 00129 } 00130 LOCK(Mutex); 00131 if ((tq->size + f->payload_len) > tq->max_size) 00132 { 00133 ret = 0; 00134 goto out; 00135 } 00136 if (pico_tree_insert(&tq->pool,f) != 0) 00137 { 00138 ret = 0; 00139 goto out; 00140 } 00141 tq->size += f->payload_len; 00142 if (f->payload_len > 0) 00143 tq->frames++; 00144 ret = f->payload_len; 00145 00146 out : 00147 UNLOCK(Mutex); 00148 return ret; 00149 } 00150 00151 static void pico_discard_segment(struct pico_tcp_queue *tq, struct pico_frame *f) 00152 { 00153 struct pico_frame *f1; 00154 LOCK(Mutex); 00155 f1 = pico_tree_delete(&tq->pool,f); 00156 if (f1) { 00157 tq->size -= f->payload_len; 00158 if (f->payload_len > 0) 00159 tq->frames--; 00160 } 00161 pico_frame_discard(f); 00162 UNLOCK(Mutex); 00163 } 00164 00165 /* Structure for TCP socket */ 00166 struct tcp_sack_block { 00167 uint32_t left; 00168 uint32_t right; 00169 struct tcp_sack_block *next; 00170 }; 00171 00172 struct pico_socket_tcp { 00173 struct pico_socket sock; 00174 00175 /* Tree/queues */ 00176 struct pico_tcp_queue tcpq_in; 00177 struct pico_tcp_queue tcpq_out; 00178 struct pico_tcp_queue tcpq_hold; /* buffer to hold delayed frames according to Nagle */ 00179 00180 /* tcp_output */ 00181 uint32_t snd_nxt; 00182 uint32_t snd_last; 00183 uint32_t snd_old_ack; 00184 uint32_t snd_retry; 00185 uint32_t snd_last_out; 00186 00187 /* congestion control */ 00188 uint32_t avg_rtt; 00189 uint32_t rttvar; 00190 uint32_t rto; 00191 uint32_t in_flight; 00192 uint8_t timer_running; 00193 uint8_t keepalive_timer_running; 00194 uint16_t cwnd_counter; 00195 uint16_t cwnd; 00196 uint16_t ssthresh; 00197 uint16_t recv_wnd; 00198 uint16_t recv_wnd_scale; 00199 00200 /* tcp_input */ 00201 uint32_t rcv_nxt; 00202 uint32_t rcv_ackd; 00203 uint32_t rcv_processed; 00204 uint16_t wnd; 00205 uint16_t wnd_scale; 00206 00207 /* options */ 00208 uint32_t ts_nxt; 00209 uint16_t mss; 00210 uint8_t sack_ok; 00211 uint8_t ts_ok; 00212 uint8_t mss_ok; 00213 uint8_t scale_ok; 00214 struct tcp_sack_block *sacks; 00215 uint8_t jumbo; 00216 00217 /* Transmission */ 00218 uint8_t x_mode; 00219 uint8_t dupacks; 00220 uint8_t backoff; 00221 00222 }; 00223 00224 /* Queues */ 00225 static struct pico_queue tcp_in = {}; 00226 static struct pico_queue tcp_out = {}; 00227 00228 /* If Nagle enabled, this function can make 1 new segment from smaller segments in hold queue */ 00229 static struct pico_frame * pico_hold_segment_make(struct pico_socket_tcp *t); 00230 00231 /* checks if tcpq_in is empty */ 00232 int pico_tcp_queue_in_is_empty(struct pico_socket *s) 00233 { 00234 struct pico_socket_tcp *t = (struct pico_socket_tcp *) s; 00235 00236 if (t->tcpq_in.frames == 0) 00237 return 1; 00238 else 00239 return 0; 00240 } 00241 00242 /* Useful for getting rid of the beginning of the buffer (read() op) */ 00243 static int release_until(struct pico_tcp_queue *q, uint32_t seq) 00244 { 00245 struct pico_frame *head = first_segment(q); 00246 int ret = 0; 00247 while (head && (seq_compare(SEQN(head) + head->payload_len, seq) <= 0)) { 00248 struct pico_frame *cur = head; 00249 head = next_segment(q, cur); 00250 tcp_dbg("Releasing %p\n", q); 00251 pico_discard_segment(q, cur); 00252 ret++; 00253 } 00254 return ret; 00255 } 00256 00257 static int release_all_until(struct pico_tcp_queue *q, uint32_t seq) 00258 { 00259 struct pico_frame *f = NULL, *tmp __attribute__((unused)); 00260 struct pico_tree_node * idx, * temp; 00261 int ret = 0; 00262 00263 pico_tree_foreach_safe(idx,&q->pool,temp){ 00264 f = idx->keyValue; 00265 if (seq_compare(SEQN(f) + f->payload_len, seq) <= 0) { 00266 tcp_dbg("Releasing %p\n", f); 00267 pico_discard_segment(q, f); 00268 ret++; 00269 } else 00270 return ret; 00271 } 00272 return ret; 00273 } 00274 00275 /* API calls */ 00276 00277 uint16_t pico_tcp_checksum_ipv4(struct pico_frame *f) 00278 { 00279 struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *) f->net_hdr; 00280 struct pico_tcp_hdr *tcp_hdr = (struct pico_tcp_hdr *) f->transport_hdr; 00281 struct pico_socket *s = f->sock; 00282 struct pico_ipv4_pseudo_hdr pseudo; 00283 00284 if (s) { 00285 /* Case of outgoing frame */ 00286 //dbg("TCP CRC: on outgoing frame\n"); 00287 pseudo.src.addr = s->local_addr.ip4.addr; 00288 pseudo.dst.addr = s->remote_addr.ip4.addr; 00289 } else { 00290 /* Case of incomming frame */ 00291 //dbg("TCP CRC: on incomming frame\n"); 00292 pseudo.src.addr = hdr->src.addr; 00293 pseudo.dst.addr = hdr->dst.addr; 00294 } 00295 pseudo.zeros = 0; 00296 pseudo.proto = PICO_PROTO_TCP; 00297 pseudo.len = short_be(f->transport_len); 00298 00299 return pico_dualbuffer_checksum(&pseudo, sizeof(struct pico_ipv4_pseudo_hdr), tcp_hdr, f->transport_len); 00300 } 00301 00302 static void tcp_send_fin(struct pico_socket_tcp *t); 00303 static int pico_tcp_process_out(struct pico_protocol *self, struct pico_frame *f) 00304 { 00305 struct pico_tcp_hdr *hdr; 00306 struct pico_socket_tcp *t = (struct pico_socket_tcp *)f->sock; 00307 hdr = (struct pico_tcp_hdr *)f->transport_hdr; 00308 00309 if (f->payload_len > 0) { 00310 tcp_dbg("Process out: sending %p (%d bytes)\n",f, f->payload_len); 00311 } else { 00312 tcp_dbg("Sending empty packet\n"); 00313 } 00314 00315 if (f->payload_len > 0) { 00316 if (seq_compare(SEQN(f) + f->payload_len, t->snd_nxt) > 0) { 00317 t->snd_nxt = SEQN(f) + f->payload_len; 00318 tcp_dbg("%s: snd_nxt is now %08x\n", __FUNCTION__, t->snd_nxt); 00319 } 00320 } else if (hdr->flags == PICO_TCP_ACK) { /* pure ack */ 00321 //hdr->seq = long_be(t->snd_nxt); /* XXX disabled this to not to mess with seq nrs of ACKs anymore */ 00322 } else { 00323 tcp_dbg("%s: non-pure ACK with len=0, fl:%04x\n", __FUNCTION__, hdr->flags); 00324 } 00325 00326 pico_network_send(f); 00327 return 0; 00328 } 00329 00330 int pico_tcp_push(struct pico_protocol *self, struct pico_frame *data); 00331 00332 /* Interface: protocol definition */ 00333 struct pico_protocol pico_proto_tcp = { 00334 .name = "tcp", 00335 .proto_number = PICO_PROTO_TCP, 00336 .layer = PICO_LAYER_TRANSPORT, 00337 .process_in = pico_transport_process_in, 00338 .process_out = pico_tcp_process_out, 00339 .push = pico_tcp_push, 00340 .q_in = &tcp_in, 00341 .q_out = &tcp_out, 00342 }; 00343 00344 static uint32_t pico_paws(void) 00345 { 00346 static unsigned long _paws = 0; 00347 _paws = pico_rand(); 00348 return long_be(_paws); /*XXX: implement paws */ 00349 } 00350 00351 static void tcp_add_options(struct pico_socket_tcp *ts, struct pico_frame *f, uint16_t flags, int optsiz) 00352 { 00353 uint32_t tsval = long_be(pico_tick); 00354 uint32_t tsecr = long_be(ts->ts_nxt); 00355 int i = 0; 00356 f->start = f->transport_hdr + PICO_SIZE_TCPHDR; 00357 00358 memset(f->start, PICO_TCP_OPTION_NOOP, optsiz); /* fill blanks with noop */ 00359 00360 if (flags & PICO_TCP_SYN) { 00361 f->start[i++] = PICO_TCP_OPTION_MSS; 00362 f->start[i++] = PICO_TCPOPTLEN_MSS; 00363 f->start[i++] = (ts->mss >> 8) & 0xFF; 00364 f->start[i++] = ts->mss & 0xFF; 00365 f->start[i++] = PICO_TCP_OPTION_SACK_OK; 00366 f->start[i++] = PICO_TCPOPTLEN_SACK_OK; 00367 } 00368 00369 f->start[i++] = PICO_TCP_OPTION_WS; 00370 f->start[i++] = PICO_TCPOPTLEN_WS; 00371 f->start[i++] = ts->wnd_scale; 00372 00373 if (optsiz >= 12) { 00374 f->start[i++] = PICO_TCP_OPTION_TIMESTAMP; 00375 f->start[i++] = PICO_TCPOPTLEN_TIMESTAMP; 00376 memcpy(f->start + i, &tsval, 4); 00377 i += 4; 00378 memcpy(f->start + i, &tsecr, 4); 00379 i += 4; 00380 } 00381 00382 if (flags & PICO_TCP_ACK) { 00383 struct tcp_sack_block *sb; 00384 int len_off; 00385 00386 if (ts->sack_ok && ts->sacks) { 00387 f->start[i++] = PICO_TCP_OPTION_SACK; 00388 len_off = i; 00389 f->start[i++] = PICO_TCPOPTLEN_SACK; 00390 while(ts->sacks) { 00391 sb = ts->sacks; 00392 ts->sacks = sb->next; 00393 memcpy(f->start + i, sb, 2 * sizeof(uint32_t)); 00394 i += (2 * sizeof(uint32_t)); 00395 f->start[len_off] += (2 * sizeof(uint32_t)); 00396 pico_free(sb); 00397 } 00398 } 00399 } 00400 if (i < optsiz) 00401 f->start[ optsiz - 1 ] = PICO_TCP_OPTION_END; 00402 } 00403 00404 static void tcp_send_ack(struct pico_socket_tcp *t); 00405 00406 static void tcp_set_space(struct pico_socket_tcp *t) 00407 { 00408 int mtu, space; 00409 int shift = 0; 00410 00411 mtu = t->mss + PICO_SIZE_TCPHDR + PICO_SIZE_TCPOPT_SYN ; 00412 if (t->tcpq_in.max_size == 0) { 00413 space = 1024 * 1024 * 1024; /* One Gigabyte, for unlimited sockets. */ 00414 } else { 00415 space = ((t->tcpq_in.max_size - t->tcpq_in.size) / mtu) * t->mss; 00416 } 00417 if (space < 0) 00418 space = 0; 00419 while(space > 0xFFFF) { 00420 space >>= 1; 00421 shift++; 00422 } 00423 if ((space != t->wnd) || (shift != t->wnd_scale) || ((space - t->wnd) > (space>>2))) { 00424 t->wnd = space; 00425 t->wnd_scale = shift; 00426 } 00427 } 00428 00429 /* Return 32-bit aligned option size */ 00430 static int tcp_options_size(struct pico_socket_tcp *t, uint16_t flags) 00431 { 00432 int size = 0; 00433 struct tcp_sack_block *sb = t->sacks; 00434 00435 if (flags & PICO_TCP_SYN) { /* Full options */ 00436 size = PICO_TCPOPTLEN_MSS + PICO_TCP_OPTION_SACK_OK + PICO_TCPOPTLEN_WS + PICO_TCPOPTLEN_TIMESTAMP; 00437 } else { 00438 00439 /* Always update window scale. */ 00440 size += PICO_TCPOPTLEN_WS; 00441 00442 if (t->ts_ok) 00443 size += PICO_TCPOPTLEN_TIMESTAMP; 00444 00445 size+= PICO_TCPOPTLEN_END; 00446 } 00447 if ((flags & PICO_TCP_ACK) && (t->sack_ok && sb)) { 00448 size += 2; 00449 while(sb) { 00450 size += (2 * sizeof(uint32_t)); 00451 sb = sb->next; 00452 } 00453 } 00454 size = (((size + 3) >> 2) << 2); 00455 return size; 00456 } 00457 00458 int pico_tcp_overhead(struct pico_socket *s) 00459 { 00460 if (!s) 00461 return 0; 00462 00463 return PICO_SIZE_TCPHDR + tcp_options_size((struct pico_socket_tcp *)s, 0); /* hdr + Options size for data pkt */ 00464 00465 } 00466 00467 static void tcp_process_sack(struct pico_socket_tcp *t, uint32_t start, uint32_t end) 00468 { 00469 struct pico_frame *f; 00470 struct pico_tree_node * index, * temp; 00471 int cmp; 00472 int count = 0; 00473 00474 pico_tree_foreach_safe(index,&t->tcpq_out.pool,temp){ 00475 f = index->keyValue; 00476 cmp = seq_compare(SEQN(f), start); 00477 if (cmp > 0) 00478 goto done; 00479 00480 if (cmp == 0) { 00481 cmp = seq_compare(SEQN(f) + f->payload_len, end); 00482 if (cmp > 0) { 00483 tcp_dbg("Invalid SACK: ignoring.\n"); 00484 } 00485 00486 tcp_dbg("Marking (by SACK) segment %08x BLK:[%08x::%08x]\n", SEQN(f), start, end); 00487 f->flags |= PICO_FRAME_FLAG_SACKED; 00488 count++; 00489 00490 if (cmp == 0) { 00491 /* that was last segment sacked. Job done */ 00492 goto done; 00493 } 00494 } 00495 } 00496 00497 done: 00498 if (t->x_mode > PICO_TCP_LOOKAHEAD) { 00499 if (t->in_flight > (count)) 00500 t->in_flight -= (count); 00501 else 00502 t->in_flight = 0; 00503 } 00504 } 00505 00506 static void tcp_rcv_sack(struct pico_socket_tcp *t, uint8_t *opt, int len) 00507 { 00508 uint32_t start, end; 00509 int i = 0; 00510 if (len % 8) { 00511 tcp_dbg("SACK: Invalid len.\n"); 00512 return; 00513 } 00514 while (i < len) { 00515 start = long_from(opt + i); 00516 i += 4; 00517 end = long_from(opt + i); 00518 i += 4; 00519 tcp_process_sack(t, long_be(start), long_be(end)); 00520 } 00521 } 00522 00523 static void tcp_parse_options(struct pico_frame *f) 00524 { 00525 struct pico_socket_tcp *t = (struct pico_socket_tcp *)f->sock; 00526 uint8_t *opt = f->transport_hdr + PICO_SIZE_TCPHDR; 00527 int i = 0; 00528 f->timestamp = 0; 00529 while (i < (f->transport_len - PICO_SIZE_TCPHDR)) { 00530 uint8_t type = opt[i++]; 00531 uint8_t len; 00532 if(i < (f->transport_len - PICO_SIZE_TCPHDR) && (type > 1)) 00533 len = opt[i++]; 00534 else 00535 len = 1; 00536 if (f->payload && ((opt + i) > f->payload)) 00537 break; 00538 tcp_dbg_options("Received option '%d', len = %d \n", type, len); 00539 switch (type) { 00540 case PICO_TCP_OPTION_NOOP: 00541 case PICO_TCP_OPTION_END: 00542 break; 00543 case PICO_TCP_OPTION_WS: 00544 if (len != PICO_TCPOPTLEN_WS) { 00545 tcp_dbg_options("TCP Window scale: bad len received (%d).\n", len); 00546 i += len - 2; 00547 break; 00548 } 00549 t->recv_wnd_scale = opt[i++]; 00550 tcp_dbg_options("TCP Window scale: received %d\n", t->recv_wnd_scale); 00551 break; 00552 case PICO_TCP_OPTION_SACK_OK: 00553 if (len != PICO_TCPOPTLEN_SACK_OK) { 00554 tcp_dbg_options("TCP option sack: bad len received.\n"); 00555 i += len - 2; 00556 break; 00557 } 00558 t->sack_ok = 1; 00559 break; 00560 case PICO_TCP_OPTION_MSS: { 00561 uint16_t mss; 00562 if (len != PICO_TCPOPTLEN_MSS) { 00563 tcp_dbg_options("TCP option mss: bad len received.\n"); 00564 i += len - 2; 00565 break; 00566 } 00567 t->mss_ok = 1; 00568 mss = short_from(opt + i); 00569 i += sizeof(uint16_t); 00570 if (t->mss > short_be(mss)) 00571 t->mss = short_be(mss); 00572 break; 00573 } 00574 case PICO_TCP_OPTION_TIMESTAMP: { 00575 uint32_t tsval, tsecr; 00576 if (len != PICO_TCPOPTLEN_TIMESTAMP) { 00577 tcp_dbg_options("TCP option timestamp: bad len received.\n"); 00578 i += len - 2; 00579 break; 00580 } 00581 t->ts_ok = 1; 00582 tsval = long_from(opt + i); 00583 i += sizeof(uint32_t); 00584 tsecr = long_from(opt + i); 00585 f->timestamp = long_be(tsecr); 00586 i += sizeof(uint32_t); 00587 t->ts_nxt = long_be(tsval); 00588 break; 00589 } 00590 case PICO_TCP_OPTION_SACK: 00591 { 00592 tcp_rcv_sack(t, opt + i, len - 2); 00593 i += len - 2; 00594 break; 00595 } 00596 default: 00597 tcp_dbg_options("TCP: received unsupported option %u\n", type); 00598 i += len - 2; 00599 } 00600 } 00601 } 00602 00603 static int tcp_send(struct pico_socket_tcp *ts, struct pico_frame *f) 00604 { 00605 struct pico_tcp_hdr *hdr= (struct pico_tcp_hdr *) f->transport_hdr; 00606 struct pico_frame *cpy; 00607 hdr->trans.sport = ts->sock.local_port; 00608 hdr->trans.dport = ts->sock.remote_port; 00609 if (!hdr->seq) 00610 hdr->seq = long_be(ts->snd_nxt); 00611 00612 if (ts->rcv_nxt != 0) { 00613 if ( (ts->rcv_ackd == 0) || (seq_compare(ts->rcv_ackd, ts->rcv_nxt) != 0) || (hdr->flags & PICO_TCP_ACK)) { 00614 hdr->flags |= PICO_TCP_ACK; 00615 hdr->ack = long_be(ts->rcv_nxt); 00616 ts->rcv_ackd = ts->rcv_nxt; 00617 } 00618 } 00619 00620 if (hdr->flags & PICO_TCP_SYN) { 00621 ts->snd_nxt++; 00622 } 00623 if (f->payload_len > 0) { 00624 hdr->flags |= PICO_TCP_PSH | PICO_TCP_ACK; 00625 hdr->ack = long_be(ts->rcv_nxt); 00626 ts->rcv_ackd = ts->rcv_nxt; 00627 ts->keepalive_timer_running = 2; /* XXX TODO check fix: added 1 to counter to postpone sending keepalive, ACK is in data segments */ 00628 } 00629 00630 f->start = f->transport_hdr + PICO_SIZE_TCPHDR; 00631 hdr->rwnd = short_be(ts->wnd); 00632 hdr->crc = 0; 00633 hdr->crc = short_be(pico_tcp_checksum_ipv4(f)); 00634 00635 /* TCP: ENQUEUE to PROTO ( Transmit ) */ 00636 cpy = pico_frame_copy(f); 00637 if ((pico_enqueue(&tcp_out, cpy) > 0)) { 00638 if (f->payload_len > 0) { 00639 ts->in_flight++; 00640 ts->snd_nxt += f->payload_len; /* update next pointer here to prevent sending same segment twice when called twice in same tick */ 00641 } 00642 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", 00643 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 ); 00644 } else { 00645 pico_frame_discard(cpy); 00646 } 00647 return 0; 00648 } 00649 00650 //#define PICO_TCP_SUPPORT_SOCKET_STATS 00651 00652 #ifdef PICO_TCP_SUPPORT_SOCKET_STATS 00653 static void sock_stats(unsigned long when, void *arg) 00654 { 00655 struct pico_socket_tcp *t = (struct pico_socket_tcp *)arg; 00656 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", 00657 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); 00658 pico_timer_add(2000, sock_stats, t); 00659 } 00660 #endif 00661 00662 struct pico_socket *pico_tcp_open(void) 00663 { 00664 struct pico_socket_tcp *t = pico_zalloc(sizeof(struct pico_socket_tcp)); 00665 if (!t) 00666 return NULL; 00667 t->mss = PICO_TCP_DEFAULT_MSS; 00668 00669 t->tcpq_in.pool.root = t->tcpq_hold.pool.root = t->tcpq_out.pool.root = &LEAF; 00670 t->tcpq_hold.pool.compare = t->tcpq_in.pool.compare = t->tcpq_out.pool.compare = segment_compare; 00671 00672 t->tcpq_in.max_size = PICO_DEFAULT_SOCKETQ; 00673 t->tcpq_out.max_size = PICO_DEFAULT_SOCKETQ; 00674 t->tcpq_hold.max_size = 2*PICO_TCP_DEFAULT_MSS; 00675 00676 /* disable Nagle by default */ 00677 t->sock.opt_flags |= (1 << PICO_SOCKET_OPT_TCPNODELAY); 00678 00679 #ifdef PICO_TCP_SUPPORT_SOCKET_STATS 00680 pico_timer_add(2000, sock_stats, t); 00681 #endif 00682 tcp_set_space(t); 00683 00684 return &t->sock; 00685 } 00686 00687 int pico_tcp_read(struct pico_socket *s, void *buf, int len) 00688 { 00689 struct pico_socket_tcp *t = TCP_SOCK(s); 00690 struct pico_frame *f; 00691 uint32_t in_frame_off, in_frame_len; 00692 int tot_rd_len = 0; 00693 00694 while (tot_rd_len < len) { 00695 /* To be sure we don't have garbage at the beginning */ 00696 release_until(&t->tcpq_in, t->rcv_processed); 00697 f = first_segment(&t->tcpq_in); 00698 if (!f) { 00699 tcp_set_space(t); 00700 goto out; 00701 } 00702 00703 /* Hole at the beginning of data, awaiting retransmissions. */ 00704 if (seq_compare(t->rcv_processed, SEQN(f)) < 0) { 00705 tcp_dbg("TCP> read hole beginning of data, %08x - %08x. rcv_nxt is %08x\n",t->rcv_processed, SEQN(f), t->rcv_nxt); 00706 goto out; 00707 } 00708 00709 if(seq_compare(t->rcv_processed, SEQN(f)) > 0) { 00710 in_frame_off = t->rcv_processed - SEQN(f); 00711 in_frame_len = f->payload_len - in_frame_off; 00712 } else { 00713 in_frame_off = 0; 00714 in_frame_len = f->payload_len; 00715 } 00716 if ((in_frame_len + tot_rd_len) > len) { 00717 in_frame_len = len - tot_rd_len; 00718 } 00719 00720 if (in_frame_len > f->payload_len - in_frame_off) 00721 in_frame_len = f->payload_len - in_frame_off; 00722 00723 memcpy((uint8_t *)buf + tot_rd_len, f->payload + in_frame_off, in_frame_len); 00724 tot_rd_len += in_frame_len; 00725 t->rcv_processed += in_frame_len; 00726 00727 if ((in_frame_len == 0) || (in_frame_len == f->payload_len)) { 00728 pico_discard_segment(&t->tcpq_in, f); 00729 } 00730 } 00731 00732 out: 00733 tcp_set_space(t); 00734 if (t->tcpq_in.size == 0) { 00735 s->ev_pending &= (~PICO_SOCK_EV_RD); 00736 } 00737 return tot_rd_len; 00738 } 00739 00740 int pico_tcp_initconn(struct pico_socket *s); 00741 static void initconn_retry(unsigned long when, void *arg) 00742 { 00743 struct pico_socket_tcp *t = (struct pico_socket_tcp *)arg; 00744 if (TCPSTATE(&t->sock) == PICO_SOCKET_STATE_TCP_SYN_SENT) { 00745 if (t->backoff > PICO_TCP_MAX_CONNECT_RETRIES) { 00746 tcp_dbg("TCP> Connection timeout. \n"); 00747 if (t->sock.wakeup) 00748 t->sock.wakeup(PICO_SOCK_EV_ERR, &t->sock); 00749 return; 00750 } 00751 tcp_dbg("TCP> SYN retry %d...\n", t->backoff); 00752 t->backoff++; 00753 pico_tcp_initconn(&t->sock); 00754 } else { 00755 tcp_dbg("TCP> Connection is already established: no retry needed. good.\n"); 00756 } 00757 } 00758 00759 int pico_tcp_initconn(struct pico_socket *s) 00760 { 00761 struct pico_socket_tcp *ts = TCP_SOCK(s); 00762 struct pico_frame *syn; 00763 struct pico_tcp_hdr *hdr; 00764 int opt_len = tcp_options_size(ts, PICO_TCP_SYN); 00765 00766 syn = s->net->alloc(s->net, PICO_SIZE_TCPHDR + opt_len); 00767 if (!syn) 00768 return -1; 00769 hdr = (struct pico_tcp_hdr *) syn->transport_hdr; 00770 00771 if (!ts->snd_nxt) 00772 ts->snd_nxt = long_be(pico_paws()); 00773 ts->snd_last = ts->snd_nxt; 00774 ts->cwnd = PICO_TCP_IW; 00775 ts->ssthresh = 40; 00776 syn->sock = s; 00777 hdr->seq = long_be(ts->snd_nxt); 00778 hdr->len = (PICO_SIZE_TCPHDR + opt_len) << 2 | ts->jumbo; 00779 hdr->flags = PICO_TCP_SYN; 00780 tcp_set_space(ts); 00781 hdr->rwnd = short_be(ts->wnd); 00782 tcp_add_options(ts,syn, PICO_TCP_SYN, opt_len); 00783 hdr->trans.sport = ts->sock.local_port; 00784 hdr->trans.dport = ts->sock.remote_port; 00785 00786 hdr->crc = 0; 00787 hdr->crc = short_be(pico_tcp_checksum_ipv4(syn)); 00788 00789 /* TCP: ENQUEUE to PROTO ( SYN ) */ 00790 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); 00791 pico_enqueue(&tcp_out, syn); 00792 pico_timer_add(PICO_TCP_SYN_TO << ts->backoff, initconn_retry, ts); 00793 return 0; 00794 } 00795 00796 static int tcp_send_synack(struct pico_socket *s) 00797 { 00798 struct pico_socket_tcp *ts = TCP_SOCK(s); 00799 struct pico_frame *synack; 00800 struct pico_tcp_hdr *hdr; 00801 int opt_len = tcp_options_size(ts, PICO_TCP_SYN | PICO_TCP_ACK); 00802 00803 synack = s->net->alloc(s->net, PICO_SIZE_TCPHDR + opt_len); 00804 if (!synack) 00805 return -1; 00806 hdr = (struct pico_tcp_hdr *) synack->transport_hdr; 00807 00808 synack->sock = s; 00809 hdr->len = (PICO_SIZE_TCPHDR + opt_len) << 2 | ts->jumbo; 00810 hdr->flags = PICO_TCP_SYN | PICO_TCP_ACK; 00811 hdr->rwnd = short_be(ts->wnd); 00812 hdr->seq = long_be(ts->snd_nxt); 00813 ts->rcv_processed = long_be(hdr->seq); 00814 ts->snd_last = ts->snd_nxt; 00815 tcp_set_space(ts); 00816 tcp_add_options(ts,synack, hdr->flags, opt_len); 00817 synack->payload_len = 0; 00818 synack->timestamp = pico_tick; 00819 tcp_send(ts, synack); 00820 pico_frame_discard(synack); 00821 return 0; 00822 } 00823 00824 static void tcp_send_empty(struct pico_socket_tcp *t, uint16_t flags) 00825 { 00826 struct pico_frame *f; 00827 struct pico_tcp_hdr *hdr; 00828 int opt_len = tcp_options_size(t, flags); 00829 f = t->sock.net->alloc(t->sock.net, PICO_SIZE_TCPHDR + opt_len); 00830 if (!f) { 00831 return; 00832 } 00833 f->sock = &t->sock; 00834 hdr = (struct pico_tcp_hdr *) f->transport_hdr; 00835 hdr->len = (PICO_SIZE_TCPHDR + opt_len) << 2 | t->jumbo; 00836 hdr->flags = flags; 00837 hdr->rwnd = short_be(t->wnd); 00838 tcp_set_space(t); 00839 tcp_add_options(t,f, flags, opt_len); 00840 hdr->trans.sport = t->sock.local_port; 00841 hdr->trans.dport = t->sock.remote_port; 00842 hdr->seq = long_be(t->snd_nxt); 00843 if ((flags & PICO_TCP_ACK) != 0) 00844 hdr->ack = long_be(t->rcv_nxt); 00845 t->rcv_ackd = t->rcv_nxt; 00846 00847 f->start = f->transport_hdr + PICO_SIZE_TCPHDR; 00848 hdr->rwnd = short_be(t->wnd); 00849 hdr->crc = 0; 00850 hdr->crc = short_be(pico_tcp_checksum_ipv4(f)); 00851 00852 /* TCP: ENQUEUE to PROTO */ 00853 pico_enqueue(&tcp_out, f); 00854 } 00855 00856 static void tcp_send_ack(struct pico_socket_tcp *t) 00857 { 00858 return tcp_send_empty(t, PICO_TCP_ACK); 00859 } 00860 00861 static int tcp_send_rst(struct pico_socket *s, struct pico_frame *fr) 00862 { 00863 struct pico_socket_tcp *t = (struct pico_socket_tcp *) s; 00864 struct pico_frame *f; 00865 struct pico_tcp_hdr *hdr, *hdr_rcv; 00866 int opt_len = tcp_options_size(t, PICO_TCP_RST); 00867 int close; 00868 00869 tcp_dbg("TCP SEND_RST >>>>>>>>>>>>>>> START\n"); 00870 00871 f = t->sock.net->alloc(t->sock.net, PICO_SIZE_TCPHDR + opt_len); 00872 00873 if (!f) { 00874 return -1; 00875 } 00876 00877 hdr_rcv = (struct pico_tcp_hdr *) fr->transport_hdr; 00878 00879 f->sock = &t->sock; 00880 hdr = (struct pico_tcp_hdr *) f->transport_hdr; 00881 hdr->len = (PICO_SIZE_TCPHDR + opt_len) << 2 | t->jumbo; 00882 hdr->flags = PICO_TCP_RST; 00883 hdr->rwnd = short_be(t->wnd); 00884 tcp_set_space(t); 00885 tcp_add_options(t,f, PICO_TCP_RST, opt_len); 00886 hdr->trans.sport = t->sock.local_port; 00887 hdr->trans.dport = t->sock.remote_port; 00888 hdr->seq = long_be(t->snd_nxt); 00889 00890 /* check if state is synchronized */ 00891 if (((s->state & PICO_SOCKET_STATE_TCP) > PICO_SOCKET_STATE_TCP_SYN_RECV)) { 00892 /* in synchronized state: send RST with seq = ack from previous segment */ 00893 hdr->seq = hdr_rcv->ack; 00894 close = 0; 00895 } else { 00896 /* non-synchronized state */ 00897 /* go to CLOSED here to prevent timer callback to go on after timeout */ 00898 (t->sock).state &= 0x00FFU; 00899 (t->sock).state |= PICO_SOCKET_STATE_TCP_CLOSED; 00900 close = 1; 00901 } 00902 00903 hdr->ack = long_be(t->rcv_nxt); 00904 t->rcv_ackd = t->rcv_nxt; 00905 f->start = f->transport_hdr + PICO_SIZE_TCPHDR; 00906 hdr->rwnd = short_be(t->wnd); 00907 hdr->crc = 0; 00908 hdr->crc = short_be(pico_tcp_checksum_ipv4(f)); 00909 00910 /* TCP: ENQUEUE to PROTO */ 00911 pico_enqueue(&tcp_out, f); 00912 00913 /* goto CLOSED */ 00914 if (close) { 00915 (t->sock).state &= 0xFF00U; 00916 (t->sock).state |= PICO_SOCKET_STATE_CLOSED; 00917 00918 /* call EV_FIN wakeup before deleting */ 00919 if ((t->sock).wakeup) 00920 (t->sock).wakeup(PICO_SOCK_EV_FIN, &(t->sock)); 00921 00922 /* delete socket */ 00923 pico_socket_del(&t->sock); 00924 00925 tcp_dbg("TCP SEND_RST >>>>>>>>>>>>>>> DONE, deleted socket\n"); 00926 } 00927 00928 return 0; 00929 } 00930 00931 int pico_tcp_reply_rst(struct pico_frame *fr) 00932 { 00933 struct pico_tcp_hdr *hdr; 00934 struct pico_frame *f; 00935 int size = PICO_SIZE_TCPHDR; 00936 00937 tcp_dbg("TCP>>>>>>>>>>>>>>>> sending RST ... <<<<<<<<<<<<<<<<<<\n"); 00938 00939 f = fr->sock->net->alloc(fr->sock->net, size); 00940 00941 /* fill in IP data from original frame */ 00942 // TODO if IPv4 00943 ((struct pico_ipv4_hdr *)(f->net_hdr))->dst.addr = ((struct pico_ipv4_hdr *)(fr->net_hdr))->src.addr; 00944 ((struct pico_ipv4_hdr *)(f->net_hdr))->src.addr = ((struct pico_ipv4_hdr *)(fr->net_hdr))->dst.addr; 00945 00946 /* fill in TCP data from original frame */ 00947 ((struct pico_tcp_hdr *)(f->transport_hdr))->trans.dport = ((struct pico_tcp_hdr *)(fr->transport_hdr))->trans.sport; 00948 ((struct pico_tcp_hdr *)(f->transport_hdr))->trans.sport = ((struct pico_tcp_hdr *)(fr->transport_hdr))->trans.dport; 00949 hdr = (struct pico_tcp_hdr *) f->transport_hdr; 00950 hdr->len = size << 2; 00951 hdr->flags = PICO_TCP_RST | PICO_TCP_ACK; 00952 hdr->rwnd = 0; 00953 if (((struct pico_tcp_hdr *)(fr->transport_hdr))->flags & PICO_TCP_ACK) { 00954 hdr->seq = ((struct pico_tcp_hdr *)(fr->transport_hdr))->ack; 00955 } else { 00956 hdr->seq = 0U; 00957 } 00958 00959 hdr->ack = ((struct pico_tcp_hdr *)(fr->transport_hdr))->seq + short_be(fr->payload_len); 00960 00961 /* enqueue for transmission */ 00962 pico_ipv4_frame_push(f,&(((struct pico_ipv4_hdr *)(f->net_hdr))->dst),PICO_PROTO_TCP); 00963 00964 return 0; 00965 } 00966 00967 static int tcp_nosync_rst(struct pico_socket *s, struct pico_frame *fr) 00968 { 00969 struct pico_socket_tcp *t = (struct pico_socket_tcp *) s; 00970 struct pico_frame *f; 00971 struct pico_tcp_hdr *hdr, *hdr_rcv; 00972 int opt_len = tcp_options_size(t, PICO_TCP_RST | PICO_TCP_ACK); 00973 00974 tcp_dbg("TCP SEND RST (NON-SYNC) >>>>>>>>>>>>>>>>>> state %x\n",(s->state & PICO_SOCKET_STATE_TCP)); 00975 if (((s->state & PICO_SOCKET_STATE_TCP) == PICO_SOCKET_STATE_TCP_LISTEN)) { 00976 /* XXX TODO NOTE: to prevent the parent socket from trying to send, because this socket has no knowledge of dst IP !!! */ 00977 return pico_tcp_reply_rst(fr); 00978 } 00979 00980 /***************************************************************************/ 00981 /* sending RST */ 00982 f = t->sock.net->alloc(t->sock.net, PICO_SIZE_TCPHDR + opt_len); 00983 00984 if (!f) { 00985 return -1; 00986 } 00987 00988 hdr_rcv = (struct pico_tcp_hdr *) fr->transport_hdr; 00989 00990 f->sock = &t->sock; 00991 hdr = (struct pico_tcp_hdr *) f->transport_hdr; 00992 hdr->len = (PICO_SIZE_TCPHDR + opt_len) << 2 | t->jumbo; 00993 hdr->flags = PICO_TCP_RST | PICO_TCP_ACK; 00994 hdr->rwnd = short_be(t->wnd); 00995 tcp_set_space(t); 00996 tcp_add_options(t,f, PICO_TCP_RST | PICO_TCP_ACK, opt_len); 00997 hdr->trans.sport = t->sock.local_port; 00998 hdr->trans.dport = t->sock.remote_port; 00999 01000 /* non-synchronized state */ 01001 if (hdr_rcv->flags & PICO_TCP_ACK) { 01002 hdr->seq = hdr_rcv->ack; 01003 } else { 01004 hdr->seq = 0U; 01005 } 01006 01007 hdr->ack = hdr_rcv->seq + short_be(fr->payload_len); 01008 01009 t->rcv_ackd = t->rcv_nxt; 01010 f->start = f->transport_hdr + PICO_SIZE_TCPHDR; 01011 hdr->rwnd = short_be(t->wnd); 01012 hdr->crc = 0; 01013 hdr->crc = short_be(pico_tcp_checksum_ipv4(f)); 01014 01015 /* TCP: ENQUEUE to PROTO */ 01016 pico_enqueue(&tcp_out, f); 01017 01018 /***************************************************************************/ 01019 01020 tcp_dbg("TCP SEND_RST (NON_SYNC) >>>>>>>>>>>>>>> DONE, ...\n"); 01021 01022 return 0; 01023 } 01024 01025 static void tcp_send_fin(struct pico_socket_tcp *t) 01026 { 01027 struct pico_frame *f; 01028 struct pico_tcp_hdr *hdr; 01029 int opt_len = tcp_options_size(t, PICO_TCP_FIN); 01030 f = t->sock.net->alloc(t->sock.net, PICO_SIZE_TCPHDR + opt_len); 01031 if (!f) { 01032 return; 01033 } 01034 f->sock = &t->sock; 01035 hdr = (struct pico_tcp_hdr *) f->transport_hdr; 01036 hdr->len = (PICO_SIZE_TCPHDR + opt_len) << 2 | t->jumbo; 01037 hdr->flags = PICO_TCP_FIN | PICO_TCP_ACK; 01038 hdr->ack = long_be(t->rcv_nxt); 01039 t->rcv_ackd = t->rcv_nxt; 01040 hdr->rwnd = short_be(t->wnd); 01041 tcp_set_space(t); 01042 tcp_add_options(t,f, PICO_TCP_FIN, opt_len); 01043 hdr->trans.sport = t->sock.local_port; 01044 hdr->trans.dport = t->sock.remote_port; 01045 hdr->seq = long_be(t->snd_nxt); /* XXX TODO check correct ?? --> snd_last? otherwise maybe data after FIN */ 01046 01047 f->start = f->transport_hdr + PICO_SIZE_TCPHDR; 01048 hdr->rwnd = short_be(t->wnd); 01049 hdr->crc = 0; 01050 hdr->crc = short_be(pico_tcp_checksum_ipv4(f)); 01051 //tcp_dbg("SENDING FIN...\n"); 01052 /* TCP: ENQUEUE to PROTO ( Pure ACK ) */ 01053 pico_enqueue(&tcp_out, f); 01054 t->snd_nxt++; 01055 } 01056 01057 static void tcp_sack_prepare(struct pico_socket_tcp *t) 01058 { 01059 struct pico_frame *pkt; 01060 uint32_t left=0, right=0; 01061 struct tcp_sack_block *sb; 01062 int n = 0; 01063 if (t->sacks) /* previous sacks are pending */ 01064 return; 01065 01066 pkt = first_segment(&t->tcpq_in); 01067 while(n < 3) { 01068 if (!pkt) { 01069 if(left) { 01070 sb = pico_zalloc(sizeof(struct tcp_sack_block)); 01071 if (!sb) 01072 break; 01073 sb->left = long_be(left); 01074 sb->right = long_be(right); 01075 n++; 01076 sb->next = t->sacks; 01077 t->sacks = sb; 01078 left = 0; 01079 right = 0; 01080 } 01081 break; 01082 } 01083 if ((SEQN(pkt) < t->rcv_nxt)) { 01084 pkt = next_segment(&t->tcpq_in, pkt); 01085 continue; 01086 } 01087 if (!left) { 01088 left = SEQN(pkt); 01089 right = SEQN(pkt) + pkt->payload_len; 01090 pkt = next_segment(&t->tcpq_in, pkt); 01091 continue; 01092 } 01093 if(SEQN(pkt) == (right + 1)) { 01094 right += pkt->payload_len; 01095 pkt = next_segment(&t->tcpq_in, pkt); 01096 continue; 01097 } else { 01098 sb = pico_zalloc(sizeof(struct tcp_sack_block)); 01099 if (!sb) 01100 break; 01101 sb->left = long_be(left); 01102 sb->right = long_be(right); 01103 n++; 01104 sb->next = t->sacks; 01105 t->sacks = sb; 01106 left = 0; 01107 right = 0; 01108 pkt = next_segment(&t->tcpq_in, pkt); 01109 } 01110 } 01111 } 01112 01113 static int tcp_data_in(struct pico_socket *s, struct pico_frame *f) 01114 { 01115 struct pico_socket_tcp *t = (struct pico_socket_tcp *)s; 01116 struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *) f->transport_hdr; 01117 01118 if (((hdr->len & 0xf0) >> 2) <= f->transport_len) { 01119 tcp_parse_options(f); 01120 f->payload = f->transport_hdr + ((hdr->len & 0xf0) >>2); 01121 f->payload_len = f->transport_len - ((hdr->len & 0xf0) >>2); 01122 tcp_dbg("TCP> Received segment. (exp: %x got: %x)\n", t->rcv_nxt, SEQN(f)); 01123 01124 if (seq_compare(SEQN(f), t->rcv_nxt) <= 0) { 01125 struct pico_frame *nxt; 01126 if (seq_compare(SEQN(f), t->rcv_nxt) == 0) { /* Exactly what we expected */ 01127 struct pico_frame *cpy = pico_frame_copy(f); 01128 /* Enqueue: try to put into RCV buffer */ 01129 if(pico_enqueue_segment(&t->tcpq_in, cpy) <= 0) { 01130 pico_frame_discard(cpy); 01131 } 01132 t->rcv_nxt = SEQN(f) + f->payload_len; 01133 nxt = peek_segment(&t->tcpq_in, t->rcv_nxt); 01134 while(nxt) { 01135 tcp_dbg("scrolling rcv_nxt...%08x\n", t->rcv_nxt); 01136 t->rcv_nxt += f->payload_len; 01137 nxt = peek_segment(&t->tcpq_in, t->rcv_nxt); 01138 } 01139 t->sock.ev_pending |= PICO_SOCK_EV_RD; 01140 t->rcv_nxt = SEQN(f) + f->payload_len; 01141 } else { 01142 tcp_dbg("TCP> lo segment. Uninteresting retransmission. (exp: %x got: %x)\n", t->rcv_nxt, SEQN(f)); 01143 } 01144 } else { 01145 tcp_dbg("TCP> hi segment. Possible packet loss. I'll dupack this. (exp: %x got: %x)\n", t->rcv_nxt, SEQN(f)); 01146 if (t->sack_ok) { 01147 tcp_sack_prepare(t); 01148 } 01149 } 01150 /* In either case, ack til recv_nxt. */ 01151 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)) { 01152 //tcp_dbg("SENDACK CALLED FROM OUTSIDE tcp_synack, state %x\n",t->sock.state); 01153 tcp_send_ack(t); 01154 } else { 01155 //tcp_dbg("SENDACK PREVENTED IN SYNSENT STATE\n"); 01156 } 01157 return 0; 01158 } else { 01159 tcp_dbg("TCP: invalid data in pkt len, exp: %d, got %d\n", (hdr->len & 0xf0) >> 2, f->transport_len); 01160 return -1; 01161 } 01162 } 01163 01164 static int tcp_ack_advance_una(struct pico_socket_tcp *t, struct pico_frame *f) 01165 { 01166 int ret = release_all_until(&t->tcpq_out, ACKN(f)); 01167 if (ret > 0) 01168 t->sock.ev_pending |= PICO_SOCK_EV_WR; 01169 return ret; 01170 } 01171 01172 static uint16_t time_diff(unsigned long a, unsigned long b) 01173 { 01174 if (a >= b) 01175 return (a - b); 01176 else 01177 return (b - a); 01178 } 01179 01180 static void tcp_rtt(struct pico_socket_tcp *t, uint32_t rtt) 01181 { 01182 01183 uint32_t avg = t->avg_rtt; 01184 uint32_t rvar = t->rttvar; 01185 if (!avg) { 01186 /* This follows RFC2988 01187 * (2.2) When the first RTT measurement R is made, the host MUST set 01188 * 01189 * SRTT <- R 01190 * RTTVAR <- R/2 01191 * RTO <- SRTT + max (G, K*RTTVAR) 01192 */ 01193 t->avg_rtt = rtt; 01194 t->rttvar = rtt >> 1; 01195 t->rto = t->avg_rtt + (t->rttvar << 4); 01196 } else { 01197 int var = (t->avg_rtt - rtt); 01198 if (var < 0) 01199 var = 0-var; 01200 /* RFC2988, section (2.3). Alpha and beta are the ones suggested. */ 01201 01202 /* First, evaluate a new value for the rttvar */ 01203 t->rttvar <<= 2; 01204 t->rttvar -= rvar; 01205 t->rttvar += var; 01206 t->rttvar >>= 2; 01207 01208 /* Then, calculate the new avg_rtt */ 01209 t->avg_rtt <<= 3; 01210 t->avg_rtt -= avg; 01211 t->avg_rtt += rtt; 01212 t->avg_rtt >>= 3; 01213 01214 /* Finally, assign a new value for the RTO, as specified in the RFC, with K=4 */ 01215 t->rto = t->avg_rtt + (t->rttvar << 2); 01216 } 01217 tcp_dbg(" -----=============== RTT CUR: %u AVG: %u RTTVAR: %u RTO: %u ======================----\n", rtt, t->avg_rtt, t->rttvar, t->rto); 01218 } 01219 01220 static void tcp_congestion_control(struct pico_socket_tcp *t) 01221 { 01222 if (t->x_mode > PICO_TCP_LOOKAHEAD) 01223 return; 01224 if (t->cwnd > t->tcpq_out.frames) { 01225 tcp_dbg("Limited by app: %d\n", t->cwnd); 01226 if (t->sock.wakeup) 01227 t->sock.wakeup(PICO_SOCK_EV_WR, &t->sock); 01228 return; 01229 } 01230 tcp_dbg("Doing congestion control\n"); 01231 if (t->cwnd < t->ssthresh) { 01232 t->cwnd++; 01233 } else { 01234 t->cwnd_counter++; 01235 if (t->cwnd_counter >= t->cwnd) { 01236 t->cwnd++; 01237 t->cwnd_counter = 0; 01238 } 01239 } 01240 tcp_dbg("TCP_CWND, %lu, %u, %u, %u\n", pico_tick, t->cwnd, t->ssthresh, t->in_flight); 01241 } 01242 01243 static void add_retransmission_timer(struct pico_socket_tcp *t, unsigned long next_ts); 01244 static void tcp_retrans_timeout(unsigned long val, void *sock) 01245 { 01246 struct pico_socket_tcp *t = (struct pico_socket_tcp *) sock; 01247 struct pico_frame *f = NULL; 01248 unsigned long limit = val - t->rto; 01249 struct pico_tcp_hdr *hdr; 01250 if( t->sock.net && ((t->sock.state & 0xFF00) == PICO_SOCKET_STATE_TCP_ESTABLISHED 01251 || (t->sock.state & 0xFF00) == PICO_SOCKET_STATE_TCP_CLOSE_WAIT) ) 01252 { 01253 tcp_dbg("\n\nTIMEOUT! backoff = %d\n", t->backoff); 01254 /* was timer cancelled? */ 01255 if (t->timer_running == 0) { 01256 add_retransmission_timer(t, 0); 01257 return; 01258 } 01259 t->timer_running--; 01260 01261 f = first_segment(&t->tcpq_out); 01262 while (f) { 01263 if ((t->x_mode == PICO_TCP_WINDOW_FULL) || 01264 ((f->timestamp != 0) && (f->timestamp <= limit))) { 01265 struct pico_frame *cpy; 01266 hdr = (struct pico_tcp_hdr *)f->transport_hdr; 01267 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); 01268 if ((t->x_mode != PICO_TCP_WINDOW_FULL) ) { 01269 t->x_mode = PICO_TCP_BLACKOUT; 01270 tcp_dbg("Mode: Blackout.\n"); 01271 t->cwnd = PICO_TCP_IW; 01272 t->in_flight = 0; 01273 } 01274 f->timestamp = pico_tick; 01275 tcp_add_options(t, f, 0, f->transport_len - f->payload_len - PICO_SIZE_TCPHDR); 01276 hdr->rwnd = short_be(t->wnd); 01277 hdr->flags |= PICO_TCP_PSH; 01278 hdr->ack = long_be(t->rcv_nxt); 01279 hdr->crc = 0; 01280 hdr->crc = short_be(pico_tcp_checksum_ipv4(f)); 01281 /* TCP: ENQUEUE to PROTO ( retransmit )*/ 01282 cpy = pico_frame_copy(f); 01283 if (pico_enqueue(&tcp_out, cpy) > 0) { 01284 t->backoff++; 01285 add_retransmission_timer(t, (t->rto << t->backoff) + pico_tick); 01286 tcp_dbg("TCP_CWND, %lu, %u, %u, %u\n", pico_tick, t->cwnd, t->ssthresh, t->in_flight); 01287 return; 01288 } else { 01289 add_retransmission_timer(t, (t->rto << t->backoff) + pico_tick); 01290 pico_frame_discard(cpy); 01291 } 01292 } 01293 f = next_segment(&t->tcpq_out, f); 01294 } 01295 t->backoff = 0; 01296 add_retransmission_timer(t, 0); 01297 if (t->tcpq_out.size < t->tcpq_out.max_size) 01298 t->sock.ev_pending |= PICO_SOCK_EV_WR; 01299 return; 01300 } 01301 } 01302 01303 static void add_retransmission_timer(struct pico_socket_tcp *t, unsigned long next_ts) 01304 { 01305 struct pico_tree_node * index; 01306 01307 if (t->timer_running > 0) 01308 return; 01309 01310 if (next_ts == 0) { 01311 struct pico_frame *f; 01312 01313 pico_tree_foreach(index,&t->tcpq_out.pool){ 01314 f = index->keyValue; 01315 if (((next_ts == 0) || (f->timestamp < next_ts)) && (f->timestamp > 0)) { 01316 next_ts = f->timestamp; 01317 } 01318 } 01319 } 01320 if (next_ts > 0) { 01321 if ((next_ts + t->rto) > pico_tick) { 01322 pico_timer_add(next_ts + t->rto - pico_tick, tcp_retrans_timeout, t); 01323 } else { 01324 pico_timer_add(1, tcp_retrans_timeout, t); 01325 } 01326 t->timer_running++; 01327 } 01328 } 01329 01330 static int tcp_retrans(struct pico_socket_tcp *t, struct pico_frame *f) 01331 { 01332 struct pico_frame *cpy; 01333 struct pico_tcp_hdr *hdr; 01334 if (f) { 01335 hdr = (struct pico_tcp_hdr *)f->transport_hdr; 01336 tcp_dbg("TCP> RETRANS (by dupack) frame %08x, len= %d\n", SEQN(f), f->payload_len); 01337 f->timestamp = pico_tick; 01338 tcp_add_options(t, f, 0, f->transport_len - f->payload_len - PICO_SIZE_TCPHDR); 01339 hdr->rwnd = short_be(t->wnd); 01340 hdr->flags |= PICO_TCP_PSH; 01341 hdr->ack = long_be(t->rcv_nxt); 01342 hdr->crc = 0; 01343 hdr->crc = short_be(pico_tcp_checksum_ipv4(f)); 01344 /* TCP: ENQUEUE to PROTO ( retransmit )*/ 01345 cpy = pico_frame_copy(f); 01346 if (pico_enqueue(&tcp_out, cpy) > 0) { 01347 t->in_flight++; 01348 t->snd_last_out = SEQN(cpy); 01349 add_retransmission_timer(t, pico_tick + t->rto); 01350 } else { 01351 pico_frame_discard(cpy); 01352 } 01353 return(f->payload_len); 01354 } 01355 return 0; 01356 } 01357 01358 #ifdef TCP_ACK_DBG 01359 static void tcp_ack_dbg(struct pico_socket *s, struct pico_frame *f) 01360 { 01361 uint32_t una, nxt, ack, cur; 01362 struct pico_frame *una_f = NULL, *cur_f; 01363 struct pico_tree_node *idx; 01364 struct pico_socket_tcp *t = (struct pico_socket_tcp *)s; 01365 char info[64]; 01366 char tmp[64]; 01367 ack = ACKN(f); 01368 nxt = t->snd_nxt; 01369 tcp_dbg("===================================\n"); 01370 tcp_dbg("Queue out (%d/%d). ACKED=%08x\n", t->tcpq_out.size, t->tcpq_out.max_size, ack); 01371 01372 pico_tree_foreach(idx, &t->tcpq_out.pool) { 01373 info[0] = 0; 01374 cur_f = idx->keyValue; 01375 cur = SEQN(cur_f); 01376 if (!una_f) { 01377 una_f = cur_f; 01378 una = SEQN(una_f); 01379 } 01380 01381 if (cur == nxt) { 01382 strncpy(tmp, info, strlen(info)); 01383 snprintf(info,64, "%s SND_NXT", tmp); 01384 } 01385 if (cur == ack) { 01386 strncpy(tmp, info, strlen(info)); 01387 snprintf(info,64, "%s ACK", tmp); 01388 } 01389 if (cur == una) { 01390 strncpy(tmp, info, strlen(info)); 01391 snprintf(info,64, "%s SND_UNA", tmp); 01392 } 01393 if (cur == t->snd_last) { 01394 strncpy(tmp, info, strlen(info)); 01395 snprintf(info,64, "%s SND_LAST", tmp); 01396 } 01397 tcp_dbg("%08x %d%s\n", cur, cur_f->payload_len, info); 01398 01399 } 01400 tcp_dbg("SND_NXT is %08x, snd_LAST is %08x", nxt, t->snd_last); 01401 tcp_dbg("===================================\n"); 01402 tcp_dbg("\n\n"); 01403 } 01404 #endif 01405 01406 static int tcp_ack(struct pico_socket *s, struct pico_frame *f) 01407 { 01408 struct pico_frame *f_new; /* use with Nagle to push to out queue */ 01409 struct pico_socket_tcp *t = (struct pico_socket_tcp *)s; 01410 struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *) f->transport_hdr; 01411 uint32_t rtt = 0; 01412 int acked = 0; 01413 struct pico_frame *una = NULL; 01414 if ((hdr->flags & PICO_TCP_ACK) == 0) 01415 return -1; 01416 01417 #ifdef TCP_ACK_DBG 01418 tcp_ack_dbg(s,f); 01419 #endif 01420 01421 tcp_parse_options(f); 01422 t->recv_wnd = short_be(hdr->rwnd); 01423 01424 acked = tcp_ack_advance_una(t, f); 01425 una = first_segment(&t->tcpq_out); 01426 01427 if ((t->x_mode == PICO_TCP_BLACKOUT) || 01428 ((t->x_mode == PICO_TCP_WINDOW_FULL) && ((t->recv_wnd << t->recv_wnd_scale) > t->mss))) { 01429 tcp_dbg("Re-entering look-ahead...\n\n\n"); 01430 t->x_mode = PICO_TCP_LOOKAHEAD; 01431 t->backoff = 0; 01432 } 01433 01434 /* One should be acked. */ 01435 // if ((acked == 0) && (t->in_flight > 0)) 01436 if ((acked == 0) && (f->payload_len == 0) && (t->in_flight > 0)) 01437 t->in_flight--; 01438 if (!una || acked > 0) { 01439 t->x_mode = PICO_TCP_LOOKAHEAD; 01440 tcp_dbg("Mode: Look-ahead. In flight: %d/%d buf: %d\n", t->in_flight, t->cwnd, t->tcpq_out.frames); 01441 t->backoff = 0; 01442 01443 /* Do rtt/rttvar/rto calculations */ 01444 /* First, try with timestamps, using the value from options */ 01445 if(f && (f->timestamp != 0)) { 01446 rtt = time_diff(pico_tick, f->timestamp); 01447 if (rtt) 01448 tcp_rtt(t, rtt); 01449 } else if(una && (una->timestamp != 0)) { 01450 /* If no timestamps are there, use conservatve estimation on the una */ 01451 rtt = time_diff(pico_tick, una->timestamp); 01452 if (rtt) 01453 tcp_rtt(t, rtt); 01454 } 01455 01456 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)); 01457 if (acked > t->in_flight) { 01458 tcp_dbg("WARNING: in flight < 0\n"); 01459 t->in_flight = 0; 01460 } else 01461 t->in_flight -= (acked); 01462 01463 } else if ((t->snd_old_ack == ACKN(f)) && /* We've just seen this ack, and... */ 01464 ((0 == (hdr->flags & (PICO_TCP_PSH | PICO_TCP_SYN))) && 01465 (f->payload_len == 0)) && /* This is a pure ack, and... */ 01466 (ACKN(f) != t->snd_nxt)) /* There is something in flight awaiting to be acked... */ 01467 { 01468 /* Process incoming duplicate ack. */ 01469 if (t->x_mode < PICO_TCP_RECOVER) { 01470 t->x_mode++; 01471 tcp_dbg("Mode: DUPACK %d, due to PURE ACK %0x, len = %d\n", t->x_mode, SEQN(f), f->payload_len); 01472 tcp_dbg("ACK: %x - QUEUE: %x\n",ACKN(f), SEQN(first_segment(&t->tcpq_out))); 01473 if (t->x_mode == PICO_TCP_RECOVER) { /* Switching mode */ 01474 t->snd_retry = SEQN(first_segment(&t->tcpq_out)); 01475 if (t->ssthresh > t->cwnd) 01476 t->ssthresh >>=2; 01477 else 01478 t->ssthresh = (t->cwnd >> 1); 01479 if (t->ssthresh < 2) 01480 t->ssthresh = 2; 01481 } 01482 } else if (t->x_mode == PICO_TCP_RECOVER) { 01483 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)); 01484 if (t->in_flight <= t->cwnd) { 01485 struct pico_frame *nxt = peek_segment(&t->tcpq_out, t->snd_retry); 01486 if (!nxt) 01487 nxt = first_segment(&t->tcpq_out); 01488 01489 while (nxt && (nxt->flags & PICO_FRAME_FLAG_SACKED) && (nxt != first_segment(&t->tcpq_out))) { 01490 tcp_dbg("Skipping %08x because it is sacked.\n", SEQN(nxt)); 01491 nxt = next_segment(&t->tcpq_out, nxt); 01492 } 01493 01494 if (nxt && (seq_compare(SEQN(nxt), t->snd_nxt)) > 0) 01495 nxt = NULL; 01496 if (nxt && (seq_compare(SEQN(nxt), SEQN(first_segment(&t->tcpq_out))) > (t->recv_wnd << t->recv_wnd_scale))) 01497 nxt = NULL; 01498 01499 if(!nxt) 01500 nxt = first_segment(&t->tcpq_out); 01501 if (nxt) { 01502 tcp_retrans(t, peek_segment(&t->tcpq_out, t->snd_retry)); 01503 t->snd_retry = SEQN(nxt); 01504 } 01505 } 01506 01507 if (++t->cwnd_counter > 1) { 01508 t->cwnd--; 01509 if (t->cwnd < 2) 01510 t->cwnd = 2; 01511 t->cwnd_counter = 0; 01512 } 01513 } else { 01514 tcp_dbg("DUPACK in mode %d \n", t->x_mode); 01515 01516 } 01517 } /* End case duplicate ack detection */ 01518 01519 /* Do congestion control */ 01520 tcp_congestion_control(t); 01521 if ((acked > 0) && t->sock.wakeup) { 01522 if (t->tcpq_out.size < t->tcpq_out.max_size) 01523 t->sock.wakeup(PICO_SOCK_EV_WR, &(t->sock)); 01524 //t->sock.ev_pending |= PICO_SOCK_EV_WR; 01525 } 01526 01527 /* if Nagle enabled, check if no unack'ed data and fill out queue (till window) */ 01528 if (IS_NAGLE_ENABLED((&(t->sock)))) { 01529 while (!IS_TCP_HOLDQ_EMPTY(t) && ((t->tcpq_out.max_size - t->tcpq_out.size) >= PICO_TCP_DEFAULT_MSS)) { 01530 tcp_dbg_nagle("TCP_ACK - NAGLE add new segment\n"); 01531 f_new = pico_hold_segment_make(t); 01532 if (f_new == NULL) 01533 break; /* XXX corrupt !!! (or no memory) */ 01534 if (pico_enqueue_segment(&t->tcpq_out,f_new) <= 0) 01535 // handle error 01536 tcp_dbg_nagle("TCP_ACK - NAGLE FAILED to enqueue in out\n"); 01537 } 01538 } 01539 01540 /* If some space was created, put a few segments out. */ 01541 tcp_dbg("TCP_CWND, %lu, %u, %u, %u\n", pico_tick, t->cwnd, t->ssthresh, t->in_flight); 01542 if (t->x_mode == PICO_TCP_LOOKAHEAD) { 01543 if ((t->cwnd >= t->in_flight) && (t->snd_nxt > t->snd_last_out)) { 01544 pico_tcp_output(&t->sock, t->cwnd - t->in_flight); 01545 } 01546 } 01547 01548 t->snd_old_ack = ACKN(f); 01549 return 0; 01550 } 01551 01552 static int tcp_finwaitack(struct pico_socket *s, struct pico_frame *f) 01553 { 01554 tcp_dbg("RECEIVED ACK IN FIN_WAIT1\nTCP> IN STATE FIN_WAIT2\n"); 01555 01556 /* acking part */ 01557 tcp_ack(s,f); 01558 /* update TCP state */ 01559 s->state &= 0x00FFU; 01560 s->state |= PICO_SOCKET_STATE_TCP_FIN_WAIT2; 01561 01562 return 0; 01563 } 01564 01565 static void tcp_deltcb(unsigned long when, void *arg) 01566 { 01567 struct pico_socket_tcp *t = (struct pico_socket_tcp *)arg; 01568 if (TCPSTATE(&t->sock) == PICO_SOCKET_STATE_TCP_TIME_WAIT) { 01569 tcp_dbg("TCP> state: time_wait, final timer expired, going to closed state\n"); 01570 /* update state */ 01571 (t->sock).state &= 0x00FFU; 01572 (t->sock).state |= PICO_SOCKET_STATE_TCP_CLOSED; 01573 (t->sock).state &= 0xFF00U; 01574 (t->sock).state |= PICO_SOCKET_STATE_CLOSED; 01575 /* call EV_FIN wakeup before deleting */ 01576 if (t->sock.wakeup) { 01577 (t->sock).wakeup(PICO_SOCK_EV_FIN, &(t->sock)); 01578 } 01579 /* delete socket */ 01580 pico_socket_del(&t->sock); 01581 } else { 01582 tcp_dbg("TCP> trying to go to closed, wrong state\n"); 01583 } 01584 } 01585 01586 static int tcp_finwaitfin(struct pico_socket *s, struct pico_frame *f) 01587 { 01588 struct pico_socket_tcp *t = (struct pico_socket_tcp *)s; 01589 struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *) (f->transport_hdr); 01590 tcp_dbg("TCP> received fin in FIN_WAIT2\n"); 01591 /* received FIN, increase ACK nr */ 01592 t->rcv_nxt = long_be(hdr->seq) + 1; 01593 s->state &= 0x00FFU; 01594 s->state |= PICO_SOCKET_STATE_TCP_TIME_WAIT; 01595 /* set SHUT_REMOTE */ 01596 s->state |= PICO_SOCKET_STATE_SHUT_REMOTE; 01597 if (s->wakeup) 01598 s->wakeup(PICO_SOCK_EV_CLOSE, s); 01599 if (f->payload_len > 0) /* needed?? */ 01600 tcp_data_in(s,f); 01601 /* send ACK */ 01602 tcp_send_ack(t); 01603 /* set timer */ 01604 pico_timer_add(200, tcp_deltcb, t); 01605 return 0; 01606 } 01607 01608 static int tcp_closewaitack(struct pico_socket *s, struct pico_frame *f) 01609 { 01610 struct pico_socket_tcp *t = (struct pico_socket_tcp *)s; 01611 tcp_dbg("TCP> received ack in CLOSING\n"); 01612 /* acking part */ 01613 tcp_ack(s,f); 01614 /* update TCP state */ 01615 s->state &= 0x00FFU; 01616 s->state |= PICO_SOCKET_STATE_TCP_TIME_WAIT; 01617 /* set timer */ 01618 pico_timer_add(200, tcp_deltcb, t); 01619 return 0; 01620 } 01621 01622 static int tcp_lastackwait(struct pico_socket *s, struct pico_frame *f) 01623 { 01624 tcp_dbg("TCP> state: last_ack, received ack, to closed\n"); 01625 s->state &= 0x00FFU; 01626 s->state |= PICO_SOCKET_STATE_TCP_CLOSED; 01627 s->state &= 0xFF00U; 01628 s->state |= PICO_SOCKET_STATE_CLOSED; 01629 /* call socket wakeup with EV_FIN */ 01630 if (s->wakeup) 01631 s->wakeup(PICO_SOCK_EV_FIN, s); 01632 /* delete socket */ 01633 pico_socket_del(s); 01634 return 0; 01635 } 01636 01637 static int tcp_syn(struct pico_socket *s, struct pico_frame *f) 01638 { 01639 /* TODO: Check against backlog length */ 01640 struct pico_socket_tcp *new = (struct pico_socket_tcp *)pico_socket_clone(s); 01641 struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *)f->transport_hdr; 01642 if (!new) 01643 return -1; 01644 01645 #ifdef PICO_TCP_SUPPORT_SOCKET_STATS 01646 pico_timer_add(2000, sock_stats, s); 01647 #endif 01648 01649 new->sock.remote_port = ((struct pico_trans *)f->transport_hdr)->sport; 01650 #ifdef PICO_SUPPORT_IPV4 01651 if (IS_IPV4(f)) { 01652 new->sock.remote_addr.ip4.addr = ((struct pico_ipv4_hdr *)(f->net_hdr))->src.addr; 01653 new->sock.local_addr.ip4.addr = ((struct pico_ipv4_hdr *)(f->net_hdr))->dst.addr; 01654 } 01655 #endif 01656 #ifdef PICO_SUPPORT_IPV6 01657 if (IS_IPV6(f)) { 01658 new->sock.remote_addr.ip6 = ((struct pico_ipv6_hdr *)(f->net_hdr))->src; 01659 new->sock.local_addr.ip6 = ((struct pico_ipv6_hdr *)(f->net_hdr))->dst; 01660 } 01661 #endif 01662 01663 /* Set socket limits */ 01664 new->tcpq_in.max_size = PICO_DEFAULT_SOCKETQ; 01665 new->tcpq_out.max_size = PICO_DEFAULT_SOCKETQ; 01666 new->tcpq_hold.max_size = 2*PICO_TCP_DEFAULT_MSS; 01667 01668 f->sock = &new->sock; 01669 tcp_parse_options(f); 01670 new->mss = PICO_TCP_DEFAULT_MSS; 01671 new->rcv_nxt = long_be(hdr->seq) + 1; 01672 new->snd_nxt = long_be(pico_paws()); 01673 new->snd_last = new->snd_nxt; 01674 new->cwnd = PICO_TCP_IW; 01675 new->ssthresh = 40; 01676 new->recv_wnd = short_be(hdr->rwnd); 01677 new->jumbo = hdr->len & 0x07; 01678 new->sock.parent = s; 01679 new->sock.wakeup = s->wakeup; 01680 /* Initialize timestamp values */ 01681 new->sock.state = PICO_SOCKET_STATE_BOUND | PICO_SOCKET_STATE_CONNECTED | PICO_SOCKET_STATE_TCP_SYN_RECV; 01682 pico_socket_add(&new->sock); 01683 tcp_send_synack(&new->sock); 01684 tcp_dbg("SYNACK sent, socket added. snd_nxt is %08x\n", new->snd_nxt); 01685 return 0; 01686 } 01687 01688 static void tcp_set_init_point(struct pico_socket *s) 01689 { 01690 struct pico_socket_tcp *t = (struct pico_socket_tcp *)s; 01691 t->rcv_processed = t->rcv_nxt; 01692 } 01693 01694 static int tcp_synack(struct pico_socket *s, struct pico_frame *f) 01695 { 01696 struct pico_socket_tcp *t = (struct pico_socket_tcp *) s; 01697 struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *)f->transport_hdr; 01698 01699 if (ACKN(f) == (1 + t->snd_nxt)) { 01700 t->rcv_nxt = long_be(hdr->seq); 01701 t->rcv_processed = t->rcv_nxt + 1; 01702 tcp_ack(s, f); 01703 01704 s->state &= 0x00FFU; 01705 s->state |= PICO_SOCKET_STATE_TCP_ESTABLISHED; 01706 tcp_dbg("TCP> Established. State: %x\n", s->state); 01707 01708 if (s->wakeup) 01709 s->wakeup(PICO_SOCK_EV_CONN, s); 01710 s->ev_pending |= PICO_SOCK_EV_WR; 01711 01712 t->rcv_nxt++; 01713 t->snd_nxt++; 01714 tcp_send_ack(t); /* return ACK */ 01715 01716 return 0; 01717 01718 } else { 01719 tcp_dbg("TCP> Not established, RST sent.\n"); 01720 tcp_nosync_rst(s,f); 01721 return 0; 01722 } 01723 } 01724 01725 static int tcp_first_ack(struct pico_socket *s, struct pico_frame *f) 01726 { 01727 struct pico_socket_tcp *t = (struct pico_socket_tcp *)s; 01728 tcp_dbg("ACK in SYN_RECV: expecting %08x got %08x\n", t->snd_nxt, ACKN(f)); 01729 if (t->snd_nxt == ACKN(f)) { 01730 tcp_set_init_point(s); 01731 tcp_ack(s, f); 01732 s->state &= 0x00FFU; 01733 s->state |= PICO_SOCKET_STATE_TCP_ESTABLISHED; 01734 tcp_dbg("TCP: Established. State now: %04x\n", s->state); 01735 if( !s->parent && s->wakeup) { /* If the socket has no parent, -> sending socket that has a sim_open */ 01736 tcp_dbg("FIRST ACK - No parent found -> sending socket\n"); 01737 s->wakeup(PICO_SOCK_EV_CONN, s); 01738 } 01739 if (s->parent && s->parent->wakeup) { 01740 tcp_dbg("FIRST ACK - Parent found -> listening socket\n"); 01741 s->wakeup = s->parent->wakeup; 01742 s->parent->wakeup(PICO_SOCK_EV_CONN, s->parent); 01743 } 01744 s->ev_pending |= PICO_SOCK_EV_WR; 01745 tcp_dbg("%s: snd_nxt is now %08x\n", __FUNCTION__, t->snd_nxt); 01746 return 0; 01747 } else { 01748 tcp_nosync_rst(s,f); 01749 return 0; 01750 } 01751 } 01752 01753 static int tcp_closewait(struct pico_socket *s, struct pico_frame *f) 01754 { 01755 01756 struct pico_socket_tcp *t = (struct pico_socket_tcp *)s; 01757 struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *) (f->transport_hdr); 01758 01759 01760 if (f->payload_len > 0) 01761 tcp_data_in(s,f); 01762 if (f->flags & PICO_TCP_ACK) 01763 tcp_ack(s,f); 01764 if (seq_compare(SEQN(f), t->rcv_nxt) == 0) { 01765 /* received FIN, increase ACK nr */ 01766 t->rcv_nxt = long_be(hdr->seq) + 1; 01767 s->state &= 0x00FFU; 01768 s->state |= PICO_SOCKET_STATE_TCP_CLOSE_WAIT; 01769 /* set SHUT_REMOTE */ 01770 s->state |= PICO_SOCKET_STATE_SHUT_REMOTE; 01771 tcp_dbg("TCP> Close-wait\n"); 01772 01773 if (s->wakeup){ 01774 if(f->payload_len>0){ 01775 struct pico_socket_tcp *t = (struct pico_socket_tcp *)s; 01776 t->sock.ev_pending |=PICO_SOCK_EV_CLOSE; 01777 }else 01778 s->wakeup(PICO_SOCK_EV_CLOSE, s); 01779 } 01780 } else { 01781 tcp_send_ack(t); /* return ACK */ 01782 } 01783 return 0; 01784 } 01785 01786 /*static int tcp_fin(struct pico_socket *s, struct pico_frame *f) 01787 { 01788 return 0; 01789 }*/ 01790 01791 static int tcp_rcvfin(struct pico_socket *s, struct pico_frame *f) 01792 { 01793 struct pico_socket_tcp *t = (struct pico_socket_tcp *)s; 01794 tcp_dbg("TCP> Received FIN in FIN_WAIT1\n"); 01795 s->state &= 0x00FFU; 01796 s->state |= PICO_SOCKET_STATE_TCP_CLOSING; 01797 t->rcv_processed = t->rcv_nxt + 1; 01798 t->rcv_nxt++; 01799 /* send ACK */ 01800 tcp_send_ack(t); 01801 return 0; 01802 } 01803 01804 static int tcp_finack(struct pico_socket *s, struct pico_frame *f) 01805 { 01806 struct pico_socket_tcp *t = (struct pico_socket_tcp *)s; 01807 tcp_dbg("TCP> ENTERED finack\n"); 01808 t->rcv_nxt++; 01809 /* send ACK */ 01810 tcp_send_ack(t); 01811 01812 /* call socket wakeup with EV_FIN */ 01813 if (s->wakeup) 01814 s->wakeup(PICO_SOCK_EV_FIN, s); 01815 s->state &= 0x00FFU; 01816 s->state |= PICO_SOCKET_STATE_TCP_TIME_WAIT; 01817 /* set SHUT_REMOTE */ 01818 s->state |= PICO_SOCKET_STATE_SHUT_REMOTE; 01819 pico_timer_add(2000, tcp_deltcb, t); 01820 01821 return 0; 01822 } 01823 01824 static int tcp_rst(struct pico_socket *s, struct pico_frame *f) 01825 { 01826 struct pico_socket_tcp *t = (struct pico_socket_tcp *) s; 01827 struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *) (f->transport_hdr); 01828 01829 tcp_dbg("TCP >>>>>>>>>>>>>> received RST <<<<<<<<<<<<<<<<<<<<\n"); 01830 if ((s->state & PICO_SOCKET_STATE_TCP) == PICO_SOCKET_STATE_TCP_SYN_SENT) { 01831 /* the RST is acceptable if the ACK field acknowledges the SYN */ 01832 if ((t->snd_nxt + 1) == ACKN(f)) { /* valid, got to closed state */ 01833 /* update state */ 01834 (t->sock).state &= 0x00FFU; 01835 (t->sock).state |= PICO_SOCKET_STATE_TCP_CLOSED; 01836 (t->sock).state &= 0xFF00U; 01837 (t->sock).state |= PICO_SOCKET_STATE_CLOSED; 01838 01839 /* call EV_FIN wakeup before deleting */ 01840 if ((t->sock).wakeup) 01841 (t->sock).wakeup(PICO_SOCK_EV_FIN, &(t->sock)); 01842 01843 /* call EV_ERR wakeup before deleting */ 01844 pico_err = PICO_ERR_ECONNRESET; 01845 if ((t->sock).wakeup) 01846 (t->sock).wakeup(PICO_SOCK_EV_ERR, &(t->sock)); 01847 01848 /* delete socket */ 01849 pico_socket_del(&t->sock); 01850 } else { /* not valid, ignore */ 01851 tcp_dbg("TCP RST> IGNORE\n"); 01852 return 0; 01853 } 01854 } else { /* all other states */ 01855 /* all reset (RST) segments are validated by checking their SEQ-fields, 01856 a reset is valid if its sequence number is in the window */ 01857 if ((long_be(hdr->seq) >= t->rcv_ackd) && (long_be(hdr->seq) <= ((short_be(hdr->rwnd)<<(t->wnd_scale)) + t->rcv_ackd))) { 01858 if ((s->state & PICO_SOCKET_STATE_TCP) == PICO_SOCKET_STATE_TCP_SYN_RECV) { 01859 /* go to closed */ 01860 (t->sock).state &= 0x00FFU; 01861 (t->sock).state |= PICO_SOCKET_STATE_TCP_CLOSED; 01862 (t->sock).state &= 0xFF00U; 01863 (t->sock).state |= PICO_SOCKET_STATE_CLOSED; 01864 /* call EV_ERR wakeup */ 01865 pico_err = PICO_ERR_ECONNRESET; 01866 if ((t->sock).wakeup) 01867 (t->sock).wakeup(PICO_SOCK_EV_ERR, &(t->sock)); 01868 tcp_dbg("TCP RST> SOCKET BACK TO LISTEN\n"); 01869 pico_socket_del(s); 01870 } else { 01871 /* go to closed */ 01872 (t->sock).state &= 0x00FFU; 01873 (t->sock).state |= PICO_SOCKET_STATE_TCP_CLOSED; 01874 (t->sock).state &= 0xFF00U; 01875 (t->sock).state |= PICO_SOCKET_STATE_CLOSED; 01876 01877 /* call EV_FIN wakeup before deleting */ 01878 if ((t->sock).wakeup) 01879 (t->sock).wakeup(PICO_SOCK_EV_FIN, &(t->sock)); 01880 /* call EV_ERR wakeup before deleting */ 01881 pico_err = PICO_ERR_ECONNRESET; 01882 if ((t->sock).wakeup) 01883 (t->sock).wakeup(PICO_SOCK_EV_ERR, &(t->sock)); 01884 01885 /* delete socket */ 01886 pico_socket_del(&t->sock); 01887 } 01888 } else { /* not valid, ignore */ 01889 tcp_dbg("TCP RST> IGNORE\n"); 01890 return 0; 01891 } 01892 } 01893 01894 return 0; 01895 } 01896 01897 struct tcp_action_entry { 01898 uint16_t tcpstate; 01899 int (*syn)(struct pico_socket *s, struct pico_frame *f); 01900 int (*synack)(struct pico_socket *s, struct pico_frame *f); 01901 int (*ack)(struct pico_socket *s, struct pico_frame *f); 01902 int (*data)(struct pico_socket *s, struct pico_frame *f); 01903 int (*fin)(struct pico_socket *s, struct pico_frame *f); 01904 int (*finack)(struct pico_socket *s, struct pico_frame *f); 01905 int (*rst)(struct pico_socket *s, struct pico_frame *f); 01906 }; 01907 01908 static struct tcp_action_entry tcp_fsm[] = { 01909 /* State syn synack ack data fin finack rst*/ 01910 { PICO_SOCKET_STATE_TCP_UNDEF, NULL, NULL, NULL, NULL, NULL, NULL, NULL }, 01911 { PICO_SOCKET_STATE_TCP_CLOSED, NULL, NULL, NULL, NULL, NULL, NULL, NULL }, 01912 { PICO_SOCKET_STATE_TCP_LISTEN, &tcp_syn, &tcp_nosync_rst, &tcp_nosync_rst, &tcp_nosync_rst, &tcp_nosync_rst, &tcp_nosync_rst, NULL }, 01913 { 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 }, 01914 { PICO_SOCKET_STATE_TCP_SYN_RECV, NULL, &tcp_nosync_rst, &tcp_first_ack, &tcp_nosync_rst, &tcp_nosync_rst, &tcp_nosync_rst, &tcp_rst }, 01915 { PICO_SOCKET_STATE_TCP_ESTABLISHED, NULL, &tcp_ack, &tcp_ack, &tcp_data_in, &tcp_closewait, &tcp_closewait, &tcp_rst }, 01916 { PICO_SOCKET_STATE_TCP_CLOSE_WAIT, NULL, &tcp_ack, &tcp_ack, &tcp_send_rst, &tcp_closewait, &tcp_closewait, &tcp_rst }, 01917 { PICO_SOCKET_STATE_TCP_LAST_ACK, NULL, &tcp_ack, &tcp_lastackwait, &tcp_send_rst, &tcp_send_rst, &tcp_send_rst, &tcp_rst }, 01918 { PICO_SOCKET_STATE_TCP_FIN_WAIT1, NULL, &tcp_ack, &tcp_finwaitack, &tcp_data_in, &tcp_rcvfin, &tcp_finack, &tcp_rst }, 01919 { PICO_SOCKET_STATE_TCP_FIN_WAIT2, NULL, &tcp_ack, &tcp_ack, &tcp_data_in, &tcp_finwaitfin, &tcp_finack, &tcp_rst }, 01920 { PICO_SOCKET_STATE_TCP_CLOSING, NULL, &tcp_ack, &tcp_closewaitack, &tcp_send_rst, &tcp_send_rst, &tcp_send_rst, &tcp_rst }, 01921 { PICO_SOCKET_STATE_TCP_TIME_WAIT, NULL, &tcp_ack, &tcp_send_rst, &tcp_send_rst, &tcp_send_rst, &tcp_send_rst, &tcp_rst } 01922 }; 01923 01924 /* 01925 NOTE: in SYN-RECV receiving syn when cloned by default (see yellow pos-it), should send reset. 01926 */ 01927 01928 int pico_tcp_input(struct pico_socket *s, struct pico_frame *f) 01929 { 01930 struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *) (f->transport_hdr); 01931 int ret = 0; 01932 uint8_t flags = hdr->flags; 01933 struct tcp_action_entry *action = &tcp_fsm[s->state >> 8]; 01934 01935 f->payload = (f->transport_hdr + ((hdr->len & 0xf0) >> 2)); 01936 f->payload_len = f->transport_len - ((hdr->len & 0xf0) >> 2); 01937 01938 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, 01939 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 ); 01940 01941 /* This copy of the frame has the current socket as owner */ 01942 f->sock = s; 01943 01944 /* Those are not supported at this time. */ 01945 flags &= ~(PICO_TCP_CWR | PICO_TCP_URG | PICO_TCP_ECN); 01946 if (flags == PICO_TCP_SYN) { 01947 if (action->syn) 01948 action->syn(s,f); 01949 } else if (flags == (PICO_TCP_SYN | PICO_TCP_ACK)) { 01950 if (action->synack) 01951 action->synack(s,f); 01952 } else { 01953 if ((flags == PICO_TCP_ACK) || (flags == (PICO_TCP_ACK | PICO_TCP_PSH))) { 01954 if (action->ack) { 01955 action->ack(s,f); 01956 } 01957 } 01958 if (f->payload_len > 0) { 01959 ret = f->payload_len; 01960 if (action->data) 01961 action->data(s,f); 01962 } 01963 if (flags == PICO_TCP_FIN) { 01964 if (action->fin) 01965 action->fin(s,f); 01966 } 01967 if ((flags == (PICO_TCP_FIN | PICO_TCP_ACK)) || (flags == (PICO_TCP_FIN | PICO_TCP_ACK | PICO_TCP_PSH))) { 01968 if (action->finack) 01969 action->finack(s,f); 01970 } 01971 if (flags & PICO_TCP_RST) { 01972 if (action->rst) 01973 action->rst(s,f); 01974 } 01975 } 01976 01977 //discard: 01978 pico_frame_discard(f); 01979 return ret; 01980 } 01981 01982 static void tcp_send_keepalive(unsigned long when, void *_t) 01983 { 01984 struct pico_socket_tcp *t = (struct pico_socket_tcp *)_t; 01985 tcp_dbg("\n\nSending keepalive (%d), [State = %d]...\n", t->backoff,t->sock.state ); 01986 if( t->sock.net && ((t->sock.state & 0xFF00) == PICO_SOCKET_STATE_TCP_ESTABLISHED) ) 01987 { 01988 tcp_send_ack(t); 01989 01990 if (t->keepalive_timer_running > 0) { 01991 t->keepalive_timer_running--; 01992 } 01993 01994 if (t->keepalive_timer_running == 0) { 01995 t->keepalive_timer_running++; 01996 tcp_dbg("[Self] Adding timer(retransmit keepalive)\n"); 01997 pico_timer_add(t->rto << (++t->backoff), tcp_send_keepalive, t); 01998 } 01999 } 02000 } 02001 02002 int pico_tcp_output(struct pico_socket *s, int loop_score) 02003 { 02004 struct pico_socket_tcp *t = (struct pico_socket_tcp *)s; 02005 struct pico_frame *f, *una; 02006 struct pico_tcp_hdr *hdr; 02007 int sent = 0; 02008 02009 una = first_segment(&t->tcpq_out); 02010 02011 f = peek_segment(&t->tcpq_out, t->snd_nxt); 02012 while((f) && (t->cwnd >= t->in_flight)) { 02013 hdr = (struct pico_tcp_hdr *)f->transport_hdr; 02014 f->timestamp = pico_tick; 02015 tcp_add_options(t, f, hdr->flags, tcp_options_size(t, hdr->flags)); 02016 if (seq_compare(SEQN(f) + f->payload_len, SEQN(una) + (t->recv_wnd << t->recv_wnd_scale)) > 0) { 02017 t->cwnd = t->in_flight; 02018 if (t->cwnd < 1) 02019 t->cwnd = 1; 02020 if (t->x_mode != PICO_TCP_WINDOW_FULL) { 02021 tcp_dbg("TCP> RIGHT SIZING (rwnd: %d, frame len: %d\n",t->recv_wnd << t->recv_wnd_scale, f->payload_len); 02022 tcp_dbg("In window full...\n"); 02023 t->snd_nxt = SEQN(una); /* XXX prevent out-of-order-packets ! */ /*DLA re-enabled.*/ 02024 t->snd_retry = SEQN(una); /* XXX replace by retry pointer? */ 02025 02026 /* Alternative to the line above: (better performance, but seems to lock anyway with larger buffers) 02027 if (seq_compare(t->snd_nxt, SEQN(una)) > 0) 02028 t->snd_nxt -= f->payload_len; 02029 */ 02030 02031 t->x_mode = PICO_TCP_WINDOW_FULL; 02032 if (t->keepalive_timer_running == 0) { 02033 tcp_dbg("[Window full] Adding timer(send keepalive)\n"); 02034 tcp_send_keepalive(0, t); 02035 } 02036 } 02037 break; 02038 } 02039 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); 02040 tcp_send(t, f); 02041 sent++; 02042 loop_score--; 02043 t->snd_last_out = SEQN(f); 02044 if (loop_score < 1) 02045 break; 02046 if (f->payload_len > 0) { 02047 f = next_segment(&t->tcpq_out, f); 02048 } else { 02049 f = NULL; 02050 } 02051 } 02052 if (sent > 0) { 02053 if (t->rto < PICO_TCP_RTO_MIN) 02054 t->rto = PICO_TCP_RTO_MIN; 02055 //if (s->wakeup) 02056 // t->sock.wakeup(PICO_SOCK_EV_WR, &t->sock); 02057 add_retransmission_timer(t, pico_tick + t->rto); 02058 } else { 02059 /* Nothing to transmit. */ 02060 } 02061 02062 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 */ 02063 if ((s->state & PICO_SOCKET_STATE_TCP) == PICO_SOCKET_STATE_TCP_ESTABLISHED) { 02064 tcp_dbg("TCP> buffer empty, shutdown established ...\n"); 02065 /* send fin if queue empty and in state shut local (write) */ 02066 tcp_send_fin(t); 02067 /* change tcp state to FIN_WAIT1 */ 02068 s->state &= 0x00FFU; 02069 s->state |= PICO_SOCKET_STATE_TCP_FIN_WAIT1; 02070 } else if ((s->state & PICO_SOCKET_STATE_TCP) == PICO_SOCKET_STATE_TCP_CLOSE_WAIT) { 02071 /* send fin if queue empty and in state shut local (write) */ 02072 tcp_send_fin(t); 02073 /* change tcp state to LAST_ACK */ 02074 s->state &= 0x00FFU; 02075 s->state |= PICO_SOCKET_STATE_TCP_LAST_ACK; 02076 tcp_dbg("TCP> STATE: LAST_ACK.\n"); 02077 } 02078 } 02079 return loop_score; 02080 } 02081 02082 /* function to make new segment from hold queue with specific size (mss) */ 02083 static struct pico_frame * pico_hold_segment_make(struct pico_socket_tcp *t) 02084 { 02085 struct pico_frame *f_temp,*f_new; 02086 struct pico_socket *s = (struct pico_socket *) &t->sock; 02087 struct pico_tcp_hdr *hdr; 02088 int total_len = 0, total_payload_len = 0; 02089 int off = 0, test = 0; 02090 02091 off = pico_tcp_overhead(s); 02092 02093 /* init with first frame in hold queue */ 02094 f_temp = first_segment(&t->tcpq_hold); 02095 total_len = f_temp->payload_len; 02096 f_temp = next_segment(&t->tcpq_hold, f_temp); 02097 02098 /* check till total_len <= MSS */ 02099 while ((f_temp != NULL) && ((total_len+f_temp->payload_len) <= PICO_TCP_DEFAULT_MSS)) { 02100 total_len += f_temp->payload_len; 02101 f_temp = next_segment(&t->tcpq_hold, f_temp); 02102 if (f_temp == NULL) 02103 break; 02104 } 02105 /* alloc new frame with payload size = off + total_len */ 02106 f_new = pico_socket_frame_alloc(s, off + total_len); 02107 if (!f_new) { 02108 pico_err = PICO_ERR_ENOMEM; 02109 return f_new; 02110 } 02111 02112 hdr = (struct pico_tcp_hdr *) f_new->transport_hdr; 02113 /* init new frame */ 02114 f_new->payload += off; 02115 f_new->payload_len -= off; 02116 f_new->sock = s; 02117 02118 f_temp = first_segment(&t->tcpq_hold); 02119 hdr->seq = ((struct pico_tcp_hdr *)(f_temp->transport_hdr))->seq; /* get sequence number of first frame */ 02120 hdr->trans.sport = t->sock.local_port; 02121 hdr->trans.dport = t->sock.remote_port; 02122 02123 /* check till total_payload_len <= MSS */ 02124 while ((f_temp != NULL) && ((total_payload_len + f_temp->payload_len) <= PICO_TCP_DEFAULT_MSS)) { 02125 /* cpy data and discard frame */ 02126 test++; 02127 memcpy(f_new->payload + total_payload_len, f_temp->payload, f_temp->payload_len); 02128 total_payload_len += f_temp->payload_len; 02129 pico_discard_segment(&t->tcpq_hold, f_temp); 02130 f_temp = first_segment(&t->tcpq_hold); 02131 } 02132 02133 hdr->len = (f_new->payload - f_new->transport_hdr) << 2 | t->jumbo; 02134 02135 tcp_dbg_nagle("NAGLE make - joined %d segments, len %d bytes\n",test,total_payload_len); 02136 02137 return f_new; 02138 } 02139 02140 /* original behavior kept when Nagle disabled; 02141 Nagle algorithm added here, keeping hold frame queue instead of eg linked list of data */ 02142 int pico_tcp_push(struct pico_protocol *self, struct pico_frame *f) 02143 { 02144 struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *)f->transport_hdr; 02145 struct pico_socket_tcp *t = (struct pico_socket_tcp *) f->sock; 02146 struct pico_frame *f_new; 02147 int total_len = 0; 02148 02149 hdr->trans.sport = t->sock.local_port; 02150 hdr->trans.dport = t->sock.remote_port; 02151 hdr->seq = long_be(t->snd_last + 1); 02152 hdr->len = (f->payload - f->transport_hdr) << 2 | t->jumbo; 02153 02154 if (f->payload_len > (t->tcpq_out.max_size - t->tcpq_out.size)) 02155 t->sock.ev_pending &= (~PICO_SOCK_EV_WR); 02156 02157 /***************************************************************************/ 02158 02159 if (!IS_NAGLE_ENABLED((&(t->sock)))) { 02160 /* TCP_NODELAY enabled, original behavior */ 02161 if (pico_enqueue_segment(&t->tcpq_out,f) > 0) { 02162 tcp_dbg_nagle("TCP_PUSH - NO NAGLE - Pushing segment %08x, len %08x to socket %p\n", t->snd_last + 1, f->payload_len, t); 02163 t->snd_last += f->payload_len; 02164 return f->payload_len; 02165 } else { 02166 tcp_dbg("Enqueue failed.\n"); 02167 return 0; 02168 } 02169 } 02170 /***************************************************************************/ 02171 else { 02172 /* Nagle's algorithm enabled, check if ready to send, or put frame in hold queue */ 02173 if (IS_TCP_IDLE(t) && IS_TCP_HOLDQ_EMPTY(t)) { /* opt 1. send frame */ 02174 if (pico_enqueue_segment(&t->tcpq_out,f) > 0) { 02175 tcp_dbg_nagle("TCP_PUSH - NAGLE - Pushing segment %08x, len %08x to socket %p\n", t->snd_last + 1, f->payload_len, t); 02176 t->snd_last += f->payload_len; 02177 return f->payload_len; 02178 } else { 02179 tcp_dbg("Enqueue failed.\n"); 02180 return 0; 02181 } 02182 } else { /* opt 2. hold data back */ 02183 total_len = f->payload_len + t->tcpq_hold.size; 02184 if ((total_len >= PICO_TCP_DEFAULT_MSS) && ((t->tcpq_out.max_size - t->tcpq_out.size) >= PICO_TCP_DEFAULT_MSS)) {/* TODO check mss socket */ 02185 /* IF enough data in hold (>mss) AND space in out queue (>mss) */ 02186 /* add current frame in hold and make new segment */ 02187 if (pico_enqueue_segment(&t->tcpq_hold,f) > 0 ) { 02188 tcp_dbg_nagle("TCP_PUSH - NAGLE - Pushed into hold, make new (enqueued frames out %d)\n",t->tcpq_out.frames); 02189 t->snd_last += f->payload_len; /* XXX WATCH OUT */ 02190 f_new = pico_hold_segment_make(t); 02191 } else { 02192 tcp_dbg_nagle("TCP_PUSH - NAGLE - enqueue hold failed 1\n"); 02193 return 0; 02194 } 02195 /* and put new frame in out queue */ 02196 if ((f_new != NULL) && (pico_enqueue_segment(&t->tcpq_out,f_new) > 0)) { 02197 return f_new->payload_len; 02198 } else { 02199 tcp_dbg_nagle("TCP_PUSH - NAGLE - enqueue out failed, f_new = %p\n",f_new); 02200 return -1; /* XXX something seriously wrong */ 02201 } 02202 } else { 02203 /* ELSE put frame in hold queue */ 02204 if (pico_enqueue_segment(&t->tcpq_hold,f) > 0) { 02205 tcp_dbg_nagle("TCP_PUSH - NAGLE - Pushed into hold (enqueued frames out %d)\n",t->tcpq_out.frames); 02206 t->snd_last += f->payload_len; /* XXX WATCH OUT */ 02207 return f->payload_len; 02208 } else { 02209 tcp_dbg_nagle("TCP_PUSH - NAGLE - enqueue hold failed 2\n"); 02210 return 0; 02211 } 02212 } 02213 } 02214 } 02215 /***************************************************************************/ 02216 } 02217 #endif //PICO_SUPPORT_TCP
Generated on Wed Jul 13 2022 02:20:46 by 1.7.2