blob: 441b26a57850286308e5e063f57fe6e4cba36dd2 [file] [log] [blame]
Per Lidenb97bf3f2006-01-02 19:04:38 +01001/*
2 * net/tipc/link.c: TIPC link code
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09003 *
Allan Stephens05646c92007-06-10 17:25:24 -07004 * Copyright (c) 1996-2007, Ericsson AB
5 * Copyright (c) 2004-2007, Wind River Systems
Per Lidenb97bf3f2006-01-02 19:04:38 +01006 * All rights reserved.
7 *
Per Liden9ea1fd32006-01-11 13:30:43 +01008 * Redistribution and use in source and binary forms, with or without
Per Lidenb97bf3f2006-01-02 19:04:38 +01009 * modification, are permitted provided that the following conditions are met:
10 *
Per Liden9ea1fd32006-01-11 13:30:43 +010011 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the names of the copyright holders nor the names of its
17 * contributors may be used to endorse or promote products derived from
18 * this software without specific prior written permission.
Per Lidenb97bf3f2006-01-02 19:04:38 +010019 *
Per Liden9ea1fd32006-01-11 13:30:43 +010020 * Alternatively, this software may be distributed under the terms of the
21 * GNU General Public License ("GPL") version 2 as published by the Free
22 * Software Foundation.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
25 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
28 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
32 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
Per Lidenb97bf3f2006-01-02 19:04:38 +010034 * POSSIBILITY OF SUCH DAMAGE.
35 */
36
37#include "core.h"
38#include "dbg.h"
39#include "link.h"
40#include "net.h"
41#include "node.h"
42#include "port.h"
43#include "addr.h"
44#include "node_subscr.h"
45#include "name_distr.h"
46#include "bearer.h"
47#include "name_table.h"
48#include "discover.h"
49#include "config.h"
50#include "bcast.h"
51
52
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +090053/*
Allan Stephensa686e682008-06-04 17:29:39 -070054 * Out-of-range value for link session numbers
55 */
56
57#define INVALID_SESSION 0x10000
58
59/*
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +090060 * Limit for deferred reception queue:
Per Lidenb97bf3f2006-01-02 19:04:38 +010061 */
62
63#define DEF_QUEUE_LIMIT 256u
64
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +090065/*
66 * Link state events:
Per Lidenb97bf3f2006-01-02 19:04:38 +010067 */
68
69#define STARTING_EVT 856384768 /* link processing trigger */
70#define TRAFFIC_MSG_EVT 560815u /* rx'd ??? */
71#define TIMEOUT_EVT 560817u /* link timer expired */
72
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +090073/*
74 * The following two 'message types' is really just implementation
75 * data conveniently stored in the message header.
Per Lidenb97bf3f2006-01-02 19:04:38 +010076 * They must not be considered part of the protocol
77 */
78#define OPEN_MSG 0
79#define CLOSED_MSG 1
80
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +090081/*
Per Lidenb97bf3f2006-01-02 19:04:38 +010082 * State value stored in 'exp_msg_count'
83 */
84
85#define START_CHANGEOVER 100000u
86
87/**
88 * struct link_name - deconstructed link name
89 * @addr_local: network address of node at this end
90 * @if_local: name of interface at this end
91 * @addr_peer: network address of node at far end
92 * @if_peer: name of interface at far end
93 */
94
95struct link_name {
96 u32 addr_local;
97 char if_local[TIPC_MAX_IF_NAME];
98 u32 addr_peer;
99 char if_peer[TIPC_MAX_IF_NAME];
100};
101
102#if 0
103
104/* LINK EVENT CODE IS NOT SUPPORTED AT PRESENT */
105
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900106/**
Per Lidenb97bf3f2006-01-02 19:04:38 +0100107 * struct link_event - link up/down event notification
108 */
109
110struct link_event {
111 u32 addr;
112 int up;
113 void (*fcn)(u32, char *, int);
114 char name[TIPC_MAX_LINK_NAME];
115};
116
117#endif
118
119static void link_handle_out_of_seq_msg(struct link *l_ptr,
120 struct sk_buff *buf);
121static void link_recv_proto_msg(struct link *l_ptr, struct sk_buff *buf);
122static int link_recv_changeover_msg(struct link **l_ptr, struct sk_buff **buf);
123static void link_set_supervision_props(struct link *l_ptr, u32 tolerance);
124static int link_send_sections_long(struct port *sender,
125 struct iovec const *msg_sect,
126 u32 num_sect, u32 destnode);
127static void link_check_defragm_bufs(struct link *l_ptr);
128static void link_state_event(struct link *l_ptr, u32 event);
129static void link_reset_statistics(struct link *l_ptr);
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900130static void link_print(struct link *l_ptr, struct print_buf *buf,
Per Lidenb97bf3f2006-01-02 19:04:38 +0100131 const char *str);
132
133/*
134 * Debugging code used by link routines only
135 *
136 * When debugging link problems on a system that has multiple links,
137 * the standard TIPC debugging routines may not be useful since they
138 * allow the output from multiple links to be intermixed. For this reason
139 * routines of the form "dbg_link_XXX()" have been created that will capture
140 * debug info into a link's personal print buffer, which can then be dumped
Allan Stephensa3df92c2006-10-16 21:49:03 -0700141 * into the TIPC system log (TIPC_LOG) upon request.
Per Lidenb97bf3f2006-01-02 19:04:38 +0100142 *
143 * To enable per-link debugging, use LINK_LOG_BUF_SIZE to specify the size
144 * of the print buffer used by each link. If LINK_LOG_BUF_SIZE is set to 0,
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900145 * the dbg_link_XXX() routines simply send their output to the standard
Per Lidenb97bf3f2006-01-02 19:04:38 +0100146 * debug print buffer (DBG_OUTPUT), if it has been defined; this can be useful
147 * when there is only a single link in the system being debugged.
148 *
149 * Notes:
Allan Stephensa3df92c2006-10-16 21:49:03 -0700150 * - When enabled, LINK_LOG_BUF_SIZE should be set to at least TIPC_PB_MIN_SIZE
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900151 * - "l_ptr" must be valid when using dbg_link_XXX() macros
Per Lidenb97bf3f2006-01-02 19:04:38 +0100152 */
153
154#define LINK_LOG_BUF_SIZE 0
155
Allan Stephens48c97132008-05-05 01:24:06 -0700156#define dbg_link(fmt, arg...) \
157 do { \
158 if (LINK_LOG_BUF_SIZE) \
159 tipc_printf(&l_ptr->print_buf, fmt, ## arg); \
160 } while (0)
161#define dbg_link_msg(msg, txt) \
162 do { \
163 if (LINK_LOG_BUF_SIZE) \
164 tipc_msg_dbg(&l_ptr->print_buf, msg, txt); \
165 } while (0)
166#define dbg_link_state(txt) \
167 do { \
168 if (LINK_LOG_BUF_SIZE) \
169 link_print(l_ptr, &l_ptr->print_buf, txt); \
170 } while (0)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100171#define dbg_link_dump() do { \
172 if (LINK_LOG_BUF_SIZE) { \
173 tipc_printf(LOG, "\n\nDumping link <%s>:\n", l_ptr->name); \
Per Liden4323add2006-01-18 00:38:21 +0100174 tipc_printbuf_move(LOG, &l_ptr->print_buf); \
Per Lidenb97bf3f2006-01-02 19:04:38 +0100175 } \
176} while (0)
177
Sam Ravnborg05790c62006-03-20 22:37:04 -0800178static void dbg_print_link(struct link *l_ptr, const char *str)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100179{
Allan Stephensa3df92c2006-10-16 21:49:03 -0700180 if (DBG_OUTPUT != TIPC_NULL)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100181 link_print(l_ptr, DBG_OUTPUT, str);
182}
183
Sam Ravnborg05790c62006-03-20 22:37:04 -0800184static void dbg_print_buf_chain(struct sk_buff *root_buf)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100185{
Allan Stephensa3df92c2006-10-16 21:49:03 -0700186 if (DBG_OUTPUT != TIPC_NULL) {
Per Lidenb97bf3f2006-01-02 19:04:38 +0100187 struct sk_buff *buf = root_buf;
188
189 while (buf) {
190 msg_dbg(buf_msg(buf), "In chain: ");
191 buf = buf->next;
192 }
193 }
194}
195
196/*
Sam Ravnborg05790c62006-03-20 22:37:04 -0800197 * Simple link routines
Per Lidenb97bf3f2006-01-02 19:04:38 +0100198 */
199
Sam Ravnborg05790c62006-03-20 22:37:04 -0800200static unsigned int align(unsigned int i)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100201{
202 return (i + 3) & ~3u;
203}
204
Sam Ravnborg05790c62006-03-20 22:37:04 -0800205static int link_working_working(struct link *l_ptr)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100206{
207 return (l_ptr->state == WORKING_WORKING);
208}
209
Sam Ravnborg05790c62006-03-20 22:37:04 -0800210static int link_working_unknown(struct link *l_ptr)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100211{
212 return (l_ptr->state == WORKING_UNKNOWN);
213}
214
Sam Ravnborg05790c62006-03-20 22:37:04 -0800215static int link_reset_unknown(struct link *l_ptr)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100216{
217 return (l_ptr->state == RESET_UNKNOWN);
218}
219
Sam Ravnborg05790c62006-03-20 22:37:04 -0800220static int link_reset_reset(struct link *l_ptr)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100221{
222 return (l_ptr->state == RESET_RESET);
223}
224
Sam Ravnborg05790c62006-03-20 22:37:04 -0800225static int link_blocked(struct link *l_ptr)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100226{
227 return (l_ptr->exp_msg_count || l_ptr->blocked);
228}
229
Sam Ravnborg05790c62006-03-20 22:37:04 -0800230static int link_congested(struct link *l_ptr)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100231{
232 return (l_ptr->out_queue_size >= l_ptr->queue_limit[0]);
233}
234
Sam Ravnborg05790c62006-03-20 22:37:04 -0800235static void link_init_max_pkt(struct link *l_ptr)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100236{
237 u32 max_pkt;
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900238
Per Lidenb97bf3f2006-01-02 19:04:38 +0100239 max_pkt = (l_ptr->b_ptr->publ.mtu & ~3);
240 if (max_pkt > MAX_MSG_SIZE)
241 max_pkt = MAX_MSG_SIZE;
242
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900243 l_ptr->max_pkt_target = max_pkt;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100244 if (l_ptr->max_pkt_target < MAX_PKT_DEFAULT)
245 l_ptr->max_pkt = l_ptr->max_pkt_target;
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900246 else
Per Lidenb97bf3f2006-01-02 19:04:38 +0100247 l_ptr->max_pkt = MAX_PKT_DEFAULT;
248
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900249 l_ptr->max_pkt_probes = 0;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100250}
251
Sam Ravnborg05790c62006-03-20 22:37:04 -0800252static u32 link_next_sent(struct link *l_ptr)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100253{
254 if (l_ptr->next_out)
255 return msg_seqno(buf_msg(l_ptr->next_out));
256 return mod(l_ptr->next_out_no);
257}
258
Sam Ravnborg05790c62006-03-20 22:37:04 -0800259static u32 link_last_sent(struct link *l_ptr)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100260{
261 return mod(link_next_sent(l_ptr) - 1);
262}
263
264/*
Sam Ravnborg05790c62006-03-20 22:37:04 -0800265 * Simple non-static link routines (i.e. referenced outside this file)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100266 */
267
Per Liden4323add2006-01-18 00:38:21 +0100268int tipc_link_is_up(struct link *l_ptr)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100269{
270 if (!l_ptr)
271 return 0;
272 return (link_working_working(l_ptr) || link_working_unknown(l_ptr));
273}
274
Per Liden4323add2006-01-18 00:38:21 +0100275int tipc_link_is_active(struct link *l_ptr)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100276{
277 return ((l_ptr->owner->active_links[0] == l_ptr) ||
278 (l_ptr->owner->active_links[1] == l_ptr));
279}
280
281/**
282 * link_name_validate - validate & (optionally) deconstruct link name
283 * @name - ptr to link name string
284 * @name_parts - ptr to area for link name components (or NULL if not needed)
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900285 *
Per Lidenb97bf3f2006-01-02 19:04:38 +0100286 * Returns 1 if link name is valid, otherwise 0.
287 */
288
289static int link_name_validate(const char *name, struct link_name *name_parts)
290{
291 char name_copy[TIPC_MAX_LINK_NAME];
292 char *addr_local;
293 char *if_local;
294 char *addr_peer;
295 char *if_peer;
296 char dummy;
297 u32 z_local, c_local, n_local;
298 u32 z_peer, c_peer, n_peer;
299 u32 if_local_len;
300 u32 if_peer_len;
301
302 /* copy link name & ensure length is OK */
303
304 name_copy[TIPC_MAX_LINK_NAME - 1] = 0;
305 /* need above in case non-Posix strncpy() doesn't pad with nulls */
306 strncpy(name_copy, name, TIPC_MAX_LINK_NAME);
307 if (name_copy[TIPC_MAX_LINK_NAME - 1] != 0)
308 return 0;
309
310 /* ensure all component parts of link name are present */
311
312 addr_local = name_copy;
313 if ((if_local = strchr(addr_local, ':')) == NULL)
314 return 0;
315 *(if_local++) = 0;
316 if ((addr_peer = strchr(if_local, '-')) == NULL)
317 return 0;
318 *(addr_peer++) = 0;
319 if_local_len = addr_peer - if_local;
320 if ((if_peer = strchr(addr_peer, ':')) == NULL)
321 return 0;
322 *(if_peer++) = 0;
323 if_peer_len = strlen(if_peer) + 1;
324
325 /* validate component parts of link name */
326
327 if ((sscanf(addr_local, "%u.%u.%u%c",
328 &z_local, &c_local, &n_local, &dummy) != 3) ||
329 (sscanf(addr_peer, "%u.%u.%u%c",
330 &z_peer, &c_peer, &n_peer, &dummy) != 3) ||
331 (z_local > 255) || (c_local > 4095) || (n_local > 4095) ||
332 (z_peer > 255) || (c_peer > 4095) || (n_peer > 4095) ||
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900333 (if_local_len <= 1) || (if_local_len > TIPC_MAX_IF_NAME) ||
334 (if_peer_len <= 1) || (if_peer_len > TIPC_MAX_IF_NAME) ||
Per Lidenb97bf3f2006-01-02 19:04:38 +0100335 (strspn(if_local, tipc_alphabet) != (if_local_len - 1)) ||
336 (strspn(if_peer, tipc_alphabet) != (if_peer_len - 1)))
337 return 0;
338
339 /* return link name components, if necessary */
340
341 if (name_parts) {
342 name_parts->addr_local = tipc_addr(z_local, c_local, n_local);
343 strcpy(name_parts->if_local, if_local);
344 name_parts->addr_peer = tipc_addr(z_peer, c_peer, n_peer);
345 strcpy(name_parts->if_peer, if_peer);
346 }
347 return 1;
348}
349
350/**
351 * link_timeout - handle expiration of link timer
352 * @l_ptr: pointer to link
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900353 *
Per Liden4323add2006-01-18 00:38:21 +0100354 * This routine must not grab "tipc_net_lock" to avoid a potential deadlock conflict
355 * with tipc_link_delete(). (There is no risk that the node will be deleted by
356 * another thread because tipc_link_delete() always cancels the link timer before
357 * tipc_node_delete() is called.)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100358 */
359
360static void link_timeout(struct link *l_ptr)
361{
Per Liden4323add2006-01-18 00:38:21 +0100362 tipc_node_lock(l_ptr->owner);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100363
364 /* update counters used in statistical profiling of send traffic */
365
366 l_ptr->stats.accu_queue_sz += l_ptr->out_queue_size;
367 l_ptr->stats.queue_sz_counts++;
368
369 if (l_ptr->out_queue_size > l_ptr->stats.max_queue_sz)
370 l_ptr->stats.max_queue_sz = l_ptr->out_queue_size;
371
372 if (l_ptr->first_out) {
373 struct tipc_msg *msg = buf_msg(l_ptr->first_out);
374 u32 length = msg_size(msg);
375
Joe Perchesf64f9e72009-11-29 16:55:45 -0800376 if ((msg_user(msg) == MSG_FRAGMENTER) &&
377 (msg_type(msg) == FIRST_FRAGMENT)) {
Per Lidenb97bf3f2006-01-02 19:04:38 +0100378 length = msg_size(msg_get_wrapped(msg));
379 }
380 if (length) {
381 l_ptr->stats.msg_lengths_total += length;
382 l_ptr->stats.msg_length_counts++;
383 if (length <= 64)
384 l_ptr->stats.msg_length_profile[0]++;
385 else if (length <= 256)
386 l_ptr->stats.msg_length_profile[1]++;
387 else if (length <= 1024)
388 l_ptr->stats.msg_length_profile[2]++;
389 else if (length <= 4096)
390 l_ptr->stats.msg_length_profile[3]++;
391 else if (length <= 16384)
392 l_ptr->stats.msg_length_profile[4]++;
393 else if (length <= 32768)
394 l_ptr->stats.msg_length_profile[5]++;
395 else
396 l_ptr->stats.msg_length_profile[6]++;
397 }
398 }
399
400 /* do all other link processing performed on a periodic basis */
401
402 link_check_defragm_bufs(l_ptr);
403
404 link_state_event(l_ptr, TIMEOUT_EVT);
405
406 if (l_ptr->next_out)
Per Liden4323add2006-01-18 00:38:21 +0100407 tipc_link_push_queue(l_ptr);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100408
Per Liden4323add2006-01-18 00:38:21 +0100409 tipc_node_unlock(l_ptr->owner);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100410}
411
Sam Ravnborg05790c62006-03-20 22:37:04 -0800412static void link_set_timer(struct link *l_ptr, u32 time)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100413{
414 k_start_timer(&l_ptr->timer, time);
415}
416
417/**
Per Liden4323add2006-01-18 00:38:21 +0100418 * tipc_link_create - create a new link
Per Lidenb97bf3f2006-01-02 19:04:38 +0100419 * @b_ptr: pointer to associated bearer
420 * @peer: network address of node at other end of link
421 * @media_addr: media address to use when sending messages over link
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900422 *
Per Lidenb97bf3f2006-01-02 19:04:38 +0100423 * Returns pointer to link.
424 */
425
Per Liden4323add2006-01-18 00:38:21 +0100426struct link *tipc_link_create(struct bearer *b_ptr, const u32 peer,
427 const struct tipc_media_addr *media_addr)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100428{
429 struct link *l_ptr;
430 struct tipc_msg *msg;
431 char *if_name;
432
Panagiotis Issaris0da974f2006-07-21 14:51:30 -0700433 l_ptr = kzalloc(sizeof(*l_ptr), GFP_ATOMIC);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100434 if (!l_ptr) {
Allan Stephensa10bd922006-06-25 23:52:17 -0700435 warn("Link creation failed, no memory\n");
Per Lidenb97bf3f2006-01-02 19:04:38 +0100436 return NULL;
437 }
Per Lidenb97bf3f2006-01-02 19:04:38 +0100438
Florian Westphal945710652007-07-26 00:05:07 -0700439 if (LINK_LOG_BUF_SIZE) {
440 char *pb = kmalloc(LINK_LOG_BUF_SIZE, GFP_ATOMIC);
441
442 if (!pb) {
443 kfree(l_ptr);
444 warn("Link creation failed, no memory for print buffer\n");
445 return NULL;
446 }
447 tipc_printbuf_init(&l_ptr->print_buf, pb, LINK_LOG_BUF_SIZE);
448 }
449
Per Lidenb97bf3f2006-01-02 19:04:38 +0100450 l_ptr->addr = peer;
451 if_name = strchr(b_ptr->publ.name, ':') + 1;
452 sprintf(l_ptr->name, "%u.%u.%u:%s-%u.%u.%u:",
453 tipc_zone(tipc_own_addr), tipc_cluster(tipc_own_addr),
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900454 tipc_node(tipc_own_addr),
Per Lidenb97bf3f2006-01-02 19:04:38 +0100455 if_name,
456 tipc_zone(peer), tipc_cluster(peer), tipc_node(peer));
457 /* note: peer i/f is appended to link name by reset/activate */
458 memcpy(&l_ptr->media_addr, media_addr, sizeof(*media_addr));
Per Lidenb97bf3f2006-01-02 19:04:38 +0100459 l_ptr->checkpoint = 1;
460 l_ptr->b_ptr = b_ptr;
461 link_set_supervision_props(l_ptr, b_ptr->media->tolerance);
462 l_ptr->state = RESET_UNKNOWN;
463
464 l_ptr->pmsg = (struct tipc_msg *)&l_ptr->proto_msg;
465 msg = l_ptr->pmsg;
Allan Stephens75715212008-06-04 17:37:34 -0700466 msg_init(msg, LINK_PROTOCOL, RESET_MSG, INT_H_SIZE, l_ptr->addr);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100467 msg_set_size(msg, sizeof(l_ptr->proto_msg));
Allan Stephensa686e682008-06-04 17:29:39 -0700468 msg_set_session(msg, (tipc_random & 0xffff));
Per Lidenb97bf3f2006-01-02 19:04:38 +0100469 msg_set_bearer_id(msg, b_ptr->identity);
470 strcpy((char *)msg_data(msg), if_name);
471
472 l_ptr->priority = b_ptr->priority;
Per Liden4323add2006-01-18 00:38:21 +0100473 tipc_link_set_queue_limits(l_ptr, b_ptr->media->window);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100474
475 link_init_max_pkt(l_ptr);
476
477 l_ptr->next_out_no = 1;
478 INIT_LIST_HEAD(&l_ptr->waiting_ports);
479
480 link_reset_statistics(l_ptr);
481
Per Liden4323add2006-01-18 00:38:21 +0100482 l_ptr->owner = tipc_node_attach_link(l_ptr);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100483 if (!l_ptr->owner) {
Florian Westphal945710652007-07-26 00:05:07 -0700484 if (LINK_LOG_BUF_SIZE)
485 kfree(l_ptr->print_buf.buf);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100486 kfree(l_ptr);
487 return NULL;
488 }
489
Florian Westphal945710652007-07-26 00:05:07 -0700490 k_init_timer(&l_ptr->timer, (Handler)link_timeout, (unsigned long)l_ptr);
491 list_add_tail(&l_ptr->link_list, &b_ptr->links);
Per Liden4323add2006-01-18 00:38:21 +0100492 tipc_k_signal((Handler)tipc_link_start, (unsigned long)l_ptr);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100493
Per Liden4323add2006-01-18 00:38:21 +0100494 dbg("tipc_link_create(): tolerance = %u,cont intv = %u, abort_limit = %u\n",
Per Lidenb97bf3f2006-01-02 19:04:38 +0100495 l_ptr->tolerance, l_ptr->continuity_interval, l_ptr->abort_limit);
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900496
Per Lidenb97bf3f2006-01-02 19:04:38 +0100497 return l_ptr;
498}
499
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900500/**
Per Liden4323add2006-01-18 00:38:21 +0100501 * tipc_link_delete - delete a link
Per Lidenb97bf3f2006-01-02 19:04:38 +0100502 * @l_ptr: pointer to link
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900503 *
Per Liden4323add2006-01-18 00:38:21 +0100504 * Note: 'tipc_net_lock' is write_locked, bearer is locked.
Per Lidenb97bf3f2006-01-02 19:04:38 +0100505 * This routine must not grab the node lock until after link timer cancellation
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900506 * to avoid a potential deadlock situation.
Per Lidenb97bf3f2006-01-02 19:04:38 +0100507 */
508
Per Liden4323add2006-01-18 00:38:21 +0100509void tipc_link_delete(struct link *l_ptr)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100510{
511 if (!l_ptr) {
512 err("Attempt to delete non-existent link\n");
513 return;
514 }
515
Per Liden4323add2006-01-18 00:38:21 +0100516 dbg("tipc_link_delete()\n");
Per Lidenb97bf3f2006-01-02 19:04:38 +0100517
518 k_cancel_timer(&l_ptr->timer);
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900519
Per Liden4323add2006-01-18 00:38:21 +0100520 tipc_node_lock(l_ptr->owner);
521 tipc_link_reset(l_ptr);
522 tipc_node_detach_link(l_ptr->owner, l_ptr);
523 tipc_link_stop(l_ptr);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100524 list_del_init(&l_ptr->link_list);
525 if (LINK_LOG_BUF_SIZE)
526 kfree(l_ptr->print_buf.buf);
Per Liden4323add2006-01-18 00:38:21 +0100527 tipc_node_unlock(l_ptr->owner);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100528 k_term_timer(&l_ptr->timer);
529 kfree(l_ptr);
530}
531
Per Liden4323add2006-01-18 00:38:21 +0100532void tipc_link_start(struct link *l_ptr)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100533{
Per Liden4323add2006-01-18 00:38:21 +0100534 dbg("tipc_link_start %x\n", l_ptr);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100535 link_state_event(l_ptr, STARTING_EVT);
536}
537
538/**
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900539 * link_schedule_port - schedule port for deferred sending
Per Lidenb97bf3f2006-01-02 19:04:38 +0100540 * @l_ptr: pointer to link
541 * @origport: reference to sending port
542 * @sz: amount of data to be sent
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900543 *
544 * Schedules port for renewed sending of messages after link congestion
Per Lidenb97bf3f2006-01-02 19:04:38 +0100545 * has abated.
546 */
547
548static int link_schedule_port(struct link *l_ptr, u32 origport, u32 sz)
549{
550 struct port *p_ptr;
551
Per Liden4323add2006-01-18 00:38:21 +0100552 spin_lock_bh(&tipc_port_list_lock);
553 p_ptr = tipc_port_lock(origport);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100554 if (p_ptr) {
555 if (!p_ptr->wakeup)
556 goto exit;
557 if (!list_empty(&p_ptr->wait_list))
558 goto exit;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100559 p_ptr->publ.congested = 1;
Allan Stephens15e979d2010-05-11 14:30:10 +0000560 p_ptr->waiting_pkts = 1 + ((sz - 1) / l_ptr->max_pkt);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100561 list_add_tail(&p_ptr->wait_list, &l_ptr->waiting_ports);
562 l_ptr->stats.link_congs++;
563exit:
Per Liden4323add2006-01-18 00:38:21 +0100564 tipc_port_unlock(p_ptr);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100565 }
Per Liden4323add2006-01-18 00:38:21 +0100566 spin_unlock_bh(&tipc_port_list_lock);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100567 return -ELINKCONG;
568}
569
Per Liden4323add2006-01-18 00:38:21 +0100570void tipc_link_wakeup_ports(struct link *l_ptr, int all)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100571{
572 struct port *p_ptr;
573 struct port *temp_p_ptr;
574 int win = l_ptr->queue_limit[0] - l_ptr->out_queue_size;
575
576 if (all)
577 win = 100000;
578 if (win <= 0)
579 return;
Per Liden4323add2006-01-18 00:38:21 +0100580 if (!spin_trylock_bh(&tipc_port_list_lock))
Per Lidenb97bf3f2006-01-02 19:04:38 +0100581 return;
582 if (link_congested(l_ptr))
583 goto exit;
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900584 list_for_each_entry_safe(p_ptr, temp_p_ptr, &l_ptr->waiting_ports,
Per Lidenb97bf3f2006-01-02 19:04:38 +0100585 wait_list) {
586 if (win <= 0)
587 break;
588 list_del_init(&p_ptr->wait_list);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100589 spin_lock_bh(p_ptr->publ.lock);
590 p_ptr->publ.congested = 0;
591 p_ptr->wakeup(&p_ptr->publ);
592 win -= p_ptr->waiting_pkts;
593 spin_unlock_bh(p_ptr->publ.lock);
594 }
595
596exit:
Per Liden4323add2006-01-18 00:38:21 +0100597 spin_unlock_bh(&tipc_port_list_lock);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100598}
599
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900600/**
Per Lidenb97bf3f2006-01-02 19:04:38 +0100601 * link_release_outqueue - purge link's outbound message queue
602 * @l_ptr: pointer to link
603 */
604
605static void link_release_outqueue(struct link *l_ptr)
606{
607 struct sk_buff *buf = l_ptr->first_out;
608 struct sk_buff *next;
609
610 while (buf) {
611 next = buf->next;
612 buf_discard(buf);
613 buf = next;
614 }
615 l_ptr->first_out = NULL;
616 l_ptr->out_queue_size = 0;
617}
618
619/**
Per Liden4323add2006-01-18 00:38:21 +0100620 * tipc_link_reset_fragments - purge link's inbound message fragments queue
Per Lidenb97bf3f2006-01-02 19:04:38 +0100621 * @l_ptr: pointer to link
622 */
623
Per Liden4323add2006-01-18 00:38:21 +0100624void tipc_link_reset_fragments(struct link *l_ptr)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100625{
626 struct sk_buff *buf = l_ptr->defragm_buf;
627 struct sk_buff *next;
628
629 while (buf) {
630 next = buf->next;
631 buf_discard(buf);
632 buf = next;
633 }
634 l_ptr->defragm_buf = NULL;
635}
636
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900637/**
Per Liden4323add2006-01-18 00:38:21 +0100638 * tipc_link_stop - purge all inbound and outbound messages associated with link
Per Lidenb97bf3f2006-01-02 19:04:38 +0100639 * @l_ptr: pointer to link
640 */
641
Per Liden4323add2006-01-18 00:38:21 +0100642void tipc_link_stop(struct link *l_ptr)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100643{
644 struct sk_buff *buf;
645 struct sk_buff *next;
646
647 buf = l_ptr->oldest_deferred_in;
648 while (buf) {
649 next = buf->next;
650 buf_discard(buf);
651 buf = next;
652 }
653
654 buf = l_ptr->first_out;
655 while (buf) {
656 next = buf->next;
657 buf_discard(buf);
658 buf = next;
659 }
660
Per Liden4323add2006-01-18 00:38:21 +0100661 tipc_link_reset_fragments(l_ptr);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100662
663 buf_discard(l_ptr->proto_msg_queue);
664 l_ptr->proto_msg_queue = NULL;
665}
666
667#if 0
668
669/* LINK EVENT CODE IS NOT SUPPORTED AT PRESENT */
670
671static void link_recv_event(struct link_event *ev)
672{
673 ev->fcn(ev->addr, ev->name, ev->up);
674 kfree(ev);
675}
676
677static void link_send_event(void (*fcn)(u32 a, char *n, int up),
678 struct link *l_ptr, int up)
679{
680 struct link_event *ev;
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900681
Per Lidenb97bf3f2006-01-02 19:04:38 +0100682 ev = kmalloc(sizeof(*ev), GFP_ATOMIC);
683 if (!ev) {
684 warn("Link event allocation failure\n");
685 return;
686 }
687 ev->addr = l_ptr->addr;
688 ev->up = up;
689 ev->fcn = fcn;
690 memcpy(ev->name, l_ptr->name, TIPC_MAX_LINK_NAME);
Per Liden4323add2006-01-18 00:38:21 +0100691 tipc_k_signal((Handler)link_recv_event, (unsigned long)ev);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100692}
693
694#else
695
696#define link_send_event(fcn, l_ptr, up) do { } while (0)
697
698#endif
699
Per Liden4323add2006-01-18 00:38:21 +0100700void tipc_link_reset(struct link *l_ptr)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100701{
702 struct sk_buff *buf;
703 u32 prev_state = l_ptr->state;
704 u32 checkpoint = l_ptr->next_in_no;
Allan Stephens5392d642006-06-25 23:52:50 -0700705 int was_active_link = tipc_link_is_active(l_ptr);
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900706
Allan Stephensa686e682008-06-04 17:29:39 -0700707 msg_set_session(l_ptr->pmsg, ((msg_session(l_ptr->pmsg) + 1) & 0xffff));
Per Lidenb97bf3f2006-01-02 19:04:38 +0100708
Allan Stephensa686e682008-06-04 17:29:39 -0700709 /* Link is down, accept any session */
710 l_ptr->peer_session = INVALID_SESSION;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100711
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900712 /* Prepare for max packet size negotiation */
Per Lidenb97bf3f2006-01-02 19:04:38 +0100713 link_init_max_pkt(l_ptr);
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900714
Per Lidenb97bf3f2006-01-02 19:04:38 +0100715 l_ptr->state = RESET_UNKNOWN;
716 dbg_link_state("Resetting Link\n");
717
718 if ((prev_state == RESET_UNKNOWN) || (prev_state == RESET_RESET))
719 return;
720
Per Liden4323add2006-01-18 00:38:21 +0100721 tipc_node_link_down(l_ptr->owner, l_ptr);
722 tipc_bearer_remove_dest(l_ptr->b_ptr, l_ptr->addr);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100723#if 0
Per Liden4323add2006-01-18 00:38:21 +0100724 tipc_printf(TIPC_CONS, "\nReset link <%s>\n", l_ptr->name);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100725 dbg_link_dump();
726#endif
Allan Stephens5392d642006-06-25 23:52:50 -0700727 if (was_active_link && tipc_node_has_active_links(l_ptr->owner) &&
Per Lidenb97bf3f2006-01-02 19:04:38 +0100728 l_ptr->owner->permit_changeover) {
729 l_ptr->reset_checkpoint = checkpoint;
730 l_ptr->exp_msg_count = START_CHANGEOVER;
731 }
732
733 /* Clean up all queues: */
734
735 link_release_outqueue(l_ptr);
736 buf_discard(l_ptr->proto_msg_queue);
737 l_ptr->proto_msg_queue = NULL;
738 buf = l_ptr->oldest_deferred_in;
739 while (buf) {
740 struct sk_buff *next = buf->next;
741 buf_discard(buf);
742 buf = next;
743 }
744 if (!list_empty(&l_ptr->waiting_ports))
Per Liden4323add2006-01-18 00:38:21 +0100745 tipc_link_wakeup_ports(l_ptr, 1);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100746
747 l_ptr->retransm_queue_head = 0;
748 l_ptr->retransm_queue_size = 0;
749 l_ptr->last_out = NULL;
750 l_ptr->first_out = NULL;
751 l_ptr->next_out = NULL;
752 l_ptr->unacked_window = 0;
753 l_ptr->checkpoint = 1;
754 l_ptr->next_out_no = 1;
755 l_ptr->deferred_inqueue_sz = 0;
756 l_ptr->oldest_deferred_in = NULL;
757 l_ptr->newest_deferred_in = NULL;
758 l_ptr->fsm_msg_cnt = 0;
759 l_ptr->stale_count = 0;
760 link_reset_statistics(l_ptr);
761
Per Liden4323add2006-01-18 00:38:21 +0100762 link_send_event(tipc_cfg_link_event, l_ptr, 0);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100763 if (!in_own_cluster(l_ptr->addr))
Per Liden4323add2006-01-18 00:38:21 +0100764 link_send_event(tipc_disc_link_event, l_ptr, 0);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100765}
766
767
768static void link_activate(struct link *l_ptr)
769{
Allan Stephens5392d642006-06-25 23:52:50 -0700770 l_ptr->next_in_no = l_ptr->stats.recv_info = 1;
Per Liden4323add2006-01-18 00:38:21 +0100771 tipc_node_link_up(l_ptr->owner, l_ptr);
772 tipc_bearer_add_dest(l_ptr->b_ptr, l_ptr->addr);
773 link_send_event(tipc_cfg_link_event, l_ptr, 1);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100774 if (!in_own_cluster(l_ptr->addr))
Per Liden4323add2006-01-18 00:38:21 +0100775 link_send_event(tipc_disc_link_event, l_ptr, 1);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100776}
777
778/**
779 * link_state_event - link finite state machine
780 * @l_ptr: pointer to link
781 * @event: state machine event to process
782 */
783
784static void link_state_event(struct link *l_ptr, unsigned event)
785{
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900786 struct link *other;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100787 u32 cont_intv = l_ptr->continuity_interval;
788
789 if (!l_ptr->started && (event != STARTING_EVT))
790 return; /* Not yet. */
791
792 if (link_blocked(l_ptr)) {
793 if (event == TIMEOUT_EVT) {
794 link_set_timer(l_ptr, cont_intv);
795 }
796 return; /* Changeover going on */
797 }
798 dbg_link("STATE_EV: <%s> ", l_ptr->name);
799
800 switch (l_ptr->state) {
801 case WORKING_WORKING:
802 dbg_link("WW/");
803 switch (event) {
804 case TRAFFIC_MSG_EVT:
805 dbg_link("TRF-");
806 /* fall through */
807 case ACTIVATE_MSG:
808 dbg_link("ACT\n");
809 break;
810 case TIMEOUT_EVT:
811 dbg_link("TIM ");
812 if (l_ptr->next_in_no != l_ptr->checkpoint) {
813 l_ptr->checkpoint = l_ptr->next_in_no;
Per Liden4323add2006-01-18 00:38:21 +0100814 if (tipc_bclink_acks_missing(l_ptr->owner)) {
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900815 tipc_link_send_proto_msg(l_ptr, STATE_MSG,
Per Liden4323add2006-01-18 00:38:21 +0100816 0, 0, 0, 0, 0);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100817 l_ptr->fsm_msg_cnt++;
818 } else if (l_ptr->max_pkt < l_ptr->max_pkt_target) {
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900819 tipc_link_send_proto_msg(l_ptr, STATE_MSG,
Per Liden4323add2006-01-18 00:38:21 +0100820 1, 0, 0, 0, 0);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100821 l_ptr->fsm_msg_cnt++;
822 }
823 link_set_timer(l_ptr, cont_intv);
824 break;
825 }
826 dbg_link(" -> WU\n");
827 l_ptr->state = WORKING_UNKNOWN;
828 l_ptr->fsm_msg_cnt = 0;
Per Liden4323add2006-01-18 00:38:21 +0100829 tipc_link_send_proto_msg(l_ptr, STATE_MSG, 1, 0, 0, 0, 0);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100830 l_ptr->fsm_msg_cnt++;
831 link_set_timer(l_ptr, cont_intv / 4);
832 break;
833 case RESET_MSG:
834 dbg_link("RES -> RR\n");
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900835 info("Resetting link <%s>, requested by peer\n",
Allan Stephensa10bd922006-06-25 23:52:17 -0700836 l_ptr->name);
Per Liden4323add2006-01-18 00:38:21 +0100837 tipc_link_reset(l_ptr);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100838 l_ptr->state = RESET_RESET;
839 l_ptr->fsm_msg_cnt = 0;
Per Liden4323add2006-01-18 00:38:21 +0100840 tipc_link_send_proto_msg(l_ptr, ACTIVATE_MSG, 0, 0, 0, 0, 0);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100841 l_ptr->fsm_msg_cnt++;
842 link_set_timer(l_ptr, cont_intv);
843 break;
844 default:
845 err("Unknown link event %u in WW state\n", event);
846 }
847 break;
848 case WORKING_UNKNOWN:
849 dbg_link("WU/");
850 switch (event) {
851 case TRAFFIC_MSG_EVT:
852 dbg_link("TRF-");
853 case ACTIVATE_MSG:
854 dbg_link("ACT -> WW\n");
855 l_ptr->state = WORKING_WORKING;
856 l_ptr->fsm_msg_cnt = 0;
857 link_set_timer(l_ptr, cont_intv);
858 break;
859 case RESET_MSG:
860 dbg_link("RES -> RR\n");
Allan Stephensa10bd922006-06-25 23:52:17 -0700861 info("Resetting link <%s>, requested by peer "
862 "while probing\n", l_ptr->name);
Per Liden4323add2006-01-18 00:38:21 +0100863 tipc_link_reset(l_ptr);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100864 l_ptr->state = RESET_RESET;
865 l_ptr->fsm_msg_cnt = 0;
Per Liden4323add2006-01-18 00:38:21 +0100866 tipc_link_send_proto_msg(l_ptr, ACTIVATE_MSG, 0, 0, 0, 0, 0);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100867 l_ptr->fsm_msg_cnt++;
868 link_set_timer(l_ptr, cont_intv);
869 break;
870 case TIMEOUT_EVT:
871 dbg_link("TIM ");
872 if (l_ptr->next_in_no != l_ptr->checkpoint) {
Frans Popa570f092010-03-24 07:57:29 +0000873 dbg_link("-> WW\n");
Per Lidenb97bf3f2006-01-02 19:04:38 +0100874 l_ptr->state = WORKING_WORKING;
875 l_ptr->fsm_msg_cnt = 0;
876 l_ptr->checkpoint = l_ptr->next_in_no;
Per Liden4323add2006-01-18 00:38:21 +0100877 if (tipc_bclink_acks_missing(l_ptr->owner)) {
878 tipc_link_send_proto_msg(l_ptr, STATE_MSG,
879 0, 0, 0, 0, 0);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100880 l_ptr->fsm_msg_cnt++;
881 }
882 link_set_timer(l_ptr, cont_intv);
883 } else if (l_ptr->fsm_msg_cnt < l_ptr->abort_limit) {
884 dbg_link("Probing %u/%u,timer = %u ms)\n",
885 l_ptr->fsm_msg_cnt, l_ptr->abort_limit,
886 cont_intv / 4);
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900887 tipc_link_send_proto_msg(l_ptr, STATE_MSG,
Per Liden4323add2006-01-18 00:38:21 +0100888 1, 0, 0, 0, 0);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100889 l_ptr->fsm_msg_cnt++;
890 link_set_timer(l_ptr, cont_intv / 4);
891 } else { /* Link has failed */
892 dbg_link("-> RU (%u probes unanswered)\n",
893 l_ptr->fsm_msg_cnt);
Allan Stephensa10bd922006-06-25 23:52:17 -0700894 warn("Resetting link <%s>, peer not responding\n",
895 l_ptr->name);
Per Liden4323add2006-01-18 00:38:21 +0100896 tipc_link_reset(l_ptr);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100897 l_ptr->state = RESET_UNKNOWN;
898 l_ptr->fsm_msg_cnt = 0;
Per Liden4323add2006-01-18 00:38:21 +0100899 tipc_link_send_proto_msg(l_ptr, RESET_MSG,
900 0, 0, 0, 0, 0);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100901 l_ptr->fsm_msg_cnt++;
902 link_set_timer(l_ptr, cont_intv);
903 }
904 break;
905 default:
906 err("Unknown link event %u in WU state\n", event);
907 }
908 break;
909 case RESET_UNKNOWN:
910 dbg_link("RU/");
911 switch (event) {
912 case TRAFFIC_MSG_EVT:
913 dbg_link("TRF-\n");
914 break;
915 case ACTIVATE_MSG:
916 other = l_ptr->owner->active_links[0];
917 if (other && link_working_unknown(other)) {
918 dbg_link("ACT\n");
919 break;
920 }
921 dbg_link("ACT -> WW\n");
922 l_ptr->state = WORKING_WORKING;
923 l_ptr->fsm_msg_cnt = 0;
924 link_activate(l_ptr);
Per Liden4323add2006-01-18 00:38:21 +0100925 tipc_link_send_proto_msg(l_ptr, STATE_MSG, 1, 0, 0, 0, 0);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100926 l_ptr->fsm_msg_cnt++;
927 link_set_timer(l_ptr, cont_intv);
928 break;
929 case RESET_MSG:
Frans Popa570f092010-03-24 07:57:29 +0000930 dbg_link("RES\n");
Per Lidenb97bf3f2006-01-02 19:04:38 +0100931 dbg_link(" -> RR\n");
932 l_ptr->state = RESET_RESET;
933 l_ptr->fsm_msg_cnt = 0;
Per Liden4323add2006-01-18 00:38:21 +0100934 tipc_link_send_proto_msg(l_ptr, ACTIVATE_MSG, 1, 0, 0, 0, 0);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100935 l_ptr->fsm_msg_cnt++;
936 link_set_timer(l_ptr, cont_intv);
937 break;
938 case STARTING_EVT:
939 dbg_link("START-");
940 l_ptr->started = 1;
941 /* fall through */
942 case TIMEOUT_EVT:
Frans Popa570f092010-03-24 07:57:29 +0000943 dbg_link("TIM\n");
Per Liden4323add2006-01-18 00:38:21 +0100944 tipc_link_send_proto_msg(l_ptr, RESET_MSG, 0, 0, 0, 0, 0);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100945 l_ptr->fsm_msg_cnt++;
946 link_set_timer(l_ptr, cont_intv);
947 break;
948 default:
949 err("Unknown link event %u in RU state\n", event);
950 }
951 break;
952 case RESET_RESET:
953 dbg_link("RR/ ");
954 switch (event) {
955 case TRAFFIC_MSG_EVT:
956 dbg_link("TRF-");
957 /* fall through */
958 case ACTIVATE_MSG:
959 other = l_ptr->owner->active_links[0];
960 if (other && link_working_unknown(other)) {
961 dbg_link("ACT\n");
962 break;
963 }
964 dbg_link("ACT -> WW\n");
965 l_ptr->state = WORKING_WORKING;
966 l_ptr->fsm_msg_cnt = 0;
967 link_activate(l_ptr);
Per Liden4323add2006-01-18 00:38:21 +0100968 tipc_link_send_proto_msg(l_ptr, STATE_MSG, 1, 0, 0, 0, 0);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100969 l_ptr->fsm_msg_cnt++;
970 link_set_timer(l_ptr, cont_intv);
971 break;
972 case RESET_MSG:
973 dbg_link("RES\n");
974 break;
975 case TIMEOUT_EVT:
976 dbg_link("TIM\n");
Per Liden4323add2006-01-18 00:38:21 +0100977 tipc_link_send_proto_msg(l_ptr, ACTIVATE_MSG, 0, 0, 0, 0, 0);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100978 l_ptr->fsm_msg_cnt++;
979 link_set_timer(l_ptr, cont_intv);
980 dbg_link("fsm_msg_cnt %u\n", l_ptr->fsm_msg_cnt);
981 break;
982 default:
983 err("Unknown link event %u in RR state\n", event);
984 }
985 break;
986 default:
987 err("Unknown link state %u/%u\n", l_ptr->state, event);
988 }
989}
990
991/*
992 * link_bundle_buf(): Append contents of a buffer to
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900993 * the tail of an existing one.
Per Lidenb97bf3f2006-01-02 19:04:38 +0100994 */
995
996static int link_bundle_buf(struct link *l_ptr,
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900997 struct sk_buff *bundler,
Per Lidenb97bf3f2006-01-02 19:04:38 +0100998 struct sk_buff *buf)
999{
1000 struct tipc_msg *bundler_msg = buf_msg(bundler);
1001 struct tipc_msg *msg = buf_msg(buf);
1002 u32 size = msg_size(msg);
Allan Stephense49060c2006-06-29 12:32:46 -07001003 u32 bundle_size = msg_size(bundler_msg);
1004 u32 to_pos = align(bundle_size);
1005 u32 pad = to_pos - bundle_size;
Per Lidenb97bf3f2006-01-02 19:04:38 +01001006
1007 if (msg_user(bundler_msg) != MSG_BUNDLER)
1008 return 0;
1009 if (msg_type(bundler_msg) != OPEN_MSG)
1010 return 0;
Allan Stephense49060c2006-06-29 12:32:46 -07001011 if (skb_tailroom(bundler) < (pad + size))
Per Lidenb97bf3f2006-01-02 19:04:38 +01001012 return 0;
Allan Stephens15e979d2010-05-11 14:30:10 +00001013 if (l_ptr->max_pkt < (to_pos + size))
Allan Stephens863fae62006-07-03 19:39:36 -07001014 return 0;
Per Lidenb97bf3f2006-01-02 19:04:38 +01001015
Allan Stephense49060c2006-06-29 12:32:46 -07001016 skb_put(bundler, pad + size);
Arnaldo Carvalho de Melo27d7ff42007-03-31 11:55:19 -03001017 skb_copy_to_linear_data_offset(bundler, to_pos, buf->data, size);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001018 msg_set_size(bundler_msg, to_pos + size);
1019 msg_set_msgcnt(bundler_msg, msg_msgcnt(bundler_msg) + 1);
1020 dbg("Packed msg # %u(%u octets) into pos %u in buf(#%u)\n",
1021 msg_msgcnt(bundler_msg), size, to_pos, msg_seqno(bundler_msg));
1022 msg_dbg(msg, "PACKD:");
1023 buf_discard(buf);
1024 l_ptr->stats.sent_bundled++;
1025 return 1;
1026}
1027
Sam Ravnborg05790c62006-03-20 22:37:04 -08001028static void link_add_to_outqueue(struct link *l_ptr,
1029 struct sk_buff *buf,
1030 struct tipc_msg *msg)
Per Lidenb97bf3f2006-01-02 19:04:38 +01001031{
1032 u32 ack = mod(l_ptr->next_in_no - 1);
1033 u32 seqno = mod(l_ptr->next_out_no++);
1034
1035 msg_set_word(msg, 2, ((ack << 16) | seqno));
1036 msg_set_bcast_ack(msg, l_ptr->owner->bclink.last_in);
1037 buf->next = NULL;
1038 if (l_ptr->first_out) {
1039 l_ptr->last_out->next = buf;
1040 l_ptr->last_out = buf;
1041 } else
1042 l_ptr->first_out = l_ptr->last_out = buf;
1043 l_ptr->out_queue_size++;
1044}
1045
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001046/*
1047 * tipc_link_send_buf() is the 'full path' for messages, called from
Per Lidenb97bf3f2006-01-02 19:04:38 +01001048 * inside TIPC when the 'fast path' in tipc_send_buf
1049 * has failed, and from link_send()
1050 */
1051
Per Liden4323add2006-01-18 00:38:21 +01001052int tipc_link_send_buf(struct link *l_ptr, struct sk_buff *buf)
Per Lidenb97bf3f2006-01-02 19:04:38 +01001053{
1054 struct tipc_msg *msg = buf_msg(buf);
1055 u32 size = msg_size(msg);
1056 u32 dsz = msg_data_sz(msg);
1057 u32 queue_size = l_ptr->out_queue_size;
1058 u32 imp = msg_tot_importance(msg);
1059 u32 queue_limit = l_ptr->queue_limit[imp];
Allan Stephens15e979d2010-05-11 14:30:10 +00001060 u32 max_packet = l_ptr->max_pkt;
Per Lidenb97bf3f2006-01-02 19:04:38 +01001061
1062 msg_set_prevnode(msg, tipc_own_addr); /* If routed message */
1063
1064 /* Match msg importance against queue limits: */
1065
1066 if (unlikely(queue_size >= queue_limit)) {
1067 if (imp <= TIPC_CRITICAL_IMPORTANCE) {
1068 return link_schedule_port(l_ptr, msg_origport(msg),
1069 size);
1070 }
1071 msg_dbg(msg, "TIPC: Congestion, throwing away\n");
1072 buf_discard(buf);
1073 if (imp > CONN_MANAGER) {
Allan Stephensa10bd922006-06-25 23:52:17 -07001074 warn("Resetting link <%s>, send queue full", l_ptr->name);
Per Liden4323add2006-01-18 00:38:21 +01001075 tipc_link_reset(l_ptr);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001076 }
1077 return dsz;
1078 }
1079
1080 /* Fragmentation needed ? */
1081
1082 if (size > max_packet)
Per Liden4323add2006-01-18 00:38:21 +01001083 return tipc_link_send_long_buf(l_ptr, buf);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001084
1085 /* Packet can be queued or sent: */
1086
1087 if (queue_size > l_ptr->stats.max_queue_sz)
1088 l_ptr->stats.max_queue_sz = queue_size;
1089
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001090 if (likely(!tipc_bearer_congested(l_ptr->b_ptr, l_ptr) &&
Per Lidenb97bf3f2006-01-02 19:04:38 +01001091 !link_congested(l_ptr))) {
1092 link_add_to_outqueue(l_ptr, buf, msg);
1093
Per Liden4323add2006-01-18 00:38:21 +01001094 if (likely(tipc_bearer_send(l_ptr->b_ptr, buf, &l_ptr->media_addr))) {
Per Lidenb97bf3f2006-01-02 19:04:38 +01001095 l_ptr->unacked_window = 0;
1096 } else {
Per Liden4323add2006-01-18 00:38:21 +01001097 tipc_bearer_schedule(l_ptr->b_ptr, l_ptr);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001098 l_ptr->stats.bearer_congs++;
1099 l_ptr->next_out = buf;
1100 }
1101 return dsz;
1102 }
1103 /* Congestion: can message be bundled ?: */
1104
1105 if ((msg_user(msg) != CHANGEOVER_PROTOCOL) &&
1106 (msg_user(msg) != MSG_FRAGMENTER)) {
1107
1108 /* Try adding message to an existing bundle */
1109
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001110 if (l_ptr->next_out &&
Per Lidenb97bf3f2006-01-02 19:04:38 +01001111 link_bundle_buf(l_ptr, l_ptr->last_out, buf)) {
Per Liden4323add2006-01-18 00:38:21 +01001112 tipc_bearer_resolve_congestion(l_ptr->b_ptr, l_ptr);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001113 return dsz;
1114 }
1115
1116 /* Try creating a new bundle */
1117
1118 if (size <= max_packet * 2 / 3) {
1119 struct sk_buff *bundler = buf_acquire(max_packet);
1120 struct tipc_msg bundler_hdr;
1121
1122 if (bundler) {
1123 msg_init(&bundler_hdr, MSG_BUNDLER, OPEN_MSG,
Allan Stephens75715212008-06-04 17:37:34 -07001124 INT_H_SIZE, l_ptr->addr);
Arnaldo Carvalho de Melo27d7ff42007-03-31 11:55:19 -03001125 skb_copy_to_linear_data(bundler, &bundler_hdr,
1126 INT_H_SIZE);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001127 skb_trim(bundler, INT_H_SIZE);
1128 link_bundle_buf(l_ptr, bundler, buf);
1129 buf = bundler;
1130 msg = buf_msg(buf);
1131 l_ptr->stats.sent_bundles++;
1132 }
1133 }
1134 }
1135 if (!l_ptr->next_out)
1136 l_ptr->next_out = buf;
1137 link_add_to_outqueue(l_ptr, buf, msg);
Per Liden4323add2006-01-18 00:38:21 +01001138 tipc_bearer_resolve_congestion(l_ptr->b_ptr, l_ptr);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001139 return dsz;
1140}
1141
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001142/*
1143 * tipc_link_send(): same as tipc_link_send_buf(), but the link to use has
Per Lidenb97bf3f2006-01-02 19:04:38 +01001144 * not been selected yet, and the the owner node is not locked
1145 * Called by TIPC internal users, e.g. the name distributor
1146 */
1147
Per Liden4323add2006-01-18 00:38:21 +01001148int tipc_link_send(struct sk_buff *buf, u32 dest, u32 selector)
Per Lidenb97bf3f2006-01-02 19:04:38 +01001149{
1150 struct link *l_ptr;
David S. Miller6c000552008-09-02 23:38:32 -07001151 struct tipc_node *n_ptr;
Per Lidenb97bf3f2006-01-02 19:04:38 +01001152 int res = -ELINKCONG;
1153
Per Liden4323add2006-01-18 00:38:21 +01001154 read_lock_bh(&tipc_net_lock);
1155 n_ptr = tipc_node_select(dest, selector);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001156 if (n_ptr) {
Per Liden4323add2006-01-18 00:38:21 +01001157 tipc_node_lock(n_ptr);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001158 l_ptr = n_ptr->active_links[selector & 1];
Per Lidenb97bf3f2006-01-02 19:04:38 +01001159 if (l_ptr) {
Allan Stephensc33d53b2006-06-25 23:50:30 -07001160 dbg("tipc_link_send: found link %x for dest %x\n", l_ptr, dest);
Per Liden4323add2006-01-18 00:38:21 +01001161 res = tipc_link_send_buf(l_ptr, buf);
Allan Stephensc33d53b2006-06-25 23:50:30 -07001162 } else {
1163 dbg("Attempt to send msg to unreachable node:\n");
1164 msg_dbg(buf_msg(buf),">>>");
1165 buf_discard(buf);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001166 }
Per Liden4323add2006-01-18 00:38:21 +01001167 tipc_node_unlock(n_ptr);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001168 } else {
1169 dbg("Attempt to send msg to unknown node:\n");
1170 msg_dbg(buf_msg(buf),">>>");
1171 buf_discard(buf);
1172 }
Per Liden4323add2006-01-18 00:38:21 +01001173 read_unlock_bh(&tipc_net_lock);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001174 return res;
1175}
1176
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001177/*
1178 * link_send_buf_fast: Entry for data messages where the
Per Lidenb97bf3f2006-01-02 19:04:38 +01001179 * destination link is known and the header is complete,
1180 * inclusive total message length. Very time critical.
1181 * Link is locked. Returns user data length.
1182 */
1183
Sam Ravnborg05790c62006-03-20 22:37:04 -08001184static int link_send_buf_fast(struct link *l_ptr, struct sk_buff *buf,
1185 u32 *used_max_pkt)
Per Lidenb97bf3f2006-01-02 19:04:38 +01001186{
1187 struct tipc_msg *msg = buf_msg(buf);
1188 int res = msg_data_sz(msg);
1189
1190 if (likely(!link_congested(l_ptr))) {
Allan Stephens15e979d2010-05-11 14:30:10 +00001191 if (likely(msg_size(msg) <= l_ptr->max_pkt)) {
Per Lidenb97bf3f2006-01-02 19:04:38 +01001192 if (likely(list_empty(&l_ptr->b_ptr->cong_links))) {
1193 link_add_to_outqueue(l_ptr, buf, msg);
Per Liden4323add2006-01-18 00:38:21 +01001194 if (likely(tipc_bearer_send(l_ptr->b_ptr, buf,
1195 &l_ptr->media_addr))) {
Per Lidenb97bf3f2006-01-02 19:04:38 +01001196 l_ptr->unacked_window = 0;
1197 msg_dbg(msg,"SENT_FAST:");
1198 return res;
1199 }
1200 dbg("failed sent fast...\n");
Per Liden4323add2006-01-18 00:38:21 +01001201 tipc_bearer_schedule(l_ptr->b_ptr, l_ptr);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001202 l_ptr->stats.bearer_congs++;
1203 l_ptr->next_out = buf;
1204 return res;
1205 }
1206 }
1207 else
Allan Stephens15e979d2010-05-11 14:30:10 +00001208 *used_max_pkt = l_ptr->max_pkt;
Per Lidenb97bf3f2006-01-02 19:04:38 +01001209 }
Per Liden4323add2006-01-18 00:38:21 +01001210 return tipc_link_send_buf(l_ptr, buf); /* All other cases */
Per Lidenb97bf3f2006-01-02 19:04:38 +01001211}
1212
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001213/*
1214 * tipc_send_buf_fast: Entry for data messages where the
Per Lidenb97bf3f2006-01-02 19:04:38 +01001215 * destination node is known and the header is complete,
1216 * inclusive total message length.
1217 * Returns user data length.
1218 */
1219int tipc_send_buf_fast(struct sk_buff *buf, u32 destnode)
1220{
1221 struct link *l_ptr;
David S. Miller6c000552008-09-02 23:38:32 -07001222 struct tipc_node *n_ptr;
Per Lidenb97bf3f2006-01-02 19:04:38 +01001223 int res;
1224 u32 selector = msg_origport(buf_msg(buf)) & 1;
1225 u32 dummy;
1226
1227 if (destnode == tipc_own_addr)
Per Liden4323add2006-01-18 00:38:21 +01001228 return tipc_port_recv_msg(buf);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001229
Per Liden4323add2006-01-18 00:38:21 +01001230 read_lock_bh(&tipc_net_lock);
1231 n_ptr = tipc_node_select(destnode, selector);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001232 if (likely(n_ptr)) {
Per Liden4323add2006-01-18 00:38:21 +01001233 tipc_node_lock(n_ptr);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001234 l_ptr = n_ptr->active_links[selector];
1235 dbg("send_fast: buf %x selected %x, destnode = %x\n",
1236 buf, l_ptr, destnode);
1237 if (likely(l_ptr)) {
1238 res = link_send_buf_fast(l_ptr, buf, &dummy);
Per Liden4323add2006-01-18 00:38:21 +01001239 tipc_node_unlock(n_ptr);
1240 read_unlock_bh(&tipc_net_lock);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001241 return res;
1242 }
Per Liden4323add2006-01-18 00:38:21 +01001243 tipc_node_unlock(n_ptr);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001244 }
Per Liden4323add2006-01-18 00:38:21 +01001245 read_unlock_bh(&tipc_net_lock);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001246 res = msg_data_sz(buf_msg(buf));
1247 tipc_reject_msg(buf, TIPC_ERR_NO_NODE);
1248 return res;
1249}
1250
1251
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001252/*
1253 * tipc_link_send_sections_fast: Entry for messages where the
Per Lidenb97bf3f2006-01-02 19:04:38 +01001254 * destination processor is known and the header is complete,
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001255 * except for total message length.
Per Lidenb97bf3f2006-01-02 19:04:38 +01001256 * Returns user data length or errno.
1257 */
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001258int tipc_link_send_sections_fast(struct port *sender,
Per Liden4323add2006-01-18 00:38:21 +01001259 struct iovec const *msg_sect,
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001260 const u32 num_sect,
Per Liden4323add2006-01-18 00:38:21 +01001261 u32 destaddr)
Per Lidenb97bf3f2006-01-02 19:04:38 +01001262{
1263 struct tipc_msg *hdr = &sender->publ.phdr;
1264 struct link *l_ptr;
1265 struct sk_buff *buf;
David S. Miller6c000552008-09-02 23:38:32 -07001266 struct tipc_node *node;
Per Lidenb97bf3f2006-01-02 19:04:38 +01001267 int res;
1268 u32 selector = msg_origport(hdr) & 1;
1269
Per Lidenb97bf3f2006-01-02 19:04:38 +01001270again:
1271 /*
1272 * Try building message using port's max_pkt hint.
1273 * (Must not hold any locks while building message.)
1274 */
1275
Allan Stephens05646c92007-06-10 17:25:24 -07001276 res = msg_build(hdr, msg_sect, num_sect, sender->publ.max_pkt,
Per Lidenb97bf3f2006-01-02 19:04:38 +01001277 !sender->user_port, &buf);
1278
Per Liden4323add2006-01-18 00:38:21 +01001279 read_lock_bh(&tipc_net_lock);
1280 node = tipc_node_select(destaddr, selector);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001281 if (likely(node)) {
Per Liden4323add2006-01-18 00:38:21 +01001282 tipc_node_lock(node);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001283 l_ptr = node->active_links[selector];
1284 if (likely(l_ptr)) {
1285 if (likely(buf)) {
1286 res = link_send_buf_fast(l_ptr, buf,
Allan Stephens05646c92007-06-10 17:25:24 -07001287 &sender->publ.max_pkt);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001288 if (unlikely(res < 0))
1289 buf_discard(buf);
1290exit:
Per Liden4323add2006-01-18 00:38:21 +01001291 tipc_node_unlock(node);
1292 read_unlock_bh(&tipc_net_lock);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001293 return res;
1294 }
1295
1296 /* Exit if build request was invalid */
1297
1298 if (unlikely(res < 0))
1299 goto exit;
1300
1301 /* Exit if link (or bearer) is congested */
1302
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001303 if (link_congested(l_ptr) ||
Per Lidenb97bf3f2006-01-02 19:04:38 +01001304 !list_empty(&l_ptr->b_ptr->cong_links)) {
1305 res = link_schedule_port(l_ptr,
1306 sender->publ.ref, res);
1307 goto exit;
1308 }
1309
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001310 /*
Per Lidenb97bf3f2006-01-02 19:04:38 +01001311 * Message size exceeds max_pkt hint; update hint,
1312 * then re-try fast path or fragment the message
1313 */
1314
Allan Stephens15e979d2010-05-11 14:30:10 +00001315 sender->publ.max_pkt = l_ptr->max_pkt;
Per Liden4323add2006-01-18 00:38:21 +01001316 tipc_node_unlock(node);
1317 read_unlock_bh(&tipc_net_lock);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001318
1319
Allan Stephens05646c92007-06-10 17:25:24 -07001320 if ((msg_hdr_sz(hdr) + res) <= sender->publ.max_pkt)
Per Lidenb97bf3f2006-01-02 19:04:38 +01001321 goto again;
1322
1323 return link_send_sections_long(sender, msg_sect,
1324 num_sect, destaddr);
1325 }
Per Liden4323add2006-01-18 00:38:21 +01001326 tipc_node_unlock(node);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001327 }
Per Liden4323add2006-01-18 00:38:21 +01001328 read_unlock_bh(&tipc_net_lock);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001329
1330 /* Couldn't find a link to the destination node */
1331
1332 if (buf)
1333 return tipc_reject_msg(buf, TIPC_ERR_NO_NODE);
1334 if (res >= 0)
Per Liden4323add2006-01-18 00:38:21 +01001335 return tipc_port_reject_sections(sender, hdr, msg_sect, num_sect,
1336 TIPC_ERR_NO_NODE);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001337 return res;
1338}
1339
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001340/*
1341 * link_send_sections_long(): Entry for long messages where the
Per Lidenb97bf3f2006-01-02 19:04:38 +01001342 * destination node is known and the header is complete,
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001343 * inclusive total message length.
Per Lidenb97bf3f2006-01-02 19:04:38 +01001344 * Link and bearer congestion status have been checked to be ok,
1345 * and are ignored if they change.
1346 *
1347 * Note that fragments do not use the full link MTU so that they won't have
1348 * to undergo refragmentation if link changeover causes them to be sent
1349 * over another link with an additional tunnel header added as prefix.
1350 * (Refragmentation will still occur if the other link has a smaller MTU.)
1351 *
1352 * Returns user data length or errno.
1353 */
1354static int link_send_sections_long(struct port *sender,
1355 struct iovec const *msg_sect,
1356 u32 num_sect,
1357 u32 destaddr)
1358{
1359 struct link *l_ptr;
David S. Miller6c000552008-09-02 23:38:32 -07001360 struct tipc_node *node;
Per Lidenb97bf3f2006-01-02 19:04:38 +01001361 struct tipc_msg *hdr = &sender->publ.phdr;
1362 u32 dsz = msg_data_sz(hdr);
1363 u32 max_pkt,fragm_sz,rest;
1364 struct tipc_msg fragm_hdr;
1365 struct sk_buff *buf,*buf_chain,*prev;
1366 u32 fragm_crs,fragm_rest,hsz,sect_rest;
1367 const unchar *sect_crs;
1368 int curr_sect;
1369 u32 fragm_no;
1370
1371again:
1372 fragm_no = 1;
Allan Stephens05646c92007-06-10 17:25:24 -07001373 max_pkt = sender->publ.max_pkt - INT_H_SIZE;
Per Lidenb97bf3f2006-01-02 19:04:38 +01001374 /* leave room for tunnel header in case of link changeover */
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001375 fragm_sz = max_pkt - INT_H_SIZE;
Per Lidenb97bf3f2006-01-02 19:04:38 +01001376 /* leave room for fragmentation header in each fragment */
1377 rest = dsz;
1378 fragm_crs = 0;
1379 fragm_rest = 0;
1380 sect_rest = 0;
Sam Ravnborg1fc54d82006-03-20 22:36:47 -08001381 sect_crs = NULL;
Per Lidenb97bf3f2006-01-02 19:04:38 +01001382 curr_sect = -1;
1383
1384 /* Prepare reusable fragment header: */
1385
1386 msg_dbg(hdr, ">FRAGMENTING>");
1387 msg_init(&fragm_hdr, MSG_FRAGMENTER, FIRST_FRAGMENT,
Allan Stephens75715212008-06-04 17:37:34 -07001388 INT_H_SIZE, msg_destnode(hdr));
Per Lidenb97bf3f2006-01-02 19:04:38 +01001389 msg_set_link_selector(&fragm_hdr, sender->publ.ref);
1390 msg_set_size(&fragm_hdr, max_pkt);
1391 msg_set_fragm_no(&fragm_hdr, 1);
1392
1393 /* Prepare header of first fragment: */
1394
1395 buf_chain = buf = buf_acquire(max_pkt);
1396 if (!buf)
1397 return -ENOMEM;
1398 buf->next = NULL;
Arnaldo Carvalho de Melo27d7ff42007-03-31 11:55:19 -03001399 skb_copy_to_linear_data(buf, &fragm_hdr, INT_H_SIZE);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001400 hsz = msg_hdr_sz(hdr);
Arnaldo Carvalho de Melo27d7ff42007-03-31 11:55:19 -03001401 skb_copy_to_linear_data_offset(buf, INT_H_SIZE, hdr, hsz);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001402 msg_dbg(buf_msg(buf), ">BUILD>");
1403
1404 /* Chop up message: */
1405
1406 fragm_crs = INT_H_SIZE + hsz;
1407 fragm_rest = fragm_sz - hsz;
1408
1409 do { /* For all sections */
1410 u32 sz;
1411
1412 if (!sect_rest) {
1413 sect_rest = msg_sect[++curr_sect].iov_len;
1414 sect_crs = (const unchar *)msg_sect[curr_sect].iov_base;
1415 }
1416
1417 if (sect_rest < fragm_rest)
1418 sz = sect_rest;
1419 else
1420 sz = fragm_rest;
1421
1422 if (likely(!sender->user_port)) {
1423 if (copy_from_user(buf->data + fragm_crs, sect_crs, sz)) {
1424error:
1425 for (; buf_chain; buf_chain = buf) {
1426 buf = buf_chain->next;
1427 buf_discard(buf_chain);
1428 }
1429 return -EFAULT;
1430 }
1431 } else
Arnaldo Carvalho de Melo27d7ff42007-03-31 11:55:19 -03001432 skb_copy_to_linear_data_offset(buf, fragm_crs,
1433 sect_crs, sz);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001434 sect_crs += sz;
1435 sect_rest -= sz;
1436 fragm_crs += sz;
1437 fragm_rest -= sz;
1438 rest -= sz;
1439
1440 if (!fragm_rest && rest) {
1441
1442 /* Initiate new fragment: */
1443 if (rest <= fragm_sz) {
1444 fragm_sz = rest;
1445 msg_set_type(&fragm_hdr,LAST_FRAGMENT);
1446 } else {
1447 msg_set_type(&fragm_hdr, FRAGMENT);
1448 }
1449 msg_set_size(&fragm_hdr, fragm_sz + INT_H_SIZE);
1450 msg_set_fragm_no(&fragm_hdr, ++fragm_no);
1451 prev = buf;
1452 buf = buf_acquire(fragm_sz + INT_H_SIZE);
1453 if (!buf)
1454 goto error;
1455
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001456 buf->next = NULL;
Per Lidenb97bf3f2006-01-02 19:04:38 +01001457 prev->next = buf;
Arnaldo Carvalho de Melo27d7ff42007-03-31 11:55:19 -03001458 skb_copy_to_linear_data(buf, &fragm_hdr, INT_H_SIZE);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001459 fragm_crs = INT_H_SIZE;
1460 fragm_rest = fragm_sz;
1461 msg_dbg(buf_msg(buf)," >BUILD>");
1462 }
1463 }
1464 while (rest > 0);
1465
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001466 /*
Per Lidenb97bf3f2006-01-02 19:04:38 +01001467 * Now we have a buffer chain. Select a link and check
1468 * that packet size is still OK
1469 */
Per Liden4323add2006-01-18 00:38:21 +01001470 node = tipc_node_select(destaddr, sender->publ.ref & 1);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001471 if (likely(node)) {
Per Liden4323add2006-01-18 00:38:21 +01001472 tipc_node_lock(node);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001473 l_ptr = node->active_links[sender->publ.ref & 1];
1474 if (!l_ptr) {
Per Liden4323add2006-01-18 00:38:21 +01001475 tipc_node_unlock(node);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001476 goto reject;
1477 }
Allan Stephens15e979d2010-05-11 14:30:10 +00001478 if (l_ptr->max_pkt < max_pkt) {
1479 sender->publ.max_pkt = l_ptr->max_pkt;
Per Liden4323add2006-01-18 00:38:21 +01001480 tipc_node_unlock(node);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001481 for (; buf_chain; buf_chain = buf) {
1482 buf = buf_chain->next;
1483 buf_discard(buf_chain);
1484 }
1485 goto again;
1486 }
1487 } else {
1488reject:
1489 for (; buf_chain; buf_chain = buf) {
1490 buf = buf_chain->next;
1491 buf_discard(buf_chain);
1492 }
Per Liden4323add2006-01-18 00:38:21 +01001493 return tipc_port_reject_sections(sender, hdr, msg_sect, num_sect,
1494 TIPC_ERR_NO_NODE);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001495 }
1496
1497 /* Append whole chain to send queue: */
1498
1499 buf = buf_chain;
1500 l_ptr->long_msg_seq_no = mod(l_ptr->long_msg_seq_no + 1);
1501 if (!l_ptr->next_out)
1502 l_ptr->next_out = buf_chain;
1503 l_ptr->stats.sent_fragmented++;
1504 while (buf) {
1505 struct sk_buff *next = buf->next;
1506 struct tipc_msg *msg = buf_msg(buf);
1507
1508 l_ptr->stats.sent_fragments++;
1509 msg_set_long_msgno(msg, l_ptr->long_msg_seq_no);
1510 link_add_to_outqueue(l_ptr, buf, msg);
1511 msg_dbg(msg, ">ADD>");
1512 buf = next;
1513 }
1514
1515 /* Send it, if possible: */
1516
Per Liden4323add2006-01-18 00:38:21 +01001517 tipc_link_push_queue(l_ptr);
1518 tipc_node_unlock(node);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001519 return dsz;
1520}
1521
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001522/*
Per Liden4323add2006-01-18 00:38:21 +01001523 * tipc_link_push_packet: Push one unsent packet to the media
Per Lidenb97bf3f2006-01-02 19:04:38 +01001524 */
Per Liden4323add2006-01-18 00:38:21 +01001525u32 tipc_link_push_packet(struct link *l_ptr)
Per Lidenb97bf3f2006-01-02 19:04:38 +01001526{
1527 struct sk_buff *buf = l_ptr->first_out;
1528 u32 r_q_size = l_ptr->retransm_queue_size;
1529 u32 r_q_head = l_ptr->retransm_queue_head;
1530
1531 /* Step to position where retransmission failed, if any, */
1532 /* consider that buffers may have been released in meantime */
1533
1534 if (r_q_size && buf) {
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001535 u32 last = lesser(mod(r_q_head + r_q_size),
Per Lidenb97bf3f2006-01-02 19:04:38 +01001536 link_last_sent(l_ptr));
1537 u32 first = msg_seqno(buf_msg(buf));
1538
1539 while (buf && less(first, r_q_head)) {
1540 first = mod(first + 1);
1541 buf = buf->next;
1542 }
1543 l_ptr->retransm_queue_head = r_q_head = first;
1544 l_ptr->retransm_queue_size = r_q_size = mod(last - first);
1545 }
1546
1547 /* Continue retransmission now, if there is anything: */
1548
Neil Hormanca509102010-03-15 07:58:45 +00001549 if (r_q_size && buf) {
Per Lidenb97bf3f2006-01-02 19:04:38 +01001550 msg_set_ack(buf_msg(buf), mod(l_ptr->next_in_no - 1));
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001551 msg_set_bcast_ack(buf_msg(buf), l_ptr->owner->bclink.last_in);
Per Liden4323add2006-01-18 00:38:21 +01001552 if (tipc_bearer_send(l_ptr->b_ptr, buf, &l_ptr->media_addr)) {
Per Lidenb97bf3f2006-01-02 19:04:38 +01001553 msg_dbg(buf_msg(buf), ">DEF-RETR>");
1554 l_ptr->retransm_queue_head = mod(++r_q_head);
1555 l_ptr->retransm_queue_size = --r_q_size;
1556 l_ptr->stats.retransmitted++;
Allan Stephens0e35fd52008-07-14 22:44:01 -07001557 return 0;
Per Lidenb97bf3f2006-01-02 19:04:38 +01001558 } else {
1559 l_ptr->stats.bearer_congs++;
1560 msg_dbg(buf_msg(buf), "|>DEF-RETR>");
1561 return PUSH_FAILED;
1562 }
1563 }
1564
1565 /* Send deferred protocol message, if any: */
1566
1567 buf = l_ptr->proto_msg_queue;
1568 if (buf) {
1569 msg_set_ack(buf_msg(buf), mod(l_ptr->next_in_no - 1));
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001570 msg_set_bcast_ack(buf_msg(buf),l_ptr->owner->bclink.last_in);
Per Liden4323add2006-01-18 00:38:21 +01001571 if (tipc_bearer_send(l_ptr->b_ptr, buf, &l_ptr->media_addr)) {
Per Lidenb97bf3f2006-01-02 19:04:38 +01001572 msg_dbg(buf_msg(buf), ">DEF-PROT>");
1573 l_ptr->unacked_window = 0;
1574 buf_discard(buf);
Sam Ravnborg1fc54d82006-03-20 22:36:47 -08001575 l_ptr->proto_msg_queue = NULL;
Allan Stephens0e35fd52008-07-14 22:44:01 -07001576 return 0;
Per Lidenb97bf3f2006-01-02 19:04:38 +01001577 } else {
1578 msg_dbg(buf_msg(buf), "|>DEF-PROT>");
1579 l_ptr->stats.bearer_congs++;
1580 return PUSH_FAILED;
1581 }
1582 }
1583
1584 /* Send one deferred data message, if send window not full: */
1585
1586 buf = l_ptr->next_out;
1587 if (buf) {
1588 struct tipc_msg *msg = buf_msg(buf);
1589 u32 next = msg_seqno(msg);
1590 u32 first = msg_seqno(buf_msg(l_ptr->first_out));
1591
1592 if (mod(next - first) < l_ptr->queue_limit[0]) {
1593 msg_set_ack(msg, mod(l_ptr->next_in_no - 1));
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001594 msg_set_bcast_ack(msg, l_ptr->owner->bclink.last_in);
Per Liden4323add2006-01-18 00:38:21 +01001595 if (tipc_bearer_send(l_ptr->b_ptr, buf, &l_ptr->media_addr)) {
Per Lidenb97bf3f2006-01-02 19:04:38 +01001596 if (msg_user(msg) == MSG_BUNDLER)
1597 msg_set_type(msg, CLOSED_MSG);
1598 msg_dbg(msg, ">PUSH-DATA>");
1599 l_ptr->next_out = buf->next;
Allan Stephens0e35fd52008-07-14 22:44:01 -07001600 return 0;
Per Lidenb97bf3f2006-01-02 19:04:38 +01001601 } else {
1602 msg_dbg(msg, "|PUSH-DATA|");
1603 l_ptr->stats.bearer_congs++;
1604 return PUSH_FAILED;
1605 }
1606 }
1607 }
1608 return PUSH_FINISHED;
1609}
1610
1611/*
1612 * push_queue(): push out the unsent messages of a link where
1613 * congestion has abated. Node is locked
1614 */
Per Liden4323add2006-01-18 00:38:21 +01001615void tipc_link_push_queue(struct link *l_ptr)
Per Lidenb97bf3f2006-01-02 19:04:38 +01001616{
1617 u32 res;
1618
Per Liden4323add2006-01-18 00:38:21 +01001619 if (tipc_bearer_congested(l_ptr->b_ptr, l_ptr))
Per Lidenb97bf3f2006-01-02 19:04:38 +01001620 return;
1621
1622 do {
Per Liden4323add2006-01-18 00:38:21 +01001623 res = tipc_link_push_packet(l_ptr);
Allan Stephens0e35fd52008-07-14 22:44:01 -07001624 } while (!res);
1625
Per Lidenb97bf3f2006-01-02 19:04:38 +01001626 if (res == PUSH_FAILED)
Per Liden4323add2006-01-18 00:38:21 +01001627 tipc_bearer_schedule(l_ptr->b_ptr, l_ptr);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001628}
1629
Allan Stephensd356eeb2006-06-25 23:40:01 -07001630static void link_reset_all(unsigned long addr)
1631{
David S. Miller6c000552008-09-02 23:38:32 -07001632 struct tipc_node *n_ptr;
Allan Stephensd356eeb2006-06-25 23:40:01 -07001633 char addr_string[16];
1634 u32 i;
1635
1636 read_lock_bh(&tipc_net_lock);
1637 n_ptr = tipc_node_find((u32)addr);
1638 if (!n_ptr) {
1639 read_unlock_bh(&tipc_net_lock);
1640 return; /* node no longer exists */
1641 }
1642
1643 tipc_node_lock(n_ptr);
1644
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001645 warn("Resetting all links to %s\n",
Allan Stephensd356eeb2006-06-25 23:40:01 -07001646 addr_string_fill(addr_string, n_ptr->addr));
1647
1648 for (i = 0; i < MAX_BEARERS; i++) {
1649 if (n_ptr->links[i]) {
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001650 link_print(n_ptr->links[i], TIPC_OUTPUT,
Allan Stephensd356eeb2006-06-25 23:40:01 -07001651 "Resetting link\n");
1652 tipc_link_reset(n_ptr->links[i]);
1653 }
1654 }
1655
1656 tipc_node_unlock(n_ptr);
1657 read_unlock_bh(&tipc_net_lock);
1658}
1659
1660static void link_retransmit_failure(struct link *l_ptr, struct sk_buff *buf)
1661{
1662 struct tipc_msg *msg = buf_msg(buf);
1663
1664 warn("Retransmission failure on link <%s>\n", l_ptr->name);
Allan Stephens48c97132008-05-05 01:24:06 -07001665 tipc_msg_dbg(TIPC_OUTPUT, msg, ">RETR-FAIL>");
Allan Stephensd356eeb2006-06-25 23:40:01 -07001666
1667 if (l_ptr->addr) {
1668
1669 /* Handle failure on standard link */
1670
1671 link_print(l_ptr, TIPC_OUTPUT, "Resetting link\n");
1672 tipc_link_reset(l_ptr);
1673
1674 } else {
1675
1676 /* Handle failure on broadcast link */
1677
David S. Miller6c000552008-09-02 23:38:32 -07001678 struct tipc_node *n_ptr;
Allan Stephensd356eeb2006-06-25 23:40:01 -07001679 char addr_string[16];
1680
1681 tipc_printf(TIPC_OUTPUT, "Msg seq number: %u, ", msg_seqno(msg));
Jeff Garzik617dbea2006-10-03 16:25:34 -07001682 tipc_printf(TIPC_OUTPUT, "Outstanding acks: %lu\n",
1683 (unsigned long) TIPC_SKB_CB(buf)->handle);
1684
Allan Stephensd356eeb2006-06-25 23:40:01 -07001685 n_ptr = l_ptr->owner->next;
1686 tipc_node_lock(n_ptr);
1687
1688 addr_string_fill(addr_string, n_ptr->addr);
1689 tipc_printf(TIPC_OUTPUT, "Multicast link info for %s\n", addr_string);
1690 tipc_printf(TIPC_OUTPUT, "Supported: %d, ", n_ptr->bclink.supported);
1691 tipc_printf(TIPC_OUTPUT, "Acked: %u\n", n_ptr->bclink.acked);
1692 tipc_printf(TIPC_OUTPUT, "Last in: %u, ", n_ptr->bclink.last_in);
1693 tipc_printf(TIPC_OUTPUT, "Gap after: %u, ", n_ptr->bclink.gap_after);
1694 tipc_printf(TIPC_OUTPUT, "Gap to: %u\n", n_ptr->bclink.gap_to);
1695 tipc_printf(TIPC_OUTPUT, "Nack sync: %u\n\n", n_ptr->bclink.nack_sync);
1696
1697 tipc_k_signal((Handler)link_reset_all, (unsigned long)n_ptr->addr);
1698
1699 tipc_node_unlock(n_ptr);
1700
1701 l_ptr->stale_count = 0;
1702 }
1703}
1704
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001705void tipc_link_retransmit(struct link *l_ptr, struct sk_buff *buf,
Per Liden4323add2006-01-18 00:38:21 +01001706 u32 retransmits)
Per Lidenb97bf3f2006-01-02 19:04:38 +01001707{
1708 struct tipc_msg *msg;
1709
Allan Stephensd356eeb2006-06-25 23:40:01 -07001710 if (!buf)
1711 return;
1712
1713 msg = buf_msg(buf);
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001714
Per Lidenb97bf3f2006-01-02 19:04:38 +01001715 dbg("Retransmitting %u in link %x\n", retransmits, l_ptr);
1716
Allan Stephensd356eeb2006-06-25 23:40:01 -07001717 if (tipc_bearer_congested(l_ptr->b_ptr, l_ptr)) {
Neil Hormanca509102010-03-15 07:58:45 +00001718 if (l_ptr->retransm_queue_size == 0) {
Allan Stephensd356eeb2006-06-25 23:40:01 -07001719 msg_dbg(msg, ">NO_RETR->BCONG>");
1720 dbg_print_link(l_ptr, " ");
1721 l_ptr->retransm_queue_head = msg_seqno(msg);
1722 l_ptr->retransm_queue_size = retransmits;
Allan Stephensd356eeb2006-06-25 23:40:01 -07001723 } else {
Neil Hormanca509102010-03-15 07:58:45 +00001724 err("Unexpected retransmit on link %s (qsize=%d)\n",
1725 l_ptr->name, l_ptr->retransm_queue_size);
Allan Stephensd356eeb2006-06-25 23:40:01 -07001726 }
Neil Hormanca509102010-03-15 07:58:45 +00001727 return;
Allan Stephensd356eeb2006-06-25 23:40:01 -07001728 } else {
1729 /* Detect repeated retransmit failures on uncongested bearer */
1730
1731 if (l_ptr->last_retransmitted == msg_seqno(msg)) {
1732 if (++l_ptr->stale_count > 100) {
1733 link_retransmit_failure(l_ptr, buf);
1734 return;
1735 }
1736 } else {
1737 l_ptr->last_retransmitted = msg_seqno(msg);
1738 l_ptr->stale_count = 1;
1739 }
Per Lidenb97bf3f2006-01-02 19:04:38 +01001740 }
Allan Stephensd356eeb2006-06-25 23:40:01 -07001741
Neil Hormanca509102010-03-15 07:58:45 +00001742 while (retransmits && (buf != l_ptr->next_out) && buf) {
Per Lidenb97bf3f2006-01-02 19:04:38 +01001743 msg = buf_msg(buf);
1744 msg_set_ack(msg, mod(l_ptr->next_in_no - 1));
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001745 msg_set_bcast_ack(msg, l_ptr->owner->bclink.last_in);
Per Liden4323add2006-01-18 00:38:21 +01001746 if (tipc_bearer_send(l_ptr->b_ptr, buf, &l_ptr->media_addr)) {
Per Lidenb97bf3f2006-01-02 19:04:38 +01001747 msg_dbg(buf_msg(buf), ">RETR>");
1748 buf = buf->next;
1749 retransmits--;
1750 l_ptr->stats.retransmitted++;
1751 } else {
Per Liden4323add2006-01-18 00:38:21 +01001752 tipc_bearer_schedule(l_ptr->b_ptr, l_ptr);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001753 l_ptr->stats.bearer_congs++;
1754 l_ptr->retransm_queue_head = msg_seqno(buf_msg(buf));
1755 l_ptr->retransm_queue_size = retransmits;
1756 return;
1757 }
1758 }
Allan Stephensd356eeb2006-06-25 23:40:01 -07001759
Per Lidenb97bf3f2006-01-02 19:04:38 +01001760 l_ptr->retransm_queue_head = l_ptr->retransm_queue_size = 0;
1761}
1762
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001763/**
Per Lidenb97bf3f2006-01-02 19:04:38 +01001764 * link_insert_deferred_queue - insert deferred messages back into receive chain
1765 */
1766
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001767static struct sk_buff *link_insert_deferred_queue(struct link *l_ptr,
Per Lidenb97bf3f2006-01-02 19:04:38 +01001768 struct sk_buff *buf)
1769{
1770 u32 seq_no;
1771
1772 if (l_ptr->oldest_deferred_in == NULL)
1773 return buf;
1774
1775 seq_no = msg_seqno(buf_msg(l_ptr->oldest_deferred_in));
1776 if (seq_no == mod(l_ptr->next_in_no)) {
1777 l_ptr->newest_deferred_in->next = buf;
1778 buf = l_ptr->oldest_deferred_in;
1779 l_ptr->oldest_deferred_in = NULL;
1780 l_ptr->deferred_inqueue_sz = 0;
1781 }
1782 return buf;
1783}
1784
Allan Stephens85035562008-04-15 19:04:54 -07001785/**
1786 * link_recv_buf_validate - validate basic format of received message
1787 *
1788 * This routine ensures a TIPC message has an acceptable header, and at least
1789 * as much data as the header indicates it should. The routine also ensures
1790 * that the entire message header is stored in the main fragment of the message
1791 * buffer, to simplify future access to message header fields.
1792 *
1793 * Note: Having extra info present in the message header or data areas is OK.
1794 * TIPC will ignore the excess, under the assumption that it is optional info
1795 * introduced by a later release of the protocol.
1796 */
1797
1798static int link_recv_buf_validate(struct sk_buff *buf)
1799{
1800 static u32 min_data_hdr_size[8] = {
1801 SHORT_H_SIZE, MCAST_H_SIZE, LONG_H_SIZE, DIR_MSG_H_SIZE,
1802 MAX_H_SIZE, MAX_H_SIZE, MAX_H_SIZE, MAX_H_SIZE
1803 };
1804
1805 struct tipc_msg *msg;
1806 u32 tipc_hdr[2];
1807 u32 size;
1808 u32 hdr_size;
1809 u32 min_hdr_size;
1810
1811 if (unlikely(buf->len < MIN_H_SIZE))
1812 return 0;
1813
1814 msg = skb_header_pointer(buf, 0, sizeof(tipc_hdr), tipc_hdr);
1815 if (msg == NULL)
1816 return 0;
1817
1818 if (unlikely(msg_version(msg) != TIPC_VERSION))
1819 return 0;
1820
1821 size = msg_size(msg);
1822 hdr_size = msg_hdr_sz(msg);
1823 min_hdr_size = msg_isdata(msg) ?
1824 min_data_hdr_size[msg_type(msg)] : INT_H_SIZE;
1825
1826 if (unlikely((hdr_size < min_hdr_size) ||
1827 (size < hdr_size) ||
1828 (buf->len < size) ||
1829 (size - hdr_size > TIPC_MAX_USER_MSG_SIZE)))
1830 return 0;
1831
1832 return pskb_may_pull(buf, hdr_size);
1833}
1834
Per Lidenb97bf3f2006-01-02 19:04:38 +01001835void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *tb_ptr)
1836{
Per Liden4323add2006-01-18 00:38:21 +01001837 read_lock_bh(&tipc_net_lock);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001838 while (head) {
Allan Stephens1265a022008-06-04 17:32:35 -07001839 struct bearer *b_ptr = (struct bearer *)tb_ptr;
David S. Miller6c000552008-09-02 23:38:32 -07001840 struct tipc_node *n_ptr;
Per Lidenb97bf3f2006-01-02 19:04:38 +01001841 struct link *l_ptr;
1842 struct sk_buff *crs;
1843 struct sk_buff *buf = head;
Allan Stephens85035562008-04-15 19:04:54 -07001844 struct tipc_msg *msg;
1845 u32 seq_no;
1846 u32 ackd;
Per Lidenb97bf3f2006-01-02 19:04:38 +01001847 u32 released = 0;
1848 int type;
1849
Per Lidenb97bf3f2006-01-02 19:04:38 +01001850 head = head->next;
Allan Stephens85035562008-04-15 19:04:54 -07001851
1852 /* Ensure message is well-formed */
1853
1854 if (unlikely(!link_recv_buf_validate(buf)))
Per Lidenb97bf3f2006-01-02 19:04:38 +01001855 goto cont;
Per Lidenb97bf3f2006-01-02 19:04:38 +01001856
Allan Stephensfe13dda2008-04-15 19:03:23 -07001857 /* Ensure message data is a single contiguous unit */
1858
1859 if (unlikely(buf_linearize(buf))) {
1860 goto cont;
1861 }
1862
Allan Stephens85035562008-04-15 19:04:54 -07001863 /* Handle arrival of a non-unicast link message */
1864
1865 msg = buf_msg(buf);
1866
Per Lidenb97bf3f2006-01-02 19:04:38 +01001867 if (unlikely(msg_non_seq(msg))) {
Allan Stephens1265a022008-06-04 17:32:35 -07001868 if (msg_user(msg) == LINK_CONFIG)
1869 tipc_disc_recv_msg(buf, b_ptr);
1870 else
1871 tipc_bclink_recv_pkt(buf);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001872 continue;
1873 }
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001874
Allan Stephens26008242006-06-25 23:39:31 -07001875 if (unlikely(!msg_short(msg) &&
1876 (msg_destnode(msg) != tipc_own_addr)))
1877 goto cont;
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001878
Neil Hormande586572010-03-08 12:43:56 -08001879 /* Discard non-routeable messages destined for another node */
1880
1881 if (unlikely(!msg_isdata(msg) &&
1882 (msg_destnode(msg) != tipc_own_addr))) {
1883 if ((msg_user(msg) != CONN_MANAGER) &&
1884 (msg_user(msg) != MSG_FRAGMENTER))
1885 goto cont;
1886 }
1887
Allan Stephens85035562008-04-15 19:04:54 -07001888 /* Locate unicast link endpoint that should handle message */
1889
Per Liden4323add2006-01-18 00:38:21 +01001890 n_ptr = tipc_node_find(msg_prevnode(msg));
Per Lidenb97bf3f2006-01-02 19:04:38 +01001891 if (unlikely(!n_ptr))
1892 goto cont;
Per Liden4323add2006-01-18 00:38:21 +01001893 tipc_node_lock(n_ptr);
Allan Stephens85035562008-04-15 19:04:54 -07001894
Per Lidenb97bf3f2006-01-02 19:04:38 +01001895 l_ptr = n_ptr->links[b_ptr->identity];
1896 if (unlikely(!l_ptr)) {
Per Liden4323add2006-01-18 00:38:21 +01001897 tipc_node_unlock(n_ptr);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001898 goto cont;
1899 }
Allan Stephens85035562008-04-15 19:04:54 -07001900
1901 /* Validate message sequence number info */
1902
1903 seq_no = msg_seqno(msg);
1904 ackd = msg_ack(msg);
1905
1906 /* Release acked messages */
1907
Per Lidenb97bf3f2006-01-02 19:04:38 +01001908 if (less(n_ptr->bclink.acked, msg_bcast_ack(msg))) {
Per Liden4323add2006-01-18 00:38:21 +01001909 if (tipc_node_is_up(n_ptr) && n_ptr->bclink.supported)
1910 tipc_bclink_acknowledge(n_ptr, msg_bcast_ack(msg));
Per Lidenb97bf3f2006-01-02 19:04:38 +01001911 }
1912
1913 crs = l_ptr->first_out;
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001914 while ((crs != l_ptr->next_out) &&
Per Lidenb97bf3f2006-01-02 19:04:38 +01001915 less_eq(msg_seqno(buf_msg(crs)), ackd)) {
1916 struct sk_buff *next = crs->next;
1917
1918 buf_discard(crs);
1919 crs = next;
1920 released++;
1921 }
1922 if (released) {
1923 l_ptr->first_out = crs;
1924 l_ptr->out_queue_size -= released;
1925 }
Allan Stephens85035562008-04-15 19:04:54 -07001926
1927 /* Try sending any messages link endpoint has pending */
1928
Per Lidenb97bf3f2006-01-02 19:04:38 +01001929 if (unlikely(l_ptr->next_out))
Per Liden4323add2006-01-18 00:38:21 +01001930 tipc_link_push_queue(l_ptr);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001931 if (unlikely(!list_empty(&l_ptr->waiting_ports)))
Per Liden4323add2006-01-18 00:38:21 +01001932 tipc_link_wakeup_ports(l_ptr, 0);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001933 if (unlikely(++l_ptr->unacked_window >= TIPC_MIN_LINK_WIN)) {
1934 l_ptr->stats.sent_acks++;
Per Liden4323add2006-01-18 00:38:21 +01001935 tipc_link_send_proto_msg(l_ptr, STATE_MSG, 0, 0, 0, 0, 0);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001936 }
1937
Allan Stephens85035562008-04-15 19:04:54 -07001938 /* Now (finally!) process the incoming message */
1939
Per Lidenb97bf3f2006-01-02 19:04:38 +01001940protocol_check:
1941 if (likely(link_working_working(l_ptr))) {
1942 if (likely(seq_no == mod(l_ptr->next_in_no))) {
1943 l_ptr->next_in_no++;
1944 if (unlikely(l_ptr->oldest_deferred_in))
1945 head = link_insert_deferred_queue(l_ptr,
1946 head);
1947 if (likely(msg_is_dest(msg, tipc_own_addr))) {
1948deliver:
1949 if (likely(msg_isdata(msg))) {
Per Liden4323add2006-01-18 00:38:21 +01001950 tipc_node_unlock(n_ptr);
1951 tipc_port_recv_msg(buf);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001952 continue;
1953 }
1954 switch (msg_user(msg)) {
1955 case MSG_BUNDLER:
1956 l_ptr->stats.recv_bundles++;
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001957 l_ptr->stats.recv_bundled +=
Per Lidenb97bf3f2006-01-02 19:04:38 +01001958 msg_msgcnt(msg);
Per Liden4323add2006-01-18 00:38:21 +01001959 tipc_node_unlock(n_ptr);
1960 tipc_link_recv_bundle(buf);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001961 continue;
1962 case ROUTE_DISTRIBUTOR:
Per Liden4323add2006-01-18 00:38:21 +01001963 tipc_node_unlock(n_ptr);
1964 tipc_cltr_recv_routing_table(buf);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001965 continue;
1966 case NAME_DISTRIBUTOR:
Per Liden4323add2006-01-18 00:38:21 +01001967 tipc_node_unlock(n_ptr);
1968 tipc_named_recv(buf);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001969 continue;
1970 case CONN_MANAGER:
Per Liden4323add2006-01-18 00:38:21 +01001971 tipc_node_unlock(n_ptr);
1972 tipc_port_recv_proto_msg(buf);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001973 continue;
1974 case MSG_FRAGMENTER:
1975 l_ptr->stats.recv_fragments++;
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001976 if (tipc_link_recv_fragment(&l_ptr->defragm_buf,
Per Liden4323add2006-01-18 00:38:21 +01001977 &buf, &msg)) {
Per Lidenb97bf3f2006-01-02 19:04:38 +01001978 l_ptr->stats.recv_fragmented++;
1979 goto deliver;
1980 }
1981 break;
1982 case CHANGEOVER_PROTOCOL:
1983 type = msg_type(msg);
Per Liden4323add2006-01-18 00:38:21 +01001984 if (link_recv_changeover_msg(&l_ptr, &buf)) {
Per Lidenb97bf3f2006-01-02 19:04:38 +01001985 msg = buf_msg(buf);
1986 seq_no = msg_seqno(msg);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001987 if (type == ORIGINAL_MSG)
1988 goto deliver;
1989 goto protocol_check;
1990 }
1991 break;
1992 }
1993 }
Per Liden4323add2006-01-18 00:38:21 +01001994 tipc_node_unlock(n_ptr);
1995 tipc_net_route_msg(buf);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001996 continue;
1997 }
1998 link_handle_out_of_seq_msg(l_ptr, buf);
1999 head = link_insert_deferred_queue(l_ptr, head);
Per Liden4323add2006-01-18 00:38:21 +01002000 tipc_node_unlock(n_ptr);
Per Lidenb97bf3f2006-01-02 19:04:38 +01002001 continue;
2002 }
2003
2004 if (msg_user(msg) == LINK_PROTOCOL) {
2005 link_recv_proto_msg(l_ptr, buf);
2006 head = link_insert_deferred_queue(l_ptr, head);
Per Liden4323add2006-01-18 00:38:21 +01002007 tipc_node_unlock(n_ptr);
Per Lidenb97bf3f2006-01-02 19:04:38 +01002008 continue;
2009 }
2010 msg_dbg(msg,"NSEQ<REC<");
2011 link_state_event(l_ptr, TRAFFIC_MSG_EVT);
2012
2013 if (link_working_working(l_ptr)) {
2014 /* Re-insert in front of queue */
2015 msg_dbg(msg,"RECV-REINS:");
2016 buf->next = head;
2017 head = buf;
Per Liden4323add2006-01-18 00:38:21 +01002018 tipc_node_unlock(n_ptr);
Per Lidenb97bf3f2006-01-02 19:04:38 +01002019 continue;
2020 }
Per Liden4323add2006-01-18 00:38:21 +01002021 tipc_node_unlock(n_ptr);
Per Lidenb97bf3f2006-01-02 19:04:38 +01002022cont:
2023 buf_discard(buf);
2024 }
Per Liden4323add2006-01-18 00:38:21 +01002025 read_unlock_bh(&tipc_net_lock);
Per Lidenb97bf3f2006-01-02 19:04:38 +01002026}
2027
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002028/*
2029 * link_defer_buf(): Sort a received out-of-sequence packet
Per Lidenb97bf3f2006-01-02 19:04:38 +01002030 * into the deferred reception queue.
2031 * Returns the increase of the queue length,i.e. 0 or 1
2032 */
2033
Per Liden4323add2006-01-18 00:38:21 +01002034u32 tipc_link_defer_pkt(struct sk_buff **head,
2035 struct sk_buff **tail,
2036 struct sk_buff *buf)
Per Lidenb97bf3f2006-01-02 19:04:38 +01002037{
Sam Ravnborg1fc54d82006-03-20 22:36:47 -08002038 struct sk_buff *prev = NULL;
Per Lidenb97bf3f2006-01-02 19:04:38 +01002039 struct sk_buff *crs = *head;
2040 u32 seq_no = msg_seqno(buf_msg(buf));
2041
2042 buf->next = NULL;
2043
2044 /* Empty queue ? */
2045 if (*head == NULL) {
2046 *head = *tail = buf;
2047 return 1;
2048 }
2049
2050 /* Last ? */
2051 if (less(msg_seqno(buf_msg(*tail)), seq_no)) {
2052 (*tail)->next = buf;
2053 *tail = buf;
2054 return 1;
2055 }
2056
2057 /* Scan through queue and sort it in */
2058 do {
2059 struct tipc_msg *msg = buf_msg(crs);
2060
2061 if (less(seq_no, msg_seqno(msg))) {
2062 buf->next = crs;
2063 if (prev)
2064 prev->next = buf;
2065 else
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002066 *head = buf;
Per Lidenb97bf3f2006-01-02 19:04:38 +01002067 return 1;
2068 }
2069 if (seq_no == msg_seqno(msg)) {
2070 break;
2071 }
2072 prev = crs;
2073 crs = crs->next;
2074 }
2075 while (crs);
2076
2077 /* Message is a duplicate of an existing message */
2078
2079 buf_discard(buf);
2080 return 0;
2081}
2082
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002083/**
Per Lidenb97bf3f2006-01-02 19:04:38 +01002084 * link_handle_out_of_seq_msg - handle arrival of out-of-sequence packet
2085 */
2086
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002087static void link_handle_out_of_seq_msg(struct link *l_ptr,
Per Lidenb97bf3f2006-01-02 19:04:38 +01002088 struct sk_buff *buf)
2089{
2090 u32 seq_no = msg_seqno(buf_msg(buf));
2091
2092 if (likely(msg_user(buf_msg(buf)) == LINK_PROTOCOL)) {
2093 link_recv_proto_msg(l_ptr, buf);
2094 return;
2095 }
2096
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002097 dbg("rx OOS msg: seq_no %u, expecting %u (%u)\n",
Per Lidenb97bf3f2006-01-02 19:04:38 +01002098 seq_no, mod(l_ptr->next_in_no), l_ptr->next_in_no);
2099
2100 /* Record OOS packet arrival (force mismatch on next timeout) */
2101
2102 l_ptr->checkpoint--;
2103
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002104 /*
Per Lidenb97bf3f2006-01-02 19:04:38 +01002105 * Discard packet if a duplicate; otherwise add it to deferred queue
2106 * and notify peer of gap as per protocol specification
2107 */
2108
2109 if (less(seq_no, mod(l_ptr->next_in_no))) {
2110 l_ptr->stats.duplicates++;
2111 buf_discard(buf);
2112 return;
2113 }
2114
Per Liden4323add2006-01-18 00:38:21 +01002115 if (tipc_link_defer_pkt(&l_ptr->oldest_deferred_in,
2116 &l_ptr->newest_deferred_in, buf)) {
Per Lidenb97bf3f2006-01-02 19:04:38 +01002117 l_ptr->deferred_inqueue_sz++;
2118 l_ptr->stats.deferred_recv++;
2119 if ((l_ptr->deferred_inqueue_sz % 16) == 1)
Per Liden4323add2006-01-18 00:38:21 +01002120 tipc_link_send_proto_msg(l_ptr, STATE_MSG, 0, 0, 0, 0, 0);
Per Lidenb97bf3f2006-01-02 19:04:38 +01002121 } else
2122 l_ptr->stats.duplicates++;
2123}
2124
2125/*
2126 * Send protocol message to the other endpoint.
2127 */
Per Liden4323add2006-01-18 00:38:21 +01002128void tipc_link_send_proto_msg(struct link *l_ptr, u32 msg_typ, int probe_msg,
2129 u32 gap, u32 tolerance, u32 priority, u32 ack_mtu)
Per Lidenb97bf3f2006-01-02 19:04:38 +01002130{
Sam Ravnborg1fc54d82006-03-20 22:36:47 -08002131 struct sk_buff *buf = NULL;
Per Lidenb97bf3f2006-01-02 19:04:38 +01002132 struct tipc_msg *msg = l_ptr->pmsg;
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002133 u32 msg_size = sizeof(l_ptr->proto_msg);
Per Lidenb97bf3f2006-01-02 19:04:38 +01002134
2135 if (link_blocked(l_ptr))
2136 return;
2137 msg_set_type(msg, msg_typ);
2138 msg_set_net_plane(msg, l_ptr->b_ptr->net_plane);
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002139 msg_set_bcast_ack(msg, mod(l_ptr->owner->bclink.last_in));
Per Liden4323add2006-01-18 00:38:21 +01002140 msg_set_last_bcast(msg, tipc_bclink_get_last_sent());
Per Lidenb97bf3f2006-01-02 19:04:38 +01002141
2142 if (msg_typ == STATE_MSG) {
2143 u32 next_sent = mod(l_ptr->next_out_no);
2144
Per Liden4323add2006-01-18 00:38:21 +01002145 if (!tipc_link_is_up(l_ptr))
Per Lidenb97bf3f2006-01-02 19:04:38 +01002146 return;
2147 if (l_ptr->next_out)
2148 next_sent = msg_seqno(buf_msg(l_ptr->next_out));
2149 msg_set_next_sent(msg, next_sent);
2150 if (l_ptr->oldest_deferred_in) {
2151 u32 rec = msg_seqno(buf_msg(l_ptr->oldest_deferred_in));
2152 gap = mod(rec - mod(l_ptr->next_in_no));
2153 }
2154 msg_set_seq_gap(msg, gap);
2155 if (gap)
2156 l_ptr->stats.sent_nacks++;
2157 msg_set_link_tolerance(msg, tolerance);
2158 msg_set_linkprio(msg, priority);
2159 msg_set_max_pkt(msg, ack_mtu);
2160 msg_set_ack(msg, mod(l_ptr->next_in_no - 1));
2161 msg_set_probe(msg, probe_msg != 0);
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002162 if (probe_msg) {
Per Lidenb97bf3f2006-01-02 19:04:38 +01002163 u32 mtu = l_ptr->max_pkt;
2164
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002165 if ((mtu < l_ptr->max_pkt_target) &&
Per Lidenb97bf3f2006-01-02 19:04:38 +01002166 link_working_working(l_ptr) &&
2167 l_ptr->fsm_msg_cnt) {
2168 msg_size = (mtu + (l_ptr->max_pkt_target - mtu)/2 + 2) & ~3;
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002169 if (l_ptr->max_pkt_probes == 10) {
2170 l_ptr->max_pkt_target = (msg_size - 4);
2171 l_ptr->max_pkt_probes = 0;
Per Lidenb97bf3f2006-01-02 19:04:38 +01002172 msg_size = (mtu + (l_ptr->max_pkt_target - mtu)/2 + 2) & ~3;
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002173 }
Per Lidenb97bf3f2006-01-02 19:04:38 +01002174 l_ptr->max_pkt_probes++;
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002175 }
Per Lidenb97bf3f2006-01-02 19:04:38 +01002176
2177 l_ptr->stats.sent_probes++;
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002178 }
Per Lidenb97bf3f2006-01-02 19:04:38 +01002179 l_ptr->stats.sent_states++;
2180 } else { /* RESET_MSG or ACTIVATE_MSG */
2181 msg_set_ack(msg, mod(l_ptr->reset_checkpoint - 1));
2182 msg_set_seq_gap(msg, 0);
2183 msg_set_next_sent(msg, 1);
2184 msg_set_link_tolerance(msg, l_ptr->tolerance);
2185 msg_set_linkprio(msg, l_ptr->priority);
2186 msg_set_max_pkt(msg, l_ptr->max_pkt_target);
2187 }
2188
Per Liden4323add2006-01-18 00:38:21 +01002189 if (tipc_node_has_redundant_links(l_ptr->owner)) {
Per Lidenb97bf3f2006-01-02 19:04:38 +01002190 msg_set_redundant_link(msg);
2191 } else {
2192 msg_clear_redundant_link(msg);
2193 }
2194 msg_set_linkprio(msg, l_ptr->priority);
2195
2196 /* Ensure sequence number will not fit : */
2197
2198 msg_set_seqno(msg, mod(l_ptr->next_out_no + (0xffff/2)));
2199
2200 /* Congestion? */
2201
Per Liden4323add2006-01-18 00:38:21 +01002202 if (tipc_bearer_congested(l_ptr->b_ptr, l_ptr)) {
Per Lidenb97bf3f2006-01-02 19:04:38 +01002203 if (!l_ptr->proto_msg_queue) {
2204 l_ptr->proto_msg_queue =
2205 buf_acquire(sizeof(l_ptr->proto_msg));
2206 }
2207 buf = l_ptr->proto_msg_queue;
2208 if (!buf)
2209 return;
Arnaldo Carvalho de Melo27d7ff42007-03-31 11:55:19 -03002210 skb_copy_to_linear_data(buf, msg, sizeof(l_ptr->proto_msg));
Per Lidenb97bf3f2006-01-02 19:04:38 +01002211 return;
2212 }
2213 msg_set_timestamp(msg, jiffies_to_msecs(jiffies));
2214
2215 /* Message can be sent */
2216
2217 msg_dbg(msg, ">>");
2218
2219 buf = buf_acquire(msg_size);
2220 if (!buf)
2221 return;
2222
Arnaldo Carvalho de Melo27d7ff42007-03-31 11:55:19 -03002223 skb_copy_to_linear_data(buf, msg, sizeof(l_ptr->proto_msg));
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002224 msg_set_size(buf_msg(buf), msg_size);
Per Lidenb97bf3f2006-01-02 19:04:38 +01002225
Per Liden4323add2006-01-18 00:38:21 +01002226 if (tipc_bearer_send(l_ptr->b_ptr, buf, &l_ptr->media_addr)) {
Per Lidenb97bf3f2006-01-02 19:04:38 +01002227 l_ptr->unacked_window = 0;
2228 buf_discard(buf);
2229 return;
2230 }
2231
2232 /* New congestion */
Per Liden4323add2006-01-18 00:38:21 +01002233 tipc_bearer_schedule(l_ptr->b_ptr, l_ptr);
Per Lidenb97bf3f2006-01-02 19:04:38 +01002234 l_ptr->proto_msg_queue = buf;
2235 l_ptr->stats.bearer_congs++;
2236}
2237
2238/*
2239 * Receive protocol message :
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002240 * Note that network plane id propagates through the network, and may
2241 * change at any time. The node with lowest address rules
Per Lidenb97bf3f2006-01-02 19:04:38 +01002242 */
2243
2244static void link_recv_proto_msg(struct link *l_ptr, struct sk_buff *buf)
2245{
2246 u32 rec_gap = 0;
2247 u32 max_pkt_info;
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002248 u32 max_pkt_ack;
Per Lidenb97bf3f2006-01-02 19:04:38 +01002249 u32 msg_tol;
2250 struct tipc_msg *msg = buf_msg(buf);
2251
2252 dbg("AT(%u):", jiffies_to_msecs(jiffies));
2253 msg_dbg(msg, "<<");
2254 if (link_blocked(l_ptr))
2255 goto exit;
2256
2257 /* record unnumbered packet arrival (force mismatch on next timeout) */
2258
2259 l_ptr->checkpoint--;
2260
2261 if (l_ptr->b_ptr->net_plane != msg_net_plane(msg))
2262 if (tipc_own_addr > msg_prevnode(msg))
2263 l_ptr->b_ptr->net_plane = msg_net_plane(msg);
2264
2265 l_ptr->owner->permit_changeover = msg_redundant_link(msg);
2266
2267 switch (msg_type(msg)) {
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002268
Per Lidenb97bf3f2006-01-02 19:04:38 +01002269 case RESET_MSG:
Allan Stephensa686e682008-06-04 17:29:39 -07002270 if (!link_working_unknown(l_ptr) &&
2271 (l_ptr->peer_session != INVALID_SESSION)) {
Per Lidenb97bf3f2006-01-02 19:04:38 +01002272 if (msg_session(msg) == l_ptr->peer_session) {
2273 dbg("Duplicate RESET: %u<->%u\n",
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002274 msg_session(msg), l_ptr->peer_session);
Per Lidenb97bf3f2006-01-02 19:04:38 +01002275 break; /* duplicate: ignore */
2276 }
2277 }
2278 /* fall thru' */
2279 case ACTIVATE_MSG:
2280 /* Update link settings according other endpoint's values */
2281
2282 strcpy((strrchr(l_ptr->name, ':') + 1), (char *)msg_data(msg));
2283
2284 if ((msg_tol = msg_link_tolerance(msg)) &&
2285 (msg_tol > l_ptr->tolerance))
2286 link_set_supervision_props(l_ptr, msg_tol);
2287
2288 if (msg_linkprio(msg) > l_ptr->priority)
2289 l_ptr->priority = msg_linkprio(msg);
2290
2291 max_pkt_info = msg_max_pkt(msg);
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002292 if (max_pkt_info) {
Per Lidenb97bf3f2006-01-02 19:04:38 +01002293 if (max_pkt_info < l_ptr->max_pkt_target)
2294 l_ptr->max_pkt_target = max_pkt_info;
2295 if (l_ptr->max_pkt > l_ptr->max_pkt_target)
2296 l_ptr->max_pkt = l_ptr->max_pkt_target;
2297 } else {
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002298 l_ptr->max_pkt = l_ptr->max_pkt_target;
Per Lidenb97bf3f2006-01-02 19:04:38 +01002299 }
2300 l_ptr->owner->bclink.supported = (max_pkt_info != 0);
2301
2302 link_state_event(l_ptr, msg_type(msg));
2303
2304 l_ptr->peer_session = msg_session(msg);
2305 l_ptr->peer_bearer_id = msg_bearer_id(msg);
2306
2307 /* Synchronize broadcast sequence numbers */
Per Liden4323add2006-01-18 00:38:21 +01002308 if (!tipc_node_has_redundant_links(l_ptr->owner)) {
Per Lidenb97bf3f2006-01-02 19:04:38 +01002309 l_ptr->owner->bclink.last_in = mod(msg_last_bcast(msg));
2310 }
2311 break;
2312 case STATE_MSG:
2313
2314 if ((msg_tol = msg_link_tolerance(msg)))
2315 link_set_supervision_props(l_ptr, msg_tol);
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002316
2317 if (msg_linkprio(msg) &&
Per Lidenb97bf3f2006-01-02 19:04:38 +01002318 (msg_linkprio(msg) != l_ptr->priority)) {
Allan Stephensa10bd922006-06-25 23:52:17 -07002319 warn("Resetting link <%s>, priority change %u->%u\n",
Per Lidenb97bf3f2006-01-02 19:04:38 +01002320 l_ptr->name, l_ptr->priority, msg_linkprio(msg));
2321 l_ptr->priority = msg_linkprio(msg);
Per Liden4323add2006-01-18 00:38:21 +01002322 tipc_link_reset(l_ptr); /* Enforce change to take effect */
Per Lidenb97bf3f2006-01-02 19:04:38 +01002323 break;
2324 }
2325 link_state_event(l_ptr, TRAFFIC_MSG_EVT);
2326 l_ptr->stats.recv_states++;
2327 if (link_reset_unknown(l_ptr))
2328 break;
2329
2330 if (less_eq(mod(l_ptr->next_in_no), msg_next_sent(msg))) {
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002331 rec_gap = mod(msg_next_sent(msg) -
Per Lidenb97bf3f2006-01-02 19:04:38 +01002332 mod(l_ptr->next_in_no));
2333 }
2334
2335 max_pkt_ack = msg_max_pkt(msg);
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002336 if (max_pkt_ack > l_ptr->max_pkt) {
2337 dbg("Link <%s> updated MTU %u -> %u\n",
2338 l_ptr->name, l_ptr->max_pkt, max_pkt_ack);
2339 l_ptr->max_pkt = max_pkt_ack;
2340 l_ptr->max_pkt_probes = 0;
2341 }
Per Lidenb97bf3f2006-01-02 19:04:38 +01002342
2343 max_pkt_ack = 0;
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002344 if (msg_probe(msg)) {
Per Lidenb97bf3f2006-01-02 19:04:38 +01002345 l_ptr->stats.recv_probes++;
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002346 if (msg_size(msg) > sizeof(l_ptr->proto_msg)) {
2347 max_pkt_ack = msg_size(msg);
2348 }
2349 }
Per Lidenb97bf3f2006-01-02 19:04:38 +01002350
2351 /* Protocol message before retransmits, reduce loss risk */
2352
Per Liden4323add2006-01-18 00:38:21 +01002353 tipc_bclink_check_gap(l_ptr->owner, msg_last_bcast(msg));
Per Lidenb97bf3f2006-01-02 19:04:38 +01002354
2355 if (rec_gap || (msg_probe(msg))) {
Per Liden4323add2006-01-18 00:38:21 +01002356 tipc_link_send_proto_msg(l_ptr, STATE_MSG,
2357 0, rec_gap, 0, 0, max_pkt_ack);
Per Lidenb97bf3f2006-01-02 19:04:38 +01002358 }
2359 if (msg_seq_gap(msg)) {
2360 msg_dbg(msg, "With Gap:");
2361 l_ptr->stats.recv_nacks++;
Per Liden4323add2006-01-18 00:38:21 +01002362 tipc_link_retransmit(l_ptr, l_ptr->first_out,
2363 msg_seq_gap(msg));
Per Lidenb97bf3f2006-01-02 19:04:38 +01002364 }
2365 break;
2366 default:
2367 msg_dbg(buf_msg(buf), "<DISCARDING UNKNOWN<");
2368 }
2369exit:
2370 buf_discard(buf);
2371}
2372
2373
2374/*
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002375 * tipc_link_tunnel(): Send one message via a link belonging to
Per Lidenb97bf3f2006-01-02 19:04:38 +01002376 * another bearer. Owner node is locked.
2377 */
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002378void tipc_link_tunnel(struct link *l_ptr,
2379 struct tipc_msg *tunnel_hdr,
Per Liden4323add2006-01-18 00:38:21 +01002380 struct tipc_msg *msg,
2381 u32 selector)
Per Lidenb97bf3f2006-01-02 19:04:38 +01002382{
2383 struct link *tunnel;
2384 struct sk_buff *buf;
2385 u32 length = msg_size(msg);
2386
2387 tunnel = l_ptr->owner->active_links[selector & 1];
Allan Stephens5392d642006-06-25 23:52:50 -07002388 if (!tipc_link_is_up(tunnel)) {
2389 warn("Link changeover error, "
2390 "tunnel link no longer available\n");
Per Lidenb97bf3f2006-01-02 19:04:38 +01002391 return;
Allan Stephens5392d642006-06-25 23:52:50 -07002392 }
Per Lidenb97bf3f2006-01-02 19:04:38 +01002393 msg_set_size(tunnel_hdr, length + INT_H_SIZE);
2394 buf = buf_acquire(length + INT_H_SIZE);
Allan Stephens5392d642006-06-25 23:52:50 -07002395 if (!buf) {
2396 warn("Link changeover error, "
2397 "unable to send tunnel msg\n");
Per Lidenb97bf3f2006-01-02 19:04:38 +01002398 return;
Allan Stephens5392d642006-06-25 23:52:50 -07002399 }
Arnaldo Carvalho de Melo27d7ff42007-03-31 11:55:19 -03002400 skb_copy_to_linear_data(buf, tunnel_hdr, INT_H_SIZE);
2401 skb_copy_to_linear_data_offset(buf, INT_H_SIZE, msg, length);
Per Lidenb97bf3f2006-01-02 19:04:38 +01002402 dbg("%c->%c:", l_ptr->b_ptr->net_plane, tunnel->b_ptr->net_plane);
2403 msg_dbg(buf_msg(buf), ">SEND>");
Per Liden4323add2006-01-18 00:38:21 +01002404 tipc_link_send_buf(tunnel, buf);
Per Lidenb97bf3f2006-01-02 19:04:38 +01002405}
2406
2407
2408
2409/*
2410 * changeover(): Send whole message queue via the remaining link
2411 * Owner node is locked.
2412 */
2413
Per Liden4323add2006-01-18 00:38:21 +01002414void tipc_link_changeover(struct link *l_ptr)
Per Lidenb97bf3f2006-01-02 19:04:38 +01002415{
2416 u32 msgcount = l_ptr->out_queue_size;
2417 struct sk_buff *crs = l_ptr->first_out;
2418 struct link *tunnel = l_ptr->owner->active_links[0];
Per Lidenb97bf3f2006-01-02 19:04:38 +01002419 struct tipc_msg tunnel_hdr;
Allan Stephens5392d642006-06-25 23:52:50 -07002420 int split_bundles;
Per Lidenb97bf3f2006-01-02 19:04:38 +01002421
2422 if (!tunnel)
2423 return;
2424
Allan Stephens5392d642006-06-25 23:52:50 -07002425 if (!l_ptr->owner->permit_changeover) {
2426 warn("Link changeover error, "
2427 "peer did not permit changeover\n");
Per Lidenb97bf3f2006-01-02 19:04:38 +01002428 return;
Allan Stephens5392d642006-06-25 23:52:50 -07002429 }
Per Lidenb97bf3f2006-01-02 19:04:38 +01002430
2431 msg_init(&tunnel_hdr, CHANGEOVER_PROTOCOL,
Allan Stephens75715212008-06-04 17:37:34 -07002432 ORIGINAL_MSG, INT_H_SIZE, l_ptr->addr);
Per Lidenb97bf3f2006-01-02 19:04:38 +01002433 msg_set_bearer_id(&tunnel_hdr, l_ptr->peer_bearer_id);
2434 msg_set_msgcnt(&tunnel_hdr, msgcount);
Allan Stephens5392d642006-06-25 23:52:50 -07002435 dbg("Link changeover requires %u tunnel messages\n", msgcount);
Allan Stephensf1310722006-06-25 23:51:37 -07002436
Per Lidenb97bf3f2006-01-02 19:04:38 +01002437 if (!l_ptr->first_out) {
2438 struct sk_buff *buf;
2439
Per Lidenb97bf3f2006-01-02 19:04:38 +01002440 buf = buf_acquire(INT_H_SIZE);
2441 if (buf) {
Arnaldo Carvalho de Melo27d7ff42007-03-31 11:55:19 -03002442 skb_copy_to_linear_data(buf, &tunnel_hdr, INT_H_SIZE);
Per Lidenb97bf3f2006-01-02 19:04:38 +01002443 msg_set_size(&tunnel_hdr, INT_H_SIZE);
2444 dbg("%c->%c:", l_ptr->b_ptr->net_plane,
2445 tunnel->b_ptr->net_plane);
2446 msg_dbg(&tunnel_hdr, "EMPTY>SEND>");
Per Liden4323add2006-01-18 00:38:21 +01002447 tipc_link_send_buf(tunnel, buf);
Per Lidenb97bf3f2006-01-02 19:04:38 +01002448 } else {
Allan Stephensa10bd922006-06-25 23:52:17 -07002449 warn("Link changeover error, "
2450 "unable to send changeover msg\n");
Per Lidenb97bf3f2006-01-02 19:04:38 +01002451 }
2452 return;
2453 }
Allan Stephensf1310722006-06-25 23:51:37 -07002454
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002455 split_bundles = (l_ptr->owner->active_links[0] !=
Allan Stephens5392d642006-06-25 23:52:50 -07002456 l_ptr->owner->active_links[1]);
2457
Per Lidenb97bf3f2006-01-02 19:04:38 +01002458 while (crs) {
2459 struct tipc_msg *msg = buf_msg(crs);
2460
2461 if ((msg_user(msg) == MSG_BUNDLER) && split_bundles) {
Per Lidenb97bf3f2006-01-02 19:04:38 +01002462 struct tipc_msg *m = msg_get_wrapped(msg);
2463 unchar* pos = (unchar*)m;
2464
Florian Westphald788d802007-08-02 19:28:06 -07002465 msgcount = msg_msgcnt(msg);
Per Lidenb97bf3f2006-01-02 19:04:38 +01002466 while (msgcount--) {
2467 msg_set_seqno(m,msg_seqno(msg));
Per Liden4323add2006-01-18 00:38:21 +01002468 tipc_link_tunnel(l_ptr, &tunnel_hdr, m,
2469 msg_link_selector(m));
Per Lidenb97bf3f2006-01-02 19:04:38 +01002470 pos += align(msg_size(m));
2471 m = (struct tipc_msg *)pos;
2472 }
2473 } else {
Per Liden4323add2006-01-18 00:38:21 +01002474 tipc_link_tunnel(l_ptr, &tunnel_hdr, msg,
2475 msg_link_selector(msg));
Per Lidenb97bf3f2006-01-02 19:04:38 +01002476 }
2477 crs = crs->next;
2478 }
2479}
2480
Per Liden4323add2006-01-18 00:38:21 +01002481void tipc_link_send_duplicate(struct link *l_ptr, struct link *tunnel)
Per Lidenb97bf3f2006-01-02 19:04:38 +01002482{
2483 struct sk_buff *iter;
2484 struct tipc_msg tunnel_hdr;
2485
2486 msg_init(&tunnel_hdr, CHANGEOVER_PROTOCOL,
Allan Stephens75715212008-06-04 17:37:34 -07002487 DUPLICATE_MSG, INT_H_SIZE, l_ptr->addr);
Per Lidenb97bf3f2006-01-02 19:04:38 +01002488 msg_set_msgcnt(&tunnel_hdr, l_ptr->out_queue_size);
2489 msg_set_bearer_id(&tunnel_hdr, l_ptr->peer_bearer_id);
2490 iter = l_ptr->first_out;
2491 while (iter) {
2492 struct sk_buff *outbuf;
2493 struct tipc_msg *msg = buf_msg(iter);
2494 u32 length = msg_size(msg);
2495
2496 if (msg_user(msg) == MSG_BUNDLER)
2497 msg_set_type(msg, CLOSED_MSG);
2498 msg_set_ack(msg, mod(l_ptr->next_in_no - 1)); /* Update */
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002499 msg_set_bcast_ack(msg, l_ptr->owner->bclink.last_in);
Per Lidenb97bf3f2006-01-02 19:04:38 +01002500 msg_set_size(&tunnel_hdr, length + INT_H_SIZE);
2501 outbuf = buf_acquire(length + INT_H_SIZE);
2502 if (outbuf == NULL) {
Allan Stephensa10bd922006-06-25 23:52:17 -07002503 warn("Link changeover error, "
2504 "unable to send duplicate msg\n");
Per Lidenb97bf3f2006-01-02 19:04:38 +01002505 return;
2506 }
Arnaldo Carvalho de Melo27d7ff42007-03-31 11:55:19 -03002507 skb_copy_to_linear_data(outbuf, &tunnel_hdr, INT_H_SIZE);
2508 skb_copy_to_linear_data_offset(outbuf, INT_H_SIZE, iter->data,
2509 length);
Per Lidenb97bf3f2006-01-02 19:04:38 +01002510 dbg("%c->%c:", l_ptr->b_ptr->net_plane,
2511 tunnel->b_ptr->net_plane);
2512 msg_dbg(buf_msg(outbuf), ">SEND>");
Per Liden4323add2006-01-18 00:38:21 +01002513 tipc_link_send_buf(tunnel, outbuf);
2514 if (!tipc_link_is_up(l_ptr))
Per Lidenb97bf3f2006-01-02 19:04:38 +01002515 return;
2516 iter = iter->next;
2517 }
2518}
2519
2520
2521
2522/**
2523 * buf_extract - extracts embedded TIPC message from another message
2524 * @skb: encapsulating message buffer
2525 * @from_pos: offset to extract from
2526 *
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002527 * Returns a new message buffer containing an embedded message. The
Per Lidenb97bf3f2006-01-02 19:04:38 +01002528 * encapsulating message itself is left unchanged.
2529 */
2530
2531static struct sk_buff *buf_extract(struct sk_buff *skb, u32 from_pos)
2532{
2533 struct tipc_msg *msg = (struct tipc_msg *)(skb->data + from_pos);
2534 u32 size = msg_size(msg);
2535 struct sk_buff *eb;
2536
2537 eb = buf_acquire(size);
2538 if (eb)
Arnaldo Carvalho de Melo27d7ff42007-03-31 11:55:19 -03002539 skb_copy_to_linear_data(eb, msg, size);
Per Lidenb97bf3f2006-01-02 19:04:38 +01002540 return eb;
2541}
2542
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002543/*
Per Lidenb97bf3f2006-01-02 19:04:38 +01002544 * link_recv_changeover_msg(): Receive tunneled packet sent
2545 * via other link. Node is locked. Return extracted buffer.
2546 */
2547
2548static int link_recv_changeover_msg(struct link **l_ptr,
2549 struct sk_buff **buf)
2550{
2551 struct sk_buff *tunnel_buf = *buf;
2552 struct link *dest_link;
2553 struct tipc_msg *msg;
2554 struct tipc_msg *tunnel_msg = buf_msg(tunnel_buf);
2555 u32 msg_typ = msg_type(tunnel_msg);
2556 u32 msg_count = msg_msgcnt(tunnel_msg);
2557
2558 dest_link = (*l_ptr)->owner->links[msg_bearer_id(tunnel_msg)];
Per Lidenb97bf3f2006-01-02 19:04:38 +01002559 if (!dest_link) {
2560 msg_dbg(tunnel_msg, "NOLINK/<REC<");
2561 goto exit;
2562 }
Allan Stephensf1310722006-06-25 23:51:37 -07002563 if (dest_link == *l_ptr) {
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002564 err("Unexpected changeover message on link <%s>\n",
Allan Stephensf1310722006-06-25 23:51:37 -07002565 (*l_ptr)->name);
2566 goto exit;
2567 }
Per Lidenb97bf3f2006-01-02 19:04:38 +01002568 dbg("%c<-%c:", dest_link->b_ptr->net_plane,
2569 (*l_ptr)->b_ptr->net_plane);
2570 *l_ptr = dest_link;
2571 msg = msg_get_wrapped(tunnel_msg);
2572
2573 if (msg_typ == DUPLICATE_MSG) {
2574 if (less(msg_seqno(msg), mod(dest_link->next_in_no))) {
2575 msg_dbg(tunnel_msg, "DROP/<REC<");
2576 goto exit;
2577 }
2578 *buf = buf_extract(tunnel_buf,INT_H_SIZE);
2579 if (*buf == NULL) {
Allan Stephensa10bd922006-06-25 23:52:17 -07002580 warn("Link changeover error, duplicate msg dropped\n");
Per Lidenb97bf3f2006-01-02 19:04:38 +01002581 goto exit;
2582 }
2583 msg_dbg(tunnel_msg, "TNL<REC<");
2584 buf_discard(tunnel_buf);
2585 return 1;
2586 }
2587
2588 /* First original message ?: */
2589
Per Liden4323add2006-01-18 00:38:21 +01002590 if (tipc_link_is_up(dest_link)) {
Per Lidenb97bf3f2006-01-02 19:04:38 +01002591 msg_dbg(tunnel_msg, "UP/FIRST/<REC<");
Allan Stephensa10bd922006-06-25 23:52:17 -07002592 info("Resetting link <%s>, changeover initiated by peer\n",
2593 dest_link->name);
Per Liden4323add2006-01-18 00:38:21 +01002594 tipc_link_reset(dest_link);
Per Lidenb97bf3f2006-01-02 19:04:38 +01002595 dest_link->exp_msg_count = msg_count;
Allan Stephens5392d642006-06-25 23:52:50 -07002596 dbg("Expecting %u tunnelled messages\n", msg_count);
Per Lidenb97bf3f2006-01-02 19:04:38 +01002597 if (!msg_count)
2598 goto exit;
2599 } else if (dest_link->exp_msg_count == START_CHANGEOVER) {
2600 msg_dbg(tunnel_msg, "BLK/FIRST/<REC<");
2601 dest_link->exp_msg_count = msg_count;
Allan Stephens5392d642006-06-25 23:52:50 -07002602 dbg("Expecting %u tunnelled messages\n", msg_count);
Per Lidenb97bf3f2006-01-02 19:04:38 +01002603 if (!msg_count)
2604 goto exit;
2605 }
2606
2607 /* Receive original message */
2608
2609 if (dest_link->exp_msg_count == 0) {
Allan Stephens5392d642006-06-25 23:52:50 -07002610 warn("Link switchover error, "
2611 "got too many tunnelled messages\n");
Per Lidenb97bf3f2006-01-02 19:04:38 +01002612 msg_dbg(tunnel_msg, "OVERDUE/DROP/<REC<");
2613 dbg_print_link(dest_link, "LINK:");
2614 goto exit;
2615 }
2616 dest_link->exp_msg_count--;
2617 if (less(msg_seqno(msg), dest_link->reset_checkpoint)) {
2618 msg_dbg(tunnel_msg, "DROP/DUPL/<REC<");
2619 goto exit;
2620 } else {
2621 *buf = buf_extract(tunnel_buf, INT_H_SIZE);
2622 if (*buf != NULL) {
2623 msg_dbg(tunnel_msg, "TNL<REC<");
2624 buf_discard(tunnel_buf);
2625 return 1;
2626 } else {
Allan Stephensa10bd922006-06-25 23:52:17 -07002627 warn("Link changeover error, original msg dropped\n");
Per Lidenb97bf3f2006-01-02 19:04:38 +01002628 }
2629 }
2630exit:
Sam Ravnborg1fc54d82006-03-20 22:36:47 -08002631 *buf = NULL;
Per Lidenb97bf3f2006-01-02 19:04:38 +01002632 buf_discard(tunnel_buf);
2633 return 0;
2634}
2635
2636/*
2637 * Bundler functionality:
2638 */
Per Liden4323add2006-01-18 00:38:21 +01002639void tipc_link_recv_bundle(struct sk_buff *buf)
Per Lidenb97bf3f2006-01-02 19:04:38 +01002640{
2641 u32 msgcount = msg_msgcnt(buf_msg(buf));
2642 u32 pos = INT_H_SIZE;
2643 struct sk_buff *obuf;
2644
2645 msg_dbg(buf_msg(buf), "<BNDL<: ");
2646 while (msgcount--) {
2647 obuf = buf_extract(buf, pos);
2648 if (obuf == NULL) {
Allan Stephensa10bd922006-06-25 23:52:17 -07002649 warn("Link unable to unbundle message(s)\n");
2650 break;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -07002651 }
Per Lidenb97bf3f2006-01-02 19:04:38 +01002652 pos += align(msg_size(buf_msg(obuf)));
2653 msg_dbg(buf_msg(obuf), " /");
Per Liden4323add2006-01-18 00:38:21 +01002654 tipc_net_route_msg(obuf);
Per Lidenb97bf3f2006-01-02 19:04:38 +01002655 }
2656 buf_discard(buf);
2657}
2658
2659/*
2660 * Fragmentation/defragmentation:
2661 */
2662
2663
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002664/*
Per Liden4323add2006-01-18 00:38:21 +01002665 * tipc_link_send_long_buf: Entry for buffers needing fragmentation.
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002666 * The buffer is complete, inclusive total message length.
Per Lidenb97bf3f2006-01-02 19:04:38 +01002667 * Returns user data length.
2668 */
Per Liden4323add2006-01-18 00:38:21 +01002669int tipc_link_send_long_buf(struct link *l_ptr, struct sk_buff *buf)
Per Lidenb97bf3f2006-01-02 19:04:38 +01002670{
2671 struct tipc_msg *inmsg = buf_msg(buf);
2672 struct tipc_msg fragm_hdr;
2673 u32 insize = msg_size(inmsg);
2674 u32 dsz = msg_data_sz(inmsg);
2675 unchar *crs = buf->data;
2676 u32 rest = insize;
Allan Stephens15e979d2010-05-11 14:30:10 +00002677 u32 pack_sz = l_ptr->max_pkt;
Per Lidenb97bf3f2006-01-02 19:04:38 +01002678 u32 fragm_sz = pack_sz - INT_H_SIZE;
2679 u32 fragm_no = 1;
Allan Stephens9c396a72008-06-04 17:36:58 -07002680 u32 destaddr;
Per Lidenb97bf3f2006-01-02 19:04:38 +01002681
2682 if (msg_short(inmsg))
2683 destaddr = l_ptr->addr;
Allan Stephens9c396a72008-06-04 17:36:58 -07002684 else
2685 destaddr = msg_destnode(inmsg);
Per Lidenb97bf3f2006-01-02 19:04:38 +01002686
2687 if (msg_routed(inmsg))
2688 msg_set_prevnode(inmsg, tipc_own_addr);
2689
2690 /* Prepare reusable fragment header: */
2691
2692 msg_init(&fragm_hdr, MSG_FRAGMENTER, FIRST_FRAGMENT,
Allan Stephens75715212008-06-04 17:37:34 -07002693 INT_H_SIZE, destaddr);
Per Lidenb97bf3f2006-01-02 19:04:38 +01002694 msg_set_link_selector(&fragm_hdr, msg_link_selector(inmsg));
2695 msg_set_long_msgno(&fragm_hdr, mod(l_ptr->long_msg_seq_no++));
2696 msg_set_fragm_no(&fragm_hdr, fragm_no);
2697 l_ptr->stats.sent_fragmented++;
2698
2699 /* Chop up message: */
2700
2701 while (rest > 0) {
2702 struct sk_buff *fragm;
2703
2704 if (rest <= fragm_sz) {
2705 fragm_sz = rest;
2706 msg_set_type(&fragm_hdr, LAST_FRAGMENT);
2707 }
2708 fragm = buf_acquire(fragm_sz + INT_H_SIZE);
2709 if (fragm == NULL) {
Allan Stephensa10bd922006-06-25 23:52:17 -07002710 warn("Link unable to fragment message\n");
Per Lidenb97bf3f2006-01-02 19:04:38 +01002711 dsz = -ENOMEM;
2712 goto exit;
2713 }
2714 msg_set_size(&fragm_hdr, fragm_sz + INT_H_SIZE);
Arnaldo Carvalho de Melo27d7ff42007-03-31 11:55:19 -03002715 skb_copy_to_linear_data(fragm, &fragm_hdr, INT_H_SIZE);
2716 skb_copy_to_linear_data_offset(fragm, INT_H_SIZE, crs,
2717 fragm_sz);
Per Lidenb97bf3f2006-01-02 19:04:38 +01002718 /* Send queued messages first, if any: */
2719
2720 l_ptr->stats.sent_fragments++;
Per Liden4323add2006-01-18 00:38:21 +01002721 tipc_link_send_buf(l_ptr, fragm);
2722 if (!tipc_link_is_up(l_ptr))
Per Lidenb97bf3f2006-01-02 19:04:38 +01002723 return dsz;
2724 msg_set_fragm_no(&fragm_hdr, ++fragm_no);
2725 rest -= fragm_sz;
2726 crs += fragm_sz;
2727 msg_set_type(&fragm_hdr, FRAGMENT);
2728 }
2729exit:
2730 buf_discard(buf);
2731 return dsz;
2732}
2733
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002734/*
2735 * A pending message being re-assembled must store certain values
2736 * to handle subsequent fragments correctly. The following functions
Per Lidenb97bf3f2006-01-02 19:04:38 +01002737 * help storing these values in unused, available fields in the
2738 * pending message. This makes dynamic memory allocation unecessary.
2739 */
2740
Sam Ravnborg05790c62006-03-20 22:37:04 -08002741static void set_long_msg_seqno(struct sk_buff *buf, u32 seqno)
Per Lidenb97bf3f2006-01-02 19:04:38 +01002742{
2743 msg_set_seqno(buf_msg(buf), seqno);
2744}
2745
Sam Ravnborg05790c62006-03-20 22:37:04 -08002746static u32 get_fragm_size(struct sk_buff *buf)
Per Lidenb97bf3f2006-01-02 19:04:38 +01002747{
2748 return msg_ack(buf_msg(buf));
2749}
2750
Sam Ravnborg05790c62006-03-20 22:37:04 -08002751static void set_fragm_size(struct sk_buff *buf, u32 sz)
Per Lidenb97bf3f2006-01-02 19:04:38 +01002752{
2753 msg_set_ack(buf_msg(buf), sz);
2754}
2755
Sam Ravnborg05790c62006-03-20 22:37:04 -08002756static u32 get_expected_frags(struct sk_buff *buf)
Per Lidenb97bf3f2006-01-02 19:04:38 +01002757{
2758 return msg_bcast_ack(buf_msg(buf));
2759}
2760
Sam Ravnborg05790c62006-03-20 22:37:04 -08002761static void set_expected_frags(struct sk_buff *buf, u32 exp)
Per Lidenb97bf3f2006-01-02 19:04:38 +01002762{
2763 msg_set_bcast_ack(buf_msg(buf), exp);
2764}
2765
Sam Ravnborg05790c62006-03-20 22:37:04 -08002766static u32 get_timer_cnt(struct sk_buff *buf)
Per Lidenb97bf3f2006-01-02 19:04:38 +01002767{
2768 return msg_reroute_cnt(buf_msg(buf));
2769}
2770
Sam Ravnborg05790c62006-03-20 22:37:04 -08002771static void incr_timer_cnt(struct sk_buff *buf)
Per Lidenb97bf3f2006-01-02 19:04:38 +01002772{
2773 msg_incr_reroute_cnt(buf_msg(buf));
2774}
2775
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002776/*
2777 * tipc_link_recv_fragment(): Called with node lock on. Returns
Per Lidenb97bf3f2006-01-02 19:04:38 +01002778 * the reassembled buffer if message is complete.
2779 */
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002780int tipc_link_recv_fragment(struct sk_buff **pending, struct sk_buff **fb,
Per Liden4323add2006-01-18 00:38:21 +01002781 struct tipc_msg **m)
Per Lidenb97bf3f2006-01-02 19:04:38 +01002782{
Sam Ravnborg1fc54d82006-03-20 22:36:47 -08002783 struct sk_buff *prev = NULL;
Per Lidenb97bf3f2006-01-02 19:04:38 +01002784 struct sk_buff *fbuf = *fb;
2785 struct tipc_msg *fragm = buf_msg(fbuf);
2786 struct sk_buff *pbuf = *pending;
2787 u32 long_msg_seq_no = msg_long_msgno(fragm);
2788
Sam Ravnborg1fc54d82006-03-20 22:36:47 -08002789 *fb = NULL;
Per Lidenb97bf3f2006-01-02 19:04:38 +01002790 msg_dbg(fragm,"FRG<REC<");
2791
2792 /* Is there an incomplete message waiting for this fragment? */
2793
Joe Perchesf64f9e72009-11-29 16:55:45 -08002794 while (pbuf && ((msg_seqno(buf_msg(pbuf)) != long_msg_seq_no) ||
2795 (msg_orignode(fragm) != msg_orignode(buf_msg(pbuf))))) {
Per Lidenb97bf3f2006-01-02 19:04:38 +01002796 prev = pbuf;
2797 pbuf = pbuf->next;
2798 }
2799
2800 if (!pbuf && (msg_type(fragm) == FIRST_FRAGMENT)) {
2801 struct tipc_msg *imsg = (struct tipc_msg *)msg_data(fragm);
2802 u32 msg_sz = msg_size(imsg);
2803 u32 fragm_sz = msg_data_sz(fragm);
2804 u32 exp_fragm_cnt = msg_sz/fragm_sz + !!(msg_sz % fragm_sz);
2805 u32 max = TIPC_MAX_USER_MSG_SIZE + LONG_H_SIZE;
2806 if (msg_type(imsg) == TIPC_MCAST_MSG)
2807 max = TIPC_MAX_USER_MSG_SIZE + MCAST_H_SIZE;
2808 if (msg_size(imsg) > max) {
2809 msg_dbg(fragm,"<REC<Oversized: ");
2810 buf_discard(fbuf);
2811 return 0;
2812 }
2813 pbuf = buf_acquire(msg_size(imsg));
2814 if (pbuf != NULL) {
2815 pbuf->next = *pending;
2816 *pending = pbuf;
Arnaldo Carvalho de Melo27d7ff42007-03-31 11:55:19 -03002817 skb_copy_to_linear_data(pbuf, imsg,
2818 msg_data_sz(fragm));
Per Lidenb97bf3f2006-01-02 19:04:38 +01002819 /* Prepare buffer for subsequent fragments. */
2820
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002821 set_long_msg_seqno(pbuf, long_msg_seq_no);
2822 set_fragm_size(pbuf,fragm_sz);
2823 set_expected_frags(pbuf,exp_fragm_cnt - 1);
Per Lidenb97bf3f2006-01-02 19:04:38 +01002824 } else {
Allan Stephensa10bd922006-06-25 23:52:17 -07002825 warn("Link unable to reassemble fragmented message\n");
Per Lidenb97bf3f2006-01-02 19:04:38 +01002826 }
2827 buf_discard(fbuf);
2828 return 0;
2829 } else if (pbuf && (msg_type(fragm) != FIRST_FRAGMENT)) {
2830 u32 dsz = msg_data_sz(fragm);
2831 u32 fsz = get_fragm_size(pbuf);
2832 u32 crs = ((msg_fragm_no(fragm) - 1) * fsz);
2833 u32 exp_frags = get_expected_frags(pbuf) - 1;
Arnaldo Carvalho de Melo27d7ff42007-03-31 11:55:19 -03002834 skb_copy_to_linear_data_offset(pbuf, crs,
2835 msg_data(fragm), dsz);
Per Lidenb97bf3f2006-01-02 19:04:38 +01002836 buf_discard(fbuf);
2837
2838 /* Is message complete? */
2839
2840 if (exp_frags == 0) {
2841 if (prev)
2842 prev->next = pbuf->next;
2843 else
2844 *pending = pbuf->next;
2845 msg_reset_reroute_cnt(buf_msg(pbuf));
2846 *fb = pbuf;
2847 *m = buf_msg(pbuf);
2848 return 1;
2849 }
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002850 set_expected_frags(pbuf,exp_frags);
Per Lidenb97bf3f2006-01-02 19:04:38 +01002851 return 0;
2852 }
2853 dbg(" Discarding orphan fragment %x\n",fbuf);
2854 msg_dbg(fragm,"ORPHAN:");
2855 dbg("Pending long buffers:\n");
2856 dbg_print_buf_chain(*pending);
2857 buf_discard(fbuf);
2858 return 0;
2859}
2860
2861/**
2862 * link_check_defragm_bufs - flush stale incoming message fragments
2863 * @l_ptr: pointer to link
2864 */
2865
2866static void link_check_defragm_bufs(struct link *l_ptr)
2867{
Sam Ravnborg1fc54d82006-03-20 22:36:47 -08002868 struct sk_buff *prev = NULL;
2869 struct sk_buff *next = NULL;
Per Lidenb97bf3f2006-01-02 19:04:38 +01002870 struct sk_buff *buf = l_ptr->defragm_buf;
2871
2872 if (!buf)
2873 return;
2874 if (!link_working_working(l_ptr))
2875 return;
2876 while (buf) {
2877 u32 cnt = get_timer_cnt(buf);
2878
2879 next = buf->next;
2880 if (cnt < 4) {
2881 incr_timer_cnt(buf);
2882 prev = buf;
2883 } else {
2884 dbg(" Discarding incomplete long buffer\n");
2885 msg_dbg(buf_msg(buf), "LONG:");
2886 dbg_print_link(l_ptr, "curr:");
2887 dbg("Pending long buffers:\n");
2888 dbg_print_buf_chain(l_ptr->defragm_buf);
2889 if (prev)
2890 prev->next = buf->next;
2891 else
2892 l_ptr->defragm_buf = buf->next;
2893 buf_discard(buf);
2894 }
2895 buf = next;
2896 }
2897}
2898
2899
2900
2901static void link_set_supervision_props(struct link *l_ptr, u32 tolerance)
2902{
2903 l_ptr->tolerance = tolerance;
2904 l_ptr->continuity_interval =
2905 ((tolerance / 4) > 500) ? 500 : tolerance / 4;
2906 l_ptr->abort_limit = tolerance / (l_ptr->continuity_interval / 4);
2907}
2908
2909
Per Liden4323add2006-01-18 00:38:21 +01002910void tipc_link_set_queue_limits(struct link *l_ptr, u32 window)
Per Lidenb97bf3f2006-01-02 19:04:38 +01002911{
2912 /* Data messages from this node, inclusive FIRST_FRAGM */
Allan Stephens06d82c92008-03-06 15:06:55 -08002913 l_ptr->queue_limit[TIPC_LOW_IMPORTANCE] = window;
2914 l_ptr->queue_limit[TIPC_MEDIUM_IMPORTANCE] = (window / 3) * 4;
2915 l_ptr->queue_limit[TIPC_HIGH_IMPORTANCE] = (window / 3) * 5;
2916 l_ptr->queue_limit[TIPC_CRITICAL_IMPORTANCE] = (window / 3) * 6;
Per Lidenb97bf3f2006-01-02 19:04:38 +01002917 /* Transiting data messages,inclusive FIRST_FRAGM */
Allan Stephens06d82c92008-03-06 15:06:55 -08002918 l_ptr->queue_limit[TIPC_LOW_IMPORTANCE + 4] = 300;
2919 l_ptr->queue_limit[TIPC_MEDIUM_IMPORTANCE + 4] = 600;
2920 l_ptr->queue_limit[TIPC_HIGH_IMPORTANCE + 4] = 900;
2921 l_ptr->queue_limit[TIPC_CRITICAL_IMPORTANCE + 4] = 1200;
Per Lidenb97bf3f2006-01-02 19:04:38 +01002922 l_ptr->queue_limit[CONN_MANAGER] = 1200;
2923 l_ptr->queue_limit[ROUTE_DISTRIBUTOR] = 1200;
2924 l_ptr->queue_limit[CHANGEOVER_PROTOCOL] = 2500;
2925 l_ptr->queue_limit[NAME_DISTRIBUTOR] = 3000;
2926 /* FRAGMENT and LAST_FRAGMENT packets */
2927 l_ptr->queue_limit[MSG_FRAGMENTER] = 4000;
2928}
2929
2930/**
2931 * link_find_link - locate link by name
2932 * @name - ptr to link name string
2933 * @node - ptr to area to be filled with ptr to associated node
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002934 *
Per Liden4323add2006-01-18 00:38:21 +01002935 * Caller must hold 'tipc_net_lock' to ensure node and bearer are not deleted;
Per Lidenb97bf3f2006-01-02 19:04:38 +01002936 * this also prevents link deletion.
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002937 *
Per Lidenb97bf3f2006-01-02 19:04:38 +01002938 * Returns pointer to link (or 0 if invalid link name).
2939 */
2940
David S. Miller6c000552008-09-02 23:38:32 -07002941static struct link *link_find_link(const char *name, struct tipc_node **node)
Per Lidenb97bf3f2006-01-02 19:04:38 +01002942{
2943 struct link_name link_name_parts;
2944 struct bearer *b_ptr;
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002945 struct link *l_ptr;
Per Lidenb97bf3f2006-01-02 19:04:38 +01002946
2947 if (!link_name_validate(name, &link_name_parts))
Sam Ravnborg1fc54d82006-03-20 22:36:47 -08002948 return NULL;
Per Lidenb97bf3f2006-01-02 19:04:38 +01002949
Per Liden4323add2006-01-18 00:38:21 +01002950 b_ptr = tipc_bearer_find_interface(link_name_parts.if_local);
Per Lidenb97bf3f2006-01-02 19:04:38 +01002951 if (!b_ptr)
Sam Ravnborg1fc54d82006-03-20 22:36:47 -08002952 return NULL;
Per Lidenb97bf3f2006-01-02 19:04:38 +01002953
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002954 *node = tipc_node_find(link_name_parts.addr_peer);
Per Lidenb97bf3f2006-01-02 19:04:38 +01002955 if (!*node)
Sam Ravnborg1fc54d82006-03-20 22:36:47 -08002956 return NULL;
Per Lidenb97bf3f2006-01-02 19:04:38 +01002957
2958 l_ptr = (*node)->links[b_ptr->identity];
2959 if (!l_ptr || strcmp(l_ptr->name, name))
Sam Ravnborg1fc54d82006-03-20 22:36:47 -08002960 return NULL;
Per Lidenb97bf3f2006-01-02 19:04:38 +01002961
2962 return l_ptr;
2963}
2964
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002965struct sk_buff *tipc_link_cmd_config(const void *req_tlv_area, int req_tlv_space,
Per Liden4323add2006-01-18 00:38:21 +01002966 u16 cmd)
Per Lidenb97bf3f2006-01-02 19:04:38 +01002967{
2968 struct tipc_link_config *args;
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002969 u32 new_value;
Per Lidenb97bf3f2006-01-02 19:04:38 +01002970 struct link *l_ptr;
David S. Miller6c000552008-09-02 23:38:32 -07002971 struct tipc_node *node;
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002972 int res;
Per Lidenb97bf3f2006-01-02 19:04:38 +01002973
2974 if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_LINK_CONFIG))
Per Liden4323add2006-01-18 00:38:21 +01002975 return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
Per Lidenb97bf3f2006-01-02 19:04:38 +01002976
2977 args = (struct tipc_link_config *)TLV_DATA(req_tlv_area);
2978 new_value = ntohl(args->value);
2979
Per Liden4323add2006-01-18 00:38:21 +01002980 if (!strcmp(args->name, tipc_bclink_name)) {
Per Lidenb97bf3f2006-01-02 19:04:38 +01002981 if ((cmd == TIPC_CMD_SET_LINK_WINDOW) &&
Per Liden4323add2006-01-18 00:38:21 +01002982 (tipc_bclink_set_queue_limits(new_value) == 0))
2983 return tipc_cfg_reply_none();
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002984 return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
Per Liden4323add2006-01-18 00:38:21 +01002985 " (cannot change setting on broadcast link)");
Per Lidenb97bf3f2006-01-02 19:04:38 +01002986 }
2987
Per Liden4323add2006-01-18 00:38:21 +01002988 read_lock_bh(&tipc_net_lock);
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002989 l_ptr = link_find_link(args->name, &node);
Per Lidenb97bf3f2006-01-02 19:04:38 +01002990 if (!l_ptr) {
Per Liden4323add2006-01-18 00:38:21 +01002991 read_unlock_bh(&tipc_net_lock);
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002992 return tipc_cfg_reply_error_string("link not found");
Per Lidenb97bf3f2006-01-02 19:04:38 +01002993 }
2994
Per Liden4323add2006-01-18 00:38:21 +01002995 tipc_node_lock(node);
Per Lidenb97bf3f2006-01-02 19:04:38 +01002996 res = -EINVAL;
2997 switch (cmd) {
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002998 case TIPC_CMD_SET_LINK_TOL:
2999 if ((new_value >= TIPC_MIN_LINK_TOL) &&
Per Lidenb97bf3f2006-01-02 19:04:38 +01003000 (new_value <= TIPC_MAX_LINK_TOL)) {
3001 link_set_supervision_props(l_ptr, new_value);
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09003002 tipc_link_send_proto_msg(l_ptr, STATE_MSG,
Per Liden4323add2006-01-18 00:38:21 +01003003 0, 0, new_value, 0, 0);
Allan Stephens0e35fd52008-07-14 22:44:01 -07003004 res = 0;
Per Lidenb97bf3f2006-01-02 19:04:38 +01003005 }
3006 break;
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09003007 case TIPC_CMD_SET_LINK_PRI:
Per Liden16cb4b32006-01-13 22:22:22 +01003008 if ((new_value >= TIPC_MIN_LINK_PRI) &&
3009 (new_value <= TIPC_MAX_LINK_PRI)) {
Per Lidenb97bf3f2006-01-02 19:04:38 +01003010 l_ptr->priority = new_value;
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09003011 tipc_link_send_proto_msg(l_ptr, STATE_MSG,
Per Liden4323add2006-01-18 00:38:21 +01003012 0, 0, 0, new_value, 0);
Allan Stephens0e35fd52008-07-14 22:44:01 -07003013 res = 0;
Per Lidenb97bf3f2006-01-02 19:04:38 +01003014 }
3015 break;
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09003016 case TIPC_CMD_SET_LINK_WINDOW:
3017 if ((new_value >= TIPC_MIN_LINK_WIN) &&
Per Lidenb97bf3f2006-01-02 19:04:38 +01003018 (new_value <= TIPC_MAX_LINK_WIN)) {
Per Liden4323add2006-01-18 00:38:21 +01003019 tipc_link_set_queue_limits(l_ptr, new_value);
Allan Stephens0e35fd52008-07-14 22:44:01 -07003020 res = 0;
Per Lidenb97bf3f2006-01-02 19:04:38 +01003021 }
3022 break;
3023 }
Per Liden4323add2006-01-18 00:38:21 +01003024 tipc_node_unlock(node);
Per Lidenb97bf3f2006-01-02 19:04:38 +01003025
Per Liden4323add2006-01-18 00:38:21 +01003026 read_unlock_bh(&tipc_net_lock);
Per Lidenb97bf3f2006-01-02 19:04:38 +01003027 if (res)
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09003028 return tipc_cfg_reply_error_string("cannot change link setting");
Per Lidenb97bf3f2006-01-02 19:04:38 +01003029
Per Liden4323add2006-01-18 00:38:21 +01003030 return tipc_cfg_reply_none();
Per Lidenb97bf3f2006-01-02 19:04:38 +01003031}
3032
3033/**
3034 * link_reset_statistics - reset link statistics
3035 * @l_ptr: pointer to link
3036 */
3037
3038static void link_reset_statistics(struct link *l_ptr)
3039{
3040 memset(&l_ptr->stats, 0, sizeof(l_ptr->stats));
3041 l_ptr->stats.sent_info = l_ptr->next_out_no;
3042 l_ptr->stats.recv_info = l_ptr->next_in_no;
3043}
3044
Per Liden4323add2006-01-18 00:38:21 +01003045struct sk_buff *tipc_link_cmd_reset_stats(const void *req_tlv_area, int req_tlv_space)
Per Lidenb97bf3f2006-01-02 19:04:38 +01003046{
3047 char *link_name;
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09003048 struct link *l_ptr;
David S. Miller6c000552008-09-02 23:38:32 -07003049 struct tipc_node *node;
Per Lidenb97bf3f2006-01-02 19:04:38 +01003050
3051 if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_LINK_NAME))
Per Liden4323add2006-01-18 00:38:21 +01003052 return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
Per Lidenb97bf3f2006-01-02 19:04:38 +01003053
3054 link_name = (char *)TLV_DATA(req_tlv_area);
Per Liden4323add2006-01-18 00:38:21 +01003055 if (!strcmp(link_name, tipc_bclink_name)) {
3056 if (tipc_bclink_reset_stats())
3057 return tipc_cfg_reply_error_string("link not found");
3058 return tipc_cfg_reply_none();
Per Lidenb97bf3f2006-01-02 19:04:38 +01003059 }
3060
Per Liden4323add2006-01-18 00:38:21 +01003061 read_lock_bh(&tipc_net_lock);
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09003062 l_ptr = link_find_link(link_name, &node);
Per Lidenb97bf3f2006-01-02 19:04:38 +01003063 if (!l_ptr) {
Per Liden4323add2006-01-18 00:38:21 +01003064 read_unlock_bh(&tipc_net_lock);
3065 return tipc_cfg_reply_error_string("link not found");
Per Lidenb97bf3f2006-01-02 19:04:38 +01003066 }
3067
Per Liden4323add2006-01-18 00:38:21 +01003068 tipc_node_lock(node);
Per Lidenb97bf3f2006-01-02 19:04:38 +01003069 link_reset_statistics(l_ptr);
Per Liden4323add2006-01-18 00:38:21 +01003070 tipc_node_unlock(node);
3071 read_unlock_bh(&tipc_net_lock);
3072 return tipc_cfg_reply_none();
Per Lidenb97bf3f2006-01-02 19:04:38 +01003073}
3074
3075/**
3076 * percent - convert count to a percentage of total (rounding up or down)
3077 */
3078
3079static u32 percent(u32 count, u32 total)
3080{
3081 return (count * 100 + (total / 2)) / total;
3082}
3083
3084/**
Per Liden4323add2006-01-18 00:38:21 +01003085 * tipc_link_stats - print link statistics
Per Lidenb97bf3f2006-01-02 19:04:38 +01003086 * @name: link name
3087 * @buf: print buffer area
3088 * @buf_size: size of print buffer area
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09003089 *
Per Lidenb97bf3f2006-01-02 19:04:38 +01003090 * Returns length of print buffer data string (or 0 if error)
3091 */
3092
Per Liden4323add2006-01-18 00:38:21 +01003093static int tipc_link_stats(const char *name, char *buf, const u32 buf_size)
Per Lidenb97bf3f2006-01-02 19:04:38 +01003094{
3095 struct print_buf pb;
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09003096 struct link *l_ptr;
David S. Miller6c000552008-09-02 23:38:32 -07003097 struct tipc_node *node;
Per Lidenb97bf3f2006-01-02 19:04:38 +01003098 char *status;
3099 u32 profile_total = 0;
3100
Per Liden4323add2006-01-18 00:38:21 +01003101 if (!strcmp(name, tipc_bclink_name))
3102 return tipc_bclink_stats(buf, buf_size);
Per Lidenb97bf3f2006-01-02 19:04:38 +01003103
Per Liden4323add2006-01-18 00:38:21 +01003104 tipc_printbuf_init(&pb, buf, buf_size);
Per Lidenb97bf3f2006-01-02 19:04:38 +01003105
Per Liden4323add2006-01-18 00:38:21 +01003106 read_lock_bh(&tipc_net_lock);
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09003107 l_ptr = link_find_link(name, &node);
Per Lidenb97bf3f2006-01-02 19:04:38 +01003108 if (!l_ptr) {
Per Liden4323add2006-01-18 00:38:21 +01003109 read_unlock_bh(&tipc_net_lock);
Per Lidenb97bf3f2006-01-02 19:04:38 +01003110 return 0;
3111 }
Per Liden4323add2006-01-18 00:38:21 +01003112 tipc_node_lock(node);
Per Lidenb97bf3f2006-01-02 19:04:38 +01003113
Per Liden4323add2006-01-18 00:38:21 +01003114 if (tipc_link_is_active(l_ptr))
Per Lidenb97bf3f2006-01-02 19:04:38 +01003115 status = "ACTIVE";
Per Liden4323add2006-01-18 00:38:21 +01003116 else if (tipc_link_is_up(l_ptr))
Per Lidenb97bf3f2006-01-02 19:04:38 +01003117 status = "STANDBY";
3118 else
3119 status = "DEFUNCT";
3120 tipc_printf(&pb, "Link <%s>\n"
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09003121 " %s MTU:%u Priority:%u Tolerance:%u ms"
3122 " Window:%u packets\n",
Allan Stephens15e979d2010-05-11 14:30:10 +00003123 l_ptr->name, status, l_ptr->max_pkt,
Per Lidenb97bf3f2006-01-02 19:04:38 +01003124 l_ptr->priority, l_ptr->tolerance, l_ptr->queue_limit[0]);
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09003125 tipc_printf(&pb, " RX packets:%u fragments:%u/%u bundles:%u/%u\n",
Per Lidenb97bf3f2006-01-02 19:04:38 +01003126 l_ptr->next_in_no - l_ptr->stats.recv_info,
3127 l_ptr->stats.recv_fragments,
3128 l_ptr->stats.recv_fragmented,
3129 l_ptr->stats.recv_bundles,
3130 l_ptr->stats.recv_bundled);
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09003131 tipc_printf(&pb, " TX packets:%u fragments:%u/%u bundles:%u/%u\n",
Per Lidenb97bf3f2006-01-02 19:04:38 +01003132 l_ptr->next_out_no - l_ptr->stats.sent_info,
3133 l_ptr->stats.sent_fragments,
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09003134 l_ptr->stats.sent_fragmented,
Per Lidenb97bf3f2006-01-02 19:04:38 +01003135 l_ptr->stats.sent_bundles,
3136 l_ptr->stats.sent_bundled);
3137 profile_total = l_ptr->stats.msg_length_counts;
3138 if (!profile_total)
3139 profile_total = 1;
3140 tipc_printf(&pb, " TX profile sample:%u packets average:%u octets\n"
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09003141 " 0-64:%u%% -256:%u%% -1024:%u%% -4096:%u%% "
3142 "-16354:%u%% -32768:%u%% -66000:%u%%\n",
Per Lidenb97bf3f2006-01-02 19:04:38 +01003143 l_ptr->stats.msg_length_counts,
3144 l_ptr->stats.msg_lengths_total / profile_total,
3145 percent(l_ptr->stats.msg_length_profile[0], profile_total),
3146 percent(l_ptr->stats.msg_length_profile[1], profile_total),
3147 percent(l_ptr->stats.msg_length_profile[2], profile_total),
3148 percent(l_ptr->stats.msg_length_profile[3], profile_total),
3149 percent(l_ptr->stats.msg_length_profile[4], profile_total),
3150 percent(l_ptr->stats.msg_length_profile[5], profile_total),
3151 percent(l_ptr->stats.msg_length_profile[6], profile_total));
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09003152 tipc_printf(&pb, " RX states:%u probes:%u naks:%u defs:%u dups:%u\n",
Per Lidenb97bf3f2006-01-02 19:04:38 +01003153 l_ptr->stats.recv_states,
3154 l_ptr->stats.recv_probes,
3155 l_ptr->stats.recv_nacks,
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09003156 l_ptr->stats.deferred_recv,
Per Lidenb97bf3f2006-01-02 19:04:38 +01003157 l_ptr->stats.duplicates);
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09003158 tipc_printf(&pb, " TX states:%u probes:%u naks:%u acks:%u dups:%u\n",
3159 l_ptr->stats.sent_states,
3160 l_ptr->stats.sent_probes,
3161 l_ptr->stats.sent_nacks,
3162 l_ptr->stats.sent_acks,
Per Lidenb97bf3f2006-01-02 19:04:38 +01003163 l_ptr->stats.retransmitted);
3164 tipc_printf(&pb, " Congestion bearer:%u link:%u Send queue max:%u avg:%u\n",
3165 l_ptr->stats.bearer_congs,
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09003166 l_ptr->stats.link_congs,
Per Lidenb97bf3f2006-01-02 19:04:38 +01003167 l_ptr->stats.max_queue_sz,
3168 l_ptr->stats.queue_sz_counts
3169 ? (l_ptr->stats.accu_queue_sz / l_ptr->stats.queue_sz_counts)
3170 : 0);
3171
Per Liden4323add2006-01-18 00:38:21 +01003172 tipc_node_unlock(node);
3173 read_unlock_bh(&tipc_net_lock);
3174 return tipc_printbuf_validate(&pb);
Per Lidenb97bf3f2006-01-02 19:04:38 +01003175}
3176
3177#define MAX_LINK_STATS_INFO 2000
3178
Per Liden4323add2006-01-18 00:38:21 +01003179struct sk_buff *tipc_link_cmd_show_stats(const void *req_tlv_area, int req_tlv_space)
Per Lidenb97bf3f2006-01-02 19:04:38 +01003180{
3181 struct sk_buff *buf;
3182 struct tlv_desc *rep_tlv;
3183 int str_len;
3184
3185 if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_LINK_NAME))
Per Liden4323add2006-01-18 00:38:21 +01003186 return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
Per Lidenb97bf3f2006-01-02 19:04:38 +01003187
Per Liden4323add2006-01-18 00:38:21 +01003188 buf = tipc_cfg_reply_alloc(TLV_SPACE(MAX_LINK_STATS_INFO));
Per Lidenb97bf3f2006-01-02 19:04:38 +01003189 if (!buf)
3190 return NULL;
3191
3192 rep_tlv = (struct tlv_desc *)buf->data;
3193
Per Liden4323add2006-01-18 00:38:21 +01003194 str_len = tipc_link_stats((char *)TLV_DATA(req_tlv_area),
3195 (char *)TLV_DATA(rep_tlv), MAX_LINK_STATS_INFO);
Per Lidenb97bf3f2006-01-02 19:04:38 +01003196 if (!str_len) {
3197 buf_discard(buf);
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09003198 return tipc_cfg_reply_error_string("link not found");
Per Lidenb97bf3f2006-01-02 19:04:38 +01003199 }
3200
3201 skb_put(buf, TLV_SPACE(str_len));
3202 TLV_SET(rep_tlv, TIPC_TLV_ULTRA_STRING, NULL, str_len);
3203
3204 return buf;
3205}
3206
3207#if 0
3208int link_control(const char *name, u32 op, u32 val)
3209{
3210 int res = -EINVAL;
3211 struct link *l_ptr;
3212 u32 bearer_id;
David S. Miller6c000552008-09-02 23:38:32 -07003213 struct tipc_node * node;
Per Lidenb97bf3f2006-01-02 19:04:38 +01003214 u32 a;
3215
3216 a = link_name2addr(name, &bearer_id);
Per Liden4323add2006-01-18 00:38:21 +01003217 read_lock_bh(&tipc_net_lock);
3218 node = tipc_node_find(a);
Per Lidenb97bf3f2006-01-02 19:04:38 +01003219 if (node) {
Per Liden4323add2006-01-18 00:38:21 +01003220 tipc_node_lock(node);
Per Lidenb97bf3f2006-01-02 19:04:38 +01003221 l_ptr = node->links[bearer_id];
3222 if (l_ptr) {
3223 if (op == TIPC_REMOVE_LINK) {
3224 struct bearer *b_ptr = l_ptr->b_ptr;
3225 spin_lock_bh(&b_ptr->publ.lock);
Per Liden4323add2006-01-18 00:38:21 +01003226 tipc_link_delete(l_ptr);
Per Lidenb97bf3f2006-01-02 19:04:38 +01003227 spin_unlock_bh(&b_ptr->publ.lock);
3228 }
3229 if (op == TIPC_CMD_BLOCK_LINK) {
Per Liden4323add2006-01-18 00:38:21 +01003230 tipc_link_reset(l_ptr);
Per Lidenb97bf3f2006-01-02 19:04:38 +01003231 l_ptr->blocked = 1;
3232 }
3233 if (op == TIPC_CMD_UNBLOCK_LINK) {
3234 l_ptr->blocked = 0;
3235 }
Allan Stephens0e35fd52008-07-14 22:44:01 -07003236 res = 0;
Per Lidenb97bf3f2006-01-02 19:04:38 +01003237 }
Per Liden4323add2006-01-18 00:38:21 +01003238 tipc_node_unlock(node);
Per Lidenb97bf3f2006-01-02 19:04:38 +01003239 }
Per Liden4323add2006-01-18 00:38:21 +01003240 read_unlock_bh(&tipc_net_lock);
Per Lidenb97bf3f2006-01-02 19:04:38 +01003241 return res;
3242}
3243#endif
3244
3245/**
Per Liden4323add2006-01-18 00:38:21 +01003246 * tipc_link_get_max_pkt - get maximum packet size to use when sending to destination
Per Lidenb97bf3f2006-01-02 19:04:38 +01003247 * @dest: network address of destination node
3248 * @selector: used to select from set of active links
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09003249 *
Per Lidenb97bf3f2006-01-02 19:04:38 +01003250 * If no active link can be found, uses default maximum packet size.
3251 */
3252
Per Liden4323add2006-01-18 00:38:21 +01003253u32 tipc_link_get_max_pkt(u32 dest, u32 selector)
Per Lidenb97bf3f2006-01-02 19:04:38 +01003254{
David S. Miller6c000552008-09-02 23:38:32 -07003255 struct tipc_node *n_ptr;
Per Lidenb97bf3f2006-01-02 19:04:38 +01003256 struct link *l_ptr;
3257 u32 res = MAX_PKT_DEFAULT;
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09003258
Per Lidenb97bf3f2006-01-02 19:04:38 +01003259 if (dest == tipc_own_addr)
3260 return MAX_MSG_SIZE;
3261
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09003262 read_lock_bh(&tipc_net_lock);
Per Liden4323add2006-01-18 00:38:21 +01003263 n_ptr = tipc_node_select(dest, selector);
Per Lidenb97bf3f2006-01-02 19:04:38 +01003264 if (n_ptr) {
Per Liden4323add2006-01-18 00:38:21 +01003265 tipc_node_lock(n_ptr);
Per Lidenb97bf3f2006-01-02 19:04:38 +01003266 l_ptr = n_ptr->active_links[selector & 1];
3267 if (l_ptr)
Allan Stephens15e979d2010-05-11 14:30:10 +00003268 res = l_ptr->max_pkt;
Per Liden4323add2006-01-18 00:38:21 +01003269 tipc_node_unlock(n_ptr);
Per Lidenb97bf3f2006-01-02 19:04:38 +01003270 }
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09003271 read_unlock_bh(&tipc_net_lock);
Per Lidenb97bf3f2006-01-02 19:04:38 +01003272 return res;
3273}
3274
3275#if 0
3276static void link_dump_rec_queue(struct link *l_ptr)
3277{
3278 struct sk_buff *crs;
3279
3280 if (!l_ptr->oldest_deferred_in) {
3281 info("Reception queue empty\n");
3282 return;
3283 }
3284 info("Contents of Reception queue:\n");
3285 crs = l_ptr->oldest_deferred_in;
3286 while (crs) {
3287 if (crs->data == (void *)0x0000a3a3) {
3288 info("buffer %x invalid\n", crs);
3289 return;
3290 }
Frans Popa570f092010-03-24 07:57:29 +00003291 msg_dbg(buf_msg(crs), "In rec queue:\n");
Per Lidenb97bf3f2006-01-02 19:04:38 +01003292 crs = crs->next;
3293 }
3294}
3295#endif
3296
3297static void link_dump_send_queue(struct link *l_ptr)
3298{
3299 if (l_ptr->next_out) {
3300 info("\nContents of unsent queue:\n");
3301 dbg_print_buf_chain(l_ptr->next_out);
3302 }
3303 info("\nContents of send queue:\n");
3304 if (l_ptr->first_out) {
3305 dbg_print_buf_chain(l_ptr->first_out);
3306 }
3307 info("Empty send queue\n");
3308}
3309
3310static void link_print(struct link *l_ptr, struct print_buf *buf,
3311 const char *str)
3312{
3313 tipc_printf(buf, str);
3314 if (link_reset_reset(l_ptr) || link_reset_unknown(l_ptr))
3315 return;
3316 tipc_printf(buf, "Link %x<%s>:",
3317 l_ptr->addr, l_ptr->b_ptr->publ.name);
3318 tipc_printf(buf, ": NXO(%u):", mod(l_ptr->next_out_no));
3319 tipc_printf(buf, "NXI(%u):", mod(l_ptr->next_in_no));
3320 tipc_printf(buf, "SQUE");
3321 if (l_ptr->first_out) {
3322 tipc_printf(buf, "[%u..", msg_seqno(buf_msg(l_ptr->first_out)));
3323 if (l_ptr->next_out)
3324 tipc_printf(buf, "%u..",
3325 msg_seqno(buf_msg(l_ptr->next_out)));
Allan Stephensb82834e2010-05-11 14:30:04 +00003326 tipc_printf(buf, "%u]", msg_seqno(buf_msg(l_ptr->last_out)));
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09003327 if ((mod(msg_seqno(buf_msg(l_ptr->last_out)) -
3328 msg_seqno(buf_msg(l_ptr->first_out)))
Joe Perchesf64f9e72009-11-29 16:55:45 -08003329 != (l_ptr->out_queue_size - 1)) ||
3330 (l_ptr->last_out->next != NULL)) {
Per Lidenb97bf3f2006-01-02 19:04:38 +01003331 tipc_printf(buf, "\nSend queue inconsistency\n");
3332 tipc_printf(buf, "first_out= %x ", l_ptr->first_out);
3333 tipc_printf(buf, "next_out= %x ", l_ptr->next_out);
3334 tipc_printf(buf, "last_out= %x ", l_ptr->last_out);
3335 link_dump_send_queue(l_ptr);
3336 }
3337 } else
3338 tipc_printf(buf, "[]");
3339 tipc_printf(buf, "SQSIZ(%u)", l_ptr->out_queue_size);
3340 if (l_ptr->oldest_deferred_in) {
3341 u32 o = msg_seqno(buf_msg(l_ptr->oldest_deferred_in));
3342 u32 n = msg_seqno(buf_msg(l_ptr->newest_deferred_in));
3343 tipc_printf(buf, ":RQUE[%u..%u]", o, n);
3344 if (l_ptr->deferred_inqueue_sz != mod((n + 1) - o)) {
3345 tipc_printf(buf, ":RQSIZ(%u)",
3346 l_ptr->deferred_inqueue_sz);
3347 }
3348 }
3349 if (link_working_unknown(l_ptr))
3350 tipc_printf(buf, ":WU");
3351 if (link_reset_reset(l_ptr))
3352 tipc_printf(buf, ":RR");
3353 if (link_reset_unknown(l_ptr))
3354 tipc_printf(buf, ":RU");
3355 if (link_working_working(l_ptr))
3356 tipc_printf(buf, ":WW");
3357 tipc_printf(buf, "\n");
3358}
3359