| @@ -1000,6 +1000,16 @@ static size_t rtnl_prop_list_size(const struct net_device *dev) · 999 unmodified lines |
| 1000 | 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 | 1013 | static noinline size_t if_nlmsg_size(const struct net_device *dev, |
| 1004 | 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 | 1051 | + nla_total_size(4) /* IFLA_EVENT */ |
| 1042 | 1052 | + nla_total_size(4) /* IFLA_NEW_NETNSID */ |
| 1043 | 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 | 1055 | + nla_total_size(4) /* IFLA_TARGET_NETNSID */ |
| 1046 | 1056 | + nla_total_size(4) /* IFLA_CARRIER_UP_COUNT */ |
| 1047 | 1057 | + nla_total_size(4) /* IFLA_CARRIER_DOWN_COUNT */ |
| @@ -1658,6 +1668,35 @@ nest_cancel: · 610 unmodified lines |
| 1658 | 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 | 1700 | static int rtnl_fill_ifinfo(struct sk_buff *skb, |
| 1662 | 1701 | struct net_device *dev, struct net *src_net, |
| 1663 | 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 | 1747 | nla_put_u32(skb, IFLA_CARRIER_CHANGES, |
| 1709 | 1748 | atomic_read(&dev->carrier_up_count) + |
| 1710 | 1749 | atomic_read(&dev->carrier_down_count)) || |
| 1711 | | − nla_put_u8(skb, IFLA_PROTO_DOWN, dev->proto_down) || |
| 1712 | 1750 | nla_put_u32(skb, IFLA_CARRIER_UP_COUNT, |
| 1713 | 1751 | atomic_read(&dev->carrier_up_count)) || |
| 1714 | 1752 | nla_put_u32(skb, IFLA_CARRIER_DOWN_COUNT, |
| 1715 | 1753 | atomic_read(&dev->carrier_down_count))) |
| 1716 | 1754 | goto nla_put_failure; |
| 1717 | 1755 | |
| 1756 | + if (rtnl_fill_proto_down(skb, dev)) |
| 1757 | + goto nla_put_failure; |
| 1758 | + |
| 1718 | 1759 | if (event != IFLA_EVENT_NONE) { |
| 1719 | 1760 | if (nla_put_u32(skb, IFLA_EVENT, event)) |
| 1720 | 1761 | goto nla_put_failure; |
| @@ -1834,6 +1875,7 @@ static const struct nla_policy ifla_policy[IFLA_MAX+1] = { · 113 unmodified lines |
| 1834 | 1875 | [IFLA_ALT_IFNAME] = { .type = NLA_STRING, |
| 1835 | 1876 | .len = ALTIFNAMSIZ - 1 }, |
| 1836 | 1877 | [IFLA_PERM_ADDRESS] = { .type = NLA_REJECT }, |
| 1878 | + [IFLA_PROTO_DOWN_REASON] = { .type = NLA_NESTED }, |
| 1837 | 1879 | }; |
| 1838 | 1880 | |
| 1839 | 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 | 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 | 2589 | #define DO_SETLINK_MODIFIED 0x01 |
| 2487 | 2590 | /* notify flag means notify + modified. */ |
| 2488 | 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 | 2875 | err = 0; |
| 2773 | 2876 | |
| 2774 | | − if (tb[IFLA_PROTO_DOWN]) { |
| 2775 | | − err = dev_change_proto_down(dev, |
| 2776 | | − nla_get_u8(tb[IFLA_PROTO_DOWN])); |
| 2877 | + if (tb[IFLA_PROTO_DOWN] || tb[IFLA_PROTO_DOWN_REASON]) { |
| 2878 | + err = do_set_proto_down(dev, tb[IFLA_PROTO_DOWN], |
| 2879 | + tb[IFLA_PROTO_DOWN_REASON], extack); |
| 2777 | 2880 | if (err) |
| 2778 | 2881 | goto errout; |
| 2779 | 2882 | status |= DO_SETLINK_NOTIFY; |