In a few days we need to start testing the IP/UDP stack. Hence, I'm outlining below how to do the testing. In the end of the message I include some practical advice. This real life testing can be done by anyone who has a working Linux/Unix machine (Mac OS X is Unix), preferably with a working ARM compilation environment for the new runtime, an Ellduino board, an Ethernet cable, and the capability of powering the Ellduino board (either over USB, PoE, or separately). In the very beginning, we will be using a fixed IP address of 10.0.0.2, a bad Ethernet address of 00:00:00:00:00:00, no ICMP, and no ARP. Then we will add a real Ethernet address, ARP, ICMP, and (later on) DHCP. Testing steps: 1. The MCU driver is able to receive Ethernet packets (seen via LEDs or serial line). 2. The Ethernet packets are passed to the IP layer. 3. The IP layer is able to verify the packet format and recognises its IP address. 4. The packets are passed to the CoAP layer. 5. The CoAP replies are received by the Ethernet layer. CoAP-layer replying down to the Ethernet layer has already been tested with mockups. However, even in this there may be bugs related to the differences between the emulator and the real hardware. For example, I expect that the UDP socket and CoAP URL data structures may align differently, requiring #ifdefs. 6. The Ethernet layer passes the reply packets to the ENC28J60 chip. 7. The outgoing packets are visible in the Ethernet. 8. The outgoing packets are formatted correctly. 9. A CoAP transaction works correctly end-to-end. The initial steps may be the most frustrating ones, as there it is very hard to figure out what is wrong (if anything). I expect that most time will go to steps 8 and 9. For Step 8 since the stack has been written from the ground up and is likely to contain subtle protocol bugs. For Step 9 for the same reason plus because this is the first time I'm implementing CoAP. (IP and related protocols I have implemented a few times in the past.) ---------------- The main tool for testing is either Wireshark or TCP dump. I will most probably be using Wireshark myself. https://www.wireshark.org Now, before we can actually get to the testing, we need to prepare the laptop for working with an endpoint that doesn't implement ARP or DHCP. For that we need to manually configure a static ARP table entry and configure the network interface to contain an IP address within the same subnet as the Ellduino board. 1. Configuring the host network interface In Linux/Unix, each network interface is usually configured to have a single IP address, subnet mask, and default gateway. However, it is possible to configure the interface to have multiple IP addresses. The latter is often used for so-called multi-homing, in a situation where a single Ethernet network carries multiple IP subnetworks. In our case, whether the Ethernet carries just a single IP subnet or many depends on how the Ellduino and the testing Unix/Linux are connected to each other. If they are connected with a direct cable (crossover or not, depending on the host Ethernet port), then one subnet is enough. If they are connected through a switch or a hub, and the host uses the Ethernet also for other traffic, two subnets are needed. In the examples below I expect that we are using two subnets and that the host is Unix. In Linux the commands are different (and I don't remember them by heart), but the principles are the same. In the host, the network interfaces are named with sort mnemonics, e.g. eth0, en2, bge3. In both Linux and Unix you can list the interfaces with "ifconfig -a"; the output format is different. In Mac OS X the output looks like the following: $ ifconfig -a lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> mtu 16384 options=3<RXCSUM,TXCSUM> inet6 fe80::1%lo0 prefixlen 64 scopeid 0x1 inet 127.0.0.1 netmask 0xff000000 inet6 ::1 prefixlen 128 ... en0: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500 options=2b<RXCSUM,TXCSUM,VLAN_HWTAGGING,TSO4> media: autoselect (none) status: inactive ... Here en0 is my laptop's Ethernet interface. (I just need to know which mnemonic is which physical interface. If I don't know, I need to connect the cable to a switch and figure out which interface changes its status from inactive to active.) At this stage it is disconnected (status: inactive) and it does not have an IP address. (I have removed the Ethernet address for privacy purposes.) When I connect the Ethernet and wait for a while for my router to give my laptop a DHCP address, the output changes as follows: en0: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500 options=2b<RXCSUM,TXCSUM,VLAN_HWTAGGING,TSO4> inet6 fe80::cx2c:14zz:yy03:1111%en0 prefixlen 64 scopeid 0x5 inet 192.168.1.233 netmask 0xffffff00 broadcast 192.168.1.255 media: autoselect (1000baseT <full-duplex,flow-control>) status: active Now the interface is connected (status: active) and it has been assigned an IP address of 192.168.1.233, with the subnetwork mask (netmask) of 255.255.255.0 (0xffffff00). I can also see that it is connected to a gigabit switch and has been assigned an link-local IPv6 address (mangled). Now, to prepare the interface for Ellduino IP/UDP testing, I need to configure the interface to be in the same subnetwork where the Ellduino fixed IP address is, i.e. in the 10.0.0.0/24 subnetwork. In Unix, I can add an IP alias for that. In Linux this is done differently and I don't remember how; we did configure the Raspberry Pi so in October with Teemu, but I don't remember the details. Hence, in a Unix I give the following command: $ sudo ifconfig en0 10.0.0.1 netmask 255.255.255.0 alias The "alias" in the end indicates that I want this address to be used in *addition* to the other IP address. If I just wanted to replace the existing address, or configure an address when there is none, I could enter the same command without the "alias". After that the output looks as follows: en0: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500 options=2b<RXCSUM,TXCSUM,VLAN_HWTAGGING,TSO4> inet6 fe80::cx2c:14zz:yy03:1111%en0 prefixlen 64 scopeid 0x5 inet 192.168.1.233 netmask 0xffffff00 broadcast 192.168.1.255 inet 10.0.0.1 netmask 0xffffff00 broadcast 10.0.0.255 media: autoselect (1000baseT <full-duplex,flow-control>) status: active Here we can see that the interface now has two IP addresses, 192.168.1.233 in the subnet 192.168.1.233/24 and 10.0.0.1 in the subnet 10.0.0.0/24. 2. Adding a static ARP table entry The ARP protocol maintains a table that lists the Ethernet address for each active remote IP address. For example, in my laptop the arp table looks like the following at the moment (with the Ethernet addresses masked for privacy): $ arp -a ? (192.168.1.17) at 0:x1:x2:x3:x4:x5 on en0 ifscope [ethernet] ? (192.168.1.18) at 0:y1:y2:y3:y4:y5 on en0 ifscope [ethernet] ? (192.168.2.4) at 0:z1:z2:z3:z4:z5 on en1 ifscope [ethernet] ? (192.168.2.17) at 0:s1:s2:s3:s4:s5 on en1 ifscope [ethernet] ? (192.168.2.164) at 0:t1:t2:t3:t4:t5 on en1 ifscope [ethernet] Since the Ellduino board won't have ARP in the first phase, we need to manually create a static ARP entry for it. The following command does this in Unix; again, the Linux syntax is likely to be somewhat different: $ sudo arp -s 10.0.0.2 00:00:00:00:00:00 ifscope en0 After that the ARP table looks like the following: $ arp -an ? (10.0.0.2) at 0:0:0:0:0:0 on en0 ifscope permanent [ethernet] ? (192.168.1.17) at 0:x1:x2:x3:x4:x5 on en0 ifscope [ethernet] ? (192.168.1.18) at 0:y1:y2:y3:y4:y5 on en0 ifscope [ethernet] ? (192.168.2.4) at 0:z1:z2:z3:z4:z5 on en1 ifscope [ethernet] ? (192.168.2.17) at 0:s1:s2:s3:s4:s5 on en1 ifscope [ethernet] ? (192.168.2.164) at 0:t1:t2:t3:t4:t5 on en1 ifscope [ethernet] When you stop testing, it is a good idea to remove the entry $ sudo arp -d 10.0.0.2 ------------- With the host interface configured and the static ARP table entry there, it is now possible to start the actual testing. 1. The MCU driver is able to receive Ethernet packets (seen via LEDs or serial line). In the first step, we should just send packets to the board and see that they are received by the ENC28J60 chip receives them correctly and passes to the protocol stack. For this initial testing ICMP is good enough: $ ping 10.0.0.2 At the same time, use wireshark (or tcpdump) to see that the packets actually go out from the host interface. (It is best to use wireshark or tcpdump on a separate host, but that is more tricky with modern switches and not recommended for beginners. If you have an old 10baseT hub that broadcasts every received packet on all ports, that would be perfect for this testing.) Just as an example, while running the ping I can see the following in tcpdump (running on another window): $ sudo tcpdump -ni en0 tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on en0, link-type EN10MB (Ethernet), capture size 65535 bytes 07:52:19.225853 IP 10.0.0.1 > 10.0.0.2: ICMP echo request, id 3088, seq 0, length 64 07:52:20.226951 IP 10.0.0.1 > 10.0.0.2: ICMP echo request, id 3088, seq 1, length 64 07:52:21.228137 IP 10.0.0.1 > 10.0.0.2: ICMP echo request, id 3088, seq 2, length 64 07:52:22.229215 IP 10.0.0.1 > 10.0.0.2: ICMP echo request, id 3088, seq 3, length 64 Once we know that the packets actually go out from the host, IIRC there is also a led in the Ellduino board that should blink when the ENC28J60 receives a packet. The next step is then to see that the packets are passed to the MCU. For that the driver should be instrumented with a debug LED or serial line output. 2. The Ethernet packets are passed to the IP layer. 3. The IP layer is able to verify the packet format and recognises its IP address. 4. The packets are passed to the CoAP layer. 5. The CoAP replies are received by the Ethernet layer. 6. The Ethernet layer passes the reply packets to the ENC28J60 chip. The following steps 2-6 are tested in the same way, just adding/moving the debug instrumentation into the next place in the stack source code. In step 4 it is no longer possible to use ICMP (unless someone implements a minimal ICMP that is able to respond to ICMP echo requests), but one has to move to UDP and then CoAP. Copper is a CoAP implementation for the Firefox browser. h5.coap is a CoAP implementation for node.js. Both have been tested by Teemu and I and are known to work. 7. The outgoing packets are visible in the Ethernet. 8. The outgoing packets are formatted correctly. In step 7 (or earlier if ICMP is there), the reply packets should start appearing on the network. Hence, they should be visible in Wireshark or tcpdump. Initially they are likely to be malformed, meaning that Wireshark or tcpdump may interpret them in a weird way. 9. A CoAP transaction works correctly end-to-end. This step is ready when we'll be able to use real CoAP GETs and PUTs from Copper, node.js, or something similar. --Pekka