hostap_ap.c revision 1bcca3c463e4930cef9986b05165bb0b3eb46f63
1ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen/*
2ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * Intersil Prism2 driver with Host AP (software access point) support
3ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
485d32e7b0ea53a11d2a4018d8ad2605052778df7Jouni Malinen * <j@w1.fi>
585d32e7b0ea53a11d2a4018d8ad2605052778df7Jouni Malinen * Copyright (c) 2002-2005, Jouni Malinen <j@w1.fi>
6ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen *
7ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * This file is to be included into hostap.c when S/W AP functionality is
8ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * compiled.
9ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen *
10ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * AP:  FIX:
11ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * - if unicast Class 2 (assoc,reassoc,disassoc) frame received from
12ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen *   unauthenticated STA, send deauth. frame (8802.11: 5.5)
13ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * - if unicast Class 3 (data with to/from DS,deauth,pspoll) frame received
14ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen *   from authenticated, but unassoc STA, send disassoc frame (8802.11: 5.5)
15ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * - if unicast Class 3 received from unauthenticated STA, send deauth. frame
16ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen *   (8802.11: 5.5)
17ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen */
18ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
195fad5a2e1f34b333a801b749c4e143c2ac3e8a4fAdrian Bunk#include <linux/proc_fs.h>
205fad5a2e1f34b333a801b749c4e143c2ac3e8a4fAdrian Bunk#include <linux/delay.h>
215fad5a2e1f34b333a801b749c4e143c2ac3e8a4fAdrian Bunk#include <linux/random.h>
225fad5a2e1f34b333a801b749c4e143c2ac3e8a4fAdrian Bunk
235fad5a2e1f34b333a801b749c4e143c2ac3e8a4fAdrian Bunk#include "hostap_wlan.h"
245fad5a2e1f34b333a801b749c4e143c2ac3e8a4fAdrian Bunk#include "hostap.h"
255fad5a2e1f34b333a801b749c4e143c2ac3e8a4fAdrian Bunk#include "hostap_ap.h"
265fad5a2e1f34b333a801b749c4e143c2ac3e8a4fAdrian Bunk
27ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenstatic int other_ap_policy[MAX_PARM_DEVICES] = { AP_OTHER_AP_SKIP_ALL,
28ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen						 DEF_INTS };
29ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenmodule_param_array(other_ap_policy, int, NULL, 0444);
30ff1d2767d5a43c85f944e86a45284b721f66196cJouni MalinenMODULE_PARM_DESC(other_ap_policy, "Other AP beacon monitoring policy (0-3)");
31ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
32ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenstatic int ap_max_inactivity[MAX_PARM_DEVICES] = { AP_MAX_INACTIVITY_SEC,
33ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen						   DEF_INTS };
34ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenmodule_param_array(ap_max_inactivity, int, NULL, 0444);
35ff1d2767d5a43c85f944e86a45284b721f66196cJouni MalinenMODULE_PARM_DESC(ap_max_inactivity, "AP timeout (in seconds) for station "
36ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		 "inactivity");
37ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
38ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenstatic int ap_bridge_packets[MAX_PARM_DEVICES] = { 1, DEF_INTS };
39ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenmodule_param_array(ap_bridge_packets, int, NULL, 0444);
40ff1d2767d5a43c85f944e86a45284b721f66196cJouni MalinenMODULE_PARM_DESC(ap_bridge_packets, "Bridge packets directly between "
41ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		 "stations");
42ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
43ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenstatic int autom_ap_wds[MAX_PARM_DEVICES] = { 0, DEF_INTS };
44ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenmodule_param_array(autom_ap_wds, int, NULL, 0444);
45ff1d2767d5a43c85f944e86a45284b721f66196cJouni MalinenMODULE_PARM_DESC(autom_ap_wds, "Add WDS connections to other APs "
46ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		 "automatically");
47ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
48ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
49ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenstatic struct sta_info* ap_get_sta(struct ap_data *ap, u8 *sta);
50ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenstatic void hostap_event_expired_sta(struct net_device *dev,
51ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen				     struct sta_info *sta);
52c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howellsstatic void handle_add_proc_queue(struct work_struct *work);
53ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
54ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
55c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howellsstatic void handle_wds_oper_queue(struct work_struct *work);
56ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenstatic void prism2_send_mgmt(struct net_device *dev,
574339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen			     u16 type_subtype, char *body,
58ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			     int body_len, u8 *addr, u16 tx_cb_idx);
59ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
60ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
61ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
62ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#ifndef PRISM2_NO_PROCFS_DEBUG
63ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenstatic int ap_debug_proc_read(char *page, char **start, off_t off,
64ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			      int count, int *eof, void *data)
65ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{
66ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	char *p = page;
67ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	struct ap_data *ap = (struct ap_data *) data;
68ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
69ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (off != 0) {
70ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		*eof = 1;
71ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		return 0;
72ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
73ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
74ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	p += sprintf(p, "BridgedUnicastFrames=%u\n", ap->bridged_unicast);
75ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	p += sprintf(p, "BridgedMulticastFrames=%u\n", ap->bridged_multicast);
76ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	p += sprintf(p, "max_inactivity=%u\n", ap->max_inactivity / HZ);
77ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	p += sprintf(p, "bridge_packets=%u\n", ap->bridge_packets);
78ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	p += sprintf(p, "nullfunc_ack=%u\n", ap->nullfunc_ack);
79ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	p += sprintf(p, "autom_ap_wds=%u\n", ap->autom_ap_wds);
80ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	p += sprintf(p, "auth_algs=%u\n", ap->local->auth_algs);
81ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	p += sprintf(p, "tx_drop_nonassoc=%u\n", ap->tx_drop_nonassoc);
82ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
83ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	return (p - page);
84ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen}
85ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#endif /* PRISM2_NO_PROCFS_DEBUG */
86ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
87ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
88ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenstatic void ap_sta_hash_add(struct ap_data *ap, struct sta_info *sta)
89ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{
90ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	sta->hnext = ap->sta_hash[STA_HASH(sta->addr)];
91ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	ap->sta_hash[STA_HASH(sta->addr)] = sta;
92ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen}
93ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
94ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenstatic void ap_sta_hash_del(struct ap_data *ap, struct sta_info *sta)
95ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{
96ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	struct sta_info *s;
970795af5729b18218767fab27c44b1384f72dc9adJoe Perches	DECLARE_MAC_BUF(mac);
98ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
99ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	s = ap->sta_hash[STA_HASH(sta->addr)];
100ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (s == NULL) return;
101ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (memcmp(s->addr, sta->addr, ETH_ALEN) == 0) {
102ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		ap->sta_hash[STA_HASH(sta->addr)] = s->hnext;
103ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		return;
104ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
105ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
106ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	while (s->hnext != NULL && memcmp(s->hnext->addr, sta->addr, ETH_ALEN)
107ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	       != 0)
108ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		s = s->hnext;
109ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (s->hnext != NULL)
110ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		s->hnext = s->hnext->hnext;
111ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	else
1120795af5729b18218767fab27c44b1384f72dc9adJoe Perches		printk("AP: could not remove STA %s"
1130795af5729b18218767fab27c44b1384f72dc9adJoe Perches		       " from hash table\n",
1140795af5729b18218767fab27c44b1384f72dc9adJoe Perches		       print_mac(mac, sta->addr));
115ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen}
116ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
117ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenstatic void ap_free_sta(struct ap_data *ap, struct sta_info *sta)
118ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{
1190795af5729b18218767fab27c44b1384f72dc9adJoe Perches	DECLARE_MAC_BUF(mac);
120ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (sta->ap && sta->local)
121ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		hostap_event_expired_sta(sta->local->dev, sta);
122ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
123ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (ap->proc != NULL) {
124ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		char name[20];
1250795af5729b18218767fab27c44b1384f72dc9adJoe Perches		sprintf(name, "%s", print_mac(mac, sta->addr));
126ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		remove_proc_entry(name, ap->proc);
127ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
128ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
129ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (sta->crypt) {
130ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		sta->crypt->ops->deinit(sta->crypt->priv);
131ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		kfree(sta->crypt);
132ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		sta->crypt = NULL;
133ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
134ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
135ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	skb_queue_purge(&sta->tx_buf);
136ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
137ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	ap->num_sta--;
138ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
139ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (sta->aid > 0)
140ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		ap->sta_aid[sta->aid - 1] = NULL;
141ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
142ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (!sta->ap && sta->u.sta.challenge)
143ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		kfree(sta->u.sta.challenge);
144ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	del_timer(&sta->timer);
145ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
146ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
147ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	kfree(sta);
148ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen}
149ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
150ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
151ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenstatic void hostap_set_tim(local_info_t *local, int aid, int set)
152ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{
153ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (local->func->set_tim)
154ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		local->func->set_tim(local->dev, aid, set);
155ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen}
156ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
157ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
158ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenstatic void hostap_event_new_sta(struct net_device *dev, struct sta_info *sta)
159ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{
160ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	union iwreq_data wrqu;
161ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	memset(&wrqu, 0, sizeof(wrqu));
162ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	memcpy(wrqu.addr.sa_data, sta->addr, ETH_ALEN);
163ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	wrqu.addr.sa_family = ARPHRD_ETHER;
164ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	wireless_send_event(dev, IWEVREGISTERED, &wrqu, NULL);
165ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen}
166ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
167ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
168ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenstatic void hostap_event_expired_sta(struct net_device *dev,
169ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen				     struct sta_info *sta)
170ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{
171ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	union iwreq_data wrqu;
172ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	memset(&wrqu, 0, sizeof(wrqu));
173ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	memcpy(wrqu.addr.sa_data, sta->addr, ETH_ALEN);
174ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	wrqu.addr.sa_family = ARPHRD_ETHER;
175ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	wireless_send_event(dev, IWEVEXPIRED, &wrqu, NULL);
176ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen}
177ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
178ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
179ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
180ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
181ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenstatic void ap_handle_timer(unsigned long data)
182ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{
183ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	struct sta_info *sta = (struct sta_info *) data;
184ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	local_info_t *local;
185ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	struct ap_data *ap;
186ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	unsigned long next_time = 0;
187ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	int was_assoc;
1880795af5729b18218767fab27c44b1384f72dc9adJoe Perches	DECLARE_MAC_BUF(mac);
189ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
190ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (sta == NULL || sta->local == NULL || sta->local->ap == NULL) {
191ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		PDEBUG(DEBUG_AP, "ap_handle_timer() called with NULL data\n");
192ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		return;
193ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
194ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
195ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	local = sta->local;
196ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	ap = local->ap;
197ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	was_assoc = sta->flags & WLAN_STA_ASSOC;
198ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
199ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (atomic_read(&sta->users) != 0)
200ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		next_time = jiffies + HZ;
201ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	else if ((sta->flags & WLAN_STA_PERM) && !(sta->flags & WLAN_STA_AUTH))
202ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		next_time = jiffies + ap->max_inactivity;
203ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
204ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (time_before(jiffies, sta->last_rx + ap->max_inactivity)) {
205ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		/* station activity detected; reset timeout state */
206ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		sta->timeout_next = STA_NULLFUNC;
207ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		next_time = sta->last_rx + ap->max_inactivity;
208ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	} else if (sta->timeout_next == STA_DISASSOC &&
209ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		   !(sta->flags & WLAN_STA_PENDING_POLL)) {
210ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		/* STA ACKed data nullfunc frame poll */
211ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		sta->timeout_next = STA_NULLFUNC;
212ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		next_time = jiffies + ap->max_inactivity;
213ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
214ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
215ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (next_time) {
216ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		sta->timer.expires = next_time;
217ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		add_timer(&sta->timer);
218ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		return;
219ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
220ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
221ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (sta->ap)
222ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		sta->timeout_next = STA_DEAUTH;
223ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
224ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (sta->timeout_next == STA_DEAUTH && !(sta->flags & WLAN_STA_PERM)) {
225ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		spin_lock(&ap->sta_table_lock);
226ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		ap_sta_hash_del(ap, sta);
227ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		list_del(&sta->list);
228ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		spin_unlock(&ap->sta_table_lock);
229ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
230ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	} else if (sta->timeout_next == STA_DISASSOC)
231ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		sta->flags &= ~WLAN_STA_ASSOC;
232ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
233ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (was_assoc && !(sta->flags & WLAN_STA_ASSOC) && !sta->ap)
234ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		hostap_event_expired_sta(local->dev, sta);
235ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
236ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (sta->timeout_next == STA_DEAUTH && sta->aid > 0 &&
237ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	    !skb_queue_empty(&sta->tx_buf)) {
238ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		hostap_set_tim(local, sta->aid, 0);
239ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		sta->flags &= ~WLAN_STA_TIM;
240ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
241ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
242ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (sta->ap) {
243ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		if (ap->autom_ap_wds) {
244ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			PDEBUG(DEBUG_AP, "%s: removing automatic WDS "
2450795af5729b18218767fab27c44b1384f72dc9adJoe Perches			       "connection to AP %s\n",
2460795af5729b18218767fab27c44b1384f72dc9adJoe Perches			       local->dev->name, print_mac(mac, sta->addr));
247ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			hostap_wds_link_oper(local, sta->addr, WDS_DEL);
248ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		}
249ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	} else if (sta->timeout_next == STA_NULLFUNC) {
250ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		/* send data frame to poll STA and check whether this frame
251ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		 * is ACKed */
2524339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen		/* FIX: IEEE80211_STYPE_NULLFUNC would be more appropriate, but
253ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		 * it is apparently not retried so TX Exc events are not
254ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		 * received for it */
255ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		sta->flags |= WLAN_STA_PENDING_POLL;
2564339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen		prism2_send_mgmt(local->dev, IEEE80211_FTYPE_DATA |
2574339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen				 IEEE80211_STYPE_DATA, NULL, 0,
258ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen				 sta->addr, ap->tx_callback_poll);
259ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	} else {
260ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		int deauth = sta->timeout_next == STA_DEAUTH;
2618a9faf3cd08b91aca1502dbe18e3b5063fda2e87Al Viro		__le16 resp;
2620795af5729b18218767fab27c44b1384f72dc9adJoe Perches		PDEBUG(DEBUG_AP, "%s: sending %s info to STA %s"
263ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		       "(last=%lu, jiffies=%lu)\n",
264ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		       local->dev->name,
265ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		       deauth ? "deauthentication" : "disassociation",
2660795af5729b18218767fab27c44b1384f72dc9adJoe Perches		       print_mac(mac, sta->addr), sta->last_rx, jiffies);
267ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
268ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		resp = cpu_to_le16(deauth ? WLAN_REASON_PREV_AUTH_NOT_VALID :
269ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen				   WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY);
2704339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen		prism2_send_mgmt(local->dev, IEEE80211_FTYPE_MGMT |
2714339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen				 (deauth ? IEEE80211_STYPE_DEAUTH :
2724339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen				  IEEE80211_STYPE_DISASSOC),
273ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen				 (char *) &resp, 2, sta->addr, 0);
274ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
275ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
276ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (sta->timeout_next == STA_DEAUTH) {
277ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		if (sta->flags & WLAN_STA_PERM) {
2780795af5729b18218767fab27c44b1384f72dc9adJoe Perches			PDEBUG(DEBUG_AP, "%s: STA %s"
2790795af5729b18218767fab27c44b1384f72dc9adJoe Perches			       " would have been removed, "
2800795af5729b18218767fab27c44b1384f72dc9adJoe Perches			       "but it has 'perm' flag\n",
2810795af5729b18218767fab27c44b1384f72dc9adJoe Perches			       local->dev->name, print_mac(mac, sta->addr));
282ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		} else
283ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			ap_free_sta(ap, sta);
284ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		return;
285ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
286ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
287ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (sta->timeout_next == STA_NULLFUNC) {
288ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		sta->timeout_next = STA_DISASSOC;
289ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		sta->timer.expires = jiffies + AP_DISASSOC_DELAY;
290ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	} else {
291ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		sta->timeout_next = STA_DEAUTH;
292ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		sta->timer.expires = jiffies + AP_DEAUTH_DELAY;
293ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
294ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
295ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	add_timer(&sta->timer);
296ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen}
297ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
298ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
299ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenvoid hostap_deauth_all_stas(struct net_device *dev, struct ap_data *ap,
300ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			    int resend)
301ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{
302ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	u8 addr[ETH_ALEN];
3038a9faf3cd08b91aca1502dbe18e3b5063fda2e87Al Viro	__le16 resp;
304ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	int i;
305ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
306ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	PDEBUG(DEBUG_AP, "%s: Deauthenticate all stations\n", dev->name);
307ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	memset(addr, 0xff, ETH_ALEN);
308ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
3098a9faf3cd08b91aca1502dbe18e3b5063fda2e87Al Viro	resp = cpu_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
310ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
311ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	/* deauth message sent; try to resend it few times; the message is
312ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	 * broadcast, so it may be delayed until next DTIM; there is not much
313ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	 * else we can do at this point since the driver is going to be shut
314ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	 * down */
315ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	for (i = 0; i < 5; i++) {
3164339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen		prism2_send_mgmt(dev, IEEE80211_FTYPE_MGMT |
3174339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen				 IEEE80211_STYPE_DEAUTH,
318ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen				 (char *) &resp, 2, addr, 0);
319ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
320ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		if (!resend || ap->num_sta <= 0)
321ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			return;
322ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
323ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		mdelay(50);
324ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
325ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen}
326ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
327ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
328ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenstatic int ap_control_proc_read(char *page, char **start, off_t off,
329ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen				int count, int *eof, void *data)
330ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{
331ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	char *p = page;
332ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	struct ap_data *ap = (struct ap_data *) data;
333ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	char *policy_txt;
334ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	struct mac_entry *entry;
3350795af5729b18218767fab27c44b1384f72dc9adJoe Perches	DECLARE_MAC_BUF(mac);
336ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
337ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (off != 0) {
338ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		*eof = 1;
339ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		return 0;
340ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
341ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
342ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	switch (ap->mac_restrictions.policy) {
343ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	case MAC_POLICY_OPEN:
344ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		policy_txt = "open";
345ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		break;
346ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	case MAC_POLICY_ALLOW:
347ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		policy_txt = "allow";
348ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		break;
349ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	case MAC_POLICY_DENY:
350ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		policy_txt = "deny";
351ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		break;
352ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	default:
353ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		policy_txt = "unknown";
354ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		break;
355ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	};
356ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	p += sprintf(p, "MAC policy: %s\n", policy_txt);
357ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	p += sprintf(p, "MAC entries: %u\n", ap->mac_restrictions.entries);
358ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	p += sprintf(p, "MAC list:\n");
359ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	spin_lock_bh(&ap->mac_restrictions.lock);
360c15057313725942c6af8dcb60b4d4322101316d9Matthias Kaehlcke	list_for_each_entry(entry, &ap->mac_restrictions.mac_list, list) {
361ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		if (p - page > PAGE_SIZE - 80) {
362ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			p += sprintf(p, "All entries did not fit one page.\n");
363ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			break;
364ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		}
365ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
3660795af5729b18218767fab27c44b1384f72dc9adJoe Perches		p += sprintf(p, "%s\n", print_mac(mac, entry->addr));
367ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
368ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	spin_unlock_bh(&ap->mac_restrictions.lock);
369ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
370ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	return (p - page);
371ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen}
372ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
373ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
3745fad5a2e1f34b333a801b749c4e143c2ac3e8a4fAdrian Bunkint ap_control_add_mac(struct mac_restrictions *mac_restrictions, u8 *mac)
375ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{
376ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	struct mac_entry *entry;
377ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
378ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	entry = kmalloc(sizeof(struct mac_entry), GFP_KERNEL);
379ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (entry == NULL)
380ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		return -1;
381ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
382ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	memcpy(entry->addr, mac, ETH_ALEN);
383ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
384ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	spin_lock_bh(&mac_restrictions->lock);
385ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	list_add_tail(&entry->list, &mac_restrictions->mac_list);
386ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	mac_restrictions->entries++;
387ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	spin_unlock_bh(&mac_restrictions->lock);
388ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
389ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	return 0;
390ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen}
391ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
392ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
3935fad5a2e1f34b333a801b749c4e143c2ac3e8a4fAdrian Bunkint ap_control_del_mac(struct mac_restrictions *mac_restrictions, u8 *mac)
394ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{
395ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	struct list_head *ptr;
396ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	struct mac_entry *entry;
397ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
398ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	spin_lock_bh(&mac_restrictions->lock);
399ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	for (ptr = mac_restrictions->mac_list.next;
400ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	     ptr != &mac_restrictions->mac_list; ptr = ptr->next) {
401ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		entry = list_entry(ptr, struct mac_entry, list);
402ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
403ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		if (memcmp(entry->addr, mac, ETH_ALEN) == 0) {
404ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			list_del(ptr);
405ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			kfree(entry);
406ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			mac_restrictions->entries--;
407ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			spin_unlock_bh(&mac_restrictions->lock);
408ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			return 0;
409ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		}
410ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
411ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	spin_unlock_bh(&mac_restrictions->lock);
412ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	return -1;
413ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen}
414ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
415ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
416ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenstatic int ap_control_mac_deny(struct mac_restrictions *mac_restrictions,
417ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			       u8 *mac)
418ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{
419ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	struct mac_entry *entry;
420ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	int found = 0;
421ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
422ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (mac_restrictions->policy == MAC_POLICY_OPEN)
423ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		return 0;
424ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
425ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	spin_lock_bh(&mac_restrictions->lock);
426c15057313725942c6af8dcb60b4d4322101316d9Matthias Kaehlcke	list_for_each_entry(entry, &mac_restrictions->mac_list, list) {
427ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		if (memcmp(entry->addr, mac, ETH_ALEN) == 0) {
428ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			found = 1;
429ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			break;
430ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		}
431ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
432ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	spin_unlock_bh(&mac_restrictions->lock);
433ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
434ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (mac_restrictions->policy == MAC_POLICY_ALLOW)
435ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		return !found;
436ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	else
437ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		return found;
438ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen}
439ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
440ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
4415fad5a2e1f34b333a801b749c4e143c2ac3e8a4fAdrian Bunkvoid ap_control_flush_macs(struct mac_restrictions *mac_restrictions)
442ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{
443ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	struct list_head *ptr, *n;
444ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	struct mac_entry *entry;
445ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
446ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (mac_restrictions->entries == 0)
447ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		return;
448ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
449ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	spin_lock_bh(&mac_restrictions->lock);
450ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	for (ptr = mac_restrictions->mac_list.next, n = ptr->next;
451ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	     ptr != &mac_restrictions->mac_list;
452ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	     ptr = n, n = ptr->next) {
453ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		entry = list_entry(ptr, struct mac_entry, list);
454ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		list_del(ptr);
455ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		kfree(entry);
456ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
457ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	mac_restrictions->entries = 0;
458ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	spin_unlock_bh(&mac_restrictions->lock);
459ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen}
460ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
461ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
4625fad5a2e1f34b333a801b749c4e143c2ac3e8a4fAdrian Bunkint ap_control_kick_mac(struct ap_data *ap, struct net_device *dev, u8 *mac)
463ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{
464ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	struct sta_info *sta;
4658a9faf3cd08b91aca1502dbe18e3b5063fda2e87Al Viro	__le16 resp;
466ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
467ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	spin_lock_bh(&ap->sta_table_lock);
468ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	sta = ap_get_sta(ap, mac);
469ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (sta) {
470ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		ap_sta_hash_del(ap, sta);
471ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		list_del(&sta->list);
472ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
473ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	spin_unlock_bh(&ap->sta_table_lock);
474ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
475ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (!sta)
476ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		return -EINVAL;
477ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
478ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	resp = cpu_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
4794339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen	prism2_send_mgmt(dev, IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_DEAUTH,
480ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			 (char *) &resp, 2, sta->addr, 0);
481ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
482ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap)
483ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		hostap_event_expired_sta(dev, sta);
484ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
485ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	ap_free_sta(ap, sta);
486ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
487ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	return 0;
488ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen}
489ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
490ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
491ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
492ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
4935fad5a2e1f34b333a801b749c4e143c2ac3e8a4fAdrian Bunkvoid ap_control_kickall(struct ap_data *ap)
494ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{
495ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	struct list_head *ptr, *n;
496ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	struct sta_info *sta;
49774fae82c8bd5dd78365abe25506a9ba388d4a889Jeff Garzik
498ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	spin_lock_bh(&ap->sta_table_lock);
499ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	for (ptr = ap->sta_list.next, n = ptr->next; ptr != &ap->sta_list;
500ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	     ptr = n, n = ptr->next) {
501ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		sta = list_entry(ptr, struct sta_info, list);
502ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		ap_sta_hash_del(ap, sta);
503ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		list_del(&sta->list);
504ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap && sta->local)
505ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			hostap_event_expired_sta(sta->local->dev, sta);
506ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		ap_free_sta(ap, sta);
507ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
508ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	spin_unlock_bh(&ap->sta_table_lock);
509ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen}
510ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
511ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
512ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
513ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
514ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#define PROC_LIMIT (PAGE_SIZE - 80)
515ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
516ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenstatic int prism2_ap_proc_read(char *page, char **start, off_t off,
517ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			       int count, int *eof, void *data)
518ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{
519ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	char *p = page;
520ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	struct ap_data *ap = (struct ap_data *) data;
521c15057313725942c6af8dcb60b4d4322101316d9Matthias Kaehlcke	struct sta_info *sta;
522ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	int i;
5230795af5729b18218767fab27c44b1384f72dc9adJoe Perches	DECLARE_MAC_BUF(mac);
524ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
525ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (off > PROC_LIMIT) {
526ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		*eof = 1;
527ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		return 0;
528ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
529ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
530ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	p += sprintf(p, "# BSSID CHAN SIGNAL NOISE RATE SSID FLAGS\n");
531ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	spin_lock_bh(&ap->sta_table_lock);
532c15057313725942c6af8dcb60b4d4322101316d9Matthias Kaehlcke	list_for_each_entry(sta, &ap->sta_list, list) {
533ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		if (!sta->ap)
534ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			continue;
535ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
5360795af5729b18218767fab27c44b1384f72dc9adJoe Perches		p += sprintf(p, "%s %d %d %d %d '",
5370795af5729b18218767fab27c44b1384f72dc9adJoe Perches			     print_mac(mac, sta->addr),
538ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			     sta->u.ap.channel, sta->last_rx_signal,
539ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			     sta->last_rx_silence, sta->last_rx_rate);
540ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		for (i = 0; i < sta->u.ap.ssid_len; i++)
541ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			p += sprintf(p, ((sta->u.ap.ssid[i] >= 32 &&
542ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen					  sta->u.ap.ssid[i] < 127) ?
543ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen					 "%c" : "<%02x>"),
544ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen				     sta->u.ap.ssid[i]);
545ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		p += sprintf(p, "'");
546ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		if (sta->capability & WLAN_CAPABILITY_ESS)
547ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			p += sprintf(p, " [ESS]");
548ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		if (sta->capability & WLAN_CAPABILITY_IBSS)
549ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			p += sprintf(p, " [IBSS]");
550ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		if (sta->capability & WLAN_CAPABILITY_PRIVACY)
551ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			p += sprintf(p, " [WEP]");
552ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		p += sprintf(p, "\n");
553ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
554ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		if ((p - page) > PROC_LIMIT) {
555ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			printk(KERN_DEBUG "hostap: ap proc did not fit\n");
556ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			break;
557ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		}
558ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
559ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	spin_unlock_bh(&ap->sta_table_lock);
560ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
561ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if ((p - page) <= off) {
562ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		*eof = 1;
563ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		return 0;
564ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
565ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
566ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	*start = page + off;
567ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
568ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	return (p - page - off);
569ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen}
570ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
571ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
572ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
573ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenvoid hostap_check_sta_fw_version(struct ap_data *ap, int sta_fw_ver)
574ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{
575ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (!ap)
576ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		return;
577ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
578ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (sta_fw_ver == PRISM2_FW_VER(0,8,0)) {
579ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		PDEBUG(DEBUG_AP, "Using data::nullfunc ACK workaround - "
580ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		       "firmware upgrade recommended\n");
581ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		ap->nullfunc_ack = 1;
582ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	} else
583ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		ap->nullfunc_ack = 0;
584ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
585ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (sta_fw_ver == PRISM2_FW_VER(1,4,2)) {
586ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		printk(KERN_WARNING "%s: Warning: secondary station firmware "
587ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		       "version 1.4.2 does not seem to work in Host AP mode\n",
588ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		       ap->local->dev->name);
589ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
590ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen}
591ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
592ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
593ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen/* Called only as a tasklet (software IRQ) */
594ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenstatic void hostap_ap_tx_cb(struct sk_buff *skb, int ok, void *data)
595ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{
596ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	struct ap_data *ap = data;
597ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	u16 fc;
598d041674d62e1ad565f2fb6d53ae80b31d6656033James Ketrenos	struct ieee80211_hdr_4addr *hdr;
599ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
600ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (!ap->local->hostapd || !ap->local->apdev) {
601ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		dev_kfree_skb(skb);
602ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		return;
603ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
604ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
605d041674d62e1ad565f2fb6d53ae80b31d6656033James Ketrenos	hdr = (struct ieee80211_hdr_4addr *) skb->data;
606c0f72ca8e4f1b459b5582c1c8dcaf7e53151f069Jouni Malinen	fc = le16_to_cpu(hdr->frame_ctl);
607ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
608ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	/* Pass the TX callback frame to the hostapd; use 802.11 header version
609ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	 * 1 to indicate failure (no ACK) and 2 success (frame ACKed) */
610ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
611b2f4a2e3b1620667da9654f9e220c92ea52bdbe4Jouni Malinen	fc &= ~IEEE80211_FCTL_VERS;
612ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	fc |= ok ? BIT(1) : BIT(0);
613c0f72ca8e4f1b459b5582c1c8dcaf7e53151f069Jouni Malinen	hdr->frame_ctl = cpu_to_le16(fc);
614ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
615ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	skb->dev = ap->local->apdev;
616ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	skb_pull(skb, hostap_80211_get_hdrlen(fc));
617ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	skb->pkt_type = PACKET_OTHERHOST;
618ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	skb->protocol = __constant_htons(ETH_P_802_2);
619ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	memset(skb->cb, 0, sizeof(skb->cb));
620ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	netif_rx(skb);
621ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen}
622ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
623ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
624ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
625ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen/* Called only as a tasklet (software IRQ) */
626ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenstatic void hostap_ap_tx_cb_auth(struct sk_buff *skb, int ok, void *data)
627ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{
628ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	struct ap_data *ap = data;
629ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	struct net_device *dev = ap->local->dev;
630d041674d62e1ad565f2fb6d53ae80b31d6656033James Ketrenos	struct ieee80211_hdr_4addr *hdr;
6318a9faf3cd08b91aca1502dbe18e3b5063fda2e87Al Viro	u16 fc, auth_alg, auth_transaction, status;
6328a9faf3cd08b91aca1502dbe18e3b5063fda2e87Al Viro	__le16 *pos;
633ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	struct sta_info *sta = NULL;
634ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	char *txt = NULL;
635ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
636ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (ap->local->hostapd) {
637ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		dev_kfree_skb(skb);
638ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		return;
639ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
640ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
641d041674d62e1ad565f2fb6d53ae80b31d6656033James Ketrenos	hdr = (struct ieee80211_hdr_4addr *) skb->data;
642c0f72ca8e4f1b459b5582c1c8dcaf7e53151f069Jouni Malinen	fc = le16_to_cpu(hdr->frame_ctl);
6434339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen	if (WLAN_FC_GET_TYPE(fc) != IEEE80211_FTYPE_MGMT ||
6444339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen	    WLAN_FC_GET_STYPE(fc) != IEEE80211_STYPE_AUTH ||
645ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	    skb->len < IEEE80211_MGMT_HDR_LEN + 6) {
646ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		printk(KERN_DEBUG "%s: hostap_ap_tx_cb_auth received invalid "
647ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		       "frame\n", dev->name);
648ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		dev_kfree_skb(skb);
649ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		return;
650ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
651ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
6528a9faf3cd08b91aca1502dbe18e3b5063fda2e87Al Viro	pos = (__le16 *) (skb->data + IEEE80211_MGMT_HDR_LEN);
653ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	auth_alg = le16_to_cpu(*pos++);
654ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	auth_transaction = le16_to_cpu(*pos++);
655ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	status = le16_to_cpu(*pos++);
656ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
657ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (!ok) {
658ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		txt = "frame was not ACKed";
659ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		goto done;
660ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
661ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
662ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	spin_lock(&ap->sta_table_lock);
663ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	sta = ap_get_sta(ap, hdr->addr1);
664ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (sta)
665ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		atomic_inc(&sta->users);
666ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	spin_unlock(&ap->sta_table_lock);
667ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
668ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (!sta) {
669ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		txt = "STA not found";
670ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		goto done;
671ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
672ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
673ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (status == WLAN_STATUS_SUCCESS &&
674ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	    ((auth_alg == WLAN_AUTH_OPEN && auth_transaction == 2) ||
675ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	     (auth_alg == WLAN_AUTH_SHARED_KEY && auth_transaction == 4))) {
676ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		txt = "STA authenticated";
677ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		sta->flags |= WLAN_STA_AUTH;
678ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		sta->last_auth = jiffies;
679ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	} else if (status != WLAN_STATUS_SUCCESS)
680ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		txt = "authentication failed";
681ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
682ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen done:
683ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (sta)
684ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		atomic_dec(&sta->users);
685ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (txt) {
68621f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller		PDEBUG(DEBUG_AP, "%s: " MAC_FMT " auth_cb - alg=%d "
6870795af5729b18218767fab27c44b1384f72dc9adJoe Perches		       "trans#=%d status=%d - %s\n",
68821f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller		       dev->name,
68921f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller		       hdr->addr1[0], hdr->addr1[1], hdr->addr1[2],
69021f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller		       hdr->addr1[3], hdr->addr1[4], hdr->addr1[5],
69121f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller		       auth_alg, auth_transaction, status, txt);
692ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
693ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	dev_kfree_skb(skb);
694ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen}
695ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
696ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
697ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen/* Called only as a tasklet (software IRQ) */
698ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenstatic void hostap_ap_tx_cb_assoc(struct sk_buff *skb, int ok, void *data)
699ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{
700ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	struct ap_data *ap = data;
701ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	struct net_device *dev = ap->local->dev;
702d041674d62e1ad565f2fb6d53ae80b31d6656033James Ketrenos	struct ieee80211_hdr_4addr *hdr;
7038a9faf3cd08b91aca1502dbe18e3b5063fda2e87Al Viro	u16 fc, status;
7048a9faf3cd08b91aca1502dbe18e3b5063fda2e87Al Viro	__le16 *pos;
705ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	struct sta_info *sta = NULL;
706ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	char *txt = NULL;
707ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
708ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (ap->local->hostapd) {
709ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		dev_kfree_skb(skb);
710ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		return;
711ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
712ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
713d041674d62e1ad565f2fb6d53ae80b31d6656033James Ketrenos	hdr = (struct ieee80211_hdr_4addr *) skb->data;
714c0f72ca8e4f1b459b5582c1c8dcaf7e53151f069Jouni Malinen	fc = le16_to_cpu(hdr->frame_ctl);
7154339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen	if (WLAN_FC_GET_TYPE(fc) != IEEE80211_FTYPE_MGMT ||
7164339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen	    (WLAN_FC_GET_STYPE(fc) != IEEE80211_STYPE_ASSOC_RESP &&
7174339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen	     WLAN_FC_GET_STYPE(fc) != IEEE80211_STYPE_REASSOC_RESP) ||
718ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	    skb->len < IEEE80211_MGMT_HDR_LEN + 4) {
719ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		printk(KERN_DEBUG "%s: hostap_ap_tx_cb_assoc received invalid "
720ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		       "frame\n", dev->name);
721ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		dev_kfree_skb(skb);
722ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		return;
723ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
724ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
725ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (!ok) {
726ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		txt = "frame was not ACKed";
727ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		goto done;
728ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
729ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
730ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	spin_lock(&ap->sta_table_lock);
731ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	sta = ap_get_sta(ap, hdr->addr1);
732ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (sta)
733ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		atomic_inc(&sta->users);
734ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	spin_unlock(&ap->sta_table_lock);
735ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
736ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (!sta) {
737ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		txt = "STA not found";
738ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		goto done;
739ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
740ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
7418a9faf3cd08b91aca1502dbe18e3b5063fda2e87Al Viro	pos = (__le16 *) (skb->data + IEEE80211_MGMT_HDR_LEN);
742ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	pos++;
743ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	status = le16_to_cpu(*pos++);
744ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (status == WLAN_STATUS_SUCCESS) {
745ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		if (!(sta->flags & WLAN_STA_ASSOC))
746ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			hostap_event_new_sta(dev, sta);
747ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		txt = "STA associated";
748ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		sta->flags |= WLAN_STA_ASSOC;
749ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		sta->last_assoc = jiffies;
750ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	} else
751ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		txt = "association failed";
752ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
753ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen done:
754ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (sta)
755ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		atomic_dec(&sta->users);
756ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (txt) {
75721f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller		PDEBUG(DEBUG_AP, "%s: " MAC_FMT " assoc_cb - %s\n",
75821f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller		       dev->name,
75921f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller		       hdr->addr1[0], hdr->addr1[1], hdr->addr1[2],
76021f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller		       hdr->addr1[3], hdr->addr1[4], hdr->addr1[5],
76121f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller		       txt);
762ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
763ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	dev_kfree_skb(skb);
764ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen}
765ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
766ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen/* Called only as a tasklet (software IRQ); TX callback for poll frames used
767ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * in verifying whether the STA is still present. */
768ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenstatic void hostap_ap_tx_cb_poll(struct sk_buff *skb, int ok, void *data)
769ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{
770ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	struct ap_data *ap = data;
771d041674d62e1ad565f2fb6d53ae80b31d6656033James Ketrenos	struct ieee80211_hdr_4addr *hdr;
772ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	struct sta_info *sta;
773ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
774ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (skb->len < 24)
775ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		goto fail;
776d041674d62e1ad565f2fb6d53ae80b31d6656033James Ketrenos	hdr = (struct ieee80211_hdr_4addr *) skb->data;
777ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (ok) {
778ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		spin_lock(&ap->sta_table_lock);
779ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		sta = ap_get_sta(ap, hdr->addr1);
780ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		if (sta)
781ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			sta->flags &= ~WLAN_STA_PENDING_POLL;
782ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		spin_unlock(&ap->sta_table_lock);
783ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	} else {
78421f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller		PDEBUG(DEBUG_AP, "%s: STA " MAC_FMT
7850795af5729b18218767fab27c44b1384f72dc9adJoe Perches		       " did not ACK activity poll frame\n",
78621f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller		       ap->local->dev->name,
78721f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller		       hdr->addr1[0], hdr->addr1[1], hdr->addr1[2],
78821f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller		       hdr->addr1[3], hdr->addr1[4], hdr->addr1[5]);
789ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
790ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
791ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen fail:
792ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	dev_kfree_skb(skb);
793ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen}
794ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
795ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
796ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
797ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenvoid hostap_init_data(local_info_t *local)
798ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{
799ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	struct ap_data *ap = local->ap;
800ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
801ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (ap == NULL) {
802ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		printk(KERN_WARNING "hostap_init_data: ap == NULL\n");
803ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		return;
804ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
805ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	memset(ap, 0, sizeof(struct ap_data));
806ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	ap->local = local;
807ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
808ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	ap->ap_policy = GET_INT_PARM(other_ap_policy, local->card_idx);
809ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	ap->bridge_packets = GET_INT_PARM(ap_bridge_packets, local->card_idx);
810ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	ap->max_inactivity =
811ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		GET_INT_PARM(ap_max_inactivity, local->card_idx) * HZ;
812ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	ap->autom_ap_wds = GET_INT_PARM(autom_ap_wds, local->card_idx);
813ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
814ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	spin_lock_init(&ap->sta_table_lock);
815ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	INIT_LIST_HEAD(&ap->sta_list);
816ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
817ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	/* Initialize task queue structure for AP management */
818c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howells	INIT_WORK(&local->ap->add_sta_proc_queue, handle_add_proc_queue);
819ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
820ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	ap->tx_callback_idx =
821ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		hostap_tx_callback_register(local, hostap_ap_tx_cb, ap);
822ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (ap->tx_callback_idx == 0)
823ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		printk(KERN_WARNING "%s: failed to register TX callback for "
824ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		       "AP\n", local->dev->name);
825ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
826c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howells	INIT_WORK(&local->ap->wds_oper_queue, handle_wds_oper_queue);
827ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
828ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	ap->tx_callback_auth =
829ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		hostap_tx_callback_register(local, hostap_ap_tx_cb_auth, ap);
830ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	ap->tx_callback_assoc =
831ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		hostap_tx_callback_register(local, hostap_ap_tx_cb_assoc, ap);
832ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	ap->tx_callback_poll =
833ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		hostap_tx_callback_register(local, hostap_ap_tx_cb_poll, ap);
834ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (ap->tx_callback_auth == 0 || ap->tx_callback_assoc == 0 ||
835ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		ap->tx_callback_poll == 0)
836ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		printk(KERN_WARNING "%s: failed to register TX callback for "
837ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		       "AP\n", local->dev->name);
838ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
839ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	spin_lock_init(&ap->mac_restrictions.lock);
840ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	INIT_LIST_HEAD(&ap->mac_restrictions.mac_list);
841ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
842ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
843ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	ap->initialized = 1;
844ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen}
845ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
846ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
847ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenvoid hostap_init_ap_proc(local_info_t *local)
848ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{
849ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	struct ap_data *ap = local->ap;
850ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
851ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	ap->proc = local->proc;
852ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (ap->proc == NULL)
853ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		return;
854ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
855ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#ifndef PRISM2_NO_PROCFS_DEBUG
856ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	create_proc_read_entry("ap_debug", 0, ap->proc,
857ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			       ap_debug_proc_read, ap);
858ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#endif /* PRISM2_NO_PROCFS_DEBUG */
859ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
860ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
861ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	create_proc_read_entry("ap_control", 0, ap->proc,
862ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			       ap_control_proc_read, ap);
863ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	create_proc_read_entry("ap", 0, ap->proc,
864ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			       prism2_ap_proc_read, ap);
865ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
866ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
867ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen}
868ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
869ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
870ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenvoid hostap_free_data(struct ap_data *ap)
871ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{
872c15057313725942c6af8dcb60b4d4322101316d9Matthias Kaehlcke	struct sta_info *n, *sta;
873ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
874ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (ap == NULL || !ap->initialized) {
875ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		printk(KERN_DEBUG "hostap_free_data: ap has not yet been "
876ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		       "initialized - skip resource freeing\n");
877ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		return;
878ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
879ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
880ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
881ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (ap->crypt)
882ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		ap->crypt->deinit(ap->crypt_priv);
883ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	ap->crypt = ap->crypt_priv = NULL;
884ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
885ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
886c15057313725942c6af8dcb60b4d4322101316d9Matthias Kaehlcke	list_for_each_entry_safe(sta, n, &ap->sta_list, list) {
887ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		ap_sta_hash_del(ap, sta);
888ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		list_del(&sta->list);
889ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap && sta->local)
890ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			hostap_event_expired_sta(sta->local->dev, sta);
891ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		ap_free_sta(ap, sta);
892ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
893ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
894ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#ifndef PRISM2_NO_PROCFS_DEBUG
895ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (ap->proc != NULL) {
896ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		remove_proc_entry("ap_debug", ap->proc);
897ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
898ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#endif /* PRISM2_NO_PROCFS_DEBUG */
899ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
900ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
901ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (ap->proc != NULL) {
902ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	  remove_proc_entry("ap", ap->proc);
903ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		remove_proc_entry("ap_control", ap->proc);
904ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
905ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	ap_control_flush_macs(&ap->mac_restrictions);
906ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
907ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
908ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	ap->initialized = 0;
909ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen}
910ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
911ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
912ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen/* caller should have mutex for AP STA list handling */
913ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenstatic struct sta_info* ap_get_sta(struct ap_data *ap, u8 *sta)
914ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{
915ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	struct sta_info *s;
916ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
917ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	s = ap->sta_hash[STA_HASH(sta)];
918ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	while (s != NULL && memcmp(s->addr, sta, ETH_ALEN) != 0)
919ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		s = s->hnext;
920ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	return s;
921ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen}
922ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
923ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
924ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
925ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
926ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen/* Called from timer handler and from scheduled AP queue handlers */
927ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenstatic void prism2_send_mgmt(struct net_device *dev,
9284339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen			     u16 type_subtype, char *body,
929ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			     int body_len, u8 *addr, u16 tx_cb_idx)
930ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{
931ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	struct hostap_interface *iface;
932ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	local_info_t *local;
933d041674d62e1ad565f2fb6d53ae80b31d6656033James Ketrenos	struct ieee80211_hdr_4addr *hdr;
934ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	u16 fc;
935ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	struct sk_buff *skb;
936ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	struct hostap_skb_tx_data *meta;
937ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	int hdrlen;
938ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
939ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	iface = netdev_priv(dev);
940ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	local = iface->local;
941ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	dev = local->dev; /* always use master radio device */
942ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	iface = netdev_priv(dev);
943ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
944ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (!(dev->flags & IFF_UP)) {
945ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		PDEBUG(DEBUG_AP, "%s: prism2_send_mgmt - device is not UP - "
946ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		       "cannot send frame\n", dev->name);
947ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		return;
948ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
949ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
950ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	skb = dev_alloc_skb(sizeof(*hdr) + body_len);
951ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (skb == NULL) {
952ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		PDEBUG(DEBUG_AP, "%s: prism2_send_mgmt failed to allocate "
953ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		       "skb\n", dev->name);
954ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		return;
955ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
956ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
9574339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen	fc = type_subtype;
958ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	hdrlen = hostap_80211_get_hdrlen(fc);
959d041674d62e1ad565f2fb6d53ae80b31d6656033James Ketrenos	hdr = (struct ieee80211_hdr_4addr *) skb_put(skb, hdrlen);
960ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (body)
961ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		memcpy(skb_put(skb, body_len), body, body_len);
962ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
963ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	memset(hdr, 0, hdrlen);
964ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
965ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	/* FIX: ctrl::ack sending used special HFA384X_TX_CTRL_802_11
966ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	 * tx_control instead of using local->tx_control */
967ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
968ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
969ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	memcpy(hdr->addr1, addr, ETH_ALEN); /* DA / RA */
9704339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen	if (WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_DATA) {
971b2f4a2e3b1620667da9654f9e220c92ea52bdbe4Jouni Malinen		fc |= IEEE80211_FCTL_FROMDS;
972ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		memcpy(hdr->addr2, dev->dev_addr, ETH_ALEN); /* BSSID */
973ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		memcpy(hdr->addr3, dev->dev_addr, ETH_ALEN); /* SA */
9744339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen	} else if (WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_CTL) {
975ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		/* control:ACK does not have addr2 or addr3 */
976ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		memset(hdr->addr2, 0, ETH_ALEN);
977ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		memset(hdr->addr3, 0, ETH_ALEN);
978ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	} else {
979ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		memcpy(hdr->addr2, dev->dev_addr, ETH_ALEN); /* SA */
980ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		memcpy(hdr->addr3, dev->dev_addr, ETH_ALEN); /* BSSID */
981ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
982ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
983c0f72ca8e4f1b459b5582c1c8dcaf7e53151f069Jouni Malinen	hdr->frame_ctl = cpu_to_le16(fc);
984ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
985ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	meta = (struct hostap_skb_tx_data *) skb->cb;
986ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	memset(meta, 0, sizeof(*meta));
987ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	meta->magic = HOSTAP_SKB_TX_DATA_MAGIC;
988ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	meta->iface = iface;
989ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	meta->tx_cb_idx = tx_cb_idx;
990ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
991ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	skb->dev = dev;
992459a98ed881802dee55897441bc7f77af614368eArnaldo Carvalho de Melo	skb_reset_mac_header(skb);
993c1d2bbe1cd6c7bbdc6d532cefebb66c7efb789ceArnaldo Carvalho de Melo	skb_reset_network_header(skb);
994ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	dev_queue_xmit(skb);
995ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen}
996ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
997ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
998ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
999ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenstatic int prism2_sta_proc_read(char *page, char **start, off_t off,
1000ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen				int count, int *eof, void *data)
1001ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{
1002ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	char *p = page;
1003ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	struct sta_info *sta = (struct sta_info *) data;
1004ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	int i;
10050795af5729b18218767fab27c44b1384f72dc9adJoe Perches	DECLARE_MAC_BUF(mac);
1006ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1007ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	/* FIX: possible race condition.. the STA data could have just expired,
1008ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	 * but proc entry was still here so that the read could have started;
1009ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	 * some locking should be done here.. */
1010ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1011ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (off != 0) {
1012ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		*eof = 1;
1013ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		return 0;
1014ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
1015ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
10160795af5729b18218767fab27c44b1384f72dc9adJoe Perches	p += sprintf(p, "%s=%s\nusers=%d\naid=%d\n"
1017ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		     "flags=0x%04x%s%s%s%s%s%s%s\n"
1018ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		     "capability=0x%02x\nlisten_interval=%d\nsupported_rates=",
1019ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		     sta->ap ? "AP" : "STA",
10200795af5729b18218767fab27c44b1384f72dc9adJoe Perches		     print_mac(mac, sta->addr), atomic_read(&sta->users), sta->aid,
1021ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		     sta->flags,
1022ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		     sta->flags & WLAN_STA_AUTH ? " AUTH" : "",
1023ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		     sta->flags & WLAN_STA_ASSOC ? " ASSOC" : "",
1024ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		     sta->flags & WLAN_STA_PS ? " PS" : "",
1025ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		     sta->flags & WLAN_STA_TIM ? " TIM" : "",
1026ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		     sta->flags & WLAN_STA_PERM ? " PERM" : "",
1027ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		     sta->flags & WLAN_STA_AUTHORIZED ? " AUTHORIZED" : "",
1028ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		     sta->flags & WLAN_STA_PENDING_POLL ? " POLL" : "",
1029ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		     sta->capability, sta->listen_interval);
1030ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	/* supported_rates: 500 kbit/s units with msb ignored */
1031ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	for (i = 0; i < sizeof(sta->supported_rates); i++)
1032ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		if (sta->supported_rates[i] != 0)
1033ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			p += sprintf(p, "%d%sMbps ",
1034ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen				     (sta->supported_rates[i] & 0x7f) / 2,
1035ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen				     sta->supported_rates[i] & 1 ? ".5" : "");
1036ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	p += sprintf(p, "\njiffies=%lu\nlast_auth=%lu\nlast_assoc=%lu\n"
1037ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		     "last_rx=%lu\nlast_tx=%lu\nrx_packets=%lu\n"
1038ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		     "tx_packets=%lu\n"
1039ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		     "rx_bytes=%lu\ntx_bytes=%lu\nbuffer_count=%d\n"
1040ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		     "last_rx: silence=%d dBm signal=%d dBm rate=%d%s Mbps\n"
1041ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		     "tx_rate=%d\ntx[1M]=%d\ntx[2M]=%d\ntx[5.5M]=%d\n"
1042ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		     "tx[11M]=%d\n"
1043ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		     "rx[1M]=%d\nrx[2M]=%d\nrx[5.5M]=%d\nrx[11M]=%d\n",
1044ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		     jiffies, sta->last_auth, sta->last_assoc, sta->last_rx,
1045ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		     sta->last_tx,
1046ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		     sta->rx_packets, sta->tx_packets, sta->rx_bytes,
1047ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		     sta->tx_bytes, skb_queue_len(&sta->tx_buf),
1048ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		     sta->last_rx_silence,
1049ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		     sta->last_rx_signal, sta->last_rx_rate / 10,
1050ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		     sta->last_rx_rate % 10 ? ".5" : "",
1051ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		     sta->tx_rate, sta->tx_count[0], sta->tx_count[1],
1052ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		     sta->tx_count[2], sta->tx_count[3],  sta->rx_count[0],
1053ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		     sta->rx_count[1], sta->rx_count[2], sta->rx_count[3]);
1054ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (sta->crypt && sta->crypt->ops && sta->crypt->ops->print_stats)
1055ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		p = sta->crypt->ops->print_stats(p, sta->crypt->priv);
1056ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
1057ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (sta->ap) {
1058ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		if (sta->u.ap.channel >= 0)
1059ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			p += sprintf(p, "channel=%d\n", sta->u.ap.channel);
1060ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		p += sprintf(p, "ssid=");
1061ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		for (i = 0; i < sta->u.ap.ssid_len; i++)
1062ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			p += sprintf(p, ((sta->u.ap.ssid[i] >= 32 &&
1063ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen					  sta->u.ap.ssid[i] < 127) ?
1064ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen					 "%c" : "<%02x>"),
1065ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen				     sta->u.ap.ssid[i]);
1066ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		p += sprintf(p, "\n");
1067ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
1068ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
1069ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1070ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	return (p - page);
1071ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen}
1072ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1073ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1074c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howellsstatic void handle_add_proc_queue(struct work_struct *work)
1075ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{
1076c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howells	struct ap_data *ap = container_of(work, struct ap_data,
1077c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howells					  add_sta_proc_queue);
1078ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	struct sta_info *sta;
1079ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	char name[20];
1080ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	struct add_sta_proc_data *entry, *prev;
10810795af5729b18218767fab27c44b1384f72dc9adJoe Perches	DECLARE_MAC_BUF(mac);
1082ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1083ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	entry = ap->add_sta_proc_entries;
1084ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	ap->add_sta_proc_entries = NULL;
1085ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1086ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	while (entry) {
1087ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		spin_lock_bh(&ap->sta_table_lock);
1088ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		sta = ap_get_sta(ap, entry->addr);
1089ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		if (sta)
1090ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			atomic_inc(&sta->users);
1091ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		spin_unlock_bh(&ap->sta_table_lock);
1092ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1093ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		if (sta) {
10940795af5729b18218767fab27c44b1384f72dc9adJoe Perches			sprintf(name, "%s", print_mac(mac, sta->addr));
1095ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			sta->proc = create_proc_read_entry(
1096ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen				name, 0, ap->proc,
1097ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen				prism2_sta_proc_read, sta);
1098ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1099ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			atomic_dec(&sta->users);
1100ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		}
1101ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1102ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		prev = entry;
1103ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		entry = entry->next;
1104ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		kfree(prev);
1105ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
1106ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen}
1107ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1108ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1109ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenstatic struct sta_info * ap_add_sta(struct ap_data *ap, u8 *addr)
1110ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{
1111ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	struct sta_info *sta;
1112ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1113b0471bb7b779f5deea109e5bfdfe8c18d4a06241Yan Burman	sta = kzalloc(sizeof(struct sta_info), GFP_ATOMIC);
1114ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (sta == NULL) {
1115ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		PDEBUG(DEBUG_AP, "AP: kmalloc failed\n");
1116ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		return NULL;
1117ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
1118ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1119ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	/* initialize STA info data */
1120ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	sta->local = ap->local;
1121ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	skb_queue_head_init(&sta->tx_buf);
1122ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	memcpy(sta->addr, addr, ETH_ALEN);
1123ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1124ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	atomic_inc(&sta->users);
1125ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	spin_lock_bh(&ap->sta_table_lock);
1126ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	list_add(&sta->list, &ap->sta_list);
1127ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	ap->num_sta++;
1128ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	ap_sta_hash_add(ap, sta);
1129ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	spin_unlock_bh(&ap->sta_table_lock);
1130ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1131ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (ap->proc) {
1132ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		struct add_sta_proc_data *entry;
1133ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		/* schedule a non-interrupt context process to add a procfs
1134ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		 * entry for the STA since procfs code use GFP_KERNEL */
1135ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
1136ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		if (entry) {
1137ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			memcpy(entry->addr, sta->addr, ETH_ALEN);
1138ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			entry->next = ap->add_sta_proc_entries;
1139ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			ap->add_sta_proc_entries = entry;
1140ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			schedule_work(&ap->add_sta_proc_queue);
1141ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		} else
1142ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			printk(KERN_DEBUG "Failed to add STA proc data\n");
1143ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
1144ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1145ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
1146ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	init_timer(&sta->timer);
1147ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	sta->timer.expires = jiffies + ap->max_inactivity;
1148ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	sta->timer.data = (unsigned long) sta;
1149ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	sta->timer.function = ap_handle_timer;
1150ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (!ap->local->hostapd)
1151ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		add_timer(&sta->timer);
1152ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
1153ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1154ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	return sta;
1155ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen}
1156ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1157ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1158ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenstatic int ap_tx_rate_ok(int rateidx, struct sta_info *sta,
1159ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			 local_info_t *local)
1160ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{
1161ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (rateidx > sta->tx_max_rate ||
1162ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	    !(sta->tx_supp_rates & (1 << rateidx)))
1163ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		return 0;
1164ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1165ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (local->tx_rate_control != 0 &&
1166ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	    !(local->tx_rate_control & (1 << rateidx)))
1167ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		return 0;
1168ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1169ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	return 1;
1170ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen}
1171ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1172ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1173ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenstatic void prism2_check_tx_rates(struct sta_info *sta)
1174ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{
1175ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	int i;
1176ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1177ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	sta->tx_supp_rates = 0;
1178ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	for (i = 0; i < sizeof(sta->supported_rates); i++) {
1179ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		if ((sta->supported_rates[i] & 0x7f) == 2)
1180ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			sta->tx_supp_rates |= WLAN_RATE_1M;
1181ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		if ((sta->supported_rates[i] & 0x7f) == 4)
1182ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			sta->tx_supp_rates |= WLAN_RATE_2M;
1183ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		if ((sta->supported_rates[i] & 0x7f) == 11)
1184ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			sta->tx_supp_rates |= WLAN_RATE_5M5;
1185ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		if ((sta->supported_rates[i] & 0x7f) == 22)
1186ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			sta->tx_supp_rates |= WLAN_RATE_11M;
1187ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
1188ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	sta->tx_max_rate = sta->tx_rate = sta->tx_rate_idx = 0;
1189ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (sta->tx_supp_rates & WLAN_RATE_1M) {
1190ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		sta->tx_max_rate = 0;
1191ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		if (ap_tx_rate_ok(0, sta, sta->local)) {
1192ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			sta->tx_rate = 10;
1193ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			sta->tx_rate_idx = 0;
1194ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		}
1195ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
1196ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (sta->tx_supp_rates & WLAN_RATE_2M) {
1197ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		sta->tx_max_rate = 1;
1198ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		if (ap_tx_rate_ok(1, sta, sta->local)) {
1199ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			sta->tx_rate = 20;
1200ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			sta->tx_rate_idx = 1;
1201ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		}
1202ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
1203ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (sta->tx_supp_rates & WLAN_RATE_5M5) {
1204ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		sta->tx_max_rate = 2;
1205ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		if (ap_tx_rate_ok(2, sta, sta->local)) {
1206ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			sta->tx_rate = 55;
1207ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			sta->tx_rate_idx = 2;
1208ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		}
1209ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
1210ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (sta->tx_supp_rates & WLAN_RATE_11M) {
1211ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		sta->tx_max_rate = 3;
1212ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		if (ap_tx_rate_ok(3, sta, sta->local)) {
1213ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			sta->tx_rate = 110;
1214ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			sta->tx_rate_idx = 3;
1215ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		}
1216ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
1217ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen}
1218ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1219ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1220ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
1221ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1222ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenstatic void ap_crypt_init(struct ap_data *ap)
1223ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{
122462fe7e378109537ff80971c5208e12d40bf88beeJouni Malinen	ap->crypt = ieee80211_get_crypto_ops("WEP");
1225ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1226ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (ap->crypt) {
1227ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		if (ap->crypt->init) {
1228ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			ap->crypt_priv = ap->crypt->init(0);
1229ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			if (ap->crypt_priv == NULL)
1230ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen				ap->crypt = NULL;
1231ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			else {
1232ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen				u8 key[WEP_KEY_LEN];
1233ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen				get_random_bytes(key, WEP_KEY_LEN);
1234ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen				ap->crypt->set_key(key, WEP_KEY_LEN, NULL,
1235ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen						   ap->crypt_priv);
1236ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			}
1237ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		}
1238ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
1239ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1240ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (ap->crypt == NULL) {
1241ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		printk(KERN_WARNING "AP could not initialize WEP: load module "
124262fe7e378109537ff80971c5208e12d40bf88beeJouni Malinen		       "ieee80211_crypt_wep.ko\n");
1243ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
1244ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen}
1245ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1246ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1247ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen/* Generate challenge data for shared key authentication. IEEE 802.11 specifies
1248ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * that WEP algorithm is used for generating challange. This should be unique,
1249ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * but otherwise there is not really need for randomness etc. Initialize WEP
1250ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * with pseudo random key and then use increasing IV to get unique challenge
1251ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * streams.
1252ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen *
1253ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * Called only as a scheduled task for pending AP frames.
1254ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen */
1255ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenstatic char * ap_auth_make_challenge(struct ap_data *ap)
1256ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{
1257ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	char *tmpbuf;
1258ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	struct sk_buff *skb;
1259ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1260ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (ap->crypt == NULL) {
1261ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		ap_crypt_init(ap);
1262ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		if (ap->crypt == NULL)
1263ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			return NULL;
1264ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
1265ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
12665cbded585d129d0226cb48ac4202b253c781be26Robert P. J. Day	tmpbuf = kmalloc(WLAN_AUTH_CHALLENGE_LEN, GFP_ATOMIC);
1267ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (tmpbuf == NULL) {
1268ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		PDEBUG(DEBUG_AP, "AP: kmalloc failed for challenge\n");
1269ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		return NULL;
1270ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
1271ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1272ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	skb = dev_alloc_skb(WLAN_AUTH_CHALLENGE_LEN +
12735bfc819b53ed67c76f33f969ab627070e85d87c1James Ketrenos			    ap->crypt->extra_mpdu_prefix_len +
12745bfc819b53ed67c76f33f969ab627070e85d87c1James Ketrenos			    ap->crypt->extra_mpdu_postfix_len);
1275ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (skb == NULL) {
1276ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		kfree(tmpbuf);
1277ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		return NULL;
1278ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
1279ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
12805bfc819b53ed67c76f33f969ab627070e85d87c1James Ketrenos	skb_reserve(skb, ap->crypt->extra_mpdu_prefix_len);
1281ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	memset(skb_put(skb, WLAN_AUTH_CHALLENGE_LEN), 0,
1282ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	       WLAN_AUTH_CHALLENGE_LEN);
1283ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (ap->crypt->encrypt_mpdu(skb, 0, ap->crypt_priv)) {
1284ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		dev_kfree_skb(skb);
1285ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		kfree(tmpbuf);
1286ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		return NULL;
1287ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
1288ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1289d626f62b11e00c16e81e4308ab93d3f13551812aArnaldo Carvalho de Melo	skb_copy_from_linear_data_offset(skb, ap->crypt->extra_mpdu_prefix_len,
1290d626f62b11e00c16e81e4308ab93d3f13551812aArnaldo Carvalho de Melo					 tmpbuf, WLAN_AUTH_CHALLENGE_LEN);
1291ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	dev_kfree_skb(skb);
1292ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1293ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	return tmpbuf;
1294ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen}
1295ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1296ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1297ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen/* Called only as a scheduled task for pending AP frames. */
1298ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenstatic void handle_authen(local_info_t *local, struct sk_buff *skb,
1299ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			  struct hostap_80211_rx_status *rx_stats)
1300ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{
1301ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	struct net_device *dev = local->dev;
1302d041674d62e1ad565f2fb6d53ae80b31d6656033James Ketrenos	struct ieee80211_hdr_4addr *hdr = (struct ieee80211_hdr_4addr *) skb->data;
1303ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	size_t hdrlen;
1304ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	struct ap_data *ap = local->ap;
1305ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	char body[8 + WLAN_AUTH_CHALLENGE_LEN], *challenge = NULL;
1306ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	int len, olen;
13078a9faf3cd08b91aca1502dbe18e3b5063fda2e87Al Viro	u16 auth_alg, auth_transaction, status_code;
13088a9faf3cd08b91aca1502dbe18e3b5063fda2e87Al Viro	__le16 *pos;
1309ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	u16 resp = WLAN_STATUS_SUCCESS, fc;
1310ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	struct sta_info *sta = NULL;
131162fe7e378109537ff80971c5208e12d40bf88beeJouni Malinen	struct ieee80211_crypt_data *crypt;
1312ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	char *txt = "";
1313ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1314ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	len = skb->len - IEEE80211_MGMT_HDR_LEN;
1315ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1316c0f72ca8e4f1b459b5582c1c8dcaf7e53151f069Jouni Malinen	fc = le16_to_cpu(hdr->frame_ctl);
1317ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	hdrlen = hostap_80211_get_hdrlen(fc);
1318ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1319ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (len < 6) {
1320ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		PDEBUG(DEBUG_AP, "%s: handle_authen - too short payload "
132121f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller		       "(len=%d) from " MAC_FMT "\n", dev->name, len,
132221f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller		       hdr->addr2[0], hdr->addr2[1], hdr->addr2[2],
132321f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller		       hdr->addr2[3], hdr->addr2[4], hdr->addr2[5]);
1324ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		return;
1325ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
1326ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1327ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	spin_lock_bh(&local->ap->sta_table_lock);
1328ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	sta = ap_get_sta(local->ap, hdr->addr2);
1329ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (sta)
1330ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		atomic_inc(&sta->users);
1331ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	spin_unlock_bh(&local->ap->sta_table_lock);
1332ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1333ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (sta && sta->crypt)
1334ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		crypt = sta->crypt;
1335ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	else {
1336ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		int idx = 0;
1337ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		if (skb->len >= hdrlen + 3)
1338ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			idx = skb->data[hdrlen + 3] >> 6;
1339ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		crypt = local->crypt[idx];
1340ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
1341ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
13428a9faf3cd08b91aca1502dbe18e3b5063fda2e87Al Viro	pos = (__le16 *) (skb->data + IEEE80211_MGMT_HDR_LEN);
1343ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	auth_alg = __le16_to_cpu(*pos);
1344ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	pos++;
1345ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	auth_transaction = __le16_to_cpu(*pos);
1346ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	pos++;
1347ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	status_code = __le16_to_cpu(*pos);
1348ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	pos++;
1349ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1350ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (memcmp(dev->dev_addr, hdr->addr2, ETH_ALEN) == 0 ||
1351ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	    ap_control_mac_deny(&ap->mac_restrictions, hdr->addr2)) {
1352ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		txt = "authentication denied";
1353ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1354ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		goto fail;
1355ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
1356ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1357ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (((local->auth_algs & PRISM2_AUTH_OPEN) &&
1358ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	     auth_alg == WLAN_AUTH_OPEN) ||
1359ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	    ((local->auth_algs & PRISM2_AUTH_SHARED_KEY) &&
1360ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	     crypt && auth_alg == WLAN_AUTH_SHARED_KEY)) {
1361ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	} else {
1362ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		txt = "unsupported algorithm";
1363ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		resp = WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG;
1364ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		goto fail;
1365ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
1366ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1367ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (len >= 8) {
1368ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		u8 *u = (u8 *) pos;
1369ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		if (*u == WLAN_EID_CHALLENGE) {
1370ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			if (*(u + 1) != WLAN_AUTH_CHALLENGE_LEN) {
1371ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen				txt = "invalid challenge len";
1372ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen				resp = WLAN_STATUS_CHALLENGE_FAIL;
1373ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen				goto fail;
1374ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			}
1375ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			if (len - 8 < WLAN_AUTH_CHALLENGE_LEN) {
1376ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen				txt = "challenge underflow";
1377ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen				resp = WLAN_STATUS_CHALLENGE_FAIL;
1378ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen				goto fail;
1379ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			}
1380ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			challenge = (char *) (u + 2);
1381ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		}
1382ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
1383ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1384ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (sta && sta->ap) {
1385ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		if (time_after(jiffies, sta->u.ap.last_beacon +
1386ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			       (10 * sta->listen_interval * HZ) / 1024)) {
1387ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			PDEBUG(DEBUG_AP, "%s: no beacons received for a while,"
138821f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller			       " assuming AP " MAC_FMT " is now STA\n",
138921f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller			       dev->name,
139021f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller			       sta->addr[0], sta->addr[1], sta->addr[2],
139121f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller			       sta->addr[3], sta->addr[4], sta->addr[5]);
1392ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			sta->ap = 0;
1393ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			sta->flags = 0;
1394ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			sta->u.sta.challenge = NULL;
1395ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		} else {
1396ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			txt = "AP trying to authenticate?";
1397ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1398ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			goto fail;
1399ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		}
1400ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
1401ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1402ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if ((auth_alg == WLAN_AUTH_OPEN && auth_transaction == 1) ||
1403ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	    (auth_alg == WLAN_AUTH_SHARED_KEY &&
1404ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	     (auth_transaction == 1 ||
1405ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	      (auth_transaction == 3 && sta != NULL &&
1406ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	       sta->u.sta.challenge != NULL)))) {
1407ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	} else {
1408ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		txt = "unknown authentication transaction number";
1409ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		resp = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION;
1410ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		goto fail;
1411ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
1412ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1413ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (sta == NULL) {
1414ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		txt = "new STA";
1415ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1416ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		if (local->ap->num_sta >= MAX_STA_COUNT) {
1417ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			/* FIX: might try to remove some old STAs first? */
1418ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			txt = "no more room for new STAs";
1419ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1420ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			goto fail;
1421ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		}
1422ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1423ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		sta = ap_add_sta(local->ap, hdr->addr2);
1424ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		if (sta == NULL) {
1425ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			txt = "ap_add_sta failed";
1426ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1427ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			goto fail;
1428ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		}
1429ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
1430ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1431ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	switch (auth_alg) {
1432ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	case WLAN_AUTH_OPEN:
1433ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		txt = "authOK";
1434ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		/* IEEE 802.11 standard is not completely clear about
1435ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		 * whether STA is considered authenticated after
1436ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		 * authentication OK frame has been send or after it
1437ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		 * has been ACKed. In order to reduce interoperability
1438ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		 * issues, mark the STA authenticated before ACK. */
1439ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		sta->flags |= WLAN_STA_AUTH;
1440ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		break;
1441ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1442ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	case WLAN_AUTH_SHARED_KEY:
1443ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		if (auth_transaction == 1) {
1444ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			if (sta->u.sta.challenge == NULL) {
1445ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen				sta->u.sta.challenge =
1446ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen					ap_auth_make_challenge(local->ap);
1447ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen				if (sta->u.sta.challenge == NULL) {
1448ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen					resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1449ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen					goto fail;
1450ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen				}
1451ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			}
1452ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		} else {
1453ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			if (sta->u.sta.challenge == NULL ||
1454ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			    challenge == NULL ||
1455ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			    memcmp(sta->u.sta.challenge, challenge,
1456ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen				   WLAN_AUTH_CHALLENGE_LEN) != 0 ||
1457831a179fc9387af6dbaa12816ae1e074d1f1a730Jeff Garzik			    !(fc & IEEE80211_FCTL_PROTECTED)) {
1458ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen				txt = "challenge response incorrect";
1459ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen				resp = WLAN_STATUS_CHALLENGE_FAIL;
1460ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen				goto fail;
1461ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			}
1462ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1463ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			txt = "challenge OK - authOK";
1464ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			/* IEEE 802.11 standard is not completely clear about
1465ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			 * whether STA is considered authenticated after
1466ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			 * authentication OK frame has been send or after it
1467ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			 * has been ACKed. In order to reduce interoperability
1468ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			 * issues, mark the STA authenticated before ACK. */
1469ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			sta->flags |= WLAN_STA_AUTH;
1470ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			kfree(sta->u.sta.challenge);
1471ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			sta->u.sta.challenge = NULL;
1472ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		}
1473ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		break;
1474ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
1475ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1476ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen fail:
14778a9faf3cd08b91aca1502dbe18e3b5063fda2e87Al Viro	pos = (__le16 *) body;
1478ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	*pos = cpu_to_le16(auth_alg);
1479ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	pos++;
1480ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	*pos = cpu_to_le16(auth_transaction + 1);
1481ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	pos++;
1482ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	*pos = cpu_to_le16(resp); /* status_code */
1483ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	pos++;
1484ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	olen = 6;
1485ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1486ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (resp == WLAN_STATUS_SUCCESS && sta != NULL &&
1487ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	    sta->u.sta.challenge != NULL &&
1488ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	    auth_alg == WLAN_AUTH_SHARED_KEY && auth_transaction == 1) {
1489ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		u8 *tmp = (u8 *) pos;
1490ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		*tmp++ = WLAN_EID_CHALLENGE;
1491ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		*tmp++ = WLAN_AUTH_CHALLENGE_LEN;
1492ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		pos++;
1493ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		memcpy(pos, sta->u.sta.challenge, WLAN_AUTH_CHALLENGE_LEN);
1494ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		olen += 2 + WLAN_AUTH_CHALLENGE_LEN;
1495ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
1496ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
14974339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen	prism2_send_mgmt(dev, IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_AUTH,
1498ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			 body, olen, hdr->addr2, ap->tx_callback_auth);
1499ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1500ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (sta) {
1501ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		sta->last_rx = jiffies;
1502ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		atomic_dec(&sta->users);
1503ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
1504ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1505ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (resp) {
150621f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller		PDEBUG(DEBUG_AP, "%s: " MAC_FMT " auth (alg=%d "
15070795af5729b18218767fab27c44b1384f72dc9adJoe Perches		       "trans#=%d stat=%d len=%d fc=%04x) ==> %d (%s)\n",
150821f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller		       dev->name,
150921f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller		       hdr->addr2[0], hdr->addr2[1], hdr->addr2[2],
151021f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller		       hdr->addr2[3], hdr->addr2[4], hdr->addr2[5],
151121f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller		       auth_alg, auth_transaction, status_code, len,
151221f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller		       fc, resp, txt);
1513ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
1514ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen}
1515ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1516ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1517ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen/* Called only as a scheduled task for pending AP frames. */
1518ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenstatic void handle_assoc(local_info_t *local, struct sk_buff *skb,
1519ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			 struct hostap_80211_rx_status *rx_stats, int reassoc)
1520ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{
1521ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	struct net_device *dev = local->dev;
1522d041674d62e1ad565f2fb6d53ae80b31d6656033James Ketrenos	struct ieee80211_hdr_4addr *hdr = (struct ieee80211_hdr_4addr *) skb->data;
1523ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	char body[12], *p, *lpos;
1524ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	int len, left;
15258a9faf3cd08b91aca1502dbe18e3b5063fda2e87Al Viro	__le16 *pos;
1526ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	u16 resp = WLAN_STATUS_SUCCESS;
1527ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	struct sta_info *sta = NULL;
1528ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	int send_deauth = 0;
1529ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	char *txt = "";
1530ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	u8 prev_ap[ETH_ALEN];
1531ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1532ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	left = len = skb->len - IEEE80211_MGMT_HDR_LEN;
1533ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1534ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (len < (reassoc ? 10 : 4)) {
1535ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		PDEBUG(DEBUG_AP, "%s: handle_assoc - too short payload "
153621f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller		       "(len=%d, reassoc=%d) from " MAC_FMT "\n",
153721f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller		       dev->name, len, reassoc,
153821f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller		       hdr->addr2[0], hdr->addr2[1], hdr->addr2[2],
153921f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller		       hdr->addr2[3], hdr->addr2[4], hdr->addr2[5]);
1540ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		return;
1541ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
1542ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1543ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	spin_lock_bh(&local->ap->sta_table_lock);
1544ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	sta = ap_get_sta(local->ap, hdr->addr2);
1545ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (sta == NULL || (sta->flags & WLAN_STA_AUTH) == 0) {
1546ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		spin_unlock_bh(&local->ap->sta_table_lock);
1547ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		txt = "trying to associate before authentication";
1548ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		send_deauth = 1;
1549ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1550ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		sta = NULL; /* do not decrement sta->users */
1551ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		goto fail;
1552ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
1553ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	atomic_inc(&sta->users);
1554ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	spin_unlock_bh(&local->ap->sta_table_lock);
1555ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
15568a9faf3cd08b91aca1502dbe18e3b5063fda2e87Al Viro	pos = (__le16 *) (skb->data + IEEE80211_MGMT_HDR_LEN);
1557ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	sta->capability = __le16_to_cpu(*pos);
1558ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	pos++; left -= 2;
1559ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	sta->listen_interval = __le16_to_cpu(*pos);
1560ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	pos++; left -= 2;
1561ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1562ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (reassoc) {
1563ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		memcpy(prev_ap, pos, ETH_ALEN);
1564ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		pos++; pos++; pos++; left -= 6;
1565ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	} else
1566ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		memset(prev_ap, 0, ETH_ALEN);
1567ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1568ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (left >= 2) {
1569ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		unsigned int ileft;
1570ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		unsigned char *u = (unsigned char *) pos;
1571ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1572ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		if (*u == WLAN_EID_SSID) {
1573ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			u++; left--;
1574ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			ileft = *u;
1575ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			u++; left--;
1576ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1577ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			if (ileft > left || ileft > MAX_SSID_LEN) {
1578ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen				txt = "SSID overflow";
1579ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen				resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1580ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen				goto fail;
1581ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			}
1582ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1583ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			if (ileft != strlen(local->essid) ||
1584ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			    memcmp(local->essid, u, ileft) != 0) {
1585ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen				txt = "not our SSID";
1586ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen				resp = WLAN_STATUS_ASSOC_DENIED_UNSPEC;
1587ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen				goto fail;
1588ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			}
1589ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1590ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			u += ileft;
1591ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			left -= ileft;
1592ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		}
1593ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1594ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		if (left >= 2 && *u == WLAN_EID_SUPP_RATES) {
1595ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			u++; left--;
1596ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			ileft = *u;
1597ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			u++; left--;
159874fae82c8bd5dd78365abe25506a9ba388d4a889Jeff Garzik
1599ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			if (ileft > left || ileft == 0 ||
1600ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			    ileft > WLAN_SUPP_RATES_MAX) {
1601ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen				txt = "SUPP_RATES len error";
1602ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen				resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1603ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen				goto fail;
1604ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			}
1605ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1606ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			memset(sta->supported_rates, 0,
1607ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			       sizeof(sta->supported_rates));
1608ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			memcpy(sta->supported_rates, u, ileft);
1609ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			prism2_check_tx_rates(sta);
1610ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1611ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			u += ileft;
1612ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			left -= ileft;
1613ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		}
1614ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1615ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		if (left > 0) {
161621f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller			PDEBUG(DEBUG_AP, "%s: assoc from " MAC_FMT
16170795af5729b18218767fab27c44b1384f72dc9adJoe Perches			       " with extra data (%d bytes) [",
161821f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller			       dev->name,
161921f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller			       hdr->addr2[0], hdr->addr2[1], hdr->addr2[2],
162021f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller			       hdr->addr2[3], hdr->addr2[4], hdr->addr2[5],
162121f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller			       left);
1622ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			while (left > 0) {
1623ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen				PDEBUG2(DEBUG_AP, "<%02x>", *u);
1624ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen				u++; left--;
1625ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			}
1626ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			PDEBUG2(DEBUG_AP, "]\n");
1627ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		}
1628ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	} else {
1629ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		txt = "frame underflow";
1630ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
1631ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		goto fail;
1632ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
1633ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1634ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	/* get a unique AID */
1635ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (sta->aid > 0)
1636ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		txt = "OK, old AID";
1637ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	else {
1638ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		spin_lock_bh(&local->ap->sta_table_lock);
1639ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		for (sta->aid = 1; sta->aid <= MAX_AID_TABLE_SIZE; sta->aid++)
1640ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			if (local->ap->sta_aid[sta->aid - 1] == NULL)
1641ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen				break;
1642ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		if (sta->aid > MAX_AID_TABLE_SIZE) {
1643ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			sta->aid = 0;
1644ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			spin_unlock_bh(&local->ap->sta_table_lock);
1645ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
1646ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			txt = "no room for more AIDs";
1647ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		} else {
1648ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			local->ap->sta_aid[sta->aid - 1] = sta;
1649ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			spin_unlock_bh(&local->ap->sta_table_lock);
1650ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			txt = "OK, new AID";
1651ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		}
1652ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
1653ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1654ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen fail:
16558a9faf3cd08b91aca1502dbe18e3b5063fda2e87Al Viro	pos = (__le16 *) body;
1656ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1657ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (send_deauth) {
16588a9faf3cd08b91aca1502dbe18e3b5063fda2e87Al Viro		*pos = cpu_to_le16(WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH);
1659ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		pos++;
1660ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	} else {
1661ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		/* FIX: CF-Pollable and CF-PollReq should be set to match the
1662ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		 * values in beacons/probe responses */
1663ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		/* FIX: how about privacy and WEP? */
1664ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		/* capability */
16658a9faf3cd08b91aca1502dbe18e3b5063fda2e87Al Viro		*pos = cpu_to_le16(WLAN_CAPABILITY_ESS);
1666ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		pos++;
1667ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1668ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		/* status_code */
16698a9faf3cd08b91aca1502dbe18e3b5063fda2e87Al Viro		*pos = cpu_to_le16(resp);
1670ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		pos++;
1671ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
16728a9faf3cd08b91aca1502dbe18e3b5063fda2e87Al Viro		*pos = cpu_to_le16((sta && sta->aid > 0 ? sta->aid : 0) |
1673ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen				     BIT(14) | BIT(15)); /* AID */
1674ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		pos++;
1675ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1676ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		/* Supported rates (Information element) */
1677ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		p = (char *) pos;
1678ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		*p++ = WLAN_EID_SUPP_RATES;
1679ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		lpos = p;
1680ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		*p++ = 0; /* len */
1681ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		if (local->tx_rate_control & WLAN_RATE_1M) {
1682ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			*p++ = local->basic_rates & WLAN_RATE_1M ? 0x82 : 0x02;
1683ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			(*lpos)++;
1684ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		}
1685ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		if (local->tx_rate_control & WLAN_RATE_2M) {
1686ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			*p++ = local->basic_rates & WLAN_RATE_2M ? 0x84 : 0x04;
1687ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			(*lpos)++;
1688ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		}
1689ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		if (local->tx_rate_control & WLAN_RATE_5M5) {
1690ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			*p++ = local->basic_rates & WLAN_RATE_5M5 ?
1691ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen				0x8b : 0x0b;
1692ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			(*lpos)++;
1693ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		}
1694ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		if (local->tx_rate_control & WLAN_RATE_11M) {
1695ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			*p++ = local->basic_rates & WLAN_RATE_11M ?
1696ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen				0x96 : 0x16;
1697ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			(*lpos)++;
1698ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		}
16998a9faf3cd08b91aca1502dbe18e3b5063fda2e87Al Viro		pos = (__le16 *) p;
1700ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
1701ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
17024339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen	prism2_send_mgmt(dev, IEEE80211_FTYPE_MGMT |
17034339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen			 (send_deauth ? IEEE80211_STYPE_DEAUTH :
17044339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen			  (reassoc ? IEEE80211_STYPE_REASSOC_RESP :
17054339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen			   IEEE80211_STYPE_ASSOC_RESP)),
1706ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			 body, (u8 *) pos - (u8 *) body,
1707ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			 hdr->addr2,
1708ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			 send_deauth ? 0 : local->ap->tx_callback_assoc);
1709ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1710ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (sta) {
1711ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		if (resp == WLAN_STATUS_SUCCESS) {
1712ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			sta->last_rx = jiffies;
1713ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			/* STA will be marked associated from TX callback, if
1714ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			 * AssocResp is ACKed */
1715ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		}
1716ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		atomic_dec(&sta->users);
1717ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
1718ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1719ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#if 0
172021f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller	PDEBUG(DEBUG_AP, "%s: " MAC_FMT" %sassoc (len=%d "
172121f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller	       "prev_ap=" MAC_FMT") => %d(%d) (%s)\n",
172221f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller	       dev->name,
172321f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller	       hdr->addr2[0], hdr->addr2[1], hdr->addr2[2],
172421f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller	       hdr->addr2[3], hdr->addr2[4], hdr->addr2[5],
172521f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller	       reassoc ? "re" : "", len,
172621f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller	       prev_ap[0], prev_ap[1], prev_ap[2],
172721f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller	       prev_ap[3], prev_ap[4], prev_ap[5],
172821f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller	       resp, send_deauth, txt);
1729ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#endif
1730ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen}
1731ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1732ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1733ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen/* Called only as a scheduled task for pending AP frames. */
1734ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenstatic void handle_deauth(local_info_t *local, struct sk_buff *skb,
1735ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			  struct hostap_80211_rx_status *rx_stats)
1736ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{
1737ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	struct net_device *dev = local->dev;
1738d041674d62e1ad565f2fb6d53ae80b31d6656033James Ketrenos	struct ieee80211_hdr_4addr *hdr = (struct ieee80211_hdr_4addr *) skb->data;
1739ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	char *body = (char *) (skb->data + IEEE80211_MGMT_HDR_LEN);
1740ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	int len;
17418a9faf3cd08b91aca1502dbe18e3b5063fda2e87Al Viro	u16 reason_code;
17428a9faf3cd08b91aca1502dbe18e3b5063fda2e87Al Viro	__le16 *pos;
1743ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	struct sta_info *sta = NULL;
17440795af5729b18218767fab27c44b1384f72dc9adJoe Perches	DECLARE_MAC_BUF(mac);
1745ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1746ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	len = skb->len - IEEE80211_MGMT_HDR_LEN;
1747ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1748ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (len < 2) {
1749ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		printk("handle_deauth - too short payload (len=%d)\n", len);
1750ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		return;
1751ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
1752ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
17538a9faf3cd08b91aca1502dbe18e3b5063fda2e87Al Viro	pos = (__le16 *) body;
17548a9faf3cd08b91aca1502dbe18e3b5063fda2e87Al Viro	reason_code = le16_to_cpu(*pos);
1755ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
175621f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller	PDEBUG(DEBUG_AP, "%s: deauthentication: " MAC_FMT " len=%d, "
175721f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller	       "reason_code=%d\n", dev->name,
175821f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller	       hdr->addr2[0], hdr->addr2[1], hdr->addr2[2],
175921f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller	       hdr->addr2[3], hdr->addr2[4], hdr->addr2[5],
176021f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller	       len, reason_code);
1761ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1762ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	spin_lock_bh(&local->ap->sta_table_lock);
1763ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	sta = ap_get_sta(local->ap, hdr->addr2);
1764ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (sta != NULL) {
1765ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap)
1766ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			hostap_event_expired_sta(local->dev, sta);
1767ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
1768ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
1769ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	spin_unlock_bh(&local->ap->sta_table_lock);
1770ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (sta == NULL) {
177121f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller		printk("%s: deauthentication from " MAC_FMT ", "
1772ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	       "reason_code=%d, but STA not authenticated\n", dev->name,
177321f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller		       hdr->addr2[0], hdr->addr2[1], hdr->addr2[2],
177421f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller		       hdr->addr2[3], hdr->addr2[4], hdr->addr2[5],
177521f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller		       reason_code);
1776ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
1777ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen}
1778ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1779ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1780ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen/* Called only as a scheduled task for pending AP frames. */
1781ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenstatic void handle_disassoc(local_info_t *local, struct sk_buff *skb,
1782ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			    struct hostap_80211_rx_status *rx_stats)
1783ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{
1784ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	struct net_device *dev = local->dev;
1785d041674d62e1ad565f2fb6d53ae80b31d6656033James Ketrenos	struct ieee80211_hdr_4addr *hdr = (struct ieee80211_hdr_4addr *) skb->data;
1786ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	char *body = skb->data + IEEE80211_MGMT_HDR_LEN;
1787ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	int len;
17888a9faf3cd08b91aca1502dbe18e3b5063fda2e87Al Viro	u16 reason_code;
17898a9faf3cd08b91aca1502dbe18e3b5063fda2e87Al Viro	__le16 *pos;
1790ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	struct sta_info *sta = NULL;
1791ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1792ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	len = skb->len - IEEE80211_MGMT_HDR_LEN;
1793ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1794ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (len < 2) {
1795ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		printk("handle_disassoc - too short payload (len=%d)\n", len);
1796ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		return;
1797ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
1798ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
17998a9faf3cd08b91aca1502dbe18e3b5063fda2e87Al Viro	pos = (__le16 *) body;
18008a9faf3cd08b91aca1502dbe18e3b5063fda2e87Al Viro	reason_code = le16_to_cpu(*pos);
1801ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
180221f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller	PDEBUG(DEBUG_AP, "%s: disassociation: " MAC_FMT " len=%d, "
180321f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller	       "reason_code=%d\n", dev->name,
180421f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller	       hdr->addr2[0], hdr->addr2[1], hdr->addr2[2],
180521f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller	       hdr->addr2[3], hdr->addr2[4], hdr->addr2[5],
180621f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller	       len, reason_code);
1807ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1808ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	spin_lock_bh(&local->ap->sta_table_lock);
1809ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	sta = ap_get_sta(local->ap, hdr->addr2);
1810ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (sta != NULL) {
1811ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap)
1812ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			hostap_event_expired_sta(local->dev, sta);
1813ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		sta->flags &= ~WLAN_STA_ASSOC;
1814ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
1815ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	spin_unlock_bh(&local->ap->sta_table_lock);
1816ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (sta == NULL) {
181721f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller		printk("%s: disassociation from " MAC_FMT ", "
1818ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		       "reason_code=%d, but STA not authenticated\n",
181921f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller		       dev->name,
182021f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller		       hdr->addr2[0], hdr->addr2[1], hdr->addr2[2],
182121f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller		       hdr->addr2[3], hdr->addr2[4], hdr->addr2[5],
182221f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller		       reason_code);
1823ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
1824ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen}
1825ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1826ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1827ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen/* Called only as a scheduled task for pending AP frames. */
1828ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenstatic void ap_handle_data_nullfunc(local_info_t *local,
1829d041674d62e1ad565f2fb6d53ae80b31d6656033James Ketrenos				    struct ieee80211_hdr_4addr *hdr)
1830ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{
1831ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	struct net_device *dev = local->dev;
1832ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1833ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	/* some STA f/w's seem to require control::ACK frame for
1834ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	 * data::nullfunc, but at least Prism2 station f/w version 0.8.0 does
1835ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	 * not send this..
1836ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	 * send control::ACK for the data::nullfunc */
1837ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1838ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	printk(KERN_DEBUG "Sending control::ACK for data::nullfunc\n");
18394339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen	prism2_send_mgmt(dev, IEEE80211_FTYPE_CTL | IEEE80211_STYPE_ACK,
1840ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			 NULL, 0, hdr->addr2, 0);
1841ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen}
1842ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1843ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1844ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen/* Called only as a scheduled task for pending AP frames. */
1845ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenstatic void ap_handle_dropped_data(local_info_t *local,
1846d041674d62e1ad565f2fb6d53ae80b31d6656033James Ketrenos				   struct ieee80211_hdr_4addr *hdr)
1847ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{
1848ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	struct net_device *dev = local->dev;
1849ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	struct sta_info *sta;
18508a9faf3cd08b91aca1502dbe18e3b5063fda2e87Al Viro	__le16 reason;
1851ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1852ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	spin_lock_bh(&local->ap->sta_table_lock);
1853ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	sta = ap_get_sta(local->ap, hdr->addr2);
1854ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (sta)
1855ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		atomic_inc(&sta->users);
1856ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	spin_unlock_bh(&local->ap->sta_table_lock);
1857ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1858ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (sta != NULL && (sta->flags & WLAN_STA_ASSOC)) {
1859ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		PDEBUG(DEBUG_AP, "ap_handle_dropped_data: STA is now okay?\n");
1860ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		atomic_dec(&sta->users);
1861ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		return;
1862ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
1863ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
18648a9faf3cd08b91aca1502dbe18e3b5063fda2e87Al Viro	reason = cpu_to_le16(WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA);
18654339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen	prism2_send_mgmt(dev, IEEE80211_FTYPE_MGMT |
1866ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			 ((sta == NULL || !(sta->flags & WLAN_STA_ASSOC)) ?
18674339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen			  IEEE80211_STYPE_DEAUTH : IEEE80211_STYPE_DISASSOC),
1868ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			 (char *) &reason, sizeof(reason), hdr->addr2, 0);
1869ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1870ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (sta)
1871ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		atomic_dec(&sta->users);
1872ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen}
1873ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1874ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
1875ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1876ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1877ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen/* Called only as a scheduled task for pending AP frames. */
1878ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenstatic void pspoll_send_buffered(local_info_t *local, struct sta_info *sta,
1879ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen				 struct sk_buff *skb)
1880ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{
18815bee720fd7fa5ed4eade96058acd3a684da30932Jouni Malinen	struct hostap_skb_tx_data *meta;
18825bee720fd7fa5ed4eade96058acd3a684da30932Jouni Malinen
1883ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (!(sta->flags & WLAN_STA_PS)) {
1884ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		/* Station has moved to non-PS mode, so send all buffered
1885ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		 * frames using normal device queue. */
1886ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		dev_queue_xmit(skb);
1887ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		return;
1888ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
1889ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1890ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	/* add a flag for hostap_handle_sta_tx() to know that this skb should
1891ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	 * be passed through even though STA is using PS */
18925bee720fd7fa5ed4eade96058acd3a684da30932Jouni Malinen	meta = (struct hostap_skb_tx_data *) skb->cb;
18935bee720fd7fa5ed4eade96058acd3a684da30932Jouni Malinen	meta->flags |= HOSTAP_TX_FLAGS_BUFFERED_FRAME;
1894ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (!skb_queue_empty(&sta->tx_buf)) {
1895ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		/* indicate to STA that more frames follow */
18965bee720fd7fa5ed4eade96058acd3a684da30932Jouni Malinen		meta->flags |= HOSTAP_TX_FLAGS_ADD_MOREDATA;
1897ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
1898ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	dev_queue_xmit(skb);
1899ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen}
1900ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1901ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1902ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen/* Called only as a scheduled task for pending AP frames. */
1903ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenstatic void handle_pspoll(local_info_t *local,
1904d041674d62e1ad565f2fb6d53ae80b31d6656033James Ketrenos			  struct ieee80211_hdr_4addr *hdr,
1905ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			  struct hostap_80211_rx_status *rx_stats)
1906ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{
1907ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	struct net_device *dev = local->dev;
1908ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	struct sta_info *sta;
1909ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	u16 aid;
1910ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	struct sk_buff *skb;
1911ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
191221f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller	PDEBUG(DEBUG_PS2, "handle_pspoll: BSSID=" MAC_FMT
191321f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller	       ", TA=" MAC_FMT " PWRMGT=%d\n",
191421f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller	       hdr->addr1[0], hdr->addr1[1], hdr->addr1[2],
191521f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller	       hdr->addr1[3], hdr->addr1[4], hdr->addr1[5],
191621f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller	       hdr->addr2[0], hdr->addr2[1], hdr->addr2[2],
191721f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller	       hdr->addr2[3], hdr->addr2[4], hdr->addr2[5],
1918b2f4a2e3b1620667da9654f9e220c92ea52bdbe4Jouni Malinen	       !!(le16_to_cpu(hdr->frame_ctl) & IEEE80211_FCTL_PM));
1919ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1920ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN)) {
192121f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller		PDEBUG(DEBUG_AP, "handle_pspoll - addr1(BSSID)=" MAC_FMT
192221f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller		       " not own MAC\n",
192321f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller		       hdr->addr1[0], hdr->addr1[1], hdr->addr1[2],
192421f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller		       hdr->addr1[3], hdr->addr1[4], hdr->addr1[5]);
1925ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		return;
1926ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
1927ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
19288a9faf3cd08b91aca1502dbe18e3b5063fda2e87Al Viro	aid = le16_to_cpu(hdr->duration_id);
1929ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if ((aid & (BIT(15) | BIT(14))) != (BIT(15) | BIT(14))) {
1930ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		PDEBUG(DEBUG_PS, "   PSPOLL and AID[15:14] not set\n");
1931ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		return;
1932ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
19331bcca3c463e4930cef9986b05165bb0b3eb46f63Pavel Roskin	aid &= ~(BIT(15) | BIT(14));
1934ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (aid == 0 || aid > MAX_AID_TABLE_SIZE) {
1935ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		PDEBUG(DEBUG_PS, "   invalid aid=%d\n", aid);
1936ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		return;
1937ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
1938ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	PDEBUG(DEBUG_PS2, "   aid=%d\n", aid);
1939ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1940ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	spin_lock_bh(&local->ap->sta_table_lock);
1941ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	sta = ap_get_sta(local->ap, hdr->addr2);
1942ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (sta)
1943ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		atomic_inc(&sta->users);
1944ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	spin_unlock_bh(&local->ap->sta_table_lock);
1945ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1946ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (sta == NULL) {
1947ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		PDEBUG(DEBUG_PS, "   STA not found\n");
1948ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		return;
1949ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
1950ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (sta->aid != aid) {
1951ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		PDEBUG(DEBUG_PS, "   received aid=%i does not match with "
1952ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		       "assoc.aid=%d\n", aid, sta->aid);
1953ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		return;
1954ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
1955ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1956ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	/* FIX: todo:
1957ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	 * - add timeout for buffering (clear aid in TIM vector if buffer timed
1958ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	 *   out (expiry time must be longer than ListenInterval for
1959ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	 *   the corresponding STA; "8802-11: 11.2.1.9 AP aging function"
1960ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	 * - what to do, if buffered, pspolled, and sent frame is not ACKed by
1961ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	 *   sta; store buffer for later use and leave TIM aid bit set? use
1962ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	 *   TX event to check whether frame was ACKed?
1963ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	 */
1964ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1965ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	while ((skb = skb_dequeue(&sta->tx_buf)) != NULL) {
1966ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		/* send buffered frame .. */
1967ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		PDEBUG(DEBUG_PS2, "Sending buffered frame to STA after PS POLL"
1968ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		       " (buffer_count=%d)\n", skb_queue_len(&sta->tx_buf));
1969ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1970ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		pspoll_send_buffered(local, sta, skb);
1971ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1972ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		if (sta->flags & WLAN_STA_PS) {
1973ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			/* send only one buffered packet per PS Poll */
1974ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			/* FIX: should ignore further PS Polls until the
1975ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			 * buffered packet that was just sent is acknowledged
1976ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			 * (Tx or TxExc event) */
1977ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			break;
1978ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		}
1979ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
1980ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1981ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (skb_queue_empty(&sta->tx_buf)) {
1982ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		/* try to clear aid from TIM */
1983ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		if (!(sta->flags & WLAN_STA_TIM))
1984ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			PDEBUG(DEBUG_PS2,  "Re-unsetting TIM for aid %d\n",
1985ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			       aid);
1986ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		hostap_set_tim(local, aid, 0);
1987ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		sta->flags &= ~WLAN_STA_TIM;
1988ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
1989ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1990ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	atomic_dec(&sta->users);
1991ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen}
1992ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1993ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1994ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
1995ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
1996c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howellsstatic void handle_wds_oper_queue(struct work_struct *work)
1997ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{
1998c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howells	struct ap_data *ap = container_of(work, struct ap_data,
1999c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howells					  wds_oper_queue);
2000c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howells	local_info_t *local = ap->local;
2001ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	struct wds_oper_data *entry, *prev;
2002ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2003ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	spin_lock_bh(&local->lock);
2004ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	entry = local->ap->wds_oper_entries;
2005ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	local->ap->wds_oper_entries = NULL;
2006ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	spin_unlock_bh(&local->lock);
2007ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2008ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	while (entry) {
2009ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		PDEBUG(DEBUG_AP, "%s: %s automatic WDS connection "
201021f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller		       "to AP " MAC_FMT "\n",
2011ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		       local->dev->name,
2012ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		       entry->type == WDS_ADD ? "adding" : "removing",
201321f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller		       entry->addr[0], entry->addr[1], entry->addr[2],
201421f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller		       entry->addr[3], entry->addr[4], entry->addr[5]);
2015ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		if (entry->type == WDS_ADD)
2016ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			prism2_wds_add(local, entry->addr, 0);
2017ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		else if (entry->type == WDS_DEL)
2018ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			prism2_wds_del(local, entry->addr, 0, 1);
2019ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2020ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		prev = entry;
2021ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		entry = entry->next;
2022ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		kfree(prev);
2023ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
2024ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen}
2025ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2026ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2027ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen/* Called only as a scheduled task for pending AP frames. */
2028ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenstatic void handle_beacon(local_info_t *local, struct sk_buff *skb,
2029ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			  struct hostap_80211_rx_status *rx_stats)
2030ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{
2031d041674d62e1ad565f2fb6d53ae80b31d6656033James Ketrenos	struct ieee80211_hdr_4addr *hdr = (struct ieee80211_hdr_4addr *) skb->data;
2032ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	char *body = skb->data + IEEE80211_MGMT_HDR_LEN;
2033ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	int len, left;
20348a9faf3cd08b91aca1502dbe18e3b5063fda2e87Al Viro	u16 beacon_int, capability;
20358a9faf3cd08b91aca1502dbe18e3b5063fda2e87Al Viro	__le16 *pos;
2036ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	char *ssid = NULL;
2037ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	unsigned char *supp_rates = NULL;
2038ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	int ssid_len = 0, supp_rates_len = 0;
2039ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	struct sta_info *sta = NULL;
2040ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	int new_sta = 0, channel = -1;
2041ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2042ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	len = skb->len - IEEE80211_MGMT_HDR_LEN;
2043ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2044ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (len < 8 + 2 + 2) {
2045ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		printk(KERN_DEBUG "handle_beacon - too short payload "
2046ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		       "(len=%d)\n", len);
2047ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		return;
2048ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
2049ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
20508a9faf3cd08b91aca1502dbe18e3b5063fda2e87Al Viro	pos = (__le16 *) body;
2051ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	left = len;
2052ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2053ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	/* Timestamp (8 octets) */
2054ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	pos += 4; left -= 8;
2055ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	/* Beacon interval (2 octets) */
20568a9faf3cd08b91aca1502dbe18e3b5063fda2e87Al Viro	beacon_int = le16_to_cpu(*pos);
2057ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	pos++; left -= 2;
2058ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	/* Capability information (2 octets) */
20598a9faf3cd08b91aca1502dbe18e3b5063fda2e87Al Viro	capability = le16_to_cpu(*pos);
2060ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	pos++; left -= 2;
2061ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2062ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (local->ap->ap_policy != AP_OTHER_AP_EVEN_IBSS &&
2063ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	    capability & WLAN_CAPABILITY_IBSS)
2064ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		return;
2065ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2066ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (left >= 2) {
2067ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		unsigned int ileft;
2068ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		unsigned char *u = (unsigned char *) pos;
2069ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2070ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		if (*u == WLAN_EID_SSID) {
2071ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			u++; left--;
2072ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			ileft = *u;
2073ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			u++; left--;
2074ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2075ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			if (ileft > left || ileft > MAX_SSID_LEN) {
2076ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen				PDEBUG(DEBUG_AP, "SSID: overflow\n");
2077ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen				return;
2078ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			}
2079ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2080ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			if (local->ap->ap_policy == AP_OTHER_AP_SAME_SSID &&
2081ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			    (ileft != strlen(local->essid) ||
2082ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			     memcmp(local->essid, u, ileft) != 0)) {
2083ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen				/* not our SSID */
2084ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen				return;
2085ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			}
2086ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2087ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			ssid = u;
2088ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			ssid_len = ileft;
2089ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2090ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			u += ileft;
2091ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			left -= ileft;
2092ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		}
2093ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2094ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		if (*u == WLAN_EID_SUPP_RATES) {
2095ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			u++; left--;
2096ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			ileft = *u;
2097ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			u++; left--;
209874fae82c8bd5dd78365abe25506a9ba388d4a889Jeff Garzik
2099ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			if (ileft > left || ileft == 0 || ileft > 8) {
2100ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen				PDEBUG(DEBUG_AP, " - SUPP_RATES len error\n");
2101ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen				return;
2102ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			}
2103ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2104ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			supp_rates = u;
2105ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			supp_rates_len = ileft;
2106ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2107ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			u += ileft;
2108ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			left -= ileft;
2109ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		}
2110ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2111ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		if (*u == WLAN_EID_DS_PARAMS) {
2112ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			u++; left--;
2113ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			ileft = *u;
2114ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			u++; left--;
211574fae82c8bd5dd78365abe25506a9ba388d4a889Jeff Garzik
2116ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			if (ileft > left || ileft != 1) {
2117ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen				PDEBUG(DEBUG_AP, " - DS_PARAMS len error\n");
2118ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen				return;
2119ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			}
2120ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2121ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			channel = *u;
2122ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2123ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			u += ileft;
2124ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			left -= ileft;
2125ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		}
2126ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
2127ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2128ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	spin_lock_bh(&local->ap->sta_table_lock);
2129ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	sta = ap_get_sta(local->ap, hdr->addr2);
2130ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (sta != NULL)
2131ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		atomic_inc(&sta->users);
2132ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	spin_unlock_bh(&local->ap->sta_table_lock);
2133ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2134ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (sta == NULL) {
2135ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		/* add new AP */
2136ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		new_sta = 1;
2137ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		sta = ap_add_sta(local->ap, hdr->addr2);
2138ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		if (sta == NULL) {
2139ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			printk(KERN_INFO "prism2: kmalloc failed for AP "
2140ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			       "data structure\n");
2141ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			return;
2142ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		}
2143ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		hostap_event_new_sta(local->dev, sta);
2144ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2145ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		/* mark APs authentication and associated for pseudo ad-hoc
2146ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		 * style communication */
2147ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		sta->flags = WLAN_STA_AUTH | WLAN_STA_ASSOC;
2148ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2149ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		if (local->ap->autom_ap_wds) {
2150ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			hostap_wds_link_oper(local, sta->addr, WDS_ADD);
2151ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		}
2152ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
2153ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2154ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	sta->ap = 1;
2155ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (ssid) {
2156ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		sta->u.ap.ssid_len = ssid_len;
2157ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		memcpy(sta->u.ap.ssid, ssid, ssid_len);
2158ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		sta->u.ap.ssid[ssid_len] = '\0';
2159ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	} else {
2160ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		sta->u.ap.ssid_len = 0;
2161ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		sta->u.ap.ssid[0] = '\0';
2162ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
2163ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	sta->u.ap.channel = channel;
2164ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	sta->rx_packets++;
2165ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	sta->rx_bytes += len;
2166ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	sta->u.ap.last_beacon = sta->last_rx = jiffies;
2167ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	sta->capability = capability;
2168ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	sta->listen_interval = beacon_int;
2169ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2170ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	atomic_dec(&sta->users);
2171ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2172ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (new_sta) {
2173ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		memset(sta->supported_rates, 0, sizeof(sta->supported_rates));
2174ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		memcpy(sta->supported_rates, supp_rates, supp_rates_len);
2175ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		prism2_check_tx_rates(sta);
2176ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
2177ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen}
2178ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2179ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
2180ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2181ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2182ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen/* Called only as a tasklet. */
2183ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenstatic void handle_ap_item(local_info_t *local, struct sk_buff *skb,
2184ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			   struct hostap_80211_rx_status *rx_stats)
2185ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{
2186ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
2187ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	struct net_device *dev = local->dev;
2188ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
2189ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	u16 fc, type, stype;
2190d041674d62e1ad565f2fb6d53ae80b31d6656033James Ketrenos	struct ieee80211_hdr_4addr *hdr;
2191ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2192ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	/* FIX: should give skb->len to handler functions and check that the
2193ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	 * buffer is long enough */
2194d041674d62e1ad565f2fb6d53ae80b31d6656033James Ketrenos	hdr = (struct ieee80211_hdr_4addr *) skb->data;
2195c0f72ca8e4f1b459b5582c1c8dcaf7e53151f069Jouni Malinen	fc = le16_to_cpu(hdr->frame_ctl);
21964339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen	type = WLAN_FC_GET_TYPE(fc);
21974339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen	stype = WLAN_FC_GET_STYPE(fc);
2198ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2199ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
22004339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen	if (!local->hostapd && type == IEEE80211_FTYPE_DATA) {
2201ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		PDEBUG(DEBUG_AP, "handle_ap_item - data frame\n");
2202ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2203b2f4a2e3b1620667da9654f9e220c92ea52bdbe4Jouni Malinen		if (!(fc & IEEE80211_FCTL_TODS) ||
2204b2f4a2e3b1620667da9654f9e220c92ea52bdbe4Jouni Malinen		    (fc & IEEE80211_FCTL_FROMDS)) {
22054339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen			if (stype == IEEE80211_STYPE_NULLFUNC) {
2206ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen				/* no ToDS nullfunc seems to be used to check
2207ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen				 * AP association; so send reject message to
2208ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen				 * speed up re-association */
2209ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen				ap_handle_dropped_data(local, hdr);
2210ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen				goto done;
2211ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			}
2212ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			PDEBUG(DEBUG_AP, "   not ToDS frame (fc=0x%04x)\n",
2213ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			       fc);
2214ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			goto done;
2215ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		}
2216ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2217ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		if (memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN)) {
2218ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			PDEBUG(DEBUG_AP, "handle_ap_item - addr1(BSSID)="
221921f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller			       MAC_FMT " not own MAC\n",
222021f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller			       hdr->addr1[0], hdr->addr1[1], hdr->addr1[2],
222121f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller			       hdr->addr1[3], hdr->addr1[4], hdr->addr1[5]);
2222ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			goto done;
2223ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		}
2224ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
22254339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen		if (local->ap->nullfunc_ack &&
22264339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen		    stype == IEEE80211_STYPE_NULLFUNC)
2227ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			ap_handle_data_nullfunc(local, hdr);
2228ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		else
2229ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			ap_handle_dropped_data(local, hdr);
2230ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		goto done;
2231ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
2232ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
22334339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen	if (type == IEEE80211_FTYPE_MGMT && stype == IEEE80211_STYPE_BEACON) {
2234ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		handle_beacon(local, skb, rx_stats);
2235ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		goto done;
2236ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
2237ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
2238ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
22394339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen	if (type == IEEE80211_FTYPE_CTL && stype == IEEE80211_STYPE_PSPOLL) {
2240ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		handle_pspoll(local, hdr, rx_stats);
2241ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		goto done;
2242ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
2243ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2244ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (local->hostapd) {
2245ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		PDEBUG(DEBUG_AP, "Unknown frame in AP queue: type=0x%02x "
2246ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		       "subtype=0x%02x\n", type, stype);
2247ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		goto done;
2248ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
2249ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2250ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
22514339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen	if (type != IEEE80211_FTYPE_MGMT) {
2252ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		PDEBUG(DEBUG_AP, "handle_ap_item - not a management frame?\n");
2253ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		goto done;
2254ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
2255ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2256ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN)) {
225721f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller		PDEBUG(DEBUG_AP, "handle_ap_item - addr1(DA)=" MAC_FMT
225821f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller		       " not own MAC\n",
225921f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller		       hdr->addr1[0], hdr->addr1[1], hdr->addr1[2],
226021f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller		       hdr->addr1[3], hdr->addr1[4], hdr->addr1[5]);
2261ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		goto done;
2262ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
2263ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2264ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (memcmp(hdr->addr3, dev->dev_addr, ETH_ALEN)) {
226521f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller		PDEBUG(DEBUG_AP, "handle_ap_item - addr3(BSSID)=" MAC_FMT
226621f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller		       " not own MAC\n",
226721f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller		       hdr->addr3[0], hdr->addr3[1], hdr->addr3[2],
226821f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller		       hdr->addr3[3], hdr->addr3[4], hdr->addr3[5]);
2269ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		goto done;
2270ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
2271ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2272ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	switch (stype) {
22734339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen	case IEEE80211_STYPE_ASSOC_REQ:
2274ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		handle_assoc(local, skb, rx_stats, 0);
2275ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		break;
22764339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen	case IEEE80211_STYPE_ASSOC_RESP:
2277ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		PDEBUG(DEBUG_AP, "==> ASSOC RESP (ignored)\n");
2278ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		break;
22794339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen	case IEEE80211_STYPE_REASSOC_REQ:
2280ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		handle_assoc(local, skb, rx_stats, 1);
2281ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		break;
22824339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen	case IEEE80211_STYPE_REASSOC_RESP:
2283ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		PDEBUG(DEBUG_AP, "==> REASSOC RESP (ignored)\n");
2284ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		break;
22854339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen	case IEEE80211_STYPE_ATIM:
2286ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		PDEBUG(DEBUG_AP, "==> ATIM (ignored)\n");
2287ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		break;
22884339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen	case IEEE80211_STYPE_DISASSOC:
2289ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		handle_disassoc(local, skb, rx_stats);
2290ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		break;
22914339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen	case IEEE80211_STYPE_AUTH:
2292ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		handle_authen(local, skb, rx_stats);
2293ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		break;
22944339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen	case IEEE80211_STYPE_DEAUTH:
2295ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		handle_deauth(local, skb, rx_stats);
2296ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		break;
2297ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	default:
22984339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen		PDEBUG(DEBUG_AP, "Unknown mgmt frame subtype 0x%02x\n",
22994339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen		       stype >> 4);
2300ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		break;
2301ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
2302ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
2303ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2304ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen done:
2305ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	dev_kfree_skb(skb);
2306ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen}
2307ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2308ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2309ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen/* Called only as a tasklet (software IRQ) */
2310ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenvoid hostap_rx(struct net_device *dev, struct sk_buff *skb,
2311ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	       struct hostap_80211_rx_status *rx_stats)
2312ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{
2313ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	struct hostap_interface *iface;
2314ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	local_info_t *local;
2315ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	u16 fc;
2316d041674d62e1ad565f2fb6d53ae80b31d6656033James Ketrenos	struct ieee80211_hdr_4addr *hdr;
2317ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2318ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	iface = netdev_priv(dev);
2319ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	local = iface->local;
2320ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2321ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (skb->len < 16)
2322ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		goto drop;
2323ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2324ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	local->stats.rx_packets++;
2325ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2326d041674d62e1ad565f2fb6d53ae80b31d6656033James Ketrenos	hdr = (struct ieee80211_hdr_4addr *) skb->data;
2327c0f72ca8e4f1b459b5582c1c8dcaf7e53151f069Jouni Malinen	fc = le16_to_cpu(hdr->frame_ctl);
2328ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2329ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (local->ap->ap_policy == AP_OTHER_AP_SKIP_ALL &&
23304339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen	    WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_MGMT &&
23314339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen	    WLAN_FC_GET_STYPE(fc) == IEEE80211_STYPE_BEACON)
2332ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		goto drop;
2333ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2334ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	skb->protocol = __constant_htons(ETH_P_HOSTAP);
2335ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	handle_ap_item(local, skb, rx_stats);
2336ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	return;
2337ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2338ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen drop:
2339ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	dev_kfree_skb(skb);
2340ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen}
2341ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2342ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2343ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen/* Called only as a tasklet (software IRQ) */
2344ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenstatic void schedule_packet_send(local_info_t *local, struct sta_info *sta)
2345ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{
2346ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	struct sk_buff *skb;
2347d041674d62e1ad565f2fb6d53ae80b31d6656033James Ketrenos	struct ieee80211_hdr_4addr *hdr;
2348ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	struct hostap_80211_rx_status rx_stats;
2349ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2350ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (skb_queue_empty(&sta->tx_buf))
2351ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		return;
2352ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2353ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	skb = dev_alloc_skb(16);
2354ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (skb == NULL) {
2355ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		printk(KERN_DEBUG "%s: schedule_packet_send: skb alloc "
2356ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		       "failed\n", local->dev->name);
2357ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		return;
2358ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
2359ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2360d041674d62e1ad565f2fb6d53ae80b31d6656033James Ketrenos	hdr = (struct ieee80211_hdr_4addr *) skb_put(skb, 16);
2361ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2362ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	/* Generate a fake pspoll frame to start packet delivery */
2363c0f72ca8e4f1b459b5582c1c8dcaf7e53151f069Jouni Malinen	hdr->frame_ctl = __constant_cpu_to_le16(
23644339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen		IEEE80211_FTYPE_CTL | IEEE80211_STYPE_PSPOLL);
2365ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	memcpy(hdr->addr1, local->dev->dev_addr, ETH_ALEN);
2366ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	memcpy(hdr->addr2, sta->addr, ETH_ALEN);
2367ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	hdr->duration_id = cpu_to_le16(sta->aid | BIT(15) | BIT(14));
2368ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
23690795af5729b18218767fab27c44b1384f72dc9adJoe Perches	PDEBUG(DEBUG_PS2, "%s: Scheduling buffered packet delivery for STA "
237021f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller	       MAC_FMT "\n", local->dev->name,
237121f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller	       sta->addr[0], sta->addr[1], sta->addr[2],
237221f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller	       sta->addr[3], sta->addr[4], sta->addr[5]);
2373ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2374ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	skb->dev = local->dev;
2375ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2376ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	memset(&rx_stats, 0, sizeof(rx_stats));
2377ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	hostap_rx(local->dev, skb, &rx_stats);
2378ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen}
2379ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2380ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
23815fad5a2e1f34b333a801b749c4e143c2ac3e8a4fAdrian Bunkint prism2_ap_get_sta_qual(local_info_t *local, struct sockaddr addr[],
23825fad5a2e1f34b333a801b749c4e143c2ac3e8a4fAdrian Bunk			   struct iw_quality qual[], int buf_size,
23835fad5a2e1f34b333a801b749c4e143c2ac3e8a4fAdrian Bunk			   int aplist)
2384ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{
2385ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	struct ap_data *ap = local->ap;
2386ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	struct list_head *ptr;
2387ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	int count = 0;
2388ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2389ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	spin_lock_bh(&ap->sta_table_lock);
2390ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2391ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	for (ptr = ap->sta_list.next; ptr != NULL && ptr != &ap->sta_list;
2392ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	     ptr = ptr->next) {
2393ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		struct sta_info *sta = (struct sta_info *) ptr;
2394ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2395ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		if (aplist && !sta->ap)
2396ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			continue;
2397ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		addr[count].sa_family = ARPHRD_ETHER;
2398ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		memcpy(addr[count].sa_data, sta->addr, ETH_ALEN);
2399ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		if (sta->last_rx_silence == 0)
2400ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			qual[count].qual = sta->last_rx_signal < 27 ?
2401ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen				0 : (sta->last_rx_signal - 27) * 92 / 127;
2402ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		else
2403ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			qual[count].qual = sta->last_rx_signal -
2404ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen				sta->last_rx_silence - 35;
2405ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		qual[count].level = HFA384X_LEVEL_TO_dBm(sta->last_rx_signal);
2406ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		qual[count].noise = HFA384X_LEVEL_TO_dBm(sta->last_rx_silence);
2407ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		qual[count].updated = sta->last_rx_updated;
2408ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2409c28df16ed70d1b6cefd12135e3c68bfccd1bb635Jean Tourrilhes		sta->last_rx_updated = IW_QUAL_DBM;
2410ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2411ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		count++;
2412ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		if (count >= buf_size)
2413ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			break;
2414ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
2415ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	spin_unlock_bh(&ap->sta_table_lock);
2416ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2417ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	return count;
2418ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen}
2419ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2420ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2421ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen/* Translate our list of Access Points & Stations to a card independant
2422ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * format that the Wireless Tools will understand - Jean II */
24235fad5a2e1f34b333a801b749c4e143c2ac3e8a4fAdrian Bunkint prism2_ap_translate_scan(struct net_device *dev, char *buffer)
2424ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{
2425ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	struct hostap_interface *iface;
2426ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	local_info_t *local;
2427ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	struct ap_data *ap;
2428ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	struct list_head *ptr;
2429ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	struct iw_event iwe;
2430ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	char *current_ev = buffer;
2431ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	char *end_buf = buffer + IW_SCAN_MAX_DATA;
2432ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#if !defined(PRISM2_NO_KERNEL_IEEE80211_MGMT)
2433ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	char buf[64];
2434ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#endif
2435ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2436ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	iface = netdev_priv(dev);
2437ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	local = iface->local;
2438ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	ap = local->ap;
2439ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2440ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	spin_lock_bh(&ap->sta_table_lock);
2441ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2442ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	for (ptr = ap->sta_list.next; ptr != NULL && ptr != &ap->sta_list;
2443ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	     ptr = ptr->next) {
2444ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		struct sta_info *sta = (struct sta_info *) ptr;
2445ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2446ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		/* First entry *MUST* be the AP MAC address */
2447ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		memset(&iwe, 0, sizeof(iwe));
2448ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		iwe.cmd = SIOCGIWAP;
2449ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
2450ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		memcpy(iwe.u.ap_addr.sa_data, sta->addr, ETH_ALEN);
2451ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		iwe.len = IW_EV_ADDR_LEN;
2452ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
2453ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen						  IW_EV_ADDR_LEN);
2454ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2455ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		/* Use the mode to indicate if it's a station or
2456ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		 * an Access Point */
2457ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		memset(&iwe, 0, sizeof(iwe));
2458ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		iwe.cmd = SIOCGIWMODE;
2459ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		if (sta->ap)
2460ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			iwe.u.mode = IW_MODE_MASTER;
2461ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		else
2462ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			iwe.u.mode = IW_MODE_INFRA;
2463ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		iwe.len = IW_EV_UINT_LEN;
2464ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
2465ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen						  IW_EV_UINT_LEN);
2466ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2467ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		/* Some quality */
2468ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		memset(&iwe, 0, sizeof(iwe));
2469ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		iwe.cmd = IWEVQUAL;
2470ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		if (sta->last_rx_silence == 0)
2471ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			iwe.u.qual.qual = sta->last_rx_signal < 27 ?
2472ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen				0 : (sta->last_rx_signal - 27) * 92 / 127;
2473ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		else
2474ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			iwe.u.qual.qual = sta->last_rx_signal -
2475ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen				sta->last_rx_silence - 35;
2476ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		iwe.u.qual.level = HFA384X_LEVEL_TO_dBm(sta->last_rx_signal);
2477ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		iwe.u.qual.noise = HFA384X_LEVEL_TO_dBm(sta->last_rx_silence);
2478ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		iwe.u.qual.updated = sta->last_rx_updated;
2479ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		iwe.len = IW_EV_QUAL_LEN;
2480ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
2481ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen						  IW_EV_QUAL_LEN);
2482ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2483ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
2484ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		if (sta->ap) {
2485ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			memset(&iwe, 0, sizeof(iwe));
2486ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			iwe.cmd = SIOCGIWESSID;
2487ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			iwe.u.data.length = sta->u.ap.ssid_len;
2488ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			iwe.u.data.flags = 1;
2489ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			current_ev = iwe_stream_add_point(current_ev, end_buf,
2490ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen							  &iwe,
2491ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen							  sta->u.ap.ssid);
2492ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2493ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			memset(&iwe, 0, sizeof(iwe));
2494ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			iwe.cmd = SIOCGIWENCODE;
2495ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			if (sta->capability & WLAN_CAPABILITY_PRIVACY)
2496ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen				iwe.u.data.flags =
2497ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen					IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
2498ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			else
2499ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen				iwe.u.data.flags = IW_ENCODE_DISABLED;
2500ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			current_ev = iwe_stream_add_point(current_ev, end_buf,
2501ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen							  &iwe,
2502ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen							  sta->u.ap.ssid
2503ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen							  /* 0 byte memcpy */);
2504ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2505ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			if (sta->u.ap.channel > 0 &&
2506ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			    sta->u.ap.channel <= FREQ_COUNT) {
2507ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen				memset(&iwe, 0, sizeof(iwe));
2508ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen				iwe.cmd = SIOCGIWFREQ;
2509ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen				iwe.u.freq.m = freq_list[sta->u.ap.channel - 1]
2510ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen					* 100000;
2511ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen				iwe.u.freq.e = 1;
2512ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen				current_ev = iwe_stream_add_event(
2513ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen					current_ev, end_buf, &iwe,
2514ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen					IW_EV_FREQ_LEN);
2515ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			}
2516ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2517ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			memset(&iwe, 0, sizeof(iwe));
2518ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			iwe.cmd = IWEVCUSTOM;
2519ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			sprintf(buf, "beacon_interval=%d",
2520ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen				sta->listen_interval);
2521ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			iwe.u.data.length = strlen(buf);
2522ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			current_ev = iwe_stream_add_point(current_ev, end_buf,
2523ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen							  &iwe, buf);
2524ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		}
2525ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
2526ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2527c28df16ed70d1b6cefd12135e3c68bfccd1bb635Jean Tourrilhes		sta->last_rx_updated = IW_QUAL_DBM;
2528ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2529ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		/* To be continued, we should make good use of IWEVCUSTOM */
2530ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
2531ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2532ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	spin_unlock_bh(&ap->sta_table_lock);
2533ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2534ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	return current_ev - buffer;
2535ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen}
2536ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2537ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2538ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenstatic int prism2_hostapd_add_sta(struct ap_data *ap,
2539ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen				  struct prism2_hostapd_param *param)
2540ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{
2541ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	struct sta_info *sta;
2542ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2543ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	spin_lock_bh(&ap->sta_table_lock);
2544ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	sta = ap_get_sta(ap, param->sta_addr);
2545ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (sta)
2546ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		atomic_inc(&sta->users);
2547ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	spin_unlock_bh(&ap->sta_table_lock);
2548ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2549ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (sta == NULL) {
2550ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		sta = ap_add_sta(ap, param->sta_addr);
2551ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		if (sta == NULL)
2552ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			return -1;
2553ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
2554ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2555ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (!(sta->flags & WLAN_STA_ASSOC) && !sta->ap && sta->local)
2556ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		hostap_event_new_sta(sta->local->dev, sta);
2557ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2558ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC;
2559ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	sta->last_rx = jiffies;
2560ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	sta->aid = param->u.add_sta.aid;
2561ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	sta->capability = param->u.add_sta.capability;
2562ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	sta->tx_supp_rates = param->u.add_sta.tx_supp_rates;
2563ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (sta->tx_supp_rates & WLAN_RATE_1M)
2564ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		sta->supported_rates[0] = 2;
2565ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (sta->tx_supp_rates & WLAN_RATE_2M)
2566ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		sta->supported_rates[1] = 4;
2567ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 	if (sta->tx_supp_rates & WLAN_RATE_5M5)
2568ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		sta->supported_rates[2] = 11;
2569ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (sta->tx_supp_rates & WLAN_RATE_11M)
2570ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		sta->supported_rates[3] = 22;
2571ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	prism2_check_tx_rates(sta);
2572ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	atomic_dec(&sta->users);
2573ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	return 0;
2574ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen}
2575ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2576ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2577ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenstatic int prism2_hostapd_remove_sta(struct ap_data *ap,
2578ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen				     struct prism2_hostapd_param *param)
2579ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{
2580ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	struct sta_info *sta;
2581ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2582ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	spin_lock_bh(&ap->sta_table_lock);
2583ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	sta = ap_get_sta(ap, param->sta_addr);
2584ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (sta) {
2585ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		ap_sta_hash_del(ap, sta);
2586ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		list_del(&sta->list);
2587ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
2588ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	spin_unlock_bh(&ap->sta_table_lock);
2589ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2590ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (!sta)
2591ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		return -ENOENT;
2592ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2593ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap && sta->local)
2594ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		hostap_event_expired_sta(sta->local->dev, sta);
2595ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	ap_free_sta(ap, sta);
2596ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2597ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	return 0;
2598ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen}
2599ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2600ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2601ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenstatic int prism2_hostapd_get_info_sta(struct ap_data *ap,
2602ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen				       struct prism2_hostapd_param *param)
2603ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{
2604ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	struct sta_info *sta;
2605ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2606ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	spin_lock_bh(&ap->sta_table_lock);
2607ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	sta = ap_get_sta(ap, param->sta_addr);
2608ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (sta)
2609ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		atomic_inc(&sta->users);
2610ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	spin_unlock_bh(&ap->sta_table_lock);
2611ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2612ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (!sta)
2613ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		return -ENOENT;
2614ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2615ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	param->u.get_info_sta.inactive_sec = (jiffies - sta->last_rx) / HZ;
2616ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2617ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	atomic_dec(&sta->users);
2618ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2619ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	return 1;
2620ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen}
2621ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2622ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2623ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenstatic int prism2_hostapd_set_flags_sta(struct ap_data *ap,
2624ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen					struct prism2_hostapd_param *param)
2625ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{
2626ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	struct sta_info *sta;
2627ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2628ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	spin_lock_bh(&ap->sta_table_lock);
2629ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	sta = ap_get_sta(ap, param->sta_addr);
2630ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (sta) {
2631ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		sta->flags |= param->u.set_flags_sta.flags_or;
2632ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		sta->flags &= param->u.set_flags_sta.flags_and;
2633ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
2634ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	spin_unlock_bh(&ap->sta_table_lock);
2635ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2636ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (!sta)
2637ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		return -ENOENT;
2638ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2639ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	return 0;
2640ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen}
2641ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2642ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2643ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenstatic int prism2_hostapd_sta_clear_stats(struct ap_data *ap,
2644ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen					  struct prism2_hostapd_param *param)
2645ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{
2646ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	struct sta_info *sta;
2647ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	int rate;
2648ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2649ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	spin_lock_bh(&ap->sta_table_lock);
2650ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	sta = ap_get_sta(ap, param->sta_addr);
2651ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (sta) {
2652ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		sta->rx_packets = sta->tx_packets = 0;
2653ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		sta->rx_bytes = sta->tx_bytes = 0;
2654ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		for (rate = 0; rate < WLAN_RATE_COUNT; rate++) {
2655ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			sta->tx_count[rate] = 0;
2656ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			sta->rx_count[rate] = 0;
2657ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		}
2658ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
2659ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	spin_unlock_bh(&ap->sta_table_lock);
2660ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2661ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (!sta)
2662ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		return -ENOENT;
2663ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2664ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	return 0;
2665ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen}
2666ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2667ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
26685fad5a2e1f34b333a801b749c4e143c2ac3e8a4fAdrian Bunkint prism2_hostapd(struct ap_data *ap, struct prism2_hostapd_param *param)
2669ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{
2670ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	switch (param->cmd) {
2671ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	case PRISM2_HOSTAPD_FLUSH:
2672ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		ap_control_kickall(ap);
2673ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		return 0;
2674ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	case PRISM2_HOSTAPD_ADD_STA:
2675ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		return prism2_hostapd_add_sta(ap, param);
2676ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	case PRISM2_HOSTAPD_REMOVE_STA:
2677ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		return prism2_hostapd_remove_sta(ap, param);
2678ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	case PRISM2_HOSTAPD_GET_INFO_STA:
2679ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		return prism2_hostapd_get_info_sta(ap, param);
2680ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	case PRISM2_HOSTAPD_SET_FLAGS_STA:
2681ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		return prism2_hostapd_set_flags_sta(ap, param);
2682ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	case PRISM2_HOSTAPD_STA_CLEAR_STATS:
2683ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		return prism2_hostapd_sta_clear_stats(ap, param);
2684ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	default:
2685ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		printk(KERN_WARNING "prism2_hostapd: unknown cmd=%d\n",
2686ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		       param->cmd);
2687ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		return -EOPNOTSUPP;
2688ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
2689ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen}
2690ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2691ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2692ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen/* Update station info for host-based TX rate control and return current
2693ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * TX rate */
2694ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenstatic int ap_update_sta_tx_rate(struct sta_info *sta, struct net_device *dev)
2695ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{
2696ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	int ret = sta->tx_rate;
2697ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	struct hostap_interface *iface;
2698ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	local_info_t *local;
2699ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2700ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	iface = netdev_priv(dev);
2701ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	local = iface->local;
2702ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2703ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	sta->tx_count[sta->tx_rate_idx]++;
2704ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	sta->tx_since_last_failure++;
2705ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	sta->tx_consecutive_exc = 0;
2706ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (sta->tx_since_last_failure >= WLAN_RATE_UPDATE_COUNT &&
2707ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	    sta->tx_rate_idx < sta->tx_max_rate) {
2708ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		/* use next higher rate */
2709ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		int old_rate, new_rate;
2710ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		old_rate = new_rate = sta->tx_rate_idx;
2711ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		while (new_rate < sta->tx_max_rate) {
2712ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			new_rate++;
2713ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			if (ap_tx_rate_ok(new_rate, sta, local)) {
2714ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen				sta->tx_rate_idx = new_rate;
2715ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen				break;
2716ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			}
2717ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		}
2718ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		if (old_rate != sta->tx_rate_idx) {
2719ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			switch (sta->tx_rate_idx) {
2720ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			case 0: sta->tx_rate = 10; break;
2721ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			case 1: sta->tx_rate = 20; break;
2722ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			case 2: sta->tx_rate = 55; break;
2723ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			case 3: sta->tx_rate = 110; break;
2724ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			default: sta->tx_rate = 0; break;
2725ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			}
272621f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller			PDEBUG(DEBUG_AP, "%s: STA " MAC_FMT
27270795af5729b18218767fab27c44b1384f72dc9adJoe Perches			       " TX rate raised to %d\n",
272821f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller			       dev->name,
272921f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller			       sta->addr[0], sta->addr[1], sta->addr[2],
273021f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller			       sta->addr[3], sta->addr[4], sta->addr[5],
273121f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller			       sta->tx_rate);
2732ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		}
2733ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		sta->tx_since_last_failure = 0;
2734ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
2735ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2736ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	return ret;
2737ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen}
2738ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2739ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2740ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen/* Called only from software IRQ. Called for each TX frame prior possible
2741ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * encryption and transmit. */
2742ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenap_tx_ret hostap_handle_sta_tx(local_info_t *local, struct hostap_tx_data *tx)
2743ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{
2744ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	struct sta_info *sta = NULL;
2745ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	struct sk_buff *skb = tx->skb;
2746ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	int set_tim, ret;
2747d041674d62e1ad565f2fb6d53ae80b31d6656033James Ketrenos	struct ieee80211_hdr_4addr *hdr;
2748ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	struct hostap_skb_tx_data *meta;
2749ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2750ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	meta = (struct hostap_skb_tx_data *) skb->cb;
2751ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	ret = AP_TX_CONTINUE;
2752ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (local->ap == NULL || skb->len < 10 ||
2753ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	    meta->iface->type == HOSTAP_INTERFACE_STA)
2754ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		goto out;
2755ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2756d041674d62e1ad565f2fb6d53ae80b31d6656033James Ketrenos	hdr = (struct ieee80211_hdr_4addr *) skb->data;
2757ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2758ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (hdr->addr1[0] & 0x01) {
2759ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		/* broadcast/multicast frame - no AP related processing */
2760b918099030fe6cc093a7d60a88039bd98f16538ePavel Roskin		if (local->ap->num_sta <= 0)
2761b918099030fe6cc093a7d60a88039bd98f16538ePavel Roskin			ret = AP_TX_DROP;
2762ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		goto out;
2763ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
2764ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2765ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	/* unicast packet - check whether destination STA is associated */
2766ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	spin_lock(&local->ap->sta_table_lock);
2767ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	sta = ap_get_sta(local->ap, hdr->addr1);
2768ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (sta)
2769ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		atomic_inc(&sta->users);
2770ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	spin_unlock(&local->ap->sta_table_lock);
2771ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
27725bee720fd7fa5ed4eade96058acd3a684da30932Jouni Malinen	if (local->iw_mode == IW_MODE_MASTER && sta == NULL &&
27735bee720fd7fa5ed4eade96058acd3a684da30932Jouni Malinen	    !(meta->flags & HOSTAP_TX_FLAGS_WDS) &&
2774ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	    meta->iface->type != HOSTAP_INTERFACE_MASTER &&
2775ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	    meta->iface->type != HOSTAP_INTERFACE_AP) {
2776ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#if 0
2777ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		/* This can happen, e.g., when wlan0 is added to a bridge and
2778ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		 * bridging code does not know which port is the correct target
2779ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		 * for a unicast frame. In this case, the packet is send to all
2780ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		 * ports of the bridge. Since this is a valid scenario, do not
2781ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		 * print out any errors here. */
2782ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		if (net_ratelimit()) {
2783ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			printk(KERN_DEBUG "AP: drop packet to non-associated "
278421f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller			       "STA " MAC_FMT "\n",
278521f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller			       hdr->addr1[0], hdr->addr1[1], hdr->addr1[2],
278621f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller			       hdr->addr1[3], hdr->addr1[4], hdr->addr1[5]);
2787ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		}
2788ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#endif
2789ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		local->ap->tx_drop_nonassoc++;
2790ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		ret = AP_TX_DROP;
2791ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		goto out;
2792ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
2793ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2794ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (sta == NULL)
2795ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		goto out;
2796ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2797ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (!(sta->flags & WLAN_STA_AUTHORIZED))
2798ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		ret = AP_TX_CONTINUE_NOT_AUTHORIZED;
2799ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2800ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	/* Set tx_rate if using host-based TX rate control */
2801ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (!local->fw_tx_rate_control)
2802ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		local->ap->last_tx_rate = meta->rate =
2803ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			ap_update_sta_tx_rate(sta, local->dev);
2804ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2805ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (local->iw_mode != IW_MODE_MASTER)
2806ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		goto out;
2807ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2808ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (!(sta->flags & WLAN_STA_PS))
2809ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		goto out;
2810ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
28115bee720fd7fa5ed4eade96058acd3a684da30932Jouni Malinen	if (meta->flags & HOSTAP_TX_FLAGS_ADD_MOREDATA) {
28125bee720fd7fa5ed4eade96058acd3a684da30932Jouni Malinen		/* indicate to STA that more frames follow */
2813b2f4a2e3b1620667da9654f9e220c92ea52bdbe4Jouni Malinen		hdr->frame_ctl |=
2814b2f4a2e3b1620667da9654f9e220c92ea52bdbe4Jouni Malinen			__constant_cpu_to_le16(IEEE80211_FCTL_MOREDATA);
28155bee720fd7fa5ed4eade96058acd3a684da30932Jouni Malinen	}
2816ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
28175bee720fd7fa5ed4eade96058acd3a684da30932Jouni Malinen	if (meta->flags & HOSTAP_TX_FLAGS_BUFFERED_FRAME) {
28185bee720fd7fa5ed4eade96058acd3a684da30932Jouni Malinen		/* packet was already buffered and now send due to
28195bee720fd7fa5ed4eade96058acd3a684da30932Jouni Malinen		 * PS poll, so do not rebuffer it */
28205bee720fd7fa5ed4eade96058acd3a684da30932Jouni Malinen		goto out;
2821ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
2822ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2823ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (skb_queue_len(&sta->tx_buf) >= STA_MAX_TX_BUFFER) {
282421f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller		PDEBUG(DEBUG_PS, "%s: No more space in STA (" MAC_FMT
28250795af5729b18218767fab27c44b1384f72dc9adJoe Perches		       ")'s PS mode buffer\n",
282621f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller		       local->dev->name,
282721f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller		       sta->addr[0], sta->addr[1], sta->addr[2],
282821f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller		       sta->addr[3], sta->addr[4], sta->addr[5]);
2829ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		/* Make sure that TIM is set for the station (it might not be
2830ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		 * after AP wlan hw reset). */
2831ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		/* FIX: should fix hw reset to restore bits based on STA
2832ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		 * buffer state.. */
2833ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		hostap_set_tim(local, sta->aid, 1);
2834ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		sta->flags |= WLAN_STA_TIM;
2835ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		ret = AP_TX_DROP;
2836ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		goto out;
2837ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
2838ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2839ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	/* STA in PS mode, buffer frame for later delivery */
2840ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	set_tim = skb_queue_empty(&sta->tx_buf);
2841ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	skb_queue_tail(&sta->tx_buf, skb);
2842ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	/* FIX: could save RX time to skb and expire buffered frames after
2843ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	 * some time if STA does not poll for them */
2844ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2845ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (set_tim) {
2846ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		if (sta->flags & WLAN_STA_TIM)
2847ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			PDEBUG(DEBUG_PS2, "Re-setting TIM for aid %d\n",
2848ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			       sta->aid);
2849ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		hostap_set_tim(local, sta->aid, 1);
2850ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		sta->flags |= WLAN_STA_TIM;
2851ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
2852ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2853ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	ret = AP_TX_BUFFERED;
2854ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2855ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen out:
2856ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (sta != NULL) {
2857ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		if (ret == AP_TX_CONTINUE ||
2858ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		    ret == AP_TX_CONTINUE_NOT_AUTHORIZED) {
2859ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			sta->tx_packets++;
2860ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			sta->tx_bytes += skb->len;
2861ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			sta->last_tx = jiffies;
2862ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		}
2863ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2864ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		if ((ret == AP_TX_CONTINUE ||
2865ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		     ret == AP_TX_CONTINUE_NOT_AUTHORIZED) &&
2866ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		    sta->crypt && tx->host_encrypt) {
2867ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			tx->crypt = sta->crypt;
2868ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			tx->sta_ptr = sta; /* hostap_handle_sta_release() will
2869ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen					    * be called to release sta info
2870ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen					    * later */
2871ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		} else
2872ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			atomic_dec(&sta->users);
2873ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
2874ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2875ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	return ret;
2876ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen}
2877ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2878ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2879ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenvoid hostap_handle_sta_release(void *ptr)
2880ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{
2881ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	struct sta_info *sta = ptr;
2882ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	atomic_dec(&sta->users);
2883ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen}
2884ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2885ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2886ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen/* Called only as a tasklet (software IRQ) */
2887ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenvoid hostap_handle_sta_tx_exc(local_info_t *local, struct sk_buff *skb)
2888ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{
2889ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	struct sta_info *sta;
2890d041674d62e1ad565f2fb6d53ae80b31d6656033James Ketrenos	struct ieee80211_hdr_4addr *hdr;
2891ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	struct hostap_skb_tx_data *meta;
2892ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2893d041674d62e1ad565f2fb6d53ae80b31d6656033James Ketrenos	hdr = (struct ieee80211_hdr_4addr *) skb->data;
2894ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	meta = (struct hostap_skb_tx_data *) skb->cb;
2895ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2896ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	spin_lock(&local->ap->sta_table_lock);
2897ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	sta = ap_get_sta(local->ap, hdr->addr1);
2898ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (!sta) {
2899ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		spin_unlock(&local->ap->sta_table_lock);
290021f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller		PDEBUG(DEBUG_AP, "%s: Could not find STA " MAC_FMT
29010795af5729b18218767fab27c44b1384f72dc9adJoe Perches		       " for this TX error (@%lu)\n",
290221f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller		       local->dev->name,
290321f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller		       hdr->addr1[0], hdr->addr1[1], hdr->addr1[2],
290421f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller		       hdr->addr1[3], hdr->addr1[4], hdr->addr1[5],
290521f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller		       jiffies);
2906ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		return;
2907ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
2908ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2909ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	sta->tx_since_last_failure = 0;
2910ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	sta->tx_consecutive_exc++;
291174fae82c8bd5dd78365abe25506a9ba388d4a889Jeff Garzik
2912ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (sta->tx_consecutive_exc >= WLAN_RATE_DECREASE_THRESHOLD &&
2913ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	    sta->tx_rate_idx > 0 && meta->rate <= sta->tx_rate) {
2914ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		/* use next lower rate */
2915ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		int old, rate;
2916ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		old = rate = sta->tx_rate_idx;
2917ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		while (rate > 0) {
2918ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			rate--;
2919ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			if (ap_tx_rate_ok(rate, sta, local)) {
2920ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen				sta->tx_rate_idx = rate;
2921ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen				break;
2922ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			}
2923ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		}
2924ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		if (old != sta->tx_rate_idx) {
2925ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			switch (sta->tx_rate_idx) {
2926ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			case 0: sta->tx_rate = 10; break;
2927ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			case 1: sta->tx_rate = 20; break;
2928ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			case 2: sta->tx_rate = 55; break;
2929ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			case 3: sta->tx_rate = 110; break;
2930ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			default: sta->tx_rate = 0; break;
2931ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			}
293221f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller			PDEBUG(DEBUG_AP, "%s: STA " MAC_FMT
29330795af5729b18218767fab27c44b1384f72dc9adJoe Perches			       " TX rate lowered to %d\n",
293421f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller			       local->dev->name,
293521f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller			       sta->addr[0], sta->addr[1], sta->addr[2],
293621f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller			       sta->addr[3], sta->addr[4], sta->addr[5],
2937ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			       sta->tx_rate);
2938ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		}
2939ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		sta->tx_consecutive_exc = 0;
2940ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
2941ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	spin_unlock(&local->ap->sta_table_lock);
2942ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen}
2943ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2944ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2945ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenstatic void hostap_update_sta_ps2(local_info_t *local, struct sta_info *sta,
2946ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen				  int pwrmgt, int type, int stype)
2947ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{
29480795af5729b18218767fab27c44b1384f72dc9adJoe Perches	DECLARE_MAC_BUF(mac);
2949ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (pwrmgt && !(sta->flags & WLAN_STA_PS)) {
2950ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		sta->flags |= WLAN_STA_PS;
29510795af5729b18218767fab27c44b1384f72dc9adJoe Perches		PDEBUG(DEBUG_PS2, "STA %s changed to use PS "
2952ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		       "mode (type=0x%02X, stype=0x%02X)\n",
29530795af5729b18218767fab27c44b1384f72dc9adJoe Perches		       print_mac(mac, sta->addr), type >> 2, stype >> 4);
2954ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	} else if (!pwrmgt && (sta->flags & WLAN_STA_PS)) {
2955ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		sta->flags &= ~WLAN_STA_PS;
29560795af5729b18218767fab27c44b1384f72dc9adJoe Perches		PDEBUG(DEBUG_PS2, "STA %s changed to not use "
2957ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		       "PS mode (type=0x%02X, stype=0x%02X)\n",
29580795af5729b18218767fab27c44b1384f72dc9adJoe Perches		       print_mac(mac, sta->addr), type >> 2, stype >> 4);
29594339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen		if (type != IEEE80211_FTYPE_CTL ||
29604339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen		    stype != IEEE80211_STYPE_PSPOLL)
2961ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			schedule_packet_send(local, sta);
2962ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
2963ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen}
2964ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2965ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2966ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen/* Called only as a tasklet (software IRQ). Called for each RX frame to update
2967c0f72ca8e4f1b459b5582c1c8dcaf7e53151f069Jouni Malinen * STA power saving state. pwrmgt is a flag from 802.11 frame_ctl field. */
2968d041674d62e1ad565f2fb6d53ae80b31d6656033James Ketrenosint hostap_update_sta_ps(local_info_t *local, struct ieee80211_hdr_4addr *hdr)
2969ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{
2970ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	struct sta_info *sta;
2971ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	u16 fc;
2972ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2973ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	spin_lock(&local->ap->sta_table_lock);
2974ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	sta = ap_get_sta(local->ap, hdr->addr2);
2975ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (sta)
2976ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		atomic_inc(&sta->users);
2977ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	spin_unlock(&local->ap->sta_table_lock);
2978ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2979ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (!sta)
2980ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		return -1;
2981ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2982c0f72ca8e4f1b459b5582c1c8dcaf7e53151f069Jouni Malinen	fc = le16_to_cpu(hdr->frame_ctl);
2983b2f4a2e3b1620667da9654f9e220c92ea52bdbe4Jouni Malinen	hostap_update_sta_ps2(local, sta, fc & IEEE80211_FCTL_PM,
29844339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen			      WLAN_FC_GET_TYPE(fc), WLAN_FC_GET_STYPE(fc));
2985ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2986ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	atomic_dec(&sta->users);
2987ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	return 0;
2988ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen}
2989ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2990ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
2991ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen/* Called only as a tasklet (software IRQ). Called for each RX frame after
2992ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * getting RX header and payload from hardware. */
2993ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenap_rx_ret hostap_handle_sta_rx(local_info_t *local, struct net_device *dev,
2994ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			       struct sk_buff *skb,
2995ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			       struct hostap_80211_rx_status *rx_stats,
2996ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			       int wds)
2997ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{
2998ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	int ret;
2999ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	struct sta_info *sta;
3000ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	u16 fc, type, stype;
3001d041674d62e1ad565f2fb6d53ae80b31d6656033James Ketrenos	struct ieee80211_hdr_4addr *hdr;
3002ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
3003ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (local->ap == NULL)
3004ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		return AP_RX_CONTINUE;
3005ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
3006d041674d62e1ad565f2fb6d53ae80b31d6656033James Ketrenos	hdr = (struct ieee80211_hdr_4addr *) skb->data;
3007ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
3008c0f72ca8e4f1b459b5582c1c8dcaf7e53151f069Jouni Malinen	fc = le16_to_cpu(hdr->frame_ctl);
30094339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen	type = WLAN_FC_GET_TYPE(fc);
30104339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen	stype = WLAN_FC_GET_STYPE(fc);
3011ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
3012ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	spin_lock(&local->ap->sta_table_lock);
3013ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	sta = ap_get_sta(local->ap, hdr->addr2);
3014ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (sta)
3015ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		atomic_inc(&sta->users);
3016ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	spin_unlock(&local->ap->sta_table_lock);
3017ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
3018ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (sta && !(sta->flags & WLAN_STA_AUTHORIZED))
3019ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		ret = AP_RX_CONTINUE_NOT_AUTHORIZED;
3020ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	else
3021ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		ret = AP_RX_CONTINUE;
3022ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
3023ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
3024b2f4a2e3b1620667da9654f9e220c92ea52bdbe4Jouni Malinen	if (fc & IEEE80211_FCTL_TODS) {
3025ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		if (!wds && (sta == NULL || !(sta->flags & WLAN_STA_ASSOC))) {
3026ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			if (local->hostapd) {
3027ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen				prism2_rx_80211(local->apdev, skb, rx_stats,
3028ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen						PRISM2_RX_NON_ASSOC);
3029ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
3030ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			} else {
3031ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen				printk(KERN_DEBUG "%s: dropped received packet"
30320795af5729b18218767fab27c44b1384f72dc9adJoe Perches				       " from non-associated STA "
303321f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller				       MAC_FMT
3034ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen				       " (type=0x%02x, subtype=0x%02x)\n",
303521f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller				       dev->name,
303621f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller				       hdr->addr2[0], hdr->addr2[1],
303721f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller				       hdr->addr2[2], hdr->addr2[3],
303821f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller				       hdr->addr2[4], hdr->addr2[5],
30394339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen				       type >> 2, stype >> 4);
3040ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen				hostap_rx(dev, skb, rx_stats);
3041ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
3042ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			}
3043ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			ret = AP_RX_EXIT;
3044ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			goto out;
3045ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		}
3046b2f4a2e3b1620667da9654f9e220c92ea52bdbe4Jouni Malinen	} else if (fc & IEEE80211_FCTL_FROMDS) {
3047ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		if (!wds) {
3048ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			/* FromDS frame - not for us; probably
3049ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			 * broadcast/multicast in another BSS - drop */
3050ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			if (memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN) == 0) {
3051ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen				printk(KERN_DEBUG "Odd.. FromDS packet "
3052ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen				       "received with own BSSID\n");
3053ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen				hostap_dump_rx_80211(dev->name, skb, rx_stats);
3054ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			}
3055ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			ret = AP_RX_DROP;
3056ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			goto out;
3057ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		}
30584339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen	} else if (stype == IEEE80211_STYPE_NULLFUNC && sta == NULL &&
3059ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		   memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN) == 0) {
3060ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
3061ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		if (local->hostapd) {
3062ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			prism2_rx_80211(local->apdev, skb, rx_stats,
3063ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen					PRISM2_RX_NON_ASSOC);
3064ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
3065ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		} else {
3066ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			/* At least Lucent f/w seems to send data::nullfunc
3067ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			 * frames with no ToDS flag when the current AP returns
3068ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			 * after being unavailable for some time. Speed up
3069ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			 * re-association by informing the station about it not
3070ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			 * being associated. */
3071ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			printk(KERN_DEBUG "%s: rejected received nullfunc "
3072ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			       "frame without ToDS from not associated STA "
307321f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller			       MAC_FMT "\n",
307421f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller			       dev->name,
307521f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller			       hdr->addr2[0], hdr->addr2[1],
307621f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller			       hdr->addr2[2], hdr->addr2[3],
307721f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller			       hdr->addr2[4], hdr->addr2[5]);
3078ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			hostap_rx(dev, skb, rx_stats);
3079ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
3080ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		}
3081ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		ret = AP_RX_EXIT;
3082ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		goto out;
30834339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen	} else if (stype == IEEE80211_STYPE_NULLFUNC) {
3084ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		/* At least Lucent cards seem to send periodic nullfunc
3085ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		 * frames with ToDS. Let these through to update SQ
3086ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		 * stats and PS state. Nullfunc frames do not contain
3087ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		 * any data and they will be dropped below. */
3088ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	} else {
3089ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		/* If BSSID (Addr3) is foreign, this frame is a normal
3090ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		 * broadcast frame from an IBSS network. Drop it silently.
3091ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		 * If BSSID is own, report the dropping of this frame. */
3092ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		if (memcmp(hdr->addr3, dev->dev_addr, ETH_ALEN) == 0) {
3093ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			printk(KERN_DEBUG "%s: dropped received packet from "
309421f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller			       MAC_FMT " with no ToDS flag "
30950795af5729b18218767fab27c44b1384f72dc9adJoe Perches			       "(type=0x%02x, subtype=0x%02x)\n", dev->name,
309621f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller			       hdr->addr2[0], hdr->addr2[1],
309721f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller			       hdr->addr2[2], hdr->addr2[3],
309821f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller			       hdr->addr2[4], hdr->addr2[5],
309921f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller			       type >> 2, stype >> 4);
3100ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			hostap_dump_rx_80211(dev->name, skb, rx_stats);
3101ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		}
3102ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		ret = AP_RX_DROP;
3103ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		goto out;
3104ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
3105ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
3106ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (sta) {
3107b2f4a2e3b1620667da9654f9e220c92ea52bdbe4Jouni Malinen		hostap_update_sta_ps2(local, sta, fc & IEEE80211_FCTL_PM,
3108ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen				      type, stype);
3109ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
3110ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		sta->rx_packets++;
3111ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		sta->rx_bytes += skb->len;
3112ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		sta->last_rx = jiffies;
3113ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
3114ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
31154339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen	if (local->ap->nullfunc_ack && stype == IEEE80211_STYPE_NULLFUNC &&
3116b2f4a2e3b1620667da9654f9e220c92ea52bdbe4Jouni Malinen	    fc & IEEE80211_FCTL_TODS) {
3117ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		if (local->hostapd) {
3118ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			prism2_rx_80211(local->apdev, skb, rx_stats,
3119ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen					PRISM2_RX_NULLFUNC_ACK);
3120ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
3121ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		} else {
3122ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			/* some STA f/w's seem to require control::ACK frame
3123ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			 * for data::nullfunc, but Prism2 f/w 0.8.0 (at least
3124ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			 * from Compaq) does not send this.. Try to generate
3125ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			 * ACK for these frames from the host driver to make
3126ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			 * power saving work with, e.g., Lucent WaveLAN f/w */
3127ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			hostap_rx(dev, skb, rx_stats);
3128ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
3129ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		}
3130ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		ret = AP_RX_EXIT;
3131ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		goto out;
3132ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
3133ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
3134ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen out:
3135ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (sta)
3136ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		atomic_dec(&sta->users);
3137ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
3138ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	return ret;
3139ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen}
3140ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
3141ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
3142ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen/* Called only as a tasklet (software IRQ) */
3143ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenint hostap_handle_sta_crypto(local_info_t *local,
3144d041674d62e1ad565f2fb6d53ae80b31d6656033James Ketrenos			     struct ieee80211_hdr_4addr *hdr,
314562fe7e378109537ff80971c5208e12d40bf88beeJouni Malinen			     struct ieee80211_crypt_data **crypt,
314662fe7e378109537ff80971c5208e12d40bf88beeJouni Malinen			     void **sta_ptr)
3147ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{
3148ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	struct sta_info *sta;
3149ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
3150ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	spin_lock(&local->ap->sta_table_lock);
3151ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	sta = ap_get_sta(local->ap, hdr->addr2);
3152ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (sta)
3153ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		atomic_inc(&sta->users);
3154ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	spin_unlock(&local->ap->sta_table_lock);
3155ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
3156ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (!sta)
3157ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		return -1;
3158ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
3159ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (sta->crypt) {
3160ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		*crypt = sta->crypt;
3161ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		*sta_ptr = sta;
3162ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		/* hostap_handle_sta_release() will be called to release STA
3163ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		 * info */
3164ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	} else
3165ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		atomic_dec(&sta->users);
3166ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
3167ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	return 0;
3168ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen}
3169ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
3170ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
3171ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen/* Called only as a tasklet (software IRQ) */
3172ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenint hostap_is_sta_assoc(struct ap_data *ap, u8 *sta_addr)
3173ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{
3174ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	struct sta_info *sta;
3175ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	int ret = 0;
3176ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
3177ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	spin_lock(&ap->sta_table_lock);
3178ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	sta = ap_get_sta(ap, sta_addr);
3179ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (sta != NULL && (sta->flags & WLAN_STA_ASSOC) && !sta->ap)
3180ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		ret = 1;
3181ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	spin_unlock(&ap->sta_table_lock);
3182ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
3183ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	return ret;
3184ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen}
3185ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
3186ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
3187ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen/* Called only as a tasklet (software IRQ) */
3188ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenint hostap_is_sta_authorized(struct ap_data *ap, u8 *sta_addr)
3189ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{
3190ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	struct sta_info *sta;
3191ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	int ret = 0;
3192ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
3193ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	spin_lock(&ap->sta_table_lock);
3194ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	sta = ap_get_sta(ap, sta_addr);
3195ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (sta != NULL && (sta->flags & WLAN_STA_ASSOC) && !sta->ap &&
3196ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	    ((sta->flags & WLAN_STA_AUTHORIZED) ||
3197ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	     ap->local->ieee_802_1x == 0))
3198ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		ret = 1;
3199ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	spin_unlock(&ap->sta_table_lock);
3200ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
3201ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	return ret;
3202ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen}
3203ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
3204ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
3205ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen/* Called only as a tasklet (software IRQ) */
3206ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenint hostap_add_sta(struct ap_data *ap, u8 *sta_addr)
3207ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{
3208ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	struct sta_info *sta;
3209ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	int ret = 1;
3210ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
3211ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (!ap)
3212ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		return -1;
3213ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
3214ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	spin_lock(&ap->sta_table_lock);
3215ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	sta = ap_get_sta(ap, sta_addr);
3216ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (sta)
3217ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		ret = 0;
3218ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	spin_unlock(&ap->sta_table_lock);
3219ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
3220ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (ret == 1) {
3221ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		sta = ap_add_sta(ap, sta_addr);
3222ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		if (!sta)
322354b85f489bdfafc9306dfcc21e0d2687c34c3b34Adrian Bunk			return -1;
3224ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		sta->flags = WLAN_STA_AUTH | WLAN_STA_ASSOC;
3225ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		sta->ap = 1;
3226ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		memset(sta->supported_rates, 0, sizeof(sta->supported_rates));
3227ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		/* No way of knowing which rates are supported since we did not
3228ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		 * get supported rates element from beacon/assoc req. Assume
3229ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		 * that remote end supports all 802.11b rates. */
3230ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		sta->supported_rates[0] = 0x82;
3231ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		sta->supported_rates[1] = 0x84;
3232ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		sta->supported_rates[2] = 0x0b;
3233ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		sta->supported_rates[3] = 0x16;
3234ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		sta->tx_supp_rates = WLAN_RATE_1M | WLAN_RATE_2M |
3235ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			WLAN_RATE_5M5 | WLAN_RATE_11M;
3236ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		sta->tx_rate = 110;
3237ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		sta->tx_max_rate = sta->tx_rate_idx = 3;
3238ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
3239ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
3240ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	return ret;
3241ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen}
3242ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
3243ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
3244ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen/* Called only as a tasklet (software IRQ) */
3245ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenint hostap_update_rx_stats(struct ap_data *ap,
3246d041674d62e1ad565f2fb6d53ae80b31d6656033James Ketrenos			   struct ieee80211_hdr_4addr *hdr,
3247ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			   struct hostap_80211_rx_status *rx_stats)
3248ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{
3249ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	struct sta_info *sta;
3250ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
3251ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (!ap)
3252ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		return -1;
3253ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
3254ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	spin_lock(&ap->sta_table_lock);
3255ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	sta = ap_get_sta(ap, hdr->addr2);
3256ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (sta) {
3257ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		sta->last_rx_silence = rx_stats->noise;
3258ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		sta->last_rx_signal = rx_stats->signal;
3259ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		sta->last_rx_rate = rx_stats->rate;
3260c28df16ed70d1b6cefd12135e3c68bfccd1bb635Jean Tourrilhes		sta->last_rx_updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
3261ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		if (rx_stats->rate == 10)
3262ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			sta->rx_count[0]++;
3263ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		else if (rx_stats->rate == 20)
3264ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			sta->rx_count[1]++;
3265ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		else if (rx_stats->rate == 55)
3266ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			sta->rx_count[2]++;
3267ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		else if (rx_stats->rate == 110)
3268ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			sta->rx_count[3]++;
3269ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
3270ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	spin_unlock(&ap->sta_table_lock);
3271ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
3272ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	return sta ? 0 : -1;
3273ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen}
3274ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
3275ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
3276ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenvoid hostap_update_rates(local_info_t *local)
3277ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{
3278c15057313725942c6af8dcb60b4d4322101316d9Matthias Kaehlcke	struct sta_info *sta;
3279ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	struct ap_data *ap = local->ap;
3280ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
3281ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (!ap)
3282ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		return;
3283ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
3284ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	spin_lock_bh(&ap->sta_table_lock);
3285c15057313725942c6af8dcb60b4d4322101316d9Matthias Kaehlcke	list_for_each_entry(sta, &ap->sta_list, list) {
3286ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		prism2_check_tx_rates(sta);
3287ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
3288ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	spin_unlock_bh(&ap->sta_table_lock);
3289ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen}
3290ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
3291ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
32925fad5a2e1f34b333a801b749c4e143c2ac3e8a4fAdrian Bunkvoid * ap_crypt_get_ptrs(struct ap_data *ap, u8 *addr, int permanent,
32935fad5a2e1f34b333a801b749c4e143c2ac3e8a4fAdrian Bunk			 struct ieee80211_crypt_data ***crypt)
3294ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{
3295ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	struct sta_info *sta;
3296ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
3297ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	spin_lock_bh(&ap->sta_table_lock);
3298ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	sta = ap_get_sta(ap, addr);
3299ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (sta)
3300ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		atomic_inc(&sta->users);
3301ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	spin_unlock_bh(&ap->sta_table_lock);
3302ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
3303ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (!sta && permanent)
3304ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		sta = ap_add_sta(ap, addr);
3305ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
3306ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (!sta)
3307ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		return NULL;
3308ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
3309ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (permanent)
3310ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		sta->flags |= WLAN_STA_PERM;
3311ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
3312ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	*crypt = &sta->crypt;
3313ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
3314ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	return sta;
3315ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen}
3316ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
3317ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
3318ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenvoid hostap_add_wds_links(local_info_t *local)
3319ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{
3320ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	struct ap_data *ap = local->ap;
3321c15057313725942c6af8dcb60b4d4322101316d9Matthias Kaehlcke	struct sta_info *sta;
3322ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
3323ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	spin_lock_bh(&ap->sta_table_lock);
3324c15057313725942c6af8dcb60b4d4322101316d9Matthias Kaehlcke	list_for_each_entry(sta, &ap->sta_list, list) {
3325ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		if (sta->ap)
3326ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen			hostap_wds_link_oper(local, sta->addr, WDS_ADD);
3327ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	}
3328ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	spin_unlock_bh(&ap->sta_table_lock);
3329ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
3330ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	schedule_work(&local->ap->wds_oper_queue);
3331ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen}
3332ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
3333ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
3334ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenvoid hostap_wds_link_oper(local_info_t *local, u8 *addr, wds_oper_type type)
3335ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{
3336ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	struct wds_oper_data *entry;
3337ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
3338ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
3339ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	if (!entry)
3340ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen		return;
3341ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	memcpy(entry->addr, addr, ETH_ALEN);
3342ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	entry->type = type;
3343ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	spin_lock_bh(&local->lock);
3344ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	entry->next = local->ap->wds_oper_entries;
3345ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	local->ap->wds_oper_entries = entry;
3346ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	spin_unlock_bh(&local->lock);
3347ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
3348ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen	schedule_work(&local->ap->wds_oper_queue);
3349ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen}
3350ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
3351ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen
3352ff1d2767d5a43c85f944e86a45284b721f66196cJouni MalinenEXPORT_SYMBOL(hostap_init_data);
3353ff1d2767d5a43c85f944e86a45284b721f66196cJouni MalinenEXPORT_SYMBOL(hostap_init_ap_proc);
3354ff1d2767d5a43c85f944e86a45284b721f66196cJouni MalinenEXPORT_SYMBOL(hostap_free_data);
3355ff1d2767d5a43c85f944e86a45284b721f66196cJouni MalinenEXPORT_SYMBOL(hostap_check_sta_fw_version);
3356ff1d2767d5a43c85f944e86a45284b721f66196cJouni MalinenEXPORT_SYMBOL(hostap_handle_sta_tx_exc);
3357ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
3358ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
3359