add idl4k kernel firmware version 1.13.0.105

This commit is contained in:
Jaroslav Kysela
2015-03-26 17:22:37 +01:00
parent 5194d2792e
commit e9070cdc77
31064 changed files with 12769984 additions and 0 deletions

115
kernel/net/tipc/Kconfig Normal file
View File

@@ -0,0 +1,115 @@
#
# TIPC configuration
#
menuconfig TIPC
tristate "The TIPC Protocol (EXPERIMENTAL)"
depends on INET && EXPERIMENTAL
---help---
The Transparent Inter Process Communication (TIPC) protocol is
specially designed for intra cluster communication. This protocol
originates from Ericsson where it has been used in carrier grade
cluster applications for many years.
For more information about TIPC, see http://tipc.sourceforge.net.
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/kbuild/modules.txt>.
If in doubt, say N.
if TIPC
config TIPC_ADVANCED
bool "TIPC: Advanced configuration"
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_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_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_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_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_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_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"
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.
endif # TIPC

13
kernel/net/tipc/Makefile Normal file
View File

@@ -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

94
kernel/net/tipc/addr.c Normal file
View File

@@ -0,0 +1,94 @@
/*
* net/tipc/addr.c: TIPC address utility routines
*
* Copyright (c) 2000-2006, Ericsson AB
* Copyright (c) 2004-2005, Wind River Systems
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. 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.
*
* Alternatively, this software may be distributed under the terms of the
* GNU General Public License ("GPL") version 2 as published by the Free
* Software Foundation.
*
* 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;
}
/**
* tipc_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 tipc_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;
}
/**
* tipc_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 tipc_addr_node_valid(u32 addr)
{
return (tipc_addr_domain_valid(addr) && tipc_node(addr));
}

123
kernel/net/tipc/addr.h Normal file
View File

@@ -0,0 +1,123 @@
/*
* net/tipc/addr.h: Include file for TIPC address utility routines
*
* Copyright (c) 2000-2006, Ericsson AB
* Copyright (c) 2004-2005, Wind River Systems
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. 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.
*
* Alternatively, this software may be distributed under the terms of the
* GNU General Public License ("GPL") version 2 as published by the Free
* Software Foundation.
*
* 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 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 tipc_addr_domain_valid(u32);
int tipc_addr_node_valid(u32 addr);
#endif

831
kernel/net/tipc/bcast.c Normal file
View File

@@ -0,0 +1,831 @@
/*
* net/tipc/bcast.c: TIPC broadcast code
*
* Copyright (c) 2004-2006, Ericsson AB
* Copyright (c) 2004, Intel Corporation.
* Copyright (c) 2005, Wind River Systems
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. 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.
*
* Alternatively, this software may be distributed under the terms of the
* GNU General Public License ("GPL") version 2 as published by the Free
* Software Foundation.
*
* 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
/*
* Loss rate for incoming broadcast frames; used to test retransmission code.
* Set to N to cause every N'th frame to be discarded; 0 => don't discard any.
*/
#define TIPC_BCAST_LOSS_RATE 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: temporary array of bearer pairs used by tipc_bcbearer_sort()
* @remains: temporary node map used by tipc_bcbearer_send()
* @remains_new: temporary node map used tipc_bcbearer_send()
*
* Note: The fields labelled "temporary" are incorporated into the bearer
* to avoid consuming potentially limited stack space through the use of
* large local variables within multicast routines. Concurrent access is
* prevented through use of the spinlock "bc_lock".
*/
struct bcbearer {
struct bearer bearer;
struct media media;
struct bcbearer_pair bpairs[MAX_BEARERS];
struct bcbearer_pair bpairs_temp[TIPC_MAX_LINK_PRI + 1];
struct tipc_node_map remains;
struct tipc_node_map remains_new;
};
/**
* 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 tipc_node node;
};
static struct bcbearer *bcbearer = NULL;
static struct bclink *bclink = NULL;
static struct link *bcl = NULL;
static DEFINE_SPINLOCK(bc_lock);
const char tipc_bclink_name[] = "multicast-link";
static u32 buf_seqno(struct sk_buff *buf)
{
return msg_seqno(buf_msg(buf));
}
static u32 bcbuf_acks(struct sk_buff *buf)
{
return (u32)(unsigned long)TIPC_SKB_CB(buf)->handle;
}
static void bcbuf_set_acks(struct sk_buff *buf, u32 acks)
{
TIPC_SKB_CB(buf)->handle = (void *)(unsigned long)acks;
}
static 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 void bclink_set_gap(struct tipc_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 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 bc_lock locked
*/
static void bclink_retransmit_pkt(u32 after, u32 to)
{
struct sk_buff *buf;
buf = bcl->first_out;
while (buf && less_eq(buf_seqno(buf), after)) {
buf = buf->next;
}
tipc_link_retransmit(bcl, buf, mod(to - after));
}
/**
* tipc_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 tipc_bclink_acknowledge(struct tipc_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))
tipc_link_push_queue(bcl);
if (unlikely(released && !list_empty(&bcl->waiting_ports)))
tipc_link_wakeup_ports(bcl, 0);
spin_unlock_bh(&bc_lock);
}
/**
* bclink_send_ack - unicast an ACK msg
*
* tipc_net_lock and node lock set
*/
static void bclink_send_ack(struct tipc_node *n_ptr)
{
struct link *l_ptr = n_ptr->active_links[n_ptr->addr & 1];
if (l_ptr != NULL)
tipc_link_send_proto_msg(l_ptr, STATE_MSG, 0, 0, 0, 0, 0);
}
/**
* bclink_send_nack- broadcast a NACK msg
*
* tipc_net_lock and node lock set
*/
static void bclink_send_nack(struct tipc_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,
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 (tipc_bearer_send(&bcbearer->bearer, buf, NULL)) {
bcl->stats.sent_nacks++;
buf_discard(buf);
} else {
tipc_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;
}
}
/**
* tipc_bclink_check_gap - send a NACK if a sequence gap exists
*
* tipc_net_lock and node lock set
*/
void tipc_bclink_check_gap(struct tipc_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);
}
/**
* tipc_bclink_peek_nack - process a NACK msg meant for another node
*
* Only tipc_net_lock set.
*/
static void tipc_bclink_peek_nack(u32 dest, u32 sender_tag, u32 gap_after, u32 gap_to)
{
struct tipc_node *n_ptr = tipc_node_find(dest);
u32 my_after, my_to;
if (unlikely(!n_ptr || !tipc_node_is_up(n_ptr)))
return;
tipc_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;
break;
}
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);
}
}
tipc_node_unlock(n_ptr);
}
/**
* tipc_bclink_send_msg - broadcast a packet to all nodes in cluster
*/
int tipc_bclink_send_msg(struct sk_buff *buf)
{
int res;
spin_lock_bh(&bc_lock);
res = tipc_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;
}
/**
* tipc_bclink_recv_pkt - receive a broadcast packet, and deliver upwards
*
* tipc_net_lock is read_locked, no other locks set
*/
void tipc_bclink_recv_pkt(struct sk_buff *buf)
{
#if (TIPC_BCAST_LOSS_RATE)
static int rx_count = 0;
#endif
struct tipc_msg *msg = buf_msg(buf);
struct tipc_node* node = tipc_node_find(msg_prevnode(msg));
u32 next_in;
u32 seqno;
struct sk_buff *deferred;
msg_dbg(msg, "<BC<<<");
if (unlikely(!node || !tipc_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) {
tipc_node_lock(node);
tipc_bclink_acknowledge(node, msg_bcast_ack(msg));
tipc_node_unlock(node);
spin_lock_bh(&bc_lock);
bcl->stats.recv_nacks++;
bcl->owner->next = node; /* remember requestor */
bclink_retransmit_pkt(msg_bcgap_after(msg),
msg_bcgap_to(msg));
bcl->owner->next = NULL;
spin_unlock_bh(&bc_lock);
} else {
tipc_bclink_peek_nack(msg_destnode(msg),
msg_bcast_tag(msg),
msg_bcgap_after(msg),
msg_bcgap_to(msg));
}
buf_discard(buf);
return;
}
#if (TIPC_BCAST_LOSS_RATE)
if (++rx_count == TIPC_BCAST_LOSS_RATE) {
rx_count = 0;
buf_discard(buf);
return;
}
#endif
tipc_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))) {
tipc_node_unlock(node);
tipc_port_recv_mcast(buf, NULL);
} else if (msg_user(msg) == MSG_BUNDLER) {
bcl->stats.recv_bundles++;
bcl->stats.recv_bundled += msg_msgcnt(msg);
tipc_node_unlock(node);
tipc_link_recv_bundle(buf);
} else if (msg_user(msg) == MSG_FRAGMENTER) {
bcl->stats.recv_fragments++;
if (tipc_link_recv_fragment(&node->bclink.defragm,
&buf, &msg))
bcl->stats.recv_fragmented++;
tipc_node_unlock(node);
tipc_net_route_msg(buf);
} else {
tipc_node_unlock(node);
tipc_net_route_msg(buf);
}
if (deferred && (buf_seqno(deferred) == mod(next_in + 1))) {
tipc_node_lock(node);
buf = deferred;
msg = buf_msg(buf);
node->bclink.deferred_head = deferred->next;
goto receive;
}
return;
} else if (less(next_in, seqno)) {
u32 gap_after = node->bclink.gap_after;
u32 gap_to = node->bclink.gap_to;
if (tipc_link_defer_pkt(&node->bclink.deferred_head,
&node->bclink.deferred_tail,
buf)) {
node->bclink.nack_sync++;
bcl->stats.deferred_recv++;
if (seqno == mod(gap_after + 1))
node->bclink.gap_after = seqno;
else if (less(gap_after, seqno) && less(seqno, gap_to))
node->bclink.gap_to = seqno;
}
if (bclink_ack_allowed(node->bclink.nack_sync)) {
if (gap_to != gap_after)
bclink_send_nack(node);
bclink_set_gap(node);
}
} else {
bcl->stats.duplicates++;
buf_discard(buf);
}
tipc_node_unlock(node);
}
u32 tipc_bclink_get_last_sent(void)
{
u32 last_sent = mod(bcl->next_out_no - 1);
if (bcl->next_out)
last_sent = mod(buf_seqno(bcl->next_out) - 1);
return last_sent;
}
u32 tipc_bclink_acks_missing(struct tipc_node *n_ptr)
{
return (n_ptr->bclink.supported &&
(tipc_bclink_get_last_sent() != n_ptr->bclink.acked));
}
/**
* tipc_bcbearer_send - send a packet through the broadcast pseudo-bearer
*
* Send through as many bearers as necessary to reach all nodes
* that support TIPC multicasting.
*
* Returns 0 if packet sent successfully, non-zero if not
*/
static int tipc_bcbearer_send(struct sk_buff *buf,
struct tipc_bearer *unused1,
struct tipc_media_addr *unused2)
{
static int send_count = 0;
int bp_index;
int swap_time;
/* Prepare buffer for broadcasting (if first time trying to send it) */
if (likely(!msg_non_seq(buf_msg(buf)))) {
struct tipc_msg *msg;
assert(tipc_cltr_bcast_nodes.count != 0);
bcbuf_set_acks(buf, tipc_cltr_bcast_nodes.count);
msg = buf_msg(buf);
msg_set_non_seq(msg, 1);
msg_set_mc_netid(msg, tipc_net_id);
}
/* Determine if bearer pairs should be swapped following this attempt */
if ((swap_time = (++send_count >= 10)))
send_count = 0;
/* Send buffer over bearers until all targets reached */
bcbearer->remains = tipc_cltr_bcast_nodes;
for (bp_index = 0; bp_index < MAX_BEARERS; bp_index++) {
struct bearer *p = bcbearer->bpairs[bp_index].primary;
struct bearer *s = bcbearer->bpairs[bp_index].secondary;
if (!p)
break; /* no more bearers to try */
tipc_nmap_diff(&bcbearer->remains, &p->nodes, &bcbearer->remains_new);
if (bcbearer->remains_new.count == bcbearer->remains.count)
continue; /* bearer pair doesn't add anything */
if (!p->publ.blocked &&
!p->media->send_msg(buf, &p->publ, &p->media->bcast_addr)) {
if (swap_time && s && !s->publ.blocked)
goto swap;
else
goto update;
}
if (!s || s->publ.blocked ||
s->media->send_msg(buf, &s->publ, &s->media->bcast_addr))
continue; /* unable to send using bearer pair */
swap:
bcbearer->bpairs[bp_index].primary = s;
bcbearer->bpairs[bp_index].secondary = p;
update:
if (bcbearer->remains_new.count == 0)
return 0;
bcbearer->remains = bcbearer->remains_new;
}
/* Unable to reach all targets */
bcbearer->bearer.publ.blocked = 1;
bcl->stats.bearer_congs++;
return 1;
}
/**
* tipc_bcbearer_sort - create sets of bearer pairs used by broadcast bearer
*/
void tipc_bcbearer_sort(void)
{
struct bcbearer_pair *bp_temp = bcbearer->bpairs_temp;
struct bcbearer_pair *bp_curr;
int b_index;
int pri;
spin_lock_bh(&bc_lock);
/* Group bearers by priority (can assume max of two per priority) */
memset(bp_temp, 0, sizeof(bcbearer->bpairs_temp));
for (b_index = 0; b_index < MAX_BEARERS; b_index++) {
struct bearer *b = &tipc_bearers[b_index];
if (!b->active || !b->nodes.count)
continue;
if (!bp_temp[b->priority].primary)
bp_temp[b->priority].primary = b;
else
bp_temp[b->priority].secondary = b;
}
/* Create array of bearer pairs for broadcasting */
bp_curr = bcbearer->bpairs;
memset(bcbearer->bpairs, 0, sizeof(bcbearer->bpairs));
for (pri = TIPC_MAX_LINK_PRI; pri >= 0; pri--) {
if (!bp_temp[pri].primary)
continue;
bp_curr->primary = bp_temp[pri].primary;
if (bp_temp[pri].secondary) {
if (tipc_nmap_equal(&bp_temp[pri].primary->nodes,
&bp_temp[pri].secondary->nodes)) {
bp_curr->secondary = bp_temp[pri].secondary;
} else {
bp_curr++;
bp_curr->primary = bp_temp[pri].secondary;
}
}
bp_curr++;
}
spin_unlock_bh(&bc_lock);
}
/**
* tipc_bcbearer_push - resolve bearer congestion
*
* Forces bclink to push out any unsent packets, until all packets are gone
* or congestion reoccurs.
* No locks set when function called
*/
void tipc_bcbearer_push(void)
{
struct bearer *b_ptr;
spin_lock_bh(&bc_lock);
b_ptr = &bcbearer->bearer;
if (b_ptr->publ.blocked) {
b_ptr->publ.blocked = 0;
tipc_bearer_lock_push(b_ptr);
}
spin_unlock_bh(&bc_lock);
}
int tipc_bclink_stats(char *buf, const u32 buf_size)
{
struct print_buf pb;
if (!bcl)
return 0;
tipc_printbuf_init(&pb, buf, buf_size);
spin_lock_bh(&bc_lock);
tipc_printf(&pb, "Link <%s>\n"
" Window:%u packets\n",
bcl->name, bcl->queue_limit[0]);
tipc_printf(&pb, " RX packets:%u fragments:%u/%u bundles:%u/%u\n",
bcl->stats.recv_info,
bcl->stats.recv_fragments,
bcl->stats.recv_fragmented,
bcl->stats.recv_bundles,
bcl->stats.recv_bundled);
tipc_printf(&pb, " TX packets:%u fragments:%u/%u bundles:%u/%u\n",
bcl->stats.sent_info,
bcl->stats.sent_fragments,
bcl->stats.sent_fragmented,
bcl->stats.sent_bundles,
bcl->stats.sent_bundled);
tipc_printf(&pb, " RX naks:%u defs:%u dups:%u\n",
bcl->stats.recv_nacks,
bcl->stats.deferred_recv,
bcl->stats.duplicates);
tipc_printf(&pb, " TX naks:%u acks:%u dups:%u\n",
bcl->stats.sent_nacks,
bcl->stats.sent_acks,
bcl->stats.retransmitted);
tipc_printf(&pb, " Congestion bearer:%u link:%u Send queue max:%u avg:%u\n",
bcl->stats.bearer_congs,
bcl->stats.link_congs,
bcl->stats.max_queue_sz,
bcl->stats.queue_sz_counts
? (bcl->stats.accu_queue_sz / bcl->stats.queue_sz_counts)
: 0);
spin_unlock_bh(&bc_lock);
return tipc_printbuf_validate(&pb);
}
int tipc_bclink_reset_stats(void)
{
if (!bcl)
return -ENOPROTOOPT;
spin_lock_bh(&bc_lock);
memset(&bcl->stats, 0, sizeof(bcl->stats));
spin_unlock_bh(&bc_lock);
return 0;
}
int tipc_bclink_set_queue_limits(u32 limit)
{
if (!bcl)
return -ENOPROTOOPT;
if ((limit < TIPC_MIN_LINK_WIN) || (limit > TIPC_MAX_LINK_WIN))
return -EINVAL;
spin_lock_bh(&bc_lock);
tipc_link_set_queue_limits(bcl, limit);
spin_unlock_bh(&bc_lock);
return 0;
}
int tipc_bclink_init(void)
{
bcbearer = kzalloc(sizeof(*bcbearer), GFP_ATOMIC);
bclink = kzalloc(sizeof(*bclink), GFP_ATOMIC);
if (!bcbearer || !bclink) {
nomem:
warn("Multicast link creation failed, no memory\n");
kfree(bcbearer);
bcbearer = NULL;
kfree(bclink);
bclink = NULL;
return -ENOMEM;
}
INIT_LIST_HEAD(&bcbearer->bearer.cong_links);
bcbearer->bearer.media = &bcbearer->media;
bcbearer->media.send_msg = tipc_bcbearer_send;
sprintf(bcbearer->media.name, "tipc-multicast");
bcl = &bclink->link;
INIT_LIST_HEAD(&bcl->waiting_ports);
bcl->next_out_no = 1;
spin_lock_init(&bclink->node.lock);
bcl->owner = &bclink->node;
bcl->max_pkt = MAX_PKT_DEFAULT_MCAST;
tipc_link_set_queue_limits(bcl, BCLINK_WIN_DEFAULT);
bcl->b_ptr = &bcbearer->bearer;
bcl->state = WORKING_WORKING;
strlcpy(bcl->name, tipc_bclink_name, TIPC_MAX_LINK_NAME);
if (BCLINK_LOG_BUF_SIZE) {
char *pb = kmalloc(BCLINK_LOG_BUF_SIZE, GFP_ATOMIC);
if (!pb)
goto nomem;
tipc_printbuf_init(&bcl->print_buf, pb, BCLINK_LOG_BUF_SIZE);
}
return 0;
}
void tipc_bclink_stop(void)
{
spin_lock_bh(&bc_lock);
if (bcbearer) {
tipc_link_stop(bcl);
if (BCLINK_LOG_BUF_SIZE)
kfree(bcl->print_buf.buf);
bcl = NULL;
kfree(bclink);
bclink = NULL;
kfree(bcbearer);
bcbearer = NULL;
}
spin_unlock_bh(&bc_lock);
}

210
kernel/net/tipc/bcast.h Normal file
View File

@@ -0,0 +1,210 @@
/*
* net/tipc/bcast.h: Include file for TIPC broadcast code
*
* Copyright (c) 2003-2006, Ericsson AB
* Copyright (c) 2005, Wind River Systems
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. 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.
*
* Alternatively, this software may be distributed under the terms of the
* GNU General Public License ("GPL") version 2 as published by the Free
* Software Foundation.
*
* 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_BCAST_H
#define _TIPC_BCAST_H
#define MAX_NODES 4096
#define WSIZE 32
/**
* struct tipc_node_map - set of node identifiers
* @count: # of nodes in set
* @map: bitmap of node identifiers that are in the set
*/
struct tipc_node_map {
u32 count;
u32 map[MAX_NODES / WSIZE];
};
#define PLSIZE 32
/**
* struct port_list - set of node local destination ports
* @count: # of ports in set (only valid for first entry in list)
* @next: pointer to next entry in list
* @ports: array of port references
*/
struct port_list {
int count;
struct port_list *next;
u32 ports[PLSIZE];
};
struct tipc_node;
extern const char tipc_bclink_name[];
/**
* nmap_add - add a node to a node map
*/
static inline void tipc_nmap_add(struct tipc_node_map *nm_ptr, u32 node)
{
int n = tipc_node(node);
int w = n / WSIZE;
u32 mask = (1 << (n % WSIZE));
if ((nm_ptr->map[w] & mask) == 0) {
nm_ptr->count++;
nm_ptr->map[w] |= mask;
}
}
/**
* nmap_remove - remove a node from a node map
*/
static inline void tipc_nmap_remove(struct tipc_node_map *nm_ptr, u32 node)
{
int n = tipc_node(node);
int w = n / WSIZE;
u32 mask = (1 << (n % WSIZE));
if ((nm_ptr->map[w] & mask) != 0) {
nm_ptr->map[w] &= ~mask;
nm_ptr->count--;
}
}
/**
* nmap_equal - test for equality of node maps
*/
static inline int tipc_nmap_equal(struct tipc_node_map *nm_a, struct tipc_node_map *nm_b)
{
return !memcmp(nm_a, nm_b, sizeof(*nm_a));
}
/**
* nmap_diff - find differences between node maps
* @nm_a: input node map A
* @nm_b: input node map B
* @nm_diff: output node map A-B (i.e. nodes of A that are not in B)
*/
static inline void tipc_nmap_diff(struct tipc_node_map *nm_a, struct tipc_node_map *nm_b,
struct tipc_node_map *nm_diff)
{
int stop = ARRAY_SIZE(nm_a->map);
int w;
int b;
u32 map;
memset(nm_diff, 0, sizeof(*nm_diff));
for (w = 0; w < stop; w++) {
map = nm_a->map[w] ^ (nm_a->map[w] & nm_b->map[w]);
nm_diff->map[w] = map;
if (map != 0) {
for (b = 0 ; b < WSIZE; b++) {
if (map & (1 << b))
nm_diff->count++;
}
}
}
}
/**
* port_list_add - add a port to a port list, ensuring no duplicates
*/
static inline void tipc_port_list_add(struct port_list *pl_ptr, u32 port)
{
struct port_list *item = pl_ptr;
int i;
int item_sz = PLSIZE;
int cnt = pl_ptr->count;
for (; ; cnt -= item_sz, item = item->next) {
if (cnt < PLSIZE)
item_sz = cnt;
for (i = 0; i < item_sz; i++)
if (item->ports[i] == port)
return;
if (i < PLSIZE) {
item->ports[i] = port;
pl_ptr->count++;
return;
}
if (!item->next) {
item->next = kmalloc(sizeof(*item), GFP_ATOMIC);
if (!item->next) {
warn("Incomplete multicast delivery, no memory\n");
return;
}
item->next->next = NULL;
}
}
}
/**
* port_list_free - free dynamically created entries in port_list chain
*
* Note: First item is on stack, so it doesn't need to be released
*/
static inline void tipc_port_list_free(struct port_list *pl_ptr)
{
struct port_list *item;
struct port_list *next;
for (item = pl_ptr->next; item; item = next) {
next = item->next;
kfree(item);
}
}
int tipc_bclink_init(void);
void tipc_bclink_stop(void);
void tipc_bclink_acknowledge(struct tipc_node *n_ptr, u32 acked);
int tipc_bclink_send_msg(struct sk_buff *buf);
void tipc_bclink_recv_pkt(struct sk_buff *buf);
u32 tipc_bclink_get_last_sent(void);
u32 tipc_bclink_acks_missing(struct tipc_node *n_ptr);
void tipc_bclink_check_gap(struct tipc_node *n_ptr, u32 seqno);
int tipc_bclink_stats(char *stats_buf, const u32 buf_size);
int tipc_bclink_reset_stats(void);
int tipc_bclink_set_queue_limits(u32 limit);
void tipc_bcbearer_sort(void);
void tipc_bcbearer_push(void);
#endif

680
kernel/net/tipc/bearer.c Normal file
View File

@@ -0,0 +1,680 @@
/*
* net/tipc/bearer.c: TIPC bearer code
*
* Copyright (c) 1996-2006, Ericsson AB
* Copyright (c) 2004-2006, Wind River Systems
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. 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.
*
* Alternatively, this software may be distributed under the terms of the
* GNU General Public License ("GPL") version 2 as published by the Free
* Software Foundation.
*
* 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 "config.h"
#include "dbg.h"
#include "bearer.h"
#include "link.h"
#include "port.h"
#include "discover.h"
#include "bcast.h"
#define MAX_ADDR_STR 32
static struct media media_list[MAX_MEDIA];
static u32 media_count = 0;
struct bearer tipc_bearers[MAX_BEARERS];
/**
* media_name_valid - validate media name
*
* Returns 1 if media name is valid, otherwise 0.
*/
static int media_name_valid(const char *name)
{
u32 len;
len = strlen(name);
if ((len + 1) > TIPC_MAX_MEDIA_NAME)
return 0;
return (strspn(name, tipc_alphabet) == len);
}
/**
* media_find - locates specified media object by name
*/
static struct media *media_find(const char *name)
{
struct media *m_ptr;
u32 i;
for (i = 0, m_ptr = media_list; i < media_count; i++, m_ptr++) {
if (!strcmp(m_ptr->name, name))
return m_ptr;
}
return NULL;
}
/**
* tipc_register_media - register a media type
*
* Bearers for this media type must be activated separately at a later stage.
*/
int tipc_register_media(u32 media_type,
char *name,
int (*enable)(struct tipc_bearer *),
void (*disable)(struct tipc_bearer *),
int (*send_msg)(struct sk_buff *,
struct tipc_bearer *,
struct tipc_media_addr *),
char *(*addr2str)(struct tipc_media_addr *a,
char *str_buf, int str_size),
struct tipc_media_addr *bcast_addr,
const u32 bearer_priority,
const u32 link_tolerance, /* [ms] */
const u32 send_window_limit)
{
struct media *m_ptr;
u32 media_id;
u32 i;
int res = -EINVAL;
write_lock_bh(&tipc_net_lock);
if (tipc_mode != TIPC_NET_MODE) {
warn("Media <%s> rejected, not in networked mode yet\n", name);
goto exit;
}
if (!media_name_valid(name)) {
warn("Media <%s> rejected, illegal name\n", name);
goto exit;
}
if (!bcast_addr) {
warn("Media <%s> rejected, no broadcast address\n", name);
goto exit;
}
if ((bearer_priority < TIPC_MIN_LINK_PRI) ||
(bearer_priority > TIPC_MAX_LINK_PRI)) {
warn("Media <%s> rejected, illegal priority (%u)\n", name,
bearer_priority);
goto exit;
}
if ((link_tolerance < TIPC_MIN_LINK_TOL) ||
(link_tolerance > TIPC_MAX_LINK_TOL)) {
warn("Media <%s> rejected, illegal tolerance (%u)\n", name,
link_tolerance);
goto exit;
}
media_id = media_count++;
if (media_id >= MAX_MEDIA) {
warn("Media <%s> rejected, media limit reached (%u)\n", name,
MAX_MEDIA);
media_count--;
goto exit;
}
for (i = 0; i < media_id; i++) {
if (media_list[i].type_id == media_type) {
warn("Media <%s> rejected, duplicate type (%u)\n", name,
media_type);
media_count--;
goto exit;
}
if (!strcmp(name, media_list[i].name)) {
warn("Media <%s> rejected, duplicate name\n", name);
media_count--;
goto exit;
}
}
m_ptr = &media_list[media_id];
m_ptr->type_id = media_type;
m_ptr->send_msg = send_msg;
m_ptr->enable_bearer = enable;
m_ptr->disable_bearer = disable;
m_ptr->addr2str = addr2str;
memcpy(&m_ptr->bcast_addr, bcast_addr, sizeof(*bcast_addr));
m_ptr->bcast = 1;
strcpy(m_ptr->name, name);
m_ptr->priority = bearer_priority;
m_ptr->tolerance = link_tolerance;
m_ptr->window = send_window_limit;
dbg("Media <%s> registered\n", name);
res = 0;
exit:
write_unlock_bh(&tipc_net_lock);
return res;
}
/**
* tipc_media_addr_printf - record media address in print buffer
*/
void tipc_media_addr_printf(struct print_buf *pb, struct tipc_media_addr *a)
{
struct media *m_ptr;
u32 media_type;
u32 i;
media_type = ntohl(a->type);
for (i = 0, m_ptr = media_list; i < media_count; i++, m_ptr++) {
if (m_ptr->type_id == media_type)
break;
}
if ((i < media_count) && (m_ptr->addr2str != NULL)) {
char addr_str[MAX_ADDR_STR];
tipc_printf(pb, "%s(%s)", m_ptr->name,
m_ptr->addr2str(a, addr_str, sizeof(addr_str)));
} else {
unchar *addr = (unchar *)&a->dev_addr;
tipc_printf(pb, "UNKNOWN(%u)", media_type);
for (i = 0; i < (sizeof(*a) - sizeof(a->type)); i++) {
tipc_printf(pb, "-%02x", addr[i]);
}
}
}
/**
* tipc_media_get_names - record names of registered media in buffer
*/
struct sk_buff *tipc_media_get_names(void)
{
struct sk_buff *buf;
struct media *m_ptr;
int i;
buf = tipc_cfg_reply_alloc(MAX_MEDIA * TLV_SPACE(TIPC_MAX_MEDIA_NAME));
if (!buf)
return NULL;
read_lock_bh(&tipc_net_lock);
for (i = 0, m_ptr = media_list; i < media_count; i++, m_ptr++) {
tipc_cfg_append_tlv(buf, TIPC_TLV_MEDIA_NAME, m_ptr->name,
strlen(m_ptr->name) + 1);
}
read_unlock_bh(&tipc_net_lock);
return buf;
}
/**
* bearer_name_validate - validate & (optionally) deconstruct bearer name
* @name - ptr to bearer name string
* @name_parts - ptr to area for bearer name components (or NULL if not needed)
*
* Returns 1 if bearer name is valid, otherwise 0.
*/
static int bearer_name_validate(const char *name,
struct bearer_name *name_parts)
{
char name_copy[TIPC_MAX_BEARER_NAME];
char *media_name;
char *if_name;
u32 media_len;
u32 if_len;
/* copy bearer name & ensure length is OK */
name_copy[TIPC_MAX_BEARER_NAME - 1] = 0;
/* need above in case non-Posix strncpy() doesn't pad with nulls */
strncpy(name_copy, name, TIPC_MAX_BEARER_NAME);
if (name_copy[TIPC_MAX_BEARER_NAME - 1] != 0)
return 0;
/* ensure all component parts of bearer name are present */
media_name = name_copy;
if ((if_name = strchr(media_name, ':')) == NULL)
return 0;
*(if_name++) = 0;
media_len = if_name - media_name;
if_len = strlen(if_name) + 1;
/* validate component parts of bearer name */
if ((media_len <= 1) || (media_len > TIPC_MAX_MEDIA_NAME) ||
(if_len <= 1) || (if_len > TIPC_MAX_IF_NAME) ||
(strspn(media_name, tipc_alphabet) != (media_len - 1)) ||
(strspn(if_name, tipc_alphabet) != (if_len - 1)))
return 0;
/* return bearer name components, if necessary */
if (name_parts) {
strcpy(name_parts->media_name, media_name);
strcpy(name_parts->if_name, if_name);
}
return 1;
}
/**
* bearer_find - locates bearer object with matching bearer name
*/
static struct bearer *bearer_find(const char *name)
{
struct bearer *b_ptr;
u32 i;
if (tipc_mode != TIPC_NET_MODE)
return NULL;
for (i = 0, b_ptr = tipc_bearers; i < MAX_BEARERS; i++, b_ptr++) {
if (b_ptr->active && (!strcmp(b_ptr->publ.name, name)))
return b_ptr;
}
return NULL;
}
/**
* tipc_bearer_find_interface - locates bearer object with matching interface name
*/
struct bearer *tipc_bearer_find_interface(const char *if_name)
{
struct bearer *b_ptr;
char *b_if_name;
u32 i;
for (i = 0, b_ptr = tipc_bearers; i < MAX_BEARERS; i++, b_ptr++) {
if (!b_ptr->active)
continue;
b_if_name = strchr(b_ptr->publ.name, ':') + 1;
if (!strcmp(b_if_name, if_name))
return b_ptr;
}
return NULL;
}
/**
* tipc_bearer_get_names - record names of bearers in buffer
*/
struct sk_buff *tipc_bearer_get_names(void)
{
struct sk_buff *buf;
struct media *m_ptr;
struct bearer *b_ptr;
int i, j;
buf = tipc_cfg_reply_alloc(MAX_BEARERS * TLV_SPACE(TIPC_MAX_BEARER_NAME));
if (!buf)
return NULL;
read_lock_bh(&tipc_net_lock);
for (i = 0, m_ptr = media_list; i < media_count; i++, m_ptr++) {
for (j = 0; j < MAX_BEARERS; j++) {
b_ptr = &tipc_bearers[j];
if (b_ptr->active && (b_ptr->media == m_ptr)) {
tipc_cfg_append_tlv(buf, TIPC_TLV_BEARER_NAME,
b_ptr->publ.name,
strlen(b_ptr->publ.name) + 1);
}
}
}
read_unlock_bh(&tipc_net_lock);
return buf;
}
void tipc_bearer_add_dest(struct bearer *b_ptr, u32 dest)
{
tipc_nmap_add(&b_ptr->nodes, dest);
tipc_disc_update_link_req(b_ptr->link_req);
tipc_bcbearer_sort();
}
void tipc_bearer_remove_dest(struct bearer *b_ptr, u32 dest)
{
tipc_nmap_remove(&b_ptr->nodes, dest);
tipc_disc_update_link_req(b_ptr->link_req);
tipc_bcbearer_sort();
}
/*
* bearer_push(): Resolve bearer congestion. Force the waiting
* links to push out their unsent packets, one packet per link
* per iteration, until all packets are gone or congestion reoccurs.
* 'tipc_net_lock' is read_locked when this function is called
* bearer.lock must be taken before calling
* Returns binary true(1) ore false(0)
*/
static int bearer_push(struct bearer *b_ptr)
{
u32 res = 0;
struct link *ln, *tln;
if (b_ptr->publ.blocked)
return 0;
while (!list_empty(&b_ptr->cong_links) && (res != PUSH_FAILED)) {
list_for_each_entry_safe(ln, tln, &b_ptr->cong_links, link_list) {
res = tipc_link_push_packet(ln);
if (res == PUSH_FAILED)
break;
if (res == PUSH_FINISHED)
list_move_tail(&ln->link_list, &b_ptr->links);
}
}
return list_empty(&b_ptr->cong_links);
}
void tipc_bearer_lock_push(struct bearer *b_ptr)
{
int res;
spin_lock_bh(&b_ptr->publ.lock);
res = bearer_push(b_ptr);
spin_unlock_bh(&b_ptr->publ.lock);
if (res)
tipc_bcbearer_push();
}
/*
* Interrupt enabling new requests after bearer congestion or blocking:
* See bearer_send().
*/
void tipc_continue(struct tipc_bearer *tb_ptr)
{
struct bearer *b_ptr = (struct bearer *)tb_ptr;
spin_lock_bh(&b_ptr->publ.lock);
b_ptr->continue_count++;
if (!list_empty(&b_ptr->cong_links))
tipc_k_signal((Handler)tipc_bearer_lock_push, (unsigned long)b_ptr);
b_ptr->publ.blocked = 0;
spin_unlock_bh(&b_ptr->publ.lock);
}
/*
* Schedule link for sending of messages after the bearer
* has been deblocked by 'continue()'. This method is called
* when somebody tries to send a message via this link while
* the bearer is congested. 'tipc_net_lock' is in read_lock here
* bearer.lock is busy
*/
static void tipc_bearer_schedule_unlocked(struct bearer *b_ptr, struct link *l_ptr)
{
list_move_tail(&l_ptr->link_list, &b_ptr->cong_links);
}
/*
* Schedule link for sending of messages after the bearer
* has been deblocked by 'continue()'. This method is called
* when somebody tries to send a message via this link while
* the bearer is congested. 'tipc_net_lock' is in read_lock here,
* bearer.lock is free
*/
void tipc_bearer_schedule(struct bearer *b_ptr, struct link *l_ptr)
{
spin_lock_bh(&b_ptr->publ.lock);
tipc_bearer_schedule_unlocked(b_ptr, l_ptr);
spin_unlock_bh(&b_ptr->publ.lock);
}
/*
* tipc_bearer_resolve_congestion(): Check if there is bearer congestion,
* and if there is, try to resolve it before returning.
* 'tipc_net_lock' is read_locked when this function is called
*/
int tipc_bearer_resolve_congestion(struct bearer *b_ptr, struct link *l_ptr)
{
int res = 1;
if (list_empty(&b_ptr->cong_links))
return 1;
spin_lock_bh(&b_ptr->publ.lock);
if (!bearer_push(b_ptr)) {
tipc_bearer_schedule_unlocked(b_ptr, l_ptr);
res = 0;
}
spin_unlock_bh(&b_ptr->publ.lock);
return res;
}
/**
* tipc_enable_bearer - enable bearer with the given name
*/
int tipc_enable_bearer(const char *name, u32 bcast_scope, u32 priority)
{
struct bearer *b_ptr;
struct media *m_ptr;
struct bearer_name b_name;
char addr_string[16];
u32 bearer_id;
u32 with_this_prio;
u32 i;
int res = -EINVAL;
if (tipc_mode != TIPC_NET_MODE) {
warn("Bearer <%s> rejected, not supported in standalone mode\n",
name);
return -ENOPROTOOPT;
}
if (!bearer_name_validate(name, &b_name)) {
warn("Bearer <%s> rejected, illegal name\n", name);
return -EINVAL;
}
if (!tipc_addr_domain_valid(bcast_scope) ||
!in_scope(bcast_scope, tipc_own_addr)) {
warn("Bearer <%s> rejected, illegal broadcast scope\n", name);
return -EINVAL;
}
if ((priority < TIPC_MIN_LINK_PRI ||
priority > TIPC_MAX_LINK_PRI) &&
(priority != TIPC_MEDIA_LINK_PRI)) {
warn("Bearer <%s> rejected, illegal priority\n", name);
return -EINVAL;
}
write_lock_bh(&tipc_net_lock);
m_ptr = media_find(b_name.media_name);
if (!m_ptr) {
warn("Bearer <%s> rejected, media <%s> not registered\n", name,
b_name.media_name);
goto failed;
}
if (priority == TIPC_MEDIA_LINK_PRI)
priority = m_ptr->priority;
restart:
bearer_id = MAX_BEARERS;
with_this_prio = 1;
for (i = MAX_BEARERS; i-- != 0; ) {
if (!tipc_bearers[i].active) {
bearer_id = i;
continue;
}
if (!strcmp(name, tipc_bearers[i].publ.name)) {
warn("Bearer <%s> rejected, already enabled\n", name);
goto failed;
}
if ((tipc_bearers[i].priority == priority) &&
(++with_this_prio > 2)) {
if (priority-- == 0) {
warn("Bearer <%s> rejected, duplicate priority\n",
name);
goto failed;
}
warn("Bearer <%s> priority adjustment required %u->%u\n",
name, priority + 1, priority);
goto restart;
}
}
if (bearer_id >= MAX_BEARERS) {
warn("Bearer <%s> rejected, bearer limit reached (%u)\n",
name, MAX_BEARERS);
goto failed;
}
b_ptr = &tipc_bearers[bearer_id];
memset(b_ptr, 0, sizeof(struct bearer));
strcpy(b_ptr->publ.name, name);
res = m_ptr->enable_bearer(&b_ptr->publ);
if (res) {
warn("Bearer <%s> rejected, enable failure (%d)\n", name, -res);
goto failed;
}
b_ptr->identity = bearer_id;
b_ptr->media = m_ptr;
b_ptr->net_plane = bearer_id + 'A';
b_ptr->active = 1;
b_ptr->detect_scope = bcast_scope;
b_ptr->priority = priority;
INIT_LIST_HEAD(&b_ptr->cong_links);
INIT_LIST_HEAD(&b_ptr->links);
if (m_ptr->bcast) {
b_ptr->link_req = tipc_disc_init_link_req(b_ptr, &m_ptr->bcast_addr,
bcast_scope, 2);
}
spin_lock_init(&b_ptr->publ.lock);
write_unlock_bh(&tipc_net_lock);
info("Enabled bearer <%s>, discovery domain %s, priority %u\n",
name, addr_string_fill(addr_string, bcast_scope), priority);
return 0;
failed:
write_unlock_bh(&tipc_net_lock);
return res;
}
/**
* tipc_block_bearer(): Block the bearer with the given name,
* and reset all its links
*/
int tipc_block_bearer(const char *name)
{
struct bearer *b_ptr = NULL;
struct link *l_ptr;
struct link *temp_l_ptr;
read_lock_bh(&tipc_net_lock);
b_ptr = bearer_find(name);
if (!b_ptr) {
warn("Attempt to block unknown bearer <%s>\n", name);
read_unlock_bh(&tipc_net_lock);
return -EINVAL;
}
info("Blocking bearer <%s>\n", name);
spin_lock_bh(&b_ptr->publ.lock);
b_ptr->publ.blocked = 1;
list_for_each_entry_safe(l_ptr, temp_l_ptr, &b_ptr->links, link_list) {
struct tipc_node *n_ptr = l_ptr->owner;
spin_lock_bh(&n_ptr->lock);
tipc_link_reset(l_ptr);
spin_unlock_bh(&n_ptr->lock);
}
spin_unlock_bh(&b_ptr->publ.lock);
read_unlock_bh(&tipc_net_lock);
return 0;
}
/**
* bearer_disable -
*
* Note: This routine assumes caller holds tipc_net_lock.
*/
static int bearer_disable(const char *name)
{
struct bearer *b_ptr;
struct link *l_ptr;
struct link *temp_l_ptr;
b_ptr = bearer_find(name);
if (!b_ptr) {
warn("Attempt to disable unknown bearer <%s>\n", name);
return -EINVAL;
}
info("Disabling bearer <%s>\n", name);
tipc_disc_stop_link_req(b_ptr->link_req);
spin_lock_bh(&b_ptr->publ.lock);
b_ptr->link_req = NULL;
b_ptr->publ.blocked = 1;
if (b_ptr->media->disable_bearer) {
spin_unlock_bh(&b_ptr->publ.lock);
write_unlock_bh(&tipc_net_lock);
b_ptr->media->disable_bearer(&b_ptr->publ);
write_lock_bh(&tipc_net_lock);
spin_lock_bh(&b_ptr->publ.lock);
}
list_for_each_entry_safe(l_ptr, temp_l_ptr, &b_ptr->links, link_list) {
tipc_link_delete(l_ptr);
}
spin_unlock_bh(&b_ptr->publ.lock);
memset(b_ptr, 0, sizeof(struct bearer));
return 0;
}
int tipc_disable_bearer(const char *name)
{
int res;
write_lock_bh(&tipc_net_lock);
res = bearer_disable(name);
write_unlock_bh(&tipc_net_lock);
return res;
}
void tipc_bearer_stop(void)
{
u32 i;
for (i = 0; i < MAX_BEARERS; i++) {
if (tipc_bearers[i].active)
tipc_bearers[i].publ.blocked = 1;
}
for (i = 0; i < MAX_BEARERS; i++) {
if (tipc_bearers[i].active)
bearer_disable(tipc_bearers[i].publ.name);
}
media_count = 0;
}

170
kernel/net/tipc/bearer.h Normal file
View File

@@ -0,0 +1,170 @@
/*
* net/tipc/bearer.h: Include file for TIPC bearer code
*
* Copyright (c) 1996-2006, Ericsson AB
* Copyright (c) 2005, Wind River Systems
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. 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.
*
* Alternatively, this software may be distributed under the terms of the
* GNU General Public License ("GPL") version 2 as published by the Free
* Software Foundation.
*
* 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_BEARER_H
#define _TIPC_BEARER_H
#include "core.h"
#include "bcast.h"
#define MAX_BEARERS 8
#define MAX_MEDIA 4
/**
* struct media - TIPC media information available to internal users
* @send_msg: routine which handles buffer transmission
* @enable_bearer: routine which enables a bearer
* @disable_bearer: routine which disables a bearer
* @addr2str: routine which converts bearer's address to string form
* @bcast_addr: media address used in broadcasting
* @bcast: non-zero if media supports broadcasting [currently mandatory]
* @priority: default link (and bearer) priority
* @tolerance: default time (in ms) before declaring link failure
* @window: default window (in packets) before declaring link congestion
* @type_id: TIPC media identifier [defined in tipc_bearer.h]
* @name: media name
*/
struct media {
int (*send_msg)(struct sk_buff *buf,
struct tipc_bearer *b_ptr,
struct tipc_media_addr *dest);
int (*enable_bearer)(struct tipc_bearer *b_ptr);
void (*disable_bearer)(struct tipc_bearer *b_ptr);
char *(*addr2str)(struct tipc_media_addr *a,
char *str_buf, int str_size);
struct tipc_media_addr bcast_addr;
int bcast;
u32 priority;
u32 tolerance;
u32 window;
u32 type_id;
char name[TIPC_MAX_MEDIA_NAME];
};
/**
* struct bearer - TIPC bearer information available to internal users
* @publ: bearer information available to privileged users
* @media: ptr to media structure associated with bearer
* @priority: default link priority for bearer
* @detect_scope: network address mask used during automatic link creation
* @identity: array index of this bearer within TIPC bearer array
* @link_req: ptr to (optional) structure making periodic link setup requests
* @links: list of non-congested links associated with bearer
* @cong_links: list of congested links associated with bearer
* @continue_count: # of times bearer has resumed after congestion or blocking
* @active: non-zero if bearer structure is represents a bearer
* @net_plane: network plane ('A' through 'H') currently associated with bearer
* @nodes: indicates which nodes in cluster can be reached through bearer
*/
struct bearer {
struct tipc_bearer publ;
struct media *media;
u32 priority;
u32 detect_scope;
u32 identity;
struct link_req *link_req;
struct list_head links;
struct list_head cong_links;
u32 continue_count;
int active;
char net_plane;
struct tipc_node_map nodes;
};
struct bearer_name {
char media_name[TIPC_MAX_MEDIA_NAME];
char if_name[TIPC_MAX_IF_NAME];
};
struct link;
extern struct bearer tipc_bearers[];
void tipc_media_addr_printf(struct print_buf *pb, struct tipc_media_addr *a);
struct sk_buff *tipc_media_get_names(void);
struct sk_buff *tipc_bearer_get_names(void);
void tipc_bearer_add_dest(struct bearer *b_ptr, u32 dest);
void tipc_bearer_remove_dest(struct bearer *b_ptr, u32 dest);
void tipc_bearer_schedule(struct bearer *b_ptr, struct link *l_ptr);
struct bearer *tipc_bearer_find_interface(const char *if_name);
int tipc_bearer_resolve_congestion(struct bearer *b_ptr, struct link *l_ptr);
int tipc_bearer_init(void);
void tipc_bearer_stop(void);
void tipc_bearer_lock_push(struct bearer *b_ptr);
/**
* tipc_bearer_send- sends buffer to destination over bearer
*
* Returns true (1) if successful, or false (0) if unable to send
*
* IMPORTANT:
* The media send routine must not alter the buffer being passed in
* as it may be needed for later retransmission!
*
* If the media send routine returns a non-zero value (indicating that
* it was unable to send the buffer), it must:
* 1) mark the bearer as blocked,
* 2) call tipc_continue() once the bearer is able to send again.
* Media types that are unable to meet these two critera must ensure their
* send routine always returns success -- even if the buffer was not sent --
* and let TIPC's link code deal with the undelivered message.
*/
static inline int tipc_bearer_send(struct bearer *b_ptr, struct sk_buff *buf,
struct tipc_media_addr *dest)
{
return !b_ptr->media->send_msg(buf, &b_ptr->publ, dest);
}
/**
* tipc_bearer_congested - determines if bearer is currently congested
*/
static inline int tipc_bearer_congested(struct bearer *b_ptr, struct link *l_ptr)
{
if (unlikely(b_ptr->publ.blocked))
return 1;
if (likely(list_empty(&b_ptr->cong_links)))
return 0;
return !tipc_bearer_resolve_congestion(b_ptr, l_ptr);
}
#endif

576
kernel/net/tipc/cluster.c Normal file
View File

@@ -0,0 +1,576 @@
/*
* net/tipc/cluster.c: TIPC cluster management routines
*
* Copyright (c) 2000-2006, Ericsson AB
* Copyright (c) 2005, Wind River Systems
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. 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.
*
* Alternatively, this software may be distributed under the terms of the
* GNU General Public License ("GPL") version 2 as published by the Free
* Software Foundation.
*
* 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 "cluster.h"
#include "addr.h"
#include "node_subscr.h"
#include "link.h"
#include "node.h"
#include "net.h"
#include "msg.h"
#include "bearer.h"
static void tipc_cltr_multicast(struct cluster *c_ptr, struct sk_buff *buf,
u32 lower, u32 upper);
static struct sk_buff *tipc_cltr_prepare_routing_msg(u32 data_size, u32 dest);
struct tipc_node **tipc_local_nodes = NULL;
struct tipc_node_map tipc_cltr_bcast_nodes = {0,{0,}};
u32 tipc_highest_allowed_slave = 0;
struct cluster *tipc_cltr_create(u32 addr)
{
struct _zone *z_ptr;
struct cluster *c_ptr;
int max_nodes;
c_ptr = kzalloc(sizeof(*c_ptr), GFP_ATOMIC);
if (c_ptr == NULL) {
warn("Cluster creation failure, no memory\n");
return NULL;
}
c_ptr->addr = tipc_addr(tipc_zone(addr), tipc_cluster(addr), 0);
if (in_own_cluster(addr))
max_nodes = LOWEST_SLAVE + tipc_max_slaves;
else
max_nodes = tipc_max_nodes + 1;
c_ptr->nodes = kcalloc(max_nodes + 1, sizeof(void*), GFP_ATOMIC);
if (c_ptr->nodes == NULL) {
warn("Cluster creation failure, no memory for node area\n");
kfree(c_ptr);
return NULL;
}
if (in_own_cluster(addr))
tipc_local_nodes = c_ptr->nodes;
c_ptr->highest_slave = LOWEST_SLAVE - 1;
c_ptr->highest_node = 0;
z_ptr = tipc_zone_find(tipc_zone(addr));
if (!z_ptr) {
z_ptr = tipc_zone_create(addr);
}
if (!z_ptr) {
kfree(c_ptr->nodes);
kfree(c_ptr);
return NULL;
}
tipc_zone_attach_cluster(z_ptr, c_ptr);
c_ptr->owner = z_ptr;
return c_ptr;
}
void tipc_cltr_delete(struct cluster *c_ptr)
{
u32 n_num;
if (!c_ptr)
return;
for (n_num = 1; n_num <= c_ptr->highest_node; n_num++) {
tipc_node_delete(c_ptr->nodes[n_num]);
}
for (n_num = LOWEST_SLAVE; n_num <= c_ptr->highest_slave; n_num++) {
tipc_node_delete(c_ptr->nodes[n_num]);
}
kfree(c_ptr->nodes);
kfree(c_ptr);
}
u32 tipc_cltr_next_node(struct cluster *c_ptr, u32 addr)
{
struct tipc_node *n_ptr;
u32 n_num = tipc_node(addr) + 1;
if (!c_ptr)
return addr;
for (; n_num <= c_ptr->highest_node; n_num++) {
n_ptr = c_ptr->nodes[n_num];
if (n_ptr && tipc_node_has_active_links(n_ptr))
return n_ptr->addr;
}
for (n_num = 1; n_num < tipc_node(addr); n_num++) {
n_ptr = c_ptr->nodes[n_num];
if (n_ptr && tipc_node_has_active_links(n_ptr))
return n_ptr->addr;
}
return 0;
}
void tipc_cltr_attach_node(struct cluster *c_ptr, struct tipc_node *n_ptr)
{
u32 n_num = tipc_node(n_ptr->addr);
u32 max_n_num = tipc_max_nodes;
if (in_own_cluster(n_ptr->addr))
max_n_num = tipc_highest_allowed_slave;
assert(n_num > 0);
assert(n_num <= max_n_num);
assert(c_ptr->nodes[n_num] == NULL);
c_ptr->nodes[n_num] = n_ptr;
if (n_num > c_ptr->highest_node)
c_ptr->highest_node = n_num;
}
/**
* tipc_cltr_select_router - select router to a cluster
*
* Uses deterministic and fair algorithm.
*/
u32 tipc_cltr_select_router(struct cluster *c_ptr, u32 ref)
{
u32 n_num;
u32 ulim = c_ptr->highest_node;
u32 mask;
u32 tstart;
assert(!in_own_cluster(c_ptr->addr));
if (!ulim)
return 0;
/* Start entry must be random */
mask = tipc_max_nodes;
while (mask > ulim)
mask >>= 1;
tstart = ref & mask;
n_num = tstart;
/* Lookup upwards with wrap-around */
do {
if (tipc_node_is_up(c_ptr->nodes[n_num]))
break;
} while (++n_num <= ulim);
if (n_num > ulim) {
n_num = 1;
do {
if (tipc_node_is_up(c_ptr->nodes[n_num]))
break;
} while (++n_num < tstart);
if (n_num == tstart)
return 0;
}
assert(n_num <= ulim);
return tipc_node_select_router(c_ptr->nodes[n_num], ref);
}
/**
* tipc_cltr_select_node - select destination node within a remote cluster
*
* Uses deterministic and fair algorithm.
*/
struct tipc_node *tipc_cltr_select_node(struct cluster *c_ptr, u32 selector)
{
u32 n_num;
u32 mask = tipc_max_nodes;
u32 start_entry;
assert(!in_own_cluster(c_ptr->addr));
if (!c_ptr->highest_node)
return NULL;
/* Start entry must be random */
while (mask > c_ptr->highest_node) {
mask >>= 1;
}
start_entry = (selector & mask) ? selector & mask : 1u;
assert(start_entry <= c_ptr->highest_node);
/* Lookup upwards with wrap-around */
for (n_num = start_entry; n_num <= c_ptr->highest_node; n_num++) {
if (tipc_node_has_active_links(c_ptr->nodes[n_num]))
return c_ptr->nodes[n_num];
}
for (n_num = 1; n_num < start_entry; n_num++) {
if (tipc_node_has_active_links(c_ptr->nodes[n_num]))
return c_ptr->nodes[n_num];
}
return NULL;
}
/*
* Routing table management: See description in node.c
*/
static struct sk_buff *tipc_cltr_prepare_routing_msg(u32 data_size, u32 dest)
{
u32 size = INT_H_SIZE + data_size;
struct sk_buff *buf = buf_acquire(size);
struct tipc_msg *msg;
if (buf) {
msg = buf_msg(buf);
memset((char *)msg, 0, size);
msg_init(msg, ROUTE_DISTRIBUTOR, 0, INT_H_SIZE, dest);
}
return buf;
}
void tipc_cltr_bcast_new_route(struct cluster *c_ptr, u32 dest,
u32 lower, u32 upper)
{
struct sk_buff *buf = tipc_cltr_prepare_routing_msg(0, c_ptr->addr);
struct tipc_msg *msg;
if (buf) {
msg = buf_msg(buf);
msg_set_remote_node(msg, dest);
msg_set_type(msg, ROUTE_ADDITION);
tipc_cltr_multicast(c_ptr, buf, lower, upper);
} else {
warn("Memory squeeze: broadcast of new route failed\n");
}
}
void tipc_cltr_bcast_lost_route(struct cluster *c_ptr, u32 dest,
u32 lower, u32 upper)
{
struct sk_buff *buf = tipc_cltr_prepare_routing_msg(0, c_ptr->addr);
struct tipc_msg *msg;
if (buf) {
msg = buf_msg(buf);
msg_set_remote_node(msg, dest);
msg_set_type(msg, ROUTE_REMOVAL);
tipc_cltr_multicast(c_ptr, buf, lower, upper);
} else {
warn("Memory squeeze: broadcast of lost route failed\n");
}
}
void tipc_cltr_send_slave_routes(struct cluster *c_ptr, u32 dest)
{
struct sk_buff *buf;
struct tipc_msg *msg;
u32 highest = c_ptr->highest_slave;
u32 n_num;
int send = 0;
assert(!is_slave(dest));
assert(in_own_cluster(dest));
assert(in_own_cluster(c_ptr->addr));
if (highest <= LOWEST_SLAVE)
return;
buf = tipc_cltr_prepare_routing_msg(highest - LOWEST_SLAVE + 1,
c_ptr->addr);
if (buf) {
msg = buf_msg(buf);
msg_set_remote_node(msg, c_ptr->addr);
msg_set_type(msg, SLAVE_ROUTING_TABLE);
for (n_num = LOWEST_SLAVE; n_num <= highest; n_num++) {
if (c_ptr->nodes[n_num] &&
tipc_node_has_active_links(c_ptr->nodes[n_num])) {
send = 1;
msg_set_dataoctet(msg, n_num);
}
}
if (send)
tipc_link_send(buf, dest, dest);
else
buf_discard(buf);
} else {
warn("Memory squeeze: broadcast of lost route failed\n");
}
}
void tipc_cltr_send_ext_routes(struct cluster *c_ptr, u32 dest)
{
struct sk_buff *buf;
struct tipc_msg *msg;
u32 highest = c_ptr->highest_node;
u32 n_num;
int send = 0;
if (in_own_cluster(c_ptr->addr))
return;
assert(!is_slave(dest));
assert(in_own_cluster(dest));
highest = c_ptr->highest_node;
buf = tipc_cltr_prepare_routing_msg(highest + 1, c_ptr->addr);
if (buf) {
msg = buf_msg(buf);
msg_set_remote_node(msg, c_ptr->addr);
msg_set_type(msg, EXT_ROUTING_TABLE);
for (n_num = 1; n_num <= highest; n_num++) {
if (c_ptr->nodes[n_num] &&
tipc_node_has_active_links(c_ptr->nodes[n_num])) {
send = 1;
msg_set_dataoctet(msg, n_num);
}
}
if (send)
tipc_link_send(buf, dest, dest);
else
buf_discard(buf);
} else {
warn("Memory squeeze: broadcast of external route failed\n");
}
}
void tipc_cltr_send_local_routes(struct cluster *c_ptr, u32 dest)
{
struct sk_buff *buf;
struct tipc_msg *msg;
u32 highest = c_ptr->highest_node;
u32 n_num;
int send = 0;
assert(is_slave(dest));
assert(in_own_cluster(c_ptr->addr));
buf = tipc_cltr_prepare_routing_msg(highest, c_ptr->addr);
if (buf) {
msg = buf_msg(buf);
msg_set_remote_node(msg, c_ptr->addr);
msg_set_type(msg, LOCAL_ROUTING_TABLE);
for (n_num = 1; n_num <= highest; n_num++) {
if (c_ptr->nodes[n_num] &&
tipc_node_has_active_links(c_ptr->nodes[n_num])) {
send = 1;
msg_set_dataoctet(msg, n_num);
}
}
if (send)
tipc_link_send(buf, dest, dest);
else
buf_discard(buf);
} else {
warn("Memory squeeze: broadcast of local route failed\n");
}
}
void tipc_cltr_recv_routing_table(struct sk_buff *buf)
{
struct tipc_msg *msg = buf_msg(buf);
struct cluster *c_ptr;
struct tipc_node *n_ptr;
unchar *node_table;
u32 table_size;
u32 router;
u32 rem_node = msg_remote_node(msg);
u32 z_num;
u32 c_num;
u32 n_num;
c_ptr = tipc_cltr_find(rem_node);
if (!c_ptr) {
c_ptr = tipc_cltr_create(rem_node);
if (!c_ptr) {
buf_discard(buf);
return;
}
}
node_table = buf->data + msg_hdr_sz(msg);
table_size = msg_size(msg) - msg_hdr_sz(msg);
router = msg_prevnode(msg);
z_num = tipc_zone(rem_node);
c_num = tipc_cluster(rem_node);
switch (msg_type(msg)) {
case LOCAL_ROUTING_TABLE:
assert(is_slave(tipc_own_addr));
case EXT_ROUTING_TABLE:
for (n_num = 1; n_num < table_size; n_num++) {
if (node_table[n_num]) {
u32 addr = tipc_addr(z_num, c_num, n_num);
n_ptr = c_ptr->nodes[n_num];
if (!n_ptr) {
n_ptr = tipc_node_create(addr);
}
if (n_ptr)
tipc_node_add_router(n_ptr, router);
}
}
break;
case SLAVE_ROUTING_TABLE:
assert(!is_slave(tipc_own_addr));
assert(in_own_cluster(c_ptr->addr));
for (n_num = 1; n_num < table_size; n_num++) {
if (node_table[n_num]) {
u32 slave_num = n_num + LOWEST_SLAVE;
u32 addr = tipc_addr(z_num, c_num, slave_num);
n_ptr = c_ptr->nodes[slave_num];
if (!n_ptr) {
n_ptr = tipc_node_create(addr);
}
if (n_ptr)
tipc_node_add_router(n_ptr, router);
}
}
break;
case ROUTE_ADDITION:
if (!is_slave(tipc_own_addr)) {
assert(!in_own_cluster(c_ptr->addr)
|| is_slave(rem_node));
} else {
assert(in_own_cluster(c_ptr->addr)
&& !is_slave(rem_node));
}
n_ptr = c_ptr->nodes[tipc_node(rem_node)];
if (!n_ptr)
n_ptr = tipc_node_create(rem_node);
if (n_ptr)
tipc_node_add_router(n_ptr, router);
break;
case ROUTE_REMOVAL:
if (!is_slave(tipc_own_addr)) {
assert(!in_own_cluster(c_ptr->addr)
|| is_slave(rem_node));
} else {
assert(in_own_cluster(c_ptr->addr)
&& !is_slave(rem_node));
}
n_ptr = c_ptr->nodes[tipc_node(rem_node)];
if (n_ptr)
tipc_node_remove_router(n_ptr, router);
break;
default:
assert(!"Illegal routing manager message received\n");
}
buf_discard(buf);
}
void tipc_cltr_remove_as_router(struct cluster *c_ptr, u32 router)
{
u32 start_entry;
u32 tstop;
u32 n_num;
if (is_slave(router))
return; /* Slave nodes can not be routers */
if (in_own_cluster(c_ptr->addr)) {
start_entry = LOWEST_SLAVE;
tstop = c_ptr->highest_slave;
} else {
start_entry = 1;
tstop = c_ptr->highest_node;
}
for (n_num = start_entry; n_num <= tstop; n_num++) {
if (c_ptr->nodes[n_num]) {
tipc_node_remove_router(c_ptr->nodes[n_num], router);
}
}
}
/**
* tipc_cltr_multicast - multicast message to local nodes
*/
static void tipc_cltr_multicast(struct cluster *c_ptr, struct sk_buff *buf,
u32 lower, u32 upper)
{
struct sk_buff *buf_copy;
struct tipc_node *n_ptr;
u32 n_num;
u32 tstop;
assert(lower <= upper);
assert(((lower >= 1) && (lower <= tipc_max_nodes)) ||
((lower >= LOWEST_SLAVE) && (lower <= tipc_highest_allowed_slave)));
assert(((upper >= 1) && (upper <= tipc_max_nodes)) ||
((upper >= LOWEST_SLAVE) && (upper <= tipc_highest_allowed_slave)));
assert(in_own_cluster(c_ptr->addr));
tstop = is_slave(upper) ? c_ptr->highest_slave : c_ptr->highest_node;
if (tstop > upper)
tstop = upper;
for (n_num = lower; n_num <= tstop; n_num++) {
n_ptr = c_ptr->nodes[n_num];
if (n_ptr && tipc_node_has_active_links(n_ptr)) {
buf_copy = skb_copy(buf, GFP_ATOMIC);
if (buf_copy == NULL)
break;
msg_set_destnode(buf_msg(buf_copy), n_ptr->addr);
tipc_link_send(buf_copy, n_ptr->addr, n_ptr->addr);
}
}
buf_discard(buf);
}
/**
* tipc_cltr_broadcast - broadcast message to all nodes within cluster
*/
void tipc_cltr_broadcast(struct sk_buff *buf)
{
struct sk_buff *buf_copy;
struct cluster *c_ptr;
struct tipc_node *n_ptr;
u32 n_num;
u32 tstart;
u32 tstop;
u32 node_type;
if (tipc_mode == TIPC_NET_MODE) {
c_ptr = tipc_cltr_find(tipc_own_addr);
assert(in_own_cluster(c_ptr->addr)); /* For now */
/* Send to standard nodes, then repeat loop sending to slaves */
tstart = 1;
tstop = c_ptr->highest_node;
for (node_type = 1; node_type <= 2; node_type++) {
for (n_num = tstart; n_num <= tstop; n_num++) {
n_ptr = c_ptr->nodes[n_num];
if (n_ptr && tipc_node_has_active_links(n_ptr)) {
buf_copy = skb_copy(buf, GFP_ATOMIC);
if (buf_copy == NULL)
goto exit;
msg_set_destnode(buf_msg(buf_copy),
n_ptr->addr);
tipc_link_send(buf_copy, n_ptr->addr,
n_ptr->addr);
}
}
tstart = LOWEST_SLAVE;
tstop = c_ptr->highest_slave;
}
}
exit:
buf_discard(buf);
}
int tipc_cltr_init(void)
{
tipc_highest_allowed_slave = LOWEST_SLAVE + tipc_max_slaves;
return tipc_cltr_create(tipc_own_addr) ? 0 : -ENOMEM;
}

92
kernel/net/tipc/cluster.h Normal file
View File

@@ -0,0 +1,92 @@
/*
* net/tipc/cluster.h: Include file for TIPC cluster management routines
*
* Copyright (c) 2000-2006, Ericsson AB
* Copyright (c) 2005, Wind River Systems
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. 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.
*
* Alternatively, this software may be distributed under the terms of the
* GNU General Public License ("GPL") version 2 as published by the Free
* Software Foundation.
*
* 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_CLUSTER_H
#define _TIPC_CLUSTER_H
#include "addr.h"
#include "zone.h"
#define LOWEST_SLAVE 2048u
/**
* struct cluster - TIPC cluster structure
* @addr: network address of cluster
* @owner: pointer to zone that cluster belongs to
* @nodes: array of pointers to all nodes within cluster
* @highest_node: id of highest numbered node within cluster
* @highest_slave: (used for secondary node support)
*/
struct cluster {
u32 addr;
struct _zone *owner;
struct tipc_node **nodes;
u32 highest_node;
u32 highest_slave;
};
extern struct tipc_node **tipc_local_nodes;
extern u32 tipc_highest_allowed_slave;
extern struct tipc_node_map tipc_cltr_bcast_nodes;
void tipc_cltr_remove_as_router(struct cluster *c_ptr, u32 router);
void tipc_cltr_send_ext_routes(struct cluster *c_ptr, u32 dest);
struct tipc_node *tipc_cltr_select_node(struct cluster *c_ptr, u32 selector);
u32 tipc_cltr_select_router(struct cluster *c_ptr, u32 ref);
void tipc_cltr_recv_routing_table(struct sk_buff *buf);
struct cluster *tipc_cltr_create(u32 addr);
void tipc_cltr_delete(struct cluster *c_ptr);
void tipc_cltr_attach_node(struct cluster *c_ptr, struct tipc_node *n_ptr);
void tipc_cltr_send_slave_routes(struct cluster *c_ptr, u32 dest);
void tipc_cltr_broadcast(struct sk_buff *buf);
int tipc_cltr_init(void);
u32 tipc_cltr_next_node(struct cluster *c_ptr, u32 addr);
void tipc_cltr_bcast_new_route(struct cluster *c_ptr, u32 dest, u32 lo, u32 hi);
void tipc_cltr_send_local_routes(struct cluster *c_ptr, u32 dest);
void tipc_cltr_bcast_lost_route(struct cluster *c_ptr, u32 dest, u32 lo, u32 hi);
static inline struct cluster *tipc_cltr_find(u32 addr)
{
struct _zone *z_ptr = tipc_zone_find(addr);
if (z_ptr)
return z_ptr->clusters[1];
return NULL;
}
#endif

705
kernel/net/tipc/config.c Normal file
View File

@@ -0,0 +1,705 @@
/*
* net/tipc/config.c: TIPC configuration management code
*
* Copyright (c) 2002-2006, Ericsson AB
* Copyright (c) 2004-2007, Wind River Systems
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. 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.
*
* Alternatively, this software may be distributed under the terms of the
* GNU General Public License ("GPL") version 2 as published by the Free
* Software Foundation.
*
* 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 "bearer.h"
#include "port.h"
#include "link.h"
#include "zone.h"
#include "addr.h"
#include "name_table.h"
#include "node.h"
#include "config.h"
#include "discover.h"
struct subscr_data {
char usr_handle[8];
u32 domain;
u32 port_ref;
struct list_head subd_list;
};
struct manager {
u32 user_ref;
u32 port_ref;
u32 subscr_ref;
u32 link_subscriptions;
struct list_head link_subscribers;
};
static struct manager mng = { 0};
static DEFINE_SPINLOCK(config_lock);
static const void *req_tlv_area; /* request message TLV area */
static int req_tlv_space; /* request message TLV area size */
static int rep_headroom; /* reply message headroom to use */
void tipc_cfg_link_event(u32 addr, char *name, int up)
{
/* TIPC DOESN'T HANDLE LINK EVENT SUBSCRIPTIONS AT THE MOMENT */
}
struct sk_buff *tipc_cfg_reply_alloc(int payload_size)
{
struct sk_buff *buf;
buf = alloc_skb(rep_headroom + payload_size, GFP_ATOMIC);
if (buf)
skb_reserve(buf, rep_headroom);
return buf;
}
int tipc_cfg_append_tlv(struct sk_buff *buf, int tlv_type,
void *tlv_data, int tlv_data_size)
{
struct tlv_desc *tlv = (struct tlv_desc *)skb_tail_pointer(buf);
int new_tlv_space = TLV_SPACE(tlv_data_size);
if (skb_tailroom(buf) < new_tlv_space) {
dbg("tipc_cfg_append_tlv unable to append TLV\n");
return 0;
}
skb_put(buf, new_tlv_space);
tlv->tlv_type = htons(tlv_type);
tlv->tlv_len = htons(TLV_LENGTH(tlv_data_size));
if (tlv_data_size && tlv_data)
memcpy(TLV_DATA(tlv), tlv_data, tlv_data_size);
return 1;
}
struct sk_buff *tipc_cfg_reply_unsigned_type(u16 tlv_type, u32 value)
{
struct sk_buff *buf;
__be32 value_net;
buf = tipc_cfg_reply_alloc(TLV_SPACE(sizeof(value)));
if (buf) {
value_net = htonl(value);
tipc_cfg_append_tlv(buf, tlv_type, &value_net,
sizeof(value_net));
}
return buf;
}
struct sk_buff *tipc_cfg_reply_string_type(u16 tlv_type, char *string)
{
struct sk_buff *buf;
int string_len = strlen(string) + 1;
buf = tipc_cfg_reply_alloc(TLV_SPACE(string_len));
if (buf)
tipc_cfg_append_tlv(buf, tlv_type, string, string_len);
return buf;
}
#if 0
/* Now obsolete code for handling commands not yet implemented the new way */
int tipc_cfg_cmd(const struct tipc_cmd_msg * msg,
char *data,
u32 sz,
u32 *ret_size,
struct tipc_portid *orig)
{
int rv = -EINVAL;
u32 cmd = msg->cmd;
*ret_size = 0;
switch (cmd) {
case TIPC_REMOVE_LINK:
case TIPC_CMD_BLOCK_LINK:
case TIPC_CMD_UNBLOCK_LINK:
if (!cfg_check_connection(orig))
rv = link_control(msg->argv.link_name, msg->cmd, 0);
break;
case TIPC_ESTABLISH:
{
int connected;
tipc_isconnected(mng.conn_port_ref, &connected);
if (connected || !orig) {
rv = TIPC_FAILURE;
break;
}
rv = tipc_connect2port(mng.conn_port_ref, orig);
if (rv == TIPC_OK)
orig = 0;
break;
}
case TIPC_GET_PEER_ADDRESS:
*ret_size = link_peer_addr(msg->argv.link_name, data, sz);
break;
case TIPC_GET_ROUTES:
rv = TIPC_OK;
break;
default: {}
}
if (*ret_size)
rv = TIPC_OK;
return rv;
}
static void cfg_cmd_event(struct tipc_cmd_msg *msg,
char *data,
u32 sz,
struct tipc_portid const *orig)
{
int rv = -EINVAL;
struct tipc_cmd_result_msg rmsg;
struct iovec msg_sect[2];
int *arg;
msg->cmd = ntohl(msg->cmd);
cfg_prepare_res_msg(msg->cmd, msg->usr_handle, rv, &rmsg, msg_sect,
data, 0);
if (ntohl(msg->magic) != TIPC_MAGIC)
goto exit;
switch (msg->cmd) {
case TIPC_CREATE_LINK:
if (!cfg_check_connection(orig))
rv = disc_create_link(&msg->argv.create_link);
break;
case TIPC_LINK_SUBSCRIBE:
{
struct subscr_data *sub;
if (mng.link_subscriptions > 64)
break;
sub = kmalloc(sizeof(*sub),
GFP_ATOMIC);
if (sub == NULL) {
warn("Memory squeeze; dropped remote link subscription\n");
break;
}
INIT_LIST_HEAD(&sub->subd_list);
tipc_createport(mng.user_ref,
(void *)sub,
TIPC_HIGH_IMPORTANCE,
0,
0,
(tipc_conn_shutdown_event)cfg_linksubscr_cancel,
0,
0,
(tipc_conn_msg_event)cfg_linksubscr_cancel,
0,
&sub->port_ref);
if (!sub->port_ref) {
kfree(sub);
break;
}
memcpy(sub->usr_handle,msg->usr_handle,
sizeof(sub->usr_handle));
sub->domain = msg->argv.domain;
list_add_tail(&sub->subd_list, &mng.link_subscribers);
tipc_connect2port(sub->port_ref, orig);
rmsg.retval = TIPC_OK;
tipc_send(sub->port_ref, 2u, msg_sect);
mng.link_subscriptions++;
return;
}
default:
rv = tipc_cfg_cmd(msg, data, sz, (u32 *)&msg_sect[1].iov_len, orig);
}
exit:
rmsg.result_len = htonl(msg_sect[1].iov_len);
rmsg.retval = htonl(rv);
tipc_cfg_respond(msg_sect, 2u, orig);
}
#endif
static struct sk_buff *cfg_enable_bearer(void)
{
struct tipc_bearer_config *args;
if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_BEARER_CONFIG))
return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
args = (struct tipc_bearer_config *)TLV_DATA(req_tlv_area);
if (tipc_enable_bearer(args->name,
ntohl(args->detect_scope),
ntohl(args->priority)))
return tipc_cfg_reply_error_string("unable to enable bearer");
return tipc_cfg_reply_none();
}
static struct sk_buff *cfg_disable_bearer(void)
{
if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_BEARER_NAME))
return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
if (tipc_disable_bearer((char *)TLV_DATA(req_tlv_area)))
return tipc_cfg_reply_error_string("unable to disable bearer");
return tipc_cfg_reply_none();
}
static struct sk_buff *cfg_set_own_addr(void)
{
u32 addr;
if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_NET_ADDR))
return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
addr = ntohl(*(__be32 *)TLV_DATA(req_tlv_area));
if (addr == tipc_own_addr)
return tipc_cfg_reply_none();
if (!tipc_addr_node_valid(addr))
return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
" (node address)");
if (tipc_mode == TIPC_NET_MODE)
return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
" (cannot change node address once assigned)");
/*
* Must release all spinlocks before calling start_net() because
* Linux version of TIPC calls eth_media_start() which calls
* register_netdevice_notifier() which may block!
*
* Temporarily releasing the lock should be harmless for non-Linux TIPC,
* but Linux version of eth_media_start() should really be reworked
* so that it can be called with spinlocks held.
*/
spin_unlock_bh(&config_lock);
tipc_core_start_net(addr);
spin_lock_bh(&config_lock);
return tipc_cfg_reply_none();
}
static struct sk_buff *cfg_set_remote_mng(void)
{
u32 value;
if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area));
tipc_remote_management = (value != 0);
return tipc_cfg_reply_none();
}
static struct sk_buff *cfg_set_max_publications(void)
{
u32 value;
if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area));
if (value != delimit(value, 1, 65535))
return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
" (max publications must be 1-65535)");
tipc_max_publications = value;
return tipc_cfg_reply_none();
}
static struct sk_buff *cfg_set_max_subscriptions(void)
{
u32 value;
if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area));
if (value != delimit(value, 1, 65535))
return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
" (max subscriptions must be 1-65535");
tipc_max_subscriptions = value;
return tipc_cfg_reply_none();
}
static struct sk_buff *cfg_set_max_ports(void)
{
u32 value;
if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area));
if (value == tipc_max_ports)
return tipc_cfg_reply_none();
if (value != delimit(value, 127, 65535))
return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
" (max ports must be 127-65535)");
if (tipc_mode != TIPC_NOT_RUNNING)
return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
" (cannot change max ports while TIPC is active)");
tipc_max_ports = value;
return tipc_cfg_reply_none();
}
static struct sk_buff *cfg_set_max_zones(void)
{
u32 value;
if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area));
if (value == tipc_max_zones)
return tipc_cfg_reply_none();
if (value != delimit(value, 1, 255))
return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
" (max zones must be 1-255)");
if (tipc_mode == TIPC_NET_MODE)
return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
" (cannot change max zones once TIPC has joined a network)");
tipc_max_zones = value;
return tipc_cfg_reply_none();
}
static struct sk_buff *cfg_set_max_clusters(void)
{
u32 value;
if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area));
if (value != delimit(value, 1, 1))
return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
" (max clusters fixed at 1)");
return tipc_cfg_reply_none();
}
static struct sk_buff *cfg_set_max_nodes(void)
{
u32 value;
if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area));
if (value == tipc_max_nodes)
return tipc_cfg_reply_none();
if (value != delimit(value, 8, 2047))
return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
" (max nodes must be 8-2047)");
if (tipc_mode == TIPC_NET_MODE)
return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
" (cannot change max nodes once TIPC has joined a network)");
tipc_max_nodes = value;
return tipc_cfg_reply_none();
}
static struct sk_buff *cfg_set_max_slaves(void)
{
u32 value;
if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area));
if (value != 0)
return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
" (max secondary nodes fixed at 0)");
return tipc_cfg_reply_none();
}
static struct sk_buff *cfg_set_netid(void)
{
u32 value;
if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area));
if (value == tipc_net_id)
return tipc_cfg_reply_none();
if (value != delimit(value, 1, 9999))
return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
" (network id must be 1-9999)");
if (tipc_mode == TIPC_NET_MODE)
return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
" (cannot change network id once TIPC has joined a network)");
tipc_net_id = value;
return tipc_cfg_reply_none();
}
struct sk_buff *tipc_cfg_do_cmd(u32 orig_node, u16 cmd, const void *request_area,
int request_space, int reply_headroom)
{
struct sk_buff *rep_tlv_buf;
spin_lock_bh(&config_lock);
/* Save request and reply details in a well-known location */
req_tlv_area = request_area;
req_tlv_space = request_space;
rep_headroom = reply_headroom;
/* Check command authorization */
if (likely(orig_node == tipc_own_addr)) {
/* command is permitted */
} else if (cmd >= 0x8000) {
rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
" (cannot be done remotely)");
goto exit;
} else if (!tipc_remote_management) {
rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NO_REMOTE);
goto exit;
}
else if (cmd >= 0x4000) {
u32 domain = 0;
if ((tipc_nametbl_translate(TIPC_ZM_SRV, 0, &domain) == 0) ||
(domain != orig_node)) {
rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NOT_ZONE_MSTR);
goto exit;
}
}
/* Call appropriate processing routine */
switch (cmd) {
case TIPC_CMD_NOOP:
rep_tlv_buf = tipc_cfg_reply_none();
break;
case TIPC_CMD_GET_NODES:
rep_tlv_buf = tipc_node_get_nodes(req_tlv_area, req_tlv_space);
break;
case TIPC_CMD_GET_LINKS:
rep_tlv_buf = tipc_node_get_links(req_tlv_area, req_tlv_space);
break;
case TIPC_CMD_SHOW_LINK_STATS:
rep_tlv_buf = tipc_link_cmd_show_stats(req_tlv_area, req_tlv_space);
break;
case TIPC_CMD_RESET_LINK_STATS:
rep_tlv_buf = tipc_link_cmd_reset_stats(req_tlv_area, req_tlv_space);
break;
case TIPC_CMD_SHOW_NAME_TABLE:
rep_tlv_buf = tipc_nametbl_get(req_tlv_area, req_tlv_space);
break;
case TIPC_CMD_GET_BEARER_NAMES:
rep_tlv_buf = tipc_bearer_get_names();
break;
case TIPC_CMD_GET_MEDIA_NAMES:
rep_tlv_buf = tipc_media_get_names();
break;
case TIPC_CMD_SHOW_PORTS:
rep_tlv_buf = tipc_port_get_ports();
break;
#if 0
case TIPC_CMD_SHOW_PORT_STATS:
rep_tlv_buf = port_show_stats(req_tlv_area, req_tlv_space);
break;
case TIPC_CMD_RESET_PORT_STATS:
rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED);
break;
#endif
case TIPC_CMD_SET_LOG_SIZE:
rep_tlv_buf = tipc_log_resize_cmd(req_tlv_area, req_tlv_space);
break;
case TIPC_CMD_DUMP_LOG:
rep_tlv_buf = tipc_log_dump();
break;
case TIPC_CMD_SET_LINK_TOL:
case TIPC_CMD_SET_LINK_PRI:
case TIPC_CMD_SET_LINK_WINDOW:
rep_tlv_buf = tipc_link_cmd_config(req_tlv_area, req_tlv_space, cmd);
break;
case TIPC_CMD_ENABLE_BEARER:
rep_tlv_buf = cfg_enable_bearer();
break;
case TIPC_CMD_DISABLE_BEARER:
rep_tlv_buf = cfg_disable_bearer();
break;
case TIPC_CMD_SET_NODE_ADDR:
rep_tlv_buf = cfg_set_own_addr();
break;
case TIPC_CMD_SET_REMOTE_MNG:
rep_tlv_buf = cfg_set_remote_mng();
break;
case TIPC_CMD_SET_MAX_PORTS:
rep_tlv_buf = cfg_set_max_ports();
break;
case TIPC_CMD_SET_MAX_PUBL:
rep_tlv_buf = cfg_set_max_publications();
break;
case TIPC_CMD_SET_MAX_SUBSCR:
rep_tlv_buf = cfg_set_max_subscriptions();
break;
case TIPC_CMD_SET_MAX_ZONES:
rep_tlv_buf = cfg_set_max_zones();
break;
case TIPC_CMD_SET_MAX_CLUSTERS:
rep_tlv_buf = cfg_set_max_clusters();
break;
case TIPC_CMD_SET_MAX_NODES:
rep_tlv_buf = cfg_set_max_nodes();
break;
case TIPC_CMD_SET_MAX_SLAVES:
rep_tlv_buf = cfg_set_max_slaves();
break;
case TIPC_CMD_SET_NETID:
rep_tlv_buf = cfg_set_netid();
break;
case TIPC_CMD_GET_REMOTE_MNG:
rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_remote_management);
break;
case TIPC_CMD_GET_MAX_PORTS:
rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_max_ports);
break;
case TIPC_CMD_GET_MAX_PUBL:
rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_max_publications);
break;
case TIPC_CMD_GET_MAX_SUBSCR:
rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_max_subscriptions);
break;
case TIPC_CMD_GET_MAX_ZONES:
rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_max_zones);
break;
case TIPC_CMD_GET_MAX_CLUSTERS:
rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_max_clusters);
break;
case TIPC_CMD_GET_MAX_NODES:
rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_max_nodes);
break;
case TIPC_CMD_GET_MAX_SLAVES:
rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_max_slaves);
break;
case TIPC_CMD_GET_NETID:
rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_net_id);
break;
case TIPC_CMD_NOT_NET_ADMIN:
rep_tlv_buf =
tipc_cfg_reply_error_string(TIPC_CFG_NOT_NET_ADMIN);
break;
default:
rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
" (unknown command)");
break;
}
/* Return reply buffer */
exit:
spin_unlock_bh(&config_lock);
return rep_tlv_buf;
}
static void cfg_named_msg_event(void *userdata,
u32 port_ref,
struct sk_buff **buf,
const unchar *msg,
u32 size,
u32 importance,
struct tipc_portid const *orig,
struct tipc_name_seq const *dest)
{
struct tipc_cfg_msg_hdr *req_hdr;
struct tipc_cfg_msg_hdr *rep_hdr;
struct sk_buff *rep_buf;
/* Validate configuration message header (ignore invalid message) */
req_hdr = (struct tipc_cfg_msg_hdr *)msg;
if ((size < sizeof(*req_hdr)) ||
(size != TCM_ALIGN(ntohl(req_hdr->tcm_len))) ||
(ntohs(req_hdr->tcm_flags) != TCM_F_REQUEST)) {
warn("Invalid configuration message discarded\n");
return;
}
/* Generate reply for request (if can't, return request) */
rep_buf = tipc_cfg_do_cmd(orig->node,
ntohs(req_hdr->tcm_type),
msg + sizeof(*req_hdr),
size - sizeof(*req_hdr),
BUF_HEADROOM + MAX_H_SIZE + sizeof(*rep_hdr));
if (rep_buf) {
skb_push(rep_buf, sizeof(*rep_hdr));
rep_hdr = (struct tipc_cfg_msg_hdr *)rep_buf->data;
memcpy(rep_hdr, req_hdr, sizeof(*rep_hdr));
rep_hdr->tcm_len = htonl(rep_buf->len);
rep_hdr->tcm_flags &= htons(~TCM_F_REQUEST);
} else {
rep_buf = *buf;
*buf = NULL;
}
/* NEED TO ADD CODE TO HANDLE FAILED SEND (SUCH AS CONGESTION) */
tipc_send_buf2port(port_ref, orig, rep_buf, rep_buf->len);
}
int tipc_cfg_init(void)
{
struct tipc_name_seq seq;
int res;
memset(&mng, 0, sizeof(mng));
INIT_LIST_HEAD(&mng.link_subscribers);
res = tipc_attach(&mng.user_ref, NULL, NULL);
if (res)
goto failed;
res = tipc_createport(mng.user_ref, NULL, TIPC_CRITICAL_IMPORTANCE,
NULL, NULL, NULL,
NULL, cfg_named_msg_event, NULL,
NULL, &mng.port_ref);
if (res)
goto failed;
seq.type = TIPC_CFG_SRV;
seq.lower = seq.upper = tipc_own_addr;
res = tipc_nametbl_publish_rsv(mng.port_ref, TIPC_ZONE_SCOPE, &seq);
if (res)
goto failed;
return 0;
failed:
err("Unable to create configuration service\n");
tipc_detach(mng.user_ref);
mng.user_ref = 0;
return res;
}
void tipc_cfg_stop(void)
{
if (mng.user_ref) {
tipc_detach(mng.user_ref);
mng.user_ref = 0;
}
}

79
kernel/net/tipc/config.h Normal file
View File

@@ -0,0 +1,79 @@
/*
* net/tipc/config.h: Include file for TIPC configuration service code
*
* Copyright (c) 2003-2006, Ericsson AB
* Copyright (c) 2005, Wind River Systems
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. 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.
*
* Alternatively, this software may be distributed under the terms of the
* GNU General Public License ("GPL") version 2 as published by the Free
* Software Foundation.
*
* 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_CONFIG_H
#define _TIPC_CONFIG_H
/* ---------------------------------------------------------------------- */
#include "core.h"
#include "link.h"
struct sk_buff *tipc_cfg_reply_alloc(int payload_size);
int tipc_cfg_append_tlv(struct sk_buff *buf, int tlv_type,
void *tlv_data, int tlv_data_size);
struct sk_buff *tipc_cfg_reply_unsigned_type(u16 tlv_type, u32 value);
struct sk_buff *tipc_cfg_reply_string_type(u16 tlv_type, char *string);
static inline struct sk_buff *tipc_cfg_reply_none(void)
{
return tipc_cfg_reply_alloc(0);
}
static inline struct sk_buff *tipc_cfg_reply_unsigned(u32 value)
{
return tipc_cfg_reply_unsigned_type(TIPC_TLV_UNSIGNED, value);
}
static inline struct sk_buff *tipc_cfg_reply_error_string(char *string)
{
return tipc_cfg_reply_string_type(TIPC_TLV_ERROR_STRING, string);
}
static inline struct sk_buff *tipc_cfg_reply_ultra_string(char *string)
{
return tipc_cfg_reply_string_type(TIPC_TLV_ULTRA_STRING, string);
}
struct sk_buff *tipc_cfg_do_cmd(u32 orig_node, u16 cmd,
const void *req_tlv_area, int req_tlv_space,
int headroom);
void tipc_cfg_link_event(u32 addr, char *name, int up);
int tipc_cfg_init(void);
void tipc_cfg_stop(void);
#endif

276
kernel/net/tipc/core.c Normal file
View File

@@ -0,0 +1,276 @@
/*
* net/tipc/core.c: TIPC module code
*
* Copyright (c) 2003-2006, Ericsson AB
* Copyright (c) 2005-2006, Wind River Systems
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. 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.
*
* Alternatively, this software may be distributed under the terms of the
* GNU General Public License ("GPL") version 2 as published by the Free
* Software Foundation.
*
* 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 <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/random.h>
#include "core.h"
#include "dbg.h"
#include "ref.h"
#include "net.h"
#include "user_reg.h"
#include "name_table.h"
#include "subscr.h"
#include "config.h"
#define TIPC_MOD_VER "1.6.4"
#ifndef CONFIG_TIPC_ZONES
#define CONFIG_TIPC_ZONES 3
#endif
#ifndef CONFIG_TIPC_CLUSTERS
#define CONFIG_TIPC_CLUSTERS 1
#endif
#ifndef CONFIG_TIPC_NODES
#define CONFIG_TIPC_NODES 255
#endif
#ifndef CONFIG_TIPC_SLAVE_NODES
#define CONFIG_TIPC_SLAVE_NODES 0
#endif
#ifndef CONFIG_TIPC_PORTS
#define CONFIG_TIPC_PORTS 8191
#endif
#ifndef CONFIG_TIPC_LOG
#define CONFIG_TIPC_LOG 0
#endif
/* global variables used by multiple sub-systems within TIPC */
int tipc_mode = TIPC_NOT_RUNNING;
int tipc_random;
atomic_t tipc_user_count = ATOMIC_INIT(0);
const char tipc_alphabet[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_.";
/* configurable TIPC parameters */
u32 tipc_own_addr;
int tipc_max_zones;
int tipc_max_clusters;
int tipc_max_nodes;
int tipc_max_slaves;
int tipc_max_ports;
int tipc_max_subscriptions;
int tipc_max_publications;
int tipc_net_id;
int tipc_remote_management;
int tipc_get_mode(void)
{
return tipc_mode;
}
/**
* tipc_core_stop_net - shut down TIPC networking sub-systems
*/
void tipc_core_stop_net(void)
{
tipc_eth_media_stop();
tipc_net_stop();
}
/**
* start_net - start TIPC networking sub-systems
*/
int tipc_core_start_net(unsigned long addr)
{
int res;
if ((res = tipc_net_start(addr)) ||
(res = tipc_eth_media_start())) {
tipc_core_stop_net();
}
return res;
}
/**
* tipc_core_stop - switch TIPC from SINGLE NODE to NOT RUNNING mode
*/
void tipc_core_stop(void)
{
if (tipc_mode != TIPC_NODE_MODE)
return;
tipc_mode = TIPC_NOT_RUNNING;
tipc_netlink_stop();
tipc_handler_stop();
tipc_cfg_stop();
tipc_subscr_stop();
tipc_reg_stop();
tipc_nametbl_stop();
tipc_ref_table_stop();
tipc_socket_stop();
}
/**
* tipc_core_start - switch TIPC from NOT RUNNING to SINGLE NODE mode
*/
int tipc_core_start(void)
{
int res;
if (tipc_mode != TIPC_NOT_RUNNING)
return -ENOPROTOOPT;
get_random_bytes(&tipc_random, sizeof(tipc_random));
tipc_mode = TIPC_NODE_MODE;
if ((res = tipc_handler_start()) ||
(res = tipc_ref_table_init(tipc_max_ports, tipc_random)) ||
(res = tipc_reg_start()) ||
(res = tipc_nametbl_init()) ||
(res = tipc_k_signal((Handler)tipc_subscr_start, 0)) ||
(res = tipc_k_signal((Handler)tipc_cfg_init, 0)) ||
(res = tipc_netlink_start()) ||
(res = tipc_socket_init())) {
tipc_core_stop();
}
return res;
}
static int __init tipc_init(void)
{
int res;
tipc_log_resize(CONFIG_TIPC_LOG);
info("Activated (version " TIPC_MOD_VER
" compiled " __DATE__ " " __TIME__ ")\n");
tipc_own_addr = 0;
tipc_remote_management = 1;
tipc_max_publications = 10000;
tipc_max_subscriptions = 2000;
tipc_max_ports = delimit(CONFIG_TIPC_PORTS, 127, 65536);
tipc_max_zones = delimit(CONFIG_TIPC_ZONES, 1, 255);
tipc_max_clusters = delimit(CONFIG_TIPC_CLUSTERS, 1, 1);
tipc_max_nodes = delimit(CONFIG_TIPC_NODES, 8, 2047);
tipc_max_slaves = delimit(CONFIG_TIPC_SLAVE_NODES, 0, 2047);
tipc_net_id = 4711;
if ((res = tipc_core_start()))
err("Unable to start in single node mode\n");
else
info("Started in single node mode\n");
return res;
}
static void __exit tipc_exit(void)
{
tipc_core_stop_net();
tipc_core_stop();
info("Deactivated\n");
tipc_log_resize(0);
}
module_init(tipc_init);
module_exit(tipc_exit);
MODULE_DESCRIPTION("TIPC: Transparent Inter Process Communication");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_VERSION(TIPC_MOD_VER);
/* Native TIPC API for kernel-space applications (see tipc.h) */
EXPORT_SYMBOL(tipc_attach);
EXPORT_SYMBOL(tipc_detach);
EXPORT_SYMBOL(tipc_get_addr);
EXPORT_SYMBOL(tipc_get_mode);
EXPORT_SYMBOL(tipc_createport);
EXPORT_SYMBOL(tipc_deleteport);
EXPORT_SYMBOL(tipc_ownidentity);
EXPORT_SYMBOL(tipc_portimportance);
EXPORT_SYMBOL(tipc_set_portimportance);
EXPORT_SYMBOL(tipc_portunreliable);
EXPORT_SYMBOL(tipc_set_portunreliable);
EXPORT_SYMBOL(tipc_portunreturnable);
EXPORT_SYMBOL(tipc_set_portunreturnable);
EXPORT_SYMBOL(tipc_publish);
EXPORT_SYMBOL(tipc_withdraw);
EXPORT_SYMBOL(tipc_connect2port);
EXPORT_SYMBOL(tipc_disconnect);
EXPORT_SYMBOL(tipc_shutdown);
EXPORT_SYMBOL(tipc_isconnected);
EXPORT_SYMBOL(tipc_peer);
EXPORT_SYMBOL(tipc_ref_valid);
EXPORT_SYMBOL(tipc_send);
EXPORT_SYMBOL(tipc_send_buf);
EXPORT_SYMBOL(tipc_send2name);
EXPORT_SYMBOL(tipc_forward2name);
EXPORT_SYMBOL(tipc_send_buf2name);
EXPORT_SYMBOL(tipc_forward_buf2name);
EXPORT_SYMBOL(tipc_send2port);
EXPORT_SYMBOL(tipc_forward2port);
EXPORT_SYMBOL(tipc_send_buf2port);
EXPORT_SYMBOL(tipc_forward_buf2port);
EXPORT_SYMBOL(tipc_multicast);
/* EXPORT_SYMBOL(tipc_multicast_buf); not available yet */
EXPORT_SYMBOL(tipc_ispublished);
EXPORT_SYMBOL(tipc_available_nodes);
/* TIPC API for external bearers (see tipc_bearer.h) */
EXPORT_SYMBOL(tipc_block_bearer);
EXPORT_SYMBOL(tipc_continue);
EXPORT_SYMBOL(tipc_disable_bearer);
EXPORT_SYMBOL(tipc_enable_bearer);
EXPORT_SYMBOL(tipc_recv_msg);
EXPORT_SYMBOL(tipc_register_media);
/* TIPC API for external APIs (see tipc_port.h) */
EXPORT_SYMBOL(tipc_createport_raw);
EXPORT_SYMBOL(tipc_reject_msg);
EXPORT_SYMBOL(tipc_send_buf_fast);
EXPORT_SYMBOL(tipc_acknowledge);
EXPORT_SYMBOL(tipc_get_port);
EXPORT_SYMBOL(tipc_get_handle);

375
kernel/net/tipc/core.h Normal file
View File

@@ -0,0 +1,375 @@
/*
* net/tipc/core.h: Include file for TIPC global declarations
*
* Copyright (c) 2005-2006, Ericsson AB
* Copyright (c) 2005-2007, Wind River Systems
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. 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.
*
* Alternatively, this software may be distributed under the terms of the
* GNU General Public License ("GPL") version 2 as published by the Free
* Software Foundation.
*
* 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_CORE_H
#define _TIPC_CORE_H
#include <linux/tipc.h>
#include <linux/tipc_config.h>
#include <net/tipc/tipc_msg.h>
#include <net/tipc/tipc_port.h>
#include <net/tipc/tipc_bearer.h>
#include <net/tipc/tipc.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/mm.h>
#include <linux/timer.h>
#include <linux/string.h>
#include <asm/uaccess.h>
#include <linux/interrupt.h>
#include <asm/atomic.h>
#include <asm/hardirq.h>
#include <linux/netdevice.h>
#include <linux/in.h>
#include <linux/list.h>
#include <linux/vmalloc.h>
/*
* TIPC sanity test macros
*/
#define assert(i) BUG_ON(!(i))
/*
* TIPC system monitoring code
*/
/*
* TIPC's print buffer subsystem supports the following print buffers:
*
* TIPC_NULL : null buffer (i.e. print nowhere)
* TIPC_CONS : system console
* TIPC_LOG : TIPC log buffer
* &buf : user-defined buffer (struct print_buf *)
*
* Note: TIPC_LOG is configured to echo its output to the system console;
* user-defined buffers can be configured to do the same thing.
*/
extern struct print_buf *const TIPC_NULL;
extern struct print_buf *const TIPC_CONS;
extern struct print_buf *const TIPC_LOG;
void tipc_printf(struct print_buf *, const char *fmt, ...);
/*
* TIPC_OUTPUT is the destination print buffer for system messages.
*/
#ifndef TIPC_OUTPUT
#define TIPC_OUTPUT TIPC_LOG
#endif
/*
* TIPC can be configured to send system messages to TIPC_OUTPUT
* or to the system console only.
*/
#ifdef CONFIG_TIPC_DEBUG
#define err(fmt, arg...) tipc_printf(TIPC_OUTPUT, \
KERN_ERR "TIPC: " fmt, ## arg)
#define warn(fmt, arg...) tipc_printf(TIPC_OUTPUT, \
KERN_WARNING "TIPC: " fmt, ## arg)
#define info(fmt, arg...) tipc_printf(TIPC_OUTPUT, \
KERN_NOTICE "TIPC: " fmt, ## arg)
#else
#define err(fmt, arg...) printk(KERN_ERR "TIPC: " fmt , ## arg)
#define info(fmt, arg...) printk(KERN_INFO "TIPC: " fmt , ## arg)
#define warn(fmt, arg...) printk(KERN_WARNING "TIPC: " fmt , ## arg)
#endif
/*
* DBG_OUTPUT is the destination print buffer for debug messages.
* It defaults to the the null print buffer, but can be redefined
* (typically in the individual .c files being debugged) to allow
* selected debug messages to be generated where needed.
*/
#ifndef DBG_OUTPUT
#define DBG_OUTPUT TIPC_NULL
#endif
/*
* TIPC can be configured to send debug messages to the specified print buffer
* (typically DBG_OUTPUT) or to suppress them entirely.
*/
#ifdef CONFIG_TIPC_DEBUG
#define dbg(fmt, arg...) \
do { \
if (DBG_OUTPUT != TIPC_NULL) \
tipc_printf(DBG_OUTPUT, fmt, ## arg); \
} while (0)
#define msg_dbg(msg, txt) \
do { \
if (DBG_OUTPUT != TIPC_NULL) \
tipc_msg_dbg(DBG_OUTPUT, msg, txt); \
} while (0)
#define dump(fmt, arg...) \
do { \
if (DBG_OUTPUT != TIPC_NULL) \
tipc_dump_dbg(DBG_OUTPUT, fmt, ##arg); \
} while (0)
void tipc_msg_dbg(struct print_buf *, struct tipc_msg *, const char *);
void tipc_dump_dbg(struct print_buf *, const char *fmt, ...);
#else
#define dbg(fmt, arg...) do {} while (0)
#define msg_dbg(msg, txt) do {} while (0)
#define dump(fmt, arg...) do {} while (0)
#define tipc_msg_dbg(...) do {} while (0)
#define tipc_dump_dbg(...) do {} while (0)
#endif
/*
* TIPC-specific error codes
*/
#define ELINKCONG EAGAIN /* link congestion <=> resource unavailable */
/*
* Global configuration variables
*/
extern u32 tipc_own_addr;
extern int tipc_max_zones;
extern int tipc_max_clusters;
extern int tipc_max_nodes;
extern int tipc_max_slaves;
extern int tipc_max_ports;
extern int tipc_max_subscriptions;
extern int tipc_max_publications;
extern int tipc_net_id;
extern int tipc_remote_management;
/*
* Other global variables
*/
extern int tipc_mode;
extern int tipc_random;
extern const char tipc_alphabet[];
extern atomic_t tipc_user_count;
/*
* Routines available to privileged subsystems
*/
extern int tipc_core_start(void);
extern void tipc_core_stop(void);
extern int tipc_core_start_net(unsigned long addr);
extern void tipc_core_stop_net(void);
extern int tipc_handler_start(void);
extern void tipc_handler_stop(void);
extern int tipc_netlink_start(void);
extern void tipc_netlink_stop(void);
extern int tipc_socket_init(void);
extern void tipc_socket_stop(void);
static inline int delimit(int val, int min, int max)
{
if (val > max)
return max;
if (val < min)
return min;
return val;
}
/*
* TIPC timer and signal code
*/
typedef void (*Handler) (unsigned long);
u32 tipc_k_signal(Handler routine, unsigned long argument);
/**
* k_init_timer - initialize a timer
* @timer: pointer to timer structure
* @routine: pointer to routine to invoke when timer expires
* @argument: value to pass to routine when timer expires
*
* Timer must be initialized before use (and terminated when no longer needed).
*/
static inline void k_init_timer(struct timer_list *timer, Handler routine,
unsigned long argument)
{
dbg("initializing timer %p\n", timer);
setup_timer(timer, routine, argument);
}
/**
* k_start_timer - start a timer
* @timer: pointer to timer structure
* @msec: time to delay (in ms)
*
* Schedules a previously initialized timer for later execution.
* If timer is already running, the new timeout overrides the previous request.
*
* To ensure the timer doesn't expire before the specified delay elapses,
* the amount of delay is rounded up when converting to the jiffies
* then an additional jiffy is added to account for the fact that
* the starting time may be in the middle of the current jiffy.
*/
static inline void k_start_timer(struct timer_list *timer, unsigned long msec)
{
dbg("starting timer %p for %u\n", timer, msec);
mod_timer(timer, jiffies + msecs_to_jiffies(msec) + 1);
}
/**
* k_cancel_timer - cancel a timer
* @timer: pointer to timer structure
*
* Cancels a previously initialized timer.
* Can be called safely even if the timer is already inactive.
*
* WARNING: Must not be called when holding locks required by the timer's
* timeout routine, otherwise deadlock can occur on SMP systems!
*/
static inline void k_cancel_timer(struct timer_list *timer)
{
dbg("cancelling timer %p\n", timer);
del_timer_sync(timer);
}
/**
* k_term_timer - terminate a timer
* @timer: pointer to timer structure
*
* Prevents further use of a previously initialized timer.
*
* WARNING: Caller must ensure timer isn't currently running.
*
* (Do not "enhance" this routine to automatically cancel an active timer,
* otherwise deadlock can arise when a timeout routine calls k_term_timer.)
*/
static inline void k_term_timer(struct timer_list *timer)
{
dbg("terminating timer %p\n", timer);
}
/*
* TIPC message buffer code
*
* TIPC message buffer headroom reserves space for the worst-case
* link-level device header (in case the message is sent off-node).
*
* Note: Headroom should be a multiple of 4 to ensure the TIPC header fields
* are word aligned for quicker access
*/
#define BUF_HEADROOM LL_MAX_HEADER
struct tipc_skb_cb {
void *handle;
};
#define TIPC_SKB_CB(__skb) ((struct tipc_skb_cb *)&((__skb)->cb[0]))
static inline struct tipc_msg *buf_msg(struct sk_buff *skb)
{
return (struct tipc_msg *)skb->data;
}
/**
* buf_acquire - creates a TIPC message buffer
* @size: message size (including TIPC header)
*
* Returns a new buffer with data pointers set to the specified size.
*
* NOTE: Headroom is reserved to allow prepending of a data link header.
* There may also be unrequested tailroom present at the buffer's end.
*/
static inline struct sk_buff *buf_acquire(u32 size)
{
struct sk_buff *skb;
unsigned int buf_size = (BUF_HEADROOM + size + 3) & ~3u;
skb = alloc_skb_fclone(buf_size, GFP_ATOMIC);
if (skb) {
skb_reserve(skb, BUF_HEADROOM);
skb_put(skb, size);
skb->next = NULL;
}
return skb;
}
/**
* buf_discard - frees a TIPC message buffer
* @skb: message buffer
*
* Frees a message buffer. If passed NULL, just returns.
*/
static inline void buf_discard(struct sk_buff *skb)
{
kfree_skb(skb);
}
/**
* buf_linearize - convert a TIPC message buffer into a single contiguous piece
* @skb: message buffer
*
* Returns 0 on success.
*/
static inline int buf_linearize(struct sk_buff *skb)
{
return skb_linearize(skb);
}
#endif

427
kernel/net/tipc/dbg.c Normal file
View File

@@ -0,0 +1,427 @@
/*
* net/tipc/dbg.c: TIPC print buffer routines for debugging
*
* Copyright (c) 1996-2006, Ericsson AB
* Copyright (c) 2005-2007, Wind River Systems
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. 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.
*
* Alternatively, this software may be distributed under the terms of the
* GNU General Public License ("GPL") version 2 as published by the Free
* Software Foundation.
*
* 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 "config.h"
#include "dbg.h"
/*
* TIPC pre-defines the following print buffers:
*
* TIPC_NULL : null buffer (i.e. print nowhere)
* TIPC_CONS : system console
* TIPC_LOG : TIPC log buffer
*
* Additional user-defined print buffers are also permitted.
*/
static struct print_buf null_buf = { NULL, 0, NULL, 0 };
struct print_buf *const TIPC_NULL = &null_buf;
static struct print_buf cons_buf = { NULL, 0, NULL, 1 };
struct print_buf *const TIPC_CONS = &cons_buf;
static struct print_buf log_buf = { NULL, 0, NULL, 1 };
struct print_buf *const TIPC_LOG = &log_buf;
/*
* Locking policy when using print buffers.
*
* 1) tipc_printf() uses 'print_lock' to protect against concurrent access to
* 'print_string' when writing to a print buffer. This also protects against
* concurrent writes to the print buffer being written to.
*
* 2) tipc_dump() and tipc_log_XXX() leverage the aforementioned
* use of 'print_lock' to protect against all types of concurrent operations
* on their associated print buffer (not just write operations).
*
* Note: All routines of the form tipc_printbuf_XXX() are lock-free, and rely
* on the caller to prevent simultaneous use of the print buffer(s) being
* manipulated.
*/
static char print_string[TIPC_PB_MAX_STR];
static DEFINE_SPINLOCK(print_lock);
#define FORMAT(PTR,LEN,FMT) \
{\
va_list args;\
va_start(args, FMT);\
LEN = vsprintf(PTR, FMT, args);\
va_end(args);\
*(PTR + LEN) = '\0';\
}
/**
* tipc_printbuf_init - initialize print buffer to empty
* @pb: pointer to print buffer structure
* @raw: pointer to character array used by print buffer
* @size: size of character array
*
* Note: If the character array is too small (or absent), the print buffer
* becomes a null device that discards anything written to it.
*/
void tipc_printbuf_init(struct print_buf *pb, char *raw, u32 size)
{
pb->buf = raw;
pb->crs = raw;
pb->size = size;
pb->echo = 0;
if (size < TIPC_PB_MIN_SIZE) {
pb->buf = NULL;
} else if (raw) {
pb->buf[0] = 0;
pb->buf[size - 1] = ~0;
}
}
/**
* tipc_printbuf_reset - reinitialize print buffer to empty state
* @pb: pointer to print buffer structure
*/
void tipc_printbuf_reset(struct print_buf *pb)
{
if (pb->buf) {
pb->crs = pb->buf;
pb->buf[0] = 0;
pb->buf[pb->size - 1] = ~0;
}
}
/**
* tipc_printbuf_empty - test if print buffer is in empty state
* @pb: pointer to print buffer structure
*
* Returns non-zero if print buffer is empty.
*/
int tipc_printbuf_empty(struct print_buf *pb)
{
return (!pb->buf || (pb->crs == pb->buf));
}
/**
* tipc_printbuf_validate - check for print buffer overflow
* @pb: pointer to print buffer structure
*
* Verifies that a print buffer has captured all data written to it.
* If data has been lost, linearize buffer and prepend an error message
*
* Returns length of print buffer data string (including trailing NUL)
*/
int tipc_printbuf_validate(struct print_buf *pb)
{
char *err = "\n\n*** PRINT BUFFER OVERFLOW ***\n\n";
char *cp_buf;
struct print_buf cb;
if (!pb->buf)
return 0;
if (pb->buf[pb->size - 1] == 0) {
cp_buf = kmalloc(pb->size, GFP_ATOMIC);
if (cp_buf) {
tipc_printbuf_init(&cb, cp_buf, pb->size);
tipc_printbuf_move(&cb, pb);
tipc_printbuf_move(pb, &cb);
kfree(cp_buf);
memcpy(pb->buf, err, strlen(err));
} else {
tipc_printbuf_reset(pb);
tipc_printf(pb, err);
}
}
return (pb->crs - pb->buf + 1);
}
/**
* tipc_printbuf_move - move print buffer contents to another print buffer
* @pb_to: pointer to destination print buffer structure
* @pb_from: pointer to source print buffer structure
*
* Current contents of destination print buffer (if any) are discarded.
* Source print buffer becomes empty if a successful move occurs.
*/
void tipc_printbuf_move(struct print_buf *pb_to, struct print_buf *pb_from)
{
int len;
/* Handle the cases where contents can't be moved */
if (!pb_to->buf)
return;
if (!pb_from->buf) {
tipc_printbuf_reset(pb_to);
return;
}
if (pb_to->size < pb_from->size) {
strcpy(pb_to->buf, "*** PRINT BUFFER MOVE ERROR ***");
pb_to->buf[pb_to->size - 1] = ~0;
pb_to->crs = strchr(pb_to->buf, 0);
return;
}
/* Copy data from char after cursor to end (if used) */
len = pb_from->buf + pb_from->size - pb_from->crs - 2;
if ((pb_from->buf[pb_from->size - 1] == 0) && (len > 0)) {
strcpy(pb_to->buf, pb_from->crs + 1);
pb_to->crs = pb_to->buf + len;
} else
pb_to->crs = pb_to->buf;
/* Copy data from start to cursor (always) */
len = pb_from->crs - pb_from->buf;
strcpy(pb_to->crs, pb_from->buf);
pb_to->crs += len;
tipc_printbuf_reset(pb_from);
}
/**
* tipc_printf - append formatted output to print buffer
* @pb: pointer to print buffer
* @fmt: formatted info to be printed
*/
void tipc_printf(struct print_buf *pb, const char *fmt, ...)
{
int chars_to_add;
int chars_left;
char save_char;
spin_lock_bh(&print_lock);
FORMAT(print_string, chars_to_add, fmt);
if (chars_to_add >= TIPC_PB_MAX_STR)
strcpy(print_string, "*** PRINT BUFFER STRING TOO LONG ***");
if (pb->buf) {
chars_left = pb->buf + pb->size - pb->crs - 1;
if (chars_to_add <= chars_left) {
strcpy(pb->crs, print_string);
pb->crs += chars_to_add;
} else if (chars_to_add >= (pb->size - 1)) {
strcpy(pb->buf, print_string + chars_to_add + 1
- pb->size);
pb->crs = pb->buf + pb->size - 1;
} else {
strcpy(pb->buf, print_string + chars_left);
save_char = print_string[chars_left];
print_string[chars_left] = 0;
strcpy(pb->crs, print_string);
print_string[chars_left] = save_char;
pb->crs = pb->buf + chars_to_add - chars_left;
}
}
if (pb->echo)
printk("%s", print_string);
spin_unlock_bh(&print_lock);
}
#ifdef CONFIG_TIPC_DEBUG
/**
* print_to_console - write string of bytes to console in multiple chunks
*/
static void print_to_console(char *crs, int len)
{
int rest = len;
while (rest > 0) {
int sz = rest < TIPC_PB_MAX_STR ? rest : TIPC_PB_MAX_STR;
char c = crs[sz];
crs[sz] = 0;
printk((const char *)crs);
crs[sz] = c;
rest -= sz;
crs += sz;
}
}
/**
* printbuf_dump - write print buffer contents to console
*/
static void printbuf_dump(struct print_buf *pb)
{
int len;
if (!pb->buf) {
printk("*** PRINT BUFFER NOT ALLOCATED ***");
return;
}
/* Dump print buffer from char after cursor to end (if used) */
len = pb->buf + pb->size - pb->crs - 2;
if ((pb->buf[pb->size - 1] == 0) && (len > 0))
print_to_console(pb->crs + 1, len);
/* Dump print buffer from start to cursor (always) */
len = pb->crs - pb->buf;
print_to_console(pb->buf, len);
}
/**
* tipc_dump_dbg - dump (non-console) print buffer to console
* @pb: pointer to print buffer
*/
void tipc_dump_dbg(struct print_buf *pb, const char *fmt, ...)
{
int len;
if (pb == TIPC_CONS)
return;
spin_lock_bh(&print_lock);
FORMAT(print_string, len, fmt);
printk(print_string);
printk("\n---- Start of %s log dump ----\n\n",
(pb == TIPC_LOG) ? "global" : "local");
printbuf_dump(pb);
tipc_printbuf_reset(pb);
printk("\n---- End of dump ----\n");
spin_unlock_bh(&print_lock);
}
#endif
/**
* tipc_log_resize - change the size of the TIPC log buffer
* @log_size: print buffer size to use
*/
int tipc_log_resize(int log_size)
{
int res = 0;
spin_lock_bh(&print_lock);
if (TIPC_LOG->buf) {
kfree(TIPC_LOG->buf);
TIPC_LOG->buf = NULL;
}
if (log_size) {
if (log_size < TIPC_PB_MIN_SIZE)
log_size = TIPC_PB_MIN_SIZE;
res = TIPC_LOG->echo;
tipc_printbuf_init(TIPC_LOG, kmalloc(log_size, GFP_ATOMIC),
log_size);
TIPC_LOG->echo = res;
res = !TIPC_LOG->buf;
}
spin_unlock_bh(&print_lock);
return res;
}
/**
* tipc_log_resize_cmd - reconfigure size of TIPC log buffer
*/
struct sk_buff *tipc_log_resize_cmd(const void *req_tlv_area, int req_tlv_space)
{
u32 value;
if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area));
if (value != delimit(value, 0, 32768))
return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
" (log size must be 0-32768)");
if (tipc_log_resize(value))
return tipc_cfg_reply_error_string(
"unable to create specified log (log size is now 0)");
return tipc_cfg_reply_none();
}
/**
* tipc_log_dump - capture TIPC log buffer contents in configuration message
*/
struct sk_buff *tipc_log_dump(void)
{
struct sk_buff *reply;
spin_lock_bh(&print_lock);
if (!TIPC_LOG->buf) {
spin_unlock_bh(&print_lock);
reply = tipc_cfg_reply_ultra_string("log not activated\n");
} else if (tipc_printbuf_empty(TIPC_LOG)) {
spin_unlock_bh(&print_lock);
reply = tipc_cfg_reply_ultra_string("log is empty\n");
}
else {
struct tlv_desc *rep_tlv;
struct print_buf pb;
int str_len;
str_len = min(TIPC_LOG->size, 32768u);
spin_unlock_bh(&print_lock);
reply = tipc_cfg_reply_alloc(TLV_SPACE(str_len));
if (reply) {
rep_tlv = (struct tlv_desc *)reply->data;
tipc_printbuf_init(&pb, TLV_DATA(rep_tlv), str_len);
spin_lock_bh(&print_lock);
tipc_printbuf_move(&pb, TIPC_LOG);
spin_unlock_bh(&print_lock);
str_len = strlen(TLV_DATA(rep_tlv)) + 1;
skb_put(reply, TLV_SPACE(str_len));
TLV_SET(rep_tlv, TIPC_TLV_ULTRA_STRING, NULL, str_len);
}
}
return reply;
}

70
kernel/net/tipc/dbg.h Normal file
View File

@@ -0,0 +1,70 @@
/*
* net/tipc/dbg.h: Include file for TIPC print buffer routines
*
* Copyright (c) 1997-2006, Ericsson AB
* Copyright (c) 2005-2007, Wind River Systems
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. 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.
*
* Alternatively, this software may be distributed under the terms of the
* GNU General Public License ("GPL") version 2 as published by the Free
* Software Foundation.
*
* 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_DBG_H
#define _TIPC_DBG_H
/**
* struct print_buf - TIPC print buffer structure
* @buf: pointer to character array containing print buffer contents
* @size: size of character array
* @crs: pointer to first unused space in character array (i.e. final NUL)
* @echo: echo output to system console if non-zero
*/
struct print_buf {
char *buf;
u32 size;
char *crs;
int echo;
};
#define TIPC_PB_MIN_SIZE 64 /* minimum size for a print buffer's array */
#define TIPC_PB_MAX_STR 512 /* max printable string (with trailing NUL) */
void tipc_printbuf_init(struct print_buf *pb, char *buf, u32 size);
void tipc_printbuf_reset(struct print_buf *pb);
int tipc_printbuf_empty(struct print_buf *pb);
int tipc_printbuf_validate(struct print_buf *pb);
void tipc_printbuf_move(struct print_buf *pb_to, struct print_buf *pb_from);
int tipc_log_resize(int log_size);
struct sk_buff *tipc_log_resize_cmd(const void *req_tlv_area,
int req_tlv_space);
struct sk_buff *tipc_log_dump(void);
#endif

344
kernel/net/tipc/discover.c Normal file
View File

@@ -0,0 +1,344 @@
/*
* net/tipc/discover.c
*
* Copyright (c) 2003-2006, Ericsson AB
* Copyright (c) 2005-2006, Wind River Systems
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. 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.
*
* Alternatively, this software may be distributed under the terms of the
* GNU General Public License ("GPL") version 2 as published by the Free
* Software Foundation.
*
* 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 "link.h"
#include "zone.h"
#include "discover.h"
#include "port.h"
#include "name_table.h"
#define TIPC_LINK_REQ_INIT 125 /* min delay during bearer start up */
#define TIPC_LINK_REQ_FAST 2000 /* normal delay if bearer has no links */
#define TIPC_LINK_REQ_SLOW 600000 /* normal delay if bearer has links */
#if 0
#define GET_NODE_INFO 300
#define GET_NODE_INFO_RESULT 301
#define FORWARD_LINK_PROBE 302
#define LINK_REQUEST_REJECTED 303
#define LINK_REQUEST_ACCEPTED 304
#define DROP_LINK_REQUEST 305
#define CHECK_LINK_COUNT 306
#endif
/*
* TODO: Most of the inter-cluster setup stuff should be
* rewritten, and be made conformant with specification.
*/
/**
* struct link_req - information about an ongoing link setup request
* @bearer: bearer issuing requests
* @dest: destination address for request messages
* @buf: request message to be (repeatedly) sent
* @timer: timer governing period between requests
* @timer_intv: current interval between requests (in ms)
*/
struct link_req {
struct bearer *bearer;
struct tipc_media_addr dest;
struct sk_buff *buf;
struct timer_list timer;
unsigned int timer_intv;
};
#if 0
int disc_create_link(const struct tipc_link_create *argv)
{
/*
* Code for inter cluster link setup here
*/
return TIPC_OK;
}
#endif
/*
* disc_lost_link(): A link has lost contact
*/
void tipc_disc_link_event(u32 addr, char *name, int up)
{
if (in_own_cluster(addr))
return;
/*
* Code for inter cluster link setup here
*/
}
/**
* tipc_disc_init_msg - initialize a link setup message
* @type: message type (request or response)
* @req_links: number of links associated with message
* @dest_domain: network domain of node(s) which should respond to message
* @b_ptr: ptr to bearer issuing message
*/
static struct sk_buff *tipc_disc_init_msg(u32 type,
u32 req_links,
u32 dest_domain,
struct bearer *b_ptr)
{
struct sk_buff *buf = buf_acquire(DSC_H_SIZE);
struct tipc_msg *msg;
if (buf) {
msg = buf_msg(buf);
msg_init(msg, LINK_CONFIG, type, DSC_H_SIZE, dest_domain);
msg_set_non_seq(msg, 1);
msg_set_req_links(msg, req_links);
msg_set_dest_domain(msg, dest_domain);
msg_set_bc_netid(msg, tipc_net_id);
msg_set_media_addr(msg, &b_ptr->publ.addr);
}
return buf;
}
/**
* disc_dupl_alert - issue node address duplication alert
* @b_ptr: pointer to bearer detecting duplication
* @node_addr: duplicated node address
* @media_addr: media address advertised by duplicated node
*/
static void disc_dupl_alert(struct bearer *b_ptr, u32 node_addr,
struct tipc_media_addr *media_addr)
{
char node_addr_str[16];
char media_addr_str[64];
struct print_buf pb;
addr_string_fill(node_addr_str, node_addr);
tipc_printbuf_init(&pb, media_addr_str, sizeof(media_addr_str));
tipc_media_addr_printf(&pb, media_addr);
tipc_printbuf_validate(&pb);
warn("Duplicate %s using %s seen on <%s>\n",
node_addr_str, media_addr_str, b_ptr->publ.name);
}
/**
* tipc_disc_recv_msg - handle incoming link setup message (request or response)
* @buf: buffer containing message
* @b_ptr: bearer that message arrived on
*/
void tipc_disc_recv_msg(struct sk_buff *buf, struct bearer *b_ptr)
{
struct link *link;
struct tipc_media_addr media_addr;
struct tipc_msg *msg = buf_msg(buf);
u32 dest = msg_dest_domain(msg);
u32 orig = msg_prevnode(msg);
u32 net_id = msg_bc_netid(msg);
u32 type = msg_type(msg);
msg_get_media_addr(msg,&media_addr);
msg_dbg(msg, "RECV:");
buf_discard(buf);
if (net_id != tipc_net_id)
return;
if (!tipc_addr_domain_valid(dest))
return;
if (!tipc_addr_node_valid(orig))
return;
if (orig == tipc_own_addr) {
if (memcmp(&media_addr, &b_ptr->publ.addr, sizeof(media_addr)))
disc_dupl_alert(b_ptr, tipc_own_addr, &media_addr);
return;
}
if (!in_scope(dest, tipc_own_addr))
return;
if (is_slave(tipc_own_addr) && is_slave(orig))
return;
if (is_slave(orig) && !in_own_cluster(orig))
return;
if (in_own_cluster(orig)) {
/* Always accept link here */
struct sk_buff *rbuf;
struct tipc_media_addr *addr;
struct tipc_node *n_ptr = tipc_node_find(orig);
int link_fully_up;
dbg(" in own cluster\n");
if (n_ptr == NULL) {
n_ptr = tipc_node_create(orig);
if (!n_ptr)
return;
}
spin_lock_bh(&n_ptr->lock);
link = n_ptr->links[b_ptr->identity];
if (!link) {
dbg("creating link\n");
link = tipc_link_create(b_ptr, orig, &media_addr);
if (!link) {
spin_unlock_bh(&n_ptr->lock);
return;
}
}
addr = &link->media_addr;
if (memcmp(addr, &media_addr, sizeof(*addr))) {
if (tipc_link_is_up(link) || (!link->started)) {
disc_dupl_alert(b_ptr, orig, &media_addr);
spin_unlock_bh(&n_ptr->lock);
return;
}
warn("Resetting link <%s>, peer interface address changed\n",
link->name);
memcpy(addr, &media_addr, sizeof(*addr));
tipc_link_reset(link);
}
link_fully_up = (link->state == WORKING_WORKING);
spin_unlock_bh(&n_ptr->lock);
if ((type == DSC_RESP_MSG) || link_fully_up)
return;
rbuf = tipc_disc_init_msg(DSC_RESP_MSG, 1, orig, b_ptr);
if (rbuf != NULL) {
msg_dbg(buf_msg(rbuf),"SEND:");
b_ptr->media->send_msg(rbuf, &b_ptr->publ, &media_addr);
buf_discard(rbuf);
}
}
}
/**
* tipc_disc_stop_link_req - stop sending periodic link setup requests
* @req: ptr to link request structure
*/
void tipc_disc_stop_link_req(struct link_req *req)
{
if (!req)
return;
k_cancel_timer(&req->timer);
k_term_timer(&req->timer);
buf_discard(req->buf);
kfree(req);
}
/**
* tipc_disc_update_link_req - update frequency of periodic link setup requests
* @req: ptr to link request structure
*/
void tipc_disc_update_link_req(struct link_req *req)
{
if (!req)
return;
if (req->timer_intv == TIPC_LINK_REQ_SLOW) {
if (!req->bearer->nodes.count) {
req->timer_intv = TIPC_LINK_REQ_FAST;
k_start_timer(&req->timer, req->timer_intv);
}
} else if (req->timer_intv == TIPC_LINK_REQ_FAST) {
if (req->bearer->nodes.count) {
req->timer_intv = TIPC_LINK_REQ_SLOW;
k_start_timer(&req->timer, req->timer_intv);
}
} else {
/* leave timer "as is" if haven't yet reached a "normal" rate */
}
}
/**
* disc_timeout - send a periodic link setup request
* @req: ptr to link request structure
*
* Called whenever a link setup request timer associated with a bearer expires.
*/
static void disc_timeout(struct link_req *req)
{
spin_lock_bh(&req->bearer->publ.lock);
req->bearer->media->send_msg(req->buf, &req->bearer->publ, &req->dest);
if ((req->timer_intv == TIPC_LINK_REQ_SLOW) ||
(req->timer_intv == TIPC_LINK_REQ_FAST)) {
/* leave timer interval "as is" if already at a "normal" rate */
} else {
req->timer_intv *= 2;
if (req->timer_intv > TIPC_LINK_REQ_FAST)
req->timer_intv = TIPC_LINK_REQ_FAST;
if ((req->timer_intv == TIPC_LINK_REQ_FAST) &&
(req->bearer->nodes.count))
req->timer_intv = TIPC_LINK_REQ_SLOW;
}
k_start_timer(&req->timer, req->timer_intv);
spin_unlock_bh(&req->bearer->publ.lock);
}
/**
* tipc_disc_init_link_req - start sending periodic link setup requests
* @b_ptr: ptr to bearer issuing requests
* @dest: destination address for request messages
* @dest_domain: network domain of node(s) which should respond to message
* @req_links: max number of desired links
*
* Returns pointer to link request structure, or NULL if unable to create.
*/
struct link_req *tipc_disc_init_link_req(struct bearer *b_ptr,
const struct tipc_media_addr *dest,
u32 dest_domain,
u32 req_links)
{
struct link_req *req;
req = kmalloc(sizeof(*req), GFP_ATOMIC);
if (!req)
return NULL;
req->buf = tipc_disc_init_msg(DSC_REQ_MSG, req_links, dest_domain, b_ptr);
if (!req->buf) {
kfree(req);
return NULL;
}
memcpy(&req->dest, dest, sizeof(*dest));
req->bearer = b_ptr;
req->timer_intv = TIPC_LINK_REQ_INIT;
k_init_timer(&req->timer, (Handler)disc_timeout, (unsigned long)req);
k_start_timer(&req->timer, req->timer_intv);
return req;
}

View File

@@ -0,0 +1,58 @@
/*
* net/tipc/discover.h
*
* Copyright (c) 2003-2006, Ericsson AB
* Copyright (c) 2005, Wind River Systems
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. 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.
*
* Alternatively, this software may be distributed under the terms of the
* GNU General Public License ("GPL") version 2 as published by the Free
* Software Foundation.
*
* 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_DISCOVER_H
#define _TIPC_DISCOVER_H
#include "core.h"
struct link_req;
struct link_req *tipc_disc_init_link_req(struct bearer *b_ptr,
const struct tipc_media_addr *dest,
u32 dest_domain,
u32 req_links);
void tipc_disc_update_link_req(struct link_req *req);
void tipc_disc_stop_link_req(struct link_req *req);
void tipc_disc_recv_msg(struct sk_buff *buf, struct bearer *b_ptr);
void tipc_disc_link_event(u32 addr, char *name, int up);
#if 0
int disc_create_link(const struct tipc_link_create *argv);
#endif
#endif

313
kernel/net/tipc/eth_media.c Normal file
View File

@@ -0,0 +1,313 @@
/*
* net/tipc/eth_media.c: Ethernet bearer support for TIPC
*
* Copyright (c) 2001-2007, Ericsson AB
* Copyright (c) 2005-2007, Wind River Systems
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. 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.
*
* Alternatively, this software may be distributed under the terms of the
* GNU General Public License ("GPL") version 2 as published by the Free
* Software Foundation.
*
* 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 <net/tipc/tipc.h>
#include <net/tipc/tipc_bearer.h>
#include <net/tipc/tipc_msg.h>
#include <linux/netdevice.h>
#include <net/net_namespace.h>
#define MAX_ETH_BEARERS 2
#define ETH_LINK_PRIORITY TIPC_DEF_LINK_PRI
#define ETH_LINK_TOLERANCE TIPC_DEF_LINK_TOL
#define ETH_LINK_WINDOW TIPC_DEF_LINK_WIN
/**
* struct eth_bearer - Ethernet bearer data structure
* @bearer: ptr to associated "generic" bearer structure
* @dev: ptr to associated Ethernet network device
* @tipc_packet_type: used in binding TIPC to Ethernet driver
*/
struct eth_bearer {
struct tipc_bearer *bearer;
struct net_device *dev;
struct packet_type tipc_packet_type;
};
static struct eth_bearer eth_bearers[MAX_ETH_BEARERS];
static int eth_started = 0;
static struct notifier_block notifier;
/**
* send_msg - send a TIPC message out over an Ethernet interface
*/
static int send_msg(struct sk_buff *buf, struct tipc_bearer *tb_ptr,
struct tipc_media_addr *dest)
{
struct sk_buff *clone;
struct net_device *dev;
clone = skb_clone(buf, GFP_ATOMIC);
if (clone) {
skb_reset_network_header(clone);
dev = ((struct eth_bearer *)(tb_ptr->usr_handle))->dev;
clone->dev = dev;
dev_hard_header(clone, dev, ETH_P_TIPC,
&dest->dev_addr.eth_addr,
dev->dev_addr, clone->len);
dev_queue_xmit(clone);
}
return 0;
}
/**
* recv_msg - handle incoming TIPC message from an Ethernet interface
*
* Accept only packets explicitly sent to this node, or broadcast packets;
* ignores packets sent using Ethernet multicast, and traffic sent to other
* nodes (which can happen if interface is running in promiscuous mode).
* Routine truncates any Ethernet padding/CRC appended to the message,
* and ensures message size matches actual length
*/
static int recv_msg(struct sk_buff *buf, struct net_device *dev,
struct packet_type *pt, struct net_device *orig_dev)
{
struct eth_bearer *eb_ptr = (struct eth_bearer *)pt->af_packet_priv;
u32 size;
if (!net_eq(dev_net(dev), &init_net)) {
kfree_skb(buf);
return 0;
}
if (likely(eb_ptr->bearer)) {
if (likely(buf->pkt_type <= PACKET_BROADCAST)) {
size = msg_size((struct tipc_msg *)buf->data);
skb_trim(buf, size);
if (likely(buf->len == size)) {
buf->next = NULL;
tipc_recv_msg(buf, eb_ptr->bearer);
return 0;
}
}
}
kfree_skb(buf);
return 0;
}
/**
* enable_bearer - attach TIPC bearer to an Ethernet interface
*/
static int enable_bearer(struct tipc_bearer *tb_ptr)
{
struct net_device *dev = NULL;
struct net_device *pdev = NULL;
struct eth_bearer *eb_ptr = &eth_bearers[0];
struct eth_bearer *stop = &eth_bearers[MAX_ETH_BEARERS];
char *driver_name = strchr((const char *)tb_ptr->name, ':') + 1;
/* Find device with specified name */
for_each_netdev(&init_net, pdev){
if (!strncmp(pdev->name, driver_name, IFNAMSIZ)) {
dev = pdev;
break;
}
}
if (!dev)
return -ENODEV;
/* Find Ethernet bearer for device (or create one) */
for (;(eb_ptr != stop) && eb_ptr->dev && (eb_ptr->dev != dev); eb_ptr++);
if (eb_ptr == stop)
return -EDQUOT;
if (!eb_ptr->dev) {
eb_ptr->dev = dev;
eb_ptr->tipc_packet_type.type = htons(ETH_P_TIPC);
eb_ptr->tipc_packet_type.dev = dev;
eb_ptr->tipc_packet_type.func = recv_msg;
eb_ptr->tipc_packet_type.af_packet_priv = eb_ptr;
INIT_LIST_HEAD(&(eb_ptr->tipc_packet_type.list));
dev_hold(dev);
dev_add_pack(&eb_ptr->tipc_packet_type);
}
/* Associate TIPC bearer with Ethernet bearer */
eb_ptr->bearer = tb_ptr;
tb_ptr->usr_handle = (void *)eb_ptr;
tb_ptr->mtu = dev->mtu;
tb_ptr->blocked = 0;
tb_ptr->addr.type = htonl(TIPC_MEDIA_TYPE_ETH);
memcpy(&tb_ptr->addr.dev_addr, dev->dev_addr, ETH_ALEN);
return 0;
}
/**
* disable_bearer - detach TIPC bearer from an Ethernet interface
*
* We really should do dev_remove_pack() here, but this function can not be
* called at tasklet level. => Use eth_bearer->bearer as a flag to throw away
* incoming buffers, & postpone dev_remove_pack() to eth_media_stop() on exit.
*/
static void disable_bearer(struct tipc_bearer *tb_ptr)
{
((struct eth_bearer *)tb_ptr->usr_handle)->bearer = NULL;
}
/**
* recv_notification - handle device updates from OS
*
* Change the state of the Ethernet bearer (if any) associated with the
* specified device.
*/
static int recv_notification(struct notifier_block *nb, unsigned long evt,
void *dv)
{
struct net_device *dev = (struct net_device *)dv;
struct eth_bearer *eb_ptr = &eth_bearers[0];
struct eth_bearer *stop = &eth_bearers[MAX_ETH_BEARERS];
if (!net_eq(dev_net(dev), &init_net))
return NOTIFY_DONE;
while ((eb_ptr->dev != dev)) {
if (++eb_ptr == stop)
return NOTIFY_DONE; /* couldn't find device */
}
if (!eb_ptr->bearer)
return NOTIFY_DONE; /* bearer had been disabled */
eb_ptr->bearer->mtu = dev->mtu;
switch (evt) {
case NETDEV_CHANGE:
if (netif_carrier_ok(dev))
tipc_continue(eb_ptr->bearer);
else
tipc_block_bearer(eb_ptr->bearer->name);
break;
case NETDEV_UP:
tipc_continue(eb_ptr->bearer);
break;
case NETDEV_DOWN:
tipc_block_bearer(eb_ptr->bearer->name);
break;
case NETDEV_CHANGEMTU:
case NETDEV_CHANGEADDR:
tipc_block_bearer(eb_ptr->bearer->name);
tipc_continue(eb_ptr->bearer);
break;
case NETDEV_UNREGISTER:
case NETDEV_CHANGENAME:
tipc_disable_bearer(eb_ptr->bearer->name);
break;
}
return NOTIFY_OK;
}
/**
* eth_addr2str - convert Ethernet address to string
*/
static char *eth_addr2str(struct tipc_media_addr *a, char *str_buf, int str_size)
{
unchar *addr = (unchar *)&a->dev_addr;
if (str_size < 18)
*str_buf = '\0';
else
sprintf(str_buf, "%pM", addr);
return str_buf;
}
/**
* tipc_eth_media_start - activate Ethernet bearer support
*
* Register Ethernet media type with TIPC bearer code. Also register
* with OS for notifications about device state changes.
*/
int tipc_eth_media_start(void)
{
struct tipc_media_addr bcast_addr;
int res;
if (eth_started)
return -EINVAL;
bcast_addr.type = htonl(TIPC_MEDIA_TYPE_ETH);
memset(&bcast_addr.dev_addr, 0xff, ETH_ALEN);
memset(eth_bearers, 0, sizeof(eth_bearers));
res = tipc_register_media(TIPC_MEDIA_TYPE_ETH, "eth",
enable_bearer, disable_bearer, send_msg,
eth_addr2str, &bcast_addr, ETH_LINK_PRIORITY,
ETH_LINK_TOLERANCE, ETH_LINK_WINDOW);
if (res)
return res;
notifier.notifier_call = &recv_notification;
notifier.priority = 0;
res = register_netdevice_notifier(&notifier);
if (!res)
eth_started = 1;
return res;
}
/**
* tipc_eth_media_stop - deactivate Ethernet bearer support
*/
void tipc_eth_media_stop(void)
{
int i;
if (!eth_started)
return;
unregister_netdevice_notifier(&notifier);
for (i = 0; i < MAX_ETH_BEARERS ; i++) {
if (eth_bearers[i].bearer) {
eth_bearers[i].bearer->blocked = 1;
eth_bearers[i].bearer = NULL;
}
if (eth_bearers[i].dev) {
dev_remove_pack(&eth_bearers[i].tipc_packet_type);
dev_put(eth_bearers[i].dev);
}
}
memset(&eth_bearers, 0, sizeof(eth_bearers));
eth_started = 0;
}

132
kernel/net/tipc/handler.c Normal file
View File

@@ -0,0 +1,132 @@
/*
* net/tipc/handler.c: TIPC signal handling
*
* Copyright (c) 2000-2006, Ericsson AB
* Copyright (c) 2005, Wind River Systems
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. 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.
*
* Alternatively, this software may be distributed under the terms of the
* GNU General Public License ("GPL") version 2 as published by the Free
* Software Foundation.
*
* 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"
struct queue_item {
struct list_head next_signal;
void (*handler) (unsigned long);
unsigned long data;
};
static struct kmem_cache *tipc_queue_item_cache;
static struct list_head signal_queue_head;
static DEFINE_SPINLOCK(qitem_lock);
static int handler_enabled = 0;
static void process_signal_queue(unsigned long dummy);
static DECLARE_TASKLET_DISABLED(tipc_tasklet, process_signal_queue, 0);
unsigned int tipc_k_signal(Handler routine, unsigned long argument)
{
struct queue_item *item;
if (!handler_enabled) {
err("Signal request ignored by handler\n");
return -ENOPROTOOPT;
}
spin_lock_bh(&qitem_lock);
item = kmem_cache_alloc(tipc_queue_item_cache, GFP_ATOMIC);
if (!item) {
err("Signal queue out of memory\n");
spin_unlock_bh(&qitem_lock);
return -ENOMEM;
}
item->handler = routine;
item->data = argument;
list_add_tail(&item->next_signal, &signal_queue_head);
spin_unlock_bh(&qitem_lock);
tasklet_schedule(&tipc_tasklet);
return 0;
}
static void process_signal_queue(unsigned long dummy)
{
struct queue_item *__volatile__ item;
struct list_head *l, *n;
spin_lock_bh(&qitem_lock);
list_for_each_safe(l, n, &signal_queue_head) {
item = list_entry(l, struct queue_item, next_signal);
list_del(&item->next_signal);
spin_unlock_bh(&qitem_lock);
item->handler(item->data);
spin_lock_bh(&qitem_lock);
kmem_cache_free(tipc_queue_item_cache, item);
}
spin_unlock_bh(&qitem_lock);
}
int tipc_handler_start(void)
{
tipc_queue_item_cache =
kmem_cache_create("tipc_queue_items", sizeof(struct queue_item),
0, SLAB_HWCACHE_ALIGN, NULL);
if (!tipc_queue_item_cache)
return -ENOMEM;
INIT_LIST_HEAD(&signal_queue_head);
tasklet_enable(&tipc_tasklet);
handler_enabled = 1;
return 0;
}
void tipc_handler_stop(void)
{
struct list_head *l, *n;
struct queue_item *item;
if (!handler_enabled)
return;
handler_enabled = 0;
tasklet_disable(&tipc_tasklet);
tasklet_kill(&tipc_tasklet);
spin_lock_bh(&qitem_lock);
list_for_each_safe(l, n, &signal_queue_head) {
item = list_entry(l, struct queue_item, next_signal);
list_del(&item->next_signal);
kmem_cache_free(tipc_queue_item_cache, item);
}
spin_unlock_bh(&qitem_lock);
kmem_cache_destroy(tipc_queue_item_cache);
}

3358
kernel/net/tipc/link.c Normal file

File diff suppressed because it is too large Load Diff

295
kernel/net/tipc/link.h Normal file
View File

@@ -0,0 +1,295 @@
/*
* net/tipc/link.h: Include file for TIPC link code
*
* Copyright (c) 1995-2006, Ericsson AB
* Copyright (c) 2004-2005, Wind River Systems
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. 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.
*
* Alternatively, this software may be distributed under the terms of the
* GNU General Public License ("GPL") version 2 as published by the Free
* Software Foundation.
*
* 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_LINK_H
#define _TIPC_LINK_H
#include "dbg.h"
#include "msg.h"
#include "bearer.h"
#include "node.h"
#define PUSH_FAILED 1
#define PUSH_FINISHED 2
/*
* Link states
*/
#define WORKING_WORKING 560810u
#define WORKING_UNKNOWN 560811u
#define RESET_UNKNOWN 560812u
#define RESET_RESET 560813u
/*
* Starting value for maximum packet size negotiation on unicast links
* (unless bearer MTU is less)
*/
#define MAX_PKT_DEFAULT 1500
/**
* struct link - TIPC link data structure
* @addr: network address of link's peer node
* @name: link name character string
* @media_addr: media address to use when sending messages over link
* @timer: link timer
* @owner: pointer to peer node
* @link_list: adjacent links in bearer's list of links
* @started: indicates if link has been started
* @checkpoint: reference point for triggering link continuity checking
* @peer_session: link session # being used by peer end of link
* @peer_bearer_id: bearer id used by link's peer endpoint
* @b_ptr: pointer to bearer used by link
* @tolerance: minimum link continuity loss needed to reset link [in ms]
* @continuity_interval: link continuity testing interval [in ms]
* @abort_limit: # of unacknowledged continuity probes needed to reset link
* @state: current state of link FSM
* @blocked: indicates if link has been administratively blocked
* @fsm_msg_cnt: # of protocol messages link FSM has sent in current state
* @proto_msg: template for control messages generated by link
* @pmsg: convenience pointer to "proto_msg" field
* @priority: current link priority
* @queue_limit: outbound message queue congestion thresholds (indexed by user)
* @exp_msg_count: # of tunnelled messages expected during link changeover
* @reset_checkpoint: seq # of last acknowledged message at time of link reset
* @max_pkt: current maximum packet size for this link
* @max_pkt_target: desired maximum packet size for this link
* @max_pkt_probes: # of probes based on current (max_pkt, max_pkt_target)
* @out_queue_size: # of messages in outbound message queue
* @first_out: ptr to first outbound message in queue
* @last_out: ptr to last outbound message in queue
* @next_out_no: next sequence number to use for outbound messages
* @last_retransmitted: sequence number of most recently retransmitted message
* @stale_count: # of identical retransmit requests made by peer
* @next_in_no: next sequence number to expect for inbound messages
* @deferred_inqueue_sz: # of messages in inbound message queue
* @oldest_deferred_in: ptr to first inbound message in queue
* @newest_deferred_in: ptr to last inbound message in queue
* @unacked_window: # of inbound messages rx'd without ack'ing back to peer
* @proto_msg_queue: ptr to (single) outbound control message
* @retransm_queue_size: number of messages to retransmit
* @retransm_queue_head: sequence number of first message to retransmit
* @next_out: ptr to first unsent outbound message in queue
* @waiting_ports: linked list of ports waiting for link congestion to abate
* @long_msg_seq_no: next identifier to use for outbound fragmented messages
* @defragm_buf: list of partially reassembled inbound message fragments
* @stats: collects statistics regarding link activity
* @print_buf: print buffer used to log link activity
*/
struct link {
u32 addr;
char name[TIPC_MAX_LINK_NAME];
struct tipc_media_addr media_addr;
struct timer_list timer;
struct tipc_node *owner;
struct list_head link_list;
/* Management and link supervision data */
int started;
u32 checkpoint;
u32 peer_session;
u32 peer_bearer_id;
struct bearer *b_ptr;
u32 tolerance;
u32 continuity_interval;
u32 abort_limit;
int state;
int blocked;
u32 fsm_msg_cnt;
struct {
unchar hdr[INT_H_SIZE];
unchar body[TIPC_MAX_IF_NAME];
} proto_msg;
struct tipc_msg *pmsg;
u32 priority;
u32 queue_limit[15]; /* queue_limit[0]==window limit */
/* Changeover */
u32 exp_msg_count;
u32 reset_checkpoint;
/* Max packet negotiation */
u32 max_pkt;
u32 max_pkt_target;
u32 max_pkt_probes;
/* Sending */
u32 out_queue_size;
struct sk_buff *first_out;
struct sk_buff *last_out;
u32 next_out_no;
u32 last_retransmitted;
u32 stale_count;
/* Reception */
u32 next_in_no;
u32 deferred_inqueue_sz;
struct sk_buff *oldest_deferred_in;
struct sk_buff *newest_deferred_in;
u32 unacked_window;
/* Congestion handling */
struct sk_buff *proto_msg_queue;
u32 retransm_queue_size;
u32 retransm_queue_head;
struct sk_buff *next_out;
struct list_head waiting_ports;
/* Fragmentation/defragmentation */
u32 long_msg_seq_no;
struct sk_buff *defragm_buf;
/* Statistics */
struct {
u32 sent_info; /* used in counting # sent packets */
u32 recv_info; /* used in counting # recv'd packets */
u32 sent_states;
u32 recv_states;
u32 sent_probes;
u32 recv_probes;
u32 sent_nacks;
u32 recv_nacks;
u32 sent_acks;
u32 sent_bundled;
u32 sent_bundles;
u32 recv_bundled;
u32 recv_bundles;
u32 retransmitted;
u32 sent_fragmented;
u32 sent_fragments;
u32 recv_fragmented;
u32 recv_fragments;
u32 link_congs; /* # port sends blocked by congestion */
u32 bearer_congs;
u32 deferred_recv;
u32 duplicates;
/* for statistical profiling of send queue size */
u32 max_queue_sz;
u32 accu_queue_sz;
u32 queue_sz_counts;
/* for statistical profiling of message lengths */
u32 msg_length_counts;
u32 msg_lengths_total;
u32 msg_length_profile[7];
#if 0
u32 sent_tunneled;
u32 recv_tunneled;
#endif
} stats;
struct print_buf print_buf;
};
struct port;
struct link *tipc_link_create(struct bearer *b_ptr, const u32 peer,
const struct tipc_media_addr *media_addr);
void tipc_link_delete(struct link *l_ptr);
void tipc_link_changeover(struct link *l_ptr);
void tipc_link_send_duplicate(struct link *l_ptr, struct link *dest);
void tipc_link_reset_fragments(struct link *l_ptr);
int tipc_link_is_up(struct link *l_ptr);
int tipc_link_is_active(struct link *l_ptr);
void tipc_link_start(struct link *l_ptr);
u32 tipc_link_push_packet(struct link *l_ptr);
void tipc_link_stop(struct link *l_ptr);
struct sk_buff *tipc_link_cmd_config(const void *req_tlv_area, int req_tlv_space, u16 cmd);
struct sk_buff *tipc_link_cmd_show_stats(const void *req_tlv_area, int req_tlv_space);
struct sk_buff *tipc_link_cmd_reset_stats(const void *req_tlv_area, int req_tlv_space);
void tipc_link_reset(struct link *l_ptr);
int tipc_link_send(struct sk_buff *buf, u32 dest, u32 selector);
int tipc_link_send_buf(struct link *l_ptr, struct sk_buff *buf);
u32 tipc_link_get_max_pkt(u32 dest,u32 selector);
int tipc_link_send_sections_fast(struct port* sender,
struct iovec const *msg_sect,
const u32 num_sect,
u32 destnode);
int tipc_link_send_long_buf(struct link *l_ptr, struct sk_buff *buf);
void tipc_link_tunnel(struct link *l_ptr, struct tipc_msg *tnl_hdr,
struct tipc_msg *msg, u32 selector);
void tipc_link_recv_bundle(struct sk_buff *buf);
int tipc_link_recv_fragment(struct sk_buff **pending,
struct sk_buff **fb,
struct tipc_msg **msg);
void tipc_link_send_proto_msg(struct link *l_ptr, u32 msg_typ, int prob, u32 gap,
u32 tolerance, u32 priority, u32 acked_mtu);
void tipc_link_push_queue(struct link *l_ptr);
u32 tipc_link_defer_pkt(struct sk_buff **head, struct sk_buff **tail,
struct sk_buff *buf);
void tipc_link_wakeup_ports(struct link *l_ptr, int all);
void tipc_link_set_queue_limits(struct link *l_ptr, u32 window);
void tipc_link_retransmit(struct link *l_ptr, struct sk_buff *start, u32 retransmits);
/*
* Link sequence number manipulation routines (uses modulo 2**16 arithmetic)
*/
static inline u32 mod(u32 x)
{
return x & 0xffffu;
}
static inline int between(u32 lower, u32 upper, u32 n)
{
if ((lower < n) && (n < upper))
return 1;
if ((upper < lower) && ((n > lower) || (n < upper)))
return 1;
return 0;
}
static inline int less_eq(u32 left, u32 right)
{
return (mod(right - left) < 32768u);
}
static inline int less(u32 left, u32 right)
{
return (less_eq(left, right) && (mod(right) != mod(left)));
}
static inline u32 lesser(u32 left, u32 right)
{
return less_eq(left, right) ? left : right;
}
#endif

324
kernel/net/tipc/msg.c Normal file
View File

@@ -0,0 +1,324 @@
/*
* net/tipc/msg.c: TIPC message header routines
*
* Copyright (c) 2000-2006, Ericsson AB
* Copyright (c) 2005, Wind River Systems
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. 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.
*
* Alternatively, this software may be distributed under the terms of the
* GNU General Public License ("GPL") version 2 as published by the Free
* Software Foundation.
*
* 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 "addr.h"
#include "dbg.h"
#include "msg.h"
#include "bearer.h"
#ifdef CONFIG_TIPC_DEBUG
void tipc_msg_dbg(struct print_buf *buf, struct tipc_msg *msg, const char *str)
{
u32 usr = msg_user(msg);
tipc_printf(buf, str);
switch (usr) {
case MSG_BUNDLER:
tipc_printf(buf, "BNDL::");
tipc_printf(buf, "MSGS(%u):", msg_msgcnt(msg));
break;
case BCAST_PROTOCOL:
tipc_printf(buf, "BCASTP::");
break;
case MSG_FRAGMENTER:
tipc_printf(buf, "FRAGM::");
switch (msg_type(msg)) {
case FIRST_FRAGMENT:
tipc_printf(buf, "FIRST:");
break;
case FRAGMENT:
tipc_printf(buf, "BODY:");
break;
case LAST_FRAGMENT:
tipc_printf(buf, "LAST:");
break;
default:
tipc_printf(buf, "UNKNOWN:%x",msg_type(msg));
}
tipc_printf(buf, "NO(%u/%u):",msg_long_msgno(msg),
msg_fragm_no(msg));
break;
case TIPC_LOW_IMPORTANCE:
case TIPC_MEDIUM_IMPORTANCE:
case TIPC_HIGH_IMPORTANCE:
case TIPC_CRITICAL_IMPORTANCE:
tipc_printf(buf, "DAT%u:", msg_user(msg));
if (msg_short(msg)) {
tipc_printf(buf, "CON:");
break;
}
switch (msg_type(msg)) {
case TIPC_CONN_MSG:
tipc_printf(buf, "CON:");
break;
case TIPC_MCAST_MSG:
tipc_printf(buf, "MCST:");
break;
case TIPC_NAMED_MSG:
tipc_printf(buf, "NAM:");
break;
case TIPC_DIRECT_MSG:
tipc_printf(buf, "DIR:");
break;
default:
tipc_printf(buf, "UNKNOWN TYPE %u",msg_type(msg));
}
if (msg_routed(msg) && !msg_non_seq(msg))
tipc_printf(buf, "ROUT:");
if (msg_reroute_cnt(msg))
tipc_printf(buf, "REROUTED(%u):",
msg_reroute_cnt(msg));
break;
case NAME_DISTRIBUTOR:
tipc_printf(buf, "NMD::");
switch (msg_type(msg)) {
case PUBLICATION:
tipc_printf(buf, "PUBL(%u):", (msg_size(msg) - msg_hdr_sz(msg)) / 20); /* Items */
break;
case WITHDRAWAL:
tipc_printf(buf, "WDRW:");
break;
default:
tipc_printf(buf, "UNKNOWN:%x",msg_type(msg));
}
if (msg_routed(msg))
tipc_printf(buf, "ROUT:");
if (msg_reroute_cnt(msg))
tipc_printf(buf, "REROUTED(%u):",
msg_reroute_cnt(msg));
break;
case CONN_MANAGER:
tipc_printf(buf, "CONN_MNG:");
switch (msg_type(msg)) {
case CONN_PROBE:
tipc_printf(buf, "PROBE:");
break;
case CONN_PROBE_REPLY:
tipc_printf(buf, "PROBE_REPLY:");
break;
case CONN_ACK:
tipc_printf(buf, "CONN_ACK:");
tipc_printf(buf, "ACK(%u):",msg_msgcnt(msg));
break;
default:
tipc_printf(buf, "UNKNOWN TYPE:%x",msg_type(msg));
}
if (msg_routed(msg))
tipc_printf(buf, "ROUT:");
if (msg_reroute_cnt(msg))
tipc_printf(buf, "REROUTED(%u):",msg_reroute_cnt(msg));
break;
case LINK_PROTOCOL:
tipc_printf(buf, "PROT:TIM(%u):",msg_timestamp(msg));
switch (msg_type(msg)) {
case STATE_MSG:
tipc_printf(buf, "STATE:");
tipc_printf(buf, "%s:",msg_probe(msg) ? "PRB" :"");
tipc_printf(buf, "NXS(%u):",msg_next_sent(msg));
tipc_printf(buf, "GAP(%u):",msg_seq_gap(msg));
tipc_printf(buf, "LSTBC(%u):",msg_last_bcast(msg));
break;
case RESET_MSG:
tipc_printf(buf, "RESET:");
if (msg_size(msg) != msg_hdr_sz(msg))
tipc_printf(buf, "BEAR:%s:",msg_data(msg));
break;
case ACTIVATE_MSG:
tipc_printf(buf, "ACTIVATE:");
break;
default:
tipc_printf(buf, "UNKNOWN TYPE:%x",msg_type(msg));
}
tipc_printf(buf, "PLANE(%c):",msg_net_plane(msg));
tipc_printf(buf, "SESS(%u):",msg_session(msg));
break;
case CHANGEOVER_PROTOCOL:
tipc_printf(buf, "TUNL:");
switch (msg_type(msg)) {
case DUPLICATE_MSG:
tipc_printf(buf, "DUPL:");
break;
case ORIGINAL_MSG:
tipc_printf(buf, "ORIG:");
tipc_printf(buf, "EXP(%u)",msg_msgcnt(msg));
break;
default:
tipc_printf(buf, "UNKNOWN TYPE:%x",msg_type(msg));
}
break;
case ROUTE_DISTRIBUTOR:
tipc_printf(buf, "ROUTING_MNG:");
switch (msg_type(msg)) {
case EXT_ROUTING_TABLE:
tipc_printf(buf, "EXT_TBL:");
tipc_printf(buf, "TO:%x:",msg_remote_node(msg));
break;
case LOCAL_ROUTING_TABLE:
tipc_printf(buf, "LOCAL_TBL:");
tipc_printf(buf, "TO:%x:",msg_remote_node(msg));
break;
case SLAVE_ROUTING_TABLE:
tipc_printf(buf, "DP_TBL:");
tipc_printf(buf, "TO:%x:",msg_remote_node(msg));
break;
case ROUTE_ADDITION:
tipc_printf(buf, "ADD:");
tipc_printf(buf, "TO:%x:",msg_remote_node(msg));
break;
case ROUTE_REMOVAL:
tipc_printf(buf, "REMOVE:");
tipc_printf(buf, "TO:%x:",msg_remote_node(msg));
break;
default:
tipc_printf(buf, "UNKNOWN TYPE:%x",msg_type(msg));
}
break;
case LINK_CONFIG:
tipc_printf(buf, "CFG:");
switch (msg_type(msg)) {
case DSC_REQ_MSG:
tipc_printf(buf, "DSC_REQ:");
break;
case DSC_RESP_MSG:
tipc_printf(buf, "DSC_RESP:");
break;
default:
tipc_printf(buf, "UNKNOWN TYPE:%x:",msg_type(msg));
break;
}
break;
default:
tipc_printf(buf, "UNKNOWN USER:");
}
switch (usr) {
case CONN_MANAGER:
case TIPC_LOW_IMPORTANCE:
case TIPC_MEDIUM_IMPORTANCE:
case TIPC_HIGH_IMPORTANCE:
case TIPC_CRITICAL_IMPORTANCE:
switch (msg_errcode(msg)) {
case TIPC_OK:
break;
case TIPC_ERR_NO_NAME:
tipc_printf(buf, "NO_NAME:");
break;
case TIPC_ERR_NO_PORT:
tipc_printf(buf, "NO_PORT:");
break;
case TIPC_ERR_NO_NODE:
tipc_printf(buf, "NO_PROC:");
break;
case TIPC_ERR_OVERLOAD:
tipc_printf(buf, "OVERLOAD:");
break;
case TIPC_CONN_SHUTDOWN:
tipc_printf(buf, "SHUTDOWN:");
break;
default:
tipc_printf(buf, "UNKNOWN ERROR(%x):",
msg_errcode(msg));
}
default:{}
}
tipc_printf(buf, "HZ(%u):", msg_hdr_sz(msg));
tipc_printf(buf, "SZ(%u):", msg_size(msg));
tipc_printf(buf, "SQNO(%u):", msg_seqno(msg));
if (msg_non_seq(msg))
tipc_printf(buf, "NOSEQ:");
else {
tipc_printf(buf, "ACK(%u):", msg_ack(msg));
}
tipc_printf(buf, "BACK(%u):", msg_bcast_ack(msg));
tipc_printf(buf, "PRND(%x)", msg_prevnode(msg));
if (msg_isdata(msg)) {
if (msg_named(msg)) {
tipc_printf(buf, "NTYP(%u):", msg_nametype(msg));
tipc_printf(buf, "NINST(%u)", msg_nameinst(msg));
}
}
if ((usr != LINK_PROTOCOL) && (usr != LINK_CONFIG) &&
(usr != MSG_BUNDLER)) {
if (!msg_short(msg)) {
tipc_printf(buf, ":ORIG(%x:%u):",
msg_orignode(msg), msg_origport(msg));
tipc_printf(buf, ":DEST(%x:%u):",
msg_destnode(msg), msg_destport(msg));
} else {
tipc_printf(buf, ":OPRT(%u):", msg_origport(msg));
tipc_printf(buf, ":DPRT(%u):", msg_destport(msg));
}
if (msg_routed(msg) && !msg_non_seq(msg))
tipc_printf(buf, ":TSEQN(%u)", msg_transp_seqno(msg));
}
if (msg_user(msg) == NAME_DISTRIBUTOR) {
tipc_printf(buf, ":ONOD(%x):", msg_orignode(msg));
tipc_printf(buf, ":DNOD(%x):", msg_destnode(msg));
if (msg_routed(msg)) {
tipc_printf(buf, ":CSEQN(%u)", msg_transp_seqno(msg));
}
}
if (msg_user(msg) == LINK_CONFIG) {
u32* raw = (u32*)msg;
struct tipc_media_addr* orig = (struct tipc_media_addr*)&raw[5];
tipc_printf(buf, ":REQL(%u):", msg_req_links(msg));
tipc_printf(buf, ":DDOM(%x):", msg_dest_domain(msg));
tipc_printf(buf, ":NETID(%u):", msg_bc_netid(msg));
tipc_media_addr_printf(buf, orig);
}
if (msg_user(msg) == BCAST_PROTOCOL) {
tipc_printf(buf, "BCNACK:AFTER(%u):", msg_bcgap_after(msg));
tipc_printf(buf, "TO(%u):", msg_bcgap_to(msg));
}
tipc_printf(buf, "\n");
if ((usr == CHANGEOVER_PROTOCOL) && (msg_msgcnt(msg))) {
tipc_msg_dbg(buf, msg_get_wrapped(msg), " /");
}
if ((usr == MSG_FRAGMENTER) && (msg_type(msg) == FIRST_FRAGMENT)) {
tipc_msg_dbg(buf, msg_get_wrapped(msg), " /");
}
}
#endif

816
kernel/net/tipc/msg.h Normal file
View File

@@ -0,0 +1,816 @@
/*
* net/tipc/msg.h: Include file for TIPC message header routines
*
* Copyright (c) 2000-2007, Ericsson AB
* Copyright (c) 2005-2008, Wind River Systems
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. 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.
*
* Alternatively, this software may be distributed under the terms of the
* GNU General Public License ("GPL") version 2 as published by the Free
* Software Foundation.
*
* 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_MSG_H
#define _TIPC_MSG_H
#include "core.h"
#define TIPC_VERSION 2
#define SHORT_H_SIZE 24 /* Connected, in-cluster messages */
#define DIR_MSG_H_SIZE 32 /* Directly addressed messages */
#define LONG_H_SIZE 40 /* Named messages */
#define MCAST_H_SIZE 44 /* Multicast messages */
#define INT_H_SIZE 40 /* Internal messages */
#define MIN_H_SIZE 24 /* Smallest legal TIPC header size */
#define MAX_H_SIZE 60 /* Largest possible TIPC header size */
#define MAX_MSG_SIZE (MAX_H_SIZE + TIPC_MAX_USER_MSG_SIZE)
/*
TIPC user data message header format, version 2
- Fundamental definitions available to privileged TIPC users
are located in tipc_msg.h.
- Remaining definitions available to TIPC internal users appear below.
*/
static inline void msg_set_word(struct tipc_msg *m, u32 w, u32 val)
{
m->hdr[w] = htonl(val);
}
static inline void msg_set_bits(struct tipc_msg *m, u32 w,
u32 pos, u32 mask, u32 val)
{
val = (val & mask) << pos;
mask = mask << pos;
m->hdr[w] &= ~htonl(mask);
m->hdr[w] |= htonl(val);
}
static inline void msg_swap_words(struct tipc_msg *msg, u32 a, u32 b)
{
u32 temp = msg->hdr[a];
msg->hdr[a] = msg->hdr[b];
msg->hdr[b] = temp;
}
/*
* Word 0
*/
static inline u32 msg_version(struct tipc_msg *m)
{
return msg_bits(m, 0, 29, 7);
}
static inline void msg_set_version(struct tipc_msg *m)
{
msg_set_bits(m, 0, 29, 7, TIPC_VERSION);
}
static inline u32 msg_user(struct tipc_msg *m)
{
return msg_bits(m, 0, 25, 0xf);
}
static inline u32 msg_isdata(struct tipc_msg *m)
{
return (msg_user(m) <= TIPC_CRITICAL_IMPORTANCE);
}
static inline void msg_set_user(struct tipc_msg *m, u32 n)
{
msg_set_bits(m, 0, 25, 0xf, n);
}
static inline void msg_set_importance(struct tipc_msg *m, u32 i)
{
msg_set_user(m, i);
}
static inline void msg_set_hdr_sz(struct tipc_msg *m,u32 n)
{
msg_set_bits(m, 0, 21, 0xf, n>>2);
}
static inline int msg_non_seq(struct tipc_msg *m)
{
return msg_bits(m, 0, 20, 1);
}
static inline void msg_set_non_seq(struct tipc_msg *m, u32 n)
{
msg_set_bits(m, 0, 20, 1, n);
}
static inline int msg_dest_droppable(struct tipc_msg *m)
{
return msg_bits(m, 0, 19, 1);
}
static inline void msg_set_dest_droppable(struct tipc_msg *m, u32 d)
{
msg_set_bits(m, 0, 19, 1, d);
}
static inline int msg_src_droppable(struct tipc_msg *m)
{
return msg_bits(m, 0, 18, 1);
}
static inline void msg_set_src_droppable(struct tipc_msg *m, u32 d)
{
msg_set_bits(m, 0, 18, 1, d);
}
static inline void msg_set_size(struct tipc_msg *m, u32 sz)
{
m->hdr[0] = htonl((msg_word(m, 0) & ~0x1ffff) | sz);
}
/*
* Word 1
*/
static inline void msg_set_type(struct tipc_msg *m, u32 n)
{
msg_set_bits(m, 1, 29, 0x7, n);
}
static inline void msg_set_errcode(struct tipc_msg *m, u32 err)
{
msg_set_bits(m, 1, 25, 0xf, err);
}
static inline u32 msg_reroute_cnt(struct tipc_msg *m)
{
return msg_bits(m, 1, 21, 0xf);
}
static inline void msg_incr_reroute_cnt(struct tipc_msg *m)
{
msg_set_bits(m, 1, 21, 0xf, msg_reroute_cnt(m) + 1);
}
static inline void msg_reset_reroute_cnt(struct tipc_msg *m)
{
msg_set_bits(m, 1, 21, 0xf, 0);
}
static inline u32 msg_lookup_scope(struct tipc_msg *m)
{
return msg_bits(m, 1, 19, 0x3);
}
static inline void msg_set_lookup_scope(struct tipc_msg *m, u32 n)
{
msg_set_bits(m, 1, 19, 0x3, n);
}
static inline u32 msg_bcast_ack(struct tipc_msg *m)
{
return msg_bits(m, 1, 0, 0xffff);
}
static inline void msg_set_bcast_ack(struct tipc_msg *m, u32 n)
{
msg_set_bits(m, 1, 0, 0xffff, n);
}
/*
* Word 2
*/
static inline u32 msg_ack(struct tipc_msg *m)
{
return msg_bits(m, 2, 16, 0xffff);
}
static inline void msg_set_ack(struct tipc_msg *m, u32 n)
{
msg_set_bits(m, 2, 16, 0xffff, n);
}
static inline u32 msg_seqno(struct tipc_msg *m)
{
return msg_bits(m, 2, 0, 0xffff);
}
static inline void msg_set_seqno(struct tipc_msg *m, u32 n)
{
msg_set_bits(m, 2, 0, 0xffff, n);
}
/*
* TIPC may utilize the "link ack #" and "link seq #" fields of a short
* message header to hold the destination node for the message, since the
* normal "dest node" field isn't present. This cache is only referenced
* when required, so populating the cache of a longer message header is
* harmless (as long as the header has the two link sequence fields present).
*
* Note: Host byte order is OK here, since the info never goes off-card.
*/
static inline u32 msg_destnode_cache(struct tipc_msg *m)
{
return m->hdr[2];
}
static inline void msg_set_destnode_cache(struct tipc_msg *m, u32 dnode)
{
m->hdr[2] = dnode;
}
/*
* Words 3-10
*/
static inline void msg_set_prevnode(struct tipc_msg *m, u32 a)
{
msg_set_word(m, 3, a);
}
static inline void msg_set_origport(struct tipc_msg *m, u32 p)
{
msg_set_word(m, 4, p);
}
static inline void msg_set_destport(struct tipc_msg *m, u32 p)
{
msg_set_word(m, 5, p);
}
static inline void msg_set_mc_netid(struct tipc_msg *m, u32 p)
{
msg_set_word(m, 5, p);
}
static inline void msg_set_orignode(struct tipc_msg *m, u32 a)
{
msg_set_word(m, 6, a);
}
static inline void msg_set_destnode(struct tipc_msg *m, u32 a)
{
msg_set_word(m, 7, a);
}
static inline int msg_is_dest(struct tipc_msg *m, u32 d)
{
return(msg_short(m) || (msg_destnode(m) == d));
}
static inline u32 msg_routed(struct tipc_msg *m)
{
if (likely(msg_short(m)))
return 0;
return(msg_destnode(m) ^ msg_orignode(m)) >> 11;
}
static inline void msg_set_nametype(struct tipc_msg *m, u32 n)
{
msg_set_word(m, 8, n);
}
static inline u32 msg_transp_seqno(struct tipc_msg *m)
{
return msg_word(m, 8);
}
static inline void msg_set_timestamp(struct tipc_msg *m, u32 n)
{
msg_set_word(m, 8, n);
}
static inline u32 msg_timestamp(struct tipc_msg *m)
{
return msg_word(m, 8);
}
static inline void msg_set_transp_seqno(struct tipc_msg *m, u32 n)
{
msg_set_word(m, 8, n);
}
static inline void msg_set_namelower(struct tipc_msg *m, u32 n)
{
msg_set_word(m, 9, n);
}
static inline void msg_set_nameinst(struct tipc_msg *m, u32 n)
{
msg_set_namelower(m, n);
}
static inline void msg_set_nameupper(struct tipc_msg *m, u32 n)
{
msg_set_word(m, 10, n);
}
static inline struct tipc_msg *msg_get_wrapped(struct tipc_msg *m)
{
return (struct tipc_msg *)msg_data(m);
}
/*
TIPC internal message header format, version 2
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
w0:|vers |msg usr|hdr sz |n|resrv| packet size |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
w1:|m typ| sequence gap | broadcast ack no |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
w2:| link level ack no/bc_gap_from | seq no / bcast_gap_to |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
w3:| previous node |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
w4:| next sent broadcast/fragm no | next sent pkt/ fragm msg no |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
w5:| session no |rsv=0|r|berid|link prio|netpl|p|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
w6:| originating node |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
w7:| destination node |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
w8:| transport sequence number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
w9:| msg count / bcast tag | link tolerance |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
\ \
/ User Specific Data /
\ \
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
NB: CONN_MANAGER use data message format. LINK_CONFIG has own format.
*/
/*
* Internal users
*/
#define BCAST_PROTOCOL 5
#define MSG_BUNDLER 6
#define LINK_PROTOCOL 7
#define CONN_MANAGER 8
#define ROUTE_DISTRIBUTOR 9
#define CHANGEOVER_PROTOCOL 10
#define NAME_DISTRIBUTOR 11
#define MSG_FRAGMENTER 12
#define LINK_CONFIG 13
#define DSC_H_SIZE 40
/*
* Connection management protocol messages
*/
#define CONN_PROBE 0
#define CONN_PROBE_REPLY 1
#define CONN_ACK 2
/*
* Name distributor messages
*/
#define PUBLICATION 0
#define WITHDRAWAL 1
/*
* Word 1
*/
static inline u32 msg_seq_gap(struct tipc_msg *m)
{
return msg_bits(m, 1, 16, 0x1fff);
}
static inline void msg_set_seq_gap(struct tipc_msg *m, u32 n)
{
msg_set_bits(m, 1, 16, 0x1fff, n);
}
static inline u32 msg_req_links(struct tipc_msg *m)
{
return msg_bits(m, 1, 16, 0xfff);
}
static inline void msg_set_req_links(struct tipc_msg *m, u32 n)
{
msg_set_bits(m, 1, 16, 0xfff, n);
}
/*
* Word 2
*/
static inline u32 msg_dest_domain(struct tipc_msg *m)
{
return msg_word(m, 2);
}
static inline void msg_set_dest_domain(struct tipc_msg *m, u32 n)
{
msg_set_word(m, 2, n);
}
static inline u32 msg_bcgap_after(struct tipc_msg *m)
{
return msg_bits(m, 2, 16, 0xffff);
}
static inline void msg_set_bcgap_after(struct tipc_msg *m, u32 n)
{
msg_set_bits(m, 2, 16, 0xffff, n);
}
static inline u32 msg_bcgap_to(struct tipc_msg *m)
{
return msg_bits(m, 2, 0, 0xffff);
}
static inline void msg_set_bcgap_to(struct tipc_msg *m, u32 n)
{
msg_set_bits(m, 2, 0, 0xffff, n);
}
/*
* Word 4
*/
static inline u32 msg_last_bcast(struct tipc_msg *m)
{
return msg_bits(m, 4, 16, 0xffff);
}
static inline void msg_set_last_bcast(struct tipc_msg *m, u32 n)
{
msg_set_bits(m, 4, 16, 0xffff, n);
}
static inline u32 msg_fragm_no(struct tipc_msg *m)
{
return msg_bits(m, 4, 16, 0xffff);
}
static inline void msg_set_fragm_no(struct tipc_msg *m, u32 n)
{
msg_set_bits(m, 4, 16, 0xffff, n);
}
static inline u32 msg_next_sent(struct tipc_msg *m)
{
return msg_bits(m, 4, 0, 0xffff);
}
static inline void msg_set_next_sent(struct tipc_msg *m, u32 n)
{
msg_set_bits(m, 4, 0, 0xffff, n);
}
static inline u32 msg_long_msgno(struct tipc_msg *m)
{
return msg_bits(m, 4, 0, 0xffff);
}
static inline void msg_set_long_msgno(struct tipc_msg *m, u32 n)
{
msg_set_bits(m, 4, 0, 0xffff, n);
}
static inline u32 msg_bc_netid(struct tipc_msg *m)
{
return msg_word(m, 4);
}
static inline void msg_set_bc_netid(struct tipc_msg *m, u32 id)
{
msg_set_word(m, 4, id);
}
static inline u32 msg_link_selector(struct tipc_msg *m)
{
return msg_bits(m, 4, 0, 1);
}
static inline void msg_set_link_selector(struct tipc_msg *m, u32 n)
{
msg_set_bits(m, 4, 0, 1, (n & 1));
}
/*
* Word 5
*/
static inline u32 msg_session(struct tipc_msg *m)
{
return msg_bits(m, 5, 16, 0xffff);
}
static inline void msg_set_session(struct tipc_msg *m, u32 n)
{
msg_set_bits(m, 5, 16, 0xffff, n);
}
static inline u32 msg_probe(struct tipc_msg *m)
{
return msg_bits(m, 5, 0, 1);
}
static inline void msg_set_probe(struct tipc_msg *m, u32 val)
{
msg_set_bits(m, 5, 0, 1, (val & 1));
}
static inline char msg_net_plane(struct tipc_msg *m)
{
return msg_bits(m, 5, 1, 7) + 'A';
}
static inline void msg_set_net_plane(struct tipc_msg *m, char n)
{
msg_set_bits(m, 5, 1, 7, (n - 'A'));
}
static inline u32 msg_linkprio(struct tipc_msg *m)
{
return msg_bits(m, 5, 4, 0x1f);
}
static inline void msg_set_linkprio(struct tipc_msg *m, u32 n)
{
msg_set_bits(m, 5, 4, 0x1f, n);
}
static inline u32 msg_bearer_id(struct tipc_msg *m)
{
return msg_bits(m, 5, 9, 0x7);
}
static inline void msg_set_bearer_id(struct tipc_msg *m, u32 n)
{
msg_set_bits(m, 5, 9, 0x7, n);
}
static inline u32 msg_redundant_link(struct tipc_msg *m)
{
return msg_bits(m, 5, 12, 0x1);
}
static inline void msg_set_redundant_link(struct tipc_msg *m)
{
msg_set_bits(m, 5, 12, 0x1, 1);
}
static inline void msg_clear_redundant_link(struct tipc_msg *m)
{
msg_set_bits(m, 5, 12, 0x1, 0);
}
/*
* Word 9
*/
static inline u32 msg_msgcnt(struct tipc_msg *m)
{
return msg_bits(m, 9, 16, 0xffff);
}
static inline void msg_set_msgcnt(struct tipc_msg *m, u32 n)
{
msg_set_bits(m, 9, 16, 0xffff, n);
}
static inline u32 msg_bcast_tag(struct tipc_msg *m)
{
return msg_bits(m, 9, 16, 0xffff);
}
static inline void msg_set_bcast_tag(struct tipc_msg *m, u32 n)
{
msg_set_bits(m, 9, 16, 0xffff, n);
}
static inline u32 msg_max_pkt(struct tipc_msg *m)
{
return (msg_bits(m, 9, 16, 0xffff) * 4);
}
static inline void msg_set_max_pkt(struct tipc_msg *m, u32 n)
{
msg_set_bits(m, 9, 16, 0xffff, (n / 4));
}
static inline u32 msg_link_tolerance(struct tipc_msg *m)
{
return msg_bits(m, 9, 0, 0xffff);
}
static inline void msg_set_link_tolerance(struct tipc_msg *m, u32 n)
{
msg_set_bits(m, 9, 0, 0xffff, n);
}
/*
* Routing table message data
*/
static inline u32 msg_remote_node(struct tipc_msg *m)
{
return msg_word(m, msg_hdr_sz(m)/4);
}
static inline void msg_set_remote_node(struct tipc_msg *m, u32 a)
{
msg_set_word(m, msg_hdr_sz(m)/4, a);
}
static inline void msg_set_dataoctet(struct tipc_msg *m, u32 pos)
{
msg_data(m)[pos + 4] = 1;
}
/*
* Segmentation message types
*/
#define FIRST_FRAGMENT 0
#define FRAGMENT 1
#define LAST_FRAGMENT 2
/*
* Link management protocol message types
*/
#define STATE_MSG 0
#define RESET_MSG 1
#define ACTIVATE_MSG 2
/*
* Changeover tunnel message types
*/
#define DUPLICATE_MSG 0
#define ORIGINAL_MSG 1
/*
* Routing table message types
*/
#define EXT_ROUTING_TABLE 0
#define LOCAL_ROUTING_TABLE 1
#define SLAVE_ROUTING_TABLE 2
#define ROUTE_ADDITION 3
#define ROUTE_REMOVAL 4
/*
* Config protocol message types
*/
#define DSC_REQ_MSG 0
#define DSC_RESP_MSG 1
static inline u32 msg_tot_importance(struct tipc_msg *m)
{
if (likely(msg_isdata(m))) {
if (likely(msg_orignode(m) == tipc_own_addr))
return msg_importance(m);
return msg_importance(m) + 4;
}
if ((msg_user(m) == MSG_FRAGMENTER) &&
(msg_type(m) == FIRST_FRAGMENT))
return msg_importance(msg_get_wrapped(m));
return msg_importance(m);
}
static inline void msg_init(struct tipc_msg *m, u32 user, u32 type,
u32 hsize, u32 destnode)
{
memset(m, 0, hsize);
msg_set_version(m);
msg_set_user(m, user);
msg_set_hdr_sz(m, hsize);
msg_set_size(m, hsize);
msg_set_prevnode(m, tipc_own_addr);
msg_set_type(m, type);
if (!msg_short(m)) {
msg_set_orignode(m, tipc_own_addr);
msg_set_destnode(m, destnode);
}
}
/**
* msg_calc_data_size - determine total data size for message
*/
static inline int msg_calc_data_size(struct iovec const *msg_sect, u32 num_sect)
{
int dsz = 0;
int i;
for (i = 0; i < num_sect; i++)
dsz += msg_sect[i].iov_len;
return dsz;
}
/**
* msg_build - create message using specified header and data
*
* Note: Caller must not hold any locks in case copy_from_user() is interrupted!
*
* Returns message data size or errno
*/
static inline int msg_build(struct tipc_msg *hdr,
struct iovec const *msg_sect, u32 num_sect,
int max_size, int usrmem, struct sk_buff** buf)
{
int dsz, sz, hsz, pos, res, cnt;
dsz = msg_calc_data_size(msg_sect, num_sect);
if (unlikely(dsz > TIPC_MAX_USER_MSG_SIZE)) {
*buf = NULL;
return -EINVAL;
}
pos = hsz = msg_hdr_sz(hdr);
sz = hsz + dsz;
msg_set_size(hdr, sz);
if (unlikely(sz > max_size)) {
*buf = NULL;
return dsz;
}
*buf = buf_acquire(sz);
if (!(*buf))
return -ENOMEM;
skb_copy_to_linear_data(*buf, hdr, hsz);
for (res = 1, cnt = 0; res && (cnt < num_sect); cnt++) {
if (likely(usrmem))
res = !copy_from_user((*buf)->data + pos,
msg_sect[cnt].iov_base,
msg_sect[cnt].iov_len);
else
skb_copy_to_linear_data_offset(*buf, pos,
msg_sect[cnt].iov_base,
msg_sect[cnt].iov_len);
pos += msg_sect[cnt].iov_len;
}
if (likely(res))
return dsz;
buf_discard(*buf);
*buf = NULL;
return -EFAULT;
}
static inline void msg_set_media_addr(struct tipc_msg *m, struct tipc_media_addr *a)
{
memcpy(&((int *)m)[5], a, sizeof(*a));
}
static inline void msg_get_media_addr(struct tipc_msg *m, struct tipc_media_addr *a)
{
memcpy(a, &((int*)m)[5], sizeof(*a));
}
#endif

View File

@@ -0,0 +1,318 @@
/*
* net/tipc/name_distr.c: TIPC name distribution code
*
* Copyright (c) 2000-2006, Ericsson AB
* Copyright (c) 2005, Wind River Systems
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. 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.
*
* Alternatively, this software may be distributed under the terms of the
* GNU General Public License ("GPL") version 2 as published by the Free
* Software Foundation.
*
* 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 "cluster.h"
#include "dbg.h"
#include "link.h"
#include "msg.h"
#include "name_distr.h"
#define ITEM_SIZE sizeof(struct distr_item)
/**
* struct distr_item - publication info distributed to other nodes
* @type: name sequence type
* @lower: name sequence lower bound
* @upper: name sequence upper bound
* @ref: publishing port reference
* @key: publication key
*
* ===> All fields are stored in network byte order. <===
*
* First 3 fields identify (name or) name sequence being published.
* Reference field uniquely identifies port that published name sequence.
* Key field uniquely identifies publication, in the event a port has
* multiple publications of the same name sequence.
*
* Note: There is no field that identifies the publishing node because it is
* the same for all items contained within a publication message.
*/
struct distr_item {
__be32 type;
__be32 lower;
__be32 upper;
__be32 ref;
__be32 key;
};
/**
* List of externally visible publications by this node --
* that is, all publications having scope > TIPC_NODE_SCOPE.
*/
static LIST_HEAD(publ_root);
static u32 publ_cnt = 0;
/**
* publ_to_item - add publication info to a publication message
*/
static void publ_to_item(struct distr_item *i, struct publication *p)
{
i->type = htonl(p->type);
i->lower = htonl(p->lower);
i->upper = htonl(p->upper);
i->ref = htonl(p->ref);
i->key = htonl(p->key);
dbg("publ_to_item: %u, %u, %u\n", p->type, p->lower, p->upper);
}
/**
* named_prepare_buf - allocate & initialize a publication message
*/
static struct sk_buff *named_prepare_buf(u32 type, u32 size, u32 dest)
{
struct sk_buff *buf = buf_acquire(LONG_H_SIZE + size);
struct tipc_msg *msg;
if (buf != NULL) {
msg = buf_msg(buf);
msg_init(msg, NAME_DISTRIBUTOR, type, LONG_H_SIZE, dest);
msg_set_size(msg, LONG_H_SIZE + size);
}
return buf;
}
/**
* tipc_named_publish - tell other nodes about a new publication by this node
*/
void tipc_named_publish(struct publication *publ)
{
struct sk_buff *buf;
struct distr_item *item;
list_add_tail(&publ->local_list, &publ_root);
publ_cnt++;
buf = named_prepare_buf(PUBLICATION, ITEM_SIZE, 0);
if (!buf) {
warn("Publication distribution failure\n");
return;
}
item = (struct distr_item *)msg_data(buf_msg(buf));
publ_to_item(item, publ);
dbg("tipc_named_withdraw: broadcasting publish msg\n");
tipc_cltr_broadcast(buf);
}
/**
* tipc_named_withdraw - tell other nodes about a withdrawn publication by this node
*/
void tipc_named_withdraw(struct publication *publ)
{
struct sk_buff *buf;
struct distr_item *item;
list_del(&publ->local_list);
publ_cnt--;
buf = named_prepare_buf(WITHDRAWAL, ITEM_SIZE, 0);
if (!buf) {
warn("Withdrawl distribution failure\n");
return;
}
item = (struct distr_item *)msg_data(buf_msg(buf));
publ_to_item(item, publ);
dbg("tipc_named_withdraw: broadcasting withdraw msg\n");
tipc_cltr_broadcast(buf);
}
/**
* tipc_named_node_up - tell specified node about all publications by this node
*/
void tipc_named_node_up(unsigned long node)
{
struct publication *publ;
struct distr_item *item = NULL;
struct sk_buff *buf = NULL;
u32 left = 0;
u32 rest;
u32 max_item_buf;
read_lock_bh(&tipc_nametbl_lock);
max_item_buf = TIPC_MAX_USER_MSG_SIZE / ITEM_SIZE;
max_item_buf *= ITEM_SIZE;
rest = publ_cnt * ITEM_SIZE;
list_for_each_entry(publ, &publ_root, local_list) {
if (!buf) {
left = (rest <= max_item_buf) ? rest : max_item_buf;
rest -= left;
buf = named_prepare_buf(PUBLICATION, left, node);
if (!buf) {
warn("Bulk publication distribution failure\n");
goto exit;
}
item = (struct distr_item *)msg_data(buf_msg(buf));
}
publ_to_item(item, publ);
item++;
left -= ITEM_SIZE;
if (!left) {
msg_set_link_selector(buf_msg(buf), node);
dbg("tipc_named_node_up: sending publish msg to "
"<%u.%u.%u>\n", tipc_zone(node),
tipc_cluster(node), tipc_node(node));
tipc_link_send(buf, node, node);
buf = NULL;
}
}
exit:
read_unlock_bh(&tipc_nametbl_lock);
}
/**
* node_is_down - remove publication associated with a failed node
*
* Invoked for each publication issued by a newly failed node.
* Removes publication structure from name table & deletes it.
* In rare cases the link may have come back up again when this
* function is called, and we have two items representing the same
* publication. Nudge this item's key to distinguish it from the other.
* (Note: Publication's node subscription is already unsubscribed.)
*/
static void node_is_down(struct publication *publ)
{
struct publication *p;
write_lock_bh(&tipc_nametbl_lock);
dbg("node_is_down: withdrawing %u, %u, %u\n",
publ->type, publ->lower, publ->upper);
publ->key += 1222345;
p = tipc_nametbl_remove_publ(publ->type, publ->lower,
publ->node, publ->ref, publ->key);
write_unlock_bh(&tipc_nametbl_lock);
if (p != publ) {
err("Unable to remove publication from failed node\n"
"(type=%u, lower=%u, node=0x%x, ref=%u, key=%u)\n",
publ->type, publ->lower, publ->node, publ->ref, publ->key);
}
if (p) {
kfree(p);
}
}
/**
* tipc_named_recv - process name table update message sent by another node
*/
void tipc_named_recv(struct sk_buff *buf)
{
struct publication *publ;
struct tipc_msg *msg = buf_msg(buf);
struct distr_item *item = (struct distr_item *)msg_data(msg);
u32 count = msg_data_sz(msg) / ITEM_SIZE;
write_lock_bh(&tipc_nametbl_lock);
while (count--) {
if (msg_type(msg) == PUBLICATION) {
dbg("tipc_named_recv: got publication for %u, %u, %u\n",
ntohl(item->type), ntohl(item->lower),
ntohl(item->upper));
publ = tipc_nametbl_insert_publ(ntohl(item->type),
ntohl(item->lower),
ntohl(item->upper),
TIPC_CLUSTER_SCOPE,
msg_orignode(msg),
ntohl(item->ref),
ntohl(item->key));
if (publ) {
tipc_nodesub_subscribe(&publ->subscr,
msg_orignode(msg),
publ,
(net_ev_handler)node_is_down);
}
} else if (msg_type(msg) == WITHDRAWAL) {
dbg("tipc_named_recv: got withdrawl for %u, %u, %u\n",
ntohl(item->type), ntohl(item->lower),
ntohl(item->upper));
publ = tipc_nametbl_remove_publ(ntohl(item->type),
ntohl(item->lower),
msg_orignode(msg),
ntohl(item->ref),
ntohl(item->key));
if (publ) {
tipc_nodesub_unsubscribe(&publ->subscr);
kfree(publ);
} else {
err("Unable to remove publication by node 0x%x\n"
"(type=%u, lower=%u, ref=%u, key=%u)\n",
msg_orignode(msg),
ntohl(item->type), ntohl(item->lower),
ntohl(item->ref), ntohl(item->key));
}
} else {
warn("Unrecognized name table message received\n");
}
item++;
}
write_unlock_bh(&tipc_nametbl_lock);
buf_discard(buf);
}
/**
* tipc_named_reinit - re-initialize local publication list
*
* This routine is called whenever TIPC networking is (re)enabled.
* All existing publications by this node that have "cluster" or "zone" scope
* are updated to reflect the node's current network address.
* (If the node's address is unchanged, the update loop terminates immediately.)
*/
void tipc_named_reinit(void)
{
struct publication *publ;
write_lock_bh(&tipc_nametbl_lock);
list_for_each_entry(publ, &publ_root, local_list) {
if (publ->node == tipc_own_addr)
break;
publ->node = tipc_own_addr;
}
write_unlock_bh(&tipc_nametbl_lock);
}

View File

@@ -0,0 +1,48 @@
/*
* net/tipc/name_distr.h: Include file for TIPC name distribution code
*
* Copyright (c) 2000-2006, Ericsson AB
* Copyright (c) 2005, Wind River Systems
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. 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.
*
* Alternatively, this software may be distributed under the terms of the
* GNU General Public License ("GPL") version 2 as published by the Free
* Software Foundation.
*
* 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_NAME_DISTR_H
#define _TIPC_NAME_DISTR_H
#include "name_table.h"
void tipc_named_publish(struct publication *publ);
void tipc_named_withdraw(struct publication *publ);
void tipc_named_node_up(unsigned long node);
void tipc_named_recv(struct sk_buff *buf);
void tipc_named_reinit(void);
#endif

1104
kernel/net/tipc/name_table.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,108 @@
/*
* net/tipc/name_table.h: Include file for TIPC name table code
*
* Copyright (c) 2000-2006, Ericsson AB
* Copyright (c) 2004-2005, Wind River Systems
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. 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.
*
* Alternatively, this software may be distributed under the terms of the
* GNU General Public License ("GPL") version 2 as published by the Free
* Software Foundation.
*
* 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_NAME_TABLE_H
#define _TIPC_NAME_TABLE_H
#include "node_subscr.h"
struct subscription;
struct port_list;
/*
* TIPC name types reserved for internal TIPC use (both current and planned)
*/
#define TIPC_ZM_SRV 3 /* zone master service name type */
/**
* struct publication - info about a published (name or) name sequence
* @type: name sequence type
* @lower: name sequence lower bound
* @upper: name sequence upper bound
* @scope: scope of publication
* @node: network address of publishing port's node
* @ref: publishing port
* @key: publication key
* @subscr: subscription to "node down" event (for off-node publications only)
* @local_list: adjacent entries in list of publications made by this node
* @pport_list: adjacent entries in list of publications made by this port
* @node_list: next matching name seq publication with >= node scope
* @cluster_list: next matching name seq publication with >= cluster scope
* @zone_list: next matching name seq publication with >= zone scope
*
* Note that the node list, cluster list, and zone list are circular lists.
*/
struct publication {
u32 type;
u32 lower;
u32 upper;
u32 scope;
u32 node;
u32 ref;
u32 key;
struct tipc_node_subscr subscr;
struct list_head local_list;
struct list_head pport_list;
struct publication *node_list_next;
struct publication *cluster_list_next;
struct publication *zone_list_next;
};
extern rwlock_t tipc_nametbl_lock;
struct sk_buff *tipc_nametbl_get(const void *req_tlv_area, int req_tlv_space);
u32 tipc_nametbl_translate(u32 type, u32 instance, u32 *node);
int tipc_nametbl_mc_translate(u32 type, u32 lower, u32 upper, u32 limit,
struct port_list *dports);
int tipc_nametbl_publish_rsv(u32 ref, unsigned int scope,
struct tipc_name_seq const *seq);
struct publication *tipc_nametbl_publish(u32 type, u32 lower, u32 upper,
u32 scope, u32 port_ref, u32 key);
int tipc_nametbl_withdraw(u32 type, u32 lower, u32 ref, u32 key);
struct publication *tipc_nametbl_insert_publ(u32 type, u32 lower, u32 upper,
u32 scope, u32 node, u32 ref, u32 key);
struct publication *tipc_nametbl_remove_publ(u32 type, u32 lower,
u32 node, u32 ref, u32 key);
void tipc_nametbl_subscribe(struct subscription *s);
void tipc_nametbl_unsubscribe(struct subscription *s);
int tipc_nametbl_init(void);
void tipc_nametbl_stop(void);
#endif

296
kernel/net/tipc/net.c Normal file
View File

@@ -0,0 +1,296 @@
/*
* net/tipc/net.c: TIPC network routing code
*
* Copyright (c) 1995-2006, Ericsson AB
* Copyright (c) 2005, Wind River Systems
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. 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.
*
* Alternatively, this software may be distributed under the terms of the
* GNU General Public License ("GPL") version 2 as published by the Free
* Software Foundation.
*
* 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 "bearer.h"
#include "net.h"
#include "zone.h"
#include "addr.h"
#include "name_table.h"
#include "name_distr.h"
#include "subscr.h"
#include "link.h"
#include "msg.h"
#include "port.h"
#include "bcast.h"
#include "discover.h"
#include "config.h"
/*
* The TIPC locking policy is designed to ensure a very fine locking
* granularity, permitting complete parallel access to individual
* port and node/link instances. The code consists of three major
* locking domains, each protected with their own disjunct set of locks.
*
* 1: The routing hierarchy.
* Comprises the structures 'zone', 'cluster', 'node', 'link'
* and 'bearer'. The whole hierarchy is protected by a big
* read/write lock, tipc_net_lock, to enssure that nothing is added
* or removed while code is accessing any of these structures.
* This layer must not be called from the two others while they
* hold any of their own locks.
* Neither must it itself do any upcalls to the other two before
* it has released tipc_net_lock and other protective locks.
*
* Within the tipc_net_lock domain there are two sub-domains;'node' and
* 'bearer', where local write operations are permitted,
* provided that those are protected by individual spin_locks
* per instance. Code holding tipc_net_lock(read) and a node spin_lock
* is permitted to poke around in both the node itself and its
* subordinate links. I.e, it can update link counters and queues,
* change link state, send protocol messages, and alter the
* "active_links" array in the node; but it can _not_ remove a link
* or a node from the overall structure.
* Correspondingly, individual bearers may change status within a
* tipc_net_lock(read), protected by an individual spin_lock ber bearer
* instance, but it needs tipc_net_lock(write) to remove/add any bearers.
*
*
* 2: The transport level of the protocol.
* This consists of the structures port, (and its user level
* representations, such as user_port and tipc_sock), reference and
* tipc_user (port.c, reg.c, socket.c).
*
* This layer has four different locks:
* - The tipc_port spin_lock. This is protecting each port instance
* from parallel data access and removal. Since we can not place
* this lock in the port itself, it has been placed in the
* corresponding reference table entry, which has the same life
* cycle as the module. This entry is difficult to access from
* outside the TIPC core, however, so a pointer to the lock has
* been added in the port instance, -to be used for unlocking
* only.
* - A read/write lock to protect the reference table itself (teg.c).
* (Nobody is using read-only access to this, so it can just as
* well be changed to a spin_lock)
* - A spin lock to protect the registry of kernel/driver users (reg.c)
* - A global spin_lock (tipc_port_lock), which only task is to ensure
* consistency where more than one port is involved in an operation,
* i.e., whe a port is part of a linked list of ports.
* There are two such lists; 'port_list', which is used for management,
* and 'wait_list', which is used to queue ports during congestion.
*
* 3: The name table (name_table.c, name_distr.c, subscription.c)
* - There is one big read/write-lock (tipc_nametbl_lock) protecting the
* overall name table structure. Nothing must be added/removed to
* this structure without holding write access to it.
* - There is one local spin_lock per sub_sequence, which can be seen
* as a sub-domain to the tipc_nametbl_lock domain. It is used only
* for translation operations, and is needed because a translation
* steps the root of the 'publication' linked list between each lookup.
* This is always used within the scope of a tipc_nametbl_lock(read).
* - A local spin_lock protecting the queue of subscriber events.
*/
DEFINE_RWLOCK(tipc_net_lock);
struct _zone *tipc_zones[256] = { NULL, };
struct network tipc_net = { tipc_zones };
struct tipc_node *tipc_net_select_remote_node(u32 addr, u32 ref)
{
return tipc_zone_select_remote_node(tipc_net.zones[tipc_zone(addr)], addr, ref);
}
u32 tipc_net_select_router(u32 addr, u32 ref)
{
return tipc_zone_select_router(tipc_net.zones[tipc_zone(addr)], addr, ref);
}
#if 0
u32 tipc_net_next_node(u32 a)
{
if (tipc_net.zones[tipc_zone(a)])
return tipc_zone_next_node(a);
return 0;
}
#endif
void tipc_net_remove_as_router(u32 router)
{
u32 z_num;
for (z_num = 1; z_num <= tipc_max_zones; z_num++) {
if (!tipc_net.zones[z_num])
continue;
tipc_zone_remove_as_router(tipc_net.zones[z_num], router);
}
}
void tipc_net_send_external_routes(u32 dest)
{
u32 z_num;
for (z_num = 1; z_num <= tipc_max_zones; z_num++) {
if (tipc_net.zones[z_num])
tipc_zone_send_external_routes(tipc_net.zones[z_num], dest);
}
}
static void net_stop(void)
{
u32 z_num;
for (z_num = 1; z_num <= tipc_max_zones; z_num++)
tipc_zone_delete(tipc_net.zones[z_num]);
}
static void net_route_named_msg(struct sk_buff *buf)
{
struct tipc_msg *msg = buf_msg(buf);
u32 dnode;
u32 dport;
if (!msg_named(msg)) {
msg_dbg(msg, "tipc_net->drop_nam:");
buf_discard(buf);
return;
}
dnode = addr_domain(msg_lookup_scope(msg));
dport = tipc_nametbl_translate(msg_nametype(msg), msg_nameinst(msg), &dnode);
dbg("tipc_net->lookup<%u,%u>-><%u,%x>\n",
msg_nametype(msg), msg_nameinst(msg), dport, dnode);
if (dport) {
msg_set_destnode(msg, dnode);
msg_set_destport(msg, dport);
tipc_net_route_msg(buf);
return;
}
msg_dbg(msg, "tipc_net->rej:NO NAME: ");
tipc_reject_msg(buf, TIPC_ERR_NO_NAME);
}
void tipc_net_route_msg(struct sk_buff *buf)
{
struct tipc_msg *msg;
u32 dnode;
if (!buf)
return;
msg = buf_msg(buf);
msg_incr_reroute_cnt(msg);
if (msg_reroute_cnt(msg) > 6) {
if (msg_errcode(msg)) {
msg_dbg(msg, "NET>DISC>:");
buf_discard(buf);
} else {
msg_dbg(msg, "NET>REJ>:");
tipc_reject_msg(buf, msg_destport(msg) ?
TIPC_ERR_NO_PORT : TIPC_ERR_NO_NAME);
}
return;
}
msg_dbg(msg, "tipc_net->rout: ");
/* Handle message for this node */
dnode = msg_short(msg) ? tipc_own_addr : msg_destnode(msg);
if (in_scope(dnode, tipc_own_addr)) {
if (msg_isdata(msg)) {
if (msg_mcast(msg))
tipc_port_recv_mcast(buf, NULL);
else if (msg_destport(msg))
tipc_port_recv_msg(buf);
else
net_route_named_msg(buf);
return;
}
switch (msg_user(msg)) {
case ROUTE_DISTRIBUTOR:
tipc_cltr_recv_routing_table(buf);
break;
case NAME_DISTRIBUTOR:
tipc_named_recv(buf);
break;
case CONN_MANAGER:
tipc_port_recv_proto_msg(buf);
break;
default:
msg_dbg(msg,"DROP/NET/<REC<");
buf_discard(buf);
}
return;
}
/* Handle message for another node */
msg_dbg(msg, "NET>SEND>: ");
tipc_link_send(buf, dnode, msg_link_selector(msg));
}
int tipc_net_start(u32 addr)
{
char addr_string[16];
int res;
if (tipc_mode != TIPC_NODE_MODE)
return -ENOPROTOOPT;
tipc_subscr_stop();
tipc_cfg_stop();
tipc_own_addr = addr;
tipc_mode = TIPC_NET_MODE;
tipc_named_reinit();
tipc_port_reinit();
if ((res = tipc_cltr_init()) ||
(res = tipc_bclink_init())) {
return res;
}
tipc_k_signal((Handler)tipc_subscr_start, 0);
tipc_k_signal((Handler)tipc_cfg_init, 0);
info("Started in network mode\n");
info("Own node address %s, network identity %u\n",
addr_string_fill(addr_string, tipc_own_addr), tipc_net_id);
return 0;
}
void tipc_net_stop(void)
{
if (tipc_mode != TIPC_NET_MODE)
return;
write_lock_bh(&tipc_net_lock);
tipc_bearer_stop();
tipc_mode = TIPC_NODE_MODE;
tipc_bclink_stop();
net_stop();
write_unlock_bh(&tipc_net_lock);
info("Left network mode \n");
}

64
kernel/net/tipc/net.h Normal file
View File

@@ -0,0 +1,64 @@
/*
* net/tipc/net.h: Include file for TIPC network routing code
*
* Copyright (c) 1995-2006, Ericsson AB
* Copyright (c) 2005, Wind River Systems
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. 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.
*
* Alternatively, this software may be distributed under the terms of the
* GNU General Public License ("GPL") version 2 as published by the Free
* Software Foundation.
*
* 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_NET_H
#define _TIPC_NET_H
struct _zone;
/**
* struct network - TIPC network structure
* @zones: array of pointers to all zones within network
*/
struct network {
struct _zone **zones;
};
extern struct network tipc_net;
extern rwlock_t tipc_net_lock;
void tipc_net_remove_as_router(u32 router);
void tipc_net_send_external_routes(u32 dest);
void tipc_net_route_msg(struct sk_buff *buf);
struct tipc_node *tipc_net_select_remote_node(u32 addr, u32 ref);
u32 tipc_net_select_router(u32 addr, u32 ref);
int tipc_net_start(u32 addr);
void tipc_net_stop(void);
#endif

108
kernel/net/tipc/netlink.c Normal file
View File

@@ -0,0 +1,108 @@
/*
* net/tipc/netlink.c: TIPC configuration handling
*
* Copyright (c) 2005-2006, Ericsson AB
* Copyright (c) 2005-2007, Wind River Systems
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. 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.
*
* Alternatively, this software may be distributed under the terms of the
* GNU General Public License ("GPL") version 2 as published by the Free
* Software Foundation.
*
* 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 "config.h"
#include <net/genetlink.h>
static int handle_cmd(struct sk_buff *skb, struct genl_info *info)
{
struct sk_buff *rep_buf;
struct nlmsghdr *rep_nlh;
struct nlmsghdr *req_nlh = info->nlhdr;
struct tipc_genlmsghdr *req_userhdr = info->userhdr;
int hdr_space = NLMSG_SPACE(GENL_HDRLEN + TIPC_GENL_HDRLEN);
u16 cmd;
if ((req_userhdr->cmd & 0xC000) && (!capable(CAP_NET_ADMIN)))
cmd = TIPC_CMD_NOT_NET_ADMIN;
else
cmd = req_userhdr->cmd;
rep_buf = tipc_cfg_do_cmd(req_userhdr->dest, cmd,
NLMSG_DATA(req_nlh) + GENL_HDRLEN + TIPC_GENL_HDRLEN,
NLMSG_PAYLOAD(req_nlh, GENL_HDRLEN + TIPC_GENL_HDRLEN),
hdr_space);
if (rep_buf) {
skb_push(rep_buf, hdr_space);
rep_nlh = nlmsg_hdr(rep_buf);
memcpy(rep_nlh, req_nlh, hdr_space);
rep_nlh->nlmsg_len = rep_buf->len;
genlmsg_unicast(&init_net, rep_buf, NETLINK_CB(skb).pid);
}
return 0;
}
static struct genl_family tipc_genl_family = {
.id = GENL_ID_GENERATE,
.name = TIPC_GENL_NAME,
.version = TIPC_GENL_VERSION,
.hdrsize = TIPC_GENL_HDRLEN,
.maxattr = 0,
};
static struct genl_ops tipc_genl_ops = {
.cmd = TIPC_GENL_CMD,
.doit = handle_cmd,
};
static int tipc_genl_family_registered;
int tipc_netlink_start(void)
{
int res;
res = genl_register_family_with_ops(&tipc_genl_family,
&tipc_genl_ops, 1);
if (res) {
err("Failed to register netlink interface\n");
return res;
}
tipc_genl_family_registered = 1;
return 0;
}
void tipc_netlink_stop(void)
{
if (!tipc_genl_family_registered)
return;
genl_unregister_family(&tipc_genl_family);
tipc_genl_family_registered = 0;
}

731
kernel/net/tipc/node.c Normal file
View File

@@ -0,0 +1,731 @@
/*
* net/tipc/node.c: TIPC node management routines
*
* Copyright (c) 2000-2006, Ericsson AB
* Copyright (c) 2005-2006, Wind River Systems
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. 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.
*
* Alternatively, this software may be distributed under the terms of the
* GNU General Public License ("GPL") version 2 as published by the Free
* Software Foundation.
*
* 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 "config.h"
#include "node.h"
#include "cluster.h"
#include "net.h"
#include "addr.h"
#include "node_subscr.h"
#include "link.h"
#include "port.h"
#include "bearer.h"
#include "name_distr.h"
void node_print(struct print_buf *buf, struct tipc_node *n_ptr, char *str);
static void node_lost_contact(struct tipc_node *n_ptr);
static void node_established_contact(struct tipc_node *n_ptr);
struct tipc_node *tipc_nodes = NULL; /* sorted list of nodes within cluster */
static DEFINE_SPINLOCK(node_create_lock);
u32 tipc_own_tag = 0;
/**
* tipc_node_create - create neighboring node
*
* Currently, this routine is called by neighbor discovery code, which holds
* net_lock for reading only. We must take node_create_lock to ensure a node
* isn't created twice if two different bearers discover the node at the same
* time. (It would be preferable to switch to holding net_lock in write mode,
* but this is a non-trivial change.)
*/
struct tipc_node *tipc_node_create(u32 addr)
{
struct cluster *c_ptr;
struct tipc_node *n_ptr;
struct tipc_node **curr_node;
spin_lock_bh(&node_create_lock);
for (n_ptr = tipc_nodes; n_ptr; n_ptr = n_ptr->next) {
if (addr < n_ptr->addr)
break;
if (addr == n_ptr->addr) {
spin_unlock_bh(&node_create_lock);
return n_ptr;
}
}
n_ptr = kzalloc(sizeof(*n_ptr),GFP_ATOMIC);
if (!n_ptr) {
spin_unlock_bh(&node_create_lock);
warn("Node creation failed, no memory\n");
return NULL;
}
c_ptr = tipc_cltr_find(addr);
if (!c_ptr) {
c_ptr = tipc_cltr_create(addr);
}
if (!c_ptr) {
spin_unlock_bh(&node_create_lock);
kfree(n_ptr);
return NULL;
}
n_ptr->addr = addr;
spin_lock_init(&n_ptr->lock);
INIT_LIST_HEAD(&n_ptr->nsub);
n_ptr->owner = c_ptr;
tipc_cltr_attach_node(c_ptr, n_ptr);
n_ptr->last_router = -1;
/* Insert node into ordered list */
for (curr_node = &tipc_nodes; *curr_node;
curr_node = &(*curr_node)->next) {
if (addr < (*curr_node)->addr) {
n_ptr->next = *curr_node;
break;
}
}
(*curr_node) = n_ptr;
spin_unlock_bh(&node_create_lock);
return n_ptr;
}
void tipc_node_delete(struct tipc_node *n_ptr)
{
if (!n_ptr)
return;
#if 0
/* Not needed because links are already deleted via tipc_bearer_stop() */
u32 l_num;
for (l_num = 0; l_num < MAX_BEARERS; l_num++) {
link_delete(n_ptr->links[l_num]);
}
#endif
dbg("node %x deleted\n", n_ptr->addr);
kfree(n_ptr);
}
/**
* tipc_node_link_up - handle addition of link
*
* Link becomes active (alone or shared) or standby, depending on its priority.
*/
void tipc_node_link_up(struct tipc_node *n_ptr, struct link *l_ptr)
{
struct link **active = &n_ptr->active_links[0];
n_ptr->working_links++;
info("Established link <%s> on network plane %c\n",
l_ptr->name, l_ptr->b_ptr->net_plane);
if (!active[0]) {
dbg(" link %x into %x/%x\n", l_ptr, &active[0], &active[1]);
active[0] = active[1] = l_ptr;
node_established_contact(n_ptr);
return;
}
if (l_ptr->priority < active[0]->priority) {
info("New link <%s> becomes standby\n", l_ptr->name);
return;
}
tipc_link_send_duplicate(active[0], l_ptr);
if (l_ptr->priority == active[0]->priority) {
active[0] = l_ptr;
return;
}
info("Old link <%s> becomes standby\n", active[0]->name);
if (active[1] != active[0])
info("Old link <%s> becomes standby\n", active[1]->name);
active[0] = active[1] = l_ptr;
}
/**
* node_select_active_links - select active link
*/
static void node_select_active_links(struct tipc_node *n_ptr)
{
struct link **active = &n_ptr->active_links[0];
u32 i;
u32 highest_prio = 0;
active[0] = active[1] = NULL;
for (i = 0; i < MAX_BEARERS; i++) {
struct link *l_ptr = n_ptr->links[i];
if (!l_ptr || !tipc_link_is_up(l_ptr) ||
(l_ptr->priority < highest_prio))
continue;
if (l_ptr->priority > highest_prio) {
highest_prio = l_ptr->priority;
active[0] = active[1] = l_ptr;
} else {
active[1] = l_ptr;
}
}
}
/**
* tipc_node_link_down - handle loss of link
*/
void tipc_node_link_down(struct tipc_node *n_ptr, struct link *l_ptr)
{
struct link **active;
n_ptr->working_links--;
if (!tipc_link_is_active(l_ptr)) {
info("Lost standby link <%s> on network plane %c\n",
l_ptr->name, l_ptr->b_ptr->net_plane);
return;
}
info("Lost link <%s> on network plane %c\n",
l_ptr->name, l_ptr->b_ptr->net_plane);
active = &n_ptr->active_links[0];
if (active[0] == l_ptr)
active[0] = active[1];
if (active[1] == l_ptr)
active[1] = active[0];
if (active[0] == l_ptr)
node_select_active_links(n_ptr);
if (tipc_node_is_up(n_ptr))
tipc_link_changeover(l_ptr);
else
node_lost_contact(n_ptr);
}
int tipc_node_has_active_links(struct tipc_node *n_ptr)
{
return (n_ptr &&
((n_ptr->active_links[0]) || (n_ptr->active_links[1])));
}
int tipc_node_has_redundant_links(struct tipc_node *n_ptr)
{
return (n_ptr->working_links > 1);
}
static int tipc_node_has_active_routes(struct tipc_node *n_ptr)
{
return (n_ptr && (n_ptr->last_router >= 0));
}
int tipc_node_is_up(struct tipc_node *n_ptr)
{
return (tipc_node_has_active_links(n_ptr) || tipc_node_has_active_routes(n_ptr));
}
struct tipc_node *tipc_node_attach_link(struct link *l_ptr)
{
struct tipc_node *n_ptr = tipc_node_find(l_ptr->addr);
if (!n_ptr)
n_ptr = tipc_node_create(l_ptr->addr);
if (n_ptr) {
u32 bearer_id = l_ptr->b_ptr->identity;
char addr_string[16];
if (n_ptr->link_cnt >= 2) {
err("Attempt to create third link to %s\n",
addr_string_fill(addr_string, n_ptr->addr));
return NULL;
}
if (!n_ptr->links[bearer_id]) {
n_ptr->links[bearer_id] = l_ptr;
tipc_net.zones[tipc_zone(l_ptr->addr)]->links++;
n_ptr->link_cnt++;
return n_ptr;
}
err("Attempt to establish second link on <%s> to %s \n",
l_ptr->b_ptr->publ.name,
addr_string_fill(addr_string, l_ptr->addr));
}
return NULL;
}
void tipc_node_detach_link(struct tipc_node *n_ptr, struct link *l_ptr)
{
n_ptr->links[l_ptr->b_ptr->identity] = NULL;
tipc_net.zones[tipc_zone(l_ptr->addr)]->links--;
n_ptr->link_cnt--;
}
/*
* Routing table management - five cases to handle:
*
* 1: A link towards a zone/cluster external node comes up.
* => Send a multicast message updating routing tables of all
* system nodes within own cluster that the new destination
* can be reached via this node.
* (node.establishedContact()=>cluster.multicastNewRoute())
*
* 2: A link towards a slave node comes up.
* => Send a multicast message updating routing tables of all
* system nodes within own cluster that the new destination
* can be reached via this node.
* (node.establishedContact()=>cluster.multicastNewRoute())
* => Send a message to the slave node about existence
* of all system nodes within cluster:
* (node.establishedContact()=>cluster.sendLocalRoutes())
*
* 3: A new cluster local system node becomes available.
* => Send message(s) to this particular node containing
* information about all cluster external and slave
* nodes which can be reached via this node.
* (node.establishedContact()==>network.sendExternalRoutes())
* (node.establishedContact()==>network.sendSlaveRoutes())
* => Send messages to all directly connected slave nodes
* containing information about the existence of the new node
* (node.establishedContact()=>cluster.multicastNewRoute())
*
* 4: The link towards a zone/cluster external node or slave
* node goes down.
* => Send a multcast message updating routing tables of all
* nodes within cluster that the new destination can not any
* longer be reached via this node.
* (node.lostAllLinks()=>cluster.bcastLostRoute())
*
* 5: A cluster local system node becomes unavailable.
* => Remove all references to this node from the local
* routing tables. Note: This is a completely node
* local operation.
* (node.lostAllLinks()=>network.removeAsRouter())
* => Send messages to all directly connected slave nodes
* containing information about loss of the node
* (node.establishedContact()=>cluster.multicastLostRoute())
*
*/
static void node_established_contact(struct tipc_node *n_ptr)
{
struct cluster *c_ptr;
dbg("node_established_contact:-> %x\n", n_ptr->addr);
if (!tipc_node_has_active_routes(n_ptr) && in_own_cluster(n_ptr->addr)) {
tipc_k_signal((Handler)tipc_named_node_up, n_ptr->addr);
}
/* Syncronize broadcast acks */
n_ptr->bclink.acked = tipc_bclink_get_last_sent();
if (is_slave(tipc_own_addr))
return;
if (!in_own_cluster(n_ptr->addr)) {
/* Usage case 1 (see above) */
c_ptr = tipc_cltr_find(tipc_own_addr);
if (!c_ptr)
c_ptr = tipc_cltr_create(tipc_own_addr);
if (c_ptr)
tipc_cltr_bcast_new_route(c_ptr, n_ptr->addr, 1,
tipc_max_nodes);
return;
}
c_ptr = n_ptr->owner;
if (is_slave(n_ptr->addr)) {
/* Usage case 2 (see above) */
tipc_cltr_bcast_new_route(c_ptr, n_ptr->addr, 1, tipc_max_nodes);
tipc_cltr_send_local_routes(c_ptr, n_ptr->addr);
return;
}
if (n_ptr->bclink.supported) {
tipc_nmap_add(&tipc_cltr_bcast_nodes, n_ptr->addr);
if (n_ptr->addr < tipc_own_addr)
tipc_own_tag++;
}
/* Case 3 (see above) */
tipc_net_send_external_routes(n_ptr->addr);
tipc_cltr_send_slave_routes(c_ptr, n_ptr->addr);
tipc_cltr_bcast_new_route(c_ptr, n_ptr->addr, LOWEST_SLAVE,
tipc_highest_allowed_slave);
}
static void node_lost_contact(struct tipc_node *n_ptr)
{
struct cluster *c_ptr;
struct tipc_node_subscr *ns, *tns;
char addr_string[16];
u32 i;
/* Clean up broadcast reception remains */
n_ptr->bclink.gap_after = n_ptr->bclink.gap_to = 0;
while (n_ptr->bclink.deferred_head) {
struct sk_buff* buf = n_ptr->bclink.deferred_head;
n_ptr->bclink.deferred_head = buf->next;
buf_discard(buf);
}
if (n_ptr->bclink.defragm) {
buf_discard(n_ptr->bclink.defragm);
n_ptr->bclink.defragm = NULL;
}
if (in_own_cluster(n_ptr->addr) && n_ptr->bclink.supported) {
tipc_bclink_acknowledge(n_ptr, mod(n_ptr->bclink.acked + 10000));
}
/* Update routing tables */
if (is_slave(tipc_own_addr)) {
tipc_net_remove_as_router(n_ptr->addr);
} else {
if (!in_own_cluster(n_ptr->addr)) {
/* Case 4 (see above) */
c_ptr = tipc_cltr_find(tipc_own_addr);
tipc_cltr_bcast_lost_route(c_ptr, n_ptr->addr, 1,
tipc_max_nodes);
} else {
/* Case 5 (see above) */
c_ptr = tipc_cltr_find(n_ptr->addr);
if (is_slave(n_ptr->addr)) {
tipc_cltr_bcast_lost_route(c_ptr, n_ptr->addr, 1,
tipc_max_nodes);
} else {
if (n_ptr->bclink.supported) {
tipc_nmap_remove(&tipc_cltr_bcast_nodes,
n_ptr->addr);
if (n_ptr->addr < tipc_own_addr)
tipc_own_tag--;
}
tipc_net_remove_as_router(n_ptr->addr);
tipc_cltr_bcast_lost_route(c_ptr, n_ptr->addr,
LOWEST_SLAVE,
tipc_highest_allowed_slave);
}
}
}
if (tipc_node_has_active_routes(n_ptr))
return;
info("Lost contact with %s\n",
addr_string_fill(addr_string, n_ptr->addr));
/* Abort link changeover */
for (i = 0; i < MAX_BEARERS; i++) {
struct link *l_ptr = n_ptr->links[i];
if (!l_ptr)
continue;
l_ptr->reset_checkpoint = l_ptr->next_in_no;
l_ptr->exp_msg_count = 0;
tipc_link_reset_fragments(l_ptr);
}
/* Notify subscribers */
list_for_each_entry_safe(ns, tns, &n_ptr->nsub, nodesub_list) {
ns->node = NULL;
list_del_init(&ns->nodesub_list);
tipc_k_signal((Handler)ns->handle_node_down,
(unsigned long)ns->usr_handle);
}
}
/**
* tipc_node_select_next_hop - find the next-hop node for a message
*
* Called by when cluster local lookup has failed.
*/
struct tipc_node *tipc_node_select_next_hop(u32 addr, u32 selector)
{
struct tipc_node *n_ptr;
u32 router_addr;
if (!tipc_addr_domain_valid(addr))
return NULL;
/* Look for direct link to destination processsor */
n_ptr = tipc_node_find(addr);
if (n_ptr && tipc_node_has_active_links(n_ptr))
return n_ptr;
/* Cluster local system nodes *must* have direct links */
if (!is_slave(addr) && in_own_cluster(addr))
return NULL;
/* Look for cluster local router with direct link to node */
router_addr = tipc_node_select_router(n_ptr, selector);
if (router_addr)
return tipc_node_select(router_addr, selector);
/* Slave nodes can only be accessed within own cluster via a
known router with direct link -- if no router was found,give up */
if (is_slave(addr))
return NULL;
/* Inter zone/cluster -- find any direct link to remote cluster */
addr = tipc_addr(tipc_zone(addr), tipc_cluster(addr), 0);
n_ptr = tipc_net_select_remote_node(addr, selector);
if (n_ptr && tipc_node_has_active_links(n_ptr))
return n_ptr;
/* Last resort -- look for any router to anywhere in remote zone */
router_addr = tipc_net_select_router(addr, selector);
if (router_addr)
return tipc_node_select(router_addr, selector);
return NULL;
}
/**
* tipc_node_select_router - select router to reach specified node
*
* Uses a deterministic and fair algorithm for selecting router node.
*/
u32 tipc_node_select_router(struct tipc_node *n_ptr, u32 ref)
{
u32 ulim;
u32 mask;
u32 start;
u32 r;
if (!n_ptr)
return 0;
if (n_ptr->last_router < 0)
return 0;
ulim = ((n_ptr->last_router + 1) * 32) - 1;
/* Start entry must be random */
mask = tipc_max_nodes;
while (mask > ulim)
mask >>= 1;
start = ref & mask;
r = start;
/* Lookup upwards with wrap-around */
do {
if (((n_ptr->routers[r / 32]) >> (r % 32)) & 1)
break;
} while (++r <= ulim);
if (r > ulim) {
r = 1;
do {
if (((n_ptr->routers[r / 32]) >> (r % 32)) & 1)
break;
} while (++r < start);
assert(r != start);
}
assert(r && (r <= ulim));
return tipc_addr(own_zone(), own_cluster(), r);
}
void tipc_node_add_router(struct tipc_node *n_ptr, u32 router)
{
u32 r_num = tipc_node(router);
n_ptr->routers[r_num / 32] =
((1 << (r_num % 32)) | n_ptr->routers[r_num / 32]);
n_ptr->last_router = tipc_max_nodes / 32;
while ((--n_ptr->last_router >= 0) &&
!n_ptr->routers[n_ptr->last_router]);
}
void tipc_node_remove_router(struct tipc_node *n_ptr, u32 router)
{
u32 r_num = tipc_node(router);
if (n_ptr->last_router < 0)
return; /* No routes */
n_ptr->routers[r_num / 32] =
((~(1 << (r_num % 32))) & (n_ptr->routers[r_num / 32]));
n_ptr->last_router = tipc_max_nodes / 32;
while ((--n_ptr->last_router >= 0) &&
!n_ptr->routers[n_ptr->last_router]);
if (!tipc_node_is_up(n_ptr))
node_lost_contact(n_ptr);
}
#if 0
void node_print(struct print_buf *buf, struct tipc_node *n_ptr, char *str)
{
u32 i;
tipc_printf(buf, "\n\n%s", str);
for (i = 0; i < MAX_BEARERS; i++) {
if (!n_ptr->links[i])
continue;
tipc_printf(buf, "Links[%u]: %x, ", i, n_ptr->links[i]);
}
tipc_printf(buf, "Active links: [%x,%x]\n",
n_ptr->active_links[0], n_ptr->active_links[1]);
}
#endif
u32 tipc_available_nodes(const u32 domain)
{
struct tipc_node *n_ptr;
u32 cnt = 0;
read_lock_bh(&tipc_net_lock);
for (n_ptr = tipc_nodes; n_ptr; n_ptr = n_ptr->next) {
if (!in_scope(domain, n_ptr->addr))
continue;
if (tipc_node_is_up(n_ptr))
cnt++;
}
read_unlock_bh(&tipc_net_lock);
return cnt;
}
struct sk_buff *tipc_node_get_nodes(const void *req_tlv_area, int req_tlv_space)
{
u32 domain;
struct sk_buff *buf;
struct tipc_node *n_ptr;
struct tipc_node_info node_info;
u32 payload_size;
if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_NET_ADDR))
return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
domain = ntohl(*(__be32 *)TLV_DATA(req_tlv_area));
if (!tipc_addr_domain_valid(domain))
return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
" (network address)");
read_lock_bh(&tipc_net_lock);
if (!tipc_nodes) {
read_unlock_bh(&tipc_net_lock);
return tipc_cfg_reply_none();
}
/* For now, get space for all other nodes
(will need to modify this when slave nodes are supported */
payload_size = TLV_SPACE(sizeof(node_info)) * (tipc_max_nodes - 1);
if (payload_size > 32768u) {
read_unlock_bh(&tipc_net_lock);
return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
" (too many nodes)");
}
buf = tipc_cfg_reply_alloc(payload_size);
if (!buf) {
read_unlock_bh(&tipc_net_lock);
return NULL;
}
/* Add TLVs for all nodes in scope */
for (n_ptr = tipc_nodes; n_ptr; n_ptr = n_ptr->next) {
if (!in_scope(domain, n_ptr->addr))
continue;
node_info.addr = htonl(n_ptr->addr);
node_info.up = htonl(tipc_node_is_up(n_ptr));
tipc_cfg_append_tlv(buf, TIPC_TLV_NODE_INFO,
&node_info, sizeof(node_info));
}
read_unlock_bh(&tipc_net_lock);
return buf;
}
struct sk_buff *tipc_node_get_links(const void *req_tlv_area, int req_tlv_space)
{
u32 domain;
struct sk_buff *buf;
struct tipc_node *n_ptr;
struct tipc_link_info link_info;
u32 payload_size;
if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_NET_ADDR))
return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
domain = ntohl(*(__be32 *)TLV_DATA(req_tlv_area));
if (!tipc_addr_domain_valid(domain))
return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
" (network address)");
if (tipc_mode != TIPC_NET_MODE)
return tipc_cfg_reply_none();
read_lock_bh(&tipc_net_lock);
/* Get space for all unicast links + multicast link */
payload_size = TLV_SPACE(sizeof(link_info)) *
(tipc_net.zones[tipc_zone(tipc_own_addr)]->links + 1);
if (payload_size > 32768u) {
read_unlock_bh(&tipc_net_lock);
return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
" (too many links)");
}
buf = tipc_cfg_reply_alloc(payload_size);
if (!buf) {
read_unlock_bh(&tipc_net_lock);
return NULL;
}
/* Add TLV for broadcast link */
link_info.dest = htonl(tipc_own_addr & 0xfffff00);
link_info.up = htonl(1);
strlcpy(link_info.str, tipc_bclink_name, TIPC_MAX_LINK_NAME);
tipc_cfg_append_tlv(buf, TIPC_TLV_LINK_INFO, &link_info, sizeof(link_info));
/* Add TLVs for any other links in scope */
for (n_ptr = tipc_nodes; n_ptr; n_ptr = n_ptr->next) {
u32 i;
if (!in_scope(domain, n_ptr->addr))
continue;
tipc_node_lock(n_ptr);
for (i = 0; i < MAX_BEARERS; i++) {
if (!n_ptr->links[i])
continue;
link_info.dest = htonl(n_ptr->addr);
link_info.up = htonl(tipc_link_is_up(n_ptr->links[i]));
strcpy(link_info.str, n_ptr->links[i]->name);
tipc_cfg_append_tlv(buf, TIPC_TLV_LINK_INFO,
&link_info, sizeof(link_info));
}
tipc_node_unlock(n_ptr);
}
read_unlock_bh(&tipc_net_lock);
return buf;
}

146
kernel/net/tipc/node.h Normal file
View File

@@ -0,0 +1,146 @@
/*
* net/tipc/node.h: Include file for TIPC node management routines
*
* Copyright (c) 2000-2006, Ericsson AB
* Copyright (c) 2005, Wind River Systems
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. 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.
*
* Alternatively, this software may be distributed under the terms of the
* GNU General Public License ("GPL") version 2 as published by the Free
* Software Foundation.
*
* 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_NODE_H
#define _TIPC_NODE_H
#include "node_subscr.h"
#include "addr.h"
#include "cluster.h"
#include "bearer.h"
/**
* struct tipc_node - TIPC node structure
* @addr: network address of node
* @lock: spinlock governing access to structure
* @owner: pointer to cluster that node belongs to
* @next: pointer to next node in sorted list of cluster's nodes
* @nsub: list of "node down" subscriptions monitoring node
* @active_links: pointers to active links to node
* @links: pointers to all links to node
* @working_links: number of working links to node (both active and standby)
* @link_cnt: number of links to node
* @permit_changeover: non-zero if node has redundant links to this system
* @routers: bitmap (used for multicluster communication)
* @last_router: (used for multicluster communication)
* @bclink: broadcast-related info
* @supported: non-zero if node supports TIPC b'cast capability
* @acked: sequence # of last outbound b'cast message acknowledged by node
* @last_in: sequence # of last in-sequence b'cast message received from node
* @gap_after: sequence # of last message not requiring a NAK request
* @gap_to: sequence # of last message requiring a NAK request
* @nack_sync: counter that determines when NAK requests should be sent
* @deferred_head: oldest OOS b'cast message received from node
* @deferred_tail: newest OOS b'cast message received from node
* @defragm: list of partially reassembled b'cast message fragments from node
*/
struct tipc_node {
u32 addr;
spinlock_t lock;
struct cluster *owner;
struct tipc_node *next;
struct list_head nsub;
struct link *active_links[2];
struct link *links[MAX_BEARERS];
int link_cnt;
int working_links;
int permit_changeover;
u32 routers[512/32];
int last_router;
struct {
int supported;
u32 acked;
u32 last_in;
u32 gap_after;
u32 gap_to;
u32 nack_sync;
struct sk_buff *deferred_head;
struct sk_buff *deferred_tail;
struct sk_buff *defragm;
} bclink;
};
extern struct tipc_node *tipc_nodes;
extern u32 tipc_own_tag;
struct tipc_node *tipc_node_create(u32 addr);
void tipc_node_delete(struct tipc_node *n_ptr);
struct tipc_node *tipc_node_attach_link(struct link *l_ptr);
void tipc_node_detach_link(struct tipc_node *n_ptr, struct link *l_ptr);
void tipc_node_link_down(struct tipc_node *n_ptr, struct link *l_ptr);
void tipc_node_link_up(struct tipc_node *n_ptr, struct link *l_ptr);
int tipc_node_has_active_links(struct tipc_node *n_ptr);
int tipc_node_has_redundant_links(struct tipc_node *n_ptr);
u32 tipc_node_select_router(struct tipc_node *n_ptr, u32 ref);
struct tipc_node *tipc_node_select_next_hop(u32 addr, u32 selector);
int tipc_node_is_up(struct tipc_node *n_ptr);
void tipc_node_add_router(struct tipc_node *n_ptr, u32 router);
void tipc_node_remove_router(struct tipc_node *n_ptr, u32 router);
struct sk_buff *tipc_node_get_links(const void *req_tlv_area, int req_tlv_space);
struct sk_buff *tipc_node_get_nodes(const void *req_tlv_area, int req_tlv_space);
static inline struct tipc_node *tipc_node_find(u32 addr)
{
if (likely(in_own_cluster(addr)))
return tipc_local_nodes[tipc_node(addr)];
else if (tipc_addr_domain_valid(addr)) {
struct cluster *c_ptr = tipc_cltr_find(addr);
if (c_ptr)
return c_ptr->nodes[tipc_node(addr)];
}
return NULL;
}
static inline struct tipc_node *tipc_node_select(u32 addr, u32 selector)
{
if (likely(in_own_cluster(addr)))
return tipc_local_nodes[tipc_node(addr)];
return tipc_node_select_next_hop(addr, selector);
}
static inline void tipc_node_lock(struct tipc_node *n_ptr)
{
spin_lock_bh(&n_ptr->lock);
}
static inline void tipc_node_unlock(struct tipc_node *n_ptr)
{
spin_unlock_bh(&n_ptr->lock);
}
#endif

View File

@@ -0,0 +1,80 @@
/*
* net/tipc/node_subscr.c: TIPC "node down" subscription handling
*
* Copyright (c) 1995-2006, Ericsson AB
* Copyright (c) 2005, Wind River Systems
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. 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.
*
* Alternatively, this software may be distributed under the terms of the
* GNU General Public License ("GPL") version 2 as published by the Free
* Software Foundation.
*
* 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 "node_subscr.h"
#include "node.h"
#include "addr.h"
/**
* tipc_nodesub_subscribe - create "node down" subscription for specified node
*/
void tipc_nodesub_subscribe(struct tipc_node_subscr *node_sub, u32 addr,
void *usr_handle, net_ev_handler handle_down)
{
if (addr == tipc_own_addr) {
node_sub->node = NULL;
return;
}
node_sub->node = tipc_node_find(addr);
if (!node_sub->node) {
warn("Node subscription rejected, unknown node 0x%x\n", addr);
return;
}
node_sub->handle_node_down = handle_down;
node_sub->usr_handle = usr_handle;
tipc_node_lock(node_sub->node);
list_add_tail(&node_sub->nodesub_list, &node_sub->node->nsub);
tipc_node_unlock(node_sub->node);
}
/**
* tipc_nodesub_unsubscribe - cancel "node down" subscription (if any)
*/
void tipc_nodesub_unsubscribe(struct tipc_node_subscr *node_sub)
{
if (!node_sub->node)
return;
tipc_node_lock(node_sub->node);
list_del_init(&node_sub->nodesub_list);
tipc_node_unlock(node_sub->node);
}

View File

@@ -0,0 +1,63 @@
/*
* net/tipc/node_subscr.h: Include file for TIPC "node down" subscription handling
*
* Copyright (c) 1995-2006, Ericsson AB
* Copyright (c) 2005, Wind River Systems
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. 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.
*
* Alternatively, this software may be distributed under the terms of the
* GNU General Public License ("GPL") version 2 as published by the Free
* Software Foundation.
*
* 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_NODE_SUBSCR_H
#define _TIPC_NODE_SUBSCR_H
#include "addr.h"
typedef void (*net_ev_handler) (void *usr_handle);
/**
* struct tipc_node_subscr - "node down" subscription entry
* @node: ptr to node structure of interest (or NULL, if none)
* @handle_node_down: routine to invoke when node fails
* @usr_handle: argument to pass to routine when node fails
* @nodesub_list: adjacent entries in list of subscriptions for the node
*/
struct tipc_node_subscr {
struct tipc_node *node;
net_ev_handler handle_node_down;
void *usr_handle;
struct list_head nodesub_list;
};
void tipc_nodesub_subscribe(struct tipc_node_subscr *node_sub, u32 addr,
void *usr_handle, net_ev_handler handle_down);
void tipc_nodesub_unsubscribe(struct tipc_node_subscr *node_sub);
#endif

1706
kernel/net/tipc/port.c Normal file

File diff suppressed because it is too large Load Diff

207
kernel/net/tipc/port.h Normal file
View File

@@ -0,0 +1,207 @@
/*
* net/tipc/port.h: Include file for TIPC port code
*
* Copyright (c) 1994-2007, Ericsson AB
* Copyright (c) 2004-2007, Wind River Systems
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. 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.
*
* Alternatively, this software may be distributed under the terms of the
* GNU General Public License ("GPL") version 2 as published by the Free
* Software Foundation.
*
* 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_PORT_H
#define _TIPC_PORT_H
#include "core.h"
#include "ref.h"
#include "net.h"
#include "msg.h"
#include "dbg.h"
#include "node_subscr.h"
/**
* struct user_port - TIPC user port (used with native API)
* @user_ref: id of user who created user port
* @usr_handle: user-specified field
* @ref: object reference to associated TIPC port
* <various callback routines>
* @uport_list: adjacent user ports in list of ports held by user
*/
struct user_port {
u32 user_ref;
void *usr_handle;
u32 ref;
tipc_msg_err_event err_cb;
tipc_named_msg_err_event named_err_cb;
tipc_conn_shutdown_event conn_err_cb;
tipc_msg_event msg_cb;
tipc_named_msg_event named_msg_cb;
tipc_conn_msg_event conn_msg_cb;
tipc_continue_event continue_event_cb;
struct list_head uport_list;
};
/**
* struct port - TIPC port structure
* @publ: TIPC port info available to privileged users
* @port_list: adjacent ports in TIPC's global list of ports
* @dispatcher: ptr to routine which handles received messages
* @wakeup: ptr to routine to call when port is no longer congested
* @user_port: ptr to user port associated with port (if any)
* @wait_list: adjacent ports in list of ports waiting on link congestion
* @congested_link: ptr to congested link port is waiting on
* @waiting_pkts:
* @sent:
* @acked:
* @publications: list of publications for port
* @pub_count: total # of publications port has made during its lifetime
* @probing_state:
* @probing_interval:
* @last_in_seqno:
* @timer_ref:
* @subscription: "node down" subscription used to terminate failed connections
*/
struct port {
struct tipc_port publ;
struct list_head port_list;
u32 (*dispatcher)(struct tipc_port *, struct sk_buff *);
void (*wakeup)(struct tipc_port *);
struct user_port *user_port;
struct list_head wait_list;
struct link *congested_link;
u32 waiting_pkts;
u32 sent;
u32 acked;
struct list_head publications;
u32 pub_count;
u32 probing_state;
u32 probing_interval;
u32 last_in_seqno;
struct timer_list timer;
struct tipc_node_subscr subscription;
};
extern spinlock_t tipc_port_list_lock;
struct port_list;
int tipc_port_recv_sections(struct port *p_ptr, u32 num_sect,
struct iovec const *msg_sect);
int tipc_port_reject_sections(struct port *p_ptr, struct tipc_msg *hdr,
struct iovec const *msg_sect, u32 num_sect,
int err);
struct sk_buff *tipc_port_get_ports(void);
struct sk_buff *port_show_stats(const void *req_tlv_area, int req_tlv_space);
void tipc_port_recv_proto_msg(struct sk_buff *buf);
void tipc_port_recv_mcast(struct sk_buff *buf, struct port_list *dp);
void tipc_port_reinit(void);
/**
* tipc_port_lock - lock port instance referred to and return its pointer
*/
static inline struct port *tipc_port_lock(u32 ref)
{
return (struct port *)tipc_ref_lock(ref);
}
/**
* tipc_port_unlock - unlock a port instance
*
* Can use pointer instead of tipc_ref_unlock() since port is already locked.
*/
static inline void tipc_port_unlock(struct port *p_ptr)
{
spin_unlock_bh(p_ptr->publ.lock);
}
static inline struct port* tipc_port_deref(u32 ref)
{
return (struct port *)tipc_ref_deref(ref);
}
static inline u32 tipc_peer_port(struct port *p_ptr)
{
return msg_destport(&p_ptr->publ.phdr);
}
static inline u32 tipc_peer_node(struct port *p_ptr)
{
return msg_destnode(&p_ptr->publ.phdr);
}
static inline int tipc_port_congested(struct port *p_ptr)
{
return((p_ptr->sent - p_ptr->acked) >= (TIPC_FLOW_CONTROL_WIN * 2));
}
/**
* tipc_port_recv_msg - receive message from lower layer and deliver to port user
*/
static inline int tipc_port_recv_msg(struct sk_buff *buf)
{
struct port *p_ptr;
struct tipc_msg *msg = buf_msg(buf);
u32 destport = msg_destport(msg);
u32 dsz = msg_data_sz(msg);
u32 err;
/* forward unresolved named message */
if (unlikely(!destport)) {
tipc_net_route_msg(buf);
return dsz;
}
/* validate destination & pass to port, otherwise reject message */
p_ptr = tipc_port_lock(destport);
if (likely(p_ptr)) {
if (likely(p_ptr->publ.connected)) {
if ((unlikely(msg_origport(msg) != tipc_peer_port(p_ptr))) ||
(unlikely(msg_orignode(msg) != tipc_peer_node(p_ptr))) ||
(unlikely(!msg_connected(msg)))) {
err = TIPC_ERR_NO_PORT;
tipc_port_unlock(p_ptr);
goto reject;
}
}
err = p_ptr->dispatcher(&p_ptr->publ, buf);
tipc_port_unlock(p_ptr);
if (likely(!err))
return dsz;
} else {
err = TIPC_ERR_NO_PORT;
}
reject:
dbg("port->rejecting, err = %x..\n",err);
return tipc_reject_msg(buf, err);
}
#endif

313
kernel/net/tipc/ref.c Normal file
View File

@@ -0,0 +1,313 @@
/*
* net/tipc/ref.c: TIPC object registry code
*
* Copyright (c) 1991-2006, Ericsson AB
* Copyright (c) 2004-2007, Wind River Systems
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. 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.
*
* Alternatively, this software may be distributed under the terms of the
* GNU General Public License ("GPL") version 2 as published by the Free
* Software Foundation.
*
* 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 "ref.h"
/**
* struct reference - TIPC object reference entry
* @object: pointer to object associated with reference entry
* @lock: spinlock controlling access to object
* @ref: reference value for object (combines instance & array index info)
*/
struct reference {
void *object;
spinlock_t lock;
u32 ref;
};
/**
* struct tipc_ref_table - table of TIPC object reference entries
* @entries: pointer to array of reference entries
* @capacity: array index of first unusable entry
* @init_point: array index of first uninitialized entry
* @first_free: array index of first unused object reference entry
* @last_free: array index of last unused object reference entry
* @index_mask: bitmask for array index portion of reference values
* @start_mask: initial value for instance value portion of reference values
*/
struct ref_table {
struct reference *entries;
u32 capacity;
u32 init_point;
u32 first_free;
u32 last_free;
u32 index_mask;
u32 start_mask;
};
/*
* Object reference table consists of 2**N entries.
*
* State Object ptr Reference
* ----- ---------- ---------
* In use non-NULL XXXX|own index
* (XXXX changes each time entry is acquired)
* Free NULL YYYY|next free index
* (YYYY is one more than last used XXXX)
* Uninitialized NULL 0
*
* Entry 0 is not used; this allows index 0 to denote the end of the free list.
*
* Note that a reference value of 0 does not necessarily indicate that an
* entry is uninitialized, since the last entry in the free list could also
* have a reference value of 0 (although this is unlikely).
*/
static struct ref_table tipc_ref_table = { NULL };
static DEFINE_RWLOCK(ref_table_lock);
/**
* tipc_ref_table_init - create reference table for objects
*/
int tipc_ref_table_init(u32 requested_size, u32 start)
{
struct reference *table;
u32 actual_size;
/* account for unused entry, then round up size to a power of 2 */
requested_size++;
for (actual_size = 16; actual_size < requested_size; actual_size <<= 1)
/* do nothing */ ;
/* allocate table & mark all entries as uninitialized */
table = __vmalloc(actual_size * sizeof(struct reference),
GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO, PAGE_KERNEL);
if (table == NULL)
return -ENOMEM;
tipc_ref_table.entries = table;
tipc_ref_table.capacity = requested_size;
tipc_ref_table.init_point = 1;
tipc_ref_table.first_free = 0;
tipc_ref_table.last_free = 0;
tipc_ref_table.index_mask = actual_size - 1;
tipc_ref_table.start_mask = start & ~tipc_ref_table.index_mask;
return 0;
}
/**
* tipc_ref_table_stop - destroy reference table for objects
*/
void tipc_ref_table_stop(void)
{
if (!tipc_ref_table.entries)
return;
vfree(tipc_ref_table.entries);
tipc_ref_table.entries = NULL;
}
/**
* tipc_ref_acquire - create reference to an object
*
* Register an object pointer in reference table and lock the object.
* Returns a unique reference value that is used from then on to retrieve the
* object pointer, or to determine that the object has been deregistered.
*
* Note: The object is returned in the locked state so that the caller can
* register a partially initialized object, without running the risk that
* the object will be accessed before initialization is complete.
*/
u32 tipc_ref_acquire(void *object, spinlock_t **lock)
{
struct reference *entry;
u32 index;
u32 index_mask;
u32 next_plus_upper;
u32 ref;
if (!object) {
err("Attempt to acquire reference to non-existent object\n");
return 0;
}
if (!tipc_ref_table.entries) {
err("Reference table not found during acquisition attempt\n");
return 0;
}
/* take a free entry, if available; otherwise initialize a new entry */
write_lock_bh(&ref_table_lock);
if (tipc_ref_table.first_free) {
index = tipc_ref_table.first_free;
entry = &(tipc_ref_table.entries[index]);
index_mask = tipc_ref_table.index_mask;
/* take lock in case a previous user of entry still holds it */
spin_lock_bh(&entry->lock);
next_plus_upper = entry->ref;
tipc_ref_table.first_free = next_plus_upper & index_mask;
ref = (next_plus_upper & ~index_mask) + index;
entry->ref = ref;
entry->object = object;
*lock = &entry->lock;
}
else if (tipc_ref_table.init_point < tipc_ref_table.capacity) {
index = tipc_ref_table.init_point++;
entry = &(tipc_ref_table.entries[index]);
spin_lock_init(&entry->lock);
spin_lock_bh(&entry->lock);
ref = tipc_ref_table.start_mask + index;
entry->ref = ref;
entry->object = object;
*lock = &entry->lock;
}
else {
ref = 0;
}
write_unlock_bh(&ref_table_lock);
return ref;
}
/**
* tipc_ref_discard - invalidate references to an object
*
* Disallow future references to an object and free up the entry for re-use.
* Note: The entry's spin_lock may still be busy after discard
*/
void tipc_ref_discard(u32 ref)
{
struct reference *entry;
u32 index;
u32 index_mask;
if (!tipc_ref_table.entries) {
err("Reference table not found during discard attempt\n");
return;
}
index_mask = tipc_ref_table.index_mask;
index = ref & index_mask;
entry = &(tipc_ref_table.entries[index]);
write_lock_bh(&ref_table_lock);
if (!entry->object) {
err("Attempt to discard reference to non-existent object\n");
goto exit;
}
if (entry->ref != ref) {
err("Attempt to discard non-existent reference\n");
goto exit;
}
/*
* mark entry as unused; increment instance part of entry's reference
* to invalidate any subsequent references
*/
entry->object = NULL;
entry->ref = (ref & ~index_mask) + (index_mask + 1);
/* append entry to free entry list */
if (tipc_ref_table.first_free == 0)
tipc_ref_table.first_free = index;
else
tipc_ref_table.entries[tipc_ref_table.last_free].ref |= index;
tipc_ref_table.last_free = index;
exit:
write_unlock_bh(&ref_table_lock);
}
/**
* tipc_ref_lock - lock referenced object and return pointer to it
*/
void *tipc_ref_lock(u32 ref)
{
if (likely(tipc_ref_table.entries)) {
struct reference *entry;
entry = &tipc_ref_table.entries[ref &
tipc_ref_table.index_mask];
if (likely(entry->ref != 0)) {
spin_lock_bh(&entry->lock);
if (likely((entry->ref == ref) && (entry->object)))
return entry->object;
spin_unlock_bh(&entry->lock);
}
}
return NULL;
}
/**
* tipc_ref_unlock - unlock referenced object
*/
void tipc_ref_unlock(u32 ref)
{
if (likely(tipc_ref_table.entries)) {
struct reference *entry;
entry = &tipc_ref_table.entries[ref &
tipc_ref_table.index_mask];
if (likely((entry->ref == ref) && (entry->object)))
spin_unlock_bh(&entry->lock);
else
err("Attempt to unlock non-existent reference\n");
}
}
/**
* tipc_ref_deref - return pointer referenced object (without locking it)
*/
void *tipc_ref_deref(u32 ref)
{
if (likely(tipc_ref_table.entries)) {
struct reference *entry;
entry = &tipc_ref_table.entries[ref &
tipc_ref_table.index_mask];
if (likely(entry->ref == ref))
return entry->object;
}
return NULL;
}

50
kernel/net/tipc/ref.h Normal file
View File

@@ -0,0 +1,50 @@
/*
* net/tipc/ref.h: Include file for TIPC object registry code
*
* Copyright (c) 1991-2006, Ericsson AB
* Copyright (c) 2005-2006, Wind River Systems
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. 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.
*
* Alternatively, this software may be distributed under the terms of the
* GNU General Public License ("GPL") version 2 as published by the Free
* Software Foundation.
*
* 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_REF_H
#define _TIPC_REF_H
int tipc_ref_table_init(u32 requested_size, u32 start);
void tipc_ref_table_stop(void);
u32 tipc_ref_acquire(void *object, spinlock_t **lock);
void tipc_ref_discard(u32 ref);
void *tipc_ref_lock(u32 ref);
void tipc_ref_unlock(u32 ref);
void *tipc_ref_deref(u32 ref);
#endif

1899
kernel/net/tipc/socket.c Normal file

File diff suppressed because it is too large Load Diff

617
kernel/net/tipc/subscr.c Normal file
View File

@@ -0,0 +1,617 @@
/*
* net/tipc/subscr.c: TIPC network topology service
*
* Copyright (c) 2000-2006, Ericsson AB
* Copyright (c) 2005-2007, Wind River Systems
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. 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.
*
* Alternatively, this software may be distributed under the terms of the
* GNU General Public License ("GPL") version 2 as published by the Free
* Software Foundation.
*
* 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 "name_table.h"
#include "port.h"
#include "ref.h"
#include "subscr.h"
/**
* struct subscriber - TIPC network topology subscriber
* @port_ref: object reference to server port connecting to subscriber
* @lock: pointer to spinlock controlling access to subscriber's server port
* @subscriber_list: adjacent subscribers in top. server's list of subscribers
* @subscription_list: list of subscription objects for this subscriber
*/
struct subscriber {
u32 port_ref;
spinlock_t *lock;
struct list_head subscriber_list;
struct list_head subscription_list;
};
/**
* struct top_srv - TIPC network topology subscription service
* @user_ref: TIPC userid of subscription service
* @setup_port: reference to TIPC port that handles subscription requests
* @subscription_count: number of active subscriptions (not subscribers!)
* @subscriber_list: list of ports subscribing to service
* @lock: spinlock govering access to subscriber list
*/
struct top_srv {
u32 user_ref;
u32 setup_port;
atomic_t subscription_count;
struct list_head subscriber_list;
spinlock_t lock;
};
static struct top_srv topsrv = { 0 };
/**
* htohl - convert value to endianness used by destination
* @in: value to convert
* @swap: non-zero if endianness must be reversed
*
* Returns converted value
*/
static u32 htohl(u32 in, int swap)
{
return swap ? swab32(in) : in;
}
/**
* subscr_send_event - send a message containing a tipc_event to the subscriber
*
* Note: Must not hold subscriber's server port lock, since tipc_send() will
* try to take the lock if the message is rejected and returned!
*/
static void subscr_send_event(struct subscription *sub,
u32 found_lower,
u32 found_upper,
u32 event,
u32 port_ref,
u32 node)
{
struct iovec msg_sect;
msg_sect.iov_base = (void *)&sub->evt;
msg_sect.iov_len = sizeof(struct tipc_event);
sub->evt.event = htohl(event, sub->swap);
sub->evt.found_lower = htohl(found_lower, sub->swap);
sub->evt.found_upper = htohl(found_upper, sub->swap);
sub->evt.port.ref = htohl(port_ref, sub->swap);
sub->evt.port.node = htohl(node, sub->swap);
tipc_send(sub->server_ref, 1, &msg_sect);
}
/**
* tipc_subscr_overlap - test for subscription overlap with the given values
*
* Returns 1 if there is overlap, otherwise 0.
*/
int tipc_subscr_overlap(struct subscription *sub,
u32 found_lower,
u32 found_upper)
{
if (found_lower < sub->seq.lower)
found_lower = sub->seq.lower;
if (found_upper > sub->seq.upper)
found_upper = sub->seq.upper;
if (found_lower > found_upper)
return 0;
return 1;
}
/**
* tipc_subscr_report_overlap - issue event if there is subscription overlap
*
* Protected by nameseq.lock in name_table.c
*/
void tipc_subscr_report_overlap(struct subscription *sub,
u32 found_lower,
u32 found_upper,
u32 event,
u32 port_ref,
u32 node,
int must)
{
if (!tipc_subscr_overlap(sub, found_lower, found_upper))
return;
if (!must && !(sub->filter & TIPC_SUB_PORTS))
return;
sub->event_cb(sub, found_lower, found_upper, event, port_ref, node);
}
/**
* subscr_timeout - subscription timeout has occurred
*/
static void subscr_timeout(struct subscription *sub)
{
struct port *server_port;
/* Validate server port reference (in case subscriber is terminating) */
server_port = tipc_port_lock(sub->server_ref);
if (server_port == NULL)
return;
/* Validate timeout (in case subscription is being cancelled) */
if (sub->timeout == TIPC_WAIT_FOREVER) {
tipc_port_unlock(server_port);
return;
}
/* Unlink subscription from name table */
tipc_nametbl_unsubscribe(sub);
/* Unlink subscription from subscriber */
list_del(&sub->subscription_list);
/* Release subscriber's server port */
tipc_port_unlock(server_port);
/* Notify subscriber of timeout */
subscr_send_event(sub, sub->evt.s.seq.lower, sub->evt.s.seq.upper,
TIPC_SUBSCR_TIMEOUT, 0, 0);
/* Now destroy subscription */
k_term_timer(&sub->timer);
kfree(sub);
atomic_dec(&topsrv.subscription_count);
}
/**
* subscr_del - delete a subscription within a subscription list
*
* Called with subscriber port locked.
*/
static void subscr_del(struct subscription *sub)
{
tipc_nametbl_unsubscribe(sub);
list_del(&sub->subscription_list);
kfree(sub);
atomic_dec(&topsrv.subscription_count);
}
/**
* subscr_terminate - terminate communication with a subscriber
*
* Called with subscriber port locked. Routine must temporarily release lock
* to enable subscription timeout routine(s) to finish without deadlocking;
* the lock is then reclaimed to allow caller to release it upon return.
* (This should work even in the unlikely event some other thread creates
* a new object reference in the interim that uses this lock; this routine will
* simply wait for it to be released, then claim it.)
*/
static void subscr_terminate(struct subscriber *subscriber)
{
u32 port_ref;
struct subscription *sub;
struct subscription *sub_temp;
/* Invalidate subscriber reference */
port_ref = subscriber->port_ref;
subscriber->port_ref = 0;
spin_unlock_bh(subscriber->lock);
/* Sever connection to subscriber */
tipc_shutdown(port_ref);
tipc_deleteport(port_ref);
/* Destroy any existing subscriptions for subscriber */
list_for_each_entry_safe(sub, sub_temp, &subscriber->subscription_list,
subscription_list) {
if (sub->timeout != TIPC_WAIT_FOREVER) {
k_cancel_timer(&sub->timer);
k_term_timer(&sub->timer);
}
dbg("Term: Removing sub %u,%u,%u from subscriber %x list\n",
sub->seq.type, sub->seq.lower, sub->seq.upper, subscriber);
subscr_del(sub);
}
/* Remove subscriber from topology server's subscriber list */
spin_lock_bh(&topsrv.lock);
list_del(&subscriber->subscriber_list);
spin_unlock_bh(&topsrv.lock);
/* Reclaim subscriber lock */
spin_lock_bh(subscriber->lock);
/* Now destroy subscriber */
kfree(subscriber);
}
/**
* subscr_cancel - handle subscription cancellation request
*
* Called with subscriber port locked. Routine must temporarily release lock
* to enable the subscription timeout routine to finish without deadlocking;
* the lock is then reclaimed to allow caller to release it upon return.
*
* Note that fields of 's' use subscriber's endianness!
*/
static void subscr_cancel(struct tipc_subscr *s,
struct subscriber *subscriber)
{
struct subscription *sub;
struct subscription *sub_temp;
int found = 0;
/* Find first matching subscription, exit if not found */
list_for_each_entry_safe(sub, sub_temp, &subscriber->subscription_list,
subscription_list) {
if (!memcmp(s, &sub->evt.s, sizeof(struct tipc_subscr))) {
found = 1;
break;
}
}
if (!found)
return;
/* Cancel subscription timer (if used), then delete subscription */
if (sub->timeout != TIPC_WAIT_FOREVER) {
sub->timeout = TIPC_WAIT_FOREVER;
spin_unlock_bh(subscriber->lock);
k_cancel_timer(&sub->timer);
k_term_timer(&sub->timer);
spin_lock_bh(subscriber->lock);
}
dbg("Cancel: removing sub %u,%u,%u from subscriber %x list\n",
sub->seq.type, sub->seq.lower, sub->seq.upper, subscriber);
subscr_del(sub);
}
/**
* subscr_subscribe - create subscription for subscriber
*
* Called with subscriber port locked.
*/
static struct subscription *subscr_subscribe(struct tipc_subscr *s,
struct subscriber *subscriber)
{
struct subscription *sub;
int swap;
/* Determine subscriber's endianness */
swap = !(s->filter & (TIPC_SUB_PORTS | TIPC_SUB_SERVICE));
/* Detect & process a subscription cancellation request */
if (s->filter & htohl(TIPC_SUB_CANCEL, swap)) {
s->filter &= ~htohl(TIPC_SUB_CANCEL, swap);
subscr_cancel(s, subscriber);
return NULL;
}
/* Refuse subscription if global limit exceeded */
if (atomic_read(&topsrv.subscription_count) >= tipc_max_subscriptions) {
warn("Subscription rejected, subscription limit reached (%u)\n",
tipc_max_subscriptions);
subscr_terminate(subscriber);
return NULL;
}
/* Allocate subscription object */
sub = kmalloc(sizeof(*sub), GFP_ATOMIC);
if (!sub) {
warn("Subscription rejected, no memory\n");
subscr_terminate(subscriber);
return NULL;
}
/* Initialize subscription object */
sub->seq.type = htohl(s->seq.type, swap);
sub->seq.lower = htohl(s->seq.lower, swap);
sub->seq.upper = htohl(s->seq.upper, swap);
sub->timeout = htohl(s->timeout, swap);
sub->filter = htohl(s->filter, swap);
if ((!(sub->filter & TIPC_SUB_PORTS)
== !(sub->filter & TIPC_SUB_SERVICE))
|| (sub->seq.lower > sub->seq.upper)) {
warn("Subscription rejected, illegal request\n");
kfree(sub);
subscr_terminate(subscriber);
return NULL;
}
sub->event_cb = subscr_send_event;
INIT_LIST_HEAD(&sub->nameseq_list);
list_add(&sub->subscription_list, &subscriber->subscription_list);
sub->server_ref = subscriber->port_ref;
sub->swap = swap;
memcpy(&sub->evt.s, s, sizeof(struct tipc_subscr));
atomic_inc(&topsrv.subscription_count);
if (sub->timeout != TIPC_WAIT_FOREVER) {
k_init_timer(&sub->timer,
(Handler)subscr_timeout, (unsigned long)sub);
k_start_timer(&sub->timer, sub->timeout);
}
return sub;
}
/**
* subscr_conn_shutdown_event - handle termination request from subscriber
*
* Called with subscriber's server port unlocked.
*/
static void subscr_conn_shutdown_event(void *usr_handle,
u32 port_ref,
struct sk_buff **buf,
unsigned char const *data,
unsigned int size,
int reason)
{
struct subscriber *subscriber = usr_handle;
spinlock_t *subscriber_lock;
if (tipc_port_lock(port_ref) == NULL)
return;
subscriber_lock = subscriber->lock;
subscr_terminate(subscriber);
spin_unlock_bh(subscriber_lock);
}
/**
* subscr_conn_msg_event - handle new subscription request from subscriber
*
* Called with subscriber's server port unlocked.
*/
static void subscr_conn_msg_event(void *usr_handle,
u32 port_ref,
struct sk_buff **buf,
const unchar *data,
u32 size)
{
struct subscriber *subscriber = usr_handle;
spinlock_t *subscriber_lock;
struct subscription *sub;
/*
* Lock subscriber's server port (& make a local copy of lock pointer,
* in case subscriber is deleted while processing subscription request)
*/
if (tipc_port_lock(port_ref) == NULL)
return;
subscriber_lock = subscriber->lock;
if (size != sizeof(struct tipc_subscr)) {
subscr_terminate(subscriber);
spin_unlock_bh(subscriber_lock);
} else {
sub = subscr_subscribe((struct tipc_subscr *)data, subscriber);
spin_unlock_bh(subscriber_lock);
if (sub != NULL) {
/*
* We must release the server port lock before adding a
* subscription to the name table since TIPC needs to be
* able to (re)acquire the port lock if an event message
* issued by the subscription process is rejected and
* returned. The subscription cannot be deleted while
* it is being added to the name table because:
* a) the single-threading of the native API port code
* ensures the subscription cannot be cancelled and
* the subscriber connection cannot be broken, and
* b) the name table lock ensures the subscription
* timeout code cannot delete the subscription,
* so the subscription object is still protected.
*/
tipc_nametbl_subscribe(sub);
}
}
}
/**
* subscr_named_msg_event - handle request to establish a new subscriber
*/
static void subscr_named_msg_event(void *usr_handle,
u32 port_ref,
struct sk_buff **buf,
const unchar *data,
u32 size,
u32 importance,
struct tipc_portid const *orig,
struct tipc_name_seq const *dest)
{
static struct iovec msg_sect = {NULL, 0};
struct subscriber *subscriber;
u32 server_port_ref;
/* Create subscriber object */
subscriber = kzalloc(sizeof(struct subscriber), GFP_ATOMIC);
if (subscriber == NULL) {
warn("Subscriber rejected, no memory\n");
return;
}
INIT_LIST_HEAD(&subscriber->subscription_list);
INIT_LIST_HEAD(&subscriber->subscriber_list);
/* Create server port & establish connection to subscriber */
tipc_createport(topsrv.user_ref,
subscriber,
importance,
NULL,
NULL,
subscr_conn_shutdown_event,
NULL,
NULL,
subscr_conn_msg_event,
NULL,
&subscriber->port_ref);
if (subscriber->port_ref == 0) {
warn("Subscriber rejected, unable to create port\n");
kfree(subscriber);
return;
}
tipc_connect2port(subscriber->port_ref, orig);
/* Lock server port (& save lock address for future use) */
subscriber->lock = tipc_port_lock(subscriber->port_ref)->publ.lock;
/* Add subscriber to topology server's subscriber list */
spin_lock_bh(&topsrv.lock);
list_add(&subscriber->subscriber_list, &topsrv.subscriber_list);
spin_unlock_bh(&topsrv.lock);
/* Unlock server port */
server_port_ref = subscriber->port_ref;
spin_unlock_bh(subscriber->lock);
/* Send an ACK- to complete connection handshaking */
tipc_send(server_port_ref, 1, &msg_sect);
/* Handle optional subscription request */
if (size != 0) {
subscr_conn_msg_event(subscriber, server_port_ref,
buf, data, size);
}
}
int tipc_subscr_start(void)
{
struct tipc_name_seq seq = {TIPC_TOP_SRV, TIPC_TOP_SRV, TIPC_TOP_SRV};
int res = -1;
memset(&topsrv, 0, sizeof (topsrv));
spin_lock_init(&topsrv.lock);
INIT_LIST_HEAD(&topsrv.subscriber_list);
spin_lock_bh(&topsrv.lock);
res = tipc_attach(&topsrv.user_ref, NULL, NULL);
if (res) {
spin_unlock_bh(&topsrv.lock);
return res;
}
res = tipc_createport(topsrv.user_ref,
NULL,
TIPC_CRITICAL_IMPORTANCE,
NULL,
NULL,
NULL,
NULL,
subscr_named_msg_event,
NULL,
NULL,
&topsrv.setup_port);
if (res)
goto failed;
res = tipc_nametbl_publish_rsv(topsrv.setup_port, TIPC_NODE_SCOPE, &seq);
if (res)
goto failed;
spin_unlock_bh(&topsrv.lock);
return 0;
failed:
err("Failed to create subscription service\n");
tipc_detach(topsrv.user_ref);
topsrv.user_ref = 0;
spin_unlock_bh(&topsrv.lock);
return res;
}
void tipc_subscr_stop(void)
{
struct subscriber *subscriber;
struct subscriber *subscriber_temp;
spinlock_t *subscriber_lock;
if (topsrv.user_ref) {
tipc_deleteport(topsrv.setup_port);
list_for_each_entry_safe(subscriber, subscriber_temp,
&topsrv.subscriber_list,
subscriber_list) {
subscriber_lock = subscriber->lock;
spin_lock_bh(subscriber_lock);
subscr_terminate(subscriber);
spin_unlock_bh(subscriber_lock);
}
tipc_detach(topsrv.user_ref);
topsrv.user_ref = 0;
}
}
int tipc_ispublished(struct tipc_name const *name)
{
u32 domain = 0;
return(tipc_nametbl_translate(name->type, name->instance,&domain) != 0);
}

90
kernel/net/tipc/subscr.h Normal file
View File

@@ -0,0 +1,90 @@
/*
* net/tipc/subscr.h: Include file for TIPC network topology service
*
* Copyright (c) 2003-2006, Ericsson AB
* Copyright (c) 2005-2007, Wind River Systems
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. 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.
*
* Alternatively, this software may be distributed under the terms of the
* GNU General Public License ("GPL") version 2 as published by the Free
* Software Foundation.
*
* 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_SUBSCR_H
#define _TIPC_SUBSCR_H
struct subscription;
typedef void (*tipc_subscr_event) (struct subscription *sub,
u32 found_lower, u32 found_upper,
u32 event, u32 port_ref, u32 node);
/**
* struct subscription - TIPC network topology subscription object
* @seq: name sequence associated with subscription
* @timeout: duration of subscription (in ms)
* @filter: event filtering to be done for subscription
* @event_cb: routine invoked when a subscription event is detected
* @timer: timer governing subscription duration (optional)
* @nameseq_list: adjacent subscriptions in name sequence's subscription list
* @subscription_list: adjacent subscriptions in subscriber's subscription list
* @server_ref: object reference of server port associated with subscription
* @swap: indicates if subscriber uses opposite endianness in its messages
* @evt: template for events generated by subscription
*/
struct subscription {
struct tipc_name_seq seq;
u32 timeout;
u32 filter;
tipc_subscr_event event_cb;
struct timer_list timer;
struct list_head nameseq_list;
struct list_head subscription_list;
u32 server_ref;
int swap;
struct tipc_event evt;
};
int tipc_subscr_overlap(struct subscription *sub,
u32 found_lower,
u32 found_upper);
void tipc_subscr_report_overlap(struct subscription *sub,
u32 found_lower,
u32 found_upper,
u32 event,
u32 port_ref,
u32 node,
int must_report);
int tipc_subscr_start(void);
void tipc_subscr_stop(void);
#endif

264
kernel/net/tipc/user_reg.c Normal file
View File

@@ -0,0 +1,264 @@
/*
* net/tipc/user_reg.c: TIPC user registry code
*
* Copyright (c) 2000-2006, Ericsson AB
* Copyright (c) 2004-2005, Wind River Systems
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. 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.
*
* Alternatively, this software may be distributed under the terms of the
* GNU General Public License ("GPL") version 2 as published by the Free
* Software Foundation.
*
* 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 "user_reg.h"
/*
* TIPC user registry keeps track of users of the tipc_port interface.
*
* The registry utilizes an array of "TIPC user" entries;
* a user's ID is the index of their associated array entry.
* Array entry 0 is not used, so userid 0 is not valid;
* TIPC sometimes uses this value to denote an anonymous user.
* The list of free entries is initially chained from last entry to entry 1.
*/
/**
* struct tipc_user - registered TIPC user info
* @next: index of next free registry entry (or -1 for an allocated entry)
* @callback: ptr to routine to call when TIPC mode changes (NULL if none)
* @usr_handle: user-defined value passed to callback routine
* @ports: list of user ports owned by the user
*/
struct tipc_user {
int next;
tipc_mode_event callback;
void *usr_handle;
struct list_head ports;
};
#define MAX_USERID 64
#define USER_LIST_SIZE ((MAX_USERID + 1) * sizeof(struct tipc_user))
static struct tipc_user *users = NULL;
static u32 next_free_user = MAX_USERID + 1;
static DEFINE_SPINLOCK(reg_lock);
/**
* reg_init - create TIPC user registry (but don't activate it)
*
* If registry has been pre-initialized it is left "as is".
* NOTE: This routine may be called when TIPC is inactive.
*/
static int reg_init(void)
{
u32 i;
spin_lock_bh(&reg_lock);
if (!users) {
users = kzalloc(USER_LIST_SIZE, GFP_ATOMIC);
if (users) {
for (i = 1; i <= MAX_USERID; i++) {
users[i].next = i - 1;
}
next_free_user = MAX_USERID;
}
}
spin_unlock_bh(&reg_lock);
return users ? 0 : -ENOMEM;
}
/**
* reg_callback - inform TIPC user about current operating mode
*/
static void reg_callback(struct tipc_user *user_ptr)
{
tipc_mode_event cb;
void *arg;
spin_lock_bh(&reg_lock);
cb = user_ptr->callback;
arg = user_ptr->usr_handle;
spin_unlock_bh(&reg_lock);
if (cb)
cb(arg, tipc_mode, tipc_own_addr);
}
/**
* tipc_reg_start - activate TIPC user registry
*/
int tipc_reg_start(void)
{
u32 u;
int res;
if ((res = reg_init()))
return res;
for (u = 1; u <= MAX_USERID; u++) {
if (users[u].callback)
tipc_k_signal((Handler)reg_callback,
(unsigned long)&users[u]);
}
return 0;
}
/**
* tipc_reg_stop - shut down & delete TIPC user registry
*/
void tipc_reg_stop(void)
{
int id;
if (!users)
return;
for (id = 1; id <= MAX_USERID; id++) {
if (users[id].callback)
reg_callback(&users[id]);
}
kfree(users);
users = NULL;
}
/**
* tipc_attach - register a TIPC user
*
* NOTE: This routine may be called when TIPC is inactive.
*/
int tipc_attach(u32 *userid, tipc_mode_event cb, void *usr_handle)
{
struct tipc_user *user_ptr;
if ((tipc_mode == TIPC_NOT_RUNNING) && !cb)
return -ENOPROTOOPT;
if (!users)
reg_init();
spin_lock_bh(&reg_lock);
if (!next_free_user) {
spin_unlock_bh(&reg_lock);
return -EBUSY;
}
user_ptr = &users[next_free_user];
*userid = next_free_user;
next_free_user = user_ptr->next;
user_ptr->next = -1;
spin_unlock_bh(&reg_lock);
user_ptr->callback = cb;
user_ptr->usr_handle = usr_handle;
INIT_LIST_HEAD(&user_ptr->ports);
atomic_inc(&tipc_user_count);
if (cb && (tipc_mode != TIPC_NOT_RUNNING))
tipc_k_signal((Handler)reg_callback, (unsigned long)user_ptr);
return 0;
}
/**
* tipc_detach - deregister a TIPC user
*/
void tipc_detach(u32 userid)
{
struct tipc_user *user_ptr;
struct list_head ports_temp;
struct user_port *up_ptr, *temp_up_ptr;
if ((userid == 0) || (userid > MAX_USERID))
return;
spin_lock_bh(&reg_lock);
if ((!users) || (users[userid].next >= 0)) {
spin_unlock_bh(&reg_lock);
return;
}
user_ptr = &users[userid];
user_ptr->callback = NULL;
INIT_LIST_HEAD(&ports_temp);
list_splice(&user_ptr->ports, &ports_temp);
user_ptr->next = next_free_user;
next_free_user = userid;
spin_unlock_bh(&reg_lock);
atomic_dec(&tipc_user_count);
list_for_each_entry_safe(up_ptr, temp_up_ptr, &ports_temp, uport_list) {
tipc_deleteport(up_ptr->ref);
}
}
/**
* tipc_reg_add_port - register a user's driver port
*/
int tipc_reg_add_port(struct user_port *up_ptr)
{
struct tipc_user *user_ptr;
if (up_ptr->user_ref == 0)
return 0;
if (up_ptr->user_ref > MAX_USERID)
return -EINVAL;
if ((tipc_mode == TIPC_NOT_RUNNING) || !users )
return -ENOPROTOOPT;
spin_lock_bh(&reg_lock);
user_ptr = &users[up_ptr->user_ref];
list_add(&up_ptr->uport_list, &user_ptr->ports);
spin_unlock_bh(&reg_lock);
return 0;
}
/**
* tipc_reg_remove_port - deregister a user's driver port
*/
int tipc_reg_remove_port(struct user_port *up_ptr)
{
if (up_ptr->user_ref == 0)
return 0;
if (up_ptr->user_ref > MAX_USERID)
return -EINVAL;
if (!users )
return -ENOPROTOOPT;
spin_lock_bh(&reg_lock);
list_del_init(&up_ptr->uport_list);
spin_unlock_bh(&reg_lock);
return 0;
}

View File

@@ -0,0 +1,48 @@
/*
* net/tipc/user_reg.h: Include file for TIPC user registry code
*
* Copyright (c) 2000-2006, Ericsson AB
* Copyright (c) 2005, Wind River Systems
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. 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.
*
* Alternatively, this software may be distributed under the terms of the
* GNU General Public License ("GPL") version 2 as published by the Free
* Software Foundation.
*
* 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_USER_REG_H
#define _TIPC_USER_REG_H
#include "port.h"
int tipc_reg_start(void);
void tipc_reg_stop(void);
int tipc_reg_add_port(struct user_port *up_ptr);
int tipc_reg_remove_port(struct user_port *up_ptr);
#endif

173
kernel/net/tipc/zone.c Normal file
View File

@@ -0,0 +1,173 @@
/*
* net/tipc/zone.c: TIPC zone management routines
*
* Copyright (c) 2000-2006, Ericsson AB
* Copyright (c) 2005, Wind River Systems
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. 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.
*
* Alternatively, this software may be distributed under the terms of the
* GNU General Public License ("GPL") version 2 as published by the Free
* Software Foundation.
*
* 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 "zone.h"
#include "net.h"
#include "addr.h"
#include "node_subscr.h"
#include "cluster.h"
#include "node.h"
struct _zone *tipc_zone_create(u32 addr)
{
struct _zone *z_ptr;
u32 z_num;
if (!tipc_addr_domain_valid(addr)) {
err("Zone creation failed, invalid domain 0x%x\n", addr);
return NULL;
}
z_ptr = kzalloc(sizeof(*z_ptr), GFP_ATOMIC);
if (!z_ptr) {
warn("Zone creation failed, insufficient memory\n");
return NULL;
}
z_num = tipc_zone(addr);
z_ptr->addr = tipc_addr(z_num, 0, 0);
tipc_net.zones[z_num] = z_ptr;
return z_ptr;
}
void tipc_zone_delete(struct _zone *z_ptr)
{
u32 c_num;
if (!z_ptr)
return;
for (c_num = 1; c_num <= tipc_max_clusters; c_num++) {
tipc_cltr_delete(z_ptr->clusters[c_num]);
}
kfree(z_ptr);
}
void tipc_zone_attach_cluster(struct _zone *z_ptr, struct cluster *c_ptr)
{
u32 c_num = tipc_cluster(c_ptr->addr);
assert(c_ptr->addr);
assert(c_num <= tipc_max_clusters);
assert(z_ptr->clusters[c_num] == NULL);
z_ptr->clusters[c_num] = c_ptr;
}
void tipc_zone_remove_as_router(struct _zone *z_ptr, u32 router)
{
u32 c_num;
for (c_num = 1; c_num <= tipc_max_clusters; c_num++) {
if (z_ptr->clusters[c_num]) {
tipc_cltr_remove_as_router(z_ptr->clusters[c_num],
router);
}
}
}
void tipc_zone_send_external_routes(struct _zone *z_ptr, u32 dest)
{
u32 c_num;
for (c_num = 1; c_num <= tipc_max_clusters; c_num++) {
if (z_ptr->clusters[c_num]) {
if (in_own_cluster(z_ptr->addr))
continue;
tipc_cltr_send_ext_routes(z_ptr->clusters[c_num], dest);
}
}
}
struct tipc_node *tipc_zone_select_remote_node(struct _zone *z_ptr, u32 addr, u32 ref)
{
struct cluster *c_ptr;
struct tipc_node *n_ptr;
u32 c_num;
if (!z_ptr)
return NULL;
c_ptr = z_ptr->clusters[tipc_cluster(addr)];
if (!c_ptr)
return NULL;
n_ptr = tipc_cltr_select_node(c_ptr, ref);
if (n_ptr)
return n_ptr;
/* Links to any other clusters within this zone ? */
for (c_num = 1; c_num <= tipc_max_clusters; c_num++) {
c_ptr = z_ptr->clusters[c_num];
if (!c_ptr)
return NULL;
n_ptr = tipc_cltr_select_node(c_ptr, ref);
if (n_ptr)
return n_ptr;
}
return NULL;
}
u32 tipc_zone_select_router(struct _zone *z_ptr, u32 addr, u32 ref)
{
struct cluster *c_ptr;
u32 c_num;
u32 router;
if (!z_ptr)
return 0;
c_ptr = z_ptr->clusters[tipc_cluster(addr)];
router = c_ptr ? tipc_cltr_select_router(c_ptr, ref) : 0;
if (router)
return router;
/* Links to any other clusters within the zone? */
for (c_num = 1; c_num <= tipc_max_clusters; c_num++) {
c_ptr = z_ptr->clusters[c_num];
router = c_ptr ? tipc_cltr_select_router(c_ptr, ref) : 0;
if (router)
return router;
}
return 0;
}
u32 tipc_zone_next_node(u32 addr)
{
struct cluster *c_ptr = tipc_cltr_find(addr);
if (c_ptr)
return tipc_cltr_next_node(c_ptr, addr);
return 0;
}

71
kernel/net/tipc/zone.h Normal file
View File

@@ -0,0 +1,71 @@
/*
* net/tipc/zone.h: Include file for TIPC zone management routines
*
* Copyright (c) 2000-2006, Ericsson AB
* Copyright (c) 2005-2006, Wind River Systems
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. 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.
*
* Alternatively, this software may be distributed under the terms of the
* GNU General Public License ("GPL") version 2 as published by the Free
* Software Foundation.
*
* 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_ZONE_H
#define _TIPC_ZONE_H
#include "node_subscr.h"
#include "net.h"
/**
* struct _zone - TIPC zone structure
* @addr: network address of zone
* @clusters: array of pointers to all clusters within zone
* @links: number of (unicast) links to zone
*/
struct _zone {
u32 addr;
struct cluster *clusters[2]; /* currently limited to just 1 cluster */
u32 links;
};
struct tipc_node *tipc_zone_select_remote_node(struct _zone *z_ptr, u32 addr, u32 ref);
u32 tipc_zone_select_router(struct _zone *z_ptr, u32 addr, u32 ref);
void tipc_zone_remove_as_router(struct _zone *z_ptr, u32 router);
void tipc_zone_send_external_routes(struct _zone *z_ptr, u32 dest);
struct _zone *tipc_zone_create(u32 addr);
void tipc_zone_delete(struct _zone *z_ptr);
void tipc_zone_attach_cluster(struct _zone *z_ptr, struct cluster *c_ptr);
u32 tipc_zone_next_node(u32 addr);
static inline struct _zone *tipc_zone_find(u32 addr)
{
return tipc_net.zones[tipc_zone(addr)];
}
#endif