mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-23 20:24:12 +08:00
tipc: eliminate buffer leak in bearer layer
When enabling a bearer we create a 'neigbor discoverer' instance by calling the function tipc_disc_create() before the bearer is actually registered in the list of enabled bearers. Because of this, the very first discovery broadcast message, created by the mentioned function, is lost, since it cannot find any valid bearer to use. Furthermore, the used send function, tipc_bearer_xmit_skb() does not free the given buffer when it cannot find a bearer, resulting in the leak of exactly one send buffer each time a bearer is enabled. This commit fixes this problem by introducing two changes: 1) Instead of attemting to send the discovery message directly, we let tipc_disc_create() return the discovery buffer to the calling function, tipc_enable_bearer(), so that the latter can send it when the enabling sequence is finished. 2) In tipc_bearer_xmit_skb(), as well as in the two other transmit functions at the bearer layer, we now free the indicated buffer or buffer chain when a valid bearer cannot be found. Acked-by: Ying Xue <ying.xue@windriver.com> Signed-off-by: Jon Maloy <jon.maloy@ericsson.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
ba35855e24
commit
4e801fa14f
@ -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;
|
||||
}
|
||||
|
||||
|
@ -268,10 +268,9 @@ exit:
|
||||
* Returns 0 if successful, otherwise -errno.
|
||||
*/
|
||||
int tipc_disc_create(struct net *net, struct tipc_bearer *b,
|
||||
struct tipc_media_addr *dest)
|
||||
struct tipc_media_addr *dest, struct sk_buff **skb)
|
||||
{
|
||||
struct tipc_link_req *req;
|
||||
struct sk_buff *skb;
|
||||
|
||||
req = kmalloc(sizeof(*req), GFP_ATOMIC);
|
||||
if (!req)
|
||||
@ -293,9 +292,7 @@ int tipc_disc_create(struct net *net, struct tipc_bearer *b,
|
||||
setup_timer(&req->timer, disc_timeout, (unsigned long)req);
|
||||
mod_timer(&req->timer, jiffies + req->timer_intv);
|
||||
b->link_req = req;
|
||||
skb = skb_clone(req->buf, GFP_ATOMIC);
|
||||
if (skb)
|
||||
tipc_bearer_xmit_skb(net, req->bearer_id, skb, &req->dest);
|
||||
*skb = skb_clone(req->buf, GFP_ATOMIC);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -40,7 +40,7 @@
|
||||
struct tipc_link_req;
|
||||
|
||||
int tipc_disc_create(struct net *net, struct tipc_bearer *b_ptr,
|
||||
struct tipc_media_addr *dest);
|
||||
struct tipc_media_addr *dest, struct sk_buff **skb);
|
||||
void tipc_disc_delete(struct tipc_link_req *req);
|
||||
void tipc_disc_reset(struct net *net, struct tipc_bearer *b_ptr);
|
||||
void tipc_disc_add_dest(struct tipc_link_req *req);
|
||||
|
Loading…
Reference in New Issue
Block a user