1 /*
2  * lib/genl/family.c		Generic Netlink Family
3  *
4  *	This library is free software; you can redistribute it and/or
5  *	modify it under the terms of the GNU Lesser General Public
6  *	License as published by the Free Software Foundation version 2.1
7  *	of the License.
8  *
9  * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
10  */
11 
12 /**
13  * @ingroup genl
14  * @defgroup genl_family Generic Netlink Family
15  * @brief
16  *
17  * @{
18  */
19 
20 #include <netlink-generic.h>
21 #include <netlink/netlink.h>
22 #include <netlink/genl/genl.h>
23 #include <netlink/genl/family.h>
24 #include <netlink/utils.h>
25 
26 /** @cond SKIP */
27 #define FAMILY_ATTR_ID		0x01
28 #define FAMILY_ATTR_NAME	0x02
29 #define FAMILY_ATTR_VERSION	0x04
30 #define FAMILY_ATTR_HDRSIZE	0x08
31 #define FAMILY_ATTR_MAXATTR	0x10
32 #define FAMILY_ATTR_OPS		0x20
33 
34 struct nl_object_ops genl_family_ops;
35 /** @endcond */
36 
family_constructor(struct nl_object * c)37 static void family_constructor(struct nl_object *c)
38 {
39 	struct genl_family *family = (struct genl_family *) c;
40 
41 	nl_init_list_head(&family->gf_ops);
42 }
43 
family_free_data(struct nl_object * c)44 static void family_free_data(struct nl_object *c)
45 {
46 	struct genl_family *family = (struct genl_family *) c;
47 	struct genl_family_op *ops, *tmp;
48 
49 	if (family == NULL)
50 		return;
51 
52 	nl_list_for_each_entry_safe(ops, tmp, &family->gf_ops, o_list) {
53 		nl_list_del(&ops->o_list);
54 		free(ops);
55 	}
56 }
57 
family_clone(struct nl_object * _dst,struct nl_object * _src)58 static int family_clone(struct nl_object *_dst, struct nl_object *_src)
59 {
60 	struct genl_family *dst = nl_object_priv(_dst);
61 	struct genl_family *src = nl_object_priv(_src);
62 	struct genl_family_op *ops;
63 	int err;
64 
65 	nl_list_for_each_entry(ops, &src->gf_ops, o_list) {
66 		err = genl_family_add_op(dst, ops->o_id, ops->o_flags);
67 		if (err < 0)
68 			return err;
69 	}
70 
71 	return 0;
72 }
73 
family_dump_line(struct nl_object * obj,struct nl_dump_params * p)74 static void family_dump_line(struct nl_object *obj, struct nl_dump_params *p)
75 {
76 	struct genl_family *family = (struct genl_family *) obj;
77 
78 	nl_dump(p, "0x%04x %s version %u\n",
79 		family->gf_id, family->gf_name, family->gf_version);
80 }
81 
82 static struct trans_tbl ops_flags[] = {
83 	__ADD(GENL_ADMIN_PERM, admin-perm)
84 	__ADD(GENL_CMD_CAP_DO, has-doit)
85 	__ADD(GENL_CMD_CAP_DUMP, has-dump)
86 	__ADD(GENL_CMD_CAP_HASPOL, has-policy)
87 };
88 
ops_flags2str(int flags,char * buf,size_t len)89 static char *ops_flags2str(int flags, char *buf, size_t len)
90 {
91 	return __flags2str(flags, buf, len, ops_flags, ARRAY_SIZE(ops_flags));
92 }
93 
family_dump_details(struct nl_object * obj,struct nl_dump_params * p)94 static void family_dump_details(struct nl_object *obj, struct nl_dump_params *p)
95 {
96 	struct genl_family *family = (struct genl_family *) obj;
97 
98 	family_dump_line(obj, p);
99 	nl_dump_line(p, "    hdrsize %u maxattr %u\n",
100 		     family->gf_hdrsize, family->gf_maxattr);
101 
102 	if (family->ce_mask & FAMILY_ATTR_OPS) {
103 		struct genl_family_op *op;
104 		char buf[64];
105 
106 		nl_list_for_each_entry(op, &family->gf_ops, o_list) {
107 			ops_flags2str(op->o_flags, buf, sizeof(buf));
108 
109 			genl_op2name(family->gf_id, op->o_id, buf, sizeof(buf));
110 
111 			nl_dump_line(p, "      op %s (0x%02x)", buf, op->o_id);
112 
113 			if (op->o_flags)
114 				nl_dump(p, " <%s>",
115 					ops_flags2str(op->o_flags, buf,
116 						      sizeof(buf)));
117 
118 			nl_dump(p, "\n");
119 		}
120 	}
121 }
122 
family_dump_stats(struct nl_object * obj,struct nl_dump_params * p)123 static void family_dump_stats(struct nl_object *obj, struct nl_dump_params *p)
124 {
125 	family_dump_details(obj, p);
126 }
127 
family_compare(struct nl_object * _a,struct nl_object * _b,uint32_t attrs,int flags)128 static int family_compare(struct nl_object *_a, struct nl_object *_b,
129 			  uint32_t attrs, int flags)
130 {
131 	struct genl_family *a = (struct genl_family *) _a;
132 	struct genl_family *b = (struct genl_family *) _b;
133 	int diff = 0;
134 
135 #define FAM_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, FAMILY_ATTR_##ATTR, a, b, EXPR)
136 
137 	diff |= FAM_DIFF(ID,		a->gf_id != b->gf_id);
138 	diff |= FAM_DIFF(VERSION,	a->gf_version != b->gf_version);
139 	diff |= FAM_DIFF(HDRSIZE,	a->gf_hdrsize != b->gf_hdrsize);
140 	diff |= FAM_DIFF(MAXATTR,	a->gf_maxattr != b->gf_maxattr);
141 	diff |= FAM_DIFF(NAME,		strcmp(a->gf_name, b->gf_name));
142 
143 #undef FAM_DIFF
144 
145 	return diff;
146 }
147 
148 
149 /**
150  * @name Family Object
151  * @{
152  */
153 
genl_family_alloc(void)154 struct genl_family *genl_family_alloc(void)
155 {
156 	return (struct genl_family *) nl_object_alloc(&genl_family_ops);
157 }
158 
genl_family_put(struct genl_family * family)159 void genl_family_put(struct genl_family *family)
160 {
161 	nl_object_put((struct nl_object *) family);
162 }
163 
164 /** @} */
165 
166 /**
167  * @name Attributes
168  * @{
169  */
170 
genl_family_get_id(struct genl_family * family)171 unsigned int genl_family_get_id(struct genl_family *family)
172 {
173 	if (family->ce_mask & FAMILY_ATTR_ID)
174 		return family->gf_id;
175 	else
176 		return GENL_ID_GENERATE;
177 }
178 
genl_family_set_id(struct genl_family * family,unsigned int id)179 void genl_family_set_id(struct genl_family *family, unsigned int id)
180 {
181 	family->gf_id = id;
182 	family->ce_mask |= FAMILY_ATTR_ID;
183 }
184 
genl_family_get_name(struct genl_family * family)185 char *genl_family_get_name(struct genl_family *family)
186 {
187 	if (family->ce_mask & FAMILY_ATTR_NAME)
188 		return family->gf_name;
189 	else
190 		return NULL;
191 }
192 
genl_family_set_name(struct genl_family * family,const char * name)193 void genl_family_set_name(struct genl_family *family, const char *name)
194 {
195 	strncpy(family->gf_name, name, GENL_NAMSIZ-1);
196 	family->ce_mask |= FAMILY_ATTR_NAME;
197 }
198 
genl_family_get_version(struct genl_family * family)199 uint8_t genl_family_get_version(struct genl_family *family)
200 {
201 	if (family->ce_mask & FAMILY_ATTR_VERSION)
202 		return family->gf_version;
203 	else
204 		return 0;
205 }
206 
genl_family_set_version(struct genl_family * family,uint8_t version)207 void genl_family_set_version(struct genl_family *family, uint8_t version)
208 {
209 	family->gf_version = version;
210 	family->ce_mask |= FAMILY_ATTR_VERSION;
211 }
212 
genl_family_get_hdrsize(struct genl_family * family)213 uint32_t genl_family_get_hdrsize(struct genl_family *family)
214 {
215 	if (family->ce_mask & FAMILY_ATTR_HDRSIZE)
216 		return family->gf_hdrsize;
217 	else
218 		return 0;
219 }
220 
genl_family_set_hdrsize(struct genl_family * family,uint32_t hdrsize)221 void genl_family_set_hdrsize(struct genl_family *family, uint32_t hdrsize)
222 {
223 	family->gf_hdrsize = hdrsize;
224 	family->ce_mask |= FAMILY_ATTR_HDRSIZE;
225 }
226 
genl_family_get_maxattr(struct genl_family * family)227 uint32_t genl_family_get_maxattr(struct genl_family *family)
228 {
229 	if (family->ce_mask & FAMILY_ATTR_MAXATTR)
230 		return family->gf_maxattr;
231 	else
232 		return family->gf_maxattr;
233 }
234 
genl_family_set_maxattr(struct genl_family * family,uint32_t maxattr)235 void genl_family_set_maxattr(struct genl_family *family, uint32_t maxattr)
236 {
237 	family->gf_maxattr = maxattr;
238 	family->ce_mask |= FAMILY_ATTR_MAXATTR;
239 }
240 
genl_family_add_op(struct genl_family * family,int id,int flags)241 int genl_family_add_op(struct genl_family *family, int id, int flags)
242 {
243 	struct genl_family_op *op;
244 
245 	op = calloc(1, sizeof(*op));
246 	if (op == NULL)
247 		return -NLE_NOMEM;
248 
249 	op->o_id = id;
250 	op->o_flags = flags;
251 
252 	nl_list_add_tail(&op->o_list, &family->gf_ops);
253 	family->ce_mask |= FAMILY_ATTR_OPS;
254 
255 	return 0;
256 }
257 
258 /** @} */
259 
260 /** @cond SKIP */
261 struct nl_object_ops genl_family_ops = {
262 	.oo_name		= "genl/family",
263 	.oo_size		= sizeof(struct genl_family),
264 	.oo_constructor		= family_constructor,
265 	.oo_free_data		= family_free_data,
266 	.oo_clone		= family_clone,
267 	.oo_dump = {
268 	    [NL_DUMP_LINE]	= family_dump_line,
269 	    [NL_DUMP_DETAILS]	= family_dump_details,
270 	    [NL_DUMP_STATS]	= family_dump_stats,
271 	},
272 	.oo_compare		= family_compare,
273 	.oo_id_attrs		= FAMILY_ATTR_ID,
274 };
275 /** @endcond */
276 
277 /** @} */
278