linux/net/tipc/discover.c
<<
>>
Prefs
   1/*
   2 * net/tipc/discover.c
   3 *
   4 * Copyright (c) 2003-2006, Ericsson AB
   5 * Copyright (c) 2005-2006, 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 "link.h"
  39#include "discover.h"
  40
  41#define TIPC_LINK_REQ_INIT      125     /* min delay during bearer start up */
  42#define TIPC_LINK_REQ_FAST      1000    /* max delay if bearer has no links */
  43#define TIPC_LINK_REQ_SLOW      60000   /* max delay if bearer has links */
  44#define TIPC_LINK_REQ_INACTIVE  0xffffffff /* indicates no timer in use */
  45
  46
  47/**
  48 * struct tipc_link_req - information about an ongoing link setup request
  49 * @bearer: bearer issuing requests
  50 * @dest: destination address for request messages
  51 * @domain: network domain to which links can be established
  52 * @num_nodes: number of nodes currently discovered (i.e. with an active link)
  53 * @buf: request message to be (repeatedly) sent
  54 * @timer: timer governing period between requests
  55 * @timer_intv: current interval between requests (in ms)
  56 */
  57struct tipc_link_req {
  58        struct tipc_bearer *bearer;
  59        struct tipc_media_addr dest;
  60        u32 domain;
  61        int num_nodes;
  62        struct sk_buff *buf;
  63        struct timer_list timer;
  64        unsigned int timer_intv;
  65};
  66
  67/**
  68 * tipc_disc_init_msg - initialize a link setup message
  69 * @type: message type (request or response)
  70 * @dest_domain: network domain of node(s) which should respond to message
  71 * @b_ptr: ptr to bearer issuing message
  72 */
  73static struct sk_buff *tipc_disc_init_msg(u32 type,
  74                                          u32 dest_domain,
  75                                          struct tipc_bearer *b_ptr)
  76{
  77        struct sk_buff *buf = tipc_buf_acquire(INT_H_SIZE);
  78        struct tipc_msg *msg;
  79
  80        if (buf) {
  81                msg = buf_msg(buf);
  82                tipc_msg_init(msg, LINK_CONFIG, type, INT_H_SIZE, dest_domain);
  83                msg_set_non_seq(msg, 1);
  84                msg_set_node_sig(msg, tipc_random);
  85                msg_set_dest_domain(msg, dest_domain);
  86                msg_set_bc_netid(msg, tipc_net_id);
  87                b_ptr->media->addr2msg(&b_ptr->addr, msg_media_addr(msg));
  88        }
  89        return buf;
  90}
  91
  92/**
  93 * disc_dupl_alert - issue node address duplication alert
  94 * @b_ptr: pointer to bearer detecting duplication
  95 * @node_addr: duplicated node address
  96 * @media_addr: media address advertised by duplicated node
  97 */
  98static void disc_dupl_alert(struct tipc_bearer *b_ptr, u32 node_addr,
  99                            struct tipc_media_addr *media_addr)
 100{
 101        char node_addr_str[16];
 102        char media_addr_str[64];
 103
 104        tipc_addr_string_fill(node_addr_str, node_addr);
 105        tipc_media_addr_printf(media_addr_str, sizeof(media_addr_str),
 106                               media_addr);
 107        pr_warn("Duplicate %s using %s seen on <%s>\n", node_addr_str,
 108                media_addr_str, b_ptr->name);
 109}
 110
 111/**
 112 * tipc_disc_recv_msg - handle incoming link setup message (request or response)
 113 * @buf: buffer containing message
 114 * @b_ptr: bearer that message arrived on
 115 */
 116void tipc_disc_recv_msg(struct sk_buff *buf, struct tipc_bearer *b_ptr)
 117{
 118        struct tipc_node *n_ptr;
 119        struct tipc_link *link;
 120        struct tipc_media_addr media_addr;
 121        struct sk_buff *rbuf;
 122        struct tipc_msg *msg = buf_msg(buf);
 123        u32 dest = msg_dest_domain(msg);
 124        u32 orig = msg_prevnode(msg);
 125        u32 net_id = msg_bc_netid(msg);
 126        u32 type = msg_type(msg);
 127        u32 signature = msg_node_sig(msg);
 128        int addr_mismatch;
 129        int link_fully_up;
 130
 131        media_addr.broadcast = 1;
 132        b_ptr->media->msg2addr(b_ptr, &media_addr, msg_media_addr(msg));
 133        kfree_skb(buf);
 134
 135        /* Ensure message from node is valid and communication is permitted */
 136        if (net_id != tipc_net_id)
 137                return;
 138        if (media_addr.broadcast)
 139                return;
 140        if (!tipc_addr_domain_valid(dest))
 141                return;
 142        if (!tipc_addr_node_valid(orig))
 143                return;
 144        if (orig == tipc_own_addr) {
 145                if (memcmp(&media_addr, &b_ptr->addr, sizeof(media_addr)))
 146                        disc_dupl_alert(b_ptr, tipc_own_addr, &media_addr);
 147                return;
 148        }
 149        if (!tipc_in_scope(dest, tipc_own_addr))
 150                return;
 151        if (!tipc_in_scope(b_ptr->link_req->domain, orig))
 152                return;
 153
 154        /* Locate structure corresponding to requesting node */
 155        n_ptr = tipc_node_find(orig);
 156        if (!n_ptr) {
 157                n_ptr = tipc_node_create(orig);
 158                if (!n_ptr)
 159                        return;
 160        }
 161        tipc_node_lock(n_ptr);
 162
 163        /* Prepare to validate requesting node's signature and media address */
 164        link = n_ptr->links[b_ptr->identity];
 165        addr_mismatch = (link != NULL) &&
 166                memcmp(&link->media_addr, &media_addr, sizeof(media_addr));
 167
 168        /*
 169         * Ensure discovery message's signature is correct
 170         *
 171         * If signature is incorrect and there is no working link to the node,
 172         * accept the new signature but invalidate all existing links to the
 173         * node so they won't re-activate without a new discovery message.
 174         *
 175         * If signature is incorrect and the requested link to the node is
 176         * working, accept the new signature. (This is an instance of delayed
 177         * rediscovery, where a link endpoint was able to re-establish contact
 178         * with its peer endpoint on a node that rebooted before receiving a
 179         * discovery message from that node.)
 180         *
 181         * If signature is incorrect and there is a working link to the node
 182         * that is not the requested link, reject the request (must be from
 183         * a duplicate node).
 184         */
 185        if (signature != n_ptr->signature) {
 186                if (n_ptr->working_links == 0) {
 187                        struct tipc_link *curr_link;
 188                        int i;
 189
 190                        for (i = 0; i < MAX_BEARERS; i++) {
 191                                curr_link = n_ptr->links[i];
 192                                if (curr_link) {
 193                                        memset(&curr_link->media_addr, 0,
 194                                               sizeof(media_addr));
 195                                        tipc_link_reset(curr_link);
 196                                }
 197                        }
 198                        addr_mismatch = (link != NULL);
 199                } else if (tipc_link_is_up(link) && !addr_mismatch) {
 200                        /* delayed rediscovery */
 201                } else {
 202                        disc_dupl_alert(b_ptr, orig, &media_addr);
 203                        tipc_node_unlock(n_ptr);
 204                        return;
 205                }
 206                n_ptr->signature = signature;
 207        }
 208
 209        /*
 210         * Ensure requesting node's media address is correct
 211         *
 212         * If media address doesn't match and the link is working, reject the
 213         * request (must be from a duplicate node).
 214         *
 215         * If media address doesn't match and the link is not working, accept
 216         * the new media address and reset the link to ensure it starts up
 217         * cleanly.
 218         */
 219        if (addr_mismatch) {
 220                if (tipc_link_is_up(link)) {
 221                        disc_dupl_alert(b_ptr, orig, &media_addr);
 222                        tipc_node_unlock(n_ptr);
 223                        return;
 224                } else {
 225                        memcpy(&link->media_addr, &media_addr,
 226                               sizeof(media_addr));
 227                        tipc_link_reset(link);
 228                }
 229        }
 230
 231        /* Create a link endpoint for this bearer, if necessary */
 232        if (!link) {
 233                link = tipc_link_create(n_ptr, b_ptr, &media_addr);
 234                if (!link) {
 235                        tipc_node_unlock(n_ptr);
 236                        return;
 237                }
 238        }
 239
 240        /* Accept discovery message & send response, if necessary */
 241        link_fully_up = link_working_working(link);
 242
 243        if ((type == DSC_REQ_MSG) && !link_fully_up && !b_ptr->blocked) {
 244                rbuf = tipc_disc_init_msg(DSC_RESP_MSG, orig, b_ptr);
 245                if (rbuf) {
 246                        tipc_bearer_send(b_ptr, rbuf, &media_addr);
 247                        kfree_skb(rbuf);
 248                }
 249        }
 250
 251        tipc_node_unlock(n_ptr);
 252}
 253
 254/**
 255 * disc_update - update frequency of periodic link setup requests
 256 * @req: ptr to link request structure
 257 *
 258 * Reinitiates discovery process if discovery object has no associated nodes
 259 * and is either not currently searching or is searching at a slow rate
 260 */
 261static void disc_update(struct tipc_link_req *req)
 262{
 263        if (!req->num_nodes) {
 264                if ((req->timer_intv == TIPC_LINK_REQ_INACTIVE) ||
 265                    (req->timer_intv > TIPC_LINK_REQ_FAST)) {
 266                        req->timer_intv = TIPC_LINK_REQ_INIT;
 267                        k_start_timer(&req->timer, req->timer_intv);
 268                }
 269        }
 270}
 271
 272/**
 273 * tipc_disc_add_dest - increment set of discovered nodes
 274 * @req: ptr to link request structure
 275 */
 276void tipc_disc_add_dest(struct tipc_link_req *req)
 277{
 278        req->num_nodes++;
 279}
 280
 281/**
 282 * tipc_disc_remove_dest - decrement set of discovered nodes
 283 * @req: ptr to link request structure
 284 */
 285void tipc_disc_remove_dest(struct tipc_link_req *req)
 286{
 287        req->num_nodes--;
 288        disc_update(req);
 289}
 290
 291/**
 292 * disc_send_msg - send link setup request message
 293 * @req: ptr to link request structure
 294 */
 295static void disc_send_msg(struct tipc_link_req *req)
 296{
 297        if (!req->bearer->blocked)
 298                tipc_bearer_send(req->bearer, req->buf, &req->dest);
 299}
 300
 301/**
 302 * disc_timeout - send a periodic link setup request
 303 * @req: ptr to link request structure
 304 *
 305 * Called whenever a link setup request timer associated with a bearer expires.
 306 */
 307static void disc_timeout(struct tipc_link_req *req)
 308{
 309        int max_delay;
 310
 311        spin_lock_bh(&req->bearer->lock);
 312
 313        /* Stop searching if only desired node has been found */
 314        if (tipc_node(req->domain) && req->num_nodes) {
 315                req->timer_intv = TIPC_LINK_REQ_INACTIVE;
 316                goto exit;
 317        }
 318
 319        /*
 320         * Send discovery message, then update discovery timer
 321         *
 322         * Keep doubling time between requests until limit is reached;
 323         * hold at fast polling rate if don't have any associated nodes,
 324         * otherwise hold at slow polling rate
 325         */
 326        disc_send_msg(req);
 327
 328        req->timer_intv *= 2;
 329        if (req->num_nodes)
 330                max_delay = TIPC_LINK_REQ_SLOW;
 331        else
 332                max_delay = TIPC_LINK_REQ_FAST;
 333        if (req->timer_intv > max_delay)
 334                req->timer_intv = max_delay;
 335
 336        k_start_timer(&req->timer, req->timer_intv);
 337exit:
 338        spin_unlock_bh(&req->bearer->lock);
 339}
 340
 341/**
 342 * tipc_disc_create - create object to send periodic link setup requests
 343 * @b_ptr: ptr to bearer issuing requests
 344 * @dest: destination address for request messages
 345 * @dest_domain: network domain to which links can be established
 346 *
 347 * Returns 0 if successful, otherwise -errno.
 348 */
 349int tipc_disc_create(struct tipc_bearer *b_ptr,
 350                     struct tipc_media_addr *dest, u32 dest_domain)
 351{
 352        struct tipc_link_req *req;
 353
 354        req = kmalloc(sizeof(*req), GFP_ATOMIC);
 355        if (!req)
 356                return -ENOMEM;
 357
 358        req->buf = tipc_disc_init_msg(DSC_REQ_MSG, dest_domain, b_ptr);
 359        if (!req->buf) {
 360                kfree(req);
 361                return -ENOMSG;
 362        }
 363
 364        memcpy(&req->dest, dest, sizeof(*dest));
 365        req->bearer = b_ptr;
 366        req->domain = dest_domain;
 367        req->num_nodes = 0;
 368        req->timer_intv = TIPC_LINK_REQ_INIT;
 369        k_init_timer(&req->timer, (Handler)disc_timeout, (unsigned long)req);
 370        k_start_timer(&req->timer, req->timer_intv);
 371        b_ptr->link_req = req;
 372        disc_send_msg(req);
 373        return 0;
 374}
 375
 376/**
 377 * tipc_disc_delete - destroy object sending periodic link setup requests
 378 * @req: ptr to link request structure
 379 */
 380void tipc_disc_delete(struct tipc_link_req *req)
 381{
 382        k_cancel_timer(&req->timer);
 383        k_term_timer(&req->timer);
 384        kfree_skb(req->buf);
 385        kfree(req);
 386}
 387