6

The problem

On our system running RTEMS 4.9.2 we are experiencing a very odd issue with socket communications. We are setting up a socket and using the following command to bind:

// Bind the socket to set the local port
sockaddr_in localSocketAddress = {0};
localSocketAddress.sin_family = AF_INET;
localSocketAddress.sin_port = (u_short)localPort;
localSocketAddress.sin_addr.s_addr = localAddress;

if (bind( mSocket, (sockaddr *)&localSocketAddress, sizeof(sockaddr_in)) == SOCKET_ERROR)
{
    int errorOut = errno;
    ...

And this works for UDP communications except in a strange specific scenario which is explained below. The problem that we experience is a failure of this bind call even though the setup is correct. We get the error 125 which for RTEMS is EADDRNOTAVAIL:

A nonexistent interface was requested or the requested address was not local.

The Apparent Cause

At boot of the device we can set up our network in 1 of 2 ways:

  1. The Network IP and SUBNET is autoconfigured based on what is in the default bootloader (UBOOT), and is set up through the RTEMS OS.

  2. The RTEMS function rtems_bsdnet_ifconfig is called to change the ip address of the sole ethernet interface after boot time.

For clarification, option 2 is called like this:

rtems_bsdnet_ifconfig(eth_interface, SIOCSIFADDR, &ipaddr);

If the network is set up as indicated by option 1, everything works as expected, but if option 2 is used (even in the case where the setup matches the network options defined by option 1) then the socket bind fails.

Is there a known reason or bug for RTEMS that indicates that this bind would fail if you reconfigure your IP?

Additional Information

  • We are setting up a new IP address (option 2) using a method that essentially uses ioctl("eht1", SIOCSIFADDR, ...).

  • If we bind our socket without specifying a local ADDRESS (ie use INADDR_ANY) then it works in any case.

  • The rtems_bsdnet_ifconfig is a simple interface for the ioctl function. It is from rtems_glue.c and has the function signiture int rtems_bsdnet_ifconfig(const char *ifname, uint32_t cmd, void *param)

  • All normal network functions seem to work except for this bind.

  • After looking at this i thought maybe I needed to do more in resetting my IP address. But this doesn't work , using the first answer or even doing anything with SIOCSIFFLAGS causes all network functionality to cease.

Community
  • 1
  • 1
Fantastic Mr Fox
  • 32,495
  • 27
  • 95
  • 175
  • is it possible your `bind` is happening before the interface has completed setting up? does it continue to fail if you continue to retry the `bind`? – mark Jun 08 '16 at 16:53
  • @mark The bind is well after the setup, both setup options occur at boot before the socket setup can be attempted. – Fantastic Mr Fox Jun 08 '16 at 16:54
  • Probably something change since my rtems version (`4.6.1`) but `rtems_bsdnet_ifconfig` it is a struct not a function... – LPs Jun 14 '16 at 09:34
  • @LPs It is both, a struct exists and so does a function, the function doesnt seem to have any documentation otherwise i would link it, it can be found in `rtems_glue.c`. – Fantastic Mr Fox Jun 14 '16 at 14:34
  • Disclaimer: No expert here, just went through the code a bit. Do you explicitly set sa_family to AF_INET? [Seems](https://github.com/RTEMS/rtems/blob/4.9/cpukit/libnetworking/netinet/in_pcb.c#L159) as if this isn't required, but should be set as it is used in the [comparision](https://github.com/RTEMS/rtems/blob/4.9/cpukit/libnetworking/net/if.c#L170). Another hint, as the `sockaddr` structs are byte-compared: do you `memset` your sockaddr struct to 0 before configuring it's values and passing to `bind`? – grasbueschel Jun 16 '16 at 20:19
  • Have you tried to step through the `bind()` call with a debugger and look where the `return EADDRNOTAVAIL` exactly happens? – exilit Jun 17 '16 at 09:00
  • @exilit Unfortunately we have no active debugger, this only occurs on the actual embedded hardware, all i can use is print statements. – Fantastic Mr Fox Jun 17 '16 at 15:07
  • Do you compile the library yourself? – exilit Jun 17 '16 at 15:17
  • @exilit We compile the entire OS ourselves. But there is no interface to the embedded hardware that could use a debugger even if RTEMS implemented one. – Fantastic Mr Fox Jun 17 '16 at 15:33
  • @grasbueschel We do both those things, i have edited the question to reflect this. `sockaddr_in localSocketAddress = {0};` – Fantastic Mr Fox Jun 17 '16 at 16:16
  • That is not why I am asking. Is there any chance that you include some debug output at the relevant places and debug it that way? We will have to put some thoughts and effort into figuring out this "relevant" places, but that might be worth trying. – exilit Jun 17 '16 at 16:20
  • @exilit Yes, i can put debug prints into the operating system, it uses BSDNet libs for everything networking. I would then be able to recompile the operating system and see the prints, but i usually have to be very careful, printing too much can screw up the timing. I hate doing that ... – Fantastic Mr Fox Jun 17 '16 at 16:42
  • I hate that, too. But as long nobody answers I think you have not much choice. – exilit Jun 17 '16 at 16:48
  • @Ben alright, I see. Another thing to check, though I don't think that it's the core of the issue here: There's a `sin_len` member of [`sockaddr_in`](https://github.com/RTEMS/rtems/blob/4.9/cpukit/libnetworking/netinet/in.h#L70) which you should initialize to `sizeof struct sockaddr_in`. – grasbueschel Jun 17 '16 at 19:25
  • @grasbueschel So i gave this a go, doesn't make any difference unfortunately. – Fantastic Mr Fox Jun 23 '16 at 00:53

1 Answers1

1

You didn't mention the architecture you are running on, but you are setting the port and address in local byte order, which may not be the same as network byte order. The very first thing I would try is:

localSocketAddress.sin_port = htons (localPort); localSocketAddress.sin_addr.s_addr = htonl (localAddress);

This will also make your code more portable, in case that is NOT your problem (i.e. you are running on a big-endian host) and you one day try to compile on a different system that is little endian.

Fantastic Mr Fox
  • 32,495
  • 27
  • 95
  • 175
Kean
  • 592
  • 5
  • 10
  • 1
    Why should it be a comment? Just asking for future clarity's sake. Also did you even TRY my suggestion? Those fields are supposed to be in network byte order and using htons() and htonl() is "correct". – Kean Jul 11 '16 at 19:01
  • @Ben A solution is an answer, not a comment. You are mistaken and Kean is not. – user207421 Jul 11 '16 at 20:32
  • @Kean, my apologies about the comment thing, i will try your solution. However, do we expect it to work? If you read the question the socket bind works just fine in every case unless i run `rtems_bsdnet_ifconfig(` to reconfigure my network address. Why would it ever work if the network address was in the wrong order? – Fantastic Mr Fox Jul 11 '16 at 20:35
  • @Ben I think I assumed that the actual address you were connecting to changed after that rtems call. I should not have assumed such, but since I did my reasoning was that in the first case it could have been some constant you had assigned to localAddress, whereas after making the change you set it to something else. Assumption is the mother of all failures. Sorry about that. – Kean Jul 11 '16 at 21:35
  • Just so we are clear about this, unfortunately this solution didn't work. – Fantastic Mr Fox Aug 29 '16 at 22:26