From owner-p4-projects@FreeBSD.ORG Sun Jul 8 14:26:27 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 B25C516A50F; Sun, 8 Jul 2007 14:26:26 +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 76DB616A4FB for ; Sun, 8 Jul 2007 14:26:26 +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 5D43A13C4C2 for ; Sun, 8 Jul 2007 14:26:26 +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 l68EQQ4M006921 for ; Sun, 8 Jul 2007 14:26:26 GMT (envelope-from taleks@FreeBSD.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.13.8/8.13.8/Submit) id l68EQP6S006917 for perforce@freebsd.org; Sun, 8 Jul 2007 14:26:25 GMT (envelope-from taleks@FreeBSD.org) Date: Sun, 8 Jul 2007 14:26:25 GMT Message-Id: <200707081426.l68EQP6S006917@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 123127 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: Sun, 08 Jul 2007 14:26:27 -0000 http://perforce.freebsd.org/chv.cgi?CH=123127 Change 123127 by taleks@taleks_th on 2007/07/08 14:26:13 Overall: removed flags parameter from pxe_ip_send() and related functions, so now every sending function expects that ip/tcp/udp header is allocated by higher level code. pxe_corre_alloc_packet() is unused, will be removed. pxe_buffer: write/read code updated, pxe_buffer_alloc() function now also inits members of PXE_BUFFER structure. Default receive buffer size set to 32768, more optimal for fast connections. There is still problem in tests with data receiving exceeding buffer sizes after closing connection. Most probably corruption of stack during buffer read/write. pxe_connection: add pxe_tcp_check_connection() which sends ACK if have big space in recv buffer and have not receivig packets (situation after small receiving window). pxe_tcp_read() also starts pxe_core_recv_packets() if have big unused space in buffer. pxe_core: added for experimental purposes "exclusive" protocol handling. Which blocks receiving by PXE core other protocols. Usefull when remote host is agreessively sends packets and it's MAC address is unknown, in some cases this lead to infinite cyce of ARP packets sending. pxe_segment: adde pxe_resend_drop_same() function to remove from resending queue packets with same sequence number, in most cases with same flags but different ack number. Some updates in checks of parameters of functions to be more accurate with NULL pointer. pxe_sock: made pxe_recv() behaviour more similar to blocking function. pxe_tcp: mainly tcp_process_7() changed to update correctly FIN & SYN segments sequence numbers. Also pxe_tcp_syssend() modified to drop same packets. Affected files ... .. //depot/projects/soc2007/taleks-pxe_http/pxe_arp.c#9 edit .. //depot/projects/soc2007/taleks-pxe_http/pxe_await.h#2 edit .. //depot/projects/soc2007/taleks-pxe_http/pxe_buffer.c#4 edit .. //depot/projects/soc2007/taleks-pxe_http/pxe_buffer.h#4 edit .. //depot/projects/soc2007/taleks-pxe_http/pxe_connection.c#5 edit .. //depot/projects/soc2007/taleks-pxe_http/pxe_connection.h#4 edit .. //depot/projects/soc2007/taleks-pxe_http/pxe_core.c#18 edit .. //depot/projects/soc2007/taleks-pxe_http/pxe_core.h#14 edit .. //depot/projects/soc2007/taleks-pxe_http/pxe_icmp.c#9 edit .. //depot/projects/soc2007/taleks-pxe_http/pxe_ip.c#9 edit .. //depot/projects/soc2007/taleks-pxe_http/pxe_ip.h#7 edit .. //depot/projects/soc2007/taleks-pxe_http/pxe_segment.c#5 edit .. //depot/projects/soc2007/taleks-pxe_http/pxe_segment.h#4 edit .. //depot/projects/soc2007/taleks-pxe_http/pxe_sock.c#12 edit .. //depot/projects/soc2007/taleks-pxe_http/pxe_sock.h#10 edit .. //depot/projects/soc2007/taleks-pxe_http/pxe_tcp.c#7 edit .. //depot/projects/soc2007/taleks-pxe_http/pxe_udp.c#6 edit .. //depot/projects/soc2007/taleks-pxe_http/pxe_udp.h#4 edit Differences ... ==== //depot/projects/soc2007/taleks-pxe_http/pxe_arp.c#9 (text+ko) ==== @@ -63,12 +63,23 @@ const MAC_ADDR * pxe_arp_table_search(uint32_t ip) { +#ifdef PXE_DEBUG_HELL + printf("pxe_arp_table_search(): started\n"); +#endif int entry = 0; for (; entry < MAX_ARP_ENTRIES + 1; ++entry) { - if (arp_table[entry].ip4.ip == ip) - return (const MAC_ADDR *)&(arp_table[entry].mac); + if (arp_table[entry].ip4.ip == ip) { + + uint8_t *mac = &arp_table[entry].mac[0]; +#ifdef PXE_DEBUG_HELL + printf("pxe_arp_table_search(): %2x:%2x:%2x:%2x:%2x:%2x\n", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5] + ); +#endif + return (const MAC_ADDR *)mac; + } } return (NULL); @@ -319,6 +330,8 @@ if (res != NULL) return (res); + pxe_core_exclusive(PXE_PROTOCOL_ARP); + PXE_ARP_WAIT_DATA wait_data; wait_data.ip = ip; @@ -327,5 +340,7 @@ if (!pxe_await(pxe_arp_await, PXE_MAX_ARP_TRY, PXE_TIME_TO_DIE, &wait_data)) { } + pxe_core_exclusive(0); + return (wait_data.mac); } ==== //depot/projects/soc2007/taleks-pxe_http/pxe_await.h#2 (text+ko) ==== @@ -18,8 +18,8 @@ #define PXE_AWAIT_NEXTTRY 0x03 /* continue with next try */ #define PXE_AWAIT_BREAK 0x04 /* wait ended with failure */ -#define TIME_DELTA_MS 100 -#define TIME_DELTA 100000 +#define TIME_DELTA_MS 10 +#define TIME_DELTA 10000 /* universal waiting function */ int pxe_await(pxe_await_func func, uint16_t try_counter, uint32_t timeout, void *data); ==== //depot/projects/soc2007/taleks-pxe_http/pxe_buffer.c#4 (text+ko) ==== @@ -13,7 +13,12 @@ pxe_buffer_write(PXE_BUFFER *buf, const void *from, uint16_t size) { uint16_t to_write = (size < buf->bufleft) ? size : buf->bufleft; - + +#ifdef PXE_DEBUG_HELL + printf("pxe_buffer_write(): fstart %d, fend %d, bufleft %d (of %d), to_write %d (%d)\n", + buf->fstart, buf->fend, buf->bufleft, buf->bufsize, to_write, size); +#endif + if (to_write == 0) /* no space left*/ return (0); @@ -26,31 +31,35 @@ } else {/* may be need to place, using two memcpy operations */ - /* right part of space */ + /* right part of buffer */ uint16_t part1 = buf->bufsize - buf->fstart; - uint16_t part2 = 0; - + /* left part of buffer */ + uint16_t part2 = to_write - part1; + + if (part1) + pxe_memcpy(from, buf->data + buf->fstart, part1); + if (part1 >= to_write) { - pxe_memcpy(from, buf->data + buf->fstart, to_write); buf->fstart += to_write; + + if (buf->fstart > buf->bufsize) { + printf("pxe_buffer_write(): internal error! fstart = %d", buf->fstart); + } } else { - pxe_memcpy(from, buf->data + buf->fstart, part1); - /* left part of space */ - part2 = to_write - part1; pxe_memcpy(from + part1, buf->data, part2); - buf->fstart = part2; + buf->fstart = part2; } + #ifdef PXE_DEBUG_HELL - printf("pxe_buffer_write(): fstart %d, fend %d, bufleft %d (of %d)\n\tpart1 %d, part2 %d, to_write %d (%d)\n", - buf->fstart, buf->fend, buf->bufleft, buf->bufsize, part1, part2, to_write, size); -#endif + printf("pxe_buffer_write(): fstart %d, fend %d, bufsize %d\n\tpart1 %d, part2 %d, to_write %d (%d)\n", + buf->fstart, buf->fend, buf->bufsize, part1, part2, to_write, size); +#endif } - buf->bufleft -= to_write; -#ifdef PXE_DEBUG_HELL - printf("bufleft %d (-%d)\n", buf->bufleft, to_write); +#ifdef PXE_DEBUG + printf("pxe_buffer_write(): bufleft %d (-%d)\n", buf->bufleft, to_write); #endif return (to_write); } @@ -58,7 +67,7 @@ /* pxe_buffer_read() - reades data from buffer, if possible * in: * buf - pointer to buffer structure - * to - pointer to data to read to + * to - pointer to data to read to, if NULL data is read but not placed anywhere * size - size of data buffer * out: * actual count of read bytes @@ -77,36 +86,31 @@ uint16_t fend = buf->fend; uint16_t bufsize = buf->bufsize; - if (fstart < fend) { /* two cases */ - - if (fend != bufsize) { /* case one: |**s...e***| */ - /* right part of buffer */ - uint16_t part1 = bufsize - fend; - /* left part of buffer */ - uint16_t part2 = to_read - part1; + if (fstart <= fend) { /* two cases handling: |*s...e**|, |***se***| */ + /* right part of buffer */ + uint16_t part1 = bufsize - fend; + /* left part of buffer */ + uint16_t part2 = to_read - part1; - if (to != NULL) { - pxe_memcpy(buf->data + fend, to, part1); + if (part1 && (to != NULL) ) + pxe_memcpy(buf->data + fend, to, part1); + + if (part1 >= to_read) { + buf->fend += to_read; + } else { + if (to != NULL) pxe_memcpy(buf->data, to + part1, part2); - } - - buf->fend = part2; + + buf->fend = part2; + } - } else { /* case two: |***s.....e| */ - - if (to != NULL) - pxe_memcpy(buf->data, to, to_read); + } else { /* third case: |..e**s...| */ - buf->fend = to_read; - } - - } else { /* third case: |..e**s...|*/ if (to != NULL) pxe_memcpy(buf->data + buf->fend, to, to_read); buf->fend += to_read; - } - + } buf->bufleft += to_read; @@ -143,14 +147,18 @@ pxe_buffer_memalloc(PXE_BUFFER *buffer, uint16_t size) { - if (buffer->data != NULL) { /* don't alloc nothing, if mem already allocated */ - return (0); + if (buffer->data == NULL) { /* alloc if not already allocated */ + buffer->data = pxe_alloc(size); + + if (buffer->data == NULL) + return (0); } - buffer->data = pxe_alloc(size); - - if (buffer->data == NULL) - return (0); + + buffer->bufsize = size; + buffer->bufleft = size; + buffer->fstart = 0; + buffer->fend = size; return (1); } ==== //depot/projects/soc2007/taleks-pxe_http/pxe_buffer.h#4 (text+ko) ==== @@ -4,7 +4,7 @@ #include /* buffer size choosed by default for sending/recieving*/ -#define PXE_DEFAULT_RECV_BUFSIZE 8192 +#define PXE_DEFAULT_RECV_BUFSIZE 32768 #define PXE_DEFAULT_SEND_BUFSIZE 4096 /* pxe_buffer - buffer related information */ ==== //depot/projects/soc2007/taleks-pxe_http/pxe_connection.c#5 (text+ko) ==== @@ -221,26 +221,26 @@ if (connection->state == PXE_TCP_CLOSED) { /* already closed */ #ifdef PXE_DEBUG printf("pxe_tcp_disconnect(): connection already is closing.\n"); -#endif +#endif return (1); } /* if connection in established state - initiate active close */ - if (connection->state == PXE_TCP_ESTABLISHED) { - if (!pxe_tcp_syssend(connection, PXE_TCP_FIN | PXE_TCP_ACK)) { - printf("pxe_tcp_disconnect(): failed to send FIN.\n"); - free_connection(connection); - return (0); - } + if (!pxe_tcp_syssend(connection, PXE_TCP_FIN | PXE_TCP_ACK)) { + printf("pxe_tcp_disconnect(): failed to send FIN.\n"); + free_connection(connection); + return (0); } - /* update sequence number */ connection->next_send += 1; - connection->state = PXE_TCP_FIN_WAIT1; + + if (connection->state == PXE_TCP_ESTABLISHED) + connection->state = PXE_TCP_FIN_WAIT1; + connection->state_out = PXE_TCP_FIN; #ifdef PXE_DEBUG printf("pxe_tcp_disconnect(): new state - FIN_WAIT_1\n"); -#endif +#endif PXE_TCP_WAIT_DATA wait_data; wait_data.connection = connection; @@ -248,7 +248,7 @@ /* await TIME_WITE state. * connection will fell in this state in pxe_tcp_callback(), - * TODO: add waiting of TCP_CLOSED also + * TODO: add waiting of LAST_ACK also */ if (!pxe_await(tcp_await, 5, PXE_TCP_MSL / 5, &wait_data)) { /* failed to get to TIME_WAIT state */ free_connection(connection); @@ -265,7 +265,7 @@ #ifdef PXE_DEBUG printf("pxe_tcp_disconnect(): connection closed.\n"); -#endif +#endif return (1); } @@ -404,8 +404,8 @@ if (result != 0) { /* if receive window was zero and now is big enough, notify remote host */ - if ( (recv_buffer->bufleft > PXE_DEFAULT_RECV_BUFSIZE / 4) && - (connection->winlock == 1) ) + if ( (connection->winlock == 1) && + (recv_buffer->bufleft > PXE_DEFAULT_RECV_BUFSIZE / 4)) { if (!pxe_tcp_syssend(connection, PXE_TCP_ACK)) { printf("pxe_tcp_read(): failed to notify remote host about window.\n"); @@ -415,8 +415,9 @@ } } - /* process new packets if there are any */ - pxe_core_recv_packets(); + /* process new packets if too low data in buffer */ + if (recv_buffer->bufleft > recv_buffer->bufsize / 2) + pxe_core_recv_packets(); return (result); } @@ -468,6 +469,51 @@ return (1); } +/* pxe_tcp_check_connection() - checks connections state by sending ACK, + * used e,g, to notify remote host about enough window to recv + * in: + * sock - TCP socket to check connection for + * out: + * 0 - failed + * 1 - success + */ +int +pxe_tcp_check_connection(PXE_SOCKET *sock) +{ +#ifdef PXE_DEBUG + printf("pxe_tcp_check_connection(): started.\n"); +#endif + PXE_TCP_CONNECTION *connection = filter_to_connection(sock->filter); + + if (connection == NULL) { + printf("pxe_tcp_check_connection(): no connection for filter 0x%x (socket: 0x%x).\n", + sock->filter, sock + ); + return (0); + } + + if (connection->state != PXE_TCP_ESTABLISHED) { + printf("pxe_tcp_check_connection(): connection 0x%x is not in established state(%d).\n", + connection, connection->state + ); + return (0); /* connection not in established state, ignore available data */ + } + + PXE_BUFFER *buffer = connection->recv; + + /* send ACK ony if we place for one segment at least */ + if (buffer->bufleft < buffer->bufsize / 2) { + return (0); + } + + if (!pxe_tcp_syssend(connection, PXE_TCP_ACK)) { + printf("pxe_tcp_check_connection(): failed to send ACK.\n"); + return (0); + } + + return (1); +} + void pxe_connection_stats() { ==== //depot/projects/soc2007/taleks-pxe_http/pxe_connection.h#4 (text+ko) ==== @@ -89,4 +89,7 @@ /* pushes current segment data */ int pxe_tcp_push(PXE_SOCKET *sock); +/* checks connection, by sending ACK */ +int pxe_tcp_check_connection(PXE_SOCKET *sock); + #endif ==== //depot/projects/soc2007/taleks-pxe_http/pxe_core.c#18 (text+ko) ==== @@ -22,6 +22,7 @@ #define PXE_BUFFER_SIZE 0x1000 static uint8_t scratch_buffer[PXE_BUFFER_SIZE]; static uint8_t data_buffer[PXE_BUFFER_SIZE]; +static uint8_t exclusive_protocol = 0; static pxenv_t *pxenv = NULL; /* PXENV+ */ static pxe_t *pxe = NULL; /* !PXE */ static BOOTPLAYER bootplayer; /* PXE Cached information. */ @@ -425,7 +426,7 @@ * 1 - success * 0 - failed */ -int +static int pxe_core_call(int func) { #ifdef PXE_DEBUG_HELL @@ -520,6 +521,7 @@ if (undi_send->Status != 0) { printf("%d: pxe_core_transmit(): failed with status 0x%x\n", tryCount, undi_send->Status); + delay(100); continue; } @@ -541,7 +543,7 @@ * 0 - failed * 1 - success */ -int +static int pxe_core_get_packet(int func, t_PXENV_UNDI_ISR *undi_isr ) { #ifdef PXE_DEBUG_HELL @@ -586,7 +588,7 @@ if (count == 10) return (0); - delay(1000); /* wait, may be it will be not busy later */ + delay(10); /* wait, may be it will be not busy later */ continue; } @@ -682,11 +684,23 @@ ++packets_dropped; drop_flag = 1; /* clear queue, receiving all frames of packet */ } + + /* experimental: to avoid resendings of ip packets for unknown MAC*/ + if (exclusive_protocol && (protocol != exclusive_protocol)) { +#ifdef PXE_DEBUG + printf("recv_packets(): dropping packet, not exclusive protocol (%d != %d).\n", + protocol, exclusive_protocol + ); +#endif + ++packets_dropped; + drop_flag = 1; /* clear queue, receiving all frames of packet */ + } /* sanity check */ if (frame_size < PXE_BUFFER_SIZE) { pxe_core_copy( undi_isr->Frame.segment, undi_isr->Frame.offset, VTOPSEG(data_buffer), VTOPOFF(data_buffer), frame_size); +/* pxe_memcpy(PTOV(undi_isr->Frame.segment * 16 + undi_isr->Frame.offset), data_buffer, frame_size); */ } else { printf("pxe_core_recv_packets(): not enough buffer size (%d bytes) for frame size %d bytes.\n", PXE_BUFFER_SIZE, frame_size); @@ -916,6 +930,22 @@ core_protocol[proto]=proc; } +/* pxe_core_exclusive() - sets protocol exclusive when receiving packets + * in: + * proto - IP protocol number + * out: + * none + */ +void +pxe_core_exclusive(uint8_t proto) +{ +#ifdef PXE_DEBUG_HELL + printf("pxe_core_exlusive(): %d protocol.\n", proto); +#endif + exclusive_protocol = proto; +} + + /* pxe_get_mymac() - returns NIC MAC * in: * none ==== //depot/projects/soc2007/taleks-pxe_http/pxe_core.h#14 (text+ko) ==== @@ -106,6 +106,9 @@ /* registers protocol */ void pxe_core_register(uint8_t ip_proto, pxe_protocol_call proc); +/* set this protocol exclusive, other packets are ignored */ +void pxe_core_exclusive(uint8_t proto); + /* returns NIC MAC */ const MAC_ADDR *pxe_get_mymac(); ==== //depot/projects/soc2007/taleks-pxe_http/pxe_icmp.c#9 (text+ko) ==== @@ -118,7 +118,7 @@ reply_icmphdr->checksum = ~pxe_ip_checksum(reply_icmphdr, sizeof(PXE_ICMP_HDR) + data_size); - if (!pxe_ip_send(pack->data, iphdr->src_ip, PXE_ICMP_PROTOCOL, pack->data_size, 1) && echo_flags) { + if (!pxe_ip_send(pack->data, iphdr->src_ip, PXE_ICMP_PROTOCOL, pack->data_size) && echo_flags) { printf("pxe_ping(): failed to send echo reply.\n"); } @@ -193,7 +193,7 @@ icmphdr->checksum = ~(pxe_ip_checksum(icmphdr, sizeof(PXE_ICMP_HDR) + 32)); - if (!pxe_ip_send(data, ip->ip, PXE_ICMP_PROTOCOL, pack_size, 1) && echo_flags) { + if (!pxe_ip_send(data, ip->ip, PXE_ICMP_PROTOCOL, pack_size) && echo_flags) { printf("pxe_ping(): failed to send echo reply.\n"); } ==== //depot/projects/soc2007/taleks-pxe_http/pxe_ip.c#9 (text+ko) ==== @@ -350,54 +350,39 @@ * dst_ip - destination IP address * protocol- IP stack protocol (e.g. UDP) * size - size of data buffer - * flags - 1 if space reserved in buffer for IP header, 0 - otherwise * out: * 0 - failed * 1 - success */ int -pxe_ip_send(void *data, uint32_t dst_ip, uint8_t protocol, uint16_t size, int flags) +pxe_ip_send(void *data, uint32_t dst_ip, uint8_t protocol, uint16_t size) { - uint16_t pack_size = (flags == 0) ? size + sizeof(PXE_IP_HDR) : size; - PXE_PACKET pack; - PXE_PACKET* pack_out = &pack; + PXE_PACKET pack_out; int status = 0; - /* flags == 0: there is no space for ip header in user buffer - * flags == 1: user manually allocated space for ip header - */ - if (flags == 0) { - pack_out = pxe_core_alloc_packet(pack_size); - - if (pack_out == NULL) { /* failed to allocate packet*/ - return (0); - } - - /* copying user data */ - pxe_memcpy(data, pack_out->data + sizeof(PXE_IP_HDR), size); - } else { + pack_out.data = data; + pack_out.data_size = size; - pack_out->data = data; - pack_out->data_size = size; - } - - /* creating ip header */ - pxe_create_ip_hdr(pack_out->data, dst_ip, protocol, pack_size, 0); + pxe_create_ip_hdr(pack_out.data, dst_ip, protocol, size, 0); - /* setting pxe_core packet parameters*/ - pack_out->flags = (dst_ip != PXE_IP_BCAST) ? PXE_SINGLE : PXE_BCAST; - pack_out->protocol = PXE_PROTOCOL_IP; + /* setting pxe_core packet parameters */ + pack_out.flags = (dst_ip != PXE_IP_BCAST) ? PXE_SINGLE : PXE_BCAST; + pack_out.protocol = PXE_PROTOCOL_IP; - /* find gateway or direct MAC*/ + /* find gateway or direct MAC */ uint32_t ip_to_send = dst_ip; - if (pack_out->flags != PXE_BCAST) { + if (pack_out.flags != PXE_BCAST) { ip_to_send = pxe_ip_route_find(dst_ip); - pack_out->dest_mac = pxe_arp_ip4mac(ip_to_send); - } + pack_out.dest_mac = pxe_arp_ip4mac(ip_to_send); + } +#ifdef PXE_DEBUG_HELL + printf("pxe_ip_send(): %d proto, 0x%x, %s.\n", protocol, pack_out.dest_mac, + pack_out.flags == PXE_SINGLE ? "single" : "bcast"); +#endif - if ( (pack_out->flags != PXE_BCAST) && (pack_out->dest_mac == NULL) ) { + if ( (pack_out.flags != PXE_BCAST) && (pack_out.dest_mac == NULL) ) { /* MAC is not found for destination ip or gateway */ #ifdef PXE_DEBUG PXE_IPADDR dst; @@ -411,7 +396,7 @@ ); #endif } else { - if (!pxe_core_transmit(pack_out)) { + if (!pxe_core_transmit(&pack_out)) { #ifdef PXE_DEBUG printf("pxe_ip_send(): failed to send packet.\n"); #endif @@ -420,9 +405,5 @@ } } - if (flags == 0) { - pxe_core_commit(pack_out); - } - return (status); } ==== //depot/projects/soc2007/taleks-pxe_http/pxe_ip.h#7 (text+ko) ==== @@ -79,7 +79,7 @@ int pxe_ip_route_default(uint32_t gw); /* sends ip packet */ -int pxe_ip_send(void *data, uint32_t dst_ip, uint8_t protocol, uint16_t size, int flags); +int pxe_ip_send(void *data, uint32_t dst_ip, uint8_t protocol, uint16_t size); /* show route table */ void pxe_ip_route_stat(); ==== //depot/projects/soc2007/taleks-pxe_http/pxe_segment.c#5 (text+ko) ==== @@ -84,6 +84,9 @@ void *data = NULL; PXE_TCP_QUEUED_SEGMENT *segment = NULL; + if (connection->send == NULL) + return (NULL); + for ( ; block_index < PXE_TCP_BLOCK_COUNT; ++block_index) { /* start of block */ @@ -168,7 +171,7 @@ pxe_resend_check(PXE_TCP_CONNECTION *connection) { #ifdef PXE_DEBUG - printf("pxe_resend_check(): started.\n"); + printf("pxe_resend_check(): started, state %d.\n", connection->state); #endif PXE_BUFFER *buffer = connection->send; void *data = buffer->data; @@ -203,6 +206,10 @@ segment->trys += 1; segment->resend_at += PXE_RESEND_TIME * segment->trys; + if (segment->trys == PXE_RESEND_TRYS) { + /* TODO: need to break connection */ + } + tcp_update_segment(connection, segment); pxe_tcp_send_segment(connection, segment); @@ -226,6 +233,10 @@ /* resend later, with more delay with every try */ segment->trys += 1; segment->resend_at += PXE_RESEND_TIME * segment->trys; + + if (segment->trys == PXE_RESEND_TRYS) { + /* TODO: need to break connection */ + } tcp_update_segment(connection, segment); pxe_tcp_send_segment(connection, segment); @@ -239,6 +250,72 @@ } } +/* pxe_resend_drop_same() - removes from resend queue older segments with same + * sequence number to avoid duplicate resending of same ACKs and etc. + * in: + * connection - connection to update segments for + * segment - segment to check with + * out: + * none + */ +void +pxe_resend_drop_same(PXE_TCP_CONNECTION *connection, PXE_TCP_QUEUED_SEGMENT *new_segment) +{ +#ifdef PXE_DEBUG + printf("pxe_resend_drop_same(): started.\n"); +#endif + uint32_t drop_seq = new_segment->seq; + PXE_BUFFER *buffer = connection->send; + void *data = buffer->data; + int block_index = 0; + PXE_TCP_QUEUED_SEGMENT *segment = NULL; + uint8_t *buf_blocks = connection->buf_blocks; + + for ( ; block_index < PXE_TCP_BLOCK_COUNT; ++block_index) { + + /* block is used exclusevely by one "big" packet, skip this */ + if (buf_blocks[block_index] == PXE_TCP_BLOCK_EXCLUSIVE) { + + continue; + } + + if (buf_blocks[block_index] == PXE_TCP_BLOCK_FREE) + continue; /* block is unused */ + + /* pointer to head chunk of block */ + data = buffer->data + block_index * PXE_TCP_CHUNK_COUNT * connection->chunk_size; + + segment = (PXE_TCP_QUEUED_SEGMENT *)data; + + if (segment == new_segment) + continue; + + /* block is dirty, need to check chunks manually */ + int chunk_index = 0; + + for ( ; chunk_index < PXE_TCP_CHUNK_COUNT; ++chunk_index) { + + if (segment == new_segment) /* skip segment if it's new_segment */ + continue; + + if ( (segment->status != PXE_SEGMENT_FREE) && + (segment->seq == drop_seq) ) + { /* this segment is renewed by new segment */ +#ifdef PXE_DEBUG_HELL + printf("pxe_resend_drop_same(): dropping chunk %d#%d.\n", + chunk_index, block_index + ); +#endif + tcp_segment_free(connection, block_index, segment); + } + + /* point segment to next chunk */ + data += connection->chunk_size; + segment = (PXE_TCP_QUEUED_SEGMENT *)data; + } + } +} + /* pxe_resend_update() - update segments that were acked * in: * connection - connection to update segments for @@ -273,7 +350,7 @@ continue; /* it was not ever sent yet */ if (connection->una >= segment->seq) { /* segment was acked, release it */ -#ifdef PXE_DEBUG +#ifdef PXE_DEBUG_HELL printf("pxe_resend_update(): block %d acked.\n", block_index); #endif tcp_segment_free(connection, block_index, segment); @@ -303,9 +380,22 @@ } } +/* pxe_start_segment() - fills initial data in headers for provided segment + * in: + * connection - connection to update segments for + * segment - segment to start + * add_options - 1 if add default options (mss), 0 - do not add anything + * out: + * none + */ void tcp_start_segment(PXE_TCP_CONNECTION *connection, PXE_TCP_QUEUED_SEGMENT *segment, int add_options) { + if (segment == NULL) { + printf("tcp_start_segment(): segment = NULL.\n"); + return; + } + PXE_TCP_PACKET *tcp_packet = (PXE_TCP_PACKET *)(segment + 1); /* reserving 8 bytes for options */ @@ -340,9 +430,22 @@ segment->seq = connection->next_send; } +/* pxe_finish_segment() - finishes segmentm calculates checksums and fills sequence numbers + * in: + * connection - connection to update segments for + * segment - segment to start + * tcp_flags - flags of header (PXE_TCP_...) + * out: + * none + */ void tcp_finish_segment(PXE_TCP_CONNECTION *connection, PXE_TCP_QUEUED_SEGMENT *segment, uint8_t tcp_flags) { + if (segment == NULL) { + printf("tcp_finish_segment(): segment = NULL.\n"); + return; + } + PXE_TCP_PACKET *tcp_packet = (PXE_TCP_PACKET *)(segment + 1); uint16_t length = segment->size - sizeof(PXE_IP_HDR); @@ -393,9 +496,21 @@ #endif } +/* pxe_update_segment() - updates segment at resending, recalcs checksum for updated header + * in: + * connection - connection to update segments for + * segment - segment to start + * out: + * none + */ void tcp_update_segment(PXE_TCP_CONNECTION *connection, PXE_TCP_QUEUED_SEGMENT *segment) { + if (segment == NULL) { + printf("tcp_update_segment(): segment = NULL.\n"); + return; + } + PXE_TCP_PACKET *tcp_packet = (PXE_TCP_PACKET *)(segment + 1); uint16_t length = segment->size - sizeof(PXE_IP_HDR); @@ -450,9 +565,14 @@ int pxe_tcp_send_segment(PXE_TCP_CONNECTION *connection, PXE_TCP_QUEUED_SEGMENT *segment) { + if (segment == NULL) { + printf("pxe_tcp_send_segment(): segment = NULL.\n"); + return (0); + } + PXE_TCP_PACKET *tcp_packet = (PXE_TCP_PACKET *)(segment + 1); - if (!pxe_ip_send(tcp_packet, connection->dst_ip, PXE_TCP_PROTOCOL, segment->size, 1)) { + if (!pxe_ip_send(tcp_packet, connection->dst_ip, PXE_TCP_PROTOCOL, segment->size)) { printf("pxe_tcp_send_segment(): failed to send tcp packet to 0x%x\n", connection->dst_ip); return (0); } @@ -497,7 +617,6 @@ printf(" %d bytes.\n", length); #endif - /* check received packets */ return (1); } ==== //depot/projects/soc2007/taleks-pxe_http/pxe_segment.h#4 (text+ko) ==== @@ -11,8 +11,10 @@ #define PXE_SEGMENT_USED 0x01 /* segment is filled with data, sent but not ACKed yet */ #define PXE_SEGMENT_SENT 0x02 -/* default resend time if not acked in seconds */ -#define PXE_RESEND_TIME 5 +/* default resend time if not acked, in seconds */ +#define PXE_RESEND_TIME 1 +/* default resend trys */ +#define PXE_RESEND_TRYS 5 /* how much blocks in buffer */ #define PXE_TCP_BLOCK_COUNT 8 @@ -56,6 +58,9 @@ /* updates resend queue, removes ACKed segments */ void pxe_resend_update(PXE_TCP_CONNECTION *connection); +/* removes segments that are dublicates or old versions of new segment */ +void pxe_resend_drop_same(PXE_TCP_CONNECTION *connection, PXE_TCP_QUEUED_SEGMENT *segment); + /* destroys resend queue */ void pxe_resend_free(PXE_TCP_CONNECTION *connection); ==== //depot/projects/soc2007/taleks-pxe_http/pxe_sock.c#12 (text+ko) ==== @@ -94,11 +94,6 @@ return (-1); } - sbuf->bufsize = PXE_DEFAULT_SEND_BUFSIZE; - sbuf->bufleft = PXE_DEFAULT_SEND_BUFSIZE; - sbuf->fstart = 0; - sbuf->fend = sbuf->bufsize; - if (!pxe_buffer_memalloc(rbuf, PXE_DEFAULT_RECV_BUFSIZE)) { pxe_buffer_memfree(sbuf); @@ -106,11 +101,6 @@ return (-1); } - rbuf->bufsize = PXE_DEFAULT_RECV_BUFSIZE; - rbuf->bufleft = PXE_DEFAULT_RECV_BUFSIZE; - rbuf->fstart = 0; - rbuf->fend = rbuf->bufsize; - return (socket); } @@ -365,7 +355,7 @@ printf("pxe_sendto(): %8x:%d -> %8x:%d, size = %d bytes.\n", pxe_get_ip32(PXE_IP_MY), lport, ip, port, size); #endif - if (!pxe_udp_send(udp_pack, ip, port, lport, size + sizeof(PXE_UDP_PACKET), 1)) { + if (!pxe_udp_send(udp_pack, ip, port, lport, size + sizeof(PXE_UDP_PACKET))) { printf("pxe_sendto(): failed to send data.\n"); return (-1); } @@ -498,19 +488,52 @@ PXE_SOCKET *sock = &pxe_sockets[socket]; PXE_FILTER_ENTRY *filter = sock->filter; + + if ( (filter->protocol != PXE_UDP_PROTOCOL) && + (filter->protocol != PXE_TCP_PROTOCOL) ) + { + printf("pxe_recv(): only TCP and UDP sockets are implemented.\n"); + return (-1); + } - if (filter->protocol == PXE_UDP_PROTOCOL) { + uint32_t timer = 0; + uint32_t check_timer = 0; + + int result = 0; - return pxe_udp_read(sock, tobuf, buflen); + while (1) { - } else if (filter->protocol == PXE_TCP_PROTOCOL) { + if (filter->protocol == PXE_UDP_PROTOCOL) { - return pxe_tcp_read(sock, tobuf, buflen); - } + result = pxe_udp_read(sock, tobuf, buflen); + + } else { - printf("pxe_recv(): only TCP and UDP sockets are implemented.\n"); + result = pxe_tcp_read(sock, tobuf, buflen); + + } + + if (result != 0) + break; + + if (timer > PXE_SOCKET_TIMEOUT * 1000) + break; + + if (filter->protocol == PXE_TCP_PROTOCOL) { - return (-1); + if (check_timer > PXE_SOCKET_CHECK_TIMEOUT) { + check_timer = 0; + pxe_tcp_check_connection(sock); + } + } + + check_timer += 10; + timer += 10; + /* idle 10 ms */ + delay(10000); + } + + return (result); } /* pxe_recvfrom() - receive data to socket with information about sender ==== //depot/projects/soc2007/taleks-pxe_http/pxe_sock.h#10 (text+ko) ==== @@ -12,6 +12,10 @@ #define PXE_DEFAULT_SOCKETS 8 /* default count of waiting queue */ #define PXE_DEFAULT_WAITCOUNT 3 +/* socket timeout when receiving data, in seconds */ +#define PXE_SOCKET_TIMEOUT 30 +/* timeout, after that force connection checking, in milliseconds */ +#define PXE_SOCKET_CHECK_TIMEOUT 200 /* socket states */ #define PXE_SOCKET_FREE 0x0 /* socket unused and free for allocating */ #define PXE_SOCKET_USED 0x1 /* socket structure used */ ==== //depot/projects/soc2007/taleks-pxe_http/pxe_tcp.c#7 (text+ko) ==== @@ -109,6 +109,12 @@ int tcp_is_acceptable(PXE_TCP_CONNECTION *connection, PXE_TCP_PACKET *tcp_packet, uint16_t seglen) { + if (connection == NULL) + return (0); + >>> TRUNCATED FOR MAIL (1000 lines) <<<