LCOV - code coverage report
Current view: top level - root/contrail/vrouter/utils - nl_util.c (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 176 334 52.7 %
Date: 2026-08-03 02:19:58 Functions: 28 49 57.1 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * nl_util.c -- netlink utility functions common for all the utilities
       3             :  *
       4             :  * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
       5             :  */
       6             : #include <stdio.h>
       7             : #include <stdlib.h>
       8             : #include <unistd.h>
       9             : #include <string.h>
      10             : #include <stdbool.h>
      11             : #include <errno.h>
      12             : #include <stdlib.h>
      13             : #include <assert.h>
      14             : #include <errno.h>
      15             : 
      16             : #if defined(__linux__)
      17             : #include <asm/types.h>
      18             : #include <sys/socket.h>
      19             : #include <linux/netlink.h>
      20             : #include <linux/rtnetlink.h>
      21             : #include <linux/genetlink.h>
      22             : #include <linux/sockios.h>
      23             : #include <linux/dcbnl.h>
      24             : #include <linux/socket.h>
      25             : #endif
      26             : 
      27             : #include <stdint.h>
      28             : #include <net/if.h>
      29             : #include <netinet/in.h>
      30             : #include "vr_types.h"
      31             : #include "nl_util.h"
      32             : #include "vr_genetlink.h"
      33             : #include "vr_os.h"
      34             : 
      35             : extern struct nl_response *nl_parse_gen(struct nl_client *);
      36             : 
      37             : uint16_t vr_netlink_port = VR_DEF_NETLINK_PORT;
      38             : char *vr_socket_dir = VR_DEF_SOCKET_DIR;
      39             : struct nl_sandesh_callbacks nl_cb;
      40             : 
      41             : void
      42           0 : vrouter_ops_process(void *s_req)
      43             : {
      44           0 :     if (nl_cb.vrouter_ops_process) {
      45           0 :         nl_cb.vrouter_ops_process(s_req);
      46             :     }
      47           0 : }
      48             : 
      49             : void
      50          25 : vr_nexthop_req_process(void *s_req)
      51             : {
      52          25 :     if (nl_cb.vr_nexthop_req_process) {
      53          25 :         nl_cb.vr_nexthop_req_process(s_req);
      54             :     }
      55          25 : }
      56             : 
      57             : 
      58             : void
      59           0 : vr_flow_req_process(void *s_req)
      60             : {
      61           0 :     if (nl_cb.vr_flow_req_process) {
      62           0 :         nl_cb.vr_flow_req_process(s_req);
      63             :     }
      64           0 : }
      65             : 
      66             : void
      67         322 : vr_flow_response_process(void *s_req)
      68             : {
      69         322 :     if (nl_cb.vr_flow_response_process) {
      70         322 :         nl_cb.vr_flow_response_process(s_req);
      71             :     }
      72         322 : }
      73             : 
      74             : void
      75          13 : vr_flow_table_data_process(void *s_req)
      76             : {
      77          13 :     if (nl_cb.vr_flow_table_data_process) {
      78          13 :         nl_cb.vr_flow_table_data_process(s_req);
      79             :     }
      80          13 : }
      81             : 
      82             : void
      83         331 : vr_route_req_process(void *s_req)
      84             : {
      85         331 :     if (nl_cb.vr_route_req_process) {
      86         331 :         nl_cb.vr_route_req_process(s_req);
      87             :     }
      88         331 : }
      89             : 
      90             : void
      91         163 : vr_interface_req_process(void *s_req)
      92             : {
      93         163 :     if (nl_cb.vr_interface_req_process) {
      94         163 :         nl_cb.vr_interface_req_process(s_req);
      95             :     }
      96         163 : }
      97             : 
      98             : void
      99           1 : vr_mpls_req_process(void *s_req)
     100             : {
     101           1 :     if (nl_cb.vr_mpls_req_process) {
     102           1 :         nl_cb.vr_mpls_req_process(s_req);
     103             :     }
     104           1 : }
     105             : 
     106             : void
     107           1 : vr_mirror_req_process(void *s_req)
     108             : {
     109           1 :     if (nl_cb.vr_mirror_req_process) {
     110           1 :         nl_cb.vr_mirror_req_process(s_req);
     111             :     }
     112           1 : }
     113             : 
     114             : void
     115           0 : vr_vrf_req_process(void *s_req)
     116             : {
     117           0 :     if (nl_cb.vr_vrf_req_process) {
     118           0 :         nl_cb.vr_vrf_req_process(s_req);
     119             :     }
     120           0 : }
     121             : 
     122             : void
     123        2862 : vr_response_process(void *s_req)
     124             : {
     125        2862 :     if (nl_cb.vr_response_process) {
     126        2861 :         nl_cb.vr_response_process(s_req);
     127             :     }
     128        2862 : }
     129             : 
     130             : 
     131             : void
     132           0 : vr_vrf_assign_req_process(void *s_req)
     133             : {
     134           0 :     if (nl_cb.vr_vrf_assign_req_process) {
     135           0 :         nl_cb.vr_vrf_assign_req_process(s_req);
     136             :     }
     137           0 : }
     138             : 
     139             : void
     140           0 : vr_vrf_stats_req_process(void *s_req)
     141             : {
     142           0 :     if (nl_cb.vr_vrf_stats_req_process) {
     143           0 :         nl_cb.vr_vrf_stats_req_process(s_req);
     144             :     }
     145           0 : }
     146             : 
     147             : void
     148           0 : vr_pkt_drop_log_req_process(void *s_req)
     149             : {
     150           0 :    if (nl_cb.vr_pkt_drop_log_req_process) {
     151           0 :        nl_cb.vr_pkt_drop_log_req_process(s_req);
     152             :    }
     153           0 : }
     154             : 
     155             : void
     156           1 : vr_info_req_process(void *s_req)
     157             : {
     158           1 :    if (nl_cb.vr_info_req_process) {
     159           1 :        nl_cb.vr_info_req_process(s_req);
     160             :    }
     161           1 : }
     162             : void
     163          11 : vr_drop_stats_req_process(void *s_req)
     164             : {
     165          11 :     if (nl_cb.vr_drop_stats_req_process) {
     166          11 :         nl_cb.vr_drop_stats_req_process(s_req);
     167             :     }
     168          11 : }
     169             : 
     170             : void
     171           1 : vr_vxlan_req_process(void *s_req)
     172             : {
     173           1 :     if (nl_cb.vr_vxlan_req_process) {
     174           1 :         nl_cb.vr_vxlan_req_process(s_req);
     175             :     }
     176           1 : }
     177             : 
     178             : void
     179           0 : vr_mem_stats_req_process(void *s_req)
     180             : {
     181           0 :     if (nl_cb.vr_mem_stats_req_process) {
     182           0 :         nl_cb.vr_mem_stats_req_process(s_req);
     183             :     }
     184           0 : }
     185             : 
     186             : void
     187           0 : vr_qos_map_req_process(void *s_req)
     188             : {
     189           0 :     if (nl_cb.vr_qos_map_req_process) {
     190           0 :         nl_cb.vr_qos_map_req_process(s_req);
     191             :     }
     192           0 : }
     193             : 
     194             : void
     195           0 : vr_fc_map_req_process(void *s_req)
     196             : {
     197           0 :     if (nl_cb.vr_fc_map_req_process) {
     198           0 :         nl_cb.vr_fc_map_req_process(s_req);
     199             :     }
     200           0 : }
     201             : 
     202             : void
     203           0 : vr_bridge_table_data_process(void *s_req)
     204             : {
     205           0 :     if (nl_cb.vr_bridge_table_data_process) {
     206           0 :         nl_cb.vr_bridge_table_data_process(s_req);
     207             :     }
     208           0 : }
     209             : 
     210             : void
     211           0 : vr_hugepage_config_process(void *s_req)
     212             : {
     213           0 :     if (nl_cb.vr_hugepage_config_process) {
     214           0 :         nl_cb.vr_hugepage_config_process(s_req);
     215             :     }
     216           0 : }
     217             : 
     218             : struct nl_response *
     219           0 : nl_parse_gen_ctrl(struct nl_client *cl)
     220             : {
     221             :     int len;
     222             :     struct nlattr *nla;
     223             :     struct genl_ctrl_message *msg;
     224           0 :     char *buf = cl->cl_buf + cl->cl_buf_offset;
     225           0 :     struct nl_response *resp = &cl->resp;
     226             : 
     227           0 :     msg = (struct genl_ctrl_message *)cl->cl_resp_buf;
     228           0 :     resp->nl_data = (uint8_t *)(msg);
     229           0 :     memset(msg, 0, sizeof(*msg));
     230           0 :     msg->family_id = -1;
     231             : 
     232           0 :     len = cl->cl_msg_len - (cl->cl_buf_offset - cl->cl_msg_start);
     233           0 :     nla = (struct nlattr *)buf;
     234             : 
     235           0 :     while (len > 0 && len > NLA_HDRLEN) {
     236           0 :         if (len < NLA_ALIGN(nla->nla_len))
     237           0 :             return nl_set_resp_err(cl, -EINVAL);
     238             : 
     239           0 :         switch (nla->nla_type) {
     240           0 :         case CTRL_ATTR_FAMILY_NAME:
     241           0 :             strncpy(msg->family_name, NLA_DATA(nla), sizeof(msg->family_name) - 1);
     242           0 :             break;
     243             : 
     244           0 :         case CTRL_ATTR_FAMILY_ID:
     245           0 :             msg->family_id = *(unsigned short *)NLA_DATA(nla);
     246           0 :             break;
     247             : 
     248           0 :         default:
     249           0 :             break;
     250             :         }
     251             : 
     252           0 :         cl->cl_buf_offset += NLA_ALIGN(nla->nla_len);
     253           0 :         len -= NLA_ALIGN(nla->nla_len);
     254           0 :         nla = (struct nlattr *)((char *)nla + NLA_ALIGN(nla->nla_len));
     255             :     }
     256             : 
     257           0 :     return resp;
     258             : }
     259             : 
     260             : 
     261             : struct nl_response *
     262        2863 : nl_parse_gen(struct nl_client *cl)
     263             : {
     264        2863 :     char *buf = cl->cl_buf + cl->cl_buf_offset;
     265             :     struct genlmsghdr *ghdr;
     266        2863 :     struct nl_response *resp = &cl->resp;
     267             :     struct nlattr *nla;
     268             : 
     269        2863 :     if (cl->cl_buf_len < cl->cl_buf_offset + GENL_HDRLEN)
     270           0 :         return nl_set_resp_err(cl, -EINVAL);
     271             : 
     272        2863 :     ghdr = (struct genlmsghdr *)buf;
     273        2863 :     cl->cl_buf_offset += GENL_HDRLEN;
     274             : 
     275        2863 :     resp->nl_op = ghdr->cmd;
     276        2863 :     if (resp->nl_type == NL_MSG_TYPE_GEN_CTRL) {
     277           0 :         return nl_parse_gen_ctrl(cl);
     278             :     } else {
     279        2863 :         nla = (struct nlattr *)(cl->cl_buf + cl->cl_buf_offset);
     280        2863 :         resp->nl_len = nla->nla_len;
     281        2863 :         cl->cl_buf_offset += NLA_HDRLEN;
     282        2863 :         resp->nl_data = (uint8_t *)(cl->cl_buf + cl->cl_buf_offset);
     283        2863 :         return resp;
     284             :     }
     285             : }
     286             : 
     287             : static int
     288      300381 : nl_build_sandesh_attr_without_attr_len(struct nl_client *cl)
     289             : {
     290      300381 :     struct nlattr *nla = (struct nlattr *)
     291      300381 :         ((char *)cl->cl_buf + cl->cl_buf_offset);
     292             : 
     293      300381 :     if (cl->cl_buf_offset + NLA_HDRLEN > cl->cl_buf_len)
     294           0 :         return -ENOMEM;
     295             : 
     296      300381 :     nla->nla_len = NLA_HDRLEN;
     297      300381 :     nla->nla_type = NL_ATTR_VR_MESSAGE_PROTOCOL;
     298      300381 :     cl->cl_buf_offset += NLA_HDRLEN;
     299             : 
     300      300381 :     return 0;
     301             : }
     302             : 
     303             : int
     304      300381 : nl_build_header(struct nl_client *cl, unsigned char **buf, uint32_t *buf_len)
     305             : {
     306             :     int ret;
     307             : 
     308      300381 :     if (!cl->cl_buf)
     309           0 :         return -EINVAL;
     310             : 
     311      300381 :     if (!cl->cl_genl_family_id)
     312           0 :         return -EINVAL;
     313             : 
     314      300381 :     ret = nl_build_nlh(cl, cl->cl_genl_family_id, NLM_F_REQUEST);
     315      300381 :     if (ret)
     316           0 :         return ret;
     317             : 
     318      300381 :     ret = nl_build_genlh(cl, SANDESH_REQUEST, 0);
     319      300381 :     if (ret)
     320           0 :         return ret;
     321             : 
     322      300381 :     ret = nl_build_sandesh_attr_without_attr_len(cl);
     323      300381 :     if (ret)
     324           0 :         return ret;
     325             : 
     326      300381 :     *buf = (unsigned char *)(cl->cl_buf) + cl->cl_buf_offset;
     327      300381 :     *buf_len = cl->cl_buf_len - cl->cl_buf_offset;
     328             : 
     329      300381 :     return 0;
     330             : }
     331             : 
     332             : void
     333      300213 : nl_update_header(struct nl_client *cl, int data_len)
     334             : {
     335             :     /* First update attribute header len for NLA_SANDESH_ATTR */
     336      300213 :     struct nlattr *nla = (struct nlattr *)
     337      300213 :         ((char *)cl->cl_buf + cl->cl_buf_offset - NLA_HDRLEN);
     338             : 
     339      300213 :     assert(nla->nla_type == NL_ATTR_VR_MESSAGE_PROTOCOL);
     340      300213 :     nla->nla_len +=  data_len;
     341             : 
     342      300213 :     cl->cl_buf_offset += data_len;
     343      300213 :     nl_update_nlh(cl);
     344      300213 : }
     345             : 
     346             : int
     347           0 : nl_family_name_attr_length(char *family)
     348             : {
     349           0 :     return NLA_HDRLEN + NLA_ALIGN(strlen(family) + 1);
     350             : }
     351             : 
     352             : int
     353           0 : nl_build_family_name_attr(struct nl_client *cl, char *family)
     354             : {
     355             :     char *buf;
     356             :     int len;
     357           0 :     struct nlattr *nla = (struct nlattr *)
     358           0 :         ((char *)cl->cl_buf + cl->cl_buf_offset);
     359             : 
     360           0 :     len = nl_family_name_attr_length(family);
     361           0 :     if (cl->cl_buf_offset + len > cl->cl_buf_len)
     362           0 :         return -ENOMEM;
     363             : 
     364           0 :     nla->nla_len = len;
     365           0 :     nla->nla_type = CTRL_ATTR_FAMILY_NAME;
     366           0 :     cl->cl_buf_offset += NLA_HDRLEN;
     367             : 
     368           0 :     buf = (char *)cl->cl_buf + cl->cl_buf_offset;
     369           0 :     strcpy(buf, family);
     370           0 :     cl->cl_buf_offset += NLA_ALIGN(strlen(family) + 1);
     371             : 
     372           0 :     return 0;
     373             : }
     374             : 
     375             : 
     376             : int
     377           0 : nl_build_get_family_id(struct nl_client *cl, char *family)
     378             : {
     379             :     int ret;
     380             : 
     381           0 :     if (!cl->cl_buf)
     382           0 :         return -ENOMEM;
     383             : 
     384           0 :     ret = nl_build_nlh(cl, GENL_ID_CTRL, NLM_F_REQUEST);
     385           0 :     if (ret)
     386           0 :         return ret;
     387             : 
     388           0 :     ret = nl_build_genlh(cl, CTRL_CMD_GETFAMILY, 0);
     389           0 :     if (ret)
     390           0 :         return ret;
     391             : 
     392           0 :     ret = nl_build_family_name_attr(cl, family);
     393           0 :     if (ret)
     394           0 :         return ret;
     395             : 
     396           0 :     nl_update_nlh(cl);
     397             : 
     398           0 :     return 0;
     399             : }
     400             : 
     401             : int
     402      303243 : nl_build_genlh(struct nl_client *cl, uint8_t cmd, uint8_t version)
     403             : {
     404      303243 :     struct genlmsghdr *genlh = (struct genlmsghdr *)
     405      303243 :         ((char *)cl->cl_buf + cl->cl_buf_offset);
     406             : 
     407      303243 :     if (cl->cl_buf_offset + GENL_HDRLEN > cl->cl_buf_len)
     408           0 :         return -ENOMEM;
     409             : 
     410      303243 :     genlh->cmd = cmd;
     411      303243 :     genlh->version = version;
     412      303243 :     genlh->reserved = 0;
     413             : 
     414      303243 :     cl->cl_buf_offset += GENL_HDRLEN;
     415             : 
     416      303243 :     return 0;
     417             : }
     418             : 
     419             : 
     420             : struct nl_response *
     421           0 : nl_set_resp_err(struct nl_client *cl, int error)
     422             : {
     423           0 :     struct nl_response *resp = (struct nl_response *)cl->cl_resp_buf;
     424             : 
     425           0 :     resp->nl_type = NL_MSG_TYPE_ERROR;
     426           0 :     resp->nl_op = error;
     427           0 :     return resp;
     428             : }
     429             : 
     430             : 
     431             : void
     432      303075 : nl_update_nlh(struct nl_client *cl)
     433             : {
     434      303075 :     struct nlmsghdr *nlh = (struct nlmsghdr *)cl->cl_buf;
     435      303075 :     nlh->nlmsg_len = cl->cl_msg_len = cl->cl_buf_offset;
     436      303075 : }
     437             : 
     438             : int
     439        2862 : nl_get_attr_hdr_size()
     440             : {
     441        2862 :     return NLA_HDRLEN;
     442             : }
     443             : 
     444             : uint8_t *
     445        2862 : nl_get_buf_ptr(struct nl_client *cl)
     446             : {
     447        2862 :     return (uint8_t *)(cl->cl_buf + cl->cl_buf_offset);
     448             : }
     449             : 
     450             : uint32_t
     451        2862 : nl_get_buf_len(struct nl_client *cl)
     452             : {
     453        2862 :     return cl->cl_buf_len - cl->cl_buf_offset;
     454             : }
     455             : 
     456             : void
     457           0 : nl_update_attr_len(struct nl_client *cl, int len)
     458             : {
     459             :     struct nlattr *nla;
     460             : 
     461           0 :     nla = (struct nlattr *)cl->cl_attr;
     462           0 :     nla->nla_len += len;
     463           0 :     cl->cl_buf_offset += len;
     464           0 : }
     465             : 
     466             : void
     467        2862 : nl_build_attr(struct nl_client *cl, int len, int attr)
     468             : {
     469             :     struct nlattr *nla;
     470             : 
     471        2862 :     nla = (struct nlattr *)(cl->cl_buf + cl->cl_buf_offset);
     472        2862 :     cl->cl_attr = (uint8_t *)nla;
     473        2862 :     nla->nla_len = NLA_HDRLEN + (len);
     474        2862 :     nla->nla_type = attr;
     475             : 
     476             :     /* Adjust by attribute length */
     477        2862 :     cl->cl_buf_offset += NLA_HDRLEN + (len);
     478        2862 : }
     479             : 
     480             : 
     481             : int
     482      303243 : nl_build_nlh(struct nl_client *cl, uint32_t type, uint32_t flags)
     483             : {
     484      303243 :     struct nlmsghdr *nlh = (struct nlmsghdr *)(cl->cl_buf);
     485             : 
     486      303243 :     if (cl->cl_buf_offset + NLMSG_HDRLEN > cl->cl_buf_len)
     487           0 :         return -ENOMEM;
     488             : 
     489      303243 :     nlh->nlmsg_len = cl->cl_buf_len;
     490      303243 :     nlh->nlmsg_type = type;
     491      303243 :     nlh->nlmsg_flags = flags;
     492      303243 :     nlh->nlmsg_seq = cl->cl_seq++;
     493      303243 :     nlh->nlmsg_pid = cl->cl_id;
     494             : 
     495      303243 :     cl->cl_buf_offset = NLMSG_HDRLEN;
     496             : 
     497      303243 :     return 0;
     498             : }
     499             : 
     500             : void
     501      303133 : nl_free(struct nl_client *cl)
     502             : {
     503      303133 :     nl_free_os_specific(cl);
     504             : 
     505      303133 :     cl->cl_buf_offset = 0;
     506      303133 :     cl->cl_buf_len = 0;
     507      303133 :     if (cl->cl_buf) {
     508      303133 :         free(cl->cl_buf);
     509      303133 :         cl->cl_buf = NULL;
     510             :     }
     511             : 
     512      303133 :     cl->cl_resp_buf_len = 0;
     513      303133 :     if (cl->cl_resp_buf) {
     514        2920 :         free(cl->cl_resp_buf);
     515        2920 :         cl->cl_resp_buf = NULL;
     516             :     }
     517             : 
     518      303133 :     cl->cl_recvmsg = NULL;
     519      303133 : }
     520             : 
     521             : int
     522        2863 : nl_recvmsg(struct nl_client *cl)
     523             : {
     524        2863 :     return cl->cl_recvmsg(cl, false);
     525             : }
     526             : 
     527             : int
     528           0 : nl_recvmsg_waitall(struct nl_client *cl)
     529             : {
     530           0 :     return cl->cl_recvmsg(cl, true);
     531             : }
     532             : 
     533             : void
     534           0 : nl_set_buf(struct nl_client *cl, char *buf, unsigned int len)
     535             : {
     536           0 :     if (cl->cl_buf)
     537           0 :         free(cl->cl_buf);
     538             : 
     539           0 :     cl->cl_buf =  buf;
     540           0 :     cl->cl_buf_offset = 0;
     541           0 :     cl->cl_buf_len = len;
     542           0 :     cl->cl_msg_len = 0;
     543           0 : }
     544             : 
     545             : void
     546           0 : nl_set_rcv_len(struct nl_client *cl, unsigned int rcv_len)
     547             : {
     548           0 :     cl->cl_recv_len = rcv_len;
     549           0 :     cl->cl_buf_offset = 0;
     550           0 :     cl->cl_msg_len = 0;
     551           0 : }
     552             : 
     553             : void
     554           0 : nl_set_genl_family_id(struct nl_client *cl, unsigned int family_id)
     555             : {
     556           0 :     cl->cl_genl_family_id = family_id;
     557           0 : }
     558             : 
     559             : struct nl_client *
     560        2951 : nl_register_client(void)
     561             : {
     562             :     struct nl_client *cl;
     563             : 
     564        2951 :     cl = calloc(sizeof(*cl), 1);
     565        2951 :     if (!cl)
     566           0 :         return cl;
     567             : 
     568        2951 :     cl->cl_buf = calloc(NL_MSG_DEFAULT_SIZE, 1);
     569        2951 :     if (!cl->cl_buf)
     570           0 :         goto exit_register;
     571        2951 :     cl->cl_buf_len = NL_MSG_DEFAULT_SIZE;
     572        2951 :     cl->cl_resp_buf = malloc(NL_RESP_DEFAULT_SIZE);
     573        2951 :     if (!cl->cl_resp_buf)
     574           0 :         goto exit_register;
     575        2951 :     cl->cl_resp_buf_len = NL_RESP_DEFAULT_SIZE;
     576             : 
     577        2951 :     cl->cl_id = 0;
     578        2951 :     nl_reset_cl_sock(cl);
     579             : 
     580        2951 :     return cl;
     581             : 
     582           0 : exit_register:
     583           0 :     if (cl)
     584           0 :         nl_free_client(cl);
     585             : 
     586           0 :     return NULL;
     587             : }
     588             : 
     589             : void
     590        2920 : nl_free_client(struct nl_client *cl)
     591             : {
     592        2920 :     nl_free(cl);
     593        2920 :     free(cl);
     594        2920 : }
     595             : 
     596             : int
     597      300381 : nl_init_generic_client_req(struct nl_client *cl, int family)
     598             : {
     599      300381 :     memset(cl, 0, sizeof(*cl));
     600      300381 :     cl->cl_buf = malloc(NL_MSG_DEFAULT_SIZE);
     601      300381 :     if (!cl->cl_buf)
     602           0 :         goto exit_register;
     603      300381 :     cl->cl_buf_len = NL_MSG_DEFAULT_SIZE;
     604      300381 :     cl->cl_genl_family_id = family;
     605      300381 :     nl_reset_cl_sock(cl);
     606             : 
     607      300381 :     return 1;
     608             : 
     609           0 : exit_register:
     610           0 :     return 0;
     611             : }
     612             : 
     613             : struct nl_response *
     614        2863 : nl_parse_reply(struct nl_client *cl)
     615             : {
     616        2863 :     struct nlmsghdr *nlh = (struct nlmsghdr *)(cl->cl_buf + cl->cl_buf_offset);
     617             :     struct nlmsgerr *err;
     618        2863 :     struct nl_response *resp = &cl->resp;
     619             : 
     620        2863 :     memset(resp, 0, sizeof(*resp));
     621        2863 :     resp->nl_type = NL_MSG_TYPE_ERROR;
     622        2863 :     if (cl->cl_buf_offset + NLMSG_HDRLEN > cl->cl_recv_len)
     623           0 :         return NULL;
     624             : 
     625        2863 :     cl->cl_msg_len = nlh->nlmsg_len;
     626        2863 :     cl->cl_msg_start = cl->cl_buf_offset;
     627        2863 :     if (cl->cl_msg_len + cl->cl_buf_offset > cl->cl_recv_len)
     628           0 :         return nl_set_resp_err(cl, -ENOMEM);
     629             : 
     630        2863 :     cl->cl_buf_offset += NLMSG_HDRLEN;
     631             : 
     632        2863 :     if (nlh->nlmsg_type == NLMSG_DONE) {
     633           0 :         resp->nl_type = NL_MSG_TYPE_DONE;
     634           0 :         return resp;
     635             :     }
     636             : 
     637        2863 :     if (nlh->nlmsg_type == NETLINK_GENERIC) {
     638           0 :         resp->nl_type = NL_MSG_TYPE_GEN_CTRL;
     639           0 :         resp = nl_parse_gen(cl);
     640           0 :         return resp;
     641             :     }
     642             : 
     643        2863 :     if (nlh->nlmsg_type == cl->cl_genl_family_id) {
     644        2863 :         resp->nl_type = NL_MSG_TYPE_FMLY;
     645        2863 :         resp = nl_parse_gen(cl);
     646        2863 :         return resp;
     647             :     }
     648             : 
     649           0 :     resp = nl_parse_reply_os_specific(cl);
     650           0 :     if (resp)
     651           0 :         return resp;
     652             : 
     653           0 :     err = (struct nlmsgerr *)nl_get_buf_ptr(cl);
     654           0 :     return nl_set_resp_err(cl, err->error);
     655             : }

Generated by: LCOV version 1.14