|
@@ -56,6 +56,13 @@ static struct tipc_media * const media_info_array[] = {
|
|
|
NULL
|
|
|
};
|
|
|
|
|
|
+static struct tipc_bearer *bearer_get(struct net *net, int bearer_id)
|
|
|
+{
|
|
|
+ struct tipc_net *tn = tipc_net(net);
|
|
|
+
|
|
|
+ return rcu_dereference_rtnl(tn->bearer_list[bearer_id]);
|
|
|
+}
|
|
|
+
|
|
|
static void bearer_disable(struct net *net, struct tipc_bearer *b);
|
|
|
|
|
|
/**
|
|
@@ -323,6 +330,7 @@ restart:
|
|
|
b->domain = disc_domain;
|
|
|
b->net_plane = bearer_id + 'A';
|
|
|
b->priority = priority;
|
|
|
+ test_and_set_bit_lock(0, &b->up);
|
|
|
|
|
|
res = tipc_disc_create(net, b, &b->bcast_addr, &skb);
|
|
|
if (res) {
|
|
@@ -360,15 +368,24 @@ static int tipc_reset_bearer(struct net *net, struct tipc_bearer *b)
|
|
|
*/
|
|
|
void tipc_bearer_reset_all(struct net *net)
|
|
|
{
|
|
|
- struct tipc_net *tn = tipc_net(net);
|
|
|
struct tipc_bearer *b;
|
|
|
int i;
|
|
|
|
|
|
for (i = 0; i < MAX_BEARERS; i++) {
|
|
|
- b = rcu_dereference_rtnl(tn->bearer_list[i]);
|
|
|
+ b = bearer_get(net, i);
|
|
|
+ if (b)
|
|
|
+ clear_bit_unlock(0, &b->up);
|
|
|
+ }
|
|
|
+ for (i = 0; i < MAX_BEARERS; i++) {
|
|
|
+ b = bearer_get(net, i);
|
|
|
if (b)
|
|
|
tipc_reset_bearer(net, b);
|
|
|
}
|
|
|
+ for (i = 0; i < MAX_BEARERS; i++) {
|
|
|
+ b = bearer_get(net, i);
|
|
|
+ if (b)
|
|
|
+ test_and_set_bit_lock(0, &b->up);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -382,8 +399,9 @@ static void bearer_disable(struct net *net, struct tipc_bearer *b)
|
|
|
int bearer_id = b->identity;
|
|
|
|
|
|
pr_info("Disabling bearer <%s>\n", b->name);
|
|
|
- b->media->disable_media(b);
|
|
|
+ clear_bit_unlock(0, &b->up);
|
|
|
tipc_node_delete_links(net, bearer_id);
|
|
|
+ b->media->disable_media(b);
|
|
|
RCU_INIT_POINTER(b->media_ptr, NULL);
|
|
|
if (b->link_req)
|
|
|
tipc_disc_delete(b->link_req);
|
|
@@ -440,22 +458,16 @@ int tipc_l2_send_msg(struct net *net, struct sk_buff *skb,
|
|
|
{
|
|
|
struct net_device *dev;
|
|
|
int delta;
|
|
|
- void *tipc_ptr;
|
|
|
|
|
|
dev = (struct net_device *)rcu_dereference_rtnl(b->media_ptr);
|
|
|
if (!dev)
|
|
|
return 0;
|
|
|
|
|
|
- /* Send RESET message even if bearer is detached from device */
|
|
|
- tipc_ptr = rcu_dereference_rtnl(dev->tipc_ptr);
|
|
|
- if (unlikely(!tipc_ptr && !msg_is_reset(buf_msg(skb))))
|
|
|
- goto drop;
|
|
|
-
|
|
|
- delta = dev->hard_header_len - skb_headroom(skb);
|
|
|
- if ((delta > 0) &&
|
|
|
- pskb_expand_head(skb, SKB_DATA_ALIGN(delta), 0, GFP_ATOMIC))
|
|
|
- goto drop;
|
|
|
-
|
|
|
+ delta = SKB_DATA_ALIGN(dev->hard_header_len - skb_headroom(skb));
|
|
|
+ if ((delta > 0) && pskb_expand_head(skb, delta, 0, GFP_ATOMIC)) {
|
|
|
+ kfree_skb(skb);
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
skb_reset_network_header(skb);
|
|
|
skb->dev = dev;
|
|
|
skb->protocol = htons(ETH_P_TIPC);
|
|
@@ -463,9 +475,6 @@ int tipc_l2_send_msg(struct net *net, struct sk_buff *skb,
|
|
|
dev->dev_addr, skb->len);
|
|
|
dev_queue_xmit(skb);
|
|
|
return 0;
|
|
|
-drop:
|
|
|
- kfree_skb(skb);
|
|
|
- return 0;
|
|
|
}
|
|
|
|
|
|
int tipc_bearer_mtu(struct net *net, u32 bearer_id)
|
|
@@ -487,12 +496,12 @@ void tipc_bearer_xmit_skb(struct net *net, u32 bearer_id,
|
|
|
struct sk_buff *skb,
|
|
|
struct tipc_media_addr *dest)
|
|
|
{
|
|
|
- struct tipc_net *tn = tipc_net(net);
|
|
|
+ struct tipc_msg *hdr = buf_msg(skb);
|
|
|
struct tipc_bearer *b;
|
|
|
|
|
|
rcu_read_lock();
|
|
|
- b = rcu_dereference_rtnl(tn->bearer_list[bearer_id]);
|
|
|
- if (likely(b))
|
|
|
+ b = bearer_get(net, bearer_id);
|
|
|
+ if (likely(b && (test_bit(0, &b->up) || msg_is_reset(hdr))))
|
|
|
b->media->send_msg(net, skb, b, dest);
|
|
|
else
|
|
|
kfree_skb(skb);
|
|
@@ -505,7 +514,6 @@ void tipc_bearer_xmit(struct net *net, u32 bearer_id,
|
|
|
struct sk_buff_head *xmitq,
|
|
|
struct tipc_media_addr *dst)
|
|
|
{
|
|
|
- struct tipc_net *tn = net_generic(net, tipc_net_id);
|
|
|
struct tipc_bearer *b;
|
|
|
struct sk_buff *skb, *tmp;
|
|
|
|
|
@@ -513,12 +521,15 @@ void tipc_bearer_xmit(struct net *net, u32 bearer_id,
|
|
|
return;
|
|
|
|
|
|
rcu_read_lock();
|
|
|
- b = rcu_dereference_rtnl(tn->bearer_list[bearer_id]);
|
|
|
+ b = bearer_get(net, bearer_id);
|
|
|
if (unlikely(!b))
|
|
|
__skb_queue_purge(xmitq);
|
|
|
skb_queue_walk_safe(xmitq, skb, tmp) {
|
|
|
__skb_dequeue(xmitq);
|
|
|
- b->media->send_msg(net, skb, b, dst);
|
|
|
+ if (likely(test_bit(0, &b->up) || msg_is_reset(buf_msg(skb))))
|
|
|
+ b->media->send_msg(net, skb, b, dst);
|
|
|
+ else
|
|
|
+ kfree(skb);
|
|
|
}
|
|
|
rcu_read_unlock();
|
|
|
}
|
|
@@ -535,8 +546,8 @@ void tipc_bearer_bc_xmit(struct net *net, u32 bearer_id,
|
|
|
struct tipc_msg *hdr;
|
|
|
|
|
|
rcu_read_lock();
|
|
|
- b = rcu_dereference_rtnl(tn->bearer_list[bearer_id]);
|
|
|
- if (unlikely(!b))
|
|
|
+ b = bearer_get(net, bearer_id);
|
|
|
+ if (unlikely(!b || !test_bit(0, &b->up)))
|
|
|
__skb_queue_purge(xmitq);
|
|
|
skb_queue_walk_safe(xmitq, skb, tmp) {
|
|
|
hdr = buf_msg(skb);
|
|
@@ -566,7 +577,8 @@ static int tipc_l2_rcv_msg(struct sk_buff *skb, struct net_device *dev,
|
|
|
|
|
|
rcu_read_lock();
|
|
|
b = rcu_dereference_rtnl(dev->tipc_ptr);
|
|
|
- if (likely(b && (skb->pkt_type <= PACKET_BROADCAST))) {
|
|
|
+ if (likely(b && test_bit(0, &b->up) &&
|
|
|
+ (skb->pkt_type <= PACKET_BROADCAST))) {
|
|
|
skb->next = NULL;
|
|
|
tipc_rcv(dev_net(dev), skb, b);
|
|
|
rcu_read_unlock();
|
|
@@ -591,18 +603,9 @@ static int tipc_l2_device_event(struct notifier_block *nb, unsigned long evt,
|
|
|
{
|
|
|
struct net_device *dev = netdev_notifier_info_to_dev(ptr);
|
|
|
struct net *net = dev_net(dev);
|
|
|
- struct tipc_net *tn = tipc_net(net);
|
|
|
struct tipc_bearer *b;
|
|
|
- int i;
|
|
|
|
|
|
b = rtnl_dereference(dev->tipc_ptr);
|
|
|
- if (!b) {
|
|
|
- for (i = 0; i < MAX_BEARERS; b = NULL, i++) {
|
|
|
- b = rtnl_dereference(tn->bearer_list[i]);
|
|
|
- if (b && (b->media_ptr == dev))
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
if (!b)
|
|
|
return NOTIFY_DONE;
|
|
|
|
|
@@ -613,11 +616,10 @@ static int tipc_l2_device_event(struct notifier_block *nb, unsigned long evt,
|
|
|
if (netif_carrier_ok(dev))
|
|
|
break;
|
|
|
case NETDEV_UP:
|
|
|
- rcu_assign_pointer(dev->tipc_ptr, b);
|
|
|
+ test_and_set_bit_lock(0, &b->up);
|
|
|
break;
|
|
|
case NETDEV_GOING_DOWN:
|
|
|
- RCU_INIT_POINTER(dev->tipc_ptr, NULL);
|
|
|
- synchronize_net();
|
|
|
+ clear_bit_unlock(0, &b->up);
|
|
|
tipc_reset_bearer(net, b);
|
|
|
break;
|
|
|
case NETDEV_CHANGEMTU:
|