1b97bf3fdSPer Liden /* 2b97bf3fdSPer Liden * net/tipc/netlink.c: TIPC configuration handling 3b97bf3fdSPer Liden * 40655f6a8SRichard Alpe * Copyright (c) 2005-2006, 2014, Ericsson AB 559f0c452SAllan Stephens * Copyright (c) 2005-2007, Wind River Systems 6b97bf3fdSPer Liden * All rights reserved. 7b97bf3fdSPer Liden * 8b97bf3fdSPer Liden * Redistribution and use in source and binary forms, with or without 9b97bf3fdSPer Liden * modification, are permitted provided that the following conditions are met: 10b97bf3fdSPer Liden * 119ea1fd3cSPer Liden * 1. Redistributions of source code must retain the above copyright 129ea1fd3cSPer Liden * notice, this list of conditions and the following disclaimer. 139ea1fd3cSPer Liden * 2. Redistributions in binary form must reproduce the above copyright 149ea1fd3cSPer Liden * notice, this list of conditions and the following disclaimer in the 159ea1fd3cSPer Liden * documentation and/or other materials provided with the distribution. 169ea1fd3cSPer Liden * 3. Neither the names of the copyright holders nor the names of its 179ea1fd3cSPer Liden * contributors may be used to endorse or promote products derived from 189ea1fd3cSPer Liden * this software without specific prior written permission. 199ea1fd3cSPer Liden * 209ea1fd3cSPer Liden * Alternatively, this software may be distributed under the terms of the 219ea1fd3cSPer Liden * GNU General Public License ("GPL") version 2 as published by the Free 229ea1fd3cSPer Liden * Software Foundation. 23b97bf3fdSPer Liden * 24b97bf3fdSPer Liden * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 25b97bf3fdSPer Liden * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26b97bf3fdSPer Liden * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27b97bf3fdSPer Liden * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 28b97bf3fdSPer Liden * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 29b97bf3fdSPer Liden * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 30b97bf3fdSPer Liden * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 31b97bf3fdSPer Liden * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 32b97bf3fdSPer Liden * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 33b97bf3fdSPer Liden * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 34b97bf3fdSPer Liden * POSSIBILITY OF SUCH DAMAGE. 35b97bf3fdSPer Liden */ 36b97bf3fdSPer Liden 37b97bf3fdSPer Liden #include "core.h" 38b97bf3fdSPer Liden #include "config.h" 3934b78a12SRichard Alpe #include "socket.h" 401593123aSRichard Alpe #include "name_table.h" 410655f6a8SRichard Alpe #include "bearer.h" 427be57fc6SRichard Alpe #include "link.h" 433e4b6ab5SRichard Alpe #include "node.h" 44fd3cf2adSRichard Alpe #include "net.h" 45b97bf3fdSPer Liden #include <net/genetlink.h> 46b97bf3fdSPer Liden 47b97bf3fdSPer Liden static int handle_cmd(struct sk_buff *skb, struct genl_info *info) 48b97bf3fdSPer Liden { 49c93d3baaSYing Xue struct net *net = genl_info_net(info); 50b97bf3fdSPer Liden struct sk_buff *rep_buf; 51b97bf3fdSPer Liden struct nlmsghdr *rep_nlh; 52b97bf3fdSPer Liden struct nlmsghdr *req_nlh = info->nlhdr; 53b97bf3fdSPer Liden struct tipc_genlmsghdr *req_userhdr = info->userhdr; 54573ce260SHong zhi guo int hdr_space = nlmsg_total_size(GENL_HDRLEN + TIPC_GENL_HDRLEN); 5559f0c452SAllan Stephens u16 cmd; 56b97bf3fdSPer Liden 57*d49e2041SYing Xue if ((req_userhdr->cmd & 0xC000) && 58*d49e2041SYing Xue (!netlink_net_capable(skb, CAP_NET_ADMIN))) 5959f0c452SAllan Stephens cmd = TIPC_CMD_NOT_NET_ADMIN; 60b97bf3fdSPer Liden else 6159f0c452SAllan Stephens cmd = req_userhdr->cmd; 6259f0c452SAllan Stephens 63c93d3baaSYing Xue rep_buf = tipc_cfg_do_cmd(net, req_userhdr->dest, cmd, 64c93d3baaSYing Xue nlmsg_data(req_nlh) + GENL_HDRLEN + 65c93d3baaSYing Xue TIPC_GENL_HDRLEN, 66c93d3baaSYing Xue nlmsg_attrlen(req_nlh, GENL_HDRLEN + 67c93d3baaSYing Xue TIPC_GENL_HDRLEN), hdr_space); 68b97bf3fdSPer Liden 69b97bf3fdSPer Liden if (rep_buf) { 70b97bf3fdSPer Liden skb_push(rep_buf, hdr_space); 71b529ccf2SArnaldo Carvalho de Melo rep_nlh = nlmsg_hdr(rep_buf); 72b97bf3fdSPer Liden memcpy(rep_nlh, req_nlh, hdr_space); 73b97bf3fdSPer Liden rep_nlh->nlmsg_len = rep_buf->len; 74*d49e2041SYing Xue genlmsg_unicast(net, rep_buf, NETLINK_CB(skb).portid); 75b97bf3fdSPer Liden } 76b97bf3fdSPer Liden 77b97bf3fdSPer Liden return 0; 78b97bf3fdSPer Liden } 79b97bf3fdSPer Liden 800655f6a8SRichard Alpe static const struct nla_policy tipc_nl_policy[TIPC_NLA_MAX + 1] = { 810655f6a8SRichard Alpe [TIPC_NLA_UNSPEC] = { .type = NLA_UNSPEC, }, 820655f6a8SRichard Alpe [TIPC_NLA_BEARER] = { .type = NLA_NESTED, }, 8334b78a12SRichard Alpe [TIPC_NLA_SOCK] = { .type = NLA_NESTED, }, 847be57fc6SRichard Alpe [TIPC_NLA_PUBL] = { .type = NLA_NESTED, }, 857be57fc6SRichard Alpe [TIPC_NLA_LINK] = { .type = NLA_NESTED, }, 8646f15c67SRichard Alpe [TIPC_NLA_MEDIA] = { .type = NLA_NESTED, }, 87fd3cf2adSRichard Alpe [TIPC_NLA_NODE] = { .type = NLA_NESTED, }, 881593123aSRichard Alpe [TIPC_NLA_NET] = { .type = NLA_NESTED, }, 891593123aSRichard Alpe [TIPC_NLA_NAME_TABLE] = { .type = NLA_NESTED, } 900655f6a8SRichard Alpe }; 910655f6a8SRichard Alpe 920655f6a8SRichard Alpe /* Legacy ASCII API */ 93acb0a200SMichał Mirosław static struct genl_family tipc_genl_family = { 941dba9743SPer Liden .id = GENL_ID_GENERATE, 95b97bf3fdSPer Liden .name = TIPC_GENL_NAME, 96b97bf3fdSPer Liden .version = TIPC_GENL_VERSION, 97b97bf3fdSPer Liden .hdrsize = TIPC_GENL_HDRLEN, 98b97bf3fdSPer Liden .maxattr = 0, 99*d49e2041SYing Xue .netnsok = true, 100b97bf3fdSPer Liden }; 101b97bf3fdSPer Liden 1020655f6a8SRichard Alpe /* Legacy ASCII API */ 103c53ed742SJohannes Berg static struct genl_ops tipc_genl_ops[] = { 104c53ed742SJohannes Berg { 105b97bf3fdSPer Liden .cmd = TIPC_GENL_CMD, 106b97bf3fdSPer Liden .doit = handle_cmd, 107c53ed742SJohannes Berg }, 108b97bf3fdSPer Liden }; 109b97bf3fdSPer Liden 1100655f6a8SRichard Alpe /* Users of the legacy API (tipc-config) can't handle that we add operations, 1110655f6a8SRichard Alpe * so we have a separate genl handling for the new API. 1120655f6a8SRichard Alpe */ 1130655f6a8SRichard Alpe struct genl_family tipc_genl_v2_family = { 1140655f6a8SRichard Alpe .id = GENL_ID_GENERATE, 1150655f6a8SRichard Alpe .name = TIPC_GENL_V2_NAME, 1160655f6a8SRichard Alpe .version = TIPC_GENL_V2_VERSION, 1170655f6a8SRichard Alpe .hdrsize = 0, 1180655f6a8SRichard Alpe .maxattr = TIPC_NLA_MAX, 119*d49e2041SYing Xue .netnsok = true, 1200655f6a8SRichard Alpe }; 1210655f6a8SRichard Alpe 1220655f6a8SRichard Alpe static const struct genl_ops tipc_genl_v2_ops[] = { 1230655f6a8SRichard Alpe { 1240655f6a8SRichard Alpe .cmd = TIPC_NL_BEARER_DISABLE, 1250655f6a8SRichard Alpe .doit = tipc_nl_bearer_disable, 1260655f6a8SRichard Alpe .policy = tipc_nl_policy, 1270655f6a8SRichard Alpe }, 1280655f6a8SRichard Alpe { 1290655f6a8SRichard Alpe .cmd = TIPC_NL_BEARER_ENABLE, 1300655f6a8SRichard Alpe .doit = tipc_nl_bearer_enable, 1310655f6a8SRichard Alpe .policy = tipc_nl_policy, 13235b9dd76SRichard Alpe }, 13335b9dd76SRichard Alpe { 13435b9dd76SRichard Alpe .cmd = TIPC_NL_BEARER_GET, 13535b9dd76SRichard Alpe .doit = tipc_nl_bearer_get, 13635b9dd76SRichard Alpe .dumpit = tipc_nl_bearer_dump, 13735b9dd76SRichard Alpe .policy = tipc_nl_policy, 138315c00bcSRichard Alpe }, 139315c00bcSRichard Alpe { 140315c00bcSRichard Alpe .cmd = TIPC_NL_BEARER_SET, 141315c00bcSRichard Alpe .doit = tipc_nl_bearer_set, 142315c00bcSRichard Alpe .policy = tipc_nl_policy, 14334b78a12SRichard Alpe }, 14434b78a12SRichard Alpe { 14534b78a12SRichard Alpe .cmd = TIPC_NL_SOCK_GET, 14634b78a12SRichard Alpe .dumpit = tipc_nl_sk_dump, 14734b78a12SRichard Alpe .policy = tipc_nl_policy, 1481a1a143dSRichard Alpe }, 1491a1a143dSRichard Alpe { 1501a1a143dSRichard Alpe .cmd = TIPC_NL_PUBL_GET, 1511a1a143dSRichard Alpe .dumpit = tipc_nl_publ_dump, 1521a1a143dSRichard Alpe .policy = tipc_nl_policy, 1537be57fc6SRichard Alpe }, 1547be57fc6SRichard Alpe { 1557be57fc6SRichard Alpe .cmd = TIPC_NL_LINK_GET, 1567be57fc6SRichard Alpe .doit = tipc_nl_link_get, 1577be57fc6SRichard Alpe .dumpit = tipc_nl_link_dump, 1587be57fc6SRichard Alpe .policy = tipc_nl_policy, 159f96ce7a2SRichard Alpe }, 160f96ce7a2SRichard Alpe { 161f96ce7a2SRichard Alpe .cmd = TIPC_NL_LINK_SET, 162f96ce7a2SRichard Alpe .doit = tipc_nl_link_set, 163f96ce7a2SRichard Alpe .policy = tipc_nl_policy, 164ae36342bSRichard Alpe }, 165ae36342bSRichard Alpe { 166ae36342bSRichard Alpe .cmd = TIPC_NL_LINK_RESET_STATS, 167ae36342bSRichard Alpe .doit = tipc_nl_link_reset_stats, 168ae36342bSRichard Alpe .policy = tipc_nl_policy, 16946f15c67SRichard Alpe }, 17046f15c67SRichard Alpe { 17146f15c67SRichard Alpe .cmd = TIPC_NL_MEDIA_GET, 17246f15c67SRichard Alpe .doit = tipc_nl_media_get, 17346f15c67SRichard Alpe .dumpit = tipc_nl_media_dump, 17446f15c67SRichard Alpe .policy = tipc_nl_policy, 1751e55417dSRichard Alpe }, 1761e55417dSRichard Alpe { 1771e55417dSRichard Alpe .cmd = TIPC_NL_MEDIA_SET, 1781e55417dSRichard Alpe .doit = tipc_nl_media_set, 1791e55417dSRichard Alpe .policy = tipc_nl_policy, 1803e4b6ab5SRichard Alpe }, 1813e4b6ab5SRichard Alpe { 1823e4b6ab5SRichard Alpe .cmd = TIPC_NL_NODE_GET, 1833e4b6ab5SRichard Alpe .dumpit = tipc_nl_node_dump, 1843e4b6ab5SRichard Alpe .policy = tipc_nl_policy, 185fd3cf2adSRichard Alpe }, 186fd3cf2adSRichard Alpe { 187fd3cf2adSRichard Alpe .cmd = TIPC_NL_NET_GET, 188fd3cf2adSRichard Alpe .dumpit = tipc_nl_net_dump, 189fd3cf2adSRichard Alpe .policy = tipc_nl_policy, 19027c21416SRichard Alpe }, 19127c21416SRichard Alpe { 19227c21416SRichard Alpe .cmd = TIPC_NL_NET_SET, 19327c21416SRichard Alpe .doit = tipc_nl_net_set, 19427c21416SRichard Alpe .policy = tipc_nl_policy, 1951593123aSRichard Alpe }, 1961593123aSRichard Alpe { 1971593123aSRichard Alpe .cmd = TIPC_NL_NAME_TABLE_GET, 1981593123aSRichard Alpe .dumpit = tipc_nl_name_table_dump, 1991593123aSRichard Alpe .policy = tipc_nl_policy, 2000655f6a8SRichard Alpe } 2010655f6a8SRichard Alpe }; 2020655f6a8SRichard Alpe 2031a1a143dSRichard Alpe int tipc_nlmsg_parse(const struct nlmsghdr *nlh, struct nlattr ***attr) 2041a1a143dSRichard Alpe { 2051a1a143dSRichard Alpe u32 maxattr = tipc_genl_v2_family.maxattr; 2061a1a143dSRichard Alpe 2071a1a143dSRichard Alpe *attr = tipc_genl_v2_family.attrbuf; 2081a1a143dSRichard Alpe if (!*attr) 2091a1a143dSRichard Alpe return -EOPNOTSUPP; 2101a1a143dSRichard Alpe 2111a1a143dSRichard Alpe return nlmsg_parse(nlh, GENL_HDRLEN, *attr, maxattr, tipc_nl_policy); 2121a1a143dSRichard Alpe } 2131a1a143dSRichard Alpe 2144323add6SPer Liden int tipc_netlink_start(void) 215b97bf3fdSPer Liden { 216acb0a200SMichał Mirosław int res; 217b70e4f45SJon Maloy 218c53ed742SJohannes Berg res = genl_register_family_with_ops(&tipc_genl_family, tipc_genl_ops); 219acb0a200SMichał Mirosław if (res) { 2200655f6a8SRichard Alpe pr_err("Failed to register legacy interface\n"); 2210655f6a8SRichard Alpe return res; 2220655f6a8SRichard Alpe } 2230655f6a8SRichard Alpe 2240655f6a8SRichard Alpe res = genl_register_family_with_ops(&tipc_genl_v2_family, 2250655f6a8SRichard Alpe tipc_genl_v2_ops); 2260655f6a8SRichard Alpe if (res) { 2272cf8aa19SErik Hugne pr_err("Failed to register netlink interface\n"); 228acb0a200SMichał Mirosław return res; 229acb0a200SMichał Mirosław } 230acb0a200SMichał Mirosław return 0; 231b97bf3fdSPer Liden } 232b97bf3fdSPer Liden 2334323add6SPer Liden void tipc_netlink_stop(void) 234b97bf3fdSPer Liden { 235acb0a200SMichał Mirosław genl_unregister_family(&tipc_genl_family); 2360655f6a8SRichard Alpe genl_unregister_family(&tipc_genl_v2_family); 237b97bf3fdSPer Liden } 238