tipc: add peer removal functionality
[cascardo/linux.git] / net / tipc / node.c
index 2197419..7e8b75f 100644 (file)
@@ -1553,6 +1553,69 @@ discard:
        kfree_skb(skb);
 }
 
+int tipc_nl_peer_rm(struct sk_buff *skb, struct genl_info *info)
+{
+       struct net *net = sock_net(skb->sk);
+       struct tipc_net *tn = net_generic(net, tipc_net_id);
+       struct nlattr *attrs[TIPC_NLA_NET_MAX + 1];
+       struct tipc_node *peer;
+       u32 addr;
+       int err;
+       int i;
+
+       /* We identify the peer by its net */
+       if (!info->attrs[TIPC_NLA_NET])
+               return -EINVAL;
+
+       err = nla_parse_nested(attrs, TIPC_NLA_NET_MAX,
+                              info->attrs[TIPC_NLA_NET],
+                              tipc_nl_net_policy);
+       if (err)
+               return err;
+
+       if (!attrs[TIPC_NLA_NET_ADDR])
+               return -EINVAL;
+
+       addr = nla_get_u32(attrs[TIPC_NLA_NET_ADDR]);
+
+       if (in_own_node(net, addr))
+               return -ENOTSUPP;
+
+       spin_lock_bh(&tn->node_list_lock);
+       peer = tipc_node_find(net, addr);
+       if (!peer) {
+               spin_unlock_bh(&tn->node_list_lock);
+               return -ENXIO;
+       }
+
+       tipc_node_write_lock(peer);
+       if (peer->state != SELF_DOWN_PEER_DOWN &&
+           peer->state != SELF_DOWN_PEER_LEAVING) {
+               tipc_node_write_unlock(peer);
+               err = -EBUSY;
+               goto err_out;
+       }
+
+       for (i = 0; i < MAX_BEARERS; i++) {
+               struct tipc_link_entry *le = &peer->links[i];
+
+               if (le->link) {
+                       kfree(le->link);
+                       le->link = NULL;
+                       peer->link_cnt--;
+               }
+       }
+       tipc_node_write_unlock(peer);
+       tipc_node_delete(peer);
+
+       err = 0;
+err_out:
+       tipc_node_put(peer);
+       spin_unlock_bh(&tn->node_list_lock);
+
+       return err;
+}
+
 int tipc_nl_node_dump(struct sk_buff *skb, struct netlink_callback *cb)
 {
        int err;