port.c 32.0 KB
Newer Older
P
Per Liden 已提交
1 2
/*
 * net/tipc/port.c: TIPC port code
3
 *
4
 * Copyright (c) 1992-2007, Ericsson AB
5
 * Copyright (c) 2004-2008, 2010-2011, Wind River Systems
P
Per Liden 已提交
6 7
 * All rights reserved.
 *
P
Per Liden 已提交
8
 * Redistribution and use in source and binary forms, with or without
P
Per Liden 已提交
9 10
 * modification, are permitted provided that the following conditions are met:
 *
P
Per Liden 已提交
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.
P
Per Liden 已提交
19
 *
P
Per Liden 已提交
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
P
Per Liden 已提交
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include "core.h"
#include "config.h"
#include "port.h"
#include "name_table.h"

/* Connection management: */
#define PROBING_INTERVAL 3600000	/* [ms] => 1 h */
#define CONFIRMED 0
#define PROBING 1

#define MAX_REJECT_SIZE 1024

49 50
static struct sk_buff *msg_queue_head;
static struct sk_buff *msg_queue_tail;
P
Per Liden 已提交
51

I
Ingo Molnar 已提交
52 53
DEFINE_SPINLOCK(tipc_port_list_lock);
static DEFINE_SPINLOCK(queue_lock);
P
Per Liden 已提交
54

55
static LIST_HEAD(ports);
P
Per Liden 已提交
56
static void port_handle_node_down(unsigned long ref);
57 58
static struct sk_buff *port_build_self_abort_msg(struct tipc_port *, u32 err);
static struct sk_buff *port_build_peer_abort_msg(struct tipc_port *, u32 err);
P
Per Liden 已提交
59 60 61
static void port_timeout(unsigned long ref);


62
static u32 port_peernode(struct tipc_port *p_ptr)
P
Per Liden 已提交
63
{
64
	return msg_destnode(&p_ptr->phdr);
P
Per Liden 已提交
65 66
}

67
static u32 port_peerport(struct tipc_port *p_ptr)
P
Per Liden 已提交
68
{
69
	return msg_destport(&p_ptr->phdr);
P
Per Liden 已提交
70 71 72 73 74 75
}

/**
 * tipc_multicast - send a multicast message to local and remote destinations
 */

76
int tipc_multicast(u32 ref, struct tipc_name_seq const *seq,
P
Per Liden 已提交
77 78 79 80 81 82
		   u32 num_sect, struct iovec const *msg_sect)
{
	struct tipc_msg *hdr;
	struct sk_buff *buf;
	struct sk_buff *ibuf = NULL;
	struct port_list dports = {0, NULL, };
83
	struct tipc_port *oport = tipc_port_deref(ref);
P
Per Liden 已提交
84 85 86 87 88 89 90 91
	int ext_targets;
	int res;

	if (unlikely(!oport))
		return -EINVAL;

	/* Create multicast message */

92
	hdr = &oport->phdr;
P
Per Liden 已提交
93 94 95 96 97
	msg_set_type(hdr, TIPC_MCAST_MSG);
	msg_set_nametype(hdr, seq->type);
	msg_set_namelower(hdr, seq->lower);
	msg_set_nameupper(hdr, seq->upper);
	msg_set_hdr_sz(hdr, MCAST_H_SIZE);
98
	res = tipc_msg_build(hdr, msg_sect, num_sect, MAX_MSG_SIZE,
P
Per Liden 已提交
99 100 101 102 103 104
			!oport->user_port, &buf);
	if (unlikely(!buf))
		return res;

	/* Figure out where to send multicast message */

105 106
	ext_targets = tipc_nametbl_mc_translate(seq->type, seq->lower, seq->upper,
						TIPC_NODE_SCOPE, &dports);
107 108

	/* Send message to destinations (duplicate it only if necessary) */
P
Per Liden 已提交
109 110 111 112 113

	if (ext_targets) {
		if (dports.count != 0) {
			ibuf = skb_copy(buf, GFP_ATOMIC);
			if (ibuf == NULL) {
114
				tipc_port_list_free(&dports);
P
Per Liden 已提交
115 116 117 118
				buf_discard(buf);
				return -ENOMEM;
			}
		}
119
		res = tipc_bclink_send_msg(buf);
120
		if ((res < 0) && (dports.count != 0))
P
Per Liden 已提交
121 122 123 124 125 126 127
			buf_discard(ibuf);
	} else {
		ibuf = buf;
	}

	if (res >= 0) {
		if (ibuf)
128
			tipc_port_recv_mcast(ibuf, &dports);
P
Per Liden 已提交
129
	} else {
130
		tipc_port_list_free(&dports);
P
Per Liden 已提交
131 132 133 134 135
	}
	return res;
}

/**
136
 * tipc_port_recv_mcast - deliver multicast message to all destination ports
137
 *
P
Per Liden 已提交
138 139 140
 * If there is no port list, perform a lookup to create one
 */

141
void tipc_port_recv_mcast(struct sk_buff *buf, struct port_list *dp)
P
Per Liden 已提交
142
{
143
	struct tipc_msg *msg;
P
Per Liden 已提交
144 145 146 147 148 149 150 151 152
	struct port_list dports = {0, NULL, };
	struct port_list *item = dp;
	int cnt = 0;

	msg = buf_msg(buf);

	/* Create destination port list, if one wasn't supplied */

	if (dp == NULL) {
153
		tipc_nametbl_mc_translate(msg_nametype(msg),
P
Per Liden 已提交
154 155 156 157 158 159 160 161 162 163 164 165
				     msg_namelower(msg),
				     msg_nameupper(msg),
				     TIPC_CLUSTER_SCOPE,
				     &dports);
		item = dp = &dports;
	}

	/* Deliver a copy of message to each destination port */

	if (dp->count != 0) {
		if (dp->count == 1) {
			msg_set_destport(msg, dp->ports[0]);
166 167
			tipc_port_recv_msg(buf);
			tipc_port_list_free(dp);
P
Per Liden 已提交
168 169 170 171 172 173 174
			return;
		}
		for (; cnt < dp->count; cnt++) {
			int index = cnt % PLSIZE;
			struct sk_buff *b = skb_clone(buf, GFP_ATOMIC);

			if (b == NULL) {
175
				warn("Unable to deliver multicast message(s)\n");
P
Per Liden 已提交
176 177
				goto exit;
			}
178
			if ((index == 0) && (cnt != 0))
P
Per Liden 已提交
179
				item = item->next;
180
			msg_set_destport(buf_msg(b), item->ports[index]);
181
			tipc_port_recv_msg(b);
P
Per Liden 已提交
182 183 184 185
		}
	}
exit:
	buf_discard(buf);
186
	tipc_port_list_free(dp);
P
Per Liden 已提交
187 188 189
}

/**
190
 * tipc_createport_raw - create a generic TIPC port
191
 *
192
 * Returns pointer to (locked) TIPC port, or NULL if unable to create it
P
Per Liden 已提交
193 194
 */

195
struct tipc_port *tipc_createport_raw(void *usr_handle,
P
Per Liden 已提交
196 197
			u32 (*dispatcher)(struct tipc_port *, struct sk_buff *),
			void (*wakeup)(struct tipc_port *),
198
			const u32 importance)
P
Per Liden 已提交
199
{
200
	struct tipc_port *p_ptr;
P
Per Liden 已提交
201 202 203
	struct tipc_msg *msg;
	u32 ref;

204
	p_ptr = kzalloc(sizeof(*p_ptr), GFP_ATOMIC);
205 206
	if (!p_ptr) {
		warn("Port creation failed, no memory\n");
207
		return NULL;
P
Per Liden 已提交
208
	}
209
	ref = tipc_ref_acquire(p_ptr, &p_ptr->lock);
P
Per Liden 已提交
210
	if (!ref) {
211
		warn("Port creation failed, reference table exhausted\n");
P
Per Liden 已提交
212
		kfree(p_ptr);
213
		return NULL;
P
Per Liden 已提交
214 215
	}

216 217 218 219
	p_ptr->usr_handle = usr_handle;
	p_ptr->max_pkt = MAX_PKT_DEFAULT;
	p_ptr->ref = ref;
	msg = &p_ptr->phdr;
220
	tipc_msg_init(msg, importance, TIPC_NAMED_MSG, LONG_H_SIZE, 0);
P
Per Liden 已提交
221 222 223 224 225
	msg_set_origport(msg, ref);
	INIT_LIST_HEAD(&p_ptr->wait_list);
	INIT_LIST_HEAD(&p_ptr->subscription.nodesub_list);
	p_ptr->dispatcher = dispatcher;
	p_ptr->wakeup = wakeup;
226
	p_ptr->user_port = NULL;
P
Per Liden 已提交
227
	k_init_timer(&p_ptr->timer, (Handler)port_timeout, ref);
228
	spin_lock_bh(&tipc_port_list_lock);
P
Per Liden 已提交
229 230 231
	INIT_LIST_HEAD(&p_ptr->publications);
	INIT_LIST_HEAD(&p_ptr->port_list);
	list_add_tail(&p_ptr->port_list, &ports);
232
	spin_unlock_bh(&tipc_port_list_lock);
233
	return p_ptr;
P
Per Liden 已提交
234 235 236 237
}

int tipc_deleteport(u32 ref)
{
238
	struct tipc_port *p_ptr;
239
	struct sk_buff *buf = NULL;
P
Per Liden 已提交
240

241
	tipc_withdraw(ref, 0, NULL);
242
	p_ptr = tipc_port_lock(ref);
243
	if (!p_ptr)
P
Per Liden 已提交
244 245
		return -EINVAL;

246 247
	tipc_ref_discard(ref);
	tipc_port_unlock(p_ptr);
P
Per Liden 已提交
248 249

	k_cancel_timer(&p_ptr->timer);
250
	if (p_ptr->connected) {
P
Per Liden 已提交
251
		buf = port_build_peer_abort_msg(p_ptr, TIPC_ERR_NO_PORT);
252
		tipc_nodesub_unsubscribe(&p_ptr->subscription);
P
Per Liden 已提交
253
	}
254
	kfree(p_ptr->user_port);
P
Per Liden 已提交
255

256
	spin_lock_bh(&tipc_port_list_lock);
P
Per Liden 已提交
257 258
	list_del(&p_ptr->port_list);
	list_del(&p_ptr->wait_list);
259
	spin_unlock_bh(&tipc_port_list_lock);
P
Per Liden 已提交
260 261
	k_term_timer(&p_ptr->timer);
	kfree(p_ptr);
262
	tipc_net_route_msg(buf);
263
	return 0;
P
Per Liden 已提交
264 265
}

266
static int port_unreliable(struct tipc_port *p_ptr)
P
Per Liden 已提交
267
{
268
	return msg_src_droppable(&p_ptr->phdr);
P
Per Liden 已提交
269 270 271 272
}

int tipc_portunreliable(u32 ref, unsigned int *isunreliable)
{
273
	struct tipc_port *p_ptr;
274

275
	p_ptr = tipc_port_lock(ref);
P
Per Liden 已提交
276 277 278
	if (!p_ptr)
		return -EINVAL;
	*isunreliable = port_unreliable(p_ptr);
J
Julia Lawall 已提交
279
	tipc_port_unlock(p_ptr);
280
	return 0;
P
Per Liden 已提交
281 282 283 284
}

int tipc_set_portunreliable(u32 ref, unsigned int isunreliable)
{
285
	struct tipc_port *p_ptr;
286

287
	p_ptr = tipc_port_lock(ref);
P
Per Liden 已提交
288 289
	if (!p_ptr)
		return -EINVAL;
290
	msg_set_src_droppable(&p_ptr->phdr, (isunreliable != 0));
291
	tipc_port_unlock(p_ptr);
292
	return 0;
P
Per Liden 已提交
293 294
}

295
static int port_unreturnable(struct tipc_port *p_ptr)
P
Per Liden 已提交
296
{
297
	return msg_dest_droppable(&p_ptr->phdr);
P
Per Liden 已提交
298 299 300 301
}

int tipc_portunreturnable(u32 ref, unsigned int *isunrejectable)
{
302
	struct tipc_port *p_ptr;
303

304
	p_ptr = tipc_port_lock(ref);
P
Per Liden 已提交
305 306 307
	if (!p_ptr)
		return -EINVAL;
	*isunrejectable = port_unreturnable(p_ptr);
J
Julia Lawall 已提交
308
	tipc_port_unlock(p_ptr);
309
	return 0;
P
Per Liden 已提交
310 311 312 313
}

int tipc_set_portunreturnable(u32 ref, unsigned int isunrejectable)
{
314
	struct tipc_port *p_ptr;
315

316
	p_ptr = tipc_port_lock(ref);
P
Per Liden 已提交
317 318
	if (!p_ptr)
		return -EINVAL;
319
	msg_set_dest_droppable(&p_ptr->phdr, (isunrejectable != 0));
320
	tipc_port_unlock(p_ptr);
321
	return 0;
P
Per Liden 已提交
322 323
}

324 325 326
/*
 * port_build_proto_msg(): build a port level protocol
 * or a connection abortion message. Called with
P
Per Liden 已提交
327 328 329 330
 * tipc_port lock on.
 */
static struct sk_buff *port_build_proto_msg(u32 destport, u32 destnode,
					    u32 origport, u32 orignode,
331
					    u32 usr, u32 type, u32 err,
332
					    u32 ack)
P
Per Liden 已提交
333 334 335
{
	struct sk_buff *buf;
	struct tipc_msg *msg;
336

337
	buf = tipc_buf_acquire(LONG_H_SIZE);
P
Per Liden 已提交
338 339
	if (buf) {
		msg = buf_msg(buf);
340
		tipc_msg_init(msg, usr, type, LONG_H_SIZE, destnode);
341
		msg_set_errcode(msg, err);
P
Per Liden 已提交
342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374
		msg_set_destport(msg, destport);
		msg_set_origport(msg, origport);
		msg_set_orignode(msg, orignode);
		msg_set_msgcnt(msg, ack);
	}
	return buf;
}

int tipc_reject_msg(struct sk_buff *buf, u32 err)
{
	struct tipc_msg *msg = buf_msg(buf);
	struct sk_buff *rbuf;
	struct tipc_msg *rmsg;
	int hdr_sz;
	u32 imp = msg_importance(msg);
	u32 data_sz = msg_data_sz(msg);

	if (data_sz > MAX_REJECT_SIZE)
		data_sz = MAX_REJECT_SIZE;
	if (msg_connected(msg) && (imp < TIPC_CRITICAL_IMPORTANCE))
		imp++;

	/* discard rejected message if it shouldn't be returned to sender */
	if (msg_errcode(msg) || msg_dest_droppable(msg)) {
		buf_discard(buf);
		return data_sz;
	}

	/* construct rejected message */
	if (msg_mcast(msg))
		hdr_sz = MCAST_H_SIZE;
	else
		hdr_sz = LONG_H_SIZE;
375
	rbuf = tipc_buf_acquire(data_sz + hdr_sz);
P
Per Liden 已提交
376 377 378 379 380
	if (rbuf == NULL) {
		buf_discard(buf);
		return data_sz;
	}
	rmsg = buf_msg(rbuf);
381
	tipc_msg_init(rmsg, imp, msg_type(msg), hdr_sz, msg_orignode(msg));
382
	msg_set_errcode(rmsg, err);
P
Per Liden 已提交
383 384
	msg_set_destport(rmsg, msg_origport(msg));
	msg_set_origport(rmsg, msg_destport(msg));
385
	if (msg_short(msg)) {
P
Per Liden 已提交
386
		msg_set_orignode(rmsg, tipc_own_addr);
387 388
		/* leave name type & instance as zeroes */
	} else {
P
Per Liden 已提交
389
		msg_set_orignode(rmsg, msg_destnode(msg));
390 391 392
		msg_set_nametype(rmsg, msg_nametype(msg));
		msg_set_nameinst(rmsg, msg_nameinst(msg));
	}
393
	msg_set_size(rmsg, data_sz + hdr_sz);
394
	skb_copy_to_linear_data_offset(rbuf, hdr_sz, msg_data(msg), data_sz);
P
Per Liden 已提交
395 396 397

	/* send self-abort message when rejecting on a connected port */
	if (msg_connected(msg)) {
398
		struct sk_buff *abuf = NULL;
399
		struct tipc_port *p_ptr = tipc_port_lock(msg_destport(msg));
P
Per Liden 已提交
400 401

		if (p_ptr) {
402
			if (p_ptr->connected)
P
Per Liden 已提交
403
				abuf = port_build_self_abort_msg(p_ptr, err);
404
			tipc_port_unlock(p_ptr);
P
Per Liden 已提交
405
		}
406
		tipc_net_route_msg(abuf);
P
Per Liden 已提交
407 408 409 410
	}

	/* send rejected message */
	buf_discard(buf);
411
	tipc_net_route_msg(rbuf);
P
Per Liden 已提交
412 413 414
	return data_sz;
}

415
int tipc_port_reject_sections(struct tipc_port *p_ptr, struct tipc_msg *hdr,
416 417
			      struct iovec const *msg_sect, u32 num_sect,
			      int err)
P
Per Liden 已提交
418 419 420 421
{
	struct sk_buff *buf;
	int res;

422
	res = tipc_msg_build(hdr, msg_sect, num_sect, MAX_MSG_SIZE,
P
Per Liden 已提交
423 424 425 426 427 428 429 430 431
			!p_ptr->user_port, &buf);
	if (!buf)
		return res;

	return tipc_reject_msg(buf, err);
}

static void port_timeout(unsigned long ref)
{
432
	struct tipc_port *p_ptr = tipc_port_lock(ref);
433
	struct sk_buff *buf = NULL;
P
Per Liden 已提交
434

435 436 437
	if (!p_ptr)
		return;

438
	if (!p_ptr->connected) {
439
		tipc_port_unlock(p_ptr);
P
Per Liden 已提交
440
		return;
441
	}
P
Per Liden 已提交
442 443 444 445 446 447 448

	/* Last probe answered ? */
	if (p_ptr->probing_state == PROBING) {
		buf = port_build_self_abort_msg(p_ptr, TIPC_ERR_NO_PORT);
	} else {
		buf = port_build_proto_msg(port_peerport(p_ptr),
					   port_peernode(p_ptr),
449
					   p_ptr->ref,
P
Per Liden 已提交
450 451 452
					   tipc_own_addr,
					   CONN_MANAGER,
					   CONN_PROBE,
453
					   TIPC_OK,
P
Per Liden 已提交
454 455 456 457
					   0);
		p_ptr->probing_state = PROBING;
		k_start_timer(&p_ptr->timer, p_ptr->probing_interval);
	}
458 459
	tipc_port_unlock(p_ptr);
	tipc_net_route_msg(buf);
P
Per Liden 已提交
460 461 462 463 464
}


static void port_handle_node_down(unsigned long ref)
{
465
	struct tipc_port *p_ptr = tipc_port_lock(ref);
466
	struct sk_buff *buf = NULL;
P
Per Liden 已提交
467 468 469 470

	if (!p_ptr)
		return;
	buf = port_build_self_abort_msg(p_ptr, TIPC_ERR_NO_NODE);
471 472
	tipc_port_unlock(p_ptr);
	tipc_net_route_msg(buf);
P
Per Liden 已提交
473 474 475
}


476
static struct sk_buff *port_build_self_abort_msg(struct tipc_port *p_ptr, u32 err)
P
Per Liden 已提交
477
{
478
	u32 imp = msg_importance(&p_ptr->phdr);
P
Per Liden 已提交
479

480
	if (!p_ptr->connected)
481
		return NULL;
P
Per Liden 已提交
482 483
	if (imp < TIPC_CRITICAL_IMPORTANCE)
		imp++;
484
	return port_build_proto_msg(p_ptr->ref,
P
Per Liden 已提交
485 486 487 488 489
				    tipc_own_addr,
				    port_peerport(p_ptr),
				    port_peernode(p_ptr),
				    imp,
				    TIPC_CONN_MSG,
490
				    err,
P
Per Liden 已提交
491 492 493 494
				    0);
}


495
static struct sk_buff *port_build_peer_abort_msg(struct tipc_port *p_ptr, u32 err)
P
Per Liden 已提交
496
{
497
	u32 imp = msg_importance(&p_ptr->phdr);
P
Per Liden 已提交
498

499
	if (!p_ptr->connected)
500
		return NULL;
P
Per Liden 已提交
501 502 503 504
	if (imp < TIPC_CRITICAL_IMPORTANCE)
		imp++;
	return port_build_proto_msg(port_peerport(p_ptr),
				    port_peernode(p_ptr),
505
				    p_ptr->ref,
P
Per Liden 已提交
506 507 508
				    tipc_own_addr,
				    imp,
				    TIPC_CONN_MSG,
509
				    err,
P
Per Liden 已提交
510 511 512
				    0);
}

513
void tipc_port_recv_proto_msg(struct sk_buff *buf)
P
Per Liden 已提交
514 515
{
	struct tipc_msg *msg = buf_msg(buf);
516
	struct tipc_port *p_ptr = tipc_port_lock(msg_destport(msg));
P
Per Liden 已提交
517
	u32 err = TIPC_OK;
518 519
	struct sk_buff *r_buf = NULL;
	struct sk_buff *abort_buf = NULL;
P
Per Liden 已提交
520 521 522

	if (!p_ptr) {
		err = TIPC_ERR_NO_PORT;
523
	} else if (p_ptr->connected) {
524 525
		if ((port_peernode(p_ptr) != msg_orignode(msg)) ||
		    (port_peerport(p_ptr) != msg_origport(msg))) {
P
Per Liden 已提交
526
			err = TIPC_ERR_NO_PORT;
527
		} else if (msg_type(msg) == CONN_ACK) {
528
			int wakeup = tipc_port_congested(p_ptr) &&
529
				     p_ptr->congested &&
P
Per Liden 已提交
530 531
				     p_ptr->wakeup;
			p_ptr->acked += msg_msgcnt(msg);
532
			if (tipc_port_congested(p_ptr))
P
Per Liden 已提交
533
				goto exit;
534
			p_ptr->congested = 0;
P
Per Liden 已提交
535 536
			if (!wakeup)
				goto exit;
537
			p_ptr->wakeup(p_ptr);
P
Per Liden 已提交
538 539
			goto exit;
		}
540
	} else if (p_ptr->published) {
P
Per Liden 已提交
541 542 543 544
		err = TIPC_ERR_NO_PORT;
	}
	if (err) {
		r_buf = port_build_proto_msg(msg_origport(msg),
545 546
					     msg_orignode(msg),
					     msg_destport(msg),
P
Per Liden 已提交
547
					     tipc_own_addr,
548
					     TIPC_HIGH_IMPORTANCE,
P
Per Liden 已提交
549 550 551 552 553 554 555 556
					     TIPC_CONN_MSG,
					     err,
					     0);
		goto exit;
	}

	/* All is fine */
	if (msg_type(msg) == CONN_PROBE) {
557 558 559 560
		r_buf = port_build_proto_msg(msg_origport(msg),
					     msg_orignode(msg),
					     msg_destport(msg),
					     tipc_own_addr,
P
Per Liden 已提交
561 562 563 564 565 566 567 568
					     CONN_MANAGER,
					     CONN_PROBE_REPLY,
					     TIPC_OK,
					     0);
	}
	p_ptr->probing_state = CONFIRMED;
exit:
	if (p_ptr)
569 570 571
		tipc_port_unlock(p_ptr);
	tipc_net_route_msg(r_buf);
	tipc_net_route_msg(abort_buf);
P
Per Liden 已提交
572 573 574
	buf_discard(buf);
}

575
static void port_print(struct tipc_port *p_ptr, struct print_buf *buf, int full_id)
P
Per Liden 已提交
576
{
577
	struct publication *publ;
P
Per Liden 已提交
578 579

	if (full_id)
580
		tipc_printf(buf, "<%u.%u.%u:%u>:",
P
Per Liden 已提交
581
			    tipc_zone(tipc_own_addr), tipc_cluster(tipc_own_addr),
582
			    tipc_node(tipc_own_addr), p_ptr->ref);
P
Per Liden 已提交
583
	else
584
		tipc_printf(buf, "%-10u:", p_ptr->ref);
P
Per Liden 已提交
585

586
	if (p_ptr->connected) {
587 588 589 590 591 592
		u32 dport = port_peerport(p_ptr);
		u32 destnode = port_peernode(p_ptr);

		tipc_printf(buf, " connected to <%u.%u.%u:%u>",
			    tipc_zone(destnode), tipc_cluster(destnode),
			    tipc_node(destnode), dport);
593
		if (p_ptr->conn_type != 0)
594
			tipc_printf(buf, " via {%u,%u}",
595 596 597
				    p_ptr->conn_type,
				    p_ptr->conn_instance);
	} else if (p_ptr->published) {
598 599
		tipc_printf(buf, " bound to");
		list_for_each_entry(publ, &p_ptr->publications, pport_list) {
P
Per Liden 已提交
600 601 602 603
			if (publ->lower == publ->upper)
				tipc_printf(buf, " {%u,%u}", publ->type,
					    publ->lower);
			else
604
				tipc_printf(buf, " {%u,%u,%u}", publ->type,
P
Per Liden 已提交
605
					    publ->lower, publ->upper);
606 607 608
		}
	}
	tipc_printf(buf, "\n");
P
Per Liden 已提交
609 610 611 612
}

#define MAX_PORT_QUERY 32768

613
struct sk_buff *tipc_port_get_ports(void)
P
Per Liden 已提交
614 615 616 617
{
	struct sk_buff *buf;
	struct tlv_desc *rep_tlv;
	struct print_buf pb;
618
	struct tipc_port *p_ptr;
P
Per Liden 已提交
619 620
	int str_len;

621
	buf = tipc_cfg_reply_alloc(TLV_SPACE(MAX_PORT_QUERY));
P
Per Liden 已提交
622 623 624 625
	if (!buf)
		return NULL;
	rep_tlv = (struct tlv_desc *)buf->data;

626 627
	tipc_printbuf_init(&pb, TLV_DATA(rep_tlv), MAX_PORT_QUERY);
	spin_lock_bh(&tipc_port_list_lock);
P
Per Liden 已提交
628
	list_for_each_entry(p_ptr, &ports, port_list) {
629
		spin_lock_bh(p_ptr->lock);
P
Per Liden 已提交
630
		port_print(p_ptr, &pb, 0);
631
		spin_unlock_bh(p_ptr->lock);
P
Per Liden 已提交
632
	}
633 634
	spin_unlock_bh(&tipc_port_list_lock);
	str_len = tipc_printbuf_validate(&pb);
P
Per Liden 已提交
635 636 637 638 639 640 641

	skb_put(buf, TLV_SPACE(str_len));
	TLV_SET(rep_tlv, TIPC_TLV_ULTRA_STRING, NULL, str_len);

	return buf;
}

642
void tipc_port_reinit(void)
P
Per Liden 已提交
643
{
644
	struct tipc_port *p_ptr;
P
Per Liden 已提交
645 646
	struct tipc_msg *msg;

647
	spin_lock_bh(&tipc_port_list_lock);
P
Per Liden 已提交
648
	list_for_each_entry(p_ptr, &ports, port_list) {
649
		msg = &p_ptr->phdr;
P
Per Liden 已提交
650 651
		if (msg_orignode(msg) == tipc_own_addr)
			break;
652
		msg_set_prevnode(msg, tipc_own_addr);
P
Per Liden 已提交
653 654
		msg_set_orignode(msg, tipc_own_addr);
	}
655
	spin_unlock_bh(&tipc_port_list_lock);
P
Per Liden 已提交
656 657 658 659 660 661 662 663 664 665 666 667 668 669
}


/*
 *  port_dispatcher_sigh(): Signal handler for messages destinated
 *                          to the tipc_port interface.
 */

static void port_dispatcher_sigh(void *dummy)
{
	struct sk_buff *buf;

	spin_lock_bh(&queue_lock);
	buf = msg_queue_head;
670
	msg_queue_head = NULL;
P
Per Liden 已提交
671 672 673
	spin_unlock_bh(&queue_lock);

	while (buf) {
674
		struct tipc_port *p_ptr;
P
Per Liden 已提交
675 676 677 678 679 680
		struct user_port *up_ptr;
		struct tipc_portid orig;
		struct tipc_name_seq dseq;
		void *usr_handle;
		int connected;
		int published;
681
		u32 message_type;
P
Per Liden 已提交
682 683 684 685

		struct sk_buff *next = buf->next;
		struct tipc_msg *msg = buf_msg(buf);
		u32 dref = msg_destport(msg);
686

687 688 689 690
		message_type = msg_type(msg);
		if (message_type > TIPC_DIRECT_MSG)
			goto reject;	/* Unsupported message type */

691
		p_ptr = tipc_port_lock(dref);
692 693 694
		if (!p_ptr)
			goto reject;	/* Port deleted while msg in queue */

P
Per Liden 已提交
695 696 697 698
		orig.ref = msg_origport(msg);
		orig.node = msg_orignode(msg);
		up_ptr = p_ptr->user_port;
		usr_handle = up_ptr->usr_handle;
699 700
		connected = p_ptr->connected;
		published = p_ptr->published;
P
Per Liden 已提交
701 702 703 704

		if (unlikely(msg_errcode(msg)))
			goto err;

705
		switch (message_type) {
706

P
Per Liden 已提交
707 708 709 710
		case TIPC_CONN_MSG:{
				tipc_conn_msg_event cb = up_ptr->conn_msg_cb;
				u32 peer_port = port_peerport(p_ptr);
				u32 peer_node = port_peernode(p_ptr);
711
				u32 dsz;
P
Per Liden 已提交
712

J
Julia Lawall 已提交
713
				tipc_port_unlock(p_ptr);
714 715
				if (unlikely(!cb))
					goto reject;
P
Per Liden 已提交
716
				if (unlikely(!connected)) {
717
					if (tipc_connect2port(dref, &orig))
P
Per Liden 已提交
718
						goto reject;
719 720
				} else if ((msg_origport(msg) != peer_port) ||
					   (msg_orignode(msg) != peer_node))
P
Per Liden 已提交
721
					goto reject;
722 723 724 725
				dsz = msg_data_sz(msg);
				if (unlikely(dsz &&
					     (++p_ptr->conn_unacked >=
					      TIPC_FLOW_CONTROL_WIN)))
726
					tipc_acknowledge(dref,
727
							 p_ptr->conn_unacked);
P
Per Liden 已提交
728
				skb_pull(buf, msg_hdr_sz(msg));
729
				cb(usr_handle, dref, &buf, msg_data(msg), dsz);
P
Per Liden 已提交
730 731 732 733 734
				break;
			}
		case TIPC_DIRECT_MSG:{
				tipc_msg_event cb = up_ptr->msg_cb;

J
Julia Lawall 已提交
735
				tipc_port_unlock(p_ptr);
736
				if (unlikely(!cb || connected))
P
Per Liden 已提交
737 738
					goto reject;
				skb_pull(buf, msg_hdr_sz(msg));
739
				cb(usr_handle, dref, &buf, msg_data(msg),
P
Per Liden 已提交
740 741 742 743
				   msg_data_sz(msg), msg_importance(msg),
				   &orig);
				break;
			}
744
		case TIPC_MCAST_MSG:
P
Per Liden 已提交
745 746 747
		case TIPC_NAMED_MSG:{
				tipc_named_msg_event cb = up_ptr->named_msg_cb;

J
Julia Lawall 已提交
748
				tipc_port_unlock(p_ptr);
749
				if (unlikely(!cb || connected || !published))
P
Per Liden 已提交
750 751 752
					goto reject;
				dseq.type =  msg_nametype(msg);
				dseq.lower = msg_nameinst(msg);
753 754
				dseq.upper = (message_type == TIPC_NAMED_MSG)
					? dseq.lower : msg_nameupper(msg);
P
Per Liden 已提交
755
				skb_pull(buf, msg_hdr_sz(msg));
756
				cb(usr_handle, dref, &buf, msg_data(msg),
P
Per Liden 已提交
757 758 759 760 761 762 763 764 765 766
				   msg_data_sz(msg), msg_importance(msg),
				   &orig, &dseq);
				break;
			}
		}
		if (buf)
			buf_discard(buf);
		buf = next;
		continue;
err:
767
		switch (message_type) {
768

P
Per Liden 已提交
769
		case TIPC_CONN_MSG:{
770
				tipc_conn_shutdown_event cb =
P
Per Liden 已提交
771 772 773 774
					up_ptr->conn_err_cb;
				u32 peer_port = port_peerport(p_ptr);
				u32 peer_node = port_peernode(p_ptr);

J
Julia Lawall 已提交
775
				tipc_port_unlock(p_ptr);
776
				if (!cb || !connected)
P
Per Liden 已提交
777
					break;
778 779
				if ((msg_origport(msg) != peer_port) ||
				    (msg_orignode(msg) != peer_node))
P
Per Liden 已提交
780 781 782 783 784 785 786 787 788 789
					break;
				tipc_disconnect(dref);
				skb_pull(buf, msg_hdr_sz(msg));
				cb(usr_handle, dref, &buf, msg_data(msg),
				   msg_data_sz(msg), msg_errcode(msg));
				break;
			}
		case TIPC_DIRECT_MSG:{
				tipc_msg_err_event cb = up_ptr->err_cb;

J
Julia Lawall 已提交
790
				tipc_port_unlock(p_ptr);
791
				if (!cb || connected)
P
Per Liden 已提交
792 793 794 795 796 797
					break;
				skb_pull(buf, msg_hdr_sz(msg));
				cb(usr_handle, dref, &buf, msg_data(msg),
				   msg_data_sz(msg), msg_errcode(msg), &orig);
				break;
			}
798
		case TIPC_MCAST_MSG:
P
Per Liden 已提交
799
		case TIPC_NAMED_MSG:{
800
				tipc_named_msg_err_event cb =
P
Per Liden 已提交
801 802
					up_ptr->named_err_cb;

J
Julia Lawall 已提交
803
				tipc_port_unlock(p_ptr);
804
				if (!cb || connected)
P
Per Liden 已提交
805 806 807
					break;
				dseq.type =  msg_nametype(msg);
				dseq.lower = msg_nameinst(msg);
808 809
				dseq.upper = (message_type == TIPC_NAMED_MSG)
					? dseq.lower : msg_nameupper(msg);
P
Per Liden 已提交
810
				skb_pull(buf, msg_hdr_sz(msg));
811
				cb(usr_handle, dref, &buf, msg_data(msg),
P
Per Liden 已提交
812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839
				   msg_data_sz(msg), msg_errcode(msg), &dseq);
				break;
			}
		}
		if (buf)
			buf_discard(buf);
		buf = next;
		continue;
reject:
		tipc_reject_msg(buf, TIPC_ERR_NO_PORT);
		buf = next;
	}
}

/*
 *  port_dispatcher(): Dispatcher for messages destinated
 *  to the tipc_port interface. Called with port locked.
 */

static u32 port_dispatcher(struct tipc_port *dummy, struct sk_buff *buf)
{
	buf->next = NULL;
	spin_lock_bh(&queue_lock);
	if (msg_queue_head) {
		msg_queue_tail->next = buf;
		msg_queue_tail = buf;
	} else {
		msg_queue_tail = msg_queue_head = buf;
840
		tipc_k_signal((Handler)port_dispatcher_sigh, 0);
P
Per Liden 已提交
841 842
	}
	spin_unlock_bh(&queue_lock);
843
	return 0;
P
Per Liden 已提交
844 845
}

846
/*
P
Per Liden 已提交
847
 * Wake up port after congestion: Called with port locked,
848
 *
P
Per Liden 已提交
849 850 851 852
 */

static void port_wakeup_sh(unsigned long ref)
{
853
	struct tipc_port *p_ptr;
P
Per Liden 已提交
854
	struct user_port *up_ptr;
855 856
	tipc_continue_event cb = NULL;
	void *uh = NULL;
P
Per Liden 已提交
857

858
	p_ptr = tipc_port_lock(ref);
P
Per Liden 已提交
859 860 861 862 863 864
	if (p_ptr) {
		up_ptr = p_ptr->user_port;
		if (up_ptr) {
			cb = up_ptr->continue_event_cb;
			uh = up_ptr->usr_handle;
		}
865
		tipc_port_unlock(p_ptr);
P
Per Liden 已提交
866 867 868 869 870 871 872 873
	}
	if (cb)
		cb(uh, ref);
}


static void port_wakeup(struct tipc_port *p_ptr)
{
874
	tipc_k_signal((Handler)port_wakeup_sh, p_ptr->ref);
P
Per Liden 已提交
875 876 877 878
}

void tipc_acknowledge(u32 ref, u32 ack)
{
879
	struct tipc_port *p_ptr;
880
	struct sk_buff *buf = NULL;
P
Per Liden 已提交
881

882
	p_ptr = tipc_port_lock(ref);
P
Per Liden 已提交
883 884
	if (!p_ptr)
		return;
885 886
	if (p_ptr->connected) {
		p_ptr->conn_unacked -= ack;
P
Per Liden 已提交
887 888 889 890 891 892
		buf = port_build_proto_msg(port_peerport(p_ptr),
					   port_peernode(p_ptr),
					   ref,
					   tipc_own_addr,
					   CONN_MANAGER,
					   CONN_ACK,
893
					   TIPC_OK,
P
Per Liden 已提交
894 895
					   ack);
	}
896 897
	tipc_port_unlock(p_ptr);
	tipc_net_route_msg(buf);
P
Per Liden 已提交
898 899 900
}

/*
901
 * tipc_createport(): user level call.
P
Per Liden 已提交
902 903
 */

904
int tipc_createport(void *usr_handle,
905 906 907 908 909 910 911
		    unsigned int importance,
		    tipc_msg_err_event error_cb,
		    tipc_named_msg_err_event named_error_cb,
		    tipc_conn_shutdown_event conn_error_cb,
		    tipc_msg_event msg_cb,
		    tipc_named_msg_event named_msg_cb,
		    tipc_conn_msg_event conn_msg_cb,
P
Per Liden 已提交
912 913 914 915
		    tipc_continue_event continue_event_cb,/* May be zero */
		    u32 *portref)
{
	struct user_port *up_ptr;
916
	struct tipc_port *p_ptr;
P
Per Liden 已提交
917

918
	up_ptr = kmalloc(sizeof(*up_ptr), GFP_ATOMIC);
919
	if (!up_ptr) {
920
		warn("Port creation failed, no memory\n");
P
Per Liden 已提交
921 922
		return -ENOMEM;
	}
923
	p_ptr = (struct tipc_port *)tipc_createport_raw(NULL, port_dispatcher,
924 925
						   port_wakeup, importance);
	if (!p_ptr) {
P
Per Liden 已提交
926 927 928 929 930 931
		kfree(up_ptr);
		return -ENOMEM;
	}

	p_ptr->user_port = up_ptr;
	up_ptr->usr_handle = usr_handle;
932
	up_ptr->ref = p_ptr->ref;
P
Per Liden 已提交
933 934 935 936 937 938 939
	up_ptr->err_cb = error_cb;
	up_ptr->named_err_cb = named_error_cb;
	up_ptr->conn_err_cb = conn_error_cb;
	up_ptr->msg_cb = msg_cb;
	up_ptr->named_msg_cb = named_msg_cb;
	up_ptr->conn_msg_cb = conn_msg_cb;
	up_ptr->continue_event_cb = continue_event_cb;
940
	*portref = p_ptr->ref;
941
	tipc_port_unlock(p_ptr);
942
	return 0;
P
Per Liden 已提交
943 944 945 946
}

int tipc_portimportance(u32 ref, unsigned int *importance)
{
947
	struct tipc_port *p_ptr;
948

949
	p_ptr = tipc_port_lock(ref);
P
Per Liden 已提交
950 951
	if (!p_ptr)
		return -EINVAL;
952
	*importance = (unsigned int)msg_importance(&p_ptr->phdr);
J
Julia Lawall 已提交
953
	tipc_port_unlock(p_ptr);
954
	return 0;
P
Per Liden 已提交
955 956 957 958
}

int tipc_set_portimportance(u32 ref, unsigned int imp)
{
959
	struct tipc_port *p_ptr;
P
Per Liden 已提交
960 961 962 963

	if (imp > TIPC_CRITICAL_IMPORTANCE)
		return -EINVAL;

964
	p_ptr = tipc_port_lock(ref);
P
Per Liden 已提交
965 966
	if (!p_ptr)
		return -EINVAL;
967
	msg_set_importance(&p_ptr->phdr, (u32)imp);
J
Julia Lawall 已提交
968
	tipc_port_unlock(p_ptr);
969
	return 0;
P
Per Liden 已提交
970 971 972 973 974
}


int tipc_publish(u32 ref, unsigned int scope, struct tipc_name_seq const *seq)
{
975
	struct tipc_port *p_ptr;
P
Per Liden 已提交
976 977 978 979
	struct publication *publ;
	u32 key;
	int res = -EINVAL;

980
	p_ptr = tipc_port_lock(ref);
981 982 983
	if (!p_ptr)
		return -EINVAL;

984
	if (p_ptr->connected)
P
Per Liden 已提交
985 986 987 988 989 990 991 992 993 994
		goto exit;
	if (seq->lower > seq->upper)
		goto exit;
	if ((scope < TIPC_ZONE_SCOPE) || (scope > TIPC_NODE_SCOPE))
		goto exit;
	key = ref + p_ptr->pub_count + 1;
	if (key == ref) {
		res = -EADDRINUSE;
		goto exit;
	}
995
	publ = tipc_nametbl_publish(seq->type, seq->lower, seq->upper,
996
				    scope, p_ptr->ref, key);
P
Per Liden 已提交
997 998 999
	if (publ) {
		list_add(&publ->pport_list, &p_ptr->publications);
		p_ptr->pub_count++;
1000
		p_ptr->published = 1;
1001
		res = 0;
P
Per Liden 已提交
1002 1003
	}
exit:
1004
	tipc_port_unlock(p_ptr);
P
Per Liden 已提交
1005 1006 1007 1008 1009
	return res;
}

int tipc_withdraw(u32 ref, unsigned int scope, struct tipc_name_seq const *seq)
{
1010
	struct tipc_port *p_ptr;
P
Per Liden 已提交
1011 1012 1013
	struct publication *publ;
	struct publication *tpubl;
	int res = -EINVAL;
1014

1015
	p_ptr = tipc_port_lock(ref);
P
Per Liden 已提交
1016 1017 1018
	if (!p_ptr)
		return -EINVAL;
	if (!seq) {
1019
		list_for_each_entry_safe(publ, tpubl,
P
Per Liden 已提交
1020
					 &p_ptr->publications, pport_list) {
1021
			tipc_nametbl_withdraw(publ->type, publ->lower,
1022
					      publ->ref, publ->key);
P
Per Liden 已提交
1023
		}
1024
		res = 0;
P
Per Liden 已提交
1025
	} else {
1026
		list_for_each_entry_safe(publ, tpubl,
P
Per Liden 已提交
1027 1028 1029 1030 1031 1032 1033 1034 1035
					 &p_ptr->publications, pport_list) {
			if (publ->scope != scope)
				continue;
			if (publ->type != seq->type)
				continue;
			if (publ->lower != seq->lower)
				continue;
			if (publ->upper != seq->upper)
				break;
1036
			tipc_nametbl_withdraw(publ->type, publ->lower,
1037
					      publ->ref, publ->key);
1038
			res = 0;
P
Per Liden 已提交
1039 1040 1041 1042
			break;
		}
	}
	if (list_empty(&p_ptr->publications))
1043
		p_ptr->published = 0;
1044
	tipc_port_unlock(p_ptr);
P
Per Liden 已提交
1045 1046 1047 1048 1049
	return res;
}

int tipc_connect2port(u32 ref, struct tipc_portid const *peer)
{
1050
	struct tipc_port *p_ptr;
P
Per Liden 已提交
1051 1052 1053
	struct tipc_msg *msg;
	int res = -EINVAL;

1054
	p_ptr = tipc_port_lock(ref);
P
Per Liden 已提交
1055 1056
	if (!p_ptr)
		return -EINVAL;
1057
	if (p_ptr->published || p_ptr->connected)
P
Per Liden 已提交
1058 1059 1060 1061
		goto exit;
	if (!peer->ref)
		goto exit;

1062
	msg = &p_ptr->phdr;
P
Per Liden 已提交
1063 1064 1065
	msg_set_destnode(msg, peer->node);
	msg_set_destport(msg, peer->ref);
	msg_set_orignode(msg, tipc_own_addr);
1066
	msg_set_origport(msg, p_ptr->ref);
P
Per Liden 已提交
1067
	msg_set_type(msg, TIPC_CONN_MSG);
1068
	msg_set_hdr_sz(msg, SHORT_H_SIZE);
P
Per Liden 已提交
1069 1070 1071

	p_ptr->probing_interval = PROBING_INTERVAL;
	p_ptr->probing_state = CONFIRMED;
1072
	p_ptr->connected = 1;
P
Per Liden 已提交
1073 1074
	k_start_timer(&p_ptr->timer, p_ptr->probing_interval);

1075
	tipc_nodesub_subscribe(&p_ptr->subscription, peer->node,
1076
			  (void *)(unsigned long)ref,
P
Per Liden 已提交
1077
			  (net_ev_handler)port_handle_node_down);
1078
	res = 0;
P
Per Liden 已提交
1079
exit:
1080
	tipc_port_unlock(p_ptr);
1081
	p_ptr->max_pkt = tipc_link_get_max_pkt(peer->node, ref);
P
Per Liden 已提交
1082 1083 1084
	return res;
}

1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098
/**
 * tipc_disconnect_port - disconnect port from peer
 *
 * Port must be locked.
 */

int tipc_disconnect_port(struct tipc_port *tp_ptr)
{
	int res;

	if (tp_ptr->connected) {
		tp_ptr->connected = 0;
		/* let timer expire on it's own to avoid deadlock! */
		tipc_nodesub_unsubscribe(
1099
			&((struct tipc_port *)tp_ptr)->subscription);
1100
		res = 0;
1101 1102 1103 1104 1105 1106
	} else {
		res = -ENOTCONN;
	}
	return res;
}

P
Per Liden 已提交
1107 1108 1109 1110 1111 1112 1113
/*
 * tipc_disconnect(): Disconnect port form peer.
 *                    This is a node local operation.
 */

int tipc_disconnect(u32 ref)
{
1114
	struct tipc_port *p_ptr;
1115
	int res;
P
Per Liden 已提交
1116

1117
	p_ptr = tipc_port_lock(ref);
P
Per Liden 已提交
1118 1119
	if (!p_ptr)
		return -EINVAL;
1120
	res = tipc_disconnect_port((struct tipc_port *)p_ptr);
1121
	tipc_port_unlock(p_ptr);
P
Per Liden 已提交
1122 1123 1124 1125 1126 1127 1128 1129
	return res;
}

/*
 * tipc_shutdown(): Send a SHUTDOWN msg to peer and disconnect
 */
int tipc_shutdown(u32 ref)
{
1130
	struct tipc_port *p_ptr;
1131
	struct sk_buff *buf = NULL;
P
Per Liden 已提交
1132

1133
	p_ptr = tipc_port_lock(ref);
P
Per Liden 已提交
1134 1135 1136
	if (!p_ptr)
		return -EINVAL;

1137 1138
	if (p_ptr->connected) {
		u32 imp = msg_importance(&p_ptr->phdr);
P
Per Liden 已提交
1139 1140 1141 1142 1143 1144 1145 1146
		if (imp < TIPC_CRITICAL_IMPORTANCE)
			imp++;
		buf = port_build_proto_msg(port_peerport(p_ptr),
					   port_peernode(p_ptr),
					   ref,
					   tipc_own_addr,
					   imp,
					   TIPC_CONN_MSG,
1147
					   TIPC_CONN_SHUTDOWN,
P
Per Liden 已提交
1148 1149
					   0);
	}
1150 1151
	tipc_port_unlock(p_ptr);
	tipc_net_route_msg(buf);
P
Per Liden 已提交
1152 1153 1154 1155
	return tipc_disconnect(ref);
}

/*
1156
 *  tipc_port_recv_sections(): Concatenate and deliver sectioned
P
Per Liden 已提交
1157 1158 1159
 *                        message for this node.
 */

1160
static int tipc_port_recv_sections(struct tipc_port *sender, unsigned int num_sect,
1161
				   struct iovec const *msg_sect)
P
Per Liden 已提交
1162 1163 1164
{
	struct sk_buff *buf;
	int res;
1165

1166
	res = tipc_msg_build(&sender->phdr, msg_sect, num_sect,
P
Per Liden 已提交
1167 1168
			MAX_MSG_SIZE, !sender->user_port, &buf);
	if (likely(buf))
1169
		tipc_port_recv_msg(buf);
P
Per Liden 已提交
1170 1171 1172 1173 1174 1175 1176 1177 1178
	return res;
}

/**
 * tipc_send - send message sections on connection
 */

int tipc_send(u32 ref, unsigned int num_sect, struct iovec const *msg_sect)
{
1179
	struct tipc_port *p_ptr;
P
Per Liden 已提交
1180 1181 1182
	u32 destnode;
	int res;

1183
	p_ptr = tipc_port_deref(ref);
1184
	if (!p_ptr || !p_ptr->connected)
P
Per Liden 已提交
1185 1186
		return -EINVAL;

1187
	p_ptr->congested = 1;
1188
	if (!tipc_port_congested(p_ptr)) {
P
Per Liden 已提交
1189 1190
		destnode = port_peernode(p_ptr);
		if (likely(destnode != tipc_own_addr))
1191 1192
			res = tipc_link_send_sections_fast(p_ptr, msg_sect, num_sect,
							   destnode);
P
Per Liden 已提交
1193
		else
1194
			res = tipc_port_recv_sections(p_ptr, num_sect, msg_sect);
P
Per Liden 已提交
1195 1196

		if (likely(res != -ELINKCONG)) {
1197
			p_ptr->congested = 0;
1198 1199
			if (res > 0)
				p_ptr->sent++;
P
Per Liden 已提交
1200 1201 1202 1203
			return res;
		}
	}
	if (port_unreliable(p_ptr)) {
1204
		p_ptr->congested = 0;
P
Per Liden 已提交
1205
		/* Just calculate msg length and return */
1206
		return tipc_msg_calc_data_size(msg_sect, num_sect);
P
Per Liden 已提交
1207 1208 1209 1210 1211
	}
	return -ELINKCONG;
}

/**
1212
 * tipc_send2name - send message sections to port name
P
Per Liden 已提交
1213 1214
 */

1215 1216
int tipc_send2name(u32 ref, struct tipc_name const *name, unsigned int domain,
	   unsigned int num_sect, struct iovec const *msg_sect)
P
Per Liden 已提交
1217
{
1218
	struct tipc_port *p_ptr;
P
Per Liden 已提交
1219 1220
	struct tipc_msg *msg;
	u32 destnode = domain;
1221
	u32 destport;
P
Per Liden 已提交
1222 1223
	int res;

1224
	p_ptr = tipc_port_deref(ref);
1225
	if (!p_ptr || p_ptr->connected)
P
Per Liden 已提交
1226 1227
		return -EINVAL;

1228
	msg = &p_ptr->phdr;
P
Per Liden 已提交
1229
	msg_set_type(msg, TIPC_NAMED_MSG);
1230 1231
	msg_set_orignode(msg, tipc_own_addr);
	msg_set_origport(msg, ref);
P
Per Liden 已提交
1232 1233 1234
	msg_set_hdr_sz(msg, LONG_H_SIZE);
	msg_set_nametype(msg, name->type);
	msg_set_nameinst(msg, name->instance);
1235
	msg_set_lookup_scope(msg, tipc_addr_scope(domain));
1236
	destport = tipc_nametbl_translate(name->type, name->instance, &destnode);
P
Per Liden 已提交
1237 1238 1239
	msg_set_destnode(msg, destnode);
	msg_set_destport(msg, destport);

1240
	if (likely(destport)) {
P
Per Liden 已提交
1241
		if (likely(destnode == tipc_own_addr))
1242 1243 1244 1245 1246 1247 1248 1249
			res = tipc_port_recv_sections(p_ptr, num_sect,
						      msg_sect);
		else
			res = tipc_link_send_sections_fast(p_ptr, msg_sect,
							   num_sect, destnode);
		if (likely(res != -ELINKCONG)) {
			if (res > 0)
				p_ptr->sent++;
P
Per Liden 已提交
1250
			return res;
1251
		}
P
Per Liden 已提交
1252 1253
		if (port_unreliable(p_ptr)) {
			/* Just calculate msg length and return */
1254
			return tipc_msg_calc_data_size(msg_sect, num_sect);
P
Per Liden 已提交
1255 1256 1257
		}
		return -ELINKCONG;
	}
1258
	return tipc_port_reject_sections(p_ptr, msg, msg_sect, num_sect,
1259
					 TIPC_ERR_NO_NAME);
P
Per Liden 已提交
1260 1261 1262
}

/**
1263
 * tipc_send2port - send message sections to port identity
P
Per Liden 已提交
1264 1265
 */

1266 1267
int tipc_send2port(u32 ref, struct tipc_portid const *dest,
	   unsigned int num_sect, struct iovec const *msg_sect)
P
Per Liden 已提交
1268
{
1269
	struct tipc_port *p_ptr;
P
Per Liden 已提交
1270 1271 1272
	struct tipc_msg *msg;
	int res;

1273
	p_ptr = tipc_port_deref(ref);
1274
	if (!p_ptr || p_ptr->connected)
P
Per Liden 已提交
1275 1276
		return -EINVAL;

1277
	msg = &p_ptr->phdr;
P
Per Liden 已提交
1278
	msg_set_type(msg, TIPC_DIRECT_MSG);
1279 1280
	msg_set_orignode(msg, tipc_own_addr);
	msg_set_origport(msg, ref);
P
Per Liden 已提交
1281 1282 1283
	msg_set_destnode(msg, dest->node);
	msg_set_destport(msg, dest->ref);
	msg_set_hdr_sz(msg, DIR_MSG_H_SIZE);
1284

P
Per Liden 已提交
1285
	if (dest->node == tipc_own_addr)
1286 1287 1288 1289 1290 1291 1292
		res =  tipc_port_recv_sections(p_ptr, num_sect, msg_sect);
	else
		res = tipc_link_send_sections_fast(p_ptr, msg_sect, num_sect,
						   dest->node);
	if (likely(res != -ELINKCONG)) {
		if (res > 0)
			p_ptr->sent++;
P
Per Liden 已提交
1293
		return res;
1294
	}
P
Per Liden 已提交
1295 1296
	if (port_unreliable(p_ptr)) {
		/* Just calculate msg length and return */
1297
		return tipc_msg_calc_data_size(msg_sect, num_sect);
P
Per Liden 已提交
1298 1299 1300 1301
	}
	return -ELINKCONG;
}

1302
/**
1303
 * tipc_send_buf2port - send message buffer to port identity
P
Per Liden 已提交
1304 1305
 */

1306 1307
int tipc_send_buf2port(u32 ref, struct tipc_portid const *dest,
	       struct sk_buff *buf, unsigned int dsz)
P
Per Liden 已提交
1308
{
1309
	struct tipc_port *p_ptr;
P
Per Liden 已提交
1310 1311 1312
	struct tipc_msg *msg;
	int res;

1313 1314
	p_ptr = (struct tipc_port *)tipc_ref_deref(ref);
	if (!p_ptr || p_ptr->connected)
P
Per Liden 已提交
1315 1316
		return -EINVAL;

1317
	msg = &p_ptr->phdr;
P
Per Liden 已提交
1318
	msg_set_type(msg, TIPC_DIRECT_MSG);
1319 1320
	msg_set_orignode(msg, tipc_own_addr);
	msg_set_origport(msg, ref);
P
Per Liden 已提交
1321 1322 1323 1324 1325 1326 1327 1328
	msg_set_destnode(msg, dest->node);
	msg_set_destport(msg, dest->ref);
	msg_set_hdr_sz(msg, DIR_MSG_H_SIZE);
	msg_set_size(msg, DIR_MSG_H_SIZE + dsz);
	if (skb_cow(buf, DIR_MSG_H_SIZE))
		return -ENOMEM;

	skb_push(buf, DIR_MSG_H_SIZE);
1329
	skb_copy_to_linear_data(buf, msg, DIR_MSG_H_SIZE);
1330

P
Per Liden 已提交
1331
	if (dest->node == tipc_own_addr)
1332 1333 1334 1335 1336 1337
		res = tipc_port_recv_msg(buf);
	else
		res = tipc_send_buf_fast(buf, dest->node);
	if (likely(res != -ELINKCONG)) {
		if (res > 0)
			p_ptr->sent++;
P
Per Liden 已提交
1338
		return res;
1339
	}
P
Per Liden 已提交
1340 1341 1342 1343 1344
	if (port_unreliable(p_ptr))
		return dsz;
	return -ELINKCONG;
}