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