summaryrefslogtreecommitdiffstats
path: root/net/tipc
diff options
context:
space:
mode:
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 @@
+#
+# TIPC configuration
+#
+
+menu "TIPC Configuration (EXPERIMENTAL)"
+ depends on INET && EXPERIMENTAL
+
+config TIPC
+ tristate "The TIPC Protocol (EXPERIMENTAL)"
+ ---help---
+ TBD.
+
+ This protocol support is also available as a module ( = code which
+ can be inserted in and removed from the running kernel whenever you
+ want). The module will be called tipc. If you want to compile it
+ as a module, say M here and read <file:Documentation/modules.txt>.
+
+ If in doubt, say N.
+
+config TIPC_ADVANCED
+ bool "TIPC: Advanced configuration"
+ depends on TIPC
+ default n
+ help
+ Saying Y here will open some advanced configuration
+ for TIPC. Most users do not need to bother, so if
+ unsure, just say N.
+
+config TIPC_ZONES
+ int "Maximum number of zones in network"
+ depends on TIPC && TIPC_ADVANCED
+ default "3"
+ help
+ Max number of zones inside TIPC network. Max supported value
+ is 255 zones, minimum is 1
+
+ Default is 3 zones in a network; setting this to higher
+ allows more zones but might use more memory.
+
+config TIPC_CLUSTERS
+ int "Maximum number of clusters in a zone"
+ depends on TIPC && TIPC_ADVANCED
+ default "1"
+ help
+ ***Only 1 (one cluster in a zone) is supported by current code.
+ Any value set here will be overridden.***
+
+ (Max number of clusters inside TIPC zone. Max supported
+ value is 4095 clusters, minimum is 1.
+
+ Default is 1; setting this to smaller value might save
+ some memory, setting it to higher
+ allows more clusters and might consume more memory.)
+
+config TIPC_NODES
+ int "Maximum number of nodes in cluster"
+ depends on TIPC && TIPC_ADVANCED
+ default "255"
+ help
+ Maximum number of nodes inside a TIPC cluster. Maximum
+ supported value is 2047 nodes, minimum is 8.
+
+ Setting this to a smaller value saves some memory,
+ setting it to higher allows more nodes.
+
+config TIPC_SLAVE_NODES
+ int "Maximum number of slave nodes in cluster"
+ depends on TIPC && TIPC_ADVANCED
+ default "0"
+ help
+ ***This capability is not supported by current code.***
+
+ Maximum number of slave nodes inside a TIPC cluster. Maximum
+ supported value is 2047 nodes, minimum is 0.
+
+ Setting this to a smaller value saves some memory,
+ setting it to higher allows more nodes.
+
+config TIPC_PORTS
+ int "Maximum number of ports in a node"
+ depends on TIPC && TIPC_ADVANCED
+ default "8191"
+ help
+ Maximum number of ports within a node. Maximum
+ supported value is 64535 nodes, minimum is 127.
+
+ Setting this to a smaller value saves some memory,
+ setting it to higher allows more ports.
+
+config TIPC_LOG
+ int "Size of log buffer"
+ depends on TIPC && TIPC_ADVANCED
+ default 0
+ help
+ Size (in bytes) of TIPC's internal log buffer, which records the
+ occurrence of significant events. Maximum supported value
+ is 32768 bytes, minimum is 0.
+
+ There is no need to enable the log buffer unless the node will be
+ managed remotely via TIPC.
+
+config TIPC_DEBUG
+ bool "Enable debugging support"
+ depends on TIPC
+ default n
+ help
+ This will enable debugging of TIPC.
+
+ Only say Y here if you are having trouble with TIPC. It will
+ enable the display of detailed information about what is going on.
+
+endmenu
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 @@
+#
+# Makefile for the Linux TIPC layer
+#
+
+obj-$(CONFIG_TIPC) := tipc.o
+
+tipc-y += addr.o bcast.o bearer.o config.o cluster.o \
+ core.o handler.o link.o discover.o msg.o \
+ name_distr.o subscr.o name_table.o net.o \
+ netlink.o node.o node_subscr.o port.o ref.o \
+ socket.o user_reg.o zone.o dbg.o eth_media.o
+
+# 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 @@
+/*
+ * net/tipc/addr.c: TIPC address utility routines
+ *
+ * Copyright (c) 2003-2005, Ericsson Research Canada
+ * Copyright (c) 2004-2005, Wind River Systems
+ * Copyright (c) 2005-2006, Ericsson AB
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * Neither the names of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "core.h"
+#include "dbg.h"
+#include "addr.h"
+#include "zone.h"
+#include "cluster.h"
+#include "net.h"
+
+u32 tipc_get_addr(void)
+{
+ return tipc_own_addr;
+}
+
+/**
+ * addr_domain_valid - validates a network domain address
+ *
+ * Accepts <Z.C.N>, <Z.C.0>, <Z.0.0>, and <0.0.0>,
+ * where Z, C, and N are non-zero and do not exceed the configured limits.
+ *
+ * Returns 1 if domain address is valid, otherwise 0
+ */
+
+int addr_domain_valid(u32 addr)
+{
+ u32 n = tipc_node(addr);
+ u32 c = tipc_cluster(addr);
+ u32 z = tipc_zone(addr);
+ u32 max_nodes = tipc_max_nodes;
+
+ if (is_slave(addr))
+ max_nodes = LOWEST_SLAVE + tipc_max_slaves;
+ if (n > max_nodes)
+ return 0;
+ if (c > tipc_max_clusters)
+ return 0;
+ if (z > tipc_max_zones)
+ return 0;
+
+ if (n && (!z || !c))
+ return 0;
+ if (c && !z)
+ return 0;
+ return 1;
+}
+
+/**
+ * addr_node_valid - validates a proposed network address for this node
+ *
+ * Accepts <Z.C.N>, where Z, C, and N are non-zero and do not exceed
+ * the configured limits.
+ *
+ * Returns 1 if address can be used, otherwise 0
+ */
+
+int addr_node_valid(u32 addr)
+{
+ return (addr_domain_valid(addr) && tipc_node(addr));
+}
+
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 @@
+/*
+ * net/tipc/addr.h: Include file for TIPC address utility routines
+ *
+ * Copyright (c) 2003-2005, Ericsson Research Canada
+ * Copyright (c) 2004-2005, Wind River Systems
+ * Copyright (c) 2005-2006, Ericsson AB
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * Neither the names of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _TIPC_ADDR_H
+#define _TIPC_ADDR_H
+
+static inline u32 own_node(void)
+{
+ return tipc_node(tipc_own_addr);
+}
+
+static inline u32 own_cluster(void)
+{
+ return tipc_cluster(tipc_own_addr);
+}
+
+static inline u32 own_zone(void)
+{
+ return tipc_zone(tipc_own_addr);
+}
+
+static inline int in_own_cluster(u32 addr)
+{
+ return !((addr ^ tipc_own_addr) >> 12);
+}
+
+static inline int in_own_zone(u32 addr)
+{
+ return !((addr ^ tipc_own_addr) >> 24);
+}
+
+static inline int is_slave(u32 addr)
+{
+ return addr & 0x800;
+}
+
+static inline int may_route(u32 addr)
+{
+ return(addr ^ tipc_own_addr) >> 11;
+}
+
+static inline int in_scope(u32 domain, u32 addr)
+{
+ if (!domain || (domain == addr))
+ return 1;
+ if (domain == (addr & 0xfffff000u)) /* domain <Z.C.0> */
+ return 1;
+ if (domain == (addr & 0xff000000u)) /* domain <Z.0.0> */
+ return 1;
+ return 0;
+}
+
+/**
+ * addr_scope - convert message lookup domain to equivalent 2-bit scope value
+ */
+
+static inline int addr_scope(u32 domain)
+{
+ if (likely(!domain))
+ return TIPC_ZONE_SCOPE;
+ if (tipc_node(domain))
+ return TIPC_NODE_SCOPE;
+ if (tipc_cluster(domain))
+ return TIPC_CLUSTER_SCOPE;
+ return TIPC_ZONE_SCOPE;
+}
+
+/**
+ * addr_domain - convert 2-bit scope value to equivalent message lookup domain
+ *
+ * Needed when address of a named message must be looked up a second time
+ * after a network hop.
+ */
+
+static inline int addr_domain(int sc)
+{
+ if (likely(sc == TIPC_NODE_SCOPE))
+ return tipc_own_addr;
+ if (sc == TIPC_CLUSTER_SCOPE)
+ return tipc_addr(tipc_zone(tipc_own_addr),
+ tipc_cluster(tipc_own_addr), 0);
+ return tipc_addr(tipc_zone(tipc_own_addr), 0, 0);
+}
+
+static inline char *addr_string_fill(char *string, u32 addr)
+{
+ snprintf(string, 16, "<%u.%u.%u>",
+ tipc_zone(addr), tipc_cluster(addr), tipc_node(addr));
+ return string;
+}
+
+int addr_domain_valid(u32);
+int addr_node_valid(u32 addr);
+
+#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 @@
+/*
+ * net/tipc/bcast.c: TIPC broadcast code
+ *
+ * Copyright (c) 2003-2005, Ericsson Research Canada
+ * Copyright (c) 2004, Intel Corporation.
+ * Copyright (c) 2005, Wind River Systems
+ * Copyright (c) 2005-2006, Ericsson AB
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * Neither the names of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "core.h"
+#include "msg.h"
+#include "dbg.h"
+#include "link.h"
+#include "net.h"
+#include "node.h"
+#include "port.h"
+#include "addr.h"
+#include "node_subscr.h"
+#include "name_distr.h"
+#include "bearer.h"
+#include "name_table.h"
+#include "bcast.h"
+
+
+#define MAX_PKT_DEFAULT_MCAST 1500 /* bcast link max packet size (fixed) */
+
+#define BCLINK_WIN_DEFAULT 20 /* bcast link window size (default) */
+
+#define BCLINK_LOG_BUF_SIZE 0
+
+/**
+ * struct bcbearer_pair - a pair of bearers used by broadcast link
+ * @primary: pointer to primary bearer
+ * @secondary: pointer to secondary bearer
+ *
+ * Bearers must have same priority and same set of reachable destinations
+ * to be paired.
+ */
+
+struct bcbearer_pair {
+ struct bearer *primary;
+ struct bearer *secondary;
+};
+
+/**
+ * struct bcbearer - bearer used by broadcast link
+ * @bearer: (non-standard) broadcast bearer structure
+ * @media: (non-standard) broadcast media structure
+ * @bpairs: array of bearer pairs
+ * @bpairs_temp: array of bearer pairs used during creation of "bpairs"
+ */
+
+struct bcbearer {
+ struct bearer bearer;
+ struct media media;
+ struct bcbearer_pair bpairs[MAX_BEARERS];
+ struct bcbearer_pair bpairs_temp[TIPC_NUM_LINK_PRI];
+};
+
+/**
+ * struct bclink - link used for broadcast messages
+ * @link: (non-standard) broadcast link structure
+ * @node: (non-standard) node structure representing b'cast link's peer node
+ *
+ * Handles sequence numbering, fragmentation, bundling, etc.
+ */
+
+struct bclink {
+ struct link link;
+ struct node node;
+};
+
+
+static struct bcbearer *bcbearer = NULL;
+static struct bclink *bclink = NULL;
+static struct link *bcl = NULL;
+static spinlock_t bc_lock = SPIN_LOCK_UNLOCKED;
+
+char bc_link_name[] = "multicast-link";
+
+
+static inline u32 buf_seqno(struct sk_buff *buf)
+{
+ return msg_seqno(buf_msg(buf));
+}
+
+static inline u32 bcbuf_acks(struct sk_buff *buf)
+{
+ return (u32)TIPC_SKB_CB(buf)->handle;
+}
+
+static inline void bcbuf_set_acks(struct sk_buff *buf, u32 acks)
+{
+ TIPC_SKB_CB(buf)->handle = (void *)acks;
+}
+
+static inline void bcbuf_decr_acks(struct sk_buff *buf)
+{
+ bcbuf_set_acks(buf, bcbuf_acks(buf) - 1);
+}
+
+
+/**
+ * bclink_set_gap - set gap according to contents of current deferred pkt queue
+ *
+ * Called with 'node' locked, bc_lock unlocked
+ */
+
+static inline void bclink_set_gap(struct node *n_ptr)
+{
+ struct sk_buff *buf = n_ptr->bclink.deferred_head;
+
+ n_ptr->bclink.gap_after = n_ptr->bclink.gap_to =
+ mod(n_ptr->bclink.last_in);
+ if (unlikely(buf != NULL))
+ n_ptr->bclink.gap_to = mod(buf_seqno(buf) - 1);
+}
+
+/**
+ * bclink_ack_allowed - test if ACK or NACK message can be sent at this moment
+ *
+ * This mechanism endeavours to prevent all nodes in network from trying
+ * to ACK or NACK at the same time.
+ *
+ * Note: TIPC uses a different trigger to distribute ACKs than it does to
+ * distribute NACKs, but tries to use the same spacing (divide by 16).
+ */
+
+static inline int bclink_ack_allowed(u32 n)
+{
+ return((n % TIPC_MIN_LINK_WIN) == tipc_own_tag);
+}
+
+
+/**
+ * bclink_retransmit_pkt - retransmit broadcast packets
+ * @after: sequence number of last packet to *not* retransmit
+ * @to: sequence number of last packet to retransmit
+ *
+ * Called with 'node' locked, bc_lock unlocked
+ */
+
+static void bclink_retransmit_pkt(u32 after, u32 to)
+{
+ struct sk_buff *buf;
+
+ spin_lock_bh(&bc_lock);
+ buf = bcl->first_out;
+ while (buf && less_eq(buf_seqno(buf), after)) {
+ buf = buf->next;
+ }
+ if (buf != NULL)
+ link_retransmit(bcl, buf, mod(to - after));
+ spin_unlock_bh(&bc_lock);
+}
+
+/**
+ * bclink_acknowledge - handle acknowledgement of broadcast packets
+ * @n_ptr: node that sent acknowledgement info
+ * @acked: broadcast sequence # that has been acknowledged
+ *
+ * Node is locked, bc_lock unlocked.
+ */
+
+void bclink_acknowledge(struct node *n_ptr, u32 acked)
+{
+ struct sk_buff *crs;
+ struct sk_buff *next;
+ unsigned int released = 0;
+
+ if (less_eq(acked, n_ptr->bclink.acked))
+ return;
+
+ spin_lock_bh(&bc_lock);
+
+ /* Skip over packets that node has previously acknowledged */
+
+ crs = bcl->first_out;
+ while (crs && less_eq(buf_seqno(crs), n_ptr->bclink.acked)) {
+ crs = crs->next;
+ }
+
+ /* Update packets that node is now acknowledging */
+
+ while (crs && less_eq(buf_seqno(crs), acked)) {
+ next = crs->next;
+ bcbuf_decr_acks(crs);
+ if (bcbuf_acks(crs) == 0) {
+ bcl->first_out = next;
+ bcl->out_queue_size--;
+ buf_discard(crs);
+ released = 1;
+ }
+ crs = next;
+ }
+ n_ptr->bclink.acked = acked;
+
+ /* Try resolving broadcast link congestion, if necessary */
+
+ if (unlikely(bcl->next_out))
+ link_push_queue(bcl);
+ if (unlikely(released && !list_empty(&bcl->waiting_ports)))
+ link_wakeup_ports(bcl, 0);
+ spin_unlock_bh(&bc_lock);
+}
+
+/**
+ * bclink_send_ack - unicast an ACK msg
+ *
+ * net_lock and node lock set
+ */
+
+static void bclink_send_ack(struct node *n_ptr)
+{
+ struct link *l_ptr = n_ptr->active_links[n_ptr->addr & 1];
+
+ if (l_ptr != NULL)
+ link_send_proto_msg(l_ptr, STATE_MSG, 0, 0, 0, 0, 0);
+}
+
+/**
+ * bclink_send_nack- broadcast a NACK msg
+ *
+ * net_lock and node lock set
+ */
+
+static void bclink_send_nack(struct node *n_ptr)
+{
+ struct sk_buff *buf;
+ struct tipc_msg *msg;
+
+ if (!less(n_ptr->bclink.gap_after, n_ptr->bclink.gap_to))
+ return;
+
+ buf = buf_acquire(INT_H_SIZE);
+ if (buf) {
+ msg = buf_msg(buf);
+ msg_init(msg, BCAST_PROTOCOL, STATE_MSG,
+ TIPC_OK, INT_H_SIZE, n_ptr->addr);
+ msg_set_mc_netid(msg, tipc_net_id);
+ msg_set_bcast_ack(msg, mod(n_ptr->bclink.last_in));
+ msg_set_bcgap_after(msg, n_ptr->bclink.gap_after);
+ msg_set_bcgap_to(msg, n_ptr->bclink.gap_to);
+ msg_set_bcast_tag(msg, tipc_own_tag);
+
+ if (bearer_send(&bcbearer->bearer, buf, 0)) {
+ bcl->stats.sent_nacks++;
+ buf_discard(buf);
+ } else {
+ bearer_schedule(bcl->b_ptr, bcl);
+ bcl->proto_msg_queue = buf;
+ bcl->stats.bearer_congs++;
+ }
+
+ /*
+ * Ensure we doesn't send another NACK msg to the node
+ * until 16 more deferred messages arrive from it
+ * (i.e. helps prevent all nodes from NACK'ing at same time)
+ */
+
+ n_ptr->bclink.nack_sync = tipc_own_tag;
+ }
+}
+
+/**
+ * bclink_check_gap - send a NACK if a sequence gap exists
+ *
+ * net_lock and node lock set
+ */
+
+void bclink_check_gap(struct node *n_ptr, u32 last_sent)
+{
+ if (!n_ptr->bclink.supported ||
+ less_eq(last_sent, mod(n_ptr->bclink.last_in)))
+ return;
+
+ bclink_set_gap(n_ptr);
+ if (n_ptr->bclink.gap_after == n_ptr->bclink.gap_to)
+ n_ptr->bclink.gap_to = last_sent;
+ bclink_send_nack(n_ptr);
+}
+
+/**
+ * bclink_peek_nack - process a NACK msg meant for another node
+ *
+ * Only net_lock set.
+ */
+
+void bclink_peek_nack(u32 dest, u32 sender_tag, u32 gap_after, u32 gap_to)
+{
+ struct node *n_ptr = node_find(dest);
+ u32 my_after, my_to;
+
+ if (unlikely(!n_ptr || !node_is_up(n_ptr)))
+ return;
+ node_lock(n_ptr);
+ /*
+ * Modify gap to suppress unnecessary NACKs from this node
+ */
+ my_after = n_ptr->bclink.gap_after;
+ my_to = n_ptr->bclink.gap_to;
+
+ if (less_eq(gap_after, my_after)) {
+ if (less(my_after, gap_to) && less(gap_to, my_to))
+ n_ptr->bclink.gap_after = gap_to;
+ else if (less_eq(my_to, gap_to))
+ n_ptr->bclink.gap_to = n_ptr->bclink.gap_after;
+ } else if (less_eq(gap_after, my_to)) {
+ if (less_eq(my_to, gap_to))
+ n_ptr->bclink.gap_to = gap_after;
+ } else {
+ /*
+ * Expand gap if missing bufs not in deferred queue:
+ */
+ struct sk_buff *buf = n_ptr->bclink.deferred_head;
+ u32 prev = n_ptr->bclink.gap_to;
+
+ for (; buf; buf = buf->next) {
+ u32 seqno = buf_seqno(buf);
+
+ if (mod(seqno - prev) != 1)
+ buf = NULL;
+ if (seqno == gap_after)
+ break;
+ prev = seqno;
+ }
+ if (buf == NULL)
+ n_ptr->bclink.gap_to = gap_after;
+ }
+ /*
+ * Some nodes may send a complementary NACK now:
+ */
+ if (bclink_ack_allowed(sender_tag + 1)) {
+ if (n_ptr->bclink.gap_to != n_ptr->bclink.gap_after) {
+ bclink_send_nack(n_ptr);
+ bclink_set_gap(n_ptr);
+ }
+ }
+ node_unlock(n_ptr);
+}
+
+/**
+ * bclink_send_msg - broadcast a packet to all nodes in cluster
+ */
+
+int bclink_send_msg(struct sk_buff *buf)
+{
+ int res;
+
+ spin_lock_bh(&bc_lock);
+
+ res = link_send_buf(bcl, buf);
+ if (unlikely(res == -ELINKCONG))
+ buf_discard(buf);
+ else
+ bcl->stats.sent_info++;
+
+ if (bcl->out_queue_size > bcl->stats.max_queue_sz)
+ bcl->stats.max_queue_sz = bcl->out_queue_size;
+ bcl->stats.queue_sz_counts++;
+ bcl->stats.accu_queue_sz += bcl->out_queue_size;
+
+ spin_unlock_bh(&bc_lock);
+ return res;
+}
+
+/**
+ * bclink_recv_pkt - receive a broadcast packet, and deliver upwards
+ *
+ * net_lock is read_locked, no other locks set
+ */
+
+void bclink_recv_pkt(struct sk_buff *buf)
+{
+ struct tipc_msg *msg = buf_msg(buf);
+ struct node* node = node_find(msg_prevnode(msg));
+ u32 next_in;
+ u32 seqno;
+ struct sk_buff *deferred;
+
+ msg_dbg(msg, "<BC<<<");
+
+ if (unlikely(!node || !node_is_up(node) || !node->bclink.supported ||
+ (msg_mc_netid(msg) != tipc_net_id))) {
+ buf_discard(buf);
+ return;
+ }
+
+ if (unlikely(msg_user(msg) == BCAST_PROTOCOL)) {
+ msg_dbg(msg, "<BCNACK<<<");
+ if (msg_destnode(msg) == tipc_own_addr) {
+ node_lock(node);
+ bclink_acknowledge(node, msg_bcast_ack(msg));
+ node_unlock(node);
+ bcl->stats.recv_nacks++;
+ bclink_retransmit_pkt(msg_bcgap_after(msg),
+ msg_bcgap_to(msg));
+ } else {
+ bclink_peek_nack(msg_destnode(msg),
+ msg_bcast_tag(msg),
+ msg_bcgap_after(msg),
+ msg_bcgap_to(msg));
+ }
+ buf_discard(buf);
+ return;
+ }
+
+ node_lock(node);
+receive:
+ deferred = node->bclink.deferred_head;
+ next_in = mod(node->bclink.last_in + 1);
+ seqno = msg_seqno(msg);
+
+ if (likely(seqno == next_in)) {
+ bcl->stats.recv_info++;
+ node->bclink.last_in++;
+ bclink_set_gap(node);
+ if (unlikely(bclink_ack_allowed(seqno))) {
+ bclink_send_ack(node);
+ bcl->stats.sent_acks++;
+ }
+ if (likely(msg_isdata(msg))) {
+ node_unlock(node);
+ port_recv_mcast(buf, NULL);
+ } else if (msg_user(msg) == MSG_BUNDLER) {
+ bcl->stats.recv_bundles++;
+ bcl->stats.recv_bundled += msg_msgcnt(msg);
+ node_unlock(node);
+ link_recv_bundle(buf);
+ } else if (msg_user(msg) == MSG_FRAGMENTER) {
+ bcl->stats.recv_fragments++;
+ if (link_recv_fragment(&node->bclink.defragm,
+ &buf, &msg))
+ bcl->stats.recv_fragmented++;
+ node_unlock(node);
+ net_route_msg(buf);
+ } else {
+ node_unlock(node);
+ net_route_msg(buf);
+ }
+ if (deferred && (buf_seqno(deferred) == mod(next_in + 1))) {
+ node_lock(node);
+ buf = deferred;
+ msg = buf_msg(buf);