diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/wireless/nl80211.c | 203 |
1 files changed, 156 insertions, 47 deletions
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index a00fd644370b..50cf59316292 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -73,6 +73,7 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = { | |||
73 | [NL80211_ATTR_MAC] = { .type = NLA_BINARY, .len = ETH_ALEN }, | 73 | [NL80211_ATTR_MAC] = { .type = NLA_BINARY, .len = ETH_ALEN }, |
74 | [NL80211_ATTR_PREV_BSSID] = { .type = NLA_BINARY, .len = ETH_ALEN }, | 74 | [NL80211_ATTR_PREV_BSSID] = { .type = NLA_BINARY, .len = ETH_ALEN }, |
75 | 75 | ||
76 | [NL80211_ATTR_KEY] = { .type = NLA_NESTED, }, | ||
76 | [NL80211_ATTR_KEY_DATA] = { .type = NLA_BINARY, | 77 | [NL80211_ATTR_KEY_DATA] = { .type = NLA_BINARY, |
77 | .len = WLAN_MAX_KEY_LEN }, | 78 | .len = WLAN_MAX_KEY_LEN }, |
78 | [NL80211_ATTR_KEY_IDX] = { .type = NLA_U8 }, | 79 | [NL80211_ATTR_KEY_IDX] = { .type = NLA_U8 }, |
@@ -134,6 +135,18 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = { | |||
134 | [NL80211_ATTR_WPA_VERSIONS] = { .type = NLA_U32 }, | 135 | [NL80211_ATTR_WPA_VERSIONS] = { .type = NLA_U32 }, |
135 | }; | 136 | }; |
136 | 137 | ||
138 | /* policy for the attributes */ | ||
139 | static struct nla_policy | ||
140 | nl80211_key_policy[NL80211_KEY_MAX + 1] __read_mostly = { | ||
141 | [NL80211_KEY_DATA] = { .type = NLA_BINARY, | ||
142 | .len = WLAN_MAX_KEY_LEN }, | ||
143 | [NL80211_KEY_IDX] = { .type = NLA_U8 }, | ||
144 | [NL80211_KEY_CIPHER] = { .type = NLA_U32 }, | ||
145 | [NL80211_KEY_SEQ] = { .type = NLA_BINARY, .len = 8 }, | ||
146 | [NL80211_KEY_DEFAULT] = { .type = NLA_FLAG }, | ||
147 | [NL80211_KEY_DEFAULT_MGMT] = { .type = NLA_FLAG }, | ||
148 | }; | ||
149 | |||
137 | /* IE validation */ | 150 | /* IE validation */ |
138 | static bool is_valid_ie_attr(const struct nlattr *attr) | 151 | static bool is_valid_ie_attr(const struct nlattr *attr) |
139 | { | 152 | { |
@@ -198,6 +211,100 @@ static int nl80211_msg_put_channel(struct sk_buff *msg, | |||
198 | 211 | ||
199 | /* netlink command implementations */ | 212 | /* netlink command implementations */ |
200 | 213 | ||
214 | struct key_parse { | ||
215 | struct key_params p; | ||
216 | int idx; | ||
217 | bool def, defmgmt; | ||
218 | }; | ||
219 | |||
220 | static int nl80211_parse_key_new(struct nlattr *key, struct key_parse *k) | ||
221 | { | ||
222 | struct nlattr *tb[NL80211_KEY_MAX + 1]; | ||
223 | int err = nla_parse_nested(tb, NL80211_KEY_MAX, key, | ||
224 | nl80211_key_policy); | ||
225 | if (err) | ||
226 | return err; | ||
227 | |||
228 | k->def = !!tb[NL80211_KEY_DEFAULT]; | ||
229 | k->defmgmt = !!tb[NL80211_KEY_DEFAULT_MGMT]; | ||
230 | |||
231 | if (tb[NL80211_KEY_IDX]) | ||
232 | k->idx = nla_get_u8(tb[NL80211_KEY_IDX]); | ||
233 | |||
234 | if (tb[NL80211_KEY_DATA]) { | ||
235 | k->p.key = nla_data(tb[NL80211_KEY_DATA]); | ||
236 | k->p.key_len = nla_len(tb[NL80211_KEY_DATA]); | ||
237 | } | ||
238 | |||
239 | if (tb[NL80211_KEY_SEQ]) { | ||
240 | k->p.seq = nla_data(tb[NL80211_KEY_SEQ]); | ||
241 | k->p.seq_len = nla_len(tb[NL80211_KEY_SEQ]); | ||
242 | } | ||
243 | |||
244 | if (tb[NL80211_KEY_CIPHER]) | ||
245 | k->p.cipher = nla_get_u32(tb[NL80211_KEY_CIPHER]); | ||
246 | |||
247 | return 0; | ||
248 | } | ||
249 | |||
250 | static int nl80211_parse_key_old(struct genl_info *info, struct key_parse *k) | ||
251 | { | ||
252 | if (info->attrs[NL80211_ATTR_KEY_DATA]) { | ||
253 | k->p.key = nla_data(info->attrs[NL80211_ATTR_KEY_DATA]); | ||
254 | k->p.key_len = nla_len(info->attrs[NL80211_ATTR_KEY_DATA]); | ||
255 | } | ||
256 | |||
257 | if (info->attrs[NL80211_ATTR_KEY_SEQ]) { | ||
258 | k->p.seq = nla_data(info->attrs[NL80211_ATTR_KEY_SEQ]); | ||
259 | k->p.seq_len = nla_len(info->attrs[NL80211_ATTR_KEY_SEQ]); | ||
260 | } | ||
261 | |||
262 | if (info->attrs[NL80211_ATTR_KEY_IDX]) | ||
263 | k->idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]); | ||
264 | |||
265 | if (info->attrs[NL80211_ATTR_KEY_CIPHER]) | ||
266 | k->p.cipher = nla_get_u32(info->attrs[NL80211_ATTR_KEY_CIPHER]); | ||
267 | |||
268 | k->def = !!info->attrs[NL80211_ATTR_KEY_DEFAULT]; | ||
269 | k->defmgmt = !!info->attrs[NL80211_ATTR_KEY_DEFAULT_MGMT]; | ||
270 | |||
271 | return 0; | ||
272 | } | ||
273 | |||
274 | static int nl80211_parse_key(struct genl_info *info, struct key_parse *k) | ||
275 | { | ||
276 | int err; | ||
277 | |||
278 | memset(k, 0, sizeof(*k)); | ||
279 | k->idx = -1; | ||
280 | |||
281 | if (info->attrs[NL80211_ATTR_KEY]) | ||
282 | err = nl80211_parse_key_new(info->attrs[NL80211_ATTR_KEY], k); | ||
283 | else | ||
284 | err = nl80211_parse_key_old(info, k); | ||
285 | |||
286 | if (err) | ||
287 | return err; | ||
288 | |||
289 | if (k->def && k->defmgmt) | ||
290 | return -EINVAL; | ||
291 | |||
292 | if (k->idx != -1) { | ||
293 | if (k->defmgmt) { | ||
294 | if (k->idx < 4 || k->idx > 5) | ||
295 | return -EINVAL; | ||
296 | } else if (k->def) { | ||
297 | if (k->idx < 0 || k->idx > 3) | ||
298 | return -EINVAL; | ||
299 | } else { | ||
300 | if (k->idx < 0 || k->idx > 5) | ||
301 | return -EINVAL; | ||
302 | } | ||
303 | } | ||
304 | |||
305 | return 0; | ||
306 | } | ||
307 | |||
201 | static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | 308 | static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, |
202 | struct cfg80211_registered_device *dev) | 309 | struct cfg80211_registered_device *dev) |
203 | { | 310 | { |
@@ -943,10 +1050,12 @@ static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info) | |||
943 | struct get_key_cookie { | 1050 | struct get_key_cookie { |
944 | struct sk_buff *msg; | 1051 | struct sk_buff *msg; |
945 | int error; | 1052 | int error; |
1053 | int idx; | ||
946 | }; | 1054 | }; |
947 | 1055 | ||
948 | static void get_key_callback(void *c, struct key_params *params) | 1056 | static void get_key_callback(void *c, struct key_params *params) |
949 | { | 1057 | { |
1058 | struct nlattr *key; | ||
950 | struct get_key_cookie *cookie = c; | 1059 | struct get_key_cookie *cookie = c; |
951 | 1060 | ||
952 | if (params->key) | 1061 | if (params->key) |
@@ -961,6 +1070,26 @@ static void get_key_callback(void *c, struct key_params *params) | |||
961 | NLA_PUT_U32(cookie->msg, NL80211_ATTR_KEY_CIPHER, | 1070 | NLA_PUT_U32(cookie->msg, NL80211_ATTR_KEY_CIPHER, |
962 | params->cipher); | 1071 | params->cipher); |
963 | 1072 | ||
1073 | key = nla_nest_start(cookie->msg, NL80211_ATTR_KEY); | ||
1074 | if (!key) | ||
1075 | goto nla_put_failure; | ||
1076 | |||
1077 | if (params->key) | ||
1078 | NLA_PUT(cookie->msg, NL80211_KEY_DATA, | ||
1079 | params->key_len, params->key); | ||
1080 | |||
1081 | if (params->seq) | ||
1082 | NLA_PUT(cookie->msg, NL80211_KEY_SEQ, | ||
1083 | params->seq_len, params->seq); | ||
1084 | |||
1085 | if (params->cipher) | ||
1086 | NLA_PUT_U32(cookie->msg, NL80211_KEY_CIPHER, | ||
1087 | params->cipher); | ||
1088 | |||
1089 | NLA_PUT_U8(cookie->msg, NL80211_ATTR_KEY_IDX, cookie->idx); | ||
1090 | |||
1091 | nla_nest_end(cookie->msg, key); | ||
1092 | |||
964 | return; | 1093 | return; |
965 | nla_put_failure: | 1094 | nla_put_failure: |
966 | cookie->error = 1; | 1095 | cookie->error = 1; |
@@ -1014,6 +1143,7 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info) | |||
1014 | } | 1143 | } |
1015 | 1144 | ||
1016 | cookie.msg = msg; | 1145 | cookie.msg = msg; |
1146 | cookie.idx = key_idx; | ||
1017 | 1147 | ||
1018 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); | 1148 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); |
1019 | NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_idx); | 1149 | NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_idx); |
@@ -1049,26 +1179,21 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info) | |||
1049 | static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info) | 1179 | static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info) |
1050 | { | 1180 | { |
1051 | struct cfg80211_registered_device *rdev; | 1181 | struct cfg80211_registered_device *rdev; |
1182 | struct key_parse key; | ||
1052 | int err; | 1183 | int err; |
1053 | struct net_device *dev; | 1184 | struct net_device *dev; |
1054 | u8 key_idx; | ||
1055 | int (*func)(struct wiphy *wiphy, struct net_device *netdev, | 1185 | int (*func)(struct wiphy *wiphy, struct net_device *netdev, |
1056 | u8 key_index); | 1186 | u8 key_index); |
1057 | 1187 | ||
1058 | if (!info->attrs[NL80211_ATTR_KEY_IDX]) | 1188 | err = nl80211_parse_key(info, &key); |
1059 | return -EINVAL; | 1189 | if (err) |
1060 | 1190 | return err; | |
1061 | key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]); | ||
1062 | 1191 | ||
1063 | if (info->attrs[NL80211_ATTR_KEY_DEFAULT_MGMT]) { | 1192 | if (key.idx < 0) |
1064 | if (key_idx < 4 || key_idx > 5) | ||
1065 | return -EINVAL; | ||
1066 | } else if (key_idx > 3) | ||
1067 | return -EINVAL; | 1193 | return -EINVAL; |
1068 | 1194 | ||
1069 | /* currently only support setting default key */ | 1195 | /* only support setting default key */ |
1070 | if (!info->attrs[NL80211_ATTR_KEY_DEFAULT] && | 1196 | if (!key.def && !key.defmgmt) |
1071 | !info->attrs[NL80211_ATTR_KEY_DEFAULT_MGMT]) | ||
1072 | return -EINVAL; | 1197 | return -EINVAL; |
1073 | 1198 | ||
1074 | rtnl_lock(); | 1199 | rtnl_lock(); |
@@ -1077,7 +1202,7 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info) | |||
1077 | if (err) | 1202 | if (err) |
1078 | goto unlock_rtnl; | 1203 | goto unlock_rtnl; |
1079 | 1204 | ||
1080 | if (info->attrs[NL80211_ATTR_KEY_DEFAULT]) | 1205 | if (key.def) |
1081 | func = rdev->ops->set_default_key; | 1206 | func = rdev->ops->set_default_key; |
1082 | else | 1207 | else |
1083 | func = rdev->ops->set_default_mgmt_key; | 1208 | func = rdev->ops->set_default_mgmt_key; |
@@ -1087,13 +1212,13 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info) | |||
1087 | goto out; | 1212 | goto out; |
1088 | } | 1213 | } |
1089 | 1214 | ||
1090 | err = func(&rdev->wiphy, dev, key_idx); | 1215 | err = func(&rdev->wiphy, dev, key.idx); |
1091 | #ifdef CONFIG_WIRELESS_EXT | 1216 | #ifdef CONFIG_WIRELESS_EXT |
1092 | if (!err) { | 1217 | if (!err) { |
1093 | if (func == rdev->ops->set_default_key) | 1218 | if (func == rdev->ops->set_default_key) |
1094 | dev->ieee80211_ptr->wext.default_key = key_idx; | 1219 | dev->ieee80211_ptr->wext.default_key = key.idx; |
1095 | else | 1220 | else |
1096 | dev->ieee80211_ptr->wext.default_mgmt_key = key_idx; | 1221 | dev->ieee80211_ptr->wext.default_mgmt_key = key.idx; |
1097 | } | 1222 | } |
1098 | #endif | 1223 | #endif |
1099 | 1224 | ||
@@ -1112,34 +1237,20 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info) | |||
1112 | struct cfg80211_registered_device *rdev; | 1237 | struct cfg80211_registered_device *rdev; |
1113 | int err, i; | 1238 | int err, i; |
1114 | struct net_device *dev; | 1239 | struct net_device *dev; |
1115 | struct key_params params; | 1240 | struct key_parse key; |
1116 | u8 key_idx = 0; | ||
1117 | u8 *mac_addr = NULL; | 1241 | u8 *mac_addr = NULL; |
1118 | 1242 | ||
1119 | memset(¶ms, 0, sizeof(params)); | 1243 | err = nl80211_parse_key(info, &key); |
1244 | if (err) | ||
1245 | return err; | ||
1120 | 1246 | ||
1121 | if (!info->attrs[NL80211_ATTR_KEY_CIPHER]) | 1247 | if (!key.p.key) |
1122 | return -EINVAL; | 1248 | return -EINVAL; |
1123 | 1249 | ||
1124 | if (info->attrs[NL80211_ATTR_KEY_DATA]) { | ||
1125 | params.key = nla_data(info->attrs[NL80211_ATTR_KEY_DATA]); | ||
1126 | params.key_len = nla_len(info->attrs[NL80211_ATTR_KEY_DATA]); | ||
1127 | } | ||
1128 | |||
1129 | if (info->attrs[NL80211_ATTR_KEY_SEQ]) { | ||
1130 | params.seq = nla_data(info->attrs[NL80211_ATTR_KEY_SEQ]); | ||
1131 | params.seq_len = nla_len(info->attrs[NL80211_ATTR_KEY_SEQ]); | ||
1132 | } | ||
1133 | |||
1134 | if (info->attrs[NL80211_ATTR_KEY_IDX]) | ||
1135 | key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]); | ||
1136 | |||
1137 | params.cipher = nla_get_u32(info->attrs[NL80211_ATTR_KEY_CIPHER]); | ||
1138 | |||
1139 | if (info->attrs[NL80211_ATTR_MAC]) | 1250 | if (info->attrs[NL80211_ATTR_MAC]) |
1140 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | 1251 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); |
1141 | 1252 | ||
1142 | if (cfg80211_validate_key_settings(¶ms, key_idx, mac_addr)) | 1253 | if (cfg80211_validate_key_settings(&key.p, key.idx, mac_addr)) |
1143 | return -EINVAL; | 1254 | return -EINVAL; |
1144 | 1255 | ||
1145 | rtnl_lock(); | 1256 | rtnl_lock(); |
@@ -1149,7 +1260,7 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info) | |||
1149 | goto unlock_rtnl; | 1260 | goto unlock_rtnl; |
1150 | 1261 | ||
1151 | for (i = 0; i < rdev->wiphy.n_cipher_suites; i++) | 1262 | for (i = 0; i < rdev->wiphy.n_cipher_suites; i++) |
1152 | if (params.cipher == rdev->wiphy.cipher_suites[i]) | 1263 | if (key.p.cipher == rdev->wiphy.cipher_suites[i]) |
1153 | break; | 1264 | break; |
1154 | if (i == rdev->wiphy.n_cipher_suites) { | 1265 | if (i == rdev->wiphy.n_cipher_suites) { |
1155 | err = -EINVAL; | 1266 | err = -EINVAL; |
@@ -1161,7 +1272,7 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info) | |||
1161 | goto out; | 1272 | goto out; |
1162 | } | 1273 | } |
1163 | 1274 | ||
1164 | err = rdev->ops->add_key(&rdev->wiphy, dev, key_idx, mac_addr, ¶ms); | 1275 | err = rdev->ops->add_key(&rdev->wiphy, dev, key.idx, mac_addr, &key.p); |
1165 | 1276 | ||
1166 | out: | 1277 | out: |
1167 | cfg80211_unlock_rdev(rdev); | 1278 | cfg80211_unlock_rdev(rdev); |
@@ -1177,14 +1288,12 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info) | |||
1177 | struct cfg80211_registered_device *rdev; | 1288 | struct cfg80211_registered_device *rdev; |
1178 | int err; | 1289 | int err; |
1179 | struct net_device *dev; | 1290 | struct net_device *dev; |
1180 | u8 key_idx = 0; | ||
1181 | u8 *mac_addr = NULL; | 1291 | u8 *mac_addr = NULL; |
1292 | struct key_parse key; | ||
1182 | 1293 | ||
1183 | if (info->attrs[NL80211_ATTR_KEY_IDX]) | 1294 | err = nl80211_parse_key(info, &key); |
1184 | key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]); | 1295 | if (err) |
1185 | 1296 | return err; | |
1186 | if (key_idx > 5) | ||
1187 | return -EINVAL; | ||
1188 | 1297 | ||
1189 | if (info->attrs[NL80211_ATTR_MAC]) | 1298 | if (info->attrs[NL80211_ATTR_MAC]) |
1190 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); | 1299 | mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); |
@@ -1200,13 +1309,13 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info) | |||
1200 | goto out; | 1309 | goto out; |
1201 | } | 1310 | } |
1202 | 1311 | ||
1203 | err = rdev->ops->del_key(&rdev->wiphy, dev, key_idx, mac_addr); | 1312 | err = rdev->ops->del_key(&rdev->wiphy, dev, key.idx, mac_addr); |
1204 | 1313 | ||
1205 | #ifdef CONFIG_WIRELESS_EXT | 1314 | #ifdef CONFIG_WIRELESS_EXT |
1206 | if (!err) { | 1315 | if (!err) { |
1207 | if (key_idx == dev->ieee80211_ptr->wext.default_key) | 1316 | if (key.idx == dev->ieee80211_ptr->wext.default_key) |
1208 | dev->ieee80211_ptr->wext.default_key = -1; | 1317 | dev->ieee80211_ptr->wext.default_key = -1; |
1209 | else if (key_idx == dev->ieee80211_ptr->wext.default_mgmt_key) | 1318 | else if (key.idx == dev->ieee80211_ptr->wext.default_mgmt_key) |
1210 | dev->ieee80211_ptr->wext.default_mgmt_key = -1; | 1319 | dev->ieee80211_ptr->wext.default_mgmt_key = -1; |
1211 | } | 1320 | } |
1212 | #endif | 1321 | #endif |