blob: 4be78ecf4a6711d2f8c4f9e01fd30dc90cd01ec1 [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
Per Lidenb97bf3f2006-01-02 19:04:38 +0100102static void link_handle_out_of_seq_msg(struct link *l_ptr,
103 struct sk_buff *buf);
104static void link_recv_proto_msg(struct link *l_ptr, struct sk_buff *buf);
105static int link_recv_changeover_msg(struct link **l_ptr, struct sk_buff **buf);
106static void link_set_supervision_props(struct link *l_ptr, u32 tolerance);
107static int link_send_sections_long(struct port *sender,
108 struct iovec const *msg_sect,
109 u32 num_sect, u32 destnode);
110static void link_check_defragm_bufs(struct link *l_ptr);
111static void link_state_event(struct link *l_ptr, u32 event);
112static void link_reset_statistics(struct link *l_ptr);
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900113static void link_print(struct link *l_ptr, struct print_buf *buf,
Per Lidenb97bf3f2006-01-02 19:04:38 +0100114 const char *str);
115
116/*
117 * Debugging code used by link routines only
118 *
119 * When debugging link problems on a system that has multiple links,
120 * the standard TIPC debugging routines may not be useful since they
121 * allow the output from multiple links to be intermixed. For this reason
122 * routines of the form "dbg_link_XXX()" have been created that will capture
123 * debug info into a link's personal print buffer, which can then be dumped
Allan Stephensa3df92c2006-10-16 21:49:03 -0700124 * into the TIPC system log (TIPC_LOG) upon request.
Per Lidenb97bf3f2006-01-02 19:04:38 +0100125 *
126 * To enable per-link debugging, use LINK_LOG_BUF_SIZE to specify the size
127 * of the print buffer used by each link. If LINK_LOG_BUF_SIZE is set to 0,
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900128 * the dbg_link_XXX() routines simply send their output to the standard
Per Lidenb97bf3f2006-01-02 19:04:38 +0100129 * debug print buffer (DBG_OUTPUT), if it has been defined; this can be useful
130 * when there is only a single link in the system being debugged.
131 *
132 * Notes:
Allan Stephensa3df92c2006-10-16 21:49:03 -0700133 * - When enabled, LINK_LOG_BUF_SIZE should be set to at least TIPC_PB_MIN_SIZE
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900134 * - "l_ptr" must be valid when using dbg_link_XXX() macros
Per Lidenb97bf3f2006-01-02 19:04:38 +0100135 */
136
137#define LINK_LOG_BUF_SIZE 0
138
Allan Stephens48c97132008-05-05 01:24:06 -0700139#define dbg_link(fmt, arg...) \
140 do { \
141 if (LINK_LOG_BUF_SIZE) \
142 tipc_printf(&l_ptr->print_buf, fmt, ## arg); \
143 } while (0)
144#define dbg_link_msg(msg, txt) \
145 do { \
146 if (LINK_LOG_BUF_SIZE) \
147 tipc_msg_dbg(&l_ptr->print_buf, msg, txt); \
148 } while (0)
149#define dbg_link_state(txt) \
150 do { \
151 if (LINK_LOG_BUF_SIZE) \
152 link_print(l_ptr, &l_ptr->print_buf, txt); \
153 } while (0)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100154#define dbg_link_dump() do { \
155 if (LINK_LOG_BUF_SIZE) { \
156 tipc_printf(LOG, "\n\nDumping link <%s>:\n", l_ptr->name); \
Per Liden4323add2006-01-18 00:38:21 +0100157 tipc_printbuf_move(LOG, &l_ptr->print_buf); \
Per Lidenb97bf3f2006-01-02 19:04:38 +0100158 } \
159} while (0)
160
Sam Ravnborg05790c62006-03-20 22:37:04 -0800161static void dbg_print_link(struct link *l_ptr, const char *str)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100162{
Allan Stephensa3df92c2006-10-16 21:49:03 -0700163 if (DBG_OUTPUT != TIPC_NULL)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100164 link_print(l_ptr, DBG_OUTPUT, str);
165}
166
Sam Ravnborg05790c62006-03-20 22:37:04 -0800167static void dbg_print_buf_chain(struct sk_buff *root_buf)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100168{
Allan Stephensa3df92c2006-10-16 21:49:03 -0700169 if (DBG_OUTPUT != TIPC_NULL) {
Per Lidenb97bf3f2006-01-02 19:04:38 +0100170 struct sk_buff *buf = root_buf;
171
172 while (buf) {
173 msg_dbg(buf_msg(buf), "In chain: ");
174 buf = buf->next;
175 }
176 }
177}
178
179/*
Sam Ravnborg05790c62006-03-20 22:37:04 -0800180 * Simple link routines
Per Lidenb97bf3f2006-01-02 19:04:38 +0100181 */
182
Sam Ravnborg05790c62006-03-20 22:37:04 -0800183static unsigned int align(unsigned int i)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100184{
185 return (i + 3) & ~3u;
186}
187
Sam Ravnborg05790c62006-03-20 22:37:04 -0800188static void link_init_max_pkt(struct link *l_ptr)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100189{
190 u32 max_pkt;
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900191
Per Lidenb97bf3f2006-01-02 19:04:38 +0100192 max_pkt = (l_ptr->b_ptr->publ.mtu & ~3);
193 if (max_pkt > MAX_MSG_SIZE)
194 max_pkt = MAX_MSG_SIZE;
195
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900196 l_ptr->max_pkt_target = max_pkt;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100197 if (l_ptr->max_pkt_target < MAX_PKT_DEFAULT)
198 l_ptr->max_pkt = l_ptr->max_pkt_target;
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900199 else
Per Lidenb97bf3f2006-01-02 19:04:38 +0100200 l_ptr->max_pkt = MAX_PKT_DEFAULT;
201
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900202 l_ptr->max_pkt_probes = 0;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100203}
204
Sam Ravnborg05790c62006-03-20 22:37:04 -0800205static u32 link_next_sent(struct link *l_ptr)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100206{
207 if (l_ptr->next_out)
208 return msg_seqno(buf_msg(l_ptr->next_out));
209 return mod(l_ptr->next_out_no);
210}
211
Sam Ravnborg05790c62006-03-20 22:37:04 -0800212static u32 link_last_sent(struct link *l_ptr)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100213{
214 return mod(link_next_sent(l_ptr) - 1);
215}
216
217/*
Sam Ravnborg05790c62006-03-20 22:37:04 -0800218 * Simple non-static link routines (i.e. referenced outside this file)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100219 */
220
Per Liden4323add2006-01-18 00:38:21 +0100221int tipc_link_is_up(struct link *l_ptr)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100222{
223 if (!l_ptr)
224 return 0;
Eric Dumazeta02cec22010-09-22 20:43:57 +0000225 return link_working_working(l_ptr) || link_working_unknown(l_ptr);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100226}
227
Per Liden4323add2006-01-18 00:38:21 +0100228int tipc_link_is_active(struct link *l_ptr)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100229{
Eric Dumazeta02cec22010-09-22 20:43:57 +0000230 return (l_ptr->owner->active_links[0] == l_ptr) ||
231 (l_ptr->owner->active_links[1] == l_ptr);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100232}
233
234/**
235 * link_name_validate - validate & (optionally) deconstruct link name
236 * @name - ptr to link name string
237 * @name_parts - ptr to area for link name components (or NULL if not needed)
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900238 *
Per Lidenb97bf3f2006-01-02 19:04:38 +0100239 * Returns 1 if link name is valid, otherwise 0.
240 */
241
242static int link_name_validate(const char *name, struct link_name *name_parts)
243{
244 char name_copy[TIPC_MAX_LINK_NAME];
245 char *addr_local;
246 char *if_local;
247 char *addr_peer;
248 char *if_peer;
249 char dummy;
250 u32 z_local, c_local, n_local;
251 u32 z_peer, c_peer, n_peer;
252 u32 if_local_len;
253 u32 if_peer_len;
254
255 /* copy link name & ensure length is OK */
256
257 name_copy[TIPC_MAX_LINK_NAME - 1] = 0;
258 /* need above in case non-Posix strncpy() doesn't pad with nulls */
259 strncpy(name_copy, name, TIPC_MAX_LINK_NAME);
260 if (name_copy[TIPC_MAX_LINK_NAME - 1] != 0)
261 return 0;
262
263 /* ensure all component parts of link name are present */
264
265 addr_local = name_copy;
266 if ((if_local = strchr(addr_local, ':')) == NULL)
267 return 0;
268 *(if_local++) = 0;
269 if ((addr_peer = strchr(if_local, '-')) == NULL)
270 return 0;
271 *(addr_peer++) = 0;
272 if_local_len = addr_peer - if_local;
273 if ((if_peer = strchr(addr_peer, ':')) == NULL)
274 return 0;
275 *(if_peer++) = 0;
276 if_peer_len = strlen(if_peer) + 1;
277
278 /* validate component parts of link name */
279
280 if ((sscanf(addr_local, "%u.%u.%u%c",
281 &z_local, &c_local, &n_local, &dummy) != 3) ||
282 (sscanf(addr_peer, "%u.%u.%u%c",
283 &z_peer, &c_peer, &n_peer, &dummy) != 3) ||
284 (z_local > 255) || (c_local > 4095) || (n_local > 4095) ||
285 (z_peer > 255) || (c_peer > 4095) || (n_peer > 4095) ||
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900286 (if_local_len <= 1) || (if_local_len > TIPC_MAX_IF_NAME) ||
287 (if_peer_len <= 1) || (if_peer_len > TIPC_MAX_IF_NAME) ||
Per Lidenb97bf3f2006-01-02 19:04:38 +0100288 (strspn(if_local, tipc_alphabet) != (if_local_len - 1)) ||
289 (strspn(if_peer, tipc_alphabet) != (if_peer_len - 1)))
290 return 0;
291
292 /* return link name components, if necessary */
293
294 if (name_parts) {
295 name_parts->addr_local = tipc_addr(z_local, c_local, n_local);
296 strcpy(name_parts->if_local, if_local);
297 name_parts->addr_peer = tipc_addr(z_peer, c_peer, n_peer);
298 strcpy(name_parts->if_peer, if_peer);
299 }
300 return 1;
301}
302
303/**
304 * link_timeout - handle expiration of link timer
305 * @l_ptr: pointer to link
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900306 *
Per Liden4323add2006-01-18 00:38:21 +0100307 * This routine must not grab "tipc_net_lock" to avoid a potential deadlock conflict
308 * with tipc_link_delete(). (There is no risk that the node will be deleted by
309 * another thread because tipc_link_delete() always cancels the link timer before
310 * tipc_node_delete() is called.)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100311 */
312
313static void link_timeout(struct link *l_ptr)
314{
Per Liden4323add2006-01-18 00:38:21 +0100315 tipc_node_lock(l_ptr->owner);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100316
317 /* update counters used in statistical profiling of send traffic */
318
319 l_ptr->stats.accu_queue_sz += l_ptr->out_queue_size;
320 l_ptr->stats.queue_sz_counts++;
321
322 if (l_ptr->out_queue_size > l_ptr->stats.max_queue_sz)
323 l_ptr->stats.max_queue_sz = l_ptr->out_queue_size;
324
325 if (l_ptr->first_out) {
326 struct tipc_msg *msg = buf_msg(l_ptr->first_out);
327 u32 length = msg_size(msg);
328
Joe Perchesf64f9e72009-11-29 16:55:45 -0800329 if ((msg_user(msg) == MSG_FRAGMENTER) &&
330 (msg_type(msg) == FIRST_FRAGMENT)) {
Per Lidenb97bf3f2006-01-02 19:04:38 +0100331 length = msg_size(msg_get_wrapped(msg));
332 }
333 if (length) {
334 l_ptr->stats.msg_lengths_total += length;
335 l_ptr->stats.msg_length_counts++;
336 if (length <= 64)
337 l_ptr->stats.msg_length_profile[0]++;
338 else if (length <= 256)
339 l_ptr->stats.msg_length_profile[1]++;
340 else if (length <= 1024)
341 l_ptr->stats.msg_length_profile[2]++;
342 else if (length <= 4096)
343 l_ptr->stats.msg_length_profile[3]++;
344 else if (length <= 16384)
345 l_ptr->stats.msg_length_profile[4]++;
346 else if (length <= 32768)
347 l_ptr->stats.msg_length_profile[5]++;
348 else
349 l_ptr->stats.msg_length_profile[6]++;
350 }
351 }
352
353 /* do all other link processing performed on a periodic basis */
354
355 link_check_defragm_bufs(l_ptr);
356
357 link_state_event(l_ptr, TIMEOUT_EVT);
358
359 if (l_ptr->next_out)
Per Liden4323add2006-01-18 00:38:21 +0100360 tipc_link_push_queue(l_ptr);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100361
Per Liden4323add2006-01-18 00:38:21 +0100362 tipc_node_unlock(l_ptr->owner);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100363}
364
Sam Ravnborg05790c62006-03-20 22:37:04 -0800365static void link_set_timer(struct link *l_ptr, u32 time)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100366{
367 k_start_timer(&l_ptr->timer, time);
368}
369
370/**
Per Liden4323add2006-01-18 00:38:21 +0100371 * tipc_link_create - create a new link
Per Lidenb97bf3f2006-01-02 19:04:38 +0100372 * @b_ptr: pointer to associated bearer
373 * @peer: network address of node at other end of link
374 * @media_addr: media address to use when sending messages over link
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900375 *
Per Lidenb97bf3f2006-01-02 19:04:38 +0100376 * Returns pointer to link.
377 */
378
Per Liden4323add2006-01-18 00:38:21 +0100379struct link *tipc_link_create(struct bearer *b_ptr, const u32 peer,
380 const struct tipc_media_addr *media_addr)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100381{
382 struct link *l_ptr;
383 struct tipc_msg *msg;
384 char *if_name;
385
Panagiotis Issaris0da974f2006-07-21 14:51:30 -0700386 l_ptr = kzalloc(sizeof(*l_ptr), GFP_ATOMIC);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100387 if (!l_ptr) {
Allan Stephensa10bd922006-06-25 23:52:17 -0700388 warn("Link creation failed, no memory\n");
Per Lidenb97bf3f2006-01-02 19:04:38 +0100389 return NULL;
390 }
Per Lidenb97bf3f2006-01-02 19:04:38 +0100391
Florian Westphal945710652007-07-26 00:05:07 -0700392 if (LINK_LOG_BUF_SIZE) {
393 char *pb = kmalloc(LINK_LOG_BUF_SIZE, GFP_ATOMIC);
394
395 if (!pb) {
396 kfree(l_ptr);
397 warn("Link creation failed, no memory for print buffer\n");
398 return NULL;
399 }
400 tipc_printbuf_init(&l_ptr->print_buf, pb, LINK_LOG_BUF_SIZE);
401 }
402
Per Lidenb97bf3f2006-01-02 19:04:38 +0100403 l_ptr->addr = peer;
404 if_name = strchr(b_ptr->publ.name, ':') + 1;
405 sprintf(l_ptr->name, "%u.%u.%u:%s-%u.%u.%u:",
406 tipc_zone(tipc_own_addr), tipc_cluster(tipc_own_addr),
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900407 tipc_node(tipc_own_addr),
Per Lidenb97bf3f2006-01-02 19:04:38 +0100408 if_name,
409 tipc_zone(peer), tipc_cluster(peer), tipc_node(peer));
410 /* note: peer i/f is appended to link name by reset/activate */
411 memcpy(&l_ptr->media_addr, media_addr, sizeof(*media_addr));
Per Lidenb97bf3f2006-01-02 19:04:38 +0100412 l_ptr->checkpoint = 1;
413 l_ptr->b_ptr = b_ptr;
414 link_set_supervision_props(l_ptr, b_ptr->media->tolerance);
415 l_ptr->state = RESET_UNKNOWN;
416
417 l_ptr->pmsg = (struct tipc_msg *)&l_ptr->proto_msg;
418 msg = l_ptr->pmsg;
Allan Stephensc68ca7b2010-05-11 14:30:12 +0000419 tipc_msg_init(msg, LINK_PROTOCOL, RESET_MSG, INT_H_SIZE, l_ptr->addr);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100420 msg_set_size(msg, sizeof(l_ptr->proto_msg));
Allan Stephensa686e682008-06-04 17:29:39 -0700421 msg_set_session(msg, (tipc_random & 0xffff));
Per Lidenb97bf3f2006-01-02 19:04:38 +0100422 msg_set_bearer_id(msg, b_ptr->identity);
423 strcpy((char *)msg_data(msg), if_name);
424
425 l_ptr->priority = b_ptr->priority;
Per Liden4323add2006-01-18 00:38:21 +0100426 tipc_link_set_queue_limits(l_ptr, b_ptr->media->window);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100427
428 link_init_max_pkt(l_ptr);
429
430 l_ptr->next_out_no = 1;
431 INIT_LIST_HEAD(&l_ptr->waiting_ports);
432
433 link_reset_statistics(l_ptr);
434
Per Liden4323add2006-01-18 00:38:21 +0100435 l_ptr->owner = tipc_node_attach_link(l_ptr);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100436 if (!l_ptr->owner) {
Florian Westphal945710652007-07-26 00:05:07 -0700437 if (LINK_LOG_BUF_SIZE)
438 kfree(l_ptr->print_buf.buf);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100439 kfree(l_ptr);
440 return NULL;
441 }
442
Florian Westphal945710652007-07-26 00:05:07 -0700443 k_init_timer(&l_ptr->timer, (Handler)link_timeout, (unsigned long)l_ptr);
444 list_add_tail(&l_ptr->link_list, &b_ptr->links);
Per Liden4323add2006-01-18 00:38:21 +0100445 tipc_k_signal((Handler)tipc_link_start, (unsigned long)l_ptr);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100446
Per Liden4323add2006-01-18 00:38:21 +0100447 dbg("tipc_link_create(): tolerance = %u,cont intv = %u, abort_limit = %u\n",
Per Lidenb97bf3f2006-01-02 19:04:38 +0100448 l_ptr->tolerance, l_ptr->continuity_interval, l_ptr->abort_limit);
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900449
Per Lidenb97bf3f2006-01-02 19:04:38 +0100450 return l_ptr;
451}
452
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900453/**
Per Liden4323add2006-01-18 00:38:21 +0100454 * tipc_link_delete - delete a link
Per Lidenb97bf3f2006-01-02 19:04:38 +0100455 * @l_ptr: pointer to link
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900456 *
Per Liden4323add2006-01-18 00:38:21 +0100457 * Note: 'tipc_net_lock' is write_locked, bearer is locked.
Per Lidenb97bf3f2006-01-02 19:04:38 +0100458 * This routine must not grab the node lock until after link timer cancellation
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900459 * to avoid a potential deadlock situation.
Per Lidenb97bf3f2006-01-02 19:04:38 +0100460 */
461
Per Liden4323add2006-01-18 00:38:21 +0100462void tipc_link_delete(struct link *l_ptr)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100463{
464 if (!l_ptr) {
465 err("Attempt to delete non-existent link\n");
466 return;
467 }
468
Per Liden4323add2006-01-18 00:38:21 +0100469 dbg("tipc_link_delete()\n");
Per Lidenb97bf3f2006-01-02 19:04:38 +0100470
471 k_cancel_timer(&l_ptr->timer);
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900472
Per Liden4323add2006-01-18 00:38:21 +0100473 tipc_node_lock(l_ptr->owner);
474 tipc_link_reset(l_ptr);
475 tipc_node_detach_link(l_ptr->owner, l_ptr);
476 tipc_link_stop(l_ptr);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100477 list_del_init(&l_ptr->link_list);
478 if (LINK_LOG_BUF_SIZE)
479 kfree(l_ptr->print_buf.buf);
Per Liden4323add2006-01-18 00:38:21 +0100480 tipc_node_unlock(l_ptr->owner);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100481 k_term_timer(&l_ptr->timer);
482 kfree(l_ptr);
483}
484
Per Liden4323add2006-01-18 00:38:21 +0100485void tipc_link_start(struct link *l_ptr)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100486{
Per Liden4323add2006-01-18 00:38:21 +0100487 dbg("tipc_link_start %x\n", l_ptr);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100488 link_state_event(l_ptr, STARTING_EVT);
489}
490
491/**
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900492 * link_schedule_port - schedule port for deferred sending
Per Lidenb97bf3f2006-01-02 19:04:38 +0100493 * @l_ptr: pointer to link
494 * @origport: reference to sending port
495 * @sz: amount of data to be sent
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900496 *
497 * Schedules port for renewed sending of messages after link congestion
Per Lidenb97bf3f2006-01-02 19:04:38 +0100498 * has abated.
499 */
500
501static int link_schedule_port(struct link *l_ptr, u32 origport, u32 sz)
502{
503 struct port *p_ptr;
504
Per Liden4323add2006-01-18 00:38:21 +0100505 spin_lock_bh(&tipc_port_list_lock);
506 p_ptr = tipc_port_lock(origport);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100507 if (p_ptr) {
508 if (!p_ptr->wakeup)
509 goto exit;
510 if (!list_empty(&p_ptr->wait_list))
511 goto exit;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100512 p_ptr->publ.congested = 1;
Allan Stephens15e979d2010-05-11 14:30:10 +0000513 p_ptr->waiting_pkts = 1 + ((sz - 1) / l_ptr->max_pkt);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100514 list_add_tail(&p_ptr->wait_list, &l_ptr->waiting_ports);
515 l_ptr->stats.link_congs++;
516exit:
Per Liden4323add2006-01-18 00:38:21 +0100517 tipc_port_unlock(p_ptr);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100518 }
Per Liden4323add2006-01-18 00:38:21 +0100519 spin_unlock_bh(&tipc_port_list_lock);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100520 return -ELINKCONG;
521}
522
Per Liden4323add2006-01-18 00:38:21 +0100523void tipc_link_wakeup_ports(struct link *l_ptr, int all)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100524{
525 struct port *p_ptr;
526 struct port *temp_p_ptr;
527 int win = l_ptr->queue_limit[0] - l_ptr->out_queue_size;
528
529 if (all)
530 win = 100000;
531 if (win <= 0)
532 return;
Per Liden4323add2006-01-18 00:38:21 +0100533 if (!spin_trylock_bh(&tipc_port_list_lock))
Per Lidenb97bf3f2006-01-02 19:04:38 +0100534 return;
535 if (link_congested(l_ptr))
536 goto exit;
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900537 list_for_each_entry_safe(p_ptr, temp_p_ptr, &l_ptr->waiting_ports,
Per Lidenb97bf3f2006-01-02 19:04:38 +0100538 wait_list) {
539 if (win <= 0)
540 break;
541 list_del_init(&p_ptr->wait_list);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100542 spin_lock_bh(p_ptr->publ.lock);
543 p_ptr->publ.congested = 0;
544 p_ptr->wakeup(&p_ptr->publ);
545 win -= p_ptr->waiting_pkts;
546 spin_unlock_bh(p_ptr->publ.lock);
547 }
548
549exit:
Per Liden4323add2006-01-18 00:38:21 +0100550 spin_unlock_bh(&tipc_port_list_lock);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100551}
552
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900553/**
Per Lidenb97bf3f2006-01-02 19:04:38 +0100554 * link_release_outqueue - purge link's outbound message queue
555 * @l_ptr: pointer to link
556 */
557
558static void link_release_outqueue(struct link *l_ptr)
559{
560 struct sk_buff *buf = l_ptr->first_out;
561 struct sk_buff *next;
562
563 while (buf) {
564 next = buf->next;
565 buf_discard(buf);
566 buf = next;
567 }
568 l_ptr->first_out = NULL;
569 l_ptr->out_queue_size = 0;
570}
571
572/**
Per Liden4323add2006-01-18 00:38:21 +0100573 * tipc_link_reset_fragments - purge link's inbound message fragments queue
Per Lidenb97bf3f2006-01-02 19:04:38 +0100574 * @l_ptr: pointer to link
575 */
576
Per Liden4323add2006-01-18 00:38:21 +0100577void tipc_link_reset_fragments(struct link *l_ptr)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100578{
579 struct sk_buff *buf = l_ptr->defragm_buf;
580 struct sk_buff *next;
581
582 while (buf) {
583 next = buf->next;
584 buf_discard(buf);
585 buf = next;
586 }
587 l_ptr->defragm_buf = NULL;
588}
589
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900590/**
Per Liden4323add2006-01-18 00:38:21 +0100591 * tipc_link_stop - purge all inbound and outbound messages associated with link
Per Lidenb97bf3f2006-01-02 19:04:38 +0100592 * @l_ptr: pointer to link
593 */
594
Per Liden4323add2006-01-18 00:38:21 +0100595void tipc_link_stop(struct link *l_ptr)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100596{
597 struct sk_buff *buf;
598 struct sk_buff *next;
599
600 buf = l_ptr->oldest_deferred_in;
601 while (buf) {
602 next = buf->next;
603 buf_discard(buf);
604 buf = next;
605 }
606
607 buf = l_ptr->first_out;
608 while (buf) {
609 next = buf->next;
610 buf_discard(buf);
611 buf = next;
612 }
613
Per Liden4323add2006-01-18 00:38:21 +0100614 tipc_link_reset_fragments(l_ptr);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100615
616 buf_discard(l_ptr->proto_msg_queue);
617 l_ptr->proto_msg_queue = NULL;
618}
619
Per Lidenb97bf3f2006-01-02 19:04:38 +0100620/* LINK EVENT CODE IS NOT SUPPORTED AT PRESENT */
Per Lidenb97bf3f2006-01-02 19:04:38 +0100621#define link_send_event(fcn, l_ptr, up) do { } while (0)
622
Per Liden4323add2006-01-18 00:38:21 +0100623void tipc_link_reset(struct link *l_ptr)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100624{
625 struct sk_buff *buf;
626 u32 prev_state = l_ptr->state;
627 u32 checkpoint = l_ptr->next_in_no;
Allan Stephens5392d642006-06-25 23:52:50 -0700628 int was_active_link = tipc_link_is_active(l_ptr);
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900629
Allan Stephensa686e682008-06-04 17:29:39 -0700630 msg_set_session(l_ptr->pmsg, ((msg_session(l_ptr->pmsg) + 1) & 0xffff));
Per Lidenb97bf3f2006-01-02 19:04:38 +0100631
Allan Stephensa686e682008-06-04 17:29:39 -0700632 /* Link is down, accept any session */
633 l_ptr->peer_session = INVALID_SESSION;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100634
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900635 /* Prepare for max packet size negotiation */
Per Lidenb97bf3f2006-01-02 19:04:38 +0100636 link_init_max_pkt(l_ptr);
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900637
Per Lidenb97bf3f2006-01-02 19:04:38 +0100638 l_ptr->state = RESET_UNKNOWN;
639 dbg_link_state("Resetting Link\n");
640
641 if ((prev_state == RESET_UNKNOWN) || (prev_state == RESET_RESET))
642 return;
643
Per Liden4323add2006-01-18 00:38:21 +0100644 tipc_node_link_down(l_ptr->owner, l_ptr);
645 tipc_bearer_remove_dest(l_ptr->b_ptr, l_ptr->addr);
Paul Gortmaker7368ddf2010-10-12 14:25:58 +0000646
Allan Stephens5392d642006-06-25 23:52:50 -0700647 if (was_active_link && tipc_node_has_active_links(l_ptr->owner) &&
Per Lidenb97bf3f2006-01-02 19:04:38 +0100648 l_ptr->owner->permit_changeover) {
649 l_ptr->reset_checkpoint = checkpoint;
650 l_ptr->exp_msg_count = START_CHANGEOVER;
651 }
652
653 /* Clean up all queues: */
654
655 link_release_outqueue(l_ptr);
656 buf_discard(l_ptr->proto_msg_queue);
657 l_ptr->proto_msg_queue = NULL;
658 buf = l_ptr->oldest_deferred_in;
659 while (buf) {
660 struct sk_buff *next = buf->next;
661 buf_discard(buf);
662 buf = next;
663 }
664 if (!list_empty(&l_ptr->waiting_ports))
Per Liden4323add2006-01-18 00:38:21 +0100665 tipc_link_wakeup_ports(l_ptr, 1);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100666
667 l_ptr->retransm_queue_head = 0;
668 l_ptr->retransm_queue_size = 0;
669 l_ptr->last_out = NULL;
670 l_ptr->first_out = NULL;
671 l_ptr->next_out = NULL;
672 l_ptr->unacked_window = 0;
673 l_ptr->checkpoint = 1;
674 l_ptr->next_out_no = 1;
675 l_ptr->deferred_inqueue_sz = 0;
676 l_ptr->oldest_deferred_in = NULL;
677 l_ptr->newest_deferred_in = NULL;
678 l_ptr->fsm_msg_cnt = 0;
679 l_ptr->stale_count = 0;
680 link_reset_statistics(l_ptr);
681
Per Liden4323add2006-01-18 00:38:21 +0100682 link_send_event(tipc_cfg_link_event, l_ptr, 0);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100683 if (!in_own_cluster(l_ptr->addr))
Per Liden4323add2006-01-18 00:38:21 +0100684 link_send_event(tipc_disc_link_event, l_ptr, 0);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100685}
686
687
688static void link_activate(struct link *l_ptr)
689{
Allan Stephens5392d642006-06-25 23:52:50 -0700690 l_ptr->next_in_no = l_ptr->stats.recv_info = 1;
Per Liden4323add2006-01-18 00:38:21 +0100691 tipc_node_link_up(l_ptr->owner, l_ptr);
692 tipc_bearer_add_dest(l_ptr->b_ptr, l_ptr->addr);
693 link_send_event(tipc_cfg_link_event, l_ptr, 1);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100694 if (!in_own_cluster(l_ptr->addr))
Per Liden4323add2006-01-18 00:38:21 +0100695 link_send_event(tipc_disc_link_event, l_ptr, 1);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100696}
697
698/**
699 * link_state_event - link finite state machine
700 * @l_ptr: pointer to link
701 * @event: state machine event to process
702 */
703
704static void link_state_event(struct link *l_ptr, unsigned event)
705{
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900706 struct link *other;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100707 u32 cont_intv = l_ptr->continuity_interval;
708
709 if (!l_ptr->started && (event != STARTING_EVT))
710 return; /* Not yet. */
711
712 if (link_blocked(l_ptr)) {
713 if (event == TIMEOUT_EVT) {
714 link_set_timer(l_ptr, cont_intv);
715 }
716 return; /* Changeover going on */
717 }
718 dbg_link("STATE_EV: <%s> ", l_ptr->name);
719
720 switch (l_ptr->state) {
721 case WORKING_WORKING:
722 dbg_link("WW/");
723 switch (event) {
724 case TRAFFIC_MSG_EVT:
725 dbg_link("TRF-");
726 /* fall through */
727 case ACTIVATE_MSG:
728 dbg_link("ACT\n");
729 break;
730 case TIMEOUT_EVT:
731 dbg_link("TIM ");
732 if (l_ptr->next_in_no != l_ptr->checkpoint) {
733 l_ptr->checkpoint = l_ptr->next_in_no;
Per Liden4323add2006-01-18 00:38:21 +0100734 if (tipc_bclink_acks_missing(l_ptr->owner)) {
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900735 tipc_link_send_proto_msg(l_ptr, STATE_MSG,
Per Liden4323add2006-01-18 00:38:21 +0100736 0, 0, 0, 0, 0);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100737 l_ptr->fsm_msg_cnt++;
738 } else if (l_ptr->max_pkt < l_ptr->max_pkt_target) {
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900739 tipc_link_send_proto_msg(l_ptr, STATE_MSG,
Per Liden4323add2006-01-18 00:38:21 +0100740 1, 0, 0, 0, 0);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100741 l_ptr->fsm_msg_cnt++;
742 }
743 link_set_timer(l_ptr, cont_intv);
744 break;
745 }
746 dbg_link(" -> WU\n");
747 l_ptr->state = WORKING_UNKNOWN;
748 l_ptr->fsm_msg_cnt = 0;
Per Liden4323add2006-01-18 00:38:21 +0100749 tipc_link_send_proto_msg(l_ptr, STATE_MSG, 1, 0, 0, 0, 0);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100750 l_ptr->fsm_msg_cnt++;
751 link_set_timer(l_ptr, cont_intv / 4);
752 break;
753 case RESET_MSG:
754 dbg_link("RES -> RR\n");
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900755 info("Resetting link <%s>, requested by peer\n",
Allan Stephensa10bd922006-06-25 23:52:17 -0700756 l_ptr->name);
Per Liden4323add2006-01-18 00:38:21 +0100757 tipc_link_reset(l_ptr);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100758 l_ptr->state = RESET_RESET;
759 l_ptr->fsm_msg_cnt = 0;
Per Liden4323add2006-01-18 00:38:21 +0100760 tipc_link_send_proto_msg(l_ptr, ACTIVATE_MSG, 0, 0, 0, 0, 0);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100761 l_ptr->fsm_msg_cnt++;
762 link_set_timer(l_ptr, cont_intv);
763 break;
764 default:
765 err("Unknown link event %u in WW state\n", event);
766 }
767 break;
768 case WORKING_UNKNOWN:
769 dbg_link("WU/");
770 switch (event) {
771 case TRAFFIC_MSG_EVT:
772 dbg_link("TRF-");
773 case ACTIVATE_MSG:
774 dbg_link("ACT -> WW\n");
775 l_ptr->state = WORKING_WORKING;
776 l_ptr->fsm_msg_cnt = 0;
777 link_set_timer(l_ptr, cont_intv);
778 break;
779 case RESET_MSG:
780 dbg_link("RES -> RR\n");
Allan Stephensa10bd922006-06-25 23:52:17 -0700781 info("Resetting link <%s>, requested by peer "
782 "while probing\n", l_ptr->name);
Per Liden4323add2006-01-18 00:38:21 +0100783 tipc_link_reset(l_ptr);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100784 l_ptr->state = RESET_RESET;
785 l_ptr->fsm_msg_cnt = 0;
Per Liden4323add2006-01-18 00:38:21 +0100786 tipc_link_send_proto_msg(l_ptr, ACTIVATE_MSG, 0, 0, 0, 0, 0);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100787 l_ptr->fsm_msg_cnt++;
788 link_set_timer(l_ptr, cont_intv);
789 break;
790 case TIMEOUT_EVT:
791 dbg_link("TIM ");
792 if (l_ptr->next_in_no != l_ptr->checkpoint) {
Frans Popa570f092010-03-24 07:57:29 +0000793 dbg_link("-> WW\n");
Per Lidenb97bf3f2006-01-02 19:04:38 +0100794 l_ptr->state = WORKING_WORKING;
795 l_ptr->fsm_msg_cnt = 0;
796 l_ptr->checkpoint = l_ptr->next_in_no;
Per Liden4323add2006-01-18 00:38:21 +0100797 if (tipc_bclink_acks_missing(l_ptr->owner)) {
798 tipc_link_send_proto_msg(l_ptr, STATE_MSG,
799 0, 0, 0, 0, 0);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100800 l_ptr->fsm_msg_cnt++;
801 }
802 link_set_timer(l_ptr, cont_intv);
803 } else if (l_ptr->fsm_msg_cnt < l_ptr->abort_limit) {
804 dbg_link("Probing %u/%u,timer = %u ms)\n",
805 l_ptr->fsm_msg_cnt, l_ptr->abort_limit,
806 cont_intv / 4);
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900807 tipc_link_send_proto_msg(l_ptr, STATE_MSG,
Per Liden4323add2006-01-18 00:38:21 +0100808 1, 0, 0, 0, 0);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100809 l_ptr->fsm_msg_cnt++;
810 link_set_timer(l_ptr, cont_intv / 4);
811 } else { /* Link has failed */
812 dbg_link("-> RU (%u probes unanswered)\n",
813 l_ptr->fsm_msg_cnt);
Allan Stephensa10bd922006-06-25 23:52:17 -0700814 warn("Resetting link <%s>, peer not responding\n",
815 l_ptr->name);
Per Liden4323add2006-01-18 00:38:21 +0100816 tipc_link_reset(l_ptr);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100817 l_ptr->state = RESET_UNKNOWN;
818 l_ptr->fsm_msg_cnt = 0;
Per Liden4323add2006-01-18 00:38:21 +0100819 tipc_link_send_proto_msg(l_ptr, RESET_MSG,
820 0, 0, 0, 0, 0);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100821 l_ptr->fsm_msg_cnt++;
822 link_set_timer(l_ptr, cont_intv);
823 }
824 break;
825 default:
826 err("Unknown link event %u in WU state\n", event);
827 }
828 break;
829 case RESET_UNKNOWN:
830 dbg_link("RU/");
831 switch (event) {
832 case TRAFFIC_MSG_EVT:
833 dbg_link("TRF-\n");
834 break;
835 case ACTIVATE_MSG:
836 other = l_ptr->owner->active_links[0];
837 if (other && link_working_unknown(other)) {
838 dbg_link("ACT\n");
839 break;
840 }
841 dbg_link("ACT -> WW\n");
842 l_ptr->state = WORKING_WORKING;
843 l_ptr->fsm_msg_cnt = 0;
844 link_activate(l_ptr);
Per Liden4323add2006-01-18 00:38:21 +0100845 tipc_link_send_proto_msg(l_ptr, STATE_MSG, 1, 0, 0, 0, 0);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100846 l_ptr->fsm_msg_cnt++;
847 link_set_timer(l_ptr, cont_intv);
848 break;
849 case RESET_MSG:
Frans Popa570f092010-03-24 07:57:29 +0000850 dbg_link("RES\n");
Per Lidenb97bf3f2006-01-02 19:04:38 +0100851 dbg_link(" -> RR\n");
852 l_ptr->state = RESET_RESET;
853 l_ptr->fsm_msg_cnt = 0;
Per Liden4323add2006-01-18 00:38:21 +0100854 tipc_link_send_proto_msg(l_ptr, ACTIVATE_MSG, 1, 0, 0, 0, 0);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100855 l_ptr->fsm_msg_cnt++;
856 link_set_timer(l_ptr, cont_intv);
857 break;
858 case STARTING_EVT:
859 dbg_link("START-");
860 l_ptr->started = 1;
861 /* fall through */
862 case TIMEOUT_EVT:
Frans Popa570f092010-03-24 07:57:29 +0000863 dbg_link("TIM\n");
Per Liden4323add2006-01-18 00:38:21 +0100864 tipc_link_send_proto_msg(l_ptr, RESET_MSG, 0, 0, 0, 0, 0);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100865 l_ptr->fsm_msg_cnt++;
866 link_set_timer(l_ptr, cont_intv);
867 break;
868 default:
869 err("Unknown link event %u in RU state\n", event);
870 }
871 break;
872 case RESET_RESET:
873 dbg_link("RR/ ");
874 switch (event) {
875 case TRAFFIC_MSG_EVT:
876 dbg_link("TRF-");
877 /* fall through */
878 case ACTIVATE_MSG:
879 other = l_ptr->owner->active_links[0];
880 if (other && link_working_unknown(other)) {
881 dbg_link("ACT\n");
882 break;
883 }
884 dbg_link("ACT -> WW\n");
885 l_ptr->state = WORKING_WORKING;
886 l_ptr->fsm_msg_cnt = 0;
887 link_activate(l_ptr);
Per Liden4323add2006-01-18 00:38:21 +0100888 tipc_link_send_proto_msg(l_ptr, STATE_MSG, 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);
891 break;
892 case RESET_MSG:
893 dbg_link("RES\n");
894 break;
895 case TIMEOUT_EVT:
896 dbg_link("TIM\n");
Per Liden4323add2006-01-18 00:38:21 +0100897 tipc_link_send_proto_msg(l_ptr, ACTIVATE_MSG, 0, 0, 0, 0, 0);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100898 l_ptr->fsm_msg_cnt++;
899 link_set_timer(l_ptr, cont_intv);
900 dbg_link("fsm_msg_cnt %u\n", l_ptr->fsm_msg_cnt);
901 break;
902 default:
903 err("Unknown link event %u in RR state\n", event);
904 }
905 break;
906 default:
907 err("Unknown link state %u/%u\n", l_ptr->state, event);
908 }
909}
910
911/*
912 * link_bundle_buf(): Append contents of a buffer to
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900913 * the tail of an existing one.
Per Lidenb97bf3f2006-01-02 19:04:38 +0100914 */
915
916static int link_bundle_buf(struct link *l_ptr,
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900917 struct sk_buff *bundler,
Per Lidenb97bf3f2006-01-02 19:04:38 +0100918 struct sk_buff *buf)
919{
920 struct tipc_msg *bundler_msg = buf_msg(bundler);
921 struct tipc_msg *msg = buf_msg(buf);
922 u32 size = msg_size(msg);
Allan Stephense49060c2006-06-29 12:32:46 -0700923 u32 bundle_size = msg_size(bundler_msg);
924 u32 to_pos = align(bundle_size);
925 u32 pad = to_pos - bundle_size;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100926
927 if (msg_user(bundler_msg) != MSG_BUNDLER)
928 return 0;
929 if (msg_type(bundler_msg) != OPEN_MSG)
930 return 0;
Allan Stephense49060c2006-06-29 12:32:46 -0700931 if (skb_tailroom(bundler) < (pad + size))
Per Lidenb97bf3f2006-01-02 19:04:38 +0100932 return 0;
Allan Stephens15e979d2010-05-11 14:30:10 +0000933 if (l_ptr->max_pkt < (to_pos + size))
Allan Stephens863fae62006-07-03 19:39:36 -0700934 return 0;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100935
Allan Stephense49060c2006-06-29 12:32:46 -0700936 skb_put(bundler, pad + size);
Arnaldo Carvalho de Melo27d7ff42007-03-31 11:55:19 -0300937 skb_copy_to_linear_data_offset(bundler, to_pos, buf->data, size);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100938 msg_set_size(bundler_msg, to_pos + size);
939 msg_set_msgcnt(bundler_msg, msg_msgcnt(bundler_msg) + 1);
940 dbg("Packed msg # %u(%u octets) into pos %u in buf(#%u)\n",
941 msg_msgcnt(bundler_msg), size, to_pos, msg_seqno(bundler_msg));
942 msg_dbg(msg, "PACKD:");
943 buf_discard(buf);
944 l_ptr->stats.sent_bundled++;
945 return 1;
946}
947
Sam Ravnborg05790c62006-03-20 22:37:04 -0800948static void link_add_to_outqueue(struct link *l_ptr,
949 struct sk_buff *buf,
950 struct tipc_msg *msg)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100951{
952 u32 ack = mod(l_ptr->next_in_no - 1);
953 u32 seqno = mod(l_ptr->next_out_no++);
954
955 msg_set_word(msg, 2, ((ack << 16) | seqno));
956 msg_set_bcast_ack(msg, l_ptr->owner->bclink.last_in);
957 buf->next = NULL;
958 if (l_ptr->first_out) {
959 l_ptr->last_out->next = buf;
960 l_ptr->last_out = buf;
961 } else
962 l_ptr->first_out = l_ptr->last_out = buf;
963 l_ptr->out_queue_size++;
964}
965
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900966/*
967 * tipc_link_send_buf() is the 'full path' for messages, called from
Per Lidenb97bf3f2006-01-02 19:04:38 +0100968 * inside TIPC when the 'fast path' in tipc_send_buf
969 * has failed, and from link_send()
970 */
971
Per Liden4323add2006-01-18 00:38:21 +0100972int tipc_link_send_buf(struct link *l_ptr, struct sk_buff *buf)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100973{
974 struct tipc_msg *msg = buf_msg(buf);
975 u32 size = msg_size(msg);
976 u32 dsz = msg_data_sz(msg);
977 u32 queue_size = l_ptr->out_queue_size;
Allan Stephensc68ca7b2010-05-11 14:30:12 +0000978 u32 imp = tipc_msg_tot_importance(msg);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100979 u32 queue_limit = l_ptr->queue_limit[imp];
Allan Stephens15e979d2010-05-11 14:30:10 +0000980 u32 max_packet = l_ptr->max_pkt;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100981
982 msg_set_prevnode(msg, tipc_own_addr); /* If routed message */
983
984 /* Match msg importance against queue limits: */
985
986 if (unlikely(queue_size >= queue_limit)) {
987 if (imp <= TIPC_CRITICAL_IMPORTANCE) {
988 return link_schedule_port(l_ptr, msg_origport(msg),
989 size);
990 }
991 msg_dbg(msg, "TIPC: Congestion, throwing away\n");
992 buf_discard(buf);
993 if (imp > CONN_MANAGER) {
Allan Stephensa10bd922006-06-25 23:52:17 -0700994 warn("Resetting link <%s>, send queue full", l_ptr->name);
Per Liden4323add2006-01-18 00:38:21 +0100995 tipc_link_reset(l_ptr);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100996 }
997 return dsz;
998 }
999
1000 /* Fragmentation needed ? */
1001
1002 if (size > max_packet)
Per Liden4323add2006-01-18 00:38:21 +01001003 return tipc_link_send_long_buf(l_ptr, buf);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001004
1005 /* Packet can be queued or sent: */
1006
1007 if (queue_size > l_ptr->stats.max_queue_sz)
1008 l_ptr->stats.max_queue_sz = queue_size;
1009
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001010 if (likely(!tipc_bearer_congested(l_ptr->b_ptr, l_ptr) &&
Per Lidenb97bf3f2006-01-02 19:04:38 +01001011 !link_congested(l_ptr))) {
1012 link_add_to_outqueue(l_ptr, buf, msg);
1013
Per Liden4323add2006-01-18 00:38:21 +01001014 if (likely(tipc_bearer_send(l_ptr->b_ptr, buf, &l_ptr->media_addr))) {
Per Lidenb97bf3f2006-01-02 19:04:38 +01001015 l_ptr->unacked_window = 0;
1016 } else {
Per Liden4323add2006-01-18 00:38:21 +01001017 tipc_bearer_schedule(l_ptr->b_ptr, l_ptr);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001018 l_ptr->stats.bearer_congs++;
1019 l_ptr->next_out = buf;
1020 }
1021 return dsz;
1022 }
1023 /* Congestion: can message be bundled ?: */
1024
1025 if ((msg_user(msg) != CHANGEOVER_PROTOCOL) &&
1026 (msg_user(msg) != MSG_FRAGMENTER)) {
1027
1028 /* Try adding message to an existing bundle */
1029
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001030 if (l_ptr->next_out &&
Per Lidenb97bf3f2006-01-02 19:04:38 +01001031 link_bundle_buf(l_ptr, l_ptr->last_out, buf)) {
Per Liden4323add2006-01-18 00:38:21 +01001032 tipc_bearer_resolve_congestion(l_ptr->b_ptr, l_ptr);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001033 return dsz;
1034 }
1035
1036 /* Try creating a new bundle */
1037
1038 if (size <= max_packet * 2 / 3) {
1039 struct sk_buff *bundler = buf_acquire(max_packet);
1040 struct tipc_msg bundler_hdr;
1041
1042 if (bundler) {
Allan Stephensc68ca7b2010-05-11 14:30:12 +00001043 tipc_msg_init(&bundler_hdr, MSG_BUNDLER, OPEN_MSG,
Allan Stephens75715212008-06-04 17:37:34 -07001044 INT_H_SIZE, l_ptr->addr);
Arnaldo Carvalho de Melo27d7ff42007-03-31 11:55:19 -03001045 skb_copy_to_linear_data(bundler, &bundler_hdr,
1046 INT_H_SIZE);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001047 skb_trim(bundler, INT_H_SIZE);
1048 link_bundle_buf(l_ptr, bundler, buf);
1049 buf = bundler;
1050 msg = buf_msg(buf);
1051 l_ptr->stats.sent_bundles++;
1052 }
1053 }
1054 }
1055 if (!l_ptr->next_out)
1056 l_ptr->next_out = buf;
1057 link_add_to_outqueue(l_ptr, buf, msg);
Per Liden4323add2006-01-18 00:38:21 +01001058 tipc_bearer_resolve_congestion(l_ptr->b_ptr, l_ptr);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001059 return dsz;
1060}
1061
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001062/*
1063 * tipc_link_send(): same as tipc_link_send_buf(), but the link to use has
Per Lidenb97bf3f2006-01-02 19:04:38 +01001064 * not been selected yet, and the the owner node is not locked
1065 * Called by TIPC internal users, e.g. the name distributor
1066 */
1067
Per Liden4323add2006-01-18 00:38:21 +01001068int tipc_link_send(struct sk_buff *buf, u32 dest, u32 selector)
Per Lidenb97bf3f2006-01-02 19:04:38 +01001069{
1070 struct link *l_ptr;
David S. Miller6c000552008-09-02 23:38:32 -07001071 struct tipc_node *n_ptr;
Per Lidenb97bf3f2006-01-02 19:04:38 +01001072 int res = -ELINKCONG;
1073
Per Liden4323add2006-01-18 00:38:21 +01001074 read_lock_bh(&tipc_net_lock);
1075 n_ptr = tipc_node_select(dest, selector);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001076 if (n_ptr) {
Per Liden4323add2006-01-18 00:38:21 +01001077 tipc_node_lock(n_ptr);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001078 l_ptr = n_ptr->active_links[selector & 1];
Per Lidenb97bf3f2006-01-02 19:04:38 +01001079 if (l_ptr) {
Allan Stephensc33d53b2006-06-25 23:50:30 -07001080 dbg("tipc_link_send: found link %x for dest %x\n", l_ptr, dest);
Per Liden4323add2006-01-18 00:38:21 +01001081 res = tipc_link_send_buf(l_ptr, buf);
Allan Stephensc33d53b2006-06-25 23:50:30 -07001082 } else {
1083 dbg("Attempt to send msg to unreachable node:\n");
1084 msg_dbg(buf_msg(buf),">>>");
1085 buf_discard(buf);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001086 }
Per Liden4323add2006-01-18 00:38:21 +01001087 tipc_node_unlock(n_ptr);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001088 } else {
1089 dbg("Attempt to send msg to unknown node:\n");
1090 msg_dbg(buf_msg(buf),">>>");
1091 buf_discard(buf);
1092 }
Per Liden4323add2006-01-18 00:38:21 +01001093 read_unlock_bh(&tipc_net_lock);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001094 return res;
1095}
1096
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001097/*
1098 * link_send_buf_fast: Entry for data messages where the
Per Lidenb97bf3f2006-01-02 19:04:38 +01001099 * destination link is known and the header is complete,
1100 * inclusive total message length. Very time critical.
1101 * Link is locked. Returns user data length.
1102 */
1103
Sam Ravnborg05790c62006-03-20 22:37:04 -08001104static int link_send_buf_fast(struct link *l_ptr, struct sk_buff *buf,
1105 u32 *used_max_pkt)
Per Lidenb97bf3f2006-01-02 19:04:38 +01001106{
1107 struct tipc_msg *msg = buf_msg(buf);
1108 int res = msg_data_sz(msg);
1109
1110 if (likely(!link_congested(l_ptr))) {
Allan Stephens15e979d2010-05-11 14:30:10 +00001111 if (likely(msg_size(msg) <= l_ptr->max_pkt)) {
Per Lidenb97bf3f2006-01-02 19:04:38 +01001112 if (likely(list_empty(&l_ptr->b_ptr->cong_links))) {
1113 link_add_to_outqueue(l_ptr, buf, msg);
Per Liden4323add2006-01-18 00:38:21 +01001114 if (likely(tipc_bearer_send(l_ptr->b_ptr, buf,
1115 &l_ptr->media_addr))) {
Per Lidenb97bf3f2006-01-02 19:04:38 +01001116 l_ptr->unacked_window = 0;
1117 msg_dbg(msg,"SENT_FAST:");
1118 return res;
1119 }
1120 dbg("failed sent fast...\n");
Per Liden4323add2006-01-18 00:38:21 +01001121 tipc_bearer_schedule(l_ptr->b_ptr, l_ptr);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001122 l_ptr->stats.bearer_congs++;
1123 l_ptr->next_out = buf;
1124 return res;
1125 }
1126 }
1127 else
Allan Stephens15e979d2010-05-11 14:30:10 +00001128 *used_max_pkt = l_ptr->max_pkt;
Per Lidenb97bf3f2006-01-02 19:04:38 +01001129 }
Per Liden4323add2006-01-18 00:38:21 +01001130 return tipc_link_send_buf(l_ptr, buf); /* All other cases */
Per Lidenb97bf3f2006-01-02 19:04:38 +01001131}
1132
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001133/*
1134 * tipc_send_buf_fast: Entry for data messages where the
Per Lidenb97bf3f2006-01-02 19:04:38 +01001135 * destination node is known and the header is complete,
1136 * inclusive total message length.
1137 * Returns user data length.
1138 */
1139int tipc_send_buf_fast(struct sk_buff *buf, u32 destnode)
1140{
1141 struct link *l_ptr;
David S. Miller6c000552008-09-02 23:38:32 -07001142 struct tipc_node *n_ptr;
Per Lidenb97bf3f2006-01-02 19:04:38 +01001143 int res;
1144 u32 selector = msg_origport(buf_msg(buf)) & 1;
1145 u32 dummy;
1146
1147 if (destnode == tipc_own_addr)
Per Liden4323add2006-01-18 00:38:21 +01001148 return tipc_port_recv_msg(buf);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001149
Per Liden4323add2006-01-18 00:38:21 +01001150 read_lock_bh(&tipc_net_lock);
1151 n_ptr = tipc_node_select(destnode, selector);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001152 if (likely(n_ptr)) {
Per Liden4323add2006-01-18 00:38:21 +01001153 tipc_node_lock(n_ptr);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001154 l_ptr = n_ptr->active_links[selector];
1155 dbg("send_fast: buf %x selected %x, destnode = %x\n",
1156 buf, l_ptr, destnode);
1157 if (likely(l_ptr)) {
1158 res = link_send_buf_fast(l_ptr, buf, &dummy);
Per Liden4323add2006-01-18 00:38:21 +01001159 tipc_node_unlock(n_ptr);
1160 read_unlock_bh(&tipc_net_lock);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001161 return res;
1162 }
Per Liden4323add2006-01-18 00:38:21 +01001163 tipc_node_unlock(n_ptr);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001164 }
Per Liden4323add2006-01-18 00:38:21 +01001165 read_unlock_bh(&tipc_net_lock);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001166 res = msg_data_sz(buf_msg(buf));
1167 tipc_reject_msg(buf, TIPC_ERR_NO_NODE);
1168 return res;
1169}
1170
1171
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001172/*
1173 * tipc_link_send_sections_fast: Entry for messages where the
Per Lidenb97bf3f2006-01-02 19:04:38 +01001174 * destination processor is known and the header is complete,
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001175 * except for total message length.
Per Lidenb97bf3f2006-01-02 19:04:38 +01001176 * Returns user data length or errno.
1177 */
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001178int tipc_link_send_sections_fast(struct port *sender,
Per Liden4323add2006-01-18 00:38:21 +01001179 struct iovec const *msg_sect,
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001180 const u32 num_sect,
Per Liden4323add2006-01-18 00:38:21 +01001181 u32 destaddr)
Per Lidenb97bf3f2006-01-02 19:04:38 +01001182{
1183 struct tipc_msg *hdr = &sender->publ.phdr;
1184 struct link *l_ptr;
1185 struct sk_buff *buf;
David S. Miller6c000552008-09-02 23:38:32 -07001186 struct tipc_node *node;
Per Lidenb97bf3f2006-01-02 19:04:38 +01001187 int res;
1188 u32 selector = msg_origport(hdr) & 1;
1189
Per Lidenb97bf3f2006-01-02 19:04:38 +01001190again:
1191 /*
1192 * Try building message using port's max_pkt hint.
1193 * (Must not hold any locks while building message.)
1194 */
1195
Allan Stephensc68ca7b2010-05-11 14:30:12 +00001196 res = tipc_msg_build(hdr, msg_sect, num_sect, sender->publ.max_pkt,
Per Lidenb97bf3f2006-01-02 19:04:38 +01001197 !sender->user_port, &buf);
1198
Per Liden4323add2006-01-18 00:38:21 +01001199 read_lock_bh(&tipc_net_lock);
1200 node = tipc_node_select(destaddr, selector);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001201 if (likely(node)) {
Per Liden4323add2006-01-18 00:38:21 +01001202 tipc_node_lock(node);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001203 l_ptr = node->active_links[selector];
1204 if (likely(l_ptr)) {
1205 if (likely(buf)) {
1206 res = link_send_buf_fast(l_ptr, buf,
Allan Stephens05646c92007-06-10 17:25:24 -07001207 &sender->publ.max_pkt);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001208 if (unlikely(res < 0))
1209 buf_discard(buf);
1210exit:
Per Liden4323add2006-01-18 00:38:21 +01001211 tipc_node_unlock(node);
1212 read_unlock_bh(&tipc_net_lock);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001213 return res;
1214 }
1215
1216 /* Exit if build request was invalid */
1217
1218 if (unlikely(res < 0))
1219 goto exit;
1220
1221 /* Exit if link (or bearer) is congested */
1222
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001223 if (link_congested(l_ptr) ||
Per Lidenb97bf3f2006-01-02 19:04:38 +01001224 !list_empty(&l_ptr->b_ptr->cong_links)) {
1225 res = link_schedule_port(l_ptr,
1226 sender->publ.ref, res);
1227 goto exit;
1228 }
1229
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001230 /*
Per Lidenb97bf3f2006-01-02 19:04:38 +01001231 * Message size exceeds max_pkt hint; update hint,
1232 * then re-try fast path or fragment the message
1233 */
1234
Allan Stephens15e979d2010-05-11 14:30:10 +00001235 sender->publ.max_pkt = l_ptr->max_pkt;
Per Liden4323add2006-01-18 00:38:21 +01001236 tipc_node_unlock(node);
1237 read_unlock_bh(&tipc_net_lock);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001238
1239
Allan Stephens05646c92007-06-10 17:25:24 -07001240 if ((msg_hdr_sz(hdr) + res) <= sender->publ.max_pkt)
Per Lidenb97bf3f2006-01-02 19:04:38 +01001241 goto again;
1242
1243 return link_send_sections_long(sender, msg_sect,
1244 num_sect, destaddr);
1245 }
Per Liden4323add2006-01-18 00:38:21 +01001246 tipc_node_unlock(node);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001247 }
Per Liden4323add2006-01-18 00:38:21 +01001248 read_unlock_bh(&tipc_net_lock);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001249
1250 /* Couldn't find a link to the destination node */
1251
1252 if (buf)
1253 return tipc_reject_msg(buf, TIPC_ERR_NO_NODE);
1254 if (res >= 0)
Per Liden4323add2006-01-18 00:38:21 +01001255 return tipc_port_reject_sections(sender, hdr, msg_sect, num_sect,
1256 TIPC_ERR_NO_NODE);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001257 return res;
1258}
1259
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001260/*
1261 * link_send_sections_long(): Entry for long messages where the
Per Lidenb97bf3f2006-01-02 19:04:38 +01001262 * destination node is known and the header is complete,
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001263 * inclusive total message length.
Per Lidenb97bf3f2006-01-02 19:04:38 +01001264 * Link and bearer congestion status have been checked to be ok,
1265 * and are ignored if they change.
1266 *
1267 * Note that fragments do not use the full link MTU so that they won't have
1268 * to undergo refragmentation if link changeover causes them to be sent
1269 * over another link with an additional tunnel header added as prefix.
1270 * (Refragmentation will still occur if the other link has a smaller MTU.)
1271 *
1272 * Returns user data length or errno.
1273 */
1274static int link_send_sections_long(struct port *sender,
1275 struct iovec const *msg_sect,
1276 u32 num_sect,
1277 u32 destaddr)
1278{
1279 struct link *l_ptr;
David S. Miller6c000552008-09-02 23:38:32 -07001280 struct tipc_node *node;
Per Lidenb97bf3f2006-01-02 19:04:38 +01001281 struct tipc_msg *hdr = &sender->publ.phdr;
1282 u32 dsz = msg_data_sz(hdr);
1283 u32 max_pkt,fragm_sz,rest;
1284 struct tipc_msg fragm_hdr;
1285 struct sk_buff *buf,*buf_chain,*prev;
1286 u32 fragm_crs,fragm_rest,hsz,sect_rest;
1287 const unchar *sect_crs;
1288 int curr_sect;
1289 u32 fragm_no;
1290
1291again:
1292 fragm_no = 1;
Allan Stephens05646c92007-06-10 17:25:24 -07001293 max_pkt = sender->publ.max_pkt - INT_H_SIZE;
Per Lidenb97bf3f2006-01-02 19:04:38 +01001294 /* leave room for tunnel header in case of link changeover */
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001295 fragm_sz = max_pkt - INT_H_SIZE;
Per Lidenb97bf3f2006-01-02 19:04:38 +01001296 /* leave room for fragmentation header in each fragment */
1297 rest = dsz;
1298 fragm_crs = 0;
1299 fragm_rest = 0;
1300 sect_rest = 0;
Sam Ravnborg1fc54d82006-03-20 22:36:47 -08001301 sect_crs = NULL;
Per Lidenb97bf3f2006-01-02 19:04:38 +01001302 curr_sect = -1;
1303
1304 /* Prepare reusable fragment header: */
1305
1306 msg_dbg(hdr, ">FRAGMENTING>");
Allan Stephensc68ca7b2010-05-11 14:30:12 +00001307 tipc_msg_init(&fragm_hdr, MSG_FRAGMENTER, FIRST_FRAGMENT,
Allan Stephens75715212008-06-04 17:37:34 -07001308 INT_H_SIZE, msg_destnode(hdr));
Per Lidenb97bf3f2006-01-02 19:04:38 +01001309 msg_set_link_selector(&fragm_hdr, sender->publ.ref);
1310 msg_set_size(&fragm_hdr, max_pkt);
1311 msg_set_fragm_no(&fragm_hdr, 1);
1312
1313 /* Prepare header of first fragment: */
1314
1315 buf_chain = buf = buf_acquire(max_pkt);
1316 if (!buf)
1317 return -ENOMEM;
1318 buf->next = NULL;
Arnaldo Carvalho de Melo27d7ff42007-03-31 11:55:19 -03001319 skb_copy_to_linear_data(buf, &fragm_hdr, INT_H_SIZE);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001320 hsz = msg_hdr_sz(hdr);
Arnaldo Carvalho de Melo27d7ff42007-03-31 11:55:19 -03001321 skb_copy_to_linear_data_offset(buf, INT_H_SIZE, hdr, hsz);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001322 msg_dbg(buf_msg(buf), ">BUILD>");
1323
1324 /* Chop up message: */
1325
1326 fragm_crs = INT_H_SIZE + hsz;
1327 fragm_rest = fragm_sz - hsz;
1328
1329 do { /* For all sections */
1330 u32 sz;
1331
1332 if (!sect_rest) {
1333 sect_rest = msg_sect[++curr_sect].iov_len;
1334 sect_crs = (const unchar *)msg_sect[curr_sect].iov_base;
1335 }
1336
1337 if (sect_rest < fragm_rest)
1338 sz = sect_rest;
1339 else
1340 sz = fragm_rest;
1341
1342 if (likely(!sender->user_port)) {
1343 if (copy_from_user(buf->data + fragm_crs, sect_crs, sz)) {
1344error:
1345 for (; buf_chain; buf_chain = buf) {
1346 buf = buf_chain->next;
1347 buf_discard(buf_chain);
1348 }
1349 return -EFAULT;
1350 }
1351 } else
Arnaldo Carvalho de Melo27d7ff42007-03-31 11:55:19 -03001352 skb_copy_to_linear_data_offset(buf, fragm_crs,
1353 sect_crs, sz);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001354 sect_crs += sz;
1355 sect_rest -= sz;
1356 fragm_crs += sz;
1357 fragm_rest -= sz;
1358 rest -= sz;
1359
1360 if (!fragm_rest && rest) {
1361
1362 /* Initiate new fragment: */
1363 if (rest <= fragm_sz) {
1364 fragm_sz = rest;
1365 msg_set_type(&fragm_hdr,LAST_FRAGMENT);
1366 } else {
1367 msg_set_type(&fragm_hdr, FRAGMENT);
1368 }
1369 msg_set_size(&fragm_hdr, fragm_sz + INT_H_SIZE);
1370 msg_set_fragm_no(&fragm_hdr, ++fragm_no);
1371 prev = buf;
1372 buf = buf_acquire(fragm_sz + INT_H_SIZE);
1373 if (!buf)
1374 goto error;
1375
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001376 buf->next = NULL;
Per Lidenb97bf3f2006-01-02 19:04:38 +01001377 prev->next = buf;
Arnaldo Carvalho de Melo27d7ff42007-03-31 11:55:19 -03001378 skb_copy_to_linear_data(buf, &fragm_hdr, INT_H_SIZE);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001379 fragm_crs = INT_H_SIZE;
1380 fragm_rest = fragm_sz;
1381 msg_dbg(buf_msg(buf)," >BUILD>");
1382 }
1383 }
1384 while (rest > 0);
1385
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001386 /*
Per Lidenb97bf3f2006-01-02 19:04:38 +01001387 * Now we have a buffer chain. Select a link and check
1388 * that packet size is still OK
1389 */
Per Liden4323add2006-01-18 00:38:21 +01001390 node = tipc_node_select(destaddr, sender->publ.ref & 1);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001391 if (likely(node)) {
Per Liden4323add2006-01-18 00:38:21 +01001392 tipc_node_lock(node);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001393 l_ptr = node->active_links[sender->publ.ref & 1];
1394 if (!l_ptr) {
Per Liden4323add2006-01-18 00:38:21 +01001395 tipc_node_unlock(node);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001396 goto reject;
1397 }
Allan Stephens15e979d2010-05-11 14:30:10 +00001398 if (l_ptr->max_pkt < max_pkt) {
1399 sender->publ.max_pkt = l_ptr->max_pkt;
Per Liden4323add2006-01-18 00:38:21 +01001400 tipc_node_unlock(node);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001401 for (; buf_chain; buf_chain = buf) {
1402 buf = buf_chain->next;
1403 buf_discard(buf_chain);
1404 }
1405 goto again;
1406 }
1407 } else {
1408reject:
1409 for (; buf_chain; buf_chain = buf) {
1410 buf = buf_chain->next;
1411 buf_discard(buf_chain);
1412 }
Per Liden4323add2006-01-18 00:38:21 +01001413 return tipc_port_reject_sections(sender, hdr, msg_sect, num_sect,
1414 TIPC_ERR_NO_NODE);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001415 }
1416
1417 /* Append whole chain to send queue: */
1418
1419 buf = buf_chain;
1420 l_ptr->long_msg_seq_no = mod(l_ptr->long_msg_seq_no + 1);
1421 if (!l_ptr->next_out)
1422 l_ptr->next_out = buf_chain;
1423 l_ptr->stats.sent_fragmented++;
1424 while (buf) {
1425 struct sk_buff *next = buf->next;
1426 struct tipc_msg *msg = buf_msg(buf);
1427
1428 l_ptr->stats.sent_fragments++;
1429 msg_set_long_msgno(msg, l_ptr->long_msg_seq_no);
1430 link_add_to_outqueue(l_ptr, buf, msg);
1431 msg_dbg(msg, ">ADD>");
1432 buf = next;
1433 }
1434
1435 /* Send it, if possible: */
1436
Per Liden4323add2006-01-18 00:38:21 +01001437 tipc_link_push_queue(l_ptr);
1438 tipc_node_unlock(node);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001439 return dsz;
1440}
1441
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001442/*
Per Liden4323add2006-01-18 00:38:21 +01001443 * tipc_link_push_packet: Push one unsent packet to the media
Per Lidenb97bf3f2006-01-02 19:04:38 +01001444 */
Per Liden4323add2006-01-18 00:38:21 +01001445u32 tipc_link_push_packet(struct link *l_ptr)
Per Lidenb97bf3f2006-01-02 19:04:38 +01001446{
1447 struct sk_buff *buf = l_ptr->first_out;
1448 u32 r_q_size = l_ptr->retransm_queue_size;
1449 u32 r_q_head = l_ptr->retransm_queue_head;
1450
1451 /* Step to position where retransmission failed, if any, */
1452 /* consider that buffers may have been released in meantime */
1453
1454 if (r_q_size && buf) {
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001455 u32 last = lesser(mod(r_q_head + r_q_size),
Per Lidenb97bf3f2006-01-02 19:04:38 +01001456 link_last_sent(l_ptr));
1457 u32 first = msg_seqno(buf_msg(buf));
1458
1459 while (buf && less(first, r_q_head)) {
1460 first = mod(first + 1);
1461 buf = buf->next;
1462 }
1463 l_ptr->retransm_queue_head = r_q_head = first;
1464 l_ptr->retransm_queue_size = r_q_size = mod(last - first);
1465 }
1466
1467 /* Continue retransmission now, if there is anything: */
1468
Neil Hormanca509102010-03-15 07:58:45 +00001469 if (r_q_size && buf) {
Per Lidenb97bf3f2006-01-02 19:04:38 +01001470 msg_set_ack(buf_msg(buf), mod(l_ptr->next_in_no - 1));
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001471 msg_set_bcast_ack(buf_msg(buf), l_ptr->owner->bclink.last_in);
Per Liden4323add2006-01-18 00:38:21 +01001472 if (tipc_bearer_send(l_ptr->b_ptr, buf, &l_ptr->media_addr)) {
Per Lidenb97bf3f2006-01-02 19:04:38 +01001473 msg_dbg(buf_msg(buf), ">DEF-RETR>");
1474 l_ptr->retransm_queue_head = mod(++r_q_head);
1475 l_ptr->retransm_queue_size = --r_q_size;
1476 l_ptr->stats.retransmitted++;
Allan Stephens0e35fd52008-07-14 22:44:01 -07001477 return 0;
Per Lidenb97bf3f2006-01-02 19:04:38 +01001478 } else {
1479 l_ptr->stats.bearer_congs++;
1480 msg_dbg(buf_msg(buf), "|>DEF-RETR>");
1481 return PUSH_FAILED;
1482 }
1483 }
1484
1485 /* Send deferred protocol message, if any: */
1486
1487 buf = l_ptr->proto_msg_queue;
1488 if (buf) {
1489 msg_set_ack(buf_msg(buf), mod(l_ptr->next_in_no - 1));
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001490 msg_set_bcast_ack(buf_msg(buf),l_ptr->owner->bclink.last_in);
Per Liden4323add2006-01-18 00:38:21 +01001491 if (tipc_bearer_send(l_ptr->b_ptr, buf, &l_ptr->media_addr)) {
Per Lidenb97bf3f2006-01-02 19:04:38 +01001492 msg_dbg(buf_msg(buf), ">DEF-PROT>");
1493 l_ptr->unacked_window = 0;
1494 buf_discard(buf);
Sam Ravnborg1fc54d82006-03-20 22:36:47 -08001495 l_ptr->proto_msg_queue = NULL;
Allan Stephens0e35fd52008-07-14 22:44:01 -07001496 return 0;
Per Lidenb97bf3f2006-01-02 19:04:38 +01001497 } else {
1498 msg_dbg(buf_msg(buf), "|>DEF-PROT>");
1499 l_ptr->stats.bearer_congs++;
1500 return PUSH_FAILED;
1501 }
1502 }
1503
1504 /* Send one deferred data message, if send window not full: */
1505
1506 buf = l_ptr->next_out;
1507 if (buf) {
1508 struct tipc_msg *msg = buf_msg(buf);
1509 u32 next = msg_seqno(msg);
1510 u32 first = msg_seqno(buf_msg(l_ptr->first_out));
1511
1512 if (mod(next - first) < l_ptr->queue_limit[0]) {
1513 msg_set_ack(msg, mod(l_ptr->next_in_no - 1));
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001514 msg_set_bcast_ack(msg, l_ptr->owner->bclink.last_in);
Per Liden4323add2006-01-18 00:38:21 +01001515 if (tipc_bearer_send(l_ptr->b_ptr, buf, &l_ptr->media_addr)) {
Per Lidenb97bf3f2006-01-02 19:04:38 +01001516 if (msg_user(msg) == MSG_BUNDLER)
1517 msg_set_type(msg, CLOSED_MSG);
1518 msg_dbg(msg, ">PUSH-DATA>");
1519 l_ptr->next_out = buf->next;
Allan Stephens0e35fd52008-07-14 22:44:01 -07001520 return 0;
Per Lidenb97bf3f2006-01-02 19:04:38 +01001521 } else {
1522 msg_dbg(msg, "|PUSH-DATA|");
1523 l_ptr->stats.bearer_congs++;
1524 return PUSH_FAILED;
1525 }
1526 }
1527 }
1528 return PUSH_FINISHED;
1529}
1530
1531/*
1532 * push_queue(): push out the unsent messages of a link where
1533 * congestion has abated. Node is locked
1534 */
Per Liden4323add2006-01-18 00:38:21 +01001535void tipc_link_push_queue(struct link *l_ptr)
Per Lidenb97bf3f2006-01-02 19:04:38 +01001536{
1537 u32 res;
1538
Per Liden4323add2006-01-18 00:38:21 +01001539 if (tipc_bearer_congested(l_ptr->b_ptr, l_ptr))
Per Lidenb97bf3f2006-01-02 19:04:38 +01001540 return;
1541
1542 do {
Per Liden4323add2006-01-18 00:38:21 +01001543 res = tipc_link_push_packet(l_ptr);
Allan Stephens0e35fd52008-07-14 22:44:01 -07001544 } while (!res);
1545
Per Lidenb97bf3f2006-01-02 19:04:38 +01001546 if (res == PUSH_FAILED)
Per Liden4323add2006-01-18 00:38:21 +01001547 tipc_bearer_schedule(l_ptr->b_ptr, l_ptr);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001548}
1549
Allan Stephensd356eeb2006-06-25 23:40:01 -07001550static void link_reset_all(unsigned long addr)
1551{
David S. Miller6c000552008-09-02 23:38:32 -07001552 struct tipc_node *n_ptr;
Allan Stephensd356eeb2006-06-25 23:40:01 -07001553 char addr_string[16];
1554 u32 i;
1555
1556 read_lock_bh(&tipc_net_lock);
1557 n_ptr = tipc_node_find((u32)addr);
1558 if (!n_ptr) {
1559 read_unlock_bh(&tipc_net_lock);
1560 return; /* node no longer exists */
1561 }
1562
1563 tipc_node_lock(n_ptr);
1564
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001565 warn("Resetting all links to %s\n",
Allan Stephensc68ca7b2010-05-11 14:30:12 +00001566 tipc_addr_string_fill(addr_string, n_ptr->addr));
Allan Stephensd356eeb2006-06-25 23:40:01 -07001567
1568 for (i = 0; i < MAX_BEARERS; i++) {
1569 if (n_ptr->links[i]) {
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001570 link_print(n_ptr->links[i], TIPC_OUTPUT,
Allan Stephensd356eeb2006-06-25 23:40:01 -07001571 "Resetting link\n");
1572 tipc_link_reset(n_ptr->links[i]);
1573 }
1574 }
1575
1576 tipc_node_unlock(n_ptr);
1577 read_unlock_bh(&tipc_net_lock);
1578}
1579
1580static void link_retransmit_failure(struct link *l_ptr, struct sk_buff *buf)
1581{
1582 struct tipc_msg *msg = buf_msg(buf);
1583
1584 warn("Retransmission failure on link <%s>\n", l_ptr->name);
Allan Stephens48c97132008-05-05 01:24:06 -07001585 tipc_msg_dbg(TIPC_OUTPUT, msg, ">RETR-FAIL>");
Allan Stephensd356eeb2006-06-25 23:40:01 -07001586
1587 if (l_ptr->addr) {
1588
1589 /* Handle failure on standard link */
1590
1591 link_print(l_ptr, TIPC_OUTPUT, "Resetting link\n");
1592 tipc_link_reset(l_ptr);
1593
1594 } else {
1595
1596 /* Handle failure on broadcast link */
1597
David S. Miller6c000552008-09-02 23:38:32 -07001598 struct tipc_node *n_ptr;
Allan Stephensd356eeb2006-06-25 23:40:01 -07001599 char addr_string[16];
1600
1601 tipc_printf(TIPC_OUTPUT, "Msg seq number: %u, ", msg_seqno(msg));
Jeff Garzik617dbea2006-10-03 16:25:34 -07001602 tipc_printf(TIPC_OUTPUT, "Outstanding acks: %lu\n",
1603 (unsigned long) TIPC_SKB_CB(buf)->handle);
1604
Allan Stephensd356eeb2006-06-25 23:40:01 -07001605 n_ptr = l_ptr->owner->next;
1606 tipc_node_lock(n_ptr);
1607
Allan Stephensc68ca7b2010-05-11 14:30:12 +00001608 tipc_addr_string_fill(addr_string, n_ptr->addr);
Allan Stephensd356eeb2006-06-25 23:40:01 -07001609 tipc_printf(TIPC_OUTPUT, "Multicast link info for %s\n", addr_string);
1610 tipc_printf(TIPC_OUTPUT, "Supported: %d, ", n_ptr->bclink.supported);
1611 tipc_printf(TIPC_OUTPUT, "Acked: %u\n", n_ptr->bclink.acked);
1612 tipc_printf(TIPC_OUTPUT, "Last in: %u, ", n_ptr->bclink.last_in);
1613 tipc_printf(TIPC_OUTPUT, "Gap after: %u, ", n_ptr->bclink.gap_after);
1614 tipc_printf(TIPC_OUTPUT, "Gap to: %u\n", n_ptr->bclink.gap_to);
1615 tipc_printf(TIPC_OUTPUT, "Nack sync: %u\n\n", n_ptr->bclink.nack_sync);
1616
1617 tipc_k_signal((Handler)link_reset_all, (unsigned long)n_ptr->addr);
1618
1619 tipc_node_unlock(n_ptr);
1620
1621 l_ptr->stale_count = 0;
1622 }
1623}
1624
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001625void tipc_link_retransmit(struct link *l_ptr, struct sk_buff *buf,
Per Liden4323add2006-01-18 00:38:21 +01001626 u32 retransmits)
Per Lidenb97bf3f2006-01-02 19:04:38 +01001627{
1628 struct tipc_msg *msg;
1629
Allan Stephensd356eeb2006-06-25 23:40:01 -07001630 if (!buf)
1631 return;
1632
1633 msg = buf_msg(buf);
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001634
Per Lidenb97bf3f2006-01-02 19:04:38 +01001635 dbg("Retransmitting %u in link %x\n", retransmits, l_ptr);
1636
Allan Stephensd356eeb2006-06-25 23:40:01 -07001637 if (tipc_bearer_congested(l_ptr->b_ptr, l_ptr)) {
Neil Hormanca509102010-03-15 07:58:45 +00001638 if (l_ptr->retransm_queue_size == 0) {
Allan Stephensd356eeb2006-06-25 23:40:01 -07001639 msg_dbg(msg, ">NO_RETR->BCONG>");
1640 dbg_print_link(l_ptr, " ");
1641 l_ptr->retransm_queue_head = msg_seqno(msg);
1642 l_ptr->retransm_queue_size = retransmits;
Allan Stephensd356eeb2006-06-25 23:40:01 -07001643 } else {
Neil Hormanca509102010-03-15 07:58:45 +00001644 err("Unexpected retransmit on link %s (qsize=%d)\n",
1645 l_ptr->name, l_ptr->retransm_queue_size);
Allan Stephensd356eeb2006-06-25 23:40:01 -07001646 }
Neil Hormanca509102010-03-15 07:58:45 +00001647 return;
Allan Stephensd356eeb2006-06-25 23:40:01 -07001648 } else {
1649 /* Detect repeated retransmit failures on uncongested bearer */
1650
1651 if (l_ptr->last_retransmitted == msg_seqno(msg)) {
1652 if (++l_ptr->stale_count > 100) {
1653 link_retransmit_failure(l_ptr, buf);
1654 return;
1655 }
1656 } else {
1657 l_ptr->last_retransmitted = msg_seqno(msg);
1658 l_ptr->stale_count = 1;
1659 }
Per Lidenb97bf3f2006-01-02 19:04:38 +01001660 }
Allan Stephensd356eeb2006-06-25 23:40:01 -07001661
Neil Hormanca509102010-03-15 07:58:45 +00001662 while (retransmits && (buf != l_ptr->next_out) && buf) {
Per Lidenb97bf3f2006-01-02 19:04:38 +01001663 msg = buf_msg(buf);
1664 msg_set_ack(msg, mod(l_ptr->next_in_no - 1));
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001665 msg_set_bcast_ack(msg, l_ptr->owner->bclink.last_in);
Per Liden4323add2006-01-18 00:38:21 +01001666 if (tipc_bearer_send(l_ptr->b_ptr, buf, &l_ptr->media_addr)) {
Per Lidenb97bf3f2006-01-02 19:04:38 +01001667 msg_dbg(buf_msg(buf), ">RETR>");
1668 buf = buf->next;
1669 retransmits--;
1670 l_ptr->stats.retransmitted++;
1671 } else {
Per Liden4323add2006-01-18 00:38:21 +01001672 tipc_bearer_schedule(l_ptr->b_ptr, l_ptr);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001673 l_ptr->stats.bearer_congs++;
1674 l_ptr->retransm_queue_head = msg_seqno(buf_msg(buf));
1675 l_ptr->retransm_queue_size = retransmits;
1676 return;
1677 }
1678 }
Allan Stephensd356eeb2006-06-25 23:40:01 -07001679
Per Lidenb97bf3f2006-01-02 19:04:38 +01001680 l_ptr->retransm_queue_head = l_ptr->retransm_queue_size = 0;
1681}
1682
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001683/**
Per Lidenb97bf3f2006-01-02 19:04:38 +01001684 * link_insert_deferred_queue - insert deferred messages back into receive chain
1685 */
1686
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001687static struct sk_buff *link_insert_deferred_queue(struct link *l_ptr,
Per Lidenb97bf3f2006-01-02 19:04:38 +01001688 struct sk_buff *buf)
1689{
1690 u32 seq_no;
1691
1692 if (l_ptr->oldest_deferred_in == NULL)
1693 return buf;
1694
1695 seq_no = msg_seqno(buf_msg(l_ptr->oldest_deferred_in));
1696 if (seq_no == mod(l_ptr->next_in_no)) {
1697 l_ptr->newest_deferred_in->next = buf;
1698 buf = l_ptr->oldest_deferred_in;
1699 l_ptr->oldest_deferred_in = NULL;
1700 l_ptr->deferred_inqueue_sz = 0;
1701 }
1702 return buf;
1703}
1704
Allan Stephens85035562008-04-15 19:04:54 -07001705/**
1706 * link_recv_buf_validate - validate basic format of received message
1707 *
1708 * This routine ensures a TIPC message has an acceptable header, and at least
1709 * as much data as the header indicates it should. The routine also ensures
1710 * that the entire message header is stored in the main fragment of the message
1711 * buffer, to simplify future access to message header fields.
1712 *
1713 * Note: Having extra info present in the message header or data areas is OK.
1714 * TIPC will ignore the excess, under the assumption that it is optional info
1715 * introduced by a later release of the protocol.
1716 */
1717
1718static int link_recv_buf_validate(struct sk_buff *buf)
1719{
1720 static u32 min_data_hdr_size[8] = {
1721 SHORT_H_SIZE, MCAST_H_SIZE, LONG_H_SIZE, DIR_MSG_H_SIZE,
1722 MAX_H_SIZE, MAX_H_SIZE, MAX_H_SIZE, MAX_H_SIZE
1723 };
1724
1725 struct tipc_msg *msg;
1726 u32 tipc_hdr[2];
1727 u32 size;
1728 u32 hdr_size;
1729 u32 min_hdr_size;
1730
1731 if (unlikely(buf->len < MIN_H_SIZE))
1732 return 0;
1733
1734 msg = skb_header_pointer(buf, 0, sizeof(tipc_hdr), tipc_hdr);
1735 if (msg == NULL)
1736 return 0;
1737
1738 if (unlikely(msg_version(msg) != TIPC_VERSION))
1739 return 0;
1740
1741 size = msg_size(msg);
1742 hdr_size = msg_hdr_sz(msg);
1743 min_hdr_size = msg_isdata(msg) ?
1744 min_data_hdr_size[msg_type(msg)] : INT_H_SIZE;
1745
1746 if (unlikely((hdr_size < min_hdr_size) ||
1747 (size < hdr_size) ||
1748 (buf->len < size) ||
1749 (size - hdr_size > TIPC_MAX_USER_MSG_SIZE)))
1750 return 0;
1751
1752 return pskb_may_pull(buf, hdr_size);
1753}
1754
Allan Stephensb02b69c2010-08-17 11:00:07 +00001755/**
1756 * tipc_recv_msg - process TIPC messages arriving from off-node
1757 * @head: pointer to message buffer chain
1758 * @tb_ptr: pointer to bearer message arrived on
1759 *
1760 * Invoked with no locks held. Bearer pointer must point to a valid bearer
1761 * structure (i.e. cannot be NULL), but bearer can be inactive.
1762 */
1763
Per Lidenb97bf3f2006-01-02 19:04:38 +01001764void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *tb_ptr)
1765{
Per Liden4323add2006-01-18 00:38:21 +01001766 read_lock_bh(&tipc_net_lock);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001767 while (head) {
Allan Stephens1265a022008-06-04 17:32:35 -07001768 struct bearer *b_ptr = (struct bearer *)tb_ptr;
David S. Miller6c000552008-09-02 23:38:32 -07001769 struct tipc_node *n_ptr;
Per Lidenb97bf3f2006-01-02 19:04:38 +01001770 struct link *l_ptr;
1771 struct sk_buff *crs;
1772 struct sk_buff *buf = head;
Allan Stephens85035562008-04-15 19:04:54 -07001773 struct tipc_msg *msg;
1774 u32 seq_no;
1775 u32 ackd;
Per Lidenb97bf3f2006-01-02 19:04:38 +01001776 u32 released = 0;
1777 int type;
1778
Per Lidenb97bf3f2006-01-02 19:04:38 +01001779 head = head->next;
Allan Stephens85035562008-04-15 19:04:54 -07001780
Allan Stephensb02b69c2010-08-17 11:00:07 +00001781 /* Ensure bearer is still enabled */
1782
1783 if (unlikely(!b_ptr->active))
1784 goto cont;
1785
Allan Stephens85035562008-04-15 19:04:54 -07001786 /* Ensure message is well-formed */
1787
1788 if (unlikely(!link_recv_buf_validate(buf)))
Per Lidenb97bf3f2006-01-02 19:04:38 +01001789 goto cont;
Per Lidenb97bf3f2006-01-02 19:04:38 +01001790
Allan Stephensfe13dda2008-04-15 19:03:23 -07001791 /* Ensure message data is a single contiguous unit */
1792
1793 if (unlikely(buf_linearize(buf))) {
1794 goto cont;
1795 }
1796
Allan Stephens85035562008-04-15 19:04:54 -07001797 /* Handle arrival of a non-unicast link message */
1798
1799 msg = buf_msg(buf);
1800
Per Lidenb97bf3f2006-01-02 19:04:38 +01001801 if (unlikely(msg_non_seq(msg))) {
Allan Stephens1265a022008-06-04 17:32:35 -07001802 if (msg_user(msg) == LINK_CONFIG)
1803 tipc_disc_recv_msg(buf, b_ptr);
1804 else
1805 tipc_bclink_recv_pkt(buf);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001806 continue;
1807 }
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001808
Allan Stephens26008242006-06-25 23:39:31 -07001809 if (unlikely(!msg_short(msg) &&
1810 (msg_destnode(msg) != tipc_own_addr)))
1811 goto cont;
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001812
Neil Hormande586572010-03-08 12:43:56 -08001813 /* Discard non-routeable messages destined for another node */
1814
1815 if (unlikely(!msg_isdata(msg) &&
1816 (msg_destnode(msg) != tipc_own_addr))) {
1817 if ((msg_user(msg) != CONN_MANAGER) &&
1818 (msg_user(msg) != MSG_FRAGMENTER))
1819 goto cont;
1820 }
1821
Allan Stephens5a68d5e2010-08-17 11:00:16 +00001822 /* Locate neighboring node that sent message */
Allan Stephens85035562008-04-15 19:04:54 -07001823
Per Liden4323add2006-01-18 00:38:21 +01001824 n_ptr = tipc_node_find(msg_prevnode(msg));
Per Lidenb97bf3f2006-01-02 19:04:38 +01001825 if (unlikely(!n_ptr))
1826 goto cont;
Per Liden4323add2006-01-18 00:38:21 +01001827 tipc_node_lock(n_ptr);
Allan Stephens85035562008-04-15 19:04:54 -07001828
Allan Stephens5a68d5e2010-08-17 11:00:16 +00001829 /* Don't talk to neighbor during cleanup after last session */
1830
1831 if (n_ptr->cleanup_required) {
1832 tipc_node_unlock(n_ptr);
1833 goto cont;
1834 }
1835
1836 /* Locate unicast link endpoint that should handle message */
1837
Per Lidenb97bf3f2006-01-02 19:04:38 +01001838 l_ptr = n_ptr->links[b_ptr->identity];
1839 if (unlikely(!l_ptr)) {
Per Liden4323add2006-01-18 00:38:21 +01001840 tipc_node_unlock(n_ptr);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001841 goto cont;
1842 }
Allan Stephens85035562008-04-15 19:04:54 -07001843
1844 /* Validate message sequence number info */
1845
1846 seq_no = msg_seqno(msg);
1847 ackd = msg_ack(msg);
1848
1849 /* Release acked messages */
1850
Per Lidenb97bf3f2006-01-02 19:04:38 +01001851 if (less(n_ptr->bclink.acked, msg_bcast_ack(msg))) {
Per Liden4323add2006-01-18 00:38:21 +01001852 if (tipc_node_is_up(n_ptr) && n_ptr->bclink.supported)
1853 tipc_bclink_acknowledge(n_ptr, msg_bcast_ack(msg));
Per Lidenb97bf3f2006-01-02 19:04:38 +01001854 }
1855
1856 crs = l_ptr->first_out;
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001857 while ((crs != l_ptr->next_out) &&
Per Lidenb97bf3f2006-01-02 19:04:38 +01001858 less_eq(msg_seqno(buf_msg(crs)), ackd)) {
1859 struct sk_buff *next = crs->next;
1860
1861 buf_discard(crs);
1862 crs = next;
1863 released++;
1864 }
1865 if (released) {
1866 l_ptr->first_out = crs;
1867 l_ptr->out_queue_size -= released;
1868 }
Allan Stephens85035562008-04-15 19:04:54 -07001869
1870 /* Try sending any messages link endpoint has pending */
1871
Per Lidenb97bf3f2006-01-02 19:04:38 +01001872 if (unlikely(l_ptr->next_out))
Per Liden4323add2006-01-18 00:38:21 +01001873 tipc_link_push_queue(l_ptr);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001874 if (unlikely(!list_empty(&l_ptr->waiting_ports)))
Per Liden4323add2006-01-18 00:38:21 +01001875 tipc_link_wakeup_ports(l_ptr, 0);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001876 if (unlikely(++l_ptr->unacked_window >= TIPC_MIN_LINK_WIN)) {
1877 l_ptr->stats.sent_acks++;
Per Liden4323add2006-01-18 00:38:21 +01001878 tipc_link_send_proto_msg(l_ptr, STATE_MSG, 0, 0, 0, 0, 0);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001879 }
1880
Allan Stephens85035562008-04-15 19:04:54 -07001881 /* Now (finally!) process the incoming message */
1882
Per Lidenb97bf3f2006-01-02 19:04:38 +01001883protocol_check:
1884 if (likely(link_working_working(l_ptr))) {
1885 if (likely(seq_no == mod(l_ptr->next_in_no))) {
1886 l_ptr->next_in_no++;
1887 if (unlikely(l_ptr->oldest_deferred_in))
1888 head = link_insert_deferred_queue(l_ptr,
1889 head);
1890 if (likely(msg_is_dest(msg, tipc_own_addr))) {
1891deliver:
1892 if (likely(msg_isdata(msg))) {
Per Liden4323add2006-01-18 00:38:21 +01001893 tipc_node_unlock(n_ptr);
1894 tipc_port_recv_msg(buf);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001895 continue;
1896 }
1897 switch (msg_user(msg)) {
1898 case MSG_BUNDLER:
1899 l_ptr->stats.recv_bundles++;
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001900 l_ptr->stats.recv_bundled +=
Per Lidenb97bf3f2006-01-02 19:04:38 +01001901 msg_msgcnt(msg);
Per Liden4323add2006-01-18 00:38:21 +01001902 tipc_node_unlock(n_ptr);
1903 tipc_link_recv_bundle(buf);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001904 continue;
1905 case ROUTE_DISTRIBUTOR:
Per Liden4323add2006-01-18 00:38:21 +01001906 tipc_node_unlock(n_ptr);
1907 tipc_cltr_recv_routing_table(buf);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001908 continue;
1909 case NAME_DISTRIBUTOR:
Per Liden4323add2006-01-18 00:38:21 +01001910 tipc_node_unlock(n_ptr);
1911 tipc_named_recv(buf);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001912 continue;
1913 case CONN_MANAGER:
Per Liden4323add2006-01-18 00:38:21 +01001914 tipc_node_unlock(n_ptr);
1915 tipc_port_recv_proto_msg(buf);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001916 continue;
1917 case MSG_FRAGMENTER:
1918 l_ptr->stats.recv_fragments++;
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001919 if (tipc_link_recv_fragment(&l_ptr->defragm_buf,
Per Liden4323add2006-01-18 00:38:21 +01001920 &buf, &msg)) {
Per Lidenb97bf3f2006-01-02 19:04:38 +01001921 l_ptr->stats.recv_fragmented++;
1922 goto deliver;
1923 }
1924 break;
1925 case CHANGEOVER_PROTOCOL:
1926 type = msg_type(msg);
Per Liden4323add2006-01-18 00:38:21 +01001927 if (link_recv_changeover_msg(&l_ptr, &buf)) {
Per Lidenb97bf3f2006-01-02 19:04:38 +01001928 msg = buf_msg(buf);
1929 seq_no = msg_seqno(msg);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001930 if (type == ORIGINAL_MSG)
1931 goto deliver;
1932 goto protocol_check;
1933 }
1934 break;
1935 }
1936 }
Per Liden4323add2006-01-18 00:38:21 +01001937 tipc_node_unlock(n_ptr);
1938 tipc_net_route_msg(buf);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001939 continue;
1940 }
1941 link_handle_out_of_seq_msg(l_ptr, buf);
1942 head = link_insert_deferred_queue(l_ptr, head);
Per Liden4323add2006-01-18 00:38:21 +01001943 tipc_node_unlock(n_ptr);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001944 continue;
1945 }
1946
1947 if (msg_user(msg) == LINK_PROTOCOL) {
1948 link_recv_proto_msg(l_ptr, buf);
1949 head = link_insert_deferred_queue(l_ptr, head);
Per Liden4323add2006-01-18 00:38:21 +01001950 tipc_node_unlock(n_ptr);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001951 continue;
1952 }
1953 msg_dbg(msg,"NSEQ<REC<");
1954 link_state_event(l_ptr, TRAFFIC_MSG_EVT);
1955
1956 if (link_working_working(l_ptr)) {
1957 /* Re-insert in front of queue */
1958 msg_dbg(msg,"RECV-REINS:");
1959 buf->next = head;
1960 head = buf;
Per Liden4323add2006-01-18 00:38:21 +01001961 tipc_node_unlock(n_ptr);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001962 continue;
1963 }
Per Liden4323add2006-01-18 00:38:21 +01001964 tipc_node_unlock(n_ptr);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001965cont:
1966 buf_discard(buf);
1967 }
Per Liden4323add2006-01-18 00:38:21 +01001968 read_unlock_bh(&tipc_net_lock);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001969}
1970
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001971/*
1972 * link_defer_buf(): Sort a received out-of-sequence packet
Per Lidenb97bf3f2006-01-02 19:04:38 +01001973 * into the deferred reception queue.
1974 * Returns the increase of the queue length,i.e. 0 or 1
1975 */
1976
Per Liden4323add2006-01-18 00:38:21 +01001977u32 tipc_link_defer_pkt(struct sk_buff **head,
1978 struct sk_buff **tail,
1979 struct sk_buff *buf)
Per Lidenb97bf3f2006-01-02 19:04:38 +01001980{
Sam Ravnborg1fc54d82006-03-20 22:36:47 -08001981 struct sk_buff *prev = NULL;
Per Lidenb97bf3f2006-01-02 19:04:38 +01001982 struct sk_buff *crs = *head;
1983 u32 seq_no = msg_seqno(buf_msg(buf));
1984
1985 buf->next = NULL;
1986
1987 /* Empty queue ? */
1988 if (*head == NULL) {
1989 *head = *tail = buf;
1990 return 1;
1991 }
1992
1993 /* Last ? */
1994 if (less(msg_seqno(buf_msg(*tail)), seq_no)) {
1995 (*tail)->next = buf;
1996 *tail = buf;
1997 return 1;
1998 }
1999
2000 /* Scan through queue and sort it in */
2001 do {
2002 struct tipc_msg *msg = buf_msg(crs);
2003
2004 if (less(seq_no, msg_seqno(msg))) {
2005 buf->next = crs;
2006 if (prev)
2007 prev->next = buf;
2008 else
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002009 *head = buf;
Per Lidenb97bf3f2006-01-02 19:04:38 +01002010 return 1;
2011 }
2012 if (seq_no == msg_seqno(msg)) {
2013 break;
2014 }
2015 prev = crs;
2016 crs = crs->next;
2017 }
2018 while (crs);
2019
2020 /* Message is a duplicate of an existing message */
2021
2022 buf_discard(buf);
2023 return 0;
2024}
2025
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002026/**
Per Lidenb97bf3f2006-01-02 19:04:38 +01002027 * link_handle_out_of_seq_msg - handle arrival of out-of-sequence packet
2028 */
2029
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002030static void link_handle_out_of_seq_msg(struct link *l_ptr,
Per Lidenb97bf3f2006-01-02 19:04:38 +01002031 struct sk_buff *buf)
2032{
2033 u32 seq_no = msg_seqno(buf_msg(buf));
2034
2035 if (likely(msg_user(buf_msg(buf)) == LINK_PROTOCOL)) {
2036 link_recv_proto_msg(l_ptr, buf);
2037 return;
2038 }
2039
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002040 dbg("rx OOS msg: seq_no %u, expecting %u (%u)\n",
Per Lidenb97bf3f2006-01-02 19:04:38 +01002041 seq_no, mod(l_ptr->next_in_no), l_ptr->next_in_no);
2042
2043 /* Record OOS packet arrival (force mismatch on next timeout) */
2044
2045 l_ptr->checkpoint--;
2046
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002047 /*
Per Lidenb97bf3f2006-01-02 19:04:38 +01002048 * Discard packet if a duplicate; otherwise add it to deferred queue
2049 * and notify peer of gap as per protocol specification
2050 */
2051
2052 if (less(seq_no, mod(l_ptr->next_in_no))) {
2053 l_ptr->stats.duplicates++;
2054 buf_discard(buf);
2055 return;
2056 }
2057
Per Liden4323add2006-01-18 00:38:21 +01002058 if (tipc_link_defer_pkt(&l_ptr->oldest_deferred_in,
2059 &l_ptr->newest_deferred_in, buf)) {
Per Lidenb97bf3f2006-01-02 19:04:38 +01002060 l_ptr->deferred_inqueue_sz++;
2061 l_ptr->stats.deferred_recv++;
2062 if ((l_ptr->deferred_inqueue_sz % 16) == 1)
Per Liden4323add2006-01-18 00:38:21 +01002063 tipc_link_send_proto_msg(l_ptr, STATE_MSG, 0, 0, 0, 0, 0);
Per Lidenb97bf3f2006-01-02 19:04:38 +01002064 } else
2065 l_ptr->stats.duplicates++;
2066}
2067
2068/*
2069 * Send protocol message to the other endpoint.
2070 */
Per Liden4323add2006-01-18 00:38:21 +01002071void tipc_link_send_proto_msg(struct link *l_ptr, u32 msg_typ, int probe_msg,
2072 u32 gap, u32 tolerance, u32 priority, u32 ack_mtu)
Per Lidenb97bf3f2006-01-02 19:04:38 +01002073{
Sam Ravnborg1fc54d82006-03-20 22:36:47 -08002074 struct sk_buff *buf = NULL;
Per Lidenb97bf3f2006-01-02 19:04:38 +01002075 struct tipc_msg *msg = l_ptr->pmsg;
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002076 u32 msg_size = sizeof(l_ptr->proto_msg);
Per Lidenb97bf3f2006-01-02 19:04:38 +01002077
2078 if (link_blocked(l_ptr))
2079 return;
2080 msg_set_type(msg, msg_typ);
2081 msg_set_net_plane(msg, l_ptr->b_ptr->net_plane);
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002082 msg_set_bcast_ack(msg, mod(l_ptr->owner->bclink.last_in));
Per Liden4323add2006-01-18 00:38:21 +01002083 msg_set_last_bcast(msg, tipc_bclink_get_last_sent());
Per Lidenb97bf3f2006-01-02 19:04:38 +01002084
2085 if (msg_typ == STATE_MSG) {
2086 u32 next_sent = mod(l_ptr->next_out_no);
2087
Per Liden4323add2006-01-18 00:38:21 +01002088 if (!tipc_link_is_up(l_ptr))
Per Lidenb97bf3f2006-01-02 19:04:38 +01002089 return;
2090 if (l_ptr->next_out)
2091 next_sent = msg_seqno(buf_msg(l_ptr->next_out));
2092 msg_set_next_sent(msg, next_sent);
2093 if (l_ptr->oldest_deferred_in) {
2094 u32 rec = msg_seqno(buf_msg(l_ptr->oldest_deferred_in));
2095 gap = mod(rec - mod(l_ptr->next_in_no));
2096 }
2097 msg_set_seq_gap(msg, gap);
2098 if (gap)
2099 l_ptr->stats.sent_nacks++;
2100 msg_set_link_tolerance(msg, tolerance);
2101 msg_set_linkprio(msg, priority);
2102 msg_set_max_pkt(msg, ack_mtu);
2103 msg_set_ack(msg, mod(l_ptr->next_in_no - 1));
2104 msg_set_probe(msg, probe_msg != 0);
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002105 if (probe_msg) {
Per Lidenb97bf3f2006-01-02 19:04:38 +01002106 u32 mtu = l_ptr->max_pkt;
2107
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002108 if ((mtu < l_ptr->max_pkt_target) &&
Per Lidenb97bf3f2006-01-02 19:04:38 +01002109 link_working_working(l_ptr) &&
2110 l_ptr->fsm_msg_cnt) {
2111 msg_size = (mtu + (l_ptr->max_pkt_target - mtu)/2 + 2) & ~3;
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002112 if (l_ptr->max_pkt_probes == 10) {
2113 l_ptr->max_pkt_target = (msg_size - 4);
2114 l_ptr->max_pkt_probes = 0;
Per Lidenb97bf3f2006-01-02 19:04:38 +01002115 msg_size = (mtu + (l_ptr->max_pkt_target - mtu)/2 + 2) & ~3;
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002116 }
Per Lidenb97bf3f2006-01-02 19:04:38 +01002117 l_ptr->max_pkt_probes++;
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002118 }
Per Lidenb97bf3f2006-01-02 19:04:38 +01002119
2120 l_ptr->stats.sent_probes++;
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002121 }
Per Lidenb97bf3f2006-01-02 19:04:38 +01002122 l_ptr->stats.sent_states++;
2123 } else { /* RESET_MSG or ACTIVATE_MSG */
2124 msg_set_ack(msg, mod(l_ptr->reset_checkpoint - 1));
2125 msg_set_seq_gap(msg, 0);
2126 msg_set_next_sent(msg, 1);
2127 msg_set_link_tolerance(msg, l_ptr->tolerance);
2128 msg_set_linkprio(msg, l_ptr->priority);
2129 msg_set_max_pkt(msg, l_ptr->max_pkt_target);
2130 }
2131
Per Liden4323add2006-01-18 00:38:21 +01002132 if (tipc_node_has_redundant_links(l_ptr->owner)) {
Per Lidenb97bf3f2006-01-02 19:04:38 +01002133 msg_set_redundant_link(msg);
2134 } else {
2135 msg_clear_redundant_link(msg);
2136 }
2137 msg_set_linkprio(msg, l_ptr->priority);
2138
2139 /* Ensure sequence number will not fit : */
2140
2141 msg_set_seqno(msg, mod(l_ptr->next_out_no + (0xffff/2)));
2142
2143 /* Congestion? */
2144
Per Liden4323add2006-01-18 00:38:21 +01002145 if (tipc_bearer_congested(l_ptr->b_ptr, l_ptr)) {
Per Lidenb97bf3f2006-01-02 19:04:38 +01002146 if (!l_ptr->proto_msg_queue) {
2147 l_ptr->proto_msg_queue =
2148 buf_acquire(sizeof(l_ptr->proto_msg));
2149 }
2150 buf = l_ptr->proto_msg_queue;
2151 if (!buf)
2152 return;
Arnaldo Carvalho de Melo27d7ff42007-03-31 11:55:19 -03002153 skb_copy_to_linear_data(buf, msg, sizeof(l_ptr->proto_msg));
Per Lidenb97bf3f2006-01-02 19:04:38 +01002154 return;
2155 }
2156 msg_set_timestamp(msg, jiffies_to_msecs(jiffies));
2157
2158 /* Message can be sent */
2159
2160 msg_dbg(msg, ">>");
2161
2162 buf = buf_acquire(msg_size);
2163 if (!buf)
2164 return;
2165
Arnaldo Carvalho de Melo27d7ff42007-03-31 11:55:19 -03002166 skb_copy_to_linear_data(buf, msg, sizeof(l_ptr->proto_msg));
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002167 msg_set_size(buf_msg(buf), msg_size);
Per Lidenb97bf3f2006-01-02 19:04:38 +01002168
Per Liden4323add2006-01-18 00:38:21 +01002169 if (tipc_bearer_send(l_ptr->b_ptr, buf, &l_ptr->media_addr)) {
Per Lidenb97bf3f2006-01-02 19:04:38 +01002170 l_ptr->unacked_window = 0;
2171 buf_discard(buf);
2172 return;
2173 }
2174
2175 /* New congestion */
Per Liden4323add2006-01-18 00:38:21 +01002176 tipc_bearer_schedule(l_ptr->b_ptr, l_ptr);
Per Lidenb97bf3f2006-01-02 19:04:38 +01002177 l_ptr->proto_msg_queue = buf;
2178 l_ptr->stats.bearer_congs++;
2179}
2180
2181/*
2182 * Receive protocol message :
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002183 * Note that network plane id propagates through the network, and may
2184 * change at any time. The node with lowest address rules
Per Lidenb97bf3f2006-01-02 19:04:38 +01002185 */
2186
2187static void link_recv_proto_msg(struct link *l_ptr, struct sk_buff *buf)
2188{
2189 u32 rec_gap = 0;
2190 u32 max_pkt_info;
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002191 u32 max_pkt_ack;
Per Lidenb97bf3f2006-01-02 19:04:38 +01002192 u32 msg_tol;
2193 struct tipc_msg *msg = buf_msg(buf);
2194
2195 dbg("AT(%u):", jiffies_to_msecs(jiffies));
2196 msg_dbg(msg, "<<");
2197 if (link_blocked(l_ptr))
2198 goto exit;
2199
2200 /* record unnumbered packet arrival (force mismatch on next timeout) */
2201
2202 l_ptr->checkpoint--;
2203
2204 if (l_ptr->b_ptr->net_plane != msg_net_plane(msg))
2205 if (tipc_own_addr > msg_prevnode(msg))
2206 l_ptr->b_ptr->net_plane = msg_net_plane(msg);
2207
2208 l_ptr->owner->permit_changeover = msg_redundant_link(msg);
2209
2210 switch (msg_type(msg)) {
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002211
Per Lidenb97bf3f2006-01-02 19:04:38 +01002212 case RESET_MSG:
Allan Stephensa686e682008-06-04 17:29:39 -07002213 if (!link_working_unknown(l_ptr) &&
2214 (l_ptr->peer_session != INVALID_SESSION)) {
Per Lidenb97bf3f2006-01-02 19:04:38 +01002215 if (msg_session(msg) == l_ptr->peer_session) {
2216 dbg("Duplicate RESET: %u<->%u\n",
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002217 msg_session(msg), l_ptr->peer_session);
Per Lidenb97bf3f2006-01-02 19:04:38 +01002218 break; /* duplicate: ignore */
2219 }
2220 }
2221 /* fall thru' */
2222 case ACTIVATE_MSG:
2223 /* Update link settings according other endpoint's values */
2224
2225 strcpy((strrchr(l_ptr->name, ':') + 1), (char *)msg_data(msg));
2226
2227 if ((msg_tol = msg_link_tolerance(msg)) &&
2228 (msg_tol > l_ptr->tolerance))
2229 link_set_supervision_props(l_ptr, msg_tol);
2230
2231 if (msg_linkprio(msg) > l_ptr->priority)
2232 l_ptr->priority = msg_linkprio(msg);
2233
2234 max_pkt_info = msg_max_pkt(msg);
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002235 if (max_pkt_info) {
Per Lidenb97bf3f2006-01-02 19:04:38 +01002236 if (max_pkt_info < l_ptr->max_pkt_target)
2237 l_ptr->max_pkt_target = max_pkt_info;
2238 if (l_ptr->max_pkt > l_ptr->max_pkt_target)
2239 l_ptr->max_pkt = l_ptr->max_pkt_target;
2240 } else {
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002241 l_ptr->max_pkt = l_ptr->max_pkt_target;
Per Lidenb97bf3f2006-01-02 19:04:38 +01002242 }
2243 l_ptr->owner->bclink.supported = (max_pkt_info != 0);
2244
2245 link_state_event(l_ptr, msg_type(msg));
2246
2247 l_ptr->peer_session = msg_session(msg);
2248 l_ptr->peer_bearer_id = msg_bearer_id(msg);
2249
2250 /* Synchronize broadcast sequence numbers */
Per Liden4323add2006-01-18 00:38:21 +01002251 if (!tipc_node_has_redundant_links(l_ptr->owner)) {
Per Lidenb97bf3f2006-01-02 19:04:38 +01002252 l_ptr->owner->bclink.last_in = mod(msg_last_bcast(msg));
2253 }
2254 break;
2255 case STATE_MSG:
2256
2257 if ((msg_tol = msg_link_tolerance(msg)))
2258 link_set_supervision_props(l_ptr, msg_tol);
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002259
2260 if (msg_linkprio(msg) &&
Per Lidenb97bf3f2006-01-02 19:04:38 +01002261 (msg_linkprio(msg) != l_ptr->priority)) {
Allan Stephensa10bd922006-06-25 23:52:17 -07002262 warn("Resetting link <%s>, priority change %u->%u\n",
Per Lidenb97bf3f2006-01-02 19:04:38 +01002263 l_ptr->name, l_ptr->priority, msg_linkprio(msg));
2264 l_ptr->priority = msg_linkprio(msg);
Per Liden4323add2006-01-18 00:38:21 +01002265 tipc_link_reset(l_ptr); /* Enforce change to take effect */
Per Lidenb97bf3f2006-01-02 19:04:38 +01002266 break;
2267 }
2268 link_state_event(l_ptr, TRAFFIC_MSG_EVT);
2269 l_ptr->stats.recv_states++;
2270 if (link_reset_unknown(l_ptr))
2271 break;
2272
2273 if (less_eq(mod(l_ptr->next_in_no), msg_next_sent(msg))) {
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002274 rec_gap = mod(msg_next_sent(msg) -
Per Lidenb97bf3f2006-01-02 19:04:38 +01002275 mod(l_ptr->next_in_no));
2276 }
2277
2278 max_pkt_ack = msg_max_pkt(msg);
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002279 if (max_pkt_ack > l_ptr->max_pkt) {
2280 dbg("Link <%s> updated MTU %u -> %u\n",
2281 l_ptr->name, l_ptr->max_pkt, max_pkt_ack);
2282 l_ptr->max_pkt = max_pkt_ack;
2283 l_ptr->max_pkt_probes = 0;
2284 }
Per Lidenb97bf3f2006-01-02 19:04:38 +01002285
2286 max_pkt_ack = 0;
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002287 if (msg_probe(msg)) {
Per Lidenb97bf3f2006-01-02 19:04:38 +01002288 l_ptr->stats.recv_probes++;
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002289 if (msg_size(msg) > sizeof(l_ptr->proto_msg)) {
2290 max_pkt_ack = msg_size(msg);
2291 }
2292 }
Per Lidenb97bf3f2006-01-02 19:04:38 +01002293
2294 /* Protocol message before retransmits, reduce loss risk */
2295
Per Liden4323add2006-01-18 00:38:21 +01002296 tipc_bclink_check_gap(l_ptr->owner, msg_last_bcast(msg));
Per Lidenb97bf3f2006-01-02 19:04:38 +01002297
2298 if (rec_gap || (msg_probe(msg))) {
Per Liden4323add2006-01-18 00:38:21 +01002299 tipc_link_send_proto_msg(l_ptr, STATE_MSG,
2300 0, rec_gap, 0, 0, max_pkt_ack);
Per Lidenb97bf3f2006-01-02 19:04:38 +01002301 }
2302 if (msg_seq_gap(msg)) {
2303 msg_dbg(msg, "With Gap:");
2304 l_ptr->stats.recv_nacks++;
Per Liden4323add2006-01-18 00:38:21 +01002305 tipc_link_retransmit(l_ptr, l_ptr->first_out,
2306 msg_seq_gap(msg));
Per Lidenb97bf3f2006-01-02 19:04:38 +01002307 }
2308 break;
2309 default:
2310 msg_dbg(buf_msg(buf), "<DISCARDING UNKNOWN<");
2311 }
2312exit:
2313 buf_discard(buf);
2314}
2315
2316
2317/*
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002318 * tipc_link_tunnel(): Send one message via a link belonging to
Per Lidenb97bf3f2006-01-02 19:04:38 +01002319 * another bearer. Owner node is locked.
2320 */
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002321void tipc_link_tunnel(struct link *l_ptr,
2322 struct tipc_msg *tunnel_hdr,
Per Liden4323add2006-01-18 00:38:21 +01002323 struct tipc_msg *msg,
2324 u32 selector)
Per Lidenb97bf3f2006-01-02 19:04:38 +01002325{
2326 struct link *tunnel;
2327 struct sk_buff *buf;
2328 u32 length = msg_size(msg);
2329
2330 tunnel = l_ptr->owner->active_links[selector & 1];
Allan Stephens5392d642006-06-25 23:52:50 -07002331 if (!tipc_link_is_up(tunnel)) {
2332 warn("Link changeover error, "
2333 "tunnel link no longer available\n");
Per Lidenb97bf3f2006-01-02 19:04:38 +01002334 return;
Allan Stephens5392d642006-06-25 23:52:50 -07002335 }
Per Lidenb97bf3f2006-01-02 19:04:38 +01002336 msg_set_size(tunnel_hdr, length + INT_H_SIZE);
2337 buf = buf_acquire(length + INT_H_SIZE);
Allan Stephens5392d642006-06-25 23:52:50 -07002338 if (!buf) {
2339 warn("Link changeover error, "
2340 "unable to send tunnel msg\n");
Per Lidenb97bf3f2006-01-02 19:04:38 +01002341 return;
Allan Stephens5392d642006-06-25 23:52:50 -07002342 }
Arnaldo Carvalho de Melo27d7ff42007-03-31 11:55:19 -03002343 skb_copy_to_linear_data(buf, tunnel_hdr, INT_H_SIZE);
2344 skb_copy_to_linear_data_offset(buf, INT_H_SIZE, msg, length);
Per Lidenb97bf3f2006-01-02 19:04:38 +01002345 dbg("%c->%c:", l_ptr->b_ptr->net_plane, tunnel->b_ptr->net_plane);
2346 msg_dbg(buf_msg(buf), ">SEND>");
Per Liden4323add2006-01-18 00:38:21 +01002347 tipc_link_send_buf(tunnel, buf);
Per Lidenb97bf3f2006-01-02 19:04:38 +01002348}
2349
2350
2351
2352/*
2353 * changeover(): Send whole message queue via the remaining link
2354 * Owner node is locked.
2355 */
2356
Per Liden4323add2006-01-18 00:38:21 +01002357void tipc_link_changeover(struct link *l_ptr)
Per Lidenb97bf3f2006-01-02 19:04:38 +01002358{
2359 u32 msgcount = l_ptr->out_queue_size;
2360 struct sk_buff *crs = l_ptr->first_out;
2361 struct link *tunnel = l_ptr->owner->active_links[0];
Per Lidenb97bf3f2006-01-02 19:04:38 +01002362 struct tipc_msg tunnel_hdr;
Allan Stephens5392d642006-06-25 23:52:50 -07002363 int split_bundles;
Per Lidenb97bf3f2006-01-02 19:04:38 +01002364
2365 if (!tunnel)
2366 return;
2367
Allan Stephens5392d642006-06-25 23:52:50 -07002368 if (!l_ptr->owner->permit_changeover) {
2369 warn("Link changeover error, "
2370 "peer did not permit changeover\n");
Per Lidenb97bf3f2006-01-02 19:04:38 +01002371 return;
Allan Stephens5392d642006-06-25 23:52:50 -07002372 }
Per Lidenb97bf3f2006-01-02 19:04:38 +01002373
Allan Stephensc68ca7b2010-05-11 14:30:12 +00002374 tipc_msg_init(&tunnel_hdr, CHANGEOVER_PROTOCOL,
Allan Stephens75715212008-06-04 17:37:34 -07002375 ORIGINAL_MSG, INT_H_SIZE, l_ptr->addr);
Per Lidenb97bf3f2006-01-02 19:04:38 +01002376 msg_set_bearer_id(&tunnel_hdr, l_ptr->peer_bearer_id);
2377 msg_set_msgcnt(&tunnel_hdr, msgcount);
Allan Stephens5392d642006-06-25 23:52:50 -07002378 dbg("Link changeover requires %u tunnel messages\n", msgcount);
Allan Stephensf1310722006-06-25 23:51:37 -07002379
Per Lidenb97bf3f2006-01-02 19:04:38 +01002380 if (!l_ptr->first_out) {
2381 struct sk_buff *buf;
2382
Per Lidenb97bf3f2006-01-02 19:04:38 +01002383 buf = buf_acquire(INT_H_SIZE);
2384 if (buf) {
Arnaldo Carvalho de Melo27d7ff42007-03-31 11:55:19 -03002385 skb_copy_to_linear_data(buf, &tunnel_hdr, INT_H_SIZE);
Per Lidenb97bf3f2006-01-02 19:04:38 +01002386 msg_set_size(&tunnel_hdr, INT_H_SIZE);
2387 dbg("%c->%c:", l_ptr->b_ptr->net_plane,
2388 tunnel->b_ptr->net_plane);
2389 msg_dbg(&tunnel_hdr, "EMPTY>SEND>");
Per Liden4323add2006-01-18 00:38:21 +01002390 tipc_link_send_buf(tunnel, buf);
Per Lidenb97bf3f2006-01-02 19:04:38 +01002391 } else {
Allan Stephensa10bd922006-06-25 23:52:17 -07002392 warn("Link changeover error, "
2393 "unable to send changeover msg\n");
Per Lidenb97bf3f2006-01-02 19:04:38 +01002394 }
2395 return;
2396 }
Allan Stephensf1310722006-06-25 23:51:37 -07002397
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002398 split_bundles = (l_ptr->owner->active_links[0] !=
Allan Stephens5392d642006-06-25 23:52:50 -07002399 l_ptr->owner->active_links[1]);
2400
Per Lidenb97bf3f2006-01-02 19:04:38 +01002401 while (crs) {
2402 struct tipc_msg *msg = buf_msg(crs);
2403
2404 if ((msg_user(msg) == MSG_BUNDLER) && split_bundles) {
Per Lidenb97bf3f2006-01-02 19:04:38 +01002405 struct tipc_msg *m = msg_get_wrapped(msg);
2406 unchar* pos = (unchar*)m;
2407
Florian Westphald788d802007-08-02 19:28:06 -07002408 msgcount = msg_msgcnt(msg);
Per Lidenb97bf3f2006-01-02 19:04:38 +01002409 while (msgcount--) {
2410 msg_set_seqno(m,msg_seqno(msg));
Per Liden4323add2006-01-18 00:38:21 +01002411 tipc_link_tunnel(l_ptr, &tunnel_hdr, m,
2412 msg_link_selector(m));
Per Lidenb97bf3f2006-01-02 19:04:38 +01002413 pos += align(msg_size(m));
2414 m = (struct tipc_msg *)pos;
2415 }
2416 } else {
Per Liden4323add2006-01-18 00:38:21 +01002417 tipc_link_tunnel(l_ptr, &tunnel_hdr, msg,
2418 msg_link_selector(msg));
Per Lidenb97bf3f2006-01-02 19:04:38 +01002419 }
2420 crs = crs->next;
2421 }
2422}
2423
Per Liden4323add2006-01-18 00:38:21 +01002424void tipc_link_send_duplicate(struct link *l_ptr, struct link *tunnel)
Per Lidenb97bf3f2006-01-02 19:04:38 +01002425{
2426 struct sk_buff *iter;
2427 struct tipc_msg tunnel_hdr;
2428
Allan Stephensc68ca7b2010-05-11 14:30:12 +00002429 tipc_msg_init(&tunnel_hdr, CHANGEOVER_PROTOCOL,
Allan Stephens75715212008-06-04 17:37:34 -07002430 DUPLICATE_MSG, INT_H_SIZE, l_ptr->addr);
Per Lidenb97bf3f2006-01-02 19:04:38 +01002431 msg_set_msgcnt(&tunnel_hdr, l_ptr->out_queue_size);
2432 msg_set_bearer_id(&tunnel_hdr, l_ptr->peer_bearer_id);
2433 iter = l_ptr->first_out;
2434 while (iter) {
2435 struct sk_buff *outbuf;
2436 struct tipc_msg *msg = buf_msg(iter);
2437 u32 length = msg_size(msg);
2438
2439 if (msg_user(msg) == MSG_BUNDLER)
2440 msg_set_type(msg, CLOSED_MSG);
2441 msg_set_ack(msg, mod(l_ptr->next_in_no - 1)); /* Update */
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002442 msg_set_bcast_ack(msg, l_ptr->owner->bclink.last_in);
Per Lidenb97bf3f2006-01-02 19:04:38 +01002443 msg_set_size(&tunnel_hdr, length + INT_H_SIZE);
2444 outbuf = buf_acquire(length + INT_H_SIZE);
2445 if (outbuf == NULL) {
Allan Stephensa10bd922006-06-25 23:52:17 -07002446 warn("Link changeover error, "
2447 "unable to send duplicate msg\n");
Per Lidenb97bf3f2006-01-02 19:04:38 +01002448 return;
2449 }
Arnaldo Carvalho de Melo27d7ff42007-03-31 11:55:19 -03002450 skb_copy_to_linear_data(outbuf, &tunnel_hdr, INT_H_SIZE);
2451 skb_copy_to_linear_data_offset(outbuf, INT_H_SIZE, iter->data,
2452 length);
Per Lidenb97bf3f2006-01-02 19:04:38 +01002453 dbg("%c->%c:", l_ptr->b_ptr->net_plane,
2454 tunnel->b_ptr->net_plane);
2455 msg_dbg(buf_msg(outbuf), ">SEND>");
Per Liden4323add2006-01-18 00:38:21 +01002456 tipc_link_send_buf(tunnel, outbuf);
2457 if (!tipc_link_is_up(l_ptr))
Per Lidenb97bf3f2006-01-02 19:04:38 +01002458 return;
2459 iter = iter->next;
2460 }
2461}
2462
2463
2464
2465/**
2466 * buf_extract - extracts embedded TIPC message from another message
2467 * @skb: encapsulating message buffer
2468 * @from_pos: offset to extract from
2469 *
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002470 * Returns a new message buffer containing an embedded message. The
Per Lidenb97bf3f2006-01-02 19:04:38 +01002471 * encapsulating message itself is left unchanged.
2472 */
2473
2474static struct sk_buff *buf_extract(struct sk_buff *skb, u32 from_pos)
2475{
2476 struct tipc_msg *msg = (struct tipc_msg *)(skb->data + from_pos);
2477 u32 size = msg_size(msg);
2478 struct sk_buff *eb;
2479
2480 eb = buf_acquire(size);
2481 if (eb)
Arnaldo Carvalho de Melo27d7ff42007-03-31 11:55:19 -03002482 skb_copy_to_linear_data(eb, msg, size);
Per Lidenb97bf3f2006-01-02 19:04:38 +01002483 return eb;
2484}
2485
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002486/*
Per Lidenb97bf3f2006-01-02 19:04:38 +01002487 * link_recv_changeover_msg(): Receive tunneled packet sent
2488 * via other link. Node is locked. Return extracted buffer.
2489 */
2490
2491static int link_recv_changeover_msg(struct link **l_ptr,
2492 struct sk_buff **buf)
2493{
2494 struct sk_buff *tunnel_buf = *buf;
2495 struct link *dest_link;
2496 struct tipc_msg *msg;
2497 struct tipc_msg *tunnel_msg = buf_msg(tunnel_buf);
2498 u32 msg_typ = msg_type(tunnel_msg);
2499 u32 msg_count = msg_msgcnt(tunnel_msg);
2500
2501 dest_link = (*l_ptr)->owner->links[msg_bearer_id(tunnel_msg)];
Per Lidenb97bf3f2006-01-02 19:04:38 +01002502 if (!dest_link) {
2503 msg_dbg(tunnel_msg, "NOLINK/<REC<");
2504 goto exit;
2505 }
Allan Stephensf1310722006-06-25 23:51:37 -07002506 if (dest_link == *l_ptr) {
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002507 err("Unexpected changeover message on link <%s>\n",
Allan Stephensf1310722006-06-25 23:51:37 -07002508 (*l_ptr)->name);
2509 goto exit;
2510 }
Per Lidenb97bf3f2006-01-02 19:04:38 +01002511 dbg("%c<-%c:", dest_link->b_ptr->net_plane,
2512 (*l_ptr)->b_ptr->net_plane);
2513 *l_ptr = dest_link;
2514 msg = msg_get_wrapped(tunnel_msg);
2515
2516 if (msg_typ == DUPLICATE_MSG) {
2517 if (less(msg_seqno(msg), mod(dest_link->next_in_no))) {
2518 msg_dbg(tunnel_msg, "DROP/<REC<");
2519 goto exit;
2520 }
2521 *buf = buf_extract(tunnel_buf,INT_H_SIZE);
2522 if (*buf == NULL) {
Allan Stephensa10bd922006-06-25 23:52:17 -07002523 warn("Link changeover error, duplicate msg dropped\n");
Per Lidenb97bf3f2006-01-02 19:04:38 +01002524 goto exit;
2525 }
2526 msg_dbg(tunnel_msg, "TNL<REC<");
2527 buf_discard(tunnel_buf);
2528 return 1;
2529 }
2530
2531 /* First original message ?: */
2532
Per Liden4323add2006-01-18 00:38:21 +01002533 if (tipc_link_is_up(dest_link)) {
Per Lidenb97bf3f2006-01-02 19:04:38 +01002534 msg_dbg(tunnel_msg, "UP/FIRST/<REC<");
Allan Stephensa10bd922006-06-25 23:52:17 -07002535 info("Resetting link <%s>, changeover initiated by peer\n",
2536 dest_link->name);
Per Liden4323add2006-01-18 00:38:21 +01002537 tipc_link_reset(dest_link);
Per Lidenb97bf3f2006-01-02 19:04:38 +01002538 dest_link->exp_msg_count = msg_count;
Allan Stephens5392d642006-06-25 23:52:50 -07002539 dbg("Expecting %u tunnelled messages\n", msg_count);
Per Lidenb97bf3f2006-01-02 19:04:38 +01002540 if (!msg_count)
2541 goto exit;
2542 } else if (dest_link->exp_msg_count == START_CHANGEOVER) {
2543 msg_dbg(tunnel_msg, "BLK/FIRST/<REC<");
2544 dest_link->exp_msg_count = msg_count;
Allan Stephens5392d642006-06-25 23:52:50 -07002545 dbg("Expecting %u tunnelled messages\n", msg_count);
Per Lidenb97bf3f2006-01-02 19:04:38 +01002546 if (!msg_count)
2547 goto exit;
2548 }
2549
2550 /* Receive original message */
2551
2552 if (dest_link->exp_msg_count == 0) {
Allan Stephens5392d642006-06-25 23:52:50 -07002553 warn("Link switchover error, "
2554 "got too many tunnelled messages\n");
Per Lidenb97bf3f2006-01-02 19:04:38 +01002555 msg_dbg(tunnel_msg, "OVERDUE/DROP/<REC<");
2556 dbg_print_link(dest_link, "LINK:");
2557 goto exit;
2558 }
2559 dest_link->exp_msg_count--;
2560 if (less(msg_seqno(msg), dest_link->reset_checkpoint)) {
2561 msg_dbg(tunnel_msg, "DROP/DUPL/<REC<");
2562 goto exit;
2563 } else {
2564 *buf = buf_extract(tunnel_buf, INT_H_SIZE);
2565 if (*buf != NULL) {
2566 msg_dbg(tunnel_msg, "TNL<REC<");
2567 buf_discard(tunnel_buf);
2568 return 1;
2569 } else {
Allan Stephensa10bd922006-06-25 23:52:17 -07002570 warn("Link changeover error, original msg dropped\n");
Per Lidenb97bf3f2006-01-02 19:04:38 +01002571 }
2572 }
2573exit:
Sam Ravnborg1fc54d82006-03-20 22:36:47 -08002574 *buf = NULL;
Per Lidenb97bf3f2006-01-02 19:04:38 +01002575 buf_discard(tunnel_buf);
2576 return 0;
2577}
2578
2579/*
2580 * Bundler functionality:
2581 */
Per Liden4323add2006-01-18 00:38:21 +01002582void tipc_link_recv_bundle(struct sk_buff *buf)
Per Lidenb97bf3f2006-01-02 19:04:38 +01002583{
2584 u32 msgcount = msg_msgcnt(buf_msg(buf));
2585 u32 pos = INT_H_SIZE;
2586 struct sk_buff *obuf;
2587
2588 msg_dbg(buf_msg(buf), "<BNDL<: ");
2589 while (msgcount--) {
2590 obuf = buf_extract(buf, pos);
2591 if (obuf == NULL) {
Allan Stephensa10bd922006-06-25 23:52:17 -07002592 warn("Link unable to unbundle message(s)\n");
2593 break;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -07002594 }
Per Lidenb97bf3f2006-01-02 19:04:38 +01002595 pos += align(msg_size(buf_msg(obuf)));
2596 msg_dbg(buf_msg(obuf), " /");
Per Liden4323add2006-01-18 00:38:21 +01002597 tipc_net_route_msg(obuf);
Per Lidenb97bf3f2006-01-02 19:04:38 +01002598 }
2599 buf_discard(buf);
2600}
2601
2602/*
2603 * Fragmentation/defragmentation:
2604 */
2605
2606
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002607/*
Per Liden4323add2006-01-18 00:38:21 +01002608 * tipc_link_send_long_buf: Entry for buffers needing fragmentation.
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002609 * The buffer is complete, inclusive total message length.
Per Lidenb97bf3f2006-01-02 19:04:38 +01002610 * Returns user data length.
2611 */
Per Liden4323add2006-01-18 00:38:21 +01002612int tipc_link_send_long_buf(struct link *l_ptr, struct sk_buff *buf)
Per Lidenb97bf3f2006-01-02 19:04:38 +01002613{
2614 struct tipc_msg *inmsg = buf_msg(buf);
2615 struct tipc_msg fragm_hdr;
2616 u32 insize = msg_size(inmsg);
2617 u32 dsz = msg_data_sz(inmsg);
2618 unchar *crs = buf->data;
2619 u32 rest = insize;
Allan Stephens15e979d2010-05-11 14:30:10 +00002620 u32 pack_sz = l_ptr->max_pkt;
Per Lidenb97bf3f2006-01-02 19:04:38 +01002621 u32 fragm_sz = pack_sz - INT_H_SIZE;
2622 u32 fragm_no = 1;
Allan Stephens9c396a72008-06-04 17:36:58 -07002623 u32 destaddr;
Per Lidenb97bf3f2006-01-02 19:04:38 +01002624
2625 if (msg_short(inmsg))
2626 destaddr = l_ptr->addr;
Allan Stephens9c396a72008-06-04 17:36:58 -07002627 else
2628 destaddr = msg_destnode(inmsg);
Per Lidenb97bf3f2006-01-02 19:04:38 +01002629
2630 if (msg_routed(inmsg))
2631 msg_set_prevnode(inmsg, tipc_own_addr);
2632
2633 /* Prepare reusable fragment header: */
2634
Allan Stephensc68ca7b2010-05-11 14:30:12 +00002635 tipc_msg_init(&fragm_hdr, MSG_FRAGMENTER, FIRST_FRAGMENT,
Allan Stephens75715212008-06-04 17:37:34 -07002636 INT_H_SIZE, destaddr);
Per Lidenb97bf3f2006-01-02 19:04:38 +01002637 msg_set_link_selector(&fragm_hdr, msg_link_selector(inmsg));
2638 msg_set_long_msgno(&fragm_hdr, mod(l_ptr->long_msg_seq_no++));
2639 msg_set_fragm_no(&fragm_hdr, fragm_no);
2640 l_ptr->stats.sent_fragmented++;
2641
2642 /* Chop up message: */
2643
2644 while (rest > 0) {
2645 struct sk_buff *fragm;
2646
2647 if (rest <= fragm_sz) {
2648 fragm_sz = rest;
2649 msg_set_type(&fragm_hdr, LAST_FRAGMENT);
2650 }
2651 fragm = buf_acquire(fragm_sz + INT_H_SIZE);
2652 if (fragm == NULL) {
Allan Stephensa10bd922006-06-25 23:52:17 -07002653 warn("Link unable to fragment message\n");
Per Lidenb97bf3f2006-01-02 19:04:38 +01002654 dsz = -ENOMEM;
2655 goto exit;
2656 }
2657 msg_set_size(&fragm_hdr, fragm_sz + INT_H_SIZE);
Arnaldo Carvalho de Melo27d7ff42007-03-31 11:55:19 -03002658 skb_copy_to_linear_data(fragm, &fragm_hdr, INT_H_SIZE);
2659 skb_copy_to_linear_data_offset(fragm, INT_H_SIZE, crs,
2660 fragm_sz);
Per Lidenb97bf3f2006-01-02 19:04:38 +01002661 /* Send queued messages first, if any: */
2662
2663 l_ptr->stats.sent_fragments++;
Per Liden4323add2006-01-18 00:38:21 +01002664 tipc_link_send_buf(l_ptr, fragm);
2665 if (!tipc_link_is_up(l_ptr))
Per Lidenb97bf3f2006-01-02 19:04:38 +01002666 return dsz;
2667 msg_set_fragm_no(&fragm_hdr, ++fragm_no);
2668 rest -= fragm_sz;
2669 crs += fragm_sz;
2670 msg_set_type(&fragm_hdr, FRAGMENT);
2671 }
2672exit:
2673 buf_discard(buf);
2674 return dsz;
2675}
2676
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002677/*
2678 * A pending message being re-assembled must store certain values
2679 * to handle subsequent fragments correctly. The following functions
Per Lidenb97bf3f2006-01-02 19:04:38 +01002680 * help storing these values in unused, available fields in the
2681 * pending message. This makes dynamic memory allocation unecessary.
2682 */
2683
Sam Ravnborg05790c62006-03-20 22:37:04 -08002684static void set_long_msg_seqno(struct sk_buff *buf, u32 seqno)
Per Lidenb97bf3f2006-01-02 19:04:38 +01002685{
2686 msg_set_seqno(buf_msg(buf), seqno);
2687}
2688
Sam Ravnborg05790c62006-03-20 22:37:04 -08002689static u32 get_fragm_size(struct sk_buff *buf)
Per Lidenb97bf3f2006-01-02 19:04:38 +01002690{
2691 return msg_ack(buf_msg(buf));
2692}
2693
Sam Ravnborg05790c62006-03-20 22:37:04 -08002694static void set_fragm_size(struct sk_buff *buf, u32 sz)
Per Lidenb97bf3f2006-01-02 19:04:38 +01002695{
2696 msg_set_ack(buf_msg(buf), sz);
2697}
2698
Sam Ravnborg05790c62006-03-20 22:37:04 -08002699static u32 get_expected_frags(struct sk_buff *buf)
Per Lidenb97bf3f2006-01-02 19:04:38 +01002700{
2701 return msg_bcast_ack(buf_msg(buf));
2702}
2703
Sam Ravnborg05790c62006-03-20 22:37:04 -08002704static void set_expected_frags(struct sk_buff *buf, u32 exp)
Per Lidenb97bf3f2006-01-02 19:04:38 +01002705{
2706 msg_set_bcast_ack(buf_msg(buf), exp);
2707}
2708
Sam Ravnborg05790c62006-03-20 22:37:04 -08002709static u32 get_timer_cnt(struct sk_buff *buf)
Per Lidenb97bf3f2006-01-02 19:04:38 +01002710{
2711 return msg_reroute_cnt(buf_msg(buf));
2712}
2713
Sam Ravnborg05790c62006-03-20 22:37:04 -08002714static void incr_timer_cnt(struct sk_buff *buf)
Per Lidenb97bf3f2006-01-02 19:04:38 +01002715{
2716 msg_incr_reroute_cnt(buf_msg(buf));
2717}
2718
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002719/*
2720 * tipc_link_recv_fragment(): Called with node lock on. Returns
Per Lidenb97bf3f2006-01-02 19:04:38 +01002721 * the reassembled buffer if message is complete.
2722 */
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002723int tipc_link_recv_fragment(struct sk_buff **pending, struct sk_buff **fb,
Per Liden4323add2006-01-18 00:38:21 +01002724 struct tipc_msg **m)
Per Lidenb97bf3f2006-01-02 19:04:38 +01002725{
Sam Ravnborg1fc54d82006-03-20 22:36:47 -08002726 struct sk_buff *prev = NULL;
Per Lidenb97bf3f2006-01-02 19:04:38 +01002727 struct sk_buff *fbuf = *fb;
2728 struct tipc_msg *fragm = buf_msg(fbuf);
2729 struct sk_buff *pbuf = *pending;
2730 u32 long_msg_seq_no = msg_long_msgno(fragm);
2731
Sam Ravnborg1fc54d82006-03-20 22:36:47 -08002732 *fb = NULL;
Per Lidenb97bf3f2006-01-02 19:04:38 +01002733 msg_dbg(fragm,"FRG<REC<");
2734
2735 /* Is there an incomplete message waiting for this fragment? */
2736
Joe Perchesf64f9e72009-11-29 16:55:45 -08002737 while (pbuf && ((msg_seqno(buf_msg(pbuf)) != long_msg_seq_no) ||
2738 (msg_orignode(fragm) != msg_orignode(buf_msg(pbuf))))) {
Per Lidenb97bf3f2006-01-02 19:04:38 +01002739 prev = pbuf;
2740 pbuf = pbuf->next;
2741 }
2742
2743 if (!pbuf && (msg_type(fragm) == FIRST_FRAGMENT)) {
2744 struct tipc_msg *imsg = (struct tipc_msg *)msg_data(fragm);
2745 u32 msg_sz = msg_size(imsg);
2746 u32 fragm_sz = msg_data_sz(fragm);
2747 u32 exp_fragm_cnt = msg_sz/fragm_sz + !!(msg_sz % fragm_sz);
2748 u32 max = TIPC_MAX_USER_MSG_SIZE + LONG_H_SIZE;
2749 if (msg_type(imsg) == TIPC_MCAST_MSG)
2750 max = TIPC_MAX_USER_MSG_SIZE + MCAST_H_SIZE;
2751 if (msg_size(imsg) > max) {
2752 msg_dbg(fragm,"<REC<Oversized: ");
2753 buf_discard(fbuf);
2754 return 0;
2755 }
2756 pbuf = buf_acquire(msg_size(imsg));
2757 if (pbuf != NULL) {
2758 pbuf->next = *pending;
2759 *pending = pbuf;
Arnaldo Carvalho de Melo27d7ff42007-03-31 11:55:19 -03002760 skb_copy_to_linear_data(pbuf, imsg,
2761 msg_data_sz(fragm));
Per Lidenb97bf3f2006-01-02 19:04:38 +01002762 /* Prepare buffer for subsequent fragments. */
2763
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002764 set_long_msg_seqno(pbuf, long_msg_seq_no);
2765 set_fragm_size(pbuf,fragm_sz);
2766 set_expected_frags(pbuf,exp_fragm_cnt - 1);
Per Lidenb97bf3f2006-01-02 19:04:38 +01002767 } else {
Allan Stephensa10bd922006-06-25 23:52:17 -07002768 warn("Link unable to reassemble fragmented message\n");
Per Lidenb97bf3f2006-01-02 19:04:38 +01002769 }
2770 buf_discard(fbuf);
2771 return 0;
2772 } else if (pbuf && (msg_type(fragm) != FIRST_FRAGMENT)) {
2773 u32 dsz = msg_data_sz(fragm);
2774 u32 fsz = get_fragm_size(pbuf);
2775 u32 crs = ((msg_fragm_no(fragm) - 1) * fsz);
2776 u32 exp_frags = get_expected_frags(pbuf) - 1;
Arnaldo Carvalho de Melo27d7ff42007-03-31 11:55:19 -03002777 skb_copy_to_linear_data_offset(pbuf, crs,
2778 msg_data(fragm), dsz);
Per Lidenb97bf3f2006-01-02 19:04:38 +01002779 buf_discard(fbuf);
2780
2781 /* Is message complete? */
2782
2783 if (exp_frags == 0) {
2784 if (prev)
2785 prev->next = pbuf->next;
2786 else
2787 *pending = pbuf->next;
2788 msg_reset_reroute_cnt(buf_msg(pbuf));
2789 *fb = pbuf;
2790 *m = buf_msg(pbuf);
2791 return 1;
2792 }
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002793 set_expected_frags(pbuf,exp_frags);
Per Lidenb97bf3f2006-01-02 19:04:38 +01002794 return 0;
2795 }
2796 dbg(" Discarding orphan fragment %x\n",fbuf);
2797 msg_dbg(fragm,"ORPHAN:");
2798 dbg("Pending long buffers:\n");
2799 dbg_print_buf_chain(*pending);
2800 buf_discard(fbuf);
2801 return 0;
2802}
2803
2804/**
2805 * link_check_defragm_bufs - flush stale incoming message fragments
2806 * @l_ptr: pointer to link
2807 */
2808
2809static void link_check_defragm_bufs(struct link *l_ptr)
2810{
Sam Ravnborg1fc54d82006-03-20 22:36:47 -08002811 struct sk_buff *prev = NULL;
2812 struct sk_buff *next = NULL;
Per Lidenb97bf3f2006-01-02 19:04:38 +01002813 struct sk_buff *buf = l_ptr->defragm_buf;
2814
2815 if (!buf)
2816 return;
2817 if (!link_working_working(l_ptr))
2818 return;
2819 while (buf) {
2820 u32 cnt = get_timer_cnt(buf);
2821
2822 next = buf->next;
2823 if (cnt < 4) {
2824 incr_timer_cnt(buf);
2825 prev = buf;
2826 } else {
2827 dbg(" Discarding incomplete long buffer\n");
2828 msg_dbg(buf_msg(buf), "LONG:");
2829 dbg_print_link(l_ptr, "curr:");
2830 dbg("Pending long buffers:\n");
2831 dbg_print_buf_chain(l_ptr->defragm_buf);
2832 if (prev)
2833 prev->next = buf->next;
2834 else
2835 l_ptr->defragm_buf = buf->next;
2836 buf_discard(buf);
2837 }
2838 buf = next;
2839 }
2840}
2841
2842
2843
2844static void link_set_supervision_props(struct link *l_ptr, u32 tolerance)
2845{
2846 l_ptr->tolerance = tolerance;
2847 l_ptr->continuity_interval =
2848 ((tolerance / 4) > 500) ? 500 : tolerance / 4;
2849 l_ptr->abort_limit = tolerance / (l_ptr->continuity_interval / 4);
2850}
2851
2852
Per Liden4323add2006-01-18 00:38:21 +01002853void tipc_link_set_queue_limits(struct link *l_ptr, u32 window)
Per Lidenb97bf3f2006-01-02 19:04:38 +01002854{
2855 /* Data messages from this node, inclusive FIRST_FRAGM */
Allan Stephens06d82c92008-03-06 15:06:55 -08002856 l_ptr->queue_limit[TIPC_LOW_IMPORTANCE] = window;
2857 l_ptr->queue_limit[TIPC_MEDIUM_IMPORTANCE] = (window / 3) * 4;
2858 l_ptr->queue_limit[TIPC_HIGH_IMPORTANCE] = (window / 3) * 5;
2859 l_ptr->queue_limit[TIPC_CRITICAL_IMPORTANCE] = (window / 3) * 6;
Per Lidenb97bf3f2006-01-02 19:04:38 +01002860 /* Transiting data messages,inclusive FIRST_FRAGM */
Allan Stephens06d82c92008-03-06 15:06:55 -08002861 l_ptr->queue_limit[TIPC_LOW_IMPORTANCE + 4] = 300;
2862 l_ptr->queue_limit[TIPC_MEDIUM_IMPORTANCE + 4] = 600;
2863 l_ptr->queue_limit[TIPC_HIGH_IMPORTANCE + 4] = 900;
2864 l_ptr->queue_limit[TIPC_CRITICAL_IMPORTANCE + 4] = 1200;
Per Lidenb97bf3f2006-01-02 19:04:38 +01002865 l_ptr->queue_limit[CONN_MANAGER] = 1200;
2866 l_ptr->queue_limit[ROUTE_DISTRIBUTOR] = 1200;
2867 l_ptr->queue_limit[CHANGEOVER_PROTOCOL] = 2500;
2868 l_ptr->queue_limit[NAME_DISTRIBUTOR] = 3000;
2869 /* FRAGMENT and LAST_FRAGMENT packets */
2870 l_ptr->queue_limit[MSG_FRAGMENTER] = 4000;
2871}
2872
2873/**
2874 * link_find_link - locate link by name
2875 * @name - ptr to link name string
2876 * @node - ptr to area to be filled with ptr to associated node
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002877 *
Per Liden4323add2006-01-18 00:38:21 +01002878 * Caller must hold 'tipc_net_lock' to ensure node and bearer are not deleted;
Per Lidenb97bf3f2006-01-02 19:04:38 +01002879 * this also prevents link deletion.
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002880 *
Per Lidenb97bf3f2006-01-02 19:04:38 +01002881 * Returns pointer to link (or 0 if invalid link name).
2882 */
2883
David S. Miller6c000552008-09-02 23:38:32 -07002884static struct link *link_find_link(const char *name, struct tipc_node **node)
Per Lidenb97bf3f2006-01-02 19:04:38 +01002885{
2886 struct link_name link_name_parts;
2887 struct bearer *b_ptr;
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002888 struct link *l_ptr;
Per Lidenb97bf3f2006-01-02 19:04:38 +01002889
2890 if (!link_name_validate(name, &link_name_parts))
Sam Ravnborg1fc54d82006-03-20 22:36:47 -08002891 return NULL;
Per Lidenb97bf3f2006-01-02 19:04:38 +01002892
Per Liden4323add2006-01-18 00:38:21 +01002893 b_ptr = tipc_bearer_find_interface(link_name_parts.if_local);
Per Lidenb97bf3f2006-01-02 19:04:38 +01002894 if (!b_ptr)
Sam Ravnborg1fc54d82006-03-20 22:36:47 -08002895 return NULL;
Per Lidenb97bf3f2006-01-02 19:04:38 +01002896
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002897 *node = tipc_node_find(link_name_parts.addr_peer);
Per Lidenb97bf3f2006-01-02 19:04:38 +01002898 if (!*node)
Sam Ravnborg1fc54d82006-03-20 22:36:47 -08002899 return NULL;
Per Lidenb97bf3f2006-01-02 19:04:38 +01002900
2901 l_ptr = (*node)->links[b_ptr->identity];
2902 if (!l_ptr || strcmp(l_ptr->name, name))
Sam Ravnborg1fc54d82006-03-20 22:36:47 -08002903 return NULL;
Per Lidenb97bf3f2006-01-02 19:04:38 +01002904
2905 return l_ptr;
2906}
2907
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002908struct sk_buff *tipc_link_cmd_config(const void *req_tlv_area, int req_tlv_space,
Per Liden4323add2006-01-18 00:38:21 +01002909 u16 cmd)
Per Lidenb97bf3f2006-01-02 19:04:38 +01002910{
2911 struct tipc_link_config *args;
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002912 u32 new_value;
Per Lidenb97bf3f2006-01-02 19:04:38 +01002913 struct link *l_ptr;
David S. Miller6c000552008-09-02 23:38:32 -07002914 struct tipc_node *node;
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002915 int res;
Per Lidenb97bf3f2006-01-02 19:04:38 +01002916
2917 if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_LINK_CONFIG))
Per Liden4323add2006-01-18 00:38:21 +01002918 return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
Per Lidenb97bf3f2006-01-02 19:04:38 +01002919
2920 args = (struct tipc_link_config *)TLV_DATA(req_tlv_area);
2921 new_value = ntohl(args->value);
2922
Per Liden4323add2006-01-18 00:38:21 +01002923 if (!strcmp(args->name, tipc_bclink_name)) {
Per Lidenb97bf3f2006-01-02 19:04:38 +01002924 if ((cmd == TIPC_CMD_SET_LINK_WINDOW) &&
Per Liden4323add2006-01-18 00:38:21 +01002925 (tipc_bclink_set_queue_limits(new_value) == 0))
2926 return tipc_cfg_reply_none();
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002927 return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
Per Liden4323add2006-01-18 00:38:21 +01002928 " (cannot change setting on broadcast link)");
Per Lidenb97bf3f2006-01-02 19:04:38 +01002929 }
2930
Per Liden4323add2006-01-18 00:38:21 +01002931 read_lock_bh(&tipc_net_lock);
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002932 l_ptr = link_find_link(args->name, &node);
Per Lidenb97bf3f2006-01-02 19:04:38 +01002933 if (!l_ptr) {
Per Liden4323add2006-01-18 00:38:21 +01002934 read_unlock_bh(&tipc_net_lock);
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002935 return tipc_cfg_reply_error_string("link not found");
Per Lidenb97bf3f2006-01-02 19:04:38 +01002936 }
2937
Per Liden4323add2006-01-18 00:38:21 +01002938 tipc_node_lock(node);
Per Lidenb97bf3f2006-01-02 19:04:38 +01002939 res = -EINVAL;
2940 switch (cmd) {
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002941 case TIPC_CMD_SET_LINK_TOL:
2942 if ((new_value >= TIPC_MIN_LINK_TOL) &&
Per Lidenb97bf3f2006-01-02 19:04:38 +01002943 (new_value <= TIPC_MAX_LINK_TOL)) {
2944 link_set_supervision_props(l_ptr, new_value);
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002945 tipc_link_send_proto_msg(l_ptr, STATE_MSG,
Per Liden4323add2006-01-18 00:38:21 +01002946 0, 0, new_value, 0, 0);
Allan Stephens0e35fd52008-07-14 22:44:01 -07002947 res = 0;
Per Lidenb97bf3f2006-01-02 19:04:38 +01002948 }
2949 break;
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002950 case TIPC_CMD_SET_LINK_PRI:
Per Liden16cb4b32006-01-13 22:22:22 +01002951 if ((new_value >= TIPC_MIN_LINK_PRI) &&
2952 (new_value <= TIPC_MAX_LINK_PRI)) {
Per Lidenb97bf3f2006-01-02 19:04:38 +01002953 l_ptr->priority = new_value;
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002954 tipc_link_send_proto_msg(l_ptr, STATE_MSG,
Per Liden4323add2006-01-18 00:38:21 +01002955 0, 0, 0, new_value, 0);
Allan Stephens0e35fd52008-07-14 22:44:01 -07002956 res = 0;
Per Lidenb97bf3f2006-01-02 19:04:38 +01002957 }
2958 break;
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002959 case TIPC_CMD_SET_LINK_WINDOW:
2960 if ((new_value >= TIPC_MIN_LINK_WIN) &&
Per Lidenb97bf3f2006-01-02 19:04:38 +01002961 (new_value <= TIPC_MAX_LINK_WIN)) {
Per Liden4323add2006-01-18 00:38:21 +01002962 tipc_link_set_queue_limits(l_ptr, new_value);
Allan Stephens0e35fd52008-07-14 22:44:01 -07002963 res = 0;
Per Lidenb97bf3f2006-01-02 19:04:38 +01002964 }
2965 break;
2966 }
Per Liden4323add2006-01-18 00:38:21 +01002967 tipc_node_unlock(node);
Per Lidenb97bf3f2006-01-02 19:04:38 +01002968
Per Liden4323add2006-01-18 00:38:21 +01002969 read_unlock_bh(&tipc_net_lock);
Per Lidenb97bf3f2006-01-02 19:04:38 +01002970 if (res)
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002971 return tipc_cfg_reply_error_string("cannot change link setting");
Per Lidenb97bf3f2006-01-02 19:04:38 +01002972
Per Liden4323add2006-01-18 00:38:21 +01002973 return tipc_cfg_reply_none();
Per Lidenb97bf3f2006-01-02 19:04:38 +01002974}
2975
2976/**
2977 * link_reset_statistics - reset link statistics
2978 * @l_ptr: pointer to link
2979 */
2980
2981static void link_reset_statistics(struct link *l_ptr)
2982{
2983 memset(&l_ptr->stats, 0, sizeof(l_ptr->stats));
2984 l_ptr->stats.sent_info = l_ptr->next_out_no;
2985 l_ptr->stats.recv_info = l_ptr->next_in_no;
2986}
2987
Per Liden4323add2006-01-18 00:38:21 +01002988struct sk_buff *tipc_link_cmd_reset_stats(const void *req_tlv_area, int req_tlv_space)
Per Lidenb97bf3f2006-01-02 19:04:38 +01002989{
2990 char *link_name;
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002991 struct link *l_ptr;
David S. Miller6c000552008-09-02 23:38:32 -07002992 struct tipc_node *node;
Per Lidenb97bf3f2006-01-02 19:04:38 +01002993
2994 if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_LINK_NAME))
Per Liden4323add2006-01-18 00:38:21 +01002995 return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
Per Lidenb97bf3f2006-01-02 19:04:38 +01002996
2997 link_name = (char *)TLV_DATA(req_tlv_area);
Per Liden4323add2006-01-18 00:38:21 +01002998 if (!strcmp(link_name, tipc_bclink_name)) {
2999 if (tipc_bclink_reset_stats())
3000 return tipc_cfg_reply_error_string("link not found");
3001 return tipc_cfg_reply_none();
Per Lidenb97bf3f2006-01-02 19:04:38 +01003002 }
3003
Per Liden4323add2006-01-18 00:38:21 +01003004 read_lock_bh(&tipc_net_lock);
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09003005 l_ptr = link_find_link(link_name, &node);
Per Lidenb97bf3f2006-01-02 19:04:38 +01003006 if (!l_ptr) {
Per Liden4323add2006-01-18 00:38:21 +01003007 read_unlock_bh(&tipc_net_lock);
3008 return tipc_cfg_reply_error_string("link not found");
Per Lidenb97bf3f2006-01-02 19:04:38 +01003009 }
3010
Per Liden4323add2006-01-18 00:38:21 +01003011 tipc_node_lock(node);
Per Lidenb97bf3f2006-01-02 19:04:38 +01003012 link_reset_statistics(l_ptr);
Per Liden4323add2006-01-18 00:38:21 +01003013 tipc_node_unlock(node);
3014 read_unlock_bh(&tipc_net_lock);
3015 return tipc_cfg_reply_none();
Per Lidenb97bf3f2006-01-02 19:04:38 +01003016}
3017
3018/**
3019 * percent - convert count to a percentage of total (rounding up or down)
3020 */
3021
3022static u32 percent(u32 count, u32 total)
3023{
3024 return (count * 100 + (total / 2)) / total;
3025}
3026
3027/**
Per Liden4323add2006-01-18 00:38:21 +01003028 * tipc_link_stats - print link statistics
Per Lidenb97bf3f2006-01-02 19:04:38 +01003029 * @name: link name
3030 * @buf: print buffer area
3031 * @buf_size: size of print buffer area
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09003032 *
Per Lidenb97bf3f2006-01-02 19:04:38 +01003033 * Returns length of print buffer data string (or 0 if error)
3034 */
3035
Per Liden4323add2006-01-18 00:38:21 +01003036static int tipc_link_stats(const char *name, char *buf, const u32 buf_size)
Per Lidenb97bf3f2006-01-02 19:04:38 +01003037{
3038 struct print_buf pb;
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09003039 struct link *l_ptr;
David S. Miller6c000552008-09-02 23:38:32 -07003040 struct tipc_node *node;
Per Lidenb97bf3f2006-01-02 19:04:38 +01003041 char *status;
3042 u32 profile_total = 0;
3043
Per Liden4323add2006-01-18 00:38:21 +01003044 if (!strcmp(name, tipc_bclink_name))
3045 return tipc_bclink_stats(buf, buf_size);
Per Lidenb97bf3f2006-01-02 19:04:38 +01003046
Per Liden4323add2006-01-18 00:38:21 +01003047 tipc_printbuf_init(&pb, buf, buf_size);
Per Lidenb97bf3f2006-01-02 19:04:38 +01003048
Per Liden4323add2006-01-18 00:38:21 +01003049 read_lock_bh(&tipc_net_lock);
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09003050 l_ptr = link_find_link(name, &node);
Per Lidenb97bf3f2006-01-02 19:04:38 +01003051 if (!l_ptr) {
Per Liden4323add2006-01-18 00:38:21 +01003052 read_unlock_bh(&tipc_net_lock);
Per Lidenb97bf3f2006-01-02 19:04:38 +01003053 return 0;
3054 }
Per Liden4323add2006-01-18 00:38:21 +01003055 tipc_node_lock(node);
Per Lidenb97bf3f2006-01-02 19:04:38 +01003056
Per Liden4323add2006-01-18 00:38:21 +01003057 if (tipc_link_is_active(l_ptr))
Per Lidenb97bf3f2006-01-02 19:04:38 +01003058 status = "ACTIVE";
Per Liden4323add2006-01-18 00:38:21 +01003059 else if (tipc_link_is_up(l_ptr))
Per Lidenb97bf3f2006-01-02 19:04:38 +01003060 status = "STANDBY";
3061 else
3062 status = "DEFUNCT";
3063 tipc_printf(&pb, "Link <%s>\n"
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09003064 " %s MTU:%u Priority:%u Tolerance:%u ms"
3065 " Window:%u packets\n",
Allan Stephens15e979d2010-05-11 14:30:10 +00003066 l_ptr->name, status, l_ptr->max_pkt,
Per Lidenb97bf3f2006-01-02 19:04:38 +01003067 l_ptr->priority, l_ptr->tolerance, l_ptr->queue_limit[0]);
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09003068 tipc_printf(&pb, " RX packets:%u fragments:%u/%u bundles:%u/%u\n",
Per Lidenb97bf3f2006-01-02 19:04:38 +01003069 l_ptr->next_in_no - l_ptr->stats.recv_info,
3070 l_ptr->stats.recv_fragments,
3071 l_ptr->stats.recv_fragmented,
3072 l_ptr->stats.recv_bundles,
3073 l_ptr->stats.recv_bundled);
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09003074 tipc_printf(&pb, " TX packets:%u fragments:%u/%u bundles:%u/%u\n",
Per Lidenb97bf3f2006-01-02 19:04:38 +01003075 l_ptr->next_out_no - l_ptr->stats.sent_info,
3076 l_ptr->stats.sent_fragments,
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09003077 l_ptr->stats.sent_fragmented,
Per Lidenb97bf3f2006-01-02 19:04:38 +01003078 l_ptr->stats.sent_bundles,
3079 l_ptr->stats.sent_bundled);
3080 profile_total = l_ptr->stats.msg_length_counts;
3081 if (!profile_total)
3082 profile_total = 1;
3083 tipc_printf(&pb, " TX profile sample:%u packets average:%u octets\n"
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09003084 " 0-64:%u%% -256:%u%% -1024:%u%% -4096:%u%% "
3085 "-16354:%u%% -32768:%u%% -66000:%u%%\n",
Per Lidenb97bf3f2006-01-02 19:04:38 +01003086 l_ptr->stats.msg_length_counts,
3087 l_ptr->stats.msg_lengths_total / profile_total,
3088 percent(l_ptr->stats.msg_length_profile[0], profile_total),
3089 percent(l_ptr->stats.msg_length_profile[1], profile_total),
3090 percent(l_ptr->stats.msg_length_profile[2], profile_total),
3091 percent(l_ptr->stats.msg_length_profile[3], profile_total),
3092 percent(l_ptr->stats.msg_length_profile[4], profile_total),
3093 percent(l_ptr->stats.msg_length_profile[5], profile_total),
3094 percent(l_ptr->stats.msg_length_profile[6], profile_total));
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09003095 tipc_printf(&pb, " RX states:%u probes:%u naks:%u defs:%u dups:%u\n",
Per Lidenb97bf3f2006-01-02 19:04:38 +01003096 l_ptr->stats.recv_states,
3097 l_ptr->stats.recv_probes,
3098 l_ptr->stats.recv_nacks,
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09003099 l_ptr->stats.deferred_recv,
Per Lidenb97bf3f2006-01-02 19:04:38 +01003100 l_ptr->stats.duplicates);
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09003101 tipc_printf(&pb, " TX states:%u probes:%u naks:%u acks:%u dups:%u\n",
3102 l_ptr->stats.sent_states,
3103 l_ptr->stats.sent_probes,
3104 l_ptr->stats.sent_nacks,
3105 l_ptr->stats.sent_acks,
Per Lidenb97bf3f2006-01-02 19:04:38 +01003106 l_ptr->stats.retransmitted);
3107 tipc_printf(&pb, " Congestion bearer:%u link:%u Send queue max:%u avg:%u\n",
3108 l_ptr->stats.bearer_congs,
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09003109 l_ptr->stats.link_congs,
Per Lidenb97bf3f2006-01-02 19:04:38 +01003110 l_ptr->stats.max_queue_sz,
3111 l_ptr->stats.queue_sz_counts
3112 ? (l_ptr->stats.accu_queue_sz / l_ptr->stats.queue_sz_counts)
3113 : 0);
3114
Per Liden4323add2006-01-18 00:38:21 +01003115 tipc_node_unlock(node);
3116 read_unlock_bh(&tipc_net_lock);
3117 return tipc_printbuf_validate(&pb);
Per Lidenb97bf3f2006-01-02 19:04:38 +01003118}
3119
3120#define MAX_LINK_STATS_INFO 2000
3121
Per Liden4323add2006-01-18 00:38:21 +01003122struct sk_buff *tipc_link_cmd_show_stats(const void *req_tlv_area, int req_tlv_space)
Per Lidenb97bf3f2006-01-02 19:04:38 +01003123{
3124 struct sk_buff *buf;
3125 struct tlv_desc *rep_tlv;
3126 int str_len;
3127
3128 if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_LINK_NAME))
Per Liden4323add2006-01-18 00:38:21 +01003129 return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
Per Lidenb97bf3f2006-01-02 19:04:38 +01003130
Per Liden4323add2006-01-18 00:38:21 +01003131 buf = tipc_cfg_reply_alloc(TLV_SPACE(MAX_LINK_STATS_INFO));
Per Lidenb97bf3f2006-01-02 19:04:38 +01003132 if (!buf)
3133 return NULL;
3134
3135 rep_tlv = (struct tlv_desc *)buf->data;
3136
Per Liden4323add2006-01-18 00:38:21 +01003137 str_len = tipc_link_stats((char *)TLV_DATA(req_tlv_area),
3138 (char *)TLV_DATA(rep_tlv), MAX_LINK_STATS_INFO);
Per Lidenb97bf3f2006-01-02 19:04:38 +01003139 if (!str_len) {
3140 buf_discard(buf);
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09003141 return tipc_cfg_reply_error_string("link not found");
Per Lidenb97bf3f2006-01-02 19:04:38 +01003142 }
3143
3144 skb_put(buf, TLV_SPACE(str_len));
3145 TLV_SET(rep_tlv, TIPC_TLV_ULTRA_STRING, NULL, str_len);
3146
3147 return buf;
3148}
3149
Per Lidenb97bf3f2006-01-02 19:04:38 +01003150/**
Per Liden4323add2006-01-18 00:38:21 +01003151 * tipc_link_get_max_pkt - get maximum packet size to use when sending to destination
Per Lidenb97bf3f2006-01-02 19:04:38 +01003152 * @dest: network address of destination node
3153 * @selector: used to select from set of active links
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09003154 *
Per Lidenb97bf3f2006-01-02 19:04:38 +01003155 * If no active link can be found, uses default maximum packet size.
3156 */
3157
Per Liden4323add2006-01-18 00:38:21 +01003158u32 tipc_link_get_max_pkt(u32 dest, u32 selector)
Per Lidenb97bf3f2006-01-02 19:04:38 +01003159{
David S. Miller6c000552008-09-02 23:38:32 -07003160 struct tipc_node *n_ptr;
Per Lidenb97bf3f2006-01-02 19:04:38 +01003161 struct link *l_ptr;
3162 u32 res = MAX_PKT_DEFAULT;
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09003163
Per Lidenb97bf3f2006-01-02 19:04:38 +01003164 if (dest == tipc_own_addr)
3165 return MAX_MSG_SIZE;
3166
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09003167 read_lock_bh(&tipc_net_lock);
Per Liden4323add2006-01-18 00:38:21 +01003168 n_ptr = tipc_node_select(dest, selector);
Per Lidenb97bf3f2006-01-02 19:04:38 +01003169 if (n_ptr) {
Per Liden4323add2006-01-18 00:38:21 +01003170 tipc_node_lock(n_ptr);
Per Lidenb97bf3f2006-01-02 19:04:38 +01003171 l_ptr = n_ptr->active_links[selector & 1];
3172 if (l_ptr)
Allan Stephens15e979d2010-05-11 14:30:10 +00003173 res = l_ptr->max_pkt;
Per Liden4323add2006-01-18 00:38:21 +01003174 tipc_node_unlock(n_ptr);
Per Lidenb97bf3f2006-01-02 19:04:38 +01003175 }
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09003176 read_unlock_bh(&tipc_net_lock);
Per Lidenb97bf3f2006-01-02 19:04:38 +01003177 return res;
3178}
3179
Per Lidenb97bf3f2006-01-02 19:04:38 +01003180static void link_dump_send_queue(struct link *l_ptr)
3181{
3182 if (l_ptr->next_out) {
3183 info("\nContents of unsent queue:\n");
3184 dbg_print_buf_chain(l_ptr->next_out);
3185 }
3186 info("\nContents of send queue:\n");
3187 if (l_ptr->first_out) {
3188 dbg_print_buf_chain(l_ptr->first_out);
3189 }
3190 info("Empty send queue\n");
3191}
3192
3193static void link_print(struct link *l_ptr, struct print_buf *buf,
3194 const char *str)
3195{
3196 tipc_printf(buf, str);
3197 if (link_reset_reset(l_ptr) || link_reset_unknown(l_ptr))
3198 return;
3199 tipc_printf(buf, "Link %x<%s>:",
3200 l_ptr->addr, l_ptr->b_ptr->publ.name);
3201 tipc_printf(buf, ": NXO(%u):", mod(l_ptr->next_out_no));
3202 tipc_printf(buf, "NXI(%u):", mod(l_ptr->next_in_no));
3203 tipc_printf(buf, "SQUE");
3204 if (l_ptr->first_out) {
3205 tipc_printf(buf, "[%u..", msg_seqno(buf_msg(l_ptr->first_out)));
3206 if (l_ptr->next_out)
3207 tipc_printf(buf, "%u..",
3208 msg_seqno(buf_msg(l_ptr->next_out)));
Allan Stephensb82834e2010-05-11 14:30:04 +00003209 tipc_printf(buf, "%u]", msg_seqno(buf_msg(l_ptr->last_out)));
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09003210 if ((mod(msg_seqno(buf_msg(l_ptr->last_out)) -
3211 msg_seqno(buf_msg(l_ptr->first_out)))
Joe Perchesf64f9e72009-11-29 16:55:45 -08003212 != (l_ptr->out_queue_size - 1)) ||
3213 (l_ptr->last_out->next != NULL)) {
Per Lidenb97bf3f2006-01-02 19:04:38 +01003214 tipc_printf(buf, "\nSend queue inconsistency\n");
3215 tipc_printf(buf, "first_out= %x ", l_ptr->first_out);
3216 tipc_printf(buf, "next_out= %x ", l_ptr->next_out);
3217 tipc_printf(buf, "last_out= %x ", l_ptr->last_out);
3218 link_dump_send_queue(l_ptr);
3219 }
3220 } else
3221 tipc_printf(buf, "[]");
3222 tipc_printf(buf, "SQSIZ(%u)", l_ptr->out_queue_size);
3223 if (l_ptr->oldest_deferred_in) {
3224 u32 o = msg_seqno(buf_msg(l_ptr->oldest_deferred_in));
3225 u32 n = msg_seqno(buf_msg(l_ptr->newest_deferred_in));
3226 tipc_printf(buf, ":RQUE[%u..%u]", o, n);
3227 if (l_ptr->deferred_inqueue_sz != mod((n + 1) - o)) {
3228 tipc_printf(buf, ":RQSIZ(%u)",
3229 l_ptr->deferred_inqueue_sz);
3230 }
3231 }
3232 if (link_working_unknown(l_ptr))
3233 tipc_printf(buf, ":WU");
3234 if (link_reset_reset(l_ptr))
3235 tipc_printf(buf, ":RR");
3236 if (link_reset_unknown(l_ptr))
3237 tipc_printf(buf, ":RU");
3238 if (link_working_working(l_ptr))
3239 tipc_printf(buf, ":WW");
3240 tipc_printf(buf, "\n");
3241}
3242