link.c 81.4 KB
Newer Older
Per Liden's avatar
Per Liden committed
1
2
/*
 * net/tipc/link.c: TIPC link code
3
 *
4
 * Copyright (c) 1996-2007, Ericsson AB
5
 * Copyright (c) 2004-2007, 2010-2011, Wind River Systems
Per Liden's avatar
Per Liden committed
6
7
 * All rights reserved.
 *
Per Liden's avatar
Per Liden committed
8
 * Redistribution and use in source and binary forms, with or without
Per Liden's avatar
Per Liden committed
9
10
 * modification, are permitted provided that the following conditions are met:
 *
Per Liden's avatar
Per Liden committed
11
12
13
14
15
16
17
18
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the names of the copyright holders nor the names of its
 *    contributors may be used to endorse or promote products derived from
 *    this software without specific prior written permission.
Per Liden's avatar
Per Liden committed
19
 *
Per Liden's avatar
Per Liden committed
20
21
22
23
24
25
26
27
28
29
30
31
32
33
 * Alternatively, this software may be distributed under the terms of the
 * GNU General Public License ("GPL") version 2 as published by the Free
 * Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
Per Liden's avatar
Per Liden committed
34
35
36
37
38
39
40
41
42
43
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include "core.h"
#include "link.h"
#include "port.h"
#include "name_distr.h"
#include "discover.h"
#include "config.h"

44
45
46
47
48
49
/*
 * Error message prefixes
 */
static const char *link_co_err = "Link changeover error, ";
static const char *link_rst_msg = "Resetting link ";
static const char *link_unk_evt = "Unknown link event ";
Per Liden's avatar
Per Liden committed
50

51
52
53
54
55
/*
 * Out-of-range value for link session numbers
 */
#define INVALID_SESSION 0x10000

56
57
/*
 * Link state events:
Per Liden's avatar
Per Liden committed
58
59
60
61
62
 */
#define  STARTING_EVT    856384768	/* link processing trigger */
#define  TRAFFIC_MSG_EVT 560815u	/* rx'd ??? */
#define  TIMEOUT_EVT     560817u	/* link timer expired */

63
64
65
/*
 * The following two 'message types' is really just implementation
 * data conveniently stored in the message header.
Per Liden's avatar
Per Liden committed
66
67
68
69
70
 * They must not be considered part of the protocol
 */
#define OPEN_MSG   0
#define CLOSED_MSG 1

71
/*
Per Liden's avatar
Per Liden committed
72
73
74
75
76
 * State value stored in 'exp_msg_count'
 */
#define START_CHANGEOVER 100000u

/**
77
 * struct tipc_link_name - deconstructed link name
Per Liden's avatar
Per Liden committed
78
79
80
81
82
 * @addr_local: network address of node at this end
 * @if_local: name of interface at this end
 * @addr_peer: network address of node at far end
 * @if_peer: name of interface at far end
 */
83
struct tipc_link_name {
Per Liden's avatar
Per Liden committed
84
85
86
87
88
89
	u32 addr_local;
	char if_local[TIPC_MAX_IF_NAME];
	u32 addr_peer;
	char if_peer[TIPC_MAX_IF_NAME];
};

90
static void link_handle_out_of_seq_msg(struct tipc_link *l_ptr,
Per Liden's avatar
Per Liden committed
91
				       struct sk_buff *buf);
92
93
94
95
static void link_recv_proto_msg(struct tipc_link *l_ptr, struct sk_buff *buf);
static int  link_recv_changeover_msg(struct tipc_link **l_ptr,
				     struct sk_buff **buf);
static void link_set_supervision_props(struct tipc_link *l_ptr, u32 tolerance);
96
static int  link_send_sections_long(struct tipc_port *sender,
Per Liden's avatar
Per Liden committed
97
				    struct iovec const *msg_sect,
98
99
				    u32 num_sect, unsigned int total_len,
				    u32 destnode);
100
101
102
103
104
105
static void link_check_defragm_bufs(struct tipc_link *l_ptr);
static void link_state_event(struct tipc_link *l_ptr, u32 event);
static void link_reset_statistics(struct tipc_link *l_ptr);
static void link_print(struct tipc_link *l_ptr, const char *str);
static void link_start(struct tipc_link *l_ptr);
static int link_send_long_buf(struct tipc_link *l_ptr, struct sk_buff *buf);
106

Per Liden's avatar
Per Liden committed
107
/*
Sam Ravnborg's avatar
Sam Ravnborg committed
108
 *  Simple link routines
Per Liden's avatar
Per Liden committed
109
 */
Sam Ravnborg's avatar
Sam Ravnborg committed
110
static unsigned int align(unsigned int i)
Per Liden's avatar
Per Liden committed
111
112
113
114
{
	return (i + 3) & ~3u;
}

115
static void link_init_max_pkt(struct tipc_link *l_ptr)
Per Liden's avatar
Per Liden committed
116
117
{
	u32 max_pkt;
118

119
	max_pkt = (l_ptr->b_ptr->mtu & ~3);
Per Liden's avatar
Per Liden committed
120
121
122
	if (max_pkt > MAX_MSG_SIZE)
		max_pkt = MAX_MSG_SIZE;

123
	l_ptr->max_pkt_target = max_pkt;
Per Liden's avatar
Per Liden committed
124
125
	if (l_ptr->max_pkt_target < MAX_PKT_DEFAULT)
		l_ptr->max_pkt = l_ptr->max_pkt_target;
126
	else
Per Liden's avatar
Per Liden committed
127
128
		l_ptr->max_pkt = MAX_PKT_DEFAULT;

129
	l_ptr->max_pkt_probes = 0;
Per Liden's avatar
Per Liden committed
130
131
}

132
static u32 link_next_sent(struct tipc_link *l_ptr)
Per Liden's avatar
Per Liden committed
133
134
{
	if (l_ptr->next_out)
135
		return buf_seqno(l_ptr->next_out);
Per Liden's avatar
Per Liden committed
136
137
138
	return mod(l_ptr->next_out_no);
}

139
static u32 link_last_sent(struct tipc_link *l_ptr)
Per Liden's avatar
Per Liden committed
140
141
142
143
144
{
	return mod(link_next_sent(l_ptr) - 1);
}

/*
Sam Ravnborg's avatar
Sam Ravnborg committed
145
 *  Simple non-static link routines (i.e. referenced outside this file)
Per Liden's avatar
Per Liden committed
146
 */
147
int tipc_link_is_up(struct tipc_link *l_ptr)
Per Liden's avatar
Per Liden committed
148
149
150
{
	if (!l_ptr)
		return 0;
Eric Dumazet's avatar
Eric Dumazet committed
151
	return link_working_working(l_ptr) || link_working_unknown(l_ptr);
Per Liden's avatar
Per Liden committed
152
153
}

154
int tipc_link_is_active(struct tipc_link *l_ptr)
Per Liden's avatar
Per Liden committed
155
{
Eric Dumazet's avatar
Eric Dumazet committed
156
157
	return	(l_ptr->owner->active_links[0] == l_ptr) ||
		(l_ptr->owner->active_links[1] == l_ptr);
Per Liden's avatar
Per Liden committed
158
159
160
}

/**
161
 * link_name_validate - validate & (optionally) deconstruct tipc_link name
162
163
 * @name: ptr to link name string
 * @name_parts: ptr to area for link name components (or NULL if not needed)
164
 *
Per Liden's avatar
Per Liden committed
165
166
 * Returns 1 if link name is valid, otherwise 0.
 */
167
168
static int link_name_validate(const char *name,
				struct tipc_link_name *name_parts)
Per Liden's avatar
Per Liden committed
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
{
	char name_copy[TIPC_MAX_LINK_NAME];
	char *addr_local;
	char *if_local;
	char *addr_peer;
	char *if_peer;
	char dummy;
	u32 z_local, c_local, n_local;
	u32 z_peer, c_peer, n_peer;
	u32 if_local_len;
	u32 if_peer_len;

	/* copy link name & ensure length is OK */
	name_copy[TIPC_MAX_LINK_NAME - 1] = 0;
	/* need above in case non-Posix strncpy() doesn't pad with nulls */
	strncpy(name_copy, name, TIPC_MAX_LINK_NAME);
	if (name_copy[TIPC_MAX_LINK_NAME - 1] != 0)
		return 0;

	/* ensure all component parts of link name are present */
	addr_local = name_copy;
190
191
	if_local = strchr(addr_local, ':');
	if (if_local == NULL)
Per Liden's avatar
Per Liden committed
192
193
		return 0;
	*(if_local++) = 0;
194
195
	addr_peer = strchr(if_local, '-');
	if (addr_peer == NULL)
Per Liden's avatar
Per Liden committed
196
197
198
		return 0;
	*(addr_peer++) = 0;
	if_local_len = addr_peer - if_local;
199
200
	if_peer = strchr(addr_peer, ':');
	if (if_peer == NULL)
Per Liden's avatar
Per Liden committed
201
202
203
204
205
206
207
208
209
210
211
		return 0;
	*(if_peer++) = 0;
	if_peer_len = strlen(if_peer) + 1;

	/* validate component parts of link name */
	if ((sscanf(addr_local, "%u.%u.%u%c",
		    &z_local, &c_local, &n_local, &dummy) != 3) ||
	    (sscanf(addr_peer, "%u.%u.%u%c",
		    &z_peer, &c_peer, &n_peer, &dummy) != 3) ||
	    (z_local > 255) || (c_local > 4095) || (n_local > 4095) ||
	    (z_peer  > 255) || (c_peer  > 4095) || (n_peer  > 4095) ||
212
213
	    (if_local_len <= 1) || (if_local_len > TIPC_MAX_IF_NAME) ||
	    (if_peer_len  <= 1) || (if_peer_len  > TIPC_MAX_IF_NAME) ||
Per Liden's avatar
Per Liden committed
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
	    (strspn(if_local, tipc_alphabet) != (if_local_len - 1)) ||
	    (strspn(if_peer, tipc_alphabet) != (if_peer_len - 1)))
		return 0;

	/* return link name components, if necessary */
	if (name_parts) {
		name_parts->addr_local = tipc_addr(z_local, c_local, n_local);
		strcpy(name_parts->if_local, if_local);
		name_parts->addr_peer = tipc_addr(z_peer, c_peer, n_peer);
		strcpy(name_parts->if_peer, if_peer);
	}
	return 1;
}

/**
 * link_timeout - handle expiration of link timer
 * @l_ptr: pointer to link
231
 *
232
233
234
235
 * This routine must not grab "tipc_net_lock" to avoid a potential deadlock conflict
 * with tipc_link_delete().  (There is no risk that the node will be deleted by
 * another thread because tipc_link_delete() always cancels the link timer before
 * tipc_node_delete() is called.)
Per Liden's avatar
Per Liden committed
236
 */
237
static void link_timeout(struct tipc_link *l_ptr)
Per Liden's avatar
Per Liden committed
238
{
239
	tipc_node_lock(l_ptr->owner);
Per Liden's avatar
Per Liden committed
240
241
242
243
244
245
246
247
248

	/* update counters used in statistical profiling of send traffic */
	l_ptr->stats.accu_queue_sz += l_ptr->out_queue_size;
	l_ptr->stats.queue_sz_counts++;

	if (l_ptr->first_out) {
		struct tipc_msg *msg = buf_msg(l_ptr->first_out);
		u32 length = msg_size(msg);

249
250
		if ((msg_user(msg) == MSG_FRAGMENTER) &&
		    (msg_type(msg) == FIRST_FRAGMENT)) {
Per Liden's avatar
Per Liden committed
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
			length = msg_size(msg_get_wrapped(msg));
		}
		if (length) {
			l_ptr->stats.msg_lengths_total += length;
			l_ptr->stats.msg_length_counts++;
			if (length <= 64)
				l_ptr->stats.msg_length_profile[0]++;
			else if (length <= 256)
				l_ptr->stats.msg_length_profile[1]++;
			else if (length <= 1024)
				l_ptr->stats.msg_length_profile[2]++;
			else if (length <= 4096)
				l_ptr->stats.msg_length_profile[3]++;
			else if (length <= 16384)
				l_ptr->stats.msg_length_profile[4]++;
			else if (length <= 32768)
				l_ptr->stats.msg_length_profile[5]++;
			else
				l_ptr->stats.msg_length_profile[6]++;
		}
	}

	/* do all other link processing performed on a periodic basis */
	link_check_defragm_bufs(l_ptr);

	link_state_event(l_ptr, TIMEOUT_EVT);

	if (l_ptr->next_out)
279
		tipc_link_push_queue(l_ptr);
Per Liden's avatar
Per Liden committed
280

281
	tipc_node_unlock(l_ptr->owner);
Per Liden's avatar
Per Liden committed
282
283
}

284
static void link_set_timer(struct tipc_link *l_ptr, u32 time)
Per Liden's avatar
Per Liden committed
285
286
287
288
289
{
	k_start_timer(&l_ptr->timer, time);
}

/**
290
 * tipc_link_create - create a new link
291
 * @n_ptr: pointer to associated node
Per Liden's avatar
Per Liden committed
292
293
 * @b_ptr: pointer to associated bearer
 * @media_addr: media address to use when sending messages over link
294
 *
Per Liden's avatar
Per Liden committed
295
296
 * Returns pointer to link.
 */
297
struct tipc_link *tipc_link_create(struct tipc_node *n_ptr,
298
			      struct tipc_bearer *b_ptr,
299
			      const struct tipc_media_addr *media_addr)
Per Liden's avatar
Per Liden committed
300
{
301
	struct tipc_link *l_ptr;
Per Liden's avatar
Per Liden committed
302
303
	struct tipc_msg *msg;
	char *if_name;
304
305
306
307
308
	char addr_string[16];
	u32 peer = n_ptr->addr;

	if (n_ptr->link_cnt >= 2) {
		tipc_addr_string_fill(addr_string, n_ptr->addr);
309
		pr_err("Attempt to establish third link to %s\n", addr_string);
310
311
312
313
314
		return NULL;
	}

	if (n_ptr->links[b_ptr->identity]) {
		tipc_addr_string_fill(addr_string, n_ptr->addr);
315
316
		pr_err("Attempt to establish second link on <%s> to %s\n",
		       b_ptr->name, addr_string);
317
318
		return NULL;
	}
Per Liden's avatar
Per Liden committed
319

320
	l_ptr = kzalloc(sizeof(*l_ptr), GFP_ATOMIC);
Per Liden's avatar
Per Liden committed
321
	if (!l_ptr) {
322
		pr_warn("Link creation failed, no memory\n");
Per Liden's avatar
Per Liden committed
323
324
325
326
		return NULL;
	}

	l_ptr->addr = peer;
327
	if_name = strchr(b_ptr->name, ':') + 1;
328
	sprintf(l_ptr->name, "%u.%u.%u:%s-%u.%u.%u:unknown",
Per Liden's avatar
Per Liden committed
329
		tipc_zone(tipc_own_addr), tipc_cluster(tipc_own_addr),
330
		tipc_node(tipc_own_addr),
Per Liden's avatar
Per Liden committed
331
332
		if_name,
		tipc_zone(peer), tipc_cluster(peer), tipc_node(peer));
333
		/* note: peer i/f name is updated by reset/activate message */
Per Liden's avatar
Per Liden committed
334
	memcpy(&l_ptr->media_addr, media_addr, sizeof(*media_addr));
335
	l_ptr->owner = n_ptr;
Per Liden's avatar
Per Liden committed
336
	l_ptr->checkpoint = 1;
337
	l_ptr->peer_session = INVALID_SESSION;
Per Liden's avatar
Per Liden committed
338
	l_ptr->b_ptr = b_ptr;
339
	link_set_supervision_props(l_ptr, b_ptr->tolerance);
Per Liden's avatar
Per Liden committed
340
341
342
343
	l_ptr->state = RESET_UNKNOWN;

	l_ptr->pmsg = (struct tipc_msg *)&l_ptr->proto_msg;
	msg = l_ptr->pmsg;
344
	tipc_msg_init(msg, LINK_PROTOCOL, RESET_MSG, INT_H_SIZE, l_ptr->addr);
Per Liden's avatar
Per Liden committed
345
	msg_set_size(msg, sizeof(l_ptr->proto_msg));
346
	msg_set_session(msg, (tipc_random & 0xffff));
Per Liden's avatar
Per Liden committed
347
348
349
350
	msg_set_bearer_id(msg, b_ptr->identity);
	strcpy((char *)msg_data(msg), if_name);

	l_ptr->priority = b_ptr->priority;
351
	tipc_link_set_queue_limits(l_ptr, b_ptr->window);
Per Liden's avatar
Per Liden committed
352
353
354
355
356
357
358
359

	link_init_max_pkt(l_ptr);

	l_ptr->next_out_no = 1;
	INIT_LIST_HEAD(&l_ptr->waiting_ports);

	link_reset_statistics(l_ptr);

360
	tipc_node_attach_link(n_ptr, l_ptr);
Per Liden's avatar
Per Liden committed
361

362
363
	k_init_timer(&l_ptr->timer, (Handler)link_timeout, (unsigned long)l_ptr);
	list_add_tail(&l_ptr->link_list, &b_ptr->links);
364
	tipc_k_signal((Handler)link_start, (unsigned long)l_ptr);
Per Liden's avatar
Per Liden committed
365
366
367
368

	return l_ptr;
}

369
/**
370
 * tipc_link_delete - delete a link
Per Liden's avatar
Per Liden committed
371
 * @l_ptr: pointer to link
372
 *
373
 * Note: 'tipc_net_lock' is write_locked, bearer is locked.
Per Liden's avatar
Per Liden committed
374
 * This routine must not grab the node lock until after link timer cancellation
375
 * to avoid a potential deadlock situation.
Per Liden's avatar
Per Liden committed
376
 */
377
void tipc_link_delete(struct tipc_link *l_ptr)
Per Liden's avatar
Per Liden committed
378
379
{
	if (!l_ptr) {
380
		pr_err("Attempt to delete non-existent link\n");
Per Liden's avatar
Per Liden committed
381
382
383
384
		return;
	}

	k_cancel_timer(&l_ptr->timer);
385

386
387
388
389
	tipc_node_lock(l_ptr->owner);
	tipc_link_reset(l_ptr);
	tipc_node_detach_link(l_ptr->owner, l_ptr);
	tipc_link_stop(l_ptr);
Per Liden's avatar
Per Liden committed
390
	list_del_init(&l_ptr->link_list);
391
	tipc_node_unlock(l_ptr->owner);
Per Liden's avatar
Per Liden committed
392
393
394
395
	k_term_timer(&l_ptr->timer);
	kfree(l_ptr);
}

396
static void link_start(struct tipc_link *l_ptr)
Per Liden's avatar
Per Liden committed
397
{
398
	tipc_node_lock(l_ptr->owner);
Per Liden's avatar
Per Liden committed
399
	link_state_event(l_ptr, STARTING_EVT);
400
	tipc_node_unlock(l_ptr->owner);
Per Liden's avatar
Per Liden committed
401
402
403
}

/**
404
 * link_schedule_port - schedule port for deferred sending
Per Liden's avatar
Per Liden committed
405
406
407
 * @l_ptr: pointer to link
 * @origport: reference to sending port
 * @sz: amount of data to be sent
408
409
 *
 * Schedules port for renewed sending of messages after link congestion
Per Liden's avatar
Per Liden committed
410
411
 * has abated.
 */
412
static int link_schedule_port(struct tipc_link *l_ptr, u32 origport, u32 sz)
Per Liden's avatar
Per Liden committed
413
{
414
	struct tipc_port *p_ptr;
Per Liden's avatar
Per Liden committed
415

416
417
	spin_lock_bh(&tipc_port_list_lock);
	p_ptr = tipc_port_lock(origport);
Per Liden's avatar
Per Liden committed
418
419
420
421
422
	if (p_ptr) {
		if (!p_ptr->wakeup)
			goto exit;
		if (!list_empty(&p_ptr->wait_list))
			goto exit;
423
		p_ptr->congested = 1;
424
		p_ptr->waiting_pkts = 1 + ((sz - 1) / l_ptr->max_pkt);
Per Liden's avatar
Per Liden committed
425
426
427
		list_add_tail(&p_ptr->wait_list, &l_ptr->waiting_ports);
		l_ptr->stats.link_congs++;
exit:
428
		tipc_port_unlock(p_ptr);
Per Liden's avatar
Per Liden committed
429
	}
430
	spin_unlock_bh(&tipc_port_list_lock);
Per Liden's avatar
Per Liden committed
431
432
433
	return -ELINKCONG;
}

434
void tipc_link_wakeup_ports(struct tipc_link *l_ptr, int all)
Per Liden's avatar
Per Liden committed
435
{
436
437
	struct tipc_port *p_ptr;
	struct tipc_port *temp_p_ptr;
Per Liden's avatar
Per Liden committed
438
439
440
441
442
443
	int win = l_ptr->queue_limit[0] - l_ptr->out_queue_size;

	if (all)
		win = 100000;
	if (win <= 0)
		return;
444
	if (!spin_trylock_bh(&tipc_port_list_lock))
Per Liden's avatar
Per Liden committed
445
446
447
		return;
	if (link_congested(l_ptr))
		goto exit;
448
	list_for_each_entry_safe(p_ptr, temp_p_ptr, &l_ptr->waiting_ports,
Per Liden's avatar
Per Liden committed
449
450
451
452
				 wait_list) {
		if (win <= 0)
			break;
		list_del_init(&p_ptr->wait_list);
453
454
455
		spin_lock_bh(p_ptr->lock);
		p_ptr->congested = 0;
		p_ptr->wakeup(p_ptr);
Per Liden's avatar
Per Liden committed
456
		win -= p_ptr->waiting_pkts;
457
		spin_unlock_bh(p_ptr->lock);
Per Liden's avatar
Per Liden committed
458
459
460
	}

exit:
461
	spin_unlock_bh(&tipc_port_list_lock);
Per Liden's avatar
Per Liden committed
462
463
}

464
/**
Per Liden's avatar
Per Liden committed
465
466
467
 * link_release_outqueue - purge link's outbound message queue
 * @l_ptr: pointer to link
 */
468
static void link_release_outqueue(struct tipc_link *l_ptr)
Per Liden's avatar
Per Liden committed
469
470
471
472
473
474
{
	struct sk_buff *buf = l_ptr->first_out;
	struct sk_buff *next;

	while (buf) {
		next = buf->next;
475
		kfree_skb(buf);
Per Liden's avatar
Per Liden committed
476
477
478
479
480
481
482
		buf = next;
	}
	l_ptr->first_out = NULL;
	l_ptr->out_queue_size = 0;
}

/**
483
 * tipc_link_reset_fragments - purge link's inbound message fragments queue
Per Liden's avatar
Per Liden committed
484
485
 * @l_ptr: pointer to link
 */
486
void tipc_link_reset_fragments(struct tipc_link *l_ptr)
Per Liden's avatar
Per Liden committed
487
488
489
490
491
492
{
	struct sk_buff *buf = l_ptr->defragm_buf;
	struct sk_buff *next;

	while (buf) {
		next = buf->next;
493
		kfree_skb(buf);
Per Liden's avatar
Per Liden committed
494
495
496
497
498
		buf = next;
	}
	l_ptr->defragm_buf = NULL;
}

499
/**
500
 * tipc_link_stop - purge all inbound and outbound messages associated with link
Per Liden's avatar
Per Liden committed
501
502
 * @l_ptr: pointer to link
 */
503
void tipc_link_stop(struct tipc_link *l_ptr)
Per Liden's avatar
Per Liden committed
504
505
506
507
508
509
510
{
	struct sk_buff *buf;
	struct sk_buff *next;

	buf = l_ptr->oldest_deferred_in;
	while (buf) {
		next = buf->next;
511
		kfree_skb(buf);
Per Liden's avatar
Per Liden committed
512
513
514
515
516
517
		buf = next;
	}

	buf = l_ptr->first_out;
	while (buf) {
		next = buf->next;
518
		kfree_skb(buf);
Per Liden's avatar
Per Liden committed
519
520
521
		buf = next;
	}

522
	tipc_link_reset_fragments(l_ptr);
Per Liden's avatar
Per Liden committed
523

524
	kfree_skb(l_ptr->proto_msg_queue);
Per Liden's avatar
Per Liden committed
525
526
527
	l_ptr->proto_msg_queue = NULL;
}

528
void tipc_link_reset(struct tipc_link *l_ptr)
Per Liden's avatar
Per Liden committed
529
530
531
532
{
	struct sk_buff *buf;
	u32 prev_state = l_ptr->state;
	u32 checkpoint = l_ptr->next_in_no;
533
	int was_active_link = tipc_link_is_active(l_ptr);
534

535
	msg_set_session(l_ptr->pmsg, ((msg_session(l_ptr->pmsg) + 1) & 0xffff));
Per Liden's avatar
Per Liden committed
536

537
538
	/* Link is down, accept any session */
	l_ptr->peer_session = INVALID_SESSION;
Per Liden's avatar
Per Liden committed
539

540
	/* Prepare for max packet size negotiation */
Per Liden's avatar
Per Liden committed
541
	link_init_max_pkt(l_ptr);
542

Per Liden's avatar
Per Liden committed
543
544
545
546
547
	l_ptr->state = RESET_UNKNOWN;

	if ((prev_state == RESET_UNKNOWN) || (prev_state == RESET_RESET))
		return;

548
549
	tipc_node_link_down(l_ptr->owner, l_ptr);
	tipc_bearer_remove_dest(l_ptr->b_ptr, l_ptr->addr);
550

551
	if (was_active_link && tipc_node_active_links(l_ptr->owner) &&
Per Liden's avatar
Per Liden committed
552
553
554
555
556
557
558
	    l_ptr->owner->permit_changeover) {
		l_ptr->reset_checkpoint = checkpoint;
		l_ptr->exp_msg_count = START_CHANGEOVER;
	}

	/* Clean up all queues: */
	link_release_outqueue(l_ptr);
559
	kfree_skb(l_ptr->proto_msg_queue);
Per Liden's avatar
Per Liden committed
560
561
562
563
	l_ptr->proto_msg_queue = NULL;
	buf = l_ptr->oldest_deferred_in;
	while (buf) {
		struct sk_buff *next = buf->next;
564
		kfree_skb(buf);
Per Liden's avatar
Per Liden committed
565
566
567
		buf = next;
	}
	if (!list_empty(&l_ptr->waiting_ports))
568
		tipc_link_wakeup_ports(l_ptr, 1);
Per Liden's avatar
Per Liden committed
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586

	l_ptr->retransm_queue_head = 0;
	l_ptr->retransm_queue_size = 0;
	l_ptr->last_out = NULL;
	l_ptr->first_out = NULL;
	l_ptr->next_out = NULL;
	l_ptr->unacked_window = 0;
	l_ptr->checkpoint = 1;
	l_ptr->next_out_no = 1;
	l_ptr->deferred_inqueue_sz = 0;
	l_ptr->oldest_deferred_in = NULL;
	l_ptr->newest_deferred_in = NULL;
	l_ptr->fsm_msg_cnt = 0;
	l_ptr->stale_count = 0;
	link_reset_statistics(l_ptr);
}


587
static void link_activate(struct tipc_link *l_ptr)
Per Liden's avatar
Per Liden committed
588
{
589
	l_ptr->next_in_no = l_ptr->stats.recv_info = 1;
590
591
	tipc_node_link_up(l_ptr->owner, l_ptr);
	tipc_bearer_add_dest(l_ptr->b_ptr, l_ptr->addr);
Per Liden's avatar
Per Liden committed
592
593
594
595
596
597
598
}

/**
 * link_state_event - link finite state machine
 * @l_ptr: pointer to link
 * @event: state machine event to process
 */
599
static void link_state_event(struct tipc_link *l_ptr, unsigned int event)
Per Liden's avatar
Per Liden committed
600
{
601
	struct tipc_link *other;
Per Liden's avatar
Per Liden committed
602
603
604
605
606
607
	u32 cont_intv = l_ptr->continuity_interval;

	if (!l_ptr->started && (event != STARTING_EVT))
		return;		/* Not yet. */

	if (link_blocked(l_ptr)) {
608
		if (event == TIMEOUT_EVT)
Per Liden's avatar
Per Liden committed
609
610
611
612
613
614
615
616
617
618
619
620
621
			link_set_timer(l_ptr, cont_intv);
		return;	  /* Changeover going on */
	}

	switch (l_ptr->state) {
	case WORKING_WORKING:
		switch (event) {
		case TRAFFIC_MSG_EVT:
		case ACTIVATE_MSG:
			break;
		case TIMEOUT_EVT:
			if (l_ptr->next_in_no != l_ptr->checkpoint) {
				l_ptr->checkpoint = l_ptr->next_in_no;
622
				if (tipc_bclink_acks_missing(l_ptr->owner)) {
623
					tipc_link_send_proto_msg(l_ptr, STATE_MSG,
624
								 0, 0, 0, 0, 0);
Per Liden's avatar
Per Liden committed
625
626
					l_ptr->fsm_msg_cnt++;
				} else if (l_ptr->max_pkt < l_ptr->max_pkt_target) {
627
					tipc_link_send_proto_msg(l_ptr, STATE_MSG,
628
								 1, 0, 0, 0, 0);
Per Liden's avatar
Per Liden committed
629
630
631
632
633
634
635
					l_ptr->fsm_msg_cnt++;
				}
				link_set_timer(l_ptr, cont_intv);
				break;
			}
			l_ptr->state = WORKING_UNKNOWN;
			l_ptr->fsm_msg_cnt = 0;
636
			tipc_link_send_proto_msg(l_ptr, STATE_MSG, 1, 0, 0, 0, 0);
Per Liden's avatar
Per Liden committed
637
638
639
640
			l_ptr->fsm_msg_cnt++;
			link_set_timer(l_ptr, cont_intv / 4);
			break;
		case RESET_MSG:
641
642
			pr_info("%s<%s>, requested by peer\n", link_rst_msg,
				l_ptr->name);
643
			tipc_link_reset(l_ptr);
Per Liden's avatar
Per Liden committed
644
645
			l_ptr->state = RESET_RESET;
			l_ptr->fsm_msg_cnt = 0;
646
			tipc_link_send_proto_msg(l_ptr, ACTIVATE_MSG, 0, 0, 0, 0, 0);
Per Liden's avatar
Per Liden committed
647
648
649
650
			l_ptr->fsm_msg_cnt++;
			link_set_timer(l_ptr, cont_intv);
			break;
		default:
651
			pr_err("%s%u in WW state\n", link_unk_evt, event);
Per Liden's avatar
Per Liden committed
652
653
654
655
656
657
658
659
660
661
662
		}
		break;
	case WORKING_UNKNOWN:
		switch (event) {
		case TRAFFIC_MSG_EVT:
		case ACTIVATE_MSG:
			l_ptr->state = WORKING_WORKING;
			l_ptr->fsm_msg_cnt = 0;
			link_set_timer(l_ptr, cont_intv);
			break;
		case RESET_MSG:
663
664
			pr_info("%s<%s>, requested by peer while probing\n",
				link_rst_msg, l_ptr->name);
665
			tipc_link_reset(l_ptr);
Per Liden's avatar
Per Liden committed
666
667
			l_ptr->state = RESET_RESET;
			l_ptr->fsm_msg_cnt = 0;
668
			tipc_link_send_proto_msg(l_ptr, ACTIVATE_MSG, 0, 0, 0, 0, 0);
Per Liden's avatar
Per Liden committed
669
670
671
672
673
674
675
676
			l_ptr->fsm_msg_cnt++;
			link_set_timer(l_ptr, cont_intv);
			break;
		case TIMEOUT_EVT:
			if (l_ptr->next_in_no != l_ptr->checkpoint) {
				l_ptr->state = WORKING_WORKING;
				l_ptr->fsm_msg_cnt = 0;
				l_ptr->checkpoint = l_ptr->next_in_no;
677
678
679
				if (tipc_bclink_acks_missing(l_ptr->owner)) {
					tipc_link_send_proto_msg(l_ptr, STATE_MSG,
								 0, 0, 0, 0, 0);
Per Liden's avatar
Per Liden committed
680
681
682
683
					l_ptr->fsm_msg_cnt++;
				}
				link_set_timer(l_ptr, cont_intv);
			} else if (l_ptr->fsm_msg_cnt < l_ptr->abort_limit) {
684
				tipc_link_send_proto_msg(l_ptr, STATE_MSG,
685
							 1, 0, 0, 0, 0);
Per Liden's avatar
Per Liden committed
686
687
688
				l_ptr->fsm_msg_cnt++;
				link_set_timer(l_ptr, cont_intv / 4);
			} else {	/* Link has failed */
689
690
				pr_warn("%s<%s>, peer not responding\n",
					link_rst_msg, l_ptr->name);
691
				tipc_link_reset(l_ptr);
Per Liden's avatar
Per Liden committed
692
693
				l_ptr->state = RESET_UNKNOWN;
				l_ptr->fsm_msg_cnt = 0;
694
695
				tipc_link_send_proto_msg(l_ptr, RESET_MSG,
							 0, 0, 0, 0, 0);
Per Liden's avatar
Per Liden committed
696
697
698
699
700
				l_ptr->fsm_msg_cnt++;
				link_set_timer(l_ptr, cont_intv);
			}
			break;
		default:
701
			pr_err("%s%u in WU state\n", link_unk_evt, event);
Per Liden's avatar
Per Liden committed
702
703
704
705
706
707
708
709
		}
		break;
	case RESET_UNKNOWN:
		switch (event) {
		case TRAFFIC_MSG_EVT:
			break;
		case ACTIVATE_MSG:
			other = l_ptr->owner->active_links[0];
710
			if (other && link_working_unknown(other))
Per Liden's avatar
Per Liden committed
711
712
713
714
				break;
			l_ptr->state = WORKING_WORKING;
			l_ptr->fsm_msg_cnt = 0;
			link_activate(l_ptr);
715
			tipc_link_send_proto_msg(l_ptr, STATE_MSG, 1, 0, 0, 0, 0);
Per Liden's avatar
Per Liden committed
716
717
718
719
720
721
			l_ptr->fsm_msg_cnt++;
			link_set_timer(l_ptr, cont_intv);
			break;
		case RESET_MSG:
			l_ptr->state = RESET_RESET;
			l_ptr->fsm_msg_cnt = 0;
722
			tipc_link_send_proto_msg(l_ptr, ACTIVATE_MSG, 1, 0, 0, 0, 0);
Per Liden's avatar
Per Liden committed
723
724
725
726
727
728
729
			l_ptr->fsm_msg_cnt++;
			link_set_timer(l_ptr, cont_intv);
			break;
		case STARTING_EVT:
			l_ptr->started = 1;
			/* fall through */
		case TIMEOUT_EVT:
730
			tipc_link_send_proto_msg(l_ptr, RESET_MSG, 0, 0, 0, 0, 0);
Per Liden's avatar
Per Liden committed
731
732
733
734
			l_ptr->fsm_msg_cnt++;
			link_set_timer(l_ptr, cont_intv);
			break;
		default:
735
			pr_err("%s%u in RU state\n", link_unk_evt, event);
Per Liden's avatar
Per Liden committed
736
737
738
739
740
741
742
		}
		break;
	case RESET_RESET:
		switch (event) {
		case TRAFFIC_MSG_EVT:
		case ACTIVATE_MSG:
			other = l_ptr->owner->active_links[0];
743
			if (other && link_working_unknown(other))
Per Liden's avatar
Per Liden committed
744
745
746
747
				break;
			l_ptr->state = WORKING_WORKING;
			l_ptr->fsm_msg_cnt = 0;
			link_activate(l_ptr);
748
			tipc_link_send_proto_msg(l_ptr, STATE_MSG, 1, 0, 0, 0, 0);
Per Liden's avatar
Per Liden committed
749
750
751
752
753
754
			l_ptr->fsm_msg_cnt++;
			link_set_timer(l_ptr, cont_intv);
			break;
		case RESET_MSG:
			break;
		case TIMEOUT_EVT:
755
			tipc_link_send_proto_msg(l_ptr, ACTIVATE_MSG, 0, 0, 0, 0, 0);
Per Liden's avatar
Per Liden committed
756
757
758
759
			l_ptr->fsm_msg_cnt++;
			link_set_timer(l_ptr, cont_intv);
			break;
		default:
760
			pr_err("%s%u in RR state\n", link_unk_evt, event);
Per Liden's avatar
Per Liden committed
761
762
763
		}
		break;
	default:
764
		pr_err("Unknown link state %u/%u\n", l_ptr->state, event);
Per Liden's avatar
Per Liden committed
765
766
767
768
769
	}
}

/*
 * link_bundle_buf(): Append contents of a buffer to
770
 * the tail of an existing one.
Per Liden's avatar
Per Liden committed
771
 */
772
static int link_bundle_buf(struct tipc_link *l_ptr,
773
			   struct sk_buff *bundler,
Per Liden's avatar
Per Liden committed
774
775
776
777
778
			   struct sk_buff *buf)
{
	struct tipc_msg *bundler_msg = buf_msg(bundler);
	struct tipc_msg *msg = buf_msg(buf);
	u32 size = msg_size(msg);
779
780
781
	u32 bundle_size = msg_size(bundler_msg);
	u32 to_pos = align(bundle_size);
	u32 pad = to_pos - bundle_size;
Per Liden's avatar
Per Liden committed
782
783
784
785
786

	if (msg_user(bundler_msg) != MSG_BUNDLER)
		return 0;
	if (msg_type(bundler_msg) != OPEN_MSG)
		return 0;
787
	if (skb_tailroom(bundler) < (pad + size))
Per Liden's avatar
Per Liden committed
788
		return 0;
789
	if (l_ptr->max_pkt < (to_pos + size))
790
		return 0;
Per Liden's avatar
Per Liden committed
791

792
	skb_put(bundler, pad + size);
793
	skb_copy_to_linear_data_offset(bundler, to_pos, buf->data, size);
Per Liden's avatar
Per Liden committed
794
795
	msg_set_size(bundler_msg, to_pos + size);
	msg_set_msgcnt(bundler_msg, msg_msgcnt(bundler_msg) + 1);
796
	kfree_skb(buf);
Per Liden's avatar
Per Liden committed
797
798
799
800
	l_ptr->stats.sent_bundled++;
	return 1;
}

801
static void link_add_to_outqueue(struct tipc_link *l_ptr,
Sam Ravnborg's avatar
Sam Ravnborg committed
802
803
				 struct sk_buff *buf,
				 struct tipc_msg *msg)
Per Liden's avatar
Per Liden committed
804
805
806
807
808
809
810
811
812
813
814
815
{
	u32 ack = mod(l_ptr->next_in_no - 1);
	u32 seqno = mod(l_ptr->next_out_no++);

	msg_set_word(msg, 2, ((ack << 16) | seqno));
	msg_set_bcast_ack(msg, l_ptr->owner->bclink.last_in);
	buf->next = NULL;
	if (l_ptr->first_out) {
		l_ptr->last_out->next = buf;
		l_ptr->last_out = buf;
	} else
		l_ptr->first_out = l_ptr->last_out = buf;
816

Per Liden's avatar
Per Liden committed
817
	l_ptr->out_queue_size++;
818
819
	if (l_ptr->out_queue_size > l_ptr->stats.max_queue_sz)
		l_ptr->stats.max_queue_sz = l_ptr->out_queue_size;
Per Liden's avatar
Per Liden committed
820
821
}

822
static void link_add_chain_to_outqueue(struct tipc_link *l_ptr,
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
				       struct sk_buff *buf_chain,
				       u32 long_msgno)
{
	struct sk_buff *buf;
	struct tipc_msg *msg;

	if (!l_ptr->next_out)
		l_ptr->next_out = buf_chain;
	while (buf_chain) {
		buf = buf_chain;
		buf_chain = buf_chain->next;

		msg = buf_msg(buf);
		msg_set_long_msgno(msg, long_msgno);
		link_add_to_outqueue(l_ptr, buf, msg);
	}
}

841
842
/*
 * tipc_link_send_buf() is the 'full path' for messages, called from
Per Liden's avatar
Per Liden committed
843
844
845
 * inside TIPC when the 'fast path' in tipc_send_buf
 * has failed, and from link_send()
 */
846
int tipc_link_send_buf(struct tipc_link *l_ptr, struct sk_buff *buf)
Per Liden's avatar
Per Liden committed
847
848
849
850
851
{
	struct tipc_msg *msg = buf_msg(buf);
	u32 size = msg_size(msg);
	u32 dsz = msg_data_sz(msg);
	u32 queue_size = l_ptr->out_queue_size;
852
	u32 imp = tipc_msg_tot_importance(msg);
Per Liden's avatar
Per Liden committed
853
	u32 queue_limit = l_ptr->queue_limit[imp];
854
	u32 max_packet = l_ptr->max_pkt;
Per Liden's avatar
Per Liden committed
855
856
857
858

	/* Match msg importance against queue limits: */
	if (unlikely(queue_size >= queue_limit)) {
		if (imp <= TIPC_CRITICAL_IMPORTANCE) {
859
			link_schedule_port(l_ptr, msg_origport(msg), size);
860
			kfree_skb(buf);
861
			return -ELINKCONG;
Per Liden's avatar
Per Liden committed
862
		}
863
		kfree_skb(buf);
Per Liden's avatar
Per Liden committed
864
		if (imp > CONN_MANAGER) {
865
866
			pr_warn("%s<%s>, send queue full", link_rst_msg,
				l_ptr->name);
867
			tipc_link_reset(l_ptr);
Per Liden's avatar
Per Liden committed
868
869
870
871
872
873
		}
		return dsz;
	}

	/* Fragmentation needed ? */
	if (size > max_packet)
874
		return link_send_long_buf(l_ptr, buf);
Per Liden's avatar
Per Liden committed
875

876
	/* Packet can be queued or sent. */
877
	if (likely(!tipc_bearer_congested(l_ptr->b_ptr, l_ptr) &&
Per Liden's avatar
Per Liden committed
878
879
880
		   !link_congested(l_ptr))) {
		link_add_to_outqueue(l_ptr, buf, msg);

881
		if (likely(tipc_bearer_send(l_ptr->b_ptr, buf, &l_ptr->media_addr))) {
Per Liden's avatar
Per Liden committed
882
883
			l_ptr->unacked_window = 0;
		} else {
884
			tipc_bearer_schedule(l_ptr->b_ptr, l_ptr);
Per Liden's avatar
Per Liden committed
885
886
887
888
889
			l_ptr->stats.bearer_congs++;
			l_ptr->next_out = buf;
		}
		return dsz;
	}
890
	/* Congestion: can message be bundled ? */
Per Liden's avatar
Per Liden committed
891
892
893
894
	if ((msg_user(msg) != CHANGEOVER_PROTOCOL) &&
	    (msg_user(msg) != MSG_FRAGMENTER)) {

		/* Try adding message to an existing bundle */
895
		if (l_ptr->next_out &&
Per Liden's avatar
Per Liden committed
896
		    link_bundle_buf(l_ptr, l_ptr->last_out, buf)) {
897
			tipc_bearer_resolve_congestion(l_ptr->b_ptr, l_ptr);
Per Liden's avatar
Per Liden committed
898
899
900
901
902
			return dsz;
		}

		/* Try creating a new bundle */
		if (size <= max_packet * 2 / 3) {
903
			struct sk_buff *bundler = tipc_buf_acquire(max_packet);
Per Liden's avatar
Per Liden committed
904
905
906
			struct tipc_msg bundler_hdr;

			if (bundler) {
907
				tipc_msg_init(&bundler_hdr, MSG_BUNDLER, OPEN_MSG,
908
					 INT_H_SIZE, l_ptr->addr);
909
910
				skb_copy_to_linear_data(bundler, &bundler_hdr,
							INT_H_SIZE);
Per Liden's avatar
Per Liden committed
911
912
913
914
915
916
917
918
919
920
921
				skb_trim(bundler, INT_H_SIZE);
				link_bundle_buf(l_ptr, bundler, buf);
				buf = bundler;
				msg = buf_msg(buf);
				l_ptr->stats.sent_bundles++;
			}
		}
	}
	if (!l_ptr->next_out)
		l_ptr->next_out = buf;
	link_add_to_outqueue(l_ptr, buf, msg);
922
	tipc_bearer_resolve_congestion(l_ptr->b_ptr, l_ptr);
Per Liden's avatar
Per Liden committed
923
924
925
	return dsz;
}

926
927
/*
 * tipc_link_send(): same as tipc_link_send_buf(), but the link to use has
Per Liden's avatar
Per Liden committed
928
929
930
 * not been selected yet, and the the owner node is not locked
 * Called by TIPC internal users, e.g. the name distributor
 */
931
int tipc_link_send(struct sk_buff *buf, u32 dest, u32 selector)
Per Liden's avatar
Per Liden committed
932
{
933
	struct tipc_link *l_ptr;
934
	struct tipc_node *n_ptr;
Per Liden's avatar
Per Liden committed
935
936
	int res = -ELINKCONG;

937
	read_lock_bh(&tipc_net_lock);
938
	n_ptr = tipc_node_find(dest);
Per Liden's avatar
Per Liden committed
939
	if (n_ptr) {
940
		tipc_node_lock(n_ptr);
Per Liden's avatar
Per Liden committed
941
		l_ptr = n_ptr->active_links[selector & 1];
942
		if (l_ptr)
943
			res = tipc_link_send_buf(l_ptr, buf);
944
		else
945
			kfree_skb(buf);
946
		tipc_node_unlock(n_ptr);
Per Liden's avatar
Per Liden committed
947
	} else {
948
		kfree_skb(buf);
Per Liden's avatar
Per Liden committed
949
	}
950
	read_unlock_bh(&tipc_net_lock);
Per Liden's avatar
Per Liden committed
951
952
953
	return res;
}

954
/**
955
956
957
958
959
960
961
962
963
964
965
 * tipc_link_send_names - send name table entries to new neighbor
 *
 * Send routine for bulk delivery of name table messages when contact
 * with a new neighbor occurs. No link congestion checking is performed
 * because name table messages *must* be delivered. The messages must be
 * small enough not to require fragmentation.
 * Called without any locks held.
 */
void tipc_link_send_names(struct list_head *message_list, u32 dest)
{
	struct tipc_node *n_ptr;
966
	struct tipc_link *l_ptr;
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
	struct sk_buff *buf;
	struct sk_buff *temp_buf;

	if (list_empty(message_list))
		return;

	read_lock_bh(&tipc_net_lock);
	n_ptr = tipc_node_find(dest);
	if (n_ptr) {
		tipc_node_lock(n_ptr);
		l_ptr = n_ptr->active_links[0];
		if (l_ptr) {
			/* convert circular list to linear list */
			((struct sk_buff *)message_list->prev)->next = NULL;
			link_add_chain_to_outqueue(l_ptr,
				(struct sk_buff *)message_list->next, 0);
			tipc_link_push_queue(l_ptr);
			INIT_LIST_HEAD(message_list);
		}
		tipc_node_unlock(n_ptr);
	}
	read_unlock_bh(&tipc_net_lock);

	/* discard the messages if they couldn't be sent */
	list_for_each_safe(buf, temp_buf, ((struct sk_buff *)message_list)) {
		list_del((struct list_head *)buf);
993
		kfree_skb(buf);
994
995
996
	}
}

997
998
/*
 * link_send_buf_fast: Entry for data messages where the
Per Liden's avatar
Per Liden committed
999
1000
1001
1002
 * destination link is known and the header is complete,
 * inclusive total message length. Very time critical.
 * Link is locked. Returns user data length.
 */
1003
static int link_send_buf_fast(struct tipc_link *l_ptr, struct sk_buff *buf,
Sam Ravnborg's avatar
Sam Ravnborg committed
1004
			      u32 *used_max_pkt)
Per Liden's avatar
Per Liden committed
1005
1006
1007
1008
1009
{
	struct tipc_msg *msg = buf_msg(buf);
	int res = msg_data_sz(msg);

	if (likely(!link_congested(l_ptr))) {
1010
		if (likely(msg_size(msg) <= l_ptr->max_pkt)) {
Per Liden's avatar
Per Liden committed
1011
1012
			if (likely(list_empty(&l_ptr->b_ptr->cong_links))) {
				link_add_to_outqueue(l_ptr, buf, msg);
1013
1014
				if (likely(tipc_bearer_send(l_ptr->b_ptr, buf,
							    &l_ptr->media_addr))) {
Per Liden's avatar
Per Liden committed
1015
1016
1017
					l_ptr->unacked_window = 0;
					return res;
				}
1018
				tipc_bearer_schedule(l_ptr->b_ptr, l_ptr);
Per Liden's avatar
Per Liden committed
1019
1020
1021
1022
				l_ptr->stats.bearer_congs++;
				l_ptr->next_out = buf;
				return res;
			}
1023
		} else
1024
			*used_max_pkt = l_ptr->max_pkt;
Per Liden's avatar
Per Liden committed
1025
	}
1026
	return tipc_link_send_buf(l_ptr, buf);  /* All other cases */
Per Liden's avatar
Per Liden committed
1027
1028
}

1029
1030
/*
 * tipc_send_buf_fast: Entry for data messages where the
Per Liden's avatar
Per Liden committed
1031
1032
1033
1034
1035
1036
 * destination node is known and the header is complete,
 * inclusive total message length.
 * Returns user data length.
 */
int tipc_send_buf_fast(struct sk_buff *buf, u32 destnode)
{
1037
	struct tipc_link *l_ptr;
1038
	struct tipc_node *n_ptr;
Per Liden's avatar
Per Liden committed
1039
1040
1041
1042
	int res;
	u32 selector = msg_origport(buf_msg(buf)) & 1;
	u32 dummy;

1043
	read_lock_bh(&tipc_net_lock);
1044
	n_ptr = tipc_node_find(destnode);
Per Liden's avatar
Per Liden committed
1045
	if (likely(n_ptr)) {
1046
		tipc_node_lock(n_ptr);
Per Liden's avatar
Per Liden committed
1047
1048
1049
		l_ptr = n_ptr->active_links[selector];
		if (likely(l_ptr)) {
			res = link_send_buf_fast(l_ptr, buf, &dummy);
1050
1051
			tipc_node_unlock(n_ptr);
			read_unlock_bh(&tipc_net_lock);
Per Liden's avatar
Per Liden committed
1052
1053
			return res;
		}
1054
		tipc_node_unlock(n_ptr);
Per Liden's avatar
Per Liden committed
1055
	}
1056
	read_unlock_bh(&tipc_net_lock);
Per Liden's avatar
Per Liden committed
1057
1058
1059
1060
1061
1062
	res = msg_data_sz(buf_msg(buf));
	tipc_reject_msg(buf, TIPC_ERR_NO_NODE);
	return res;
}


1063
1064
/*
 * tipc_link_send_sections_fast: Entry for messages where the
Per Liden's avatar
Per Liden committed
1065
 * destination processor is known and the header is complete,
1066
 * except for total message length.
Per Liden's avatar
Per Liden committed
1067
1068
 * Returns user data length or errno.
 */
1069
int tipc_link_send_sections_fast(struct tipc_port *sender,
1070
				 struct iovec const *msg_sect,