diff options
Diffstat (limited to 'drivers/staging/pohmelfs/config.c')
-rw-r--r-- | drivers/staging/pohmelfs/config.c | 611 |
1 files changed, 0 insertions, 611 deletions
diff --git a/drivers/staging/pohmelfs/config.c b/drivers/staging/pohmelfs/config.c deleted file mode 100644 index b6c42cb0d1c6..000000000000 --- a/drivers/staging/pohmelfs/config.c +++ /dev/null @@ -1,611 +0,0 @@ -/* - * 2007+ Copyright (c) Evgeniy Polyakov <zbr@ioremap.net> - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include <linux/kernel.h> -#include <linux/connector.h> -#include <linux/crypto.h> -#include <linux/list.h> -#include <linux/mutex.h> -#include <linux/string.h> -#include <linux/in.h> -#include <linux/slab.h> - -#include "netfs.h" - -/* - * Global configuration list. - * Each client can be asked to get one of them. - * - * Allows to provide remote server address (ipv4/v6/whatever), port - * and so on via kernel connector. - */ - -static struct cb_id pohmelfs_cn_id = {.idx = POHMELFS_CN_IDX, .val = POHMELFS_CN_VAL}; -static LIST_HEAD(pohmelfs_config_list); -static DEFINE_MUTEX(pohmelfs_config_lock); - -static inline int pohmelfs_config_eql(struct pohmelfs_ctl *sc, struct pohmelfs_ctl *ctl) -{ - if (sc->idx == ctl->idx && sc->type == ctl->type && - sc->proto == ctl->proto && - sc->addrlen == ctl->addrlen && - !memcmp(&sc->addr, &ctl->addr, ctl->addrlen)) - return 1; - - return 0; -} - -static struct pohmelfs_config_group *pohmelfs_find_config_group(unsigned int idx) -{ - struct pohmelfs_config_group *g, *group = NULL; - - list_for_each_entry(g, &pohmelfs_config_list, group_entry) { - if (g->idx == idx) { - group = g; - break; - } - } - - return group; -} - -static struct pohmelfs_config_group *pohmelfs_find_create_config_group(unsigned int idx) -{ - struct pohmelfs_config_group *g; - - g = pohmelfs_find_config_group(idx); - if (g) - return g; - - g = kzalloc(sizeof(struct pohmelfs_config_group), GFP_KERNEL); - if (!g) - return NULL; - - INIT_LIST_HEAD(&g->config_list); - g->idx = idx; - g->num_entry = 0; - - list_add_tail(&g->group_entry, &pohmelfs_config_list); - - return g; -} - -static inline void pohmelfs_insert_config_entry(struct pohmelfs_sb *psb, struct pohmelfs_config *dst) -{ - struct pohmelfs_config *tmp; - - INIT_LIST_HEAD(&dst->config_entry); - - list_for_each_entry(tmp, &psb->state_list, config_entry) { - if (dst->state.ctl.prio > tmp->state.ctl.prio) - list_add_tail(&dst->config_entry, &tmp->config_entry); - } - if (list_empty(&dst->config_entry)) - list_add_tail(&dst->config_entry, &psb->state_list); -} - -static int pohmelfs_move_config_entry(struct pohmelfs_sb *psb, - struct pohmelfs_config *dst, struct pohmelfs_config *new) -{ - if ((dst->state.ctl.prio == new->state.ctl.prio) && - (dst->state.ctl.perm == new->state.ctl.perm)) - return 0; - - dprintk("%s: dst: prio: %d, perm: %x, new: prio: %d, perm: %d.\n", - __func__, dst->state.ctl.prio, dst->state.ctl.perm, - new->state.ctl.prio, new->state.ctl.perm); - dst->state.ctl.prio = new->state.ctl.prio; - dst->state.ctl.perm = new->state.ctl.perm; - - list_del_init(&dst->config_entry); - pohmelfs_insert_config_entry(psb, dst); - return 0; -} - -/* - * pohmelfs_copy_config() is used to copy new state configs from the - * config group (controlled by the netlink messages) into the superblock. - * This happens either at startup time where no transactions can access - * the list of the configs (and thus list of the network states), or at - * run-time, where it is protected by the psb->state_lock. - */ -int pohmelfs_copy_config(struct pohmelfs_sb *psb) -{ - struct pohmelfs_config_group *g; - struct pohmelfs_config *c, *dst; - int err = -ENODEV; - - mutex_lock(&pohmelfs_config_lock); - - g = pohmelfs_find_config_group(psb->idx); - if (!g) - goto out_unlock; - - /* - * Run over all entries in given config group and try to create and - * initialize those, which do not exist in superblock list. - * Skip all existing entries. - */ - - list_for_each_entry(c, &g->config_list, config_entry) { - err = 0; - list_for_each_entry(dst, &psb->state_list, config_entry) { - if (pohmelfs_config_eql(&dst->state.ctl, &c->state.ctl)) { - err = pohmelfs_move_config_entry(psb, dst, c); - if (!err) - err = -EEXIST; - break; - } - } - - if (err) - continue; - - dst = kzalloc(sizeof(struct pohmelfs_config), GFP_KERNEL); - if (!dst) { - err = -ENOMEM; - break; - } - - memcpy(&dst->state.ctl, &c->state.ctl, sizeof(struct pohmelfs_ctl)); - - pohmelfs_insert_config_entry(psb, dst); - - err = pohmelfs_state_init_one(psb, dst); - if (err) { - list_del(&dst->config_entry); - kfree(dst); - } - - err = 0; - } - -out_unlock: - mutex_unlock(&pohmelfs_config_lock); - - return err; -} - -int pohmelfs_copy_crypto(struct pohmelfs_sb *psb) -{ - struct pohmelfs_config_group *g; - int err = -ENOENT; - - mutex_lock(&pohmelfs_config_lock); - g = pohmelfs_find_config_group(psb->idx); - if (!g) - goto err_out_exit; - - if (g->hash_string) { - err = -ENOMEM; - psb->hash_string = kstrdup(g->hash_string, GFP_KERNEL); - if (!psb->hash_string) - goto err_out_exit; - psb->hash_strlen = g->hash_strlen; - } - - if (g->cipher_string) { - psb->cipher_string = kstrdup(g->cipher_string, GFP_KERNEL); - if (!psb->cipher_string) - goto err_out_free_hash_string; - psb->cipher_strlen = g->cipher_strlen; - } - - if (g->hash_keysize) { - psb->hash_key = kmemdup(g->hash_key, g->hash_keysize, - GFP_KERNEL); - if (!psb->hash_key) - goto err_out_free_cipher_string; - psb->hash_keysize = g->hash_keysize; - } - - if (g->cipher_keysize) { - psb->cipher_key = kmemdup(g->cipher_key, g->cipher_keysize, - GFP_KERNEL); - if (!psb->cipher_key) - goto err_out_free_hash; - psb->cipher_keysize = g->cipher_keysize; - } - - mutex_unlock(&pohmelfs_config_lock); - - return 0; - -err_out_free_hash: - kfree(psb->hash_key); -err_out_free_cipher_string: - kfree(psb->cipher_string); -err_out_free_hash_string: - kfree(psb->hash_string); -err_out_exit: - mutex_unlock(&pohmelfs_config_lock); - return err; -} - -static int pohmelfs_send_reply(int err, int msg_num, int action, struct cn_msg *msg, struct pohmelfs_ctl *ctl) -{ - struct pohmelfs_cn_ack *ack; - - ack = kzalloc(sizeof(struct pohmelfs_cn_ack), GFP_KERNEL); - if (!ack) - return -ENOMEM; - - memcpy(&ack->msg, msg, sizeof(struct cn_msg)); - - if (action == POHMELFS_CTLINFO_ACK) - memcpy(&ack->ctl, ctl, sizeof(struct pohmelfs_ctl)); - - ack->msg.len = sizeof(struct pohmelfs_cn_ack) - sizeof(struct cn_msg); - ack->msg.ack = msg->ack + 1; - ack->error = err; - ack->msg_num = msg_num; - - cn_netlink_send(&ack->msg, 0, GFP_KERNEL); - kfree(ack); - return 0; -} - -static int pohmelfs_cn_disp(struct cn_msg *msg) -{ - struct pohmelfs_config_group *g; - struct pohmelfs_ctl *ctl = (struct pohmelfs_ctl *)msg->data; - struct pohmelfs_config *c, *tmp; - int err = 0, i = 1; - - if (msg->len != sizeof(struct pohmelfs_ctl)) - return -EBADMSG; - - mutex_lock(&pohmelfs_config_lock); - - g = pohmelfs_find_config_group(ctl->idx); - if (!g) { - pohmelfs_send_reply(err, 0, POHMELFS_NOINFO_ACK, msg, NULL); - goto out_unlock; - } - - list_for_each_entry_safe(c, tmp, &g->config_list, config_entry) { - struct pohmelfs_ctl *sc = &c->state.ctl; - if (pohmelfs_send_reply(err, g->num_entry - i, POHMELFS_CTLINFO_ACK, msg, sc)) { - err = -ENOMEM; - goto out_unlock; - } - i += 1; - } - - out_unlock: - mutex_unlock(&pohmelfs_config_lock); - return err; -} - -static int pohmelfs_cn_dump(struct cn_msg *msg) -{ - struct pohmelfs_config_group *g; - struct pohmelfs_config *c, *tmp; - int err = 0, i = 1; - int total_msg = 0; - - if (msg->len != sizeof(struct pohmelfs_ctl)) - return -EBADMSG; - - mutex_lock(&pohmelfs_config_lock); - - list_for_each_entry(g, &pohmelfs_config_list, group_entry) - total_msg += g->num_entry; - if (total_msg == 0) { - if (pohmelfs_send_reply(err, 0, POHMELFS_NOINFO_ACK, msg, NULL)) - err = -ENOMEM; - goto out_unlock; - } - - list_for_each_entry(g, &pohmelfs_config_list, group_entry) { - list_for_each_entry_safe(c, tmp, &g->config_list, - config_entry) { - struct pohmelfs_ctl *sc = &c->state.ctl; - if (pohmelfs_send_reply(err, total_msg - i, - POHMELFS_CTLINFO_ACK, msg, - sc)) { - err = -ENOMEM; - goto out_unlock; - } - i += 1; - } - } - -out_unlock: - mutex_unlock(&pohmelfs_config_lock); - return err; -} - -static int pohmelfs_cn_flush(struct cn_msg *msg) -{ - struct pohmelfs_config_group *g; - struct pohmelfs_ctl *ctl = (struct pohmelfs_ctl *)msg->data; - struct pohmelfs_config *c, *tmp; - int err = 0; - - if (msg->len != sizeof(struct pohmelfs_ctl)) - return -EBADMSG; - - mutex_lock(&pohmelfs_config_lock); - - if (ctl->idx != POHMELFS_NULL_IDX) { - g = pohmelfs_find_config_group(ctl->idx); - - if (!g) - goto out_unlock; - - list_for_each_entry_safe(c, tmp, &g->config_list, config_entry) { - list_del(&c->config_entry); - g->num_entry--; - kfree(c); - } - } else { - list_for_each_entry(g, &pohmelfs_config_list, group_entry) { - list_for_each_entry_safe(c, tmp, &g->config_list, - config_entry) { - list_del(&c->config_entry); - g->num_entry--; - kfree(c); - } - } - } - -out_unlock: - mutex_unlock(&pohmelfs_config_lock); - pohmelfs_cn_dump(msg); - - return err; -} - -static int pohmelfs_modify_config(struct pohmelfs_ctl *old, struct pohmelfs_ctl *new) -{ - old->perm = new->perm; - old->prio = new->prio; - return 0; -} - -static int pohmelfs_cn_ctl(struct cn_msg *msg, int action) -{ - struct pohmelfs_config_group *g; - struct pohmelfs_ctl *ctl = (struct pohmelfs_ctl *)msg->data; - struct pohmelfs_config *c, *tmp; - int err = 0; - - if (msg->len != sizeof(struct pohmelfs_ctl)) - return -EBADMSG; - - mutex_lock(&pohmelfs_config_lock); - - g = pohmelfs_find_create_config_group(ctl->idx); - if (!g) { - err = -ENOMEM; - goto out_unlock; - } - - list_for_each_entry_safe(c, tmp, &g->config_list, config_entry) { - struct pohmelfs_ctl *sc = &c->state.ctl; - - if (pohmelfs_config_eql(sc, ctl)) { - if (action == POHMELFS_FLAGS_ADD) { - err = -EEXIST; - goto out_unlock; - } else if (action == POHMELFS_FLAGS_DEL) { - list_del(&c->config_entry); - g->num_entry--; - kfree(c); - goto out_unlock; - } else if (action == POHMELFS_FLAGS_MODIFY) { - err = pohmelfs_modify_config(sc, ctl); - goto out_unlock; - } else { - err = -EEXIST; - goto out_unlock; - } - } - } - if (action == POHMELFS_FLAGS_DEL) { - err = -EBADMSG; - goto out_unlock; - } - - c = kzalloc(sizeof(struct pohmelfs_config), GFP_KERNEL); - if (!c) { - err = -ENOMEM; - goto out_unlock; - } - memcpy(&c->state.ctl, ctl, sizeof(struct pohmelfs_ctl)); - g->num_entry++; - - list_add_tail(&c->config_entry, &g->config_list); - - out_unlock: - mutex_unlock(&pohmelfs_config_lock); - if (pohmelfs_send_reply(err, 0, POHMELFS_NOINFO_ACK, msg, NULL)) - err = -ENOMEM; - - return err; -} - -static int pohmelfs_crypto_hash_init(struct pohmelfs_config_group *g, struct pohmelfs_crypto *c) -{ - char *algo = (char *)c->data; - u8 *key = (u8 *)(algo + c->strlen); - - if (g->hash_string) - return -EEXIST; - - g->hash_string = kstrdup(algo, GFP_KERNEL); - if (!g->hash_string) - return -ENOMEM; - g->hash_strlen = c->strlen; - g->hash_keysize = c->keysize; - - g->hash_key = kmemdup(key, c->keysize, GFP_KERNEL); - if (!g->hash_key) { - kfree(g->hash_string); - return -ENOMEM; - } - - return 0; -} - -static int pohmelfs_crypto_cipher_init(struct pohmelfs_config_group *g, struct pohmelfs_crypto *c) -{ - char *algo = (char *)c->data; - u8 *key = (u8 *)(algo + c->strlen); - - if (g->cipher_string) - return -EEXIST; - - g->cipher_string = kstrdup(algo, GFP_KERNEL); - if (!g->cipher_string) - return -ENOMEM; - g->cipher_strlen = c->strlen; - g->cipher_keysize = c->keysize; - - g->cipher_key = kmemdup(key, c->keysize, GFP_KERNEL); - if (!g->cipher_key) { - kfree(g->cipher_string); - return -ENOMEM; - } - - return 0; -} - -static int pohmelfs_cn_crypto(struct cn_msg *msg) -{ - struct pohmelfs_crypto *crypto = (struct pohmelfs_crypto *)msg->data; - struct pohmelfs_config_group *g; - int err = 0; - - dprintk("%s: idx: %u, strlen: %u, type: %u, keysize: %u, algo: %s.\n", - __func__, crypto->idx, crypto->strlen, crypto->type, - crypto->keysize, (char *)crypto->data); - - mutex_lock(&pohmelfs_config_lock); - g = pohmelfs_find_create_config_group(crypto->idx); - if (!g) { - err = -ENOMEM; - goto out_unlock; - } - - switch (crypto->type) { - case POHMELFS_CRYPTO_HASH: - err = pohmelfs_crypto_hash_init(g, crypto); - break; - case POHMELFS_CRYPTO_CIPHER: - err = pohmelfs_crypto_cipher_init(g, crypto); - break; - default: - err = -ENOTSUPP; - break; - } - -out_unlock: - mutex_unlock(&pohmelfs_config_lock); - if (pohmelfs_send_reply(err, 0, POHMELFS_NOINFO_ACK, msg, NULL)) - err = -ENOMEM; - - return err; -} - -static void pohmelfs_cn_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp) -{ - int err; - - if (!cap_raised(current_cap(), CAP_SYS_ADMIN)) - return; - - switch (msg->flags) { - case POHMELFS_FLAGS_ADD: - case POHMELFS_FLAGS_DEL: - case POHMELFS_FLAGS_MODIFY: - err = pohmelfs_cn_ctl(msg, msg->flags); - break; - case POHMELFS_FLAGS_FLUSH: - err = pohmelfs_cn_flush(msg); - break; - case POHMELFS_FLAGS_SHOW: - err = pohmelfs_cn_disp(msg); - break; - case POHMELFS_FLAGS_DUMP: - err = pohmelfs_cn_dump(msg); - break; - case POHMELFS_FLAGS_CRYPTO: - err = pohmelfs_cn_crypto(msg); - break; - default: - err = -ENOSYS; - break; - } -} - -int pohmelfs_config_check(struct pohmelfs_config *config, int idx) -{ - struct pohmelfs_ctl *ctl = &config->state.ctl; - struct pohmelfs_config *tmp; - int err = -ENOENT; - struct pohmelfs_ctl *sc; - struct pohmelfs_config_group *g; - - mutex_lock(&pohmelfs_config_lock); - - g = pohmelfs_find_config_group(ctl->idx); - if (g) { - list_for_each_entry(tmp, &g->config_list, config_entry) { - sc = &tmp->state.ctl; - - if (pohmelfs_config_eql(sc, ctl)) { - err = 0; - break; - } - } - } - - mutex_unlock(&pohmelfs_config_lock); - - return err; -} - -int __init pohmelfs_config_init(void) -{ - /* XXX remove (void *) cast when vanilla connector got synced */ - return cn_add_callback(&pohmelfs_cn_id, "pohmelfs", (void *)pohmelfs_cn_callback); -} - -void pohmelfs_config_exit(void) -{ - struct pohmelfs_config *c, *tmp; - struct pohmelfs_config_group *g, *gtmp; - - cn_del_callback(&pohmelfs_cn_id); - - mutex_lock(&pohmelfs_config_lock); - list_for_each_entry_safe(g, gtmp, &pohmelfs_config_list, group_entry) { - list_for_each_entry_safe(c, tmp, &g->config_list, config_entry) { - list_del(&c->config_entry); - kfree(c); - } - - list_del(&g->group_entry); - - kfree(g->hash_string); - - kfree(g->cipher_string); - - kfree(g); - } - mutex_unlock(&pohmelfs_config_lock); -} |