blob: 77c7ccd492b54c1d662be3d326d64e6faf2a679d [file] [log] [blame]
Per Lidenb97bf3f2006-01-02 19:04:38 +01001/*
2 * net/tipc/link.c: TIPC link code
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09003 *
Jon Paul Maloy170b3922014-01-07 17:02:41 -05004 * Copyright (c) 1996-2007, 2012-2014, Ericsson AB
Ying Xue198d73b2013-06-17 10:54:42 -04005 * Copyright (c) 2004-2007, 2010-2013, 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"
Per Lidenb97bf3f2006-01-02 19:04:38 +010038#include "link.h"
Richard Alpe7be57fc2014-11-20 10:29:12 +010039#include "bcast.h"
Jon Paul Maloy9816f062014-05-14 05:39:15 -040040#include "socket.h"
Per Lidenb97bf3f2006-01-02 19:04:38 +010041#include "name_distr.h"
Per Lidenb97bf3f2006-01-02 19:04:38 +010042#include "discover.h"
43#include "config.h"
Richard Alpe0655f6a2014-11-20 10:29:07 +010044#include "netlink.h"
Per Lidenb97bf3f2006-01-02 19:04:38 +010045
Ying Xue796c75d2013-06-17 10:54:48 -040046#include <linux/pkt_sched.h>
47
Erik Hugne2cf8aa12012-06-29 00:16:37 -040048/*
49 * Error message prefixes
50 */
51static const char *link_co_err = "Link changeover error, ";
52static const char *link_rst_msg = "Resetting link ";
53static const char *link_unk_evt = "Unknown link event ";
Per Lidenb97bf3f2006-01-02 19:04:38 +010054
Richard Alpe7be57fc2014-11-20 10:29:12 +010055static const struct nla_policy tipc_nl_link_policy[TIPC_NLA_LINK_MAX + 1] = {
56 [TIPC_NLA_LINK_UNSPEC] = { .type = NLA_UNSPEC },
57 [TIPC_NLA_LINK_NAME] = {
58 .type = NLA_STRING,
59 .len = TIPC_MAX_LINK_NAME
60 },
61 [TIPC_NLA_LINK_MTU] = { .type = NLA_U32 },
62 [TIPC_NLA_LINK_BROADCAST] = { .type = NLA_FLAG },
63 [TIPC_NLA_LINK_UP] = { .type = NLA_FLAG },
64 [TIPC_NLA_LINK_ACTIVE] = { .type = NLA_FLAG },
65 [TIPC_NLA_LINK_PROP] = { .type = NLA_NESTED },
66 [TIPC_NLA_LINK_STATS] = { .type = NLA_NESTED },
67 [TIPC_NLA_LINK_RX] = { .type = NLA_U32 },
68 [TIPC_NLA_LINK_TX] = { .type = NLA_U32 }
69};
70
Richard Alpe0655f6a2014-11-20 10:29:07 +010071/* Properties valid for media, bearar and link */
72static const struct nla_policy tipc_nl_prop_policy[TIPC_NLA_PROP_MAX + 1] = {
73 [TIPC_NLA_PROP_UNSPEC] = { .type = NLA_UNSPEC },
74 [TIPC_NLA_PROP_PRIO] = { .type = NLA_U32 },
75 [TIPC_NLA_PROP_TOL] = { .type = NLA_U32 },
76 [TIPC_NLA_PROP_WIN] = { .type = NLA_U32 }
77};
78
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +090079/*
Allan Stephensa686e682008-06-04 17:29:39 -070080 * Out-of-range value for link session numbers
81 */
Allan Stephensa686e682008-06-04 17:29:39 -070082#define INVALID_SESSION 0x10000
83
84/*
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +090085 * Link state events:
Per Lidenb97bf3f2006-01-02 19:04:38 +010086 */
Per Lidenb97bf3f2006-01-02 19:04:38 +010087#define STARTING_EVT 856384768 /* link processing trigger */
88#define TRAFFIC_MSG_EVT 560815u /* rx'd ??? */
89#define TIMEOUT_EVT 560817u /* link timer expired */
90
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +090091/*
92 * The following two 'message types' is really just implementation
93 * data conveniently stored in the message header.
Per Lidenb97bf3f2006-01-02 19:04:38 +010094 * They must not be considered part of the protocol
95 */
96#define OPEN_MSG 0
97#define CLOSED_MSG 1
98
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +090099/*
Per Lidenb97bf3f2006-01-02 19:04:38 +0100100 * State value stored in 'exp_msg_count'
101 */
Per Lidenb97bf3f2006-01-02 19:04:38 +0100102#define START_CHANGEOVER 100000u
103
Ying Xuec93d3ba2015-01-09 15:27:04 +0800104static void link_handle_out_of_seq_msg(struct net *net,
105 struct tipc_link *l_ptr,
Per Lidenb97bf3f2006-01-02 19:04:38 +0100106 struct sk_buff *buf);
Ying Xuec93d3ba2015-01-09 15:27:04 +0800107static void tipc_link_proto_rcv(struct net *net, struct tipc_link *l_ptr,
108 struct sk_buff *buf);
109static int tipc_link_tunnel_rcv(struct net *net, struct tipc_node *n_ptr,
Jon Paul Maloy170b3922014-01-07 17:02:41 -0500110 struct sk_buff **buf);
Ying Xue2f55c432015-01-09 15:27:00 +0800111static void link_set_supervision_props(struct tipc_link *l_ptr, u32 tol);
Paul Gortmakera18c4bc2011-12-29 20:58:42 -0500112static void link_state_event(struct tipc_link *l_ptr, u32 event);
113static void link_reset_statistics(struct tipc_link *l_ptr);
114static void link_print(struct tipc_link *l_ptr, const char *str);
Ying Xue247f0f32014-02-18 16:06:46 +0800115static void tipc_link_sync_xmit(struct tipc_link *l);
116static void tipc_link_sync_rcv(struct tipc_node *n, struct sk_buff *buf);
Ying Xuef2f98002015-01-09 15:27:05 +0800117static int tipc_link_input(struct net *net, struct tipc_link *l,
118 struct sk_buff *buf);
Ying Xuec93d3ba2015-01-09 15:27:04 +0800119static int tipc_link_prepare_input(struct net *net, struct tipc_link *l,
120 struct sk_buff **buf);
stephen hemminger31e3c3f2010-10-13 13:20:35 +0000121
Per Lidenb97bf3f2006-01-02 19:04:38 +0100122/*
Sam Ravnborg05790c62006-03-20 22:37:04 -0800123 * Simple link routines
Per Lidenb97bf3f2006-01-02 19:04:38 +0100124 */
Sam Ravnborg05790c62006-03-20 22:37:04 -0800125static unsigned int align(unsigned int i)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100126{
127 return (i + 3) & ~3u;
128}
129
Jon Paul Maloy2d72d492015-02-03 08:59:17 -0500130static void tipc_link_release(struct kref *kref)
131{
132 kfree(container_of(kref, struct tipc_link, ref));
133}
134
135static void tipc_link_get(struct tipc_link *l_ptr)
136{
137 kref_get(&l_ptr->ref);
138}
139
140static void tipc_link_put(struct tipc_link *l_ptr)
141{
142 kref_put(&l_ptr->ref, tipc_link_release);
143}
144
Paul Gortmakera18c4bc2011-12-29 20:58:42 -0500145static void link_init_max_pkt(struct tipc_link *l_ptr)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100146{
Ying Xue7f9f95d2015-01-09 15:27:06 +0800147 struct tipc_node *node = l_ptr->owner;
148 struct tipc_net *tn = net_generic(node->net, tipc_net_id);
Ying Xue7a2f7d12014-04-21 10:55:46 +0800149 struct tipc_bearer *b_ptr;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100150 u32 max_pkt;
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900151
Ying Xue7a2f7d12014-04-21 10:55:46 +0800152 rcu_read_lock();
Ying Xue7f9f95d2015-01-09 15:27:06 +0800153 b_ptr = rcu_dereference_rtnl(tn->bearer_list[l_ptr->bearer_id]);
Ying Xue7a2f7d12014-04-21 10:55:46 +0800154 if (!b_ptr) {
155 rcu_read_unlock();
156 return;
157 }
158 max_pkt = (b_ptr->mtu & ~3);
159 rcu_read_unlock();
160
Per Lidenb97bf3f2006-01-02 19:04:38 +0100161 if (max_pkt > MAX_MSG_SIZE)
162 max_pkt = MAX_MSG_SIZE;
163
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900164 l_ptr->max_pkt_target = max_pkt;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100165 if (l_ptr->max_pkt_target < MAX_PKT_DEFAULT)
166 l_ptr->max_pkt = l_ptr->max_pkt_target;
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900167 else
Per Lidenb97bf3f2006-01-02 19:04:38 +0100168 l_ptr->max_pkt = MAX_PKT_DEFAULT;
169
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900170 l_ptr->max_pkt_probes = 0;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100171}
172
Per Lidenb97bf3f2006-01-02 19:04:38 +0100173/*
Sam Ravnborg05790c62006-03-20 22:37:04 -0800174 * Simple non-static link routines (i.e. referenced outside this file)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100175 */
Paul Gortmakera18c4bc2011-12-29 20:58:42 -0500176int tipc_link_is_up(struct tipc_link *l_ptr)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100177{
178 if (!l_ptr)
179 return 0;
Eric Dumazeta02cec22010-09-22 20:43:57 +0000180 return link_working_working(l_ptr) || link_working_unknown(l_ptr);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100181}
182
Paul Gortmakera18c4bc2011-12-29 20:58:42 -0500183int tipc_link_is_active(struct tipc_link *l_ptr)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100184{
Eric Dumazeta02cec22010-09-22 20:43:57 +0000185 return (l_ptr->owner->active_links[0] == l_ptr) ||
186 (l_ptr->owner->active_links[1] == l_ptr);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100187}
188
189/**
Per Lidenb97bf3f2006-01-02 19:04:38 +0100190 * link_timeout - handle expiration of link timer
191 * @l_ptr: pointer to link
Per Lidenb97bf3f2006-01-02 19:04:38 +0100192 */
Ying Xue2f55c432015-01-09 15:27:00 +0800193static void link_timeout(unsigned long data)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100194{
Ying Xue2f55c432015-01-09 15:27:00 +0800195 struct tipc_link *l_ptr = (struct tipc_link *)data;
Ying Xue58dc55f2014-11-26 11:41:52 +0800196 struct sk_buff *skb;
197
Per Liden4323add2006-01-18 00:38:21 +0100198 tipc_node_lock(l_ptr->owner);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100199
200 /* update counters used in statistical profiling of send traffic */
Ying Xue58dc55f2014-11-26 11:41:52 +0800201 l_ptr->stats.accu_queue_sz += skb_queue_len(&l_ptr->outqueue);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100202 l_ptr->stats.queue_sz_counts++;
203
Ying Xue58dc55f2014-11-26 11:41:52 +0800204 skb = skb_peek(&l_ptr->outqueue);
205 if (skb) {
206 struct tipc_msg *msg = buf_msg(skb);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100207 u32 length = msg_size(msg);
208
Joe Perchesf64f9e72009-11-29 16:55:45 -0800209 if ((msg_user(msg) == MSG_FRAGMENTER) &&
210 (msg_type(msg) == FIRST_FRAGMENT)) {
Per Lidenb97bf3f2006-01-02 19:04:38 +0100211 length = msg_size(msg_get_wrapped(msg));
212 }
213 if (length) {
214 l_ptr->stats.msg_lengths_total += length;
215 l_ptr->stats.msg_length_counts++;
216 if (length <= 64)
217 l_ptr->stats.msg_length_profile[0]++;
218 else if (length <= 256)
219 l_ptr->stats.msg_length_profile[1]++;
220 else if (length <= 1024)
221 l_ptr->stats.msg_length_profile[2]++;
222 else if (length <= 4096)
223 l_ptr->stats.msg_length_profile[3]++;
224 else if (length <= 16384)
225 l_ptr->stats.msg_length_profile[4]++;
226 else if (length <= 32768)
227 l_ptr->stats.msg_length_profile[5]++;
228 else
229 l_ptr->stats.msg_length_profile[6]++;
230 }
231 }
232
233 /* do all other link processing performed on a periodic basis */
Per Lidenb97bf3f2006-01-02 19:04:38 +0100234 link_state_event(l_ptr, TIMEOUT_EVT);
235
236 if (l_ptr->next_out)
Ying Xue47b4c9a2014-11-26 11:41:48 +0800237 tipc_link_push_packets(l_ptr);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100238
Per Liden4323add2006-01-18 00:38:21 +0100239 tipc_node_unlock(l_ptr->owner);
Jon Paul Maloy2d72d492015-02-03 08:59:17 -0500240 tipc_link_put(l_ptr);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100241}
242
Ying Xue2f55c432015-01-09 15:27:00 +0800243static void link_set_timer(struct tipc_link *link, unsigned long time)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100244{
Jon Paul Maloy2d72d492015-02-03 08:59:17 -0500245 if (!mod_timer(&link->timer, jiffies + time))
246 tipc_link_get(link);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100247}
248
249/**
Per Liden4323add2006-01-18 00:38:21 +0100250 * tipc_link_create - create a new link
Allan Stephens37b9c082011-02-28 11:32:27 -0500251 * @n_ptr: pointer to associated node
Per Lidenb97bf3f2006-01-02 19:04:38 +0100252 * @b_ptr: pointer to associated bearer
Per Lidenb97bf3f2006-01-02 19:04:38 +0100253 * @media_addr: media address to use when sending messages over link
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900254 *
Per Lidenb97bf3f2006-01-02 19:04:38 +0100255 * Returns pointer to link.
256 */
Paul Gortmakera18c4bc2011-12-29 20:58:42 -0500257struct tipc_link *tipc_link_create(struct tipc_node *n_ptr,
Ying Xuec61dd612014-02-13 17:29:09 -0500258 struct tipc_bearer *b_ptr,
259 const struct tipc_media_addr *media_addr)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100260{
Ying Xue34747532015-01-09 15:27:10 +0800261 struct tipc_net *tn = net_generic(n_ptr->net, tipc_net_id);
Paul Gortmakera18c4bc2011-12-29 20:58:42 -0500262 struct tipc_link *l_ptr;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100263 struct tipc_msg *msg;
264 char *if_name;
Allan Stephens37b9c082011-02-28 11:32:27 -0500265 char addr_string[16];
266 u32 peer = n_ptr->addr;
267
Holger Brunck0372bf52014-11-14 18:33:19 +0100268 if (n_ptr->link_cnt >= MAX_BEARERS) {
Allan Stephens37b9c082011-02-28 11:32:27 -0500269 tipc_addr_string_fill(addr_string, n_ptr->addr);
Holger Brunck0372bf52014-11-14 18:33:19 +0100270 pr_err("Attempt to establish %uth link to %s. Max %u allowed.\n",
271 n_ptr->link_cnt, addr_string, MAX_BEARERS);
Allan Stephens37b9c082011-02-28 11:32:27 -0500272 return NULL;
273 }
274
275 if (n_ptr->links[b_ptr->identity]) {
276 tipc_addr_string_fill(addr_string, n_ptr->addr);
Erik Hugne2cf8aa12012-06-29 00:16:37 -0400277 pr_err("Attempt to establish second link on <%s> to %s\n",
278 b_ptr->name, addr_string);
Allan Stephens37b9c082011-02-28 11:32:27 -0500279 return NULL;
280 }
Per Lidenb97bf3f2006-01-02 19:04:38 +0100281
Panagiotis Issaris0da974f2006-07-21 14:51:30 -0700282 l_ptr = kzalloc(sizeof(*l_ptr), GFP_ATOMIC);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100283 if (!l_ptr) {
Erik Hugne2cf8aa12012-06-29 00:16:37 -0400284 pr_warn("Link creation failed, no memory\n");
Per Lidenb97bf3f2006-01-02 19:04:38 +0100285 return NULL;
286 }
Jon Paul Maloy2d72d492015-02-03 08:59:17 -0500287 kref_init(&l_ptr->ref);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100288 l_ptr->addr = peer;
Allan Stephens2d627b92011-01-07 13:00:11 -0500289 if_name = strchr(b_ptr->name, ':') + 1;
Allan Stephens062b4c92011-04-07 09:28:47 -0400290 sprintf(l_ptr->name, "%u.%u.%u:%s-%u.%u.%u:unknown",
Ying Xue34747532015-01-09 15:27:10 +0800291 tipc_zone(tn->own_addr), tipc_cluster(tn->own_addr),
292 tipc_node(tn->own_addr),
Per Lidenb97bf3f2006-01-02 19:04:38 +0100293 if_name,
294 tipc_zone(peer), tipc_cluster(peer), tipc_node(peer));
Allan Stephens062b4c92011-04-07 09:28:47 -0400295 /* note: peer i/f name is updated by reset/activate message */
Per Lidenb97bf3f2006-01-02 19:04:38 +0100296 memcpy(&l_ptr->media_addr, media_addr, sizeof(*media_addr));
Allan Stephens37b9c082011-02-28 11:32:27 -0500297 l_ptr->owner = n_ptr;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100298 l_ptr->checkpoint = 1;
Allan Stephensf882cb762011-04-07 09:43:27 -0400299 l_ptr->peer_session = INVALID_SESSION;
Ying Xue7a2f7d12014-04-21 10:55:46 +0800300 l_ptr->bearer_id = b_ptr->identity;
Allan Stephens5c216e12011-10-18 11:34:29 -0400301 link_set_supervision_props(l_ptr, b_ptr->tolerance);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100302 l_ptr->state = RESET_UNKNOWN;
303
304 l_ptr->pmsg = (struct tipc_msg *)&l_ptr->proto_msg;
305 msg = l_ptr->pmsg;
Ying Xue34747532015-01-09 15:27:10 +0800306 tipc_msg_init(n_ptr->net, msg, LINK_PROTOCOL, RESET_MSG, INT_H_SIZE,
307 l_ptr->addr);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100308 msg_set_size(msg, sizeof(l_ptr->proto_msg));
Ying Xuebafa29e2015-01-09 15:27:12 +0800309 msg_set_session(msg, (tn->random & 0xffff));
Per Lidenb97bf3f2006-01-02 19:04:38 +0100310 msg_set_bearer_id(msg, b_ptr->identity);
311 strcpy((char *)msg_data(msg), if_name);
312
313 l_ptr->priority = b_ptr->priority;
Allan Stephens5c216e12011-10-18 11:34:29 -0400314 tipc_link_set_queue_limits(l_ptr, b_ptr->window);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100315
Ying Xue7a2f7d12014-04-21 10:55:46 +0800316 l_ptr->net_plane = b_ptr->net_plane;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100317 link_init_max_pkt(l_ptr);
318
319 l_ptr->next_out_no = 1;
Ying Xue58dc55f2014-11-26 11:41:52 +0800320 __skb_queue_head_init(&l_ptr->outqueue);
Ying Xuebc6fecd2014-11-26 11:41:53 +0800321 __skb_queue_head_init(&l_ptr->deferred_queue);
Richard Alpe340b6e52014-12-10 09:46:54 +0100322 skb_queue_head_init(&l_ptr->waiting_sks);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100323
324 link_reset_statistics(l_ptr);
Allan Stephens37b9c082011-02-28 11:32:27 -0500325 tipc_node_attach_link(n_ptr, l_ptr);
Ying Xue2f55c432015-01-09 15:27:00 +0800326 setup_timer(&l_ptr->timer, link_timeout, (unsigned long)l_ptr);
Jon Paul Maloy581465f2014-01-07 17:02:44 -0500327 link_state_event(l_ptr, STARTING_EVT);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100328
Per Lidenb97bf3f2006-01-02 19:04:38 +0100329 return l_ptr;
330}
331
Jon Paul Maloy2d72d492015-02-03 08:59:17 -0500332/**
333 * link_delete - Conditional deletion of link.
334 * If timer still running, real delete is done when it expires
335 * @link: link to be deleted
336 */
337void tipc_link_delete(struct tipc_link *link)
338{
339 tipc_link_reset_fragments(link);
340 tipc_node_detach_link(link->owner, link);
341 tipc_link_put(link);
342}
343
Ying Xuef2f98002015-01-09 15:27:05 +0800344void tipc_link_delete_list(struct net *net, unsigned int bearer_id,
345 bool shutting_down)
Ying Xue8d8439b2014-02-13 17:29:07 -0500346{
Ying Xuef2f98002015-01-09 15:27:05 +0800347 struct tipc_net *tn = net_generic(net, tipc_net_id);
Jon Paul Maloy2d72d492015-02-03 08:59:17 -0500348 struct tipc_link *link;
349 struct tipc_node *node;
Ying Xue8d8439b2014-02-13 17:29:07 -0500350
Ying Xue6c7a7622014-03-27 12:54:37 +0800351 rcu_read_lock();
Jon Paul Maloy2d72d492015-02-03 08:59:17 -0500352 list_for_each_entry_rcu(node, &tn->node_list, list) {
353 tipc_node_lock(node);
354 link = node->links[bearer_id];
355 if (!link) {
356 tipc_node_unlock(node);
Ying Xuec61dd612014-02-13 17:29:09 -0500357 continue;
358 }
Jon Paul Maloy2d72d492015-02-03 08:59:17 -0500359 tipc_link_reset(link);
360 if (del_timer(&link->timer))
361 tipc_link_put(link);
362 link->flags |= LINK_STOPPED;
363 /* Delete link now, or when failover is finished: */
364 if (shutting_down || !tipc_node_is_up(node))
365 tipc_link_delete(link);
366 tipc_node_unlock(node);
Ying Xue8d8439b2014-02-13 17:29:07 -0500367 }
Ying Xue6c7a7622014-03-27 12:54:37 +0800368 rcu_read_unlock();
Ying Xue8d8439b2014-02-13 17:29:07 -0500369}
Per Lidenb97bf3f2006-01-02 19:04:38 +0100370
371/**
Jon Paul Maloy50100a52014-08-22 18:09:07 -0400372 * link_schedule_user - schedule user for wakeup after congestion
373 * @link: congested link
374 * @oport: sending port
375 * @chain_sz: size of buffer chain that was attempted sent
376 * @imp: importance of message attempted sent
377 * Create pseudo msg to send back to user when congestion abates
Per Lidenb97bf3f2006-01-02 19:04:38 +0100378 */
Jon Paul Maloy50100a52014-08-22 18:09:07 -0400379static bool link_schedule_user(struct tipc_link *link, u32 oport,
380 uint chain_sz, uint imp)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100381{
Ying Xue34747532015-01-09 15:27:10 +0800382 struct net *net = link->owner->net;
383 struct tipc_net *tn = net_generic(net, tipc_net_id);
Jon Paul Maloy50100a52014-08-22 18:09:07 -0400384 struct sk_buff *buf;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100385
Ying Xue34747532015-01-09 15:27:10 +0800386 buf = tipc_msg_create(net, SOCK_WAKEUP, 0, INT_H_SIZE, 0, tn->own_addr,
387 tn->own_addr, oport, 0, 0);
Jon Paul Maloy50100a52014-08-22 18:09:07 -0400388 if (!buf)
389 return false;
390 TIPC_SKB_CB(buf)->chain_sz = chain_sz;
391 TIPC_SKB_CB(buf)->chain_imp = imp;
Richard Alpe340b6e52014-12-10 09:46:54 +0100392 skb_queue_tail(&link->waiting_sks, buf);
Jon Paul Maloy50100a52014-08-22 18:09:07 -0400393 link->stats.link_congs++;
394 return true;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100395}
396
Jon Paul Maloy50100a52014-08-22 18:09:07 -0400397/**
398 * link_prepare_wakeup - prepare users for wakeup after congestion
399 * @link: congested link
400 * Move a number of waiting users, as permitted by available space in
401 * the send queue, from link wait queue to node wait queue for wakeup
402 */
403static void link_prepare_wakeup(struct tipc_link *link)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100404{
Ying Xue58dc55f2014-11-26 11:41:52 +0800405 uint pend_qsz = skb_queue_len(&link->outqueue);
Ying Xue58d78b32014-11-26 11:41:51 +0800406 struct sk_buff *skb, *tmp;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100407
Ying Xue58d78b32014-11-26 11:41:51 +0800408 skb_queue_walk_safe(&link->waiting_sks, skb, tmp) {
409 if (pend_qsz >= link->queue_limit[TIPC_SKB_CB(skb)->chain_imp])
Per Lidenb97bf3f2006-01-02 19:04:38 +0100410 break;
Ying Xue58d78b32014-11-26 11:41:51 +0800411 pend_qsz += TIPC_SKB_CB(skb)->chain_sz;
Richard Alpe340b6e52014-12-10 09:46:54 +0100412 skb_unlink(skb, &link->waiting_sks);
413 skb_queue_tail(&link->owner->waiting_sks, skb);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100414 }
Per Lidenb97bf3f2006-01-02 19:04:38 +0100415}
416
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900417/**
Per Liden4323add2006-01-18 00:38:21 +0100418 * tipc_link_reset_fragments - purge link's inbound message fragments queue
Per Lidenb97bf3f2006-01-02 19:04:38 +0100419 * @l_ptr: pointer to link
420 */
Paul Gortmakera18c4bc2011-12-29 20:58:42 -0500421void tipc_link_reset_fragments(struct tipc_link *l_ptr)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100422{
Jon Paul Maloy37e22162014-05-14 05:39:12 -0400423 kfree_skb(l_ptr->reasm_buf);
424 l_ptr->reasm_buf = NULL;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100425}
426
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900427/**
Jon Paul Maloy581465f2014-01-07 17:02:44 -0500428 * tipc_link_purge_queues - purge all pkt queues associated with link
Per Lidenb97bf3f2006-01-02 19:04:38 +0100429 * @l_ptr: pointer to link
430 */
Jon Paul Maloy581465f2014-01-07 17:02:44 -0500431void tipc_link_purge_queues(struct tipc_link *l_ptr)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100432{
Ying Xuebc6fecd2014-11-26 11:41:53 +0800433 __skb_queue_purge(&l_ptr->deferred_queue);
Ying Xue58dc55f2014-11-26 11:41:52 +0800434 __skb_queue_purge(&l_ptr->outqueue);
Per Liden4323add2006-01-18 00:38:21 +0100435 tipc_link_reset_fragments(l_ptr);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100436}
437
Paul Gortmakera18c4bc2011-12-29 20:58:42 -0500438void tipc_link_reset(struct tipc_link *l_ptr)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100439{
Per Lidenb97bf3f2006-01-02 19:04:38 +0100440 u32 prev_state = l_ptr->state;
441 u32 checkpoint = l_ptr->next_in_no;
Allan Stephens5392d642006-06-25 23:52:50 -0700442 int was_active_link = tipc_link_is_active(l_ptr);
Jon Paul Maloy50100a52014-08-22 18:09:07 -0400443 struct tipc_node *owner = l_ptr->owner;
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900444
Allan Stephensa686e682008-06-04 17:29:39 -0700445 msg_set_session(l_ptr->pmsg, ((msg_session(l_ptr->pmsg) + 1) & 0xffff));
Per Lidenb97bf3f2006-01-02 19:04:38 +0100446
Allan Stephensa686e682008-06-04 17:29:39 -0700447 /* Link is down, accept any session */
448 l_ptr->peer_session = INVALID_SESSION;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100449
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900450 /* Prepare for max packet size negotiation */
Per Lidenb97bf3f2006-01-02 19:04:38 +0100451 link_init_max_pkt(l_ptr);
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900452
Per Lidenb97bf3f2006-01-02 19:04:38 +0100453 l_ptr->state = RESET_UNKNOWN;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100454
455 if ((prev_state == RESET_UNKNOWN) || (prev_state == RESET_RESET))
456 return;
457
Per Liden4323add2006-01-18 00:38:21 +0100458 tipc_node_link_down(l_ptr->owner, l_ptr);
Ying Xue7f9f95d2015-01-09 15:27:06 +0800459 tipc_bearer_remove_dest(owner->net, l_ptr->bearer_id, l_ptr->addr);
Paul Gortmaker7368ddf2010-10-12 14:25:58 +0000460
Jon Paul Maloyb9d4c332014-01-07 17:02:42 -0500461 if (was_active_link && tipc_node_active_links(l_ptr->owner)) {
Per Lidenb97bf3f2006-01-02 19:04:38 +0100462 l_ptr->reset_checkpoint = checkpoint;
463 l_ptr->exp_msg_count = START_CHANGEOVER;
464 }
465
466 /* Clean up all queues: */
Ying Xue58dc55f2014-11-26 11:41:52 +0800467 __skb_queue_purge(&l_ptr->outqueue);
Ying Xuebc6fecd2014-11-26 11:41:53 +0800468 __skb_queue_purge(&l_ptr->deferred_queue);
Jon Paul Maloy50100a52014-08-22 18:09:07 -0400469 if (!skb_queue_empty(&l_ptr->waiting_sks)) {
470 skb_queue_splice_init(&l_ptr->waiting_sks, &owner->waiting_sks);
471 owner->action_flags |= TIPC_WAKEUP_USERS;
472 }
Per Lidenb97bf3f2006-01-02 19:04:38 +0100473 l_ptr->next_out = NULL;
474 l_ptr->unacked_window = 0;
475 l_ptr->checkpoint = 1;
476 l_ptr->next_out_no = 1;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100477 l_ptr->fsm_msg_cnt = 0;
478 l_ptr->stale_count = 0;
479 link_reset_statistics(l_ptr);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100480}
481
Ying Xuef2f98002015-01-09 15:27:05 +0800482void tipc_link_reset_list(struct net *net, unsigned int bearer_id)
Ying Xuee0ca2c32014-02-13 17:29:06 -0500483{
Ying Xuef2f98002015-01-09 15:27:05 +0800484 struct tipc_net *tn = net_generic(net, tipc_net_id);
Ying Xuee0ca2c32014-02-13 17:29:06 -0500485 struct tipc_link *l_ptr;
Ying Xuec61dd612014-02-13 17:29:09 -0500486 struct tipc_node *n_ptr;
Ying Xuee0ca2c32014-02-13 17:29:06 -0500487
Ying Xue6c7a7622014-03-27 12:54:37 +0800488 rcu_read_lock();
Ying Xuef2f98002015-01-09 15:27:05 +0800489 list_for_each_entry_rcu(n_ptr, &tn->node_list, list) {
Ying Xue5356f3d2014-05-05 08:56:09 +0800490 tipc_node_lock(n_ptr);
Ying Xuec61dd612014-02-13 17:29:09 -0500491 l_ptr = n_ptr->links[bearer_id];
492 if (l_ptr)
493 tipc_link_reset(l_ptr);
Ying Xue5356f3d2014-05-05 08:56:09 +0800494 tipc_node_unlock(n_ptr);
Ying Xuee0ca2c32014-02-13 17:29:06 -0500495 }
Ying Xue6c7a7622014-03-27 12:54:37 +0800496 rcu_read_unlock();
Ying Xuee0ca2c32014-02-13 17:29:06 -0500497}
Per Lidenb97bf3f2006-01-02 19:04:38 +0100498
Ying Xue7f9f95d2015-01-09 15:27:06 +0800499static void link_activate(struct tipc_link *link)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100500{
Ying Xue7f9f95d2015-01-09 15:27:06 +0800501 struct tipc_node *node = link->owner;
502
503 link->next_in_no = 1;
504 link->stats.recv_info = 1;
505 tipc_node_link_up(node, link);
506 tipc_bearer_add_dest(node->net, link->bearer_id, link->addr);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100507}
508
509/**
510 * link_state_event - link finite state machine
511 * @l_ptr: pointer to link
512 * @event: state machine event to process
513 */
Eric Dumazet95c96172012-04-15 05:58:06 +0000514static void link_state_event(struct tipc_link *l_ptr, unsigned int event)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100515{
Paul Gortmakera18c4bc2011-12-29 20:58:42 -0500516 struct tipc_link *other;
Ying Xue2f55c432015-01-09 15:27:00 +0800517 unsigned long cont_intv = l_ptr->cont_intv;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100518
Jon Paul Maloy7d339392014-02-13 17:29:16 -0500519 if (l_ptr->flags & LINK_STOPPED)
520 return;
521
Ying Xue135daee2014-02-13 17:29:08 -0500522 if (!(l_ptr->flags & LINK_STARTED) && (event != STARTING_EVT))
Per Lidenb97bf3f2006-01-02 19:04:38 +0100523 return; /* Not yet. */
524
Ying Xue77a7e072013-12-10 20:45:44 -0800525 /* Check whether changeover is going on */
526 if (l_ptr->exp_msg_count) {
Allan Stephensa0168922010-12-31 18:59:35 +0000527 if (event == TIMEOUT_EVT)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100528 link_set_timer(l_ptr, cont_intv);
Ying Xue77a7e072013-12-10 20:45:44 -0800529 return;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100530 }
Per Lidenb97bf3f2006-01-02 19:04:38 +0100531
532 switch (l_ptr->state) {
533 case WORKING_WORKING:
Per Lidenb97bf3f2006-01-02 19:04:38 +0100534 switch (event) {
535 case TRAFFIC_MSG_EVT:
Per Lidenb97bf3f2006-01-02 19:04:38 +0100536 case ACTIVATE_MSG:
Per Lidenb97bf3f2006-01-02 19:04:38 +0100537 break;
538 case TIMEOUT_EVT:
Per Lidenb97bf3f2006-01-02 19:04:38 +0100539 if (l_ptr->next_in_no != l_ptr->checkpoint) {
540 l_ptr->checkpoint = l_ptr->next_in_no;
Per Liden4323add2006-01-18 00:38:21 +0100541 if (tipc_bclink_acks_missing(l_ptr->owner)) {
Ying Xue247f0f32014-02-18 16:06:46 +0800542 tipc_link_proto_xmit(l_ptr, STATE_MSG,
543 0, 0, 0, 0, 0);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100544 l_ptr->fsm_msg_cnt++;
545 } else if (l_ptr->max_pkt < l_ptr->max_pkt_target) {
Ying Xue247f0f32014-02-18 16:06:46 +0800546 tipc_link_proto_xmit(l_ptr, STATE_MSG,
547 1, 0, 0, 0, 0);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100548 l_ptr->fsm_msg_cnt++;
549 }
550 link_set_timer(l_ptr, cont_intv);
551 break;
552 }
Per Lidenb97bf3f2006-01-02 19:04:38 +0100553 l_ptr->state = WORKING_UNKNOWN;
554 l_ptr->fsm_msg_cnt = 0;
Ying Xue247f0f32014-02-18 16:06:46 +0800555 tipc_link_proto_xmit(l_ptr, STATE_MSG, 1, 0, 0, 0, 0);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100556 l_ptr->fsm_msg_cnt++;
557 link_set_timer(l_ptr, cont_intv / 4);
558 break;
559 case RESET_MSG:
Erik Hugne3fa9cac2015-01-22 17:10:31 +0100560 pr_debug("%s<%s>, requested by peer\n",
561 link_rst_msg, l_ptr->name);
Per Liden4323add2006-01-18 00:38:21 +0100562 tipc_link_reset(l_ptr);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100563 l_ptr->state = RESET_RESET;
564 l_ptr->fsm_msg_cnt = 0;
Ying Xue247f0f32014-02-18 16:06:46 +0800565 tipc_link_proto_xmit(l_ptr, ACTIVATE_MSG,
566 0, 0, 0, 0, 0);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100567 l_ptr->fsm_msg_cnt++;
568 link_set_timer(l_ptr, cont_intv);
569 break;
570 default:
Erik Hugne3fa9cac2015-01-22 17:10:31 +0100571 pr_debug("%s%u in WW state\n", link_unk_evt, event);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100572 }
573 break;
574 case WORKING_UNKNOWN:
Per Lidenb97bf3f2006-01-02 19:04:38 +0100575 switch (event) {
576 case TRAFFIC_MSG_EVT:
Per Lidenb97bf3f2006-01-02 19:04:38 +0100577 case ACTIVATE_MSG:
Per Lidenb97bf3f2006-01-02 19:04:38 +0100578 l_ptr->state = WORKING_WORKING;
579 l_ptr->fsm_msg_cnt = 0;
580 link_set_timer(l_ptr, cont_intv);
581 break;
582 case RESET_MSG:
Erik Hugne3fa9cac2015-01-22 17:10:31 +0100583 pr_debug("%s<%s>, requested by peer while probing\n",
584 link_rst_msg, l_ptr->name);
Per Liden4323add2006-01-18 00:38:21 +0100585 tipc_link_reset(l_ptr);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100586 l_ptr->state = RESET_RESET;
587 l_ptr->fsm_msg_cnt = 0;
Ying Xue247f0f32014-02-18 16:06:46 +0800588 tipc_link_proto_xmit(l_ptr, ACTIVATE_MSG,
589 0, 0, 0, 0, 0);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100590 l_ptr->fsm_msg_cnt++;
591 link_set_timer(l_ptr, cont_intv);
592 break;
593 case TIMEOUT_EVT:
Per Lidenb97bf3f2006-01-02 19:04:38 +0100594 if (l_ptr->next_in_no != l_ptr->checkpoint) {
Per Lidenb97bf3f2006-01-02 19:04:38 +0100595 l_ptr->state = WORKING_WORKING;
596 l_ptr->fsm_msg_cnt = 0;
597 l_ptr->checkpoint = l_ptr->next_in_no;
Per Liden4323add2006-01-18 00:38:21 +0100598 if (tipc_bclink_acks_missing(l_ptr->owner)) {
Ying Xue247f0f32014-02-18 16:06:46 +0800599 tipc_link_proto_xmit(l_ptr, STATE_MSG,
600 0, 0, 0, 0, 0);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100601 l_ptr->fsm_msg_cnt++;
602 }
603 link_set_timer(l_ptr, cont_intv);
604 } else if (l_ptr->fsm_msg_cnt < l_ptr->abort_limit) {
Ying Xue247f0f32014-02-18 16:06:46 +0800605 tipc_link_proto_xmit(l_ptr, STATE_MSG,
606 1, 0, 0, 0, 0);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100607 l_ptr->fsm_msg_cnt++;
608 link_set_timer(l_ptr, cont_intv / 4);
609 } else { /* Link has failed */
Erik Hugne3fa9cac2015-01-22 17:10:31 +0100610 pr_debug("%s<%s>, peer not responding\n",
611 link_rst_msg, l_ptr->name);
Per Liden4323add2006-01-18 00:38:21 +0100612 tipc_link_reset(l_ptr);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100613 l_ptr->state = RESET_UNKNOWN;
614 l_ptr->fsm_msg_cnt = 0;
Ying Xue247f0f32014-02-18 16:06:46 +0800615 tipc_link_proto_xmit(l_ptr, RESET_MSG,
616 0, 0, 0, 0, 0);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100617 l_ptr->fsm_msg_cnt++;
618 link_set_timer(l_ptr, cont_intv);
619 }
620 break;
621 default:
Erik Hugne2cf8aa12012-06-29 00:16:37 -0400622 pr_err("%s%u in WU state\n", link_unk_evt, event);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100623 }
624 break;
625 case RESET_UNKNOWN:
Per Lidenb97bf3f2006-01-02 19:04:38 +0100626 switch (event) {
627 case TRAFFIC_MSG_EVT:
Per Lidenb97bf3f2006-01-02 19:04:38 +0100628 break;
629 case ACTIVATE_MSG:
630 other = l_ptr->owner->active_links[0];
Allan Stephens8d64a5b2010-12-31 18:59:27 +0000631 if (other && link_working_unknown(other))
Per Lidenb97bf3f2006-01-02 19:04:38 +0100632 break;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100633 l_ptr->state = WORKING_WORKING;
634 l_ptr->fsm_msg_cnt = 0;
635 link_activate(l_ptr);
Ying Xue247f0f32014-02-18 16:06:46 +0800636 tipc_link_proto_xmit(l_ptr, STATE_MSG, 1, 0, 0, 0, 0);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100637 l_ptr->fsm_msg_cnt++;
Jon Maloyc64f7a62012-11-16 13:51:31 +0800638 if (l_ptr->owner->working_links == 1)
Ying Xue247f0f32014-02-18 16:06:46 +0800639 tipc_link_sync_xmit(l_ptr);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100640 link_set_timer(l_ptr, cont_intv);
641 break;
642 case RESET_MSG:
Per Lidenb97bf3f2006-01-02 19:04:38 +0100643 l_ptr->state = RESET_RESET;
644 l_ptr->fsm_msg_cnt = 0;
Ying Xue247f0f32014-02-18 16:06:46 +0800645 tipc_link_proto_xmit(l_ptr, ACTIVATE_MSG,
646 1, 0, 0, 0, 0);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100647 l_ptr->fsm_msg_cnt++;
648 link_set_timer(l_ptr, cont_intv);
649 break;
650 case STARTING_EVT:
Ying Xue135daee2014-02-13 17:29:08 -0500651 l_ptr->flags |= LINK_STARTED;
Jon Paul Maloyaf9946f2015-02-03 08:59:20 -0500652 l_ptr->fsm_msg_cnt++;
653 link_set_timer(l_ptr, cont_intv);
654 break;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100655 case TIMEOUT_EVT:
Ying Xue247f0f32014-02-18 16:06:46 +0800656 tipc_link_proto_xmit(l_ptr, RESET_MSG, 0, 0, 0, 0, 0);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100657 l_ptr->fsm_msg_cnt++;
658 link_set_timer(l_ptr, cont_intv);
659 break;
660 default:
Erik Hugne2cf8aa12012-06-29 00:16:37 -0400661 pr_err("%s%u in RU state\n", link_unk_evt, event);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100662 }
663 break;
664 case RESET_RESET:
Per Lidenb97bf3f2006-01-02 19:04:38 +0100665 switch (event) {
666 case TRAFFIC_MSG_EVT:
Per Lidenb97bf3f2006-01-02 19:04:38 +0100667 case ACTIVATE_MSG:
668 other = l_ptr->owner->active_links[0];
Allan Stephens8d64a5b2010-12-31 18:59:27 +0000669 if (other && link_working_unknown(other))
Per Lidenb97bf3f2006-01-02 19:04:38 +0100670 break;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100671 l_ptr->state = WORKING_WORKING;
672 l_ptr->fsm_msg_cnt = 0;
673 link_activate(l_ptr);
Ying Xue247f0f32014-02-18 16:06:46 +0800674 tipc_link_proto_xmit(l_ptr, STATE_MSG, 1, 0, 0, 0, 0);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100675 l_ptr->fsm_msg_cnt++;
Jon Maloyc64f7a62012-11-16 13:51:31 +0800676 if (l_ptr->owner->working_links == 1)
Ying Xue247f0f32014-02-18 16:06:46 +0800677 tipc_link_sync_xmit(l_ptr);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100678 link_set_timer(l_ptr, cont_intv);
679 break;
680 case RESET_MSG:
Per Lidenb97bf3f2006-01-02 19:04:38 +0100681 break;
682 case TIMEOUT_EVT:
Ying Xue247f0f32014-02-18 16:06:46 +0800683 tipc_link_proto_xmit(l_ptr, ACTIVATE_MSG,
684 0, 0, 0, 0, 0);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100685 l_ptr->fsm_msg_cnt++;
686 link_set_timer(l_ptr, cont_intv);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100687 break;
688 default:
Erik Hugne2cf8aa12012-06-29 00:16:37 -0400689 pr_err("%s%u in RR state\n", link_unk_evt, event);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100690 }
691 break;
692 default:
Erik Hugne2cf8aa12012-06-29 00:16:37 -0400693 pr_err("Unknown link state %u/%u\n", l_ptr->state, event);
Per Lidenb97bf3f2006-01-02 19:04:38 +0100694 }
695}
696
Jon Paul Maloy4f1688b2014-06-25 20:41:32 -0500697/* tipc_link_cong: determine return value and how to treat the
698 * sent buffer during link congestion.
699 * - For plain, errorless user data messages we keep the buffer and
700 * return -ELINKONG.
701 * - For all other messages we discard the buffer and return -EHOSTUNREACH
702 * - For TIPC internal messages we also reset the link
703 */
Ying Xuea6ca1092014-11-26 11:41:55 +0800704static int tipc_link_cong(struct tipc_link *link, struct sk_buff_head *list)
Jon Paul Maloy4f1688b2014-06-25 20:41:32 -0500705{
Ying Xuea6ca1092014-11-26 11:41:55 +0800706 struct sk_buff *skb = skb_peek(list);
707 struct tipc_msg *msg = buf_msg(skb);
Jon Paul Maloy4f1688b2014-06-25 20:41:32 -0500708 uint imp = tipc_msg_tot_importance(msg);
709 u32 oport = msg_tot_origport(msg);
710
Jon Paul Maloy50100a52014-08-22 18:09:07 -0400711 if (unlikely(imp > TIPC_CRITICAL_IMPORTANCE)) {
Jon Paul Maloy4f1688b2014-06-25 20:41:32 -0500712 pr_warn("%s<%s>, send queue full", link_rst_msg, link->name);
713 tipc_link_reset(link);
Jon Paul Maloy50100a52014-08-22 18:09:07 -0400714 goto drop;
Jon Paul Maloy4f1688b2014-06-25 20:41:32 -0500715 }
Jon Paul Maloy50100a52014-08-22 18:09:07 -0400716 if (unlikely(msg_errcode(msg)))
717 goto drop;
718 if (unlikely(msg_reroute_cnt(msg)))
719 goto drop;
Ying Xuea6ca1092014-11-26 11:41:55 +0800720 if (TIPC_SKB_CB(skb)->wakeup_pending)
Jon Paul Maloy50100a52014-08-22 18:09:07 -0400721 return -ELINKCONG;
Ying Xuea6ca1092014-11-26 11:41:55 +0800722 if (link_schedule_user(link, oport, skb_queue_len(list), imp))
Jon Paul Maloy50100a52014-08-22 18:09:07 -0400723 return -ELINKCONG;
724drop:
Ying Xuea6ca1092014-11-26 11:41:55 +0800725 __skb_queue_purge(list);
Jon Paul Maloy4f1688b2014-06-25 20:41:32 -0500726 return -EHOSTUNREACH;
727}
728
729/**
Jon Paul Maloy9fbfb8b2014-07-16 20:41:03 -0400730 * __tipc_link_xmit(): same as tipc_link_xmit, but destlink is known & locked
Jon Paul Maloy4f1688b2014-06-25 20:41:32 -0500731 * @link: link to use
Ying Xuea6ca1092014-11-26 11:41:55 +0800732 * @list: chain of buffers containing message
733 *
Jon Paul Maloy4f1688b2014-06-25 20:41:32 -0500734 * Consumes the buffer chain, except when returning -ELINKCONG
735 * Returns 0 if success, otherwise errno: -ELINKCONG, -EMSGSIZE (plain socket
736 * user data messages) or -EHOSTUNREACH (all other messages/senders)
737 * Only the socket functions tipc_send_stream() and tipc_send_packet() need
738 * to act on the return value, since they may need to do more send attempts.
739 */
Ying Xue7f9f95d2015-01-09 15:27:06 +0800740int __tipc_link_xmit(struct net *net, struct tipc_link *link,
741 struct sk_buff_head *list)
Jon Paul Maloy4f1688b2014-06-25 20:41:32 -0500742{
Ying Xuea6ca1092014-11-26 11:41:55 +0800743 struct tipc_msg *msg = buf_msg(skb_peek(list));
Jon Paul Maloy4f1688b2014-06-25 20:41:32 -0500744 uint psz = msg_size(msg);
Jon Paul Maloy4f1688b2014-06-25 20:41:32 -0500745 uint sndlim = link->queue_limit[0];
746 uint imp = tipc_msg_tot_importance(msg);
747 uint mtu = link->max_pkt;
748 uint ack = mod(link->next_in_no - 1);
749 uint seqno = link->next_out_no;
750 uint bc_last_in = link->owner->bclink.last_in;
751 struct tipc_media_addr *addr = &link->media_addr;
Ying Xue58dc55f2014-11-26 11:41:52 +0800752 struct sk_buff_head *outqueue = &link->outqueue;
Ying Xuea6ca1092014-11-26 11:41:55 +0800753 struct sk_buff *skb, *tmp;
Jon Paul Maloy4f1688b2014-06-25 20:41:32 -0500754
755 /* Match queue limits against msg importance: */
Ying Xue58dc55f2014-11-26 11:41:52 +0800756 if (unlikely(skb_queue_len(outqueue) >= link->queue_limit[imp]))
Ying Xuea6ca1092014-11-26 11:41:55 +0800757 return tipc_link_cong(link, list);
Jon Paul Maloy4f1688b2014-06-25 20:41:32 -0500758
759 /* Has valid packet limit been used ? */
760 if (unlikely(psz > mtu)) {
Ying Xuea6ca1092014-11-26 11:41:55 +0800761 __skb_queue_purge(list);
Jon Paul Maloy4f1688b2014-06-25 20:41:32 -0500762 return -EMSGSIZE;
763 }
764
765 /* Prepare each packet for sending, and add to outqueue: */
Ying Xuea6ca1092014-11-26 11:41:55 +0800766 skb_queue_walk_safe(list, skb, tmp) {
767 __skb_unlink(skb, list);
Ying Xue58dc55f2014-11-26 11:41:52 +0800768 msg = buf_msg(skb);
Jon Paul Maloy4f1688b2014-06-25 20:41:32 -0500769 msg_set_word(msg, 2, ((ack << 16) | mod(seqno)));
770 msg_set_bcast_ack(msg, bc_last_in);
771
Ying Xue58dc55f2014-11-26 11:41:52 +0800772 if (skb_queue_len(outqueue) < sndlim) {
773 __skb_queue_tail(outqueue, skb);
Ying Xue7f9f95d2015-01-09 15:27:06 +0800774 tipc_bearer_send(net, link->bearer_id,
775 skb, addr);
Ying Xue58dc55f2014-11-26 11:41:52 +0800776 link->next_out = NULL;
777 link->unacked_window = 0;
778 } else if (tipc_msg_bundle(outqueue, skb, mtu)) {
Jon Paul Maloy4f1688b2014-06-25 20:41:32 -0500779 link->stats.sent_bundled++;
Jon Paul Maloy4f1688b2014-06-25 20:41:32 -0500780 continue;
Ying Xue34747532015-01-09 15:27:10 +0800781 } else if (tipc_msg_make_bundle(net, outqueue, skb, mtu,
Ying Xue58dc55f2014-11-26 11:41:52 +0800782 link->addr)) {
Jon Paul Maloy4f1688b2014-06-25 20:41:32 -0500783 link->stats.sent_bundled++;
784 link->stats.sent_bundles++;
Jon Paul Maloy4f1688b2014-06-25 20:41:32 -0500785 if (!link->next_out)
Ying Xue58dc55f2014-11-26 11:41:52 +0800786 link->next_out = skb_peek_tail(outqueue);
Jon Paul Maloy4f1688b2014-06-25 20:41:32 -0500787 } else {
Ying Xue58dc55f2014-11-26 11:41:52 +0800788 __skb_queue_tail(outqueue, skb);
Jon Paul Maloy4f1688b2014-06-25 20:41:32 -0500789 if (!link->next_out)
Ying Xue58dc55f2014-11-26 11:41:52 +0800790 link->next_out = skb;
Jon Paul Maloy4f1688b2014-06-25 20:41:32 -0500791 }
792 seqno++;
Jon Paul Maloy4f1688b2014-06-25 20:41:32 -0500793 }
794 link->next_out_no = seqno;
Jon Paul Maloy4f1688b2014-06-25 20:41:32 -0500795 return 0;
796}
797
Ying Xuea6ca1092014-11-26 11:41:55 +0800798static void skb2list(struct sk_buff *skb, struct sk_buff_head *list)
799{
800 __skb_queue_head_init(list);
801 __skb_queue_tail(list, skb);
802}
803
804static int __tipc_link_xmit_skb(struct tipc_link *link, struct sk_buff *skb)
805{
806 struct sk_buff_head head;
807
808 skb2list(skb, &head);
Ying Xue7f9f95d2015-01-09 15:27:06 +0800809 return __tipc_link_xmit(link->owner->net, link, &head);
Ying Xuea6ca1092014-11-26 11:41:55 +0800810}
811
Ying Xuef2f98002015-01-09 15:27:05 +0800812int tipc_link_xmit_skb(struct net *net, struct sk_buff *skb, u32 dnode,
813 u32 selector)
Ying Xuea6ca1092014-11-26 11:41:55 +0800814{
815 struct sk_buff_head head;
816
817 skb2list(skb, &head);
Ying Xuef2f98002015-01-09 15:27:05 +0800818 return tipc_link_xmit(net, &head, dnode, selector);
Ying Xuea6ca1092014-11-26 11:41:55 +0800819}
820
Jon Paul Maloy4f1688b2014-06-25 20:41:32 -0500821/**
Jon Paul Maloy9fbfb8b2014-07-16 20:41:03 -0400822 * tipc_link_xmit() is the general link level function for message sending
Ying Xuef2f98002015-01-09 15:27:05 +0800823 * @net: the applicable net namespace
Ying Xuea6ca1092014-11-26 11:41:55 +0800824 * @list: chain of buffers containing message
Jon Paul Maloy4f1688b2014-06-25 20:41:32 -0500825 * @dsz: amount of user data to be sent
826 * @dnode: address of destination node
827 * @selector: a number used for deterministic link selection
828 * Consumes the buffer chain, except when returning -ELINKCONG
829 * Returns 0 if success, otherwise errno: -ELINKCONG,-EHOSTUNREACH,-EMSGSIZE
830 */
Ying Xuef2f98002015-01-09 15:27:05 +0800831int tipc_link_xmit(struct net *net, struct sk_buff_head *list, u32 dnode,
832 u32 selector)
Jon Paul Maloy4f1688b2014-06-25 20:41:32 -0500833{
834 struct tipc_link *link = NULL;
835 struct tipc_node *node;
836 int rc = -EHOSTUNREACH;
837
Ying Xuef2f98002015-01-09 15:27:05 +0800838 node = tipc_node_find(net, dnode);
Jon Paul Maloy4f1688b2014-06-25 20:41:32 -0500839 if (node) {
840 tipc_node_lock(node);
841 link = node->active_links[selector & 1];
842 if (link)
Ying Xue7f9f95d2015-01-09 15:27:06 +0800843 rc = __tipc_link_xmit(net, link, list);
Jon Paul Maloy4f1688b2014-06-25 20:41:32 -0500844 tipc_node_unlock(node);
845 }
846
847 if (link)
848 return rc;
849
Ying Xue34747532015-01-09 15:27:10 +0800850 if (likely(in_own_node(net, dnode))) {
Ying Xuea6ca1092014-11-26 11:41:55 +0800851 /* As a node local message chain never contains more than one
852 * buffer, we just need to dequeue one SKB buffer from the
853 * head list.
854 */
Ying Xuef2f98002015-01-09 15:27:05 +0800855 return tipc_sk_rcv(net, __skb_dequeue(list));
Ying Xuea6ca1092014-11-26 11:41:55 +0800856 }
857 __skb_queue_purge(list);
Jon Paul Maloy4f1688b2014-06-25 20:41:32 -0500858
Jon Paul Maloy4f1688b2014-06-25 20:41:32 -0500859 return rc;
860}
861
Jon Maloyc64f7a62012-11-16 13:51:31 +0800862/*
Ying Xue247f0f32014-02-18 16:06:46 +0800863 * tipc_link_sync_xmit - synchronize broadcast link endpoints.
Jon Maloyc64f7a62012-11-16 13:51:31 +0800864 *
865 * Give a newly added peer node the sequence number where it should
866 * start receiving and acking broadcast packets.
867 *
868 * Called with node locked
869 */
Jon Paul Maloy25b660c2014-07-16 20:40:59 -0400870static void tipc_link_sync_xmit(struct tipc_link *link)
Jon Maloyc64f7a62012-11-16 13:51:31 +0800871{
Ying Xuea6ca1092014-11-26 11:41:55 +0800872 struct sk_buff *skb;
Jon Maloyc64f7a62012-11-16 13:51:31 +0800873 struct tipc_msg *msg;
874
Ying Xuea6ca1092014-11-26 11:41:55 +0800875 skb = tipc_buf_acquire(INT_H_SIZE);
876 if (!skb)
Jon Maloyc64f7a62012-11-16 13:51:31 +0800877 return;
878
Ying Xuea6ca1092014-11-26 11:41:55 +0800879 msg = buf_msg(skb);
Ying Xue34747532015-01-09 15:27:10 +0800880 tipc_msg_init(link->owner->net, msg, BCAST_PROTOCOL, STATE_MSG,
881 INT_H_SIZE, link->addr);
Jon Paul Maloy25b660c2014-07-16 20:40:59 -0400882 msg_set_last_bcast(msg, link->owner->bclink.acked);
Ying Xuea6ca1092014-11-26 11:41:55 +0800883 __tipc_link_xmit_skb(link, skb);
Jon Maloyc64f7a62012-11-16 13:51:31 +0800884}
885
886/*
Ying Xue247f0f32014-02-18 16:06:46 +0800887 * tipc_link_sync_rcv - synchronize broadcast link endpoints.
Jon Maloyc64f7a62012-11-16 13:51:31 +0800888 * Receive the sequence number where we should start receiving and
889 * acking broadcast packets from a newly added peer node, and open
890 * up for reception of such packets.
891 *
892 * Called with node locked
893 */
Ying Xue247f0f32014-02-18 16:06:46 +0800894static void tipc_link_sync_rcv(struct tipc_node *n, struct sk_buff *buf)
Jon Maloyc64f7a62012-11-16 13:51:31 +0800895{
896 struct tipc_msg *msg = buf_msg(buf);
897
898 n->bclink.last_sent = n->bclink.last_in = msg_last_bcast(msg);
899 n->bclink.recv_permitted = true;
900 kfree_skb(buf);
901}
902
Ying Xue58dc55f2014-11-26 11:41:52 +0800903struct sk_buff *tipc_skb_queue_next(const struct sk_buff_head *list,
904 const struct sk_buff *skb)
905{
906 if (skb_queue_is_last(list, skb))
907 return NULL;
908 return skb->next;
909}
910
Jon Maloyc64f7a62012-11-16 13:51:31 +0800911/*
Ying Xue47b4c9a2014-11-26 11:41:48 +0800912 * tipc_link_push_packets - push unsent packets to bearer
913 *
914 * Push out the unsent messages of a link where congestion
915 * has abated. Node is locked.
916 *
917 * Called with node locked
Per Lidenb97bf3f2006-01-02 19:04:38 +0100918 */
Ying Xue47b4c9a2014-11-26 11:41:48 +0800919void tipc_link_push_packets(struct tipc_link *l_ptr)
Per Lidenb97bf3f2006-01-02 19:04:38 +0100920{
Ying Xue58dc55f2014-11-26 11:41:52 +0800921 struct sk_buff_head *outqueue = &l_ptr->outqueue;
922 struct sk_buff *skb = l_ptr->next_out;
Ying Xue47b4c9a2014-11-26 11:41:48 +0800923 struct tipc_msg *msg;
924 u32 next, first;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100925
Ying Xue58dc55f2014-11-26 11:41:52 +0800926 skb_queue_walk_from(outqueue, skb) {
Ying Xue47b4c9a2014-11-26 11:41:48 +0800927 msg = buf_msg(skb);
928 next = msg_seqno(msg);
Ying Xue58dc55f2014-11-26 11:41:52 +0800929 first = buf_seqno(skb_peek(outqueue));
Per Lidenb97bf3f2006-01-02 19:04:38 +0100930
931 if (mod(next - first) < l_ptr->queue_limit[0]) {
932 msg_set_ack(msg, mod(l_ptr->next_in_no - 1));
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +0900933 msg_set_bcast_ack(msg, l_ptr->owner->bclink.last_in);
Ying Xue3c294cb2012-11-15 11:34:45 +0800934 if (msg_user(msg) == MSG_BUNDLER)
Ying Xue58311d12014-11-26 11:41:49 +0800935 TIPC_SKB_CB(skb)->bundling = false;
Ying Xue7f9f95d2015-01-09 15:27:06 +0800936 tipc_bearer_send(l_ptr->owner->net,
937 l_ptr->bearer_id, skb,
Ying Xue47b4c9a2014-11-26 11:41:48 +0800938 &l_ptr->media_addr);
Ying Xue58dc55f2014-11-26 11:41:52 +0800939 l_ptr->next_out = tipc_skb_queue_next(outqueue, skb);
Ying Xue47b4c9a2014-11-26 11:41:48 +0800940 } else {
941 break;
Per Lidenb97bf3f2006-01-02 19:04:38 +0100942 }
943 }
Per Lidenb97bf3f2006-01-02 19:04:38 +0100944}
945
Ying Xue3f5a12b2014-05-05 08:56:17 +0800946void tipc_link_reset_all(struct tipc_node *node)
Allan Stephensd356eeb2006-06-25 23:40:01 -0700947{
Allan Stephensd356eeb2006-06-25 23:40:01 -0700948 char addr_string[16];
949 u32 i;
950
Ying Xue3f5a12b2014-05-05 08:56:17 +0800951 tipc_node_lock(node);
Allan Stephensd356eeb2006-06-25 23:40:01 -0700952
Erik Hugne2cf8aa12012-06-29 00:16:37 -0400953 pr_warn("Resetting all links to %s\n",
Ying Xue3f5a12b2014-05-05 08:56:17 +0800954 tipc_addr_string_fill(addr_string, node->addr));
Allan Stephensd356eeb2006-06-25 23:40:01 -0700955
956 for (i = 0; i < MAX_BEARERS; i++) {
Ying Xue3f5a12b2014-05-05 08:56:17 +0800957 if (node->links[i]) {
958 link_print(node->links[i], "Resetting link\n");
959 tipc_link_reset(node->links[i]);
Allan Stephensd356eeb2006-06-25 23:40:01 -0700960 }
961 }
962
Ying Xue3f5a12b2014-05-05 08:56:17 +0800963 tipc_node_unlock(node);
Allan Stephensd356eeb2006-06-25 23:40:01 -0700964}
965
Paul Gortmakera18c4bc2011-12-29 20:58:42 -0500966static void link_retransmit_failure(struct tipc_link *l_ptr,
Paul Gortmakerae8509c2013-06-17 10:54:47 -0400967 struct sk_buff *buf)
Allan Stephensd356eeb2006-06-25 23:40:01 -0700968{
969 struct tipc_msg *msg = buf_msg(buf);
Ying Xue1da46562015-01-09 15:27:07 +0800970 struct net *net = l_ptr->owner->net;
Allan Stephensd356eeb2006-06-25 23:40:01 -0700971
Erik Hugne2cf8aa12012-06-29 00:16:37 -0400972 pr_warn("Retransmission failure on link <%s>\n", l_ptr->name);
Allan Stephensd356eeb2006-06-25 23:40:01 -0700973
974 if (l_ptr->addr) {
Allan Stephensd356eeb2006-06-25 23:40:01 -0700975 /* Handle failure on standard link */
Allan Stephens8d64a5b2010-12-31 18:59:27 +0000976 link_print(l_ptr, "Resetting link\n");
Allan Stephensd356eeb2006-06-25 23:40:01 -0700977 tipc_link_reset(l_ptr);
978
979 } else {
Allan Stephensd356eeb2006-06-25 23:40:01 -0700980 /* Handle failure on broadcast link */
David S. Miller6c000552008-09-02 23:38:32 -0700981 struct tipc_node *n_ptr;
Allan Stephensd356eeb2006-06-25 23:40:01 -0700982 char addr_string[16];
983
Erik Hugne2cf8aa12012-06-29 00:16:37 -0400984 pr_info("Msg seq number: %u, ", msg_seqno(msg));
985 pr_cont("Outstanding acks: %lu\n",
986 (unsigned long) TIPC_SKB_CB(buf)->handle);
Jeff Garzik617dbea2006-10-03 16:25:34 -0700987
Ying Xue1da46562015-01-09 15:27:07 +0800988 n_ptr = tipc_bclink_retransmit_to(net);
Allan Stephensd356eeb2006-06-25 23:40:01 -0700989 tipc_node_lock(n_ptr);
990
Allan Stephensc68ca7b2010-05-11 14:30:12 +0000991 tipc_addr_string_fill(addr_string, n_ptr->addr);
Erik Hugne2cf8aa12012-06-29 00:16:37 -0400992 pr_info("Broadcast link info for %s\n", addr_string);
Ying Xue389dd9b2012-11-16 13:51:30 +0800993 pr_info("Reception permitted: %d, Acked: %u\n",
994 n_ptr->bclink.recv_permitted,
Erik Hugne2cf8aa12012-06-29 00:16:37 -0400995 n_ptr->bclink.acked);
996 pr_info("Last in: %u, Oos state: %u, Last sent: %u\n",
997 n_ptr->bclink.last_in,
998 n_ptr->bclink.oos_state,
999 n_ptr->bclink.last_sent);
Allan Stephensd356eeb2006-06-25 23:40:01 -07001000
Allan Stephensd356eeb2006-06-25 23:40:01 -07001001 tipc_node_unlock(n_ptr);
1002
Ying Xue1da46562015-01-09 15:27:07 +08001003 tipc_bclink_set_flags(net, TIPC_BCLINK_RESET);
Allan Stephensd356eeb2006-06-25 23:40:01 -07001004 l_ptr->stale_count = 0;
1005 }
1006}
1007
Ying Xue58dc55f2014-11-26 11:41:52 +08001008void tipc_link_retransmit(struct tipc_link *l_ptr, struct sk_buff *skb,
Per Liden4323add2006-01-18 00:38:21 +01001009 u32 retransmits)
Per Lidenb97bf3f2006-01-02 19:04:38 +01001010{
1011 struct tipc_msg *msg;
1012
Ying Xue58dc55f2014-11-26 11:41:52 +08001013 if (!skb)
Allan Stephensd356eeb2006-06-25 23:40:01 -07001014 return;
1015
Ying Xue58dc55f2014-11-26 11:41:52 +08001016 msg = buf_msg(skb);
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001017
Erik Hugne512137e2013-12-06 10:08:00 -05001018 /* Detect repeated retransmit failures */
1019 if (l_ptr->last_retransmitted == msg_seqno(msg)) {
1020 if (++l_ptr->stale_count > 100) {
Ying Xue58dc55f2014-11-26 11:41:52 +08001021 link_retransmit_failure(l_ptr, skb);
Erik Hugne512137e2013-12-06 10:08:00 -05001022 return;
Allan Stephensd356eeb2006-06-25 23:40:01 -07001023 }
1024 } else {
Erik Hugne512137e2013-12-06 10:08:00 -05001025 l_ptr->last_retransmitted = msg_seqno(msg);
1026 l_ptr->stale_count = 1;
Per Lidenb97bf3f2006-01-02 19:04:38 +01001027 }
Allan Stephensd356eeb2006-06-25 23:40:01 -07001028
Ying Xue58dc55f2014-11-26 11:41:52 +08001029 skb_queue_walk_from(&l_ptr->outqueue, skb) {
1030 if (!retransmits || skb == l_ptr->next_out)
1031 break;
1032 msg = buf_msg(skb);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001033 msg_set_ack(msg, mod(l_ptr->next_in_no - 1));
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001034 msg_set_bcast_ack(msg, l_ptr->owner->bclink.last_in);
Ying Xue7f9f95d2015-01-09 15:27:06 +08001035 tipc_bearer_send(l_ptr->owner->net, l_ptr->bearer_id, skb,
1036 &l_ptr->media_addr);
Ying Xue3c294cb2012-11-15 11:34:45 +08001037 retransmits--;
1038 l_ptr->stats.retransmitted++;
Per Lidenb97bf3f2006-01-02 19:04:38 +01001039 }
Per Lidenb97bf3f2006-01-02 19:04:38 +01001040}
1041
Ying Xuef03273f2014-11-26 11:41:54 +08001042static void link_retrieve_defq(struct tipc_link *link,
1043 struct sk_buff_head *list)
Per Lidenb97bf3f2006-01-02 19:04:38 +01001044{
1045 u32 seq_no;
1046
Ying Xuef03273f2014-11-26 11:41:54 +08001047 if (skb_queue_empty(&link->deferred_queue))
1048 return;
Per Lidenb97bf3f2006-01-02 19:04:38 +01001049
Ying Xuef03273f2014-11-26 11:41:54 +08001050 seq_no = buf_seqno(skb_peek(&link->deferred_queue));
1051 if (seq_no == mod(link->next_in_no))
1052 skb_queue_splice_tail_init(&link->deferred_queue, list);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001053}
1054
Allan Stephens85035562008-04-15 19:04:54 -07001055/**
1056 * link_recv_buf_validate - validate basic format of received message
1057 *
1058 * This routine ensures a TIPC message has an acceptable header, and at least
1059 * as much data as the header indicates it should. The routine also ensures
1060 * that the entire message header is stored in the main fragment of the message
1061 * buffer, to simplify future access to message header fields.
1062 *
1063 * Note: Having extra info present in the message header or data areas is OK.
1064 * TIPC will ignore the excess, under the assumption that it is optional info
1065 * introduced by a later release of the protocol.
1066 */
Allan Stephens85035562008-04-15 19:04:54 -07001067static int link_recv_buf_validate(struct sk_buff *buf)
1068{
1069 static u32 min_data_hdr_size[8] = {
Allan Stephens741d9eb2011-05-31 15:03:18 -04001070 SHORT_H_SIZE, MCAST_H_SIZE, NAMED_H_SIZE, BASIC_H_SIZE,
Allan Stephens85035562008-04-15 19:04:54 -07001071 MAX_H_SIZE, MAX_H_SIZE, MAX_H_SIZE, MAX_H_SIZE
1072 };
1073
1074 struct tipc_msg *msg;
1075 u32 tipc_hdr[2];
1076 u32 size;
1077 u32 hdr_size;
1078 u32 min_hdr_size;
1079
Erik Hugne64380a02014-02-11 11:38:26 +01001080 /* If this packet comes from the defer queue, the skb has already
1081 * been validated
1082 */
1083 if (unlikely(TIPC_SKB_CB(buf)->deferred))
1084 return 1;
1085
Allan Stephens85035562008-04-15 19:04:54 -07001086 if (unlikely(buf->len < MIN_H_SIZE))
1087 return 0;
1088
1089 msg = skb_header_pointer(buf, 0, sizeof(tipc_hdr), tipc_hdr);
1090 if (msg == NULL)
1091 return 0;
1092
1093 if (unlikely(msg_version(msg) != TIPC_VERSION))
1094 return 0;
1095
1096 size = msg_size(msg);
1097 hdr_size = msg_hdr_sz(msg);
1098 min_hdr_size = msg_isdata(msg) ?
1099 min_data_hdr_size[msg_type(msg)] : INT_H_SIZE;
1100
1101 if (unlikely((hdr_size < min_hdr_size) ||
1102 (size < hdr_size) ||
1103 (buf->len < size) ||
1104 (size - hdr_size > TIPC_MAX_USER_MSG_SIZE)))
1105 return 0;
1106
1107 return pskb_may_pull(buf, hdr_size);
1108}
1109
Allan Stephensb02b69c2010-08-17 11:00:07 +00001110/**
Jon Paul Maloy170b3922014-01-07 17:02:41 -05001111 * tipc_rcv - process TIPC packets/messages arriving from off-node
Ying Xuef2f98002015-01-09 15:27:05 +08001112 * @net: the applicable net namespace
Ying Xuef03273f2014-11-26 11:41:54 +08001113 * @skb: TIPC packet
Ying Xue7a2f7d12014-04-21 10:55:46 +08001114 * @b_ptr: pointer to bearer message arrived on
Allan Stephensb02b69c2010-08-17 11:00:07 +00001115 *
1116 * Invoked with no locks held. Bearer pointer must point to a valid bearer
1117 * structure (i.e. cannot be NULL), but bearer can be inactive.
1118 */
Ying Xuec93d3ba2015-01-09 15:27:04 +08001119void tipc_rcv(struct net *net, struct sk_buff *skb, struct tipc_bearer *b_ptr)
Per Lidenb97bf3f2006-01-02 19:04:38 +01001120{
Ying Xue34747532015-01-09 15:27:10 +08001121 struct tipc_net *tn = net_generic(net, tipc_net_id);
Ying Xuef03273f2014-11-26 11:41:54 +08001122 struct sk_buff_head head;
1123 struct tipc_node *n_ptr;
1124 struct tipc_link *l_ptr;
1125 struct sk_buff *skb1, *tmp;
1126 struct tipc_msg *msg;
1127 u32 seq_no;
1128 u32 ackd;
1129 u32 released;
Per Lidenb97bf3f2006-01-02 19:04:38 +01001130
Ying Xuea6ca1092014-11-26 11:41:55 +08001131 skb2list(skb, &head);
Allan Stephens85035562008-04-15 19:04:54 -07001132
Ying Xuef03273f2014-11-26 11:41:54 +08001133 while ((skb = __skb_dequeue(&head))) {
Allan Stephens85035562008-04-15 19:04:54 -07001134 /* Ensure message is well-formed */
Ying Xuef03273f2014-11-26 11:41:54 +08001135 if (unlikely(!link_recv_buf_validate(skb)))
Ying Xue3af390e2013-10-30 11:26:57 +08001136 goto discard;
Per Lidenb97bf3f2006-01-02 19:04:38 +01001137
Allan Stephensfe13dda2008-04-15 19:03:23 -07001138 /* Ensure message data is a single contiguous unit */
Ying Xuef03273f2014-11-26 11:41:54 +08001139 if (unlikely(skb_linearize(skb)))
Ying Xue3af390e2013-10-30 11:26:57 +08001140 goto discard;
Allan Stephensfe13dda2008-04-15 19:03:23 -07001141
Allan Stephens85035562008-04-15 19:04:54 -07001142 /* Handle arrival of a non-unicast link message */
Ying Xuef03273f2014-11-26 11:41:54 +08001143 msg = buf_msg(skb);
Allan Stephens85035562008-04-15 19:04:54 -07001144
Per Lidenb97bf3f2006-01-02 19:04:38 +01001145 if (unlikely(msg_non_seq(msg))) {
Allan Stephens1265a022008-06-04 17:32:35 -07001146 if (msg_user(msg) == LINK_CONFIG)
Ying Xuec93d3ba2015-01-09 15:27:04 +08001147 tipc_disc_rcv(net, skb, b_ptr);
Allan Stephens1265a022008-06-04 17:32:35 -07001148 else
Ying Xuec93d3ba2015-01-09 15:27:04 +08001149 tipc_bclink_rcv(net, skb);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001150 continue;
1151 }
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001152
Allan Stephensed33a9c2011-04-05 15:15:04 -04001153 /* Discard unicast link messages destined for another node */
Allan Stephens26008242006-06-25 23:39:31 -07001154 if (unlikely(!msg_short(msg) &&
Ying Xue34747532015-01-09 15:27:10 +08001155 (msg_destnode(msg) != tn->own_addr)))
Ying Xue3af390e2013-10-30 11:26:57 +08001156 goto discard;
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001157
Allan Stephens5a68d5e2010-08-17 11:00:16 +00001158 /* Locate neighboring node that sent message */
Ying Xuef2f98002015-01-09 15:27:05 +08001159 n_ptr = tipc_node_find(net, msg_prevnode(msg));
Per Lidenb97bf3f2006-01-02 19:04:38 +01001160 if (unlikely(!n_ptr))
Ying Xue3af390e2013-10-30 11:26:57 +08001161 goto discard;
Per Liden4323add2006-01-18 00:38:21 +01001162 tipc_node_lock(n_ptr);
Allan Stephens85035562008-04-15 19:04:54 -07001163
Allan Stephens5a68d5e2010-08-17 11:00:16 +00001164 /* Locate unicast link endpoint that should handle message */
Per Lidenb97bf3f2006-01-02 19:04:38 +01001165 l_ptr = n_ptr->links[b_ptr->identity];
Ying Xue3af390e2013-10-30 11:26:57 +08001166 if (unlikely(!l_ptr))
1167 goto unlock_discard;
Allan Stephens85035562008-04-15 19:04:54 -07001168
Allan Stephensb4b56102011-05-27 11:00:51 -04001169 /* Verify that communication with node is currently allowed */
Ying Xueaecb9bb2014-05-08 08:54:39 +08001170 if ((n_ptr->action_flags & TIPC_WAIT_PEER_LINKS_DOWN) &&
Ying Xue10f465c2014-05-05 08:56:11 +08001171 msg_user(msg) == LINK_PROTOCOL &&
1172 (msg_type(msg) == RESET_MSG ||
1173 msg_type(msg) == ACTIVATE_MSG) &&
1174 !msg_redundant_link(msg))
Ying Xueaecb9bb2014-05-08 08:54:39 +08001175 n_ptr->action_flags &= ~TIPC_WAIT_PEER_LINKS_DOWN;
Allan Stephensb4b56102011-05-27 11:00:51 -04001176
Ying Xue10f465c2014-05-05 08:56:11 +08001177 if (tipc_node_blocked(n_ptr))
Ying Xue3af390e2013-10-30 11:26:57 +08001178 goto unlock_discard;
Allan Stephensb4b56102011-05-27 11:00:51 -04001179
Allan Stephens85035562008-04-15 19:04:54 -07001180 /* Validate message sequence number info */
Allan Stephens85035562008-04-15 19:04:54 -07001181 seq_no = msg_seqno(msg);
1182 ackd = msg_ack(msg);
1183
1184 /* Release acked messages */
Ying Xue389dd9b2012-11-16 13:51:30 +08001185 if (n_ptr->bclink.recv_permitted)
Allan Stephens365595912011-10-24 15:26:24 -04001186 tipc_bclink_acknowledge(n_ptr, msg_bcast_ack(msg));
Per Lidenb97bf3f2006-01-02 19:04:38 +01001187
Ying Xue58dc55f2014-11-26 11:41:52 +08001188 released = 0;
1189 skb_queue_walk_safe(&l_ptr->outqueue, skb1, tmp) {
1190 if (skb1 == l_ptr->next_out ||
1191 more(buf_seqno(skb1), ackd))
1192 break;
1193 __skb_unlink(skb1, &l_ptr->outqueue);
1194 kfree_skb(skb1);
1195 released = 1;
Per Lidenb97bf3f2006-01-02 19:04:38 +01001196 }
Allan Stephens85035562008-04-15 19:04:54 -07001197
1198 /* Try sending any messages link endpoint has pending */
Per Lidenb97bf3f2006-01-02 19:04:38 +01001199 if (unlikely(l_ptr->next_out))
Ying Xue47b4c9a2014-11-26 11:41:48 +08001200 tipc_link_push_packets(l_ptr);
Jon Paul Maloya5377832014-02-13 17:29:15 -05001201
Jon Paul Maloy50100a52014-08-22 18:09:07 -04001202 if (released && !skb_queue_empty(&l_ptr->waiting_sks)) {
1203 link_prepare_wakeup(l_ptr);
1204 l_ptr->owner->action_flags |= TIPC_WAKEUP_USERS;
1205 }
Jon Paul Maloya5377832014-02-13 17:29:15 -05001206
Jon Paul Maloya5377832014-02-13 17:29:15 -05001207 /* Process the incoming packet */
Ying Xue3af390e2013-10-30 11:26:57 +08001208 if (unlikely(!link_working_working(l_ptr))) {
1209 if (msg_user(msg) == LINK_PROTOCOL) {
Ying Xuec93d3ba2015-01-09 15:27:04 +08001210 tipc_link_proto_rcv(net, l_ptr, skb);
Ying Xuef03273f2014-11-26 11:41:54 +08001211 link_retrieve_defq(l_ptr, &head);
Per Liden4323add2006-01-18 00:38:21 +01001212 tipc_node_unlock(n_ptr);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001213 continue;
1214 }
Ying Xue3af390e2013-10-30 11:26:57 +08001215
1216 /* Traffic message. Conditionally activate link */
1217 link_state_event(l_ptr, TRAFFIC_MSG_EVT);
1218
1219 if (link_working_working(l_ptr)) {
1220 /* Re-insert buffer in front of queue */
Ying Xuef03273f2014-11-26 11:41:54 +08001221 __skb_queue_head(&head, skb);
Ying Xue3af390e2013-10-30 11:26:57 +08001222 tipc_node_unlock(n_ptr);
1223 continue;
1224 }
1225 goto unlock_discard;
1226 }
1227
1228 /* Link is now in state WORKING_WORKING */
1229 if (unlikely(seq_no != mod(l_ptr->next_in_no))) {
Ying Xuec93d3ba2015-01-09 15:27:04 +08001230 link_handle_out_of_seq_msg(net, l_ptr, skb);
Ying Xuef03273f2014-11-26 11:41:54 +08001231 link_retrieve_defq(l_ptr, &head);
Per Liden4323add2006-01-18 00:38:21 +01001232 tipc_node_unlock(n_ptr);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001233 continue;
1234 }
Ying Xue3af390e2013-10-30 11:26:57 +08001235 l_ptr->next_in_no++;
Ying Xuebc6fecd2014-11-26 11:41:53 +08001236 if (unlikely(!skb_queue_empty(&l_ptr->deferred_queue)))
Ying Xuef03273f2014-11-26 11:41:54 +08001237 link_retrieve_defq(l_ptr, &head);
Jon Paul Maloya5377832014-02-13 17:29:15 -05001238
Erik Hugne3f53bd82014-07-01 10:22:41 +02001239 if (unlikely(++l_ptr->unacked_window >= TIPC_MIN_LINK_WIN)) {
1240 l_ptr->stats.sent_acks++;
1241 tipc_link_proto_xmit(l_ptr, STATE_MSG, 0, 0, 0, 0, 0);
1242 }
1243
Ying Xuec93d3ba2015-01-09 15:27:04 +08001244 if (tipc_link_prepare_input(net, l_ptr, &skb)) {
Per Liden4323add2006-01-18 00:38:21 +01001245 tipc_node_unlock(n_ptr);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001246 continue;
Per Lidenb97bf3f2006-01-02 19:04:38 +01001247 }
Per Liden4323add2006-01-18 00:38:21 +01001248 tipc_node_unlock(n_ptr);
Ying Xuef03273f2014-11-26 11:41:54 +08001249
Ying Xuef2f98002015-01-09 15:27:05 +08001250 if (tipc_link_input(net, l_ptr, skb) != 0)
Erik Hugne7ae934b2014-07-01 10:22:40 +02001251 goto discard;
Ying Xue3af390e2013-10-30 11:26:57 +08001252 continue;
1253unlock_discard:
Ying Xue3af390e2013-10-30 11:26:57 +08001254 tipc_node_unlock(n_ptr);
1255discard:
Ying Xuef03273f2014-11-26 11:41:54 +08001256 kfree_skb(skb);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001257 }
Per Lidenb97bf3f2006-01-02 19:04:38 +01001258}
1259
Ben Hutchings2c530402012-07-10 10:55:09 +00001260/**
Erik Hugne7ae934b2014-07-01 10:22:40 +02001261 * tipc_link_prepare_input - process TIPC link messages
1262 *
1263 * returns nonzero if the message was consumed
1264 *
1265 * Node lock must be held
1266 */
Ying Xuec93d3ba2015-01-09 15:27:04 +08001267static int tipc_link_prepare_input(struct net *net, struct tipc_link *l,
1268 struct sk_buff **buf)
Erik Hugne7ae934b2014-07-01 10:22:40 +02001269{
1270 struct tipc_node *n;
1271 struct tipc_msg *msg;
1272 int res = -EINVAL;
1273
1274 n = l->owner;
1275 msg = buf_msg(*buf);
1276 switch (msg_user(msg)) {
1277 case CHANGEOVER_PROTOCOL:
Ying Xuec93d3ba2015-01-09 15:27:04 +08001278 if (tipc_link_tunnel_rcv(net, n, buf))
Erik Hugne7ae934b2014-07-01 10:22:40 +02001279 res = 0;
1280 break;
1281 case MSG_FRAGMENTER:
1282 l->stats.recv_fragments++;
1283 if (tipc_buf_append(&l->reasm_buf, buf)) {
1284 l->stats.recv_fragmented++;
1285 res = 0;
1286 } else if (!l->reasm_buf) {
1287 tipc_link_reset(l);
1288 }
1289 break;
1290 case MSG_BUNDLER:
1291 l->stats.recv_bundles++;
1292 l->stats.recv_bundled += msg_msgcnt(msg);
1293 res = 0;
1294 break;
1295 case NAME_DISTRIBUTOR:
1296 n->bclink.recv_permitted = true;
1297 res = 0;
1298 break;
1299 case BCAST_PROTOCOL:
1300 tipc_link_sync_rcv(n, *buf);
1301 break;
1302 default:
1303 res = 0;
1304 }
1305 return res;
1306}
1307/**
1308 * tipc_link_input - Deliver message too higher layers
1309 */
Ying Xuef2f98002015-01-09 15:27:05 +08001310static int tipc_link_input(struct net *net, struct tipc_link *l,
1311 struct sk_buff *buf)
Erik Hugne7ae934b2014-07-01 10:22:40 +02001312{
1313 struct tipc_msg *msg = buf_msg(buf);
1314 int res = 0;
1315
1316 switch (msg_user(msg)) {
1317 case TIPC_LOW_IMPORTANCE:
1318 case TIPC_MEDIUM_IMPORTANCE:
1319 case TIPC_HIGH_IMPORTANCE:
1320 case TIPC_CRITICAL_IMPORTANCE:
1321 case CONN_MANAGER:
Ying Xuef2f98002015-01-09 15:27:05 +08001322 tipc_sk_rcv(net, buf);
Erik Hugne7ae934b2014-07-01 10:22:40 +02001323 break;
1324 case NAME_DISTRIBUTOR:
Ying Xuef2f98002015-01-09 15:27:05 +08001325 tipc_named_rcv(net, buf);
Erik Hugne7ae934b2014-07-01 10:22:40 +02001326 break;
1327 case MSG_BUNDLER:
Ying Xuef2f98002015-01-09 15:27:05 +08001328 tipc_link_bundle_rcv(net, buf);
Erik Hugne7ae934b2014-07-01 10:22:40 +02001329 break;
1330 default:
1331 res = -EINVAL;
1332 }
1333 return res;
1334}
1335
1336/**
Allan Stephens8809b252011-10-25 10:44:35 -04001337 * tipc_link_defer_pkt - Add out-of-sequence message to deferred reception queue
1338 *
1339 * Returns increase in queue length (i.e. 0 or 1)
Per Lidenb97bf3f2006-01-02 19:04:38 +01001340 */
Ying Xuebc6fecd2014-11-26 11:41:53 +08001341u32 tipc_link_defer_pkt(struct sk_buff_head *list, struct sk_buff *skb)
Per Lidenb97bf3f2006-01-02 19:04:38 +01001342{
Ying Xuebc6fecd2014-11-26 11:41:53 +08001343 struct sk_buff *skb1;
1344 u32 seq_no = buf_seqno(skb);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001345
1346 /* Empty queue ? */
Ying Xuebc6fecd2014-11-26 11:41:53 +08001347 if (skb_queue_empty(list)) {
1348 __skb_queue_tail(list, skb);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001349 return 1;
1350 }
1351
1352 /* Last ? */
Ying Xuebc6fecd2014-11-26 11:41:53 +08001353 if (less(buf_seqno(skb_peek_tail(list)), seq_no)) {
1354 __skb_queue_tail(list, skb);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001355 return 1;
1356 }
1357
Allan Stephens8809b252011-10-25 10:44:35 -04001358 /* Locate insertion point in queue, then insert; discard if duplicate */
Ying Xuebc6fecd2014-11-26 11:41:53 +08001359 skb_queue_walk(list, skb1) {
1360 u32 curr_seqno = buf_seqno(skb1);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001361
Allan Stephens8809b252011-10-25 10:44:35 -04001362 if (seq_no == curr_seqno) {
Ying Xuebc6fecd2014-11-26 11:41:53 +08001363 kfree_skb(skb);
Allan Stephens8809b252011-10-25 10:44:35 -04001364 return 0;
Per Lidenb97bf3f2006-01-02 19:04:38 +01001365 }
Allan Stephens8809b252011-10-25 10:44:35 -04001366
1367 if (less(seq_no, curr_seqno))
Per Lidenb97bf3f2006-01-02 19:04:38 +01001368 break;
Allan Stephens8809b252011-10-25 10:44:35 -04001369 }
Per Lidenb97bf3f2006-01-02 19:04:38 +01001370
Ying Xuebc6fecd2014-11-26 11:41:53 +08001371 __skb_queue_before(list, skb1, skb);
Allan Stephens8809b252011-10-25 10:44:35 -04001372 return 1;
Per Lidenb97bf3f2006-01-02 19:04:38 +01001373}
1374
Allan Stephens8809b252011-10-25 10:44:35 -04001375/*
Per Lidenb97bf3f2006-01-02 19:04:38 +01001376 * link_handle_out_of_seq_msg - handle arrival of out-of-sequence packet
1377 */
Ying Xuec93d3ba2015-01-09 15:27:04 +08001378static void link_handle_out_of_seq_msg(struct net *net,
1379 struct tipc_link *l_ptr,
Per Lidenb97bf3f2006-01-02 19:04:38 +01001380 struct sk_buff *buf)
1381{
Allan Stephensf9057302011-10-24 16:03:12 -04001382 u32 seq_no = buf_seqno(buf);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001383
1384 if (likely(msg_user(buf_msg(buf)) == LINK_PROTOCOL)) {
Ying Xuec93d3ba2015-01-09 15:27:04 +08001385 tipc_link_proto_rcv(net, l_ptr, buf);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001386 return;
1387 }
1388
Per Lidenb97bf3f2006-01-02 19:04:38 +01001389 /* Record OOS packet arrival (force mismatch on next timeout) */
Per Lidenb97bf3f2006-01-02 19:04:38 +01001390 l_ptr->checkpoint--;
1391
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001392 /*
Per Lidenb97bf3f2006-01-02 19:04:38 +01001393 * Discard packet if a duplicate; otherwise add it to deferred queue
1394 * and notify peer of gap as per protocol specification
1395 */
Per Lidenb97bf3f2006-01-02 19:04:38 +01001396 if (less(seq_no, mod(l_ptr->next_in_no))) {
1397 l_ptr->stats.duplicates++;
Allan Stephens5f6d9122011-11-04 13:24:29 -04001398 kfree_skb(buf);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001399 return;
1400 }
1401
Ying Xuebc6fecd2014-11-26 11:41:53 +08001402 if (tipc_link_defer_pkt(&l_ptr->deferred_queue, buf)) {
Per Lidenb97bf3f2006-01-02 19:04:38 +01001403 l_ptr->stats.deferred_recv++;
Erik Hugne64380a02014-02-11 11:38:26 +01001404 TIPC_SKB_CB(buf)->deferred = true;
Ying Xuebc6fecd2014-11-26 11:41:53 +08001405 if ((skb_queue_len(&l_ptr->deferred_queue) % 16) == 1)
Ying Xue247f0f32014-02-18 16:06:46 +08001406 tipc_link_proto_xmit(l_ptr, STATE_MSG, 0, 0, 0, 0, 0);
Ying Xuebc6fecd2014-11-26 11:41:53 +08001407 } else {
Per Lidenb97bf3f2006-01-02 19:04:38 +01001408 l_ptr->stats.duplicates++;
Ying Xuebc6fecd2014-11-26 11:41:53 +08001409 }
Per Lidenb97bf3f2006-01-02 19:04:38 +01001410}
1411
1412/*
1413 * Send protocol message to the other endpoint.
1414 */
Ying Xue247f0f32014-02-18 16:06:46 +08001415void tipc_link_proto_xmit(struct tipc_link *l_ptr, u32 msg_typ, int probe_msg,
1416 u32 gap, u32 tolerance, u32 priority, u32 ack_mtu)
Per Lidenb97bf3f2006-01-02 19:04:38 +01001417{
Sam Ravnborg1fc54d82006-03-20 22:36:47 -08001418 struct sk_buff *buf = NULL;
Per Lidenb97bf3f2006-01-02 19:04:38 +01001419 struct tipc_msg *msg = l_ptr->pmsg;
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001420 u32 msg_size = sizeof(l_ptr->proto_msg);
Allan Stephens75f0aa42011-02-28 15:30:20 -05001421 int r_flag;
Per Lidenb97bf3f2006-01-02 19:04:38 +01001422
Ying Xue77a7e072013-12-10 20:45:44 -08001423 /* Don't send protocol message during link changeover */
1424 if (l_ptr->exp_msg_count)
Per Lidenb97bf3f2006-01-02 19:04:38 +01001425 return;
Allan Stephensb4b56102011-05-27 11:00:51 -04001426
1427 /* Abort non-RESET send if communication with node is prohibited */
Ying Xue10f465c2014-05-05 08:56:11 +08001428 if ((tipc_node_blocked(l_ptr->owner)) && (msg_typ != RESET_MSG))
Allan Stephensb4b56102011-05-27 11:00:51 -04001429 return;
1430
Allan Stephens92d2c902011-10-25 11:20:26 -04001431 /* Create protocol message with "out-of-sequence" sequence number */
Per Lidenb97bf3f2006-01-02 19:04:38 +01001432 msg_set_type(msg, msg_typ);
Ying Xue7a2f7d12014-04-21 10:55:46 +08001433 msg_set_net_plane(msg, l_ptr->net_plane);
Allan Stephens7a54d4a2011-10-27 14:17:53 -04001434 msg_set_bcast_ack(msg, l_ptr->owner->bclink.last_in);
Ying Xue1da46562015-01-09 15:27:07 +08001435 msg_set_last_bcast(msg, tipc_bclink_get_last_sent(l_ptr->owner->net));
Per Lidenb97bf3f2006-01-02 19:04:38 +01001436
1437 if (msg_typ == STATE_MSG) {
1438 u32 next_sent = mod(l_ptr->next_out_no);
1439
Per Liden4323add2006-01-18 00:38:21 +01001440 if (!tipc_link_is_up(l_ptr))
Per Lidenb97bf3f2006-01-02 19:04:38 +01001441 return;
1442 if (l_ptr->next_out)
Allan Stephensf9057302011-10-24 16:03:12 -04001443 next_sent = buf_seqno(l_ptr->next_out);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001444 msg_set_next_sent(msg, next_sent);
Ying Xuebc6fecd2014-11-26 11:41:53 +08001445 if (!skb_queue_empty(&l_ptr->deferred_queue)) {
1446 u32 rec = buf_seqno(skb_peek(&l_ptr->deferred_queue));
Per Lidenb97bf3f2006-01-02 19:04:38 +01001447 gap = mod(rec - mod(l_ptr->next_in_no));
1448 }
1449 msg_set_seq_gap(msg, gap);
1450 if (gap)
1451 l_ptr->stats.sent_nacks++;
1452 msg_set_link_tolerance(msg, tolerance);
1453 msg_set_linkprio(msg, priority);
1454 msg_set_max_pkt(msg, ack_mtu);
1455 msg_set_ack(msg, mod(l_ptr->next_in_no - 1));
1456 msg_set_probe(msg, probe_msg != 0);
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001457 if (probe_msg) {
Per Lidenb97bf3f2006-01-02 19:04:38 +01001458 u32 mtu = l_ptr->max_pkt;
1459
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001460 if ((mtu < l_ptr->max_pkt_target) &&
Per Lidenb97bf3f2006-01-02 19:04:38 +01001461 link_working_working(l_ptr) &&
1462 l_ptr->fsm_msg_cnt) {
1463 msg_size = (mtu + (l_ptr->max_pkt_target - mtu)/2 + 2) & ~3;
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001464 if (l_ptr->max_pkt_probes == 10) {
1465 l_ptr->max_pkt_target = (msg_size - 4);
1466 l_ptr->max_pkt_probes = 0;
Per Lidenb97bf3f2006-01-02 19:04:38 +01001467 msg_size = (mtu + (l_ptr->max_pkt_target - mtu)/2 + 2) & ~3;
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001468 }
Per Lidenb97bf3f2006-01-02 19:04:38 +01001469 l_ptr->max_pkt_probes++;
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001470 }
Per Lidenb97bf3f2006-01-02 19:04:38 +01001471
1472 l_ptr->stats.sent_probes++;
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001473 }
Per Lidenb97bf3f2006-01-02 19:04:38 +01001474 l_ptr->stats.sent_states++;
1475 } else { /* RESET_MSG or ACTIVATE_MSG */
1476 msg_set_ack(msg, mod(l_ptr->reset_checkpoint - 1));
1477 msg_set_seq_gap(msg, 0);
1478 msg_set_next_sent(msg, 1);
Allan Stephensf23d9bf2011-01-18 15:15:34 -05001479 msg_set_probe(msg, 0);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001480 msg_set_link_tolerance(msg, l_ptr->tolerance);
1481 msg_set_linkprio(msg, l_ptr->priority);
1482 msg_set_max_pkt(msg, l_ptr->max_pkt_target);
1483 }
1484
Allan Stephens75f0aa42011-02-28 15:30:20 -05001485 r_flag = (l_ptr->owner->working_links > tipc_link_is_up(l_ptr));
1486 msg_set_redundant_link(msg, r_flag);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001487 msg_set_linkprio(msg, l_ptr->priority);
Allan Stephens92d2c902011-10-25 11:20:26 -04001488 msg_set_size(msg, msg_size);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001489
1490 msg_set_seqno(msg, mod(l_ptr->next_out_no + (0xffff/2)));
1491
stephen hemminger31e3c3f2010-10-13 13:20:35 +00001492 buf = tipc_buf_acquire(msg_size);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001493 if (!buf)
1494 return;
1495
Arnaldo Carvalho de Melo27d7ff42007-03-31 11:55:19 -03001496 skb_copy_to_linear_data(buf, msg, sizeof(l_ptr->proto_msg));
Ying Xue796c75d2013-06-17 10:54:48 -04001497 buf->priority = TC_PRIO_CONTROL;
Per Lidenb97bf3f2006-01-02 19:04:38 +01001498
Ying Xue7f9f95d2015-01-09 15:27:06 +08001499 tipc_bearer_send(l_ptr->owner->net, l_ptr->bearer_id, buf,
1500 &l_ptr->media_addr);
Allan Stephens92d2c902011-10-25 11:20:26 -04001501 l_ptr->unacked_window = 0;
Allan Stephens5f6d9122011-11-04 13:24:29 -04001502 kfree_skb(buf);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001503}
1504
1505/*
1506 * Receive protocol message :
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001507 * Note that network plane id propagates through the network, and may
1508 * change at any time. The node with lowest address rules
Per Lidenb97bf3f2006-01-02 19:04:38 +01001509 */
Ying Xuec93d3ba2015-01-09 15:27:04 +08001510static void tipc_link_proto_rcv(struct net *net, struct tipc_link *l_ptr,
1511 struct sk_buff *buf)
Per Lidenb97bf3f2006-01-02 19:04:38 +01001512{
Ying Xue34747532015-01-09 15:27:10 +08001513 struct tipc_net *tn = net_generic(net, tipc_net_id);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001514 u32 rec_gap = 0;
1515 u32 max_pkt_info;
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001516 u32 max_pkt_ack;
Per Lidenb97bf3f2006-01-02 19:04:38 +01001517 u32 msg_tol;
1518 struct tipc_msg *msg = buf_msg(buf);
1519
Ying Xue77a7e072013-12-10 20:45:44 -08001520 /* Discard protocol message during link changeover */
1521 if (l_ptr->exp_msg_count)
Per Lidenb97bf3f2006-01-02 19:04:38 +01001522 goto exit;
1523
Ying Xue7a2f7d12014-04-21 10:55:46 +08001524 if (l_ptr->net_plane != msg_net_plane(msg))
Ying Xue34747532015-01-09 15:27:10 +08001525 if (tn->own_addr > msg_prevnode(msg))
Ying Xue7a2f7d12014-04-21 10:55:46 +08001526 l_ptr->net_plane = msg_net_plane(msg);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001527
Per Lidenb97bf3f2006-01-02 19:04:38 +01001528 switch (msg_type(msg)) {
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001529
Per Lidenb97bf3f2006-01-02 19:04:38 +01001530 case RESET_MSG:
Allan Stephensa686e682008-06-04 17:29:39 -07001531 if (!link_working_unknown(l_ptr) &&
1532 (l_ptr->peer_session != INVALID_SESSION)) {
Allan Stephens641c2182011-04-07 09:54:43 -04001533 if (less_eq(msg_session(msg), l_ptr->peer_session))
1534 break; /* duplicate or old reset: ignore */
Per Lidenb97bf3f2006-01-02 19:04:38 +01001535 }
Allan Stephensb4b56102011-05-27 11:00:51 -04001536
1537 if (!msg_redundant_link(msg) && (link_working_working(l_ptr) ||
1538 link_working_unknown(l_ptr))) {
1539 /*
1540 * peer has lost contact -- don't allow peer's links
1541 * to reactivate before we recognize loss & clean up
1542 */
Ying Xueca9cf062014-05-08 08:54:40 +08001543 l_ptr->owner->action_flags |= TIPC_WAIT_OWN_LINKS_DOWN;
Allan Stephensb4b56102011-05-27 11:00:51 -04001544 }
1545
Allan Stephens47361c82011-10-26 10:55:16 -04001546 link_state_event(l_ptr, RESET_MSG);
1547
Per Lidenb97bf3f2006-01-02 19:04:38 +01001548 /* fall thru' */
1549 case ACTIVATE_MSG:
1550 /* Update link settings according other endpoint's values */
Per Lidenb97bf3f2006-01-02 19:04:38 +01001551 strcpy((strrchr(l_ptr->name, ':') + 1), (char *)msg_data(msg));
1552
Allan Stephens2db99832010-12-31 18:59:33 +00001553 msg_tol = msg_link_tolerance(msg);
1554 if (msg_tol > l_ptr->tolerance)
Per Lidenb97bf3f2006-01-02 19:04:38 +01001555 link_set_supervision_props(l_ptr, msg_tol);
1556
1557 if (msg_linkprio(msg) > l_ptr->priority)
1558 l_ptr->priority = msg_linkprio(msg);
1559
1560 max_pkt_info = msg_max_pkt(msg);
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001561 if (max_pkt_info) {
Per Lidenb97bf3f2006-01-02 19:04:38 +01001562 if (max_pkt_info < l_ptr->max_pkt_target)
1563 l_ptr->max_pkt_target = max_pkt_info;
1564 if (l_ptr->max_pkt > l_ptr->max_pkt_target)
1565 l_ptr->max_pkt = l_ptr->max_pkt_target;
1566 } else {
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001567 l_ptr->max_pkt = l_ptr->max_pkt_target;
Per Lidenb97bf3f2006-01-02 19:04:38 +01001568 }
Per Lidenb97bf3f2006-01-02 19:04:38 +01001569
Allan Stephens4d753132011-10-25 12:19:05 -04001570 /* Synchronize broadcast link info, if not done previously */
Allan Stephens7a54d4a2011-10-27 14:17:53 -04001571 if (!tipc_node_is_up(l_ptr->owner)) {
1572 l_ptr->owner->bclink.last_sent =
1573 l_ptr->owner->bclink.last_in =
1574 msg_last_bcast(msg);
1575 l_ptr->owner->bclink.oos_state = 0;
1576 }
Allan Stephens4d753132011-10-25 12:19:05 -04001577
Per Lidenb97bf3f2006-01-02 19:04:38 +01001578 l_ptr->peer_session = msg_session(msg);
1579 l_ptr->peer_bearer_id = msg_bearer_id(msg);
Allan Stephens47361c82011-10-26 10:55:16 -04001580
1581 if (msg_type(msg) == ACTIVATE_MSG)
1582 link_state_event(l_ptr, ACTIVATE_MSG);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001583 break;
1584 case STATE_MSG:
1585
Allan Stephens2db99832010-12-31 18:59:33 +00001586 msg_tol = msg_link_tolerance(msg);
1587 if (msg_tol)
Per Lidenb97bf3f2006-01-02 19:04:38 +01001588 link_set_supervision_props(l_ptr, msg_tol);
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001589
1590 if (msg_linkprio(msg) &&
Per Lidenb97bf3f2006-01-02 19:04:38 +01001591 (msg_linkprio(msg) != l_ptr->priority)) {
Erik Hugne3fa9cac2015-01-22 17:10:31 +01001592 pr_debug("%s<%s>, priority change %u->%u\n",
1593 link_rst_msg, l_ptr->name,
1594 l_ptr->priority, msg_linkprio(msg));
Per Lidenb97bf3f2006-01-02 19:04:38 +01001595 l_ptr->priority = msg_linkprio(msg);
Per Liden4323add2006-01-18 00:38:21 +01001596 tipc_link_reset(l_ptr); /* Enforce change to take effect */
Per Lidenb97bf3f2006-01-02 19:04:38 +01001597 break;
1598 }
Jon Paul Maloyec37dcd2014-05-14 05:39:10 -04001599
1600 /* Record reception; force mismatch at next timeout: */
1601 l_ptr->checkpoint--;
1602
Per Lidenb97bf3f2006-01-02 19:04:38 +01001603 link_state_event(l_ptr, TRAFFIC_MSG_EVT);
1604 l_ptr->stats.recv_states++;
1605 if (link_reset_unknown(l_ptr))
1606 break;
1607
1608 if (less_eq(mod(l_ptr->next_in_no), msg_next_sent(msg))) {
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001609 rec_gap = mod(msg_next_sent(msg) -
Per Lidenb97bf3f2006-01-02 19:04:38 +01001610 mod(l_ptr->next_in_no));
1611 }
1612
1613 max_pkt_ack = msg_max_pkt(msg);
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001614 if (max_pkt_ack > l_ptr->max_pkt) {
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001615 l_ptr->max_pkt = max_pkt_ack;
1616 l_ptr->max_pkt_probes = 0;
1617 }
Per Lidenb97bf3f2006-01-02 19:04:38 +01001618
1619 max_pkt_ack = 0;
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001620 if (msg_probe(msg)) {
Per Lidenb97bf3f2006-01-02 19:04:38 +01001621 l_ptr->stats.recv_probes++;
Allan Stephensa0168922010-12-31 18:59:35 +00001622 if (msg_size(msg) > sizeof(l_ptr->proto_msg))
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001623 max_pkt_ack = msg_size(msg);
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001624 }
Per Lidenb97bf3f2006-01-02 19:04:38 +01001625
1626 /* Protocol message before retransmits, reduce loss risk */
Ying Xue389dd9b2012-11-16 13:51:30 +08001627 if (l_ptr->owner->bclink.recv_permitted)
Ying Xuec93d3ba2015-01-09 15:27:04 +08001628 tipc_bclink_update_link_state(net, l_ptr->owner,
Allan Stephens7a54d4a2011-10-27 14:17:53 -04001629 msg_last_bcast(msg));
Per Lidenb97bf3f2006-01-02 19:04:38 +01001630
1631 if (rec_gap || (msg_probe(msg))) {
Ying Xue247f0f32014-02-18 16:06:46 +08001632 tipc_link_proto_xmit(l_ptr, STATE_MSG, 0, rec_gap, 0,
1633 0, max_pkt_ack);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001634 }
1635 if (msg_seq_gap(msg)) {
Per Lidenb97bf3f2006-01-02 19:04:38 +01001636 l_ptr->stats.recv_nacks++;
Ying Xue58dc55f2014-11-26 11:41:52 +08001637 tipc_link_retransmit(l_ptr, skb_peek(&l_ptr->outqueue),
Per Liden4323add2006-01-18 00:38:21 +01001638 msg_seq_gap(msg));
Per Lidenb97bf3f2006-01-02 19:04:38 +01001639 }
1640 break;
Per Lidenb97bf3f2006-01-02 19:04:38 +01001641 }
1642exit:
Allan Stephens5f6d9122011-11-04 13:24:29 -04001643 kfree_skb(buf);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001644}
1645
1646
Jon Paul Maloy170b3922014-01-07 17:02:41 -05001647/* tipc_link_tunnel_xmit(): Tunnel one packet via a link belonging to
1648 * a different bearer. Owner node is locked.
Per Lidenb97bf3f2006-01-02 19:04:38 +01001649 */
Jon Paul Maloy170b3922014-01-07 17:02:41 -05001650static void tipc_link_tunnel_xmit(struct tipc_link *l_ptr,
1651 struct tipc_msg *tunnel_hdr,
1652 struct tipc_msg *msg,
1653 u32 selector)
Per Lidenb97bf3f2006-01-02 19:04:38 +01001654{
Paul Gortmakera18c4bc2011-12-29 20:58:42 -05001655 struct tipc_link *tunnel;
Ying Xuea6ca1092014-11-26 11:41:55 +08001656 struct sk_buff *skb;
Per Lidenb97bf3f2006-01-02 19:04:38 +01001657 u32 length = msg_size(msg);
1658
1659 tunnel = l_ptr->owner->active_links[selector & 1];
Allan Stephens5392d642006-06-25 23:52:50 -07001660 if (!tipc_link_is_up(tunnel)) {
Erik Hugne2cf8aa12012-06-29 00:16:37 -04001661 pr_warn("%stunnel link no longer available\n", link_co_err);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001662 return;
Allan Stephens5392d642006-06-25 23:52:50 -07001663 }
Per Lidenb97bf3f2006-01-02 19:04:38 +01001664 msg_set_size(tunnel_hdr, length + INT_H_SIZE);
Ying Xuea6ca1092014-11-26 11:41:55 +08001665 skb = tipc_buf_acquire(length + INT_H_SIZE);
1666 if (!skb) {
Erik Hugne2cf8aa12012-06-29 00:16:37 -04001667 pr_warn("%sunable to send tunnel msg\n", link_co_err);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001668 return;
Allan Stephens5392d642006-06-25 23:52:50 -07001669 }
Ying Xuea6ca1092014-11-26 11:41:55 +08001670 skb_copy_to_linear_data(skb, tunnel_hdr, INT_H_SIZE);
1671 skb_copy_to_linear_data_offset(skb, INT_H_SIZE, msg, length);
1672 __tipc_link_xmit_skb(tunnel, skb);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001673}
1674
1675
Jon Paul Maloy170b3922014-01-07 17:02:41 -05001676/* tipc_link_failover_send_queue(): A link has gone down, but a second
1677 * link is still active. We can do failover. Tunnel the failing link's
1678 * whole send queue via the remaining link. This way, we don't lose
1679 * any packets, and sequence order is preserved for subsequent traffic
1680 * sent over the remaining link. Owner node is locked.
Per Lidenb97bf3f2006-01-02 19:04:38 +01001681 */
Jon Paul Maloy170b3922014-01-07 17:02:41 -05001682void tipc_link_failover_send_queue(struct tipc_link *l_ptr)
Per Lidenb97bf3f2006-01-02 19:04:38 +01001683{
Ying Xue58dc55f2014-11-26 11:41:52 +08001684 u32 msgcount = skb_queue_len(&l_ptr->outqueue);
Paul Gortmakera18c4bc2011-12-29 20:58:42 -05001685 struct tipc_link *tunnel = l_ptr->owner->active_links[0];
Per Lidenb97bf3f2006-01-02 19:04:38 +01001686 struct tipc_msg tunnel_hdr;
Ying Xue58dc55f2014-11-26 11:41:52 +08001687 struct sk_buff *skb;
Allan Stephens5392d642006-06-25 23:52:50 -07001688 int split_bundles;
Per Lidenb97bf3f2006-01-02 19:04:38 +01001689
1690 if (!tunnel)
1691 return;
1692
Ying Xue34747532015-01-09 15:27:10 +08001693 tipc_msg_init(l_ptr->owner->net, &tunnel_hdr, CHANGEOVER_PROTOCOL,
1694 ORIGINAL_MSG, INT_H_SIZE, l_ptr->addr);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001695 msg_set_bearer_id(&tunnel_hdr, l_ptr->peer_bearer_id);
1696 msg_set_msgcnt(&tunnel_hdr, msgcount);
Allan Stephensf1310722006-06-25 23:51:37 -07001697
Ying Xue58dc55f2014-11-26 11:41:52 +08001698 if (skb_queue_empty(&l_ptr->outqueue)) {
1699 skb = tipc_buf_acquire(INT_H_SIZE);
1700 if (skb) {
1701 skb_copy_to_linear_data(skb, &tunnel_hdr, INT_H_SIZE);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001702 msg_set_size(&tunnel_hdr, INT_H_SIZE);
Ying Xuea6ca1092014-11-26 11:41:55 +08001703 __tipc_link_xmit_skb(tunnel, skb);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001704 } else {
Erik Hugne2cf8aa12012-06-29 00:16:37 -04001705 pr_warn("%sunable to send changeover msg\n",
1706 link_co_err);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001707 }
1708 return;
1709 }
Allan Stephensf1310722006-06-25 23:51:37 -07001710
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001711 split_bundles = (l_ptr->owner->active_links[0] !=
Allan Stephens5392d642006-06-25 23:52:50 -07001712 l_ptr->owner->active_links[1]);
1713
Ying Xue58dc55f2014-11-26 11:41:52 +08001714 skb_queue_walk(&l_ptr->outqueue, skb) {
1715 struct tipc_msg *msg = buf_msg(skb);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001716
1717 if ((msg_user(msg) == MSG_BUNDLER) && split_bundles) {
Per Lidenb97bf3f2006-01-02 19:04:38 +01001718 struct tipc_msg *m = msg_get_wrapped(msg);
Allan Stephens0e659672010-12-31 18:59:32 +00001719 unchar *pos = (unchar *)m;
Per Lidenb97bf3f2006-01-02 19:04:38 +01001720
Florian Westphald788d802007-08-02 19:28:06 -07001721 msgcount = msg_msgcnt(msg);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001722 while (msgcount--) {
Allan Stephens0e659672010-12-31 18:59:32 +00001723 msg_set_seqno(m, msg_seqno(msg));
Jon Paul Maloy170b3922014-01-07 17:02:41 -05001724 tipc_link_tunnel_xmit(l_ptr, &tunnel_hdr, m,
1725 msg_link_selector(m));
Per Lidenb97bf3f2006-01-02 19:04:38 +01001726 pos += align(msg_size(m));
1727 m = (struct tipc_msg *)pos;
1728 }
1729 } else {
Jon Paul Maloy170b3922014-01-07 17:02:41 -05001730 tipc_link_tunnel_xmit(l_ptr, &tunnel_hdr, msg,
1731 msg_link_selector(msg));
Per Lidenb97bf3f2006-01-02 19:04:38 +01001732 }
Per Lidenb97bf3f2006-01-02 19:04:38 +01001733 }
1734}
1735
Ying Xue247f0f32014-02-18 16:06:46 +08001736/* tipc_link_dup_queue_xmit(): A second link has become active. Tunnel a
Jon Paul Maloy170b3922014-01-07 17:02:41 -05001737 * duplicate of the first link's send queue via the new link. This way, we
1738 * are guaranteed that currently queued packets from a socket are delivered
1739 * before future traffic from the same socket, even if this is using the
1740 * new link. The last arriving copy of each duplicate packet is dropped at
1741 * the receiving end by the regular protocol check, so packet cardinality
1742 * and sequence order is preserved per sender/receiver socket pair.
1743 * Owner node is locked.
1744 */
Ying Xue247f0f32014-02-18 16:06:46 +08001745void tipc_link_dup_queue_xmit(struct tipc_link *l_ptr,
Jon Paul Maloy170b3922014-01-07 17:02:41 -05001746 struct tipc_link *tunnel)
Per Lidenb97bf3f2006-01-02 19:04:38 +01001747{
Ying Xue58dc55f2014-11-26 11:41:52 +08001748 struct sk_buff *skb;
Per Lidenb97bf3f2006-01-02 19:04:38 +01001749 struct tipc_msg tunnel_hdr;
1750
Ying Xue34747532015-01-09 15:27:10 +08001751 tipc_msg_init(l_ptr->owner->net, &tunnel_hdr, CHANGEOVER_PROTOCOL,
1752 DUPLICATE_MSG, INT_H_SIZE, l_ptr->addr);
Ying Xue58dc55f2014-11-26 11:41:52 +08001753 msg_set_msgcnt(&tunnel_hdr, skb_queue_len(&l_ptr->outqueue));
Per Lidenb97bf3f2006-01-02 19:04:38 +01001754 msg_set_bearer_id(&tunnel_hdr, l_ptr->peer_bearer_id);
Ying Xue58dc55f2014-11-26 11:41:52 +08001755 skb_queue_walk(&l_ptr->outqueue, skb) {
1756 struct sk_buff *outskb;
1757 struct tipc_msg *msg = buf_msg(skb);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001758 u32 length = msg_size(msg);
1759
1760 if (msg_user(msg) == MSG_BUNDLER)
1761 msg_set_type(msg, CLOSED_MSG);
1762 msg_set_ack(msg, mod(l_ptr->next_in_no - 1)); /* Update */
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001763 msg_set_bcast_ack(msg, l_ptr->owner->bclink.last_in);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001764 msg_set_size(&tunnel_hdr, length + INT_H_SIZE);
Ying Xue58dc55f2014-11-26 11:41:52 +08001765 outskb = tipc_buf_acquire(length + INT_H_SIZE);
1766 if (outskb == NULL) {
Erik Hugne2cf8aa12012-06-29 00:16:37 -04001767 pr_warn("%sunable to send duplicate msg\n",
1768 link_co_err);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001769 return;
1770 }
Ying Xue58dc55f2014-11-26 11:41:52 +08001771 skb_copy_to_linear_data(outskb, &tunnel_hdr, INT_H_SIZE);
1772 skb_copy_to_linear_data_offset(outskb, INT_H_SIZE, skb->data,
Arnaldo Carvalho de Melo27d7ff42007-03-31 11:55:19 -03001773 length);
Ying Xuea6ca1092014-11-26 11:41:55 +08001774 __tipc_link_xmit_skb(tunnel, outskb);
Per Liden4323add2006-01-18 00:38:21 +01001775 if (!tipc_link_is_up(l_ptr))
Per Lidenb97bf3f2006-01-02 19:04:38 +01001776 return;
Per Lidenb97bf3f2006-01-02 19:04:38 +01001777 }
1778}
1779
Per Lidenb97bf3f2006-01-02 19:04:38 +01001780/**
1781 * buf_extract - extracts embedded TIPC message from another message
1782 * @skb: encapsulating message buffer
1783 * @from_pos: offset to extract from
1784 *
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001785 * Returns a new message buffer containing an embedded message. The
Per Lidenb97bf3f2006-01-02 19:04:38 +01001786 * encapsulating message itself is left unchanged.
1787 */
Per Lidenb97bf3f2006-01-02 19:04:38 +01001788static struct sk_buff *buf_extract(struct sk_buff *skb, u32 from_pos)
1789{
1790 struct tipc_msg *msg = (struct tipc_msg *)(skb->data + from_pos);
1791 u32 size = msg_size(msg);
1792 struct sk_buff *eb;
1793
stephen hemminger31e3c3f2010-10-13 13:20:35 +00001794 eb = tipc_buf_acquire(size);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001795 if (eb)
Arnaldo Carvalho de Melo27d7ff42007-03-31 11:55:19 -03001796 skb_copy_to_linear_data(eb, msg, size);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001797 return eb;
1798}
1799
Jon Paul Maloy1dab3d52014-02-13 17:29:10 -05001800
1801
1802/* tipc_link_dup_rcv(): Receive a tunnelled DUPLICATE_MSG packet.
1803 * Owner node is locked.
1804 */
Ying Xuec93d3ba2015-01-09 15:27:04 +08001805static void tipc_link_dup_rcv(struct net *net, struct tipc_link *l_ptr,
Jon Paul Maloy1dab3d52014-02-13 17:29:10 -05001806 struct sk_buff *t_buf)
1807{
1808 struct sk_buff *buf;
1809
1810 if (!tipc_link_is_up(l_ptr))
1811 return;
1812
1813 buf = buf_extract(t_buf, INT_H_SIZE);
1814 if (buf == NULL) {
1815 pr_warn("%sfailed to extract inner dup pkt\n", link_co_err);
1816 return;
1817 }
1818
1819 /* Add buffer to deferred queue, if applicable: */
Ying Xuec93d3ba2015-01-09 15:27:04 +08001820 link_handle_out_of_seq_msg(net, l_ptr, buf);
Jon Paul Maloy1dab3d52014-02-13 17:29:10 -05001821}
1822
Jon Paul Maloyf006c9c2014-02-13 17:29:11 -05001823/* tipc_link_failover_rcv(): Receive a tunnelled ORIGINAL_MSG packet
1824 * Owner node is locked.
1825 */
1826static struct sk_buff *tipc_link_failover_rcv(struct tipc_link *l_ptr,
1827 struct sk_buff *t_buf)
1828{
1829 struct tipc_msg *t_msg = buf_msg(t_buf);
1830 struct sk_buff *buf = NULL;
1831 struct tipc_msg *msg;
1832
1833 if (tipc_link_is_up(l_ptr))
1834 tipc_link_reset(l_ptr);
1835
1836 /* First failover packet? */
1837 if (l_ptr->exp_msg_count == START_CHANGEOVER)
1838 l_ptr->exp_msg_count = msg_msgcnt(t_msg);
1839
1840 /* Should there be an inner packet? */
1841 if (l_ptr->exp_msg_count) {
1842 l_ptr->exp_msg_count--;
1843 buf = buf_extract(t_buf, INT_H_SIZE);
1844 if (buf == NULL) {
1845 pr_warn("%sno inner failover pkt\n", link_co_err);
1846 goto exit;
1847 }
1848 msg = buf_msg(buf);
1849
1850 if (less(msg_seqno(msg), l_ptr->reset_checkpoint)) {
1851 kfree_skb(buf);
1852 buf = NULL;
1853 goto exit;
1854 }
1855 if (msg_user(msg) == MSG_FRAGMENTER) {
1856 l_ptr->stats.recv_fragments++;
Jon Paul Maloy37e22162014-05-14 05:39:12 -04001857 tipc_buf_append(&l_ptr->reasm_buf, &buf);
Jon Paul Maloyf006c9c2014-02-13 17:29:11 -05001858 }
1859 }
Jon Paul Maloyf006c9c2014-02-13 17:29:11 -05001860exit:
Jon Paul Maloy2d72d492015-02-03 08:59:17 -05001861 if ((!l_ptr->exp_msg_count) && (l_ptr->flags & LINK_STOPPED))
1862 tipc_link_delete(l_ptr);
Jon Paul Maloyf006c9c2014-02-13 17:29:11 -05001863 return buf;
1864}
1865
Jon Paul Maloy1dab3d52014-02-13 17:29:10 -05001866/* tipc_link_tunnel_rcv(): Receive a tunnelled packet, sent
Jon Paul Maloy170b3922014-01-07 17:02:41 -05001867 * via other link as result of a failover (ORIGINAL_MSG) or
1868 * a new active link (DUPLICATE_MSG). Failover packets are
1869 * returned to the active link for delivery upwards.
1870 * Owner node is locked.
Per Lidenb97bf3f2006-01-02 19:04:38 +01001871 */
Ying Xuec93d3ba2015-01-09 15:27:04 +08001872static int tipc_link_tunnel_rcv(struct net *net, struct tipc_node *n_ptr,
Jon Paul Maloy170b3922014-01-07 17:02:41 -05001873 struct sk_buff **buf)
Per Lidenb97bf3f2006-01-02 19:04:38 +01001874{
Jon Paul Maloy02842f72014-02-13 17:29:14 -05001875 struct sk_buff *t_buf = *buf;
1876 struct tipc_link *l_ptr;
1877 struct tipc_msg *t_msg = buf_msg(t_buf);
1878 u32 bearer_id = msg_bearer_id(t_msg);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001879
Jon Paul Maloy1e9d47a2014-02-13 17:29:13 -05001880 *buf = NULL;
1881
Dan Carpentercb4b102f2013-05-06 08:28:41 +00001882 if (bearer_id >= MAX_BEARERS)
1883 goto exit;
Jon Paul Maloy1dab3d52014-02-13 17:29:10 -05001884
Jon Paul Maloy02842f72014-02-13 17:29:14 -05001885 l_ptr = n_ptr->links[bearer_id];
1886 if (!l_ptr)
Per Lidenb97bf3f2006-01-02 19:04:38 +01001887 goto exit;
Per Lidenb97bf3f2006-01-02 19:04:38 +01001888
Jon Paul Maloy02842f72014-02-13 17:29:14 -05001889 if (msg_type(t_msg) == DUPLICATE_MSG)
Ying Xuec93d3ba2015-01-09 15:27:04 +08001890 tipc_link_dup_rcv(net, l_ptr, t_buf);
Jon Paul Maloy02842f72014-02-13 17:29:14 -05001891 else if (msg_type(t_msg) == ORIGINAL_MSG)
1892 *buf = tipc_link_failover_rcv(l_ptr, t_buf);
Jon Paul Maloy1e9d47a2014-02-13 17:29:13 -05001893 else
1894 pr_warn("%sunknown tunnel pkt received\n", link_co_err);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001895exit:
Jon Paul Maloy02842f72014-02-13 17:29:14 -05001896 kfree_skb(t_buf);
Jon Paul Maloy1e9d47a2014-02-13 17:29:13 -05001897 return *buf != NULL;
Per Lidenb97bf3f2006-01-02 19:04:38 +01001898}
1899
1900/*
1901 * Bundler functionality:
1902 */
Ying Xuef2f98002015-01-09 15:27:05 +08001903void tipc_link_bundle_rcv(struct net *net, struct sk_buff *buf)
Per Lidenb97bf3f2006-01-02 19:04:38 +01001904{
1905 u32 msgcount = msg_msgcnt(buf_msg(buf));
1906 u32 pos = INT_H_SIZE;
1907 struct sk_buff *obuf;
Jon Paul Maloyec8a2e52014-06-25 20:41:40 -05001908 struct tipc_msg *omsg;
Per Lidenb97bf3f2006-01-02 19:04:38 +01001909
Per Lidenb97bf3f2006-01-02 19:04:38 +01001910 while (msgcount--) {
1911 obuf = buf_extract(buf, pos);
1912 if (obuf == NULL) {
Erik Hugne2cf8aa12012-06-29 00:16:37 -04001913 pr_warn("Link unable to unbundle message(s)\n");
Allan Stephensa10bd922006-06-25 23:52:17 -07001914 break;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -07001915 }
Jon Paul Maloyec8a2e52014-06-25 20:41:40 -05001916 omsg = buf_msg(obuf);
1917 pos += align(msg_size(omsg));
Jon Paul Maloy643566d2014-10-17 15:25:28 -04001918 if (msg_isdata(omsg)) {
1919 if (unlikely(msg_type(omsg) == TIPC_MCAST_MSG))
Ying Xuef2f98002015-01-09 15:27:05 +08001920 tipc_sk_mcast_rcv(net, obuf);
Jon Paul Maloy643566d2014-10-17 15:25:28 -04001921 else
Ying Xuef2f98002015-01-09 15:27:05 +08001922 tipc_sk_rcv(net, obuf);
Jon Paul Maloy643566d2014-10-17 15:25:28 -04001923 } else if (msg_user(omsg) == CONN_MANAGER) {
Ying Xuef2f98002015-01-09 15:27:05 +08001924 tipc_sk_rcv(net, obuf);
Jon Paul Maloyec8a2e52014-06-25 20:41:40 -05001925 } else if (msg_user(omsg) == NAME_DISTRIBUTOR) {
Ying Xuef2f98002015-01-09 15:27:05 +08001926 tipc_named_rcv(net, obuf);
Jon Paul Maloyec8a2e52014-06-25 20:41:40 -05001927 } else {
1928 pr_warn("Illegal bundled msg: %u\n", msg_user(omsg));
1929 kfree_skb(obuf);
1930 }
Per Lidenb97bf3f2006-01-02 19:04:38 +01001931 }
Allan Stephens5f6d9122011-11-04 13:24:29 -04001932 kfree_skb(buf);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001933}
1934
Ying Xue2f55c432015-01-09 15:27:00 +08001935static void link_set_supervision_props(struct tipc_link *l_ptr, u32 tol)
Per Lidenb97bf3f2006-01-02 19:04:38 +01001936{
Ying Xue2f55c432015-01-09 15:27:00 +08001937 unsigned long intv = ((tol / 4) > 500) ? 500 : tol / 4;
1938
1939 if ((tol < TIPC_MIN_LINK_TOL) || (tol > TIPC_MAX_LINK_TOL))
Allan Stephens5413b4c2011-01-18 13:24:55 -05001940 return;
1941
Ying Xue2f55c432015-01-09 15:27:00 +08001942 l_ptr->tolerance = tol;
1943 l_ptr->cont_intv = msecs_to_jiffies(intv);
1944 l_ptr->abort_limit = tol / (jiffies_to_msecs(l_ptr->cont_intv) / 4);
Per Lidenb97bf3f2006-01-02 19:04:38 +01001945}
1946
Paul Gortmakera18c4bc2011-12-29 20:58:42 -05001947void tipc_link_set_queue_limits(struct tipc_link *l_ptr, u32 window)
Per Lidenb97bf3f2006-01-02 19:04:38 +01001948{
1949 /* Data messages from this node, inclusive FIRST_FRAGM */
Allan Stephens06d82c92008-03-06 15:06:55 -08001950 l_ptr->queue_limit[TIPC_LOW_IMPORTANCE] = window;
1951 l_ptr->queue_limit[TIPC_MEDIUM_IMPORTANCE] = (window / 3) * 4;
1952 l_ptr->queue_limit[TIPC_HIGH_IMPORTANCE] = (window / 3) * 5;
1953 l_ptr->queue_limit[TIPC_CRITICAL_IMPORTANCE] = (window / 3) * 6;
Per Lidenb97bf3f2006-01-02 19:04:38 +01001954 /* Transiting data messages,inclusive FIRST_FRAGM */
Allan Stephens06d82c92008-03-06 15:06:55 -08001955 l_ptr->queue_limit[TIPC_LOW_IMPORTANCE + 4] = 300;
1956 l_ptr->queue_limit[TIPC_MEDIUM_IMPORTANCE + 4] = 600;
1957 l_ptr->queue_limit[TIPC_HIGH_IMPORTANCE + 4] = 900;
1958 l_ptr->queue_limit[TIPC_CRITICAL_IMPORTANCE + 4] = 1200;
Per Lidenb97bf3f2006-01-02 19:04:38 +01001959 l_ptr->queue_limit[CONN_MANAGER] = 1200;
Per Lidenb97bf3f2006-01-02 19:04:38 +01001960 l_ptr->queue_limit[CHANGEOVER_PROTOCOL] = 2500;
1961 l_ptr->queue_limit[NAME_DISTRIBUTOR] = 3000;
1962 /* FRAGMENT and LAST_FRAGMENT packets */
1963 l_ptr->queue_limit[MSG_FRAGMENTER] = 4000;
1964}
1965
Jon Paul Maloye099e862014-02-13 17:29:18 -05001966/* tipc_link_find_owner - locate owner node of link by link's name
Ying Xuef2f98002015-01-09 15:27:05 +08001967 * @net: the applicable net namespace
Jon Paul Maloye099e862014-02-13 17:29:18 -05001968 * @name: pointer to link name string
1969 * @bearer_id: pointer to index in 'node->links' array where the link was found.
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09001970 *
Jon Paul Maloye099e862014-02-13 17:29:18 -05001971 * Returns pointer to node owning the link, or 0 if no matching link is found.
Per Lidenb97bf3f2006-01-02 19:04:38 +01001972 */
Ying Xuef2f98002015-01-09 15:27:05 +08001973static struct tipc_node *tipc_link_find_owner(struct net *net,
1974 const char *link_name,
Jon Paul Maloye099e862014-02-13 17:29:18 -05001975 unsigned int *bearer_id)
Per Lidenb97bf3f2006-01-02 19:04:38 +01001976{
Ying Xuef2f98002015-01-09 15:27:05 +08001977 struct tipc_net *tn = net_generic(net, tipc_net_id);
Paul Gortmakera18c4bc2011-12-29 20:58:42 -05001978 struct tipc_link *l_ptr;
Erik Hugnebbfbe472013-10-18 07:23:21 +02001979 struct tipc_node *n_ptr;
Fabian Frederick886eaa12014-12-25 12:05:50 +01001980 struct tipc_node *found_node = NULL;
Erik Hugnebbfbe472013-10-18 07:23:21 +02001981 int i;
Per Lidenb97bf3f2006-01-02 19:04:38 +01001982
Jon Paul Maloye099e862014-02-13 17:29:18 -05001983 *bearer_id = 0;
Ying Xue6c7a7622014-03-27 12:54:37 +08001984 rcu_read_lock();
Ying Xuef2f98002015-01-09 15:27:05 +08001985 list_for_each_entry_rcu(n_ptr, &tn->node_list, list) {
Jon Paul Maloya11607f2014-02-14 16:40:44 -05001986 tipc_node_lock(n_ptr);
Erik Hugnebbfbe472013-10-18 07:23:21 +02001987 for (i = 0; i < MAX_BEARERS; i++) {
1988 l_ptr = n_ptr->links[i];
Jon Paul Maloye099e862014-02-13 17:29:18 -05001989 if (l_ptr && !strcmp(l_ptr->name, link_name)) {
1990 *bearer_id = i;
1991 found_node = n_ptr;
1992 break;
1993 }
Erik Hugnebbfbe472013-10-18 07:23:21 +02001994 }
Jon Paul Maloya11607f2014-02-14 16:40:44 -05001995 tipc_node_unlock(n_ptr);
Jon Paul Maloye099e862014-02-13 17:29:18 -05001996 if (found_node)
1997 break;
Erik Hugnebbfbe472013-10-18 07:23:21 +02001998 }
Ying Xue6c7a7622014-03-27 12:54:37 +08001999 rcu_read_unlock();
2000
Jon Paul Maloye099e862014-02-13 17:29:18 -05002001 return found_node;
Per Lidenb97bf3f2006-01-02 19:04:38 +01002002}
2003
Allan Stephens5c216e12011-10-18 11:34:29 -04002004/**
2005 * link_value_is_valid -- validate proposed link tolerance/priority/window
2006 *
Ben Hutchings2c530402012-07-10 10:55:09 +00002007 * @cmd: value type (TIPC_CMD_SET_LINK_*)
2008 * @new_value: the new value
Allan Stephens5c216e12011-10-18 11:34:29 -04002009 *
2010 * Returns 1 if value is within range, 0 if not.
2011 */
Allan Stephens5c216e12011-10-18 11:34:29 -04002012static int link_value_is_valid(u16 cmd, u32 new_value)
2013{
2014 switch (cmd) {
2015 case TIPC_CMD_SET_LINK_TOL:
2016 return (new_value >= TIPC_MIN_LINK_TOL) &&
2017 (new_value <= TIPC_MAX_LINK_TOL);
2018 case TIPC_CMD_SET_LINK_PRI:
2019 return (new_value <= TIPC_MAX_LINK_PRI);
2020 case TIPC_CMD_SET_LINK_WINDOW:
2021 return (new_value >= TIPC_MIN_LINK_WIN) &&
2022 (new_value <= TIPC_MAX_LINK_WIN);
2023 }
2024 return 0;
2025}
2026
Allan Stephens5c216e12011-10-18 11:34:29 -04002027/**
2028 * link_cmd_set_value - change priority/tolerance/window for link/bearer/media
Ying Xuef2f98002015-01-09 15:27:05 +08002029 * @net: the applicable net namespace
Ben Hutchings2c530402012-07-10 10:55:09 +00002030 * @name: ptr to link, bearer, or media name
2031 * @new_value: new value of link, bearer, or media setting
2032 * @cmd: which link, bearer, or media attribute to set (TIPC_CMD_SET_LINK_*)
Allan Stephens5c216e12011-10-18 11:34:29 -04002033 *
Ying Xue7216cd92014-04-21 10:55:48 +08002034 * Caller must hold RTNL lock to ensure link/bearer/media is not deleted.
Allan Stephens5c216e12011-10-18 11:34:29 -04002035 *
2036 * Returns 0 if value updated and negative value on error.
2037 */
Ying Xuef2f98002015-01-09 15:27:05 +08002038static int link_cmd_set_value(struct net *net, const char *name, u32 new_value,
2039 u16 cmd)
Allan Stephens5c216e12011-10-18 11:34:29 -04002040{
2041 struct tipc_node *node;
Paul Gortmakera18c4bc2011-12-29 20:58:42 -05002042 struct tipc_link *l_ptr;
Allan Stephens5c216e12011-10-18 11:34:29 -04002043 struct tipc_bearer *b_ptr;
Paul Gortmaker358a0d12011-12-29 20:19:42 -05002044 struct tipc_media *m_ptr;
Jon Paul Maloye099e862014-02-13 17:29:18 -05002045 int bearer_id;
Ying Xue636c0372013-10-18 07:23:20 +02002046 int res = 0;
Allan Stephens5c216e12011-10-18 11:34:29 -04002047
Ying Xuef2f98002015-01-09 15:27:05 +08002048 node = tipc_link_find_owner(net, name, &bearer_id);
Jon Paul Maloye099e862014-02-13 17:29:18 -05002049 if (node) {
Allan Stephens5c216e12011-10-18 11:34:29 -04002050 tipc_node_lock(node);
Jon Paul Maloye099e862014-02-13 17:29:18 -05002051 l_ptr = node->links[bearer_id];
2052
2053 if (l_ptr) {
2054 switch (cmd) {
2055 case TIPC_CMD_SET_LINK_TOL:
2056 link_set_supervision_props(l_ptr, new_value);
Ying Xue247f0f32014-02-18 16:06:46 +08002057 tipc_link_proto_xmit(l_ptr, STATE_MSG, 0, 0,
2058 new_value, 0, 0);
Jon Paul Maloye099e862014-02-13 17:29:18 -05002059 break;
2060 case TIPC_CMD_SET_LINK_PRI:
2061 l_ptr->priority = new_value;
Ying Xue247f0f32014-02-18 16:06:46 +08002062 tipc_link_proto_xmit(l_ptr, STATE_MSG, 0, 0,
2063 0, new_value, 0);
Jon Paul Maloye099e862014-02-13 17:29:18 -05002064 break;
2065 case TIPC_CMD_SET_LINK_WINDOW:
2066 tipc_link_set_queue_limits(l_ptr, new_value);
2067 break;
2068 default:
2069 res = -EINVAL;
2070 break;
2071 }
Allan Stephens5c216e12011-10-18 11:34:29 -04002072 }
2073 tipc_node_unlock(node);
Ying Xue636c0372013-10-18 07:23:20 +02002074 return res;
Allan Stephens5c216e12011-10-18 11:34:29 -04002075 }
2076
Ying Xue7f9f95d2015-01-09 15:27:06 +08002077 b_ptr = tipc_bearer_find(net, name);
Allan Stephens5c216e12011-10-18 11:34:29 -04002078 if (b_ptr) {
2079 switch (cmd) {
2080 case TIPC_CMD_SET_LINK_TOL:
2081 b_ptr->tolerance = new_value;
Ying Xue636c0372013-10-18 07:23:20 +02002082 break;
Allan Stephens5c216e12011-10-18 11:34:29 -04002083 case TIPC_CMD_SET_LINK_PRI:
2084 b_ptr->priority = new_value;
Ying Xue636c0372013-10-18 07:23:20 +02002085 break;
Allan Stephens5c216e12011-10-18 11:34:29 -04002086 case TIPC_CMD_SET_LINK_WINDOW:
2087 b_ptr->window = new_value;
Ying Xue636c0372013-10-18 07:23:20 +02002088 break;
2089 default:
2090 res = -EINVAL;
2091 break;
Allan Stephens5c216e12011-10-18 11:34:29 -04002092 }
Ying Xue636c0372013-10-18 07:23:20 +02002093 return res;
Allan Stephens5c216e12011-10-18 11:34:29 -04002094 }
2095
2096 m_ptr = tipc_media_find(name);
2097 if (!m_ptr)
2098 return -ENODEV;
2099 switch (cmd) {
2100 case TIPC_CMD_SET_LINK_TOL:
2101 m_ptr->tolerance = new_value;
Ying Xue636c0372013-10-18 07:23:20 +02002102 break;
Allan Stephens5c216e12011-10-18 11:34:29 -04002103 case TIPC_CMD_SET_LINK_PRI:
2104 m_ptr->priority = new_value;
Ying Xue636c0372013-10-18 07:23:20 +02002105 break;
Allan Stephens5c216e12011-10-18 11:34:29 -04002106 case TIPC_CMD_SET_LINK_WINDOW:
2107 m_ptr->window = new_value;
Ying Xue636c0372013-10-18 07:23:20 +02002108 break;
2109 default:
2110 res = -EINVAL;
2111 break;
Allan Stephens5c216e12011-10-18 11:34:29 -04002112 }
Ying Xue636c0372013-10-18 07:23:20 +02002113 return res;
Allan Stephens5c216e12011-10-18 11:34:29 -04002114}
2115
Ying Xuef2f98002015-01-09 15:27:05 +08002116struct sk_buff *tipc_link_cmd_config(struct net *net, const void *req_tlv_area,
2117 int req_tlv_space, u16 cmd)
Per Lidenb97bf3f2006-01-02 19:04:38 +01002118{
2119 struct tipc_link_config *args;
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002120 u32 new_value;
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002121 int res;
Per Lidenb97bf3f2006-01-02 19:04:38 +01002122
2123 if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_LINK_CONFIG))
Per Liden4323add2006-01-18 00:38:21 +01002124 return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
Per Lidenb97bf3f2006-01-02 19:04:38 +01002125
2126 args = (struct tipc_link_config *)TLV_DATA(req_tlv_area);
2127 new_value = ntohl(args->value);
2128
Allan Stephens5c216e12011-10-18 11:34:29 -04002129 if (!link_value_is_valid(cmd, new_value))
2130 return tipc_cfg_reply_error_string(
2131 "cannot change, value invalid");
2132
Per Liden4323add2006-01-18 00:38:21 +01002133 if (!strcmp(args->name, tipc_bclink_name)) {
Per Lidenb97bf3f2006-01-02 19:04:38 +01002134 if ((cmd == TIPC_CMD_SET_LINK_WINDOW) &&
Ying Xue1da46562015-01-09 15:27:07 +08002135 (tipc_bclink_set_queue_limits(net, new_value) == 0))
Per Liden4323add2006-01-18 00:38:21 +01002136 return tipc_cfg_reply_none();
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002137 return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
Per Liden4323add2006-01-18 00:38:21 +01002138 " (cannot change setting on broadcast link)");
Per Lidenb97bf3f2006-01-02 19:04:38 +01002139 }
2140
Ying Xuef2f98002015-01-09 15:27:05 +08002141 res = link_cmd_set_value(net, args->name, new_value, cmd);
Per Lidenb97bf3f2006-01-02 19:04:38 +01002142 if (res)
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002143 return tipc_cfg_reply_error_string("cannot change link setting");
Per Lidenb97bf3f2006-01-02 19:04:38 +01002144
Per Liden4323add2006-01-18 00:38:21 +01002145 return tipc_cfg_reply_none();
Per Lidenb97bf3f2006-01-02 19:04:38 +01002146}
2147
2148/**
2149 * link_reset_statistics - reset link statistics
2150 * @l_ptr: pointer to link
2151 */
Paul Gortmakera18c4bc2011-12-29 20:58:42 -05002152static void link_reset_statistics(struct tipc_link *l_ptr)
Per Lidenb97bf3f2006-01-02 19:04:38 +01002153{
2154 memset(&l_ptr->stats, 0, sizeof(l_ptr->stats));
2155 l_ptr->stats.sent_info = l_ptr->next_out_no;
2156 l_ptr->stats.recv_info = l_ptr->next_in_no;
2157}
2158
Ying Xuef2f98002015-01-09 15:27:05 +08002159struct sk_buff *tipc_link_cmd_reset_stats(struct net *net,
2160 const void *req_tlv_area,
2161 int req_tlv_space)
Per Lidenb97bf3f2006-01-02 19:04:38 +01002162{
2163 char *link_name;
Paul Gortmakera18c4bc2011-12-29 20:58:42 -05002164 struct tipc_link *l_ptr;
David S. Miller6c000552008-09-02 23:38:32 -07002165 struct tipc_node *node;
Jon Paul Maloye099e862014-02-13 17:29:18 -05002166 unsigned int bearer_id;
Per Lidenb97bf3f2006-01-02 19:04:38 +01002167
2168 if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_LINK_NAME))
Per Liden4323add2006-01-18 00:38:21 +01002169 return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
Per Lidenb97bf3f2006-01-02 19:04:38 +01002170
2171 link_name = (char *)TLV_DATA(req_tlv_area);
Per Liden4323add2006-01-18 00:38:21 +01002172 if (!strcmp(link_name, tipc_bclink_name)) {
Ying Xue1da46562015-01-09 15:27:07 +08002173 if (tipc_bclink_reset_stats(net))
Per Liden4323add2006-01-18 00:38:21 +01002174 return tipc_cfg_reply_error_string("link not found");
2175 return tipc_cfg_reply_none();
Per Lidenb97bf3f2006-01-02 19:04:38 +01002176 }
Ying Xuef2f98002015-01-09 15:27:05 +08002177 node = tipc_link_find_owner(net, link_name, &bearer_id);
Ying Xue7216cd92014-04-21 10:55:48 +08002178 if (!node)
Per Liden4323add2006-01-18 00:38:21 +01002179 return tipc_cfg_reply_error_string("link not found");
Ying Xue7216cd92014-04-21 10:55:48 +08002180
Jon Paul Maloya11607f2014-02-14 16:40:44 -05002181 tipc_node_lock(node);
Jon Paul Maloye099e862014-02-13 17:29:18 -05002182 l_ptr = node->links[bearer_id];
2183 if (!l_ptr) {
2184 tipc_node_unlock(node);
Jon Paul Maloye099e862014-02-13 17:29:18 -05002185 return tipc_cfg_reply_error_string("link not found");
2186 }
Per Lidenb97bf3f2006-01-02 19:04:38 +01002187 link_reset_statistics(l_ptr);
Per Liden4323add2006-01-18 00:38:21 +01002188 tipc_node_unlock(node);
Per Liden4323add2006-01-18 00:38:21 +01002189 return tipc_cfg_reply_none();
Per Lidenb97bf3f2006-01-02 19:04:38 +01002190}
2191
2192/**
2193 * percent - convert count to a percentage of total (rounding up or down)
2194 */
Per Lidenb97bf3f2006-01-02 19:04:38 +01002195static u32 percent(u32 count, u32 total)
2196{
2197 return (count * 100 + (total / 2)) / total;
2198}
2199
2200/**
Per Liden4323add2006-01-18 00:38:21 +01002201 * tipc_link_stats - print link statistics
Ying Xuef2f98002015-01-09 15:27:05 +08002202 * @net: the applicable net namespace
Per Lidenb97bf3f2006-01-02 19:04:38 +01002203 * @name: link name
2204 * @buf: print buffer area
2205 * @buf_size: size of print buffer area
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002206 *
Per Lidenb97bf3f2006-01-02 19:04:38 +01002207 * Returns length of print buffer data string (or 0 if error)
2208 */
Ying Xuef2f98002015-01-09 15:27:05 +08002209static int tipc_link_stats(struct net *net, const char *name, char *buf,
2210 const u32 buf_size)
Per Lidenb97bf3f2006-01-02 19:04:38 +01002211{
Erik Hugnedc1aed32012-06-29 00:50:23 -04002212 struct tipc_link *l;
2213 struct tipc_stats *s;
David S. Miller6c000552008-09-02 23:38:32 -07002214 struct tipc_node *node;
Per Lidenb97bf3f2006-01-02 19:04:38 +01002215 char *status;
2216 u32 profile_total = 0;
Jon Paul Maloye099e862014-02-13 17:29:18 -05002217 unsigned int bearer_id;
Erik Hugnedc1aed32012-06-29 00:50:23 -04002218 int ret;
Per Lidenb97bf3f2006-01-02 19:04:38 +01002219
Per Liden4323add2006-01-18 00:38:21 +01002220 if (!strcmp(name, tipc_bclink_name))
Ying Xue1da46562015-01-09 15:27:07 +08002221 return tipc_bclink_stats(net, buf, buf_size);
Per Lidenb97bf3f2006-01-02 19:04:38 +01002222
Ying Xuef2f98002015-01-09 15:27:05 +08002223 node = tipc_link_find_owner(net, name, &bearer_id);
Ying Xue7216cd92014-04-21 10:55:48 +08002224 if (!node)
Per Lidenb97bf3f2006-01-02 19:04:38 +01002225 return 0;
Ying Xue7216cd92014-04-21 10:55:48 +08002226
Per Liden4323add2006-01-18 00:38:21 +01002227 tipc_node_lock(node);
Jon Paul Maloye099e862014-02-13 17:29:18 -05002228
2229 l = node->links[bearer_id];
2230 if (!l) {
2231 tipc_node_unlock(node);
Jon Paul Maloye099e862014-02-13 17:29:18 -05002232 return 0;
2233 }
2234
Erik Hugnedc1aed32012-06-29 00:50:23 -04002235 s = &l->stats;
Per Lidenb97bf3f2006-01-02 19:04:38 +01002236
Erik Hugnedc1aed32012-06-29 00:50:23 -04002237 if (tipc_link_is_active(l))
Per Lidenb97bf3f2006-01-02 19:04:38 +01002238 status = "ACTIVE";
Erik Hugnedc1aed32012-06-29 00:50:23 -04002239 else if (tipc_link_is_up(l))
Per Lidenb97bf3f2006-01-02 19:04:38 +01002240 status = "STANDBY";
2241 else
2242 status = "DEFUNCT";
Erik Hugnedc1aed32012-06-29 00:50:23 -04002243
2244 ret = tipc_snprintf(buf, buf_size, "Link <%s>\n"
2245 " %s MTU:%u Priority:%u Tolerance:%u ms"
2246 " Window:%u packets\n",
2247 l->name, status, l->max_pkt, l->priority,
2248 l->tolerance, l->queue_limit[0]);
2249
2250 ret += tipc_snprintf(buf + ret, buf_size - ret,
2251 " RX packets:%u fragments:%u/%u bundles:%u/%u\n",
2252 l->next_in_no - s->recv_info, s->recv_fragments,
2253 s->recv_fragmented, s->recv_bundles,
2254 s->recv_bundled);
2255
2256 ret += tipc_snprintf(buf + ret, buf_size - ret,
2257 " TX packets:%u fragments:%u/%u bundles:%u/%u\n",
2258 l->next_out_no - s->sent_info, s->sent_fragments,
2259 s->sent_fragmented, s->sent_bundles,
2260 s->sent_bundled);
2261
2262 profile_total = s->msg_length_counts;
Per Lidenb97bf3f2006-01-02 19:04:38 +01002263 if (!profile_total)
2264 profile_total = 1;
Erik Hugnedc1aed32012-06-29 00:50:23 -04002265
2266 ret += tipc_snprintf(buf + ret, buf_size - ret,
2267 " TX profile sample:%u packets average:%u octets\n"
2268 " 0-64:%u%% -256:%u%% -1024:%u%% -4096:%u%% "
2269 "-16384:%u%% -32768:%u%% -66000:%u%%\n",
2270 s->msg_length_counts,
2271 s->msg_lengths_total / profile_total,
2272 percent(s->msg_length_profile[0], profile_total),
2273 percent(s->msg_length_profile[1], profile_total),
2274 percent(s->msg_length_profile[2], profile_total),
2275 percent(s->msg_length_profile[3], profile_total),
2276 percent(s->msg_length_profile[4], profile_total),
2277 percent(s->msg_length_profile[5], profile_total),
2278 percent(s->msg_length_profile[6], profile_total));
2279
2280 ret += tipc_snprintf(buf + ret, buf_size - ret,
2281 " RX states:%u probes:%u naks:%u defs:%u"
2282 " dups:%u\n", s->recv_states, s->recv_probes,
2283 s->recv_nacks, s->deferred_recv, s->duplicates);
2284
2285 ret += tipc_snprintf(buf + ret, buf_size - ret,
2286 " TX states:%u probes:%u naks:%u acks:%u"
2287 " dups:%u\n", s->sent_states, s->sent_probes,
2288 s->sent_nacks, s->sent_acks, s->retransmitted);
2289
2290 ret += tipc_snprintf(buf + ret, buf_size - ret,
Ying Xue3c294cb2012-11-15 11:34:45 +08002291 " Congestion link:%u Send queue"
2292 " max:%u avg:%u\n", s->link_congs,
Erik Hugnedc1aed32012-06-29 00:50:23 -04002293 s->max_queue_sz, s->queue_sz_counts ?
2294 (s->accu_queue_sz / s->queue_sz_counts) : 0);
Per Lidenb97bf3f2006-01-02 19:04:38 +01002295
Per Liden4323add2006-01-18 00:38:21 +01002296 tipc_node_unlock(node);
Erik Hugnedc1aed32012-06-29 00:50:23 -04002297 return ret;
Per Lidenb97bf3f2006-01-02 19:04:38 +01002298}
2299
Ying Xuef2f98002015-01-09 15:27:05 +08002300struct sk_buff *tipc_link_cmd_show_stats(struct net *net,
2301 const void *req_tlv_area,
2302 int req_tlv_space)
Per Lidenb97bf3f2006-01-02 19:04:38 +01002303{
2304 struct sk_buff *buf;
2305 struct tlv_desc *rep_tlv;
2306 int str_len;
Erik Hugnedc1aed32012-06-29 00:50:23 -04002307 int pb_len;
2308 char *pb;
Per Lidenb97bf3f2006-01-02 19:04:38 +01002309
2310 if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_LINK_NAME))
Per Liden4323add2006-01-18 00:38:21 +01002311 return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
Per Lidenb97bf3f2006-01-02 19:04:38 +01002312
Erik Hugnedc1aed32012-06-29 00:50:23 -04002313 buf = tipc_cfg_reply_alloc(TLV_SPACE(ULTRA_STRING_MAX_LEN));
Per Lidenb97bf3f2006-01-02 19:04:38 +01002314 if (!buf)
2315 return NULL;
2316
2317 rep_tlv = (struct tlv_desc *)buf->data;
Erik Hugnedc1aed32012-06-29 00:50:23 -04002318 pb = TLV_DATA(rep_tlv);
2319 pb_len = ULTRA_STRING_MAX_LEN;
Ying Xuef2f98002015-01-09 15:27:05 +08002320 str_len = tipc_link_stats(net, (char *)TLV_DATA(req_tlv_area),
Erik Hugnedc1aed32012-06-29 00:50:23 -04002321 pb, pb_len);
Per Lidenb97bf3f2006-01-02 19:04:38 +01002322 if (!str_len) {
Allan Stephens5f6d9122011-11-04 13:24:29 -04002323 kfree_skb(buf);
YOSHIFUJI Hideakic4307282007-02-09 23:25:21 +09002324 return tipc_cfg_reply_error_string("link not found");
Per Lidenb97bf3f2006-01-02 19:04:38 +01002325 }
Erik Hugnedc1aed32012-06-29 00:50:23 -04002326 str_len += 1; /* for "\0" */
Per Lidenb97bf3f2006-01-02 19:04:38 +01002327 skb_put(buf, TLV_SPACE(str_len));
2328 TLV_SET(rep_tlv, TIPC_TLV_ULTRA_STRING, NULL, str_len);
2329
2330 return buf;
2331}
2332
Paul Gortmakera18c4bc2011-12-29 20:58:42 -05002333static void link_print(struct tipc_link *l_ptr, const char *str)
Per Lidenb97bf3f2006-01-02 19:04:38 +01002334{
Ying Xue7f9f95d2015-01-09 15:27:06 +08002335 struct tipc_net *tn = net_generic(l_ptr->owner->net, tipc_net_id);
Ying Xue7a2f7d12014-04-21 10:55:46 +08002336 struct tipc_bearer *b_ptr;
2337
2338 rcu_read_lock();
Ying Xue7f9f95d2015-01-09 15:27:06 +08002339 b_ptr = rcu_dereference_rtnl(tn->bearer_list[l_ptr->bearer_id]);
Ying Xue7a2f7d12014-04-21 10:55:46 +08002340 if (b_ptr)
2341 pr_info("%s Link %x<%s>:", str, l_ptr->addr, b_ptr->name);
2342 rcu_read_unlock();
Allan Stephens8d64a5b2010-12-31 18:59:27 +00002343
Per Lidenb97bf3f2006-01-02 19:04:38 +01002344 if (link_working_unknown(l_ptr))
Paul Gortmaker5deedde2012-07-11 19:27:56 -04002345 pr_cont(":WU\n");
Allan Stephens8d64a5b2010-12-31 18:59:27 +00002346 else if (link_reset_reset(l_ptr))
Paul Gortmaker5deedde2012-07-11 19:27:56 -04002347 pr_cont(":RR\n");
Allan Stephens8d64a5b2010-12-31 18:59:27 +00002348 else if (link_reset_unknown(l_ptr))
Paul Gortmaker5deedde2012-07-11 19:27:56 -04002349 pr_cont(":RU\n");
Allan Stephens8d64a5b2010-12-31 18:59:27 +00002350 else if (link_working_working(l_ptr))
Paul Gortmaker5deedde2012-07-11 19:27:56 -04002351 pr_cont(":WW\n");
2352 else
2353 pr_cont("\n");
Per Lidenb97bf3f2006-01-02 19:04:38 +01002354}
Richard Alpe0655f6a2014-11-20 10:29:07 +01002355
2356/* Parse and validate nested (link) properties valid for media, bearer and link
2357 */
2358int tipc_nl_parse_link_prop(struct nlattr *prop, struct nlattr *props[])
2359{
2360 int err;
2361
2362 err = nla_parse_nested(props, TIPC_NLA_PROP_MAX, prop,
2363 tipc_nl_prop_policy);
2364 if (err)
2365 return err;
2366
2367 if (props[TIPC_NLA_PROP_PRIO]) {
2368 u32 prio;
2369
2370 prio = nla_get_u32(props[TIPC_NLA_PROP_PRIO]);
2371 if (prio > TIPC_MAX_LINK_PRI)
2372 return -EINVAL;
2373 }
2374
2375 if (props[TIPC_NLA_PROP_TOL]) {
2376 u32 tol;
2377
2378 tol = nla_get_u32(props[TIPC_NLA_PROP_TOL]);
2379 if ((tol < TIPC_MIN_LINK_TOL) || (tol > TIPC_MAX_LINK_TOL))
2380 return -EINVAL;
2381 }
2382
2383 if (props[TIPC_NLA_PROP_WIN]) {
2384 u32 win;
2385
2386 win = nla_get_u32(props[TIPC_NLA_PROP_WIN]);
2387 if ((win < TIPC_MIN_LINK_WIN) || (win > TIPC_MAX_LINK_WIN))
2388 return -EINVAL;
2389 }
2390
2391 return 0;
2392}
Richard Alpe7be57fc2014-11-20 10:29:12 +01002393
Richard Alpef96ce7a2014-11-20 10:29:13 +01002394int tipc_nl_link_set(struct sk_buff *skb, struct genl_info *info)
2395{
2396 int err;
2397 int res = 0;
2398 int bearer_id;
2399 char *name;
2400 struct tipc_link *link;
2401 struct tipc_node *node;
2402 struct nlattr *attrs[TIPC_NLA_LINK_MAX + 1];
Ying Xuef2f98002015-01-09 15:27:05 +08002403 struct net *net = genl_info_net(info);
Richard Alpef96ce7a2014-11-20 10:29:13 +01002404
2405 if (!info->attrs[TIPC_NLA_LINK])
2406 return -EINVAL;
2407
2408 err = nla_parse_nested(attrs, TIPC_NLA_LINK_MAX,
2409 info->attrs[TIPC_NLA_LINK],
2410 tipc_nl_link_policy);
2411 if (err)
2412 return err;
2413
2414 if (!attrs[TIPC_NLA_LINK_NAME])
2415 return -EINVAL;
2416
2417 name = nla_data(attrs[TIPC_NLA_LINK_NAME]);
2418
Ying Xuef2f98002015-01-09 15:27:05 +08002419 node = tipc_link_find_owner(net, name, &bearer_id);
Richard Alpef96ce7a2014-11-20 10:29:13 +01002420 if (!node)
2421 return -EINVAL;
2422
2423 tipc_node_lock(node);
2424
2425 link = node->links[bearer_id];
2426 if (!link) {
2427 res = -EINVAL;
2428 goto out;
2429 }
2430
2431 if (attrs[TIPC_NLA_LINK_PROP]) {
2432 struct nlattr *props[TIPC_NLA_PROP_MAX + 1];
2433
2434 err = tipc_nl_parse_link_prop(attrs[TIPC_NLA_LINK_PROP],
2435 props);
2436 if (err) {
2437 res = err;
2438 goto out;
2439 }
2440
2441 if (props[TIPC_NLA_PROP_TOL]) {
2442 u32 tol;
2443
2444 tol = nla_get_u32(props[TIPC_NLA_PROP_TOL]);
2445 link_set_supervision_props(link, tol);
2446 tipc_link_proto_xmit(link, STATE_MSG, 0, 0, tol, 0, 0);
2447 }
2448 if (props[TIPC_NLA_PROP_PRIO]) {
2449 u32 prio;
2450
2451 prio = nla_get_u32(props[TIPC_NLA_PROP_PRIO]);
2452 link->priority = prio;
2453 tipc_link_proto_xmit(link, STATE_MSG, 0, 0, 0, prio, 0);
2454 }
2455 if (props[TIPC_NLA_PROP_WIN]) {
2456 u32 win;
2457
2458 win = nla_get_u32(props[TIPC_NLA_PROP_WIN]);
2459 tipc_link_set_queue_limits(link, win);
2460 }
2461 }
2462
2463out:
2464 tipc_node_unlock(node);
2465
2466 return res;
2467}
Richard Alped8182802014-11-24 11:10:29 +01002468
2469static int __tipc_nl_add_stats(struct sk_buff *skb, struct tipc_stats *s)
Richard Alpe7be57fc2014-11-20 10:29:12 +01002470{
2471 int i;
2472 struct nlattr *stats;
2473
2474 struct nla_map {
2475 u32 key;
2476 u32 val;
2477 };
2478
2479 struct nla_map map[] = {
2480 {TIPC_NLA_STATS_RX_INFO, s->recv_info},
2481 {TIPC_NLA_STATS_RX_FRAGMENTS, s->recv_fragments},
2482 {TIPC_NLA_STATS_RX_FRAGMENTED, s->recv_fragmented},
2483 {TIPC_NLA_STATS_RX_BUNDLES, s->recv_bundles},
2484 {TIPC_NLA_STATS_RX_BUNDLED, s->recv_bundled},
2485 {TIPC_NLA_STATS_TX_INFO, s->sent_info},
2486 {TIPC_NLA_STATS_TX_FRAGMENTS, s->sent_fragments},
2487 {TIPC_NLA_STATS_TX_FRAGMENTED, s->sent_fragmented},
2488 {TIPC_NLA_STATS_TX_BUNDLES, s->sent_bundles},
2489 {TIPC_NLA_STATS_TX_BUNDLED, s->sent_bundled},
2490 {TIPC_NLA_STATS_MSG_PROF_TOT, (s->msg_length_counts) ?
2491 s->msg_length_counts : 1},
2492 {TIPC_NLA_STATS_MSG_LEN_CNT, s->msg_length_counts},
2493 {TIPC_NLA_STATS_MSG_LEN_TOT, s->msg_lengths_total},
2494 {TIPC_NLA_STATS_MSG_LEN_P0, s->msg_length_profile[0]},
2495 {TIPC_NLA_STATS_MSG_LEN_P1, s->msg_length_profile[1]},
2496 {TIPC_NLA_STATS_MSG_LEN_P2, s->msg_length_profile[2]},
2497 {TIPC_NLA_STATS_MSG_LEN_P3, s->msg_length_profile[3]},
2498 {TIPC_NLA_STATS_MSG_LEN_P4, s->msg_length_profile[4]},
2499 {TIPC_NLA_STATS_MSG_LEN_P5, s->msg_length_profile[5]},
2500 {TIPC_NLA_STATS_MSG_LEN_P6, s->msg_length_profile[6]},
2501 {TIPC_NLA_STATS_RX_STATES, s->recv_states},
2502 {TIPC_NLA_STATS_RX_PROBES, s->recv_probes},
2503 {TIPC_NLA_STATS_RX_NACKS, s->recv_nacks},
2504 {TIPC_NLA_STATS_RX_DEFERRED, s->deferred_recv},
2505 {TIPC_NLA_STATS_TX_STATES, s->sent_states},
2506 {TIPC_NLA_STATS_TX_PROBES, s->sent_probes},
2507 {TIPC_NLA_STATS_TX_NACKS, s->sent_nacks},
2508 {TIPC_NLA_STATS_TX_ACKS, s->sent_acks},
2509 {TIPC_NLA_STATS_RETRANSMITTED, s->retransmitted},
2510 {TIPC_NLA_STATS_DUPLICATES, s->duplicates},
2511 {TIPC_NLA_STATS_LINK_CONGS, s->link_congs},
2512 {TIPC_NLA_STATS_MAX_QUEUE, s->max_queue_sz},
2513 {TIPC_NLA_STATS_AVG_QUEUE, s->queue_sz_counts ?
2514 (s->accu_queue_sz / s->queue_sz_counts) : 0}
2515 };
2516
2517 stats = nla_nest_start(skb, TIPC_NLA_LINK_STATS);
2518 if (!stats)
2519 return -EMSGSIZE;
2520
2521 for (i = 0; i < ARRAY_SIZE(map); i++)
2522 if (nla_put_u32(skb, map[i].key, map[i].val))
2523 goto msg_full;
2524
2525 nla_nest_end(skb, stats);
2526
2527 return 0;
2528msg_full:
2529 nla_nest_cancel(skb, stats);
2530
2531 return -EMSGSIZE;
2532}
2533
2534/* Caller should hold appropriate locks to protect the link */
Ying Xue34747532015-01-09 15:27:10 +08002535static int __tipc_nl_add_link(struct net *net, struct tipc_nl_msg *msg,
2536 struct tipc_link *link)
Richard Alpe7be57fc2014-11-20 10:29:12 +01002537{
2538 int err;
2539 void *hdr;
2540 struct nlattr *attrs;
2541 struct nlattr *prop;
Ying Xue34747532015-01-09 15:27:10 +08002542 struct tipc_net *tn = net_generic(net, tipc_net_id);
Richard Alpe7be57fc2014-11-20 10:29:12 +01002543
2544 hdr = genlmsg_put(msg->skb, msg->portid, msg->seq, &tipc_genl_v2_family,
2545 NLM_F_MULTI, TIPC_NL_LINK_GET);
2546 if (!hdr)
2547 return -EMSGSIZE;
2548
2549 attrs = nla_nest_start(msg->skb, TIPC_NLA_LINK);
2550 if (!attrs)
2551 goto msg_full;
2552
2553 if (nla_put_string(msg->skb, TIPC_NLA_LINK_NAME, link->name))
2554 goto attr_msg_full;
2555 if (nla_put_u32(msg->skb, TIPC_NLA_LINK_DEST,
Ying Xue34747532015-01-09 15:27:10 +08002556 tipc_cluster_mask(tn->own_addr)))
Richard Alpe7be57fc2014-11-20 10:29:12 +01002557 goto attr_msg_full;
2558 if (nla_put_u32(msg->skb, TIPC_NLA_LINK_MTU, link->max_pkt))
2559 goto attr_msg_full;
2560 if (nla_put_u32(msg->skb, TIPC_NLA_LINK_RX, link->next_in_no))
2561 goto attr_msg_full;
2562 if (nla_put_u32(msg->skb, TIPC_NLA_LINK_TX, link->next_out_no))
2563 goto attr_msg_full;
2564
2565 if (tipc_link_is_up(link))
2566 if (nla_put_flag(msg->skb, TIPC_NLA_LINK_UP))
2567 goto attr_msg_full;
2568 if (tipc_link_is_active(link))
2569 if (nla_put_flag(msg->skb, TIPC_NLA_LINK_ACTIVE))
2570 goto attr_msg_full;
2571
2572 prop = nla_nest_start(msg->skb, TIPC_NLA_LINK_PROP);
2573 if (!prop)
2574 goto attr_msg_full;
2575 if (nla_put_u32(msg->skb, TIPC_NLA_PROP_PRIO, link->priority))
2576 goto prop_msg_full;
2577 if (nla_put_u32(msg->skb, TIPC_NLA_PROP_TOL, link->tolerance))
2578 goto prop_msg_full;
2579 if (nla_put_u32(msg->skb, TIPC_NLA_PROP_WIN,
2580 link->queue_limit[TIPC_LOW_IMPORTANCE]))
2581 goto prop_msg_full;
2582 if (nla_put_u32(msg->skb, TIPC_NLA_PROP_PRIO, link->priority))
2583 goto prop_msg_full;
2584 nla_nest_end(msg->skb, prop);
2585
2586 err = __tipc_nl_add_stats(msg->skb, &link->stats);
2587 if (err)
2588 goto attr_msg_full;
2589
2590 nla_nest_end(msg->skb, attrs);
2591 genlmsg_end(msg->skb, hdr);
2592
2593 return 0;
2594
2595prop_msg_full:
2596 nla_nest_cancel(msg->skb, prop);
2597attr_msg_full:
2598 nla_nest_cancel(msg->skb, attrs);
2599msg_full:
2600 genlmsg_cancel(msg->skb, hdr);
2601
2602 return -EMSGSIZE;
2603}
2604
2605/* Caller should hold node lock */
Ying Xue34747532015-01-09 15:27:10 +08002606static int __tipc_nl_add_node_links(struct net *net, struct tipc_nl_msg *msg,
2607 struct tipc_node *node, u32 *prev_link)
Richard Alpe7be57fc2014-11-20 10:29:12 +01002608{
2609 u32 i;
2610 int err;
2611
2612 for (i = *prev_link; i < MAX_BEARERS; i++) {
2613 *prev_link = i;
2614
2615 if (!node->links[i])
2616 continue;
2617
Ying Xue34747532015-01-09 15:27:10 +08002618 err = __tipc_nl_add_link(net, msg, node->links[i]);
Richard Alpe7be57fc2014-11-20 10:29:12 +01002619 if (err)
2620 return err;
2621 }
2622 *prev_link = 0;
2623
2624 return 0;
2625}
2626
2627int tipc_nl_link_dump(struct sk_buff *skb, struct netlink_callback *cb)
2628{
Ying Xuef2f98002015-01-09 15:27:05 +08002629 struct net *net = sock_net(skb->sk);
2630 struct tipc_net *tn = net_generic(net, tipc_net_id);
Richard Alpe7be57fc2014-11-20 10:29:12 +01002631 struct tipc_node *node;
2632 struct tipc_nl_msg msg;
2633 u32 prev_node = cb->args[0];
2634 u32 prev_link = cb->args[1];
2635 int done = cb->args[2];
2636 int err;
2637
2638 if (done)
2639 return 0;
2640
2641 msg.skb = skb;
2642 msg.portid = NETLINK_CB(cb->skb).portid;
2643 msg.seq = cb->nlh->nlmsg_seq;
2644
2645 rcu_read_lock();
2646
2647 if (prev_node) {
Ying Xuef2f98002015-01-09 15:27:05 +08002648 node = tipc_node_find(net, prev_node);
Richard Alpe7be57fc2014-11-20 10:29:12 +01002649 if (!node) {
2650 /* We never set seq or call nl_dump_check_consistent()
2651 * this means that setting prev_seq here will cause the
2652 * consistence check to fail in the netlink callback
2653 * handler. Resulting in the last NLMSG_DONE message
2654 * having the NLM_F_DUMP_INTR flag set.
2655 */
2656 cb->prev_seq = 1;
2657 goto out;
2658 }
2659
Ying Xuef2f98002015-01-09 15:27:05 +08002660 list_for_each_entry_continue_rcu(node, &tn->node_list,
2661 list) {
Richard Alpe7be57fc2014-11-20 10:29:12 +01002662 tipc_node_lock(node);
Ying Xue34747532015-01-09 15:27:10 +08002663 err = __tipc_nl_add_node_links(net, &msg, node,
2664 &prev_link);
Richard Alpe7be57fc2014-11-20 10:29:12 +01002665 tipc_node_unlock(node);
2666 if (err)
2667 goto out;
2668
2669 prev_node = node->addr;
2670 }
2671 } else {
Ying Xue1da46562015-01-09 15:27:07 +08002672 err = tipc_nl_add_bc_link(net, &msg);
Richard Alpe7be57fc2014-11-20 10:29:12 +01002673 if (err)
2674 goto out;
2675
Ying Xuef2f98002015-01-09 15:27:05 +08002676 list_for_each_entry_rcu(node, &tn->node_list, list) {
Richard Alpe7be57fc2014-11-20 10:29:12 +01002677 tipc_node_lock(node);
Ying Xue34747532015-01-09 15:27:10 +08002678 err = __tipc_nl_add_node_links(net, &msg, node,
2679 &prev_link);
Richard Alpe7be57fc2014-11-20 10:29:12 +01002680 tipc_node_unlock(node);
2681 if (err)
2682 goto out;
2683
2684 prev_node = node->addr;
2685 }
2686 }
2687 done = 1;
2688out:
2689 rcu_read_unlock();
2690
2691 cb->args[0] = prev_node;
2692 cb->args[1] = prev_link;
2693 cb->args[2] = done;
2694
2695 return skb->len;
2696}
2697
2698int tipc_nl_link_get(struct sk_buff *skb, struct genl_info *info)
2699{
Ying Xuef2f98002015-01-09 15:27:05 +08002700 struct net *net = genl_info_net(info);
Richard Alpe7be57fc2014-11-20 10:29:12 +01002701 struct sk_buff *ans_skb;
2702 struct tipc_nl_msg msg;
2703 struct tipc_link *link;
2704 struct tipc_node *node;
2705 char *name;
2706 int bearer_id;
2707 int err;
2708
2709 if (!info->attrs[TIPC_NLA_LINK_NAME])
2710 return -EINVAL;
2711
2712 name = nla_data(info->attrs[TIPC_NLA_LINK_NAME]);
Ying Xuef2f98002015-01-09 15:27:05 +08002713 node = tipc_link_find_owner(net, name, &bearer_id);
Richard Alpe7be57fc2014-11-20 10:29:12 +01002714 if (!node)
2715 return -EINVAL;
2716
2717 ans_skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
2718 if (!ans_skb)
2719 return -ENOMEM;
2720
2721 msg.skb = ans_skb;
2722 msg.portid = info->snd_portid;
2723 msg.seq = info->snd_seq;
2724
2725 tipc_node_lock(node);
2726 link = node->links[bearer_id];
2727 if (!link) {
2728 err = -EINVAL;
2729 goto err_out;
2730 }
2731
Ying Xue34747532015-01-09 15:27:10 +08002732 err = __tipc_nl_add_link(net, &msg, link);
Richard Alpe7be57fc2014-11-20 10:29:12 +01002733 if (err)
2734 goto err_out;
2735
2736 tipc_node_unlock(node);
2737
2738 return genlmsg_reply(ans_skb, info);
2739
2740err_out:
2741 tipc_node_unlock(node);
2742 nlmsg_free(ans_skb);
2743
2744 return err;
2745}
Richard Alpeae363422014-11-20 10:29:14 +01002746
2747int tipc_nl_link_reset_stats(struct sk_buff *skb, struct genl_info *info)
2748{
2749 int err;
2750 char *link_name;
2751 unsigned int bearer_id;
2752 struct tipc_link *link;
2753 struct tipc_node *node;
2754 struct nlattr *attrs[TIPC_NLA_LINK_MAX + 1];
Ying Xuef2f98002015-01-09 15:27:05 +08002755 struct net *net = genl_info_net(info);
Richard Alpeae363422014-11-20 10:29:14 +01002756
2757 if (!info->attrs[TIPC_NLA_LINK])
2758 return -EINVAL;
2759
2760 err = nla_parse_nested(attrs, TIPC_NLA_LINK_MAX,
2761 info->attrs[TIPC_NLA_LINK],
2762 tipc_nl_link_policy);
2763 if (err)
2764 return err;
2765
2766 if (!attrs[TIPC_NLA_LINK_NAME])
2767 return -EINVAL;
2768
2769 link_name = nla_data(attrs[TIPC_NLA_LINK_NAME]);
2770
2771 if (strcmp(link_name, tipc_bclink_name) == 0) {
Ying Xue1da46562015-01-09 15:27:07 +08002772 err = tipc_bclink_reset_stats(net);
Richard Alpeae363422014-11-20 10:29:14 +01002773 if (err)
2774 return err;
2775 return 0;
2776 }
2777
Ying Xuef2f98002015-01-09 15:27:05 +08002778 node = tipc_link_find_owner(net, link_name, &bearer_id);
Richard Alpeae363422014-11-20 10:29:14 +01002779 if (!node)
2780 return -EINVAL;
2781
2782 tipc_node_lock(node);
2783
2784 link = node->links[bearer_id];
2785 if (!link) {
2786 tipc_node_unlock(node);
2787 return -EINVAL;
2788 }
2789
2790 link_reset_statistics(link);
2791
2792 tipc_node_unlock(node);
2793
2794 return 0;
2795}