Changeset 0093ab6 in mainline
- Timestamp:
- 2011-09-21T19:56:41Z (13 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 032bbe7
- Parents:
- 4c55a64
- Location:
- uspace/srv/net/tl/tcp
- Files:
-
- 8 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/srv/net/tl/tcp/conn.c
r4c55a64 r0093ab6 38 38 #include <errno.h> 39 39 #include <io/log.h> 40 #include <macros.h> 40 41 #include <stdlib.h> 41 42 #include "conn.h" … … 46 47 #include "tqueue.h" 47 48 49 #define RCV_BUF_SIZE 4096 50 48 51 LIST_INITIALIZE(conn_list); 49 52 … … 54 57 tcp_conn_t *conn; 55 58 59 /* Allocate connection structure */ 56 60 conn = calloc(1, sizeof(tcp_conn_t)); 57 61 if (conn == NULL) 58 62 return NULL; 59 63 64 /* Allocate receive buffer */ 65 conn->rcv_buf_size = RCV_BUF_SIZE; 66 conn->rcv_buf_used = 0; 67 conn->rcv_buf = calloc(1, conn->rcv_buf_size); 68 if (conn->rcv_buf == NULL) { 69 free(conn); 70 return NULL; 71 } 72 73 /* Set up receive window. */ 74 conn->rcv_wnd = conn->rcv_buf_size; 75 76 /* Initialize incoming segment queue */ 60 77 tcp_iqueue_init(&conn->incoming, conn); 61 78 … … 175 192 176 193 tcp_tqueue_ctrl_seg(conn, CTL_SYN | CTL_ACK /* XXX */); 194 195 tcp_segment_delete(seg); 177 196 } 178 197 … … 225 244 tcp_tqueue_ctrl_seg(conn, CTL_SYN | CTL_ACK /* XXX */); 226 245 } 246 247 tcp_segment_delete(seg); 227 248 } 228 249 … … 288 309 static cproc_t tcp_conn_seg_proc_ack_est(tcp_conn_t *conn, tcp_segment_t *seg) 289 310 { 311 log_msg(LVL_DEBUG, "tcp_conn_seg_proc_ack_est(%p, %p)", conn, seg); 312 313 log_msg(LVL_DEBUG, "SEG.ACK=%u, SND.UNA=%u, SND.NXT=%u", 314 (unsigned)seg->ack, (unsigned)conn->snd_una, 315 (unsigned)conn->snd_nxt); 316 290 317 if (!seq_no_ack_acceptable(conn, seg->ack)) { 318 log_msg(LVL_DEBUG, "ACK not acceptable."); 291 319 if (!seq_no_ack_duplicate(conn, seg->ack)) { 320 log_msg(LVL_WARN, "Not acceptable, not duplicate. " 321 "Send ACK and drop."); 292 322 /* Not acceptable, not duplicate. Send ACK and drop. */ 293 323 tcp_tqueue_ctrl_seg(conn, CTL_ACK); 294 324 tcp_segment_delete(seg); 295 325 return cp_done; 326 } else { 327 log_msg(LVL_DEBUG, "Ignoring duplicate ACK."); 296 328 } 297 329 } else { … … 401 433 } 402 434 435 /** Process segment text. */ 403 436 static cproc_t tcp_conn_seg_proc_text(tcp_conn_t *conn, tcp_segment_t *seg) 404 437 { 438 size_t text_size; 439 size_t xfer_size; 440 441 log_msg(LVL_DEBUG, "tcp_conn_seg_proc_text(%p, %p)", conn, seg); 442 405 443 switch (conn->cstate) { 406 444 case st_established: … … 422 460 } 423 461 424 /* TODO Process segment text */ 462 /* 463 * Process segment text 464 */ 465 assert(seq_no_segment_ready(conn, seg)); 466 467 /* Trim anything outside our receive window */ 468 tcp_conn_trim_seg_to_wnd(conn, seg); 469 470 /* Determine how many bytes to copy */ 471 text_size = tcp_segment_text_size(seg); 472 xfer_size = min(text_size, conn->rcv_buf_size - conn->rcv_buf_used); 473 474 /* Copy data to receive buffer */ 475 tcp_segment_text_copy(seg, conn->rcv_buf, xfer_size); 476 477 /* Advance RCV.NXT */ 478 conn->rcv_nxt += xfer_size; 479 480 /* Update receive window. XXX Not an efficient strategy. */ 481 conn->rcv_wnd -= xfer_size; 482 483 /* XXX Signal user that some data arrived. */ 484 485 /* Send ACK */ 486 if (xfer_size > 0) 487 tcp_tqueue_ctrl_seg(conn, CTL_ACK); 488 489 /* Anything left in the segment? (text, FIN) */ 490 if (xfer_size < seg->len) { 491 /* 492 * Some text or control remains. Insert remainder back 493 * into the incoming queue. 494 */ 495 tcp_conn_trim_seg_to_wnd(conn, seg); 496 tcp_iqueue_insert_seg(&conn->incoming, seg); 497 498 return cp_done; 499 } 500 425 501 return cp_continue; 426 502 } … … 472 548 if (tcp_conn_seg_proc_fin(conn, seg) == cp_done) 473 549 return; 550 551 tcp_segment_delete(seg); 474 552 } 475 553 … … 498 576 } 499 577 578 void tcp_conn_trim_seg_to_wnd(tcp_conn_t *conn, tcp_segment_t *seg) 579 { 580 uint32_t left, right; 581 582 seq_no_seg_trim_calc(conn, seg, &left, &right); 583 tcp_segment_trim(seg, left, right); 584 } 585 500 586 void tcp_unexpected_segment(tcp_sockpair_t *sp, tcp_segment_t *seg) 501 587 { -
uspace/srv/net/tl/tcp/conn.h
r4c55a64 r0093ab6 43 43 extern tcp_conn_t *tcp_conn_find(tcp_sockpair_t *); 44 44 extern void tcp_conn_segment_arrived(tcp_conn_t *, tcp_segment_t *); 45 extern void tcp_conn_trim_seg_to_wnd(tcp_conn_t *, tcp_segment_t *); 45 46 extern void tcp_unexpected_segment(tcp_sockpair_t *, tcp_segment_t *); 46 47 extern void tcp_sockpair_flipped(tcp_sockpair_t *, tcp_sockpair_t *); -
uspace/srv/net/tl/tcp/header.c
r4c55a64 r0093ab6 61 61 62 62 /* XXX This will only work as long as we don't have any header options */ 63 phdr->tcp_length = sizeof(tcp_header_t) + tcp_segment_ data_len(seg);63 phdr->tcp_length = sizeof(tcp_header_t) + tcp_segment_text_size(seg); 64 64 } 65 65 -
uspace/srv/net/tl/tcp/segment.c
r4c55a64 r0093ab6 35 35 */ 36 36 37 #include <mem.h> 37 38 #include <stdlib.h> 38 39 #include "segment.h" … … 79 80 } 80 81 81 size_t tcp_segment_data_len(tcp_segment_t *seg) 82 /** Trim segment to the specified interval. 83 * 84 * Trim any text or control whose sequence number is outside of [lo, hi) 85 * interval. 86 */ 87 void tcp_segment_trim(tcp_segment_t *seg, uint32_t left, uint32_t right) 88 { 89 uint32_t t_size; 90 91 assert(left + right <= seg->len); 92 93 /* Special case, entire segment trimmed from left */ 94 if (left == seg->len) { 95 seg->seq = seg->seq + seg->len; 96 seg->len = 0; 97 return; 98 } 99 100 /* Special case, entire segment trimmed from right */ 101 if (right == seg->len) { 102 seg->len = 0; 103 return; 104 } 105 106 /* General case */ 107 108 t_size = tcp_segment_text_size(seg); 109 110 if (left > 0 && (seg->ctrl & CTL_SYN) != 0) { 111 /* Trim SYN */ 112 seg->ctrl &= ~CTL_SYN; 113 seg->seq++; 114 seg->len--; 115 left--; 116 } 117 118 if (right > 0 && (seg->ctrl & CTL_FIN) != 0) { 119 /* Trim FIN */ 120 seg->ctrl &= ~CTL_FIN; 121 seg->len--; 122 right--; 123 } 124 125 if (left > 0 || right > 0) { 126 /* Trim segment text */ 127 assert(left + right <= t_size); 128 129 seg->data += left; 130 seg->len -= left + right; 131 } 132 } 133 134 /** Copy out text data from segment. 135 * 136 */ 137 void tcp_segment_text_copy(tcp_segment_t *seg, void *buf, size_t size) 138 { 139 assert(size <= tcp_segment_text_size(seg)); 140 memcpy(buf, seg->data, size); 141 } 142 143 /** Return number of bytes in segment text. */ 144 size_t tcp_segment_text_size(tcp_segment_t *seg) 82 145 { 83 146 return seg->len - seq_no_control_len(seg->ctrl); -
uspace/srv/net/tl/tcp/segment.h
r4c55a64 r0093ab6 36 36 #define SEGMENT_H 37 37 38 #include <sys/types.h> 38 39 #include "tcp_type.h" 39 40 … … 42 43 extern tcp_segment_t *tcp_segment_make_ctrl(tcp_control_t); 43 44 extern tcp_segment_t *tcp_segment_make_rst(tcp_segment_t *); 44 extern size_t tcp_segment_data_len(tcp_segment_t *); 45 extern void tcp_segment_trim(tcp_segment_t *, uint32_t, uint32_t); 46 extern void tcp_segment_text_copy(tcp_segment_t *, void *, size_t); 47 extern size_t tcp_segment_text_size(tcp_segment_t *); 45 48 46 49 -
uspace/srv/net/tl/tcp/seq_no.c
r4c55a64 r0093ab6 71 71 * 72 72 * ACK is duplicate if it refers to a sequence number that has 73 * aleady been acked (SEG.ACK < SND.UNA).73 * aleady been acked (SEG.ACK <= SND.UNA). 74 74 */ 75 75 bool seq_no_ack_duplicate(tcp_conn_t *conn, uint32_t seg_ack) … … 81 81 * equivalent of SEG.ACK < SND.UNA. Thus we do it 82 82 * on a best-effort basis, based on the difference. 83 * [-2^31, 0) means less-than, [0, 2^31) means greater-than. 83 * [-2^31, 0) means less-than, 0 means equal, [0, 2^31) 84 * means greater-than. Less-than or equal means duplicate. 84 85 */ 85 86 diff = seg_ack - conn->snd_una; 86 return (diff & (0x1 << 31)) != 0;87 return diff == 0 || (diff & (0x1 << 31)) != 0; 87 88 } 88 89 … … 176 177 } 177 178 179 /** Calculate the amount of trim needed to fit segment in receive window. */ 180 extern void seq_no_seg_trim_calc(tcp_conn_t *conn, tcp_segment_t *seg, 181 uint32_t *left, uint32_t *right) 182 { 183 assert(seq_no_segment_acceptable(conn, seg)); 184 185 /* 186 * If RCV.NXT is between SEG.SEQ and RCV.NXT+RCV.WND, then 187 * left trim amount is positive 188 */ 189 if (seq_no_lt_le(seg->seq, conn->rcv_nxt, 190 conn->rcv_nxt + conn->rcv_wnd)) { 191 *left = conn->rcv_nxt - seg->seq; 192 } else { 193 *left = 0; 194 } 195 196 /* 197 * If SEG.SEQ+SEG.LEN is between SEG.SEQ and RCV.NXT+RCV.WND, 198 * then right trim is zero. 199 */ 200 if (seq_no_lt_le(seg->seq - 1, seg->seq + seg->len, 201 conn->rcv_nxt + conn->rcv_wnd)) { 202 *right = 0; 203 } else { 204 *right = (seg->seq + seg->len) - 205 (conn->rcv_nxt + conn->rcv_wnd); 206 } 207 } 208 178 209 /** 179 210 * @} -
uspace/srv/net/tl/tcp/seq_no.h
r4c55a64 r0093ab6 46 46 extern bool seq_no_segment_ready(tcp_conn_t *, tcp_segment_t *); 47 47 extern bool seq_no_segment_acceptable(tcp_conn_t *, tcp_segment_t *); 48 extern void seq_no_seg_trim_calc(tcp_conn_t *, tcp_segment_t *, uint32_t *, 49 uint32_t *); 48 50 49 51 extern uint32_t seq_no_control_len(tcp_control_t); -
uspace/srv/net/tl/tcp/tcp_type.h
r4c55a64 r0093ab6 109 109 tcp_iqueue_t incoming; 110 110 111 /** Receive buffer */ 112 uint8_t *rcv_buf; 113 /** Receive buffer size */ 114 size_t rcv_buf_size; 115 size_t rcv_buf_used; 116 111 117 /** Send unacknowledged */ 112 118 uint32_t snd_una; … … 153 159 uint32_t up; 154 160 155 /** Segment data */161 /** Segment data, may be moved when trimming segment */ 156 162 void *data; 163 /** Segment data, original pointer used to free data */ 164 void *dfptr; 157 165 } tcp_segment_t; 158 166
Note:
See TracChangeset
for help on using the changeset viewer.