📄 hostap_ap.c
字号:
} fail: pos = (u16 *) body; *pos = cpu_to_le16(auth_alg); pos++; *pos = cpu_to_le16(auth_transaction + 1); pos++; *pos = cpu_to_le16(resp); /* status_code */ pos++; olen = 6; if (resp == WLAN_STATUS_SUCCESS && sta != NULL && sta->u.sta.challenge != NULL && auth_alg == WLAN_AUTH_SHARED_KEY && auth_transaction == 1) { u8 *tmp = (u8 *) pos; *tmp++ = WLAN_EID_CHALLENGE; *tmp++ = WLAN_AUTH_CHALLENGE_LEN; pos++; memcpy(pos, sta->u.sta.challenge, WLAN_AUTH_CHALLENGE_LEN); olen += 2 + WLAN_AUTH_CHALLENGE_LEN; } prism2_send_mgmt(dev, IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_AUTH, body, olen, hdr->addr2, ap->tx_callback_auth); if (sta) { sta->last_rx = jiffies; atomic_dec(&sta->users); } if (resp) { PDEBUG(DEBUG_AP, "%s: " MACSTR " auth (alg=%d trans#=%d " "stat=%d len=%d fc=%04x) ==> %d (%s)\n", dev->name, MAC2STR(hdr->addr2), auth_alg, auth_transaction, status_code, len, fc, resp, txt); }}/* Called only as a scheduled task for pending AP frames. */static void handle_assoc(local_info_t *local, struct sk_buff *skb, struct hostap_80211_rx_status *rx_stats, int reassoc){ struct net_device *dev = local->dev; struct ieee80211_hdr_4addr *hdr = (struct ieee80211_hdr_4addr *) skb->data; char body[12], *p, *lpos; int len, left; u16 *pos; u16 resp = WLAN_STATUS_SUCCESS; struct sta_info *sta = NULL; int send_deauth = 0; char *txt = ""; u8 prev_ap[ETH_ALEN]; left = len = skb->len - IEEE80211_MGMT_HDR_LEN; if (len < (reassoc ? 10 : 4)) { PDEBUG(DEBUG_AP, "%s: handle_assoc - too short payload " "(len=%d, reassoc=%d) from " MACSTR "\n", dev->name, len, reassoc, MAC2STR(hdr->addr2)); return; } spin_lock_bh(&local->ap->sta_table_lock); sta = ap_get_sta(local->ap, hdr->addr2); if (sta == NULL || (sta->flags & WLAN_STA_AUTH) == 0) { spin_unlock_bh(&local->ap->sta_table_lock); txt = "trying to associate before authentication"; send_deauth = 1; resp = WLAN_STATUS_UNSPECIFIED_FAILURE; sta = NULL; /* do not decrement sta->users */ goto fail; } atomic_inc(&sta->users); spin_unlock_bh(&local->ap->sta_table_lock); pos = (u16 *) (skb->data + IEEE80211_MGMT_HDR_LEN); sta->capability = __le16_to_cpu(*pos); pos++; left -= 2; sta->listen_interval = __le16_to_cpu(*pos); pos++; left -= 2; if (reassoc) { memcpy(prev_ap, pos, ETH_ALEN); pos++; pos++; pos++; left -= 6; } else memset(prev_ap, 0, ETH_ALEN); if (left >= 2) { unsigned int ileft; unsigned char *u = (unsigned char *) pos; if (*u == WLAN_EID_SSID) { u++; left--; ileft = *u; u++; left--; if (ileft > left || ileft > MAX_SSID_LEN) { txt = "SSID overflow"; resp = WLAN_STATUS_UNSPECIFIED_FAILURE; goto fail; } if (ileft != strlen(local->essid) || memcmp(local->essid, u, ileft) != 0) { txt = "not our SSID"; resp = WLAN_STATUS_ASSOC_DENIED_UNSPEC; goto fail; } u += ileft; left -= ileft; } if (left >= 2 && *u == WLAN_EID_SUPP_RATES) { u++; left--; ileft = *u; u++; left--; if (ileft > left || ileft == 0 || ileft > WLAN_SUPP_RATES_MAX) { txt = "SUPP_RATES len error"; resp = WLAN_STATUS_UNSPECIFIED_FAILURE; goto fail; } memset(sta->supported_rates, 0, sizeof(sta->supported_rates)); memcpy(sta->supported_rates, u, ileft); prism2_check_tx_rates(sta); u += ileft; left -= ileft; } if (left > 0) { PDEBUG(DEBUG_AP, "%s: assoc from " MACSTR " with extra" " data (%d bytes) [", dev->name, MAC2STR(hdr->addr2), left); while (left > 0) { PDEBUG2(DEBUG_AP, "<%02x>", *u); u++; left--; } PDEBUG2(DEBUG_AP, "]\n"); } } else { txt = "frame underflow"; resp = WLAN_STATUS_UNSPECIFIED_FAILURE; goto fail; } /* get a unique AID */ if (sta->aid > 0) txt = "OK, old AID"; else { spin_lock_bh(&local->ap->sta_table_lock); for (sta->aid = 1; sta->aid <= MAX_AID_TABLE_SIZE; sta->aid++) if (local->ap->sta_aid[sta->aid - 1] == NULL) break; if (sta->aid > MAX_AID_TABLE_SIZE) { sta->aid = 0; spin_unlock_bh(&local->ap->sta_table_lock); resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA; txt = "no room for more AIDs"; } else { local->ap->sta_aid[sta->aid - 1] = sta; spin_unlock_bh(&local->ap->sta_table_lock); txt = "OK, new AID"; } } fail: pos = (u16 *) body; if (send_deauth) { *pos = __constant_cpu_to_le16( WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH); pos++; } else { /* FIX: CF-Pollable and CF-PollReq should be set to match the * values in beacons/probe responses */ /* FIX: how about privacy and WEP? */ /* capability */ *pos = __constant_cpu_to_le16(WLAN_CAPABILITY_ESS); pos++; /* status_code */ *pos = __cpu_to_le16(resp); pos++; *pos = __cpu_to_le16((sta && sta->aid > 0 ? sta->aid : 0) | BIT(14) | BIT(15)); /* AID */ pos++; /* Supported rates (Information element) */ p = (char *) pos; *p++ = WLAN_EID_SUPP_RATES; lpos = p; *p++ = 0; /* len */ if (local->tx_rate_control & WLAN_RATE_1M) { *p++ = local->basic_rates & WLAN_RATE_1M ? 0x82 : 0x02; (*lpos)++; } if (local->tx_rate_control & WLAN_RATE_2M) { *p++ = local->basic_rates & WLAN_RATE_2M ? 0x84 : 0x04; (*lpos)++; } if (local->tx_rate_control & WLAN_RATE_5M5) { *p++ = local->basic_rates & WLAN_RATE_5M5 ? 0x8b : 0x0b; (*lpos)++; } if (local->tx_rate_control & WLAN_RATE_11M) { *p++ = local->basic_rates & WLAN_RATE_11M ? 0x96 : 0x16; (*lpos)++; } pos = (u16 *) p; } prism2_send_mgmt(dev, IEEE80211_FTYPE_MGMT | (send_deauth ? IEEE80211_STYPE_DEAUTH : (reassoc ? IEEE80211_STYPE_REASSOC_RESP : IEEE80211_STYPE_ASSOC_RESP)), body, (u8 *) pos - (u8 *) body, hdr->addr2, send_deauth ? 0 : local->ap->tx_callback_assoc); if (sta) { if (resp == WLAN_STATUS_SUCCESS) { sta->last_rx = jiffies; /* STA will be marked associated from TX callback, if * AssocResp is ACKed */ } atomic_dec(&sta->users); }#if 0 PDEBUG(DEBUG_AP, "%s: " MACSTR " %sassoc (len=%d prev_ap=" MACSTR ") => %d(%d) (%s)\n", dev->name, MAC2STR(hdr->addr2), reassoc ? "re" : "", len, MAC2STR(prev_ap), resp, send_deauth, txt);#endif}/* Called only as a scheduled task for pending AP frames. */static void handle_deauth(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; char *body = (char *) (skb->data + IEEE80211_MGMT_HDR_LEN); int len; u16 reason_code, *pos; struct sta_info *sta = NULL; len = skb->len - IEEE80211_MGMT_HDR_LEN; if (len < 2) { printk("handle_deauth - too short payload (len=%d)\n", len); return; } pos = (u16 *) body; reason_code = __le16_to_cpu(*pos); PDEBUG(DEBUG_AP, "%s: deauthentication: " MACSTR " len=%d, " "reason_code=%d\n", dev->name, MAC2STR(hdr->addr2), len, reason_code); spin_lock_bh(&local->ap->sta_table_lock); sta = ap_get_sta(local->ap, hdr->addr2); if (sta != NULL) { if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap) hostap_event_expired_sta(local->dev, sta); sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC); } spin_unlock_bh(&local->ap->sta_table_lock); if (sta == NULL) { printk("%s: deauthentication from " MACSTR ", " "reason_code=%d, but STA not authenticated\n", dev->name, MAC2STR(hdr->addr2), reason_code); }}/* Called only as a scheduled task for pending AP frames. */static void handle_disassoc(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; char *body = skb->data + IEEE80211_MGMT_HDR_LEN; int len; u16 reason_code, *pos; struct sta_info *sta = NULL; len = skb->len - IEEE80211_MGMT_HDR_LEN; if (len < 2) { printk("handle_disassoc - too short payload (len=%d)\n", len); return; } pos = (u16 *) body; reason_code = __le16_to_cpu(*pos); PDEBUG(DEBUG_AP, "%s: disassociation: " MACSTR " len=%d, " "reason_code=%d\n", dev->name, MAC2STR(hdr->addr2), len, reason_code); spin_lock_bh(&local->ap->sta_table_lock); sta = ap_get_sta(local->ap, hdr->addr2); if (sta != NULL) { if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap) hostap_event_expired_sta(local->dev, sta); sta->flags &= ~WLAN_STA_ASSOC; } spin_unlock_bh(&local->ap->sta_table_lock); if (sta == NULL) { printk("%s: disassociation from " MACSTR ", " "reason_code=%d, but STA not authenticated\n", dev->name, MAC2STR(hdr->addr2), reason_code); }}/* Called only as a scheduled task for pending AP frames. */static void ap_handle_data_nullfunc(local_info_t *local, struct ieee80211_hdr_4addr *hdr){ struct net_device *dev = local->dev; /* some STA f/w's seem to require control::ACK frame for * data::nullfunc, but at least Prism2 station f/w version 0.8.0 does * not send this.. * send control::ACK for the data::nullfunc */ printk(KERN_DEBUG "Sending control::ACK for data::nullfunc\n"); prism2_send_mgmt(dev, IEEE80211_FTYPE_CTL | IEEE80211_STYPE_ACK, NULL, 0, hdr->addr2, 0);}/* Called only as a scheduled task for pending AP frames. */static void ap_handle_dropped_data(local_info_t *local, struct ieee80211_hdr_4addr *hdr){ struct net_device *dev = local->dev; struct sta_info *sta; u16 reason; 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 != NULL && (sta->flags & WLAN_STA_ASSOC)) { PDEBUG(DEBUG_AP, "ap_handle_dropped_data: STA is now okay?\n"); atomic_dec(&sta->users); return; } reason = __constant_cpu_to_le16( WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA); prism2_send_mgmt(dev, IEEE80211_FTYPE_MGMT | ((sta == NULL || !(sta->flags & WLAN_STA_ASSOC)) ? IEEE80211_STYPE_DEAUTH : IEEE80211_STYPE_DISASSOC), (char *) &reason, sizeof(reason), hdr->addr2, 0); if (sta) atomic_dec(&sta->users);}#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT *//* Called only as a scheduled task for pending AP frames. */static void pspoll_send_buffered(local_info_t *local, struct sta_info *sta, struct sk_buff *skb){ struct hostap_skb_tx_data *meta; if (!(sta->flags & WLAN_STA_PS)) { /* Station has moved to non-PS mode, so send all buffered * frames using normal device queue. */ dev_queue_xmit(skb); return; } /* add a flag for hostap_handle_sta_tx() to know that this skb should * be passed through even though STA is using PS */ meta = (struct hostap_skb_tx_data *) skb->cb; meta->flags |= HOSTAP_TX_FLAGS_BUFFERED_FRAME; if (!skb_queue_empty(&sta->tx_buf)) { /* indicate to STA that more frames follow */ meta->flags |= HOSTAP_TX_FLAGS_ADD_MOREDATA; } dev_queue_xmit(skb);}/* Called only as a scheduled task for pending AP frames. */static void handle_pspoll(local_info_t *local, struct ieee80211_hdr_4addr *hdr, struct hostap_80211_rx_status *rx_stats){ struct net_device *dev = local->dev; struct sta_info *sta; u16 aid; struct sk_buff *skb; PDEBUG(DEBUG_PS2, "handle_pspoll: BSSID=" MACSTR ", TA=" MACSTR " PWRMGT=%d\n", MAC2STR(hdr->addr1), MAC2STR(hdr->addr2), !!(le16_to_cpu(hdr->frame_ctl) & IEEE80211_FCTL_PM)); if (memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN)) { PDEBUG(DEBUG_AP, "handle_pspoll - addr1(BSSID)=" MACSTR " not own MAC\n", MAC2STR(hdr->addr1)); return; } aid = __le16_to_cpu(hdr->duration_id); if ((aid & (BIT(15) | BIT(14))) != (BIT(15) | BIT(14))) { PDEBUG(DEBUG_PS, " PSPOLL and AID[15:14] not set\n"); return; } aid &= ~BIT(15) & ~BIT(14); if (aid == 0 || aid > MAX_AID_TABLE_SIZE) { PDEBUG(DEBUG_PS, " invalid aid=%d\n", aid); return; } PDEBUG(DEBUG_PS2, " aid=%d\n", aid); 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 == NULL) { PDEBUG(DEBUG_PS, " STA not found\n"); return; } if (sta->aid != aid) { PDEBUG(DEBUG_PS, " received aid=%i does not match with " "assoc.aid=%d\n", aid, sta->aid); return; } /* FIX: todo: * - add timeout for buffering (clear aid in TIM vector if buffer timed * out (expiry time must be longer than ListenInterval for * the corresponding STA; "8802-11: 11.2.1.9 AP aging function" * - what to do, if buffered, pspolled, and sent frame is not ACKed by * sta; store buffer for later use and leave TIM aid bit set? use * TX event to check whether frame was ACKed? */ while ((skb = skb_dequeue(&sta->tx_buf)) != NULL) { /* send buffered frame .. */ PDEBUG(DEBUG_PS2, "Sending buffered frame to STA after PS POLL" " (buffer_count=%d)\n", skb_queue_len(&sta->tx_buf)); pspoll_send_buffered(local, sta, skb); if (sta->flags & WLAN_STA_PS) { /* send only one buffered packet per PS Poll */ /* FIX: should ignore further PS Polls until the * buffered packet that was just sent is acknowledged * (Tx or TxExc event) */ break; } } if (skb_queue_empty(&sta->tx_buf)) { /* try to clear aid from TIM */ if (!(sta->flags & WLAN_STA_TIM)) PDEBUG(DEBUG_PS2, "Re-unsetting TIM for aid %d\n", aid); hostap_set_tim(local, aid, 0);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -