#include <net/tcp.h>
 
 static int ip_metrics_convert(struct net *net, struct nlattr *fc_mx,
-                             int fc_mx_len, u32 *metrics)
+                             int fc_mx_len, u32 *metrics,
+                             struct netlink_ext_ack *extack)
 {
        bool ecn_ca = false;
        struct nlattr *nla;
 
                if (!type)
                        continue;
-               if (type > RTAX_MAX)
+               if (type > RTAX_MAX) {
+                       NL_SET_ERR_MSG(extack, "Invalid metric type");
                        return -EINVAL;
+               }
 
                if (type == RTAX_CC_ALGO) {
                        char tmp[TCP_CA_NAME_MAX];
 
                        nla_strlcpy(tmp, nla, sizeof(tmp));
                        val = tcp_ca_get_key_by_name(net, tmp, &ecn_ca);
-                       if (val == TCP_CA_UNSPEC)
+                       if (val == TCP_CA_UNSPEC) {
+                               NL_SET_ERR_MSG(extack, "Unknown tcp congestion algorithm");
                                return -EINVAL;
+                       }
                } else {
-                       if (nla_len(nla) != sizeof(u32))
+                       if (nla_len(nla) != sizeof(u32)) {
+                               NL_SET_ERR_MSG_ATTR(extack, nla,
+                                                   "Invalid attribute in metrics");
                                return -EINVAL;
+                       }
                        val = nla_get_u32(nla);
                }
                if (type == RTAX_ADVMSS && val > 65535 - 40)
                        val = 65535 - 15;
                if (type == RTAX_HOPLIMIT && val > 255)
                        val = 255;
-               if (type == RTAX_FEATURES && (val & ~RTAX_FEATURE_MASK))
+               if (type == RTAX_FEATURES && (val & ~RTAX_FEATURE_MASK)) {
+                       NL_SET_ERR_MSG(extack, "Unknown flag set in feature mask in metrics attribute");
                        return -EINVAL;
+               }
                metrics[type - 1] = val;
        }
 
 }
 
 struct dst_metrics *ip_fib_metrics_init(struct net *net, struct nlattr *fc_mx,
-                                       int fc_mx_len)
+                                       int fc_mx_len,
+                                       struct netlink_ext_ack *extack)
 {
        struct dst_metrics *fib_metrics;
        int err;
        if (unlikely(!fib_metrics))
                return ERR_PTR(-ENOMEM);
 
-       err = ip_metrics_convert(net, fc_mx, fc_mx_len, fib_metrics->metrics);
+       err = ip_metrics_convert(net, fc_mx, fc_mx_len, fib_metrics->metrics,
+                                extack);
        if (!err) {
                refcount_set(&fib_metrics->refcnt, 1);
        } else {
 
        if (!rt)
                goto out;
 
-       rt->fib6_metrics = ip_fib_metrics_init(net, cfg->fc_mx, cfg->fc_mx_len);
+       rt->fib6_metrics = ip_fib_metrics_init(net, cfg->fc_mx, cfg->fc_mx_len,
+                                              extack);
        if (IS_ERR(rt->fib6_metrics)) {
                err = PTR_ERR(rt->fib6_metrics);
                /* Do not leave garbage there. */
        if (!f6i)
                return ERR_PTR(-ENOMEM);
 
-       f6i->fib6_metrics = ip_fib_metrics_init(net, NULL, 0);
+       f6i->fib6_metrics = ip_fib_metrics_init(net, NULL, 0, NULL);
        f6i->dst_nocount = true;
        f6i->dst_host = true;
        f6i->fib6_protocol = RTPROT_KERNEL;