SO_BINDTODEVICE is not supported on this system

Matthias Andree mandree at FreeBSD.org
Thu Jul 18 18:59:55 UTC 2013


Am 18.07.2013 16:58, schrieb Lambrecht Jürgen:
> On 07/18/2013 12:49 PM, Lambrecht Jürgen wrote:
>> Hi,
>>
>> I am porting the busybox dhcp server to an RTOS (eCos). eCos uses the
>> FreeBSD TCP/IP stack.
>>
>> I get this message: bb_error_msg("SO_BINDTODEVICE is not supported on
>> this system");.
>>
>> Why not ignoring this option on systems that do not support it, as long
>> as there is only 1 network interface?
>>
>> When I have fixed this, I can maybe supply a patch for systems with only
>> 1 network interface (as in the ISC DHCPD code). Alowing to not use
>> SO_BINDTODEVICE will improve portability.
>>
>> Regards,
>> Jürgen
>>
> patch to solve this in attach
> (I can also use git send-email if you prefer, but I wanted to reply to 
> this mail)
> It also contains a small fix for calling 'alloca': it wants a size_t, 
> not an int.

Greeting Jürgen, and everyone else on the list,

I'd say that the SO_BINDTODEVICE stuff can be avoided, as sketched
below. The plan is:

1. obtain the interface's primary address for the socket's address
family with ioctl (socket, SIOCGIFADDR, struct ifreq *something)
<http://www.freebsd.org/cgi/man.cgi?query=netintro&apropos=0&sektion=0&manpath=FreeBSD+8.3-RELEASE&arch=default&format=html>

2. bind(2) to that address.


Note: IPv6 stuff needs more #includes, must use SIOCGIFADDR_IN6 and read
the address from a different-form structure.  It must also figure out
the domain (AF_INET/AF_INET6) the socket is in... this is left as an
exercise for the readers.
Some is in
http://www.freebsd.org/doc/en/books/developers-handbook/ipv6.html but I
have not looked further from there.

If IPv6-enabled, this should go into libbb/xconnect.c:


// BEWARE: THE CODE BELOW IS ONLY GOOD FOR FREEBSD AND IPV4

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <net/route.h>

/* ... */

int FAST_FUNC setsockopt_bindtodevice(int sock, const char *ifname)
{
	// input: int sock - a socket obtained from the socket() syscall
	// input: const char *ifname - interface name as C string
	struct ifreq ifr;

	memset(&ifr, 0, sizeof(ifr));	// see man 2 bind why needed
	if (strlcpy(ifr.ifr_name, ifname, IFNAMSIZ) >= IFNAMSIZ) {
		bb_perror_msg("interface name %s too long", ifname);
		return -1;
	}
	if (-1 == ioctl(sock, SIOCGIFADDR, &ifr)) {
		// see man 4 netintro for SIOCGIFADDR
		bb_perror_msg("ioctl(%d,SIOCGIFADDR,\"%s\") failed", sock, ifname);
		return -1;
	}
	// the next line will not compile on Linux for lack of sa_len
	// but you have the SO_BINDTODEVICE alternative there:
	if (-1 == bind(sock, &ifr.ifr_addr, ifr.ifr_addr.sa_len)) {
		bb_perror_msg("cannot bind socket %d to interface %s", sock, ifname);
		return -1;
	}
	return 0;
}


I am attaching demo code, to be compiled with:

gcc -O2 -Wall -Wextra -std=gnu99 btd.c -DFAST_FUNC= -include string.h \
-o try-freebsd-btd main.c  -include stdio.h -include stdlib.h \
'-Dbb_perror_msg(...)=fprintf(stderr, __VA_ARGS__)' -include unistd.h

best run as truss ./try-freebsd-btd so you see what's going on behind
the scenes.

Hope that helps.

BTW, note that the FreeBSD port does not enable networking modules such
as udhcpd.

-------------- next part --------------
A non-text attachment was scrubbed...
Name: btd.c
Type: text/x-csrc
Size: 868 bytes
Desc: not available
URL: <http://lists.busybox.net/pipermail/busybox/attachments/20130718/804af91d/attachment.c>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: main.c
Type: text/x-csrc
Size: 554 bytes
Desc: not available
URL: <http://lists.busybox.net/pipermail/busybox/attachments/20130718/804af91d/attachment-0001.c>


More information about the busybox mailing list