tipc: fix default link prop regression in nl compat
authorRichard Alpe <richard.alpe@ericsson.com>
Wed, 6 May 2015 11:58:54 +0000 (13:58 +0200)
committerDavid S. Miller <davem@davemloft.net>
Sat, 9 May 2015 20:40:02 +0000 (16:40 -0400)
Default link properties can be set for media or bearer. This
functionality was missed when introducing the NL compatibility layer.

This patch implements this functionality in the compat netlink
layer. It works the same way as it did in the old API. We search for
media and bearers matching the "link name". If we find a matching
media or bearer the link tolerance, priority or window is used as
default for new links on that media or bearer.

Fixes: 37e2d4843f9e (tipc: convert legacy nl link prop set to nl compat)
Reported-by: Tomi Ollila <tomi.ollila@iki.fi>
Signed-off-by: Richard Alpe <richard.alpe@ericsson.com>
Reviewed-by: Erik Hugne <erik.hugne@ericsson.com>
Reviewed-by: Ying Xue <ying.xue@windriver.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/tipc/bearer.c
net/tipc/netlink_compat.c

index 70e3dacbf84ab7a899298fca1fdcb2e77fd0c2d5..99c0bd43feede865d18c62995e870334ff2bd504 100644 (file)
@@ -812,7 +812,7 @@ int tipc_nl_bearer_set(struct sk_buff *skb, struct genl_info *info)
        char *name;
        struct tipc_bearer *b;
        struct nlattr *attrs[TIPC_NLA_BEARER_MAX + 1];
-       struct net *net = genl_info_net(info);
+       struct net *net = sock_net(skb->sk);
 
        if (!info->attrs[TIPC_NLA_BEARER])
                return -EINVAL;
index ce9121e8e990302d104902b977ce7304949de0ef..809aaf027876b995e7e6d8db3c645b0a7f4bda8b 100644 (file)
@@ -55,6 +55,7 @@ struct tipc_nl_compat_msg {
        int rep_type;
        int rep_size;
        int req_type;
+       struct net *net;
        struct sk_buff *rep;
        struct tlv_desc *req;
        struct sock *dst_sk;
@@ -68,7 +69,8 @@ struct tipc_nl_compat_cmd_dump {
 
 struct tipc_nl_compat_cmd_doit {
        int (*doit)(struct sk_buff *skb, struct genl_info *info);
-       int (*transcode)(struct sk_buff *skb, struct tipc_nl_compat_msg *msg);
+       int (*transcode)(struct tipc_nl_compat_cmd_doit *cmd,
+                        struct sk_buff *skb, struct tipc_nl_compat_msg *msg);
 };
 
 static int tipc_skb_tailroom(struct sk_buff *skb)
@@ -281,7 +283,7 @@ static int __tipc_nl_compat_doit(struct tipc_nl_compat_cmd_doit *cmd,
        if (!trans_buf)
                return -ENOMEM;
 
-       err = (*cmd->transcode)(trans_buf, msg);
+       err = (*cmd->transcode)(cmd, trans_buf, msg);
        if (err)
                goto trans_out;
 
@@ -353,7 +355,8 @@ static int tipc_nl_compat_bearer_dump(struct tipc_nl_compat_msg *msg,
                            nla_len(bearer[TIPC_NLA_BEARER_NAME]));
 }
 
-static int tipc_nl_compat_bearer_enable(struct sk_buff *skb,
+static int tipc_nl_compat_bearer_enable(struct tipc_nl_compat_cmd_doit *cmd,
+                                       struct sk_buff *skb,
                                        struct tipc_nl_compat_msg *msg)
 {
        struct nlattr *prop;
@@ -385,7 +388,8 @@ static int tipc_nl_compat_bearer_enable(struct sk_buff *skb,
        return 0;
 }
 
-static int tipc_nl_compat_bearer_disable(struct sk_buff *skb,
+static int tipc_nl_compat_bearer_disable(struct tipc_nl_compat_cmd_doit *cmd,
+                                        struct sk_buff *skb,
                                         struct tipc_nl_compat_msg *msg)
 {
        char *name;
@@ -576,11 +580,81 @@ static int tipc_nl_compat_link_dump(struct tipc_nl_compat_msg *msg,
                            &link_info, sizeof(link_info));
 }
 
-static int tipc_nl_compat_link_set(struct sk_buff *skb,
-                                  struct tipc_nl_compat_msg *msg)
+static int __tipc_add_link_prop(struct sk_buff *skb,
+                               struct tipc_nl_compat_msg *msg,
+                               struct tipc_link_config *lc)
+{
+       switch (msg->cmd) {
+       case TIPC_CMD_SET_LINK_PRI:
+               return nla_put_u32(skb, TIPC_NLA_PROP_PRIO, ntohl(lc->value));
+       case TIPC_CMD_SET_LINK_TOL:
+               return nla_put_u32(skb, TIPC_NLA_PROP_TOL, ntohl(lc->value));
+       case TIPC_CMD_SET_LINK_WINDOW:
+               return nla_put_u32(skb, TIPC_NLA_PROP_WIN, ntohl(lc->value));
+       }
+
+       return -EINVAL;
+}
+
+static int tipc_nl_compat_media_set(struct sk_buff *skb,
+                                   struct tipc_nl_compat_msg *msg)
 {
-       struct nlattr *link;
        struct nlattr *prop;
+       struct nlattr *media;
+       struct tipc_link_config *lc;
+
+       lc = (struct tipc_link_config *)TLV_DATA(msg->req);
+
+       media = nla_nest_start(skb, TIPC_NLA_MEDIA);
+       if (!media)
+               return -EMSGSIZE;
+
+       if (nla_put_string(skb, TIPC_NLA_MEDIA_NAME, lc->name))
+               return -EMSGSIZE;
+
+       prop = nla_nest_start(skb, TIPC_NLA_MEDIA_PROP);
+       if (!prop)
+               return -EMSGSIZE;
+
+       __tipc_add_link_prop(skb, msg, lc);
+       nla_nest_end(skb, prop);
+       nla_nest_end(skb, media);
+
+       return 0;
+}
+
+static int tipc_nl_compat_bearer_set(struct sk_buff *skb,
+                                    struct tipc_nl_compat_msg *msg)
+{
+       struct nlattr *prop;
+       struct nlattr *bearer;
+       struct tipc_link_config *lc;
+
+       lc = (struct tipc_link_config *)TLV_DATA(msg->req);
+
+       bearer = nla_nest_start(skb, TIPC_NLA_BEARER);
+       if (!bearer)
+               return -EMSGSIZE;
+
+       if (nla_put_string(skb, TIPC_NLA_BEARER_NAME, lc->name))
+               return -EMSGSIZE;
+
+       prop = nla_nest_start(skb, TIPC_NLA_BEARER_PROP);
+       if (!prop)
+               return -EMSGSIZE;
+
+       __tipc_add_link_prop(skb, msg, lc);
+       nla_nest_end(skb, prop);
+       nla_nest_end(skb, bearer);
+
+       return 0;
+}
+
+static int __tipc_nl_compat_link_set(struct sk_buff *skb,
+                                    struct tipc_nl_compat_msg *msg)
+{
+       struct nlattr *prop;
+       struct nlattr *link;
        struct tipc_link_config *lc;
 
        lc = (struct tipc_link_config *)TLV_DATA(msg->req);
@@ -596,24 +670,40 @@ static int tipc_nl_compat_link_set(struct sk_buff *skb,
        if (!prop)
                return -EMSGSIZE;
 
-       if (msg->cmd == TIPC_CMD_SET_LINK_PRI) {
-               if (nla_put_u32(skb, TIPC_NLA_PROP_PRIO, ntohl(lc->value)))
-                       return -EMSGSIZE;
-       } else if (msg->cmd == TIPC_CMD_SET_LINK_TOL) {
-               if (nla_put_u32(skb, TIPC_NLA_PROP_TOL, ntohl(lc->value)))
-                       return -EMSGSIZE;
-       } else if (msg->cmd == TIPC_CMD_SET_LINK_WINDOW) {
-               if (nla_put_u32(skb, TIPC_NLA_PROP_WIN, ntohl(lc->value)))
-                       return -EMSGSIZE;
-       }
-
+       __tipc_add_link_prop(skb, msg, lc);
        nla_nest_end(skb, prop);
        nla_nest_end(skb, link);
 
        return 0;
 }
 
-static int tipc_nl_compat_link_reset_stats(struct sk_buff *skb,
+static int tipc_nl_compat_link_set(struct tipc_nl_compat_cmd_doit *cmd,
+                                  struct sk_buff *skb,
+                                  struct tipc_nl_compat_msg *msg)
+{
+       struct tipc_link_config *lc;
+       struct tipc_bearer *bearer;
+       struct tipc_media *media;
+
+       lc = (struct tipc_link_config *)TLV_DATA(msg->req);
+
+       media = tipc_media_find(lc->name);
+       if (media) {
+               cmd->doit = &tipc_nl_media_set;
+               return tipc_nl_compat_media_set(skb, msg);
+       }
+
+       bearer = tipc_bearer_find(msg->net, lc->name);
+       if (bearer) {
+               cmd->doit = &tipc_nl_bearer_set;
+               return tipc_nl_compat_bearer_set(skb, msg);
+       }
+
+       return __tipc_nl_compat_link_set(skb, msg);
+}
+
+static int tipc_nl_compat_link_reset_stats(struct tipc_nl_compat_cmd_doit *cmd,
+                                          struct sk_buff *skb,
                                           struct tipc_nl_compat_msg *msg)
 {
        char *name;
@@ -851,7 +941,8 @@ static int tipc_nl_compat_node_dump(struct tipc_nl_compat_msg *msg,
                            sizeof(node_info));
 }
 
-static int tipc_nl_compat_net_set(struct sk_buff *skb,
+static int tipc_nl_compat_net_set(struct tipc_nl_compat_cmd_doit *cmd,
+                                 struct sk_buff *skb,
                                  struct tipc_nl_compat_msg *msg)
 {
        u32 val;
@@ -1007,7 +1098,6 @@ static int tipc_nl_compat_recv(struct sk_buff *skb, struct genl_info *info)
        struct nlmsghdr *req_nlh;
        struct nlmsghdr *rep_nlh;
        struct tipc_genlmsghdr *req_userhdr = info->userhdr;
-       struct net *net = genl_info_net(info);
 
        memset(&msg, 0, sizeof(msg));
 
@@ -1015,6 +1105,7 @@ static int tipc_nl_compat_recv(struct sk_buff *skb, struct genl_info *info)
        msg.req = nlmsg_data(req_nlh) + GENL_HDRLEN + TIPC_GENL_HDRLEN;
        msg.cmd = req_userhdr->cmd;
        msg.dst_sk = info->dst_sk;
+       msg.net = genl_info_net(info);
 
        if ((msg.cmd & 0xC000) && (!netlink_net_capable(skb, CAP_NET_ADMIN))) {
                msg.rep = tipc_get_err_tlv(TIPC_CFG_NOT_NET_ADMIN);
@@ -1043,7 +1134,7 @@ send:
        rep_nlh = nlmsg_hdr(msg.rep);
        memcpy(rep_nlh, info->nlhdr, len);
        rep_nlh->nlmsg_len = msg.rep->len;
-       genlmsg_unicast(net, msg.rep, NETLINK_CB(skb).portid);
+       genlmsg_unicast(msg.net, msg.rep, NETLINK_CB(skb).portid);
 
        return err;
 }