1*de1e4e89SAndroid Build Coastguard Worker /*
2*de1e4e89SAndroid Build Coastguard Worker * mnlg.c Generic Netlink helpers for libmnl
3*de1e4e89SAndroid Build Coastguard Worker *
4*de1e4e89SAndroid Build Coastguard Worker * This program is free software; you can redistribute it and/or
5*de1e4e89SAndroid Build Coastguard Worker * modify it under the terms of the GNU General Public License
6*de1e4e89SAndroid Build Coastguard Worker * as published by the Free Software Foundation; either version
7*de1e4e89SAndroid Build Coastguard Worker * 2 of the License, or (at your option) any later version.
8*de1e4e89SAndroid Build Coastguard Worker *
9*de1e4e89SAndroid Build Coastguard Worker * Authors: Jiri Pirko <[email protected]>
10*de1e4e89SAndroid Build Coastguard Worker */
11*de1e4e89SAndroid Build Coastguard Worker
12*de1e4e89SAndroid Build Coastguard Worker #include <stdlib.h>
13*de1e4e89SAndroid Build Coastguard Worker #include <stdbool.h>
14*de1e4e89SAndroid Build Coastguard Worker #include <string.h>
15*de1e4e89SAndroid Build Coastguard Worker #include <errno.h>
16*de1e4e89SAndroid Build Coastguard Worker #include <unistd.h>
17*de1e4e89SAndroid Build Coastguard Worker #include <time.h>
18*de1e4e89SAndroid Build Coastguard Worker #include <libmnl/libmnl.h>
19*de1e4e89SAndroid Build Coastguard Worker #include <linux/genetlink.h>
20*de1e4e89SAndroid Build Coastguard Worker
21*de1e4e89SAndroid Build Coastguard Worker #include "mnlg.h"
22*de1e4e89SAndroid Build Coastguard Worker
23*de1e4e89SAndroid Build Coastguard Worker struct mnlg_socket {
24*de1e4e89SAndroid Build Coastguard Worker struct mnl_socket *nl;
25*de1e4e89SAndroid Build Coastguard Worker char *buf;
26*de1e4e89SAndroid Build Coastguard Worker uint32_t id;
27*de1e4e89SAndroid Build Coastguard Worker uint8_t version;
28*de1e4e89SAndroid Build Coastguard Worker unsigned int seq;
29*de1e4e89SAndroid Build Coastguard Worker unsigned int portid;
30*de1e4e89SAndroid Build Coastguard Worker };
31*de1e4e89SAndroid Build Coastguard Worker
__mnlg_msg_prepare(struct mnlg_socket * nlg,uint8_t cmd,uint16_t flags,uint32_t id,uint8_t version)32*de1e4e89SAndroid Build Coastguard Worker static struct nlmsghdr *__mnlg_msg_prepare(struct mnlg_socket *nlg, uint8_t cmd,
33*de1e4e89SAndroid Build Coastguard Worker uint16_t flags, uint32_t id,
34*de1e4e89SAndroid Build Coastguard Worker uint8_t version)
35*de1e4e89SAndroid Build Coastguard Worker {
36*de1e4e89SAndroid Build Coastguard Worker struct nlmsghdr *nlh;
37*de1e4e89SAndroid Build Coastguard Worker struct genlmsghdr *genl;
38*de1e4e89SAndroid Build Coastguard Worker
39*de1e4e89SAndroid Build Coastguard Worker nlh = mnl_nlmsg_put_header(nlg->buf);
40*de1e4e89SAndroid Build Coastguard Worker nlh->nlmsg_type = id;
41*de1e4e89SAndroid Build Coastguard Worker nlh->nlmsg_flags = flags;
42*de1e4e89SAndroid Build Coastguard Worker nlg->seq = time(NULL);
43*de1e4e89SAndroid Build Coastguard Worker nlh->nlmsg_seq = nlg->seq;
44*de1e4e89SAndroid Build Coastguard Worker
45*de1e4e89SAndroid Build Coastguard Worker genl = mnl_nlmsg_put_extra_header(nlh, sizeof(struct genlmsghdr));
46*de1e4e89SAndroid Build Coastguard Worker genl->cmd = cmd;
47*de1e4e89SAndroid Build Coastguard Worker genl->version = version;
48*de1e4e89SAndroid Build Coastguard Worker
49*de1e4e89SAndroid Build Coastguard Worker return nlh;
50*de1e4e89SAndroid Build Coastguard Worker }
51*de1e4e89SAndroid Build Coastguard Worker
mnlg_msg_prepare(struct mnlg_socket * nlg,uint8_t cmd,uint16_t flags)52*de1e4e89SAndroid Build Coastguard Worker struct nlmsghdr *mnlg_msg_prepare(struct mnlg_socket *nlg, uint8_t cmd,
53*de1e4e89SAndroid Build Coastguard Worker uint16_t flags)
54*de1e4e89SAndroid Build Coastguard Worker {
55*de1e4e89SAndroid Build Coastguard Worker return __mnlg_msg_prepare(nlg, cmd, flags, nlg->id, nlg->version);
56*de1e4e89SAndroid Build Coastguard Worker }
57*de1e4e89SAndroid Build Coastguard Worker
mnlg_socket_send(struct mnlg_socket * nlg,const struct nlmsghdr * nlh)58*de1e4e89SAndroid Build Coastguard Worker int mnlg_socket_send(struct mnlg_socket *nlg, const struct nlmsghdr *nlh)
59*de1e4e89SAndroid Build Coastguard Worker {
60*de1e4e89SAndroid Build Coastguard Worker return mnl_socket_sendto(nlg->nl, nlh, nlh->nlmsg_len);
61*de1e4e89SAndroid Build Coastguard Worker }
62*de1e4e89SAndroid Build Coastguard Worker
mnlg_socket_recv_run(struct mnlg_socket * nlg,mnl_cb_t data_cb,void * data)63*de1e4e89SAndroid Build Coastguard Worker int mnlg_socket_recv_run(struct mnlg_socket *nlg, mnl_cb_t data_cb, void *data)
64*de1e4e89SAndroid Build Coastguard Worker {
65*de1e4e89SAndroid Build Coastguard Worker int err;
66*de1e4e89SAndroid Build Coastguard Worker
67*de1e4e89SAndroid Build Coastguard Worker do {
68*de1e4e89SAndroid Build Coastguard Worker err = mnl_socket_recvfrom(nlg->nl, nlg->buf,
69*de1e4e89SAndroid Build Coastguard Worker MNL_SOCKET_BUFFER_SIZE);
70*de1e4e89SAndroid Build Coastguard Worker if (err <= 0)
71*de1e4e89SAndroid Build Coastguard Worker break;
72*de1e4e89SAndroid Build Coastguard Worker err = mnl_cb_run(nlg->buf, err, nlg->seq, nlg->portid,
73*de1e4e89SAndroid Build Coastguard Worker data_cb, data);
74*de1e4e89SAndroid Build Coastguard Worker } while (err > 0);
75*de1e4e89SAndroid Build Coastguard Worker
76*de1e4e89SAndroid Build Coastguard Worker return err;
77*de1e4e89SAndroid Build Coastguard Worker }
78*de1e4e89SAndroid Build Coastguard Worker
79*de1e4e89SAndroid Build Coastguard Worker struct group_info {
80*de1e4e89SAndroid Build Coastguard Worker bool found;
81*de1e4e89SAndroid Build Coastguard Worker uint32_t id;
82*de1e4e89SAndroid Build Coastguard Worker const char *name;
83*de1e4e89SAndroid Build Coastguard Worker };
84*de1e4e89SAndroid Build Coastguard Worker
parse_mc_grps_cb(const struct nlattr * attr,void * data)85*de1e4e89SAndroid Build Coastguard Worker static int parse_mc_grps_cb(const struct nlattr *attr, void *data)
86*de1e4e89SAndroid Build Coastguard Worker {
87*de1e4e89SAndroid Build Coastguard Worker const struct nlattr **tb = data;
88*de1e4e89SAndroid Build Coastguard Worker int type = mnl_attr_get_type(attr);
89*de1e4e89SAndroid Build Coastguard Worker
90*de1e4e89SAndroid Build Coastguard Worker if (mnl_attr_type_valid(attr, CTRL_ATTR_MCAST_GRP_MAX) < 0)
91*de1e4e89SAndroid Build Coastguard Worker return MNL_CB_OK;
92*de1e4e89SAndroid Build Coastguard Worker
93*de1e4e89SAndroid Build Coastguard Worker switch (type) {
94*de1e4e89SAndroid Build Coastguard Worker case CTRL_ATTR_MCAST_GRP_ID:
95*de1e4e89SAndroid Build Coastguard Worker if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
96*de1e4e89SAndroid Build Coastguard Worker return MNL_CB_ERROR;
97*de1e4e89SAndroid Build Coastguard Worker break;
98*de1e4e89SAndroid Build Coastguard Worker case CTRL_ATTR_MCAST_GRP_NAME:
99*de1e4e89SAndroid Build Coastguard Worker if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0)
100*de1e4e89SAndroid Build Coastguard Worker return MNL_CB_ERROR;
101*de1e4e89SAndroid Build Coastguard Worker break;
102*de1e4e89SAndroid Build Coastguard Worker }
103*de1e4e89SAndroid Build Coastguard Worker tb[type] = attr;
104*de1e4e89SAndroid Build Coastguard Worker return MNL_CB_OK;
105*de1e4e89SAndroid Build Coastguard Worker }
106*de1e4e89SAndroid Build Coastguard Worker
parse_genl_mc_grps(struct nlattr * nested,struct group_info * group_info)107*de1e4e89SAndroid Build Coastguard Worker static void parse_genl_mc_grps(struct nlattr *nested,
108*de1e4e89SAndroid Build Coastguard Worker struct group_info *group_info)
109*de1e4e89SAndroid Build Coastguard Worker {
110*de1e4e89SAndroid Build Coastguard Worker struct nlattr *pos;
111*de1e4e89SAndroid Build Coastguard Worker const char *name;
112*de1e4e89SAndroid Build Coastguard Worker
113*de1e4e89SAndroid Build Coastguard Worker mnl_attr_for_each_nested(pos, nested) {
114*de1e4e89SAndroid Build Coastguard Worker struct nlattr *tb[CTRL_ATTR_MCAST_GRP_MAX + 1] = {};
115*de1e4e89SAndroid Build Coastguard Worker
116*de1e4e89SAndroid Build Coastguard Worker mnl_attr_parse_nested(pos, parse_mc_grps_cb, tb);
117*de1e4e89SAndroid Build Coastguard Worker if (!tb[CTRL_ATTR_MCAST_GRP_NAME] ||
118*de1e4e89SAndroid Build Coastguard Worker !tb[CTRL_ATTR_MCAST_GRP_ID])
119*de1e4e89SAndroid Build Coastguard Worker continue;
120*de1e4e89SAndroid Build Coastguard Worker
121*de1e4e89SAndroid Build Coastguard Worker name = mnl_attr_get_str(tb[CTRL_ATTR_MCAST_GRP_NAME]);
122*de1e4e89SAndroid Build Coastguard Worker if (strcmp(name, group_info->name) != 0)
123*de1e4e89SAndroid Build Coastguard Worker continue;
124*de1e4e89SAndroid Build Coastguard Worker
125*de1e4e89SAndroid Build Coastguard Worker group_info->id = mnl_attr_get_u32(tb[CTRL_ATTR_MCAST_GRP_ID]);
126*de1e4e89SAndroid Build Coastguard Worker group_info->found = true;
127*de1e4e89SAndroid Build Coastguard Worker }
128*de1e4e89SAndroid Build Coastguard Worker }
129*de1e4e89SAndroid Build Coastguard Worker
get_group_id_attr_cb(const struct nlattr * attr,void * data)130*de1e4e89SAndroid Build Coastguard Worker static int get_group_id_attr_cb(const struct nlattr *attr, void *data)
131*de1e4e89SAndroid Build Coastguard Worker {
132*de1e4e89SAndroid Build Coastguard Worker const struct nlattr **tb = data;
133*de1e4e89SAndroid Build Coastguard Worker int type = mnl_attr_get_type(attr);
134*de1e4e89SAndroid Build Coastguard Worker
135*de1e4e89SAndroid Build Coastguard Worker if (mnl_attr_type_valid(attr, CTRL_ATTR_MAX) < 0)
136*de1e4e89SAndroid Build Coastguard Worker return MNL_CB_ERROR;
137*de1e4e89SAndroid Build Coastguard Worker
138*de1e4e89SAndroid Build Coastguard Worker if (type == CTRL_ATTR_MCAST_GROUPS &&
139*de1e4e89SAndroid Build Coastguard Worker mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0)
140*de1e4e89SAndroid Build Coastguard Worker return MNL_CB_ERROR;
141*de1e4e89SAndroid Build Coastguard Worker tb[type] = attr;
142*de1e4e89SAndroid Build Coastguard Worker return MNL_CB_OK;
143*de1e4e89SAndroid Build Coastguard Worker }
144*de1e4e89SAndroid Build Coastguard Worker
get_group_id_cb(const struct nlmsghdr * nlh,void * data)145*de1e4e89SAndroid Build Coastguard Worker static int get_group_id_cb(const struct nlmsghdr *nlh, void *data)
146*de1e4e89SAndroid Build Coastguard Worker {
147*de1e4e89SAndroid Build Coastguard Worker struct group_info *group_info = data;
148*de1e4e89SAndroid Build Coastguard Worker struct nlattr *tb[CTRL_ATTR_MAX + 1] = {};
149*de1e4e89SAndroid Build Coastguard Worker struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
150*de1e4e89SAndroid Build Coastguard Worker
151*de1e4e89SAndroid Build Coastguard Worker mnl_attr_parse(nlh, sizeof(*genl), get_group_id_attr_cb, tb);
152*de1e4e89SAndroid Build Coastguard Worker if (!tb[CTRL_ATTR_MCAST_GROUPS])
153*de1e4e89SAndroid Build Coastguard Worker return MNL_CB_ERROR;
154*de1e4e89SAndroid Build Coastguard Worker parse_genl_mc_grps(tb[CTRL_ATTR_MCAST_GROUPS], group_info);
155*de1e4e89SAndroid Build Coastguard Worker return MNL_CB_OK;
156*de1e4e89SAndroid Build Coastguard Worker }
157*de1e4e89SAndroid Build Coastguard Worker
mnlg_socket_group_add(struct mnlg_socket * nlg,const char * group_name)158*de1e4e89SAndroid Build Coastguard Worker int mnlg_socket_group_add(struct mnlg_socket *nlg, const char *group_name)
159*de1e4e89SAndroid Build Coastguard Worker {
160*de1e4e89SAndroid Build Coastguard Worker struct nlmsghdr *nlh;
161*de1e4e89SAndroid Build Coastguard Worker struct group_info group_info;
162*de1e4e89SAndroid Build Coastguard Worker int err;
163*de1e4e89SAndroid Build Coastguard Worker
164*de1e4e89SAndroid Build Coastguard Worker nlh = __mnlg_msg_prepare(nlg, CTRL_CMD_GETFAMILY,
165*de1e4e89SAndroid Build Coastguard Worker NLM_F_REQUEST | NLM_F_ACK, GENL_ID_CTRL, 1);
166*de1e4e89SAndroid Build Coastguard Worker mnl_attr_put_u32(nlh, CTRL_ATTR_FAMILY_ID, nlg->id);
167*de1e4e89SAndroid Build Coastguard Worker
168*de1e4e89SAndroid Build Coastguard Worker err = mnlg_socket_send(nlg, nlh);
169*de1e4e89SAndroid Build Coastguard Worker if (err < 0)
170*de1e4e89SAndroid Build Coastguard Worker return err;
171*de1e4e89SAndroid Build Coastguard Worker
172*de1e4e89SAndroid Build Coastguard Worker group_info.found = false;
173*de1e4e89SAndroid Build Coastguard Worker group_info.name = group_name;
174*de1e4e89SAndroid Build Coastguard Worker err = mnlg_socket_recv_run(nlg, get_group_id_cb, &group_info);
175*de1e4e89SAndroid Build Coastguard Worker if (err < 0)
176*de1e4e89SAndroid Build Coastguard Worker return err;
177*de1e4e89SAndroid Build Coastguard Worker
178*de1e4e89SAndroid Build Coastguard Worker if (!group_info.found) {
179*de1e4e89SAndroid Build Coastguard Worker errno = ENOENT;
180*de1e4e89SAndroid Build Coastguard Worker return -1;
181*de1e4e89SAndroid Build Coastguard Worker }
182*de1e4e89SAndroid Build Coastguard Worker
183*de1e4e89SAndroid Build Coastguard Worker err = mnl_socket_setsockopt(nlg->nl, NETLINK_ADD_MEMBERSHIP,
184*de1e4e89SAndroid Build Coastguard Worker &group_info.id, sizeof(group_info.id));
185*de1e4e89SAndroid Build Coastguard Worker if (err < 0)
186*de1e4e89SAndroid Build Coastguard Worker return err;
187*de1e4e89SAndroid Build Coastguard Worker
188*de1e4e89SAndroid Build Coastguard Worker return 0;
189*de1e4e89SAndroid Build Coastguard Worker }
190*de1e4e89SAndroid Build Coastguard Worker
get_family_id_attr_cb(const struct nlattr * attr,void * data)191*de1e4e89SAndroid Build Coastguard Worker static int get_family_id_attr_cb(const struct nlattr *attr, void *data)
192*de1e4e89SAndroid Build Coastguard Worker {
193*de1e4e89SAndroid Build Coastguard Worker const struct nlattr **tb = data;
194*de1e4e89SAndroid Build Coastguard Worker int type = mnl_attr_get_type(attr);
195*de1e4e89SAndroid Build Coastguard Worker
196*de1e4e89SAndroid Build Coastguard Worker if (mnl_attr_type_valid(attr, CTRL_ATTR_MAX) < 0)
197*de1e4e89SAndroid Build Coastguard Worker return MNL_CB_ERROR;
198*de1e4e89SAndroid Build Coastguard Worker
199*de1e4e89SAndroid Build Coastguard Worker if (type == CTRL_ATTR_FAMILY_ID &&
200*de1e4e89SAndroid Build Coastguard Worker mnl_attr_validate(attr, MNL_TYPE_U16) < 0)
201*de1e4e89SAndroid Build Coastguard Worker return MNL_CB_ERROR;
202*de1e4e89SAndroid Build Coastguard Worker tb[type] = attr;
203*de1e4e89SAndroid Build Coastguard Worker return MNL_CB_OK;
204*de1e4e89SAndroid Build Coastguard Worker }
205*de1e4e89SAndroid Build Coastguard Worker
get_family_id_cb(const struct nlmsghdr * nlh,void * data)206*de1e4e89SAndroid Build Coastguard Worker static int get_family_id_cb(const struct nlmsghdr *nlh, void *data)
207*de1e4e89SAndroid Build Coastguard Worker {
208*de1e4e89SAndroid Build Coastguard Worker uint32_t *p_id = data;
209*de1e4e89SAndroid Build Coastguard Worker struct nlattr *tb[CTRL_ATTR_MAX + 1] = {};
210*de1e4e89SAndroid Build Coastguard Worker struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
211*de1e4e89SAndroid Build Coastguard Worker
212*de1e4e89SAndroid Build Coastguard Worker mnl_attr_parse(nlh, sizeof(*genl), get_family_id_attr_cb, tb);
213*de1e4e89SAndroid Build Coastguard Worker if (!tb[CTRL_ATTR_FAMILY_ID])
214*de1e4e89SAndroid Build Coastguard Worker return MNL_CB_ERROR;
215*de1e4e89SAndroid Build Coastguard Worker *p_id = mnl_attr_get_u16(tb[CTRL_ATTR_FAMILY_ID]);
216*de1e4e89SAndroid Build Coastguard Worker return MNL_CB_OK;
217*de1e4e89SAndroid Build Coastguard Worker }
218*de1e4e89SAndroid Build Coastguard Worker
mnlg_socket_open(const char * family_name,uint8_t version)219*de1e4e89SAndroid Build Coastguard Worker struct mnlg_socket *mnlg_socket_open(const char *family_name, uint8_t version)
220*de1e4e89SAndroid Build Coastguard Worker {
221*de1e4e89SAndroid Build Coastguard Worker struct mnlg_socket *nlg;
222*de1e4e89SAndroid Build Coastguard Worker struct nlmsghdr *nlh;
223*de1e4e89SAndroid Build Coastguard Worker int err;
224*de1e4e89SAndroid Build Coastguard Worker
225*de1e4e89SAndroid Build Coastguard Worker nlg = malloc(sizeof(*nlg));
226*de1e4e89SAndroid Build Coastguard Worker if (!nlg)
227*de1e4e89SAndroid Build Coastguard Worker return NULL;
228*de1e4e89SAndroid Build Coastguard Worker
229*de1e4e89SAndroid Build Coastguard Worker nlg->buf = malloc(MNL_SOCKET_BUFFER_SIZE);
230*de1e4e89SAndroid Build Coastguard Worker if (!nlg->buf)
231*de1e4e89SAndroid Build Coastguard Worker goto err_buf_alloc;
232*de1e4e89SAndroid Build Coastguard Worker
233*de1e4e89SAndroid Build Coastguard Worker nlg->nl = mnl_socket_open(NETLINK_GENERIC);
234*de1e4e89SAndroid Build Coastguard Worker if (!nlg->nl)
235*de1e4e89SAndroid Build Coastguard Worker goto err_mnl_socket_open;
236*de1e4e89SAndroid Build Coastguard Worker
237*de1e4e89SAndroid Build Coastguard Worker err = mnl_socket_bind(nlg->nl, 0, MNL_SOCKET_AUTOPID);
238*de1e4e89SAndroid Build Coastguard Worker if (err < 0)
239*de1e4e89SAndroid Build Coastguard Worker goto err_mnl_socket_bind;
240*de1e4e89SAndroid Build Coastguard Worker
241*de1e4e89SAndroid Build Coastguard Worker nlg->portid = mnl_socket_get_portid(nlg->nl);
242*de1e4e89SAndroid Build Coastguard Worker
243*de1e4e89SAndroid Build Coastguard Worker nlh = __mnlg_msg_prepare(nlg, CTRL_CMD_GETFAMILY,
244*de1e4e89SAndroid Build Coastguard Worker NLM_F_REQUEST | NLM_F_ACK, GENL_ID_CTRL, 1);
245*de1e4e89SAndroid Build Coastguard Worker mnl_attr_put_strz(nlh, CTRL_ATTR_FAMILY_NAME, family_name);
246*de1e4e89SAndroid Build Coastguard Worker
247*de1e4e89SAndroid Build Coastguard Worker err = mnlg_socket_send(nlg, nlh);
248*de1e4e89SAndroid Build Coastguard Worker if (err < 0)
249*de1e4e89SAndroid Build Coastguard Worker goto err_mnlg_socket_send;
250*de1e4e89SAndroid Build Coastguard Worker
251*de1e4e89SAndroid Build Coastguard Worker err = mnlg_socket_recv_run(nlg, get_family_id_cb, &nlg->id);
252*de1e4e89SAndroid Build Coastguard Worker if (err < 0)
253*de1e4e89SAndroid Build Coastguard Worker goto err_mnlg_socket_recv_run;
254*de1e4e89SAndroid Build Coastguard Worker
255*de1e4e89SAndroid Build Coastguard Worker nlg->version = version;
256*de1e4e89SAndroid Build Coastguard Worker return nlg;
257*de1e4e89SAndroid Build Coastguard Worker
258*de1e4e89SAndroid Build Coastguard Worker err_mnlg_socket_recv_run:
259*de1e4e89SAndroid Build Coastguard Worker err_mnlg_socket_send:
260*de1e4e89SAndroid Build Coastguard Worker err_mnl_socket_bind:
261*de1e4e89SAndroid Build Coastguard Worker mnl_socket_close(nlg->nl);
262*de1e4e89SAndroid Build Coastguard Worker err_mnl_socket_open:
263*de1e4e89SAndroid Build Coastguard Worker free(nlg->buf);
264*de1e4e89SAndroid Build Coastguard Worker err_buf_alloc:
265*de1e4e89SAndroid Build Coastguard Worker free(nlg);
266*de1e4e89SAndroid Build Coastguard Worker return NULL;
267*de1e4e89SAndroid Build Coastguard Worker }
268*de1e4e89SAndroid Build Coastguard Worker
mnlg_socket_close(struct mnlg_socket * nlg)269*de1e4e89SAndroid Build Coastguard Worker void mnlg_socket_close(struct mnlg_socket *nlg)
270*de1e4e89SAndroid Build Coastguard Worker {
271*de1e4e89SAndroid Build Coastguard Worker mnl_socket_close(nlg->nl);
272*de1e4e89SAndroid Build Coastguard Worker free(nlg->buf);
273*de1e4e89SAndroid Build Coastguard Worker free(nlg);
274*de1e4e89SAndroid Build Coastguard Worker }
275