From owner-p4-projects@FreeBSD.ORG Thu Jun 21 14:10:55 2007 Return-Path: X-Original-To: p4-projects@freebsd.org Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id B390916A46B; Thu, 21 Jun 2007 14:10:54 +0000 (UTC) X-Original-To: perforce@FreeBSD.org Delivered-To: perforce@FreeBSD.org Received: from mx1.freebsd.org (mx1.freebsd.org [69.147.83.52]) by hub.freebsd.org (Postfix) with ESMTP id 5B8B516A421 for ; Thu, 21 Jun 2007 14:10:54 +0000 (UTC) (envelope-from taleks@FreeBSD.org) Received: from repoman.freebsd.org (repoman.freebsd.org [69.147.83.41]) by mx1.freebsd.org (Postfix) with ESMTP id 4AE1713C46C for ; Thu, 21 Jun 2007 14:10:54 +0000 (UTC) (envelope-from taleks@FreeBSD.org) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.13.8/8.13.8) with ESMTP id l5LEAsM5087712 for ; Thu, 21 Jun 2007 14:10:54 GMT (envelope-from taleks@FreeBSD.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.13.8/8.13.8/Submit) id l5LEAreH087709 for perforce@freebsd.org; Thu, 21 Jun 2007 14:10:53 GMT (envelope-from taleks@FreeBSD.org) Date: Thu, 21 Jun 2007 14:10:53 GMT Message-Id: <200706211410.l5LEAreH087709@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to taleks@FreeBSD.org using -f From: Alexey Tarasov To: Perforce Change Reviews Cc: Subject: PERFORCE change 122093 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 21 Jun 2007 14:10:55 -0000 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 #include + +#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) <<<