Hi folks,
Here's an update for the ICMP project. The diff is attached. Since it's
already in late August, I think this might be much close to my final HCD
job. But I'm still working. I'm listing my achievements together with
unfinished stuff below.
1. ICMP error handling
Error handling are uniformly done by calling the error_reply() hook of the
domain protocol (i.e., ipv4), which delegates the actual job to the icmp
module (icmp_error_reply, more exactly). Currently I take care of the
following 4 kinds of errors as per RFC1122:
* Destination Unreachable, Code 2 (Protocol Unreachable) and 3 (Port
Unreachable)
Code 2 is triggered inside ipv4; while Code 3 is found in the udp
module.
* Time Exceeded, Code 1 (in Fragment Reassembly)
We call the error_reply hook in the StaleTimer() callback when the
reassembly timer
expires.
* Parameter Problem
* Source Quench
Source Quench errors are reported if a B_NO_MEMORY error occurs while adding
an IP fragment or if the buffer size exceeds 90% (a defined macro) of the
buffer capacity (in raw_receive_data() of the ipv4 module). I'm not sure
whether it's right.
All these errors are described in RFC792&1122 only to be generated on hosts
but not gateways. ICMP extensions beyond RFC792 such as Address Mask
Request/Response as in RFC950 are not supported.
Back to the implementation of icmp_error_reply(). It constructs the ICMP
header and asks the domain module to send the ICMP response out. The
icmp_encode()/icmp_decode() functions are used here to encode/decode the
ICMP types and codes. I don't think this is a good approach either, but for
now let's keep it this way. Since ICMP messages are required to carry the
original IP header and first 8 bytes of the datagram, a duplicated copy of
the original IP header is preserved in the net_buffer struct as the data
passes ipv4_receive_data().
2. ICMP error propagation
Error propagation is accomplished by the error_received hooks. I have
expanded the icmp_receive_data() function implementation to make it support
the 11 types of ICMP messages mentioned in RFC792.
For non-error messages, I handled Timestamp Request and Echo Request
(originally supported) and ignored other types. For error messages, all
errors are propagated to the upper protocols by invoking error_received() on
the domain protocol except Redirect. To respond to a Redirect message, I
need to update the local routing information accordingly but I don't know
how to do this right now.
ipv4_error_received() then dispatches the error to the right upper protocol
by extracting the IP header carried in the ICMP message data. The transport
protocol modules (tcp and udp) have to react properly upon reception of
certain ICMP errors.
ICMP message handling in TCP and UDP is implemented as defined in rfc1122.
If an error needs to be reported to the application layer, a net_socket
pointer is first obtained by looking up the endpoint table. Then I call
gSocketModule->notify(socket, B_SELECT_ERROR, errno) to report the error.
PMTU discovery documented in rfc1191 is not supported yet. But I left an
empty pmtu_discovery() stub there for future work.
3. Test
As said, the unit test cases are missing. Unfortunately the most terrible
thing is that functional tests haven't been finished either. I did write
several test applications in src/tests/kits/net/icmp_tests/ and they compile
on Linux (quite probably also on Haiku). But I had little time to study the
Jamfile rules and don't know how to make use of my test apps. Even worse, I
didn't manage to configure my Haiku VM right, inside which I cannot access
the Internet.
Anyhow the test kits should be of some value to the future functional test
(which I would like to continue working on). These 3 test apps are:
* icmp_dumper.c: An ICMP dumper which dumps the type of code of all
received ICMP messages. tcpdump should also be capable of doing this, but I
think icmp_dumper is more specific and clean.
* udp_unreachable.c: A program that sends simply a "Hello" UDP datagram to
a closed port on a remote machine. This program expects to receive an ICMP
destination unreachable message with code 4 indicating "port unreachable".
The user should receive an ECONNREFUSED error.
* tcp_unreachable.c: This program is similar to the previous
udp_unreachable except that it sends the message using TCP. Actually the
expected behavior of this program has nothing to do with ICMP error handling
because TCP is already a stateful protocol and it responds to messages to an
unreachable port with RST flag set, which will terminate the TCP connection.
However, the application also gets the ECONNREFUSED error as in UDP.
* big_datagram.c: A program that sends specified bytes of data to a remote
host by UDP, with DF bit set. If a device with small MTU is in the route, an
ICMP Fragment Needed message should be received. This program *has not
been*verified to work (on Linux).
4. Questions
My questions are
a) How to properly handle Redirect messages? Or more specifically, how do I
update the local routing information?
b) Concurrency is not quite taken into consideration. I only added locks in
a few places. Is there anything I should be aware of?
Other questions may rise when the tests get run. And the PMTU discovery
functionality is still under development.
Any comments are appreciated.
References:
[1] RFC792, Internet Control Message Protocol.
[2] RFC1122, Requirements for Internet Hosts -- Communication Layers.
[3] RFC768, User Datagram Protocol.
[4] RFC1191, Path MTU Discovery.
[5] RFC791, Internet Protocol.
--
Yin Qiu
Nanjing University, China
-------------------------------------------