tipc: clean up connection protocol reception function
[linux-2.6/btrfs-unstable.git] / net / tipc / port.c
blob9f53d5ac35e169db2c692b3008314c7987f6ea1d
1 /*
2 * net/tipc/port.c: TIPC port code
4 * Copyright (c) 1992-2007, 2014, Ericsson AB
5 * Copyright (c) 2004-2008, 2010-2013, Wind River Systems
6 * All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are met:
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.
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.
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
34 * POSSIBILITY OF SUCH DAMAGE.
37 #include "core.h"
38 #include "config.h"
39 #include "port.h"
40 #include "name_table.h"
41 #include "socket.h"
43 /* Connection management: */
44 #define PROBING_INTERVAL 3600000 /* [ms] => 1 h */
46 #define MAX_REJECT_SIZE 1024
48 DEFINE_SPINLOCK(tipc_port_list_lock);
50 static LIST_HEAD(ports);
51 static void port_handle_node_down(unsigned long ref);
52 static struct sk_buff *port_build_self_abort_msg(struct tipc_port *, u32 err);
53 static struct sk_buff *port_build_peer_abort_msg(struct tipc_port *, u32 err);
54 static void port_timeout(unsigned long ref);
56 /**
57 * tipc_port_peer_msg - verify message was sent by connected port's peer
59 * Handles cases where the node's network address has changed from
60 * the default of <0.0.0> to its configured setting.
62 int tipc_port_peer_msg(struct tipc_port *p_ptr, struct tipc_msg *msg)
64 u32 peernode;
65 u32 orignode;
67 if (msg_origport(msg) != tipc_port_peerport(p_ptr))
68 return 0;
70 orignode = msg_orignode(msg);
71 peernode = tipc_port_peernode(p_ptr);
72 return (orignode == peernode) ||
73 (!orignode && (peernode == tipc_own_addr)) ||
74 (!peernode && (orignode == tipc_own_addr));
77 /**
78 * tipc_port_mcast_xmit - send a multicast message to local and remote
79 * destinations
81 int 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)
86 struct tipc_msg *hdr;
87 struct sk_buff *buf;
88 struct sk_buff *ibuf = NULL;
89 struct tipc_port_list dports = {0, NULL, };
90 int ext_targets;
91 int res;
93 /* Create multicast message */
94 hdr = &oport->phdr;
95 msg_set_type(hdr, TIPC_MCAST_MSG);
96 msg_set_lookup_scope(hdr, TIPC_CLUSTER_SCOPE);
97 msg_set_destport(hdr, 0);
98 msg_set_destnode(hdr, 0);
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);
103 res = tipc_msg_build(hdr, msg_sect, len, MAX_MSG_SIZE, &buf);
104 if (unlikely(!buf))
105 return res;
107 /* Figure out where to send multicast message */
108 ext_targets = tipc_nametbl_mc_translate(seq->type, seq->lower, seq->upper,
109 TIPC_NODE_SCOPE, &dports);
111 /* Send message to destinations (duplicate it only if necessary) */
112 if (ext_targets) {
113 if (dports.count != 0) {
114 ibuf = skb_copy(buf, GFP_ATOMIC);
115 if (ibuf == NULL) {
116 tipc_port_list_free(&dports);
117 kfree_skb(buf);
118 return -ENOMEM;
121 res = tipc_bclink_xmit(buf);
122 if ((res < 0) && (dports.count != 0))
123 kfree_skb(ibuf);
124 } else {
125 ibuf = buf;
128 if (res >= 0) {
129 if (ibuf)
130 tipc_port_mcast_rcv(ibuf, &dports);
131 } else {
132 tipc_port_list_free(&dports);
134 return res;
138 * tipc_port_mcast_rcv - deliver multicast message to all destination ports
140 * If there is no port list, perform a lookup to create one
142 void tipc_port_mcast_rcv(struct sk_buff *buf, struct tipc_port_list *dp)
144 struct tipc_msg *msg;
145 struct tipc_port_list dports = {0, NULL, };
146 struct tipc_port_list *item = dp;
147 int cnt = 0;
149 msg = buf_msg(buf);
151 /* Create destination port list, if one wasn't supplied */
152 if (dp == NULL) {
153 tipc_nametbl_mc_translate(msg_nametype(msg),
154 msg_namelower(msg),
155 msg_nameupper(msg),
156 TIPC_CLUSTER_SCOPE,
157 &dports);
158 item = dp = &dports;
161 /* Deliver a copy of message to each destination port */
162 if (dp->count != 0) {
163 msg_set_destnode(msg, tipc_own_addr);
164 if (dp->count == 1) {
165 msg_set_destport(msg, dp->ports[0]);
166 tipc_sk_rcv(buf);
167 tipc_port_list_free(dp);
168 return;
170 for (; cnt < dp->count; cnt++) {
171 int index = cnt % PLSIZE;
172 struct sk_buff *b = skb_clone(buf, GFP_ATOMIC);
174 if (b == NULL) {
175 pr_warn("Unable to deliver multicast message(s)\n");
176 goto exit;
178 if ((index == 0) && (cnt != 0))
179 item = item->next;
180 msg_set_destport(buf_msg(b), item->ports[index]);
181 tipc_sk_rcv(b);
184 exit:
185 kfree_skb(buf);
186 tipc_port_list_free(dp);
190 void tipc_port_wakeup(struct tipc_port *port)
192 tipc_sock_wakeup(tipc_port_to_sock(port));
195 /* tipc_port_init - intiate TIPC port and lock it
197 * Returns obtained reference if initialization is successful, zero otherwise
199 u32 tipc_port_init(struct tipc_port *p_ptr,
200 const unsigned int importance)
202 struct tipc_msg *msg;
203 u32 ref;
205 ref = tipc_ref_acquire(p_ptr, &p_ptr->lock);
206 if (!ref) {
207 pr_warn("Port registration failed, ref. table exhausted\n");
208 return 0;
211 p_ptr->max_pkt = MAX_PKT_DEFAULT;
212 p_ptr->sent = 1;
213 p_ptr->ref = ref;
214 INIT_LIST_HEAD(&p_ptr->wait_list);
215 INIT_LIST_HEAD(&p_ptr->subscription.nodesub_list);
216 k_init_timer(&p_ptr->timer, (Handler)port_timeout, ref);
217 INIT_LIST_HEAD(&p_ptr->publications);
218 INIT_LIST_HEAD(&p_ptr->port_list);
221 * Must hold port list lock while initializing message header template
222 * to ensure a change to node's own network address doesn't result
223 * in template containing out-dated network address information
225 spin_lock_bh(&tipc_port_list_lock);
226 msg = &p_ptr->phdr;
227 tipc_msg_init(msg, importance, TIPC_NAMED_MSG, NAMED_H_SIZE, 0);
228 msg_set_origport(msg, ref);
229 list_add_tail(&p_ptr->port_list, &ports);
230 spin_unlock_bh(&tipc_port_list_lock);
231 return ref;
234 void tipc_port_destroy(struct tipc_port *p_ptr)
236 struct sk_buff *buf = NULL;
237 struct tipc_msg *msg = NULL;
238 u32 peer;
240 tipc_withdraw(p_ptr, 0, NULL);
242 spin_lock_bh(p_ptr->lock);
243 tipc_ref_discard(p_ptr->ref);
244 spin_unlock_bh(p_ptr->lock);
246 k_cancel_timer(&p_ptr->timer);
247 if (p_ptr->connected) {
248 buf = port_build_peer_abort_msg(p_ptr, TIPC_ERR_NO_PORT);
249 tipc_nodesub_unsubscribe(&p_ptr->subscription);
250 msg = buf_msg(buf);
251 peer = msg_destnode(msg);
252 tipc_link_xmit2(buf, peer, msg_link_selector(msg));
254 spin_lock_bh(&tipc_port_list_lock);
255 list_del(&p_ptr->port_list);
256 list_del(&p_ptr->wait_list);
257 spin_unlock_bh(&tipc_port_list_lock);
258 k_term_timer(&p_ptr->timer);
262 * port_build_proto_msg(): create connection protocol message for port
264 * On entry the port must be locked and connected.
266 static struct sk_buff *port_build_proto_msg(struct tipc_port *p_ptr,
267 u32 type, u32 ack)
269 struct sk_buff *buf;
270 struct tipc_msg *msg;
272 buf = tipc_buf_acquire(INT_H_SIZE);
273 if (buf) {
274 msg = buf_msg(buf);
275 tipc_msg_init(msg, CONN_MANAGER, type, INT_H_SIZE,
276 tipc_port_peernode(p_ptr));
277 msg_set_destport(msg, tipc_port_peerport(p_ptr));
278 msg_set_origport(msg, p_ptr->ref);
279 msg_set_msgcnt(msg, ack);
280 buf->next = NULL;
282 return buf;
285 static void port_timeout(unsigned long ref)
287 struct tipc_port *p_ptr = tipc_port_lock(ref);
288 struct sk_buff *buf = NULL;
289 struct tipc_msg *msg = NULL;
291 if (!p_ptr)
292 return;
294 if (!p_ptr->connected) {
295 tipc_port_unlock(p_ptr);
296 return;
299 /* Last probe answered ? */
300 if (p_ptr->probing_state == TIPC_CONN_PROBING) {
301 buf = port_build_self_abort_msg(p_ptr, TIPC_ERR_NO_PORT);
302 } else {
303 buf = port_build_proto_msg(p_ptr, CONN_PROBE, 0);
304 p_ptr->probing_state = TIPC_CONN_PROBING;
305 k_start_timer(&p_ptr->timer, p_ptr->probing_interval);
307 tipc_port_unlock(p_ptr);
308 msg = buf_msg(buf);
309 tipc_link_xmit2(buf, msg_destnode(msg), msg_link_selector(msg));
313 static void port_handle_node_down(unsigned long ref)
315 struct tipc_port *p_ptr = tipc_port_lock(ref);
316 struct sk_buff *buf = NULL;
317 struct tipc_msg *msg = NULL;
319 if (!p_ptr)
320 return;
321 buf = port_build_self_abort_msg(p_ptr, TIPC_ERR_NO_NODE);
322 tipc_port_unlock(p_ptr);
323 msg = buf_msg(buf);
324 tipc_link_xmit2(buf, msg_destnode(msg), msg_link_selector(msg));
328 static struct sk_buff *port_build_self_abort_msg(struct tipc_port *p_ptr, u32 err)
330 struct sk_buff *buf = port_build_peer_abort_msg(p_ptr, err);
332 if (buf) {
333 struct tipc_msg *msg = buf_msg(buf);
334 msg_swap_words(msg, 4, 5);
335 msg_swap_words(msg, 6, 7);
336 buf->next = NULL;
338 return buf;
342 static struct sk_buff *port_build_peer_abort_msg(struct tipc_port *p_ptr, u32 err)
344 struct sk_buff *buf;
345 struct tipc_msg *msg;
346 u32 imp;
348 if (!p_ptr->connected)
349 return NULL;
351 buf = tipc_buf_acquire(BASIC_H_SIZE);
352 if (buf) {
353 msg = buf_msg(buf);
354 memcpy(msg, &p_ptr->phdr, BASIC_H_SIZE);
355 msg_set_hdr_sz(msg, BASIC_H_SIZE);
356 msg_set_size(msg, BASIC_H_SIZE);
357 imp = msg_importance(msg);
358 if (imp < TIPC_CRITICAL_IMPORTANCE)
359 msg_set_importance(msg, ++imp);
360 msg_set_errcode(msg, err);
361 buf->next = NULL;
363 return buf;
366 static int port_print(struct tipc_port *p_ptr, char *buf, int len, int full_id)
368 struct publication *publ;
369 int ret;
371 if (full_id)
372 ret = tipc_snprintf(buf, len, "<%u.%u.%u:%u>:",
373 tipc_zone(tipc_own_addr),
374 tipc_cluster(tipc_own_addr),
375 tipc_node(tipc_own_addr), p_ptr->ref);
376 else
377 ret = tipc_snprintf(buf, len, "%-10u:", p_ptr->ref);
379 if (p_ptr->connected) {
380 u32 dport = tipc_port_peerport(p_ptr);
381 u32 destnode = tipc_port_peernode(p_ptr);
383 ret += tipc_snprintf(buf + ret, len - ret,
384 " connected to <%u.%u.%u:%u>",
385 tipc_zone(destnode),
386 tipc_cluster(destnode),
387 tipc_node(destnode), dport);
388 if (p_ptr->conn_type != 0)
389 ret += tipc_snprintf(buf + ret, len - ret,
390 " via {%u,%u}", p_ptr->conn_type,
391 p_ptr->conn_instance);
392 } else if (p_ptr->published) {
393 ret += tipc_snprintf(buf + ret, len - ret, " bound to");
394 list_for_each_entry(publ, &p_ptr->publications, pport_list) {
395 if (publ->lower == publ->upper)
396 ret += tipc_snprintf(buf + ret, len - ret,
397 " {%u,%u}", publ->type,
398 publ->lower);
399 else
400 ret += tipc_snprintf(buf + ret, len - ret,
401 " {%u,%u,%u}", publ->type,
402 publ->lower, publ->upper);
405 ret += tipc_snprintf(buf + ret, len - ret, "\n");
406 return ret;
409 struct sk_buff *tipc_port_get_ports(void)
411 struct sk_buff *buf;
412 struct tlv_desc *rep_tlv;
413 char *pb;
414 int pb_len;
415 struct tipc_port *p_ptr;
416 int str_len = 0;
418 buf = tipc_cfg_reply_alloc(TLV_SPACE(ULTRA_STRING_MAX_LEN));
419 if (!buf)
420 return NULL;
421 rep_tlv = (struct tlv_desc *)buf->data;
422 pb = TLV_DATA(rep_tlv);
423 pb_len = ULTRA_STRING_MAX_LEN;
425 spin_lock_bh(&tipc_port_list_lock);
426 list_for_each_entry(p_ptr, &ports, port_list) {
427 spin_lock_bh(p_ptr->lock);
428 str_len += port_print(p_ptr, pb, pb_len, 0);
429 spin_unlock_bh(p_ptr->lock);
431 spin_unlock_bh(&tipc_port_list_lock);
432 str_len += 1; /* for "\0" */
433 skb_put(buf, TLV_SPACE(str_len));
434 TLV_SET(rep_tlv, TIPC_TLV_ULTRA_STRING, NULL, str_len);
436 return buf;
439 void tipc_port_reinit(void)
441 struct tipc_port *p_ptr;
442 struct tipc_msg *msg;
444 spin_lock_bh(&tipc_port_list_lock);
445 list_for_each_entry(p_ptr, &ports, port_list) {
446 msg = &p_ptr->phdr;
447 msg_set_prevnode(msg, tipc_own_addr);
448 msg_set_orignode(msg, tipc_own_addr);
450 spin_unlock_bh(&tipc_port_list_lock);
453 void tipc_acknowledge(u32 ref, u32 ack)
455 struct tipc_port *p_ptr;
456 struct sk_buff *buf = NULL;
457 struct tipc_msg *msg;
459 p_ptr = tipc_port_lock(ref);
460 if (!p_ptr)
461 return;
462 if (p_ptr->connected) {
463 p_ptr->conn_unacked -= ack;
464 buf = port_build_proto_msg(p_ptr, CONN_ACK, ack);
466 tipc_port_unlock(p_ptr);
467 if (!buf)
468 return;
469 msg = buf_msg(buf);
470 tipc_link_xmit2(buf, msg_destnode(msg), msg_link_selector(msg));
473 int tipc_publish(struct tipc_port *p_ptr, unsigned int scope,
474 struct tipc_name_seq const *seq)
476 struct publication *publ;
477 u32 key;
479 if (p_ptr->connected)
480 return -EINVAL;
481 key = p_ptr->ref + p_ptr->pub_count + 1;
482 if (key == p_ptr->ref)
483 return -EADDRINUSE;
485 publ = tipc_nametbl_publish(seq->type, seq->lower, seq->upper,
486 scope, p_ptr->ref, key);
487 if (publ) {
488 list_add(&publ->pport_list, &p_ptr->publications);
489 p_ptr->pub_count++;
490 p_ptr->published = 1;
491 return 0;
493 return -EINVAL;
496 int tipc_withdraw(struct tipc_port *p_ptr, unsigned int scope,
497 struct tipc_name_seq const *seq)
499 struct publication *publ;
500 struct publication *tpubl;
501 int res = -EINVAL;
503 if (!seq) {
504 list_for_each_entry_safe(publ, tpubl,
505 &p_ptr->publications, pport_list) {
506 tipc_nametbl_withdraw(publ->type, publ->lower,
507 publ->ref, publ->key);
509 res = 0;
510 } else {
511 list_for_each_entry_safe(publ, tpubl,
512 &p_ptr->publications, pport_list) {
513 if (publ->scope != scope)
514 continue;
515 if (publ->type != seq->type)
516 continue;
517 if (publ->lower != seq->lower)
518 continue;
519 if (publ->upper != seq->upper)
520 break;
521 tipc_nametbl_withdraw(publ->type, publ->lower,
522 publ->ref, publ->key);
523 res = 0;
524 break;
527 if (list_empty(&p_ptr->publications))
528 p_ptr->published = 0;
529 return res;
532 int tipc_port_connect(u32 ref, struct tipc_portid const *peer)
534 struct tipc_port *p_ptr;
535 int res;
537 p_ptr = tipc_port_lock(ref);
538 if (!p_ptr)
539 return -EINVAL;
540 res = __tipc_port_connect(ref, p_ptr, peer);
541 tipc_port_unlock(p_ptr);
542 return res;
546 * __tipc_port_connect - connect to a remote peer
548 * Port must be locked.
550 int __tipc_port_connect(u32 ref, struct tipc_port *p_ptr,
551 struct tipc_portid const *peer)
553 struct tipc_msg *msg;
554 int res = -EINVAL;
556 if (p_ptr->published || p_ptr->connected)
557 goto exit;
558 if (!peer->ref)
559 goto exit;
561 msg = &p_ptr->phdr;
562 msg_set_destnode(msg, peer->node);
563 msg_set_destport(msg, peer->ref);
564 msg_set_type(msg, TIPC_CONN_MSG);
565 msg_set_lookup_scope(msg, 0);
566 msg_set_hdr_sz(msg, SHORT_H_SIZE);
568 p_ptr->probing_interval = PROBING_INTERVAL;
569 p_ptr->probing_state = TIPC_CONN_OK;
570 p_ptr->connected = 1;
571 k_start_timer(&p_ptr->timer, p_ptr->probing_interval);
573 tipc_nodesub_subscribe(&p_ptr->subscription, peer->node,
574 (void *)(unsigned long)ref,
575 (net_ev_handler)port_handle_node_down);
576 res = 0;
577 exit:
578 p_ptr->max_pkt = tipc_node_get_mtu(peer->node, ref);
579 return res;
583 * __tipc_disconnect - disconnect port from peer
585 * Port must be locked.
587 int __tipc_port_disconnect(struct tipc_port *tp_ptr)
589 if (tp_ptr->connected) {
590 tp_ptr->connected = 0;
591 /* let timer expire on it's own to avoid deadlock! */
592 tipc_nodesub_unsubscribe(&tp_ptr->subscription);
593 return 0;
596 return -ENOTCONN;
600 * tipc_port_disconnect(): Disconnect port form peer.
601 * This is a node local operation.
603 int tipc_port_disconnect(u32 ref)
605 struct tipc_port *p_ptr;
606 int res;
608 p_ptr = tipc_port_lock(ref);
609 if (!p_ptr)
610 return -EINVAL;
611 res = __tipc_port_disconnect(p_ptr);
612 tipc_port_unlock(p_ptr);
613 return res;
617 * tipc_port_shutdown(): Send a SHUTDOWN msg to peer and disconnect
619 int tipc_port_shutdown(u32 ref)
621 struct tipc_msg *msg;
622 struct tipc_port *p_ptr;
623 struct sk_buff *buf = NULL;
625 p_ptr = tipc_port_lock(ref);
626 if (!p_ptr)
627 return -EINVAL;
629 buf = port_build_peer_abort_msg(p_ptr, TIPC_CONN_SHUTDOWN);
630 tipc_port_unlock(p_ptr);
631 msg = buf_msg(buf);
632 tipc_link_xmit2(buf, msg_destnode(msg), msg_link_selector(msg));
633 return tipc_port_disconnect(ref);