linux/net/tipc/config.c
<<
>>
Prefs
   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
 135        str_len = tipc_printbuf_validate(&pb);
 136        skb_put(buf, TLV_SPACE(str_len));
 137        TLV_SET(rep_tlv, TIPC_TLV_ULTRA_STRING, NULL, str_len);
 138
 139        return buf;
 140}
 141
 142static struct sk_buff *cfg_enable_bearer(void)
 143{
 144        struct tipc_bearer_config *args;
 145
 146        if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_BEARER_CONFIG))
 147                return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
 148
 149        args = (struct tipc_bearer_config *)TLV_DATA(req_tlv_area);
 150        if (tipc_enable_bearer(args->name,
 151                               ntohl(args->disc_domain),
 152                               ntohl(args->priority)))
 153                return tipc_cfg_reply_error_string("unable to enable bearer");
 154
 155        return tipc_cfg_reply_none();
 156}
 157
 158static struct sk_buff *cfg_disable_bearer(void)
 159{
 160        if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_BEARER_NAME))
 161                return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
 162
 163        if (tipc_disable_bearer((char *)TLV_DATA(req_tlv_area)))
 164                return tipc_cfg_reply_error_string("unable to disable bearer");
 165
 166        return tipc_cfg_reply_none();
 167}
 168
 169static struct sk_buff *cfg_set_own_addr(void)
 170{
 171        u32 addr;
 172
 173        if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_NET_ADDR))
 174                return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
 175
 176        addr = ntohl(*(__be32 *)TLV_DATA(req_tlv_area));
 177        if (addr == tipc_own_addr)
 178                return tipc_cfg_reply_none();
 179        if (!tipc_addr_node_valid(addr))
 180                return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
 181                                                   " (node address)");
 182        if (tipc_mode == TIPC_NET_MODE)
 183                return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
 184                                                   " (cannot change node address once assigned)");
 185
 186        /*
 187         * Must temporarily release configuration spinlock while switching into
 188         * networking mode as it calls tipc_eth_media_start(), which may sleep.
 189         * Releasing the lock is harmless as other locally-issued configuration
 190         * commands won't occur until this one completes, and remotely-issued
 191         * configuration commands can't be received until a local configuration
 192         * command to enable the first bearer is received and processed.
 193         */
 194
 195        spin_unlock_bh(&config_lock);
 196        tipc_core_start_net(addr);
 197        spin_lock_bh(&config_lock);
 198        return tipc_cfg_reply_none();
 199}
 200
 201static struct sk_buff *cfg_set_remote_mng(void)
 202{
 203        u32 value;
 204
 205        if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
 206                return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
 207
 208        value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area));
 209        tipc_remote_management = (value != 0);
 210        return tipc_cfg_reply_none();
 211}
 212
 213static struct sk_buff *cfg_set_max_publications(void)
 214{
 215        u32 value;
 216
 217        if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
 218                return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
 219
 220        value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area));
 221        if (value != delimit(value, 1, 65535))
 222                return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
 223                                                   " (max publications must be 1-65535)");
 224        tipc_max_publications = value;
 225        return tipc_cfg_reply_none();
 226}
 227
 228static struct sk_buff *cfg_set_max_subscriptions(void)
 229{
 230        u32 value;
 231
 232        if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
 233                return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
 234
 235        value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area));
 236        if (value != delimit(value, 1, 65535))
 237                return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
 238                                                   " (max subscriptions must be 1-65535");
 239        tipc_max_subscriptions = value;
 240        return tipc_cfg_reply_none();
 241}
 242
 243static struct sk_buff *cfg_set_max_ports(void)
 244{
 245        u32 value;
 246
 247        if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
 248                return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
 249        value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area));
 250        if (value == tipc_max_ports)
 251                return tipc_cfg_reply_none();
 252        if (value != delimit(value, 127, 65535))
 253                return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
 254                                                   " (max ports must be 127-65535)");
 255        if (tipc_mode != TIPC_NOT_RUNNING)
 256                return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
 257                        " (cannot change max ports while TIPC is active)");
 258        tipc_max_ports = value;
 259        return tipc_cfg_reply_none();
 260}
 261
 262static struct sk_buff *cfg_set_netid(void)
 263{
 264        u32 value;
 265
 266        if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
 267                return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
 268        value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area));
 269        if (value == tipc_net_id)
 270                return tipc_cfg_reply_none();
 271        if (value != delimit(value, 1, 9999))
 272                return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
 273                                                   " (network id must be 1-9999)");
 274        if (tipc_mode == TIPC_NET_MODE)
 275                return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
 276                        " (cannot change network id once TIPC has joined a network)");
 277        tipc_net_id = value;
 278        return tipc_cfg_reply_none();
 279}
 280
 281struct sk_buff *tipc_cfg_do_cmd(u32 orig_node, u16 cmd, const void *request_area,
 282                                int request_space, int reply_headroom)
 283{
 284        struct sk_buff *rep_tlv_buf;
 285
 286        spin_lock_bh(&config_lock);
 287
 288        /* Save request and reply details in a well-known location */
 289
 290        req_tlv_area = request_area;
 291        req_tlv_space = request_space;
 292        rep_headroom = reply_headroom;
 293
 294        /* Check command authorization */
 295
 296        if (likely(orig_node == tipc_own_addr)) {
 297                /* command is permitted */
 298        } else if (cmd >= 0x8000) {
 299                rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
 300                                                          " (cannot be done remotely)");
 301                goto exit;
 302        } else if (!tipc_remote_management) {
 303                rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NO_REMOTE);
 304                goto exit;
 305        } else if (cmd >= 0x4000) {
 306                u32 domain = 0;
 307
 308                if ((tipc_nametbl_translate(TIPC_ZM_SRV, 0, &domain) == 0) ||
 309                    (domain != orig_node)) {
 310                        rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NOT_ZONE_MSTR);
 311                        goto exit;
 312                }
 313        }
 314
 315        /* Call appropriate processing routine */
 316
 317        switch (cmd) {
 318        case TIPC_CMD_NOOP:
 319                rep_tlv_buf = tipc_cfg_reply_none();
 320                break;
 321        case TIPC_CMD_GET_NODES:
 322                rep_tlv_buf = tipc_node_get_nodes(req_tlv_area, req_tlv_space);
 323                break;
 324        case TIPC_CMD_GET_LINKS:
 325                rep_tlv_buf = tipc_node_get_links(req_tlv_area, req_tlv_space);
 326                break;
 327        case TIPC_CMD_SHOW_LINK_STATS:
 328                rep_tlv_buf = tipc_link_cmd_show_stats(req_tlv_area, req_tlv_space);
 329                break;
 330        case TIPC_CMD_RESET_LINK_STATS:
 331                rep_tlv_buf = tipc_link_cmd_reset_stats(req_tlv_area, req_tlv_space);
 332                break;
 333        case TIPC_CMD_SHOW_NAME_TABLE:
 334                rep_tlv_buf = tipc_nametbl_get(req_tlv_area, req_tlv_space);
 335                break;
 336        case TIPC_CMD_GET_BEARER_NAMES:
 337                rep_tlv_buf = tipc_bearer_get_names();
 338                break;
 339        case TIPC_CMD_GET_MEDIA_NAMES:
 340                rep_tlv_buf = tipc_media_get_names();
 341                break;
 342        case TIPC_CMD_SHOW_PORTS:
 343                rep_tlv_buf = tipc_port_get_ports();
 344                break;
 345        case TIPC_CMD_SET_LOG_SIZE:
 346                rep_tlv_buf = tipc_log_resize_cmd(req_tlv_area, req_tlv_space);
 347                break;
 348        case TIPC_CMD_DUMP_LOG:
 349                rep_tlv_buf = tipc_log_dump();
 350                break;
 351        case TIPC_CMD_SHOW_STATS:
 352                rep_tlv_buf = tipc_show_stats();
 353                break;
 354        case TIPC_CMD_SET_LINK_TOL:
 355        case TIPC_CMD_SET_LINK_PRI:
 356        case TIPC_CMD_SET_LINK_WINDOW:
 357                rep_tlv_buf = tipc_link_cmd_config(req_tlv_area, req_tlv_space, cmd);
 358                break;
 359        case TIPC_CMD_ENABLE_BEARER:
 360                rep_tlv_buf = cfg_enable_bearer();
 361                break;
 362        case TIPC_CMD_DISABLE_BEARER:
 363                rep_tlv_buf = cfg_disable_bearer();
 364                break;
 365        case TIPC_CMD_SET_NODE_ADDR:
 366                rep_tlv_buf = cfg_set_own_addr();
 367                break;
 368        case TIPC_CMD_SET_REMOTE_MNG:
 369                rep_tlv_buf = cfg_set_remote_mng();
 370                break;
 371        case TIPC_CMD_SET_MAX_PORTS:
 372                rep_tlv_buf = cfg_set_max_ports();
 373                break;
 374        case TIPC_CMD_SET_MAX_PUBL:
 375                rep_tlv_buf = cfg_set_max_publications();
 376                break;
 377        case TIPC_CMD_SET_MAX_SUBSCR:
 378                rep_tlv_buf = cfg_set_max_subscriptions();
 379                break;
 380        case TIPC_CMD_SET_NETID:
 381                rep_tlv_buf = cfg_set_netid();
 382                break;
 383        case TIPC_CMD_GET_REMOTE_MNG:
 384                rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_remote_management);
 385                break;
 386        case TIPC_CMD_GET_MAX_PORTS:
 387                rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_max_ports);
 388                break;
 389        case TIPC_CMD_GET_MAX_PUBL:
 390                rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_max_publications);
 391                break;
 392        case TIPC_CMD_GET_MAX_SUBSCR:
 393                rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_max_subscriptions);
 394                break;
 395        case TIPC_CMD_GET_NETID:
 396                rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_net_id);
 397                break;
 398        case TIPC_CMD_NOT_NET_ADMIN:
 399                rep_tlv_buf =
 400                        tipc_cfg_reply_error_string(TIPC_CFG_NOT_NET_ADMIN);
 401                break;
 402        case TIPC_CMD_SET_MAX_ZONES:
 403        case TIPC_CMD_GET_MAX_ZONES:
 404        case TIPC_CMD_SET_MAX_SLAVES:
 405        case TIPC_CMD_GET_MAX_SLAVES:
 406        case TIPC_CMD_SET_MAX_CLUSTERS:
 407        case TIPC_CMD_GET_MAX_CLUSTERS:
 408        case TIPC_CMD_SET_MAX_NODES:
 409        case TIPC_CMD_GET_MAX_NODES:
 410                rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
 411                                                          " (obsolete command)");
 412                break;
 413        default:
 414                rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
 415                                                          " (unknown command)");
 416                break;
 417        }
 418
 419        /* Return reply buffer */
 420exit:
 421        spin_unlock_bh(&config_lock);
 422        return rep_tlv_buf;
 423}
 424
 425static void cfg_named_msg_event(void *userdata,
 426                                u32 port_ref,
 427                                struct sk_buff **buf,
 428                                const unchar *msg,
 429                                u32 size,
 430                                u32 importance,
 431                                struct tipc_portid const *orig,
 432                                struct tipc_name_seq const *dest)
 433{
 434        struct tipc_cfg_msg_hdr *req_hdr;
 435        struct tipc_cfg_msg_hdr *rep_hdr;
 436        struct sk_buff *rep_buf;
 437
 438        /* Validate configuration message header (ignore invalid message) */
 439
 440        req_hdr = (struct tipc_cfg_msg_hdr *)msg;
 441        if ((size < sizeof(*req_hdr)) ||
 442            (size != TCM_ALIGN(ntohl(req_hdr->tcm_len))) ||
 443            (ntohs(req_hdr->tcm_flags) != TCM_F_REQUEST)) {
 444                warn("Invalid configuration message discarded\n");
 445                return;
 446        }
 447
 448        /* Generate reply for request (if can't, return request) */
 449
 450        rep_buf = tipc_cfg_do_cmd(orig->node,
 451                                  ntohs(req_hdr->tcm_type),
 452                                  msg + sizeof(*req_hdr),
 453                                  size - sizeof(*req_hdr),
 454                                  BUF_HEADROOM + MAX_H_SIZE + sizeof(*rep_hdr));
 455        if (rep_buf) {
 456                skb_push(rep_buf, sizeof(*rep_hdr));
 457                rep_hdr = (struct tipc_cfg_msg_hdr *)rep_buf->data;
 458                memcpy(rep_hdr, req_hdr, sizeof(*rep_hdr));
 459                rep_hdr->tcm_len = htonl(rep_buf->len);
 460                rep_hdr->tcm_flags &= htons(~TCM_F_REQUEST);
 461        } else {
 462                rep_buf = *buf;
 463                *buf = NULL;
 464        }
 465
 466        /* NEED TO ADD CODE TO HANDLE FAILED SEND (SUCH AS CONGESTION) */
 467        tipc_send_buf2port(port_ref, orig, rep_buf, rep_buf->len);
 468}
 469
 470int tipc_cfg_init(void)
 471{
 472        struct tipc_name_seq seq;
 473        int res;
 474
 475        res = tipc_createport(NULL, TIPC_CRITICAL_IMPORTANCE,
 476                              NULL, NULL, NULL,
 477                              NULL, cfg_named_msg_event, NULL,
 478                              NULL, &config_port_ref);
 479        if (res)
 480                goto failed;
 481
 482        seq.type = TIPC_CFG_SRV;
 483        seq.lower = seq.upper = tipc_own_addr;
 484        res = tipc_nametbl_publish_rsv(config_port_ref, TIPC_ZONE_SCOPE, &seq);
 485        if (res)
 486                goto failed;
 487
 488        return 0;
 489
 490failed:
 491        err("Unable to create configuration service\n");
 492        return res;
 493}
 494
 495void tipc_cfg_stop(void)
 496{
 497        if (config_port_ref) {
 498                tipc_deleteport(config_port_ref);
 499                config_port_ref = 0;
 500        }
 501}
 502