title: Problems with SO_BINDTODEVICE Linux socket option
body: <p>I have a PC with two network cards. One (<code>eth0</code>) is for LAN/internet and the other for UDP communication with one microcontroller device. The microcontroller has an IP (192.168.7.2) and a MAC address. The second pc network adapter (<code>eth1</code>) has 192.168.7.1.</p>
  
  <p>The microcontroller has a very simple IP stack, so the easiest way for the mc to send UDP packets is to broadcast them.</p>
  
  <p>On the PC side I'd like to receive the broadcasts - but only from <code>eth1</code>. So I try to bind the UDP socket to the <code>eth1</code> device. </p>
  
  <p>The problems (source code below):</p>
  
  <ol>
  <li><p><code>setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, device, sizeof(device))</code> requires root privileges, why? (setting other options works as user)</p></li>
  <li><p><code>getsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, (void *)buffer, &amp;opt_length)</code> gives "Protocol not available". I would like to read back the device I set via <code>setsockopt</code> command.</p></li>
  <li><p>Where can I find good info? I checked some Linux-programming, network books, but for example the <code>SO_BINDTODEVICE</code> option I've only found on the internet.</p></li>
  </ol>
  
  <p>My lengthy (dirty) test program shows the problems. Setting and getting back the <code>SO_RCVTIMEO</code> and <code>SO_BROADCAST</code> options works as expected.</p>
  
  <p>Running the code as user exits with:</p>
  
  <pre class="lang-none prettyprint-override"><code>could not set SO_BINDTODEVICE (Operation not permitted)"
  </code></pre>
  
  <p>Running with sudo gives:</p>
  
  <pre class="lang-none prettyprint-override"><code>SO_BINDTODEVICE set
  ./mc-test: could not get SO_BINDTODEVICE (Protocol not available)
  </code></pre>
  
  <p>So, setting the option seems to work but reading it back is not possible?</p>
  
  <pre><code>/* SO_BINDTODEVICE test */ 
  
  #include &lt;sys/types.h&gt;
  #include &lt;sys/socket.h&gt;
  #include &lt;netinet/in.h&gt;
  #include &lt;arpa/inet.h&gt;
  #include &lt;netdb.h&gt;
  #include &lt;stdio.h&gt;
  #include &lt;unistd.h&gt;
  #include &lt;string.h&gt;
  #include &lt;stdlib.h&gt;
  #include &lt;sys/time.h&gt;
  #include &lt;errno.h&gt;
  
  #define MC_IP "192.168.7.2"
  #define MC_PORT (54321)
  #define MY_PORT (54321)
  #define MY_DEVICE "eth1"
  
  #define BUFFERSIZE (1000)
  
  /* global variables */
  int sock;
  struct sockaddr_in MC_addr;
  struct sockaddr_in my_addr;
  char buffer[BUFFERSIZE];
  
  int main(int argc, char *argv[]) 
  {
    unsigned int echolen, clientlen;
    int rc, n;
    char opt_buffer[1000];
    struct protoent *udp_protoent;
    struct timeval receive_timeout;
    int optval;
    socklen_t opt_length;
  
    /* Create the UDP socket */
    if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) &lt; 0) 
    {
      printf ("%s: failed to create UDP socket (%s) \n",
          argv[0], strerror(errno));
      exit (EXIT_FAILURE);
    }
    printf ("UDP socket created\n");
  
    /* set the recvfrom timeout value */
    receive_timeout.tv_sec = 5;
    receive_timeout.tv_usec = 0;
    rc=setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &amp;receive_timeout,
                  sizeof(receive_timeout));
    if (rc != 0) 
    {
       printf ("%s: could not set SO_RCVTIMEO (%s)\n",
          argv[0], strerror(errno));
       exit (EXIT_FAILURE);
    }
    printf ("set timeout to\ntime [s]: %d\ntime [ms]: %d\n", receive_timeout.tv_sec, receive_timeout.tv_usec);
    /* verify the recvfrom timeout value */
    rc=getsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &amp;receive_timeout, &amp;opt_length);
    if (rc != 0) 
    {
       printf ("%s: could not get socket options (%s)\n",
          argv[0], strerror(errno));
       exit (EXIT_FAILURE);
    }
    printf ("timeout value\ntime [s]: %d\ntime [ms]: %d\n", receive_timeout.tv_sec, receive_timeout.tv_usec);
  
    /* allow broadcast messages for the socket */
    int true = 1;
    rc=setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &amp;true, sizeof(true));
    if (rc != 0) 
    {
       printf ("%s: could not set SO_BROADCAST (%s)\n",
          argv[0], strerror(errno));
       exit (EXIT_FAILURE);
    }
    printf ("set SO_BROADCAST\n");
    /* verify SO_BROADCAST setting */
    rc=getsockopt(sock, SOL_SOCKET, SO_BROADCAST, &amp;optval, &amp;opt_length);
    if (optval != 0) 
    {
      printf("SO_BROADCAST is enabled\n");
    }
  
    /* bind the socket to one network device */
    const char device[] = MY_DEVICE;
    rc=setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, device, sizeof(device));
    if (rc != 0) 
    {
       printf ("%s: could not set SO_BINDTODEVICE (%s)\n",
          argv[0], strerror(errno));
       exit (EXIT_FAILURE);
    }
    printf ("SO_BINDTODEVICE set\n");
    /* verify SO_BINDTODEVICE setting */
    rc = getsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, (void *)buffer, &amp;opt_length);
    if (rc != 0) 
    {
       printf ("%s: could not get SO_BINDTODEVICE (%s)\n",
          argv[0], strerror(errno));
       exit (EXIT_FAILURE);
    }
    if (rc == 0) 
    {
      printf("SO_BINDTODEVICE is: %s\n", buffer);
    }
  
  
    /* Construct the server sockaddr_in structure */
    memset(&amp;MC_addr, 0, sizeof(MC_addr));     /* Clear struct */
    MC_addr.sin_family = AF_INET;         /* Internet/IP */
    MC_addr.sin_addr.s_addr = inet_addr(MC_IP);   /* IP address */
    MC_addr.sin_port = htons(MC_PORT);        /* server port */
  
    /* bind my own Port */
    my_addr.sin_family = AF_INET;
    my_addr.sin_addr.s_addr = INADDR_ANY; /* INADDR_ANY all local addresses */
    my_addr.sin_port = htons(MY_PORT);
    rc = bind (sock, (struct sockaddr *) &amp;my_addr, sizeof(my_addr));
    if (rc &lt; 0) 
    {
       printf ("%s: could not bind port (%s)\n",
          argv[0], strerror(errno));
       exit (EXIT_FAILURE);
    }
    printf ("port bound\n");
  
    /* identify mc */
    buffer[0] = (char)1;
    buffer[1] = (char)0;
    send_data (buffer, 2);  
    printf ("sent command: %d\n", (char)buffer[0]);
  
    rc=receive_data(buffer);
    printf ("%d bytes received\n", rc);
    buffer[rc] = (char)0; /* string end symbol */
    printf ("%d - %s\n", (int)(char)buffer[0], &amp;buffer[1]);
  
    close(sock);
    printf ("socket closed\n");
  
    exit(0);
  }
  
  /* send data to the MC *****************************************************/
  /* buffer points to the bytes to send */
  /* buf_length is the number of bytes to send */
  /* returns allways 0 */
  int send_data( char *buffer, int buf_length )
  {
    int rc;
  
    rc = sendto (sock, buffer, buf_length, 0,
                   (struct sockaddr *) &amp;MC_addr,
                   sizeof(MC_addr));
    if (rc &lt; 0) 
    {
      printf ("could not send data\n");
      close (sock);
      exit (EXIT_FAILURE);
    }
    return(0);
  }
  
  /* receive data from the MC *****************************************************/
  /* buffer points to the memory for the received data */
  /* max BUFFERSIZE bytes can be received */
  /* returns number of bytes received */
  int receive_data(char *buffer)
  {
    int rc, MC_addr_length;
  
    MC_addr_length = sizeof(MC_addr);
    rc = recvfrom (sock, buffer, BUFFERSIZE, 0,
                   (struct sockaddr *) &amp;MC_addr,
                   &amp;MC_addr_length);
    if (rc &lt; 0) 
    {
      printf ("could not receive data\n");
      close (sock);
      exit (EXIT_FAILURE);
    }
    return(rc);
  }
  </code></pre>