Archive for June, 2007

First TCP steps.

Thursday, June 21st, 2007

From time of last post there were big enough changes in code.

First of all, await functions support was implemented, so pxe_core_recv_packets() function now is hidden from user code even deeper.

Await functions are functions that are called back by pxe_await()  during simple waiting mechanism. It seems in some modules it made code smaller in lines, but added wait_data structures, which stores current wait related variables. As for TCP module, it seems await function is not useful, but to be similar to all other modules – waiting during handshaking is done using tcp_await()

pxe_await() provides event, current try and wait related data when executes await callback function. So, all await functions are similar and are processing next try, new packets, start of try, end of try events.

DNS client was rewritten a little bit to use await functions mechanism, DHCP client was written to support it from the first lines of code.

After different issues with DHCP protocol simple client was produced to get nameserver, gateway and other useful as well as useless information from DHCP server. May be I need also to add project related DHCP-option, which will specify from which server to download files.

After implementing of major UDP services needed by project, finally TCP module got its first implementation.

As earlier in other protocols, main function for packet processing is callback named simply pxe_tcp_callback(). Main difference from other protocols, especialy UDP – that sockets and filters here firstly used separately and actual work is done in state handlers, not in main callback from start till end.

State handler functions registered now in compile time (and I believe never will be registered in run time, although it’s possible) in state_functions array and each function serves for one TCP connection state handling, if it’s NULL, state is ignored.

Connection is binded more to filter, than to socket structure. This is done to handle correctly TIME_WAIT state, when there is no actually any socket, but any lost packets must be got and forgot.

After testing in soft conditions of LAN it seems active establishing and active closing of connection is done correctly.

Next things to do:

1. resending of packets after timeouts. Adding max segment size option to tcp packet.

2. data send/recv using TCP sockets. Adding pxe_push() function to push data.

3. queueing of received not in correct sequential order packets. Now they are just dropped. It may be useful to move core_packets structure to TCP module for this purpose.

DNS client and etc.

Saturday, June 9th, 2007

Well, first version of DNS client was working about a week ago, but it had one problem: some of domain names were resolved, others were not. In fact, even packets were not returned in reply to sended requests. I’ve checked request making function and found no problems, added verbosity of debug information and found no problems still. After some thoughts, I’ve decided that only lower levels of code may produce such fault. And after some hunting for bugs, one fat error was found at UDP checksum calculation. UDP checksum is calculated for pseudo IP header, UDP header and data. I was calculating this sum separately (for pseudo header and for rest) and after that adding them together. On this stage there was error and routers, which check UDP checksums, just were dropping this packets. When local DNS server was able to resolve cached name (requested by other DNS clients in LAN) it was answering, cause it was not checking sums.

DNS clients (and currently developing DHCP client) are implemented using UDP sockets. For sockets I’ve added cyclic buffers and routines to work with them. UDP callback functions stores datagrams (which passed filters) to socket recv_buffer, heading structure with source address information that is used by pxe_recvfrom(). There is no ability to know if datagram is truncated now. if user recv’ed less then total size of datagram – rest of it is dropped.

Added after this pxe_bind() function required using of socket state. Now it’s not only free/used, but binded/connected/established. Binded socket has only one part of filter set strictly, connected – both source and destination related parts, established is unused, but will be used later with TCP.

DNS client is used in pxe_gethostbyname() function which returns ip4 addr by domain name. Need testing of CNAME handling, if there is no A record in additional or answer section (in this case request resended with CNAME to resolve. In my tests there was no DNS server, which returned somedomain CNAME canonical_domain without leading canonical _domain A ip.ip.ip.ip.). Resolved names are not cached, I don’t think it’s needed for this project. Meanwhile testing, i’ve found funny thing: www.google.ru is CNAME to www.google.com, but google.ru is just A to set of ip’s (by the way DNS client takes first appropriate record as ip resolved for given name). So just three letters and you are logically in other network.

UDP sockets seems working (I’ll test it later on NFS client in pxe.c to be sure there are no bugs). pxe_sendto() moves socket to connected state if it was not binded before (it’s used in DNS client, may be it’s better to change behaviour of this function)

Next to implement:

  • universal waiting mechanism for packets to avoid repeating of cycles in every module. It will be similar to Etherboot or to the uIP await functions.
  • getting default gateway/nameserver from DHCP server. Although, it’s possible to change them manually (‘pxe ns’ and ‘pxe route’ commands in testing module) it must be get by default from DHCP server (also, in DHCP packet may be returned host from which perform downloading of files via http. this need adding user option to packet). For some reasons cached DHCPACK packet data in PXE is filled with zeroes (during downloading of NBP, TFTP has this information, it shows it, but returned by PXE API call data contains no information in options section. May be I need check legacy BOOTP section if it hides needed info instead of filename and servername)
  • start implementing TCP recieve/send packets function.
  • add raw_handlers. Currently, if protocol callback function does not think packet useful for itself, function drops it. raw_handler for protocol will be callback, which will get this packets. it’ll be set by users. It’ll no change currently working code except of return values of callback functions.