fix up hostapd for mac80211
[openwrt/openwrt.git] / package / hostapd / patches / 006-use-nl80211-for-sta.patch
1 ---
2 hostapd/driver_devicescape.c | 330 ++++++++++++++++++++++++++++++++-----------
3 1 file changed, 249 insertions(+), 81 deletions(-)
4
5 --- hostap.orig/hostapd/driver_devicescape.c 2007-11-09 13:41:15.000000000 +0100
6 +++ hostap/hostapd/driver_devicescape.c 2007-11-09 13:41:16.000000000 +0100
7 @@ -75,8 +75,14 @@ struct i802_driver_data {
8
9 #define HAPD_DECL struct hostapd_data *hapd = iface->bss[0]
10
11 -static int i802_sta_set_flags(void *priv, const u8 *addr,
12 - int total_flags, int flags_or, int flags_and);
13 +/* helper for netlink get routines */
14 +static int ack_wait_handler(struct nl_msg *msg, void *arg)
15 +{
16 + int *finished = arg;
17 +
18 + *finished = 1;
19 + return NL_STOP;
20 +}
21
22
23 static int hostapd_set_iface_flags(struct i802_driver_data *drv, int dev_up)
24 @@ -255,14 +261,6 @@ static int get_key_handler(struct nl_msg
25 return NL_SKIP;
26 }
27
28 -static int ack_wait_handler(struct nl_msg *msg, void *arg)
29 -{
30 - int *finished = arg;
31 -
32 - *finished = 1;
33 - return NL_STOP;
34 -}
35 -
36 static int i802_get_seqnum(const char *iface, void *priv, const u8 *addr,
37 int idx, u8 *seq)
38 {
39 @@ -629,43 +627,126 @@ static int i802_get_retry(void *priv, in
40 static int i802_flush(void *priv)
41 {
42 struct i802_driver_data *drv = priv;
43 - struct prism2_hostapd_param param;
44 + struct nl_msg *msg;
45 + int ret = -1;
46
47 - memset(&param, 0, sizeof(param));
48 - param.cmd = PRISM2_HOSTAPD_FLUSH;
49 - return hostapd_ioctl(drv, &param, sizeof(param));
50 + msg = nlmsg_alloc();
51 + if (!msg)
52 + goto out;
53 +
54 + genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
55 + 0, NL80211_CMD_NEW_STATION, 0);
56 +
57 + /*
58 + * XXX: FIX! this needs to flush all VLANs too
59 + */
60 + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
61 + if_nametoindex(drv->iface));
62 +
63 + ret = 0;
64 +
65 + if (nl_send_auto_complete(drv->nl_handle, msg) < 0 ||
66 + nl_wait_for_ack(drv->nl_handle) < 0) {
67 + ret = -1;
68 + }
69 +
70 + nla_put_failure:
71 + nlmsg_free(msg);
72 +
73 + out:
74 + return ret;
75 }
76
77
78 +static int get_sta_handler(struct nl_msg *msg, void *arg)
79 +{
80 + struct nlattr *tb[NL80211_ATTR_MAX + 1];
81 + struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
82 + struct hostap_sta_driver_data *data = arg;
83 + struct nlattr *stats[NL80211_STA_STAT_MAX + 1];
84 + static struct nla_policy stats_policy[NL80211_STA_STAT_MAX + 1] = {
85 + [NL80211_STA_STAT_INACTIVE_TIME] = { .type = NLA_U32 },
86 + [NL80211_STA_STAT_RX_BYTES] = { .type = NLA_U32 },
87 + [NL80211_STA_STAT_TX_BYTES] = { .type = NLA_U32 },
88 + };
89 +
90 + nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
91 + genlmsg_attrlen(gnlh, 0), NULL);
92 +
93 + /*
94 + * TODO: validate the interface and mac address!
95 + * Otherwise, there's a race condition as soon as
96 + * the kernel starts sending station notifications.
97 + */
98 +
99 + if (!tb[NL80211_ATTR_STA_STATS]) {
100 + printf("sta stats missing!\n");
101 + return NL_SKIP;
102 + }
103 + if (nla_parse_nested(stats, NL80211_STA_STAT_MAX,
104 + tb[NL80211_ATTR_STA_STATS],
105 + stats_policy)) {
106 + printf("failed to parse nested attributes!\n");
107 + return NL_SKIP;
108 + }
109 +
110 + if (stats[NL80211_STA_STAT_INACTIVE_TIME])
111 + data->inactive_msec =
112 + nla_get_u32(stats[NL80211_STA_STAT_INACTIVE_TIME]);
113 + if (stats[NL80211_STA_STAT_RX_BYTES])
114 + data->rx_bytes = nla_get_u32(stats[NL80211_STA_STAT_RX_BYTES]);
115 + if (stats[NL80211_STA_STAT_TX_BYTES])
116 + data->rx_bytes = nla_get_u32(stats[NL80211_STA_STAT_TX_BYTES]);
117 +
118 + return NL_SKIP;
119 +}
120 +
121 static int i802_read_sta_data(void *priv, struct hostap_sta_driver_data *data,
122 const u8 *addr)
123 {
124 struct i802_driver_data *drv = priv;
125 - struct prism2_hostapd_param param;
126 + struct nl_msg *msg;
127 + struct nl_cb *cb = NULL;
128 + int ret = -1;
129 + int err = 0;
130 + int finished = 0;
131
132 - memset(data, 0, sizeof(*data));
133 + msg = nlmsg_alloc();
134 + if (!msg)
135 + goto out;
136
137 - memset(&param, 0, sizeof(param));
138 - param.cmd = PRISM2_HOSTAPD_GET_INFO_STA;
139 - memcpy(param.sta_addr, addr, ETH_ALEN);
140 - if (hostapd_ioctl(drv, &param, sizeof(param))) {
141 - printf(" Could not get station info from kernel driver.\n");
142 - return -1;
143 - }
144 + genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
145 + 0, NL80211_CMD_GET_STATION, 0);
146 +
147 + NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
148 + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(drv->iface));
149 +
150 + cb = nl_cb_alloc(NL_CB_CUSTOM);
151 + if (!cb)
152 + goto out;
153 +
154 + if (nl_send_auto_complete(drv->nl_handle, msg) < 0)
155 + goto out;
156 +
157 + nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, get_sta_handler, data);
158 + nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_wait_handler, &finished);
159 +
160 + err = nl_recvmsgs(drv->nl_handle, cb);
161 +
162 + if (!finished)
163 + err = nl_wait_for_ack(drv->nl_handle);
164 +
165 + if (err < 0)
166 + goto out;
167 +
168 + ret = 0;
169 +
170 + out:
171 + nl_cb_put(cb);
172 + nla_put_failure:
173 + nlmsg_free(msg);
174 + return ret;
175
176 - data->inactive_msec = param.u.get_info_sta.inactive_msec;
177 - data->rx_packets = param.u.get_info_sta.rx_packets;
178 - data->tx_packets = param.u.get_info_sta.tx_packets;
179 - data->rx_bytes = param.u.get_info_sta.rx_bytes;
180 - data->tx_bytes = param.u.get_info_sta.tx_bytes;
181 - data->current_tx_rate = param.u.get_info_sta.current_tx_rate;
182 - data->flags = param.u.get_info_sta.flags;
183 - data->num_ps_buf_frames = param.u.get_info_sta.num_ps_buf_frames;
184 - data->tx_retry_failed = param.u.get_info_sta.tx_retry_failed;
185 - data->tx_retry_count = param.u.get_info_sta.tx_retry_count;
186 - data->last_rssi = param.u.get_info_sta.last_rssi;
187 - data->last_ack_rssi = param.u.get_info_sta.last_ack_rssi;
188 - return 0;
189 }
190
191
192 @@ -744,35 +825,68 @@ static int i802_sta_add(const char *ifna
193 size_t supp_rates_len, int flags)
194 {
195 struct i802_driver_data *drv = priv;
196 - struct prism2_hostapd_param param;
197 - size_t len;
198 + struct nl_msg *msg;
199 + int ret = -1;
200
201 - memset(&param, 0, sizeof(param));
202 - param.cmd = PRISM2_HOSTAPD_ADD_STA;
203 - memcpy(param.sta_addr, addr, ETH_ALEN);
204 - param.u.add_sta.aid = aid;
205 - param.u.add_sta.capability = capability;
206 - len = supp_rates_len;
207 - if (len > sizeof(param.u.add_sta.supp_rates))
208 - len = sizeof(param.u.add_sta.supp_rates);
209 - memcpy(param.u.add_sta.supp_rates, supp_rates, len);
210 - return hostapd_ioctl_iface(ifname, drv, &param, sizeof(param));
211 + msg = nlmsg_alloc();
212 + if (!msg)
213 + goto out;
214 +
215 + genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
216 + 0, NL80211_CMD_NEW_STATION, 0);
217 +
218 + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
219 + if_nametoindex(drv->iface));
220 + NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
221 + NLA_PUT_U16(msg, NL80211_ATTR_STA_AID, aid);
222 + NLA_PUT(msg, NL80211_ATTR_STA_SUPPORTED_RATES, supp_rates_len,
223 + supp_rates);
224 + NLA_PUT_U16(msg, NL80211_ATTR_STA_LISTEN_INTERVAL, 0);
225 +
226 + ret = 0;
227 +
228 + if (nl_send_auto_complete(drv->nl_handle, msg) < 0 ||
229 + nl_wait_for_ack(drv->nl_handle) < 0) {
230 + ret = -1;
231 + }
232 +
233 + nla_put_failure:
234 + nlmsg_free(msg);
235 +
236 + out:
237 + return ret;
238 }
239
240
241 static int i802_sta_remove(void *priv, const u8 *addr)
242 {
243 struct i802_driver_data *drv = priv;
244 - struct prism2_hostapd_param param;
245 + struct nl_msg *msg;
246 + int ret = -1;
247
248 - i802_sta_set_flags(drv, addr, 0, 0, ~WLAN_STA_AUTHORIZED);
249 + msg = nlmsg_alloc();
250 + if (!msg)
251 + goto out;
252
253 - memset(&param, 0, sizeof(param));
254 - param.cmd = PRISM2_HOSTAPD_REMOVE_STA;
255 - memcpy(param.sta_addr, addr, ETH_ALEN);
256 - if (hostapd_ioctl(drv, &param, sizeof(param)))
257 - return -1;
258 - return 0;
259 + genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
260 + 0, NL80211_CMD_DEL_STATION, 0);
261 +
262 + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
263 + if_nametoindex(drv->iface));
264 + NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
265 +
266 + ret = 0;
267 +
268 + if (nl_send_auto_complete(drv->nl_handle, msg) < 0 ||
269 + nl_wait_for_ack(drv->nl_handle) < 0) {
270 + ret = -1;
271 + }
272 +
273 + nla_put_failure:
274 + nlmsg_free(msg);
275 +
276 + out:
277 + return ret;
278 }
279
280
281 @@ -780,14 +894,51 @@ static int i802_sta_set_flags(void *priv
282 int total_flags, int flags_or, int flags_and)
283 {
284 struct i802_driver_data *drv = priv;
285 - struct prism2_hostapd_param param;
286 + struct nl_msg *msg, *flags = NULL;
287 + int ret = -1;
288
289 - memset(&param, 0, sizeof(param));
290 - param.cmd = PRISM2_HOSTAPD_SET_FLAGS_STA;
291 - memcpy(param.sta_addr, addr, ETH_ALEN);
292 - param.u.set_flags_sta.flags_or = flags_or;
293 - param.u.set_flags_sta.flags_and = flags_and;
294 - return hostapd_ioctl(drv, &param, sizeof(param));
295 + msg = nlmsg_alloc();
296 + if (!msg)
297 + goto out;
298 +
299 + flags = nlmsg_alloc();
300 + if (!flags)
301 + goto free_msg;
302 +
303 + genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
304 + 0, NL80211_CMD_SET_STATION, 0);
305 +
306 + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
307 + if_nametoindex(drv->iface));
308 + NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
309 +
310 + if (total_flags & WLAN_STA_AUTHORIZED)
311 + NLA_PUT_FLAG(flags, NL80211_STA_FLAG_AUTHORIZED);
312 +
313 + if (total_flags & WLAN_STA_WME)
314 + NLA_PUT_FLAG(flags, NL80211_STA_FLAG_WME);
315 +
316 + if (total_flags & WLAN_STA_SHORT_PREAMBLE)
317 + NLA_PUT_FLAG(flags, NL80211_STA_FLAG_SHORT_PREAMBLE);
318 +
319 + if (nla_put_nested(msg, NL80211_ATTR_STA_FLAGS, flags))
320 + goto nla_put_failure;
321 +
322 + ret = 0;
323 +
324 + if (nl_send_auto_complete(drv->nl_handle, msg) < 0 ||
325 + nl_wait_for_ack(drv->nl_handle) < 0) {
326 + ret = -1;
327 + }
328 +
329 + nla_put_failure:
330 + nlmsg_free(flags);
331 +
332 + free_msg:
333 + nlmsg_free(msg);
334 +
335 + out:
336 + return ret;
337 }
338
339
340 @@ -1257,18 +1408,38 @@ static struct hostapd_hw_modes * i802_ge
341 }
342
343
344 -static int i802_set_sta_vlan(void *priv, const u8 *addr, const char *ifname,
345 - int vlan_id)
346 +static int i802_set_sta_vlan(void *priv, const u8 *addr,
347 + const char *ifname, int vlan_id)
348 {
349 struct i802_driver_data *drv = priv;
350 - struct prism2_hostapd_param param;
351 + struct nl_msg *msg;
352 + int ret = -1;
353
354 - memset(&param, 0, sizeof(param));
355 - param.cmd = PRISM2_HOSTAPD_SET_STA_VLAN;
356 - memcpy(param.sta_addr, addr, ETH_ALEN);
357 - os_strlcpy(param.u.set_sta_vlan.vlan_name, ifname, IFNAMSIZ);
358 - param.u.set_sta_vlan.vlan_id = vlan_id;
359 - return hostapd_ioctl(drv, &param, sizeof(param));
360 + msg = nlmsg_alloc();
361 + if (!msg)
362 + goto out;
363 +
364 + genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
365 + 0, NL80211_CMD_SET_STATION, 0);
366 +
367 + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
368 + if_nametoindex(drv->iface));
369 + NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
370 + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
371 + if_nametoindex(ifname));
372 +
373 + ret = 0;
374 +
375 + if (nl_send_auto_complete(drv->nl_handle, msg) < 0 ||
376 + nl_wait_for_ack(drv->nl_handle) < 0) {
377 + ret = -1;
378 + }
379 +
380 + nla_put_failure:
381 + nlmsg_free(msg);
382 +
383 + out:
384 + return ret;
385 }
386
387
388 @@ -1750,17 +1921,14 @@ static int i802_init_sockets(struct i802
389
390 static int i802_get_inact_sec(void *priv, const u8 *addr)
391 {
392 - struct i802_driver_data *drv = priv;
393 - struct prism2_hostapd_param param;
394 + struct hostap_sta_driver_data data;
395 + int ret;
396
397 - memset(&param, 0, sizeof(param));
398 - param.cmd = PRISM2_HOSTAPD_GET_INFO_STA;
399 - memcpy(param.sta_addr, addr, ETH_ALEN);
400 - if (hostapd_ioctl(drv, &param, sizeof(param))) {
401 + data.inactive_msec = -1;
402 + ret = i802_read_sta_data(priv, &data, addr);
403 + if (ret || data.inactive_msec == -1)
404 return -1;
405 - }
406 -
407 - return param.u.get_info_sta.inactive_msec / 1000;
408 + return data.inactive_msec / 1000;
409 }
410
411