Parcourir la source

TCP support

tags/v0.9.3
Nikhil Chandru Rao il y a 18 ans
Parent
révision
9225f4edac
2 fichiers modifiés avec 716 ajouts et 0 suppressions
  1. 106
    0
      src/include/gpxe/tcp.h
  2. 610
    0
      src/net/tcp.c

+ 106
- 0
src/include/gpxe/tcp.h Voir le fichier

@@ -11,6 +11,8 @@
11 11
 
12 12
 #include <stddef.h>
13 13
 #include <gpxe/in.h>
14
+#include <gpxe/list.h>
15
+#include <gpxe/pkbuff.h>
14 16
 
15 17
 struct tcp_connection;
16 18
 
@@ -87,6 +89,8 @@ struct tcp_operations {
87 89
 			      size_t len );
88 90
 };
89 91
 
92
+#if USE_UIP
93
+
90 94
 /**
91 95
  * A TCP connection
92 96
  *
@@ -104,4 +108,106 @@ extern void tcp_send ( struct tcp_connection *conn, const void *data,
104 108
 extern void tcp_kick ( struct tcp_connection *conn );
105 109
 extern void tcp_close ( struct tcp_connection *conn );
106 110
 
111
+#else
112
+
113
+#define TCP_NOMSG ""
114
+#define TCP_NOMSG_LEN 0
115
+
116
+/* Smallest port number on which a TCP connection can listen */
117
+#define TCP_MIN_PORT 1
118
+
119
+/* Some PKB constants */
120
+#define MAX_HDR_LEN	100
121
+#define MAX_PKB_LEN	1500
122
+#define MIN_PKB_LEN	MAX_HDR_LEN + 100 /* To account for padding by LL */
123
+
124
+/**
125
+ * TCP states
126
+ */
127
+#define TCP_CLOSED	0
128
+#define TCP_LISTEN	1
129
+#define TCP_SYN_SENT	2
130
+#define TCP_SYN_RCVD	3
131
+#define TCP_ESTABLISHED	4
132
+#define TCP_FIN_WAIT_1	5
133
+#define TCP_FIN_WAIT_2	6
134
+#define TCP_CLOSING	7
135
+#define TCP_TIME_WAIT	8
136
+#define TCP_CLOSE_WAIT	9
137
+#define TCP_LAST_ACK	10
138
+
139
+#define TCP_INVALID	11
140
+
141
+/**
142
+ * A TCP connection
143
+ */
144
+struct tcp_connection {
145
+	struct sockaddr sa;		/* Remote socket address */
146
+	struct sockaddr_in sin;		/* Internet socket address */
147
+	uint16_t local_port;		/* Local port, in network byte order */
148
+	int tcp_state;			/* TCP state */
149
+	int tcp_lstate;			/* Last TCP state */
150
+	uint32_t snd_una;		/* Lowest unacked byte on snd stream */
151
+	uint32_t snd_win;		/* Offered by remote end */
152
+	uint32_t rcv_nxt;		/* Next expected byte on rcv stream */
153
+	uint32_t rcv_win;		/* Advertised to receiver */
154
+	uint8_t tcp_flags;		/* TCP header flags */
155
+	struct list_head list;		/* List of TCP connections */
156
+	struct pk_buff *tx_pkb;		/* Transmit packet buffer */
157
+	struct tcp_operations *tcp_op;	/* Operations table for connection */
158
+};
159
+
160
+/**
161
+ * Connection closed status codes
162
+ */
163
+#define CONN_SNDCLOSE	0
164
+#define CONN_RESTART	1
165
+#define CONN_TIMEOUT	2
166
+#define CONN_RCVCLOSE	3
167
+
168
+/**
169
+ * A TCP header
170
+ */
171
+struct tcp_header {
172
+	uint16_t src;		/* Source port */
173
+	uint16_t dest;		/* Destination port */
174
+	uint32_t seq;		/* Sequence number */
175
+	uint32_t ack;		/* Acknowledgement number */
176
+	uint8_t hlen;		/* Header length (4), Reserved (4) */
177
+	uint8_t flags;		/* Reserved (2), Flags (6) */
178
+	uint16_t win;		/* Advertised window */
179
+	uint16_t csum;		/* Checksum */
180
+	uint16_t urg;		/* Urgent pointer */
181
+};
182
+
183
+/**
184
+ * TCP masks
185
+ */
186
+#define TCP_MASK_HLEN	0xf0
187
+#define TCP_MASK_FLAGS	0x3f
188
+
189
+/**
190
+ * TCP flags
191
+ */
192
+#define TCP_RST		0x20
193
+#define TCP_ACK		0x10
194
+#define TCP_PSH		0x08
195
+#define TCP_URG		0x04
196
+#define TCP_SYN		0x02
197
+#define TCP_FIN		0x01
198
+
199
+extern struct tcpip_protocol tcp_protocol;
200
+
201
+extern void tcp_init_conn ( struct tcp_connection *conn );
202
+extern int tcp_connect ( struct tcp_connection *conn );
203
+extern int tcp_connectto ( struct tcp_connection *conn, struct sockaddr *peer );
204
+extern int tcp_listen ( struct tcp_connection *conn, uint16_t port );
205
+extern int tcp_senddata ( struct tcp_connection *conn );
206
+extern int tcp_close ( struct tcp_connection *conn );
207
+
208
+extern int tcp_send ( struct tcp_connection *conn, const void *data, 
209
+		      size_t len );
210
+
211
+#endif /* USE_UIP */
212
+
107 213
 #endif /* _GPXE_TCP_H */

+ 610
- 0
src/net/tcp.c Voir le fichier

@@ -1,4 +1,5 @@
1 1
 #include <string.h>
2
+#include <stdlib.h>
2 3
 #include <assert.h>
3 4
 #include <byteswap.h>
4 5
 #include <latch.h>
@@ -9,6 +10,7 @@
9 10
 #include <gpxe/pkbuff.h>
10 11
 #include <gpxe/ip.h>
11 12
 #include <gpxe/tcp.h>
13
+#include <gpxe/tcpip.h>
12 14
 #include "uip/uip.h"
13 15
 
14 16
 /** @file
@@ -31,6 +33,8 @@
31 33
  *
32 34
  */
33 35
 
36
+#if USE_UIP
37
+
34 38
 /**
35 39
  * TCP transmit buffer
36 40
  *
@@ -222,3 +226,609 @@ static void init_tcp ( void ) {
222 226
 }
223 227
 
224 228
 INIT_FN ( INIT_PROCESS, init_tcp, NULL, NULL );
229
+
230
+#else
231
+
232
+/**
233
+ * List of registered TCP connections
234
+ */
235
+static LIST_HEAD ( tcp_conns );
236
+
237
+/**
238
+ * List of TCP states
239
+ */
240
+static const char *tcp_states[] = {
241
+	"CLOSED",
242
+	"LISTEN",
243
+	"SYN_SENT",
244
+	"SYN_RCVD",
245
+	"ESTABLISHED",
246
+	"FIN_WAIT_1",
247
+	"FIN_WAIT_2",
248
+	"CLOSING",
249
+	"TIME_WAIT",
250
+	"CLOSE_WAIT",
251
+	"LAST_ACK",
252
+	"INVALID" };
253
+
254
+/**
255
+ * TCP state transition function
256
+ *
257
+ * @v conn	TCP connection
258
+ * @v nxt_state Next TCP state
259
+ */
260
+void tcp_trans ( struct tcp_connection *conn, int nxt_state ) {
261
+	/* Remember the last state */
262
+	conn->tcp_lstate = conn->tcp_state;
263
+	conn->tcp_state = nxt_state;
264
+
265
+	/* TODO: Check if this check is required */
266
+	if ( conn->tcp_lstate == conn->tcp_state || 
267
+	     conn->tcp_state == TCP_INVALID ) {
268
+		conn->tcp_flags = 0;
269
+		return;
270
+	}
271
+
272
+	/* Set the TCP flags */
273
+	switch ( conn->tcp_state ) {
274
+	case TCP_CLOSED:
275
+		if ( conn->tcp_lstate == TCP_SYN_RCVD ) {
276
+			conn->tcp_flags |= TCP_RST;
277
+		}
278
+		break;
279
+	case TCP_LISTEN:
280
+		break;
281
+	case TCP_SYN_SENT:
282
+		if ( conn->tcp_lstate == TCP_LISTEN ||
283
+		     conn->tcp_lstate == TCP_CLOSED ) {
284
+			conn->tcp_flags |= TCP_SYN;
285
+		}
286
+		break;
287
+	case TCP_SYN_RCVD:
288
+		if ( conn->tcp_lstate == TCP_LISTEN ||
289
+		     conn->tcp_lstate == TCP_SYN_SENT ) {
290
+			conn->tcp_flags |= ( TCP_SYN | TCP_ACK );
291
+		}
292
+		break;
293
+	case TCP_ESTABLISHED:
294
+		if ( conn->tcp_lstate == TCP_SYN_SENT ) {
295
+			conn->tcp_flags |= TCP_ACK;
296
+		}
297
+		break;
298
+	case TCP_FIN_WAIT_1:
299
+		if ( conn->tcp_lstate == TCP_SYN_RCVD ||
300
+		     conn->tcp_lstate == TCP_ESTABLISHED ) {
301
+			conn->tcp_flags |= TCP_FIN;
302
+		}
303
+		break;
304
+	case TCP_FIN_WAIT_2:
305
+		break;
306
+	case TCP_CLOSING:
307
+		if ( conn->tcp_lstate == TCP_FIN_WAIT_1 ) {
308
+			conn->tcp_flags |= TCP_ACK;
309
+		}
310
+		break;
311
+	case TCP_TIME_WAIT:
312
+		if ( conn->tcp_lstate == TCP_FIN_WAIT_1 ||
313
+		     conn->tcp_lstate == TCP_FIN_WAIT_2 ) {
314
+			conn->tcp_flags |= TCP_ACK;
315
+		}
316
+		break;
317
+	case TCP_CLOSE_WAIT:
318
+		if ( conn->tcp_lstate == TCP_ESTABLISHED ) {
319
+			conn->tcp_flags |= TCP_ACK;
320
+		}
321
+		break;
322
+	case TCP_LAST_ACK:
323
+		if ( conn->tcp_lstate == TCP_CLOSE_WAIT ) {
324
+			conn->tcp_flags |= TCP_FIN;
325
+		}
326
+		break;
327
+	default:
328
+		DBG ( "TCP_INVALID state %d\n", conn->tcp_state );
329
+		return;
330
+	}
331
+}
332
+
333
+/**
334
+ * Dump TCP header
335
+ *
336
+ * @v tcphdr	TCP header
337
+ */
338
+void tcp_dump ( struct tcp_header *tcphdr ) {
339
+	DBG ( "TCP header at %p+%d\n", tcphdr, sizeof ( *tcphdr ) );
340
+	DBG ( "\tSource port = %d, Destination port = %d\n",
341
+		ntohs ( tcphdr->src ), ntohs ( tcphdr->dest ) );
342
+	DBG ( "\tSequence Number = %ld, Acknowledgement Number = %ld\n",
343
+		ntohl ( tcphdr->seq ), ntohl ( tcphdr->ack ) );
344
+	DBG ( "\tHeader length (/4) = %hd, Flags [..RAPUSF]= %#x\n",
345
+		( ( tcphdr->hlen & TCP_MASK_HLEN ) / 16 ),
346
+		( tcphdr->flags & TCP_MASK_FLAGS ) );
347
+	DBG ( "\tAdvertised window = %ld, Checksum = %x, Urgent Pointer = %d\n",
348
+		ntohs ( tcphdr->win ), tcphdr->csum, ntohs ( tcphdr->urg ) );
349
+}
350
+
351
+/**
352
+ * Initialize a TCP connection
353
+ *
354
+ * @v conn	TCP connection
355
+ *
356
+ * This function assigns initial values to some fields in the connection
357
+ * structure. The application should call tcp_init_conn after creating a new
358
+ * connection before calling any other "tcp_*" function.
359
+ *
360
+ * struct tcp_connection my_conn;
361
+ * tcp_init_conn ( &my_conn );
362
+ * ... 
363
+ */
364
+void tcp_init_conn ( struct tcp_connection *conn ) {
365
+	conn->local_port = 0;
366
+	conn->tcp_state = TCP_CLOSED;
367
+	conn->tcp_lstate = TCP_INVALID;
368
+	conn->tx_pkb = NULL;
369
+	conn->tcp_op = NULL;
370
+}
371
+
372
+/**
373
+ * Connect to a remote server
374
+ *
375
+ * @v conn	TCP connection
376
+ * @v peer	Remote socket address
377
+ *
378
+ * This function initiates a TCP connection to the socket address specified in
379
+ * peer. It sends a SYN packet to peer. When the connection is established, the
380
+ * TCP stack calls the connected() callback function.
381
+ */
382
+int tcp_connectto ( struct tcp_connection *conn, struct sockaddr *peer ) {
383
+	int rc;
384
+
385
+	/* A connection can only be established from the CLOSED state */
386
+	if ( conn->tcp_state != TCP_CLOSED ) {
387
+		DBG ( "Error opening connection: Invalid state %s\n",
388
+				tcp_states[conn->tcp_state] );
389
+		return -EISCONN;
390
+	}
391
+
392
+	/* Add the connection to the set of listening connections */
393
+	if ( ( rc = tcp_listen ( conn, conn->local_port ) ) != 0 ) {
394
+		return rc;
395
+	}
396
+	memcpy ( &conn->sa, peer, sizeof ( *peer ) );
397
+
398
+	/* Send a SYN packet and transition to TCP_SYN_SENT */
399
+	conn->snd_una = ( ( ( uint32_t ) random() ) << 16 ) & random();
400
+	tcp_trans ( conn, TCP_SYN_SENT );
401
+	/* Allocate space for the packet */
402
+	free_pkb ( conn->tx_pkb );
403
+	conn->tx_pkb = alloc_pkb ( MIN_PKB_LEN );
404
+	pkb_reserve ( conn->tx_pkb, MAX_HDR_LEN );
405
+	conn->rcv_win = MAX_PKB_LEN - MAX_HDR_LEN; /* TODO: Is this OK? */
406
+	return tcp_send ( conn, TCP_NOMSG, TCP_NOMSG_LEN );
407
+}
408
+
409
+int tcp_connect ( struct tcp_connection *conn ) {
410
+	return tcp_connectto ( conn, &conn->sa );
411
+}
412
+
413
+/**
414
+ * Close the connection
415
+ *
416
+ * @v conn
417
+ *
418
+ * This function sends a FIN packet to the remote end of the connection. When
419
+ * the remote end of the connection ACKs the FIN (FIN consumes one byte on the
420
+ * snd stream), the stack invokes the closed() callback function.
421
+ */
422
+int tcp_close ( struct tcp_connection *conn ) {
423
+	/* A connection can only be closed if it is a connected state */
424
+	switch ( conn->tcp_state ) {
425
+	case TCP_SYN_RCVD:
426
+	case TCP_ESTABLISHED:
427
+		tcp_trans ( conn, TCP_FIN_WAIT_1 );
428
+		conn->tcp_op->closed ( conn, CONN_SNDCLOSE ); /* TODO: Check! */
429
+		/* FIN consumes one byte on the snd stream */
430
+//		conn->snd_una++;
431
+		goto send_tcp_nomsg;
432
+	case TCP_SYN_SENT:
433
+	case TCP_LISTEN:
434
+		/**
435
+		 * Since the connection does not expect any packets from the
436
+		 * remote end, it can be removed from the set of listening
437
+		 * connections.
438
+		 */
439
+		list_del ( &conn->list );
440
+		tcp_trans ( conn, TCP_CLOSED );
441
+		conn->tcp_op->closed ( conn, CONN_SNDCLOSE );
442
+		return 0;
443
+	case TCP_CLOSE_WAIT:
444
+		tcp_trans ( conn, TCP_LAST_ACK );
445
+		conn->tcp_op->closed ( conn, CONN_SNDCLOSE ); /* TODO: Check! */
446
+		/* FIN consumes one byte on the snd stream */
447
+//		conn->snd_una++;
448
+		goto send_tcp_nomsg;
449
+	default:
450
+		DBG ( "tcp_close(): Invalid state %s\n",
451
+					tcp_states[conn->tcp_state] );
452
+		return -EPROTO;
453
+	}
454
+
455
+  send_tcp_nomsg:
456
+	free_pkb ( conn->tx_pkb );
457
+	conn->tx_pkb = alloc_pkb ( MIN_PKB_LEN );
458
+	conn->tcp_flags = TCP_FIN;
459
+	pkb_reserve ( conn->tx_pkb, MAX_HDR_LEN );
460
+	return tcp_send ( conn, TCP_NOMSG, TCP_NOMSG_LEN );
461
+}
462
+
463
+
464
+/**
465
+ * Listen for a packet
466
+ *
467
+ * @v conn	TCP connection
468
+ * @v port	Local port, in network byte order
469
+ *
470
+ * This function adds the connection to a list of registered tcp connections. If
471
+ * the local port is 0, the connection is assigned the lowest available port
472
+ * between MIN_TCP_PORT and 65535.
473
+ */
474
+int tcp_listen ( struct tcp_connection *conn, uint16_t port ) {
475
+	struct tcp_connection *cconn;
476
+	if ( port != 0 ) {
477
+		list_for_each_entry ( cconn, &tcp_conns, list ) {
478
+			if ( cconn->local_port == port ) {
479
+				DBG ( "Error listening to %d\n", 
480
+							ntohs ( port ) );
481
+				return -EISCONN;
482
+			}
483
+		}
484
+		/* Add the connection to the list of registered connections */
485
+		conn->local_port = port;
486
+		list_add ( &conn->list, &tcp_conns );
487
+		return 0;
488
+	}
489
+	/* Assigning lowest port not supported */
490
+	DBG ( "Assigning lowest port not implemented\n");
491
+	return -ENOSYS;
492
+}
493
+
494
+/**
495
+ * Send data
496
+ *
497
+ * @v conn	TCP connection
498
+ * 
499
+ * This function allocates space to the transmit buffer and invokes the
500
+ * senddata() callback function. It passes the allocated buffer to senddata().
501
+ * The applicaion may use this space to write it's data.
502
+ */
503
+int tcp_senddata ( struct tcp_connection *conn ) {
504
+	/* The connection must be in a state in which the user can send data */
505
+	switch ( conn->tcp_state ) {
506
+	case TCP_LISTEN:
507
+		tcp_trans ( conn, TCP_SYN_SENT );
508
+		conn->snd_una = ( ( ( uint32_t ) random() ) << 16 ) & random();
509
+		break;
510
+	case TCP_ESTABLISHED:
511
+	case TCP_CLOSE_WAIT:
512
+		break;
513
+	default:
514
+		DBG ( "tcp_senddata: Invalid state %s\n",
515
+				tcp_states[conn->tcp_state] );
516
+		return -EPROTO;
517
+	}
518
+
519
+	/* Allocate space to the TX buffer */
520
+	free_pkb ( conn->tx_pkb );
521
+	conn->tx_pkb = alloc_pkb ( MAX_PKB_LEN );
522
+	if ( !conn->tx_pkb ) {
523
+		DBG ( "Insufficient memory\n" );
524
+		return -ENOMEM;
525
+	}
526
+	pkb_reserve ( conn->tx_pkb, MAX_HDR_LEN );
527
+	/* Set the advertised window */
528
+	conn->rcv_win = pkb_available ( conn->tx_pkb );
529
+	/* Call the senddata() call back function */
530
+	conn->tcp_op->senddata ( conn, conn->tx_pkb->data, 
531
+					pkb_available ( conn->tx_pkb ) );
532
+	return 0;
533
+}
534
+
535
+/**
536
+ * Transmit data
537
+ *
538
+ * @v conn	TCP connection
539
+ * @v data	Data to be sent
540
+ * @v len	Length of the data
541
+ *
542
+ * This function sends data to the peer socket address
543
+ */
544
+int tcp_send ( struct tcp_connection *conn, const void *data, size_t len ) {
545
+	struct sockaddr *peer = &conn->sa;
546
+	struct pk_buff *pkb = conn->tx_pkb;
547
+	int slen;
548
+
549
+	/* Determine the amount of data to be sent */
550
+	slen = len < conn->snd_win ? len : conn->snd_win;
551
+	/* Copy payload */
552
+	memmove ( pkb_put ( pkb, slen ), data, slen );
553
+
554
+	/* Fill up the TCP header */
555
+	struct tcp_header *tcphdr = pkb_push ( pkb, sizeof ( *tcphdr ) );
556
+
557
+	/* Source port, assumed to be in network byte order in conn */
558
+	tcphdr->src = conn->local_port;
559
+	/* Destination port, assumed to be in network byte order in peer */
560
+	switch ( peer->sa_family ) {
561
+	case AF_INET:
562
+		tcphdr->dest = peer->sin.sin_port;
563
+		break;
564
+	case AF_INET6:
565
+		tcphdr->dest = peer->sin6.sin6_port;
566
+		break;
567
+	default:
568
+		DBG ( "Family type %d not supported\n", 
569
+					peer->sa_family );
570
+		return -EAFNOSUPPORT;
571
+	}
572
+	tcphdr->seq = htonl ( conn->snd_una );
573
+	tcphdr->ack = htonl ( conn->rcv_nxt );
574
+	/* Header length, = 0x50 (without TCP options) */
575
+	tcphdr->hlen = ( uint8_t ) ( ( sizeof ( *tcphdr ) / 4 ) << 4 );
576
+	/* Copy TCP flags, and then reset the variable */
577
+	tcphdr->flags = conn->tcp_flags;
578
+	conn->tcp_flags = 0;
579
+	/* Advertised window, in network byte order */
580
+	tcphdr->win = htons ( conn->rcv_win );
581
+	/* Set urgent pointer to 0 */
582
+	tcphdr->urg = 0;
583
+	/* Calculate and store partial checksum, in network byte order */
584
+	tcphdr->csum = 0;
585
+	tcphdr->csum = tcpip_chksum ( pkb->data, pkb_len ( pkb ) );
586
+	
587
+	/* Dump the TCP header */
588
+	tcp_dump ( tcphdr );
589
+
590
+	/* Transmit packet */
591
+	return tcpip_tx ( pkb, &tcp_protocol, peer );
592
+}
593
+
594
+/**
595
+ * Process received packet
596
+ *
597
+ * @v pkb	Packet buffer
598
+ * @v partial	Partial checksum
599
+ */
600
+void tcp_rx ( struct pk_buff *pkb, uint16_t partial ) {
601
+	struct tcp_connection *conn;
602
+	struct tcp_header *tcphdr;
603
+	uint32_t acked, toack;
604
+	int hlen;
605
+
606
+	/* Sanity check */
607
+	if ( pkb_len ( pkb ) < sizeof ( *tcphdr ) ) {
608
+		DBG ( "Packet too short (%d bytes)\n", pkb_len ( pkb ) );
609
+		return;
610
+	}
611
+
612
+	/* Process TCP header */
613
+	tcphdr = pkb->data;
614
+
615
+	/* Verify header length */
616
+	hlen = ( ( tcphdr->hlen & TCP_MASK_HLEN ) / 16 ) * 4;
617
+	if ( hlen != sizeof ( *tcphdr ) ) {
618
+		DBG ( "Bad header length (%d bytes)\n", hlen );
619
+		return;
620
+	}
621
+	
622
+	/* TODO: Verify checksum */
623
+	
624
+	/* Demux TCP connection */
625
+	list_for_each_entry ( conn, &tcp_conns, list ) {
626
+		if ( tcphdr->dest == conn->local_port ) {
627
+			goto found_conn;
628
+		}
629
+	}
630
+	
631
+	DBG ( "No connection found on port %d\n", ntohs ( tcphdr->dest ) );
632
+	return;
633
+
634
+  found_conn:
635
+	/* Set the advertised window */
636
+	conn->snd_win = tcphdr->win;
637
+
638
+	/* TCP State Machine */
639
+	uint8_t out_flags = 0;
640
+	conn->tcp_lstate = conn->tcp_state;
641
+	switch ( conn->tcp_state ) {
642
+	case TCP_CLOSED:
643
+		DBG ( "tcp_rx(): Invalid state %s\n",
644
+				tcp_states[conn->tcp_state] );
645
+		return;
646
+	case TCP_LISTEN:
647
+		if ( tcphdr->flags & TCP_SYN ) {
648
+			tcp_trans ( conn, TCP_SYN_RCVD );
649
+			/* Synchronize the sequence numbers */
650
+			conn->rcv_nxt = ntohl ( tcphdr->seq ) + 1;
651
+			out_flags |= TCP_ACK;
652
+
653
+			/* Set the sequence number for the snd stream */
654
+			conn->snd_una = ( ( ( uint32_t ) random() ) << 16 );
655
+			conn->snd_una &= random();
656
+			out_flags |= TCP_SYN;
657
+
658
+			/* Send a SYN,ACK packet */
659
+			goto send_tcp_nomsg;
660
+		}
661
+		/* Unexpected packet */
662
+		goto unexpected;
663
+	case TCP_SYN_SENT:
664
+		if ( tcphdr->flags & TCP_SYN ) {
665
+			/* Synchronize the sequence number in rcv stream */
666
+			conn->rcv_nxt = ntohl ( tcphdr->seq ) + 1;
667
+			out_flags |= TCP_ACK;
668
+
669
+			if ( tcphdr->flags & TCP_ACK ) {
670
+				tcp_trans ( conn, TCP_ESTABLISHED );
671
+				/**
672
+				 * Process ACK of SYN. This does not invoke the
673
+				 * acked() callback function.
674
+				 */
675
+				conn->snd_una = ntohl ( tcphdr->ack );
676
+				conn->tcp_op->connected ( conn );
677
+			} else {
678
+				tcp_trans ( conn, TCP_SYN_RCVD );
679
+				out_flags |= TCP_SYN;
680
+			}
681
+			/* Send SYN,ACK or ACK packet */
682
+			goto send_tcp_nomsg;
683
+		}
684
+		/* Unexpected packet */
685
+		goto unexpected;
686
+	case TCP_SYN_RCVD:
687
+		if ( tcphdr->flags & TCP_RST ) {
688
+			tcp_trans ( conn, TCP_LISTEN );
689
+			conn->tcp_op->closed ( conn, CONN_RESTART );
690
+			return;
691
+		}
692
+		if ( tcphdr->flags & TCP_ACK ) {
693
+			tcp_trans ( conn, TCP_ESTABLISHED );
694
+			/**
695
+			 * Process ACK of SYN. It neither invokes the callback
696
+			 * function nor does it send an ACK.
697
+			 */
698
+			conn->snd_una = tcphdr->ack - 1;
699
+			conn->tcp_op->connected ( conn );
700
+			return;
701
+		}
702
+		/* Unexpected packet */
703
+		goto unexpected;
704
+	case TCP_ESTABLISHED:
705
+		if ( tcphdr->flags & TCP_FIN ) {
706
+			tcp_trans ( conn, TCP_CLOSE_WAIT );
707
+			/* FIN consumes one byte */
708
+			conn->rcv_nxt++;
709
+			out_flags |= TCP_ACK;
710
+			/* Send an acknowledgement */
711
+			goto send_tcp_nomsg;
712
+		}
713
+		/* Packet might contain data */
714
+		break;
715
+	case TCP_FIN_WAIT_1:
716
+		if ( tcphdr->flags & TCP_FIN ) {
717
+			conn->rcv_nxt++;
718
+			out_flags |= TCP_ACK;
719
+			conn->tcp_op->closed ( conn, CONN_SNDCLOSE );
720
+
721
+			if ( tcphdr->flags & TCP_ACK ) {
722
+				tcp_trans ( conn, TCP_TIME_WAIT );
723
+			} else {
724
+				tcp_trans ( conn, TCP_CLOSING );
725
+			}
726
+			/* Send an acknowledgement */
727
+			goto send_tcp_nomsg;
728
+		}
729
+		if ( tcphdr->flags & TCP_ACK ) {
730
+			tcp_trans ( conn, TCP_FIN_WAIT_2 );
731
+		}
732
+		/* Packet might contain data */
733
+		break;
734
+	case TCP_FIN_WAIT_2:
735
+		if ( tcphdr->flags & TCP_FIN ) {
736
+			tcp_trans ( conn, TCP_TIME_WAIT );
737
+			/* FIN consumes one byte */
738
+			conn->rcv_nxt++;
739
+			out_flags |= TCP_ACK;
740
+			goto send_tcp_nomsg;
741
+		}
742
+		/* Packet might contain data */
743
+		break;
744
+	case TCP_CLOSING:
745
+		if ( tcphdr->flags & TCP_ACK ) {
746
+			tcp_trans ( conn, TCP_TIME_WAIT );
747
+			return;
748
+		}
749
+		/* Unexpected packet */
750
+		goto unexpected;
751
+	case TCP_TIME_WAIT:
752
+		/* Unexpected packet */
753
+		goto unexpected;
754
+	case TCP_CLOSE_WAIT:
755
+		/* Packet could acknowledge data */
756
+		break;
757
+	case TCP_LAST_ACK:
758
+		if ( tcphdr->flags & TCP_ACK ) {
759
+			tcp_trans ( conn, TCP_CLOSED );
760
+			return;
761
+		}
762
+		/* Unexpected packet */
763
+		goto unexpected;
764
+	}
765
+
766
+	/**
767
+	 * Any packet reaching this point either contains new data or
768
+	 * acknowledges previously transmitted data.
769
+	 */
770
+	assert ( ( tcphdr->flags & TCP_ACK ) ||
771
+		 pkb_len ( pkb ) > sizeof ( *tcphdr ) );
772
+
773
+	/* Check for new data */
774
+	toack = pkb_len ( pkb ) - hlen;
775
+	if ( toack > 0 ) {
776
+		/* Check if expected sequence number */
777
+		if ( conn->rcv_nxt == ntohl ( tcphdr->seq ) ) {
778
+			conn->rcv_nxt += toack;
779
+			conn->tcp_op->newdata ( conn, pkb->data + sizeof ( *tcphdr ), toack );
780
+		}
781
+
782
+		/* Acknowledge new data */
783
+		out_flags |= TCP_ACK;
784
+		if ( !( tcphdr->flags & TCP_ACK ) ) {
785
+			goto send_tcp_nomsg;
786
+		}
787
+	}
788
+
789
+	/* Process ACK */
790
+	if ( tcphdr->flags & TCP_ACK ) {
791
+		acked = ntohl ( tcphdr->ack ) - conn->snd_una;
792
+		if ( acked < 0 ) { /* TODO: Replace all uint32_t arith */
793
+			DBG ( "Previously ACKed (%d)\n", tcphdr->ack );
794
+			return;
795
+		}
796
+		/* Advance snd stream */
797
+		conn->snd_una += acked;
798
+		/* Set the ACK flag */
799
+		conn->tcp_flags |= TCP_ACK;
800
+		/* Invoke the acked() callback function */
801
+		conn->tcp_op->acked ( conn, acked );
802
+		/* Invoke the senddata() callback function */
803
+		tcp_senddata ( conn );
804
+	}
805
+	return;
806
+
807
+  send_tcp_nomsg:
808
+	free_pkb ( conn->tx_pkb );
809
+	conn->tx_pkb = alloc_pkb ( MIN_PKB_LEN );
810
+	pkb_reserve ( conn->tx_pkb, MAX_HDR_LEN );
811
+	int rc;
812
+	if ( ( rc = tcp_send ( conn, TCP_NOMSG, TCP_NOMSG_LEN ) ) != 0 ) {
813
+		DBG ( "Error sending TCP message (rc = %d)\n", rc );
814
+	}
815
+	return;
816
+
817
+  unexpected:
818
+	DBG ( "Unexpected packet received in %d state with flags = %hd\n",
819
+			conn->tcp_state, tcphdr->flags & TCP_MASK_FLAGS );
820
+	free_pkb ( conn->tx_pkb );
821
+	return;
822
+}
823
+
824
+/** TCP protocol */
825
+struct tcpip_protocol tcp_protocol = {
826
+	.name = "TCP",
827
+	.rx = tcp_rx,
828
+	.trans_proto = IP_TCP,
829
+	.csum_offset = 16,
830
+};
831
+
832
+TCPIP_PROTOCOL ( tcp_protocol );
833
+
834
+#endif /* USE_UIP */

Chargement…
Annuler
Enregistrer