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 35b2cbae2cSRoland Dreier #include <net/netlink.h> 36b2cbae2cSRoland Dreier #include <net/net_namespace.h> 37b2cbae2cSRoland Dreier #include <net/sock.h> 38b2cbae2cSRoland Dreier #include <rdma/rdma_netlink.h> 39b2cbae2cSRoland Dreier 40b2cbae2cSRoland Dreier struct ibnl_client { 41b2cbae2cSRoland Dreier struct list_head list; 42b2cbae2cSRoland Dreier int index; 43b2cbae2cSRoland Dreier int nops; 44b2cbae2cSRoland Dreier const struct ibnl_client_cbs *cb_table; 45b2cbae2cSRoland Dreier }; 46b2cbae2cSRoland Dreier 47b2cbae2cSRoland Dreier static DEFINE_MUTEX(ibnl_mutex); 48b2cbae2cSRoland Dreier static struct sock *nls; 49b2cbae2cSRoland Dreier static LIST_HEAD(client_list); 50b2cbae2cSRoland Dreier 51b2cbae2cSRoland Dreier int ibnl_add_client(int index, int nops, 52b2cbae2cSRoland Dreier const struct ibnl_client_cbs cb_table[]) 53b2cbae2cSRoland Dreier { 54b2cbae2cSRoland Dreier struct ibnl_client *cur; 55b2cbae2cSRoland Dreier struct ibnl_client *nl_client; 56b2cbae2cSRoland Dreier 57b2cbae2cSRoland Dreier nl_client = kmalloc(sizeof *nl_client, GFP_KERNEL); 58b2cbae2cSRoland Dreier if (!nl_client) 59b2cbae2cSRoland Dreier return -ENOMEM; 60b2cbae2cSRoland Dreier 61b2cbae2cSRoland Dreier nl_client->index = index; 62b2cbae2cSRoland Dreier nl_client->nops = nops; 63b2cbae2cSRoland Dreier nl_client->cb_table = cb_table; 64b2cbae2cSRoland Dreier 65b2cbae2cSRoland Dreier mutex_lock(&ibnl_mutex); 66b2cbae2cSRoland Dreier 67b2cbae2cSRoland Dreier list_for_each_entry(cur, &client_list, list) { 68b2cbae2cSRoland Dreier if (cur->index == index) { 69b2cbae2cSRoland Dreier pr_warn("Client for %d already exists\n", index); 70b2cbae2cSRoland Dreier mutex_unlock(&ibnl_mutex); 71b2cbae2cSRoland Dreier kfree(nl_client); 72b2cbae2cSRoland Dreier return -EINVAL; 73b2cbae2cSRoland Dreier } 74b2cbae2cSRoland Dreier } 75b2cbae2cSRoland Dreier 76b2cbae2cSRoland Dreier list_add_tail(&nl_client->list, &client_list); 77b2cbae2cSRoland Dreier 78b2cbae2cSRoland Dreier mutex_unlock(&ibnl_mutex); 79b2cbae2cSRoland Dreier 80b2cbae2cSRoland Dreier return 0; 81b2cbae2cSRoland Dreier } 82b2cbae2cSRoland Dreier EXPORT_SYMBOL(ibnl_add_client); 83b2cbae2cSRoland Dreier 84b2cbae2cSRoland Dreier int ibnl_remove_client(int index) 85b2cbae2cSRoland Dreier { 86b2cbae2cSRoland Dreier struct ibnl_client *cur, *next; 87b2cbae2cSRoland Dreier 88b2cbae2cSRoland Dreier mutex_lock(&ibnl_mutex); 89b2cbae2cSRoland Dreier list_for_each_entry_safe(cur, next, &client_list, list) { 90b2cbae2cSRoland Dreier if (cur->index == index) { 91b2cbae2cSRoland Dreier list_del(&(cur->list)); 92b2cbae2cSRoland Dreier mutex_unlock(&ibnl_mutex); 93b2cbae2cSRoland Dreier kfree(cur); 94b2cbae2cSRoland Dreier return 0; 95b2cbae2cSRoland Dreier } 96b2cbae2cSRoland Dreier } 97b2cbae2cSRoland Dreier pr_warn("Can't remove callback for client idx %d. Not found\n", index); 98b2cbae2cSRoland Dreier mutex_unlock(&ibnl_mutex); 99b2cbae2cSRoland Dreier 100b2cbae2cSRoland Dreier return -EINVAL; 101b2cbae2cSRoland Dreier } 102b2cbae2cSRoland Dreier EXPORT_SYMBOL(ibnl_remove_client); 103b2cbae2cSRoland Dreier 104b2cbae2cSRoland Dreier void *ibnl_put_msg(struct sk_buff *skb, struct nlmsghdr **nlh, int seq, 105b2cbae2cSRoland Dreier int len, int client, int op) 106b2cbae2cSRoland Dreier { 107b2cbae2cSRoland Dreier unsigned char *prev_tail; 108b2cbae2cSRoland Dreier 109b2cbae2cSRoland Dreier prev_tail = skb_tail_pointer(skb); 110b2cbae2cSRoland Dreier *nlh = NLMSG_NEW(skb, 0, seq, RDMA_NL_GET_TYPE(client, op), 111b2cbae2cSRoland Dreier len, NLM_F_MULTI); 112b2cbae2cSRoland Dreier (*nlh)->nlmsg_len = skb_tail_pointer(skb) - prev_tail; 113b2cbae2cSRoland Dreier return NLMSG_DATA(*nlh); 114b2cbae2cSRoland Dreier 115b2cbae2cSRoland Dreier nlmsg_failure: 116b2cbae2cSRoland Dreier nlmsg_trim(skb, prev_tail); 117b2cbae2cSRoland Dreier return NULL; 118b2cbae2cSRoland Dreier } 119b2cbae2cSRoland Dreier EXPORT_SYMBOL(ibnl_put_msg); 120b2cbae2cSRoland Dreier 121b2cbae2cSRoland Dreier int ibnl_put_attr(struct sk_buff *skb, struct nlmsghdr *nlh, 122b2cbae2cSRoland Dreier int len, void *data, int type) 123b2cbae2cSRoland Dreier { 124b2cbae2cSRoland Dreier unsigned char *prev_tail; 125b2cbae2cSRoland Dreier 126b2cbae2cSRoland Dreier prev_tail = skb_tail_pointer(skb); 127b2cbae2cSRoland Dreier NLA_PUT(skb, type, len, data); 128b2cbae2cSRoland Dreier nlh->nlmsg_len += skb_tail_pointer(skb) - prev_tail; 129b2cbae2cSRoland Dreier return 0; 130b2cbae2cSRoland Dreier 131b2cbae2cSRoland Dreier nla_put_failure: 132b2cbae2cSRoland Dreier nlmsg_trim(skb, prev_tail - nlh->nlmsg_len); 133b2cbae2cSRoland Dreier return -EMSGSIZE; 134b2cbae2cSRoland Dreier } 135b2cbae2cSRoland Dreier EXPORT_SYMBOL(ibnl_put_attr); 136b2cbae2cSRoland Dreier 137b2cbae2cSRoland Dreier static int ibnl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) 138b2cbae2cSRoland Dreier { 139b2cbae2cSRoland Dreier struct ibnl_client *client; 140b2cbae2cSRoland Dreier int type = nlh->nlmsg_type; 141b2cbae2cSRoland Dreier int index = RDMA_NL_GET_CLIENT(type); 142b2cbae2cSRoland Dreier int op = RDMA_NL_GET_OP(type); 143b2cbae2cSRoland Dreier 144b2cbae2cSRoland Dreier list_for_each_entry(client, &client_list, list) { 145b2cbae2cSRoland Dreier if (client->index == index) { 146b2cbae2cSRoland Dreier if (op < 0 || op >= client->nops || 147b2cbae2cSRoland Dreier !client->cb_table[RDMA_NL_GET_OP(op)].dump) 148b2cbae2cSRoland Dreier return -EINVAL; 149b2cbae2cSRoland Dreier return netlink_dump_start(nls, skb, nlh, 150b2cbae2cSRoland Dreier client->cb_table[op].dump, 151c7ac8679SGreg Rose NULL, 0); 152b2cbae2cSRoland Dreier } 153b2cbae2cSRoland Dreier } 154b2cbae2cSRoland Dreier 155b2cbae2cSRoland Dreier pr_info("Index %d wasn't found in client list\n", index); 156b2cbae2cSRoland Dreier return -EINVAL; 157b2cbae2cSRoland Dreier } 158b2cbae2cSRoland Dreier 159b2cbae2cSRoland Dreier static void ibnl_rcv(struct sk_buff *skb) 160b2cbae2cSRoland Dreier { 161b2cbae2cSRoland Dreier mutex_lock(&ibnl_mutex); 162b2cbae2cSRoland Dreier netlink_rcv_skb(skb, &ibnl_rcv_msg); 163b2cbae2cSRoland Dreier mutex_unlock(&ibnl_mutex); 164b2cbae2cSRoland Dreier } 165b2cbae2cSRoland Dreier 166b2cbae2cSRoland Dreier int __init ibnl_init(void) 167b2cbae2cSRoland Dreier { 168b2cbae2cSRoland Dreier nls = netlink_kernel_create(&init_net, NETLINK_RDMA, 0, ibnl_rcv, 169b2cbae2cSRoland Dreier NULL, THIS_MODULE); 170b2cbae2cSRoland Dreier if (!nls) { 171b2cbae2cSRoland Dreier pr_warn("Failed to create netlink socket\n"); 172b2cbae2cSRoland Dreier return -ENOMEM; 173b2cbae2cSRoland Dreier } 174b2cbae2cSRoland Dreier 175b2cbae2cSRoland Dreier return 0; 176b2cbae2cSRoland Dreier } 177b2cbae2cSRoland Dreier 178b2cbae2cSRoland Dreier void ibnl_cleanup(void) 179b2cbae2cSRoland Dreier { 180b2cbae2cSRoland Dreier struct ibnl_client *cur, *next; 181b2cbae2cSRoland Dreier 182b2cbae2cSRoland Dreier mutex_lock(&ibnl_mutex); 183b2cbae2cSRoland Dreier list_for_each_entry_safe(cur, next, &client_list, list) { 184b2cbae2cSRoland Dreier list_del(&(cur->list)); 185b2cbae2cSRoland Dreier kfree(cur); 186b2cbae2cSRoland Dreier } 187b2cbae2cSRoland Dreier mutex_unlock(&ibnl_mutex); 188b2cbae2cSRoland Dreier 189b2cbae2cSRoland Dreier netlink_kernel_release(nls); 190b2cbae2cSRoland Dreier } 191