nl80211: add a few extended error strings to key parsing
authorJohannes Berg <johannes.berg@intel.com>
Mon, 13 Nov 2017 14:35:06 +0000 (15:35 +0100)
committerJohannes Berg <johannes.berg@intel.com>
Mon, 11 Dec 2017 11:19:45 +0000 (12:19 +0100)
This mostly serves as an example for how to add error strings
and erroneous attribute pointers.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
net/wireless/nl80211.c

index b1ac23ca20c86be0af71e9a1ba92cc99d8d5a967..e4522ad5f770c866f11f8e1962da056ff2cedbc5 100644 (file)
@@ -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,8 +823,10 @@ 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]) {
@@ -850,31 +855,42 @@ 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;
+                       }
                }
        }
 
@@ -883,8 +899,9 @@ static int nl80211_parse_key(struct genl_info *info, struct key_parse *k)
 
 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);
        }