xref: /aosp_15_r20/external/iproute2/tipc/msg.c (revision de1e4e894b0c224df933550f0afdecc354b238c4)
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