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