fix up hostapd for mac80211
[openwrt/openwrt.git] / package / mac80211 / patches / 017-nl80211-add-key-mgmt.patch
1 Subject: cfg80211/nl80211: introduce key handling
2
3 This introduces key handling to cfg80211/nl80211. Default
4 and group keys can be added, changed and removed; sequence
5 counters for each key can be retrieved.
6
7 Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
8
9 ---
10 include/linux/nl80211.h | 34 +++++
11 include/net/cfg80211.h | 44 +++++++
12 net/wireless/core.c | 3
13 net/wireless/nl80211.c | 289 ++++++++++++++++++++++++++++++++++++++++++++++++
14 4 files changed, 370 insertions(+)
15
16 --- everything.orig/include/linux/nl80211.h 2007-10-30 15:33:43.587381346 +0100
17 +++ everything/include/linux/nl80211.h 2007-11-07 13:19:37.861516599 +0100
18 @@ -37,6 +37,16 @@
19 * userspace to request deletion of a virtual interface, then requires
20 * attribute %NL80211_ATTR_IFINDEX.
21 *
22 + * @NL80211_CMD_GET_KEY: Get sequence counter information for a key specified
23 + * by %NL80211_ATTR_KEY_IDX and/or %NL80211_ATTR_MAC.
24 + * @NL80211_CMD_SET_KEY: Set key attributes %NL80211_ATTR_KEY_DEFAULT or
25 + * %NL80211_ATTR_KEY_THRESHOLD.
26 + * @NL80211_CMD_NEW_KEY: add a key with given %NL80211_ATTR_KEY_DATA,
27 + * %NL80211_ATTR_KEY_IDX, %NL80211_ATTR_MAC and %NL80211_ATTR_KEY_CIPHER
28 + * attributes.
29 + * @NL80211_CMD_DEL_KEY: delete a key identified by %NL80211_ATTR_KEY_IDX
30 + * or %NL80211_ATTR_MAC.
31 + *
32 * @NL80211_CMD_MAX: highest used command number
33 * @__NL80211_CMD_AFTER_LAST: internal use
34 */
35 @@ -54,6 +64,11 @@ enum nl80211_commands {
36 NL80211_CMD_NEW_INTERFACE,
37 NL80211_CMD_DEL_INTERFACE,
38
39 + NL80211_CMD_GET_KEY,
40 + NL80211_CMD_SET_KEY,
41 + NL80211_CMD_NEW_KEY,
42 + NL80211_CMD_DEL_KEY,
43 +
44 /* add commands here */
45
46 /* used to define NL80211_CMD_MAX below */
47 @@ -75,6 +90,17 @@ enum nl80211_commands {
48 * @NL80211_ATTR_IFNAME: network interface name
49 * @NL80211_ATTR_IFTYPE: type of virtual interface, see &enum nl80211_iftype
50 *
51 + * @NL80211_ATTR_MAC: MAC address (various uses)
52 + *
53 + * @NL80211_ATTR_KEY_DATA: (temporal) key data; for TKIP this consists of
54 + * 16 bytes encryption key followed by 8 bytes each for TX and RX MIC
55 + * keys
56 + * @NL80211_ATTR_KEY_IDX: key ID (u8, 0-3)
57 + * @NL80211_ATTR_KEY_CIPHER: key cipher suite (u32, as defined by IEEE 802.11
58 + * section 7.3.2.25.1, e.g. 0x000FAC04)
59 + * @NL80211_ATTR_KEY_SEQ: transmit key sequence number (IV/PN) for TKIP and
60 + * CCMP keys, each six bytes in little endian
61 + *
62 * @NL80211_ATTR_MAX: highest attribute number currently defined
63 * @__NL80211_ATTR_AFTER_LAST: internal use
64 */
65 @@ -89,6 +115,14 @@ enum nl80211_attrs {
66 NL80211_ATTR_IFNAME,
67 NL80211_ATTR_IFTYPE,
68
69 + NL80211_ATTR_MAC,
70 +
71 + NL80211_ATTR_KEY_DATA,
72 + NL80211_ATTR_KEY_IDX,
73 + NL80211_ATTR_KEY_CIPHER,
74 + NL80211_ATTR_KEY_SEQ,
75 + NL80211_ATTR_KEY_DEFAULT,
76 +
77 /* add attributes here, update the policy in nl80211.c */
78
79 __NL80211_ATTR_AFTER_LAST,
80 --- everything.orig/net/wireless/nl80211.c 2007-10-30 15:33:43.637380153 +0100
81 +++ everything/net/wireless/nl80211.c 2007-11-07 13:19:38.201511066 +0100
82 @@ -61,6 +61,14 @@ static struct nla_policy nl80211_policy[
83 [NL80211_ATTR_IFTYPE] = { .type = NLA_U32 },
84 [NL80211_ATTR_IFINDEX] = { .type = NLA_U32 },
85 [NL80211_ATTR_IFNAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ-1 },
86 +
87 + [NL80211_ATTR_MAC] = { .type = NLA_BINARY, .len = ETH_ALEN },
88 +
89 + [NL80211_ATTR_KEY_DATA] = { .type = NLA_BINARY,
90 + .len = WLAN_MAX_KEY_LEN },
91 + [NL80211_ATTR_KEY_IDX] = { .type = NLA_U8 },
92 + [NL80211_ATTR_KEY_CIPHER] = { .type = NLA_U32 },
93 + [NL80211_ATTR_KEY_DEFAULT] = { .type = NLA_FLAG },
94 };
95
96 /* message building helper */
97 @@ -335,6 +343,263 @@ static int nl80211_del_interface(struct
98 return err;
99 }
100
101 +struct get_key_cookie {
102 + struct sk_buff *msg;
103 + int error;
104 +};
105 +
106 +static void get_key_callback(void *c, struct key_params *params)
107 +{
108 + struct get_key_cookie *cookie = c;
109 +
110 + if (params->key)
111 + NLA_PUT(cookie->msg, NL80211_ATTR_KEY_DATA,
112 + params->key_len, params->key);
113 +
114 + if (params->seq)
115 + NLA_PUT(cookie->msg, NL80211_ATTR_KEY_SEQ,
116 + params->seq_len, params->seq);
117 +
118 + if (params->cipher)
119 + NLA_PUT_U32(cookie->msg, NL80211_ATTR_KEY_CIPHER,
120 + params->cipher);
121 +
122 + return;
123 + nla_put_failure:
124 + cookie->error = 1;
125 +}
126 +
127 +static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info)
128 +{
129 + struct cfg80211_registered_device *drv;
130 + int err;
131 + struct net_device *dev;
132 + u8 key_idx = 0;
133 + u8 *mac_addr = NULL;
134 + struct get_key_cookie cookie = {
135 + .error = 0,
136 + };
137 + void *hdr;
138 + struct sk_buff *msg;
139 +
140 + if (info->attrs[NL80211_ATTR_KEY_IDX])
141 + key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
142 +
143 + if (key_idx > 3)
144 + return -EINVAL;
145 +
146 + if (info->attrs[NL80211_ATTR_MAC])
147 + mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
148 +
149 + err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
150 + if (err)
151 + return err;
152 +
153 + if (!drv->ops->get_key) {
154 + err = -EOPNOTSUPP;
155 + goto out;
156 + }
157 +
158 + msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
159 + if (!msg) {
160 + err = -ENOMEM;
161 + goto out;
162 + }
163 +
164 + hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0,
165 + NL80211_CMD_NEW_KEY);
166 +
167 + if (IS_ERR(hdr)) {
168 + err = PTR_ERR(hdr);
169 + goto out;
170 + }
171 +
172 + cookie.msg = msg;
173 +
174 + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);
175 + NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_idx);
176 + if (mac_addr)
177 + NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr);
178 +
179 + rtnl_lock();
180 + err = drv->ops->get_key(&drv->wiphy, dev, key_idx, mac_addr,
181 + &cookie, get_key_callback);
182 + rtnl_unlock();
183 +
184 + if (err)
185 + goto out;
186 +
187 + if (cookie.error)
188 + goto nla_put_failure;
189 +
190 + genlmsg_end(msg, hdr);
191 + err = genlmsg_unicast(msg, info->snd_pid);
192 + goto out;
193 +
194 + nla_put_failure:
195 + err = -ENOBUFS;
196 + nlmsg_free(msg);
197 + out:
198 + cfg80211_put_dev(drv);
199 + dev_put(dev);
200 + return err;
201 +}
202 +
203 +static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
204 +{
205 + struct cfg80211_registered_device *drv;
206 + int err;
207 + struct net_device *dev;
208 + u8 key_idx;
209 +
210 + if (!info->attrs[NL80211_ATTR_KEY_IDX])
211 + return -EINVAL;
212 +
213 + key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
214 +
215 + if (key_idx > 3)
216 + return -EINVAL;
217 +
218 + /* currently only support setting default key */
219 + if (!info->attrs[NL80211_ATTR_KEY_DEFAULT])
220 + return -EINVAL;
221 +
222 + err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
223 + if (err)
224 + return err;
225 +
226 + if (!drv->ops->set_default_key) {
227 + err = -EOPNOTSUPP;
228 + goto out;
229 + }
230 +
231 + rtnl_lock();
232 + err = drv->ops->set_default_key(&drv->wiphy, dev, key_idx);
233 + rtnl_unlock();
234 +
235 + out:
236 + cfg80211_put_dev(drv);
237 + dev_put(dev);
238 + return err;
239 +}
240 +
241 +static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info)
242 +{
243 + struct cfg80211_registered_device *drv;
244 + int err;
245 + struct net_device *dev;
246 + struct key_params params;
247 + u8 key_idx = 0;
248 + u8 *mac_addr = NULL;
249 +
250 + memset(&params, 0, sizeof(params));
251 +
252 + if (!info->attrs[NL80211_ATTR_KEY_CIPHER])
253 + return -EINVAL;
254 +
255 + if (info->attrs[NL80211_ATTR_KEY_DATA]) {
256 + params.key = nla_data(info->attrs[NL80211_ATTR_KEY_DATA]);
257 + params.key_len = nla_len(info->attrs[NL80211_ATTR_KEY_DATA]);
258 + }
259 +
260 + if (info->attrs[NL80211_ATTR_KEY_IDX])
261 + key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
262 +
263 + params.cipher = nla_get_u32(info->attrs[NL80211_ATTR_KEY_CIPHER]);
264 +
265 + if (info->attrs[NL80211_ATTR_MAC])
266 + mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
267 +
268 + if (key_idx > 3)
269 + return -EINVAL;
270 +
271 + /*
272 + * Disallow pairwise keys with non-zero index unless it's WEP
273 + * (because current deployments use pairwise WEP keys with
274 + * non-zero indizes but 802.11i clearly specifies to use zero)
275 + */
276 + if (mac_addr && key_idx &&
277 + params.cipher != WLAN_CIPHER_SUITE_WEP40 &&
278 + params.cipher != WLAN_CIPHER_SUITE_WEP104)
279 + return -EINVAL;
280 +
281 + /* TODO: add definitions for the lengths to linux/ieee80211.h */
282 + switch (params.cipher) {
283 + case WLAN_CIPHER_SUITE_WEP40:
284 + if (params.key_len != 5)
285 + return -EINVAL;
286 + break;
287 + case WLAN_CIPHER_SUITE_TKIP:
288 + if (params.key_len != 32)
289 + return -EINVAL;
290 + break;
291 + case WLAN_CIPHER_SUITE_CCMP:
292 + if (params.key_len != 16)
293 + return -EINVAL;
294 + break;
295 + case WLAN_CIPHER_SUITE_WEP104:
296 + if (params.key_len != 13)
297 + return -EINVAL;
298 + break;
299 + default:
300 + return -EINVAL;
301 + }
302 +
303 + err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
304 + if (err)
305 + return err;
306 +
307 + if (!drv->ops->add_key) {
308 + err = -EOPNOTSUPP;
309 + goto out;
310 + }
311 +
312 + rtnl_lock();
313 + err = drv->ops->add_key(&drv->wiphy, dev, key_idx, mac_addr, &params);
314 + rtnl_unlock();
315 +
316 + out:
317 + cfg80211_put_dev(drv);
318 + dev_put(dev);
319 + return err;
320 +}
321 +
322 +static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info)
323 +{
324 + struct cfg80211_registered_device *drv;
325 + int err;
326 + struct net_device *dev;
327 + u8 key_idx = 0;
328 + u8 *mac_addr = NULL;
329 +
330 + if (info->attrs[NL80211_ATTR_KEY_IDX])
331 + key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
332 +
333 + if (key_idx > 3)
334 + return -EINVAL;
335 +
336 + if (info->attrs[NL80211_ATTR_MAC])
337 + mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
338 +
339 + err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
340 + if (err)
341 + return err;
342 +
343 + if (!drv->ops->del_key) {
344 + err = -EOPNOTSUPP;
345 + goto out;
346 + }
347 +
348 + rtnl_lock();
349 + err = drv->ops->del_key(&drv->wiphy, dev, key_idx, mac_addr);
350 + rtnl_unlock();
351 +
352 + out:
353 + cfg80211_put_dev(drv);
354 + dev_put(dev);
355 + return err;
356 +}
357 +
358 static struct genl_ops nl80211_ops[] = {
359 {
360 .cmd = NL80211_CMD_GET_WIPHY,
361 @@ -374,6 +639,30 @@ static struct genl_ops nl80211_ops[] = {
362 .policy = nl80211_policy,
363 .flags = GENL_ADMIN_PERM,
364 },
365 + {
366 + .cmd = NL80211_CMD_GET_KEY,
367 + .doit = nl80211_get_key,
368 + .policy = nl80211_policy,
369 + .flags = GENL_ADMIN_PERM,
370 + },
371 + {
372 + .cmd = NL80211_CMD_SET_KEY,
373 + .doit = nl80211_set_key,
374 + .policy = nl80211_policy,
375 + .flags = GENL_ADMIN_PERM,
376 + },
377 + {
378 + .cmd = NL80211_CMD_NEW_KEY,
379 + .doit = nl80211_new_key,
380 + .policy = nl80211_policy,
381 + .flags = GENL_ADMIN_PERM,
382 + },
383 + {
384 + .cmd = NL80211_CMD_DEL_KEY,
385 + .doit = nl80211_del_key,
386 + .policy = nl80211_policy,
387 + .flags = GENL_ADMIN_PERM,
388 + },
389 };
390
391 /* multicast groups */
392 --- everything.orig/net/wireless/core.c 2007-10-30 15:33:43.677380478 +0100
393 +++ everything/net/wireless/core.c 2007-11-07 13:19:38.221513833 +0100
394 @@ -184,6 +184,9 @@ struct wiphy *wiphy_new(struct cfg80211_
395 struct cfg80211_registered_device *drv;
396 int alloc_size;
397
398 + WARN_ON(!ops->add_key && ops->del_key);
399 + WARN_ON(ops->add_key && !ops->del_key);
400 +
401 alloc_size = sizeof(*drv) + sizeof_priv;
402
403 drv = kzalloc(alloc_size, GFP_KERNEL);
404 --- everything.orig/include/net/cfg80211.h 2007-10-30 15:33:43.617381780 +0100
405 +++ everything/include/net/cfg80211.h 2007-11-07 13:19:38.231512748 +0100
406 @@ -49,6 +49,26 @@ extern int ieee80211_radiotap_iterator_n
407 struct ieee80211_radiotap_iterator *iterator);
408
409
410 + /**
411 + * struct key_params - key information
412 + *
413 + * Information about a key
414 + *
415 + * @key: key material
416 + * @key_len: length of key material
417 + * @cipher: cipher suite selector
418 + * @seq: sequence counter (IV/PN) for TKIP and CCMP keys, only used
419 + * with the get_key() callback, must be in little endian,
420 + * length given by @seq_len.
421 + */
422 +struct key_params {
423 + u8 *key;
424 + u8 *seq;
425 + int key_len;
426 + int seq_len;
427 + u32 cipher;
428 +};
429 +
430 /* from net/wireless.h */
431 struct wiphy;
432
433 @@ -71,6 +91,18 @@ struct wiphy;
434 *
435 * @change_virtual_intf: change type of virtual interface
436 *
437 + * @add_key: add a key with the given parameters. @mac_addr will be %NULL
438 + * when adding a group key.
439 + *
440 + * @get_key: get information about the key with the given parameters.
441 + * @mac_addr will be %NULL when requesting information for a group
442 + * key. All pointers given to the @callback function need not be valid
443 + * after it returns.
444 + *
445 + * @del_key: remove a key given the @mac_addr (%NULL for a group key)
446 + * and @key_index
447 + *
448 + * @set_default_key: set the default key on an interface
449 */
450 struct cfg80211_ops {
451 int (*add_virtual_intf)(struct wiphy *wiphy, char *name,
452 @@ -78,6 +110,18 @@ struct cfg80211_ops {
453 int (*del_virtual_intf)(struct wiphy *wiphy, int ifindex);
454 int (*change_virtual_intf)(struct wiphy *wiphy, int ifindex,
455 enum nl80211_iftype type);
456 +
457 + int (*add_key)(struct wiphy *wiphy, struct net_device *netdev,
458 + u8 key_index, u8 *mac_addr,
459 + struct key_params *params);
460 + int (*get_key)(struct wiphy *wiphy, struct net_device *netdev,
461 + u8 key_index, u8 *mac_addr, void *cookie,
462 + void (*callback)(void *cookie, struct key_params*));
463 + int (*del_key)(struct wiphy *wiphy, struct net_device *netdev,
464 + u8 key_index, u8 *mac_addr);
465 + int (*set_default_key)(struct wiphy *wiphy,
466 + struct net_device *netdev,
467 + u8 key_index);
468 };
469
470 #endif /* __NET_CFG80211_H */