cregit-Linux how code gets into the kernel

Release 4.8 net/tipc/node.c

Directory: net/tipc
/*
 * net/tipc/node.c: TIPC node management routines
 *
 * Copyright (c) 2000-2006, 2012-2016, Ericsson AB
 * Copyright (c) 2005-2006, 2010-2014, Wind River Systems
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the names of the copyright holders nor the names of its
 *    contributors may be used to endorse or promote products derived from
 *    this software without specific prior written permission.
 *
 * Alternatively, this software may be distributed under the terms of the
 * GNU General Public License ("GPL") version 2 as published by the Free
 * Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include "core.h"
#include "link.h"
#include "node.h"
#include "name_distr.h"
#include "socket.h"
#include "bcast.h"
#include "monitor.h"
#include "discover.h"
#include "netlink.h"


#define INVALID_NODE_SIG	0x10000

/* Flags used to take different actions according to flag type
 * TIPC_NOTIFY_NODE_DOWN: notify node is down
 * TIPC_NOTIFY_NODE_UP: notify node is up
 * TIPC_DISTRIBUTE_NAME: publish or withdraw link state name type
 */
enum {
	
TIPC_NOTIFY_NODE_DOWN		= (1 << 3),
	
TIPC_NOTIFY_NODE_UP		= (1 << 4),
	
TIPC_NOTIFY_LINK_UP		= (1 << 6),
	
TIPC_NOTIFY_LINK_DOWN		= (1 << 7)
};


struct tipc_link_entry {
	
struct tipc_link *link;
	
spinlock_t lock; /* per link */
	
u32 mtu;
	
struct sk_buff_head inputq;
	
struct tipc_media_addr maddr;
};


struct tipc_bclink_entry {
	
struct tipc_link *link;
	
struct sk_buff_head inputq1;
	
struct sk_buff_head arrvq;
	
struct sk_buff_head inputq2;
	
struct sk_buff_head namedq;
};

/**
 * struct tipc_node - TIPC node structure
 * @addr: network address of node
 * @ref: reference counter to node object
 * @lock: rwlock governing access to structure
 * @net: the applicable net namespace
 * @hash: links to adjacent nodes in unsorted hash chain
 * @inputq: pointer to input queue containing messages for msg event
 * @namedq: pointer to name table input queue with name table messages
 * @active_links: bearer ids of active links, used as index into links[] array
 * @links: array containing references to all links to node
 * @action_flags: bit mask of different types of node actions
 * @state: connectivity state vs peer node
 * @sync_point: sequence number where synch/failover is finished
 * @list: links to adjacent nodes in sorted list of cluster's nodes
 * @working_links: number of working links to node (both active and standby)
 * @link_cnt: number of links to node
 * @capabilities: bitmap, indicating peer node's functional capabilities
 * @signature: node instance identifier
 * @link_id: local and remote bearer ids of changing link, if any
 * @publ_list: list of publications
 * @rcu: rcu struct for tipc_node
 */

struct tipc_node {
	
u32 addr;
	
struct kref kref;
	
rwlock_t lock;
	
struct net *net;
	
struct hlist_node hash;
	
int active_links[2];
	
struct tipc_link_entry links[MAX_BEARERS];
	
struct tipc_bclink_entry bc_entry;
	
int action_flags;
	
struct list_head list;
	
int state;
	
u16 sync_point;
	
int link_cnt;
	
u16 working_links;
	
u16 capabilities;
	
u32 signature;
	
u32 link_id;
	
struct list_head publ_list;
	
struct list_head conn_sks;
	
unsigned long keepalive_intv;
	
struct timer_list timer;
	
struct rcu_head rcu;
};

/* Node FSM states and events:
 */
enum {
	
SELF_DOWN_PEER_DOWN    = 0xdd,
	
SELF_UP_PEER_UP        = 0xaa,
	
SELF_DOWN_PEER_LEAVING = 0xd1,
	
SELF_UP_PEER_COMING    = 0xac,
	
SELF_COMING_PEER_UP    = 0xca,
	
SELF_LEAVING_PEER_DOWN = 0x1d,
	
NODE_FAILINGOVER       = 0xf0,
	
NODE_SYNCHING          = 0xcc
};

enum {
	
SELF_ESTABL_CONTACT_EVT = 0xece,
	
SELF_LOST_CONTACT_EVT   = 0x1ce,
	
PEER_ESTABL_CONTACT_EVT = 0x9ece,
	
PEER_LOST_CONTACT_EVT   = 0x91ce,
	
NODE_FAILOVER_BEGIN_EVT = 0xfbe,
	
NODE_FAILOVER_END_EVT   = 0xfee,
	
NODE_SYNCH_BEGIN_EVT    = 0xcbe,
	
NODE_SYNCH_END_EVT      = 0xcee
};

static void __tipc_node_link_down(struct tipc_node *n, int *bearer_id,
				  struct sk_buff_head *xmitq,
				  struct tipc_media_addr **maddr);
static void tipc_node_link_down(struct tipc_node *n, int bearer_id,
				bool delete);
static void node_lost_contact(struct tipc_node *n, struct sk_buff_head *inputq);
static void tipc_node_delete(struct tipc_node *node);
static void tipc_node_timeout(unsigned long data);
static void tipc_node_fsm_evt(struct tipc_node *n, int evt);
static struct tipc_node *tipc_node_find(struct net *net, u32 addr);
static void tipc_node_put(struct tipc_node *node);
static bool tipc_node_is_up(struct tipc_node *n);


struct tipc_sock_conn {
	
u32 port;
	
u32 peer_port;
	
u32 peer_node;
	
struct list_head list;
};


static struct tipc_link *node_active_link(struct tipc_node *n, int sel) { int bearer_id = n->active_links[sel & 1]; if (unlikely(bearer_id == INVALID_BEARER_ID)) return NULL; return n->links[bearer_id].link; }

Contributors

PersonTokensPropCommitsCommitProp
jon paul maloyjon paul maloy50100.00%1100.00%
Total50100.00%1100.00%


int tipc_node_get_mtu(struct net *net, u32 addr, u32 sel) { struct tipc_node *n; int bearer_id; unsigned int mtu = MAX_MSG_SIZE; n = tipc_node_find(net, addr); if (unlikely(!n)) return mtu; bearer_id = n->active_links[sel & 1]; if (likely(bearer_id != INVALID_BEARER_ID)) mtu = n->links[bearer_id].mtu; tipc_node_put(n); return mtu; }

Contributors

PersonTokensPropCommitsCommitProp
jon paul maloyjon paul maloy89100.00%1100.00%
Total89100.00%1100.00%


u16 tipc_node_get_capabilities(struct net *net, u32 addr) { struct tipc_node *n; u16 caps; n = tipc_node_find(net, addr); if (unlikely(!n)) return TIPC_NODE_CAPABILITIES; caps = n->capabilities; tipc_node_put(n); return caps; }

Contributors

PersonTokensPropCommitsCommitProp
jon paul maloyjon paul maloy55100.00%1100.00%
Total55100.00%1100.00%


static void tipc_node_kref_release(struct kref *kref) { struct tipc_node *n = container_of(kref, struct tipc_node, kref); kfree(n->bc_entry.link); kfree_rcu(n, rcu); }

Contributors

PersonTokensPropCommitsCommitProp
ying xueying xue2866.67%150.00%
jon paul maloyjon paul maloy1433.33%150.00%
Total42100.00%2100.00%


static void tipc_node_put(struct tipc_node *node) { kref_put(&node->kref, tipc_node_kref_release); }

Contributors

PersonTokensPropCommitsCommitProp
ying xueying xue2095.24%150.00%
jon paul maloyjon paul maloy14.76%150.00%
Total21100.00%2100.00%


static void tipc_node_get(struct tipc_node *node) { kref_get(&node->kref); }

Contributors

PersonTokensPropCommitsCommitProp
ying xueying xue19100.00%1100.00%
Total19100.00%1100.00%

/* * tipc_node_find - locate specified node object, if it exists */
static struct tipc_node *tipc_node_find(struct net *net, u32 addr) { struct tipc_net *tn = tipc_net(net); struct tipc_node *node; unsigned int thash = tipc_hashfn(addr); if (unlikely(!in_own_cluster_exact(net, addr))) return NULL; rcu_read_lock(); hlist_for_each_entry_rcu(node, &tn->node_htable[thash], hash) { if (node->addr != addr) continue; if (!kref_get_unless_zero(&node->kref)) node = NULL; break; } rcu_read_unlock(); return node; }

Contributors

PersonTokensPropCommitsCommitProp
allan stephensallan stephens4646.00%222.22%
ying xueying xue2727.00%555.56%
jon paul maloyjon paul maloy2727.00%222.22%
Total100100.00%9100.00%


static void tipc_node_read_lock(struct tipc_node *n) { read_lock_bh(&n->lock); }

Contributors

PersonTokensPropCommitsCommitProp
jon paul maloyjon paul maloy19100.00%2100.00%
Total19100.00%2100.00%


static void tipc_node_read_unlock(struct tipc_node *n) { read_unlock_bh(&n->lock); }

Contributors

PersonTokensPropCommitsCommitProp
jon paul maloyjon paul maloy19100.00%2100.00%
Total19100.00%2100.00%


static void tipc_node_write_lock(struct tipc_node *n) { write_lock_bh(&n->lock); }

Contributors

PersonTokensPropCommitsCommitProp
jon paul maloyjon paul maloy19100.00%1100.00%
Total19100.00%1100.00%


static void tipc_node_write_unlock(struct tipc_node *n) { struct net *net = n->net; u32 addr = 0; u32 flags = n->action_flags; u32 link_id = 0; u32 bearer_id; struct list_head *publ_list; if (likely(!flags)) { write_unlock_bh(&n->lock); return; } addr = n->addr; link_id = n->link_id; bearer_id = link_id & 0xffff; publ_list = &n->publ_list; n->action_flags &= ~(TIPC_NOTIFY_NODE_DOWN | TIPC_NOTIFY_NODE_UP | TIPC_NOTIFY_LINK_DOWN | TIPC_NOTIFY_LINK_UP); write_unlock_bh(&n->lock); if (flags & TIPC_NOTIFY_NODE_DOWN) tipc_publ_notify(net, publ_list, addr); if (flags & TIPC_NOTIFY_NODE_UP) tipc_named_node_up(net, addr); if (flags & TIPC_NOTIFY_LINK_UP) { tipc_mon_peer_up(net, addr, bearer_id); tipc_nametbl_publish(net, TIPC_LINK_STATE, addr, addr, TIPC_NODE_SCOPE, link_id, addr); } if (flags & TIPC_NOTIFY_LINK_DOWN) { tipc_mon_peer_down(net, addr, bearer_id); tipc_nametbl_withdraw(net, TIPC_LINK_STATE, addr, link_id, addr); } }

Contributors

PersonTokensPropCommitsCommitProp
jon paul maloyjon paul maloy204100.00%2100.00%
Total204100.00%2100.00%


struct tipc_node *tipc_node_create(struct net *net, u32 addr, u16 capabilities) { struct tipc_net *tn = net_generic(net, tipc_net_id); struct tipc_node *n, *temp_node; int i; spin_lock_bh(&tn->node_list_lock); n = tipc_node_find(net, addr); if (n) { /* Same node may come back with new capabilities */ n->capabilities = capabilities; goto exit; } n = kzalloc(sizeof(*n), GFP_ATOMIC); if (!n) { pr_warn("Node creation failed, no memory\n"); goto exit; } n->addr = addr; n->net = net; n->capabilities = capabilities; kref_init(&n->kref); rwlock_init(&n->lock); INIT_HLIST_NODE(&n->hash); INIT_LIST_HEAD(&n->list); INIT_LIST_HEAD(&n->publ_list); INIT_LIST_HEAD(&n->conn_sks); skb_queue_head_init(&n->bc_entry.namedq); skb_queue_head_init(&n->bc_entry.inputq1); __skb_queue_head_init(&n->bc_entry.arrvq); skb_queue_head_init(&n->bc_entry.inputq2); for (i = 0; i < MAX_BEARERS; i++) spin_lock_init(&n->links[i].lock); n->state = SELF_DOWN_PEER_LEAVING; n->signature = INVALID_NODE_SIG; n->active_links[0] = INVALID_BEARER_ID; n->active_links[1] = INVALID_BEARER_ID; if (!tipc_link_bc_create(net, tipc_own_addr(net), n->addr, U16_MAX, tipc_link_window(tipc_bc_sndlink(net)), n->capabilities, &n->bc_entry.inputq1, &n->bc_entry.namedq, tipc_bc_sndlink(net), &n->bc_entry.link)) { pr_warn("Broadcast rcv link creation failed, no memory\n"); kfree(n); n = NULL; goto exit; } tipc_node_get(n); setup_timer(&n->timer, tipc_node_timeout, (unsigned long)n); n->keepalive_intv = U32_MAX; hlist_add_head_rcu(&n->hash, &tn->node_htable[tipc_hashfn(addr)]); list_for_each_entry_rcu(temp_node, &tn->node_list, list) { if (n->addr < temp_node->addr) break; } list_add_tail_rcu(&n->list, &temp_node->list); exit: spin_unlock_bh(&tn->node_list_lock); return n; }

Contributors

PersonTokensPropCommitsCommitProp
jon paul maloyjon paul maloy29668.36%1546.88%
ying xueying xue4710.85%515.62%
allan stephensallan stephens429.70%618.75%
per lidenper liden419.47%26.25%
ingo molnaringo molnar30.69%13.12%
david s. millerdavid s. miller20.46%13.12%
erik hugneerik hugne10.23%13.12%
arnaldo carvalho de meloarnaldo carvalho de melo10.23%13.12%
Total433100.00%32100.00%


static void tipc_node_calculate_timer(struct tipc_node *n, struct tipc_link *l) { unsigned long tol = tipc_link_tolerance(l); unsigned long intv = ((tol / 4) > 500) ? 500 : tol / 4; /* Link with lowest tolerance determines timer interval */ if (intv < n->keepalive_intv) n->keepalive_intv = intv; /* Ensure link's abort limit corresponds to current tolerance */ tipc_link_set_abort_limit(l, tol / n->keepalive_intv); }

Contributors

PersonTokensPropCommitsCommitProp
jon paul maloyjon paul maloy72100.00%3100.00%
Total72100.00%3100.00%


static void tipc_node_delete(struct tipc_node *node) { list_del_rcu(&node->list); hlist_del_rcu(&node->hash); tipc_node_put(node); del_timer_sync(&node->timer); tipc_node_put(node); }

Contributors

PersonTokensPropCommitsCommitProp
jon paul maloyjon paul maloy1431.11%220.00%
allan stephensallan stephens1226.67%220.00%
per lidenper liden1124.44%220.00%
ying xueying xue715.56%330.00%
david s. millerdavid s. miller12.22%110.00%
Total45100.00%10100.00%


void tipc_node_stop(struct net *net) { struct tipc_net *tn = tipc_net(net); struct tipc_node *node, *t_node; spin_lock_bh(&tn->node_list_lock); list_for_each_entry_safe(node, t_node, &tn->node_list, list) tipc_node_delete(node); spin_unlock_bh(&tn->node_list_lock); }

Contributors

PersonTokensPropCommitsCommitProp
ying xueying xue5796.61%266.67%
jon paul maloyjon paul maloy23.39%133.33%
Total59100.00%3100.00%


void tipc_node_subscribe(struct net *net, struct list_head *subscr, u32 addr) { struct tipc_node *n; if (in_own_node(net, addr)) return; n = tipc_node_find(net, addr); if (!n) { pr_warn("Node subscribe rejected, unknown node 0x%x\n", addr); return; } tipc_node_write_lock(n); list_add_tail(subscr, &n->publ_list); tipc_node_write_unlock(n); tipc_node_put(n); }

Contributors

PersonTokensPropCommitsCommitProp
jon paul maloyjon paul maloy82100.00%2100.00%
Total82100.00%2100.00%


void tipc_node_unsubscribe(struct net *net, struct list_head *subscr, u32 addr) { struct tipc_node *n; if (in_own_node(net, addr)) return; n = tipc_node_find(net, addr); if (!n) { pr_warn("Node unsubscribe rejected, unknown node 0x%x\n", addr); return; } tipc_node_write_lock(n); list_del_init(subscr); tipc_node_write_unlock(n); tipc_node_put(n); }

Contributors

PersonTokensPropCommitsCommitProp
jon paul maloyjon paul maloy77100.00%2100.00%
Total77100.00%2100.00%


int tipc_node_add_conn(struct net *net, u32 dnode, u32 port, u32 peer_port) { struct tipc_node *node; struct tipc_sock_conn *conn; int err = 0; if (in_own_node(net, dnode)) return 0; node = tipc_node_find(net, dnode); if (!node) { pr_warn("Connecting sock to node 0x%x failed\n", dnode); return -EHOSTUNREACH; } conn = kmalloc(sizeof(*conn), GFP_ATOMIC); if (!conn) { err = -EHOSTUNREACH; goto exit; } conn->peer_node = dnode; conn->port = port; conn->peer_port = peer_port; tipc_node_write_lock(node); list_add_tail(&conn->list, &node->conn_sks); tipc_node_write_unlock(node); exit: tipc_node_put(node); return err; }

Contributors

PersonTokensPropCommitsCommitProp
jon paul maloyjon paul maloy12280.26%240.00%
ying xueying xue3019.74%360.00%
Total152100.00%5100.00%


void tipc_node_remove_conn(struct net *net, u32 dnode, u32 port) { struct tipc_node *node; struct tipc_sock_conn *conn, *safe; if (in_own_node(net, dnode)) return; node = tipc_node_find(net, dnode); if (!node) return; tipc_node_write_lock(node); list_for_each_entry_safe(conn, safe, &node->conn_sks, list) { if (port != conn->port) continue; list_del(&conn->list); kfree(conn); } tipc_node_write_unlock(node); tipc_node_put(node); }

Contributors

PersonTokensPropCommitsCommitProp
jon paul maloyjon paul maloy8986.41%240.00%
ying xueying xue1413.59%360.00%
Total103100.00%5100.00%

/* tipc_node_timeout - handle expiration of node timer */
static void tipc_node_timeout(unsigned long data) { struct tipc_node *n = (struct tipc_node *)data; struct tipc_link_entry *le; struct sk_buff_head xmitq; int bearer_id; int rc = 0; __skb_queue_head_init(&xmitq); for (bearer_id = 0; bearer_id < MAX_BEARERS; bearer_id++) { tipc_node_read_lock(n); le = &n->links[bearer_id]; spin_lock_bh(&le->lock); if (le->link) { /* Link tolerance may change asynchronously: */ tipc_node_calculate_timer(n, le->link); rc = tipc_link_timeout(le->link, &xmitq); } spin_unlock_bh(&le->lock); tipc_node_read_unlock(n); tipc_bearer_xmit(n->net, bearer_id, &xmitq, &le->maddr); if (rc & TIPC_LINK_DOWN_EVT) tipc_node_link_down(n, bearer_id, false); } mod_timer(&n->timer, jiffies + msecs_to_jiffies(n->keepalive_intv)); }

Contributors

PersonTokensPropCommitsCommitProp
jon paul maloyjon paul maloy175100.00%5100.00%
Total175100.00%5100.00%

/** * __tipc_node_link_up - handle addition of link * Node lock must be held by caller * Link becomes active (alone or shared) or standby, depending on its priority. */
static void __tipc_node_link_up(struct tipc_node *n, int bearer_id, struct sk_buff_head *xmitq) { int *slot0 = &n->active_links[0]; int *slot1 = &n->active_links[1]; struct tipc_link *ol = node_active_link(n, 0); struct tipc_link *nl = n->links[bearer_id].link; if (!nl || tipc_link_is_up(nl)) return; tipc_link_fsm_evt(nl, LINK_ESTABLISH_EVT); if (!tipc_link_is_up(nl)) return; n->working_links++; n->action_flags |= TIPC_NOTIFY_LINK_UP; n->link_id = tipc_link_id(nl); /* Leave room for tunnel header when returning 'mtu' to users: */ n->links[bearer_id].mtu = tipc_link_mtu(nl) - INT_H_SIZE; tipc_bearer_add_dest(n->net, bearer_id, n->addr); tipc_bcast_inc_bearer_dst_cnt(n->net, bearer_id); pr_debug("Established link <%s> on network plane %c\n", tipc_link_name(nl), tipc_link_plane(nl)); /* Ensure that a STATE message goes first */ tipc_link_build_state_msg(nl, xmitq); /* First link? => give it both slots */ if (!ol) { *slot0 = bearer_id; *slot1 = bearer_id; tipc_node_fsm_evt(n, SELF_ESTABL_CONTACT_EVT); n->action_flags |= TIPC_NOTIFY_NODE_UP; tipc_link_set_active(nl, true); tipc_bcast_add_peer(n->net, nl, xmitq); return; } /* Second link => redistribute slots */ if (tipc_link_prio(nl) > tipc_link_prio(ol)) { pr_debug("Old link <%s> becomes standby\n", tipc_link_name(ol)); *slot0 = bearer_id; *slot1 = bearer_id; tipc_link_set_active(nl, true); tipc_link_set_active(ol, false); } else if (tipc_link_prio(nl) == tipc_link_prio(ol)) { tipc_link_set_active(nl, true); *slot1 = bearer_id; } else { pr_debug("New link <%s> is standby\n", tipc_link_name(nl)); } /* Prepare synchronization with first link */ tipc_link_tnl_prepare(ol, nl, SYNCH_MSG, xmitq); }

Contributors

PersonTokensPropCommitsCommitProp
jon paul maloyjon paul maloy25577.51%1669.57%
per lidenper liden5215.81%14.35%
ying xueying xue82.43%14.35%
allan stephensallan stephens72.13%28.70%
erik hugneerik hugne61.82%28.70%
david s. millerdavid s. miller10.30%14.35%
Total329100.00%23100.00%

/** * tipc_node_link_up - handle addition of link * * Link becomes active (alone or shared) or standby, depending on its priority. */
static void tipc_node_link_up(struct tipc_node *n, int bearer_id, struct sk_buff_head *xmitq) { struct tipc_media_addr *maddr; tipc_node_write_lock(n); __tipc_node_link_up(n, bearer_id, xmitq); maddr = &n->links[bearer_id].maddr; tipc_bearer_xmit(n->net, bearer_id, xmitq, maddr); tipc_node_write_unlock(n); }

Contributors

PersonTokensPropCommitsCommitProp
jon paul maloyjon paul maloy6189.71%675.00%
per lidenper liden68.82%112.50%
david s. millerdavid s. miller11.47%112.50%
Total68100.00%8100.00%

/** * __tipc_node_link_down - handle loss of link */
static void __tipc_node_link_down(struct tipc_node *n, int *bearer_id, struct sk_buff_head *xmitq, struct tipc_media_addr **maddr) { struct tipc_link_entry *le = &n->links[*bearer_id]; int *slot0 = &n->active_links[0]; int *slot1 = &n->active_links[1]; int i, highest = 0, prio; struct tipc_link *l, *_l, *tnl; l = n->links[*bearer_id].link; if (!l || tipc_link_is_reset(l)) return; n->working_links--; n->action_flags |= TIPC_NOTIFY_LINK_DOWN; n->link_id = tipc_link_id(l); tipc_bearer_remove_dest(n->net, *bearer_id, n->addr); pr_debug("Lost link <%s> on network plane %c\n", tipc_link_name(l), tipc_link_plane(l)); /* Select new active link if any available */ *slot0 = INVALID_BEARER_ID; *slot1 = INVALID_BEARER_ID; for (i = 0; i < MAX_BEARERS; i++) { _l = n->links[i].link;