1*de1e4e89SAndroid Build Coastguard Worker /*
2*de1e4e89SAndroid Build Coastguard Worker * msg.c Messaging (netlink) helper functions.
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: Richard Alpe <[email protected]>
10*de1e4e89SAndroid Build Coastguard Worker */
11*de1e4e89SAndroid Build Coastguard Worker
12*de1e4e89SAndroid Build Coastguard Worker #include <stdio.h>
13*de1e4e89SAndroid Build Coastguard Worker #include <time.h>
14*de1e4e89SAndroid Build Coastguard Worker #include <errno.h>
15*de1e4e89SAndroid Build Coastguard Worker
16*de1e4e89SAndroid Build Coastguard Worker #include <linux/tipc_netlink.h>
17*de1e4e89SAndroid Build Coastguard Worker #include <linux/tipc.h>
18*de1e4e89SAndroid Build Coastguard Worker #include <linux/genetlink.h>
19*de1e4e89SAndroid Build Coastguard Worker #include <libmnl/libmnl.h>
20*de1e4e89SAndroid Build Coastguard Worker
21*de1e4e89SAndroid Build Coastguard Worker #include "msg.h"
22*de1e4e89SAndroid Build Coastguard Worker
parse_attrs(const struct nlattr * attr,void * data)23*de1e4e89SAndroid Build Coastguard Worker int parse_attrs(const struct nlattr *attr, void *data)
24*de1e4e89SAndroid Build Coastguard Worker {
25*de1e4e89SAndroid Build Coastguard Worker const struct nlattr **tb = data;
26*de1e4e89SAndroid Build Coastguard Worker int type = mnl_attr_get_type(attr);
27*de1e4e89SAndroid Build Coastguard Worker
28*de1e4e89SAndroid Build Coastguard Worker tb[type] = attr;
29*de1e4e89SAndroid Build Coastguard Worker
30*de1e4e89SAndroid Build Coastguard Worker return MNL_CB_OK;
31*de1e4e89SAndroid Build Coastguard Worker }
32*de1e4e89SAndroid Build Coastguard Worker
family_id_cb(const struct nlmsghdr * nlh,void * data)33*de1e4e89SAndroid Build Coastguard Worker static int family_id_cb(const struct nlmsghdr *nlh, void *data)
34*de1e4e89SAndroid Build Coastguard Worker {
35*de1e4e89SAndroid Build Coastguard Worker struct nlattr *tb[CTRL_ATTR_MAX + 1] = {};
36*de1e4e89SAndroid Build Coastguard Worker struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
37*de1e4e89SAndroid Build Coastguard Worker int *id = data;
38*de1e4e89SAndroid Build Coastguard Worker
39*de1e4e89SAndroid Build Coastguard Worker mnl_attr_parse(nlh, sizeof(*genl), parse_attrs, tb);
40*de1e4e89SAndroid Build Coastguard Worker if (!tb[CTRL_ATTR_FAMILY_ID])
41*de1e4e89SAndroid Build Coastguard Worker return MNL_CB_ERROR;
42*de1e4e89SAndroid Build Coastguard Worker
43*de1e4e89SAndroid Build Coastguard Worker *id = mnl_attr_get_u16(tb[CTRL_ATTR_FAMILY_ID]);
44*de1e4e89SAndroid Build Coastguard Worker
45*de1e4e89SAndroid Build Coastguard Worker return MNL_CB_OK;
46*de1e4e89SAndroid Build Coastguard Worker }
47*de1e4e89SAndroid Build Coastguard Worker
msg_send(struct nlmsghdr * nlh)48*de1e4e89SAndroid Build Coastguard Worker static struct mnl_socket *msg_send(struct nlmsghdr *nlh)
49*de1e4e89SAndroid Build Coastguard Worker {
50*de1e4e89SAndroid Build Coastguard Worker int ret;
51*de1e4e89SAndroid Build Coastguard Worker struct mnl_socket *nl;
52*de1e4e89SAndroid Build Coastguard Worker
53*de1e4e89SAndroid Build Coastguard Worker nl = mnl_socket_open(NETLINK_GENERIC);
54*de1e4e89SAndroid Build Coastguard Worker if (nl == NULL) {
55*de1e4e89SAndroid Build Coastguard Worker perror("mnl_socket_open");
56*de1e4e89SAndroid Build Coastguard Worker return NULL;
57*de1e4e89SAndroid Build Coastguard Worker }
58*de1e4e89SAndroid Build Coastguard Worker
59*de1e4e89SAndroid Build Coastguard Worker ret = mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID);
60*de1e4e89SAndroid Build Coastguard Worker if (ret < 0) {
61*de1e4e89SAndroid Build Coastguard Worker perror("mnl_socket_bind");
62*de1e4e89SAndroid Build Coastguard Worker return NULL;
63*de1e4e89SAndroid Build Coastguard Worker }
64*de1e4e89SAndroid Build Coastguard Worker
65*de1e4e89SAndroid Build Coastguard Worker ret = mnl_socket_sendto(nl, nlh, nlh->nlmsg_len);
66*de1e4e89SAndroid Build Coastguard Worker if (ret < 0) {
67*de1e4e89SAndroid Build Coastguard Worker perror("mnl_socket_send");
68*de1e4e89SAndroid Build Coastguard Worker return NULL;
69*de1e4e89SAndroid Build Coastguard Worker }
70*de1e4e89SAndroid Build Coastguard Worker
71*de1e4e89SAndroid Build Coastguard Worker return nl;
72*de1e4e89SAndroid Build Coastguard Worker }
73*de1e4e89SAndroid Build Coastguard Worker
msg_recv(struct mnl_socket * nl,mnl_cb_t callback,void * data,int seq)74*de1e4e89SAndroid Build Coastguard Worker static int msg_recv(struct mnl_socket *nl, mnl_cb_t callback, void *data, int seq)
75*de1e4e89SAndroid Build Coastguard Worker {
76*de1e4e89SAndroid Build Coastguard Worker int ret;
77*de1e4e89SAndroid Build Coastguard Worker unsigned int portid;
78*de1e4e89SAndroid Build Coastguard Worker char buf[MNL_SOCKET_BUFFER_SIZE];
79*de1e4e89SAndroid Build Coastguard Worker
80*de1e4e89SAndroid Build Coastguard Worker portid = mnl_socket_get_portid(nl);
81*de1e4e89SAndroid Build Coastguard Worker
82*de1e4e89SAndroid Build Coastguard Worker ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
83*de1e4e89SAndroid Build Coastguard Worker while (ret > 0) {
84*de1e4e89SAndroid Build Coastguard Worker ret = mnl_cb_run(buf, ret, seq, portid, callback, data);
85*de1e4e89SAndroid Build Coastguard Worker if (ret <= 0)
86*de1e4e89SAndroid Build Coastguard Worker break;
87*de1e4e89SAndroid Build Coastguard Worker ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
88*de1e4e89SAndroid Build Coastguard Worker }
89*de1e4e89SAndroid Build Coastguard Worker if (ret == -1)
90*de1e4e89SAndroid Build Coastguard Worker perror("error");
91*de1e4e89SAndroid Build Coastguard Worker
92*de1e4e89SAndroid Build Coastguard Worker mnl_socket_close(nl);
93*de1e4e89SAndroid Build Coastguard Worker
94*de1e4e89SAndroid Build Coastguard Worker return ret;
95*de1e4e89SAndroid Build Coastguard Worker }
96*de1e4e89SAndroid Build Coastguard Worker
msg_query(struct nlmsghdr * nlh,mnl_cb_t callback,void * data)97*de1e4e89SAndroid Build Coastguard Worker static int msg_query(struct nlmsghdr *nlh, mnl_cb_t callback, void *data)
98*de1e4e89SAndroid Build Coastguard Worker {
99*de1e4e89SAndroid Build Coastguard Worker unsigned int seq;
100*de1e4e89SAndroid Build Coastguard Worker struct mnl_socket *nl;
101*de1e4e89SAndroid Build Coastguard Worker
102*de1e4e89SAndroid Build Coastguard Worker seq = time(NULL);
103*de1e4e89SAndroid Build Coastguard Worker nlh->nlmsg_seq = seq;
104*de1e4e89SAndroid Build Coastguard Worker
105*de1e4e89SAndroid Build Coastguard Worker nl = msg_send(nlh);
106*de1e4e89SAndroid Build Coastguard Worker if (!nl)
107*de1e4e89SAndroid Build Coastguard Worker return -ENOTSUP;
108*de1e4e89SAndroid Build Coastguard Worker
109*de1e4e89SAndroid Build Coastguard Worker return msg_recv(nl, callback, data, seq);
110*de1e4e89SAndroid Build Coastguard Worker }
111*de1e4e89SAndroid Build Coastguard Worker
get_family(void)112*de1e4e89SAndroid Build Coastguard Worker static int get_family(void)
113*de1e4e89SAndroid Build Coastguard Worker {
114*de1e4e89SAndroid Build Coastguard Worker int err;
115*de1e4e89SAndroid Build Coastguard Worker int nl_family;
116*de1e4e89SAndroid Build Coastguard Worker struct nlmsghdr *nlh;
117*de1e4e89SAndroid Build Coastguard Worker struct genlmsghdr *genl;
118*de1e4e89SAndroid Build Coastguard Worker char buf[MNL_SOCKET_BUFFER_SIZE];
119*de1e4e89SAndroid Build Coastguard Worker
120*de1e4e89SAndroid Build Coastguard Worker nlh = mnl_nlmsg_put_header(buf);
121*de1e4e89SAndroid Build Coastguard Worker nlh->nlmsg_type = GENL_ID_CTRL;
122*de1e4e89SAndroid Build Coastguard Worker nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
123*de1e4e89SAndroid Build Coastguard Worker
124*de1e4e89SAndroid Build Coastguard Worker genl = mnl_nlmsg_put_extra_header(nlh, sizeof(struct genlmsghdr));
125*de1e4e89SAndroid Build Coastguard Worker genl->cmd = CTRL_CMD_GETFAMILY;
126*de1e4e89SAndroid Build Coastguard Worker genl->version = 1;
127*de1e4e89SAndroid Build Coastguard Worker
128*de1e4e89SAndroid Build Coastguard Worker mnl_attr_put_u32(nlh, CTRL_ATTR_FAMILY_ID, GENL_ID_CTRL);
129*de1e4e89SAndroid Build Coastguard Worker mnl_attr_put_strz(nlh, CTRL_ATTR_FAMILY_NAME, TIPC_GENL_V2_NAME);
130*de1e4e89SAndroid Build Coastguard Worker
131*de1e4e89SAndroid Build Coastguard Worker if ((err = msg_query(nlh, family_id_cb, &nl_family)))
132*de1e4e89SAndroid Build Coastguard Worker return err;
133*de1e4e89SAndroid Build Coastguard Worker
134*de1e4e89SAndroid Build Coastguard Worker return nl_family;
135*de1e4e89SAndroid Build Coastguard Worker }
136*de1e4e89SAndroid Build Coastguard Worker
msg_doit(struct nlmsghdr * nlh,mnl_cb_t callback,void * data)137*de1e4e89SAndroid Build Coastguard Worker int msg_doit(struct nlmsghdr *nlh, mnl_cb_t callback, void *data)
138*de1e4e89SAndroid Build Coastguard Worker {
139*de1e4e89SAndroid Build Coastguard Worker nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
140*de1e4e89SAndroid Build Coastguard Worker return msg_query(nlh, callback, data);
141*de1e4e89SAndroid Build Coastguard Worker }
142*de1e4e89SAndroid Build Coastguard Worker
msg_dumpit(struct nlmsghdr * nlh,mnl_cb_t callback,void * data)143*de1e4e89SAndroid Build Coastguard Worker int msg_dumpit(struct nlmsghdr *nlh, mnl_cb_t callback, void *data)
144*de1e4e89SAndroid Build Coastguard Worker {
145*de1e4e89SAndroid Build Coastguard Worker nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
146*de1e4e89SAndroid Build Coastguard Worker return msg_query(nlh, callback, data);
147*de1e4e89SAndroid Build Coastguard Worker }
148*de1e4e89SAndroid Build Coastguard Worker
msg_init(char * buf,int cmd)149*de1e4e89SAndroid Build Coastguard Worker struct nlmsghdr *msg_init(char *buf, int cmd)
150*de1e4e89SAndroid Build Coastguard Worker {
151*de1e4e89SAndroid Build Coastguard Worker int family;
152*de1e4e89SAndroid Build Coastguard Worker struct nlmsghdr *nlh;
153*de1e4e89SAndroid Build Coastguard Worker struct genlmsghdr *genl;
154*de1e4e89SAndroid Build Coastguard Worker
155*de1e4e89SAndroid Build Coastguard Worker family = get_family();
156*de1e4e89SAndroid Build Coastguard Worker if (family <= 0) {
157*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr,
158*de1e4e89SAndroid Build Coastguard Worker "Unable to get TIPC nl family id (module loaded?)\n");
159*de1e4e89SAndroid Build Coastguard Worker return NULL;
160*de1e4e89SAndroid Build Coastguard Worker }
161*de1e4e89SAndroid Build Coastguard Worker
162*de1e4e89SAndroid Build Coastguard Worker nlh = mnl_nlmsg_put_header(buf);
163*de1e4e89SAndroid Build Coastguard Worker nlh->nlmsg_type = family;
164*de1e4e89SAndroid Build Coastguard Worker
165*de1e4e89SAndroid Build Coastguard Worker genl = mnl_nlmsg_put_extra_header(nlh, sizeof(struct genlmsghdr));
166*de1e4e89SAndroid Build Coastguard Worker genl->cmd = cmd;
167*de1e4e89SAndroid Build Coastguard Worker genl->version = 1;
168*de1e4e89SAndroid Build Coastguard Worker
169*de1e4e89SAndroid Build Coastguard Worker return nlh;
170*de1e4e89SAndroid Build Coastguard Worker }
171