diff options
Diffstat (limited to 'net/tipc/netlink_compat.c')
| -rw-r--r-- | net/tipc/netlink_compat.c | 137 |
1 files changed, 114 insertions, 23 deletions
diff --git a/net/tipc/netlink_compat.c b/net/tipc/netlink_compat.c index ce9121e8e990..53e0fee80086 100644 --- a/net/tipc/netlink_compat.c +++ b/net/tipc/netlink_compat.c | |||
| @@ -55,6 +55,7 @@ struct tipc_nl_compat_msg { | |||
| 55 | int rep_type; | 55 | int rep_type; |
| 56 | int rep_size; | 56 | int rep_size; |
| 57 | int req_type; | 57 | int req_type; |
| 58 | struct net *net; | ||
| 58 | struct sk_buff *rep; | 59 | struct sk_buff *rep; |
| 59 | struct tlv_desc *req; | 60 | struct tlv_desc *req; |
| 60 | struct sock *dst_sk; | 61 | struct sock *dst_sk; |
| @@ -68,7 +69,8 @@ struct tipc_nl_compat_cmd_dump { | |||
| 68 | 69 | ||
| 69 | struct tipc_nl_compat_cmd_doit { | 70 | struct tipc_nl_compat_cmd_doit { |
| 70 | int (*doit)(struct sk_buff *skb, struct genl_info *info); | 71 | int (*doit)(struct sk_buff *skb, struct genl_info *info); |
| 71 | int (*transcode)(struct sk_buff *skb, struct tipc_nl_compat_msg *msg); | 72 | int (*transcode)(struct tipc_nl_compat_cmd_doit *cmd, |
| 73 | struct sk_buff *skb, struct tipc_nl_compat_msg *msg); | ||
| 72 | }; | 74 | }; |
| 73 | 75 | ||
| 74 | static int tipc_skb_tailroom(struct sk_buff *skb) | 76 | 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, | |||
| 281 | if (!trans_buf) | 283 | if (!trans_buf) |
| 282 | return -ENOMEM; | 284 | return -ENOMEM; |
| 283 | 285 | ||
| 284 | err = (*cmd->transcode)(trans_buf, msg); | 286 | err = (*cmd->transcode)(cmd, trans_buf, msg); |
| 285 | if (err) | 287 | if (err) |
| 286 | goto trans_out; | 288 | goto trans_out; |
| 287 | 289 | ||
| @@ -353,7 +355,8 @@ static int tipc_nl_compat_bearer_dump(struct tipc_nl_compat_msg *msg, | |||
| 353 | nla_len(bearer[TIPC_NLA_BEARER_NAME])); | 355 | nla_len(bearer[TIPC_NLA_BEARER_NAME])); |
| 354 | } | 356 | } |
| 355 | 357 | ||
| 356 | static int tipc_nl_compat_bearer_enable(struct sk_buff *skb, | 358 | static int tipc_nl_compat_bearer_enable(struct tipc_nl_compat_cmd_doit *cmd, |
| 359 | struct sk_buff *skb, | ||
| 357 | struct tipc_nl_compat_msg *msg) | 360 | struct tipc_nl_compat_msg *msg) |
| 358 | { | 361 | { |
| 359 | struct nlattr *prop; | 362 | struct nlattr *prop; |
| @@ -385,7 +388,8 @@ static int tipc_nl_compat_bearer_enable(struct sk_buff *skb, | |||
| 385 | return 0; | 388 | return 0; |
| 386 | } | 389 | } |
| 387 | 390 | ||
| 388 | static int tipc_nl_compat_bearer_disable(struct sk_buff *skb, | 391 | static int tipc_nl_compat_bearer_disable(struct tipc_nl_compat_cmd_doit *cmd, |
| 392 | struct sk_buff *skb, | ||
| 389 | struct tipc_nl_compat_msg *msg) | 393 | struct tipc_nl_compat_msg *msg) |
| 390 | { | 394 | { |
| 391 | char *name; | 395 | char *name; |
| @@ -576,11 +580,81 @@ static int tipc_nl_compat_link_dump(struct tipc_nl_compat_msg *msg, | |||
| 576 | &link_info, sizeof(link_info)); | 580 | &link_info, sizeof(link_info)); |
| 577 | } | 581 | } |
| 578 | 582 | ||
| 579 | static int tipc_nl_compat_link_set(struct sk_buff *skb, | 583 | static int __tipc_add_link_prop(struct sk_buff *skb, |
| 580 | struct tipc_nl_compat_msg *msg) | 584 | struct tipc_nl_compat_msg *msg, |
| 585 | struct tipc_link_config *lc) | ||
| 586 | { | ||
| 587 | switch (msg->cmd) { | ||
| 588 | case TIPC_CMD_SET_LINK_PRI: | ||
| 589 | return nla_put_u32(skb, TIPC_NLA_PROP_PRIO, ntohl(lc->value)); | ||
| 590 | case TIPC_CMD_SET_LINK_TOL: | ||
| 591 | return nla_put_u32(skb, TIPC_NLA_PROP_TOL, ntohl(lc->value)); | ||
| 592 | case TIPC_CMD_SET_LINK_WINDOW: | ||
| 593 | return nla_put_u32(skb, TIPC_NLA_PROP_WIN, ntohl(lc->value)); | ||
| 594 | } | ||
| 595 | |||
| 596 | return -EINVAL; | ||
| 597 | } | ||
| 598 | |||
| 599 | static int tipc_nl_compat_media_set(struct sk_buff *skb, | ||
| 600 | struct tipc_nl_compat_msg *msg) | ||
| 581 | { | 601 | { |
| 582 | struct nlattr *link; | ||
| 583 | struct nlattr *prop; | 602 | struct nlattr *prop; |
| 603 | struct nlattr *media; | ||
| 604 | struct tipc_link_config *lc; | ||
| 605 | |||
| 606 | lc = (struct tipc_link_config *)TLV_DATA(msg->req); | ||
| 607 | |||
| 608 | media = nla_nest_start(skb, TIPC_NLA_MEDIA); | ||
| 609 | if (!media) | ||
| 610 | return -EMSGSIZE; | ||
| 611 | |||
| 612 | if (nla_put_string(skb, TIPC_NLA_MEDIA_NAME, lc->name)) | ||
| 613 | return -EMSGSIZE; | ||
| 614 | |||
| 615 | prop = nla_nest_start(skb, TIPC_NLA_MEDIA_PROP); | ||
| 616 | if (!prop) | ||
| 617 | return -EMSGSIZE; | ||
| 618 | |||
| 619 | __tipc_add_link_prop(skb, msg, lc); | ||
| 620 | nla_nest_end(skb, prop); | ||
| 621 | nla_nest_end(skb, media); | ||
| 622 | |||
| 623 | return 0; | ||
| 624 | } | ||
| 625 | |||
| 626 | static int tipc_nl_compat_bearer_set(struct sk_buff *skb, | ||
| 627 | struct tipc_nl_compat_msg *msg) | ||
| 628 | { | ||
| 629 | struct nlattr *prop; | ||
| 630 | struct nlattr *bearer; | ||
| 631 | struct tipc_link_config *lc; | ||
| 632 | |||
| 633 | lc = (struct tipc_link_config *)TLV_DATA(msg->req); | ||
| 634 | |||
| 635 | bearer = nla_nest_start(skb, TIPC_NLA_BEARER); | ||
| 636 | if (!bearer) | ||
| 637 | return -EMSGSIZE; | ||
| 638 | |||
| 639 | if (nla_put_string(skb, TIPC_NLA_BEARER_NAME, lc->name)) | ||
| 640 | return -EMSGSIZE; | ||
| 641 | |||
| 642 | prop = nla_nest_start(skb, TIPC_NLA_BEARER_PROP); | ||
| 643 | if (!prop) | ||
| 644 | return -EMSGSIZE; | ||
| 645 | |||
| 646 | __tipc_add_link_prop(skb, msg, lc); | ||
| 647 | nla_nest_end(skb, prop); | ||
| 648 | nla_nest_end(skb, bearer); | ||
| 649 | |||
| 650 | return 0; | ||
| 651 | } | ||
| 652 | |||
| 653 | static int __tipc_nl_compat_link_set(struct sk_buff *skb, | ||
| 654 | struct tipc_nl_compat_msg *msg) | ||
| 655 | { | ||
| 656 | struct nlattr *prop; | ||
| 657 | struct nlattr *link; | ||
| 584 | struct tipc_link_config *lc; | 658 | struct tipc_link_config *lc; |
| 585 | 659 | ||
| 586 | lc = (struct tipc_link_config *)TLV_DATA(msg->req); | 660 | lc = (struct tipc_link_config *)TLV_DATA(msg->req); |
| @@ -596,24 +670,40 @@ static int tipc_nl_compat_link_set(struct sk_buff *skb, | |||
| 596 | if (!prop) | 670 | if (!prop) |
| 597 | return -EMSGSIZE; | 671 | return -EMSGSIZE; |
| 598 | 672 | ||
| 599 | if (msg->cmd == TIPC_CMD_SET_LINK_PRI) { | 673 | __tipc_add_link_prop(skb, msg, lc); |
| 600 | if (nla_put_u32(skb, TIPC_NLA_PROP_PRIO, ntohl(lc->value))) | ||
| 601 | return -EMSGSIZE; | ||
| 602 | } else if (msg->cmd == TIPC_CMD_SET_LINK_TOL) { | ||
| 603 | if (nla_put_u32(skb, TIPC_NLA_PROP_TOL, ntohl(lc->value))) | ||
| 604 | return -EMSGSIZE; | ||
| 605 | } else if (msg->cmd == TIPC_CMD_SET_LINK_WINDOW) { | ||
| 606 | if (nla_put_u32(skb, TIPC_NLA_PROP_WIN, ntohl(lc->value))) | ||
| 607 | return -EMSGSIZE; | ||
| 608 | } | ||
| 609 | |||
| 610 | nla_nest_end(skb, prop); | 674 | nla_nest_end(skb, prop); |
| 611 | nla_nest_end(skb, link); | 675 | nla_nest_end(skb, link); |
| 612 | 676 | ||
| 613 | return 0; | 677 | return 0; |
| 614 | } | 678 | } |
| 615 | 679 | ||
| 616 | static int tipc_nl_compat_link_reset_stats(struct sk_buff *skb, | 680 | static int tipc_nl_compat_link_set(struct tipc_nl_compat_cmd_doit *cmd, |
| 681 | struct sk_buff *skb, | ||
| 682 | struct tipc_nl_compat_msg *msg) | ||
| 683 | { | ||
| 684 | struct tipc_link_config *lc; | ||
| 685 | struct tipc_bearer *bearer; | ||
| 686 | struct tipc_media *media; | ||
| 687 | |||
| 688 | lc = (struct tipc_link_config *)TLV_DATA(msg->req); | ||
| 689 | |||
| 690 | media = tipc_media_find(lc->name); | ||
| 691 | if (media) { | ||
| 692 | cmd->doit = &tipc_nl_media_set; | ||
| 693 | return tipc_nl_compat_media_set(skb, msg); | ||
| 694 | } | ||
| 695 | |||
| 696 | bearer = tipc_bearer_find(msg->net, lc->name); | ||
| 697 | if (bearer) { | ||
| 698 | cmd->doit = &tipc_nl_bearer_set; | ||
| 699 | return tipc_nl_compat_bearer_set(skb, msg); | ||
| 700 | } | ||
| 701 | |||
| 702 | return __tipc_nl_compat_link_set(skb, msg); | ||
| 703 | } | ||
| 704 | |||
| 705 | static int tipc_nl_compat_link_reset_stats(struct tipc_nl_compat_cmd_doit *cmd, | ||
| 706 | struct sk_buff *skb, | ||
| 617 | struct tipc_nl_compat_msg *msg) | 707 | struct tipc_nl_compat_msg *msg) |
| 618 | { | 708 | { |
| 619 | char *name; | 709 | char *name; |
| @@ -851,7 +941,8 @@ static int tipc_nl_compat_node_dump(struct tipc_nl_compat_msg *msg, | |||
| 851 | sizeof(node_info)); | 941 | sizeof(node_info)); |
| 852 | } | 942 | } |
| 853 | 943 | ||
| 854 | static int tipc_nl_compat_net_set(struct sk_buff *skb, | 944 | static int tipc_nl_compat_net_set(struct tipc_nl_compat_cmd_doit *cmd, |
| 945 | struct sk_buff *skb, | ||
| 855 | struct tipc_nl_compat_msg *msg) | 946 | struct tipc_nl_compat_msg *msg) |
| 856 | { | 947 | { |
| 857 | u32 val; | 948 | u32 val; |
| @@ -1007,7 +1098,6 @@ static int tipc_nl_compat_recv(struct sk_buff *skb, struct genl_info *info) | |||
| 1007 | struct nlmsghdr *req_nlh; | 1098 | struct nlmsghdr *req_nlh; |
| 1008 | struct nlmsghdr *rep_nlh; | 1099 | struct nlmsghdr *rep_nlh; |
| 1009 | struct tipc_genlmsghdr *req_userhdr = info->userhdr; | 1100 | struct tipc_genlmsghdr *req_userhdr = info->userhdr; |
| 1010 | struct net *net = genl_info_net(info); | ||
| 1011 | 1101 | ||
| 1012 | memset(&msg, 0, sizeof(msg)); | 1102 | memset(&msg, 0, sizeof(msg)); |
| 1013 | 1103 | ||
| @@ -1015,6 +1105,7 @@ static int tipc_nl_compat_recv(struct sk_buff *skb, struct genl_info *info) | |||
| 1015 | msg.req = nlmsg_data(req_nlh) + GENL_HDRLEN + TIPC_GENL_HDRLEN; | 1105 | msg.req = nlmsg_data(req_nlh) + GENL_HDRLEN + TIPC_GENL_HDRLEN; |
| 1016 | msg.cmd = req_userhdr->cmd; | 1106 | msg.cmd = req_userhdr->cmd; |
| 1017 | msg.dst_sk = info->dst_sk; | 1107 | msg.dst_sk = info->dst_sk; |
| 1108 | msg.net = genl_info_net(info); | ||
| 1018 | 1109 | ||
| 1019 | if ((msg.cmd & 0xC000) && (!netlink_net_capable(skb, CAP_NET_ADMIN))) { | 1110 | if ((msg.cmd & 0xC000) && (!netlink_net_capable(skb, CAP_NET_ADMIN))) { |
| 1020 | msg.rep = tipc_get_err_tlv(TIPC_CFG_NOT_NET_ADMIN); | 1111 | msg.rep = tipc_get_err_tlv(TIPC_CFG_NOT_NET_ADMIN); |
| @@ -1030,7 +1121,7 @@ static int tipc_nl_compat_recv(struct sk_buff *skb, struct genl_info *info) | |||
| 1030 | } | 1121 | } |
| 1031 | 1122 | ||
| 1032 | err = tipc_nl_compat_handle(&msg); | 1123 | err = tipc_nl_compat_handle(&msg); |
| 1033 | if (err == -EOPNOTSUPP) | 1124 | if ((err == -EOPNOTSUPP) || (err == -EPERM)) |
| 1034 | msg.rep = tipc_get_err_tlv(TIPC_CFG_NOT_SUPPORTED); | 1125 | msg.rep = tipc_get_err_tlv(TIPC_CFG_NOT_SUPPORTED); |
| 1035 | else if (err == -EINVAL) | 1126 | else if (err == -EINVAL) |
| 1036 | msg.rep = tipc_get_err_tlv(TIPC_CFG_TLV_ERROR); | 1127 | msg.rep = tipc_get_err_tlv(TIPC_CFG_TLV_ERROR); |
| @@ -1043,7 +1134,7 @@ send: | |||
| 1043 | rep_nlh = nlmsg_hdr(msg.rep); | 1134 | rep_nlh = nlmsg_hdr(msg.rep); |
| 1044 | memcpy(rep_nlh, info->nlhdr, len); | 1135 | memcpy(rep_nlh, info->nlhdr, len); |
| 1045 | rep_nlh->nlmsg_len = msg.rep->len; | 1136 | rep_nlh->nlmsg_len = msg.rep->len; |
| 1046 | genlmsg_unicast(net, msg.rep, NETLINK_CB(skb).portid); | 1137 | genlmsg_unicast(msg.net, msg.rep, NETLINK_CB(skb).portid); |
| 1047 | 1138 | ||
| 1048 | return err; | 1139 | return err; |
| 1049 | } | 1140 | } |
