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 *
snl_create_genl_msg_request(struct snl_writer * nw,uint16_t genl_family,uint8_t genl_cmd)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
snl_get_genl_family_info(struct snl_state * ss,const char * family_name,struct _getfamily_attrs * attrs)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
snl_get_genl_family(struct snl_state * ss,const char * family_name)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
snl_get_genl_mcast_group(struct snl_state * ss,const char * family_name,const char * group_name,uint16_t * family_id)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