Commit 889750bd authored by David S. Miller's avatar David S. Miller

Merge branch 'tipc-next'

Jon Maloy says:

====================
tipc: some small fixes

When fix a minor buffer leak, and ensure that bearers filter packets
correctly while they are being shut down.

v2: Corrected typos in commit #3, as per feedback from S. Shtylyov
v3: Removed commit #3 from the series. Improved version will be
    re-submitted later.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents ba35855e 5b7066c3
...@@ -205,6 +205,7 @@ static int tipc_enable_bearer(struct net *net, const char *name, ...@@ -205,6 +205,7 @@ static int tipc_enable_bearer(struct net *net, const char *name,
struct tipc_bearer *b; struct tipc_bearer *b;
struct tipc_media *m; struct tipc_media *m;
struct tipc_bearer_names b_names; struct tipc_bearer_names b_names;
struct sk_buff *skb;
char addr_string[16]; char addr_string[16];
u32 bearer_id; u32 bearer_id;
u32 with_this_prio; u32 with_this_prio;
...@@ -301,7 +302,7 @@ static int tipc_enable_bearer(struct net *net, const char *name, ...@@ -301,7 +302,7 @@ static int tipc_enable_bearer(struct net *net, const char *name,
b->net_plane = bearer_id + 'A'; b->net_plane = bearer_id + 'A';
b->priority = priority; b->priority = priority;
res = tipc_disc_create(net, b, &b->bcast_addr); res = tipc_disc_create(net, b, &b->bcast_addr, &skb);
if (res) { if (res) {
bearer_disable(net, b); bearer_disable(net, b);
pr_warn("Bearer <%s> rejected, discovery object creation failed\n", pr_warn("Bearer <%s> rejected, discovery object creation failed\n",
...@@ -310,7 +311,8 @@ static int tipc_enable_bearer(struct net *net, const char *name, ...@@ -310,7 +311,8 @@ static int tipc_enable_bearer(struct net *net, const char *name,
} }
rcu_assign_pointer(tn->bearer_list[bearer_id], b); 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", pr_info("Enabled bearer <%s>, discovery domain %s, priority %u\n",
name, name,
tipc_addr_string_fill(addr_string, disc_domain), priority); tipc_addr_string_fill(addr_string, disc_domain), priority);
...@@ -335,23 +337,16 @@ static int tipc_reset_bearer(struct net *net, struct tipc_bearer *b) ...@@ -335,23 +337,16 @@ static int tipc_reset_bearer(struct net *net, struct tipc_bearer *b)
*/ */
static void bearer_disable(struct net *net, struct tipc_bearer *b) static void bearer_disable(struct net *net, struct tipc_bearer *b)
{ {
struct tipc_net *tn = net_generic(net, tipc_net_id); struct tipc_net *tn = tipc_net(net);
u32 i; int bearer_id = b->identity;
pr_info("Disabling bearer <%s>\n", b->name); pr_info("Disabling bearer <%s>\n", b->name);
b->media->disable_media(b); b->media->disable_media(b);
tipc_node_delete_links(net, bearer_id);
tipc_node_delete_links(net, b->identity);
RCU_INIT_POINTER(b->media_ptr, NULL); RCU_INIT_POINTER(b->media_ptr, NULL);
if (b->link_req) if (b->link_req)
tipc_disc_delete(b->link_req); tipc_disc_delete(b->link_req);
RCU_INIT_POINTER(tn->bearer_list[bearer_id], NULL);
for (i = 0; i < MAX_BEARERS; i++) {
if (b == rtnl_dereference(tn->bearer_list[i])) {
RCU_INIT_POINTER(tn->bearer_list[i], NULL);
break;
}
}
kfree_rcu(b, rcu); kfree_rcu(b, rcu);
} }
...@@ -394,7 +389,7 @@ void tipc_disable_l2_media(struct tipc_bearer *b) ...@@ -394,7 +389,7 @@ void tipc_disable_l2_media(struct tipc_bearer *b)
/** /**
* tipc_l2_send_msg - send a TIPC packet out over an L2 interface * tipc_l2_send_msg - send a TIPC packet out over an L2 interface
* @buf: the packet to be sent * @skb: the packet to be sent
* @b: the bearer through which the packet is to be sent * @b: the bearer through which the packet is to be sent
* @dest: peer destination address * @dest: peer destination address
*/ */
...@@ -403,17 +398,21 @@ int tipc_l2_send_msg(struct net *net, struct sk_buff *skb, ...@@ -403,17 +398,21 @@ int tipc_l2_send_msg(struct net *net, struct sk_buff *skb,
{ {
struct net_device *dev; struct net_device *dev;
int delta; int delta;
void *tipc_ptr;
dev = (struct net_device *)rcu_dereference_rtnl(b->media_ptr); dev = (struct net_device *)rcu_dereference_rtnl(b->media_ptr);
if (!dev) if (!dev)
return 0; return 0;
/* Send RESET message even if bearer is detached from device */
tipc_ptr = rtnl_dereference(dev->tipc_ptr);
if (unlikely(!tipc_ptr && !msg_is_reset(buf_msg(skb))))
goto drop;
delta = dev->hard_header_len - skb_headroom(skb); delta = dev->hard_header_len - skb_headroom(skb);
if ((delta > 0) && if ((delta > 0) &&
pskb_expand_head(skb, SKB_DATA_ALIGN(delta), 0, GFP_ATOMIC)) { pskb_expand_head(skb, SKB_DATA_ALIGN(delta), 0, GFP_ATOMIC))
kfree_skb(skb); goto drop;
return 0;
}
skb_reset_network_header(skb); skb_reset_network_header(skb);
skb->dev = dev; skb->dev = dev;
...@@ -422,6 +421,9 @@ int tipc_l2_send_msg(struct net *net, struct sk_buff *skb, ...@@ -422,6 +421,9 @@ int tipc_l2_send_msg(struct net *net, struct sk_buff *skb,
dev->dev_addr, skb->len); dev->dev_addr, skb->len);
dev_queue_xmit(skb); dev_queue_xmit(skb);
return 0; return 0;
drop:
kfree_skb(skb);
return 0;
} }
int tipc_bearer_mtu(struct net *net, u32 bearer_id) int tipc_bearer_mtu(struct net *net, u32 bearer_id)
...@@ -450,6 +452,8 @@ void tipc_bearer_xmit_skb(struct net *net, u32 bearer_id, ...@@ -450,6 +452,8 @@ void tipc_bearer_xmit_skb(struct net *net, u32 bearer_id,
b = rcu_dereference_rtnl(tn->bearer_list[bearer_id]); b = rcu_dereference_rtnl(tn->bearer_list[bearer_id]);
if (likely(b)) if (likely(b))
b->media->send_msg(net, skb, b, dest); b->media->send_msg(net, skb, b, dest);
else
kfree_skb(skb);
rcu_read_unlock(); rcu_read_unlock();
} }
...@@ -468,11 +472,11 @@ void tipc_bearer_xmit(struct net *net, u32 bearer_id, ...@@ -468,11 +472,11 @@ void tipc_bearer_xmit(struct net *net, u32 bearer_id,
rcu_read_lock(); rcu_read_lock();
b = rcu_dereference_rtnl(tn->bearer_list[bearer_id]); b = rcu_dereference_rtnl(tn->bearer_list[bearer_id]);
if (likely(b)) { if (unlikely(!b))
skb_queue_walk_safe(xmitq, skb, tmp) { __skb_queue_purge(xmitq);
__skb_dequeue(xmitq); skb_queue_walk_safe(xmitq, skb, tmp) {
b->media->send_msg(net, skb, b, dst); __skb_dequeue(xmitq);
} b->media->send_msg(net, skb, b, dst);
} }
rcu_read_unlock(); rcu_read_unlock();
} }
...@@ -490,14 +494,14 @@ void tipc_bearer_bc_xmit(struct net *net, u32 bearer_id, ...@@ -490,14 +494,14 @@ void tipc_bearer_bc_xmit(struct net *net, u32 bearer_id,
rcu_read_lock(); rcu_read_lock();
b = rcu_dereference_rtnl(tn->bearer_list[bearer_id]); b = rcu_dereference_rtnl(tn->bearer_list[bearer_id]);
if (likely(b)) { if (unlikely(!b))
skb_queue_walk_safe(xmitq, skb, tmp) { __skb_queue_purge(xmitq);
hdr = buf_msg(skb); skb_queue_walk_safe(xmitq, skb, tmp) {
msg_set_non_seq(hdr, 1); hdr = buf_msg(skb);
msg_set_mc_netid(hdr, net_id); msg_set_non_seq(hdr, 1);
__skb_dequeue(xmitq); msg_set_mc_netid(hdr, net_id);
b->media->send_msg(net, skb, b, &b->bcast_addr); __skb_dequeue(xmitq);
} b->media->send_msg(net, skb, b, &b->bcast_addr);
} }
rcu_read_unlock(); rcu_read_unlock();
} }
...@@ -513,24 +517,21 @@ void tipc_bearer_bc_xmit(struct net *net, u32 bearer_id, ...@@ -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 * ignores packets sent using interface multicast, and traffic sent to other
* nodes (which can happen if interface is running in promiscuous mode). * 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 packet_type *pt, struct net_device *orig_dev)
{ {
struct tipc_bearer *b; struct tipc_bearer *b;
rcu_read_lock(); rcu_read_lock();
b = rcu_dereference_rtnl(dev->tipc_ptr); b = rcu_dereference_rtnl(dev->tipc_ptr);
if (likely(b)) { if (likely(b && (skb->pkt_type <= PACKET_BROADCAST))) {
if (likely(buf->pkt_type <= PACKET_BROADCAST)) { skb->next = NULL;
buf->next = NULL; tipc_rcv(dev_net(dev), skb, b);
tipc_rcv(dev_net(dev), buf, b); rcu_read_unlock();
rcu_read_unlock(); return NET_RX_SUCCESS;
return NET_RX_SUCCESS;
}
} }
rcu_read_unlock(); rcu_read_unlock();
kfree_skb(skb);
kfree_skb(buf);
return NET_RX_DROP; return NET_RX_DROP;
} }
...@@ -548,9 +549,18 @@ static int tipc_l2_device_event(struct notifier_block *nb, unsigned long evt, ...@@ -548,9 +549,18 @@ 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_device *dev = netdev_notifier_info_to_dev(ptr);
struct net *net = dev_net(dev); struct net *net = dev_net(dev);
struct tipc_net *tn = tipc_net(net);
struct tipc_bearer *b; struct tipc_bearer *b;
int i;
b = rtnl_dereference(dev->tipc_ptr); 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) if (!b)
return NOTIFY_DONE; return NOTIFY_DONE;
...@@ -560,13 +570,20 @@ static int tipc_l2_device_event(struct notifier_block *nb, unsigned long evt, ...@@ -560,13 +570,20 @@ static int tipc_l2_device_event(struct notifier_block *nb, unsigned long evt,
case NETDEV_CHANGE: case NETDEV_CHANGE:
if (netif_carrier_ok(dev)) if (netif_carrier_ok(dev))
break; break;
case NETDEV_UP:
rcu_assign_pointer(dev->tipc_ptr, b);
break;
case NETDEV_GOING_DOWN: case NETDEV_GOING_DOWN:
RCU_INIT_POINTER(dev->tipc_ptr, NULL);
synchronize_net();
tipc_reset_bearer(net, b);
break;
case NETDEV_CHANGEMTU: case NETDEV_CHANGEMTU:
tipc_reset_bearer(net, b); tipc_reset_bearer(net, b);
break; break;
case NETDEV_CHANGEADDR: case NETDEV_CHANGEADDR:
b->media->raw2addr(b, &b->addr, b->media->raw2addr(b, &b->addr,
(char *)dev->dev_addr); (char *)dev->dev_addr);
tipc_reset_bearer(net, b); tipc_reset_bearer(net, b);
break; break;
case NETDEV_UNREGISTER: case NETDEV_UNREGISTER:
......
...@@ -268,10 +268,9 @@ static void disc_timeout(unsigned long data) ...@@ -268,10 +268,9 @@ static void disc_timeout(unsigned long data)
* Returns 0 if successful, otherwise -errno. * Returns 0 if successful, otherwise -errno.
*/ */
int tipc_disc_create(struct net *net, struct tipc_bearer *b, 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 tipc_link_req *req;
struct sk_buff *skb;
req = kmalloc(sizeof(*req), GFP_ATOMIC); req = kmalloc(sizeof(*req), GFP_ATOMIC);
if (!req) if (!req)
...@@ -293,9 +292,7 @@ int tipc_disc_create(struct net *net, struct tipc_bearer *b, ...@@ -293,9 +292,7 @@ int tipc_disc_create(struct net *net, struct tipc_bearer *b,
setup_timer(&req->timer, disc_timeout, (unsigned long)req); setup_timer(&req->timer, disc_timeout, (unsigned long)req);
mod_timer(&req->timer, jiffies + req->timer_intv); mod_timer(&req->timer, jiffies + req->timer_intv);
b->link_req = req; b->link_req = req;
skb = skb_clone(req->buf, GFP_ATOMIC); *skb = skb_clone(req->buf, GFP_ATOMIC);
if (skb)
tipc_bearer_xmit_skb(net, req->bearer_id, skb, &req->dest);
return 0; return 0;
} }
......
...@@ -40,7 +40,7 @@ ...@@ -40,7 +40,7 @@
struct tipc_link_req; struct tipc_link_req;
int tipc_disc_create(struct net *net, struct tipc_bearer *b_ptr, 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_delete(struct tipc_link_req *req);
void tipc_disc_reset(struct net *net, struct tipc_bearer *b_ptr); void tipc_disc_reset(struct net *net, struct tipc_bearer *b_ptr);
void tipc_disc_add_dest(struct tipc_link_req *req); void tipc_disc_add_dest(struct tipc_link_req *req);
......
...@@ -779,6 +779,11 @@ static inline bool msg_peer_node_is_up(struct tipc_msg *m) ...@@ -779,6 +779,11 @@ static inline bool msg_peer_node_is_up(struct tipc_msg *m)
return msg_redundant_link(m); return msg_redundant_link(m);
} }
static inline bool msg_is_reset(struct tipc_msg *hdr)
{
return (msg_user(hdr) == LINK_PROTOCOL) && (msg_type(hdr) == RESET_MSG);
}
struct sk_buff *tipc_buf_acquire(u32 size); struct sk_buff *tipc_buf_acquire(u32 size);
bool tipc_msg_validate(struct sk_buff *skb); bool tipc_msg_validate(struct sk_buff *skb);
bool tipc_msg_reverse(u32 own_addr, struct sk_buff **skb, int err); bool tipc_msg_reverse(u32 own_addr, struct sk_buff **skb, int err);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment