MINZKN.COM |  |  | Services | About

1.1. 개요

netlink.png
[PNG image (982 Bytes)]

Netlink 는 Kernel과 User space간 원활한 정보교류를 위한 비교적 유연한 통신 방식입니다.

본 내용을 이해하기 위해서 다음의 Linux kernel header 를 먼저 열어보시고 함께 보시면 좋습니다.
  • "<linux/netlink.h>"
    #define NETLINK_<XXX> ...
    #define NLM_F_<XXX> ...
    
    #define NLMSG_ALIGNTO   4U
    #define NLMSG_ALIGN(len) ( ((len)+NLMSG_ALIGNTO-1) & ~(NLMSG_ALIGNTO-1) )
    #define NLMSG_HDRLEN     ((int) NLMSG_ALIGN(sizeof(struct nlmsghdr)))
    #define NLMSG_LENGTH(len) ((len) + NLMSG_HDRLEN)
    #define NLMSG_SPACE(len) NLMSG_ALIGN(NLMSG_LENGTH(len))
    #define NLMSG_DATA(nlh)  ((void*)(((char*)nlh) + NLMSG_LENGTH(0)))
    #define NLMSG_NEXT(nlh,len)      ((len) -= NLMSG_ALIGN((nlh)->nlmsg_len), \
                                      (struct nlmsghdr*)(((char*)(nlh)) + NLMSG_ALIGN((nlh)->nlmsg_len)))
    #define NLMSG_OK(nlh,len) ((len) >= (int)sizeof(struct nlmsghdr) && \
                               (nlh)->nlmsg_len >= sizeof(struct nlmsghdr) && \
                               (nlh)->nlmsg_len <= (len))
    #define NLMSG_PAYLOAD(nlh,len) ((nlh)->nlmsg_len - NLMSG_SPACE((len)))
    
    #define NLMSG_NOOP              0x1     /* Nothing.             */
    #define NLMSG_ERROR             0x2     /* Error                */
    #define NLMSG_DONE              0x3     /* End of a dump        */
    #define NLMSG_OVERRUN           0x4     /* Data lost            */
    
    #define NLMSG_MIN_TYPE          0x10    /* < 0x10: reserved control messages */
    
    #define NLA_ALIGNTO             4
    #define NLA_ALIGN(len)          (((len) + NLA_ALIGNTO - 1) & ~(NLA_ALIGNTO - 1))
    #define NLA_HDRLEN              ((int) NLA_ALIGN(sizeof(struct nlattr)))
    
    struct sockaddr_nl { ... };
    struct nlmsghdr { ... };
    struct nlattr { ... };
    
  • "<linux/genetlink.h>"
    #define GENL_HDRLEN     NLMSG_ALIGN(sizeof(struct genlmsghdr))
    #define GENL_ID_CTRL            NLMSG_MIN_TYPE
    
    enum {
    ...
            CTRL_ATTR_FAMILY_ID,
            CTRL_ATTR_FAMILY_NAME,
    ...
    };
    
    struct genlmsghdr { ... };
    
  • "<linux/rtnetlink.h>"
    #define RTA_ALIGNTO     4U
    #define RTA_ALIGN(len) ( ((len)+RTA_ALIGNTO-1) & ~(RTA_ALIGNTO-1) )
    #define RTA_OK(rta,len) ((len) >= (int)sizeof(struct rtattr) && \
                             (rta)->rta_len >= sizeof(struct rtattr) && \
                             (rta)->rta_len <= (len))
    #define RTA_NEXT(rta,attrlen)   ((attrlen) -= RTA_ALIGN((rta)->rta_len), \
                                     (struct rtattr*)(((char*)(rta)) + RTA_ALIGN((rta)->rta_len)))
    #define RTA_LENGTH(len) (RTA_ALIGN(sizeof(struct rtattr)) + (len))
    #define RTA_SPACE(len)  RTA_ALIGN(RTA_LENGTH(len))
    #define RTA_DATA(rta)   ((void*)(((char*)(rta)) + RTA_LENGTH(0)))
    #define RTA_PAYLOAD(rta) ((int)((rta)->rta_len) - RTA_LENGTH(0))
    
    struct rtattr { ... };
    struct rtmsg { ... };
    
  • "<linux/if_addr.h>"
  • "<linux/if_link.h>"
  • "<linux/netconf.h>"
  • "<linux/neighbour.h>"
  • "<linux/xfrm.h>" : (Transform) IPSec VPN에 관련한 Netlink 정의

  • 예제소스
  • 1.2. netlink message format

    기본적으로 Netlink message는 하나 이상을 연속으로 붙여 하나의 요청(Request) 또는 응답(Response) 단위로 묶어 전송구현합니다.
    
     +----------------------+----------------------+----------------------+----------------------+ ~ ~ ~ ~ ~ +----------------------+
     |  Netlink messaeg #1  |  Netlink messaeg #2  |  Netlink messaeg #3  |  Netlink messaeg #4  |    ...    |  Netlink messaeg #n  |
     | (Header+Payload+Pad) | (Header+Payload+Pad) | (Header+Payload+Pad) | (Header+Payload+Pad) |           | (Header+Payload+Pad) |
     +----------------------+----------------------+----------------------+----------------------+ ~ ~ ~ ~ ~ +----------------------+
    
     <--------------------------------------------------- Request OR Response packet ----------------------------------------------->
    
    


    하나의 Netlink message의 Header와 Payload는 각각 정렬(Align)된 형태를 맞추기 위해서 Padding 을 포함할 수 있습니다. (정렬의 크기는 "<linux/netlink.h>" kernel header에 정의된 NLMSG_ALIGNTO 정의를 기준으로 하며 NLMSG_ALIGN macro 함수를 사용하여 계산할 수 있습니다.)

    • Netlink message format
      Netlink message format
      0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 Description
      32bit Length (Header를 포함한 message 크기) ↑↓16 bytes NLMSG_HDRLEN
      (struct nlmsghdr)
      ↑↓Netlink message
      (nlmsghdr.nlmsg_len)
      16-bit Type (Message content) 16-bit Flags (Additional flags)
      32bit Sequence Number
      32bit Process ID (PID, Sending process port ID)
      Payload (Variable data)
      data_ptr = NLMSG_DATA(nlmsghdr)
      ↑↓(nlmsghdr.nlmsg_len - NLMSG_HDRLEN)

    • Netlink message overview
        <----- NLMSG_HDRLEN ------> <-------- Payload-Len -------->
       +---------------------+- - -+- - - - - - - - - - - - - - - -+ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
       |        Header       | Pad |            Payload            | ... (Next netlink message) ...
       |  (struct nlmsghdr)  | ing | Specific data + [attribute..] |
       +---------------------+- - -+- - - - - - - - - - - - - - - -+ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
       ↑ nlmsghdr                  ↑ NLMSG_DATA(&nlmsghdr)         ↑ NLMSG_NEXT(&nlmsghdr)
        <------------------ nlmsghdr->nlmsg_len ------------------>
        <------------------ NLMSG_LENGTH(Payload-Len) ------------>
      
        Payload의 선두부분은 nlmsg_type에 따른 고유 구조체(Specific data) 형식이 올 수 있으며 NLMSG_ALIGN(sizeof(Specific data)) 정렬 후 그 다음에 attribute로 구성되는게 일반적입니다.
      


    • Netlink attribute overview (Netlink message payload 내에서 Specific data 뒷부분에 선택적으로 추가됨)
        <------- NLA_HDRLEN ------> <-- NLA_ALIGN(payload)-->
       +---------------------+- - -+- - - - - - - - - -+- - -+ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
       |        Header       | Pad |     Payload       | Pad | ... (Next attribute) ...
       |   (struct nlattr)   | ing |                   | ing |
       +---------------------+- - -+- - - - - - - - - -+- - -+ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
       ↑ nlattr
        <-------------- nlattr->nla_len -------------->
      


    • netlink header struct
       struct nlmsghdr {
           uint32_t nlmsg_len;      /* Header를 포함한 Netlink message 크기 */
           uint16_t nlmsg_type;     /* Message content */
           uint16_t nlmsg_flags;    /* Additional flags */
           uint32_t nlmsg_seq;      /* Sequence number */
           uint32_t nlmsg_pid;      /* Sending process port ID */
       };
      


    • netlink attribute header struct
       struct nlattr {
           uint16_t nla_len; /* Header를 포함한 attribute 크기 */
           uint16_t nla_type; /* Attribute type */
       };
      


    1.3. Generic Netlink message Overview

      0                   1                   2                   3
      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |                Netlink message header (nlmsghdr)              |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |           Generic Netlink message header (genlmsghdr)         |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |             Optional user specific message header             |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |           Optional Generic Netlink message payload            |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    


    "iotop" 명령어가 task 상태에 대한 모니터링을 위한 구현을 위해서 Generic Netlink를 사용하는 대표적 사용예입니다.

    1.4. 구현사항에 대한 간략한 골격구조 설명

    1. Netlink socket을 XFRM쪽으로 open
      s_socket = socket(PF_NETLINK, SOCK_RAW, NETLINK_XFRM /* 6 - ipsec */);
      


    2. XFRM모듈쪽의 어떤 Group 과 통신할지를 binding
      __u32 s_nl_groups;
      struct sockaddr_nl s_sockaddr_nl;
      
      s_nl_groups |= XFRMNLGRP_ACQUIRE;
      s_nl_groups |= XFRMNLGRP_EXPIRE;
      s_nl_groups |= XFRMNLGRP_SA;
      s_nl_groups |= XFRMNLGRP_POLICY;
      s_nl_groups |= XFRMNLGRP_AEVENTS;
      s_nl_groups |= XFRMNLGRP_REPORT;
      s_nl_groups |= XFRMNLGRP_MIGRATE;
      s_nl_groups |= XFRMNLGRP_MAPPING;
      
      s_sockaddr_nl.nl_family = AF_NETLINK;
      s_sockaddr_nl.nl_pad = (unsigned short)0u;
      s_sockaddr_nl.nl_pid = (pid_t)0;
      s_sockaddr_nl.nl_groups = s_nl_groups; /* Multicast groups mask */
      
      bind(s_socket, (const struct sockaddr *)(&s_sockaddr_nl), (socklen_t)sizeof(s_sockaddr_nl));
      


    3. netlink socket으로부터 Netlink protocol RAW 수신
      socklen_t s_socklen;
      
      s_socklen = (socklen_t)sizeof(s_sockaddr_nl);
      s_recv_bytes = recvfrom(
          s_socket,
          s_buffer,
          s_buffer_size,
          MSG_NOSIGNAL,
          (struct sockaddr *)(&s_sockaddr_nl),
          (socklen_t *)(&s_socklen)
      );
      


    4. 수신된 Netlink protocol RAW data에서 Netlink header 를 통해서 각 요소별 분리
      size_t s_msg_size;
      struct nlmsghdr *s_nlmsghdr;
      size_t s_payload_size;
      void *s_payload;
      
      s_msg_size = (size_t)s_recv_bytes;
      for(s_nlmsghdr = (struct nlmsghdr *)s_buffer;(s_is_break == 0) && NLMSG_OK(s_nlmsghdr, s_msg_size);s_nlmsghdr = NLMSG_NEXT(s_nlmsghdr, s_msg_size)) {            /* Netlink 수신패킷 하나에 여러개의 Netlink header가 탑재될 수 있는데 이를 각 Header 단위로 분리하는 Loop */
          s_payload_size = (size_t)NLMSG_PAYLOAD(s_nlmsghdr, 0); /* Header 내의 실제 Data 크기 */
          s_payload = NLMSG_DATA(s_nlmsghdr); /* Header 내의 실제 Data 위치 포인터 */
      
          switch(s_nlmsghdr->nlmsg_type) { /* 각 메세지의 종류별로 다른 파싱구조를 가지고 있으므로 커널을 참조하여 해당 부분을 파싱해야 합니다. */
              .....
          }
      }
      

    1.5. 실제 VPN 장비에서 VPN연결과정에서 본 예제프로그램으로 Netlink 통신을 수신하여 파싱된 내용을 모니터링한 콘솔내용

    내용을 보시려면 여기를 클릭해주세요.

    1.6. Netlink 를 가공하기 위한 함수 예시

    • Netlink를 다루기 위한 기본 macro 를 포함하기 위한 include
      #include <linux/netlink.h>
      #include <linux/genetlink.h>
      
    • Netlink message (NLMSG) build 함수
      size_t hwport_generate_netlink_message(void *s_buffer, size_t s_buffer_size, unsigned int s_nlmsg_type, unsigned int s_nlmsg_flags, unsigned int s_nlmsg_seq, unsigned int s_nlmsg_pid, const void *s_payload, size_t s_payload_size)
      {
              int s_aligned_payload_size;
      
              struct nlmsghdr *s_nlmsghdr;
              void *s_payload_ptr;
      
              s_aligned_payload_size = (int)NLMSG_ALIGN((uint32_t)s_payload_size);
              if (s_buffer_size < ((size_t)NLMSG_LENGTH(s_aligned_payload_size))) {
                      return((size_t)0u);
              }
      
              s_nlmsghdr = (struct nlmsghdr *)memset(s_buffer, 0, sizeof(struct nlmsghdr));
              s_nlmsghdr->nlmsg_len = (uint32_t)NLMSG_LENGTH(s_aligned_payload_size);
              s_nlmsghdr->nlmsg_type = (uint16_t)s_nlmsg_type;
              s_nlmsghdr->nlmsg_flags = (uint16_t)s_nlmsg_flags;
              s_nlmsghdr->nlmsg_seq = (uint32_t)s_nlmsg_seq;
              s_nlmsghdr->nlmsg_pid = (uint32_t)s_nlmsg_pid;
      
              s_payload_ptr = (void *)NLMSG_DATA(s_nlmsghdr);
              if (s_payload_size > ((size_t)0u)) {
                      if (s_payload == ((const void *)(NULL))) {
                              (void)memset(s_payload_ptr, 0, s_payload_size);
                      }
                      else {
                              (void)memcpy(s_payload_ptr, s_payload, s_payload_size);
                      }
              }
      
              return((size_t)s_nlmsghdr->nlmsg_len);
      }
      
    • Netlink attribute (NLA) build append 함수
      size_t hwport_append_netlink_attr(void *s_buffer, size_t s_buffer_size, unsigned int s_nla_type, const void *s_attr1, size_t s_attr1_size, const void *s_attr2, size_t s_attr2_size)
      {
              struct nlmsghdr *s_nlmsghdr;
              struct nlattr *s_nlattr;
              size_t s_attr_size;
              void *s_attr_ptr;
      
              s_attr_size = s_attr1_size + s_attr2_size;
      
              s_nlmsghdr = (struct nlmsghdr *)s_buffer;
              if (s_buffer_size < ((size_t)(s_nlmsghdr->nlmsg_len + NLA_HDRLEN + NLA_ALIGN(s_attr_size)))) {
                      return((size_t)0u);
              }
      
              s_nlattr = (struct nlattr *)(((uint8_t *)s_buffer) + s_nlmsghdr->nlmsg_len);
              s_nlattr->nla_len = (uint16_t)NLA_HDRLEN + s_attr_size;
              s_nlattr->nla_type = (uint16_t)s_nla_type;
      
              s_attr_ptr = (void *)(((uint8_t *)s_nlattr) + NLA_HDRLEN);
              if(s_attr1_size > ((size_t)0u)) {
                      if(s_attr1 == ((const void *)0)) {
                              (void)memset((void *)s_attr_ptr, 0, s_attr1_size);
                      }
                      else if(((const void *)s_attr_ptr) != s_attr1) {
                              (void)memcpy((void *)s_attr_ptr, s_attr1, s_attr1_size);
                      }
      
                      s_attr_ptr = (void *)(((uint8_t *)s_attr_ptr) + s_attr1_size);
              }
              if(s_attr2_size > ((size_t)0u)) {
                      if(s_attr2 == ((const void *)0)) {
                              (void)memset((void *)s_attr_ptr, 0, s_attr2_size);
                      }
                      else if(((const void *)s_attr_ptr) != s_attr2) {
                              (void)memcpy((void *)s_attr_ptr, s_attr2, s_attr2_size);
                      }
              }
      
              s_nlmsghdr->nlmsg_len += (uint32_t)NLA_ALIGN(s_nlattr->nla_len);
      
              return((size_t)s_nlmsghdr->nlmsg_len);
      }
      
    • Netlink message request 함수
      ssize_t hwport_request_generic_netlink(int s_socket, const void *s_data, size_t s_size, const struct sockaddr *s_sockaddr, socklen_t s_socklen)
      {
              size_t s_sent_size;
              size_t s_want_size;
              ssize_t s_send_bytes;
              const uint8_t *s_uint8_ptr;
              struct sockaddr_nl s_sockaddr_nl;
      
              if (s_socket == (-1)) {
                      errno = EINVAL;
                      return((ssize_t)(-1));
              }
      
              if (s_sockaddr == ((struct sockaddr *)(NULL))) {
                      s_socklen = (socklen_t)sizeof(s_sockaddr_nl);
                      s_sockaddr = (const struct sockaddr *)memset((void *)(&s_sockaddr_nl), 0, sizeof(s_sockaddr_nl));
                      s_sockaddr_nl.nl_family = AF_NETLINK;
                      s_sockaddr_nl.nl_pid = 0; /* port ID */
                      s_sockaddr_nl.nl_groups = 0; /* multicast groups mask */
              }
      
              s_sent_size = (size_t)0u;
              s_uint8_ptr = (const uint8_t *)s_data;
              while (s_sent_size < s_size) {
                      s_want_size = s_size - s_sent_size;
                      s_send_bytes = sendto(
                              s_socket,
                              (const void *)(&s_uint8_ptr[s_sent_size]),
                              s_want_size,
                              MSG_NOSIGNAL,
                              s_sockaddr,
                              s_socklen
                      );
                      if (s_send_bytes > ((ssize_t)0)) {
                              s_sent_size += (size_t)s_send_bytes;
                      }
                      else if((s_send_bytes == ((ssize_t)(-1))) && ((errno == EINTR) || (errno == EAGAIN))) {
                              continue;
                      }
                      else { /* error */
                              return(s_send_bytes);
                      }
              }
      
              return((ssize_t)s_sent_size);
      }
      
    • Netlink message response 함수
      ssize_t hwport_response_generic_netlink(int s_socket, void *s_data, size_t s_size, struct sockaddr *s_sockaddr, socklen_t *s_socklen_ptr)
      {
              struct sockaddr_storage s_sockaddr_storage;
              socklen_t s_socklen;
      
              if (s_socket == (-1)) {
                      errno = EINVAL;
                      return((ssize_t)(-1));
              }
      
              if (s_sockaddr == ((struct sockaddr *)(NULL))) {
                      s_sockaddr = (struct sockaddr *)memset((void *)(&s_sockaddr_storage), 0, sizeof(s_sockaddr_storage));
              }
              if (s_socklen_ptr == ((socklen_t *)(NULL))) {
                      s_socklen = (socklen_t)sizeof(struct sockaddr_nl);
                      s_socklen_ptr = (socklen_t *)(&s_socklen);
              }
      
              return(recvfrom(s_socket, s_data, s_size, MSG_NOSIGNAL, s_sockaddr, s_socklen_ptr));
      }
      
    • Generic Netlink message 중에서 Family Name으로 요청하여 Family ID를 얻는 함수
      int hwport_get_family_id_by_name(int s_socket, const char *s_family_name)
      {
              int s_family_id;
              size_t s_family_name_size;
      
              uint8_t s_buffer[ 4 << 10 ];
              size_t s_message_size;
              size_t s_offset;
              int s_is_break;
              struct nlmsghdr *s_nlmsghdr;
              struct genlmsghdr *s_genlmsghdr;
              struct nlattr *s_nlattr;
      
              ssize_t s_send_bytes;
              ssize_t s_recv_bytes;
      
              if (s_socket == (-1)) {
                      errno = EINVAL;
                      return(-1);
              }
      
              if (s_family_name == ((const char *)(NULL))) {
                      errno = EINVAL;
                      return(-1);
              }
              s_family_name_size = strlen(s_family_name);
      
              s_nlmsghdr = (struct nlmsghdr *)(&s_buffer[0]);
              s_message_size = hwport_generate_netlink_message(
                      (void *)s_nlmsghdr,
                      sizeof(s_buffer),
                      (unsigned int)GENL_ID_CTRL, /* nlmsg_type */
                      (unsigned int)NLM_F_REQUEST /* | NLM_F_ACK */, /* nlmsg_flags */
                      0u, /* nlmsg_seq */
                      (unsigned int)getpid(), /* nlmsg_pid */
                      (const void *)(NULL), /* payload */
                      sizeof(struct genlmsghdr)
              );
              if (s_message_size <= ((size_t)0u)) {
                      errno = ENOMEM;
                      return(-1);
              }
      
              s_genlmsghdr = (struct genlmsghdr *)memset((void *)NLMSG_DATA(s_nlmsghdr), 0, sizeof(struct genlmsghdr));
              s_genlmsghdr->cmd = CTRL_CMD_GETFAMILY; /* SeeAlso : CTRL_CMD_XXXX in "include/uapi/linux/genetlink.h" */
              s_genlmsghdr->version = 1 /* 해당 message 종류에 따른 VERSION을 넣어야 함 */;
      
              s_message_size = hwport_append_netlink_attr(
                      (void *)s_nlmsghdr,
                      sizeof(s_buffer),
                      (unsigned int)CTRL_ATTR_FAMILY_NAME, /* nla_type */
                      (const void *)s_family_name, /* attr1 */
                      s_family_name_size + ((size_t)1u), /* attr1_size (family name 은 문자열 뒤의 nul terminate까지 포함한 길이여야 함) */
                      (const void *)(NULL), /* attr2 */
                      (size_t)0u /* attr2_size */
              );
              if (s_message_size <= ((size_t)0u)) {
                      errno = ENOMEM;
                      return(-1);
              }
      
              s_send_bytes = hwport_request_generic_netlink(
                      s_socket,
                      (const void *)s_nlmsghdr,
                      s_message_size,
                      (const struct sockaddr *)(NULL),
                      (socklen_t)0
              );
              if (s_send_bytes <= ((ssize_t)0)) {
                      return(-1);
              }
      
              s_recv_bytes = hwport_response_generic_netlink(
                      s_socket,
                      (void *)(&s_buffer[0]),
                      sizeof(s_buffer),
                      (struct sockaddr *)(NULL),
                      (socklen_t *)(NULL)
              );
              if (s_recv_bytes <= ((ssize_t)0)) {
                      return(-1);
              }
      
              s_family_id = (-1);
      
              s_is_break = 0;
              s_message_size = (size_t)s_recv_bytes;
              for (s_nlmsghdr = (struct nlmsghdr *)(&s_buffer[0]);(s_is_break == 0) && NLMSG_OK(s_nlmsghdr, s_message_size);s_nlmsghdr = NLMSG_NEXT(s_nlmsghdr, s_message_size)) {
                      /* payload_size = (size_t)NLMSG_PAYLOAD(s_nlmsghdr, 0); */
                      /* payload = NLMSG_DATA(s_nlmsghdr); */
      
                      switch(s_nlmsghdr->nlmsg_type) {
                              case NLMSG_NOOP:
                                      break;
                              case NLMSG_ERROR:
                                      s_is_break = 1;
                                      break;
                              case NLMSG_DONE:
                                      s_is_break = 1;
                                      break;
                              case NLMSG_OVERRUN:
                                      s_is_break = 1;
                                      break;
                              case GENL_ID_CTRL: /* NLMSG_MIN_TYPE */
                                      s_genlmsghdr = (struct genlmsghdr *)NLMSG_DATA(s_nlmsghdr);
                                      for (s_offset = (size_t)(NLMSG_HDRLEN + NLMSG_ALIGN(sizeof(struct genlmsghdr)));s_offset < s_nlmsghdr->nlmsg_len;) {
                                              if ((s_offset + ((size_t)NLA_HDRLEN)) > ((size_t)s_nlmsghdr->nlmsg_len)) {
                                                      /* attibute header 만큼이 남지 않았음. */
                                                      break;
                                              }
      
                                              s_nlattr = (struct nlattr *)(((uint8_t *)s_nlmsghdr) + s_offset);
                                              if (s_nlattr->nla_len < ((size_t)NLA_HDRLEN)) {
                                                      /* attribute length 가 최소 크기를 만족하지 못함 */
                                                      break;
                                              }
      
                                              if ((s_offset + ((size_t)NLA_ALIGN(s_nlattr->nla_len))) > ((size_t)s_nlmsghdr->nlmsg_len)) {
                                                      /* attribute 공간이 nlmsg를 넘어섬 */
                                                      break;
                                              }
      
                                              switch(s_nlattr->nla_type) { /* SeeAlso : CTRL_ATTR_XXXX in "include/uapi/linux/genetlink.h" */
                                                      case CTRL_ATTR_UNSPEC: /* 0 */
                                                              break;
                                                      case CTRL_ATTR_FAMILY_ID: /* 1 */
                                                              s_family_id = (int)(*((uint16_t *)(((uint8_t *)s_nlattr) + NLA_HDRLEN)));
      #if 1L
                                                              if (s_family_id != (-1)) {
                                                                      /* family id 를 인지했으므로 더이상의 attr은 볼 필요가 없음 */
                                                                      s_is_break = 1;
                                                                      break;
                                                              }
      #endif
                                                              break;
                                                      case CTRL_ATTR_FAMILY_NAME: /* 2 */
                                                              break;
                                                      case CTRL_ATTR_VERSION: /* 3 */
                                                              break;
                                                      case CTRL_ATTR_HDRSIZE: /* 4 */
                                                              break;
                                                      case CTRL_ATTR_MAXATTR: /* 5 */
                                                              break;
                                                      case CTRL_ATTR_OPS: /* 6 */
                                                              break;
                                                      case CTRL_ATTR_MCAST_GROUPS: /* 7 */
                                                              break;
                                                      default: /* 8 >= */
                                                              break;
                                              }
      
                                              s_offset += (size_t)NLA_ALIGN(s_nlattr->nla_len);
                                      }
                                      break;
                              default:
                                      break;
                      }
              }
      
              return(s_family_id);
      }
      
    • Generic Netlink socket open 함수
      int hwport_open_generic_netlink(uint32_t s_port_id, uint32_t s_groups_mask)
      {
              int s_socket;
              struct sockaddr_nl s_sockaddr_nl;
      
              s_socket = socket(PF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
              if (s_socket == (-1)) {
                      return(-1);
              }
      
              (void)memset((void *)(&s_sockaddr_nl), 0, sizeof(s_sockaddr_nl));
              s_sockaddr_nl.nl_family = AF_NETLINK;
      #if 0L
              s_sockaddr_nl.nl_pad = 0;
      #endif
              s_sockaddr_nl.nl_pid = s_port_id; /* port ID */
              s_sockaddr_nl.nl_groups = s_groups_mask; /* multicast groups mask */
              if (bind(s_socket, (struct sockaddr *)(&s_sockaddr_nl), (socklen_t)sizeof(s_sockaddr_nl)) == (-1)) {
                      int s_check;
                      int s_save_errno;
      
                      s_save_errno = errno;
                      do {
                              s_check = close(s_socket);
                      }while((s_check == (-1)) && (errno == EINTR));
                      errno = s_save_errno;
                      return(-1);
              }
      
              return(s_socket);
      }
      
    • Generic Netlink socket close 함수
      int hwport_close_generic_netlink(int s_socket)
      {
              int s_check;
      
              if (s_socket == (-1)) {
                      errno = EINVAL;
                      return(-1);
              }
      
              do {
                      s_check = close(s_socket);
              }while((s_check == (-1)) && (errno == EINTR));
      
              return(s_check);
      }
      


    Copyright ⓒ MINZKN.COM
    All Rights Reserved.