aboutsummaryrefslogtreecommitdiffstats
path: root/net/tipc
diff options
context:
space:
mode:
authorPer Liden <per.liden@nospam.ericsson.com>2006-01-02 13:04:38 -0500
committerDavid S. Miller <davem@sunset.davemloft.net>2006-01-12 17:06:31 -0500
commitb97bf3fd8f6a16966d4f18983b2c40993ff937d4 (patch)
tree59959f8a0f3087455efdcb430846686f303c5991 /net/tipc
parent58cba4650a7a414eabd2b40cc9d8e45fcdf192d9 (diff)
[TIPC] Initial merge
TIPC (Transparent Inter Process Communication) is a protocol designed for intra cluster communication. For more information see http://tipc.sourceforge.net Signed-off-by: Per Liden <per.liden@nospam.ericsson.com>
Diffstat (limited to 'net/tipc')
-rw-r--r--net/tipc/Kconfig112
-rw-r--r--net/tipc/Makefile13
-rw-r--r--net/tipc/addr.c91
-rw-r--r--net/tipc/addr.h125
-rw-r--r--net/tipc/bcast.c803
-rw-r--r--net/tipc/bcast.h220
-rw-r--r--net/tipc/bearer.c689
-rw-r--r--net/tipc/bearer.h169
-rw-r--r--net/tipc/cluster.c573
-rw-r--r--net/tipc/cluster.h89
-rw-r--r--net/tipc/config.c715
-rw-r--r--net/tipc/config.h76
-rw-r--r--net/tipc/core.c282
-rw-r--r--net/tipc/core.h313
-rw-r--r--net/tipc/dbg.c392
-rw-r--r--net/tipc/dbg.h56
-rw-r--r--net/tipc/discover.c339
-rw-r--r--net/tipc/discover.h55
-rw-r--r--net/tipc/eth_media.c296
-rw-r--r--net/tipc/handler.c129
-rw-r--r--net/tipc/link.c3164
-rw-r--r--net/tipc/link.h293
-rw-r--r--net/tipc/msg.c331
-rw-r--r--net/tipc/msg.h815
-rw-r--r--net/tipc/name_distr.c306
-rw-r--r--net/tipc/name_distr.h45
-rw-r--r--net/tipc/name_table.c1076
-rw-r--r--net/tipc/name_table.h105
-rw-r--r--net/tipc/net.c308
-rw-r--r--net/tipc/net.h63
-rw-r--r--net/tipc/netlink.c107
-rw-r--r--net/tipc/node.c676
-rw-r--r--net/tipc/node.h141
-rw-r--r--net/tipc/node_subscr.c76
-rw-r--r--net/tipc/node_subscr.h60
-rw-r--r--net/tipc/port.c1704
-rw-r--r--net/tipc/port.h206
-rw-r--r--net/tipc/ref.c186
-rw-r--r--net/tipc/ref.h128
-rw-r--r--net/tipc/socket.c1722
-rw-r--r--net/tipc/subscr.c522
-rw-r--r--net/tipc/subscr.h77
-rw-r--r--net/tipc/user_reg.c262
-rw-r--r--net/tipc/user_reg.h45
-rw-r--r--net/tipc/zone.c166
-rw-r--r--net/tipc/zone.h68
46 files changed, 18189 insertions, 0 deletions
diff --git a/net/tipc/Kconfig b/net/tipc/Kconfig
new file mode 100644
index 000000000000..05ab18e62dee
--- /dev/null
+++ b/net/tipc/Kconfig
@@ -0,0 +1,112 @@
1#
2# TIPC configuration
3#
4
5menu "TIPC Configuration (EXPERIMENTAL)"
6 depends on INET && EXPERIMENTAL
7
8config TIPC
9 tristate "The TIPC Protocol (EXPERIMENTAL)"
10 ---help---
11 TBD.
12
13 This protocol support is also available as a module ( = code which
14 can be inserted in and removed from the running kernel whenever you
15 want). The module will be called tipc. If you want to compile it
16 as a module, say M here and read <file:Documentation/modules.txt>.
17
18 If in doubt, say N.
19
20config TIPC_ADVANCED
21 bool "TIPC: Advanced configuration"
22 depends on TIPC
23 default n
24 help
25 Saying Y here will open some advanced configuration
26 for TIPC. Most users do not need to bother, so if
27 unsure, just say N.
28
29config TIPC_ZONES
30 int "Maximum number of zones in network"
31 depends on TIPC && TIPC_ADVANCED
32 default "3"
33 help
34 Max number of zones inside TIPC network. Max supported value
35 is 255 zones, minimum is 1
36
37 Default is 3 zones in a network; setting this to higher
38 allows more zones but might use more memory.
39
40config TIPC_CLUSTERS
41 int "Maximum number of clusters in a zone"
42 depends on TIPC && TIPC_ADVANCED
43 default "1"
44 help
45 ***Only 1 (one cluster in a zone) is supported by current code.
46 Any value set here will be overridden.***
47
48 (Max number of clusters inside TIPC zone. Max supported
49 value is 4095 clusters, minimum is 1.
50
51 Default is 1; setting this to smaller value might save
52 some memory, setting it to higher
53 allows more clusters and might consume more memory.)
54
55config TIPC_NODES
56 int "Maximum number of nodes in cluster"
57 depends on TIPC && TIPC_ADVANCED
58 default "255"
59 help
60 Maximum number of nodes inside a TIPC cluster. Maximum
61 supported value is 2047 nodes, minimum is 8.
62
63 Setting this to a smaller value saves some memory,
64 setting it to higher allows more nodes.
65
66config TIPC_SLAVE_NODES
67 int "Maximum number of slave nodes in cluster"
68 depends on TIPC && TIPC_ADVANCED
69 default "0"
70 help
71 ***This capability is not supported by current code.***
72
73 Maximum number of slave nodes inside a TIPC cluster. Maximum
74 supported value is 2047 nodes, minimum is 0.
75
76 Setting this to a smaller value saves some memory,
77 setting it to higher allows more nodes.
78
79config TIPC_PORTS
80 int "Maximum number of ports in a node"
81 depends on TIPC && TIPC_ADVANCED
82 default "8191"
83 help
84 Maximum number of ports within a node. Maximum
85 supported value is 64535 nodes, minimum is 127.
86
87 Setting this to a smaller value saves some memory,
88 setting it to higher allows more ports.
89
90config TIPC_LOG
91 int "Size of log buffer"
92 depends on TIPC && TIPC_ADVANCED
93 default 0
94 help
95 Size (in bytes) of TIPC's internal log buffer, which records the
96 occurrence of significant events. Maximum supported value
97 is 32768 bytes, minimum is 0.
98
99 There is no need to enable the log buffer unless the node will be
100 managed remotely via TIPC.
101
102config TIPC_DEBUG
103 bool "Enable debugging support"
104 depends on TIPC
105 default n
106 help
107 This will enable debugging of TIPC.
108
109 Only say Y here if you are having trouble with TIPC. It will
110 enable the display of detailed information about what is going on.
111
112endmenu
diff --git a/net/tipc/Makefile b/net/tipc/Makefile
new file mode 100644
index 000000000000..dceb7027946c
--- /dev/null
+++ b/net/tipc/Makefile
@@ -0,0 +1,13 @@
1#
2# Makefile for the Linux TIPC layer
3#
4
5obj-$(CONFIG_TIPC) := tipc.o
6
7tipc-y += addr.o bcast.o bearer.o config.o cluster.o \
8 core.o handler.o link.o discover.o msg.o \
9 name_distr.o subscr.o name_table.o net.o \
10 netlink.o node.o node_subscr.o port.o ref.o \
11 socket.o user_reg.o zone.o dbg.o eth_media.o
12
13# End of file
diff --git a/net/tipc/addr.c b/net/tipc/addr.c
new file mode 100644
index 000000000000..bc353639562a
--- /dev/null
+++ b/net/tipc/addr.c
@@ -0,0 +1,91 @@
1/*
2 * net/tipc/addr.c: TIPC address utility routines
3 *
4 * Copyright (c) 2003-2005, Ericsson Research Canada
5 * Copyright (c) 2004-2005, Wind River Systems
6 * Copyright (c) 2005-2006, Ericsson AB
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions are met:
11 *
12 * Redistributions of source code must retain the above copyright notice, this
13 * list of conditions and the following disclaimer.
14 * Redistributions in binary form must reproduce the above copyright notice,
15 * this list of conditions and the following disclaimer in the documentation
16 * and/or other materials provided with the distribution.
17 * Neither the names of the copyright holders nor the names of its
18 * contributors may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 */
33
34#include "core.h"
35#include "dbg.h"
36#include "addr.h"
37#include "zone.h"
38#include "cluster.h"
39#include "net.h"
40
41u32 tipc_get_addr(void)
42{
43 return tipc_own_addr;
44}
45
46/**
47 * addr_domain_valid - validates a network domain address
48 *
49 * Accepts <Z.C.N>, <Z.C.0>, <Z.0.0>, and <0.0.0>,
50 * where Z, C, and N are non-zero and do not exceed the configured limits.
51 *
52 * Returns 1 if domain address is valid, otherwise 0
53 */
54
55int addr_domain_valid(u32 addr)
56{
57 u32 n = tipc_node(addr);
58 u32 c = tipc_cluster(addr);
59 u32 z = tipc_zone(addr);
60 u32 max_nodes = tipc_max_nodes;
61
62 if (is_slave(addr))
63 max_nodes = LOWEST_SLAVE + tipc_max_slaves;
64 if (n > max_nodes)
65 return 0;
66 if (c > tipc_max_clusters)
67 return 0;
68 if (z > tipc_max_zones)
69 return 0;
70
71 if (n && (!z || !c))
72 return 0;
73 if (c && !z)
74 return 0;
75 return 1;
76}
77
78/**
79 * addr_node_valid - validates a proposed network address for this node
80 *
81 * Accepts <Z.C.N>, where Z, C, and N are non-zero and do not exceed
82 * the configured limits.
83 *
84 * Returns 1 if address can be used, otherwise 0
85 */
86
87int addr_node_valid(u32 addr)
88{
89 return (addr_domain_valid(addr) && tipc_node(addr));
90}
91
diff --git a/net/tipc/addr.h b/net/tipc/addr.h
new file mode 100644
index 000000000000..9dabebcba6de
--- /dev/null
+++ b/net/tipc/addr.h
@@ -0,0 +1,125 @@
1/*
2 * net/tipc/addr.h: Include file for TIPC address utility routines
3 *
4 * Copyright (c) 2003-2005, Ericsson Research Canada
5 * Copyright (c) 2004-2005, Wind River Systems
6 * Copyright (c) 2005-2006, Ericsson AB
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions are met:
11 *
12 * Redistributions of source code must retain the above copyright notice, this
13 * list of conditions and the following disclaimer.
14 * Redistributions in binary form must reproduce the above copyright notice,
15 * this list of conditions and the following disclaimer in the documentation
16 * and/or other materials provided with the distribution.
17 * Neither the names of the copyright holders nor the names of its
18 * contributors may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 */
33
34#ifndef _TIPC_ADDR_H
35#define _TIPC_ADDR_H
36
37static inline u32 own_node(void)
38{
39 return tipc_node(tipc_own_addr);
40}
41
42static inline u32 own_cluster(void)
43{
44 return tipc_cluster(tipc_own_addr);
45}
46
47static inline u32 own_zone(void)
48{
49 return tipc_zone(tipc_own_addr);
50}
51
52static inline int in_own_cluster(u32 addr)
53{
54 return !((addr ^ tipc_own_addr) >> 12);
55}
56
57static inline int in_own_zone(u32 addr)
58{
59 return !((addr ^ tipc_own_addr) >> 24);
60}
61
62static inline int is_slave(u32 addr)
63{
64 return addr & 0x800;
65}
66
67static inline int may_route(u32 addr)
68{
69 return(addr ^ tipc_own_addr) >> 11;
70}
71
72static inline int in_scope(u32 domain, u32 addr)
73{
74 if (!domain || (domain == addr))
75 return 1;
76 if (domain == (addr & 0xfffff000u)) /* domain <Z.C.0> */
77 return 1;
78 if (domain == (addr & 0xff000000u)) /* domain <Z.0.0> */
79 return 1;
80 return 0;
81}
82
83/**
84 * addr_scope - convert message lookup domain to equivalent 2-bit scope value
85 */
86
87static inline int addr_scope(u32 domain)
88{
89 if (likely(!domain))
90 return TIPC_ZONE_SCOPE;
91 if (tipc_node(domain))
92 return TIPC_NODE_SCOPE;
93 if (tipc_cluster(domain))
94 return TIPC_CLUSTER_SCOPE;
95 return TIPC_ZONE_SCOPE;
96}
97
98/**
99 * addr_domain - convert 2-bit scope value to equivalent message lookup domain
100 *
101 * Needed when address of a named message must be looked up a second time
102 * after a network hop.
103 */
104
105static inline int addr_domain(int sc)
106{
107 if (likely(sc == TIPC_NODE_SCOPE))
108 return tipc_own_addr;
109 if (sc == TIPC_CLUSTER_SCOPE)
110 return tipc_addr(tipc_zone(tipc_own_addr),
111 tipc_cluster(tipc_own_addr), 0);
112 return tipc_addr(tipc_zone(tipc_own_addr), 0, 0);
113}
114
115static inline char *addr_string_fill(char *string, u32 addr)
116{
117 snprintf(string, 16, "<%u.%u.%u>",
118 tipc_zone(addr), tipc_cluster(addr), tipc_node(addr));
119 return string;
120}
121
122int addr_domain_valid(u32);
123int addr_node_valid(u32 addr);
124
125#endif
diff --git a/net/tipc/bcast.c b/net/tipc/bcast.c
new file mode 100644
index 000000000000..35ca90667a59
--- /dev/null
+++ b/net/tipc/bcast.c
@@ -0,0 +1,803 @@
1/*
2 * net/tipc/bcast.c: TIPC broadcast code
3 *
4 * Copyright (c) 2003-2005, Ericsson Research Canada
5 * Copyright (c) 2004, Intel Corporation.
6 * Copyright (c) 2005, Wind River Systems
7 * Copyright (c) 2005-2006, Ericsson AB
8 * All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions are met:
12 *
13 * Redistributions of source code must retain the above copyright notice, this
14 * list of conditions and the following disclaimer.
15 * Redistributions in binary form must reproduce the above copyright notice,
16 * this list of conditions and the following disclaimer in the documentation
17 * and/or other materials provided with the distribution.
18 * Neither the names of the copyright holders nor the names of its
19 * contributors may be used to endorse or promote products derived from this
20 * software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
26 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 * POSSIBILITY OF SUCH DAMAGE.
33 */
34
35#include "core.h"
36#include "msg.h"
37#include "dbg.h"
38#include "link.h"
39#include "net.h"
40#include "node.h"
41#include "port.h"
42#include "addr.h"
43#include "node_subscr.h"
44#include "name_distr.h"
45#include "bearer.h"
46#include "name_table.h"
47#include "bcast.h"
48
49
50#define MAX_PKT_DEFAULT_MCAST 1500 /* bcast link max packet size (fixed) */
51
52#define BCLINK_WIN_DEFAULT 20 /* bcast link window size (default) */
53
54#define BCLINK_LOG_BUF_SIZE 0
55
56/**
57 * struct bcbearer_pair - a pair of bearers used by broadcast link
58 * @primary: pointer to primary bearer
59 * @secondary: pointer to secondary bearer
60 *
61 * Bearers must have same priority and same set of reachable destinations
62 * to be paired.
63 */
64
65struct bcbearer_pair {
66 struct bearer *primary;
67 struct bearer *secondary;
68};
69
70/**
71 * struct bcbearer - bearer used by broadcast link
72 * @bearer: (non-standard) broadcast bearer structure
73 * @media: (non-standard) broadcast media structure
74 * @bpairs: array of bearer pairs
75 * @bpairs_temp: array of bearer pairs used during creation of "bpairs"
76 */
77
78struct bcbearer {
79 struct bearer bearer;
80 struct media media;
81 struct bcbearer_pair bpairs[MAX_BEARERS];
82 struct bcbearer_pair bpairs_temp[TIPC_NUM_LINK_PRI];
83};
84
85/**
86 * struct bclink - link used for broadcast messages
87 * @link: (non-standard) broadcast link structure
88 * @node: (non-standard) node structure representing b'cast link's peer node
89 *
90 * Handles sequence numbering, fragmentation, bundling, etc.
91 */
92
93struct bclink {
94 struct link link;
95 struct node node;
96};
97
98
99static struct bcbearer *bcbearer = NULL;
100static struct bclink *bclink = NULL;
101static struct link *bcl = NULL;
102static spinlock_t bc_lock = SPIN_LOCK_UNLOCKED;
103
104char bc_link_name[] = "multicast-link";
105
106
107static inline u32 buf_seqno(struct sk_buff *buf)
108{
109 return msg_seqno(buf_msg(buf));
110}
111
112static inline u32 bcbuf_acks(struct sk_buff *buf)
113{
114 return (u32)TIPC_SKB_CB(buf)->handle;
115}
116
117static inline void bcbuf_set_acks(struct sk_buff *buf, u32 acks)
118{
119 TIPC_SKB_CB(buf)->handle = (void *)acks;
120}
121
122static inline void bcbuf_decr_acks(struct sk_buff *buf)
123{
124 bcbuf_set_acks(buf, bcbuf_acks(buf) - 1);
125}
126
127
128/**
129 * bclink_set_gap - set gap according to contents of current deferred pkt queue
130 *
131 * Called with 'node' locked, bc_lock unlocked
132 */
133
134static inline void bclink_set_gap(struct node *n_ptr)
135{
136 struct sk_buff *buf = n_ptr->bclink.deferred_head;
137
138 n_ptr->bclink.gap_after = n_ptr->bclink.gap_to =
139 mod(n_ptr->bclink.last_in);
140 if (unlikely(buf != NULL))
141 n_ptr->bclink.gap_to = mod(buf_seqno(buf) - 1);
142}
143
144/**
145 * bclink_ack_allowed - test if ACK or NACK message can be sent at this moment
146 *
147 * This mechanism endeavours to prevent all nodes in network from trying
148 * to ACK or NACK at the same time.
149 *
150 * Note: TIPC uses a different trigger to distribute ACKs than it does to
151 * distribute NACKs, but tries to use the same spacing (divide by 16).
152 */
153
154static inline int bclink_ack_allowed(u32 n)
155{
156 return((n % TIPC_MIN_LINK_WIN) == tipc_own_tag);
157}
158
159
160/**
161 * bclink_retransmit_pkt - retransmit broadcast packets
162 * @after: sequence number of last packet to *not* retransmit
163 * @to: sequence number of last packet to retransmit
164 *
165 * Called with 'node' locked, bc_lock unlocked
166 */
167
168static void bclink_retransmit_pkt(u32 after, u32 to)
169{
170 struct sk_buff *buf;
171
172 spin_lock_bh(&bc_lock);
173 buf = bcl->first_out;
174 while (buf && less_eq(buf_seqno(buf), after)) {
175 buf = buf->next;
176 }
177 if (buf != NULL)
178 link_retransmit(bcl, buf, mod(to - after));
179 spin_unlock_bh(&bc_lock);
180}
181
182/**
183 * bclink_acknowledge - handle acknowledgement of broadcast packets
184 * @n_ptr: node that sent acknowledgement info
185 * @acked: broadcast sequence # that has been acknowledged
186 *
187 * Node is locked, bc_lock unlocked.
188 */
189
190void bclink_acknowledge(struct node *n_ptr, u32 acked)
191{
192 struct sk_buff *crs;
193 struct sk_buff *next;
194 unsigned int released = 0;
195
196 if (less_eq(acked, n_ptr->bclink.acked))
197 return;
198
199 spin_lock_bh(&bc_lock);
200
201 /* Skip over packets that node has previously acknowledged */
202
203 crs = bcl->first_out;
204 while (crs && less_eq(buf_seqno(crs), n_ptr->bclink.acked)) {
205 crs = crs->next;
206 }
207
208 /* Update packets that node is now acknowledging */
209
210 while (crs && less_eq(buf_seqno(crs), acked)) {
211 next = crs->next;
212 bcbuf_decr_acks(crs);
213 if (bcbuf_acks(crs) == 0) {
214 bcl->first_out = next;
215 bcl->out_queue_size--;
216 buf_discard(crs);
217 released = 1;
218 }
219 crs = next;
220 }
221 n_ptr->bclink.acked = acked;
222
223 /* Try resolving broadcast link congestion, if necessary */
224
225 if (unlikely(bcl->next_out))
226 link_push_queue(bcl);
227 if (unlikely(released && !list_empty(&bcl->waiting_ports)))
228 link_wakeup_ports(bcl, 0);
229 spin_unlock_bh(&bc_lock);
230}
231
232/**
233 * bclink_send_ack - unicast an ACK msg
234 *
235 * net_lock and node lock set
236 */
237
238static void bclink_send_ack(struct node *n_ptr)
239{
240 struct link *l_ptr = n_ptr->active_links[n_ptr->addr & 1];
241
242 if (l_ptr != NULL)
243 link_send_proto_msg(l_ptr, STATE_MSG, 0, 0, 0, 0, 0);
244}
245
246/**
247 * bclink_send_nack- broadcast a NACK msg
248 *
249 * net_lock and node lock set
250 */
251
252static void bclink_send_nack(struct node *n_ptr)
253{
254 struct sk_buff *buf;
255 struct tipc_msg *msg;
256
257 if (!less(n_ptr->bclink.gap_after, n_ptr->bclink.gap_to))
258 return;
259
260 buf = buf_acquire(INT_H_SIZE);
261 if (buf) {
262 msg = buf_msg(buf);
263 msg_init(msg, BCAST_PROTOCOL, STATE_MSG,
264 TIPC_OK, INT_H_SIZE, n_ptr->addr);
265 msg_set_mc_netid(msg, tipc_net_id);
266 msg_set_bcast_ack(msg, mod(n_ptr->bclink.last_in));
267 msg_set_bcgap_after(msg, n_ptr->bclink.gap_after);
268 msg_set_bcgap_to(msg, n_ptr->bclink.gap_to);
269 msg_set_bcast_tag(msg, tipc_own_tag);
270
271 if (bearer_send(&bcbearer->bearer, buf, 0)) {
272 bcl->stats.sent_nacks++;
273 buf_discard(buf);
274 } else {
275 bearer_schedule(bcl->b_ptr, bcl);
276 bcl->proto_msg_queue = buf;
277 bcl->stats.bearer_congs++;
278 }
279
280 /*
281 * Ensure we doesn't send another NACK msg to the node
282 * until 16 more deferred messages arrive from it
283 * (i.e. helps prevent all nodes from NACK'ing at same time)
284 */
285
286 n_ptr->bclink.nack_sync = tipc_own_tag;
287 }
288}
289
290/**
291 * bclink_check_gap - send a NACK if a sequence gap exists
292 *
293 * net_lock and node lock set
294 */
295
296void bclink_check_gap(struct node *n_ptr, u32 last_sent)
297{
298 if (!n_ptr->bclink.supported ||
299 less_eq(last_sent, mod(n_ptr->bclink.last_in)))
300 return;
301
302 bclink_set_gap(n_ptr);
303 if (n_ptr->bclink.gap_after == n_ptr->bclink.gap_to)
304 n_ptr->bclink.gap_to = last_sent;
305 bclink_send_nack(n_ptr);
306}
307
308/**
309 * bclink_peek_nack - process a NACK msg meant for another node
310 *
311 * Only net_lock set.
312 */
313
314void bclink_peek_nack(u32 dest, u32 sender_tag, u32 gap_after, u32 gap_to)
315{
316 struct node *n_ptr = node_find(dest);
317 u32 my_after, my_to;
318
319 if (unlikely(!n_ptr || !node_is_up(n_ptr)))
320 return;
321 node_lock(n_ptr);
322 /*
323 * Modify gap to suppress unnecessary NACKs from this node
324 */
325 my_after = n_ptr->bclink.gap_after;
326 my_to = n_ptr->bclink.gap_to;
327
328 if (less_eq(gap_after, my_after)) {
329 if (less(my_after, gap_to) && less(gap_to, my_to))
330 n_ptr->bclink.gap_after = gap_to;
331 else if (less_eq(my_to, gap_to))
332 n_ptr->bclink.gap_to = n_ptr->bclink.gap_after;
333 } else if (less_eq(gap_after, my_to)) {
334 if (less_eq(my_to, gap_to))
335 n_ptr->bclink.gap_to = gap_after;
336 } else {
337 /*
338 * Expand gap if missing bufs not in deferred queue:
339 */
340 struct sk_buff *buf = n_ptr->bclink.deferred_head;
341 u32 prev = n_ptr->bclink.gap_to;
342
343 for (; buf; buf = buf->next) {
344 u32 seqno = buf_seqno(buf);
345
346 if (mod(seqno - prev) != 1)
347 buf = NULL;
348 if (seqno == gap_after)
349 break;
350 prev = seqno;
351 }
352 if (buf == NULL)
353 n_ptr->bclink.gap_to = gap_after;
354 }
355 /*
356 * Some nodes may send a complementary NACK now:
357 */
358 if (bclink_ack_allowed(sender_tag + 1)) {
359 if (n_ptr->bclink.gap_to != n_ptr->bclink.gap_after) {
360 bclink_send_nack(n_ptr);
361 bclink_set_gap(n_ptr);
362 }
363 }
364 node_unlock(n_ptr);
365}
366
367/**
368 * bclink_send_msg - broadcast a packet to all nodes in cluster
369 */
370
371int bclink_send_msg(struct sk_buff *buf)
372{
373 int res;
374
375 spin_lock_bh(&bc_lock);
376
377 res = link_send_buf(bcl, buf);
378 if (unlikely(res == -ELINKCONG))
379 buf_discard(buf);
380 else
381 bcl->stats.sent_info++;
382
383 if (bcl->out_queue_size > bcl->stats.max_queue_sz)
384 bcl->stats.max_queue_sz = bcl->out_queue_size;
385 bcl->stats.queue_sz_counts++;
386 bcl->stats.accu_queue_sz += bcl->out_queue_size;
387
388 spin_unlock_bh(&bc_lock);
389 return res;
390}
391
392/**
393 * bclink_recv_pkt - receive a broadcast packet, and deliver upwards
394 *
395 * net_lock is read_locked, no other locks set
396 */
397
398void bclink_recv_pkt(struct sk_buff *buf)
399{
400 struct tipc_msg *msg = buf_msg(buf);
401 struct node* node = node_find(msg_prevnode(msg));
402 u32 next_in;
403 u32 seqno;
404 struct sk_buff *deferred;
405
406 msg_dbg(msg, "<BC<<<");
407
408 if (unlikely(!node || !node_is_up(node) || !node->bclink.supported ||
409 (msg_mc_netid(msg) != tipc_net_id))) {
410 buf_discard(buf);
411 return;
412 }
413
414 if (unlikely(msg_user(msg) == BCAST_PROTOCOL)) {
415 msg_dbg(msg, "<BCNACK<<<");
416 if (msg_destnode(msg) == tipc_own_addr) {
417 node_lock(node);
418 bclink_acknowledge(node, msg_bcast_ack(msg));
419 node_unlock(node);
420 bcl->stats.recv_nacks++;
421 bclink_retransmit_pkt(msg_bcgap_after(msg),
422 msg_bcgap_to(msg));
423 } else {
424 bclink_peek_nack(msg_destnode(msg),
425 msg_bcast_tag(msg),
426 msg_bcgap_after(msg),
427 msg_bcgap_to(msg));
428 }
429 buf_discard(buf);
430 return;
431 }
432
433 node_lock(node);
434receive:
435 deferred = node->bclink.deferred_head;
436 next_in = mod(node->bclink.last_in + 1);
437 seqno = msg_seqno(msg);
438
439 if (likely(seqno == next_in)) {
440 bcl->stats.recv_info++;
441 node->bclink.last_in++;
442 bclink_set_gap(node);
443 if (unlikely(bclink_ack_allowed(seqno))) {
444 bclink_send_ack(node);
445 bcl->stats.sent_acks++;
446 }
447 if (likely(msg_isdata(msg))) {
448 node_unlock(node);
449 port_recv_mcast(buf, NULL);
450 } else if (msg_user(msg) == MSG_BUNDLER) {
451 bcl->stats.recv_bundles++;
452 bcl->stats.recv_bundled += msg_msgcnt(msg);
453 node_unlock(node);
454 link_recv_bundle(buf);
455 } else if (msg_user(msg) == MSG_FRAGMENTER) {
456 bcl->stats.recv_fragments++;
457 if (link_recv_fragment(&node->bclink.defragm,
458 &buf, &msg))
459 bcl->stats.recv_fragmented++;
460 node_unlock(node);
461 net_route_msg(buf);
462 } else {
463 node_unlock(node);
464 net_route_msg(buf);
465 }
466 if (deferred && (buf_seqno(deferred) == mod(next_in + 1))) {
467 node_lock(node);
468 buf = deferred;
469 msg = buf_msg(buf);
470 node->bclink.deferred_head = deferred->next;
471 goto receive;
472 }
473 return;
474 } else if (less(next_in, seqno)) {
475 u32 gap_after = node->bclink.gap_after;
476 u32 gap_to = node->bclink.gap_to;
477
478 if (link_defer_pkt(&node->bclink.deferred_head,
479 &node->bclink.deferred_tail,
480 buf)) {
481 node->bclink.nack_sync++;
482 bcl->stats.deferred_recv++;
483 if (seqno == mod(gap_after + 1))
484 node->bclink.gap_after = seqno;
485 else if (less(gap_after, seqno) && less(seqno, gap_to))
486 node->bclink.gap_to = seqno;
487 }
488 if (bclink_ack_allowed(node->bclink.nack_sync)) {
489 if (gap_to != gap_after)
490 bclink_send_nack(node);
491 bclink_set_gap(node);
492 }
493 } else {
494 bcl->stats.duplicates++;
495 buf_discard(buf);
496 }
497 node_unlock(node);
498}
499
500u32 bclink_get_last_sent(void)
501{
502 u32 last_sent = mod(bcl->next_out_no - 1);
503
504 if (bcl->next_out)
505 last_sent = mod(buf_seqno(bcl->next_out) - 1);
506 return last_sent;
507}
508
509u32 bclink_acks_missing(struct node *n_ptr)
510{
511 return (n_ptr->bclink.supported &&
512 (bclink_get_last_sent() != n_ptr->bclink.acked));
513}
514
515
516/**
517 * bcbearer_send - send a packet through the broadcast pseudo-bearer
518 *
519 * Send through as many bearers as necessary to reach all nodes
520 * that support TIPC multicasting.
521 *
522 * Returns 0 if packet sent successfully, non-zero if not
523 */
524
525int bcbearer_send(struct sk_buff *buf,
526 struct tipc_bearer *unused1,
527 struct tipc_media_addr *unused2)
528{
529 static int send_count = 0;
530
531 struct node_map remains;
532 struct node_map remains_new;
533 int bp_index;
534 int swap_time;
535
536 /* Prepare buffer for broadcasting (if first time trying to send it) */
537
538 if (likely(!msg_non_seq(buf_msg(buf)))) {
539 struct tipc_msg *msg;
540
541 assert(cluster_bcast_nodes.count != 0);
542 bcbuf_set_acks(buf, cluster_bcast_nodes.count);
543 msg = buf_msg(buf);
544 msg_set_non_seq(msg);
545 msg_set_mc_netid(msg, tipc_net_id);
546 }
547
548 /* Determine if bearer pairs should be swapped following this attempt */
549
550 if ((swap_time = (++send_count >= 10)))
551 send_count = 0;
552
553 /* Send buffer over bearers until all targets reached */
554
555 remains = cluster_bcast_nodes;
556
557 for (bp_index = 0; bp_index < MAX_BEARERS; bp_index++) {
558 struct bearer *p = bcbearer->bpairs[bp_index].primary;
559 struct bearer *s = bcbearer->bpairs[bp_index].secondary;
560
561 if (!p)
562 break; /* no more bearers to try */
563
564 nmap_diff(&remains, &p->nodes, &remains_new);
565 if (remains_new.count == remains.count)
566 continue; /* bearer pair doesn't add anything */
567
568 if (!p->publ.blocked &&
569 !p->media->send_msg(buf, &p->publ, &p->media->bcast_addr)) {
570 if (swap_time && s && !s->publ.blocked)
571 goto swap;
572 else
573 goto update;
574 }
575
576 if (!s || s->publ.blocked ||
577 s->media->send_msg(buf, &s->publ, &s->media->bcast_addr))
578 continue; /* unable to send using bearer pair */
579swap:
580 bcbearer->bpairs[bp_index].primary = s;
581 bcbearer->bpairs[bp_index].secondary = p;
582update:
583 if (remains_new.count == 0)
584 return TIPC_OK;
585
586 remains = remains_new;
587 }
588
589 /* Unable to reach all targets */
590
591 bcbearer->bearer.publ.blocked = 1;
592 bcl->stats.bearer_congs++;
593 return ~TIPC_OK;
594}
595
596/**
597 * bcbearer_sort - create sets of bearer pairs used by broadcast bearer
598 */
599
600void bcbearer_sort(void)
601{
602 struct bcbearer_pair *bp_temp = bcbearer->bpairs_temp;
603 struct bcbearer_pair *bp_curr;
604 int b_index;
605 int pri;
606
607 spin_lock_bh(&bc_lock);
608
609 /* Group bearers by priority (can assume max of two per priority) */
610
611 memset(bp_temp, 0, sizeof(bcbearer->bpairs_temp));
612
613 for (b_index = 0; b_index < MAX_BEARERS; b_index++) {
614 struct bearer *b = &bearers[b_index];
615
616 if (!b->active || !b->nodes.count)
617 continue;
618
619 if (!bp_temp[b->priority].primary)
620 bp_temp[b->priority].primary = b;
621 else
622 bp_temp[b->priority].secondary = b;
623 }
624
625 /* Create array of bearer pairs for broadcasting */
626
627 bp_curr = bcbearer->bpairs;
628 memset(bcbearer->bpairs, 0, sizeof(bcbearer->bpairs));
629
630 for (pri = (TIPC_NUM_LINK_PRI - 1); pri >= 0; pri--) {
631
632 if (!bp_temp[pri].primary)
633 continue;
634
635 bp_curr->primary = bp_temp[pri].primary;
636
637 if (bp_temp[pri].secondary) {
638 if (nmap_equal(&bp_temp[pri].primary->nodes,
639 &bp_temp[pri].secondary->nodes)) {
640 bp_curr->secondary = bp_temp[pri].secondary;
641 } else {
642 bp_curr++;
643 bp_curr->primary = bp_temp[pri].secondary;
644 }
645 }
646
647 bp_curr++;
648 }
649
650 spin_unlock_bh(&bc_lock);
651}
652
653/**
654 * bcbearer_push - resolve bearer congestion
655 *
656 * Forces bclink to push out any unsent packets, until all packets are gone
657 * or congestion reoccurs.
658 * No locks set when function called
659 */
660
661void bcbearer_push(void)
662{
663 struct bearer *b_ptr;
664
665 spin_lock_bh(&bc_lock);
666 b_ptr = &bcbearer->bearer;
667 if (b_ptr->publ.blocked) {
668 b_ptr->publ.blocked = 0;
669 bearer_lock_push(b_ptr);
670 }
671 spin_unlock_bh(&bc_lock);
672}
673
674
675int bclink_stats(char *buf, const u32 buf_size)
676{
677 struct print_buf pb;
678
679 if (!bcl)
680 return 0;
681
682 printbuf_init(&pb, buf, buf_size);
683
684 spin_lock_bh(&bc_lock);
685
686 tipc_printf(&pb, "Link <%s>\n"
687 " Window:%u packets\n",
688 bcl->name, bcl->queue_limit[0]);
689 tipc_printf(&pb, " RX packets:%u fragments:%u/%u bundles:%u/%u\n",
690 bcl->stats.recv_info,
691 bcl->stats.recv_fragments,
692 bcl->stats.recv_fragmented,
693 bcl->stats.recv_bundles,
694 bcl->stats.recv_bundled);
695 tipc_printf(&pb, " TX packets:%u fragments:%u/%u bundles:%u/%u\n",
696 bcl->stats.sent_info,
697 bcl->stats.sent_fragments,
698 bcl->stats.sent_fragmented,
699 bcl->stats.sent_bundles,
700 bcl->stats.sent_bundled);
701 tipc_printf(&pb, " RX naks:%u defs:%u dups:%u\n",
702 bcl->stats.recv_nacks,
703 bcl->stats.deferred_recv,
704 bcl->stats.duplicates);
705 tipc_printf(&pb, " TX naks:%u acks:%u dups:%u\n",
706 bcl->stats.sent_nacks,
707 bcl->stats.sent_acks,
708 bcl->stats.retransmitted);
709 tipc_printf(&pb, " Congestion bearer:%u link:%u Send queue max:%u avg:%u\n",
710 bcl->stats.bearer_congs,
711 bcl->stats.link_congs,
712 bcl->stats.max_queue_sz,
713 bcl->stats.queue_sz_counts
714 ? (bcl->stats.accu_queue_sz / bcl->stats.queue_sz_counts)
715 : 0);
716
717 spin_unlock_bh(&bc_lock);
718 return printbuf_validate(&pb);
719}
720
721int bclink_reset_stats(void)
722{
723 if (!bcl)
724 return -ENOPROTOOPT;
725
726 spin_lock_bh(&bc_lock);
727 memset(&bcl->stats, 0, sizeof(bcl->stats));
728 spin_unlock_bh(&bc_lock);
729 return TIPC_OK;
730}
731
732int bclink_set_queue_limits(u32 limit)
733{
734 if (!bcl)
735 return -ENOPROTOOPT;
736 if ((limit < TIPC_MIN_LINK_WIN) || (limit > TIPC_MAX_LINK_WIN))
737 return -EINVAL;
738
739 spin_lock_bh(&bc_lock);
740 link_set_queue_limits(bcl, limit);
741 spin_unlock_bh(&bc_lock);
742 return TIPC_OK;
743}
744
745int bclink_init(void)
746{
747 bcbearer = kmalloc(sizeof(*bcbearer), GFP_ATOMIC);
748 bclink = kmalloc(sizeof(*bclink), GFP_ATOMIC);
749 if (!bcbearer || !bclink) {
750 nomem:
751 warn("Memory squeeze; Failed to create multicast link\n");
752 kfree(bcbearer);
753 bcbearer = NULL;
754 kfree(bclink);
755 bclink = NULL;
756 return -ENOMEM;
757 }
758
759 memset(bcbearer, 0, sizeof(struct bcbearer));
760 INIT_LIST_HEAD(&bcbearer->bearer.cong_links);
761 bcbearer->bearer.media = &bcbearer->media;
762 bcbearer->media.send_msg = bcbearer_send;
763 sprintf(bcbearer->media.name, "tipc-multicast");
764
765 bcl = &bclink->link;
766 memset(bclink, 0, sizeof(struct bclink));
767 INIT_LIST_HEAD(&bcl->waiting_ports);
768 bcl->next_out_no = 1;
769 bclink->node.lock = SPIN_LOCK_UNLOCKED;
770 bcl->owner = &bclink->node;
771 bcl->max_pkt = MAX_PKT_DEFAULT_MCAST;
772 link_set_queue_limits(bcl, BCLINK_WIN_DEFAULT);
773 bcl->b_ptr = &bcbearer->bearer;
774 bcl->state = WORKING_WORKING;
775 sprintf(bcl->name, bc_link_name);
776
777 if (BCLINK_LOG_BUF_SIZE) {
778 char *pb = kmalloc(BCLINK_LOG_BUF_SIZE, GFP_ATOMIC);
779
780 if (!pb)
781 goto nomem;
782 printbuf_init(&bcl->print_buf, pb, BCLINK_LOG_BUF_SIZE);
783 }
784
785 return TIPC_OK;
786}
787
788void bclink_stop(void)
789{
790 spin_lock_bh(&bc_lock);
791 if (bcbearer) {
792 link_stop(bcl);
793 if (BCLINK_LOG_BUF_SIZE)
794 kfree(bcl->print_buf.buf);
795 bcl = NULL;
796 kfree(bclink);
797 bclink = NULL;
798 kfree(bcbearer);
799 bcbearer = NULL;
800 }
801 spin_unlock_bh(&bc_lock);
802}
803
diff --git a/net/tipc/bcast.h b/net/tipc/bcast.h
new file mode 100644
index 000000000000..cc2ede15c4fd
--- /dev/null
+++ b/net/tipc/bcast.h
@@ -0,0 +1,220 @@
1/*
2 * net/tipc/bcast.h: Include file for TIPC broadcast code
3 *
4 * Copyright (c) 2003-2005, Ericsson Research Canada
5 * Copyright (c) 2005, Wind River Systems
6 * Copyright (c) 2005-2006, Ericsson AB
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions are met:
11 *
12 * Redistributions of source code must retain the above copyright notice, this
13 * list of conditions and the following disclaimer.
14 * Redistributions in binary form must reproduce the above copyright notice,
15 * this list of conditions and the following disclaimer in the documentation
16 * and/or other materials provided with the distribution.
17 * Neither the names of the copyright holders nor the names of its
18 * contributors may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 */
33
34#ifndef _TIPC_BCAST_H
35#define _TIPC_BCAST_H
36
37#define MAX_NODES 4096
38#define WSIZE 32
39
40/**
41 * struct node_map - set of node identifiers
42 * @count: # of nodes in set
43 * @map: bitmap of node identifiers that are in the set
44 */
45
46struct node_map {
47 u32 count;
48 u32 map[MAX_NODES / WSIZE];
49};
50
51
52#define PLSIZE 32
53
54/**
55 * struct port_list - set of node local destination ports
56 * @count: # of ports in set (only valid for first entry in list)
57 * @next: pointer to next entry in list
58 * @ports: array of port references
59 */
60
61struct port_list {
62 int count;
63 struct port_list *next;
64 u32 ports[PLSIZE];
65};
66
67
68struct node;
69
70extern char bc_link_name[];
71
72
73/**
74 * nmap_get - determine if node exists in a node map
75 */
76
77static inline int nmap_get(struct node_map *nm_ptr, u32 node)
78{
79 int n = tipc_node(node);
80 int w = n / WSIZE;
81 int b = n % WSIZE;
82
83 return nm_ptr->map[w] & (1 << b);
84}
85
86/**
87 * nmap_add - add a node to a node map
88 */
89
90static inline void nmap_add(struct node_map *nm_ptr, u32 node)
91{
92 int n = tipc_node(node);
93 int w = n / WSIZE;
94 u32 mask = (1 << (n % WSIZE));
95
96 if ((nm_ptr->map[w] & mask) == 0) {
97 nm_ptr->count++;
98 nm_ptr->map[w] |= mask;
99 }
100}
101
102/**
103 * nmap_remove - remove a node from a node map
104 */
105
106static inline void nmap_remove(struct node_map *nm_ptr, u32 node)
107{
108 int n = tipc_node(node);
109 int w = n / WSIZE;
110 u32 mask = (1 << (n % WSIZE));
111
112 if ((nm_ptr->map[w] & mask) != 0) {
113 nm_ptr->map[w] &= ~mask;
114 nm_ptr->count--;
115 }
116}
117
118/**
119 * nmap_equal - test for equality of node maps
120 */
121
122static inline int nmap_equal(struct node_map *nm_a, struct node_map *nm_b)
123{
124 return !memcmp(nm_a, nm_b, sizeof(*nm_a));
125}
126
127/**
128 * nmap_diff - find differences between node maps
129 * @nm_a: input node map A
130 * @nm_b: input node map B
131 * @nm_diff: output node map A-B (i.e. nodes of A that are not in B)
132 */
133
134static inline void nmap_diff(struct node_map *nm_a, struct node_map *nm_b,
135 struct node_map *nm_diff)
136{
137 int stop = sizeof(nm_a->map) / sizeof(u32);
138 int w;
139 int b;
140 u32 map;
141
142 memset(nm_diff, 0, sizeof(*nm_diff));
143 for (w = 0; w < stop; w++) {
144 map = nm_a->map[w] ^ (nm_a->map[w] & nm_b->map[w]);
145 nm_diff->map[w] = map;
146 if (map != 0) {
147 for (b = 0 ; b < WSIZE; b++) {
148 if (map & (1 << b))
149 nm_diff->count++;
150 }
151 }
152 }
153}
154
155/**
156 * port_list_add - add a port to a port list, ensuring no duplicates
157 */
158
159static inline void port_list_add(struct port_list *pl_ptr, u32 port)
160{
161 struct port_list *item = pl_ptr;
162 int i;
163 int item_sz = PLSIZE;
164 int cnt = pl_ptr->count;
165
166 for (; ; cnt -= item_sz, item = item->next) {
167 if (cnt < PLSIZE)
168 item_sz = cnt;
169 for (i = 0; i < item_sz; i++)
170 if (item->ports[i] == port)
171 return;
172 if (i < PLSIZE) {
173 item->ports[i] = port;
174 pl_ptr->count++;
175 return;
176 }
177 if (!item->next) {
178 item->next = kmalloc(sizeof(*item), GFP_ATOMIC);
179 if (!item->next) {
180 warn("Memory squeeze: multicast destination port list is incomplete\n");
181 return;
182 }
183 item->next->next = NULL;
184 }
185 }
186}
187
188/**
189 * port_list_free - free dynamically created entries in port_list chain
190 *
191 * Note: First item is on stack, so it doesn't need to be released
192 */
193
194static inline void port_list_free(struct port_list *pl_ptr)
195{
196 struct port_list *item;
197 struct port_list *next;
198
199 for (item = pl_ptr->next; item; item = next) {
200 next = item->next;
201 kfree(item);
202 }
203}
204
205
206int bclink_init(void);
207void bclink_stop(void);
208void bclink_acknowledge(struct node *n_ptr, u32 acked);
209int bclink_send_msg(struct sk_buff *buf);
210void bclink_recv_pkt(struct sk_buff *buf);
211u32 bclink_get_last_sent(void);
212u32 bclink_acks_missing(struct node *n_ptr);
213void bclink_check_gap(struct node *n_ptr, u32 seqno);
214int bclink_stats(char *stats_buf, const u32 buf_size);
215int bclink_reset_stats(void);
216int bclink_set_queue_limits(u32 limit);
217void bcbearer_sort(void);
218void bcbearer_push(void);
219
220#endif
diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c
new file mode 100644
index 000000000000..c19465c5f035
--- /dev/null
+++ b/net/tipc/bearer.c
@@ -0,0 +1,689 @@
1/*
2 * net/tipc/bearer.c: TIPC bearer code
3 *
4 * Copyright (c) 2003-2005, Ericsson Research Canada
5 * Copyright (c) 2004-2005, Wind River Systems
6 * Copyright (c) 2005-2006, Ericsson AB
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions are met:
11 *
12 * Redistributions of source code must retain the above copyright notice, this
13 * list of conditions and the following disclaimer.
14 * Redistributions in binary form must reproduce the above copyright notice,
15 * this list of conditions and the following disclaimer in the documentation
16 * and/or other materials provided with the distribution.
17 * Neither the names of the copyright holders nor the names of its
18 * contributors may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 */
33
34#include "core.h"
35#include "config.h"
36#include "dbg.h"
37#include "bearer.h"
38#include "link.h"
39#include "port.h"
40#include "discover.h"
41#include "bcast.h"
42
43#define MAX_ADDR_STR 32
44
45static struct media *media_list = 0;
46static u32 media_count = 0;
47
48struct bearer *bearers = 0;
49
50/**
51 * media_name_valid - validate media name
52 *
53 * Returns 1 if media name is valid, otherwise 0.
54 */
55
56static int media_name_valid(const char *name)
57{
58 u32 len;
59
60 len = strlen(name);
61 if ((len + 1) > TIPC_MAX_MEDIA_NAME)
62 return 0;
63 return (strspn(name, tipc_alphabet) == len);
64}
65
66/**
67 * media_find - locates specified media object by name
68 */
69
70static struct media *media_find(const char *name)
71{
72 struct media *m_ptr;
73 u32 i;
74
75 for (i = 0, m_ptr = media_list; i < media_count; i++, m_ptr++) {
76 if (!strcmp(m_ptr->name, name))
77 return m_ptr;
78 }
79 return 0;
80}
81
82/**
83 * tipc_register_media - register a media type
84 *
85 * Bearers for this media type must be activated separately at a later stage.
86 */
87
88int tipc_register_media(u32 media_type,
89 char *name,
90 int (*enable)(struct tipc_bearer *),
91 void (*disable)(struct tipc_bearer *),
92 int (*send_msg)(struct sk_buff *,
93 struct tipc_bearer *,
94 struct tipc_media_addr *),
95 char *(*addr2str)(struct tipc_media_addr *a,
96 char *str_buf, int str_size),
97 struct tipc_media_addr *bcast_addr,
98 const u32 bearer_priority,
99 const u32 link_tolerance, /* [ms] */
100 const u32 send_window_limit)
101{
102 struct media *m_ptr;
103 u32 media_id;
104 u32 i;
105 int res = -EINVAL;
106
107 write_lock_bh(&net_lock);
108 if (!media_list)
109 goto exit;
110
111 if (!media_name_valid(name)) {
112 warn("Media registration error: illegal name <%s>\n", name);
113 goto exit;
114 }
115 if (!bcast_addr) {
116 warn("Media registration error: no broadcast address supplied\n");
117 goto exit;
118 }
119 if (bearer_priority >= TIPC_NUM_LINK_PRI) {
120 warn("Media registration error: priority %u\n", bearer_priority);
121 goto exit;
122 }
123 if ((link_tolerance < TIPC_MIN_LINK_TOL) ||
124 (link_tolerance > TIPC_MAX_LINK_TOL)) {
125 warn("Media registration error: tolerance %u\n", link_tolerance);
126 goto exit;
127 }
128
129 media_id = media_count++;
130 if (media_id >= MAX_MEDIA) {
131 warn("Attempt to register more than %u media\n", MAX_MEDIA);
132 media_count--;
133 goto exit;
134 }
135 for (i = 0; i < media_id; i++) {
136 if (media_list[i].type_id == media_type) {
137 warn("Attempt to register second media with type %u\n",
138 media_type);
139 media_count--;
140 goto exit;
141 }
142 if (!strcmp(name, media_list[i].name)) {
143 warn("Attempt to re-register media name <%s>\n", name);
144 media_count--;
145 goto exit;
146 }
147 }
148
149 m_ptr = &media_list[media_id];
150 m_ptr->type_id = media_type;
151 m_ptr->send_msg = send_msg;
152 m_ptr->enable_bearer = enable;
153 m_ptr->disable_bearer = disable;
154 m_ptr->addr2str = addr2str;
155 memcpy(&m_ptr->bcast_addr, bcast_addr, sizeof(*bcast_addr));
156 m_ptr->bcast = 1;
157 strcpy(m_ptr->name, name);
158 m_ptr->priority = bearer_priority;
159 m_ptr->tolerance = link_tolerance;
160 m_ptr->window = send_window_limit;
161 dbg("Media <%s> registered\n", name);
162 res = 0;
163exit:
164 write_unlock_bh(&net_lock);
165 return res;
166}
167
168/**
169 * media_addr_printf - record media address in print buffer
170 */
171
172void media_addr_printf(struct print_buf *pb, struct tipc_media_addr *a)
173{
174 struct media *m_ptr;
175 u32 media_type;
176 u32 i;
177
178 media_type = ntohl(a->type);
179 for (i = 0, m_ptr = media_list; i < media_count; i++, m_ptr++) {
180 if (m_ptr->type_id == media_type)
181 break;
182 }
183
184 if ((i < media_count) && (m_ptr->addr2str != NULL)) {
185 char addr_str[MAX_ADDR_STR];
186
187 tipc_printf(pb, "%s(%s) ", m_ptr->name,
188 m_ptr->addr2str(a, addr_str, sizeof(addr_str)));
189 } else {
190 unchar *addr = (unchar *)&a->dev_addr;
191
192 tipc_printf(pb, "UNKNOWN(%u):", media_type);
193 for (i = 0; i < (sizeof(*a) - sizeof(a->type)); i++) {
194 tipc_printf(pb, "%02x ", addr[i]);
195 }
196 }
197}
198
199/**
200 * media_get_names - record names of registered media in buffer
201 */
202
203struct sk_buff *media_get_names(void)
204{
205 struct sk_buff *buf;
206 struct media *m_ptr;
207 int i;
208
209 buf = cfg_reply_alloc(MAX_MEDIA * TLV_SPACE(TIPC_MAX_MEDIA_NAME));
210 if (!buf)
211 return NULL;
212
213 read_lock_bh(&net_lock);
214 for (i = 0, m_ptr = media_list; i < media_count; i++, m_ptr++) {
215 cfg_append_tlv(buf, TIPC_TLV_MEDIA_NAME, m_ptr->name,
216 strlen(m_ptr->name) + 1);
217 }
218 read_unlock_bh(&net_lock);
219 return buf;
220}
221
222/**
223 * bearer_name_validate - validate & (optionally) deconstruct bearer name
224 * @name - ptr to bearer name string
225 * @name_parts - ptr to area for bearer name components (or NULL if not needed)
226 *
227 * Returns 1 if bearer name is valid, otherwise 0.
228 */
229
230static int bearer_name_validate(const char *name,
231 struct bearer_name *name_parts)
232{
233 char name_copy[TIPC_MAX_BEARER_NAME];
234 char *media_name;
235 char *if_name;
236 u32 media_len;
237 u32 if_len;
238
239 /* copy bearer name & ensure length is OK */
240
241 name_copy[TIPC_MAX_BEARER_NAME - 1] = 0;
242 /* need above in case non-Posix strncpy() doesn't pad with nulls */
243 strncpy(name_copy, name, TIPC_MAX_BEARER_NAME);
244 if (name_copy[TIPC_MAX_BEARER_NAME - 1] != 0)
245 return 0;
246
247 /* ensure all component parts of bearer name are present */
248
249 media_name = name_copy;
250 if ((if_name = strchr(media_name, ':')) == NULL)
251 return 0;
252 *(if_name++) = 0;
253 media_len = if_name - media_name;
254 if_len = strlen(if_name) + 1;
255
256 /* validate component parts of bearer name */
257
258 if ((media_len <= 1) || (media_len > TIPC_MAX_MEDIA_NAME) ||
259 (if_len <= 1) || (if_len > TIPC_MAX_IF_NAME) ||
260 (strspn(media_name, tipc_alphabet) != (media_len - 1)) ||
261 (strspn(if_name, tipc_alphabet) != (if_len - 1)))
262 return 0;
263
264 /* return bearer name components, if necessary */
265
266 if (name_parts) {
267 strcpy(name_parts->media_name, media_name);
268 strcpy(name_parts->if_name, if_name);
269 }
270 return 1;
271}
272
273/**
274 * bearer_find - locates bearer object with matching bearer name
275 */
276
277static struct bearer *bearer_find(const char *name)
278{
279 struct bearer *b_ptr;
280 u32 i;
281
282 for (i = 0, b_ptr = bearers; i < MAX_BEARERS; i++, b_ptr++) {
283 if (b_ptr->active && (!strcmp(b_ptr->publ.name, name)))
284 return b_ptr;
285 }
286 return 0;
287}
288
289/**
290 * bearer_find - locates bearer object with matching interface name
291 */
292
293struct bearer *bearer_find_interface(const char *if_name)
294{
295 struct bearer *b_ptr;
296 char *b_if_name;
297 u32 i;
298
299 for (i = 0, b_ptr = bearers; i < MAX_BEARERS; i++, b_ptr++) {
300 if (!b_ptr->active)
301 continue;
302 b_if_name = strchr(b_ptr->publ.name, ':') + 1;
303 if (!strcmp(b_if_name, if_name))
304 return b_ptr;
305 }
306 return 0;
307}
308
309/**
310 * bearer_get_names - record names of bearers in buffer
311 */
312
313struct sk_buff *bearer_get_names(void)
314{
315 struct sk_buff *buf;
316 struct media *m_ptr;
317 struct bearer *b_ptr;
318 int i, j;
319
320 buf = cfg_reply_alloc(MAX_BEARERS * TLV_SPACE(TIPC_MAX_BEARER_NAME));
321 if (!buf)
322 return NULL;
323
324 read_lock_bh(&net_lock);
325 for (i = 0, m_ptr = media_list; i < media_count; i++, m_ptr++) {
326 for (j = 0; j < MAX_BEARERS; j++) {
327 b_ptr = &bearers[j];
328 if (b_ptr->active && (b_ptr->media == m_ptr)) {
329 cfg_append_tlv(buf, TIPC_TLV_BEARER_NAME,
330 b_ptr->publ.name,
331 strlen(b_ptr->publ.name) + 1);
332 }
333 }
334 }
335 read_unlock_bh(&net_lock);
336 return buf;
337}
338
339void bearer_add_dest(struct bearer *b_ptr, u32 dest)
340{
341 nmap_add(&b_ptr->nodes, dest);
342 disc_update_link_req(b_ptr->link_req);
343 bcbearer_sort();
344}
345
346void bearer_remove_dest(struct bearer *b_ptr, u32 dest)
347{
348 nmap_remove(&b_ptr->nodes, dest);
349 disc_update_link_req(b_ptr->link_req);
350 bcbearer_sort();
351}
352
353/*
354 * bearer_push(): Resolve bearer congestion. Force the waiting
355 * links to push out their unsent packets, one packet per link
356 * per iteration, until all packets are gone or congestion reoccurs.
357 * 'net_lock' is read_locked when this function is called
358 * bearer.lock must be taken before calling
359 * Returns binary true(1) ore false(0)
360 */
361static int bearer_push(struct bearer *b_ptr)
362{
363 u32 res = TIPC_OK;
364 struct link *ln, *tln;
365
366 if (b_ptr->publ.blocked)
367 return 0;
368
369 while (!list_empty(&b_ptr->cong_links) && (res != PUSH_FAILED)) {
370 list_for_each_entry_safe(ln, tln, &b_ptr->cong_links, link_list) {
371 res = link_push_packet(ln);
372 if (res == PUSH_FAILED)
373 break;
374 if (res == PUSH_FINISHED)
375 list_move_tail(&ln->link_list, &b_ptr->links);
376 }
377 }
378 return list_empty(&b_ptr->cong_links);
379}
380
381void bearer_lock_push(struct bearer *b_ptr)
382{
383 int res;
384
385 spin_lock_bh(&b_ptr->publ.lock);
386 res = bearer_push(b_ptr);
387 spin_unlock_bh(&b_ptr->publ.lock);
388 if (res)
389 bcbearer_push();
390}
391
392
393/*
394 * Interrupt enabling new requests after bearer congestion or blocking:
395 * See bearer_send().
396 */
397void tipc_continue(struct tipc_bearer *tb_ptr)
398{
399 struct bearer *b_ptr = (struct bearer *)tb_ptr;
400
401 spin_lock_bh(&b_ptr->publ.lock);
402 b_ptr->continue_count++;
403 if (!list_empty(&b_ptr->cong_links))
404 k_signal((Handler)bearer_lock_push, (unsigned long)b_ptr);
405 b_ptr->publ.blocked = 0;
406 spin_unlock_bh(&b_ptr->publ.lock);
407}
408
409/*
410 * Schedule link for sending of messages after the bearer
411 * has been deblocked by 'continue()'. This method is called
412 * when somebody tries to send a message via this link while
413 * the bearer is congested. 'net_lock' is in read_lock here
414 * bearer.lock is busy
415 */
416
417static void bearer_schedule_unlocked(struct bearer *b_ptr, struct link *l_ptr)
418{
419 list_move_tail(&l_ptr->link_list, &b_ptr->cong_links);
420}
421
422/*
423 * Schedule link for sending of messages after the bearer
424 * has been deblocked by 'continue()'. This method is called
425 * when somebody tries to send a message via this link while
426 * the bearer is congested. 'net_lock' is in read_lock here,
427 * bearer.lock is free
428 */
429
430void bearer_schedule(struct bearer *b_ptr, struct link *l_ptr)
431{
432 spin_lock_bh(&b_ptr->publ.lock);
433 bearer_schedule_unlocked(b_ptr, l_ptr);
434 spin_unlock_bh(&b_ptr->publ.lock);
435}
436
437
438/*
439 * bearer_resolve_congestion(): Check if there is bearer congestion,
440 * and if there is, try to resolve it before returning.
441 * 'net_lock' is read_locked when this function is called
442 */
443int bearer_resolve_congestion(struct bearer *b_ptr, struct link *l_ptr)
444{
445 int res = 1;
446
447 if (list_empty(&b_ptr->cong_links))
448 return 1;
449 spin_lock_bh(&b_ptr->publ.lock);
450 if (!bearer_push(b_ptr)) {
451 bearer_schedule_unlocked(b_ptr, l_ptr);
452 res = 0;
453 }
454 spin_unlock_bh(&b_ptr->publ.lock);
455 return res;
456}
457
458
459/**
460 * tipc_enable_bearer - enable bearer with the given name
461 */
462
463int tipc_enable_bearer(const char *name, u32 bcast_scope, u32 priority)
464{
465 struct bearer *b_ptr;
466 struct media *m_ptr;
467 struct bearer_name b_name;
468 char addr_string[16];
469 u32 bearer_id;
470 u32 with_this_prio;
471 u32 i;
472 int res = -EINVAL;
473
474 if (tipc_mode != TIPC_NET_MODE)
475 return -ENOPROTOOPT;
476 if (!bearer_name_validate(name, &b_name) ||
477 !addr_domain_valid(bcast_scope) ||
478 !in_scope(bcast_scope, tipc_own_addr) ||
479 (priority > TIPC_NUM_LINK_PRI))
480 return -EINVAL;
481
482 write_lock_bh(&net_lock);
483 if (!bearers)
484 goto failed;
485
486 m_ptr = media_find(b_name.media_name);
487 if (!m_ptr) {
488 warn("No media <%s>\n", b_name.media_name);
489 goto failed;
490 }
491 if (priority == TIPC_NUM_LINK_PRI)
492 priority = m_ptr->priority;
493
494restart:
495 bearer_id = MAX_BEARERS;
496 with_this_prio = 1;
497 for (i = MAX_BEARERS; i-- != 0; ) {
498 if (!bearers[i].active) {
499 bearer_id = i;
500 continue;
501 }
502 if (!strcmp(name, bearers[i].publ.name)) {
503 warn("Bearer <%s> already enabled\n", name);
504 goto failed;
505 }
506 if ((bearers[i].priority == priority) &&
507 (++with_this_prio > 2)) {
508 if (priority-- == 0) {
509 warn("Third bearer <%s> with priority %u, unable to lower to %u\n",
510 name, priority + 1, priority);
511 goto failed;
512 }
513 warn("Third bearer <%s> with priority %u, lowering to %u\n",
514 name, priority + 1, priority);
515 goto restart;
516 }
517 }
518 if (bearer_id >= MAX_BEARERS) {
519 warn("Attempt to enable more than %d bearers\n", MAX_BEARERS);
520 goto failed;
521 }
522
523 b_ptr = &bearers[bearer_id];
524 memset(b_ptr, 0, sizeof(struct bearer));
525
526 strcpy(b_ptr->publ.name, name);
527 res = m_ptr->enable_bearer(&b_ptr->publ);
528 if (res) {
529 warn("Failed to enable bearer <%s>\n", name);
530 goto failed;
531 }
532
533 b_ptr->identity = bearer_id;
534 b_ptr->media = m_ptr;
535 b_ptr->net_plane = bearer_id + 'A';
536 b_ptr->active = 1;
537 b_ptr->detect_scope = bcast_scope;
538 b_ptr->priority = priority;
539 INIT_LIST_HEAD(&b_ptr->cong_links);
540 INIT_LIST_HEAD(&b_ptr->links);
541 if (m_ptr->bcast) {
542 b_ptr->link_req = disc_init_link_req(b_ptr, &m_ptr->bcast_addr,
543 bcast_scope, 2);
544 }
545 b_ptr->publ.lock = SPIN_LOCK_UNLOCKED;
546 write_unlock_bh(&net_lock);
547 info("Enabled bearer <%s>, discovery domain %s\n",
548 name, addr_string_fill(addr_string, bcast_scope));
549 return 0;
550failed:
551 write_unlock_bh(&net_lock);
552 return res;
553}
554
555/**
556 * tipc_block_bearer(): Block the bearer with the given name,
557 * and reset all its links
558 */
559
560int tipc_block_bearer(const char *name)
561{
562 struct bearer *b_ptr = 0;
563 struct link *l_ptr;
564 struct link *temp_l_ptr;
565
566 if (tipc_mode != TIPC_NET_MODE)
567 return -ENOPROTOOPT;
568
569 read_lock_bh(&net_lock);
570 b_ptr = bearer_find(name);
571 if (!b_ptr) {
572 warn("Attempt to block unknown bearer <%s>\n", name);
573 read_unlock_bh(&net_lock);
574 return -EINVAL;
575 }
576
577 spin_lock_bh(&b_ptr->publ.lock);
578 b_ptr->publ.blocked = 1;
579 list_for_each_entry_safe(l_ptr, temp_l_ptr, &b_ptr->links, link_list) {
580 struct node *n_ptr = l_ptr->owner;
581
582 spin_lock_bh(&n_ptr->lock);
583 link_reset(l_ptr);
584 spin_unlock_bh(&n_ptr->lock);
585 }
586 spin_unlock_bh(&b_ptr->publ.lock);
587 read_unlock_bh(&net_lock);
588 info("Blocked bearer <%s>\n", name);
589 return TIPC_OK;
590}
591
592/**
593 * bearer_disable -
594 *
595 * Note: This routine assumes caller holds net_lock.
596 */
597
598static int bearer_disable(const char *name)
599{
600 struct bearer *b_ptr;
601 struct link *l_ptr;
602 struct link *temp_l_ptr;
603
604 if (tipc_mode != TIPC_NET_MODE)
605 return -ENOPROTOOPT;
606
607 b_ptr = bearer_find(name);
608 if (!b_ptr) {
609 warn("Attempt to disable unknown bearer <%s>\n", name);
610 return -EINVAL;
611 }
612
613 disc_stop_link_req(b_ptr->link_req);
614 spin_lock_bh(&b_ptr->publ.lock);
615 b_ptr->link_req = NULL;
616 b_ptr->publ.blocked = 1;
617 if (b_ptr->media->disable_bearer) {
618 spin_unlock_bh(&b_ptr->publ.lock);
619 write_unlock_bh(&net_lock);
620 b_ptr->media->disable_bearer(&b_ptr->publ);
621 write_lock_bh(&net_lock);
622 spin_lock_bh(&b_ptr->publ.lock);
623 }
624 list_for_each_entry_safe(l_ptr, temp_l_ptr, &b_ptr->links, link_list) {
625 link_delete(l_ptr);
626 }
627 spin_unlock_bh(&b_ptr->publ.lock);
628 info("Disabled bearer <%s>\n", name);
629 memset(b_ptr, 0, sizeof(struct bearer));
630 return TIPC_OK;
631}
632
633int tipc_disable_bearer(const char *name)
634{
635 int res;
636
637 write_lock_bh(&net_lock);
638 res = bearer_disable(name);
639 write_unlock_bh(&net_lock);
640 return res;
641}
642
643
644
645int bearer_init(void)
646{
647 int res;
648
649 write_lock_bh(&net_lock);
650 bearers = kmalloc(MAX_BEARERS * sizeof(struct bearer), GFP_ATOMIC);
651 media_list = kmalloc(MAX_MEDIA * sizeof(struct media), GFP_ATOMIC);
652 if (bearers && media_list) {
653 memset(bearers, 0, MAX_BEARERS * sizeof(struct bearer));
654 memset(media_list, 0, MAX_MEDIA * sizeof(struct media));
655 res = TIPC_OK;
656 } else {
657 kfree(bearers);
658 kfree(media_list);
659 bearers = 0;
660 media_list = 0;
661 res = -ENOMEM;
662 }
663 write_unlock_bh(&net_lock);
664 return res;
665}
666
667void bearer_stop(void)
668{
669 u32 i;
670
671 if (!bearers)
672 return;
673
674 for (i = 0; i < MAX_BEARERS; i++) {
675 if (bearers[i].active)
676 bearers[i].publ.blocked = 1;
677 }
678 for (i = 0; i < MAX_BEARERS; i++) {
679 if (bearers[i].active)
680 bearer_disable(bearers[i].publ.name);
681 }
682 kfree(bearers);
683 kfree(media_list);
684 bearers = 0;
685 media_list = 0;
686 media_count = 0;
687}
688
689
diff --git a/net/tipc/bearer.h b/net/tipc/bearer.h
new file mode 100644
index 000000000000..02a16f86defa
--- /dev/null
+++ b/net/tipc/bearer.h
@@ -0,0 +1,169 @@
1/*
2 * net/tipc/bearer.h: Include file for TIPC bearer code
3 *
4 * Copyright (c) 2003-2005, Ericsson Research Canada
5 * Copyright (c) 2005, Wind River Systems
6 * Copyright (c) 2005-2006, Ericsson AB
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions are met:
11 *
12 * Redistributions of source code must retain the above copyright notice, this
13 * list of conditions and the following disclaimer.
14 * Redistributions in binary form must reproduce the above copyright notice,
15 * this list of conditions and the following disclaimer in the documentation
16 * and/or other materials provided with the distribution.
17 * Neither the names of the copyright holders nor the names of its
18 * contributors may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 */
33
34#ifndef _TIPC_BEARER_H
35#define _TIPC_BEARER_H
36
37#include <net/tipc/tipc_bearer.h>
38#include "bcast.h"
39
40#define MAX_BEARERS 8
41#define MAX_MEDIA 4
42
43
44/**
45 * struct media - TIPC media information available to internal users
46 * @send_msg: routine which handles buffer transmission
47 * @enable_bearer: routine which enables a bearer
48 * @disable_bearer: routine which disables a bearer
49 * @addr2str: routine which converts bearer's address to string form
50 * @bcast_addr: media address used in broadcasting
51 * @bcast: non-zero if media supports broadcasting [currently mandatory]
52 * @priority: default link (and bearer) priority
53 * @tolerance: default time (in ms) before declaring link failure
54 * @window: default window (in packets) before declaring link congestion
55 * @type_id: TIPC media identifier [defined in tipc_bearer.h]
56 * @name: media name
57 */
58
59struct media {
60 int (*send_msg)(struct sk_buff *buf,
61 struct tipc_bearer *b_ptr,
62 struct tipc_media_addr *dest);
63 int (*enable_bearer)(struct tipc_bearer *b_ptr);
64 void (*disable_bearer)(struct tipc_bearer *b_ptr);
65 char *(*addr2str)(struct tipc_media_addr *a,
66 char *str_buf, int str_size);
67 struct tipc_media_addr bcast_addr;
68 int bcast;
69 u32 priority;
70 u32 tolerance;
71 u32 window;
72 u32 type_id;
73 char name[TIPC_MAX_MEDIA_NAME];
74};
75
76/**
77 * struct bearer - TIPC bearer information available to internal users
78 * @publ: bearer information available to privileged users
79 * @media: ptr to media structure associated with bearer
80 * @priority: default link priority for bearer
81 * @detect_scope: network address mask used during automatic link creation
82 * @identity: array index of this bearer within TIPC bearer array
83 * @link_req: ptr to (optional) structure making periodic link setup requests
84 * @links: list of non-congested links associated with bearer
85 * @cong_links: list of congested links associated with bearer
86 * @continue_count: # of times bearer has resumed after congestion or blocking
87 * @active: non-zero if bearer structure is represents a bearer
88 * @net_plane: network plane ('A' through 'H') currently associated with bearer
89 * @nodes: indicates which nodes in cluster can be reached through bearer
90 */
91
92struct bearer {
93 struct tipc_bearer publ;
94 struct media *media;
95 u32 priority;
96 u32 detect_scope;
97 u32 identity;
98 struct link_req *link_req;
99 struct list_head links;
100 struct list_head cong_links;
101 u32 continue_count;
102 int active;
103 char net_plane;
104 struct node_map nodes;
105};
106
107struct bearer_name {
108 char media_name[TIPC_MAX_MEDIA_NAME];
109 char if_name[TIPC_MAX_IF_NAME];
110};
111
112struct link;
113
114extern struct bearer *bearers;
115
116void media_addr_printf(struct print_buf *pb, struct tipc_media_addr *a);
117struct sk_buff *media_get_names(void);
118
119struct sk_buff *bearer_get_names(void);
120void bearer_add_dest(struct bearer *b_ptr, u32 dest);
121void bearer_remove_dest(struct bearer *b_ptr, u32 dest);
122void bearer_schedule(struct bearer *b_ptr, struct link *l_ptr);
123struct bearer *bearer_find_interface(const char *if_name);
124int bearer_resolve_congestion(struct bearer *b_ptr, struct link *l_ptr);
125int bearer_init(void);
126void bearer_stop(void);
127int bearer_broadcast(struct sk_buff *buf, struct tipc_bearer *b_ptr,
128 struct tipc_media_addr *dest);
129void bearer_lock_push(struct bearer *b_ptr);
130
131
132/**
133 * bearer_send- sends buffer to destination over bearer
134 *
135 * Returns true (1) if successful, or false (0) if unable to send
136 *
137 * IMPORTANT:
138 * The media send routine must not alter the buffer being passed in
139 * as it may be needed for later retransmission!
140 *
141 * If the media send routine returns a non-zero value (indicating that
142 * it was unable to send the buffer), it must:
143 * 1) mark the bearer as blocked,
144 * 2) call tipc_continue() once the bearer is able to send again.
145 * Media types that are unable to meet these two critera must ensure their
146 * send routine always returns success -- even if the buffer was not sent --
147 * and let TIPC's link code deal with the undelivered message.
148 */
149
150static inline int bearer_send(struct bearer *b_ptr, struct sk_buff *buf,
151 struct tipc_media_addr *dest)
152{
153 return !b_ptr->media->send_msg(buf, &b_ptr->publ, dest);
154}
155
156/**
157 * bearer_congested - determines if bearer is currently congested
158 */
159
160static inline int bearer_congested(struct bearer *b_ptr, struct link *l_ptr)
161{
162 if (unlikely(b_ptr->publ.blocked))
163 return 1;
164 if (likely(list_empty(&b_ptr->cong_links)))
165 return 0;
166 return !bearer_resolve_congestion(b_ptr, l_ptr);
167}
168
169#endif
diff --git a/net/tipc/cluster.c b/net/tipc/cluster.c
new file mode 100644
index 000000000000..d7d0f5f17e00
--- /dev/null
+++ b/net/tipc/cluster.c
@@ -0,0 +1,573 @@
1/*
2 * net/tipc/cluster.c: TIPC cluster management routines
3 *
4 * Copyright (c) 2003-2005, Ericsson Research Canada
5 * Copyright (c) 2005, Wind River Systems
6 * Copyright (c) 2005-2006, Ericsson AB
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions are met:
11 *
12 * Redistributions of source code must retain the above copyright notice, this
13 * list of conditions and the following disclaimer.
14 * Redistributions in binary form must reproduce the above copyright notice,
15 * this list of conditions and the following disclaimer in the documentation
16 * and/or other materials provided with the distribution.
17 * Neither the names of the copyright holders nor the names of its
18 * contributors may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 */
33
34#include "core.h"
35#include "cluster.h"
36#include "addr.h"
37#include "node_subscr.h"
38#include "link.h"
39#include "node.h"
40#include "net.h"
41#include "msg.h"
42#include "bearer.h"
43
44void cluster_multicast(struct cluster *c_ptr, struct sk_buff *buf,
45 u32 lower, u32 upper);
46struct sk_buff *cluster_prepare_routing_msg(u32 data_size, u32 dest);
47
48struct node **local_nodes = 0;
49struct node_map cluster_bcast_nodes = {0,{0,}};
50u32 highest_allowed_slave = 0;
51
52struct cluster *cluster_create(u32 addr)
53{
54 struct _zone *z_ptr;
55 struct cluster *c_ptr;
56 int max_nodes;
57 int alloc;
58
59 c_ptr = (struct cluster *)kmalloc(sizeof(*c_ptr), GFP_ATOMIC);
60 if (c_ptr == NULL)
61 return 0;
62 memset(c_ptr, 0, sizeof(*c_ptr));
63
64 c_ptr->addr = tipc_addr(tipc_zone(addr), tipc_cluster(addr), 0);
65 if (in_own_cluster(addr))
66 max_nodes = LOWEST_SLAVE + tipc_max_slaves;
67 else
68 max_nodes = tipc_max_nodes + 1;
69 alloc = sizeof(void *) * (max_nodes + 1);
70 c_ptr->nodes = (struct node **)kmalloc(alloc, GFP_ATOMIC);
71 if (c_ptr->nodes == NULL) {
72 kfree(c_ptr);
73 return 0;
74 }
75 memset(c_ptr->nodes, 0, alloc);
76 if (in_own_cluster(addr))
77 local_nodes = c_ptr->nodes;
78 c_ptr->highest_slave = LOWEST_SLAVE - 1;
79 c_ptr->highest_node = 0;
80
81 z_ptr = zone_find(tipc_zone(addr));
82 if (z_ptr == NULL) {
83 z_ptr = zone_create(addr);
84 }
85 if (z_ptr != NULL) {
86 zone_attach_cluster(z_ptr, c_ptr);
87 c_ptr->owner = z_ptr;
88 }
89 else {
90 kfree(c_ptr);
91 c_ptr = 0;
92 }
93
94 return c_ptr;
95}
96
97void cluster_delete(struct cluster *c_ptr)
98{
99 u32 n_num;
100
101 if (!c_ptr)
102 return;
103 for (n_num = 1; n_num <= c_ptr->highest_node; n_num++) {
104 node_delete(c_ptr->nodes[n_num]);
105 }
106 for (n_num = LOWEST_SLAVE; n_num <= c_ptr->highest_slave; n_num++) {
107 node_delete(c_ptr->nodes[n_num]);
108 }
109 kfree(c_ptr->nodes);
110 kfree(c_ptr);
111}
112
113u32 cluster_next_node(struct cluster *c_ptr, u32 addr)
114{
115 struct node *n_ptr;
116 u32 n_num = tipc_node(addr) + 1;
117
118 if (!c_ptr)
119 return addr;
120 for (; n_num <= c_ptr->highest_node; n_num++) {
121 n_ptr = c_ptr->nodes[n_num];
122 if (n_ptr && node_has_active_links(n_ptr))
123 return n_ptr->addr;
124 }
125 for (n_num = 1; n_num < tipc_node(addr); n_num++) {
126 n_ptr = c_ptr->nodes[n_num];
127 if (n_ptr && node_has_active_links(n_ptr))
128 return n_ptr->addr;
129 }
130 return 0;
131}
132
133void cluster_attach_node(struct cluster *c_ptr, struct node *n_ptr)
134{
135 u32 n_num = tipc_node(n_ptr->addr);
136 u32 max_n_num = tipc_max_nodes;
137
138 if (in_own_cluster(n_ptr->addr))
139 max_n_num = highest_allowed_slave;
140 assert(n_num > 0);
141 assert(n_num <= max_n_num);
142 assert(c_ptr->nodes[n_num] == 0);
143 c_ptr->nodes[n_num] = n_ptr;
144 if (n_num > c_ptr->highest_node)
145 c_ptr->highest_node = n_num;
146}
147
148/**
149 * cluster_select_router - select router to a cluster
150 *
151 * Uses deterministic and fair algorithm.
152 */
153
154u32 cluster_select_router(struct cluster *c_ptr, u32 ref)
155{
156 u32 n_num;
157 u32 ulim = c_ptr->highest_node;
158 u32 mask;
159 u32 tstart;
160
161 assert(!in_own_cluster(c_ptr->addr));
162 if (!ulim)
163 return 0;
164
165 /* Start entry must be random */
166 mask = tipc_max_nodes;
167 while (mask > ulim)
168 mask >>= 1;
169 tstart = ref & mask;
170 n_num = tstart;
171
172 /* Lookup upwards with wrap-around */
173 do {
174 if (node_is_up(c_ptr->nodes[n_num]))
175 break;
176 } while (++n_num <= ulim);
177 if (n_num > ulim) {
178 n_num = 1;
179 do {
180 if (node_is_up(c_ptr->nodes[n_num]))
181 break;
182 } while (++n_num < tstart);
183 if (n_num == tstart)
184 return 0;
185 }
186 assert(n_num <= ulim);
187 return node_select_router(c_ptr->nodes[n_num], ref);
188}
189
190/**
191 * cluster_select_node - select destination node within a remote cluster
192 *
193 * Uses deterministic and fair algorithm.
194 */
195
196struct node *cluster_select_node(struct cluster *c_ptr, u32 selector)
197{
198 u32 n_num;
199 u32 mask = tipc_max_nodes;
200 u32 start_entry;
201
202 assert(!in_own_cluster(c_ptr->addr));
203 if (!c_ptr->highest_node)
204 return 0;
205
206 /* Start entry must be random */
207 while (mask > c_ptr->highest_node) {
208 mask >>= 1;
209 }
210 start_entry = (selector & mask) ? selector & mask : 1u;
211 assert(start_entry <= c_ptr->highest_node);
212
213 /* Lookup upwards with wrap-around */
214 for (n_num = start_entry; n_num <= c_ptr->highest_node; n_num++) {
215 if (node_has_active_links(c_ptr->nodes[n_num]))
216 return c_ptr->nodes[n_num];
217 }
218 for (n_num = 1; n_num < start_entry; n_num++) {
219 if (node_has_active_links(c_ptr->nodes[n_num]))
220 return c_ptr->nodes[n_num];
221 }
222 return 0;
223}
224
225/*
226 * Routing table management: See description in node.c
227 */
228
229struct sk_buff *cluster_prepare_routing_msg(u32 data_size, u32 dest)
230{
231 u32 size = INT_H_SIZE + data_size;
232 struct sk_buff *buf = buf_acquire(size);
233 struct tipc_msg *msg;
234
235 if (buf) {
236 msg = buf_msg(buf);
237 memset((char *)msg, 0, size);
238 msg_init(msg, ROUTE_DISTRIBUTOR, 0, TIPC_OK, INT_H_SIZE, dest);
239 }
240 return buf;
241}
242
243void cluster_bcast_new_route(struct cluster *c_ptr, u32 dest,
244 u32 lower, u32 upper)
245{
246 struct sk_buff *buf = cluster_prepare_routing_msg(0, c_ptr->addr);
247 struct tipc_msg *msg;
248
249 if (buf) {
250 msg = buf_msg(buf);
251 msg_set_remote_node(msg, dest);
252 msg_set_type(msg, ROUTE_ADDITION);
253 cluster_multicast(c_ptr, buf, lower, upper);
254 } else {
255 warn("Memory squeeze: broadcast of new route failed\n");
256 }
257}
258
259void cluster_bcast_lost_route(struct cluster *c_ptr, u32 dest,
260 u32 lower, u32 upper)
261{
262 struct sk_buff *buf = cluster_prepare_routing_msg(0, c_ptr->addr);
263 struct tipc_msg *msg;
264
265 if (buf) {
266 msg = buf_msg(buf);
267 msg_set_remote_node(msg, dest);
268 msg_set_type(msg, ROUTE_REMOVAL);
269 cluster_multicast(c_ptr, buf, lower, upper);
270 } else {
271 warn("Memory squeeze: broadcast of lost route failed\n");
272 }
273}
274
275void cluster_send_slave_routes(struct cluster *c_ptr, u32 dest)
276{
277 struct sk_buff *buf;
278 struct tipc_msg *msg;
279 u32 highest = c_ptr->highest_slave;
280 u32 n_num;
281 int send = 0;
282
283 assert(!is_slave(dest));
284 assert(in_own_cluster(dest));
285 assert(in_own_cluster(c_ptr->addr));
286 if (highest <= LOWEST_SLAVE)
287 return;
288 buf = cluster_prepare_routing_msg(highest - LOWEST_SLAVE + 1,
289 c_ptr->addr);
290 if (buf) {
291 msg = buf_msg(buf);
292 msg_set_remote_node(msg, c_ptr->addr);
293 msg_set_type(msg, SLAVE_ROUTING_TABLE);
294 for (n_num = LOWEST_SLAVE; n_num <= highest; n_num++) {
295 if (c_ptr->nodes[n_num] &&
296 node_has_active_links(c_ptr->nodes[n_num])) {
297 send = 1;
298 msg_set_dataoctet(msg, n_num);
299 }
300 }
301 if (send)
302 link_send(buf, dest, dest);
303 else
304 buf_discard(buf);
305 } else {
306 warn("Memory squeeze: broadcast of lost route failed\n");
307 }
308}
309
310void cluster_send_ext_routes(struct cluster *c_ptr, u32 dest)
311{
312 struct sk_buff *buf;
313 struct tipc_msg *msg;
314 u32 highest = c_ptr->highest_node;
315 u32 n_num;
316 int send = 0;
317
318 if (in_own_cluster(c_ptr->addr))
319 return;
320 assert(!is_slave(dest));
321 assert(in_own_cluster(dest));
322 highest = c_ptr->highest_node;
323 buf = cluster_prepare_routing_msg(highest + 1, c_ptr->addr);
324 if (buf) {
325 msg = buf_msg(buf);
326 msg_set_remote_node(msg, c_ptr->addr);
327 msg_set_type(msg, EXT_ROUTING_TABLE);
328 for (n_num = 1; n_num <= highest; n_num++) {
329 if (c_ptr->nodes[n_num] &&
330 node_has_active_links(c_ptr->nodes[n_num])) {
331 send = 1;
332 msg_set_dataoctet(msg, n_num);
333 }
334 }
335 if (send)
336 link_send(buf, dest, dest);
337 else
338 buf_discard(buf);
339 } else {
340 warn("Memory squeeze: broadcast of external route failed\n");
341 }
342}
343
344void cluster_send_local_routes(struct cluster *c_ptr, u32 dest)
345{
346 struct sk_buff *buf;
347 struct tipc_msg *msg;
348 u32 highest = c_ptr->highest_node;
349 u32 n_num;
350 int send = 0;
351
352 assert(is_slave(dest));
353 assert(in_own_cluster(c_ptr->addr));
354 buf = cluster_prepare_routing_msg(highest, c_ptr->addr);
355 if (buf) {
356 msg = buf_msg(buf);
357 msg_set_remote_node(msg, c_ptr->addr);
358 msg_set_type(msg, LOCAL_ROUTING_TABLE);
359 for (n_num = 1; n_num <= highest; n_num++) {
360 if (c_ptr->nodes[n_num] &&
361 node_has_active_links(c_ptr->nodes[n_num])) {
362 send = 1;
363 msg_set_dataoctet(msg, n_num);
364 }
365 }
366 if (send)
367 link_send(buf, dest, dest);
368 else
369 buf_discard(buf);
370 } else {
371 warn("Memory squeeze: broadcast of local route failed\n");
372 }
373}
374
375void cluster_recv_routing_table(struct sk_buff *buf)
376{
377 struct tipc_msg *msg = buf_msg(buf);
378 struct cluster *c_ptr;
379 struct node *n_ptr;
380 unchar *node_table;
381 u32 table_size;
382 u32 router;
383 u32 rem_node = msg_remote_node(msg);
384 u32 z_num;
385 u32 c_num;
386 u32 n_num;
387
388 c_ptr = cluster_find(rem_node);
389 if (!c_ptr) {
390 c_ptr = cluster_create(rem_node);
391 if (!c_ptr) {
392 buf_discard(buf);
393 return;
394 }
395 }
396
397 node_table = buf->data + msg_hdr_sz(msg);
398 table_size = msg_size(msg) - msg_hdr_sz(msg);
399 router = msg_prevnode(msg);
400 z_num = tipc_zone(rem_node);
401 c_num = tipc_cluster(rem_node);
402
403 switch (msg_type(msg)) {
404 case LOCAL_ROUTING_TABLE:
405 assert(is_slave(tipc_own_addr));
406 case EXT_ROUTING_TABLE:
407 for (n_num = 1; n_num < table_size; n_num++) {
408 if (node_table[n_num]) {
409 u32 addr = tipc_addr(z_num, c_num, n_num);
410 n_ptr = c_ptr->nodes[n_num];
411 if (!n_ptr) {
412 n_ptr = node_create(addr);
413 }
414 if (n_ptr)
415 node_add_router(n_ptr, router);
416 }
417 }
418 break;
419 case SLAVE_ROUTING_TABLE:
420 assert(!is_slave(tipc_own_addr));
421 assert(in_own_cluster(c_ptr->addr));
422 for (n_num = 1; n_num < table_size; n_num++) {
423 if (node_table[n_num]) {
424 u32 slave_num = n_num + LOWEST_SLAVE;
425 u32 addr = tipc_addr(z_num, c_num, slave_num);
426 n_ptr = c_ptr->nodes[slave_num];
427 if (!n_ptr) {
428 n_ptr = node_create(addr);
429 }
430 if (n_ptr)
431 node_add_router(n_ptr, router);
432 }
433 }
434 break;
435 case ROUTE_ADDITION:
436 if (!is_slave(tipc_own_addr)) {
437 assert(!in_own_cluster(c_ptr->addr)
438 || is_slave(rem_node));
439 } else {
440 assert(in_own_cluster(c_ptr->addr)
441 && !is_slave(rem_node));
442 }
443 n_ptr = c_ptr->nodes[tipc_node(rem_node)];
444 if (!n_ptr)
445 n_ptr = node_create(rem_node);
446 if (n_ptr)
447 node_add_router(n_ptr, router);
448 break;
449 case ROUTE_REMOVAL:
450 if (!is_slave(tipc_own_addr)) {
451 assert(!in_own_cluster(c_ptr->addr)
452 || is_slave(rem_node));
453 } else {
454 assert(in_own_cluster(c_ptr->addr)
455 && !is_slave(rem_node));
456 }
457 n_ptr = c_ptr->nodes[tipc_node(rem_node)];
458 if (n_ptr)
459 node_remove_router(n_ptr, router);
460 break;
461 default:
462 assert(!"Illegal routing manager message received\n");
463 }
464 buf_discard(buf);
465}
466
467void cluster_remove_as_router(struct cluster *c_ptr, u32 router)
468{
469 u32 start_entry;
470 u32 tstop;
471 u32 n_num;
472
473 if (is_slave(router))
474 return; /* Slave nodes can not be routers */
475
476 if (in_own_cluster(c_ptr->addr)) {
477 start_entry = LOWEST_SLAVE;
478 tstop = c_ptr->highest_slave;
479 } else {
480 start_entry = 1;
481 tstop = c_ptr->highest_node;
482 }
483
484 for (n_num = start_entry; n_num <= tstop; n_num++) {
485 if (c_ptr->nodes[n_num]) {
486 node_remove_router(c_ptr->nodes[n_num], router);
487 }
488 }
489}
490
491/**
492 * cluster_multicast - multicast message to local nodes
493 */
494
495void cluster_multicast(struct cluster *c_ptr, struct sk_buff *buf,
496 u32 lower, u32 upper)
497{
498 struct sk_buff *buf_copy;
499 struct node *n_ptr;
500 u32 n_num;
501 u32 tstop;
502
503 assert(lower <= upper);
504 assert(((lower >= 1) && (lower <= tipc_max_nodes)) ||
505 ((lower >= LOWEST_SLAVE) && (lower <= highest_allowed_slave)));
506 assert(((upper >= 1) && (upper <= tipc_max_nodes)) ||
507 ((upper >= LOWEST_SLAVE) && (upper <= highest_allowed_slave)));
508 assert(in_own_cluster(c_ptr->addr));
509
510 tstop = is_slave(upper) ? c_ptr->highest_slave : c_ptr->highest_node;
511 if (tstop > upper)
512 tstop = upper;
513 for (n_num = lower; n_num <= tstop; n_num++) {
514 n_ptr = c_ptr->nodes[n_num];
515 if (n_ptr && node_has_active_links(n_ptr)) {
516 buf_copy = skb_copy(buf, GFP_ATOMIC);
517 if (buf_copy == NULL)
518 break;
519 msg_set_destnode(buf_msg(buf_copy), n_ptr->addr);
520 link_send(buf_copy, n_ptr->addr, n_ptr->addr);
521 }
522 }
523 buf_discard(buf);
524}
525
526/**
527 * cluster_broadcast - broadcast message to all nodes within cluster
528 */
529
530void cluster_broadcast(struct sk_buff *buf)
531{
532 struct sk_buff *buf_copy;
533 struct cluster *c_ptr;
534 struct node *n_ptr;
535 u32 n_num;
536 u32 tstart;
537 u32 tstop;
538 u32 node_type;
539
540 if (tipc_mode == TIPC_NET_MODE) {
541 c_ptr = cluster_find(tipc_own_addr);
542 assert(in_own_cluster(c_ptr->addr)); /* For now */
543
544 /* Send to standard nodes, then repeat loop sending to slaves */
545 tstart = 1;
546 tstop = c_ptr->highest_node;
547 for (node_type = 1; node_type <= 2; node_type++) {
548 for (n_num = tstart; n_num <= tstop; n_num++) {
549 n_ptr = c_ptr->nodes[n_num];
550 if (n_ptr && node_has_active_links(n_ptr)) {
551 buf_copy = skb_copy(buf, GFP_ATOMIC);
552 if (buf_copy == NULL)
553 goto exit;
554 msg_set_destnode(buf_msg(buf_copy),
555 n_ptr->addr);
556 link_send(buf_copy, n_ptr->addr,
557 n_ptr->addr);
558 }
559 }
560 tstart = LOWEST_SLAVE;
561 tstop = c_ptr->highest_slave;
562 }
563 }
564exit:
565 buf_discard(buf);
566}
567
568int cluster_init(void)
569{
570 highest_allowed_slave = LOWEST_SLAVE + tipc_max_slaves;
571 return cluster_create(tipc_own_addr) ? TIPC_OK : -ENOMEM;
572}
573
diff --git a/net/tipc/cluster.h b/net/tipc/cluster.h
new file mode 100644
index 000000000000..c12875ab46be
--- /dev/null
+++ b/net/tipc/cluster.h
@@ -0,0 +1,89 @@
1/*
2 * net/tipc/cluster.h: Include file for TIPC cluster management routines
3 *
4 * Copyright (c) 2003-2005, Ericsson Research Canada
5 * Copyright (c) 2005, Wind River Systems
6 * Copyright (c) 2005-2006, Ericsson AB
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions are met:
11 *
12 * Redistributions of source code must retain the above copyright notice, this
13 * list of conditions and the following disclaimer.
14 * Redistributions in binary form must reproduce the above copyright notice,
15 * this list of conditions and the following disclaimer in the documentation
16 * and/or other materials provided with the distribution.
17 * Neither the names of the copyright holders nor the names of its
18 * contributors may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 */
33
34#ifndef _TIPC_CLUSTER_H
35#define _TIPC_CLUSTER_H
36
37#include "addr.h"
38#include "zone.h"
39
40#define LOWEST_SLAVE 2048u
41
42/**
43 * struct cluster - TIPC cluster structure
44 * @addr: network address of cluster
45 * @owner: pointer to zone that cluster belongs to
46 * @nodes: array of pointers to all nodes within cluster
47 * @highest_node: id of highest numbered node within cluster
48 * @highest_slave: (used for secondary node support)
49 */
50
51struct cluster {
52 u32 addr;
53 struct _zone *owner;
54 struct node **nodes;
55 u32 highest_node;
56 u32 highest_slave;
57};
58
59
60extern struct node **local_nodes;
61extern u32 highest_allowed_slave;
62extern struct node_map cluster_bcast_nodes;
63
64void cluster_remove_as_router(struct cluster *c_ptr, u32 router);
65void cluster_send_ext_routes(struct cluster *c_ptr, u32 dest);
66struct node *cluster_select_node(struct cluster *c_ptr, u32 selector);
67u32 cluster_select_router(struct cluster *c_ptr, u32 ref);
68void cluster_recv_routing_table(struct sk_buff *buf);
69struct cluster *cluster_create(u32 addr);
70void cluster_delete(struct cluster *c_ptr);
71void cluster_attach_node(struct cluster *c_ptr, struct node *n_ptr);
72void cluster_send_slave_routes(struct cluster *c_ptr, u32 dest);
73void cluster_broadcast(struct sk_buff *buf);
74int cluster_init(void);
75u32 cluster_next_node(struct cluster *c_ptr, u32 addr);
76void cluster_bcast_new_route(struct cluster *c_ptr, u32 dest, u32 lo, u32 hi);
77void cluster_send_local_routes(struct cluster *c_ptr, u32 dest);
78void cluster_bcast_lost_route(struct cluster *c_ptr, u32 dest, u32 lo, u32 hi);
79
80static inline struct cluster *cluster_find(u32 addr)
81{
82 struct _zone *z_ptr = zone_find(addr);
83
84 if (z_ptr)
85 return z_ptr->clusters[1];
86 return 0;
87}
88
89#endif
diff --git a/net/tipc/config.c b/net/tipc/config.c
new file mode 100644
index 000000000000..0f31c342d11c
--- /dev/null
+++ b/net/tipc/config.c
@@ -0,0 +1,715 @@
1/*
2 * net/tipc/config.c: TIPC configuration management code
3 *
4 * Copyright (c) 2003-2005, Ericsson Research Canada
5 * Copyright (c) 2004-2005, Wind River Systems
6 * Copyright (c) 2005-2006, Ericsson AB
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions are met:
11 *
12 * Redistributions of source code must retain the above copyright notice, this
13 * list of conditions and the following disclaimer.
14 * Redistributions in binary form must reproduce the above copyright notice,
15 * this list of conditions and the following disclaimer in the documentation
16 * and/or other materials provided with the distribution.
17 * Neither the names of the copyright holders nor the names of its
18 * contributors may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 */
33
34#include "core.h"
35#include "dbg.h"
36#include "bearer.h"
37#include "port.h"
38#include "link.h"
39#include "zone.h"
40#include "addr.h"
41#include "name_table.h"
42#include "node.h"
43#include "config.h"
44#include "discover.h"
45
46struct subscr_data {
47 char usr_handle[8];
48 u32 domain;
49 u32 port_ref;
50 struct list_head subd_list;
51};
52
53struct manager {
54 u32 user_ref;
55 u32 port_ref;
56 u32 subscr_ref;
57 u32 link_subscriptions;
58 struct list_head link_subscribers;
59};
60
61static struct manager mng = { 0};
62
63static spinlock_t config_lock = SPIN_LOCK_UNLOCKED;
64
65static const void *req_tlv_area; /* request message TLV area */
66static int req_tlv_space; /* request message TLV area size */
67static int rep_headroom; /* reply message headroom to use */
68
69
70void cfg_link_event(u32 addr, char *name, int up)
71{
72 /* TIPC DOESN'T HANDLE LINK EVENT SUBSCRIPTIONS AT THE MOMENT */
73}
74
75
76struct sk_buff *cfg_reply_alloc(int payload_size)
77{
78 struct sk_buff *buf;
79
80 buf = alloc_skb(rep_headroom + payload_size, GFP_ATOMIC);
81 if (buf)
82 skb_reserve(buf, rep_headroom);
83 return buf;
84}
85
86int cfg_append_tlv(struct sk_buff *buf, int tlv_type,
87 void *tlv_data, int tlv_data_size)
88{
89 struct tlv_desc *tlv = (struct tlv_desc *)buf->tail;
90 int new_tlv_space = TLV_SPACE(tlv_data_size);
91
92 if (skb_tailroom(buf) < new_tlv_space) {
93 dbg("cfg_append_tlv unable to append TLV\n");
94 return 0;
95 }
96 skb_put(buf, new_tlv_space);
97 tlv->tlv_type = htons(tlv_type);
98 tlv->tlv_len = htons(TLV_LENGTH(tlv_data_size));
99 if (tlv_data_size && tlv_data)
100 memcpy(TLV_DATA(tlv), tlv_data, tlv_data_size);
101 return 1;
102}
103
104struct sk_buff *cfg_reply_unsigned_type(u16 tlv_type, u32 value)
105{
106 struct sk_buff *buf;
107 u32 value_net;
108
109 buf = cfg_reply_alloc(TLV_SPACE(sizeof(value)));
110 if (buf) {
111 value_net = htonl(value);
112 cfg_append_tlv(buf, tlv_type, &value_net,
113 sizeof(value_net));
114 }
115 return buf;
116}
117
118struct sk_buff *cfg_reply_string_type(u16 tlv_type, char *string)
119{
120 struct sk_buff *buf;
121 int string_len = strlen(string) + 1;
122
123 buf = cfg_reply_alloc(TLV_SPACE(string_len));
124 if (buf)
125 cfg_append_tlv(buf, tlv_type, string, string_len);
126 return buf;
127}
128
129
130
131
132#if 0
133
134/* Now obsolete code for handling commands not yet implemented the new way */
135
136int tipc_cfg_cmd(const struct tipc_cmd_msg * msg,
137 char *data,
138 u32 sz,
139 u32 *ret_size,
140 struct tipc_portid *orig)
141{
142 int rv = -EINVAL;
143 u32 cmd = msg->cmd;
144
145 *ret_size = 0;
146 switch (cmd) {
147 case TIPC_REMOVE_LINK:
148 case TIPC_CMD_BLOCK_LINK:
149 case TIPC_CMD_UNBLOCK_LINK:
150 if (!cfg_check_connection(orig))
151 rv = link_control(msg->argv.link_name, msg->cmd, 0);
152 break;
153 case TIPC_ESTABLISH:
154 {
155 int connected;
156
157 tipc_isconnected(mng.conn_port_ref, &connected);
158 if (connected || !orig) {
159 rv = TIPC_FAILURE;
160 break;
161 }
162 rv = tipc_connect2port(mng.conn_port_ref, orig);
163 if (rv == TIPC_OK)
164 orig = 0;
165 break;
166 }
167 case TIPC_GET_PEER_ADDRESS:
168 *ret_size = link_peer_addr(msg->argv.link_name, data, sz);
169 break;
170 case TIPC_GET_ROUTES:
171 rv = TIPC_OK;
172 break;
173 default: {}
174 }
175 if (*ret_size)
176 rv = TIPC_OK;
177 return rv;
178}
179
180static void cfg_cmd_event(struct tipc_cmd_msg *msg,
181 char *data,
182 u32 sz,
183 struct tipc_portid const *orig)
184{
185 int rv = -EINVAL;
186 struct tipc_cmd_result_msg rmsg;
187 struct iovec msg_sect[2];
188 int *arg;
189
190 msg->cmd = ntohl(msg->cmd);
191
192 cfg_prepare_res_msg(msg->cmd, msg->usr_handle, rv, &rmsg, msg_sect,
193 data, 0);
194 if (ntohl(msg->magic) != TIPC_MAGIC)
195 goto exit;
196
197 switch (msg->cmd) {
198 case TIPC_CREATE_LINK:
199 if (!cfg_check_connection(orig))
200 rv = disc_create_link(&msg->argv.create_link);
201 break;
202 case TIPC_LINK_SUBSCRIBE:
203 {
204 struct subscr_data *sub;
205
206 if (mng.link_subscriptions > 64)
207 break;
208 sub = (struct subscr_data *)kmalloc(sizeof(*sub),
209 GFP_ATOMIC);
210 if (sub == NULL) {
211 warn("Memory squeeze; dropped remote link subscription\n");
212 break;
213 }
214 INIT_LIST_HEAD(&sub->subd_list);
215 tipc_createport(mng.user_ref,
216 (void *)sub,
217 TIPC_HIGH_IMPORTANCE,
218 0,
219 0,
220 (tipc_conn_shutdown_event)cfg_linksubscr_cancel,
221 0,
222 0,
223 (tipc_conn_msg_event)cfg_linksubscr_cancel,
224 0,
225 &sub->port_ref);
226 if (!sub->port_ref) {
227 kfree(sub);
228 break;
229 }
230 memcpy(sub->usr_handle,msg->usr_handle,
231 sizeof(sub->usr_handle));
232 sub->domain = msg->argv.domain;
233 list_add_tail(&sub->subd_list, &mng.link_subscribers);
234 tipc_connect2port(sub->port_ref, orig);
235 rmsg.retval = TIPC_OK;
236 tipc_send(sub->port_ref, 2u, msg_sect);
237 mng.link_subscriptions++;
238 return;
239 }
240 default:
241 rv = tipc_cfg_cmd(msg, data, sz, (u32 *)&msg_sect[1].iov_len, orig);
242 }
243 exit:
244 rmsg.result_len = htonl(msg_sect[1].iov_len);
245 rmsg.retval = htonl(rv);
246 cfg_respond(msg_sect, 2u, orig);
247}
248#endif
249
250static struct sk_buff *cfg_enable_bearer(void)
251{
252 struct tipc_bearer_config *args;
253
254 if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_BEARER_CONFIG))
255 return cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
256
257 args = (struct tipc_bearer_config *)TLV_DATA(req_tlv_area);
258 if (tipc_enable_bearer(args->name,
259 ntohl(args->detect_scope),
260 ntohl(args->priority)))
261 return cfg_reply_error_string("unable to enable bearer");
262
263 return cfg_reply_none();
264}
265
266static struct sk_buff *cfg_disable_bearer(void)
267{
268 if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_BEARER_NAME))
269 return cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
270
271 if (tipc_disable_bearer((char *)TLV_DATA(req_tlv_area)))
272 return cfg_reply_error_string("unable to disable bearer");
273
274 return cfg_reply_none();
275}
276
277static struct sk_buff *cfg_set_own_addr(void)
278{
279 u32 addr;
280
281 if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_NET_ADDR))
282 return cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
283
284 addr = *(u32 *)TLV_DATA(req_tlv_area);
285 addr = ntohl(addr);
286 if (addr == tipc_own_addr)
287 return cfg_reply_none();
288 if (!addr_node_valid(addr))
289 return cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
290 " (node address)");
291 if (tipc_own_addr)
292 return cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
293 " (cannot change node address once assigned)");
294
295 spin_unlock_bh(&config_lock);
296 stop_net();
297 tipc_own_addr = addr;
298 start_net();
299 spin_lock_bh(&config_lock);
300 return cfg_reply_none();
301}
302
303static struct sk_buff *cfg_set_remote_mng(void)
304{
305 u32 value;
306
307 if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
308 return cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
309
310 value = *(u32 *)TLV_DATA(req_tlv_area);
311 value = ntohl(value);
312 tipc_remote_management = (value != 0);
313 return cfg_reply_none();
314}
315
316static struct sk_buff *cfg_set_max_publications(void)
317{
318 u32 value;
319
320 if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
321 return cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
322
323 value = *(u32 *)TLV_DATA(req_tlv_area);
324 value = ntohl(value);
325 if (value != delimit(value, 1, 65535))
326 return cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
327 " (max publications must be 1-65535)");
328 tipc_max_publications = value;
329 return cfg_reply_none();
330}
331
332static struct sk_buff *cfg_set_max_subscriptions(void)
333{
334 u32 value;
335
336 if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
337 return cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
338
339 value = *(u32 *)TLV_DATA(req_tlv_area);
340 value = ntohl(value);
341 if (value != delimit(value, 1, 65535))
342 return cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
343 " (max subscriptions must be 1-65535");
344 tipc_max_subscriptions = value;
345 return cfg_reply_none();
346}
347
348static struct sk_buff *cfg_set_max_ports(void)
349{
350 int orig_mode;
351 u32 value;
352
353 if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
354 return cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
355 value = *(u32 *)TLV_DATA(req_tlv_area);
356 value = ntohl(value);
357 if (value != delimit(value, 127, 65535))
358 return cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
359 " (max ports must be 127-65535)");
360
361 if (value == tipc_max_ports)
362 return cfg_reply_none();
363
364 if (atomic_read(&tipc_user_count) > 2)
365 return cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
366 " (cannot change max ports while TIPC users exist)");
367
368 spin_unlock_bh(&config_lock);
369 orig_mode = tipc_get_mode();
370 if (orig_mode == TIPC_NET_MODE)
371 stop_net();
372 stop_core();
373 tipc_max_ports = value;
374 start_core();
375 if (orig_mode == TIPC_NET_MODE)
376 start_net();
377 spin_lock_bh(&config_lock);
378 return cfg_reply_none();
379}
380
381static struct sk_buff *set_net_max(int value, int *parameter)
382{
383 int orig_mode;
384
385 if (value != *parameter) {
386 orig_mode = tipc_get_mode();
387 if (orig_mode == TIPC_NET_MODE)
388 stop_net();
389 *parameter = value;
390 if (orig_mode == TIPC_NET_MODE)
391 start_net();
392 }
393
394 return cfg_reply_none();
395}
396
397static struct sk_buff *cfg_set_max_zones(void)
398{
399 u32 value;
400
401 if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
402 return cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
403 value = *(u32 *)TLV_DATA(req_tlv_area);
404 value = ntohl(value);
405 if (value != delimit(value, 1, 255))
406 return cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
407 " (max zones must be 1-255)");
408 return set_net_max(value, &tipc_max_zones);
409}
410
411static struct sk_buff *cfg_set_max_clusters(void)
412{
413 u32 value;
414
415 if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
416 return cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
417 value = *(u32 *)TLV_DATA(req_tlv_area);
418 value = ntohl(value);
419 if (value != 1)
420 return cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
421 " (max clusters fixed at 1)");
422 return cfg_reply_none();
423}
424
425static struct sk_buff *cfg_set_max_nodes(void)
426{
427 u32 value;
428
429 if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
430 return cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
431 value = *(u32 *)TLV_DATA(req_tlv_area);
432 value = ntohl(value);
433 if (value != delimit(value, 8, 2047))
434 return cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
435 " (max nodes must be 8-2047)");
436 return set_net_max(value, &tipc_max_nodes);
437}
438
439static struct sk_buff *cfg_set_max_slaves(void)
440{
441 u32 value;
442
443 if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
444 return cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
445 value = *(u32 *)TLV_DATA(req_tlv_area);
446 value = ntohl(value);
447 if (value != 0)
448 return cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
449 " (max secondary nodes fixed at 0)");
450 return cfg_reply_none();
451}
452
453static struct sk_buff *cfg_set_netid(void)
454{
455 u32 value;
456
457 if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
458 return cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
459 value = *(u32 *)TLV_DATA(req_tlv_area);
460 value = ntohl(value);
461 if (value != delimit(value, 1, 9999))
462 return cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
463 " (network id must be 1-9999)");
464
465 if (tipc_own_addr)
466 return cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
467 " (cannot change network id once part of network)");
468
469 return set_net_max(value, &tipc_net_id);
470}
471
472struct sk_buff *cfg_do_cmd(u32 orig_node, u16 cmd, const void *request_area,
473 int request_space, int reply_headroom)
474{
475 struct sk_buff *rep_tlv_buf;
476
477 spin_lock_bh(&config_lock);
478
479 /* Save request and reply details in a well-known location */
480
481 req_tlv_area = request_area;
482 req_tlv_space = request_space;
483 rep_headroom = reply_headroom;
484
485 /* Check command authorization */
486
487 if (likely(orig_node == tipc_own_addr)) {
488 /* command is permitted */
489 } else if (cmd >= 0x8000) {
490 rep_tlv_buf = cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
491 " (cannot be done remotely)");
492 goto exit;
493 } else if (!tipc_remote_management) {
494 rep_tlv_buf = cfg_reply_error_string(TIPC_CFG_NO_REMOTE);
495 goto exit;
496 }
497 else if (cmd >= 0x4000) {
498 u32 domain = 0;
499
500 if ((nametbl_translate(TIPC_ZM_SRV, 0, &domain) == 0) ||
501 (domain != orig_node)) {
502 rep_tlv_buf = cfg_reply_error_string(TIPC_CFG_NOT_ZONE_MSTR);
503 goto exit;
504 }
505 }
506
507 /* Call appropriate processing routine */
508
509 switch (cmd) {
510 case TIPC_CMD_NOOP:
511 rep_tlv_buf = cfg_reply_none();
512 break;
513 case TIPC_CMD_GET_NODES:
514 rep_tlv_buf = node_get_nodes(req_tlv_area, req_tlv_space);
515 break;
516 case TIPC_CMD_GET_LINKS:
517 rep_tlv_buf = node_get_links(req_tlv_area, req_tlv_space);
518 break;
519 case TIPC_CMD_SHOW_LINK_STATS:
520 rep_tlv_buf = link_cmd_show_stats(req_tlv_area, req_tlv_space);
521 break;
522 case TIPC_CMD_RESET_LINK_STATS:
523 rep_tlv_buf = link_cmd_reset_stats(req_tlv_area, req_tlv_space);
524 break;
525 case TIPC_CMD_SHOW_NAME_TABLE:
526 rep_tlv_buf = nametbl_get(req_tlv_area, req_tlv_space);
527 break;
528 case TIPC_CMD_GET_BEARER_NAMES:
529 rep_tlv_buf = bearer_get_names();
530 break;
531 case TIPC_CMD_GET_MEDIA_NAMES:
532 rep_tlv_buf = media_get_names();
533 break;
534 case TIPC_CMD_SHOW_PORTS:
535 rep_tlv_buf = port_get_ports();
536 break;
537#if 0
538 case TIPC_CMD_SHOW_PORT_STATS:
539 rep_tlv_buf = port_show_stats(req_tlv_area, req_tlv_space);
540 break;
541 case TIPC_CMD_RESET_PORT_STATS:
542 rep_tlv_buf = cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED);
543 break;
544#endif
545 case TIPC_CMD_SET_LOG_SIZE:
546 rep_tlv_buf = log_resize(req_tlv_area, req_tlv_space);
547 break;
548 case TIPC_CMD_DUMP_LOG:
549 rep_tlv_buf = log_dump();
550 break;
551 case TIPC_CMD_SET_LINK_TOL:
552 case TIPC_CMD_SET_LINK_PRI:
553 case TIPC_CMD_SET_LINK_WINDOW:
554 rep_tlv_buf = link_cmd_config(req_tlv_area, req_tlv_space, cmd);
555 break;
556 case TIPC_CMD_ENABLE_BEARER:
557 rep_tlv_buf = cfg_enable_bearer();
558 break;
559 case TIPC_CMD_DISABLE_BEARER:
560 rep_tlv_buf = cfg_disable_bearer();
561 break;
562 case TIPC_CMD_SET_NODE_ADDR:
563 rep_tlv_buf = cfg_set_own_addr();
564 break;
565 case TIPC_CMD_SET_REMOTE_MNG:
566 rep_tlv_buf = cfg_set_remote_mng();
567 break;
568 case TIPC_CMD_SET_MAX_PORTS:
569 rep_tlv_buf = cfg_set_max_ports();
570 break;
571 case TIPC_CMD_SET_MAX_PUBL:
572 rep_tlv_buf = cfg_set_max_publications();
573 break;
574 case TIPC_CMD_SET_MAX_SUBSCR:
575 rep_tlv_buf = cfg_set_max_subscriptions();
576 break;
577 case TIPC_CMD_SET_MAX_ZONES:
578 rep_tlv_buf = cfg_set_max_zones();
579 break;
580 case TIPC_CMD_SET_MAX_CLUSTERS:
581 rep_tlv_buf = cfg_set_max_clusters();
582 break;
583 case TIPC_CMD_SET_MAX_NODES:
584 rep_tlv_buf = cfg_set_max_nodes();
585 break;
586 case TIPC_CMD_SET_MAX_SLAVES:
587 rep_tlv_buf = cfg_set_max_slaves();
588 break;
589 case TIPC_CMD_SET_NETID:
590 rep_tlv_buf = cfg_set_netid();
591 break;
592 case TIPC_CMD_GET_REMOTE_MNG:
593 rep_tlv_buf = cfg_reply_unsigned(tipc_remote_management);
594 break;
595 case TIPC_CMD_GET_MAX_PORTS:
596 rep_tlv_buf = cfg_reply_unsigned(tipc_max_ports);
597 break;
598 case TIPC_CMD_GET_MAX_PUBL:
599 rep_tlv_buf = cfg_reply_unsigned(tipc_max_publications);
600 break;
601 case TIPC_CMD_GET_MAX_SUBSCR:
602 rep_tlv_buf = cfg_reply_unsigned(tipc_max_subscriptions);
603 break;
604 case TIPC_CMD_GET_MAX_ZONES:
605 rep_tlv_buf = cfg_reply_unsigned(tipc_max_zones);
606 break;
607 case TIPC_CMD_GET_MAX_CLUSTERS:
608 rep_tlv_buf = cfg_reply_unsigned(tipc_max_clusters);
609 break;
610 case TIPC_CMD_GET_MAX_NODES:
611 rep_tlv_buf = cfg_reply_unsigned(tipc_max_nodes);
612 break;
613 case TIPC_CMD_GET_MAX_SLAVES:
614 rep_tlv_buf = cfg_reply_unsigned(tipc_max_slaves);
615 break;
616 case TIPC_CMD_GET_NETID:
617 rep_tlv_buf = cfg_reply_unsigned(tipc_net_id);
618 break;
619 default:
620 rep_tlv_buf = NULL;
621 break;
622 }
623
624 /* Return reply buffer */
625exit:
626 spin_unlock_bh(&config_lock);
627 return rep_tlv_buf;
628}
629
630static void cfg_named_msg_event(void *userdata,
631 u32 port_ref,
632 struct sk_buff **buf,
633 const unchar *msg,
634 u32 size,
635 u32 importance,
636 struct tipc_portid const *orig,
637 struct tipc_name_seq const *dest)
638{
639 struct tipc_cfg_msg_hdr *req_hdr;
640 struct tipc_cfg_msg_hdr *rep_hdr;
641 struct sk_buff *rep_buf;
642
643 /* Validate configuration message header (ignore invalid message) */
644
645 req_hdr = (struct tipc_cfg_msg_hdr *)msg;
646 if ((size < sizeof(*req_hdr)) ||
647 (size != TCM_ALIGN(ntohl(req_hdr->tcm_len))) ||
648 (ntohs(req_hdr->tcm_flags) != TCM_F_REQUEST)) {
649 warn("discarded invalid configuration message\n");
650 return;
651 }
652
653 /* Generate reply for request (if can't, return request) */
654
655 rep_buf = cfg_do_cmd(orig->node,
656 ntohs(req_hdr->tcm_type),
657 msg + sizeof(*req_hdr),
658 size - sizeof(*req_hdr),
659 BUF_HEADROOM + MAX_H_SIZE + sizeof(*rep_hdr));
660 if (rep_buf) {
661 skb_push(rep_buf, sizeof(*rep_hdr));
662 rep_hdr = (struct tipc_cfg_msg_hdr *)rep_buf->data;
663 memcpy(rep_hdr, req_hdr, sizeof(*rep_hdr));
664 rep_hdr->tcm_len = htonl(rep_buf->len);
665 rep_hdr->tcm_flags &= htons(~TCM_F_REQUEST);
666 } else {
667 rep_buf = *buf;
668 *buf = NULL;
669 }
670
671 /* NEED TO ADD CODE TO HANDLE FAILED SEND (SUCH AS CONGESTION) */
672 tipc_send_buf2port(port_ref, orig, rep_buf, rep_buf->len);
673}
674
675int cfg_init(void)
676{
677 struct tipc_name_seq seq;
678 int res;
679
680 memset(&mng, 0, sizeof(mng));
681 INIT_LIST_HEAD(&mng.link_subscribers);
682
683 res = tipc_attach(&mng.user_ref, 0, 0);
684 if (res)
685 goto failed;
686
687 res = tipc_createport(mng.user_ref, 0, TIPC_CRITICAL_IMPORTANCE,
688 NULL, NULL, NULL,
689 NULL, cfg_named_msg_event, NULL,
690 NULL, &mng.port_ref);
691 if (res)
692 goto failed;
693
694 seq.type = TIPC_CFG_SRV;
695 seq.lower = seq.upper = tipc_own_addr;
696 res = nametbl_publish_rsv(mng.port_ref, TIPC_ZONE_SCOPE, &seq);
697 if (res)
698 goto failed;
699
700 return 0;
701
702failed:
703 err("Unable to create configuration service\n");
704 tipc_detach(mng.user_ref);
705 mng.user_ref = 0;
706 return res;
707}
708
709void cfg_stop(void)
710{
711 if (mng.user_ref) {
712 tipc_detach(mng.user_ref);
713 mng.user_ref = 0;
714 }
715}
diff --git a/net/tipc/config.h b/net/tipc/config.h
new file mode 100644
index 000000000000..7ac0af57bf57
--- /dev/null
+++ b/net/tipc/config.h
@@ -0,0 +1,76 @@
1/*
2 * net/tipc/config.h: Include file for TIPC configuration service code
3 *
4 * Copyright (c) 2003-2005, Ericsson Research Canada
5 * Copyright (c) 2005, Wind River Systems
6 * Copyright (c) 2005-2006, Ericsson AB
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions are met:
11 *
12 * Redistributions of source code must retain the above copyright notice, this
13 * list of conditions and the following disclaimer.
14 * Redistributions in binary form must reproduce the above copyright notice,
15 * this list of conditions and the following disclaimer in the documentation
16 * and/or other materials provided with the distribution.
17 * Neither the names of the copyright holders nor the names of its
18 * contributors may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 */
33
34#ifndef _TIPC_CONFIG_H
35#define _TIPC_CONFIG_H
36
37/* ---------------------------------------------------------------------- */
38
39#include <linux/tipc.h>
40#include "link.h"
41
42struct sk_buff *cfg_reply_alloc(int payload_size);
43int cfg_append_tlv(struct sk_buff *buf, int tlv_type,
44 void *tlv_data, int tlv_data_size);
45struct sk_buff *cfg_reply_unsigned_type(u16 tlv_type, u32 value);
46struct sk_buff *cfg_reply_string_type(u16 tlv_type, char *string);
47
48static inline struct sk_buff *cfg_reply_none(void)
49{
50 return cfg_reply_alloc(0);
51}
52
53static inline struct sk_buff *cfg_reply_unsigned(u32 value)
54{
55 return cfg_reply_unsigned_type(TIPC_TLV_UNSIGNED, value);
56}
57
58static inline struct sk_buff *cfg_reply_error_string(char *string)
59{
60 return cfg_reply_string_type(TIPC_TLV_ERROR_STRING, string);
61}
62
63static inline struct sk_buff *cfg_reply_ultra_string(char *string)
64{
65 return cfg_reply_string_type(TIPC_TLV_ULTRA_STRING, string);
66}
67
68struct sk_buff *cfg_do_cmd(u32 orig_node, u16 cmd,
69 const void *req_tlv_area, int req_tlv_space,
70 int headroom);
71
72void cfg_link_event(u32 addr, char *name, int up);
73int cfg_init(void);
74void cfg_stop(void);
75
76#endif
diff --git a/net/tipc/core.c b/net/tipc/core.c
new file mode 100644
index 000000000000..17c723f49185
--- /dev/null
+++ b/net/tipc/core.c
@@ -0,0 +1,282 @@
1/*
2 * net/tipc/core.c: TIPC module code
3 *
4 * Copyright (c) 2003-2005, Ericsson Research Canada
5 * Copyright (c) 2005, Wind River Systems
6 * Copyright (c) 2005-2006, Ericsson AB
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions are met:
11 *
12 * Redistributions of source code must retain the above copyright notice, this
13 * list of conditions and the following disclaimer.
14 * Redistributions in binary form must reproduce the above copyright notice,
15 * this list of conditions and the following disclaimer in the documentation
16 * and/or other materials provided with the distribution.
17 * Neither the names of the copyright holders nor the names of its
18 * contributors may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 */
33
34#include <linux/init.h>
35#include <linux/module.h>
36#include <linux/kernel.h>
37#include <linux/version.h>
38#include <linux/random.h>
39
40#include "core.h"
41#include "dbg.h"
42#include "ref.h"
43#include "net.h"
44#include "user_reg.h"
45#include "name_table.h"
46#include "subscr.h"
47#include "config.h"
48
49int eth_media_start(void);
50void eth_media_stop(void);
51int handler_start(void);
52void handler_stop(void);
53int socket_init(void);
54void socket_stop(void);
55int netlink_start(void);
56void netlink_stop(void);
57
58#define MOD_NAME "tipc_start: "
59
60#ifndef CONFIG_TIPC_ZONES
61#define CONFIG_TIPC_ZONES 3
62#endif
63
64#ifndef CONFIG_TIPC_CLUSTERS
65#define CONFIG_TIPC_CLUSTERS 1
66#endif
67
68#ifndef CONFIG_TIPC_NODES
69#define CONFIG_TIPC_NODES 255
70#endif
71
72#ifndef CONFIG_TIPC_SLAVE_NODES
73#define CONFIG_TIPC_SLAVE_NODES 0
74#endif
75
76#ifndef CONFIG_TIPC_PORTS
77#define CONFIG_TIPC_PORTS 8191
78#endif
79
80#ifndef CONFIG_TIPC_LOG
81#define CONFIG_TIPC_LOG 0
82#endif
83
84/* global variables used by multiple sub-systems within TIPC */
85
86int tipc_mode = TIPC_NOT_RUNNING;
87int tipc_random;
88atomic_t tipc_user_count = ATOMIC_INIT(0);
89
90const char tipc_alphabet[] =
91 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_";
92
93/* configurable TIPC parameters */
94
95u32 tipc_own_addr;
96int tipc_max_zones;
97int tipc_max_clusters;
98int tipc_max_nodes;
99int tipc_max_slaves;
100int tipc_max_ports;
101int tipc_max_subscriptions;
102int tipc_max_publications;
103int tipc_net_id;
104int tipc_remote_management;
105
106
107int tipc_get_mode(void)
108{
109 return tipc_mode;
110}
111
112/**
113 * stop_net - shut down TIPC networking sub-systems
114 */
115
116void stop_net(void)
117{
118 eth_media_stop();
119 tipc_stop_net();
120}
121
122/**
123 * start_net - start TIPC networking sub-systems
124 */
125
126int start_net(void)
127{
128 int res;
129
130 if ((res = tipc_start_net()) ||
131 (res = eth_media_start())) {
132 stop_net();
133 }
134 return res;
135}
136
137/**
138 * stop_core - switch TIPC from SINGLE NODE to NOT RUNNING mode
139 */
140
141void stop_core(void)
142{
143 if (tipc_mode != TIPC_NODE_MODE)
144 return;
145
146 tipc_mode = TIPC_NOT_RUNNING;
147
148 netlink_stop();
149 handler_stop();
150 cfg_stop();
151 subscr_stop();
152 reg_stop();
153 nametbl_stop();
154 ref_table_stop();
155 socket_stop();
156}
157
158/**
159 * start_core - switch TIPC from NOT RUNNING to SINGLE NODE mode
160 */
161
162int start_core(void)
163{
164 int res;
165
166 if (tipc_mode != TIPC_NOT_RUNNING)
167 return -ENOPROTOOPT;
168
169 get_random_bytes(&tipc_random, sizeof(tipc_random));
170 tipc_mode = TIPC_NODE_MODE;
171
172 if ((res = handler_start()) ||
173 (res = ref_table_init(tipc_max_ports + tipc_max_subscriptions,
174 tipc_random)) ||
175 (res = reg_start()) ||
176 (res = nametbl_init()) ||
177 (res = k_signal((Handler)subscr_start, 0)) ||
178 (res = k_signal((Handler)cfg_init, 0)) ||
179 (res = netlink_start()) ||
180 (res = socket_init())) {
181 stop_core();
182 }
183 return res;
184}
185
186
187static int __init tipc_init(void)
188{
189 int res;
190
191 log_reinit(CONFIG_TIPC_LOG);
192 info("Activated (compiled " __DATE__ " " __TIME__ ")\n");
193
194 tipc_own_addr = 0;
195 tipc_remote_management = 1;
196 tipc_max_publications = 10000;
197 tipc_max_subscriptions = 2000;
198 tipc_max_ports = delimit(CONFIG_TIPC_PORTS, 127, 65536);
199 tipc_max_zones = delimit(CONFIG_TIPC_ZONES, 1, 511);
200 tipc_max_clusters = delimit(CONFIG_TIPC_CLUSTERS, 1, 1);
201 tipc_max_nodes = delimit(CONFIG_TIPC_NODES, 8, 2047);
202 tipc_max_slaves = delimit(CONFIG_TIPC_SLAVE_NODES, 0, 2047);
203 tipc_net_id = 4711;
204
205 if ((res = start_core()))
206 err("Unable to start in single node mode\n");
207 else
208 info("Started in single node mode\n");
209 return res;
210}
211
212static void __exit tipc_exit(void)
213{
214 stop_net();
215 stop_core();
216 info("Deactivated\n");
217 log_stop();
218}
219
220module_init(tipc_init);
221module_exit(tipc_exit);
222
223MODULE_DESCRIPTION("TIPC: Transparent Inter Process Communication");
224MODULE_LICENSE("Dual BSD/GPL");
225
226/* Native TIPC API for kernel-space applications (see tipc.h) */
227
228EXPORT_SYMBOL(tipc_attach);
229EXPORT_SYMBOL(tipc_detach);
230EXPORT_SYMBOL(tipc_get_addr);
231EXPORT_SYMBOL(tipc_get_mode);
232EXPORT_SYMBOL(tipc_createport);
233EXPORT_SYMBOL(tipc_deleteport);
234EXPORT_SYMBOL(tipc_ownidentity);
235EXPORT_SYMBOL(tipc_portimportance);
236EXPORT_SYMBOL(tipc_set_portimportance);
237EXPORT_SYMBOL(tipc_portunreliable);
238EXPORT_SYMBOL(tipc_set_portunreliable);
239EXPORT_SYMBOL(tipc_portunreturnable);
240EXPORT_SYMBOL(tipc_set_portunreturnable);
241EXPORT_SYMBOL(tipc_publish);
242EXPORT_SYMBOL(tipc_withdraw);
243EXPORT_SYMBOL(tipc_connect2port);
244EXPORT_SYMBOL(tipc_disconnect);
245EXPORT_SYMBOL(tipc_shutdown);
246EXPORT_SYMBOL(tipc_isconnected);
247EXPORT_SYMBOL(tipc_peer);
248EXPORT_SYMBOL(tipc_ref_valid);
249EXPORT_SYMBOL(tipc_send);
250EXPORT_SYMBOL(tipc_send_buf);
251EXPORT_SYMBOL(tipc_send2name);
252EXPORT_SYMBOL(tipc_forward2name);
253EXPORT_SYMBOL(tipc_send_buf2name);
254EXPORT_SYMBOL(tipc_forward_buf2name);
255EXPORT_SYMBOL(tipc_send2port);
256EXPORT_SYMBOL(tipc_forward2port);
257EXPORT_SYMBOL(tipc_send_buf2port);
258EXPORT_SYMBOL(tipc_forward_buf2port);
259EXPORT_SYMBOL(tipc_multicast);
260/* EXPORT_SYMBOL(tipc_multicast_buf); not available yet */
261EXPORT_SYMBOL(tipc_ispublished);
262EXPORT_SYMBOL(tipc_available_nodes);
263
264/* TIPC API for external bearers (see tipc_bearer.h) */
265
266EXPORT_SYMBOL(tipc_block_bearer);
267EXPORT_SYMBOL(tipc_continue);
268EXPORT_SYMBOL(tipc_disable_bearer);
269EXPORT_SYMBOL(tipc_enable_bearer);
270EXPORT_SYMBOL(tipc_recv_msg);
271EXPORT_SYMBOL(tipc_register_media);
272
273/* TIPC API for external APIs (see tipc_port.h) */
274
275EXPORT_SYMBOL(tipc_createport_raw);
276EXPORT_SYMBOL(tipc_set_msg_option);
277EXPORT_SYMBOL(tipc_reject_msg);
278EXPORT_SYMBOL(tipc_send_buf_fast);
279EXPORT_SYMBOL(tipc_acknowledge);
280EXPORT_SYMBOL(tipc_get_port);
281EXPORT_SYMBOL(tipc_get_handle);
282
diff --git a/net/tipc/core.h b/net/tipc/core.h
new file mode 100644
index 000000000000..d92898d6c093
--- /dev/null
+++ b/net/tipc/core.h
@@ -0,0 +1,313 @@
1/*
2 * net/tipc/core.h: Include file for TIPC global declarations
3 *
4 * Copyright (c) 2003-2005, Ericsson Research Canada
5 * Copyright (c) 2005, Wind River Systems
6 * Copyright (c) 2005-2006, Ericsson AB
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions are met:
11 *
12 * Redistributions of source code must retain the above copyright notice, this
13 * list of conditions and the following disclaimer.
14 * Redistributions in binary form must reproduce the above copyright notice,
15 * this list of conditions and the following disclaimer in the documentation
16 * and/or other materials provided with the distribution.
17 * Neither the names of the copyright holders nor the names of its
18 * contributors may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 */
33
34#ifndef _TIPC_CORE_H
35#define _TIPC_CORE_H
36
37#include <net/tipc/tipc.h>
38#include <linux/types.h>
39#include <linux/kernel.h>
40#include <linux/errno.h>
41#include <linux/mm.h>
42#include <linux/timer.h>
43#include <linux/string.h>
44#include <asm/uaccess.h>
45#include <linux/interrupt.h>
46#include <asm/atomic.h>
47#include <asm/hardirq.h>
48#include <linux/netdevice.h>
49#include <linux/in.h>
50#include <linux/list.h>
51#include <linux/vmalloc.h>
52
53/*
54 * TIPC debugging code
55 */
56
57#define assert(i) BUG_ON(!(i))
58
59struct tipc_msg;
60extern struct print_buf *CONS, *LOG;
61extern struct print_buf *TEE(struct print_buf *, struct print_buf *);
62void msg_print(struct print_buf*,struct tipc_msg *,const char*);
63void tipc_printf(struct print_buf *, const char *fmt, ...);
64void tipc_dump(struct print_buf*,const char *fmt, ...);
65
66#ifdef CONFIG_TIPC_DEBUG
67
68/*
69 * TIPC debug support included:
70 * - system messages are printed to TIPC_OUTPUT print buffer
71 * - debug messages are printed to DBG_OUTPUT print buffer
72 */
73
74#define err(fmt, arg...) tipc_printf(TIPC_OUTPUT, KERN_ERR "TIPC: " fmt, ## arg)
75#define warn(fmt, arg...) tipc_printf(TIPC_OUTPUT, KERN_WARNING "TIPC: " fmt, ## arg)
76#define info(fmt, arg...) tipc_printf(TIPC_OUTPUT, KERN_NOTICE "TIPC: " fmt, ## arg)
77
78#define dbg(fmt, arg...) do {if (DBG_OUTPUT) tipc_printf(DBG_OUTPUT, fmt, ## arg);} while(0)
79#define msg_dbg(msg, txt) do {if (DBG_OUTPUT) msg_print(DBG_OUTPUT, msg, txt);} while(0)
80#define dump(fmt, arg...) do {if (DBG_OUTPUT) tipc_dump(DBG_OUTPUT, fmt, ##arg);} while(0)
81
82
83/*
84 * By default, TIPC_OUTPUT is defined to be system console and TIPC log buffer,
85 * while DBG_OUTPUT is the null print buffer. These defaults can be changed
86 * here, or on a per .c file basis, by redefining these symbols. The following
87 * print buffer options are available:
88 *
89 * NULL : Output to null print buffer (i.e. print nowhere)
90 * CONS : Output to system console
91 * LOG : Output to TIPC log buffer
92 * &buf : Output to user-defined buffer (struct print_buf *)
93 * TEE(&buf_a,&buf_b) : Output to two print buffers (eg. TEE(CONS,LOG) )
94 */
95
96#ifndef TIPC_OUTPUT
97#define TIPC_OUTPUT TEE(CONS,LOG)
98#endif
99
100#ifndef DBG_OUTPUT
101#define DBG_OUTPUT NULL
102#endif
103
104#else
105
106#ifndef DBG_OUTPUT
107#define DBG_OUTPUT NULL
108#endif
109
110/*
111 * TIPC debug support not included:
112 * - system messages are printed to system console
113 * - debug messages are not printed
114 */
115
116#define err(fmt, arg...) printk(KERN_ERR "%s: " fmt "\n" , __FILE__ , ## arg)
117#define info(fmt, arg...) printk(KERN_INFO "%s: " fmt "\n" , __FILE__ , ## arg)
118#define warn(fmt, arg...) printk(KERN_WARNING "%s: " fmt "\n" , __FILE__ , ## arg)
119
120#define dbg(fmt, arg...) do {} while (0)
121#define msg_dbg(msg,txt) do {} while (0)
122#define dump(fmt,arg...) do {} while (0)
123
124#endif
125
126
127/*
128 * TIPC-specific error codes
129 */
130
131#define ELINKCONG EAGAIN /* link congestion <=> resource unavailable */
132
133/*
134 * Global configuration variables
135 */
136
137extern u32 tipc_own_addr;
138extern int tipc_max_zones;
139extern int tipc_max_clusters;
140extern int tipc_max_nodes;
141extern int tipc_max_slaves;
142extern int tipc_max_ports;
143extern int tipc_max_subscriptions;
144extern int tipc_max_publications;
145extern int tipc_net_id;
146extern int tipc_remote_management;
147
148/*
149 * Other global variables
150 */
151
152extern int tipc_mode;
153extern int tipc_random;
154extern const char tipc_alphabet[];
155extern atomic_t tipc_user_count;
156
157
158/*
159 * Routines available to privileged subsystems
160 */
161
162extern int start_core(void);
163extern void stop_core(void);
164extern int start_net(void);
165extern void stop_net(void);
166
167static inline int delimit(int val, int min, int max)
168{
169 if (val > max)
170 return max;
171 if (val < min)
172 return min;
173 return val;
174}
175
176
177/*
178 * TIPC timer and signal code
179 */
180
181typedef void (*Handler) (unsigned long);
182
183u32 k_signal(Handler routine, unsigned long argument);
184
185/**
186 * k_init_timer - initialize a timer
187 * @timer: pointer to timer structure
188 * @routine: pointer to routine to invoke when timer expires
189 * @argument: value to pass to routine when timer expires
190 *
191 * Timer must be initialized before use (and terminated when no longer needed).
192 */
193
194static inline void k_init_timer(struct timer_list *timer, Handler routine,
195 unsigned long argument)
196{
197 dbg("initializing timer %p\n", timer);
198 init_timer(timer);
199 timer->function = routine;
200 timer->data = argument;
201}
202
203/**
204 * k_start_timer - start a timer
205 * @timer: pointer to timer structure
206 * @msec: time to delay (in ms)
207 *
208 * Schedules a previously initialized timer for later execution.
209 * If timer is already running, the new timeout overrides the previous request.
210 *
211 * To ensure the timer doesn't expire before the specified delay elapses,
212 * the amount of delay is rounded up when converting to the jiffies
213 * then an additional jiffy is added to account for the fact that
214 * the starting time may be in the middle of the current jiffy.
215 */
216
217static inline void k_start_timer(struct timer_list *timer, unsigned long msec)
218{
219 dbg("starting timer %p for %u\n", timer, msec);
220 mod_timer(timer, jiffies + msecs_to_jiffies(msec) + 1);
221}
222
223/**
224 * k_cancel_timer - cancel a timer
225 * @timer: pointer to timer structure
226 *
227 * Cancels a previously initialized timer.
228 * Can be called safely even if the timer is already inactive.
229 *
230 * WARNING: Must not be called when holding locks required by the timer's
231 * timeout routine, otherwise deadlock can occur on SMP systems!
232 */
233
234static inline void k_cancel_timer(struct timer_list *timer)
235{
236 dbg("cancelling timer %p\n", timer);
237 del_timer_sync(timer);
238}
239
240/**
241 * k_term_timer - terminate a timer
242 * @timer: pointer to timer structure
243 *
244 * Prevents further use of a previously initialized timer.
245 *
246 * WARNING: Caller must ensure timer isn't currently running.
247 *
248 * (Do not "enhance" this routine to automatically cancel an active timer,
249 * otherwise deadlock can arise when a timeout routine calls k_term_timer.)
250 */
251
252static inline void k_term_timer(struct timer_list *timer)
253{
254 dbg("terminating timer %p\n", timer);
255}
256
257
258/*
259 * TIPC message buffer code
260 *
261 * TIPC message buffer headroom leaves room for 14 byte Ethernet header,
262 * while ensuring TIPC header is word aligned for quicker access
263 */
264
265#define BUF_HEADROOM 16u
266
267struct tipc_skb_cb {
268 void *handle;
269};
270
271#define TIPC_SKB_CB(__skb) ((struct tipc_skb_cb *)&((__skb)->cb[0]))
272
273
274static inline struct tipc_msg *buf_msg(struct sk_buff *skb)
275{
276 return (struct tipc_msg *)skb->data;
277}
278
279/**
280 * buf_acquire - creates a TIPC message buffer
281 * @size: message size (including TIPC header)
282 *
283 * Returns a new buffer. Space is reserved for a data link header.
284 */
285
286static inline struct sk_buff *buf_acquire(u32 size)
287{
288 struct sk_buff *skb;
289 unsigned int buf_size = (BUF_HEADROOM + size + 3) & ~3u;
290
291 skb = alloc_skb(buf_size, GFP_ATOMIC);
292 if (skb) {
293 skb_reserve(skb, BUF_HEADROOM);
294 skb_put(skb, size);
295 skb->next = NULL;
296 }
297 return skb;
298}
299
300/**
301 * buf_discard - frees a TIPC message buffer
302 * @skb: message buffer
303 *
304 * Frees a new buffer. If passed NULL, just returns.
305 */
306
307static inline void buf_discard(struct sk_buff *skb)
308{
309 if (likely(skb != NULL))
310 kfree_skb(skb);
311}
312
313#endif
diff --git a/net/tipc/dbg.c b/net/tipc/dbg.c
new file mode 100644
index 000000000000..efd6d652d052
--- /dev/null
+++ b/net/tipc/dbg.c
@@ -0,0 +1,392 @@
1/*
2 * net/tipc/dbg.c: TIPC print buffer routines for debuggign
3 *
4 * Copyright (c) 2003-2005, Ericsson Research Canada
5 * Copyright (c) 2005, Wind River Systems
6 * Copyright (c) 2005-2006, Ericsson AB
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions are met:
11 *
12 * Redistributions of source code must retain the above copyright notice, this
13 * list of conditions and the following disclaimer.
14 * Redistributions in binary form must reproduce the above copyright notice,
15 * this list of conditions and the following disclaimer in the documentation
16 * and/or other materials provided with the distribution.
17 * Neither the names of the copyright holders nor the names of its
18 * contributors may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 */
33
34#include "core.h"
35#include "config.h"
36#include "dbg.h"
37
38#define MAX_STRING 512
39
40static char print_string[MAX_STRING];
41static spinlock_t print_lock = SPIN_LOCK_UNLOCKED;
42
43static struct print_buf cons_buf = { NULL, 0, NULL, NULL };
44struct print_buf *CONS = &cons_buf;
45
46static struct print_buf log_buf = { NULL, 0, NULL, NULL };
47struct print_buf *LOG = &log_buf;
48
49
50#define FORMAT(PTR,LEN,FMT) \
51{\
52 va_list args;\
53 va_start(args, FMT);\
54 LEN = vsprintf(PTR, FMT, args);\
55 va_end(args);\
56 *(PTR + LEN) = '\0';\
57}
58
59/*
60 * Locking policy when using print buffers.
61 *
62 * 1) Routines of the form printbuf_XXX() rely on the caller to prevent
63 * simultaneous use of the print buffer(s) being manipulated.
64 * 2) tipc_printf() uses 'print_lock' to prevent simultaneous use of
65 * 'print_string' and to protect its print buffer(s).
66 * 3) TEE() uses 'print_lock' to protect its print buffer(s).
67 * 4) Routines of the form log_XXX() uses 'print_lock' to protect LOG.
68 */
69
70/**
71 * printbuf_init - initialize print buffer to empty
72 */
73
74void printbuf_init(struct print_buf *pb, char *raw, u32 sz)
75{
76 if (!pb || !raw || (sz < (MAX_STRING + 1)))
77 return;
78
79 pb->crs = pb->buf = raw;
80 pb->size = sz;
81 pb->next = 0;
82 pb->buf[0] = 0;
83 pb->buf[sz-1] = ~0;
84}
85
86/**
87 * printbuf_reset - reinitialize print buffer to empty state
88 */
89
90void printbuf_reset(struct print_buf *pb)
91{
92 if (pb && pb->buf)
93 printbuf_init(pb, pb->buf, pb->size);
94}
95
96/**
97 * printbuf_empty - test if print buffer is in empty state
98 */
99
100int printbuf_empty(struct print_buf *pb)
101{
102 return (!pb || !pb->buf || (pb->crs == pb->buf));
103}
104
105/**
106 * printbuf_validate - check for print buffer overflow
107 *
108 * Verifies that a print buffer has captured all data written to it.
109 * If data has been lost, linearize buffer and prepend an error message
110 *
111 * Returns length of print buffer data string (including trailing NULL)
112 */
113
114int printbuf_validate(struct print_buf *pb)
115{
116 char *err = " *** PRINT BUFFER WRAPPED AROUND ***\n";
117 char *cp_buf;
118 struct print_buf cb;
119
120 if (!pb || !pb->buf)
121 return 0;
122
123 if (pb->buf[pb->size - 1] == '\0') {
124 cp_buf = kmalloc(pb->size, GFP_ATOMIC);
125 if (cp_buf != NULL){
126 printbuf_init(&cb, cp_buf, pb->size);
127 printbuf_move(&cb, pb);
128 printbuf_move(pb, &cb);
129 kfree(cp_buf);
130 memcpy(pb->buf, err, strlen(err));
131 } else {
132 printbuf_reset(pb);
133 tipc_printf(pb, err);
134 }
135 }
136 return (pb->crs - pb->buf + 1);
137}
138
139/**
140 * printbuf_move - move print buffer contents to another print buffer
141 *
142 * Current contents of destination print buffer (if any) are discarded.
143 * Source print buffer becomes empty if a successful move occurs.
144 */
145
146void printbuf_move(struct print_buf *pb_to, struct print_buf *pb_from)
147{
148 int len;
149
150 /* Handle the cases where contents can't be moved */
151
152 if (!pb_to || !pb_to->buf)
153 return;
154
155 if (!pb_from || !pb_from->buf) {
156 printbuf_reset(pb_to);
157 return;
158 }
159
160 if (pb_to->size < pb_from->size) {
161 printbuf_reset(pb_to);
162 tipc_printf(pb_to, "*** PRINT BUFFER OVERFLOW ***");
163 return;
164 }
165
166 /* Copy data from char after cursor to end (if used) */
167 len = pb_from->buf + pb_from->size - pb_from->crs - 2;
168 if ((pb_from->buf[pb_from->size-1] == 0) && (len > 0)) {
169 strcpy(pb_to->buf, pb_from->crs + 1);
170 pb_to->crs = pb_to->buf + len;
171 } else
172 pb_to->crs = pb_to->buf;
173
174 /* Copy data from start to cursor (always) */
175 len = pb_from->crs - pb_from->buf;
176 strcpy(pb_to->crs, pb_from->buf);
177 pb_to->crs += len;
178
179 printbuf_reset(pb_from);
180}
181
182/**
183 * tipc_printf - append formatted output to print buffer chain
184 */
185
186void tipc_printf(struct print_buf *pb, const char *fmt, ...)
187{
188 int chars_to_add;
189 int chars_left;
190 char save_char;
191 struct print_buf *pb_next;
192
193 spin_lock_bh(&print_lock);
194 FORMAT(print_string, chars_to_add, fmt);
195 if (chars_to_add >= MAX_STRING)
196 strcpy(print_string, "*** STRING TOO LONG ***");
197
198 while (pb) {
199 if (pb == CONS)
200 printk(print_string);
201 else if (pb->buf) {
202 chars_left = pb->buf + pb->size - pb->crs - 1;
203 if (chars_to_add <= chars_left) {
204 strcpy(pb->crs, print_string);
205 pb->crs += chars_to_add;
206 } else {
207 strcpy(pb->buf, print_string + chars_left);
208 save_char = print_string[chars_left];
209 print_string[chars_left] = 0;
210 strcpy(pb->crs, print_string);
211 print_string[chars_left] = save_char;
212 pb->crs = pb->buf + chars_to_add - chars_left;
213 }
214 }
215 pb_next = pb->next;
216 pb->next = 0;
217 pb = pb_next;
218 }
219 spin_unlock_bh(&print_lock);
220}
221
222/**
223 * TEE - perform next output operation on both print buffers
224 */
225
226struct print_buf *TEE(struct print_buf *b0, struct print_buf *b1)
227{
228 struct print_buf *pb = b0;
229
230 if (!b0 || (b0 == b1))
231 return b1;
232 if (!b1)
233 return b0;
234
235 spin_lock_bh(&print_lock);
236 while (pb->next) {
237 if ((pb->next == b1) || (pb->next == b0))
238 pb->next = pb->next->next;
239 else
240 pb = pb->next;
241 }
242 pb->next = b1;
243 spin_unlock_bh(&print_lock);
244 return b0;
245}
246
247/**
248 * print_to_console - write string of bytes to console in multiple chunks
249 */
250
251static void print_to_console(char *crs, int len)
252{
253 int rest = len;
254
255 while (rest > 0) {
256 int sz = rest < MAX_STRING ? rest : MAX_STRING;
257 char c = crs[sz];
258
259 crs[sz] = 0;
260 printk((const char *)crs);
261 crs[sz] = c;
262 rest -= sz;
263 crs += sz;
264 }
265}
266
267/**
268 * printbuf_dump - write print buffer contents to console
269 */
270
271static void printbuf_dump(struct print_buf *pb)
272{
273 int len;
274
275 /* Dump print buffer from char after cursor to end (if used) */
276 len = pb->buf + pb->size - pb->crs - 2;
277 if ((pb->buf[pb->size - 1] == 0) && (len > 0))
278 print_to_console(pb->crs + 1, len);
279
280 /* Dump print buffer from start to cursor (always) */
281 len = pb->crs - pb->buf;
282 print_to_console(pb->buf, len);
283}
284
285/**
286 * tipc_dump - dump non-console print buffer(s) to console
287 */
288
289void tipc_dump(struct print_buf *pb, const char *fmt, ...)
290{
291 int len;
292
293 spin_lock_bh(&print_lock);
294 FORMAT(CONS->buf, len, fmt);
295 printk(CONS->buf);
296
297 for (; pb; pb = pb->next) {
298 if (pb == CONS)
299 continue;
300 printk("\n---- Start of dump,%s log ----\n\n",
301 (pb == LOG) ? "global" : "local");
302 printbuf_dump(pb);
303 printbuf_reset(pb);
304 printk("\n-------- End of dump --------\n");
305 }
306 spin_unlock_bh(&print_lock);
307}
308
309/**
310 * log_stop - free up TIPC log print buffer
311 */
312
313void log_stop(void)
314{
315 spin_lock_bh(&print_lock);
316 if (LOG->buf) {
317 kfree(LOG->buf);
318 LOG->buf = NULL;
319 }
320 spin_unlock_bh(&print_lock);
321}
322
323/**
324 * log_reinit - set TIPC log print buffer to specified size
325 */
326
327void log_reinit(int log_size)
328{
329 log_stop();
330
331 if (log_size) {
332 if (log_size <= MAX_STRING)
333 log_size = MAX_STRING + 1;
334 spin_lock_bh(&print_lock);
335 printbuf_init(LOG, kmalloc(log_size, GFP_ATOMIC), log_size);
336 spin_unlock_bh(&print_lock);
337 }
338}
339
340/**
341 * log_resize - reconfigure size of TIPC log buffer
342 */
343
344struct sk_buff *log_resize(const void *req_tlv_area, int req_tlv_space)
345{
346 u32 value;
347
348 if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
349 return cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
350
351 value = *(u32 *)TLV_DATA(req_tlv_area);
352 value = ntohl(value);
353 if (value != delimit(value, 0, 32768))
354 return cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
355 " (log size must be 0-32768)");
356 log_reinit(value);
357 return cfg_reply_none();
358}
359
360/**
361 * log_dump - capture TIPC log buffer contents in configuration message
362 */
363
364struct sk_buff *log_dump(void)
365{
366 struct sk_buff *reply;
367
368 spin_lock_bh(&print_lock);
369 if (!LOG->buf)
370 reply = cfg_reply_ultra_string("log not activated\n");
371 else if (printbuf_empty(LOG))
372 reply = cfg_reply_ultra_string("log is empty\n");
373 else {
374 struct tlv_desc *rep_tlv;
375 struct print_buf pb;
376 int str_len;
377
378 str_len = min(LOG->size, 32768u);
379 reply = cfg_reply_alloc(TLV_SPACE(str_len));
380 if (reply) {
381 rep_tlv = (struct tlv_desc *)reply->data;
382 printbuf_init(&pb, TLV_DATA(rep_tlv), str_len);
383 printbuf_move(&pb, LOG);
384 str_len = strlen(TLV_DATA(rep_tlv)) + 1;
385 skb_put(reply, TLV_SPACE(str_len));
386 TLV_SET(rep_tlv, TIPC_TLV_ULTRA_STRING, NULL, str_len);
387 }
388 }
389 spin_unlock_bh(&print_lock);
390 return reply;
391}
392
diff --git a/net/tipc/dbg.h b/net/tipc/dbg.h
new file mode 100644
index 000000000000..af4217a993cf
--- /dev/null
+++ b/net/tipc/dbg.h
@@ -0,0 +1,56 @@
1/*
2 * net/tipc/dbg.h: Include file for TIPC print buffer routines
3 *
4 * Copyright (c) 2003-2005, Ericsson Research Canada
5 * Copyright (c) 2005, Wind River Systems
6 * Copyright (c) 2005-2006, Ericsson AB
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions are met:
11 *
12 * Redistributions of source code must retain the above copyright notice, this
13 * list of conditions and the following disclaimer.
14 * Redistributions in binary form must reproduce the above copyright notice,
15 * this list of conditions and the following disclaimer in the documentation
16 * and/or other materials provided with the distribution.
17 * Neither the names of the copyright holders nor the names of its
18 * contributors may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 */
33
34#ifndef _TIPC_DBG_H
35#define _TIPC_DBG_H
36
37struct print_buf {
38 char *buf;
39 u32 size;
40 char *crs;
41 struct print_buf *next;
42};
43
44void printbuf_init(struct print_buf *pb, char *buf, u32 sz);
45void printbuf_reset(struct print_buf *pb);
46int printbuf_empty(struct print_buf *pb);
47int printbuf_validate(struct print_buf *pb);
48void printbuf_move(struct print_buf *pb_to, struct print_buf *pb_from);
49
50void log_reinit(int log_size);
51void log_stop(void);
52
53struct sk_buff *log_resize(const void *req_tlv_area, int req_tlv_space);
54struct sk_buff *log_dump(void);
55
56#endif
diff --git a/net/tipc/discover.c b/net/tipc/discover.c
new file mode 100644
index 000000000000..c83c1be17f85
--- /dev/null
+++ b/net/tipc/discover.c
@@ -0,0 +1,339 @@
1/*
2 * net/tipc/discover.c
3 *
4 * Copyright (c) 2003-2005, Ericsson Research Canada
5 * Copyright (c) 2005, Wind River Systems
6 * Copyright (c) 2005-2006, Ericsson AB
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions are met:
11 *
12 * Redistributions of source code must retain the above copyright notice, this
13 * list of conditions and the following disclaimer.
14 * Redistributions in binary form must reproduce the above copyright notice,
15 * this list of conditions and the following disclaimer in the documentation
16 * and/or other materials provided with the distribution.
17 * Neither the names of the copyright holders nor the names of its
18 * contributors may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 */
33
34#include "core.h"
35#include "dbg.h"
36#include "link.h"
37#include "zone.h"
38#include "discover.h"
39#include "port.h"
40#include "name_table.h"
41
42#define TIPC_LINK_REQ_INIT 125 /* min delay during bearer start up */
43#define TIPC_LINK_REQ_FAST 2000 /* normal delay if bearer has no links */
44#define TIPC_LINK_REQ_SLOW 600000 /* normal delay if bearer has links */
45
46#if 0
47#define GET_NODE_INFO 300
48#define GET_NODE_INFO_RESULT 301
49#define FORWARD_LINK_PROBE 302
50#define LINK_REQUEST_REJECTED 303
51#define LINK_REQUEST_ACCEPTED 304
52#define DROP_LINK_REQUEST 305
53#define CHECK_LINK_COUNT 306
54#endif
55
56/*
57 * TODO: Most of the inter-cluster setup stuff should be
58 * rewritten, and be made conformant with specification.
59 */
60
61
62/**
63 * struct link_req - information about an ongoing link setup request
64 * @bearer: bearer issuing requests
65 * @dest: destination address for request messages
66 * @buf: request message to be (repeatedly) sent
67 * @timer: timer governing period between requests
68 * @timer_intv: current interval between requests (in ms)
69 */
70struct link_req {
71 struct bearer *bearer;
72 struct tipc_media_addr dest;
73 struct sk_buff *buf;
74 struct timer_list timer;
75 unsigned int timer_intv;
76};
77
78
79#if 0
80int disc_create_link(const struct tipc_link_create *argv)
81{
82 /*
83 * Code for inter cluster link setup here
84 */
85 return TIPC_OK;
86}
87#endif
88
89/*
90 * disc_lost_link(): A link has lost contact
91 */
92
93void disc_link_event(u32 addr, char *name, int up)
94{
95 if (in_own_cluster(addr))
96 return;
97 /*
98 * Code for inter cluster link setup here
99 */
100}
101
102/**
103 * disc_init_msg - initialize a link setup message
104 * @type: message type (request or response)
105 * @req_links: number of links associated with message
106 * @dest_domain: network domain of node(s) which should respond to message
107 * @b_ptr: ptr to bearer issuing message
108 */
109
110struct sk_buff *disc_init_msg(u32 type,
111 u32 req_links,
112 u32 dest_domain,
113 struct bearer *b_ptr)
114{
115 struct sk_buff *buf = buf_acquire(DSC_H_SIZE);
116 struct tipc_msg *msg;
117
118 if (buf) {
119 msg = buf_msg(buf);
120 msg_init(msg, LINK_CONFIG, type, TIPC_OK, DSC_H_SIZE,
121 dest_domain);
122 msg_set_non_seq(msg);
123 msg_set_req_links(msg, req_links);
124 msg_set_dest_domain(msg, dest_domain);
125 msg_set_bc_netid(msg, tipc_net_id);
126 msg_set_media_addr(msg, &b_ptr->publ.addr);
127 }
128 return buf;
129}
130
131/**
132 * disc_recv_msg - handle incoming link setup message (request or response)
133 * @buf: buffer containing message
134 */
135
136void disc_recv_msg(struct sk_buff *buf)
137{
138 struct bearer *b_ptr = (struct bearer *)TIPC_SKB_CB(buf)->handle;
139 struct link *link;
140 struct tipc_media_addr media_addr;
141 struct tipc_msg *msg = buf_msg(buf);
142 u32 dest = msg_dest_domain(msg);
143 u32 orig = msg_prevnode(msg);
144 u32 net_id = msg_bc_netid(msg);
145 u32 type = msg_type(msg);
146
147 msg_get_media_addr(msg,&media_addr);
148 msg_dbg(msg, "RECV:");
149 buf_discard(buf);
150
151 if (net_id != tipc_net_id)
152 return;
153 if (!addr_domain_valid(dest))
154 return;
155 if (!addr_node_valid(orig))
156 return;
157 if (orig == tipc_own_addr)
158 return;
159 if (!in_scope(dest, tipc_own_addr))
160 return;
161 if (is_slave(tipc_own_addr) && is_slave(orig))
162 return;
163 if (is_slave(orig) && !in_own_cluster(orig))
164 return;
165 if (in_own_cluster(orig)) {
166 /* Always accept link here */
167 struct sk_buff *rbuf;
168 struct tipc_media_addr *addr;
169 struct node *n_ptr = node_find(orig);
170 int link_up;
171 dbg(" in own cluster\n");
172 if (n_ptr == NULL) {
173 n_ptr = node_create(orig);
174 }
175 if (n_ptr == NULL) {
176 warn("Memory squeeze; Failed to create node\n");
177 return;
178 }
179 spin_lock_bh(&n_ptr->lock);
180 link = n_ptr->links[b_ptr->identity];
181 if (!link) {
182 dbg("creating link\n");
183 link = link_create(b_ptr, orig, &media_addr);
184 if (!link) {
185 spin_unlock_bh(&n_ptr->lock);
186 return;
187 }
188 }
189 addr = &link->media_addr;
190 if (memcmp(addr, &media_addr, sizeof(*addr))) {
191 char addr_string[16];
192
193 warn("New bearer address for %s\n",
194 addr_string_fill(addr_string, orig));
195 memcpy(addr, &media_addr, sizeof(*addr));
196 link_reset(link);
197 }
198 link_up = link_is_up(link);
199 spin_unlock_bh(&n_ptr->lock);
200 if ((type == DSC_RESP_MSG) || link_up)
201 return;
202 rbuf = disc_init_msg(DSC_RESP_MSG, 1, orig, b_ptr);
203 if (rbuf != NULL) {
204 msg_dbg(buf_msg(rbuf),"SEND:");
205 b_ptr->media->send_msg(rbuf, &b_ptr->publ, &media_addr);
206 buf_discard(rbuf);
207 }
208 }
209}
210
211/**
212 * disc_stop_link_req - stop sending periodic link setup requests
213 * @req: ptr to link request structure
214 */
215
216void disc_stop_link_req(struct link_req *req)
217{
218 if (!req)
219 return;
220
221 k_cancel_timer(&req->timer);
222 k_term_timer(&req->timer);
223 buf_discard(req->buf);
224 kfree(req);
225}
226
227/**
228 * disc_update_link_req - update frequency of periodic link setup requests
229 * @req: ptr to link request structure
230 */
231
232void disc_update_link_req(struct link_req *req)
233{
234 if (!req)
235 return;
236
237 if (req->timer_intv == TIPC_LINK_REQ_SLOW) {
238 if (!req->bearer->nodes.count) {
239 req->timer_intv = TIPC_LINK_REQ_FAST;
240 k_start_timer(&req->timer, req->timer_intv);
241 }
242 } else if (req->timer_intv == TIPC_LINK_REQ_FAST) {
243 if (req->bearer->nodes.count) {
244 req->timer_intv = TIPC_LINK_REQ_SLOW;
245 k_start_timer(&req->timer, req->timer_intv);
246 }
247 } else {
248 /* leave timer "as is" if haven't yet reached a "normal" rate */
249 }
250}
251
252/**
253 * disc_timeout - send a periodic link setup request
254 * @req: ptr to link request structure
255 *
256 * Called whenever a link setup request timer associated with a bearer expires.
257 */
258
259static void disc_timeout(struct link_req *req)
260{
261 struct tipc_msg *msg = buf_msg(req->buf);
262
263 spin_lock_bh(&req->bearer->publ.lock);
264
265#if 0
266 /* CURRENTLY DON'T SUPPORT INTER-ZONE LINKS */
267 u32 dest_domain = msg_dest_domain(msg);
268 int stop = 0;
269 if (!in_scope(dest_domain, tipc_own_addr)) {
270 struct _zone *z_ptr = zone_find(dest_domain);
271
272 if (z_ptr && (z_ptr->links >= msg_req_links(msg)))
273 stop = 1;
274 if (req->timer_intv >= 32000)
275 stop = 1;
276 }
277 if (stop) {
278 k_cancel_timer(&req->timer);
279 buf_discard(req->buf);
280 kfree(req);
281 spin_unlock_bh(&req->bearer->publ.lock);
282 return;
283 }
284#endif
285
286 msg_dbg(msg,"SEND:");
287 req->bearer->media->send_msg(req->buf, &req->bearer->publ, &req->dest);
288
289 if ((req->timer_intv == TIPC_LINK_REQ_SLOW) ||
290 (req->timer_intv == TIPC_LINK_REQ_FAST)) {
291 /* leave timer interval "as is" if already at a "normal" rate */
292 } else {
293 req->timer_intv *= 2;
294 if (req->timer_intv > TIPC_LINK_REQ_FAST)
295 req->timer_intv = TIPC_LINK_REQ_FAST;
296 if ((req->timer_intv == TIPC_LINK_REQ_FAST) &&
297 (req->bearer->nodes.count))
298 req->timer_intv = TIPC_LINK_REQ_SLOW;
299 }
300 k_start_timer(&req->timer, req->timer_intv);
301
302 spin_unlock_bh(&req->bearer->publ.lock);
303}
304
305/**
306 * disc_init_link_req - start sending periodic link setup requests
307 * @b_ptr: ptr to bearer issuing requests
308 * @dest: destination address for request messages
309 * @dest_domain: network domain of node(s) which should respond to message
310 * @req_links: max number of desired links
311 *
312 * Returns pointer to link request structure, or NULL if unable to create.
313 */
314
315struct link_req *disc_init_link_req(struct bearer *b_ptr,
316 const struct tipc_media_addr *dest,
317 u32 dest_domain,
318 u32 req_links)
319{
320 struct link_req *req;
321
322 req = (struct link_req *)kmalloc(sizeof(*req), GFP_ATOMIC);
323 if (!req)
324 return NULL;
325
326 req->buf = disc_init_msg(DSC_REQ_MSG, req_links, dest_domain, b_ptr);
327 if (!req->buf) {
328 kfree(req);
329 return NULL;
330 }
331
332 memcpy(&req->dest, dest, sizeof(*dest));
333 req->bearer = b_ptr;
334 req->timer_intv = TIPC_LINK_REQ_INIT;
335 k_init_timer(&req->timer, (Handler)disc_timeout, (unsigned long)req);
336 k_start_timer(&req->timer, req->timer_intv);
337 return req;
338}
339
diff --git a/net/tipc/discover.h b/net/tipc/discover.h
new file mode 100644
index 000000000000..90c1de905e78
--- /dev/null
+++ b/net/tipc/discover.h
@@ -0,0 +1,55 @@
1/*
2 * net/tipc/discover.h
3 *
4 * Copyright (c) 2003-2005, Ericsson Research Canada
5 * Copyright (c) 2005, Wind River Systems
6 * Copyright (c) 2005-2006, Ericsson AB
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions are met:
11 *
12 * Redistributions of source code must retain the above copyright notice, this
13 * list of conditions and the following disclaimer.
14 * Redistributions in binary form must reproduce the above copyright notice,
15 * this list of conditions and the following disclaimer in the documentation
16 * and/or other materials provided with the distribution.
17 * Neither the names of the copyright holders nor the names of its
18 * contributors may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 */
33
34#ifndef _TIPC_DISCOVER_H
35#define _TIPC_DISCOVER_H
36
37#include <linux/tipc.h>
38
39struct link_req;
40
41struct link_req *disc_init_link_req(struct bearer *b_ptr,
42 const struct tipc_media_addr *dest,
43 u32 dest_domain,
44 u32 req_links);
45void disc_update_link_req(struct link_req *req);
46void disc_stop_link_req(struct link_req *req);
47
48void disc_recv_msg(struct sk_buff *buf);
49
50void disc_link_event(u32 addr, char *name, int up);
51#if 0
52int disc_create_link(const struct tipc_link_create *argv);
53#endif
54
55#endif
diff --git a/net/tipc/eth_media.c b/net/tipc/eth_media.c
new file mode 100644
index 000000000000..b634d7a5640e
--- /dev/null
+++ b/net/tipc/eth_media.c
@@ -0,0 +1,296 @@
1/*
2 * net/tipc/eth_media.c: Ethernet bearer support for TIPC
3 *
4 * Copyright (c) 2003-2005, Ericsson Research Canada
5 * Copyright (c) 2005, Wind River Systems
6 * Copyright (c) 2005-2006, Ericsson AB
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions are met:
11 *
12 * Redistributions of source code must retain the above copyright notice, this
13 * list of conditions and the following disclaimer.
14 * Redistributions in binary form must reproduce the above copyright notice,
15 * this list of conditions and the following disclaimer in the documentation
16 * and/or other materials provided with the distribution.
17 * Neither the names of the copyright holders nor the names of its
18 * contributors may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 */
33
34#include <net/tipc/tipc.h>
35#include <net/tipc/tipc_bearer.h>
36#include <net/tipc/tipc_msg.h>
37#include <linux/netdevice.h>
38#include <linux/version.h>
39
40#define MAX_ETH_BEARERS 2
41#define TIPC_PROTOCOL 0x88ca
42#define ETH_LINK_PRIORITY 10
43#define ETH_LINK_TOLERANCE TIPC_DEF_LINK_TOL
44
45
46/**
47 * struct eth_bearer - Ethernet bearer data structure
48 * @bearer: ptr to associated "generic" bearer structure
49 * @dev: ptr to associated Ethernet network device
50 * @tipc_packet_type: used in binding TIPC to Ethernet driver
51 */
52
53struct eth_bearer {
54 struct tipc_bearer *bearer;
55 struct net_device *dev;
56 struct packet_type tipc_packet_type;
57};
58
59static struct eth_bearer eth_bearers[MAX_ETH_BEARERS];
60static int eth_started = 0;
61static struct notifier_block notifier;
62
63/**
64 * send_msg - send a TIPC message out over an Ethernet interface
65 */
66
67static int send_msg(struct sk_buff *buf, struct tipc_bearer *tb_ptr,
68 struct tipc_media_addr *dest)
69{
70 struct sk_buff *clone;
71 struct net_device *dev;
72
73 clone = skb_clone(buf, GFP_ATOMIC);
74 if (clone) {
75 clone->nh.raw = clone->data;
76 dev = ((struct eth_bearer *)(tb_ptr->usr_handle))->dev;
77 clone->dev = dev;
78 dev->hard_header(clone, dev, TIPC_PROTOCOL,
79 &dest->dev_addr.eth_addr,
80 dev->dev_addr, clone->len);
81 dev_queue_xmit(clone);
82 }
83 return TIPC_OK;
84}
85
86/**
87 * recv_msg - handle incoming TIPC message from an Ethernet interface
88 *
89 * Routine truncates any Ethernet padding/CRC appended to the message,
90 * and ensures message size matches actual length
91 */
92
93static int recv_msg(struct sk_buff *buf, struct net_device *dev,
94 struct packet_type *pt, struct net_device *orig_dev)
95{
96 struct eth_bearer *eb_ptr = (struct eth_bearer *)pt->af_packet_priv;
97 u32 size;
98
99 if (likely(eb_ptr->bearer)) {
100 size = msg_size((struct tipc_msg *)buf->data);
101 skb_trim(buf, size);
102 if (likely(buf->len == size)) {
103 buf->next = NULL;
104 tipc_recv_msg(buf, eb_ptr->bearer);
105 } else {
106 kfree_skb(buf);
107 }
108 } else {
109 kfree_skb(buf);
110 }
111 return TIPC_OK;
112}
113
114/**
115 * enable_bearer - attach TIPC bearer to an Ethernet interface
116 */
117
118static int enable_bearer(struct tipc_bearer *tb_ptr)
119{
120 struct net_device *dev = dev_base;
121 struct eth_bearer *eb_ptr = &eth_bearers[0];
122 struct eth_bearer *stop = &eth_bearers[MAX_ETH_BEARERS];
123 char *driver_name = strchr((const char *)tb_ptr->name, ':') + 1;
124
125 /* Find device with specified name */
126
127 while (dev && dev->name &&
128 (memcmp(dev->name, driver_name, strlen(dev->name)))) {
129 dev = dev->next;
130 }
131 if (!dev)
132 return -ENODEV;
133
134 /* Find Ethernet bearer for device (or create one) */
135
136 for (;(eb_ptr != stop) && eb_ptr->dev && (eb_ptr->dev != dev); eb_ptr++);
137 if (eb_ptr == stop)
138 return -EDQUOT;
139 if (!eb_ptr->dev) {
140 eb_ptr->dev = dev;
141 eb_ptr->tipc_packet_type.type = __constant_htons(TIPC_PROTOCOL);
142 eb_ptr->tipc_packet_type.dev = dev;
143 eb_ptr->tipc_packet_type.func = recv_msg;
144 eb_ptr->tipc_packet_type.af_packet_priv = eb_ptr;
145 INIT_LIST_HEAD(&(eb_ptr->tipc_packet_type.list));
146 dev_hold(dev);
147 dev_add_pack(&eb_ptr->tipc_packet_type);
148 }
149
150 /* Associate TIPC bearer with Ethernet bearer */
151
152 eb_ptr->bearer = tb_ptr;
153 tb_ptr->usr_handle = (void *)eb_ptr;
154 tb_ptr->mtu = dev->mtu;
155 tb_ptr->blocked = 0;
156 tb_ptr->addr.type = htonl(TIPC_MEDIA_TYPE_ETH);
157 memcpy(&tb_ptr->addr.dev_addr, &dev->dev_addr, ETH_ALEN);
158 return 0;
159}
160
161/**
162 * disable_bearer - detach TIPC bearer from an Ethernet interface
163 *
164 * We really should do dev_remove_pack() here, but this function can not be
165 * called at tasklet level. => Use eth_bearer->bearer as a flag to throw away
166 * incoming buffers, & postpone dev_remove_pack() to eth_media_stop() on exit.
167 */
168
169static void disable_bearer(struct tipc_bearer *tb_ptr)
170{
171 ((struct eth_bearer *)tb_ptr->usr_handle)->bearer = 0;
172}
173
174/**
175 * recv_notification - handle device updates from OS
176 *
177 * Change the state of the Ethernet bearer (if any) associated with the
178 * specified device.
179 */
180
181static int recv_notification(struct notifier_block *nb, unsigned long evt,
182 void *dv)
183{
184 struct net_device *dev = (struct net_device *)dv;
185 struct eth_bearer *eb_ptr = &eth_bearers[0];
186 struct eth_bearer *stop = &eth_bearers[MAX_ETH_BEARERS];
187
188 while ((eb_ptr->dev != dev)) {
189 if (++eb_ptr == stop)
190 return NOTIFY_DONE; /* couldn't find device */
191 }
192 if (!eb_ptr->bearer)
193 return NOTIFY_DONE; /* bearer had been disabled */
194
195 eb_ptr->bearer->mtu = dev->mtu;
196
197 switch (evt) {
198 case NETDEV_CHANGE:
199 if (netif_carrier_ok(dev))
200 tipc_continue(eb_ptr->bearer);
201 else
202 tipc_block_bearer(eb_ptr->bearer->name);
203 break;
204 case NETDEV_UP:
205 tipc_continue(eb_ptr->bearer);
206 break;
207 case NETDEV_DOWN:
208 tipc_block_bearer(eb_ptr->bearer->name);
209 break;
210 case NETDEV_CHANGEMTU:
211 case NETDEV_CHANGEADDR:
212 tipc_block_bearer(eb_ptr->bearer->name);
213 tipc_continue(eb_ptr->bearer);
214 break;
215 case NETDEV_UNREGISTER:
216 case NETDEV_CHANGENAME:
217 tipc_disable_bearer(eb_ptr->bearer->name);
218 break;
219 }
220 return NOTIFY_OK;
221}
222
223/**
224 * eth_addr2str - convert Ethernet address to string
225 */
226
227static char *eth_addr2str(struct tipc_media_addr *a, char *str_buf, int str_size)
228{
229 unchar *addr = (unchar *)&a->dev_addr;
230
231 if (str_size < 18)
232 *str_buf = '\0';
233 else
234 sprintf(str_buf, "%02x:%02x:%02x:%02x:%02x:%02x",
235 addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
236 return str_buf;
237}
238
239/**
240 * eth_media_start - activate Ethernet bearer support
241 *
242 * Register Ethernet media type with TIPC bearer code. Also register
243 * with OS for notifications about device state changes.
244 */
245
246int eth_media_start(void)
247{
248 struct tipc_media_addr bcast_addr;
249 int res;
250
251 if (eth_started)
252 return -EINVAL;
253
254 memset(&bcast_addr, 0xff, sizeof(bcast_addr));
255 memset(eth_bearers, 0, sizeof(eth_bearers));
256
257 res = tipc_register_media(TIPC_MEDIA_TYPE_ETH, "eth",
258 enable_bearer, disable_bearer, send_msg,
259 eth_addr2str, &bcast_addr, ETH_LINK_PRIORITY,
260 ETH_LINK_TOLERANCE, TIPC_DEF_LINK_WIN);
261 if (res)
262 return res;
263
264 notifier.notifier_call = &recv_notification;
265 notifier.priority = 0;
266 res = register_netdevice_notifier(&notifier);
267 if (!res)
268 eth_started = 1;
269 return res;
270}
271
272/**
273 * eth_media_stop - deactivate Ethernet bearer support
274 */
275
276void eth_media_stop(void)
277{
278 int i;
279
280 if (!eth_started)
281 return;
282
283 unregister_netdevice_notifier(&notifier);
284 for (i = 0; i < MAX_ETH_BEARERS ; i++) {
285 if (eth_bearers[i].bearer) {
286 eth_bearers[i].bearer->blocked = 1;
287 eth_bearers[i].bearer = 0;
288 }
289 if (eth_bearers[i].dev) {
290 dev_remove_pack(&eth_bearers[i].tipc_packet_type);
291 dev_put(eth_bearers[i].dev);
292 }
293 }
294 memset(&eth_bearers, 0, sizeof(eth_bearers));
295 eth_started = 0;
296}
diff --git a/net/tipc/handler.c b/net/tipc/handler.c
new file mode 100644
index 000000000000..c8fbb2071dfc
--- /dev/null
+++ b/net/tipc/handler.c
@@ -0,0 +1,129 @@
1/*
2 * net/tipc/handler.c: TIPC signal handling
3 *
4 * Copyright (c) 2003-2005, Ericsson Research Canada
5 * Copyright (c) 2005, Wind River Systems
6 * Copyright (c) 2005-2006, Ericsson AB
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions are met:
11 *
12 * Redistributions of source code must retain the above copyright notice, this
13 * list of conditions and the following disclaimer.
14 * Redistributions in binary form must reproduce the above copyright notice,
15 * this list of conditions and the following disclaimer in the documentation
16 * and/or other materials provided with the distribution.
17 * Neither the names of the copyright holders nor the names of its
18 * contributors may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 */
33
34#include "core.h"
35
36struct queue_item {
37 struct list_head next_signal;
38 void (*handler) (unsigned long);
39 unsigned long data;
40};
41
42static kmem_cache_t *tipc_queue_item_cache;
43static struct list_head signal_queue_head;
44static spinlock_t qitem_lock = SPIN_LOCK_UNLOCKED;
45static int handler_enabled = 0;
46
47static void process_signal_queue(unsigned long dummy);
48
49static DECLARE_TASKLET_DISABLED(tipc_tasklet, process_signal_queue, 0);
50
51
52unsigned int k_signal(Handler routine, unsigned long argument)
53{
54 struct queue_item *item;
55
56 if (!handler_enabled) {
57 err("Signal request ignored by handler\n");
58 return -ENOPROTOOPT;
59 }
60
61 spin_lock_bh(&qitem_lock);
62 item = kmem_cache_alloc(tipc_queue_item_cache, GFP_ATOMIC);
63 if (!item) {
64 err("Signal queue out of memory\n");
65 spin_unlock_bh(&qitem_lock);
66 return -ENOMEM;
67 }
68 item->handler = routine;
69 item->data = argument;
70 list_add_tail(&item->next_signal, &signal_queue_head);
71 spin_unlock_bh(&qitem_lock);
72 tasklet_schedule(&tipc_tasklet);
73 return 0;
74}
75
76static void process_signal_queue(unsigned long dummy)
77{
78 struct queue_item *__volatile__ item;
79 struct list_head *l, *n;
80
81 spin_lock_bh(&qitem_lock);
82 list_for_each_safe(l, n, &signal_queue_head) {
83 item = list_entry(l, struct queue_item, next_signal);
84 list_del(&item->next_signal);
85 spin_unlock_bh(&qitem_lock);
86 item->handler(item->data);
87 spin_lock_bh(&qitem_lock);
88 kmem_cache_free(tipc_queue_item_cache, item);
89 }
90 spin_unlock_bh(&qitem_lock);
91}
92
93int handler_start(void)
94{
95 tipc_queue_item_cache =
96 kmem_cache_create("tipc_queue_items", sizeof(struct queue_item),
97 0, SLAB_HWCACHE_ALIGN, NULL, NULL);
98 if (!tipc_queue_item_cache)
99 return -ENOMEM;
100
101 INIT_LIST_HEAD(&signal_queue_head);
102 tasklet_enable(&tipc_tasklet);
103 handler_enabled = 1;
104 return 0;
105}
106
107void handler_stop(void)
108{
109 struct list_head *l, *n;
110 struct queue_item *item;
111
112 if (!handler_enabled)
113 return;
114
115 handler_enabled = 0;
116 tasklet_disable(&tipc_tasklet);
117 tasklet_kill(&tipc_tasklet);
118
119 spin_lock_bh(&qitem_lock);
120 list_for_each_safe(l, n, &signal_queue_head) {
121 item = list_entry(l, struct queue_item, next_signal);
122 list_del(&item->next_signal);
123 kmem_cache_free(tipc_queue_item_cache, item);
124 }
125 spin_unlock_bh(&qitem_lock);
126
127 kmem_cache_destroy(tipc_queue_item_cache);
128}
129
diff --git a/net/tipc/link.c b/net/tipc/link.c
new file mode 100644
index 000000000000..92acb80bb24d
--- /dev/null
+++ b/net/tipc/link.c
@@ -0,0 +1,3164 @@
1/*
2 * net/tipc/link.c: TIPC link code
3 *
4 * Copyright (c) 2003-2005, Ericsson Research Canada
5 * Copyright (c) 2004-2005, Wind River Systems
6 * Copyright (c) 2005-2006, Ericsson AB
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions are met:
11 *
12 * Redistributions of source code must retain the above copyright notice, this
13 * list of conditions and the following disclaimer.
14 * Redistributions in binary form must reproduce the above copyright notice,
15 * this list of conditions and the following disclaimer in the documentation
16 * and/or other materials provided with the distribution.
17 * Neither the names of the copyright holders nor the names of its
18 * contributors may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 */
33
34#include "core.h"
35#include "dbg.h"
36#include "link.h"
37#include "net.h"
38#include "node.h"
39#include "port.h"
40#include "addr.h"
41#include "node_subscr.h"
42#include "name_distr.h"
43#include "bearer.h"
44#include "name_table.h"
45#include "discover.h"
46#include "config.h"
47#include "bcast.h"
48
49
50/*
51 * Limit for deferred reception queue:
52 */
53
54#define DEF_QUEUE_LIMIT 256u
55
56/*
57 * Link state events:
58 */
59
60#define STARTING_EVT 856384768 /* link processing trigger */
61#define TRAFFIC_MSG_EVT 560815u /* rx'd ??? */
62#define TIMEOUT_EVT 560817u /* link timer expired */
63
64/*
65 * The following two 'message types' is really just implementation
66 * data conveniently stored in the message header.
67 * They must not be considered part of the protocol
68 */
69#define OPEN_MSG 0
70#define CLOSED_MSG 1
71
72/*
73 * State value stored in 'exp_msg_count'
74 */
75
76#define START_CHANGEOVER 100000u
77
78/**
79 * struct link_name - deconstructed link name
80 * @addr_local: network address of node at this end
81 * @if_local: name of interface at this end
82 * @addr_peer: network address of node at far end
83 * @if_peer: name of interface at far end
84 */
85
86struct link_name {
87 u32 addr_local;
88 char if_local[TIPC_MAX_IF_NAME];
89 u32 addr_peer;
90 char if_peer[TIPC_MAX_IF_NAME];
91};
92
93#if 0
94
95/* LINK EVENT CODE IS NOT SUPPORTED AT PRESENT */
96
97/**
98 * struct link_event - link up/down event notification
99 */
100
101struct link_event {
102 u32 addr;
103 int up;
104 void (*fcn)(u32, char *, int);
105 char name[TIPC_MAX_LINK_NAME];
106};
107
108#endif
109
110static void link_handle_out_of_seq_msg(struct link *l_ptr,
111 struct sk_buff *buf);
112static void link_recv_proto_msg(struct link *l_ptr, struct sk_buff *buf);
113static int link_recv_changeover_msg(struct link **l_ptr, struct sk_buff **buf);
114static void link_set_supervision_props(struct link *l_ptr, u32 tolerance);
115static int link_send_sections_long(struct port *sender,
116 struct iovec const *msg_sect,
117 u32 num_sect, u32 destnode);
118static void link_check_defragm_bufs(struct link *l_ptr);
119static void link_state_event(struct link *l_ptr, u32 event);
120static void link_reset_statistics(struct link *l_ptr);
121static void link_print(struct link *l_ptr, struct print_buf *buf,
122 const char *str);
123
124/*
125 * Debugging code used by link routines only
126 *
127 * When debugging link problems on a system that has multiple links,
128 * the standard TIPC debugging routines may not be useful since they
129 * allow the output from multiple links to be intermixed. For this reason
130 * routines of the form "dbg_link_XXX()" have been created that will capture
131 * debug info into a link's personal print buffer, which can then be dumped
132 * into the TIPC system log (LOG) upon request.
133 *
134 * To enable per-link debugging, use LINK_LOG_BUF_SIZE to specify the size
135 * of the print buffer used by each link. If LINK_LOG_BUF_SIZE is set to 0,
136 * the dbg_link_XXX() routines simply send their output to the standard
137 * debug print buffer (DBG_OUTPUT), if it has been defined; this can be useful
138 * when there is only a single link in the system being debugged.
139 *
140 * Notes:
141 * - When enabled, LINK_LOG_BUF_SIZE should be set to at least 1000 (bytes)
142 * - "l_ptr" must be valid when using dbg_link_XXX() macros
143 */
144
145#define LINK_LOG_BUF_SIZE 0
146
147#define dbg_link(fmt, arg...) do {if (LINK_LOG_BUF_SIZE) tipc_printf(&l_ptr->print_buf, fmt, ## arg); } while(0)
148#define dbg_link_msg(msg, txt) do {if (LINK_LOG_BUF_SIZE) msg_print(&l_ptr->print_buf, msg, txt); } while(0)
149#define dbg_link_state(txt) do {if (LINK_LOG_BUF_SIZE) link_print(l_ptr, &l_ptr->print_buf, txt); } while(0)
150#define dbg_link_dump() do { \
151 if (LINK_LOG_BUF_SIZE) { \
152 tipc_printf(LOG, "\n\nDumping link <%s>:\n", l_ptr->name); \
153 printbuf_move(LOG, &l_ptr->print_buf); \
154 } \
155} while (0)
156
157static inline void dbg_print_link(struct link *l_ptr, const char *str)
158{
159 if (DBG_OUTPUT)
160 link_print(l_ptr, DBG_OUTPUT, str);
161}
162
163static inline void dbg_print_buf_chain(struct sk_buff *root_buf)
164{
165 if (DBG_OUTPUT) {
166 struct sk_buff *buf = root_buf;
167
168 while (buf) {
169 msg_dbg(buf_msg(buf), "In chain: ");
170 buf = buf->next;
171 }
172 }
173}
174
175/*
176 * Simple inlined link routines
177 */
178
179static inline unsigned int align(unsigned int i)
180{
181 return (i + 3) & ~3u;
182}
183
184static inline int link_working_working(struct link *l_ptr)
185{
186 return (l_ptr->state == WORKING_WORKING);
187}
188
189static inline int link_working_unknown(struct link *l_ptr)
190{
191 return (l_ptr->state == WORKING_UNKNOWN);
192}
193
194static inline int link_reset_unknown(struct link *l_ptr)
195{
196 return (l_ptr->state == RESET_UNKNOWN);
197}
198
199static inline int link_reset_reset(struct link *l_ptr)
200{
201 return (l_ptr->state == RESET_RESET);
202}
203
204static inline int link_blocked(struct link *l_ptr)
205{
206 return (l_ptr->exp_msg_count || l_ptr->blocked);
207}
208
209static inline int link_congested(struct link *l_ptr)
210{
211 return (l_ptr->out_queue_size >= l_ptr->queue_limit[0]);
212}
213
214static inline u32 link_max_pkt(struct link *l_ptr)
215{
216 return l_ptr->max_pkt;
217}
218
219static inline void link_init_max_pkt(struct link *l_ptr)
220{
221 u32 max_pkt;
222
223 max_pkt = (l_ptr->b_ptr->publ.mtu & ~3);
224 if (max_pkt > MAX_MSG_SIZE)
225 max_pkt = MAX_MSG_SIZE;
226
227 l_ptr->max_pkt_target = max_pkt;
228 if (l_ptr->max_pkt_target < MAX_PKT_DEFAULT)
229 l_ptr->max_pkt = l_ptr->max_pkt_target;
230 else
231 l_ptr->max_pkt = MAX_PKT_DEFAULT;
232
233 l_ptr->max_pkt_probes = 0;
234}
235
236static inline u32 link_next_sent(struct link *l_ptr)
237{
238 if (l_ptr->next_out)
239 return msg_seqno(buf_msg(l_ptr->next_out));
240 return mod(l_ptr->next_out_no);
241}
242
243static inline u32 link_last_sent(struct link *l_ptr)
244{
245 return mod(link_next_sent(l_ptr) - 1);
246}
247
248/*
249 * Simple non-inlined link routines (i.e. referenced outside this file)
250 */
251
252int link_is_up(struct link *l_ptr)
253{
254 if (!l_ptr)
255 return 0;
256 return (link_working_working(l_ptr) || link_working_unknown(l_ptr));
257}
258
259int link_is_active(struct link *l_ptr)
260{
261 return ((l_ptr->owner->active_links[0] == l_ptr) ||
262 (l_ptr->owner->active_links[1] == l_ptr));
263}
264
265/**
266 * link_name_validate - validate & (optionally) deconstruct link name
267 * @name - ptr to link name string
268 * @name_parts - ptr to area for link name components (or NULL if not needed)
269 *
270 * Returns 1 if link name is valid, otherwise 0.
271 */
272
273static int link_name_validate(const char *name, struct link_name *name_parts)
274{
275 char name_copy[TIPC_MAX_LINK_NAME];
276 char *addr_local;
277 char *if_local;
278 char *addr_peer;
279 char *if_peer;
280 char dummy;
281 u32 z_local, c_local, n_local;
282 u32 z_peer, c_peer, n_peer;
283 u32 if_local_len;
284 u32 if_peer_len;
285
286 /* copy link name & ensure length is OK */
287
288 name_copy[TIPC_MAX_LINK_NAME - 1] = 0;
289 /* need above in case non-Posix strncpy() doesn't pad with nulls */
290 strncpy(name_copy, name, TIPC_MAX_LINK_NAME);
291 if (name_copy[TIPC_MAX_LINK_NAME - 1] != 0)
292 return 0;
293
294 /* ensure all component parts of link name are present */
295
296 addr_local = name_copy;
297 if ((if_local = strchr(addr_local, ':')) == NULL)
298 return 0;
299 *(if_local++) = 0;
300 if ((addr_peer = strchr(if_local, '-')) == NULL)
301 return 0;
302 *(addr_peer++) = 0;
303 if_local_len = addr_peer - if_local;
304 if ((if_peer = strchr(addr_peer, ':')) == NULL)
305 return 0;
306 *(if_peer++) = 0;
307 if_peer_len = strlen(if_peer) + 1;
308
309 /* validate component parts of link name */
310
311 if ((sscanf(addr_local, "%u.%u.%u%c",
312 &z_local, &c_local, &n_local, &dummy) != 3) ||
313 (sscanf(addr_peer, "%u.%u.%u%c",
314 &z_peer, &c_peer, &n_peer, &dummy) != 3) ||
315 (z_local > 255) || (c_local > 4095) || (n_local > 4095) ||
316 (z_peer > 255) || (c_peer > 4095) || (n_peer > 4095) ||
317 (if_local_len <= 1) || (if_local_len > TIPC_MAX_IF_NAME) ||
318 (if_peer_len <= 1) || (if_peer_len > TIPC_MAX_IF_NAME) ||
319 (strspn(if_local, tipc_alphabet) != (if_local_len - 1)) ||
320 (strspn(if_peer, tipc_alphabet) != (if_peer_len - 1)))
321 return 0;
322
323 /* return link name components, if necessary */
324
325 if (name_parts) {
326 name_parts->addr_local = tipc_addr(z_local, c_local, n_local);
327 strcpy(name_parts->if_local, if_local);
328 name_parts->addr_peer = tipc_addr(z_peer, c_peer, n_peer);
329 strcpy(name_parts->if_peer, if_peer);
330 }
331 return 1;
332}
333
334/**
335 * link_timeout - handle expiration of link timer
336 * @l_ptr: pointer to link
337 *
338 * This routine must not grab "net_lock" to avoid a potential deadlock conflict
339 * with link_delete(). (There is no risk that the node will be deleted by
340 * another thread because link_delete() always cancels the link timer before
341 * node_delete() is called.)
342 */
343
344static void link_timeout(struct link *l_ptr)
345{
346 node_lock(l_ptr->owner);
347
348 /* update counters used in statistical profiling of send traffic */
349
350 l_ptr->stats.accu_queue_sz += l_ptr->out_queue_size;
351 l_ptr->stats.queue_sz_counts++;
352
353 if (l_ptr->out_queue_size > l_ptr->stats.max_queue_sz)
354 l_ptr->stats.max_queue_sz = l_ptr->out_queue_size;
355
356 if (l_ptr->first_out) {
357 struct tipc_msg *msg = buf_msg(l_ptr->first_out);
358 u32 length = msg_size(msg);
359
360 if ((msg_user(msg) == MSG_FRAGMENTER)
361 && (msg_type(msg) == FIRST_FRAGMENT)) {
362 length = msg_size(msg_get_wrapped(msg));
363 }
364 if (length) {
365 l_ptr->stats.msg_lengths_total += length;
366 l_ptr->stats.msg_length_counts++;
367 if (length <= 64)
368 l_ptr->stats.msg_length_profile[0]++;
369 else if (length <= 256)
370 l_ptr->stats.msg_length_profile[1]++;
371 else if (length <= 1024)
372 l_ptr->stats.msg_length_profile[2]++;
373 else if (length <= 4096)
374 l_ptr->stats.msg_length_profile[3]++;
375 else if (length <= 16384)
376 l_ptr->stats.msg_length_profile[4]++;
377 else if (length <= 32768)
378 l_ptr->stats.msg_length_profile[5]++;
379 else
380 l_ptr->stats.msg_length_profile[6]++;
381 }
382 }
383
384 /* do all other link processing performed on a periodic basis */
385
386 link_check_defragm_bufs(l_ptr);
387
388 link_state_event(l_ptr, TIMEOUT_EVT);
389
390 if (l_ptr->next_out)
391 link_push_queue(l_ptr);
392
393 node_unlock(l_ptr->owner);
394}
395
396static inline void link_set_timer(struct link *l_ptr, u32 time)
397{
398 k_start_timer(&l_ptr->timer, time);
399}
400
401/**
402 * link_create - create a new link
403 * @b_ptr: pointer to associated bearer
404 * @peer: network address of node at other end of link
405 * @media_addr: media address to use when sending messages over link
406 *
407 * Returns pointer to link.
408 */
409
410struct link *link_create(struct bearer *b_ptr, const u32 peer,
411 const struct tipc_media_addr *media_addr)
412{
413 struct link *l_ptr;
414 struct tipc_msg *msg;
415 char *if_name;
416
417 l_ptr = (struct link *)kmalloc(sizeof(*l_ptr), GFP_ATOMIC);
418 if (!l_ptr) {
419 warn("Memory squeeze; Failed to create link\n");
420 return NULL;
421 }
422 memset(l_ptr, 0, sizeof(*l_ptr));
423
424 l_ptr->addr = peer;
425 if_name = strchr(b_ptr->publ.name, ':') + 1;
426 sprintf(l_ptr->name, "%u.%u.%u:%s-%u.%u.%u:",
427 tipc_zone(tipc_own_addr), tipc_cluster(tipc_own_addr),
428 tipc_node(tipc_own_addr),
429 if_name,
430 tipc_zone(peer), tipc_cluster(peer), tipc_node(peer));
431 /* note: peer i/f is appended to link name by reset/activate */
432 memcpy(&l_ptr->media_addr, media_addr, sizeof(*media_addr));
433 k_init_timer(&l_ptr->timer, (Handler)link_timeout, (unsigned long)l_ptr);
434 list_add_tail(&l_ptr->link_list, &b_ptr->links);
435 l_ptr->checkpoint = 1;
436 l_ptr->b_ptr = b_ptr;
437 link_set_supervision_props(l_ptr, b_ptr->media->tolerance);
438 l_ptr->state = RESET_UNKNOWN;
439
440 l_ptr->pmsg = (struct tipc_msg *)&l_ptr->proto_msg;
441 msg = l_ptr->pmsg;
442 msg_init(msg, LINK_PROTOCOL, RESET_MSG, TIPC_OK, INT_H_SIZE, l_ptr->addr);
443 msg_set_size(msg, sizeof(l_ptr->proto_msg));
444 msg_set_session(msg, tipc_random);
445 msg_set_bearer_id(msg, b_ptr->identity);
446 strcpy((char *)msg_data(msg), if_name);
447
448 l_ptr->priority = b_ptr->priority;
449 link_set_queue_limits(l_ptr, b_ptr->media->window);
450
451 link_init_max_pkt(l_ptr);
452
453 l_ptr->next_out_no = 1;
454 INIT_LIST_HEAD(&l_ptr->waiting_ports);
455
456 link_reset_statistics(l_ptr);
457
458 l_ptr->owner = node_attach_link(l_ptr);
459 if (!l_ptr->owner) {
460 kfree(l_ptr);
461 return NULL;
462 }
463
464 if (LINK_LOG_BUF_SIZE) {
465 char *pb = kmalloc(LINK_LOG_BUF_SIZE, GFP_ATOMIC);
466
467 if (!pb) {
468 kfree(l_ptr);
469 warn("Memory squeeze; Failed to create link\n");
470 return NULL;
471 }
472 printbuf_init(&l_ptr->print_buf, pb, LINK_LOG_BUF_SIZE);
473 }
474
475 k_signal((Handler)link_start, (unsigned long)l_ptr);
476
477 dbg("link_create(): tolerance = %u,cont intv = %u, abort_limit = %u\n",
478 l_ptr->tolerance, l_ptr->continuity_interval, l_ptr->abort_limit);
479
480 return l_ptr;
481}
482
483/**
484 * link_delete - delete a link
485 * @l_ptr: pointer to link
486 *
487 * Note: 'net_lock' is write_locked, bearer is locked.
488 * This routine must not grab the node lock until after link timer cancellation
489 * to avoid a potential deadlock situation.
490 */
491
492void link_delete(struct link *l_ptr)
493{
494 if (!l_ptr) {
495 err("Attempt to delete non-existent link\n");
496 return;
497 }
498
499 dbg("link_delete()\n");
500
501 k_cancel_timer(&l_ptr->timer);
502
503 node_lock(l_ptr->owner);
504 link_reset(l_ptr);
505 node_detach_link(l_ptr->owner, l_ptr);
506 link_stop(l_ptr);
507 list_del_init(&l_ptr->link_list);
508 if (LINK_LOG_BUF_SIZE)
509 kfree(l_ptr->print_buf.buf);
510 node_unlock(l_ptr->owner);
511 k_term_timer(&l_ptr->timer);
512 kfree(l_ptr);
513}
514
515void link_start(struct link *l_ptr)
516{
517 dbg("link_start %x\n", l_ptr);
518 link_state_event(l_ptr, STARTING_EVT);
519}
520
521/**
522 * link_schedule_port - schedule port for deferred sending
523 * @l_ptr: pointer to link
524 * @origport: reference to sending port
525 * @sz: amount of data to be sent
526 *
527 * Schedules port for renewed sending of messages after link congestion
528 * has abated.
529 */
530
531static int link_schedule_port(struct link *l_ptr, u32 origport, u32 sz)
532{
533 struct port *p_ptr;
534
535 spin_lock_bh(&port_list_lock);
536 p_ptr = port_lock(origport);
537 if (p_ptr) {
538 if (!p_ptr->wakeup)
539 goto exit;
540 if (!list_empty(&p_ptr->wait_list))
541 goto exit;
542 p_ptr->congested_link = l_ptr;
543 p_ptr->publ.congested = 1;
544 p_ptr->waiting_pkts = 1 + ((sz - 1) / link_max_pkt(l_ptr));
545 list_add_tail(&p_ptr->wait_list, &l_ptr->waiting_ports);
546 l_ptr->stats.link_congs++;
547exit:
548 port_unlock(p_ptr);
549 }
550 spin_unlock_bh(&port_list_lock);
551 return -ELINKCONG;
552}
553
554void link_wakeup_ports(struct link *l_ptr, int all)
555{
556 struct port *p_ptr;
557 struct port *temp_p_ptr;
558 int win = l_ptr->queue_limit[0] - l_ptr->out_queue_size;
559
560 if (all)
561 win = 100000;
562 if (win <= 0)
563 return;
564 if (!spin_trylock_bh(&port_list_lock))
565 return;
566 if (link_congested(l_ptr))
567 goto exit;
568 list_for_each_entry_safe(p_ptr, temp_p_ptr, &l_ptr->waiting_ports,
569 wait_list) {
570 if (win <= 0)
571 break;
572 list_del_init(&p_ptr->wait_list);
573 p_ptr->congested_link = 0;
574 assert(p_ptr->wakeup);
575 spin_lock_bh(p_ptr->publ.lock);
576 p_ptr->publ.congested = 0;
577 p_ptr->wakeup(&p_ptr->publ);
578 win -= p_ptr->waiting_pkts;
579 spin_unlock_bh(p_ptr->publ.lock);
580 }
581
582exit:
583 spin_unlock_bh(&port_list_lock);
584}
585
586/**
587 * link_release_outqueue - purge link's outbound message queue
588 * @l_ptr: pointer to link
589 */
590
591static void link_release_outqueue(struct link *l_ptr)
592{
593 struct sk_buff *buf = l_ptr->first_out;
594 struct sk_buff *next;
595
596 while (buf) {
597 next = buf->next;
598 buf_discard(buf);
599 buf = next;
600 }
601 l_ptr->first_out = NULL;
602 l_ptr->out_queue_size = 0;
603}
604
605/**
606 * link_reset_fragments - purge link's inbound message fragments queue
607 * @l_ptr: pointer to link
608 */
609
610void link_reset_fragments(struct link *l_ptr)
611{
612 struct sk_buff *buf = l_ptr->defragm_buf;
613 struct sk_buff *next;
614
615 while (buf) {
616 next = buf->next;
617 buf_discard(buf);
618 buf = next;
619 }
620 l_ptr->defragm_buf = NULL;
621}
622
623/**
624 * link_stop - purge all inbound and outbound messages associated with link
625 * @l_ptr: pointer to link
626 */
627
628void link_stop(struct link *l_ptr)
629{
630 struct sk_buff *buf;
631 struct sk_buff *next;
632
633 buf = l_ptr->oldest_deferred_in;
634 while (buf) {
635 next = buf->next;
636 buf_discard(buf);
637 buf = next;
638 }
639
640 buf = l_ptr->first_out;
641 while (buf) {
642 next = buf->next;
643 buf_discard(buf);
644 buf = next;
645 }
646
647 link_reset_fragments(l_ptr);
648
649 buf_discard(l_ptr->proto_msg_queue);
650 l_ptr->proto_msg_queue = NULL;
651}
652
653#if 0
654
655/* LINK EVENT CODE IS NOT SUPPORTED AT PRESENT */
656
657static void link_recv_event(struct link_event *ev)
658{
659 ev->fcn(ev->addr, ev->name, ev->up);
660 kfree(ev);
661}
662
663static void link_send_event(void (*fcn)(u32 a, char *n, int up),
664 struct link *l_ptr, int up)
665{
666 struct link_event *ev;
667
668 ev = kmalloc(sizeof(*ev), GFP_ATOMIC);
669 if (!ev) {
670 warn("Link event allocation failure\n");
671 return;
672 }
673 ev->addr = l_ptr->addr;
674 ev->up = up;
675 ev->fcn = fcn;
676 memcpy(ev->name, l_ptr->name, TIPC_MAX_LINK_NAME);
677 k_signal((Handler)link_recv_event, (unsigned long)ev);
678}
679
680#else
681
682#define link_send_event(fcn, l_ptr, up) do { } while (0)
683
684#endif
685
686void link_reset(struct link *l_ptr)
687{
688 struct sk_buff *buf;
689 u32 prev_state = l_ptr->state;
690 u32 checkpoint = l_ptr->next_in_no;
691
692 msg_set_session(l_ptr->pmsg, msg_session(l_ptr->pmsg) + 1);
693
694 /* Link is down, accept any session: */
695 l_ptr->peer_session = 0;
696
697 /* Prepare for max packet size negotiation */
698 link_init_max_pkt(l_ptr);
699
700 l_ptr->state = RESET_UNKNOWN;
701 dbg_link_state("Resetting Link\n");
702
703 if ((prev_state == RESET_UNKNOWN) || (prev_state == RESET_RESET))
704 return;
705
706 node_link_down(l_ptr->owner, l_ptr);
707 bearer_remove_dest(l_ptr->b_ptr, l_ptr->addr);
708#if 0
709 tipc_printf(CONS, "\nReset link <%s>\n", l_ptr->name);
710 dbg_link_dump();
711#endif
712 if (node_has_active_links(l_ptr->owner) &&
713 l_ptr->owner->permit_changeover) {
714 l_ptr->reset_checkpoint = checkpoint;
715 l_ptr->exp_msg_count = START_CHANGEOVER;
716 }
717
718 /* Clean up all queues: */
719
720 link_release_outqueue(l_ptr);
721 buf_discard(l_ptr->proto_msg_queue);
722 l_ptr->proto_msg_queue = NULL;
723 buf = l_ptr->oldest_deferred_in;
724 while (buf) {
725 struct sk_buff *next = buf->next;
726 buf_discard(buf);
727 buf = next;
728 }
729 if (!list_empty(&l_ptr->waiting_ports))
730 link_wakeup_ports(l_ptr, 1);
731
732 l_ptr->retransm_queue_head = 0;
733 l_ptr->retransm_queue_size = 0;
734 l_ptr->last_out = NULL;
735 l_ptr->first_out = NULL;
736 l_ptr->next_out = NULL;
737 l_ptr->unacked_window = 0;
738 l_ptr->checkpoint = 1;
739 l_ptr->next_out_no = 1;
740 l_ptr->deferred_inqueue_sz = 0;
741 l_ptr->oldest_deferred_in = NULL;
742 l_ptr->newest_deferred_in = NULL;
743 l_ptr->fsm_msg_cnt = 0;
744 l_ptr->stale_count = 0;
745 link_reset_statistics(l_ptr);
746
747 link_send_event(cfg_link_event, l_ptr, 0);
748 if (!in_own_cluster(l_ptr->addr))
749 link_send_event(disc_link_event, l_ptr, 0);
750}
751
752
753static void link_activate(struct link *l_ptr)
754{
755 l_ptr->next_in_no = 1;
756 node_link_up(l_ptr->owner, l_ptr);
757 bearer_add_dest(l_ptr->b_ptr, l_ptr->addr);
758 link_send_event(cfg_link_event, l_ptr, 1);
759 if (!in_own_cluster(l_ptr->addr))
760 link_send_event(disc_link_event, l_ptr, 1);
761}
762
763/**
764 * link_state_event - link finite state machine
765 * @l_ptr: pointer to link
766 * @event: state machine event to process
767 */
768
769static void link_state_event(struct link *l_ptr, unsigned event)
770{
771 struct link *other;
772 u32 cont_intv = l_ptr->continuity_interval;
773
774 if (!l_ptr->started && (event != STARTING_EVT))
775 return; /* Not yet. */
776
777 if (link_blocked(l_ptr)) {
778 if (event == TIMEOUT_EVT) {
779 link_set_timer(l_ptr, cont_intv);
780 }
781 return; /* Changeover going on */
782 }
783 dbg_link("STATE_EV: <%s> ", l_ptr->name);
784
785 switch (l_ptr->state) {
786 case WORKING_WORKING:
787 dbg_link("WW/");
788 switch (event) {
789 case TRAFFIC_MSG_EVT:
790 dbg_link("TRF-");
791 /* fall through */
792 case ACTIVATE_MSG:
793 dbg_link("ACT\n");
794 break;
795 case TIMEOUT_EVT:
796 dbg_link("TIM ");
797 if (l_ptr->next_in_no != l_ptr->checkpoint) {
798 l_ptr->checkpoint = l_ptr->next_in_no;
799 if (bclink_acks_missing(l_ptr->owner)) {
800 link_send_proto_msg(l_ptr, STATE_MSG,
801 0, 0, 0, 0, 0);
802 l_ptr->fsm_msg_cnt++;
803 } else if (l_ptr->max_pkt < l_ptr->max_pkt_target) {
804 link_send_proto_msg(l_ptr, STATE_MSG,
805 1, 0, 0, 0, 0);
806 l_ptr->fsm_msg_cnt++;
807 }
808 link_set_timer(l_ptr, cont_intv);
809 break;
810 }
811 dbg_link(" -> WU\n");
812 l_ptr->state = WORKING_UNKNOWN;
813 l_ptr->fsm_msg_cnt = 0;
814 link_send_proto_msg(l_ptr, STATE_MSG, 1, 0, 0, 0, 0);
815 l_ptr->fsm_msg_cnt++;
816 link_set_timer(l_ptr, cont_intv / 4);
817 break;
818 case RESET_MSG:
819 dbg_link("RES -> RR\n");
820 link_reset(l_ptr);
821 l_ptr->state = RESET_RESET;
822 l_ptr->fsm_msg_cnt = 0;
823 link_send_proto_msg(l_ptr, ACTIVATE_MSG, 0, 0, 0, 0, 0);
824 l_ptr->fsm_msg_cnt++;
825 link_set_timer(l_ptr, cont_intv);
826 break;
827 default:
828 err("Unknown link event %u in WW state\n", event);
829 }
830 break;
831 case WORKING_UNKNOWN:
832 dbg_link("WU/");
833 switch (event) {
834 case TRAFFIC_MSG_EVT:
835 dbg_link("TRF-");
836 case ACTIVATE_MSG:
837 dbg_link("ACT -> WW\n");
838 l_ptr->state = WORKING_WORKING;
839 l_ptr->fsm_msg_cnt = 0;
840 link_set_timer(l_ptr, cont_intv);
841 break;
842 case RESET_MSG:
843 dbg_link("RES -> RR\n");
844 link_reset(l_ptr);
845 l_ptr->state = RESET_RESET;
846 l_ptr->fsm_msg_cnt = 0;
847 link_send_proto_msg(l_ptr, ACTIVATE_MSG, 0, 0, 0, 0, 0);
848 l_ptr->fsm_msg_cnt++;
849 link_set_timer(l_ptr, cont_intv);
850 break;
851 case TIMEOUT_EVT:
852 dbg_link("TIM ");
853 if (l_ptr->next_in_no != l_ptr->checkpoint) {
854 dbg_link("-> WW \n");
855 l_ptr->state = WORKING_WORKING;
856 l_ptr->fsm_msg_cnt = 0;
857 l_ptr->checkpoint = l_ptr->next_in_no;
858 if (bclink_acks_missing(l_ptr->owner)) {
859 link_send_proto_msg(l_ptr, STATE_MSG,
860 0, 0, 0, 0, 0);
861 l_ptr->fsm_msg_cnt++;
862 }
863 link_set_timer(l_ptr, cont_intv);
864 } else if (l_ptr->fsm_msg_cnt < l_ptr->abort_limit) {
865 dbg_link("Probing %u/%u,timer = %u ms)\n",
866 l_ptr->fsm_msg_cnt, l_ptr->abort_limit,
867 cont_intv / 4);
868 link_send_proto_msg(l_ptr, STATE_MSG,
869 1, 0, 0, 0, 0);
870 l_ptr->fsm_msg_cnt++;
871 link_set_timer(l_ptr, cont_intv / 4);
872 } else { /* Link has failed */
873 dbg_link("-> RU (%u probes unanswered)\n",
874 l_ptr->fsm_msg_cnt);
875 link_reset(l_ptr);
876 l_ptr->state = RESET_UNKNOWN;
877 l_ptr->fsm_msg_cnt = 0;
878 link_send_proto_msg(l_ptr, RESET_MSG,
879 0, 0, 0, 0, 0);
880 l_ptr->fsm_msg_cnt++;
881 link_set_timer(l_ptr, cont_intv);
882 }
883 break;
884 default:
885 err("Unknown link event %u in WU state\n", event);
886 }
887 break;
888 case RESET_UNKNOWN:
889 dbg_link("RU/");
890 switch (event) {
891 case TRAFFIC_MSG_EVT:
892 dbg_link("TRF-\n");
893 break;
894 case ACTIVATE_MSG:
895 other = l_ptr->owner->active_links[0];
896 if (other && link_working_unknown(other)) {
897 dbg_link("ACT\n");
898 break;
899 }
900 dbg_link("ACT -> WW\n");
901 l_ptr->state = WORKING_WORKING;
902 l_ptr->fsm_msg_cnt = 0;
903 link_activate(l_ptr);
904 link_send_proto_msg(l_ptr, STATE_MSG, 1, 0, 0, 0, 0);
905 l_ptr->fsm_msg_cnt++;
906 link_set_timer(l_ptr, cont_intv);
907 break;
908 case RESET_MSG:
909 dbg_link("RES \n");
910 dbg_link(" -> RR\n");
911 l_ptr->state = RESET_RESET;
912 l_ptr->fsm_msg_cnt = 0;
913 link_send_proto_msg(l_ptr, ACTIVATE_MSG, 1, 0, 0, 0, 0);
914 l_ptr->fsm_msg_cnt++;
915 link_set_timer(l_ptr, cont_intv);
916 break;
917 case STARTING_EVT:
918 dbg_link("START-");
919 l_ptr->started = 1;
920 /* fall through */
921 case TIMEOUT_EVT:
922 dbg_link("TIM \n");
923 link_send_proto_msg(l_ptr, RESET_MSG, 0, 0, 0, 0, 0);
924 l_ptr->fsm_msg_cnt++;
925 link_set_timer(l_ptr, cont_intv);
926 break;
927 default:
928 err("Unknown link event %u in RU state\n", event);
929 }
930 break;
931 case RESET_RESET:
932 dbg_link("RR/ ");
933 switch (event) {
934 case TRAFFIC_MSG_EVT:
935 dbg_link("TRF-");
936 /* fall through */
937 case ACTIVATE_MSG:
938 other = l_ptr->owner->active_links[0];
939 if (other && link_working_unknown(other)) {
940 dbg_link("ACT\n");
941 break;
942 }
943 dbg_link("ACT -> WW\n");
944 l_ptr->state = WORKING_WORKING;
945 l_ptr->fsm_msg_cnt = 0;
946 link_activate(l_ptr);
947 link_send_proto_msg(l_ptr, STATE_MSG, 1, 0, 0, 0, 0);
948 l_ptr->fsm_msg_cnt++;
949 link_set_timer(l_ptr, cont_intv);
950 break;
951 case RESET_MSG:
952 dbg_link("RES\n");
953 break;
954 case TIMEOUT_EVT:
955 dbg_link("TIM\n");
956 link_send_proto_msg(l_ptr, ACTIVATE_MSG, 0, 0, 0, 0, 0);
957 l_ptr->fsm_msg_cnt++;
958 link_set_timer(l_ptr, cont_intv);
959 dbg_link("fsm_msg_cnt %u\n", l_ptr->fsm_msg_cnt);
960 break;
961 default:
962 err("Unknown link event %u in RR state\n", event);
963 }
964 break;
965 default:
966 err("Unknown link state %u/%u\n", l_ptr->state, event);
967 }
968}
969
970/*
971 * link_bundle_buf(): Append contents of a buffer to
972 * the tail of an existing one.
973 */
974
975static int link_bundle_buf(struct link *l_ptr,
976 struct sk_buff *bundler,
977 struct sk_buff *buf)
978{
979 struct tipc_msg *bundler_msg = buf_msg(bundler);
980 struct tipc_msg *msg = buf_msg(buf);
981 u32 size = msg_size(msg);
982 u32 to_pos = align(msg_size(bundler_msg));
983 u32 rest = link_max_pkt(l_ptr) - to_pos;
984
985 if (msg_user(bundler_msg) != MSG_BUNDLER)
986 return 0;
987 if (msg_type(bundler_msg) != OPEN_MSG)
988 return 0;
989 if (rest < align(size))
990 return 0;
991
992 skb_put(bundler, (to_pos - msg_size(bundler_msg)) + size);
993 memcpy(bundler->data + to_pos, buf->data, size);
994 msg_set_size(bundler_msg, to_pos + size);
995 msg_set_msgcnt(bundler_msg, msg_msgcnt(bundler_msg) + 1);
996 dbg("Packed msg # %u(%u octets) into pos %u in buf(#%u)\n",
997 msg_msgcnt(bundler_msg), size, to_pos, msg_seqno(bundler_msg));
998 msg_dbg(msg, "PACKD:");
999 buf_discard(buf);
1000 l_ptr->stats.sent_bundled++;
1001 return 1;
1002}
1003
1004static inline void link_add_to_outqueue(struct link *l_ptr,
1005 struct sk_buff *buf,
1006 struct tipc_msg *msg)
1007{
1008 u32 ack = mod(l_ptr->next_in_no - 1);
1009 u32 seqno = mod(l_ptr->next_out_no++);
1010
1011 msg_set_word(msg, 2, ((ack << 16) | seqno));
1012 msg_set_bcast_ack(msg, l_ptr->owner->bclink.last_in);
1013 buf->next = NULL;
1014 if (l_ptr->first_out) {
1015 l_ptr->last_out->next = buf;
1016 l_ptr->last_out = buf;
1017 } else
1018 l_ptr->first_out = l_ptr->last_out = buf;
1019 l_ptr->out_queue_size++;
1020}
1021
1022/*
1023 * link_send_buf() is the 'full path' for messages, called from
1024 * inside TIPC when the 'fast path' in tipc_send_buf
1025 * has failed, and from link_send()
1026 */
1027
1028int link_send_buf(struct link *l_ptr, struct sk_buff *buf)
1029{
1030 struct tipc_msg *msg = buf_msg(buf);
1031 u32 size = msg_size(msg);
1032 u32 dsz = msg_data_sz(msg);
1033 u32 queue_size = l_ptr->out_queue_size;
1034 u32 imp = msg_tot_importance(msg);
1035 u32 queue_limit = l_ptr->queue_limit[imp];
1036 u32 max_packet = link_max_pkt(l_ptr);
1037
1038 msg_set_prevnode(msg, tipc_own_addr); /* If routed message */
1039
1040 /* Match msg importance against queue limits: */
1041
1042 if (unlikely(queue_size >= queue_limit)) {
1043 if (imp <= TIPC_CRITICAL_IMPORTANCE) {
1044 return link_schedule_port(l_ptr, msg_origport(msg),
1045 size);
1046 }
1047 msg_dbg(msg, "TIPC: Congestion, throwing away\n");
1048 buf_discard(buf);
1049 if (imp > CONN_MANAGER) {
1050 warn("Resetting <%s>, send queue full", l_ptr->name);
1051 link_reset(l_ptr);
1052 }
1053 return dsz;
1054 }
1055
1056 /* Fragmentation needed ? */
1057
1058 if (size > max_packet)
1059 return link_send_long_buf(l_ptr, buf);
1060
1061 /* Packet can be queued or sent: */
1062
1063 if (queue_size > l_ptr->stats.max_queue_sz)
1064 l_ptr->stats.max_queue_sz = queue_size;
1065
1066 if (likely(!bearer_congested(l_ptr->b_ptr, l_ptr) &&
1067 !link_congested(l_ptr))) {
1068 link_add_to_outqueue(l_ptr, buf, msg);
1069
1070 if (likely(bearer_send(l_ptr->b_ptr, buf, &l_ptr->media_addr))) {
1071 l_ptr->unacked_window = 0;
1072 } else {
1073 bearer_schedule(l_ptr->b_ptr, l_ptr);
1074 l_ptr->stats.bearer_congs++;
1075 l_ptr->next_out = buf;
1076 }
1077 return dsz;
1078 }
1079 /* Congestion: can message be bundled ?: */
1080
1081 if ((msg_user(msg) != CHANGEOVER_PROTOCOL) &&
1082 (msg_user(msg) != MSG_FRAGMENTER)) {
1083
1084 /* Try adding message to an existing bundle */
1085
1086 if (l_ptr->next_out &&
1087 link_bundle_buf(l_ptr, l_ptr->last_out, buf)) {
1088 bearer_resolve_congestion(l_ptr->b_ptr, l_ptr);
1089 return dsz;
1090 }
1091
1092 /* Try creating a new bundle */
1093
1094 if (size <= max_packet * 2 / 3) {
1095 struct sk_buff *bundler = buf_acquire(max_packet);
1096 struct tipc_msg bundler_hdr;
1097
1098 if (bundler) {
1099 msg_init(&bundler_hdr, MSG_BUNDLER, OPEN_MSG,
1100 TIPC_OK, INT_H_SIZE, l_ptr->addr);
1101 memcpy(bundler->data, (unchar *)&bundler_hdr,
1102 INT_H_SIZE);
1103 skb_trim(bundler, INT_H_SIZE);
1104 link_bundle_buf(l_ptr, bundler, buf);
1105 buf = bundler;
1106 msg = buf_msg(buf);
1107 l_ptr->stats.sent_bundles++;
1108 }
1109 }
1110 }
1111 if (!l_ptr->next_out)
1112 l_ptr->next_out = buf;
1113 link_add_to_outqueue(l_ptr, buf, msg);
1114 bearer_resolve_congestion(l_ptr->b_ptr, l_ptr);
1115 return dsz;
1116}
1117
1118/*
1119 * link_send(): same as link_send_buf(), but the link to use has
1120 * not been selected yet, and the the owner node is not locked
1121 * Called by TIPC internal users, e.g. the name distributor
1122 */
1123
1124int link_send(struct sk_buff *buf, u32 dest, u32 selector)
1125{
1126 struct link *l_ptr;
1127 struct node *n_ptr;
1128 int res = -ELINKCONG;
1129
1130 read_lock_bh(&net_lock);
1131 n_ptr = node_select(dest, selector);
1132 if (n_ptr) {
1133 node_lock(n_ptr);
1134 l_ptr = n_ptr->active_links[selector & 1];
1135 dbg("link_send: found link %x for dest %x\n", l_ptr, dest);
1136 if (l_ptr) {
1137 res = link_send_buf(l_ptr, buf);
1138 }
1139 node_unlock(n_ptr);
1140 } else {
1141 dbg("Attempt to send msg to unknown node:\n");
1142 msg_dbg(buf_msg(buf),">>>");
1143 buf_discard(buf);
1144 }
1145 read_unlock_bh(&net_lock);
1146 return res;
1147}
1148
1149/*
1150 * link_send_buf_fast: Entry for data messages where the
1151 * destination link is known and the header is complete,
1152 * inclusive total message length. Very time critical.
1153 * Link is locked. Returns user data length.
1154 */
1155
1156static inline int link_send_buf_fast(struct link *l_ptr, struct sk_buff *buf,
1157 u32 *used_max_pkt)
1158{
1159 struct tipc_msg *msg = buf_msg(buf);
1160 int res = msg_data_sz(msg);
1161
1162 if (likely(!link_congested(l_ptr))) {
1163 if (likely(msg_size(msg) <= link_max_pkt(l_ptr))) {
1164 if (likely(list_empty(&l_ptr->b_ptr->cong_links))) {
1165 link_add_to_outqueue(l_ptr, buf, msg);
1166 if (likely(bearer_send(l_ptr->b_ptr, buf,
1167 &l_ptr->media_addr))) {
1168 l_ptr->unacked_window = 0;
1169 msg_dbg(msg,"SENT_FAST:");
1170 return res;
1171 }
1172 dbg("failed sent fast...\n");
1173 bearer_schedule(l_ptr->b_ptr, l_ptr);
1174 l_ptr->stats.bearer_congs++;
1175 l_ptr->next_out = buf;
1176 return res;
1177 }
1178 }
1179 else
1180 *used_max_pkt = link_max_pkt(l_ptr);
1181 }
1182 return link_send_buf(l_ptr, buf); /* All other cases */
1183}
1184
1185/*
1186 * tipc_send_buf_fast: Entry for data messages where the
1187 * destination node is known and the header is complete,
1188 * inclusive total message length.
1189 * Returns user data length.
1190 */
1191int tipc_send_buf_fast(struct sk_buff *buf, u32 destnode)
1192{
1193 struct link *l_ptr;
1194 struct node *n_ptr;
1195 int res;
1196 u32 selector = msg_origport(buf_msg(buf)) & 1;
1197 u32 dummy;
1198
1199 if (destnode == tipc_own_addr)
1200 return port_recv_msg(buf);
1201
1202 read_lock_bh(&net_lock);
1203 n_ptr = node_select(destnode, selector);
1204 if (likely(n_ptr)) {
1205 node_lock(n_ptr);
1206 l_ptr = n_ptr->active_links[selector];
1207 dbg("send_fast: buf %x selected %x, destnode = %x\n",
1208 buf, l_ptr, destnode);
1209 if (likely(l_ptr)) {
1210 res = link_send_buf_fast(l_ptr, buf, &dummy);
1211 node_unlock(n_ptr);
1212 read_unlock_bh(&net_lock);
1213 return res;
1214 }
1215 node_unlock(n_ptr);
1216 }
1217 read_unlock_bh(&net_lock);
1218 res = msg_data_sz(buf_msg(buf));
1219 tipc_reject_msg(buf, TIPC_ERR_NO_NODE);
1220 return res;
1221}
1222
1223
1224/*
1225 * link_send_sections_fast: Entry for messages where the
1226 * destination processor is known and the header is complete,
1227 * except for total message length.
1228 * Returns user data length or errno.
1229 */
1230int link_send_sections_fast(struct port *sender,
1231 struct iovec const *msg_sect,
1232 const u32 num_sect,
1233 u32 destaddr)
1234{
1235 struct tipc_msg *hdr = &sender->publ.phdr;
1236 struct link *l_ptr;
1237 struct sk_buff *buf;
1238 struct node *node;
1239 int res;
1240 u32 selector = msg_origport(hdr) & 1;
1241
1242 assert(destaddr != tipc_own_addr);
1243
1244again:
1245 /*
1246 * Try building message using port's max_pkt hint.
1247 * (Must not hold any locks while building message.)
1248 */
1249
1250 res = msg_build(hdr, msg_sect, num_sect, sender->max_pkt,
1251 !sender->user_port, &buf);
1252
1253 read_lock_bh(&net_lock);
1254 node = node_select(destaddr, selector);
1255 if (likely(node)) {
1256 node_lock(node);
1257 l_ptr = node->active_links[selector];
1258 if (likely(l_ptr)) {
1259 if (likely(buf)) {
1260 res = link_send_buf_fast(l_ptr, buf,
1261 &sender->max_pkt);
1262 if (unlikely(res < 0))
1263 buf_discard(buf);
1264exit:
1265 node_unlock(node);
1266 read_unlock_bh(&net_lock);
1267 return res;
1268 }
1269
1270 /* Exit if build request was invalid */
1271
1272 if (unlikely(res < 0))
1273 goto exit;
1274
1275 /* Exit if link (or bearer) is congested */
1276
1277 if (link_congested(l_ptr) ||
1278 !list_empty(&l_ptr->b_ptr->cong_links)) {
1279 res = link_schedule_port(l_ptr,
1280 sender->publ.ref, res);
1281 goto exit;
1282 }
1283
1284 /*
1285 * Message size exceeds max_pkt hint; update hint,
1286 * then re-try fast path or fragment the message
1287 */
1288
1289 sender->max_pkt = link_max_pkt(l_ptr);
1290 node_unlock(node);
1291 read_unlock_bh(&net_lock);
1292
1293
1294 if ((msg_hdr_sz(hdr) + res) <= sender->max_pkt)
1295 goto again;
1296
1297 return link_send_sections_long(sender, msg_sect,
1298 num_sect, destaddr);
1299 }
1300 node_unlock(node);
1301 }
1302 read_unlock_bh(&net_lock);
1303
1304 /* Couldn't find a link to the destination node */
1305
1306 if (buf)
1307 return tipc_reject_msg(buf, TIPC_ERR_NO_NODE);
1308 if (res >= 0)
1309 return port_reject_sections(sender, hdr, msg_sect, num_sect,
1310 TIPC_ERR_NO_NODE);
1311 return res;
1312}
1313
1314/*
1315 * link_send_sections_long(): Entry for long messages where the
1316 * destination node is known and the header is complete,
1317 * inclusive total message length.
1318 * Link and bearer congestion status have been checked to be ok,
1319 * and are ignored if they change.
1320 *
1321 * Note that fragments do not use the full link MTU so that they won't have
1322 * to undergo refragmentation if link changeover causes them to be sent
1323 * over another link with an additional tunnel header added as prefix.
1324 * (Refragmentation will still occur if the other link has a smaller MTU.)
1325 *
1326 * Returns user data length or errno.
1327 */
1328static int link_send_sections_long(struct port *sender,
1329 struct iovec const *msg_sect,
1330 u32 num_sect,
1331 u32 destaddr)
1332{
1333 struct link *l_ptr;
1334 struct node *node;
1335 struct tipc_msg *hdr = &sender->publ.phdr;
1336 u32 dsz = msg_data_sz(hdr);
1337 u32 max_pkt,fragm_sz,rest;
1338 struct tipc_msg fragm_hdr;
1339 struct sk_buff *buf,*buf_chain,*prev;
1340 u32 fragm_crs,fragm_rest,hsz,sect_rest;
1341 const unchar *sect_crs;
1342 int curr_sect;
1343 u32 fragm_no;
1344
1345again:
1346 fragm_no = 1;
1347 max_pkt = sender->max_pkt - INT_H_SIZE;
1348 /* leave room for tunnel header in case of link changeover */
1349 fragm_sz = max_pkt - INT_H_SIZE;
1350 /* leave room for fragmentation header in each fragment */
1351 rest = dsz;
1352 fragm_crs = 0;
1353 fragm_rest = 0;
1354 sect_rest = 0;
1355 sect_crs = 0;
1356 curr_sect = -1;
1357
1358 /* Prepare reusable fragment header: */
1359
1360 msg_dbg(hdr, ">FRAGMENTING>");
1361 msg_init(&fragm_hdr, MSG_FRAGMENTER, FIRST_FRAGMENT,
1362 TIPC_OK, INT_H_SIZE, msg_destnode(hdr));
1363 msg_set_link_selector(&fragm_hdr, sender->publ.ref);
1364 msg_set_size(&fragm_hdr, max_pkt);
1365 msg_set_fragm_no(&fragm_hdr, 1);
1366
1367 /* Prepare header of first fragment: */
1368
1369 buf_chain = buf = buf_acquire(max_pkt);
1370 if (!buf)
1371 return -ENOMEM;
1372 buf->next = NULL;
1373 memcpy(buf->data, (unchar *)&fragm_hdr, INT_H_SIZE);
1374 hsz = msg_hdr_sz(hdr);
1375 memcpy(buf->data + INT_H_SIZE, (unchar *)hdr, hsz);
1376 msg_dbg(buf_msg(buf), ">BUILD>");
1377
1378 /* Chop up message: */
1379
1380 fragm_crs = INT_H_SIZE + hsz;
1381 fragm_rest = fragm_sz - hsz;
1382
1383 do { /* For all sections */
1384 u32 sz;
1385
1386 if (!sect_rest) {
1387 sect_rest = msg_sect[++curr_sect].iov_len;
1388 sect_crs = (const unchar *)msg_sect[curr_sect].iov_base;
1389 }
1390
1391 if (sect_rest < fragm_rest)
1392 sz = sect_rest;
1393 else
1394 sz = fragm_rest;
1395
1396 if (likely(!sender->user_port)) {
1397 if (copy_from_user(buf->data + fragm_crs, sect_crs, sz)) {
1398error:
1399 for (; buf_chain; buf_chain = buf) {
1400 buf = buf_chain->next;
1401 buf_discard(buf_chain);
1402 }
1403 return -EFAULT;
1404 }
1405 } else
1406 memcpy(buf->data + fragm_crs, sect_crs, sz);
1407
1408 sect_crs += sz;
1409 sect_rest -= sz;
1410 fragm_crs += sz;
1411 fragm_rest -= sz;
1412 rest -= sz;
1413
1414 if (!fragm_rest && rest) {
1415
1416 /* Initiate new fragment: */
1417 if (rest <= fragm_sz) {
1418 fragm_sz = rest;
1419 msg_set_type(&fragm_hdr,LAST_FRAGMENT);
1420 } else {
1421 msg_set_type(&fragm_hdr, FRAGMENT);
1422 }
1423 msg_set_size(&fragm_hdr, fragm_sz + INT_H_SIZE);
1424 msg_set_fragm_no(&fragm_hdr, ++fragm_no);
1425 prev = buf;
1426 buf = buf_acquire(fragm_sz + INT_H_SIZE);
1427 if (!buf)
1428 goto error;
1429
1430 buf->next = NULL;
1431 prev->next = buf;
1432 memcpy(buf->data, (unchar *)&fragm_hdr, INT_H_SIZE);
1433 fragm_crs = INT_H_SIZE;
1434 fragm_rest = fragm_sz;
1435 msg_dbg(buf_msg(buf)," >BUILD>");
1436 }
1437 }
1438 while (rest > 0);
1439
1440 /*
1441 * Now we have a buffer chain. Select a link and check
1442 * that packet size is still OK
1443 */
1444 node = node_select(destaddr, sender->publ.ref & 1);
1445 if (likely(node)) {
1446 node_lock(node);
1447 l_ptr = node->active_links[sender->publ.ref & 1];
1448 if (!l_ptr) {
1449 node_unlock(node);
1450 goto reject;
1451 }
1452 if (link_max_pkt(l_ptr) < max_pkt) {
1453 sender->max_pkt = link_max_pkt(l_ptr);
1454 node_unlock(node);
1455 for (; buf_chain; buf_chain = buf) {
1456 buf = buf_chain->next;
1457 buf_discard(buf_chain);
1458 }
1459 goto again;
1460 }
1461 } else {
1462reject:
1463 for (; buf_chain; buf_chain = buf) {
1464 buf = buf_chain->next;
1465 buf_discard(buf_chain);
1466 }
1467 return port_reject_sections(sender, hdr, msg_sect, num_sect,
1468 TIPC_ERR_NO_NODE);
1469 }
1470
1471 /* Append whole chain to send queue: */
1472
1473 buf = buf_chain;
1474 l_ptr->long_msg_seq_no = mod(l_ptr->long_msg_seq_no + 1);
1475 if (!l_ptr->next_out)
1476 l_ptr->next_out = buf_chain;
1477 l_ptr->stats.sent_fragmented++;
1478 while (buf) {
1479 struct sk_buff *next = buf->next;
1480 struct tipc_msg *msg = buf_msg(buf);
1481
1482 l_ptr->stats.sent_fragments++;
1483 msg_set_long_msgno(msg, l_ptr->long_msg_seq_no);
1484 link_add_to_outqueue(l_ptr, buf, msg);
1485 msg_dbg(msg, ">ADD>");
1486 buf = next;
1487 }
1488
1489 /* Send it, if possible: */
1490
1491 link_push_queue(l_ptr);
1492 node_unlock(node);
1493 return dsz;
1494}
1495
1496/*
1497 * link_push_packet: Push one unsent packet to the media
1498 */
1499u32 link_push_packet(struct link *l_ptr)
1500{
1501 struct sk_buff *buf = l_ptr->first_out;
1502 u32 r_q_size = l_ptr->retransm_queue_size;
1503 u32 r_q_head = l_ptr->retransm_queue_head;
1504
1505 /* Step to position where retransmission failed, if any, */
1506 /* consider that buffers may have been released in meantime */
1507
1508 if (r_q_size && buf) {
1509 u32 last = lesser(mod(r_q_head + r_q_size),
1510 link_last_sent(l_ptr));
1511 u32 first = msg_seqno(buf_msg(buf));
1512
1513 while (buf && less(first, r_q_head)) {
1514 first = mod(first + 1);
1515 buf = buf->next;
1516 }
1517 l_ptr->retransm_queue_head = r_q_head = first;
1518 l_ptr->retransm_queue_size = r_q_size = mod(last - first);
1519 }
1520
1521 /* Continue retransmission now, if there is anything: */
1522
1523 if (r_q_size && buf && !skb_cloned(buf)) {
1524 msg_set_ack(buf_msg(buf), mod(l_ptr->next_in_no - 1));
1525 msg_set_bcast_ack(buf_msg(buf), l_ptr->owner->bclink.last_in);
1526 if (bearer_send(l_ptr->b_ptr, buf, &l_ptr->media_addr)) {
1527 msg_dbg(buf_msg(buf), ">DEF-RETR>");
1528 l_ptr->retransm_queue_head = mod(++r_q_head);
1529 l_ptr->retransm_queue_size = --r_q_size;
1530 l_ptr->stats.retransmitted++;
1531 return TIPC_OK;
1532 } else {
1533 l_ptr->stats.bearer_congs++;
1534 msg_dbg(buf_msg(buf), "|>DEF-RETR>");
1535 return PUSH_FAILED;
1536 }
1537 }
1538
1539 /* Send deferred protocol message, if any: */
1540
1541 buf = l_ptr->proto_msg_queue;
1542 if (buf) {
1543 msg_set_ack(buf_msg(buf), mod(l_ptr->next_in_no - 1));
1544 msg_set_bcast_ack(buf_msg(buf),l_ptr->owner->bclink.last_in);
1545 if (bearer_send(l_ptr->b_ptr, buf, &l_ptr->media_addr)) {
1546 msg_dbg(buf_msg(buf), ">DEF-PROT>");
1547 l_ptr->unacked_window = 0;
1548 buf_discard(buf);
1549 l_ptr->proto_msg_queue = 0;
1550 return TIPC_OK;
1551 } else {
1552 msg_dbg(buf_msg(buf), "|>DEF-PROT>");
1553 l_ptr->stats.bearer_congs++;
1554 return PUSH_FAILED;
1555 }
1556 }
1557
1558 /* Send one deferred data message, if send window not full: */
1559
1560 buf = l_ptr->next_out;
1561 if (buf) {
1562 struct tipc_msg *msg = buf_msg(buf);
1563 u32 next = msg_seqno(msg);
1564 u32 first = msg_seqno(buf_msg(l_ptr->first_out));
1565
1566 if (mod(next - first) < l_ptr->queue_limit[0]) {
1567 msg_set_ack(msg, mod(l_ptr->next_in_no - 1));
1568 msg_set_bcast_ack(msg, l_ptr->owner->bclink.last_in);
1569 if (bearer_send(l_ptr->b_ptr, buf, &l_ptr->media_addr)) {
1570 if (msg_user(msg) == MSG_BUNDLER)
1571 msg_set_type(msg, CLOSED_MSG);
1572 msg_dbg(msg, ">PUSH-DATA>");
1573 l_ptr->next_out = buf->next;
1574 return TIPC_OK;
1575 } else {
1576 msg_dbg(msg, "|PUSH-DATA|");
1577 l_ptr->stats.bearer_congs++;
1578 return PUSH_FAILED;
1579 }
1580 }
1581 }
1582 return PUSH_FINISHED;
1583}
1584
1585/*
1586 * push_queue(): push out the unsent messages of a link where
1587 * congestion has abated. Node is locked
1588 */
1589void link_push_queue(struct link *l_ptr)
1590{
1591 u32 res;
1592
1593 if (bearer_congested(l_ptr->b_ptr, l_ptr))
1594 return;
1595
1596 do {
1597 res = link_push_packet(l_ptr);
1598 }
1599 while (res == TIPC_OK);
1600 if (res == PUSH_FAILED)
1601 bearer_schedule(l_ptr->b_ptr, l_ptr);
1602}
1603
1604void link_retransmit(struct link *l_ptr, struct sk_buff *buf,
1605 u32 retransmits)
1606{
1607 struct tipc_msg *msg;
1608
1609 dbg("Retransmitting %u in link %x\n", retransmits, l_ptr);
1610
1611 if (bearer_congested(l_ptr->b_ptr, l_ptr) && buf && !skb_cloned(buf)) {
1612 msg_dbg(buf_msg(buf), ">NO_RETR->BCONG>");
1613 dbg_print_link(l_ptr, " ");
1614 l_ptr->retransm_queue_head = msg_seqno(buf_msg(buf));
1615 l_ptr->retransm_queue_size = retransmits;
1616 return;
1617 }
1618 while (retransmits && (buf != l_ptr->next_out) && buf && !skb_cloned(buf)) {
1619 msg = buf_msg(buf);
1620 msg_set_ack(msg, mod(l_ptr->next_in_no - 1));
1621 msg_set_bcast_ack(msg, l_ptr->owner->bclink.last_in);
1622 if (bearer_send(l_ptr->b_ptr, buf, &l_ptr->media_addr)) {
1623 /* Catch if retransmissions fail repeatedly: */
1624 if (l_ptr->last_retransmitted == msg_seqno(msg)) {
1625 if (++l_ptr->stale_count > 100) {
1626 msg_print(CONS, buf_msg(buf), ">RETR>");
1627 info("...Retransmitted %u times\n",
1628 l_ptr->stale_count);
1629 link_print(l_ptr, CONS, "Resetting Link\n");;
1630 link_reset(l_ptr);
1631 break;
1632 }
1633 } else {
1634 l_ptr->stale_count = 0;
1635 }
1636 l_ptr->last_retransmitted = msg_seqno(msg);
1637
1638 msg_dbg(buf_msg(buf), ">RETR>");
1639 buf = buf->next;
1640 retransmits--;
1641 l_ptr->stats.retransmitted++;
1642 } else {
1643 bearer_schedule(l_ptr->b_ptr, l_ptr);
1644 l_ptr->stats.bearer_congs++;
1645 l_ptr->retransm_queue_head = msg_seqno(buf_msg(buf));
1646 l_ptr->retransm_queue_size = retransmits;
1647 return;
1648 }
1649 }
1650 l_ptr->retransm_queue_head = l_ptr->retransm_queue_size = 0;
1651}
1652
1653/*
1654 * link_recv_non_seq: Receive packets which are outside
1655 * the link sequence flow
1656 */
1657
1658static void link_recv_non_seq(struct sk_buff *buf)
1659{
1660 struct tipc_msg *msg = buf_msg(buf);
1661
1662 if (msg_user(msg) == LINK_CONFIG)
1663 disc_recv_msg(buf);
1664 else
1665 bclink_recv_pkt(buf);
1666}
1667
1668/**
1669 * link_insert_deferred_queue - insert deferred messages back into receive chain
1670 */
1671
1672static struct sk_buff *link_insert_deferred_queue(struct link *l_ptr,
1673 struct sk_buff *buf)
1674{
1675 u32 seq_no;
1676
1677 if (l_ptr->oldest_deferred_in == NULL)
1678 return buf;
1679
1680 seq_no = msg_seqno(buf_msg(l_ptr->oldest_deferred_in));
1681 if (seq_no == mod(l_ptr->next_in_no)) {
1682 l_ptr->newest_deferred_in->next = buf;
1683 buf = l_ptr->oldest_deferred_in;
1684 l_ptr->oldest_deferred_in = NULL;
1685 l_ptr->deferred_inqueue_sz = 0;
1686 }
1687 return buf;
1688}
1689
1690void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *tb_ptr)
1691{
1692 read_lock_bh(&net_lock);
1693 while (head) {
1694 struct bearer *b_ptr;
1695 struct node *n_ptr;
1696 struct link *l_ptr;
1697 struct sk_buff *crs;
1698 struct sk_buff *buf = head;
1699 struct tipc_msg *msg = buf_msg(buf);
1700 u32 seq_no = msg_seqno(msg);
1701 u32 ackd = msg_ack(msg);
1702 u32 released = 0;
1703 int type;
1704
1705 b_ptr = (struct bearer *)tb_ptr;
1706 TIPC_SKB_CB(buf)->handle = b_ptr;
1707
1708 head = head->next;
1709 if (unlikely(msg_version(msg) != TIPC_VERSION))
1710 goto cont;
1711#if 0
1712 if (msg_user(msg) != LINK_PROTOCOL)
1713#endif
1714 msg_dbg(msg,"<REC<");
1715
1716 if (unlikely(msg_non_seq(msg))) {
1717 link_recv_non_seq(buf);
1718 continue;
1719 }
1720 n_ptr = node_find(msg_prevnode(msg));
1721 if (unlikely(!n_ptr))
1722 goto cont;
1723
1724 node_lock(n_ptr);
1725 l_ptr = n_ptr->links[b_ptr->identity];
1726 if (unlikely(!l_ptr)) {
1727 node_unlock(n_ptr);
1728 goto cont;
1729 }
1730 /*
1731 * Release acked messages
1732 */
1733 if (less(n_ptr->bclink.acked, msg_bcast_ack(msg))) {
1734 if (node_is_up(n_ptr) && n_ptr->bclink.supported)
1735 bclink_acknowledge(n_ptr, msg_bcast_ack(msg));
1736 }
1737
1738 crs = l_ptr->first_out;
1739 while ((crs != l_ptr->next_out) &&
1740 less_eq(msg_seqno(buf_msg(crs)), ackd)) {
1741 struct sk_buff *next = crs->next;
1742
1743 buf_discard(crs);
1744 crs = next;
1745 released++;
1746 }
1747 if (released) {
1748 l_ptr->first_out = crs;
1749 l_ptr->out_queue_size -= released;
1750 }
1751 if (unlikely(l_ptr->next_out))
1752 link_push_queue(l_ptr);
1753 if (unlikely(!list_empty(&l_ptr->waiting_ports)))
1754 link_wakeup_ports(l_ptr, 0);
1755 if (unlikely(++l_ptr->unacked_window >= TIPC_MIN_LINK_WIN)) {
1756 l_ptr->stats.sent_acks++;
1757 link_send_proto_msg(l_ptr, STATE_MSG, 0, 0, 0, 0, 0);
1758 }
1759
1760protocol_check:
1761 if (likely(link_working_working(l_ptr))) {
1762 if (likely(seq_no == mod(l_ptr->next_in_no))) {
1763 l_ptr->next_in_no++;
1764 if (unlikely(l_ptr->oldest_deferred_in))
1765 head = link_insert_deferred_queue(l_ptr,
1766 head);
1767 if (likely(msg_is_dest(msg, tipc_own_addr))) {
1768deliver:
1769 if (likely(msg_isdata(msg))) {
1770 node_unlock(n_ptr);
1771 port_recv_msg(buf);
1772 continue;
1773 }
1774 switch (msg_user(msg)) {
1775 case MSG_BUNDLER:
1776 l_ptr->stats.recv_bundles++;
1777 l_ptr->stats.recv_bundled +=
1778 msg_msgcnt(msg);
1779 node_unlock(n_ptr);
1780 link_recv_bundle(buf);
1781 continue;
1782 case ROUTE_DISTRIBUTOR:
1783 node_unlock(n_ptr);
1784 cluster_recv_routing_table(buf);
1785 continue;
1786 case NAME_DISTRIBUTOR:
1787 node_unlock(n_ptr);
1788 named_recv(buf);
1789 continue;
1790 case CONN_MANAGER:
1791 node_unlock(n_ptr);
1792 port_recv_proto_msg(buf);
1793 continue;
1794 case MSG_FRAGMENTER:
1795 l_ptr->stats.recv_fragments++;
1796 if (link_recv_fragment(
1797 &l_ptr->defragm_buf,
1798 &buf, &msg)) {
1799 l_ptr->stats.recv_fragmented++;
1800 goto deliver;
1801 }
1802 break;
1803 case CHANGEOVER_PROTOCOL:
1804 type = msg_type(msg);
1805 if (link_recv_changeover_msg(
1806 &l_ptr, &buf)) {
1807 msg = buf_msg(buf);
1808 seq_no = msg_seqno(msg);
1809 TIPC_SKB_CB(buf)->handle
1810 = b_ptr;
1811 if (type == ORIGINAL_MSG)
1812 goto deliver;
1813 goto protocol_check;
1814 }
1815 break;
1816 }
1817 }
1818 node_unlock(n_ptr);
1819 net_route_msg(buf);
1820 continue;
1821 }
1822 link_handle_out_of_seq_msg(l_ptr, buf);
1823 head = link_insert_deferred_queue(l_ptr, head);
1824 node_unlock(n_ptr);
1825 continue;
1826 }
1827
1828 if (msg_user(msg) == LINK_PROTOCOL) {
1829 link_recv_proto_msg(l_ptr, buf);
1830 head = link_insert_deferred_queue(l_ptr, head);
1831 node_unlock(n_ptr);
1832 continue;
1833 }
1834 msg_dbg(msg,"NSEQ<REC<");
1835 link_state_event(l_ptr, TRAFFIC_MSG_EVT);
1836
1837 if (link_working_working(l_ptr)) {
1838 /* Re-insert in front of queue */
1839 msg_dbg(msg,"RECV-REINS:");
1840 buf->next = head;
1841 head = buf;
1842 node_unlock(n_ptr);
1843 continue;
1844 }
1845 node_unlock(n_ptr);
1846cont:
1847 buf_discard(buf);
1848 }
1849 read_unlock_bh(&net_lock);
1850}
1851
1852/*
1853 * link_defer_buf(): Sort a received out-of-sequence packet
1854 * into the deferred reception queue.
1855 * Returns the increase of the queue length,i.e. 0 or 1
1856 */
1857
1858u32 link_defer_pkt(struct sk_buff **head,
1859 struct sk_buff **tail,
1860 struct sk_buff *buf)
1861{
1862 struct sk_buff *prev = 0;
1863 struct sk_buff *crs = *head;
1864 u32 seq_no = msg_seqno(buf_msg(buf));
1865
1866 buf->next = NULL;
1867
1868 /* Empty queue ? */
1869 if (*head == NULL) {
1870 *head = *tail = buf;
1871 return 1;
1872 }
1873
1874 /* Last ? */
1875 if (less(msg_seqno(buf_msg(*tail)), seq_no)) {
1876 (*tail)->next = buf;
1877 *tail = buf;
1878 return 1;
1879 }
1880
1881 /* Scan through queue and sort it in */
1882 do {
1883 struct tipc_msg *msg = buf_msg(crs);
1884
1885 if (less(seq_no, msg_seqno(msg))) {
1886 buf->next = crs;
1887 if (prev)
1888 prev->next = buf;
1889 else
1890 *head = buf;
1891 return 1;
1892 }
1893 if (seq_no == msg_seqno(msg)) {
1894 break;
1895 }
1896 prev = crs;
1897 crs = crs->next;
1898 }
1899 while (crs);
1900
1901 /* Message is a duplicate of an existing message */
1902
1903 buf_discard(buf);
1904 return 0;
1905}
1906
1907/**
1908 * link_handle_out_of_seq_msg - handle arrival of out-of-sequence packet
1909 */
1910
1911static void link_handle_out_of_seq_msg(struct link *l_ptr,
1912 struct sk_buff *buf)
1913{
1914 u32 seq_no = msg_seqno(buf_msg(buf));
1915
1916 if (likely(msg_user(buf_msg(buf)) == LINK_PROTOCOL)) {
1917 link_recv_proto_msg(l_ptr, buf);
1918 return;
1919 }
1920
1921 dbg("rx OOS msg: seq_no %u, expecting %u (%u)\n",
1922 seq_no, mod(l_ptr->next_in_no), l_ptr->next_in_no);
1923
1924 /* Record OOS packet arrival (force mismatch on next timeout) */
1925
1926 l_ptr->checkpoint--;
1927
1928 /*
1929 * Discard packet if a duplicate; otherwise add it to deferred queue
1930 * and notify peer of gap as per protocol specification
1931 */
1932
1933 if (less(seq_no, mod(l_ptr->next_in_no))) {
1934 l_ptr->stats.duplicates++;
1935 buf_discard(buf);
1936 return;
1937 }
1938
1939 if (link_defer_pkt(&l_ptr->oldest_deferred_in,
1940 &l_ptr->newest_deferred_in, buf)) {
1941 l_ptr->deferred_inqueue_sz++;
1942 l_ptr->stats.deferred_recv++;
1943 if ((l_ptr->deferred_inqueue_sz % 16) == 1)
1944 link_send_proto_msg(l_ptr, STATE_MSG, 0, 0, 0, 0, 0);
1945 } else
1946 l_ptr->stats.duplicates++;
1947}
1948
1949/*
1950 * Send protocol message to the other endpoint.
1951 */
1952void link_send_proto_msg(struct link *l_ptr, u32 msg_typ, int probe_msg,
1953 u32 gap, u32 tolerance, u32 priority, u32 ack_mtu)
1954{
1955 struct sk_buff *buf = 0;
1956 struct tipc_msg *msg = l_ptr->pmsg;
1957 u32 msg_size = sizeof(l_ptr->proto_msg);
1958
1959 if (link_blocked(l_ptr))
1960 return;
1961 msg_set_type(msg, msg_typ);
1962 msg_set_net_plane(msg, l_ptr->b_ptr->net_plane);
1963 msg_set_bcast_ack(msg, mod(l_ptr->owner->bclink.last_in));
1964 msg_set_last_bcast(msg, bclink_get_last_sent());
1965
1966 if (msg_typ == STATE_MSG) {
1967 u32 next_sent = mod(l_ptr->next_out_no);
1968
1969 if (!link_is_up(l_ptr))
1970 return;
1971 if (l_ptr->next_out)
1972 next_sent = msg_seqno(buf_msg(l_ptr->next_out));
1973 msg_set_next_sent(msg, next_sent);
1974 if (l_ptr->oldest_deferred_in) {
1975 u32 rec = msg_seqno(buf_msg(l_ptr->oldest_deferred_in));
1976 gap = mod(rec - mod(l_ptr->next_in_no));
1977 }
1978 msg_set_seq_gap(msg, gap);
1979 if (gap)
1980 l_ptr->stats.sent_nacks++;
1981 msg_set_link_tolerance(msg, tolerance);
1982 msg_set_linkprio(msg, priority);
1983 msg_set_max_pkt(msg, ack_mtu);
1984 msg_set_ack(msg, mod(l_ptr->next_in_no - 1));
1985 msg_set_probe(msg, probe_msg != 0);
1986 if (probe_msg) {
1987 u32 mtu = l_ptr->max_pkt;
1988
1989 if ((mtu < l_ptr->max_pkt_target) &&
1990 link_working_working(l_ptr) &&
1991 l_ptr->fsm_msg_cnt) {
1992 msg_size = (mtu + (l_ptr->max_pkt_target - mtu)/2 + 2) & ~3;
1993 if (l_ptr->max_pkt_probes == 10) {
1994 l_ptr->max_pkt_target = (msg_size - 4);
1995 l_ptr->max_pkt_probes = 0;
1996 msg_size = (mtu + (l_ptr->max_pkt_target - mtu)/2 + 2) & ~3;
1997 }
1998 l_ptr->max_pkt_probes++;
1999 }
2000
2001 l_ptr->stats.sent_probes++;
2002 }
2003 l_ptr->stats.sent_states++;
2004 } else { /* RESET_MSG or ACTIVATE_MSG */
2005 msg_set_ack(msg, mod(l_ptr->reset_checkpoint - 1));
2006 msg_set_seq_gap(msg, 0);
2007 msg_set_next_sent(msg, 1);
2008 msg_set_link_tolerance(msg, l_ptr->tolerance);
2009 msg_set_linkprio(msg, l_ptr->priority);
2010 msg_set_max_pkt(msg, l_ptr->max_pkt_target);
2011 }
2012
2013 if (node_has_redundant_links(l_ptr->owner)) {
2014 msg_set_redundant_link(msg);
2015 } else {
2016 msg_clear_redundant_link(msg);
2017 }
2018 msg_set_linkprio(msg, l_ptr->priority);
2019
2020 /* Ensure sequence number will not fit : */
2021
2022 msg_set_seqno(msg, mod(l_ptr->next_out_no + (0xffff/2)));
2023
2024 /* Congestion? */
2025
2026 if (bearer_congested(l_ptr->b_ptr, l_ptr)) {
2027 if (!l_ptr->proto_msg_queue) {
2028 l_ptr->proto_msg_queue =
2029 buf_acquire(sizeof(l_ptr->proto_msg));
2030 }
2031 buf = l_ptr->proto_msg_queue;
2032 if (!buf)
2033 return;
2034 memcpy(buf->data, (unchar *)msg, sizeof(l_ptr->proto_msg));
2035 return;
2036 }
2037 msg_set_timestamp(msg, jiffies_to_msecs(jiffies));
2038
2039 /* Message can be sent */
2040
2041 msg_dbg(msg, ">>");
2042
2043 buf = buf_acquire(msg_size);
2044 if (!buf)
2045 return;
2046
2047 memcpy(buf->data, (unchar *)msg, sizeof(l_ptr->proto_msg));
2048 msg_set_size(buf_msg(buf), msg_size);
2049
2050 if (bearer_send(l_ptr->b_ptr, buf, &l_ptr->media_addr)) {
2051 l_ptr->unacked_window = 0;
2052 buf_discard(buf);
2053 return;
2054 }
2055
2056 /* New congestion */
2057 bearer_schedule(l_ptr->b_ptr, l_ptr);
2058 l_ptr->proto_msg_queue = buf;
2059 l_ptr->stats.bearer_congs++;
2060}
2061
2062/*
2063 * Receive protocol message :
2064 * Note that network plane id propagates through the network, and may
2065 * change at any time. The node with lowest address rules
2066 */
2067
2068static void link_recv_proto_msg(struct link *l_ptr, struct sk_buff *buf)
2069{
2070 u32 rec_gap = 0;
2071 u32 max_pkt_info;
2072 u32 max_pkt_ack;
2073 u32 msg_tol;
2074 struct tipc_msg *msg = buf_msg(buf);
2075
2076 dbg("AT(%u):", jiffies_to_msecs(jiffies));
2077 msg_dbg(msg, "<<");
2078 if (link_blocked(l_ptr))
2079 goto exit;
2080
2081 /* record unnumbered packet arrival (force mismatch on next timeout) */
2082
2083 l_ptr->checkpoint--;
2084
2085 if (l_ptr->b_ptr->net_plane != msg_net_plane(msg))
2086 if (tipc_own_addr > msg_prevnode(msg))
2087 l_ptr->b_ptr->net_plane = msg_net_plane(msg);
2088
2089 l_ptr->owner->permit_changeover = msg_redundant_link(msg);
2090
2091 switch (msg_type(msg)) {
2092
2093 case RESET_MSG:
2094 if (!link_working_unknown(l_ptr) && l_ptr->peer_session) {
2095 if (msg_session(msg) == l_ptr->peer_session) {
2096 dbg("Duplicate RESET: %u<->%u\n",
2097 msg_session(msg), l_ptr->peer_session);
2098 break; /* duplicate: ignore */
2099 }
2100 }
2101 /* fall thru' */
2102 case ACTIVATE_MSG:
2103 /* Update link settings according other endpoint's values */
2104
2105 strcpy((strrchr(l_ptr->name, ':') + 1), (char *)msg_data(msg));
2106
2107 if ((msg_tol = msg_link_tolerance(msg)) &&
2108 (msg_tol > l_ptr->tolerance))
2109 link_set_supervision_props(l_ptr, msg_tol);
2110
2111 if (msg_linkprio(msg) > l_ptr->priority)
2112 l_ptr->priority = msg_linkprio(msg);
2113
2114 max_pkt_info = msg_max_pkt(msg);
2115 if (max_pkt_info) {
2116 if (max_pkt_info < l_ptr->max_pkt_target)
2117 l_ptr->max_pkt_target = max_pkt_info;
2118 if (l_ptr->max_pkt > l_ptr->max_pkt_target)
2119 l_ptr->max_pkt = l_ptr->max_pkt_target;
2120 } else {
2121 l_ptr->max_pkt = l_ptr->max_pkt_target;
2122 }
2123 l_ptr->owner->bclink.supported = (max_pkt_info != 0);
2124
2125 link_state_event(l_ptr, msg_type(msg));
2126
2127 l_ptr->peer_session = msg_session(msg);
2128 l_ptr->peer_bearer_id = msg_bearer_id(msg);
2129
2130 /* Synchronize broadcast sequence numbers */
2131 if (!node_has_redundant_links(l_ptr->owner)) {
2132 l_ptr->owner->bclink.last_in = mod(msg_last_bcast(msg));
2133 }
2134 break;
2135 case STATE_MSG:
2136
2137 if ((msg_tol = msg_link_tolerance(msg)))
2138 link_set_supervision_props(l_ptr, msg_tol);
2139
2140 if (msg_linkprio(msg) &&
2141 (msg_linkprio(msg) != l_ptr->priority)) {
2142 warn("Changing prio <%s>: %u->%u\n",
2143 l_ptr->name, l_ptr->priority, msg_linkprio(msg));
2144 l_ptr->priority = msg_linkprio(msg);
2145 link_reset(l_ptr); /* Enforce change to take effect */
2146 break;
2147 }
2148 link_state_event(l_ptr, TRAFFIC_MSG_EVT);
2149 l_ptr->stats.recv_states++;
2150 if (link_reset_unknown(l_ptr))
2151 break;
2152
2153 if (less_eq(mod(l_ptr->next_in_no), msg_next_sent(msg))) {
2154 rec_gap = mod(msg_next_sent(msg) -
2155 mod(l_ptr->next_in_no));
2156 }
2157
2158 max_pkt_ack = msg_max_pkt(msg);
2159 if (max_pkt_ack > l_ptr->max_pkt) {
2160 dbg("Link <%s> updated MTU %u -> %u\n",
2161 l_ptr->name, l_ptr->max_pkt, max_pkt_ack);
2162 l_ptr->max_pkt = max_pkt_ack;
2163 l_ptr->max_pkt_probes = 0;
2164 }
2165
2166 max_pkt_ack = 0;
2167 if (msg_probe(msg)) {
2168 l_ptr->stats.recv_probes++;
2169 if (msg_size(msg) > sizeof(l_ptr->proto_msg)) {
2170 max_pkt_ack = msg_size(msg);
2171 }
2172 }
2173
2174 /* Protocol message before retransmits, reduce loss risk */
2175
2176 bclink_check_gap(l_ptr->owner, msg_last_bcast(msg));
2177
2178 if (rec_gap || (msg_probe(msg))) {
2179 link_send_proto_msg(l_ptr, STATE_MSG,
2180 0, rec_gap, 0, 0, max_pkt_ack);
2181 }
2182 if (msg_seq_gap(msg)) {
2183 msg_dbg(msg, "With Gap:");
2184 l_ptr->stats.recv_nacks++;
2185 link_retransmit(l_ptr, l_ptr->first_out,
2186 msg_seq_gap(msg));
2187 }
2188 break;
2189 default:
2190 msg_dbg(buf_msg(buf), "<DISCARDING UNKNOWN<");
2191 }
2192exit:
2193 buf_discard(buf);
2194}
2195
2196
2197/*
2198 * link_tunnel(): Send one message via a link belonging to
2199 * another bearer. Owner node is locked.
2200 */
2201void link_tunnel(struct link *l_ptr,
2202 struct tipc_msg *tunnel_hdr,
2203 struct tipc_msg *msg,
2204 u32 selector)
2205{
2206 struct link *tunnel;
2207 struct sk_buff *buf;
2208 u32 length = msg_size(msg);
2209
2210 tunnel = l_ptr->owner->active_links[selector & 1];
2211 if (!link_is_up(tunnel))
2212 return;
2213 msg_set_size(tunnel_hdr, length + INT_H_SIZE);
2214 buf = buf_acquire(length + INT_H_SIZE);
2215 if (!buf)
2216 return;
2217 memcpy(buf->data, (unchar *)tunnel_hdr, INT_H_SIZE);
2218 memcpy(buf->data + INT_H_SIZE, (unchar *)msg, length);
2219 dbg("%c->%c:", l_ptr->b_ptr->net_plane, tunnel->b_ptr->net_plane);
2220 msg_dbg(buf_msg(buf), ">SEND>");
2221 assert(tunnel);
2222 link_send_buf(tunnel, buf);
2223}
2224
2225
2226
2227/*
2228 * changeover(): Send whole message queue via the remaining link
2229 * Owner node is locked.
2230 */
2231
2232void link_changeover(struct link *l_ptr)
2233{
2234 u32 msgcount = l_ptr->out_queue_size;
2235 struct sk_buff *crs = l_ptr->first_out;
2236 struct link *tunnel = l_ptr->owner->active_links[0];
2237 int split_bundles = node_has_redundant_links(l_ptr->owner);
2238 struct tipc_msg tunnel_hdr;
2239
2240 if (!tunnel)
2241 return;
2242
2243 if (!l_ptr->owner->permit_changeover)
2244 return;
2245
2246 msg_init(&tunnel_hdr, CHANGEOVER_PROTOCOL,
2247 ORIGINAL_MSG, TIPC_OK, INT_H_SIZE, l_ptr->addr);
2248 msg_set_bearer_id(&tunnel_hdr, l_ptr->peer_bearer_id);
2249 msg_set_msgcnt(&tunnel_hdr, msgcount);
2250 if (!l_ptr->first_out) {
2251 struct sk_buff *buf;
2252
2253 assert(!msgcount);
2254 buf = buf_acquire(INT_H_SIZE);
2255 if (buf) {
2256 memcpy(buf->data, (unchar *)&tunnel_hdr, INT_H_SIZE);
2257 msg_set_size(&tunnel_hdr, INT_H_SIZE);
2258 dbg("%c->%c:", l_ptr->b_ptr->net_plane,
2259 tunnel->b_ptr->net_plane);
2260 msg_dbg(&tunnel_hdr, "EMPTY>SEND>");
2261 link_send_buf(tunnel, buf);
2262 } else {
2263 warn("Memory squeeze; link changeover failed\n");
2264 }
2265 return;
2266 }
2267 while (crs) {
2268 struct tipc_msg *msg = buf_msg(crs);
2269
2270 if ((msg_user(msg) == MSG_BUNDLER) && split_bundles) {
2271 u32 msgcount = msg_msgcnt(msg);
2272 struct tipc_msg *m = msg_get_wrapped(msg);
2273 unchar* pos = (unchar*)m;
2274
2275 while (msgcount--) {
2276 msg_set_seqno(m,msg_seqno(msg));
2277 link_tunnel(l_ptr, &tunnel_hdr, m,
2278 msg_link_selector(m));
2279 pos += align(msg_size(m));
2280 m = (struct tipc_msg *)pos;
2281 }
2282 } else {
2283 link_tunnel(l_ptr, &tunnel_hdr, msg,
2284 msg_link_selector(msg));
2285 }
2286 crs = crs->next;
2287 }
2288}
2289
2290void link_send_duplicate(struct link *l_ptr, struct link *tunnel)
2291{
2292 struct sk_buff *iter;
2293 struct tipc_msg tunnel_hdr;
2294
2295 msg_init(&tunnel_hdr, CHANGEOVER_PROTOCOL,
2296 DUPLICATE_MSG, TIPC_OK, INT_H_SIZE, l_ptr->addr);
2297 msg_set_msgcnt(&tunnel_hdr, l_ptr->out_queue_size);
2298 msg_set_bearer_id(&tunnel_hdr, l_ptr->peer_bearer_id);
2299 iter = l_ptr->first_out;
2300 while (iter) {
2301 struct sk_buff *outbuf;
2302 struct tipc_msg *msg = buf_msg(iter);
2303 u32 length = msg_size(msg);
2304
2305 if (msg_user(msg) == MSG_BUNDLER)
2306 msg_set_type(msg, CLOSED_MSG);
2307 msg_set_ack(msg, mod(l_ptr->next_in_no - 1)); /* Update */
2308 msg_set_bcast_ack(msg, l_ptr->owner->bclink.last_in);
2309 msg_set_size(&tunnel_hdr, length + INT_H_SIZE);
2310 outbuf = buf_acquire(length + INT_H_SIZE);
2311 if (outbuf == NULL) {
2312 warn("Memory squeeze; buffer duplication failed\n");
2313 return;
2314 }
2315 memcpy(outbuf->data, (unchar *)&tunnel_hdr, INT_H_SIZE);
2316 memcpy(outbuf->data + INT_H_SIZE, iter->data, length);
2317 dbg("%c->%c:", l_ptr->b_ptr->net_plane,
2318 tunnel->b_ptr->net_plane);
2319 msg_dbg(buf_msg(outbuf), ">SEND>");
2320 link_send_buf(tunnel, outbuf);
2321 if (!link_is_up(l_ptr))
2322 return;
2323 iter = iter->next;
2324 }
2325}
2326
2327
2328
2329/**
2330 * buf_extract - extracts embedded TIPC message from another message
2331 * @skb: encapsulating message buffer
2332 * @from_pos: offset to extract from
2333 *
2334 * Returns a new message buffer containing an embedded message. The
2335 * encapsulating message itself is left unchanged.
2336 */
2337
2338static struct sk_buff *buf_extract(struct sk_buff *skb, u32 from_pos)
2339{
2340 struct tipc_msg *msg = (struct tipc_msg *)(skb->data + from_pos);
2341 u32 size = msg_size(msg);
2342 struct sk_buff *eb;
2343
2344 eb = buf_acquire(size);
2345 if (eb)
2346 memcpy(eb->data, (unchar *)msg, size);
2347 return eb;
2348}
2349
2350/*
2351 * link_recv_changeover_msg(): Receive tunneled packet sent
2352 * via other link. Node is locked. Return extracted buffer.
2353 */
2354
2355static int link_recv_changeover_msg(struct link **l_ptr,
2356 struct sk_buff **buf)
2357{
2358 struct sk_buff *tunnel_buf = *buf;
2359 struct link *dest_link;
2360 struct tipc_msg *msg;
2361 struct tipc_msg *tunnel_msg = buf_msg(tunnel_buf);
2362 u32 msg_typ = msg_type(tunnel_msg);
2363 u32 msg_count = msg_msgcnt(tunnel_msg);
2364
2365 dest_link = (*l_ptr)->owner->links[msg_bearer_id(tunnel_msg)];
2366 assert(dest_link != *l_ptr);
2367 if (!dest_link) {
2368 msg_dbg(tunnel_msg, "NOLINK/<REC<");
2369 goto exit;
2370 }
2371 dbg("%c<-%c:", dest_link->b_ptr->net_plane,
2372 (*l_ptr)->b_ptr->net_plane);
2373 *l_ptr = dest_link;
2374 msg = msg_get_wrapped(tunnel_msg);
2375
2376 if (msg_typ == DUPLICATE_MSG) {
2377 if (less(msg_seqno(msg), mod(dest_link->next_in_no))) {
2378 msg_dbg(tunnel_msg, "DROP/<REC<");
2379 goto exit;
2380 }
2381 *buf = buf_extract(tunnel_buf,INT_H_SIZE);
2382 if (*buf == NULL) {
2383 warn("Memory squeeze; failed to extract msg\n");
2384 goto exit;
2385 }
2386 msg_dbg(tunnel_msg, "TNL<REC<");
2387 buf_discard(tunnel_buf);
2388 return 1;
2389 }
2390
2391 /* First original message ?: */
2392
2393 if (link_is_up(dest_link)) {
2394 msg_dbg(tunnel_msg, "UP/FIRST/<REC<");
2395 link_reset(dest_link);
2396 dest_link->exp_msg_count = msg_count;
2397 if (!msg_count)
2398 goto exit;
2399 } else if (dest_link->exp_msg_count == START_CHANGEOVER) {
2400 msg_dbg(tunnel_msg, "BLK/FIRST/<REC<");
2401 dest_link->exp_msg_count = msg_count;
2402 if (!msg_count)
2403 goto exit;
2404 }
2405
2406 /* Receive original message */
2407
2408 if (dest_link->exp_msg_count == 0) {
2409 msg_dbg(tunnel_msg, "OVERDUE/DROP/<REC<");
2410 dbg_print_link(dest_link, "LINK:");
2411 goto exit;
2412 }
2413 dest_link->exp_msg_count--;
2414 if (less(msg_seqno(msg), dest_link->reset_checkpoint)) {
2415 msg_dbg(tunnel_msg, "DROP/DUPL/<REC<");
2416 goto exit;
2417 } else {
2418 *buf = buf_extract(tunnel_buf, INT_H_SIZE);
2419 if (*buf != NULL) {
2420 msg_dbg(tunnel_msg, "TNL<REC<");
2421 buf_discard(tunnel_buf);
2422 return 1;
2423 } else {
2424 warn("Memory squeeze; dropped incoming msg\n");
2425 }
2426 }
2427exit:
2428 *buf = 0;
2429 buf_discard(tunnel_buf);
2430 return 0;
2431}
2432
2433/*
2434 * Bundler functionality:
2435 */
2436void link_recv_bundle(struct sk_buff *buf)
2437{
2438 u32 msgcount = msg_msgcnt(buf_msg(buf));
2439 u32 pos = INT_H_SIZE;
2440 struct sk_buff *obuf;
2441
2442 msg_dbg(buf_msg(buf), "<BNDL<: ");
2443 while (msgcount--) {
2444 obuf = buf_extract(buf, pos);
2445 if (obuf == NULL) {
2446 char addr_string[16];
2447
2448 warn("Buffer allocation failure;\n");
2449 warn(" incoming message(s) from %s lost\n",
2450 addr_string_fill(addr_string,
2451 msg_orignode(buf_msg(buf))));
2452 return;
2453 };
2454 pos += align(msg_size(buf_msg(obuf)));
2455 msg_dbg(buf_msg(obuf), " /");
2456 net_route_msg(obuf);
2457 }
2458 buf_discard(buf);
2459}
2460
2461/*
2462 * Fragmentation/defragmentation:
2463 */
2464
2465
2466/*
2467 * link_send_long_buf: Entry for buffers needing fragmentation.
2468 * The buffer is complete, inclusive total message length.
2469 * Returns user data length.
2470 */
2471int link_send_long_buf(struct link *l_ptr, struct sk_buff *buf)
2472{
2473 struct tipc_msg *inmsg = buf_msg(buf);
2474 struct tipc_msg fragm_hdr;
2475 u32 insize = msg_size(inmsg);
2476 u32 dsz = msg_data_sz(inmsg);
2477 unchar *crs = buf->data;
2478 u32 rest = insize;
2479 u32 pack_sz = link_max_pkt(l_ptr);
2480 u32 fragm_sz = pack_sz - INT_H_SIZE;
2481 u32 fragm_no = 1;
2482 u32 destaddr = msg_destnode(inmsg);
2483
2484 if (msg_short(inmsg))
2485 destaddr = l_ptr->addr;
2486
2487 if (msg_routed(inmsg))
2488 msg_set_prevnode(inmsg, tipc_own_addr);
2489
2490 /* Prepare reusable fragment header: */
2491
2492 msg_init(&fragm_hdr, MSG_FRAGMENTER, FIRST_FRAGMENT,
2493 TIPC_OK, INT_H_SIZE, destaddr);
2494 msg_set_link_selector(&fragm_hdr, msg_link_selector(inmsg));
2495 msg_set_long_msgno(&fragm_hdr, mod(l_ptr->long_msg_seq_no++));
2496 msg_set_fragm_no(&fragm_hdr, fragm_no);
2497 l_ptr->stats.sent_fragmented++;
2498
2499 /* Chop up message: */
2500
2501 while (rest > 0) {
2502 struct sk_buff *fragm;
2503
2504 if (rest <= fragm_sz) {
2505 fragm_sz = rest;
2506 msg_set_type(&fragm_hdr, LAST_FRAGMENT);
2507 }
2508 fragm = buf_acquire(fragm_sz + INT_H_SIZE);
2509 if (fragm == NULL) {
2510 warn("Memory squeeze; failed to fragment msg\n");
2511 dsz = -ENOMEM;
2512 goto exit;
2513 }
2514 msg_set_size(&fragm_hdr, fragm_sz + INT_H_SIZE);
2515 memcpy(fragm->data, (unchar *)&fragm_hdr, INT_H_SIZE);
2516 memcpy(fragm->data + INT_H_SIZE, crs, fragm_sz);
2517
2518 /* Send queued messages first, if any: */
2519
2520 l_ptr->stats.sent_fragments++;
2521 link_send_buf(l_ptr, fragm);
2522 if (!link_is_up(l_ptr))
2523 return dsz;
2524 msg_set_fragm_no(&fragm_hdr, ++fragm_no);
2525 rest -= fragm_sz;
2526 crs += fragm_sz;
2527 msg_set_type(&fragm_hdr, FRAGMENT);
2528 }
2529exit:
2530 buf_discard(buf);
2531 return dsz;
2532}
2533
2534/*
2535 * A pending message being re-assembled must store certain values
2536 * to handle subsequent fragments correctly. The following functions
2537 * help storing these values in unused, available fields in the
2538 * pending message. This makes dynamic memory allocation unecessary.
2539 */
2540
2541static inline u32 get_long_msg_seqno(struct sk_buff *buf)
2542{
2543 return msg_seqno(buf_msg(buf));
2544}
2545
2546static inline void set_long_msg_seqno(struct sk_buff *buf, u32 seqno)
2547{
2548 msg_set_seqno(buf_msg(buf), seqno);
2549}
2550
2551static inline u32 get_fragm_size(struct sk_buff *buf)
2552{
2553 return msg_ack(buf_msg(buf));
2554}
2555
2556static inline void set_fragm_size(struct sk_buff *buf, u32 sz)
2557{
2558 msg_set_ack(buf_msg(buf), sz);
2559}
2560
2561static inline u32 get_expected_frags(struct sk_buff *buf)
2562{
2563 return msg_bcast_ack(buf_msg(buf));
2564}
2565
2566static inline void set_expected_frags(struct sk_buff *buf, u32 exp)
2567{
2568 msg_set_bcast_ack(buf_msg(buf), exp);
2569}
2570
2571static inline u32 get_timer_cnt(struct sk_buff *buf)
2572{
2573 return msg_reroute_cnt(buf_msg(buf));
2574}
2575
2576static inline void incr_timer_cnt(struct sk_buff *buf)
2577{
2578 msg_incr_reroute_cnt(buf_msg(buf));
2579}
2580
2581/*
2582 * link_recv_fragment(): Called with node lock on. Returns
2583 * the reassembled buffer if message is complete.
2584 */
2585int link_recv_fragment(struct sk_buff **pending, struct sk_buff **fb,
2586 struct tipc_msg **m)
2587{
2588 struct sk_buff *prev = 0;
2589 struct sk_buff *fbuf = *fb;
2590 struct tipc_msg *fragm = buf_msg(fbuf);
2591 struct sk_buff *pbuf = *pending;
2592 u32 long_msg_seq_no = msg_long_msgno(fragm);
2593
2594 *fb = 0;
2595 msg_dbg(fragm,"FRG<REC<");
2596
2597 /* Is there an incomplete message waiting for this fragment? */
2598
2599 while (pbuf && ((msg_seqno(buf_msg(pbuf)) != long_msg_seq_no)
2600 || (msg_orignode(fragm) != msg_orignode(buf_msg(pbuf))))) {
2601 prev = pbuf;
2602 pbuf = pbuf->next;
2603 }
2604
2605 if (!pbuf && (msg_type(fragm) == FIRST_FRAGMENT)) {
2606 struct tipc_msg *imsg = (struct tipc_msg *)msg_data(fragm);
2607 u32 msg_sz = msg_size(imsg);
2608 u32 fragm_sz = msg_data_sz(fragm);
2609 u32 exp_fragm_cnt = msg_sz/fragm_sz + !!(msg_sz % fragm_sz);
2610 u32 max = TIPC_MAX_USER_MSG_SIZE + LONG_H_SIZE;
2611 if (msg_type(imsg) == TIPC_MCAST_MSG)
2612 max = TIPC_MAX_USER_MSG_SIZE + MCAST_H_SIZE;
2613 if (msg_size(imsg) > max) {
2614 msg_dbg(fragm,"<REC<Oversized: ");
2615 buf_discard(fbuf);
2616 return 0;
2617 }
2618 pbuf = buf_acquire(msg_size(imsg));
2619 if (pbuf != NULL) {
2620 pbuf->next = *pending;
2621 *pending = pbuf;
2622 memcpy(pbuf->data, (unchar *)imsg, msg_data_sz(fragm));
2623
2624 /* Prepare buffer for subsequent fragments. */
2625
2626 set_long_msg_seqno(pbuf, long_msg_seq_no);
2627 set_fragm_size(pbuf,fragm_sz);
2628 set_expected_frags(pbuf,exp_fragm_cnt - 1);
2629 } else {
2630 warn("Memory squeeze; got no defragmenting buffer\n");
2631 }
2632 buf_discard(fbuf);
2633 return 0;
2634 } else if (pbuf && (msg_type(fragm) != FIRST_FRAGMENT)) {
2635 u32 dsz = msg_data_sz(fragm);
2636 u32 fsz = get_fragm_size(pbuf);
2637 u32 crs = ((msg_fragm_no(fragm) - 1) * fsz);
2638 u32 exp_frags = get_expected_frags(pbuf) - 1;
2639 memcpy(pbuf->data + crs, msg_data(fragm), dsz);
2640 buf_discard(fbuf);
2641
2642 /* Is message complete? */
2643
2644 if (exp_frags == 0) {
2645 if (prev)
2646 prev->next = pbuf->next;
2647 else
2648 *pending = pbuf->next;
2649 msg_reset_reroute_cnt(buf_msg(pbuf));
2650 *fb = pbuf;
2651 *m = buf_msg(pbuf);
2652 return 1;
2653 }
2654 set_expected_frags(pbuf,exp_frags);
2655 return 0;
2656 }
2657 dbg(" Discarding orphan fragment %x\n",fbuf);
2658 msg_dbg(fragm,"ORPHAN:");
2659 dbg("Pending long buffers:\n");
2660 dbg_print_buf_chain(*pending);
2661 buf_discard(fbuf);
2662 return 0;
2663}
2664
2665/**
2666 * link_check_defragm_bufs - flush stale incoming message fragments
2667 * @l_ptr: pointer to link
2668 */
2669
2670static void link_check_defragm_bufs(struct link *l_ptr)
2671{
2672 struct sk_buff *prev = 0;
2673 struct sk_buff *next = 0;
2674 struct sk_buff *buf = l_ptr->defragm_buf;
2675
2676 if (!buf)
2677 return;
2678 if (!link_working_working(l_ptr))
2679 return;
2680 while (buf) {
2681 u32 cnt = get_timer_cnt(buf);
2682
2683 next = buf->next;
2684 if (cnt < 4) {
2685 incr_timer_cnt(buf);
2686 prev = buf;
2687 } else {
2688 dbg(" Discarding incomplete long buffer\n");
2689 msg_dbg(buf_msg(buf), "LONG:");
2690 dbg_print_link(l_ptr, "curr:");
2691 dbg("Pending long buffers:\n");
2692 dbg_print_buf_chain(l_ptr->defragm_buf);
2693 if (prev)
2694 prev->next = buf->next;
2695 else
2696 l_ptr->defragm_buf = buf->next;
2697 buf_discard(buf);
2698 }
2699 buf = next;
2700 }
2701}
2702
2703
2704
2705static void link_set_supervision_props(struct link *l_ptr, u32 tolerance)
2706{
2707 l_ptr->tolerance = tolerance;
2708 l_ptr->continuity_interval =
2709 ((tolerance / 4) > 500) ? 500 : tolerance / 4;
2710 l_ptr->abort_limit = tolerance / (l_ptr->continuity_interval / 4);
2711}
2712
2713
2714void link_set_queue_limits(struct link *l_ptr, u32 window)
2715{
2716 /* Data messages from this node, inclusive FIRST_FRAGM */
2717 l_ptr->queue_limit[DATA_LOW] = window;
2718 l_ptr->queue_limit[DATA_MEDIUM] = (window / 3) * 4;
2719 l_ptr->queue_limit[DATA_HIGH] = (window / 3) * 5;
2720 l_ptr->queue_limit[DATA_CRITICAL] = (window / 3) * 6;
2721 /* Transiting data messages,inclusive FIRST_FRAGM */
2722 l_ptr->queue_limit[DATA_LOW + 4] = 300;
2723 l_ptr->queue_limit[DATA_MEDIUM + 4] = 600;
2724 l_ptr->queue_limit[DATA_HIGH + 4] = 900;
2725 l_ptr->queue_limit[DATA_CRITICAL + 4] = 1200;
2726 l_ptr->queue_limit[CONN_MANAGER] = 1200;
2727 l_ptr->queue_limit[ROUTE_DISTRIBUTOR] = 1200;
2728 l_ptr->queue_limit[CHANGEOVER_PROTOCOL] = 2500;
2729 l_ptr->queue_limit[NAME_DISTRIBUTOR] = 3000;
2730 /* FRAGMENT and LAST_FRAGMENT packets */
2731 l_ptr->queue_limit[MSG_FRAGMENTER] = 4000;
2732}
2733
2734/**
2735 * link_find_link - locate link by name
2736 * @name - ptr to link name string
2737 * @node - ptr to area to be filled with ptr to associated node
2738 *
2739 * Caller must hold 'net_lock' to ensure node and bearer are not deleted;
2740 * this also prevents link deletion.
2741 *
2742 * Returns pointer to link (or 0 if invalid link name).
2743 */
2744
2745static struct link *link_find_link(const char *name, struct node **node)
2746{
2747 struct link_name link_name_parts;
2748 struct bearer *b_ptr;
2749 struct link *l_ptr;
2750
2751 if (!link_name_validate(name, &link_name_parts))
2752 return 0;
2753
2754 b_ptr = bearer_find_interface(link_name_parts.if_local);
2755 if (!b_ptr)
2756 return 0;
2757
2758 *node = node_find(link_name_parts.addr_peer);
2759 if (!*node)
2760 return 0;
2761
2762 l_ptr = (*node)->links[b_ptr->identity];
2763 if (!l_ptr || strcmp(l_ptr->name, name))
2764 return 0;
2765
2766 return l_ptr;
2767}
2768
2769struct sk_buff *link_cmd_config(const void *req_tlv_area, int req_tlv_space,
2770 u16 cmd)
2771{
2772 struct tipc_link_config *args;
2773 u32 new_value;
2774 struct link *l_ptr;
2775 struct node *node;
2776 int res;
2777
2778 if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_LINK_CONFIG))
2779 return cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
2780
2781 args = (struct tipc_link_config *)TLV_DATA(req_tlv_area);
2782 new_value = ntohl(args->value);
2783
2784 if (!strcmp(args->name, bc_link_name)) {
2785 if ((cmd == TIPC_CMD_SET_LINK_WINDOW) &&
2786 (bclink_set_queue_limits(new_value) == 0))
2787 return cfg_reply_none();
2788 return cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
2789 " (cannot change setting on broadcast link)");
2790 }
2791
2792 read_lock_bh(&net_lock);
2793 l_ptr = link_find_link(args->name, &node);
2794 if (!l_ptr) {
2795 read_unlock_bh(&net_lock);
2796 return cfg_reply_error_string("link not found");
2797 }
2798
2799 node_lock(node);
2800 res = -EINVAL;
2801 switch (cmd) {
2802 case TIPC_CMD_SET_LINK_TOL:
2803 if ((new_value >= TIPC_MIN_LINK_TOL) &&
2804 (new_value <= TIPC_MAX_LINK_TOL)) {
2805 link_set_supervision_props(l_ptr, new_value);
2806 link_send_proto_msg(l_ptr, STATE_MSG,
2807 0, 0, new_value, 0, 0);
2808 res = TIPC_OK;
2809 }
2810 break;
2811 case TIPC_CMD_SET_LINK_PRI:
2812 if (new_value < TIPC_NUM_LINK_PRI) {
2813 l_ptr->priority = new_value;
2814 link_send_proto_msg(l_ptr, STATE_MSG,
2815 0, 0, 0, new_value, 0);
2816 res = TIPC_OK;
2817 }
2818 break;
2819 case TIPC_CMD_SET_LINK_WINDOW:
2820 if ((new_value >= TIPC_MIN_LINK_WIN) &&
2821 (new_value <= TIPC_MAX_LINK_WIN)) {
2822 link_set_queue_limits(l_ptr, new_value);
2823 res = TIPC_OK;
2824 }
2825 break;
2826 }
2827 node_unlock(node);
2828
2829 read_unlock_bh(&net_lock);
2830 if (res)
2831 return cfg_reply_error_string("cannot change link setting");
2832
2833 return cfg_reply_none();
2834}
2835
2836/**
2837 * link_reset_statistics - reset link statistics
2838 * @l_ptr: pointer to link
2839 */
2840
2841static void link_reset_statistics(struct link *l_ptr)
2842{
2843 memset(&l_ptr->stats, 0, sizeof(l_ptr->stats));
2844 l_ptr->stats.sent_info = l_ptr->next_out_no;
2845 l_ptr->stats.recv_info = l_ptr->next_in_no;
2846}
2847
2848struct sk_buff *link_cmd_reset_stats(const void *req_tlv_area, int req_tlv_space)
2849{
2850 char *link_name;
2851 struct link *l_ptr;
2852 struct node *node;
2853
2854 if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_LINK_NAME))
2855 return cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
2856
2857 link_name = (char *)TLV_DATA(req_tlv_area);
2858 if (!strcmp(link_name, bc_link_name)) {
2859 if (bclink_reset_stats())
2860 return cfg_reply_error_string("link not found");
2861 return cfg_reply_none();
2862 }
2863
2864 read_lock_bh(&net_lock);
2865 l_ptr = link_find_link(link_name, &node);
2866 if (!l_ptr) {
2867 read_unlock_bh(&net_lock);
2868 return cfg_reply_error_string("link not found");
2869 }
2870
2871 node_lock(node);
2872 link_reset_statistics(l_ptr);
2873 node_unlock(node);
2874 read_unlock_bh(&net_lock);
2875 return cfg_reply_none();
2876}
2877
2878/**
2879 * percent - convert count to a percentage of total (rounding up or down)
2880 */
2881
2882static u32 percent(u32 count, u32 total)
2883{
2884 return (count * 100 + (total / 2)) / total;
2885}
2886
2887/**
2888 * link_stats - print link statistics
2889 * @name: link name
2890 * @buf: print buffer area
2891 * @buf_size: size of print buffer area
2892 *
2893 * Returns length of print buffer data string (or 0 if error)
2894 */
2895
2896static int link_stats(const char *name, char *buf, const u32 buf_size)
2897{
2898 struct print_buf pb;
2899 struct link *l_ptr;
2900 struct node *node;
2901 char *status;
2902 u32 profile_total = 0;
2903
2904 if (!strcmp(name, bc_link_name))
2905 return bclink_stats(buf, buf_size);
2906
2907 printbuf_init(&pb, buf, buf_size);
2908
2909 read_lock_bh(&net_lock);
2910 l_ptr = link_find_link(name, &node);
2911 if (!l_ptr) {
2912 read_unlock_bh(&net_lock);
2913 return 0;
2914 }
2915 node_lock(node);
2916
2917 if (link_is_active(l_ptr))
2918 status = "ACTIVE";
2919 else if (link_is_up(l_ptr))
2920 status = "STANDBY";
2921 else
2922 status = "DEFUNCT";
2923 tipc_printf(&pb, "Link <%s>\n"
2924 " %s MTU:%u Priority:%u Tolerance:%u ms"
2925 " Window:%u packets\n",
2926 l_ptr->name, status, link_max_pkt(l_ptr),
2927 l_ptr->priority, l_ptr->tolerance, l_ptr->queue_limit[0]);
2928 tipc_printf(&pb, " RX packets:%u fragments:%u/%u bundles:%u/%u\n",
2929 l_ptr->next_in_no - l_ptr->stats.recv_info,
2930 l_ptr->stats.recv_fragments,
2931 l_ptr->stats.recv_fragmented,
2932 l_ptr->stats.recv_bundles,
2933 l_ptr->stats.recv_bundled);
2934 tipc_printf(&pb, " TX packets:%u fragments:%u/%u bundles:%u/%u\n",
2935 l_ptr->next_out_no - l_ptr->stats.sent_info,
2936 l_ptr->stats.sent_fragments,
2937 l_ptr->stats.sent_fragmented,
2938 l_ptr->stats.sent_bundles,
2939 l_ptr->stats.sent_bundled);
2940 profile_total = l_ptr->stats.msg_length_counts;
2941 if (!profile_total)
2942 profile_total = 1;
2943 tipc_printf(&pb, " TX profile sample:%u packets average:%u octets\n"
2944 " 0-64:%u%% -256:%u%% -1024:%u%% -4096:%u%% "
2945 "-16354:%u%% -32768:%u%% -66000:%u%%\n",
2946 l_ptr->stats.msg_length_counts,
2947 l_ptr->stats.msg_lengths_total / profile_total,
2948 percent(l_ptr->stats.msg_length_profile[0], profile_total),
2949 percent(l_ptr->stats.msg_length_profile[1], profile_total),
2950 percent(l_ptr->stats.msg_length_profile[2], profile_total),
2951 percent(l_ptr->stats.msg_length_profile[3], profile_total),
2952 percent(l_ptr->stats.msg_length_profile[4], profile_total),
2953 percent(l_ptr->stats.msg_length_profile[5], profile_total),
2954 percent(l_ptr->stats.msg_length_profile[6], profile_total));
2955 tipc_printf(&pb, " RX states:%u probes:%u naks:%u defs:%u dups:%u\n",
2956 l_ptr->stats.recv_states,
2957 l_ptr->stats.recv_probes,
2958 l_ptr->stats.recv_nacks,
2959 l_ptr->stats.deferred_recv,
2960 l_ptr->stats.duplicates);
2961 tipc_printf(&pb, " TX states:%u probes:%u naks:%u acks:%u dups:%u\n",
2962 l_ptr->stats.sent_states,
2963 l_ptr->stats.sent_probes,
2964 l_ptr->stats.sent_nacks,
2965 l_ptr->stats.sent_acks,
2966 l_ptr->stats.retransmitted);
2967 tipc_printf(&pb, " Congestion bearer:%u link:%u Send queue max:%u avg:%u\n",
2968 l_ptr->stats.bearer_congs,
2969 l_ptr->stats.link_congs,
2970 l_ptr->stats.max_queue_sz,
2971 l_ptr->stats.queue_sz_counts
2972 ? (l_ptr->stats.accu_queue_sz / l_ptr->stats.queue_sz_counts)
2973 : 0);
2974
2975 node_unlock(node);
2976 read_unlock_bh(&net_lock);
2977 return printbuf_validate(&pb);
2978}
2979
2980#define MAX_LINK_STATS_INFO 2000
2981
2982struct sk_buff *link_cmd_show_stats(const void *req_tlv_area, int req_tlv_space)
2983{
2984 struct sk_buff *buf;
2985 struct tlv_desc *rep_tlv;
2986 int str_len;
2987
2988 if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_LINK_NAME))
2989 return cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
2990
2991 buf = cfg_reply_alloc(TLV_SPACE(MAX_LINK_STATS_INFO));
2992 if (!buf)
2993 return NULL;
2994
2995 rep_tlv = (struct tlv_desc *)buf->data;
2996
2997 str_len = link_stats((char *)TLV_DATA(req_tlv_area),
2998 (char *)TLV_DATA(rep_tlv), MAX_LINK_STATS_INFO);
2999 if (!str_len) {
3000 buf_discard(buf);
3001 return cfg_reply_error_string("link not found");
3002 }
3003
3004 skb_put(buf, TLV_SPACE(str_len));
3005 TLV_SET(rep_tlv, TIPC_TLV_ULTRA_STRING, NULL, str_len);
3006
3007 return buf;
3008}
3009
3010#if 0
3011int link_control(const char *name, u32 op, u32 val)
3012{
3013 int res = -EINVAL;
3014 struct link *l_ptr;
3015 u32 bearer_id;
3016 struct node * node;
3017 u32 a;
3018
3019 a = link_name2addr(name, &bearer_id);
3020 read_lock_bh(&net_lock);
3021 node = node_find(a);
3022 if (node) {
3023 node_lock(node);
3024 l_ptr = node->links[bearer_id];
3025 if (l_ptr) {
3026 if (op == TIPC_REMOVE_LINK) {
3027 struct bearer *b_ptr = l_ptr->b_ptr;
3028 spin_lock_bh(&b_ptr->publ.lock);
3029 link_delete(l_ptr);
3030 spin_unlock_bh(&b_ptr->publ.lock);
3031 }
3032 if (op == TIPC_CMD_BLOCK_LINK) {
3033 link_reset(l_ptr);
3034 l_ptr->blocked = 1;
3035 }
3036 if (op == TIPC_CMD_UNBLOCK_LINK) {
3037 l_ptr->blocked = 0;
3038 }
3039 res = TIPC_OK;
3040 }
3041 node_unlock(node);
3042 }
3043 read_unlock_bh(&net_lock);
3044 return res;
3045}
3046#endif
3047
3048/**
3049 * link_get_max_pkt - get maximum packet size to use when sending to destination
3050 * @dest: network address of destination node
3051 * @selector: used to select from set of active links
3052 *
3053 * If no active link can be found, uses default maximum packet size.
3054 */
3055
3056u32 link_get_max_pkt(u32 dest, u32 selector)
3057{
3058 struct node *n_ptr;
3059 struct link *l_ptr;
3060 u32 res = MAX_PKT_DEFAULT;
3061
3062 if (dest == tipc_own_addr)
3063 return MAX_MSG_SIZE;
3064
3065 read_lock_bh(&net_lock);
3066 n_ptr = node_select(dest, selector);
3067 if (n_ptr) {
3068 node_lock(n_ptr);
3069 l_ptr = n_ptr->active_links[selector & 1];
3070 if (l_ptr)
3071 res = link_max_pkt(l_ptr);
3072 node_unlock(n_ptr);
3073 }
3074 read_unlock_bh(&net_lock);
3075 return res;
3076}
3077
3078#if 0
3079static void link_dump_rec_queue(struct link *l_ptr)
3080{
3081 struct sk_buff *crs;
3082
3083 if (!l_ptr->oldest_deferred_in) {
3084 info("Reception queue empty\n");
3085 return;
3086 }
3087 info("Contents of Reception queue:\n");
3088 crs = l_ptr->oldest_deferred_in;
3089 while (crs) {
3090 if (crs->data == (void *)0x0000a3a3) {
3091 info("buffer %x invalid\n", crs);
3092 return;
3093 }
3094 msg_dbg(buf_msg(crs), "In rec queue: \n");
3095 crs = crs->next;
3096 }
3097}
3098#endif
3099
3100static void link_dump_send_queue(struct link *l_ptr)
3101{
3102 if (l_ptr->next_out) {
3103 info("\nContents of unsent queue:\n");
3104 dbg_print_buf_chain(l_ptr->next_out);
3105 }
3106 info("\nContents of send queue:\n");
3107 if (l_ptr->first_out) {
3108 dbg_print_buf_chain(l_ptr->first_out);
3109 }
3110 info("Empty send queue\n");
3111}
3112
3113static void link_print(struct link *l_ptr, struct print_buf *buf,
3114 const char *str)
3115{
3116 tipc_printf(buf, str);
3117 if (link_reset_reset(l_ptr) || link_reset_unknown(l_ptr))
3118 return;
3119 tipc_printf(buf, "Link %x<%s>:",
3120 l_ptr->addr, l_ptr->b_ptr->publ.name);
3121 tipc_printf(buf, ": NXO(%u):", mod(l_ptr->next_out_no));
3122 tipc_printf(buf, "NXI(%u):", mod(l_ptr->next_in_no));
3123 tipc_printf(buf, "SQUE");
3124 if (l_ptr->first_out) {
3125 tipc_printf(buf, "[%u..", msg_seqno(buf_msg(l_ptr->first_out)));
3126 if (l_ptr->next_out)
3127 tipc_printf(buf, "%u..",
3128 msg_seqno(buf_msg(l_ptr->next_out)));
3129 tipc_printf(buf, "%u]",
3130 msg_seqno(buf_msg
3131 (l_ptr->last_out)), l_ptr->out_queue_size);
3132 if ((mod(msg_seqno(buf_msg(l_ptr->last_out)) -
3133 msg_seqno(buf_msg(l_ptr->first_out)))
3134 != (l_ptr->out_queue_size - 1))
3135 || (l_ptr->last_out->next != 0)) {
3136 tipc_printf(buf, "\nSend queue inconsistency\n");
3137 tipc_printf(buf, "first_out= %x ", l_ptr->first_out);
3138 tipc_printf(buf, "next_out= %x ", l_ptr->next_out);
3139 tipc_printf(buf, "last_out= %x ", l_ptr->last_out);
3140 link_dump_send_queue(l_ptr);
3141 }
3142 } else
3143 tipc_printf(buf, "[]");
3144 tipc_printf(buf, "SQSIZ(%u)", l_ptr->out_queue_size);
3145 if (l_ptr->oldest_deferred_in) {
3146 u32 o = msg_seqno(buf_msg(l_ptr->oldest_deferred_in));
3147 u32 n = msg_seqno(buf_msg(l_ptr->newest_deferred_in));
3148 tipc_printf(buf, ":RQUE[%u..%u]", o, n);
3149 if (l_ptr->deferred_inqueue_sz != mod((n + 1) - o)) {
3150 tipc_printf(buf, ":RQSIZ(%u)",
3151 l_ptr->deferred_inqueue_sz);
3152 }
3153 }
3154 if (link_working_unknown(l_ptr))
3155 tipc_printf(buf, ":WU");
3156 if (link_reset_reset(l_ptr))
3157 tipc_printf(buf, ":RR");
3158 if (link_reset_unknown(l_ptr))
3159 tipc_printf(buf, ":RU");
3160 if (link_working_working(l_ptr))
3161 tipc_printf(buf, ":WW");
3162 tipc_printf(buf, "\n");
3163}
3164
diff --git a/net/tipc/link.h b/net/tipc/link.h
new file mode 100644
index 000000000000..e7db3476d84e
--- /dev/null
+++ b/net/tipc/link.h
@@ -0,0 +1,293 @@
1/*
2 * net/tipc/link.h: Include file for TIPC link code
3 *
4 * Copyright (c) 2003-2005, Ericsson Research Canada
5 * Copyright (c) 2004-2005, Wind River Systems
6 * Copyright (c) 2005-2006, Ericsson AB
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions are met:
11 *
12 * Redistributions of source code must retain the above copyright notice, this
13 * list of conditions and the following disclaimer.
14 * Redistributions in binary form must reproduce the above copyright notice,
15 * this list of conditions and the following disclaimer in the documentation
16 * and/or other materials provided with the distribution.
17 * Neither the names of the copyright holders nor the names of its
18 * contributors may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 */
33
34#ifndef _TIPC_LINK_H
35#define _TIPC_LINK_H
36
37#include "dbg.h"
38#include "msg.h"
39#include "bearer.h"
40#include "node.h"
41
42#define PUSH_FAILED 1
43#define PUSH_FINISHED 2
44
45/*
46 * Link states
47 */
48
49#define WORKING_WORKING 560810u
50#define WORKING_UNKNOWN 560811u
51#define RESET_UNKNOWN 560812u
52#define RESET_RESET 560813u
53
54/*
55 * Starting value for maximum packet size negotiation on unicast links
56 * (unless bearer MTU is less)
57 */
58
59#define MAX_PKT_DEFAULT 1500
60
61/**
62 * struct link - TIPC link data structure
63 * @addr: network address of link's peer node
64 * @name: link name character string
65 * @media_addr: media address to use when sending messages over link
66 * @timer: link timer
67 * @owner: pointer to peer node
68 * @link_list: adjacent links in bearer's list of links
69 * @started: indicates if link has been started
70 * @checkpoint: reference point for triggering link continuity checking
71 * @peer_session: link session # being used by peer end of link
72 * @peer_bearer_id: bearer id used by link's peer endpoint
73 * @b_ptr: pointer to bearer used by link
74 * @tolerance: minimum link continuity loss needed to reset link [in ms]
75 * @continuity_interval: link continuity testing interval [in ms]
76 * @abort_limit: # of unacknowledged continuity probes needed to reset link
77 * @state: current state of link FSM
78 * @blocked: indicates if link has been administratively blocked
79 * @fsm_msg_cnt: # of protocol messages link FSM has sent in current state
80 * @proto_msg: template for control messages generated by link
81 * @pmsg: convenience pointer to "proto_msg" field
82 * @priority: current link priority
83 * @queue_limit: outbound message queue congestion thresholds (indexed by user)
84 * @exp_msg_count: # of tunnelled messages expected during link changeover
85 * @reset_checkpoint: seq # of last acknowledged message at time of link reset
86 * @max_pkt: current maximum packet size for this link
87 * @max_pkt_target: desired maximum packet size for this link
88 * @max_pkt_probes: # of probes based on current (max_pkt, max_pkt_target)
89 * @out_queue_size: # of messages in outbound message queue
90 * @first_out: ptr to first outbound message in queue
91 * @last_out: ptr to last outbound message in queue
92 * @next_out_no: next sequence number to use for outbound messages
93 * @last_retransmitted: sequence number of most recently retransmitted message
94 * @stale_count: # of identical retransmit requests made by peer
95 * @next_in_no: next sequence number to expect for inbound messages
96 * @deferred_inqueue_sz: # of messages in inbound message queue
97 * @oldest_deferred_in: ptr to first inbound message in queue
98 * @newest_deferred_in: ptr to last inbound message in queue
99 * @unacked_window: # of inbound messages rx'd without ack'ing back to peer
100 * @proto_msg_queue: ptr to (single) outbound control message
101 * @retransm_queue_size: number of messages to retransmit
102 * @retransm_queue_head: sequence number of first message to retransmit
103 * @next_out: ptr to first unsent outbound message in queue
104 * @waiting_ports: linked list of ports waiting for link congestion to abate
105 * @long_msg_seq_no: next identifier to use for outbound fragmented messages
106 * @defragm_buf: list of partially reassembled inbound message fragments
107 * @stats: collects statistics regarding link activity
108 * @print_buf: print buffer used to log link activity
109 */
110
111struct link {
112 u32 addr;
113 char name[TIPC_MAX_LINK_NAME];
114 struct tipc_media_addr media_addr;
115 struct timer_list timer;
116 struct node *owner;
117 struct list_head link_list;
118
119 /* Management and link supervision data */
120 int started;
121 u32 checkpoint;
122 u32 peer_session;
123 u32 peer_bearer_id;
124 struct bearer *b_ptr;
125 u32 tolerance;
126 u32 continuity_interval;
127 u32 abort_limit;
128 int state;
129 int blocked;
130 u32 fsm_msg_cnt;
131 struct {
132 unchar hdr[INT_H_SIZE];
133 unchar body[TIPC_MAX_IF_NAME];
134 } proto_msg;
135 struct tipc_msg *pmsg;
136 u32 priority;
137 u32 queue_limit[15]; /* queue_limit[0]==window limit */
138
139 /* Changeover */
140 u32 exp_msg_count;
141 u32 reset_checkpoint;
142
143 /* Max packet negotiation */
144 u32 max_pkt;
145 u32 max_pkt_target;
146 u32 max_pkt_probes;
147
148 /* Sending */
149 u32 out_queue_size;
150 struct sk_buff *first_out;
151 struct sk_buff *last_out;
152 u32 next_out_no;
153 u32 last_retransmitted;
154 u32 stale_count;
155
156 /* Reception */
157 u32 next_in_no;
158 u32 deferred_inqueue_sz;
159 struct sk_buff *oldest_deferred_in;
160 struct sk_buff *newest_deferred_in;
161 u32 unacked_window;
162
163 /* Congestion handling */
164 struct sk_buff *proto_msg_queue;
165 u32 retransm_queue_size;
166 u32 retransm_queue_head;
167 struct sk_buff *next_out;
168 struct list_head waiting_ports;
169
170 /* Fragmentation/defragmentation */
171 u32 long_msg_seq_no;
172 struct sk_buff *defragm_buf;
173
174 /* Statistics */
175 struct {
176 u32 sent_info; /* used in counting # sent packets */
177 u32 recv_info; /* used in counting # recv'd packets */
178 u32 sent_states;
179 u32 recv_states;
180 u32 sent_probes;
181 u32 recv_probes;
182 u32 sent_nacks;
183 u32 recv_nacks;
184 u32 sent_acks;
185 u32 sent_bundled;
186 u32 sent_bundles;
187 u32 recv_bundled;
188 u32 recv_bundles;
189 u32 retransmitted;
190 u32 sent_fragmented;
191 u32 sent_fragments;
192 u32 recv_fragmented;
193 u32 recv_fragments;
194 u32 link_congs; /* # port sends blocked by congestion */
195 u32 bearer_congs;
196 u32 deferred_recv;
197 u32 duplicates;
198
199 /* for statistical profiling of send queue size */
200
201 u32 max_queue_sz;
202 u32 accu_queue_sz;
203 u32 queue_sz_counts;
204
205 /* for statistical profiling of message lengths */
206
207 u32 msg_length_counts;
208 u32 msg_lengths_total;
209 u32 msg_length_profile[7];
210#if 0
211 u32 sent_tunneled;
212 u32 recv_tunneled;
213#endif
214 } stats;
215
216 struct print_buf print_buf;
217};
218
219struct port;
220
221struct link *link_create(struct bearer *b_ptr, const u32 peer,
222 const struct tipc_media_addr *media_addr);
223void link_delete(struct link *l_ptr);
224void link_changeover(struct link *l_ptr);
225void link_send_duplicate(struct link *l_ptr, struct link *dest);
226void link_reset_fragments(struct link *l_ptr);
227int link_is_up(struct link *l_ptr);
228int link_is_active(struct link *l_ptr);
229void link_start(struct link *l_ptr);
230u32 link_push_packet(struct link *l_ptr);
231void link_stop(struct link *l_ptr);
232struct sk_buff *link_cmd_config(const void *req_tlv_area, int req_tlv_space, u16 cmd);
233struct sk_buff *link_cmd_show_stats(const void *req_tlv_area, int req_tlv_space);
234struct sk_buff *link_cmd_reset_stats(const void *req_tlv_area, int req_tlv_space);
235void link_reset(struct link *l_ptr);
236int link_send(struct sk_buff *buf, u32 dest, u32 selector);
237int link_send_buf(struct link *l_ptr, struct sk_buff *buf);
238u32 link_get_max_pkt(u32 dest,u32 selector);
239int link_send_sections_fast(struct port* sender,
240 struct iovec const *msg_sect,
241 const u32 num_sect,
242 u32 destnode);
243
244int link_send_long_buf(struct link *l_ptr, struct sk_buff *buf);
245void link_tunnel(struct link *l_ptr, struct tipc_msg *tnl_hdr,
246 struct tipc_msg *msg, u32 selector);
247void link_recv_bundle(struct sk_buff *buf);
248int link_recv_fragment(struct sk_buff **pending,
249 struct sk_buff **fb,
250 struct tipc_msg **msg);
251void link_send_proto_msg(struct link *l_ptr, u32 msg_typ, int prob, u32 gap,
252 u32 tolerance, u32 priority, u32 acked_mtu);
253void link_push_queue(struct link *l_ptr);
254u32 link_defer_pkt(struct sk_buff **head, struct sk_buff **tail,
255 struct sk_buff *buf);
256void link_wakeup_ports(struct link *l_ptr, int all);
257void link_set_queue_limits(struct link *l_ptr, u32 window);
258void link_retransmit(struct link *l_ptr, struct sk_buff *start, u32 retransmits);
259
260/*
261 * Link sequence number manipulation routines (uses modulo 2**16 arithmetic)
262 */
263
264static inline u32 mod(u32 x)
265{
266 return x & 0xffffu;
267}
268
269static inline int between(u32 lower, u32 upper, u32 n)
270{
271 if ((lower < n) && (n < upper))
272 return 1;
273 if ((upper < lower) && ((n > lower) || (n < upper)))
274 return 1;
275 return 0;
276}
277
278static inline int less_eq(u32 left, u32 right)
279{
280 return (mod(right - left) < 32768u);
281}
282
283static inline int less(u32 left, u32 right)
284{
285 return (less_eq(left, right) && (mod(right) != mod(left)));
286}
287
288static inline u32 lesser(u32 left, u32 right)
289{
290 return less_eq(left, right) ? left : right;
291}
292
293#endif
diff --git a/net/tipc/msg.c b/net/tipc/msg.c
new file mode 100644
index 000000000000..c6e90efd59f2
--- /dev/null
+++ b/net/tipc/msg.c
@@ -0,0 +1,331 @@
1/*
2 * net/tipc/msg.c: TIPC message header routines
3 *
4 * Copyright (c) 2003-2005, Ericsson Research Canada
5 * Copyright (c) 2005, Wind River Systems
6 * Copyright (c) 2005-2006, Ericsson AB
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions are met:
11 *
12 * Redistributions of source code must retain the above copyright notice, this
13 * list of conditions and the following disclaimer.
14 * Redistributions in binary form must reproduce the above copyright notice,
15 * this list of conditions and the following disclaimer in the documentation
16 * and/or other materials provided with the distribution.
17 * Neither the names of the copyright holders nor the names of its
18 * contributors may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 */
33
34#include "core.h"
35#include "addr.h"
36#include "dbg.h"
37#include "msg.h"
38#include "bearer.h"
39
40
41void msg_set_media_addr(struct tipc_msg *m, struct tipc_media_addr *a)
42{
43 memcpy(&((int *)m)[5], a, sizeof(*a));
44}
45
46void msg_get_media_addr(struct tipc_msg *m, struct tipc_media_addr *a)
47{
48 memcpy(a, &((int*)m)[5], sizeof(*a));
49}
50
51
52void msg_print(struct print_buf *buf, struct tipc_msg *msg, const char *str)
53{
54 u32 usr = msg_user(msg);
55 tipc_printf(buf, str);
56
57 switch (usr) {
58 case MSG_BUNDLER:
59 tipc_printf(buf, "BNDL::");
60 tipc_printf(buf, "MSGS(%u):", msg_msgcnt(msg));
61 break;
62 case BCAST_PROTOCOL:
63 tipc_printf(buf, "BCASTP::");
64 break;
65 case MSG_FRAGMENTER:
66 tipc_printf(buf, "FRAGM::");
67 switch (msg_type(msg)) {
68 case FIRST_FRAGMENT:
69 tipc_printf(buf, "FIRST:");
70 break;
71 case FRAGMENT:
72 tipc_printf(buf, "BODY:");
73 break;
74 case LAST_FRAGMENT:
75 tipc_printf(buf, "LAST:");
76 break;
77 default:
78 tipc_printf(buf, "UNKNOWN:%x",msg_type(msg));
79
80 }
81 tipc_printf(buf, "NO(%u/%u):",msg_long_msgno(msg),
82 msg_fragm_no(msg));
83 break;
84 case DATA_LOW:
85 case DATA_MEDIUM:
86 case DATA_HIGH:
87 case DATA_CRITICAL:
88 tipc_printf(buf, "DAT%u:", msg_user(msg));
89 if (msg_short(msg)) {
90 tipc_printf(buf, "CON:");
91 break;
92 }
93 switch (msg_type(msg)) {
94 case TIPC_CONN_MSG:
95 tipc_printf(buf, "CON:");
96 break;
97 case TIPC_MCAST_MSG:
98 tipc_printf(buf, "MCST:");
99 break;
100 case TIPC_NAMED_MSG:
101 tipc_printf(buf, "NAM:");
102 break;
103 case TIPC_DIRECT_MSG:
104 tipc_printf(buf, "DIR:");
105 break;
106 default:
107 tipc_printf(buf, "UNKNOWN TYPE %u",msg_type(msg));
108 }
109 if (msg_routed(msg) && !msg_non_seq(msg))
110 tipc_printf(buf, "ROUT:");
111 if (msg_reroute_cnt(msg))
112 tipc_printf(buf, "REROUTED(%u):",
113 msg_reroute_cnt(msg));
114 break;
115 case NAME_DISTRIBUTOR:
116 tipc_printf(buf, "NMD::");
117 switch (msg_type(msg)) {
118 case PUBLICATION:
119 tipc_printf(buf, "PUBL(%u):", (msg_size(msg) - msg_hdr_sz(msg)) / 20); /* Items */
120 break;
121 case WITHDRAWAL:
122 tipc_printf(buf, "WDRW:");
123 break;
124 default:
125 tipc_printf(buf, "UNKNOWN:%x",msg_type(msg));
126 }
127 if (msg_routed(msg))
128 tipc_printf(buf, "ROUT:");
129 if (msg_reroute_cnt(msg))
130 tipc_printf(buf, "REROUTED(%u):",
131 msg_reroute_cnt(msg));
132 break;
133 case CONN_MANAGER:
134 tipc_printf(buf, "CONN_MNG:");
135 switch (msg_type(msg)) {
136 case CONN_PROBE:
137 tipc_printf(buf, "PROBE:");
138 break;
139 case CONN_PROBE_REPLY:
140 tipc_printf(buf, "PROBE_REPLY:");
141 break;
142 case CONN_ACK:
143 tipc_printf(buf, "CONN_ACK:");
144 tipc_printf(buf, "ACK(%u):",msg_msgcnt(msg));
145 break;
146 default:
147 tipc_printf(buf, "UNKNOWN TYPE:%x",msg_type(msg));
148 }
149 if (msg_routed(msg))
150 tipc_printf(buf, "ROUT:");
151 if (msg_reroute_cnt(msg))
152 tipc_printf(buf, "REROUTED(%u):",msg_reroute_cnt(msg));
153 break;
154 case LINK_PROTOCOL:
155 tipc_printf(buf, "PROT:TIM(%u):",msg_timestamp(msg));
156 switch (msg_type(msg)) {
157 case STATE_MSG:
158 tipc_printf(buf, "STATE:");
159 tipc_printf(buf, "%s:",msg_probe(msg) ? "PRB" :"");
160 tipc_printf(buf, "NXS(%u):",msg_next_sent(msg));
161 tipc_printf(buf, "GAP(%u):",msg_seq_gap(msg));
162 tipc_printf(buf, "LSTBC(%u):",msg_last_bcast(msg));
163 break;
164 case RESET_MSG:
165 tipc_printf(buf, "RESET:");
166 if (msg_size(msg) != msg_hdr_sz(msg))
167 tipc_printf(buf, "BEAR:%s:",msg_data(msg));
168 break;
169 case ACTIVATE_MSG:
170 tipc_printf(buf, "ACTIVATE:");
171 break;
172 default:
173 tipc_printf(buf, "UNKNOWN TYPE:%x",msg_type(msg));
174 }
175 tipc_printf(buf, "PLANE(%c):",msg_net_plane(msg));
176 tipc_printf(buf, "SESS(%u):",msg_session(msg));
177 break;
178 case CHANGEOVER_PROTOCOL:
179 tipc_printf(buf, "TUNL:");
180 switch (msg_type(msg)) {
181 case DUPLICATE_MSG:
182 tipc_printf(buf, "DUPL:");
183 break;
184 case ORIGINAL_MSG:
185 tipc_printf(buf, "ORIG:");
186 tipc_printf(buf, "EXP(%u)",msg_msgcnt(msg));
187 break;
188 default:
189 tipc_printf(buf, "UNKNOWN TYPE:%x",msg_type(msg));
190 }
191 break;
192 case ROUTE_DISTRIBUTOR:
193 tipc_printf(buf, "ROUTING_MNG:");
194 switch (msg_type(msg)) {
195 case EXT_ROUTING_TABLE:
196 tipc_printf(buf, "EXT_TBL:");
197 tipc_printf(buf, "TO:%x:",msg_remote_node(msg));
198 break;
199 case LOCAL_ROUTING_TABLE:
200 tipc_printf(buf, "LOCAL_TBL:");
201 tipc_printf(buf, "TO:%x:",msg_remote_node(msg));
202 break;
203 case SLAVE_ROUTING_TABLE:
204 tipc_printf(buf, "DP_TBL:");
205 tipc_printf(buf, "TO:%x:",msg_remote_node(msg));
206 break;
207 case ROUTE_ADDITION:
208 tipc_printf(buf, "ADD:");
209 tipc_printf(buf, "TO:%x:",msg_remote_node(msg));
210 break;
211 case ROUTE_REMOVAL:
212 tipc_printf(buf, "REMOVE:");
213 tipc_printf(buf, "TO:%x:",msg_remote_node(msg));
214 break;
215 default:
216 tipc_printf(buf, "UNKNOWN TYPE:%x",msg_type(msg));
217 }
218 break;
219 case LINK_CONFIG:
220 tipc_printf(buf, "CFG:");
221 switch (msg_type(msg)) {
222 case DSC_REQ_MSG:
223 tipc_printf(buf, "DSC_REQ:");
224 break;
225 case DSC_RESP_MSG:
226 tipc_printf(buf, "DSC_RESP:");
227 break;
228 default:
229 tipc_printf(buf, "UNKNOWN TYPE:%x:",msg_type(msg));
230 break;
231 }
232 break;
233 default:
234 tipc_printf(buf, "UNKNOWN USER:");
235 }
236
237 switch (usr) {
238 case CONN_MANAGER:
239 case NAME_DISTRIBUTOR:
240 case DATA_LOW:
241 case DATA_MEDIUM:
242 case DATA_HIGH:
243 case DATA_CRITICAL:
244 if (msg_short(msg))
245 break; /* No error */
246 switch (msg_errcode(msg)) {
247 case TIPC_OK:
248 break;
249 case TIPC_ERR_NO_NAME:
250 tipc_printf(buf, "NO_NAME:");
251 break;
252 case TIPC_ERR_NO_PORT:
253 tipc_printf(buf, "NO_PORT:");
254 break;
255 case TIPC_ERR_NO_NODE:
256 tipc_printf(buf, "NO_PROC:");
257 break;
258 case TIPC_ERR_OVERLOAD:
259 tipc_printf(buf, "OVERLOAD:");
260 break;
261 case TIPC_CONN_SHUTDOWN:
262 tipc_printf(buf, "SHUTDOWN:");
263 break;
264 default:
265 tipc_printf(buf, "UNKNOWN ERROR(%x):",
266 msg_errcode(msg));
267 }
268 default:{}
269 }
270
271 tipc_printf(buf, "HZ(%u):", msg_hdr_sz(msg));
272 tipc_printf(buf, "SZ(%u):", msg_size(msg));
273 tipc_printf(buf, "SQNO(%u):", msg_seqno(msg));
274
275 if (msg_non_seq(msg))
276 tipc_printf(buf, "NOSEQ:");
277 else {
278 tipc_printf(buf, "ACK(%u):", msg_ack(msg));
279 }
280 tipc_printf(buf, "BACK(%u):", msg_bcast_ack(msg));
281 tipc_printf(buf, "PRND(%x)", msg_prevnode(msg));
282
283 if (msg_isdata(msg)) {
284 if (msg_named(msg)) {
285 tipc_printf(buf, "NTYP(%u):", msg_nametype(msg));
286 tipc_printf(buf, "NINST(%u)", msg_nameinst(msg));
287 }
288 }
289
290 if ((usr != LINK_PROTOCOL) && (usr != LINK_CONFIG) &&
291 (usr != MSG_BUNDLER)) {
292 if (!msg_short(msg)) {
293 tipc_printf(buf, ":ORIG(%x:%u):",
294 msg_orignode(msg), msg_origport(msg));
295 tipc_printf(buf, ":DEST(%x:%u):",
296 msg_destnode(msg), msg_destport(msg));
297 } else {
298 tipc_printf(buf, ":OPRT(%u):", msg_origport(msg));
299 tipc_printf(buf, ":DPRT(%u):", msg_destport(msg));
300 }
301 if (msg_routed(msg) && !msg_non_seq(msg))
302 tipc_printf(buf, ":TSEQN(%u)", msg_transp_seqno(msg));
303 }
304 if (msg_user(msg) == NAME_DISTRIBUTOR) {
305 tipc_printf(buf, ":ONOD(%x):", msg_orignode(msg));
306 tipc_printf(buf, ":DNOD(%x):", msg_destnode(msg));
307 if (msg_routed(msg)) {
308 tipc_printf(buf, ":CSEQN(%u)", msg_transp_seqno(msg));
309 }
310 }
311
312 if (msg_user(msg) == LINK_CONFIG) {
313 u32* raw = (u32*)msg;
314 struct tipc_media_addr* orig = (struct tipc_media_addr*)&raw[5];
315 tipc_printf(buf, ":REQL(%u):", msg_req_links(msg));
316 tipc_printf(buf, ":DDOM(%x):", msg_dest_domain(msg));
317 tipc_printf(buf, ":NETID(%u):", msg_bc_netid(msg));
318 media_addr_printf(buf, orig);
319 }
320 if (msg_user(msg) == BCAST_PROTOCOL) {
321 tipc_printf(buf, "BCNACK:AFTER(%u):", msg_bcgap_after(msg));
322 tipc_printf(buf, "TO(%u):", msg_bcgap_to(msg));
323 }
324 tipc_printf(buf, "\n");
325 if ((usr == CHANGEOVER_PROTOCOL) && (msg_msgcnt(msg))) {
326 msg_print(buf,msg_get_wrapped(msg)," /");
327 }
328 if ((usr == MSG_FRAGMENTER) && (msg_type(msg) == FIRST_FRAGMENT)) {
329 msg_print(buf,msg_get_wrapped(msg)," /");
330 }
331}
diff --git a/net/tipc/msg.h b/net/tipc/msg.h
new file mode 100644
index 000000000000..3dcd23f51883
--- /dev/null
+++ b/net/tipc/msg.h
@@ -0,0 +1,815 @@
1/*
2 * net/tipc/msg.h: Include file for TIPC message header routines
3 *
4 * Copyright (c) 2003-2005, Ericsson Research Canada
5 * Copyright (c) 2005, Wind River Systems
6 * Copyright (c) 2005-2006, Ericsson AB
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions are met:
11 *
12 * Redistributions of source code must retain the above copyright notice, this
13 * list of conditions and the following disclaimer.
14 * Redistributions in binary form must reproduce the above copyright notice,
15 * this list of conditions and the following disclaimer in the documentation
16 * and/or other materials provided with the distribution.
17 * Neither the names of the copyright holders nor the names of its
18 * contributors may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 */
33
34#ifndef _TIPC_MSG_H
35#define _TIPC_MSG_H
36
37#include <net/tipc/tipc_msg.h>
38
39#define TIPC_VERSION 2
40#define DATA_LOW TIPC_LOW_IMPORTANCE
41#define DATA_MEDIUM TIPC_MEDIUM_IMPORTANCE
42#define DATA_HIGH TIPC_HIGH_IMPORTANCE
43#define DATA_CRITICAL TIPC_CRITICAL_IMPORTANCE
44#define SHORT_H_SIZE 24 /* Connected,in cluster */
45#define DIR_MSG_H_SIZE 32 /* Directly addressed messages */
46#define CONN_MSG_H_SIZE 36 /* Routed connected msgs*/
47#define LONG_H_SIZE 40 /* Named Messages */
48#define MCAST_H_SIZE 44 /* Multicast messages */
49#define MAX_H_SIZE 60 /* Inclusive full options */
50#define MAX_MSG_SIZE (MAX_H_SIZE + TIPC_MAX_USER_MSG_SIZE)
51#define LINK_CONFIG 13
52
53
54/*
55 TIPC user data message header format, version 2
56
57 - Fundamental definitions available to privileged TIPC users
58 are located in tipc_msg.h.
59 - Remaining definitions available to TIPC internal users appear below.
60*/
61
62
63static inline void msg_set_word(struct tipc_msg *m, u32 w, u32 val)
64{
65 m->hdr[w] = htonl(val);
66}
67
68static inline void msg_set_bits(struct tipc_msg *m, u32 w,
69 u32 pos, u32 mask, u32 val)
70{
71 u32 word = msg_word(m,w) & ~(mask << pos);
72 msg_set_word(m, w, (word |= (val << pos)));
73}
74
75/*
76 * Word 0
77 */
78
79static inline u32 msg_version(struct tipc_msg *m)
80{
81 return msg_bits(m, 0, 29, 7);
82}
83
84static inline void msg_set_version(struct tipc_msg *m)
85{
86 msg_set_bits(m, 0, 29, 0xf, TIPC_VERSION);
87}
88
89static inline u32 msg_user(struct tipc_msg *m)
90{
91 return msg_bits(m, 0, 25, 0xf);
92}
93
94static inline u32 msg_isdata(struct tipc_msg *m)
95{
96 return (msg_user(m) <= DATA_CRITICAL);
97}
98
99static inline void msg_set_user(struct tipc_msg *m, u32 n)
100{
101 msg_set_bits(m, 0, 25, 0xf, n);
102}
103
104static inline void msg_set_importance(struct tipc_msg *m, u32 i)
105{
106 msg_set_user(m, i);
107}
108
109static inline void msg_set_hdr_sz(struct tipc_msg *m,u32 n)
110{
111 msg_set_bits(m, 0, 21, 0xf, n>>2);
112}
113
114static inline int msg_non_seq(struct tipc_msg *m)
115{
116 return msg_bits(m, 0, 20, 1);
117}
118
119static inline void msg_set_non_seq(struct tipc_msg *m)
120{
121 msg_set_bits(m, 0, 20, 1, 1);
122}
123
124static inline int msg_dest_droppable(struct tipc_msg *m)
125{
126 return msg_bits(m, 0, 19, 1);
127}
128
129static inline void msg_set_dest_droppable(struct tipc_msg *m, u32 d)
130{
131 msg_set_bits(m, 0, 19, 1, d);
132}
133
134static inline int msg_src_droppable(struct tipc_msg *m)
135{
136 return msg_bits(m, 0, 18, 1);
137}
138
139static inline void msg_set_src_droppable(struct tipc_msg *m, u32 d)
140{
141 msg_set_bits(m, 0, 18, 1, d);
142}
143
144static inline void msg_set_size(struct tipc_msg *m, u32 sz)
145{
146 m->hdr[0] = htonl((msg_word(m, 0) & ~0x1ffff) | sz);
147}
148
149
150/*
151 * Word 1
152 */
153
154static inline void msg_set_type(struct tipc_msg *m, u32 n)
155{
156 msg_set_bits(m, 1, 29, 0x7, n);
157}
158
159static inline void msg_set_errcode(struct tipc_msg *m, u32 err)
160{
161 msg_set_bits(m, 1, 25, 0xf, err);
162}
163
164static inline u32 msg_reroute_cnt(struct tipc_msg *m)
165{
166 return msg_bits(m, 1, 21, 0xf);
167}
168
169static inline void msg_incr_reroute_cnt(struct tipc_msg *m)
170{
171 msg_set_bits(m, 1, 21, 0xf, msg_reroute_cnt(m) + 1);
172}
173
174static inline void msg_reset_reroute_cnt(struct tipc_msg *m)
175{
176 msg_set_bits(m, 1, 21, 0xf, 0);
177}
178
179static inline u32 msg_lookup_scope(struct tipc_msg *m)
180{
181 return msg_bits(m, 1, 19, 0x3);
182}
183
184static inline void msg_set_lookup_scope(struct tipc_msg *m, u32 n)
185{
186 msg_set_bits(m, 1, 19, 0x3, n);
187}
188
189static inline void msg_set_options(struct tipc_msg *m, const char *opt, u32 sz)
190{
191 u32 hsz = msg_hdr_sz(m);
192 char *to = (char *)&m->hdr[hsz/4];
193
194 if ((hsz < DIR_MSG_H_SIZE) || ((hsz + sz) > MAX_H_SIZE))
195 return;
196 msg_set_bits(m, 1, 16, 0x7, (hsz - 28)/4);
197 msg_set_hdr_sz(m, hsz + sz);
198 memcpy(to, opt, sz);
199}
200
201static inline u32 msg_bcast_ack(struct tipc_msg *m)
202{
203 return msg_bits(m, 1, 0, 0xffff);
204}
205
206static inline void msg_set_bcast_ack(struct tipc_msg *m, u32 n)
207{
208 msg_set_bits(m, 1, 0, 0xffff, n);
209}
210
211
212/*
213 * Word 2
214 */
215
216static inline u32 msg_ack(struct tipc_msg *m)
217{
218 return msg_bits(m, 2, 16, 0xffff);
219}
220
221static inline void msg_set_ack(struct tipc_msg *m, u32 n)
222{
223 msg_set_bits(m, 2, 16, 0xffff, n);
224}
225
226static inline u32 msg_seqno(struct tipc_msg *m)
227{
228 return msg_bits(m, 2, 0, 0xffff);
229}
230
231static inline void msg_set_seqno(struct tipc_msg *m, u32 n)
232{
233 msg_set_bits(m, 2, 0, 0xffff, n);
234}
235
236
237/*
238 * Words 3-10
239 */
240
241
242static inline void msg_set_prevnode(struct tipc_msg *m, u32 a)
243{
244 msg_set_word(m, 3, a);
245}
246
247static inline void msg_set_origport(struct tipc_msg *m, u32 p)
248{
249 msg_set_word(m, 4, p);
250}
251
252static inline void msg_set_destport(struct tipc_msg *m, u32 p)
253{
254 msg_set_word(m, 5, p);
255}
256
257static inline void msg_set_mc_netid(struct tipc_msg *m, u32 p)
258{
259 msg_set_word(m, 5, p);
260}
261
262static inline void msg_set_orignode(struct tipc_msg *m, u32 a)
263{
264 msg_set_word(m, 6, a);
265}
266
267static inline void msg_set_destnode(struct tipc_msg *m, u32 a)
268{
269 msg_set_word(m, 7, a);
270}
271
272static inline int msg_is_dest(struct tipc_msg *m, u32 d)
273{
274 return(msg_short(m) || (msg_destnode(m) == d));
275}
276
277static inline u32 msg_routed(struct tipc_msg *m)
278{
279 if (likely(msg_short(m)))
280 return 0;
281 return(msg_destnode(m) ^ msg_orignode(m)) >> 11;
282}
283
284static inline void msg_set_nametype(struct tipc_msg *m, u32 n)
285{
286 msg_set_word(m, 8, n);
287}
288
289static inline u32 msg_transp_seqno(struct tipc_msg *m)
290{
291 return msg_word(m, 8);
292}
293
294static inline void msg_set_timestamp(struct tipc_msg *m, u32 n)
295{
296 msg_set_word(m, 8, n);
297}
298
299static inline u32 msg_timestamp(struct tipc_msg *m)
300{
301 return msg_word(m, 8);
302}
303
304static inline void msg_set_transp_seqno(struct tipc_msg *m, u32 n)
305{
306 msg_set_word(m, 8, n);
307}
308
309static inline void msg_set_namelower(struct tipc_msg *m, u32 n)
310{
311 msg_set_word(m, 9, n);
312}
313
314static inline void msg_set_nameinst(struct tipc_msg *m, u32 n)
315{
316 msg_set_namelower(m, n);
317}
318
319static inline void msg_set_nameupper(struct tipc_msg *m, u32 n)
320{
321 msg_set_word(m, 10, n);
322}
323
324static inline struct tipc_msg *msg_get_wrapped(struct tipc_msg *m)
325{
326 return (struct tipc_msg *)msg_data(m);
327}
328
329static inline void msg_expand(struct tipc_msg *m, u32 destnode)
330{
331 if (!msg_short(m))
332 return;
333 msg_set_hdr_sz(m, LONG_H_SIZE);
334 msg_set_orignode(m, msg_prevnode(m));
335 msg_set_destnode(m, destnode);
336 memset(&m->hdr[8], 0, 12);
337}
338
339
340
341/*
342 TIPC internal message header format, version 2
343
344 1 0 9 8 7 6 5 4|3 2 1 0 9 8 7 6|5 4 3 2 1 0 9 8|7 6 5 4 3 2 1 0
345 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
346 w0:|vers |msg usr|hdr sz |n|resrv| packet size |
347 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
348 w1:|m typ|rsv=0| sequence gap | broadcast ack no |
349 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
350 w2:| link level ack no/bc_gap_from | seq no / bcast_gap_to |
351 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
352 w3:| previous node |
353 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
354 w4:| next sent broadcast/fragm no | next sent pkt/ fragm msg no |
355 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
356 w5:| session no |rsv=0|r|berid|link prio|netpl|p|
357 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
358 w6:| originating node |
359 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
360 w7:| destination node |
361 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
362 w8:| transport sequence number |
363 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
364 w9:| msg count / bcast tag | link tolerance |
365 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
366 \ \
367 / User Specific Data /
368 \ \
369 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
370
371 NB: CONN_MANAGER use data message format. LINK_CONFIG has own format.
372*/
373
374/*
375 * Internal users
376 */
377
378#define BCAST_PROTOCOL 5
379#define MSG_BUNDLER 6
380#define LINK_PROTOCOL 7
381#define CONN_MANAGER 8
382#define ROUTE_DISTRIBUTOR 9
383#define CHANGEOVER_PROTOCOL 10
384#define NAME_DISTRIBUTOR 11
385#define MSG_FRAGMENTER 12
386#define LINK_CONFIG 13
387#define INT_H_SIZE 40
388#define DSC_H_SIZE 40
389
390/*
391 * Connection management protocol messages
392 */
393
394#define CONN_PROBE 0
395#define CONN_PROBE_REPLY 1
396#define CONN_ACK 2
397
398/*
399 * Name distributor messages
400 */
401
402#define PUBLICATION 0
403#define WITHDRAWAL 1
404
405
406/*
407 * Word 1
408 */
409
410static inline u32 msg_seq_gap(struct tipc_msg *m)
411{
412 return msg_bits(m, 1, 16, 0xff);
413}
414
415static inline void msg_set_seq_gap(struct tipc_msg *m, u32 n)
416{
417 msg_set_bits(m, 1, 16, 0xff, n);
418}
419
420static inline u32 msg_req_links(struct tipc_msg *m)
421{
422 return msg_bits(m, 1, 16, 0xfff);
423}
424
425static inline void msg_set_req_links(struct tipc_msg *m, u32 n)
426{
427 msg_set_bits(m, 1, 16, 0xfff, n);
428}
429
430
431/*
432 * Word 2
433 */
434
435static inline u32 msg_dest_domain(struct tipc_msg *m)
436{
437 return msg_word(m, 2);
438}
439
440static inline void msg_set_dest_domain(struct tipc_msg *m, u32 n)
441{
442 msg_set_word(m, 2, n);
443}
444
445static inline u32 msg_bcgap_after(struct tipc_msg *m)
446{
447 return msg_bits(m, 2, 16, 0xffff);
448}
449
450static inline void msg_set_bcgap_after(struct tipc_msg *m, u32 n)
451{
452 msg_set_bits(m, 2, 16, 0xffff, n);
453}
454
455static inline u32 msg_bcgap_to(struct tipc_msg *m)
456{
457 return msg_bits(m, 2, 0, 0xffff);
458}
459
460static inline void msg_set_bcgap_to(struct tipc_msg *m, u32 n)
461{
462 msg_set_bits(m, 2, 0, 0xffff, n);
463}
464
465
466/*
467 * Word 4
468 */
469
470static inline u32 msg_last_bcast(struct tipc_msg *m)
471{
472 return msg_bits(m, 4, 16, 0xffff);
473}
474
475static inline void msg_set_last_bcast(struct tipc_msg *m, u32 n)
476{
477 msg_set_bits(m, 4, 16, 0xffff, n);
478}
479
480
481static inline u32 msg_fragm_no(struct tipc_msg *m)
482{
483 return msg_bits(m, 4, 16, 0xffff);
484}
485
486static inline void msg_set_fragm_no(struct tipc_msg *m, u32 n)
487{
488 msg_set_bits(m, 4, 16, 0xffff, n);
489}
490
491
492static inline u32 msg_next_sent(struct tipc_msg *m)
493{
494 return msg_bits(m, 4, 0, 0xffff);
495}
496
497static inline void msg_set_next_sent(struct tipc_msg *m, u32 n)
498{
499 msg_set_bits(m, 4, 0, 0xffff, n);
500}
501
502
503static inline u32 msg_long_msgno(struct tipc_msg *m)
504{
505 return msg_bits(m, 4, 0, 0xffff);
506}
507
508static inline void msg_set_long_msgno(struct tipc_msg *m, u32 n)
509{
510 msg_set_bits(m, 4, 0, 0xffff, n);
511}
512
513static inline u32 msg_bc_netid(struct tipc_msg *m)
514{
515 return msg_word(m, 4);
516}
517
518static inline void msg_set_bc_netid(struct tipc_msg *m, u32 id)
519{
520 msg_set_word(m, 4, id);
521}
522
523static inline u32 msg_link_selector(struct tipc_msg *m)
524{
525 return msg_bits(m, 4, 0, 1);
526}
527
528static inline void msg_set_link_selector(struct tipc_msg *m, u32 n)
529{
530 msg_set_bits(m, 4, 0, 1, (n & 1));
531}
532
533/*
534 * Word 5
535 */
536
537static inline u32 msg_session(struct tipc_msg *m)
538{
539 return msg_bits(m, 5, 16, 0xffff);
540}
541
542static inline void msg_set_session(struct tipc_msg *m, u32 n)
543{
544 msg_set_bits(m, 5, 16, 0xffff, n);
545}
546
547static inline u32 msg_probe(struct tipc_msg *m)
548{
549 return msg_bits(m, 5, 0, 1);
550}
551
552static inline void msg_set_probe(struct tipc_msg *m, u32 val)
553{
554 msg_set_bits(m, 5, 0, 1, (val & 1));
555}
556
557static inline char msg_net_plane(struct tipc_msg *m)
558{
559 return msg_bits(m, 5, 1, 7) + 'A';
560}
561
562static inline void msg_set_net_plane(struct tipc_msg *m, char n)
563{
564 msg_set_bits(m, 5, 1, 7, (n - 'A'));
565}
566
567static inline u32 msg_linkprio(struct tipc_msg *m)
568{
569 return msg_bits(m, 5, 4, 0x1f);
570}
571
572static inline void msg_set_linkprio(struct tipc_msg *m, u32 n)
573{
574 msg_set_bits(m, 5, 4, 0x1f, n);
575}
576
577static inline u32 msg_bearer_id(struct tipc_msg *m)
578{
579 return msg_bits(m, 5, 9, 0x7);
580}
581
582static inline void msg_set_bearer_id(struct tipc_msg *m, u32 n)
583{
584 msg_set_bits(m, 5, 9, 0x7, n);
585}
586
587static inline u32 msg_redundant_link(struct tipc_msg *m)
588{
589 return msg_bits(m, 5, 12, 0x1);
590}
591
592static inline void msg_set_redundant_link(struct tipc_msg *m)
593{
594 msg_set_bits(m, 5, 12, 0x1, 1);
595}
596
597static inline void msg_clear_redundant_link(struct tipc_msg *m)
598{
599 msg_set_bits(m, 5, 12, 0x1, 0);
600}
601
602
603/*
604 * Word 9
605 */
606
607static inline u32 msg_msgcnt(struct tipc_msg *m)
608{
609 return msg_bits(m, 9, 16, 0xffff);
610}
611
612static inline void msg_set_msgcnt(struct tipc_msg *m, u32 n)
613{
614 msg_set_bits(m, 9, 16, 0xffff, n);
615}
616
617static inline u32 msg_bcast_tag(struct tipc_msg *m)
618{
619 return msg_bits(m, 9, 16, 0xffff);
620}
621
622static inline void msg_set_bcast_tag(struct tipc_msg *m, u32 n)
623{
624 msg_set_bits(m, 9, 16, 0xffff, n);
625}
626
627static inline u32 msg_max_pkt(struct tipc_msg *m)
628{
629 return (msg_bits(m, 9, 16, 0xffff) * 4);
630}
631
632static inline void msg_set_max_pkt(struct tipc_msg *m, u32 n)
633{
634 msg_set_bits(m, 9, 16, 0xffff, (n / 4));
635}
636
637static inline u32 msg_link_tolerance(struct tipc_msg *m)
638{
639 return msg_bits(m, 9, 0, 0xffff);
640}
641
642static inline void msg_set_link_tolerance(struct tipc_msg *m, u32 n)
643{
644 msg_set_bits(m, 9, 0, 0xffff, n);
645}
646
647/*
648 * Routing table message data
649 */
650
651
652static inline u32 msg_remote_node(struct tipc_msg *m)
653{
654 return msg_word(m, msg_hdr_sz(m)/4);
655}
656
657static inline void msg_set_remote_node(struct tipc_msg *m, u32 a)
658{
659 msg_set_word(m, msg_hdr_sz(m)/4, a);
660}
661
662static inline int msg_dataoctet(struct tipc_msg *m, u32 pos)
663{
664 return(msg_data(m)[pos + 4] != 0);
665}
666
667static inline void msg_set_dataoctet(struct tipc_msg *m, u32 pos)
668{
669 msg_data(m)[pos + 4] = 1;
670}
671
672/*
673 * Segmentation message types
674 */
675
676#define FIRST_FRAGMENT 0
677#define FRAGMENT 1
678#define LAST_FRAGMENT 2
679
680/*
681 * Link management protocol message types
682 */
683
684#define STATE_MSG 0
685#define RESET_MSG 1
686#define ACTIVATE_MSG 2
687
688/*
689 * Changeover tunnel message types
690 */
691#define DUPLICATE_MSG 0
692#define ORIGINAL_MSG 1
693
694/*
695 * Routing table message types
696 */
697#define EXT_ROUTING_TABLE 0
698#define LOCAL_ROUTING_TABLE 1
699#define SLAVE_ROUTING_TABLE 2
700#define ROUTE_ADDITION 3
701#define ROUTE_REMOVAL 4
702
703/*
704 * Config protocol message types
705 */
706
707#define DSC_REQ_MSG 0
708#define DSC_RESP_MSG 1
709
710static inline u32 msg_tot_importance(struct tipc_msg *m)
711{
712 if (likely(msg_isdata(m))) {
713 if (likely(msg_orignode(m) == tipc_own_addr))
714 return msg_importance(m);
715 return msg_importance(m) + 4;
716 }
717 if ((msg_user(m) == MSG_FRAGMENTER) &&
718 (msg_type(m) == FIRST_FRAGMENT))
719 return msg_importance(msg_get_wrapped(m));
720 return msg_importance(m);
721}
722
723
724static inline void msg_init(struct tipc_msg *m, u32 user, u32 type,
725 u32 err, u32 hsize, u32 destnode)
726{
727 memset(m, 0, hsize);
728 msg_set_version(m);
729 msg_set_user(m, user);
730 msg_set_hdr_sz(m, hsize);
731 msg_set_size(m, hsize);
732 msg_set_prevnode(m, tipc_own_addr);
733 msg_set_type(m, type);
734 msg_set_errcode(m, err);
735 if (!msg_short(m)) {
736 msg_set_orignode(m, tipc_own_addr);
737 msg_set_destnode(m, destnode);
738 }
739}
740
741/**
742 * msg_calc_data_size - determine total data size for message
743 */
744
745static inline int msg_calc_data_size(struct iovec const *msg_sect, u32 num_sect)
746{
747 int dsz = 0;
748 int i;
749
750 for (i = 0; i < num_sect; i++)
751 dsz += msg_sect[i].iov_len;
752 return dsz;
753}
754
755/**
756 * msg_build - create message using specified header and data
757 *
758 * Note: Caller must not hold any locks in case copy_from_user() is interrupted!
759 *
760 * Returns message data size or errno
761 */
762
763static inline int msg_build(struct tipc_msg *hdr,
764 struct iovec const *msg_sect, u32 num_sect,
765 int max_size, int usrmem, struct sk_buff** buf)
766{
767 int dsz, sz, hsz, pos, res, cnt;
768
769 dsz = msg_calc_data_size(msg_sect, num_sect);
770 if (unlikely(dsz > TIPC_MAX_USER_MSG_SIZE)) {
771 *buf = NULL;
772 return -EINVAL;
773 }
774
775 pos = hsz = msg_hdr_sz(hdr);
776 sz = hsz + dsz;
777 msg_set_size(hdr, sz);
778 if (unlikely(sz > max_size)) {
779 *buf = NULL;
780 return dsz;
781 }
782
783 *buf = buf_acquire(sz);
784 if (!(*buf))
785 return -ENOMEM;
786 memcpy((*buf)->data, (unchar *)hdr, hsz);
787 for (res = 1, cnt = 0; res && (cnt < num_sect); cnt++) {
788 if (likely(usrmem))
789 res = !copy_from_user((*buf)->data + pos,
790 msg_sect[cnt].iov_base,
791 msg_sect[cnt].iov_len);
792 else
793 memcpy((*buf)->data + pos, msg_sect[cnt].iov_base,
794 msg_sect[cnt].iov_len);
795 pos += msg_sect[cnt].iov_len;
796 }
797 if (likely(res))
798 return dsz;
799
800 buf_discard(*buf);
801 *buf = NULL;
802 return -EFAULT;
803}
804
805
806struct tipc_media_addr;
807
808extern void msg_set_media_addr(struct tipc_msg *m,
809 struct tipc_media_addr *a);
810
811extern void msg_get_media_addr(struct tipc_msg *m,
812 struct tipc_media_addr *a);
813
814
815#endif
diff --git a/net/tipc/name_distr.c b/net/tipc/name_distr.c
new file mode 100644
index 000000000000..5e0604cb3aeb
--- /dev/null
+++ b/net/tipc/name_distr.c
@@ -0,0 +1,306 @@
1/*
2 * net/tipc/name_distr.c: TIPC name distribution code
3 *
4 * Copyright (c) 2003-2005, Ericsson Research Canada
5 * Copyright (c) 2005, Wind River Systems
6 * Copyright (c) 2005-2006, Ericsson AB
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions are met:
11 *
12 * Redistributions of source code must retain the above copyright notice, this
13 * list of conditions and the following disclaimer.
14 * Redistributions in binary form must reproduce the above copyright notice,
15 * this list of conditions and the following disclaimer in the documentation
16 * and/or other materials provided with the distribution.
17 * Neither the names of the copyright holders nor the names of its
18 * contributors may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 */
33
34#include "core.h"
35#include "cluster.h"
36#include "dbg.h"
37#include "link.h"
38#include "msg.h"
39#include "name_distr.h"
40
41#undef DBG_OUTPUT
42#define DBG_OUTPUT NULL
43
44#define ITEM_SIZE sizeof(struct distr_item)
45
46/**
47 * struct distr_item - publication info distributed to other nodes
48 * @type: name sequence type
49 * @lower: name sequence lower bound
50 * @upper: name sequence upper bound
51 * @ref: publishing port reference
52 * @key: publication key
53 *
54 * ===> All fields are stored in network byte order. <===
55 *
56 * First 3 fields identify (name or) name sequence being published.
57 * Reference field uniquely identifies port that published name sequence.
58 * Key field uniquely identifies publication, in the event a port has
59 * multiple publications of the same name sequence.
60 *
61 * Note: There is no field that identifies the publishing node because it is
62 * the same for all items contained within a publication message.
63 */
64
65struct distr_item {
66 u32 type;
67 u32 lower;
68 u32 upper;
69 u32 ref;
70 u32 key;
71};
72
73/**
74 * List of externally visible publications by this node --
75 * that is, all publications having scope > TIPC_NODE_SCOPE.
76 */
77
78static LIST_HEAD(publ_root);
79static u32 publ_cnt = 0;
80
81/**
82 * publ_to_item - add publication info to a publication message
83 */
84
85static void publ_to_item(struct distr_item *i, struct publication *p)
86{
87 i->type = htonl(p->type);
88 i->lower = htonl(p->lower);
89 i->upper = htonl(p->upper);
90 i->ref = htonl(p->ref);
91 i->key = htonl(p->key);
92 dbg("publ_to_item: %u, %u, %u\n", p->type, p->lower, p->upper);
93}
94
95/**
96 * named_prepare_buf - allocate & initialize a publication message
97 */
98
99static struct sk_buff *named_prepare_buf(u32 type, u32 size, u32 dest)
100{
101 struct sk_buff *buf = buf_acquire(LONG_H_SIZE + size);
102 struct tipc_msg *msg;
103
104 if (buf != NULL) {
105 msg = buf_msg(buf);
106 msg_init(msg, NAME_DISTRIBUTOR, type, TIPC_OK,
107 LONG_H_SIZE, dest);
108 msg_set_size(msg, LONG_H_SIZE + size);
109 }
110 return buf;
111}
112
113/**
114 * named_publish - tell other nodes about a new publication by this node
115 */
116
117void named_publish(struct publication *publ)
118{
119 struct sk_buff *buf;
120 struct distr_item *item;
121
122 list_add(&publ->local_list, &publ_root);
123 publ_cnt++;
124
125 buf = named_prepare_buf(PUBLICATION, ITEM_SIZE, 0);
126 if (!buf) {
127 warn("Memory squeeze; failed to distribute publication\n");
128 return;
129 }
130
131 item = (struct distr_item *)msg_data(buf_msg(buf));
132 publ_to_item(item, publ);
133 dbg("named_withdraw: broadcasting publish msg\n");
134 cluster_broadcast(buf);
135}
136
137/**
138 * named_withdraw - tell other nodes about a withdrawn publication by this node
139 */
140
141void named_withdraw(struct publication *publ)
142{
143 struct sk_buff *buf;
144 struct distr_item *item;
145
146 list_del(&publ->local_list);
147 publ_cnt--;
148
149 buf = named_prepare_buf(WITHDRAWAL, ITEM_SIZE, 0);
150 if (!buf) {
151 warn("Memory squeeze; failed to distribute withdrawal\n");
152 return;
153 }
154
155 item = (struct distr_item *)msg_data(buf_msg(buf));
156 publ_to_item(item, publ);
157 dbg("named_withdraw: broadcasting withdraw msg\n");
158 cluster_broadcast(buf);
159}
160
161/**
162 * named_node_up - tell specified node about all publications by this node
163 */
164
165void named_node_up(unsigned long node)
166{
167 struct publication *publ;
168 struct distr_item *item = 0;
169 struct sk_buff *buf = 0;
170 u32 left = 0;
171 u32 rest;
172 u32 max_item_buf;
173
174 assert(in_own_cluster(node));
175 read_lock_bh(&nametbl_lock);
176 max_item_buf = TIPC_MAX_USER_MSG_SIZE / ITEM_SIZE;
177 max_item_buf *= ITEM_SIZE;
178 rest = publ_cnt * ITEM_SIZE;
179
180 list_for_each_entry(publ, &publ_root, local_list) {
181 if (!buf) {
182 left = (rest <= max_item_buf) ? rest : max_item_buf;
183 rest -= left;
184 buf = named_prepare_buf(PUBLICATION, left, node);
185 if (buf == NULL) {
186 warn("Memory Squeeze; could not send publication\n");
187 goto exit;
188 }
189 item = (struct distr_item *)msg_data(buf_msg(buf));
190 }
191 publ_to_item(item, publ);
192 item++;
193 left -= ITEM_SIZE;
194 if (!left) {
195 msg_set_link_selector(buf_msg(buf), node);
196 dbg("named_node_up: sending publish msg to "
197 "<%u.%u.%u>\n", tipc_zone(node),
198 tipc_cluster(node), tipc_node(node));
199 link_send(buf, node, node);
200 buf = 0;
201 }
202 }
203exit:
204 read_unlock_bh(&nametbl_lock);
205}
206
207/**
208 * node_is_down - remove publication associated with a failed node
209 *
210 * Invoked for each publication issued by a newly failed node.
211 * Removes publication structure from name table & deletes it.
212 * In rare cases the link may have come back up again when this
213 * function is called, and we have two items representing the same
214 * publication. Nudge this item's key to distinguish it from the other.
215 * (Note: Publication's node subscription is already unsubscribed.)
216 */
217
218static void node_is_down(struct publication *publ)
219{
220 struct publication *p;
221 write_lock_bh(&nametbl_lock);
222 dbg("node_is_down: withdrawing %u, %u, %u\n",
223 publ->type, publ->lower, publ->upper);
224 publ->key += 1222345;
225 p = nametbl_remove_publ(publ->type, publ->lower,
226 publ->node, publ->ref, publ->key);
227 assert(p == publ);
228 write_unlock_bh(&nametbl_lock);
229 if (publ)
230 kfree(publ);
231}
232
233/**
234 * named_recv - process name table update message sent by another node
235 */
236
237void named_recv(struct sk_buff *buf)
238{
239 struct publication *publ;
240 struct tipc_msg *msg = buf_msg(buf);
241 struct distr_item *item = (struct distr_item *)msg_data(msg);
242 u32 count = msg_data_sz(msg) / ITEM_SIZE;
243
244 write_lock_bh(&nametbl_lock);
245 while (count--) {
246 if (msg_type(msg) == PUBLICATION) {
247 dbg("named_recv: got publication for %u, %u, %u\n",
248 ntohl(item->type), ntohl(item->lower),
249 ntohl(item->upper));
250 publ = nametbl_insert_publ(ntohl(item->type),
251 ntohl(item->lower),
252 ntohl(item->upper),
253 TIPC_CLUSTER_SCOPE,
254 msg_orignode(msg),
255 ntohl(item->ref),
256 ntohl(item->key));
257 if (publ) {
258 nodesub_subscribe(&publ->subscr,
259 msg_orignode(msg),
260 publ,
261 (net_ev_handler)node_is_down);
262 }
263 } else if (msg_type(msg) == WITHDRAWAL) {
264 dbg("named_recv: got withdrawl for %u, %u, %u\n",
265 ntohl(item->type), ntohl(item->lower),
266 ntohl(item->upper));
267 publ = nametbl_remove_publ(ntohl(item->type),
268 ntohl(item->lower),
269 msg_orignode(msg),
270 ntohl(item->ref),
271 ntohl(item->key));
272
273 if (publ) {
274 nodesub_unsubscribe(&publ->subscr);
275 kfree(publ);
276 }
277 } else {
278 warn("named_recv: unknown msg\n");
279 }
280 item++;
281 }
282 write_unlock_bh(&nametbl_lock);
283 buf_discard(buf);
284}
285
286/**
287 * named_reinit - re-initialize local publication list
288 *
289 * This routine is called whenever TIPC networking is (re)enabled.
290 * All existing publications by this node that have "cluster" or "zone" scope
291 * are updated to reflect the node's current network address.
292 * (If the node's address is unchanged, the update loop terminates immediately.)
293 */
294
295void named_reinit(void)
296{
297 struct publication *publ;
298
299 write_lock_bh(&nametbl_lock);
300 list_for_each_entry(publ, &publ_root, local_list) {
301 if (publ->node == tipc_own_addr)
302 break;
303 publ->node = tipc_own_addr;
304 }
305 write_unlock_bh(&nametbl_lock);
306}
diff --git a/net/tipc/name_distr.h b/net/tipc/name_distr.h
new file mode 100644
index 000000000000..7c6616aecc03
--- /dev/null
+++ b/net/tipc/name_distr.h
@@ -0,0 +1,45 @@
1/*
2 * net/tipc/name_distr.h: Include file for TIPC name distribution code
3 *
4 * Copyright (c) 2003-2005, Ericsson Research Canada
5 * Copyright (c) 2005, Wind River Systems
6 * Copyright (c) 2005-2006, Ericsson AB
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions are met:
11 *
12 * Redistributions of source code must retain the above copyright notice, this
13 * list of conditions and the following disclaimer.
14 * Redistributions in binary form must reproduce the above copyright notice,
15 * this list of conditions and the following disclaimer in the documentation
16 * and/or other materials provided with the distribution.
17 * Neither the names of the copyright holders nor the names of its
18 * contributors may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 */
33
34#ifndef _TIPC_NAME_DISTR_H
35#define _TIPC_NAME_DISTR_H
36
37#include "name_table.h"
38
39void named_publish(struct publication *publ);
40void named_withdraw(struct publication *publ);
41void named_node_up(unsigned long node);
42void named_recv(struct sk_buff *buf);
43void named_reinit(void);
44
45#endif
diff --git a/net/tipc/name_table.c b/net/tipc/name_table.c
new file mode 100644
index 000000000000..9626c5b30678
--- /dev/null
+++ b/net/tipc/name_table.c
@@ -0,0 +1,1076 @@
1/*
2 * net/tipc/name_table.c: TIPC name table code
3 *
4 * Copyright (c) 2003-2005, Ericsson Research Canada
5 * Copyright (c) 2004-2005, Wind River Systems
6 * Copyright (c) 2005-2006, Ericsson AB
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions are met:
11 *
12 * Redistributions of source code must retain the above copyright notice, this
13 * list of conditions and the following disclaimer.
14 * Redistributions in binary form must reproduce the above copyright notice,
15 * this list of conditions and the following disclaimer in the documentation
16 * and/or other materials provided with the distribution.
17 * Neither the names of the copyright holders nor the names of its
18 * contributors may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 */
33
34#include "core.h"
35#include "config.h"
36#include "dbg.h"
37#include "name_table.h"
38#include "name_distr.h"
39#include "addr.h"
40#include "node_subscr.h"
41#include "subscr.h"
42#include "port.h"
43#include "cluster.h"
44#include "bcast.h"
45
46int tipc_nametbl_size = 1024; /* must be a power of 2 */
47
48/**
49 * struct sub_seq - container for all published instances of a name sequence
50 * @lower: name sequence lower bound
51 * @upper: name sequence upper bound
52 * @node_list: circular list of matching publications with >= node scope
53 * @cluster_list: circular list of matching publications with >= cluster scope
54 * @zone_list: circular list of matching publications with >= zone scope
55 */
56
57struct sub_seq {
58 u32 lower;
59 u32 upper;
60 struct publication *node_list;
61 struct publication *cluster_list;
62 struct publication *zone_list;
63};
64
65/**
66 * struct name_seq - container for all published instances of a name type
67 * @type: 32 bit 'type' value for name sequence
68 * @sseq: pointer to dynamically-sized array of sub-sequences of this 'type';
69 * sub-sequences are sorted in ascending order
70 * @alloc: number of sub-sequences currently in array
71 * @first_free: upper bound of highest sub-sequence + 1
72 * @ns_list: links to adjacent name sequences in hash chain
73 * @subscriptions: list of subscriptions for this 'type'
74 * @lock: spinlock controlling access to name sequence structure
75 */
76
77struct name_seq {
78 u32 type;
79 struct sub_seq *sseqs;
80 u32 alloc;
81 u32 first_free;
82 struct hlist_node ns_list;
83 struct list_head subscriptions;
84 spinlock_t lock;
85};
86
87/**
88 * struct name_table - table containing all existing port name publications
89 * @types: pointer to fixed-sized array of name sequence lists,
90 * accessed via hashing on 'type'; name sequence lists are *not* sorted
91 * @local_publ_count: number of publications issued by this node
92 */
93
94struct name_table {
95 struct hlist_head *types;
96 u32 local_publ_count;
97};
98
99struct name_table table = { NULL } ;
100static atomic_t rsv_publ_ok = ATOMIC_INIT(0);
101rwlock_t nametbl_lock = RW_LOCK_UNLOCKED;
102
103
104static inline int hash(int x)
105{
106 return(x & (tipc_nametbl_size - 1));
107}
108
109/**
110 * publ_create - create a publication structure
111 */
112
113static struct publication *publ_create(u32 type, u32 lower, u32 upper,
114 u32 scope, u32 node, u32 port_ref,
115 u32 key)
116{
117 struct publication *publ =
118 (struct publication *)kmalloc(sizeof(*publ), GFP_ATOMIC);
119 if (publ == NULL) {
120 warn("Memory squeeze; failed to create publication\n");
121 return 0;
122 }
123
124 memset(publ, 0, sizeof(*publ));
125 publ->type = type;
126 publ->lower = lower;
127 publ->upper = upper;
128 publ->scope = scope;
129 publ->node = node;
130 publ->ref = port_ref;
131 publ->key = key;
132 INIT_LIST_HEAD(&publ->local_list);
133 INIT_LIST_HEAD(&publ->pport_list);
134 INIT_LIST_HEAD(&publ->subscr.nodesub_list);
135 return publ;
136}
137
138/**
139 * subseq_alloc - allocate a specified number of sub-sequence structures
140 */
141
142struct sub_seq *subseq_alloc(u32 cnt)
143{
144 u32 sz = cnt * sizeof(struct sub_seq);
145 struct sub_seq *sseq = (struct sub_seq *)kmalloc(sz, GFP_ATOMIC);
146
147 if (sseq)
148 memset(sseq, 0, sz);
149 return sseq;
150}
151
152/**
153 * nameseq_create - create a name sequence structure for the specified 'type'
154 *
155 * Allocates a single sub-sequence structure and sets it to all 0's.
156 */
157
158struct name_seq *nameseq_create(u32 type, struct hlist_head *seq_head)
159{
160 struct name_seq *nseq =
161 (struct name_seq *)kmalloc(sizeof(*nseq), GFP_ATOMIC);
162 struct sub_seq *sseq = subseq_alloc(1);
163
164 if (!nseq || !sseq) {
165 warn("Memory squeeze; failed to create name sequence\n");
166 kfree(nseq);
167 kfree(sseq);
168 return 0;
169 }
170
171 memset(nseq, 0, sizeof(*nseq));
172 nseq->lock = SPIN_LOCK_UNLOCKED;
173 nseq->type = type;
174 nseq->sseqs = sseq;
175 dbg("nameseq_create() nseq = %x type %u, ssseqs %x, ff: %u\n",
176 nseq, type, nseq->sseqs, nseq->first_free);
177 nseq->alloc = 1;
178 INIT_HLIST_NODE(&nseq->ns_list);
179 INIT_LIST_HEAD(&nseq->subscriptions);
180 hlist_add_head(&nseq->ns_list, seq_head);
181 return nseq;
182}
183
184/**
185 * nameseq_find_subseq - find sub-sequence (if any) matching a name instance
186 *
187 * Very time-critical, so binary searches through sub-sequence array.
188 */
189
190static inline struct sub_seq *nameseq_find_subseq(struct name_seq *nseq,
191 u32 instance)
192{
193 struct sub_seq *sseqs = nseq->sseqs;
194 int low = 0;
195 int high = nseq->first_free - 1;
196 int mid;
197
198 while (low <= high) {
199 mid = (low + high) / 2;
200 if (instance < sseqs[mid].lower)
201 high = mid - 1;
202 else if (instance > sseqs[mid].upper)
203 low = mid + 1;
204 else
205 return &sseqs[mid];
206 }
207 return 0;
208}
209
210/**
211 * nameseq_locate_subseq - determine position of name instance in sub-sequence
212 *
213 * Returns index in sub-sequence array of the entry that contains the specified
214 * instance value; if no entry contains that value, returns the position
215 * where a new entry for it would be inserted in the array.
216 *
217 * Note: Similar to binary search code for locating a sub-sequence.
218 */
219
220static u32 nameseq_locate_subseq(struct name_seq *nseq, u32 instance)
221{
222 struct sub_seq *sseqs = nseq->sseqs;
223 int low = 0;
224 int high = nseq->first_free - 1;
225 int mid;
226
227 while (low <= high) {
228 mid = (low + high) / 2;
229 if (instance < sseqs[mid].lower)
230 high = mid - 1;
231 else if (instance > sseqs[mid].upper)
232 low = mid + 1;
233 else
234 return mid;
235 }
236 return low;
237}
238
239/**
240 * nameseq_insert_publ -
241 */
242
243struct publication *nameseq_insert_publ(struct name_seq *nseq,
244 u32 type, u32 lower, u32 upper,
245 u32 scope, u32 node, u32 port, u32 key)
246{
247 struct subscription *s;
248 struct subscription *st;
249 struct publication *publ;
250 struct sub_seq *sseq;
251 int created_subseq = 0;
252
253 assert(nseq->first_free <= nseq->alloc);
254 sseq = nameseq_find_subseq(nseq, lower);
255 dbg("nameseq_ins: for seq %x,<%u,%u>, found sseq %x\n",
256 nseq, type, lower, sseq);
257 if (sseq) {
258
259 /* Lower end overlaps existing entry => need an exact match */
260
261 if ((sseq->lower != lower) || (sseq->upper != upper)) {
262 warn("Overlapping publ <%u,%u,%u>\n", type, lower, upper);
263 return 0;
264 }
265 } else {
266 u32 inspos;
267 struct sub_seq *freesseq;
268
269 /* Find where lower end should be inserted */
270
271 inspos = nameseq_locate_subseq(nseq, lower);
272
273 /* Fail if upper end overlaps into an existing entry */
274
275 if ((inspos < nseq->first_free) &&
276 (upper >= nseq->sseqs[inspos].lower)) {
277 warn("Overlapping publ <%u,%u,%u>\n", type, lower, upper);
278 return 0;
279 }
280
281 /* Ensure there is space for new sub-sequence */
282
283 if (nseq->first_free == nseq->alloc) {
284 struct sub_seq *sseqs = nseq->sseqs;
285 nseq->sseqs = subseq_alloc(nseq->alloc * 2);
286 if (nseq->sseqs != NULL) {
287 memcpy(nseq->sseqs, sseqs,
288 nseq->alloc * sizeof (struct sub_seq));
289 kfree(sseqs);
290 dbg("Allocated %u sseqs\n", nseq->alloc);
291 nseq->alloc *= 2;
292 } else {
293 warn("Memory squeeze; failed to create sub-sequence\n");
294 return 0;
295 }
296 }
297 dbg("Have %u sseqs for type %u\n", nseq->alloc, type);
298
299 /* Insert new sub-sequence */
300
301 dbg("ins in pos %u, ff = %u\n", inspos, nseq->first_free);
302 sseq = &nseq->sseqs[inspos];
303 freesseq = &nseq->sseqs[nseq->first_free];
304 memmove(sseq + 1, sseq, (freesseq - sseq) * sizeof (*sseq));
305 memset(sseq, 0, sizeof (*sseq));
306 nseq->first_free++;
307 sseq->lower = lower;
308 sseq->upper = upper;
309 created_subseq = 1;
310 }
311 dbg("inserting (%u %u %u) from %x:%u into sseq %x(%u,%u) of seq %x\n",
312 type, lower, upper, node, port, sseq,
313 sseq->lower, sseq->upper, nseq);
314
315 /* Insert a publication: */
316
317 publ = publ_create(type, lower, upper, scope, node, port, key);
318 if (!publ)
319 return 0;
320 dbg("inserting publ %x, node=%x publ->node=%x, subscr->node=%x\n",
321 publ, node, publ->node, publ->subscr.node);
322
323 if (!sseq->zone_list)
324 sseq->zone_list = publ->zone_list_next = publ;
325 else {
326 publ->zone_list_next = sseq->zone_list->zone_list_next;
327 sseq->zone_list->zone_list_next = publ;
328 }
329
330 if (in_own_cluster(node)) {
331 if (!sseq->cluster_list)
332 sseq->cluster_list = publ->cluster_list_next = publ;
333 else {
334 publ->cluster_list_next =
335 sseq->cluster_list->cluster_list_next;
336 sseq->cluster_list->cluster_list_next = publ;
337 }
338 }
339
340 if (node == tipc_own_addr) {
341 if (!sseq->node_list)
342 sseq->node_list = publ->node_list_next = publ;
343 else {
344 publ->node_list_next = sseq->node_list->node_list_next;
345 sseq->node_list->node_list_next = publ;
346 }
347 }
348
349 /*
350 * Any subscriptions waiting for notification?
351 */
352 list_for_each_entry_safe(s, st, &nseq->subscriptions, nameseq_list) {
353 dbg("calling report_overlap()\n");
354 subscr_report_overlap(s,
355 publ->lower,
356 publ->upper,
357 TIPC_PUBLISHED,
358 publ->ref,
359 publ->node,
360 created_subseq);
361 }
362 return publ;
363}
364
365/**
366 * nameseq_remove_publ -
367 */
368
369struct publication *nameseq_remove_publ(struct name_seq *nseq, u32 inst,
370 u32 node, u32 ref, u32 key)
371{
372 struct publication *publ;
373 struct publication *prev;
374 struct sub_seq *sseq = nameseq_find_subseq(nseq, inst);
375 struct sub_seq *free;
376 struct subscription *s, *st;
377 int removed_subseq = 0;
378
379 assert(nseq);
380
381 if (!sseq) {
382 int i;
383
384 warn("Withdraw unknown <%u,%u>?\n", nseq->type, inst);
385 assert(nseq->sseqs);
386 dbg("Dumping subseqs %x for %x, alloc = %u,ff=%u\n",
387 nseq->sseqs, nseq, nseq->alloc,
388 nseq->first_free);
389 for (i = 0; i < nseq->first_free; i++) {
390 dbg("Subseq %u(%x): lower = %u,upper = %u\n",
391 i, &nseq->sseqs[i], nseq->sseqs[i].lower,
392 nseq->sseqs[i].upper);
393 }
394 return 0;
395 }
396 dbg("nameseq_remove: seq: %x, sseq %x, <%u,%u> key %u\n",
397 nseq, sseq, nseq->type, inst, key);
398
399 prev = sseq->zone_list;
400 publ = sseq->zone_list->zone_list_next;
401 while ((publ->key != key) || (publ->ref != ref) ||
402 (publ->node && (publ->node != node))) {
403 prev = publ;
404 publ = publ->zone_list_next;
405 assert(prev != sseq->zone_list);
406 }
407 if (publ != sseq->zone_list)
408 prev->zone_list_next = publ->zone_list_next;
409 else if (publ->zone_list_next != publ) {
410 prev->zone_list_next = publ->zone_list_next;
411 sseq->zone_list = publ->zone_list_next;
412 } else {
413 sseq->zone_list = 0;
414 }
415
416 if (in_own_cluster(node)) {
417 prev = sseq->cluster_list;
418 publ = sseq->cluster_list->cluster_list_next;
419 while ((publ->key != key) || (publ->ref != ref) ||
420 (publ->node && (publ->node != node))) {
421 prev = publ;
422 publ = publ->cluster_list_next;
423 assert(prev != sseq->cluster_list);
424 }
425 if (publ != sseq->cluster_list)
426 prev->cluster_list_next = publ->cluster_list_next;
427 else if (publ->cluster_list_next != publ) {
428 prev->cluster_list_next = publ->cluster_list_next;
429 sseq->cluster_list = publ->cluster_list_next;
430 } else {
431 sseq->cluster_list = 0;
432 }
433 }
434
435 if (node == tipc_own_addr) {
436 prev = sseq->node_list;
437 publ = sseq->node_list->node_list_next;
438 while ((publ->key != key) || (publ->ref != ref) ||
439 (publ->node && (publ->node != node))) {
440 prev = publ;
441 publ = publ->node_list_next;
442 assert(prev != sseq->node_list);
443 }
444 if (publ != sseq->node_list)
445 prev->node_list_next = publ->node_list_next;
446 else if (publ->node_list_next != publ) {
447 prev->node_list_next = publ->node_list_next;
448 sseq->node_list = publ->node_list_next;
449 } else {
450 sseq->node_list = 0;
451 }
452 }
453 assert(!publ->node || (publ->node == node));
454 assert(publ->ref == ref);
455 assert(publ->key == key);
456
457 /*
458 * Contract subseq list if no more publications:
459 */
460 if (!sseq->node_list && !sseq->cluster_list && !sseq->zone_list) {
461 free = &nseq->sseqs[nseq->first_free--];
462 memmove(sseq, sseq + 1, (free - (sseq + 1)) * sizeof (*sseq));
463 removed_subseq = 1;
464 }
465
466 /*
467 * Any subscriptions waiting ?
468 */
469 list_for_each_entry_safe(s, st, &nseq->subscriptions, nameseq_list) {
470 subscr_report_overlap(s,
471 publ->lower,
472 publ->upper,
473 TIPC_WITHDRAWN,
474 publ->ref,
475 publ->node,
476 removed_subseq);
477 }
478 return publ;
479}
480
481/**
482 * nameseq_subscribe: attach a subscription, and issue
483 * the prescribed number of events if there is any sub-
484 * sequence overlapping with the requested sequence
485 */
486
487void nameseq_subscribe(struct name_seq *nseq, struct subscription *s)
488{
489 struct sub_seq *sseq = nseq->sseqs;
490
491 list_add(&s->nameseq_list, &nseq->subscriptions);
492
493 if (!sseq)
494 return;
495
496 while (sseq != &nseq->sseqs[nseq->first_free]) {
497 struct publication *zl = sseq->zone_list;
498 if (zl && subscr_overlap(s,sseq->lower,sseq->upper)) {
499 struct publication *crs = zl;
500 int must_report = 1;
501
502 do {
503 subscr_report_overlap(s,
504 sseq->lower,
505 sseq->upper,
506 TIPC_PUBLISHED,
507 crs->ref,
508 crs->node,
509 must_report);
510 must_report = 0;
511 crs = crs->zone_list_next;
512 } while (crs != zl);
513 }
514 sseq++;
515 }
516}
517
518static struct name_seq *nametbl_find_seq(u32 type)
519{
520 struct hlist_head *seq_head;
521 struct hlist_node *seq_node;
522 struct name_seq *ns;
523
524 dbg("find_seq %u,(%u,0x%x) table = %p, hash[type] = %u\n",
525 type, ntohl(type), type, table.types, hash(type));
526
527 seq_head = &table.types[hash(type)];
528 hlist_for_each_entry(ns, seq_node, seq_head, ns_list) {
529 if (ns->type == type) {
530 dbg("found %x\n", ns);
531 return ns;
532 }
533 }
534
535 return 0;
536};
537
538struct publication *nametbl_insert_publ(u32 type, u32 lower, u32 upper,
539 u32 scope, u32 node, u32 port, u32 key)
540{
541 struct name_seq *seq = nametbl_find_seq(type);
542
543 dbg("ins_publ: <%u,%x,%x> found %x\n", type, lower, upper, seq);
544 if (lower > upper) {
545 warn("Failed to publish illegal <%u,%u,%u>\n",
546 type, lower, upper);
547 return 0;
548 }
549
550 dbg("Publishing <%u,%u,%u> from %x\n", type, lower, upper, node);
551 if (!seq) {
552 seq = nameseq_create(type, &table.types[hash(type)]);
553 dbg("nametbl_insert_publ: created %x\n", seq);
554 }
555 if (!seq)
556 return 0;
557
558 assert(seq->type == type);
559 return nameseq_insert_publ(seq, type, lower, upper,
560 scope, node, port, key);
561}
562
563struct publication *nametbl_remove_publ(u32 type, u32 lower,
564 u32 node, u32 ref, u32 key)
565{
566 struct publication *publ;
567 struct name_seq *seq = nametbl_find_seq(type);
568
569 if (!seq)
570 return 0;
571
572 dbg("Withdrawing <%u,%u> from %x\n", type, lower, node);
573 publ = nameseq_remove_publ(seq, lower, node, ref, key);
574
575 if (!seq->first_free && list_empty(&seq->subscriptions)) {
576 hlist_del_init(&seq->ns_list);
577 kfree(seq->sseqs);
578 kfree(seq);
579 }
580 return publ;
581}
582
583/*
584 * nametbl_translate(): Translate tipc_name -> tipc_portid.
585 * Very time-critical.
586 *
587 * Note: on entry 'destnode' is the search domain used during translation;
588 * on exit it passes back the node address of the matching port (if any)
589 */
590
591u32 nametbl_translate(u32 type, u32 instance, u32 *destnode)
592{
593 struct sub_seq *sseq;
594 struct publication *publ = 0;
595 struct name_seq *seq;
596 u32 ref;
597
598 if (!in_scope(*destnode, tipc_own_addr))
599 return 0;
600
601 read_lock_bh(&nametbl_lock);
602 seq = nametbl_find_seq(type);
603 if (unlikely(!seq))
604 goto not_found;
605 sseq = nameseq_find_subseq(seq, instance);
606 if (unlikely(!sseq))
607 goto not_found;
608 spin_lock_bh(&seq->lock);
609
610 /* Closest-First Algorithm: */
611 if (likely(!*destnode)) {
612 publ = sseq->node_list;
613 if (publ) {
614 sseq->node_list = publ->node_list_next;
615found:
616 ref = publ->ref;
617 *destnode = publ->node;
618 spin_unlock_bh(&seq->lock);
619 read_unlock_bh(&nametbl_lock);
620 return ref;
621 }
622 publ = sseq->cluster_list;
623 if (publ) {
624 sseq->cluster_list = publ->cluster_list_next;
625 goto found;
626 }
627 publ = sseq->zone_list;
628 if (publ) {
629 sseq->zone_list = publ->zone_list_next;
630 goto found;
631 }
632 }
633
634 /* Round-Robin Algorithm: */
635 else if (*destnode == tipc_own_addr) {
636 publ = sseq->node_list;
637 if (publ) {
638 sseq->node_list = publ->node_list_next;
639 goto found;
640 }
641 } else if (in_own_cluster(*destnode)) {
642 publ = sseq->cluster_list;
643 if (publ) {
644 sseq->cluster_list = publ->cluster_list_next;
645 goto found;
646 }
647 } else {
648 publ = sseq->zone_list;
649 if (publ) {
650 sseq->zone_list = publ->zone_list_next;
651 goto found;
652 }
653 }
654 spin_unlock_bh(&seq->lock);
655not_found:
656 *destnode = 0;
657 read_unlock_bh(&nametbl_lock);
658 return 0;
659}
660
661/**
662 * nametbl_mc_translate - find multicast destinations
663 *
664 * Creates list of all local ports that overlap the given multicast address;
665 * also determines if any off-node ports overlap.
666 *
667 * Note: Publications with a scope narrower than 'limit' are ignored.
668 * (i.e. local node-scope publications mustn't receive messages arriving
669 * from another node, even if the multcast link brought it here)
670 *
671 * Returns non-zero if any off-node ports overlap
672 */
673
674int nametbl_mc_translate(u32 type, u32 lower, u32 upper, u32 limit,
675 struct port_list *dports)
676{
677 struct name_seq *seq;
678 struct sub_seq *sseq;
679 struct sub_seq *sseq_stop;
680 int res = 0;
681
682 read_lock_bh(&nametbl_lock);
683 seq = nametbl_find_seq(type);
684 if (!seq)
685 goto exit;
686
687 spin_lock_bh(&seq->lock);
688
689 sseq = seq->sseqs + nameseq_locate_subseq(seq, lower);
690 sseq_stop = seq->sseqs + seq->first_free;
691 for (; sseq != sseq_stop; sseq++) {
692 struct publication *publ;
693
694 if (sseq->lower > upper)
695 break;
696 publ = sseq->cluster_list;
697 if (publ && (publ->scope <= limit))
698 do {
699 if (publ->node == tipc_own_addr)
700 port_list_add(dports, publ->ref);
701 else
702 res = 1;
703 publ = publ->cluster_list_next;
704 } while (publ != sseq->cluster_list);
705 }
706
707 spin_unlock_bh(&seq->lock);
708exit:
709 read_unlock_bh(&nametbl_lock);
710 return res;
711}
712
713/**
714 * nametbl_publish_rsv - publish port name using a reserved name type
715 */
716
717int nametbl_publish_rsv(u32 ref, unsigned int scope,
718 struct tipc_name_seq const *seq)
719{
720 int res;
721
722 atomic_inc(&rsv_publ_ok);
723 res = tipc_publish(ref, scope, seq);
724 atomic_dec(&rsv_publ_ok);
725 return res;
726}
727
728/**
729 * nametbl_publish - add name publication to network name tables
730 */
731
732struct publication *nametbl_publish(u32 type, u32 lower, u32 upper,
733 u32 scope, u32 port_ref, u32 key)
734{
735 struct publication *publ;
736
737 if (table.local_publ_count >= tipc_max_publications) {
738 warn("Failed publish: max %u local publication\n",
739 tipc_max_publications);
740 return 0;
741 }
742 if ((type < TIPC_RESERVED_TYPES) && !atomic_read(&rsv_publ_ok)) {
743 warn("Failed to publish reserved name <%u,%u,%u>\n",
744 type, lower, upper);
745 return 0;
746 }
747
748 write_lock_bh(&nametbl_lock);
749 table.local_publ_count++;
750 publ = nametbl_insert_publ(type, lower, upper, scope,
751 tipc_own_addr, port_ref, key);
752 if (publ && (scope != TIPC_NODE_SCOPE)) {
753 named_publish(publ);
754 }
755 write_unlock_bh(&nametbl_lock);
756 return publ;
757}
758
759/**
760 * nametbl_withdraw - withdraw name publication from network name tables
761 */
762
763int nametbl_withdraw(u32 type, u32 lower, u32 ref, u32 key)
764{
765 struct publication *publ;
766
767 dbg("nametbl_withdraw:<%d,%d,%d>\n", type, lower, key);
768 write_lock_bh(&nametbl_lock);
769 publ = nametbl_remove_publ(type, lower, tipc_own_addr, ref, key);
770 if (publ) {
771 table.local_publ_count--;
772 if (publ->scope != TIPC_NODE_SCOPE)
773 named_withdraw(publ);
774 write_unlock_bh(&nametbl_lock);
775 list_del_init(&publ->pport_list);
776 kfree(publ);
777 return 1;
778 }
779 write_unlock_bh(&nametbl_lock);
780 return 0;
781}
782
783/**
784 * nametbl_subscribe - add a subscription object to the name table
785 */
786
787void
788nametbl_subscribe(struct subscription *s)
789{
790 u32 type = s->seq.type;
791 struct name_seq *seq;
792
793 write_lock_bh(&nametbl_lock);
794 seq = nametbl_find_seq(type);
795 if (!seq) {
796 seq = nameseq_create(type, &table.types[hash(type)]);
797 }
798 if (seq){
799 spin_lock_bh(&seq->lock);
800 dbg("nametbl_subscribe:found %x for <%u,%u,%u>\n",
801 seq, type, s->seq.lower, s->seq.upper);
802 assert(seq->type == type);
803 nameseq_subscribe(seq, s);
804 spin_unlock_bh(&seq->lock);
805 }
806 write_unlock_bh(&nametbl_lock);
807}
808
809/**
810 * nametbl_unsubscribe - remove a subscription object from name table
811 */
812
813void
814nametbl_unsubscribe(struct subscription *s)
815{
816 struct name_seq *seq;
817
818 write_lock_bh(&nametbl_lock);
819 seq = nametbl_find_seq(s->seq.type);
820 if (seq != NULL){
821 spin_lock_bh(&seq->lock);
822 list_del_init(&s->nameseq_list);
823 spin_unlock_bh(&seq->lock);
824 if ((seq->first_free == 0) && list_empty(&seq->subscriptions)) {
825 hlist_del_init(&seq->ns_list);
826 kfree(seq->sseqs);
827 kfree(seq);
828 }
829 }
830 write_unlock_bh(&nametbl_lock);
831}
832
833
834/**
835 * subseq_list: print specified sub-sequence contents into the given buffer
836 */
837
838static void subseq_list(struct sub_seq *sseq, struct print_buf *buf, u32 depth,
839 u32 index)
840{
841 char portIdStr[27];
842 char *scopeStr;
843 struct publication *publ = sseq->zone_list;
844
845 tipc_printf(buf, "%-10u %-10u ", sseq->lower, sseq->upper);
846
847 if (depth == 2 || !publ) {
848 tipc_printf(buf, "\n");
849 return;
850 }
851
852 do {
853 sprintf (portIdStr, "<%u.%u.%u:%u>",
854 tipc_zone(publ->node), tipc_cluster(publ->node),
855 tipc_node(publ->node), publ->ref);
856 tipc_printf(buf, "%-26s ", portIdStr);
857 if (depth > 3) {
858 if (publ->node != tipc_own_addr)
859 scopeStr = "";
860 else if (publ->scope == TIPC_NODE_SCOPE)
861 scopeStr = "node";
862 else if (publ->scope == TIPC_CLUSTER_SCOPE)
863 scopeStr = "cluster";
864 else
865 scopeStr = "zone";
866 tipc_printf(buf, "%-10u %s", publ->key, scopeStr);
867 }
868
869 publ = publ->zone_list_next;
870 if (publ == sseq->zone_list)
871 break;
872
873 tipc_printf(buf, "\n%33s", " ");
874 } while (1);
875
876 tipc_printf(buf, "\n");
877}
878
879/**
880 * nameseq_list: print specified name sequence contents into the given buffer
881 */
882
883static void nameseq_list(struct name_seq *seq, struct print_buf *buf, u32 depth,
884 u32 type, u32 lowbound, u32 upbound, u32 index)
885{
886 struct sub_seq *sseq;
887 char typearea[11];
888
889 sprintf(typearea, "%-10u", seq->type);
890
891 if (depth == 1) {
892 tipc_printf(buf, "%s\n", typearea);
893 return;
894 }
895
896 for (sseq = seq->sseqs; sseq != &seq->sseqs[seq->first_free]; sseq++) {
897 if ((lowbound <= sseq->upper) && (upbound >= sseq->lower)) {
898 tipc_printf(buf, "%s ", typearea);
899 subseq_list(sseq, buf, depth, index);
900 sprintf(typearea, "%10s", " ");
901 }
902 }
903}
904
905/**
906 * nametbl_header - print name table header into the given buffer
907 */
908
909static void nametbl_header(struct print_buf *buf, u32 depth)
910{
911 tipc_printf(buf, "Type ");
912
913 if (depth > 1)
914 tipc_printf(buf, "Lower Upper ");
915 if (depth > 2)
916 tipc_printf(buf, "Port Identity ");
917 if (depth > 3)
918 tipc_printf(buf, "Publication");
919
920 tipc_printf(buf, "\n-----------");
921
922 if (depth > 1)
923 tipc_printf(buf, "--------------------- ");
924 if (depth > 2)
925 tipc_printf(buf, "-------------------------- ");
926 if (depth > 3)
927 tipc_printf(buf, "------------------");
928
929 tipc_printf(buf, "\n");
930}
931
932/**
933 * nametbl_list - print specified name table contents into the given buffer
934 */
935
936static void nametbl_list(struct print_buf *buf, u32 depth_info,
937 u32 type, u32 lowbound, u32 upbound)
938{
939 struct hlist_head *seq_head;
940 struct hlist_node *seq_node;
941 struct name_seq *seq;
942 int all_types;
943 u32 depth;
944 u32 i;
945
946 all_types = (depth_info & TIPC_NTQ_ALLTYPES);
947 depth = (depth_info & ~TIPC_NTQ_ALLTYPES);
948
949 if (depth == 0)
950 return;
951
952 if (all_types) {
953 /* display all entries in name table to specified depth */
954 nametbl_header(buf, depth);
955 lowbound = 0;
956 upbound = ~0;
957 for (i = 0; i < tipc_nametbl_size; i++) {
958 seq_head = &table.types[i];
959 hlist_for_each_entry(seq, seq_node, seq_head, ns_list) {
960 nameseq_list(seq, buf, depth, seq->type,
961 lowbound, upbound, i);
962 }
963 }
964 } else {
965 /* display only the sequence that matches the specified type */
966 if (upbound < lowbound) {
967 tipc_printf(buf, "invalid name sequence specified\n");
968 return;
969 }
970 nametbl_header(buf, depth);
971 i = hash(type);
972 seq_head = &table.types[i];
973 hlist_for_each_entry(seq, seq_node, seq_head, ns_list) {
974 if (seq->type == type) {
975 nameseq_list(seq, buf, depth, type,
976 lowbound, upbound, i);
977 break;
978 }
979 }
980 }
981}
982
983void nametbl_print(struct print_buf *buf, const char *str)
984{
985 tipc_printf(buf, str);
986 read_lock_bh(&nametbl_lock);
987 nametbl_list(buf, 0, 0, 0, 0);
988 read_unlock_bh(&nametbl_lock);
989}
990
991#define MAX_NAME_TBL_QUERY 32768
992
993struct sk_buff *nametbl_get(const void *req_tlv_area, int req_tlv_space)
994{
995 struct sk_buff *buf;
996 struct tipc_name_table_query *argv;
997 struct tlv_desc *rep_tlv;
998 struct print_buf b;
999 int str_len;
1000
1001 if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_NAME_TBL_QUERY))
1002 return cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
1003
1004 buf = cfg_reply_alloc(TLV_SPACE(MAX_NAME_TBL_QUERY));
1005 if (!buf)
1006 return NULL;
1007
1008 rep_tlv = (struct tlv_desc *)buf->data;
1009 printbuf_init(&b, TLV_DATA(rep_tlv), MAX_NAME_TBL_QUERY);
1010 argv = (struct tipc_name_table_query *)TLV_DATA(req_tlv_area);
1011 read_lock_bh(&nametbl_lock);
1012 nametbl_list(&b, ntohl(argv->depth), ntohl(argv->type),
1013 ntohl(argv->lowbound), ntohl(argv->upbound));
1014 read_unlock_bh(&nametbl_lock);
1015 str_len = printbuf_validate(&b);
1016
1017 skb_put(buf, TLV_SPACE(str_len));
1018 TLV_SET(rep_tlv, TIPC_TLV_ULTRA_STRING, NULL, str_len);
1019
1020 return buf;
1021}
1022
1023void nametbl_dump(void)
1024{
1025 nametbl_list(CONS, 0, 0, 0, 0);
1026}
1027
1028int nametbl_init(void)
1029{
1030 int array_size = sizeof(struct hlist_head) * tipc_nametbl_size;
1031
1032 table.types = (struct hlist_head *)kmalloc(array_size, GFP_ATOMIC);
1033 if (!table.types)
1034 return -ENOMEM;
1035
1036 write_lock_bh(&nametbl_lock);
1037 memset(table.types, 0, array_size);
1038 table.local_publ_count = 0;
1039 write_unlock_bh(&nametbl_lock);
1040 return 0;
1041}
1042
1043void nametbl_stop(void)
1044{
1045 struct hlist_head *seq_head;
1046 struct hlist_node *seq_node;
1047 struct hlist_node *tmp;
1048 struct name_seq *seq;
1049 u32 i;
1050
1051 if (!table.types)
1052 return;
1053
1054 write_lock_bh(&nametbl_lock);
1055 for (i = 0; i < tipc_nametbl_size; i++) {
1056 seq_head = &table.types[i];
1057 hlist_for_each_entry_safe(seq, seq_node, tmp, seq_head, ns_list) {
1058 struct sub_seq *sseq = seq->sseqs;
1059
1060 for (; sseq != &seq->sseqs[seq->first_free]; sseq++) {
1061 struct publication *publ = sseq->zone_list;
1062 assert(publ);
1063 do {
1064 struct publication *next =
1065 publ->zone_list_next;
1066 kfree(publ);
1067 publ = next;
1068 }
1069 while (publ != sseq->zone_list);
1070 }
1071 }
1072 }
1073 kfree(table.types);
1074 table.types = NULL;
1075 write_unlock_bh(&nametbl_lock);
1076}
diff --git a/net/tipc/name_table.h b/net/tipc/name_table.h
new file mode 100644
index 000000000000..5036b5bac360
--- /dev/null
+++ b/net/tipc/name_table.h
@@ -0,0 +1,105 @@
1/*
2 * net/tipc/name_table.h: Include file for TIPC name table code
3 *
4 * Copyright (c) 2003-2005, Ericsson Research Canada
5 * Copyright (c) 2004-2005, Wind River Systems
6 * Copyright (c) 2005-2006, Ericsson AB
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions are met:
11 *
12 * Redistributions of source code must retain the above copyright notice, this
13 * list of conditions and the following disclaimer.
14 * Redistributions in binary form must reproduce the above copyright notice,
15 * this list of conditions and the following disclaimer in the documentation
16 * and/or other materials provided with the distribution.
17 * Neither the names of the copyright holders nor the names of its
18 * contributors may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 */
33
34#ifndef _TIPC_NAME_TABLE_H
35#define _TIPC_NAME_TABLE_H
36
37#include "node_subscr.h"
38
39struct subscription;
40struct port_list;
41
42/*
43 * TIPC name types reserved for internal TIPC use (both current and planned)
44 */
45
46#define TIPC_ZM_SRV 3 /* zone master service name type */
47
48
49/**
50 * struct publication - info about a published (name or) name sequence
51 * @type: name sequence type
52 * @lower: name sequence lower bound
53 * @upper: name sequence upper bound
54 * @scope: scope of publication
55 * @node: network address of publishing port's node
56 * @ref: publishing port
57 * @key: publication key
58 * @subscr: subscription to "node down" event (for off-node publications only)
59 * @local_list: adjacent entries in list of publications made by this node
60 * @pport_list: adjacent entries in list of publications made by this port
61 * @node_list: next matching name seq publication with >= node scope
62 * @cluster_list: next matching name seq publication with >= cluster scope
63 * @zone_list: next matching name seq publication with >= zone scope
64 *
65 * Note that the node list, cluster list, and zone list are circular lists.
66 */
67
68struct publication {
69 u32 type;
70 u32 lower;
71 u32 upper;
72 u32 scope;
73 u32 node;
74 u32 ref;
75 u32 key;
76 struct node_subscr subscr;
77 struct list_head local_list;
78 struct list_head pport_list;
79 struct publication *node_list_next;
80 struct publication *cluster_list_next;
81 struct publication *zone_list_next;
82};
83
84
85extern rwlock_t nametbl_lock;
86
87struct sk_buff *nametbl_get(const void *req_tlv_area, int req_tlv_space);
88u32 nametbl_translate(u32 type, u32 instance, u32 *node);
89int nametbl_mc_translate(u32 type, u32 lower, u32 upper, u32 limit,
90 struct port_list *dports);
91int nametbl_publish_rsv(u32 ref, unsigned int scope,
92 struct tipc_name_seq const *seq);
93struct publication *nametbl_publish(u32 type, u32 lower, u32 upper,
94 u32 scope, u32 port_ref, u32 key);
95int nametbl_withdraw(u32 type, u32 lower, u32 ref, u32 key);
96struct publication *nametbl_insert_publ(u32 type, u32 lower, u32 upper,
97 u32 scope, u32 node, u32 ref, u32 key);
98struct publication *nametbl_remove_publ(u32 type, u32 lower,
99 u32 node, u32 ref, u32 key);
100void nametbl_subscribe(struct subscription *s);
101void nametbl_unsubscribe(struct subscription *s);
102int nametbl_init(void);
103void nametbl_stop(void);
104
105#endif
diff --git a/net/tipc/net.c b/net/tipc/net.c
new file mode 100644
index 000000000000..eba88033b90e
--- /dev/null
+++ b/net/tipc/net.c
@@ -0,0 +1,308 @@
1/*
2 * net/tipc/net.c: TIPC network routing code
3 *
4 * Copyright (c) 2003-2005, Ericsson Research Canada
5 * Copyright (c) 2005, Wind River Systems
6 * Copyright (c) 2005-2006, Ericsson AB
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions are met:
11 *
12 * Redistributions of source code must retain the above copyright notice, this
13 * list of conditions and the following disclaimer.
14 * Redistributions in binary form must reproduce the above copyright notice,
15 * this list of conditions and the following disclaimer in the documentation
16 * and/or other materials provided with the distribution.
17 * Neither the names of the copyright holders nor the names of its
18 * contributors may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 */
33
34#include "core.h"
35#include "bearer.h"
36#include "net.h"
37#include "zone.h"
38#include "addr.h"
39#include "name_table.h"
40#include "name_distr.h"
41#include "subscr.h"
42#include "link.h"
43#include "msg.h"
44#include "port.h"
45#include "bcast.h"
46#include "discover.h"
47#include "config.h"
48
49/*
50 * The TIPC locking policy is designed to ensure a very fine locking
51 * granularity, permitting complete parallel access to individual
52 * port and node/link instances. The code consists of three major
53 * locking domains, each protected with their own disjunct set of locks.
54 *
55 * 1: The routing hierarchy.
56 * Comprises the structures 'zone', 'cluster', 'node', 'link'
57 * and 'bearer'. The whole hierarchy is protected by a big
58 * read/write lock, net_lock, to enssure that nothing is added
59 * or removed while code is accessing any of these structures.
60 * This layer must not be called from the two others while they
61 * hold any of their own locks.
62 * Neither must it itself do any upcalls to the other two before
63 * it has released net_lock and other protective locks.
64 *
65 * Within the net_lock domain there are two sub-domains;'node' and
66 * 'bearer', where local write operations are permitted,
67 * provided that those are protected by individual spin_locks
68 * per instance. Code holding net_lock(read) and a node spin_lock
69 * is permitted to poke around in both the node itself and its
70 * subordinate links. I.e, it can update link counters and queues,
71 * change link state, send protocol messages, and alter the
72 * "active_links" array in the node; but it can _not_ remove a link
73 * or a node from the overall structure.
74 * Correspondingly, individual bearers may change status within a
75 * net_lock(read), protected by an individual spin_lock ber bearer
76 * instance, but it needs net_lock(write) to remove/add any bearers.
77 *
78 *
79 * 2: The transport level of the protocol.
80 * This consists of the structures port, (and its user level
81 * representations, such as user_port and tipc_sock), reference and
82 * tipc_user (port.c, reg.c, socket.c).
83 *
84 * This layer has four different locks:
85 * - The tipc_port spin_lock. This is protecting each port instance
86 * from parallel data access and removal. Since we can not place
87 * this lock in the port itself, it has been placed in the
88 * corresponding reference table entry, which has the same life
89 * cycle as the module. This entry is difficult to access from
90 * outside the TIPC core, however, so a pointer to the lock has
91 * been added in the port instance, -to be used for unlocking
92 * only.
93 * - A read/write lock to protect the reference table itself (teg.c).
94 * (Nobody is using read-only access to this, so it can just as
95 * well be changed to a spin_lock)
96 * - A spin lock to protect the registry of kernel/driver users (reg.c)
97 * - A global spin_lock (port_lock), which only task is to ensure
98 * consistency where more than one port is involved in an operation,
99 * i.e., whe a port is part of a linked list of ports.
100 * There are two such lists; 'port_list', which is used for management,
101 * and 'wait_list', which is used to queue ports during congestion.
102 *
103 * 3: The name table (name_table.c, name_distr.c, subscription.c)
104 * - There is one big read/write-lock (nametbl_lock) protecting the
105 * overall name table structure. Nothing must be added/removed to
106 * this structure without holding write access to it.
107 * - There is one local spin_lock per sub_sequence, which can be seen
108 * as a sub-domain to the nametbl_lock domain. It is used only
109 * for translation operations, and is needed because a translation
110 * steps the root of the 'publication' linked list between each lookup.
111 * This is always used within the scope of a nametbl_lock(read).
112 * - A local spin_lock protecting the queue of subscriber events.
113*/
114
115rwlock_t net_lock = RW_LOCK_UNLOCKED;
116struct network net = { 0 };
117
118struct node *net_select_remote_node(u32 addr, u32 ref)
119{
120 return zone_select_remote_node(net.zones[tipc_zone(addr)], addr, ref);
121}
122
123u32 net_select_router(u32 addr, u32 ref)
124{
125 return zone_select_router(net.zones[tipc_zone(addr)], addr, ref);
126}
127
128
129u32 net_next_node(u32 a)
130{
131 if (net.zones[tipc_zone(a)])
132 return zone_next_node(a);
133 return 0;
134}
135
136void net_remove_as_router(u32 router)
137{
138 u32 z_num;
139
140 for (z_num = 1; z_num <= tipc_max_zones; z_num++) {
141 if (!net.zones[z_num])
142 continue;
143 zone_remove_as_router(net.zones[z_num], router);
144 }
145}
146
147void net_send_external_routes(u32 dest)
148{
149 u32 z_num;
150
151 for (z_num = 1; z_num <= tipc_max_zones; z_num++) {
152 if (net.zones[z_num])
153 zone_send_external_routes(net.zones[z_num], dest);
154 }
155}
156
157int net_init(void)
158{
159 u32 sz = sizeof(struct _zone *) * (tipc_max_zones + 1);
160
161 memset(&net, 0, sizeof(net));
162 net.zones = (struct _zone **)kmalloc(sz, GFP_ATOMIC);
163 if (!net.zones) {
164 return -ENOMEM;
165 }
166 memset(net.zones, 0, sz);
167 return TIPC_OK;
168}
169
170void net_stop(void)
171{
172 u32 z_num;
173
174 if (!net.zones)
175 return;
176
177 for (z_num = 1; z_num <= tipc_max_zones; z_num++) {
178 zone_delete(net.zones[z_num]);
179 }
180 kfree(net.zones);
181 net.zones = 0;
182}
183
184static void net_route_named_msg(struct sk_buff *buf)
185{
186 struct tipc_msg *msg = buf_msg(buf);
187 u32 dnode;
188 u32 dport;
189
190 if (!msg_named(msg)) {
191 msg_dbg(msg, "net->drop_nam:");
192 buf_discard(buf);
193 return;
194 }
195
196 dnode = addr_domain(msg_lookup_scope(msg));
197 dport = nametbl_translate(msg_nametype(msg), msg_nameinst(msg), &dnode);
198 dbg("net->lookup<%u,%u>-><%u,%x>\n",
199 msg_nametype(msg), msg_nameinst(msg), dport, dnode);
200 if (dport) {
201 msg_set_destnode(msg, dnode);
202 msg_set_destport(msg, dport);
203 net_route_msg(buf);
204 return;
205 }
206 msg_dbg(msg, "net->rej:NO NAME: ");
207 tipc_reject_msg(buf, TIPC_ERR_NO_NAME);
208}
209
210void net_route_msg(struct sk_buff *buf)
211{
212 struct tipc_msg *msg;
213 u32 dnode;
214
215 if (!buf)
216 return;
217 msg = buf_msg(buf);
218
219 msg_incr_reroute_cnt(msg);
220 if (msg_reroute_cnt(msg) > 6) {
221 if (msg_errcode(msg)) {
222 msg_dbg(msg, "NET>DISC>:");
223 buf_discard(buf);
224 } else {
225 msg_dbg(msg, "NET>REJ>:");
226 tipc_reject_msg(buf, msg_destport(msg) ?
227 TIPC_ERR_NO_PORT : TIPC_ERR_NO_NAME);
228 }
229 return;
230 }
231
232 msg_dbg(msg, "net->rout: ");
233
234 /* Handle message for this node */
235 dnode = msg_short(msg) ? tipc_own_addr : msg_destnode(msg);
236 if (in_scope(dnode, tipc_own_addr)) {
237 if (msg_isdata(msg)) {
238 if (msg_mcast(msg))
239 port_recv_mcast(buf, NULL);
240 else if (msg_destport(msg))
241 port_recv_msg(buf);
242 else
243 net_route_named_msg(buf);
244 return;
245 }
246 switch (msg_user(msg)) {
247 case ROUTE_DISTRIBUTOR:
248 cluster_recv_routing_table(buf);
249 break;
250 case NAME_DISTRIBUTOR:
251 named_recv(buf);
252 break;
253 case CONN_MANAGER:
254 port_recv_proto_msg(buf);
255 break;
256 default:
257 msg_dbg(msg,"DROP/NET/<REC<");
258 buf_discard(buf);
259 }
260 return;
261 }
262
263 /* Handle message for another node */
264 msg_dbg(msg, "NET>SEND>: ");
265 link_send(buf, dnode, msg_link_selector(msg));
266}
267
268int tipc_start_net(void)
269{
270 char addr_string[16];
271 int res;
272
273 if (tipc_mode != TIPC_NODE_MODE)
274 return -ENOPROTOOPT;
275
276 tipc_mode = TIPC_NET_MODE;
277 named_reinit();
278 port_reinit();
279
280 if ((res = bearer_init()) ||
281 (res = net_init()) ||
282 (res = cluster_init()) ||
283 (res = bclink_init())) {
284 return res;
285 }
286 subscr_stop();
287 cfg_stop();
288 k_signal((Handler)subscr_start, 0);
289 k_signal((Handler)cfg_init, 0);
290 info("Started in network mode\n");
291 info("Own node address %s, network identity %u\n",
292 addr_string_fill(addr_string, tipc_own_addr), tipc_net_id);
293 return TIPC_OK;
294}
295
296void tipc_stop_net(void)
297{
298 if (tipc_mode != TIPC_NET_MODE)
299 return;
300 write_lock_bh(&net_lock);
301 bearer_stop();
302 tipc_mode = TIPC_NODE_MODE;
303 bclink_stop();
304 net_stop();
305 write_unlock_bh(&net_lock);
306 info("Left network mode \n");
307}
308
diff --git a/net/tipc/net.h b/net/tipc/net.h
new file mode 100644
index 000000000000..50098455a898
--- /dev/null
+++ b/net/tipc/net.h
@@ -0,0 +1,63 @@
1/*
2 * net/tipc/net.h: Include file for TIPC network routing code
3 *
4 * Copyright (c) 2003-2005, Ericsson Research Canada
5 * Copyright (c) 2005, Wind River Systems
6 * Copyright (c) 2005-2006, Ericsson AB
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions are met:
11 *
12 * Redistributions of source code must retain the above copyright notice, this
13 * list of conditions and the following disclaimer.
14 * Redistributions in binary form must reproduce the above copyright notice,
15 * this list of conditions and the following disclaimer in the documentation
16 * and/or other materials provided with the distribution.
17 * Neither the names of the copyright holders nor the names of its
18 * contributors may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 */
33
34#ifndef _TIPC_NET_H
35#define _TIPC_NET_H
36
37struct _zone;
38
39/**
40 * struct network - TIPC network structure
41 * @zones: array of pointers to all zones within network
42 */
43
44struct network {
45 struct _zone **zones;
46};
47
48
49extern struct network net;
50extern rwlock_t net_lock;
51
52int net_init(void);
53void net_stop(void);
54void net_remove_as_router(u32 router);
55void net_send_external_routes(u32 dest);
56void net_route_msg(struct sk_buff *buf);
57struct node *net_select_remote_node(u32 addr, u32 ref);
58u32 net_select_router(u32 addr, u32 ref);
59
60int tipc_start_net(void);
61void tipc_stop_net(void);
62
63#endif
diff --git a/net/tipc/netlink.c b/net/tipc/netlink.c
new file mode 100644
index 000000000000..35fbc7933604
--- /dev/null
+++ b/net/tipc/netlink.c
@@ -0,0 +1,107 @@
1/*
2 * net/tipc/netlink.c: TIPC configuration handling
3 *
4 * Copyright (c) 2005, Wind River Systems
5 * Copyright (c) 2005-2006, Ericsson AB
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are met:
10 *
11 * Redistributions of source code must retain the above copyright notice, this
12 * list of conditions and the following disclaimer.
13 * Redistributions in binary form must reproduce the above copyright notice,
14 * this list of conditions and the following disclaimer in the documentation
15 * and/or other materials provided with the distribution.
16 * Neither the names of the copyright holders nor the names of its
17 * contributors may be used to endorse or promote products derived from this
18 * software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 */
32
33#include "core.h"
34#include "config.h"
35#include <net/genetlink.h>
36
37static int handle_cmd(struct sk_buff *skb, struct genl_info *info)
38{
39 struct sk_buff *rep_buf;
40 struct nlmsghdr *rep_nlh;
41 struct nlmsghdr *req_nlh = info->nlhdr;
42 struct tipc_genlmsghdr *req_userhdr = info->userhdr;
43 int hdr_space = NLMSG_SPACE(0);
44
45 if ((req_userhdr->cmd & 0xC000) && (!capable(CAP_NET_ADMIN)))
46 rep_buf = cfg_reply_error_string(TIPC_CFG_NOT_NET_ADMIN);
47 else
48 rep_buf = cfg_do_cmd(req_userhdr->dest,
49 req_userhdr->cmd,
50 NLMSG_DATA(req_nlh) + GENL_HDRLEN + TIPC_GENL_HDRLEN,
51 NLMSG_PAYLOAD(req_nlh, GENL_HDRLEN + TIPC_GENL_HDRLEN),
52 hdr_space);
53
54 if (rep_buf) {
55 skb_push(rep_buf, hdr_space);
56 rep_nlh = (struct nlmsghdr *)rep_buf->data;
57 memcpy(rep_nlh, req_nlh, hdr_space);
58 rep_nlh->nlmsg_len = rep_buf->len;
59 genlmsg_unicast(rep_buf, req_nlh->nlmsg_pid);
60 }
61
62 return 0;
63}
64
65static struct genl_family family = {
66 .id = TIPC_GENL_FAMILY,
67 .name = TIPC_GENL_NAME,
68 .version = TIPC_GENL_VERSION,
69 .hdrsize = TIPC_GENL_HDRLEN,
70 .maxattr = 0,
71 .owner = THIS_MODULE,
72};
73
74static struct genl_ops ops = {
75 .cmd = TIPC_GENL_CMD,
76 .doit = handle_cmd,
77};
78
79static int family_registered = 0;
80
81int netlink_start(void)
82{
83 if (genl_register_family(&family))
84 goto err;
85
86 family_registered = 1;
87
88 if (genl_register_ops(&family, &ops))
89 goto err_unregister;
90
91 return 0;
92
93 err_unregister:
94 genl_unregister_family(&family);
95 family_registered = 0;
96 err:
97 err("Failed to register netlink interface");
98 return -EFAULT;
99}
100
101void netlink_stop(void)
102{
103 if (family_registered) {
104 genl_unregister_family(&family);
105 family_registered = 0;
106 }
107}
diff --git a/net/tipc/node.c b/net/tipc/node.c
new file mode 100644
index 000000000000..e311638b9b3d
--- /dev/null
+++ b/net/tipc/node.c
@@ -0,0 +1,676 @@
1/*
2 * net/tipc/node.c: TIPC node management routines
3 *
4 * Copyright (c) 2003-2005, Ericsson Research Canada
5 * Copyright (c) 2005, Wind River Systems
6 * Copyright (c) 2005-2006, Ericsson AB
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions are met:
11 *
12 * Redistributions of source code must retain the above copyright notice, this
13 * list of conditions and the following disclaimer.
14 * Redistributions in binary form must reproduce the above copyright notice,
15 * this list of conditions and the following disclaimer in the documentation
16 * and/or other materials provided with the distribution.
17 * Neither the names of the copyright holders nor the names of its
18 * contributors may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 */
33
34#include "core.h"
35#include "config.h"
36#include "node.h"
37#include "cluster.h"
38#include "net.h"
39#include "addr.h"
40#include "node_subscr.h"
41#include "link.h"
42#include "port.h"
43#include "bearer.h"
44#include "name_distr.h"
45#include "net.h"
46
47void node_print(struct print_buf *buf, struct node *n_ptr, char *str);
48static void node_lost_contact(struct node *n_ptr);
49static void node_established_contact(struct node *n_ptr);
50
51struct node *nodes = NULL; /* sorted list of nodes within cluster */
52
53u32 tipc_own_tag = 0;
54
55struct node *node_create(u32 addr)
56{
57 struct cluster *c_ptr;
58 struct node *n_ptr;
59 struct node **curr_node;
60
61 n_ptr = kmalloc(sizeof(*n_ptr),GFP_ATOMIC);
62 if (n_ptr != NULL) {
63 memset(n_ptr, 0, sizeof(*n_ptr));
64 n_ptr->addr = addr;
65 n_ptr->lock = SPIN_LOCK_UNLOCKED;
66 INIT_LIST_HEAD(&n_ptr->nsub);
67
68 c_ptr = cluster_find(addr);
69 if (c_ptr == NULL)
70 c_ptr = cluster_create(addr);
71 if (c_ptr != NULL) {
72 n_ptr->owner = c_ptr;
73 cluster_attach_node(c_ptr, n_ptr);
74 n_ptr->last_router = -1;
75
76 /* Insert node into ordered list */
77 for (curr_node = &nodes; *curr_node;
78 curr_node = &(*curr_node)->next) {
79 if (addr < (*curr_node)->addr) {
80 n_ptr->next = *curr_node;
81 break;
82 }
83 }
84 (*curr_node) = n_ptr;
85 } else {
86 kfree(n_ptr);
87 n_ptr = NULL;
88 }
89 }
90 return n_ptr;
91}
92
93void node_delete(struct node *n_ptr)
94{
95 if (!n_ptr)
96 return;
97
98#if 0
99 /* Not needed because links are already deleted via bearer_stop() */
100
101 u32 l_num;
102
103 for (l_num = 0; l_num < MAX_BEARERS; l_num++) {
104 link_delete(n_ptr->links[l_num]);
105 }
106#endif
107
108 dbg("node %x deleted\n", n_ptr->addr);
109 kfree(n_ptr);
110}
111
112
113/**
114 * node_link_up - handle addition of link
115 *
116 * Link becomes active (alone or shared) or standby, depending on its priority.
117 */
118
119void node_link_up(struct node *n_ptr, struct link *l_ptr)
120{
121 struct link **active = &n_ptr->active_links[0];
122
123 info("Established link <%s> on network plane %c\n",
124 l_ptr->name, l_ptr->b_ptr->net_plane);
125
126 if (!active[0]) {
127 dbg(" link %x into %x/%x\n", l_ptr, &active[0], &active[1]);
128 active[0] = active[1] = l_ptr;
129 node_established_contact(n_ptr);
130 return;
131 }
132 if (l_ptr->priority < active[0]->priority) {
133 info("Link is standby\n");
134 return;
135 }
136 link_send_duplicate(active[0], l_ptr);
137 if (l_ptr->priority == active[0]->priority) {
138 active[0] = l_ptr;
139 return;
140 }
141 info("Link <%s> on network plane %c becomes standby\n",
142 active[0]->name, active[0]->b_ptr->net_plane);
143 active[0] = active[1] = l_ptr;
144}
145
146/**
147 * node_select_active_links - select active link
148 */
149
150static void node_select_active_links(struct node *n_ptr)
151{
152 struct link **active = &n_ptr->active_links[0];
153 u32 i;
154 u32 highest_prio = 0;
155
156 active[0] = active[1] = 0;
157
158 for (i = 0; i < MAX_BEARERS; i++) {
159 struct link *l_ptr = n_ptr->links[i];
160
161 if (!l_ptr || !link_is_up(l_ptr) ||
162 (l_ptr->priority < highest_prio))
163 continue;
164
165 if (l_ptr->priority > highest_prio) {
166 highest_prio = l_ptr->priority;
167 active[0] = active[1] = l_ptr;
168 } else {
169 active[1] = l_ptr;
170 }
171 }
172}
173
174/**
175 * node_link_down - handle loss of link
176 */
177
178void node_link_down(struct node *n_ptr, struct link *l_ptr)
179{
180 struct link **active;
181
182 if (!link_is_active(l_ptr)) {
183 info("Lost standby link <%s> on network plane %c\n",
184 l_ptr->name, l_ptr->b_ptr->net_plane);
185 return;
186 }
187 info("Lost link <%s> on network plane %c\n",
188 l_ptr->name, l_ptr->b_ptr->net_plane);
189
190 active = &n_ptr->active_links[0];
191 if (active[0] == l_ptr)
192 active[0] = active[1];
193 if (active[1] == l_ptr)
194 active[1] = active[0];
195 if (active[0] == l_ptr)
196 node_select_active_links(n_ptr);
197 if (node_is_up(n_ptr))
198 link_changeover(l_ptr);
199 else
200 node_lost_contact(n_ptr);
201}
202
203int node_has_active_links(struct node *n_ptr)
204{
205 return (n_ptr &&
206 ((n_ptr->active_links[0]) || (n_ptr->active_links[1])));
207}
208
209int node_has_redundant_links(struct node *n_ptr)
210{
211 return (node_has_active_links(n_ptr) &&
212 (n_ptr->active_links[0] != n_ptr->active_links[1]));
213}
214
215int node_has_active_routes(struct node *n_ptr)
216{
217 return (n_ptr && (n_ptr->last_router >= 0));
218}
219
220int node_is_up(struct node *n_ptr)
221{
222 return (node_has_active_links(n_ptr) || node_has_active_routes(n_ptr));
223}
224
225struct node *node_attach_link(struct link *l_ptr)
226{
227 struct node *n_ptr = node_find(l_ptr->addr);
228
229 if (!n_ptr)
230 n_ptr = node_create(l_ptr->addr);
231 if (n_ptr) {
232 u32 bearer_id = l_ptr->b_ptr->identity;
233 char addr_string[16];
234
235 assert(bearer_id < MAX_BEARERS);
236 if (n_ptr->link_cnt >= 2) {
237 char addr_string[16];
238
239 err("Attempt to create third link to %s\n",
240 addr_string_fill(addr_string, n_ptr->addr));
241 return 0;
242 }
243
244 if (!n_ptr->links[bearer_id]) {
245 n_ptr->links[bearer_id] = l_ptr;
246 net.zones[tipc_zone(l_ptr->addr)]->links++;
247 n_ptr->link_cnt++;
248 return n_ptr;
249 }
250 err("Attempt to establish second link on <%s> to <%s> \n",
251 l_ptr->b_ptr->publ.name,
252 addr_string_fill(addr_string, l_ptr->addr));
253 }
254 return 0;
255}
256
257void node_detach_link(struct node *n_ptr, struct link *l_ptr)
258{
259 n_ptr->links[l_ptr->b_ptr->identity] = 0;
260 net.zones[tipc_zone(l_ptr->addr)]->links--;
261 n_ptr->link_cnt--;
262}
263
264/*
265 * Routing table management - five cases to handle:
266 *
267 * 1: A link towards a zone/cluster external node comes up.
268 * => Send a multicast message updating routing tables of all
269 * system nodes within own cluster that the new destination
270 * can be reached via this node.
271 * (node.establishedContact()=>cluster.multicastNewRoute())
272 *
273 * 2: A link towards a slave node comes up.
274 * => Send a multicast message updating routing tables of all
275 * system nodes within own cluster that the new destination
276 * can be reached via this node.
277 * (node.establishedContact()=>cluster.multicastNewRoute())
278 * => Send a message to the slave node about existence
279 * of all system nodes within cluster:
280 * (node.establishedContact()=>cluster.sendLocalRoutes())
281 *
282 * 3: A new cluster local system node becomes available.
283 * => Send message(s) to this particular node containing
284 * information about all cluster external and slave
285 * nodes which can be reached via this node.
286 * (node.establishedContact()==>network.sendExternalRoutes())
287 * (node.establishedContact()==>network.sendSlaveRoutes())
288 * => Send messages to all directly connected slave nodes
289 * containing information about the existence of the new node
290 * (node.establishedContact()=>cluster.multicastNewRoute())
291 *
292 * 4: The link towards a zone/cluster external node or slave
293 * node goes down.
294 * => Send a multcast message updating routing tables of all
295 * nodes within cluster that the new destination can not any
296 * longer be reached via this node.
297 * (node.lostAllLinks()=>cluster.bcastLostRoute())
298 *
299 * 5: A cluster local system node becomes unavailable.
300 * => Remove all references to this node from the local
301 * routing tables. Note: This is a completely node
302 * local operation.
303 * (node.lostAllLinks()=>network.removeAsRouter())
304 * => Send messages to all directly connected slave nodes
305 * containing information about loss of the node
306 * (node.establishedContact()=>cluster.multicastLostRoute())
307 *
308 */
309
310static void node_established_contact(struct node *n_ptr)
311{
312 struct cluster *c_ptr;
313
314 dbg("node_established_contact:-> %x\n", n_ptr->addr);
315 if (!node_has_active_routes(n_ptr)) {
316 k_signal((Handler)named_node_up, n_ptr->addr);
317 }
318
319 /* Syncronize broadcast acks */
320 n_ptr->bclink.acked = bclink_get_last_sent();
321
322 if (is_slave(tipc_own_addr))
323 return;
324 if (!in_own_cluster(n_ptr->addr)) {
325 /* Usage case 1 (see above) */
326 c_ptr = cluster_find(tipc_own_addr);
327 if (!c_ptr)
328 c_ptr = cluster_create(tipc_own_addr);
329 if (c_ptr)
330 cluster_bcast_new_route(c_ptr, n_ptr->addr, 1,
331 tipc_max_nodes);
332 return;
333 }
334
335 c_ptr = n_ptr->owner;
336 if (is_slave(n_ptr->addr)) {
337 /* Usage case 2 (see above) */
338 cluster_bcast_new_route(c_ptr, n_ptr->addr, 1, tipc_max_nodes);
339 cluster_send_local_routes(c_ptr, n_ptr->addr);
340 return;
341 }
342
343 if (n_ptr->bclink.supported) {
344 nmap_add(&cluster_bcast_nodes, n_ptr->addr);
345 if (n_ptr->addr < tipc_own_addr)
346 tipc_own_tag++;
347 }
348
349 /* Case 3 (see above) */
350 net_send_external_routes(n_ptr->addr);
351 cluster_send_slave_routes(c_ptr, n_ptr->addr);
352 cluster_bcast_new_route(c_ptr, n_ptr->addr, LOWEST_SLAVE,
353 highest_allowed_slave);
354}
355
356static void node_lost_contact(struct node *n_ptr)
357{
358 struct cluster *c_ptr;
359 struct node_subscr *ns, *tns;
360 char addr_string[16];
361 u32 i;
362
363 /* Clean up broadcast reception remains */
364 n_ptr->bclink.gap_after = n_ptr->bclink.gap_to = 0;
365 while (n_ptr->bclink.deferred_head) {
366 struct sk_buff* buf = n_ptr->bclink.deferred_head;
367 n_ptr->bclink.deferred_head = buf->next;
368 buf_discard(buf);
369 }
370 if (n_ptr->bclink.defragm) {
371 buf_discard(n_ptr->bclink.defragm);
372 n_ptr->bclink.defragm = NULL;
373 }
374 if (in_own_cluster(n_ptr->addr) && n_ptr->bclink.supported) {
375 bclink_acknowledge(n_ptr, mod(n_ptr->bclink.acked + 10000));
376 }
377
378 /* Update routing tables */
379 if (is_slave(tipc_own_addr)) {
380 net_remove_as_router(n_ptr->addr);
381 } else {
382 if (!in_own_cluster(n_ptr->addr)) {
383 /* Case 4 (see above) */
384 c_ptr = cluster_find(tipc_own_addr);
385 cluster_bcast_lost_route(c_ptr, n_ptr->addr, 1,
386 tipc_max_nodes);
387 } else {
388 /* Case 5 (see above) */
389 c_ptr = cluster_find(n_ptr->addr);
390 if (is_slave(n_ptr->addr)) {
391 cluster_bcast_lost_route(c_ptr, n_ptr->addr, 1,
392 tipc_max_nodes);
393 } else {
394 if (n_ptr->bclink.supported) {
395 nmap_remove(&cluster_bcast_nodes,
396 n_ptr->addr);
397 if (n_ptr->addr < tipc_own_addr)
398 tipc_own_tag--;
399 }
400 net_remove_as_router(n_ptr->addr);
401 cluster_bcast_lost_route(c_ptr, n_ptr->addr,
402 LOWEST_SLAVE,
403 highest_allowed_slave);
404 }
405 }
406 }
407 if (node_has_active_routes(n_ptr))
408 return;
409
410 info("Lost contact with %s\n",
411 addr_string_fill(addr_string, n_ptr->addr));
412
413 /* Abort link changeover */
414 for (i = 0; i < MAX_BEARERS; i++) {
415 struct link *l_ptr = n_ptr->links[i];
416 if (!l_ptr)
417 continue;
418 l_ptr->reset_checkpoint = l_ptr->next_in_no;
419 l_ptr->exp_msg_count = 0;
420 link_reset_fragments(l_ptr);
421 }
422
423 /* Notify subscribers */
424 list_for_each_entry_safe(ns, tns, &n_ptr->nsub, nodesub_list) {
425 ns->node = 0;
426 list_del_init(&ns->nodesub_list);
427 k_signal((Handler)ns->handle_node_down,
428 (unsigned long)ns->usr_handle);
429 }
430}
431
432/**
433 * node_select_next_hop - find the next-hop node for a message
434 *
435 * Called by when cluster local lookup has failed.
436 */
437
438struct node *node_select_next_hop(u32 addr, u32 selector)
439{
440 struct node *n_ptr;
441 u32 router_addr;
442
443 if (!addr_domain_valid(addr))
444 return 0;
445
446 /* Look for direct link to destination processsor */
447 n_ptr = node_find(addr);
448 if (n_ptr && node_has_active_links(n_ptr))
449 return n_ptr;
450
451 /* Cluster local system nodes *must* have direct links */
452 if (!is_slave(addr) && in_own_cluster(addr))
453 return 0;
454
455 /* Look for cluster local router with direct link to node */
456 router_addr = node_select_router(n_ptr, selector);
457 if (router_addr)
458 return node_select(router_addr, selector);
459
460 /* Slave nodes can only be accessed within own cluster via a
461 known router with direct link -- if no router was found,give up */
462 if (is_slave(addr))
463 return 0;
464
465 /* Inter zone/cluster -- find any direct link to remote cluster */
466 addr = tipc_addr(tipc_zone(addr), tipc_cluster(addr), 0);
467 n_ptr = net_select_remote_node(addr, selector);
468 if (n_ptr && node_has_active_links(n_ptr))
469 return n_ptr;
470
471 /* Last resort -- look for any router to anywhere in remote zone */
472 router_addr = net_select_router(addr, selector);
473 if (router_addr)
474 return node_select(router_addr, selector);
475
476 return 0;
477}
478
479/**
480 * node_select_router - select router to reach specified node
481 *
482 * Uses a deterministic and fair algorithm for selecting router node.
483 */
484
485u32 node_select_router(struct node *n_ptr, u32 ref)
486{
487 u32 ulim;
488 u32 mask;
489 u32 start;
490 u32 r;
491
492 if (!n_ptr)
493 return 0;
494
495 if (n_ptr->last_router < 0)
496 return 0;
497 ulim = ((n_ptr->last_router + 1) * 32) - 1;
498
499 /* Start entry must be random */
500 mask = tipc_max_nodes;
501 while (mask > ulim)
502 mask >>= 1;
503 start = ref & mask;
504 r = start;
505
506 /* Lookup upwards with wrap-around */
507 do {
508 if (((n_ptr->routers[r / 32]) >> (r % 32)) & 1)
509 break;
510 } while (++r <= ulim);
511 if (r > ulim) {
512 r = 1;
513 do {
514 if (((n_ptr->routers[r / 32]) >> (r % 32)) & 1)
515 break;
516 } while (++r < start);
517 assert(r != start);
518 }
519 assert(r && (r <= ulim));
520 return tipc_addr(own_zone(), own_cluster(), r);
521}
522
523void node_add_router(struct node *n_ptr, u32 router)
524{
525 u32 r_num = tipc_node(router);
526
527 n_ptr->routers[r_num / 32] =
528 ((1 << (r_num % 32)) | n_ptr->routers[r_num / 32]);
529 n_ptr->last_router = tipc_max_nodes / 32;
530 while ((--n_ptr->last_router >= 0) &&
531 !n_ptr->routers[n_ptr->last_router]);
532}
533
534void node_remove_router(struct node *n_ptr, u32 router)
535{
536 u32 r_num = tipc_node(router);
537
538 if (n_ptr->last_router < 0)
539 return; /* No routes */
540
541 n_ptr->routers[r_num / 32] =
542 ((~(1 << (r_num % 32))) & (n_ptr->routers[r_num / 32]));
543 n_ptr->last_router = tipc_max_nodes / 32;
544 while ((--n_ptr->last_router >= 0) &&
545 !n_ptr->routers[n_ptr->last_router]);
546
547 if (!node_is_up(n_ptr))
548 node_lost_contact(n_ptr);
549}
550
551#if 0
552void node_print(struct print_buf *buf, struct node *n_ptr, char *str)
553{
554 u32 i;
555
556 tipc_printf(buf, "\n\n%s", str);
557 for (i = 0; i < MAX_BEARERS; i++) {
558 if (!n_ptr->links[i])
559 continue;
560 tipc_printf(buf, "Links[%u]: %x, ", i, n_ptr->links[i]);
561 }
562 tipc_printf(buf, "Active links: [%x,%x]\n",
563 n_ptr->active_links[0], n_ptr->active_links[1]);
564}
565#endif
566
567u32 tipc_available_nodes(const u32 domain)
568{
569 struct node *n_ptr;
570 u32 cnt = 0;
571
572 for (n_ptr = nodes; n_ptr; n_ptr = n_ptr->next) {
573 if (!in_scope(domain, n_ptr->addr))
574 continue;
575 if (node_is_up(n_ptr))
576 cnt++;
577 }
578 return cnt;
579}
580
581struct sk_buff *node_get_nodes(const void *req_tlv_area, int req_tlv_space)
582{
583 u32 domain;
584 struct sk_buff *buf;
585 struct node *n_ptr;
586 struct tipc_node_info node_info;
587
588 if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_NET_ADDR))
589 return cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
590
591 domain = *(u32 *)TLV_DATA(req_tlv_area);
592 domain = ntohl(domain);
593 if (!addr_domain_valid(domain))
594 return cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
595 " (network address)");
596
597 if (!nodes)
598 return cfg_reply_none();
599
600 /* For now, get space for all other nodes
601 (will need to modify this when slave nodes are supported */
602
603 buf = cfg_reply_alloc(TLV_SPACE(sizeof(node_info)) *
604 (tipc_max_nodes - 1));
605 if (!buf)
606 return NULL;
607
608 /* Add TLVs for all nodes in scope */
609
610 for (n_ptr = nodes; n_ptr; n_ptr = n_ptr->next) {
611 if (!in_scope(domain, n_ptr->addr))
612 continue;
613 node_info.addr = htonl(n_ptr->addr);
614 node_info.up = htonl(node_is_up(n_ptr));
615 cfg_append_tlv(buf, TIPC_TLV_NODE_INFO,
616 &node_info, sizeof(node_info));
617 }
618
619 return buf;
620}
621
622struct sk_buff *node_get_links(const void *req_tlv_area, int req_tlv_space)
623{
624 u32 domain;
625 struct sk_buff *buf;
626 struct node *n_ptr;
627 struct tipc_link_info link_info;
628
629 if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_NET_ADDR))
630 return cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
631
632 domain = *(u32 *)TLV_DATA(req_tlv_area);
633 domain = ntohl(domain);
634 if (!addr_domain_valid(domain))
635 return cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
636 " (network address)");
637
638 if (!nodes)
639 return cfg_reply_none();
640
641 /* For now, get space for 2 links to all other nodes + bcast link
642 (will need to modify this when slave nodes are supported */
643
644 buf = cfg_reply_alloc(TLV_SPACE(sizeof(link_info)) *
645 (2 * (tipc_max_nodes - 1) + 1));
646 if (!buf)
647 return NULL;
648
649 /* Add TLV for broadcast link */
650
651 link_info.dest = tipc_own_addr & 0xfffff00;
652 link_info.dest = htonl(link_info.dest);
653 link_info.up = htonl(1);
654 sprintf(link_info.str, bc_link_name);
655 cfg_append_tlv(buf, TIPC_TLV_LINK_INFO, &link_info, sizeof(link_info));
656
657 /* Add TLVs for any other links in scope */
658
659 for (n_ptr = nodes; n_ptr; n_ptr = n_ptr->next) {
660 u32 i;
661
662 if (!in_scope(domain, n_ptr->addr))
663 continue;
664 for (i = 0; i < MAX_BEARERS; i++) {
665 if (!n_ptr->links[i])
666 continue;
667 link_info.dest = htonl(n_ptr->addr);
668 link_info.up = htonl(link_is_up(n_ptr->links[i]));
669 strcpy(link_info.str, n_ptr->links[i]->name);
670 cfg_append_tlv(buf, TIPC_TLV_LINK_INFO,
671 &link_info, sizeof(link_info));
672 }
673 }
674
675 return buf;
676}
diff --git a/net/tipc/node.h b/net/tipc/node.h
new file mode 100644
index 000000000000..1f616873a724
--- /dev/null
+++ b/net/tipc/node.h
@@ -0,0 +1,141 @@
1/*
2 * net/tipc/node.h: Include file for TIPC node management routines
3 *
4 * Copyright (c) 2003-2005, Ericsson Research Canada
5 * Copyright (c) 2005, Wind River Systems
6 * Copyright (c) 2005-2006, Ericsson AB
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions are met:
11 *
12 * Redistributions of source code must retain the above copyright notice, this
13 * list of conditions and the following disclaimer.
14 * Redistributions in binary form must reproduce the above copyright notice,
15 * this list of conditions and the following disclaimer in the documentation
16 * and/or other materials provided with the distribution.
17 * Neither the names of the copyright holders nor the names of its
18 * contributors may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 */
33
34#ifndef _TIPC_NODE_H
35#define _TIPC_NODE_H
36
37#include "node_subscr.h"
38#include "addr.h"
39#include "cluster.h"
40#include "bearer.h"
41
42/**
43 * struct node - TIPC node structure
44 * @addr: network address of node
45 * @lock: spinlock governing access to structure
46 * @owner: pointer to cluster that node belongs to
47 * @next: pointer to next node in sorted list of cluster's nodes
48 * @nsub: list of "node down" subscriptions monitoring node
49 * @active_links: pointers to active links to node
50 * @links: pointers to all links to node
51 * @link_cnt: number of links to node
52 * @permit_changeover: non-zero if node has redundant links to this system
53 * @routers: bitmap (used for multicluster communication)
54 * @last_router: (used for multicluster communication)
55 * @bclink: broadcast-related info
56 * @supported: non-zero if node supports TIPC b'cast capability
57 * @acked: sequence # of last outbound b'cast message acknowledged by node
58 * @last_in: sequence # of last in-sequence b'cast message received from node
59 * @gap_after: sequence # of last message not requiring a NAK request
60 * @gap_to: sequence # of last message requiring a NAK request
61 * @nack_sync: counter that determines when NAK requests should be sent
62 * @deferred_head: oldest OOS b'cast message received from node
63 * @deferred_tail: newest OOS b'cast message received from node
64 * @defragm: list of partially reassembled b'cast message fragments from node
65 */
66
67struct node {
68 u32 addr;
69 spinlock_t lock;
70 struct cluster *owner;
71 struct node *next;
72 struct list_head nsub;
73 struct link *active_links[2];
74 struct link *links[MAX_BEARERS];
75 int link_cnt;
76 int permit_changeover;
77 u32 routers[512/32];
78 int last_router;
79 struct {
80 int supported;
81 u32 acked;
82 u32 last_in;
83 u32 gap_after;
84 u32 gap_to;
85 u32 nack_sync;
86 struct sk_buff *deferred_head;
87 struct sk_buff *deferred_tail;
88 struct sk_buff *defragm;
89 } bclink;
90};
91
92extern struct node *nodes;
93extern u32 tipc_own_tag;
94
95struct node *node_create(u32 addr);
96void node_delete(struct node *n_ptr);
97struct node *node_attach_link(struct link *l_ptr);
98void node_detach_link(struct node *n_ptr, struct link *l_ptr);
99void node_link_down(struct node *n_ptr, struct link *l_ptr);
100void node_link_up(struct node *n_ptr, struct link *l_ptr);
101int node_has_active_links(struct node *n_ptr);
102int node_has_redundant_links(struct node *n_ptr);
103u32 node_select_router(struct node *n_ptr, u32 ref);
104struct node *node_select_next_hop(u32 addr, u32 selector);
105int node_is_up(struct node *n_ptr);
106void node_add_router(struct node *n_ptr, u32 router);
107void node_remove_router(struct node *n_ptr, u32 router);
108struct sk_buff *node_get_links(const void *req_tlv_area, int req_tlv_space);
109struct sk_buff *node_get_nodes(const void *req_tlv_area, int req_tlv_space);
110
111static inline struct node *node_find(u32 addr)
112{
113 if (likely(in_own_cluster(addr)))
114 return local_nodes[tipc_node(addr)];
115 else if (addr_domain_valid(addr)) {
116 struct cluster *c_ptr = cluster_find(addr);
117
118 if (c_ptr)
119 return c_ptr->nodes[tipc_node(addr)];
120 }
121 return 0;
122}
123
124static inline struct node *node_select(u32 addr, u32 selector)
125{
126 if (likely(in_own_cluster(addr)))
127 return local_nodes[tipc_node(addr)];
128 return node_select_next_hop(addr, selector);
129}
130
131static inline void node_lock(struct node *n_ptr)
132{
133 spin_lock_bh(&n_ptr->lock);
134}
135
136static inline void node_unlock(struct node *n_ptr)
137{
138 spin_unlock_bh(&n_ptr->lock);
139}
140
141#endif
diff --git a/net/tipc/node_subscr.c b/net/tipc/node_subscr.c
new file mode 100644
index 000000000000..c38a3b0e847d
--- /dev/null
+++ b/net/tipc/node_subscr.c
@@ -0,0 +1,76 @@
1/*
2 * net/tipc/node_subscr.c: TIPC "node down" subscription handling
3 *
4 * Copyright (c) 2003-2005, Ericsson Research Canada
5 * Copyright (c) 2005, Wind River Systems
6 * Copyright (c) 2005-2006, Ericsson AB
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions are met:
11 *
12 * Redistributions of source code must retain the above copyright notice, this
13 * list of conditions and the following disclaimer.
14 * Redistributions in binary form must reproduce the above copyright notice,
15 * this list of conditions and the following disclaimer in the documentation
16 * and/or other materials provided with the distribution.
17 * Neither the names of the copyright holders nor the names of its
18 * contributors may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 */
33
34#include "core.h"
35#include "dbg.h"
36#include "node_subscr.h"
37#include "node.h"
38#include "addr.h"
39
40/**
41 * nodesub_subscribe - create "node down" subscription for specified node
42 */
43
44void nodesub_subscribe(struct node_subscr *node_sub, u32 addr,
45 void *usr_handle, net_ev_handler handle_down)
46{
47 node_sub->node = 0;
48 if (addr == tipc_own_addr)
49 return;
50 if (!addr_node_valid(addr)) {
51 warn("node_subscr with illegal %x\n", addr);
52 return;
53 }
54
55 node_sub->handle_node_down = handle_down;
56 node_sub->usr_handle = usr_handle;
57 node_sub->node = node_find(addr);
58 assert(node_sub->node);
59 node_lock(node_sub->node);
60 list_add_tail(&node_sub->nodesub_list, &node_sub->node->nsub);
61 node_unlock(node_sub->node);
62}
63
64/**
65 * nodesub_unsubscribe - cancel "node down" subscription (if any)
66 */
67
68void nodesub_unsubscribe(struct node_subscr *node_sub)
69{
70 if (!node_sub->node)
71 return;
72
73 node_lock(node_sub->node);
74 list_del_init(&node_sub->nodesub_list);
75 node_unlock(node_sub->node);
76}
diff --git a/net/tipc/node_subscr.h b/net/tipc/node_subscr.h
new file mode 100644
index 000000000000..63ae92e0c82e
--- /dev/null
+++ b/net/tipc/node_subscr.h
@@ -0,0 +1,60 @@
1/*
2 * net/tipc/node_subscr.h: Include file for TIPC "node down" subscription handling
3 *
4 * Copyright (c) 2003-2005, Ericsson Research Canada
5 * Copyright (c) 2005, Wind River Systems
6 * Copyright (c) 2005-2006, Ericsson AB
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions are met:
11 *
12 * Redistributions of source code must retain the above copyright notice, this
13 * list of conditions and the following disclaimer.
14 * Redistributions in binary form must reproduce the above copyright notice,
15 * this list of conditions and the following disclaimer in the documentation
16 * and/or other materials provided with the distribution.
17 * Neither the names of the copyright holders nor the names of its
18 * contributors may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 */
33
34#ifndef _TIPC_NODE_SUBSCR_H
35#define _TIPC_NODE_SUBSCR_H
36
37#include "addr.h"
38
39typedef void (*net_ev_handler) (void *usr_handle);
40
41/**
42 * struct node_subscr - "node down" subscription entry
43 * @node: ptr to node structure of interest (or NULL, if none)
44 * @handle_node_down: routine to invoke when node fails
45 * @usr_handle: argument to pass to routine when node fails
46 * @nodesub_list: adjacent entries in list of subscriptions for the node
47 */
48
49struct node_subscr {
50 struct node *node;
51 net_ev_handler handle_node_down;
52 void *usr_handle;
53 struct list_head nodesub_list;
54};
55
56void nodesub_subscribe(struct node_subscr *node_sub, u32 addr,
57 void *usr_handle, net_ev_handler handle_down);
58void nodesub_unsubscribe(struct node_subscr *node_sub);
59
60#endif
diff --git a/net/tipc/port.c b/net/tipc/port.c
new file mode 100644
index 000000000000..f0f228c9589a
--- /dev/null
+++ b/net/tipc/port.c
@@ -0,0 +1,1704 @@
1/*
2 * net/tipc/port.c: TIPC port code
3 *
4 * Copyright (c) 2003-2005, Ericsson Research Canada
5 * Copyright (c) 2004-2005, Wind River Systems
6 * Copyright (c) 2005-2006, Ericsson AB
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions are met:
11 *
12 * Redistributions of source code must retain the above copyright notice, this
13 * list of conditions and the following disclaimer.
14 * Redistributions in binary form must reproduce the above copyright notice,
15 * this list of conditions and the following disclaimer in the documentation
16 * and/or other materials provided with the distribution.
17 * Neither the names of the copyright holders nor the names of its
18 * contributors may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 */
33
34#include "core.h"
35#include "config.h"
36#include "dbg.h"
37#include "port.h"
38#include "addr.h"
39#include "link.h"
40#include "node.h"
41#include "port.h"
42#include "name_table.h"
43#include "user_reg.h"
44#include "msg.h"
45#include "bcast.h"
46
47/* Connection management: */
48#define PROBING_INTERVAL 3600000 /* [ms] => 1 h */
49#define CONFIRMED 0
50#define PROBING 1
51
52#define MAX_REJECT_SIZE 1024
53
54static struct sk_buff *msg_queue_head = 0;
55static struct sk_buff *msg_queue_tail = 0;
56
57spinlock_t port_list_lock = SPIN_LOCK_UNLOCKED;
58static spinlock_t queue_lock = SPIN_LOCK_UNLOCKED;
59
60LIST_HEAD(ports);
61static void port_handle_node_down(unsigned long ref);
62static struct sk_buff* port_build_self_abort_msg(struct port *,u32 err);
63static struct sk_buff* port_build_peer_abort_msg(struct port *,u32 err);
64static void port_timeout(unsigned long ref);
65
66
67static inline u32 port_peernode(struct port *p_ptr)
68{
69 return msg_destnode(&p_ptr->publ.phdr);
70}
71
72static inline u32 port_peerport(struct port *p_ptr)
73{
74 return msg_destport(&p_ptr->publ.phdr);
75}
76
77static inline u32 port_out_seqno(struct port *p_ptr)
78{
79 return msg_transp_seqno(&p_ptr->publ.phdr);
80}
81
82static inline void port_set_out_seqno(struct port *p_ptr, u32 seqno)
83{
84 msg_set_transp_seqno(&p_ptr->publ.phdr,seqno);
85}
86
87static inline void port_incr_out_seqno(struct port *p_ptr)
88{
89 struct tipc_msg *m = &p_ptr->publ.phdr;
90
91 if (likely(!msg_routed(m)))
92 return;
93 msg_set_transp_seqno(m, (msg_transp_seqno(m) + 1));
94}
95
96/**
97 * tipc_multicast - send a multicast message to local and remote destinations
98 */
99
100int tipc_multicast(u32 ref, struct tipc_name_seq const *seq, u32 domain,
101 u32 num_sect, struct iovec const *msg_sect)
102{
103 struct tipc_msg *hdr;
104 struct sk_buff *buf;
105 struct sk_buff *ibuf = NULL;
106 struct port_list dports = {0, NULL, };
107 struct port *oport = port_deref(ref);
108 int ext_targets;
109 int res;
110
111 if (unlikely(!oport))
112 return -EINVAL;
113
114 /* Create multicast message */
115
116 hdr = &oport->publ.phdr;
117 msg_set_type(hdr, TIPC_MCAST_MSG);
118 msg_set_nametype(hdr, seq->type);
119 msg_set_namelower(hdr, seq->lower);
120 msg_set_nameupper(hdr, seq->upper);
121 msg_set_hdr_sz(hdr, MCAST_H_SIZE);
122 res = msg_build(hdr, msg_sect, num_sect, MAX_MSG_SIZE,
123 !oport->user_port, &buf);
124 if (unlikely(!buf))
125 return res;
126
127 /* Figure out where to send multicast message */
128
129 ext_targets = nametbl_mc_translate(seq->type, seq->lower, seq->upper,
130 TIPC_NODE_SCOPE, &dports);
131
132 /* Send message to destinations (duplicate it only if necessary) */
133
134 if (ext_targets) {
135 if (dports.count != 0) {
136 ibuf = skb_copy(buf, GFP_ATOMIC);
137 if (ibuf == NULL) {
138 port_list_free(&dports);
139 buf_discard(buf);
140 return -ENOMEM;
141 }
142 }
143 res = bclink_send_msg(buf);
144 if ((res < 0) && (dports.count != 0)) {
145 buf_discard(ibuf);
146 }
147 } else {
148 ibuf = buf;
149 }
150
151 if (res >= 0) {
152 if (ibuf)
153 port_recv_mcast(ibuf, &dports);
154 } else {
155 port_list_free(&dports);
156 }
157 return res;
158}
159
160/**
161 * port_recv_mcast - deliver multicast message to all destination ports
162 *
163 * If there is no port list, perform a lookup to create one
164 */
165
166void port_recv_mcast(struct sk_buff *buf, struct port_list *dp)
167{
168 struct tipc_msg* msg;
169 struct port_list dports = {0, NULL, };
170 struct port_list *item = dp;
171 int cnt = 0;
172
173 assert(buf);
174 msg = buf_msg(buf);
175
176 /* Create destination port list, if one wasn't supplied */
177
178 if (dp == NULL) {
179 nametbl_mc_translate(msg_nametype(msg),
180 msg_namelower(msg),
181 msg_nameupper(msg),
182 TIPC_CLUSTER_SCOPE,
183 &dports);
184 item = dp = &dports;
185 }
186
187 /* Deliver a copy of message to each destination port */
188
189 if (dp->count != 0) {
190 if (dp->count == 1) {
191 msg_set_destport(msg, dp->ports[0]);
192 port_recv_msg(buf);
193 port_list_free(dp);
194 return;
195 }
196 for (; cnt < dp->count; cnt++) {
197 int index = cnt % PLSIZE;
198 struct sk_buff *b = skb_clone(buf, GFP_ATOMIC);
199
200 if (b == NULL) {
201 warn("Buffer allocation failure\n");
202 msg_dbg(msg, "LOST:");
203 goto exit;
204 }
205 if ((index == 0) && (cnt != 0)) {
206 item = item->next;
207 }
208 msg_set_destport(buf_msg(b),item->ports[index]);
209 port_recv_msg(b);
210 }
211 }
212exit:
213 buf_discard(buf);
214 port_list_free(dp);
215}
216
217/**
218 * tipc_createport_raw - create a native TIPC port
219 *
220 * Returns local port reference
221 */
222
223u32 tipc_createport_raw(void *usr_handle,
224 u32 (*dispatcher)(struct tipc_port *, struct sk_buff *),
225 void (*wakeup)(struct tipc_port *),
226 const u32 importance)
227{
228 struct port *p_ptr;
229 struct tipc_msg *msg;
230 u32 ref;
231
232 p_ptr = kmalloc(sizeof(*p_ptr), GFP_ATOMIC);
233 if (p_ptr == NULL) {
234 warn("Memory squeeze; failed to create port\n");
235 return 0;
236 }
237 memset(p_ptr, 0, sizeof(*p_ptr));
238 ref = ref_acquire(p_ptr, &p_ptr->publ.lock);
239 if (!ref) {
240 warn("Reference Table Exhausted\n");
241 kfree(p_ptr);
242 return 0;
243 }
244
245 port_lock(ref);
246 p_ptr->publ.ref = ref;
247 msg = &p_ptr->publ.phdr;
248 msg_init(msg, DATA_LOW, TIPC_NAMED_MSG, TIPC_OK, LONG_H_SIZE, 0);
249 msg_set_orignode(msg, tipc_own_addr);
250 msg_set_prevnode(msg, tipc_own_addr);
251 msg_set_origport(msg, ref);
252 msg_set_importance(msg,importance);
253 p_ptr->last_in_seqno = 41;
254 p_ptr->sent = 1;
255 p_ptr->publ.usr_handle = usr_handle;
256 INIT_LIST_HEAD(&p_ptr->wait_list);
257 INIT_LIST_HEAD(&p_ptr->subscription.nodesub_list);
258 p_ptr->congested_link = 0;
259 p_ptr->max_pkt = MAX_PKT_DEFAULT;
260 p_ptr->dispatcher = dispatcher;
261 p_ptr->wakeup = wakeup;
262 p_ptr->user_port = 0;
263 k_init_timer(&p_ptr->timer, (Handler)port_timeout, ref);
264 spin_lock_bh(&port_list_lock);
265 INIT_LIST_HEAD(&p_ptr->publications);
266 INIT_LIST_HEAD(&p_ptr->port_list);
267 list_add_tail(&p_ptr->port_list, &ports);
268 spin_unlock_bh(&port_list_lock);
269 port_unlock(p_ptr);
270 return ref;
271}
272
273int tipc_deleteport(u32 ref)
274{
275 struct port *p_ptr;
276 struct sk_buff *buf = 0;
277
278 tipc_withdraw(ref, 0, 0);
279 p_ptr = port_lock(ref);
280 if (!p_ptr)
281 return -EINVAL;
282
283 ref_discard(ref);
284 port_unlock(p_ptr);
285
286 k_cancel_timer(&p_ptr->timer);
287 if (p_ptr->publ.connected) {
288 buf = port_build_peer_abort_msg(p_ptr, TIPC_ERR_NO_PORT);
289 nodesub_unsubscribe(&p_ptr->subscription);
290 }
291 if (p_ptr->user_port) {
292 reg_remove_port(p_ptr->user_port);
293 kfree(p_ptr->user_port);
294 }
295
296 spin_lock_bh(&port_list_lock);
297 list_del(&p_ptr->port_list);
298 list_del(&p_ptr->wait_list);
299 spin_unlock_bh(&port_list_lock);
300 k_term_timer(&p_ptr->timer);
301 kfree(p_ptr);
302 dbg("Deleted port %u\n", ref);
303 net_route_msg(buf);
304 return TIPC_OK;
305}
306
307/**
308 * tipc_get_port() - return port associated with 'ref'
309 *
310 * Note: Port is not locked.
311 */
312
313struct tipc_port *tipc_get_port(const u32 ref)
314{
315 return (struct tipc_port *)ref_deref(ref);
316}
317
318/**
319 * tipc_get_handle - return user handle associated to port 'ref'
320 */
321
322void *tipc_get_handle(const u32 ref)
323{
324 struct port *p_ptr;
325 void * handle;
326
327 p_ptr = port_lock(ref);
328 if (!p_ptr)
329 return 0;
330 handle = p_ptr->publ.usr_handle;
331 port_unlock(p_ptr);
332 return handle;
333}
334
335static inline int port_unreliable(struct port *p_ptr)
336{
337 return msg_src_droppable(&p_ptr->publ.phdr);
338}
339
340int tipc_portunreliable(u32 ref, unsigned int *isunreliable)
341{
342 struct port *p_ptr;
343
344 p_ptr = port_lock(ref);
345 if (!p_ptr)
346 return -EINVAL;
347 *isunreliable = port_unreliable(p_ptr);
348 spin_unlock_bh(p_ptr->publ.lock);
349 return TIPC_OK;
350}
351
352int tipc_set_portunreliable(u32 ref, unsigned int isunreliable)
353{
354 struct port *p_ptr;
355
356 p_ptr = port_lock(ref);
357 if (!p_ptr)
358 return -EINVAL;
359 msg_set_src_droppable(&p_ptr->publ.phdr, (isunreliable != 0));
360 port_unlock(p_ptr);
361 return TIPC_OK;
362}
363
364static inline int port_unreturnable(struct port *p_ptr)
365{
366 return msg_dest_droppable(&p_ptr->publ.phdr);
367}
368
369int tipc_portunreturnable(u32 ref, unsigned int *isunrejectable)
370{
371 struct port *p_ptr;
372
373 p_ptr = port_lock(ref);
374 if (!p_ptr)
375 return -EINVAL;
376 *isunrejectable = port_unreturnable(p_ptr);
377 spin_unlock_bh(p_ptr->publ.lock);
378 return TIPC_OK;
379}
380
381int tipc_set_portunreturnable(u32 ref, unsigned int isunrejectable)
382{
383 struct port *p_ptr;
384
385 p_ptr = port_lock(ref);
386 if (!p_ptr)
387 return -EINVAL;
388 msg_set_dest_droppable(&p_ptr->publ.phdr, (isunrejectable != 0));
389 port_unlock(p_ptr);
390 return TIPC_OK;
391}
392
393/*
394 * port_build_proto_msg(): build a port level protocol
395 * or a connection abortion message. Called with
396 * tipc_port lock on.
397 */
398static struct sk_buff *port_build_proto_msg(u32 destport, u32 destnode,
399 u32 origport, u32 orignode,
400 u32 usr, u32 type, u32 err,
401 u32 seqno, u32 ack)
402{
403 struct sk_buff *buf;
404 struct tipc_msg *msg;
405
406 buf = buf_acquire(LONG_H_SIZE);
407 if (buf) {
408 msg = buf_msg(buf);
409 msg_init(msg, usr, type, err, LONG_H_SIZE, destnode);
410 msg_set_destport(msg, destport);
411 msg_set_origport(msg, origport);
412 msg_set_destnode(msg, destnode);
413 msg_set_orignode(msg, orignode);
414 msg_set_transp_seqno(msg, seqno);
415 msg_set_msgcnt(msg, ack);
416 msg_dbg(msg, "PORT>SEND>:");
417 }
418 return buf;
419}
420
421int tipc_set_msg_option(struct tipc_port *tp_ptr, const char *opt, const u32 sz)
422{
423 msg_expand(&tp_ptr->phdr, msg_destnode(&tp_ptr->phdr));
424 msg_set_options(&tp_ptr->phdr, opt, sz);
425 return TIPC_OK;
426}
427
428int tipc_reject_msg(struct sk_buff *buf, u32 err)
429{
430 struct tipc_msg *msg = buf_msg(buf);
431 struct sk_buff *rbuf;
432 struct tipc_msg *rmsg;
433 int hdr_sz;
434 u32 imp = msg_importance(msg);
435 u32 data_sz = msg_data_sz(msg);
436
437 if (data_sz > MAX_REJECT_SIZE)
438 data_sz = MAX_REJECT_SIZE;
439 if (msg_connected(msg) && (imp < TIPC_CRITICAL_IMPORTANCE))
440 imp++;
441 msg_dbg(msg, "port->rej: ");
442
443 /* discard rejected message if it shouldn't be returned to sender */
444 if (msg_errcode(msg) || msg_dest_droppable(msg)) {
445 buf_discard(buf);
446 return data_sz;
447 }
448
449 /* construct rejected message */
450 if (msg_mcast(msg))
451 hdr_sz = MCAST_H_SIZE;
452 else
453 hdr_sz = LONG_H_SIZE;
454 rbuf = buf_acquire(data_sz + hdr_sz);
455 if (rbuf == NULL) {
456 buf_discard(buf);
457 return data_sz;
458 }
459 rmsg = buf_msg(rbuf);
460 msg_init(rmsg, imp, msg_type(msg), err, hdr_sz, msg_orignode(msg));
461 msg_set_destport(rmsg, msg_origport(msg));
462 msg_set_prevnode(rmsg, tipc_own_addr);
463 msg_set_origport(rmsg, msg_destport(msg));
464 if (msg_short(msg))
465 msg_set_orignode(rmsg, tipc_own_addr);
466 else
467 msg_set_orignode(rmsg, msg_destnode(msg));
468 msg_set_size(rmsg, data_sz + hdr_sz);
469 msg_set_nametype(rmsg, msg_nametype(msg));
470 msg_set_nameinst(rmsg, msg_nameinst(msg));
471 memcpy(rbuf->data + hdr_sz, msg_data(msg), data_sz);
472
473 /* send self-abort message when rejecting on a connected port */
474 if (msg_connected(msg)) {
475 struct sk_buff *abuf = 0;
476 struct port *p_ptr = port_lock(msg_destport(msg));
477
478 if (p_ptr) {
479 if (p_ptr->publ.connected)
480 abuf = port_build_self_abort_msg(p_ptr, err);
481 port_unlock(p_ptr);
482 }
483 net_route_msg(abuf);
484 }
485
486 /* send rejected message */
487 buf_discard(buf);
488 net_route_msg(rbuf);
489 return data_sz;
490}
491
492int port_reject_sections(struct port *p_ptr, struct tipc_msg *hdr,
493 struct iovec const *msg_sect, u32 num_sect,
494 int err)
495{
496 struct sk_buff *buf;
497 int res;
498
499 res = msg_build(hdr, msg_sect, num_sect, MAX_MSG_SIZE,
500 !p_ptr->user_port, &buf);
501 if (!buf)
502 return res;
503
504 return tipc_reject_msg(buf, err);
505}
506
507static void port_timeout(unsigned long ref)
508{
509 struct port *p_ptr = port_lock(ref);
510 struct sk_buff *buf = 0;
511
512 if (!p_ptr || !p_ptr->publ.connected)
513 return;
514
515 /* Last probe answered ? */
516 if (p_ptr->probing_state == PROBING) {
517 buf = port_build_self_abort_msg(p_ptr, TIPC_ERR_NO_PORT);
518 } else {
519 buf = port_build_proto_msg(port_peerport(p_ptr),
520 port_peernode(p_ptr),
521 p_ptr->publ.ref,
522 tipc_own_addr,
523 CONN_MANAGER,
524 CONN_PROBE,
525 TIPC_OK,
526 port_out_seqno(p_ptr),
527 0);
528 port_incr_out_seqno(p_ptr);
529 p_ptr->probing_state = PROBING;
530 k_start_timer(&p_ptr->timer, p_ptr->probing_interval);
531 }
532 port_unlock(p_ptr);
533 net_route_msg(buf);
534}
535
536
537static void port_handle_node_down(unsigned long ref)
538{
539 struct port *p_ptr = port_lock(ref);
540 struct sk_buff* buf = 0;
541
542 if (!p_ptr)
543 return;
544 buf = port_build_self_abort_msg(p_ptr, TIPC_ERR_NO_NODE);
545 port_unlock(p_ptr);
546 net_route_msg(buf);
547}
548
549
550static struct sk_buff *port_build_self_abort_msg(struct port *p_ptr, u32 err)
551{
552 u32 imp = msg_importance(&p_ptr->publ.phdr);
553
554 if (!p_ptr->publ.connected)
555 return 0;
556 if (imp < TIPC_CRITICAL_IMPORTANCE)
557 imp++;
558 return port_build_proto_msg(p_ptr->publ.ref,
559 tipc_own_addr,
560 port_peerport(p_ptr),
561 port_peernode(p_ptr),
562 imp,
563 TIPC_CONN_MSG,
564 err,
565 p_ptr->last_in_seqno + 1,
566 0);
567}
568
569
570static struct sk_buff *port_build_peer_abort_msg(struct port *p_ptr, u32 err)
571{
572 u32 imp = msg_importance(&p_ptr->publ.phdr);
573
574 if (!p_ptr->publ.connected)
575 return 0;
576 if (imp < TIPC_CRITICAL_IMPORTANCE)
577 imp++;
578 return port_build_proto_msg(port_peerport(p_ptr),
579 port_peernode(p_ptr),
580 p_ptr->publ.ref,
581 tipc_own_addr,
582 imp,
583 TIPC_CONN_MSG,
584 err,
585 port_out_seqno(p_ptr),
586 0);
587}
588
589void port_recv_proto_msg(struct sk_buff *buf)
590{
591 struct tipc_msg *msg = buf_msg(buf);
592 struct port *p_ptr = port_lock(msg_destport(msg));
593 u32 err = TIPC_OK;
594 struct sk_buff *r_buf = 0;
595 struct sk_buff *abort_buf = 0;
596
597 msg_dbg(msg, "PORT<RECV<:");
598
599 if (!p_ptr) {
600 err = TIPC_ERR_NO_PORT;
601 } else if (p_ptr->publ.connected) {
602 if (port_peernode(p_ptr) != msg_orignode(msg))
603 err = TIPC_ERR_NO_PORT;
604 if (port_peerport(p_ptr) != msg_origport(msg))
605 err = TIPC_ERR_NO_PORT;
606 if (!err && msg_routed(msg)) {
607 u32 seqno = msg_transp_seqno(msg);
608 u32 myno = ++p_ptr->last_in_seqno;
609 if (seqno != myno) {
610 err = TIPC_ERR_NO_PORT;
611 abort_buf = port_build_self_abort_msg(p_ptr, err);
612 }
613 }
614 if (msg_type(msg) == CONN_ACK) {
615 int wakeup = port_congested(p_ptr) &&
616 p_ptr->publ.congested &&
617 p_ptr->wakeup;
618 p_ptr->acked += msg_msgcnt(msg);
619 if (port_congested(p_ptr))
620 goto exit;
621 p_ptr->publ.congested = 0;
622 if (!wakeup)
623 goto exit;
624 p_ptr->wakeup(&p_ptr->publ);
625 goto exit;
626 }
627 } else if (p_ptr->publ.published) {
628 err = TIPC_ERR_NO_PORT;
629 }
630 if (err) {
631 r_buf = port_build_proto_msg(msg_origport(msg),
632 msg_orignode(msg),
633 msg_destport(msg),
634 tipc_own_addr,
635 DATA_HIGH,
636 TIPC_CONN_MSG,
637 err,
638 0,
639 0);
640 goto exit;
641 }
642
643 /* All is fine */
644 if (msg_type(msg) == CONN_PROBE) {
645 r_buf = port_build_proto_msg(msg_origport(msg),
646 msg_orignode(msg),
647 msg_destport(msg),
648 tipc_own_addr,
649 CONN_MANAGER,
650 CONN_PROBE_REPLY,
651 TIPC_OK,
652 port_out_seqno(p_ptr),
653 0);
654 }
655 p_ptr->probing_state = CONFIRMED;
656 port_incr_out_seqno(p_ptr);
657exit:
658 if (p_ptr)
659 port_unlock(p_ptr);
660 net_route_msg(r_buf);
661 net_route_msg(abort_buf);
662 buf_discard(buf);
663}
664
665static void port_print(struct port *p_ptr, struct print_buf *buf, int full_id)
666{
667 struct publication *publ;
668
669 if (full_id)
670 tipc_printf(buf, "<%u.%u.%u:%u>:",
671 tipc_zone(tipc_own_addr), tipc_cluster(tipc_own_addr),
672 tipc_node(tipc_own_addr), p_ptr->publ.ref);
673 else
674 tipc_printf(buf, "%-10u:", p_ptr->publ.ref);
675
676 if (p_ptr->publ.connected) {
677 u32 dport = port_peerport(p_ptr);
678 u32 destnode = port_peernode(p_ptr);
679
680 tipc_printf(buf, " connected to <%u.%u.%u:%u>",
681 tipc_zone(destnode), tipc_cluster(destnode),
682 tipc_node(destnode), dport);
683 if (p_ptr->publ.conn_type != 0)
684 tipc_printf(buf, " via {%u,%u}",
685 p_ptr->publ.conn_type,
686 p_ptr->publ.conn_instance);
687 }
688 else if (p_ptr->publ.published) {
689 tipc_printf(buf, " bound to");
690 list_for_each_entry(publ, &p_ptr->publications, pport_list) {
691 if (publ->lower == publ->upper)
692 tipc_printf(buf, " {%u,%u}", publ->type,
693 publ->lower);
694 else
695 tipc_printf(buf, " {%u,%u,%u}", publ->type,
696 publ->lower, publ->upper);
697 }
698 }
699 tipc_printf(buf, "\n");
700}
701
702#define MAX_PORT_QUERY 32768
703
704struct sk_buff *port_get_ports(void)
705{
706 struct sk_buff *buf;
707 struct tlv_desc *rep_tlv;
708 struct print_buf pb;
709 struct port *p_ptr;
710 int str_len;
711
712 buf = cfg_reply_alloc(TLV_SPACE(MAX_PORT_QUERY));
713 if (!buf)
714 return NULL;
715 rep_tlv = (struct tlv_desc *)buf->data;
716
717 printbuf_init(&pb, TLV_DATA(rep_tlv), MAX_PORT_QUERY);
718 spin_lock_bh(&port_list_lock);
719 list_for_each_entry(p_ptr, &ports, port_list) {
720 spin_lock_bh(p_ptr->publ.lock);
721 port_print(p_ptr, &pb, 0);
722 spin_unlock_bh(p_ptr->publ.lock);
723 }
724 spin_unlock_bh(&port_list_lock);
725 str_len = printbuf_validate(&pb);
726
727 skb_put(buf, TLV_SPACE(str_len));
728 TLV_SET(rep_tlv, TIPC_TLV_ULTRA_STRING, NULL, str_len);
729
730 return buf;
731}
732
733#if 0
734
735#define MAX_PORT_STATS 2000
736
737struct sk_buff *port_show_stats(const void *req_tlv_area, int req_tlv_space)
738{
739 u32 ref;
740 struct port *p_ptr;
741 struct sk_buff *buf;
742 struct tlv_desc *rep_tlv;
743 struct print_buf pb;
744 int str_len;
745
746 if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_PORT_REF))
747 return cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
748
749 ref = *(u32 *)TLV_DATA(req_tlv_area);
750 ref = ntohl(ref);
751
752 p_ptr = port_lock(ref);
753 if (!p_ptr)
754 return cfg_reply_error_string("port not found");
755
756 buf = cfg_reply_alloc(TLV_SPACE(MAX_PORT_STATS));
757 if (!buf) {
758 port_unlock(p_ptr);
759 return NULL;
760 }
761 rep_tlv = (struct tlv_desc *)buf->data;
762
763 printbuf_init(&pb, TLV_DATA(rep_tlv), MAX_PORT_STATS);
764 port_print(p_ptr, &pb, 1);
765 /* NEED TO FILL IN ADDITIONAL PORT STATISTICS HERE */
766 port_unlock(p_ptr);
767 str_len = printbuf_validate(&pb);
768
769 skb_put(buf, TLV_SPACE(str_len));
770 TLV_SET(rep_tlv, TIPC_TLV_ULTRA_STRING, NULL, str_len);
771
772 return buf;
773}
774
775#endif
776
777void port_reinit(void)
778{
779 struct port *p_ptr;
780 struct tipc_msg *msg;
781
782 spin_lock_bh(&port_list_lock);
783 list_for_each_entry(p_ptr, &ports, port_list) {
784 msg = &p_ptr->publ.phdr;
785 if (msg_orignode(msg) == tipc_own_addr)
786 break;
787 msg_set_orignode(msg, tipc_own_addr);
788 }
789 spin_unlock_bh(&port_list_lock);
790}
791
792
793/*
794 * port_dispatcher_sigh(): Signal handler for messages destinated
795 * to the tipc_port interface.
796 */
797
798static void port_dispatcher_sigh(void *dummy)
799{
800 struct sk_buff *buf;
801
802 spin_lock_bh(&queue_lock);
803 buf = msg_queue_head;
804 msg_queue_head = 0;
805 spin_unlock_bh(&queue_lock);
806
807 while (buf) {
808 struct port *p_ptr;
809 struct user_port *up_ptr;
810 struct tipc_portid orig;
811 struct tipc_name_seq dseq;
812 void *usr_handle;
813 int connected;
814 int published;
815
816 struct sk_buff *next = buf->next;
817 struct tipc_msg *msg = buf_msg(buf);
818 u32 dref = msg_destport(msg);
819
820 p_ptr = port_lock(dref);
821 if (!p_ptr) {
822 /* Port deleted while msg in queue */
823 tipc_reject_msg(buf, TIPC_ERR_NO_PORT);
824 buf = next;
825 continue;
826 }
827 orig.ref = msg_origport(msg);
828 orig.node = msg_orignode(msg);
829 up_ptr = p_ptr->user_port;
830 usr_handle = up_ptr->usr_handle;
831 connected = p_ptr->publ.connected;
832 published = p_ptr->publ.published;
833
834 if (unlikely(msg_errcode(msg)))
835 goto err;
836
837 switch (msg_type(msg)) {
838
839 case TIPC_CONN_MSG:{
840 tipc_conn_msg_event cb = up_ptr->conn_msg_cb;
841 u32 peer_port = port_peerport(p_ptr);
842 u32 peer_node = port_peernode(p_ptr);
843
844 spin_unlock_bh(p_ptr->publ.lock);
845 if (unlikely(!connected)) {
846 if (unlikely(published))
847 goto reject;
848 tipc_connect2port(dref,&orig);
849 }
850 if (unlikely(msg_origport(msg) != peer_port))
851 goto reject;
852 if (unlikely(msg_orignode(msg) != peer_node))
853 goto reject;
854 if (unlikely(!cb))
855 goto reject;
856 if (unlikely(++p_ptr->publ.conn_unacked >=
857 TIPC_FLOW_CONTROL_WIN))
858 tipc_acknowledge(dref,
859 p_ptr->publ.conn_unacked);
860 skb_pull(buf, msg_hdr_sz(msg));
861 cb(usr_handle, dref, &buf, msg_data(msg),
862 msg_data_sz(msg));
863 break;
864 }
865 case TIPC_DIRECT_MSG:{
866 tipc_msg_event cb = up_ptr->msg_cb;
867
868 spin_unlock_bh(p_ptr->publ.lock);
869 if (unlikely(connected))
870 goto reject;
871 if (unlikely(!cb))
872 goto reject;
873 skb_pull(buf, msg_hdr_sz(msg));
874 cb(usr_handle, dref, &buf, msg_data(msg),
875 msg_data_sz(msg), msg_importance(msg),
876 &orig);
877 break;
878 }
879 case TIPC_NAMED_MSG:{
880 tipc_named_msg_event cb = up_ptr->named_msg_cb;
881
882 spin_unlock_bh(p_ptr->publ.lock);
883 if (unlikely(connected))
884 goto reject;
885 if (unlikely(!cb))
886 goto reject;
887 if (unlikely(!published))
888 goto reject;
889 dseq.type = msg_nametype(msg);
890 dseq.lower = msg_nameinst(msg);
891 dseq.upper = dseq.lower;
892 skb_pull(buf, msg_hdr_sz(msg));
893 cb(usr_handle, dref, &buf, msg_data(msg),
894 msg_data_sz(msg), msg_importance(msg),
895 &orig, &dseq);
896 break;
897 }
898 }
899 if (buf)
900 buf_discard(buf);
901 buf = next;
902 continue;
903err:
904 switch (msg_type(msg)) {
905
906 case TIPC_CONN_MSG:{
907 tipc_conn_shutdown_event cb =
908 up_ptr->conn_err_cb;
909 u32 peer_port = port_peerport(p_ptr);
910 u32 peer_node = port_peernode(p_ptr);
911
912 spin_unlock_bh(p_ptr->publ.lock);
913 if (!connected || !cb)
914 break;
915 if (msg_origport(msg) != peer_port)
916 break;
917 if (msg_orignode(msg) != peer_node)
918 break;
919 tipc_disconnect(dref);
920 skb_pull(buf, msg_hdr_sz(msg));
921 cb(usr_handle, dref, &buf, msg_data(msg),
922 msg_data_sz(msg), msg_errcode(msg));
923 break;
924 }
925 case TIPC_DIRECT_MSG:{
926 tipc_msg_err_event cb = up_ptr->err_cb;
927
928 spin_unlock_bh(p_ptr->publ.lock);
929 if (connected || !cb)
930 break;
931 skb_pull(buf, msg_hdr_sz(msg));
932 cb(usr_handle, dref, &buf, msg_data(msg),
933 msg_data_sz(msg), msg_errcode(msg), &orig);
934 break;
935 }
936 case TIPC_NAMED_MSG:{
937 tipc_named_msg_err_event cb =
938 up_ptr->named_err_cb;
939
940 spin_unlock_bh(p_ptr->publ.lock);
941 if (connected || !cb)
942 break;
943 dseq.type = msg_nametype(msg);
944 dseq.lower = msg_nameinst(msg);
945 dseq.upper = dseq.lower;
946 skb_pull(buf, msg_hdr_sz(msg));
947 cb(usr_handle, dref, &buf, msg_data(msg),
948 msg_data_sz(msg), msg_errcode(msg), &dseq);
949 break;
950 }
951 }
952 if (buf)
953 buf_discard(buf);
954 buf = next;
955 continue;
956reject:
957 tipc_reject_msg(buf, TIPC_ERR_NO_PORT);
958 buf = next;
959 }
960}
961
962/*
963 * port_dispatcher(): Dispatcher for messages destinated
964 * to the tipc_port interface. Called with port locked.
965 */
966
967static u32 port_dispatcher(struct tipc_port *dummy, struct sk_buff *buf)
968{
969 buf->next = NULL;
970 spin_lock_bh(&queue_lock);
971 if (msg_queue_head) {
972 msg_queue_tail->next = buf;
973 msg_queue_tail = buf;
974 } else {
975 msg_queue_tail = msg_queue_head = buf;
976 k_signal((Handler)port_dispatcher_sigh, 0);
977 }
978 spin_unlock_bh(&queue_lock);
979 return TIPC_OK;
980}
981
982/*
983 * Wake up port after congestion: Called with port locked,
984 *
985 */
986
987static void port_wakeup_sh(unsigned long ref)
988{
989 struct port *p_ptr;
990 struct user_port *up_ptr;
991 tipc_continue_event cb = 0;
992 void *uh = 0;
993
994 p_ptr = port_lock(ref);
995 if (p_ptr) {
996 up_ptr = p_ptr->user_port;
997 if (up_ptr) {
998 cb = up_ptr->continue_event_cb;
999 uh = up_ptr->usr_handle;
1000 }
1001 port_unlock(p_ptr);
1002 }
1003 if (cb)
1004 cb(uh, ref);
1005}
1006
1007
1008static void port_wakeup(struct tipc_port *p_ptr)
1009{
1010 k_signal((Handler)port_wakeup_sh, p_ptr->ref);
1011}
1012
1013void tipc_acknowledge(u32 ref, u32 ack)
1014{
1015 struct port *p_ptr;
1016 struct sk_buff *buf = 0;
1017
1018 p_ptr = port_lock(ref);
1019 if (!p_ptr)
1020 return;
1021 if (p_ptr->publ.connected) {
1022 p_ptr->publ.conn_unacked -= ack;
1023 buf = port_build_proto_msg(port_peerport(p_ptr),
1024 port_peernode(p_ptr),
1025 ref,
1026 tipc_own_addr,
1027 CONN_MANAGER,
1028 CONN_ACK,
1029 TIPC_OK,
1030 port_out_seqno(p_ptr),
1031 ack);
1032 }
1033 port_unlock(p_ptr);
1034 net_route_msg(buf);
1035}
1036
1037/*
1038 * tipc_createport(): user level call. Will add port to
1039 * registry if non-zero user_ref.
1040 */
1041
1042int tipc_createport(u32 user_ref,
1043 void *usr_handle,
1044 unsigned int importance,
1045 tipc_msg_err_event error_cb,
1046 tipc_named_msg_err_event named_error_cb,
1047 tipc_conn_shutdown_event conn_error_cb,
1048 tipc_msg_event msg_cb,
1049 tipc_named_msg_event named_msg_cb,
1050 tipc_conn_msg_event conn_msg_cb,
1051 tipc_continue_event continue_event_cb,/* May be zero */
1052 u32 *portref)
1053{
1054 struct user_port *up_ptr;
1055 struct port *p_ptr;
1056 u32 ref;
1057
1058 up_ptr = (struct user_port *)kmalloc(sizeof(*up_ptr), GFP_ATOMIC);
1059 if (up_ptr == NULL) {
1060 return -ENOMEM;
1061 }
1062 ref = tipc_createport_raw(0, port_dispatcher, port_wakeup, importance);
1063 p_ptr = port_lock(ref);
1064 if (!p_ptr) {
1065 kfree(up_ptr);
1066 return -ENOMEM;
1067 }
1068
1069 p_ptr->user_port = up_ptr;
1070 up_ptr->user_ref = user_ref;
1071 up_ptr->usr_handle = usr_handle;
1072 up_ptr->ref = p_ptr->publ.ref;
1073 up_ptr->err_cb = error_cb;
1074 up_ptr->named_err_cb = named_error_cb;
1075 up_ptr->conn_err_cb = conn_error_cb;
1076 up_ptr->msg_cb = msg_cb;
1077 up_ptr->named_msg_cb = named_msg_cb;
1078 up_ptr->conn_msg_cb = conn_msg_cb;
1079 up_ptr->continue_event_cb = continue_event_cb;
1080 INIT_LIST_HEAD(&up_ptr->uport_list);
1081 reg_add_port(up_ptr);
1082 *portref = p_ptr->publ.ref;
1083 dbg(" tipc_createport: %x with ref %u\n", p_ptr, p_ptr->publ.ref);
1084 port_unlock(p_ptr);
1085 return TIPC_OK;
1086}
1087
1088int tipc_ownidentity(u32 ref, struct tipc_portid *id)
1089{
1090 id->ref = ref;
1091 id->node = tipc_own_addr;
1092 return TIPC_OK;
1093}
1094
1095int tipc_portimportance(u32 ref, unsigned int *importance)
1096{
1097 struct port *p_ptr;
1098
1099 p_ptr = port_lock(ref);
1100 if (!p_ptr)
1101 return -EINVAL;
1102 *importance = (unsigned int)msg_importance(&p_ptr->publ.phdr);
1103 spin_unlock_bh(p_ptr->publ.lock);
1104 return TIPC_OK;
1105}
1106
1107int tipc_set_portimportance(u32 ref, unsigned int imp)
1108{
1109 struct port *p_ptr;
1110
1111 if (imp > TIPC_CRITICAL_IMPORTANCE)
1112 return -EINVAL;
1113
1114 p_ptr = port_lock(ref);
1115 if (!p_ptr)
1116 return -EINVAL;
1117 msg_set_importance(&p_ptr->publ.phdr, (u32)imp);
1118 spin_unlock_bh(p_ptr->publ.lock);
1119 return TIPC_OK;
1120}
1121
1122
1123int tipc_publish(u32 ref, unsigned int scope, struct tipc_name_seq const *seq)
1124{
1125 struct port *p_ptr;
1126 struct publication *publ;
1127 u32 key;
1128 int res = -EINVAL;
1129
1130 p_ptr = port_lock(ref);
1131 dbg("tipc_publ %u, p_ptr = %x, conn = %x, scope = %x, "
1132 "lower = %u, upper = %u\n",
1133 ref, p_ptr, p_ptr->publ.connected, scope, seq->lower, seq->upper);
1134 if (!p_ptr)
1135 return -EINVAL;
1136 if (p_ptr->publ.connected)
1137 goto exit;
1138 if (seq->lower > seq->upper)
1139 goto exit;
1140 if ((scope < TIPC_ZONE_SCOPE) || (scope > TIPC_NODE_SCOPE))
1141 goto exit;
1142 key = ref + p_ptr->pub_count + 1;
1143 if (key == ref) {
1144 res = -EADDRINUSE;
1145 goto exit;
1146 }
1147 publ = nametbl_publish(seq->type, seq->lower, seq->upper,
1148 scope, p_ptr->publ.ref, key);
1149 if (publ) {
1150 list_add(&publ->pport_list, &p_ptr->publications);
1151 p_ptr->pub_count++;
1152 p_ptr->publ.published = 1;
1153 res = TIPC_OK;
1154 }
1155exit:
1156 port_unlock(p_ptr);
1157 return res;
1158}
1159
1160int tipc_withdraw(u32 ref, unsigned int scope, struct tipc_name_seq const *seq)
1161{
1162 struct port *p_ptr;
1163 struct publication *publ;
1164 struct publication *tpubl;
1165 int res = -EINVAL;
1166
1167 p_ptr = port_lock(ref);
1168 if (!p_ptr)
1169 return -EINVAL;
1170 if (!p_ptr->publ.published)
1171 goto exit;
1172 if (!seq) {
1173 list_for_each_entry_safe(publ, tpubl,
1174 &p_ptr->publications, pport_list) {
1175 nametbl_withdraw(publ->type, publ->lower,
1176 publ->ref, publ->key);
1177 }
1178 res = TIPC_OK;
1179 } else {
1180 list_for_each_entry_safe(publ, tpubl,
1181 &p_ptr->publications, pport_list) {
1182 if (publ->scope != scope)
1183 continue;
1184 if (publ->type != seq->type)
1185 continue;
1186 if (publ->lower != seq->lower)
1187 continue;
1188 if (publ->upper != seq->upper)
1189 break;
1190 nametbl_withdraw(publ->type, publ->lower,
1191 publ->ref, publ->key);
1192 res = TIPC_OK;
1193 break;
1194 }
1195 }
1196 if (list_empty(&p_ptr->publications))
1197 p_ptr->publ.published = 0;
1198exit:
1199 port_unlock(p_ptr);
1200 return res;
1201}
1202
1203int tipc_connect2port(u32 ref, struct tipc_portid const *peer)
1204{
1205 struct port *p_ptr;
1206 struct tipc_msg *msg;
1207 int res = -EINVAL;
1208
1209 p_ptr = port_lock(ref);
1210 if (!p_ptr)
1211 return -EINVAL;
1212 if (p_ptr->publ.published || p_ptr->publ.connected)
1213 goto exit;
1214 if (!peer->ref)
1215 goto exit;
1216
1217 msg = &p_ptr->publ.phdr;
1218 msg_set_destnode(msg, peer->node);
1219 msg_set_destport(msg, peer->ref);
1220 msg_set_orignode(msg, tipc_own_addr);
1221 msg_set_origport(msg, p_ptr->publ.ref);
1222 msg_set_transp_seqno(msg, 42);
1223 msg_set_type(msg, TIPC_CONN_MSG);
1224 if (!may_route(peer->node))
1225 msg_set_hdr_sz(msg, SHORT_H_SIZE);
1226 else
1227 msg_set_hdr_sz(msg, LONG_H_SIZE);
1228
1229 p_ptr->probing_interval = PROBING_INTERVAL;
1230 p_ptr->probing_state = CONFIRMED;
1231 p_ptr->publ.connected = 1;
1232 k_start_timer(&p_ptr->timer, p_ptr->probing_interval);
1233
1234 nodesub_subscribe(&p_ptr->subscription,peer->node, (void *)ref,
1235 (net_ev_handler)port_handle_node_down);
1236 res = TIPC_OK;
1237exit:
1238 port_unlock(p_ptr);
1239 p_ptr->max_pkt = link_get_max_pkt(peer->node, ref);
1240 return res;
1241}
1242
1243/*
1244 * tipc_disconnect(): Disconnect port form peer.
1245 * This is a node local operation.
1246 */
1247
1248int tipc_disconnect(u32 ref)
1249{
1250 struct port *p_ptr;
1251 int res = -ENOTCONN;
1252
1253 p_ptr = port_lock(ref);
1254 if (!p_ptr)
1255 return -EINVAL;
1256 if (p_ptr->publ.connected) {
1257 p_ptr->publ.connected = 0;
1258 /* let timer expire on it's own to avoid deadlock! */
1259 nodesub_unsubscribe(&p_ptr->subscription);
1260 res = TIPC_OK;
1261 }
1262 port_unlock(p_ptr);
1263 return res;
1264}
1265
1266/*
1267 * tipc_shutdown(): Send a SHUTDOWN msg to peer and disconnect
1268 */
1269int tipc_shutdown(u32 ref)
1270{
1271 struct port *p_ptr;
1272 struct sk_buff *buf = 0;
1273
1274 p_ptr = port_lock(ref);
1275 if (!p_ptr)
1276 return -EINVAL;
1277
1278 if (p_ptr->publ.connected) {
1279 u32 imp = msg_importance(&p_ptr->publ.phdr);
1280 if (imp < TIPC_CRITICAL_IMPORTANCE)
1281 imp++;
1282 buf = port_build_proto_msg(port_peerport(p_ptr),
1283 port_peernode(p_ptr),
1284 ref,
1285 tipc_own_addr,
1286 imp,
1287 TIPC_CONN_MSG,
1288 TIPC_CONN_SHUTDOWN,
1289 port_out_seqno(p_ptr),
1290 0);
1291 }
1292 port_unlock(p_ptr);
1293 net_route_msg(buf);
1294 return tipc_disconnect(ref);
1295}
1296
1297int tipc_isconnected(u32 ref, int *isconnected)
1298{
1299 struct port *p_ptr;
1300
1301 p_ptr = port_lock(ref);
1302 if (!p_ptr)
1303 return -EINVAL;
1304 *isconnected = p_ptr->publ.connected;
1305 port_unlock(p_ptr);
1306 return TIPC_OK;
1307}
1308
1309int tipc_peer(u32 ref, struct tipc_portid *peer)
1310{
1311 struct port *p_ptr;
1312 int res;
1313
1314 p_ptr = port_lock(ref);
1315 if (!p_ptr)
1316 return -EINVAL;
1317 if (p_ptr->publ.connected) {
1318 peer->ref = port_peerport(p_ptr);
1319 peer->node = port_peernode(p_ptr);
1320 res = TIPC_OK;
1321 } else
1322 res = -ENOTCONN;
1323 port_unlock(p_ptr);
1324 return res;
1325}
1326
1327int tipc_ref_valid(u32 ref)
1328{
1329 /* Works irrespective of type */
1330 return !!ref_deref(ref);
1331}
1332
1333
1334/*
1335 * port_recv_sections(): Concatenate and deliver sectioned
1336 * message for this node.
1337 */
1338
1339int port_recv_sections(struct port *sender, unsigned int num_sect,
1340 struct iovec const *msg_sect)
1341{
1342 struct sk_buff *buf;
1343 int res;
1344
1345 res = msg_build(&sender->publ.phdr, msg_sect, num_sect,
1346 MAX_MSG_SIZE, !sender->user_port, &buf);
1347 if (likely(buf))
1348 port_recv_msg(buf);
1349 return res;
1350}
1351
1352/**
1353 * tipc_send - send message sections on connection
1354 */
1355
1356int tipc_send(u32 ref, unsigned int num_sect, struct iovec const *msg_sect)
1357{
1358 struct port *p_ptr;
1359 u32 destnode;
1360 int res;
1361
1362 p_ptr = port_deref(ref);
1363 if (!p_ptr || !p_ptr->publ.connected)
1364 return -EINVAL;
1365
1366 p_ptr->publ.congested = 1;
1367 if (!port_congested(p_ptr)) {
1368 destnode = port_peernode(p_ptr);
1369 if (likely(destnode != tipc_own_addr))
1370 res = link_send_sections_fast(p_ptr, msg_sect, num_sect,
1371 destnode);
1372 else
1373 res = port_recv_sections(p_ptr, num_sect, msg_sect);
1374
1375 if (likely(res != -ELINKCONG)) {
1376 port_incr_out_seqno(p_ptr);
1377 p_ptr->publ.congested = 0;
1378 p_ptr->sent++;
1379 return res;
1380 }
1381 }
1382 if (port_unreliable(p_ptr)) {
1383 p_ptr->publ.congested = 0;
1384 /* Just calculate msg length and return */
1385 return msg_calc_data_size(msg_sect, num_sect);
1386 }
1387 return -ELINKCONG;
1388}
1389
1390/**
1391 * tipc_send_buf - send message buffer on connection
1392 */
1393
1394int tipc_send_buf(u32 ref, struct sk_buff *buf, unsigned int dsz)
1395{
1396 struct port *p_ptr;
1397 struct tipc_msg *msg;
1398 u32 destnode;
1399 u32 hsz;
1400 u32 sz;
1401 u32 res;
1402
1403 p_ptr = port_deref(ref);
1404 if (!p_ptr || !p_ptr->publ.connected)
1405 return -EINVAL;
1406
1407 msg = &p_ptr->publ.phdr;
1408 hsz = msg_hdr_sz(msg);
1409 sz = hsz + dsz;
1410 msg_set_size(msg, sz);
1411 if (skb_cow(buf, hsz))
1412 return -ENOMEM;
1413
1414 skb_push(buf, hsz);
1415 memcpy(buf->data, (unchar *)msg, hsz);
1416 destnode = msg_destnode(msg);
1417 p_ptr->publ.congested = 1;
1418 if (!port_congested(p_ptr)) {
1419 if (likely(destnode != tipc_own_addr))
1420 res = tipc_send_buf_fast(buf, destnode);
1421 else {
1422 port_recv_msg(buf);
1423 res = sz;
1424 }
1425 if (likely(res != -ELINKCONG)) {
1426 port_incr_out_seqno(p_ptr);
1427 p_ptr->sent++;
1428 p_ptr->publ.congested = 0;
1429 return res;
1430 }
1431 }
1432 if (port_unreliable(p_ptr)) {
1433 p_ptr->publ.congested = 0;
1434 return dsz;
1435 }
1436 return -ELINKCONG;
1437}
1438
1439/**
1440 * tipc_forward2name - forward message sections to port name
1441 */
1442
1443int tipc_forward2name(u32 ref,
1444 struct tipc_name const *name,
1445 u32 domain,
1446 u32 num_sect,
1447 struct iovec const *msg_sect,
1448 struct tipc_portid const *orig,
1449 unsigned int importance)
1450{
1451 struct port *p_ptr;
1452 struct tipc_msg *msg;
1453 u32 destnode = domain;
1454 u32 destport = 0;
1455 int res;
1456
1457 p_ptr = port_deref(ref);
1458 if (!p_ptr || p_ptr->publ.connected)
1459 return -EINVAL;
1460
1461 msg = &p_ptr->publ.phdr;
1462 msg_set_type(msg, TIPC_NAMED_MSG);
1463 msg_set_orignode(msg, orig->node);
1464 msg_set_origport(msg, orig->ref);
1465 msg_set_hdr_sz(msg, LONG_H_SIZE);
1466 msg_set_nametype(msg, name->type);
1467 msg_set_nameinst(msg, name->instance);
1468 msg_set_lookup_scope(msg, addr_scope(domain));
1469 if (importance <= TIPC_CRITICAL_IMPORTANCE)
1470 msg_set_importance(msg,importance);
1471 destport = nametbl_translate(name->type, name->instance, &destnode);
1472 msg_set_destnode(msg, destnode);
1473 msg_set_destport(msg, destport);
1474
1475 if (likely(destport || destnode)) {
1476 p_ptr->sent++;
1477 if (likely(destnode == tipc_own_addr))
1478 return port_recv_sections(p_ptr, num_sect, msg_sect);
1479 res = link_send_sections_fast(p_ptr, msg_sect, num_sect,
1480 destnode);
1481 if (likely(res != -ELINKCONG))
1482 return res;
1483 if (port_unreliable(p_ptr)) {
1484 /* Just calculate msg length and return */
1485 return msg_calc_data_size(msg_sect, num_sect);
1486 }
1487 return -ELINKCONG;
1488 }
1489 return port_reject_sections(p_ptr, msg, msg_sect, num_sect,
1490 TIPC_ERR_NO_NAME);
1491}
1492
1493/**
1494 * tipc_send2name - send message sections to port name
1495 */
1496
1497int tipc_send2name(u32 ref,
1498 struct tipc_name const *name,
1499 unsigned int domain,
1500 unsigned int num_sect,
1501 struct iovec const *msg_sect)
1502{
1503 struct tipc_portid orig;
1504
1505 orig.ref = ref;
1506 orig.node = tipc_own_addr;
1507 return tipc_forward2name(ref, name, domain, num_sect, msg_sect, &orig,
1508 TIPC_PORT_IMPORTANCE);
1509}
1510
1511/**
1512 * tipc_forward_buf2name - forward message buffer to port name
1513 */
1514
1515int tipc_forward_buf2name(u32 ref,
1516 struct tipc_name const *name,
1517 u32 domain,
1518 struct sk_buff *buf,
1519 unsigned int dsz,
1520 struct tipc_portid const *orig,
1521 unsigned int importance)
1522{
1523 struct port *p_ptr;
1524 struct tipc_msg *msg;
1525 u32 destnode = domain;
1526 u32 destport = 0;
1527 int res;
1528
1529 p_ptr = (struct port *)ref_deref(ref);
1530 if (!p_ptr || p_ptr->publ.connected)
1531 return -EINVAL;
1532
1533 msg = &p_ptr->publ.phdr;
1534 if (importance <= TIPC_CRITICAL_IMPORTANCE)
1535 msg_set_importance(msg, importance);
1536 msg_set_type(msg, TIPC_NAMED_MSG);
1537 msg_set_orignode(msg, orig->node);
1538 msg_set_origport(msg, orig->ref);
1539 msg_set_nametype(msg, name->type);
1540 msg_set_nameinst(msg, name->instance);
1541 msg_set_lookup_scope(msg, addr_scope(domain));
1542 msg_set_hdr_sz(msg, LONG_H_SIZE);
1543 msg_set_size(msg, LONG_H_SIZE + dsz);
1544 destport = nametbl_translate(name->type, name->instance, &destnode);
1545 msg_set_destnode(msg, destnode);
1546 msg_set_destport(msg, destport);
1547 msg_dbg(msg, "forw2name ==> ");
1548 if (skb_cow(buf, LONG_H_SIZE))
1549 return -ENOMEM;
1550 skb_push(buf, LONG_H_SIZE);
1551 memcpy(buf->data, (unchar *)msg, LONG_H_SIZE);
1552 msg_dbg(buf_msg(buf),"PREP:");
1553 if (likely(destport || destnode)) {
1554 p_ptr->sent++;
1555 if (destnode == tipc_own_addr)
1556 return port_recv_msg(buf);
1557 res = tipc_send_buf_fast(buf, destnode);
1558 if (likely(res != -ELINKCONG))
1559 return res;
1560 if (port_unreliable(p_ptr))
1561 return dsz;
1562 return -ELINKCONG;
1563 }
1564 return tipc_reject_msg(buf, TIPC_ERR_NO_NAME);
1565}
1566
1567/**
1568 * tipc_send_buf2name - send message buffer to port name
1569 */
1570
1571int tipc_send_buf2name(u32 ref,
1572 struct tipc_name const *dest,
1573 u32 domain,
1574 struct sk_buff *buf,
1575 unsigned int dsz)
1576{
1577 struct tipc_portid orig;
1578
1579 orig.ref = ref;
1580 orig.node = tipc_own_addr;
1581 return tipc_forward_buf2name(ref, dest, domain, buf, dsz, &orig,
1582 TIPC_PORT_IMPORTANCE);
1583}
1584
1585/**
1586 * tipc_forward2port - forward message sections to port identity
1587 */
1588
1589int tipc_forward2port(u32 ref,
1590 struct tipc_portid const *dest,
1591 unsigned int num_sect,
1592 struct iovec const *msg_sect,
1593 struct tipc_portid const *orig,
1594 unsigned int importance)
1595{
1596 struct port *p_ptr;
1597 struct tipc_msg *msg;
1598 int res;
1599
1600 p_ptr = port_deref(ref);
1601 if (!p_ptr || p_ptr->publ.connected)
1602 return -EINVAL;
1603
1604 msg = &p_ptr->publ.phdr;
1605 msg_set_type(msg, TIPC_DIRECT_MSG);
1606 msg_set_orignode(msg, orig->node);
1607 msg_set_origport(msg, orig->ref);
1608 msg_set_destnode(msg, dest->node);
1609 msg_set_destport(msg, dest->ref);
1610 msg_set_hdr_sz(msg, DIR_MSG_H_SIZE);
1611 if (importance <= TIPC_CRITICAL_IMPORTANCE)
1612 msg_set_importance(msg, importance);
1613 p_ptr->sent++;
1614 if (dest->node == tipc_own_addr)
1615 return port_recv_sections(p_ptr, num_sect, msg_sect);
1616 res = link_send_sections_fast(p_ptr, msg_sect, num_sect, dest->node);
1617 if (likely(res != -ELINKCONG))
1618 return res;
1619 if (port_unreliable(p_ptr)) {
1620 /* Just calculate msg length and return */
1621 return msg_calc_data_size(msg_sect, num_sect);
1622 }
1623 return -ELINKCONG;
1624}
1625
1626/**
1627 * tipc_send2port - send message sections to port identity
1628 */
1629
1630int tipc_send2port(u32 ref,
1631 struct tipc_portid const *dest,
1632 unsigned int num_sect,
1633 struct iovec const *msg_sect)
1634{
1635 struct tipc_portid orig;
1636
1637 orig.ref = ref;
1638 orig.node = tipc_own_addr;
1639 return tipc_forward2port(ref, dest, num_sect, msg_sect, &orig,
1640 TIPC_PORT_IMPORTANCE);
1641}
1642
1643/**
1644 * tipc_forward_buf2port - forward message buffer to port identity
1645 */
1646int tipc_forward_buf2port(u32 ref,
1647 struct tipc_portid const *dest,
1648 struct sk_buff *buf,
1649 unsigned int dsz,
1650 struct tipc_portid const *orig,
1651 unsigned int importance)
1652{
1653 struct port *p_ptr;
1654 struct tipc_msg *msg;
1655 int res;
1656
1657 p_ptr = (struct port *)ref_deref(ref);
1658 if (!p_ptr || p_ptr->publ.connected)
1659 return -EINVAL;
1660
1661 msg = &p_ptr->publ.phdr;
1662 msg_set_type(msg, TIPC_DIRECT_MSG);
1663 msg_set_orignode(msg, orig->node);
1664 msg_set_origport(msg, orig->ref);
1665 msg_set_destnode(msg, dest->node);
1666 msg_set_destport(msg, dest->ref);
1667 msg_set_hdr_sz(msg, DIR_MSG_H_SIZE);
1668 if (importance <= TIPC_CRITICAL_IMPORTANCE)
1669 msg_set_importance(msg, importance);
1670 msg_set_size(msg, DIR_MSG_H_SIZE + dsz);
1671 if (skb_cow(buf, DIR_MSG_H_SIZE))
1672 return -ENOMEM;
1673
1674 skb_push(buf, DIR_MSG_H_SIZE);
1675 memcpy(buf->data, (unchar *)msg, DIR_MSG_H_SIZE);
1676 msg_dbg(msg, "buf2port: ");
1677 p_ptr->sent++;
1678 if (dest->node == tipc_own_addr)
1679 return port_recv_msg(buf);
1680 res = tipc_send_buf_fast(buf, dest->node);
1681 if (likely(res != -ELINKCONG))
1682 return res;
1683 if (port_unreliable(p_ptr))
1684 return dsz;
1685 return -ELINKCONG;
1686}
1687
1688/**
1689 * tipc_send_buf2port - send message buffer to port identity
1690 */
1691
1692int tipc_send_buf2port(u32 ref,
1693 struct tipc_portid const *dest,
1694 struct sk_buff *buf,
1695 unsigned int dsz)
1696{
1697 struct tipc_portid orig;
1698
1699 orig.ref = ref;
1700 orig.node = tipc_own_addr;
1701 return tipc_forward_buf2port(ref, dest, buf, dsz, &orig,
1702 TIPC_PORT_IMPORTANCE);
1703}
1704
diff --git a/net/tipc/port.h b/net/tipc/port.h
new file mode 100644
index 000000000000..e40235ef92fe
--- /dev/null
+++ b/net/tipc/port.h
@@ -0,0 +1,206 @@
1/*
2 * net/tipc/port.h: Include file for TIPC port code
3 *
4 * Copyright (c) 2003-2005, Ericsson Research Canada
5 * Copyright (c) 2004-2005, Wind River Systems
6 * Copyright (c) 2005-2006, Ericsson AB
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions are met:
11 *
12 * Redistributions of source code must retain the above copyright notice, this
13 * list of conditions and the following disclaimer.
14 * Redistributions in binary form must reproduce the above copyright notice,
15 * this list of conditions and the following disclaimer in the documentation
16 * and/or other materials provided with the distribution.
17 * Neither the names of the copyright holders nor the names of its
18 * contributors may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 */
33
34#ifndef _TIPC_PORT_H
35#define _TIPC_PORT_H
36
37#include <net/tipc/tipc_port.h>
38#include "ref.h"
39#include "net.h"
40#include "msg.h"
41#include "dbg.h"
42#include "node_subscr.h"
43
44/**
45 * struct user_port - TIPC user port (used with native API)
46 * @user_ref: id of user who created user port
47 * @usr_handle: user-specified field
48 * @ref: object reference to associated TIPC port
49 * <various callback routines>
50 * @uport_list: adjacent user ports in list of ports held by user
51 */
52
53struct user_port {
54 u32 user_ref;
55 void *usr_handle;
56 u32 ref;
57 tipc_msg_err_event err_cb;
58 tipc_named_msg_err_event named_err_cb;
59 tipc_conn_shutdown_event conn_err_cb;
60 tipc_msg_event msg_cb;
61 tipc_named_msg_event named_msg_cb;
62 tipc_conn_msg_event conn_msg_cb;
63 tipc_continue_event continue_event_cb;
64 struct list_head uport_list;
65};
66
67/**
68 * struct port - TIPC port structure
69 * @publ: TIPC port info available to privileged users
70 * @port_list: adjacent ports in TIPC's global list of ports
71 * @dispatcher: ptr to routine which handles received messages
72 * @wakeup: ptr to routine to call when port is no longer congested
73 * @user_port: ptr to user port associated with port (if any)
74 * @wait_list: adjacent ports in list of ports waiting on link congestion
75 * @congested_link: ptr to congested link port is waiting on
76 * @waiting_pkts:
77 * @sent:
78 * @acked:
79 * @publications: list of publications for port
80 * @pub_count: total # of publications port has made during its lifetime
81 * @max_pkt: maximum packet size "hint" used when building messages sent by port
82 * @probing_state:
83 * @probing_interval:
84 * @last_in_seqno:
85 * @timer_ref:
86 * @subscription: "node down" subscription used to terminate failed connections
87 */
88
89struct port {
90 struct tipc_port publ;
91 struct list_head port_list;
92 u32 (*dispatcher)(struct tipc_port *, struct sk_buff *);
93 void (*wakeup)(struct tipc_port *);
94 struct user_port *user_port;
95 struct list_head wait_list;
96 struct link *congested_link;
97 u32 waiting_pkts;
98 u32 sent;
99 u32 acked;
100 struct list_head publications;
101 u32 pub_count;
102 u32 max_pkt;
103 u32 probing_state;
104 u32 probing_interval;
105 u32 last_in_seqno;
106 struct timer_list timer;
107 struct node_subscr subscription;
108};
109
110extern spinlock_t port_list_lock;
111struct port_list;
112
113int port_recv_sections(struct port *p_ptr, u32 num_sect,
114 struct iovec const *msg_sect);
115int port_reject_sections(struct port *p_ptr, struct tipc_msg *hdr,
116 struct iovec const *msg_sect, u32 num_sect,
117 int err);
118struct sk_buff *port_get_ports(void);
119struct sk_buff *port_show_stats(const void *req_tlv_area, int req_tlv_space);
120void port_recv_proto_msg(struct sk_buff *buf);
121void port_recv_mcast(struct sk_buff *buf, struct port_list *dp);
122void port_reinit(void);
123
124/**
125 * port_lock - lock port instance referred to and return its pointer
126 */
127
128static inline struct port *port_lock(u32 ref)
129{
130 return (struct port *)ref_lock(ref);
131}
132
133/**
134 * port_unlock - unlock a port instance
135 *
136 * Can use pointer instead of ref_unlock() since port is already locked.
137 */
138
139static inline void port_unlock(struct port *p_ptr)
140{
141 spin_unlock_bh(p_ptr->publ.lock);
142}
143
144static inline struct port* port_deref(u32 ref)
145{
146 return (struct port *)ref_deref(ref);
147}
148
149static inline u32 peer_port(struct port *p_ptr)
150{
151 return msg_destport(&p_ptr->publ.phdr);
152}
153
154static inline u32 peer_node(struct port *p_ptr)
155{
156 return msg_destnode(&p_ptr->publ.phdr);
157}
158
159static inline int port_congested(struct port *p_ptr)
160{
161 return((p_ptr->sent - p_ptr->acked) >= (TIPC_FLOW_CONTROL_WIN * 2));
162}
163
164/**
165 * port_recv_msg - receive message from lower layer and deliver to port user
166 */
167
168static inline int port_recv_msg(struct sk_buff *buf)
169{
170 struct port *p_ptr;
171 struct tipc_msg *msg = buf_msg(buf);
172 u32 destport = msg_destport(msg);
173 u32 dsz = msg_data_sz(msg);
174 u32 err;
175
176 /* forward unresolved named message */
177 if (unlikely(!destport)) {
178 net_route_msg(buf);
179 return dsz;
180 }
181
182 /* validate destination & pass to port, otherwise reject message */
183 p_ptr = port_lock(destport);
184 if (likely(p_ptr)) {
185 if (likely(p_ptr->publ.connected)) {
186 if ((unlikely(msg_origport(msg) != peer_port(p_ptr))) ||
187 (unlikely(msg_orignode(msg) != peer_node(p_ptr))) ||
188 (unlikely(!msg_connected(msg)))) {
189 err = TIPC_ERR_NO_PORT;
190 port_unlock(p_ptr);
191 goto reject;
192 }
193 }
194 err = p_ptr->dispatcher(&p_ptr->publ, buf);
195 port_unlock(p_ptr);
196 if (likely(!err))
197 return dsz;
198 } else {
199 err = TIPC_ERR_NO_PORT;
200 }
201reject:
202 dbg("port->rejecting, err = %x..\n",err);
203 return tipc_reject_msg(buf, err);
204}
205
206#endif
diff --git a/net/tipc/ref.c b/net/tipc/ref.c
new file mode 100644
index 000000000000..aee48c797b1e
--- /dev/null
+++ b/net/tipc/ref.c
@@ -0,0 +1,186 @@
1/*
2 * net/tipc/ref.c: TIPC object registry code
3 *
4 * Copyright (c) 2003-2005, Ericsson Research Canada
5 * Copyright (c) 2004-2005, Wind River Systems
6 * Copyright (c) 2005-2006, Ericsson AB
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions are met:
11 *
12 * Redistributions of source code must retain the above copyright notice, this
13 * list of conditions and the following disclaimer.
14 * Redistributions in binary form must reproduce the above copyright notice,
15 * this list of conditions and the following disclaimer in the documentation
16 * and/or other materials provided with the distribution.
17 * Neither the names of the copyright holders nor the names of its
18 * contributors may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 */
33
34#include "core.h"
35#include "ref.h"
36#include "port.h"
37#include "subscr.h"
38#include "name_distr.h"
39#include "name_table.h"
40#include "config.h"
41#include "discover.h"
42#include "bearer.h"
43#include "node.h"
44#include "bcast.h"
45
46/*
47 * Object reference table consists of 2**N entries.
48 *
49 * A used entry has object ptr != 0, reference == XXXX|own index
50 * (XXXX changes each time entry is acquired)
51 * A free entry has object ptr == 0, reference == YYYY|next free index
52 * (YYYY is one more than last used XXXX)
53 *
54 * Free list is initially chained from entry (2**N)-1 to entry 1.
55 * Entry 0 is not used to allow index 0 to indicate the end of the free list.
56 *
57 * Note: Any accidental reference of the form XXXX|0--0 won't match entry 0
58 * because entry 0's reference field has the form XXXX|1--1.
59 */
60
61struct ref_table ref_table = { 0 };
62
63rwlock_t reftbl_lock = RW_LOCK_UNLOCKED;
64
65/**
66 * ref_table_init - create reference table for objects
67 */
68
69int ref_table_init(u32 requested_size, u32 start)
70{
71 struct reference *table;
72 u32 sz = 1 << 4;
73 u32 index_mask;
74 int i;
75
76 while (sz < requested_size) {
77 sz <<= 1;
78 }
79 table = (struct reference *)vmalloc(sz * sizeof(struct reference));
80 if (table == NULL)
81 return -ENOMEM;
82
83 write_lock_bh(&reftbl_lock);
84 index_mask = sz - 1;
85 for (i = sz - 1; i >= 0; i--) {
86 table[i].object = 0;
87 table[i].lock = SPIN_LOCK_UNLOCKED;
88 table[i].data.next_plus_upper = (start & ~index_mask) + i - 1;
89 }
90 ref_table.entries = table;
91 ref_table.index_mask = index_mask;
92 ref_table.first_free = sz - 1;
93 ref_table.last_free = 1;
94 write_unlock_bh(&reftbl_lock);
95 return TIPC_OK;
96}
97
98/**
99 * ref_table_stop - destroy reference table for objects
100 */
101
102void ref_table_stop(void)
103{
104 if (!ref_table.entries)
105 return;
106
107 vfree(ref_table.entries);
108 ref_table.entries = 0;
109}
110
111/**
112 * ref_acquire - create reference to an object
113 *
114 * Return a unique reference value which can be translated back to the pointer
115 * 'object' at a later time. Also, pass back a pointer to the lock protecting
116 * the object, but without locking it.
117 */
118
119u32 ref_acquire(void *object, spinlock_t **lock)
120{
121 struct reference *entry;
122 u32 index;
123 u32 index_mask;
124 u32 next_plus_upper;
125 u32 reference = 0;
126
127 assert(ref_table.entries && object);
128
129 write_lock_bh(&reftbl_lock);
130 if (ref_table.first_free) {
131 index = ref_table.first_free;
132 entry = &(ref_table.entries[index]);
133 index_mask = ref_table.index_mask;
134 /* take lock in case a previous user of entry still holds it */
135 spin_lock_bh(&entry->lock);
136 next_plus_upper = entry->data.next_plus_upper;
137 ref_table.first_free = next_plus_upper & index_mask;
138 reference = (next_plus_upper & ~index_mask) + index;
139 entry->data.reference = reference;
140 entry->object = object;
141 if (lock != 0)
142 *lock = &entry->lock;
143 spin_unlock_bh(&entry->lock);
144 }
145 write_unlock_bh(&reftbl_lock);
146 return reference;
147}
148
149/**
150 * ref_discard - invalidate references to an object
151 *
152 * Disallow future references to an object and free up the entry for re-use.
153 * Note: The entry's spin_lock may still be busy after discard
154 */
155
156void ref_discard(u32 ref)
157{
158 struct reference *entry;
159 u32 index;
160 u32 index_mask;
161
162 assert(ref_table.entries);
163 assert(ref != 0);
164
165 write_lock_bh(&reftbl_lock);
166 index_mask = ref_table.index_mask;
167 index = ref & index_mask;
168 entry = &(ref_table.entries[index]);
169 assert(entry->object != 0);
170 assert(entry->data.reference == ref);
171
172 /* mark entry as unused */
173 entry->object = 0;
174 if (ref_table.first_free == 0)
175 ref_table.first_free = index;
176 else
177 /* next_plus_upper is always XXXX|0--0 for last free entry */
178 ref_table.entries[ref_table.last_free].data.next_plus_upper
179 |= index;
180 ref_table.last_free = index;
181
182 /* increment upper bits of entry to invalidate subsequent references */
183 entry->data.next_plus_upper = (ref & ~index_mask) + (index_mask + 1);
184 write_unlock_bh(&reftbl_lock);
185}
186
diff --git a/net/tipc/ref.h b/net/tipc/ref.h
new file mode 100644
index 000000000000..e6cd5bb3dc29
--- /dev/null
+++ b/net/tipc/ref.h
@@ -0,0 +1,128 @@
1/*
2 * net/tipc/ref.h: Include file for TIPC object registry code
3 *
4 * Copyright (c) 2003-2005, Ericsson Research Canada
5 * Copyright (c) 2005, Wind River Systems
6 * Copyright (c) 2005-2006, Ericsson AB
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions are met:
11 *
12 * Redistributions of source code must retain the above copyright notice, this
13 * list of conditions and the following disclaimer.
14 * Redistributions in binary form must reproduce the above copyright notice,
15 * this list of conditions and the following disclaimer in the documentation
16 * and/or other materials provided with the distribution.
17 * Neither the names of the copyright holders nor the names of its
18 * contributors may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 */
33
34#ifndef _TIPC_REF_H
35#define _TIPC_REF_H
36
37/**
38 * struct reference - TIPC object reference entry
39 * @object: pointer to object associated with reference entry
40 * @lock: spinlock controlling access to object
41 * @data: reference value associated with object (or link to next unused entry)
42 */
43
44struct reference {
45 void *object;
46 spinlock_t lock;
47 union {
48 u32 next_plus_upper;
49 u32 reference;
50 } data;
51};
52
53/**
54 * struct ref_table - table of TIPC object reference entries
55 * @entries: pointer to array of reference entries
56 * @index_mask: bitmask for array index portion of reference values
57 * @first_free: array index of first unused object reference entry
58 * @last_free: array index of last unused object reference entry
59 */
60
61struct ref_table {
62 struct reference *entries;
63 u32 index_mask;
64 u32 first_free;
65 u32 last_free;
66};
67
68extern struct ref_table ref_table;
69
70int ref_table_init(u32 requested_size, u32 start);
71void ref_table_stop(void);
72
73u32 ref_acquire(void *object, spinlock_t **lock);
74void ref_discard(u32 ref);
75
76
77/**
78 * ref_lock - lock referenced object and return pointer to it
79 */
80
81static inline void *ref_lock(u32 ref)
82{
83 if (likely(ref_table.entries)) {
84 struct reference *r =
85 &ref_table.entries[ref & ref_table.index_mask];
86
87 spin_lock_bh(&r->lock);
88 if (likely(r->data.reference == ref))
89 return r->object;
90 spin_unlock_bh(&r->lock);
91 }
92 return 0;
93}
94
95/**
96 * ref_unlock - unlock referenced object
97 */
98
99static inline void ref_unlock(u32 ref)
100{
101 if (likely(ref_table.entries)) {
102 struct reference *r =
103 &ref_table.entries[ref & ref_table.index_mask];
104
105 if (likely(r->data.reference == ref))
106 spin_unlock_bh(&r->lock);
107 else
108 err("ref_unlock() invoked using obsolete reference\n");
109 }
110}
111
112/**
113 * ref_deref - return pointer referenced object (without locking it)
114 */
115
116static inline void *ref_deref(u32 ref)
117{
118 if (likely(ref_table.entries)) {
119 struct reference *r =
120 &ref_table.entries[ref & ref_table.index_mask];
121
122 if (likely(r->data.reference == ref))
123 return r->object;
124 }
125 return 0;
126}
127
128#endif
diff --git a/net/tipc/socket.c b/net/tipc/socket.c
new file mode 100644
index 000000000000..22dcb724e760
--- /dev/null
+++ b/net/tipc/socket.c
@@ -0,0 +1,1722 @@
1/*
2 * net/tipc/socket.c: TIPC socket API
3 *
4 * Copyright (c) 2003-2005, Ericsson Research Canada
5 * Copyright (c) 2004-2005, Wind River Systems
6 * Copyright (c) 2005-2006, Ericsson AB
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions are met:
11 *
12 * Redistributions of source code must retain the above copyright notice, this
13 * list of conditions and the following disclaimer.
14 * Redistributions in binary form must reproduce the above copyright notice,
15 * this list of conditions and the following disclaimer in the documentation
16 * and/or other materials provided with the distribution.
17 * Neither the names of the copyright holders nor the names of its
18 * contributors may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 */
33
34#include <linux/module.h>
35#include <linux/types.h>
36#include <linux/net.h>
37#include <linux/socket.h>
38#include <linux/errno.h>
39#include <linux/mm.h>
40#include <linux/slab.h>
41#include <linux/poll.h>
42#include <linux/version.h>
43#include <linux/fcntl.h>
44#include <linux/version.h>
45#include <asm/semaphore.h>
46#include <asm/string.h>
47#include <asm/atomic.h>
48#include <net/sock.h>
49
50#include <linux/tipc.h>
51#include <net/tipc/tipc_msg.h>
52#include <net/tipc/tipc_port.h>
53
54#include "core.h"
55
56#define SS_LISTENING -1 /* socket is listening */
57#define SS_READY -2 /* socket is connectionless */
58
59#define OVERLOAD_LIMIT_BASE 5000
60
61struct tipc_sock {
62 struct sock sk;
63 struct tipc_port *p;
64 struct semaphore sem;
65};
66
67#define tipc_sk(sk) ((struct tipc_sock*)sk)
68
69static u32 dispatch(struct tipc_port *tport, struct sk_buff *buf);
70static void wakeupdispatch(struct tipc_port *tport);
71
72static struct proto_ops packet_ops;
73static struct proto_ops stream_ops;
74static struct proto_ops msg_ops;
75
76static struct proto tipc_proto;
77
78static int sockets_enabled = 0;
79
80static atomic_t tipc_queue_size = ATOMIC_INIT(0);
81
82
83/*
84 * sock_lock(): Lock a port/socket pair. lock_sock() can
85 * not be used here, since the same lock must protect ports
86 * with non-socket interfaces.
87 * See net.c for description of locking policy.
88 */
89static inline void sock_lock(struct tipc_sock* tsock)
90{
91 spin_lock_bh(tsock->p->lock);
92}
93
94/*
95 * sock_unlock(): Unlock a port/socket pair
96 */
97static inline void sock_unlock(struct tipc_sock* tsock)
98{
99 spin_unlock_bh(tsock->p->lock);
100}
101
102/**
103 * pollmask - determine the current set of poll() events for a socket
104 * @sock: socket structure
105 *
106 * TIPC sets the returned events as follows:
107 * a) POLLRDNORM and POLLIN are set if the socket's receive queue is non-empty
108 * or if a connection-oriented socket is does not have an active connection
109 * (i.e. a read operation will not block).
110 * b) POLLOUT is set except when a socket's connection has been terminated
111 * (i.e. a write operation will not block).
112 * c) POLLHUP is set when a socket's connection has been terminated.
113 *
114 * IMPORTANT: The fact that a read or write operation will not block does NOT
115 * imply that the operation will succeed!
116 *
117 * Returns pollmask value
118 */
119
120static inline u32 pollmask(struct socket *sock)
121{
122 u32 mask;
123
124 if ((skb_queue_len(&sock->sk->sk_receive_queue) != 0) ||
125 (sock->state == SS_UNCONNECTED) ||
126 (sock->state == SS_DISCONNECTING))
127 mask = (POLLRDNORM | POLLIN);
128 else
129 mask = 0;
130
131 if (sock->state == SS_DISCONNECTING)
132 mask |= POLLHUP;
133 else
134 mask |= POLLOUT;
135
136 return mask;
137}
138
139
140/**
141 * advance_queue - discard first buffer in queue
142 * @tsock: TIPC socket
143 */
144
145static inline void advance_queue(struct tipc_sock *tsock)
146{
147 sock_lock(tsock);
148 buf_discard(skb_dequeue(&tsock->sk.sk_receive_queue));
149 sock_unlock(tsock);
150 atomic_dec(&tipc_queue_size);
151}
152
153/**
154 * tipc_create - create a TIPC socket
155 * @sock: pre-allocated socket structure
156 * @protocol: protocol indicator (must be 0)
157 *
158 * This routine creates and attaches a 'struct sock' to the 'struct socket',
159 * then create and attaches a TIPC port to the 'struct sock' part.
160 *
161 * Returns 0 on success, errno otherwise
162 */
163static int tipc_create(struct socket *sock, int protocol)
164{
165 struct tipc_sock *tsock;
166 struct tipc_port *port;
167 struct sock *sk;
168 u32 ref;
169
170 if ((sock->type != SOCK_STREAM) &&
171 (sock->type != SOCK_SEQPACKET) &&
172 (sock->type != SOCK_DGRAM) &&
173 (sock->type != SOCK_RDM))
174 return -EPROTOTYPE;
175
176 if (unlikely(protocol != 0))
177 return -EPROTONOSUPPORT;
178
179 ref = tipc_createport_raw(0, &dispatch, &wakeupdispatch, TIPC_LOW_IMPORTANCE);
180 if (unlikely(!ref))
181 return -ENOMEM;
182
183 sock->state = SS_UNCONNECTED;
184
185 switch (sock->type) {
186 case SOCK_STREAM:
187 sock->ops = &stream_ops;
188 break;
189 case SOCK_SEQPACKET:
190 sock->ops = &packet_ops;
191 break;
192 case SOCK_DGRAM:
193 tipc_set_portunreliable(ref, 1);
194 /* fall through */
195 case SOCK_RDM:
196 tipc_set_portunreturnable(ref, 1);
197 sock->ops = &msg_ops;
198 sock->state = SS_READY;
199 break;
200 }
201
202 sk = sk_alloc(AF_TIPC, GFP_KERNEL, &tipc_proto, 1);
203 if (!sk) {
204 tipc_deleteport(ref);
205 return -ENOMEM;
206 }
207
208 sock_init_data(sock, sk);
209 init_waitqueue_head(sk->sk_sleep);
210 sk->sk_rcvtimeo = 8 * HZ; /* default connect timeout = 8s */
211
212 tsock = tipc_sk(sk);
213 port = tipc_get_port(ref);
214
215 tsock->p = port;
216 port->usr_handle = tsock;
217
218 init_MUTEX(&tsock->sem);
219
220 dbg("sock_create: %x\n",tsock);
221
222 atomic_inc(&tipc_user_count);
223
224 return 0;
225}
226
227/**
228 * release - destroy a TIPC socket
229 * @sock: socket to destroy
230 *
231 * This routine cleans up any messages that are still queued on the socket.
232 * For DGRAM and RDM socket types, all queued messages are rejected.
233 * For SEQPACKET and STREAM socket types, the first message is rejected
234 * and any others are discarded. (If the first message on a STREAM socket
235 * is partially-read, it is discarded and the next one is rejected instead.)
236 *
237 * NOTE: Rejected messages are not necessarily returned to the sender! They
238 * are returned or discarded according to the "destination droppable" setting
239 * specified for the message by the sender.
240 *
241 * Returns 0 on success, errno otherwise
242 */
243
244static int release(struct socket *sock)
245{
246 struct tipc_sock *tsock = tipc_sk(sock->sk);
247 struct sock *sk = sock->sk;
248 int res = TIPC_OK;
249 struct sk_buff *buf;
250
251 dbg("sock_delete: %x\n",tsock);
252 if (!tsock)
253 return 0;
254 down_interruptible(&tsock->sem);
255 if (!sock->sk) {
256 up(&tsock->sem);
257 return 0;
258 }
259
260 /* Reject unreceived messages, unless no longer connected */
261
262 while (sock->state != SS_DISCONNECTING) {
263 sock_lock(tsock);
264 buf = skb_dequeue(&sk->sk_receive_queue);
265 if (!buf)
266 tsock->p->usr_handle = 0;
267 sock_unlock(tsock);
268 if (!buf)
269 break;
270 if (TIPC_SKB_CB(buf)->handle != msg_data(buf_msg(buf)))
271 buf_discard(buf);
272 else
273 tipc_reject_msg(buf, TIPC_ERR_NO_PORT);
274 atomic_dec(&tipc_queue_size);
275 }
276
277 /* Delete TIPC port */
278
279 res = tipc_deleteport(tsock->p->ref);
280 sock->sk = NULL;
281
282 /* Discard any remaining messages */
283
284 while ((buf = skb_dequeue(&sk->sk_receive_queue))) {
285 buf_discard(buf);
286 atomic_dec(&tipc_queue_size);
287 }
288
289 up(&tsock->sem);
290
291 sock_put(sk);
292
293 atomic_dec(&tipc_user_count);
294 return res;
295}
296
297/**
298 * bind - associate or disassocate TIPC name(s) with a socket
299 * @sock: socket structure
300 * @uaddr: socket address describing name(s) and desired operation
301 * @uaddr_len: size of socket address data structure
302 *
303 * Name and name sequence binding is indicated using a positive scope value;
304 * a negative scope value unbinds the specified name. Specifying no name
305 * (i.e. a socket address length of 0) unbinds all names from the socket.
306 *
307 * Returns 0 on success, errno otherwise
308 */
309
310static int bind(struct socket *sock, struct sockaddr *uaddr, int uaddr_len)
311{
312 struct tipc_sock *tsock = tipc_sk(sock->sk);
313 struct sockaddr_tipc *addr = (struct sockaddr_tipc *)uaddr;
314 int res;
315
316 if (down_interruptible(&tsock->sem))
317 return -ERESTARTSYS;
318
319 if (unlikely(!uaddr_len)) {
320 res = tipc_withdraw(tsock->p->ref, 0, 0);
321 goto exit;
322 }
323
324 if (uaddr_len < sizeof(struct sockaddr_tipc)) {
325 res = -EINVAL;
326 goto exit;
327 }
328
329 if (addr->family != AF_TIPC) {
330 res = -EAFNOSUPPORT;
331 goto exit;
332 }
333 if (addr->addrtype == TIPC_ADDR_NAME)
334 addr->addr.nameseq.upper = addr->addr.nameseq.lower;
335 else if (addr->addrtype != TIPC_ADDR_NAMESEQ) {
336 res = -EAFNOSUPPORT;
337 goto exit;
338 }
339
340 if (addr->scope > 0)
341 res = tipc_publish(tsock->p->ref, addr->scope,
342 &addr->addr.nameseq);
343 else
344 res = tipc_withdraw(tsock->p->ref, -addr->scope,
345 &addr->addr.nameseq);
346exit:
347 up(&tsock->sem);
348 return res;
349}
350
351/**
352 * get_name - get port ID of socket or peer socket
353 * @sock: socket structure
354 * @uaddr: area for returned socket address
355 * @uaddr_len: area for returned length of socket address
356 * @peer: 0 to obtain socket name, 1 to obtain peer socket name
357 *
358 * Returns 0 on success, errno otherwise
359 */
360
361static int get_name(struct socket *sock, struct sockaddr *uaddr,
362 int *uaddr_len, int peer)
363{
364 struct tipc_sock *tsock = tipc_sk(sock->sk);
365 struct sockaddr_tipc *addr = (struct sockaddr_tipc *)uaddr;
366 u32 res;
367
368 if (down_interruptible(&tsock->sem))
369 return -ERESTARTSYS;
370
371 *uaddr_len = sizeof(*addr);
372 addr->addrtype = TIPC_ADDR_ID;
373 addr->family = AF_TIPC;
374 addr->scope = 0;
375 if (peer)
376 res = tipc_peer(tsock->p->ref, &addr->addr.id);
377 else
378 res = tipc_ownidentity(tsock->p->ref, &addr->addr.id);
379 addr->addr.name.domain = 0;
380
381 up(&tsock->sem);
382 return res;
383}
384
385/**
386 * poll - read and possibly block on pollmask
387 * @file: file structure associated with the socket
388 * @sock: socket for which to calculate the poll bits
389 * @wait: ???
390 *
391 * Returns the pollmask
392 */
393
394static unsigned int poll(struct file *file, struct socket *sock,
395 poll_table *wait)
396{
397 poll_wait(file, sock->sk->sk_sleep, wait);
398 /* NEED LOCK HERE? */
399 return pollmask(sock);
400}
401
402/**
403 * dest_name_check - verify user is permitted to send to specified port name
404 * @dest: destination address
405 * @m: descriptor for message to be sent
406 *
407 * Prevents restricted configuration commands from being issued by
408 * unauthorized users.
409 *
410 * Returns 0 if permission is granted, otherwise errno
411 */
412
413static inline int dest_name_check(struct sockaddr_tipc *dest, struct msghdr *m)
414{
415 struct tipc_cfg_msg_hdr hdr;
416
417 if (likely(dest->addr.name.name.type >= TIPC_RESERVED_TYPES))
418 return 0;
419 if (likely(dest->addr.name.name.type == TIPC_TOP_SRV))
420 return 0;
421
422 if (likely(dest->addr.name.name.type != TIPC_CFG_SRV))
423 return -EACCES;
424
425 if (copy_from_user(&hdr, m->msg_iov[0].iov_base, sizeof(hdr)))
426 return -EFAULT;
427 if ((ntohs(hdr.tcm_type) & 0xC000) & (!capable(CAP_NET_ADMIN)))
428 return -EACCES;
429
430 return 0;
431}
432
433/**
434 * send_msg - send message in connectionless manner
435 * @iocb: (unused)
436 * @sock: socket structure
437 * @m: message to send
438 * @total_len: (unused)
439 *
440 * Message must have an destination specified explicitly.
441 * Used for SOCK_RDM and SOCK_DGRAM messages,
442 * and for 'SYN' messages on SOCK_SEQPACKET and SOCK_STREAM connections.
443 * (Note: 'SYN+' is prohibited on SOCK_STREAM.)
444 *
445 * Returns the number of bytes sent on success, or errno otherwise
446 */
447
448static int send_msg(struct kiocb *iocb, struct socket *sock,
449 struct msghdr *m, size_t total_len)
450{
451 struct tipc_sock *tsock = tipc_sk(sock->sk);
452 struct sockaddr_tipc *dest = (struct sockaddr_tipc *)m->msg_name;
453 struct sk_buff *buf;
454 int needs_conn;
455 int res = -EINVAL;
456
457 if (unlikely(!dest))
458 return -EDESTADDRREQ;
459 if (unlikely(dest->family != AF_TIPC))
460 return -EINVAL;
461
462 needs_conn = (sock->state != SS_READY);
463 if (unlikely(needs_conn)) {
464 if (sock->state == SS_LISTENING)
465 return -EPIPE;
466 if (sock->state != SS_UNCONNECTED)
467 return -EISCONN;
468 if ((tsock->p->published) ||
469 ((sock->type == SOCK_STREAM) && (total_len != 0)))
470 return -EOPNOTSUPP;
471 }
472
473 if (down_interruptible(&tsock->sem))
474 return -ERESTARTSYS;
475
476 if (needs_conn) {
477
478 /* Abort any pending connection attempts (very unlikely) */
479
480 while ((buf = skb_dequeue(&sock->sk->sk_receive_queue))) {
481 tipc_reject_msg(buf, TIPC_ERR_NO_PORT);
482 atomic_dec(&tipc_queue_size);
483 }
484
485 sock->state = SS_CONNECTING;
486 }
487
488 do {
489 if (dest->addrtype == TIPC_ADDR_NAME) {
490 if ((res = dest_name_check(dest, m)))
491 goto exit;
492 res = tipc_send2name(tsock->p->ref,
493 &dest->addr.name.name,
494 dest->addr.name.domain,
495 m->msg_iovlen,
496 m->msg_iov);
497 }
498 else if (dest->addrtype == TIPC_ADDR_ID) {
499 res = tipc_send2port(tsock->p->ref,
500 &dest->addr.id,
501 m->msg_iovlen,
502 m->msg_iov);
503 }
504 else if (dest->addrtype == TIPC_ADDR_MCAST) {
505 if (needs_conn) {
506 res = -EOPNOTSUPP;
507 goto exit;
508 }
509 if ((res = dest_name_check(dest, m)))
510 goto exit;
511 res = tipc_multicast(tsock->p->ref,
512 &dest->addr.nameseq,
513 0,
514 m->msg_iovlen,
515 m->msg_iov);
516 }
517 if (likely(res != -ELINKCONG)) {
518exit:
519 up(&tsock->sem);
520 return res;
521 }
522 if (m->msg_flags & MSG_DONTWAIT) {
523 res = -EWOULDBLOCK;
524 goto exit;
525 }
526 if (wait_event_interruptible(*sock->sk->sk_sleep,
527 !tsock->p->congested)) {
528 res = -ERESTARTSYS;
529 goto exit;
530 }
531 } while (1);
532}
533
534/**
535 * send_packet - send a connection-oriented message
536 * @iocb: (unused)
537 * @sock: socket structure
538 * @m: message to send
539 * @total_len: (unused)
540 *
541 * Used for SOCK_SEQPACKET messages and SOCK_STREAM data.
542 *
543 * Returns the number of bytes sent on success, or errno otherwise
544 */
545
546static int send_packet(struct kiocb *iocb, struct socket *sock,
547 struct msghdr *m, size_t total_len)
548{
549 struct tipc_sock *tsock = tipc_sk(sock->sk);
550 struct sockaddr_tipc *dest = (struct sockaddr_tipc *)m->msg_name;
551 int res;
552
553 /* Handle implied connection establishment */
554
555 if (unlikely(dest))
556 return send_msg(iocb, sock, m, total_len);
557
558 if (down_interruptible(&tsock->sem)) {
559 return -ERESTARTSYS;
560 }
561
562 if (unlikely(sock->state != SS_CONNECTED)) {
563 if (sock->state == SS_DISCONNECTING)
564 res = -EPIPE;
565 else
566 res = -ENOTCONN;
567 goto exit;
568 }
569
570 do {
571 res = tipc_send(tsock->p->ref, m->msg_iovlen, m->msg_iov);
572 if (likely(res != -ELINKCONG)) {
573exit:
574 up(&tsock->sem);
575 return res;
576 }
577 if (m->msg_flags & MSG_DONTWAIT) {
578 res = -EWOULDBLOCK;
579 goto exit;
580 }
581 if (wait_event_interruptible(*sock->sk->sk_sleep,
582 !tsock->p->congested)) {
583 res = -ERESTARTSYS;
584 goto exit;
585 }
586 } while (1);
587}
588
589/**
590 * send_stream - send stream-oriented data
591 * @iocb: (unused)
592 * @sock: socket structure
593 * @m: data to send
594 * @total_len: total length of data to be sent
595 *
596 * Used for SOCK_STREAM data.
597 *
598 * Returns the number of bytes sent on success, or errno otherwise
599 */
600
601
602static int send_stream(struct kiocb *iocb, struct socket *sock,
603 struct msghdr *m, size_t total_len)
604{
605 struct msghdr my_msg;
606 struct iovec my_iov;
607 struct iovec *curr_iov;
608 int curr_iovlen;
609 char __user *curr_start;
610 int curr_left;
611 int bytes_to_send;
612 int res;
613
614 if (likely(total_len <= TIPC_MAX_USER_MSG_SIZE))
615 return send_packet(iocb, sock, m, total_len);
616
617 /* Can only send large data streams if already connected */
618
619 if (unlikely(sock->state != SS_CONNECTED)) {
620 if (sock->state == SS_DISCONNECTING)
621 return -EPIPE;
622 else
623 return -ENOTCONN;
624 }
625
626 /*
627 * Send each iovec entry using one or more messages
628 *
629 * Note: This algorithm is good for the most likely case
630 * (i.e. one large iovec entry), but could be improved to pass sets
631 * of small iovec entries into send_packet().
632 */
633
634 my_msg = *m;
635 curr_iov = my_msg.msg_iov;
636 curr_iovlen = my_msg.msg_iovlen;
637 my_msg.msg_iov = &my_iov;
638 my_msg.msg_iovlen = 1;
639
640 while (curr_iovlen--) {
641 curr_start = curr_iov->iov_base;
642 curr_left = curr_iov->iov_len;
643
644 while (curr_left) {
645 bytes_to_send = (curr_left < TIPC_MAX_USER_MSG_SIZE)
646 ? curr_left : TIPC_MAX_USER_MSG_SIZE;
647 my_iov.iov_base = curr_start;
648 my_iov.iov_len = bytes_to_send;
649 if ((res = send_packet(iocb, sock, &my_msg, 0)) < 0)
650 return res;
651 curr_left -= bytes_to_send;
652 curr_start += bytes_to_send;
653 }
654
655 curr_iov++;
656 }
657
658 return total_len;
659}
660
661/**
662 * auto_connect - complete connection setup to a remote port
663 * @sock: socket structure
664 * @tsock: TIPC-specific socket structure
665 * @msg: peer's response message
666 *
667 * Returns 0 on success, errno otherwise
668 */
669
670static int auto_connect(struct socket *sock, struct tipc_sock *tsock,
671 struct tipc_msg *msg)
672{
673 struct tipc_portid peer;
674
675 if (msg_errcode(msg)) {
676 sock->state = SS_DISCONNECTING;
677 return -ECONNREFUSED;
678 }
679
680 peer.ref = msg_origport(msg);
681 peer.node = msg_orignode(msg);
682 tipc_connect2port(tsock->p->ref, &peer);
683 tipc_set_portimportance(tsock->p->ref, msg_importance(msg));
684 sock->state = SS_CONNECTED;
685 return 0;
686}
687
688/**
689 * set_orig_addr - capture sender's address for received message
690 * @m: descriptor for message info
691 * @msg: received message header
692 *
693 * Note: Address is not captured if not requested by receiver.
694 */
695
696static inline void set_orig_addr(struct msghdr *m, struct tipc_msg *msg)
697{
698 struct sockaddr_tipc *addr = (struct sockaddr_tipc *)m->msg_name;
699
700 if (addr) {
701 addr->family = AF_TIPC;
702 addr->addrtype = TIPC_ADDR_ID;
703 addr->addr.id.ref = msg_origport(msg);
704 addr->addr.id.node = msg_orignode(msg);
705 addr->addr.name.domain = 0; /* could leave uninitialized */
706 addr->scope = 0; /* could leave uninitialized */
707 m->msg_namelen = sizeof(struct sockaddr_tipc);
708 }
709}
710
711/**
712 * anc_data_recv - optionally capture ancillary data for received message
713 * @m: descriptor for message info
714 * @msg: received message header
715 * @tport: TIPC port associated with message
716 *
717 * Note: Ancillary data is not captured if not requested by receiver.
718 *
719 * Returns 0 if successful, otherwise errno
720 */
721
722static inline int anc_data_recv(struct msghdr *m, struct tipc_msg *msg,
723 struct tipc_port *tport)
724{
725 u32 anc_data[3];
726 u32 err;
727 u32 dest_type;
728 int res;
729
730 if (likely(m->msg_controllen == 0))
731 return 0;
732
733 /* Optionally capture errored message object(s) */
734
735 err = msg ? msg_errcode(msg) : 0;
736 if (unlikely(err)) {
737 anc_data[0] = err;
738 anc_data[1] = msg_data_sz(msg);
739 if ((res = put_cmsg(m, SOL_SOCKET, TIPC_ERRINFO, 8, anc_data)))
740 return res;
741 if (anc_data[1] &&
742 (res = put_cmsg(m, SOL_SOCKET, TIPC_RETDATA, anc_data[1],
743 msg_data(msg))))
744 return res;
745 }
746
747 /* Optionally capture message destination object */
748
749 dest_type = msg ? msg_type(msg) : TIPC_DIRECT_MSG;
750 switch (dest_type) {
751 case TIPC_NAMED_MSG:
752 anc_data[0] = msg_nametype(msg);
753 anc_data[1] = msg_namelower(msg);
754 anc_data[2] = msg_namelower(msg);
755 break;
756 case TIPC_MCAST_MSG:
757 anc_data[0] = msg_nametype(msg);
758 anc_data[1] = msg_namelower(msg);
759 anc_data[2] = msg_nameupper(msg);
760 break;
761 case TIPC_CONN_MSG:
762 anc_data[0] = tport->conn_type;
763 anc_data[1] = tport->conn_instance;
764 anc_data[2] = tport->conn_instance;
765 break;
766 default:
767 anc_data[0] = 0;
768 }
769 if (anc_data[0] &&
770 (res = put_cmsg(m, SOL_SOCKET, TIPC_DESTNAME, 12, anc_data)))
771 return res;
772
773 return 0;
774}
775
776/**
777 * recv_msg - receive packet-oriented message
778 * @iocb: (unused)
779 * @m: descriptor for message info
780 * @buf_len: total size of user buffer area
781 * @flags: receive flags
782 *
783 * Used for SOCK_DGRAM, SOCK_RDM, and SOCK_SEQPACKET messages.
784 * If the complete message doesn't fit in user area, truncate it.
785 *
786 * Returns size of returned message data, errno otherwise
787 */
788
789static int recv_msg(struct kiocb *iocb, struct socket *sock,
790 struct msghdr *m, size_t buf_len, int flags)
791{
792 struct tipc_sock *tsock = tipc_sk(sock->sk);
793 struct sk_buff *buf;
794 struct tipc_msg *msg;
795 unsigned int q_len;
796 unsigned int sz;
797 u32 err;
798 int res;
799
800 /* Currently doesn't support receiving into multiple iovec entries */
801
802 if (m->msg_iovlen != 1)
803 return -EOPNOTSUPP;
804
805 /* Catch invalid receive attempts */
806
807 if (unlikely(!buf_len))
808 return -EINVAL;
809
810 if (sock->type == SOCK_SEQPACKET) {
811 if (unlikely(sock->state == SS_UNCONNECTED))
812 return -ENOTCONN;
813 if (unlikely((sock->state == SS_DISCONNECTING) &&
814 (skb_queue_len(&sock->sk->sk_receive_queue) == 0)))
815 return -ENOTCONN;
816 }
817
818 /* Look for a message in receive queue; wait if necessary */
819
820 if (unlikely(down_interruptible(&tsock->sem)))
821 return -ERESTARTSYS;
822
823restart:
824 if (unlikely((skb_queue_len(&sock->sk->sk_receive_queue) == 0) &&
825 (flags & MSG_DONTWAIT))) {
826 res = -EWOULDBLOCK;
827 goto exit;
828 }
829
830 if ((res = wait_event_interruptible(
831 *sock->sk->sk_sleep,
832 ((q_len = skb_queue_len(&sock->sk->sk_receive_queue)) ||
833 (sock->state == SS_DISCONNECTING))) )) {
834 goto exit;
835 }
836
837 /* Catch attempt to receive on an already terminated connection */
838 /* [THIS CHECK MAY OVERLAP WITH AN EARLIER CHECK] */
839
840 if (!q_len) {
841 res = -ENOTCONN;
842 goto exit;
843 }
844
845 /* Get access to first message in receive queue */
846
847 buf = skb_peek(&sock->sk->sk_receive_queue);
848 msg = buf_msg(buf);
849 sz = msg_data_sz(msg);
850 err = msg_errcode(msg);
851
852 /* Complete connection setup for an implied connect */
853
854 if (unlikely(sock->state == SS_CONNECTING)) {
855 if ((res = auto_connect(sock, tsock, msg)))
856 goto exit;
857 }
858
859 /* Discard an empty non-errored message & try again */
860
861 if ((!sz) && (!err)) {
862 advance_queue(tsock);
863 goto restart;
864 }
865
866 /* Capture sender's address (optional) */
867
868 set_orig_addr(m, msg);
869
870 /* Capture ancillary data (optional) */
871
872 if ((res = anc_data_recv(m, msg, tsock->p)))
873 goto exit;
874
875 /* Capture message data (if valid) & compute return value (always) */
876
877 if (!err) {
878 if (unlikely(buf_len < sz)) {
879 sz = buf_len;
880 m->msg_flags |= MSG_TRUNC;
881 }
882 if (unlikely(copy_to_user(m->msg_iov->iov_base, msg_data(msg),
883 sz))) {
884 res = -EFAULT;
885 goto exit;
886 }
887 res = sz;
888 } else {
889 if ((sock->state == SS_READY) ||
890 ((err == TIPC_CONN_SHUTDOWN) || m->msg_control))
891 res = 0;
892 else
893 res = -ECONNRESET;
894 }
895
896 /* Consume received message (optional) */
897
898 if (likely(!(flags & MSG_PEEK))) {
899 if (unlikely(++tsock->p->conn_unacked >= TIPC_FLOW_CONTROL_WIN))
900 tipc_acknowledge(tsock->p->ref, tsock->p->conn_unacked);
901 advance_queue(tsock);
902 }
903exit:
904 up(&tsock->sem);
905 return res;
906}
907
908/**
909 * recv_stream - receive stream-oriented data
910 * @iocb: (unused)
911 * @m: descriptor for message info
912 * @buf_len: total size of user buffer area
913 * @flags: receive flags
914 *
915 * Used for SOCK_STREAM messages only. If not enough data is available
916 * will optionally wait for more; never truncates data.
917 *
918 * Returns size of returned message data, errno otherwise
919 */
920
921static int recv_stream(struct kiocb *iocb, struct socket *sock,
922 struct msghdr *m, size_t buf_len, int flags)
923{
924 struct tipc_sock *tsock = tipc_sk(sock->sk);
925 struct sk_buff *buf;
926 struct tipc_msg *msg;
927 unsigned int q_len;
928 unsigned int sz;
929 int sz_to_copy;
930 int sz_copied = 0;
931 int needed;
932 char *crs = m->msg_iov->iov_base;
933 unsigned char *buf_crs;
934 u32 err;
935 int res;
936
937 /* Currently doesn't support receiving into multiple iovec entries */
938
939 if (m->msg_iovlen != 1)
940 return -EOPNOTSUPP;
941
942 /* Catch invalid receive attempts */
943
944 if (unlikely(!buf_len))
945 return -EINVAL;
946
947 if (unlikely(sock->state == SS_DISCONNECTING)) {
948 if (skb_queue_len(&sock->sk->sk_receive_queue) == 0)
949 return -ENOTCONN;
950 } else if (unlikely(sock->state != SS_CONNECTED))
951 return -ENOTCONN;
952
953 /* Look for a message in receive queue; wait if necessary */
954
955 if (unlikely(down_interruptible(&tsock->sem)))
956 return -ERESTARTSYS;
957
958restart:
959 if (unlikely((skb_queue_len(&sock->sk->sk_receive_queue) == 0) &&
960 (flags & MSG_DONTWAIT))) {
961 res = (sz_copied == 0) ? -EWOULDBLOCK : 0;
962 goto exit;
963 }
964
965 if ((res = wait_event_interruptible(
966 *sock->sk->sk_sleep,
967 ((q_len = skb_queue_len(&sock->sk->sk_receive_queue)) ||
968 (sock->state == SS_DISCONNECTING))) )) {
969 goto exit;
970 }
971
972 /* Catch attempt to receive on an already terminated connection */
973 /* [THIS CHECK MAY OVERLAP WITH AN EARLIER CHECK] */
974
975 if (!q_len) {
976 res = -ENOTCONN;
977 goto exit;
978 }
979
980 /* Get access to first message in receive queue */
981
982 buf = skb_peek(&sock->sk->sk_receive_queue);
983 msg = buf_msg(buf);
984 sz = msg_data_sz(msg);
985 err = msg_errcode(msg);
986
987 /* Discard an empty non-errored message & try again */
988
989 if ((!sz) && (!err)) {
990 advance_queue(tsock);
991 goto restart;
992 }
993
994 /* Optionally capture sender's address & ancillary data of first msg */
995
996 if (sz_copied == 0) {
997 set_orig_addr(m, msg);
998 if ((res = anc_data_recv(m, msg, tsock->p)))
999 goto exit;
1000 }
1001
1002 /* Capture message data (if valid) & compute return value (always) */
1003
1004 if (!err) {
1005 buf_crs = (unsigned char *)(TIPC_SKB_CB(buf)->handle);
1006 sz = buf->tail - buf_crs;
1007
1008 needed = (buf_len - sz_copied);
1009 sz_to_copy = (sz <= needed) ? sz : needed;
1010 if (unlikely(copy_to_user(crs, buf_crs, sz_to_copy))) {
1011 res = -EFAULT;
1012 goto exit;
1013 }
1014 sz_copied += sz_to_copy;
1015
1016 if (sz_to_copy < sz) {
1017 if (!(flags & MSG_PEEK))
1018 TIPC_SKB_CB(buf)->handle = buf_crs + sz_to_copy;
1019 goto exit;
1020 }
1021
1022 crs += sz_to_copy;
1023 } else {
1024 if (sz_copied != 0)
1025 goto exit; /* can't add error msg to valid data */
1026
1027 if ((err == TIPC_CONN_SHUTDOWN) || m->msg_control)
1028 res = 0;
1029 else
1030 res = -ECONNRESET;
1031 }
1032
1033 /* Consume received message (optional) */
1034
1035 if (likely(!(flags & MSG_PEEK))) {
1036 if (unlikely(++tsock->p->conn_unacked >= TIPC_FLOW_CONTROL_WIN))
1037 tipc_acknowledge(tsock->p->ref, tsock->p->conn_unacked);
1038 advance_queue(tsock);
1039 }
1040
1041 /* Loop around if more data is required */
1042
1043 if ((sz_copied < buf_len) /* didn't get all requested data */
1044 && (flags & MSG_WAITALL) /* ... and need to wait for more */
1045 && (!(flags & MSG_PEEK)) /* ... and aren't just peeking at data */
1046 && (!err) /* ... and haven't reached a FIN */
1047 )
1048 goto restart;
1049
1050exit:
1051 up(&tsock->sem);
1052 return res ? res : sz_copied;
1053}
1054
1055/**
1056 * queue_overloaded - test if queue overload condition exists
1057 * @queue_size: current size of queue
1058 * @base: nominal maximum size of queue
1059 * @msg: message to be added to queue
1060 *
1061 * Returns 1 if queue is currently overloaded, 0 otherwise
1062 */
1063
1064static int queue_overloaded(u32 queue_size, u32 base, struct tipc_msg *msg)
1065{
1066 u32 threshold;
1067 u32 imp = msg_importance(msg);
1068
1069 if (imp == TIPC_LOW_IMPORTANCE)
1070 threshold = base;
1071 else if (imp == TIPC_MEDIUM_IMPORTANCE)
1072 threshold = base * 2;
1073 else if (imp == TIPC_HIGH_IMPORTANCE)
1074 threshold = base * 100;
1075 else
1076 return 0;
1077
1078 if (msg_connected(msg))
1079 threshold *= 4;
1080
1081 return (queue_size > threshold);
1082}
1083
1084/**
1085 * async_disconnect - wrapper function used to disconnect port
1086 * @portref: TIPC port reference (passed as pointer-sized value)
1087 */
1088
1089static void async_disconnect(unsigned long portref)
1090{
1091 tipc_disconnect((u32)portref);
1092}
1093
1094/**
1095 * dispatch - handle arriving message
1096 * @tport: TIPC port that received message
1097 * @buf: message
1098 *
1099 * Called with port locked. Must not take socket lock to avoid deadlock risk.
1100 *
1101 * Returns TIPC error status code (TIPC_OK if message is not to be rejected)
1102 */
1103
1104static u32 dispatch(struct tipc_port *tport, struct sk_buff *buf)
1105{
1106 struct tipc_msg *msg = buf_msg(buf);
1107 struct tipc_sock *tsock = (struct tipc_sock *)tport->usr_handle;
1108 struct socket *sock;
1109 u32 recv_q_len;
1110
1111 /* Reject message if socket is closing */
1112
1113 if (!tsock)
1114 return TIPC_ERR_NO_PORT;
1115
1116 /* Reject message if it is wrong sort of message for socket */
1117
1118 /*
1119 * WOULD IT BE BETTER TO JUST DISCARD THESE MESSAGES INSTEAD?
1120 * "NO PORT" ISN'T REALLY THE RIGHT ERROR CODE, AND THERE MAY
1121 * BE SECURITY IMPLICATIONS INHERENT IN REJECTING INVALID TRAFFIC
1122 */
1123 sock = tsock->sk.sk_socket;
1124 if (sock->state == SS_READY) {
1125 if (msg_connected(msg)) {
1126 msg_dbg(msg, "dispatch filter 1\n");
1127 return TIPC_ERR_NO_PORT;
1128 }
1129 } else {
1130 if (msg_mcast(msg)) {
1131 msg_dbg(msg, "dispatch filter 2\n");
1132 return TIPC_ERR_NO_PORT;
1133 }
1134 if (sock->state == SS_CONNECTED) {
1135 if (!msg_connected(msg)) {
1136 msg_dbg(msg, "dispatch filter 3\n");
1137 return TIPC_ERR_NO_PORT;
1138 }
1139 }
1140 else if (sock->state == SS_CONNECTING) {
1141 if (!msg_connected(msg) && (msg_errcode(msg) == 0)) {
1142 msg_dbg(msg, "dispatch filter 4\n");
1143 return TIPC_ERR_NO_PORT;
1144 }
1145 }
1146 else if (sock->state == SS_LISTENING) {
1147 if (msg_connected(msg) || msg_errcode(msg)) {
1148 msg_dbg(msg, "dispatch filter 5\n");
1149 return TIPC_ERR_NO_PORT;
1150 }
1151 }
1152 else if (sock->state == SS_DISCONNECTING) {
1153 msg_dbg(msg, "dispatch filter 6\n");
1154 return TIPC_ERR_NO_PORT;
1155 }
1156 else /* (sock->state == SS_UNCONNECTED) */ {
1157 if (msg_connected(msg) || msg_errcode(msg)) {
1158 msg_dbg(msg, "dispatch filter 7\n");
1159 return TIPC_ERR_NO_PORT;
1160 }
1161 }
1162 }
1163
1164 /* Reject message if there isn't room to queue it */
1165
1166 if (unlikely((u32)atomic_read(&tipc_queue_size) >
1167 OVERLOAD_LIMIT_BASE)) {
1168 if (queue_overloaded(atomic_read(&tipc_queue_size),
1169 OVERLOAD_LIMIT_BASE, msg))
1170 return TIPC_ERR_OVERLOAD;
1171 }
1172 recv_q_len = skb_queue_len(&tsock->sk.sk_receive_queue);
1173 if (unlikely(recv_q_len > (OVERLOAD_LIMIT_BASE / 2))) {
1174 if (queue_overloaded(recv_q_len,
1175 OVERLOAD_LIMIT_BASE / 2, msg))
1176 return TIPC_ERR_OVERLOAD;
1177 }
1178
1179 /* Initiate connection termination for an incoming 'FIN' */
1180
1181 if (unlikely(msg_errcode(msg) && (sock->state == SS_CONNECTED))) {
1182 sock->state = SS_DISCONNECTING;
1183 /* Note: Use signal since port lock is already taken! */
1184 k_signal((Handler)async_disconnect, tport->ref);
1185 }
1186
1187 /* Enqueue message (finally!) */
1188
1189 msg_dbg(msg,"<DISP<: ");
1190 TIPC_SKB_CB(buf)->handle = msg_data(msg);
1191 atomic_inc(&tipc_queue_size);
1192 skb_queue_tail(&sock->sk->sk_receive_queue, buf);
1193
1194 wake_up_interruptible(sock->sk->sk_sleep);
1195 return TIPC_OK;
1196}
1197
1198/**
1199 * wakeupdispatch - wake up port after congestion
1200 * @tport: port to wakeup
1201 *
1202 * Called with port lock on.
1203 */
1204
1205static void wakeupdispatch(struct tipc_port *tport)
1206{
1207 struct tipc_sock *tsock = (struct tipc_sock *)tport->usr_handle;
1208
1209 wake_up_interruptible(tsock->sk.sk_sleep);
1210}
1211
1212/**
1213 * connect - establish a connection to another TIPC port
1214 * @sock: socket structure
1215 * @dest: socket address for destination port
1216 * @destlen: size of socket address data structure
1217 * @flags: (unused)
1218 *
1219 * Returns 0 on success, errno otherwise
1220 */
1221
1222static int connect(struct socket *sock, struct sockaddr *dest, int destlen,
1223 int flags)
1224{
1225 struct tipc_sock *tsock = tipc_sk(sock->sk);
1226 struct sockaddr_tipc *dst = (struct sockaddr_tipc *)dest;
1227 struct msghdr m = {0,};
1228 struct sk_buff *buf;
1229 struct tipc_msg *msg;
1230 int res;
1231
1232 /* For now, TIPC does not allow use of connect() with DGRAM or RDM types */
1233
1234 if (sock->state == SS_READY)
1235 return -EOPNOTSUPP;
1236
1237 /* MOVE THE REST OF THIS ERROR CHECKING TO send_msg()? */
1238 if (sock->state == SS_LISTENING)
1239 return -EOPNOTSUPP;
1240 if (sock->state == SS_CONNECTING)
1241 return -EALREADY;
1242 if (sock->state != SS_UNCONNECTED)
1243 return -EISCONN;
1244
1245 if ((dst->family != AF_TIPC) ||
1246 ((dst->addrtype != TIPC_ADDR_NAME) && (dst->addrtype != TIPC_ADDR_ID)))
1247 return -EINVAL;
1248
1249 /* Send a 'SYN-' to destination */
1250
1251 m.msg_name = dest;
1252 if ((res = send_msg(0, sock, &m, 0)) < 0) {
1253 sock->state = SS_DISCONNECTING;
1254 return res;
1255 }
1256
1257 if (down_interruptible(&tsock->sem))
1258 return -ERESTARTSYS;
1259
1260 /* Wait for destination's 'ACK' response */
1261
1262 res = wait_event_interruptible_timeout(*sock->sk->sk_sleep,
1263 skb_queue_len(&sock->sk->sk_receive_queue),
1264 sock->sk->sk_rcvtimeo);
1265 buf = skb_peek(&sock->sk->sk_receive_queue);
1266 if (res > 0) {
1267 msg = buf_msg(buf);
1268 res = auto_connect(sock, tsock, msg);
1269 if (!res) {
1270 if (dst->addrtype == TIPC_ADDR_NAME) {
1271 tsock->p->conn_type = dst->addr.name.name.type;
1272 tsock->p->conn_instance = dst->addr.name.name.instance;
1273 }
1274 if (!msg_data_sz(msg))
1275 advance_queue(tsock);
1276 }
1277 } else {
1278 if (res == 0) {
1279 res = -ETIMEDOUT;
1280 } else
1281 { /* leave "res" unchanged */ }
1282 sock->state = SS_DISCONNECTING;
1283 }
1284
1285 up(&tsock->sem);
1286 return res;
1287}
1288
1289/**
1290 * listen - allow socket to listen for incoming connections
1291 * @sock: socket structure
1292 * @len: (unused)
1293 *
1294 * Returns 0 on success, errno otherwise
1295 */
1296
1297static int listen(struct socket *sock, int len)
1298{
1299 /* REQUIRES SOCKET LOCKING OF SOME SORT? */
1300
1301 if (sock->state == SS_READY)
1302 return -EOPNOTSUPP;
1303 if (sock->state != SS_UNCONNECTED)
1304 return -EINVAL;
1305 sock->state = SS_LISTENING;
1306 return 0;
1307}
1308
1309/**
1310 * accept - wait for connection request
1311 * @sock: listening socket
1312 * @newsock: new socket that is to be connected
1313 * @flags: file-related flags associated with socket
1314 *
1315 * Returns 0 on success, errno otherwise
1316 */
1317
1318static int accept(struct socket *sock, struct socket *newsock, int flags)
1319{
1320 struct tipc_sock *tsock = tipc_sk(sock->sk);
1321 struct sk_buff *buf;
1322 int res = -EFAULT;
1323
1324 if (sock->state == SS_READY)
1325 return -EOPNOTSUPP;
1326 if (sock->state != SS_LISTENING)
1327 return -EINVAL;
1328
1329 if (unlikely((skb_queue_len(&sock->sk->sk_receive_queue) == 0) &&
1330 (flags & O_NONBLOCK)))
1331 return -EWOULDBLOCK;
1332
1333 if (down_interruptible(&tsock->sem))
1334 return -ERESTARTSYS;
1335
1336 if (wait_event_interruptible(*sock->sk->sk_sleep,
1337 skb_queue_len(&sock->sk->sk_receive_queue))) {
1338 res = -ERESTARTSYS;
1339 goto exit;
1340 }
1341 buf = skb_peek(&sock->sk->sk_receive_queue);
1342
1343 res = tipc_create(newsock, 0);
1344 if (!res) {
1345 struct tipc_sock *new_tsock = tipc_sk(newsock->sk);
1346 struct tipc_portid id;
1347 struct tipc_msg *msg = buf_msg(buf);
1348 u32 new_ref = new_tsock->p->ref;
1349
1350 id.ref = msg_origport(msg);
1351 id.node = msg_orignode(msg);
1352 tipc_connect2port(new_ref, &id);
1353 newsock->state = SS_CONNECTED;
1354
1355 tipc_set_portimportance(new_ref, msg_importance(msg));
1356 if (msg_named(msg)) {
1357 new_tsock->p->conn_type = msg_nametype(msg);
1358 new_tsock->p->conn_instance = msg_nameinst(msg);
1359 }
1360
1361 /*
1362 * Respond to 'SYN-' by discarding it & returning 'ACK'-.
1363 * Respond to 'SYN+' by queuing it on new socket.
1364 */
1365
1366 msg_dbg(msg,"<ACC<: ");
1367 if (!msg_data_sz(msg)) {
1368 struct msghdr m = {0,};
1369
1370 send_packet(0, newsock, &m, 0);
1371 advance_queue(tsock);
1372 } else {
1373 sock_lock(tsock);
1374 skb_dequeue(&sock->sk->sk_receive_queue);
1375 sock_unlock(tsock);
1376 skb_queue_head(&newsock->sk->sk_receive_queue, buf);
1377 }
1378 }
1379exit:
1380 up(&tsock->sem);
1381 return res;
1382}
1383
1384/**
1385 * shutdown - shutdown socket connection
1386 * @sock: socket structure
1387 * @how: direction to close (always treated as read + write)
1388 *
1389 * Terminates connection (if necessary), then purges socket's receive queue.
1390 *
1391 * Returns 0 on success, errno otherwise
1392 */
1393
1394static int shutdown(struct socket *sock, int how)
1395{
1396 struct tipc_sock* tsock = tipc_sk(sock->sk);
1397 struct sk_buff *buf;
1398 int res;
1399
1400 /* Could return -EINVAL for an invalid "how", but why bother? */
1401
1402 if (down_interruptible(&tsock->sem))
1403 return -ERESTARTSYS;
1404
1405 sock_lock(tsock);
1406
1407 switch (sock->state) {
1408 case SS_CONNECTED:
1409
1410 /* Send 'FIN+' or 'FIN-' message to peer */
1411
1412 sock_unlock(tsock);
1413restart:
1414 if ((buf = skb_dequeue(&sock->sk->sk_receive_queue))) {
1415 atomic_dec(&tipc_queue_size);
1416 if (TIPC_SKB_CB(buf)->handle != msg_data(buf_msg(buf))) {
1417 buf_discard(buf);
1418 goto restart;
1419 }
1420 tipc_reject_msg(buf, TIPC_CONN_SHUTDOWN);
1421 }
1422 else {
1423 tipc_shutdown(tsock->p->ref);
1424 }
1425 sock_lock(tsock);
1426
1427 /* fall through */
1428
1429 case SS_DISCONNECTING:
1430
1431 /* Discard any unreceived messages */
1432
1433 while ((buf = skb_dequeue(&sock->sk->sk_receive_queue))) {
1434 atomic_dec(&tipc_queue_size);
1435 buf_discard(buf);
1436 }
1437 tsock->p->conn_unacked = 0;
1438
1439 /* fall through */
1440
1441 case SS_CONNECTING:
1442 sock->state = SS_DISCONNECTING;
1443 res = 0;
1444 break;
1445
1446 default:
1447 res = -ENOTCONN;
1448 }
1449
1450 sock_unlock(tsock);
1451
1452 up(&tsock->sem);
1453 return res;
1454}
1455
1456/**
1457 * setsockopt - set socket option
1458 * @sock: socket structure
1459 * @lvl: option level
1460 * @opt: option identifier
1461 * @ov: pointer to new option value
1462 * @ol: length of option value
1463 *
1464 * For stream sockets only, accepts and ignores all IPPROTO_TCP options
1465 * (to ease compatibility).
1466 *
1467 * Returns 0 on success, errno otherwise
1468 */
1469
1470static int setsockopt(struct socket *sock, int lvl, int opt, char *ov, int ol)
1471{
1472 struct tipc_sock *tsock = tipc_sk(sock->sk);
1473 u32 value;
1474 int res;
1475
1476 if ((lvl == IPPROTO_TCP) && (sock->type == SOCK_STREAM))
1477 return 0;
1478 if (lvl != SOL_TIPC)
1479 return -ENOPROTOOPT;
1480 if (ol < sizeof(value))
1481 return -EINVAL;
1482 if ((res = get_user(value, (u32 *)ov)))
1483 return res;
1484
1485 if (down_interruptible(&tsock->sem))
1486 return -ERESTARTSYS;
1487
1488 switch (opt) {
1489 case TIPC_IMPORTANCE:
1490 res = tipc_set_portimportance(tsock->p->ref, value);
1491 break;
1492 case TIPC_SRC_DROPPABLE:
1493 if (sock->type != SOCK_STREAM)
1494 res = tipc_set_portunreliable(tsock->p->ref, value);
1495 else
1496 res = -ENOPROTOOPT;
1497 break;
1498 case TIPC_DEST_DROPPABLE:
1499 res = tipc_set_portunreturnable(tsock->p->ref, value);
1500 break;
1501 case TIPC_CONN_TIMEOUT:
1502 sock->sk->sk_rcvtimeo = (value * HZ / 1000);
1503 break;
1504 default:
1505 res = -EINVAL;
1506 }
1507
1508 up(&tsock->sem);
1509 return res;
1510}
1511
1512/**
1513 * getsockopt - get socket option
1514 * @sock: socket structure
1515 * @lvl: option level
1516 * @opt: option identifier
1517 * @ov: receptacle for option value
1518 * @ol: receptacle for length of option value
1519 *
1520 * For stream sockets only, returns 0 length result for all IPPROTO_TCP options
1521 * (to ease compatibility).
1522 *
1523 * Returns 0 on success, errno otherwise
1524 */
1525
1526static int getsockopt(struct socket *sock, int lvl, int opt, char *ov, int *ol)
1527{
1528 struct tipc_sock *tsock = tipc_sk(sock->sk);
1529 int len;
1530 u32 value;
1531 int res;
1532
1533 if ((lvl == IPPROTO_TCP) && (sock->type == SOCK_STREAM))
1534 return put_user(0, ol);
1535 if (lvl != SOL_TIPC)
1536 return -ENOPROTOOPT;
1537 if ((res = get_user(len, ol)))
1538 return res;
1539
1540 if (down_interruptible(&tsock->sem))
1541 return -ERESTARTSYS;
1542
1543 switch (opt) {
1544 case TIPC_IMPORTANCE:
1545 res = tipc_portimportance(tsock->p->ref, &value);
1546 break;
1547 case TIPC_SRC_DROPPABLE:
1548 res = tipc_portunreliable(tsock->p->ref, &value);
1549 break;
1550 case TIPC_DEST_DROPPABLE:
1551 res = tipc_portunreturnable(tsock->p->ref, &value);
1552 break;
1553 case TIPC_CONN_TIMEOUT:
1554 value = (sock->sk->sk_rcvtimeo * 1000) / HZ;
1555 break;
1556 default:
1557 res = -EINVAL;
1558 }
1559
1560 if (res) {
1561 /* "get" failed */
1562 }
1563 else if (len < sizeof(value)) {
1564 res = -EINVAL;
1565 }
1566 else if ((res = copy_to_user(ov, &value, sizeof(value)))) {
1567 /* couldn't return value */
1568 }
1569 else {
1570 res = put_user(sizeof(value), ol);
1571 }
1572
1573 up(&tsock->sem);
1574 return res;
1575}
1576
1577/**
1578 * Placeholders for non-implemented functionality
1579 *
1580 * Returns error code (POSIX-compliant where defined)
1581 */
1582
1583static int ioctl(struct socket *s, u32 cmd, unsigned long arg)
1584{
1585 return -EINVAL;
1586}
1587
1588static int no_mmap(struct file *file, struct socket *sock,
1589 struct vm_area_struct *vma)
1590{
1591 return -EINVAL;
1592}
1593static ssize_t no_sendpage(struct socket *sock, struct page *page,
1594 int offset, size_t size, int flags)
1595{
1596 return -EINVAL;
1597}
1598
1599static int no_skpair(struct socket *s1, struct socket *s2)
1600{
1601 return -EOPNOTSUPP;
1602}
1603
1604/**
1605 * Protocol switches for the various types of TIPC sockets
1606 */
1607
1608static struct proto_ops msg_ops = {
1609 .owner = THIS_MODULE,
1610 .family = AF_TIPC,
1611 .release = release,
1612 .bind = bind,
1613 .connect = connect,
1614 .socketpair = no_skpair,
1615 .accept = accept,
1616 .getname = get_name,
1617 .poll = poll,
1618 .ioctl = ioctl,
1619 .listen = listen,
1620 .shutdown = shutdown,
1621 .setsockopt = setsockopt,
1622 .getsockopt = getsockopt,
1623 .sendmsg = send_msg,
1624 .recvmsg = recv_msg,
1625 .mmap = no_mmap,
1626 .sendpage = no_sendpage
1627};
1628
1629static struct proto_ops packet_ops = {
1630 .owner = THIS_MODULE,
1631 .family = AF_TIPC,
1632 .release = release,
1633 .bind = bind,
1634 .connect = connect,
1635 .socketpair = no_skpair,
1636 .accept = accept,
1637 .getname = get_name,
1638 .poll = poll,
1639 .ioctl = ioctl,
1640 .listen = listen,
1641 .shutdown = shutdown,
1642 .setsockopt = setsockopt,
1643 .getsockopt = getsockopt,
1644 .sendmsg = send_packet,
1645 .recvmsg = recv_msg,
1646 .mmap = no_mmap,
1647 .sendpage = no_sendpage
1648};
1649
1650static struct proto_ops stream_ops = {
1651 .owner = THIS_MODULE,
1652 .family = AF_TIPC,
1653 .release = release,
1654 .bind = bind,
1655 .connect = connect,
1656 .socketpair = no_skpair,
1657 .accept = accept,
1658 .getname = get_name,
1659 .poll = poll,
1660 .ioctl = ioctl,
1661 .listen = listen,
1662 .shutdown = shutdown,
1663 .setsockopt = setsockopt,
1664 .getsockopt = getsockopt,
1665 .sendmsg = send_stream,
1666 .recvmsg = recv_stream,
1667 .mmap = no_mmap,
1668 .sendpage = no_sendpage
1669};
1670
1671static struct net_proto_family tipc_family_ops = {
1672 .owner = THIS_MODULE,
1673 .family = AF_TIPC,
1674 .create = tipc_create
1675};
1676
1677static struct proto tipc_proto = {
1678 .name = "TIPC",
1679 .owner = THIS_MODULE,
1680 .obj_size = sizeof(struct tipc_sock)
1681};
1682
1683/**
1684 * socket_init - initialize TIPC socket interface
1685 *
1686 * Returns 0 on success, errno otherwise
1687 */
1688int socket_init(void)
1689{
1690 int res;
1691
1692 res = proto_register(&tipc_proto, 1);
1693 if (res) {
1694 err("Unable to register TIPC protocol type\n");
1695 goto out;
1696 }
1697
1698 res = sock_register(&tipc_family_ops);
1699 if (res) {
1700 err("Unable to register TIPC socket type\n");
1701 proto_unregister(&tipc_proto);
1702 goto out;
1703 }
1704
1705 sockets_enabled = 1;
1706 out:
1707 return res;
1708}
1709
1710/**
1711 * sock_stop - stop TIPC socket interface
1712 */
1713void socket_stop(void)
1714{
1715 if (!sockets_enabled)
1716 return;
1717
1718 sockets_enabled = 0;
1719 sock_unregister(tipc_family_ops.family);
1720 proto_unregister(&tipc_proto);
1721}
1722
diff --git a/net/tipc/subscr.c b/net/tipc/subscr.c
new file mode 100644
index 000000000000..6f651a2c477e
--- /dev/null
+++ b/net/tipc/subscr.c
@@ -0,0 +1,522 @@
1/*
2 * net/tipc/subscr.c: TIPC subscription service
3 *
4 * Copyright (c) 2003-2005, Ericsson Research Canada
5 * Copyright (c) 2005, Wind River Systems
6 * Copyright (c) 2005-2006, Ericsson AB
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions are met:
11 *
12 * Redistributions of source code must retain the above copyright notice, this
13 * list of conditions and the following disclaimer.
14 * Redistributions in binary form must reproduce the above copyright notice,
15 * this list of conditions and the following disclaimer in the documentation
16 * and/or other materials provided with the distribution.
17 * Neither the names of the copyright holders nor the names of its
18 * contributors may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 */
33
34#include "core.h"
35#include "dbg.h"
36#include "subscr.h"
37#include "name_table.h"
38#include "ref.h"
39
40/**
41 * struct subscriber - TIPC network topology subscriber
42 * @ref: object reference to subscriber object itself
43 * @lock: pointer to spinlock controlling access to subscriber object
44 * @subscriber_list: adjacent subscribers in top. server's list of subscribers
45 * @subscription_list: list of subscription objects for this subscriber
46 * @port_ref: object reference to port used to communicate with subscriber
47 * @swap: indicates if subscriber uses opposite endianness in its messages
48 */
49
50struct subscriber {
51 u32 ref;
52 spinlock_t *lock;
53 struct list_head subscriber_list;
54 struct list_head subscription_list;
55 u32 port_ref;
56 int swap;
57};
58
59/**
60 * struct top_srv - TIPC network topology subscription service
61 * @user_ref: TIPC userid of subscription service
62 * @setup_port: reference to TIPC port that handles subscription requests
63 * @subscription_count: number of active subscriptions (not subscribers!)
64 * @subscriber_list: list of ports subscribing to service
65 * @lock: spinlock govering access to subscriber list
66 */
67
68struct top_srv {
69 u32 user_ref;
70 u32 setup_port;
71 atomic_t subscription_count;
72 struct list_head subscriber_list;
73 spinlock_t lock;
74};
75
76static struct top_srv topsrv = { 0 };
77
78/**
79 * htohl - convert value to endianness used by destination
80 * @in: value to convert
81 * @swap: non-zero if endianness must be reversed
82 *
83 * Returns converted value
84 */
85
86static inline u32 htohl(u32 in, int swap)
87{
88 char *c = (char *)&in;
89
90 return swap ? ((c[3] << 3) + (c[2] << 2) + (c[1] << 1) + c[0]) : in;
91}
92
93/**
94 * subscr_send_event - send a message containing a tipc_event to the subscriber
95 */
96
97static void subscr_send_event(struct subscription *sub,
98 u32 found_lower,
99 u32 found_upper,
100 u32 event,
101 u32 port_ref,
102 u32 node)
103{
104 struct iovec msg_sect;
105
106 msg_sect.iov_base = (void *)&sub->evt;
107 msg_sect.iov_len = sizeof(struct tipc_event);
108
109 sub->evt.event = htohl(event, sub->owner->swap);
110 sub->evt.found_lower = htohl(found_lower, sub->owner->swap);
111 sub->evt.found_upper = htohl(found_upper, sub->owner->swap);
112 sub->evt.port.ref = htohl(port_ref, sub->owner->swap);
113 sub->evt.port.node = htohl(node, sub->owner->swap);
114 tipc_send(sub->owner->port_ref, 1, &msg_sect);
115}
116
117/**
118 * subscr_overlap - test for subscription overlap with the given values
119 *
120 * Returns 1 if there is overlap, otherwise 0.
121 */
122
123int subscr_overlap(struct subscription *sub,
124 u32 found_lower,
125 u32 found_upper)
126
127{
128 if (found_lower < sub->seq.lower)
129 found_lower = sub->seq.lower;
130 if (found_upper > sub->seq.upper)
131 found_upper = sub->seq.upper;
132 if (found_lower > found_upper)
133 return 0;
134 return 1;
135}
136
137/**
138 * subscr_report_overlap - issue event if there is subscription overlap
139 *
140 * Protected by nameseq.lock in name_table.c
141 */
142
143void subscr_report_overlap(struct subscription *sub,
144 u32 found_lower,
145 u32 found_upper,
146 u32 event,
147 u32 port_ref,
148 u32 node,
149 int must)
150{
151 dbg("Rep overlap %u:%u,%u<->%u,%u\n", sub->seq.type, sub->seq.lower,
152 sub->seq.upper, found_lower, found_upper);
153 if (!subscr_overlap(sub, found_lower, found_upper))
154 return;
155 if (!must && (sub->filter != TIPC_SUB_PORTS))
156 return;
157 subscr_send_event(sub, found_lower, found_upper, event, port_ref, node);
158}
159
160/**
161 * subscr_timeout - subscription timeout has occurred
162 */
163
164static void subscr_timeout(struct subscription *sub)
165{
166 struct subscriber *subscriber;
167 u32 subscriber_ref;
168
169 /* Validate subscriber reference (in case subscriber is terminating) */
170
171 subscriber_ref = sub->owner->ref;
172 subscriber = (struct subscriber *)ref_lock(subscriber_ref);
173 if (subscriber == NULL)
174 return;
175
176 /* Unlink subscription from name table */
177
178 nametbl_unsubscribe(sub);
179
180 /* Notify subscriber of timeout, then unlink subscription */
181
182 subscr_send_event(sub,
183 sub->evt.s.seq.lower,
184 sub->evt.s.seq.upper,
185 TIPC_SUBSCR_TIMEOUT,
186 0,
187 0);
188 list_del(&sub->subscription_list);
189
190 /* Now destroy subscription */
191
192 ref_unlock(subscriber_ref);
193 k_term_timer(&sub->timer);
194 kfree(sub);
195 atomic_dec(&topsrv.subscription_count);
196}
197
198/**
199 * subscr_terminate - terminate communication with a subscriber
200 *
201 * Called with subscriber locked. Routine must temporarily release this lock
202 * to enable subscription timeout routine(s) to finish without deadlocking;
203 * the lock is then reclaimed to allow caller to release it upon return.
204 * (This should work even in the unlikely event some other thread creates
205 * a new object reference in the interim that uses this lock; this routine will
206 * simply wait for it to be released, then claim it.)
207 */
208
209static void subscr_terminate(struct subscriber *subscriber)
210{
211 struct subscription *sub;
212 struct subscription *sub_temp;
213
214 /* Invalidate subscriber reference */
215
216 ref_discard(subscriber->ref);
217 spin_unlock_bh(subscriber->lock);
218
219 /* Destroy any existing subscriptions for subscriber */
220
221 list_for_each_entry_safe(sub, sub_temp, &subscriber->subscription_list,
222 subscription_list) {
223 if (sub->timeout != TIPC_WAIT_FOREVER) {
224 k_cancel_timer(&sub->timer);
225 k_term_timer(&sub->timer);
226 }
227 nametbl_unsubscribe(sub);
228 list_del(&sub->subscription_list);
229 dbg("Term: Removed sub %u,%u,%u from subscriber %x list\n",
230 sub->seq.type, sub->seq.lower, sub->seq.upper, subscriber);
231 kfree(sub);
232 atomic_dec(&topsrv.subscription_count);
233 }
234
235 /* Sever connection to subscriber */
236
237 tipc_shutdown(subscriber->port_ref);
238 tipc_deleteport(subscriber->port_ref);
239
240 /* Remove subscriber from topology server's subscriber list */
241
242 spin_lock_bh(&topsrv.lock);
243 list_del(&subscriber->subscriber_list);
244 spin_unlock_bh(&topsrv.lock);
245
246 /* Now destroy subscriber */
247
248 spin_lock_bh(subscriber->lock);
249 kfree(subscriber);
250}
251
252/**
253 * subscr_subscribe - create subscription for subscriber
254 *
255 * Called with subscriber locked
256 */
257
258static void subscr_subscribe(struct tipc_subscr *s,
259 struct subscriber *subscriber)
260{
261 struct subscription *sub;
262
263 /* Refuse subscription if global limit exceeded */
264
265 if (atomic_read(&topsrv.subscription_count) >= tipc_max_subscriptions) {
266 warn("Failed: max %u subscriptions\n", tipc_max_subscriptions);
267 subscr_terminate(subscriber);
268 return;
269 }
270
271 /* Allocate subscription object */
272
273 sub = kmalloc(sizeof(*sub), GFP_ATOMIC);
274 if (sub == NULL) {
275 warn("Memory squeeze; ignoring subscription\n");
276 subscr_terminate(subscriber);
277 return;
278 }
279
280 /* Determine/update subscriber's endianness */
281
282 if ((s->filter == TIPC_SUB_PORTS) || (s->filter == TIPC_SUB_SERVICE))
283 subscriber->swap = 0;
284 else
285 subscriber->swap = 1;
286
287 /* Initialize subscription object */
288
289 memset(sub, 0, sizeof(*sub));
290 sub->seq.type = htohl(s->seq.type, subscriber->swap);
291 sub->seq.lower = htohl(s->seq.lower, subscriber->swap);
292 sub->seq.upper = htohl(s->seq.upper, subscriber->swap);
293 sub->timeout = htohl(s->timeout, subscriber->swap);
294 sub->filter = htohl(s->filter, subscriber->swap);
295 if ((((sub->filter != TIPC_SUB_PORTS)
296 && (sub->filter != TIPC_SUB_SERVICE)))
297 || (sub->seq.lower > sub->seq.upper)) {
298 warn("Rejecting illegal subscription %u,%u,%u\n",
299 sub->seq.type, sub->seq.lower, sub->seq.upper);
300 kfree(sub);
301 subscr_terminate(subscriber);
302 return;
303 }
304 memcpy(&sub->evt.s, s, sizeof(struct tipc_subscr));
305 INIT_LIST_HEAD(&sub->subscription_list);
306 INIT_LIST_HEAD(&sub->nameseq_list);
307 list_add(&sub->subscription_list, &subscriber->subscription_list);
308 atomic_inc(&topsrv.subscription_count);
309 if (sub->timeout != TIPC_WAIT_FOREVER) {
310 k_init_timer(&sub->timer,
311 (Handler)subscr_timeout, (unsigned long)sub);
312 k_start_timer(&sub->timer, sub->timeout);
313 }
314 sub->owner = subscriber;
315 nametbl_subscribe(sub);
316}
317
318/**
319 * subscr_conn_shutdown_event - handle termination request from subscriber
320 */
321
322static void subscr_conn_shutdown_event(void *usr_handle,
323 u32 portref,
324 struct sk_buff **buf,
325 unsigned char const *data,
326 unsigned int size,
327 int reason)
328{
329 struct subscriber *subscriber = ref_lock((u32)usr_handle);
330 spinlock_t *subscriber_lock;
331
332 if (subscriber == NULL)
333 return;
334
335 subscriber_lock = subscriber->lock;
336 subscr_terminate(subscriber);
337 spin_unlock_bh(subscriber_lock);
338}
339
340/**
341 * subscr_conn_msg_event - handle new subscription request from subscriber
342 */
343
344static void subscr_conn_msg_event(void *usr_handle,
345 u32 port_ref,
346 struct sk_buff **buf,
347 const unchar *data,
348 u32 size)
349{
350 struct subscriber *subscriber = ref_lock((u32)usr_handle);
351 spinlock_t *subscriber_lock;
352
353 if (subscriber == NULL)
354 return;
355
356 subscriber_lock = subscriber->lock;
357 if (size != sizeof(struct tipc_subscr))
358 subscr_terminate(subscriber);
359 else
360 subscr_subscribe((struct tipc_subscr *)data, subscriber);
361
362 spin_unlock_bh(subscriber_lock);
363}
364
365/**
366 * subscr_named_msg_event - handle request to establish a new subscriber
367 */
368
369static void subscr_named_msg_event(void *usr_handle,
370 u32 port_ref,
371 struct sk_buff **buf,
372 const unchar *data,
373 u32 size,
374 u32 importance,
375 struct tipc_portid const *orig,
376 struct tipc_name_seq const *dest)
377{
378 struct subscriber *subscriber;
379 struct iovec msg_sect = {0, 0};
380 spinlock_t *subscriber_lock;
381
382 dbg("subscr_named_msg_event: orig = %x own = %x,\n",
383 orig->node, tipc_own_addr);
384 if (size && (size != sizeof(struct tipc_subscr))) {
385 warn("Received tipc_subscr of invalid size\n");
386 return;
387 }
388
389 /* Create subscriber object */
390
391 subscriber = kmalloc(sizeof(struct subscriber), GFP_ATOMIC);
392 if (subscriber == NULL) {
393 warn("Memory squeeze; ignoring subscriber setup\n");
394 return;
395 }
396 memset(subscriber, 0, sizeof(struct subscriber));
397 INIT_LIST_HEAD(&subscriber->subscription_list);
398 INIT_LIST_HEAD(&subscriber->subscriber_list);
399 subscriber->ref = ref_acquire(subscriber, &subscriber->lock);
400 if (subscriber->ref == 0) {
401 warn("Failed to acquire subscriber reference\n");
402 kfree(subscriber);
403 return;
404 }
405
406 /* Establish a connection to subscriber */
407
408 tipc_createport(topsrv.user_ref,
409 (void *)subscriber->ref,
410 importance,
411 0,
412 0,
413 subscr_conn_shutdown_event,
414 0,
415 0,
416 subscr_conn_msg_event,
417 0,
418 &subscriber->port_ref);
419 if (subscriber->port_ref == 0) {
420 warn("Memory squeeze; failed to create subscription port\n");
421 ref_discard(subscriber->ref);
422 kfree(subscriber);
423 return;
424 }
425 tipc_connect2port(subscriber->port_ref, orig);
426
427
428 /* Add subscriber to topology server's subscriber list */
429
430 ref_lock(subscriber->ref);
431 spin_lock_bh(&topsrv.lock);
432 list_add(&subscriber->subscriber_list, &topsrv.subscriber_list);
433 spin_unlock_bh(&topsrv.lock);
434
435 /*
436 * Subscribe now if message contains a subscription,
437 * otherwise send an empty response to complete connection handshaking
438 */
439
440 subscriber_lock = subscriber->lock;
441 if (size)
442 subscr_subscribe((struct tipc_subscr *)data, subscriber);
443 else
444 tipc_send(subscriber->port_ref, 1, &msg_sect);
445
446 spin_unlock_bh(subscriber_lock);
447}
448
449int subscr_start(void)
450{
451 struct tipc_name_seq seq = {TIPC_TOP_SRV, TIPC_TOP_SRV, TIPC_TOP_SRV};
452 int res = -1;
453
454 memset(&topsrv, 0, sizeof (topsrv));
455 topsrv.lock = SPIN_LOCK_UNLOCKED;
456 INIT_LIST_HEAD(&topsrv.subscriber_list);
457
458 spin_lock_bh(&topsrv.lock);
459 res = tipc_attach(&topsrv.user_ref, 0, 0);
460 if (res) {
461 spin_unlock_bh(&topsrv.lock);
462 return res;
463 }
464
465 res = tipc_createport(topsrv.user_ref,
466 0,
467 TIPC_CRITICAL_IMPORTANCE,
468 0,
469 0,
470 0,
471 0,
472 subscr_named_msg_event,
473 0,
474 0,
475 &topsrv.setup_port);
476 if (res)
477 goto failed;
478
479 res = nametbl_publish_rsv(topsrv.setup_port, TIPC_NODE_SCOPE, &seq);
480 if (res)
481 goto failed;
482
483 spin_unlock_bh(&topsrv.lock);
484 return 0;
485
486failed:
487 err("Unable to create subscription service\n");
488 tipc_detach(topsrv.user_ref);
489 topsrv.user_ref = 0;
490 spin_unlock_bh(&topsrv.lock);
491 return res;
492}
493
494void subscr_stop(void)
495{
496 struct subscriber *subscriber;
497 struct subscriber *subscriber_temp;
498 spinlock_t *subscriber_lock;
499
500 if (topsrv.user_ref) {
501 tipc_deleteport(topsrv.setup_port);
502 list_for_each_entry_safe(subscriber, subscriber_temp,
503 &topsrv.subscriber_list,
504 subscriber_list) {
505 ref_lock(subscriber->ref);
506 subscriber_lock = subscriber->lock;
507 subscr_terminate(subscriber);
508 spin_unlock_bh(subscriber_lock);
509 }
510 tipc_detach(topsrv.user_ref);
511 topsrv.user_ref = 0;
512 }
513}
514
515
516int tipc_ispublished(struct tipc_name const *name)
517{
518 u32 domain = 0;
519
520 return(nametbl_translate(name->type, name->instance,&domain) != 0);
521}
522
diff --git a/net/tipc/subscr.h b/net/tipc/subscr.h
new file mode 100644
index 000000000000..e6cb9c3ad870
--- /dev/null
+++ b/net/tipc/subscr.h
@@ -0,0 +1,77 @@
1/*
2 * net/tipc/subscr.h: Include file for TIPC subscription service
3 *
4 * Copyright (c) 2003-2005, Ericsson Research Canada
5 * Copyright (c) 2005, Wind River Systems
6 * Copyright (c) 2005-2006, Ericsson AB
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions are met:
11 *
12 * Redistributions of source code must retain the above copyright notice, this
13 * list of conditions and the following disclaimer.
14 * Redistributions in binary form must reproduce the above copyright notice,
15 * this list of conditions and the following disclaimer in the documentation
16 * and/or other materials provided with the distribution.
17 * Neither the names of the copyright holders nor the names of its
18 * contributors may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 */
33
34#ifndef _TIPC_SUBSCR_H
35#define _TIPC_SUBSCR_H
36
37/**
38 * struct subscription - TIPC network topology subscription object
39 * @seq: name sequence associated with subscription
40 * @timeout: duration of subscription (in ms)
41 * @filter: event filtering to be done for subscription
42 * @evt: template for events generated by subscription
43 * @subscription_list: adjacent subscriptions in subscriber's subscription list
44 * @nameseq_list: adjacent subscriptions in name sequence's subscription list
45 * @timer_ref: reference to timer governing subscription duration (may be NULL)
46 * @owner: pointer to subscriber object associated with this subscription
47 */
48
49struct subscription {
50 struct tipc_name_seq seq;
51 u32 timeout;
52 u32 filter;
53 struct tipc_event evt;
54 struct list_head subscription_list;
55 struct list_head nameseq_list;
56 struct timer_list timer;
57 struct subscriber *owner;
58};
59
60int subscr_overlap(struct subscription * sub,
61 u32 found_lower,
62 u32 found_upper);
63
64void subscr_report_overlap(struct subscription * sub,
65 u32 found_lower,
66 u32 found_upper,
67 u32 event,
68 u32 port_ref,
69 u32 node,
70 int must_report);
71
72int subscr_start(void);
73
74void subscr_stop(void);
75
76
77#endif
diff --git a/net/tipc/user_reg.c b/net/tipc/user_reg.c
new file mode 100644
index 000000000000..e4da5becc342
--- /dev/null
+++ b/net/tipc/user_reg.c
@@ -0,0 +1,262 @@
1/*
2 * net/tipc/user_reg.c: TIPC user registry code
3 *
4 * Copyright (c) 2003-2005, Ericsson Research Canada
5 * Copyright (c) 2004-2005, Wind River Systems
6 * Copyright (c) 2005-2006, Ericsson AB
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions are met:
11 *
12 * Redistributions of source code must retain the above copyright notice, this
13 * list of conditions and the following disclaimer.
14 * Redistributions in binary form must reproduce the above copyright notice,
15 * this list of conditions and the following disclaimer in the documentation
16 * and/or other materials provided with the distribution.
17 * Neither the names of the copyright holders nor the names of its
18 * contributors may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 */
33
34#include "core.h"
35#include "user_reg.h"
36
37/*
38 * TIPC user registry keeps track of users of the tipc_port interface.
39 *
40 * The registry utilizes an array of "TIPC user" entries;
41 * a user's ID is the index of their associated array entry.
42 * Array entry 0 is not used, so userid 0 is not valid;
43 * TIPC sometimes uses this value to denote an anonymous user.
44 * The list of free entries is initially chained from last entry to entry 1.
45 */
46
47/**
48 * struct tipc_user - registered TIPC user info
49 * @next: index of next free registry entry (or -1 for an allocated entry)
50 * @callback: ptr to routine to call when TIPC mode changes (NULL if none)
51 * @usr_handle: user-defined value passed to callback routine
52 * @ports: list of user ports owned by the user
53 */
54
55struct tipc_user {
56 int next;
57 tipc_mode_event callback;
58 void *usr_handle;
59 struct list_head ports;
60};
61
62#define MAX_USERID 64
63#define USER_LIST_SIZE ((MAX_USERID + 1) * sizeof(struct tipc_user))
64
65static struct tipc_user *users = 0;
66static u32 next_free_user = MAX_USERID + 1;
67static spinlock_t reg_lock = SPIN_LOCK_UNLOCKED;
68
69/**
70 * reg_init - create TIPC user registry (but don't activate it)
71 *
72 * If registry has been pre-initialized it is left "as is".
73 * NOTE: This routine may be called when TIPC is inactive.
74 */
75
76static int reg_init(void)
77{
78 u32 i;
79
80 spin_lock_bh(&reg_lock);
81 if (!users) {
82 users = (struct tipc_user *)kmalloc(USER_LIST_SIZE, GFP_ATOMIC);
83 if (users) {
84 memset(users, 0, USER_LIST_SIZE);
85 for (i = 1; i <= MAX_USERID; i++) {
86 users[i].next = i - 1;
87 }
88 next_free_user = MAX_USERID;
89 }
90 }
91 spin_unlock_bh(&reg_lock);
92 return users ? TIPC_OK : -ENOMEM;
93}
94
95/**
96 * reg_callback - inform TIPC user about current operating mode
97 */
98
99static void reg_callback(struct tipc_user *user_ptr)
100{
101 tipc_mode_event cb;
102 void *arg;
103
104 spin_lock_bh(&reg_lock);
105 cb = user_ptr->callback;
106 arg = user_ptr->usr_handle;
107 spin_unlock_bh(&reg_lock);
108
109 if (cb)
110 cb(arg, tipc_mode, tipc_own_addr);
111}
112
113/**
114 * reg_start - activate TIPC user registry
115 */
116
117int reg_start(void)
118{
119 u32 u;
120 int res;
121
122 if ((res = reg_init()))
123 return res;
124
125 for (u = 1; u <= MAX_USERID; u++) {
126 if (users[u].callback)
127 k_signal((Handler)reg_callback,
128 (unsigned long)&users[u]);
129 }
130 return TIPC_OK;
131}
132
133/**
134 * reg_stop - shut down & delete TIPC user registry
135 */
136
137void reg_stop(void)
138{
139 int id;
140
141 if (!users)
142 return;
143
144 for (id = 1; id <= MAX_USERID; id++) {
145 if (users[id].callback)
146 reg_callback(&users[id]);
147 }
148 kfree(users);
149 users = 0;
150}
151
152/**
153 * tipc_attach - register a TIPC user
154 *
155 * NOTE: This routine may be called when TIPC is inactive.
156 */
157
158int tipc_attach(u32 *userid, tipc_mode_event cb, void *usr_handle)
159{
160 struct tipc_user *user_ptr;
161
162 if ((tipc_mode == TIPC_NOT_RUNNING) && !cb)
163 return -ENOPROTOOPT;
164 if (!users)
165 reg_init();
166
167 spin_lock_bh(&reg_lock);
168 if (!next_free_user) {
169 spin_unlock_bh(&reg_lock);
170 return -EBUSY;
171 }
172 user_ptr = &users[next_free_user];
173 *userid = next_free_user;
174 next_free_user = user_ptr->next;
175 user_ptr->next = -1;
176 spin_unlock_bh(&reg_lock);
177
178 user_ptr->callback = cb;
179 user_ptr->usr_handle = usr_handle;
180 INIT_LIST_HEAD(&user_ptr->ports);
181 atomic_inc(&tipc_user_count);
182
183 if (cb && (tipc_mode != TIPC_NOT_RUNNING))
184 k_signal((Handler)reg_callback, (unsigned long)user_ptr);
185 return TIPC_OK;
186}
187
188/**
189 * tipc_detach - deregister a TIPC user
190 */
191
192void tipc_detach(u32 userid)
193{
194 struct tipc_user *user_ptr;
195 struct list_head ports_temp;
196 struct user_port *up_ptr, *temp_up_ptr;
197
198 if ((userid == 0) || (userid > MAX_USERID))
199 return;
200
201 spin_lock_bh(&reg_lock);
202 if ((!users) || (users[userid].next >= 0)) {
203 spin_unlock_bh(&reg_lock);
204 return;
205 }
206
207 user_ptr = &users[userid];
208 user_ptr->callback = NULL;
209 INIT_LIST_HEAD(&ports_temp);
210 list_splice(&user_ptr->ports, &ports_temp);
211 user_ptr->next = next_free_user;
212 next_free_user = userid;
213 spin_unlock_bh(&reg_lock);
214
215 atomic_dec(&tipc_user_count);
216
217 list_for_each_entry_safe(up_ptr, temp_up_ptr, &ports_temp, uport_list) {
218 tipc_deleteport(up_ptr->ref);
219 }
220}
221
222/**
223 * reg_add_port - register a user's driver port
224 */
225
226int reg_add_port(struct user_port *up_ptr)
227{
228 struct tipc_user *user_ptr;
229
230 if (up_ptr->user_ref == 0)
231 return TIPC_OK;
232 if (up_ptr->user_ref > MAX_USERID)
233 return -EINVAL;
234 if ((tipc_mode == TIPC_NOT_RUNNING) || !users )
235 return -ENOPROTOOPT;
236
237 spin_lock_bh(&reg_lock);
238 user_ptr = &users[up_ptr->user_ref];
239 list_add(&up_ptr->uport_list, &user_ptr->ports);
240 spin_unlock_bh(&reg_lock);
241 return TIPC_OK;
242}
243
244/**
245 * reg_remove_port - deregister a user's driver port
246 */
247
248int reg_remove_port(struct user_port *up_ptr)
249{
250 if (up_ptr->user_ref == 0)
251 return TIPC_OK;
252 if (up_ptr->user_ref > MAX_USERID)
253 return -EINVAL;
254 if (!users )
255 return -ENOPROTOOPT;
256
257 spin_lock_bh(&reg_lock);
258 list_del_init(&up_ptr->uport_list);
259 spin_unlock_bh(&reg_lock);
260 return TIPC_OK;
261}
262
diff --git a/net/tipc/user_reg.h b/net/tipc/user_reg.h
new file mode 100644
index 000000000000..44f219458a39
--- /dev/null
+++ b/net/tipc/user_reg.h
@@ -0,0 +1,45 @@
1/*
2 * net/tipc/user_reg.h: Include file for TIPC user registry code
3 *
4 * Copyright (c) 2003-2005, Ericsson Research Canada
5 * Copyright (c) 2005, Wind River Systems
6 * Copyright (c) 2005-2006, Ericsson AB
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions are met:
11 *
12 * Redistributions of source code must retain the above copyright notice, this
13 * list of conditions and the following disclaimer.
14 * Redistributions in binary form must reproduce the above copyright notice,
15 * this list of conditions and the following disclaimer in the documentation
16 * and/or other materials provided with the distribution.
17 * Neither the names of the copyright holders nor the names of its
18 * contributors may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 */
33
34#ifndef _TIPC_USER_REG_H
35#define _TIPC_USER_REG_H
36
37#include "port.h"
38
39int reg_start(void);
40void reg_stop(void);
41
42int reg_add_port(struct user_port *up_ptr);
43int reg_remove_port(struct user_port *up_ptr);
44
45#endif
diff --git a/net/tipc/zone.c b/net/tipc/zone.c
new file mode 100644
index 000000000000..336eebb7bf54
--- /dev/null
+++ b/net/tipc/zone.c
@@ -0,0 +1,166 @@
1/*
2 * net/tipc/zone.c: TIPC zone management routines
3 *
4 * Copyright (c) 2003-2005, Ericsson Research Canada
5 * Copyright (c) 2005, Wind River Systems
6 * Copyright (c) 2005-2006, Ericsson AB
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions are met:
11 *
12 * Redistributions of source code must retain the above copyright notice, this
13 * list of conditions and the following disclaimer.
14 * Redistributions in binary form must reproduce the above copyright notice,
15 * this list of conditions and the following disclaimer in the documentation
16 * and/or other materials provided with the distribution.
17 * Neither the names of the copyright holders nor the names of its
18 * contributors may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 */
33
34#include "core.h"
35#include "zone.h"
36#include "net.h"
37#include "addr.h"
38#include "node_subscr.h"
39#include "cluster.h"
40#include "node.h"
41
42struct _zone *zone_create(u32 addr)
43{
44 struct _zone *z_ptr = 0;
45 u32 z_num;
46
47 if (!addr_domain_valid(addr))
48 return 0;
49
50 z_ptr = (struct _zone *)kmalloc(sizeof(*z_ptr), GFP_ATOMIC);
51 if (z_ptr != NULL) {
52 memset(z_ptr, 0, sizeof(*z_ptr));
53 z_num = tipc_zone(addr);
54 z_ptr->addr = tipc_addr(z_num, 0, 0);
55 net.zones[z_num] = z_ptr;
56 }
57 return z_ptr;
58}
59
60void zone_delete(struct _zone *z_ptr)
61{
62 u32 c_num;
63
64 if (!z_ptr)
65 return;
66 for (c_num = 1; c_num <= tipc_max_clusters; c_num++) {
67 cluster_delete(z_ptr->clusters[c_num]);
68 }
69 kfree(z_ptr);
70}
71
72void zone_attach_cluster(struct _zone *z_ptr, struct cluster *c_ptr)
73{
74 u32 c_num = tipc_cluster(c_ptr->addr);
75
76 assert(c_ptr->addr);
77 assert(c_num <= tipc_max_clusters);
78 assert(z_ptr->clusters[c_num] == 0);
79 z_ptr->clusters[c_num] = c_ptr;
80}
81
82void zone_remove_as_router(struct _zone *z_ptr, u32 router)
83{
84 u32 c_num;
85
86 for (c_num = 1; c_num <= tipc_max_clusters; c_num++) {
87 if (z_ptr->clusters[c_num]) {
88 cluster_remove_as_router(z_ptr->clusters[c_num],
89 router);
90 }
91 }
92}
93
94void zone_send_external_routes(struct _zone *z_ptr, u32 dest)
95{
96 u32 c_num;
97
98 for (c_num = 1; c_num <= tipc_max_clusters; c_num++) {
99 if (z_ptr->clusters[c_num]) {
100 if (in_own_cluster(z_ptr->addr))
101 continue;
102 cluster_send_ext_routes(z_ptr->clusters[c_num], dest);
103 }
104 }
105}
106
107struct node *zone_select_remote_node(struct _zone *z_ptr, u32 addr, u32 ref)
108{
109 struct cluster *c_ptr;
110 struct node *n_ptr;
111 u32 c_num;
112
113 if (!z_ptr)
114 return 0;
115 c_ptr = z_ptr->clusters[tipc_cluster(addr)];
116 if (!c_ptr)
117 return 0;
118 n_ptr = cluster_select_node(c_ptr, ref);
119 if (n_ptr)
120 return n_ptr;
121
122 /* Links to any other clusters within this zone ? */
123 for (c_num = 1; c_num <= tipc_max_clusters; c_num++) {
124 c_ptr = z_ptr->clusters[c_num];
125 if (!c_ptr)
126 return 0;
127 n_ptr = cluster_select_node(c_ptr, ref);
128 if (n_ptr)
129 return n_ptr;
130 }
131 return 0;
132}
133
134u32 zone_select_router(struct _zone *z_ptr, u32 addr, u32 ref)
135{
136 struct cluster *c_ptr;
137 u32 c_num;
138 u32 router;
139
140 if (!z_ptr)
141 return 0;
142 c_ptr = z_ptr->clusters[tipc_cluster(addr)];
143 router = c_ptr ? cluster_select_router(c_ptr, ref) : 0;
144 if (router)
145 return router;
146
147 /* Links to any other clusters within the zone? */
148 for (c_num = 1; c_num <= tipc_max_clusters; c_num++) {
149 c_ptr = z_ptr->clusters[c_num];
150 router = c_ptr ? cluster_select_router(c_ptr, ref) : 0;
151 if (router)
152 return router;
153 }
154 return 0;
155}
156
157
158u32 zone_next_node(u32 addr)
159{
160 struct cluster *c_ptr = cluster_find(addr);
161
162 if (c_ptr)
163 return cluster_next_node(c_ptr, addr);
164 return 0;
165}
166
diff --git a/net/tipc/zone.h b/net/tipc/zone.h
new file mode 100644
index 000000000000..19fd51a8bd2b
--- /dev/null
+++ b/net/tipc/zone.h
@@ -0,0 +1,68 @@
1/*
2 * net/tipc/zone.h: Include file for TIPC zone management routines
3 *
4 * Copyright (c) 2003-2005, Ericsson Research Canada
5 * Copyright (c) 2005, Wind River Systems
6 * Copyright (c) 2005-2006, Ericsson AB
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions are met:
11 *
12 * Redistributions of source code must retain the above copyright notice, this
13 * list of conditions and the following disclaimer.
14 * Redistributions in binary form must reproduce the above copyright notice,
15 * this list of conditions and the following disclaimer in the documentation
16 * and/or other materials provided with the distribution.
17 * Neither the names of the copyright holders nor the names of its
18 * contributors may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 */
33
34#ifndef _TIPC_ZONE_H
35#define _TIPC_ZONE_H
36
37#include "node_subscr.h"
38#include "net.h"
39
40
41/**
42 * struct _zone - TIPC zone structure
43 * @addr: network address of zone
44 * @clusters: array of pointers to all clusters within zone
45 * @links: (used for inter-zone communication)
46 */
47
48struct _zone {
49 u32 addr;
50 struct cluster *clusters[2]; /* currently limited to just 1 cluster */
51 u32 links;
52};
53
54struct node *zone_select_remote_node(struct _zone *z_ptr, u32 addr, u32 ref);
55u32 zone_select_router(struct _zone *z_ptr, u32 addr, u32 ref);
56void zone_remove_as_router(struct _zone *z_ptr, u32 router);
57void zone_send_external_routes(struct _zone *z_ptr, u32 dest);
58struct _zone *zone_create(u32 addr);
59void zone_delete(struct _zone *z_ptr);
60void zone_attach_cluster(struct _zone *z_ptr, struct cluster *c_ptr);
61u32 zone_next_node(u32 addr);
62
63static inline struct _zone *zone_find(u32 addr)
64{
65 return net.zones[tipc_zone(addr)];
66}
67
68#endif