config.c revision 5cbded585d129d0226cb48ac4202b253c781be26
1/* 2 * net/tipc/config.c: TIPC configuration management code 3 * 4 * Copyright (c) 2002-2006, Ericsson AB 5 * Copyright (c) 2004-2006, 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 "dbg.h" 39#include "bearer.h" 40#include "port.h" 41#include "link.h" 42#include "zone.h" 43#include "addr.h" 44#include "name_table.h" 45#include "node.h" 46#include "config.h" 47#include "discover.h" 48 49struct subscr_data { 50 char usr_handle[8]; 51 u32 domain; 52 u32 port_ref; 53 struct list_head subd_list; 54}; 55 56struct manager { 57 u32 user_ref; 58 u32 port_ref; 59 u32 subscr_ref; 60 u32 link_subscriptions; 61 struct list_head link_subscribers; 62}; 63 64static struct manager mng = { 0}; 65 66static DEFINE_SPINLOCK(config_lock); 67 68static const void *req_tlv_area; /* request message TLV area */ 69static int req_tlv_space; /* request message TLV area size */ 70static int rep_headroom; /* reply message headroom to use */ 71 72 73void tipc_cfg_link_event(u32 addr, char *name, int up) 74{ 75 /* TIPC DOESN'T HANDLE LINK EVENT SUBSCRIPTIONS AT THE MOMENT */ 76} 77 78 79struct sk_buff *tipc_cfg_reply_alloc(int payload_size) 80{ 81 struct sk_buff *buf; 82 83 buf = alloc_skb(rep_headroom + payload_size, GFP_ATOMIC); 84 if (buf) 85 skb_reserve(buf, rep_headroom); 86 return buf; 87} 88 89int tipc_cfg_append_tlv(struct sk_buff *buf, int tlv_type, 90 void *tlv_data, int tlv_data_size) 91{ 92 struct tlv_desc *tlv = (struct tlv_desc *)buf->tail; 93 int new_tlv_space = TLV_SPACE(tlv_data_size); 94 95 if (skb_tailroom(buf) < new_tlv_space) { 96 dbg("tipc_cfg_append_tlv unable to append TLV\n"); 97 return 0; 98 } 99 skb_put(buf, new_tlv_space); 100 tlv->tlv_type = htons(tlv_type); 101 tlv->tlv_len = htons(TLV_LENGTH(tlv_data_size)); 102 if (tlv_data_size && tlv_data) 103 memcpy(TLV_DATA(tlv), tlv_data, tlv_data_size); 104 return 1; 105} 106 107struct sk_buff *tipc_cfg_reply_unsigned_type(u16 tlv_type, u32 value) 108{ 109 struct sk_buff *buf; 110 __be32 value_net; 111 112 buf = tipc_cfg_reply_alloc(TLV_SPACE(sizeof(value))); 113 if (buf) { 114 value_net = htonl(value); 115 tipc_cfg_append_tlv(buf, tlv_type, &value_net, 116 sizeof(value_net)); 117 } 118 return buf; 119} 120 121struct sk_buff *tipc_cfg_reply_string_type(u16 tlv_type, char *string) 122{ 123 struct sk_buff *buf; 124 int string_len = strlen(string) + 1; 125 126 buf = tipc_cfg_reply_alloc(TLV_SPACE(string_len)); 127 if (buf) 128 tipc_cfg_append_tlv(buf, tlv_type, string, string_len); 129 return buf; 130} 131 132 133 134 135#if 0 136 137/* Now obsolete code for handling commands not yet implemented the new way */ 138 139int tipc_cfg_cmd(const struct tipc_cmd_msg * msg, 140 char *data, 141 u32 sz, 142 u32 *ret_size, 143 struct tipc_portid *orig) 144{ 145 int rv = -EINVAL; 146 u32 cmd = msg->cmd; 147 148 *ret_size = 0; 149 switch (cmd) { 150 case TIPC_REMOVE_LINK: 151 case TIPC_CMD_BLOCK_LINK: 152 case TIPC_CMD_UNBLOCK_LINK: 153 if (!cfg_check_connection(orig)) 154 rv = link_control(msg->argv.link_name, msg->cmd, 0); 155 break; 156 case TIPC_ESTABLISH: 157 { 158 int connected; 159 160 tipc_isconnected(mng.conn_port_ref, &connected); 161 if (connected || !orig) { 162 rv = TIPC_FAILURE; 163 break; 164 } 165 rv = tipc_connect2port(mng.conn_port_ref, orig); 166 if (rv == TIPC_OK) 167 orig = 0; 168 break; 169 } 170 case TIPC_GET_PEER_ADDRESS: 171 *ret_size = link_peer_addr(msg->argv.link_name, data, sz); 172 break; 173 case TIPC_GET_ROUTES: 174 rv = TIPC_OK; 175 break; 176 default: {} 177 } 178 if (*ret_size) 179 rv = TIPC_OK; 180 return rv; 181} 182 183static void cfg_cmd_event(struct tipc_cmd_msg *msg, 184 char *data, 185 u32 sz, 186 struct tipc_portid const *orig) 187{ 188 int rv = -EINVAL; 189 struct tipc_cmd_result_msg rmsg; 190 struct iovec msg_sect[2]; 191 int *arg; 192 193 msg->cmd = ntohl(msg->cmd); 194 195 cfg_prepare_res_msg(msg->cmd, msg->usr_handle, rv, &rmsg, msg_sect, 196 data, 0); 197 if (ntohl(msg->magic) != TIPC_MAGIC) 198 goto exit; 199 200 switch (msg->cmd) { 201 case TIPC_CREATE_LINK: 202 if (!cfg_check_connection(orig)) 203 rv = disc_create_link(&msg->argv.create_link); 204 break; 205 case TIPC_LINK_SUBSCRIBE: 206 { 207 struct subscr_data *sub; 208 209 if (mng.link_subscriptions > 64) 210 break; 211 sub = kmalloc(sizeof(*sub), 212 GFP_ATOMIC); 213 if (sub == NULL) { 214 warn("Memory squeeze; dropped remote link subscription\n"); 215 break; 216 } 217 INIT_LIST_HEAD(&sub->subd_list); 218 tipc_createport(mng.user_ref, 219 (void *)sub, 220 TIPC_HIGH_IMPORTANCE, 221 0, 222 0, 223 (tipc_conn_shutdown_event)cfg_linksubscr_cancel, 224 0, 225 0, 226 (tipc_conn_msg_event)cfg_linksubscr_cancel, 227 0, 228 &sub->port_ref); 229 if (!sub->port_ref) { 230 kfree(sub); 231 break; 232 } 233 memcpy(sub->usr_handle,msg->usr_handle, 234 sizeof(sub->usr_handle)); 235 sub->domain = msg->argv.domain; 236 list_add_tail(&sub->subd_list, &mng.link_subscribers); 237 tipc_connect2port(sub->port_ref, orig); 238 rmsg.retval = TIPC_OK; 239 tipc_send(sub->port_ref, 2u, msg_sect); 240 mng.link_subscriptions++; 241 return; 242 } 243 default: 244 rv = tipc_cfg_cmd(msg, data, sz, (u32 *)&msg_sect[1].iov_len, orig); 245 } 246 exit: 247 rmsg.result_len = htonl(msg_sect[1].iov_len); 248 rmsg.retval = htonl(rv); 249 tipc_cfg_respond(msg_sect, 2u, orig); 250} 251#endif 252 253static struct sk_buff *cfg_enable_bearer(void) 254{ 255 struct tipc_bearer_config *args; 256 257 if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_BEARER_CONFIG)) 258 return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR); 259 260 args = (struct tipc_bearer_config *)TLV_DATA(req_tlv_area); 261 if (tipc_enable_bearer(args->name, 262 ntohl(args->detect_scope), 263 ntohl(args->priority))) 264 return tipc_cfg_reply_error_string("unable to enable bearer"); 265 266 return tipc_cfg_reply_none(); 267} 268 269static struct sk_buff *cfg_disable_bearer(void) 270{ 271 if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_BEARER_NAME)) 272 return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR); 273 274 if (tipc_disable_bearer((char *)TLV_DATA(req_tlv_area))) 275 return tipc_cfg_reply_error_string("unable to disable bearer"); 276 277 return tipc_cfg_reply_none(); 278} 279 280static struct sk_buff *cfg_set_own_addr(void) 281{ 282 u32 addr; 283 284 if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_NET_ADDR)) 285 return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR); 286 287 addr = ntohl(*(__be32 *)TLV_DATA(req_tlv_area)); 288 if (addr == tipc_own_addr) 289 return tipc_cfg_reply_none(); 290 if (!tipc_addr_node_valid(addr)) 291 return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE 292 " (node address)"); 293 if (tipc_mode == TIPC_NET_MODE) 294 return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED 295 " (cannot change node address once assigned)"); 296 tipc_own_addr = addr; 297 298 /* 299 * Must release all spinlocks before calling start_net() because 300 * Linux version of TIPC calls eth_media_start() which calls 301 * register_netdevice_notifier() which may block! 302 * 303 * Temporarily releasing the lock should be harmless for non-Linux TIPC, 304 * but Linux version of eth_media_start() should really be reworked 305 * so that it can be called with spinlocks held. 306 */ 307 308 spin_unlock_bh(&config_lock); 309 tipc_core_start_net(); 310 spin_lock_bh(&config_lock); 311 return tipc_cfg_reply_none(); 312} 313 314static struct sk_buff *cfg_set_remote_mng(void) 315{ 316 u32 value; 317 318 if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED)) 319 return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR); 320 321 value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area)); 322 tipc_remote_management = (value != 0); 323 return tipc_cfg_reply_none(); 324} 325 326static struct sk_buff *cfg_set_max_publications(void) 327{ 328 u32 value; 329 330 if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED)) 331 return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR); 332 333 value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area)); 334 if (value != delimit(value, 1, 65535)) 335 return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE 336 " (max publications must be 1-65535)"); 337 tipc_max_publications = value; 338 return tipc_cfg_reply_none(); 339} 340 341static struct sk_buff *cfg_set_max_subscriptions(void) 342{ 343 u32 value; 344 345 if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED)) 346 return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR); 347 348 value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area)); 349 if (value != delimit(value, 1, 65535)) 350 return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE 351 " (max subscriptions must be 1-65535"); 352 tipc_max_subscriptions = value; 353 return tipc_cfg_reply_none(); 354} 355 356static struct sk_buff *cfg_set_max_ports(void) 357{ 358 u32 value; 359 360 if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED)) 361 return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR); 362 value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area)); 363 if (value == tipc_max_ports) 364 return tipc_cfg_reply_none(); 365 if (value != delimit(value, 127, 65535)) 366 return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE 367 " (max ports must be 127-65535)"); 368 if (tipc_mode != TIPC_NOT_RUNNING) 369 return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED 370 " (cannot change max ports while TIPC is active)"); 371 tipc_max_ports = value; 372 return tipc_cfg_reply_none(); 373} 374 375static struct sk_buff *cfg_set_max_zones(void) 376{ 377 u32 value; 378 379 if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED)) 380 return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR); 381 value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area)); 382 if (value == tipc_max_zones) 383 return tipc_cfg_reply_none(); 384 if (value != delimit(value, 1, 255)) 385 return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE 386 " (max zones must be 1-255)"); 387 if (tipc_mode == TIPC_NET_MODE) 388 return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED 389 " (cannot change max zones once TIPC has joined a network)"); 390 tipc_max_zones = value; 391 return tipc_cfg_reply_none(); 392} 393 394static struct sk_buff *cfg_set_max_clusters(void) 395{ 396 u32 value; 397 398 if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED)) 399 return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR); 400 value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area)); 401 if (value != delimit(value, 1, 1)) 402 return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE 403 " (max clusters fixed at 1)"); 404 return tipc_cfg_reply_none(); 405} 406 407static struct sk_buff *cfg_set_max_nodes(void) 408{ 409 u32 value; 410 411 if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED)) 412 return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR); 413 value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area)); 414 if (value == tipc_max_nodes) 415 return tipc_cfg_reply_none(); 416 if (value != delimit(value, 8, 2047)) 417 return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE 418 " (max nodes must be 8-2047)"); 419 if (tipc_mode == TIPC_NET_MODE) 420 return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED 421 " (cannot change max nodes once TIPC has joined a network)"); 422 tipc_max_nodes = value; 423 return tipc_cfg_reply_none(); 424} 425 426static struct sk_buff *cfg_set_max_slaves(void) 427{ 428 u32 value; 429 430 if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED)) 431 return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR); 432 value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area)); 433 if (value != 0) 434 return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED 435 " (max secondary nodes fixed at 0)"); 436 return tipc_cfg_reply_none(); 437} 438 439static struct sk_buff *cfg_set_netid(void) 440{ 441 u32 value; 442 443 if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED)) 444 return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR); 445 value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area)); 446 if (value == tipc_net_id) 447 return tipc_cfg_reply_none(); 448 if (value != delimit(value, 1, 9999)) 449 return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE 450 " (network id must be 1-9999)"); 451 if (tipc_mode == TIPC_NET_MODE) 452 return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED 453 " (cannot change network id once TIPC has joined a network)"); 454 tipc_net_id = value; 455 return tipc_cfg_reply_none(); 456} 457 458struct sk_buff *tipc_cfg_do_cmd(u32 orig_node, u16 cmd, const void *request_area, 459 int request_space, int reply_headroom) 460{ 461 struct sk_buff *rep_tlv_buf; 462 463 spin_lock_bh(&config_lock); 464 465 /* Save request and reply details in a well-known location */ 466 467 req_tlv_area = request_area; 468 req_tlv_space = request_space; 469 rep_headroom = reply_headroom; 470 471 /* Check command authorization */ 472 473 if (likely(orig_node == tipc_own_addr)) { 474 /* command is permitted */ 475 } else if (cmd >= 0x8000) { 476 rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED 477 " (cannot be done remotely)"); 478 goto exit; 479 } else if (!tipc_remote_management) { 480 rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NO_REMOTE); 481 goto exit; 482 } 483 else if (cmd >= 0x4000) { 484 u32 domain = 0; 485 486 if ((tipc_nametbl_translate(TIPC_ZM_SRV, 0, &domain) == 0) || 487 (domain != orig_node)) { 488 rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NOT_ZONE_MSTR); 489 goto exit; 490 } 491 } 492 493 /* Call appropriate processing routine */ 494 495 switch (cmd) { 496 case TIPC_CMD_NOOP: 497 rep_tlv_buf = tipc_cfg_reply_none(); 498 break; 499 case TIPC_CMD_GET_NODES: 500 rep_tlv_buf = tipc_node_get_nodes(req_tlv_area, req_tlv_space); 501 break; 502 case TIPC_CMD_GET_LINKS: 503 rep_tlv_buf = tipc_node_get_links(req_tlv_area, req_tlv_space); 504 break; 505 case TIPC_CMD_SHOW_LINK_STATS: 506 rep_tlv_buf = tipc_link_cmd_show_stats(req_tlv_area, req_tlv_space); 507 break; 508 case TIPC_CMD_RESET_LINK_STATS: 509 rep_tlv_buf = tipc_link_cmd_reset_stats(req_tlv_area, req_tlv_space); 510 break; 511 case TIPC_CMD_SHOW_NAME_TABLE: 512 rep_tlv_buf = tipc_nametbl_get(req_tlv_area, req_tlv_space); 513 break; 514 case TIPC_CMD_GET_BEARER_NAMES: 515 rep_tlv_buf = tipc_bearer_get_names(); 516 break; 517 case TIPC_CMD_GET_MEDIA_NAMES: 518 rep_tlv_buf = tipc_media_get_names(); 519 break; 520 case TIPC_CMD_SHOW_PORTS: 521 rep_tlv_buf = tipc_port_get_ports(); 522 break; 523#if 0 524 case TIPC_CMD_SHOW_PORT_STATS: 525 rep_tlv_buf = port_show_stats(req_tlv_area, req_tlv_space); 526 break; 527 case TIPC_CMD_RESET_PORT_STATS: 528 rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED); 529 break; 530#endif 531 case TIPC_CMD_SET_LOG_SIZE: 532 rep_tlv_buf = tipc_log_resize(req_tlv_area, req_tlv_space); 533 break; 534 case TIPC_CMD_DUMP_LOG: 535 rep_tlv_buf = tipc_log_dump(); 536 break; 537 case TIPC_CMD_SET_LINK_TOL: 538 case TIPC_CMD_SET_LINK_PRI: 539 case TIPC_CMD_SET_LINK_WINDOW: 540 rep_tlv_buf = tipc_link_cmd_config(req_tlv_area, req_tlv_space, cmd); 541 break; 542 case TIPC_CMD_ENABLE_BEARER: 543 rep_tlv_buf = cfg_enable_bearer(); 544 break; 545 case TIPC_CMD_DISABLE_BEARER: 546 rep_tlv_buf = cfg_disable_bearer(); 547 break; 548 case TIPC_CMD_SET_NODE_ADDR: 549 rep_tlv_buf = cfg_set_own_addr(); 550 break; 551 case TIPC_CMD_SET_REMOTE_MNG: 552 rep_tlv_buf = cfg_set_remote_mng(); 553 break; 554 case TIPC_CMD_SET_MAX_PORTS: 555 rep_tlv_buf = cfg_set_max_ports(); 556 break; 557 case TIPC_CMD_SET_MAX_PUBL: 558 rep_tlv_buf = cfg_set_max_publications(); 559 break; 560 case TIPC_CMD_SET_MAX_SUBSCR: 561 rep_tlv_buf = cfg_set_max_subscriptions(); 562 break; 563 case TIPC_CMD_SET_MAX_ZONES: 564 rep_tlv_buf = cfg_set_max_zones(); 565 break; 566 case TIPC_CMD_SET_MAX_CLUSTERS: 567 rep_tlv_buf = cfg_set_max_clusters(); 568 break; 569 case TIPC_CMD_SET_MAX_NODES: 570 rep_tlv_buf = cfg_set_max_nodes(); 571 break; 572 case TIPC_CMD_SET_MAX_SLAVES: 573 rep_tlv_buf = cfg_set_max_slaves(); 574 break; 575 case TIPC_CMD_SET_NETID: 576 rep_tlv_buf = cfg_set_netid(); 577 break; 578 case TIPC_CMD_GET_REMOTE_MNG: 579 rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_remote_management); 580 break; 581 case TIPC_CMD_GET_MAX_PORTS: 582 rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_max_ports); 583 break; 584 case TIPC_CMD_GET_MAX_PUBL: 585 rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_max_publications); 586 break; 587 case TIPC_CMD_GET_MAX_SUBSCR: 588 rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_max_subscriptions); 589 break; 590 case TIPC_CMD_GET_MAX_ZONES: 591 rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_max_zones); 592 break; 593 case TIPC_CMD_GET_MAX_CLUSTERS: 594 rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_max_clusters); 595 break; 596 case TIPC_CMD_GET_MAX_NODES: 597 rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_max_nodes); 598 break; 599 case TIPC_CMD_GET_MAX_SLAVES: 600 rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_max_slaves); 601 break; 602 case TIPC_CMD_GET_NETID: 603 rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_net_id); 604 break; 605 default: 606 rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED 607 " (unknown command)"); 608 break; 609 } 610 611 /* Return reply buffer */ 612exit: 613 spin_unlock_bh(&config_lock); 614 return rep_tlv_buf; 615} 616 617static void cfg_named_msg_event(void *userdata, 618 u32 port_ref, 619 struct sk_buff **buf, 620 const unchar *msg, 621 u32 size, 622 u32 importance, 623 struct tipc_portid const *orig, 624 struct tipc_name_seq const *dest) 625{ 626 struct tipc_cfg_msg_hdr *req_hdr; 627 struct tipc_cfg_msg_hdr *rep_hdr; 628 struct sk_buff *rep_buf; 629 630 /* Validate configuration message header (ignore invalid message) */ 631 632 req_hdr = (struct tipc_cfg_msg_hdr *)msg; 633 if ((size < sizeof(*req_hdr)) || 634 (size != TCM_ALIGN(ntohl(req_hdr->tcm_len))) || 635 (ntohs(req_hdr->tcm_flags) != TCM_F_REQUEST)) { 636 warn("Invalid configuration message discarded\n"); 637 return; 638 } 639 640 /* Generate reply for request (if can't, return request) */ 641 642 rep_buf = tipc_cfg_do_cmd(orig->node, 643 ntohs(req_hdr->tcm_type), 644 msg + sizeof(*req_hdr), 645 size - sizeof(*req_hdr), 646 BUF_HEADROOM + MAX_H_SIZE + sizeof(*rep_hdr)); 647 if (rep_buf) { 648 skb_push(rep_buf, sizeof(*rep_hdr)); 649 rep_hdr = (struct tipc_cfg_msg_hdr *)rep_buf->data; 650 memcpy(rep_hdr, req_hdr, sizeof(*rep_hdr)); 651 rep_hdr->tcm_len = htonl(rep_buf->len); 652 rep_hdr->tcm_flags &= htons(~TCM_F_REQUEST); 653 } else { 654 rep_buf = *buf; 655 *buf = NULL; 656 } 657 658 /* NEED TO ADD CODE TO HANDLE FAILED SEND (SUCH AS CONGESTION) */ 659 tipc_send_buf2port(port_ref, orig, rep_buf, rep_buf->len); 660} 661 662int tipc_cfg_init(void) 663{ 664 struct tipc_name_seq seq; 665 int res; 666 667 memset(&mng, 0, sizeof(mng)); 668 INIT_LIST_HEAD(&mng.link_subscribers); 669 670 res = tipc_attach(&mng.user_ref, NULL, NULL); 671 if (res) 672 goto failed; 673 674 res = tipc_createport(mng.user_ref, NULL, TIPC_CRITICAL_IMPORTANCE, 675 NULL, NULL, NULL, 676 NULL, cfg_named_msg_event, NULL, 677 NULL, &mng.port_ref); 678 if (res) 679 goto failed; 680 681 seq.type = TIPC_CFG_SRV; 682 seq.lower = seq.upper = tipc_own_addr; 683 res = tipc_nametbl_publish_rsv(mng.port_ref, TIPC_ZONE_SCOPE, &seq); 684 if (res) 685 goto failed; 686 687 return 0; 688 689failed: 690 err("Unable to create configuration service\n"); 691 tipc_detach(mng.user_ref); 692 mng.user_ref = 0; 693 return res; 694} 695 696void tipc_cfg_stop(void) 697{ 698 if (mng.user_ref) { 699 tipc_detach(mng.user_ref); 700 mng.user_ref = 0; 701 } 702} 703