|
@@ -258,17 +258,7 @@ static const char *tcp_states[] = {
|
258
|
258
|
* @v conn TCP connection
|
259
|
259
|
* @v nxt_state Next TCP state
|
260
|
260
|
*/
|
261
|
|
-void tcp_trans ( struct tcp_connection *conn, int nxt_state ) {
|
262
|
|
- /* Remember the last state */
|
263
|
|
- conn->tcp_lstate = conn->tcp_state;
|
264
|
|
- conn->tcp_state = nxt_state;
|
265
|
|
-
|
266
|
|
- /* TODO: Check if this check is required */
|
267
|
|
- if ( conn->tcp_lstate == conn->tcp_state ||
|
268
|
|
- conn->tcp_state == TCP_INVALID ) {
|
269
|
|
- conn->tcp_flags = 0;
|
270
|
|
- return;
|
271
|
|
- }
|
|
261
|
+void tcp_set_flags ( struct tcp_connection *conn ) {
|
272
|
262
|
|
273
|
263
|
/* Set the TCP flags */
|
274
|
264
|
switch ( conn->tcp_state ) {
|
|
@@ -331,12 +321,29 @@ void tcp_trans ( struct tcp_connection *conn, int nxt_state ) {
|
331
|
321
|
}
|
332
|
322
|
}
|
333
|
323
|
|
|
324
|
+void tcp_trans ( struct tcp_connection *conn, int nxt_state ) {
|
|
325
|
+ /* Remember the last state */
|
|
326
|
+ conn->tcp_lstate = conn->tcp_state;
|
|
327
|
+ conn->tcp_state = nxt_state;
|
|
328
|
+
|
|
329
|
+ printf ( "Transition from %s to %s\n", tcp_states[conn->tcp_lstate], tcp_states[conn->tcp_state] );
|
|
330
|
+
|
|
331
|
+ /* TODO: Check if this check is required */
|
|
332
|
+ if ( conn->tcp_lstate == conn->tcp_state ||
|
|
333
|
+ conn->tcp_state == TCP_INVALID ) {
|
|
334
|
+ conn->tcp_flags = 0;
|
|
335
|
+ return;
|
|
336
|
+ }
|
|
337
|
+ tcp_set_flags ( conn );
|
|
338
|
+}
|
|
339
|
+
|
334
|
340
|
/**
|
335
|
341
|
* Dump TCP header
|
336
|
342
|
*
|
337
|
343
|
* @v tcphdr TCP header
|
338
|
344
|
*/
|
339
|
345
|
void tcp_dump ( struct tcp_header *tcphdr ) {
|
|
346
|
+/*
|
340
|
347
|
DBG ( "TCP header at %p+%d\n", tcphdr, sizeof ( *tcphdr ) );
|
341
|
348
|
DBG ( "\tSource port = %d, Destination port = %d\n",
|
342
|
349
|
ntohs ( tcphdr->src ), ntohs ( tcphdr->dest ) );
|
|
@@ -347,6 +354,10 @@ void tcp_dump ( struct tcp_header *tcphdr ) {
|
347
|
354
|
( tcphdr->flags & TCP_MASK_FLAGS ) );
|
348
|
355
|
DBG ( "\tAdvertised window = %ld, Checksum = %x, Urgent Pointer = %d\n",
|
349
|
356
|
ntohs ( tcphdr->win ), tcphdr->csum, ntohs ( tcphdr->urg ) );
|
|
357
|
+*/
|
|
358
|
+ DBG ( "TCP %p at %p src:%d dest:%d seq:%lld ack:%lld hlen:%hd flags:%#hx\n",
|
|
359
|
+ &tcp_protocol, tcphdr, ntohs ( tcphdr->src ), ntohs ( tcphdr->dest ), ntohl ( tcphdr->seq ),
|
|
360
|
+ ntohl ( tcphdr->ack ), ( ( tcphdr->hlen & TCP_MASK_HLEN ) / 16 ), ( tcphdr->flags & TCP_MASK_FLAGS ) );
|
350
|
361
|
}
|
351
|
362
|
|
352
|
363
|
/**
|
|
@@ -377,49 +388,64 @@ void tcp_init_conn ( struct tcp_connection *conn ) {
|
377
|
388
|
*/
|
378
|
389
|
void tcp_expired ( struct retry_timer *timer, int over ) {
|
379
|
390
|
struct tcp_connection *conn;
|
380
|
|
- if ( over ) {
|
381
|
|
- conn = ( struct tcp_connection * ) container_of ( timer,
|
382
|
|
- struct tcp_connection, timer );
|
383
|
|
- switch ( conn->tcp_state ) {
|
384
|
|
- case TCP_SYN_SENT:
|
385
|
|
- if ( conn->retransmits > MAX_RETRANSMITS ) {
|
386
|
|
- tcp_trans ( conn, TCP_CLOSED );
|
387
|
|
- return;
|
388
|
|
- }
|
389
|
|
- if ( conn->tcp_lstate == TCP_CLOSED ||
|
390
|
|
- conn->tcp_lstate == TCP_LISTEN ) {
|
391
|
|
- goto send_tcp_nomsg;
|
392
|
|
- }
|
393
|
|
- return;
|
394
|
|
- case TCP_SYN_RCVD:
|
|
391
|
+ conn = ( struct tcp_connection * ) container_of ( timer,
|
|
392
|
+ struct tcp_connection, timer );
|
|
393
|
+ DBG ( "Timer expired in %s\n", tcp_states[conn->tcp_state] );
|
|
394
|
+ switch ( conn->tcp_state ) {
|
|
395
|
+ case TCP_SYN_SENT:
|
|
396
|
+ if ( over ) {
|
395
|
397
|
tcp_trans ( conn, TCP_CLOSED );
|
396
|
|
- if ( conn->tcp_lstate == TCP_LISTEN ||
|
397
|
|
- conn->tcp_lstate == TCP_SYN_SENT ) {
|
398
|
|
- goto send_tcp_nomsg;
|
399
|
|
- }
|
400
|
|
- return;
|
401
|
|
- case TCP_ESTABLISHED:
|
402
|
|
- break;
|
403
|
|
- case TCP_FIN_WAIT_1:
|
404
|
|
- case TCP_FIN_WAIT_2:
|
405
|
|
- case TCP_CLOSE_WAIT:
|
406
|
|
- goto send_tcp_nomsg;
|
407
|
|
- case TCP_CLOSING:
|
408
|
|
- case TCP_LAST_ACK:
|
|
398
|
+ stop_timer ( &conn->timer );
|
|
399
|
+ DBG ( "Timeout! Connection closed\n" );
|
409
|
400
|
return;
|
410
|
|
- case TCP_TIME_WAIT:
|
|
401
|
+ }
|
|
402
|
+ goto send_tcp_nomsg;
|
|
403
|
+ case TCP_SYN_RCVD:
|
|
404
|
+ if ( over ) {
|
411
|
405
|
tcp_trans ( conn, TCP_CLOSED );
|
412
|
|
- return;
|
|
406
|
+ stop_timer ( &conn->timer );
|
|
407
|
+ goto send_tcp_nomsg;
|
|
408
|
+ }
|
|
409
|
+ goto send_tcp_nomsg;
|
|
410
|
+ case TCP_ESTABLISHED:
|
|
411
|
+ if ( conn->tcp_lstate == TCP_SYN_SENT ) {
|
|
412
|
+ goto send_tcp_nomsg;
|
|
413
|
+ }
|
|
414
|
+ break;
|
|
415
|
+ case TCP_CLOSE_WAIT:
|
|
416
|
+ if ( conn->tcp_lstate == TCP_ESTABLISHED ) {
|
|
417
|
+ goto send_tcp_nomsg;
|
|
418
|
+ }
|
|
419
|
+ break;
|
|
420
|
+ case TCP_FIN_WAIT_1:
|
|
421
|
+ case TCP_FIN_WAIT_2:
|
|
422
|
+ goto send_tcp_nomsg;
|
|
423
|
+ case TCP_CLOSING:
|
|
424
|
+ case TCP_LAST_ACK:
|
|
425
|
+ if ( conn->tcp_lstate == TCP_CLOSE_WAIT ) {
|
|
426
|
+ goto send_tcp_nomsg;
|
413
|
427
|
}
|
414
|
|
- /* Retransmit the data */
|
415
|
|
- tcp_senddata ( conn );
|
416
|
|
- conn->retransmits++;
|
417
|
428
|
return;
|
|
429
|
+ case TCP_TIME_WAIT:
|
|
430
|
+ tcp_trans ( conn, TCP_CLOSED );
|
|
431
|
+ stop_timer ( &conn->timer );
|
|
432
|
+ return;
|
|
433
|
+ }
|
|
434
|
+ /* Retransmit the data */
|
|
435
|
+ tcp_set_flags ( conn );
|
|
436
|
+ tcp_senddata ( conn );
|
|
437
|
+ return;
|
418
|
438
|
|
419
|
439
|
send_tcp_nomsg:
|
420
|
|
- tcp_send ( conn, TCP_NOMSG, TCP_NOMSG_LEN );
|
421
|
|
- return;
|
|
440
|
+// free_pkb ( conn->tx_pkb );
|
|
441
|
+ conn->tx_pkb = alloc_pkb ( MIN_PKB_LEN );
|
|
442
|
+ pkb_reserve ( conn->tx_pkb, MAX_HDR_LEN );
|
|
443
|
+ tcp_set_flags ( conn );
|
|
444
|
+ int rc;
|
|
445
|
+ if ( ( rc = tcp_send ( conn, TCP_NOMSG, TCP_NOMSG_LEN ) ) != 0 ) {
|
|
446
|
+ DBG ( "Error sending TCP message (rc = %d)\n", rc );
|
422
|
447
|
}
|
|
448
|
+ return;
|
423
|
449
|
}
|
424
|
450
|
|
425
|
451
|
/**
|
|
@@ -634,7 +660,13 @@ int tcp_send ( struct tcp_connection *conn, const void *data, size_t len ) {
|
634
|
660
|
tcp_dump ( tcphdr );
|
635
|
661
|
|
636
|
662
|
/* Start the timer */
|
637
|
|
- start_timer ( &conn->timer );
|
|
663
|
+ if ( ( conn->tcp_state == TCP_ESTABLISHED && conn->tcp_lstate == TCP_SYN_SENT ) ||
|
|
664
|
+ ( conn->tcp_state == TCP_LISTEN && conn->tcp_lstate == TCP_SYN_RCVD ) ||
|
|
665
|
+ ( conn->tcp_state == TCP_CLOSED && conn->tcp_lstate == TCP_SYN_RCVD ) ) {
|
|
666
|
+ // Don't start the timer
|
|
667
|
+ } else {
|
|
668
|
+ start_timer ( &conn->timer );
|
|
669
|
+ }
|
638
|
670
|
|
639
|
671
|
/* Transmit packet */
|
640
|
672
|
return tcpip_tx ( pkb, &tcp_protocol, peer );
|
|
@@ -653,6 +685,7 @@ static int tcp_rx ( struct pk_buff *pkb,
|
653
|
685
|
struct tcp_header *tcphdr;
|
654
|
686
|
uint32_t acked, toack;
|
655
|
687
|
int hlen;
|
|
688
|
+ int add = 0;
|
656
|
689
|
|
657
|
690
|
/* Sanity check */
|
658
|
691
|
if ( pkb_len ( pkb ) < sizeof ( *tcphdr ) ) {
|
|
@@ -660,14 +693,21 @@ static int tcp_rx ( struct pk_buff *pkb,
|
660
|
693
|
return -EINVAL;
|
661
|
694
|
}
|
662
|
695
|
|
|
696
|
+
|
663
|
697
|
/* Process TCP header */
|
664
|
698
|
tcphdr = pkb->data;
|
|
699
|
+ tcp_dump ( tcphdr );
|
665
|
700
|
|
666
|
701
|
/* Verify header length */
|
667
|
702
|
hlen = ( ( tcphdr->hlen & TCP_MASK_HLEN ) / 16 ) * 4;
|
668
|
703
|
if ( hlen != sizeof ( *tcphdr ) ) {
|
669
|
|
- DBG ( "Bad header length (%d bytes)\n", hlen );
|
670
|
|
- return -EINVAL;
|
|
704
|
+ if ( hlen == sizeof ( *tcphdr ) + 4 ) {
|
|
705
|
+ DBG ( "TCP options sent\n" );
|
|
706
|
+ add = 4;
|
|
707
|
+ } else {
|
|
708
|
+ DBG ( "Bad header length (%d bytes)\n", hlen );
|
|
709
|
+ return -EINVAL;
|
|
710
|
+ }
|
671
|
711
|
}
|
672
|
712
|
|
673
|
713
|
/* TODO: Verify checksum */
|
|
@@ -685,7 +725,6 @@ static int tcp_rx ( struct pk_buff *pkb,
|
685
|
725
|
found_conn:
|
686
|
726
|
/* Stop the timer */
|
687
|
727
|
stop_timer ( &conn->timer );
|
688
|
|
- conn->retransmits = 0;
|
689
|
728
|
|
690
|
729
|
/* Set the advertised window */
|
691
|
730
|
conn->snd_win = tcphdr->win;
|
|
@@ -729,6 +768,7 @@ static int tcp_rx ( struct pk_buff *pkb,
|
729
|
768
|
*/
|
730
|
769
|
conn->snd_una = ntohl ( tcphdr->ack );
|
731
|
770
|
conn->tcp_op->connected ( conn );
|
|
771
|
+ tcp_senddata ( conn );
|
732
|
772
|
} else {
|
733
|
773
|
tcp_trans ( conn, TCP_SYN_RCVD );
|
734
|
774
|
out_flags |= TCP_SYN;
|
|
@@ -752,6 +792,7 @@ static int tcp_rx ( struct pk_buff *pkb,
|
752
|
792
|
*/
|
753
|
793
|
conn->snd_una = tcphdr->ack - 1;
|
754
|
794
|
conn->tcp_op->connected ( conn );
|
|
795
|
+ tcp_senddata ( conn );
|
755
|
796
|
return 0;
|
756
|
797
|
}
|
757
|
798
|
/* Unexpected packet */
|
|
@@ -799,6 +840,7 @@ static int tcp_rx ( struct pk_buff *pkb,
|
799
|
840
|
case TCP_CLOSING:
|
800
|
841
|
if ( tcphdr->flags & TCP_ACK ) {
|
801
|
842
|
tcp_trans ( conn, TCP_TIME_WAIT );
|
|
843
|
+ start_timer ( &conn->timer );
|
802
|
844
|
return 0;
|
803
|
845
|
}
|
804
|
846
|
/* Unexpected packet */
|
|
@@ -831,7 +873,7 @@ static int tcp_rx ( struct pk_buff *pkb,
|
831
|
873
|
/* Check if expected sequence number */
|
832
|
874
|
if ( conn->rcv_nxt == ntohl ( tcphdr->seq ) ) {
|
833
|
875
|
conn->rcv_nxt += toack;
|
834
|
|
- conn->tcp_op->newdata ( conn, pkb->data + sizeof ( *tcphdr ), toack );
|
|
876
|
+ conn->tcp_op->newdata ( conn, pkb->data + sizeof ( *tcphdr ) + add, toack );
|
835
|
877
|
}
|
836
|
878
|
|
837
|
879
|
/* Acknowledge new data */
|
|
@@ -870,8 +912,9 @@ static int tcp_rx ( struct pk_buff *pkb,
|
870
|
912
|
return 0;
|
871
|
913
|
|
872
|
914
|
unexpected:
|
873
|
|
- DBG ( "Unexpected packet received in %d state with flags = %hd\n",
|
874
|
|
- conn->tcp_state, tcphdr->flags & TCP_MASK_FLAGS );
|
|
915
|
+ DBG ( "Unexpected packet received in %s with flags = %#hx\n",
|
|
916
|
+ tcp_states[conn->tcp_state], tcphdr->flags & TCP_MASK_FLAGS );
|
|
917
|
+ tcp_close ( conn );
|
875
|
918
|
free_pkb ( conn->tx_pkb );
|
876
|
919
|
return -EINVAL;
|
877
|
920
|
}
|