diff options
Diffstat (limited to 'net/core/rtnetlink.c')
-rw-r--r-- | net/core/rtnetlink.c | 63 |
1 files changed, 31 insertions, 32 deletions
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index ecb02afd52dc..2bd9c5f7627d 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c | |||
@@ -504,7 +504,7 @@ int rtnl_put_cacheinfo(struct sk_buff *skb, struct dst_entry *dst, u32 id, | |||
504 | 504 | ||
505 | EXPORT_SYMBOL_GPL(rtnl_put_cacheinfo); | 505 | EXPORT_SYMBOL_GPL(rtnl_put_cacheinfo); |
506 | 506 | ||
507 | static int set_operstate(struct net_device *dev, unsigned char transition, bool send_notification) | 507 | static void set_operstate(struct net_device *dev, unsigned char transition) |
508 | { | 508 | { |
509 | unsigned char operstate = dev->operstate; | 509 | unsigned char operstate = dev->operstate; |
510 | 510 | ||
@@ -527,12 +527,8 @@ static int set_operstate(struct net_device *dev, unsigned char transition, bool | |||
527 | write_lock_bh(&dev_base_lock); | 527 | write_lock_bh(&dev_base_lock); |
528 | dev->operstate = operstate; | 528 | dev->operstate = operstate; |
529 | write_unlock_bh(&dev_base_lock); | 529 | write_unlock_bh(&dev_base_lock); |
530 | 530 | netdev_state_change(dev); | |
531 | if (send_notification) | 531 | } |
532 | netdev_state_change(dev); | ||
533 | return 1; | ||
534 | } else | ||
535 | return 0; | ||
536 | } | 532 | } |
537 | 533 | ||
538 | static void copy_rtnl_link_stats(struct rtnl_link_stats *a, | 534 | static void copy_rtnl_link_stats(struct rtnl_link_stats *a, |
@@ -693,10 +689,12 @@ const struct nla_policy ifla_policy[IFLA_MAX+1] = { | |||
693 | [IFLA_BROADCAST] = { .type = NLA_BINARY, .len = MAX_ADDR_LEN }, | 689 | [IFLA_BROADCAST] = { .type = NLA_BINARY, .len = MAX_ADDR_LEN }, |
694 | [IFLA_MAP] = { .len = sizeof(struct rtnl_link_ifmap) }, | 690 | [IFLA_MAP] = { .len = sizeof(struct rtnl_link_ifmap) }, |
695 | [IFLA_MTU] = { .type = NLA_U32 }, | 691 | [IFLA_MTU] = { .type = NLA_U32 }, |
692 | [IFLA_LINK] = { .type = NLA_U32 }, | ||
696 | [IFLA_TXQLEN] = { .type = NLA_U32 }, | 693 | [IFLA_TXQLEN] = { .type = NLA_U32 }, |
697 | [IFLA_WEIGHT] = { .type = NLA_U32 }, | 694 | [IFLA_WEIGHT] = { .type = NLA_U32 }, |
698 | [IFLA_OPERSTATE] = { .type = NLA_U8 }, | 695 | [IFLA_OPERSTATE] = { .type = NLA_U8 }, |
699 | [IFLA_LINKMODE] = { .type = NLA_U8 }, | 696 | [IFLA_LINKMODE] = { .type = NLA_U8 }, |
697 | [IFLA_LINKINFO] = { .type = NLA_NESTED }, | ||
700 | [IFLA_NET_NS_PID] = { .type = NLA_U32 }, | 698 | [IFLA_NET_NS_PID] = { .type = NLA_U32 }, |
701 | }; | 699 | }; |
702 | 700 | ||
@@ -724,6 +722,21 @@ static struct net *get_net_ns_by_pid(pid_t pid) | |||
724 | return net; | 722 | return net; |
725 | } | 723 | } |
726 | 724 | ||
725 | static int validate_linkmsg(struct net_device *dev, struct nlattr *tb[]) | ||
726 | { | ||
727 | if (dev) { | ||
728 | if (tb[IFLA_ADDRESS] && | ||
729 | nla_len(tb[IFLA_ADDRESS]) < dev->addr_len) | ||
730 | return -EINVAL; | ||
731 | |||
732 | if (tb[IFLA_BROADCAST] && | ||
733 | nla_len(tb[IFLA_BROADCAST]) < dev->addr_len) | ||
734 | return -EINVAL; | ||
735 | } | ||
736 | |||
737 | return 0; | ||
738 | } | ||
739 | |||
727 | static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm, | 740 | static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm, |
728 | struct nlattr **tb, char *ifname, int modified) | 741 | struct nlattr **tb, char *ifname, int modified) |
729 | { | 742 | { |
@@ -826,7 +839,6 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm, | |||
826 | if (tb[IFLA_BROADCAST]) { | 839 | if (tb[IFLA_BROADCAST]) { |
827 | nla_memcpy(dev->broadcast, tb[IFLA_BROADCAST], dev->addr_len); | 840 | nla_memcpy(dev->broadcast, tb[IFLA_BROADCAST], dev->addr_len); |
828 | send_addr_notify = 1; | 841 | send_addr_notify = 1; |
829 | modified = 1; | ||
830 | } | 842 | } |
831 | 843 | ||
832 | if (ifm->ifi_flags || ifm->ifi_change) { | 844 | if (ifm->ifi_flags || ifm->ifi_change) { |
@@ -839,23 +851,16 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm, | |||
839 | dev_change_flags(dev, flags); | 851 | dev_change_flags(dev, flags); |
840 | } | 852 | } |
841 | 853 | ||
842 | if (tb[IFLA_TXQLEN]) { | 854 | if (tb[IFLA_TXQLEN]) |
843 | if (dev->tx_queue_len != nla_get_u32(tb[IFLA_TXQLEN])) { | 855 | dev->tx_queue_len = nla_get_u32(tb[IFLA_TXQLEN]); |
844 | dev->tx_queue_len = nla_get_u32(tb[IFLA_TXQLEN]); | ||
845 | modified = 1; | ||
846 | } | ||
847 | } | ||
848 | 856 | ||
849 | if (tb[IFLA_OPERSTATE]) | 857 | if (tb[IFLA_OPERSTATE]) |
850 | modified |= set_operstate(dev, nla_get_u8(tb[IFLA_OPERSTATE]), false); | 858 | set_operstate(dev, nla_get_u8(tb[IFLA_OPERSTATE])); |
851 | 859 | ||
852 | if (tb[IFLA_LINKMODE]) { | 860 | if (tb[IFLA_LINKMODE]) { |
853 | if (dev->link_mode != nla_get_u8(tb[IFLA_LINKMODE])) { | 861 | write_lock_bh(&dev_base_lock); |
854 | write_lock_bh(&dev_base_lock); | 862 | dev->link_mode = nla_get_u8(tb[IFLA_LINKMODE]); |
855 | dev->link_mode = nla_get_u8(tb[IFLA_LINKMODE]); | 863 | write_unlock_bh(&dev_base_lock); |
856 | write_lock_bh(&dev_base_lock); | ||
857 | modified = 1; | ||
858 | } | ||
859 | } | 864 | } |
860 | 865 | ||
861 | err = 0; | 866 | err = 0; |
@@ -869,10 +874,6 @@ errout: | |||
869 | 874 | ||
870 | if (send_addr_notify) | 875 | if (send_addr_notify) |
871 | call_netdevice_notifiers(NETDEV_CHANGEADDR, dev); | 876 | call_netdevice_notifiers(NETDEV_CHANGEADDR, dev); |
872 | |||
873 | if (modified) | ||
874 | netdev_state_change(dev); | ||
875 | |||
876 | return err; | 877 | return err; |
877 | } | 878 | } |
878 | 879 | ||
@@ -908,12 +909,7 @@ static int rtnl_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | |||
908 | goto errout; | 909 | goto errout; |
909 | } | 910 | } |
910 | 911 | ||
911 | if (tb[IFLA_ADDRESS] && | 912 | if ((err = validate_linkmsg(dev, tb)) < 0) |
912 | nla_len(tb[IFLA_ADDRESS]) < dev->addr_len) | ||
913 | goto errout_dev; | ||
914 | |||
915 | if (tb[IFLA_BROADCAST] && | ||
916 | nla_len(tb[IFLA_BROADCAST]) < dev->addr_len) | ||
917 | goto errout_dev; | 913 | goto errout_dev; |
918 | 914 | ||
919 | err = do_setlink(dev, ifm, tb, ifname, 0); | 915 | err = do_setlink(dev, ifm, tb, ifname, 0); |
@@ -990,7 +986,7 @@ struct net_device *rtnl_create_link(struct net *net, char *ifname, | |||
990 | if (tb[IFLA_TXQLEN]) | 986 | if (tb[IFLA_TXQLEN]) |
991 | dev->tx_queue_len = nla_get_u32(tb[IFLA_TXQLEN]); | 987 | dev->tx_queue_len = nla_get_u32(tb[IFLA_TXQLEN]); |
992 | if (tb[IFLA_OPERSTATE]) | 988 | if (tb[IFLA_OPERSTATE]) |
993 | set_operstate(dev, nla_get_u8(tb[IFLA_OPERSTATE]), true); | 989 | set_operstate(dev, nla_get_u8(tb[IFLA_OPERSTATE])); |
994 | if (tb[IFLA_LINKMODE]) | 990 | if (tb[IFLA_LINKMODE]) |
995 | dev->link_mode = nla_get_u8(tb[IFLA_LINKMODE]); | 991 | dev->link_mode = nla_get_u8(tb[IFLA_LINKMODE]); |
996 | 992 | ||
@@ -1034,6 +1030,9 @@ replay: | |||
1034 | else | 1030 | else |
1035 | dev = NULL; | 1031 | dev = NULL; |
1036 | 1032 | ||
1033 | if ((err = validate_linkmsg(dev, tb)) < 0) | ||
1034 | return err; | ||
1035 | |||
1037 | if (tb[IFLA_LINKINFO]) { | 1036 | if (tb[IFLA_LINKINFO]) { |
1038 | err = nla_parse_nested(linkinfo, IFLA_INFO_MAX, | 1037 | err = nla_parse_nested(linkinfo, IFLA_INFO_MAX, |
1039 | tb[IFLA_LINKINFO], ifla_info_policy); | 1038 | tb[IFLA_LINKINFO], ifla_info_policy); |