1 Subject: cfg80211/nl80211: introduce key handling
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.
7 Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
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(+)
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
19 * userspace to request deletion of a virtual interface, then requires
20 * attribute %NL80211_ATTR_IFINDEX.
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
29 + * @NL80211_CMD_DEL_KEY: delete a key identified by %NL80211_ATTR_KEY_IDX
30 + * or %NL80211_ATTR_MAC.
32 * @NL80211_CMD_MAX: highest used command number
33 * @__NL80211_CMD_AFTER_LAST: internal use
35 @@ -54,6 +64,11 @@ enum nl80211_commands {
36 NL80211_CMD_NEW_INTERFACE,
37 NL80211_CMD_DEL_INTERFACE,
39 + NL80211_CMD_GET_KEY,
40 + NL80211_CMD_SET_KEY,
41 + NL80211_CMD_NEW_KEY,
42 + NL80211_CMD_DEL_KEY,
44 /* add commands here */
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
51 + * @NL80211_ATTR_MAC: MAC address (various uses)
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
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
62 * @NL80211_ATTR_MAX: highest attribute number currently defined
63 * @__NL80211_ATTR_AFTER_LAST: internal use
65 @@ -89,6 +115,14 @@ enum nl80211_attrs {
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,
77 /* add attributes here, update the policy in nl80211.c */
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 },
87 + [NL80211_ATTR_MAC] = { .type = NLA_BINARY, .len = ETH_ALEN },
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 },
96 /* message building helper */
97 @@ -335,6 +343,263 @@ static int nl80211_del_interface(struct
101 +struct get_key_cookie {
102 + struct sk_buff *msg;
106 +static void get_key_callback(void *c, struct key_params *params)
108 + struct get_key_cookie *cookie = c;
111 + NLA_PUT(cookie->msg, NL80211_ATTR_KEY_DATA,
112 + params->key_len, params->key);
115 + NLA_PUT(cookie->msg, NL80211_ATTR_KEY_SEQ,
116 + params->seq_len, params->seq);
118 + if (params->cipher)
119 + NLA_PUT_U32(cookie->msg, NL80211_ATTR_KEY_CIPHER,
127 +static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info)
129 + struct cfg80211_registered_device *drv;
131 + struct net_device *dev;
133 + u8 *mac_addr = NULL;
134 + struct get_key_cookie cookie = {
138 + struct sk_buff *msg;
140 + if (info->attrs[NL80211_ATTR_KEY_IDX])
141 + key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
146 + if (info->attrs[NL80211_ATTR_MAC])
147 + mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
149 + err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
153 + if (!drv->ops->get_key) {
158 + msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
164 + hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0,
165 + NL80211_CMD_NEW_KEY);
168 + err = PTR_ERR(hdr);
174 + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);
175 + NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_idx);
177 + NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr);
180 + err = drv->ops->get_key(&drv->wiphy, dev, key_idx, mac_addr,
181 + &cookie, get_key_callback);
188 + goto nla_put_failure;
190 + genlmsg_end(msg, hdr);
191 + err = genlmsg_unicast(msg, info->snd_pid);
198 + cfg80211_put_dev(drv);
203 +static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
205 + struct cfg80211_registered_device *drv;
207 + struct net_device *dev;
210 + if (!info->attrs[NL80211_ATTR_KEY_IDX])
213 + key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
218 + /* currently only support setting default key */
219 + if (!info->attrs[NL80211_ATTR_KEY_DEFAULT])
222 + err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
226 + if (!drv->ops->set_default_key) {
232 + err = drv->ops->set_default_key(&drv->wiphy, dev, key_idx);
236 + cfg80211_put_dev(drv);
241 +static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info)
243 + struct cfg80211_registered_device *drv;
245 + struct net_device *dev;
246 + struct key_params params;
248 + u8 *mac_addr = NULL;
250 + memset(¶ms, 0, sizeof(params));
252 + if (!info->attrs[NL80211_ATTR_KEY_CIPHER])
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]);
260 + if (info->attrs[NL80211_ATTR_KEY_IDX])
261 + key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
263 + params.cipher = nla_get_u32(info->attrs[NL80211_ATTR_KEY_CIPHER]);
265 + if (info->attrs[NL80211_ATTR_MAC])
266 + mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
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)
276 + if (mac_addr && key_idx &&
277 + params.cipher != WLAN_CIPHER_SUITE_WEP40 &&
278 + params.cipher != WLAN_CIPHER_SUITE_WEP104)
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)
287 + case WLAN_CIPHER_SUITE_TKIP:
288 + if (params.key_len != 32)
291 + case WLAN_CIPHER_SUITE_CCMP:
292 + if (params.key_len != 16)
295 + case WLAN_CIPHER_SUITE_WEP104:
296 + if (params.key_len != 13)
303 + err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
307 + if (!drv->ops->add_key) {
313 + err = drv->ops->add_key(&drv->wiphy, dev, key_idx, mac_addr, ¶ms);
317 + cfg80211_put_dev(drv);
322 +static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info)
324 + struct cfg80211_registered_device *drv;
326 + struct net_device *dev;
328 + u8 *mac_addr = NULL;
330 + if (info->attrs[NL80211_ATTR_KEY_IDX])
331 + key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
336 + if (info->attrs[NL80211_ATTR_MAC])
337 + mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
339 + err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
343 + if (!drv->ops->del_key) {
349 + err = drv->ops->del_key(&drv->wiphy, dev, key_idx, mac_addr);
353 + cfg80211_put_dev(drv);
358 static struct genl_ops nl80211_ops[] = {
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,
366 + .cmd = NL80211_CMD_GET_KEY,
367 + .doit = nl80211_get_key,
368 + .policy = nl80211_policy,
369 + .flags = GENL_ADMIN_PERM,
372 + .cmd = NL80211_CMD_SET_KEY,
373 + .doit = nl80211_set_key,
374 + .policy = nl80211_policy,
375 + .flags = GENL_ADMIN_PERM,
378 + .cmd = NL80211_CMD_NEW_KEY,
379 + .doit = nl80211_new_key,
380 + .policy = nl80211_policy,
381 + .flags = GENL_ADMIN_PERM,
384 + .cmd = NL80211_CMD_DEL_KEY,
385 + .doit = nl80211_del_key,
386 + .policy = nl80211_policy,
387 + .flags = GENL_ADMIN_PERM,
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;
398 + WARN_ON(!ops->add_key && ops->del_key);
399 + WARN_ON(ops->add_key && !ops->del_key);
401 alloc_size = sizeof(*drv) + sizeof_priv;
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);
411 + * struct key_params - key information
413 + * Information about a key
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.
430 /* from net/wireless.h */
433 @@ -71,6 +91,18 @@ struct wiphy;
435 * @change_virtual_intf: change type of virtual interface
437 + * @add_key: add a key with the given parameters. @mac_addr will be %NULL
438 + * when adding a group key.
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.
445 + * @del_key: remove a key given the @mac_addr (%NULL for a group key)
448 + * @set_default_key: set the default key on an interface
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);
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,
470 #endif /* __NET_CFG80211_H */