📄 hostap_ap.c
字号:
hdr->frame_ctl = cpu_to_le16(fc); meta = (struct hostap_skb_tx_data *) skb->cb; memset(meta, 0, sizeof(*meta)); meta->magic = HOSTAP_SKB_TX_DATA_MAGIC; meta->iface = iface; meta->tx_cb_idx = tx_cb_idx; skb->dev = dev; skb->mac.raw = skb->nh.raw = skb->data; dev_queue_xmit(skb);}#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */static int prism2_sta_proc_read(char *page, char **start, off_t off, int count, int *eof, void *data){ char *p = page; struct sta_info *sta = (struct sta_info *) data; int i; /* FIX: possible race condition.. the STA data could have just expired, * but proc entry was still here so that the read could have started; * some locking should be done here.. */ if (off != 0) { *eof = 1; return 0; } p += sprintf(p, "%s=" MACSTR "\nusers=%d\naid=%d\n" "flags=0x%04x%s%s%s%s%s%s%s\n" "capability=0x%02x\nlisten_interval=%d\nsupported_rates=", sta->ap ? "AP" : "STA", MAC2STR(sta->addr), atomic_read(&sta->users), sta->aid, sta->flags, sta->flags & WLAN_STA_AUTH ? " AUTH" : "", sta->flags & WLAN_STA_ASSOC ? " ASSOC" : "", sta->flags & WLAN_STA_PS ? " PS" : "", sta->flags & WLAN_STA_TIM ? " TIM" : "", sta->flags & WLAN_STA_PERM ? " PERM" : "", sta->flags & WLAN_STA_AUTHORIZED ? " AUTHORIZED" : "", sta->flags & WLAN_STA_PENDING_POLL ? " POLL" : "", sta->capability, sta->listen_interval); /* supported_rates: 500 kbit/s units with msb ignored */ for (i = 0; i < sizeof(sta->supported_rates); i++) if (sta->supported_rates[i] != 0) p += sprintf(p, "%d%sMbps ", (sta->supported_rates[i] & 0x7f) / 2, sta->supported_rates[i] & 1 ? ".5" : ""); p += sprintf(p, "\njiffies=%lu\nlast_auth=%lu\nlast_assoc=%lu\n" "last_rx=%lu\nlast_tx=%lu\nrx_packets=%lu\n" "tx_packets=%lu\n" "rx_bytes=%lu\ntx_bytes=%lu\nbuffer_count=%d\n" "last_rx: silence=%d dBm signal=%d dBm rate=%d%s Mbps\n" "tx_rate=%d\ntx[1M]=%d\ntx[2M]=%d\ntx[5.5M]=%d\n" "tx[11M]=%d\n" "rx[1M]=%d\nrx[2M]=%d\nrx[5.5M]=%d\nrx[11M]=%d\n", jiffies, sta->last_auth, sta->last_assoc, sta->last_rx, sta->last_tx, sta->rx_packets, sta->tx_packets, sta->rx_bytes, sta->tx_bytes, skb_queue_len(&sta->tx_buf), sta->last_rx_silence, sta->last_rx_signal, sta->last_rx_rate / 10, sta->last_rx_rate % 10 ? ".5" : "", sta->tx_rate, sta->tx_count[0], sta->tx_count[1], sta->tx_count[2], sta->tx_count[3], sta->rx_count[0], sta->rx_count[1], sta->rx_count[2], sta->rx_count[3]); if (sta->crypt && sta->crypt->ops && sta->crypt->ops->print_stats) p = sta->crypt->ops->print_stats(p, sta->crypt->priv);#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT if (sta->ap) { if (sta->u.ap.channel >= 0) p += sprintf(p, "channel=%d\n", sta->u.ap.channel); p += sprintf(p, "ssid="); for (i = 0; i < sta->u.ap.ssid_len; i++) p += sprintf(p, ((sta->u.ap.ssid[i] >= 32 && sta->u.ap.ssid[i] < 127) ? "%c" : "<%02x>"), sta->u.ap.ssid[i]); p += sprintf(p, "\n"); }#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ return (p - page);}static void handle_add_proc_queue(void *data){ struct ap_data *ap = (struct ap_data *) data; struct sta_info *sta; char name[20]; struct add_sta_proc_data *entry, *prev; entry = ap->add_sta_proc_entries; ap->add_sta_proc_entries = NULL; while (entry) { spin_lock_bh(&ap->sta_table_lock); sta = ap_get_sta(ap, entry->addr); if (sta) atomic_inc(&sta->users); spin_unlock_bh(&ap->sta_table_lock); if (sta) { sprintf(name, MACSTR, MAC2STR(sta->addr)); sta->proc = create_proc_read_entry( name, 0, ap->proc, prism2_sta_proc_read, sta); atomic_dec(&sta->users); } prev = entry; entry = entry->next; kfree(prev); }}static struct sta_info * ap_add_sta(struct ap_data *ap, u8 *addr){ struct sta_info *sta; sta = (struct sta_info *) kmalloc(sizeof(struct sta_info), GFP_ATOMIC); if (sta == NULL) { PDEBUG(DEBUG_AP, "AP: kmalloc failed\n"); return NULL; } /* initialize STA info data */ memset(sta, 0, sizeof(struct sta_info)); sta->local = ap->local; skb_queue_head_init(&sta->tx_buf); memcpy(sta->addr, addr, ETH_ALEN); atomic_inc(&sta->users); spin_lock_bh(&ap->sta_table_lock); list_add(&sta->list, &ap->sta_list); ap->num_sta++; ap_sta_hash_add(ap, sta); spin_unlock_bh(&ap->sta_table_lock); if (ap->proc) { struct add_sta_proc_data *entry; /* schedule a non-interrupt context process to add a procfs * entry for the STA since procfs code use GFP_KERNEL */ entry = kmalloc(sizeof(*entry), GFP_ATOMIC); if (entry) { memcpy(entry->addr, sta->addr, ETH_ALEN); entry->next = ap->add_sta_proc_entries; ap->add_sta_proc_entries = entry; schedule_work(&ap->add_sta_proc_queue); } else printk(KERN_DEBUG "Failed to add STA proc data\n"); }#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT init_timer(&sta->timer); sta->timer.expires = jiffies + ap->max_inactivity; sta->timer.data = (unsigned long) sta; sta->timer.function = ap_handle_timer; if (!ap->local->hostapd) add_timer(&sta->timer);#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ return sta;}static int ap_tx_rate_ok(int rateidx, struct sta_info *sta, local_info_t *local){ if (rateidx > sta->tx_max_rate || !(sta->tx_supp_rates & (1 << rateidx))) return 0; if (local->tx_rate_control != 0 && !(local->tx_rate_control & (1 << rateidx))) return 0; return 1;}static void prism2_check_tx_rates(struct sta_info *sta){ int i; sta->tx_supp_rates = 0; for (i = 0; i < sizeof(sta->supported_rates); i++) { if ((sta->supported_rates[i] & 0x7f) == 2) sta->tx_supp_rates |= WLAN_RATE_1M; if ((sta->supported_rates[i] & 0x7f) == 4) sta->tx_supp_rates |= WLAN_RATE_2M; if ((sta->supported_rates[i] & 0x7f) == 11) sta->tx_supp_rates |= WLAN_RATE_5M5; if ((sta->supported_rates[i] & 0x7f) == 22) sta->tx_supp_rates |= WLAN_RATE_11M; } sta->tx_max_rate = sta->tx_rate = sta->tx_rate_idx = 0; if (sta->tx_supp_rates & WLAN_RATE_1M) { sta->tx_max_rate = 0; if (ap_tx_rate_ok(0, sta, sta->local)) { sta->tx_rate = 10; sta->tx_rate_idx = 0; } } if (sta->tx_supp_rates & WLAN_RATE_2M) { sta->tx_max_rate = 1; if (ap_tx_rate_ok(1, sta, sta->local)) { sta->tx_rate = 20; sta->tx_rate_idx = 1; } } if (sta->tx_supp_rates & WLAN_RATE_5M5) { sta->tx_max_rate = 2; if (ap_tx_rate_ok(2, sta, sta->local)) { sta->tx_rate = 55; sta->tx_rate_idx = 2; } } if (sta->tx_supp_rates & WLAN_RATE_11M) { sta->tx_max_rate = 3; if (ap_tx_rate_ok(3, sta, sta->local)) { sta->tx_rate = 110; sta->tx_rate_idx = 3; } }}#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMTstatic void ap_crypt_init(struct ap_data *ap){ ap->crypt = ieee80211_get_crypto_ops("WEP"); if (ap->crypt) { if (ap->crypt->init) { ap->crypt_priv = ap->crypt->init(0); if (ap->crypt_priv == NULL) ap->crypt = NULL; else { u8 key[WEP_KEY_LEN]; get_random_bytes(key, WEP_KEY_LEN); ap->crypt->set_key(key, WEP_KEY_LEN, NULL, ap->crypt_priv); } } } if (ap->crypt == NULL) { printk(KERN_WARNING "AP could not initialize WEP: load module " "ieee80211_crypt_wep.ko\n"); }}/* Generate challenge data for shared key authentication. IEEE 802.11 specifies * that WEP algorithm is used for generating challange. This should be unique, * but otherwise there is not really need for randomness etc. Initialize WEP * with pseudo random key and then use increasing IV to get unique challenge * streams. * * Called only as a scheduled task for pending AP frames. */static char * ap_auth_make_challenge(struct ap_data *ap){ char *tmpbuf; struct sk_buff *skb; if (ap->crypt == NULL) { ap_crypt_init(ap); if (ap->crypt == NULL) return NULL; } tmpbuf = (char *) kmalloc(WLAN_AUTH_CHALLENGE_LEN, GFP_ATOMIC); if (tmpbuf == NULL) { PDEBUG(DEBUG_AP, "AP: kmalloc failed for challenge\n"); return NULL; } skb = dev_alloc_skb(WLAN_AUTH_CHALLENGE_LEN + ap->crypt->extra_mpdu_prefix_len + ap->crypt->extra_mpdu_postfix_len); if (skb == NULL) { kfree(tmpbuf); return NULL; } skb_reserve(skb, ap->crypt->extra_mpdu_prefix_len); memset(skb_put(skb, WLAN_AUTH_CHALLENGE_LEN), 0, WLAN_AUTH_CHALLENGE_LEN); if (ap->crypt->encrypt_mpdu(skb, 0, ap->crypt_priv)) { dev_kfree_skb(skb); kfree(tmpbuf); return NULL; } memcpy(tmpbuf, skb->data + ap->crypt->extra_mpdu_prefix_len, WLAN_AUTH_CHALLENGE_LEN); dev_kfree_skb(skb); return tmpbuf;}/* Called only as a scheduled task for pending AP frames. */static void handle_authen(local_info_t *local, struct sk_buff *skb, struct hostap_80211_rx_status *rx_stats){ struct net_device *dev = local->dev; struct ieee80211_hdr_4addr *hdr = (struct ieee80211_hdr_4addr *) skb->data; size_t hdrlen; struct ap_data *ap = local->ap; char body[8 + WLAN_AUTH_CHALLENGE_LEN], *challenge = NULL; int len, olen; u16 auth_alg, auth_transaction, status_code, *pos; u16 resp = WLAN_STATUS_SUCCESS, fc; struct sta_info *sta = NULL; struct ieee80211_crypt_data *crypt; char *txt = ""; len = skb->len - IEEE80211_MGMT_HDR_LEN; fc = le16_to_cpu(hdr->frame_ctl); hdrlen = hostap_80211_get_hdrlen(fc); if (len < 6) { PDEBUG(DEBUG_AP, "%s: handle_authen - too short payload " "(len=%d) from " MACSTR "\n", dev->name, len, MAC2STR(hdr->addr2)); return; } spin_lock_bh(&local->ap->sta_table_lock); sta = ap_get_sta(local->ap, hdr->addr2); if (sta) atomic_inc(&sta->users); spin_unlock_bh(&local->ap->sta_table_lock); if (sta && sta->crypt) crypt = sta->crypt; else { int idx = 0; if (skb->len >= hdrlen + 3) idx = skb->data[hdrlen + 3] >> 6; crypt = local->crypt[idx]; } pos = (u16 *) (skb->data + IEEE80211_MGMT_HDR_LEN); auth_alg = __le16_to_cpu(*pos); pos++; auth_transaction = __le16_to_cpu(*pos); pos++; status_code = __le16_to_cpu(*pos); pos++; if (memcmp(dev->dev_addr, hdr->addr2, ETH_ALEN) == 0 || ap_control_mac_deny(&ap->mac_restrictions, hdr->addr2)) { txt = "authentication denied"; resp = WLAN_STATUS_UNSPECIFIED_FAILURE; goto fail; } if (((local->auth_algs & PRISM2_AUTH_OPEN) && auth_alg == WLAN_AUTH_OPEN) || ((local->auth_algs & PRISM2_AUTH_SHARED_KEY) && crypt && auth_alg == WLAN_AUTH_SHARED_KEY)) { } else { txt = "unsupported algorithm"; resp = WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG; goto fail; } if (len >= 8) { u8 *u = (u8 *) pos; if (*u == WLAN_EID_CHALLENGE) { if (*(u + 1) != WLAN_AUTH_CHALLENGE_LEN) { txt = "invalid challenge len"; resp = WLAN_STATUS_CHALLENGE_FAIL; goto fail; } if (len - 8 < WLAN_AUTH_CHALLENGE_LEN) { txt = "challenge underflow"; resp = WLAN_STATUS_CHALLENGE_FAIL; goto fail; } challenge = (char *) (u + 2); } } if (sta && sta->ap) { if (time_after(jiffies, sta->u.ap.last_beacon + (10 * sta->listen_interval * HZ) / 1024)) { PDEBUG(DEBUG_AP, "%s: no beacons received for a while," " assuming AP " MACSTR " is now STA\n", dev->name, MAC2STR(sta->addr)); sta->ap = 0; sta->flags = 0; sta->u.sta.challenge = NULL; } else { txt = "AP trying to authenticate?"; resp = WLAN_STATUS_UNSPECIFIED_FAILURE; goto fail; } } if ((auth_alg == WLAN_AUTH_OPEN && auth_transaction == 1) || (auth_alg == WLAN_AUTH_SHARED_KEY && (auth_transaction == 1 || (auth_transaction == 3 && sta != NULL && sta->u.sta.challenge != NULL)))) { } else { txt = "unknown authentication transaction number"; resp = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION; goto fail; } if (sta == NULL) { txt = "new STA"; if (local->ap->num_sta >= MAX_STA_COUNT) { /* FIX: might try to remove some old STAs first? */ txt = "no more room for new STAs"; resp = WLAN_STATUS_UNSPECIFIED_FAILURE; goto fail; } sta = ap_add_sta(local->ap, hdr->addr2); if (sta == NULL) { txt = "ap_add_sta failed"; resp = WLAN_STATUS_UNSPECIFIED_FAILURE; goto fail; } } switch (auth_alg) { case WLAN_AUTH_OPEN: txt = "authOK"; /* IEEE 802.11 standard is not completely clear about * whether STA is considered authenticated after * authentication OK frame has been send or after it * has been ACKed. In order to reduce interoperability * issues, mark the STA authenticated before ACK. */ sta->flags |= WLAN_STA_AUTH; break; case WLAN_AUTH_SHARED_KEY: if (auth_transaction == 1) { if (sta->u.sta.challenge == NULL) { sta->u.sta.challenge = ap_auth_make_challenge(local->ap); if (sta->u.sta.challenge == NULL) { resp = WLAN_STATUS_UNSPECIFIED_FAILURE; goto fail; } } } else { if (sta->u.sta.challenge == NULL || challenge == NULL || memcmp(sta->u.sta.challenge, challenge, WLAN_AUTH_CHALLENGE_LEN) != 0 || !(fc & IEEE80211_FCTL_PROTECTED)) { txt = "challenge response incorrect"; resp = WLAN_STATUS_CHALLENGE_FAIL; goto fail; } txt = "challenge OK - authOK"; /* IEEE 802.11 standard is not completely clear about * whether STA is considered authenticated after * authentication OK frame has been send or after it * has been ACKed. In order to reduce interoperability * issues, mark the STA authenticated before ACK. */ sta->flags |= WLAN_STA_AUTH; kfree(sta->u.sta.challenge); sta->u.sta.challenge = NULL; } break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -