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> 40233c1955SLeon Romanovsky #include "core_priv.h" 41b2cbae2cSRoland Dreier 42c9901724SLeon Romanovsky #include "core_priv.h" 43b2cbae2cSRoland Dreier 44c9901724SLeon Romanovsky static DEFINE_MUTEX(rdma_nl_mutex); 45b2cbae2cSRoland Dreier static struct sock *nls; 46c9901724SLeon Romanovsky static struct { 47c9901724SLeon Romanovsky const struct ibnl_client_cbs *cb_table; 48c9901724SLeon Romanovsky } rdma_nl_types[RDMA_NL_NUM_CLIENTS]; 49b2cbae2cSRoland Dreier 50bc10ed7dSKaike Wan int ibnl_chk_listeners(unsigned int group) 51bc10ed7dSKaike Wan { 52bc10ed7dSKaike Wan if (netlink_has_listeners(nls, group) == 0) 53bc10ed7dSKaike Wan return -1; 54bc10ed7dSKaike Wan return 0; 55bc10ed7dSKaike Wan } 56bc10ed7dSKaike Wan 57c9901724SLeon Romanovsky static bool is_nl_msg_valid(unsigned int type, unsigned int op) 58c9901724SLeon Romanovsky { 59c9901724SLeon Romanovsky static const unsigned int max_num_ops[RDMA_NL_NUM_CLIENTS - 1] = { 60c9901724SLeon Romanovsky RDMA_NL_RDMA_CM_NUM_OPS, 61c9901724SLeon Romanovsky RDMA_NL_IWPM_NUM_OPS, 62c9901724SLeon Romanovsky 0, 63c9901724SLeon Romanovsky RDMA_NL_LS_NUM_OPS, 64c9901724SLeon Romanovsky 0 }; 65c9901724SLeon Romanovsky 66c9901724SLeon Romanovsky /* 67c9901724SLeon Romanovsky * This BUILD_BUG_ON is intended to catch addition of new 68c9901724SLeon Romanovsky * RDMA netlink protocol without updating the array above. 69c9901724SLeon Romanovsky */ 70c9901724SLeon Romanovsky BUILD_BUG_ON(RDMA_NL_NUM_CLIENTS != 6); 71c9901724SLeon Romanovsky 72c9901724SLeon Romanovsky if (type > RDMA_NL_NUM_CLIENTS - 1) 73c9901724SLeon Romanovsky return false; 74c9901724SLeon Romanovsky 75c9901724SLeon Romanovsky return (op < max_num_ops[type - 1]) ? true : false; 76c9901724SLeon Romanovsky } 77c9901724SLeon Romanovsky 78c9901724SLeon Romanovsky static bool is_nl_valid(unsigned int type, unsigned int op) 79c9901724SLeon Romanovsky { 80c9901724SLeon Romanovsky if (!is_nl_msg_valid(type, op) || 81c9901724SLeon Romanovsky !rdma_nl_types[type].cb_table || 82c9901724SLeon Romanovsky !rdma_nl_types[type].cb_table[op].dump) 83c9901724SLeon Romanovsky return false; 84c9901724SLeon Romanovsky return true; 85c9901724SLeon Romanovsky } 86c9901724SLeon Romanovsky 87c9901724SLeon Romanovsky void rdma_nl_register(unsigned int index, 88b2cbae2cSRoland Dreier const struct ibnl_client_cbs cb_table[]) 89b2cbae2cSRoland Dreier { 90c9901724SLeon Romanovsky mutex_lock(&rdma_nl_mutex); 91c9901724SLeon Romanovsky if (!is_nl_msg_valid(index, 0)) { 92c9901724SLeon Romanovsky /* 93c9901724SLeon Romanovsky * All clients are not interesting in success/failure of 94c9901724SLeon Romanovsky * this call. They want to see the print to error log and 95c9901724SLeon Romanovsky * continue their initialization. Print warning for them, 96c9901724SLeon Romanovsky * because it is programmer's error to be here. 97c9901724SLeon Romanovsky */ 98c9901724SLeon Romanovsky mutex_unlock(&rdma_nl_mutex); 99c9901724SLeon Romanovsky WARN(true, 100c9901724SLeon Romanovsky "The not-valid %u index was supplied to RDMA netlink\n", 101c9901724SLeon Romanovsky index); 102c9901724SLeon Romanovsky return; 103b2cbae2cSRoland Dreier } 104b2cbae2cSRoland Dreier 105c9901724SLeon Romanovsky if (rdma_nl_types[index].cb_table) { 106c9901724SLeon Romanovsky mutex_unlock(&rdma_nl_mutex); 107c9901724SLeon Romanovsky WARN(true, 108c9901724SLeon Romanovsky "The %u index is already registered in RDMA netlink\n", 109c9901724SLeon Romanovsky index); 110c9901724SLeon Romanovsky return; 111b2cbae2cSRoland Dreier } 112b2cbae2cSRoland Dreier 113c9901724SLeon Romanovsky rdma_nl_types[index].cb_table = cb_table; 114c9901724SLeon Romanovsky mutex_unlock(&rdma_nl_mutex); 115c9901724SLeon Romanovsky } 116c9901724SLeon Romanovsky EXPORT_SYMBOL(rdma_nl_register); 117c9901724SLeon Romanovsky 118c9901724SLeon Romanovsky void rdma_nl_unregister(unsigned int index) 119b2cbae2cSRoland Dreier { 120c9901724SLeon Romanovsky mutex_lock(&rdma_nl_mutex); 121c9901724SLeon Romanovsky rdma_nl_types[index].cb_table = NULL; 122c9901724SLeon Romanovsky mutex_unlock(&rdma_nl_mutex); 123b2cbae2cSRoland Dreier } 124c9901724SLeon Romanovsky EXPORT_SYMBOL(rdma_nl_unregister); 125b2cbae2cSRoland Dreier 126b2cbae2cSRoland Dreier void *ibnl_put_msg(struct sk_buff *skb, struct nlmsghdr **nlh, int seq, 12730dc5e63STatyana Nikolova int len, int client, int op, int flags) 128b2cbae2cSRoland Dreier { 1291a1c116fSLeon Romanovsky *nlh = nlmsg_put(skb, 0, seq, RDMA_NL_GET_TYPE(client, op), len, flags); 130e0527334SDavid S. Miller if (!*nlh) 131b2cbae2cSRoland Dreier return NULL; 1321a1c116fSLeon Romanovsky return nlmsg_data(*nlh); 133b2cbae2cSRoland Dreier } 134b2cbae2cSRoland Dreier EXPORT_SYMBOL(ibnl_put_msg); 135b2cbae2cSRoland Dreier 136b2cbae2cSRoland Dreier int ibnl_put_attr(struct sk_buff *skb, struct nlmsghdr *nlh, 137b2cbae2cSRoland Dreier int len, void *data, int type) 138b2cbae2cSRoland Dreier { 1391a1c116fSLeon Romanovsky if (nla_put(skb, type, len, data)) { 1401a1c116fSLeon Romanovsky nlmsg_cancel(skb, nlh); 141b2cbae2cSRoland Dreier return -EMSGSIZE; 142b2cbae2cSRoland Dreier } 1431a1c116fSLeon Romanovsky return 0; 1441a1c116fSLeon Romanovsky } 145b2cbae2cSRoland Dreier EXPORT_SYMBOL(ibnl_put_attr); 146b2cbae2cSRoland Dreier 1473c3e75d5SLeon Romanovsky static int rdma_nl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, 1482d4bc933SJohannes Berg struct netlink_ext_ack *extack) 149b2cbae2cSRoland Dreier { 150b2cbae2cSRoland Dreier int type = nlh->nlmsg_type; 151c9901724SLeon Romanovsky unsigned int index = RDMA_NL_GET_CLIENT(type); 1521ae5ccc7SMark Bloch unsigned int op = RDMA_NL_GET_OP(type); 153c9901724SLeon Romanovsky struct netlink_callback cb = {}; 154c9901724SLeon Romanovsky struct netlink_dump_control c = {}; 155b2cbae2cSRoland Dreier 156c9901724SLeon Romanovsky if (!is_nl_valid(index, op)) 157b2cbae2cSRoland Dreier return -EINVAL; 15880d326faSPablo Neira Ayuso 159e3a2b93dSLeon Romanovsky if ((rdma_nl_types[index].cb_table[op].flags & RDMA_NL_ADMIN_PERM) && 160e3a2b93dSLeon Romanovsky !netlink_capable(skb, CAP_NET_ADMIN)) 161e3a2b93dSLeon Romanovsky return -EPERM; 162e3a2b93dSLeon Romanovsky 163bc10ed7dSKaike Wan /* 164bc10ed7dSKaike Wan * For response or local service set_timeout request, 165bc10ed7dSKaike Wan * there is no need to use netlink_dump_start. 166bc10ed7dSKaike Wan */ 167bc10ed7dSKaike Wan if (!(nlh->nlmsg_flags & NLM_F_REQUEST) || 168c9901724SLeon Romanovsky (index == RDMA_NL_LS && op == RDMA_NL_LS_OP_SET_TIMEOUT)) { 169c9901724SLeon Romanovsky cb.skb = skb; 170c9901724SLeon Romanovsky cb.nlh = nlh; 171c9901724SLeon Romanovsky cb.dump = rdma_nl_types[index].cb_table[op].dump; 172bc10ed7dSKaike Wan return cb.dump(skb, &cb); 173bc10ed7dSKaike Wan } 174bc10ed7dSKaike Wan 175c9901724SLeon Romanovsky c.dump = rdma_nl_types[index].cb_table[op].dump; 17680d326faSPablo Neira Ayuso return netlink_dump_start(nls, skb, nlh, &c); 17780d326faSPablo Neira Ayuso } 178b2cbae2cSRoland Dreier 1793c3e75d5SLeon Romanovsky /* 1803c3e75d5SLeon Romanovsky * This function is similar to netlink_rcv_skb with one exception: 1813c3e75d5SLeon Romanovsky * It calls to the callback for the netlink messages without NLM_F_REQUEST 1823c3e75d5SLeon Romanovsky * flag. These messages are intended for RDMA_NL_LS consumer, so it is allowed 1833c3e75d5SLeon Romanovsky * for that consumer only. 1843c3e75d5SLeon Romanovsky */ 1853c3e75d5SLeon Romanovsky static int rdma_nl_rcv_skb(struct sk_buff *skb, int (*cb)(struct sk_buff *, 1863c3e75d5SLeon Romanovsky struct nlmsghdr *, 1873c3e75d5SLeon Romanovsky struct netlink_ext_ack *)) 188bc10ed7dSKaike Wan { 1893c3e75d5SLeon Romanovsky struct netlink_ext_ack extack = {}; 190bc10ed7dSKaike Wan struct nlmsghdr *nlh; 1913c3e75d5SLeon Romanovsky int err; 1923c3e75d5SLeon Romanovsky 1933c3e75d5SLeon Romanovsky while (skb->len >= nlmsg_total_size(0)) { 194bc10ed7dSKaike Wan int msglen; 195bc10ed7dSKaike Wan 196bc10ed7dSKaike Wan nlh = nlmsg_hdr(skb); 1973c3e75d5SLeon Romanovsky err = 0; 198bc10ed7dSKaike Wan 199bc10ed7dSKaike Wan if (nlh->nlmsg_len < NLMSG_HDRLEN || skb->len < nlh->nlmsg_len) 2003c3e75d5SLeon Romanovsky return 0; 201bc10ed7dSKaike Wan 2023c3e75d5SLeon Romanovsky /* 2033c3e75d5SLeon Romanovsky * Generally speaking, the only requests are handled 2043c3e75d5SLeon Romanovsky * by the kernel, but RDMA_NL_LS is different, because it 2053c3e75d5SLeon Romanovsky * runs backward netlink scheme. Kernel initiates messages 2063c3e75d5SLeon Romanovsky * and waits for reply with data to keep pathrecord cache 2073c3e75d5SLeon Romanovsky * in sync. 2083c3e75d5SLeon Romanovsky */ 2093c3e75d5SLeon Romanovsky if (!(nlh->nlmsg_flags & NLM_F_REQUEST) && 2103c3e75d5SLeon Romanovsky (RDMA_NL_GET_CLIENT(nlh->nlmsg_type) != RDMA_NL_LS)) 2113c3e75d5SLeon Romanovsky goto ack; 212bc10ed7dSKaike Wan 2133c3e75d5SLeon Romanovsky /* Skip control messages */ 2143c3e75d5SLeon Romanovsky if (nlh->nlmsg_type < NLMSG_MIN_TYPE) 2153c3e75d5SLeon Romanovsky goto ack; 216bc10ed7dSKaike Wan 2173c3e75d5SLeon Romanovsky err = cb(skb, nlh, &extack); 2183c3e75d5SLeon Romanovsky if (err == -EINTR) 2193c3e75d5SLeon Romanovsky goto skip; 2203c3e75d5SLeon Romanovsky 2213c3e75d5SLeon Romanovsky ack: 2223c3e75d5SLeon Romanovsky if (nlh->nlmsg_flags & NLM_F_ACK || err) 2233c3e75d5SLeon Romanovsky netlink_ack(skb, nlh, err, &extack); 2243c3e75d5SLeon Romanovsky 2253c3e75d5SLeon Romanovsky skip: 226bc10ed7dSKaike Wan msglen = NLMSG_ALIGN(nlh->nlmsg_len); 227bc10ed7dSKaike Wan if (msglen > skb->len) 228bc10ed7dSKaike Wan msglen = skb->len; 229bc10ed7dSKaike Wan skb_pull(skb, msglen); 230bc10ed7dSKaike Wan } 2313c3e75d5SLeon Romanovsky 2323c3e75d5SLeon Romanovsky return 0; 233bc10ed7dSKaike Wan } 234bc10ed7dSKaike Wan 2353c3e75d5SLeon Romanovsky static void rdma_nl_rcv(struct sk_buff *skb) 236b2cbae2cSRoland Dreier { 237c9901724SLeon Romanovsky mutex_lock(&rdma_nl_mutex); 2383c3e75d5SLeon Romanovsky rdma_nl_rcv_skb(skb, &rdma_nl_rcv_msg); 239c9901724SLeon Romanovsky mutex_unlock(&rdma_nl_mutex); 240b2cbae2cSRoland Dreier } 241b2cbae2cSRoland Dreier 242f00e6463SLeon Romanovsky int rdma_nl_unicast(struct sk_buff *skb, u32 pid) 24330dc5e63STatyana Nikolova { 244cea05eadSMustafa Ismail int err; 245cea05eadSMustafa Ismail 2469047811bSIsmail, Mustafa err = netlink_unicast(nls, skb, pid, MSG_DONTWAIT); 247cea05eadSMustafa Ismail return (err < 0) ? err : 0; 24830dc5e63STatyana Nikolova } 249f00e6463SLeon Romanovsky EXPORT_SYMBOL(rdma_nl_unicast); 25030dc5e63STatyana Nikolova 251f00e6463SLeon Romanovsky int rdma_nl_unicast_wait(struct sk_buff *skb, __u32 pid) 2529047811bSIsmail, Mustafa { 2539047811bSIsmail, Mustafa int err; 2549047811bSIsmail, Mustafa 2559047811bSIsmail, Mustafa err = netlink_unicast(nls, skb, pid, 0); 2569047811bSIsmail, Mustafa return (err < 0) ? err : 0; 2579047811bSIsmail, Mustafa } 258f00e6463SLeon Romanovsky EXPORT_SYMBOL(rdma_nl_unicast_wait); 2599047811bSIsmail, Mustafa 2604d7f693aSLeon Romanovsky int rdma_nl_multicast(struct sk_buff *skb, unsigned int group, gfp_t flags) 26130dc5e63STatyana Nikolova { 26230dc5e63STatyana Nikolova return nlmsg_multicast(nls, skb, 0, group, flags); 26330dc5e63STatyana Nikolova } 2644d7f693aSLeon Romanovsky EXPORT_SYMBOL(rdma_nl_multicast); 26530dc5e63STatyana Nikolova 266c9901724SLeon Romanovsky int __init rdma_nl_init(void) 267b2cbae2cSRoland Dreier { 268a31f2d17SPablo Neira Ayuso struct netlink_kernel_cfg cfg = { 2693c3e75d5SLeon Romanovsky .input = rdma_nl_rcv, 270a31f2d17SPablo Neira Ayuso }; 271a31f2d17SPablo Neira Ayuso 2729f00d977SPablo Neira Ayuso nls = netlink_kernel_create(&init_net, NETLINK_RDMA, &cfg); 273c9901724SLeon Romanovsky if (!nls) 274b2cbae2cSRoland Dreier return -ENOMEM; 275b2cbae2cSRoland Dreier 276cea05eadSMustafa Ismail nls->sk_sndtimeo = 10 * HZ; 277b2cbae2cSRoland Dreier return 0; 278b2cbae2cSRoland Dreier } 279b2cbae2cSRoland Dreier 280c9901724SLeon Romanovsky void rdma_nl_exit(void) 281b2cbae2cSRoland Dreier { 282c9901724SLeon Romanovsky int idx; 283b2cbae2cSRoland Dreier 284c9901724SLeon Romanovsky for (idx = 0; idx < RDMA_NL_NUM_CLIENTS; idx++) 285c9901724SLeon Romanovsky rdma_nl_unregister(idx); 286b2cbae2cSRoland Dreier 287b2cbae2cSRoland Dreier netlink_kernel_release(nls); 288b2cbae2cSRoland Dreier } 289