summaryrefslogtreecommitdiff
path: root/net/tipc
diff options
context:
space:
mode:
authorScott Wood <scottwood@freescale.com>2014-04-07 23:49:35 (GMT)
committerScott Wood <scottwood@freescale.com>2014-04-07 23:49:35 (GMT)
commit62b8c978ee6b8d135d9e7953221de58000dba986 (patch)
tree683b04b2e627f6710c22c151b23c8cc9a165315e /net/tipc
parent78fd82238d0e5716578c326404184a27ba67fd6e (diff)
downloadlinux-fsl-qoriq-62b8c978ee6b8d135d9e7953221de58000dba986.tar.xz
Rewind v3.13-rc3+ (78fd82238d0e5716) to v3.12
Diffstat (limited to 'net/tipc')
-rw-r--r--net/tipc/bcast.c16
-rw-r--r--net/tipc/bearer.c18
-rw-r--r--net/tipc/bearer.h10
-rw-r--r--net/tipc/core.h28
-rw-r--r--net/tipc/eth_media.c68
-rw-r--r--net/tipc/ib_media.c58
-rw-r--r--net/tipc/link.c493
-rw-r--r--net/tipc/link.h24
-rw-r--r--net/tipc/msg.c27
-rw-r--r--net/tipc/msg.h15
-rw-r--r--net/tipc/netlink.c11
-rw-r--r--net/tipc/node.c7
-rw-r--r--net/tipc/node.h6
-rw-r--r--net/tipc/port.c66
-rw-r--r--net/tipc/port.h16
-rw-r--r--net/tipc/socket.c18
16 files changed, 535 insertions, 346 deletions
diff --git a/net/tipc/bcast.c b/net/tipc/bcast.c
index 0d44025..716de1a 100644
--- a/net/tipc/bcast.c
+++ b/net/tipc/bcast.c
@@ -480,24 +480,18 @@ receive:
tipc_node_unlock(node);
tipc_link_recv_bundle(buf);
} else if (msg_user(msg) == MSG_FRAGMENTER) {
- int ret;
- ret = tipc_link_recv_fragment(&node->bclink.reasm_head,
- &node->bclink.reasm_tail,
- &buf);
- if (ret == LINK_REASM_ERROR)
+ int ret = tipc_link_recv_fragment(&node->bclink.defragm,
+ &buf, &msg);
+ if (ret < 0)
goto unlock;
spin_lock_bh(&bc_lock);
bclink_accept_pkt(node, seqno);
bcl->stats.recv_fragments++;
- if (ret == LINK_REASM_COMPLETE) {
+ if (ret > 0)
bcl->stats.recv_fragmented++;
- /* Point msg to inner header */
- msg = buf_msg(buf);
- spin_unlock_bh(&bc_lock);
- goto receive;
- }
spin_unlock_bh(&bc_lock);
tipc_node_unlock(node);
+ tipc_net_route_msg(buf);
} else if (msg_user(msg) == NAME_DISTRIBUTOR) {
spin_lock_bh(&bc_lock);
bclink_accept_pkt(node, seqno);
diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c
index 3f9707a..609c30c 100644
--- a/net/tipc/bearer.c
+++ b/net/tipc/bearer.c
@@ -387,7 +387,7 @@ restart:
b_ptr = &tipc_bearers[bearer_id];
strcpy(b_ptr->name, name);
- res = m_ptr->enable_media(b_ptr);
+ res = m_ptr->enable_bearer(b_ptr);
if (res) {
pr_warn("Bearer <%s> rejected, enable failure (%d)\n",
name, -res);
@@ -420,15 +420,23 @@ exit:
}
/**
- * tipc_block_bearer - Block the bearer, and reset all its links
+ * tipc_block_bearer - Block the bearer with the given name, and reset all its links
*/
-int tipc_block_bearer(struct tipc_bearer *b_ptr)
+int tipc_block_bearer(const char *name)
{
+ struct tipc_bearer *b_ptr = NULL;
struct tipc_link *l_ptr;
struct tipc_link *temp_l_ptr;
read_lock_bh(&tipc_net_lock);
- pr_info("Blocking bearer <%s>\n", b_ptr->name);
+ b_ptr = tipc_bearer_find(name);
+ if (!b_ptr) {
+ pr_warn("Attempt to block unknown bearer <%s>\n", name);
+ read_unlock_bh(&tipc_net_lock);
+ return -EINVAL;
+ }
+
+ pr_info("Blocking bearer <%s>\n", name);
spin_lock_bh(&b_ptr->lock);
b_ptr->blocked = 1;
list_for_each_entry_safe(l_ptr, temp_l_ptr, &b_ptr->links, link_list) {
@@ -457,7 +465,7 @@ static void bearer_disable(struct tipc_bearer *b_ptr)
pr_info("Disabling bearer <%s>\n", b_ptr->name);
spin_lock_bh(&b_ptr->lock);
b_ptr->blocked = 1;
- b_ptr->media->disable_media(b_ptr);
+ b_ptr->media->disable_bearer(b_ptr);
list_for_each_entry_safe(l_ptr, temp_l_ptr, &b_ptr->links, link_list) {
tipc_link_delete(l_ptr);
}
diff --git a/net/tipc/bearer.h b/net/tipc/bearer.h
index e5e04be..09c869a 100644
--- a/net/tipc/bearer.h
+++ b/net/tipc/bearer.h
@@ -75,8 +75,8 @@ struct tipc_bearer;
/**
* struct tipc_media - TIPC media information available to internal users
* @send_msg: routine which handles buffer transmission
- * @enable_media: routine which enables a media
- * @disable_media: routine which disables a media
+ * @enable_bearer: routine which enables a bearer
+ * @disable_bearer: routine which disables a bearer
* @addr2str: routine which converts media address to string
* @addr2msg: routine which converts media address to protocol message area
* @msg2addr: routine which converts media address from protocol message area
@@ -91,8 +91,8 @@ 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 (*enable_bearer)(struct tipc_bearer *b_ptr);
+ void (*disable_bearer)(struct tipc_bearer *b_ptr);
int (*addr2str)(struct tipc_media_addr *a, char *str_buf, int str_size);
int (*addr2msg)(struct tipc_media_addr *a, char *msg_area);
int (*msg2addr)(const struct tipc_bearer *b_ptr,
@@ -163,7 +163,7 @@ int tipc_register_media(struct tipc_media *m_ptr);
void tipc_recv_msg(struct sk_buff *buf, struct tipc_bearer *tb_ptr);
-int tipc_block_bearer(struct tipc_bearer *b_ptr);
+int tipc_block_bearer(const char *name);
void tipc_continue(struct tipc_bearer *tb_ptr);
int tipc_enable_bearer(const char *bearer_name, u32 disc_domain, u32 priority);
diff --git a/net/tipc/core.h b/net/tipc/core.h
index 94895d4..be72f8c 100644
--- a/net/tipc/core.h
+++ b/net/tipc/core.h
@@ -90,21 +90,21 @@ extern int tipc_random __read_mostly;
/*
* Routines available to privileged subsystems
*/
-int tipc_core_start_net(unsigned long);
-int tipc_handler_start(void);
-void tipc_handler_stop(void);
-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);
+extern int tipc_core_start_net(unsigned long);
+extern int tipc_handler_start(void);
+extern void tipc_handler_stop(void);
+extern int tipc_netlink_start(void);
+extern void tipc_netlink_stop(void);
+extern int tipc_socket_init(void);
+extern void tipc_socket_stop(void);
+extern int tipc_sock_create_local(int type, struct socket **res);
+extern void tipc_sock_release_local(struct socket *sock);
+extern 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);
+extern int tipc_register_sysctl(void);
+extern void tipc_unregister_sysctl(void);
#else
#define tipc_register_sysctl() 0
#define tipc_unregister_sysctl()
@@ -201,6 +201,6 @@ 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);
+extern struct sk_buff *tipc_buf_acquire(u32 size);
#endif
diff --git a/net/tipc/eth_media.c b/net/tipc/eth_media.c
index f80d59f..40ea40c 100644
--- a/net/tipc/eth_media.c
+++ b/net/tipc/eth_media.c
@@ -2,7 +2,7 @@
* net/tipc/eth_media.c: Ethernet bearer support for TIPC
*
* Copyright (c) 2001-2007, Ericsson AB
- * Copyright (c) 2005-2008, 2011-2013, Wind River Systems
+ * Copyright (c) 2005-2008, 2011, Wind River Systems
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -37,19 +37,19 @@
#include "core.h"
#include "bearer.h"
-#define MAX_ETH_MEDIA MAX_BEARERS
+#define MAX_ETH_BEARERS MAX_BEARERS
#define ETH_ADDR_OFFSET 4 /* message header offset of MAC address */
/**
- * struct eth_media - Ethernet bearer data structure
+ * struct eth_bearer - Ethernet bearer data structure
* @bearer: ptr to associated "generic" bearer structure
* @dev: ptr to associated Ethernet network device
* @tipc_packet_type: used in binding TIPC to Ethernet driver
* @setup: work item used when enabling bearer
* @cleanup: work item used when disabling bearer
*/
-struct eth_media {
+struct eth_bearer {
struct tipc_bearer *bearer;
struct net_device *dev;
struct packet_type tipc_packet_type;
@@ -58,7 +58,7 @@ struct eth_media {
};
static struct tipc_media eth_media_info;
-static struct eth_media eth_media_array[MAX_ETH_MEDIA];
+static struct eth_bearer eth_bearers[MAX_ETH_BEARERS];
static int eth_started;
static int recv_notification(struct notifier_block *nb, unsigned long evt,
@@ -100,7 +100,7 @@ static int send_msg(struct sk_buff *buf, struct tipc_bearer *tb_ptr,
if (!clone)
return 0;
- dev = ((struct eth_media *)(tb_ptr->usr_handle))->dev;
+ dev = ((struct eth_bearer *)(tb_ptr->usr_handle))->dev;
delta = dev->hard_header_len - skb_headroom(buf);
if ((delta > 0) &&
@@ -128,43 +128,43 @@ static int send_msg(struct sk_buff *buf, struct tipc_bearer *tb_ptr,
static int recv_msg(struct sk_buff *buf, struct net_device *dev,
struct packet_type *pt, struct net_device *orig_dev)
{
- struct eth_media *eb_ptr = (struct eth_media *)pt->af_packet_priv;
+ struct eth_bearer *eb_ptr = (struct eth_bearer *)pt->af_packet_priv;
if (!net_eq(dev_net(dev), &init_net)) {
kfree_skb(buf);
- return NET_RX_DROP;
+ return 0;
}
if (likely(eb_ptr->bearer)) {
if (likely(buf->pkt_type <= PACKET_BROADCAST)) {
buf->next = NULL;
tipc_recv_msg(buf, eb_ptr->bearer);
- return NET_RX_SUCCESS;
+ return 0;
}
}
kfree_skb(buf);
- return NET_RX_DROP;
+ return 0;
}
/**
- * setup_media - setup association between Ethernet bearer and interface
+ * setup_bearer - setup association between Ethernet bearer and interface
*/
-static void setup_media(struct work_struct *work)
+static void setup_bearer(struct work_struct *work)
{
- struct eth_media *eb_ptr =
- container_of(work, struct eth_media, setup);
+ struct eth_bearer *eb_ptr =
+ container_of(work, struct eth_bearer, setup);
dev_add_pack(&eb_ptr->tipc_packet_type);
}
/**
- * enable_media - attach TIPC bearer to an Ethernet interface
+ * enable_bearer - attach TIPC bearer to an Ethernet interface
*/
-static int enable_media(struct tipc_bearer *tb_ptr)
+static int enable_bearer(struct tipc_bearer *tb_ptr)
{
struct net_device *dev;
- struct eth_media *eb_ptr = &eth_media_array[0];
- struct eth_media *stop = &eth_media_array[MAX_ETH_MEDIA];
+ struct eth_bearer *eb_ptr = &eth_bearers[0];
+ struct eth_bearer *stop = &eth_bearers[MAX_ETH_BEARERS];
char *driver_name = strchr((const char *)tb_ptr->name, ':') + 1;
int pending_dev = 0;
@@ -188,7 +188,7 @@ static int enable_media(struct tipc_bearer *tb_ptr)
eb_ptr->tipc_packet_type.func = recv_msg;
eb_ptr->tipc_packet_type.af_packet_priv = eb_ptr;
INIT_LIST_HEAD(&(eb_ptr->tipc_packet_type.list));
- INIT_WORK(&eb_ptr->setup, setup_media);
+ INIT_WORK(&eb_ptr->setup, setup_bearer);
schedule_work(&eb_ptr->setup);
/* Associate TIPC bearer with Ethernet bearer */
@@ -205,14 +205,14 @@ static int enable_media(struct tipc_bearer *tb_ptr)
}
/**
- * cleanup_media - break association between Ethernet bearer and interface
+ * cleanup_bearer - break association between Ethernet bearer and interface
*
* This routine must be invoked from a work queue because it can sleep.
*/
-static void cleanup_media(struct work_struct *work)
+static void cleanup_bearer(struct work_struct *work)
{
- struct eth_media *eb_ptr =
- container_of(work, struct eth_media, cleanup);
+ struct eth_bearer *eb_ptr =
+ container_of(work, struct eth_bearer, cleanup);
dev_remove_pack(&eb_ptr->tipc_packet_type);
dev_put(eb_ptr->dev);
@@ -220,18 +220,18 @@ static void cleanup_media(struct work_struct *work)
}
/**
- * disable_media - detach TIPC bearer from an Ethernet interface
+ * disable_bearer - detach TIPC bearer from an Ethernet interface
*
* Mark Ethernet 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.)
*/
-static void disable_media(struct tipc_bearer *tb_ptr)
+static void disable_bearer(struct tipc_bearer *tb_ptr)
{
- struct eth_media *eb_ptr = (struct eth_media *)tb_ptr->usr_handle;
+ struct eth_bearer *eb_ptr = (struct eth_bearer *)tb_ptr->usr_handle;
eb_ptr->bearer = NULL;
- INIT_WORK(&eb_ptr->cleanup, cleanup_media);
+ INIT_WORK(&eb_ptr->cleanup, cleanup_bearer);
schedule_work(&eb_ptr->cleanup);
}
@@ -245,8 +245,8 @@ static int recv_notification(struct notifier_block *nb, unsigned long evt,
void *ptr)
{
struct net_device *dev = netdev_notifier_info_to_dev(ptr);
- struct eth_media *eb_ptr = &eth_media_array[0];
- struct eth_media *stop = &eth_media_array[MAX_ETH_MEDIA];
+ struct eth_bearer *eb_ptr = &eth_bearers[0];
+ struct eth_bearer *stop = &eth_bearers[MAX_ETH_BEARERS];
if (!net_eq(dev_net(dev), &init_net))
return NOTIFY_DONE;
@@ -265,17 +265,17 @@ static int recv_notification(struct notifier_block *nb, unsigned long evt,
if (netif_carrier_ok(dev))
tipc_continue(eb_ptr->bearer);
else
- tipc_block_bearer(eb_ptr->bearer);
+ tipc_block_bearer(eb_ptr->bearer->name);
break;
case NETDEV_UP:
tipc_continue(eb_ptr->bearer);
break;
case NETDEV_DOWN:
- tipc_block_bearer(eb_ptr->bearer);
+ tipc_block_bearer(eb_ptr->bearer->name);
break;
case NETDEV_CHANGEMTU:
case NETDEV_CHANGEADDR:
- tipc_block_bearer(eb_ptr->bearer);
+ tipc_block_bearer(eb_ptr->bearer->name);
tipc_continue(eb_ptr->bearer);
break;
case NETDEV_UNREGISTER:
@@ -327,8 +327,8 @@ static int eth_msg2addr(const struct tipc_bearer *tb_ptr,
*/
static struct tipc_media eth_media_info = {
.send_msg = send_msg,
- .enable_media = enable_media,
- .disable_media = disable_media,
+ .enable_bearer = enable_bearer,
+ .disable_bearer = disable_bearer,
.addr2str = eth_addr2str,
.addr2msg = eth_addr2msg,
.msg2addr = eth_msg2addr,
diff --git a/net/tipc/ib_media.c b/net/tipc/ib_media.c
index c139892..9934a32 100644
--- a/net/tipc/ib_media.c
+++ b/net/tipc/ib_media.c
@@ -42,17 +42,17 @@
#include "core.h"
#include "bearer.h"
-#define MAX_IB_MEDIA MAX_BEARERS
+#define MAX_IB_BEARERS MAX_BEARERS
/**
- * struct ib_media - Infiniband media data structure
+ * struct ib_bearer - Infiniband bearer data structure
* @bearer: ptr to associated "generic" bearer structure
* @dev: ptr to associated Infiniband network device
* @tipc_packet_type: used in binding TIPC to Infiniband driver
* @cleanup: work item used when disabling bearer
*/
-struct ib_media {
+struct ib_bearer {
struct tipc_bearer *bearer;
struct net_device *dev;
struct packet_type tipc_packet_type;
@@ -61,7 +61,7 @@ struct ib_media {
};
static struct tipc_media ib_media_info;
-static struct ib_media ib_media_array[MAX_IB_MEDIA];
+static struct ib_bearer ib_bearers[MAX_IB_BEARERS];
static int ib_started;
/**
@@ -93,7 +93,7 @@ static int send_msg(struct sk_buff *buf, struct tipc_bearer *tb_ptr,
if (!clone)
return 0;
- dev = ((struct ib_media *)(tb_ptr->usr_handle))->dev;
+ dev = ((struct ib_bearer *)(tb_ptr->usr_handle))->dev;
delta = dev->hard_header_len - skb_headroom(buf);
if ((delta > 0) &&
@@ -121,43 +121,43 @@ static int send_msg(struct sk_buff *buf, struct tipc_bearer *tb_ptr,
static int recv_msg(struct sk_buff *buf, struct net_device *dev,
struct packet_type *pt, struct net_device *orig_dev)
{
- struct ib_media *ib_ptr = (struct ib_media *)pt->af_packet_priv;
+ struct ib_bearer *ib_ptr = (struct ib_bearer *)pt->af_packet_priv;
if (!net_eq(dev_net(dev), &init_net)) {
kfree_skb(buf);
- return NET_RX_DROP;
+ return 0;
}
if (likely(ib_ptr->bearer)) {
if (likely(buf->pkt_type <= PACKET_BROADCAST)) {
buf->next = NULL;
tipc_recv_msg(buf, ib_ptr->bearer);
- return NET_RX_SUCCESS;
+ return 0;
}
}
kfree_skb(buf);
- return NET_RX_DROP;
+ return 0;
}
/**
* setup_bearer - setup association between InfiniBand bearer and interface
*/
-static void setup_media(struct work_struct *work)
+static void setup_bearer(struct work_struct *work)
{
- struct ib_media *ib_ptr =
- container_of(work, struct ib_media, setup);
+ struct ib_bearer *ib_ptr =
+ container_of(work, struct ib_bearer, setup);
dev_add_pack(&ib_ptr->tipc_packet_type);
}
/**
- * enable_media - attach TIPC bearer to an InfiniBand interface
+ * enable_bearer - attach TIPC bearer to an InfiniBand interface
*/
-static int enable_media(struct tipc_bearer *tb_ptr)
+static int enable_bearer(struct tipc_bearer *tb_ptr)
{
struct net_device *dev;
- struct ib_media *ib_ptr = &ib_media_array[0];
- struct ib_media *stop = &ib_media_array[MAX_IB_MEDIA];
+ struct ib_bearer *ib_ptr = &ib_bearers[0];
+ struct ib_bearer *stop = &ib_bearers[MAX_IB_BEARERS];
char *driver_name = strchr((const char *)tb_ptr->name, ':') + 1;
int pending_dev = 0;
@@ -181,7 +181,7 @@ static int enable_media(struct tipc_bearer *tb_ptr)
ib_ptr->tipc_packet_type.func = recv_msg;
ib_ptr->tipc_packet_type.af_packet_priv = ib_ptr;
INIT_LIST_HEAD(&(ib_ptr->tipc_packet_type.list));
- INIT_WORK(&ib_ptr->setup, setup_media);
+ INIT_WORK(&ib_ptr->setup, setup_bearer);
schedule_work(&ib_ptr->setup);
/* Associate TIPC bearer with InfiniBand bearer */
@@ -204,8 +204,8 @@ static int enable_media(struct tipc_bearer *tb_ptr)
*/
static void cleanup_bearer(struct work_struct *work)
{
- struct ib_media *ib_ptr =
- container_of(work, struct ib_media, cleanup);
+ struct ib_bearer *ib_ptr =
+ container_of(work, struct ib_bearer, cleanup);
dev_remove_pack(&ib_ptr->tipc_packet_type);
dev_put(ib_ptr->dev);
@@ -213,15 +213,15 @@ static void cleanup_bearer(struct work_struct *work)
}
/**
- * disable_media - detach TIPC bearer from an InfiniBand interface
+ * disable_bearer - detach TIPC bearer from an InfiniBand interface
*
* Mark InfiniBand 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.)
*/
-static void disable_media(struct tipc_bearer *tb_ptr)
+static void disable_bearer(struct tipc_bearer *tb_ptr)
{
- struct ib_media *ib_ptr = (struct ib_media *)tb_ptr->usr_handle;
+ struct ib_bearer *ib_ptr = (struct ib_bearer *)tb_ptr->usr_handle;
ib_ptr->bearer = NULL;
INIT_WORK(&ib_ptr->cleanup, cleanup_bearer);
@@ -238,8 +238,8 @@ static int recv_notification(struct notifier_block *nb, unsigned long evt,
void *ptr)
{
struct net_device *dev = netdev_notifier_info_to_dev(ptr);
- struct ib_media *ib_ptr = &ib_media_array[0];
- struct ib_media *stop = &ib_media_array[MAX_IB_MEDIA];
+ struct ib_bearer *ib_ptr = &ib_bearers[0];
+ struct ib_bearer *stop = &ib_bearers[MAX_IB_BEARERS];
if (!net_eq(dev_net(dev), &init_net))
return NOTIFY_DONE;
@@ -258,17 +258,17 @@ static int recv_notification(struct notifier_block *nb, unsigned long evt,
if (netif_carrier_ok(dev))
tipc_continue(ib_ptr->bearer);
else
- tipc_block_bearer(ib_ptr->bearer);
+ tipc_block_bearer(ib_ptr->bearer->name);
break;
case NETDEV_UP:
tipc_continue(ib_ptr->bearer);
break;
case NETDEV_DOWN:
- tipc_block_bearer(ib_ptr->bearer);
+ tipc_block_bearer(ib_ptr->bearer->name);
break;
case NETDEV_CHANGEMTU:
case NETDEV_CHANGEADDR:
- tipc_block_bearer(ib_ptr->bearer);
+ tipc_block_bearer(ib_ptr->bearer->name);
tipc_continue(ib_ptr->bearer);
break;
case NETDEV_UNREGISTER:
@@ -323,8 +323,8 @@ static int ib_msg2addr(const struct tipc_bearer *tb_ptr,
*/
static struct tipc_media ib_media_info = {
.send_msg = send_msg,
- .enable_media = enable_media,
- .disable_media = disable_media,
+ .enable_bearer = enable_bearer,
+ .disable_bearer = disable_bearer,
.addr2str = ib_addr2str,
.addr2msg = ib_addr2msg,
.msg2addr = ib_msg2addr,
diff --git a/net/tipc/link.c b/net/tipc/link.c
index 69cd9bf..0cc3d90 100644
--- a/net/tipc/link.c
+++ b/net/tipc/link.c
@@ -75,6 +75,20 @@ static const char *link_unk_evt = "Unknown link event ";
*/
#define START_CHANGEOVER 100000u
+/**
+ * struct tipc_link_name - deconstructed link name
+ * @addr_local: network address of node at this end
+ * @if_local: name of interface at this end
+ * @addr_peer: network address of node at far end
+ * @if_peer: name of interface at far end
+ */
+struct tipc_link_name {
+ u32 addr_local;
+ char if_local[TIPC_MAX_IF_NAME];
+ u32 addr_peer;
+ char if_peer[TIPC_MAX_IF_NAME];
+};
+
static void link_handle_out_of_seq_msg(struct tipc_link *l_ptr,
struct sk_buff *buf);
static void link_recv_proto_msg(struct tipc_link *l_ptr, struct sk_buff *buf);
@@ -83,7 +97,8 @@ static int link_recv_changeover_msg(struct tipc_link **l_ptr,
static void link_set_supervision_props(struct tipc_link *l_ptr, u32 tolerance);
static int link_send_sections_long(struct tipc_port *sender,
struct iovec const *msg_sect,
- unsigned int len, u32 destnode);
+ u32 num_sect, unsigned int total_len,
+ u32 destnode);
static void link_state_event(struct tipc_link *l_ptr, u32 event);
static void link_reset_statistics(struct tipc_link *l_ptr);
static void link_print(struct tipc_link *l_ptr, const char *str);
@@ -146,6 +161,72 @@ int tipc_link_is_active(struct tipc_link *l_ptr)
}
/**
+ * link_name_validate - validate & (optionally) deconstruct tipc_link name
+ * @name: ptr to link name string
+ * @name_parts: ptr to area for link name components (or NULL if not needed)
+ *
+ * Returns 1 if link name is valid, otherwise 0.
+ */
+static int link_name_validate(const char *name,
+ struct tipc_link_name *name_parts)
+{
+ char name_copy[TIPC_MAX_LINK_NAME];
+ char *addr_local;
+ char *if_local;
+ char *addr_peer;
+ char *if_peer;
+ char dummy;
+ u32 z_local, c_local, n_local;
+ u32 z_peer, c_peer, n_peer;
+ u32 if_local_len;
+ u32 if_peer_len;
+
+ /* copy link name & ensure length is OK */
+ name_copy[TIPC_MAX_LINK_NAME - 1] = 0;
+ /* need above in case non-Posix strncpy() doesn't pad with nulls */
+ strncpy(name_copy, name, TIPC_MAX_LINK_NAME);
+ if (name_copy[TIPC_MAX_LINK_NAME - 1] != 0)
+ return 0;
+
+ /* ensure all component parts of link name are present */
+ addr_local = name_copy;
+ if_local = strchr(addr_local, ':');
+ if (if_local == NULL)
+ return 0;
+ *(if_local++) = 0;
+ addr_peer = strchr(if_local, '-');
+ if (addr_peer == NULL)
+ return 0;
+ *(addr_peer++) = 0;
+ if_local_len = addr_peer - if_local;
+ if_peer = strchr(addr_peer, ':');
+ if (if_peer == NULL)
+ return 0;
+ *(if_peer++) = 0;
+ if_peer_len = strlen(if_peer) + 1;
+
+ /* validate component parts of link name */
+ if ((sscanf(addr_local, "%u.%u.%u%c",
+ &z_local, &c_local, &n_local, &dummy) != 3) ||
+ (sscanf(addr_peer, "%u.%u.%u%c",
+ &z_peer, &c_peer, &n_peer, &dummy) != 3) ||
+ (z_local > 255) || (c_local > 4095) || (n_local > 4095) ||
+ (z_peer > 255) || (c_peer > 4095) || (n_peer > 4095) ||
+ (if_local_len <= 1) || (if_local_len > TIPC_MAX_IF_NAME) ||
+ (if_peer_len <= 1) || (if_peer_len > TIPC_MAX_IF_NAME))
+ return 0;
+
+ /* return link name components, if necessary */
+ if (name_parts) {
+ name_parts->addr_local = tipc_addr(z_local, c_local, n_local);
+ strcpy(name_parts->if_local, if_local);
+ name_parts->addr_peer = tipc_addr(z_peer, c_peer, n_peer);
+ strcpy(name_parts->if_peer, if_peer);
+ }
+ return 1;
+}
+
+/**
* link_timeout - handle expiration of link timer
* @l_ptr: pointer to link
*
@@ -404,9 +485,15 @@ static void link_release_outqueue(struct tipc_link *l_ptr)
*/
void tipc_link_reset_fragments(struct tipc_link *l_ptr)
{
- kfree_skb(l_ptr->reasm_head);
- l_ptr->reasm_head = NULL;
- l_ptr->reasm_tail = NULL;
+ struct sk_buff *buf = l_ptr->defragm_buf;
+ struct sk_buff *next;
+
+ while (buf) {
+ next = buf->next;
+ kfree_skb(buf);
+ buf = next;
+ }
+ l_ptr->defragm_buf = NULL;
}
/**
@@ -978,7 +1065,8 @@ static int link_send_buf_fast(struct tipc_link *l_ptr, struct sk_buff *buf,
*/
int tipc_link_send_sections_fast(struct tipc_port *sender,
struct iovec const *msg_sect,
- unsigned int len, u32 destaddr)
+ const u32 num_sect, unsigned int total_len,
+ u32 destaddr)
{
struct tipc_msg *hdr = &sender->phdr;
struct tipc_link *l_ptr;
@@ -992,7 +1080,8 @@ again:
* Try building message using port's max_pkt hint.
* (Must not hold any locks while building message.)
*/
- res = tipc_msg_build(hdr, msg_sect, len, sender->max_pkt, &buf);
+ res = tipc_msg_build(hdr, msg_sect, num_sect, total_len,
+ sender->max_pkt, &buf);
/* Exit if build request was invalid */
if (unlikely(res < 0))
return res;
@@ -1032,7 +1121,8 @@ exit:
if ((msg_hdr_sz(hdr) + res) <= sender->max_pkt)
goto again;
- return link_send_sections_long(sender, msg_sect, len,
+ return link_send_sections_long(sender, msg_sect,
+ num_sect, total_len,
destaddr);
}
tipc_node_unlock(node);
@@ -1043,8 +1133,8 @@ exit:
if (buf)
return tipc_reject_msg(buf, TIPC_ERR_NO_NODE);
if (res >= 0)
- return tipc_port_reject_sections(sender, hdr, msg_sect,
- len, TIPC_ERR_NO_NODE);
+ return tipc_port_reject_sections(sender, hdr, msg_sect, num_sect,
+ total_len, TIPC_ERR_NO_NODE);
return res;
}
@@ -1064,17 +1154,18 @@ exit:
*/
static int link_send_sections_long(struct tipc_port *sender,
struct iovec const *msg_sect,
- unsigned int len, u32 destaddr)
+ u32 num_sect, unsigned int total_len,
+ u32 destaddr)
{
struct tipc_link *l_ptr;
struct tipc_node *node;
struct tipc_msg *hdr = &sender->phdr;
- u32 dsz = len;
+ u32 dsz = total_len;
u32 max_pkt, fragm_sz, rest;
struct tipc_msg fragm_hdr;
struct sk_buff *buf, *buf_chain, *prev;
u32 fragm_crs, fragm_rest, hsz, sect_rest;
- const unchar __user *sect_crs;
+ const unchar *sect_crs;
int curr_sect;
u32 fragm_no;
int res = 0;
@@ -1116,7 +1207,7 @@ again:
if (!sect_rest) {
sect_rest = msg_sect[++curr_sect].iov_len;
- sect_crs = msg_sect[curr_sect].iov_base;
+ sect_crs = (const unchar *)msg_sect[curr_sect].iov_base;
}
if (sect_rest < fragm_rest)
@@ -1192,8 +1283,8 @@ reject:
buf = buf_chain->next;
kfree_skb(buf_chain);
}
- return tipc_port_reject_sections(sender, hdr, msg_sect,
- len, TIPC_ERR_NO_NODE);
+ return tipc_port_reject_sections(sender, hdr, msg_sect, num_sect,
+ total_len, TIPC_ERR_NO_NODE);
}
/* Append chain of fragments to send queue & send them */
@@ -1501,15 +1592,15 @@ void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *b_ptr)
/* Ensure bearer is still enabled */
if (unlikely(!b_ptr->active))
- goto discard;
+ goto cont;
/* Ensure message is well-formed */
if (unlikely(!link_recv_buf_validate(buf)))
- goto discard;
+ goto cont;
/* Ensure message data is a single contiguous unit */
if (unlikely(skb_linearize(buf)))
- goto discard;
+ goto cont;
/* Handle arrival of a non-unicast link message */
msg = buf_msg(buf);
@@ -1525,18 +1616,20 @@ void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *b_ptr)
/* Discard unicast link messages destined for another node */
if (unlikely(!msg_short(msg) &&
(msg_destnode(msg) != tipc_own_addr)))
- goto discard;
+ goto cont;
/* Locate neighboring node that sent message */
n_ptr = tipc_node_find(msg_prevnode(msg));
if (unlikely(!n_ptr))
- goto discard;
+ goto cont;
tipc_node_lock(n_ptr);
/* Locate unicast link endpoint that should handle message */
l_ptr = n_ptr->links[b_ptr->identity];
- if (unlikely(!l_ptr))
- goto unlock_discard;
+ if (unlikely(!l_ptr)) {
+ tipc_node_unlock(n_ptr);
+ goto cont;
+ }
/* Verify that communication with node is currently allowed */
if ((n_ptr->block_setup & WAIT_PEER_DOWN) &&
@@ -1546,8 +1639,10 @@ void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *b_ptr)
!msg_redundant_link(msg))
n_ptr->block_setup &= ~WAIT_PEER_DOWN;
- if (n_ptr->block_setup)
- goto unlock_discard;
+ if (n_ptr->block_setup) {
+ tipc_node_unlock(n_ptr);
+ goto cont;
+ }
/* Validate message sequence number info */
seq_no = msg_seqno(msg);
@@ -1583,100 +1678,98 @@ void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *b_ptr)
/* Now (finally!) process the incoming message */
protocol_check:
- if (unlikely(!link_working_working(l_ptr))) {
- if (msg_user(msg) == LINK_PROTOCOL) {
- link_recv_proto_msg(l_ptr, buf);
- head = link_insert_deferred_queue(l_ptr, head);
- tipc_node_unlock(n_ptr);
- continue;
- }
-
- /* Traffic message. Conditionally activate link */
- link_state_event(l_ptr, TRAFFIC_MSG_EVT);
-
- if (link_working_working(l_ptr)) {
- /* Re-insert buffer in front of queue */
- buf->next = head;
- head = buf;
+ if (likely(link_working_working(l_ptr))) {
+ if (likely(seq_no == mod(l_ptr->next_in_no))) {
+ l_ptr->next_in_no++;
+ if (unlikely(l_ptr->oldest_deferred_in))
+ head = link_insert_deferred_queue(l_ptr,
+ head);
+deliver:
+ if (likely(msg_isdata(msg))) {
+ tipc_node_unlock(n_ptr);
+ tipc_port_recv_msg(buf);
+ continue;
+ }
+ switch (msg_user(msg)) {
+ int ret;
+ case MSG_BUNDLER:
+ l_ptr->stats.recv_bundles++;
+ l_ptr->stats.recv_bundled +=
+ msg_msgcnt(msg);
+ tipc_node_unlock(n_ptr);
+ tipc_link_recv_bundle(buf);
+ continue;
+ case NAME_DISTRIBUTOR:
+ n_ptr->bclink.recv_permitted = true;
+ tipc_node_unlock(n_ptr);
+ tipc_named_recv(buf);
+ continue;
+ case BCAST_PROTOCOL:
+ tipc_link_recv_sync(n_ptr, buf);
+ tipc_node_unlock(n_ptr);
+ continue;
+ case CONN_MANAGER:
+ tipc_node_unlock(n_ptr);
+ tipc_port_recv_proto_msg(buf);
+ continue;
+ case MSG_FRAGMENTER:
+ l_ptr->stats.recv_fragments++;
+ ret = tipc_link_recv_fragment(
+ &l_ptr->defragm_buf,
+ &buf, &msg);
+ if (ret == 1) {
+ l_ptr->stats.recv_fragmented++;
+ goto deliver;
+ }
+ if (ret == -1)
+ l_ptr->next_in_no--;
+ break;
+ case CHANGEOVER_PROTOCOL:
+ type = msg_type(msg);
+ if (link_recv_changeover_msg(&l_ptr,
+ &buf)) {
+ msg = buf_msg(buf);
+ seq_no = msg_seqno(msg);
+ if (type == ORIGINAL_MSG)
+ goto deliver;
+ goto protocol_check;
+ }
+ break;
+ default:
+ kfree_skb(buf);
+ buf = NULL;
+ break;
+ }
tipc_node_unlock(n_ptr);
+ tipc_net_route_msg(buf);
continue;
}
- goto unlock_discard;
- }
-
- /* Link is now in state WORKING_WORKING */
- if (unlikely(seq_no != mod(l_ptr->next_in_no))) {
link_handle_out_of_seq_msg(l_ptr, buf);
head = link_insert_deferred_queue(l_ptr, head);
tipc_node_unlock(n_ptr);
continue;
}
- l_ptr->next_in_no++;
- if (unlikely(l_ptr->oldest_deferred_in))
+
+ /* Link is not in state WORKING_WORKING */
+ if (msg_user(msg) == LINK_PROTOCOL) {
+ link_recv_proto_msg(l_ptr, buf);
head = link_insert_deferred_queue(l_ptr, head);
-deliver:
- if (likely(msg_isdata(msg))) {
tipc_node_unlock(n_ptr);
- tipc_port_recv_msg(buf);
continue;
}
- switch (msg_user(msg)) {
- int ret;
- case MSG_BUNDLER:
- l_ptr->stats.recv_bundles++;
- l_ptr->stats.recv_bundled += msg_msgcnt(msg);
- tipc_node_unlock(n_ptr);
- tipc_link_recv_bundle(buf);
- continue;
- case NAME_DISTRIBUTOR:
- n_ptr->bclink.recv_permitted = true;
- tipc_node_unlock(n_ptr);
- tipc_named_recv(buf);
- continue;
- case BCAST_PROTOCOL:
- tipc_link_recv_sync(n_ptr, buf);
- tipc_node_unlock(n_ptr);
- continue;
- case CONN_MANAGER:
- tipc_node_unlock(n_ptr);
- tipc_port_recv_proto_msg(buf);
- continue;
- case MSG_FRAGMENTER:
- l_ptr->stats.recv_fragments++;
- ret = tipc_link_recv_fragment(&l_ptr->reasm_head,
- &l_ptr->reasm_tail,
- &buf);
- if (ret == LINK_REASM_COMPLETE) {
- l_ptr->stats.recv_fragmented++;
- msg = buf_msg(buf);
- goto deliver;
- }
- if (ret == LINK_REASM_ERROR)
- tipc_link_reset(l_ptr);
+
+ /* Traffic message. Conditionally activate link */
+ link_state_event(l_ptr, TRAFFIC_MSG_EVT);
+
+ if (link_working_working(l_ptr)) {
+ /* Re-insert buffer in front of queue */
+ buf->next = head;
+ head = buf;
tipc_node_unlock(n_ptr);
continue;
- case CHANGEOVER_PROTOCOL:
- type = msg_type(msg);
- if (link_recv_changeover_msg(&l_ptr, &buf)) {
- msg = buf_msg(buf);
- seq_no = msg_seqno(msg);
- if (type == ORIGINAL_MSG)
- goto deliver;
- goto protocol_check;
- }
- break;
- default:
- kfree_skb(buf);
- buf = NULL;
- break;
}
tipc_node_unlock(n_ptr);
- tipc_net_route_msg(buf);
- continue;
-unlock_discard:
-
- tipc_node_unlock(n_ptr);
-discard:
+cont:
kfree_skb(buf);
}
read_unlock_bh(&tipc_net_lock);
@@ -2339,48 +2432,114 @@ static int link_send_long_buf(struct tipc_link *l_ptr, struct sk_buff *buf)
}
/*
+ * A pending message being re-assembled must store certain values
+ * to handle subsequent fragments correctly. The following functions
+ * help storing these values in unused, available fields in the
+ * pending message. This makes dynamic memory allocation unnecessary.
+ */
+static void set_long_msg_seqno(struct sk_buff *buf, u32 seqno)
+{
+ msg_set_seqno(buf_msg(buf), seqno);
+}
+
+static u32 get_fragm_size(struct sk_buff *buf)
+{
+ return msg_ack(buf_msg(buf));
+}
+
+static void set_fragm_size(struct sk_buff *buf, u32 sz)
+{
+ msg_set_ack(buf_msg(buf), sz);
+}
+
+static u32 get_expected_frags(struct sk_buff *buf)
+{
+ return msg_bcast_ack(buf_msg(buf));
+}
+
+static void set_expected_frags(struct sk_buff *buf, u32 exp)
+{
+ msg_set_bcast_ack(buf_msg(buf), exp);
+}
+
+/*
* tipc_link_recv_fragment(): Called with node lock on. Returns
* the reassembled buffer if message is complete.
*/
-int tipc_link_recv_fragment(struct sk_buff **head, struct sk_buff **tail,
- struct sk_buff **fbuf)
-{
- struct sk_buff *frag = *fbuf;
- struct tipc_msg *msg = buf_msg(frag);
- u32 fragid = msg_type(msg);
- bool headstolen;
- int delta;
-
- skb_pull(frag, msg_hdr_sz(msg));
- if (fragid == FIRST_FRAGMENT) {
- if (*head || skb_unclone(frag, GFP_ATOMIC))
- goto out_free;
- *head = frag;
- skb_frag_list_init(*head);
+int tipc_link_recv_fragment(struct sk_buff **pending, struct sk_buff **fb,
+ struct tipc_msg **m)
+{
+ struct sk_buff *prev = NULL;
+ struct sk_buff *fbuf = *fb;
+ struct tipc_msg *fragm = buf_msg(fbuf);
+ struct sk_buff *pbuf = *pending;
+ u32 long_msg_seq_no = msg_long_msgno(fragm);
+
+ *fb = NULL;
+
+ /* Is there an incomplete message waiting for this fragment? */
+ while (pbuf && ((buf_seqno(pbuf) != long_msg_seq_no) ||
+ (msg_orignode(fragm) != msg_orignode(buf_msg(pbuf))))) {
+ prev = pbuf;
+ pbuf = pbuf->next;
+ }
+
+ if (!pbuf && (msg_type(fragm) == FIRST_FRAGMENT)) {
+ struct tipc_msg *imsg = (struct tipc_msg *)msg_data(fragm);
+ u32 msg_sz = msg_size(imsg);
+ u32 fragm_sz = msg_data_sz(fragm);
+ u32 exp_fragm_cnt;
+ u32 max = TIPC_MAX_USER_MSG_SIZE + NAMED_H_SIZE;
+
+ if (msg_type(imsg) == TIPC_MCAST_MSG)
+ max = TIPC_MAX_USER_MSG_SIZE + MCAST_H_SIZE;
+ if (fragm_sz == 0 || msg_size(imsg) > max) {
+ kfree_skb(fbuf);
+ return 0;
+ }
+ exp_fragm_cnt = msg_sz / fragm_sz + !!(msg_sz % fragm_sz);
+ pbuf = tipc_buf_acquire(msg_size(imsg));
+ if (pbuf != NULL) {
+ pbuf->next = *pending;
+ *pending = pbuf;
+ skb_copy_to_linear_data(pbuf, imsg,
+ msg_data_sz(fragm));
+ /* Prepare buffer for subsequent fragments. */
+ set_long_msg_seqno(pbuf, long_msg_seq_no);
+ set_fragm_size(pbuf, fragm_sz);
+ set_expected_frags(pbuf, exp_fragm_cnt - 1);
+ } else {
+ pr_debug("Link unable to reassemble fragmented message\n");
+ kfree_skb(fbuf);
+ return -1;
+ }
+ kfree_skb(fbuf);
+ return 0;
+ } else if (pbuf && (msg_type(fragm) != FIRST_FRAGMENT)) {
+ u32 dsz = msg_data_sz(fragm);
+ u32 fsz = get_fragm_size(pbuf);
+ u32 crs = ((msg_fragm_no(fragm) - 1) * fsz);
+ u32 exp_frags = get_expected_frags(pbuf) - 1;
+ skb_copy_to_linear_data_offset(pbuf, crs,
+ msg_data(fragm), dsz);
+ kfree_skb(fbuf);
+
+ /* Is message complete? */
+ if (exp_frags == 0) {
+ if (prev)
+ prev->next = pbuf->next;
+ else
+ *pending = pbuf->next;
+ msg_reset_reroute_cnt(buf_msg(pbuf));
+ *fb = pbuf;
+ *m = buf_msg(pbuf);
+ return 1;
+ }
+ set_expected_frags(pbuf, exp_frags);
return 0;
- } else if (*head &&
- skb_try_coalesce(*head, frag, &headstolen, &delta)) {
- kfree_skb_partial(frag, headstolen);
- } else {
- if (!*head)
- goto out_free;
- if (!skb_has_frag_list(*head))
- skb_shinfo(*head)->frag_list = frag;
- else
- (*tail)->next = frag;
- *tail = frag;
- (*head)->truesize += frag->truesize;
- }
- if (fragid == LAST_FRAGMENT) {
- *fbuf = *head;
- *tail = *head = NULL;
- return LINK_REASM_COMPLETE;
}
+ kfree_skb(fbuf);
return 0;
-out_free:
- pr_warn_ratelimited("Link unable to reassemble fragmented message\n");
- kfree_skb(*fbuf);
- return LINK_REASM_ERROR;
}
static void link_set_supervision_props(struct tipc_link *l_ptr, u32 tolerance)
@@ -2426,21 +2585,25 @@ void tipc_link_set_queue_limits(struct tipc_link *l_ptr, u32 window)
static struct tipc_link *link_find_link(const char *name,
struct tipc_node **node)
{
+ struct tipc_link_name link_name_parts;
+ struct tipc_bearer *b_ptr;
struct tipc_link *l_ptr;
- struct tipc_node *n_ptr;
- int i;
- list_for_each_entry(n_ptr, &tipc_node_list, list) {
- for (i = 0; i < MAX_BEARERS; i++) {
- l_ptr = n_ptr->links[i];
- if (l_ptr && !strcmp(l_ptr->name, name))
- goto found;
- }
- }
- l_ptr = NULL;
- n_ptr = NULL;
-found:
- *node = n_ptr;
+ if (!link_name_validate(name, &link_name_parts))
+ return NULL;
+
+ b_ptr = tipc_bearer_find_interface(link_name_parts.if_local);
+ if (!b_ptr)
+ return NULL;
+
+ *node = tipc_node_find(link_name_parts.addr_peer);
+ if (!*node)
+ return NULL;
+
+ l_ptr = (*node)->links[b_ptr->identity];
+ if (!l_ptr || strcmp(l_ptr->name, name))
+ return NULL;
+
return l_ptr;
}
@@ -2483,7 +2646,6 @@ static int link_cmd_set_value(const char *name, u32 new_value, u16 cmd)
struct tipc_link *l_ptr;
struct tipc_bearer *b_ptr;
struct tipc_media *m_ptr;
- int res = 0;
l_ptr = link_find_link(name, &node);
if (l_ptr) {
@@ -2506,12 +2668,9 @@ static int link_cmd_set_value(const char *name, u32 new_value, u16 cmd)
case TIPC_CMD_SET_LINK_WINDOW:
tipc_link_set_queue_limits(l_ptr, new_value);
break;
- default:
- res = -EINVAL;
- break;
}
tipc_node_unlock(node);
- return res;
+ return 0;
}
b_ptr = tipc_bearer_find(name);
@@ -2519,18 +2678,15 @@ static int link_cmd_set_value(const char *name, u32 new_value, u16 cmd)
switch (cmd) {
case TIPC_CMD_SET_LINK_TOL:
b_ptr->tolerance = new_value;
- break;
+ return 0;
case TIPC_CMD_SET_LINK_PRI:
b_ptr->priority = new_value;
- break;
+ return 0;
case TIPC_CMD_SET_LINK_WINDOW:
b_ptr->window = new_value;
- break;
- default:
- res = -EINVAL;
- break;
+ return 0;
}
- return res;
+ return -EINVAL;
}
m_ptr = tipc_media_find(name);
@@ -2539,18 +2695,15 @@ static int link_cmd_set_value(const char *name, u32 new_value, u16 cmd)
switch (cmd) {
case TIPC_CMD_SET_LINK_TOL:
m_ptr->tolerance = new_value;
- break;
+ return 0;
case TIPC_CMD_SET_LINK_PRI:
m_ptr->priority = new_value;
- break;
+ return 0;
case TIPC_CMD_SET_LINK_WINDOW:
m_ptr->window = new_value;
- break;
- default:
- res = -EINVAL;
- break;
+ return 0;
}
- return res;
+ return -EINVAL;
}
struct sk_buff *tipc_link_cmd_config(const void *req_tlv_area, int req_tlv_space,
diff --git a/net/tipc/link.h b/net/tipc/link.h
index 8a6c102..c048ed1 100644
--- a/net/tipc/link.h
+++ b/net/tipc/link.h
@@ -41,12 +41,6 @@
#include "node.h"
/*
- * Link reassembly status codes
- */
-#define LINK_REASM_ERROR -1
-#define LINK_REASM_COMPLETE 1
-
-/*
* Out-of-range value for link sequence numbers
*/
#define INVALID_LINK_SEQ 0x10000
@@ -140,8 +134,7 @@ struct tipc_stats {
* @next_out: ptr to first unsent outbound message in queue
* @waiting_ports: linked list of ports waiting for link congestion to abate
* @long_msg_seq_no: next identifier to use for outbound fragmented messages
- * @reasm_head: list head of partially reassembled inbound message fragments
- * @reasm_tail: last fragment received
+ * @defragm_buf: list of partially reassembled inbound message fragments
* @stats: collects statistics regarding link activity
*/
struct tipc_link {
@@ -203,10 +196,9 @@ struct tipc_link {
struct sk_buff *next_out;
struct list_head waiting_ports;
- /* Fragmentation/reassembly */
+ /* Fragmentation/defragmentation */
u32 long_msg_seq_no;
- struct sk_buff *reasm_head;
- struct sk_buff *reasm_tail;
+ struct sk_buff *defragm_buf;
/* Statistics */
struct tipc_stats stats;
@@ -235,11 +227,13 @@ int tipc_link_send_buf(struct tipc_link *l_ptr, struct sk_buff *buf);
u32 tipc_link_get_max_pkt(u32 dest, u32 selector);
int tipc_link_send_sections_fast(struct tipc_port *sender,
struct iovec const *msg_sect,
- unsigned int len, u32 destnode);
+ const u32 num_sect,
+ unsigned int total_len,
+ u32 destnode);
void tipc_link_recv_bundle(struct sk_buff *buf);
-int tipc_link_recv_fragment(struct sk_buff **reasm_head,
- struct sk_buff **reasm_tail,
- struct sk_buff **fbuf);
+int tipc_link_recv_fragment(struct sk_buff **pending,
+ struct sk_buff **fb,
+ struct tipc_msg **msg);
void tipc_link_send_proto_msg(struct tipc_link *l_ptr, u32 msg_typ, int prob,
u32 gap, u32 tolerance, u32 priority,
u32 acked_mtu);
diff --git a/net/tipc/msg.c b/net/tipc/msg.c
index e525f8c..ced60e2 100644
--- a/net/tipc/msg.c
+++ b/net/tipc/msg.c
@@ -73,13 +73,13 @@ void tipc_msg_init(struct tipc_msg *m, u32 user, u32 type, u32 hsize,
* Returns message data size or errno
*/
int tipc_msg_build(struct tipc_msg *hdr, struct iovec const *msg_sect,
- unsigned int len, int max_size, struct sk_buff **buf)
+ u32 num_sect, unsigned int total_len, int max_size,
+ struct sk_buff **buf)
{
- int dsz, sz, hsz;
- unsigned char *to;
+ int dsz, sz, hsz, pos, res, cnt;
- dsz = len;
- hsz = msg_hdr_sz(hdr);
+ dsz = total_len;
+ pos = hsz = msg_hdr_sz(hdr);
sz = hsz + dsz;
msg_set_size(hdr, sz);
if (unlikely(sz > max_size)) {
@@ -91,11 +91,16 @@ int tipc_msg_build(struct tipc_msg *hdr, struct iovec const *msg_sect,
if (!(*buf))
return -ENOMEM;
skb_copy_to_linear_data(*buf, hdr, hsz);
- to = (*buf)->data + hsz;
- if (len && memcpy_fromiovecend(to, msg_sect, 0, dsz)) {
- kfree_skb(*buf);
- *buf = NULL;
- return -EFAULT;
+ for (res = 1, cnt = 0; res && (cnt < num_sect); cnt++) {
+ skb_copy_to_linear_data_offset(*buf, pos,
+ msg_sect[cnt].iov_base,
+ msg_sect[cnt].iov_len);
+ pos += msg_sect[cnt].iov_len;
}
- return dsz;
+ if (likely(res))
+ return dsz;
+
+ kfree_skb(*buf);
+ *buf = NULL;
+ return -EFAULT;
}
diff --git a/net/tipc/msg.h b/net/tipc/msg.h
index 76d1269..5e4ccf5 100644
--- a/net/tipc/msg.h
+++ b/net/tipc/msg.h
@@ -554,6 +554,12 @@ static inline void msg_set_last_bcast(struct tipc_msg *m, u32 n)
msg_set_bits(m, 4, 16, 0xffff, n);
}
+
+static inline u32 msg_fragm_no(struct tipc_msg *m)
+{
+ return msg_bits(m, 4, 16, 0xffff);
+}
+
static inline void msg_set_fragm_no(struct tipc_msg *m, u32 n)
{
msg_set_bits(m, 4, 16, 0xffff, n);
@@ -570,6 +576,12 @@ static inline void msg_set_next_sent(struct tipc_msg *m, u32 n)
msg_set_bits(m, 4, 0, 0xffff, n);
}
+
+static inline u32 msg_long_msgno(struct tipc_msg *m)
+{
+ return msg_bits(m, 4, 0, 0xffff);
+}
+
static inline void msg_set_long_msgno(struct tipc_msg *m, u32 n)
{
msg_set_bits(m, 4, 0, 0xffff, n);
@@ -710,5 +722,6 @@ u32 tipc_msg_tot_importance(struct tipc_msg *m);
void tipc_msg_init(struct tipc_msg *m, u32 user, u32 type, u32 hsize,
u32 destnode);
int tipc_msg_build(struct tipc_msg *hdr, struct iovec const *msg_sect,
- unsigned int len, int max_size, struct sk_buff **buf);
+ u32 num_sect, unsigned int total_len, int max_size,
+ struct sk_buff **buf);
#endif
diff --git a/net/tipc/netlink.c b/net/tipc/netlink.c
index 9f72a63..8bcd498 100644
--- a/net/tipc/netlink.c
+++ b/net/tipc/netlink.c
@@ -76,11 +76,9 @@ static struct genl_family tipc_genl_family = {
.maxattr = 0,
};
-static struct genl_ops tipc_genl_ops[] = {
- {
- .cmd = TIPC_GENL_CMD,
- .doit = handle_cmd,
- },
+static struct genl_ops tipc_genl_ops = {
+ .cmd = TIPC_GENL_CMD,
+ .doit = handle_cmd,
};
static int tipc_genl_family_registered;
@@ -89,7 +87,8 @@ int tipc_netlink_start(void)
{
int res;
- res = genl_register_family_with_ops(&tipc_genl_family, tipc_genl_ops);
+ res = genl_register_family_with_ops(&tipc_genl_family,
+ &tipc_genl_ops, 1);
if (res) {
pr_err("Failed to register netlink interface\n");
return res;
diff --git a/net/tipc/node.c b/net/tipc/node.c
index 25100c0..6e6c434 100644
--- a/net/tipc/node.c
+++ b/net/tipc/node.c
@@ -298,10 +298,9 @@ static void node_lost_contact(struct tipc_node *n_ptr)
}
n_ptr->bclink.deferred_size = 0;
- if (n_ptr->bclink.reasm_head) {
- kfree_skb(n_ptr->bclink.reasm_head);
- n_ptr->bclink.reasm_head = NULL;
- n_ptr->bclink.reasm_tail = NULL;
+ if (n_ptr->bclink.defragm) {
+ kfree_skb(n_ptr->bclink.defragm);
+ n_ptr->bclink.defragm = NULL;
}
tipc_bclink_remove_node(n_ptr->addr);
diff --git a/net/tipc/node.h b/net/tipc/node.h
index e5e96c0..3c189b3 100644
--- a/net/tipc/node.h
+++ b/net/tipc/node.h
@@ -74,8 +74,7 @@
* @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_head: broadcast reassembly queue head from node
- * @reasm_tail: last broadcast fragment received from node
+ * @defragm: list of partially reassembled b'cast message fragments from node
* @recv_permitted: true if node is allowed to receive b'cast messages
*/
struct tipc_node {
@@ -99,8 +98,7 @@ struct tipc_node {
u32 deferred_size;
struct sk_buff *deferred_head;
struct sk_buff *deferred_tail;
- struct sk_buff *reasm_head;
- struct sk_buff *reasm_tail;
+ struct sk_buff *defragm;
bool recv_permitted;
} bclink;
};
diff --git a/net/tipc/port.c b/net/tipc/port.c
index c081a76..b3ed2fc 100644
--- a/net/tipc/port.c
+++ b/net/tipc/port.c
@@ -90,7 +90,8 @@ int tipc_port_peer_msg(struct tipc_port *p_ptr, struct tipc_msg *msg)
* tipc_multicast - send a multicast message to local and remote destinations
*/
int tipc_multicast(u32 ref, struct tipc_name_seq const *seq,
- struct iovec const *msg_sect, unsigned int len)
+ u32 num_sect, struct iovec const *msg_sect,
+ unsigned int total_len)
{
struct tipc_msg *hdr;
struct sk_buff *buf;
@@ -113,7 +114,8 @@ int tipc_multicast(u32 ref, struct tipc_name_seq const *seq,
msg_set_namelower(hdr, seq->lower);
msg_set_nameupper(hdr, seq->upper);
msg_set_hdr_sz(hdr, MCAST_H_SIZE);
- res = tipc_msg_build(hdr, msg_sect, len, MAX_MSG_SIZE, &buf);
+ res = tipc_msg_build(hdr, msg_sect, num_sect, total_len, MAX_MSG_SIZE,
+ &buf);
if (unlikely(!buf))
return res;
@@ -434,13 +436,14 @@ exit:
}
int tipc_port_reject_sections(struct tipc_port *p_ptr, struct tipc_msg *hdr,
- struct iovec const *msg_sect, unsigned int len,
- int err)
+ struct iovec const *msg_sect, u32 num_sect,
+ unsigned int total_len, int err)
{
struct sk_buff *buf;
int res;
- res = tipc_msg_build(hdr, msg_sect, len, MAX_MSG_SIZE, &buf);
+ res = tipc_msg_build(hdr, msg_sect, num_sect, total_len, MAX_MSG_SIZE,
+ &buf);
if (!buf)
return res;
@@ -915,14 +918,15 @@ int tipc_port_recv_msg(struct sk_buff *buf)
* tipc_port_recv_sections(): Concatenate and deliver sectioned
* message for this node.
*/
-static int tipc_port_recv_sections(struct tipc_port *sender,
+static int tipc_port_recv_sections(struct tipc_port *sender, unsigned int num_sect,
struct iovec const *msg_sect,
- unsigned int len)
+ unsigned int total_len)
{
struct sk_buff *buf;
int res;
- res = tipc_msg_build(&sender->phdr, msg_sect, len, MAX_MSG_SIZE, &buf);
+ res = tipc_msg_build(&sender->phdr, msg_sect, num_sect, total_len,
+ MAX_MSG_SIZE, &buf);
if (likely(buf))
tipc_port_recv_msg(buf);
return res;
@@ -931,7 +935,8 @@ static int tipc_port_recv_sections(struct tipc_port *sender,
/**
* tipc_send - send message sections on connection
*/
-int tipc_send(u32 ref, struct iovec const *msg_sect, unsigned int len)
+int tipc_send(u32 ref, unsigned int num_sect, struct iovec const *msg_sect,
+ unsigned int total_len)
{
struct tipc_port *p_ptr;
u32 destnode;
@@ -945,10 +950,11 @@ int tipc_send(u32 ref, struct iovec const *msg_sect, unsigned int len)
if (!tipc_port_congested(p_ptr)) {
destnode = port_peernode(p_ptr);
if (likely(!in_own_node(destnode)))
- res = tipc_link_send_sections_fast(p_ptr, msg_sect,
- len, destnode);
+ res = tipc_link_send_sections_fast(p_ptr, msg_sect, num_sect,
+ total_len, destnode);
else
- res = tipc_port_recv_sections(p_ptr, msg_sect, len);
+ res = tipc_port_recv_sections(p_ptr, num_sect, msg_sect,
+ total_len);
if (likely(res != -ELINKCONG)) {
p_ptr->congested = 0;
@@ -959,7 +965,7 @@ int tipc_send(u32 ref, struct iovec const *msg_sect, unsigned int len)
}
if (port_unreliable(p_ptr)) {
p_ptr->congested = 0;
- return len;
+ return total_len;
}
return -ELINKCONG;
}
@@ -968,7 +974,8 @@ int tipc_send(u32 ref, struct iovec const *msg_sect, unsigned int len)
* tipc_send2name - send message sections to port name
*/
int tipc_send2name(u32 ref, struct tipc_name const *name, unsigned int domain,
- struct iovec const *msg_sect, unsigned int len)
+ unsigned int num_sect, struct iovec const *msg_sect,
+ unsigned int total_len)
{
struct tipc_port *p_ptr;
struct tipc_msg *msg;
@@ -992,32 +999,36 @@ int tipc_send2name(u32 ref, struct tipc_name const *name, unsigned int domain,
if (likely(destport || destnode)) {
if (likely(in_own_node(destnode)))
- res = tipc_port_recv_sections(p_ptr, msg_sect, len);
+ res = tipc_port_recv_sections(p_ptr, num_sect,
+ msg_sect, total_len);
else if (tipc_own_addr)
res = tipc_link_send_sections_fast(p_ptr, msg_sect,
- len, destnode);
+ num_sect, total_len,
+ destnode);
else
res = tipc_port_reject_sections(p_ptr, msg, msg_sect,
- len, TIPC_ERR_NO_NODE);
+ num_sect, total_len,
+ TIPC_ERR_NO_NODE);
if (likely(res != -ELINKCONG)) {
if (res > 0)
p_ptr->sent++;
return res;
}
if (port_unreliable(p_ptr)) {
- return len;
+ return total_len;
}
return -ELINKCONG;
}
- return tipc_port_reject_sections(p_ptr, msg, msg_sect, len,
- TIPC_ERR_NO_NAME);
+ return tipc_port_reject_sections(p_ptr, msg, msg_sect, num_sect,
+ total_len, TIPC_ERR_NO_NAME);
}
/**
* tipc_send2port - send message sections to port identity
*/
int tipc_send2port(u32 ref, struct tipc_portid const *dest,
- struct iovec const *msg_sect, unsigned int len)
+ unsigned int num_sect, struct iovec const *msg_sect,
+ unsigned int total_len)
{
struct tipc_port *p_ptr;
struct tipc_msg *msg;
@@ -1035,20 +1046,21 @@ int tipc_send2port(u32 ref, struct tipc_portid const *dest,
msg_set_hdr_sz(msg, BASIC_H_SIZE);
if (in_own_node(dest->node))
- res = tipc_port_recv_sections(p_ptr, msg_sect, len);
+ res = tipc_port_recv_sections(p_ptr, num_sect, msg_sect,
+ total_len);
else if (tipc_own_addr)
- res = tipc_link_send_sections_fast(p_ptr, msg_sect, len,
- dest->node);
+ res = tipc_link_send_sections_fast(p_ptr, msg_sect, num_sect,
+ total_len, dest->node);
else
- res = tipc_port_reject_sections(p_ptr, msg, msg_sect, len,
- TIPC_ERR_NO_NODE);
+ res = tipc_port_reject_sections(p_ptr, msg, msg_sect, num_sect,
+ total_len, TIPC_ERR_NO_NODE);
if (likely(res != -ELINKCONG)) {
if (res > 0)
p_ptr->sent++;
return res;
}
if (port_unreliable(p_ptr)) {
- return len;
+ return total_len;
}
return -ELINKCONG;
}
diff --git a/net/tipc/port.h b/net/tipc/port.h
index 9122535..5a7026b 100644
--- a/net/tipc/port.h
+++ b/net/tipc/port.h
@@ -151,20 +151,24 @@ int tipc_port_peer_msg(struct tipc_port *p_ptr, struct tipc_msg *msg);
* TIPC messaging routines
*/
int tipc_port_recv_msg(struct sk_buff *buf);
-int tipc_send(u32 portref, struct iovec const *msg_sect, unsigned int len);
+int tipc_send(u32 portref, unsigned int num_sect, struct iovec const *msg_sect,
+ unsigned int total_len);
int tipc_send2name(u32 portref, struct tipc_name const *name, u32 domain,
- struct iovec const *msg_sect, unsigned int len);
+ unsigned int num_sect, struct iovec const *msg_sect,
+ unsigned int total_len);
int tipc_send2port(u32 portref, struct tipc_portid const *dest,
- struct iovec const *msg_sect, unsigned int len);
+ unsigned int num_sect, struct iovec const *msg_sect,
+ unsigned int total_len);
int tipc_multicast(u32 portref, struct tipc_name_seq const *seq,
- struct iovec const *msg, unsigned int len);
+ unsigned int section_count, struct iovec const *msg,
+ unsigned int total_len);
int tipc_port_reject_sections(struct tipc_port *p_ptr, struct tipc_msg *hdr,
- struct iovec const *msg_sect, unsigned int len,
- int err);
+ struct iovec const *msg_sect, u32 num_sect,
+ unsigned int total_len, int err);
struct sk_buff *tipc_port_get_ports(void);
void tipc_port_recv_proto_msg(struct sk_buff *buf);
void tipc_port_recv_mcast(struct sk_buff *buf, struct tipc_port_list *dp);
diff --git a/net/tipc/socket.c b/net/tipc/socket.c
index 3b61851..6cc7ddd 100644
--- a/net/tipc/socket.c
+++ b/net/tipc/socket.c
@@ -338,7 +338,7 @@ static int release(struct socket *sock)
buf = __skb_dequeue(&sk->sk_receive_queue);
if (buf == NULL)
break;
- if (TIPC_SKB_CB(buf)->handle != NULL)
+ if (TIPC_SKB_CB(buf)->handle != 0)
kfree_skb(buf);
else {
if ((sock->state == SS_CONNECTING) ||
@@ -622,11 +622,13 @@ static int send_msg(struct kiocb *iocb, struct socket *sock,
res = tipc_send2name(tport->ref,
&dest->addr.name.name,
dest->addr.name.domain,
+ m->msg_iovlen,
m->msg_iov,
total_len);
} else if (dest->addrtype == TIPC_ADDR_ID) {
res = tipc_send2port(tport->ref,
&dest->addr.id,
+ m->msg_iovlen,
m->msg_iov,
total_len);
} else if (dest->addrtype == TIPC_ADDR_MCAST) {
@@ -639,6 +641,7 @@ static int send_msg(struct kiocb *iocb, struct socket *sock,
break;
res = tipc_multicast(tport->ref,
&dest->addr.nameseq,
+ m->msg_iovlen,
m->msg_iov,
total_len);
}
@@ -704,7 +707,8 @@ static int send_packet(struct kiocb *iocb, struct socket *sock,
break;
}
- res = tipc_send(tport->ref, m->msg_iov, total_len);
+ res = tipc_send(tport->ref, m->msg_iovlen, m->msg_iov,
+ total_len);
if (likely(res != -ELINKCONG))
break;
if (timeout_val <= 0L) {
@@ -980,6 +984,9 @@ static int recv_msg(struct kiocb *iocb, struct socket *sock,
goto exit;
}
+ /* will be updated in set_orig_addr() if needed */
+ m->msg_namelen = 0;
+
timeout = sock_rcvtimeo(sk, flags & MSG_DONTWAIT);
restart:
@@ -1088,6 +1095,9 @@ static int recv_stream(struct kiocb *iocb, struct socket *sock,
goto exit;
}
+ /* will be updated in set_orig_addr() if needed */
+ m->msg_namelen = 0;
+
target = sock_rcvlowat(sk, flags & MSG_WAITALL, buf_len);
timeout = sock_rcvtimeo(sk, flags & MSG_DONTWAIT);
@@ -1358,7 +1368,7 @@ static u32 filter_rcv(struct sock *sk, struct sk_buff *buf)
return TIPC_ERR_OVERLOAD;
/* Enqueue message */
- TIPC_SKB_CB(buf)->handle = NULL;
+ TIPC_SKB_CB(buf)->handle = 0;
__skb_queue_tail(&sk->sk_receive_queue, buf);
skb_set_owner_r(buf, sk);
@@ -1681,7 +1691,7 @@ restart:
/* Disconnect and send a 'FIN+' or 'FIN-' message to peer */
buf = __skb_dequeue(&sk->sk_receive_queue);
if (buf) {
- if (TIPC_SKB_CB(buf)->handle != NULL) {
+ if (TIPC_SKB_CB(buf)->handle != 0) {
kfree_skb(buf);
goto restart;
}