tipc: simplify connection congestion handling
[deliverable/linux.git] / net / tipc / port.c
CommitLineData
b97bf3fd
PL
1/*
2 * net/tipc/port.c: TIPC port code
c4307285 3 *
8826cde6 4 * Copyright (c) 1992-2007, 2014, Ericsson AB
198d73b8 5 * Copyright (c) 2004-2008, 2010-2013, 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"
8826cde6 41#include "socket.h"
b97bf3fd
PL
42
43/* Connection management: */
44#define PROBING_INTERVAL 3600000 /* [ms] => 1 h */
b97bf3fd
PL
45
46#define MAX_REJECT_SIZE 1024
47
34af946a 48DEFINE_SPINLOCK(tipc_port_list_lock);
b97bf3fd 49
4323add6 50static LIST_HEAD(ports);
b97bf3fd 51static void port_handle_node_down(unsigned long ref);
23dd4cce
AS
52static struct sk_buff *port_build_self_abort_msg(struct tipc_port *, u32 err);
53static struct sk_buff *port_build_peer_abort_msg(struct tipc_port *, u32 err);
b97bf3fd
PL
54static void port_timeout(unsigned long ref);
55
2c53040f 56/**
f0712e86
AS
57 * tipc_port_peer_msg - verify message was sent by connected port's peer
58 *
59 * Handles cases where the node's network address has changed from
60 * the default of <0.0.0> to its configured setting.
61 */
f0712e86
AS
62int tipc_port_peer_msg(struct tipc_port *p_ptr, struct tipc_msg *msg)
63{
64 u32 peernode;
65 u32 orignode;
66
f9fef18c 67 if (msg_origport(msg) != tipc_port_peerport(p_ptr))
f0712e86
AS
68 return 0;
69
70 orignode = msg_orignode(msg);
f9fef18c 71 peernode = tipc_port_peernode(p_ptr);
f0712e86
AS
72 return (orignode == peernode) ||
73 (!orignode && (peernode == tipc_own_addr)) ||
74 (!peernode && (orignode == tipc_own_addr));
75}
76
b97bf3fd 77/**
247f0f3c
YX
78 * tipc_port_mcast_xmit - send a multicast message to local and remote
79 * destinations
b97bf3fd 80 */
5c311421
JPM
81int tipc_port_mcast_xmit(struct tipc_port *oport,
82 struct tipc_name_seq const *seq,
83 struct iovec const *msg_sect,
84 unsigned int len)
b97bf3fd
PL
85{
86 struct tipc_msg *hdr;
87 struct sk_buff *buf;
88 struct sk_buff *ibuf = NULL;
4584310b 89 struct tipc_port_list dports = {0, NULL, };
b97bf3fd
PL
90 int ext_targets;
91 int res;
92
b97bf3fd 93 /* Create multicast message */
23dd4cce 94 hdr = &oport->phdr;
b97bf3fd 95 msg_set_type(hdr, TIPC_MCAST_MSG);
53b94364 96 msg_set_lookup_scope(hdr, TIPC_CLUSTER_SCOPE);
7462b9e9
AS
97 msg_set_destport(hdr, 0);
98 msg_set_destnode(hdr, 0);
b97bf3fd
PL
99 msg_set_nametype(hdr, seq->type);
100 msg_set_namelower(hdr, seq->lower);
101 msg_set_nameupper(hdr, seq->upper);
102 msg_set_hdr_sz(hdr, MCAST_H_SIZE);
9446b87a 103 res = tipc_msg_build(hdr, msg_sect, len, MAX_MSG_SIZE, &buf);
b97bf3fd
PL
104 if (unlikely(!buf))
105 return res;
106
107 /* Figure out where to send multicast message */
4323add6
PL
108 ext_targets = tipc_nametbl_mc_translate(seq->type, seq->lower, seq->upper,
109 TIPC_NODE_SCOPE, &dports);
c4307285
YH
110
111 /* Send message to destinations (duplicate it only if necessary) */
b97bf3fd
PL
112 if (ext_targets) {
113 if (dports.count != 0) {
114 ibuf = skb_copy(buf, GFP_ATOMIC);
115 if (ibuf == NULL) {
4323add6 116 tipc_port_list_free(&dports);
5f6d9123 117 kfree_skb(buf);
b97bf3fd
PL
118 return -ENOMEM;
119 }
120 }
247f0f3c 121 res = tipc_bclink_xmit(buf);
a016892c 122 if ((res < 0) && (dports.count != 0))
5f6d9123 123 kfree_skb(ibuf);
b97bf3fd
PL
124 } else {
125 ibuf = buf;
126 }
127
128 if (res >= 0) {
129 if (ibuf)
247f0f3c 130 tipc_port_mcast_rcv(ibuf, &dports);
b97bf3fd 131 } else {
4323add6 132 tipc_port_list_free(&dports);
b97bf3fd
PL
133 }
134 return res;
135}
136
137/**
247f0f3c 138 * tipc_port_mcast_rcv - deliver multicast message to all destination ports
c4307285 139 *
b97bf3fd
PL
140 * If there is no port list, perform a lookup to create one
141 */
247f0f3c 142void tipc_port_mcast_rcv(struct sk_buff *buf, struct tipc_port_list *dp)
b97bf3fd 143{
0e65967e 144 struct tipc_msg *msg;
4584310b
PG
145 struct tipc_port_list dports = {0, NULL, };
146 struct tipc_port_list *item = dp;
b97bf3fd
PL
147 int cnt = 0;
148
b97bf3fd
PL
149 msg = buf_msg(buf);
150
151 /* Create destination port list, if one wasn't supplied */
b97bf3fd 152 if (dp == NULL) {
4323add6 153 tipc_nametbl_mc_translate(msg_nametype(msg),
b97bf3fd
PL
154 msg_namelower(msg),
155 msg_nameupper(msg),
156 TIPC_CLUSTER_SCOPE,
157 &dports);
158 item = dp = &dports;
159 }
160
161 /* Deliver a copy of message to each destination port */
b97bf3fd 162 if (dp->count != 0) {
7f47f5c7 163 msg_set_destnode(msg, tipc_own_addr);
b97bf3fd
PL
164 if (dp->count == 1) {
165 msg_set_destport(msg, dp->ports[0]);
9816f061 166 tipc_sk_rcv(buf);
4323add6 167 tipc_port_list_free(dp);
b97bf3fd
PL
168 return;
169 }
170 for (; cnt < dp->count; cnt++) {
171 int index = cnt % PLSIZE;
172 struct sk_buff *b = skb_clone(buf, GFP_ATOMIC);
173
174 if (b == NULL) {
2cf8aa19 175 pr_warn("Unable to deliver multicast message(s)\n");
b97bf3fd
PL
176 goto exit;
177 }
a016892c 178 if ((index == 0) && (cnt != 0))
b97bf3fd 179 item = item->next;
0e65967e 180 msg_set_destport(buf_msg(b), item->ports[index]);
9816f061 181 tipc_sk_rcv(b);
b97bf3fd
PL
182 }
183 }
184exit:
5f6d9123 185 kfree_skb(buf);
4323add6 186 tipc_port_list_free(dp);
b97bf3fd
PL
187}
188
24be34b5 189/* tipc_port_init - intiate TIPC port and lock it
c4307285 190 *
24be34b5 191 * Returns obtained reference if initialization is successful, zero otherwise
b97bf3fd 192 */
24be34b5
JPM
193u32 tipc_port_init(struct tipc_port *p_ptr,
194 const unsigned int importance)
b97bf3fd 195{
b97bf3fd
PL
196 struct tipc_msg *msg;
197 u32 ref;
198
23dd4cce 199 ref = tipc_ref_acquire(p_ptr, &p_ptr->lock);
b97bf3fd 200 if (!ref) {
8826cde6 201 pr_warn("Port registration failed, ref. table exhausted\n");
24be34b5 202 return 0;
b97bf3fd
PL
203 }
204
23dd4cce
AS
205 p_ptr->max_pkt = MAX_PKT_DEFAULT;
206 p_ptr->ref = ref;
b97bf3fd
PL
207 INIT_LIST_HEAD(&p_ptr->wait_list);
208 INIT_LIST_HEAD(&p_ptr->subscription.nodesub_list);
b97bf3fd 209 k_init_timer(&p_ptr->timer, (Handler)port_timeout, ref);
b97bf3fd
PL
210 INIT_LIST_HEAD(&p_ptr->publications);
211 INIT_LIST_HEAD(&p_ptr->port_list);
f21536d1
AS
212
213 /*
214 * Must hold port list lock while initializing message header template
215 * to ensure a change to node's own network address doesn't result
216 * in template containing out-dated network address information
217 */
f21536d1
AS
218 spin_lock_bh(&tipc_port_list_lock);
219 msg = &p_ptr->phdr;
220 tipc_msg_init(msg, importance, TIPC_NAMED_MSG, NAMED_H_SIZE, 0);
221 msg_set_origport(msg, ref);
b97bf3fd 222 list_add_tail(&p_ptr->port_list, &ports);
4323add6 223 spin_unlock_bh(&tipc_port_list_lock);
24be34b5 224 return ref;
b97bf3fd
PL
225}
226
24be34b5 227void tipc_port_destroy(struct tipc_port *p_ptr)
b97bf3fd 228{
1fc54d8f 229 struct sk_buff *buf = NULL;
b786e2b0
JPM
230 struct tipc_msg *msg = NULL;
231 u32 peer;
b97bf3fd 232
84602761 233 tipc_withdraw(p_ptr, 0, NULL);
b97bf3fd 234
84602761
YX
235 spin_lock_bh(p_ptr->lock);
236 tipc_ref_discard(p_ptr->ref);
237 spin_unlock_bh(p_ptr->lock);
b97bf3fd
PL
238
239 k_cancel_timer(&p_ptr->timer);
23dd4cce 240 if (p_ptr->connected) {
b97bf3fd 241 buf = port_build_peer_abort_msg(p_ptr, TIPC_ERR_NO_PORT);
4323add6 242 tipc_nodesub_unsubscribe(&p_ptr->subscription);
b786e2b0
JPM
243 msg = buf_msg(buf);
244 peer = msg_destnode(msg);
245 tipc_link_xmit2(buf, peer, msg_link_selector(msg));
b97bf3fd 246 }
4323add6 247 spin_lock_bh(&tipc_port_list_lock);
b97bf3fd
PL
248 list_del(&p_ptr->port_list);
249 list_del(&p_ptr->wait_list);
4323add6 250 spin_unlock_bh(&tipc_port_list_lock);
b97bf3fd 251 k_term_timer(&p_ptr->timer);
b97bf3fd
PL
252}
253
c4307285 254/*
e4a0aee4
AS
255 * port_build_proto_msg(): create connection protocol message for port
256 *
257 * On entry the port must be locked and connected.
b97bf3fd 258 */
e4a0aee4
AS
259static struct sk_buff *port_build_proto_msg(struct tipc_port *p_ptr,
260 u32 type, u32 ack)
b97bf3fd
PL
261{
262 struct sk_buff *buf;
263 struct tipc_msg *msg;
c4307285 264
741d9eb7 265 buf = tipc_buf_acquire(INT_H_SIZE);
b97bf3fd
PL
266 if (buf) {
267 msg = buf_msg(buf);
e4a0aee4 268 tipc_msg_init(msg, CONN_MANAGER, type, INT_H_SIZE,
f9fef18c
JPM
269 tipc_port_peernode(p_ptr));
270 msg_set_destport(msg, tipc_port_peerport(p_ptr));
e4a0aee4 271 msg_set_origport(msg, p_ptr->ref);
b97bf3fd 272 msg_set_msgcnt(msg, ack);
b786e2b0 273 buf->next = NULL;
b97bf3fd
PL
274 }
275 return buf;
276}
277
b97bf3fd
PL
278static void port_timeout(unsigned long ref)
279{
23dd4cce 280 struct tipc_port *p_ptr = tipc_port_lock(ref);
1fc54d8f 281 struct sk_buff *buf = NULL;
b786e2b0 282 struct tipc_msg *msg = NULL;
b97bf3fd 283
065fd177
AS
284 if (!p_ptr)
285 return;
286
23dd4cce 287 if (!p_ptr->connected) {
065fd177 288 tipc_port_unlock(p_ptr);
b97bf3fd 289 return;
065fd177 290 }
b97bf3fd
PL
291
292 /* Last probe answered ? */
ac0074ee 293 if (p_ptr->probing_state == TIPC_CONN_PROBING) {
b97bf3fd
PL
294 buf = port_build_self_abort_msg(p_ptr, TIPC_ERR_NO_PORT);
295 } else {
e4a0aee4 296 buf = port_build_proto_msg(p_ptr, CONN_PROBE, 0);
ac0074ee 297 p_ptr->probing_state = TIPC_CONN_PROBING;
b97bf3fd
PL
298 k_start_timer(&p_ptr->timer, p_ptr->probing_interval);
299 }
4323add6 300 tipc_port_unlock(p_ptr);
b786e2b0
JPM
301 msg = buf_msg(buf);
302 tipc_link_xmit2(buf, msg_destnode(msg), msg_link_selector(msg));
b97bf3fd
PL
303}
304
305
306static void port_handle_node_down(unsigned long ref)
307{
23dd4cce 308 struct tipc_port *p_ptr = tipc_port_lock(ref);
0e65967e 309 struct sk_buff *buf = NULL;
b786e2b0 310 struct tipc_msg *msg = NULL;
b97bf3fd
PL
311
312 if (!p_ptr)
313 return;
314 buf = port_build_self_abort_msg(p_ptr, TIPC_ERR_NO_NODE);
4323add6 315 tipc_port_unlock(p_ptr);
b786e2b0
JPM
316 msg = buf_msg(buf);
317 tipc_link_xmit2(buf, msg_destnode(msg), msg_link_selector(msg));
b97bf3fd
PL
318}
319
320
23dd4cce 321static struct sk_buff *port_build_self_abort_msg(struct tipc_port *p_ptr, u32 err)
b97bf3fd 322{
e244a915 323 struct sk_buff *buf = port_build_peer_abort_msg(p_ptr, err);
b97bf3fd 324
e244a915
AS
325 if (buf) {
326 struct tipc_msg *msg = buf_msg(buf);
327 msg_swap_words(msg, 4, 5);
328 msg_swap_words(msg, 6, 7);
b786e2b0 329 buf->next = NULL;
e244a915
AS
330 }
331 return buf;
b97bf3fd
PL
332}
333
334
23dd4cce 335static struct sk_buff *port_build_peer_abort_msg(struct tipc_port *p_ptr, u32 err)
b97bf3fd 336{
e244a915
AS
337 struct sk_buff *buf;
338 struct tipc_msg *msg;
339 u32 imp;
b97bf3fd 340
23dd4cce 341 if (!p_ptr->connected)
1fc54d8f 342 return NULL;
e244a915
AS
343
344 buf = tipc_buf_acquire(BASIC_H_SIZE);
345 if (buf) {
346 msg = buf_msg(buf);
347 memcpy(msg, &p_ptr->phdr, BASIC_H_SIZE);
348 msg_set_hdr_sz(msg, BASIC_H_SIZE);
349 msg_set_size(msg, BASIC_H_SIZE);
350 imp = msg_importance(msg);
351 if (imp < TIPC_CRITICAL_IMPORTANCE)
352 msg_set_importance(msg, ++imp);
353 msg_set_errcode(msg, err);
b786e2b0 354 buf->next = NULL;
e244a915
AS
355 }
356 return buf;
b97bf3fd
PL
357}
358
dc1aed37 359static int port_print(struct tipc_port *p_ptr, char *buf, int len, int full_id)
b97bf3fd 360{
c4307285 361 struct publication *publ;
dc1aed37 362 int ret;
b97bf3fd
PL
363
364 if (full_id)
dc1aed37
EH
365 ret = tipc_snprintf(buf, len, "<%u.%u.%u:%u>:",
366 tipc_zone(tipc_own_addr),
367 tipc_cluster(tipc_own_addr),
368 tipc_node(tipc_own_addr), p_ptr->ref);
b97bf3fd 369 else
dc1aed37 370 ret = tipc_snprintf(buf, len, "%-10u:", p_ptr->ref);
b97bf3fd 371
23dd4cce 372 if (p_ptr->connected) {
f9fef18c
JPM
373 u32 dport = tipc_port_peerport(p_ptr);
374 u32 destnode = tipc_port_peernode(p_ptr);
c4307285 375
dc1aed37
EH
376 ret += tipc_snprintf(buf + ret, len - ret,
377 " connected to <%u.%u.%u:%u>",
378 tipc_zone(destnode),
379 tipc_cluster(destnode),
380 tipc_node(destnode), dport);
23dd4cce 381 if (p_ptr->conn_type != 0)
dc1aed37
EH
382 ret += tipc_snprintf(buf + ret, len - ret,
383 " via {%u,%u}", p_ptr->conn_type,
384 p_ptr->conn_instance);
23dd4cce 385 } else if (p_ptr->published) {
dc1aed37 386 ret += tipc_snprintf(buf + ret, len - ret, " bound to");
c4307285 387 list_for_each_entry(publ, &p_ptr->publications, pport_list) {
b97bf3fd 388 if (publ->lower == publ->upper)
dc1aed37
EH
389 ret += tipc_snprintf(buf + ret, len - ret,
390 " {%u,%u}", publ->type,
391 publ->lower);
b97bf3fd 392 else
dc1aed37
EH
393 ret += tipc_snprintf(buf + ret, len - ret,
394 " {%u,%u,%u}", publ->type,
395 publ->lower, publ->upper);
c4307285
YH
396 }
397 }
dc1aed37
EH
398 ret += tipc_snprintf(buf + ret, len - ret, "\n");
399 return ret;
b97bf3fd
PL
400}
401
4323add6 402struct sk_buff *tipc_port_get_ports(void)
b97bf3fd
PL
403{
404 struct sk_buff *buf;
405 struct tlv_desc *rep_tlv;
dc1aed37
EH
406 char *pb;
407 int pb_len;
23dd4cce 408 struct tipc_port *p_ptr;
dc1aed37 409 int str_len = 0;
b97bf3fd 410
dc1aed37 411 buf = tipc_cfg_reply_alloc(TLV_SPACE(ULTRA_STRING_MAX_LEN));
b97bf3fd
PL
412 if (!buf)
413 return NULL;
414 rep_tlv = (struct tlv_desc *)buf->data;
dc1aed37
EH
415 pb = TLV_DATA(rep_tlv);
416 pb_len = ULTRA_STRING_MAX_LEN;
b97bf3fd 417
4323add6 418 spin_lock_bh(&tipc_port_list_lock);
b97bf3fd 419 list_for_each_entry(p_ptr, &ports, port_list) {
23dd4cce 420 spin_lock_bh(p_ptr->lock);
dc1aed37 421 str_len += port_print(p_ptr, pb, pb_len, 0);
23dd4cce 422 spin_unlock_bh(p_ptr->lock);
b97bf3fd 423 }
4323add6 424 spin_unlock_bh(&tipc_port_list_lock);
dc1aed37 425 str_len += 1; /* for "\0" */
b97bf3fd
PL
426 skb_put(buf, TLV_SPACE(str_len));
427 TLV_SET(rep_tlv, TIPC_TLV_ULTRA_STRING, NULL, str_len);
428
429 return buf;
430}
431
4323add6 432void tipc_port_reinit(void)
b97bf3fd 433{
23dd4cce 434 struct tipc_port *p_ptr;
b97bf3fd
PL
435 struct tipc_msg *msg;
436
4323add6 437 spin_lock_bh(&tipc_port_list_lock);
b97bf3fd 438 list_for_each_entry(p_ptr, &ports, port_list) {
23dd4cce 439 msg = &p_ptr->phdr;
6d4a6672 440 msg_set_prevnode(msg, tipc_own_addr);
b97bf3fd
PL
441 msg_set_orignode(msg, tipc_own_addr);
442 }
4323add6 443 spin_unlock_bh(&tipc_port_list_lock);
b97bf3fd
PL
444}
445
b97bf3fd
PL
446void tipc_acknowledge(u32 ref, u32 ack)
447{
23dd4cce 448 struct tipc_port *p_ptr;
1fc54d8f 449 struct sk_buff *buf = NULL;
b786e2b0 450 struct tipc_msg *msg;
b97bf3fd 451
4323add6 452 p_ptr = tipc_port_lock(ref);
b97bf3fd
PL
453 if (!p_ptr)
454 return;
60120526 455 if (p_ptr->connected)
e4a0aee4 456 buf = port_build_proto_msg(p_ptr, CONN_ACK, ack);
60120526 457
4323add6 458 tipc_port_unlock(p_ptr);
b786e2b0
JPM
459 if (!buf)
460 return;
461 msg = buf_msg(buf);
462 tipc_link_xmit2(buf, msg_destnode(msg), msg_link_selector(msg));
b97bf3fd
PL
463}
464
84602761
YX
465int tipc_publish(struct tipc_port *p_ptr, unsigned int scope,
466 struct tipc_name_seq const *seq)
b97bf3fd 467{
b97bf3fd
PL
468 struct publication *publ;
469 u32 key;
b97bf3fd 470
84602761 471 if (p_ptr->connected)
d55b4c63 472 return -EINVAL;
84602761
YX
473 key = p_ptr->ref + p_ptr->pub_count + 1;
474 if (key == p_ptr->ref)
475 return -EADDRINUSE;
d55b4c63 476
4323add6 477 publ = tipc_nametbl_publish(seq->type, seq->lower, seq->upper,
23dd4cce 478 scope, p_ptr->ref, key);
b97bf3fd
PL
479 if (publ) {
480 list_add(&publ->pport_list, &p_ptr->publications);
481 p_ptr->pub_count++;
23dd4cce 482 p_ptr->published = 1;
84602761 483 return 0;
b97bf3fd 484 }
84602761 485 return -EINVAL;
b97bf3fd
PL
486}
487
84602761
YX
488int tipc_withdraw(struct tipc_port *p_ptr, unsigned int scope,
489 struct tipc_name_seq const *seq)
b97bf3fd 490{
b97bf3fd
PL
491 struct publication *publ;
492 struct publication *tpubl;
493 int res = -EINVAL;
c4307285 494
b97bf3fd 495 if (!seq) {
c4307285 496 list_for_each_entry_safe(publ, tpubl,
b97bf3fd 497 &p_ptr->publications, pport_list) {
c4307285 498 tipc_nametbl_withdraw(publ->type, publ->lower,
4323add6 499 publ->ref, publ->key);
b97bf3fd 500 }
0e35fd5e 501 res = 0;
b97bf3fd 502 } else {
c4307285 503 list_for_each_entry_safe(publ, tpubl,
b97bf3fd
PL
504 &p_ptr->publications, pport_list) {
505 if (publ->scope != scope)
506 continue;
507 if (publ->type != seq->type)
508 continue;
509 if (publ->lower != seq->lower)
510 continue;
511 if (publ->upper != seq->upper)
512 break;
c4307285 513 tipc_nametbl_withdraw(publ->type, publ->lower,
4323add6 514 publ->ref, publ->key);
0e35fd5e 515 res = 0;
b97bf3fd
PL
516 break;
517 }
518 }
519 if (list_empty(&p_ptr->publications))
23dd4cce 520 p_ptr->published = 0;
b97bf3fd
PL
521 return res;
522}
523
247f0f3c 524int tipc_port_connect(u32 ref, struct tipc_portid const *peer)
b97bf3fd 525{
23dd4cce 526 struct tipc_port *p_ptr;
bc879117 527 int res;
b97bf3fd 528
4323add6 529 p_ptr = tipc_port_lock(ref);
b97bf3fd
PL
530 if (!p_ptr)
531 return -EINVAL;
247f0f3c 532 res = __tipc_port_connect(ref, p_ptr, peer);
bc879117
PG
533 tipc_port_unlock(p_ptr);
534 return res;
535}
536
537/*
247f0f3c 538 * __tipc_port_connect - connect to a remote peer
bc879117
PG
539 *
540 * Port must be locked.
541 */
247f0f3c 542int __tipc_port_connect(u32 ref, struct tipc_port *p_ptr,
bc879117
PG
543 struct tipc_portid const *peer)
544{
545 struct tipc_msg *msg;
546 int res = -EINVAL;
547
23dd4cce 548 if (p_ptr->published || p_ptr->connected)
b97bf3fd
PL
549 goto exit;
550 if (!peer->ref)
551 goto exit;
552
23dd4cce 553 msg = &p_ptr->phdr;
b97bf3fd
PL
554 msg_set_destnode(msg, peer->node);
555 msg_set_destport(msg, peer->ref);
b97bf3fd 556 msg_set_type(msg, TIPC_CONN_MSG);
53b94364 557 msg_set_lookup_scope(msg, 0);
08c80e9a 558 msg_set_hdr_sz(msg, SHORT_H_SIZE);
b97bf3fd
PL
559
560 p_ptr->probing_interval = PROBING_INTERVAL;
ac0074ee 561 p_ptr->probing_state = TIPC_CONN_OK;
23dd4cce 562 p_ptr->connected = 1;
b97bf3fd
PL
563 k_start_timer(&p_ptr->timer, p_ptr->probing_interval);
564
0e65967e 565 tipc_nodesub_subscribe(&p_ptr->subscription, peer->node,
880b005f 566 (void *)(unsigned long)ref,
b97bf3fd 567 (net_ev_handler)port_handle_node_down);
0e35fd5e 568 res = 0;
b97bf3fd 569exit:
4ccfe5e0 570 p_ptr->max_pkt = tipc_node_get_mtu(peer->node, ref);
b97bf3fd
PL
571 return res;
572}
573
bc879117
PG
574/*
575 * __tipc_disconnect - disconnect port from peer
0c3141e9
AS
576 *
577 * Port must be locked.
578 */
247f0f3c 579int __tipc_port_disconnect(struct tipc_port *tp_ptr)
0c3141e9 580{
0c3141e9
AS
581 if (tp_ptr->connected) {
582 tp_ptr->connected = 0;
583 /* let timer expire on it's own to avoid deadlock! */
e3192690 584 tipc_nodesub_unsubscribe(&tp_ptr->subscription);
0cee6bbe 585 return 0;
0c3141e9 586 }
0cee6bbe 587
588 return -ENOTCONN;
0c3141e9
AS
589}
590
b97bf3fd 591/*
247f0f3c 592 * tipc_port_disconnect(): Disconnect port form peer.
b97bf3fd
PL
593 * This is a node local operation.
594 */
247f0f3c 595int tipc_port_disconnect(u32 ref)
b97bf3fd 596{
23dd4cce 597 struct tipc_port *p_ptr;
0c3141e9 598 int res;
b97bf3fd 599
4323add6 600 p_ptr = tipc_port_lock(ref);
b97bf3fd
PL
601 if (!p_ptr)
602 return -EINVAL;
247f0f3c 603 res = __tipc_port_disconnect(p_ptr);
4323add6 604 tipc_port_unlock(p_ptr);
b97bf3fd
PL
605 return res;
606}
607
608/*
247f0f3c 609 * tipc_port_shutdown(): Send a SHUTDOWN msg to peer and disconnect
b97bf3fd 610 */
247f0f3c 611int tipc_port_shutdown(u32 ref)
b97bf3fd 612{
b786e2b0 613 struct tipc_msg *msg;
23dd4cce 614 struct tipc_port *p_ptr;
1fc54d8f 615 struct sk_buff *buf = NULL;
b97bf3fd 616
4323add6 617 p_ptr = tipc_port_lock(ref);
b97bf3fd
PL
618 if (!p_ptr)
619 return -EINVAL;
620
e244a915 621 buf = port_build_peer_abort_msg(p_ptr, TIPC_CONN_SHUTDOWN);
4323add6 622 tipc_port_unlock(p_ptr);
b786e2b0
JPM
623 msg = buf_msg(buf);
624 tipc_link_xmit2(buf, msg_destnode(msg), msg_link_selector(msg));
247f0f3c 625 return tipc_port_disconnect(ref);
b97bf3fd 626}
This page took 0.701791 seconds and 5 git commands to generate.