arduino-libraries / Ethernet

Ethernet Library for Arduino
http://arduino.cc/
259 stars 264 forks source link

Link local addresses and ARP messages #263

Open henkelis opened 6 months ago

henkelis commented 6 months ago

Hi,

I'm using the Ethernet library on an ESP32S3 with an attached W5500. For my use case I want to be able to connect to another host either via a router and DHCP, or via a switch or direct cable-to-cable. I don't want to use static IP addresses if there is no DHCP (as I may be connecting multiple boards to the host), so I've been looking at adding link local/AUTOIP support to Ethernet.

I've "ported" the AUTOIP code from lwIP and made appropriate changes so it works with Ethernet (I can try to acquire a DHCP address, then switch to acquiring a link local address if DHCP fails). It successfully negotiates a link local address, which I then use for a web socket connection.

To send the ARP probe/response and announcement messages, I've resorted to using port 0 on the W5500 in MACRAW mode - if I open in UDP mode, the messages have the IP header attached rather than being plain ARP. I can see that the W5500 is capable of sending plain ARP messages (it does so after I've configured link local) - does anyone know if there's a way to make it do that without having to resort to MACRAW?

Obviously if anyone wants to test out/use my link local code I can upload it.

Mark.

JABCanford commented 1 week ago

Hi Mark,

I'm using the Ethernet library on a RP2040 with a w5500, and would also like to be able to implement link-local addressing.

Having done a lot of reading forums and the w5500 datasheet, I would agree that using MACRAW mode seems to be the best way of doing it.

I know some other IP stacks for the w5500, such as lwip, support link-local, but those have been an order of magnitude slower serving pages in my testing, which is less than ideal for my application.

I'd be very interested to test out your code, if you're still willing to upload it.

James.

henkelis commented 1 week ago

Hi James,

Happy to share. I've uploaded my amended Ethernet code here: https://github.com/henkelis/Ethernet

There's a second readme (README.md) that gives an overview of the changes.

I've also added a simple example into the examples/AutoIP folder (untested, it's a much cut down version of my code).

Mark.

JABCanford commented 4 days ago

Hi Mark,

I've done some testing on a custom board which is based on the Wiznet W5500-EVB-Pico, but with additional hardware (relays, LCD etc).

I tested your example code (with a changed CS pin), and it happily obtained an IP via DHCP, and when there was no DHCP server it gave itself a link-local. Calling beginautoip(mac, 30000, 1000) while on a network without a DHCP server, and with a host already using the code's first choice (169.254.263.174 (for my MAC)), resulted in an IP address one bit higher (169.254.163.175), so the link local part seems to be working well.

I also added the modified Ethernet library to my program (web server controlling relays etc) for my custom board. The library was still able to determine a link local address, and get an address via DHCP, but calling ethernet.maintain after getting a DHCP allocation caused the rp2040 to crash (activity on both cores is halted). I think it was due to the stack becoming full, as after a lot of head scratching, changing a 100 byte array local variable to a global variable in one of my functions fixed the issue, and everything is now working well; so I'm now confident the issue was with my program as a whole and not your changes to the library. Sorry for taking a while to feed back on your modified library, I wanted to track down this issue with my code, rather than saying your modifications broke things.

One other thing I noticed was that reducing the timeout to 5 seconds (ie. calling beginautoip(mac, 5000, 1000)) can result in no IP being set. Looking at a wireshark capture of what goes on with the link-local process, it looks like more than two ARP requests are sent (I've seen 3 to 6), followed by two Gratuitous ARPs, which means the first timeout needs to be about 10 times larger at minimum (looks like slightly more is needed if it tries to use an address that's in use), so 30000 is fairly sensible for the responseTimeout being 1000. It might be worth adding a check to make sure the timeout value is at least a certain number of times larger than the responseTimeout value?

Also, are you happy to licence the use of your changes under the same licence as the rest of the Arduino Ethernet library (LGPL 2.1)?

James.

henkelis commented 4 days ago

Great that it works for you.

I did lower some timeouts from the spec values, it's possible that that has caused an issue. For my use case I want to get a connection as quickly as possible once DHCP has failed. I'll have look at timings etc when I get a chance (that won't be in the immediate future). I also need to build some more hardware to test multiple concurrent connection attempts.

Yes I'm happy to licence my changes under the same licence (as they're based on lwip code I should include their copyright notice).