 b108d9764c
			
		
	
	
	b108d9764c
	
	
	
		
			
			These were getting it implicitly via device.h --> module.h but we are going to stop that when we clean up the headers. Fix these in advance so the tree remains biscect-clean. Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com>
		
			
				
	
	
		
			191 lines
		
	
	
	
		
			4.8 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			191 lines
		
	
	
	
		
			4.8 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * Copyright (c) 2010 Voltaire Inc.  All rights reserved.
 | |
|  *
 | |
|  * This software is available to you under a choice of one of two
 | |
|  * licenses.  You may choose to be licensed under the terms of the GNU
 | |
|  * General Public License (GPL) Version 2, available from the file
 | |
|  * COPYING in the main directory of this source tree, or the
 | |
|  * OpenIB.org BSD license below:
 | |
|  *
 | |
|  *     Redistribution and use in source and binary forms, with or
 | |
|  *     without modification, are permitted provided that the following
 | |
|  *     conditions are met:
 | |
|  *
 | |
|  *      - Redistributions of source code must retain the above
 | |
|  *        copyright notice, this list of conditions and the following
 | |
|  *        disclaimer.
 | |
|  *
 | |
|  *      - Redistributions in binary form must reproduce the above
 | |
|  *        copyright notice, this list of conditions and the following
 | |
|  *        disclaimer in the documentation and/or other materials
 | |
|  *        provided with the distribution.
 | |
|  *
 | |
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 | |
|  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 | |
|  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 | |
|  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
 | |
|  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 | |
|  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 | |
|  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 | |
|  * SOFTWARE.
 | |
|  */
 | |
| 
 | |
| #define pr_fmt(fmt) "%s:%s: " fmt, KBUILD_MODNAME, __func__
 | |
| 
 | |
| #include <linux/export.h>
 | |
| #include <net/netlink.h>
 | |
| #include <net/net_namespace.h>
 | |
| #include <net/sock.h>
 | |
| #include <rdma/rdma_netlink.h>
 | |
| 
 | |
| struct ibnl_client {
 | |
| 	struct list_head		list;
 | |
| 	int				index;
 | |
| 	int				nops;
 | |
| 	const struct ibnl_client_cbs   *cb_table;
 | |
| };
 | |
| 
 | |
| static DEFINE_MUTEX(ibnl_mutex);
 | |
| static struct sock *nls;
 | |
| static LIST_HEAD(client_list);
 | |
| 
 | |
| int ibnl_add_client(int index, int nops,
 | |
| 		    const struct ibnl_client_cbs cb_table[])
 | |
| {
 | |
| 	struct ibnl_client *cur;
 | |
| 	struct ibnl_client *nl_client;
 | |
| 
 | |
| 	nl_client = kmalloc(sizeof *nl_client, GFP_KERNEL);
 | |
| 	if (!nl_client)
 | |
| 		return -ENOMEM;
 | |
| 
 | |
| 	nl_client->index	= index;
 | |
| 	nl_client->nops		= nops;
 | |
| 	nl_client->cb_table	= cb_table;
 | |
| 
 | |
| 	mutex_lock(&ibnl_mutex);
 | |
| 
 | |
| 	list_for_each_entry(cur, &client_list, list) {
 | |
| 		if (cur->index == index) {
 | |
| 			pr_warn("Client for %d already exists\n", index);
 | |
| 			mutex_unlock(&ibnl_mutex);
 | |
| 			kfree(nl_client);
 | |
| 			return -EINVAL;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	list_add_tail(&nl_client->list, &client_list);
 | |
| 
 | |
| 	mutex_unlock(&ibnl_mutex);
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| EXPORT_SYMBOL(ibnl_add_client);
 | |
| 
 | |
| int ibnl_remove_client(int index)
 | |
| {
 | |
| 	struct ibnl_client *cur, *next;
 | |
| 
 | |
| 	mutex_lock(&ibnl_mutex);
 | |
| 	list_for_each_entry_safe(cur, next, &client_list, list) {
 | |
| 		if (cur->index == index) {
 | |
| 			list_del(&(cur->list));
 | |
| 			mutex_unlock(&ibnl_mutex);
 | |
| 			kfree(cur);
 | |
| 			return 0;
 | |
| 		}
 | |
| 	}
 | |
| 	pr_warn("Can't remove callback for client idx %d. Not found\n", index);
 | |
| 	mutex_unlock(&ibnl_mutex);
 | |
| 
 | |
| 	return -EINVAL;
 | |
| }
 | |
| EXPORT_SYMBOL(ibnl_remove_client);
 | |
| 
 | |
| void *ibnl_put_msg(struct sk_buff *skb, struct nlmsghdr **nlh, int seq,
 | |
| 		   int len, int client, int op)
 | |
| {
 | |
| 	unsigned char *prev_tail;
 | |
| 
 | |
| 	prev_tail = skb_tail_pointer(skb);
 | |
| 	*nlh = NLMSG_NEW(skb, 0, seq, RDMA_NL_GET_TYPE(client, op),
 | |
| 			len, NLM_F_MULTI);
 | |
| 	(*nlh)->nlmsg_len = skb_tail_pointer(skb) - prev_tail;
 | |
| 	return NLMSG_DATA(*nlh);
 | |
| 
 | |
| nlmsg_failure:
 | |
| 	nlmsg_trim(skb, prev_tail);
 | |
| 	return NULL;
 | |
| }
 | |
| EXPORT_SYMBOL(ibnl_put_msg);
 | |
| 
 | |
| int ibnl_put_attr(struct sk_buff *skb, struct nlmsghdr *nlh,
 | |
| 		  int len, void *data, int type)
 | |
| {
 | |
| 	unsigned char *prev_tail;
 | |
| 
 | |
| 	prev_tail = skb_tail_pointer(skb);
 | |
| 	NLA_PUT(skb, type, len, data);
 | |
| 	nlh->nlmsg_len += skb_tail_pointer(skb) - prev_tail;
 | |
| 	return 0;
 | |
| 
 | |
| nla_put_failure:
 | |
| 	nlmsg_trim(skb, prev_tail - nlh->nlmsg_len);
 | |
| 	return -EMSGSIZE;
 | |
| }
 | |
| EXPORT_SYMBOL(ibnl_put_attr);
 | |
| 
 | |
| static int ibnl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
 | |
| {
 | |
| 	struct ibnl_client *client;
 | |
| 	int type = nlh->nlmsg_type;
 | |
| 	int index = RDMA_NL_GET_CLIENT(type);
 | |
| 	int op = RDMA_NL_GET_OP(type);
 | |
| 
 | |
| 	list_for_each_entry(client, &client_list, list) {
 | |
| 		if (client->index == index) {
 | |
| 			if (op < 0 || op >= client->nops ||
 | |
| 			    !client->cb_table[RDMA_NL_GET_OP(op)].dump)
 | |
| 				return -EINVAL;
 | |
| 			return netlink_dump_start(nls, skb, nlh,
 | |
| 						  client->cb_table[op].dump,
 | |
| 						  NULL, 0);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	pr_info("Index %d wasn't found in client list\n", index);
 | |
| 	return -EINVAL;
 | |
| }
 | |
| 
 | |
| static void ibnl_rcv(struct sk_buff *skb)
 | |
| {
 | |
| 	mutex_lock(&ibnl_mutex);
 | |
| 	netlink_rcv_skb(skb, &ibnl_rcv_msg);
 | |
| 	mutex_unlock(&ibnl_mutex);
 | |
| }
 | |
| 
 | |
| int __init ibnl_init(void)
 | |
| {
 | |
| 	nls = netlink_kernel_create(&init_net, NETLINK_RDMA, 0, ibnl_rcv,
 | |
| 				    NULL, THIS_MODULE);
 | |
| 	if (!nls) {
 | |
| 		pr_warn("Failed to create netlink socket\n");
 | |
| 		return -ENOMEM;
 | |
| 	}
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| void ibnl_cleanup(void)
 | |
| {
 | |
| 	struct ibnl_client *cur, *next;
 | |
| 
 | |
| 	mutex_lock(&ibnl_mutex);
 | |
| 	list_for_each_entry_safe(cur, next, &client_list, list) {
 | |
| 		list_del(&(cur->list));
 | |
| 		kfree(cur);
 | |
| 	}
 | |
| 	mutex_unlock(&ibnl_mutex);
 | |
| 
 | |
| 	netlink_kernel_release(nls);
 | |
| }
 |