* @DCB_CMD_IEEE_GET: get IEEE 802.1Qaz configuration
  * @DCB_CMD_GDCBX: get DCBX engine configuration
  * @DCB_CMD_SDCBX: set DCBX engine configuration
+ * @DCB_CMD_GFEATCFG: get DCBX features flags
+ * @DCB_CMD_SFEATCFG: set DCBX features negotiation flags
  */
 enum dcbnl_commands {
        DCB_CMD_UNDEFINED,
        DCB_CMD_GDCBX,
        DCB_CMD_SDCBX,
 
+       DCB_CMD_GFEATCFG,
+       DCB_CMD_SFEATCFG,
+
        __DCB_CMD_ENUM_MAX,
        DCB_CMD_MAX = __DCB_CMD_ENUM_MAX - 1,
 };
  * @DCB_ATTR_BCN: backward congestion notification configuration (NLA_NESTED)
  * @DCB_ATTR_IEEE: IEEE 802.1Qaz supported attributes (NLA_NESTED)
  * @DCB_ATTR_DCBX: DCBX engine configuration in the device (NLA_U8)
+ * @DCB_ATTR_FEATCFG: DCBX features flags (NLA_NESTED)
  */
 enum dcbnl_attrs {
        DCB_ATTR_UNDEFINED,
        DCB_ATTR_IEEE,
 
        DCB_ATTR_DCBX,
+       DCB_ATTR_FEATCFG,
 
        __DCB_ATTR_ENUM_MAX,
        DCB_ATTR_MAX = __DCB_ATTR_ENUM_MAX - 1,
        DCB_APP_ATTR_MAX = __DCB_APP_ATTR_ENUM_MAX - 1,
 };
 
+/**
+ * enum dcbnl_featcfg_attrs - features conifiguration flags
+ *
+ * @DCB_FEATCFG_ATTR_UNDEFINED: unspecified attribute to catch errors
+ * @DCB_FEATCFG_ATTR_ALL: (NLA_FLAG) all features configuration attributes
+ * @DCB_FEATCFG_ATTR_PG: (NLA_U8) configuration flags for priority groups
+ * @DCB_FEATCFG_ATTR_PFC: (NLA_U8) configuration flags for priority
+ *                                 flow control
+ * @DCB_FEATCFG_ATTR_APP: (NLA_U8) configuration flags for application TLV
+ *
+ */
+#define DCB_FEATCFG_ERROR      0x01    /* error in feature resolution */
+#define DCB_FEATCFG_ENABLE     0x02    /* enable feature */
+#define DCB_FEATCFG_WILLING    0x04    /* feature is willing */
+#define DCB_FEATCFG_ADVERTISE  0x08    /* advertise feature */
+enum dcbnl_featcfg_attrs {
+       DCB_FEATCFG_ATTR_UNDEFINED,
+       DCB_FEATCFG_ATTR_ALL,
+       DCB_FEATCFG_ATTR_PG,
+       DCB_FEATCFG_ATTR_PFC,
+       DCB_FEATCFG_ATTR_APP,
+
+       __DCB_FEATCFG_ATTR_ENUM_MAX,
+       DCB_FEATCFG_ATTR_MAX = __DCB_FEATCFG_ATTR_ENUM_MAX - 1,
+};
+
 #endif /* __LINUX_DCBNL_H__ */
 
        [DCB_ATTR_APP]         = {.type = NLA_NESTED},
        [DCB_ATTR_IEEE]        = {.type = NLA_NESTED},
        [DCB_ATTR_DCBX]        = {.type = NLA_U8},
+       [DCB_ATTR_FEATCFG]     = {.type = NLA_NESTED},
 };
 
 /* DCB priority flow control to User Priority nested attributes */
        [DCB_ATTR_IEEE_APP]         = {.len = sizeof(struct dcb_app)},
 };
 
+/* DCB number of traffic classes nested attributes. */
+static const struct nla_policy dcbnl_featcfg_nest[DCB_FEATCFG_ATTR_MAX + 1] = {
+       [DCB_FEATCFG_ATTR_ALL]      = {.type = NLA_FLAG},
+       [DCB_FEATCFG_ATTR_PG]       = {.type = NLA_U8},
+       [DCB_FEATCFG_ATTR_PFC]      = {.type = NLA_U8},
+       [DCB_FEATCFG_ATTR_APP]      = {.type = NLA_U8},
+};
+
 static LIST_HEAD(dcb_app_list);
 static DEFINE_SPINLOCK(dcb_lock);
 
        return ret;
 }
 
+static int dcbnl_getfeatcfg(struct net_device *netdev, struct nlattr **tb,
+                           u32 pid, u32 seq, u16 flags)
+{
+       struct sk_buff *dcbnl_skb;
+       struct nlmsghdr *nlh;
+       struct dcbmsg *dcb;
+       struct nlattr *data[DCB_FEATCFG_ATTR_MAX + 1], *nest;
+       u8 value;
+       int ret = -EINVAL;
+       int i;
+       int getall = 0;
+
+       if (!tb[DCB_ATTR_FEATCFG] || !netdev->dcbnl_ops->getfeatcfg)
+               return ret;
+
+       ret = nla_parse_nested(data, DCB_FEATCFG_ATTR_MAX, tb[DCB_ATTR_FEATCFG],
+                              dcbnl_featcfg_nest);
+       if (ret) {
+               ret = -EINVAL;
+               goto err_out;
+       }
+
+       dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+       if (!dcbnl_skb) {
+               ret = -EINVAL;
+               goto err_out;
+       }
+
+       nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags);
+
+       dcb = NLMSG_DATA(nlh);
+       dcb->dcb_family = AF_UNSPEC;
+       dcb->cmd = DCB_CMD_GFEATCFG;
+
+       nest = nla_nest_start(dcbnl_skb, DCB_ATTR_FEATCFG);
+       if (!nest) {
+               ret = -EINVAL;
+               goto err;
+       }
+
+       if (data[DCB_FEATCFG_ATTR_ALL])
+               getall = 1;
+
+       for (i = DCB_FEATCFG_ATTR_ALL+1; i <= DCB_FEATCFG_ATTR_MAX; i++) {
+               if (!getall && !data[i])
+                       continue;
+
+               ret = netdev->dcbnl_ops->getfeatcfg(netdev, i, &value);
+               if (!ret) {
+                       ret = nla_put_u8(dcbnl_skb, i, value);
+
+                       if (ret) {
+                               nla_nest_cancel(dcbnl_skb, nest);
+                               ret = -EINVAL;
+                               goto err;
+                       }
+               } else
+                       goto err;
+       }
+       nla_nest_end(dcbnl_skb, nest);
+
+       nlmsg_end(dcbnl_skb, nlh);
+
+       ret = rtnl_unicast(dcbnl_skb, &init_net, pid);
+       if (ret) {
+               ret = -EINVAL;
+               goto err_out;
+       }
+
+       return 0;
+nlmsg_failure:
+err:
+       kfree_skb(dcbnl_skb);
+err_out:
+       return ret;
+}
+
+static int dcbnl_setfeatcfg(struct net_device *netdev, struct nlattr **tb,
+                           u32 pid, u32 seq, u16 flags)
+{
+       struct nlattr *data[DCB_FEATCFG_ATTR_MAX + 1];
+       int ret = -EINVAL;
+       u8 value;
+       int i;
+
+       if (!tb[DCB_ATTR_FEATCFG] || !netdev->dcbnl_ops->setfeatcfg)
+               return ret;
+
+       ret = nla_parse_nested(data, DCB_FEATCFG_ATTR_MAX, tb[DCB_ATTR_FEATCFG],
+                              dcbnl_featcfg_nest);
+
+       if (ret) {
+               ret = -EINVAL;
+               goto err;
+       }
+
+       for (i = DCB_FEATCFG_ATTR_ALL+1; i <= DCB_FEATCFG_ATTR_MAX; i++) {
+               if (data[i] == NULL)
+                       continue;
+
+               value = nla_get_u8(data[i]);
+
+               ret = netdev->dcbnl_ops->setfeatcfg(netdev, i, value);
+
+               if (ret)
+                       goto operr;
+       }
+
+operr:
+       ret = dcbnl_reply(!!ret, RTM_SETDCB, DCB_CMD_SFEATCFG,
+                         DCB_ATTR_FEATCFG, pid, seq, flags);
+
+err:
+       return ret;
+}
+
 static int dcb_doit(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
 {
        struct net *net = sock_net(skb->sk);
                ret = dcbnl_setdcbx(netdev, tb, pid, nlh->nlmsg_seq,
                                    nlh->nlmsg_flags);
                goto out;
+       case DCB_CMD_GFEATCFG:
+               ret = dcbnl_getfeatcfg(netdev, tb, pid, nlh->nlmsg_seq,
+                                      nlh->nlmsg_flags);
+               goto out;
+       case DCB_CMD_SFEATCFG:
+               ret = dcbnl_setfeatcfg(netdev, tb, pid, nlh->nlmsg_seq,
+                                      nlh->nlmsg_flags);
+               goto out;
        default:
                goto errout;
        }