18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * net/tipc/discover.c
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Copyright (c) 2003-2006, 2014-2018, Ericsson AB
58c2ecf20Sopenharmony_ci * Copyright (c) 2005-2006, 2010-2011, Wind River Systems
68c2ecf20Sopenharmony_ci * All rights reserved.
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or without
98c2ecf20Sopenharmony_ci * modification, are permitted provided that the following conditions are met:
108c2ecf20Sopenharmony_ci *
118c2ecf20Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright
128c2ecf20Sopenharmony_ci *    notice, this list of conditions and the following disclaimer.
138c2ecf20Sopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright
148c2ecf20Sopenharmony_ci *    notice, this list of conditions and the following disclaimer in the
158c2ecf20Sopenharmony_ci *    documentation and/or other materials provided with the distribution.
168c2ecf20Sopenharmony_ci * 3. Neither the names of the copyright holders nor the names of its
178c2ecf20Sopenharmony_ci *    contributors may be used to endorse or promote products derived from
188c2ecf20Sopenharmony_ci *    this software without specific prior written permission.
198c2ecf20Sopenharmony_ci *
208c2ecf20Sopenharmony_ci * Alternatively, this software may be distributed under the terms of the
218c2ecf20Sopenharmony_ci * GNU General Public License ("GPL") version 2 as published by the Free
228c2ecf20Sopenharmony_ci * Software Foundation.
238c2ecf20Sopenharmony_ci *
248c2ecf20Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
258c2ecf20Sopenharmony_ci * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
268c2ecf20Sopenharmony_ci * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
278c2ecf20Sopenharmony_ci * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
288c2ecf20Sopenharmony_ci * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
298c2ecf20Sopenharmony_ci * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
308c2ecf20Sopenharmony_ci * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
318c2ecf20Sopenharmony_ci * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
328c2ecf20Sopenharmony_ci * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
338c2ecf20Sopenharmony_ci * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
348c2ecf20Sopenharmony_ci * POSSIBILITY OF SUCH DAMAGE.
358c2ecf20Sopenharmony_ci */
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci#include "core.h"
388c2ecf20Sopenharmony_ci#include "node.h"
398c2ecf20Sopenharmony_ci#include "discover.h"
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci/* min delay during bearer start up */
428c2ecf20Sopenharmony_ci#define TIPC_DISC_INIT	msecs_to_jiffies(125)
438c2ecf20Sopenharmony_ci/* max delay if bearer has no links */
448c2ecf20Sopenharmony_ci#define TIPC_DISC_FAST	msecs_to_jiffies(1000)
458c2ecf20Sopenharmony_ci/* max delay if bearer has links */
468c2ecf20Sopenharmony_ci#define TIPC_DISC_SLOW	msecs_to_jiffies(60000)
478c2ecf20Sopenharmony_ci/* indicates no timer in use */
488c2ecf20Sopenharmony_ci#define TIPC_DISC_INACTIVE	0xffffffff
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci/**
518c2ecf20Sopenharmony_ci * struct tipc_discoverer - information about an ongoing link setup request
528c2ecf20Sopenharmony_ci * @bearer_id: identity of bearer issuing requests
538c2ecf20Sopenharmony_ci * @net: network namespace instance
548c2ecf20Sopenharmony_ci * @dest: destination address for request messages
558c2ecf20Sopenharmony_ci * @domain: network domain to which links can be established
568c2ecf20Sopenharmony_ci * @num_nodes: number of nodes currently discovered (i.e. with an active link)
578c2ecf20Sopenharmony_ci * @lock: spinlock for controlling access to requests
588c2ecf20Sopenharmony_ci * @skb: request message to be (repeatedly) sent
598c2ecf20Sopenharmony_ci * @timer: timer governing period between requests
608c2ecf20Sopenharmony_ci * @timer_intv: current interval between requests (in ms)
618c2ecf20Sopenharmony_ci */
628c2ecf20Sopenharmony_cistruct tipc_discoverer {
638c2ecf20Sopenharmony_ci	u32 bearer_id;
648c2ecf20Sopenharmony_ci	struct tipc_media_addr dest;
658c2ecf20Sopenharmony_ci	struct net *net;
668c2ecf20Sopenharmony_ci	u32 domain;
678c2ecf20Sopenharmony_ci	int num_nodes;
688c2ecf20Sopenharmony_ci	spinlock_t lock;
698c2ecf20Sopenharmony_ci	struct sk_buff *skb;
708c2ecf20Sopenharmony_ci	struct timer_list timer;
718c2ecf20Sopenharmony_ci	unsigned long timer_intv;
728c2ecf20Sopenharmony_ci};
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci/**
758c2ecf20Sopenharmony_ci * tipc_disc_init_msg - initialize a link setup message
768c2ecf20Sopenharmony_ci * @net: the applicable net namespace
778c2ecf20Sopenharmony_ci * @mtyp: message type (request or response)
788c2ecf20Sopenharmony_ci * @b: ptr to bearer issuing message
798c2ecf20Sopenharmony_ci */
808c2ecf20Sopenharmony_cistatic void tipc_disc_init_msg(struct net *net, struct sk_buff *skb,
818c2ecf20Sopenharmony_ci			       u32 mtyp,  struct tipc_bearer *b)
828c2ecf20Sopenharmony_ci{
838c2ecf20Sopenharmony_ci	struct tipc_net *tn = tipc_net(net);
848c2ecf20Sopenharmony_ci	u32 dest_domain = b->domain;
858c2ecf20Sopenharmony_ci	struct tipc_msg *hdr;
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci	hdr = buf_msg(skb);
888c2ecf20Sopenharmony_ci	tipc_msg_init(tn->trial_addr, hdr, LINK_CONFIG, mtyp,
898c2ecf20Sopenharmony_ci		      MAX_H_SIZE, dest_domain);
908c2ecf20Sopenharmony_ci	msg_set_size(hdr, MAX_H_SIZE + NODE_ID_LEN);
918c2ecf20Sopenharmony_ci	msg_set_non_seq(hdr, 1);
928c2ecf20Sopenharmony_ci	msg_set_node_sig(hdr, tn->random);
938c2ecf20Sopenharmony_ci	msg_set_node_capabilities(hdr, TIPC_NODE_CAPABILITIES);
948c2ecf20Sopenharmony_ci	msg_set_dest_domain(hdr, dest_domain);
958c2ecf20Sopenharmony_ci	msg_set_bc_netid(hdr, tn->net_id);
968c2ecf20Sopenharmony_ci	b->media->addr2msg(msg_media_addr(hdr), &b->addr);
978c2ecf20Sopenharmony_ci	msg_set_peer_net_hash(hdr, tipc_net_hash_mixes(net, tn->random));
988c2ecf20Sopenharmony_ci	msg_set_node_id(hdr, tipc_own_id(net));
998c2ecf20Sopenharmony_ci}
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_cistatic void tipc_disc_msg_xmit(struct net *net, u32 mtyp, u32 dst,
1028c2ecf20Sopenharmony_ci			       u32 src, u32 sugg_addr,
1038c2ecf20Sopenharmony_ci			       struct tipc_media_addr *maddr,
1048c2ecf20Sopenharmony_ci			       struct tipc_bearer *b)
1058c2ecf20Sopenharmony_ci{
1068c2ecf20Sopenharmony_ci	struct tipc_msg *hdr;
1078c2ecf20Sopenharmony_ci	struct sk_buff *skb;
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	skb = tipc_buf_acquire(MAX_H_SIZE + NODE_ID_LEN, GFP_ATOMIC);
1108c2ecf20Sopenharmony_ci	if (!skb)
1118c2ecf20Sopenharmony_ci		return;
1128c2ecf20Sopenharmony_ci	hdr = buf_msg(skb);
1138c2ecf20Sopenharmony_ci	tipc_disc_init_msg(net, skb, mtyp, b);
1148c2ecf20Sopenharmony_ci	msg_set_sugg_node_addr(hdr, sugg_addr);
1158c2ecf20Sopenharmony_ci	msg_set_dest_domain(hdr, dst);
1168c2ecf20Sopenharmony_ci	tipc_bearer_xmit_skb(net, b->identity, skb, maddr);
1178c2ecf20Sopenharmony_ci}
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci/**
1208c2ecf20Sopenharmony_ci * disc_dupl_alert - issue node address duplication alert
1218c2ecf20Sopenharmony_ci * @b: pointer to bearer detecting duplication
1228c2ecf20Sopenharmony_ci * @node_addr: duplicated node address
1238c2ecf20Sopenharmony_ci * @media_addr: media address advertised by duplicated node
1248c2ecf20Sopenharmony_ci */
1258c2ecf20Sopenharmony_cistatic void disc_dupl_alert(struct tipc_bearer *b, u32 node_addr,
1268c2ecf20Sopenharmony_ci			    struct tipc_media_addr *media_addr)
1278c2ecf20Sopenharmony_ci{
1288c2ecf20Sopenharmony_ci	char media_addr_str[64];
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	tipc_media_addr_printf(media_addr_str, sizeof(media_addr_str),
1318c2ecf20Sopenharmony_ci			       media_addr);
1328c2ecf20Sopenharmony_ci	pr_warn("Duplicate %x using %s seen on <%s>\n", node_addr,
1338c2ecf20Sopenharmony_ci		media_addr_str, b->name);
1348c2ecf20Sopenharmony_ci}
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci/* tipc_disc_addr_trial(): - handle an address uniqueness trial from peer
1378c2ecf20Sopenharmony_ci * Returns true if message should be dropped by caller, i.e., if it is a
1388c2ecf20Sopenharmony_ci * trial message or we are inside trial period. Otherwise false.
1398c2ecf20Sopenharmony_ci */
1408c2ecf20Sopenharmony_cistatic bool tipc_disc_addr_trial_msg(struct tipc_discoverer *d,
1418c2ecf20Sopenharmony_ci				     struct tipc_media_addr *maddr,
1428c2ecf20Sopenharmony_ci				     struct tipc_bearer *b,
1438c2ecf20Sopenharmony_ci				     u32 dst, u32 src,
1448c2ecf20Sopenharmony_ci				     u32 sugg_addr,
1458c2ecf20Sopenharmony_ci				     u8 *peer_id,
1468c2ecf20Sopenharmony_ci				     int mtyp)
1478c2ecf20Sopenharmony_ci{
1488c2ecf20Sopenharmony_ci	struct net *net = d->net;
1498c2ecf20Sopenharmony_ci	struct tipc_net *tn = tipc_net(net);
1508c2ecf20Sopenharmony_ci	u32 self = tipc_own_addr(net);
1518c2ecf20Sopenharmony_ci	bool trial = time_before(jiffies, tn->addr_trial_end) && !self;
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci	if (mtyp == DSC_TRIAL_FAIL_MSG) {
1548c2ecf20Sopenharmony_ci		if (!trial)
1558c2ecf20Sopenharmony_ci			return true;
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci		/* Ignore if somebody else already gave new suggestion */
1588c2ecf20Sopenharmony_ci		if (dst != tn->trial_addr)
1598c2ecf20Sopenharmony_ci			return true;
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci		/* Otherwise update trial address and restart trial period */
1628c2ecf20Sopenharmony_ci		tn->trial_addr = sugg_addr;
1638c2ecf20Sopenharmony_ci		msg_set_prevnode(buf_msg(d->skb), sugg_addr);
1648c2ecf20Sopenharmony_ci		tn->addr_trial_end = jiffies + msecs_to_jiffies(1000);
1658c2ecf20Sopenharmony_ci		return true;
1668c2ecf20Sopenharmony_ci	}
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci	/* Apply trial address if we just left trial period */
1698c2ecf20Sopenharmony_ci	if (!trial && !self) {
1708c2ecf20Sopenharmony_ci		schedule_work(&tn->work);
1718c2ecf20Sopenharmony_ci		msg_set_prevnode(buf_msg(d->skb), tn->trial_addr);
1728c2ecf20Sopenharmony_ci		msg_set_type(buf_msg(d->skb), DSC_REQ_MSG);
1738c2ecf20Sopenharmony_ci	}
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci	/* Accept regular link requests/responses only after trial period */
1768c2ecf20Sopenharmony_ci	if (mtyp != DSC_TRIAL_MSG)
1778c2ecf20Sopenharmony_ci		return trial;
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	sugg_addr = tipc_node_try_addr(net, peer_id, src);
1808c2ecf20Sopenharmony_ci	if (sugg_addr)
1818c2ecf20Sopenharmony_ci		tipc_disc_msg_xmit(net, DSC_TRIAL_FAIL_MSG, src,
1828c2ecf20Sopenharmony_ci				   self, sugg_addr, maddr, b);
1838c2ecf20Sopenharmony_ci	return true;
1848c2ecf20Sopenharmony_ci}
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci/**
1878c2ecf20Sopenharmony_ci * tipc_disc_rcv - handle incoming discovery message (request or response)
1888c2ecf20Sopenharmony_ci * @net: applicable net namespace
1898c2ecf20Sopenharmony_ci * @skb: buffer containing message
1908c2ecf20Sopenharmony_ci * @b: bearer that message arrived on
1918c2ecf20Sopenharmony_ci */
1928c2ecf20Sopenharmony_civoid tipc_disc_rcv(struct net *net, struct sk_buff *skb,
1938c2ecf20Sopenharmony_ci		   struct tipc_bearer *b)
1948c2ecf20Sopenharmony_ci{
1958c2ecf20Sopenharmony_ci	struct tipc_net *tn = tipc_net(net);
1968c2ecf20Sopenharmony_ci	struct tipc_msg *hdr = buf_msg(skb);
1978c2ecf20Sopenharmony_ci	u32 pnet_hash = msg_peer_net_hash(hdr);
1988c2ecf20Sopenharmony_ci	u16 caps = msg_node_capabilities(hdr);
1998c2ecf20Sopenharmony_ci	bool legacy = tn->legacy_addr_format;
2008c2ecf20Sopenharmony_ci	u32 sugg = msg_sugg_node_addr(hdr);
2018c2ecf20Sopenharmony_ci	u32 signature = msg_node_sig(hdr);
2028c2ecf20Sopenharmony_ci	u8 peer_id[NODE_ID_LEN] = {0,};
2038c2ecf20Sopenharmony_ci	u32 dst = msg_dest_domain(hdr);
2048c2ecf20Sopenharmony_ci	u32 net_id = msg_bc_netid(hdr);
2058c2ecf20Sopenharmony_ci	struct tipc_media_addr maddr;
2068c2ecf20Sopenharmony_ci	u32 src = msg_prevnode(hdr);
2078c2ecf20Sopenharmony_ci	u32 mtyp = msg_type(hdr);
2088c2ecf20Sopenharmony_ci	bool dupl_addr = false;
2098c2ecf20Sopenharmony_ci	bool respond = false;
2108c2ecf20Sopenharmony_ci	u32 self;
2118c2ecf20Sopenharmony_ci	int err;
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci	if (skb_linearize(skb)) {
2148c2ecf20Sopenharmony_ci		kfree_skb(skb);
2158c2ecf20Sopenharmony_ci		return;
2168c2ecf20Sopenharmony_ci	}
2178c2ecf20Sopenharmony_ci	hdr = buf_msg(skb);
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci	if (caps & TIPC_NODE_ID128)
2208c2ecf20Sopenharmony_ci		memcpy(peer_id, msg_node_id(hdr), NODE_ID_LEN);
2218c2ecf20Sopenharmony_ci	else
2228c2ecf20Sopenharmony_ci		sprintf(peer_id, "%x", src);
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci	err = b->media->msg2addr(b, &maddr, msg_media_addr(hdr));
2258c2ecf20Sopenharmony_ci	kfree_skb(skb);
2268c2ecf20Sopenharmony_ci	if (err || maddr.broadcast) {
2278c2ecf20Sopenharmony_ci		pr_warn_ratelimited("Rcv corrupt discovery message\n");
2288c2ecf20Sopenharmony_ci		return;
2298c2ecf20Sopenharmony_ci	}
2308c2ecf20Sopenharmony_ci	/* Ignore discovery messages from own node */
2318c2ecf20Sopenharmony_ci	if (!memcmp(&maddr, &b->addr, sizeof(maddr)))
2328c2ecf20Sopenharmony_ci		return;
2338c2ecf20Sopenharmony_ci	if (net_id != tn->net_id)
2348c2ecf20Sopenharmony_ci		return;
2358c2ecf20Sopenharmony_ci	if (tipc_disc_addr_trial_msg(b->disc, &maddr, b, dst,
2368c2ecf20Sopenharmony_ci				     src, sugg, peer_id, mtyp))
2378c2ecf20Sopenharmony_ci		return;
2388c2ecf20Sopenharmony_ci	self = tipc_own_addr(net);
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci	/* Message from somebody using this node's address */
2418c2ecf20Sopenharmony_ci	if (in_own_node(net, src)) {
2428c2ecf20Sopenharmony_ci		disc_dupl_alert(b, self, &maddr);
2438c2ecf20Sopenharmony_ci		return;
2448c2ecf20Sopenharmony_ci	}
2458c2ecf20Sopenharmony_ci	if (!tipc_in_scope(legacy, dst, self))
2468c2ecf20Sopenharmony_ci		return;
2478c2ecf20Sopenharmony_ci	if (!tipc_in_scope(legacy, b->domain, src))
2488c2ecf20Sopenharmony_ci		return;
2498c2ecf20Sopenharmony_ci	tipc_node_check_dest(net, src, peer_id, b, caps, signature, pnet_hash,
2508c2ecf20Sopenharmony_ci			     &maddr, &respond, &dupl_addr);
2518c2ecf20Sopenharmony_ci	if (dupl_addr)
2528c2ecf20Sopenharmony_ci		disc_dupl_alert(b, src, &maddr);
2538c2ecf20Sopenharmony_ci	if (!respond)
2548c2ecf20Sopenharmony_ci		return;
2558c2ecf20Sopenharmony_ci	if (mtyp != DSC_REQ_MSG)
2568c2ecf20Sopenharmony_ci		return;
2578c2ecf20Sopenharmony_ci	tipc_disc_msg_xmit(net, DSC_RESP_MSG, src, self, 0, &maddr, b);
2588c2ecf20Sopenharmony_ci}
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci/* tipc_disc_add_dest - increment set of discovered nodes
2618c2ecf20Sopenharmony_ci */
2628c2ecf20Sopenharmony_civoid tipc_disc_add_dest(struct tipc_discoverer *d)
2638c2ecf20Sopenharmony_ci{
2648c2ecf20Sopenharmony_ci	spin_lock_bh(&d->lock);
2658c2ecf20Sopenharmony_ci	d->num_nodes++;
2668c2ecf20Sopenharmony_ci	spin_unlock_bh(&d->lock);
2678c2ecf20Sopenharmony_ci}
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci/* tipc_disc_remove_dest - decrement set of discovered nodes
2708c2ecf20Sopenharmony_ci */
2718c2ecf20Sopenharmony_civoid tipc_disc_remove_dest(struct tipc_discoverer *d)
2728c2ecf20Sopenharmony_ci{
2738c2ecf20Sopenharmony_ci	int intv, num;
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci	spin_lock_bh(&d->lock);
2768c2ecf20Sopenharmony_ci	d->num_nodes--;
2778c2ecf20Sopenharmony_ci	num = d->num_nodes;
2788c2ecf20Sopenharmony_ci	intv = d->timer_intv;
2798c2ecf20Sopenharmony_ci	if (!num && (intv == TIPC_DISC_INACTIVE || intv > TIPC_DISC_FAST))  {
2808c2ecf20Sopenharmony_ci		d->timer_intv = TIPC_DISC_INIT;
2818c2ecf20Sopenharmony_ci		mod_timer(&d->timer, jiffies + d->timer_intv);
2828c2ecf20Sopenharmony_ci	}
2838c2ecf20Sopenharmony_ci	spin_unlock_bh(&d->lock);
2848c2ecf20Sopenharmony_ci}
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci/* tipc_disc_timeout - send a periodic link setup request
2878c2ecf20Sopenharmony_ci * Called whenever a link setup request timer associated with a bearer expires.
2888c2ecf20Sopenharmony_ci * - Keep doubling time between sent request until limit is reached;
2898c2ecf20Sopenharmony_ci * - Hold at fast polling rate if we don't have any associated nodes
2908c2ecf20Sopenharmony_ci * - Otherwise hold at slow polling rate
2918c2ecf20Sopenharmony_ci */
2928c2ecf20Sopenharmony_cistatic void tipc_disc_timeout(struct timer_list *t)
2938c2ecf20Sopenharmony_ci{
2948c2ecf20Sopenharmony_ci	struct tipc_discoverer *d = from_timer(d, t, timer);
2958c2ecf20Sopenharmony_ci	struct tipc_net *tn = tipc_net(d->net);
2968c2ecf20Sopenharmony_ci	struct tipc_media_addr maddr;
2978c2ecf20Sopenharmony_ci	struct sk_buff *skb = NULL;
2988c2ecf20Sopenharmony_ci	struct net *net = d->net;
2998c2ecf20Sopenharmony_ci	u32 bearer_id;
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci	spin_lock_bh(&d->lock);
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci	/* Stop searching if only desired node has been found */
3048c2ecf20Sopenharmony_ci	if (tipc_node(d->domain) && d->num_nodes) {
3058c2ecf20Sopenharmony_ci		d->timer_intv = TIPC_DISC_INACTIVE;
3068c2ecf20Sopenharmony_ci		goto exit;
3078c2ecf20Sopenharmony_ci	}
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci	/* Did we just leave trial period ? */
3108c2ecf20Sopenharmony_ci	if (!time_before(jiffies, tn->addr_trial_end) && !tipc_own_addr(net)) {
3118c2ecf20Sopenharmony_ci		mod_timer(&d->timer, jiffies + TIPC_DISC_INIT);
3128c2ecf20Sopenharmony_ci		spin_unlock_bh(&d->lock);
3138c2ecf20Sopenharmony_ci		schedule_work(&tn->work);
3148c2ecf20Sopenharmony_ci		return;
3158c2ecf20Sopenharmony_ci	}
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci	/* Adjust timeout interval according to discovery phase */
3188c2ecf20Sopenharmony_ci	if (time_before(jiffies, tn->addr_trial_end)) {
3198c2ecf20Sopenharmony_ci		d->timer_intv = TIPC_DISC_INIT;
3208c2ecf20Sopenharmony_ci	} else {
3218c2ecf20Sopenharmony_ci		d->timer_intv *= 2;
3228c2ecf20Sopenharmony_ci		if (d->num_nodes && d->timer_intv > TIPC_DISC_SLOW)
3238c2ecf20Sopenharmony_ci			d->timer_intv = TIPC_DISC_SLOW;
3248c2ecf20Sopenharmony_ci		else if (!d->num_nodes && d->timer_intv > TIPC_DISC_FAST)
3258c2ecf20Sopenharmony_ci			d->timer_intv = TIPC_DISC_FAST;
3268c2ecf20Sopenharmony_ci		msg_set_type(buf_msg(d->skb), DSC_REQ_MSG);
3278c2ecf20Sopenharmony_ci		msg_set_prevnode(buf_msg(d->skb), tn->trial_addr);
3288c2ecf20Sopenharmony_ci	}
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci	mod_timer(&d->timer, jiffies + d->timer_intv);
3318c2ecf20Sopenharmony_ci	memcpy(&maddr, &d->dest, sizeof(maddr));
3328c2ecf20Sopenharmony_ci	skb = skb_clone(d->skb, GFP_ATOMIC);
3338c2ecf20Sopenharmony_ci	bearer_id = d->bearer_id;
3348c2ecf20Sopenharmony_ciexit:
3358c2ecf20Sopenharmony_ci	spin_unlock_bh(&d->lock);
3368c2ecf20Sopenharmony_ci	if (skb)
3378c2ecf20Sopenharmony_ci		tipc_bearer_xmit_skb(net, bearer_id, skb, &maddr);
3388c2ecf20Sopenharmony_ci}
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_ci/**
3418c2ecf20Sopenharmony_ci * tipc_disc_create - create object to send periodic link setup requests
3428c2ecf20Sopenharmony_ci * @net: the applicable net namespace
3438c2ecf20Sopenharmony_ci * @b: ptr to bearer issuing requests
3448c2ecf20Sopenharmony_ci * @dest: destination address for request messages
3458c2ecf20Sopenharmony_ci * @skb: pointer to created frame
3468c2ecf20Sopenharmony_ci *
3478c2ecf20Sopenharmony_ci * Returns 0 if successful, otherwise -errno.
3488c2ecf20Sopenharmony_ci */
3498c2ecf20Sopenharmony_ciint tipc_disc_create(struct net *net, struct tipc_bearer *b,
3508c2ecf20Sopenharmony_ci		     struct tipc_media_addr *dest, struct sk_buff **skb)
3518c2ecf20Sopenharmony_ci{
3528c2ecf20Sopenharmony_ci	struct tipc_net *tn = tipc_net(net);
3538c2ecf20Sopenharmony_ci	struct tipc_discoverer *d;
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_ci	d = kmalloc(sizeof(*d), GFP_ATOMIC);
3568c2ecf20Sopenharmony_ci	if (!d)
3578c2ecf20Sopenharmony_ci		return -ENOMEM;
3588c2ecf20Sopenharmony_ci	d->skb = tipc_buf_acquire(MAX_H_SIZE + NODE_ID_LEN, GFP_ATOMIC);
3598c2ecf20Sopenharmony_ci	if (!d->skb) {
3608c2ecf20Sopenharmony_ci		kfree(d);
3618c2ecf20Sopenharmony_ci		return -ENOMEM;
3628c2ecf20Sopenharmony_ci	}
3638c2ecf20Sopenharmony_ci	tipc_disc_init_msg(net, d->skb, DSC_REQ_MSG, b);
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci	/* Do we need an address trial period first ? */
3668c2ecf20Sopenharmony_ci	if (!tipc_own_addr(net)) {
3678c2ecf20Sopenharmony_ci		tn->addr_trial_end = jiffies + msecs_to_jiffies(1000);
3688c2ecf20Sopenharmony_ci		msg_set_type(buf_msg(d->skb), DSC_TRIAL_MSG);
3698c2ecf20Sopenharmony_ci	}
3708c2ecf20Sopenharmony_ci	memcpy(&d->dest, dest, sizeof(*dest));
3718c2ecf20Sopenharmony_ci	d->net = net;
3728c2ecf20Sopenharmony_ci	d->bearer_id = b->identity;
3738c2ecf20Sopenharmony_ci	d->domain = b->domain;
3748c2ecf20Sopenharmony_ci	d->num_nodes = 0;
3758c2ecf20Sopenharmony_ci	d->timer_intv = TIPC_DISC_INIT;
3768c2ecf20Sopenharmony_ci	spin_lock_init(&d->lock);
3778c2ecf20Sopenharmony_ci	timer_setup(&d->timer, tipc_disc_timeout, 0);
3788c2ecf20Sopenharmony_ci	mod_timer(&d->timer, jiffies + d->timer_intv);
3798c2ecf20Sopenharmony_ci	b->disc = d;
3808c2ecf20Sopenharmony_ci	*skb = skb_clone(d->skb, GFP_ATOMIC);
3818c2ecf20Sopenharmony_ci	return 0;
3828c2ecf20Sopenharmony_ci}
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_ci/**
3858c2ecf20Sopenharmony_ci * tipc_disc_delete - destroy object sending periodic link setup requests
3868c2ecf20Sopenharmony_ci * @d: ptr to link duest structure
3878c2ecf20Sopenharmony_ci */
3888c2ecf20Sopenharmony_civoid tipc_disc_delete(struct tipc_discoverer *d)
3898c2ecf20Sopenharmony_ci{
3908c2ecf20Sopenharmony_ci	del_timer_sync(&d->timer);
3918c2ecf20Sopenharmony_ci	kfree_skb(d->skb);
3928c2ecf20Sopenharmony_ci	kfree(d);
3938c2ecf20Sopenharmony_ci}
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_ci/**
3968c2ecf20Sopenharmony_ci * tipc_disc_reset - reset object to send periodic link setup requests
3978c2ecf20Sopenharmony_ci * @net: the applicable net namespace
3988c2ecf20Sopenharmony_ci * @b: ptr to bearer issuing requests
3998c2ecf20Sopenharmony_ci */
4008c2ecf20Sopenharmony_civoid tipc_disc_reset(struct net *net, struct tipc_bearer *b)
4018c2ecf20Sopenharmony_ci{
4028c2ecf20Sopenharmony_ci	struct tipc_discoverer *d = b->disc;
4038c2ecf20Sopenharmony_ci	struct tipc_media_addr maddr;
4048c2ecf20Sopenharmony_ci	struct sk_buff *skb;
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_ci	spin_lock_bh(&d->lock);
4078c2ecf20Sopenharmony_ci	tipc_disc_init_msg(net, d->skb, DSC_REQ_MSG, b);
4088c2ecf20Sopenharmony_ci	d->net = net;
4098c2ecf20Sopenharmony_ci	d->bearer_id = b->identity;
4108c2ecf20Sopenharmony_ci	d->domain = b->domain;
4118c2ecf20Sopenharmony_ci	d->num_nodes = 0;
4128c2ecf20Sopenharmony_ci	d->timer_intv = TIPC_DISC_INIT;
4138c2ecf20Sopenharmony_ci	memcpy(&maddr, &d->dest, sizeof(maddr));
4148c2ecf20Sopenharmony_ci	mod_timer(&d->timer, jiffies + d->timer_intv);
4158c2ecf20Sopenharmony_ci	skb = skb_clone(d->skb, GFP_ATOMIC);
4168c2ecf20Sopenharmony_ci	spin_unlock_bh(&d->lock);
4178c2ecf20Sopenharmony_ci	if (skb)
4188c2ecf20Sopenharmony_ci		tipc_bearer_xmit_skb(net, b->identity, skb, &maddr);
4198c2ecf20Sopenharmony_ci}
420