xref: /freebsd/sys/netlink/netlink_snl_generic.h (revision dd21556857e8d40f66bf5ad54754d9d52669ebf7)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2022 Alexander V. Chernikov <melifaro@FreeBSD.org>
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27 #ifndef	_NETLINK_NETLINK_SNL_GENERIC_H_
28 #define	_NETLINK_NETLINK_SNL_GENERIC_H_
29 
30 #include <netlink/netlink.h>
31 #include <netlink/netlink_generic.h>
32 #include <netlink/netlink_snl.h>
33 
34 /* Genetlink helpers */
35 static inline struct nlmsghdr *
36 snl_create_genl_msg_request(struct snl_writer *nw, uint16_t genl_family,
37     uint8_t genl_cmd)
38 {
39 	struct nlmsghdr *hdr;
40 	struct genlmsghdr *ghdr;
41 
42 	assert(nw->hdr == NULL);
43 
44 	hdr = snl_reserve_msg_object(nw, struct nlmsghdr);
45 	if (__predict_false(hdr == NULL))
46 		return (NULL);
47 	hdr->nlmsg_type = genl_family;
48 	hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
49 	ghdr = snl_reserve_msg_object(nw, struct genlmsghdr);
50 	if (__predict_false(ghdr == NULL))
51 		return (NULL);
52 	ghdr->cmd = genl_cmd;
53 	nw->hdr = hdr;
54 
55 	return (hdr);
56 }
57 
58 static struct snl_field_parser snl_fp_genl[] = {};
59 
60 #define	SNL_DECLARE_GENL_PARSER(_name, _np)	SNL_DECLARE_PARSER(_name,\
61     struct genlmsghdr, snl_fp_genl, _np)
62 
63 struct snl_genl_ctrl_mcast_group {
64 	uint32_t mcast_grp_id;
65 	char *mcast_grp_name;
66 };
67 
68 struct snl_genl_ctrl_mcast_groups {
69 	uint32_t num_groups;
70 	struct snl_genl_ctrl_mcast_group **groups;
71 };
72 
73 #define	_OUT(_field)	offsetof(struct snl_genl_ctrl_mcast_group, _field)
74 static struct snl_attr_parser _nla_p_getmc[] = {
75 	{ .type = CTRL_ATTR_MCAST_GRP_NAME, .off = _OUT(mcast_grp_name), .cb = snl_attr_get_string },
76 	{ .type = CTRL_ATTR_MCAST_GRP_ID, .off = _OUT(mcast_grp_id), .cb = snl_attr_get_uint32 },
77 };
78 #undef _OUT
79 SNL_DECLARE_ATTR_PARSER_EXT(_genl_ctrl_mc_parser,
80 		sizeof(struct snl_genl_ctrl_mcast_group),
81 		_nla_p_getmc, NULL);
82 
83 struct _getfamily_attrs {
84 	uint16_t family_id;
85 	char	*family_name;
86 	struct snl_genl_ctrl_mcast_groups mcast_groups;
87 };
88 
89 #define	_IN(_field)	offsetof(struct genlmsghdr, _field)
90 #define	_OUT(_field)	offsetof(struct _getfamily_attrs, _field)
91 static struct snl_attr_parser _nla_p_getfam[] = {
92 	{ .type = CTRL_ATTR_FAMILY_ID , .off = _OUT(family_id), .cb = snl_attr_get_uint16 },
93 	{ .type = CTRL_ATTR_FAMILY_NAME, .off = _OUT(family_name), .cb = snl_attr_get_string },
94 	{
95 		.type = CTRL_ATTR_MCAST_GROUPS,
96 		.off = _OUT(mcast_groups),
97 		.cb = snl_attr_get_parray,
98 		.arg = &_genl_ctrl_mc_parser,
99 	},
100 };
101 #undef _IN
102 #undef _OUT
103 SNL_DECLARE_GENL_PARSER(_genl_ctrl_getfam_parser, _nla_p_getfam);
104 
105 static bool
106 snl_get_genl_family_info(struct snl_state *ss, const char *family_name,
107     struct _getfamily_attrs *attrs)
108 {
109 	struct snl_writer nw;
110 	struct nlmsghdr *hdr;
111 
112 	memset(attrs, 0, sizeof(*attrs));
113 
114 	snl_init_writer(ss, &nw);
115 	hdr = snl_create_genl_msg_request(&nw, GENL_ID_CTRL, CTRL_CMD_GETFAMILY);
116 	snl_add_msg_attr_string(&nw, CTRL_ATTR_FAMILY_NAME, family_name);
117 	if ((hdr = snl_finalize_msg(&nw)) == NULL || !snl_send_message(ss, hdr))
118 		return (false);
119 
120 	hdr = snl_read_reply(ss, hdr->nlmsg_seq);
121 	if (hdr != NULL && hdr->nlmsg_type != NLMSG_ERROR) {
122 		if (snl_parse_nlmsg(ss, hdr, &_genl_ctrl_getfam_parser, attrs))
123 			return (true);
124 	}
125 
126 	return (false);
127 }
128 
129 static inline uint16_t
130 snl_get_genl_family(struct snl_state *ss, const char *family_name)
131 {
132 	struct _getfamily_attrs attrs = {};
133 
134 	snl_get_genl_family_info(ss, family_name, &attrs);
135 	return (attrs.family_id);
136 }
137 
138 static inline uint16_t
139 snl_get_genl_mcast_group(struct snl_state *ss, const char *family_name,
140     const char *group_name, uint16_t *family_id)
141 {
142 	struct _getfamily_attrs attrs = {};
143 
144 	snl_get_genl_family_info(ss, family_name, &attrs);
145 	if (attrs.family_id == 0)
146 		return (0);
147 	if (family_id != NULL)
148 		*family_id = attrs.family_id;
149 	for (u_int i = 0; i < attrs.mcast_groups.num_groups; i++)
150 		if (strcmp(attrs.mcast_groups.groups[i]->mcast_grp_name,
151                     group_name) == 0)
152 			return (attrs.mcast_groups.groups[i]->mcast_grp_id);
153 	return (0);
154 }
155 
156 static const struct snl_hdr_parser *snl_all_genl_parsers[] = {
157 	&_genl_ctrl_getfam_parser, &_genl_ctrl_mc_parser,
158 };
159 
160 #endif
161