diff options
author | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-22 10:38:37 -0500 |
---|---|---|
committer | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-22 10:38:37 -0500 |
commit | fcc9d2e5a6c89d22b8b773a64fb4ad21ac318446 (patch) | |
tree | a57612d1888735a2ec7972891b68c1ac5ec8faea /drivers/staging/pohmelfs/config.c | |
parent | 8dea78da5cee153b8af9c07a2745f6c55057fe12 (diff) |
Diffstat (limited to 'drivers/staging/pohmelfs/config.c')
-rw-r--r-- | drivers/staging/pohmelfs/config.c | 611 |
1 files changed, 611 insertions, 0 deletions
diff --git a/drivers/staging/pohmelfs/config.c b/drivers/staging/pohmelfs/config.c new file mode 100644 index 00000000000..b6c42cb0d1c --- /dev/null +++ b/drivers/staging/pohmelfs/config.c | |||
@@ -0,0 +1,611 @@ | |||
1 | /* | ||
2 | * 2007+ Copyright (c) Evgeniy Polyakov <zbr@ioremap.net> | ||
3 | * All rights reserved. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | */ | ||
15 | |||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/connector.h> | ||
18 | #include <linux/crypto.h> | ||
19 | #include <linux/list.h> | ||
20 | #include <linux/mutex.h> | ||
21 | #include <linux/string.h> | ||
22 | #include <linux/in.h> | ||
23 | #include <linux/slab.h> | ||
24 | |||
25 | #include "netfs.h" | ||
26 | |||
27 | /* | ||
28 | * Global configuration list. | ||
29 | * Each client can be asked to get one of them. | ||
30 | * | ||
31 | * Allows to provide remote server address (ipv4/v6/whatever), port | ||
32 | * and so on via kernel connector. | ||
33 | */ | ||
34 | |||
35 | static struct cb_id pohmelfs_cn_id = {.idx = POHMELFS_CN_IDX, .val = POHMELFS_CN_VAL}; | ||
36 | static LIST_HEAD(pohmelfs_config_list); | ||
37 | static DEFINE_MUTEX(pohmelfs_config_lock); | ||
38 | |||
39 | static inline int pohmelfs_config_eql(struct pohmelfs_ctl *sc, struct pohmelfs_ctl *ctl) | ||
40 | { | ||
41 | if (sc->idx == ctl->idx && sc->type == ctl->type && | ||
42 | sc->proto == ctl->proto && | ||
43 | sc->addrlen == ctl->addrlen && | ||
44 | !memcmp(&sc->addr, &ctl->addr, ctl->addrlen)) | ||
45 | return 1; | ||
46 | |||
47 | return 0; | ||
48 | } | ||
49 | |||
50 | static struct pohmelfs_config_group *pohmelfs_find_config_group(unsigned int idx) | ||
51 | { | ||
52 | struct pohmelfs_config_group *g, *group = NULL; | ||
53 | |||
54 | list_for_each_entry(g, &pohmelfs_config_list, group_entry) { | ||
55 | if (g->idx == idx) { | ||
56 | group = g; | ||
57 | break; | ||
58 | } | ||
59 | } | ||
60 | |||
61 | return group; | ||
62 | } | ||
63 | |||
64 | static struct pohmelfs_config_group *pohmelfs_find_create_config_group(unsigned int idx) | ||
65 | { | ||
66 | struct pohmelfs_config_group *g; | ||
67 | |||
68 | g = pohmelfs_find_config_group(idx); | ||
69 | if (g) | ||
70 | return g; | ||
71 | |||
72 | g = kzalloc(sizeof(struct pohmelfs_config_group), GFP_KERNEL); | ||
73 | if (!g) | ||
74 | return NULL; | ||
75 | |||
76 | INIT_LIST_HEAD(&g->config_list); | ||
77 | g->idx = idx; | ||
78 | g->num_entry = 0; | ||
79 | |||
80 | list_add_tail(&g->group_entry, &pohmelfs_config_list); | ||
81 | |||
82 | return g; | ||
83 | } | ||
84 | |||
85 | static inline void pohmelfs_insert_config_entry(struct pohmelfs_sb *psb, struct pohmelfs_config *dst) | ||
86 | { | ||
87 | struct pohmelfs_config *tmp; | ||
88 | |||
89 | INIT_LIST_HEAD(&dst->config_entry); | ||
90 | |||
91 | list_for_each_entry(tmp, &psb->state_list, config_entry) { | ||
92 | if (dst->state.ctl.prio > tmp->state.ctl.prio) | ||
93 | list_add_tail(&dst->config_entry, &tmp->config_entry); | ||
94 | } | ||
95 | if (list_empty(&dst->config_entry)) | ||
96 | list_add_tail(&dst->config_entry, &psb->state_list); | ||
97 | } | ||
98 | |||
99 | static int pohmelfs_move_config_entry(struct pohmelfs_sb *psb, | ||
100 | struct pohmelfs_config *dst, struct pohmelfs_config *new) | ||
101 | { | ||
102 | if ((dst->state.ctl.prio == new->state.ctl.prio) && | ||
103 | (dst->state.ctl.perm == new->state.ctl.perm)) | ||
104 | return 0; | ||
105 | |||
106 | dprintk("%s: dst: prio: %d, perm: %x, new: prio: %d, perm: %d.\n", | ||
107 | __func__, dst->state.ctl.prio, dst->state.ctl.perm, | ||
108 | new->state.ctl.prio, new->state.ctl.perm); | ||
109 | dst->state.ctl.prio = new->state.ctl.prio; | ||
110 | dst->state.ctl.perm = new->state.ctl.perm; | ||
111 | |||
112 | list_del_init(&dst->config_entry); | ||
113 | pohmelfs_insert_config_entry(psb, dst); | ||
114 | return 0; | ||
115 | } | ||
116 | |||
117 | /* | ||
118 | * pohmelfs_copy_config() is used to copy new state configs from the | ||
119 | * config group (controlled by the netlink messages) into the superblock. | ||
120 | * This happens either at startup time where no transactions can access | ||
121 | * the list of the configs (and thus list of the network states), or at | ||
122 | * run-time, where it is protected by the psb->state_lock. | ||
123 | */ | ||
124 | int pohmelfs_copy_config(struct pohmelfs_sb *psb) | ||
125 | { | ||
126 | struct pohmelfs_config_group *g; | ||
127 | struct pohmelfs_config *c, *dst; | ||
128 | int err = -ENODEV; | ||
129 | |||
130 | mutex_lock(&pohmelfs_config_lock); | ||
131 | |||
132 | g = pohmelfs_find_config_group(psb->idx); | ||
133 | if (!g) | ||
134 | goto out_unlock; | ||
135 | |||
136 | /* | ||
137 | * Run over all entries in given config group and try to create and | ||
138 | * initialize those, which do not exist in superblock list. | ||
139 | * Skip all existing entries. | ||
140 | */ | ||
141 | |||
142 | list_for_each_entry(c, &g->config_list, config_entry) { | ||
143 | err = 0; | ||
144 | list_for_each_entry(dst, &psb->state_list, config_entry) { | ||
145 | if (pohmelfs_config_eql(&dst->state.ctl, &c->state.ctl)) { | ||
146 | err = pohmelfs_move_config_entry(psb, dst, c); | ||
147 | if (!err) | ||
148 | err = -EEXIST; | ||
149 | break; | ||
150 | } | ||
151 | } | ||
152 | |||
153 | if (err) | ||
154 | continue; | ||
155 | |||
156 | dst = kzalloc(sizeof(struct pohmelfs_config), GFP_KERNEL); | ||
157 | if (!dst) { | ||
158 | err = -ENOMEM; | ||
159 | break; | ||
160 | } | ||
161 | |||
162 | memcpy(&dst->state.ctl, &c->state.ctl, sizeof(struct pohmelfs_ctl)); | ||
163 | |||
164 | pohmelfs_insert_config_entry(psb, dst); | ||
165 | |||
166 | err = pohmelfs_state_init_one(psb, dst); | ||
167 | if (err) { | ||
168 | list_del(&dst->config_entry); | ||
169 | kfree(dst); | ||
170 | } | ||
171 | |||
172 | err = 0; | ||
173 | } | ||
174 | |||
175 | out_unlock: | ||
176 | mutex_unlock(&pohmelfs_config_lock); | ||
177 | |||
178 | return err; | ||
179 | } | ||
180 | |||
181 | int pohmelfs_copy_crypto(struct pohmelfs_sb *psb) | ||
182 | { | ||
183 | struct pohmelfs_config_group *g; | ||
184 | int err = -ENOENT; | ||
185 | |||
186 | mutex_lock(&pohmelfs_config_lock); | ||
187 | g = pohmelfs_find_config_group(psb->idx); | ||
188 | if (!g) | ||
189 | goto err_out_exit; | ||
190 | |||
191 | if (g->hash_string) { | ||
192 | err = -ENOMEM; | ||
193 | psb->hash_string = kstrdup(g->hash_string, GFP_KERNEL); | ||
194 | if (!psb->hash_string) | ||
195 | goto err_out_exit; | ||
196 | psb->hash_strlen = g->hash_strlen; | ||
197 | } | ||
198 | |||
199 | if (g->cipher_string) { | ||
200 | psb->cipher_string = kstrdup(g->cipher_string, GFP_KERNEL); | ||
201 | if (!psb->cipher_string) | ||
202 | goto err_out_free_hash_string; | ||
203 | psb->cipher_strlen = g->cipher_strlen; | ||
204 | } | ||
205 | |||
206 | if (g->hash_keysize) { | ||
207 | psb->hash_key = kmemdup(g->hash_key, g->hash_keysize, | ||
208 | GFP_KERNEL); | ||
209 | if (!psb->hash_key) | ||
210 | goto err_out_free_cipher_string; | ||
211 | psb->hash_keysize = g->hash_keysize; | ||
212 | } | ||
213 | |||
214 | if (g->cipher_keysize) { | ||
215 | psb->cipher_key = kmemdup(g->cipher_key, g->cipher_keysize, | ||
216 | GFP_KERNEL); | ||
217 | if (!psb->cipher_key) | ||
218 | goto err_out_free_hash; | ||
219 | psb->cipher_keysize = g->cipher_keysize; | ||
220 | } | ||
221 | |||
222 | mutex_unlock(&pohmelfs_config_lock); | ||
223 | |||
224 | return 0; | ||
225 | |||
226 | err_out_free_hash: | ||
227 | kfree(psb->hash_key); | ||
228 | err_out_free_cipher_string: | ||
229 | kfree(psb->cipher_string); | ||
230 | err_out_free_hash_string: | ||
231 | kfree(psb->hash_string); | ||
232 | err_out_exit: | ||
233 | mutex_unlock(&pohmelfs_config_lock); | ||
234 | return err; | ||
235 | } | ||
236 | |||
237 | static int pohmelfs_send_reply(int err, int msg_num, int action, struct cn_msg *msg, struct pohmelfs_ctl *ctl) | ||
238 | { | ||
239 | struct pohmelfs_cn_ack *ack; | ||
240 | |||
241 | ack = kzalloc(sizeof(struct pohmelfs_cn_ack), GFP_KERNEL); | ||
242 | if (!ack) | ||
243 | return -ENOMEM; | ||
244 | |||
245 | memcpy(&ack->msg, msg, sizeof(struct cn_msg)); | ||
246 | |||
247 | if (action == POHMELFS_CTLINFO_ACK) | ||
248 | memcpy(&ack->ctl, ctl, sizeof(struct pohmelfs_ctl)); | ||
249 | |||
250 | ack->msg.len = sizeof(struct pohmelfs_cn_ack) - sizeof(struct cn_msg); | ||
251 | ack->msg.ack = msg->ack + 1; | ||
252 | ack->error = err; | ||
253 | ack->msg_num = msg_num; | ||
254 | |||
255 | cn_netlink_send(&ack->msg, 0, GFP_KERNEL); | ||
256 | kfree(ack); | ||
257 | return 0; | ||
258 | } | ||
259 | |||
260 | static int pohmelfs_cn_disp(struct cn_msg *msg) | ||
261 | { | ||
262 | struct pohmelfs_config_group *g; | ||
263 | struct pohmelfs_ctl *ctl = (struct pohmelfs_ctl *)msg->data; | ||
264 | struct pohmelfs_config *c, *tmp; | ||
265 | int err = 0, i = 1; | ||
266 | |||
267 | if (msg->len != sizeof(struct pohmelfs_ctl)) | ||
268 | return -EBADMSG; | ||
269 | |||
270 | mutex_lock(&pohmelfs_config_lock); | ||
271 | |||
272 | g = pohmelfs_find_config_group(ctl->idx); | ||
273 | if (!g) { | ||
274 | pohmelfs_send_reply(err, 0, POHMELFS_NOINFO_ACK, msg, NULL); | ||
275 | goto out_unlock; | ||
276 | } | ||
277 | |||
278 | list_for_each_entry_safe(c, tmp, &g->config_list, config_entry) { | ||
279 | struct pohmelfs_ctl *sc = &c->state.ctl; | ||
280 | if (pohmelfs_send_reply(err, g->num_entry - i, POHMELFS_CTLINFO_ACK, msg, sc)) { | ||
281 | err = -ENOMEM; | ||
282 | goto out_unlock; | ||
283 | } | ||
284 | i += 1; | ||
285 | } | ||
286 | |||
287 | out_unlock: | ||
288 | mutex_unlock(&pohmelfs_config_lock); | ||
289 | return err; | ||
290 | } | ||
291 | |||
292 | static int pohmelfs_cn_dump(struct cn_msg *msg) | ||
293 | { | ||
294 | struct pohmelfs_config_group *g; | ||
295 | struct pohmelfs_config *c, *tmp; | ||
296 | int err = 0, i = 1; | ||
297 | int total_msg = 0; | ||
298 | |||
299 | if (msg->len != sizeof(struct pohmelfs_ctl)) | ||
300 | return -EBADMSG; | ||
301 | |||
302 | mutex_lock(&pohmelfs_config_lock); | ||
303 | |||
304 | list_for_each_entry(g, &pohmelfs_config_list, group_entry) | ||
305 | total_msg += g->num_entry; | ||
306 | if (total_msg == 0) { | ||
307 | if (pohmelfs_send_reply(err, 0, POHMELFS_NOINFO_ACK, msg, NULL)) | ||
308 | err = -ENOMEM; | ||
309 | goto out_unlock; | ||
310 | } | ||
311 | |||
312 | list_for_each_entry(g, &pohmelfs_config_list, group_entry) { | ||
313 | list_for_each_entry_safe(c, tmp, &g->config_list, | ||
314 | config_entry) { | ||
315 | struct pohmelfs_ctl *sc = &c->state.ctl; | ||
316 | if (pohmelfs_send_reply(err, total_msg - i, | ||
317 | POHMELFS_CTLINFO_ACK, msg, | ||
318 | sc)) { | ||
319 | err = -ENOMEM; | ||
320 | goto out_unlock; | ||
321 | } | ||
322 | i += 1; | ||
323 | } | ||
324 | } | ||
325 | |||
326 | out_unlock: | ||
327 | mutex_unlock(&pohmelfs_config_lock); | ||
328 | return err; | ||
329 | } | ||
330 | |||
331 | static int pohmelfs_cn_flush(struct cn_msg *msg) | ||
332 | { | ||
333 | struct pohmelfs_config_group *g; | ||
334 | struct pohmelfs_ctl *ctl = (struct pohmelfs_ctl *)msg->data; | ||
335 | struct pohmelfs_config *c, *tmp; | ||
336 | int err = 0; | ||
337 | |||
338 | if (msg->len != sizeof(struct pohmelfs_ctl)) | ||
339 | return -EBADMSG; | ||
340 | |||
341 | mutex_lock(&pohmelfs_config_lock); | ||
342 | |||
343 | if (ctl->idx != POHMELFS_NULL_IDX) { | ||
344 | g = pohmelfs_find_config_group(ctl->idx); | ||
345 | |||
346 | if (!g) | ||
347 | goto out_unlock; | ||
348 | |||
349 | list_for_each_entry_safe(c, tmp, &g->config_list, config_entry) { | ||
350 | list_del(&c->config_entry); | ||
351 | g->num_entry--; | ||
352 | kfree(c); | ||
353 | } | ||
354 | } else { | ||
355 | list_for_each_entry(g, &pohmelfs_config_list, group_entry) { | ||
356 | list_for_each_entry_safe(c, tmp, &g->config_list, | ||
357 | config_entry) { | ||
358 | list_del(&c->config_entry); | ||
359 | g->num_entry--; | ||
360 | kfree(c); | ||
361 | } | ||
362 | } | ||
363 | } | ||
364 | |||
365 | out_unlock: | ||
366 | mutex_unlock(&pohmelfs_config_lock); | ||
367 | pohmelfs_cn_dump(msg); | ||
368 | |||
369 | return err; | ||
370 | } | ||
371 | |||
372 | static int pohmelfs_modify_config(struct pohmelfs_ctl *old, struct pohmelfs_ctl *new) | ||
373 | { | ||
374 | old->perm = new->perm; | ||
375 | old->prio = new->prio; | ||
376 | return 0; | ||
377 | } | ||
378 | |||
379 | static int pohmelfs_cn_ctl(struct cn_msg *msg, int action) | ||
380 | { | ||
381 | struct pohmelfs_config_group *g; | ||
382 | struct pohmelfs_ctl *ctl = (struct pohmelfs_ctl *)msg->data; | ||
383 | struct pohmelfs_config *c, *tmp; | ||
384 | int err = 0; | ||
385 | |||
386 | if (msg->len != sizeof(struct pohmelfs_ctl)) | ||
387 | return -EBADMSG; | ||
388 | |||
389 | mutex_lock(&pohmelfs_config_lock); | ||
390 | |||
391 | g = pohmelfs_find_create_config_group(ctl->idx); | ||
392 | if (!g) { | ||
393 | err = -ENOMEM; | ||
394 | goto out_unlock; | ||
395 | } | ||
396 | |||
397 | list_for_each_entry_safe(c, tmp, &g->config_list, config_entry) { | ||
398 | struct pohmelfs_ctl *sc = &c->state.ctl; | ||
399 | |||
400 | if (pohmelfs_config_eql(sc, ctl)) { | ||
401 | if (action == POHMELFS_FLAGS_ADD) { | ||
402 | err = -EEXIST; | ||
403 | goto out_unlock; | ||
404 | } else if (action == POHMELFS_FLAGS_DEL) { | ||
405 | list_del(&c->config_entry); | ||
406 | g->num_entry--; | ||
407 | kfree(c); | ||
408 | goto out_unlock; | ||
409 | } else if (action == POHMELFS_FLAGS_MODIFY) { | ||
410 | err = pohmelfs_modify_config(sc, ctl); | ||
411 | goto out_unlock; | ||
412 | } else { | ||
413 | err = -EEXIST; | ||
414 | goto out_unlock; | ||
415 | } | ||
416 | } | ||
417 | } | ||
418 | if (action == POHMELFS_FLAGS_DEL) { | ||
419 | err = -EBADMSG; | ||
420 | goto out_unlock; | ||
421 | } | ||
422 | |||
423 | c = kzalloc(sizeof(struct pohmelfs_config), GFP_KERNEL); | ||
424 | if (!c) { | ||
425 | err = -ENOMEM; | ||
426 | goto out_unlock; | ||
427 | } | ||
428 | memcpy(&c->state.ctl, ctl, sizeof(struct pohmelfs_ctl)); | ||
429 | g->num_entry++; | ||
430 | |||
431 | list_add_tail(&c->config_entry, &g->config_list); | ||
432 | |||
433 | out_unlock: | ||
434 | mutex_unlock(&pohmelfs_config_lock); | ||
435 | if (pohmelfs_send_reply(err, 0, POHMELFS_NOINFO_ACK, msg, NULL)) | ||
436 | err = -ENOMEM; | ||
437 | |||
438 | return err; | ||
439 | } | ||
440 | |||
441 | static int pohmelfs_crypto_hash_init(struct pohmelfs_config_group *g, struct pohmelfs_crypto *c) | ||
442 | { | ||
443 | char *algo = (char *)c->data; | ||
444 | u8 *key = (u8 *)(algo + c->strlen); | ||
445 | |||
446 | if (g->hash_string) | ||
447 | return -EEXIST; | ||
448 | |||
449 | g->hash_string = kstrdup(algo, GFP_KERNEL); | ||
450 | if (!g->hash_string) | ||
451 | return -ENOMEM; | ||
452 | g->hash_strlen = c->strlen; | ||
453 | g->hash_keysize = c->keysize; | ||
454 | |||
455 | g->hash_key = kmemdup(key, c->keysize, GFP_KERNEL); | ||
456 | if (!g->hash_key) { | ||
457 | kfree(g->hash_string); | ||
458 | return -ENOMEM; | ||
459 | } | ||
460 | |||
461 | return 0; | ||
462 | } | ||
463 | |||
464 | static int pohmelfs_crypto_cipher_init(struct pohmelfs_config_group *g, struct pohmelfs_crypto *c) | ||
465 | { | ||
466 | char *algo = (char *)c->data; | ||
467 | u8 *key = (u8 *)(algo + c->strlen); | ||
468 | |||
469 | if (g->cipher_string) | ||
470 | return -EEXIST; | ||
471 | |||
472 | g->cipher_string = kstrdup(algo, GFP_KERNEL); | ||
473 | if (!g->cipher_string) | ||
474 | return -ENOMEM; | ||
475 | g->cipher_strlen = c->strlen; | ||
476 | g->cipher_keysize = c->keysize; | ||
477 | |||
478 | g->cipher_key = kmemdup(key, c->keysize, GFP_KERNEL); | ||
479 | if (!g->cipher_key) { | ||
480 | kfree(g->cipher_string); | ||
481 | return -ENOMEM; | ||
482 | } | ||
483 | |||
484 | return 0; | ||
485 | } | ||
486 | |||
487 | static int pohmelfs_cn_crypto(struct cn_msg *msg) | ||
488 | { | ||
489 | struct pohmelfs_crypto *crypto = (struct pohmelfs_crypto *)msg->data; | ||
490 | struct pohmelfs_config_group *g; | ||
491 | int err = 0; | ||
492 | |||
493 | dprintk("%s: idx: %u, strlen: %u, type: %u, keysize: %u, algo: %s.\n", | ||
494 | __func__, crypto->idx, crypto->strlen, crypto->type, | ||
495 | crypto->keysize, (char *)crypto->data); | ||
496 | |||
497 | mutex_lock(&pohmelfs_config_lock); | ||
498 | g = pohmelfs_find_create_config_group(crypto->idx); | ||
499 | if (!g) { | ||
500 | err = -ENOMEM; | ||
501 | goto out_unlock; | ||
502 | } | ||
503 | |||
504 | switch (crypto->type) { | ||
505 | case POHMELFS_CRYPTO_HASH: | ||
506 | err = pohmelfs_crypto_hash_init(g, crypto); | ||
507 | break; | ||
508 | case POHMELFS_CRYPTO_CIPHER: | ||
509 | err = pohmelfs_crypto_cipher_init(g, crypto); | ||
510 | break; | ||
511 | default: | ||
512 | err = -ENOTSUPP; | ||
513 | break; | ||
514 | } | ||
515 | |||
516 | out_unlock: | ||
517 | mutex_unlock(&pohmelfs_config_lock); | ||
518 | if (pohmelfs_send_reply(err, 0, POHMELFS_NOINFO_ACK, msg, NULL)) | ||
519 | err = -ENOMEM; | ||
520 | |||
521 | return err; | ||
522 | } | ||
523 | |||
524 | static void pohmelfs_cn_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp) | ||
525 | { | ||
526 | int err; | ||
527 | |||
528 | if (!cap_raised(current_cap(), CAP_SYS_ADMIN)) | ||
529 | return; | ||
530 | |||
531 | switch (msg->flags) { | ||
532 | case POHMELFS_FLAGS_ADD: | ||
533 | case POHMELFS_FLAGS_DEL: | ||
534 | case POHMELFS_FLAGS_MODIFY: | ||
535 | err = pohmelfs_cn_ctl(msg, msg->flags); | ||
536 | break; | ||
537 | case POHMELFS_FLAGS_FLUSH: | ||
538 | err = pohmelfs_cn_flush(msg); | ||
539 | break; | ||
540 | case POHMELFS_FLAGS_SHOW: | ||
541 | err = pohmelfs_cn_disp(msg); | ||
542 | break; | ||
543 | case POHMELFS_FLAGS_DUMP: | ||
544 | err = pohmelfs_cn_dump(msg); | ||
545 | break; | ||
546 | case POHMELFS_FLAGS_CRYPTO: | ||
547 | err = pohmelfs_cn_crypto(msg); | ||
548 | break; | ||
549 | default: | ||
550 | err = -ENOSYS; | ||
551 | break; | ||
552 | } | ||
553 | } | ||
554 | |||
555 | int pohmelfs_config_check(struct pohmelfs_config *config, int idx) | ||
556 | { | ||
557 | struct pohmelfs_ctl *ctl = &config->state.ctl; | ||
558 | struct pohmelfs_config *tmp; | ||
559 | int err = -ENOENT; | ||
560 | struct pohmelfs_ctl *sc; | ||
561 | struct pohmelfs_config_group *g; | ||
562 | |||
563 | mutex_lock(&pohmelfs_config_lock); | ||
564 | |||
565 | g = pohmelfs_find_config_group(ctl->idx); | ||
566 | if (g) { | ||
567 | list_for_each_entry(tmp, &g->config_list, config_entry) { | ||
568 | sc = &tmp->state.ctl; | ||
569 | |||
570 | if (pohmelfs_config_eql(sc, ctl)) { | ||
571 | err = 0; | ||
572 | break; | ||
573 | } | ||
574 | } | ||
575 | } | ||
576 | |||
577 | mutex_unlock(&pohmelfs_config_lock); | ||
578 | |||
579 | return err; | ||
580 | } | ||
581 | |||
582 | int __init pohmelfs_config_init(void) | ||
583 | { | ||
584 | /* XXX remove (void *) cast when vanilla connector got synced */ | ||
585 | return cn_add_callback(&pohmelfs_cn_id, "pohmelfs", (void *)pohmelfs_cn_callback); | ||
586 | } | ||
587 | |||
588 | void pohmelfs_config_exit(void) | ||
589 | { | ||
590 | struct pohmelfs_config *c, *tmp; | ||
591 | struct pohmelfs_config_group *g, *gtmp; | ||
592 | |||
593 | cn_del_callback(&pohmelfs_cn_id); | ||
594 | |||
595 | mutex_lock(&pohmelfs_config_lock); | ||
596 | list_for_each_entry_safe(g, gtmp, &pohmelfs_config_list, group_entry) { | ||
597 | list_for_each_entry_safe(c, tmp, &g->config_list, config_entry) { | ||
598 | list_del(&c->config_entry); | ||
599 | kfree(c); | ||
600 | } | ||
601 | |||
602 | list_del(&g->group_entry); | ||
603 | |||
604 | kfree(g->hash_string); | ||
605 | |||
606 | kfree(g->cipher_string); | ||
607 | |||
608 | kfree(g); | ||
609 | } | ||
610 | mutex_unlock(&pohmelfs_config_lock); | ||
611 | } | ||