| @@ -1000,6 +1000,16 @@ static size_t rtnl_prop_list_size(const struct net_device *dev) · 999 unmodified lines |
| 1000 | return size; | 1000 | return size; |
| 1001 | } | 1001 | } |
| 1002 | | 1002 | |
| | 1003 | static size_t rtnl_proto_down_size(const struct net_device *dev) |
| | 1004 | { |
| | 1005 | size_t size = nla_total_size(1); |
| | 1006 | |
| | 1007 | if (dev->proto_down_reason) |
| | 1008 | size += nla_total_size(0) + nla_total_size(4); |
| | 1009 | |
| | 1010 | return size; |
| | 1011 | } |
| | 1012 | |
| 1003 | static noinline size_t if_nlmsg_size(const struct net_device *dev, | 1013 | static noinline size_t if_nlmsg_size(const struct net_device *dev, |
| 1004 | u32 ext_filter_mask) | 1014 | u32 ext_filter_mask) |
| 1005 | { | 1015 | { |
| @@ -1041,7 +1051,7 @@ static noinline size_t if_nlmsg_size(const struct net_device *dev, · 35 unmodified lines |
| 1041 | + nla_total_size(4) /* IFLA_EVENT */ | 1051 | + nla_total_size(4) /* IFLA_EVENT */ |
| 1042 | + nla_total_size(4) /* IFLA_NEW_NETNSID */ | 1052 | + nla_total_size(4) /* IFLA_NEW_NETNSID */ |
| 1043 | + nla_total_size(4) /* IFLA_NEW_IFINDEX */ | 1053 | + nla_total_size(4) /* IFLA_NEW_IFINDEX */ |
| 1044 | + nla_total_size(1) /* IFLA_PROTO_DOWN */ | 1054 | + rtnl_proto_down_size(dev) /* proto down */ |
| 1045 | + nla_total_size(4) /* IFLA_TARGET_NETNSID */ | 1055 | + nla_total_size(4) /* IFLA_TARGET_NETNSID */ |
| 1046 | + nla_total_size(4) /* IFLA_CARRIER_UP_COUNT */ | 1056 | + nla_total_size(4) /* IFLA_CARRIER_UP_COUNT */ |
| 1047 | + nla_total_size(4) /* IFLA_CARRIER_DOWN_COUNT */ | 1057 | + nla_total_size(4) /* IFLA_CARRIER_DOWN_COUNT */ |
| @@ -1658,6 +1668,35 @@ nest_cancel: · 610 unmodified lines |
| 1658 | return ret; | 1668 | return ret; |
| 1659 | } | 1669 | } |
| 1660 | | 1670 | |
| | 1671 | static int rtnl_fill_proto_down(struct sk_buff *skb, |
| | 1672 | const struct net_device *dev) |
| | 1673 | { |
| | 1674 | struct nlattr *pr; |
| | 1675 | u32 preason; |
| | 1676 | |
| | 1677 | if (nla_put_u8(skb, IFLA_PROTO_DOWN, dev->proto_down)) |
| | 1678 | goto nla_put_failure; |
| | 1679 | |
| | 1680 | preason = dev->proto_down_reason; |
| | 1681 | if (!preason) |
| | 1682 | return 0; |
| | 1683 | |
| | 1684 | pr = nla_nest_start(skb, IFLA_PROTO_DOWN_REASON); |
| | 1685 | if (!pr) |
| | 1686 | return -EMSGSIZE; |
| | 1687 | |
| | 1688 | if (nla_put_u32(skb, IFLA_PROTO_DOWN_REASON_VALUE, preason)) { |
| | 1689 | nla_nest_cancel(skb, pr); |
| | 1690 | goto nla_put_failure; |
| | 1691 | } |
| | 1692 | |
| | 1693 | nla_nest_end(skb, pr); |
| | 1694 | return 0; |
| | 1695 | |
| | 1696 | nla_put_failure: |
| | 1697 | return -EMSGSIZE; |
| | 1698 | } |
| | 1699 | |
| 1661 | static int rtnl_fill_ifinfo(struct sk_buff *skb, | 1700 | static int rtnl_fill_ifinfo(struct sk_buff *skb, |
| 1662 | struct net_device *dev, struct net *src_net, | 1701 | struct net_device *dev, struct net *src_net, |
| 1663 | int type, u32 pid, u32 seq, u32 change, | 1702 | int type, u32 pid, u32 seq, u32 change, |
| @@ -1708,13 +1747,15 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, · 44 unmodified lines |
| 1708 | nla_put_u32(skb, IFLA_CARRIER_CHANGES, | 1747 | nla_put_u32(skb, IFLA_CARRIER_CHANGES, |
| 1709 | atomic_read(&dev->carrier_up_count) + | 1748 | atomic_read(&dev->carrier_up_count) + |
| 1710 | atomic_read(&dev->carrier_down_count)) || | 1749 | atomic_read(&dev->carrier_down_count)) || |
| 1711 | nla_put_u8(skb, IFLA_PROTO_DOWN, dev->proto_down) || | | |
| 1712 | nla_put_u32(skb, IFLA_CARRIER_UP_COUNT, | 1750 | nla_put_u32(skb, IFLA_CARRIER_UP_COUNT, |
| 1713 | atomic_read(&dev->carrier_up_count)) || | 1751 | atomic_read(&dev->carrier_up_count)) || |
| 1714 | nla_put_u32(skb, IFLA_CARRIER_DOWN_COUNT, | 1752 | nla_put_u32(skb, IFLA_CARRIER_DOWN_COUNT, |
| 1715 | atomic_read(&dev->carrier_down_count))) | 1753 | atomic_read(&dev->carrier_down_count))) |
| 1716 | goto nla_put_failure; | 1754 | goto nla_put_failure; |
| 1717 | | 1755 | |
| | 1756 | if (rtnl_fill_proto_down(skb, dev)) |
| | 1757 | goto nla_put_failure; |
| | 1758 | |
| 1718 | if (event != IFLA_EVENT_NONE) { | 1759 | if (event != IFLA_EVENT_NONE) { |
| 1719 | if (nla_put_u32(skb, IFLA_EVENT, event)) | 1760 | if (nla_put_u32(skb, IFLA_EVENT, event)) |
| 1720 | goto nla_put_failure; | 1761 | goto nla_put_failure; |
| @@ -1834,6 +1875,7 @@ static const struct nla_policy ifla_policy[IFLA_MAX+1] = { · 113 unmodified lines |
| 1834 | [IFLA_ALT_IFNAME] = { .type = NLA_STRING, | 1875 | [IFLA_ALT_IFNAME] = { .type = NLA_STRING, |
| 1835 | .len = ALTIFNAMSIZ - 1 }, | 1876 | .len = ALTIFNAMSIZ - 1 }, |
| 1836 | [IFLA_PERM_ADDRESS] = { .type = NLA_REJECT }, | 1877 | [IFLA_PERM_ADDRESS] = { .type = NLA_REJECT }, |
| | 1878 | [IFLA_PROTO_DOWN_REASON] = { .type = NLA_NESTED }, |
| 1837 | }; | 1879 | }; |
| 1838 | | 1880 | |
| 1839 | static const struct nla_policy ifla_info_policy[IFLA_INFO_MAX+1] = { | 1881 | static const struct nla_policy ifla_info_policy[IFLA_INFO_MAX+1] = { |
| @@ -2483,6 +2525,67 @@ static int do_set_master(struct net_device *dev, int ifindex, · 643 unmodified lines |
| 2483 | return 0; | 2525 | return 0; |
| 2484 | } | 2526 | } |
| 2485 | | 2527 | |
| | 2528 | static const struct nla_policy ifla_proto_down_reason_policy[IFLA_PROTO_DOWN_REASON_VALUE + 1] = { |
| | 2529 | [IFLA_PROTO_DOWN_REASON_MASK] = { .type = NLA_U32 }, |
| | 2530 | [IFLA_PROTO_DOWN_REASON_VALUE] = { .type = NLA_U32 }, |
| | 2531 | }; |
| | 2532 | |
| | 2533 | static int do_set_proto_down(struct net_device *dev, |
| | 2534 | struct nlattr *nl_proto_down, |
| | 2535 | struct nlattr *nl_proto_down_reason, |
| | 2536 | struct netlink_ext_ack *extack) |
| | 2537 | { |
| | 2538 | struct nlattr *pdreason[IFLA_PROTO_DOWN_REASON_MAX + 1]; |
| | 2539 | const struct net_device_ops *ops = dev->netdev_ops; |
| | 2540 | unsigned long mask = 0; |
| | 2541 | u32 value; |
| | 2542 | bool proto_down; |
| | 2543 | int err; |
| | 2544 | |
| | 2545 | if (!ops->ndo_change_proto_down) { |
| | 2546 | NL_SET_ERR_MSG(extack, "Protodown not supported by device"); |
| | 2547 | return -EOPNOTSUPP; |
| | 2548 | } |
| | 2549 | |
| | 2550 | if (nl_proto_down_reason) { |
| | 2551 | err = nla_parse_nested_deprecated(pdreason, |
| | 2552 | IFLA_PROTO_DOWN_REASON_MAX, |
| | 2553 | nl_proto_down_reason, |
| | 2554 | ifla_proto_down_reason_policy, |
| | 2555 | NULL); |
| | 2556 | if (err < 0) |
| | 2557 | return err; |
| | 2558 | |
| | 2559 | if (!pdreason[IFLA_PROTO_DOWN_REASON_VALUE]) { |
| | 2560 | NL_SET_ERR_MSG(extack, "Invalid protodown reason value"); |
| | 2561 | return -EINVAL; |
| | 2562 | } |
| | 2563 | |
| | 2564 | value = nla_get_u32(pdreason[IFLA_PROTO_DOWN_REASON_VALUE]); |
| | 2565 | |
| | 2566 | if (pdreason[IFLA_PROTO_DOWN_REASON_MASK]) |
| | 2567 | mask = nla_get_u32(pdreason[IFLA_PROTO_DOWN_REASON_MASK]); |
| | 2568 | |
| | 2569 | dev_change_proto_down_reason(dev, mask, value); |
| | 2570 | } |
| | 2571 | |
| | 2572 | if (nl_proto_down) { |
| | 2573 | proto_down = nla_get_u8(nl_proto_down); |
| | 2574 | |
| | 2575 | /* Dont turn off protodown if there are active reasons */ |
| | 2576 | if (!proto_down && dev->proto_down_reason) { |
| | 2577 | NL_SET_ERR_MSG(extack, "Cannot clear protodown, active reasons"); |
| | 2578 | return -EBUSY; |
| | 2579 | } |
| | 2580 | err = dev_change_proto_down(dev, |
| | 2581 | proto_down); |
| | 2582 | if (err) |
| | 2583 | return err; |
| | 2584 | } |
| | 2585 | |
| | 2586 | return 0; |
| | 2587 | } |
| | 2588 | |
| 2486 | #define DO_SETLINK_MODIFIED 0x01 | 2589 | #define DO_SETLINK_MODIFIED 0x01 |
| 2487 | /* notify flag means notify + modified. */ | 2590 | /* notify flag means notify + modified. */ |
| 2488 | #define DO_SETLINK_NOTIFY 0x03 | 2591 | #define DO_SETLINK_NOTIFY 0x03 |
| @@ -2771,9 +2874,9 @@ static int do_setlink(const struct sk_buff *skb, · 282 unmodified lines |
| 2771 | } | 2874 | } |
| 2772 | err = 0; | 2875 | err = 0; |
| 2773 | | 2876 | |
| 2774 | if (tb[IFLA_PROTO_DOWN]) { | 2877 | if (tb[IFLA_PROTO_DOWN] || tb[IFLA_PROTO_DOWN_REASON]) { |
| 2775 | err = dev_change_proto_down(dev, | 2878 | err = do_set_proto_down(dev, tb[IFLA_PROTO_DOWN], |
| 2776 | nla_get_u8(tb[IFLA_PROTO_DOWN])); | 2879 | tb[IFLA_PROTO_DOWN_REASON], extack); |
| 2777 | if (err) | 2880 | if (err) |
| 2778 | goto errout; | 2881 | goto errout; |
| 2779 | status |= DO_SETLINK_NOTIFY; | 2882 | status |= DO_SETLINK_NOTIFY; |