1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * net/tipc/discover.c
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * Copyright (c) 2003-2006, 2014-2018, Ericsson AB
5*4882a593Smuzhiyun * Copyright (c) 2005-2006, 2010-2011, Wind River Systems
6*4882a593Smuzhiyun * All rights reserved.
7*4882a593Smuzhiyun *
8*4882a593Smuzhiyun * Redistribution and use in source and binary forms, with or without
9*4882a593Smuzhiyun * modification, are permitted provided that the following conditions are met:
10*4882a593Smuzhiyun *
11*4882a593Smuzhiyun * 1. Redistributions of source code must retain the above copyright
12*4882a593Smuzhiyun * notice, this list of conditions and the following disclaimer.
13*4882a593Smuzhiyun * 2. Redistributions in binary form must reproduce the above copyright
14*4882a593Smuzhiyun * notice, this list of conditions and the following disclaimer in the
15*4882a593Smuzhiyun * documentation and/or other materials provided with the distribution.
16*4882a593Smuzhiyun * 3. Neither the names of the copyright holders nor the names of its
17*4882a593Smuzhiyun * contributors may be used to endorse or promote products derived from
18*4882a593Smuzhiyun * this software without specific prior written permission.
19*4882a593Smuzhiyun *
20*4882a593Smuzhiyun * Alternatively, this software may be distributed under the terms of the
21*4882a593Smuzhiyun * GNU General Public License ("GPL") version 2 as published by the Free
22*4882a593Smuzhiyun * Software Foundation.
23*4882a593Smuzhiyun *
24*4882a593Smuzhiyun * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
25*4882a593Smuzhiyun * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26*4882a593Smuzhiyun * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27*4882a593Smuzhiyun * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
28*4882a593Smuzhiyun * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29*4882a593Smuzhiyun * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30*4882a593Smuzhiyun * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31*4882a593Smuzhiyun * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
32*4882a593Smuzhiyun * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33*4882a593Smuzhiyun * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34*4882a593Smuzhiyun * POSSIBILITY OF SUCH DAMAGE.
35*4882a593Smuzhiyun */
36*4882a593Smuzhiyun
37*4882a593Smuzhiyun #include "core.h"
38*4882a593Smuzhiyun #include "node.h"
39*4882a593Smuzhiyun #include "discover.h"
40*4882a593Smuzhiyun
41*4882a593Smuzhiyun /* min delay during bearer start up */
42*4882a593Smuzhiyun #define TIPC_DISC_INIT msecs_to_jiffies(125)
43*4882a593Smuzhiyun /* max delay if bearer has no links */
44*4882a593Smuzhiyun #define TIPC_DISC_FAST msecs_to_jiffies(1000)
45*4882a593Smuzhiyun /* max delay if bearer has links */
46*4882a593Smuzhiyun #define TIPC_DISC_SLOW msecs_to_jiffies(60000)
47*4882a593Smuzhiyun /* indicates no timer in use */
48*4882a593Smuzhiyun #define TIPC_DISC_INACTIVE 0xffffffff
49*4882a593Smuzhiyun
50*4882a593Smuzhiyun /**
51*4882a593Smuzhiyun * struct tipc_discoverer - information about an ongoing link setup request
52*4882a593Smuzhiyun * @bearer_id: identity of bearer issuing requests
53*4882a593Smuzhiyun * @net: network namespace instance
54*4882a593Smuzhiyun * @dest: destination address for request messages
55*4882a593Smuzhiyun * @domain: network domain to which links can be established
56*4882a593Smuzhiyun * @num_nodes: number of nodes currently discovered (i.e. with an active link)
57*4882a593Smuzhiyun * @lock: spinlock for controlling access to requests
58*4882a593Smuzhiyun * @skb: request message to be (repeatedly) sent
59*4882a593Smuzhiyun * @timer: timer governing period between requests
60*4882a593Smuzhiyun * @timer_intv: current interval between requests (in ms)
61*4882a593Smuzhiyun */
62*4882a593Smuzhiyun struct tipc_discoverer {
63*4882a593Smuzhiyun u32 bearer_id;
64*4882a593Smuzhiyun struct tipc_media_addr dest;
65*4882a593Smuzhiyun struct net *net;
66*4882a593Smuzhiyun u32 domain;
67*4882a593Smuzhiyun int num_nodes;
68*4882a593Smuzhiyun spinlock_t lock;
69*4882a593Smuzhiyun struct sk_buff *skb;
70*4882a593Smuzhiyun struct timer_list timer;
71*4882a593Smuzhiyun unsigned long timer_intv;
72*4882a593Smuzhiyun };
73*4882a593Smuzhiyun
74*4882a593Smuzhiyun /**
75*4882a593Smuzhiyun * tipc_disc_init_msg - initialize a link setup message
76*4882a593Smuzhiyun * @net: the applicable net namespace
77*4882a593Smuzhiyun * @mtyp: message type (request or response)
78*4882a593Smuzhiyun * @b: ptr to bearer issuing message
79*4882a593Smuzhiyun */
tipc_disc_init_msg(struct net * net,struct sk_buff * skb,u32 mtyp,struct tipc_bearer * b)80*4882a593Smuzhiyun static void tipc_disc_init_msg(struct net *net, struct sk_buff *skb,
81*4882a593Smuzhiyun u32 mtyp, struct tipc_bearer *b)
82*4882a593Smuzhiyun {
83*4882a593Smuzhiyun struct tipc_net *tn = tipc_net(net);
84*4882a593Smuzhiyun u32 dest_domain = b->domain;
85*4882a593Smuzhiyun struct tipc_msg *hdr;
86*4882a593Smuzhiyun
87*4882a593Smuzhiyun hdr = buf_msg(skb);
88*4882a593Smuzhiyun tipc_msg_init(tn->trial_addr, hdr, LINK_CONFIG, mtyp,
89*4882a593Smuzhiyun MAX_H_SIZE, dest_domain);
90*4882a593Smuzhiyun msg_set_size(hdr, MAX_H_SIZE + NODE_ID_LEN);
91*4882a593Smuzhiyun msg_set_non_seq(hdr, 1);
92*4882a593Smuzhiyun msg_set_node_sig(hdr, tn->random);
93*4882a593Smuzhiyun msg_set_node_capabilities(hdr, TIPC_NODE_CAPABILITIES);
94*4882a593Smuzhiyun msg_set_dest_domain(hdr, dest_domain);
95*4882a593Smuzhiyun msg_set_bc_netid(hdr, tn->net_id);
96*4882a593Smuzhiyun b->media->addr2msg(msg_media_addr(hdr), &b->addr);
97*4882a593Smuzhiyun msg_set_peer_net_hash(hdr, tipc_net_hash_mixes(net, tn->random));
98*4882a593Smuzhiyun msg_set_node_id(hdr, tipc_own_id(net));
99*4882a593Smuzhiyun }
100*4882a593Smuzhiyun
tipc_disc_msg_xmit(struct net * net,u32 mtyp,u32 dst,u32 src,u32 sugg_addr,struct tipc_media_addr * maddr,struct tipc_bearer * b)101*4882a593Smuzhiyun static void tipc_disc_msg_xmit(struct net *net, u32 mtyp, u32 dst,
102*4882a593Smuzhiyun u32 src, u32 sugg_addr,
103*4882a593Smuzhiyun struct tipc_media_addr *maddr,
104*4882a593Smuzhiyun struct tipc_bearer *b)
105*4882a593Smuzhiyun {
106*4882a593Smuzhiyun struct tipc_msg *hdr;
107*4882a593Smuzhiyun struct sk_buff *skb;
108*4882a593Smuzhiyun
109*4882a593Smuzhiyun skb = tipc_buf_acquire(MAX_H_SIZE + NODE_ID_LEN, GFP_ATOMIC);
110*4882a593Smuzhiyun if (!skb)
111*4882a593Smuzhiyun return;
112*4882a593Smuzhiyun hdr = buf_msg(skb);
113*4882a593Smuzhiyun tipc_disc_init_msg(net, skb, mtyp, b);
114*4882a593Smuzhiyun msg_set_sugg_node_addr(hdr, sugg_addr);
115*4882a593Smuzhiyun msg_set_dest_domain(hdr, dst);
116*4882a593Smuzhiyun tipc_bearer_xmit_skb(net, b->identity, skb, maddr);
117*4882a593Smuzhiyun }
118*4882a593Smuzhiyun
119*4882a593Smuzhiyun /**
120*4882a593Smuzhiyun * disc_dupl_alert - issue node address duplication alert
121*4882a593Smuzhiyun * @b: pointer to bearer detecting duplication
122*4882a593Smuzhiyun * @node_addr: duplicated node address
123*4882a593Smuzhiyun * @media_addr: media address advertised by duplicated node
124*4882a593Smuzhiyun */
disc_dupl_alert(struct tipc_bearer * b,u32 node_addr,struct tipc_media_addr * media_addr)125*4882a593Smuzhiyun static void disc_dupl_alert(struct tipc_bearer *b, u32 node_addr,
126*4882a593Smuzhiyun struct tipc_media_addr *media_addr)
127*4882a593Smuzhiyun {
128*4882a593Smuzhiyun char media_addr_str[64];
129*4882a593Smuzhiyun
130*4882a593Smuzhiyun tipc_media_addr_printf(media_addr_str, sizeof(media_addr_str),
131*4882a593Smuzhiyun media_addr);
132*4882a593Smuzhiyun pr_warn("Duplicate %x using %s seen on <%s>\n", node_addr,
133*4882a593Smuzhiyun media_addr_str, b->name);
134*4882a593Smuzhiyun }
135*4882a593Smuzhiyun
136*4882a593Smuzhiyun /* tipc_disc_addr_trial(): - handle an address uniqueness trial from peer
137*4882a593Smuzhiyun * Returns true if message should be dropped by caller, i.e., if it is a
138*4882a593Smuzhiyun * trial message or we are inside trial period. Otherwise false.
139*4882a593Smuzhiyun */
tipc_disc_addr_trial_msg(struct tipc_discoverer * d,struct tipc_media_addr * maddr,struct tipc_bearer * b,u32 dst,u32 src,u32 sugg_addr,u8 * peer_id,int mtyp)140*4882a593Smuzhiyun static bool tipc_disc_addr_trial_msg(struct tipc_discoverer *d,
141*4882a593Smuzhiyun struct tipc_media_addr *maddr,
142*4882a593Smuzhiyun struct tipc_bearer *b,
143*4882a593Smuzhiyun u32 dst, u32 src,
144*4882a593Smuzhiyun u32 sugg_addr,
145*4882a593Smuzhiyun u8 *peer_id,
146*4882a593Smuzhiyun int mtyp)
147*4882a593Smuzhiyun {
148*4882a593Smuzhiyun struct net *net = d->net;
149*4882a593Smuzhiyun struct tipc_net *tn = tipc_net(net);
150*4882a593Smuzhiyun u32 self = tipc_own_addr(net);
151*4882a593Smuzhiyun bool trial = time_before(jiffies, tn->addr_trial_end) && !self;
152*4882a593Smuzhiyun
153*4882a593Smuzhiyun if (mtyp == DSC_TRIAL_FAIL_MSG) {
154*4882a593Smuzhiyun if (!trial)
155*4882a593Smuzhiyun return true;
156*4882a593Smuzhiyun
157*4882a593Smuzhiyun /* Ignore if somebody else already gave new suggestion */
158*4882a593Smuzhiyun if (dst != tn->trial_addr)
159*4882a593Smuzhiyun return true;
160*4882a593Smuzhiyun
161*4882a593Smuzhiyun /* Otherwise update trial address and restart trial period */
162*4882a593Smuzhiyun tn->trial_addr = sugg_addr;
163*4882a593Smuzhiyun msg_set_prevnode(buf_msg(d->skb), sugg_addr);
164*4882a593Smuzhiyun tn->addr_trial_end = jiffies + msecs_to_jiffies(1000);
165*4882a593Smuzhiyun return true;
166*4882a593Smuzhiyun }
167*4882a593Smuzhiyun
168*4882a593Smuzhiyun /* Apply trial address if we just left trial period */
169*4882a593Smuzhiyun if (!trial && !self) {
170*4882a593Smuzhiyun schedule_work(&tn->work);
171*4882a593Smuzhiyun msg_set_prevnode(buf_msg(d->skb), tn->trial_addr);
172*4882a593Smuzhiyun msg_set_type(buf_msg(d->skb), DSC_REQ_MSG);
173*4882a593Smuzhiyun }
174*4882a593Smuzhiyun
175*4882a593Smuzhiyun /* Accept regular link requests/responses only after trial period */
176*4882a593Smuzhiyun if (mtyp != DSC_TRIAL_MSG)
177*4882a593Smuzhiyun return trial;
178*4882a593Smuzhiyun
179*4882a593Smuzhiyun sugg_addr = tipc_node_try_addr(net, peer_id, src);
180*4882a593Smuzhiyun if (sugg_addr)
181*4882a593Smuzhiyun tipc_disc_msg_xmit(net, DSC_TRIAL_FAIL_MSG, src,
182*4882a593Smuzhiyun self, sugg_addr, maddr, b);
183*4882a593Smuzhiyun return true;
184*4882a593Smuzhiyun }
185*4882a593Smuzhiyun
186*4882a593Smuzhiyun /**
187*4882a593Smuzhiyun * tipc_disc_rcv - handle incoming discovery message (request or response)
188*4882a593Smuzhiyun * @net: applicable net namespace
189*4882a593Smuzhiyun * @skb: buffer containing message
190*4882a593Smuzhiyun * @b: bearer that message arrived on
191*4882a593Smuzhiyun */
tipc_disc_rcv(struct net * net,struct sk_buff * skb,struct tipc_bearer * b)192*4882a593Smuzhiyun void tipc_disc_rcv(struct net *net, struct sk_buff *skb,
193*4882a593Smuzhiyun struct tipc_bearer *b)
194*4882a593Smuzhiyun {
195*4882a593Smuzhiyun struct tipc_net *tn = tipc_net(net);
196*4882a593Smuzhiyun struct tipc_msg *hdr = buf_msg(skb);
197*4882a593Smuzhiyun u32 pnet_hash = msg_peer_net_hash(hdr);
198*4882a593Smuzhiyun u16 caps = msg_node_capabilities(hdr);
199*4882a593Smuzhiyun bool legacy = tn->legacy_addr_format;
200*4882a593Smuzhiyun u32 sugg = msg_sugg_node_addr(hdr);
201*4882a593Smuzhiyun u32 signature = msg_node_sig(hdr);
202*4882a593Smuzhiyun u8 peer_id[NODE_ID_LEN] = {0,};
203*4882a593Smuzhiyun u32 dst = msg_dest_domain(hdr);
204*4882a593Smuzhiyun u32 net_id = msg_bc_netid(hdr);
205*4882a593Smuzhiyun struct tipc_media_addr maddr;
206*4882a593Smuzhiyun u32 src = msg_prevnode(hdr);
207*4882a593Smuzhiyun u32 mtyp = msg_type(hdr);
208*4882a593Smuzhiyun bool dupl_addr = false;
209*4882a593Smuzhiyun bool respond = false;
210*4882a593Smuzhiyun u32 self;
211*4882a593Smuzhiyun int err;
212*4882a593Smuzhiyun
213*4882a593Smuzhiyun if (skb_linearize(skb)) {
214*4882a593Smuzhiyun kfree_skb(skb);
215*4882a593Smuzhiyun return;
216*4882a593Smuzhiyun }
217*4882a593Smuzhiyun hdr = buf_msg(skb);
218*4882a593Smuzhiyun
219*4882a593Smuzhiyun if (caps & TIPC_NODE_ID128)
220*4882a593Smuzhiyun memcpy(peer_id, msg_node_id(hdr), NODE_ID_LEN);
221*4882a593Smuzhiyun else
222*4882a593Smuzhiyun sprintf(peer_id, "%x", src);
223*4882a593Smuzhiyun
224*4882a593Smuzhiyun err = b->media->msg2addr(b, &maddr, msg_media_addr(hdr));
225*4882a593Smuzhiyun kfree_skb(skb);
226*4882a593Smuzhiyun if (err || maddr.broadcast) {
227*4882a593Smuzhiyun pr_warn_ratelimited("Rcv corrupt discovery message\n");
228*4882a593Smuzhiyun return;
229*4882a593Smuzhiyun }
230*4882a593Smuzhiyun /* Ignore discovery messages from own node */
231*4882a593Smuzhiyun if (!memcmp(&maddr, &b->addr, sizeof(maddr)))
232*4882a593Smuzhiyun return;
233*4882a593Smuzhiyun if (net_id != tn->net_id)
234*4882a593Smuzhiyun return;
235*4882a593Smuzhiyun if (tipc_disc_addr_trial_msg(b->disc, &maddr, b, dst,
236*4882a593Smuzhiyun src, sugg, peer_id, mtyp))
237*4882a593Smuzhiyun return;
238*4882a593Smuzhiyun self = tipc_own_addr(net);
239*4882a593Smuzhiyun
240*4882a593Smuzhiyun /* Message from somebody using this node's address */
241*4882a593Smuzhiyun if (in_own_node(net, src)) {
242*4882a593Smuzhiyun disc_dupl_alert(b, self, &maddr);
243*4882a593Smuzhiyun return;
244*4882a593Smuzhiyun }
245*4882a593Smuzhiyun if (!tipc_in_scope(legacy, dst, self))
246*4882a593Smuzhiyun return;
247*4882a593Smuzhiyun if (!tipc_in_scope(legacy, b->domain, src))
248*4882a593Smuzhiyun return;
249*4882a593Smuzhiyun tipc_node_check_dest(net, src, peer_id, b, caps, signature, pnet_hash,
250*4882a593Smuzhiyun &maddr, &respond, &dupl_addr);
251*4882a593Smuzhiyun if (dupl_addr)
252*4882a593Smuzhiyun disc_dupl_alert(b, src, &maddr);
253*4882a593Smuzhiyun if (!respond)
254*4882a593Smuzhiyun return;
255*4882a593Smuzhiyun if (mtyp != DSC_REQ_MSG)
256*4882a593Smuzhiyun return;
257*4882a593Smuzhiyun tipc_disc_msg_xmit(net, DSC_RESP_MSG, src, self, 0, &maddr, b);
258*4882a593Smuzhiyun }
259*4882a593Smuzhiyun
260*4882a593Smuzhiyun /* tipc_disc_add_dest - increment set of discovered nodes
261*4882a593Smuzhiyun */
tipc_disc_add_dest(struct tipc_discoverer * d)262*4882a593Smuzhiyun void tipc_disc_add_dest(struct tipc_discoverer *d)
263*4882a593Smuzhiyun {
264*4882a593Smuzhiyun spin_lock_bh(&d->lock);
265*4882a593Smuzhiyun d->num_nodes++;
266*4882a593Smuzhiyun spin_unlock_bh(&d->lock);
267*4882a593Smuzhiyun }
268*4882a593Smuzhiyun
269*4882a593Smuzhiyun /* tipc_disc_remove_dest - decrement set of discovered nodes
270*4882a593Smuzhiyun */
tipc_disc_remove_dest(struct tipc_discoverer * d)271*4882a593Smuzhiyun void tipc_disc_remove_dest(struct tipc_discoverer *d)
272*4882a593Smuzhiyun {
273*4882a593Smuzhiyun int intv, num;
274*4882a593Smuzhiyun
275*4882a593Smuzhiyun spin_lock_bh(&d->lock);
276*4882a593Smuzhiyun d->num_nodes--;
277*4882a593Smuzhiyun num = d->num_nodes;
278*4882a593Smuzhiyun intv = d->timer_intv;
279*4882a593Smuzhiyun if (!num && (intv == TIPC_DISC_INACTIVE || intv > TIPC_DISC_FAST)) {
280*4882a593Smuzhiyun d->timer_intv = TIPC_DISC_INIT;
281*4882a593Smuzhiyun mod_timer(&d->timer, jiffies + d->timer_intv);
282*4882a593Smuzhiyun }
283*4882a593Smuzhiyun spin_unlock_bh(&d->lock);
284*4882a593Smuzhiyun }
285*4882a593Smuzhiyun
286*4882a593Smuzhiyun /* tipc_disc_timeout - send a periodic link setup request
287*4882a593Smuzhiyun * Called whenever a link setup request timer associated with a bearer expires.
288*4882a593Smuzhiyun * - Keep doubling time between sent request until limit is reached;
289*4882a593Smuzhiyun * - Hold at fast polling rate if we don't have any associated nodes
290*4882a593Smuzhiyun * - Otherwise hold at slow polling rate
291*4882a593Smuzhiyun */
tipc_disc_timeout(struct timer_list * t)292*4882a593Smuzhiyun static void tipc_disc_timeout(struct timer_list *t)
293*4882a593Smuzhiyun {
294*4882a593Smuzhiyun struct tipc_discoverer *d = from_timer(d, t, timer);
295*4882a593Smuzhiyun struct tipc_net *tn = tipc_net(d->net);
296*4882a593Smuzhiyun struct tipc_media_addr maddr;
297*4882a593Smuzhiyun struct sk_buff *skb = NULL;
298*4882a593Smuzhiyun struct net *net = d->net;
299*4882a593Smuzhiyun u32 bearer_id;
300*4882a593Smuzhiyun
301*4882a593Smuzhiyun spin_lock_bh(&d->lock);
302*4882a593Smuzhiyun
303*4882a593Smuzhiyun /* Stop searching if only desired node has been found */
304*4882a593Smuzhiyun if (tipc_node(d->domain) && d->num_nodes) {
305*4882a593Smuzhiyun d->timer_intv = TIPC_DISC_INACTIVE;
306*4882a593Smuzhiyun goto exit;
307*4882a593Smuzhiyun }
308*4882a593Smuzhiyun
309*4882a593Smuzhiyun /* Did we just leave trial period ? */
310*4882a593Smuzhiyun if (!time_before(jiffies, tn->addr_trial_end) && !tipc_own_addr(net)) {
311*4882a593Smuzhiyun mod_timer(&d->timer, jiffies + TIPC_DISC_INIT);
312*4882a593Smuzhiyun spin_unlock_bh(&d->lock);
313*4882a593Smuzhiyun schedule_work(&tn->work);
314*4882a593Smuzhiyun return;
315*4882a593Smuzhiyun }
316*4882a593Smuzhiyun
317*4882a593Smuzhiyun /* Adjust timeout interval according to discovery phase */
318*4882a593Smuzhiyun if (time_before(jiffies, tn->addr_trial_end)) {
319*4882a593Smuzhiyun d->timer_intv = TIPC_DISC_INIT;
320*4882a593Smuzhiyun } else {
321*4882a593Smuzhiyun d->timer_intv *= 2;
322*4882a593Smuzhiyun if (d->num_nodes && d->timer_intv > TIPC_DISC_SLOW)
323*4882a593Smuzhiyun d->timer_intv = TIPC_DISC_SLOW;
324*4882a593Smuzhiyun else if (!d->num_nodes && d->timer_intv > TIPC_DISC_FAST)
325*4882a593Smuzhiyun d->timer_intv = TIPC_DISC_FAST;
326*4882a593Smuzhiyun msg_set_type(buf_msg(d->skb), DSC_REQ_MSG);
327*4882a593Smuzhiyun msg_set_prevnode(buf_msg(d->skb), tn->trial_addr);
328*4882a593Smuzhiyun }
329*4882a593Smuzhiyun
330*4882a593Smuzhiyun mod_timer(&d->timer, jiffies + d->timer_intv);
331*4882a593Smuzhiyun memcpy(&maddr, &d->dest, sizeof(maddr));
332*4882a593Smuzhiyun skb = skb_clone(d->skb, GFP_ATOMIC);
333*4882a593Smuzhiyun bearer_id = d->bearer_id;
334*4882a593Smuzhiyun exit:
335*4882a593Smuzhiyun spin_unlock_bh(&d->lock);
336*4882a593Smuzhiyun if (skb)
337*4882a593Smuzhiyun tipc_bearer_xmit_skb(net, bearer_id, skb, &maddr);
338*4882a593Smuzhiyun }
339*4882a593Smuzhiyun
340*4882a593Smuzhiyun /**
341*4882a593Smuzhiyun * tipc_disc_create - create object to send periodic link setup requests
342*4882a593Smuzhiyun * @net: the applicable net namespace
343*4882a593Smuzhiyun * @b: ptr to bearer issuing requests
344*4882a593Smuzhiyun * @dest: destination address for request messages
345*4882a593Smuzhiyun * @skb: pointer to created frame
346*4882a593Smuzhiyun *
347*4882a593Smuzhiyun * Returns 0 if successful, otherwise -errno.
348*4882a593Smuzhiyun */
tipc_disc_create(struct net * net,struct tipc_bearer * b,struct tipc_media_addr * dest,struct sk_buff ** skb)349*4882a593Smuzhiyun int tipc_disc_create(struct net *net, struct tipc_bearer *b,
350*4882a593Smuzhiyun struct tipc_media_addr *dest, struct sk_buff **skb)
351*4882a593Smuzhiyun {
352*4882a593Smuzhiyun struct tipc_net *tn = tipc_net(net);
353*4882a593Smuzhiyun struct tipc_discoverer *d;
354*4882a593Smuzhiyun
355*4882a593Smuzhiyun d = kmalloc(sizeof(*d), GFP_ATOMIC);
356*4882a593Smuzhiyun if (!d)
357*4882a593Smuzhiyun return -ENOMEM;
358*4882a593Smuzhiyun d->skb = tipc_buf_acquire(MAX_H_SIZE + NODE_ID_LEN, GFP_ATOMIC);
359*4882a593Smuzhiyun if (!d->skb) {
360*4882a593Smuzhiyun kfree(d);
361*4882a593Smuzhiyun return -ENOMEM;
362*4882a593Smuzhiyun }
363*4882a593Smuzhiyun tipc_disc_init_msg(net, d->skb, DSC_REQ_MSG, b);
364*4882a593Smuzhiyun
365*4882a593Smuzhiyun /* Do we need an address trial period first ? */
366*4882a593Smuzhiyun if (!tipc_own_addr(net)) {
367*4882a593Smuzhiyun tn->addr_trial_end = jiffies + msecs_to_jiffies(1000);
368*4882a593Smuzhiyun msg_set_type(buf_msg(d->skb), DSC_TRIAL_MSG);
369*4882a593Smuzhiyun }
370*4882a593Smuzhiyun memcpy(&d->dest, dest, sizeof(*dest));
371*4882a593Smuzhiyun d->net = net;
372*4882a593Smuzhiyun d->bearer_id = b->identity;
373*4882a593Smuzhiyun d->domain = b->domain;
374*4882a593Smuzhiyun d->num_nodes = 0;
375*4882a593Smuzhiyun d->timer_intv = TIPC_DISC_INIT;
376*4882a593Smuzhiyun spin_lock_init(&d->lock);
377*4882a593Smuzhiyun timer_setup(&d->timer, tipc_disc_timeout, 0);
378*4882a593Smuzhiyun mod_timer(&d->timer, jiffies + d->timer_intv);
379*4882a593Smuzhiyun b->disc = d;
380*4882a593Smuzhiyun *skb = skb_clone(d->skb, GFP_ATOMIC);
381*4882a593Smuzhiyun return 0;
382*4882a593Smuzhiyun }
383*4882a593Smuzhiyun
384*4882a593Smuzhiyun /**
385*4882a593Smuzhiyun * tipc_disc_delete - destroy object sending periodic link setup requests
386*4882a593Smuzhiyun * @d: ptr to link duest structure
387*4882a593Smuzhiyun */
tipc_disc_delete(struct tipc_discoverer * d)388*4882a593Smuzhiyun void tipc_disc_delete(struct tipc_discoverer *d)
389*4882a593Smuzhiyun {
390*4882a593Smuzhiyun del_timer_sync(&d->timer);
391*4882a593Smuzhiyun kfree_skb(d->skb);
392*4882a593Smuzhiyun kfree(d);
393*4882a593Smuzhiyun }
394*4882a593Smuzhiyun
395*4882a593Smuzhiyun /**
396*4882a593Smuzhiyun * tipc_disc_reset - reset object to send periodic link setup requests
397*4882a593Smuzhiyun * @net: the applicable net namespace
398*4882a593Smuzhiyun * @b: ptr to bearer issuing requests
399*4882a593Smuzhiyun */
tipc_disc_reset(struct net * net,struct tipc_bearer * b)400*4882a593Smuzhiyun void tipc_disc_reset(struct net *net, struct tipc_bearer *b)
401*4882a593Smuzhiyun {
402*4882a593Smuzhiyun struct tipc_discoverer *d = b->disc;
403*4882a593Smuzhiyun struct tipc_media_addr maddr;
404*4882a593Smuzhiyun struct sk_buff *skb;
405*4882a593Smuzhiyun
406*4882a593Smuzhiyun spin_lock_bh(&d->lock);
407*4882a593Smuzhiyun tipc_disc_init_msg(net, d->skb, DSC_REQ_MSG, b);
408*4882a593Smuzhiyun d->net = net;
409*4882a593Smuzhiyun d->bearer_id = b->identity;
410*4882a593Smuzhiyun d->domain = b->domain;
411*4882a593Smuzhiyun d->num_nodes = 0;
412*4882a593Smuzhiyun d->timer_intv = TIPC_DISC_INIT;
413*4882a593Smuzhiyun memcpy(&maddr, &d->dest, sizeof(maddr));
414*4882a593Smuzhiyun mod_timer(&d->timer, jiffies + d->timer_intv);
415*4882a593Smuzhiyun skb = skb_clone(d->skb, GFP_ATOMIC);
416*4882a593Smuzhiyun spin_unlock_bh(&d->lock);
417*4882a593Smuzhiyun if (skb)
418*4882a593Smuzhiyun tipc_bearer_xmit_skb(net, b->identity, skb, &maddr);
419*4882a593Smuzhiyun }
420