Skip to content

Commit

Permalink
tipc: enable creating a "preliminary" node
Browse files Browse the repository at this point in the history
When user sets RX key for a peer not existing on the own node, a new
node entry is needed to which the RX key will be attached. However,
since the peer node address (& capabilities) is unknown at that moment,
only the node-ID is provided, this commit allows the creation of a node
with only the data that we call as “preliminary”.

A preliminary node is not the object of the “tipc_node_find()” but the
“tipc_node_find_by_id()”. Once the first message i.e. LINK_CONFIG comes
from that peer, and is successfully decrypted by the own node, the
actual peer node data will be properly updated and the node will
function as usual.

In addition, the node timer always starts when a node object is created
so if a preliminary node is not used, it will be cleaned up.

The later encryption functions will also use the node timer and be able
to create a preliminary node automatically when needed.

Acked-by: Ying Xue <ying.xue@windreiver.com>
Acked-by: Jon Maloy <jon.maloy@ericsson.com>
Signed-off-by: Tuong Lien <tuong.t.lien@dektech.com.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Tuong Lien authored and David S. Miller committed Nov 8, 2019
1 parent 2a7ee69 commit 4cbf8ac
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 27 deletions.
99 changes: 72 additions & 27 deletions net/tipc/node.c
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ struct tipc_bclink_entry {
* @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
* @preliminary: a preliminary node or not
* @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)
Expand All @@ -112,6 +113,7 @@ struct tipc_node {
int action_flags;
struct list_head list;
int state;
bool preliminary;
bool failover_sent;
u16 sync_point;
int link_cnt;
Expand All @@ -120,6 +122,7 @@ struct tipc_node {
u32 signature;
u32 link_id;
u8 peer_id[16];
char peer_id_string[NODE_ID_STR_LEN];
struct list_head publ_list;
struct list_head conn_sks;
unsigned long keepalive_intv;
Expand Down Expand Up @@ -245,6 +248,16 @@ u16 tipc_node_get_capabilities(struct net *net, u32 addr)
return caps;
}

u32 tipc_node_get_addr(struct tipc_node *node)
{
return (node) ? node->addr : 0;
}

char *tipc_node_get_id_str(struct tipc_node *node)
{
return node->peer_id_string;
}

static void tipc_node_kref_release(struct kref *kref)
{
struct tipc_node *n = container_of(kref, struct tipc_node, kref);
Expand Down Expand Up @@ -274,7 +287,7 @@ static struct tipc_node *tipc_node_find(struct net *net, u32 addr)

rcu_read_lock();
hlist_for_each_entry_rcu(node, &tn->node_htable[thash], hash) {
if (node->addr != addr)
if (node->addr != addr || node->preliminary)
continue;
if (!kref_get_unless_zero(&node->kref))
node = NULL;
Expand Down Expand Up @@ -400,17 +413,39 @@ static void tipc_node_assign_peer_net(struct tipc_node *n, u32 hash_mixes)

static struct tipc_node *tipc_node_create(struct net *net, u32 addr,
u8 *peer_id, u16 capabilities,
u32 signature, u32 hash_mixes)
u32 hash_mixes, bool preliminary)
{
struct tipc_net *tn = net_generic(net, tipc_net_id);
struct tipc_node *n, *temp_node;
struct tipc_link *l;
unsigned long intv;
int bearer_id;
int i;

spin_lock_bh(&tn->node_list_lock);
n = tipc_node_find(net, addr);
n = tipc_node_find(net, addr) ?:
tipc_node_find_by_id(net, peer_id);
if (n) {
if (!n->preliminary)
goto update;
if (preliminary)
goto exit;
/* A preliminary node becomes "real" now, refresh its data */
tipc_node_write_lock(n);
n->preliminary = false;
n->addr = addr;
hlist_del_rcu(&n->hash);
hlist_add_head_rcu(&n->hash,
&tn->node_htable[tipc_hashfn(addr)]);
list_del_rcu(&n->list);
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);
tipc_node_write_unlock_fast(n);

update:
if (n->peer_hash_mix ^ hash_mixes)
tipc_node_assign_peer_net(n, hash_mixes);
if (n->capabilities == capabilities)
Expand Down Expand Up @@ -438,7 +473,9 @@ static struct tipc_node *tipc_node_create(struct net *net, u32 addr,
pr_warn("Node creation failed, no memory\n");
goto exit;
}
tipc_nodeid2string(n->peer_id_string, peer_id);
n->addr = addr;
n->preliminary = preliminary;
memcpy(&n->peer_id, peer_id, 16);
n->net = net;
n->peer_net = NULL;
Expand All @@ -463,22 +500,14 @@ static struct tipc_node *tipc_node_create(struct net *net, u32 addr,
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),
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;
}
n->bc_entry.link = NULL;
tipc_node_get(n);
timer_setup(&n->timer, tipc_node_timeout, 0);
n->keepalive_intv = U32_MAX;
/* Start a slow timer anyway, crypto needs it */
n->keepalive_intv = 10000;
intv = jiffies + msecs_to_jiffies(n->keepalive_intv);
if (!mod_timer(&n->timer, intv))
tipc_node_get(n);
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)
Expand Down Expand Up @@ -1001,6 +1030,8 @@ u32 tipc_node_try_addr(struct net *net, u8 *id, u32 addr)
{
struct tipc_net *tn = tipc_net(net);
struct tipc_node *n;
bool preliminary;
u32 sugg_addr;

/* Suggest new address if some other peer is using this one */
n = tipc_node_find(net, addr);
Expand All @@ -1016,9 +1047,11 @@ u32 tipc_node_try_addr(struct net *net, u8 *id, u32 addr)
/* Suggest previously used address if peer is known */
n = tipc_node_find_by_id(net, id);
if (n) {
addr = n->addr;
sugg_addr = n->addr;
preliminary = n->preliminary;
tipc_node_put(n);
return addr;
if (!preliminary)
return sugg_addr;
}

/* Even this node may be in conflict */
Expand All @@ -1035,7 +1068,7 @@ void tipc_node_check_dest(struct net *net, u32 addr,
bool *respond, bool *dupl_addr)
{
struct tipc_node *n;
struct tipc_link *l;
struct tipc_link *l, *snd_l;
struct tipc_link_entry *le;
bool addr_match = false;
bool sign_match = false;
Expand All @@ -1049,12 +1082,27 @@ void tipc_node_check_dest(struct net *net, u32 addr,
*dupl_addr = false;
*respond = false;

n = tipc_node_create(net, addr, peer_id, capabilities, signature,
hash_mixes);
n = tipc_node_create(net, addr, peer_id, capabilities, hash_mixes,
false);
if (!n)
return;

tipc_node_write_lock(n);
if (unlikely(!n->bc_entry.link)) {
snd_l = tipc_bc_sndlink(net);
if (!tipc_link_bc_create(net, tipc_own_addr(net),
addr, U16_MAX,
tipc_link_window(snd_l),
n->capabilities,
&n->bc_entry.inputq1,
&n->bc_entry.namedq, snd_l,
&n->bc_entry.link)) {
pr_warn("Broadcast rcv link creation failed, no mem\n");
tipc_node_write_unlock_fast(n);
tipc_node_put(n);
return;
}
}

le = &n->links[b->identity];

Expand Down Expand Up @@ -2134,6 +2182,8 @@ int tipc_nl_node_dump(struct sk_buff *skb, struct netlink_callback *cb)
}

list_for_each_entry_rcu(node, &tn->node_list, list) {
if (node->preliminary)
continue;
if (last_addr) {
if (node->addr == last_addr)
last_addr = 0;
Expand Down Expand Up @@ -2649,11 +2699,6 @@ int tipc_nl_node_dump_monitor_peer(struct sk_buff *skb,
return skb->len;
}

u32 tipc_node_get_addr(struct tipc_node *node)
{
return (node) ? node->addr : 0;
}

/**
* tipc_node_dump - dump TIPC node data
* @n: tipc node to be dumped
Expand Down
1 change: 1 addition & 0 deletions net/tipc/node.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ enum {
void tipc_node_stop(struct net *net);
bool tipc_node_get_id(struct net *net, u32 addr, u8 *id);
u32 tipc_node_get_addr(struct tipc_node *node);
char *tipc_node_get_id_str(struct tipc_node *node);
u32 tipc_node_try_addr(struct net *net, u8 *id, u32 addr);
void tipc_node_check_dest(struct net *net, u32 onode, u8 *peer_id128,
struct tipc_bearer *bearer,
Expand Down

0 comments on commit 4cbf8ac

Please sign in to comment.