blob: c2229c4b18ef90210b9f8eb5c983fe238b5d383d [file] [log] [blame]
Per Lidenb97bf3f2006-01-02 19:04:38 +01001/*
2 * net/tipc/port.c: TIPC port code
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09003 *
Allan Stephens05646c92007-06-10 17:25:24 -07004 * Copyright (c) 1992-2007, Ericsson AB
Allan Stephens23dd4cc2011-01-07 11:43:40 -05005 * Copyright (c) 2004-2008, 2010-2011, Wind River Systems
Per Lidenb97bf3f2006-01-02 19:04:38 +01006 * All rights reserved.
7 *
Per Liden9ea1fd32006-01-11 13:30:43 +01008 * Redistribution and use in source and binary forms, with or without
Per Lidenb97bf3f2006-01-02 19:04:38 +01009 * modification, are permitted provided that the following conditions are met:
10 *
Per Liden9ea1fd32006-01-11 13:30:43 +010011 * 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.
Per Lidenb97bf3f2006-01-02 19:04:38 +010019 *
Per Liden9ea1fd32006-01-11 13:30:43 +010020 * 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
Per Lidenb97bf3f2006-01-02 19:04:38 +010034 * POSSIBILITY OF SUCH DAMAGE.
35 */
36
37#include "core.h"
38#include "config.h"
Per Lidenb97bf3f2006-01-02 19:04:38 +010039#include "port.h"
Per Lidenb97bf3f2006-01-02 19:04:38 +010040#include "name_table.h"
Per Lidenb97bf3f2006-01-02 19:04:38 +010041
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
Allan Stephense3ec9c72010-12-31 18:59:34 +000049static struct sk_buff *msg_queue_head;
50static struct sk_buff *msg_queue_tail;
Per Lidenb97bf3f2006-01-02 19:04:38 +010051
Ingo Molnar34af9462006-06-27 02:53:55 -070052DEFINE_SPINLOCK(tipc_port_list_lock);
53static DEFINE_SPINLOCK(queue_lock);
Per Lidenb97bf3f2006-01-02 19:04:38 +010054
Per Liden4323add2006-01-18 00:38:21 +010055static LIST_HEAD(ports);
Per Lidenb97bf3f2006-01-02 19:04:38 +010056static void port_handle_node_down(unsigned long ref);
Allan Stephens23dd4cc2011-01-07 11:43:40 -050057static 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);
Per Lidenb97bf3f2006-01-02 19:04:38 +010059static void port_timeout(unsigned long ref);
60
61
Allan Stephens23dd4cc2011-01-07 11:43:40 -050062static u32 port_peernode(struct tipc_port *p_ptr)
Per Lidenb97bf3f2006-01-02 19:04:38 +010063{
Allan Stephens23dd4cc2011-01-07 11:43:40 -050064 return msg_destnode(&p_ptr->phdr);
Per Lidenb97bf3f2006-01-02 19:04:38 +010065}
66
Allan Stephens23dd4cc2011-01-07 11:43:40 -050067static u32 port_peerport(struct tipc_port *p_ptr)
Per Lidenb97bf3f2006-01-02 19:04:38 +010068{
Allan Stephens23dd4cc2011-01-07 11:43:40 -050069 return msg_destport(&p_ptr->phdr);
Per Lidenb97bf3f2006-01-02 19:04:38 +010070}
71
Per Lidenb97bf3f2006-01-02 19:04:38 +010072/**
73 * tipc_multicast - send a multicast message to local and remote destinations
74 */
75
Allan Stephens38f232e2010-11-30 12:00:59 +000076int tipc_multicast(u32 ref, struct tipc_name_seq const *seq,
Per Lidenb97bf3f2006-01-02 19:04:38 +010077 u32 num_sect, struct iovec const *msg_sect)
78{
79 struct tipc_msg *hdr;
80 struct sk_buff *buf;
81 struct sk_buff *ibuf = NULL;
82 struct port_list dports = {0, NULL, };
Allan Stephens23dd4cc2011-01-07 11:43:40 -050083 struct tipc_port *oport = tipc_port_deref(ref);
Per Lidenb97bf3f2006-01-02 19:04:38 +010084 int ext_targets;
85 int res;
86
87 if (unlikely(!oport))
88 return -EINVAL;
89
90 /* Create multicast message */
91
Allan Stephens23dd4cc2011-01-07 11:43:40 -050092 hdr = &oport->phdr;
Per Lidenb97bf3f2006-01-02 19:04:38 +010093 msg_set_type(hdr, TIPC_MCAST_MSG);
Allan Stephens53b94362011-04-17 16:02:11 -040094 msg_set_lookup_scope(hdr, TIPC_CLUSTER_SCOPE);
Per Lidenb97bf3f2006-01-02 19:04:38 +010095 msg_set_nametype(hdr, seq->type);
96 msg_set_namelower(hdr, seq->lower);
97 msg_set_nameupper(hdr, seq->upper);
98 msg_set_hdr_sz(hdr, MCAST_H_SIZE);
Allan Stephensc68ca7b2010-05-11 14:30:12 +000099 res = tipc_msg_build(hdr, msg_sect, num_sect, MAX_MSG_SIZE,
Per Lidenb97bf3f2006-01-02 19:04:38 +0100100 !oport->user_port, &buf);
101 if (unlikely(!buf))
102 return res;
103
104 /* Figure out where to send multicast message */
105
Per Liden4323add2006-01-18 00:38:21 +0100106 ext_targets = tipc_nametbl_mc_translate(seq->type, seq->lower, seq->upper,
107 TIPC_NODE_SCOPE, &dports);
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900108
109 /* Send message to destinations (duplicate it only if necessary) */
Per Lidenb97bf3f2006-01-02 19:04:38 +0100110
111 if (ext_targets) {
112 if (dports.count != 0) {
113 ibuf = skb_copy(buf, GFP_ATOMIC);
114 if (ibuf == NULL) {
Per Liden4323add2006-01-18 00:38:21 +0100115 tipc_port_list_free(&dports);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100116 buf_discard(buf);
117 return -ENOMEM;
118 }
119 }
Per Liden4323add2006-01-18 00:38:21 +0100120 res = tipc_bclink_send_msg(buf);
Allan Stephensa0168922010-12-31 18:59:35 +0000121 if ((res < 0) && (dports.count != 0))
Per Lidenb97bf3f2006-01-02 19:04:38 +0100122 buf_discard(ibuf);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100123 } else {
124 ibuf = buf;
125 }
126
127 if (res >= 0) {
128 if (ibuf)
Per Liden4323add2006-01-18 00:38:21 +0100129 tipc_port_recv_mcast(ibuf, &dports);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100130 } else {
Per Liden4323add2006-01-18 00:38:21 +0100131 tipc_port_list_free(&dports);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100132 }
133 return res;
134}
135
136/**
Per Liden4323add2006-01-18 00:38:21 +0100137 * tipc_port_recv_mcast - deliver multicast message to all destination ports
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900138 *
Per Lidenb97bf3f2006-01-02 19:04:38 +0100139 * If there is no port list, perform a lookup to create one
140 */
141
Per Liden4323add2006-01-18 00:38:21 +0100142void tipc_port_recv_mcast(struct sk_buff *buf, struct port_list *dp)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100143{
Allan Stephens0e659672010-12-31 18:59:32 +0000144 struct tipc_msg *msg;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100145 struct port_list dports = {0, NULL, };
146 struct port_list *item = dp;
147 int cnt = 0;
148
Per Lidenb97bf3f2006-01-02 19:04:38 +0100149 msg = buf_msg(buf);
150
151 /* Create destination port list, if one wasn't supplied */
152
153 if (dp == NULL) {
Per Liden4323add2006-01-18 00:38:21 +0100154 tipc_nametbl_mc_translate(msg_nametype(msg),
Per Lidenb97bf3f2006-01-02 19:04:38 +0100155 msg_namelower(msg),
156 msg_nameupper(msg),
157 TIPC_CLUSTER_SCOPE,
158 &dports);
159 item = dp = &dports;
160 }
161
162 /* Deliver a copy of message to each destination port */
163
164 if (dp->count != 0) {
165 if (dp->count == 1) {
166 msg_set_destport(msg, dp->ports[0]);
Per Liden4323add2006-01-18 00:38:21 +0100167 tipc_port_recv_msg(buf);
168 tipc_port_list_free(dp);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100169 return;
170 }
171 for (; cnt < dp->count; cnt++) {
172 int index = cnt % PLSIZE;
173 struct sk_buff *b = skb_clone(buf, GFP_ATOMIC);
174
175 if (b == NULL) {
Allan Stephensa10bd922006-06-25 23:52:17 -0700176 warn("Unable to deliver multicast message(s)\n");
Per Lidenb97bf3f2006-01-02 19:04:38 +0100177 goto exit;
178 }
Allan Stephensa0168922010-12-31 18:59:35 +0000179 if ((index == 0) && (cnt != 0))
Per Lidenb97bf3f2006-01-02 19:04:38 +0100180 item = item->next;
Allan Stephens0e659672010-12-31 18:59:32 +0000181 msg_set_destport(buf_msg(b), item->ports[index]);
Per Liden4323add2006-01-18 00:38:21 +0100182 tipc_port_recv_msg(b);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100183 }
184 }
185exit:
186 buf_discard(buf);
Per Liden4323add2006-01-18 00:38:21 +0100187 tipc_port_list_free(dp);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100188}
189
190/**
Allan Stephens7ef43eb2008-05-12 15:42:28 -0700191 * tipc_createport_raw - create a generic TIPC port
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900192 *
Allan Stephens0ea52242008-07-14 22:42:19 -0700193 * Returns pointer to (locked) TIPC port, or NULL if unable to create it
Per Lidenb97bf3f2006-01-02 19:04:38 +0100194 */
195
Allan Stephens0ea52242008-07-14 22:42:19 -0700196struct tipc_port *tipc_createport_raw(void *usr_handle,
Per Lidenb97bf3f2006-01-02 19:04:38 +0100197 u32 (*dispatcher)(struct tipc_port *, struct sk_buff *),
198 void (*wakeup)(struct tipc_port *),
Allan Stephens0ea52242008-07-14 22:42:19 -0700199 const u32 importance)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100200{
Allan Stephens23dd4cc2011-01-07 11:43:40 -0500201 struct tipc_port *p_ptr;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100202 struct tipc_msg *msg;
203 u32 ref;
204
Panagiotis Issaris0da974f2006-07-21 14:51:30 -0700205 p_ptr = kzalloc(sizeof(*p_ptr), GFP_ATOMIC);
Allan Stephensa10bd922006-06-25 23:52:17 -0700206 if (!p_ptr) {
207 warn("Port creation failed, no memory\n");
Allan Stephens0ea52242008-07-14 22:42:19 -0700208 return NULL;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100209 }
Allan Stephens23dd4cc2011-01-07 11:43:40 -0500210 ref = tipc_ref_acquire(p_ptr, &p_ptr->lock);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100211 if (!ref) {
Allan Stephensa10bd922006-06-25 23:52:17 -0700212 warn("Port creation failed, reference table exhausted\n");
Per Lidenb97bf3f2006-01-02 19:04:38 +0100213 kfree(p_ptr);
Allan Stephens0ea52242008-07-14 22:42:19 -0700214 return NULL;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100215 }
216
Allan Stephens23dd4cc2011-01-07 11:43:40 -0500217 p_ptr->usr_handle = usr_handle;
218 p_ptr->max_pkt = MAX_PKT_DEFAULT;
219 p_ptr->ref = ref;
220 msg = &p_ptr->phdr;
Allan Stephensc68ca7b2010-05-11 14:30:12 +0000221 tipc_msg_init(msg, importance, TIPC_NAMED_MSG, LONG_H_SIZE, 0);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100222 msg_set_origport(msg, ref);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100223 INIT_LIST_HEAD(&p_ptr->wait_list);
224 INIT_LIST_HEAD(&p_ptr->subscription.nodesub_list);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100225 p_ptr->dispatcher = dispatcher;
226 p_ptr->wakeup = wakeup;
Sam Ravnborg1fc54d82006-03-20 22:36:47 -0800227 p_ptr->user_port = NULL;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100228 k_init_timer(&p_ptr->timer, (Handler)port_timeout, ref);
Per Liden4323add2006-01-18 00:38:21 +0100229 spin_lock_bh(&tipc_port_list_lock);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100230 INIT_LIST_HEAD(&p_ptr->publications);
231 INIT_LIST_HEAD(&p_ptr->port_list);
232 list_add_tail(&p_ptr->port_list, &ports);
Per Liden4323add2006-01-18 00:38:21 +0100233 spin_unlock_bh(&tipc_port_list_lock);
Allan Stephens23dd4cc2011-01-07 11:43:40 -0500234 return p_ptr;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100235}
236
237int tipc_deleteport(u32 ref)
238{
Allan Stephens23dd4cc2011-01-07 11:43:40 -0500239 struct tipc_port *p_ptr;
Sam Ravnborg1fc54d82006-03-20 22:36:47 -0800240 struct sk_buff *buf = NULL;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100241
Sam Ravnborg1fc54d82006-03-20 22:36:47 -0800242 tipc_withdraw(ref, 0, NULL);
Per Liden4323add2006-01-18 00:38:21 +0100243 p_ptr = tipc_port_lock(ref);
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900244 if (!p_ptr)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100245 return -EINVAL;
246
Per Liden4323add2006-01-18 00:38:21 +0100247 tipc_ref_discard(ref);
248 tipc_port_unlock(p_ptr);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100249
250 k_cancel_timer(&p_ptr->timer);
Allan Stephens23dd4cc2011-01-07 11:43:40 -0500251 if (p_ptr->connected) {
Per Lidenb97bf3f2006-01-02 19:04:38 +0100252 buf = port_build_peer_abort_msg(p_ptr, TIPC_ERR_NO_PORT);
Per Liden4323add2006-01-18 00:38:21 +0100253 tipc_nodesub_unsubscribe(&p_ptr->subscription);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100254 }
Allan Stephense83504f2010-12-31 18:59:30 +0000255 kfree(p_ptr->user_port);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100256
Per Liden4323add2006-01-18 00:38:21 +0100257 spin_lock_bh(&tipc_port_list_lock);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100258 list_del(&p_ptr->port_list);
259 list_del(&p_ptr->wait_list);
Per Liden4323add2006-01-18 00:38:21 +0100260 spin_unlock_bh(&tipc_port_list_lock);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100261 k_term_timer(&p_ptr->timer);
262 kfree(p_ptr);
Per Liden4323add2006-01-18 00:38:21 +0100263 tipc_net_route_msg(buf);
Allan Stephens0e35fd52008-07-14 22:44:01 -0700264 return 0;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100265}
266
Allan Stephens23dd4cc2011-01-07 11:43:40 -0500267static int port_unreliable(struct tipc_port *p_ptr)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100268{
Allan Stephens23dd4cc2011-01-07 11:43:40 -0500269 return msg_src_droppable(&p_ptr->phdr);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100270}
271
272int tipc_portunreliable(u32 ref, unsigned int *isunreliable)
273{
Allan Stephens23dd4cc2011-01-07 11:43:40 -0500274 struct tipc_port *p_ptr;
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900275
Per Liden4323add2006-01-18 00:38:21 +0100276 p_ptr = tipc_port_lock(ref);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100277 if (!p_ptr)
278 return -EINVAL;
279 *isunreliable = port_unreliable(p_ptr);
Julia Lawall4cec72c2008-01-08 23:48:20 -0800280 tipc_port_unlock(p_ptr);
Allan Stephens0e35fd52008-07-14 22:44:01 -0700281 return 0;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100282}
283
284int tipc_set_portunreliable(u32 ref, unsigned int isunreliable)
285{
Allan Stephens23dd4cc2011-01-07 11:43:40 -0500286 struct tipc_port *p_ptr;
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900287
Per Liden4323add2006-01-18 00:38:21 +0100288 p_ptr = tipc_port_lock(ref);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100289 if (!p_ptr)
290 return -EINVAL;
Allan Stephens23dd4cc2011-01-07 11:43:40 -0500291 msg_set_src_droppable(&p_ptr->phdr, (isunreliable != 0));
Per Liden4323add2006-01-18 00:38:21 +0100292 tipc_port_unlock(p_ptr);
Allan Stephens0e35fd52008-07-14 22:44:01 -0700293 return 0;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100294}
295
Allan Stephens23dd4cc2011-01-07 11:43:40 -0500296static int port_unreturnable(struct tipc_port *p_ptr)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100297{
Allan Stephens23dd4cc2011-01-07 11:43:40 -0500298 return msg_dest_droppable(&p_ptr->phdr);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100299}
300
301int tipc_portunreturnable(u32 ref, unsigned int *isunrejectable)
302{
Allan Stephens23dd4cc2011-01-07 11:43:40 -0500303 struct tipc_port *p_ptr;
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900304
Per Liden4323add2006-01-18 00:38:21 +0100305 p_ptr = tipc_port_lock(ref);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100306 if (!p_ptr)
307 return -EINVAL;
308 *isunrejectable = port_unreturnable(p_ptr);
Julia Lawall4cec72c2008-01-08 23:48:20 -0800309 tipc_port_unlock(p_ptr);
Allan Stephens0e35fd52008-07-14 22:44:01 -0700310 return 0;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100311}
312
313int tipc_set_portunreturnable(u32 ref, unsigned int isunrejectable)
314{
Allan Stephens23dd4cc2011-01-07 11:43:40 -0500315 struct tipc_port *p_ptr;
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900316
Per Liden4323add2006-01-18 00:38:21 +0100317 p_ptr = tipc_port_lock(ref);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100318 if (!p_ptr)
319 return -EINVAL;
Allan Stephens23dd4cc2011-01-07 11:43:40 -0500320 msg_set_dest_droppable(&p_ptr->phdr, (isunrejectable != 0));
Per Liden4323add2006-01-18 00:38:21 +0100321 tipc_port_unlock(p_ptr);
Allan Stephens0e35fd52008-07-14 22:44:01 -0700322 return 0;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100323}
324
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900325/*
326 * port_build_proto_msg(): build a port level protocol
327 * or a connection abortion message. Called with
Per Lidenb97bf3f2006-01-02 19:04:38 +0100328 * tipc_port lock on.
329 */
330static struct sk_buff *port_build_proto_msg(u32 destport, u32 destnode,
331 u32 origport, u32 orignode,
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900332 u32 usr, u32 type, u32 err,
Allan Stephens741de3e2011-01-25 13:33:31 -0500333 u32 ack)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100334{
335 struct sk_buff *buf;
336 struct tipc_msg *msg;
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900337
stephen hemminger31e3c3f2010-10-13 13:20:35 +0000338 buf = tipc_buf_acquire(LONG_H_SIZE);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100339 if (buf) {
340 msg = buf_msg(buf);
Allan Stephensc68ca7b2010-05-11 14:30:12 +0000341 tipc_msg_init(msg, usr, type, LONG_H_SIZE, destnode);
Allan Stephens75715212008-06-04 17:37:34 -0700342 msg_set_errcode(msg, err);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100343 msg_set_destport(msg, destport);
344 msg_set_origport(msg, origport);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100345 msg_set_orignode(msg, orignode);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100346 msg_set_msgcnt(msg, ack);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100347 }
348 return buf;
349}
350
Per Lidenb97bf3f2006-01-02 19:04:38 +0100351int tipc_reject_msg(struct sk_buff *buf, u32 err)
352{
353 struct tipc_msg *msg = buf_msg(buf);
354 struct sk_buff *rbuf;
355 struct tipc_msg *rmsg;
356 int hdr_sz;
357 u32 imp = msg_importance(msg);
358 u32 data_sz = msg_data_sz(msg);
359
360 if (data_sz > MAX_REJECT_SIZE)
361 data_sz = MAX_REJECT_SIZE;
362 if (msg_connected(msg) && (imp < TIPC_CRITICAL_IMPORTANCE))
363 imp++;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100364
365 /* discard rejected message if it shouldn't be returned to sender */
366 if (msg_errcode(msg) || msg_dest_droppable(msg)) {
367 buf_discard(buf);
368 return data_sz;
369 }
370
371 /* construct rejected message */
372 if (msg_mcast(msg))
373 hdr_sz = MCAST_H_SIZE;
374 else
375 hdr_sz = LONG_H_SIZE;
stephen hemminger31e3c3f2010-10-13 13:20:35 +0000376 rbuf = tipc_buf_acquire(data_sz + hdr_sz);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100377 if (rbuf == NULL) {
378 buf_discard(buf);
379 return data_sz;
380 }
381 rmsg = buf_msg(rbuf);
Allan Stephensc68ca7b2010-05-11 14:30:12 +0000382 tipc_msg_init(rmsg, imp, msg_type(msg), hdr_sz, msg_orignode(msg));
Allan Stephens75715212008-06-04 17:37:34 -0700383 msg_set_errcode(rmsg, err);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100384 msg_set_destport(rmsg, msg_origport(msg));
Per Lidenb97bf3f2006-01-02 19:04:38 +0100385 msg_set_origport(rmsg, msg_destport(msg));
Allan Stephens99c14592008-06-04 17:48:25 -0700386 if (msg_short(msg)) {
Per Lidenb97bf3f2006-01-02 19:04:38 +0100387 msg_set_orignode(rmsg, tipc_own_addr);
Allan Stephens99c14592008-06-04 17:48:25 -0700388 /* leave name type & instance as zeroes */
389 } else {
Per Lidenb97bf3f2006-01-02 19:04:38 +0100390 msg_set_orignode(rmsg, msg_destnode(msg));
Allan Stephens99c14592008-06-04 17:48:25 -0700391 msg_set_nametype(rmsg, msg_nametype(msg));
392 msg_set_nameinst(rmsg, msg_nameinst(msg));
393 }
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900394 msg_set_size(rmsg, data_sz + hdr_sz);
Arnaldo Carvalho de Melo27d7ff42007-03-31 11:55:19 -0300395 skb_copy_to_linear_data_offset(rbuf, hdr_sz, msg_data(msg), data_sz);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100396
397 /* send self-abort message when rejecting on a connected port */
398 if (msg_connected(msg)) {
Sam Ravnborg1fc54d82006-03-20 22:36:47 -0800399 struct sk_buff *abuf = NULL;
Allan Stephens23dd4cc2011-01-07 11:43:40 -0500400 struct tipc_port *p_ptr = tipc_port_lock(msg_destport(msg));
Per Lidenb97bf3f2006-01-02 19:04:38 +0100401
402 if (p_ptr) {
Allan Stephens23dd4cc2011-01-07 11:43:40 -0500403 if (p_ptr->connected)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100404 abuf = port_build_self_abort_msg(p_ptr, err);
Per Liden4323add2006-01-18 00:38:21 +0100405 tipc_port_unlock(p_ptr);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100406 }
Per Liden4323add2006-01-18 00:38:21 +0100407 tipc_net_route_msg(abuf);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100408 }
409
410 /* send rejected message */
411 buf_discard(buf);
Per Liden4323add2006-01-18 00:38:21 +0100412 tipc_net_route_msg(rbuf);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100413 return data_sz;
414}
415
Allan Stephens23dd4cc2011-01-07 11:43:40 -0500416int tipc_port_reject_sections(struct tipc_port *p_ptr, struct tipc_msg *hdr,
Per Liden4323add2006-01-18 00:38:21 +0100417 struct iovec const *msg_sect, u32 num_sect,
418 int err)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100419{
420 struct sk_buff *buf;
421 int res;
422
Allan Stephensc68ca7b2010-05-11 14:30:12 +0000423 res = tipc_msg_build(hdr, msg_sect, num_sect, MAX_MSG_SIZE,
Per Lidenb97bf3f2006-01-02 19:04:38 +0100424 !p_ptr->user_port, &buf);
425 if (!buf)
426 return res;
427
428 return tipc_reject_msg(buf, err);
429}
430
431static void port_timeout(unsigned long ref)
432{
Allan Stephens23dd4cc2011-01-07 11:43:40 -0500433 struct tipc_port *p_ptr = tipc_port_lock(ref);
Sam Ravnborg1fc54d82006-03-20 22:36:47 -0800434 struct sk_buff *buf = NULL;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100435
Allan Stephens065fd172006-10-16 21:38:05 -0700436 if (!p_ptr)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100437 return;
438
Allan Stephens23dd4cc2011-01-07 11:43:40 -0500439 if (!p_ptr->connected) {
Allan Stephens065fd172006-10-16 21:38:05 -0700440 tipc_port_unlock(p_ptr);
441 return;
442 }
443
Per Lidenb97bf3f2006-01-02 19:04:38 +0100444 /* Last probe answered ? */
445 if (p_ptr->probing_state == PROBING) {
446 buf = port_build_self_abort_msg(p_ptr, TIPC_ERR_NO_PORT);
447 } else {
448 buf = port_build_proto_msg(port_peerport(p_ptr),
449 port_peernode(p_ptr),
Allan Stephens23dd4cc2011-01-07 11:43:40 -0500450 p_ptr->ref,
Per Lidenb97bf3f2006-01-02 19:04:38 +0100451 tipc_own_addr,
452 CONN_MANAGER,
453 CONN_PROBE,
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900454 TIPC_OK,
Per Lidenb97bf3f2006-01-02 19:04:38 +0100455 0);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100456 p_ptr->probing_state = PROBING;
457 k_start_timer(&p_ptr->timer, p_ptr->probing_interval);
458 }
Per Liden4323add2006-01-18 00:38:21 +0100459 tipc_port_unlock(p_ptr);
460 tipc_net_route_msg(buf);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100461}
462
463
464static void port_handle_node_down(unsigned long ref)
465{
Allan Stephens23dd4cc2011-01-07 11:43:40 -0500466 struct tipc_port *p_ptr = tipc_port_lock(ref);
Allan Stephens0e659672010-12-31 18:59:32 +0000467 struct sk_buff *buf = NULL;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100468
469 if (!p_ptr)
470 return;
471 buf = port_build_self_abort_msg(p_ptr, TIPC_ERR_NO_NODE);
Per Liden4323add2006-01-18 00:38:21 +0100472 tipc_port_unlock(p_ptr);
473 tipc_net_route_msg(buf);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100474}
475
476
Allan Stephens23dd4cc2011-01-07 11:43:40 -0500477static struct sk_buff *port_build_self_abort_msg(struct tipc_port *p_ptr, u32 err)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100478{
Allan Stephens23dd4cc2011-01-07 11:43:40 -0500479 u32 imp = msg_importance(&p_ptr->phdr);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100480
Allan Stephens23dd4cc2011-01-07 11:43:40 -0500481 if (!p_ptr->connected)
Sam Ravnborg1fc54d82006-03-20 22:36:47 -0800482 return NULL;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100483 if (imp < TIPC_CRITICAL_IMPORTANCE)
484 imp++;
Allan Stephens23dd4cc2011-01-07 11:43:40 -0500485 return port_build_proto_msg(p_ptr->ref,
Per Lidenb97bf3f2006-01-02 19:04:38 +0100486 tipc_own_addr,
487 port_peerport(p_ptr),
488 port_peernode(p_ptr),
489 imp,
490 TIPC_CONN_MSG,
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900491 err,
Per Lidenb97bf3f2006-01-02 19:04:38 +0100492 0);
493}
494
495
Allan Stephens23dd4cc2011-01-07 11:43:40 -0500496static struct sk_buff *port_build_peer_abort_msg(struct tipc_port *p_ptr, u32 err)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100497{
Allan Stephens23dd4cc2011-01-07 11:43:40 -0500498 u32 imp = msg_importance(&p_ptr->phdr);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100499
Allan Stephens23dd4cc2011-01-07 11:43:40 -0500500 if (!p_ptr->connected)
Sam Ravnborg1fc54d82006-03-20 22:36:47 -0800501 return NULL;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100502 if (imp < TIPC_CRITICAL_IMPORTANCE)
503 imp++;
504 return port_build_proto_msg(port_peerport(p_ptr),
505 port_peernode(p_ptr),
Allan Stephens23dd4cc2011-01-07 11:43:40 -0500506 p_ptr->ref,
Per Lidenb97bf3f2006-01-02 19:04:38 +0100507 tipc_own_addr,
508 imp,
509 TIPC_CONN_MSG,
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900510 err,
Per Lidenb97bf3f2006-01-02 19:04:38 +0100511 0);
512}
513
Per Liden4323add2006-01-18 00:38:21 +0100514void tipc_port_recv_proto_msg(struct sk_buff *buf)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100515{
516 struct tipc_msg *msg = buf_msg(buf);
Allan Stephens23dd4cc2011-01-07 11:43:40 -0500517 struct tipc_port *p_ptr = tipc_port_lock(msg_destport(msg));
Per Lidenb97bf3f2006-01-02 19:04:38 +0100518 u32 err = TIPC_OK;
Sam Ravnborg1fc54d82006-03-20 22:36:47 -0800519 struct sk_buff *r_buf = NULL;
520 struct sk_buff *abort_buf = NULL;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100521
Per Lidenb97bf3f2006-01-02 19:04:38 +0100522 if (!p_ptr) {
523 err = TIPC_ERR_NO_PORT;
Allan Stephens23dd4cc2011-01-07 11:43:40 -0500524 } else if (p_ptr->connected) {
Allan Stephens96d841b2010-08-17 11:00:11 +0000525 if ((port_peernode(p_ptr) != msg_orignode(msg)) ||
526 (port_peerport(p_ptr) != msg_origport(msg))) {
Per Lidenb97bf3f2006-01-02 19:04:38 +0100527 err = TIPC_ERR_NO_PORT;
Allan Stephens96d841b2010-08-17 11:00:11 +0000528 } else if (msg_type(msg) == CONN_ACK) {
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900529 int wakeup = tipc_port_congested(p_ptr) &&
Allan Stephens23dd4cc2011-01-07 11:43:40 -0500530 p_ptr->congested &&
Per Lidenb97bf3f2006-01-02 19:04:38 +0100531 p_ptr->wakeup;
532 p_ptr->acked += msg_msgcnt(msg);
Per Liden4323add2006-01-18 00:38:21 +0100533 if (tipc_port_congested(p_ptr))
Per Lidenb97bf3f2006-01-02 19:04:38 +0100534 goto exit;
Allan Stephens23dd4cc2011-01-07 11:43:40 -0500535 p_ptr->congested = 0;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100536 if (!wakeup)
537 goto exit;
Allan Stephens23dd4cc2011-01-07 11:43:40 -0500538 p_ptr->wakeup(p_ptr);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100539 goto exit;
540 }
Allan Stephens23dd4cc2011-01-07 11:43:40 -0500541 } else if (p_ptr->published) {
Per Lidenb97bf3f2006-01-02 19:04:38 +0100542 err = TIPC_ERR_NO_PORT;
543 }
544 if (err) {
545 r_buf = port_build_proto_msg(msg_origport(msg),
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900546 msg_orignode(msg),
547 msg_destport(msg),
Per Lidenb97bf3f2006-01-02 19:04:38 +0100548 tipc_own_addr,
Allan Stephens06d82c92008-03-06 15:06:55 -0800549 TIPC_HIGH_IMPORTANCE,
Per Lidenb97bf3f2006-01-02 19:04:38 +0100550 TIPC_CONN_MSG,
551 err,
Per Lidenb97bf3f2006-01-02 19:04:38 +0100552 0);
553 goto exit;
554 }
555
556 /* All is fine */
557 if (msg_type(msg) == CONN_PROBE) {
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900558 r_buf = port_build_proto_msg(msg_origport(msg),
559 msg_orignode(msg),
560 msg_destport(msg),
561 tipc_own_addr,
Per Lidenb97bf3f2006-01-02 19:04:38 +0100562 CONN_MANAGER,
563 CONN_PROBE_REPLY,
564 TIPC_OK,
Per Lidenb97bf3f2006-01-02 19:04:38 +0100565 0);
566 }
567 p_ptr->probing_state = CONFIRMED;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100568exit:
569 if (p_ptr)
Per Liden4323add2006-01-18 00:38:21 +0100570 tipc_port_unlock(p_ptr);
571 tipc_net_route_msg(r_buf);
572 tipc_net_route_msg(abort_buf);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100573 buf_discard(buf);
574}
575
Allan Stephens23dd4cc2011-01-07 11:43:40 -0500576static void port_print(struct tipc_port *p_ptr, struct print_buf *buf, int full_id)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100577{
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900578 struct publication *publ;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100579
580 if (full_id)
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900581 tipc_printf(buf, "<%u.%u.%u:%u>:",
Per Lidenb97bf3f2006-01-02 19:04:38 +0100582 tipc_zone(tipc_own_addr), tipc_cluster(tipc_own_addr),
Allan Stephens23dd4cc2011-01-07 11:43:40 -0500583 tipc_node(tipc_own_addr), p_ptr->ref);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100584 else
Allan Stephens23dd4cc2011-01-07 11:43:40 -0500585 tipc_printf(buf, "%-10u:", p_ptr->ref);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100586
Allan Stephens23dd4cc2011-01-07 11:43:40 -0500587 if (p_ptr->connected) {
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900588 u32 dport = port_peerport(p_ptr);
589 u32 destnode = port_peernode(p_ptr);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100590
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900591 tipc_printf(buf, " connected to <%u.%u.%u:%u>",
592 tipc_zone(destnode), tipc_cluster(destnode),
593 tipc_node(destnode), dport);
Allan Stephens23dd4cc2011-01-07 11:43:40 -0500594 if (p_ptr->conn_type != 0)
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900595 tipc_printf(buf, " via {%u,%u}",
Allan Stephens23dd4cc2011-01-07 11:43:40 -0500596 p_ptr->conn_type,
597 p_ptr->conn_instance);
598 } else if (p_ptr->published) {
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900599 tipc_printf(buf, " bound to");
600 list_for_each_entry(publ, &p_ptr->publications, pport_list) {
Per Lidenb97bf3f2006-01-02 19:04:38 +0100601 if (publ->lower == publ->upper)
602 tipc_printf(buf, " {%u,%u}", publ->type,
603 publ->lower);
604 else
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900605 tipc_printf(buf, " {%u,%u,%u}", publ->type,
Per Lidenb97bf3f2006-01-02 19:04:38 +0100606 publ->lower, publ->upper);
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900607 }
608 }
609 tipc_printf(buf, "\n");
Per Lidenb97bf3f2006-01-02 19:04:38 +0100610}
611
612#define MAX_PORT_QUERY 32768
613
Per Liden4323add2006-01-18 00:38:21 +0100614struct sk_buff *tipc_port_get_ports(void)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100615{
616 struct sk_buff *buf;
617 struct tlv_desc *rep_tlv;
618 struct print_buf pb;
Allan Stephens23dd4cc2011-01-07 11:43:40 -0500619 struct tipc_port *p_ptr;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100620 int str_len;
621
Per Liden4323add2006-01-18 00:38:21 +0100622 buf = tipc_cfg_reply_alloc(TLV_SPACE(MAX_PORT_QUERY));
Per Lidenb97bf3f2006-01-02 19:04:38 +0100623 if (!buf)
624 return NULL;
625 rep_tlv = (struct tlv_desc *)buf->data;
626
Per Liden4323add2006-01-18 00:38:21 +0100627 tipc_printbuf_init(&pb, TLV_DATA(rep_tlv), MAX_PORT_QUERY);
628 spin_lock_bh(&tipc_port_list_lock);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100629 list_for_each_entry(p_ptr, &ports, port_list) {
Allan Stephens23dd4cc2011-01-07 11:43:40 -0500630 spin_lock_bh(p_ptr->lock);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100631 port_print(p_ptr, &pb, 0);
Allan Stephens23dd4cc2011-01-07 11:43:40 -0500632 spin_unlock_bh(p_ptr->lock);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100633 }
Per Liden4323add2006-01-18 00:38:21 +0100634 spin_unlock_bh(&tipc_port_list_lock);
635 str_len = tipc_printbuf_validate(&pb);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100636
637 skb_put(buf, TLV_SPACE(str_len));
638 TLV_SET(rep_tlv, TIPC_TLV_ULTRA_STRING, NULL, str_len);
639
640 return buf;
641}
642
Per Liden4323add2006-01-18 00:38:21 +0100643void tipc_port_reinit(void)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100644{
Allan Stephens23dd4cc2011-01-07 11:43:40 -0500645 struct tipc_port *p_ptr;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100646 struct tipc_msg *msg;
647
Per Liden4323add2006-01-18 00:38:21 +0100648 spin_lock_bh(&tipc_port_list_lock);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100649 list_for_each_entry(p_ptr, &ports, port_list) {
Allan Stephens23dd4cc2011-01-07 11:43:40 -0500650 msg = &p_ptr->phdr;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100651 if (msg_orignode(msg) == tipc_own_addr)
652 break;
Allan Stephens6d4a6672008-05-21 14:54:12 -0700653 msg_set_prevnode(msg, tipc_own_addr);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100654 msg_set_orignode(msg, tipc_own_addr);
655 }
Per Liden4323add2006-01-18 00:38:21 +0100656 spin_unlock_bh(&tipc_port_list_lock);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100657}
658
659
660/*
661 * port_dispatcher_sigh(): Signal handler for messages destinated
662 * to the tipc_port interface.
663 */
664
665static void port_dispatcher_sigh(void *dummy)
666{
667 struct sk_buff *buf;
668
669 spin_lock_bh(&queue_lock);
670 buf = msg_queue_head;
Sam Ravnborg1fc54d82006-03-20 22:36:47 -0800671 msg_queue_head = NULL;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100672 spin_unlock_bh(&queue_lock);
673
674 while (buf) {
Allan Stephens23dd4cc2011-01-07 11:43:40 -0500675 struct tipc_port *p_ptr;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100676 struct user_port *up_ptr;
677 struct tipc_portid orig;
678 struct tipc_name_seq dseq;
679 void *usr_handle;
680 int connected;
681 int published;
Allan Stephens96882432006-06-25 23:38:58 -0700682 u32 message_type;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100683
684 struct sk_buff *next = buf->next;
685 struct tipc_msg *msg = buf_msg(buf);
686 u32 dref = msg_destport(msg);
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900687
Allan Stephens96882432006-06-25 23:38:58 -0700688 message_type = msg_type(msg);
689 if (message_type > TIPC_DIRECT_MSG)
690 goto reject; /* Unsupported message type */
691
Per Liden4323add2006-01-18 00:38:21 +0100692 p_ptr = tipc_port_lock(dref);
Allan Stephens96882432006-06-25 23:38:58 -0700693 if (!p_ptr)
694 goto reject; /* Port deleted while msg in queue */
695
Per Lidenb97bf3f2006-01-02 19:04:38 +0100696 orig.ref = msg_origport(msg);
697 orig.node = msg_orignode(msg);
698 up_ptr = p_ptr->user_port;
699 usr_handle = up_ptr->usr_handle;
Allan Stephens23dd4cc2011-01-07 11:43:40 -0500700 connected = p_ptr->connected;
701 published = p_ptr->published;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100702
703 if (unlikely(msg_errcode(msg)))
704 goto err;
705
Allan Stephens96882432006-06-25 23:38:58 -0700706 switch (message_type) {
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900707
Per Lidenb97bf3f2006-01-02 19:04:38 +0100708 case TIPC_CONN_MSG:{
709 tipc_conn_msg_event cb = up_ptr->conn_msg_cb;
710 u32 peer_port = port_peerport(p_ptr);
711 u32 peer_node = port_peernode(p_ptr);
Allan Stephenscb7ce912011-01-24 15:02:14 -0500712 u32 dsz;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100713
Julia Lawall4cec72c2008-01-08 23:48:20 -0800714 tipc_port_unlock(p_ptr);
Allan Stephens5307e462008-06-04 17:28:45 -0700715 if (unlikely(!cb))
716 goto reject;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100717 if (unlikely(!connected)) {
Allan Stephens84b07c12008-06-04 17:28:21 -0700718 if (tipc_connect2port(dref, &orig))
Per Lidenb97bf3f2006-01-02 19:04:38 +0100719 goto reject;
Allan Stephens84b07c12008-06-04 17:28:21 -0700720 } else if ((msg_origport(msg) != peer_port) ||
721 (msg_orignode(msg) != peer_node))
Per Lidenb97bf3f2006-01-02 19:04:38 +0100722 goto reject;
Allan Stephenscb7ce912011-01-24 15:02:14 -0500723 dsz = msg_data_sz(msg);
724 if (unlikely(dsz &&
725 (++p_ptr->conn_unacked >=
726 TIPC_FLOW_CONTROL_WIN)))
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900727 tipc_acknowledge(dref,
Allan Stephens23dd4cc2011-01-07 11:43:40 -0500728 p_ptr->conn_unacked);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100729 skb_pull(buf, msg_hdr_sz(msg));
Allan Stephenscb7ce912011-01-24 15:02:14 -0500730 cb(usr_handle, dref, &buf, msg_data(msg), dsz);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100731 break;
732 }
733 case TIPC_DIRECT_MSG:{
734 tipc_msg_event cb = up_ptr->msg_cb;
735
Julia Lawall4cec72c2008-01-08 23:48:20 -0800736 tipc_port_unlock(p_ptr);
Allan Stephens5307e462008-06-04 17:28:45 -0700737 if (unlikely(!cb || connected))
Per Lidenb97bf3f2006-01-02 19:04:38 +0100738 goto reject;
739 skb_pull(buf, msg_hdr_sz(msg));
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900740 cb(usr_handle, dref, &buf, msg_data(msg),
Per Lidenb97bf3f2006-01-02 19:04:38 +0100741 msg_data_sz(msg), msg_importance(msg),
742 &orig);
743 break;
744 }
Allan Stephens96882432006-06-25 23:38:58 -0700745 case TIPC_MCAST_MSG:
Per Lidenb97bf3f2006-01-02 19:04:38 +0100746 case TIPC_NAMED_MSG:{
747 tipc_named_msg_event cb = up_ptr->named_msg_cb;
748
Julia Lawall4cec72c2008-01-08 23:48:20 -0800749 tipc_port_unlock(p_ptr);
Allan Stephens5307e462008-06-04 17:28:45 -0700750 if (unlikely(!cb || connected || !published))
Per Lidenb97bf3f2006-01-02 19:04:38 +0100751 goto reject;
752 dseq.type = msg_nametype(msg);
753 dseq.lower = msg_nameinst(msg);
Allan Stephens96882432006-06-25 23:38:58 -0700754 dseq.upper = (message_type == TIPC_NAMED_MSG)
755 ? dseq.lower : msg_nameupper(msg);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100756 skb_pull(buf, msg_hdr_sz(msg));
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900757 cb(usr_handle, dref, &buf, msg_data(msg),
Per Lidenb97bf3f2006-01-02 19:04:38 +0100758 msg_data_sz(msg), msg_importance(msg),
759 &orig, &dseq);
760 break;
761 }
762 }
763 if (buf)
764 buf_discard(buf);
765 buf = next;
766 continue;
767err:
Allan Stephens96882432006-06-25 23:38:58 -0700768 switch (message_type) {
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900769
Per Lidenb97bf3f2006-01-02 19:04:38 +0100770 case TIPC_CONN_MSG:{
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900771 tipc_conn_shutdown_event cb =
Per Lidenb97bf3f2006-01-02 19:04:38 +0100772 up_ptr->conn_err_cb;
773 u32 peer_port = port_peerport(p_ptr);
774 u32 peer_node = port_peernode(p_ptr);
775
Julia Lawall4cec72c2008-01-08 23:48:20 -0800776 tipc_port_unlock(p_ptr);
Allan Stephens5307e462008-06-04 17:28:45 -0700777 if (!cb || !connected)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100778 break;
Allan Stephens5307e462008-06-04 17:28:45 -0700779 if ((msg_origport(msg) != peer_port) ||
780 (msg_orignode(msg) != peer_node))
Per Lidenb97bf3f2006-01-02 19:04:38 +0100781 break;
782 tipc_disconnect(dref);
783 skb_pull(buf, msg_hdr_sz(msg));
784 cb(usr_handle, dref, &buf, msg_data(msg),
785 msg_data_sz(msg), msg_errcode(msg));
786 break;
787 }
788 case TIPC_DIRECT_MSG:{
789 tipc_msg_err_event cb = up_ptr->err_cb;
790
Julia Lawall4cec72c2008-01-08 23:48:20 -0800791 tipc_port_unlock(p_ptr);
Allan Stephens5307e462008-06-04 17:28:45 -0700792 if (!cb || connected)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100793 break;
794 skb_pull(buf, msg_hdr_sz(msg));
795 cb(usr_handle, dref, &buf, msg_data(msg),
796 msg_data_sz(msg), msg_errcode(msg), &orig);
797 break;
798 }
Allan Stephens96882432006-06-25 23:38:58 -0700799 case TIPC_MCAST_MSG:
Per Lidenb97bf3f2006-01-02 19:04:38 +0100800 case TIPC_NAMED_MSG:{
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900801 tipc_named_msg_err_event cb =
Per Lidenb97bf3f2006-01-02 19:04:38 +0100802 up_ptr->named_err_cb;
803
Julia Lawall4cec72c2008-01-08 23:48:20 -0800804 tipc_port_unlock(p_ptr);
Allan Stephens5307e462008-06-04 17:28:45 -0700805 if (!cb || connected)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100806 break;
807 dseq.type = msg_nametype(msg);
808 dseq.lower = msg_nameinst(msg);
Allan Stephens96882432006-06-25 23:38:58 -0700809 dseq.upper = (message_type == TIPC_NAMED_MSG)
810 ? dseq.lower : msg_nameupper(msg);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100811 skb_pull(buf, msg_hdr_sz(msg));
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900812 cb(usr_handle, dref, &buf, msg_data(msg),
Per Lidenb97bf3f2006-01-02 19:04:38 +0100813 msg_data_sz(msg), msg_errcode(msg), &dseq);
814 break;
815 }
816 }
817 if (buf)
818 buf_discard(buf);
819 buf = next;
820 continue;
821reject:
822 tipc_reject_msg(buf, TIPC_ERR_NO_PORT);
823 buf = next;
824 }
825}
826
827/*
828 * port_dispatcher(): Dispatcher for messages destinated
829 * to the tipc_port interface. Called with port locked.
830 */
831
832static u32 port_dispatcher(struct tipc_port *dummy, struct sk_buff *buf)
833{
834 buf->next = NULL;
835 spin_lock_bh(&queue_lock);
836 if (msg_queue_head) {
837 msg_queue_tail->next = buf;
838 msg_queue_tail = buf;
839 } else {
840 msg_queue_tail = msg_queue_head = buf;
Per Liden4323add2006-01-18 00:38:21 +0100841 tipc_k_signal((Handler)port_dispatcher_sigh, 0);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100842 }
843 spin_unlock_bh(&queue_lock);
Allan Stephens0e35fd52008-07-14 22:44:01 -0700844 return 0;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100845}
846
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900847/*
Per Lidenb97bf3f2006-01-02 19:04:38 +0100848 * Wake up port after congestion: Called with port locked,
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900849 *
Per Lidenb97bf3f2006-01-02 19:04:38 +0100850 */
851
852static void port_wakeup_sh(unsigned long ref)
853{
Allan Stephens23dd4cc2011-01-07 11:43:40 -0500854 struct tipc_port *p_ptr;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100855 struct user_port *up_ptr;
Sam Ravnborg1fc54d82006-03-20 22:36:47 -0800856 tipc_continue_event cb = NULL;
857 void *uh = NULL;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100858
Per Liden4323add2006-01-18 00:38:21 +0100859 p_ptr = tipc_port_lock(ref);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100860 if (p_ptr) {
861 up_ptr = p_ptr->user_port;
862 if (up_ptr) {
863 cb = up_ptr->continue_event_cb;
864 uh = up_ptr->usr_handle;
865 }
Per Liden4323add2006-01-18 00:38:21 +0100866 tipc_port_unlock(p_ptr);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100867 }
868 if (cb)
869 cb(uh, ref);
870}
871
872
873static void port_wakeup(struct tipc_port *p_ptr)
874{
Per Liden4323add2006-01-18 00:38:21 +0100875 tipc_k_signal((Handler)port_wakeup_sh, p_ptr->ref);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100876}
877
878void tipc_acknowledge(u32 ref, u32 ack)
879{
Allan Stephens23dd4cc2011-01-07 11:43:40 -0500880 struct tipc_port *p_ptr;
Sam Ravnborg1fc54d82006-03-20 22:36:47 -0800881 struct sk_buff *buf = NULL;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100882
Per Liden4323add2006-01-18 00:38:21 +0100883 p_ptr = tipc_port_lock(ref);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100884 if (!p_ptr)
885 return;
Allan Stephens23dd4cc2011-01-07 11:43:40 -0500886 if (p_ptr->connected) {
887 p_ptr->conn_unacked -= ack;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100888 buf = port_build_proto_msg(port_peerport(p_ptr),
889 port_peernode(p_ptr),
890 ref,
891 tipc_own_addr,
892 CONN_MANAGER,
893 CONN_ACK,
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900894 TIPC_OK,
Per Lidenb97bf3f2006-01-02 19:04:38 +0100895 ack);
896 }
Per Liden4323add2006-01-18 00:38:21 +0100897 tipc_port_unlock(p_ptr);
898 tipc_net_route_msg(buf);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100899}
900
901/*
Allan Stephensb0c1e922010-12-31 18:59:22 +0000902 * tipc_createport(): user level call.
Per Lidenb97bf3f2006-01-02 19:04:38 +0100903 */
904
Allan Stephensb0c1e922010-12-31 18:59:22 +0000905int tipc_createport(void *usr_handle,
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900906 unsigned int importance,
907 tipc_msg_err_event error_cb,
908 tipc_named_msg_err_event named_error_cb,
909 tipc_conn_shutdown_event conn_error_cb,
910 tipc_msg_event msg_cb,
911 tipc_named_msg_event named_msg_cb,
912 tipc_conn_msg_event conn_msg_cb,
Per Lidenb97bf3f2006-01-02 19:04:38 +0100913 tipc_continue_event continue_event_cb,/* May be zero */
914 u32 *portref)
915{
916 struct user_port *up_ptr;
Allan Stephens23dd4cc2011-01-07 11:43:40 -0500917 struct tipc_port *p_ptr;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100918
Panagiotis Issaris0da974f2006-07-21 14:51:30 -0700919 up_ptr = kmalloc(sizeof(*up_ptr), GFP_ATOMIC);
Allan Stephensa10bd922006-06-25 23:52:17 -0700920 if (!up_ptr) {
Allan Stephensa75bf872006-06-25 23:50:01 -0700921 warn("Port creation failed, no memory\n");
Per Lidenb97bf3f2006-01-02 19:04:38 +0100922 return -ENOMEM;
923 }
Allan Stephens23dd4cc2011-01-07 11:43:40 -0500924 p_ptr = (struct tipc_port *)tipc_createport_raw(NULL, port_dispatcher,
Allan Stephens0ea52242008-07-14 22:42:19 -0700925 port_wakeup, importance);
926 if (!p_ptr) {
Per Lidenb97bf3f2006-01-02 19:04:38 +0100927 kfree(up_ptr);
928 return -ENOMEM;
929 }
930
931 p_ptr->user_port = up_ptr;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100932 up_ptr->usr_handle = usr_handle;
Allan Stephens23dd4cc2011-01-07 11:43:40 -0500933 up_ptr->ref = p_ptr->ref;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100934 up_ptr->err_cb = error_cb;
935 up_ptr->named_err_cb = named_error_cb;
936 up_ptr->conn_err_cb = conn_error_cb;
937 up_ptr->msg_cb = msg_cb;
938 up_ptr->named_msg_cb = named_msg_cb;
939 up_ptr->conn_msg_cb = conn_msg_cb;
940 up_ptr->continue_event_cb = continue_event_cb;
Allan Stephens23dd4cc2011-01-07 11:43:40 -0500941 *portref = p_ptr->ref;
Per Liden4323add2006-01-18 00:38:21 +0100942 tipc_port_unlock(p_ptr);
Allan Stephens0e35fd52008-07-14 22:44:01 -0700943 return 0;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100944}
945
Per Lidenb97bf3f2006-01-02 19:04:38 +0100946int tipc_portimportance(u32 ref, unsigned int *importance)
947{
Allan Stephens23dd4cc2011-01-07 11:43:40 -0500948 struct tipc_port *p_ptr;
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900949
Per Liden4323add2006-01-18 00:38:21 +0100950 p_ptr = tipc_port_lock(ref);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100951 if (!p_ptr)
952 return -EINVAL;
Allan Stephens23dd4cc2011-01-07 11:43:40 -0500953 *importance = (unsigned int)msg_importance(&p_ptr->phdr);
Julia Lawall4cec72c2008-01-08 23:48:20 -0800954 tipc_port_unlock(p_ptr);
Allan Stephens0e35fd52008-07-14 22:44:01 -0700955 return 0;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100956}
957
958int tipc_set_portimportance(u32 ref, unsigned int imp)
959{
Allan Stephens23dd4cc2011-01-07 11:43:40 -0500960 struct tipc_port *p_ptr;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100961
962 if (imp > TIPC_CRITICAL_IMPORTANCE)
963 return -EINVAL;
964
Per Liden4323add2006-01-18 00:38:21 +0100965 p_ptr = tipc_port_lock(ref);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100966 if (!p_ptr)
967 return -EINVAL;
Allan Stephens23dd4cc2011-01-07 11:43:40 -0500968 msg_set_importance(&p_ptr->phdr, (u32)imp);
Julia Lawall4cec72c2008-01-08 23:48:20 -0800969 tipc_port_unlock(p_ptr);
Allan Stephens0e35fd52008-07-14 22:44:01 -0700970 return 0;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100971}
972
973
974int tipc_publish(u32 ref, unsigned int scope, struct tipc_name_seq const *seq)
975{
Allan Stephens23dd4cc2011-01-07 11:43:40 -0500976 struct tipc_port *p_ptr;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100977 struct publication *publ;
978 u32 key;
979 int res = -EINVAL;
980
Per Liden4323add2006-01-18 00:38:21 +0100981 p_ptr = tipc_port_lock(ref);
Adrian Bunkd55b4c62006-10-31 16:59:35 -0800982 if (!p_ptr)
983 return -EINVAL;
984
Allan Stephens23dd4cc2011-01-07 11:43:40 -0500985 if (p_ptr->connected)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100986 goto exit;
987 if (seq->lower > seq->upper)
988 goto exit;
989 if ((scope < TIPC_ZONE_SCOPE) || (scope > TIPC_NODE_SCOPE))
990 goto exit;
991 key = ref + p_ptr->pub_count + 1;
992 if (key == ref) {
993 res = -EADDRINUSE;
994 goto exit;
995 }
Per Liden4323add2006-01-18 00:38:21 +0100996 publ = tipc_nametbl_publish(seq->type, seq->lower, seq->upper,
Allan Stephens23dd4cc2011-01-07 11:43:40 -0500997 scope, p_ptr->ref, key);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100998 if (publ) {
999 list_add(&publ->pport_list, &p_ptr->publications);
1000 p_ptr->pub_count++;
Allan Stephens23dd4cc2011-01-07 11:43:40 -05001001 p_ptr->published = 1;
Allan Stephens0e35fd52008-07-14 22:44:01 -07001002 res = 0;
Per Lidenb97bf3f2006-01-02 19:04:38 +01001003 }
1004exit:
Per Liden4323add2006-01-18 00:38:21 +01001005 tipc_port_unlock(p_ptr);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001006 return res;
1007}
1008
1009int tipc_withdraw(u32 ref, unsigned int scope, struct tipc_name_seq const *seq)
1010{
Allan Stephens23dd4cc2011-01-07 11:43:40 -05001011 struct tipc_port *p_ptr;
Per Lidenb97bf3f2006-01-02 19:04:38 +01001012 struct publication *publ;
1013 struct publication *tpubl;
1014 int res = -EINVAL;
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001015
Per Liden4323add2006-01-18 00:38:21 +01001016 p_ptr = tipc_port_lock(ref);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001017 if (!p_ptr)
1018 return -EINVAL;
Per Lidenb97bf3f2006-01-02 19:04:38 +01001019 if (!seq) {
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001020 list_for_each_entry_safe(publ, tpubl,
Per Lidenb97bf3f2006-01-02 19:04:38 +01001021 &p_ptr->publications, pport_list) {
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001022 tipc_nametbl_withdraw(publ->type, publ->lower,
Per Liden4323add2006-01-18 00:38:21 +01001023 publ->ref, publ->key);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001024 }
Allan Stephens0e35fd52008-07-14 22:44:01 -07001025 res = 0;
Per Lidenb97bf3f2006-01-02 19:04:38 +01001026 } else {
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001027 list_for_each_entry_safe(publ, tpubl,
Per Lidenb97bf3f2006-01-02 19:04:38 +01001028 &p_ptr->publications, pport_list) {
1029 if (publ->scope != scope)
1030 continue;
1031 if (publ->type != seq->type)
1032 continue;
1033 if (publ->lower != seq->lower)
1034 continue;
1035 if (publ->upper != seq->upper)
1036 break;
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001037 tipc_nametbl_withdraw(publ->type, publ->lower,
Per Liden4323add2006-01-18 00:38:21 +01001038 publ->ref, publ->key);
Allan Stephens0e35fd52008-07-14 22:44:01 -07001039 res = 0;
Per Lidenb97bf3f2006-01-02 19:04:38 +01001040 break;
1041 }
1042 }
1043 if (list_empty(&p_ptr->publications))
Allan Stephens23dd4cc2011-01-07 11:43:40 -05001044 p_ptr->published = 0;
Per Liden4323add2006-01-18 00:38:21 +01001045 tipc_port_unlock(p_ptr);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001046 return res;
1047}
1048
1049int tipc_connect2port(u32 ref, struct tipc_portid const *peer)
1050{
Allan Stephens23dd4cc2011-01-07 11:43:40 -05001051 struct tipc_port *p_ptr;
Per Lidenb97bf3f2006-01-02 19:04:38 +01001052 struct tipc_msg *msg;
1053 int res = -EINVAL;
1054
Per Liden4323add2006-01-18 00:38:21 +01001055 p_ptr = tipc_port_lock(ref);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001056 if (!p_ptr)
1057 return -EINVAL;
Allan Stephens23dd4cc2011-01-07 11:43:40 -05001058 if (p_ptr->published || p_ptr->connected)
Per Lidenb97bf3f2006-01-02 19:04:38 +01001059 goto exit;
1060 if (!peer->ref)
1061 goto exit;
1062
Allan Stephens23dd4cc2011-01-07 11:43:40 -05001063 msg = &p_ptr->phdr;
Per Lidenb97bf3f2006-01-02 19:04:38 +01001064 msg_set_destnode(msg, peer->node);
1065 msg_set_destport(msg, peer->ref);
1066 msg_set_orignode(msg, tipc_own_addr);
Allan Stephens23dd4cc2011-01-07 11:43:40 -05001067 msg_set_origport(msg, p_ptr->ref);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001068 msg_set_type(msg, TIPC_CONN_MSG);
Allan Stephens53b94362011-04-17 16:02:11 -04001069 msg_set_lookup_scope(msg, 0);
Allan Stephens08c80e92010-12-31 18:59:17 +00001070 msg_set_hdr_sz(msg, SHORT_H_SIZE);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001071
1072 p_ptr->probing_interval = PROBING_INTERVAL;
1073 p_ptr->probing_state = CONFIRMED;
Allan Stephens23dd4cc2011-01-07 11:43:40 -05001074 p_ptr->connected = 1;
Per Lidenb97bf3f2006-01-02 19:04:38 +01001075 k_start_timer(&p_ptr->timer, p_ptr->probing_interval);
1076
Allan Stephens0e659672010-12-31 18:59:32 +00001077 tipc_nodesub_subscribe(&p_ptr->subscription, peer->node,
David S. Miller880b0052006-01-12 13:22:32 -08001078 (void *)(unsigned long)ref,
Per Lidenb97bf3f2006-01-02 19:04:38 +01001079 (net_ev_handler)port_handle_node_down);
Allan Stephens0e35fd52008-07-14 22:44:01 -07001080 res = 0;
Per Lidenb97bf3f2006-01-02 19:04:38 +01001081exit:
Per Liden4323add2006-01-18 00:38:21 +01001082 tipc_port_unlock(p_ptr);
Allan Stephens23dd4cc2011-01-07 11:43:40 -05001083 p_ptr->max_pkt = tipc_link_get_max_pkt(peer->node, ref);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001084 return res;
1085}
1086
Allan Stephens0c3141e2008-04-15 00:22:02 -07001087/**
1088 * tipc_disconnect_port - disconnect port from peer
1089 *
1090 * Port must be locked.
1091 */
1092
1093int tipc_disconnect_port(struct tipc_port *tp_ptr)
1094{
1095 int res;
1096
1097 if (tp_ptr->connected) {
1098 tp_ptr->connected = 0;
1099 /* let timer expire on it's own to avoid deadlock! */
1100 tipc_nodesub_unsubscribe(
Allan Stephens23dd4cc2011-01-07 11:43:40 -05001101 &((struct tipc_port *)tp_ptr)->subscription);
Allan Stephens0e35fd52008-07-14 22:44:01 -07001102 res = 0;
Allan Stephens0c3141e2008-04-15 00:22:02 -07001103 } else {
1104 res = -ENOTCONN;
1105 }
1106 return res;
1107}
1108
Per Lidenb97bf3f2006-01-02 19:04:38 +01001109/*
1110 * tipc_disconnect(): Disconnect port form peer.
1111 * This is a node local operation.
1112 */
1113
1114int tipc_disconnect(u32 ref)
1115{
Allan Stephens23dd4cc2011-01-07 11:43:40 -05001116 struct tipc_port *p_ptr;
Allan Stephens0c3141e2008-04-15 00:22:02 -07001117 int res;
Per Lidenb97bf3f2006-01-02 19:04:38 +01001118
Per Liden4323add2006-01-18 00:38:21 +01001119 p_ptr = tipc_port_lock(ref);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001120 if (!p_ptr)
1121 return -EINVAL;
Allan Stephens0c3141e2008-04-15 00:22:02 -07001122 res = tipc_disconnect_port((struct tipc_port *)p_ptr);
Per Liden4323add2006-01-18 00:38:21 +01001123 tipc_port_unlock(p_ptr);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001124 return res;
1125}
1126
1127/*
1128 * tipc_shutdown(): Send a SHUTDOWN msg to peer and disconnect
1129 */
1130int tipc_shutdown(u32 ref)
1131{
Allan Stephens23dd4cc2011-01-07 11:43:40 -05001132 struct tipc_port *p_ptr;
Sam Ravnborg1fc54d82006-03-20 22:36:47 -08001133 struct sk_buff *buf = NULL;
Per Lidenb97bf3f2006-01-02 19:04:38 +01001134
Per Liden4323add2006-01-18 00:38:21 +01001135 p_ptr = tipc_port_lock(ref);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001136 if (!p_ptr)
1137 return -EINVAL;
1138
Allan Stephens23dd4cc2011-01-07 11:43:40 -05001139 if (p_ptr->connected) {
1140 u32 imp = msg_importance(&p_ptr->phdr);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001141 if (imp < TIPC_CRITICAL_IMPORTANCE)
1142 imp++;
1143 buf = port_build_proto_msg(port_peerport(p_ptr),
1144 port_peernode(p_ptr),
1145 ref,
1146 tipc_own_addr,
1147 imp,
1148 TIPC_CONN_MSG,
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001149 TIPC_CONN_SHUTDOWN,
Per Lidenb97bf3f2006-01-02 19:04:38 +01001150 0);
1151 }
Per Liden4323add2006-01-18 00:38:21 +01001152 tipc_port_unlock(p_ptr);
1153 tipc_net_route_msg(buf);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001154 return tipc_disconnect(ref);
1155}
1156
Per Lidenb97bf3f2006-01-02 19:04:38 +01001157/*
Per Liden4323add2006-01-18 00:38:21 +01001158 * tipc_port_recv_sections(): Concatenate and deliver sectioned
Per Lidenb97bf3f2006-01-02 19:04:38 +01001159 * message for this node.
1160 */
1161
Allan Stephens23dd4cc2011-01-07 11:43:40 -05001162static int tipc_port_recv_sections(struct tipc_port *sender, unsigned int num_sect,
stephen hemminger31e3c3f2010-10-13 13:20:35 +00001163 struct iovec const *msg_sect)
Per Lidenb97bf3f2006-01-02 19:04:38 +01001164{
1165 struct sk_buff *buf;
1166 int res;
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001167
Allan Stephens23dd4cc2011-01-07 11:43:40 -05001168 res = tipc_msg_build(&sender->phdr, msg_sect, num_sect,
Per Lidenb97bf3f2006-01-02 19:04:38 +01001169 MAX_MSG_SIZE, !sender->user_port, &buf);
1170 if (likely(buf))
Per Liden4323add2006-01-18 00:38:21 +01001171 tipc_port_recv_msg(buf);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001172 return res;
1173}
1174
1175/**
1176 * tipc_send - send message sections on connection
1177 */
1178
1179int tipc_send(u32 ref, unsigned int num_sect, struct iovec const *msg_sect)
1180{
Allan Stephens23dd4cc2011-01-07 11:43:40 -05001181 struct tipc_port *p_ptr;
Per Lidenb97bf3f2006-01-02 19:04:38 +01001182 u32 destnode;
1183 int res;
1184
Per Liden4323add2006-01-18 00:38:21 +01001185 p_ptr = tipc_port_deref(ref);
Allan Stephens23dd4cc2011-01-07 11:43:40 -05001186 if (!p_ptr || !p_ptr->connected)
Per Lidenb97bf3f2006-01-02 19:04:38 +01001187 return -EINVAL;
1188
Allan Stephens23dd4cc2011-01-07 11:43:40 -05001189 p_ptr->congested = 1;
Per Liden4323add2006-01-18 00:38:21 +01001190 if (!tipc_port_congested(p_ptr)) {
Per Lidenb97bf3f2006-01-02 19:04:38 +01001191 destnode = port_peernode(p_ptr);
1192 if (likely(destnode != tipc_own_addr))
Per Liden4323add2006-01-18 00:38:21 +01001193 res = tipc_link_send_sections_fast(p_ptr, msg_sect, num_sect,
1194 destnode);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001195 else
Per Liden4323add2006-01-18 00:38:21 +01001196 res = tipc_port_recv_sections(p_ptr, num_sect, msg_sect);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001197
1198 if (likely(res != -ELINKCONG)) {
Allan Stephens23dd4cc2011-01-07 11:43:40 -05001199 p_ptr->congested = 0;
Allan Stephenscb7ce912011-01-24 15:02:14 -05001200 if (res > 0)
1201 p_ptr->sent++;
Per Lidenb97bf3f2006-01-02 19:04:38 +01001202 return res;
1203 }
1204 }
1205 if (port_unreliable(p_ptr)) {
Allan Stephens23dd4cc2011-01-07 11:43:40 -05001206 p_ptr->congested = 0;
Per Lidenb97bf3f2006-01-02 19:04:38 +01001207 /* Just calculate msg length and return */
Allan Stephensc68ca7b2010-05-11 14:30:12 +00001208 return tipc_msg_calc_data_size(msg_sect, num_sect);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001209 }
1210 return -ELINKCONG;
1211}
1212
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001213/**
Allan Stephens12bae472010-11-30 12:01:02 +00001214 * tipc_send2name - send message sections to port name
Per Lidenb97bf3f2006-01-02 19:04:38 +01001215 */
1216
Allan Stephens12bae472010-11-30 12:01:02 +00001217int tipc_send2name(u32 ref, struct tipc_name const *name, unsigned int domain,
1218 unsigned int num_sect, struct iovec const *msg_sect)
Per Lidenb97bf3f2006-01-02 19:04:38 +01001219{
Allan Stephens23dd4cc2011-01-07 11:43:40 -05001220 struct tipc_port *p_ptr;
Per Lidenb97bf3f2006-01-02 19:04:38 +01001221 struct tipc_msg *msg;
1222 u32 destnode = domain;
Allan Stephens9ccc2eb2010-05-11 14:30:06 +00001223 u32 destport;
Per Lidenb97bf3f2006-01-02 19:04:38 +01001224 int res;
1225
Per Liden4323add2006-01-18 00:38:21 +01001226 p_ptr = tipc_port_deref(ref);
Allan Stephens23dd4cc2011-01-07 11:43:40 -05001227 if (!p_ptr || p_ptr->connected)
Per Lidenb97bf3f2006-01-02 19:04:38 +01001228 return -EINVAL;
1229
Allan Stephens23dd4cc2011-01-07 11:43:40 -05001230 msg = &p_ptr->phdr;
Per Lidenb97bf3f2006-01-02 19:04:38 +01001231 msg_set_type(msg, TIPC_NAMED_MSG);
Allan Stephens12bae472010-11-30 12:01:02 +00001232 msg_set_orignode(msg, tipc_own_addr);
1233 msg_set_origport(msg, ref);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001234 msg_set_hdr_sz(msg, LONG_H_SIZE);
1235 msg_set_nametype(msg, name->type);
1236 msg_set_nameinst(msg, name->instance);
Allan Stephensc68ca7b2010-05-11 14:30:12 +00001237 msg_set_lookup_scope(msg, tipc_addr_scope(domain));
Per Liden4323add2006-01-18 00:38:21 +01001238 destport = tipc_nametbl_translate(name->type, name->instance, &destnode);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001239 msg_set_destnode(msg, destnode);
1240 msg_set_destport(msg, destport);
1241
Allan Stephens5d9c54c2010-09-03 08:33:39 +00001242 if (likely(destport)) {
Per Lidenb97bf3f2006-01-02 19:04:38 +01001243 if (likely(destnode == tipc_own_addr))
Allan Stephenscb7ce912011-01-24 15:02:14 -05001244 res = tipc_port_recv_sections(p_ptr, num_sect,
1245 msg_sect);
1246 else
1247 res = tipc_link_send_sections_fast(p_ptr, msg_sect,
1248 num_sect, destnode);
1249 if (likely(res != -ELINKCONG)) {
1250 if (res > 0)
1251 p_ptr->sent++;
Per Lidenb97bf3f2006-01-02 19:04:38 +01001252 return res;
Allan Stephenscb7ce912011-01-24 15:02:14 -05001253 }
Per Lidenb97bf3f2006-01-02 19:04:38 +01001254 if (port_unreliable(p_ptr)) {
1255 /* Just calculate msg length and return */
Allan Stephensc68ca7b2010-05-11 14:30:12 +00001256 return tipc_msg_calc_data_size(msg_sect, num_sect);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001257 }
1258 return -ELINKCONG;
1259 }
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001260 return tipc_port_reject_sections(p_ptr, msg, msg_sect, num_sect,
Per Liden4323add2006-01-18 00:38:21 +01001261 TIPC_ERR_NO_NAME);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001262}
1263
1264/**
Allan Stephens12bae472010-11-30 12:01:02 +00001265 * tipc_send2port - send message sections to port identity
Per Lidenb97bf3f2006-01-02 19:04:38 +01001266 */
1267
Allan Stephens12bae472010-11-30 12:01:02 +00001268int tipc_send2port(u32 ref, struct tipc_portid const *dest,
1269 unsigned int num_sect, struct iovec const *msg_sect)
Per Lidenb97bf3f2006-01-02 19:04:38 +01001270{
Allan Stephens23dd4cc2011-01-07 11:43:40 -05001271 struct tipc_port *p_ptr;
Per Lidenb97bf3f2006-01-02 19:04:38 +01001272 struct tipc_msg *msg;
1273 int res;
1274
Per Liden4323add2006-01-18 00:38:21 +01001275 p_ptr = tipc_port_deref(ref);
Allan Stephens23dd4cc2011-01-07 11:43:40 -05001276 if (!p_ptr || p_ptr->connected)
Per Lidenb97bf3f2006-01-02 19:04:38 +01001277 return -EINVAL;
1278
Allan Stephens23dd4cc2011-01-07 11:43:40 -05001279 msg = &p_ptr->phdr;
Per Lidenb97bf3f2006-01-02 19:04:38 +01001280 msg_set_type(msg, TIPC_DIRECT_MSG);
Allan Stephens53b94362011-04-17 16:02:11 -04001281 msg_set_lookup_scope(msg, 0);
Allan Stephens12bae472010-11-30 12:01:02 +00001282 msg_set_orignode(msg, tipc_own_addr);
1283 msg_set_origport(msg, ref);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001284 msg_set_destnode(msg, dest->node);
1285 msg_set_destport(msg, dest->ref);
1286 msg_set_hdr_sz(msg, DIR_MSG_H_SIZE);
Allan Stephenscb7ce912011-01-24 15:02:14 -05001287
Per Lidenb97bf3f2006-01-02 19:04:38 +01001288 if (dest->node == tipc_own_addr)
Allan Stephenscb7ce912011-01-24 15:02:14 -05001289 res = tipc_port_recv_sections(p_ptr, num_sect, msg_sect);
1290 else
1291 res = tipc_link_send_sections_fast(p_ptr, msg_sect, num_sect,
1292 dest->node);
1293 if (likely(res != -ELINKCONG)) {
1294 if (res > 0)
1295 p_ptr->sent++;
Per Lidenb97bf3f2006-01-02 19:04:38 +01001296 return res;
Allan Stephenscb7ce912011-01-24 15:02:14 -05001297 }
Per Lidenb97bf3f2006-01-02 19:04:38 +01001298 if (port_unreliable(p_ptr)) {
1299 /* Just calculate msg length and return */
Allan Stephensc68ca7b2010-05-11 14:30:12 +00001300 return tipc_msg_calc_data_size(msg_sect, num_sect);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001301 }
1302 return -ELINKCONG;
1303}
1304
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001305/**
Allan Stephens12bae472010-11-30 12:01:02 +00001306 * tipc_send_buf2port - send message buffer to port identity
Per Lidenb97bf3f2006-01-02 19:04:38 +01001307 */
1308
Allan Stephens12bae472010-11-30 12:01:02 +00001309int tipc_send_buf2port(u32 ref, struct tipc_portid const *dest,
1310 struct sk_buff *buf, unsigned int dsz)
Per Lidenb97bf3f2006-01-02 19:04:38 +01001311{
Allan Stephens23dd4cc2011-01-07 11:43:40 -05001312 struct tipc_port *p_ptr;
Per Lidenb97bf3f2006-01-02 19:04:38 +01001313 struct tipc_msg *msg;
1314 int res;
1315
Allan Stephens23dd4cc2011-01-07 11:43:40 -05001316 p_ptr = (struct tipc_port *)tipc_ref_deref(ref);
1317 if (!p_ptr || p_ptr->connected)
Per Lidenb97bf3f2006-01-02 19:04:38 +01001318 return -EINVAL;
1319
Allan Stephens23dd4cc2011-01-07 11:43:40 -05001320 msg = &p_ptr->phdr;
Per Lidenb97bf3f2006-01-02 19:04:38 +01001321 msg_set_type(msg, TIPC_DIRECT_MSG);
Allan Stephens12bae472010-11-30 12:01:02 +00001322 msg_set_orignode(msg, tipc_own_addr);
1323 msg_set_origport(msg, ref);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001324 msg_set_destnode(msg, dest->node);
1325 msg_set_destport(msg, dest->ref);
1326 msg_set_hdr_sz(msg, DIR_MSG_H_SIZE);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001327 msg_set_size(msg, DIR_MSG_H_SIZE + dsz);
1328 if (skb_cow(buf, DIR_MSG_H_SIZE))
1329 return -ENOMEM;
1330
1331 skb_push(buf, DIR_MSG_H_SIZE);
Arnaldo Carvalho de Melo27d7ff42007-03-31 11:55:19 -03001332 skb_copy_to_linear_data(buf, msg, DIR_MSG_H_SIZE);
Allan Stephenscb7ce912011-01-24 15:02:14 -05001333
Per Lidenb97bf3f2006-01-02 19:04:38 +01001334 if (dest->node == tipc_own_addr)
Allan Stephenscb7ce912011-01-24 15:02:14 -05001335 res = tipc_port_recv_msg(buf);
1336 else
1337 res = tipc_send_buf_fast(buf, dest->node);
1338 if (likely(res != -ELINKCONG)) {
1339 if (res > 0)
1340 p_ptr->sent++;
Per Lidenb97bf3f2006-01-02 19:04:38 +01001341 return res;
Allan Stephenscb7ce912011-01-24 15:02:14 -05001342 }
Per Lidenb97bf3f2006-01-02 19:04:38 +01001343 if (port_unreliable(p_ptr))
1344 return dsz;
1345 return -ELINKCONG;
1346}
1347