Merge branch 'for-3.19' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup
[deliverable/linux.git] / net / tipc / net.c
index 93b9944a6a8bb1e94c332b8bd5e5f641d90899d8..cf13df3cde8f9ec48ddb8ee2f326e2caad9a25de 100644 (file)
 #include "node.h"
 #include "config.h"
 
+static const struct nla_policy tipc_nl_net_policy[TIPC_NLA_NET_MAX + 1] = {
+       [TIPC_NLA_NET_UNSPEC]   = { .type = NLA_UNSPEC },
+       [TIPC_NLA_NET_ID]       = { .type = NLA_U32 }
+};
+
 /*
  * The TIPC locking policy is designed to ensure a very fine locking
  * granularity, permitting complete parallel access to individual
@@ -138,3 +143,104 @@ void tipc_net_stop(void)
 
        pr_info("Left network mode\n");
 }
+
+static int __tipc_nl_add_net(struct tipc_nl_msg *msg)
+{
+       void *hdr;
+       struct nlattr *attrs;
+
+       hdr = genlmsg_put(msg->skb, msg->portid, msg->seq, &tipc_genl_v2_family,
+                         NLM_F_MULTI, TIPC_NL_NET_GET);
+       if (!hdr)
+               return -EMSGSIZE;
+
+       attrs = nla_nest_start(msg->skb, TIPC_NLA_NET);
+       if (!attrs)
+               goto msg_full;
+
+       if (nla_put_u32(msg->skb, TIPC_NLA_NET_ID, tipc_net_id))
+               goto attr_msg_full;
+
+       nla_nest_end(msg->skb, attrs);
+       genlmsg_end(msg->skb, hdr);
+
+       return 0;
+
+attr_msg_full:
+       nla_nest_cancel(msg->skb, attrs);
+msg_full:
+       genlmsg_cancel(msg->skb, hdr);
+
+       return -EMSGSIZE;
+}
+
+int tipc_nl_net_dump(struct sk_buff *skb, struct netlink_callback *cb)
+{
+       int err;
+       int done = cb->args[0];
+       struct tipc_nl_msg msg;
+
+       if (done)
+               return 0;
+
+       msg.skb = skb;
+       msg.portid = NETLINK_CB(cb->skb).portid;
+       msg.seq = cb->nlh->nlmsg_seq;
+
+       err = __tipc_nl_add_net(&msg);
+       if (err)
+               goto out;
+
+       done = 1;
+out:
+       cb->args[0] = done;
+
+       return skb->len;
+}
+
+int tipc_nl_net_set(struct sk_buff *skb, struct genl_info *info)
+{
+       int err;
+       struct nlattr *attrs[TIPC_NLA_NET_MAX + 1];
+
+       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_ID]) {
+               u32 val;
+
+               /* Can't change net id once TIPC has joined a network */
+               if (tipc_own_addr)
+                       return -EPERM;
+
+               val = nla_get_u32(attrs[TIPC_NLA_NET_ID]);
+               if (val < 1 || val > 9999)
+                       return -EINVAL;
+
+               tipc_net_id = val;
+       }
+
+       if (attrs[TIPC_NLA_NET_ADDR]) {
+               u32 addr;
+
+               /* Can't change net addr once TIPC has joined a network */
+               if (tipc_own_addr)
+                       return -EPERM;
+
+               addr = nla_get_u32(attrs[TIPC_NLA_NET_ADDR]);
+               if (!tipc_addr_node_valid(addr))
+                       return -EINVAL;
+
+               rtnl_lock();
+               tipc_net_start(addr);
+               rtnl_unlock();
+       }
+
+       return 0;
+}
This page took 0.024506 seconds and 5 git commands to generate.