at v3.5-rc1 504 lines 15 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-2011, 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 42static u32 config_port_ref; 43 44static DEFINE_SPINLOCK(config_lock); 45 46static const void *req_tlv_area; /* request message TLV area */ 47static int req_tlv_space; /* request message TLV area size */ 48static int rep_headroom; /* reply message headroom to use */ 49 50 51struct sk_buff *tipc_cfg_reply_alloc(int payload_size) 52{ 53 struct sk_buff *buf; 54 55 buf = alloc_skb(rep_headroom + payload_size, GFP_ATOMIC); 56 if (buf) 57 skb_reserve(buf, rep_headroom); 58 return buf; 59} 60 61int tipc_cfg_append_tlv(struct sk_buff *buf, int tlv_type, 62 void *tlv_data, int tlv_data_size) 63{ 64 struct tlv_desc *tlv = (struct tlv_desc *)skb_tail_pointer(buf); 65 int new_tlv_space = TLV_SPACE(tlv_data_size); 66 67 if (skb_tailroom(buf) < new_tlv_space) 68 return 0; 69 skb_put(buf, new_tlv_space); 70 tlv->tlv_type = htons(tlv_type); 71 tlv->tlv_len = htons(TLV_LENGTH(tlv_data_size)); 72 if (tlv_data_size && tlv_data) 73 memcpy(TLV_DATA(tlv), tlv_data, tlv_data_size); 74 return 1; 75} 76 77static struct sk_buff *tipc_cfg_reply_unsigned_type(u16 tlv_type, u32 value) 78{ 79 struct sk_buff *buf; 80 __be32 value_net; 81 82 buf = tipc_cfg_reply_alloc(TLV_SPACE(sizeof(value))); 83 if (buf) { 84 value_net = htonl(value); 85 tipc_cfg_append_tlv(buf, tlv_type, &value_net, 86 sizeof(value_net)); 87 } 88 return buf; 89} 90 91static struct sk_buff *tipc_cfg_reply_unsigned(u32 value) 92{ 93 return tipc_cfg_reply_unsigned_type(TIPC_TLV_UNSIGNED, value); 94} 95 96struct sk_buff *tipc_cfg_reply_string_type(u16 tlv_type, char *string) 97{ 98 struct sk_buff *buf; 99 int string_len = strlen(string) + 1; 100 101 buf = tipc_cfg_reply_alloc(TLV_SPACE(string_len)); 102 if (buf) 103 tipc_cfg_append_tlv(buf, tlv_type, string, string_len); 104 return buf; 105} 106 107#define MAX_STATS_INFO 2000 108 109static struct sk_buff *tipc_show_stats(void) 110{ 111 struct sk_buff *buf; 112 struct tlv_desc *rep_tlv; 113 struct print_buf pb; 114 int str_len; 115 u32 value; 116 117 if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED)) 118 return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR); 119 120 value = ntohl(*(u32 *)TLV_DATA(req_tlv_area)); 121 if (value != 0) 122 return tipc_cfg_reply_error_string("unsupported argument"); 123 124 buf = tipc_cfg_reply_alloc(TLV_SPACE(MAX_STATS_INFO)); 125 if (buf == NULL) 126 return NULL; 127 128 rep_tlv = (struct tlv_desc *)buf->data; 129 tipc_printbuf_init(&pb, (char *)TLV_DATA(rep_tlv), MAX_STATS_INFO); 130 131 tipc_printf(&pb, "TIPC version " TIPC_MOD_VER "\n"); 132 133 /* Use additional tipc_printf()'s to return more info ... */ 134 str_len = tipc_printbuf_validate(&pb); 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 185 /* 186 * Must temporarily release configuration spinlock while switching into 187 * networking mode as it calls tipc_eth_media_start(), which may sleep. 188 * Releasing the lock is harmless as other locally-issued configuration 189 * commands won't occur until this one completes, and remotely-issued 190 * configuration commands can't be received until a local configuration 191 * command to enable the first bearer is received and processed. 192 */ 193 spin_unlock_bh(&config_lock); 194 tipc_core_start_net(addr); 195 spin_lock_bh(&config_lock); 196 return tipc_cfg_reply_none(); 197} 198 199static struct sk_buff *cfg_set_remote_mng(void) 200{ 201 u32 value; 202 203 if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED)) 204 return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR); 205 206 value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area)); 207 tipc_remote_management = (value != 0); 208 return tipc_cfg_reply_none(); 209} 210 211static struct sk_buff *cfg_set_max_publications(void) 212{ 213 u32 value; 214 215 if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED)) 216 return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR); 217 218 value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area)); 219 if (value < 1 || value > 65535) 220 return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE 221 " (max publications must be 1-65535)"); 222 tipc_max_publications = value; 223 return tipc_cfg_reply_none(); 224} 225 226static struct sk_buff *cfg_set_max_subscriptions(void) 227{ 228 u32 value; 229 230 if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED)) 231 return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR); 232 233 value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area)); 234 if (value < 1 || value > 65535) 235 return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE 236 " (max subscriptions must be 1-65535"); 237 tipc_max_subscriptions = value; 238 return tipc_cfg_reply_none(); 239} 240 241static struct sk_buff *cfg_set_max_ports(void) 242{ 243 u32 value; 244 245 if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED)) 246 return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR); 247 value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area)); 248 if (value == tipc_max_ports) 249 return tipc_cfg_reply_none(); 250 if (value < 127 || value > 65535) 251 return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE 252 " (max ports must be 127-65535)"); 253 return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED 254 " (cannot change max ports while TIPC is active)"); 255} 256 257static struct sk_buff *cfg_set_netid(void) 258{ 259 u32 value; 260 261 if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED)) 262 return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR); 263 value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area)); 264 if (value == tipc_net_id) 265 return tipc_cfg_reply_none(); 266 if (value < 1 || value > 9999) 267 return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE 268 " (network id must be 1-9999)"); 269 if (tipc_own_addr) 270 return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED 271 " (cannot change network id once TIPC has joined a network)"); 272 tipc_net_id = value; 273 return tipc_cfg_reply_none(); 274} 275 276struct sk_buff *tipc_cfg_do_cmd(u32 orig_node, u16 cmd, const void *request_area, 277 int request_space, int reply_headroom) 278{ 279 struct sk_buff *rep_tlv_buf; 280 281 spin_lock_bh(&config_lock); 282 283 /* Save request and reply details in a well-known location */ 284 req_tlv_area = request_area; 285 req_tlv_space = request_space; 286 rep_headroom = reply_headroom; 287 288 /* Check command authorization */ 289 if (likely(in_own_node(orig_node))) { 290 /* command is permitted */ 291 } else if (cmd >= 0x8000) { 292 rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED 293 " (cannot be done remotely)"); 294 goto exit; 295 } else if (!tipc_remote_management) { 296 rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NO_REMOTE); 297 goto exit; 298 } else if (cmd >= 0x4000) { 299 u32 domain = 0; 300 301 if ((tipc_nametbl_translate(TIPC_ZM_SRV, 0, &domain) == 0) || 302 (domain != orig_node)) { 303 rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NOT_ZONE_MSTR); 304 goto exit; 305 } 306 } 307 308 /* Call appropriate processing routine */ 309 switch (cmd) { 310 case TIPC_CMD_NOOP: 311 rep_tlv_buf = tipc_cfg_reply_none(); 312 break; 313 case TIPC_CMD_GET_NODES: 314 rep_tlv_buf = tipc_node_get_nodes(req_tlv_area, req_tlv_space); 315 break; 316 case TIPC_CMD_GET_LINKS: 317 rep_tlv_buf = tipc_node_get_links(req_tlv_area, req_tlv_space); 318 break; 319 case TIPC_CMD_SHOW_LINK_STATS: 320 rep_tlv_buf = tipc_link_cmd_show_stats(req_tlv_area, req_tlv_space); 321 break; 322 case TIPC_CMD_RESET_LINK_STATS: 323 rep_tlv_buf = tipc_link_cmd_reset_stats(req_tlv_area, req_tlv_space); 324 break; 325 case TIPC_CMD_SHOW_NAME_TABLE: 326 rep_tlv_buf = tipc_nametbl_get(req_tlv_area, req_tlv_space); 327 break; 328 case TIPC_CMD_GET_BEARER_NAMES: 329 rep_tlv_buf = tipc_bearer_get_names(); 330 break; 331 case TIPC_CMD_GET_MEDIA_NAMES: 332 rep_tlv_buf = tipc_media_get_names(); 333 break; 334 case TIPC_CMD_SHOW_PORTS: 335 rep_tlv_buf = tipc_port_get_ports(); 336 break; 337 case TIPC_CMD_SET_LOG_SIZE: 338 rep_tlv_buf = tipc_log_resize_cmd(req_tlv_area, req_tlv_space); 339 break; 340 case TIPC_CMD_DUMP_LOG: 341 rep_tlv_buf = tipc_log_dump(); 342 break; 343 case TIPC_CMD_SHOW_STATS: 344 rep_tlv_buf = tipc_show_stats(); 345 break; 346 case TIPC_CMD_SET_LINK_TOL: 347 case TIPC_CMD_SET_LINK_PRI: 348 case TIPC_CMD_SET_LINK_WINDOW: 349 rep_tlv_buf = tipc_link_cmd_config(req_tlv_area, req_tlv_space, cmd); 350 break; 351 case TIPC_CMD_ENABLE_BEARER: 352 rep_tlv_buf = cfg_enable_bearer(); 353 break; 354 case TIPC_CMD_DISABLE_BEARER: 355 rep_tlv_buf = cfg_disable_bearer(); 356 break; 357 case TIPC_CMD_SET_NODE_ADDR: 358 rep_tlv_buf = cfg_set_own_addr(); 359 break; 360 case TIPC_CMD_SET_REMOTE_MNG: 361 rep_tlv_buf = cfg_set_remote_mng(); 362 break; 363 case TIPC_CMD_SET_MAX_PORTS: 364 rep_tlv_buf = cfg_set_max_ports(); 365 break; 366 case TIPC_CMD_SET_MAX_PUBL: 367 rep_tlv_buf = cfg_set_max_publications(); 368 break; 369 case TIPC_CMD_SET_MAX_SUBSCR: 370 rep_tlv_buf = cfg_set_max_subscriptions(); 371 break; 372 case TIPC_CMD_SET_NETID: 373 rep_tlv_buf = cfg_set_netid(); 374 break; 375 case TIPC_CMD_GET_REMOTE_MNG: 376 rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_remote_management); 377 break; 378 case TIPC_CMD_GET_MAX_PORTS: 379 rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_max_ports); 380 break; 381 case TIPC_CMD_GET_MAX_PUBL: 382 rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_max_publications); 383 break; 384 case TIPC_CMD_GET_MAX_SUBSCR: 385 rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_max_subscriptions); 386 break; 387 case TIPC_CMD_GET_NETID: 388 rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_net_id); 389 break; 390 case TIPC_CMD_NOT_NET_ADMIN: 391 rep_tlv_buf = 392 tipc_cfg_reply_error_string(TIPC_CFG_NOT_NET_ADMIN); 393 break; 394 case TIPC_CMD_SET_MAX_ZONES: 395 case TIPC_CMD_GET_MAX_ZONES: 396 case TIPC_CMD_SET_MAX_SLAVES: 397 case TIPC_CMD_GET_MAX_SLAVES: 398 case TIPC_CMD_SET_MAX_CLUSTERS: 399 case TIPC_CMD_GET_MAX_CLUSTERS: 400 case TIPC_CMD_SET_MAX_NODES: 401 case TIPC_CMD_GET_MAX_NODES: 402 rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED 403 " (obsolete command)"); 404 break; 405 default: 406 rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED 407 " (unknown command)"); 408 break; 409 } 410 411 /* Return reply buffer */ 412exit: 413 spin_unlock_bh(&config_lock); 414 return rep_tlv_buf; 415} 416 417static void cfg_named_msg_event(void *userdata, 418 u32 port_ref, 419 struct sk_buff **buf, 420 const unchar *msg, 421 u32 size, 422 u32 importance, 423 struct tipc_portid const *orig, 424 struct tipc_name_seq const *dest) 425{ 426 struct tipc_cfg_msg_hdr *req_hdr; 427 struct tipc_cfg_msg_hdr *rep_hdr; 428 struct sk_buff *rep_buf; 429 430 /* Validate configuration message header (ignore invalid message) */ 431 req_hdr = (struct tipc_cfg_msg_hdr *)msg; 432 if ((size < sizeof(*req_hdr)) || 433 (size != TCM_ALIGN(ntohl(req_hdr->tcm_len))) || 434 (ntohs(req_hdr->tcm_flags) != TCM_F_REQUEST)) { 435 warn("Invalid configuration message discarded\n"); 436 return; 437 } 438 439 /* Generate reply for request (if can't, return request) */ 440 rep_buf = tipc_cfg_do_cmd(orig->node, 441 ntohs(req_hdr->tcm_type), 442 msg + sizeof(*req_hdr), 443 size - sizeof(*req_hdr), 444 BUF_HEADROOM + MAX_H_SIZE + sizeof(*rep_hdr)); 445 if (rep_buf) { 446 skb_push(rep_buf, sizeof(*rep_hdr)); 447 rep_hdr = (struct tipc_cfg_msg_hdr *)rep_buf->data; 448 memcpy(rep_hdr, req_hdr, sizeof(*rep_hdr)); 449 rep_hdr->tcm_len = htonl(rep_buf->len); 450 rep_hdr->tcm_flags &= htons(~TCM_F_REQUEST); 451 } else { 452 rep_buf = *buf; 453 *buf = NULL; 454 } 455 456 /* NEED TO ADD CODE TO HANDLE FAILED SEND (SUCH AS CONGESTION) */ 457 tipc_send_buf2port(port_ref, orig, rep_buf, rep_buf->len); 458} 459 460int tipc_cfg_init(void) 461{ 462 struct tipc_name_seq seq; 463 int res; 464 465 res = tipc_createport(NULL, TIPC_CRITICAL_IMPORTANCE, 466 NULL, NULL, NULL, 467 NULL, cfg_named_msg_event, NULL, 468 NULL, &config_port_ref); 469 if (res) 470 goto failed; 471 472 seq.type = TIPC_CFG_SRV; 473 seq.lower = seq.upper = tipc_own_addr; 474 res = tipc_publish(config_port_ref, TIPC_ZONE_SCOPE, &seq); 475 if (res) 476 goto failed; 477 478 return 0; 479 480failed: 481 err("Unable to create configuration service\n"); 482 return res; 483} 484 485void tipc_cfg_reinit(void) 486{ 487 struct tipc_name_seq seq; 488 int res; 489 490 seq.type = TIPC_CFG_SRV; 491 seq.lower = seq.upper = 0; 492 tipc_withdraw(config_port_ref, TIPC_ZONE_SCOPE, &seq); 493 494 seq.lower = seq.upper = tipc_own_addr; 495 res = tipc_publish(config_port_ref, TIPC_ZONE_SCOPE, &seq); 496 if (res) 497 err("Unable to reinitialize configuration service\n"); 498} 499 500void tipc_cfg_stop(void) 501{ 502 tipc_deleteport(config_port_ref); 503 config_port_ref = 0; 504}