/* update endpoint address(es) of template(s) */
 static int xfrm_policy_migrate(struct xfrm_policy *pol,
-                              struct xfrm_migrate *m, int num_migrate)
+                              struct xfrm_migrate *m, int num_migrate,
+                              struct netlink_ext_ack *extack)
 {
        struct xfrm_migrate *mp;
        int i, j, n = 0;
        write_lock_bh(&pol->lock);
        if (unlikely(pol->walk.dead)) {
                /* target policy has been deleted */
+               NL_SET_ERR_MSG(extack, "Target policy not found");
                write_unlock_bh(&pol->lock);
                return -ENOENT;
        }
        return 0;
 }
 
-static int xfrm_migrate_check(const struct xfrm_migrate *m, int num_migrate)
+static int xfrm_migrate_check(const struct xfrm_migrate *m, int num_migrate,
+                             struct netlink_ext_ack *extack)
 {
        int i, j;
 
-       if (num_migrate < 1 || num_migrate > XFRM_MAX_DEPTH)
+       if (num_migrate < 1 || num_migrate > XFRM_MAX_DEPTH) {
+               NL_SET_ERR_MSG(extack, "Invalid number of SAs to migrate, must be 0 < num <= XFRM_MAX_DEPTH (6)");
                return -EINVAL;
+       }
 
        for (i = 0; i < num_migrate; i++) {
                if (xfrm_addr_any(&m[i].new_daddr, m[i].new_family) ||
-                   xfrm_addr_any(&m[i].new_saddr, m[i].new_family))
+                   xfrm_addr_any(&m[i].new_saddr, m[i].new_family)) {
+                       NL_SET_ERR_MSG(extack, "Addresses in the MIGRATE attribute's list cannot be null");
                        return -EINVAL;
+               }
 
                /* check if there is any duplicated entry */
                for (j = i + 1; j < num_migrate; j++) {
                            m[i].proto == m[j].proto &&
                            m[i].mode == m[j].mode &&
                            m[i].reqid == m[j].reqid &&
-                           m[i].old_family == m[j].old_family)
+                           m[i].old_family == m[j].old_family) {
+                               NL_SET_ERR_MSG(extack, "Entries in the MIGRATE attribute's list must be unique");
                                return -EINVAL;
+                       }
                }
        }
 
 int xfrm_migrate(const struct xfrm_selector *sel, u8 dir, u8 type,
                 struct xfrm_migrate *m, int num_migrate,
                 struct xfrm_kmaddress *k, struct net *net,
-                struct xfrm_encap_tmpl *encap, u32 if_id)
+                struct xfrm_encap_tmpl *encap, u32 if_id,
+                struct netlink_ext_ack *extack)
 {
        int i, err, nx_cur = 0, nx_new = 0;
        struct xfrm_policy *pol = NULL;
        struct xfrm_migrate *mp;
 
        /* Stage 0 - sanity checks */
-       err = xfrm_migrate_check(m, num_migrate);
+       err = xfrm_migrate_check(m, num_migrate, extack);
        if (err < 0)
                goto out;
 
        if (dir >= XFRM_POLICY_MAX) {
+               NL_SET_ERR_MSG(extack, "Invalid policy direction");
                err = -EINVAL;
                goto out;
        }
        /* Stage 1 - find policy */
        pol = xfrm_migrate_policy_find(sel, dir, type, net, if_id);
        if (!pol) {
+               NL_SET_ERR_MSG(extack, "Target policy not found");
                err = -ENOENT;
                goto out;
        }
        }
 
        /* Stage 3 - update policy */
-       err = xfrm_policy_migrate(pol, m, num_migrate);
+       err = xfrm_policy_migrate(pol, m, num_migrate, extack);
        if (err < 0)
                goto restore_state;
 
 
 #ifdef CONFIG_XFRM_MIGRATE
 static int copy_from_user_migrate(struct xfrm_migrate *ma,
                                  struct xfrm_kmaddress *k,
-                                 struct nlattr **attrs, int *num)
+                                 struct nlattr **attrs, int *num,
+                                 struct netlink_ext_ack *extack)
 {
        struct nlattr *rt = attrs[XFRMA_MIGRATE];
        struct xfrm_user_migrate *um;
        um = nla_data(rt);
        num_migrate = nla_len(rt) / sizeof(*um);
 
-       if (num_migrate <= 0 || num_migrate > XFRM_MAX_DEPTH)
+       if (num_migrate <= 0 || num_migrate > XFRM_MAX_DEPTH) {
+               NL_SET_ERR_MSG(extack, "Invalid number of SAs to migrate, must be 0 < num <= XFRM_MAX_DEPTH (6)");
                return -EINVAL;
+       }
 
        for (i = 0; i < num_migrate; i++, um++, ma++) {
                memcpy(&ma->old_daddr, &um->old_daddr, sizeof(ma->old_daddr));
        struct xfrm_encap_tmpl  *encap = NULL;
        u32 if_id = 0;
 
-       if (!attrs[XFRMA_MIGRATE])
+       if (!attrs[XFRMA_MIGRATE]) {
+               NL_SET_ERR_MSG(extack, "Missing required MIGRATE attribute");
                return -EINVAL;
+       }
 
        kmp = attrs[XFRMA_KMADDRESS] ? &km : NULL;
 
        if (err)
                return err;
 
-       err = copy_from_user_migrate(m, kmp, attrs, &n);
+       err = copy_from_user_migrate(m, kmp, attrs, &n, extack);
        if (err)
                return err;
 
        if (attrs[XFRMA_IF_ID])
                if_id = nla_get_u32(attrs[XFRMA_IF_ID]);
 
-       err = xfrm_migrate(&pi->sel, pi->dir, type, m, n, kmp, net, encap, if_id);
+       err = xfrm_migrate(&pi->sel, pi->dir, type, m, n, kmp, net, encap,
+                          if_id, extack);
 
        kfree(encap);