Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v3.17-rc4 342 lines 11 kB view raw
1/* 2 * net/tipc/config.c: TIPC configuration management code 3 * 4 * Copyright (c) 2002-2006, Ericsson AB 5 * Copyright (c) 2004-2007, 2010-2013, Wind River Systems 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions are met: 10 * 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the names of the copyright holders nor the names of its 17 * contributors may be used to endorse or promote products derived from 18 * this software without specific prior written permission. 19 * 20 * Alternatively, this software may be distributed under the terms of the 21 * GNU General Public License ("GPL") version 2 as published by the Free 22 * Software Foundation. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 25 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 28 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 30 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 32 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 33 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 34 * POSSIBILITY OF SUCH DAMAGE. 35 */ 36 37#include "core.h" 38#include "port.h" 39#include "name_table.h" 40#include "config.h" 41#include "server.h" 42 43#define REPLY_TRUNCATED "<truncated>\n" 44 45static const void *req_tlv_area; /* request message TLV area */ 46static int req_tlv_space; /* request message TLV area size */ 47static int rep_headroom; /* reply message headroom to use */ 48 49struct sk_buff *tipc_cfg_reply_alloc(int payload_size) 50{ 51 struct sk_buff *buf; 52 53 buf = alloc_skb(rep_headroom + payload_size, GFP_ATOMIC); 54 if (buf) 55 skb_reserve(buf, rep_headroom); 56 return buf; 57} 58 59int tipc_cfg_append_tlv(struct sk_buff *buf, int tlv_type, 60 void *tlv_data, int tlv_data_size) 61{ 62 struct tlv_desc *tlv = (struct tlv_desc *)skb_tail_pointer(buf); 63 int new_tlv_space = TLV_SPACE(tlv_data_size); 64 65 if (skb_tailroom(buf) < new_tlv_space) 66 return 0; 67 skb_put(buf, new_tlv_space); 68 tlv->tlv_type = htons(tlv_type); 69 tlv->tlv_len = htons(TLV_LENGTH(tlv_data_size)); 70 if (tlv_data_size && tlv_data) 71 memcpy(TLV_DATA(tlv), tlv_data, tlv_data_size); 72 return 1; 73} 74 75static struct sk_buff *tipc_cfg_reply_unsigned_type(u16 tlv_type, u32 value) 76{ 77 struct sk_buff *buf; 78 __be32 value_net; 79 80 buf = tipc_cfg_reply_alloc(TLV_SPACE(sizeof(value))); 81 if (buf) { 82 value_net = htonl(value); 83 tipc_cfg_append_tlv(buf, tlv_type, &value_net, 84 sizeof(value_net)); 85 } 86 return buf; 87} 88 89static struct sk_buff *tipc_cfg_reply_unsigned(u32 value) 90{ 91 return tipc_cfg_reply_unsigned_type(TIPC_TLV_UNSIGNED, value); 92} 93 94struct sk_buff *tipc_cfg_reply_string_type(u16 tlv_type, char *string) 95{ 96 struct sk_buff *buf; 97 int string_len = strlen(string) + 1; 98 99 buf = tipc_cfg_reply_alloc(TLV_SPACE(string_len)); 100 if (buf) 101 tipc_cfg_append_tlv(buf, tlv_type, string, string_len); 102 return buf; 103} 104 105static struct sk_buff *tipc_show_stats(void) 106{ 107 struct sk_buff *buf; 108 struct tlv_desc *rep_tlv; 109 char *pb; 110 int pb_len; 111 int str_len; 112 u32 value; 113 114 if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED)) 115 return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR); 116 117 value = ntohl(*(u32 *)TLV_DATA(req_tlv_area)); 118 if (value != 0) 119 return tipc_cfg_reply_error_string("unsupported argument"); 120 121 buf = tipc_cfg_reply_alloc(TLV_SPACE(ULTRA_STRING_MAX_LEN)); 122 if (buf == NULL) 123 return NULL; 124 125 rep_tlv = (struct tlv_desc *)buf->data; 126 pb = TLV_DATA(rep_tlv); 127 pb_len = ULTRA_STRING_MAX_LEN; 128 129 str_len = tipc_snprintf(pb, pb_len, "TIPC version " TIPC_MOD_VER "\n"); 130 str_len += 1; /* for "\0" */ 131 skb_put(buf, TLV_SPACE(str_len)); 132 TLV_SET(rep_tlv, TIPC_TLV_ULTRA_STRING, NULL, str_len); 133 134 return buf; 135} 136 137static struct sk_buff *cfg_enable_bearer(void) 138{ 139 struct tipc_bearer_config *args; 140 141 if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_BEARER_CONFIG)) 142 return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR); 143 144 args = (struct tipc_bearer_config *)TLV_DATA(req_tlv_area); 145 if (tipc_enable_bearer(args->name, 146 ntohl(args->disc_domain), 147 ntohl(args->priority))) 148 return tipc_cfg_reply_error_string("unable to enable bearer"); 149 150 return tipc_cfg_reply_none(); 151} 152 153static struct sk_buff *cfg_disable_bearer(void) 154{ 155 if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_BEARER_NAME)) 156 return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR); 157 158 if (tipc_disable_bearer((char *)TLV_DATA(req_tlv_area))) 159 return tipc_cfg_reply_error_string("unable to disable bearer"); 160 161 return tipc_cfg_reply_none(); 162} 163 164static struct sk_buff *cfg_set_own_addr(void) 165{ 166 u32 addr; 167 168 if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_NET_ADDR)) 169 return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR); 170 171 addr = ntohl(*(__be32 *)TLV_DATA(req_tlv_area)); 172 if (addr == tipc_own_addr) 173 return tipc_cfg_reply_none(); 174 if (!tipc_addr_node_valid(addr)) 175 return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE 176 " (node address)"); 177 if (tipc_own_addr) 178 return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED 179 " (cannot change node address once assigned)"); 180 if (!tipc_net_start(addr)) 181 return tipc_cfg_reply_none(); 182 183 return tipc_cfg_reply_error_string("cannot change to network mode"); 184} 185 186static struct sk_buff *cfg_set_max_ports(void) 187{ 188 u32 value; 189 190 if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED)) 191 return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR); 192 value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area)); 193 if (value == tipc_max_ports) 194 return tipc_cfg_reply_none(); 195 if (value < 127 || value > 65535) 196 return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE 197 " (max ports must be 127-65535)"); 198 return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED 199 " (cannot change max ports while TIPC is active)"); 200} 201 202static struct sk_buff *cfg_set_netid(void) 203{ 204 u32 value; 205 206 if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED)) 207 return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR); 208 value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area)); 209 if (value == tipc_net_id) 210 return tipc_cfg_reply_none(); 211 if (value < 1 || value > 9999) 212 return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE 213 " (network id must be 1-9999)"); 214 if (tipc_own_addr) 215 return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED 216 " (cannot change network id once TIPC has joined a network)"); 217 tipc_net_id = value; 218 return tipc_cfg_reply_none(); 219} 220 221struct sk_buff *tipc_cfg_do_cmd(u32 orig_node, u16 cmd, const void *request_area, 222 int request_space, int reply_headroom) 223{ 224 struct sk_buff *rep_tlv_buf; 225 226 rtnl_lock(); 227 228 /* Save request and reply details in a well-known location */ 229 req_tlv_area = request_area; 230 req_tlv_space = request_space; 231 rep_headroom = reply_headroom; 232 233 /* Check command authorization */ 234 if (likely(in_own_node(orig_node))) { 235 /* command is permitted */ 236 } else { 237 rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED 238 " (cannot be done remotely)"); 239 goto exit; 240 } 241 242 /* Call appropriate processing routine */ 243 switch (cmd) { 244 case TIPC_CMD_NOOP: 245 rep_tlv_buf = tipc_cfg_reply_none(); 246 break; 247 case TIPC_CMD_GET_NODES: 248 rep_tlv_buf = tipc_node_get_nodes(req_tlv_area, req_tlv_space); 249 break; 250 case TIPC_CMD_GET_LINKS: 251 rep_tlv_buf = tipc_node_get_links(req_tlv_area, req_tlv_space); 252 break; 253 case TIPC_CMD_SHOW_LINK_STATS: 254 rep_tlv_buf = tipc_link_cmd_show_stats(req_tlv_area, req_tlv_space); 255 break; 256 case TIPC_CMD_RESET_LINK_STATS: 257 rep_tlv_buf = tipc_link_cmd_reset_stats(req_tlv_area, req_tlv_space); 258 break; 259 case TIPC_CMD_SHOW_NAME_TABLE: 260 rep_tlv_buf = tipc_nametbl_get(req_tlv_area, req_tlv_space); 261 break; 262 case TIPC_CMD_GET_BEARER_NAMES: 263 rep_tlv_buf = tipc_bearer_get_names(); 264 break; 265 case TIPC_CMD_GET_MEDIA_NAMES: 266 rep_tlv_buf = tipc_media_get_names(); 267 break; 268 case TIPC_CMD_SHOW_PORTS: 269 rep_tlv_buf = tipc_port_get_ports(); 270 break; 271 case TIPC_CMD_SHOW_STATS: 272 rep_tlv_buf = tipc_show_stats(); 273 break; 274 case TIPC_CMD_SET_LINK_TOL: 275 case TIPC_CMD_SET_LINK_PRI: 276 case TIPC_CMD_SET_LINK_WINDOW: 277 rep_tlv_buf = tipc_link_cmd_config(req_tlv_area, req_tlv_space, cmd); 278 break; 279 case TIPC_CMD_ENABLE_BEARER: 280 rep_tlv_buf = cfg_enable_bearer(); 281 break; 282 case TIPC_CMD_DISABLE_BEARER: 283 rep_tlv_buf = cfg_disable_bearer(); 284 break; 285 case TIPC_CMD_SET_NODE_ADDR: 286 rep_tlv_buf = cfg_set_own_addr(); 287 break; 288 case TIPC_CMD_SET_MAX_PORTS: 289 rep_tlv_buf = cfg_set_max_ports(); 290 break; 291 case TIPC_CMD_SET_NETID: 292 rep_tlv_buf = cfg_set_netid(); 293 break; 294 case TIPC_CMD_GET_MAX_PORTS: 295 rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_max_ports); 296 break; 297 case TIPC_CMD_GET_NETID: 298 rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_net_id); 299 break; 300 case TIPC_CMD_NOT_NET_ADMIN: 301 rep_tlv_buf = 302 tipc_cfg_reply_error_string(TIPC_CFG_NOT_NET_ADMIN); 303 break; 304 case TIPC_CMD_SET_MAX_ZONES: 305 case TIPC_CMD_GET_MAX_ZONES: 306 case TIPC_CMD_SET_MAX_SLAVES: 307 case TIPC_CMD_GET_MAX_SLAVES: 308 case TIPC_CMD_SET_MAX_CLUSTERS: 309 case TIPC_CMD_GET_MAX_CLUSTERS: 310 case TIPC_CMD_SET_MAX_NODES: 311 case TIPC_CMD_GET_MAX_NODES: 312 case TIPC_CMD_SET_MAX_SUBSCR: 313 case TIPC_CMD_GET_MAX_SUBSCR: 314 case TIPC_CMD_SET_MAX_PUBL: 315 case TIPC_CMD_GET_MAX_PUBL: 316 case TIPC_CMD_SET_LOG_SIZE: 317 case TIPC_CMD_SET_REMOTE_MNG: 318 case TIPC_CMD_GET_REMOTE_MNG: 319 case TIPC_CMD_DUMP_LOG: 320 rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED 321 " (obsolete command)"); 322 break; 323 default: 324 rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED 325 " (unknown command)"); 326 break; 327 } 328 329 WARN_ON(rep_tlv_buf->len > TLV_SPACE(ULTRA_STRING_MAX_LEN)); 330 331 /* Append an error message if we cannot return all requested data */ 332 if (rep_tlv_buf->len == TLV_SPACE(ULTRA_STRING_MAX_LEN)) { 333 if (*(rep_tlv_buf->data + ULTRA_STRING_MAX_LEN) != '\0') 334 sprintf(rep_tlv_buf->data + rep_tlv_buf->len - 335 sizeof(REPLY_TRUNCATED) - 1, REPLY_TRUNCATED); 336 } 337 338 /* Return reply buffer */ 339exit: 340 rtnl_unlock(); 341 return rep_tlv_buf; 342}