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

Generated by: LCOV version 1.14