IAN SEYLER

Just enough TCP

Screenshot

Over the end the summer I decided to extend on the work I originally did for minIP. BareMetal needed some simple example programs (especially for the unikernel version) and this was one of them.

minIP contained just enough TCP/IP (ICMP and ARP as well) to serve a page - far from a complete implementation of TCP/IP. It handled the 3-way TCP handshake, sent the HTML data, and immediately closed the client connection.

The big update here was a DHCP client. Hardcoded values are fine but automatic config is nice to have. By booting BareMetal on a physical system connected to my LAN it was able to get an IP on its own. Forwarding port 80 to that IP from my router allowed the system to be accessed via the internet successfully!

That resulted in a binary of 8784 bytes. Not bad, but the interest was to see just how small the resulting binary could be.

-Os, obviously

4250 bytes - perfect start.

Don't reinvent the wheel - Endianness

u16 swap16(u16 in)
u32 swap32(u32 in)

It turns out I don't need to provide these functions as GCC has built-in versions

#define swap16(x) __builtin_bswap16(x)
#define swap32(x) __builtin_bswap32(x)

I doubt this did much (if anything) to the resulting binary but was still a good change.

Make use of memcpy()

src_MAC[0] = os_MAC[0];
src_MAC[1] = os_MAC[1];
src_MAC[2] = os_MAC[2];
src_MAC[3] = os_MAC[3];
src_MAC[4] = os_MAC[4];
src_MAC[5] = os_MAC[5];

C isn't my language of choice but the above code worked. Instead of setting values manually they can just be copied with memcpy().

memcpy(src_MAC, os_MAC, 6);

Down to 4122 bytes

Remove abstractions that are no longer needed

minIP was originally written to be run on BareMetal as well as Linux. Wrapper functions for sending/receiving data were used to make things simpler but Linux support was no longer required. Bye-bye wrappers!

4026 bytes. It was finally under 4KiB in size.

Clean up hardcoded values

Addresses for the IP, subnet, and gateway are global variables and were all set to 0. In main() the variables were set to the desired values. This didn't make sense in the long run so the variables can just be set once instead.

Final result

4006 bytes. The code can be seen here.