fix up hostapd for mac80211
[librecmc/librecmc.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 */