Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 768075eb authored by Johannes Berg's avatar Johannes Berg
Browse files

nl80211: add a few extended error strings to key parsing



This mostly serves as an example for how to add error strings
and erroneous attribute pointers.

Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent 6c2fb1e6
Loading
Loading
Loading
Loading
+41 −20
Original line number Diff line number Diff line
@@ -734,11 +734,12 @@ struct key_parse {
	bool def_uni, def_multi;
};

static int nl80211_parse_key_new(struct nlattr *key, struct key_parse *k)
static int nl80211_parse_key_new(struct genl_info *info, struct nlattr *key,
				 struct key_parse *k)
{
	struct nlattr *tb[NL80211_KEY_MAX + 1];
	int err = nla_parse_nested(tb, NL80211_KEY_MAX, key,
				   nl80211_key_policy, NULL);
				   nl80211_key_policy, info->extack);
	if (err)
		return err;

@@ -771,7 +772,8 @@ static int nl80211_parse_key_new(struct nlattr *key, struct key_parse *k)
	if (tb[NL80211_KEY_TYPE]) {
		k->type = nla_get_u32(tb[NL80211_KEY_TYPE]);
		if (k->type < 0 || k->type >= NUM_NL80211_KEYTYPES)
			return -EINVAL;
			return genl_err_attr(info, -EINVAL,
					     tb[NL80211_KEY_TYPE]);
	}

	if (tb[NL80211_KEY_DEFAULT_TYPES]) {
@@ -779,7 +781,8 @@ static int nl80211_parse_key_new(struct nlattr *key, struct key_parse *k)

		err = nla_parse_nested(kdt, NUM_NL80211_KEY_DEFAULT_TYPES - 1,
				       tb[NL80211_KEY_DEFAULT_TYPES],
				       nl80211_key_default_policy, NULL);
				       nl80211_key_default_policy,
				       info->extack);
		if (err)
			return err;

@@ -820,9 +823,11 @@ static int nl80211_parse_key_old(struct genl_info *info, struct key_parse *k)

	if (info->attrs[NL80211_ATTR_KEY_TYPE]) {
		k->type = nla_get_u32(info->attrs[NL80211_ATTR_KEY_TYPE]);
		if (k->type < 0 || k->type >= NUM_NL80211_KEYTYPES)
		if (k->type < 0 || k->type >= NUM_NL80211_KEYTYPES) {
			GENL_SET_ERR_MSG(info, "key type out of range");
			return -EINVAL;
		}
	}

	if (info->attrs[NL80211_ATTR_KEY_DEFAULT_TYPES]) {
		struct nlattr *kdt[NUM_NL80211_KEY_DEFAULT_TYPES];
@@ -850,41 +855,53 @@ static int nl80211_parse_key(struct genl_info *info, struct key_parse *k)
	k->type = -1;

	if (info->attrs[NL80211_ATTR_KEY])
		err = nl80211_parse_key_new(info->attrs[NL80211_ATTR_KEY], k);
		err = nl80211_parse_key_new(info, info->attrs[NL80211_ATTR_KEY], k);
	else
		err = nl80211_parse_key_old(info, k);

	if (err)
		return err;

	if (k->def && k->defmgmt)
	if (k->def && k->defmgmt) {
		GENL_SET_ERR_MSG(info, "key with def && defmgmt is invalid");
		return -EINVAL;
	}

	if (k->defmgmt) {
		if (k->def_uni || !k->def_multi)
		if (k->def_uni || !k->def_multi) {
			GENL_SET_ERR_MSG(info, "defmgmt key must be mcast");
			return -EINVAL;
		}
	}

	if (k->idx != -1) {
		if (k->defmgmt) {
			if (k->idx < 4 || k->idx > 5)
			if (k->idx < 4 || k->idx > 5) {
				GENL_SET_ERR_MSG(info,
						 "defmgmt key idx not 4 or 5");
				return -EINVAL;
			}
		} else if (k->def) {
			if (k->idx < 0 || k->idx > 3)
			if (k->idx < 0 || k->idx > 3) {
				GENL_SET_ERR_MSG(info, "def key idx not 0-3");
				return -EINVAL;
			}
		} else {
			if (k->idx < 0 || k->idx > 5)
			if (k->idx < 0 || k->idx > 5) {
				GENL_SET_ERR_MSG(info, "key idx not 0-5");
				return -EINVAL;
			}
		}
	}

	return 0;
}

static struct cfg80211_cached_keys *
nl80211_parse_connkeys(struct cfg80211_registered_device *rdev,
		       struct nlattr *keys, bool *no_ht)
		       struct genl_info *info, bool *no_ht)
{
	struct nlattr *keys = info->attrs[NL80211_ATTR_KEYS];
	struct key_parse parse;
	struct nlattr *key;
	struct cfg80211_cached_keys *result;
@@ -909,17 +926,22 @@ nl80211_parse_connkeys(struct cfg80211_registered_device *rdev,
		memset(&parse, 0, sizeof(parse));
		parse.idx = -1;

		err = nl80211_parse_key_new(key, &parse);
		err = nl80211_parse_key_new(info, key, &parse);
		if (err)
			goto error;
		err = -EINVAL;
		if (!parse.p.key)
			goto error;
		if (parse.idx < 0 || parse.idx > 3)
		if (parse.idx < 0 || parse.idx > 3) {
			GENL_SET_ERR_MSG(info, "key index out of range [0-3]");
			goto error;
		}
		if (parse.def) {
			if (def)
			if (def) {
				GENL_SET_ERR_MSG(info,
						 "only one key can be default");
				goto error;
			}
			def = 1;
			result->def = parse.idx;
			if (!parse.def_uni || !parse.def_multi)
@@ -932,6 +954,7 @@ nl80211_parse_connkeys(struct cfg80211_registered_device *rdev,
			goto error;
		if (parse.p.cipher != WLAN_CIPHER_SUITE_WEP40 &&
		    parse.p.cipher != WLAN_CIPHER_SUITE_WEP104) {
			GENL_SET_ERR_MSG(info, "connect key must be WEP");
			err = -EINVAL;
			goto error;
		}
@@ -947,6 +970,7 @@ nl80211_parse_connkeys(struct cfg80211_registered_device *rdev,

	if (result->def < 0) {
		err = -EINVAL;
		GENL_SET_ERR_MSG(info, "need a default/TX key");
		goto error;
	}

@@ -8611,9 +8635,7 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
	if (ibss.privacy && info->attrs[NL80211_ATTR_KEYS]) {
		bool no_ht = false;

		connkeys = nl80211_parse_connkeys(rdev,
					  info->attrs[NL80211_ATTR_KEYS],
					  &no_ht);
		connkeys = nl80211_parse_connkeys(rdev, info, &no_ht);
		if (IS_ERR(connkeys))
			return PTR_ERR(connkeys);

@@ -9017,8 +9039,7 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
	}

	if (connect.privacy && info->attrs[NL80211_ATTR_KEYS]) {
		connkeys = nl80211_parse_connkeys(rdev,
					  info->attrs[NL80211_ATTR_KEYS], NULL);
		connkeys = nl80211_parse_connkeys(rdev, info, NULL);
		if (IS_ERR(connkeys))
			return PTR_ERR(connkeys);
	}