+bool
+nl_attr_validate(const struct nlattr *nla, const struct nl_policy *policy)
+{
+ uint16_t type = nl_attr_type(nla);
+ size_t min_len;
+ size_t max_len;
+ size_t len;
+
+ if (policy->type == NL_A_NO_ATTR) {
+ return true;
+ }
+
+ /* Figure out min and max length. */
+ min_len = policy->min_len;
+ if (!min_len) {
+ min_len = attr_len_range[policy->type][0];
+ }
+ max_len = policy->max_len;
+ if (!max_len) {
+ max_len = attr_len_range[policy->type][1];
+ }
+
+ /* Verify length. */
+ len = nl_attr_get_size(nla);
+ if (len < min_len || len > max_len) {
+ VLOG_DBG_RL(&rl, "attr %"PRIu16" length %zu not in "
+ "allowed range %zu...%zu", type, len, min_len, max_len);
+ return false;
+ }
+
+ /* Strings must be null terminated and must not have embedded nulls. */
+ if (policy->type == NL_A_STRING) {
+ if (((char *) nla)[nla->nla_len - 1]) {
+ VLOG_DBG_RL(&rl, "attr %"PRIu16" lacks null at end", type);
+ return false;
+ }
+ if (memchr(nla + 1, '\0', len - 1) != NULL) {
+ VLOG_DBG_RL(&rl, "attr %"PRIu16" has bad length", type);
+ return false;
+ }
+ }
+
+ return true;
+}
+