tipc: eliminate buffer leak in bearer layer
[cascardo/linux.git] / net / tipc / bearer.c
index 27a5406..20566e9 100644 (file)
@@ -205,6 +205,7 @@ static int tipc_enable_bearer(struct net *net, const char *name,
        struct tipc_bearer *b;
        struct tipc_media *m;
        struct tipc_bearer_names b_names;
+       struct sk_buff *skb;
        char addr_string[16];
        u32 bearer_id;
        u32 with_this_prio;
@@ -301,7 +302,7 @@ restart:
        b->net_plane = bearer_id + 'A';
        b->priority = priority;
 
-       res = tipc_disc_create(net, b, &b->bcast_addr);
+       res = tipc_disc_create(net, b, &b->bcast_addr, &skb);
        if (res) {
                bearer_disable(net, b);
                pr_warn("Bearer <%s> rejected, discovery object creation failed\n",
@@ -310,7 +311,8 @@ restart:
        }
 
        rcu_assign_pointer(tn->bearer_list[bearer_id], b);
-
+       if (skb)
+               tipc_bearer_xmit_skb(net, bearer_id, skb, &b->bcast_addr);
        pr_info("Enabled bearer <%s>, discovery domain %s, priority %u\n",
                name,
                tipc_addr_string_fill(addr_string, disc_domain), priority);
@@ -450,6 +452,8 @@ void tipc_bearer_xmit_skb(struct net *net, u32 bearer_id,
        b = rcu_dereference_rtnl(tn->bearer_list[bearer_id]);
        if (likely(b))
                b->media->send_msg(net, skb, b, dest);
+       else
+               kfree_skb(skb);
        rcu_read_unlock();
 }
 
@@ -468,11 +472,11 @@ void tipc_bearer_xmit(struct net *net, u32 bearer_id,
 
        rcu_read_lock();
        b = rcu_dereference_rtnl(tn->bearer_list[bearer_id]);
-       if (likely(b)) {
-               skb_queue_walk_safe(xmitq, skb, tmp) {
-                       __skb_dequeue(xmitq);
-                       b->media->send_msg(net, skb, b, dst);
-               }
+       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);
        }
        rcu_read_unlock();
 }
@@ -490,14 +494,14 @@ void tipc_bearer_bc_xmit(struct net *net, u32 bearer_id,
 
        rcu_read_lock();
        b = rcu_dereference_rtnl(tn->bearer_list[bearer_id]);
-       if (likely(b)) {
-               skb_queue_walk_safe(xmitq, skb, tmp) {
-                       hdr = buf_msg(skb);
-                       msg_set_non_seq(hdr, 1);
-                       msg_set_mc_netid(hdr, net_id);
-                       __skb_dequeue(xmitq);
-                       b->media->send_msg(net, skb, b, &b->bcast_addr);
-               }
+       if (unlikely(!b))
+               __skb_queue_purge(xmitq);
+       skb_queue_walk_safe(xmitq, skb, tmp) {
+               hdr = buf_msg(skb);
+               msg_set_non_seq(hdr, 1);
+               msg_set_mc_netid(hdr, net_id);
+               __skb_dequeue(xmitq);
+               b->media->send_msg(net, skb, b, &b->bcast_addr);
        }
        rcu_read_unlock();
 }
@@ -513,24 +517,21 @@ void tipc_bearer_bc_xmit(struct net *net, u32 bearer_id,
  * 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,
+static int tipc_l2_rcv_msg(struct sk_buff *skb, struct net_device *dev,
                           struct packet_type *pt, struct net_device *orig_dev)
 {
        struct tipc_bearer *b;
 
        rcu_read_lock();
        b = rcu_dereference_rtnl(dev->tipc_ptr);
-       if (likely(b)) {
-               if (likely(buf->pkt_type <= PACKET_BROADCAST)) {
-                       buf->next = NULL;
-                       tipc_rcv(dev_net(dev), buf, b);
-                       rcu_read_unlock();
-                       return NET_RX_SUCCESS;
-               }
+       if (likely(b && (skb->pkt_type <= PACKET_BROADCAST))) {
+               skb->next = NULL;
+               tipc_rcv(dev_net(dev), skb, b);
+               rcu_read_unlock();
+               return NET_RX_SUCCESS;
        }
        rcu_read_unlock();
-
-       kfree_skb(buf);
+       kfree_skb(skb);
        return NET_RX_DROP;
 }