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> 206bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells#include <linux/seq_file.h> 215fad5a2e1f34b333a801b749c4e143c2ac3e8a4fAdrian Bunk#include <linux/delay.h> 225fad5a2e1f34b333a801b749c4e143c2ac3e8a4fAdrian Bunk#include <linux/random.h> 231ea893fde29d8cf1639da8989f4b843dc3283ca8Dan Williams#include <linux/if_arp.h> 245a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 25ee40fa0656a730491765545ff7550f3c1ceb0fbcPaul Gortmaker#include <linux/export.h> 266eb07caf1ac5723720caea2ee93cd11b7058a0aaPaul Gortmaker#include <linux/moduleparam.h> 27d22fbd70c2770b5e3ba0d7bc5b29f6ee686cdba4dingtianhong#include <linux/etherdevice.h> 285fad5a2e1f34b333a801b749c4e143c2ac3e8a4fAdrian Bunk 295fad5a2e1f34b333a801b749c4e143c2ac3e8a4fAdrian Bunk#include "hostap_wlan.h" 305fad5a2e1f34b333a801b749c4e143c2ac3e8a4fAdrian Bunk#include "hostap.h" 315fad5a2e1f34b333a801b749c4e143c2ac3e8a4fAdrian Bunk#include "hostap_ap.h" 325fad5a2e1f34b333a801b749c4e143c2ac3e8a4fAdrian Bunk 33ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenstatic int other_ap_policy[MAX_PARM_DEVICES] = { AP_OTHER_AP_SKIP_ALL, 34ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen DEF_INTS }; 35ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenmodule_param_array(other_ap_policy, int, NULL, 0444); 36ff1d2767d5a43c85f944e86a45284b721f66196cJouni MalinenMODULE_PARM_DESC(other_ap_policy, "Other AP beacon monitoring policy (0-3)"); 37ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 38ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenstatic int ap_max_inactivity[MAX_PARM_DEVICES] = { AP_MAX_INACTIVITY_SEC, 39ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen DEF_INTS }; 40ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenmodule_param_array(ap_max_inactivity, int, NULL, 0444); 41ff1d2767d5a43c85f944e86a45284b721f66196cJouni MalinenMODULE_PARM_DESC(ap_max_inactivity, "AP timeout (in seconds) for station " 42ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen "inactivity"); 43ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 44ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenstatic int ap_bridge_packets[MAX_PARM_DEVICES] = { 1, DEF_INTS }; 45ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenmodule_param_array(ap_bridge_packets, int, NULL, 0444); 46ff1d2767d5a43c85f944e86a45284b721f66196cJouni MalinenMODULE_PARM_DESC(ap_bridge_packets, "Bridge packets directly between " 47ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen "stations"); 48ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 49ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenstatic int autom_ap_wds[MAX_PARM_DEVICES] = { 0, DEF_INTS }; 50ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenmodule_param_array(autom_ap_wds, int, NULL, 0444); 51ff1d2767d5a43c85f944e86a45284b721f66196cJouni MalinenMODULE_PARM_DESC(autom_ap_wds, "Add WDS connections to other APs " 52ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen "automatically"); 53ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 54ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 55ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenstatic struct sta_info* ap_get_sta(struct ap_data *ap, u8 *sta); 56ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenstatic void hostap_event_expired_sta(struct net_device *dev, 57ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct sta_info *sta); 58c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howellsstatic void handle_add_proc_queue(struct work_struct *work); 59ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 60ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT 61c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howellsstatic void handle_wds_oper_queue(struct work_struct *work); 62ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenstatic void prism2_send_mgmt(struct net_device *dev, 634339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen u16 type_subtype, char *body, 64ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen int body_len, u8 *addr, u16 tx_cb_idx); 65ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ 66ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 67ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 68ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#ifndef PRISM2_NO_PROCFS_DEBUG 696bbefe86796c07fb8a6d28114f1e3f770586ba05David Howellsstatic int ap_debug_proc_show(struct seq_file *m, void *v) 70ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{ 716bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells struct ap_data *ap = m->private; 726bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells 736bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells seq_printf(m, "BridgedUnicastFrames=%u\n", ap->bridged_unicast); 746bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells seq_printf(m, "BridgedMulticastFrames=%u\n", ap->bridged_multicast); 756bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells seq_printf(m, "max_inactivity=%u\n", ap->max_inactivity / HZ); 766bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells seq_printf(m, "bridge_packets=%u\n", ap->bridge_packets); 776bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells seq_printf(m, "nullfunc_ack=%u\n", ap->nullfunc_ack); 786bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells seq_printf(m, "autom_ap_wds=%u\n", ap->autom_ap_wds); 796bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells seq_printf(m, "auth_algs=%u\n", ap->local->auth_algs); 806bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells seq_printf(m, "tx_drop_nonassoc=%u\n", ap->tx_drop_nonassoc); 816bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells return 0; 826bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells} 83ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 846bbefe86796c07fb8a6d28114f1e3f770586ba05David Howellsstatic int ap_debug_proc_open(struct inode *inode, struct file *file) 856bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells{ 866bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells return single_open(file, ap_debug_proc_show, PDE_DATA(inode)); 87ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen} 886bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells 896bbefe86796c07fb8a6d28114f1e3f770586ba05David Howellsstatic const struct file_operations ap_debug_proc_fops = { 906bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells .open = ap_debug_proc_open, 916bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells .read = seq_read, 926bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells .llseek = seq_lseek, 93bc3041f055c228ec8347580d95cb2b344b503dcbAl Viro .release = single_release, 946bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells}; 95ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#endif /* PRISM2_NO_PROCFS_DEBUG */ 96ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 97ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 98ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenstatic void ap_sta_hash_add(struct ap_data *ap, struct sta_info *sta) 99ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{ 100ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->hnext = ap->sta_hash[STA_HASH(sta->addr)]; 101ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen ap->sta_hash[STA_HASH(sta->addr)] = sta; 102ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen} 103ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 104ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenstatic void ap_sta_hash_del(struct ap_data *ap, struct sta_info *sta) 105ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{ 106ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct sta_info *s; 107ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 108ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen s = ap->sta_hash[STA_HASH(sta->addr)]; 109ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (s == NULL) return; 110d22fbd70c2770b5e3ba0d7bc5b29f6ee686cdba4dingtianhong if (ether_addr_equal(s->addr, sta->addr)) { 111ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen ap->sta_hash[STA_HASH(sta->addr)] = s->hnext; 112ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return; 113ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 114ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 115d22fbd70c2770b5e3ba0d7bc5b29f6ee686cdba4dingtianhong while (s->hnext != NULL && !ether_addr_equal(s->hnext->addr, sta->addr)) 116ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen s = s->hnext; 117ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (s->hnext != NULL) 118ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen s->hnext = s->hnext->hnext; 119ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen else 120e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg printk("AP: could not remove STA %pM from hash table\n", 121e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg sta->addr); 122ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen} 123ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 124ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenstatic void ap_free_sta(struct ap_data *ap, struct sta_info *sta) 125ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{ 126ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (sta->ap && sta->local) 127ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen hostap_event_expired_sta(sta->local->dev, sta); 128ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 129ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (ap->proc != NULL) { 130ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen char name[20]; 131e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg sprintf(name, "%pM", sta->addr); 132ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen remove_proc_entry(name, ap->proc); 133ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 134ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 135ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (sta->crypt) { 136ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->crypt->ops->deinit(sta->crypt->priv); 137ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen kfree(sta->crypt); 138ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->crypt = NULL; 139ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 140ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 141ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen skb_queue_purge(&sta->tx_buf); 142ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 143ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen ap->num_sta--; 144ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT 145ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (sta->aid > 0) 146ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen ap->sta_aid[sta->aid - 1] = NULL; 147ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 148ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (!sta->ap && sta->u.sta.challenge) 149ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen kfree(sta->u.sta.challenge); 15072471c0d3197d02da53897868692f0b91042f8a5Kirill Tkhai del_timer_sync(&sta->timer); 151ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ 152ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 153ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen kfree(sta); 154ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen} 155ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 156ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 157ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenstatic void hostap_set_tim(local_info_t *local, int aid, int set) 158ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{ 159ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (local->func->set_tim) 160ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen local->func->set_tim(local->dev, aid, set); 161ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen} 162ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 163ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 164ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenstatic void hostap_event_new_sta(struct net_device *dev, struct sta_info *sta) 165ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{ 166ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen union iwreq_data wrqu; 167ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen memset(&wrqu, 0, sizeof(wrqu)); 168ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen memcpy(wrqu.addr.sa_data, sta->addr, ETH_ALEN); 169ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen wrqu.addr.sa_family = ARPHRD_ETHER; 170ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen wireless_send_event(dev, IWEVREGISTERED, &wrqu, NULL); 171ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen} 172ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 173ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 174ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenstatic void hostap_event_expired_sta(struct net_device *dev, 175ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct sta_info *sta) 176ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{ 177ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen union iwreq_data wrqu; 178ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen memset(&wrqu, 0, sizeof(wrqu)); 179ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen memcpy(wrqu.addr.sa_data, sta->addr, ETH_ALEN); 180ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen wrqu.addr.sa_family = ARPHRD_ETHER; 181ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen wireless_send_event(dev, IWEVEXPIRED, &wrqu, NULL); 182ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen} 183ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 184ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 185ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT 186ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 187ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenstatic void ap_handle_timer(unsigned long data) 188ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{ 189ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct sta_info *sta = (struct sta_info *) data; 190ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen local_info_t *local; 191ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct ap_data *ap; 192ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen unsigned long next_time = 0; 193ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen int was_assoc; 194ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 195ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (sta == NULL || sta->local == NULL || sta->local->ap == NULL) { 196ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen PDEBUG(DEBUG_AP, "ap_handle_timer() called with NULL data\n"); 197ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return; 198ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 199ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 200ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen local = sta->local; 201ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen ap = local->ap; 202ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen was_assoc = sta->flags & WLAN_STA_ASSOC; 203ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 204ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (atomic_read(&sta->users) != 0) 205ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen next_time = jiffies + HZ; 206ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen else if ((sta->flags & WLAN_STA_PERM) && !(sta->flags & WLAN_STA_AUTH)) 207ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen next_time = jiffies + ap->max_inactivity; 208ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 209ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (time_before(jiffies, sta->last_rx + ap->max_inactivity)) { 210ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen /* station activity detected; reset timeout state */ 211ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->timeout_next = STA_NULLFUNC; 212ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen next_time = sta->last_rx + ap->max_inactivity; 213ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } else if (sta->timeout_next == STA_DISASSOC && 214ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen !(sta->flags & WLAN_STA_PENDING_POLL)) { 215ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen /* STA ACKed data nullfunc frame poll */ 216ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->timeout_next = STA_NULLFUNC; 217ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen next_time = jiffies + ap->max_inactivity; 218ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 219ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 220ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (next_time) { 221ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->timer.expires = next_time; 222ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen add_timer(&sta->timer); 223ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return; 224ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 225ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 226ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (sta->ap) 227ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->timeout_next = STA_DEAUTH; 228ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 229ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (sta->timeout_next == STA_DEAUTH && !(sta->flags & WLAN_STA_PERM)) { 230ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen spin_lock(&ap->sta_table_lock); 231ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen ap_sta_hash_del(ap, sta); 232ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen list_del(&sta->list); 233ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen spin_unlock(&ap->sta_table_lock); 234ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC); 235ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } else if (sta->timeout_next == STA_DISASSOC) 236ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->flags &= ~WLAN_STA_ASSOC; 237ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 238ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (was_assoc && !(sta->flags & WLAN_STA_ASSOC) && !sta->ap) 239ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen hostap_event_expired_sta(local->dev, sta); 240ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 241ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (sta->timeout_next == STA_DEAUTH && sta->aid > 0 && 242ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen !skb_queue_empty(&sta->tx_buf)) { 243ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen hostap_set_tim(local, sta->aid, 0); 244ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->flags &= ~WLAN_STA_TIM; 245ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 246ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 247ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (sta->ap) { 248ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (ap->autom_ap_wds) { 249ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen PDEBUG(DEBUG_AP, "%s: removing automatic WDS " 250e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg "connection to AP %pM\n", 251e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg local->dev->name, sta->addr); 252ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen hostap_wds_link_oper(local, sta->addr, WDS_DEL); 253ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 254ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } else if (sta->timeout_next == STA_NULLFUNC) { 255ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen /* send data frame to poll STA and check whether this frame 256ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * is ACKed */ 2574339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen /* FIX: IEEE80211_STYPE_NULLFUNC would be more appropriate, but 258ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * it is apparently not retried so TX Exc events are not 259ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * received for it */ 260ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->flags |= WLAN_STA_PENDING_POLL; 2614339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen prism2_send_mgmt(local->dev, IEEE80211_FTYPE_DATA | 2624339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen IEEE80211_STYPE_DATA, NULL, 0, 263ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->addr, ap->tx_callback_poll); 264ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } else { 265ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen int deauth = sta->timeout_next == STA_DEAUTH; 2668a9faf3cd08b91aca1502dbe18e3b5063fda2e87Al Viro __le16 resp; 267e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg PDEBUG(DEBUG_AP, "%s: sending %s info to STA %pM" 268ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen "(last=%lu, jiffies=%lu)\n", 269ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen local->dev->name, 270ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen deauth ? "deauthentication" : "disassociation", 271e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg sta->addr, sta->last_rx, jiffies); 272ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 273ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen resp = cpu_to_le16(deauth ? WLAN_REASON_PREV_AUTH_NOT_VALID : 274ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY); 2754339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen prism2_send_mgmt(local->dev, IEEE80211_FTYPE_MGMT | 2764339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen (deauth ? IEEE80211_STYPE_DEAUTH : 2774339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen IEEE80211_STYPE_DISASSOC), 278ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen (char *) &resp, 2, sta->addr, 0); 279ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 280ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 281ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (sta->timeout_next == STA_DEAUTH) { 282ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (sta->flags & WLAN_STA_PERM) { 283e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg PDEBUG(DEBUG_AP, "%s: STA %pM" 2840795af5729b18218767fab27c44b1384f72dc9adJoe Perches " would have been removed, " 2850795af5729b18218767fab27c44b1384f72dc9adJoe Perches "but it has 'perm' flag\n", 286e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg local->dev->name, sta->addr); 287ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } else 288ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen ap_free_sta(ap, sta); 289ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return; 290ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 291ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 292ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (sta->timeout_next == STA_NULLFUNC) { 293ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->timeout_next = STA_DISASSOC; 294ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->timer.expires = jiffies + AP_DISASSOC_DELAY; 295ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } else { 296ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->timeout_next = STA_DEAUTH; 297ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->timer.expires = jiffies + AP_DEAUTH_DELAY; 298ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 299ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 300ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen add_timer(&sta->timer); 301ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen} 302ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 303ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 304ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenvoid hostap_deauth_all_stas(struct net_device *dev, struct ap_data *ap, 305ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen int resend) 306ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{ 307ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen u8 addr[ETH_ALEN]; 3088a9faf3cd08b91aca1502dbe18e3b5063fda2e87Al Viro __le16 resp; 309ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen int i; 310ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 311ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen PDEBUG(DEBUG_AP, "%s: Deauthenticate all stations\n", dev->name); 312ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen memset(addr, 0xff, ETH_ALEN); 313ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 3148a9faf3cd08b91aca1502dbe18e3b5063fda2e87Al Viro resp = cpu_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID); 315ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 316ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen /* deauth message sent; try to resend it few times; the message is 317ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * broadcast, so it may be delayed until next DTIM; there is not much 318ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * else we can do at this point since the driver is going to be shut 319ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * down */ 320ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen for (i = 0; i < 5; i++) { 3214339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen prism2_send_mgmt(dev, IEEE80211_FTYPE_MGMT | 3224339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen IEEE80211_STYPE_DEAUTH, 323ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen (char *) &resp, 2, addr, 0); 324ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 325ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (!resend || ap->num_sta <= 0) 326ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return; 327ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 328ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen mdelay(50); 329ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 330ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen} 331ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 332ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 3336bbefe86796c07fb8a6d28114f1e3f770586ba05David Howellsstatic int ap_control_proc_show(struct seq_file *m, void *v) 334ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{ 3356bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells struct ap_data *ap = m->private; 336ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen char *policy_txt; 337ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct mac_entry *entry; 338ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 3396bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells if (v == SEQ_START_TOKEN) { 3406bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells switch (ap->mac_restrictions.policy) { 3416bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells case MAC_POLICY_OPEN: 3426bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells policy_txt = "open"; 3436bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells break; 3446bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells case MAC_POLICY_ALLOW: 3456bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells policy_txt = "allow"; 3466bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells break; 3476bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells case MAC_POLICY_DENY: 3486bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells policy_txt = "deny"; 3496bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells break; 3506bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells default: 3516bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells policy_txt = "unknown"; 3526bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells break; 3536bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells } 3546bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells seq_printf(m, "MAC policy: %s\n", policy_txt); 3556bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells seq_printf(m, "MAC entries: %u\n", ap->mac_restrictions.entries); 3566bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells seq_puts(m, "MAC list:\n"); 357ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return 0; 358ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 359ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 3606bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells entry = v; 3616bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells seq_printf(m, "%pM\n", entry->addr); 3626bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells return 0; 3636bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells} 3646bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells 3656bbefe86796c07fb8a6d28114f1e3f770586ba05David Howellsstatic void *ap_control_proc_start(struct seq_file *m, loff_t *_pos) 3666bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells{ 3676bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells struct ap_data *ap = m->private; 368ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen spin_lock_bh(&ap->mac_restrictions.lock); 3696bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells return seq_list_start_head(&ap->mac_restrictions.mac_list, *_pos); 3706bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells} 371ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 3726bbefe86796c07fb8a6d28114f1e3f770586ba05David Howellsstatic void *ap_control_proc_next(struct seq_file *m, void *v, loff_t *_pos) 3736bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells{ 3746bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells struct ap_data *ap = m->private; 3756bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells return seq_list_next(v, &ap->mac_restrictions.mac_list, _pos); 3766bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells} 3776bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells 3786bbefe86796c07fb8a6d28114f1e3f770586ba05David Howellsstatic void ap_control_proc_stop(struct seq_file *m, void *v) 3796bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells{ 3806bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells struct ap_data *ap = m->private; 381ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen spin_unlock_bh(&ap->mac_restrictions.lock); 3826bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells} 3836bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells 3846bbefe86796c07fb8a6d28114f1e3f770586ba05David Howellsstatic const struct seq_operations ap_control_proc_seqops = { 3856bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells .start = ap_control_proc_start, 3866bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells .next = ap_control_proc_next, 3876bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells .stop = ap_control_proc_stop, 3886bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells .show = ap_control_proc_show, 3896bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells}; 390ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 3916bbefe86796c07fb8a6d28114f1e3f770586ba05David Howellsstatic int ap_control_proc_open(struct inode *inode, struct file *file) 3926bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells{ 3936bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells int ret = seq_open(file, &ap_control_proc_seqops); 3946bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells if (ret == 0) { 3956bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells struct seq_file *m = file->private_data; 3966bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells m->private = PDE_DATA(inode); 3976bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells } 3986bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells return ret; 399ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen} 400ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 4016bbefe86796c07fb8a6d28114f1e3f770586ba05David Howellsstatic const struct file_operations ap_control_proc_fops = { 4026bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells .open = ap_control_proc_open, 4036bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells .read = seq_read, 4046bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells .llseek = seq_lseek, 4056bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells .release = seq_release, 4066bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells}; 4076bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells 408ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 4095fad5a2e1f34b333a801b749c4e143c2ac3e8a4fAdrian Bunkint ap_control_add_mac(struct mac_restrictions *mac_restrictions, u8 *mac) 410ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{ 411ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct mac_entry *entry; 412ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 413ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen entry = kmalloc(sizeof(struct mac_entry), GFP_KERNEL); 414ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (entry == NULL) 415b53cf458ea20dd7f5e32611366f63728e40c9021Kumar Amit Mehta return -ENOMEM; 416ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 417ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen memcpy(entry->addr, mac, ETH_ALEN); 418ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 419ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen spin_lock_bh(&mac_restrictions->lock); 420ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen list_add_tail(&entry->list, &mac_restrictions->mac_list); 421ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen mac_restrictions->entries++; 422ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen spin_unlock_bh(&mac_restrictions->lock); 423ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 424ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return 0; 425ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen} 426ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 427ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 4285fad5a2e1f34b333a801b749c4e143c2ac3e8a4fAdrian Bunkint ap_control_del_mac(struct mac_restrictions *mac_restrictions, u8 *mac) 429ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{ 430ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct list_head *ptr; 431ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct mac_entry *entry; 432ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 433ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen spin_lock_bh(&mac_restrictions->lock); 434ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen for (ptr = mac_restrictions->mac_list.next; 435ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen ptr != &mac_restrictions->mac_list; ptr = ptr->next) { 436ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen entry = list_entry(ptr, struct mac_entry, list); 437ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 438d22fbd70c2770b5e3ba0d7bc5b29f6ee686cdba4dingtianhong if (ether_addr_equal(entry->addr, mac)) { 439ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen list_del(ptr); 440ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen kfree(entry); 441ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen mac_restrictions->entries--; 442ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen spin_unlock_bh(&mac_restrictions->lock); 443ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return 0; 444ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 445ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 446ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen spin_unlock_bh(&mac_restrictions->lock); 447ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return -1; 448ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen} 449ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 450ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 451ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenstatic int ap_control_mac_deny(struct mac_restrictions *mac_restrictions, 452ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen u8 *mac) 453ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{ 454ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct mac_entry *entry; 455ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen int found = 0; 456ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 457ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (mac_restrictions->policy == MAC_POLICY_OPEN) 458ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return 0; 459ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 460ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen spin_lock_bh(&mac_restrictions->lock); 461c15057313725942c6af8dcb60b4d4322101316d9Matthias Kaehlcke list_for_each_entry(entry, &mac_restrictions->mac_list, list) { 462d22fbd70c2770b5e3ba0d7bc5b29f6ee686cdba4dingtianhong if (ether_addr_equal(entry->addr, mac)) { 463ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen found = 1; 464ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen break; 465ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 466ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 467ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen spin_unlock_bh(&mac_restrictions->lock); 468ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 469ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (mac_restrictions->policy == MAC_POLICY_ALLOW) 470ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return !found; 471ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen else 472ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return found; 473ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen} 474ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 475ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 4765fad5a2e1f34b333a801b749c4e143c2ac3e8a4fAdrian Bunkvoid ap_control_flush_macs(struct mac_restrictions *mac_restrictions) 477ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{ 478ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct list_head *ptr, *n; 479ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct mac_entry *entry; 480ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 481ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (mac_restrictions->entries == 0) 482ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return; 483ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 484ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen spin_lock_bh(&mac_restrictions->lock); 485ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen for (ptr = mac_restrictions->mac_list.next, n = ptr->next; 486ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen ptr != &mac_restrictions->mac_list; 487ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen ptr = n, n = ptr->next) { 488ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen entry = list_entry(ptr, struct mac_entry, list); 489ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen list_del(ptr); 490ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen kfree(entry); 491ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 492ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen mac_restrictions->entries = 0; 493ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen spin_unlock_bh(&mac_restrictions->lock); 494ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen} 495ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 496ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 4975fad5a2e1f34b333a801b749c4e143c2ac3e8a4fAdrian Bunkint ap_control_kick_mac(struct ap_data *ap, struct net_device *dev, u8 *mac) 498ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{ 499ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct sta_info *sta; 5008a9faf3cd08b91aca1502dbe18e3b5063fda2e87Al Viro __le16 resp; 501ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 502ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen spin_lock_bh(&ap->sta_table_lock); 503ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta = ap_get_sta(ap, mac); 504ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (sta) { 505ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen ap_sta_hash_del(ap, sta); 506ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen list_del(&sta->list); 507ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 508ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen spin_unlock_bh(&ap->sta_table_lock); 509ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 510ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (!sta) 511ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return -EINVAL; 512ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 513ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen resp = cpu_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID); 5144339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen prism2_send_mgmt(dev, IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_DEAUTH, 515ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen (char *) &resp, 2, sta->addr, 0); 516ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 517ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap) 518ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen hostap_event_expired_sta(dev, sta); 519ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 520ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen ap_free_sta(ap, sta); 521ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 522ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return 0; 523ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen} 524ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 525ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ 526ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 527ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 5285fad5a2e1f34b333a801b749c4e143c2ac3e8a4fAdrian Bunkvoid ap_control_kickall(struct ap_data *ap) 529ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{ 530ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct list_head *ptr, *n; 531ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct sta_info *sta; 53274fae82c8bd5dd78365abe25506a9ba388d4a889Jeff Garzik 533ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen spin_lock_bh(&ap->sta_table_lock); 534ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen for (ptr = ap->sta_list.next, n = ptr->next; ptr != &ap->sta_list; 535ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen ptr = n, n = ptr->next) { 536ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta = list_entry(ptr, struct sta_info, list); 537ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen ap_sta_hash_del(ap, sta); 538ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen list_del(&sta->list); 539ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap && sta->local) 540ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen hostap_event_expired_sta(sta->local->dev, sta); 541ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen ap_free_sta(ap, sta); 542ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 543ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen spin_unlock_bh(&ap->sta_table_lock); 544ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen} 545ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 546ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 547ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT 548ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 5496bbefe86796c07fb8a6d28114f1e3f770586ba05David Howellsstatic int prism2_ap_proc_show(struct seq_file *m, void *v) 550ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{ 5516bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells struct sta_info *sta = v; 552ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen int i; 553ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 5546bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells if (v == SEQ_START_TOKEN) { 5556bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells seq_printf(m, "# BSSID CHAN SIGNAL NOISE RATE SSID FLAGS\n"); 556ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return 0; 557ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 558ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 5596bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells if (!sta->ap) 560ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return 0; 5616bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells 5626bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells seq_printf(m, "%pM %d %d %d %d '", 5636bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells sta->addr, 5646bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells sta->u.ap.channel, sta->last_rx_signal, 5656bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells sta->last_rx_silence, sta->last_rx_rate); 5666bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells 5676bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells for (i = 0; i < sta->u.ap.ssid_len; i++) { 5686bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells if (sta->u.ap.ssid[i] >= 32 && sta->u.ap.ssid[i] < 127) 5696bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells seq_putc(m, sta->u.ap.ssid[i]); 5706bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells else 5716bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells seq_printf(m, "<%02x>", sta->u.ap.ssid[i]); 572ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 573ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 5746bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells seq_putc(m, '\''); 5756bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells if (sta->capability & WLAN_CAPABILITY_ESS) 5766bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells seq_puts(m, " [ESS]"); 5776bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells if (sta->capability & WLAN_CAPABILITY_IBSS) 5786bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells seq_puts(m, " [IBSS]"); 5796bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells if (sta->capability & WLAN_CAPABILITY_PRIVACY) 5806bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells seq_puts(m, " [WEP]"); 5816bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells seq_putc(m, '\n'); 5826bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells return 0; 5836bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells} 584ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 5856bbefe86796c07fb8a6d28114f1e3f770586ba05David Howellsstatic void *prism2_ap_proc_start(struct seq_file *m, loff_t *_pos) 5866bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells{ 5876bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells struct ap_data *ap = m->private; 5886bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells spin_lock_bh(&ap->sta_table_lock); 5896bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells return seq_list_start_head(&ap->sta_list, *_pos); 5906bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells} 5916bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells 5926bbefe86796c07fb8a6d28114f1e3f770586ba05David Howellsstatic void *prism2_ap_proc_next(struct seq_file *m, void *v, loff_t *_pos) 5936bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells{ 5946bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells struct ap_data *ap = m->private; 5956bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells return seq_list_next(v, &ap->sta_list, _pos); 596ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen} 5976bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells 5986bbefe86796c07fb8a6d28114f1e3f770586ba05David Howellsstatic void prism2_ap_proc_stop(struct seq_file *m, void *v) 5996bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells{ 6006bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells struct ap_data *ap = m->private; 6016bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells spin_unlock_bh(&ap->sta_table_lock); 6026bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells} 6036bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells 6046bbefe86796c07fb8a6d28114f1e3f770586ba05David Howellsstatic const struct seq_operations prism2_ap_proc_seqops = { 6056bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells .start = prism2_ap_proc_start, 6066bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells .next = prism2_ap_proc_next, 6076bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells .stop = prism2_ap_proc_stop, 6086bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells .show = prism2_ap_proc_show, 6096bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells}; 6106bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells 6116bbefe86796c07fb8a6d28114f1e3f770586ba05David Howellsstatic int prism2_ap_proc_open(struct inode *inode, struct file *file) 6126bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells{ 6136bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells int ret = seq_open(file, &prism2_ap_proc_seqops); 6146bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells if (ret == 0) { 6156bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells struct seq_file *m = file->private_data; 6166bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells m->private = PDE_DATA(inode); 6176bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells } 6186bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells return ret; 6196bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells} 6206bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells 6216bbefe86796c07fb8a6d28114f1e3f770586ba05David Howellsstatic const struct file_operations prism2_ap_proc_fops = { 6226bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells .open = prism2_ap_proc_open, 6236bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells .read = seq_read, 6246bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells .llseek = seq_lseek, 6256bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells .release = seq_release, 6266bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells}; 627ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ 628ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 629ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 630ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenvoid hostap_check_sta_fw_version(struct ap_data *ap, int sta_fw_ver) 631ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{ 632ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (!ap) 633ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return; 634ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 635ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (sta_fw_ver == PRISM2_FW_VER(0,8,0)) { 636ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen PDEBUG(DEBUG_AP, "Using data::nullfunc ACK workaround - " 637ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen "firmware upgrade recommended\n"); 638ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen ap->nullfunc_ack = 1; 639ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } else 640ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen ap->nullfunc_ack = 0; 641ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 642ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (sta_fw_ver == PRISM2_FW_VER(1,4,2)) { 643ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen printk(KERN_WARNING "%s: Warning: secondary station firmware " 644ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen "version 1.4.2 does not seem to work in Host AP mode\n", 645ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen ap->local->dev->name); 646ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 647ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen} 648ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 649ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 650ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen/* Called only as a tasklet (software IRQ) */ 651ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenstatic void hostap_ap_tx_cb(struct sk_buff *skb, int ok, void *data) 652ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{ 653ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct ap_data *ap = data; 6541ea893fde29d8cf1639da8989f4b843dc3283ca8Dan Williams struct ieee80211_hdr *hdr; 655ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 656ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (!ap->local->hostapd || !ap->local->apdev) { 657ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen dev_kfree_skb(skb); 658ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return; 659ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 660ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 661ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen /* Pass the TX callback frame to the hostapd; use 802.11 header version 662ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * 1 to indicate failure (no ACK) and 2 success (frame ACKed) */ 663ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 6641ea893fde29d8cf1639da8989f4b843dc3283ca8Dan Williams hdr = (struct ieee80211_hdr *) skb->data; 6651ea893fde29d8cf1639da8989f4b843dc3283ca8Dan Williams hdr->frame_control &= cpu_to_le16(~IEEE80211_FCTL_VERS); 6661ea893fde29d8cf1639da8989f4b843dc3283ca8Dan Williams hdr->frame_control |= cpu_to_le16(ok ? BIT(1) : BIT(0)); 667ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 668ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen skb->dev = ap->local->apdev; 6691ea893fde29d8cf1639da8989f4b843dc3283ca8Dan Williams skb_pull(skb, hostap_80211_get_hdrlen(hdr->frame_control)); 670ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen skb->pkt_type = PACKET_OTHERHOST; 671c1b4aa3fb619782213af2af6652663c8f9cef373Harvey Harrison skb->protocol = cpu_to_be16(ETH_P_802_2); 672ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen memset(skb->cb, 0, sizeof(skb->cb)); 673ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen netif_rx(skb); 674ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen} 675ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 676ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 677ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT 678ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen/* Called only as a tasklet (software IRQ) */ 679ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenstatic void hostap_ap_tx_cb_auth(struct sk_buff *skb, int ok, void *data) 680ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{ 681ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct ap_data *ap = data; 682ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct net_device *dev = ap->local->dev; 6831ea893fde29d8cf1639da8989f4b843dc3283ca8Dan Williams struct ieee80211_hdr *hdr; 6841ea893fde29d8cf1639da8989f4b843dc3283ca8Dan Williams u16 auth_alg, auth_transaction, status; 6858a9faf3cd08b91aca1502dbe18e3b5063fda2e87Al Viro __le16 *pos; 686ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct sta_info *sta = NULL; 687ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen char *txt = NULL; 688ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 689ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (ap->local->hostapd) { 690ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen dev_kfree_skb(skb); 691ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return; 692ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 693ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 6941ea893fde29d8cf1639da8989f4b843dc3283ca8Dan Williams hdr = (struct ieee80211_hdr *) skb->data; 6951ea893fde29d8cf1639da8989f4b843dc3283ca8Dan Williams if (!ieee80211_is_auth(hdr->frame_control) || 696ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen skb->len < IEEE80211_MGMT_HDR_LEN + 6) { 697ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen printk(KERN_DEBUG "%s: hostap_ap_tx_cb_auth received invalid " 698ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen "frame\n", dev->name); 699ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen dev_kfree_skb(skb); 700ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return; 701ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 702ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 7038a9faf3cd08b91aca1502dbe18e3b5063fda2e87Al Viro pos = (__le16 *) (skb->data + IEEE80211_MGMT_HDR_LEN); 704ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen auth_alg = le16_to_cpu(*pos++); 705ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen auth_transaction = le16_to_cpu(*pos++); 706ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen status = le16_to_cpu(*pos++); 707ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 708ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (!ok) { 709ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen txt = "frame was not ACKed"; 710ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen goto done; 711ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 712ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 713ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen spin_lock(&ap->sta_table_lock); 714ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta = ap_get_sta(ap, hdr->addr1); 715ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (sta) 716ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen atomic_inc(&sta->users); 717ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen spin_unlock(&ap->sta_table_lock); 718ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 719ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (!sta) { 720ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen txt = "STA not found"; 721ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen goto done; 722ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 723ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 724ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (status == WLAN_STATUS_SUCCESS && 725ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen ((auth_alg == WLAN_AUTH_OPEN && auth_transaction == 2) || 726ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen (auth_alg == WLAN_AUTH_SHARED_KEY && auth_transaction == 4))) { 727ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen txt = "STA authenticated"; 728ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->flags |= WLAN_STA_AUTH; 729ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->last_auth = jiffies; 730ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } else if (status != WLAN_STATUS_SUCCESS) 731ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen txt = "authentication failed"; 732ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 733ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen done: 734ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (sta) 735ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen atomic_dec(&sta->users); 736ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (txt) { 737e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg PDEBUG(DEBUG_AP, "%s: %pM auth_cb - alg=%d " 7380795af5729b18218767fab27c44b1384f72dc9adJoe Perches "trans#=%d status=%d - %s\n", 739e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg dev->name, hdr->addr1, 74021f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller auth_alg, auth_transaction, status, txt); 741ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 742ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen dev_kfree_skb(skb); 743ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen} 744ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 745ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 746ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen/* Called only as a tasklet (software IRQ) */ 747ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenstatic void hostap_ap_tx_cb_assoc(struct sk_buff *skb, int ok, void *data) 748ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{ 749ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct ap_data *ap = data; 750ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct net_device *dev = ap->local->dev; 7511ea893fde29d8cf1639da8989f4b843dc3283ca8Dan Williams struct ieee80211_hdr *hdr; 7521baf8a90bd5ad61bc0c55521cc097586531e7eb7Justin P. Mattock u16 status; 7538a9faf3cd08b91aca1502dbe18e3b5063fda2e87Al Viro __le16 *pos; 754ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct sta_info *sta = NULL; 755ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen char *txt = NULL; 756ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 757ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (ap->local->hostapd) { 758ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen dev_kfree_skb(skb); 759ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return; 760ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 761ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 7621ea893fde29d8cf1639da8989f4b843dc3283ca8Dan Williams hdr = (struct ieee80211_hdr *) skb->data; 7631ea893fde29d8cf1639da8989f4b843dc3283ca8Dan Williams if ((!ieee80211_is_assoc_resp(hdr->frame_control) && 7641ea893fde29d8cf1639da8989f4b843dc3283ca8Dan Williams !ieee80211_is_reassoc_resp(hdr->frame_control)) || 765ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen skb->len < IEEE80211_MGMT_HDR_LEN + 4) { 766ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen printk(KERN_DEBUG "%s: hostap_ap_tx_cb_assoc received invalid " 767ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen "frame\n", dev->name); 768ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen dev_kfree_skb(skb); 769ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return; 770ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 771ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 772ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (!ok) { 773ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen txt = "frame was not ACKed"; 774ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen goto done; 775ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 776ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 777ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen spin_lock(&ap->sta_table_lock); 778ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta = ap_get_sta(ap, hdr->addr1); 779ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (sta) 780ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen atomic_inc(&sta->users); 781ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen spin_unlock(&ap->sta_table_lock); 782ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 783ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (!sta) { 784ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen txt = "STA not found"; 785ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen goto done; 786ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 787ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 7888a9faf3cd08b91aca1502dbe18e3b5063fda2e87Al Viro pos = (__le16 *) (skb->data + IEEE80211_MGMT_HDR_LEN); 789ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen pos++; 790ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen status = le16_to_cpu(*pos++); 791ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (status == WLAN_STATUS_SUCCESS) { 792ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (!(sta->flags & WLAN_STA_ASSOC)) 793ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen hostap_event_new_sta(dev, sta); 794ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen txt = "STA associated"; 795ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->flags |= WLAN_STA_ASSOC; 796ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->last_assoc = jiffies; 797ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } else 798ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen txt = "association failed"; 799ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 800ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen done: 801ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (sta) 802ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen atomic_dec(&sta->users); 803ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (txt) { 804e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg PDEBUG(DEBUG_AP, "%s: %pM assoc_cb - %s\n", 805e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg dev->name, hdr->addr1, txt); 806ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 807ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen dev_kfree_skb(skb); 808ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen} 809ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 810ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen/* Called only as a tasklet (software IRQ); TX callback for poll frames used 811ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * in verifying whether the STA is still present. */ 812ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenstatic void hostap_ap_tx_cb_poll(struct sk_buff *skb, int ok, void *data) 813ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{ 814ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct ap_data *ap = data; 8151ea893fde29d8cf1639da8989f4b843dc3283ca8Dan Williams struct ieee80211_hdr *hdr; 816ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct sta_info *sta; 817ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 818ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (skb->len < 24) 819ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen goto fail; 8201ea893fde29d8cf1639da8989f4b843dc3283ca8Dan Williams hdr = (struct ieee80211_hdr *) skb->data; 821ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (ok) { 822ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen spin_lock(&ap->sta_table_lock); 823ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta = ap_get_sta(ap, hdr->addr1); 824ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (sta) 825ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->flags &= ~WLAN_STA_PENDING_POLL; 826ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen spin_unlock(&ap->sta_table_lock); 827ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } else { 828e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg PDEBUG(DEBUG_AP, 829e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg "%s: STA %pM did not ACK activity poll frame\n", 830e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg ap->local->dev->name, hdr->addr1); 831ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 832ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 833ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen fail: 834ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen dev_kfree_skb(skb); 835ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen} 836ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ 837ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 838ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 839ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenvoid hostap_init_data(local_info_t *local) 840ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{ 841ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct ap_data *ap = local->ap; 842ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 843ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (ap == NULL) { 844ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen printk(KERN_WARNING "hostap_init_data: ap == NULL\n"); 845ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return; 846ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 847ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen memset(ap, 0, sizeof(struct ap_data)); 848ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen ap->local = local; 849ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 850ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen ap->ap_policy = GET_INT_PARM(other_ap_policy, local->card_idx); 851ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen ap->bridge_packets = GET_INT_PARM(ap_bridge_packets, local->card_idx); 852ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen ap->max_inactivity = 853ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen GET_INT_PARM(ap_max_inactivity, local->card_idx) * HZ; 854ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen ap->autom_ap_wds = GET_INT_PARM(autom_ap_wds, local->card_idx); 855ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 856ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen spin_lock_init(&ap->sta_table_lock); 857ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen INIT_LIST_HEAD(&ap->sta_list); 858ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 859ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen /* Initialize task queue structure for AP management */ 860c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howells INIT_WORK(&local->ap->add_sta_proc_queue, handle_add_proc_queue); 861ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 862ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen ap->tx_callback_idx = 863ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen hostap_tx_callback_register(local, hostap_ap_tx_cb, ap); 864ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (ap->tx_callback_idx == 0) 865ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen printk(KERN_WARNING "%s: failed to register TX callback for " 866ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen "AP\n", local->dev->name); 867ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT 868c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howells INIT_WORK(&local->ap->wds_oper_queue, handle_wds_oper_queue); 869ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 870ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen ap->tx_callback_auth = 871ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen hostap_tx_callback_register(local, hostap_ap_tx_cb_auth, ap); 872ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen ap->tx_callback_assoc = 873ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen hostap_tx_callback_register(local, hostap_ap_tx_cb_assoc, ap); 874ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen ap->tx_callback_poll = 875ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen hostap_tx_callback_register(local, hostap_ap_tx_cb_poll, ap); 876ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (ap->tx_callback_auth == 0 || ap->tx_callback_assoc == 0 || 877ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen ap->tx_callback_poll == 0) 878ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen printk(KERN_WARNING "%s: failed to register TX callback for " 879ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen "AP\n", local->dev->name); 880ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 881ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen spin_lock_init(&ap->mac_restrictions.lock); 882ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen INIT_LIST_HEAD(&ap->mac_restrictions.mac_list); 883ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ 884ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 885ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen ap->initialized = 1; 886ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen} 887ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 888ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 889ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenvoid hostap_init_ap_proc(local_info_t *local) 890ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{ 891ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct ap_data *ap = local->ap; 892ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 893ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen ap->proc = local->proc; 894ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (ap->proc == NULL) 895ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return; 896ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 897ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#ifndef PRISM2_NO_PROCFS_DEBUG 8986bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells proc_create_data("ap_debug", 0, ap->proc, &ap_debug_proc_fops, ap); 899ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#endif /* PRISM2_NO_PROCFS_DEBUG */ 900ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 901ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT 9026bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells proc_create_data("ap_control", 0, ap->proc, &ap_control_proc_fops, ap); 9036bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells proc_create_data("ap", 0, ap->proc, &prism2_ap_proc_fops, ap); 904ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ 905ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 906ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen} 907ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 908ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 909ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenvoid hostap_free_data(struct ap_data *ap) 910ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{ 911c15057313725942c6af8dcb60b4d4322101316d9Matthias Kaehlcke struct sta_info *n, *sta; 912ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 913ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (ap == NULL || !ap->initialized) { 914ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen printk(KERN_DEBUG "hostap_free_data: ap has not yet been " 915ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen "initialized - skip resource freeing\n"); 916ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return; 917ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 918ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 91943829731dd372d04d6706c51052b9dabab9ca356Tejun Heo flush_work(&ap->add_sta_proc_queue); 9201635953305694ece16d99078ca6d32f3d4e7eb36Tejun Heo 921ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT 92243829731dd372d04d6706c51052b9dabab9ca356Tejun Heo flush_work(&ap->wds_oper_queue); 923ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (ap->crypt) 924ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen ap->crypt->deinit(ap->crypt_priv); 925ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen ap->crypt = ap->crypt_priv = NULL; 926ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ 927ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 928c15057313725942c6af8dcb60b4d4322101316d9Matthias Kaehlcke list_for_each_entry_safe(sta, n, &ap->sta_list, list) { 929ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen ap_sta_hash_del(ap, sta); 930ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen list_del(&sta->list); 931ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap && sta->local) 932ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen hostap_event_expired_sta(sta->local->dev, sta); 933ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen ap_free_sta(ap, sta); 934ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 935ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 936ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#ifndef PRISM2_NO_PROCFS_DEBUG 937ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (ap->proc != NULL) { 938ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen remove_proc_entry("ap_debug", ap->proc); 939ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 940ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#endif /* PRISM2_NO_PROCFS_DEBUG */ 941ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 942ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT 943ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (ap->proc != NULL) { 944ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen remove_proc_entry("ap", ap->proc); 945ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen remove_proc_entry("ap_control", ap->proc); 946ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 947ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen ap_control_flush_macs(&ap->mac_restrictions); 948ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ 949ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 950ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen ap->initialized = 0; 951ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen} 952ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 953ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 954ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen/* caller should have mutex for AP STA list handling */ 955ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenstatic struct sta_info* ap_get_sta(struct ap_data *ap, u8 *sta) 956ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{ 957ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct sta_info *s; 958ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 959ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen s = ap->sta_hash[STA_HASH(sta)]; 960d22fbd70c2770b5e3ba0d7bc5b29f6ee686cdba4dingtianhong while (s != NULL && !ether_addr_equal(s->addr, sta)) 961ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen s = s->hnext; 962ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return s; 963ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen} 964ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 965ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 966ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT 967ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 968ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen/* Called from timer handler and from scheduled AP queue handlers */ 969ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenstatic void prism2_send_mgmt(struct net_device *dev, 9704339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen u16 type_subtype, char *body, 971ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen int body_len, u8 *addr, u16 tx_cb_idx) 972ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{ 973ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct hostap_interface *iface; 974ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen local_info_t *local; 9751ea893fde29d8cf1639da8989f4b843dc3283ca8Dan Williams struct ieee80211_hdr *hdr; 976ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen u16 fc; 977ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct sk_buff *skb; 978ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct hostap_skb_tx_data *meta; 979ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen int hdrlen; 980ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 981ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen iface = netdev_priv(dev); 982ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen local = iface->local; 983ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen dev = local->dev; /* always use master radio device */ 984ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen iface = netdev_priv(dev); 985ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 986ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (!(dev->flags & IFF_UP)) { 987ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen PDEBUG(DEBUG_AP, "%s: prism2_send_mgmt - device is not UP - " 988ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen "cannot send frame\n", dev->name); 989ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return; 990ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 991ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 992ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen skb = dev_alloc_skb(sizeof(*hdr) + body_len); 993ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (skb == NULL) { 994ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen PDEBUG(DEBUG_AP, "%s: prism2_send_mgmt failed to allocate " 995ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen "skb\n", dev->name); 996ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return; 997ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 998ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 9994339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen fc = type_subtype; 10001ea893fde29d8cf1639da8989f4b843dc3283ca8Dan Williams hdrlen = hostap_80211_get_hdrlen(cpu_to_le16(type_subtype)); 10011ea893fde29d8cf1639da8989f4b843dc3283ca8Dan Williams hdr = (struct ieee80211_hdr *) skb_put(skb, hdrlen); 1002ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (body) 1003ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen memcpy(skb_put(skb, body_len), body, body_len); 1004ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1005ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen memset(hdr, 0, hdrlen); 1006ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1007ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen /* FIX: ctrl::ack sending used special HFA384X_TX_CTRL_802_11 1008ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * tx_control instead of using local->tx_control */ 1009ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1010ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1011ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen memcpy(hdr->addr1, addr, ETH_ALEN); /* DA / RA */ 10121ea893fde29d8cf1639da8989f4b843dc3283ca8Dan Williams if (ieee80211_is_data(hdr->frame_control)) { 1013b2f4a2e3b1620667da9654f9e220c92ea52bdbe4Jouni Malinen fc |= IEEE80211_FCTL_FROMDS; 1014ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen memcpy(hdr->addr2, dev->dev_addr, ETH_ALEN); /* BSSID */ 1015ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen memcpy(hdr->addr3, dev->dev_addr, ETH_ALEN); /* SA */ 10161ea893fde29d8cf1639da8989f4b843dc3283ca8Dan Williams } else if (ieee80211_is_ctl(hdr->frame_control)) { 1017ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen /* control:ACK does not have addr2 or addr3 */ 1018ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen memset(hdr->addr2, 0, ETH_ALEN); 1019ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen memset(hdr->addr3, 0, ETH_ALEN); 1020ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } else { 1021ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen memcpy(hdr->addr2, dev->dev_addr, ETH_ALEN); /* SA */ 1022ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen memcpy(hdr->addr3, dev->dev_addr, ETH_ALEN); /* BSSID */ 1023ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 1024ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 10251ea893fde29d8cf1639da8989f4b843dc3283ca8Dan Williams hdr->frame_control = cpu_to_le16(fc); 1026ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1027ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen meta = (struct hostap_skb_tx_data *) skb->cb; 1028ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen memset(meta, 0, sizeof(*meta)); 1029ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen meta->magic = HOSTAP_SKB_TX_DATA_MAGIC; 1030ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen meta->iface = iface; 1031ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen meta->tx_cb_idx = tx_cb_idx; 1032ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1033ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen skb->dev = dev; 1034459a98ed881802dee55897441bc7f77af614368eArnaldo Carvalho de Melo skb_reset_mac_header(skb); 1035c1d2bbe1cd6c7bbdc6d532cefebb66c7efb789ceArnaldo Carvalho de Melo skb_reset_network_header(skb); 1036ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen dev_queue_xmit(skb); 1037ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen} 1038ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ 1039ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1040ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 10416bbefe86796c07fb8a6d28114f1e3f770586ba05David Howellsstatic int prism2_sta_proc_show(struct seq_file *m, void *v) 1042ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{ 10436bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells struct sta_info *sta = m->private; 1044ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen int i; 1045ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1046ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen /* FIX: possible race condition.. the STA data could have just expired, 1047ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * but proc entry was still here so that the read could have started; 1048ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * some locking should be done here.. */ 1049ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 10506bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells seq_printf(m, 10516bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells "%s=%pM\nusers=%d\naid=%d\n" 10526bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells "flags=0x%04x%s%s%s%s%s%s%s\n" 10536bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells "capability=0x%02x\nlisten_interval=%d\nsupported_rates=", 10546bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells sta->ap ? "AP" : "STA", 10556bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells sta->addr, atomic_read(&sta->users), sta->aid, 10566bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells sta->flags, 10576bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells sta->flags & WLAN_STA_AUTH ? " AUTH" : "", 10586bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells sta->flags & WLAN_STA_ASSOC ? " ASSOC" : "", 10596bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells sta->flags & WLAN_STA_PS ? " PS" : "", 10606bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells sta->flags & WLAN_STA_TIM ? " TIM" : "", 10616bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells sta->flags & WLAN_STA_PERM ? " PERM" : "", 10626bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells sta->flags & WLAN_STA_AUTHORIZED ? " AUTHORIZED" : "", 10636bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells sta->flags & WLAN_STA_PENDING_POLL ? " POLL" : "", 10646bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells sta->capability, sta->listen_interval); 1065ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen /* supported_rates: 500 kbit/s units with msb ignored */ 1066ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen for (i = 0; i < sizeof(sta->supported_rates); i++) 1067ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (sta->supported_rates[i] != 0) 10686bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells seq_printf(m, "%d%sMbps ", 10696bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells (sta->supported_rates[i] & 0x7f) / 2, 10706bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells sta->supported_rates[i] & 1 ? ".5" : ""); 10716bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells seq_printf(m, 10726bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells "\njiffies=%lu\nlast_auth=%lu\nlast_assoc=%lu\n" 10736bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells "last_rx=%lu\nlast_tx=%lu\nrx_packets=%lu\n" 10746bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells "tx_packets=%lu\n" 10756bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells "rx_bytes=%lu\ntx_bytes=%lu\nbuffer_count=%d\n" 10766bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells "last_rx: silence=%d dBm signal=%d dBm rate=%d%s Mbps\n" 10776bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells "tx_rate=%d\ntx[1M]=%d\ntx[2M]=%d\ntx[5.5M]=%d\n" 10786bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells "tx[11M]=%d\n" 10796bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells "rx[1M]=%d\nrx[2M]=%d\nrx[5.5M]=%d\nrx[11M]=%d\n", 10806bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells jiffies, sta->last_auth, sta->last_assoc, sta->last_rx, 10816bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells sta->last_tx, 10826bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells sta->rx_packets, sta->tx_packets, sta->rx_bytes, 10836bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells sta->tx_bytes, skb_queue_len(&sta->tx_buf), 10846bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells sta->last_rx_silence, 10856bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells sta->last_rx_signal, sta->last_rx_rate / 10, 10866bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells sta->last_rx_rate % 10 ? ".5" : "", 10876bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells sta->tx_rate, sta->tx_count[0], sta->tx_count[1], 10886bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells sta->tx_count[2], sta->tx_count[3], sta->rx_count[0], 10896bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells sta->rx_count[1], sta->rx_count[2], sta->rx_count[3]); 1090ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (sta->crypt && sta->crypt->ops && sta->crypt->ops->print_stats) 10916bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells sta->crypt->ops->print_stats(m, sta->crypt->priv); 1092ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT 1093ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (sta->ap) { 1094ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (sta->u.ap.channel >= 0) 10956bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells seq_printf(m, "channel=%d\n", sta->u.ap.channel); 10966bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells seq_puts(m, "ssid="); 10976bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells for (i = 0; i < sta->u.ap.ssid_len; i++) { 10986bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells if (sta->u.ap.ssid[i] >= 32 && sta->u.ap.ssid[i] < 127) 10996bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells seq_putc(m, sta->u.ap.ssid[i]); 11006bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells else 11016bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells seq_printf(m, "<%02x>", sta->u.ap.ssid[i]); 11026bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells } 11036bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells seq_putc(m, '\n'); 1104ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 1105ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ 1106ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 11076bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells return 0; 11086bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells} 11096bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells 11106bbefe86796c07fb8a6d28114f1e3f770586ba05David Howellsstatic int prism2_sta_proc_open(struct inode *inode, struct file *file) 11116bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells{ 11126bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells return single_open(file, prism2_sta_proc_show, PDE_DATA(inode)); 1113ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen} 1114ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 11156bbefe86796c07fb8a6d28114f1e3f770586ba05David Howellsstatic const struct file_operations prism2_sta_proc_fops = { 11166bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells .open = prism2_sta_proc_open, 11176bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells .read = seq_read, 11186bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells .llseek = seq_lseek, 1119bc3041f055c228ec8347580d95cb2b344b503dcbAl Viro .release = single_release, 11206bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells}; 1121ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1122c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howellsstatic void handle_add_proc_queue(struct work_struct *work) 1123ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{ 1124c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howells struct ap_data *ap = container_of(work, struct ap_data, 1125c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howells add_sta_proc_queue); 1126ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct sta_info *sta; 1127ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen char name[20]; 1128ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct add_sta_proc_data *entry, *prev; 1129ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1130ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen entry = ap->add_sta_proc_entries; 1131ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen ap->add_sta_proc_entries = NULL; 1132ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1133ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen while (entry) { 1134ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen spin_lock_bh(&ap->sta_table_lock); 1135ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta = ap_get_sta(ap, entry->addr); 1136ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (sta) 1137ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen atomic_inc(&sta->users); 1138ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen spin_unlock_bh(&ap->sta_table_lock); 1139ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1140ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (sta) { 1141e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg sprintf(name, "%pM", sta->addr); 11426bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells sta->proc = proc_create_data( 1143ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen name, 0, ap->proc, 11446bbefe86796c07fb8a6d28114f1e3f770586ba05David Howells &prism2_sta_proc_fops, sta); 1145ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1146ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen atomic_dec(&sta->users); 1147ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 1148ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1149ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen prev = entry; 1150ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen entry = entry->next; 1151ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen kfree(prev); 1152ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 1153ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen} 1154ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1155ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1156ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenstatic struct sta_info * ap_add_sta(struct ap_data *ap, u8 *addr) 1157ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{ 1158ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct sta_info *sta; 1159ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1160b0471bb7b779f5deea109e5bfdfe8c18d4a06241Yan Burman sta = kzalloc(sizeof(struct sta_info), GFP_ATOMIC); 1161ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (sta == NULL) { 1162ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen PDEBUG(DEBUG_AP, "AP: kmalloc failed\n"); 1163ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return NULL; 1164ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 1165ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1166ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen /* initialize STA info data */ 1167ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->local = ap->local; 1168ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen skb_queue_head_init(&sta->tx_buf); 1169ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen memcpy(sta->addr, addr, ETH_ALEN); 1170ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1171ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen atomic_inc(&sta->users); 1172ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen spin_lock_bh(&ap->sta_table_lock); 1173ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen list_add(&sta->list, &ap->sta_list); 1174ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen ap->num_sta++; 1175ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen ap_sta_hash_add(ap, sta); 1176ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen spin_unlock_bh(&ap->sta_table_lock); 1177ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1178ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (ap->proc) { 1179ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct add_sta_proc_data *entry; 1180ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen /* schedule a non-interrupt context process to add a procfs 1181ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * entry for the STA since procfs code use GFP_KERNEL */ 1182ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen entry = kmalloc(sizeof(*entry), GFP_ATOMIC); 1183ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (entry) { 1184ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen memcpy(entry->addr, sta->addr, ETH_ALEN); 1185ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen entry->next = ap->add_sta_proc_entries; 1186ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen ap->add_sta_proc_entries = entry; 1187ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen schedule_work(&ap->add_sta_proc_queue); 1188ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } else 1189ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen printk(KERN_DEBUG "Failed to add STA proc data\n"); 1190ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 1191ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1192ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT 1193ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen init_timer(&sta->timer); 1194ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->timer.expires = jiffies + ap->max_inactivity; 1195ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->timer.data = (unsigned long) sta; 1196ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->timer.function = ap_handle_timer; 1197ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (!ap->local->hostapd) 1198ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen add_timer(&sta->timer); 1199ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ 1200ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1201ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return sta; 1202ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen} 1203ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1204ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1205ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenstatic int ap_tx_rate_ok(int rateidx, struct sta_info *sta, 1206ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen local_info_t *local) 1207ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{ 1208ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (rateidx > sta->tx_max_rate || 1209ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen !(sta->tx_supp_rates & (1 << rateidx))) 1210ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return 0; 1211ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1212ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (local->tx_rate_control != 0 && 1213ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen !(local->tx_rate_control & (1 << rateidx))) 1214ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return 0; 1215ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1216ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return 1; 1217ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen} 1218ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1219ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1220ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenstatic void prism2_check_tx_rates(struct sta_info *sta) 1221ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{ 1222ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen int i; 1223ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1224ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->tx_supp_rates = 0; 1225ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen for (i = 0; i < sizeof(sta->supported_rates); i++) { 1226ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if ((sta->supported_rates[i] & 0x7f) == 2) 1227ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->tx_supp_rates |= WLAN_RATE_1M; 1228ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if ((sta->supported_rates[i] & 0x7f) == 4) 1229ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->tx_supp_rates |= WLAN_RATE_2M; 1230ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if ((sta->supported_rates[i] & 0x7f) == 11) 1231ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->tx_supp_rates |= WLAN_RATE_5M5; 1232ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if ((sta->supported_rates[i] & 0x7f) == 22) 1233ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->tx_supp_rates |= WLAN_RATE_11M; 1234ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 1235ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->tx_max_rate = sta->tx_rate = sta->tx_rate_idx = 0; 1236ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (sta->tx_supp_rates & WLAN_RATE_1M) { 1237ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->tx_max_rate = 0; 1238ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (ap_tx_rate_ok(0, sta, sta->local)) { 1239ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->tx_rate = 10; 1240ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->tx_rate_idx = 0; 1241ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 1242ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 1243ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (sta->tx_supp_rates & WLAN_RATE_2M) { 1244ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->tx_max_rate = 1; 1245ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (ap_tx_rate_ok(1, sta, sta->local)) { 1246ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->tx_rate = 20; 1247ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->tx_rate_idx = 1; 1248ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 1249ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 1250ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (sta->tx_supp_rates & WLAN_RATE_5M5) { 1251ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->tx_max_rate = 2; 1252ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (ap_tx_rate_ok(2, sta, sta->local)) { 1253ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->tx_rate = 55; 1254ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->tx_rate_idx = 2; 1255ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 1256ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 1257ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (sta->tx_supp_rates & WLAN_RATE_11M) { 1258ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->tx_max_rate = 3; 1259ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (ap_tx_rate_ok(3, sta, sta->local)) { 1260ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->tx_rate = 110; 1261ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->tx_rate_idx = 3; 1262ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 1263ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 1264ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen} 1265ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1266ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1267ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT 1268ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1269ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenstatic void ap_crypt_init(struct ap_data *ap) 1270ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{ 1271274bfb8dc5ffa16cb073801bebe76ab7f4e2e73dJohn W. Linville ap->crypt = lib80211_get_crypto_ops("WEP"); 1272ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1273ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (ap->crypt) { 1274ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (ap->crypt->init) { 1275ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen ap->crypt_priv = ap->crypt->init(0); 1276ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (ap->crypt_priv == NULL) 1277ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen ap->crypt = NULL; 1278ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen else { 1279ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen u8 key[WEP_KEY_LEN]; 1280ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen get_random_bytes(key, WEP_KEY_LEN); 1281ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen ap->crypt->set_key(key, WEP_KEY_LEN, NULL, 1282ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen ap->crypt_priv); 1283ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 1284ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 1285ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 1286ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1287ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (ap->crypt == NULL) { 1288ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen printk(KERN_WARNING "AP could not initialize WEP: load module " 1289274bfb8dc5ffa16cb073801bebe76ab7f4e2e73dJohn W. Linville "lib80211_crypt_wep.ko\n"); 1290ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 1291ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen} 1292ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1293ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1294ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen/* Generate challenge data for shared key authentication. IEEE 802.11 specifies 129525d1fbfdd98e6547f2ba3e36787f20d251019591Uwe Kleine-König * that WEP algorithm is used for generating challenge. This should be unique, 1296ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * but otherwise there is not really need for randomness etc. Initialize WEP 1297ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * with pseudo random key and then use increasing IV to get unique challenge 1298ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * streams. 1299ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * 1300ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * Called only as a scheduled task for pending AP frames. 1301ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen */ 1302ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenstatic char * ap_auth_make_challenge(struct ap_data *ap) 1303ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{ 1304ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen char *tmpbuf; 1305ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct sk_buff *skb; 1306ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1307ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (ap->crypt == NULL) { 1308ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen ap_crypt_init(ap); 1309ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (ap->crypt == NULL) 1310ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return NULL; 1311ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 1312ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 13135cbded585d129d0226cb48ac4202b253c781be26Robert P. J. Day tmpbuf = kmalloc(WLAN_AUTH_CHALLENGE_LEN, GFP_ATOMIC); 1314ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (tmpbuf == NULL) { 1315ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen PDEBUG(DEBUG_AP, "AP: kmalloc failed for challenge\n"); 1316ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return NULL; 1317ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 1318ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1319ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen skb = dev_alloc_skb(WLAN_AUTH_CHALLENGE_LEN + 13205bfc819b53ed67c76f33f969ab627070e85d87c1James Ketrenos ap->crypt->extra_mpdu_prefix_len + 13215bfc819b53ed67c76f33f969ab627070e85d87c1James Ketrenos ap->crypt->extra_mpdu_postfix_len); 1322ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (skb == NULL) { 1323ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen kfree(tmpbuf); 1324ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return NULL; 1325ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 1326ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 13275bfc819b53ed67c76f33f969ab627070e85d87c1James Ketrenos skb_reserve(skb, ap->crypt->extra_mpdu_prefix_len); 1328ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen memset(skb_put(skb, WLAN_AUTH_CHALLENGE_LEN), 0, 1329ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen WLAN_AUTH_CHALLENGE_LEN); 1330ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (ap->crypt->encrypt_mpdu(skb, 0, ap->crypt_priv)) { 1331ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen dev_kfree_skb(skb); 1332ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen kfree(tmpbuf); 1333ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return NULL; 1334ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 1335ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1336d626f62b11e00c16e81e4308ab93d3f13551812aArnaldo Carvalho de Melo skb_copy_from_linear_data_offset(skb, ap->crypt->extra_mpdu_prefix_len, 1337d626f62b11e00c16e81e4308ab93d3f13551812aArnaldo Carvalho de Melo tmpbuf, WLAN_AUTH_CHALLENGE_LEN); 1338ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen dev_kfree_skb(skb); 1339ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1340ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return tmpbuf; 1341ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen} 1342ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1343ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1344ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen/* Called only as a scheduled task for pending AP frames. */ 1345ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenstatic void handle_authen(local_info_t *local, struct sk_buff *skb, 1346ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct hostap_80211_rx_status *rx_stats) 1347ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{ 1348ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct net_device *dev = local->dev; 13491ea893fde29d8cf1639da8989f4b843dc3283ca8Dan Williams struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; 1350ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen size_t hdrlen; 1351ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct ap_data *ap = local->ap; 1352ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen char body[8 + WLAN_AUTH_CHALLENGE_LEN], *challenge = NULL; 1353ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen int len, olen; 13548a9faf3cd08b91aca1502dbe18e3b5063fda2e87Al Viro u16 auth_alg, auth_transaction, status_code; 13558a9faf3cd08b91aca1502dbe18e3b5063fda2e87Al Viro __le16 *pos; 13561ea893fde29d8cf1639da8989f4b843dc3283ca8Dan Williams u16 resp = WLAN_STATUS_SUCCESS; 1357ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct sta_info *sta = NULL; 1358274bfb8dc5ffa16cb073801bebe76ab7f4e2e73dJohn W. Linville struct lib80211_crypt_data *crypt; 1359ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen char *txt = ""; 1360ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1361ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen len = skb->len - IEEE80211_MGMT_HDR_LEN; 1362ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 13631ea893fde29d8cf1639da8989f4b843dc3283ca8Dan Williams hdrlen = hostap_80211_get_hdrlen(hdr->frame_control); 1364ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1365ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (len < 6) { 1366ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen PDEBUG(DEBUG_AP, "%s: handle_authen - too short payload " 1367e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg "(len=%d) from %pM\n", dev->name, len, hdr->addr2); 1368ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return; 1369ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 1370ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1371ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen spin_lock_bh(&local->ap->sta_table_lock); 1372ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta = ap_get_sta(local->ap, hdr->addr2); 1373ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (sta) 1374ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen atomic_inc(&sta->users); 1375ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen spin_unlock_bh(&local->ap->sta_table_lock); 1376ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1377ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (sta && sta->crypt) 1378ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen crypt = sta->crypt; 1379ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen else { 1380ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen int idx = 0; 1381ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (skb->len >= hdrlen + 3) 1382ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen idx = skb->data[hdrlen + 3] >> 6; 1383274bfb8dc5ffa16cb073801bebe76ab7f4e2e73dJohn W. Linville crypt = local->crypt_info.crypt[idx]; 1384ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 1385ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 13868a9faf3cd08b91aca1502dbe18e3b5063fda2e87Al Viro pos = (__le16 *) (skb->data + IEEE80211_MGMT_HDR_LEN); 1387ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen auth_alg = __le16_to_cpu(*pos); 1388ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen pos++; 1389ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen auth_transaction = __le16_to_cpu(*pos); 1390ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen pos++; 1391ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen status_code = __le16_to_cpu(*pos); 1392ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen pos++; 1393ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1394d22fbd70c2770b5e3ba0d7bc5b29f6ee686cdba4dingtianhong if (ether_addr_equal(dev->dev_addr, hdr->addr2) || 1395ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen ap_control_mac_deny(&ap->mac_restrictions, hdr->addr2)) { 1396ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen txt = "authentication denied"; 1397ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen resp = WLAN_STATUS_UNSPECIFIED_FAILURE; 1398ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen goto fail; 1399ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 1400ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1401ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (((local->auth_algs & PRISM2_AUTH_OPEN) && 1402ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen auth_alg == WLAN_AUTH_OPEN) || 1403ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen ((local->auth_algs & PRISM2_AUTH_SHARED_KEY) && 1404ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen crypt && auth_alg == WLAN_AUTH_SHARED_KEY)) { 1405ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } else { 1406ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen txt = "unsupported algorithm"; 1407ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen resp = WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG; 1408ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen goto fail; 1409ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 1410ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1411ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (len >= 8) { 1412ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen u8 *u = (u8 *) pos; 1413ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (*u == WLAN_EID_CHALLENGE) { 1414ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (*(u + 1) != WLAN_AUTH_CHALLENGE_LEN) { 1415ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen txt = "invalid challenge len"; 1416ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen resp = WLAN_STATUS_CHALLENGE_FAIL; 1417ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen goto fail; 1418ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 1419ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (len - 8 < WLAN_AUTH_CHALLENGE_LEN) { 1420ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen txt = "challenge underflow"; 1421ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen resp = WLAN_STATUS_CHALLENGE_FAIL; 1422ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen goto fail; 1423ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 1424ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen challenge = (char *) (u + 2); 1425ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 1426ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 1427ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1428ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (sta && sta->ap) { 1429ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (time_after(jiffies, sta->u.ap.last_beacon + 1430ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen (10 * sta->listen_interval * HZ) / 1024)) { 1431ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen PDEBUG(DEBUG_AP, "%s: no beacons received for a while," 1432e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg " assuming AP %pM is now STA\n", 1433e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg dev->name, sta->addr); 1434ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->ap = 0; 1435ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->flags = 0; 1436ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->u.sta.challenge = NULL; 1437ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } else { 1438ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen txt = "AP trying to authenticate?"; 1439ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen resp = WLAN_STATUS_UNSPECIFIED_FAILURE; 1440ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen goto fail; 1441ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 1442ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 1443ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1444ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if ((auth_alg == WLAN_AUTH_OPEN && auth_transaction == 1) || 1445ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen (auth_alg == WLAN_AUTH_SHARED_KEY && 1446ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen (auth_transaction == 1 || 1447ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen (auth_transaction == 3 && sta != NULL && 1448ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->u.sta.challenge != NULL)))) { 1449ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } else { 1450ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen txt = "unknown authentication transaction number"; 1451ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen resp = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION; 1452ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen goto fail; 1453ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 1454ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1455ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (sta == NULL) { 1456ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen txt = "new STA"; 1457ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1458ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (local->ap->num_sta >= MAX_STA_COUNT) { 1459ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen /* FIX: might try to remove some old STAs first? */ 1460ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen txt = "no more room for new STAs"; 1461ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen resp = WLAN_STATUS_UNSPECIFIED_FAILURE; 1462ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen goto fail; 1463ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 1464ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1465ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta = ap_add_sta(local->ap, hdr->addr2); 1466ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (sta == NULL) { 1467ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen txt = "ap_add_sta failed"; 1468ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen resp = WLAN_STATUS_UNSPECIFIED_FAILURE; 1469ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen goto fail; 1470ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 1471ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 1472ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1473ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen switch (auth_alg) { 1474ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen case WLAN_AUTH_OPEN: 1475ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen txt = "authOK"; 1476ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen /* IEEE 802.11 standard is not completely clear about 1477ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * whether STA is considered authenticated after 1478ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * authentication OK frame has been send or after it 1479ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * has been ACKed. In order to reduce interoperability 1480ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * issues, mark the STA authenticated before ACK. */ 1481ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->flags |= WLAN_STA_AUTH; 1482ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen break; 1483ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1484ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen case WLAN_AUTH_SHARED_KEY: 1485ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (auth_transaction == 1) { 1486ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (sta->u.sta.challenge == NULL) { 1487ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->u.sta.challenge = 1488ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen ap_auth_make_challenge(local->ap); 1489ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (sta->u.sta.challenge == NULL) { 1490ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen resp = WLAN_STATUS_UNSPECIFIED_FAILURE; 1491ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen goto fail; 1492ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 1493ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 1494ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } else { 1495ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (sta->u.sta.challenge == NULL || 1496ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen challenge == NULL || 1497ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen memcmp(sta->u.sta.challenge, challenge, 1498ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen WLAN_AUTH_CHALLENGE_LEN) != 0 || 14991ea893fde29d8cf1639da8989f4b843dc3283ca8Dan Williams !ieee80211_has_protected(hdr->frame_control)) { 1500ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen txt = "challenge response incorrect"; 1501ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen resp = WLAN_STATUS_CHALLENGE_FAIL; 1502ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen goto fail; 1503ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 1504ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1505ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen txt = "challenge OK - authOK"; 1506ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen /* IEEE 802.11 standard is not completely clear about 1507ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * whether STA is considered authenticated after 1508ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * authentication OK frame has been send or after it 1509ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * has been ACKed. In order to reduce interoperability 1510ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * issues, mark the STA authenticated before ACK. */ 1511ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->flags |= WLAN_STA_AUTH; 1512ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen kfree(sta->u.sta.challenge); 1513ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->u.sta.challenge = NULL; 1514ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 1515ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen break; 1516ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 1517ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1518ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen fail: 15198a9faf3cd08b91aca1502dbe18e3b5063fda2e87Al Viro pos = (__le16 *) body; 1520ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen *pos = cpu_to_le16(auth_alg); 1521ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen pos++; 1522ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen *pos = cpu_to_le16(auth_transaction + 1); 1523ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen pos++; 1524ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen *pos = cpu_to_le16(resp); /* status_code */ 1525ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen pos++; 1526ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen olen = 6; 1527ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1528ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (resp == WLAN_STATUS_SUCCESS && sta != NULL && 1529ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->u.sta.challenge != NULL && 1530ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen auth_alg == WLAN_AUTH_SHARED_KEY && auth_transaction == 1) { 1531ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen u8 *tmp = (u8 *) pos; 1532ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen *tmp++ = WLAN_EID_CHALLENGE; 1533ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen *tmp++ = WLAN_AUTH_CHALLENGE_LEN; 1534ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen pos++; 1535ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen memcpy(pos, sta->u.sta.challenge, WLAN_AUTH_CHALLENGE_LEN); 1536ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen olen += 2 + WLAN_AUTH_CHALLENGE_LEN; 1537ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 1538ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 15394339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen prism2_send_mgmt(dev, IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_AUTH, 1540ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen body, olen, hdr->addr2, ap->tx_callback_auth); 1541ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1542ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (sta) { 1543ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->last_rx = jiffies; 1544ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen atomic_dec(&sta->users); 1545ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 1546ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1547ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (resp) { 1548e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg PDEBUG(DEBUG_AP, "%s: %pM auth (alg=%d " 15490795af5729b18218767fab27c44b1384f72dc9adJoe Perches "trans#=%d stat=%d len=%d fc=%04x) ==> %d (%s)\n", 1550e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg dev->name, hdr->addr2, 155121f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller auth_alg, auth_transaction, status_code, len, 15521ea893fde29d8cf1639da8989f4b843dc3283ca8Dan Williams le16_to_cpu(hdr->frame_control), resp, txt); 1553ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 1554ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen} 1555ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1556ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1557ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen/* Called only as a scheduled task for pending AP frames. */ 1558ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenstatic void handle_assoc(local_info_t *local, struct sk_buff *skb, 1559ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct hostap_80211_rx_status *rx_stats, int reassoc) 1560ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{ 1561ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct net_device *dev = local->dev; 15621ea893fde29d8cf1639da8989f4b843dc3283ca8Dan Williams struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; 1563ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen char body[12], *p, *lpos; 1564ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen int len, left; 15658a9faf3cd08b91aca1502dbe18e3b5063fda2e87Al Viro __le16 *pos; 1566ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen u16 resp = WLAN_STATUS_SUCCESS; 1567ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct sta_info *sta = NULL; 1568ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen int send_deauth = 0; 1569ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen char *txt = ""; 1570ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen u8 prev_ap[ETH_ALEN]; 1571ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1572ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen left = len = skb->len - IEEE80211_MGMT_HDR_LEN; 1573ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1574ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (len < (reassoc ? 10 : 4)) { 1575ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen PDEBUG(DEBUG_AP, "%s: handle_assoc - too short payload " 1576e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg "(len=%d, reassoc=%d) from %pM\n", 1577e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg dev->name, len, reassoc, hdr->addr2); 1578ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return; 1579ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 1580ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1581ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen spin_lock_bh(&local->ap->sta_table_lock); 1582ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta = ap_get_sta(local->ap, hdr->addr2); 1583ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (sta == NULL || (sta->flags & WLAN_STA_AUTH) == 0) { 1584ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen spin_unlock_bh(&local->ap->sta_table_lock); 1585ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen txt = "trying to associate before authentication"; 1586ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen send_deauth = 1; 1587ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen resp = WLAN_STATUS_UNSPECIFIED_FAILURE; 1588ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta = NULL; /* do not decrement sta->users */ 1589ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen goto fail; 1590ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 1591ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen atomic_inc(&sta->users); 1592ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen spin_unlock_bh(&local->ap->sta_table_lock); 1593ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 15948a9faf3cd08b91aca1502dbe18e3b5063fda2e87Al Viro pos = (__le16 *) (skb->data + IEEE80211_MGMT_HDR_LEN); 1595ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->capability = __le16_to_cpu(*pos); 1596ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen pos++; left -= 2; 1597ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->listen_interval = __le16_to_cpu(*pos); 1598ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen pos++; left -= 2; 1599ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1600ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (reassoc) { 1601ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen memcpy(prev_ap, pos, ETH_ALEN); 1602ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen pos++; pos++; pos++; left -= 6; 1603ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } else 1604ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen memset(prev_ap, 0, ETH_ALEN); 1605ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1606ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (left >= 2) { 1607ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen unsigned int ileft; 1608ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen unsigned char *u = (unsigned char *) pos; 1609ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1610ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (*u == WLAN_EID_SSID) { 1611ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen u++; left--; 1612ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen ileft = *u; 1613ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen u++; left--; 1614ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1615ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (ileft > left || ileft > MAX_SSID_LEN) { 1616ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen txt = "SSID overflow"; 1617ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen resp = WLAN_STATUS_UNSPECIFIED_FAILURE; 1618ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen goto fail; 1619ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 1620ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1621ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (ileft != strlen(local->essid) || 1622ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen memcmp(local->essid, u, ileft) != 0) { 1623ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen txt = "not our SSID"; 1624ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen resp = WLAN_STATUS_ASSOC_DENIED_UNSPEC; 1625ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen goto fail; 1626ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 1627ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1628ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen u += ileft; 1629ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen left -= ileft; 1630ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 1631ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1632ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (left >= 2 && *u == WLAN_EID_SUPP_RATES) { 1633ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen u++; left--; 1634ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen ileft = *u; 1635ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen u++; left--; 163674fae82c8bd5dd78365abe25506a9ba388d4a889Jeff Garzik 1637ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (ileft > left || ileft == 0 || 1638ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen ileft > WLAN_SUPP_RATES_MAX) { 1639ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen txt = "SUPP_RATES len error"; 1640ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen resp = WLAN_STATUS_UNSPECIFIED_FAILURE; 1641ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen goto fail; 1642ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 1643ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1644ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen memset(sta->supported_rates, 0, 1645ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sizeof(sta->supported_rates)); 1646ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen memcpy(sta->supported_rates, u, ileft); 1647ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen prism2_check_tx_rates(sta); 1648ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1649ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen u += ileft; 1650ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen left -= ileft; 1651ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 1652ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1653ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (left > 0) { 1654e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg PDEBUG(DEBUG_AP, "%s: assoc from %pM" 16550795af5729b18218767fab27c44b1384f72dc9adJoe Perches " with extra data (%d bytes) [", 1656e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg dev->name, hdr->addr2, left); 1657ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen while (left > 0) { 1658ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen PDEBUG2(DEBUG_AP, "<%02x>", *u); 1659ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen u++; left--; 1660ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 1661ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen PDEBUG2(DEBUG_AP, "]\n"); 1662ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 1663ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } else { 1664ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen txt = "frame underflow"; 1665ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen resp = WLAN_STATUS_UNSPECIFIED_FAILURE; 1666ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen goto fail; 1667ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 1668ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1669ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen /* get a unique AID */ 1670ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (sta->aid > 0) 1671ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen txt = "OK, old AID"; 1672ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen else { 1673ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen spin_lock_bh(&local->ap->sta_table_lock); 1674ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen for (sta->aid = 1; sta->aid <= MAX_AID_TABLE_SIZE; sta->aid++) 1675ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (local->ap->sta_aid[sta->aid - 1] == NULL) 1676ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen break; 1677ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (sta->aid > MAX_AID_TABLE_SIZE) { 1678ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->aid = 0; 1679ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen spin_unlock_bh(&local->ap->sta_table_lock); 1680ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA; 1681ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen txt = "no room for more AIDs"; 1682ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } else { 1683ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen local->ap->sta_aid[sta->aid - 1] = sta; 1684ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen spin_unlock_bh(&local->ap->sta_table_lock); 1685ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen txt = "OK, new AID"; 1686ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 1687ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 1688ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1689ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen fail: 16908a9faf3cd08b91aca1502dbe18e3b5063fda2e87Al Viro pos = (__le16 *) body; 1691ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1692ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (send_deauth) { 16938a9faf3cd08b91aca1502dbe18e3b5063fda2e87Al Viro *pos = cpu_to_le16(WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH); 1694ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen pos++; 1695ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } else { 1696ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen /* FIX: CF-Pollable and CF-PollReq should be set to match the 1697ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * values in beacons/probe responses */ 1698ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen /* FIX: how about privacy and WEP? */ 1699ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen /* capability */ 17008a9faf3cd08b91aca1502dbe18e3b5063fda2e87Al Viro *pos = cpu_to_le16(WLAN_CAPABILITY_ESS); 1701ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen pos++; 1702ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1703ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen /* status_code */ 17048a9faf3cd08b91aca1502dbe18e3b5063fda2e87Al Viro *pos = cpu_to_le16(resp); 1705ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen pos++; 1706ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 17078a9faf3cd08b91aca1502dbe18e3b5063fda2e87Al Viro *pos = cpu_to_le16((sta && sta->aid > 0 ? sta->aid : 0) | 1708ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen BIT(14) | BIT(15)); /* AID */ 1709ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen pos++; 1710ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1711ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen /* Supported rates (Information element) */ 1712ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen p = (char *) pos; 1713ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen *p++ = WLAN_EID_SUPP_RATES; 1714ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen lpos = p; 1715ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen *p++ = 0; /* len */ 1716ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (local->tx_rate_control & WLAN_RATE_1M) { 1717ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen *p++ = local->basic_rates & WLAN_RATE_1M ? 0x82 : 0x02; 1718ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen (*lpos)++; 1719ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 1720ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (local->tx_rate_control & WLAN_RATE_2M) { 1721ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen *p++ = local->basic_rates & WLAN_RATE_2M ? 0x84 : 0x04; 1722ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen (*lpos)++; 1723ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 1724ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (local->tx_rate_control & WLAN_RATE_5M5) { 1725ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen *p++ = local->basic_rates & WLAN_RATE_5M5 ? 1726ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 0x8b : 0x0b; 1727ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen (*lpos)++; 1728ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 1729ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (local->tx_rate_control & WLAN_RATE_11M) { 1730ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen *p++ = local->basic_rates & WLAN_RATE_11M ? 1731ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 0x96 : 0x16; 1732ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen (*lpos)++; 1733ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 17348a9faf3cd08b91aca1502dbe18e3b5063fda2e87Al Viro pos = (__le16 *) p; 1735ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 1736ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 17374339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen prism2_send_mgmt(dev, IEEE80211_FTYPE_MGMT | 17384339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen (send_deauth ? IEEE80211_STYPE_DEAUTH : 17394339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen (reassoc ? IEEE80211_STYPE_REASSOC_RESP : 17404339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen IEEE80211_STYPE_ASSOC_RESP)), 1741ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen body, (u8 *) pos - (u8 *) body, 1742ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen hdr->addr2, 1743ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen send_deauth ? 0 : local->ap->tx_callback_assoc); 1744ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1745ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (sta) { 1746ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (resp == WLAN_STATUS_SUCCESS) { 1747ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->last_rx = jiffies; 1748ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen /* STA will be marked associated from TX callback, if 1749ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * AssocResp is ACKed */ 1750ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 1751ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen atomic_dec(&sta->users); 1752ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 1753ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1754ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#if 0 1755e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg PDEBUG(DEBUG_AP, "%s: %pM %sassoc (len=%d " 1756e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg "prev_ap=%pM) => %d(%d) (%s)\n", 175721f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller dev->name, 1758e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg hdr->addr2, 175921f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller reassoc ? "re" : "", len, 1760e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg prev_ap, 176121f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller resp, send_deauth, txt); 1762ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#endif 1763ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen} 1764ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1765ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1766ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen/* Called only as a scheduled task for pending AP frames. */ 1767ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenstatic void handle_deauth(local_info_t *local, struct sk_buff *skb, 1768ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct hostap_80211_rx_status *rx_stats) 1769ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{ 1770ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct net_device *dev = local->dev; 17711ea893fde29d8cf1639da8989f4b843dc3283ca8Dan Williams struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; 1772ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen char *body = (char *) (skb->data + IEEE80211_MGMT_HDR_LEN); 1773ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen int len; 17748a9faf3cd08b91aca1502dbe18e3b5063fda2e87Al Viro u16 reason_code; 17758a9faf3cd08b91aca1502dbe18e3b5063fda2e87Al Viro __le16 *pos; 1776ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct sta_info *sta = NULL; 1777ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1778ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen len = skb->len - IEEE80211_MGMT_HDR_LEN; 1779ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1780ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (len < 2) { 1781ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen printk("handle_deauth - too short payload (len=%d)\n", len); 1782ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return; 1783ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 1784ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 17858a9faf3cd08b91aca1502dbe18e3b5063fda2e87Al Viro pos = (__le16 *) body; 17868a9faf3cd08b91aca1502dbe18e3b5063fda2e87Al Viro reason_code = le16_to_cpu(*pos); 1787ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1788e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg PDEBUG(DEBUG_AP, "%s: deauthentication: %pM len=%d, " 1789e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg "reason_code=%d\n", dev->name, hdr->addr2, 179021f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller len, reason_code); 1791ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1792ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen spin_lock_bh(&local->ap->sta_table_lock); 1793ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta = ap_get_sta(local->ap, hdr->addr2); 1794ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (sta != NULL) { 1795ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap) 1796ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen hostap_event_expired_sta(local->dev, sta); 1797ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC); 1798ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 1799ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen spin_unlock_bh(&local->ap->sta_table_lock); 1800ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (sta == NULL) { 1801e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg printk("%s: deauthentication from %pM, " 1802ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen "reason_code=%d, but STA not authenticated\n", dev->name, 1803e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg hdr->addr2, reason_code); 1804ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 1805ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen} 1806ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1807ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1808ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen/* Called only as a scheduled task for pending AP frames. */ 1809ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenstatic void handle_disassoc(local_info_t *local, struct sk_buff *skb, 1810ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct hostap_80211_rx_status *rx_stats) 1811ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{ 1812ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct net_device *dev = local->dev; 18131ea893fde29d8cf1639da8989f4b843dc3283ca8Dan Williams struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; 1814ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen char *body = skb->data + IEEE80211_MGMT_HDR_LEN; 1815ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen int len; 18168a9faf3cd08b91aca1502dbe18e3b5063fda2e87Al Viro u16 reason_code; 18178a9faf3cd08b91aca1502dbe18e3b5063fda2e87Al Viro __le16 *pos; 1818ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct sta_info *sta = NULL; 1819ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1820ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen len = skb->len - IEEE80211_MGMT_HDR_LEN; 1821ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1822ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (len < 2) { 1823ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen printk("handle_disassoc - too short payload (len=%d)\n", len); 1824ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return; 1825ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 1826ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 18278a9faf3cd08b91aca1502dbe18e3b5063fda2e87Al Viro pos = (__le16 *) body; 18288a9faf3cd08b91aca1502dbe18e3b5063fda2e87Al Viro reason_code = le16_to_cpu(*pos); 1829ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1830e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg PDEBUG(DEBUG_AP, "%s: disassociation: %pM len=%d, " 1831e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg "reason_code=%d\n", dev->name, hdr->addr2, 183221f644f3eabde637f255f75ad05d0821a7a36b7fDavid S. Miller len, reason_code); 1833ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1834ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen spin_lock_bh(&local->ap->sta_table_lock); 1835ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta = ap_get_sta(local->ap, hdr->addr2); 1836ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (sta != NULL) { 1837ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap) 1838ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen hostap_event_expired_sta(local->dev, sta); 1839ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->flags &= ~WLAN_STA_ASSOC; 1840ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 1841ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen spin_unlock_bh(&local->ap->sta_table_lock); 1842ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (sta == NULL) { 1843e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg printk("%s: disassociation from %pM, " 1844ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen "reason_code=%d, but STA not authenticated\n", 1845e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg dev->name, hdr->addr2, reason_code); 1846ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 1847ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen} 1848ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1849ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1850ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen/* Called only as a scheduled task for pending AP frames. */ 1851ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenstatic void ap_handle_data_nullfunc(local_info_t *local, 18521ea893fde29d8cf1639da8989f4b843dc3283ca8Dan Williams struct ieee80211_hdr *hdr) 1853ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{ 1854ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct net_device *dev = local->dev; 1855ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1856ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen /* some STA f/w's seem to require control::ACK frame for 1857ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * data::nullfunc, but at least Prism2 station f/w version 0.8.0 does 1858ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * not send this.. 1859ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * send control::ACK for the data::nullfunc */ 1860ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1861ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen printk(KERN_DEBUG "Sending control::ACK for data::nullfunc\n"); 18624339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen prism2_send_mgmt(dev, IEEE80211_FTYPE_CTL | IEEE80211_STYPE_ACK, 1863ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen NULL, 0, hdr->addr2, 0); 1864ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen} 1865ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1866ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1867ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen/* Called only as a scheduled task for pending AP frames. */ 1868ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenstatic void ap_handle_dropped_data(local_info_t *local, 18691ea893fde29d8cf1639da8989f4b843dc3283ca8Dan Williams struct ieee80211_hdr *hdr) 1870ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{ 1871ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct net_device *dev = local->dev; 1872ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct sta_info *sta; 18738a9faf3cd08b91aca1502dbe18e3b5063fda2e87Al Viro __le16 reason; 1874ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1875ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen spin_lock_bh(&local->ap->sta_table_lock); 1876ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta = ap_get_sta(local->ap, hdr->addr2); 1877ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (sta) 1878ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen atomic_inc(&sta->users); 1879ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen spin_unlock_bh(&local->ap->sta_table_lock); 1880ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1881ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (sta != NULL && (sta->flags & WLAN_STA_ASSOC)) { 1882ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen PDEBUG(DEBUG_AP, "ap_handle_dropped_data: STA is now okay?\n"); 1883ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen atomic_dec(&sta->users); 1884ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return; 1885ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 1886ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 18878a9faf3cd08b91aca1502dbe18e3b5063fda2e87Al Viro reason = cpu_to_le16(WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA); 18884339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen prism2_send_mgmt(dev, IEEE80211_FTYPE_MGMT | 1889ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen ((sta == NULL || !(sta->flags & WLAN_STA_ASSOC)) ? 18904339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen IEEE80211_STYPE_DEAUTH : IEEE80211_STYPE_DISASSOC), 1891ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen (char *) &reason, sizeof(reason), hdr->addr2, 0); 1892ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1893ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (sta) 1894ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen atomic_dec(&sta->users); 1895ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen} 1896ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1897ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ 1898ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1899ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1900ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen/* Called only as a scheduled task for pending AP frames. */ 1901ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenstatic void pspoll_send_buffered(local_info_t *local, struct sta_info *sta, 1902ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct sk_buff *skb) 1903ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{ 19045bee720fd7fa5ed4eade96058acd3a684da30932Jouni Malinen struct hostap_skb_tx_data *meta; 19055bee720fd7fa5ed4eade96058acd3a684da30932Jouni Malinen 1906ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (!(sta->flags & WLAN_STA_PS)) { 1907ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen /* Station has moved to non-PS mode, so send all buffered 1908ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * frames using normal device queue. */ 1909ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen dev_queue_xmit(skb); 1910ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return; 1911ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 1912ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1913ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen /* add a flag for hostap_handle_sta_tx() to know that this skb should 1914ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * be passed through even though STA is using PS */ 19155bee720fd7fa5ed4eade96058acd3a684da30932Jouni Malinen meta = (struct hostap_skb_tx_data *) skb->cb; 19165bee720fd7fa5ed4eade96058acd3a684da30932Jouni Malinen meta->flags |= HOSTAP_TX_FLAGS_BUFFERED_FRAME; 1917ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (!skb_queue_empty(&sta->tx_buf)) { 1918ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen /* indicate to STA that more frames follow */ 19195bee720fd7fa5ed4eade96058acd3a684da30932Jouni Malinen meta->flags |= HOSTAP_TX_FLAGS_ADD_MOREDATA; 1920ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 1921ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen dev_queue_xmit(skb); 1922ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen} 1923ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1924ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1925ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen/* Called only as a scheduled task for pending AP frames. */ 1926ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenstatic void handle_pspoll(local_info_t *local, 19271ea893fde29d8cf1639da8989f4b843dc3283ca8Dan Williams struct ieee80211_hdr *hdr, 1928ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct hostap_80211_rx_status *rx_stats) 1929ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{ 1930ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct net_device *dev = local->dev; 1931ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct sta_info *sta; 1932ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen u16 aid; 1933ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct sk_buff *skb; 1934ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1935e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg PDEBUG(DEBUG_PS2, "handle_pspoll: BSSID=%pM, TA=%pM PWRMGT=%d\n", 19361ea893fde29d8cf1639da8989f4b843dc3283ca8Dan Williams hdr->addr1, hdr->addr2, !!ieee80211_has_pm(hdr->frame_control)); 1937ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1938d22fbd70c2770b5e3ba0d7bc5b29f6ee686cdba4dingtianhong if (!ether_addr_equal(hdr->addr1, dev->dev_addr)) { 1939e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg PDEBUG(DEBUG_AP, 1940e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg "handle_pspoll - addr1(BSSID)=%pM not own MAC\n", 1941e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg hdr->addr1); 1942ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return; 1943ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 1944ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 19458a9faf3cd08b91aca1502dbe18e3b5063fda2e87Al Viro aid = le16_to_cpu(hdr->duration_id); 1946ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if ((aid & (BIT(15) | BIT(14))) != (BIT(15) | BIT(14))) { 1947ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen PDEBUG(DEBUG_PS, " PSPOLL and AID[15:14] not set\n"); 1948ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return; 1949ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 19501bcca3c463e4930cef9986b05165bb0b3eb46f63Pavel Roskin aid &= ~(BIT(15) | BIT(14)); 1951ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (aid == 0 || aid > MAX_AID_TABLE_SIZE) { 1952ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen PDEBUG(DEBUG_PS, " invalid aid=%d\n", aid); 1953ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return; 1954ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 1955ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen PDEBUG(DEBUG_PS2, " aid=%d\n", aid); 1956ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1957ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen spin_lock_bh(&local->ap->sta_table_lock); 1958ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta = ap_get_sta(local->ap, hdr->addr2); 1959ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (sta) 1960ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen atomic_inc(&sta->users); 1961ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen spin_unlock_bh(&local->ap->sta_table_lock); 1962ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1963ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (sta == NULL) { 1964ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen PDEBUG(DEBUG_PS, " STA not found\n"); 1965ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return; 1966ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 1967ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (sta->aid != aid) { 1968ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen PDEBUG(DEBUG_PS, " received aid=%i does not match with " 1969ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen "assoc.aid=%d\n", aid, sta->aid); 1970ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return; 1971ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 1972ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1973ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen /* FIX: todo: 1974ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * - add timeout for buffering (clear aid in TIM vector if buffer timed 1975ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * out (expiry time must be longer than ListenInterval for 1976ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * the corresponding STA; "8802-11: 11.2.1.9 AP aging function" 1977ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * - what to do, if buffered, pspolled, and sent frame is not ACKed by 1978ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * sta; store buffer for later use and leave TIM aid bit set? use 1979ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * TX event to check whether frame was ACKed? 1980ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen */ 1981ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1982ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen while ((skb = skb_dequeue(&sta->tx_buf)) != NULL) { 1983ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen /* send buffered frame .. */ 1984ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen PDEBUG(DEBUG_PS2, "Sending buffered frame to STA after PS POLL" 1985ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen " (buffer_count=%d)\n", skb_queue_len(&sta->tx_buf)); 1986ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1987ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen pspoll_send_buffered(local, sta, skb); 1988ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1989ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (sta->flags & WLAN_STA_PS) { 1990ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen /* send only one buffered packet per PS Poll */ 1991ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen /* FIX: should ignore further PS Polls until the 1992ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * buffered packet that was just sent is acknowledged 1993ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * (Tx or TxExc event) */ 1994ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen break; 1995ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 1996ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 1997ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 1998ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (skb_queue_empty(&sta->tx_buf)) { 1999ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen /* try to clear aid from TIM */ 2000ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (!(sta->flags & WLAN_STA_TIM)) 2001ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen PDEBUG(DEBUG_PS2, "Re-unsetting TIM for aid %d\n", 2002ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen aid); 2003ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen hostap_set_tim(local, aid, 0); 2004ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->flags &= ~WLAN_STA_TIM; 2005ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 2006ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2007ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen atomic_dec(&sta->users); 2008ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen} 2009ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2010ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2011ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT 2012ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2013c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howellsstatic void handle_wds_oper_queue(struct work_struct *work) 2014ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{ 2015c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howells struct ap_data *ap = container_of(work, struct ap_data, 2016c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howells wds_oper_queue); 2017c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howells local_info_t *local = ap->local; 2018ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct wds_oper_data *entry, *prev; 2019ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2020ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen spin_lock_bh(&local->lock); 2021ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen entry = local->ap->wds_oper_entries; 2022ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen local->ap->wds_oper_entries = NULL; 2023ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen spin_unlock_bh(&local->lock); 2024ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2025ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen while (entry) { 2026ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen PDEBUG(DEBUG_AP, "%s: %s automatic WDS connection " 2027e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg "to AP %pM\n", 2028ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen local->dev->name, 2029ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen entry->type == WDS_ADD ? "adding" : "removing", 2030e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg entry->addr); 2031ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (entry->type == WDS_ADD) 2032ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen prism2_wds_add(local, entry->addr, 0); 2033ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen else if (entry->type == WDS_DEL) 2034ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen prism2_wds_del(local, entry->addr, 0, 1); 2035ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2036ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen prev = entry; 2037ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen entry = entry->next; 2038ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen kfree(prev); 2039ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 2040ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen} 2041ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2042ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2043ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen/* Called only as a scheduled task for pending AP frames. */ 2044ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenstatic void handle_beacon(local_info_t *local, struct sk_buff *skb, 2045ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct hostap_80211_rx_status *rx_stats) 2046ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{ 20471ea893fde29d8cf1639da8989f4b843dc3283ca8Dan Williams struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; 2048ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen char *body = skb->data + IEEE80211_MGMT_HDR_LEN; 2049ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen int len, left; 20508a9faf3cd08b91aca1502dbe18e3b5063fda2e87Al Viro u16 beacon_int, capability; 20518a9faf3cd08b91aca1502dbe18e3b5063fda2e87Al Viro __le16 *pos; 2052ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen char *ssid = NULL; 2053ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen unsigned char *supp_rates = NULL; 2054ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen int ssid_len = 0, supp_rates_len = 0; 2055ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct sta_info *sta = NULL; 2056ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen int new_sta = 0, channel = -1; 2057ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2058ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen len = skb->len - IEEE80211_MGMT_HDR_LEN; 2059ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2060ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (len < 8 + 2 + 2) { 2061ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen printk(KERN_DEBUG "handle_beacon - too short payload " 2062ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen "(len=%d)\n", len); 2063ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return; 2064ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 2065ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 20668a9faf3cd08b91aca1502dbe18e3b5063fda2e87Al Viro pos = (__le16 *) body; 2067ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen left = len; 2068ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2069ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen /* Timestamp (8 octets) */ 2070ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen pos += 4; left -= 8; 2071ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen /* Beacon interval (2 octets) */ 20728a9faf3cd08b91aca1502dbe18e3b5063fda2e87Al Viro beacon_int = le16_to_cpu(*pos); 2073ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen pos++; left -= 2; 2074ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen /* Capability information (2 octets) */ 20758a9faf3cd08b91aca1502dbe18e3b5063fda2e87Al Viro capability = le16_to_cpu(*pos); 2076ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen pos++; left -= 2; 2077ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2078ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (local->ap->ap_policy != AP_OTHER_AP_EVEN_IBSS && 2079ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen capability & WLAN_CAPABILITY_IBSS) 2080ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return; 2081ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2082ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (left >= 2) { 2083ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen unsigned int ileft; 2084ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen unsigned char *u = (unsigned char *) pos; 2085ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2086ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (*u == WLAN_EID_SSID) { 2087ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen u++; left--; 2088ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen ileft = *u; 2089ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen u++; left--; 2090ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2091ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (ileft > left || ileft > MAX_SSID_LEN) { 2092ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen PDEBUG(DEBUG_AP, "SSID: overflow\n"); 2093ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return; 2094ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 2095ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2096ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (local->ap->ap_policy == AP_OTHER_AP_SAME_SSID && 2097ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen (ileft != strlen(local->essid) || 2098ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen memcmp(local->essid, u, ileft) != 0)) { 2099ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen /* not our SSID */ 2100ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return; 2101ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 2102ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2103ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen ssid = u; 2104ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen ssid_len = ileft; 2105ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2106ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen u += ileft; 2107ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen left -= ileft; 2108ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 2109ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2110ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (*u == WLAN_EID_SUPP_RATES) { 2111ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen u++; left--; 2112ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen ileft = *u; 2113ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen u++; left--; 211474fae82c8bd5dd78365abe25506a9ba388d4a889Jeff Garzik 2115ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (ileft > left || ileft == 0 || ileft > 8) { 2116ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen PDEBUG(DEBUG_AP, " - SUPP_RATES len error\n"); 2117ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return; 2118ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 2119ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2120ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen supp_rates = u; 2121ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen supp_rates_len = ileft; 2122ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2123ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen u += ileft; 2124ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen left -= ileft; 2125ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 2126ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2127ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (*u == WLAN_EID_DS_PARAMS) { 2128ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen u++; left--; 2129ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen ileft = *u; 2130ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen u++; left--; 213174fae82c8bd5dd78365abe25506a9ba388d4a889Jeff Garzik 2132ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (ileft > left || ileft != 1) { 2133ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen PDEBUG(DEBUG_AP, " - DS_PARAMS len error\n"); 2134ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return; 2135ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 2136ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2137ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen channel = *u; 2138ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2139ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen u += ileft; 2140ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen left -= ileft; 2141ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 2142ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 2143ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2144ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen spin_lock_bh(&local->ap->sta_table_lock); 2145ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta = ap_get_sta(local->ap, hdr->addr2); 2146ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (sta != NULL) 2147ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen atomic_inc(&sta->users); 2148ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen spin_unlock_bh(&local->ap->sta_table_lock); 2149ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2150ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (sta == NULL) { 2151ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen /* add new AP */ 2152ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen new_sta = 1; 2153ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta = ap_add_sta(local->ap, hdr->addr2); 2154ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (sta == NULL) { 2155ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen printk(KERN_INFO "prism2: kmalloc failed for AP " 2156ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen "data structure\n"); 2157ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return; 2158ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 2159ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen hostap_event_new_sta(local->dev, sta); 2160ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2161ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen /* mark APs authentication and associated for pseudo ad-hoc 2162ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * style communication */ 2163ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->flags = WLAN_STA_AUTH | WLAN_STA_ASSOC; 2164ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2165ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (local->ap->autom_ap_wds) { 2166ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen hostap_wds_link_oper(local, sta->addr, WDS_ADD); 2167ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 2168ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 2169ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2170ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->ap = 1; 2171ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (ssid) { 2172ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->u.ap.ssid_len = ssid_len; 2173ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen memcpy(sta->u.ap.ssid, ssid, ssid_len); 2174ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->u.ap.ssid[ssid_len] = '\0'; 2175ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } else { 2176ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->u.ap.ssid_len = 0; 2177ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->u.ap.ssid[0] = '\0'; 2178ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 2179ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->u.ap.channel = channel; 2180ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->rx_packets++; 2181ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->rx_bytes += len; 2182ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->u.ap.last_beacon = sta->last_rx = jiffies; 2183ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->capability = capability; 2184ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->listen_interval = beacon_int; 2185ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2186ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen atomic_dec(&sta->users); 2187ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2188ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (new_sta) { 2189ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen memset(sta->supported_rates, 0, sizeof(sta->supported_rates)); 2190ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen memcpy(sta->supported_rates, supp_rates, supp_rates_len); 2191ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen prism2_check_tx_rates(sta); 2192ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 2193ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen} 2194ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2195ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ 2196ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2197ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2198ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen/* Called only as a tasklet. */ 2199ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenstatic void handle_ap_item(local_info_t *local, struct sk_buff *skb, 2200ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct hostap_80211_rx_status *rx_stats) 2201ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{ 2202ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT 2203ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct net_device *dev = local->dev; 2204ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ 2205ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen u16 fc, type, stype; 22061ea893fde29d8cf1639da8989f4b843dc3283ca8Dan Williams struct ieee80211_hdr *hdr; 2207ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2208ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen /* FIX: should give skb->len to handler functions and check that the 2209ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * buffer is long enough */ 22101ea893fde29d8cf1639da8989f4b843dc3283ca8Dan Williams hdr = (struct ieee80211_hdr *) skb->data; 22111ea893fde29d8cf1639da8989f4b843dc3283ca8Dan Williams fc = le16_to_cpu(hdr->frame_control); 22121ea893fde29d8cf1639da8989f4b843dc3283ca8Dan Williams type = fc & IEEE80211_FCTL_FTYPE; 22131ea893fde29d8cf1639da8989f4b843dc3283ca8Dan Williams stype = fc & IEEE80211_FCTL_STYPE; 2214ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2215ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT 22164339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen if (!local->hostapd && type == IEEE80211_FTYPE_DATA) { 2217ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen PDEBUG(DEBUG_AP, "handle_ap_item - data frame\n"); 2218ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2219b2f4a2e3b1620667da9654f9e220c92ea52bdbe4Jouni Malinen if (!(fc & IEEE80211_FCTL_TODS) || 2220b2f4a2e3b1620667da9654f9e220c92ea52bdbe4Jouni Malinen (fc & IEEE80211_FCTL_FROMDS)) { 22214339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen if (stype == IEEE80211_STYPE_NULLFUNC) { 2222ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen /* no ToDS nullfunc seems to be used to check 2223ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * AP association; so send reject message to 2224ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * speed up re-association */ 2225ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen ap_handle_dropped_data(local, hdr); 2226ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen goto done; 2227ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 2228ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen PDEBUG(DEBUG_AP, " not ToDS frame (fc=0x%04x)\n", 2229ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen fc); 2230ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen goto done; 2231ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 2232ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2233d22fbd70c2770b5e3ba0d7bc5b29f6ee686cdba4dingtianhong if (!ether_addr_equal(hdr->addr1, dev->dev_addr)) { 2234e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg PDEBUG(DEBUG_AP, "handle_ap_item - addr1(BSSID)=%pM" 2235e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg " not own MAC\n", hdr->addr1); 2236ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen goto done; 2237ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 2238ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 22394339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen if (local->ap->nullfunc_ack && 22404339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen stype == IEEE80211_STYPE_NULLFUNC) 2241ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen ap_handle_data_nullfunc(local, hdr); 2242ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen else 2243ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen ap_handle_dropped_data(local, hdr); 2244ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen goto done; 2245ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 2246ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 22474339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen if (type == IEEE80211_FTYPE_MGMT && stype == IEEE80211_STYPE_BEACON) { 2248ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen handle_beacon(local, skb, rx_stats); 2249ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen goto done; 2250ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 2251ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ 2252ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 22534339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen if (type == IEEE80211_FTYPE_CTL && stype == IEEE80211_STYPE_PSPOLL) { 2254ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen handle_pspoll(local, hdr, rx_stats); 2255ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen goto done; 2256ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 2257ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2258ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (local->hostapd) { 2259ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen PDEBUG(DEBUG_AP, "Unknown frame in AP queue: type=0x%02x " 2260ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen "subtype=0x%02x\n", type, stype); 2261ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen goto done; 2262ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 2263ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2264ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT 22654339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen if (type != IEEE80211_FTYPE_MGMT) { 2266ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen PDEBUG(DEBUG_AP, "handle_ap_item - not a management frame?\n"); 2267ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen goto done; 2268ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 2269ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2270d22fbd70c2770b5e3ba0d7bc5b29f6ee686cdba4dingtianhong if (!ether_addr_equal(hdr->addr1, dev->dev_addr)) { 2271e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg PDEBUG(DEBUG_AP, "handle_ap_item - addr1(DA)=%pM" 2272e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg " not own MAC\n", hdr->addr1); 2273ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen goto done; 2274ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 2275ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2276d22fbd70c2770b5e3ba0d7bc5b29f6ee686cdba4dingtianhong if (!ether_addr_equal(hdr->addr3, dev->dev_addr)) { 2277e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg PDEBUG(DEBUG_AP, "handle_ap_item - addr3(BSSID)=%pM" 2278e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg " not own MAC\n", hdr->addr3); 2279ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen goto done; 2280ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 2281ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2282ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen switch (stype) { 22834339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen case IEEE80211_STYPE_ASSOC_REQ: 2284ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen handle_assoc(local, skb, rx_stats, 0); 2285ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen break; 22864339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen case IEEE80211_STYPE_ASSOC_RESP: 2287ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen PDEBUG(DEBUG_AP, "==> ASSOC RESP (ignored)\n"); 2288ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen break; 22894339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen case IEEE80211_STYPE_REASSOC_REQ: 2290ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen handle_assoc(local, skb, rx_stats, 1); 2291ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen break; 22924339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen case IEEE80211_STYPE_REASSOC_RESP: 2293ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen PDEBUG(DEBUG_AP, "==> REASSOC RESP (ignored)\n"); 2294ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen break; 22954339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen case IEEE80211_STYPE_ATIM: 2296ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen PDEBUG(DEBUG_AP, "==> ATIM (ignored)\n"); 2297ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen break; 22984339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen case IEEE80211_STYPE_DISASSOC: 2299ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen handle_disassoc(local, skb, rx_stats); 2300ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen break; 23014339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen case IEEE80211_STYPE_AUTH: 2302ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen handle_authen(local, skb, rx_stats); 2303ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen break; 23044339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen case IEEE80211_STYPE_DEAUTH: 2305ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen handle_deauth(local, skb, rx_stats); 2306ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen break; 2307ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen default: 23084339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen PDEBUG(DEBUG_AP, "Unknown mgmt frame subtype 0x%02x\n", 23094339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen stype >> 4); 2310ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen break; 2311ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 2312ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ 2313ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2314ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen done: 2315ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen dev_kfree_skb(skb); 2316ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen} 2317ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2318ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2319ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen/* Called only as a tasklet (software IRQ) */ 2320ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenvoid hostap_rx(struct net_device *dev, struct sk_buff *skb, 2321ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct hostap_80211_rx_status *rx_stats) 2322ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{ 2323ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct hostap_interface *iface; 2324ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen local_info_t *local; 23251ea893fde29d8cf1639da8989f4b843dc3283ca8Dan Williams struct ieee80211_hdr *hdr; 2326ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2327ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen iface = netdev_priv(dev); 2328ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen local = iface->local; 2329ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2330ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (skb->len < 16) 2331ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen goto drop; 2332ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 23334cfa8e45f4bb26ff38155f94a810a876b739958dStephen Hemminger dev->stats.rx_packets++; 2334ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 23351ea893fde29d8cf1639da8989f4b843dc3283ca8Dan Williams hdr = (struct ieee80211_hdr *) skb->data; 2336ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2337ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (local->ap->ap_policy == AP_OTHER_AP_SKIP_ALL && 23381ea893fde29d8cf1639da8989f4b843dc3283ca8Dan Williams ieee80211_is_beacon(hdr->frame_control)) 2339ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen goto drop; 2340ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2341c1b4aa3fb619782213af2af6652663c8f9cef373Harvey Harrison skb->protocol = cpu_to_be16(ETH_P_HOSTAP); 2342ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen handle_ap_item(local, skb, rx_stats); 2343ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return; 2344ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2345ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen drop: 2346ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen dev_kfree_skb(skb); 2347ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen} 2348ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2349ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2350ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen/* Called only as a tasklet (software IRQ) */ 2351ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenstatic void schedule_packet_send(local_info_t *local, struct sta_info *sta) 2352ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{ 2353ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct sk_buff *skb; 23541ea893fde29d8cf1639da8989f4b843dc3283ca8Dan Williams struct ieee80211_hdr *hdr; 2355ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct hostap_80211_rx_status rx_stats; 2356ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2357ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (skb_queue_empty(&sta->tx_buf)) 2358ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return; 2359ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2360ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen skb = dev_alloc_skb(16); 2361ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (skb == NULL) { 2362ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen printk(KERN_DEBUG "%s: schedule_packet_send: skb alloc " 2363ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen "failed\n", local->dev->name); 2364ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return; 2365ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 2366ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 23671ea893fde29d8cf1639da8989f4b843dc3283ca8Dan Williams hdr = (struct ieee80211_hdr *) skb_put(skb, 16); 2368ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2369ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen /* Generate a fake pspoll frame to start packet delivery */ 23701ea893fde29d8cf1639da8989f4b843dc3283ca8Dan Williams hdr->frame_control = cpu_to_le16( 23714339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen IEEE80211_FTYPE_CTL | IEEE80211_STYPE_PSPOLL); 2372ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen memcpy(hdr->addr1, local->dev->dev_addr, ETH_ALEN); 2373ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen memcpy(hdr->addr2, sta->addr, ETH_ALEN); 2374ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen hdr->duration_id = cpu_to_le16(sta->aid | BIT(15) | BIT(14)); 2375ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2376e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg PDEBUG(DEBUG_PS2, 2377e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg "%s: Scheduling buffered packet delivery for STA %pM\n", 2378e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg local->dev->name, sta->addr); 2379ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2380ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen skb->dev = local->dev; 2381ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2382ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen memset(&rx_stats, 0, sizeof(rx_stats)); 2383ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen hostap_rx(local->dev, skb, &rx_stats); 2384ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen} 2385ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2386ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 23875fad5a2e1f34b333a801b749c4e143c2ac3e8a4fAdrian Bunkint prism2_ap_get_sta_qual(local_info_t *local, struct sockaddr addr[], 23885fad5a2e1f34b333a801b749c4e143c2ac3e8a4fAdrian Bunk struct iw_quality qual[], int buf_size, 23895fad5a2e1f34b333a801b749c4e143c2ac3e8a4fAdrian Bunk int aplist) 2390ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{ 2391ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct ap_data *ap = local->ap; 2392ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct list_head *ptr; 2393ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen int count = 0; 2394ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2395ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen spin_lock_bh(&ap->sta_table_lock); 2396ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2397ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen for (ptr = ap->sta_list.next; ptr != NULL && ptr != &ap->sta_list; 2398ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen ptr = ptr->next) { 2399ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct sta_info *sta = (struct sta_info *) ptr; 2400ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2401ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (aplist && !sta->ap) 2402ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen continue; 2403ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen addr[count].sa_family = ARPHRD_ETHER; 2404ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen memcpy(addr[count].sa_data, sta->addr, ETH_ALEN); 2405ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (sta->last_rx_silence == 0) 2406ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen qual[count].qual = sta->last_rx_signal < 27 ? 2407ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 0 : (sta->last_rx_signal - 27) * 92 / 127; 2408ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen else 2409ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen qual[count].qual = sta->last_rx_signal - 2410ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->last_rx_silence - 35; 2411ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen qual[count].level = HFA384X_LEVEL_TO_dBm(sta->last_rx_signal); 2412ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen qual[count].noise = HFA384X_LEVEL_TO_dBm(sta->last_rx_silence); 2413ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen qual[count].updated = sta->last_rx_updated; 2414ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2415c28df16ed70d1b6cefd12135e3c68bfccd1bb635Jean Tourrilhes sta->last_rx_updated = IW_QUAL_DBM; 2416ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2417ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen count++; 2418ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (count >= buf_size) 2419ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen break; 2420ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 2421ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen spin_unlock_bh(&ap->sta_table_lock); 2422ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2423ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return count; 2424ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen} 2425ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2426ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 242725985edcedea6396277003854657b5f3cb31a628Lucas De Marchi/* Translate our list of Access Points & Stations to a card independent 2428ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * format that the Wireless Tools will understand - Jean II */ 2429ccc580571cf0799d0460a085a7632b77753f083eDavid S. Millerint prism2_ap_translate_scan(struct net_device *dev, 2430ccc580571cf0799d0460a085a7632b77753f083eDavid S. Miller struct iw_request_info *info, char *buffer) 2431ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{ 2432ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct hostap_interface *iface; 2433ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen local_info_t *local; 2434ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct ap_data *ap; 2435ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct list_head *ptr; 2436ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct iw_event iwe; 2437ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen char *current_ev = buffer; 2438ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen char *end_buf = buffer + IW_SCAN_MAX_DATA; 2439ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#if !defined(PRISM2_NO_KERNEL_IEEE80211_MGMT) 2440ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen char buf[64]; 2441ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#endif 2442ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2443ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen iface = netdev_priv(dev); 2444ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen local = iface->local; 2445ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen ap = local->ap; 2446ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2447ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen spin_lock_bh(&ap->sta_table_lock); 2448ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2449ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen for (ptr = ap->sta_list.next; ptr != NULL && ptr != &ap->sta_list; 2450ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen ptr = ptr->next) { 2451ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct sta_info *sta = (struct sta_info *) ptr; 2452ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2453ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen /* First entry *MUST* be the AP MAC address */ 2454ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen memset(&iwe, 0, sizeof(iwe)); 2455ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen iwe.cmd = SIOCGIWAP; 2456ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen iwe.u.ap_addr.sa_family = ARPHRD_ETHER; 2457ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen memcpy(iwe.u.ap_addr.sa_data, sta->addr, ETH_ALEN); 2458ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen iwe.len = IW_EV_ADDR_LEN; 2459ccc580571cf0799d0460a085a7632b77753f083eDavid S. Miller current_ev = iwe_stream_add_event(info, current_ev, end_buf, 2460ccc580571cf0799d0460a085a7632b77753f083eDavid S. Miller &iwe, IW_EV_ADDR_LEN); 2461ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2462ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen /* Use the mode to indicate if it's a station or 2463ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * an Access Point */ 2464ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen memset(&iwe, 0, sizeof(iwe)); 2465ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen iwe.cmd = SIOCGIWMODE; 2466ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (sta->ap) 2467ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen iwe.u.mode = IW_MODE_MASTER; 2468ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen else 2469ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen iwe.u.mode = IW_MODE_INFRA; 2470ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen iwe.len = IW_EV_UINT_LEN; 2471ccc580571cf0799d0460a085a7632b77753f083eDavid S. Miller current_ev = iwe_stream_add_event(info, current_ev, end_buf, 2472ccc580571cf0799d0460a085a7632b77753f083eDavid S. Miller &iwe, IW_EV_UINT_LEN); 2473ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2474ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen /* Some quality */ 2475ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen memset(&iwe, 0, sizeof(iwe)); 2476ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen iwe.cmd = IWEVQUAL; 2477ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (sta->last_rx_silence == 0) 2478ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen iwe.u.qual.qual = sta->last_rx_signal < 27 ? 2479ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 0 : (sta->last_rx_signal - 27) * 92 / 127; 2480ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen else 2481ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen iwe.u.qual.qual = sta->last_rx_signal - 2482ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->last_rx_silence - 35; 2483ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen iwe.u.qual.level = HFA384X_LEVEL_TO_dBm(sta->last_rx_signal); 2484ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen iwe.u.qual.noise = HFA384X_LEVEL_TO_dBm(sta->last_rx_silence); 2485ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen iwe.u.qual.updated = sta->last_rx_updated; 2486ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen iwe.len = IW_EV_QUAL_LEN; 2487ccc580571cf0799d0460a085a7632b77753f083eDavid S. Miller current_ev = iwe_stream_add_event(info, current_ev, end_buf, 2488ccc580571cf0799d0460a085a7632b77753f083eDavid S. Miller &iwe, IW_EV_QUAL_LEN); 2489ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2490ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT 2491ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (sta->ap) { 2492ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen memset(&iwe, 0, sizeof(iwe)); 2493ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen iwe.cmd = SIOCGIWESSID; 2494ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen iwe.u.data.length = sta->u.ap.ssid_len; 2495ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen iwe.u.data.flags = 1; 2496ccc580571cf0799d0460a085a7632b77753f083eDavid S. Miller current_ev = iwe_stream_add_point(info, current_ev, 2497ccc580571cf0799d0460a085a7632b77753f083eDavid S. Miller end_buf, &iwe, 2498ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->u.ap.ssid); 2499ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2500ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen memset(&iwe, 0, sizeof(iwe)); 2501ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen iwe.cmd = SIOCGIWENCODE; 2502ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (sta->capability & WLAN_CAPABILITY_PRIVACY) 2503ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen iwe.u.data.flags = 2504ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; 2505ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen else 2506ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen iwe.u.data.flags = IW_ENCODE_DISABLED; 2507ccc580571cf0799d0460a085a7632b77753f083eDavid S. Miller current_ev = iwe_stream_add_point(info, current_ev, 2508ccc580571cf0799d0460a085a7632b77753f083eDavid S. Miller end_buf, &iwe, 2509ccc580571cf0799d0460a085a7632b77753f083eDavid S. Miller sta->u.ap.ssid); 2510ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2511ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (sta->u.ap.channel > 0 && 2512ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->u.ap.channel <= FREQ_COUNT) { 2513ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen memset(&iwe, 0, sizeof(iwe)); 2514ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen iwe.cmd = SIOCGIWFREQ; 2515ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen iwe.u.freq.m = freq_list[sta->u.ap.channel - 1] 2516ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * 100000; 2517ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen iwe.u.freq.e = 1; 2518ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen current_ev = iwe_stream_add_event( 2519ccc580571cf0799d0460a085a7632b77753f083eDavid S. Miller info, current_ev, end_buf, &iwe, 2520ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen IW_EV_FREQ_LEN); 2521ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 2522ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2523ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen memset(&iwe, 0, sizeof(iwe)); 2524ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen iwe.cmd = IWEVCUSTOM; 2525ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sprintf(buf, "beacon_interval=%d", 2526ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->listen_interval); 2527ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen iwe.u.data.length = strlen(buf); 2528ccc580571cf0799d0460a085a7632b77753f083eDavid S. Miller current_ev = iwe_stream_add_point(info, current_ev, 2529ccc580571cf0799d0460a085a7632b77753f083eDavid S. Miller end_buf, &iwe, buf); 2530ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 2531ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ 2532ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2533c28df16ed70d1b6cefd12135e3c68bfccd1bb635Jean Tourrilhes sta->last_rx_updated = IW_QUAL_DBM; 2534ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2535ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen /* To be continued, we should make good use of IWEVCUSTOM */ 2536ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 2537ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2538ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen spin_unlock_bh(&ap->sta_table_lock); 2539ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2540ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return current_ev - buffer; 2541ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen} 2542ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2543ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2544ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenstatic int prism2_hostapd_add_sta(struct ap_data *ap, 2545ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct prism2_hostapd_param *param) 2546ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{ 2547ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct sta_info *sta; 2548ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2549ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen spin_lock_bh(&ap->sta_table_lock); 2550ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta = ap_get_sta(ap, param->sta_addr); 2551ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (sta) 2552ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen atomic_inc(&sta->users); 2553ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen spin_unlock_bh(&ap->sta_table_lock); 2554ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2555ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (sta == NULL) { 2556ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta = ap_add_sta(ap, param->sta_addr); 2557ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (sta == NULL) 2558ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return -1; 2559ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 2560ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2561ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (!(sta->flags & WLAN_STA_ASSOC) && !sta->ap && sta->local) 2562ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen hostap_event_new_sta(sta->local->dev, sta); 2563ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2564ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC; 2565ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->last_rx = jiffies; 2566ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->aid = param->u.add_sta.aid; 2567ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->capability = param->u.add_sta.capability; 2568ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->tx_supp_rates = param->u.add_sta.tx_supp_rates; 2569ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (sta->tx_supp_rates & WLAN_RATE_1M) 2570ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->supported_rates[0] = 2; 2571ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (sta->tx_supp_rates & WLAN_RATE_2M) 2572ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->supported_rates[1] = 4; 2573ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (sta->tx_supp_rates & WLAN_RATE_5M5) 2574ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->supported_rates[2] = 11; 2575ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (sta->tx_supp_rates & WLAN_RATE_11M) 2576ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->supported_rates[3] = 22; 2577ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen prism2_check_tx_rates(sta); 2578ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen atomic_dec(&sta->users); 2579ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return 0; 2580ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen} 2581ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2582ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2583ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenstatic int prism2_hostapd_remove_sta(struct ap_data *ap, 2584ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct prism2_hostapd_param *param) 2585ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{ 2586ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct sta_info *sta; 2587ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2588ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen spin_lock_bh(&ap->sta_table_lock); 2589ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta = ap_get_sta(ap, param->sta_addr); 2590ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (sta) { 2591ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen ap_sta_hash_del(ap, sta); 2592ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen list_del(&sta->list); 2593ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 2594ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen spin_unlock_bh(&ap->sta_table_lock); 2595ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2596ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (!sta) 2597ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return -ENOENT; 2598ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2599ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap && sta->local) 2600ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen hostap_event_expired_sta(sta->local->dev, sta); 2601ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen ap_free_sta(ap, sta); 2602ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2603ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return 0; 2604ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen} 2605ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2606ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2607ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenstatic int prism2_hostapd_get_info_sta(struct ap_data *ap, 2608ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct prism2_hostapd_param *param) 2609ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{ 2610ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct sta_info *sta; 2611ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2612ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen spin_lock_bh(&ap->sta_table_lock); 2613ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta = ap_get_sta(ap, param->sta_addr); 2614ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (sta) 2615ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen atomic_inc(&sta->users); 2616ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen spin_unlock_bh(&ap->sta_table_lock); 2617ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2618ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (!sta) 2619ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return -ENOENT; 2620ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2621ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen param->u.get_info_sta.inactive_sec = (jiffies - sta->last_rx) / HZ; 2622ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2623ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen atomic_dec(&sta->users); 2624ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2625ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return 1; 2626ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen} 2627ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2628ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2629ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenstatic int prism2_hostapd_set_flags_sta(struct ap_data *ap, 2630ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct prism2_hostapd_param *param) 2631ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{ 2632ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct sta_info *sta; 2633ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2634ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen spin_lock_bh(&ap->sta_table_lock); 2635ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta = ap_get_sta(ap, param->sta_addr); 2636ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (sta) { 2637ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->flags |= param->u.set_flags_sta.flags_or; 2638ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->flags &= param->u.set_flags_sta.flags_and; 2639ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 2640ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen spin_unlock_bh(&ap->sta_table_lock); 2641ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2642ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (!sta) 2643ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return -ENOENT; 2644ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2645ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return 0; 2646ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen} 2647ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2648ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2649ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenstatic int prism2_hostapd_sta_clear_stats(struct ap_data *ap, 2650ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct prism2_hostapd_param *param) 2651ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{ 2652ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct sta_info *sta; 2653ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen int rate; 2654ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2655ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen spin_lock_bh(&ap->sta_table_lock); 2656ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta = ap_get_sta(ap, param->sta_addr); 2657ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (sta) { 2658ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->rx_packets = sta->tx_packets = 0; 2659ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->rx_bytes = sta->tx_bytes = 0; 2660ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen for (rate = 0; rate < WLAN_RATE_COUNT; rate++) { 2661ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->tx_count[rate] = 0; 2662ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->rx_count[rate] = 0; 2663ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 2664ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 2665ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen spin_unlock_bh(&ap->sta_table_lock); 2666ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2667ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (!sta) 2668ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return -ENOENT; 2669ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2670ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return 0; 2671ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen} 2672ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2673ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 26745fad5a2e1f34b333a801b749c4e143c2ac3e8a4fAdrian Bunkint prism2_hostapd(struct ap_data *ap, struct prism2_hostapd_param *param) 2675ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{ 2676ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen switch (param->cmd) { 2677ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen case PRISM2_HOSTAPD_FLUSH: 2678ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen ap_control_kickall(ap); 2679ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return 0; 2680ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen case PRISM2_HOSTAPD_ADD_STA: 2681ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return prism2_hostapd_add_sta(ap, param); 2682ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen case PRISM2_HOSTAPD_REMOVE_STA: 2683ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return prism2_hostapd_remove_sta(ap, param); 2684ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen case PRISM2_HOSTAPD_GET_INFO_STA: 2685ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return prism2_hostapd_get_info_sta(ap, param); 2686ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen case PRISM2_HOSTAPD_SET_FLAGS_STA: 2687ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return prism2_hostapd_set_flags_sta(ap, param); 2688ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen case PRISM2_HOSTAPD_STA_CLEAR_STATS: 2689ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return prism2_hostapd_sta_clear_stats(ap, param); 2690ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen default: 2691ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen printk(KERN_WARNING "prism2_hostapd: unknown cmd=%d\n", 2692ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen param->cmd); 2693ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return -EOPNOTSUPP; 2694ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 2695ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen} 2696ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2697ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2698ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen/* Update station info for host-based TX rate control and return current 2699ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * TX rate */ 2700ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenstatic int ap_update_sta_tx_rate(struct sta_info *sta, struct net_device *dev) 2701ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{ 2702ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen int ret = sta->tx_rate; 2703ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct hostap_interface *iface; 2704ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen local_info_t *local; 2705ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2706ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen iface = netdev_priv(dev); 2707ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen local = iface->local; 2708ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2709ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->tx_count[sta->tx_rate_idx]++; 2710ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->tx_since_last_failure++; 2711ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->tx_consecutive_exc = 0; 2712ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (sta->tx_since_last_failure >= WLAN_RATE_UPDATE_COUNT && 2713ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->tx_rate_idx < sta->tx_max_rate) { 2714ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen /* use next higher rate */ 2715ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen int old_rate, new_rate; 2716ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen old_rate = new_rate = sta->tx_rate_idx; 2717ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen while (new_rate < sta->tx_max_rate) { 2718ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen new_rate++; 2719ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (ap_tx_rate_ok(new_rate, sta, local)) { 2720ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->tx_rate_idx = new_rate; 2721ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen break; 2722ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 2723ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 2724ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (old_rate != sta->tx_rate_idx) { 2725ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen switch (sta->tx_rate_idx) { 2726ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen case 0: sta->tx_rate = 10; break; 2727ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen case 1: sta->tx_rate = 20; break; 2728ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen case 2: sta->tx_rate = 55; break; 2729ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen case 3: sta->tx_rate = 110; break; 2730ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen default: sta->tx_rate = 0; break; 2731ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 2732e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg PDEBUG(DEBUG_AP, "%s: STA %pM TX rate raised to %d\n", 2733e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg dev->name, sta->addr, sta->tx_rate); 2734ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 2735ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->tx_since_last_failure = 0; 2736ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 2737ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2738ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return ret; 2739ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen} 2740ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2741ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2742ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen/* Called only from software IRQ. Called for each TX frame prior possible 2743ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * encryption and transmit. */ 2744ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenap_tx_ret hostap_handle_sta_tx(local_info_t *local, struct hostap_tx_data *tx) 2745ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{ 2746ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct sta_info *sta = NULL; 2747ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct sk_buff *skb = tx->skb; 2748ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen int set_tim, ret; 27491ea893fde29d8cf1639da8989f4b843dc3283ca8Dan Williams struct ieee80211_hdr *hdr; 2750ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct hostap_skb_tx_data *meta; 2751ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2752ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen meta = (struct hostap_skb_tx_data *) skb->cb; 2753ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen ret = AP_TX_CONTINUE; 2754ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (local->ap == NULL || skb->len < 10 || 2755ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen meta->iface->type == HOSTAP_INTERFACE_STA) 2756ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen goto out; 2757ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 27581ea893fde29d8cf1639da8989f4b843dc3283ca8Dan Williams hdr = (struct ieee80211_hdr *) skb->data; 2759ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2760ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (hdr->addr1[0] & 0x01) { 2761ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen /* broadcast/multicast frame - no AP related processing */ 2762b918099030fe6cc093a7d60a88039bd98f16538ePavel Roskin if (local->ap->num_sta <= 0) 2763b918099030fe6cc093a7d60a88039bd98f16538ePavel Roskin ret = AP_TX_DROP; 2764ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen goto out; 2765ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 2766ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2767ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen /* unicast packet - check whether destination STA is associated */ 2768ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen spin_lock(&local->ap->sta_table_lock); 2769ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta = ap_get_sta(local->ap, hdr->addr1); 2770ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (sta) 2771ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen atomic_inc(&sta->users); 2772ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen spin_unlock(&local->ap->sta_table_lock); 2773ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 27745bee720fd7fa5ed4eade96058acd3a684da30932Jouni Malinen if (local->iw_mode == IW_MODE_MASTER && sta == NULL && 27755bee720fd7fa5ed4eade96058acd3a684da30932Jouni Malinen !(meta->flags & HOSTAP_TX_FLAGS_WDS) && 2776ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen meta->iface->type != HOSTAP_INTERFACE_MASTER && 2777ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen meta->iface->type != HOSTAP_INTERFACE_AP) { 2778ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#if 0 2779ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen /* This can happen, e.g., when wlan0 is added to a bridge and 2780ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * bridging code does not know which port is the correct target 2781ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * for a unicast frame. In this case, the packet is send to all 2782ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * ports of the bridge. Since this is a valid scenario, do not 2783ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * print out any errors here. */ 2784ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (net_ratelimit()) { 2785ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen printk(KERN_DEBUG "AP: drop packet to non-associated " 2786e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg "STA %pM\n", hdr->addr1); 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 */ 28131ea893fde29d8cf1639da8989f4b843dc3283ca8Dan Williams hdr->frame_control |= 2814c1b4aa3fb619782213af2af6652663c8f9cef373Harvey Harrison 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) { 2824e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg PDEBUG(DEBUG_PS, "%s: No more space in STA (%pM)'s" 2825e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg "PS mode buffer\n", 2826e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg local->dev->name, sta->addr); 2827ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen /* Make sure that TIM is set for the station (it might not be 2828ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * after AP wlan hw reset). */ 2829ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen /* FIX: should fix hw reset to restore bits based on STA 2830ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * buffer state.. */ 2831ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen hostap_set_tim(local, sta->aid, 1); 2832ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->flags |= WLAN_STA_TIM; 2833ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen ret = AP_TX_DROP; 2834ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen goto out; 2835ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 2836ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2837ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen /* STA in PS mode, buffer frame for later delivery */ 2838ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen set_tim = skb_queue_empty(&sta->tx_buf); 2839ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen skb_queue_tail(&sta->tx_buf, skb); 2840ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen /* FIX: could save RX time to skb and expire buffered frames after 2841ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * some time if STA does not poll for them */ 2842ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2843ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (set_tim) { 2844ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (sta->flags & WLAN_STA_TIM) 2845ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen PDEBUG(DEBUG_PS2, "Re-setting TIM for aid %d\n", 2846ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->aid); 2847ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen hostap_set_tim(local, sta->aid, 1); 2848ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->flags |= WLAN_STA_TIM; 2849ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 2850ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2851ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen ret = AP_TX_BUFFERED; 2852ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2853ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen out: 2854ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (sta != NULL) { 2855ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (ret == AP_TX_CONTINUE || 2856ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen ret == AP_TX_CONTINUE_NOT_AUTHORIZED) { 2857ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->tx_packets++; 2858ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->tx_bytes += skb->len; 2859ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->last_tx = jiffies; 2860ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 2861ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2862ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if ((ret == AP_TX_CONTINUE || 2863ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen ret == AP_TX_CONTINUE_NOT_AUTHORIZED) && 2864ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->crypt && tx->host_encrypt) { 2865ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen tx->crypt = sta->crypt; 2866ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen tx->sta_ptr = sta; /* hostap_handle_sta_release() will 2867ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * be called to release sta info 2868ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * later */ 2869ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } else 2870ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen atomic_dec(&sta->users); 2871ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 2872ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2873ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return ret; 2874ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen} 2875ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2876ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2877ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenvoid hostap_handle_sta_release(void *ptr) 2878ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{ 2879ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct sta_info *sta = ptr; 2880ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen atomic_dec(&sta->users); 2881ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen} 2882ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2883ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2884ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen/* Called only as a tasklet (software IRQ) */ 2885ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenvoid hostap_handle_sta_tx_exc(local_info_t *local, struct sk_buff *skb) 2886ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{ 2887ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct sta_info *sta; 28881ea893fde29d8cf1639da8989f4b843dc3283ca8Dan Williams struct ieee80211_hdr *hdr; 2889ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct hostap_skb_tx_data *meta; 2890ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 28911ea893fde29d8cf1639da8989f4b843dc3283ca8Dan Williams hdr = (struct ieee80211_hdr *) skb->data; 2892ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen meta = (struct hostap_skb_tx_data *) skb->cb; 2893ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2894ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen spin_lock(&local->ap->sta_table_lock); 2895ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta = ap_get_sta(local->ap, hdr->addr1); 2896ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (!sta) { 2897ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen spin_unlock(&local->ap->sta_table_lock); 2898e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg PDEBUG(DEBUG_AP, "%s: Could not find STA %pM" 28990795af5729b18218767fab27c44b1384f72dc9adJoe Perches " for this TX error (@%lu)\n", 2900e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg local->dev->name, hdr->addr1, jiffies); 2901ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return; 2902ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 2903ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2904ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->tx_since_last_failure = 0; 2905ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->tx_consecutive_exc++; 290674fae82c8bd5dd78365abe25506a9ba388d4a889Jeff Garzik 2907ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (sta->tx_consecutive_exc >= WLAN_RATE_DECREASE_THRESHOLD && 2908ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->tx_rate_idx > 0 && meta->rate <= sta->tx_rate) { 2909ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen /* use next lower rate */ 2910ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen int old, rate; 2911ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen old = rate = sta->tx_rate_idx; 2912ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen while (rate > 0) { 2913ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen rate--; 2914ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (ap_tx_rate_ok(rate, sta, local)) { 2915ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->tx_rate_idx = rate; 2916ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen break; 2917ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 2918ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 2919ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (old != sta->tx_rate_idx) { 2920ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen switch (sta->tx_rate_idx) { 2921ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen case 0: sta->tx_rate = 10; break; 2922ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen case 1: sta->tx_rate = 20; break; 2923ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen case 2: sta->tx_rate = 55; break; 2924ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen case 3: sta->tx_rate = 110; break; 2925ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen default: sta->tx_rate = 0; break; 2926ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 2927e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg PDEBUG(DEBUG_AP, 2928e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg "%s: STA %pM TX rate lowered to %d\n", 2929e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg local->dev->name, sta->addr, sta->tx_rate); 2930ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 2931ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->tx_consecutive_exc = 0; 2932ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 2933ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen spin_unlock(&local->ap->sta_table_lock); 2934ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen} 2935ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2936ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2937ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenstatic void hostap_update_sta_ps2(local_info_t *local, struct sta_info *sta, 2938ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen int pwrmgt, int type, int stype) 2939ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{ 2940ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (pwrmgt && !(sta->flags & WLAN_STA_PS)) { 2941ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->flags |= WLAN_STA_PS; 2942e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg PDEBUG(DEBUG_PS2, "STA %pM changed to use PS " 2943ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen "mode (type=0x%02X, stype=0x%02X)\n", 2944e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg sta->addr, type >> 2, stype >> 4); 2945ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } else if (!pwrmgt && (sta->flags & WLAN_STA_PS)) { 2946ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->flags &= ~WLAN_STA_PS; 2947e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg PDEBUG(DEBUG_PS2, "STA %pM changed to not use " 2948ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen "PS mode (type=0x%02X, stype=0x%02X)\n", 2949e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg sta->addr, type >> 2, stype >> 4); 29504339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen if (type != IEEE80211_FTYPE_CTL || 29514339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen stype != IEEE80211_STYPE_PSPOLL) 2952ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen schedule_packet_send(local, sta); 2953ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 2954ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen} 2955ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2956ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2957ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen/* Called only as a tasklet (software IRQ). Called for each RX frame to update 29581ea893fde29d8cf1639da8989f4b843dc3283ca8Dan Williams * STA power saving state. pwrmgt is a flag from 802.11 frame_control field. */ 29591ea893fde29d8cf1639da8989f4b843dc3283ca8Dan Williamsint hostap_update_sta_ps(local_info_t *local, struct ieee80211_hdr *hdr) 2960ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{ 2961ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct sta_info *sta; 2962ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen u16 fc; 2963ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2964ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen spin_lock(&local->ap->sta_table_lock); 2965ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta = ap_get_sta(local->ap, hdr->addr2); 2966ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (sta) 2967ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen atomic_inc(&sta->users); 2968ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen spin_unlock(&local->ap->sta_table_lock); 2969ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2970ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (!sta) 2971ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return -1; 2972ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 29731ea893fde29d8cf1639da8989f4b843dc3283ca8Dan Williams fc = le16_to_cpu(hdr->frame_control); 2974b2f4a2e3b1620667da9654f9e220c92ea52bdbe4Jouni Malinen hostap_update_sta_ps2(local, sta, fc & IEEE80211_FCTL_PM, 29751ea893fde29d8cf1639da8989f4b843dc3283ca8Dan Williams fc & IEEE80211_FCTL_FTYPE, 29761ea893fde29d8cf1639da8989f4b843dc3283ca8Dan Williams fc & IEEE80211_FCTL_STYPE); 2977ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2978ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen atomic_dec(&sta->users); 2979ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return 0; 2980ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen} 2981ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2982ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2983ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen/* Called only as a tasklet (software IRQ). Called for each RX frame after 2984ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * getting RX header and payload from hardware. */ 2985ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenap_rx_ret hostap_handle_sta_rx(local_info_t *local, struct net_device *dev, 2986ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct sk_buff *skb, 2987ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct hostap_80211_rx_status *rx_stats, 2988ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen int wds) 2989ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{ 2990ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen int ret; 2991ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct sta_info *sta; 2992ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen u16 fc, type, stype; 29931ea893fde29d8cf1639da8989f4b843dc3283ca8Dan Williams struct ieee80211_hdr *hdr; 2994ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 2995ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (local->ap == NULL) 2996ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return AP_RX_CONTINUE; 2997ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 29981ea893fde29d8cf1639da8989f4b843dc3283ca8Dan Williams hdr = (struct ieee80211_hdr *) skb->data; 2999ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 30001ea893fde29d8cf1639da8989f4b843dc3283ca8Dan Williams fc = le16_to_cpu(hdr->frame_control); 30011ea893fde29d8cf1639da8989f4b843dc3283ca8Dan Williams type = fc & IEEE80211_FCTL_FTYPE; 30021ea893fde29d8cf1639da8989f4b843dc3283ca8Dan Williams stype = fc & IEEE80211_FCTL_STYPE; 3003ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 3004ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen spin_lock(&local->ap->sta_table_lock); 3005ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta = ap_get_sta(local->ap, hdr->addr2); 3006ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (sta) 3007ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen atomic_inc(&sta->users); 3008ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen spin_unlock(&local->ap->sta_table_lock); 3009ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 3010ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (sta && !(sta->flags & WLAN_STA_AUTHORIZED)) 3011ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen ret = AP_RX_CONTINUE_NOT_AUTHORIZED; 3012ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen else 3013ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen ret = AP_RX_CONTINUE; 3014ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 3015ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 3016b2f4a2e3b1620667da9654f9e220c92ea52bdbe4Jouni Malinen if (fc & IEEE80211_FCTL_TODS) { 3017ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (!wds && (sta == NULL || !(sta->flags & WLAN_STA_ASSOC))) { 3018ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (local->hostapd) { 3019ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen prism2_rx_80211(local->apdev, skb, rx_stats, 3020ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen PRISM2_RX_NON_ASSOC); 3021ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT 3022ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } else { 3023ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen printk(KERN_DEBUG "%s: dropped received packet" 3024e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg " from non-associated STA %pM" 3025ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen " (type=0x%02x, subtype=0x%02x)\n", 3026e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg dev->name, hdr->addr2, 30274339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen type >> 2, stype >> 4); 3028ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen hostap_rx(dev, skb, rx_stats); 3029ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ 3030ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 3031ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen ret = AP_RX_EXIT; 3032ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen goto out; 3033ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 3034b2f4a2e3b1620667da9654f9e220c92ea52bdbe4Jouni Malinen } else if (fc & IEEE80211_FCTL_FROMDS) { 3035ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (!wds) { 3036ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen /* FromDS frame - not for us; probably 3037ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * broadcast/multicast in another BSS - drop */ 3038d22fbd70c2770b5e3ba0d7bc5b29f6ee686cdba4dingtianhong if (ether_addr_equal(hdr->addr1, dev->dev_addr)) { 3039ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen printk(KERN_DEBUG "Odd.. FromDS packet " 3040ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen "received with own BSSID\n"); 3041ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen hostap_dump_rx_80211(dev->name, skb, rx_stats); 3042ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 3043ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen ret = AP_RX_DROP; 3044ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen goto out; 3045ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 30464339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen } else if (stype == IEEE80211_STYPE_NULLFUNC && sta == NULL && 3047d22fbd70c2770b5e3ba0d7bc5b29f6ee686cdba4dingtianhong ether_addr_equal(hdr->addr1, dev->dev_addr)) { 3048ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 3049ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (local->hostapd) { 3050ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen prism2_rx_80211(local->apdev, skb, rx_stats, 3051ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen PRISM2_RX_NON_ASSOC); 3052ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT 3053ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } else { 3054ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen /* At least Lucent f/w seems to send data::nullfunc 3055ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * frames with no ToDS flag when the current AP returns 3056ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * after being unavailable for some time. Speed up 3057ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * re-association by informing the station about it not 3058ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * being associated. */ 3059e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg printk(KERN_DEBUG "%s: rejected received nullfunc frame" 3060e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg " without ToDS from not associated STA %pM\n", 3061e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg dev->name, hdr->addr2); 3062ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen hostap_rx(dev, skb, rx_stats); 3063ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ 3064ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 3065ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen ret = AP_RX_EXIT; 3066ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen goto out; 30674339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen } else if (stype == IEEE80211_STYPE_NULLFUNC) { 3068ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen /* At least Lucent cards seem to send periodic nullfunc 3069ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * frames with ToDS. Let these through to update SQ 3070ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * stats and PS state. Nullfunc frames do not contain 3071ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * any data and they will be dropped below. */ 3072ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } else { 3073ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen /* If BSSID (Addr3) is foreign, this frame is a normal 3074ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * broadcast frame from an IBSS network. Drop it silently. 3075ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * If BSSID is own, report the dropping of this frame. */ 3076d22fbd70c2770b5e3ba0d7bc5b29f6ee686cdba4dingtianhong if (ether_addr_equal(hdr->addr3, dev->dev_addr)) { 3077e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg printk(KERN_DEBUG "%s: dropped received packet from %pM" 3078e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg " with no ToDS flag " 30790795af5729b18218767fab27c44b1384f72dc9adJoe Perches "(type=0x%02x, subtype=0x%02x)\n", dev->name, 3080e174961ca1a0b28f7abf0be47973ad57cb74e5f0Johannes Berg hdr->addr2, type >> 2, stype >> 4); 3081ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen hostap_dump_rx_80211(dev->name, skb, rx_stats); 3082ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 3083ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen ret = AP_RX_DROP; 3084ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen goto out; 3085ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 3086ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 3087ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (sta) { 3088b2f4a2e3b1620667da9654f9e220c92ea52bdbe4Jouni Malinen hostap_update_sta_ps2(local, sta, fc & IEEE80211_FCTL_PM, 3089ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen type, stype); 3090ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 3091ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->rx_packets++; 3092ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->rx_bytes += skb->len; 3093ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->last_rx = jiffies; 3094ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 3095ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 30964339d328631aa815fe2181b9164b3690ca2db4daJouni Malinen if (local->ap->nullfunc_ack && stype == IEEE80211_STYPE_NULLFUNC && 3097b2f4a2e3b1620667da9654f9e220c92ea52bdbe4Jouni Malinen fc & IEEE80211_FCTL_TODS) { 3098ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (local->hostapd) { 3099ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen prism2_rx_80211(local->apdev, skb, rx_stats, 3100ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen PRISM2_RX_NULLFUNC_ACK); 3101ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT 3102ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } else { 3103ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen /* some STA f/w's seem to require control::ACK frame 3104ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * for data::nullfunc, but Prism2 f/w 0.8.0 (at least 3105ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * from Compaq) does not send this.. Try to generate 3106ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * ACK for these frames from the host driver to make 3107ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * power saving work with, e.g., Lucent WaveLAN f/w */ 3108ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen hostap_rx(dev, skb, rx_stats); 3109ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ 3110ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 3111ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen ret = AP_RX_EXIT; 3112ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen goto out; 3113ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 3114ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 3115ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen out: 3116ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (sta) 3117ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen atomic_dec(&sta->users); 3118ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 3119ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return ret; 3120ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen} 3121ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 3122ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 3123ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen/* Called only as a tasklet (software IRQ) */ 3124ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenint hostap_handle_sta_crypto(local_info_t *local, 31251ea893fde29d8cf1639da8989f4b843dc3283ca8Dan Williams struct ieee80211_hdr *hdr, 3126274bfb8dc5ffa16cb073801bebe76ab7f4e2e73dJohn W. Linville struct lib80211_crypt_data **crypt, 312762fe7e378109537ff80971c5208e12d40bf88beeJouni Malinen void **sta_ptr) 3128ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{ 3129ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct sta_info *sta; 3130ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 3131ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen spin_lock(&local->ap->sta_table_lock); 3132ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta = ap_get_sta(local->ap, hdr->addr2); 3133ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (sta) 3134ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen atomic_inc(&sta->users); 3135ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen spin_unlock(&local->ap->sta_table_lock); 3136ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 3137ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (!sta) 3138ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return -1; 3139ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 3140ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (sta->crypt) { 3141ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen *crypt = sta->crypt; 3142ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen *sta_ptr = sta; 3143ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen /* hostap_handle_sta_release() will be called to release STA 3144ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * info */ 3145ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } else 3146ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen atomic_dec(&sta->users); 3147ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 3148ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return 0; 3149ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen} 3150ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 3151ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 3152ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen/* Called only as a tasklet (software IRQ) */ 3153ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenint hostap_is_sta_assoc(struct ap_data *ap, u8 *sta_addr) 3154ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{ 3155ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct sta_info *sta; 3156ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen int ret = 0; 3157ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 3158ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen spin_lock(&ap->sta_table_lock); 3159ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta = ap_get_sta(ap, sta_addr); 3160ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (sta != NULL && (sta->flags & WLAN_STA_ASSOC) && !sta->ap) 3161ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen ret = 1; 3162ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen spin_unlock(&ap->sta_table_lock); 3163ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 3164ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return ret; 3165ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen} 3166ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 3167ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 3168ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen/* Called only as a tasklet (software IRQ) */ 3169ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenint hostap_is_sta_authorized(struct ap_data *ap, u8 *sta_addr) 3170ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{ 3171ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct sta_info *sta; 3172ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen int ret = 0; 3173ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 3174ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen spin_lock(&ap->sta_table_lock); 3175ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta = ap_get_sta(ap, sta_addr); 3176ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (sta != NULL && (sta->flags & WLAN_STA_ASSOC) && !sta->ap && 3177ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen ((sta->flags & WLAN_STA_AUTHORIZED) || 3178ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen ap->local->ieee_802_1x == 0)) 3179ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen ret = 1; 3180ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen spin_unlock(&ap->sta_table_lock); 3181ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 3182ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return ret; 3183ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen} 3184ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 3185ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 3186ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen/* Called only as a tasklet (software IRQ) */ 3187ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenint hostap_add_sta(struct ap_data *ap, u8 *sta_addr) 3188ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{ 3189ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct sta_info *sta; 3190ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen int ret = 1; 3191ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 3192ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (!ap) 3193ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return -1; 3194ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 3195ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen spin_lock(&ap->sta_table_lock); 3196ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta = ap_get_sta(ap, sta_addr); 3197ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (sta) 3198ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen ret = 0; 3199ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen spin_unlock(&ap->sta_table_lock); 3200ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 3201ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (ret == 1) { 3202ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta = ap_add_sta(ap, sta_addr); 3203ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (!sta) 320454b85f489bdfafc9306dfcc21e0d2687c34c3b34Adrian Bunk return -1; 3205ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->flags = WLAN_STA_AUTH | WLAN_STA_ASSOC; 3206ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->ap = 1; 3207ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen memset(sta->supported_rates, 0, sizeof(sta->supported_rates)); 3208ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen /* No way of knowing which rates are supported since we did not 3209ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * get supported rates element from beacon/assoc req. Assume 3210ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen * that remote end supports all 802.11b rates. */ 3211ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->supported_rates[0] = 0x82; 3212ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->supported_rates[1] = 0x84; 3213ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->supported_rates[2] = 0x0b; 3214ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->supported_rates[3] = 0x16; 3215ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->tx_supp_rates = WLAN_RATE_1M | WLAN_RATE_2M | 3216ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen WLAN_RATE_5M5 | WLAN_RATE_11M; 3217ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->tx_rate = 110; 3218ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->tx_max_rate = sta->tx_rate_idx = 3; 3219ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 3220ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 3221ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return ret; 3222ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen} 3223ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 3224ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 3225ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen/* Called only as a tasklet (software IRQ) */ 3226ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenint hostap_update_rx_stats(struct ap_data *ap, 32271ea893fde29d8cf1639da8989f4b843dc3283ca8Dan Williams struct ieee80211_hdr *hdr, 3228ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct hostap_80211_rx_status *rx_stats) 3229ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{ 3230ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct sta_info *sta; 3231ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 3232ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (!ap) 3233ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return -1; 3234ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 3235ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen spin_lock(&ap->sta_table_lock); 3236ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta = ap_get_sta(ap, hdr->addr2); 3237ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (sta) { 3238ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->last_rx_silence = rx_stats->noise; 3239ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->last_rx_signal = rx_stats->signal; 3240ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->last_rx_rate = rx_stats->rate; 3241c28df16ed70d1b6cefd12135e3c68bfccd1bb635Jean Tourrilhes sta->last_rx_updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; 3242ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (rx_stats->rate == 10) 3243ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->rx_count[0]++; 3244ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen else if (rx_stats->rate == 20) 3245ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->rx_count[1]++; 3246ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen else if (rx_stats->rate == 55) 3247ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->rx_count[2]++; 3248ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen else if (rx_stats->rate == 110) 3249ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->rx_count[3]++; 3250ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 3251ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen spin_unlock(&ap->sta_table_lock); 3252ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 3253ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return sta ? 0 : -1; 3254ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen} 3255ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 3256ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 3257ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenvoid hostap_update_rates(local_info_t *local) 3258ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{ 3259c15057313725942c6af8dcb60b4d4322101316d9Matthias Kaehlcke struct sta_info *sta; 3260ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct ap_data *ap = local->ap; 3261ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 3262ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (!ap) 3263ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return; 3264ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 3265ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen spin_lock_bh(&ap->sta_table_lock); 3266c15057313725942c6af8dcb60b4d4322101316d9Matthias Kaehlcke list_for_each_entry(sta, &ap->sta_list, list) { 3267ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen prism2_check_tx_rates(sta); 3268ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 3269ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen spin_unlock_bh(&ap->sta_table_lock); 3270ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen} 3271ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 3272ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 32735fad5a2e1f34b333a801b749c4e143c2ac3e8a4fAdrian Bunkvoid * ap_crypt_get_ptrs(struct ap_data *ap, u8 *addr, int permanent, 3274274bfb8dc5ffa16cb073801bebe76ab7f4e2e73dJohn W. Linville struct lib80211_crypt_data ***crypt) 3275ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{ 3276ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct sta_info *sta; 3277ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 3278ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen spin_lock_bh(&ap->sta_table_lock); 3279ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta = ap_get_sta(ap, addr); 3280ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (sta) 3281ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen atomic_inc(&sta->users); 3282ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen spin_unlock_bh(&ap->sta_table_lock); 3283ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 3284ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (!sta && permanent) 3285ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta = ap_add_sta(ap, addr); 3286ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 3287ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (!sta) 3288ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return NULL; 3289ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 3290ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (permanent) 3291ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen sta->flags |= WLAN_STA_PERM; 3292ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 3293ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen *crypt = &sta->crypt; 3294ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 3295ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return sta; 3296ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen} 3297ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 3298ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 3299ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenvoid hostap_add_wds_links(local_info_t *local) 3300ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{ 3301ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct ap_data *ap = local->ap; 3302c15057313725942c6af8dcb60b4d4322101316d9Matthias Kaehlcke struct sta_info *sta; 3303ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 3304ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen spin_lock_bh(&ap->sta_table_lock); 3305c15057313725942c6af8dcb60b4d4322101316d9Matthias Kaehlcke list_for_each_entry(sta, &ap->sta_list, list) { 3306ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (sta->ap) 3307ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen hostap_wds_link_oper(local, sta->addr, WDS_ADD); 3308ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen } 3309ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen spin_unlock_bh(&ap->sta_table_lock); 3310ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 3311ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen schedule_work(&local->ap->wds_oper_queue); 3312ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen} 3313ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 3314ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 3315ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinenvoid hostap_wds_link_oper(local_info_t *local, u8 *addr, wds_oper_type type) 3316ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen{ 3317ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen struct wds_oper_data *entry; 3318ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 3319ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen entry = kmalloc(sizeof(*entry), GFP_ATOMIC); 3320ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen if (!entry) 3321ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen return; 3322ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen memcpy(entry->addr, addr, ETH_ALEN); 3323ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen entry->type = type; 3324ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen spin_lock_bh(&local->lock); 3325ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen entry->next = local->ap->wds_oper_entries; 3326ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen local->ap->wds_oper_entries = entry; 3327ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen spin_unlock_bh(&local->lock); 3328ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 3329ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen schedule_work(&local->ap->wds_oper_queue); 3330ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen} 3331ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 3332ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen 3333ff1d2767d5a43c85f944e86a45284b721f66196cJouni MalinenEXPORT_SYMBOL(hostap_init_data); 3334ff1d2767d5a43c85f944e86a45284b721f66196cJouni MalinenEXPORT_SYMBOL(hostap_init_ap_proc); 3335ff1d2767d5a43c85f944e86a45284b721f66196cJouni MalinenEXPORT_SYMBOL(hostap_free_data); 3336ff1d2767d5a43c85f944e86a45284b721f66196cJouni MalinenEXPORT_SYMBOL(hostap_check_sta_fw_version); 3337ff1d2767d5a43c85f944e86a45284b721f66196cJouni MalinenEXPORT_SYMBOL(hostap_handle_sta_tx_exc); 3338ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT 3339ff1d2767d5a43c85f944e86a45284b721f66196cJouni Malinen#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ 3340