Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 21 Jun 2007 14:10:53 GMT
From:      Alexey Tarasov <taleks@FreeBSD.org>
To:        Perforce Change Reviews <perforce@FreeBSD.org>
Subject:   PERFORCE change 122093 for review
Message-ID:  <200706211410.l5LEAreH087709@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=122093

Change 122093 by taleks@taleks_th on 2007/06/21 14:10:11

	Updated pxe_socks module for connecting and closing  to TCP sockets. pxe_tcp module seems do handshaking and breaking correctly in active closing/establishing connection.
	Need to implement passive closing (CLOSE_WAIT, LAST_ACK states)  and resending of packets.

Affected files ...

.. //depot/projects/soc2007/taleks-pxe_http/pxe_sock.c#9 edit
.. //depot/projects/soc2007/taleks-pxe_http/pxe_tcp.c#2 edit
.. //depot/projects/soc2007/taleks-pxe_http/pxe_tcp.h#4 edit

Differences ...

==== //depot/projects/soc2007/taleks-pxe_http/pxe_sock.c#9 (text+ko) ====

@@ -140,18 +140,28 @@
 #endif 	
 		return (0);
 	}
+
+	PXE_FILTER_ENTRY *filter = sock->filter;
+
+	/* socket buffers seems not be used more */
+	pxe_buffer_memfree(&sock->send_buffer);
+	pxe_buffer_memfree(&sock->recv_buffer);
 	
-	if (sock->filter != NULL)	
-		pxe_filter_remove(sock->filter);
-	else {
+	/* UDP socket closing is simple */	
+	if (filter->protocol == PXE_UDP_PROTOCOL) {
+
+		if (filter != NULL)	
+			pxe_filter_remove(sock->filter);
+		else {
 #ifdef PXE_DEBUG
-		printf("pxe_close(): filter for socket already NULL.\n");
+			printf("pxe_close(): filter for socket already NULL.\n");
 #endif
+		}
+	} else {
+		 /* filter removing is done in check_time_to_die() in pxe_tcp.c */
+		 pxe_tcp_disconnect(sock);
 	}
 	
-	pxe_buffer_memfree(&sock->send_buffer);
-	pxe_buffer_memfree(&sock->recv_buffer);
-	
 	return pxe_socket_free(socket);
 }
 
@@ -332,7 +342,7 @@
 	} else  { /* not binded, connect */
 	
 		/* NOTE: if it's already connected, return error */
-		if (!pxe_connect(socket, ip, port, PXE_UDP_PROTOCOL)) {
+		if (pxe_connect(socket, ip, port, PXE_UDP_PROTOCOL) == -1) {
 			printf("pxe_sendto(): failed to connect.\n");
 			return (-1);
 		}
@@ -351,7 +361,6 @@
 	 * for binded sockets pxe_connect() skipped, so we need manually call pxe_next_port()
 	 * to get local port (so, we don't use binded local port, it seems correct behaviour)
 	 */
-/*	uint16_t lport = (sock->state == PXE_SOCKET_BINDED) ? pxe_next_port() : filter->dst_port; */
 	uint16_t lport = filter->dst_port;
 
 #ifdef PXE_DEBUG
@@ -377,14 +386,14 @@
  *	proto	- IP stack protocol
  * out:
  *	-1		- failed
- *	nonnegative	- new socket descriptor number
+ *	0		- success
  */	
 int
 pxe_connect(int socket, uint32_t ip, uint16_t port, uint8_t proto)
 {
 
 	if ( (socket >= PXE_DEFAULT_SOCKETS) || (socket == -1)) {
-		return (0);
+		return (-1);
 	}
 	
 	PXE_SOCKET	*sock = &pxe_sockets[socket];
@@ -405,7 +414,7 @@
 	
 	if (port == 0) {
 		printf("pxe_connect(): failed to allocate local port.\n");
-		return (0);
+		return (-1);
 	}
 	
 	PXE_FILTER_ENTRY *entry =
@@ -414,7 +423,7 @@
 	
 	if ( entry == NULL ) {
 		printf("pxe_connect(): failed to add filter.\n");
-		return (0);	
+		return (-1);	
 	}
 	
 	sock->filter = entry;
@@ -425,16 +434,15 @@
 		if (pxe_tcp_connect(sock)) {
 			sock->state = PXE_SOCKET_ESTABLISHED;
 		} else { /* failed, cleanup */
-			pxe_filter_remove(entry);
-			return (0);
+			return (-1);
 		}
 	}
 
 #ifdef PXE_DEBUG
-	printf("pxe_connect(): socket %d connected, 0x%x:%d -> 0x%x:%d\n", socket, pxe_get_ip32(PXE_IP_MY), lport,  ip, port);
+	printf("pxe_connect(): socket %d connected, 0x%x:%d -> 0x%x:%d\n", socket, pxe_get_ip32(PXE_IP_MY), lport, ip, port);
 #endif	
 	/* all is ok */
-	return (1);
+	return (0);
 }
 
 /* NOTE: assuming socket is UDP, need to think about TCP/UDP functions calling

==== //depot/projects/soc2007/taleks-pxe_http/pxe_tcp.c#2 (text+ko) ====

@@ -8,25 +8,49 @@
 #include "pxe_sock.h"
 #include "pxe_tcp.h"
 
+/* state handle functions */
+static int tcp_syn_sent(PXE_TCP_PACKET *tcp_packet, PXE_TCP_CONNECTION *connection);
+static int tcp_established(PXE_TCP_PACKET *tcp_packet, PXE_TCP_CONNECTION *connection);
+static int tcp_fin_wait1(PXE_TCP_PACKET *tcp_packet, PXE_TCP_CONNECTION *connection);
+static int tcp_closing(PXE_TCP_PACKET *tcp_packet, PXE_TCP_CONNECTION *connection);
+static int tcp_fin_wait2(PXE_TCP_PACKET *tcp_packet, PXE_TCP_CONNECTION *connection);
+static int tcp_time_wait(PXE_TCP_PACKET *tcp_packet, PXE_TCP_CONNECTION *connection);
+static int tcp_close_wait(PXE_TCP_PACKET *tcp_packet, PXE_TCP_CONNECTION *connection);
+static int tcp_last_ack(PXE_TCP_PACKET *tcp_packet, PXE_TCP_CONNECTION *connection);
+
+/* connection structs storage */
 static PXE_TCP_CONNECTION	tcp_connections[PXE_MAX_TCP_CONNECTIONS];
+/* currently allocated connections */
 static int			all_connections = 0;
+/* pointers to appropriate state handlers */
+static pxe_tcp_state_func	state_functions[PXE_TCP_ALL_STATES] = {
+					NULL,		/* PXE_TCP_CLOSED */
+					tcp_syn_sent,	/* PXE_TCP_SYN_SENT */
+					NULL,		/* PXE_TCP_SYN_RECEIVED */
+					tcp_established,/* PXE_TCP_ESTABLISHED */
+					tcp_close_wait,	/* PXE_TCP_CLOSE_WAIT */
+					tcp_last_ack,	/* PXE_TCP_LAST_ACK */
+					tcp_fin_wait1,	/* PXE_TCP_FIN_WAIT1 */
+					tcp_closing,	/* PXE_TCP_CLOSING */
+					tcp_fin_wait2,	/* PXE_TCP_FIN_WAIT2 */
+					tcp_time_wait,	/* PXE_TCP_TIME_WAIT */
+				};
 
-
-/* sock_to_connection() - returns connections, associated with provided socket
+/* filter_to_connection() - returns connections, associated with provided filter
  * in:
- *	sock - pointer to socket structure, for which connection is searched
+ *	filter - pointer to filter entry structure, for which connection is searched
  * out:
  *	NULL	- failed to find
  *	not NULL- searched connections
  */
 static PXE_TCP_CONNECTION *
-sock_to_connection(PXE_SOCKET *sock)
+filter_to_connection(PXE_FILTER_ENTRY *filter)
 {
 	int con_index = 0;
 	
 	for ( ; con_index < PXE_MAX_TCP_CONNECTIONS; ++con_index) {
 
-		if (tcp_connections[con_index].sock == sock) {
+		if (tcp_connections[con_index].filter == filter) {
 			return (&tcp_connections[con_index]);
 		}
 	}
@@ -34,6 +58,93 @@
 	return (NULL);
 }
 
+/* alloc_connection() - returns pointer to free connection structure
+ * in:
+ *	none
+ * out:
+ *	NULL	- failed to alloc
+ *	non NULL- pointer to allocated structure
+ */
+PXE_TCP_CONNECTION *
+alloc_connection()
+{
+	if (all_connections == PXE_MAX_TCP_CONNECTIONS)
+		return (NULL);
+		
+	uint16_t	index = 0;
+	
+	for ( ; index < PXE_MAX_TCP_CONNECTIONS; ++index) {
+	
+		if (tcp_connections[index].state == PXE_TCP_CLOSED) {
+			/* if state is closed, it's free structure*/
+			all_connections += 1;
+			return &tcp_connections[index];
+		}
+	}
+	
+	/* NOTE: we must not ever get here */
+	return (NULL);
+}
+
+/* free_connection() - releases connections
+ * in:
+ *	connection - pointer to connection to release (assuming it's valid connection)
+ * out:
+ *	none
+ */
+void
+free_connection(PXE_TCP_CONNECTION *connection)
+{
+
+	connection->state = PXE_TCP_CLOSED;
+	all_connections -= 1;
+}
+
+/* get_secs() - returns time in seconds
+ * in:
+ *	none
+ * out:
+ *	elapsed time in seconds
+ */
+static time_t
+get_secs()
+{
+	time_t secs;
+
+	time(&secs);
+	
+	return (secs);
+}
+
+/* check_time_to_die() - moves to CLOSED state connections from state
+ *	TIME_WAIT if last received packet (ACK for FIN in most cases)
+ *	was more than 2*MSL time ago.
+ * in:
+ *	connection - connection to check
+ * out:
+ *	none
+ */
+static void
+check_time_to_die(PXE_TCP_CONNECTION *connection)
+{
+	/* if connection in other states - do nothing */
+	if (connection->state != PXE_TCP_TIME_WAIT)
+		return;
+		
+	time_t cur_time = get_secs();
+
+	if (cur_time - connection->last_recv > 2 * PXE_TCP_MSL) {
+		/* release filter */
+		PXE_FILTER_ENTRY *filter = connection->filter;
+		
+		if (filter != NULL) /* it must always be non NULL */
+			pxe_filter_remove(filter);
+		
+		/* release connection */
+		free_connection(connection);
+	}
+}
+
 /* tcp_send_rst_for() - sends RST in reply to provided packet
  * in:
  *	tcp_packet - packet which caused RST sending
@@ -41,10 +152,9 @@
  *	0 - failed
  *	1 - success
  */
-int
+static int
 tcp_send_rst_for(PXE_TCP_PACKET *tcp_packet)
 {
-
 	PXE_TCP_CONNECTION	connection;
 	pxe_memset(&connection, 0, sizeof(PXE_TCP_CONNECTION));
 			
@@ -52,30 +162,260 @@
 	connection.src_port = le2be16(tcp_packet->tcphdr.dst_port);
 	connection.dst_ip = tcp_packet->iphdr.src_ip;
 	connection.next_recv = le2be32(tcp_packet->tcphdr.sequence) + 1;
+	connection.next_send = le2be32(tcp_packet->tcphdr.ack_next);
+	
+	return pxe_tcp_send(&connection, 0, PXE_TCP_RST | PXE_TCP_ACK);
+}
+
+/* tcp_syn_sent() - SYN_SENT state handler
+ * in:
+ *	tcp_packet - incoming packet data
+ *	connection - current connection
+ * out:
+ *	0 - don't interested more in this packet
+ *	1 - interested
+ *	2 - try next state handler
+ */
+static int
+tcp_syn_sent(PXE_TCP_PACKET *tcp_packet, PXE_TCP_CONNECTION *connection)
+{
+	uint8_t flags = tcp_packet->tcphdr.flags;
+	
+	/*  accepting only SYN+ACK */
+	if ( (flags & (PXE_TCP_SYN | PXE_TCP_ACK)) 
+		!= (PXE_TCP_SYN | PXE_TCP_ACK)) 
+	{
+		return (0);		/* drop, may be better RST */
+	}
+
+	connection->next_recv = le2be32(tcp_packet->tcphdr.sequence) + 1;
+	connection->next_send = le2be32(tcp_packet->tcphdr.ack_next);
+
+#ifdef PXE_DEBUG_HELL
+	printf("tcp_syn_sent(): ack = %d, seq = %d\n", connection->next_recv, connection->next_send);
+#endif	
+	if (pxe_tcp_send(connection, 0, PXE_TCP_ACK)) {
+		connection->state = PXE_TCP_ESTABLISHED;
+#ifdef PXE_DEBUG_HELL
+		printf("tcp_syn_sent(): new state - ESTABLISHED\n");
+#endif
+		/* updating last recv time. Used in resending and TIME_WAIT state */
+		connection->last_recv = get_secs();
+	} else {
+		printf("tcp_syn_sent(): failed to ack syn reply packet.\n");
+	}
+
+	return (0);
+}
+
+/* tcp_established() - ESTABLISHED state handler
+ * in:
+ *	tcp_packet - incoming packet data
+ *	connection - current connection
+ * out:
+ *	0 - don't interested more in this packet
+ *	1 - interested
+ *	2 - try next state handler
+ */
+static int
+tcp_established(PXE_TCP_PACKET *tcp_packet, PXE_TCP_CONNECTION *connection)
+{
+	uint8_t flags = tcp_packet->tcphdr.flags;
 	
-	return pxe_tcp_send(&connection, 0, PXE_TCP_RST);;
+	if (flags & PXE_TCP_FIN) {	/* remote host requested connection break */
+	
+		connection->next_recv = le2be32(tcp_packet->tcphdr.sequence) + 1;
+		connection->next_send = le2be32(tcp_packet->tcphdr.ack_next);
+
+#ifdef PXE_DEBUG_HELL
+		printf("tcp_established(): ack = %d, seq = %d\n", connection->next_recv, connection->next_send);
+#endif		
+		if (!pxe_tcp_send(connection, 0, PXE_TCP_ACK)) {
+			printf("tcp_established(): failed to ack FIN request.\n");
+			return (0);
+		}
+	
+		connection->last_recv = get_secs();	
+		connection->state = PXE_TCP_CLOSE_WAIT;
+#ifdef PXE_DEBUG_HELL
+		printf("tcp_established(): new state - CLOSE_WAIT\n");
+#endif
+		return (0);
+	}
+	
+	/* TODO: process data receiving */
+	
+	
+	connection->last_recv = get_secs();
+	return (0);
+}
+
+/* tcp_fin_wait1() - FIN_WAIT_1 state handler
+ * in:
+ *	tcp_packet - incoming packet data
+ *	connection - current connection
+ * out:
+ *	0 - don't interested more in this packet
+ *	1 - interested
+ *	2 - try next state handler
+ */
+static int
+tcp_fin_wait1(PXE_TCP_PACKET *tcp_packet, PXE_TCP_CONNECTION *connection)
+{
+	uint8_t flags = tcp_packet->tcphdr.flags;
+	
+	if ( (flags & (PXE_TCP_ACK | PXE_TCP_FIN)) == ((PXE_TCP_ACK | PXE_TCP_FIN)) ) {
+		/* remote host acked our FIN and sent FIN  */
+
+		connection->next_recv = le2be32(tcp_packet->tcphdr.sequence) + 1; 
+		connection->next_send = le2be32(tcp_packet->tcphdr.ack_next);
+
+#ifdef PXE_DEBUG_HELL
+		printf("tcp_fin_wait1(): ack = %d, seq = %d\n", connection->next_recv, connection->next_send);
+#endif	
+		
+		if (!pxe_tcp_send(connection, 0, PXE_TCP_ACK)) {
+			printf("tcp_fin_wait2(): failed to ack FIN request.\n");
+			return (0);
+		}
+		
+		connection->state = PXE_TCP_CLOSING;
+#ifdef PXE_DEBUG_HELL
+		printf("tcp_fin_wait1(): new state - CLOSING\n");
+#endif		
+		connection->last_recv = get_secs();
+		return (0);
+	}
+	
+	if (flags & PXE_TCP_ACK) { /* remote host just acked our FIN  */
+
+/*		connection->next_recv = le2be32(tcp_packet->tcphdr.sequence) + 1; */
+		connection->next_send = le2be32(tcp_packet->tcphdr.ack_next);
+		connection->state = PXE_TCP_FIN_WAIT2;
+#ifdef PXE_DEBUG_HELL
+		printf("tcp_fin_wait1(): ack = %d, seq = %d\n", connection->next_recv, connection->next_send);
+		printf("tcp_fin_wait1(): new state - FIN_WAIT_2\n");
+#endif				
+		connection->last_recv = get_secs();
+	}
+
+	return (0);
+}
+
+/* tcp_closing() - CLOSING state handler
+ * in:
+ *	tcp_packet - incoming packet data
+ *	connection - current connection
+ * out:
+ *	0 - don't interested more in this packet
+ *	1 - interested
+ *	2 - try next state handler
+ */
+static int
+tcp_closing(PXE_TCP_PACKET *tcp_packet, PXE_TCP_CONNECTION *connection)
+{
+	uint8_t flags = tcp_packet->tcphdr.flags;
+	
+	if (flags & PXE_TCP_ACK) { /* remote host acked FIN */
+		connection->state = PXE_TCP_TIME_WAIT;
+#ifdef PXE_DEBUG_HELL
+		printf("tcp_closing(): new state - TIME_WAIT\n");
+#endif		
+		connection->last_recv = get_secs();
+	}
+	
+	return (0);
 }
 
-/* tcp_send_ack_for() - sends ACK in reply to provided packet
+/* tcp_fin_wait2() - FIN_WAIT_2 state handler
  * in:
- *	tcp_packet - packet which caused RST sending
+ *	tcp_packet - incoming packet data
+ *	connection - current connection
  * out:
- *	0 - failed
- *	1 - success
+ *	0 - don't interested more in this packet
+ *	1 - interested
+ *	2 - try next state handler
  */
-int
-tcp_send_ack_for(PXE_TCP_PACKET *tcp_packet, uint32_t next_recv)
+static int
+tcp_fin_wait2(PXE_TCP_PACKET *tcp_packet, PXE_TCP_CONNECTION *connection)
 {
+	uint8_t flags = tcp_packet->tcphdr.flags;
+	
+	if (flags & PXE_TCP_FIN) {	/* remote sent FIN */
+	
+		connection->next_recv = le2be32(tcp_packet->tcphdr.sequence) + 1;
+		connection->next_send = le2be32(tcp_packet->tcphdr.ack_next);
+#ifdef PXE_DEBUG_HELL	
+		printf("tcp_fin_wait2(): ack = %d, seq = %d\n", connection->next_recv, connection->next_send);
+#endif		
+		if (!pxe_tcp_send(connection, 0, PXE_TCP_ACK)) {
+			printf("tcp_fin_wait2(): failed to ack FIN request.\n");
+			return (0);
+		}
+		
+		connection->state = PXE_TCP_TIME_WAIT;
+#ifdef PXE_DEBUG_HELL
+		printf("tcp_fin_wait2(): new state - TIME_WAIT\n");
+#endif		
+		connection->last_recv = get_secs();
+	}
+	
+	return (0);
+}
 
-	PXE_TCP_CONNECTION	connection;
-	pxe_memset(&connection, 0, sizeof(PXE_TCP_CONNECTION));
-			
-	connection.dst_port = le2be16(tcp_packet->tcphdr.src_port);
-	connection.src_port = le2be16(tcp_packet->tcphdr.dst_port);
-	connection.dst_ip = tcp_packet->iphdr.src_ip;
-	connection.next_recv = le2be32(next_recv);
+/* tcp_time_wait() - TIME_WAIT state handler
+ * in:
+ *	tcp_packet - incoming packet data
+ *	connection - current connection
+ * out:
+ *	0 - don't interested more in this packet
+ *	1 - interested
+ *	2 - try next state handler
+ */
+static int
+tcp_time_wait(PXE_TCP_PACKET *tcp_packet, PXE_TCP_CONNECTION *connection)
+{
+	/* this state grabs lost packets */
+	
+	check_time_to_die(connection);
 	
-	return pxe_tcp_send(&connection, 0, PXE_TCP_ACK);;
+	return (0);
+}
+
+/* tcp_close_wait() - CLOSE_WAIT state handler. TODO: implement
+ * in:
+ *	tcp_packet - incoming packet data
+ *	connection - current connection
+ * out:
+ *	0 - don't interested more in this packet
+ *	1 - interested
+ *	2 - try next state handler
+ */
+static int
+tcp_close_wait(PXE_TCP_PACKET *tcp_packet, PXE_TCP_CONNECTION *connection)
+{
+#ifdef PXE_DEBUG_HELL
+	printf("tcp_close_wait(): started.\n");
+#endif
+	return (0);
+}
+
+/* tcp_last_ack() - LAST_ACK state handler. TODO: implement
+ * in:
+ *	tcp_packet - incoming packet data
+ *	connection - current connection
+ * out:
+ *	0 - don't interested more in this packet
+ *	1 - interested
+ *	2 - try next state handler
+ */
+static int
+tcp_last_ack(PXE_TCP_PACKET *tcp_packet, PXE_TCP_CONNECTION *connection)
+{
+#ifdef PXE_DEBUG_HELL
+	printf("tcp_last_ack(): started.\n");
+#endif
+	return (0);
 }
 
 /* pxe_tcp_callback() - TCP protocol callback function, executed by pxe_core
@@ -144,7 +484,7 @@
 		if (flags & PXE_TCP_SYN) {	/* this was hopeless attempt to connect */
 		
 			tcp_send_rst_for(tcp_packet);
-		}
+		} /* otherwise just ignore this packet */
 		
 		return (0);	
 	}
@@ -154,76 +494,60 @@
 
 	/* TODO:  verify checksum  */
 	
-	/* Here socket is not NULL, that means packet is for connected socket or
-	 * connection is trying to be established
+	/* Here filter is not NULL, that means packet is for connected socket or
+	 * connection is trying to be established/breaked correctly
 	 */
 	
-	PXE_TCP_CONNECTION	*connection = sock_to_connection(sock);
+	PXE_TCP_CONNECTION	*connection = filter_to_connection(sock->filter);
 
 	if (connection == NULL) {
-		printf("pxe_tcp_callback(): there is no connection for socket 0x%x", sock);
+		printf("pxe_tcp_callback(): there is no connection for filter 0x%x\n", sock->filter);
 		return (0);	/* NOTE: this is internal error, if got here */
 	}
 
-	switch (connection->state) {
-	case PXE_TCP_CLOSED:			/* connection is already closed */
-		tcp_send_rst_for(tcp_packet);	/* in fact, we must not ever reach this point */
-		return (0);			/* cause filter for connection is destroyed */
-						/* so this checks for internal error */
-
-	case PXE_TCP_SYN_SENT:			/* started client handshaking, waiting SYN ACK only */
-		if (flags != (PXE_TCP_SYN | PXE_TCP_ACK)) {
-			return (0);		/* drop, may be better RST */
-		}
-		break;
-
-	case PXE_TCP_ESTABLISHED:		/* process receiving data to socket buffer */
-		break;
-/*
-	case PXE_TCP_CLOSE_WAIT:
-	case PXE_TCP_SYN_RECIEVED:	
-	case PXE_TCP_LAST_ACK:
-	case PXE_TCP_FIN_WAIT1:
-	case PXE_TCP_CLOSING:
-	case PXE_TCP_FIN_WAIT2:
-	case PXE_TCP_TIME_WAIT:
-*/	
-	default:	/* never getting here */
-		return (0);
-		break;
-	}
-	
-	/* connection is in established state */
-	
-	/* checking sequence order (!SIMPLE STUB!) */
 	uint32_t seq = le2be32(tcp_packet->tcphdr.sequence);
 	
-	if (seq != connection->next_recv) {				/* not next in order, drop it, send ACK */
-		tcp_send_ack_for(tcp_packet, connection->next_recv);	/* with next needed sequence number */
+	if (flags & PXE_TCP_RST) {	/* connection aborted (hard error) by remote host */
+		printf("pxe_tcp_callback(): connectuion refused.\n");
+		connection->state = PXE_TCP_RESETED;
 		return (0);
 	}
-	
-	/* receiving data to buffer */
-	uint16_t buf_free = sock->recv_buffer.bufleft;
-	
-	if (buf_free < data_size) {	/* no space, by the way */
-		/* send packet with buf_free window */
-		tcp_send_ack_for(tcp_packet, connection->next_recv);
-		return (0);
-	}
 
-	PXE_BUFFER* recv_buffer = &sock->recv_buffer;
+	if (connection->state > PXE_TCP_SYN_SENT) { /* if we know sequence number, then check it */
 
-	if (pxe_buffer_space(recv_buffer) < data_size) {
-		printf("pxe_udp_callback(): not enough space in recv buffer for socket %d\n", sock);	
+		if (seq != connection->next_recv) {			/* not next in order, drop it, send ACK */
+/*		tcp_send_ack_for(tcp_packet, connection->next_recv,	/* with next needed sequence number */
+/*			connection->next_send, sock); */
+#ifdef PXE_DEBUG
+			printf("pxe_tcp_callback(): got %d != awaited %d\n", seq, connection->next_recv);
+#endif
+			return (0);
+		}
 	} else {
-		pxe_buffer_write(recv_buffer, tcp_packet + 1, data_size);
+	    /* in case of SYN_SENT state we don't know sequence number yet */
+	}
+	
+	/* calling appropriate state handler, if it's not NULL */
+	if (connection->state < PXE_TCP_ALL_STATES) {
+	
+		int result = 0;
+		while (1) {
+		    
+		    if (state_functions[connection->state] != NULL) {
+			    result = state_functions[connection->state](tcp_packet, connection);
+			    
+			    if (result == 2)
+				    continue;
+			
+			    return (result);
+		    }
+		}
 	}
 	
 	return (0);
 }                                                            
 
-/* pxe_udp_init() - initialization of UDP module
+/* pxe_tcp_init() - initialization of TCP module
  * in/out:
  *	none
  */
@@ -251,7 +575,6 @@
 int
 pxe_tcp_send(PXE_TCP_CONNECTION *connection, uint16_t size, uint8_t tcp_flags)
 {
-
 	PXE_TCP_PACKET	dummy_packet;
 	PXE_TCP_PACKET  *tcp_packet = &dummy_packet;
        
@@ -259,11 +582,15 @@
 	tcp_packet->tcphdr.src_port = le2be16(connection->src_port);
 	tcp_packet->tcphdr.dst_port = le2be16(connection->dst_port);
 	tcp_packet->tcphdr.checksum = 0;
-	tcp_packet->tcphdr.sequence = 0;
+	tcp_packet->tcphdr.sequence = le2be32(connection->next_send);
 	tcp_packet->tcphdr.ack_next = le2be32(connection->next_recv);
 	tcp_packet->tcphdr.data_off = (uint8_t)((sizeof(PXE_TCP_HDR)/4) << 4);
 	tcp_packet->tcphdr.flags = tcp_flags;
-	tcp_packet->tcphdr.window_size = 0;
+
+	PXE_BUFFER *recv_buffer = connection->recv;
+
+	/* set window size to free buffer space size, or to zero if recv_buffer == NULL */
+	tcp_packet->tcphdr.window_size = (recv_buffer != NULL) ? le2be16(recv_buffer->bufleft) : 0;
 	tcp_packet->tcphdr.checksum = 0;
 	tcp_packet->tcphdr.urgent = 0;
 	
@@ -274,16 +601,16 @@
 	pseudo_hdr.zero = 0;
 	pseudo_hdr.proto = PXE_TCP_PROTOCOL;
 	pseudo_hdr.length = le2be16(length);
-       /* adding pseudo header checksum to checksum of udp header with data
+
+       /* adding pseudo header checksum to checksum of tcp header with data
         * and make it complimentary
 	*/
-																									 
 	uint16_t part1 = pxe_ip_checksum(&pseudo_hdr, sizeof(PXE_IP4_PSEUDO_HDR));
 	uint16_t part2 = pxe_ip_checksum(&tcp_packet->tcphdr, length);
 	
 	uint32_t tmp_sum = ((uint32_t)part1) + ((uint32_t)part2);
 	
-	if (tmp_sum & 0xf0000) { /*need carry out */
+	if (tmp_sum & 0xf0000) { /* need carry out */
 		tmp_sum -= 0xffff;
 																															         }
 	tcp_packet->tcphdr.checksum = ~((uint16_t)(tmp_sum & 0xffff));
@@ -298,60 +625,19 @@
 
 	if (!pxe_ip_send(tcp_packet, connection->dst_ip, PXE_TCP_PROTOCOL, length + sizeof(PXE_IP_HDR), 1)) {
                  printf("pxe_tcp_send(): failed to send tcp packet to 0x%x\n", connection->dst_ip);
+		 return (0);
 	}
 	
-	time_t secs;
-	time(&secs);
-	
-	connection->last_sent = secs;
+	connection->last_sent = get_secs();
 																																																	 
-	return (0);	
+	return (1);	
 }
 
-/* alloc_connection() - returns pointer to free connection structure
- * in:
- *	none
- * out:
- *	NULL	- failed to alloc
- *	non NULL- pointer to allocated structure
- */
-PXE_TCP_CONNECTION *
-alloc_connection()
-{
-	if (all_connections == PXE_MAX_TCP_CONNECTIONS)
-		return (NULL);
-		
-	uint16_t	index = 0;
-	
-	for ( ; index < PXE_MAX_TCP_CONNECTIONS; ++index) {
-	
-		if (tcp_connections[index].state == PXE_TCP_CLOSED) {
-			/* if state is closed, it's free structure*/
-			all_connections += 1;
-			return &tcp_connections[index];
-		}
-	}
-	
-	/* NOTE: we must not ever get here */
-	return (NULL);
-}
-
-/* free_connection() - releases connections
- * in:
- *	connection - pointer to connection to release (assuming it's valid connection)
- * out:
- *	none
- */
-void
-free_connection(PXE_TCP_CONNECTION *connection)
-{
-
-	connection->state = PXE_TCP_CLOSED;
-	all_connections -= 1;
-}
 
 /* tcp_await() - await function for some TCP protocol functions (handshaking,
- *    breaking connection). Note, that much of work is done in pxe_tcp_callback()
+ *	breaking connection).
+ * NOTE:
+ *	main work is done in pxe_tcp_callback()
  */
 int
 tcp_await(uint8_t function, uint16_t try_number, uint32_t timeout, void *data)
@@ -359,11 +645,14 @@
 	PXE_TCP_WAIT_DATA *wait_data = (PXE_TCP_WAIT_DATA *)data;
 	
         switch(function) {
-	        case PXE_AWAIT_NEWPACKETS:
+	        case PXE_AWAIT_NEWPACKETS:	/* check current state with needed to wait for */
 		{
 			PXE_TCP_CONNECTION *conn = wait_data->connection;
 			if (wait_data->state == conn->state)
 				return (PXE_AWAIT_COMPLETED);
+				
+			if (conn->state == PXE_TCP_RESETED)
+				return (PXE_AWAIT_BREAK);
 		}
 		break;		
 		
@@ -396,18 +685,21 @@
 	PXE_FILTER_ENTRY	*filter = sock->filter;	
 	PXE_TCP_CONNECTION	*connection = alloc_connection();
 
-	if (alloc_connection == NULL) {
+	if (connection == NULL) {
 		return (0);
 	}
 	
-	pxe_memset(&connection, 0, sizeof(PXE_TCP_CONNECTION));
+	pxe_memset(connection, 0, sizeof(PXE_TCP_CONNECTION));
 			
 	connection->dst_port = filter->src_port;
 	connection->src_port = filter->dst_port;
 	connection->dst_ip = filter->src_ip;
 	connection->next_recv = 0;
-	connection->next_send = 0;
-	connection->sock = sock;
+	
+	/* NOTE: need to make more correct initial number */
+	connection->next_send = (uint32_t)get_secs();
+	
+	connection->filter = filter;
 	connection->recv = &sock->recv_buffer;
 	connection->send = &sock->send_buffer;
 
@@ -418,7 +710,9 @@
 	}
 
 	connection->state = PXE_TCP_SYN_SENT;
-	
+#ifdef PXE_DEBUG_HELL
+	printf("pxe_tcp_connect(): new state - SYN_SENT\n");
+#endif		
 	PXE_TCP_WAIT_DATA wait_data;
 	wait_data.connection = connection;
 	
@@ -428,11 +722,14 @@
 	 * connection will fell in this state in pxe_tcp_callback(),
 	 * after receiving SYN ACK and sending ACK to remote host
 	 */
-	if (!pxe_await(tcp_await, 1, 20000, &wait_data)) { /* failed to get SYN/ACK */
+	if (!pxe_await(tcp_await, 1, PXE_TCP_MSL, &wait_data)) { /* failed to get SYN/ACK */
 	    	free_connection(connection);
 		return (0);
 	}
-	
+
+#ifdef PXE_DEBUG
+	printf("pxe_tcp_connect(): connection established.\n");
+#endif	
 	return (1);
 }
 
@@ -441,11 +738,50 @@
  *	socket - socket
  * out:
  *	0	- failed to disconnect (timeout)
- *	1	- handshaking successful
+ *	1	- disconnect successful
  */
 int
 pxe_tcp_disconnect(PXE_SOCKET *sock)
 {
+	PXE_FILTER_ENTRY	*filter = sock->filter;	
+	
+	if (filter == NULL) {
+		/* NULL filters means there are no connection for socket */
+		return (1);
+	}
+	
+	PXE_TCP_CONNECTION	*connection = filter_to_connection(filter);
+
+	if (connection == NULL) {
+		return (0);
+	}
+	
+	if (!pxe_tcp_send(connection, 0, PXE_TCP_FIN | PXE_TCP_ACK)) {
+		printf("pxe_tcp_connect(): failed to send FIN.\n");
+		free_connection(connection);
+		return (0);
+	}
+
+	connection->state = PXE_TCP_FIN_WAIT1;
+#ifdef PXE_DEBUG_HELL
+	printf("pxe_tcp_disconnect(): new state - FIN_WAIT_1\n");
+#endif	
+	PXE_TCP_WAIT_DATA wait_data;
+	wait_data.connection = connection;
+	
+	wait_data.state = PXE_TCP_TIME_WAIT;
+	
+	/* await TIME_WITE state.
+	 * connection will fell in this state in pxe_tcp_callback(),
+	 * after receiving SYN ACK and sending ACK to remote host
+	 */
+	if (!pxe_await(tcp_await, 1, PXE_TCP_MSL, &wait_data)) { /* failed to get SYN/ACK */
+	    	free_connection(connection);
+		return (0);
+	}
 
-	return (0);
-}+#ifdef PXE_DEBUG
+	printf("pxe_tcp_connect(): connection closed.\n");
+#endif	
+	return (1);
+}

==== //depot/projects/soc2007/taleks-pxe_http/pxe_tcp.h#4 (text+ko) ====

@@ -7,13 +7,18 @@
 
 #include <stdint.h>
 #include <stddef.h>
+
+#include "pxe_buffer.h"
 #include "pxe_ip.h"
-#include "pxe_sock.h"
+#include "pxe_filter.h"
+/* #include "pxe_sock.h" */
 
 /* maximum existing connections at one time */
 #define PXE_MAX_TCP_CONNECTIONS	4
 /* TCP IP stack protocol number*/
 #define PXE_TCP_PROTOCOL	6
+/* maximum segment life time in ms */
+#define PXE_TCP_MSL		60000
 
 /* tcp packet flags */
 #define PXE_TCP_FIN 0x01
@@ -27,9 +32,10 @@
 #define PXE_TCP_STATE_MASK      0x0f
 
 #define PXE_TCP_CLOSED          0x00    /* closed */
+#define PXE_TCP_RESETED         0x0f    /* received RST */
 
 #define PXE_TCP_SYN_SENT        0x01    /* active */
-#define PXE_TCP_SYN_RECIEVED    0x02    /* sent & received SYN */
+#define PXE_TCP_SYN_RECEIVED    0x02    /* sent & received SYN */
 #define PXE_TCP_ESTABLISHED     0x03    /* established connection */
 #define PXE_TCP_CLOSE_WAIT      0x04    /* got FIN, waiting to close */
 #define PXE_TCP_LAST_ACK        0x05    /* got FIN, closing and waiting FIN ACK */
@@ -38,6 +44,7 @@
 #define PXE_TCP_CLOSING         0x07    /* got FIN, sent ACK, waiting FIN ACK */
 #define PXE_TCP_FIN_WAIT2       0x08    /* got FIN ACK */
 #define PXE_TCP_TIME_WAIT       0x09    /* closed, waiting 2MSL*/
+#define PXE_TCP_ALL_STATES      10
 
 typedef struct pxe_tcp_hdr {
 
@@ -61,6 +68,9 @@
 typedef struct pxe_tcp_connecton {
 
     uint8_t	state;
+/*  uint8_t	state_in;
+    uint8_t	state_out;
+ */
     uint32_t	next_recv;
     uint32_t	next_send;
     uint16_t	src_port;
@@ -68,7 +78,7 @@
     uint32_t	dst_ip;
     PXE_BUFFER	*recv;
     PXE_BUFFER	*send;
-    PXE_SOCKET	*sock;
+    PXE_FILTER_ENTRY* filter;
     time_t	last_sent;
     time_t	last_recv;
 } PXE_TCP_CONNECTION;
@@ -79,6 +89,8 @@
     PXE_TCP_CONNECTION		*connection;	/* which connection is monitored */
 } __packed PXE_TCP_WAIT_DATA;
 
+typedef int (*pxe_tcp_state_func)(PXE_TCP_PACKET *tcp_packet, PXE_TCP_CONNECTION *connection);
+
 /* init tcp */
 void pxe_tcp_init();
 
@@ -88,5 +100,8 @@
 /* initates handshaking */
 int pxe_tcp_connect(PXE_SOCKET* sock);
 
+/* initates connection break */
+int pxe_tcp_disconnect(PXE_SOCKET* sock);
+
 
 #endif // PXE_TCP_H_INCLUDED

>>> TRUNCATED FOR MAIL (1000 lines) <<<



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200706211410.l5LEAreH087709>