Skip to content

Commit

Permalink
Merge branch 'tipc'
Browse files Browse the repository at this point in the history
Jon Maloy says:

====================
tipc: cleanups in media and bearer layer

This commit series performs a number cleanups in order to make the
bearer and media part of the code more comprehensible and manageable.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Dec 11, 2013
2 parents 4ba3f99 + 77a7e07 commit fcfa1a1
Show file tree
Hide file tree
Showing 9 changed files with 311 additions and 747 deletions.
3 changes: 3 additions & 0 deletions include/linux/netdevice.h
Original file line number Diff line number Diff line change
Expand Up @@ -1282,6 +1282,9 @@ struct net_device {
#endif
#if IS_ENABLED(CONFIG_NET_DSA)
struct dsa_switch_tree *dsa_ptr; /* dsa specific data */
#endif
#if IS_ENABLED(CONFIG_TIPC)
struct tipc_bearer __rcu *tipc_ptr; /* TIPC specific data */
#endif
void *atalk_ptr; /* AppleTalk link */
struct in_device __rcu *ip_ptr; /* IPv4 specific data */
Expand Down
292 changes: 233 additions & 59 deletions net/tipc/bearer.c
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
/*
* net/tipc/bearer.c: TIPC bearer code
*
* Copyright (c) 1996-2006, Ericsson AB
* Copyright (c) 2004-2006, 2010-2011, Wind River Systems
* 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
Expand Down Expand Up @@ -41,8 +41,13 @@

#define MAX_ADDR_STR 60

static struct tipc_media *media_list[MAX_MEDIA];
static u32 media_count;
static struct tipc_media * const media_info_array[] = {
&eth_media_info,
#ifdef CONFIG_TIPC_MEDIA_IB
&ib_media_info,
#endif
NULL
};

struct tipc_bearer tipc_bearers[MAX_BEARERS];

Expand All @@ -55,11 +60,11 @@ struct tipc_media *tipc_media_find(const char *name)
{
u32 i;

for (i = 0; i < media_count; i++) {
if (!strcmp(media_list[i]->name, name))
return media_list[i];
for (i = 0; media_info_array[i] != NULL; i++) {
if (!strcmp(media_info_array[i]->name, name))
break;
}
return NULL;
return media_info_array[i];
}

/**
Expand All @@ -69,44 +74,11 @@ static struct tipc_media *media_find_id(u8 type)
{
u32 i;

for (i = 0; i < media_count; i++) {
if (media_list[i]->type_id == type)
return media_list[i];
for (i = 0; media_info_array[i] != NULL; i++) {
if (media_info_array[i]->type_id == type)
break;
}
return NULL;
}

/**
* tipc_register_media - register a media type
*
* Bearers for this media type must be activated separately at a later stage.
*/
int tipc_register_media(struct tipc_media *m_ptr)
{
int res = -EINVAL;

write_lock_bh(&tipc_net_lock);

if ((strlen(m_ptr->name) + 1) > TIPC_MAX_MEDIA_NAME)
goto exit;
if (m_ptr->priority > TIPC_MAX_LINK_PRI)
goto exit;
if ((m_ptr->tolerance < TIPC_MIN_LINK_TOL) ||
(m_ptr->tolerance > TIPC_MAX_LINK_TOL))
goto exit;
if (media_count >= MAX_MEDIA)
goto exit;
if (tipc_media_find(m_ptr->name) || media_find_id(m_ptr->type_id))
goto exit;

media_list[media_count] = m_ptr;
media_count++;
res = 0;
exit:
write_unlock_bh(&tipc_net_lock);
if (res)
pr_warn("Media <%s> registration error\n", m_ptr->name);
return res;
return media_info_array[i];
}

/**
Expand Down Expand Up @@ -144,13 +116,11 @@ struct sk_buff *tipc_media_get_names(void)
if (!buf)
return NULL;

read_lock_bh(&tipc_net_lock);
for (i = 0; i < media_count; i++) {
for (i = 0; media_info_array[i] != NULL; i++) {
tipc_cfg_append_tlv(buf, TIPC_TLV_MEDIA_NAME,
media_list[i]->name,
strlen(media_list[i]->name) + 1);
media_info_array[i]->name,
strlen(media_info_array[i]->name) + 1);
}
read_unlock_bh(&tipc_net_lock);
return buf;
}

Expand Down Expand Up @@ -239,21 +209,21 @@ struct tipc_bearer *tipc_bearer_find_interface(const char *if_name)
struct sk_buff *tipc_bearer_get_names(void)
{
struct sk_buff *buf;
struct tipc_bearer *b_ptr;
struct tipc_bearer *b;
int i, j;

buf = tipc_cfg_reply_alloc(MAX_BEARERS * TLV_SPACE(TIPC_MAX_BEARER_NAME));
if (!buf)
return NULL;

read_lock_bh(&tipc_net_lock);
for (i = 0; i < media_count; i++) {
for (i = 0; media_info_array[i] != NULL; i++) {
for (j = 0; j < MAX_BEARERS; j++) {
b_ptr = &tipc_bearers[j];
if (b_ptr->active && (b_ptr->media == media_list[i])) {
b = &tipc_bearers[j];
if (b->active && (b->media == media_info_array[i])) {
tipc_cfg_append_tlv(buf, TIPC_TLV_BEARER_NAME,
b_ptr->name,
strlen(b_ptr->name) + 1);
b->name,
strlen(b->name) + 1);
}
}
}
Expand Down Expand Up @@ -362,6 +332,7 @@ int tipc_enable_bearer(const char *name, u32 disc_domain, u32 priority)

b_ptr = &tipc_bearers[bearer_id];
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",
Expand All @@ -370,7 +341,6 @@ int tipc_enable_bearer(const char *name, u32 disc_domain, u32 priority)
}

b_ptr->identity = bearer_id;
b_ptr->media = m_ptr;
b_ptr->tolerance = m_ptr->tolerance;
b_ptr->window = m_ptr->window;
b_ptr->net_plane = bearer_id + 'A';
Expand All @@ -397,7 +367,7 @@ int tipc_enable_bearer(const char *name, u32 disc_domain, u32 priority)
/**
* tipc_reset_bearer - Reset all links established over this bearer
*/
int tipc_reset_bearer(struct tipc_bearer *b_ptr)
static int tipc_reset_bearer(struct tipc_bearer *b_ptr)
{
struct tipc_link *l_ptr;
struct tipc_link *temp_l_ptr;
Expand Down Expand Up @@ -463,6 +433,211 @@ int tipc_disable_bearer(const char *name)
}


/* tipc_l2_media_addr_set - initialize Ethernet media address structure
*
* Media-dependent "value" field stores MAC address in first 6 bytes
* and zeroes out the remaining bytes.
*/
void tipc_l2_media_addr_set(const struct tipc_bearer *b,
struct tipc_media_addr *a, char *mac)
{
int len = b->media->hwaddr_len;

if (unlikely(sizeof(a->value) < len)) {
WARN_ONCE(1, "Media length invalid\n");
return;
}

memcpy(a->value, mac, len);
memset(a->value + len, 0, sizeof(a->value) - len);
a->media_id = b->media->type_id;
a->broadcast = !memcmp(mac, b->bcast_addr.value, len);
}

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 Ethernet bearer */
b->media_ptr = dev;
memset(b->bcast_addr.value, 0, sizeof(b->bcast_addr.value));
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;
tipc_l2_media_addr_set(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 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.)
*/
void tipc_disable_l2_media(struct tipc_bearer *b)
{
struct net_device *dev = (struct net_device *)b->media_ptr;
RCU_INIT_POINTER(dev->tipc_ptr, NULL);
dev_put(dev);
}

/**
* tipc_l2_send_msg - send a TIPC packet out over an Ethernet interface
* @buf: the packet to be sent
* @b_ptr: the bearer throught 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;
int delta;
struct net_device *dev = (struct net_device *)b->media_ptr;

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(struct tipc_bearer *b, struct sk_buff *buf,
struct tipc_media_addr *dest)
{
b->media->send_msg(buf, b, dest);
}

/**
* 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(dev->tipc_ptr);
if (likely(b_ptr)) {
if (likely(buf->pkt_type <= PACKET_BROADCAST)) {
buf->next = NULL;
tipc_recv_msg(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;

rcu_read_lock();
b_ptr = rcu_dereference(dev->tipc_ptr);
if (!b_ptr) {
rcu_read_unlock();
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:
case NETDEV_CHANGEADDR:
tipc_reset_bearer(b_ptr);
break;
case NETDEV_UNREGISTER:
case NETDEV_CHANGENAME:
tipc_disable_bearer(b_ptr->name);
break;
}
rcu_read_unlock();

return NOTIFY_OK;
}

static struct packet_type tipc_packet_type __read_mostly = {
.type = __constant_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)
{
dev_add_pack(&tipc_packet_type);
return register_netdevice_notifier(&notifier);
}

void tipc_bearer_cleanup(void)
{
unregister_netdevice_notifier(&notifier);
dev_remove_pack(&tipc_packet_type);
}

void tipc_bearer_stop(void)
{
Expand All @@ -472,5 +647,4 @@ void tipc_bearer_stop(void)
if (tipc_bearers[i].active)
bearer_disable(&tipc_bearers[i]);
}
media_count = 0;
}
Loading

0 comments on commit fcfa1a1

Please sign in to comment.