tipc: fix default link prop regression in nl compat

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: 37e2d4843f (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>
This commit is contained in:
Richard Alpe 2015-05-06 13:58:54 +02:00 committed by David S. Miller
parent c035e183eb
commit c3d6fb85b2
2 changed files with 114 additions and 23 deletions

View 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;

View 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 @@ static int tipc_nl_compat_recv(struct sk_buff *skb, struct genl_info *info)
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;
}