title: Linux - rtnetlink RTM_GETLINK - handle and understand answered data
body: <p>I'am trying to understand how rtnetlink works, so I started playing with the idea to build a little library for my self to get into it.</p>
  
  <p>I've got to the point where sending/receiving netlink messages works fine.
  Right now I'am struggling on how to process the answer of an <em>RTM_GETLINK</em> request.
  This is my current code:</p>
  
  <pre><code>#include &lt;errno.h&gt;
  #include &lt;linux/if.h&gt;
  #include &lt;linux/if_link.h&gt;
  #include &lt;linux/rtnetlink.h&gt;
  #include &lt;stdio.h&gt;
  #include &lt;stdlib.h&gt;
  #include &lt;string.h&gt;
  #include &lt;sys/socket.h&gt;
  #include &lt;unistd.h&gt;
  
  int main(void) {
    unsigned char buf[65535];
    unsigned char mac_buf[6];
    int tmp_int;
  
    /*
     * a standard request
     */
    struct {
      struct nlmsghdr __r_nl_msg;
      struct ifinfomsg __r_ii_msg;
    } req;
  
    int sfd, answer_size, attr_len;
  
    struct nlmsghdr *nl_msg_ptr;
    struct ifinfomsg *inf_msg_ptr;
    struct rtattr *rta_ptr;
  
    /*
     * create a socket
     */
    if ((sfd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE)) &lt; 0) {
      fprintf(stderr, "ERROR socket(): %s\n", strerror(errno));
      return (sfd);
    }
  
    /*
     * zero out req
     */
    memset(&amp;req, 0, sizeof(req));
  
    /*
     * prepare the header
     */
    req.__r_nl_msg.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
    req.__r_nl_msg.nlmsg_flags = NLM_F_REQUEST | NLM_F_MATCH;
    req.__r_nl_msg.nlmsg_type = RTM_GETLINK; /* to get iface information */
    req.__r_nl_msg.nlmsg_seq = 1;            /* start seq */
  
    req.__r_ii_msg.ifi_family = AF_UNSPEC; /* AF_INET6 for IPv6 */
    req.__r_ii_msg.ifi_change =
        0xffffffff; /* man rtnetlink says this; but why? */
  
    /*
     * send out request
     */
    if (send(sfd, &amp;req, req.__r_nl_msg.nlmsg_len, 0) &lt; 0) {
      fprintf(stderr, "ERROR send(): %s\n", strerror(errno));
      close(sfd);
      return (-1);
    }
  
    /*
     * receive the answer/process it
     */
    while (1) {
      if ((answer_size = recv(sfd, buf, sizeof(buf), 0)) &lt; 0) {
        fprintf(stderr, "ERROR recv(): %s\n", strerror(errno));
        close(sfd);
        return (-1);
      }
  
      printf("\n=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n");
      printf("[INFO] %d bytes received.\n", answer_size);
  
      /*
       * go over the nlmsghdr's in this answer
       */
      for (nl_msg_ptr = (struct nlmsghdr *)buf;
           answer_size &gt; (int)sizeof(*nl_msg_ptr);) {
        int len = nl_msg_ptr-&gt;nlmsg_len;
  
        printf("[INFO] Message length of '%d' bytes.\n", len);
  
        /*
         * check if we should stop here
         */
        switch (nl_msg_ptr-&gt;nlmsg_type) {
        case NLMSG_ERROR:
          printf("[ERROR] Message is of tmp_int 'NLMSG_ERROR'.\n");
        case NLMSG_DONE:
          close(sfd);
          return (0);
        }
  
        if (!NLMSG_OK(nl_msg_ptr, (unsigned int)answer_size)) {
          printf("[ERROR] Received message is NOT ok.\n");
          close(sfd);
          return (-1);
        }
  
        /*
         * set pointers to work with
         */
        inf_msg_ptr = (struct ifinfomsg *)NLMSG_DATA(nl_msg_ptr);
        rta_ptr = (struct rtattr *)IFLA_RTA(inf_msg_ptr);
  
        printf("[INFO] Index is: '%d'.\n", inf_msg_ptr-&gt;ifi_index);
        printf("[INFO] Iface Type: '%d'\n", inf_msg_ptr-&gt;ifi_type); /* ARPHRD_* */
        printf("[INFO] Up/Down: '%d'\n", inf_msg_ptr-&gt;ifi_flags &amp; IFF_UP);
        printf("[INFO] Promisc: '%d'\n", inf_msg_ptr-&gt;ifi_flags &amp; IFF_PROMISC);
  
        /*
         * process attributes
         */
        attr_len = IFLA_PAYLOAD(nl_msg_ptr);
  
        for (; RTA_OK(rta_ptr, attr_len); rta_ptr = RTA_NEXT(rta_ptr, attr_len)) {
          switch (rta_ptr-&gt;rta_type) {
          case IFLA_ADDRESS:
            memcpy(mac_buf, RTA_DATA(rta_ptr), 6);
            printf("[%d][ADDRRESS] %02x:%02x:%02x:%02x:%02x:%02x\n",
                   inf_msg_ptr-&gt;ifi_index, mac_buf[0], mac_buf[1], mac_buf[2],
                   mac_buf[3], mac_buf[4], mac_buf[5]);
            break;
  
          case IFLA_BROADCAST:
            memcpy(mac_buf, RTA_DATA(rta_ptr), 6);
            printf("[%d][BROADCAST] %02x:%02x:%02x:%02x:%02x:%02x\n",
                   inf_msg_ptr-&gt;ifi_index, mac_buf[0], mac_buf[1], mac_buf[2],
                   mac_buf[3], mac_buf[4], mac_buf[5]);
            break;
  
          case IFLA_IFNAME:
            printf("[%d][IFNAME] %s\n", inf_msg_ptr-&gt;ifi_index,
                   RTA_DATA(rta_ptr));
            break;
  
          case IFLA_MTU:
            memcpy(&amp;tmp_int, RTA_DATA(rta_ptr), 4);
            printf("[%d][MTU] %d\n", inf_msg_ptr-&gt;ifi_index, tmp_int);
            break;
  
          case IFLA_LINK:  /* ??? */
            memcpy(&amp;tmp_int, RTA_DATA(rta_ptr), 4);
            printf("[%d][LINK] %d\n", inf_msg_ptr-&gt;ifi_index, tmp_int);
            break;
  
          case IFLA_QDISC:
            printf("[%d][QDISC] %s\n", inf_msg_ptr-&gt;ifi_index, RTA_DATA(rta_ptr));
            break;
  
          case IFLA_STATS:
            printf("[%d][STATS] ...\n", inf_msg_ptr-&gt;ifi_index);
            break;
  
          case IFLA_COST: /* ??? */
            memcpy(&amp;tmp_int, RTA_DATA(rta_ptr), 4);
            printf("[%d][COST] %d\n", inf_msg_ptr-&gt;ifi_index, tmp_int);
            break;
  
          case IFLA_PRIORITY: /* ??? */
            memcpy(&amp;tmp_int, RTA_DATA(rta_ptr), 4);
            printf("[%d][PRIORITY] %d\n", inf_msg_ptr-&gt;ifi_index, tmp_int);
            break;
  
          case IFLA_MASTER: /* ??? */
            memcpy(&amp;tmp_int, RTA_DATA(rta_ptr), 4);
            printf("[%d][MASTER] %d\n", inf_msg_ptr-&gt;ifi_index, tmp_int);
            break;
  
          case IFLA_WIRELESS: /* ??? */
            memcpy(&amp;tmp_int, RTA_DATA(rta_ptr), 4);
            printf("[%d][WIRELESS] %d\n", inf_msg_ptr-&gt;ifi_index, tmp_int);
            break;
  
          case IFLA_PROTINFO: /* ??? */
            memcpy(&amp;tmp_int, RTA_DATA(rta_ptr), 4);
            printf("[%d][PROTINFO] %d\n", inf_msg_ptr-&gt;ifi_index, tmp_int);
            break;
  
          case IFLA_TXQLEN:
            memcpy(&amp;tmp_int, RTA_DATA(rta_ptr), 4);
            printf("[%d][TXQLEN] %d\n", inf_msg_ptr-&gt;ifi_index, tmp_int);
            break;
  
          case IFLA_MAP: /* ??? */
            printf("[%d][MAP] ...\n", inf_msg_ptr-&gt;ifi_index);
            break;
  
          case IFLA_WEIGHT: /* ??? */
            memcpy(&amp;tmp_int, RTA_DATA(rta_ptr), 4);
            printf("[%d][WIGHT] %d\n", inf_msg_ptr-&gt;ifi_index, tmp_int);
            break;
  
          case IFLA_OPERSTATE: /* operational state; interface can be up but if
                                  nothing is connected its OPERSTATE is down */
            memcpy(&amp;tmp_int, RTA_DATA(rta_ptr), 4);
            printf("[%d][OPERSTATE] %d=", inf_msg_ptr-&gt;ifi_index, tmp_int);
            switch (tmp_int) {
            case IF_OPER_UP:
              printf("IF_OPER_UP\n");
              break;
            case IF_OPER_DORMANT:
              printf("IF_OPER_DORMANT\n");
              break;
            case IF_OPER_LOWERLAYERDOWN:
              printf("IF_OPER_LOWERLAYERDOWN\n");
              break;
            case IF_OPER_DOWN:
              printf("IF_OPER_DOWN\n");
              break;
            case IF_OPER_NOTPRESENT:
              printf("IF_OPER_NOTPRESENT\n");
              break;
            case IF_OPER_TESTING:
              printf("IF_OPER_TESTING\n");
              break;
            case IF_OPER_UNKNOWN:
              printf("IF_OPER_UNKNOWN\n");
              break;
            default:
              printf("N/A\n");
              break;
            };
            break;
  
          case IFLA_LINKMODE: /* Mode of the link */
            memcpy(&amp;tmp_int, RTA_DATA(rta_ptr), 4);
            printf("[%d][LINKMODE] %d=", inf_msg_ptr-&gt;ifi_index, tmp_int);
            if (tmp_int == IF_LINK_MODE_DORMANT) {
              printf("IF_LINK_MODE_DORMANT\n");
            } else if (tmp_int == IF_LINK_MODE_DEFAULT) {
              printf("IF_LINK_MODE_DEFAULT\n");
            } else {
              printf("UNKNOWN\n");
            }
            break;
  
          case IFLA_LINKINFO: /* ??? */
            printf("[%d][LINKINFO] ... len=%d\n", inf_msg_ptr-&gt;ifi_index,
                   rta_ptr-&gt;rta_len);
            break;
  
          case IFLA_IFALIAS: /* alias of the interface - outdated since one
                                interface can have multiple addrs. */
            printf("[%d][IFALIAS] %s\n", inf_msg_ptr-&gt;ifi_index,
                   RTA_DATA(rta_ptr));
            break;
  
          case IFLA_STATS64: /* stats with 64 bit values */
            printf("[%d][STATS64] ...\n", inf_msg_ptr-&gt;ifi_index);
            break;
  
          case IFLA_GROUP: /* the group to which the interface belongs to ??? */
            memcpy(&amp;tmp_int, RTA_DATA(rta_ptr), 4);
            printf("[%d][GROUP] %d\n", inf_msg_ptr-&gt;ifi_index, tmp_int);
            break;
  
          case IFLA_PROMISCUITY: /* if &gt; 0, the interface is in promisc mode */
            memcpy(&amp;tmp_int, RTA_DATA(rta_ptr), 4);
            printf("[%d][PROMISCUITY] %d\n", inf_msg_ptr-&gt;ifi_index, tmp_int);
            break;
  
          case IFLA_CARRIER: /* if &gt; 0, the interface has a carrier e.g. is
                                connected to something (???) */
            memcpy(&amp;tmp_int, RTA_DATA(rta_ptr), 4);
            printf("[%d][CARRIER] %d\n", inf_msg_ptr-&gt;ifi_index, tmp_int);
            break;
  
          case IFLA_PAD: /* ??? */
            printf("[%d][PAD] len=%d\n", inf_msg_ptr-&gt;ifi_index,
                   rta_ptr-&gt;rta_len);
            break;
  
          case IFLA_XDP: /* something about packet filtering ... ??? */
            printf("[%d][XDP] len=%d\n", inf_msg_ptr-&gt;ifi_index,
                   rta_ptr-&gt;rta_len);
            break;
  
          case IFLA_EVENT: /* ??? */
            printf("[%d][EVENT] len=%d\n", inf_msg_ptr-&gt;ifi_index,
                   rta_ptr-&gt;rta_len);
            break;
  
          default:
            printf("[%d][UNKNOWN] len=%d tmp_int=%d\n", inf_msg_ptr-&gt;ifi_index,
                   rta_ptr-&gt;rta_len, rta_ptr-&gt;rta_type);
            break;
          };
        }
  
        answer_size -= NLMSG_ALIGN(len);
        nl_msg_ptr = (struct nlmsghdr *)((char *)nl_msg_ptr + NLMSG_ALIGN(len));
      }
    }
    return (0);
  }
  </code></pre>
  
  <p>My biggest problem is that I don't know what some of the attribute types mean and what form they have (<em>char[], int, unsigned int, ...</em>).
  Also, I don't know how to handle "nested" attributes like <em>IFLA_LINKINFO</em>.
  A summary of attributes I have problems with:</p>
  
  <pre><code>IFLA_LINK, IFLA_COST, IFLA_PRIORITY, IFLA_MASTER, IFLA_WIRELESS, IFLA_PROTINFO, IFLA_MAP, IFLA_WEIGHT, IFLA_LINKINFO, IFLA_AF_SPEC, IFLA_GROUP, IFLA_NUM_RX_QUEUES, IFLA_NUM_TX_QUEUES, IFLA_CARRIER, IFLA_CARRIER_CHANGES, IFLA_PROTO_DOWN, IFLA_GSO_MAX_SEGS, IFLA_GSO_MAX_SIZE, IFLA_PAD, IFLA_CARRIER_UP_COUNT, IFLA_CARRIER_DOWN_COUNT, IFLA_EVENT 
  </code></pre>
  
  <p>... so basically with all of them.
  I used <em>/usr/include/linux/if_link.h</em> as reference for the attribute types.</p>
  
  <p>Any kind of help on any of my questions would be really nice! (Also feedback on my code) -- Thanks in advance!</p>