mirror of
https://github.com/AetherDroid/android_kernel_samsung_on5xelte.git
synced 2025-09-08 17:18:05 -04:00
Fixed MTP to work with TWRP
This commit is contained in:
commit
f6dfaef42e
50820 changed files with 20846062 additions and 0 deletions
40
net/tipc/Kconfig
Normal file
40
net/tipc/Kconfig
Normal file
|
@ -0,0 +1,40 @@
|
|||
#
|
||||
# TIPC configuration
|
||||
#
|
||||
|
||||
menuconfig TIPC
|
||||
tristate "The TIPC Protocol"
|
||||
depends on INET
|
||||
---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.
|
||||
|
||||
config TIPC_PORTS
|
||||
int "Maximum number of ports in a node"
|
||||
depends on TIPC
|
||||
range 127 65535
|
||||
default "8191"
|
||||
help
|
||||
Specifies how many ports can be supported by a node.
|
||||
Can range from 127 to 65535 ports; default is 8191.
|
||||
|
||||
Setting this to a smaller value saves some memory,
|
||||
setting it to higher allows for more ports.
|
||||
|
||||
config TIPC_MEDIA_IB
|
||||
bool "InfiniBand media type support"
|
||||
depends on TIPC && INFINIBAND_IPOIB
|
||||
help
|
||||
Saying Y here will enable support for running TIPC on
|
||||
IP-over-InfiniBand devices.
|
14
net/tipc/Makefile
Normal file
14
net/tipc/Makefile
Normal file
|
@ -0,0 +1,14 @@
|
|||
#
|
||||
# Makefile for the Linux TIPC layer
|
||||
#
|
||||
|
||||
obj-$(CONFIG_TIPC) := tipc.o
|
||||
|
||||
tipc-y += addr.o bcast.o bearer.o config.o \
|
||||
core.o link.o discover.o msg.o \
|
||||
name_distr.o subscr.o name_table.o net.o \
|
||||
netlink.o node.o node_subscr.o \
|
||||
socket.o log.o eth_media.o server.o
|
||||
|
||||
tipc-$(CONFIG_TIPC_MEDIA_IB) += ib_media.o
|
||||
tipc-$(CONFIG_SYSCTL) += sysctl.o
|
103
net/tipc/addr.c
Normal file
103
net/tipc/addr.c
Normal file
|
@ -0,0 +1,103 @@
|
|||
/*
|
||||
* net/tipc/addr.c: TIPC address utility routines
|
||||
*
|
||||
* Copyright (c) 2000-2006, Ericsson AB
|
||||
* Copyright (c) 2004-2005, 2010-2011, 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"
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* 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);
|
||||
|
||||
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.
|
||||
*
|
||||
* 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);
|
||||
}
|
||||
|
||||
int tipc_in_scope(u32 domain, u32 addr)
|
||||
{
|
||||
if (!domain || (domain == addr))
|
||||
return 1;
|
||||
if (domain == tipc_cluster_mask(addr)) /* domain <Z.C.0> */
|
||||
return 1;
|
||||
if (domain == tipc_zone_mask(addr)) /* domain <Z.0.0> */
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* tipc_addr_scope - convert message lookup domain to a 2-bit scope value
|
||||
*/
|
||||
int tipc_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;
|
||||
}
|
||||
|
||||
char *tipc_addr_string_fill(char *string, u32 addr)
|
||||
{
|
||||
snprintf(string, 16, "<%u.%u.%u>",
|
||||
tipc_zone(addr), tipc_cluster(addr), tipc_node(addr));
|
||||
return string;
|
||||
}
|
96
net/tipc/addr.h
Normal file
96
net/tipc/addr.h
Normal file
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* 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
|
||||
|
||||
#include "core.h"
|
||||
|
||||
#define TIPC_ZONE_MASK 0xff000000u
|
||||
#define TIPC_CLUSTER_MASK 0xfffff000u
|
||||
|
||||
static inline u32 tipc_zone_mask(u32 addr)
|
||||
{
|
||||
return addr & TIPC_ZONE_MASK;
|
||||
}
|
||||
|
||||
static inline u32 tipc_cluster_mask(u32 addr)
|
||||
{
|
||||
return addr & TIPC_CLUSTER_MASK;
|
||||
}
|
||||
|
||||
static inline int in_own_cluster_exact(u32 addr)
|
||||
{
|
||||
return !((addr ^ tipc_own_addr) >> 12);
|
||||
}
|
||||
|
||||
/**
|
||||
* in_own_node - test for node inclusion; <0.0.0> always matches
|
||||
*/
|
||||
static inline int in_own_node(u32 addr)
|
||||
{
|
||||
return (addr == tipc_own_addr) || !addr;
|
||||
}
|
||||
|
||||
/**
|
||||
* in_own_cluster - test for cluster inclusion; <0.0.0> always matches
|
||||
*/
|
||||
static inline int in_own_cluster(u32 addr)
|
||||
{
|
||||
return in_own_cluster_exact(addr) || !addr;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 u32 addr_domain(u32 sc)
|
||||
{
|
||||
if (likely(sc == TIPC_NODE_SCOPE))
|
||||
return tipc_own_addr;
|
||||
if (sc == TIPC_CLUSTER_SCOPE)
|
||||
return tipc_cluster_mask(tipc_own_addr);
|
||||
return tipc_zone_mask(tipc_own_addr);
|
||||
}
|
||||
|
||||
int tipc_addr_domain_valid(u32);
|
||||
int tipc_addr_node_valid(u32 addr);
|
||||
int tipc_in_scope(u32 domain, u32 addr);
|
||||
int tipc_addr_scope(u32 domain);
|
||||
char *tipc_addr_string_fill(char *string, u32 addr);
|
||||
#endif
|
983
net/tipc/bcast.c
Normal file
983
net/tipc/bcast.c
Normal file
|
@ -0,0 +1,983 @@
|
|||
/*
|
||||
* net/tipc/bcast.c: TIPC broadcast code
|
||||
*
|
||||
* Copyright (c) 2004-2006, 2014, Ericsson AB
|
||||
* Copyright (c) 2004, Intel Corporation.
|
||||
* Copyright (c) 2005, 2010-2011, 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 "link.h"
|
||||
#include "socket.h"
|
||||
#include "msg.h"
|
||||
#include "bcast.h"
|
||||
#include "name_distr.h"
|
||||
|
||||
#define MAX_PKT_DEFAULT_MCAST 1500 /* bcast link max packet size (fixed) */
|
||||
#define BCLINK_WIN_DEFAULT 20 /* bcast link window size (default) */
|
||||
#define BCBEARER MAX_BEARERS
|
||||
|
||||
/**
|
||||
* struct tipc_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 tipc_bcbearer_pair {
|
||||
struct tipc_bearer *primary;
|
||||
struct tipc_bearer *secondary;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct tipc_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 "bclink_lock".
|
||||
*/
|
||||
struct tipc_bcbearer {
|
||||
struct tipc_bearer bearer;
|
||||
struct tipc_media media;
|
||||
struct tipc_bcbearer_pair bpairs[MAX_BEARERS];
|
||||
struct tipc_bcbearer_pair bpairs_temp[TIPC_MAX_LINK_PRI + 1];
|
||||
struct tipc_node_map remains;
|
||||
struct tipc_node_map remains_new;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct tipc_bclink - link used for broadcast messages
|
||||
* @lock: spinlock governing access to structure
|
||||
* @link: (non-standard) broadcast link structure
|
||||
* @node: (non-standard) node structure representing b'cast link's peer node
|
||||
* @flags: represent bclink states
|
||||
* @bcast_nodes: map of broadcast-capable nodes
|
||||
* @retransmit_to: node that most recently requested a retransmit
|
||||
*
|
||||
* Handles sequence numbering, fragmentation, bundling, etc.
|
||||
*/
|
||||
struct tipc_bclink {
|
||||
spinlock_t lock;
|
||||
struct tipc_link link;
|
||||
struct tipc_node node;
|
||||
unsigned int flags;
|
||||
struct tipc_node_map bcast_nodes;
|
||||
struct tipc_node *retransmit_to;
|
||||
};
|
||||
|
||||
static struct tipc_bcbearer *bcbearer;
|
||||
static struct tipc_bclink *bclink;
|
||||
static struct tipc_link *bcl;
|
||||
|
||||
const char tipc_bclink_name[] = "broadcast-link";
|
||||
|
||||
static void tipc_nmap_diff(struct tipc_node_map *nm_a,
|
||||
struct tipc_node_map *nm_b,
|
||||
struct tipc_node_map *nm_diff);
|
||||
static void tipc_nmap_add(struct tipc_node_map *nm_ptr, u32 node);
|
||||
static void tipc_nmap_remove(struct tipc_node_map *nm_ptr, u32 node);
|
||||
|
||||
static void tipc_bclink_lock(void)
|
||||
{
|
||||
spin_lock_bh(&bclink->lock);
|
||||
}
|
||||
|
||||
static void tipc_bclink_unlock(void)
|
||||
{
|
||||
struct tipc_node *node = NULL;
|
||||
|
||||
if (likely(!bclink->flags)) {
|
||||
spin_unlock_bh(&bclink->lock);
|
||||
return;
|
||||
}
|
||||
|
||||
if (bclink->flags & TIPC_BCLINK_RESET) {
|
||||
bclink->flags &= ~TIPC_BCLINK_RESET;
|
||||
node = tipc_bclink_retransmit_to();
|
||||
}
|
||||
spin_unlock_bh(&bclink->lock);
|
||||
|
||||
if (node)
|
||||
tipc_link_reset_all(node);
|
||||
}
|
||||
|
||||
uint tipc_bclink_get_mtu(void)
|
||||
{
|
||||
return MAX_PKT_DEFAULT_MCAST;
|
||||
}
|
||||
|
||||
void tipc_bclink_set_flags(unsigned int flags)
|
||||
{
|
||||
bclink->flags |= flags;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void tipc_bclink_add_node(u32 addr)
|
||||
{
|
||||
tipc_bclink_lock();
|
||||
tipc_nmap_add(&bclink->bcast_nodes, addr);
|
||||
tipc_bclink_unlock();
|
||||
}
|
||||
|
||||
void tipc_bclink_remove_node(u32 addr)
|
||||
{
|
||||
tipc_bclink_lock();
|
||||
tipc_nmap_remove(&bclink->bcast_nodes, addr);
|
||||
tipc_bclink_unlock();
|
||||
}
|
||||
|
||||
static void bclink_set_last_sent(void)
|
||||
{
|
||||
if (bcl->next_out)
|
||||
bcl->fsm_msg_cnt = mod(buf_seqno(bcl->next_out) - 1);
|
||||
else
|
||||
bcl->fsm_msg_cnt = mod(bcl->next_out_no - 1);
|
||||
}
|
||||
|
||||
u32 tipc_bclink_get_last_sent(void)
|
||||
{
|
||||
return bcl->fsm_msg_cnt;
|
||||
}
|
||||
|
||||
static void bclink_update_last_sent(struct tipc_node *node, u32 seqno)
|
||||
{
|
||||
node->bclink.last_sent = less_eq(node->bclink.last_sent, seqno) ?
|
||||
seqno : node->bclink.last_sent;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* tipc_bclink_retransmit_to - get most recent node to request retransmission
|
||||
*
|
||||
* Called with bclink_lock locked
|
||||
*/
|
||||
struct tipc_node *tipc_bclink_retransmit_to(void)
|
||||
{
|
||||
return bclink->retransmit_to;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 bclink_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_wakeup_users - wake up pending users
|
||||
*
|
||||
* Called with no locks taken
|
||||
*/
|
||||
void tipc_bclink_wakeup_users(void)
|
||||
{
|
||||
while (skb_queue_len(&bclink->link.waiting_sks))
|
||||
tipc_sk_rcv(skb_dequeue(&bclink->link.waiting_sks));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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, bclink_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;
|
||||
|
||||
tipc_bclink_lock();
|
||||
/* Bail out if tx queue is empty (no clean up is required) */
|
||||
crs = bcl->first_out;
|
||||
if (!crs)
|
||||
goto exit;
|
||||
|
||||
/* Determine which messages need to be acknowledged */
|
||||
if (acked == INVALID_LINK_SEQ) {
|
||||
/*
|
||||
* Contact with specified node has been lost, so need to
|
||||
* acknowledge sent messages only (if other nodes still exist)
|
||||
* or both sent and unsent messages (otherwise)
|
||||
*/
|
||||
if (bclink->bcast_nodes.count)
|
||||
acked = bcl->fsm_msg_cnt;
|
||||
else
|
||||
acked = bcl->next_out_no;
|
||||
} else {
|
||||
/*
|
||||
* Bail out if specified sequence number does not correspond
|
||||
* to a message that has been sent and not yet acknowledged
|
||||
*/
|
||||
if (less(acked, buf_seqno(crs)) ||
|
||||
less(bcl->fsm_msg_cnt, acked) ||
|
||||
less_eq(acked, n_ptr->bclink.acked))
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* Skip over packets that node has previously acknowledged */
|
||||
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;
|
||||
|
||||
if (crs != bcl->next_out)
|
||||
bcbuf_decr_acks(crs);
|
||||
else {
|
||||
bcbuf_set_acks(crs, 0);
|
||||
bcl->next_out = next;
|
||||
bclink_set_last_sent();
|
||||
}
|
||||
|
||||
if (bcbuf_acks(crs) == 0) {
|
||||
bcl->first_out = next;
|
||||
bcl->out_queue_size--;
|
||||
kfree_skb(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);
|
||||
bclink_set_last_sent();
|
||||
}
|
||||
if (unlikely(released && !skb_queue_empty(&bcl->waiting_sks)))
|
||||
n_ptr->action_flags |= TIPC_WAKEUP_BCAST_USERS;
|
||||
|
||||
exit:
|
||||
tipc_bclink_unlock();
|
||||
}
|
||||
|
||||
/**
|
||||
* tipc_bclink_update_link_state - update broadcast link state
|
||||
*
|
||||
* RCU and node lock set
|
||||
*/
|
||||
void tipc_bclink_update_link_state(struct tipc_node *n_ptr, u32 last_sent)
|
||||
{
|
||||
struct sk_buff *buf;
|
||||
|
||||
/* Ignore "stale" link state info */
|
||||
|
||||
if (less_eq(last_sent, n_ptr->bclink.last_in))
|
||||
return;
|
||||
|
||||
/* Update link synchronization state; quit if in sync */
|
||||
|
||||
bclink_update_last_sent(n_ptr, last_sent);
|
||||
|
||||
if (n_ptr->bclink.last_sent == n_ptr->bclink.last_in)
|
||||
return;
|
||||
|
||||
/* Update out-of-sync state; quit if loss is still unconfirmed */
|
||||
|
||||
if ((++n_ptr->bclink.oos_state) == 1) {
|
||||
if (n_ptr->bclink.deferred_size < (TIPC_MIN_LINK_WIN / 2))
|
||||
return;
|
||||
n_ptr->bclink.oos_state++;
|
||||
}
|
||||
|
||||
/* Don't NACK if one has been recently sent (or seen) */
|
||||
|
||||
if (n_ptr->bclink.oos_state & 0x1)
|
||||
return;
|
||||
|
||||
/* Send NACK */
|
||||
|
||||
buf = tipc_buf_acquire(INT_H_SIZE);
|
||||
if (buf) {
|
||||
struct tipc_msg *msg = buf_msg(buf);
|
||||
|
||||
tipc_msg_init(msg, BCAST_PROTOCOL, STATE_MSG,
|
||||
INT_H_SIZE, n_ptr->addr);
|
||||
msg_set_non_seq(msg, 1);
|
||||
msg_set_mc_netid(msg, tipc_net_id);
|
||||
msg_set_bcast_ack(msg, n_ptr->bclink.last_in);
|
||||
msg_set_bcgap_after(msg, n_ptr->bclink.last_in);
|
||||
msg_set_bcgap_to(msg, n_ptr->bclink.deferred_head
|
||||
? buf_seqno(n_ptr->bclink.deferred_head) - 1
|
||||
: n_ptr->bclink.last_sent);
|
||||
|
||||
tipc_bclink_lock();
|
||||
tipc_bearer_send(MAX_BEARERS, buf, NULL);
|
||||
bcl->stats.sent_nacks++;
|
||||
tipc_bclink_unlock();
|
||||
kfree_skb(buf);
|
||||
|
||||
n_ptr->bclink.oos_state++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* bclink_peek_nack - monitor retransmission requests sent by other nodes
|
||||
*
|
||||
* Delay any upcoming NACK by this node if another node has already
|
||||
* requested the first message this node is going to ask for.
|
||||
*/
|
||||
static void bclink_peek_nack(struct tipc_msg *msg)
|
||||
{
|
||||
struct tipc_node *n_ptr = tipc_node_find(msg_destnode(msg));
|
||||
|
||||
if (unlikely(!n_ptr))
|
||||
return;
|
||||
|
||||
tipc_node_lock(n_ptr);
|
||||
|
||||
if (n_ptr->bclink.recv_permitted &&
|
||||
(n_ptr->bclink.last_in != n_ptr->bclink.last_sent) &&
|
||||
(n_ptr->bclink.last_in == msg_bcgap_after(msg)))
|
||||
n_ptr->bclink.oos_state = 2;
|
||||
|
||||
tipc_node_unlock(n_ptr);
|
||||
}
|
||||
|
||||
/* tipc_bclink_xmit - broadcast buffer chain to all nodes in cluster
|
||||
* and to identified node local sockets
|
||||
* @buf: chain of buffers containing message
|
||||
* Consumes the buffer chain, except when returning -ELINKCONG
|
||||
* Returns 0 if success, otherwise errno: -ELINKCONG,-EHOSTUNREACH,-EMSGSIZE
|
||||
*/
|
||||
int tipc_bclink_xmit(struct sk_buff *buf)
|
||||
{
|
||||
int rc = 0;
|
||||
int bc = 0;
|
||||
struct sk_buff *clbuf;
|
||||
|
||||
/* Prepare clone of message for local node */
|
||||
clbuf = tipc_msg_reassemble(buf);
|
||||
if (unlikely(!clbuf)) {
|
||||
kfree_skb_list(buf);
|
||||
return -EHOSTUNREACH;
|
||||
}
|
||||
|
||||
/* Broadcast to all other nodes */
|
||||
if (likely(bclink)) {
|
||||
tipc_bclink_lock();
|
||||
if (likely(bclink->bcast_nodes.count)) {
|
||||
rc = __tipc_link_xmit(bcl, buf);
|
||||
if (likely(!rc)) {
|
||||
bclink_set_last_sent();
|
||||
bcl->stats.queue_sz_counts++;
|
||||
bcl->stats.accu_queue_sz += bcl->out_queue_size;
|
||||
}
|
||||
bc = 1;
|
||||
}
|
||||
tipc_bclink_unlock();
|
||||
}
|
||||
|
||||
if (unlikely(!bc))
|
||||
kfree_skb_list(buf);
|
||||
|
||||
/* Deliver message clone */
|
||||
if (likely(!rc))
|
||||
tipc_sk_mcast_rcv(clbuf);
|
||||
else
|
||||
kfree_skb(clbuf);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* bclink_accept_pkt - accept an incoming, in-sequence broadcast packet
|
||||
*
|
||||
* Called with both sending node's lock and bclink_lock taken.
|
||||
*/
|
||||
static void bclink_accept_pkt(struct tipc_node *node, u32 seqno)
|
||||
{
|
||||
bclink_update_last_sent(node, seqno);
|
||||
node->bclink.last_in = seqno;
|
||||
node->bclink.oos_state = 0;
|
||||
bcl->stats.recv_info++;
|
||||
|
||||
/*
|
||||
* Unicast an ACK periodically, ensuring that
|
||||
* all nodes in the cluster don't ACK at the same time
|
||||
*/
|
||||
|
||||
if (((seqno - tipc_own_addr) % TIPC_MIN_LINK_WIN) == 0) {
|
||||
tipc_link_proto_xmit(node->active_links[node->addr & 1],
|
||||
STATE_MSG, 0, 0, 0, 0, 0);
|
||||
bcl->stats.sent_acks++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* tipc_bclink_rcv - receive a broadcast packet, and deliver upwards
|
||||
*
|
||||
* RCU is locked, no other locks set
|
||||
*/
|
||||
void tipc_bclink_rcv(struct sk_buff *buf)
|
||||
{
|
||||
struct tipc_msg *msg = buf_msg(buf);
|
||||
struct tipc_node *node;
|
||||
u32 next_in;
|
||||
u32 seqno;
|
||||
int deferred = 0;
|
||||
|
||||
/* Screen out unwanted broadcast messages */
|
||||
|
||||
if (msg_mc_netid(msg) != tipc_net_id)
|
||||
goto exit;
|
||||
|
||||
node = tipc_node_find(msg_prevnode(msg));
|
||||
if (unlikely(!node))
|
||||
goto exit;
|
||||
|
||||
tipc_node_lock(node);
|
||||
if (unlikely(!node->bclink.recv_permitted))
|
||||
goto unlock;
|
||||
|
||||
/* Handle broadcast protocol message */
|
||||
|
||||
if (unlikely(msg_user(msg) == BCAST_PROTOCOL)) {
|
||||
if (msg_type(msg) != STATE_MSG)
|
||||
goto unlock;
|
||||
if (msg_destnode(msg) == tipc_own_addr) {
|
||||
tipc_bclink_acknowledge(node, msg_bcast_ack(msg));
|
||||
tipc_node_unlock(node);
|
||||
tipc_bclink_lock();
|
||||
bcl->stats.recv_nacks++;
|
||||
bclink->retransmit_to = node;
|
||||
bclink_retransmit_pkt(msg_bcgap_after(msg),
|
||||
msg_bcgap_to(msg));
|
||||
tipc_bclink_unlock();
|
||||
} else {
|
||||
tipc_node_unlock(node);
|
||||
bclink_peek_nack(msg);
|
||||
}
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* Handle in-sequence broadcast message */
|
||||
|
||||
seqno = msg_seqno(msg);
|
||||
next_in = mod(node->bclink.last_in + 1);
|
||||
|
||||
if (likely(seqno == next_in)) {
|
||||
receive:
|
||||
/* Deliver message to destination */
|
||||
|
||||
if (likely(msg_isdata(msg))) {
|
||||
tipc_bclink_lock();
|
||||
bclink_accept_pkt(node, seqno);
|
||||
tipc_bclink_unlock();
|
||||
tipc_node_unlock(node);
|
||||
if (likely(msg_mcast(msg)))
|
||||
tipc_sk_mcast_rcv(buf);
|
||||
else
|
||||
kfree_skb(buf);
|
||||
} else if (msg_user(msg) == MSG_BUNDLER) {
|
||||
tipc_bclink_lock();
|
||||
bclink_accept_pkt(node, seqno);
|
||||
bcl->stats.recv_bundles++;
|
||||
bcl->stats.recv_bundled += msg_msgcnt(msg);
|
||||
tipc_bclink_unlock();
|
||||
tipc_node_unlock(node);
|
||||
tipc_link_bundle_rcv(buf);
|
||||
} else if (msg_user(msg) == MSG_FRAGMENTER) {
|
||||
tipc_buf_append(&node->bclink.reasm_buf, &buf);
|
||||
if (unlikely(!buf && !node->bclink.reasm_buf))
|
||||
goto unlock;
|
||||
tipc_bclink_lock();
|
||||
bclink_accept_pkt(node, seqno);
|
||||
bcl->stats.recv_fragments++;
|
||||
if (buf) {
|
||||
bcl->stats.recv_fragmented++;
|
||||
msg = buf_msg(buf);
|
||||
tipc_bclink_unlock();
|
||||
goto receive;
|
||||
}
|
||||
tipc_bclink_unlock();
|
||||
tipc_node_unlock(node);
|
||||
} else if (msg_user(msg) == NAME_DISTRIBUTOR) {
|
||||
tipc_bclink_lock();
|
||||
bclink_accept_pkt(node, seqno);
|
||||
tipc_bclink_unlock();
|
||||
tipc_node_unlock(node);
|
||||
tipc_named_rcv(buf);
|
||||
} else {
|
||||
tipc_bclink_lock();
|
||||
bclink_accept_pkt(node, seqno);
|
||||
tipc_bclink_unlock();
|
||||
tipc_node_unlock(node);
|
||||
kfree_skb(buf);
|
||||
}
|
||||
buf = NULL;
|
||||
|
||||
/* Determine new synchronization state */
|
||||
|
||||
tipc_node_lock(node);
|
||||
if (unlikely(!tipc_node_is_up(node)))
|
||||
goto unlock;
|
||||
|
||||
if (node->bclink.last_in == node->bclink.last_sent)
|
||||
goto unlock;
|
||||
|
||||
if (!node->bclink.deferred_head) {
|
||||
node->bclink.oos_state = 1;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
msg = buf_msg(node->bclink.deferred_head);
|
||||
seqno = msg_seqno(msg);
|
||||
next_in = mod(next_in + 1);
|
||||
if (seqno != next_in)
|
||||
goto unlock;
|
||||
|
||||
/* Take in-sequence message from deferred queue & deliver it */
|
||||
|
||||
buf = node->bclink.deferred_head;
|
||||
node->bclink.deferred_head = buf->next;
|
||||
buf->next = NULL;
|
||||
node->bclink.deferred_size--;
|
||||
goto receive;
|
||||
}
|
||||
|
||||
/* Handle out-of-sequence broadcast message */
|
||||
|
||||
if (less(next_in, seqno)) {
|
||||
deferred = tipc_link_defer_pkt(&node->bclink.deferred_head,
|
||||
&node->bclink.deferred_tail,
|
||||
buf);
|
||||
node->bclink.deferred_size += deferred;
|
||||
bclink_update_last_sent(node, seqno);
|
||||
buf = NULL;
|
||||
}
|
||||
|
||||
tipc_bclink_lock();
|
||||
|
||||
if (deferred)
|
||||
bcl->stats.deferred_recv++;
|
||||
else
|
||||
bcl->stats.duplicates++;
|
||||
|
||||
tipc_bclink_unlock();
|
||||
|
||||
unlock:
|
||||
tipc_node_unlock(node);
|
||||
exit:
|
||||
kfree_skb(buf);
|
||||
}
|
||||
|
||||
u32 tipc_bclink_acks_missing(struct tipc_node *n_ptr)
|
||||
{
|
||||
return (n_ptr->bclink.recv_permitted &&
|
||||
(tipc_bclink_get_last_sent() != n_ptr->bclink.acked));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* tipc_bcbearer_send - send a packet through the broadcast pseudo-bearer
|
||||
*
|
||||
* Send packet over as many bearers as necessary to reach all nodes
|
||||
* that have joined the broadcast link.
|
||||
*
|
||||
* Returns 0 (packet sent successfully) under all circumstances,
|
||||
* since the broadcast link's pseudo-bearer never blocks
|
||||
*/
|
||||
static int tipc_bcbearer_send(struct sk_buff *buf, struct tipc_bearer *unused1,
|
||||
struct tipc_media_addr *unused2)
|
||||
{
|
||||
int bp_index;
|
||||
struct tipc_msg *msg = buf_msg(buf);
|
||||
|
||||
/* Prepare broadcast link message for reliable transmission,
|
||||
* if first time trying to send it;
|
||||
* preparation is skipped for broadcast link protocol messages
|
||||
* since they are sent in an unreliable manner and don't need it
|
||||
*/
|
||||
if (likely(!msg_non_seq(buf_msg(buf)))) {
|
||||
bcbuf_set_acks(buf, bclink->bcast_nodes.count);
|
||||
msg_set_non_seq(msg, 1);
|
||||
msg_set_mc_netid(msg, tipc_net_id);
|
||||
bcl->stats.sent_info++;
|
||||
|
||||
if (WARN_ON(!bclink->bcast_nodes.count)) {
|
||||
dump_stack();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Send buffer over bearers until all targets reached */
|
||||
bcbearer->remains = bclink->bcast_nodes;
|
||||
|
||||
for (bp_index = 0; bp_index < MAX_BEARERS; bp_index++) {
|
||||
struct tipc_bearer *p = bcbearer->bpairs[bp_index].primary;
|
||||
struct tipc_bearer *s = bcbearer->bpairs[bp_index].secondary;
|
||||
struct tipc_bearer *bp[2] = {p, s};
|
||||
struct tipc_bearer *b = bp[msg_link_selector(msg)];
|
||||
struct sk_buff *tbuf;
|
||||
|
||||
if (!p)
|
||||
break; /* No more bearers to try */
|
||||
if (!b)
|
||||
b = p;
|
||||
tipc_nmap_diff(&bcbearer->remains, &b->nodes,
|
||||
&bcbearer->remains_new);
|
||||
if (bcbearer->remains_new.count == bcbearer->remains.count)
|
||||
continue; /* Nothing added by bearer pair */
|
||||
|
||||
if (bp_index == 0) {
|
||||
/* Use original buffer for first bearer */
|
||||
tipc_bearer_send(b->identity, buf, &b->bcast_addr);
|
||||
} else {
|
||||
/* Avoid concurrent buffer access */
|
||||
tbuf = pskb_copy_for_clone(buf, GFP_ATOMIC);
|
||||
if (!tbuf)
|
||||
break;
|
||||
tipc_bearer_send(b->identity, tbuf, &b->bcast_addr);
|
||||
kfree_skb(tbuf); /* Bearer keeps a clone */
|
||||
}
|
||||
if (bcbearer->remains_new.count == 0)
|
||||
break; /* All targets reached */
|
||||
|
||||
bcbearer->remains = bcbearer->remains_new;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* tipc_bcbearer_sort - create sets of bearer pairs used by broadcast bearer
|
||||
*/
|
||||
void tipc_bcbearer_sort(struct tipc_node_map *nm_ptr, u32 node, bool action)
|
||||
{
|
||||
struct tipc_bcbearer_pair *bp_temp = bcbearer->bpairs_temp;
|
||||
struct tipc_bcbearer_pair *bp_curr;
|
||||
struct tipc_bearer *b;
|
||||
int b_index;
|
||||
int pri;
|
||||
|
||||
tipc_bclink_lock();
|
||||
|
||||
if (action)
|
||||
tipc_nmap_add(nm_ptr, node);
|
||||
else
|
||||
tipc_nmap_remove(nm_ptr, node);
|
||||
|
||||
/* Group bearers by priority (can assume max of two per priority) */
|
||||
memset(bp_temp, 0, sizeof(bcbearer->bpairs_temp));
|
||||
|
||||
rcu_read_lock();
|
||||
for (b_index = 0; b_index < MAX_BEARERS; b_index++) {
|
||||
b = rcu_dereference_rtnl(bearer_list[b_index]);
|
||||
if (!b || !b->nodes.count)
|
||||
continue;
|
||||
|
||||
if (!bp_temp[b->priority].primary)
|
||||
bp_temp[b->priority].primary = b;
|
||||
else
|
||||
bp_temp[b->priority].secondary = b;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
/* 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++;
|
||||
}
|
||||
|
||||
tipc_bclink_unlock();
|
||||
}
|
||||
|
||||
|
||||
int tipc_bclink_stats(char *buf, const u32 buf_size)
|
||||
{
|
||||
int ret;
|
||||
struct tipc_stats *s;
|
||||
|
||||
if (!bcl)
|
||||
return 0;
|
||||
|
||||
tipc_bclink_lock();
|
||||
|
||||
s = &bcl->stats;
|
||||
|
||||
ret = tipc_snprintf(buf, buf_size, "Link <%s>\n"
|
||||
" Window:%u packets\n",
|
||||
bcl->name, bcl->queue_limit[0]);
|
||||
ret += tipc_snprintf(buf + ret, buf_size - ret,
|
||||
" RX packets:%u fragments:%u/%u bundles:%u/%u\n",
|
||||
s->recv_info, s->recv_fragments,
|
||||
s->recv_fragmented, s->recv_bundles,
|
||||
s->recv_bundled);
|
||||
ret += tipc_snprintf(buf + ret, buf_size - ret,
|
||||
" TX packets:%u fragments:%u/%u bundles:%u/%u\n",
|
||||
s->sent_info, s->sent_fragments,
|
||||
s->sent_fragmented, s->sent_bundles,
|
||||
s->sent_bundled);
|
||||
ret += tipc_snprintf(buf + ret, buf_size - ret,
|
||||
" RX naks:%u defs:%u dups:%u\n",
|
||||
s->recv_nacks, s->deferred_recv, s->duplicates);
|
||||
ret += tipc_snprintf(buf + ret, buf_size - ret,
|
||||
" TX naks:%u acks:%u dups:%u\n",
|
||||
s->sent_nacks, s->sent_acks, s->retransmitted);
|
||||
ret += tipc_snprintf(buf + ret, buf_size - ret,
|
||||
" Congestion link:%u Send queue max:%u avg:%u\n",
|
||||
s->link_congs, s->max_queue_sz,
|
||||
s->queue_sz_counts ?
|
||||
(s->accu_queue_sz / s->queue_sz_counts) : 0);
|
||||
|
||||
tipc_bclink_unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
int tipc_bclink_reset_stats(void)
|
||||
{
|
||||
if (!bcl)
|
||||
return -ENOPROTOOPT;
|
||||
|
||||
tipc_bclink_lock();
|
||||
memset(&bcl->stats, 0, sizeof(bcl->stats));
|
||||
tipc_bclink_unlock();
|
||||
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;
|
||||
|
||||
tipc_bclink_lock();
|
||||
tipc_link_set_queue_limits(bcl, limit);
|
||||
tipc_bclink_unlock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tipc_bclink_init(void)
|
||||
{
|
||||
bcbearer = kzalloc(sizeof(*bcbearer), GFP_ATOMIC);
|
||||
if (!bcbearer)
|
||||
return -ENOMEM;
|
||||
|
||||
bclink = kzalloc(sizeof(*bclink), GFP_ATOMIC);
|
||||
if (!bclink) {
|
||||
kfree(bcbearer);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
bcl = &bclink->link;
|
||||
bcbearer->bearer.media = &bcbearer->media;
|
||||
bcbearer->media.send_msg = tipc_bcbearer_send;
|
||||
sprintf(bcbearer->media.name, "tipc-broadcast");
|
||||
|
||||
spin_lock_init(&bclink->lock);
|
||||
__skb_queue_head_init(&bcl->waiting_sks);
|
||||
bcl->next_out_no = 1;
|
||||
spin_lock_init(&bclink->node.lock);
|
||||
__skb_queue_head_init(&bclink->node.waiting_sks);
|
||||
bcl->owner = &bclink->node;
|
||||
bcl->max_pkt = MAX_PKT_DEFAULT_MCAST;
|
||||
tipc_link_set_queue_limits(bcl, BCLINK_WIN_DEFAULT);
|
||||
bcl->bearer_id = MAX_BEARERS;
|
||||
rcu_assign_pointer(bearer_list[MAX_BEARERS], &bcbearer->bearer);
|
||||
bcl->state = WORKING_WORKING;
|
||||
strlcpy(bcl->name, tipc_bclink_name, TIPC_MAX_LINK_NAME);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void tipc_bclink_stop(void)
|
||||
{
|
||||
tipc_bclink_lock();
|
||||
tipc_link_purge_queues(bcl);
|
||||
tipc_bclink_unlock();
|
||||
|
||||
RCU_INIT_POINTER(bearer_list[BCBEARER], NULL);
|
||||
synchronize_net();
|
||||
kfree(bcbearer);
|
||||
kfree(bclink);
|
||||
}
|
||||
|
||||
/**
|
||||
* tipc_nmap_add - add a node to a node map
|
||||
*/
|
||||
static 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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* tipc_nmap_remove - remove a node from a node map
|
||||
*/
|
||||
static 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--;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* tipc_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 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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* tipc_port_list_add - add a port to a port list, ensuring no duplicates
|
||||
*/
|
||||
void tipc_port_list_add(struct tipc_port_list *pl_ptr, u32 port)
|
||||
{
|
||||
struct tipc_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) {
|
||||
pr_warn("Incomplete multicast delivery, no memory\n");
|
||||
return;
|
||||
}
|
||||
item->next->next = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* tipc_port_list_free - free dynamically created entries in port_list chain
|
||||
*
|
||||
*/
|
||||
void tipc_port_list_free(struct tipc_port_list *pl_ptr)
|
||||
{
|
||||
struct tipc_port_list *item;
|
||||
struct tipc_port_list *next;
|
||||
|
||||
for (item = pl_ptr->next; item; item = next) {
|
||||
next = item->next;
|
||||
kfree(item);
|
||||
}
|
||||
}
|
103
net/tipc/bcast.h
Normal file
103
net/tipc/bcast.h
Normal file
|
@ -0,0 +1,103 @@
|
|||
/*
|
||||
* net/tipc/bcast.h: Include file for TIPC broadcast code
|
||||
*
|
||||
* Copyright (c) 2003-2006, 2014, Ericsson AB
|
||||
* Copyright (c) 2005, 2010-2011, 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
|
||||
#define TIPC_BCLINK_RESET 1
|
||||
|
||||
/**
|
||||
* 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 tipc_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 tipc_port_list {
|
||||
int count;
|
||||
struct tipc_port_list *next;
|
||||
u32 ports[PLSIZE];
|
||||
};
|
||||
|
||||
|
||||
struct tipc_node;
|
||||
|
||||
extern const char tipc_bclink_name[];
|
||||
|
||||
/**
|
||||
* tipc_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));
|
||||
}
|
||||
|
||||
void tipc_port_list_add(struct tipc_port_list *pl_ptr, u32 port);
|
||||
void tipc_port_list_free(struct tipc_port_list *pl_ptr);
|
||||
|
||||
int tipc_bclink_init(void);
|
||||
void tipc_bclink_stop(void);
|
||||
void tipc_bclink_set_flags(unsigned int flags);
|
||||
void tipc_bclink_add_node(u32 addr);
|
||||
void tipc_bclink_remove_node(u32 addr);
|
||||
struct tipc_node *tipc_bclink_retransmit_to(void);
|
||||
void tipc_bclink_acknowledge(struct tipc_node *n_ptr, u32 acked);
|
||||
void tipc_bclink_rcv(struct sk_buff *buf);
|
||||
u32 tipc_bclink_get_last_sent(void);
|
||||
u32 tipc_bclink_acks_missing(struct tipc_node *n_ptr);
|
||||
void tipc_bclink_update_link_state(struct tipc_node *n_ptr, u32 last_sent);
|
||||
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(struct tipc_node_map *nm_ptr, u32 node, bool action);
|
||||
uint tipc_bclink_get_mtu(void);
|
||||
int tipc_bclink_xmit(struct sk_buff *buf);
|
||||
void tipc_bclink_wakeup_users(void);
|
||||
#endif
|
629
net/tipc/bearer.c
Normal file
629
net/tipc/bearer.c
Normal file
|
@ -0,0 +1,629 @@
|
|||
/*
|
||||
* net/tipc/bearer.c: TIPC bearer code
|
||||
*
|
||||
* Copyright (c) 1996-2006, 2013, Ericsson AB
|
||||
* Copyright (c) 2004-2006, 2010-2013, 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 "bearer.h"
|
||||
#include "discover.h"
|
||||
|
||||
#define MAX_ADDR_STR 60
|
||||
|
||||
static struct tipc_media * const media_info_array[] = {
|
||||
ð_media_info,
|
||||
#ifdef CONFIG_TIPC_MEDIA_IB
|
||||
&ib_media_info,
|
||||
#endif
|
||||
NULL
|
||||
};
|
||||
|
||||
struct tipc_bearer __rcu *bearer_list[MAX_BEARERS + 1];
|
||||
|
||||
static void bearer_disable(struct tipc_bearer *b_ptr, bool shutting_down);
|
||||
|
||||
/**
|
||||
* tipc_media_find - locates specified media object by name
|
||||
*/
|
||||
struct tipc_media *tipc_media_find(const char *name)
|
||||
{
|
||||
u32 i;
|
||||
|
||||
for (i = 0; media_info_array[i] != NULL; i++) {
|
||||
if (!strcmp(media_info_array[i]->name, name))
|
||||
break;
|
||||
}
|
||||
return media_info_array[i];
|
||||
}
|
||||
|
||||
/**
|
||||
* media_find_id - locates specified media object by type identifier
|
||||
*/
|
||||
static struct tipc_media *media_find_id(u8 type)
|
||||
{
|
||||
u32 i;
|
||||
|
||||
for (i = 0; media_info_array[i] != NULL; i++) {
|
||||
if (media_info_array[i]->type_id == type)
|
||||
break;
|
||||
}
|
||||
return media_info_array[i];
|
||||
}
|
||||
|
||||
/**
|
||||
* tipc_media_addr_printf - record media address in print buffer
|
||||
*/
|
||||
void tipc_media_addr_printf(char *buf, int len, struct tipc_media_addr *a)
|
||||
{
|
||||
char addr_str[MAX_ADDR_STR];
|
||||
struct tipc_media *m_ptr;
|
||||
int ret;
|
||||
|
||||
m_ptr = media_find_id(a->media_id);
|
||||
|
||||
if (m_ptr && !m_ptr->addr2str(a, addr_str, sizeof(addr_str)))
|
||||
ret = tipc_snprintf(buf, len, "%s(%s)", m_ptr->name, addr_str);
|
||||
else {
|
||||
u32 i;
|
||||
|
||||
ret = tipc_snprintf(buf, len, "UNKNOWN(%u)", a->media_id);
|
||||
for (i = 0; i < sizeof(a->value); i++)
|
||||
ret += tipc_snprintf(buf - ret, len + ret,
|
||||
"-%02x", a->value[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* tipc_media_get_names - record names of registered media in buffer
|
||||
*/
|
||||
struct sk_buff *tipc_media_get_names(void)
|
||||
{
|
||||
struct sk_buff *buf;
|
||||
int i;
|
||||
|
||||
buf = tipc_cfg_reply_alloc(MAX_MEDIA * TLV_SPACE(TIPC_MAX_MEDIA_NAME));
|
||||
if (!buf)
|
||||
return NULL;
|
||||
|
||||
for (i = 0; media_info_array[i] != NULL; i++) {
|
||||
tipc_cfg_append_tlv(buf, TIPC_TLV_MEDIA_NAME,
|
||||
media_info_array[i]->name,
|
||||
strlen(media_info_array[i]->name) + 1);
|
||||
}
|
||||
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 tipc_bearer_names *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_name = strchr(media_name, ':');
|
||||
if (if_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))
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* tipc_bearer_find - locates bearer object with matching bearer name
|
||||
*/
|
||||
struct tipc_bearer *tipc_bearer_find(const char *name)
|
||||
{
|
||||
struct tipc_bearer *b_ptr;
|
||||
u32 i;
|
||||
|
||||
for (i = 0; i < MAX_BEARERS; i++) {
|
||||
b_ptr = rtnl_dereference(bearer_list[i]);
|
||||
if (b_ptr && (!strcmp(b_ptr->name, 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 tipc_bearer *b;
|
||||
int i, j;
|
||||
|
||||
buf = tipc_cfg_reply_alloc(MAX_BEARERS * TLV_SPACE(TIPC_MAX_BEARER_NAME));
|
||||
if (!buf)
|
||||
return NULL;
|
||||
|
||||
for (i = 0; media_info_array[i] != NULL; i++) {
|
||||
for (j = 0; j < MAX_BEARERS; j++) {
|
||||
b = rtnl_dereference(bearer_list[j]);
|
||||
if (!b)
|
||||
continue;
|
||||
if (b->media == media_info_array[i]) {
|
||||
tipc_cfg_append_tlv(buf, TIPC_TLV_BEARER_NAME,
|
||||
b->name,
|
||||
strlen(b->name) + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
void tipc_bearer_add_dest(u32 bearer_id, u32 dest)
|
||||
{
|
||||
struct tipc_bearer *b_ptr;
|
||||
|
||||
rcu_read_lock();
|
||||
b_ptr = rcu_dereference_rtnl(bearer_list[bearer_id]);
|
||||
if (b_ptr) {
|
||||
tipc_bcbearer_sort(&b_ptr->nodes, dest, true);
|
||||
tipc_disc_add_dest(b_ptr->link_req);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
void tipc_bearer_remove_dest(u32 bearer_id, u32 dest)
|
||||
{
|
||||
struct tipc_bearer *b_ptr;
|
||||
|
||||
rcu_read_lock();
|
||||
b_ptr = rcu_dereference_rtnl(bearer_list[bearer_id]);
|
||||
if (b_ptr) {
|
||||
tipc_bcbearer_sort(&b_ptr->nodes, dest, false);
|
||||
tipc_disc_remove_dest(b_ptr->link_req);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
/**
|
||||
* tipc_enable_bearer - enable bearer with the given name
|
||||
*/
|
||||
int tipc_enable_bearer(const char *name, u32 disc_domain, u32 priority)
|
||||
{
|
||||
struct tipc_bearer *b_ptr;
|
||||
struct tipc_media *m_ptr;
|
||||
struct tipc_bearer_names b_names;
|
||||
char addr_string[16];
|
||||
u32 bearer_id;
|
||||
u32 with_this_prio;
|
||||
u32 i;
|
||||
int res = -EINVAL;
|
||||
|
||||
if (!tipc_own_addr) {
|
||||
pr_warn("Bearer <%s> rejected, not supported in standalone mode\n",
|
||||
name);
|
||||
return -ENOPROTOOPT;
|
||||
}
|
||||
if (!bearer_name_validate(name, &b_names)) {
|
||||
pr_warn("Bearer <%s> rejected, illegal name\n", name);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (tipc_addr_domain_valid(disc_domain) &&
|
||||
(disc_domain != tipc_own_addr)) {
|
||||
if (tipc_in_scope(disc_domain, tipc_own_addr)) {
|
||||
disc_domain = tipc_own_addr & TIPC_CLUSTER_MASK;
|
||||
res = 0; /* accept any node in own cluster */
|
||||
} else if (in_own_cluster_exact(disc_domain))
|
||||
res = 0; /* accept specified node in own cluster */
|
||||
}
|
||||
if (res) {
|
||||
pr_warn("Bearer <%s> rejected, illegal discovery domain\n",
|
||||
name);
|
||||
return -EINVAL;
|
||||
}
|
||||
if ((priority > TIPC_MAX_LINK_PRI) &&
|
||||
(priority != TIPC_MEDIA_LINK_PRI)) {
|
||||
pr_warn("Bearer <%s> rejected, illegal priority\n", name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
m_ptr = tipc_media_find(b_names.media_name);
|
||||
if (!m_ptr) {
|
||||
pr_warn("Bearer <%s> rejected, media <%s> not registered\n",
|
||||
name, b_names.media_name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
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; ) {
|
||||
b_ptr = rtnl_dereference(bearer_list[i]);
|
||||
if (!b_ptr) {
|
||||
bearer_id = i;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(name, b_ptr->name)) {
|
||||
pr_warn("Bearer <%s> rejected, already enabled\n",
|
||||
name);
|
||||
return -EINVAL;
|
||||
}
|
||||
if ((b_ptr->priority == priority) &&
|
||||
(++with_this_prio > 2)) {
|
||||
if (priority-- == 0) {
|
||||
pr_warn("Bearer <%s> rejected, duplicate priority\n",
|
||||
name);
|
||||
return -EINVAL;
|
||||
}
|
||||
pr_warn("Bearer <%s> priority adjustment required %u->%u\n",
|
||||
name, priority + 1, priority);
|
||||
goto restart;
|
||||
}
|
||||
}
|
||||
if (bearer_id >= MAX_BEARERS) {
|
||||
pr_warn("Bearer <%s> rejected, bearer limit reached (%u)\n",
|
||||
name, MAX_BEARERS);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
b_ptr = kzalloc(sizeof(*b_ptr), GFP_ATOMIC);
|
||||
if (!b_ptr)
|
||||
return -ENOMEM;
|
||||
|
||||
strcpy(b_ptr->name, name);
|
||||
b_ptr->media = m_ptr;
|
||||
res = m_ptr->enable_media(b_ptr);
|
||||
if (res) {
|
||||
pr_warn("Bearer <%s> rejected, enable failure (%d)\n",
|
||||
name, -res);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
b_ptr->identity = bearer_id;
|
||||
b_ptr->tolerance = m_ptr->tolerance;
|
||||
b_ptr->window = m_ptr->window;
|
||||
b_ptr->domain = disc_domain;
|
||||
b_ptr->net_plane = bearer_id + 'A';
|
||||
b_ptr->priority = priority;
|
||||
|
||||
res = tipc_disc_create(b_ptr, &b_ptr->bcast_addr);
|
||||
if (res) {
|
||||
bearer_disable(b_ptr, false);
|
||||
pr_warn("Bearer <%s> rejected, discovery object creation failed\n",
|
||||
name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rcu_assign_pointer(bearer_list[bearer_id], b_ptr);
|
||||
|
||||
pr_info("Enabled bearer <%s>, discovery domain %s, priority %u\n",
|
||||
name,
|
||||
tipc_addr_string_fill(addr_string, disc_domain), priority);
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* tipc_reset_bearer - Reset all links established over this bearer
|
||||
*/
|
||||
static int tipc_reset_bearer(struct tipc_bearer *b_ptr)
|
||||
{
|
||||
pr_info("Resetting bearer <%s>\n", b_ptr->name);
|
||||
tipc_link_reset_list(b_ptr->identity);
|
||||
tipc_disc_reset(b_ptr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* bearer_disable
|
||||
*
|
||||
* Note: This routine assumes caller holds RTNL lock.
|
||||
*/
|
||||
static void bearer_disable(struct tipc_bearer *b_ptr, bool shutting_down)
|
||||
{
|
||||
u32 i;
|
||||
|
||||
pr_info("Disabling bearer <%s>\n", b_ptr->name);
|
||||
b_ptr->media->disable_media(b_ptr);
|
||||
|
||||
tipc_link_delete_list(b_ptr->identity, shutting_down);
|
||||
if (b_ptr->link_req)
|
||||
tipc_disc_delete(b_ptr->link_req);
|
||||
|
||||
for (i = 0; i < MAX_BEARERS; i++) {
|
||||
if (b_ptr == rtnl_dereference(bearer_list[i])) {
|
||||
RCU_INIT_POINTER(bearer_list[i], NULL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
kfree_rcu(b_ptr, rcu);
|
||||
}
|
||||
|
||||
int tipc_disable_bearer(const char *name)
|
||||
{
|
||||
struct tipc_bearer *b_ptr;
|
||||
int res;
|
||||
|
||||
b_ptr = tipc_bearer_find(name);
|
||||
if (b_ptr == NULL) {
|
||||
pr_warn("Attempt to disable unknown bearer <%s>\n", name);
|
||||
res = -EINVAL;
|
||||
} else {
|
||||
bearer_disable(b_ptr, false);
|
||||
res = 0;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
int tipc_enable_l2_media(struct tipc_bearer *b)
|
||||
{
|
||||
struct net_device *dev;
|
||||
char *driver_name = strchr((const char *)b->name, ':') + 1;
|
||||
|
||||
/* Find device with specified name */
|
||||
dev = dev_get_by_name(&init_net, driver_name);
|
||||
if (!dev)
|
||||
return -ENODEV;
|
||||
|
||||
/* Associate TIPC bearer with L2 bearer */
|
||||
rcu_assign_pointer(b->media_ptr, dev);
|
||||
memset(&b->bcast_addr, 0, sizeof(b->bcast_addr));
|
||||
memcpy(b->bcast_addr.value, dev->broadcast, b->media->hwaddr_len);
|
||||
b->bcast_addr.media_id = b->media->type_id;
|
||||
b->bcast_addr.broadcast = 1;
|
||||
b->mtu = dev->mtu;
|
||||
b->media->raw2addr(b, &b->addr, (char *)dev->dev_addr);
|
||||
rcu_assign_pointer(dev->tipc_ptr, b);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* tipc_disable_l2_media - detach TIPC bearer from an L2 interface
|
||||
*
|
||||
* Mark L2 bearer as inactive so that incoming buffers are thrown away,
|
||||
* then get worker thread to complete bearer cleanup. (Can't do cleanup
|
||||
* here because cleanup code needs to sleep and caller holds spinlocks.)
|
||||
*/
|
||||
void tipc_disable_l2_media(struct tipc_bearer *b)
|
||||
{
|
||||
struct net_device *dev;
|
||||
|
||||
dev = (struct net_device *)rtnl_dereference(b->media_ptr);
|
||||
RCU_INIT_POINTER(b->media_ptr, NULL);
|
||||
RCU_INIT_POINTER(dev->tipc_ptr, NULL);
|
||||
synchronize_net();
|
||||
dev_put(dev);
|
||||
}
|
||||
|
||||
/**
|
||||
* tipc_l2_send_msg - send a TIPC packet out over an L2 interface
|
||||
* @buf: the packet to be sent
|
||||
* @b_ptr: the bearer through which the packet is to be sent
|
||||
* @dest: peer destination address
|
||||
*/
|
||||
int tipc_l2_send_msg(struct sk_buff *buf, struct tipc_bearer *b,
|
||||
struct tipc_media_addr *dest)
|
||||
{
|
||||
struct sk_buff *clone;
|
||||
struct net_device *dev;
|
||||
int delta;
|
||||
|
||||
dev = (struct net_device *)rcu_dereference_rtnl(b->media_ptr);
|
||||
if (!dev)
|
||||
return 0;
|
||||
|
||||
clone = skb_clone(buf, GFP_ATOMIC);
|
||||
if (!clone)
|
||||
return 0;
|
||||
|
||||
delta = dev->hard_header_len - skb_headroom(buf);
|
||||
if ((delta > 0) &&
|
||||
pskb_expand_head(clone, SKB_DATA_ALIGN(delta), 0, GFP_ATOMIC)) {
|
||||
kfree_skb(clone);
|
||||
return 0;
|
||||
}
|
||||
|
||||
skb_reset_network_header(clone);
|
||||
clone->dev = dev;
|
||||
clone->protocol = htons(ETH_P_TIPC);
|
||||
dev_hard_header(clone, dev, ETH_P_TIPC, dest->value,
|
||||
dev->dev_addr, clone->len);
|
||||
dev_queue_xmit(clone);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* tipc_bearer_send- sends buffer to destination over bearer
|
||||
*
|
||||
* IMPORTANT:
|
||||
* The media send routine must not alter the buffer being passed in
|
||||
* as it may be needed for later retransmission!
|
||||
*/
|
||||
void tipc_bearer_send(u32 bearer_id, struct sk_buff *buf,
|
||||
struct tipc_media_addr *dest)
|
||||
{
|
||||
struct tipc_bearer *b_ptr;
|
||||
|
||||
rcu_read_lock();
|
||||
b_ptr = rcu_dereference_rtnl(bearer_list[bearer_id]);
|
||||
if (likely(b_ptr))
|
||||
b_ptr->media->send_msg(buf, b_ptr, dest);
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
/**
|
||||
* tipc_l2_rcv_msg - handle incoming TIPC message from an interface
|
||||
* @buf: the received packet
|
||||
* @dev: the net device that the packet was received on
|
||||
* @pt: the packet_type structure which was used to register this handler
|
||||
* @orig_dev: the original receive net device in case the device is a bond
|
||||
*
|
||||
* Accept only packets explicitly sent to this node, or broadcast packets;
|
||||
* ignores packets sent using interface multicast, and traffic sent to other
|
||||
* nodes (which can happen if interface is running in promiscuous mode).
|
||||
*/
|
||||
static int tipc_l2_rcv_msg(struct sk_buff *buf, struct net_device *dev,
|
||||
struct packet_type *pt, struct net_device *orig_dev)
|
||||
{
|
||||
struct tipc_bearer *b_ptr;
|
||||
|
||||
if (!net_eq(dev_net(dev), &init_net)) {
|
||||
kfree_skb(buf);
|
||||
return NET_RX_DROP;
|
||||
}
|
||||
|
||||
rcu_read_lock();
|
||||
b_ptr = rcu_dereference_rtnl(dev->tipc_ptr);
|
||||
if (likely(b_ptr)) {
|
||||
if (likely(buf->pkt_type <= PACKET_BROADCAST)) {
|
||||
buf->next = NULL;
|
||||
tipc_rcv(buf, b_ptr);
|
||||
rcu_read_unlock();
|
||||
return NET_RX_SUCCESS;
|
||||
}
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
kfree_skb(buf);
|
||||
return NET_RX_DROP;
|
||||
}
|
||||
|
||||
/**
|
||||
* tipc_l2_device_event - handle device events from network device
|
||||
* @nb: the context of the notification
|
||||
* @evt: the type of event
|
||||
* @ptr: the net device that the event was on
|
||||
*
|
||||
* This function is called by the Ethernet driver in case of link
|
||||
* change event.
|
||||
*/
|
||||
static int tipc_l2_device_event(struct notifier_block *nb, unsigned long evt,
|
||||
void *ptr)
|
||||
{
|
||||
struct tipc_bearer *b_ptr;
|
||||
struct net_device *dev = netdev_notifier_info_to_dev(ptr);
|
||||
|
||||
if (!net_eq(dev_net(dev), &init_net))
|
||||
return NOTIFY_DONE;
|
||||
|
||||
b_ptr = rtnl_dereference(dev->tipc_ptr);
|
||||
if (!b_ptr)
|
||||
return NOTIFY_DONE;
|
||||
|
||||
b_ptr->mtu = dev->mtu;
|
||||
|
||||
switch (evt) {
|
||||
case NETDEV_CHANGE:
|
||||
if (netif_carrier_ok(dev))
|
||||
break;
|
||||
case NETDEV_DOWN:
|
||||
case NETDEV_CHANGEMTU:
|
||||
tipc_reset_bearer(b_ptr);
|
||||
break;
|
||||
case NETDEV_CHANGEADDR:
|
||||
b_ptr->media->raw2addr(b_ptr, &b_ptr->addr,
|
||||
(char *)dev->dev_addr);
|
||||
tipc_reset_bearer(b_ptr);
|
||||
break;
|
||||
case NETDEV_UNREGISTER:
|
||||
case NETDEV_CHANGENAME:
|
||||
bearer_disable(b_ptr, false);
|
||||
break;
|
||||
}
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
static struct packet_type tipc_packet_type __read_mostly = {
|
||||
.type = htons(ETH_P_TIPC),
|
||||
.func = tipc_l2_rcv_msg,
|
||||
};
|
||||
|
||||
static struct notifier_block notifier = {
|
||||
.notifier_call = tipc_l2_device_event,
|
||||
.priority = 0,
|
||||
};
|
||||
|
||||
int tipc_bearer_setup(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = register_netdevice_notifier(¬ifier);
|
||||
if (err)
|
||||
return err;
|
||||
dev_add_pack(&tipc_packet_type);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void tipc_bearer_cleanup(void)
|
||||
{
|
||||
unregister_netdevice_notifier(¬ifier);
|
||||
dev_remove_pack(&tipc_packet_type);
|
||||
}
|
||||
|
||||
void tipc_bearer_stop(void)
|
||||
{
|
||||
struct tipc_bearer *b_ptr;
|
||||
u32 i;
|
||||
|
||||
for (i = 0; i < MAX_BEARERS; i++) {
|
||||
b_ptr = rtnl_dereference(bearer_list[i]);
|
||||
if (b_ptr) {
|
||||
bearer_disable(b_ptr, true);
|
||||
bearer_list[i] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
199
net/tipc/bearer.h
Normal file
199
net/tipc/bearer.h
Normal file
|
@ -0,0 +1,199 @@
|
|||
/*
|
||||
* net/tipc/bearer.h: Include file for TIPC bearer code
|
||||
*
|
||||
* Copyright (c) 1996-2006, 2013, Ericsson AB
|
||||
* Copyright (c) 2005, 2010-2011, 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 "bcast.h"
|
||||
|
||||
#define MAX_BEARERS 2
|
||||
#define MAX_MEDIA 2
|
||||
|
||||
/* Identifiers associated with TIPC message header media address info
|
||||
* - address info field is 32 bytes long
|
||||
* - the field's actual content and length is defined per media
|
||||
* - remaining unused bytes in the field are set to zero
|
||||
*/
|
||||
#define TIPC_MEDIA_ADDR_SIZE 32
|
||||
#define TIPC_MEDIA_TYPE_OFFSET 3
|
||||
|
||||
/*
|
||||
* Identifiers of supported TIPC media types
|
||||
*/
|
||||
#define TIPC_MEDIA_TYPE_ETH 1
|
||||
#define TIPC_MEDIA_TYPE_IB 2
|
||||
|
||||
/**
|
||||
* struct tipc_media_addr - destination address used by TIPC bearers
|
||||
* @value: address info (format defined by media)
|
||||
* @media_id: TIPC media type identifier
|
||||
* @broadcast: non-zero if address is a broadcast address
|
||||
*/
|
||||
struct tipc_media_addr {
|
||||
u8 value[TIPC_MEDIA_ADDR_SIZE];
|
||||
u8 media_id;
|
||||
u8 broadcast;
|
||||
};
|
||||
|
||||
struct tipc_bearer;
|
||||
|
||||
/**
|
||||
* struct tipc_media - Media specific info exposed to generic bearer layer
|
||||
* @send_msg: routine which handles buffer transmission
|
||||
* @enable_media: routine which enables a media
|
||||
* @disable_media: routine which disables a media
|
||||
* @addr2str: convert media address format to string
|
||||
* @addr2msg: convert from media addr format to discovery msg addr format
|
||||
* @msg2addr: convert from discovery msg addr format to media addr format
|
||||
* @raw2addr: convert from raw addr format to media addr format
|
||||
* @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
|
||||
* @hwaddr_len: TIPC media address len
|
||||
* @name: media name
|
||||
*/
|
||||
struct tipc_media {
|
||||
int (*send_msg)(struct sk_buff *buf,
|
||||
struct tipc_bearer *b_ptr,
|
||||
struct tipc_media_addr *dest);
|
||||
int (*enable_media)(struct tipc_bearer *b_ptr);
|
||||
void (*disable_media)(struct tipc_bearer *b_ptr);
|
||||
int (*addr2str)(struct tipc_media_addr *addr,
|
||||
char *strbuf,
|
||||
int bufsz);
|
||||
int (*addr2msg)(char *msg, struct tipc_media_addr *addr);
|
||||
int (*msg2addr)(struct tipc_bearer *b,
|
||||
struct tipc_media_addr *addr,
|
||||
char *msg);
|
||||
int (*raw2addr)(struct tipc_bearer *b,
|
||||
struct tipc_media_addr *addr,
|
||||
char *raw);
|
||||
u32 priority;
|
||||
u32 tolerance;
|
||||
u32 window;
|
||||
u32 type_id;
|
||||
u32 hwaddr_len;
|
||||
char name[TIPC_MAX_MEDIA_NAME];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct tipc_bearer - Generic TIPC bearer structure
|
||||
* @media_ptr: pointer to additional media-specific information about bearer
|
||||
* @mtu: max packet size bearer can support
|
||||
* @addr: media-specific address associated with bearer
|
||||
* @name: bearer name (format = media:interface)
|
||||
* @media: ptr to media structure associated with bearer
|
||||
* @bcast_addr: media address used in broadcasting
|
||||
* @rcu: rcu struct for tipc_bearer
|
||||
* @priority: default link priority for bearer
|
||||
* @window: default window size for bearer
|
||||
* @tolerance: default link tolerance for bearer
|
||||
* @domain: network domain to which links can be established
|
||||
* @identity: array index of this bearer within TIPC bearer array
|
||||
* @link_req: ptr to (optional) structure making periodic link setup requests
|
||||
* @net_plane: network plane ('A' through 'H') currently associated with bearer
|
||||
* @nodes: indicates which nodes in cluster can be reached through bearer
|
||||
*
|
||||
* Note: media-specific code is responsible for initialization of the fields
|
||||
* indicated below when a bearer is enabled; TIPC's generic bearer code takes
|
||||
* care of initializing all other fields.
|
||||
*/
|
||||
struct tipc_bearer {
|
||||
void __rcu *media_ptr; /* initalized by media */
|
||||
u32 mtu; /* initalized by media */
|
||||
struct tipc_media_addr addr; /* initalized by media */
|
||||
char name[TIPC_MAX_BEARER_NAME];
|
||||
struct tipc_media *media;
|
||||
struct tipc_media_addr bcast_addr;
|
||||
struct rcu_head rcu;
|
||||
u32 priority;
|
||||
u32 window;
|
||||
u32 tolerance;
|
||||
u32 domain;
|
||||
u32 identity;
|
||||
struct tipc_link_req *link_req;
|
||||
char net_plane;
|
||||
struct tipc_node_map nodes;
|
||||
};
|
||||
|
||||
struct tipc_bearer_names {
|
||||
char media_name[TIPC_MAX_MEDIA_NAME];
|
||||
char if_name[TIPC_MAX_IF_NAME];
|
||||
};
|
||||
|
||||
struct tipc_link;
|
||||
|
||||
extern struct tipc_bearer __rcu *bearer_list[];
|
||||
|
||||
/*
|
||||
* TIPC routines available to supported media types
|
||||
*/
|
||||
|
||||
void tipc_rcv(struct sk_buff *buf, struct tipc_bearer *tb_ptr);
|
||||
int tipc_enable_bearer(const char *bearer_name, u32 disc_domain, u32 priority);
|
||||
int tipc_disable_bearer(const char *name);
|
||||
|
||||
/*
|
||||
* Routines made available to TIPC by supported media types
|
||||
*/
|
||||
extern struct tipc_media eth_media_info;
|
||||
|
||||
#ifdef CONFIG_TIPC_MEDIA_IB
|
||||
extern struct tipc_media ib_media_info;
|
||||
#endif
|
||||
|
||||
int tipc_media_set_priority(const char *name, u32 new_value);
|
||||
int tipc_media_set_window(const char *name, u32 new_value);
|
||||
void tipc_media_addr_printf(char *buf, int len, struct tipc_media_addr *a);
|
||||
struct sk_buff *tipc_media_get_names(void);
|
||||
int tipc_enable_l2_media(struct tipc_bearer *b);
|
||||
void tipc_disable_l2_media(struct tipc_bearer *b);
|
||||
int tipc_l2_send_msg(struct sk_buff *buf, struct tipc_bearer *b,
|
||||
struct tipc_media_addr *dest);
|
||||
|
||||
struct sk_buff *tipc_bearer_get_names(void);
|
||||
void tipc_bearer_add_dest(u32 bearer_id, u32 dest);
|
||||
void tipc_bearer_remove_dest(u32 bearer_id, u32 dest);
|
||||
struct tipc_bearer *tipc_bearer_find(const char *name);
|
||||
struct tipc_media *tipc_media_find(const char *name);
|
||||
int tipc_bearer_setup(void);
|
||||
void tipc_bearer_cleanup(void);
|
||||
void tipc_bearer_stop(void);
|
||||
void tipc_bearer_send(u32 bearer_id, struct sk_buff *buf,
|
||||
struct tipc_media_addr *dest);
|
||||
|
||||
#endif /* _TIPC_BEARER_H */
|
342
net/tipc/config.c
Normal file
342
net/tipc/config.c
Normal file
|
@ -0,0 +1,342 @@
|
|||
/*
|
||||
* net/tipc/config.c: TIPC configuration management code
|
||||
*
|
||||
* Copyright (c) 2002-2006, Ericsson AB
|
||||
* Copyright (c) 2004-2007, 2010-2013, 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 "socket.h"
|
||||
#include "name_table.h"
|
||||
#include "config.h"
|
||||
#include "server.h"
|
||||
|
||||
#define REPLY_TRUNCATED "<truncated>\n"
|
||||
|
||||
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 */
|
||||
|
||||
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)
|
||||
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;
|
||||
}
|
||||
|
||||
static 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;
|
||||
}
|
||||
|
||||
static struct sk_buff *tipc_cfg_reply_unsigned(u32 value)
|
||||
{
|
||||
return tipc_cfg_reply_unsigned_type(TIPC_TLV_UNSIGNED, value);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static struct sk_buff *tipc_show_stats(void)
|
||||
{
|
||||
struct sk_buff *buf;
|
||||
struct tlv_desc *rep_tlv;
|
||||
char *pb;
|
||||
int pb_len;
|
||||
int str_len;
|
||||
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(*(u32 *)TLV_DATA(req_tlv_area));
|
||||
if (value != 0)
|
||||
return tipc_cfg_reply_error_string("unsupported argument");
|
||||
|
||||
buf = tipc_cfg_reply_alloc(TLV_SPACE(ULTRA_STRING_MAX_LEN));
|
||||
if (buf == NULL)
|
||||
return NULL;
|
||||
|
||||
rep_tlv = (struct tlv_desc *)buf->data;
|
||||
pb = TLV_DATA(rep_tlv);
|
||||
pb_len = ULTRA_STRING_MAX_LEN;
|
||||
|
||||
str_len = tipc_snprintf(pb, pb_len, "TIPC version " TIPC_MOD_VER "\n");
|
||||
str_len += 1; /* for "\0" */
|
||||
skb_put(buf, TLV_SPACE(str_len));
|
||||
TLV_SET(rep_tlv, TIPC_TLV_ULTRA_STRING, NULL, str_len);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
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->disc_domain),
|
||||
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_own_addr)
|
||||
return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
|
||||
" (cannot change node address once assigned)");
|
||||
if (!tipc_net_start(addr))
|
||||
return tipc_cfg_reply_none();
|
||||
|
||||
return tipc_cfg_reply_error_string("cannot change to network mode");
|
||||
}
|
||||
|
||||
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 < 127 || value > 65535)
|
||||
return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
|
||||
" (max ports must be 127-65535)");
|
||||
return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
|
||||
" (cannot change max ports while TIPC is active)");
|
||||
}
|
||||
|
||||
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 < 1 || value > 9999)
|
||||
return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
|
||||
" (network id must be 1-9999)");
|
||||
if (tipc_own_addr)
|
||||
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;
|
||||
|
||||
rtnl_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(in_own_node(orig_node))) {
|
||||
/* command is permitted */
|
||||
} else {
|
||||
rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
|
||||
" (cannot be done remotely)");
|
||||
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_sk_socks_show();
|
||||
break;
|
||||
case TIPC_CMD_SHOW_STATS:
|
||||
rep_tlv_buf = tipc_show_stats();
|
||||
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_MAX_PORTS:
|
||||
rep_tlv_buf = cfg_set_max_ports();
|
||||
break;
|
||||
case TIPC_CMD_SET_NETID:
|
||||
rep_tlv_buf = cfg_set_netid();
|
||||
break;
|
||||
case TIPC_CMD_GET_MAX_PORTS:
|
||||
rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_max_ports);
|
||||
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;
|
||||
case TIPC_CMD_SET_MAX_ZONES:
|
||||
case TIPC_CMD_GET_MAX_ZONES:
|
||||
case TIPC_CMD_SET_MAX_SLAVES:
|
||||
case TIPC_CMD_GET_MAX_SLAVES:
|
||||
case TIPC_CMD_SET_MAX_CLUSTERS:
|
||||
case TIPC_CMD_GET_MAX_CLUSTERS:
|
||||
case TIPC_CMD_SET_MAX_NODES:
|
||||
case TIPC_CMD_GET_MAX_NODES:
|
||||
case TIPC_CMD_SET_MAX_SUBSCR:
|
||||
case TIPC_CMD_GET_MAX_SUBSCR:
|
||||
case TIPC_CMD_SET_MAX_PUBL:
|
||||
case TIPC_CMD_GET_MAX_PUBL:
|
||||
case TIPC_CMD_SET_LOG_SIZE:
|
||||
case TIPC_CMD_SET_REMOTE_MNG:
|
||||
case TIPC_CMD_GET_REMOTE_MNG:
|
||||
case TIPC_CMD_DUMP_LOG:
|
||||
rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
|
||||
" (obsolete command)");
|
||||
break;
|
||||
default:
|
||||
rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
|
||||
" (unknown command)");
|
||||
break;
|
||||
}
|
||||
|
||||
WARN_ON(rep_tlv_buf->len > TLV_SPACE(ULTRA_STRING_MAX_LEN));
|
||||
|
||||
/* Append an error message if we cannot return all requested data */
|
||||
if (rep_tlv_buf->len == TLV_SPACE(ULTRA_STRING_MAX_LEN)) {
|
||||
if (*(rep_tlv_buf->data + ULTRA_STRING_MAX_LEN) != '\0')
|
||||
sprintf(rep_tlv_buf->data + rep_tlv_buf->len -
|
||||
sizeof(REPLY_TRUNCATED) - 1, REPLY_TRUNCATED);
|
||||
}
|
||||
|
||||
/* Return reply buffer */
|
||||
exit:
|
||||
rtnl_unlock();
|
||||
return rep_tlv_buf;
|
||||
}
|
67
net/tipc/config.h
Normal file
67
net/tipc/config.h
Normal file
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* 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 "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_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_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);
|
||||
#endif
|
181
net/tipc/core.c
Normal file
181
net/tipc/core.c
Normal file
|
@ -0,0 +1,181 @@
|
|||
/*
|
||||
* net/tipc/core.c: TIPC module code
|
||||
*
|
||||
* Copyright (c) 2003-2006, 2013, Ericsson AB
|
||||
* Copyright (c) 2005-2006, 2010-2013, 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 "name_table.h"
|
||||
#include "subscr.h"
|
||||
#include "config.h"
|
||||
#include "socket.h"
|
||||
|
||||
#include <linux/module.h>
|
||||
|
||||
/* global variables used by multiple sub-systems within TIPC */
|
||||
int tipc_random __read_mostly;
|
||||
|
||||
/* configurable TIPC parameters */
|
||||
u32 tipc_own_addr __read_mostly;
|
||||
int tipc_max_ports __read_mostly;
|
||||
int tipc_net_id __read_mostly;
|
||||
int sysctl_tipc_rmem[3] __read_mostly; /* min/default/max */
|
||||
|
||||
/**
|
||||
* tipc_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.
|
||||
*/
|
||||
struct sk_buff *tipc_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;
|
||||
}
|
||||
|
||||
/**
|
||||
* tipc_core_stop - switch TIPC from SINGLE NODE to NOT RUNNING mode
|
||||
*/
|
||||
static void tipc_core_stop(void)
|
||||
{
|
||||
tipc_net_stop();
|
||||
tipc_bearer_cleanup();
|
||||
tipc_netlink_stop();
|
||||
tipc_subscr_stop();
|
||||
tipc_nametbl_stop();
|
||||
tipc_sk_ref_table_stop();
|
||||
tipc_socket_stop();
|
||||
tipc_unregister_sysctl();
|
||||
}
|
||||
|
||||
/**
|
||||
* tipc_core_start - switch TIPC from NOT RUNNING to SINGLE NODE mode
|
||||
*/
|
||||
static int tipc_core_start(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
get_random_bytes(&tipc_random, sizeof(tipc_random));
|
||||
|
||||
err = tipc_sk_ref_table_init(tipc_max_ports, tipc_random);
|
||||
if (err)
|
||||
goto out_reftbl;
|
||||
|
||||
err = tipc_nametbl_init();
|
||||
if (err)
|
||||
goto out_nametbl;
|
||||
|
||||
err = tipc_netlink_start();
|
||||
if (err)
|
||||
goto out_netlink;
|
||||
|
||||
err = tipc_socket_init();
|
||||
if (err)
|
||||
goto out_socket;
|
||||
|
||||
err = tipc_register_sysctl();
|
||||
if (err)
|
||||
goto out_sysctl;
|
||||
|
||||
err = tipc_subscr_start();
|
||||
if (err)
|
||||
goto out_subscr;
|
||||
|
||||
err = tipc_bearer_setup();
|
||||
if (err)
|
||||
goto out_bearer;
|
||||
|
||||
return 0;
|
||||
out_bearer:
|
||||
tipc_subscr_stop();
|
||||
out_subscr:
|
||||
tipc_unregister_sysctl();
|
||||
out_sysctl:
|
||||
tipc_socket_stop();
|
||||
out_socket:
|
||||
tipc_netlink_stop();
|
||||
out_netlink:
|
||||
tipc_nametbl_stop();
|
||||
out_nametbl:
|
||||
tipc_sk_ref_table_stop();
|
||||
out_reftbl:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int __init tipc_init(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
pr_info("Activated (version " TIPC_MOD_VER ")\n");
|
||||
|
||||
tipc_own_addr = 0;
|
||||
tipc_max_ports = CONFIG_TIPC_PORTS;
|
||||
tipc_net_id = 4711;
|
||||
|
||||
sysctl_tipc_rmem[0] = TIPC_CONN_OVERLOAD_LIMIT >> 4 <<
|
||||
TIPC_LOW_IMPORTANCE;
|
||||
sysctl_tipc_rmem[1] = TIPC_CONN_OVERLOAD_LIMIT >> 4 <<
|
||||
TIPC_CRITICAL_IMPORTANCE;
|
||||
sysctl_tipc_rmem[2] = TIPC_CONN_OVERLOAD_LIMIT;
|
||||
|
||||
res = tipc_core_start();
|
||||
if (res)
|
||||
pr_err("Unable to start in single node mode\n");
|
||||
else
|
||||
pr_info("Started in single node mode\n");
|
||||
return res;
|
||||
}
|
||||
|
||||
static void __exit tipc_exit(void)
|
||||
{
|
||||
tipc_core_stop();
|
||||
pr_info("Deactivated\n");
|
||||
}
|
||||
|
||||
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);
|
207
net/tipc/core.h
Normal file
207
net/tipc/core.h
Normal file
|
@ -0,0 +1,207 @@
|
|||
/*
|
||||
* net/tipc/core.h: Include file for TIPC global declarations
|
||||
*
|
||||
* Copyright (c) 2005-2006, 2013 Ericsson AB
|
||||
* Copyright (c) 2005-2007, 2010-2013, 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
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/tipc.h>
|
||||
#include <linux/tipc_config.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 <linux/uaccess.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/atomic.h>
|
||||
#include <asm/hardirq.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/in.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <linux/etherdevice.h>
|
||||
|
||||
#define TIPC_MOD_VER "2.0.0"
|
||||
|
||||
#define ULTRA_STRING_MAX_LEN 32768
|
||||
#define TIPC_MAX_SUBSCRIPTIONS 65535
|
||||
#define TIPC_MAX_PUBLICATIONS 65535
|
||||
|
||||
struct tipc_msg; /* msg.h */
|
||||
|
||||
int tipc_snprintf(char *buf, int len, const char *fmt, ...);
|
||||
|
||||
/*
|
||||
* TIPC-specific error codes
|
||||
*/
|
||||
#define ELINKCONG EAGAIN /* link congestion <=> resource unavailable */
|
||||
|
||||
/*
|
||||
* Global configuration variables
|
||||
*/
|
||||
extern u32 tipc_own_addr __read_mostly;
|
||||
extern int tipc_max_ports __read_mostly;
|
||||
extern int tipc_net_id __read_mostly;
|
||||
extern int sysctl_tipc_rmem[3] __read_mostly;
|
||||
extern int sysctl_tipc_named_timeout __read_mostly;
|
||||
|
||||
/*
|
||||
* Other global variables
|
||||
*/
|
||||
extern int tipc_random __read_mostly;
|
||||
|
||||
/*
|
||||
* Routines available to privileged subsystems
|
||||
*/
|
||||
int tipc_netlink_start(void);
|
||||
void tipc_netlink_stop(void);
|
||||
int tipc_socket_init(void);
|
||||
void tipc_socket_stop(void);
|
||||
int tipc_sock_create_local(int type, struct socket **res);
|
||||
void tipc_sock_release_local(struct socket *sock);
|
||||
int tipc_sock_accept_local(struct socket *sock, struct socket **newsock,
|
||||
int flags);
|
||||
|
||||
#ifdef CONFIG_SYSCTL
|
||||
int tipc_register_sysctl(void);
|
||||
void tipc_unregister_sysctl(void);
|
||||
#else
|
||||
#define tipc_register_sysctl() 0
|
||||
#define tipc_unregister_sysctl()
|
||||
#endif
|
||||
|
||||
/*
|
||||
* TIPC timer code
|
||||
*/
|
||||
typedef void (*Handler) (unsigned long);
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* 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;
|
||||
struct sk_buff *tail;
|
||||
bool deferred;
|
||||
bool wakeup_pending;
|
||||
u16 chain_sz;
|
||||
u16 chain_imp;
|
||||
};
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
struct sk_buff *tipc_buf_acquire(u32 size);
|
||||
|
||||
#endif
|
403
net/tipc/discover.c
Normal file
403
net/tipc/discover.c
Normal file
|
@ -0,0 +1,403 @@
|
|||
/*
|
||||
* net/tipc/discover.c
|
||||
*
|
||||
* Copyright (c) 2003-2006, 2014, Ericsson AB
|
||||
* Copyright (c) 2005-2006, 2010-2011, 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 "link.h"
|
||||
#include "discover.h"
|
||||
|
||||
#define TIPC_LINK_REQ_INIT 125 /* min delay during bearer start up */
|
||||
#define TIPC_LINK_REQ_FAST 1000 /* max delay if bearer has no links */
|
||||
#define TIPC_LINK_REQ_SLOW 60000 /* max delay if bearer has links */
|
||||
#define TIPC_LINK_REQ_INACTIVE 0xffffffff /* indicates no timer in use */
|
||||
|
||||
|
||||
/**
|
||||
* struct tipc_link_req - information about an ongoing link setup request
|
||||
* @bearer_id: identity of bearer issuing requests
|
||||
* @dest: destination address for request messages
|
||||
* @domain: network domain to which links can be established
|
||||
* @num_nodes: number of nodes currently discovered (i.e. with an active link)
|
||||
* @lock: spinlock for controlling access to requests
|
||||
* @buf: request message to be (repeatedly) sent
|
||||
* @timer: timer governing period between requests
|
||||
* @timer_intv: current interval between requests (in ms)
|
||||
*/
|
||||
struct tipc_link_req {
|
||||
u32 bearer_id;
|
||||
struct tipc_media_addr dest;
|
||||
u32 domain;
|
||||
int num_nodes;
|
||||
spinlock_t lock;
|
||||
struct sk_buff *buf;
|
||||
struct timer_list timer;
|
||||
unsigned int timer_intv;
|
||||
};
|
||||
|
||||
/**
|
||||
* tipc_disc_init_msg - initialize a link setup message
|
||||
* @type: message type (request or response)
|
||||
* @b_ptr: ptr to bearer issuing message
|
||||
*/
|
||||
static void tipc_disc_init_msg(struct sk_buff *buf, u32 type,
|
||||
struct tipc_bearer *b_ptr)
|
||||
{
|
||||
struct tipc_msg *msg;
|
||||
u32 dest_domain = b_ptr->domain;
|
||||
|
||||
msg = buf_msg(buf);
|
||||
tipc_msg_init(msg, LINK_CONFIG, type, INT_H_SIZE, dest_domain);
|
||||
msg_set_non_seq(msg, 1);
|
||||
msg_set_node_sig(msg, tipc_random);
|
||||
msg_set_dest_domain(msg, dest_domain);
|
||||
msg_set_bc_netid(msg, tipc_net_id);
|
||||
b_ptr->media->addr2msg(msg_media_addr(msg), &b_ptr->addr);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 tipc_bearer *b_ptr, u32 node_addr,
|
||||
struct tipc_media_addr *media_addr)
|
||||
{
|
||||
char node_addr_str[16];
|
||||
char media_addr_str[64];
|
||||
|
||||
tipc_addr_string_fill(node_addr_str, node_addr);
|
||||
tipc_media_addr_printf(media_addr_str, sizeof(media_addr_str),
|
||||
media_addr);
|
||||
pr_warn("Duplicate %s using %s seen on <%s>\n", node_addr_str,
|
||||
media_addr_str, b_ptr->name);
|
||||
}
|
||||
|
||||
/**
|
||||
* tipc_disc_rcv - handle incoming discovery message (request or response)
|
||||
* @buf: buffer containing message
|
||||
* @bearer: bearer that message arrived on
|
||||
*/
|
||||
void tipc_disc_rcv(struct sk_buff *buf, struct tipc_bearer *bearer)
|
||||
{
|
||||
struct tipc_node *node;
|
||||
struct tipc_link *link;
|
||||
struct tipc_media_addr maddr;
|
||||
struct sk_buff *rbuf;
|
||||
struct tipc_msg *msg = buf_msg(buf);
|
||||
u32 ddom = msg_dest_domain(msg);
|
||||
u32 onode = msg_prevnode(msg);
|
||||
u32 net_id = msg_bc_netid(msg);
|
||||
u32 mtyp = msg_type(msg);
|
||||
u32 signature = msg_node_sig(msg);
|
||||
bool addr_match = false;
|
||||
bool sign_match = false;
|
||||
bool link_up = false;
|
||||
bool accept_addr = false;
|
||||
bool accept_sign = false;
|
||||
bool respond = false;
|
||||
|
||||
bearer->media->msg2addr(bearer, &maddr, msg_media_addr(msg));
|
||||
kfree_skb(buf);
|
||||
|
||||
/* Ensure message from node is valid and communication is permitted */
|
||||
if (net_id != tipc_net_id)
|
||||
return;
|
||||
if (maddr.broadcast)
|
||||
return;
|
||||
if (!tipc_addr_domain_valid(ddom))
|
||||
return;
|
||||
if (!tipc_addr_node_valid(onode))
|
||||
return;
|
||||
|
||||
if (in_own_node(onode)) {
|
||||
if (memcmp(&maddr, &bearer->addr, sizeof(maddr)))
|
||||
disc_dupl_alert(bearer, tipc_own_addr, &maddr);
|
||||
return;
|
||||
}
|
||||
if (!tipc_in_scope(ddom, tipc_own_addr))
|
||||
return;
|
||||
if (!tipc_in_scope(bearer->domain, onode))
|
||||
return;
|
||||
|
||||
/* Locate, or if necessary, create, node: */
|
||||
node = tipc_node_find(onode);
|
||||
if (!node)
|
||||
node = tipc_node_create(onode);
|
||||
if (!node)
|
||||
return;
|
||||
|
||||
tipc_node_lock(node);
|
||||
link = node->links[bearer->identity];
|
||||
|
||||
/* Prepare to validate requesting node's signature and media address */
|
||||
sign_match = (signature == node->signature);
|
||||
addr_match = link && !memcmp(&link->media_addr, &maddr, sizeof(maddr));
|
||||
link_up = link && tipc_link_is_up(link);
|
||||
|
||||
|
||||
/* These three flags give us eight permutations: */
|
||||
|
||||
if (sign_match && addr_match && link_up) {
|
||||
/* All is fine. Do nothing. */
|
||||
} else if (sign_match && addr_match && !link_up) {
|
||||
/* Respond. The link will come up in due time */
|
||||
respond = true;
|
||||
} else if (sign_match && !addr_match && link_up) {
|
||||
/* Peer has changed i/f address without rebooting.
|
||||
* If so, the link will reset soon, and the next
|
||||
* discovery will be accepted. So we can ignore it.
|
||||
* It may also be an cloned or malicious peer having
|
||||
* chosen the same node address and signature as an
|
||||
* existing one.
|
||||
* Ignore requests until the link goes down, if ever.
|
||||
*/
|
||||
disc_dupl_alert(bearer, onode, &maddr);
|
||||
} else if (sign_match && !addr_match && !link_up) {
|
||||
/* Peer link has changed i/f address without rebooting.
|
||||
* It may also be a cloned or malicious peer; we can't
|
||||
* distinguish between the two.
|
||||
* The signature is correct, so we must accept.
|
||||
*/
|
||||
accept_addr = true;
|
||||
respond = true;
|
||||
} else if (!sign_match && addr_match && link_up) {
|
||||
/* Peer node rebooted. Two possibilities:
|
||||
* - Delayed re-discovery; this link endpoint has already
|
||||
* reset and re-established contact with the peer, before
|
||||
* receiving a discovery message from that node.
|
||||
* (The peer happened to receive one from this node first).
|
||||
* - The peer came back so fast that our side has not
|
||||
* discovered it yet. Probing from this side will soon
|
||||
* reset the link, since there can be no working link
|
||||
* endpoint at the peer end, and the link will re-establish.
|
||||
* Accept the signature, since it comes from a known peer.
|
||||
*/
|
||||
accept_sign = true;
|
||||
} else if (!sign_match && addr_match && !link_up) {
|
||||
/* The peer node has rebooted.
|
||||
* Accept signature, since it is a known peer.
|
||||
*/
|
||||
accept_sign = true;
|
||||
respond = true;
|
||||
} else if (!sign_match && !addr_match && link_up) {
|
||||
/* Peer rebooted with new address, or a new/duplicate peer.
|
||||
* Ignore until the link goes down, if ever.
|
||||
*/
|
||||
disc_dupl_alert(bearer, onode, &maddr);
|
||||
} else if (!sign_match && !addr_match && !link_up) {
|
||||
/* Peer rebooted with new address, or it is a new peer.
|
||||
* Accept signature and address.
|
||||
*/
|
||||
accept_sign = true;
|
||||
accept_addr = true;
|
||||
respond = true;
|
||||
}
|
||||
|
||||
if (accept_sign)
|
||||
node->signature = signature;
|
||||
|
||||
if (accept_addr) {
|
||||
if (!link)
|
||||
link = tipc_link_create(node, bearer, &maddr);
|
||||
if (link) {
|
||||
memcpy(&link->media_addr, &maddr, sizeof(maddr));
|
||||
tipc_link_reset(link);
|
||||
} else {
|
||||
respond = false;
|
||||
}
|
||||
}
|
||||
|
||||
/* Send response, if necessary */
|
||||
if (respond && (mtyp == DSC_REQ_MSG)) {
|
||||
rbuf = tipc_buf_acquire(INT_H_SIZE);
|
||||
if (rbuf) {
|
||||
tipc_disc_init_msg(rbuf, DSC_RESP_MSG, bearer);
|
||||
tipc_bearer_send(bearer->identity, rbuf, &maddr);
|
||||
kfree_skb(rbuf);
|
||||
}
|
||||
}
|
||||
tipc_node_unlock(node);
|
||||
}
|
||||
|
||||
/**
|
||||
* disc_update - update frequency of periodic link setup requests
|
||||
* @req: ptr to link request structure
|
||||
*
|
||||
* Reinitiates discovery process if discovery object has no associated nodes
|
||||
* and is either not currently searching or is searching at a slow rate
|
||||
*/
|
||||
static void disc_update(struct tipc_link_req *req)
|
||||
{
|
||||
if (!req->num_nodes) {
|
||||
if ((req->timer_intv == TIPC_LINK_REQ_INACTIVE) ||
|
||||
(req->timer_intv > TIPC_LINK_REQ_FAST)) {
|
||||
req->timer_intv = TIPC_LINK_REQ_INIT;
|
||||
k_start_timer(&req->timer, req->timer_intv);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* tipc_disc_add_dest - increment set of discovered nodes
|
||||
* @req: ptr to link request structure
|
||||
*/
|
||||
void tipc_disc_add_dest(struct tipc_link_req *req)
|
||||
{
|
||||
spin_lock_bh(&req->lock);
|
||||
req->num_nodes++;
|
||||
spin_unlock_bh(&req->lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* tipc_disc_remove_dest - decrement set of discovered nodes
|
||||
* @req: ptr to link request structure
|
||||
*/
|
||||
void tipc_disc_remove_dest(struct tipc_link_req *req)
|
||||
{
|
||||
spin_lock_bh(&req->lock);
|
||||
req->num_nodes--;
|
||||
disc_update(req);
|
||||
spin_unlock_bh(&req->lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 tipc_link_req *req)
|
||||
{
|
||||
int max_delay;
|
||||
|
||||
spin_lock_bh(&req->lock);
|
||||
|
||||
/* Stop searching if only desired node has been found */
|
||||
if (tipc_node(req->domain) && req->num_nodes) {
|
||||
req->timer_intv = TIPC_LINK_REQ_INACTIVE;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/*
|
||||
* Send discovery message, then update discovery timer
|
||||
*
|
||||
* Keep doubling time between requests until limit is reached;
|
||||
* hold at fast polling rate if don't have any associated nodes,
|
||||
* otherwise hold at slow polling rate
|
||||
*/
|
||||
tipc_bearer_send(req->bearer_id, req->buf, &req->dest);
|
||||
|
||||
|
||||
req->timer_intv *= 2;
|
||||
if (req->num_nodes)
|
||||
max_delay = TIPC_LINK_REQ_SLOW;
|
||||
else
|
||||
max_delay = TIPC_LINK_REQ_FAST;
|
||||
if (req->timer_intv > max_delay)
|
||||
req->timer_intv = max_delay;
|
||||
|
||||
k_start_timer(&req->timer, req->timer_intv);
|
||||
exit:
|
||||
spin_unlock_bh(&req->lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* tipc_disc_create - create object to send periodic link setup requests
|
||||
* @b_ptr: ptr to bearer issuing requests
|
||||
* @dest: destination address for request messages
|
||||
* @dest_domain: network domain to which links can be established
|
||||
*
|
||||
* Returns 0 if successful, otherwise -errno.
|
||||
*/
|
||||
int tipc_disc_create(struct tipc_bearer *b_ptr, struct tipc_media_addr *dest)
|
||||
{
|
||||
struct tipc_link_req *req;
|
||||
|
||||
req = kmalloc(sizeof(*req), GFP_ATOMIC);
|
||||
if (!req)
|
||||
return -ENOMEM;
|
||||
|
||||
req->buf = tipc_buf_acquire(INT_H_SIZE);
|
||||
if (!req->buf) {
|
||||
kfree(req);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
tipc_disc_init_msg(req->buf, DSC_REQ_MSG, b_ptr);
|
||||
memcpy(&req->dest, dest, sizeof(*dest));
|
||||
req->bearer_id = b_ptr->identity;
|
||||
req->domain = b_ptr->domain;
|
||||
req->num_nodes = 0;
|
||||
req->timer_intv = TIPC_LINK_REQ_INIT;
|
||||
spin_lock_init(&req->lock);
|
||||
k_init_timer(&req->timer, (Handler)disc_timeout, (unsigned long)req);
|
||||
k_start_timer(&req->timer, req->timer_intv);
|
||||
b_ptr->link_req = req;
|
||||
tipc_bearer_send(req->bearer_id, req->buf, &req->dest);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* tipc_disc_delete - destroy object sending periodic link setup requests
|
||||
* @req: ptr to link request structure
|
||||
*/
|
||||
void tipc_disc_delete(struct tipc_link_req *req)
|
||||
{
|
||||
k_cancel_timer(&req->timer);
|
||||
k_term_timer(&req->timer);
|
||||
kfree_skb(req->buf);
|
||||
kfree(req);
|
||||
}
|
||||
|
||||
/**
|
||||
* tipc_disc_reset - reset object to send periodic link setup requests
|
||||
* @b_ptr: ptr to bearer issuing requests
|
||||
* @dest_domain: network domain to which links can be established
|
||||
*/
|
||||
void tipc_disc_reset(struct tipc_bearer *b_ptr)
|
||||
{
|
||||
struct tipc_link_req *req = b_ptr->link_req;
|
||||
|
||||
spin_lock_bh(&req->lock);
|
||||
tipc_disc_init_msg(req->buf, DSC_REQ_MSG, b_ptr);
|
||||
req->bearer_id = b_ptr->identity;
|
||||
req->domain = b_ptr->domain;
|
||||
req->num_nodes = 0;
|
||||
req->timer_intv = TIPC_LINK_REQ_INIT;
|
||||
k_start_timer(&req->timer, req->timer_intv);
|
||||
tipc_bearer_send(req->bearer_id, req->buf, &req->dest);
|
||||
spin_unlock_bh(&req->lock);
|
||||
}
|
49
net/tipc/discover.h
Normal file
49
net/tipc/discover.h
Normal file
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* net/tipc/discover.h
|
||||
*
|
||||
* Copyright (c) 2003-2006, Ericsson AB
|
||||
* Copyright (c) 2005, 2010-2011, 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
|
||||
|
||||
struct tipc_link_req;
|
||||
|
||||
int tipc_disc_create(struct tipc_bearer *b_ptr, struct tipc_media_addr *dest);
|
||||
void tipc_disc_delete(struct tipc_link_req *req);
|
||||
void tipc_disc_reset(struct tipc_bearer *b_ptr);
|
||||
void tipc_disc_add_dest(struct tipc_link_req *req);
|
||||
void tipc_disc_remove_dest(struct tipc_link_req *req);
|
||||
void tipc_disc_rcv(struct sk_buff *buf, struct tipc_bearer *b_ptr);
|
||||
|
||||
#endif
|
101
net/tipc/eth_media.c
Normal file
101
net/tipc/eth_media.c
Normal file
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
* net/tipc/eth_media.c: Ethernet bearer support for TIPC
|
||||
*
|
||||
* Copyright (c) 2001-2007, 2013-2014, Ericsson AB
|
||||
* Copyright (c) 2005-2008, 2011-2013, 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"
|
||||
|
||||
#define ETH_ADDR_OFFSET 4 /* MAC addr position inside address field */
|
||||
|
||||
/* Convert Ethernet address (media address format) to string */
|
||||
static int tipc_eth_addr2str(struct tipc_media_addr *addr,
|
||||
char *strbuf, int bufsz)
|
||||
{
|
||||
if (bufsz < 18) /* 18 = strlen("aa:bb:cc:dd:ee:ff\0") */
|
||||
return 1;
|
||||
|
||||
sprintf(strbuf, "%pM", addr->value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Convert from media address format to discovery message addr format */
|
||||
static int tipc_eth_addr2msg(char *msg, struct tipc_media_addr *addr)
|
||||
{
|
||||
memset(msg, 0, TIPC_MEDIA_ADDR_SIZE);
|
||||
msg[TIPC_MEDIA_TYPE_OFFSET] = TIPC_MEDIA_TYPE_ETH;
|
||||
memcpy(msg + ETH_ADDR_OFFSET, addr->value, ETH_ALEN);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Convert raw mac address format to media addr format */
|
||||
static int tipc_eth_raw2addr(struct tipc_bearer *b,
|
||||
struct tipc_media_addr *addr,
|
||||
char *msg)
|
||||
{
|
||||
char bcast_mac[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
|
||||
|
||||
memset(addr, 0, sizeof(*addr));
|
||||
ether_addr_copy(addr->value, msg);
|
||||
addr->media_id = TIPC_MEDIA_TYPE_ETH;
|
||||
addr->broadcast = !memcmp(addr->value, bcast_mac, ETH_ALEN);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Convert discovery msg addr format to Ethernet media addr format */
|
||||
static int tipc_eth_msg2addr(struct tipc_bearer *b,
|
||||
struct tipc_media_addr *addr,
|
||||
char *msg)
|
||||
{
|
||||
/* Skip past preamble: */
|
||||
msg += ETH_ADDR_OFFSET;
|
||||
return tipc_eth_raw2addr(b, addr, msg);
|
||||
}
|
||||
|
||||
/* Ethernet media registration info */
|
||||
struct tipc_media eth_media_info = {
|
||||
.send_msg = tipc_l2_send_msg,
|
||||
.enable_media = tipc_enable_l2_media,
|
||||
.disable_media = tipc_disable_l2_media,
|
||||
.addr2str = tipc_eth_addr2str,
|
||||
.addr2msg = tipc_eth_addr2msg,
|
||||
.msg2addr = tipc_eth_msg2addr,
|
||||
.raw2addr = tipc_eth_raw2addr,
|
||||
.priority = TIPC_DEF_LINK_PRI,
|
||||
.tolerance = TIPC_DEF_LINK_TOL,
|
||||
.window = TIPC_DEF_LINK_WIN,
|
||||
.type_id = TIPC_MEDIA_TYPE_ETH,
|
||||
.hwaddr_len = ETH_ALEN,
|
||||
.name = "eth"
|
||||
};
|
101
net/tipc/ib_media.c
Normal file
101
net/tipc/ib_media.c
Normal file
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
* net/tipc/ib_media.c: Infiniband bearer support for TIPC
|
||||
*
|
||||
* Copyright (c) 2013 Patrick McHardy <kaber@trash.net>
|
||||
*
|
||||
* Based on eth_media.c, which carries the following copyright notice:
|
||||
*
|
||||
* Copyright (c) 2001-2007, Ericsson AB
|
||||
* Copyright (c) 2005-2008, 2011, 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/if_infiniband.h>
|
||||
#include "core.h"
|
||||
#include "bearer.h"
|
||||
|
||||
/* convert InfiniBand address (media address format) media address to string */
|
||||
static int tipc_ib_addr2str(struct tipc_media_addr *a, char *str_buf,
|
||||
int str_size)
|
||||
{
|
||||
if (str_size < 60) /* 60 = 19 * strlen("xx:") + strlen("xx\0") */
|
||||
return 1;
|
||||
|
||||
sprintf(str_buf, "%20phC", a->value);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Convert from media address format to discovery message addr format */
|
||||
static int tipc_ib_addr2msg(char *msg, struct tipc_media_addr *addr)
|
||||
{
|
||||
memset(msg, 0, TIPC_MEDIA_ADDR_SIZE);
|
||||
memcpy(msg, addr->value, INFINIBAND_ALEN);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Convert raw InfiniBand address format to media addr format */
|
||||
static int tipc_ib_raw2addr(struct tipc_bearer *b,
|
||||
struct tipc_media_addr *addr,
|
||||
char *msg)
|
||||
{
|
||||
memset(addr, 0, sizeof(*addr));
|
||||
memcpy(addr->value, msg, INFINIBAND_ALEN);
|
||||
addr->media_id = TIPC_MEDIA_TYPE_IB;
|
||||
addr->broadcast = !memcmp(msg, b->bcast_addr.value,
|
||||
INFINIBAND_ALEN);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Convert discovery msg addr format to InfiniBand media addr format */
|
||||
static int tipc_ib_msg2addr(struct tipc_bearer *b,
|
||||
struct tipc_media_addr *addr,
|
||||
char *msg)
|
||||
{
|
||||
return tipc_ib_raw2addr(b, addr, msg);
|
||||
}
|
||||
|
||||
/* InfiniBand media registration info */
|
||||
struct tipc_media ib_media_info = {
|
||||
.send_msg = tipc_l2_send_msg,
|
||||
.enable_media = tipc_enable_l2_media,
|
||||
.disable_media = tipc_disable_l2_media,
|
||||
.addr2str = tipc_ib_addr2str,
|
||||
.addr2msg = tipc_ib_addr2msg,
|
||||
.msg2addr = tipc_ib_msg2addr,
|
||||
.raw2addr = tipc_ib_raw2addr,
|
||||
.priority = TIPC_DEF_LINK_PRI,
|
||||
.tolerance = TIPC_DEF_LINK_TOL,
|
||||
.window = TIPC_DEF_LINK_WIN,
|
||||
.type_id = TIPC_MEDIA_TYPE_IB,
|
||||
.hwaddr_len = INFINIBAND_ALEN,
|
||||
.name = "ib"
|
||||
};
|
2377
net/tipc/link.c
Normal file
2377
net/tipc/link.c
Normal file
File diff suppressed because it is too large
Load diff
308
net/tipc/link.h
Normal file
308
net/tipc/link.h
Normal file
|
@ -0,0 +1,308 @@
|
|||
/*
|
||||
* net/tipc/link.h: Include file for TIPC link code
|
||||
*
|
||||
* Copyright (c) 1995-2006, 2013-2014, Ericsson AB
|
||||
* Copyright (c) 2004-2005, 2010-2011, 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 "msg.h"
|
||||
#include "node.h"
|
||||
|
||||
/* Out-of-range value for link sequence numbers
|
||||
*/
|
||||
#define INVALID_LINK_SEQ 0x10000
|
||||
|
||||
/* Link working states
|
||||
*/
|
||||
#define WORKING_WORKING 560810u
|
||||
#define WORKING_UNKNOWN 560811u
|
||||
#define RESET_UNKNOWN 560812u
|
||||
#define RESET_RESET 560813u
|
||||
|
||||
/* Link endpoint execution states
|
||||
*/
|
||||
#define LINK_STARTED 0x0001
|
||||
#define LINK_STOPPED 0x0002
|
||||
|
||||
/* Starting value for maximum packet size negotiation on unicast links
|
||||
* (unless bearer MTU is less)
|
||||
*/
|
||||
#define MAX_PKT_DEFAULT 1500
|
||||
|
||||
struct tipc_stats {
|
||||
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 deferred_recv;
|
||||
u32 duplicates;
|
||||
u32 max_queue_sz; /* send queue size high water mark */
|
||||
u32 accu_queue_sz; /* used for send queue size profiling */
|
||||
u32 queue_sz_counts; /* used for send queue size profiling */
|
||||
u32 msg_length_counts; /* used for message length profiling */
|
||||
u32 msg_lengths_total; /* used for message length profiling */
|
||||
u32 msg_length_profile[7]; /* used for msg. length profiling */
|
||||
};
|
||||
|
||||
/**
|
||||
* struct tipc_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
|
||||
* @flags: execution state flags for link endpoint instance
|
||||
* @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
|
||||
* @bearer_id: local bearer id 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
|
||||
* @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
|
||||
* @net_plane: current link network plane ('A' through 'H')
|
||||
* @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_sks: linked list of sockets waiting for link congestion to abate
|
||||
* @long_msg_seq_no: next identifier to use for outbound fragmented messages
|
||||
* @reasm_buf: head of partially reassembled inbound message fragments
|
||||
* @stats: collects statistics regarding link activity
|
||||
*/
|
||||
struct tipc_link {
|
||||
u32 addr;
|
||||
char name[TIPC_MAX_LINK_NAME];
|
||||
struct tipc_media_addr media_addr;
|
||||
struct timer_list timer;
|
||||
struct tipc_node *owner;
|
||||
|
||||
/* Management and link supervision data */
|
||||
unsigned int flags;
|
||||
u32 checkpoint;
|
||||
u32 peer_session;
|
||||
u32 peer_bearer_id;
|
||||
u32 bearer_id;
|
||||
u32 tolerance;
|
||||
u32 continuity_interval;
|
||||
u32 abort_limit;
|
||||
int state;
|
||||
u32 fsm_msg_cnt;
|
||||
struct {
|
||||
unchar hdr[INT_H_SIZE];
|
||||
unchar body[TIPC_MAX_IF_NAME];
|
||||
} proto_msg;
|
||||
struct tipc_msg *pmsg;
|
||||
u32 priority;
|
||||
char net_plane;
|
||||
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 sk_buff_head waiting_sks;
|
||||
|
||||
/* Fragmentation/reassembly */
|
||||
u32 long_msg_seq_no;
|
||||
struct sk_buff *reasm_buf;
|
||||
|
||||
/* Statistics */
|
||||
struct tipc_stats stats;
|
||||
};
|
||||
|
||||
struct tipc_port;
|
||||
|
||||
struct tipc_link *tipc_link_create(struct tipc_node *n_ptr,
|
||||
struct tipc_bearer *b_ptr,
|
||||
const struct tipc_media_addr *media_addr);
|
||||
void tipc_link_delete_list(unsigned int bearer_id, bool shutting_down);
|
||||
void tipc_link_failover_send_queue(struct tipc_link *l_ptr);
|
||||
void tipc_link_dup_queue_xmit(struct tipc_link *l_ptr, struct tipc_link *dest);
|
||||
void tipc_link_reset_fragments(struct tipc_link *l_ptr);
|
||||
int tipc_link_is_up(struct tipc_link *l_ptr);
|
||||
int tipc_link_is_active(struct tipc_link *l_ptr);
|
||||
void tipc_link_purge_queues(struct tipc_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_all(struct tipc_node *node);
|
||||
void tipc_link_reset(struct tipc_link *l_ptr);
|
||||
void tipc_link_reset_list(unsigned int bearer_id);
|
||||
int tipc_link_xmit(struct sk_buff *buf, u32 dest, u32 selector);
|
||||
int __tipc_link_xmit(struct tipc_link *link, struct sk_buff *buf);
|
||||
u32 tipc_link_get_max_pkt(u32 dest, u32 selector);
|
||||
void tipc_link_bundle_rcv(struct sk_buff *buf);
|
||||
void tipc_link_proto_xmit(struct tipc_link *l_ptr, u32 msg_typ, int prob,
|
||||
u32 gap, u32 tolerance, u32 priority, u32 acked_mtu);
|
||||
void tipc_link_push_queue(struct tipc_link *l_ptr);
|
||||
u32 tipc_link_defer_pkt(struct sk_buff **head, struct sk_buff **tail,
|
||||
struct sk_buff *buf);
|
||||
void tipc_link_set_queue_limits(struct tipc_link *l_ptr, u32 window);
|
||||
void tipc_link_retransmit(struct tipc_link *l_ptr,
|
||||
struct sk_buff *start, u32 retransmits);
|
||||
|
||||
/*
|
||||
* Link sequence number manipulation routines (uses modulo 2**16 arithmetic)
|
||||
*/
|
||||
static inline u32 buf_seqno(struct sk_buff *buf)
|
||||
{
|
||||
return msg_seqno(buf_msg(buf));
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Link status checking routines
|
||||
*/
|
||||
static inline int link_working_working(struct tipc_link *l_ptr)
|
||||
{
|
||||
return l_ptr->state == WORKING_WORKING;
|
||||
}
|
||||
|
||||
static inline int link_working_unknown(struct tipc_link *l_ptr)
|
||||
{
|
||||
return l_ptr->state == WORKING_UNKNOWN;
|
||||
}
|
||||
|
||||
static inline int link_reset_unknown(struct tipc_link *l_ptr)
|
||||
{
|
||||
return l_ptr->state == RESET_UNKNOWN;
|
||||
}
|
||||
|
||||
static inline int link_reset_reset(struct tipc_link *l_ptr)
|
||||
{
|
||||
return l_ptr->state == RESET_RESET;
|
||||
}
|
||||
|
||||
static inline int link_congested(struct tipc_link *l_ptr)
|
||||
{
|
||||
return l_ptr->out_queue_size >= l_ptr->queue_limit[0];
|
||||
}
|
||||
|
||||
#endif
|
55
net/tipc/log.c
Normal file
55
net/tipc/log.c
Normal file
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* net/tipc/log.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"
|
||||
|
||||
/**
|
||||
* tipc_snprintf - append formatted output to print buffer
|
||||
* @buf: pointer to print buffer
|
||||
* @len: buffer length
|
||||
* @fmt: formatted info to be printed
|
||||
*/
|
||||
int tipc_snprintf(char *buf, int len, const char *fmt, ...)
|
||||
{
|
||||
int i;
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
i = vscnprintf(buf, len, fmt, args);
|
||||
va_end(args);
|
||||
return i;
|
||||
}
|
462
net/tipc/msg.c
Normal file
462
net/tipc/msg.c
Normal file
|
@ -0,0 +1,462 @@
|
|||
/*
|
||||
* net/tipc/msg.c: TIPC message header routines
|
||||
*
|
||||
* Copyright (c) 2000-2006, 2014, Ericsson AB
|
||||
* Copyright (c) 2005, 2010-2011, 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 "addr.h"
|
||||
#include "name_table.h"
|
||||
|
||||
#define MAX_FORWARD_SIZE 1024
|
||||
|
||||
static unsigned int align(unsigned int i)
|
||||
{
|
||||
return (i + 3) & ~3u;
|
||||
}
|
||||
|
||||
void tipc_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 (hsize > SHORT_H_SIZE) {
|
||||
msg_set_orignode(m, tipc_own_addr);
|
||||
msg_set_destnode(m, destnode);
|
||||
}
|
||||
}
|
||||
|
||||
struct sk_buff *tipc_msg_create(uint user, uint type, uint hdr_sz,
|
||||
uint data_sz, u32 dnode, u32 onode,
|
||||
u32 dport, u32 oport, int errcode)
|
||||
{
|
||||
struct tipc_msg *msg;
|
||||
struct sk_buff *buf;
|
||||
|
||||
buf = tipc_buf_acquire(hdr_sz + data_sz);
|
||||
if (unlikely(!buf))
|
||||
return NULL;
|
||||
|
||||
msg = buf_msg(buf);
|
||||
tipc_msg_init(msg, user, type, hdr_sz, dnode);
|
||||
msg_set_size(msg, hdr_sz + data_sz);
|
||||
msg_set_prevnode(msg, onode);
|
||||
msg_set_origport(msg, oport);
|
||||
msg_set_destport(msg, dport);
|
||||
msg_set_errcode(msg, errcode);
|
||||
if (hdr_sz > SHORT_H_SIZE) {
|
||||
msg_set_orignode(msg, onode);
|
||||
msg_set_destnode(msg, dnode);
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
/* tipc_buf_append(): Append a buffer to the fragment list of another buffer
|
||||
* @*headbuf: in: NULL for first frag, otherwise value returned from prev call
|
||||
* out: set when successful non-complete reassembly, otherwise NULL
|
||||
* @*buf: in: the buffer to append. Always defined
|
||||
* out: head buf after sucessful complete reassembly, otherwise NULL
|
||||
* Returns 1 when reassembly complete, otherwise 0
|
||||
*/
|
||||
int tipc_buf_append(struct sk_buff **headbuf, struct sk_buff **buf)
|
||||
{
|
||||
struct sk_buff *head = *headbuf;
|
||||
struct sk_buff *frag = *buf;
|
||||
struct sk_buff *tail;
|
||||
struct tipc_msg *msg;
|
||||
u32 fragid;
|
||||
int delta;
|
||||
bool headstolen;
|
||||
|
||||
if (!frag)
|
||||
goto err;
|
||||
|
||||
msg = buf_msg(frag);
|
||||
fragid = msg_type(msg);
|
||||
frag->next = NULL;
|
||||
skb_pull(frag, msg_hdr_sz(msg));
|
||||
|
||||
if (fragid == FIRST_FRAGMENT) {
|
||||
if (unlikely(head))
|
||||
goto err;
|
||||
if (unlikely(skb_unclone(frag, GFP_ATOMIC)))
|
||||
goto err;
|
||||
head = *headbuf = frag;
|
||||
skb_frag_list_init(head);
|
||||
TIPC_SKB_CB(head)->tail = NULL;
|
||||
*buf = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!head)
|
||||
goto err;
|
||||
|
||||
if (skb_try_coalesce(head, frag, &headstolen, &delta)) {
|
||||
kfree_skb_partial(frag, headstolen);
|
||||
} else {
|
||||
tail = TIPC_SKB_CB(head)->tail;
|
||||
if (!skb_has_frag_list(head))
|
||||
skb_shinfo(head)->frag_list = frag;
|
||||
else
|
||||
tail->next = frag;
|
||||
head->truesize += frag->truesize;
|
||||
head->data_len += frag->len;
|
||||
head->len += frag->len;
|
||||
TIPC_SKB_CB(head)->tail = frag;
|
||||
}
|
||||
|
||||
if (fragid == LAST_FRAGMENT) {
|
||||
*buf = head;
|
||||
TIPC_SKB_CB(head)->tail = NULL;
|
||||
*headbuf = NULL;
|
||||
return 1;
|
||||
}
|
||||
*buf = NULL;
|
||||
return 0;
|
||||
|
||||
err:
|
||||
pr_warn_ratelimited("Unable to build fragment list\n");
|
||||
kfree_skb(*buf);
|
||||
kfree_skb(*headbuf);
|
||||
*buf = *headbuf = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* tipc_msg_build - create buffer chain containing specified header and data
|
||||
* @mhdr: Message header, to be prepended to data
|
||||
* @iov: User data
|
||||
* @offset: Posision in iov to start copying from
|
||||
* @dsz: Total length of user data
|
||||
* @pktmax: Max packet size that can be used
|
||||
* @chain: Buffer or chain of buffers to be returned to caller
|
||||
* Returns message data size or errno: -ENOMEM, -EFAULT
|
||||
*/
|
||||
int tipc_msg_build(struct tipc_msg *mhdr, struct iovec const *iov,
|
||||
int offset, int dsz, int pktmax , struct sk_buff **chain)
|
||||
{
|
||||
int mhsz = msg_hdr_sz(mhdr);
|
||||
int msz = mhsz + dsz;
|
||||
int pktno = 1;
|
||||
int pktsz;
|
||||
int pktrem = pktmax;
|
||||
int drem = dsz;
|
||||
struct tipc_msg pkthdr;
|
||||
struct sk_buff *buf, *prev;
|
||||
char *pktpos;
|
||||
int rc;
|
||||
uint chain_sz = 0;
|
||||
msg_set_size(mhdr, msz);
|
||||
|
||||
/* No fragmentation needed? */
|
||||
if (likely(msz <= pktmax)) {
|
||||
buf = tipc_buf_acquire(msz);
|
||||
*chain = buf;
|
||||
if (unlikely(!buf))
|
||||
return -ENOMEM;
|
||||
skb_copy_to_linear_data(buf, mhdr, mhsz);
|
||||
pktpos = buf->data + mhsz;
|
||||
TIPC_SKB_CB(buf)->chain_sz = 1;
|
||||
if (!dsz || !memcpy_fromiovecend(pktpos, iov, offset, dsz))
|
||||
return dsz;
|
||||
rc = -EFAULT;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Prepare reusable fragment header */
|
||||
tipc_msg_init(&pkthdr, MSG_FRAGMENTER, FIRST_FRAGMENT,
|
||||
INT_H_SIZE, msg_destnode(mhdr));
|
||||
msg_set_size(&pkthdr, pktmax);
|
||||
msg_set_fragm_no(&pkthdr, pktno);
|
||||
|
||||
/* Prepare first fragment */
|
||||
*chain = buf = tipc_buf_acquire(pktmax);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
chain_sz = 1;
|
||||
pktpos = buf->data;
|
||||
skb_copy_to_linear_data(buf, &pkthdr, INT_H_SIZE);
|
||||
pktpos += INT_H_SIZE;
|
||||
pktrem -= INT_H_SIZE;
|
||||
skb_copy_to_linear_data_offset(buf, INT_H_SIZE, mhdr, mhsz);
|
||||
pktpos += mhsz;
|
||||
pktrem -= mhsz;
|
||||
|
||||
do {
|
||||
if (drem < pktrem)
|
||||
pktrem = drem;
|
||||
|
||||
if (memcpy_fromiovecend(pktpos, iov, offset, pktrem)) {
|
||||
rc = -EFAULT;
|
||||
goto error;
|
||||
}
|
||||
drem -= pktrem;
|
||||
offset += pktrem;
|
||||
|
||||
if (!drem)
|
||||
break;
|
||||
|
||||
/* Prepare new fragment: */
|
||||
if (drem < (pktmax - INT_H_SIZE))
|
||||
pktsz = drem + INT_H_SIZE;
|
||||
else
|
||||
pktsz = pktmax;
|
||||
prev = buf;
|
||||
buf = tipc_buf_acquire(pktsz);
|
||||
if (!buf) {
|
||||
rc = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
chain_sz++;
|
||||
prev->next = buf;
|
||||
msg_set_type(&pkthdr, FRAGMENT);
|
||||
msg_set_size(&pkthdr, pktsz);
|
||||
msg_set_fragm_no(&pkthdr, ++pktno);
|
||||
skb_copy_to_linear_data(buf, &pkthdr, INT_H_SIZE);
|
||||
pktpos = buf->data + INT_H_SIZE;
|
||||
pktrem = pktsz - INT_H_SIZE;
|
||||
|
||||
} while (1);
|
||||
TIPC_SKB_CB(*chain)->chain_sz = chain_sz;
|
||||
msg_set_type(buf_msg(buf), LAST_FRAGMENT);
|
||||
return dsz;
|
||||
error:
|
||||
kfree_skb_list(*chain);
|
||||
*chain = NULL;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* tipc_msg_bundle(): Append contents of a buffer to tail of an existing one
|
||||
* @bbuf: the existing buffer ("bundle")
|
||||
* @buf: buffer to be appended
|
||||
* @mtu: max allowable size for the bundle buffer
|
||||
* Consumes buffer if successful
|
||||
* Returns true if bundling could be performed, otherwise false
|
||||
*/
|
||||
bool tipc_msg_bundle(struct sk_buff *bbuf, struct sk_buff *buf, u32 mtu)
|
||||
{
|
||||
struct tipc_msg *bmsg = buf_msg(bbuf);
|
||||
struct tipc_msg *msg = buf_msg(buf);
|
||||
unsigned int bsz = msg_size(bmsg);
|
||||
unsigned int msz = msg_size(msg);
|
||||
u32 start = align(bsz);
|
||||
u32 max = mtu - INT_H_SIZE;
|
||||
u32 pad = start - bsz;
|
||||
|
||||
if (likely(msg_user(msg) == MSG_FRAGMENTER))
|
||||
return false;
|
||||
if (unlikely(msg_user(msg) == CHANGEOVER_PROTOCOL))
|
||||
return false;
|
||||
if (unlikely(msg_user(msg) == BCAST_PROTOCOL))
|
||||
return false;
|
||||
if (likely(msg_user(bmsg) != MSG_BUNDLER))
|
||||
return false;
|
||||
if (likely(msg_type(bmsg) != BUNDLE_OPEN))
|
||||
return false;
|
||||
if (unlikely(skb_tailroom(bbuf) < (pad + msz)))
|
||||
return false;
|
||||
if (unlikely(max < (start + msz)))
|
||||
return false;
|
||||
|
||||
skb_put(bbuf, pad + msz);
|
||||
skb_copy_to_linear_data_offset(bbuf, start, buf->data, msz);
|
||||
msg_set_size(bmsg, start + msz);
|
||||
msg_set_msgcnt(bmsg, msg_msgcnt(bmsg) + 1);
|
||||
bbuf->next = buf->next;
|
||||
kfree_skb(buf);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* tipc_msg_make_bundle(): Create bundle buf and append message to its tail
|
||||
* @buf: buffer to be appended and replaced
|
||||
* @mtu: max allowable size for the bundle buffer, inclusive header
|
||||
* @dnode: destination node for message. (Not always present in header)
|
||||
* Replaces buffer if successful
|
||||
* Returns true if sucess, otherwise false
|
||||
*/
|
||||
bool tipc_msg_make_bundle(struct sk_buff **buf, u32 mtu, u32 dnode)
|
||||
{
|
||||
struct sk_buff *bbuf;
|
||||
struct tipc_msg *bmsg;
|
||||
struct tipc_msg *msg = buf_msg(*buf);
|
||||
u32 msz = msg_size(msg);
|
||||
u32 max = mtu - INT_H_SIZE;
|
||||
|
||||
if (msg_user(msg) == MSG_FRAGMENTER)
|
||||
return false;
|
||||
if (msg_user(msg) == CHANGEOVER_PROTOCOL)
|
||||
return false;
|
||||
if (msg_user(msg) == BCAST_PROTOCOL)
|
||||
return false;
|
||||
if (msz > (max / 2))
|
||||
return false;
|
||||
|
||||
bbuf = tipc_buf_acquire(max);
|
||||
if (!bbuf)
|
||||
return false;
|
||||
|
||||
skb_trim(bbuf, INT_H_SIZE);
|
||||
bmsg = buf_msg(bbuf);
|
||||
tipc_msg_init(bmsg, MSG_BUNDLER, BUNDLE_OPEN, INT_H_SIZE, dnode);
|
||||
msg_set_seqno(bmsg, msg_seqno(msg));
|
||||
msg_set_ack(bmsg, msg_ack(msg));
|
||||
msg_set_bcast_ack(bmsg, msg_bcast_ack(msg));
|
||||
bbuf->next = (*buf)->next;
|
||||
tipc_msg_bundle(bbuf, *buf, mtu);
|
||||
*buf = bbuf;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* tipc_msg_reverse(): swap source and destination addresses and add error code
|
||||
* @buf: buffer containing message to be reversed
|
||||
* @dnode: return value: node where to send message after reversal
|
||||
* @err: error code to be set in message
|
||||
* Consumes buffer if failure
|
||||
* Returns true if success, otherwise false
|
||||
*/
|
||||
bool tipc_msg_reverse(struct sk_buff *buf, u32 *dnode, int err)
|
||||
{
|
||||
struct tipc_msg *msg = buf_msg(buf);
|
||||
uint imp = msg_importance(msg);
|
||||
struct tipc_msg ohdr;
|
||||
uint rdsz = min_t(uint, msg_data_sz(msg), MAX_FORWARD_SIZE);
|
||||
|
||||
if (skb_linearize(buf))
|
||||
goto exit;
|
||||
if (msg_dest_droppable(msg))
|
||||
goto exit;
|
||||
if (msg_errcode(msg))
|
||||
goto exit;
|
||||
|
||||
memcpy(&ohdr, msg, msg_hdr_sz(msg));
|
||||
imp = min_t(uint, imp + 1, TIPC_CRITICAL_IMPORTANCE);
|
||||
if (msg_isdata(msg))
|
||||
msg_set_importance(msg, imp);
|
||||
msg_set_errcode(msg, err);
|
||||
msg_set_origport(msg, msg_destport(&ohdr));
|
||||
msg_set_destport(msg, msg_origport(&ohdr));
|
||||
msg_set_prevnode(msg, tipc_own_addr);
|
||||
if (!msg_short(msg)) {
|
||||
msg_set_orignode(msg, msg_destnode(&ohdr));
|
||||
msg_set_destnode(msg, msg_orignode(&ohdr));
|
||||
}
|
||||
msg_set_size(msg, msg_hdr_sz(msg) + rdsz);
|
||||
skb_trim(buf, msg_size(msg));
|
||||
skb_orphan(buf);
|
||||
*dnode = msg_orignode(&ohdr);
|
||||
return true;
|
||||
exit:
|
||||
kfree_skb(buf);
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* tipc_msg_eval: determine fate of message that found no destination
|
||||
* @buf: the buffer containing the message.
|
||||
* @dnode: return value: next-hop node, if message to be forwarded
|
||||
* @err: error code to use, if message to be rejected
|
||||
*
|
||||
* Does not consume buffer
|
||||
* Returns 0 (TIPC_OK) if message ok and we can try again, -TIPC error
|
||||
* code if message to be rejected
|
||||
*/
|
||||
int tipc_msg_eval(struct sk_buff *buf, u32 *dnode)
|
||||
{
|
||||
struct tipc_msg *msg = buf_msg(buf);
|
||||
u32 dport;
|
||||
|
||||
if (msg_type(msg) != TIPC_NAMED_MSG)
|
||||
return -TIPC_ERR_NO_PORT;
|
||||
if (skb_linearize(buf))
|
||||
return -TIPC_ERR_NO_NAME;
|
||||
if (msg_data_sz(msg) > MAX_FORWARD_SIZE)
|
||||
return -TIPC_ERR_NO_NAME;
|
||||
if (msg_reroute_cnt(msg) > 0)
|
||||
return -TIPC_ERR_NO_NAME;
|
||||
|
||||
*dnode = addr_domain(msg_lookup_scope(msg));
|
||||
dport = tipc_nametbl_translate(msg_nametype(msg),
|
||||
msg_nameinst(msg),
|
||||
dnode);
|
||||
if (!dport)
|
||||
return -TIPC_ERR_NO_NAME;
|
||||
msg_incr_reroute_cnt(msg);
|
||||
msg_set_destnode(msg, *dnode);
|
||||
msg_set_destport(msg, dport);
|
||||
return TIPC_OK;
|
||||
}
|
||||
|
||||
/* tipc_msg_reassemble() - clone a buffer chain of fragments and
|
||||
* reassemble the clones into one message
|
||||
*/
|
||||
struct sk_buff *tipc_msg_reassemble(struct sk_buff *chain)
|
||||
{
|
||||
struct sk_buff *buf = chain;
|
||||
struct sk_buff *frag = buf;
|
||||
struct sk_buff *head = NULL;
|
||||
int hdr_sz;
|
||||
|
||||
/* Copy header if single buffer */
|
||||
if (!buf->next) {
|
||||
hdr_sz = skb_headroom(buf) + msg_hdr_sz(buf_msg(buf));
|
||||
return __pskb_copy(buf, hdr_sz, GFP_ATOMIC);
|
||||
}
|
||||
|
||||
/* Clone all fragments and reassemble */
|
||||
while (buf) {
|
||||
frag = skb_clone(buf, GFP_ATOMIC);
|
||||
if (!frag)
|
||||
goto error;
|
||||
frag->next = NULL;
|
||||
if (tipc_buf_append(&head, &frag))
|
||||
break;
|
||||
if (!head)
|
||||
goto error;
|
||||
buf = buf->next;
|
||||
}
|
||||
return frag;
|
||||
error:
|
||||
pr_warn("Failed do clone local mcast rcv buffer\n");
|
||||
kfree_skb(head);
|
||||
return NULL;
|
||||
}
|
751
net/tipc/msg.h
Normal file
751
net/tipc/msg.h
Normal file
|
@ -0,0 +1,751 @@
|
|||
/*
|
||||
* net/tipc/msg.h: Include file for TIPC message header routines
|
||||
*
|
||||
* Copyright (c) 2000-2007, 2014, Ericsson AB
|
||||
* Copyright (c) 2005-2008, 2010-2011, 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 "bearer.h"
|
||||
|
||||
/*
|
||||
* Constants and routines used to read and write TIPC payload message headers
|
||||
*
|
||||
* Note: Some items are also used with TIPC internal message headers
|
||||
*/
|
||||
#define TIPC_VERSION 2
|
||||
|
||||
/*
|
||||
* Payload message users are defined in TIPC's public API:
|
||||
* - TIPC_LOW_IMPORTANCE
|
||||
* - TIPC_MEDIUM_IMPORTANCE
|
||||
* - TIPC_HIGH_IMPORTANCE
|
||||
* - TIPC_CRITICAL_IMPORTANCE
|
||||
*/
|
||||
|
||||
/*
|
||||
* Payload message types
|
||||
*/
|
||||
#define TIPC_CONN_MSG 0
|
||||
#define TIPC_MCAST_MSG 1
|
||||
#define TIPC_NAMED_MSG 2
|
||||
#define TIPC_DIRECT_MSG 3
|
||||
|
||||
/*
|
||||
* Message header sizes
|
||||
*/
|
||||
#define SHORT_H_SIZE 24 /* In-cluster basic payload message */
|
||||
#define BASIC_H_SIZE 32 /* Basic payload message */
|
||||
#define NAMED_H_SIZE 40 /* Named payload message */
|
||||
#define MCAST_H_SIZE 44 /* Multicast payload message */
|
||||
#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)
|
||||
|
||||
#define TIPC_MEDIA_ADDR_OFFSET 5
|
||||
|
||||
|
||||
struct tipc_msg {
|
||||
__be32 hdr[15];
|
||||
};
|
||||
|
||||
|
||||
static inline u32 msg_word(struct tipc_msg *m, u32 pos)
|
||||
{
|
||||
return ntohl(m->hdr[pos]);
|
||||
}
|
||||
|
||||
static inline void msg_set_word(struct tipc_msg *m, u32 w, u32 val)
|
||||
{
|
||||
m->hdr[w] = htonl(val);
|
||||
}
|
||||
|
||||
static inline u32 msg_bits(struct tipc_msg *m, u32 w, u32 pos, u32 mask)
|
||||
{
|
||||
return (msg_word(m, w) >> pos) & mask;
|
||||
}
|
||||
|
||||
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 u32 msg_importance(struct tipc_msg *m)
|
||||
{
|
||||
return msg_bits(m, 0, 25, 0xf);
|
||||
}
|
||||
|
||||
static inline void msg_set_importance(struct tipc_msg *m, u32 i)
|
||||
{
|
||||
msg_set_user(m, i);
|
||||
}
|
||||
|
||||
static inline u32 msg_hdr_sz(struct tipc_msg *m)
|
||||
{
|
||||
return msg_bits(m, 0, 21, 0xf) << 2;
|
||||
}
|
||||
|
||||
static inline void msg_set_hdr_sz(struct tipc_msg *m, u32 n)
|
||||
{
|
||||
msg_set_bits(m, 0, 21, 0xf, n>>2);
|
||||
}
|
||||
|
||||
static inline u32 msg_size(struct tipc_msg *m)
|
||||
{
|
||||
return msg_bits(m, 0, 0, 0x1ffff);
|
||||
}
|
||||
|
||||
static inline u32 msg_data_sz(struct tipc_msg *m)
|
||||
{
|
||||
return msg_size(m) - msg_hdr_sz(m);
|
||||
}
|
||||
|
||||
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 u32 msg_type(struct tipc_msg *m)
|
||||
{
|
||||
return msg_bits(m, 1, 29, 0x7);
|
||||
}
|
||||
|
||||
static inline void msg_set_type(struct tipc_msg *m, u32 n)
|
||||
{
|
||||
msg_set_bits(m, 1, 29, 0x7, n);
|
||||
}
|
||||
|
||||
static inline u32 msg_named(struct tipc_msg *m)
|
||||
{
|
||||
return msg_type(m) == TIPC_NAMED_MSG;
|
||||
}
|
||||
|
||||
static inline u32 msg_mcast(struct tipc_msg *m)
|
||||
{
|
||||
return msg_type(m) == TIPC_MCAST_MSG;
|
||||
}
|
||||
|
||||
static inline u32 msg_connected(struct tipc_msg *m)
|
||||
{
|
||||
return msg_type(m) == TIPC_CONN_MSG;
|
||||
}
|
||||
|
||||
static inline u32 msg_errcode(struct tipc_msg *m)
|
||||
{
|
||||
return msg_bits(m, 1, 25, 0xf);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/*
|
||||
* Words 3-10
|
||||
*/
|
||||
static inline u32 msg_prevnode(struct tipc_msg *m)
|
||||
{
|
||||
return msg_word(m, 3);
|
||||
}
|
||||
|
||||
static inline void msg_set_prevnode(struct tipc_msg *m, u32 a)
|
||||
{
|
||||
msg_set_word(m, 3, a);
|
||||
}
|
||||
|
||||
static inline u32 msg_origport(struct tipc_msg *m)
|
||||
{
|
||||
return msg_word(m, 4);
|
||||
}
|
||||
|
||||
static inline void msg_set_origport(struct tipc_msg *m, u32 p)
|
||||
{
|
||||
msg_set_word(m, 4, p);
|
||||
}
|
||||
|
||||
static inline u32 msg_destport(struct tipc_msg *m)
|
||||
{
|
||||
return msg_word(m, 5);
|
||||
}
|
||||
|
||||
static inline void msg_set_destport(struct tipc_msg *m, u32 p)
|
||||
{
|
||||
msg_set_word(m, 5, p);
|
||||
}
|
||||
|
||||
static inline u32 msg_mc_netid(struct tipc_msg *m)
|
||||
{
|
||||
return msg_word(m, 5);
|
||||
}
|
||||
|
||||
static inline void msg_set_mc_netid(struct tipc_msg *m, u32 p)
|
||||
{
|
||||
msg_set_word(m, 5, p);
|
||||
}
|
||||
|
||||
static inline int msg_short(struct tipc_msg *m)
|
||||
{
|
||||
return msg_hdr_sz(m) == SHORT_H_SIZE;
|
||||
}
|
||||
|
||||
static inline u32 msg_orignode(struct tipc_msg *m)
|
||||
{
|
||||
if (likely(msg_short(m)))
|
||||
return msg_prevnode(m);
|
||||
return msg_word(m, 6);
|
||||
}
|
||||
|
||||
static inline void msg_set_orignode(struct tipc_msg *m, u32 a)
|
||||
{
|
||||
msg_set_word(m, 6, a);
|
||||
}
|
||||
|
||||
static inline u32 msg_destnode(struct tipc_msg *m)
|
||||
{
|
||||
return msg_word(m, 7);
|
||||
}
|
||||
|
||||
static inline void msg_set_destnode(struct tipc_msg *m, u32 a)
|
||||
{
|
||||
msg_set_word(m, 7, a);
|
||||
}
|
||||
|
||||
static inline u32 msg_nametype(struct tipc_msg *m)
|
||||
{
|
||||
return msg_word(m, 8);
|
||||
}
|
||||
|
||||
static inline void msg_set_nametype(struct tipc_msg *m, u32 n)
|
||||
{
|
||||
msg_set_word(m, 8, n);
|
||||
}
|
||||
|
||||
static inline u32 msg_nameinst(struct tipc_msg *m)
|
||||
{
|
||||
return msg_word(m, 9);
|
||||
}
|
||||
|
||||
static inline u32 msg_namelower(struct tipc_msg *m)
|
||||
{
|
||||
return msg_nameinst(m);
|
||||
}
|
||||
|
||||
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 u32 msg_nameupper(struct tipc_msg *m)
|
||||
{
|
||||
return msg_word(m, 10);
|
||||
}
|
||||
|
||||
static inline void msg_set_nameupper(struct tipc_msg *m, u32 n)
|
||||
{
|
||||
msg_set_word(m, 10, n);
|
||||
}
|
||||
|
||||
static inline unchar *msg_data(struct tipc_msg *m)
|
||||
{
|
||||
return ((unchar *)m) + msg_hdr_sz(m);
|
||||
}
|
||||
|
||||
static inline struct tipc_msg *msg_get_wrapped(struct tipc_msg *m)
|
||||
{
|
||||
return (struct tipc_msg *)msg_data(m);
|
||||
}
|
||||
|
||||
/*
|
||||
* Constants and routines used to read and write TIPC internal message headers
|
||||
*/
|
||||
|
||||
/*
|
||||
* Internal message users
|
||||
*/
|
||||
#define BCAST_PROTOCOL 5
|
||||
#define MSG_BUNDLER 6
|
||||
#define LINK_PROTOCOL 7
|
||||
#define CONN_MANAGER 8
|
||||
#define ROUTE_DISTRIBUTOR 9 /* obsoleted */
|
||||
#define CHANGEOVER_PROTOCOL 10
|
||||
#define NAME_DISTRIBUTOR 11
|
||||
#define MSG_FRAGMENTER 12
|
||||
#define LINK_CONFIG 13
|
||||
#define SOCK_WAKEUP 14 /* pseudo user */
|
||||
|
||||
/*
|
||||
* Connection management protocol message types
|
||||
*/
|
||||
#define CONN_PROBE 0
|
||||
#define CONN_PROBE_REPLY 1
|
||||
#define CONN_ACK 2
|
||||
|
||||
/*
|
||||
* Name distributor message types
|
||||
*/
|
||||
#define PUBLICATION 0
|
||||
#define WITHDRAWAL 1
|
||||
|
||||
/*
|
||||
* Segmentation message types
|
||||
*/
|
||||
#define FIRST_FRAGMENT 0
|
||||
#define FRAGMENT 1
|
||||
#define LAST_FRAGMENT 2
|
||||
|
||||
/* Bundling protocol message types
|
||||
*/
|
||||
#define BUNDLE_OPEN 0
|
||||
#define BUNDLE_CLOSED 1
|
||||
|
||||
/*
|
||||
* 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
|
||||
|
||||
/*
|
||||
* Config protocol message types
|
||||
*/
|
||||
#define DSC_REQ_MSG 0
|
||||
#define DSC_RESP_MSG 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_node_sig(struct tipc_msg *m)
|
||||
{
|
||||
return msg_bits(m, 1, 0, 0xffff);
|
||||
}
|
||||
|
||||
static inline void msg_set_node_sig(struct tipc_msg *m, u32 n)
|
||||
{
|
||||
msg_set_bits(m, 1, 0, 0xffff, 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 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 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);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
|
||||
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, u32 r)
|
||||
{
|
||||
msg_set_bits(m, 5, 12, 0x1, r);
|
||||
}
|
||||
|
||||
static inline char *msg_media_addr(struct tipc_msg *m)
|
||||
{
|
||||
return (char *)&m->hdr[TIPC_MEDIA_ADDR_OFFSET];
|
||||
}
|
||||
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
|
||||
static inline u32 tipc_msg_tot_importance(struct tipc_msg *m)
|
||||
{
|
||||
if ((msg_user(m) == MSG_FRAGMENTER) && (msg_type(m) == FIRST_FRAGMENT))
|
||||
return msg_importance(msg_get_wrapped(m));
|
||||
return msg_importance(m);
|
||||
}
|
||||
|
||||
static inline u32 msg_tot_origport(struct tipc_msg *m)
|
||||
{
|
||||
if ((msg_user(m) == MSG_FRAGMENTER) && (msg_type(m) == FIRST_FRAGMENT))
|
||||
return msg_origport(msg_get_wrapped(m));
|
||||
return msg_origport(m);
|
||||
}
|
||||
|
||||
bool tipc_msg_reverse(struct sk_buff *buf, u32 *dnode, int err);
|
||||
|
||||
int tipc_msg_eval(struct sk_buff *buf, u32 *dnode);
|
||||
|
||||
void tipc_msg_init(struct tipc_msg *m, u32 user, u32 type, u32 hsize,
|
||||
u32 destnode);
|
||||
|
||||
struct sk_buff *tipc_msg_create(uint user, uint type, uint hdr_sz,
|
||||
uint data_sz, u32 dnode, u32 onode,
|
||||
u32 dport, u32 oport, int errcode);
|
||||
|
||||
int tipc_buf_append(struct sk_buff **headbuf, struct sk_buff **buf);
|
||||
|
||||
bool tipc_msg_bundle(struct sk_buff *bbuf, struct sk_buff *buf, u32 mtu);
|
||||
|
||||
bool tipc_msg_make_bundle(struct sk_buff **buf, u32 mtu, u32 dnode);
|
||||
|
||||
int tipc_msg_build(struct tipc_msg *mhdr, struct iovec const *iov,
|
||||
int offset, int dsz, int mtu , struct sk_buff **chain);
|
||||
|
||||
struct sk_buff *tipc_msg_reassemble(struct sk_buff *chain);
|
||||
|
||||
#endif
|
403
net/tipc/name_distr.c
Normal file
403
net/tipc/name_distr.c
Normal file
|
@ -0,0 +1,403 @@
|
|||
/*
|
||||
* net/tipc/name_distr.c: TIPC name distribution code
|
||||
*
|
||||
* Copyright (c) 2000-2006, 2014, Ericsson AB
|
||||
* Copyright (c) 2005, 2010-2011, 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 "link.h"
|
||||
#include "name_distr.h"
|
||||
|
||||
/**
|
||||
* struct publ_list - list of publications made by this node
|
||||
* @list: circular list of publications
|
||||
* @list_size: number of entries in list
|
||||
*/
|
||||
struct publ_list {
|
||||
struct list_head list;
|
||||
u32 size;
|
||||
};
|
||||
|
||||
static struct publ_list publ_zone = {
|
||||
.list = LIST_HEAD_INIT(publ_zone.list),
|
||||
.size = 0,
|
||||
};
|
||||
|
||||
static struct publ_list publ_cluster = {
|
||||
.list = LIST_HEAD_INIT(publ_cluster.list),
|
||||
.size = 0,
|
||||
};
|
||||
|
||||
static struct publ_list publ_node = {
|
||||
.list = LIST_HEAD_INIT(publ_node.list),
|
||||
.size = 0,
|
||||
};
|
||||
|
||||
static struct publ_list *publ_lists[] = {
|
||||
NULL,
|
||||
&publ_zone, /* publ_lists[TIPC_ZONE_SCOPE] */
|
||||
&publ_cluster, /* publ_lists[TIPC_CLUSTER_SCOPE] */
|
||||
&publ_node /* publ_lists[TIPC_NODE_SCOPE] */
|
||||
};
|
||||
|
||||
|
||||
int sysctl_tipc_named_timeout __read_mostly = 2000;
|
||||
|
||||
/**
|
||||
* struct tipc_dist_queue - queue holding deferred name table updates
|
||||
*/
|
||||
static struct list_head tipc_dist_queue = LIST_HEAD_INIT(tipc_dist_queue);
|
||||
|
||||
struct distr_queue_item {
|
||||
struct distr_item i;
|
||||
u32 dtype;
|
||||
u32 node;
|
||||
unsigned long expires;
|
||||
struct list_head next;
|
||||
};
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 = tipc_buf_acquire(INT_H_SIZE + size);
|
||||
struct tipc_msg *msg;
|
||||
|
||||
if (buf != NULL) {
|
||||
msg = buf_msg(buf);
|
||||
tipc_msg_init(msg, NAME_DISTRIBUTOR, type, INT_H_SIZE, dest);
|
||||
msg_set_size(msg, INT_H_SIZE + size);
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
void named_cluster_distribute(struct sk_buff *buf)
|
||||
{
|
||||
struct sk_buff *obuf;
|
||||
struct tipc_node *node;
|
||||
u32 dnode;
|
||||
|
||||
rcu_read_lock();
|
||||
list_for_each_entry_rcu(node, &tipc_node_list, list) {
|
||||
dnode = node->addr;
|
||||
if (in_own_node(dnode))
|
||||
continue;
|
||||
if (!tipc_node_active_links(node))
|
||||
continue;
|
||||
obuf = skb_copy(buf, GFP_ATOMIC);
|
||||
if (!obuf)
|
||||
break;
|
||||
msg_set_destnode(buf_msg(obuf), dnode);
|
||||
tipc_link_xmit(obuf, dnode, dnode);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
kfree_skb(buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* tipc_named_publish - tell other nodes about a new publication by this node
|
||||
*/
|
||||
struct sk_buff *tipc_named_publish(struct publication *publ)
|
||||
{
|
||||
struct sk_buff *buf;
|
||||
struct distr_item *item;
|
||||
|
||||
list_add_tail(&publ->local_list, &publ_lists[publ->scope]->list);
|
||||
publ_lists[publ->scope]->size++;
|
||||
|
||||
if (publ->scope == TIPC_NODE_SCOPE)
|
||||
return NULL;
|
||||
|
||||
buf = named_prepare_buf(PUBLICATION, ITEM_SIZE, 0);
|
||||
if (!buf) {
|
||||
pr_warn("Publication distribution failure\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
item = (struct distr_item *)msg_data(buf_msg(buf));
|
||||
publ_to_item(item, publ);
|
||||
return buf;
|
||||
}
|
||||
|
||||
/**
|
||||
* tipc_named_withdraw - tell other nodes about a withdrawn publication by this node
|
||||
*/
|
||||
struct sk_buff *tipc_named_withdraw(struct publication *publ)
|
||||
{
|
||||
struct sk_buff *buf;
|
||||
struct distr_item *item;
|
||||
|
||||
list_del(&publ->local_list);
|
||||
publ_lists[publ->scope]->size--;
|
||||
|
||||
if (publ->scope == TIPC_NODE_SCOPE)
|
||||
return NULL;
|
||||
|
||||
buf = named_prepare_buf(WITHDRAWAL, ITEM_SIZE, 0);
|
||||
if (!buf) {
|
||||
pr_warn("Withdrawal distribution failure\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
item = (struct distr_item *)msg_data(buf_msg(buf));
|
||||
publ_to_item(item, publ);
|
||||
return buf;
|
||||
}
|
||||
|
||||
/**
|
||||
* named_distribute - prepare name info for bulk distribution to another node
|
||||
* @msg_list: list of messages (buffers) to be returned from this function
|
||||
* @dnode: node to be updated
|
||||
* @pls: linked list of publication items to be packed into buffer chain
|
||||
*/
|
||||
static void named_distribute(struct list_head *msg_list, u32 dnode,
|
||||
struct publ_list *pls)
|
||||
{
|
||||
struct publication *publ;
|
||||
struct sk_buff *buf = NULL;
|
||||
struct distr_item *item = NULL;
|
||||
uint dsz = pls->size * ITEM_SIZE;
|
||||
uint msg_dsz = (tipc_node_get_mtu(dnode, 0) / ITEM_SIZE) * ITEM_SIZE;
|
||||
uint rem = dsz;
|
||||
uint msg_rem = 0;
|
||||
|
||||
list_for_each_entry(publ, &pls->list, local_list) {
|
||||
/* Prepare next buffer: */
|
||||
if (!buf) {
|
||||
msg_rem = min_t(uint, rem, msg_dsz);
|
||||
rem -= msg_rem;
|
||||
buf = named_prepare_buf(PUBLICATION, msg_rem, dnode);
|
||||
if (!buf) {
|
||||
pr_warn("Bulk publication failure\n");
|
||||
return;
|
||||
}
|
||||
item = (struct distr_item *)msg_data(buf_msg(buf));
|
||||
}
|
||||
|
||||
/* Pack publication into message: */
|
||||
publ_to_item(item, publ);
|
||||
item++;
|
||||
msg_rem -= ITEM_SIZE;
|
||||
|
||||
/* Append full buffer to list: */
|
||||
if (!msg_rem) {
|
||||
list_add_tail((struct list_head *)buf, msg_list);
|
||||
buf = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* tipc_named_node_up - tell specified node about all publications by this node
|
||||
*/
|
||||
void tipc_named_node_up(u32 dnode)
|
||||
{
|
||||
LIST_HEAD(msg_list);
|
||||
struct sk_buff *buf_chain;
|
||||
|
||||
read_lock_bh(&tipc_nametbl_lock);
|
||||
named_distribute(&msg_list, dnode, &publ_cluster);
|
||||
named_distribute(&msg_list, dnode, &publ_zone);
|
||||
read_unlock_bh(&tipc_nametbl_lock);
|
||||
|
||||
/* Convert circular list to linear list and send: */
|
||||
buf_chain = (struct sk_buff *)msg_list.next;
|
||||
((struct sk_buff *)msg_list.prev)->next = NULL;
|
||||
tipc_link_xmit(buf_chain, dnode, dnode);
|
||||
}
|
||||
|
||||
/**
|
||||
* named_purge_publ - 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.
|
||||
*/
|
||||
static void named_purge_publ(struct publication *publ)
|
||||
{
|
||||
struct publication *p;
|
||||
|
||||
write_lock_bh(&tipc_nametbl_lock);
|
||||
p = tipc_nametbl_remove_publ(publ->type, publ->lower,
|
||||
publ->node, publ->ref, publ->key);
|
||||
if (p)
|
||||
tipc_nodesub_unsubscribe(&p->subscr);
|
||||
write_unlock_bh(&tipc_nametbl_lock);
|
||||
|
||||
if (p != publ) {
|
||||
pr_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);
|
||||
}
|
||||
|
||||
kfree(p);
|
||||
}
|
||||
|
||||
/**
|
||||
* tipc_update_nametbl - try to process a nametable update and notify
|
||||
* subscribers
|
||||
*
|
||||
* tipc_nametbl_lock must be held.
|
||||
* Returns the publication item if successful, otherwise NULL.
|
||||
*/
|
||||
static bool tipc_update_nametbl(struct distr_item *i, u32 node, u32 dtype)
|
||||
{
|
||||
struct publication *publ = NULL;
|
||||
|
||||
if (dtype == PUBLICATION) {
|
||||
publ = tipc_nametbl_insert_publ(ntohl(i->type), ntohl(i->lower),
|
||||
ntohl(i->upper),
|
||||
TIPC_CLUSTER_SCOPE, node,
|
||||
ntohl(i->ref), ntohl(i->key));
|
||||
if (publ) {
|
||||
tipc_nodesub_subscribe(&publ->subscr, node, publ,
|
||||
(net_ev_handler)
|
||||
named_purge_publ);
|
||||
return true;
|
||||
}
|
||||
} else if (dtype == WITHDRAWAL) {
|
||||
publ = tipc_nametbl_remove_publ(ntohl(i->type), ntohl(i->lower),
|
||||
node, ntohl(i->ref),
|
||||
ntohl(i->key));
|
||||
if (publ) {
|
||||
tipc_nodesub_unsubscribe(&publ->subscr);
|
||||
kfree(publ);
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
pr_warn("Unrecognized name table message received\n");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* tipc_named_add_backlog - add a failed name table update to the backlog
|
||||
*
|
||||
*/
|
||||
static void tipc_named_add_backlog(struct distr_item *i, u32 type, u32 node)
|
||||
{
|
||||
struct distr_queue_item *e;
|
||||
unsigned long now = get_jiffies_64();
|
||||
|
||||
e = kzalloc(sizeof(*e), GFP_ATOMIC);
|
||||
if (!e)
|
||||
return;
|
||||
e->dtype = type;
|
||||
e->node = node;
|
||||
e->expires = now + msecs_to_jiffies(sysctl_tipc_named_timeout);
|
||||
memcpy(e, i, sizeof(*i));
|
||||
list_add_tail(&e->next, &tipc_dist_queue);
|
||||
}
|
||||
|
||||
/**
|
||||
* tipc_named_process_backlog - try to process any pending name table updates
|
||||
* from the network.
|
||||
*/
|
||||
void tipc_named_process_backlog(void)
|
||||
{
|
||||
struct distr_queue_item *e, *tmp;
|
||||
char addr[16];
|
||||
unsigned long now = get_jiffies_64();
|
||||
|
||||
list_for_each_entry_safe(e, tmp, &tipc_dist_queue, next) {
|
||||
if (time_after(e->expires, now)) {
|
||||
if (!tipc_update_nametbl(&e->i, e->node, e->dtype))
|
||||
continue;
|
||||
} else {
|
||||
tipc_addr_string_fill(addr, e->node);
|
||||
pr_warn_ratelimited("Dropping name table update (%d) of {%u, %u, %u} from %s key=%u\n",
|
||||
e->dtype, ntohl(e->i.type),
|
||||
ntohl(e->i.lower),
|
||||
ntohl(e->i.upper),
|
||||
addr, ntohl(e->i.key));
|
||||
}
|
||||
list_del(&e->next);
|
||||
kfree(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* tipc_named_rcv - process name table update message sent by another node
|
||||
*/
|
||||
void tipc_named_rcv(struct sk_buff *buf)
|
||||
{
|
||||
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;
|
||||
u32 node = msg_orignode(msg);
|
||||
|
||||
write_lock_bh(&tipc_nametbl_lock);
|
||||
while (count--) {
|
||||
if (!tipc_update_nametbl(item, node, msg_type(msg)))
|
||||
tipc_named_add_backlog(item, msg_type(msg), node);
|
||||
item++;
|
||||
}
|
||||
tipc_named_process_backlog();
|
||||
write_unlock_bh(&tipc_nametbl_lock);
|
||||
kfree_skb(buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* tipc_named_reinit - re-initialize local publications
|
||||
*
|
||||
* This routine is called whenever TIPC networking is enabled.
|
||||
* All name table entries published by this node are updated to reflect
|
||||
* the node's new network address.
|
||||
*/
|
||||
void tipc_named_reinit(void)
|
||||
{
|
||||
struct publication *publ;
|
||||
int scope;
|
||||
|
||||
write_lock_bh(&tipc_nametbl_lock);
|
||||
|
||||
for (scope = TIPC_ZONE_SCOPE; scope <= TIPC_NODE_SCOPE; scope++)
|
||||
list_for_each_entry(publ, &publ_lists[scope]->list, local_list)
|
||||
publ->node = tipc_own_addr;
|
||||
|
||||
write_unlock_bh(&tipc_nametbl_lock);
|
||||
}
|
78
net/tipc/name_distr.h
Normal file
78
net/tipc/name_distr.h
Normal file
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
* 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"
|
||||
|
||||
#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;
|
||||
};
|
||||
|
||||
struct sk_buff *tipc_named_publish(struct publication *publ);
|
||||
struct sk_buff *tipc_named_withdraw(struct publication *publ);
|
||||
void named_cluster_distribute(struct sk_buff *buf);
|
||||
void tipc_named_node_up(u32 dnode);
|
||||
void tipc_named_rcv(struct sk_buff *buf);
|
||||
void tipc_named_reinit(void);
|
||||
void tipc_named_process_backlog(void);
|
||||
|
||||
#endif
|
997
net/tipc/name_table.c
Normal file
997
net/tipc/name_table.c
Normal file
|
@ -0,0 +1,997 @@
|
|||
/*
|
||||
* net/tipc/name_table.c: TIPC name table code
|
||||
*
|
||||
* Copyright (c) 2000-2006, Ericsson AB
|
||||
* Copyright (c) 2004-2008, 2010-2011, 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 "name_table.h"
|
||||
#include "name_distr.h"
|
||||
#include "subscr.h"
|
||||
|
||||
#define TIPC_NAMETBL_SIZE 1024 /* must be a power of 2 */
|
||||
|
||||
/**
|
||||
* struct name_info - name sequence publication info
|
||||
* @node_list: circular list of publications made by own node
|
||||
* @cluster_list: circular list of publications made by own cluster
|
||||
* @zone_list: circular list of publications made by own zone
|
||||
* @node_list_size: number of entries in "node_list"
|
||||
* @cluster_list_size: number of entries in "cluster_list"
|
||||
* @zone_list_size: number of entries in "zone_list"
|
||||
*
|
||||
* Note: The zone list always contains at least one entry, since all
|
||||
* publications of the associated name sequence belong to it.
|
||||
* (The cluster and node lists may be empty.)
|
||||
*/
|
||||
struct name_info {
|
||||
struct list_head node_list;
|
||||
struct list_head cluster_list;
|
||||
struct list_head zone_list;
|
||||
u32 node_list_size;
|
||||
u32 cluster_list_size;
|
||||
u32 zone_list_size;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct sub_seq - container for all published instances of a name sequence
|
||||
* @lower: name sequence lower bound
|
||||
* @upper: name sequence upper bound
|
||||
* @info: pointer to name sequence publication info
|
||||
*/
|
||||
struct sub_seq {
|
||||
u32 lower;
|
||||
u32 upper;
|
||||
struct name_info *info;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct name_seq - container for all published instances of a name type
|
||||
* @type: 32 bit 'type' value for name sequence
|
||||
* @sseq: pointer to dynamically-sized array of sub-sequences of this 'type';
|
||||
* sub-sequences are sorted in ascending order
|
||||
* @alloc: number of sub-sequences currently in array
|
||||
* @first_free: array index of first unused sub-sequence entry
|
||||
* @ns_list: links to adjacent name sequences in hash chain
|
||||
* @subscriptions: list of subscriptions for this 'type'
|
||||
* @lock: spinlock controlling access to publication lists of all sub-sequences
|
||||
*/
|
||||
struct name_seq {
|
||||
u32 type;
|
||||
struct sub_seq *sseqs;
|
||||
u32 alloc;
|
||||
u32 first_free;
|
||||
struct hlist_node ns_list;
|
||||
struct list_head subscriptions;
|
||||
spinlock_t lock;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct name_table - table containing all existing port name publications
|
||||
* @types: pointer to fixed-sized array of name sequence lists,
|
||||
* accessed via hashing on 'type'; name sequence lists are *not* sorted
|
||||
* @local_publ_count: number of publications issued by this node
|
||||
*/
|
||||
struct name_table {
|
||||
struct hlist_head *types;
|
||||
u32 local_publ_count;
|
||||
};
|
||||
|
||||
static struct name_table table;
|
||||
DEFINE_RWLOCK(tipc_nametbl_lock);
|
||||
|
||||
static int hash(int x)
|
||||
{
|
||||
return x & (TIPC_NAMETBL_SIZE - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* publ_create - create a publication structure
|
||||
*/
|
||||
static struct publication *publ_create(u32 type, u32 lower, u32 upper,
|
||||
u32 scope, u32 node, u32 port_ref,
|
||||
u32 key)
|
||||
{
|
||||
struct publication *publ = kzalloc(sizeof(*publ), GFP_ATOMIC);
|
||||
if (publ == NULL) {
|
||||
pr_warn("Publication creation failure, no memory\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
publ->type = type;
|
||||
publ->lower = lower;
|
||||
publ->upper = upper;
|
||||
publ->scope = scope;
|
||||
publ->node = node;
|
||||
publ->ref = port_ref;
|
||||
publ->key = key;
|
||||
INIT_LIST_HEAD(&publ->local_list);
|
||||
INIT_LIST_HEAD(&publ->pport_list);
|
||||
INIT_LIST_HEAD(&publ->subscr.nodesub_list);
|
||||
return publ;
|
||||
}
|
||||
|
||||
/**
|
||||
* tipc_subseq_alloc - allocate a specified number of sub-sequence structures
|
||||
*/
|
||||
static struct sub_seq *tipc_subseq_alloc(u32 cnt)
|
||||
{
|
||||
return kcalloc(cnt, sizeof(struct sub_seq), GFP_ATOMIC);
|
||||
}
|
||||
|
||||
/**
|
||||
* tipc_nameseq_create - create a name sequence structure for the specified 'type'
|
||||
*
|
||||
* Allocates a single sub-sequence structure and sets it to all 0's.
|
||||
*/
|
||||
static struct name_seq *tipc_nameseq_create(u32 type, struct hlist_head *seq_head)
|
||||
{
|
||||
struct name_seq *nseq = kzalloc(sizeof(*nseq), GFP_ATOMIC);
|
||||
struct sub_seq *sseq = tipc_subseq_alloc(1);
|
||||
|
||||
if (!nseq || !sseq) {
|
||||
pr_warn("Name sequence creation failed, no memory\n");
|
||||
kfree(nseq);
|
||||
kfree(sseq);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
spin_lock_init(&nseq->lock);
|
||||
nseq->type = type;
|
||||
nseq->sseqs = sseq;
|
||||
nseq->alloc = 1;
|
||||
INIT_HLIST_NODE(&nseq->ns_list);
|
||||
INIT_LIST_HEAD(&nseq->subscriptions);
|
||||
hlist_add_head(&nseq->ns_list, seq_head);
|
||||
return nseq;
|
||||
}
|
||||
|
||||
/*
|
||||
* nameseq_delete_empty - deletes a name sequence structure if now unused
|
||||
*/
|
||||
static void nameseq_delete_empty(struct name_seq *seq)
|
||||
{
|
||||
if (!seq->first_free && list_empty(&seq->subscriptions)) {
|
||||
hlist_del_init(&seq->ns_list);
|
||||
kfree(seq->sseqs);
|
||||
kfree(seq);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* nameseq_find_subseq - find sub-sequence (if any) matching a name instance
|
||||
*
|
||||
* Very time-critical, so binary searches through sub-sequence array.
|
||||
*/
|
||||
static struct sub_seq *nameseq_find_subseq(struct name_seq *nseq,
|
||||
u32 instance)
|
||||
{
|
||||
struct sub_seq *sseqs = nseq->sseqs;
|
||||
int low = 0;
|
||||
int high = nseq->first_free - 1;
|
||||
int mid;
|
||||
|
||||
while (low <= high) {
|
||||
mid = (low + high) / 2;
|
||||
if (instance < sseqs[mid].lower)
|
||||
high = mid - 1;
|
||||
else if (instance > sseqs[mid].upper)
|
||||
low = mid + 1;
|
||||
else
|
||||
return &sseqs[mid];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* nameseq_locate_subseq - determine position of name instance in sub-sequence
|
||||
*
|
||||
* Returns index in sub-sequence array of the entry that contains the specified
|
||||
* instance value; if no entry contains that value, returns the position
|
||||
* where a new entry for it would be inserted in the array.
|
||||
*
|
||||
* Note: Similar to binary search code for locating a sub-sequence.
|
||||
*/
|
||||
static u32 nameseq_locate_subseq(struct name_seq *nseq, u32 instance)
|
||||
{
|
||||
struct sub_seq *sseqs = nseq->sseqs;
|
||||
int low = 0;
|
||||
int high = nseq->first_free - 1;
|
||||
int mid;
|
||||
|
||||
while (low <= high) {
|
||||
mid = (low + high) / 2;
|
||||
if (instance < sseqs[mid].lower)
|
||||
high = mid - 1;
|
||||
else if (instance > sseqs[mid].upper)
|
||||
low = mid + 1;
|
||||
else
|
||||
return mid;
|
||||
}
|
||||
return low;
|
||||
}
|
||||
|
||||
/**
|
||||
* tipc_nameseq_insert_publ
|
||||
*/
|
||||
static struct publication *tipc_nameseq_insert_publ(struct name_seq *nseq,
|
||||
u32 type, u32 lower, u32 upper,
|
||||
u32 scope, u32 node, u32 port, u32 key)
|
||||
{
|
||||
struct tipc_subscription *s;
|
||||
struct tipc_subscription *st;
|
||||
struct publication *publ;
|
||||
struct sub_seq *sseq;
|
||||
struct name_info *info;
|
||||
int created_subseq = 0;
|
||||
|
||||
sseq = nameseq_find_subseq(nseq, lower);
|
||||
if (sseq) {
|
||||
|
||||
/* Lower end overlaps existing entry => need an exact match */
|
||||
if ((sseq->lower != lower) || (sseq->upper != upper)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
info = sseq->info;
|
||||
|
||||
/* Check if an identical publication already exists */
|
||||
list_for_each_entry(publ, &info->zone_list, zone_list) {
|
||||
if ((publ->ref == port) && (publ->key == key) &&
|
||||
(!publ->node || (publ->node == node)))
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
u32 inspos;
|
||||
struct sub_seq *freesseq;
|
||||
|
||||
/* Find where lower end should be inserted */
|
||||
inspos = nameseq_locate_subseq(nseq, lower);
|
||||
|
||||
/* Fail if upper end overlaps into an existing entry */
|
||||
if ((inspos < nseq->first_free) &&
|
||||
(upper >= nseq->sseqs[inspos].lower)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Ensure there is space for new sub-sequence */
|
||||
if (nseq->first_free == nseq->alloc) {
|
||||
struct sub_seq *sseqs = tipc_subseq_alloc(nseq->alloc * 2);
|
||||
|
||||
if (!sseqs) {
|
||||
pr_warn("Cannot publish {%u,%u,%u}, no memory\n",
|
||||
type, lower, upper);
|
||||
return NULL;
|
||||
}
|
||||
memcpy(sseqs, nseq->sseqs,
|
||||
nseq->alloc * sizeof(struct sub_seq));
|
||||
kfree(nseq->sseqs);
|
||||
nseq->sseqs = sseqs;
|
||||
nseq->alloc *= 2;
|
||||
}
|
||||
|
||||
info = kzalloc(sizeof(*info), GFP_ATOMIC);
|
||||
if (!info) {
|
||||
pr_warn("Cannot publish {%u,%u,%u}, no memory\n",
|
||||
type, lower, upper);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
INIT_LIST_HEAD(&info->node_list);
|
||||
INIT_LIST_HEAD(&info->cluster_list);
|
||||
INIT_LIST_HEAD(&info->zone_list);
|
||||
|
||||
/* Insert new sub-sequence */
|
||||
sseq = &nseq->sseqs[inspos];
|
||||
freesseq = &nseq->sseqs[nseq->first_free];
|
||||
memmove(sseq + 1, sseq, (freesseq - sseq) * sizeof(*sseq));
|
||||
memset(sseq, 0, sizeof(*sseq));
|
||||
nseq->first_free++;
|
||||
sseq->lower = lower;
|
||||
sseq->upper = upper;
|
||||
sseq->info = info;
|
||||
created_subseq = 1;
|
||||
}
|
||||
|
||||
/* Insert a publication */
|
||||
publ = publ_create(type, lower, upper, scope, node, port, key);
|
||||
if (!publ)
|
||||
return NULL;
|
||||
|
||||
list_add(&publ->zone_list, &info->zone_list);
|
||||
info->zone_list_size++;
|
||||
|
||||
if (in_own_cluster(node)) {
|
||||
list_add(&publ->cluster_list, &info->cluster_list);
|
||||
info->cluster_list_size++;
|
||||
}
|
||||
|
||||
if (in_own_node(node)) {
|
||||
list_add(&publ->node_list, &info->node_list);
|
||||
info->node_list_size++;
|
||||
}
|
||||
|
||||
/* Any subscriptions waiting for notification? */
|
||||
list_for_each_entry_safe(s, st, &nseq->subscriptions, nameseq_list) {
|
||||
tipc_subscr_report_overlap(s,
|
||||
publ->lower,
|
||||
publ->upper,
|
||||
TIPC_PUBLISHED,
|
||||
publ->ref,
|
||||
publ->node,
|
||||
created_subseq);
|
||||
}
|
||||
return publ;
|
||||
}
|
||||
|
||||
/**
|
||||
* tipc_nameseq_remove_publ
|
||||
*
|
||||
* NOTE: There may be cases where TIPC is asked to remove a publication
|
||||
* that is not in the name table. For example, if another node issues a
|
||||
* publication for a name sequence that overlaps an existing name sequence
|
||||
* the publication will not be recorded, which means the publication won't
|
||||
* be found when the name sequence is later withdrawn by that node.
|
||||
* A failed withdraw request simply returns a failure indication and lets the
|
||||
* caller issue any error or warning messages associated with such a problem.
|
||||
*/
|
||||
static struct publication *tipc_nameseq_remove_publ(struct name_seq *nseq, u32 inst,
|
||||
u32 node, u32 ref, u32 key)
|
||||
{
|
||||
struct publication *publ;
|
||||
struct sub_seq *sseq = nameseq_find_subseq(nseq, inst);
|
||||
struct name_info *info;
|
||||
struct sub_seq *free;
|
||||
struct tipc_subscription *s, *st;
|
||||
int removed_subseq = 0;
|
||||
|
||||
if (!sseq)
|
||||
return NULL;
|
||||
|
||||
info = sseq->info;
|
||||
|
||||
/* Locate publication, if it exists */
|
||||
list_for_each_entry(publ, &info->zone_list, zone_list) {
|
||||
if ((publ->key == key) && (publ->ref == ref) &&
|
||||
(!publ->node || (publ->node == node)))
|
||||
goto found;
|
||||
}
|
||||
return NULL;
|
||||
|
||||
found:
|
||||
/* Remove publication from zone scope list */
|
||||
list_del(&publ->zone_list);
|
||||
info->zone_list_size--;
|
||||
|
||||
/* Remove publication from cluster scope list, if present */
|
||||
if (in_own_cluster(node)) {
|
||||
list_del(&publ->cluster_list);
|
||||
info->cluster_list_size--;
|
||||
}
|
||||
|
||||
/* Remove publication from node scope list, if present */
|
||||
if (in_own_node(node)) {
|
||||
list_del(&publ->node_list);
|
||||
info->node_list_size--;
|
||||
}
|
||||
|
||||
/* Contract subseq list if no more publications for that subseq */
|
||||
if (list_empty(&info->zone_list)) {
|
||||
kfree(info);
|
||||
free = &nseq->sseqs[nseq->first_free--];
|
||||
memmove(sseq, sseq + 1, (free - (sseq + 1)) * sizeof(*sseq));
|
||||
removed_subseq = 1;
|
||||
}
|
||||
|
||||
/* Notify any waiting subscriptions */
|
||||
list_for_each_entry_safe(s, st, &nseq->subscriptions, nameseq_list) {
|
||||
tipc_subscr_report_overlap(s,
|
||||
publ->lower,
|
||||
publ->upper,
|
||||
TIPC_WITHDRAWN,
|
||||
publ->ref,
|
||||
publ->node,
|
||||
removed_subseq);
|
||||
}
|
||||
|
||||
return publ;
|
||||
}
|
||||
|
||||
/**
|
||||
* tipc_nameseq_subscribe - attach a subscription, and issue
|
||||
* the prescribed number of events if there is any sub-
|
||||
* sequence overlapping with the requested sequence
|
||||
*/
|
||||
static void tipc_nameseq_subscribe(struct name_seq *nseq,
|
||||
struct tipc_subscription *s)
|
||||
{
|
||||
struct sub_seq *sseq = nseq->sseqs;
|
||||
|
||||
list_add(&s->nameseq_list, &nseq->subscriptions);
|
||||
|
||||
if (!sseq)
|
||||
return;
|
||||
|
||||
while (sseq != &nseq->sseqs[nseq->first_free]) {
|
||||
if (tipc_subscr_overlap(s, sseq->lower, sseq->upper)) {
|
||||
struct publication *crs;
|
||||
struct name_info *info = sseq->info;
|
||||
int must_report = 1;
|
||||
|
||||
list_for_each_entry(crs, &info->zone_list, zone_list) {
|
||||
tipc_subscr_report_overlap(s,
|
||||
sseq->lower,
|
||||
sseq->upper,
|
||||
TIPC_PUBLISHED,
|
||||
crs->ref,
|
||||
crs->node,
|
||||
must_report);
|
||||
must_report = 0;
|
||||
}
|
||||
}
|
||||
sseq++;
|
||||
}
|
||||
}
|
||||
|
||||
static struct name_seq *nametbl_find_seq(u32 type)
|
||||
{
|
||||
struct hlist_head *seq_head;
|
||||
struct name_seq *ns;
|
||||
|
||||
seq_head = &table.types[hash(type)];
|
||||
hlist_for_each_entry(ns, seq_head, ns_list) {
|
||||
if (ns->type == type)
|
||||
return ns;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
};
|
||||
|
||||
struct publication *tipc_nametbl_insert_publ(u32 type, u32 lower, u32 upper,
|
||||
u32 scope, u32 node, u32 port, u32 key)
|
||||
{
|
||||
struct name_seq *seq = nametbl_find_seq(type);
|
||||
|
||||
if ((scope < TIPC_ZONE_SCOPE) || (scope > TIPC_NODE_SCOPE) ||
|
||||
(lower > upper)) {
|
||||
pr_debug("Failed to publish illegal {%u,%u,%u} with scope %u\n",
|
||||
type, lower, upper, scope);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!seq)
|
||||
seq = tipc_nameseq_create(type, &table.types[hash(type)]);
|
||||
if (!seq)
|
||||
return NULL;
|
||||
|
||||
return tipc_nameseq_insert_publ(seq, type, lower, upper,
|
||||
scope, node, port, key);
|
||||
}
|
||||
|
||||
struct publication *tipc_nametbl_remove_publ(u32 type, u32 lower,
|
||||
u32 node, u32 ref, u32 key)
|
||||
{
|
||||
struct publication *publ;
|
||||
struct name_seq *seq = nametbl_find_seq(type);
|
||||
|
||||
if (!seq)
|
||||
return NULL;
|
||||
|
||||
publ = tipc_nameseq_remove_publ(seq, lower, node, ref, key);
|
||||
nameseq_delete_empty(seq);
|
||||
return publ;
|
||||
}
|
||||
|
||||
/**
|
||||
* tipc_nametbl_translate - perform name translation
|
||||
*
|
||||
* On entry, 'destnode' is the search domain used during translation.
|
||||
*
|
||||
* On exit:
|
||||
* - if name translation is deferred to another node/cluster/zone,
|
||||
* leaves 'destnode' unchanged (will be non-zero) and returns 0
|
||||
* - if name translation is attempted and succeeds, sets 'destnode'
|
||||
* to publishing node and returns port reference (will be non-zero)
|
||||
* - if name translation is attempted and fails, sets 'destnode' to 0
|
||||
* and returns 0
|
||||
*/
|
||||
u32 tipc_nametbl_translate(u32 type, u32 instance, u32 *destnode)
|
||||
{
|
||||
struct sub_seq *sseq;
|
||||
struct name_info *info;
|
||||
struct publication *publ;
|
||||
struct name_seq *seq;
|
||||
u32 ref = 0;
|
||||
u32 node = 0;
|
||||
|
||||
if (!tipc_in_scope(*destnode, tipc_own_addr))
|
||||
return 0;
|
||||
|
||||
read_lock_bh(&tipc_nametbl_lock);
|
||||
seq = nametbl_find_seq(type);
|
||||
if (unlikely(!seq))
|
||||
goto not_found;
|
||||
sseq = nameseq_find_subseq(seq, instance);
|
||||
if (unlikely(!sseq))
|
||||
goto not_found;
|
||||
spin_lock_bh(&seq->lock);
|
||||
info = sseq->info;
|
||||
|
||||
/* Closest-First Algorithm */
|
||||
if (likely(!*destnode)) {
|
||||
if (!list_empty(&info->node_list)) {
|
||||
publ = list_first_entry(&info->node_list,
|
||||
struct publication,
|
||||
node_list);
|
||||
list_move_tail(&publ->node_list,
|
||||
&info->node_list);
|
||||
} else if (!list_empty(&info->cluster_list)) {
|
||||
publ = list_first_entry(&info->cluster_list,
|
||||
struct publication,
|
||||
cluster_list);
|
||||
list_move_tail(&publ->cluster_list,
|
||||
&info->cluster_list);
|
||||
} else {
|
||||
publ = list_first_entry(&info->zone_list,
|
||||
struct publication,
|
||||
zone_list);
|
||||
list_move_tail(&publ->zone_list,
|
||||
&info->zone_list);
|
||||
}
|
||||
}
|
||||
|
||||
/* Round-Robin Algorithm */
|
||||
else if (*destnode == tipc_own_addr) {
|
||||
if (list_empty(&info->node_list))
|
||||
goto no_match;
|
||||
publ = list_first_entry(&info->node_list, struct publication,
|
||||
node_list);
|
||||
list_move_tail(&publ->node_list, &info->node_list);
|
||||
} else if (in_own_cluster_exact(*destnode)) {
|
||||
if (list_empty(&info->cluster_list))
|
||||
goto no_match;
|
||||
publ = list_first_entry(&info->cluster_list, struct publication,
|
||||
cluster_list);
|
||||
list_move_tail(&publ->cluster_list, &info->cluster_list);
|
||||
} else {
|
||||
publ = list_first_entry(&info->zone_list, struct publication,
|
||||
zone_list);
|
||||
list_move_tail(&publ->zone_list, &info->zone_list);
|
||||
}
|
||||
|
||||
ref = publ->ref;
|
||||
node = publ->node;
|
||||
no_match:
|
||||
spin_unlock_bh(&seq->lock);
|
||||
not_found:
|
||||
read_unlock_bh(&tipc_nametbl_lock);
|
||||
*destnode = node;
|
||||
return ref;
|
||||
}
|
||||
|
||||
/**
|
||||
* tipc_nametbl_mc_translate - find multicast destinations
|
||||
*
|
||||
* Creates list of all local ports that overlap the given multicast address;
|
||||
* also determines if any off-node ports overlap.
|
||||
*
|
||||
* Note: Publications with a scope narrower than 'limit' are ignored.
|
||||
* (i.e. local node-scope publications mustn't receive messages arriving
|
||||
* from another node, even if the multcast link brought it here)
|
||||
*
|
||||
* Returns non-zero if any off-node ports overlap
|
||||
*/
|
||||
int tipc_nametbl_mc_translate(u32 type, u32 lower, u32 upper, u32 limit,
|
||||
struct tipc_port_list *dports)
|
||||
{
|
||||
struct name_seq *seq;
|
||||
struct sub_seq *sseq;
|
||||
struct sub_seq *sseq_stop;
|
||||
struct name_info *info;
|
||||
int res = 0;
|
||||
|
||||
read_lock_bh(&tipc_nametbl_lock);
|
||||
seq = nametbl_find_seq(type);
|
||||
if (!seq)
|
||||
goto exit;
|
||||
|
||||
spin_lock_bh(&seq->lock);
|
||||
|
||||
sseq = seq->sseqs + nameseq_locate_subseq(seq, lower);
|
||||
sseq_stop = seq->sseqs + seq->first_free;
|
||||
for (; sseq != sseq_stop; sseq++) {
|
||||
struct publication *publ;
|
||||
|
||||
if (sseq->lower > upper)
|
||||
break;
|
||||
|
||||
info = sseq->info;
|
||||
list_for_each_entry(publ, &info->node_list, node_list) {
|
||||
if (publ->scope <= limit)
|
||||
tipc_port_list_add(dports, publ->ref);
|
||||
}
|
||||
|
||||
if (info->cluster_list_size != info->node_list_size)
|
||||
res = 1;
|
||||
}
|
||||
|
||||
spin_unlock_bh(&seq->lock);
|
||||
exit:
|
||||
read_unlock_bh(&tipc_nametbl_lock);
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
* tipc_nametbl_publish - add name publication to network name tables
|
||||
*/
|
||||
struct publication *tipc_nametbl_publish(u32 type, u32 lower, u32 upper,
|
||||
u32 scope, u32 port_ref, u32 key)
|
||||
{
|
||||
struct publication *publ;
|
||||
struct sk_buff *buf = NULL;
|
||||
|
||||
if (table.local_publ_count >= TIPC_MAX_PUBLICATIONS) {
|
||||
pr_warn("Publication failed, local publication limit reached (%u)\n",
|
||||
TIPC_MAX_PUBLICATIONS);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
write_lock_bh(&tipc_nametbl_lock);
|
||||
publ = tipc_nametbl_insert_publ(type, lower, upper, scope,
|
||||
tipc_own_addr, port_ref, key);
|
||||
if (likely(publ)) {
|
||||
table.local_publ_count++;
|
||||
buf = tipc_named_publish(publ);
|
||||
/* Any pending external events? */
|
||||
tipc_named_process_backlog();
|
||||
}
|
||||
write_unlock_bh(&tipc_nametbl_lock);
|
||||
|
||||
if (buf)
|
||||
named_cluster_distribute(buf);
|
||||
return publ;
|
||||
}
|
||||
|
||||
/**
|
||||
* tipc_nametbl_withdraw - withdraw name publication from network name tables
|
||||
*/
|
||||
int tipc_nametbl_withdraw(u32 type, u32 lower, u32 ref, u32 key)
|
||||
{
|
||||
struct publication *publ;
|
||||
struct sk_buff *buf;
|
||||
|
||||
write_lock_bh(&tipc_nametbl_lock);
|
||||
publ = tipc_nametbl_remove_publ(type, lower, tipc_own_addr, ref, key);
|
||||
if (likely(publ)) {
|
||||
table.local_publ_count--;
|
||||
buf = tipc_named_withdraw(publ);
|
||||
/* Any pending external events? */
|
||||
tipc_named_process_backlog();
|
||||
write_unlock_bh(&tipc_nametbl_lock);
|
||||
list_del_init(&publ->pport_list);
|
||||
kfree(publ);
|
||||
|
||||
if (buf)
|
||||
named_cluster_distribute(buf);
|
||||
return 1;
|
||||
}
|
||||
write_unlock_bh(&tipc_nametbl_lock);
|
||||
pr_err("Unable to remove local publication\n"
|
||||
"(type=%u, lower=%u, ref=%u, key=%u)\n",
|
||||
type, lower, ref, key);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* tipc_nametbl_subscribe - add a subscription object to the name table
|
||||
*/
|
||||
void tipc_nametbl_subscribe(struct tipc_subscription *s)
|
||||
{
|
||||
u32 type = s->seq.type;
|
||||
struct name_seq *seq;
|
||||
|
||||
write_lock_bh(&tipc_nametbl_lock);
|
||||
seq = nametbl_find_seq(type);
|
||||
if (!seq)
|
||||
seq = tipc_nameseq_create(type, &table.types[hash(type)]);
|
||||
if (seq) {
|
||||
spin_lock_bh(&seq->lock);
|
||||
tipc_nameseq_subscribe(seq, s);
|
||||
spin_unlock_bh(&seq->lock);
|
||||
} else {
|
||||
pr_warn("Failed to create subscription for {%u,%u,%u}\n",
|
||||
s->seq.type, s->seq.lower, s->seq.upper);
|
||||
}
|
||||
write_unlock_bh(&tipc_nametbl_lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* tipc_nametbl_unsubscribe - remove a subscription object from name table
|
||||
*/
|
||||
void tipc_nametbl_unsubscribe(struct tipc_subscription *s)
|
||||
{
|
||||
struct name_seq *seq;
|
||||
|
||||
write_lock_bh(&tipc_nametbl_lock);
|
||||
seq = nametbl_find_seq(s->seq.type);
|
||||
if (seq != NULL) {
|
||||
spin_lock_bh(&seq->lock);
|
||||
list_del_init(&s->nameseq_list);
|
||||
spin_unlock_bh(&seq->lock);
|
||||
nameseq_delete_empty(seq);
|
||||
}
|
||||
write_unlock_bh(&tipc_nametbl_lock);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* subseq_list - print specified sub-sequence contents into the given buffer
|
||||
*/
|
||||
static int subseq_list(struct sub_seq *sseq, char *buf, int len, u32 depth,
|
||||
u32 index)
|
||||
{
|
||||
char portIdStr[27];
|
||||
const char *scope_str[] = {"", " zone", " cluster", " node"};
|
||||
struct publication *publ;
|
||||
struct name_info *info;
|
||||
int ret;
|
||||
|
||||
ret = tipc_snprintf(buf, len, "%-10u %-10u ", sseq->lower, sseq->upper);
|
||||
|
||||
if (depth == 2) {
|
||||
ret += tipc_snprintf(buf - ret, len + ret, "\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
info = sseq->info;
|
||||
|
||||
list_for_each_entry(publ, &info->zone_list, zone_list) {
|
||||
sprintf(portIdStr, "<%u.%u.%u:%u>",
|
||||
tipc_zone(publ->node), tipc_cluster(publ->node),
|
||||
tipc_node(publ->node), publ->ref);
|
||||
ret += tipc_snprintf(buf + ret, len - ret, "%-26s ", portIdStr);
|
||||
if (depth > 3) {
|
||||
ret += tipc_snprintf(buf + ret, len - ret, "%-10u %s",
|
||||
publ->key, scope_str[publ->scope]);
|
||||
}
|
||||
if (!list_is_last(&publ->zone_list, &info->zone_list))
|
||||
ret += tipc_snprintf(buf + ret, len - ret,
|
||||
"\n%33s", " ");
|
||||
}
|
||||
|
||||
ret += tipc_snprintf(buf + ret, len - ret, "\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* nameseq_list - print specified name sequence contents into the given buffer
|
||||
*/
|
||||
static int nameseq_list(struct name_seq *seq, char *buf, int len, u32 depth,
|
||||
u32 type, u32 lowbound, u32 upbound, u32 index)
|
||||
{
|
||||
struct sub_seq *sseq;
|
||||
char typearea[11];
|
||||
int ret = 0;
|
||||
|
||||
if (seq->first_free == 0)
|
||||
return 0;
|
||||
|
||||
sprintf(typearea, "%-10u", seq->type);
|
||||
|
||||
if (depth == 1) {
|
||||
ret += tipc_snprintf(buf, len, "%s\n", typearea);
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (sseq = seq->sseqs; sseq != &seq->sseqs[seq->first_free]; sseq++) {
|
||||
if ((lowbound <= sseq->upper) && (upbound >= sseq->lower)) {
|
||||
ret += tipc_snprintf(buf + ret, len - ret, "%s ",
|
||||
typearea);
|
||||
spin_lock_bh(&seq->lock);
|
||||
ret += subseq_list(sseq, buf + ret, len - ret,
|
||||
depth, index);
|
||||
spin_unlock_bh(&seq->lock);
|
||||
sprintf(typearea, "%10s", " ");
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* nametbl_header - print name table header into the given buffer
|
||||
*/
|
||||
static int nametbl_header(char *buf, int len, u32 depth)
|
||||
{
|
||||
const char *header[] = {
|
||||
"Type ",
|
||||
"Lower Upper ",
|
||||
"Port Identity ",
|
||||
"Publication Scope"
|
||||
};
|
||||
|
||||
int i;
|
||||
int ret = 0;
|
||||
|
||||
if (depth > 4)
|
||||
depth = 4;
|
||||
for (i = 0; i < depth; i++)
|
||||
ret += tipc_snprintf(buf + ret, len - ret, header[i]);
|
||||
ret += tipc_snprintf(buf + ret, len - ret, "\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* nametbl_list - print specified name table contents into the given buffer
|
||||
*/
|
||||
static int nametbl_list(char *buf, int len, u32 depth_info,
|
||||
u32 type, u32 lowbound, u32 upbound)
|
||||
{
|
||||
struct hlist_head *seq_head;
|
||||
struct name_seq *seq;
|
||||
int all_types;
|
||||
int ret = 0;
|
||||
u32 depth;
|
||||
u32 i;
|
||||
|
||||
all_types = (depth_info & TIPC_NTQ_ALLTYPES);
|
||||
depth = (depth_info & ~TIPC_NTQ_ALLTYPES);
|
||||
|
||||
if (depth == 0)
|
||||
return 0;
|
||||
|
||||
if (all_types) {
|
||||
/* display all entries in name table to specified depth */
|
||||
ret += nametbl_header(buf, len, depth);
|
||||
lowbound = 0;
|
||||
upbound = ~0;
|
||||
for (i = 0; i < TIPC_NAMETBL_SIZE; i++) {
|
||||
seq_head = &table.types[i];
|
||||
hlist_for_each_entry(seq, seq_head, ns_list) {
|
||||
ret += nameseq_list(seq, buf + ret, len - ret,
|
||||
depth, seq->type,
|
||||
lowbound, upbound, i);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* display only the sequence that matches the specified type */
|
||||
if (upbound < lowbound) {
|
||||
ret += tipc_snprintf(buf + ret, len - ret,
|
||||
"invalid name sequence specified\n");
|
||||
return ret;
|
||||
}
|
||||
ret += nametbl_header(buf + ret, len - ret, depth);
|
||||
i = hash(type);
|
||||
seq_head = &table.types[i];
|
||||
hlist_for_each_entry(seq, seq_head, ns_list) {
|
||||
if (seq->type == type) {
|
||||
ret += nameseq_list(seq, buf + ret, len - ret,
|
||||
depth, type,
|
||||
lowbound, upbound, i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct sk_buff *tipc_nametbl_get(const void *req_tlv_area, int req_tlv_space)
|
||||
{
|
||||
struct sk_buff *buf;
|
||||
struct tipc_name_table_query *argv;
|
||||
struct tlv_desc *rep_tlv;
|
||||
char *pb;
|
||||
int pb_len;
|
||||
int str_len;
|
||||
|
||||
if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_NAME_TBL_QUERY))
|
||||
return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
|
||||
|
||||
buf = tipc_cfg_reply_alloc(TLV_SPACE(ULTRA_STRING_MAX_LEN));
|
||||
if (!buf)
|
||||
return NULL;
|
||||
|
||||
rep_tlv = (struct tlv_desc *)buf->data;
|
||||
pb = TLV_DATA(rep_tlv);
|
||||
pb_len = ULTRA_STRING_MAX_LEN;
|
||||
argv = (struct tipc_name_table_query *)TLV_DATA(req_tlv_area);
|
||||
read_lock_bh(&tipc_nametbl_lock);
|
||||
str_len = nametbl_list(pb, pb_len, ntohl(argv->depth),
|
||||
ntohl(argv->type),
|
||||
ntohl(argv->lowbound), ntohl(argv->upbound));
|
||||
read_unlock_bh(&tipc_nametbl_lock);
|
||||
str_len += 1; /* for "\0" */
|
||||
skb_put(buf, TLV_SPACE(str_len));
|
||||
TLV_SET(rep_tlv, TIPC_TLV_ULTRA_STRING, NULL, str_len);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
int tipc_nametbl_init(void)
|
||||
{
|
||||
table.types = kcalloc(TIPC_NAMETBL_SIZE, sizeof(struct hlist_head),
|
||||
GFP_ATOMIC);
|
||||
if (!table.types)
|
||||
return -ENOMEM;
|
||||
|
||||
table.local_publ_count = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* tipc_purge_publications - remove all publications for a given type
|
||||
*
|
||||
* tipc_nametbl_lock must be held when calling this function
|
||||
*/
|
||||
static void tipc_purge_publications(struct name_seq *seq)
|
||||
{
|
||||
struct publication *publ, *safe;
|
||||
struct sub_seq *sseq;
|
||||
struct name_info *info;
|
||||
|
||||
if (!seq->sseqs) {
|
||||
nameseq_delete_empty(seq);
|
||||
return;
|
||||
}
|
||||
sseq = seq->sseqs;
|
||||
info = sseq->info;
|
||||
list_for_each_entry_safe(publ, safe, &info->zone_list, zone_list) {
|
||||
tipc_nametbl_remove_publ(publ->type, publ->lower, publ->node,
|
||||
publ->ref, publ->key);
|
||||
kfree(publ);
|
||||
}
|
||||
}
|
||||
|
||||
void tipc_nametbl_stop(void)
|
||||
{
|
||||
u32 i;
|
||||
struct name_seq *seq;
|
||||
struct hlist_head *seq_head;
|
||||
struct hlist_node *safe;
|
||||
|
||||
/* Verify name table is empty and purge any lingering
|
||||
* publications, then release the name table
|
||||
*/
|
||||
write_lock_bh(&tipc_nametbl_lock);
|
||||
for (i = 0; i < TIPC_NAMETBL_SIZE; i++) {
|
||||
if (hlist_empty(&table.types[i]))
|
||||
continue;
|
||||
seq_head = &table.types[i];
|
||||
hlist_for_each_entry_safe(seq, safe, seq_head, ns_list) {
|
||||
tipc_purge_publications(seq);
|
||||
}
|
||||
}
|
||||
kfree(table.types);
|
||||
table.types = NULL;
|
||||
write_unlock_bh(&tipc_nametbl_lock);
|
||||
}
|
104
net/tipc/name_table.h
Normal file
104
net/tipc/name_table.h
Normal file
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
* net/tipc/name_table.h: Include file for TIPC name table code
|
||||
*
|
||||
* Copyright (c) 2000-2006, Ericsson AB
|
||||
* Copyright (c) 2004-2005, 2010-2011, 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 tipc_subscription;
|
||||
struct tipc_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: adjacent matching name seq publications with >= node scope
|
||||
* @cluster_list: adjacent matching name seq publications with >= cluster scope
|
||||
* @zone_list: adjacent matching name seq publications 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 list_head node_list;
|
||||
struct list_head cluster_list;
|
||||
struct list_head zone_list;
|
||||
};
|
||||
|
||||
|
||||
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 tipc_port_list *dports);
|
||||
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 tipc_subscription *s);
|
||||
void tipc_nametbl_unsubscribe(struct tipc_subscription *s);
|
||||
int tipc_nametbl_init(void);
|
||||
void tipc_nametbl_stop(void);
|
||||
|
||||
#endif
|
140
net/tipc/net.c
Normal file
140
net/tipc/net.c
Normal file
|
@ -0,0 +1,140 @@
|
|||
/*
|
||||
* net/tipc/net.c: TIPC network routing code
|
||||
*
|
||||
* Copyright (c) 1995-2006, 2014, Ericsson AB
|
||||
* Copyright (c) 2005, 2010-2011, 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 "net.h"
|
||||
#include "name_distr.h"
|
||||
#include "subscr.h"
|
||||
#include "socket.h"
|
||||
#include "node.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 four major
|
||||
* locking domains, each protected with their own disjunct set of locks.
|
||||
*
|
||||
* 1: The bearer level.
|
||||
* RTNL lock is used to serialize the process of configuring bearer
|
||||
* on update side, and RCU lock is applied on read side to make
|
||||
* bearer instance valid on both paths of message transmission and
|
||||
* reception.
|
||||
*
|
||||
* 2: The node and link level.
|
||||
* All node instances are saved into two tipc_node_list and node_htable
|
||||
* lists. The two lists are protected by node_list_lock on write side,
|
||||
* and they are guarded with RCU lock on read side. Especially node
|
||||
* instance is destroyed only when TIPC module is removed, and we can
|
||||
* confirm that there has no any user who is accessing the node at the
|
||||
* moment. Therefore, Except for iterating the two lists within RCU
|
||||
* protection, it's no needed to hold RCU that we access node instance
|
||||
* in other places.
|
||||
*
|
||||
* In addition, all members in node structure including link instances
|
||||
* are protected by node spin lock.
|
||||
*
|
||||
* 3: 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.
|
||||
*
|
||||
* 4: 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.
|
||||
*/
|
||||
|
||||
int tipc_net_start(u32 addr)
|
||||
{
|
||||
char addr_string[16];
|
||||
int res;
|
||||
|
||||
tipc_own_addr = addr;
|
||||
tipc_named_reinit();
|
||||
tipc_sk_reinit();
|
||||
res = tipc_bclink_init();
|
||||
if (res)
|
||||
return res;
|
||||
|
||||
tipc_nametbl_publish(TIPC_CFG_SRV, tipc_own_addr, tipc_own_addr,
|
||||
TIPC_ZONE_SCOPE, 0, tipc_own_addr);
|
||||
|
||||
pr_info("Started in network mode\n");
|
||||
pr_info("Own node address %s, network identity %u\n",
|
||||
tipc_addr_string_fill(addr_string, tipc_own_addr), tipc_net_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void tipc_net_stop(void)
|
||||
{
|
||||
if (!tipc_own_addr)
|
||||
return;
|
||||
|
||||
tipc_nametbl_withdraw(TIPC_CFG_SRV, tipc_own_addr, 0, tipc_own_addr);
|
||||
rtnl_lock();
|
||||
tipc_bearer_stop();
|
||||
tipc_bclink_stop();
|
||||
tipc_node_stop();
|
||||
rtnl_unlock();
|
||||
|
||||
pr_info("Left network mode\n");
|
||||
}
|
43
net/tipc/net.h
Normal file
43
net/tipc/net.h
Normal file
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* net/tipc/net.h: Include file for TIPC network routing code
|
||||
*
|
||||
* Copyright (c) 1995-2006, Ericsson AB
|
||||
* Copyright (c) 2005, 2010-2011, 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
|
||||
|
||||
int tipc_net_start(u32 addr);
|
||||
void tipc_net_stop(void);
|
||||
|
||||
#endif
|
101
net/tipc/netlink.c
Normal file
101
net/tipc/netlink.c
Normal file
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
* 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_total_size(GENL_HDRLEN + TIPC_GENL_HDRLEN);
|
||||
u16 cmd;
|
||||
|
||||
if ((req_userhdr->cmd & 0xC000) && (!netlink_capable(skb, 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_attrlen(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).portid);
|
||||
}
|
||||
|
||||
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,
|
||||
},
|
||||
};
|
||||
|
||||
int tipc_netlink_start(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = genl_register_family_with_ops(&tipc_genl_family, tipc_genl_ops);
|
||||
if (res) {
|
||||
pr_err("Failed to register netlink interface\n");
|
||||
return res;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void tipc_netlink_stop(void)
|
||||
{
|
||||
genl_unregister_family(&tipc_genl_family);
|
||||
}
|
603
net/tipc/node.c
Normal file
603
net/tipc/node.c
Normal file
|
@ -0,0 +1,603 @@
|
|||
/*
|
||||
* net/tipc/node.c: TIPC node management routines
|
||||
*
|
||||
* Copyright (c) 2000-2006, 2012-2014, Ericsson AB
|
||||
* Copyright (c) 2005-2006, 2010-2014, 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 "name_distr.h"
|
||||
#include "socket.h"
|
||||
|
||||
#define NODE_HTABLE_SIZE 512
|
||||
|
||||
static void node_lost_contact(struct tipc_node *n_ptr);
|
||||
static void node_established_contact(struct tipc_node *n_ptr);
|
||||
|
||||
static struct hlist_head node_htable[NODE_HTABLE_SIZE];
|
||||
LIST_HEAD(tipc_node_list);
|
||||
static u32 tipc_num_nodes;
|
||||
static u32 tipc_num_links;
|
||||
static DEFINE_SPINLOCK(node_list_lock);
|
||||
|
||||
struct tipc_sock_conn {
|
||||
u32 port;
|
||||
u32 peer_port;
|
||||
u32 peer_node;
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
/*
|
||||
* A trivial power-of-two bitmask technique is used for speed, since this
|
||||
* operation is done for every incoming TIPC packet. The number of hash table
|
||||
* entries has been chosen so that no hash chain exceeds 8 nodes and will
|
||||
* usually be much smaller (typically only a single node).
|
||||
*/
|
||||
static unsigned int tipc_hashfn(u32 addr)
|
||||
{
|
||||
return addr & (NODE_HTABLE_SIZE - 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* tipc_node_find - locate specified node object, if it exists
|
||||
*/
|
||||
struct tipc_node *tipc_node_find(u32 addr)
|
||||
{
|
||||
struct tipc_node *node;
|
||||
|
||||
if (unlikely(!in_own_cluster_exact(addr)))
|
||||
return NULL;
|
||||
|
||||
rcu_read_lock();
|
||||
hlist_for_each_entry_rcu(node, &node_htable[tipc_hashfn(addr)], hash) {
|
||||
if (node->addr == addr) {
|
||||
rcu_read_unlock();
|
||||
return node;
|
||||
}
|
||||
}
|
||||
rcu_read_unlock();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct tipc_node *tipc_node_create(u32 addr)
|
||||
{
|
||||
struct tipc_node *n_ptr, *temp_node;
|
||||
|
||||
spin_lock_bh(&node_list_lock);
|
||||
|
||||
n_ptr = kzalloc(sizeof(*n_ptr), GFP_ATOMIC);
|
||||
if (!n_ptr) {
|
||||
spin_unlock_bh(&node_list_lock);
|
||||
pr_warn("Node creation failed, no memory\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
n_ptr->addr = addr;
|
||||
spin_lock_init(&n_ptr->lock);
|
||||
INIT_HLIST_NODE(&n_ptr->hash);
|
||||
INIT_LIST_HEAD(&n_ptr->list);
|
||||
INIT_LIST_HEAD(&n_ptr->nsub);
|
||||
INIT_LIST_HEAD(&n_ptr->conn_sks);
|
||||
__skb_queue_head_init(&n_ptr->waiting_sks);
|
||||
|
||||
hlist_add_head_rcu(&n_ptr->hash, &node_htable[tipc_hashfn(addr)]);
|
||||
|
||||
list_for_each_entry_rcu(temp_node, &tipc_node_list, list) {
|
||||
if (n_ptr->addr < temp_node->addr)
|
||||
break;
|
||||
}
|
||||
list_add_tail_rcu(&n_ptr->list, &temp_node->list);
|
||||
n_ptr->action_flags = TIPC_WAIT_PEER_LINKS_DOWN;
|
||||
n_ptr->signature = INVALID_NODE_SIG;
|
||||
|
||||
tipc_num_nodes++;
|
||||
|
||||
spin_unlock_bh(&node_list_lock);
|
||||
return n_ptr;
|
||||
}
|
||||
|
||||
static void tipc_node_delete(struct tipc_node *n_ptr)
|
||||
{
|
||||
list_del_rcu(&n_ptr->list);
|
||||
hlist_del_rcu(&n_ptr->hash);
|
||||
kfree_rcu(n_ptr, rcu);
|
||||
|
||||
tipc_num_nodes--;
|
||||
}
|
||||
|
||||
void tipc_node_stop(void)
|
||||
{
|
||||
struct tipc_node *node, *t_node;
|
||||
|
||||
spin_lock_bh(&node_list_lock);
|
||||
list_for_each_entry_safe(node, t_node, &tipc_node_list, list)
|
||||
tipc_node_delete(node);
|
||||
spin_unlock_bh(&node_list_lock);
|
||||
}
|
||||
|
||||
int tipc_node_add_conn(u32 dnode, u32 port, u32 peer_port)
|
||||
{
|
||||
struct tipc_node *node;
|
||||
struct tipc_sock_conn *conn;
|
||||
|
||||
if (in_own_node(dnode))
|
||||
return 0;
|
||||
|
||||
node = tipc_node_find(dnode);
|
||||
if (!node) {
|
||||
pr_warn("Connecting sock to node 0x%x failed\n", dnode);
|
||||
return -EHOSTUNREACH;
|
||||
}
|
||||
conn = kmalloc(sizeof(*conn), GFP_ATOMIC);
|
||||
if (!conn)
|
||||
return -EHOSTUNREACH;
|
||||
conn->peer_node = dnode;
|
||||
conn->port = port;
|
||||
conn->peer_port = peer_port;
|
||||
|
||||
tipc_node_lock(node);
|
||||
list_add_tail(&conn->list, &node->conn_sks);
|
||||
tipc_node_unlock(node);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void tipc_node_remove_conn(u32 dnode, u32 port)
|
||||
{
|
||||
struct tipc_node *node;
|
||||
struct tipc_sock_conn *conn, *safe;
|
||||
|
||||
if (in_own_node(dnode))
|
||||
return;
|
||||
|
||||
node = tipc_node_find(dnode);
|
||||
if (!node)
|
||||
return;
|
||||
|
||||
tipc_node_lock(node);
|
||||
list_for_each_entry_safe(conn, safe, &node->conn_sks, list) {
|
||||
if (port != conn->port)
|
||||
continue;
|
||||
list_del(&conn->list);
|
||||
kfree(conn);
|
||||
}
|
||||
tipc_node_unlock(node);
|
||||
}
|
||||
|
||||
void tipc_node_abort_sock_conns(struct list_head *conns)
|
||||
{
|
||||
struct tipc_sock_conn *conn, *safe;
|
||||
struct sk_buff *buf;
|
||||
|
||||
list_for_each_entry_safe(conn, safe, conns, list) {
|
||||
buf = tipc_msg_create(TIPC_CRITICAL_IMPORTANCE, TIPC_CONN_MSG,
|
||||
SHORT_H_SIZE, 0, tipc_own_addr,
|
||||
conn->peer_node, conn->port,
|
||||
conn->peer_port, TIPC_ERR_NO_NODE);
|
||||
if (likely(buf))
|
||||
tipc_sk_rcv(buf);
|
||||
list_del(&conn->list);
|
||||
kfree(conn);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 tipc_link *l_ptr)
|
||||
{
|
||||
struct tipc_link **active = &n_ptr->active_links[0];
|
||||
|
||||
n_ptr->working_links++;
|
||||
n_ptr->action_flags |= TIPC_NOTIFY_LINK_UP;
|
||||
n_ptr->link_id = l_ptr->peer_bearer_id << 16 | l_ptr->bearer_id;
|
||||
|
||||
pr_info("Established link <%s> on network plane %c\n",
|
||||
l_ptr->name, l_ptr->net_plane);
|
||||
|
||||
if (!active[0]) {
|
||||
active[0] = active[1] = l_ptr;
|
||||
node_established_contact(n_ptr);
|
||||
goto exit;
|
||||
}
|
||||
if (l_ptr->priority < active[0]->priority) {
|
||||
pr_info("New link <%s> becomes standby\n", l_ptr->name);
|
||||
goto exit;
|
||||
}
|
||||
tipc_link_dup_queue_xmit(active[0], l_ptr);
|
||||
if (l_ptr->priority == active[0]->priority) {
|
||||
active[0] = l_ptr;
|
||||
goto exit;
|
||||
}
|
||||
pr_info("Old link <%s> becomes standby\n", active[0]->name);
|
||||
if (active[1] != active[0])
|
||||
pr_info("Old link <%s> becomes standby\n", active[1]->name);
|
||||
active[0] = active[1] = l_ptr;
|
||||
exit:
|
||||
/* Leave room for changeover header when returning 'mtu' to users: */
|
||||
n_ptr->act_mtus[0] = active[0]->max_pkt - INT_H_SIZE;
|
||||
n_ptr->act_mtus[1] = active[1]->max_pkt - INT_H_SIZE;
|
||||
}
|
||||
|
||||
/**
|
||||
* node_select_active_links - select active link
|
||||
*/
|
||||
static void node_select_active_links(struct tipc_node *n_ptr)
|
||||
{
|
||||
struct tipc_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 tipc_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 tipc_link *l_ptr)
|
||||
{
|
||||
struct tipc_link **active;
|
||||
|
||||
n_ptr->working_links--;
|
||||
n_ptr->action_flags |= TIPC_NOTIFY_LINK_DOWN;
|
||||
n_ptr->link_id = l_ptr->peer_bearer_id << 16 | l_ptr->bearer_id;
|
||||
|
||||
if (!tipc_link_is_active(l_ptr)) {
|
||||
pr_info("Lost standby link <%s> on network plane %c\n",
|
||||
l_ptr->name, l_ptr->net_plane);
|
||||
return;
|
||||
}
|
||||
pr_info("Lost link <%s> on network plane %c\n",
|
||||
l_ptr->name, l_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_failover_send_queue(l_ptr);
|
||||
else
|
||||
node_lost_contact(n_ptr);
|
||||
|
||||
/* Leave room for changeover header when returning 'mtu' to users: */
|
||||
if (active[0]) {
|
||||
n_ptr->act_mtus[0] = active[0]->max_pkt - INT_H_SIZE;
|
||||
n_ptr->act_mtus[1] = active[1]->max_pkt - INT_H_SIZE;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Loopback link went down? No fragmentation needed from now on. */
|
||||
if (n_ptr->addr == tipc_own_addr) {
|
||||
n_ptr->act_mtus[0] = MAX_MSG_SIZE;
|
||||
n_ptr->act_mtus[1] = MAX_MSG_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
int tipc_node_active_links(struct tipc_node *n_ptr)
|
||||
{
|
||||
return n_ptr->active_links[0] != NULL;
|
||||
}
|
||||
|
||||
int tipc_node_is_up(struct tipc_node *n_ptr)
|
||||
{
|
||||
return tipc_node_active_links(n_ptr);
|
||||
}
|
||||
|
||||
void tipc_node_attach_link(struct tipc_node *n_ptr, struct tipc_link *l_ptr)
|
||||
{
|
||||
n_ptr->links[l_ptr->bearer_id] = l_ptr;
|
||||
spin_lock_bh(&node_list_lock);
|
||||
tipc_num_links++;
|
||||
spin_unlock_bh(&node_list_lock);
|
||||
n_ptr->link_cnt++;
|
||||
}
|
||||
|
||||
void tipc_node_detach_link(struct tipc_node *n_ptr, struct tipc_link *l_ptr)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_BEARERS; i++) {
|
||||
if (l_ptr != n_ptr->links[i])
|
||||
continue;
|
||||
n_ptr->links[i] = NULL;
|
||||
spin_lock_bh(&node_list_lock);
|
||||
tipc_num_links--;
|
||||
spin_unlock_bh(&node_list_lock);
|
||||
n_ptr->link_cnt--;
|
||||
}
|
||||
}
|
||||
|
||||
static void node_established_contact(struct tipc_node *n_ptr)
|
||||
{
|
||||
n_ptr->action_flags |= TIPC_NOTIFY_NODE_UP;
|
||||
n_ptr->bclink.oos_state = 0;
|
||||
n_ptr->bclink.acked = tipc_bclink_get_last_sent();
|
||||
tipc_bclink_add_node(n_ptr->addr);
|
||||
}
|
||||
|
||||
static void node_lost_contact(struct tipc_node *n_ptr)
|
||||
{
|
||||
char addr_string[16];
|
||||
u32 i;
|
||||
|
||||
pr_info("Lost contact with %s\n",
|
||||
tipc_addr_string_fill(addr_string, n_ptr->addr));
|
||||
|
||||
/* Flush broadcast link info associated with lost node */
|
||||
if (n_ptr->bclink.recv_permitted) {
|
||||
kfree_skb_list(n_ptr->bclink.deferred_head);
|
||||
n_ptr->bclink.deferred_size = 0;
|
||||
|
||||
if (n_ptr->bclink.reasm_buf) {
|
||||
kfree_skb(n_ptr->bclink.reasm_buf);
|
||||
n_ptr->bclink.reasm_buf = NULL;
|
||||
}
|
||||
|
||||
tipc_bclink_remove_node(n_ptr->addr);
|
||||
tipc_bclink_acknowledge(n_ptr, INVALID_LINK_SEQ);
|
||||
|
||||
n_ptr->bclink.recv_permitted = false;
|
||||
}
|
||||
|
||||
/* Abort link changeover */
|
||||
for (i = 0; i < MAX_BEARERS; i++) {
|
||||
struct tipc_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);
|
||||
}
|
||||
|
||||
n_ptr->action_flags &= ~TIPC_WAIT_OWN_LINKS_DOWN;
|
||||
|
||||
/* Notify subscribers and prevent re-contact with node until
|
||||
* cleanup is done.
|
||||
*/
|
||||
n_ptr->action_flags |= TIPC_WAIT_PEER_LINKS_DOWN |
|
||||
TIPC_NOTIFY_NODE_DOWN;
|
||||
}
|
||||
|
||||
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)");
|
||||
|
||||
spin_lock_bh(&node_list_lock);
|
||||
if (!tipc_num_nodes) {
|
||||
spin_unlock_bh(&node_list_lock);
|
||||
return tipc_cfg_reply_none();
|
||||
}
|
||||
|
||||
/* For now, get space for all other nodes */
|
||||
payload_size = TLV_SPACE(sizeof(node_info)) * tipc_num_nodes;
|
||||
if (payload_size > 32768u) {
|
||||
spin_unlock_bh(&node_list_lock);
|
||||
return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
|
||||
" (too many nodes)");
|
||||
}
|
||||
spin_unlock_bh(&node_list_lock);
|
||||
|
||||
buf = tipc_cfg_reply_alloc(payload_size);
|
||||
if (!buf)
|
||||
return NULL;
|
||||
|
||||
/* Add TLVs for all nodes in scope */
|
||||
rcu_read_lock();
|
||||
list_for_each_entry_rcu(n_ptr, &tipc_node_list, list) {
|
||||
if (!tipc_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));
|
||||
}
|
||||
rcu_read_unlock();
|
||||
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_own_addr)
|
||||
return tipc_cfg_reply_none();
|
||||
|
||||
spin_lock_bh(&node_list_lock);
|
||||
/* Get space for all unicast links + broadcast link */
|
||||
payload_size = TLV_SPACE((sizeof(link_info)) * (tipc_num_links + 1));
|
||||
if (payload_size > 32768u) {
|
||||
spin_unlock_bh(&node_list_lock);
|
||||
return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
|
||||
" (too many links)");
|
||||
}
|
||||
spin_unlock_bh(&node_list_lock);
|
||||
|
||||
buf = tipc_cfg_reply_alloc(payload_size);
|
||||
if (!buf)
|
||||
return NULL;
|
||||
|
||||
/* Add TLV for broadcast link */
|
||||
link_info.dest = htonl(tipc_cluster_mask(tipc_own_addr));
|
||||
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 */
|
||||
rcu_read_lock();
|
||||
list_for_each_entry_rcu(n_ptr, &tipc_node_list, list) {
|
||||
u32 i;
|
||||
|
||||
if (!tipc_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);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
return buf;
|
||||
}
|
||||
|
||||
/**
|
||||
* tipc_node_get_linkname - get the name of a link
|
||||
*
|
||||
* @bearer_id: id of the bearer
|
||||
* @node: peer node address
|
||||
* @linkname: link name output buffer
|
||||
*
|
||||
* Returns 0 on success
|
||||
*/
|
||||
int tipc_node_get_linkname(u32 bearer_id, u32 addr, char *linkname, size_t len)
|
||||
{
|
||||
struct tipc_link *link;
|
||||
struct tipc_node *node = tipc_node_find(addr);
|
||||
|
||||
if ((bearer_id >= MAX_BEARERS) || !node)
|
||||
return -EINVAL;
|
||||
tipc_node_lock(node);
|
||||
link = node->links[bearer_id];
|
||||
if (link) {
|
||||
strncpy(linkname, link->name, len);
|
||||
tipc_node_unlock(node);
|
||||
return 0;
|
||||
}
|
||||
tipc_node_unlock(node);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
void tipc_node_unlock(struct tipc_node *node)
|
||||
{
|
||||
LIST_HEAD(nsub_list);
|
||||
LIST_HEAD(conn_sks);
|
||||
struct sk_buff_head waiting_sks;
|
||||
u32 addr = 0;
|
||||
int flags = node->action_flags;
|
||||
u32 link_id = 0;
|
||||
|
||||
if (likely(!flags)) {
|
||||
spin_unlock_bh(&node->lock);
|
||||
return;
|
||||
}
|
||||
|
||||
addr = node->addr;
|
||||
link_id = node->link_id;
|
||||
__skb_queue_head_init(&waiting_sks);
|
||||
|
||||
if (flags & TIPC_WAKEUP_USERS)
|
||||
skb_queue_splice_init(&node->waiting_sks, &waiting_sks);
|
||||
|
||||
if (flags & TIPC_NOTIFY_NODE_DOWN) {
|
||||
list_replace_init(&node->nsub, &nsub_list);
|
||||
list_replace_init(&node->conn_sks, &conn_sks);
|
||||
}
|
||||
node->action_flags &= ~(TIPC_WAKEUP_USERS | TIPC_NOTIFY_NODE_DOWN |
|
||||
TIPC_NOTIFY_NODE_UP | TIPC_NOTIFY_LINK_UP |
|
||||
TIPC_NOTIFY_LINK_DOWN |
|
||||
TIPC_WAKEUP_BCAST_USERS);
|
||||
|
||||
spin_unlock_bh(&node->lock);
|
||||
|
||||
while (!skb_queue_empty(&waiting_sks))
|
||||
tipc_sk_rcv(__skb_dequeue(&waiting_sks));
|
||||
|
||||
if (!list_empty(&conn_sks))
|
||||
tipc_node_abort_sock_conns(&conn_sks);
|
||||
|
||||
if (!list_empty(&nsub_list))
|
||||
tipc_nodesub_notify(&nsub_list);
|
||||
|
||||
if (flags & TIPC_WAKEUP_BCAST_USERS)
|
||||
tipc_bclink_wakeup_users();
|
||||
|
||||
if (flags & TIPC_NOTIFY_NODE_UP)
|
||||
tipc_named_node_up(addr);
|
||||
|
||||
if (flags & TIPC_NOTIFY_LINK_UP)
|
||||
tipc_nametbl_publish(TIPC_LINK_STATE, addr, addr,
|
||||
TIPC_NODE_SCOPE, link_id, addr);
|
||||
|
||||
if (flags & TIPC_NOTIFY_LINK_DOWN)
|
||||
tipc_nametbl_withdraw(TIPC_LINK_STATE, addr,
|
||||
link_id, addr);
|
||||
}
|
174
net/tipc/node.h
Normal file
174
net/tipc/node.h
Normal file
|
@ -0,0 +1,174 @@
|
|||
/*
|
||||
* net/tipc/node.h: Include file for TIPC node management routines
|
||||
*
|
||||
* Copyright (c) 2000-2006, Ericsson AB
|
||||
* Copyright (c) 2005, 2010-2014, 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 "net.h"
|
||||
#include "bearer.h"
|
||||
#include "msg.h"
|
||||
|
||||
/*
|
||||
* Out-of-range value for node signature
|
||||
*/
|
||||
#define INVALID_NODE_SIG 0x10000
|
||||
|
||||
/* Flags used to take different actions according to flag type
|
||||
* TIPC_WAIT_PEER_LINKS_DOWN: wait to see that peer's links are down
|
||||
* TIPC_WAIT_OWN_LINKS_DOWN: wait until peer node is declared down
|
||||
* TIPC_NOTIFY_NODE_DOWN: notify node is down
|
||||
* TIPC_NOTIFY_NODE_UP: notify node is up
|
||||
* TIPC_DISTRIBUTE_NAME: publish or withdraw link state name type
|
||||
*/
|
||||
enum {
|
||||
TIPC_WAIT_PEER_LINKS_DOWN = (1 << 1),
|
||||
TIPC_WAIT_OWN_LINKS_DOWN = (1 << 2),
|
||||
TIPC_NOTIFY_NODE_DOWN = (1 << 3),
|
||||
TIPC_NOTIFY_NODE_UP = (1 << 4),
|
||||
TIPC_WAKEUP_USERS = (1 << 5),
|
||||
TIPC_WAKEUP_BCAST_USERS = (1 << 6),
|
||||
TIPC_NOTIFY_LINK_UP = (1 << 7),
|
||||
TIPC_NOTIFY_LINK_DOWN = (1 << 8)
|
||||
};
|
||||
|
||||
/**
|
||||
* struct tipc_node_bclink - TIPC node bclink structure
|
||||
* @acked: sequence # of last outbound b'cast message acknowledged by node
|
||||
* @last_in: sequence # of last in-sequence b'cast message received from node
|
||||
* @last_sent: sequence # of last b'cast message sent by node
|
||||
* @oos_state: state tracker for handling OOS b'cast messages
|
||||
* @deferred_size: number of OOS b'cast messages in deferred queue
|
||||
* @deferred_head: oldest OOS b'cast message received from node
|
||||
* @deferred_tail: newest OOS b'cast message received from node
|
||||
* @reasm_buf: broadcast reassembly queue head from node
|
||||
* @recv_permitted: true if node is allowed to receive b'cast messages
|
||||
*/
|
||||
struct tipc_node_bclink {
|
||||
u32 acked;
|
||||
u32 last_in;
|
||||
u32 last_sent;
|
||||
u32 oos_state;
|
||||
u32 deferred_size;
|
||||
struct sk_buff *deferred_head;
|
||||
struct sk_buff *deferred_tail;
|
||||
struct sk_buff *reasm_buf;
|
||||
bool recv_permitted;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct tipc_node - TIPC node structure
|
||||
* @addr: network address of node
|
||||
* @lock: spinlock governing access to structure
|
||||
* @hash: links to adjacent nodes in unsorted hash chain
|
||||
* @active_links: pointers to active links to node
|
||||
* @links: pointers to all links to node
|
||||
* @action_flags: bit mask of different types of node actions
|
||||
* @bclink: broadcast-related info
|
||||
* @list: links to adjacent nodes in sorted list of cluster's nodes
|
||||
* @working_links: number of working links to node (both active and standby)
|
||||
* @link_cnt: number of links to node
|
||||
* @signature: node instance identifier
|
||||
* @link_id: local and remote bearer ids of changing link, if any
|
||||
* @nsub: list of "node down" subscriptions monitoring node
|
||||
* @rcu: rcu struct for tipc_node
|
||||
*/
|
||||
struct tipc_node {
|
||||
u32 addr;
|
||||
spinlock_t lock;
|
||||
struct hlist_node hash;
|
||||
struct tipc_link *active_links[2];
|
||||
u32 act_mtus[2];
|
||||
struct tipc_link *links[MAX_BEARERS];
|
||||
unsigned int action_flags;
|
||||
struct tipc_node_bclink bclink;
|
||||
struct list_head list;
|
||||
int link_cnt;
|
||||
int working_links;
|
||||
u32 signature;
|
||||
u32 link_id;
|
||||
struct list_head nsub;
|
||||
struct sk_buff_head waiting_sks;
|
||||
struct list_head conn_sks;
|
||||
struct rcu_head rcu;
|
||||
};
|
||||
|
||||
extern struct list_head tipc_node_list;
|
||||
|
||||
struct tipc_node *tipc_node_find(u32 addr);
|
||||
struct tipc_node *tipc_node_create(u32 addr);
|
||||
void tipc_node_stop(void);
|
||||
void tipc_node_attach_link(struct tipc_node *n_ptr, struct tipc_link *l_ptr);
|
||||
void tipc_node_detach_link(struct tipc_node *n_ptr, struct tipc_link *l_ptr);
|
||||
void tipc_node_link_down(struct tipc_node *n_ptr, struct tipc_link *l_ptr);
|
||||
void tipc_node_link_up(struct tipc_node *n_ptr, struct tipc_link *l_ptr);
|
||||
int tipc_node_active_links(struct tipc_node *n_ptr);
|
||||
int tipc_node_is_up(struct tipc_node *n_ptr);
|
||||
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);
|
||||
int tipc_node_get_linkname(u32 bearer_id, u32 node, char *linkname, size_t len);
|
||||
void tipc_node_unlock(struct tipc_node *node);
|
||||
int tipc_node_add_conn(u32 dnode, u32 port, u32 peer_port);
|
||||
void tipc_node_remove_conn(u32 dnode, u32 port);
|
||||
|
||||
static inline void tipc_node_lock(struct tipc_node *node)
|
||||
{
|
||||
spin_lock_bh(&node->lock);
|
||||
}
|
||||
|
||||
static inline bool tipc_node_blocked(struct tipc_node *node)
|
||||
{
|
||||
return (node->action_flags & (TIPC_WAIT_PEER_LINKS_DOWN |
|
||||
TIPC_NOTIFY_NODE_DOWN | TIPC_WAIT_OWN_LINKS_DOWN));
|
||||
}
|
||||
|
||||
static inline uint tipc_node_get_mtu(u32 addr, u32 selector)
|
||||
{
|
||||
struct tipc_node *node;
|
||||
u32 mtu;
|
||||
|
||||
node = tipc_node_find(addr);
|
||||
|
||||
if (likely(node))
|
||||
mtu = node->act_mtus[selector & 1];
|
||||
else
|
||||
mtu = MAX_MSG_SIZE;
|
||||
|
||||
return mtu;
|
||||
}
|
||||
|
||||
#endif
|
96
net/tipc/node_subscr.c
Normal file
96
net/tipc/node_subscr.c
Normal file
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* net/tipc/node_subscr.c: TIPC "node down" subscription handling
|
||||
*
|
||||
* Copyright (c) 1995-2006, Ericsson AB
|
||||
* Copyright (c) 2005, 2010-2011, 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 "node_subscr.h"
|
||||
#include "node.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 (in_own_node(addr)) {
|
||||
node_sub->node = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
node_sub->node = tipc_node_find(addr);
|
||||
if (!node_sub->node) {
|
||||
pr_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);
|
||||
}
|
||||
|
||||
/**
|
||||
* tipc_nodesub_notify - notify subscribers that a node is unreachable
|
||||
*
|
||||
* Note: node is locked by caller
|
||||
*/
|
||||
void tipc_nodesub_notify(struct list_head *nsub_list)
|
||||
{
|
||||
struct tipc_node_subscr *ns, *safe;
|
||||
net_ev_handler handle_node_down;
|
||||
|
||||
list_for_each_entry_safe(ns, safe, nsub_list, nodesub_list) {
|
||||
handle_node_down = ns->handle_node_down;
|
||||
if (handle_node_down) {
|
||||
ns->handle_node_down = NULL;
|
||||
handle_node_down(ns->usr_handle);
|
||||
}
|
||||
}
|
||||
}
|
63
net/tipc/node_subscr.h
Normal file
63
net/tipc/node_subscr.h
Normal 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, 2010-2011, 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);
|
||||
void tipc_nodesub_notify(struct list_head *nsub_list);
|
||||
|
||||
#endif
|
600
net/tipc/server.c
Normal file
600
net/tipc/server.c
Normal file
|
@ -0,0 +1,600 @@
|
|||
/*
|
||||
* net/tipc/server.c: TIPC server infrastructure
|
||||
*
|
||||
* Copyright (c) 2012-2013, 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 "server.h"
|
||||
#include "core.h"
|
||||
#include <net/sock.h>
|
||||
|
||||
/* Number of messages to send before rescheduling */
|
||||
#define MAX_SEND_MSG_COUNT 25
|
||||
#define MAX_RECV_MSG_COUNT 25
|
||||
#define CF_CONNECTED 1
|
||||
|
||||
#define sock2con(x) ((struct tipc_conn *)(x)->sk_user_data)
|
||||
|
||||
/**
|
||||
* struct tipc_conn - TIPC connection structure
|
||||
* @kref: reference counter to connection object
|
||||
* @conid: connection identifier
|
||||
* @sock: socket handler associated with connection
|
||||
* @flags: indicates connection state
|
||||
* @server: pointer to connected server
|
||||
* @rwork: receive work item
|
||||
* @usr_data: user-specified field
|
||||
* @rx_action: what to do when connection socket is active
|
||||
* @outqueue: pointer to first outbound message in queue
|
||||
* @outqueue_lock: control access to the outqueue
|
||||
* @outqueue: list of connection objects for its server
|
||||
* @swork: send work item
|
||||
*/
|
||||
struct tipc_conn {
|
||||
struct kref kref;
|
||||
int conid;
|
||||
struct socket *sock;
|
||||
unsigned long flags;
|
||||
struct tipc_server *server;
|
||||
struct work_struct rwork;
|
||||
int (*rx_action) (struct tipc_conn *con);
|
||||
void *usr_data;
|
||||
struct list_head outqueue;
|
||||
spinlock_t outqueue_lock;
|
||||
struct work_struct swork;
|
||||
};
|
||||
|
||||
/* An entry waiting to be sent */
|
||||
struct outqueue_entry {
|
||||
struct list_head list;
|
||||
struct kvec iov;
|
||||
struct sockaddr_tipc dest;
|
||||
};
|
||||
|
||||
static void tipc_recv_work(struct work_struct *work);
|
||||
static void tipc_send_work(struct work_struct *work);
|
||||
static void tipc_clean_outqueues(struct tipc_conn *con);
|
||||
|
||||
static void tipc_conn_kref_release(struct kref *kref)
|
||||
{
|
||||
struct tipc_conn *con = container_of(kref, struct tipc_conn, kref);
|
||||
|
||||
if (con->sock) {
|
||||
tipc_sock_release_local(con->sock);
|
||||
con->sock = NULL;
|
||||
}
|
||||
|
||||
tipc_clean_outqueues(con);
|
||||
kfree(con);
|
||||
}
|
||||
|
||||
static void conn_put(struct tipc_conn *con)
|
||||
{
|
||||
kref_put(&con->kref, tipc_conn_kref_release);
|
||||
}
|
||||
|
||||
static void conn_get(struct tipc_conn *con)
|
||||
{
|
||||
kref_get(&con->kref);
|
||||
}
|
||||
|
||||
static struct tipc_conn *tipc_conn_lookup(struct tipc_server *s, int conid)
|
||||
{
|
||||
struct tipc_conn *con;
|
||||
|
||||
spin_lock_bh(&s->idr_lock);
|
||||
con = idr_find(&s->conn_idr, conid);
|
||||
if (con)
|
||||
conn_get(con);
|
||||
spin_unlock_bh(&s->idr_lock);
|
||||
return con;
|
||||
}
|
||||
|
||||
static void sock_data_ready(struct sock *sk)
|
||||
{
|
||||
struct tipc_conn *con;
|
||||
|
||||
read_lock(&sk->sk_callback_lock);
|
||||
con = sock2con(sk);
|
||||
if (con && test_bit(CF_CONNECTED, &con->flags)) {
|
||||
conn_get(con);
|
||||
if (!queue_work(con->server->rcv_wq, &con->rwork))
|
||||
conn_put(con);
|
||||
}
|
||||
read_unlock(&sk->sk_callback_lock);
|
||||
}
|
||||
|
||||
static void sock_write_space(struct sock *sk)
|
||||
{
|
||||
struct tipc_conn *con;
|
||||
|
||||
read_lock(&sk->sk_callback_lock);
|
||||
con = sock2con(sk);
|
||||
if (con && test_bit(CF_CONNECTED, &con->flags)) {
|
||||
conn_get(con);
|
||||
if (!queue_work(con->server->send_wq, &con->swork))
|
||||
conn_put(con);
|
||||
}
|
||||
read_unlock(&sk->sk_callback_lock);
|
||||
}
|
||||
|
||||
static void tipc_register_callbacks(struct socket *sock, struct tipc_conn *con)
|
||||
{
|
||||
struct sock *sk = sock->sk;
|
||||
|
||||
write_lock_bh(&sk->sk_callback_lock);
|
||||
|
||||
sk->sk_data_ready = sock_data_ready;
|
||||
sk->sk_write_space = sock_write_space;
|
||||
sk->sk_user_data = con;
|
||||
|
||||
con->sock = sock;
|
||||
|
||||
write_unlock_bh(&sk->sk_callback_lock);
|
||||
}
|
||||
|
||||
static void tipc_unregister_callbacks(struct tipc_conn *con)
|
||||
{
|
||||
struct sock *sk = con->sock->sk;
|
||||
|
||||
write_lock_bh(&sk->sk_callback_lock);
|
||||
sk->sk_user_data = NULL;
|
||||
write_unlock_bh(&sk->sk_callback_lock);
|
||||
}
|
||||
|
||||
static void tipc_close_conn(struct tipc_conn *con)
|
||||
{
|
||||
struct tipc_server *s = con->server;
|
||||
|
||||
if (test_and_clear_bit(CF_CONNECTED, &con->flags)) {
|
||||
if (con->conid)
|
||||
s->tipc_conn_shutdown(con->conid, con->usr_data);
|
||||
|
||||
spin_lock_bh(&s->idr_lock);
|
||||
idr_remove(&s->conn_idr, con->conid);
|
||||
s->idr_in_use--;
|
||||
spin_unlock_bh(&s->idr_lock);
|
||||
|
||||
tipc_unregister_callbacks(con);
|
||||
|
||||
/* We shouldn't flush pending works as we may be in the
|
||||
* thread. In fact the races with pending rx/tx work structs
|
||||
* are harmless for us here as we have already deleted this
|
||||
* connection from server connection list and set
|
||||
* sk->sk_user_data to 0 before releasing connection object.
|
||||
*/
|
||||
kernel_sock_shutdown(con->sock, SHUT_RDWR);
|
||||
|
||||
conn_put(con);
|
||||
}
|
||||
}
|
||||
|
||||
static struct tipc_conn *tipc_alloc_conn(struct tipc_server *s)
|
||||
{
|
||||
struct tipc_conn *con;
|
||||
int ret;
|
||||
|
||||
con = kzalloc(sizeof(struct tipc_conn), GFP_ATOMIC);
|
||||
if (!con)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
kref_init(&con->kref);
|
||||
INIT_LIST_HEAD(&con->outqueue);
|
||||
spin_lock_init(&con->outqueue_lock);
|
||||
INIT_WORK(&con->swork, tipc_send_work);
|
||||
INIT_WORK(&con->rwork, tipc_recv_work);
|
||||
|
||||
spin_lock_bh(&s->idr_lock);
|
||||
ret = idr_alloc(&s->conn_idr, con, 0, 0, GFP_ATOMIC);
|
||||
if (ret < 0) {
|
||||
kfree(con);
|
||||
spin_unlock_bh(&s->idr_lock);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
con->conid = ret;
|
||||
s->idr_in_use++;
|
||||
spin_unlock_bh(&s->idr_lock);
|
||||
|
||||
set_bit(CF_CONNECTED, &con->flags);
|
||||
con->server = s;
|
||||
|
||||
return con;
|
||||
}
|
||||
|
||||
static int tipc_receive_from_sock(struct tipc_conn *con)
|
||||
{
|
||||
struct msghdr msg = {};
|
||||
struct tipc_server *s = con->server;
|
||||
struct sockaddr_tipc addr;
|
||||
struct kvec iov;
|
||||
void *buf;
|
||||
int ret;
|
||||
|
||||
buf = kmem_cache_alloc(s->rcvbuf_cache, GFP_ATOMIC);
|
||||
if (!buf) {
|
||||
ret = -ENOMEM;
|
||||
goto out_close;
|
||||
}
|
||||
|
||||
iov.iov_base = buf;
|
||||
iov.iov_len = s->max_rcvbuf_size;
|
||||
msg.msg_name = &addr;
|
||||
ret = kernel_recvmsg(con->sock, &msg, &iov, 1, iov.iov_len,
|
||||
MSG_DONTWAIT);
|
||||
if (ret <= 0) {
|
||||
kmem_cache_free(s->rcvbuf_cache, buf);
|
||||
goto out_close;
|
||||
}
|
||||
|
||||
s->tipc_conn_recvmsg(con->conid, &addr, con->usr_data, buf, ret);
|
||||
|
||||
kmem_cache_free(s->rcvbuf_cache, buf);
|
||||
|
||||
return 0;
|
||||
|
||||
out_close:
|
||||
if (ret != -EWOULDBLOCK)
|
||||
tipc_close_conn(con);
|
||||
else if (ret == 0)
|
||||
/* Don't return success if we really got EOF */
|
||||
ret = -EAGAIN;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int tipc_accept_from_sock(struct tipc_conn *con)
|
||||
{
|
||||
struct tipc_server *s = con->server;
|
||||
struct socket *sock = con->sock;
|
||||
struct socket *newsock;
|
||||
struct tipc_conn *newcon;
|
||||
int ret;
|
||||
|
||||
ret = tipc_sock_accept_local(sock, &newsock, O_NONBLOCK);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
newcon = tipc_alloc_conn(con->server);
|
||||
if (IS_ERR(newcon)) {
|
||||
ret = PTR_ERR(newcon);
|
||||
sock_release(newsock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
newcon->rx_action = tipc_receive_from_sock;
|
||||
tipc_register_callbacks(newsock, newcon);
|
||||
|
||||
/* Notify that new connection is incoming */
|
||||
newcon->usr_data = s->tipc_conn_new(newcon->conid);
|
||||
|
||||
/* Wake up receive process in case of 'SYN+' message */
|
||||
newsock->sk->sk_data_ready(newsock->sk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct socket *tipc_create_listen_sock(struct tipc_conn *con)
|
||||
{
|
||||
struct tipc_server *s = con->server;
|
||||
struct socket *sock = NULL;
|
||||
int ret;
|
||||
|
||||
ret = tipc_sock_create_local(s->type, &sock);
|
||||
if (ret < 0)
|
||||
return NULL;
|
||||
ret = kernel_setsockopt(sock, SOL_TIPC, TIPC_IMPORTANCE,
|
||||
(char *)&s->imp, sizeof(s->imp));
|
||||
if (ret < 0)
|
||||
goto create_err;
|
||||
ret = kernel_bind(sock, (struct sockaddr *)s->saddr, sizeof(*s->saddr));
|
||||
if (ret < 0)
|
||||
goto create_err;
|
||||
|
||||
switch (s->type) {
|
||||
case SOCK_STREAM:
|
||||
case SOCK_SEQPACKET:
|
||||
con->rx_action = tipc_accept_from_sock;
|
||||
|
||||
ret = kernel_listen(sock, 0);
|
||||
if (ret < 0)
|
||||
goto create_err;
|
||||
break;
|
||||
case SOCK_DGRAM:
|
||||
case SOCK_RDM:
|
||||
con->rx_action = tipc_receive_from_sock;
|
||||
break;
|
||||
default:
|
||||
pr_err("Unknown socket type %d\n", s->type);
|
||||
goto create_err;
|
||||
}
|
||||
return sock;
|
||||
|
||||
create_err:
|
||||
sock_release(sock);
|
||||
con->sock = NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int tipc_open_listening_sock(struct tipc_server *s)
|
||||
{
|
||||
struct socket *sock;
|
||||
struct tipc_conn *con;
|
||||
|
||||
con = tipc_alloc_conn(s);
|
||||
if (IS_ERR(con))
|
||||
return PTR_ERR(con);
|
||||
|
||||
sock = tipc_create_listen_sock(con);
|
||||
if (!sock) {
|
||||
idr_remove(&s->conn_idr, con->conid);
|
||||
s->idr_in_use--;
|
||||
kfree(con);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
tipc_register_callbacks(sock, con);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct outqueue_entry *tipc_alloc_entry(void *data, int len)
|
||||
{
|
||||
struct outqueue_entry *entry;
|
||||
void *buf;
|
||||
|
||||
entry = kmalloc(sizeof(struct outqueue_entry), GFP_ATOMIC);
|
||||
if (!entry)
|
||||
return NULL;
|
||||
|
||||
buf = kmalloc(len, GFP_ATOMIC);
|
||||
if (!buf) {
|
||||
kfree(entry);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memcpy(buf, data, len);
|
||||
entry->iov.iov_base = buf;
|
||||
entry->iov.iov_len = len;
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
static void tipc_free_entry(struct outqueue_entry *e)
|
||||
{
|
||||
kfree(e->iov.iov_base);
|
||||
kfree(e);
|
||||
}
|
||||
|
||||
static void tipc_clean_outqueues(struct tipc_conn *con)
|
||||
{
|
||||
struct outqueue_entry *e, *safe;
|
||||
|
||||
spin_lock_bh(&con->outqueue_lock);
|
||||
list_for_each_entry_safe(e, safe, &con->outqueue, list) {
|
||||
list_del(&e->list);
|
||||
tipc_free_entry(e);
|
||||
}
|
||||
spin_unlock_bh(&con->outqueue_lock);
|
||||
}
|
||||
|
||||
int tipc_conn_sendmsg(struct tipc_server *s, int conid,
|
||||
struct sockaddr_tipc *addr, void *data, size_t len)
|
||||
{
|
||||
struct outqueue_entry *e;
|
||||
struct tipc_conn *con;
|
||||
|
||||
con = tipc_conn_lookup(s, conid);
|
||||
if (!con)
|
||||
return -EINVAL;
|
||||
|
||||
e = tipc_alloc_entry(data, len);
|
||||
if (!e) {
|
||||
conn_put(con);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (addr)
|
||||
memcpy(&e->dest, addr, sizeof(struct sockaddr_tipc));
|
||||
|
||||
spin_lock_bh(&con->outqueue_lock);
|
||||
list_add_tail(&e->list, &con->outqueue);
|
||||
spin_unlock_bh(&con->outqueue_lock);
|
||||
|
||||
if (test_bit(CF_CONNECTED, &con->flags)) {
|
||||
if (!queue_work(s->send_wq, &con->swork))
|
||||
conn_put(con);
|
||||
} else {
|
||||
conn_put(con);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void tipc_conn_terminate(struct tipc_server *s, int conid)
|
||||
{
|
||||
struct tipc_conn *con;
|
||||
|
||||
con = tipc_conn_lookup(s, conid);
|
||||
if (con) {
|
||||
tipc_close_conn(con);
|
||||
conn_put(con);
|
||||
}
|
||||
}
|
||||
|
||||
static void tipc_send_to_sock(struct tipc_conn *con)
|
||||
{
|
||||
int count = 0;
|
||||
struct tipc_server *s = con->server;
|
||||
struct outqueue_entry *e;
|
||||
struct msghdr msg;
|
||||
int ret;
|
||||
|
||||
spin_lock_bh(&con->outqueue_lock);
|
||||
while (1) {
|
||||
e = list_entry(con->outqueue.next, struct outqueue_entry,
|
||||
list);
|
||||
if ((struct list_head *) e == &con->outqueue)
|
||||
break;
|
||||
spin_unlock_bh(&con->outqueue_lock);
|
||||
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
msg.msg_flags = MSG_DONTWAIT;
|
||||
|
||||
if (s->type == SOCK_DGRAM || s->type == SOCK_RDM) {
|
||||
msg.msg_name = &e->dest;
|
||||
msg.msg_namelen = sizeof(struct sockaddr_tipc);
|
||||
}
|
||||
ret = kernel_sendmsg(con->sock, &msg, &e->iov, 1,
|
||||
e->iov.iov_len);
|
||||
if (ret == -EWOULDBLOCK || ret == 0) {
|
||||
cond_resched();
|
||||
goto out;
|
||||
} else if (ret < 0) {
|
||||
goto send_err;
|
||||
}
|
||||
|
||||
/* Don't starve users filling buffers */
|
||||
if (++count >= MAX_SEND_MSG_COUNT) {
|
||||
cond_resched();
|
||||
count = 0;
|
||||
}
|
||||
|
||||
spin_lock_bh(&con->outqueue_lock);
|
||||
list_del(&e->list);
|
||||
tipc_free_entry(e);
|
||||
}
|
||||
spin_unlock_bh(&con->outqueue_lock);
|
||||
out:
|
||||
return;
|
||||
|
||||
send_err:
|
||||
tipc_close_conn(con);
|
||||
}
|
||||
|
||||
static void tipc_recv_work(struct work_struct *work)
|
||||
{
|
||||
struct tipc_conn *con = container_of(work, struct tipc_conn, rwork);
|
||||
int count = 0;
|
||||
|
||||
while (test_bit(CF_CONNECTED, &con->flags)) {
|
||||
if (con->rx_action(con))
|
||||
break;
|
||||
|
||||
/* Don't flood Rx machine */
|
||||
if (++count >= MAX_RECV_MSG_COUNT) {
|
||||
cond_resched();
|
||||
count = 0;
|
||||
}
|
||||
}
|
||||
conn_put(con);
|
||||
}
|
||||
|
||||
static void tipc_send_work(struct work_struct *work)
|
||||
{
|
||||
struct tipc_conn *con = container_of(work, struct tipc_conn, swork);
|
||||
|
||||
if (test_bit(CF_CONNECTED, &con->flags))
|
||||
tipc_send_to_sock(con);
|
||||
|
||||
conn_put(con);
|
||||
}
|
||||
|
||||
static void tipc_work_stop(struct tipc_server *s)
|
||||
{
|
||||
destroy_workqueue(s->rcv_wq);
|
||||
destroy_workqueue(s->send_wq);
|
||||
}
|
||||
|
||||
static int tipc_work_start(struct tipc_server *s)
|
||||
{
|
||||
s->rcv_wq = alloc_workqueue("tipc_rcv", WQ_UNBOUND, 1);
|
||||
if (!s->rcv_wq) {
|
||||
pr_err("can't start tipc receive workqueue\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
s->send_wq = alloc_workqueue("tipc_send", WQ_UNBOUND, 1);
|
||||
if (!s->send_wq) {
|
||||
pr_err("can't start tipc send workqueue\n");
|
||||
destroy_workqueue(s->rcv_wq);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tipc_server_start(struct tipc_server *s)
|
||||
{
|
||||
int ret;
|
||||
|
||||
spin_lock_init(&s->idr_lock);
|
||||
idr_init(&s->conn_idr);
|
||||
s->idr_in_use = 0;
|
||||
|
||||
s->rcvbuf_cache = kmem_cache_create(s->name, s->max_rcvbuf_size,
|
||||
0, SLAB_HWCACHE_ALIGN, NULL);
|
||||
if (!s->rcvbuf_cache)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = tipc_work_start(s);
|
||||
if (ret < 0) {
|
||||
kmem_cache_destroy(s->rcvbuf_cache);
|
||||
return ret;
|
||||
}
|
||||
ret = tipc_open_listening_sock(s);
|
||||
if (ret < 0) {
|
||||
tipc_work_stop(s);
|
||||
kmem_cache_destroy(s->rcvbuf_cache);
|
||||
return ret;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void tipc_server_stop(struct tipc_server *s)
|
||||
{
|
||||
struct tipc_conn *con;
|
||||
int total = 0;
|
||||
int id;
|
||||
|
||||
spin_lock_bh(&s->idr_lock);
|
||||
for (id = 0; total < s->idr_in_use; id++) {
|
||||
con = idr_find(&s->conn_idr, id);
|
||||
if (con) {
|
||||
total++;
|
||||
spin_unlock_bh(&s->idr_lock);
|
||||
tipc_close_conn(con);
|
||||
spin_lock_bh(&s->idr_lock);
|
||||
}
|
||||
}
|
||||
spin_unlock_bh(&s->idr_lock);
|
||||
|
||||
tipc_work_stop(s);
|
||||
kmem_cache_destroy(s->rcvbuf_cache);
|
||||
idr_destroy(&s->conn_idr);
|
||||
}
|
92
net/tipc/server.h
Normal file
92
net/tipc/server.h
Normal file
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
* net/tipc/server.h: Include file for TIPC server code
|
||||
*
|
||||
* Copyright (c) 2012-2013, 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_SERVER_H
|
||||
#define _TIPC_SERVER_H
|
||||
|
||||
#include "core.h"
|
||||
|
||||
#define TIPC_SERVER_NAME_LEN 32
|
||||
|
||||
/**
|
||||
* struct tipc_server - TIPC server structure
|
||||
* @conn_idr: identifier set of connection
|
||||
* @idr_lock: protect the connection identifier set
|
||||
* @idr_in_use: amount of allocated identifier entry
|
||||
* @rcvbuf_cache: memory cache of server receive buffer
|
||||
* @rcv_wq: receive workqueue
|
||||
* @send_wq: send workqueue
|
||||
* @max_rcvbuf_size: maximum permitted receive message length
|
||||
* @tipc_conn_new: callback will be called when new connection is incoming
|
||||
* @tipc_conn_shutdown: callback will be called when connection is shut down
|
||||
* @tipc_conn_recvmsg: callback will be called when message arrives
|
||||
* @saddr: TIPC server address
|
||||
* @name: server name
|
||||
* @imp: message importance
|
||||
* @type: socket type
|
||||
*/
|
||||
struct tipc_server {
|
||||
struct idr conn_idr;
|
||||
spinlock_t idr_lock;
|
||||
int idr_in_use;
|
||||
struct kmem_cache *rcvbuf_cache;
|
||||
struct workqueue_struct *rcv_wq;
|
||||
struct workqueue_struct *send_wq;
|
||||
int max_rcvbuf_size;
|
||||
void *(*tipc_conn_new) (int conid);
|
||||
void (*tipc_conn_shutdown) (int conid, void *usr_data);
|
||||
void (*tipc_conn_recvmsg) (int conid, struct sockaddr_tipc *addr,
|
||||
void *usr_data, void *buf, size_t len);
|
||||
struct sockaddr_tipc *saddr;
|
||||
const char name[TIPC_SERVER_NAME_LEN];
|
||||
int imp;
|
||||
int type;
|
||||
};
|
||||
|
||||
int tipc_conn_sendmsg(struct tipc_server *s, int conid,
|
||||
struct sockaddr_tipc *addr, void *data, size_t len);
|
||||
|
||||
/**
|
||||
* tipc_conn_terminate - terminate connection with server
|
||||
*
|
||||
* Note: Must call it in process context since it might sleep
|
||||
*/
|
||||
void tipc_conn_terminate(struct tipc_server *s, int conid);
|
||||
|
||||
int tipc_server_start(struct tipc_server *s);
|
||||
|
||||
void tipc_server_stop(struct tipc_server *s);
|
||||
|
||||
#endif
|
2804
net/tipc/socket.c
Normal file
2804
net/tipc/socket.c
Normal file
File diff suppressed because it is too large
Load diff
51
net/tipc/socket.h
Normal file
51
net/tipc/socket.h
Normal file
|
@ -0,0 +1,51 @@
|
|||
/* net/tipc/socket.h: Include file for TIPC socket code
|
||||
*
|
||||
* Copyright (c) 2014, Ericsson AB
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 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_SOCK_H
|
||||
#define _TIPC_SOCK_H
|
||||
|
||||
#include <net/sock.h>
|
||||
|
||||
#define TIPC_CONNACK_INTV 256
|
||||
#define TIPC_FLOWCTRL_WIN (TIPC_CONNACK_INTV * 2)
|
||||
#define TIPC_CONN_OVERLOAD_LIMIT ((TIPC_FLOWCTRL_WIN * 2 + 1) * \
|
||||
SKB_TRUESIZE(TIPC_MAX_USER_MSG_SIZE))
|
||||
int tipc_sk_rcv(struct sk_buff *buf);
|
||||
struct sk_buff *tipc_sk_socks_show(void);
|
||||
void tipc_sk_mcast_rcv(struct sk_buff *buf);
|
||||
void tipc_sk_reinit(void);
|
||||
int tipc_sk_ref_table_init(u32 requested_size, u32 start);
|
||||
void tipc_sk_ref_table_stop(void);
|
||||
|
||||
#endif
|
374
net/tipc/subscr.c
Normal file
374
net/tipc/subscr.c
Normal file
|
@ -0,0 +1,374 @@
|
|||
/*
|
||||
* net/tipc/subscr.c: TIPC network topology service
|
||||
*
|
||||
* Copyright (c) 2000-2006, Ericsson AB
|
||||
* Copyright (c) 2005-2007, 2010-2013, 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 "name_table.h"
|
||||
#include "subscr.h"
|
||||
|
||||
/**
|
||||
* struct tipc_subscriber - TIPC network topology subscriber
|
||||
* @conid: connection identifier to server connecting to subscriber
|
||||
* @lock: control access to subscriber
|
||||
* @subscription_list: list of subscription objects for this subscriber
|
||||
*/
|
||||
struct tipc_subscriber {
|
||||
int conid;
|
||||
spinlock_t lock;
|
||||
struct list_head subscription_list;
|
||||
};
|
||||
|
||||
static void subscr_conn_msg_event(int conid, struct sockaddr_tipc *addr,
|
||||
void *usr_data, void *buf, size_t len);
|
||||
static void *subscr_named_msg_event(int conid);
|
||||
static void subscr_conn_shutdown_event(int conid, void *usr_data);
|
||||
|
||||
static atomic_t subscription_count = ATOMIC_INIT(0);
|
||||
|
||||
static struct sockaddr_tipc topsrv_addr __read_mostly = {
|
||||
.family = AF_TIPC,
|
||||
.addrtype = TIPC_ADDR_NAMESEQ,
|
||||
.addr.nameseq.type = TIPC_TOP_SRV,
|
||||
.addr.nameseq.lower = TIPC_TOP_SRV,
|
||||
.addr.nameseq.upper = TIPC_TOP_SRV,
|
||||
.scope = TIPC_NODE_SCOPE
|
||||
};
|
||||
|
||||
static struct tipc_server topsrv __read_mostly = {
|
||||
.saddr = &topsrv_addr,
|
||||
.imp = TIPC_CRITICAL_IMPORTANCE,
|
||||
.type = SOCK_SEQPACKET,
|
||||
.max_rcvbuf_size = sizeof(struct tipc_subscr),
|
||||
.name = "topology_server",
|
||||
.tipc_conn_recvmsg = subscr_conn_msg_event,
|
||||
.tipc_conn_new = subscr_named_msg_event,
|
||||
.tipc_conn_shutdown = subscr_conn_shutdown_event,
|
||||
};
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
static void subscr_send_event(struct tipc_subscription *sub, u32 found_lower,
|
||||
u32 found_upper, u32 event, u32 port_ref,
|
||||
u32 node)
|
||||
{
|
||||
struct tipc_subscriber *subscriber = sub->subscriber;
|
||||
struct kvec 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_conn_sendmsg(&topsrv, subscriber->conid, NULL, msg_sect.iov_base,
|
||||
msg_sect.iov_len);
|
||||
}
|
||||
|
||||
/**
|
||||
* tipc_subscr_overlap - test for subscription overlap with the given values
|
||||
*
|
||||
* Returns 1 if there is overlap, otherwise 0.
|
||||
*/
|
||||
int tipc_subscr_overlap(struct tipc_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 tipc_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;
|
||||
|
||||
subscr_send_event(sub, found_lower, found_upper, event, port_ref, node);
|
||||
}
|
||||
|
||||
static void subscr_timeout(struct tipc_subscription *sub)
|
||||
{
|
||||
struct tipc_subscriber *subscriber = sub->subscriber;
|
||||
|
||||
/* The spin lock per subscriber is used to protect its members */
|
||||
spin_lock_bh(&subscriber->lock);
|
||||
|
||||
/* Validate timeout (in case subscription is being cancelled) */
|
||||
if (sub->timeout == TIPC_WAIT_FOREVER) {
|
||||
spin_unlock_bh(&subscriber->lock);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Unlink subscription from name table */
|
||||
tipc_nametbl_unsubscribe(sub);
|
||||
|
||||
/* Unlink subscription from subscriber */
|
||||
list_del(&sub->subscription_list);
|
||||
|
||||
spin_unlock_bh(&subscriber->lock);
|
||||
|
||||
/* 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(&subscription_count);
|
||||
}
|
||||
|
||||
/**
|
||||
* subscr_del - delete a subscription within a subscription list
|
||||
*
|
||||
* Called with subscriber lock held.
|
||||
*/
|
||||
static void subscr_del(struct tipc_subscription *sub)
|
||||
{
|
||||
tipc_nametbl_unsubscribe(sub);
|
||||
list_del(&sub->subscription_list);
|
||||
kfree(sub);
|
||||
atomic_dec(&subscription_count);
|
||||
}
|
||||
|
||||
/**
|
||||
* subscr_terminate - terminate communication with a subscriber
|
||||
*
|
||||
* Note: Must call it in process context since it might sleep.
|
||||
*/
|
||||
static void subscr_terminate(struct tipc_subscriber *subscriber)
|
||||
{
|
||||
tipc_conn_terminate(&topsrv, subscriber->conid);
|
||||
}
|
||||
|
||||
static void subscr_release(struct tipc_subscriber *subscriber)
|
||||
{
|
||||
struct tipc_subscription *sub;
|
||||
struct tipc_subscription *sub_temp;
|
||||
|
||||
spin_lock_bh(&subscriber->lock);
|
||||
|
||||
/* 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) {
|
||||
spin_unlock_bh(&subscriber->lock);
|
||||
k_cancel_timer(&sub->timer);
|
||||
k_term_timer(&sub->timer);
|
||||
spin_lock_bh(&subscriber->lock);
|
||||
}
|
||||
subscr_del(sub);
|
||||
}
|
||||
spin_unlock_bh(&subscriber->lock);
|
||||
|
||||
/* Now destroy subscriber */
|
||||
kfree(subscriber);
|
||||
}
|
||||
|
||||
/**
|
||||
* subscr_cancel - handle subscription cancellation request
|
||||
*
|
||||
* Called with subscriber lock held. 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 tipc_subscriber *subscriber)
|
||||
{
|
||||
struct tipc_subscription *sub;
|
||||
struct tipc_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);
|
||||
}
|
||||
subscr_del(sub);
|
||||
}
|
||||
|
||||
/**
|
||||
* subscr_subscribe - create subscription for subscriber
|
||||
*
|
||||
* Called with subscriber lock held.
|
||||
*/
|
||||
static int subscr_subscribe(struct tipc_subscr *s,
|
||||
struct tipc_subscriber *subscriber,
|
||||
struct tipc_subscription **sub_p) {
|
||||
struct tipc_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 0;
|
||||
}
|
||||
|
||||
/* Refuse subscription if global limit exceeded */
|
||||
if (atomic_read(&subscription_count) >= TIPC_MAX_SUBSCRIPTIONS) {
|
||||
pr_warn("Subscription rejected, limit reached (%u)\n",
|
||||
TIPC_MAX_SUBSCRIPTIONS);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Allocate subscription object */
|
||||
sub = kmalloc(sizeof(*sub), GFP_ATOMIC);
|
||||
if (!sub) {
|
||||
pr_warn("Subscription rejected, no memory\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* 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)) {
|
||||
pr_warn("Subscription rejected, illegal request\n");
|
||||
kfree(sub);
|
||||
return -EINVAL;
|
||||
}
|
||||
INIT_LIST_HEAD(&sub->nameseq_list);
|
||||
list_add(&sub->subscription_list, &subscriber->subscription_list);
|
||||
sub->subscriber = subscriber;
|
||||
sub->swap = swap;
|
||||
memcpy(&sub->evt.s, s, sizeof(struct tipc_subscr));
|
||||
atomic_inc(&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);
|
||||
}
|
||||
*sub_p = sub;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Handle one termination request for the subscriber */
|
||||
static void subscr_conn_shutdown_event(int conid, void *usr_data)
|
||||
{
|
||||
subscr_release((struct tipc_subscriber *)usr_data);
|
||||
}
|
||||
|
||||
/* Handle one request to create a new subscription for the subscriber */
|
||||
static void subscr_conn_msg_event(int conid, struct sockaddr_tipc *addr,
|
||||
void *usr_data, void *buf, size_t len)
|
||||
{
|
||||
struct tipc_subscriber *subscriber = usr_data;
|
||||
struct tipc_subscription *sub = NULL;
|
||||
|
||||
spin_lock_bh(&subscriber->lock);
|
||||
if (subscr_subscribe((struct tipc_subscr *)buf, subscriber, &sub) < 0) {
|
||||
spin_unlock_bh(&subscriber->lock);
|
||||
subscr_terminate(subscriber);
|
||||
return;
|
||||
}
|
||||
if (sub)
|
||||
tipc_nametbl_subscribe(sub);
|
||||
spin_unlock_bh(&subscriber->lock);
|
||||
}
|
||||
|
||||
|
||||
/* Handle one request to establish a new subscriber */
|
||||
static void *subscr_named_msg_event(int conid)
|
||||
{
|
||||
struct tipc_subscriber *subscriber;
|
||||
|
||||
/* Create subscriber object */
|
||||
subscriber = kzalloc(sizeof(struct tipc_subscriber), GFP_ATOMIC);
|
||||
if (subscriber == NULL) {
|
||||
pr_warn("Subscriber rejected, no memory\n");
|
||||
return NULL;
|
||||
}
|
||||
INIT_LIST_HEAD(&subscriber->subscription_list);
|
||||
subscriber->conid = conid;
|
||||
spin_lock_init(&subscriber->lock);
|
||||
|
||||
return (void *)subscriber;
|
||||
}
|
||||
|
||||
int tipc_subscr_start(void)
|
||||
{
|
||||
return tipc_server_start(&topsrv);
|
||||
}
|
||||
|
||||
void tipc_subscr_stop(void)
|
||||
{
|
||||
tipc_server_stop(&topsrv);
|
||||
}
|
81
net/tipc/subscr.h
Normal file
81
net/tipc/subscr.h
Normal file
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* net/tipc/subscr.h: Include file for TIPC network topology service
|
||||
*
|
||||
* Copyright (c) 2003-2006, Ericsson AB
|
||||
* Copyright (c) 2005-2007, 2012-2013, 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
|
||||
|
||||
#include "server.h"
|
||||
|
||||
struct tipc_subscription;
|
||||
struct tipc_subscriber;
|
||||
|
||||
/**
|
||||
* struct tipc_subscription - TIPC network topology subscription object
|
||||
* @subscriber: pointer to its subscriber
|
||||
* @seq: name sequence associated with subscription
|
||||
* @timeout: duration of subscription (in ms)
|
||||
* @filter: event filtering to be done for subscription
|
||||
* @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 tipc_subscription {
|
||||
struct tipc_subscriber *subscriber;
|
||||
struct tipc_name_seq seq;
|
||||
u32 timeout;
|
||||
u32 filter;
|
||||
struct timer_list timer;
|
||||
struct list_head nameseq_list;
|
||||
struct list_head subscription_list;
|
||||
int swap;
|
||||
struct tipc_event evt;
|
||||
};
|
||||
|
||||
int tipc_subscr_overlap(struct tipc_subscription *sub, u32 found_lower,
|
||||
u32 found_upper);
|
||||
|
||||
void tipc_subscr_report_overlap(struct tipc_subscription *sub, u32 found_lower,
|
||||
u32 found_upper, u32 event, u32 port_ref,
|
||||
u32 node, int must);
|
||||
|
||||
int tipc_subscr_start(void);
|
||||
|
||||
void tipc_subscr_stop(void);
|
||||
|
||||
#endif
|
71
net/tipc/sysctl.c
Normal file
71
net/tipc/sysctl.c
Normal file
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* net/tipc/sysctl.c: sysctl interface to TIPC subsystem
|
||||
*
|
||||
* Copyright (c) 2013, 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 <linux/sysctl.h>
|
||||
|
||||
static struct ctl_table_header *tipc_ctl_hdr;
|
||||
|
||||
static struct ctl_table tipc_table[] = {
|
||||
{
|
||||
.procname = "tipc_rmem",
|
||||
.data = &sysctl_tipc_rmem,
|
||||
.maxlen = sizeof(sysctl_tipc_rmem),
|
||||
.mode = 0644,
|
||||
.proc_handler = proc_dointvec,
|
||||
},
|
||||
{
|
||||
.procname = "named_timeout",
|
||||
.data = &sysctl_tipc_named_timeout,
|
||||
.maxlen = sizeof(sysctl_tipc_named_timeout),
|
||||
.mode = 0644,
|
||||
.proc_handler = proc_dointvec,
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
||||
int tipc_register_sysctl(void)
|
||||
{
|
||||
tipc_ctl_hdr = register_net_sysctl(&init_net, "net/tipc", tipc_table);
|
||||
if (tipc_ctl_hdr == NULL)
|
||||
return -ENOMEM;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void tipc_unregister_sysctl(void)
|
||||
{
|
||||
unregister_net_sysctl_table(tipc_ctl_hdr);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue