1/* 2 * net/tipc/config.c: TIPC configuration management code 3 * 4 * Copyright (c) 2002-2006, Ericsson AB 5 * Copyright (c) 2004-2007, 2010-2012, 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 42#define REPLY_TRUNCATED "<truncated>\n" 43 44static u32 config_port_ref; 45 46static DEFINE_SPINLOCK(config_lock); 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 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_ports(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 value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area)); 218 if (value == tipc_max_ports) 219 return tipc_cfg_reply_none(); 220 if (value < 127 || value > 65535) 221 return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE 222 " (max ports must be 127-65535)"); 223 return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED 224 " (cannot change max ports while TIPC is active)"); 225} 226 227static struct sk_buff *cfg_set_netid(void) 228{ 229 u32 value; 230 231 if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED)) 232 return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR); 233 value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area)); 234 if (value == tipc_net_id) 235 return tipc_cfg_reply_none(); 236 if (value < 1 || value > 9999) 237 return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE 238 " (network id must be 1-9999)"); 239 if (tipc_own_addr) 240 return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED 241 " (cannot change network id once TIPC has joined a network)"); 242 tipc_net_id = value; 243 return tipc_cfg_reply_none(); 244} 245 246struct sk_buff *tipc_cfg_do_cmd(u32 orig_node, u16 cmd, const void *request_area, 247 int request_space, int reply_headroom) 248{ 249 struct sk_buff *rep_tlv_buf; 250 251 spin_lock_bh(&config_lock); 252 253 /* Save request and reply details in a well-known location */ 254 req_tlv_area = request_area; 255 req_tlv_space = request_space; 256 rep_headroom = reply_headroom; 257 258 /* Check command authorization */ 259 if (likely(in_own_node(orig_node))) { 260 /* command is permitted */ 261 } else if (cmd >= 0x8000) { 262 rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED 263 " (cannot be done remotely)"); 264 goto exit; 265 } else if (!tipc_remote_management) { 266 rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NO_REMOTE); 267 goto exit; 268 } else if (cmd >= 0x4000) { 269 u32 domain = 0; 270 271 if ((tipc_nametbl_translate(TIPC_ZM_SRV, 0, &domain) == 0) || 272 (domain != orig_node)) { 273 rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NOT_ZONE_MSTR); 274 goto exit; 275 } 276 } 277 278 /* Call appropriate processing routine */ 279 switch (cmd) { 280 case TIPC_CMD_NOOP: 281 rep_tlv_buf = tipc_cfg_reply_none(); 282 break; 283 case TIPC_CMD_GET_NODES: 284 rep_tlv_buf = tipc_node_get_nodes(req_tlv_area, req_tlv_space); 285 break; 286 case TIPC_CMD_GET_LINKS: 287 rep_tlv_buf = tipc_node_get_links(req_tlv_area, req_tlv_space); 288 break; 289 case TIPC_CMD_SHOW_LINK_STATS: 290 rep_tlv_buf = tipc_link_cmd_show_stats(req_tlv_area, req_tlv_space); 291 break; 292 case TIPC_CMD_RESET_LINK_STATS: 293 rep_tlv_buf = tipc_link_cmd_reset_stats(req_tlv_area, req_tlv_space); 294 break; 295 case TIPC_CMD_SHOW_NAME_TABLE: 296 rep_tlv_buf = tipc_nametbl_get(req_tlv_area, req_tlv_space); 297 break; 298 case TIPC_CMD_GET_BEARER_NAMES: 299 rep_tlv_buf = tipc_bearer_get_names(); 300 break; 301 case TIPC_CMD_GET_MEDIA_NAMES: 302 rep_tlv_buf = tipc_media_get_names(); 303 break; 304 case TIPC_CMD_SHOW_PORTS: 305 rep_tlv_buf = tipc_port_get_ports(); 306 break; 307 case TIPC_CMD_SHOW_STATS: 308 rep_tlv_buf = tipc_show_stats(); 309 break; 310 case TIPC_CMD_SET_LINK_TOL: 311 case TIPC_CMD_SET_LINK_PRI: 312 case TIPC_CMD_SET_LINK_WINDOW: 313 rep_tlv_buf = tipc_link_cmd_config(req_tlv_area, req_tlv_space, cmd); 314 break; 315 case TIPC_CMD_ENABLE_BEARER: 316 rep_tlv_buf = cfg_enable_bearer(); 317 break; 318 case TIPC_CMD_DISABLE_BEARER: 319 rep_tlv_buf = cfg_disable_bearer(); 320 break; 321 case TIPC_CMD_SET_NODE_ADDR: 322 rep_tlv_buf = cfg_set_own_addr(); 323 break; 324 case TIPC_CMD_SET_REMOTE_MNG: 325 rep_tlv_buf = cfg_set_remote_mng(); 326 break; 327 case TIPC_CMD_SET_MAX_PORTS: 328 rep_tlv_buf = cfg_set_max_ports(); 329 break; 330 case TIPC_CMD_SET_NETID: 331 rep_tlv_buf = cfg_set_netid(); 332 break; 333 case TIPC_CMD_GET_REMOTE_MNG: 334 rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_remote_management); 335 break; 336 case TIPC_CMD_GET_MAX_PORTS: 337 rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_max_ports); 338 break; 339 case TIPC_CMD_GET_NETID: 340 rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_net_id); 341 break; 342 case TIPC_CMD_NOT_NET_ADMIN: 343 rep_tlv_buf = 344 tipc_cfg_reply_error_string(TIPC_CFG_NOT_NET_ADMIN); 345 break; 346 case TIPC_CMD_SET_MAX_ZONES: 347 case TIPC_CMD_GET_MAX_ZONES: 348 case TIPC_CMD_SET_MAX_SLAVES: 349 case TIPC_CMD_GET_MAX_SLAVES: 350 case TIPC_CMD_SET_MAX_CLUSTERS: 351 case TIPC_CMD_GET_MAX_CLUSTERS: 352 case TIPC_CMD_SET_MAX_NODES: 353 case TIPC_CMD_GET_MAX_NODES: 354 case TIPC_CMD_SET_MAX_SUBSCR: 355 case TIPC_CMD_GET_MAX_SUBSCR: 356 case TIPC_CMD_SET_MAX_PUBL: 357 case TIPC_CMD_GET_MAX_PUBL: 358 case TIPC_CMD_SET_LOG_SIZE: 359 case TIPC_CMD_DUMP_LOG: 360 rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED 361 " (obsolete command)"); 362 break; 363 default: 364 rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED 365 " (unknown command)"); 366 break; 367 } 368 369 WARN_ON(rep_tlv_buf->len > TLV_SPACE(ULTRA_STRING_MAX_LEN)); 370 371 /* Append an error message if we cannot return all requested data */ 372 if (rep_tlv_buf->len == TLV_SPACE(ULTRA_STRING_MAX_LEN)) { 373 if (*(rep_tlv_buf->data + ULTRA_STRING_MAX_LEN) != '\0') 374 sprintf(rep_tlv_buf->data + rep_tlv_buf->len - 375 sizeof(REPLY_TRUNCATED) - 1, REPLY_TRUNCATED); 376 } 377 378 /* Return reply buffer */ 379exit: 380 spin_unlock_bh(&config_lock); 381 return rep_tlv_buf; 382} 383 384static void cfg_named_msg_event(void *userdata, 385 u32 port_ref, 386 struct sk_buff **buf, 387 const unchar *msg, 388 u32 size, 389 u32 importance, 390 struct tipc_portid const *orig, 391 struct tipc_name_seq const *dest) 392{ 393 struct tipc_cfg_msg_hdr *req_hdr; 394 struct tipc_cfg_msg_hdr *rep_hdr; 395 struct sk_buff *rep_buf; 396 397 /* Validate configuration message header (ignore invalid message) */ 398 req_hdr = (struct tipc_cfg_msg_hdr *)msg; 399 if ((size < sizeof(*req_hdr)) || 400 (size != TCM_ALIGN(ntohl(req_hdr->tcm_len))) || 401 (ntohs(req_hdr->tcm_flags) != TCM_F_REQUEST)) { 402 pr_warn("Invalid configuration message discarded\n"); 403 return; 404 } 405 406 /* Generate reply for request (if can't, return request) */ 407 rep_buf = tipc_cfg_do_cmd(orig->node, 408 ntohs(req_hdr->tcm_type), 409 msg + sizeof(*req_hdr), 410 size - sizeof(*req_hdr), 411 BUF_HEADROOM + MAX_H_SIZE + sizeof(*rep_hdr)); 412 if (rep_buf) { 413 skb_push(rep_buf, sizeof(*rep_hdr)); 414 rep_hdr = (struct tipc_cfg_msg_hdr *)rep_buf->data; 415 memcpy(rep_hdr, req_hdr, sizeof(*rep_hdr)); 416 rep_hdr->tcm_len = htonl(rep_buf->len); 417 rep_hdr->tcm_flags &= htons(~TCM_F_REQUEST); 418 } else { 419 rep_buf = *buf; 420 *buf = NULL; 421 } 422 423 /* NEED TO ADD CODE TO HANDLE FAILED SEND (SUCH AS CONGESTION) */ 424 tipc_send_buf2port(port_ref, orig, rep_buf, rep_buf->len); 425} 426 427int tipc_cfg_init(void) 428{ 429 struct tipc_name_seq seq; 430 int res; 431 432 res = tipc_createport(NULL, TIPC_CRITICAL_IMPORTANCE, 433 NULL, NULL, NULL, 434 NULL, cfg_named_msg_event, NULL, 435 NULL, &config_port_ref); 436 if (res) 437 goto failed; 438 439 seq.type = TIPC_CFG_SRV; 440 seq.lower = seq.upper = tipc_own_addr; 441 res = tipc_publish(config_port_ref, TIPC_ZONE_SCOPE, &seq); 442 if (res) 443 goto failed; 444 445 return 0; 446 447failed: 448 pr_err("Unable to create configuration service\n"); 449 return res; 450} 451 452void tipc_cfg_reinit(void) 453{ 454 struct tipc_name_seq seq; 455 int res; 456 457 seq.type = TIPC_CFG_SRV; 458 seq.lower = seq.upper = 0; 459 tipc_withdraw(config_port_ref, TIPC_ZONE_SCOPE, &seq); 460 461 seq.lower = seq.upper = tipc_own_addr; 462 res = tipc_publish(config_port_ref, TIPC_ZONE_SCOPE, &seq); 463 if (res) 464 pr_err("Unable to reinitialize configuration service\n"); 465} 466 467void tipc_cfg_stop(void) 468{ 469 tipc_deleteport(config_port_ref); 470 config_port_ref = 0; 471} 472