fix up hostapd for mac80211
[librecmc/librecmc.git] / package / mac80211 / patches / 022-nl80211-sta.patch
1 Subject: cfg80211/nl80211: station handling
2
3 This patch adds station handling to cfg80211/nl80211.
4
5 Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
6
7 ---
8  include/linux/nl80211.h |   68 +++++++++++++
9  include/net/cfg80211.h  |   54 ++++++++++
10  net/wireless/nl80211.c  |  236 ++++++++++++++++++++++++++++++++++++++++++++++++
11  3 files changed, 358 insertions(+)
12
13 --- everything.orig/include/linux/nl80211.h     2007-11-08 16:56:32.431522732 +0100
14 +++ everything/include/linux/nl80211.h  2007-11-08 17:15:15.961529840 +0100
15 @@ -7,6 +7,18 @@
16   */
17  
18  /**
19 + * DOC: Station handling
20 + *
21 + * Stations are added per interface, but a special case exists with VLAN
22 + * interfaces. When a station is bound to an AP interface, it may be moved
23 + * into a VLAN identified by a VLAN interface index (%NL80211_ATTR_STA_VLAN).
24 + * The station is still assumed to belong to the AP interface it was added
25 + * to.
26 + *
27 + * TODO: need more info?
28 + */
29 +
30 +/**
31   * enum nl80211_commands - supported nl80211 commands
32   *
33   * @NL80211_CMD_UNSPEC: unspecified command to catch errors
34 @@ -56,6 +68,16 @@
35   *     parameters are like for %NL80211_CMD_SET_BEACON.
36   * @NL80211_CMD_DEL_BEACON: remove the beacon, stop sending it
37   *
38 + * @NL80211_CMD_GET_STATION: Get station attributes for station identified by
39 + *     %NL80211_ATTR_MAC on the interface identified by %NL80211_ATTR_IFINDEX.
40 + * @NL80211_CMD_SET_STATION: Set station attributes for station identified by
41 + *     %NL80211_ATTR_MAC on the interface identified by %NL80211_ATTR_IFINDEX.
42 + * @NL80211_CMD_NEW_STATION: Add a station with given attributes to the
43 + *     the interface identified by %NL80211_ATTR_IFINDEX.
44 + * @NL80211_CMD_DEL_STATION: Remove a station identified by %NL80211_ATTR_MAC
45 + *     or, if no MAC address given, all stations, on the interface identified
46 + *     by %NL80211_ATTR_IFINDEX.
47 + *
48   * @NL80211_CMD_MAX: highest used command number
49   * @__NL80211_CMD_AFTER_LAST: internal use
50   */
51 @@ -83,6 +105,11 @@ enum nl80211_commands {
52         NL80211_CMD_NEW_BEACON,
53         NL80211_CMD_DEL_BEACON,
54  
55 +       NL80211_CMD_GET_STATION,
56 +       NL80211_CMD_SET_STATION,
57 +       NL80211_CMD_NEW_STATION,
58 +       NL80211_CMD_DEL_STATION,
59 +
60         /* add commands here */
61  
62         /* used to define NL80211_CMD_MAX below */
63 @@ -120,6 +147,17 @@ enum nl80211_commands {
64   * @NL80211_ATTR_BEACON_HEAD: portion of the beacon before the TIM IE
65   * @NL80211_ATTR_BEACON_TAIL: portion of the beacon after the TIM IE
66   *
67 + * @NL80211_ATTR_STA_AID: Association ID for the station (u16)
68 + * @NL80211_ATTR_STA_FLAGS: flags, nested element with NLA_FLAG attributes of
69 + *     &enum nl80211_sta_flags.
70 + * @NL80211_ATTR_STA_LISTEN_INTERVAL: listen interval as defined by
71 + *     IEEE 802.11 7.3.1.6 (u16).
72 + * @NL80211_ATTR_STA_SUPPORTED_RATES: supported rates, array of supported
73 + *     rates as defined by IEEE 802.11 7.3.2.2 but without the length
74 + *     restriction (at most %NL80211_MAX_SUPP_RATES).
75 + * @NL80211_ATTR_STA_VLAN: interface index of VLAN interface to move station
76 + *     to, or the AP interface the station was originally added to to.
77 + *
78   * @NL80211_ATTR_MAX: highest attribute number currently defined
79   * @__NL80211_ATTR_AFTER_LAST: internal use
80   */
81 @@ -147,12 +185,20 @@ enum nl80211_attrs {
82         NL80211_ATTR_BEACON_HEAD,
83         NL80211_ATTR_BEACON_TAIL,
84  
85 +       NL80211_ATTR_STA_AID,
86 +       NL80211_ATTR_STA_FLAGS,
87 +       NL80211_ATTR_STA_LISTEN_INTERVAL,
88 +       NL80211_ATTR_STA_SUPPORTED_RATES,
89 +       NL80211_ATTR_STA_VLAN,
90 +
91         /* add attributes here, update the policy in nl80211.c */
92  
93         __NL80211_ATTR_AFTER_LAST,
94         NL80211_ATTR_MAX = __NL80211_ATTR_AFTER_LAST - 1
95  };
96  
97 +#define NL80211_MAX_SUPP_RATES 32
98 +
99  /**
100   * enum nl80211_iftype - (virtual) interface types
101   *
102 @@ -184,4 +230,26 @@ enum nl80211_iftype {
103         NL80211_IFTYPE_MAX = __NL80211_IFTYPE_AFTER_LAST - 1
104  };
105  
106 +/**
107 + * enum nl80211_sta_flags - station flags
108 + *
109 + * Station flags. When a station is added to an AP interface, it is
110 + * assumed to be already associated (and hence authenticated.)
111 + *
112 + * @NL80211_STA_FLAG_AUTHORIZED: station is authorized (802.1X)
113 + * @NL80211_STA_FLAG_SHORT_PREAMBLE: station is capable of receiving frames
114 + *     with short barker preamble
115 + * @NL80211_STA_FLAG_WME: station is WME/QoS capable
116 + */
117 +enum nl80211_sta_flags {
118 +       __NL80211_STA_FLAG_INVALID,
119 +       NL80211_STA_FLAG_AUTHORIZED,
120 +       NL80211_STA_FLAG_SHORT_PREAMBLE,
121 +       NL80211_STA_FLAG_WME,
122 +
123 +       /* keep last */
124 +       __NL80211_STA_FLAG_AFTER_LAST,
125 +       NL80211_STA_FLAG_MAX = __NL80211_STA_FLAG_AFTER_LAST - 1
126 +};
127 +
128  #endif /* __LINUX_NL80211_H */
129 --- everything.orig/include/net/cfg80211.h      2007-11-08 16:50:38.421522842 +0100
130 +++ everything/include/net/cfg80211.h   2007-11-08 17:15:15.971532444 +0100
131 @@ -89,6 +89,47 @@ struct beacon_parameters {
132         int head_len, tail_len;
133  };
134  
135 +/**
136 + * enum station_flags - station flags
137 + *
138 + * Station capability flags. Note that these must be the bits
139 + * according to the nl80211 flags.
140 + *
141 + * @STATION_FLAG_CHANGED: station flags were changed
142 + * @STATION_FLAG_AUTHORIZED: station is authorized to send frames (802.1X)
143 + * @STATION_FLAG_SHORT_PREAMBLE: station is capable of receiving frames
144 + *     with short preambles
145 + * @STATION_FLAG_WME: station is WME/QoS capable
146 + */
147 +enum station_flags {
148 +       STATION_FLAG_CHANGED            = 1<<0,
149 +       STATION_FLAG_AUTHORIZED         = 1<<NL80211_STA_FLAG_AUTHORIZED,
150 +       STATION_FLAG_SHORT_PREAMBLE     = 1<<NL80211_STA_FLAG_SHORT_PREAMBLE,
151 +       STATION_FLAG_WME                = 1<<NL80211_STA_FLAG_WME,
152 +};
153 +
154 +/**
155 + * struct station_parameters - station parameters
156 + *
157 + * Used to change and create a new station.
158 + *
159 + * @vlan: vlan interface station should belong to
160 + * @supported_rates: supported rates in IEEE 802.11 format
161 + *     (or NULL for no change)
162 + * @supported_rates_len: number of supported rates
163 + * @station_flags: station flags (see &enum station_flags)
164 + * @listen_interval: listen interval or -1 for no change
165 + * @aid: AID or zero for no change
166 + */
167 +struct station_parameters {
168 +       u8 *supported_rates;
169 +       struct net_device *vlan;
170 +       u32 station_flags;
171 +       int listen_interval;
172 +       u16 aid;
173 +       u8 supported_rates_len;
174 +};
175 +
176  /* from net/wireless.h */
177  struct wiphy;
178  
179 @@ -130,6 +171,12 @@ struct wiphy;
180   *     interface. This should reject the call when no beacon has been
181   *     configured.
182   * @del_beacon: Remove beacon configuration and stop sending the beacon.
183 + *
184 + * @add_station: Add a new station.
185 + *
186 + * @del_station: Remove a station; @mac may be NULL to remove all stations.
187 + *
188 + * @change_station: Modify a given station.
189   */
190  struct cfg80211_ops {
191         int     (*add_virtual_intf)(struct wiphy *wiphy, char *name,
192 @@ -155,6 +202,13 @@ struct cfg80211_ops {
193         int     (*set_beacon)(struct wiphy *wiphy, struct net_device *dev,
194                               struct beacon_parameters *info);
195         int     (*del_beacon)(struct wiphy *wiphy, struct net_device *dev);
196 +
197 +       int     (*add_station)(struct wiphy *wiphy, struct net_device *dev,
198 +                              u8 *mac, struct station_parameters *params);
199 +       int     (*del_station)(struct wiphy *wiphy, struct net_device *dev,
200 +                              u8 *mac);
201 +       int     (*change_station)(struct wiphy *wiphy, struct net_device *dev,
202 +                                 u8 *mac, struct station_parameters *params);
203  };
204  
205  #endif /* __NET_CFG80211_H */
206 --- everything.orig/net/wireless/nl80211.c      2007-11-08 16:58:36.711524524 +0100
207 +++ everything/net/wireless/nl80211.c   2007-11-08 17:15:15.981533909 +0100
208 @@ -76,6 +76,12 @@ static struct nla_policy nl80211_policy[
209                                        .len = IEEE80211_MAX_DATA_LEN },
210         [NL80211_ATTR_BEACON_TAIL] = { .type = NLA_BINARY,
211                                        .len = IEEE80211_MAX_DATA_LEN },
212 +       [NL80211_ATTR_STA_AID] = { .type = NLA_U16 },
213 +       [NL80211_ATTR_STA_FLAGS] = { .type = NLA_NESTED },
214 +       [NL80211_ATTR_STA_LISTEN_INTERVAL] = { .type = NLA_U16 },
215 +       [NL80211_ATTR_STA_SUPPORTED_RATES] = { .type = NLA_BINARY,
216 +                                              .len = NL80211_MAX_SUPP_RATES },
217 +       [NL80211_ATTR_STA_VLAN] = { .type = NLA_U32 },
218  };
219  
220  /* message building helper */
221 @@ -715,6 +721,211 @@ static int nl80211_del_beacon(struct sk_
222         return err;
223  }
224  
225 +static
226 +struct nla_policy sta_flags_policy[NL80211_STA_FLAG_MAX + 1] __read_mostly = {
227 +       [NL80211_STA_FLAG_AUTHORIZED] = { .type = NLA_FLAG },
228 +       [NL80211_STA_FLAG_SHORT_PREAMBLE] = { .type = NLA_FLAG },
229 +       [NL80211_STA_FLAG_WME] = { .type = NLA_FLAG },
230 +};
231 +
232 +static int parse_station_flags(struct nlattr *nla, u32 *staflags)
233 +{
234 +       struct nlattr *flags[NL80211_STA_FLAG_MAX + 1];
235 +       int flag;
236 +
237 +       *staflags = 0;
238 +
239 +       if (!nla)
240 +               return 0;
241 +
242 +       if (nla_parse_nested(flags, NL80211_STA_FLAG_MAX,
243 +                            nla, sta_flags_policy))
244 +               return -EINVAL;
245 +
246 +       *staflags = STATION_FLAG_CHANGED;
247 +
248 +       for (flag = 1; flag <= NL80211_STA_FLAG_MAX; flag++)
249 +               if (flags[flag])
250 +                       *staflags |= (1<<flag);
251 +
252 +       return 0;
253 +}
254 +
255 +static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info)
256 +{
257 +       return -EOPNOTSUPP;
258 +}
259 +
260 +/*
261 + * Get vlan interface making sure it is on the right wiphy.
262 + */
263 +static int get_vlan(struct nlattr *vlanattr,
264 +                   struct cfg80211_registered_device *rdev,
265 +                   struct net_device **vlan)
266 +{
267 +       *vlan = NULL;
268 +
269 +       if (vlanattr) {
270 +               *vlan = dev_get_by_index(nla_get_u32(vlanattr));
271 +               if (!*vlan)
272 +                       return -ENODEV;
273 +               if (!(*vlan)->ieee80211_ptr)
274 +                       return -EINVAL;
275 +               if ((*vlan)->ieee80211_ptr->wiphy != &rdev->wiphy)
276 +                       return -EINVAL;
277 +       }
278 +       return 0;
279 +}
280 +
281 +static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
282 +{
283 +       struct cfg80211_registered_device *drv;
284 +       int err;
285 +       struct net_device *dev;
286 +       struct station_parameters params;
287 +       u8 *mac_addr = NULL;
288 +
289 +       memset(&params, 0, sizeof(params));
290 +
291 +       params.listen_interval = -1;
292 +
293 +       if (info->attrs[NL80211_ATTR_STA_AID])
294 +               return -EINVAL;
295 +
296 +       if (!info->attrs[NL80211_ATTR_MAC])
297 +               return -EINVAL;
298 +
299 +       mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
300 +
301 +       if (info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]) {
302 +               params.supported_rates =
303 +                       nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
304 +               params.supported_rates_len =
305 +                       nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
306 +       }
307 +
308 +       if (info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL])
309 +               params.listen_interval =
310 +                   nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]);
311 +
312 +       if (parse_station_flags(info->attrs[NL80211_ATTR_STA_FLAGS],
313 +                               &params.station_flags))
314 +               return -EINVAL;
315 +
316 +       err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
317 +       if (err)
318 +               return err;
319 +
320 +       err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], drv, &params.vlan);
321 +       if (err)
322 +               goto out;
323 +
324 +       if (!drv->ops->change_station) {
325 +               err = -EOPNOTSUPP;
326 +               goto out;
327 +       }
328 +
329 +       rtnl_lock();
330 +       err = drv->ops->change_station(&drv->wiphy, dev, mac_addr, &params);
331 +       rtnl_unlock();
332 +
333 + out:
334 +       if (params.vlan)
335 +               dev_put(params.vlan);
336 +       cfg80211_put_dev(drv);
337 +       dev_put(dev);
338 +       return err;
339 +}
340 +
341 +static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
342 +{
343 +       struct cfg80211_registered_device *drv;
344 +       int err;
345 +       struct net_device *dev;
346 +       struct station_parameters params;
347 +       u8 *mac_addr = NULL;
348 +
349 +       memset(&params, 0, sizeof(params));
350 +
351 +       if (!info->attrs[NL80211_ATTR_MAC])
352 +               return -EINVAL;
353 +
354 +       if (!info->attrs[NL80211_ATTR_STA_AID])
355 +               return -EINVAL;
356 +
357 +       if (!info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL])
358 +               return -EINVAL;
359 +
360 +       if (!info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES])
361 +               return -EINVAL;
362 +
363 +       mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
364 +       params.supported_rates =
365 +               nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
366 +       params.supported_rates_len =
367 +               nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
368 +       params.listen_interval =
369 +               nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]);
370 +       params.listen_interval = nla_get_u16(info->attrs[NL80211_ATTR_STA_AID]);
371 +
372 +       if (parse_station_flags(info->attrs[NL80211_ATTR_STA_FLAGS],
373 +                               &params.station_flags))
374 +               return -EINVAL;
375 +
376 +       err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
377 +       if (err)
378 +               return err;
379 +
380 +       err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], drv, &params.vlan);
381 +       if (err)
382 +               goto out;
383 +
384 +       if (!drv->ops->add_station) {
385 +               err = -EOPNOTSUPP;
386 +               goto out;
387 +       }
388 +
389 +       rtnl_lock();
390 +       err = drv->ops->add_station(&drv->wiphy, dev, mac_addr, &params);
391 +       rtnl_unlock();
392 +
393 + out:
394 +       if (params.vlan)
395 +               dev_put(params.vlan);
396 +       cfg80211_put_dev(drv);
397 +       dev_put(dev);
398 +       return err;
399 +}
400 +
401 +static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info)
402 +{
403 +       struct cfg80211_registered_device *drv;
404 +       int err;
405 +       struct net_device *dev;
406 +       u8 *mac_addr = NULL;
407 +
408 +       if (info->attrs[NL80211_ATTR_MAC])
409 +               mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
410 +
411 +       err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
412 +       if (err)
413 +               return err;
414 +
415 +       if (!drv->ops->del_station) {
416 +               err = -EOPNOTSUPP;
417 +               goto out;
418 +       }
419 +
420 +       rtnl_lock();
421 +       err = drv->ops->del_station(&drv->wiphy, dev, mac_addr);
422 +       rtnl_unlock();
423 +
424 + out:
425 +       cfg80211_put_dev(drv);
426 +       dev_put(dev);
427 +       return err;
428 +}
429 +
430  static struct genl_ops nl80211_ops[] = {
431         {
432                 .cmd = NL80211_CMD_GET_WIPHY,
433 @@ -796,6 +1007,31 @@ static struct genl_ops nl80211_ops[] = {
434                 .flags = GENL_ADMIN_PERM,
435                 .doit = nl80211_del_beacon,
436         },
437 +       {
438 +               .cmd = NL80211_CMD_GET_STATION,
439 +               .doit = nl80211_get_station,
440 +               /* TODO: implement dumpit */
441 +               .policy = nl80211_policy,
442 +               .flags = GENL_ADMIN_PERM,
443 +       },
444 +       {
445 +               .cmd = NL80211_CMD_SET_STATION,
446 +               .doit = nl80211_set_station,
447 +               .policy = nl80211_policy,
448 +               .flags = GENL_ADMIN_PERM,
449 +       },
450 +       {
451 +               .cmd = NL80211_CMD_NEW_STATION,
452 +               .doit = nl80211_new_station,
453 +               .policy = nl80211_policy,
454 +               .flags = GENL_ADMIN_PERM,
455 +       },
456 +       {
457 +               .cmd = NL80211_CMD_DEL_STATION,
458 +               .doit = nl80211_del_station,
459 +               .policy = nl80211_policy,
460 +               .flags = GENL_ADMIN_PERM,
461 +       },
462  };
463  
464  /* multicast groups */