Blame view

net/tipc/bcast.c 21.6 KB
b97bf3fd8   Per Liden   [TIPC] Initial merge
1
2
  /*
   * net/tipc/bcast.c: TIPC broadcast code
c43072852   YOSHIFUJI Hideaki   [NET] TIPC: Fix w...
3
   *
4c94cc2d3   Jon Maloy   tipc: fall back t...
4
   * Copyright (c) 2004-2006, 2014-2017, Ericsson AB
b97bf3fd8   Per Liden   [TIPC] Initial merge
5
   * Copyright (c) 2004, Intel Corporation.
2d627b92f   Allan Stephens   tipc: Combine bea...
6
   * Copyright (c) 2005, 2010-2011, Wind River Systems
b97bf3fd8   Per Liden   [TIPC] Initial merge
7
8
   * All rights reserved.
   *
9ea1fd3c1   Per Liden   [TIPC] License he...
9
   * Redistribution and use in source and binary forms, with or without
b97bf3fd8   Per Liden   [TIPC] Initial merge
10
11
   * modification, are permitted provided that the following conditions are met:
   *
9ea1fd3c1   Per Liden   [TIPC] License he...
12
13
14
15
16
17
18
19
   * 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.
b97bf3fd8   Per Liden   [TIPC] Initial merge
20
   *
9ea1fd3c1   Per Liden   [TIPC] License he...
21
22
23
24
25
26
27
28
29
30
31
32
33
34
   * 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
b97bf3fd8   Per Liden   [TIPC] Initial merge
35
36
   * POSSIBILITY OF SUCH DAMAGE.
   */
6beb19a62   Jon Paul Maloy   tipc: move bcast ...
37
  #include <linux/tipc_config.h>
078bec826   Jon Paul Maloy   tipc: add new fun...
38
39
  #include "socket.h"
  #include "msg.h"
b97bf3fd8   Per Liden   [TIPC] Initial merge
40
  #include "bcast.h"
6beb19a62   Jon Paul Maloy   tipc: move bcast ...
41
  #include "link.h"
2ae0b8af1   Jon Paul Maloy   tipc: add functio...
42
  #include "name_table.h"
b97bf3fd8   Per Liden   [TIPC] Initial merge
43

4c94cc2d3   Jon Maloy   tipc: fall back t...
44
45
  #define BCLINK_WIN_DEFAULT  50	/* bcast link window size (default) */
  #define BCLINK_WIN_MIN      32	/* bcast minimum link window size */
b97bf3fd8   Per Liden   [TIPC] Initial merge
46

3aec9cc93   Allan Stephens   tipc: Rename "mul...
47
  const char tipc_bclink_name[] = "broadcast-link";
b97bf3fd8   Per Liden   [TIPC] Initial merge
48

6beb19a62   Jon Paul Maloy   tipc: move bcast ...
49
  /**
2af5ae372   Jon Paul Maloy   tipc: clean up un...
50
   * struct tipc_bc_base - base structure for keeping broadcast send state
b06b281e7   Jon Paul Maloy   tipc: simplify be...
51
   * @link: broadcast send link structure
2af5ae372   Jon Paul Maloy   tipc: clean up un...
52
   * @inputq: data input queue; will only carry SOCK_WAKEUP messages
9cc1bf392   Zhenbo Gao   tipc: correct spe...
53
   * @dests: array keeping number of reachable destinations per bearer
2af5ae372   Jon Paul Maloy   tipc: clean up un...
54
   * @primary_bearer: a bearer having links to all broadcast destinations, if any
9999974a8   Jon Paul Maloy   tipc: add functio...
55
   * @bcast_support: indicates if primary bearer, if any, supports broadcast
02ec6cafd   Hoang Le   tipc: support bro...
56
   * @force_bcast: forces broadcast for multicast traffic
01fd12bb1   Jon Paul Maloy   tipc: make replic...
57
   * @rcast_support: indicates if all peer nodes support replicast
02ec6cafd   Hoang Le   tipc: support bro...
58
   * @force_rcast: forces replicast for multicast traffic
01fd12bb1   Jon Paul Maloy   tipc: make replic...
59
   * @rc_ratio: dest count as percentage of cluster size where send method changes
9cc1bf392   Zhenbo Gao   tipc: correct spe...
60
   * @bc_threshold: calculated from rc_ratio; if dests > threshold use broadcast
6beb19a62   Jon Paul Maloy   tipc: move bcast ...
61
62
   */
  struct tipc_bc_base {
323019069   Jon Paul Maloy   tipc: use explici...
63
  	struct tipc_link *link;
6beb19a62   Jon Paul Maloy   tipc: move bcast ...
64
  	struct sk_buff_head inputq;
b06b281e7   Jon Paul Maloy   tipc: simplify be...
65
66
  	int dests[MAX_BEARERS];
  	int primary_bearer;
9999974a8   Jon Paul Maloy   tipc: add functio...
67
  	bool bcast_support;
02ec6cafd   Hoang Le   tipc: support bro...
68
  	bool force_bcast;
01fd12bb1   Jon Paul Maloy   tipc: make replic...
69
  	bool rcast_support;
02ec6cafd   Hoang Le   tipc: support bro...
70
  	bool force_rcast;
01fd12bb1   Jon Paul Maloy   tipc: make replic...
71
72
  	int rc_ratio;
  	int bc_threshold;
6beb19a62   Jon Paul Maloy   tipc: move bcast ...
73
  };
5fd9fd635   Jon Paul Maloy   tipc: create broa...
74
75
76
77
  static struct tipc_bc_base *tipc_bc_base(struct net *net)
  {
  	return tipc_net(net)->bcbase;
  }
4c94cc2d3   Jon Maloy   tipc: fall back t...
78
79
80
81
  /* tipc_bcast_get_mtu(): -get the MTU currently used by broadcast link
   * Note: the MTU is decremented to give room for a tunnel header, in
   * case the message needs to be sent as replicast
   */
959e1781a   Jon Paul Maloy   tipc: introduce j...
82
  int tipc_bcast_get_mtu(struct net *net)
078bec826   Jon Paul Maloy   tipc: add new fun...
83
  {
a853e4c6d   Jon Paul Maloy   tipc: introduce r...
84
  	return tipc_link_mtu(tipc_bc_sndlink(net)) - INT_H_SIZE;
078bec826   Jon Paul Maloy   tipc: add new fun...
85
  }
01fd12bb1   Jon Paul Maloy   tipc: make replic...
86
87
88
89
90
91
92
93
94
95
96
97
  void tipc_bcast_disable_rcast(struct net *net)
  {
  	tipc_bc_base(net)->rcast_support = false;
  }
  
  static void tipc_bcbase_calc_bc_threshold(struct net *net)
  {
  	struct tipc_bc_base *bb = tipc_bc_base(net);
  	int cluster_size = tipc_link_bc_peers(tipc_bc_sndlink(net));
  
  	bb->bc_threshold = 1 + (cluster_size * bb->rc_ratio / 100);
  }
b06b281e7   Jon Paul Maloy   tipc: simplify be...
98
99
100
101
102
103
104
  /* tipc_bcbase_select_primary(): find a bearer with links to all destinations,
   *                               if any, and make it primary bearer
   */
  static void tipc_bcbase_select_primary(struct net *net)
  {
  	struct tipc_bc_base *bb = tipc_bc_base(net);
  	int all_dests =  tipc_link_bc_peers(bb->link);
9999974a8   Jon Paul Maloy   tipc: add functio...
105
  	int i, mtu, prim;
b06b281e7   Jon Paul Maloy   tipc: simplify be...
106
107
  
  	bb->primary_bearer = INVALID_BEARER_ID;
9999974a8   Jon Paul Maloy   tipc: add functio...
108
  	bb->bcast_support = true;
b06b281e7   Jon Paul Maloy   tipc: simplify be...
109
110
111
112
113
  
  	if (!all_dests)
  		return;
  
  	for (i = 0; i < MAX_BEARERS; i++) {
959e1781a   Jon Paul Maloy   tipc: introduce j...
114
115
116
117
118
119
  		if (!bb->dests[i])
  			continue;
  
  		mtu = tipc_bearer_mtu(net, i);
  		if (mtu < tipc_link_mtu(bb->link))
  			tipc_link_set_mtu(bb->link, mtu);
9999974a8   Jon Paul Maloy   tipc: add functio...
120
  		bb->bcast_support &= tipc_bearer_bcast_support(net, i);
b06b281e7   Jon Paul Maloy   tipc: simplify be...
121
122
123
124
125
126
127
128
129
  		if (bb->dests[i] < all_dests)
  			continue;
  
  		bb->primary_bearer = i;
  
  		/* Reduce risk that all nodes select same primary */
  		if ((i ^ tipc_own_addr(net)) & 1)
  			break;
  	}
9999974a8   Jon Paul Maloy   tipc: add functio...
130
131
132
  	prim = bb->primary_bearer;
  	if (prim != INVALID_BEARER_ID)
  		bb->bcast_support = tipc_bearer_bcast_support(net, prim);
b06b281e7   Jon Paul Maloy   tipc: simplify be...
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
  }
  
  void tipc_bcast_inc_bearer_dst_cnt(struct net *net, int bearer_id)
  {
  	struct tipc_bc_base *bb = tipc_bc_base(net);
  
  	tipc_bcast_lock(net);
  	bb->dests[bearer_id]++;
  	tipc_bcbase_select_primary(net);
  	tipc_bcast_unlock(net);
  }
  
  void tipc_bcast_dec_bearer_dst_cnt(struct net *net, int bearer_id)
  {
  	struct tipc_bc_base *bb = tipc_bc_base(net);
  
  	tipc_bcast_lock(net);
  	bb->dests[bearer_id]--;
  	tipc_bcbase_select_primary(net);
  	tipc_bcast_unlock(net);
  }
b06b281e7   Jon Paul Maloy   tipc: simplify be...
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
  /* tipc_bcbase_xmit - broadcast a packet queue across one or more bearers
   *
   * Note that number of reachable destinations, as indicated in the dests[]
   * array, may transitionally differ from the number of destinations indicated
   * in each sent buffer. We can sustain this. Excess destination nodes will
   * drop and never acknowledge the unexpected packets, and missing destinations
   * will either require retransmission (if they are just about to be added to
   * the bearer), or be removed from the buffer's 'ackers' counter (if they
   * just went down)
   */
  static void tipc_bcbase_xmit(struct net *net, struct sk_buff_head *xmitq)
  {
  	int bearer_id;
  	struct tipc_bc_base *bb = tipc_bc_base(net);
  	struct sk_buff *skb, *_skb;
  	struct sk_buff_head _xmitq;
  
  	if (skb_queue_empty(xmitq))
  		return;
  
  	/* The typical case: at least one bearer has links to all nodes */
  	bearer_id = bb->primary_bearer;
  	if (bearer_id >= 0) {
  		tipc_bearer_bc_xmit(net, bearer_id, xmitq);
  		return;
  	}
  
  	/* We have to transmit across all bearers */
e654f9f53   Jon Maloy   tipc: clean up sk...
182
  	__skb_queue_head_init(&_xmitq);
b06b281e7   Jon Paul Maloy   tipc: simplify be...
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
  	for (bearer_id = 0; bearer_id < MAX_BEARERS; bearer_id++) {
  		if (!bb->dests[bearer_id])
  			continue;
  
  		skb_queue_walk(xmitq, skb) {
  			_skb = pskb_copy_for_clone(skb, GFP_ATOMIC);
  			if (!_skb)
  				break;
  			__skb_queue_tail(&_xmitq, _skb);
  		}
  		tipc_bearer_bc_xmit(net, bearer_id, &_xmitq);
  	}
  	__skb_queue_purge(xmitq);
  	__skb_queue_purge(&_xmitq);
  }
01fd12bb1   Jon Paul Maloy   tipc: make replic...
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
  static void tipc_bcast_select_xmit_method(struct net *net, int dests,
  					  struct tipc_mc_method *method)
  {
  	struct tipc_bc_base *bb = tipc_bc_base(net);
  	unsigned long exp = method->expires;
  
  	/* Broadcast supported by used bearer/bearers? */
  	if (!bb->bcast_support) {
  		method->rcast = true;
  		return;
  	}
  	/* Any destinations which don't support replicast ? */
  	if (!bb->rcast_support) {
  		method->rcast = false;
  		return;
  	}
  	/* Can current method be changed ? */
  	method->expires = jiffies + TIPC_METHOD_EXPIRE;
c55c8edaf   Hoang Le   tipc: smooth chan...
216
  	if (method->mandatory)
01fd12bb1   Jon Paul Maloy   tipc: make replic...
217
  		return;
c55c8edaf   Hoang Le   tipc: smooth chan...
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
  	if (!(tipc_net(net)->capabilities & TIPC_MCAST_RBCTL) &&
  	    time_before(jiffies, exp))
  		return;
  
  	/* Configuration as force 'broadcast' method */
  	if (bb->force_bcast) {
  		method->rcast = false;
  		return;
  	}
  	/* Configuration as force 'replicast' method */
  	if (bb->force_rcast) {
  		method->rcast = true;
  		return;
  	}
  	/* Configuration as 'autoselect' or default method */
01fd12bb1   Jon Paul Maloy   tipc: make replic...
233
234
235
  	/* Determine method to use now */
  	method->rcast = dests <= bb->bc_threshold;
  }
a853e4c6d   Jon Paul Maloy   tipc: introduce r...
236
  /* tipc_bcast_xmit - broadcast the buffer chain to all external nodes
f2f9800d4   Ying Xue   tipc: make tipc n...
237
   * @net: the applicable net namespace
a853e4c6d   Jon Paul Maloy   tipc: introduce r...
238
239
   * @pkts: chain of buffers containing message
   * @cong_link_cnt: set to 1 if broadcast link is congested, otherwise 0
365ad353c   Jon Paul Maloy   tipc: reduce risk...
240
   * Consumes the buffer chain.
a853e4c6d   Jon Paul Maloy   tipc: introduce r...
241
   * Returns 0 if success, otherwise errno: -EHOSTUNREACH,-EMSGSIZE
078bec826   Jon Paul Maloy   tipc: add new fun...
242
   */
a853e4c6d   Jon Paul Maloy   tipc: introduce r...
243
244
  static int tipc_bcast_xmit(struct net *net, struct sk_buff_head *pkts,
  			   u16 *cong_link_cnt)
078bec826   Jon Paul Maloy   tipc: add new fun...
245
  {
2f5661245   Jon Paul Maloy   tipc: let broadca...
246
  	struct tipc_link *l = tipc_bc_sndlink(net);
a853e4c6d   Jon Paul Maloy   tipc: introduce r...
247
  	struct sk_buff_head xmitq;
078bec826   Jon Paul Maloy   tipc: add new fun...
248
  	int rc = 0;
078bec826   Jon Paul Maloy   tipc: add new fun...
249

e654f9f53   Jon Maloy   tipc: clean up sk...
250
  	__skb_queue_head_init(&xmitq);
2f5661245   Jon Paul Maloy   tipc: let broadca...
251
252
  	tipc_bcast_lock(net);
  	if (tipc_link_bc_peers(l))
a853e4c6d   Jon Paul Maloy   tipc: introduce r...
253
  		rc = tipc_link_xmit(l, pkts, &xmitq);
2f5661245   Jon Paul Maloy   tipc: let broadca...
254
  	tipc_bcast_unlock(net);
a853e4c6d   Jon Paul Maloy   tipc: introduce r...
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
  	tipc_bcbase_xmit(net, &xmitq);
  	__skb_queue_purge(pkts);
  	if (rc == -ELINKCONG) {
  		*cong_link_cnt = 1;
  		rc = 0;
  	}
  	return rc;
  }
  
  /* tipc_rcast_xmit - replicate and send a message to given destination nodes
   * @net: the applicable net namespace
   * @pkts: chain of buffers containing message
   * @dests: list of destination nodes
   * @cong_link_cnt: returns number of congested links
   * @cong_links: returns identities of congested links
   * Returns 0 if success, otherwise errno
   */
  static int tipc_rcast_xmit(struct net *net, struct sk_buff_head *pkts,
  			   struct tipc_nlist *dests, u16 *cong_link_cnt)
  {
a80ae5306   Jon Maloy   tipc: improve des...
275
  	struct tipc_dest *dst, *tmp;
a853e4c6d   Jon Paul Maloy   tipc: introduce r...
276
  	struct sk_buff_head _pkts;
a80ae5306   Jon Maloy   tipc: improve des...
277
  	u32 dnode, selector;
a853e4c6d   Jon Paul Maloy   tipc: introduce r...
278
279
  
  	selector = msg_link_selector(buf_msg(skb_peek(pkts)));
e654f9f53   Jon Maloy   tipc: clean up sk...
280
  	__skb_queue_head_init(&_pkts);
a853e4c6d   Jon Paul Maloy   tipc: introduce r...
281

a80ae5306   Jon Maloy   tipc: improve des...
282
283
284
  	list_for_each_entry_safe(dst, tmp, &dests->list, list) {
  		dnode = dst->node;
  		if (!tipc_msg_pskb_copy(dnode, pkts, &_pkts))
a853e4c6d   Jon Paul Maloy   tipc: introduce r...
285
  			return -ENOMEM;
078bec826   Jon Paul Maloy   tipc: add new fun...
286

a853e4c6d   Jon Paul Maloy   tipc: introduce r...
287
  		/* Any other return value than -ELINKCONG is ignored */
a80ae5306   Jon Maloy   tipc: improve des...
288
  		if (tipc_node_xmit(net, &_pkts, dnode, selector) == -ELINKCONG)
a853e4c6d   Jon Paul Maloy   tipc: introduce r...
289
  			(*cong_link_cnt)++;
cb1b72809   Jon Paul Maloy   tipc: eliminate r...
290
  	}
a853e4c6d   Jon Paul Maloy   tipc: introduce r...
291
292
  	return 0;
  }
526669866   Jon Paul Maloy   tipc: let broadca...
293

c55c8edaf   Hoang Le   tipc: smooth chan...
294
295
296
297
298
  /* tipc_mcast_send_sync - deliver a dummy message with SYN bit
   * @net: the applicable net namespace
   * @skb: socket buffer to copy
   * @method: send method to be used
   * @dests: destination nodes for message.
c55c8edaf   Hoang Le   tipc: smooth chan...
299
300
301
302
   * Returns 0 if success, otherwise errno
   */
  static int tipc_mcast_send_sync(struct net *net, struct sk_buff *skb,
  				struct tipc_mc_method *method,
f83b95702   Tuong Lien   tipc: fix potenti...
303
  				struct tipc_nlist *dests)
c55c8edaf   Hoang Le   tipc: smooth chan...
304
305
306
307
  {
  	struct tipc_msg *hdr, *_hdr;
  	struct sk_buff_head tmpq;
  	struct sk_buff *_skb;
f83b95702   Tuong Lien   tipc: fix potenti...
308
309
  	u16 cong_link_cnt;
  	int rc = 0;
c55c8edaf   Hoang Le   tipc: smooth chan...
310
311
312
313
314
315
316
  
  	/* Is a cluster supporting with new capabilities ? */
  	if (!(tipc_net(net)->capabilities & TIPC_MCAST_RBCTL))
  		return 0;
  
  	hdr = buf_msg(skb);
  	if (msg_user(hdr) == MSG_FRAGMENTER)
a7dc51adc   Jon Maloy   tipc: rename func...
317
  		hdr = msg_inner_hdr(hdr);
c55c8edaf   Hoang Le   tipc: smooth chan...
318
319
320
321
322
  	if (msg_type(hdr) != TIPC_MCAST_MSG)
  		return 0;
  
  	/* Allocate dummy message */
  	_skb = tipc_buf_acquire(MCAST_H_SIZE, GFP_KERNEL);
6da88a82d   Wei Yongjun   tipc: fix return ...
323
  	if (!_skb)
c55c8edaf   Hoang Le   tipc: smooth chan...
324
325
326
327
328
329
330
331
332
333
334
335
336
  		return -ENOMEM;
  
  	/* Preparing for 'synching' header */
  	msg_set_syn(hdr, 1);
  
  	/* Copy skb's header into a dummy header */
  	skb_copy_to_linear_data(_skb, hdr, MCAST_H_SIZE);
  	skb_orphan(_skb);
  
  	/* Reverse method for dummy message */
  	_hdr = buf_msg(_skb);
  	msg_set_size(_hdr, MCAST_H_SIZE);
  	msg_set_is_rcast(_hdr, !msg_is_rcast(hdr));
f83b95702   Tuong Lien   tipc: fix potenti...
337
  	msg_set_errcode(_hdr, TIPC_ERR_NO_PORT);
c55c8edaf   Hoang Le   tipc: smooth chan...
338

e654f9f53   Jon Maloy   tipc: clean up sk...
339
  	__skb_queue_head_init(&tmpq);
c55c8edaf   Hoang Le   tipc: smooth chan...
340
341
  	__skb_queue_tail(&tmpq, _skb);
  	if (method->rcast)
f83b95702   Tuong Lien   tipc: fix potenti...
342
  		rc = tipc_bcast_xmit(net, &tmpq, &cong_link_cnt);
c55c8edaf   Hoang Le   tipc: smooth chan...
343
  	else
f83b95702   Tuong Lien   tipc: fix potenti...
344
  		rc = tipc_rcast_xmit(net, &tmpq, dests, &cong_link_cnt);
c55c8edaf   Hoang Le   tipc: smooth chan...
345
346
347
  
  	/* This queue should normally be empty by now */
  	__skb_queue_purge(&tmpq);
f83b95702   Tuong Lien   tipc: fix potenti...
348
  	return rc;
c55c8edaf   Hoang Le   tipc: smooth chan...
349
  }
a853e4c6d   Jon Paul Maloy   tipc: introduce r...
350
351
352
353
  /* tipc_mcast_xmit - deliver message to indicated destination nodes
   *                   and to identified node local sockets
   * @net: the applicable net namespace
   * @pkts: chain of buffers containing message
01fd12bb1   Jon Paul Maloy   tipc: make replic...
354
355
   * @method: send method to be used
   * @dests: destination nodes for message.
a853e4c6d   Jon Paul Maloy   tipc: introduce r...
356
   * @cong_link_cnt: returns number of encountered congested destination links
a853e4c6d   Jon Paul Maloy   tipc: introduce r...
357
358
359
360
   * Consumes buffer chain.
   * Returns 0 if success, otherwise errno
   */
  int tipc_mcast_xmit(struct net *net, struct sk_buff_head *pkts,
01fd12bb1   Jon Paul Maloy   tipc: make replic...
361
362
  		    struct tipc_mc_method *method, struct tipc_nlist *dests,
  		    u16 *cong_link_cnt)
a853e4c6d   Jon Paul Maloy   tipc: introduce r...
363
  {
a853e4c6d   Jon Paul Maloy   tipc: introduce r...
364
  	struct sk_buff_head inputq, localq;
c55c8edaf   Hoang Le   tipc: smooth chan...
365
366
367
  	bool rcast = method->rcast;
  	struct tipc_msg *hdr;
  	struct sk_buff *skb;
a853e4c6d   Jon Paul Maloy   tipc: introduce r...
368
369
370
  	int rc = 0;
  
  	skb_queue_head_init(&inputq);
e654f9f53   Jon Maloy   tipc: clean up sk...
371
  	__skb_queue_head_init(&localq);
a853e4c6d   Jon Paul Maloy   tipc: introduce r...
372
373
374
375
376
377
  
  	/* Clone packets before they are consumed by next call */
  	if (dests->local && !tipc_msg_reassemble(pkts, &localq)) {
  		rc = -ENOMEM;
  		goto exit;
  	}
01fd12bb1   Jon Paul Maloy   tipc: make replic...
378
  	/* Send according to determined transmit method */
a853e4c6d   Jon Paul Maloy   tipc: introduce r...
379
  	if (dests->remote) {
01fd12bb1   Jon Paul Maloy   tipc: make replic...
380
  		tipc_bcast_select_xmit_method(net, dests->remote, method);
c55c8edaf   Hoang Le   tipc: smooth chan...
381
382
383
384
  
  		skb = skb_peek(pkts);
  		hdr = buf_msg(skb);
  		if (msg_user(hdr) == MSG_FRAGMENTER)
a7dc51adc   Jon Maloy   tipc: rename func...
385
  			hdr = msg_inner_hdr(hdr);
c55c8edaf   Hoang Le   tipc: smooth chan...
386
387
388
  		msg_set_is_rcast(hdr, method->rcast);
  
  		/* Switch method ? */
f83b95702   Tuong Lien   tipc: fix potenti...
389
390
391
392
393
394
395
396
397
  		if (rcast != method->rcast) {
  			rc = tipc_mcast_send_sync(net, skb, method, dests);
  			if (unlikely(rc)) {
  				pr_err("Unable to send SYN: method %d, rc %d
  ",
  				       rcast, rc);
  				goto exit;
  			}
  		}
c55c8edaf   Hoang Le   tipc: smooth chan...
398

01fd12bb1   Jon Paul Maloy   tipc: make replic...
399
  		if (method->rcast)
a853e4c6d   Jon Paul Maloy   tipc: introduce r...
400
401
402
403
  			rc = tipc_rcast_xmit(net, pkts, dests, cong_link_cnt);
  		else
  			rc = tipc_bcast_xmit(net, pkts, cong_link_cnt);
  	}
6c9081a39   John Rutherford   tipc: add loopbac...
404
405
  	if (dests->local) {
  		tipc_loopback_trace(net, &localq);
a853e4c6d   Jon Paul Maloy   tipc: introduce r...
406
  		tipc_sk_mcast_rcv(net, &localq, &inputq);
6c9081a39   John Rutherford   tipc: add loopbac...
407
  	}
a853e4c6d   Jon Paul Maloy   tipc: introduce r...
408
  exit:
01fd12bb1   Jon Paul Maloy   tipc: make replic...
409
  	/* This queue should normally be empty by now */
a853e4c6d   Jon Paul Maloy   tipc: introduce r...
410
  	__skb_queue_purge(pkts);
365ad353c   Jon Paul Maloy   tipc: reduce risk...
411
  	return rc;
078bec826   Jon Paul Maloy   tipc: add new fun...
412
  }
526669866   Jon Paul Maloy   tipc: let broadca...
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
  
  /* tipc_bcast_rcv - receive a broadcast packet, and deliver to rcv link
   *
   * RCU is locked, no other locks set
   */
  int tipc_bcast_rcv(struct net *net, struct tipc_link *l, struct sk_buff *skb)
  {
  	struct tipc_msg *hdr = buf_msg(skb);
  	struct sk_buff_head *inputq = &tipc_bc_base(net)->inputq;
  	struct sk_buff_head xmitq;
  	int rc;
  
  	__skb_queue_head_init(&xmitq);
  
  	if (msg_mc_netid(hdr) != tipc_netid(net) || !tipc_link_is_up(l)) {
  		kfree_skb(skb);
  		return 0;
  	}
  
  	tipc_bcast_lock(net);
  	if (msg_user(hdr) == BCAST_PROTOCOL)
  		rc = tipc_link_bc_nack_rcv(l, skb, &xmitq);
  	else
  		rc = tipc_link_rcv(l, skb, NULL);
  	tipc_bcast_unlock(net);
b06b281e7   Jon Paul Maloy   tipc: simplify be...
438
  	tipc_bcbase_xmit(net, &xmitq);
526669866   Jon Paul Maloy   tipc: let broadca...
439
440
441
442
443
444
445
446
447
448
449
450
  
  	/* Any socket wakeup messages ? */
  	if (!skb_queue_empty(inputq))
  		tipc_sk_rcv(net, inputq);
  
  	return rc;
  }
  
  /* tipc_bcast_ack_rcv - receive and handle a broadcast acknowledge
   *
   * RCU is locked, no other locks set
   */
06bd2b1ed   Jon Paul Maloy   tipc: fix broadca...
451
452
  void tipc_bcast_ack_rcv(struct net *net, struct tipc_link *l,
  			struct tipc_msg *hdr)
526669866   Jon Paul Maloy   tipc: let broadca...
453
454
  {
  	struct sk_buff_head *inputq = &tipc_bc_base(net)->inputq;
06bd2b1ed   Jon Paul Maloy   tipc: fix broadca...
455
  	u16 acked = msg_bcast_ack(hdr);
526669866   Jon Paul Maloy   tipc: let broadca...
456
  	struct sk_buff_head xmitq;
06bd2b1ed   Jon Paul Maloy   tipc: fix broadca...
457
458
459
  	/* Ignore bc acks sent by peer before bcast synch point was received */
  	if (msg_bc_ack_invalid(hdr))
  		return;
526669866   Jon Paul Maloy   tipc: let broadca...
460
461
462
463
464
  	__skb_queue_head_init(&xmitq);
  
  	tipc_bcast_lock(net);
  	tipc_link_bc_ack_rcv(l, acked, &xmitq);
  	tipc_bcast_unlock(net);
b06b281e7   Jon Paul Maloy   tipc: simplify be...
465
  	tipc_bcbase_xmit(net, &xmitq);
526669866   Jon Paul Maloy   tipc: let broadca...
466
467
468
469
470
471
472
473
474
475
  
  	/* Any socket wakeup messages ? */
  	if (!skb_queue_empty(inputq))
  		tipc_sk_rcv(net, inputq);
  }
  
  /* tipc_bcast_synch_rcv -  check and update rcv link with peer's send state
   *
   * RCU is locked, no other locks set
   */
02d11ca20   Jon Paul Maloy   tipc: transfer br...
476
477
  int tipc_bcast_sync_rcv(struct net *net, struct tipc_link *l,
  			struct tipc_msg *hdr)
526669866   Jon Paul Maloy   tipc: let broadca...
478
479
480
  {
  	struct sk_buff_head *inputq = &tipc_bc_base(net)->inputq;
  	struct sk_buff_head xmitq;
02d11ca20   Jon Paul Maloy   tipc: transfer br...
481
  	int rc = 0;
526669866   Jon Paul Maloy   tipc: let broadca...
482
483
484
485
  
  	__skb_queue_head_init(&xmitq);
  
  	tipc_bcast_lock(net);
06bd2b1ed   Jon Paul Maloy   tipc: fix broadca...
486
487
488
  	if (msg_type(hdr) != STATE_MSG) {
  		tipc_link_bc_init_rcv(l, hdr);
  	} else if (!msg_bc_ack_invalid(hdr)) {
526669866   Jon Paul Maloy   tipc: let broadca...
489
  		tipc_link_bc_ack_rcv(l, msg_bcast_ack(hdr), &xmitq);
02d11ca20   Jon Paul Maloy   tipc: transfer br...
490
  		rc = tipc_link_bc_sync_rcv(l, hdr, &xmitq);
526669866   Jon Paul Maloy   tipc: let broadca...
491
492
  	}
  	tipc_bcast_unlock(net);
b06b281e7   Jon Paul Maloy   tipc: simplify be...
493
  	tipc_bcbase_xmit(net, &xmitq);
526669866   Jon Paul Maloy   tipc: let broadca...
494
495
496
497
  
  	/* Any socket wakeup messages ? */
  	if (!skb_queue_empty(inputq))
  		tipc_sk_rcv(net, inputq);
02d11ca20   Jon Paul Maloy   tipc: transfer br...
498
  	return rc;
526669866   Jon Paul Maloy   tipc: let broadca...
499
500
501
502
503
504
  }
  
  /* tipc_bcast_add_peer - add a peer node to broadcast link and bearer
   *
   * RCU is locked, node lock is set
   */
b06b281e7   Jon Paul Maloy   tipc: simplify be...
505
  void tipc_bcast_add_peer(struct net *net, struct tipc_link *uc_l,
526669866   Jon Paul Maloy   tipc: let broadca...
506
507
  			 struct sk_buff_head *xmitq)
  {
526669866   Jon Paul Maloy   tipc: let broadca...
508
  	struct tipc_link *snd_l = tipc_bc_sndlink(net);
b06b281e7   Jon Paul Maloy   tipc: simplify be...
509
  	tipc_bcast_lock(net);
526669866   Jon Paul Maloy   tipc: let broadca...
510
  	tipc_link_add_bc_peer(snd_l, uc_l, xmitq);
b06b281e7   Jon Paul Maloy   tipc: simplify be...
511
  	tipc_bcbase_select_primary(net);
01fd12bb1   Jon Paul Maloy   tipc: make replic...
512
  	tipc_bcbase_calc_bc_threshold(net);
b06b281e7   Jon Paul Maloy   tipc: simplify be...
513
  	tipc_bcast_unlock(net);
526669866   Jon Paul Maloy   tipc: let broadca...
514
515
516
517
518
519
  }
  
  /* tipc_bcast_remove_peer - remove a peer node from broadcast link and bearer
   *
   * RCU is locked, node lock is set
   */
b06b281e7   Jon Paul Maloy   tipc: simplify be...
520
  void tipc_bcast_remove_peer(struct net *net, struct tipc_link *rcv_l)
526669866   Jon Paul Maloy   tipc: let broadca...
521
  {
526669866   Jon Paul Maloy   tipc: let broadca...
522
  	struct tipc_link *snd_l = tipc_bc_sndlink(net);
b06b281e7   Jon Paul Maloy   tipc: simplify be...
523
  	struct sk_buff_head *inputq = &tipc_bc_base(net)->inputq;
526669866   Jon Paul Maloy   tipc: let broadca...
524
525
526
  	struct sk_buff_head xmitq;
  
  	__skb_queue_head_init(&xmitq);
b06b281e7   Jon Paul Maloy   tipc: simplify be...
527
  	tipc_bcast_lock(net);
526669866   Jon Paul Maloy   tipc: let broadca...
528
  	tipc_link_remove_bc_peer(snd_l, rcv_l, &xmitq);
b06b281e7   Jon Paul Maloy   tipc: simplify be...
529
  	tipc_bcbase_select_primary(net);
01fd12bb1   Jon Paul Maloy   tipc: make replic...
530
  	tipc_bcbase_calc_bc_threshold(net);
b06b281e7   Jon Paul Maloy   tipc: simplify be...
531
  	tipc_bcast_unlock(net);
526669866   Jon Paul Maloy   tipc: let broadca...
532

b06b281e7   Jon Paul Maloy   tipc: simplify be...
533
  	tipc_bcbase_xmit(net, &xmitq);
526669866   Jon Paul Maloy   tipc: let broadca...
534
535
536
537
538
  
  	/* Any socket wakeup messages ? */
  	if (!skb_queue_empty(inputq))
  		tipc_sk_rcv(net, inputq);
  }
1da465683   Ying Xue   tipc: make tipc b...
539
  int tipc_bclink_reset_stats(struct net *net)
b97bf3fd8   Per Liden   [TIPC] Initial merge
540
  {
38206d593   Jon Paul Maloy   tipc: narrow down...
541
  	struct tipc_link *l = tipc_bc_sndlink(net);
1da465683   Ying Xue   tipc: make tipc b...
542

38206d593   Jon Paul Maloy   tipc: narrow down...
543
  	if (!l)
b97bf3fd8   Per Liden   [TIPC] Initial merge
544
  		return -ENOPROTOOPT;
2af5ae372   Jon Paul Maloy   tipc: clean up un...
545
  	tipc_bcast_lock(net);
38206d593   Jon Paul Maloy   tipc: narrow down...
546
  	tipc_link_reset_stats(l);
2af5ae372   Jon Paul Maloy   tipc: clean up un...
547
  	tipc_bcast_unlock(net);
0e35fd5e5   Allan Stephens   tipc: Eliminate i...
548
  	return 0;
b97bf3fd8   Per Liden   [TIPC] Initial merge
549
  }
2af5ae372   Jon Paul Maloy   tipc: clean up un...
550
  static int tipc_bc_link_set_queue_limits(struct net *net, u32 limit)
b97bf3fd8   Per Liden   [TIPC] Initial merge
551
  {
2af5ae372   Jon Paul Maloy   tipc: clean up un...
552
  	struct tipc_link *l = tipc_bc_sndlink(net);
1da465683   Ying Xue   tipc: make tipc b...
553

2af5ae372   Jon Paul Maloy   tipc: clean up un...
554
  	if (!l)
b97bf3fd8   Per Liden   [TIPC] Initial merge
555
  		return -ENOPROTOOPT;
53387c4e2   Jon Paul Maloy   tipc: extend broa...
556
557
558
  	if (limit < BCLINK_WIN_MIN)
  		limit = BCLINK_WIN_MIN;
  	if (limit > TIPC_MAX_LINK_WIN)
b97bf3fd8   Per Liden   [TIPC] Initial merge
559
  		return -EINVAL;
2af5ae372   Jon Paul Maloy   tipc: clean up un...
560
561
562
  	tipc_bcast_lock(net);
  	tipc_link_set_queue_limits(l, limit);
  	tipc_bcast_unlock(net);
0e35fd5e5   Allan Stephens   tipc: Eliminate i...
563
  	return 0;
b97bf3fd8   Per Liden   [TIPC] Initial merge
564
  }
02ec6cafd   Hoang Le   tipc: support bro...
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
  static int tipc_bc_link_set_broadcast_mode(struct net *net, u32 bc_mode)
  {
  	struct tipc_bc_base *bb = tipc_bc_base(net);
  
  	switch (bc_mode) {
  	case BCLINK_MODE_BCAST:
  		if (!bb->bcast_support)
  			return -ENOPROTOOPT;
  
  		bb->force_bcast = true;
  		bb->force_rcast = false;
  		break;
  	case BCLINK_MODE_RCAST:
  		if (!bb->rcast_support)
  			return -ENOPROTOOPT;
  
  		bb->force_bcast = false;
  		bb->force_rcast = true;
  		break;
  	case BCLINK_MODE_SEL:
  		if (!bb->bcast_support || !bb->rcast_support)
  			return -ENOPROTOOPT;
  
  		bb->force_bcast = false;
  		bb->force_rcast = false;
  		break;
  	default:
  		return -EINVAL;
  	}
  
  	return 0;
  }
  
  static int tipc_bc_link_set_broadcast_ratio(struct net *net, u32 bc_ratio)
  {
  	struct tipc_bc_base *bb = tipc_bc_base(net);
  
  	if (!bb->bcast_support || !bb->rcast_support)
  		return -ENOPROTOOPT;
  
  	if (bc_ratio > 100 || bc_ratio <= 0)
  		return -EINVAL;
  
  	bb->rc_ratio = bc_ratio;
  	tipc_bcast_lock(net);
  	tipc_bcbase_calc_bc_threshold(net);
  	tipc_bcast_unlock(net);
  
  	return 0;
  }
670f4f881   Richard Alpe   tipc: add broadca...
615
616
617
618
  int tipc_nl_bc_link_set(struct net *net, struct nlattr *attrs[])
  {
  	int err;
  	u32 win;
02ec6cafd   Hoang Le   tipc: support bro...
619
620
  	u32 bc_mode;
  	u32 bc_ratio;
670f4f881   Richard Alpe   tipc: add broadca...
621
622
623
624
625
626
627
628
  	struct nlattr *props[TIPC_NLA_PROP_MAX + 1];
  
  	if (!attrs[TIPC_NLA_LINK_PROP])
  		return -EINVAL;
  
  	err = tipc_nl_parse_link_prop(attrs[TIPC_NLA_LINK_PROP], props);
  	if (err)
  		return err;
02ec6cafd   Hoang Le   tipc: support bro...
629
630
631
  	if (!props[TIPC_NLA_PROP_WIN] &&
  	    !props[TIPC_NLA_PROP_BROADCAST] &&
  	    !props[TIPC_NLA_PROP_BROADCAST_RATIO]) {
670f4f881   Richard Alpe   tipc: add broadca...
632
  		return -EOPNOTSUPP;
02ec6cafd   Hoang Le   tipc: support bro...
633
634
635
636
637
638
  	}
  
  	if (props[TIPC_NLA_PROP_BROADCAST]) {
  		bc_mode = nla_get_u32(props[TIPC_NLA_PROP_BROADCAST]);
  		err = tipc_bc_link_set_broadcast_mode(net, bc_mode);
  	}
670f4f881   Richard Alpe   tipc: add broadca...
639

02ec6cafd   Hoang Le   tipc: support bro...
640
641
642
643
  	if (!err && props[TIPC_NLA_PROP_BROADCAST_RATIO]) {
  		bc_ratio = nla_get_u32(props[TIPC_NLA_PROP_BROADCAST_RATIO]);
  		err = tipc_bc_link_set_broadcast_ratio(net, bc_ratio);
  	}
670f4f881   Richard Alpe   tipc: add broadca...
644

02ec6cafd   Hoang Le   tipc: support bro...
645
646
647
648
649
650
  	if (!err && props[TIPC_NLA_PROP_WIN]) {
  		win = nla_get_u32(props[TIPC_NLA_PROP_WIN]);
  		err = tipc_bc_link_set_queue_limits(net, win);
  	}
  
  	return err;
670f4f881   Richard Alpe   tipc: add broadca...
651
  }
6beb19a62   Jon Paul Maloy   tipc: move bcast ...
652
  int tipc_bcast_init(struct net *net)
b97bf3fd8   Per Liden   [TIPC] Initial merge
653
  {
323019069   Jon Paul Maloy   tipc: use explici...
654
  	struct tipc_net *tn = tipc_net(net);
323019069   Jon Paul Maloy   tipc: use explici...
655
656
  	struct tipc_bc_base *bb = NULL;
  	struct tipc_link *l = NULL;
a0732548b   Jia-Ju Bai   net: tipc: bcast:...
657
  	bb = kzalloc(sizeof(*bb), GFP_KERNEL);
323019069   Jon Paul Maloy   tipc: use explici...
658
659
660
  	if (!bb)
  		goto enomem;
  	tn->bcbase = bb;
0043550b0   Jon Paul Maloy   tipc: move broadc...
661
  	spin_lock_init(&tipc_net(net)->bclock);
323019069   Jon Paul Maloy   tipc: use explici...
662

c72fa872a   Jon Paul Maloy   tipc: eliminate l...
663
  	if (!tipc_link_bc_create(net, 0, 0,
4c94cc2d3   Jon Maloy   tipc: fall back t...
664
  				 FB_MTU,
323019069   Jon Paul Maloy   tipc: use explici...
665
  				 BCLINK_WIN_DEFAULT,
fd556f209   Jon Paul Maloy   tipc: introduce c...
666
  				 0,
323019069   Jon Paul Maloy   tipc: use explici...
667
  				 &bb->inputq,
2af5ae372   Jon Paul Maloy   tipc: clean up un...
668
  				 NULL,
526669866   Jon Paul Maloy   tipc: let broadca...
669
  				 NULL,
323019069   Jon Paul Maloy   tipc: use explici...
670
671
672
673
  				 &l))
  		goto enomem;
  	bb->link = l;
  	tn->bcl = l;
02ec6cafd   Hoang Le   tipc: support bro...
674
  	bb->rc_ratio = 10;
01fd12bb1   Jon Paul Maloy   tipc: make replic...
675
  	bb->rcast_support = true;
eb8b00f5f   Ying Xue   tipc: convert all...
676
  	return 0;
323019069   Jon Paul Maloy   tipc: use explici...
677
  enomem:
323019069   Jon Paul Maloy   tipc: use explici...
678
679
680
  	kfree(bb);
  	kfree(l);
  	return -ENOMEM;
b97bf3fd8   Per Liden   [TIPC] Initial merge
681
  }
6beb19a62   Jon Paul Maloy   tipc: move bcast ...
682
  void tipc_bcast_stop(struct net *net)
b97bf3fd8   Per Liden   [TIPC] Initial merge
683
  {
7f9f95d9d   Ying Xue   tipc: make bearer...
684
  	struct tipc_net *tn = net_generic(net, tipc_net_id);
eb8b00f5f   Ying Xue   tipc: convert all...
685
  	synchronize_net();
6beb19a62   Jon Paul Maloy   tipc: move bcast ...
686
  	kfree(tn->bcbase);
323019069   Jon Paul Maloy   tipc: use explici...
687
  	kfree(tn->bcl);
b97bf3fd8   Per Liden   [TIPC] Initial merge
688
  }
2ae0b8af1   Jon Paul Maloy   tipc: add functio...
689
690
691
692
693
694
695
696
697
698
699
700
  
  void tipc_nlist_init(struct tipc_nlist *nl, u32 self)
  {
  	memset(nl, 0, sizeof(*nl));
  	INIT_LIST_HEAD(&nl->list);
  	nl->self = self;
  }
  
  void tipc_nlist_add(struct tipc_nlist *nl, u32 node)
  {
  	if (node == nl->self)
  		nl->local = true;
a80ae5306   Jon Maloy   tipc: improve des...
701
  	else if (tipc_dest_push(&nl->list, node, 0))
2ae0b8af1   Jon Paul Maloy   tipc: add functio...
702
703
704
705
706
707
708
  		nl->remote++;
  }
  
  void tipc_nlist_del(struct tipc_nlist *nl, u32 node)
  {
  	if (node == nl->self)
  		nl->local = false;
a80ae5306   Jon Maloy   tipc: improve des...
709
  	else if (tipc_dest_del(&nl->list, node, 0))
2ae0b8af1   Jon Paul Maloy   tipc: add functio...
710
711
712
713
714
  		nl->remote--;
  }
  
  void tipc_nlist_purge(struct tipc_nlist *nl)
  {
a80ae5306   Jon Maloy   tipc: improve des...
715
  	tipc_dest_list_purge(&nl->list);
2ae0b8af1   Jon Paul Maloy   tipc: add functio...
716
  	nl->remote = 0;
c9efb15a9   Gustavo A. R. Silva   tipc: bcast: use ...
717
  	nl->local = false;
2ae0b8af1   Jon Paul Maloy   tipc: add functio...
718
  }
02ec6cafd   Hoang Le   tipc: support bro...
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
  
  u32 tipc_bcast_get_broadcast_mode(struct net *net)
  {
  	struct tipc_bc_base *bb = tipc_bc_base(net);
  
  	if (bb->force_bcast)
  		return BCLINK_MODE_BCAST;
  
  	if (bb->force_rcast)
  		return BCLINK_MODE_RCAST;
  
  	if (bb->bcast_support && bb->rcast_support)
  		return BCLINK_MODE_SEL;
  
  	return 0;
  }
  
  u32 tipc_bcast_get_broadcast_ratio(struct net *net)
  {
  	struct tipc_bc_base *bb = tipc_bc_base(net);
  
  	return bb->rc_ratio;
  }
c55c8edaf   Hoang Le   tipc: smooth chan...
742

08e046c89   Hoang Le   tipc: fix a null ...
743
  void tipc_mcast_filter_msg(struct net *net, struct sk_buff_head *defq,
c55c8edaf   Hoang Le   tipc: smooth chan...
744
745
746
747
748
749
750
751
  			   struct sk_buff_head *inputq)
  {
  	struct sk_buff *skb, *_skb, *tmp;
  	struct tipc_msg *hdr, *_hdr;
  	bool match = false;
  	u32 node, port;
  
  	skb = skb_peek(inputq);
e1279ff7a   Hoang Le   tipc: add NULL po...
752
753
  	if (!skb)
  		return;
c55c8edaf   Hoang Le   tipc: smooth chan...
754
755
756
757
758
759
  	hdr = buf_msg(skb);
  
  	if (likely(!msg_is_syn(hdr) && skb_queue_empty(defq)))
  		return;
  
  	node = msg_orignode(hdr);
08e046c89   Hoang Le   tipc: fix a null ...
760
761
  	if (node == tipc_own_addr(net))
  		return;
c55c8edaf   Hoang Le   tipc: smooth chan...
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
  	port = msg_origport(hdr);
  
  	/* Has the twin SYN message already arrived ? */
  	skb_queue_walk(defq, _skb) {
  		_hdr = buf_msg(_skb);
  		if (msg_orignode(_hdr) != node)
  			continue;
  		if (msg_origport(_hdr) != port)
  			continue;
  		match = true;
  		break;
  	}
  
  	if (!match) {
  		if (!msg_is_syn(hdr))
  			return;
  		__skb_dequeue(inputq);
  		__skb_queue_tail(defq, skb);
  		return;
  	}
  
  	/* Deliver non-SYN message from other link, otherwise queue it */
  	if (!msg_is_syn(hdr)) {
  		if (msg_is_rcast(hdr) != msg_is_rcast(_hdr))
  			return;
  		__skb_dequeue(inputq);
  		__skb_queue_tail(defq, skb);
  		return;
  	}
  
  	/* Queue non-SYN/SYN message from same link */
  	if (msg_is_rcast(hdr) == msg_is_rcast(_hdr)) {
  		__skb_dequeue(inputq);
  		__skb_queue_tail(defq, skb);
  		return;
  	}
  
  	/* Matching SYN messages => return the one with data, if any */
  	__skb_unlink(_skb, defq);
  	if (msg_data_sz(hdr)) {
  		kfree_skb(_skb);
  	} else {
  		__skb_dequeue(inputq);
  		kfree_skb(skb);
  		__skb_queue_tail(inputq, _skb);
  	}
  
  	/* Deliver subsequent non-SYN messages from same peer */
  	skb_queue_walk_safe(defq, _skb, tmp) {
  		_hdr = buf_msg(_skb);
  		if (msg_orignode(_hdr) != node)
  			continue;
  		if (msg_origport(_hdr) != port)
  			continue;
  		if (msg_is_syn(_hdr))
  			break;
  		__skb_unlink(_skb, defq);
  		__skb_queue_tail(inputq, _skb);
  	}
  }