tipc: take lock while updating node network address
[deliverable/linux.git] / net / tipc / port.c
CommitLineData
b97bf3fd
PL
1/*
2 * net/tipc/port.c: TIPC port code
c4307285 3 *
05646c91 4 * Copyright (c) 1992-2007, Ericsson AB
23dd4cce 5 * Copyright (c) 2004-2008, 2010-2011, Wind River Systems
b97bf3fd
PL
6 * All rights reserved.
7 *
9ea1fd3c 8 * Redistribution and use in source and binary forms, with or without
b97bf3fd
PL
9 * modification, are permitted provided that the following conditions are met:
10 *
9ea1fd3c
PL
11 * 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.
b97bf3fd 19 *
9ea1fd3c
PL
20 * 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
b97bf3fd
PL
34 * POSSIBILITY OF SUCH DAMAGE.
35 */
36
37#include "core.h"
38#include "config.h"
b97bf3fd 39#include "port.h"
b97bf3fd 40#include "name_table.h"
b97bf3fd
PL
41
42/* Connection management: */
43#define PROBING_INTERVAL 3600000 /* [ms] => 1 h */
44#define CONFIRMED 0
45#define PROBING 1
46
47#define MAX_REJECT_SIZE 1024
48
e3ec9c7d
AS
49static struct sk_buff *msg_queue_head;
50static struct sk_buff *msg_queue_tail;
b97bf3fd 51
34af946a
IM
52DEFINE_SPINLOCK(tipc_port_list_lock);
53static DEFINE_SPINLOCK(queue_lock);
b97bf3fd 54
4323add6 55static LIST_HEAD(ports);
b97bf3fd 56static void port_handle_node_down(unsigned long ref);
23dd4cce
AS
57static struct sk_buff *port_build_self_abort_msg(struct tipc_port *, u32 err);
58static struct sk_buff *port_build_peer_abort_msg(struct tipc_port *, u32 err);
b97bf3fd
PL
59static void port_timeout(unsigned long ref);
60
61
d0e17fed 62static inline u32 port_peernode(struct tipc_port *p_ptr)
b97bf3fd 63{
23dd4cce 64 return msg_destnode(&p_ptr->phdr);
b97bf3fd
PL
65}
66
d0e17fed 67static inline u32 port_peerport(struct tipc_port *p_ptr)
b97bf3fd 68{
23dd4cce 69 return msg_destport(&p_ptr->phdr);
b97bf3fd
PL
70}
71
f0712e86
AS
72/*
73 * tipc_port_peer_msg - verify message was sent by connected port's peer
74 *
75 * Handles cases where the node's network address has changed from
76 * the default of <0.0.0> to its configured setting.
77 */
78
79int tipc_port_peer_msg(struct tipc_port *p_ptr, struct tipc_msg *msg)
80{
81 u32 peernode;
82 u32 orignode;
83
84 if (msg_origport(msg) != port_peerport(p_ptr))
85 return 0;
86
87 orignode = msg_orignode(msg);
88 peernode = port_peernode(p_ptr);
89 return (orignode == peernode) ||
90 (!orignode && (peernode == tipc_own_addr)) ||
91 (!peernode && (orignode == tipc_own_addr));
92}
93
b97bf3fd
PL
94/**
95 * tipc_multicast - send a multicast message to local and remote destinations
96 */
97
38f232ea 98int tipc_multicast(u32 ref, struct tipc_name_seq const *seq,
26896904
AS
99 u32 num_sect, struct iovec const *msg_sect,
100 unsigned int total_len)
b97bf3fd
PL
101{
102 struct tipc_msg *hdr;
103 struct sk_buff *buf;
104 struct sk_buff *ibuf = NULL;
4584310b 105 struct tipc_port_list dports = {0, NULL, };
23dd4cce 106 struct tipc_port *oport = tipc_port_deref(ref);
b97bf3fd
PL
107 int ext_targets;
108 int res;
109
110 if (unlikely(!oport))
111 return -EINVAL;
112
113 /* Create multicast message */
114
23dd4cce 115 hdr = &oport->phdr;
b97bf3fd 116 msg_set_type(hdr, TIPC_MCAST_MSG);
53b94364 117 msg_set_lookup_scope(hdr, TIPC_CLUSTER_SCOPE);
7462b9e9
AS
118 msg_set_destport(hdr, 0);
119 msg_set_destnode(hdr, 0);
b97bf3fd
PL
120 msg_set_nametype(hdr, seq->type);
121 msg_set_namelower(hdr, seq->lower);
122 msg_set_nameupper(hdr, seq->upper);
123 msg_set_hdr_sz(hdr, MCAST_H_SIZE);
26896904 124 res = tipc_msg_build(hdr, msg_sect, num_sect, total_len, MAX_MSG_SIZE,
b97bf3fd
PL
125 !oport->user_port, &buf);
126 if (unlikely(!buf))
127 return res;
128
129 /* Figure out where to send multicast message */
130
4323add6
PL
131 ext_targets = tipc_nametbl_mc_translate(seq->type, seq->lower, seq->upper,
132 TIPC_NODE_SCOPE, &dports);
c4307285
YH
133
134 /* Send message to destinations (duplicate it only if necessary) */
b97bf3fd
PL
135
136 if (ext_targets) {
137 if (dports.count != 0) {
138 ibuf = skb_copy(buf, GFP_ATOMIC);
139 if (ibuf == NULL) {
4323add6 140 tipc_port_list_free(&dports);
5f6d9123 141 kfree_skb(buf);
b97bf3fd
PL
142 return -ENOMEM;
143 }
144 }
4323add6 145 res = tipc_bclink_send_msg(buf);
a016892c 146 if ((res < 0) && (dports.count != 0))
5f6d9123 147 kfree_skb(ibuf);
b97bf3fd
PL
148 } else {
149 ibuf = buf;
150 }
151
152 if (res >= 0) {
153 if (ibuf)
4323add6 154 tipc_port_recv_mcast(ibuf, &dports);
b97bf3fd 155 } else {
4323add6 156 tipc_port_list_free(&dports);
b97bf3fd
PL
157 }
158 return res;
159}
160
161/**
4323add6 162 * tipc_port_recv_mcast - deliver multicast message to all destination ports
c4307285 163 *
b97bf3fd
PL
164 * If there is no port list, perform a lookup to create one
165 */
166
4584310b 167void tipc_port_recv_mcast(struct sk_buff *buf, struct tipc_port_list *dp)
b97bf3fd 168{
0e65967e 169 struct tipc_msg *msg;
4584310b
PG
170 struct tipc_port_list dports = {0, NULL, };
171 struct tipc_port_list *item = dp;
b97bf3fd
PL
172 int cnt = 0;
173
b97bf3fd
PL
174 msg = buf_msg(buf);
175
176 /* Create destination port list, if one wasn't supplied */
177
178 if (dp == NULL) {
4323add6 179 tipc_nametbl_mc_translate(msg_nametype(msg),
b97bf3fd
PL
180 msg_namelower(msg),
181 msg_nameupper(msg),
182 TIPC_CLUSTER_SCOPE,
183 &dports);
184 item = dp = &dports;
185 }
186
187 /* Deliver a copy of message to each destination port */
188
189 if (dp->count != 0) {
7f47f5c7 190 msg_set_destnode(msg, tipc_own_addr);
b97bf3fd
PL
191 if (dp->count == 1) {
192 msg_set_destport(msg, dp->ports[0]);
4323add6
PL
193 tipc_port_recv_msg(buf);
194 tipc_port_list_free(dp);
b97bf3fd
PL
195 return;
196 }
197 for (; cnt < dp->count; cnt++) {
198 int index = cnt % PLSIZE;
199 struct sk_buff *b = skb_clone(buf, GFP_ATOMIC);
200
201 if (b == NULL) {
a10bd924 202 warn("Unable to deliver multicast message(s)\n");
b97bf3fd
PL
203 goto exit;
204 }
a016892c 205 if ((index == 0) && (cnt != 0))
b97bf3fd 206 item = item->next;
0e65967e 207 msg_set_destport(buf_msg(b), item->ports[index]);
4323add6 208 tipc_port_recv_msg(b);
b97bf3fd
PL
209 }
210 }
211exit:
5f6d9123 212 kfree_skb(buf);
4323add6 213 tipc_port_list_free(dp);
b97bf3fd
PL
214}
215
216/**
7ef43eba 217 * tipc_createport_raw - create a generic TIPC port
c4307285 218 *
0ea52241 219 * Returns pointer to (locked) TIPC port, or NULL if unable to create it
b97bf3fd
PL
220 */
221
0ea52241 222struct tipc_port *tipc_createport_raw(void *usr_handle,
b97bf3fd
PL
223 u32 (*dispatcher)(struct tipc_port *, struct sk_buff *),
224 void (*wakeup)(struct tipc_port *),
0ea52241 225 const u32 importance)
b97bf3fd 226{
23dd4cce 227 struct tipc_port *p_ptr;
b97bf3fd
PL
228 struct tipc_msg *msg;
229 u32 ref;
230
0da974f4 231 p_ptr = kzalloc(sizeof(*p_ptr), GFP_ATOMIC);
a10bd924
AS
232 if (!p_ptr) {
233 warn("Port creation failed, no memory\n");
0ea52241 234 return NULL;
b97bf3fd 235 }
23dd4cce 236 ref = tipc_ref_acquire(p_ptr, &p_ptr->lock);
b97bf3fd 237 if (!ref) {
a10bd924 238 warn("Port creation failed, reference table exhausted\n");
b97bf3fd 239 kfree(p_ptr);
0ea52241 240 return NULL;
b97bf3fd
PL
241 }
242
23dd4cce
AS
243 p_ptr->usr_handle = usr_handle;
244 p_ptr->max_pkt = MAX_PKT_DEFAULT;
245 p_ptr->ref = ref;
b97bf3fd
PL
246 INIT_LIST_HEAD(&p_ptr->wait_list);
247 INIT_LIST_HEAD(&p_ptr->subscription.nodesub_list);
b97bf3fd
PL
248 p_ptr->dispatcher = dispatcher;
249 p_ptr->wakeup = wakeup;
1fc54d8f 250 p_ptr->user_port = NULL;
b97bf3fd 251 k_init_timer(&p_ptr->timer, (Handler)port_timeout, ref);
b97bf3fd
PL
252 INIT_LIST_HEAD(&p_ptr->publications);
253 INIT_LIST_HEAD(&p_ptr->port_list);
f21536d1
AS
254
255 /*
256 * Must hold port list lock while initializing message header template
257 * to ensure a change to node's own network address doesn't result
258 * in template containing out-dated network address information
259 */
260
261 spin_lock_bh(&tipc_port_list_lock);
262 msg = &p_ptr->phdr;
263 tipc_msg_init(msg, importance, TIPC_NAMED_MSG, NAMED_H_SIZE, 0);
264 msg_set_origport(msg, ref);
b97bf3fd 265 list_add_tail(&p_ptr->port_list, &ports);
4323add6 266 spin_unlock_bh(&tipc_port_list_lock);
23dd4cce 267 return p_ptr;
b97bf3fd
PL
268}
269
270int tipc_deleteport(u32 ref)
271{
23dd4cce 272 struct tipc_port *p_ptr;
1fc54d8f 273 struct sk_buff *buf = NULL;
b97bf3fd 274
1fc54d8f 275 tipc_withdraw(ref, 0, NULL);
4323add6 276 p_ptr = tipc_port_lock(ref);
c4307285 277 if (!p_ptr)
b97bf3fd
PL
278 return -EINVAL;
279
4323add6
PL
280 tipc_ref_discard(ref);
281 tipc_port_unlock(p_ptr);
b97bf3fd
PL
282
283 k_cancel_timer(&p_ptr->timer);
23dd4cce 284 if (p_ptr->connected) {
b97bf3fd 285 buf = port_build_peer_abort_msg(p_ptr, TIPC_ERR_NO_PORT);
4323add6 286 tipc_nodesub_unsubscribe(&p_ptr->subscription);
b97bf3fd 287 }
e83504f7 288 kfree(p_ptr->user_port);
b97bf3fd 289
4323add6 290 spin_lock_bh(&tipc_port_list_lock);
b97bf3fd
PL
291 list_del(&p_ptr->port_list);
292 list_del(&p_ptr->wait_list);
4323add6 293 spin_unlock_bh(&tipc_port_list_lock);
b97bf3fd
PL
294 k_term_timer(&p_ptr->timer);
295 kfree(p_ptr);
4323add6 296 tipc_net_route_msg(buf);
0e35fd5e 297 return 0;
b97bf3fd
PL
298}
299
23dd4cce 300static int port_unreliable(struct tipc_port *p_ptr)
b97bf3fd 301{
23dd4cce 302 return msg_src_droppable(&p_ptr->phdr);
b97bf3fd
PL
303}
304
305int tipc_portunreliable(u32 ref, unsigned int *isunreliable)
306{
23dd4cce 307 struct tipc_port *p_ptr;
c4307285 308
4323add6 309 p_ptr = tipc_port_lock(ref);
b97bf3fd
PL
310 if (!p_ptr)
311 return -EINVAL;
312 *isunreliable = port_unreliable(p_ptr);
4cec72c8 313 tipc_port_unlock(p_ptr);
0e35fd5e 314 return 0;
b97bf3fd
PL
315}
316
317int tipc_set_portunreliable(u32 ref, unsigned int isunreliable)
318{
23dd4cce 319 struct tipc_port *p_ptr;
c4307285 320
4323add6 321 p_ptr = tipc_port_lock(ref);
b97bf3fd
PL
322 if (!p_ptr)
323 return -EINVAL;
23dd4cce 324 msg_set_src_droppable(&p_ptr->phdr, (isunreliable != 0));
4323add6 325 tipc_port_unlock(p_ptr);
0e35fd5e 326 return 0;
b97bf3fd
PL
327}
328
23dd4cce 329static int port_unreturnable(struct tipc_port *p_ptr)
b97bf3fd 330{
23dd4cce 331 return msg_dest_droppable(&p_ptr->phdr);
b97bf3fd
PL
332}
333
334int tipc_portunreturnable(u32 ref, unsigned int *isunrejectable)
335{
23dd4cce 336 struct tipc_port *p_ptr;
c4307285 337
4323add6 338 p_ptr = tipc_port_lock(ref);
b97bf3fd
PL
339 if (!p_ptr)
340 return -EINVAL;
341 *isunrejectable = port_unreturnable(p_ptr);
4cec72c8 342 tipc_port_unlock(p_ptr);
0e35fd5e 343 return 0;
b97bf3fd
PL
344}
345
346int tipc_set_portunreturnable(u32 ref, unsigned int isunrejectable)
347{
23dd4cce 348 struct tipc_port *p_ptr;
c4307285 349
4323add6 350 p_ptr = tipc_port_lock(ref);
b97bf3fd
PL
351 if (!p_ptr)
352 return -EINVAL;
23dd4cce 353 msg_set_dest_droppable(&p_ptr->phdr, (isunrejectable != 0));
4323add6 354 tipc_port_unlock(p_ptr);
0e35fd5e 355 return 0;
b97bf3fd
PL
356}
357
c4307285 358/*
e4a0aee4
AS
359 * port_build_proto_msg(): create connection protocol message for port
360 *
361 * On entry the port must be locked and connected.
b97bf3fd 362 */
e4a0aee4
AS
363static struct sk_buff *port_build_proto_msg(struct tipc_port *p_ptr,
364 u32 type, u32 ack)
b97bf3fd
PL
365{
366 struct sk_buff *buf;
367 struct tipc_msg *msg;
c4307285 368
741d9eb7 369 buf = tipc_buf_acquire(INT_H_SIZE);
b97bf3fd
PL
370 if (buf) {
371 msg = buf_msg(buf);
e4a0aee4
AS
372 tipc_msg_init(msg, CONN_MANAGER, type, INT_H_SIZE,
373 port_peernode(p_ptr));
374 msg_set_destport(msg, port_peerport(p_ptr));
375 msg_set_origport(msg, p_ptr->ref);
b97bf3fd 376 msg_set_msgcnt(msg, ack);
b97bf3fd
PL
377 }
378 return buf;
379}
380
b97bf3fd
PL
381int tipc_reject_msg(struct sk_buff *buf, u32 err)
382{
383 struct tipc_msg *msg = buf_msg(buf);
384 struct sk_buff *rbuf;
385 struct tipc_msg *rmsg;
386 int hdr_sz;
7dd1bf28 387 u32 imp;
b97bf3fd 388 u32 data_sz = msg_data_sz(msg);
017dac31 389 u32 src_node;
7dd1bf28 390 u32 rmsg_sz;
b97bf3fd
PL
391
392 /* discard rejected message if it shouldn't be returned to sender */
76d12527
AS
393
394 if (WARN(!msg_isdata(msg),
395 "attempt to reject message with user=%u", msg_user(msg))) {
396 dump_stack();
397 goto exit;
398 }
acc631bf
AS
399 if (msg_errcode(msg) || msg_dest_droppable(msg))
400 goto exit;
b97bf3fd 401
7dd1bf28
AS
402 /*
403 * construct returned message by copying rejected message header and
404 * data (or subset), then updating header fields that need adjusting
405 */
406
407 hdr_sz = msg_hdr_sz(msg);
408 rmsg_sz = hdr_sz + min_t(u32, data_sz, MAX_REJECT_SIZE);
409
410 rbuf = tipc_buf_acquire(rmsg_sz);
acc631bf
AS
411 if (rbuf == NULL)
412 goto exit;
413
b97bf3fd 414 rmsg = buf_msg(rbuf);
7dd1bf28
AS
415 skb_copy_to_linear_data(rbuf, msg, rmsg_sz);
416
417 if (msg_connected(rmsg)) {
418 imp = msg_importance(rmsg);
419 if (imp < TIPC_CRITICAL_IMPORTANCE)
420 msg_set_importance(rmsg, ++imp);
99c14593 421 }
7dd1bf28
AS
422 msg_set_non_seq(rmsg, 0);
423 msg_set_size(rmsg, rmsg_sz);
424 msg_set_errcode(rmsg, err);
425 msg_set_prevnode(rmsg, tipc_own_addr);
426 msg_swap_words(rmsg, 4, 5);
427 if (!msg_short(rmsg))
428 msg_swap_words(rmsg, 6, 7);
b97bf3fd
PL
429
430 /* send self-abort message when rejecting on a connected port */
431 if (msg_connected(msg)) {
23dd4cce 432 struct tipc_port *p_ptr = tipc_port_lock(msg_destport(msg));
b97bf3fd
PL
433
434 if (p_ptr) {
dff10e9e
AS
435 struct sk_buff *abuf = NULL;
436
23dd4cce 437 if (p_ptr->connected)
b97bf3fd 438 abuf = port_build_self_abort_msg(p_ptr, err);
4323add6 439 tipc_port_unlock(p_ptr);
dff10e9e 440 tipc_net_route_msg(abuf);
b97bf3fd 441 }
b97bf3fd
PL
442 }
443
acc631bf
AS
444 /* send returned message & dispose of rejected message */
445
017dac31
AS
446 src_node = msg_prevnode(msg);
447 if (src_node == tipc_own_addr)
448 tipc_port_recv_msg(rbuf);
449 else
450 tipc_link_send(rbuf, src_node, msg_link_selector(rmsg));
acc631bf 451exit:
5f6d9123 452 kfree_skb(buf);
b97bf3fd
PL
453 return data_sz;
454}
455
23dd4cce 456int tipc_port_reject_sections(struct tipc_port *p_ptr, struct tipc_msg *hdr,
4323add6 457 struct iovec const *msg_sect, u32 num_sect,
26896904 458 unsigned int total_len, int err)
b97bf3fd
PL
459{
460 struct sk_buff *buf;
461 int res;
462
26896904 463 res = tipc_msg_build(hdr, msg_sect, num_sect, total_len, MAX_MSG_SIZE,
b97bf3fd
PL
464 !p_ptr->user_port, &buf);
465 if (!buf)
466 return res;
467
468 return tipc_reject_msg(buf, err);
469}
470
471static void port_timeout(unsigned long ref)
472{
23dd4cce 473 struct tipc_port *p_ptr = tipc_port_lock(ref);
1fc54d8f 474 struct sk_buff *buf = NULL;
b97bf3fd 475
065fd177
AS
476 if (!p_ptr)
477 return;
478
23dd4cce 479 if (!p_ptr->connected) {
065fd177 480 tipc_port_unlock(p_ptr);
b97bf3fd 481 return;
065fd177 482 }
b97bf3fd
PL
483
484 /* Last probe answered ? */
485 if (p_ptr->probing_state == PROBING) {
486 buf = port_build_self_abort_msg(p_ptr, TIPC_ERR_NO_PORT);
487 } else {
e4a0aee4 488 buf = port_build_proto_msg(p_ptr, CONN_PROBE, 0);
b97bf3fd
PL
489 p_ptr->probing_state = PROBING;
490 k_start_timer(&p_ptr->timer, p_ptr->probing_interval);
491 }
4323add6
PL
492 tipc_port_unlock(p_ptr);
493 tipc_net_route_msg(buf);
b97bf3fd
PL
494}
495
496
497static void port_handle_node_down(unsigned long ref)
498{
23dd4cce 499 struct tipc_port *p_ptr = tipc_port_lock(ref);
0e65967e 500 struct sk_buff *buf = NULL;
b97bf3fd
PL
501
502 if (!p_ptr)
503 return;
504 buf = port_build_self_abort_msg(p_ptr, TIPC_ERR_NO_NODE);
4323add6
PL
505 tipc_port_unlock(p_ptr);
506 tipc_net_route_msg(buf);
b97bf3fd
PL
507}
508
509
23dd4cce 510static struct sk_buff *port_build_self_abort_msg(struct tipc_port *p_ptr, u32 err)
b97bf3fd 511{
e244a915 512 struct sk_buff *buf = port_build_peer_abort_msg(p_ptr, err);
b97bf3fd 513
e244a915
AS
514 if (buf) {
515 struct tipc_msg *msg = buf_msg(buf);
516 msg_swap_words(msg, 4, 5);
517 msg_swap_words(msg, 6, 7);
518 }
519 return buf;
b97bf3fd
PL
520}
521
522
23dd4cce 523static struct sk_buff *port_build_peer_abort_msg(struct tipc_port *p_ptr, u32 err)
b97bf3fd 524{
e244a915
AS
525 struct sk_buff *buf;
526 struct tipc_msg *msg;
527 u32 imp;
b97bf3fd 528
23dd4cce 529 if (!p_ptr->connected)
1fc54d8f 530 return NULL;
e244a915
AS
531
532 buf = tipc_buf_acquire(BASIC_H_SIZE);
533 if (buf) {
534 msg = buf_msg(buf);
535 memcpy(msg, &p_ptr->phdr, BASIC_H_SIZE);
536 msg_set_hdr_sz(msg, BASIC_H_SIZE);
537 msg_set_size(msg, BASIC_H_SIZE);
538 imp = msg_importance(msg);
539 if (imp < TIPC_CRITICAL_IMPORTANCE)
540 msg_set_importance(msg, ++imp);
541 msg_set_errcode(msg, err);
542 }
543 return buf;
b97bf3fd
PL
544}
545
4323add6 546void tipc_port_recv_proto_msg(struct sk_buff *buf)
b97bf3fd
PL
547{
548 struct tipc_msg *msg = buf_msg(buf);
1c1a551a 549 struct tipc_port *p_ptr;
1fc54d8f 550 struct sk_buff *r_buf = NULL;
1c1a551a
AS
551 u32 destport = msg_destport(msg);
552 int wakeable;
553
554 /* Validate connection */
555
556 p_ptr = tipc_port_lock(destport);
f0712e86 557 if (!p_ptr || !p_ptr->connected || !tipc_port_peer_msg(p_ptr, msg)) {
f55b5640
AS
558 r_buf = tipc_buf_acquire(BASIC_H_SIZE);
559 if (r_buf) {
560 msg = buf_msg(r_buf);
561 tipc_msg_init(msg, TIPC_HIGH_IMPORTANCE, TIPC_CONN_MSG,
f0712e86 562 BASIC_H_SIZE, msg_orignode(msg));
f55b5640
AS
563 msg_set_errcode(msg, TIPC_ERR_NO_PORT);
564 msg_set_origport(msg, destport);
f0712e86 565 msg_set_destport(msg, msg_origport(msg));
f55b5640 566 }
1c1a551a
AS
567 if (p_ptr)
568 tipc_port_unlock(p_ptr);
b97bf3fd
PL
569 goto exit;
570 }
571
1c1a551a
AS
572 /* Process protocol message sent by peer */
573
574 switch (msg_type(msg)) {
575 case CONN_ACK:
576 wakeable = tipc_port_congested(p_ptr) && p_ptr->congested &&
577 p_ptr->wakeup;
578 p_ptr->acked += msg_msgcnt(msg);
579 if (!tipc_port_congested(p_ptr)) {
580 p_ptr->congested = 0;
581 if (wakeable)
582 p_ptr->wakeup(p_ptr);
583 }
584 break;
585 case CONN_PROBE:
e4a0aee4 586 r_buf = port_build_proto_msg(p_ptr, CONN_PROBE_REPLY, 0);
1c1a551a
AS
587 break;
588 default:
589 /* CONN_PROBE_REPLY or unrecognized - no action required */
590 break;
b97bf3fd
PL
591 }
592 p_ptr->probing_state = CONFIRMED;
1c1a551a 593 tipc_port_unlock(p_ptr);
b97bf3fd 594exit:
4323add6 595 tipc_net_route_msg(r_buf);
5f6d9123 596 kfree_skb(buf);
b97bf3fd
PL
597}
598
23dd4cce 599static void port_print(struct tipc_port *p_ptr, struct print_buf *buf, int full_id)
b97bf3fd 600{
c4307285 601 struct publication *publ;
b97bf3fd
PL
602
603 if (full_id)
c4307285 604 tipc_printf(buf, "<%u.%u.%u:%u>:",
b97bf3fd 605 tipc_zone(tipc_own_addr), tipc_cluster(tipc_own_addr),
23dd4cce 606 tipc_node(tipc_own_addr), p_ptr->ref);
b97bf3fd 607 else
23dd4cce 608 tipc_printf(buf, "%-10u:", p_ptr->ref);
b97bf3fd 609
23dd4cce 610 if (p_ptr->connected) {
c4307285
YH
611 u32 dport = port_peerport(p_ptr);
612 u32 destnode = port_peernode(p_ptr);
613
614 tipc_printf(buf, " connected to <%u.%u.%u:%u>",
615 tipc_zone(destnode), tipc_cluster(destnode),
616 tipc_node(destnode), dport);
23dd4cce 617 if (p_ptr->conn_type != 0)
c4307285 618 tipc_printf(buf, " via {%u,%u}",
23dd4cce
AS
619 p_ptr->conn_type,
620 p_ptr->conn_instance);
621 } else if (p_ptr->published) {
c4307285
YH
622 tipc_printf(buf, " bound to");
623 list_for_each_entry(publ, &p_ptr->publications, pport_list) {
b97bf3fd
PL
624 if (publ->lower == publ->upper)
625 tipc_printf(buf, " {%u,%u}", publ->type,
626 publ->lower);
627 else
c4307285 628 tipc_printf(buf, " {%u,%u,%u}", publ->type,
b97bf3fd 629 publ->lower, publ->upper);
c4307285
YH
630 }
631 }
632 tipc_printf(buf, "\n");
b97bf3fd
PL
633}
634
635#define MAX_PORT_QUERY 32768
636
4323add6 637struct sk_buff *tipc_port_get_ports(void)
b97bf3fd
PL
638{
639 struct sk_buff *buf;
640 struct tlv_desc *rep_tlv;
641 struct print_buf pb;
23dd4cce 642 struct tipc_port *p_ptr;
b97bf3fd
PL
643 int str_len;
644
4323add6 645 buf = tipc_cfg_reply_alloc(TLV_SPACE(MAX_PORT_QUERY));
b97bf3fd
PL
646 if (!buf)
647 return NULL;
648 rep_tlv = (struct tlv_desc *)buf->data;
649
4323add6
PL
650 tipc_printbuf_init(&pb, TLV_DATA(rep_tlv), MAX_PORT_QUERY);
651 spin_lock_bh(&tipc_port_list_lock);
b97bf3fd 652 list_for_each_entry(p_ptr, &ports, port_list) {
23dd4cce 653 spin_lock_bh(p_ptr->lock);
b97bf3fd 654 port_print(p_ptr, &pb, 0);
23dd4cce 655 spin_unlock_bh(p_ptr->lock);
b97bf3fd 656 }
4323add6
PL
657 spin_unlock_bh(&tipc_port_list_lock);
658 str_len = tipc_printbuf_validate(&pb);
b97bf3fd
PL
659
660 skb_put(buf, TLV_SPACE(str_len));
661 TLV_SET(rep_tlv, TIPC_TLV_ULTRA_STRING, NULL, str_len);
662
663 return buf;
664}
665
4323add6 666void tipc_port_reinit(void)
b97bf3fd 667{
23dd4cce 668 struct tipc_port *p_ptr;
b97bf3fd
PL
669 struct tipc_msg *msg;
670
4323add6 671 spin_lock_bh(&tipc_port_list_lock);
b97bf3fd 672 list_for_each_entry(p_ptr, &ports, port_list) {
23dd4cce 673 msg = &p_ptr->phdr;
6d4a6672 674 msg_set_prevnode(msg, tipc_own_addr);
b97bf3fd
PL
675 msg_set_orignode(msg, tipc_own_addr);
676 }
4323add6 677 spin_unlock_bh(&tipc_port_list_lock);
b97bf3fd
PL
678}
679
680
681/*
682 * port_dispatcher_sigh(): Signal handler for messages destinated
683 * to the tipc_port interface.
684 */
685
686static void port_dispatcher_sigh(void *dummy)
687{
688 struct sk_buff *buf;
689
690 spin_lock_bh(&queue_lock);
691 buf = msg_queue_head;
1fc54d8f 692 msg_queue_head = NULL;
b97bf3fd
PL
693 spin_unlock_bh(&queue_lock);
694
695 while (buf) {
23dd4cce 696 struct tipc_port *p_ptr;
b97bf3fd
PL
697 struct user_port *up_ptr;
698 struct tipc_portid orig;
699 struct tipc_name_seq dseq;
700 void *usr_handle;
701 int connected;
f0712e86 702 int peer_invalid;
b97bf3fd 703 int published;
9688243b 704 u32 message_type;
b97bf3fd
PL
705
706 struct sk_buff *next = buf->next;
707 struct tipc_msg *msg = buf_msg(buf);
708 u32 dref = msg_destport(msg);
c4307285 709
9688243b
AS
710 message_type = msg_type(msg);
711 if (message_type > TIPC_DIRECT_MSG)
712 goto reject; /* Unsupported message type */
713
4323add6 714 p_ptr = tipc_port_lock(dref);
9688243b
AS
715 if (!p_ptr)
716 goto reject; /* Port deleted while msg in queue */
717
b97bf3fd
PL
718 orig.ref = msg_origport(msg);
719 orig.node = msg_orignode(msg);
720 up_ptr = p_ptr->user_port;
721 usr_handle = up_ptr->usr_handle;
23dd4cce 722 connected = p_ptr->connected;
f0712e86 723 peer_invalid = connected && !tipc_port_peer_msg(p_ptr, msg);
23dd4cce 724 published = p_ptr->published;
b97bf3fd
PL
725
726 if (unlikely(msg_errcode(msg)))
727 goto err;
728
9688243b 729 switch (message_type) {
c4307285 730
b97bf3fd
PL
731 case TIPC_CONN_MSG:{
732 tipc_conn_msg_event cb = up_ptr->conn_msg_cb;
cb7ce914 733 u32 dsz;
b97bf3fd 734
4cec72c8 735 tipc_port_unlock(p_ptr);
5307e469
AS
736 if (unlikely(!cb))
737 goto reject;
b97bf3fd 738 if (unlikely(!connected)) {
84b07c16 739 if (tipc_connect2port(dref, &orig))
b97bf3fd 740 goto reject;
f0712e86 741 } else if (peer_invalid)
b97bf3fd 742 goto reject;
cb7ce914
AS
743 dsz = msg_data_sz(msg);
744 if (unlikely(dsz &&
745 (++p_ptr->conn_unacked >=
746 TIPC_FLOW_CONTROL_WIN)))
c4307285 747 tipc_acknowledge(dref,
23dd4cce 748 p_ptr->conn_unacked);
b97bf3fd 749 skb_pull(buf, msg_hdr_sz(msg));
cb7ce914 750 cb(usr_handle, dref, &buf, msg_data(msg), dsz);
b97bf3fd
PL
751 break;
752 }
753 case TIPC_DIRECT_MSG:{
754 tipc_msg_event cb = up_ptr->msg_cb;
755
4cec72c8 756 tipc_port_unlock(p_ptr);
5307e469 757 if (unlikely(!cb || connected))
b97bf3fd
PL
758 goto reject;
759 skb_pull(buf, msg_hdr_sz(msg));
c4307285 760 cb(usr_handle, dref, &buf, msg_data(msg),
b97bf3fd
PL
761 msg_data_sz(msg), msg_importance(msg),
762 &orig);
763 break;
764 }
9688243b 765 case TIPC_MCAST_MSG:
b97bf3fd
PL
766 case TIPC_NAMED_MSG:{
767 tipc_named_msg_event cb = up_ptr->named_msg_cb;
768
4cec72c8 769 tipc_port_unlock(p_ptr);
5307e469 770 if (unlikely(!cb || connected || !published))
b97bf3fd
PL
771 goto reject;
772 dseq.type = msg_nametype(msg);
773 dseq.lower = msg_nameinst(msg);
9688243b
AS
774 dseq.upper = (message_type == TIPC_NAMED_MSG)
775 ? dseq.lower : msg_nameupper(msg);
b97bf3fd 776 skb_pull(buf, msg_hdr_sz(msg));
c4307285 777 cb(usr_handle, dref, &buf, msg_data(msg),
b97bf3fd
PL
778 msg_data_sz(msg), msg_importance(msg),
779 &orig, &dseq);
780 break;
781 }
782 }
783 if (buf)
5f6d9123 784 kfree_skb(buf);
b97bf3fd
PL
785 buf = next;
786 continue;
787err:
9688243b 788 switch (message_type) {
c4307285 789
b97bf3fd 790 case TIPC_CONN_MSG:{
c4307285 791 tipc_conn_shutdown_event cb =
b97bf3fd 792 up_ptr->conn_err_cb;
b97bf3fd 793
4cec72c8 794 tipc_port_unlock(p_ptr);
f0712e86 795 if (!cb || !connected || peer_invalid)
b97bf3fd
PL
796 break;
797 tipc_disconnect(dref);
798 skb_pull(buf, msg_hdr_sz(msg));
799 cb(usr_handle, dref, &buf, msg_data(msg),
800 msg_data_sz(msg), msg_errcode(msg));
801 break;
802 }
803 case TIPC_DIRECT_MSG:{
804 tipc_msg_err_event cb = up_ptr->err_cb;
805
4cec72c8 806 tipc_port_unlock(p_ptr);
5307e469 807 if (!cb || connected)
b97bf3fd
PL
808 break;
809 skb_pull(buf, msg_hdr_sz(msg));
810 cb(usr_handle, dref, &buf, msg_data(msg),
811 msg_data_sz(msg), msg_errcode(msg), &orig);
812 break;
813 }
9688243b 814 case TIPC_MCAST_MSG:
b97bf3fd 815 case TIPC_NAMED_MSG:{
c4307285 816 tipc_named_msg_err_event cb =
b97bf3fd
PL
817 up_ptr->named_err_cb;
818
4cec72c8 819 tipc_port_unlock(p_ptr);
5307e469 820 if (!cb || connected)
b97bf3fd
PL
821 break;
822 dseq.type = msg_nametype(msg);
823 dseq.lower = msg_nameinst(msg);
9688243b
AS
824 dseq.upper = (message_type == TIPC_NAMED_MSG)
825 ? dseq.lower : msg_nameupper(msg);
b97bf3fd 826 skb_pull(buf, msg_hdr_sz(msg));
c4307285 827 cb(usr_handle, dref, &buf, msg_data(msg),
b97bf3fd
PL
828 msg_data_sz(msg), msg_errcode(msg), &dseq);
829 break;
830 }
831 }
832 if (buf)
5f6d9123 833 kfree_skb(buf);
b97bf3fd
PL
834 buf = next;
835 continue;
836reject:
837 tipc_reject_msg(buf, TIPC_ERR_NO_PORT);
838 buf = next;
839 }
840}
841
842/*
843 * port_dispatcher(): Dispatcher for messages destinated
844 * to the tipc_port interface. Called with port locked.
845 */
846
847static u32 port_dispatcher(struct tipc_port *dummy, struct sk_buff *buf)
848{
849 buf->next = NULL;
850 spin_lock_bh(&queue_lock);
851 if (msg_queue_head) {
852 msg_queue_tail->next = buf;
853 msg_queue_tail = buf;
854 } else {
855 msg_queue_tail = msg_queue_head = buf;
4323add6 856 tipc_k_signal((Handler)port_dispatcher_sigh, 0);
b97bf3fd
PL
857 }
858 spin_unlock_bh(&queue_lock);
0e35fd5e 859 return 0;
b97bf3fd
PL
860}
861
c4307285 862/*
b97bf3fd 863 * Wake up port after congestion: Called with port locked,
c4307285 864 *
b97bf3fd
PL
865 */
866
867static void port_wakeup_sh(unsigned long ref)
868{
23dd4cce 869 struct tipc_port *p_ptr;
b97bf3fd 870 struct user_port *up_ptr;
1fc54d8f
SR
871 tipc_continue_event cb = NULL;
872 void *uh = NULL;
b97bf3fd 873
4323add6 874 p_ptr = tipc_port_lock(ref);
b97bf3fd
PL
875 if (p_ptr) {
876 up_ptr = p_ptr->user_port;
877 if (up_ptr) {
878 cb = up_ptr->continue_event_cb;
879 uh = up_ptr->usr_handle;
880 }
4323add6 881 tipc_port_unlock(p_ptr);
b97bf3fd
PL
882 }
883 if (cb)
884 cb(uh, ref);
885}
886
887
888static void port_wakeup(struct tipc_port *p_ptr)
889{
4323add6 890 tipc_k_signal((Handler)port_wakeup_sh, p_ptr->ref);
b97bf3fd
PL
891}
892
893void tipc_acknowledge(u32 ref, u32 ack)
894{
23dd4cce 895 struct tipc_port *p_ptr;
1fc54d8f 896 struct sk_buff *buf = NULL;
b97bf3fd 897
4323add6 898 p_ptr = tipc_port_lock(ref);
b97bf3fd
PL
899 if (!p_ptr)
900 return;
23dd4cce
AS
901 if (p_ptr->connected) {
902 p_ptr->conn_unacked -= ack;
e4a0aee4 903 buf = port_build_proto_msg(p_ptr, CONN_ACK, ack);
b97bf3fd 904 }
4323add6
PL
905 tipc_port_unlock(p_ptr);
906 tipc_net_route_msg(buf);
b97bf3fd
PL
907}
908
909/*
b0c1e928 910 * tipc_createport(): user level call.
b97bf3fd
PL
911 */
912
b0c1e928 913int tipc_createport(void *usr_handle,
c4307285
YH
914 unsigned int importance,
915 tipc_msg_err_event error_cb,
916 tipc_named_msg_err_event named_error_cb,
917 tipc_conn_shutdown_event conn_error_cb,
918 tipc_msg_event msg_cb,
919 tipc_named_msg_event named_msg_cb,
920 tipc_conn_msg_event conn_msg_cb,
b97bf3fd
PL
921 tipc_continue_event continue_event_cb,/* May be zero */
922 u32 *portref)
923{
924 struct user_port *up_ptr;
23dd4cce 925 struct tipc_port *p_ptr;
b97bf3fd 926
0da974f4 927 up_ptr = kmalloc(sizeof(*up_ptr), GFP_ATOMIC);
a10bd924 928 if (!up_ptr) {
a75bf874 929 warn("Port creation failed, no memory\n");
b97bf3fd
PL
930 return -ENOMEM;
931 }
23dd4cce 932 p_ptr = (struct tipc_port *)tipc_createport_raw(NULL, port_dispatcher,
0ea52241
AS
933 port_wakeup, importance);
934 if (!p_ptr) {
b97bf3fd
PL
935 kfree(up_ptr);
936 return -ENOMEM;
937 }
938
939 p_ptr->user_port = up_ptr;
b97bf3fd 940 up_ptr->usr_handle = usr_handle;
23dd4cce 941 up_ptr->ref = p_ptr->ref;
b97bf3fd
PL
942 up_ptr->err_cb = error_cb;
943 up_ptr->named_err_cb = named_error_cb;
944 up_ptr->conn_err_cb = conn_error_cb;
945 up_ptr->msg_cb = msg_cb;
946 up_ptr->named_msg_cb = named_msg_cb;
947 up_ptr->conn_msg_cb = conn_msg_cb;
948 up_ptr->continue_event_cb = continue_event_cb;
23dd4cce 949 *portref = p_ptr->ref;
4323add6 950 tipc_port_unlock(p_ptr);
0e35fd5e 951 return 0;
b97bf3fd
PL
952}
953
b97bf3fd
PL
954int tipc_portimportance(u32 ref, unsigned int *importance)
955{
23dd4cce 956 struct tipc_port *p_ptr;
c4307285 957
4323add6 958 p_ptr = tipc_port_lock(ref);
b97bf3fd
PL
959 if (!p_ptr)
960 return -EINVAL;
23dd4cce 961 *importance = (unsigned int)msg_importance(&p_ptr->phdr);
4cec72c8 962 tipc_port_unlock(p_ptr);
0e35fd5e 963 return 0;
b97bf3fd
PL
964}
965
966int tipc_set_portimportance(u32 ref, unsigned int imp)
967{
23dd4cce 968 struct tipc_port *p_ptr;
b97bf3fd
PL
969
970 if (imp > TIPC_CRITICAL_IMPORTANCE)
971 return -EINVAL;
972
4323add6 973 p_ptr = tipc_port_lock(ref);
b97bf3fd
PL
974 if (!p_ptr)
975 return -EINVAL;
23dd4cce 976 msg_set_importance(&p_ptr->phdr, (u32)imp);
4cec72c8 977 tipc_port_unlock(p_ptr);
0e35fd5e 978 return 0;
b97bf3fd
PL
979}
980
981
982int tipc_publish(u32 ref, unsigned int scope, struct tipc_name_seq const *seq)
983{
23dd4cce 984 struct tipc_port *p_ptr;
b97bf3fd
PL
985 struct publication *publ;
986 u32 key;
987 int res = -EINVAL;
988
4323add6 989 p_ptr = tipc_port_lock(ref);
d55b4c63
AB
990 if (!p_ptr)
991 return -EINVAL;
992
23dd4cce 993 if (p_ptr->connected)
b97bf3fd
PL
994 goto exit;
995 if (seq->lower > seq->upper)
996 goto exit;
997 if ((scope < TIPC_ZONE_SCOPE) || (scope > TIPC_NODE_SCOPE))
998 goto exit;
999 key = ref + p_ptr->pub_count + 1;
1000 if (key == ref) {
1001 res = -EADDRINUSE;
1002 goto exit;
1003 }
4323add6 1004 publ = tipc_nametbl_publish(seq->type, seq->lower, seq->upper,
23dd4cce 1005 scope, p_ptr->ref, key);
b97bf3fd
PL
1006 if (publ) {
1007 list_add(&publ->pport_list, &p_ptr->publications);
1008 p_ptr->pub_count++;
23dd4cce 1009 p_ptr->published = 1;
0e35fd5e 1010 res = 0;
b97bf3fd
PL
1011 }
1012exit:
4323add6 1013 tipc_port_unlock(p_ptr);
b97bf3fd
PL
1014 return res;
1015}
1016
1017int tipc_withdraw(u32 ref, unsigned int scope, struct tipc_name_seq const *seq)
1018{
23dd4cce 1019 struct tipc_port *p_ptr;
b97bf3fd
PL
1020 struct publication *publ;
1021 struct publication *tpubl;
1022 int res = -EINVAL;
c4307285 1023
4323add6 1024 p_ptr = tipc_port_lock(ref);
b97bf3fd
PL
1025 if (!p_ptr)
1026 return -EINVAL;
b97bf3fd 1027 if (!seq) {
c4307285 1028 list_for_each_entry_safe(publ, tpubl,
b97bf3fd 1029 &p_ptr->publications, pport_list) {
c4307285 1030 tipc_nametbl_withdraw(publ->type, publ->lower,
4323add6 1031 publ->ref, publ->key);
b97bf3fd 1032 }
0e35fd5e 1033 res = 0;
b97bf3fd 1034 } else {
c4307285 1035 list_for_each_entry_safe(publ, tpubl,
b97bf3fd
PL
1036 &p_ptr->publications, pport_list) {
1037 if (publ->scope != scope)
1038 continue;
1039 if (publ->type != seq->type)
1040 continue;
1041 if (publ->lower != seq->lower)
1042 continue;
1043 if (publ->upper != seq->upper)
1044 break;
c4307285 1045 tipc_nametbl_withdraw(publ->type, publ->lower,
4323add6 1046 publ->ref, publ->key);
0e35fd5e 1047 res = 0;
b97bf3fd
PL
1048 break;
1049 }
1050 }
1051 if (list_empty(&p_ptr->publications))
23dd4cce 1052 p_ptr->published = 0;
4323add6 1053 tipc_port_unlock(p_ptr);
b97bf3fd
PL
1054 return res;
1055}
1056
1057int tipc_connect2port(u32 ref, struct tipc_portid const *peer)
1058{
23dd4cce 1059 struct tipc_port *p_ptr;
b97bf3fd
PL
1060 struct tipc_msg *msg;
1061 int res = -EINVAL;
1062
4323add6 1063 p_ptr = tipc_port_lock(ref);
b97bf3fd
PL
1064 if (!p_ptr)
1065 return -EINVAL;
23dd4cce 1066 if (p_ptr->published || p_ptr->connected)
b97bf3fd
PL
1067 goto exit;
1068 if (!peer->ref)
1069 goto exit;
1070
23dd4cce 1071 msg = &p_ptr->phdr;
b97bf3fd
PL
1072 msg_set_destnode(msg, peer->node);
1073 msg_set_destport(msg, peer->ref);
b97bf3fd 1074 msg_set_type(msg, TIPC_CONN_MSG);
53b94364 1075 msg_set_lookup_scope(msg, 0);
08c80e9a 1076 msg_set_hdr_sz(msg, SHORT_H_SIZE);
b97bf3fd
PL
1077
1078 p_ptr->probing_interval = PROBING_INTERVAL;
1079 p_ptr->probing_state = CONFIRMED;
23dd4cce 1080 p_ptr->connected = 1;
b97bf3fd
PL
1081 k_start_timer(&p_ptr->timer, p_ptr->probing_interval);
1082
0e65967e 1083 tipc_nodesub_subscribe(&p_ptr->subscription, peer->node,
880b005f 1084 (void *)(unsigned long)ref,
b97bf3fd 1085 (net_ev_handler)port_handle_node_down);
0e35fd5e 1086 res = 0;
b97bf3fd 1087exit:
4323add6 1088 tipc_port_unlock(p_ptr);
23dd4cce 1089 p_ptr->max_pkt = tipc_link_get_max_pkt(peer->node, ref);
b97bf3fd
PL
1090 return res;
1091}
1092
0c3141e9
AS
1093/**
1094 * tipc_disconnect_port - disconnect port from peer
1095 *
1096 * Port must be locked.
1097 */
1098
1099int tipc_disconnect_port(struct tipc_port *tp_ptr)
1100{
1101 int res;
1102
1103 if (tp_ptr->connected) {
1104 tp_ptr->connected = 0;
1105 /* let timer expire on it's own to avoid deadlock! */
1106 tipc_nodesub_unsubscribe(
23dd4cce 1107 &((struct tipc_port *)tp_ptr)->subscription);
0e35fd5e 1108 res = 0;
0c3141e9
AS
1109 } else {
1110 res = -ENOTCONN;
1111 }
1112 return res;
1113}
1114
b97bf3fd
PL
1115/*
1116 * tipc_disconnect(): Disconnect port form peer.
1117 * This is a node local operation.
1118 */
1119
1120int tipc_disconnect(u32 ref)
1121{
23dd4cce 1122 struct tipc_port *p_ptr;
0c3141e9 1123 int res;
b97bf3fd 1124
4323add6 1125 p_ptr = tipc_port_lock(ref);
b97bf3fd
PL
1126 if (!p_ptr)
1127 return -EINVAL;
0c3141e9 1128 res = tipc_disconnect_port((struct tipc_port *)p_ptr);
4323add6 1129 tipc_port_unlock(p_ptr);
b97bf3fd
PL
1130 return res;
1131}
1132
1133/*
1134 * tipc_shutdown(): Send a SHUTDOWN msg to peer and disconnect
1135 */
1136int tipc_shutdown(u32 ref)
1137{
23dd4cce 1138 struct tipc_port *p_ptr;
1fc54d8f 1139 struct sk_buff *buf = NULL;
b97bf3fd 1140
4323add6 1141 p_ptr = tipc_port_lock(ref);
b97bf3fd
PL
1142 if (!p_ptr)
1143 return -EINVAL;
1144
e244a915 1145 buf = port_build_peer_abort_msg(p_ptr, TIPC_CONN_SHUTDOWN);
4323add6
PL
1146 tipc_port_unlock(p_ptr);
1147 tipc_net_route_msg(buf);
b97bf3fd
PL
1148 return tipc_disconnect(ref);
1149}
1150
9b641251
AS
1151/**
1152 * tipc_port_recv_msg - receive message from lower layer and deliver to port user
1153 */
1154
1155int tipc_port_recv_msg(struct sk_buff *buf)
1156{
1157 struct tipc_port *p_ptr;
1158 struct tipc_msg *msg = buf_msg(buf);
1159 u32 destport = msg_destport(msg);
1160 u32 dsz = msg_data_sz(msg);
1161 u32 err;
1162
1163 /* forward unresolved named message */
1164 if (unlikely(!destport)) {
1165 tipc_net_route_msg(buf);
1166 return dsz;
1167 }
1168
1169 /* validate destination & pass to port, otherwise reject message */
1170 p_ptr = tipc_port_lock(destport);
1171 if (likely(p_ptr)) {
9b641251
AS
1172 err = p_ptr->dispatcher(p_ptr, buf);
1173 tipc_port_unlock(p_ptr);
1174 if (likely(!err))
1175 return dsz;
1176 } else {
1177 err = TIPC_ERR_NO_PORT;
1178 }
f0712e86 1179
9b641251
AS
1180 return tipc_reject_msg(buf, err);
1181}
1182
b97bf3fd 1183/*
4323add6 1184 * tipc_port_recv_sections(): Concatenate and deliver sectioned
b97bf3fd
PL
1185 * message for this node.
1186 */
1187
23dd4cce 1188static int tipc_port_recv_sections(struct tipc_port *sender, unsigned int num_sect,
26896904
AS
1189 struct iovec const *msg_sect,
1190 unsigned int total_len)
b97bf3fd
PL
1191{
1192 struct sk_buff *buf;
1193 int res;
c4307285 1194
26896904 1195 res = tipc_msg_build(&sender->phdr, msg_sect, num_sect, total_len,
b97bf3fd
PL
1196 MAX_MSG_SIZE, !sender->user_port, &buf);
1197 if (likely(buf))
4323add6 1198 tipc_port_recv_msg(buf);
b97bf3fd
PL
1199 return res;
1200}
1201
1202/**
1203 * tipc_send - send message sections on connection
1204 */
1205
26896904
AS
1206int tipc_send(u32 ref, unsigned int num_sect, struct iovec const *msg_sect,
1207 unsigned int total_len)
b97bf3fd 1208{
23dd4cce 1209 struct tipc_port *p_ptr;
b97bf3fd
PL
1210 u32 destnode;
1211 int res;
1212
4323add6 1213 p_ptr = tipc_port_deref(ref);
23dd4cce 1214 if (!p_ptr || !p_ptr->connected)
b97bf3fd
PL
1215 return -EINVAL;
1216
23dd4cce 1217 p_ptr->congested = 1;
4323add6 1218 if (!tipc_port_congested(p_ptr)) {
b97bf3fd
PL
1219 destnode = port_peernode(p_ptr);
1220 if (likely(destnode != tipc_own_addr))
4323add6 1221 res = tipc_link_send_sections_fast(p_ptr, msg_sect, num_sect,
26896904 1222 total_len, destnode);
b97bf3fd 1223 else
26896904
AS
1224 res = tipc_port_recv_sections(p_ptr, num_sect, msg_sect,
1225 total_len);
b97bf3fd
PL
1226
1227 if (likely(res != -ELINKCONG)) {
23dd4cce 1228 p_ptr->congested = 0;
cb7ce914
AS
1229 if (res > 0)
1230 p_ptr->sent++;
b97bf3fd
PL
1231 return res;
1232 }
1233 }
1234 if (port_unreliable(p_ptr)) {
23dd4cce 1235 p_ptr->congested = 0;
26896904 1236 return total_len;
b97bf3fd
PL
1237 }
1238 return -ELINKCONG;
1239}
1240
b97bf3fd 1241/**
12bae479 1242 * tipc_send2name - send message sections to port name
b97bf3fd
PL
1243 */
1244
12bae479 1245int tipc_send2name(u32 ref, struct tipc_name const *name, unsigned int domain,
26896904
AS
1246 unsigned int num_sect, struct iovec const *msg_sect,
1247 unsigned int total_len)
b97bf3fd 1248{
23dd4cce 1249 struct tipc_port *p_ptr;
b97bf3fd
PL
1250 struct tipc_msg *msg;
1251 u32 destnode = domain;
9ccc2eb4 1252 u32 destport;
b97bf3fd
PL
1253 int res;
1254
4323add6 1255 p_ptr = tipc_port_deref(ref);
23dd4cce 1256 if (!p_ptr || p_ptr->connected)
b97bf3fd
PL
1257 return -EINVAL;
1258
23dd4cce 1259 msg = &p_ptr->phdr;
b97bf3fd 1260 msg_set_type(msg, TIPC_NAMED_MSG);
741d9eb7 1261 msg_set_hdr_sz(msg, NAMED_H_SIZE);
b97bf3fd
PL
1262 msg_set_nametype(msg, name->type);
1263 msg_set_nameinst(msg, name->instance);
c68ca7b7 1264 msg_set_lookup_scope(msg, tipc_addr_scope(domain));
4323add6 1265 destport = tipc_nametbl_translate(name->type, name->instance, &destnode);
b97bf3fd
PL
1266 msg_set_destnode(msg, destnode);
1267 msg_set_destport(msg, destport);
1268
bc9f8143 1269 if (likely(destport || destnode)) {
b97bf3fd 1270 if (likely(destnode == tipc_own_addr))
cb7ce914 1271 res = tipc_port_recv_sections(p_ptr, num_sect,
26896904 1272 msg_sect, total_len);
cb7ce914
AS
1273 else
1274 res = tipc_link_send_sections_fast(p_ptr, msg_sect,
26896904
AS
1275 num_sect, total_len,
1276 destnode);
cb7ce914
AS
1277 if (likely(res != -ELINKCONG)) {
1278 if (res > 0)
1279 p_ptr->sent++;
b97bf3fd 1280 return res;
cb7ce914 1281 }
b97bf3fd 1282 if (port_unreliable(p_ptr)) {
26896904 1283 return total_len;
b97bf3fd
PL
1284 }
1285 return -ELINKCONG;
1286 }
c4307285 1287 return tipc_port_reject_sections(p_ptr, msg, msg_sect, num_sect,
26896904 1288 total_len, TIPC_ERR_NO_NAME);
b97bf3fd
PL
1289}
1290
1291/**
12bae479 1292 * tipc_send2port - send message sections to port identity
b97bf3fd
PL
1293 */
1294
12bae479 1295int tipc_send2port(u32 ref, struct tipc_portid const *dest,
26896904
AS
1296 unsigned int num_sect, struct iovec const *msg_sect,
1297 unsigned int total_len)
b97bf3fd 1298{
23dd4cce 1299 struct tipc_port *p_ptr;
b97bf3fd
PL
1300 struct tipc_msg *msg;
1301 int res;
1302
4323add6 1303 p_ptr = tipc_port_deref(ref);
23dd4cce 1304 if (!p_ptr || p_ptr->connected)
b97bf3fd
PL
1305 return -EINVAL;
1306
23dd4cce 1307 msg = &p_ptr->phdr;
b97bf3fd 1308 msg_set_type(msg, TIPC_DIRECT_MSG);
53b94364 1309 msg_set_lookup_scope(msg, 0);
b97bf3fd
PL
1310 msg_set_destnode(msg, dest->node);
1311 msg_set_destport(msg, dest->ref);
741d9eb7 1312 msg_set_hdr_sz(msg, BASIC_H_SIZE);
cb7ce914 1313
b97bf3fd 1314 if (dest->node == tipc_own_addr)
26896904
AS
1315 res = tipc_port_recv_sections(p_ptr, num_sect, msg_sect,
1316 total_len);
cb7ce914
AS
1317 else
1318 res = tipc_link_send_sections_fast(p_ptr, msg_sect, num_sect,
26896904 1319 total_len, dest->node);
cb7ce914
AS
1320 if (likely(res != -ELINKCONG)) {
1321 if (res > 0)
1322 p_ptr->sent++;
b97bf3fd 1323 return res;
cb7ce914 1324 }
b97bf3fd 1325 if (port_unreliable(p_ptr)) {
26896904 1326 return total_len;
b97bf3fd
PL
1327 }
1328 return -ELINKCONG;
1329}
1330
c4307285 1331/**
12bae479 1332 * tipc_send_buf2port - send message buffer to port identity
b97bf3fd
PL
1333 */
1334
12bae479
AS
1335int tipc_send_buf2port(u32 ref, struct tipc_portid const *dest,
1336 struct sk_buff *buf, unsigned int dsz)
b97bf3fd 1337{
23dd4cce 1338 struct tipc_port *p_ptr;
b97bf3fd
PL
1339 struct tipc_msg *msg;
1340 int res;
1341
23dd4cce
AS
1342 p_ptr = (struct tipc_port *)tipc_ref_deref(ref);
1343 if (!p_ptr || p_ptr->connected)
b97bf3fd
PL
1344 return -EINVAL;
1345
23dd4cce 1346 msg = &p_ptr->phdr;
b97bf3fd 1347 msg_set_type(msg, TIPC_DIRECT_MSG);
b97bf3fd
PL
1348 msg_set_destnode(msg, dest->node);
1349 msg_set_destport(msg, dest->ref);
741d9eb7
AS
1350 msg_set_hdr_sz(msg, BASIC_H_SIZE);
1351 msg_set_size(msg, BASIC_H_SIZE + dsz);
1352 if (skb_cow(buf, BASIC_H_SIZE))
b97bf3fd
PL
1353 return -ENOMEM;
1354
741d9eb7
AS
1355 skb_push(buf, BASIC_H_SIZE);
1356 skb_copy_to_linear_data(buf, msg, BASIC_H_SIZE);
cb7ce914 1357
b97bf3fd 1358 if (dest->node == tipc_own_addr)
cb7ce914
AS
1359 res = tipc_port_recv_msg(buf);
1360 else
1361 res = tipc_send_buf_fast(buf, dest->node);
1362 if (likely(res != -ELINKCONG)) {
1363 if (res > 0)
1364 p_ptr->sent++;
b97bf3fd 1365 return res;
cb7ce914 1366 }
b97bf3fd
PL
1367 if (port_unreliable(p_ptr))
1368 return dsz;
1369 return -ELINKCONG;
1370}
1371
This page took 0.629759 seconds and 5 git commands to generate.