aboutsummaryrefslogtreecommitdiffstats
path: root/net/netlabel/netlabel_mgmt.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/netlabel/netlabel_mgmt.c')
-rw-r--r--net/netlabel/netlabel_mgmt.c541
1 files changed, 276 insertions, 265 deletions
diff --git a/net/netlabel/netlabel_mgmt.c b/net/netlabel/netlabel_mgmt.c
index 85bc11a1fc46..8626c9f678eb 100644
--- a/net/netlabel/netlabel_mgmt.c
+++ b/net/netlabel/netlabel_mgmt.c
@@ -42,15 +42,29 @@
42#include "netlabel_user.h" 42#include "netlabel_user.h"
43#include "netlabel_mgmt.h" 43#include "netlabel_mgmt.h"
44 44
45/* Argument struct for netlbl_domhsh_walk() */
46struct netlbl_domhsh_walk_arg {
47 struct netlink_callback *nl_cb;
48 struct sk_buff *skb;
49 u32 seq;
50};
51
45/* NetLabel Generic NETLINK CIPSOv4 family */ 52/* NetLabel Generic NETLINK CIPSOv4 family */
46static struct genl_family netlbl_mgmt_gnl_family = { 53static struct genl_family netlbl_mgmt_gnl_family = {
47 .id = GENL_ID_GENERATE, 54 .id = GENL_ID_GENERATE,
48 .hdrsize = 0, 55 .hdrsize = 0,
49 .name = NETLBL_NLTYPE_MGMT_NAME, 56 .name = NETLBL_NLTYPE_MGMT_NAME,
50 .version = NETLBL_PROTO_VERSION, 57 .version = NETLBL_PROTO_VERSION,
51 .maxattr = 0, 58 .maxattr = NLBL_MGMT_A_MAX,
52}; 59};
53 60
61/* NetLabel Netlink attribute policy */
62static struct nla_policy netlbl_mgmt_genl_policy[NLBL_MGMT_A_MAX + 1] = {
63 [NLBL_MGMT_A_DOMAIN] = { .type = NLA_NUL_STRING },
64 [NLBL_MGMT_A_PROTOCOL] = { .type = NLA_U32 },
65 [NLBL_MGMT_A_VERSION] = { .type = NLA_U32 },
66 [NLBL_MGMT_A_CV4DOI] = { .type = NLA_U32 },
67};
54 68
55/* 69/*
56 * NetLabel Command Handlers 70 * NetLabel Command Handlers
@@ -70,97 +84,62 @@ static struct genl_family netlbl_mgmt_gnl_family = {
70static int netlbl_mgmt_add(struct sk_buff *skb, struct genl_info *info) 84static int netlbl_mgmt_add(struct sk_buff *skb, struct genl_info *info)
71{ 85{
72 int ret_val = -EINVAL; 86 int ret_val = -EINVAL;
73 struct nlattr *msg_ptr = netlbl_netlink_payload_data(skb);
74 int msg_len = netlbl_netlink_payload_len(skb);
75 u32 count;
76 struct netlbl_dom_map *entry = NULL; 87 struct netlbl_dom_map *entry = NULL;
77 u32 iter; 88 size_t tmp_size;
78 u32 tmp_val; 89 u32 tmp_val;
79 int tmp_size;
80 90
81 ret_val = netlbl_netlink_cap_check(skb, CAP_NET_ADMIN); 91 if (!info->attrs[NLBL_MGMT_A_DOMAIN] ||
82 if (ret_val != 0) 92 !info->attrs[NLBL_MGMT_A_PROTOCOL])
83 goto add_failure; 93 goto add_failure;
84 94
85 if (msg_len < NETLBL_LEN_U32) 95 entry = kzalloc(sizeof(*entry), GFP_KERNEL);
96 if (entry == NULL) {
97 ret_val = -ENOMEM;
98 goto add_failure;
99 }
100 tmp_size = nla_len(info->attrs[NLBL_MGMT_A_DOMAIN]);
101 entry->domain = kmalloc(tmp_size, GFP_KERNEL);
102 if (entry->domain == NULL) {
103 ret_val = -ENOMEM;
86 goto add_failure; 104 goto add_failure;
87 count = netlbl_getinc_u32(&msg_ptr, &msg_len); 105 }
106 entry->type = nla_get_u32(info->attrs[NLBL_MGMT_A_PROTOCOL]);
107 nla_strlcpy(entry->domain, info->attrs[NLBL_MGMT_A_DOMAIN], tmp_size);
88 108
89 for (iter = 0; iter < count && msg_len > 0; iter++, entry = NULL) { 109 switch (entry->type) {
90 if (msg_len <= 0) { 110 case NETLBL_NLTYPE_UNLABELED:
91 ret_val = -EINVAL; 111 ret_val = netlbl_domhsh_add(entry);
92 goto add_failure; 112 break;
93 } 113 case NETLBL_NLTYPE_CIPSOV4:
94 entry = kzalloc(sizeof(*entry), GFP_KERNEL); 114 if (!info->attrs[NLBL_MGMT_A_CV4DOI])
95 if (entry == NULL) {
96 ret_val = -ENOMEM;
97 goto add_failure;
98 }
99 tmp_size = nla_len(msg_ptr);
100 if (tmp_size <= 0 || tmp_size > msg_len) {
101 ret_val = -EINVAL;
102 goto add_failure;
103 }
104 entry->domain = kmalloc(tmp_size, GFP_KERNEL);
105 if (entry->domain == NULL) {
106 ret_val = -ENOMEM;
107 goto add_failure; 115 goto add_failure;
108 }
109 nla_strlcpy(entry->domain, msg_ptr, tmp_size);
110 entry->domain[tmp_size - 1] = '\0';
111 msg_ptr = nla_next(msg_ptr, &msg_len);
112 116
113 if (msg_len < NETLBL_LEN_U32) { 117 tmp_val = nla_get_u32(info->attrs[NLBL_MGMT_A_CV4DOI]);
114 ret_val = -EINVAL; 118 /* We should be holding a rcu_read_lock() here while we hold
115 goto add_failure; 119 * the result but since the entry will always be deleted when
116 } 120 * the CIPSO DOI is deleted we aren't going to keep the
117 tmp_val = netlbl_getinc_u32(&msg_ptr, &msg_len); 121 * lock. */
118 entry->type = tmp_val; 122 rcu_read_lock();
119 switch (tmp_val) { 123 entry->type_def.cipsov4 = cipso_v4_doi_getdef(tmp_val);
120 case NETLBL_NLTYPE_UNLABELED: 124 if (entry->type_def.cipsov4 == NULL) {
121 ret_val = netlbl_domhsh_add(entry);
122 break;
123 case NETLBL_NLTYPE_CIPSOV4:
124 if (msg_len < NETLBL_LEN_U32) {
125 ret_val = -EINVAL;
126 goto add_failure;
127 }
128 tmp_val = netlbl_getinc_u32(&msg_ptr, &msg_len);
129 /* We should be holding a rcu_read_lock() here
130 * while we hold the result but since the entry
131 * will always be deleted when the CIPSO DOI
132 * is deleted we aren't going to keep the lock. */
133 rcu_read_lock();
134 entry->type_def.cipsov4 = cipso_v4_doi_getdef(tmp_val);
135 if (entry->type_def.cipsov4 == NULL) {
136 rcu_read_unlock();
137 ret_val = -EINVAL;
138 goto add_failure;
139 }
140 ret_val = netlbl_domhsh_add(entry);
141 rcu_read_unlock(); 125 rcu_read_unlock();
142 break;
143 default:
144 ret_val = -EINVAL;
145 }
146 if (ret_val != 0)
147 goto add_failure; 126 goto add_failure;
127 }
128 ret_val = netlbl_domhsh_add(entry);
129 rcu_read_unlock();
130 break;
131 default:
132 goto add_failure;
148 } 133 }
134 if (ret_val != 0)
135 goto add_failure;
149 136
150 netlbl_netlink_send_ack(info,
151 netlbl_mgmt_gnl_family.id,
152 NLBL_MGMT_C_ACK,
153 NETLBL_E_OK);
154 return 0; 137 return 0;
155 138
156add_failure: 139add_failure:
157 if (entry) 140 if (entry)
158 kfree(entry->domain); 141 kfree(entry->domain);
159 kfree(entry); 142 kfree(entry);
160 netlbl_netlink_send_ack(info,
161 netlbl_mgmt_gnl_family.id,
162 NLBL_MGMT_C_ACK,
163 -ret_val);
164 return ret_val; 143 return ret_val;
165} 144}
166 145
@@ -176,87 +155,98 @@ add_failure:
176 */ 155 */
177static int netlbl_mgmt_remove(struct sk_buff *skb, struct genl_info *info) 156static int netlbl_mgmt_remove(struct sk_buff *skb, struct genl_info *info)
178{ 157{
179 int ret_val = -EINVAL; 158 char *domain;
180 struct nlattr *msg_ptr = netlbl_netlink_payload_data(skb);
181 int msg_len = netlbl_netlink_payload_len(skb);
182 u32 count;
183 u32 iter;
184 int tmp_size;
185 unsigned char *domain;
186
187 ret_val = netlbl_netlink_cap_check(skb, CAP_NET_ADMIN);
188 if (ret_val != 0)
189 goto remove_return;
190 159
191 if (msg_len < NETLBL_LEN_U32) 160 if (!info->attrs[NLBL_MGMT_A_DOMAIN])
192 goto remove_return; 161 return -EINVAL;
193 count = netlbl_getinc_u32(&msg_ptr, &msg_len);
194 162
195 for (iter = 0; iter < count && msg_len > 0; iter++) { 163 domain = nla_data(info->attrs[NLBL_MGMT_A_DOMAIN]);
196 if (msg_len <= 0) { 164 return netlbl_domhsh_remove(domain);
197 ret_val = -EINVAL; 165}
198 goto remove_return; 166
199 } 167/**
200 tmp_size = nla_len(msg_ptr); 168 * netlbl_mgmt_listall_cb - netlbl_domhsh_walk() callback for LISTALL
201 domain = nla_data(msg_ptr); 169 * @entry: the domain mapping hash table entry
202 if (tmp_size <= 0 || tmp_size > msg_len || 170 * @arg: the netlbl_domhsh_walk_arg structure
203 domain[tmp_size - 1] != '\0') { 171 *
204 ret_val = -EINVAL; 172 * Description:
205 goto remove_return; 173 * This function is designed to be used as a callback to the
206 } 174 * netlbl_domhsh_walk() function for use in generating a response for a LISTALL
207 ret_val = netlbl_domhsh_remove(domain); 175 * message. Returns the size of the message on success, negative values on
176 * failure.
177 *
178 */
179static int netlbl_mgmt_listall_cb(struct netlbl_dom_map *entry, void *arg)
180{
181 int ret_val = -ENOMEM;
182 struct netlbl_domhsh_walk_arg *cb_arg = arg;
183 void *data;
184
185 data = netlbl_netlink_hdr_put(cb_arg->skb,
186 NETLINK_CB(cb_arg->nl_cb->skb).pid,
187 cb_arg->seq,
188 netlbl_mgmt_gnl_family.id,
189 NLM_F_MULTI,
190 NLBL_MGMT_C_LISTALL);
191 if (data == NULL)
192 goto listall_cb_failure;
193
194 ret_val = nla_put_string(cb_arg->skb,
195 NLBL_MGMT_A_DOMAIN,
196 entry->domain);
197 if (ret_val != 0)
198 goto listall_cb_failure;
199 ret_val = nla_put_u32(cb_arg->skb, NLBL_MGMT_A_PROTOCOL, entry->type);
200 if (ret_val != 0)
201 goto listall_cb_failure;
202 switch (entry->type) {
203 case NETLBL_NLTYPE_CIPSOV4:
204 ret_val = nla_put_u32(cb_arg->skb,
205 NLBL_MGMT_A_CV4DOI,
206 entry->type_def.cipsov4->doi);
208 if (ret_val != 0) 207 if (ret_val != 0)
209 goto remove_return; 208 goto listall_cb_failure;
210 msg_ptr = nla_next(msg_ptr, &msg_len); 209 break;
211 } 210 }
212 211
213 ret_val = 0; 212 cb_arg->seq++;
213 return genlmsg_end(cb_arg->skb, data);
214 214
215remove_return: 215listall_cb_failure:
216 netlbl_netlink_send_ack(info, 216 genlmsg_cancel(cb_arg->skb, data);
217 netlbl_mgmt_gnl_family.id,
218 NLBL_MGMT_C_ACK,
219 -ret_val);
220 return ret_val; 217 return ret_val;
221} 218}
222 219
223/** 220/**
224 * netlbl_mgmt_list - Handle a LIST message 221 * netlbl_mgmt_listall - Handle a LISTALL message
225 * @skb: the NETLINK buffer 222 * @skb: the NETLINK buffer
226 * @info: the Generic NETLINK info block 223 * @cb: the NETLINK callback
227 * 224 *
228 * Description: 225 * Description:
229 * Process a user generated LIST message and dumps the domain hash table in a 226 * Process a user generated LISTALL message and dumps the domain hash table in
230 * form suitable for use in a kernel generated LIST message. Returns zero on 227 * a form suitable for use in a kernel generated LISTALL message. Returns zero
231 * success, negative values on failure. 228 * on success, negative values on failure.
232 * 229 *
233 */ 230 */
234static int netlbl_mgmt_list(struct sk_buff *skb, struct genl_info *info) 231static int netlbl_mgmt_listall(struct sk_buff *skb,
232 struct netlink_callback *cb)
235{ 233{
236 int ret_val = -ENOMEM; 234 struct netlbl_domhsh_walk_arg cb_arg;
237 struct sk_buff *ans_skb; 235 u32 skip_bkt = cb->args[0];
238 236 u32 skip_chain = cb->args[1];
239 ans_skb = netlbl_domhsh_dump(NLMSG_SPACE(GENL_HDRLEN)); 237
240 if (ans_skb == NULL) 238 cb_arg.nl_cb = cb;
241 goto list_failure; 239 cb_arg.skb = skb;
242 netlbl_netlink_hdr_push(ans_skb, 240 cb_arg.seq = cb->nlh->nlmsg_seq;
243 info->snd_pid, 241
244 0, 242 netlbl_domhsh_walk(&skip_bkt,
245 netlbl_mgmt_gnl_family.id, 243 &skip_chain,
246 NLBL_MGMT_C_LIST); 244 netlbl_mgmt_listall_cb,
247 245 &cb_arg);
248 ret_val = netlbl_netlink_snd(ans_skb, info->snd_pid); 246
249 if (ret_val != 0) 247 cb->args[0] = skip_bkt;
250 goto list_failure; 248 cb->args[1] = skip_chain;
251 249 return skb->len;
252 return 0;
253
254list_failure:
255 netlbl_netlink_send_ack(info,
256 netlbl_mgmt_gnl_family.id,
257 NLBL_MGMT_C_ACK,
258 -ret_val);
259 return ret_val;
260} 250}
261 251
262/** 252/**
@@ -272,68 +262,51 @@ list_failure:
272static int netlbl_mgmt_adddef(struct sk_buff *skb, struct genl_info *info) 262static int netlbl_mgmt_adddef(struct sk_buff *skb, struct genl_info *info)
273{ 263{
274 int ret_val = -EINVAL; 264 int ret_val = -EINVAL;
275 struct nlattr *msg_ptr = netlbl_netlink_payload_data(skb);
276 int msg_len = netlbl_netlink_payload_len(skb);
277 struct netlbl_dom_map *entry = NULL; 265 struct netlbl_dom_map *entry = NULL;
278 u32 tmp_val; 266 u32 tmp_val;
279 267
280 ret_val = netlbl_netlink_cap_check(skb, CAP_NET_ADMIN); 268 if (!info->attrs[NLBL_MGMT_A_PROTOCOL])
281 if (ret_val != 0)
282 goto adddef_failure;
283
284 if (msg_len < NETLBL_LEN_U32)
285 goto adddef_failure; 269 goto adddef_failure;
286 tmp_val = netlbl_getinc_u32(&msg_ptr, &msg_len);
287 270
288 entry = kzalloc(sizeof(*entry), GFP_KERNEL); 271 entry = kzalloc(sizeof(*entry), GFP_KERNEL);
289 if (entry == NULL) { 272 if (entry == NULL) {
290 ret_val = -ENOMEM; 273 ret_val = -ENOMEM;
291 goto adddef_failure; 274 goto adddef_failure;
292 } 275 }
276 entry->type = nla_get_u32(info->attrs[NLBL_MGMT_A_PROTOCOL]);
293 277
294 entry->type = tmp_val;
295 switch (entry->type) { 278 switch (entry->type) {
296 case NETLBL_NLTYPE_UNLABELED: 279 case NETLBL_NLTYPE_UNLABELED:
297 ret_val = netlbl_domhsh_add_default(entry); 280 ret_val = netlbl_domhsh_add_default(entry);
298 break; 281 break;
299 case NETLBL_NLTYPE_CIPSOV4: 282 case NETLBL_NLTYPE_CIPSOV4:
300 if (msg_len < NETLBL_LEN_U32) { 283 if (!info->attrs[NLBL_MGMT_A_CV4DOI])
301 ret_val = -EINVAL;
302 goto adddef_failure; 284 goto adddef_failure;
303 } 285
304 tmp_val = netlbl_getinc_u32(&msg_ptr, &msg_len); 286 tmp_val = nla_get_u32(info->attrs[NLBL_MGMT_A_CV4DOI]);
305 /* We should be holding a rcu_read_lock here while we 287 /* We should be holding a rcu_read_lock() here while we hold
306 * hold the result but since the entry will always be 288 * the result but since the entry will always be deleted when
307 * deleted when the CIPSO DOI is deleted we are going 289 * the CIPSO DOI is deleted we aren't going to keep the
308 * to skip the lock. */ 290 * lock. */
309 rcu_read_lock(); 291 rcu_read_lock();
310 entry->type_def.cipsov4 = cipso_v4_doi_getdef(tmp_val); 292 entry->type_def.cipsov4 = cipso_v4_doi_getdef(tmp_val);
311 if (entry->type_def.cipsov4 == NULL) { 293 if (entry->type_def.cipsov4 == NULL) {
312 rcu_read_unlock(); 294 rcu_read_unlock();
313 ret_val = -EINVAL;
314 goto adddef_failure; 295 goto adddef_failure;
315 } 296 }
316 ret_val = netlbl_domhsh_add_default(entry); 297 ret_val = netlbl_domhsh_add_default(entry);
317 rcu_read_unlock(); 298 rcu_read_unlock();
318 break; 299 break;
319 default: 300 default:
320 ret_val = -EINVAL; 301 goto adddef_failure;
321 } 302 }
322 if (ret_val != 0) 303 if (ret_val != 0)
323 goto adddef_failure; 304 goto adddef_failure;
324 305
325 netlbl_netlink_send_ack(info,
326 netlbl_mgmt_gnl_family.id,
327 NLBL_MGMT_C_ACK,
328 NETLBL_E_OK);
329 return 0; 306 return 0;
330 307
331adddef_failure: 308adddef_failure:
332 kfree(entry); 309 kfree(entry);
333 netlbl_netlink_send_ack(info,
334 netlbl_mgmt_gnl_family.id,
335 NLBL_MGMT_C_ACK,
336 -ret_val);
337 return ret_val; 310 return ret_val;
338} 311}
339 312
@@ -349,20 +322,7 @@ adddef_failure:
349 */ 322 */
350static int netlbl_mgmt_removedef(struct sk_buff *skb, struct genl_info *info) 323static int netlbl_mgmt_removedef(struct sk_buff *skb, struct genl_info *info)
351{ 324{
352 int ret_val; 325 return netlbl_domhsh_remove_default();
353
354 ret_val = netlbl_netlink_cap_check(skb, CAP_NET_ADMIN);
355 if (ret_val != 0)
356 goto removedef_return;
357
358 ret_val = netlbl_domhsh_remove_default();
359
360removedef_return:
361 netlbl_netlink_send_ack(info,
362 netlbl_mgmt_gnl_family.id,
363 NLBL_MGMT_C_ACK,
364 -ret_val);
365 return ret_val;
366} 326}
367 327
368/** 328/**
@@ -379,88 +339,131 @@ removedef_return:
379static int netlbl_mgmt_listdef(struct sk_buff *skb, struct genl_info *info) 339static int netlbl_mgmt_listdef(struct sk_buff *skb, struct genl_info *info)
380{ 340{
381 int ret_val = -ENOMEM; 341 int ret_val = -ENOMEM;
382 struct sk_buff *ans_skb; 342 struct sk_buff *ans_skb = NULL;
343 void *data;
344 struct netlbl_dom_map *entry;
383 345
384 ans_skb = netlbl_domhsh_dump_default(NLMSG_SPACE(GENL_HDRLEN)); 346 ans_skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
385 if (ans_skb == NULL) 347 if (ans_skb == NULL)
348 return -ENOMEM;
349 data = netlbl_netlink_hdr_put(ans_skb,
350 info->snd_pid,
351 info->snd_seq,
352 netlbl_mgmt_gnl_family.id,
353 0,
354 NLBL_MGMT_C_LISTDEF);
355 if (data == NULL)
386 goto listdef_failure; 356 goto listdef_failure;
387 netlbl_netlink_hdr_push(ans_skb,
388 info->snd_pid,
389 0,
390 netlbl_mgmt_gnl_family.id,
391 NLBL_MGMT_C_LISTDEF);
392 357
393 ret_val = netlbl_netlink_snd(ans_skb, info->snd_pid); 358 rcu_read_lock();
359 entry = netlbl_domhsh_getentry(NULL);
360 if (entry == NULL) {
361 ret_val = -ENOENT;
362 goto listdef_failure_lock;
363 }
364 ret_val = nla_put_u32(ans_skb, NLBL_MGMT_A_PROTOCOL, entry->type);
394 if (ret_val != 0) 365 if (ret_val != 0)
395 goto listdef_failure; 366 goto listdef_failure_lock;
367 switch (entry->type) {
368 case NETLBL_NLTYPE_CIPSOV4:
369 ret_val = nla_put_u32(ans_skb,
370 NLBL_MGMT_A_CV4DOI,
371 entry->type_def.cipsov4->doi);
372 if (ret_val != 0)
373 goto listdef_failure_lock;
374 break;
375 }
376 rcu_read_unlock();
396 377
378 genlmsg_end(ans_skb, data);
379
380 ret_val = genlmsg_unicast(ans_skb, info->snd_pid);
381 if (ret_val != 0)
382 goto listdef_failure;
397 return 0; 383 return 0;
398 384
385listdef_failure_lock:
386 rcu_read_unlock();
399listdef_failure: 387listdef_failure:
400 netlbl_netlink_send_ack(info, 388 kfree_skb(ans_skb);
401 netlbl_mgmt_gnl_family.id,
402 NLBL_MGMT_C_ACK,
403 -ret_val);
404 return ret_val; 389 return ret_val;
405} 390}
406 391
407/** 392/**
408 * netlbl_mgmt_modules - Handle a MODULES message 393 * netlbl_mgmt_protocols_cb - Write an individual PROTOCOL message response
409 * @skb: the NETLINK buffer 394 * @skb: the skb to write to
410 * @info: the Generic NETLINK info block 395 * @seq: the NETLINK sequence number
396 * @cb: the NETLINK callback
397 * @protocol: the NetLabel protocol to use in the message
411 * 398 *
412 * Description: 399 * Description:
413 * Process a user generated MODULES message and respond accordingly. 400 * This function is to be used in conjunction with netlbl_mgmt_protocols() to
401 * answer a application's PROTOCOLS message. Returns the size of the message
402 * on success, negative values on failure.
414 * 403 *
415 */ 404 */
416static int netlbl_mgmt_modules(struct sk_buff *skb, struct genl_info *info) 405static int netlbl_mgmt_protocols_cb(struct sk_buff *skb,
406 struct netlink_callback *cb,
407 u32 protocol)
417{ 408{
418 int ret_val = -ENOMEM; 409 int ret_val = -ENOMEM;
419 size_t data_size; 410 void *data;
420 u32 mod_count; 411
421 struct sk_buff *ans_skb = NULL; 412 data = netlbl_netlink_hdr_put(skb,
422 413 NETLINK_CB(cb->skb).pid,
423 /* unlabeled + cipsov4 */ 414 cb->nlh->nlmsg_seq,
424 mod_count = 2; 415 netlbl_mgmt_gnl_family.id,
425 416 NLM_F_MULTI,
426 data_size = GENL_HDRLEN + NETLBL_LEN_U32 + mod_count * NETLBL_LEN_U32; 417 NLBL_MGMT_C_PROTOCOLS);
427 ans_skb = netlbl_netlink_alloc_skb(0, data_size, GFP_KERNEL); 418 if (data == NULL)
428 if (ans_skb == NULL) 419 goto protocols_cb_failure;
429 goto modules_failure; 420
430 421 ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL, protocol);
431 if (netlbl_netlink_hdr_put(ans_skb,
432 info->snd_pid,
433 0,
434 netlbl_mgmt_gnl_family.id,
435 NLBL_MGMT_C_MODULES) == NULL)
436 goto modules_failure;
437
438 ret_val = nla_put_u32(ans_skb, NLA_U32, mod_count);
439 if (ret_val != 0)
440 goto modules_failure;
441 ret_val = nla_put_u32(ans_skb, NLA_U32, NETLBL_NLTYPE_UNLABELED);
442 if (ret_val != 0) 422 if (ret_val != 0)
443 goto modules_failure; 423 goto protocols_cb_failure;
444 ret_val = nla_put_u32(ans_skb, NLA_U32, NETLBL_NLTYPE_CIPSOV4);
445 if (ret_val != 0)
446 goto modules_failure;
447
448 ret_val = netlbl_netlink_snd(ans_skb, info->snd_pid);
449 if (ret_val != 0)
450 goto modules_failure;
451 424
452 return 0; 425 return genlmsg_end(skb, data);
453 426
454modules_failure: 427protocols_cb_failure:
455 kfree_skb(ans_skb); 428 genlmsg_cancel(skb, data);
456 netlbl_netlink_send_ack(info,
457 netlbl_mgmt_gnl_family.id,
458 NLBL_MGMT_C_ACK,
459 -ret_val);
460 return ret_val; 429 return ret_val;
461} 430}
462 431
463/** 432/**
433 * netlbl_mgmt_protocols - Handle a PROTOCOLS message
434 * @skb: the NETLINK buffer
435 * @cb: the NETLINK callback
436 *
437 * Description:
438 * Process a user generated PROTOCOLS message and respond accordingly.
439 *
440 */
441static int netlbl_mgmt_protocols(struct sk_buff *skb,
442 struct netlink_callback *cb)
443{
444 u32 protos_sent = cb->args[0];
445
446 if (protos_sent == 0) {
447 if (netlbl_mgmt_protocols_cb(skb,
448 cb,
449 NETLBL_NLTYPE_UNLABELED) < 0)
450 goto protocols_return;
451 protos_sent++;
452 }
453 if (protos_sent == 1) {
454 if (netlbl_mgmt_protocols_cb(skb,
455 cb,
456 NETLBL_NLTYPE_CIPSOV4) < 0)
457 goto protocols_return;
458 protos_sent++;
459 }
460
461protocols_return:
462 cb->args[0] = protos_sent;
463 return skb->len;
464}
465
466/**
464 * netlbl_mgmt_version - Handle a VERSION message 467 * netlbl_mgmt_version - Handle a VERSION message
465 * @skb: the NETLINK buffer 468 * @skb: the NETLINK buffer
466 * @info: the Generic NETLINK info block 469 * @info: the Generic NETLINK info block
@@ -474,35 +477,35 @@ static int netlbl_mgmt_version(struct sk_buff *skb, struct genl_info *info)
474{ 477{
475 int ret_val = -ENOMEM; 478 int ret_val = -ENOMEM;
476 struct sk_buff *ans_skb = NULL; 479 struct sk_buff *ans_skb = NULL;
480 void *data;
477 481
478 ans_skb = netlbl_netlink_alloc_skb(0, 482 ans_skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
479 GENL_HDRLEN + NETLBL_LEN_U32,
480 GFP_KERNEL);
481 if (ans_skb == NULL) 483 if (ans_skb == NULL)
482 goto version_failure; 484 return -ENOMEM;
483 if (netlbl_netlink_hdr_put(ans_skb, 485 data = netlbl_netlink_hdr_put(ans_skb,
484 info->snd_pid, 486 info->snd_pid,
485 0, 487 info->snd_seq,
486 netlbl_mgmt_gnl_family.id, 488 netlbl_mgmt_gnl_family.id,
487 NLBL_MGMT_C_VERSION) == NULL) 489 0,
490 NLBL_MGMT_C_VERSION);
491 if (data == NULL)
488 goto version_failure; 492 goto version_failure;
489 493
490 ret_val = nla_put_u32(ans_skb, NLA_U32, NETLBL_PROTO_VERSION); 494 ret_val = nla_put_u32(ans_skb,
495 NLBL_MGMT_A_VERSION,
496 NETLBL_PROTO_VERSION);
491 if (ret_val != 0) 497 if (ret_val != 0)
492 goto version_failure; 498 goto version_failure;
493 499
494 ret_val = netlbl_netlink_snd(ans_skb, info->snd_pid); 500 genlmsg_end(ans_skb, data);
501
502 ret_val = genlmsg_unicast(ans_skb, info->snd_pid);
495 if (ret_val != 0) 503 if (ret_val != 0)
496 goto version_failure; 504 goto version_failure;
497
498 return 0; 505 return 0;
499 506
500version_failure: 507version_failure:
501 kfree_skb(ans_skb); 508 kfree_skb(ans_skb);
502 netlbl_netlink_send_ack(info,
503 netlbl_mgmt_gnl_family.id,
504 NLBL_MGMT_C_ACK,
505 -ret_val);
506 return ret_val; 509 return ret_val;
507} 510}
508 511
@@ -513,35 +516,40 @@ version_failure:
513 516
514static struct genl_ops netlbl_mgmt_genl_c_add = { 517static struct genl_ops netlbl_mgmt_genl_c_add = {
515 .cmd = NLBL_MGMT_C_ADD, 518 .cmd = NLBL_MGMT_C_ADD,
516 .flags = 0, 519 .flags = GENL_ADMIN_PERM,
520 .policy = netlbl_mgmt_genl_policy,
517 .doit = netlbl_mgmt_add, 521 .doit = netlbl_mgmt_add,
518 .dumpit = NULL, 522 .dumpit = NULL,
519}; 523};
520 524
521static struct genl_ops netlbl_mgmt_genl_c_remove = { 525static struct genl_ops netlbl_mgmt_genl_c_remove = {
522 .cmd = NLBL_MGMT_C_REMOVE, 526 .cmd = NLBL_MGMT_C_REMOVE,
523 .flags = 0, 527 .flags = GENL_ADMIN_PERM,
528 .policy = netlbl_mgmt_genl_policy,
524 .doit = netlbl_mgmt_remove, 529 .doit = netlbl_mgmt_remove,
525 .dumpit = NULL, 530 .dumpit = NULL,
526}; 531};
527 532
528static struct genl_ops netlbl_mgmt_genl_c_list = { 533static struct genl_ops netlbl_mgmt_genl_c_listall = {
529 .cmd = NLBL_MGMT_C_LIST, 534 .cmd = NLBL_MGMT_C_LISTALL,
530 .flags = 0, 535 .flags = 0,
531 .doit = netlbl_mgmt_list, 536 .policy = netlbl_mgmt_genl_policy,
532 .dumpit = NULL, 537 .doit = NULL,
538 .dumpit = netlbl_mgmt_listall,
533}; 539};
534 540
535static struct genl_ops netlbl_mgmt_genl_c_adddef = { 541static struct genl_ops netlbl_mgmt_genl_c_adddef = {
536 .cmd = NLBL_MGMT_C_ADDDEF, 542 .cmd = NLBL_MGMT_C_ADDDEF,
537 .flags = 0, 543 .flags = GENL_ADMIN_PERM,
544 .policy = netlbl_mgmt_genl_policy,
538 .doit = netlbl_mgmt_adddef, 545 .doit = netlbl_mgmt_adddef,
539 .dumpit = NULL, 546 .dumpit = NULL,
540}; 547};
541 548
542static struct genl_ops netlbl_mgmt_genl_c_removedef = { 549static struct genl_ops netlbl_mgmt_genl_c_removedef = {
543 .cmd = NLBL_MGMT_C_REMOVEDEF, 550 .cmd = NLBL_MGMT_C_REMOVEDEF,
544 .flags = 0, 551 .flags = GENL_ADMIN_PERM,
552 .policy = netlbl_mgmt_genl_policy,
545 .doit = netlbl_mgmt_removedef, 553 .doit = netlbl_mgmt_removedef,
546 .dumpit = NULL, 554 .dumpit = NULL,
547}; 555};
@@ -549,20 +557,23 @@ static struct genl_ops netlbl_mgmt_genl_c_removedef = {
549static struct genl_ops netlbl_mgmt_genl_c_listdef = { 557static struct genl_ops netlbl_mgmt_genl_c_listdef = {
550 .cmd = NLBL_MGMT_C_LISTDEF, 558 .cmd = NLBL_MGMT_C_LISTDEF,
551 .flags = 0, 559 .flags = 0,
560 .policy = netlbl_mgmt_genl_policy,
552 .doit = netlbl_mgmt_listdef, 561 .doit = netlbl_mgmt_listdef,
553 .dumpit = NULL, 562 .dumpit = NULL,
554}; 563};
555 564
556static struct genl_ops netlbl_mgmt_genl_c_modules = { 565static struct genl_ops netlbl_mgmt_genl_c_protocols = {
557 .cmd = NLBL_MGMT_C_MODULES, 566 .cmd = NLBL_MGMT_C_PROTOCOLS,
558 .flags = 0, 567 .flags = 0,
559 .doit = netlbl_mgmt_modules, 568 .policy = netlbl_mgmt_genl_policy,
560 .dumpit = NULL, 569 .doit = NULL,
570 .dumpit = netlbl_mgmt_protocols,
561}; 571};
562 572
563static struct genl_ops netlbl_mgmt_genl_c_version = { 573static struct genl_ops netlbl_mgmt_genl_c_version = {
564 .cmd = NLBL_MGMT_C_VERSION, 574 .cmd = NLBL_MGMT_C_VERSION,
565 .flags = 0, 575 .flags = 0,
576 .policy = netlbl_mgmt_genl_policy,
566 .doit = netlbl_mgmt_version, 577 .doit = netlbl_mgmt_version,
567 .dumpit = NULL, 578 .dumpit = NULL,
568}; 579};
@@ -596,7 +607,7 @@ int netlbl_mgmt_genl_init(void)
596 if (ret_val != 0) 607 if (ret_val != 0)
597 return ret_val; 608 return ret_val;
598 ret_val = genl_register_ops(&netlbl_mgmt_gnl_family, 609 ret_val = genl_register_ops(&netlbl_mgmt_gnl_family,
599 &netlbl_mgmt_genl_c_list); 610 &netlbl_mgmt_genl_c_listall);
600 if (ret_val != 0) 611 if (ret_val != 0)
601 return ret_val; 612 return ret_val;
602 ret_val = genl_register_ops(&netlbl_mgmt_gnl_family, 613 ret_val = genl_register_ops(&netlbl_mgmt_gnl_family,
@@ -612,7 +623,7 @@ int netlbl_mgmt_genl_init(void)
612 if (ret_val != 0) 623 if (ret_val != 0)
613 return ret_val; 624 return ret_val;
614 ret_val = genl_register_ops(&netlbl_mgmt_gnl_family, 625 ret_val = genl_register_ops(&netlbl_mgmt_gnl_family,
615 &netlbl_mgmt_genl_c_modules); 626 &netlbl_mgmt_genl_c_protocols);
616 if (ret_val != 0) 627 if (ret_val != 0)
617 return ret_val; 628 return ret_val;
618 ret_val = genl_register_ops(&netlbl_mgmt_gnl_family, 629 ret_val = genl_register_ops(&netlbl_mgmt_gnl_family,