at v3.11-rc4 448 lines 14 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 DEFINE_MUTEX(config_mutex); 46static struct tipc_server cfgsrv; 47 48static const void *req_tlv_area; /* request message TLV area */ 49static int req_tlv_space; /* request message TLV area size */ 50static int rep_headroom; /* reply message headroom to use */ 51 52 53struct sk_buff *tipc_cfg_reply_alloc(int payload_size) 54{ 55 struct sk_buff *buf; 56 57 buf = alloc_skb(rep_headroom + payload_size, GFP_ATOMIC); 58 if (buf) 59 skb_reserve(buf, rep_headroom); 60 return buf; 61} 62 63int tipc_cfg_append_tlv(struct sk_buff *buf, int tlv_type, 64 void *tlv_data, int tlv_data_size) 65{ 66 struct tlv_desc *tlv = (struct tlv_desc *)skb_tail_pointer(buf); 67 int new_tlv_space = TLV_SPACE(tlv_data_size); 68 69 if (skb_tailroom(buf) < new_tlv_space) 70 return 0; 71 skb_put(buf, new_tlv_space); 72 tlv->tlv_type = htons(tlv_type); 73 tlv->tlv_len = htons(TLV_LENGTH(tlv_data_size)); 74 if (tlv_data_size && tlv_data) 75 memcpy(TLV_DATA(tlv), tlv_data, tlv_data_size); 76 return 1; 77} 78 79static struct sk_buff *tipc_cfg_reply_unsigned_type(u16 tlv_type, u32 value) 80{ 81 struct sk_buff *buf; 82 __be32 value_net; 83 84 buf = tipc_cfg_reply_alloc(TLV_SPACE(sizeof(value))); 85 if (buf) { 86 value_net = htonl(value); 87 tipc_cfg_append_tlv(buf, tlv_type, &value_net, 88 sizeof(value_net)); 89 } 90 return buf; 91} 92 93static struct sk_buff *tipc_cfg_reply_unsigned(u32 value) 94{ 95 return tipc_cfg_reply_unsigned_type(TIPC_TLV_UNSIGNED, value); 96} 97 98struct sk_buff *tipc_cfg_reply_string_type(u16 tlv_type, char *string) 99{ 100 struct sk_buff *buf; 101 int string_len = strlen(string) + 1; 102 103 buf = tipc_cfg_reply_alloc(TLV_SPACE(string_len)); 104 if (buf) 105 tipc_cfg_append_tlv(buf, tlv_type, string, string_len); 106 return buf; 107} 108 109static struct sk_buff *tipc_show_stats(void) 110{ 111 struct sk_buff *buf; 112 struct tlv_desc *rep_tlv; 113 char *pb; 114 int pb_len; 115 int str_len; 116 u32 value; 117 118 if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED)) 119 return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR); 120 121 value = ntohl(*(u32 *)TLV_DATA(req_tlv_area)); 122 if (value != 0) 123 return tipc_cfg_reply_error_string("unsupported argument"); 124 125 buf = tipc_cfg_reply_alloc(TLV_SPACE(ULTRA_STRING_MAX_LEN)); 126 if (buf == NULL) 127 return NULL; 128 129 rep_tlv = (struct tlv_desc *)buf->data; 130 pb = TLV_DATA(rep_tlv); 131 pb_len = ULTRA_STRING_MAX_LEN; 132 133 str_len = tipc_snprintf(pb, pb_len, "TIPC version " TIPC_MOD_VER "\n"); 134 str_len += 1; /* for "\0" */ 135 skb_put(buf, TLV_SPACE(str_len)); 136 TLV_SET(rep_tlv, TIPC_TLV_ULTRA_STRING, NULL, str_len); 137 138 return buf; 139} 140 141static struct sk_buff *cfg_enable_bearer(void) 142{ 143 struct tipc_bearer_config *args; 144 145 if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_BEARER_CONFIG)) 146 return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR); 147 148 args = (struct tipc_bearer_config *)TLV_DATA(req_tlv_area); 149 if (tipc_enable_bearer(args->name, 150 ntohl(args->disc_domain), 151 ntohl(args->priority))) 152 return tipc_cfg_reply_error_string("unable to enable bearer"); 153 154 return tipc_cfg_reply_none(); 155} 156 157static struct sk_buff *cfg_disable_bearer(void) 158{ 159 if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_BEARER_NAME)) 160 return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR); 161 162 if (tipc_disable_bearer((char *)TLV_DATA(req_tlv_area))) 163 return tipc_cfg_reply_error_string("unable to disable bearer"); 164 165 return tipc_cfg_reply_none(); 166} 167 168static struct sk_buff *cfg_set_own_addr(void) 169{ 170 u32 addr; 171 172 if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_NET_ADDR)) 173 return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR); 174 175 addr = ntohl(*(__be32 *)TLV_DATA(req_tlv_area)); 176 if (addr == tipc_own_addr) 177 return tipc_cfg_reply_none(); 178 if (!tipc_addr_node_valid(addr)) 179 return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE 180 " (node address)"); 181 if (tipc_own_addr) 182 return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED 183 " (cannot change node address once assigned)"); 184 tipc_core_start_net(addr); 185 return tipc_cfg_reply_none(); 186} 187 188static struct sk_buff *cfg_set_remote_mng(void) 189{ 190 u32 value; 191 192 if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED)) 193 return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR); 194 195 value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area)); 196 tipc_remote_management = (value != 0); 197 return tipc_cfg_reply_none(); 198} 199 200static struct sk_buff *cfg_set_max_ports(void) 201{ 202 u32 value; 203 204 if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED)) 205 return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR); 206 value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area)); 207 if (value == tipc_max_ports) 208 return tipc_cfg_reply_none(); 209 if (value < 127 || value > 65535) 210 return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE 211 " (max ports must be 127-65535)"); 212 return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED 213 " (cannot change max ports while TIPC is active)"); 214} 215 216static struct sk_buff *cfg_set_netid(void) 217{ 218 u32 value; 219 220 if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED)) 221 return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR); 222 value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area)); 223 if (value == tipc_net_id) 224 return tipc_cfg_reply_none(); 225 if (value < 1 || value > 9999) 226 return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE 227 " (network id must be 1-9999)"); 228 if (tipc_own_addr) 229 return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED 230 " (cannot change network id once TIPC has joined a network)"); 231 tipc_net_id = value; 232 return tipc_cfg_reply_none(); 233} 234 235struct sk_buff *tipc_cfg_do_cmd(u32 orig_node, u16 cmd, const void *request_area, 236 int request_space, int reply_headroom) 237{ 238 struct sk_buff *rep_tlv_buf; 239 240 mutex_lock(&config_mutex); 241 242 /* Save request and reply details in a well-known location */ 243 req_tlv_area = request_area; 244 req_tlv_space = request_space; 245 rep_headroom = reply_headroom; 246 247 /* Check command authorization */ 248 if (likely(in_own_node(orig_node))) { 249 /* command is permitted */ 250 } else if (cmd >= 0x8000) { 251 rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED 252 " (cannot be done remotely)"); 253 goto exit; 254 } else if (!tipc_remote_management) { 255 rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NO_REMOTE); 256 goto exit; 257 } else if (cmd >= 0x4000) { 258 u32 domain = 0; 259 260 if ((tipc_nametbl_translate(TIPC_ZM_SRV, 0, &domain) == 0) || 261 (domain != orig_node)) { 262 rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NOT_ZONE_MSTR); 263 goto exit; 264 } 265 } 266 267 /* Call appropriate processing routine */ 268 switch (cmd) { 269 case TIPC_CMD_NOOP: 270 rep_tlv_buf = tipc_cfg_reply_none(); 271 break; 272 case TIPC_CMD_GET_NODES: 273 rep_tlv_buf = tipc_node_get_nodes(req_tlv_area, req_tlv_space); 274 break; 275 case TIPC_CMD_GET_LINKS: 276 rep_tlv_buf = tipc_node_get_links(req_tlv_area, req_tlv_space); 277 break; 278 case TIPC_CMD_SHOW_LINK_STATS: 279 rep_tlv_buf = tipc_link_cmd_show_stats(req_tlv_area, req_tlv_space); 280 break; 281 case TIPC_CMD_RESET_LINK_STATS: 282 rep_tlv_buf = tipc_link_cmd_reset_stats(req_tlv_area, req_tlv_space); 283 break; 284 case TIPC_CMD_SHOW_NAME_TABLE: 285 rep_tlv_buf = tipc_nametbl_get(req_tlv_area, req_tlv_space); 286 break; 287 case TIPC_CMD_GET_BEARER_NAMES: 288 rep_tlv_buf = tipc_bearer_get_names(); 289 break; 290 case TIPC_CMD_GET_MEDIA_NAMES: 291 rep_tlv_buf = tipc_media_get_names(); 292 break; 293 case TIPC_CMD_SHOW_PORTS: 294 rep_tlv_buf = tipc_port_get_ports(); 295 break; 296 case TIPC_CMD_SHOW_STATS: 297 rep_tlv_buf = tipc_show_stats(); 298 break; 299 case TIPC_CMD_SET_LINK_TOL: 300 case TIPC_CMD_SET_LINK_PRI: 301 case TIPC_CMD_SET_LINK_WINDOW: 302 rep_tlv_buf = tipc_link_cmd_config(req_tlv_area, req_tlv_space, cmd); 303 break; 304 case TIPC_CMD_ENABLE_BEARER: 305 rep_tlv_buf = cfg_enable_bearer(); 306 break; 307 case TIPC_CMD_DISABLE_BEARER: 308 rep_tlv_buf = cfg_disable_bearer(); 309 break; 310 case TIPC_CMD_SET_NODE_ADDR: 311 rep_tlv_buf = cfg_set_own_addr(); 312 break; 313 case TIPC_CMD_SET_REMOTE_MNG: 314 rep_tlv_buf = cfg_set_remote_mng(); 315 break; 316 case TIPC_CMD_SET_MAX_PORTS: 317 rep_tlv_buf = cfg_set_max_ports(); 318 break; 319 case TIPC_CMD_SET_NETID: 320 rep_tlv_buf = cfg_set_netid(); 321 break; 322 case TIPC_CMD_GET_REMOTE_MNG: 323 rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_remote_management); 324 break; 325 case TIPC_CMD_GET_MAX_PORTS: 326 rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_max_ports); 327 break; 328 case TIPC_CMD_GET_NETID: 329 rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_net_id); 330 break; 331 case TIPC_CMD_NOT_NET_ADMIN: 332 rep_tlv_buf = 333 tipc_cfg_reply_error_string(TIPC_CFG_NOT_NET_ADMIN); 334 break; 335 case TIPC_CMD_SET_MAX_ZONES: 336 case TIPC_CMD_GET_MAX_ZONES: 337 case TIPC_CMD_SET_MAX_SLAVES: 338 case TIPC_CMD_GET_MAX_SLAVES: 339 case TIPC_CMD_SET_MAX_CLUSTERS: 340 case TIPC_CMD_GET_MAX_CLUSTERS: 341 case TIPC_CMD_SET_MAX_NODES: 342 case TIPC_CMD_GET_MAX_NODES: 343 case TIPC_CMD_SET_MAX_SUBSCR: 344 case TIPC_CMD_GET_MAX_SUBSCR: 345 case TIPC_CMD_SET_MAX_PUBL: 346 case TIPC_CMD_GET_MAX_PUBL: 347 case TIPC_CMD_SET_LOG_SIZE: 348 case TIPC_CMD_DUMP_LOG: 349 rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED 350 " (obsolete command)"); 351 break; 352 default: 353 rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED 354 " (unknown command)"); 355 break; 356 } 357 358 WARN_ON(rep_tlv_buf->len > TLV_SPACE(ULTRA_STRING_MAX_LEN)); 359 360 /* Append an error message if we cannot return all requested data */ 361 if (rep_tlv_buf->len == TLV_SPACE(ULTRA_STRING_MAX_LEN)) { 362 if (*(rep_tlv_buf->data + ULTRA_STRING_MAX_LEN) != '\0') 363 sprintf(rep_tlv_buf->data + rep_tlv_buf->len - 364 sizeof(REPLY_TRUNCATED) - 1, REPLY_TRUNCATED); 365 } 366 367 /* Return reply buffer */ 368exit: 369 mutex_unlock(&config_mutex); 370 return rep_tlv_buf; 371} 372 373static void cfg_conn_msg_event(int conid, struct sockaddr_tipc *addr, 374 void *usr_data, void *buf, size_t len) 375{ 376 struct tipc_cfg_msg_hdr *req_hdr; 377 struct tipc_cfg_msg_hdr *rep_hdr; 378 struct sk_buff *rep_buf; 379 int ret; 380 381 /* Validate configuration message header (ignore invalid message) */ 382 req_hdr = (struct tipc_cfg_msg_hdr *)buf; 383 if ((len < sizeof(*req_hdr)) || 384 (len != TCM_ALIGN(ntohl(req_hdr->tcm_len))) || 385 (ntohs(req_hdr->tcm_flags) != TCM_F_REQUEST)) { 386 pr_warn("Invalid configuration message discarded\n"); 387 return; 388 } 389 390 /* Generate reply for request (if can't, return request) */ 391 rep_buf = tipc_cfg_do_cmd(addr->addr.id.node, ntohs(req_hdr->tcm_type), 392 buf + sizeof(*req_hdr), 393 len - sizeof(*req_hdr), 394 BUF_HEADROOM + MAX_H_SIZE + sizeof(*rep_hdr)); 395 if (rep_buf) { 396 skb_push(rep_buf, sizeof(*rep_hdr)); 397 rep_hdr = (struct tipc_cfg_msg_hdr *)rep_buf->data; 398 memcpy(rep_hdr, req_hdr, sizeof(*rep_hdr)); 399 rep_hdr->tcm_len = htonl(rep_buf->len); 400 rep_hdr->tcm_flags &= htons(~TCM_F_REQUEST); 401 402 ret = tipc_conn_sendmsg(&cfgsrv, conid, addr, rep_buf->data, 403 rep_buf->len); 404 if (ret < 0) 405 pr_err("Sending cfg reply message failed, no memory\n"); 406 407 kfree_skb(rep_buf); 408 } 409} 410 411static struct sockaddr_tipc cfgsrv_addr __read_mostly = { 412 .family = AF_TIPC, 413 .addrtype = TIPC_ADDR_NAMESEQ, 414 .addr.nameseq.type = TIPC_CFG_SRV, 415 .addr.nameseq.lower = 0, 416 .addr.nameseq.upper = 0, 417 .scope = TIPC_ZONE_SCOPE 418}; 419 420static struct tipc_server cfgsrv __read_mostly = { 421 .saddr = &cfgsrv_addr, 422 .imp = TIPC_CRITICAL_IMPORTANCE, 423 .type = SOCK_RDM, 424 .max_rcvbuf_size = 64 * 1024, 425 .name = "cfg_server", 426 .tipc_conn_recvmsg = cfg_conn_msg_event, 427 .tipc_conn_new = NULL, 428 .tipc_conn_shutdown = NULL 429}; 430 431int tipc_cfg_init(void) 432{ 433 return tipc_server_start(&cfgsrv); 434} 435 436void tipc_cfg_reinit(void) 437{ 438 tipc_server_stop(&cfgsrv); 439 440 cfgsrv_addr.addr.nameseq.lower = tipc_own_addr; 441 cfgsrv_addr.addr.nameseq.upper = tipc_own_addr; 442 tipc_server_start(&cfgsrv); 443} 444 445void tipc_cfg_stop(void) 446{ 447 tipc_server_stop(&cfgsrv); 448}