1b2cbae2cSRoland Dreier /* 2b2cbae2cSRoland Dreier * Copyright (c) 2010 Voltaire Inc. All rights reserved. 3b2cbae2cSRoland Dreier * 4b2cbae2cSRoland Dreier * This software is available to you under a choice of one of two 5b2cbae2cSRoland Dreier * licenses. You may choose to be licensed under the terms of the GNU 6b2cbae2cSRoland Dreier * General Public License (GPL) Version 2, available from the file 7b2cbae2cSRoland Dreier * COPYING in the main directory of this source tree, or the 8b2cbae2cSRoland Dreier * OpenIB.org BSD license below: 9b2cbae2cSRoland Dreier * 10b2cbae2cSRoland Dreier * Redistribution and use in source and binary forms, with or 11b2cbae2cSRoland Dreier * without modification, are permitted provided that the following 12b2cbae2cSRoland Dreier * conditions are met: 13b2cbae2cSRoland Dreier * 14b2cbae2cSRoland Dreier * - Redistributions of source code must retain the above 15b2cbae2cSRoland Dreier * copyright notice, this list of conditions and the following 16b2cbae2cSRoland Dreier * disclaimer. 17b2cbae2cSRoland Dreier * 18b2cbae2cSRoland Dreier * - Redistributions in binary form must reproduce the above 19b2cbae2cSRoland Dreier * copyright notice, this list of conditions and the following 20b2cbae2cSRoland Dreier * disclaimer in the documentation and/or other materials 21b2cbae2cSRoland Dreier * provided with the distribution. 22b2cbae2cSRoland Dreier * 23b2cbae2cSRoland Dreier * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 24b2cbae2cSRoland Dreier * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 25b2cbae2cSRoland Dreier * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26b2cbae2cSRoland Dreier * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27b2cbae2cSRoland Dreier * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28b2cbae2cSRoland Dreier * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29b2cbae2cSRoland Dreier * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30b2cbae2cSRoland Dreier * SOFTWARE. 31b2cbae2cSRoland Dreier */ 32b2cbae2cSRoland Dreier 33b2cbae2cSRoland Dreier #define pr_fmt(fmt) "%s:%s: " fmt, KBUILD_MODNAME, __func__ 34b2cbae2cSRoland Dreier 35b108d976SPaul Gortmaker #include <linux/export.h> 36b2cbae2cSRoland Dreier #include <net/netlink.h> 37b2cbae2cSRoland Dreier #include <net/net_namespace.h> 38b2cbae2cSRoland Dreier #include <net/sock.h> 39b2cbae2cSRoland Dreier #include <rdma/rdma_netlink.h> 40b2cbae2cSRoland Dreier 41b2cbae2cSRoland Dreier struct ibnl_client { 42b2cbae2cSRoland Dreier struct list_head list; 43b2cbae2cSRoland Dreier int index; 44b2cbae2cSRoland Dreier int nops; 45b2cbae2cSRoland Dreier const struct ibnl_client_cbs *cb_table; 46b2cbae2cSRoland Dreier }; 47b2cbae2cSRoland Dreier 48b2cbae2cSRoland Dreier static DEFINE_MUTEX(ibnl_mutex); 49b2cbae2cSRoland Dreier static struct sock *nls; 50b2cbae2cSRoland Dreier static LIST_HEAD(client_list); 51b2cbae2cSRoland Dreier 52b2cbae2cSRoland Dreier int ibnl_add_client(int index, int nops, 53b2cbae2cSRoland Dreier const struct ibnl_client_cbs cb_table[]) 54b2cbae2cSRoland Dreier { 55b2cbae2cSRoland Dreier struct ibnl_client *cur; 56b2cbae2cSRoland Dreier struct ibnl_client *nl_client; 57b2cbae2cSRoland Dreier 58b2cbae2cSRoland Dreier nl_client = kmalloc(sizeof *nl_client, GFP_KERNEL); 59b2cbae2cSRoland Dreier if (!nl_client) 60b2cbae2cSRoland Dreier return -ENOMEM; 61b2cbae2cSRoland Dreier 62b2cbae2cSRoland Dreier nl_client->index = index; 63b2cbae2cSRoland Dreier nl_client->nops = nops; 64b2cbae2cSRoland Dreier nl_client->cb_table = cb_table; 65b2cbae2cSRoland Dreier 66b2cbae2cSRoland Dreier mutex_lock(&ibnl_mutex); 67b2cbae2cSRoland Dreier 68b2cbae2cSRoland Dreier list_for_each_entry(cur, &client_list, list) { 69b2cbae2cSRoland Dreier if (cur->index == index) { 70b2cbae2cSRoland Dreier pr_warn("Client for %d already exists\n", index); 71b2cbae2cSRoland Dreier mutex_unlock(&ibnl_mutex); 72b2cbae2cSRoland Dreier kfree(nl_client); 73b2cbae2cSRoland Dreier return -EINVAL; 74b2cbae2cSRoland Dreier } 75b2cbae2cSRoland Dreier } 76b2cbae2cSRoland Dreier 77b2cbae2cSRoland Dreier list_add_tail(&nl_client->list, &client_list); 78b2cbae2cSRoland Dreier 79b2cbae2cSRoland Dreier mutex_unlock(&ibnl_mutex); 80b2cbae2cSRoland Dreier 81b2cbae2cSRoland Dreier return 0; 82b2cbae2cSRoland Dreier } 83b2cbae2cSRoland Dreier EXPORT_SYMBOL(ibnl_add_client); 84b2cbae2cSRoland Dreier 85b2cbae2cSRoland Dreier int ibnl_remove_client(int index) 86b2cbae2cSRoland Dreier { 87b2cbae2cSRoland Dreier struct ibnl_client *cur, *next; 88b2cbae2cSRoland Dreier 89b2cbae2cSRoland Dreier mutex_lock(&ibnl_mutex); 90b2cbae2cSRoland Dreier list_for_each_entry_safe(cur, next, &client_list, list) { 91b2cbae2cSRoland Dreier if (cur->index == index) { 92b2cbae2cSRoland Dreier list_del(&(cur->list)); 93b2cbae2cSRoland Dreier mutex_unlock(&ibnl_mutex); 94b2cbae2cSRoland Dreier kfree(cur); 95b2cbae2cSRoland Dreier return 0; 96b2cbae2cSRoland Dreier } 97b2cbae2cSRoland Dreier } 98b2cbae2cSRoland Dreier pr_warn("Can't remove callback for client idx %d. Not found\n", index); 99b2cbae2cSRoland Dreier mutex_unlock(&ibnl_mutex); 100b2cbae2cSRoland Dreier 101b2cbae2cSRoland Dreier return -EINVAL; 102b2cbae2cSRoland Dreier } 103b2cbae2cSRoland Dreier EXPORT_SYMBOL(ibnl_remove_client); 104b2cbae2cSRoland Dreier 105b2cbae2cSRoland Dreier void *ibnl_put_msg(struct sk_buff *skb, struct nlmsghdr **nlh, int seq, 106b2cbae2cSRoland Dreier int len, int client, int op) 107b2cbae2cSRoland Dreier { 108b2cbae2cSRoland Dreier unsigned char *prev_tail; 109b2cbae2cSRoland Dreier 110b2cbae2cSRoland Dreier prev_tail = skb_tail_pointer(skb); 111b2cbae2cSRoland Dreier *nlh = NLMSG_NEW(skb, 0, seq, RDMA_NL_GET_TYPE(client, op), 112b2cbae2cSRoland Dreier len, NLM_F_MULTI); 113b2cbae2cSRoland Dreier (*nlh)->nlmsg_len = skb_tail_pointer(skb) - prev_tail; 114b2cbae2cSRoland Dreier return NLMSG_DATA(*nlh); 115b2cbae2cSRoland Dreier 116b2cbae2cSRoland Dreier nlmsg_failure: 117b2cbae2cSRoland Dreier nlmsg_trim(skb, prev_tail); 118b2cbae2cSRoland Dreier return NULL; 119b2cbae2cSRoland Dreier } 120b2cbae2cSRoland Dreier EXPORT_SYMBOL(ibnl_put_msg); 121b2cbae2cSRoland Dreier 122b2cbae2cSRoland Dreier int ibnl_put_attr(struct sk_buff *skb, struct nlmsghdr *nlh, 123b2cbae2cSRoland Dreier int len, void *data, int type) 124b2cbae2cSRoland Dreier { 125b2cbae2cSRoland Dreier unsigned char *prev_tail; 126b2cbae2cSRoland Dreier 127b2cbae2cSRoland Dreier prev_tail = skb_tail_pointer(skb); 1284e24ffa4SDavid S. Miller if (nla_put(skb, type, len, data)) 1294e24ffa4SDavid S. Miller goto nla_put_failure; 130b2cbae2cSRoland Dreier nlh->nlmsg_len += skb_tail_pointer(skb) - prev_tail; 131b2cbae2cSRoland Dreier return 0; 132b2cbae2cSRoland Dreier 133b2cbae2cSRoland Dreier nla_put_failure: 134b2cbae2cSRoland Dreier nlmsg_trim(skb, prev_tail - nlh->nlmsg_len); 135b2cbae2cSRoland Dreier return -EMSGSIZE; 136b2cbae2cSRoland Dreier } 137b2cbae2cSRoland Dreier EXPORT_SYMBOL(ibnl_put_attr); 138b2cbae2cSRoland Dreier 139b2cbae2cSRoland Dreier static int ibnl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) 140b2cbae2cSRoland Dreier { 141b2cbae2cSRoland Dreier struct ibnl_client *client; 142b2cbae2cSRoland Dreier int type = nlh->nlmsg_type; 143b2cbae2cSRoland Dreier int index = RDMA_NL_GET_CLIENT(type); 144b2cbae2cSRoland Dreier int op = RDMA_NL_GET_OP(type); 145b2cbae2cSRoland Dreier 146b2cbae2cSRoland Dreier list_for_each_entry(client, &client_list, list) { 147b2cbae2cSRoland Dreier if (client->index == index) { 148b2cbae2cSRoland Dreier if (op < 0 || op >= client->nops || 149b2cbae2cSRoland Dreier !client->cb_table[RDMA_NL_GET_OP(op)].dump) 150b2cbae2cSRoland Dreier return -EINVAL; 15180d326faSPablo Neira Ayuso 15280d326faSPablo Neira Ayuso { 15380d326faSPablo Neira Ayuso struct netlink_dump_control c = { 15480d326faSPablo Neira Ayuso .dump = client->cb_table[op].dump, 15580d326faSPablo Neira Ayuso }; 15680d326faSPablo Neira Ayuso return netlink_dump_start(nls, skb, nlh, &c); 15780d326faSPablo Neira Ayuso } 158b2cbae2cSRoland Dreier } 159b2cbae2cSRoland Dreier } 160b2cbae2cSRoland Dreier 161b2cbae2cSRoland Dreier pr_info("Index %d wasn't found in client list\n", index); 162b2cbae2cSRoland Dreier return -EINVAL; 163b2cbae2cSRoland Dreier } 164b2cbae2cSRoland Dreier 165b2cbae2cSRoland Dreier static void ibnl_rcv(struct sk_buff *skb) 166b2cbae2cSRoland Dreier { 167b2cbae2cSRoland Dreier mutex_lock(&ibnl_mutex); 168b2cbae2cSRoland Dreier netlink_rcv_skb(skb, &ibnl_rcv_msg); 169b2cbae2cSRoland Dreier mutex_unlock(&ibnl_mutex); 170b2cbae2cSRoland Dreier } 171b2cbae2cSRoland Dreier 172b2cbae2cSRoland Dreier int __init ibnl_init(void) 173b2cbae2cSRoland Dreier { 174b2cbae2cSRoland Dreier nls = netlink_kernel_create(&init_net, NETLINK_RDMA, 0, ibnl_rcv, 175b2cbae2cSRoland Dreier NULL, THIS_MODULE); 176b2cbae2cSRoland Dreier if (!nls) { 177b2cbae2cSRoland Dreier pr_warn("Failed to create netlink socket\n"); 178b2cbae2cSRoland Dreier return -ENOMEM; 179b2cbae2cSRoland Dreier } 180b2cbae2cSRoland Dreier 181b2cbae2cSRoland Dreier return 0; 182b2cbae2cSRoland Dreier } 183b2cbae2cSRoland Dreier 184b2cbae2cSRoland Dreier void ibnl_cleanup(void) 185b2cbae2cSRoland Dreier { 186b2cbae2cSRoland Dreier struct ibnl_client *cur, *next; 187b2cbae2cSRoland Dreier 188b2cbae2cSRoland Dreier mutex_lock(&ibnl_mutex); 189b2cbae2cSRoland Dreier list_for_each_entry_safe(cur, next, &client_list, list) { 190b2cbae2cSRoland Dreier list_del(&(cur->list)); 191b2cbae2cSRoland Dreier kfree(cur); 192b2cbae2cSRoland Dreier } 193b2cbae2cSRoland Dreier mutex_unlock(&ibnl_mutex); 194b2cbae2cSRoland Dreier 195b2cbae2cSRoland Dreier netlink_kernel_release(nls); 196b2cbae2cSRoland Dreier } 197