#define NLA_TYPE_MAX (__NLA_TYPE_MAX - 1)
 
+enum nla_policy_validation {
+       NLA_VALIDATE_NONE,
+       NLA_VALIDATE_RANGE,
+       NLA_VALIDATE_MIN,
+       NLA_VALIDATE_MAX,
+};
+
 /**
  * struct nla_policy - attribute validation policy
  * @type: Type of attribute or NLA_UNSPEC
+ * @validation_type: type of attribute validation done in addition to
+ *     type-specific validation (e.g. range), see
+ *     &enum nla_policy_validation
  * @len: Type specific length of payload
  *
  * Policies are defined as arrays of this struct, the array must be
  *                         nested attributes directly inside, while an array has
  *                         the nested attributes at another level down and the
  *                         attributes directly in the nesting don't matter.
- *    All other            Unused
+ *    All other            Unused - but note that it's a union
+ *
+ * Meaning of `min' and `max' fields, use via NLA_POLICY_MIN, NLA_POLICY_MAX
+ * and NLA_POLICY_RANGE:
+ *    NLA_U8,
+ *    NLA_U16,
+ *    NLA_U32,
+ *    NLA_U64,
+ *    NLA_S8,
+ *    NLA_S16,
+ *    NLA_S32,
+ *    NLA_S64              These are used depending on the validation_type
+ *                         field, if that is min/max/range then the minimum,
+ *                         maximum and both are used (respectively) to check
+ *                         the value of the integer attribute.
+ *                         Note that in the interest of code simplicity and
+ *                         struct size both limits are s16, so you cannot
+ *                         enforce a range that doesn't fall within the range
+ *                         of s16 - do that as usual in the code instead.
+ *    All other            Unused - but note that it's a union
  *
  * Example:
  * static const struct nla_policy my_policy[ATTR_MAX+1] = {
  * };
  */
 struct nla_policy {
-       u16             type;
+       u8              type;
+       u8              validation_type;
        u16             len;
-       const void     *validation_data;
+       union {
+               const void *validation_data;
+               struct {
+                       s16 min, max;
+               };
+       };
 };
 
 #define NLA_POLICY_EXACT_LEN(_len)     { .type = NLA_EXACT_LEN, .len = _len }
 #define NLA_POLICY_NESTED_ARRAY(maxattr, policy) \
        { .type = NLA_NESTED_ARRAY, .validation_data = policy, .len = maxattr }
 
+#define __NLA_ENSURE(condition) (sizeof(char[1 - 2*!(condition)]) - 1)
+#define NLA_ENSURE_INT_TYPE(tp)                                \
+       (__NLA_ENSURE(tp == NLA_S8 || tp == NLA_U8 ||   \
+                     tp == NLA_S16 || tp == NLA_U16 || \
+                     tp == NLA_S32 || tp == NLA_U32 || \
+                     tp == NLA_S64 || tp == NLA_U64) + tp)
+
+#define NLA_POLICY_RANGE(tp, _min, _max) {             \
+       .type = NLA_ENSURE_INT_TYPE(tp),                \
+       .validation_type = NLA_VALIDATE_RANGE,          \
+       .min = _min,                                    \
+       .max = _max                                     \
+}
+
+#define NLA_POLICY_MIN(tp, _min) {                     \
+       .type = NLA_ENSURE_INT_TYPE(tp),                \
+       .validation_type = NLA_VALIDATE_MIN,            \
+       .min = _min,                                    \
+}
+
+#define NLA_POLICY_MAX(tp, _max) {                     \
+       .type = NLA_ENSURE_INT_TYPE(tp),                \
+       .validation_type = NLA_VALIDATE_MAX,            \
+       .max = _max,                                    \
+}
+
 /**
  * struct nl_info - netlink source information
  * @nlh: Netlink message header of original request
 
        return 0;
 }
 
+static int nla_validate_int_range(const struct nla_policy *pt,
+                                 const struct nlattr *nla,
+                                 struct netlink_ext_ack *extack)
+{
+       bool validate_min, validate_max;
+       s64 value;
+
+       validate_min = pt->validation_type == NLA_VALIDATE_RANGE ||
+                      pt->validation_type == NLA_VALIDATE_MIN;
+       validate_max = pt->validation_type == NLA_VALIDATE_RANGE ||
+                      pt->validation_type == NLA_VALIDATE_MAX;
+
+       switch (pt->type) {
+       case NLA_U8:
+               value = nla_get_u8(nla);
+               break;
+       case NLA_U16:
+               value = nla_get_u16(nla);
+               break;
+       case NLA_U32:
+               value = nla_get_u32(nla);
+               break;
+       case NLA_S8:
+               value = nla_get_s8(nla);
+               break;
+       case NLA_S16:
+               value = nla_get_s16(nla);
+               break;
+       case NLA_S32:
+               value = nla_get_s32(nla);
+               break;
+       case NLA_S64:
+               value = nla_get_s64(nla);
+               break;
+       case NLA_U64:
+               /* treat this one specially, since it may not fit into s64 */
+               if ((validate_min && nla_get_u64(nla) < pt->min) ||
+                   (validate_max && nla_get_u64(nla) > pt->max)) {
+                       NL_SET_ERR_MSG_ATTR(extack, nla,
+                                           "integer out of range");
+                       return -ERANGE;
+               }
+               return 0;
+       default:
+               WARN_ON(1);
+               return -EINVAL;
+       }
+
+       if ((validate_min && value < pt->min) ||
+           (validate_max && value > pt->max)) {
+               NL_SET_ERR_MSG_ATTR(extack, nla,
+                                   "integer out of range");
+               return -ERANGE;
+       }
+
+       return 0;
+}
+
 static int validate_nla(const struct nlattr *nla, int maxtype,
                        const struct nla_policy *policy,
                        struct netlink_ext_ack *extack)
                        goto out_err;
        }
 
+       /* further validation */
+       switch (pt->validation_type) {
+       case NLA_VALIDATE_NONE:
+               /* nothing to do */
+               break;
+       case NLA_VALIDATE_RANGE:
+       case NLA_VALIDATE_MIN:
+       case NLA_VALIDATE_MAX:
+               err = nla_validate_int_range(pt, nla, extack);
+               if (err)
+                       return err;
+               break;
+       }
+
        return 0;
 out_err:
        NL_SET_ERR_MSG_ATTR(extack, nla, "Attribute failed policy validation");