PERFORCE change 122093 for review
Alexey Tarasov
taleks at FreeBSD.org
Thu Jun 21 14:10:55 UTC 2007
http://perforce.freebsd.org/chv.cgi?CH=122093
Change 122093 by taleks at 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) <<<
More information about the p4-projects
mailing list