📄 hostap_ap.c
字号:
sta->flags &= ~WLAN_STA_TIM; } atomic_dec(&sta->users);}#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMTstatic void handle_wds_oper_queue(void *data){ local_info_t *local = data; struct wds_oper_data *entry, *prev; spin_lock_bh(&local->lock); entry = local->ap->wds_oper_entries; local->ap->wds_oper_entries = NULL; spin_unlock_bh(&local->lock); while (entry) { PDEBUG(DEBUG_AP, "%s: %s automatic WDS connection " "to AP " MACSTR "\n", local->dev->name, entry->type == WDS_ADD ? "adding" : "removing", MAC2STR(entry->addr)); if (entry->type == WDS_ADD) prism2_wds_add(local, entry->addr, 0); else if (entry->type == WDS_DEL) prism2_wds_del(local, entry->addr, 0, 1); prev = entry; entry = entry->next; kfree(prev); }}/* Called only as a scheduled task for pending AP frames. */static void handle_beacon(local_info_t *local, struct sk_buff *skb, struct hostap_80211_rx_status *rx_stats){ struct ieee80211_hdr_4addr *hdr = (struct ieee80211_hdr_4addr *) skb->data; char *body = skb->data + IEEE80211_MGMT_HDR_LEN; int len, left; u16 *pos, beacon_int, capability; char *ssid = NULL; unsigned char *supp_rates = NULL; int ssid_len = 0, supp_rates_len = 0; struct sta_info *sta = NULL; int new_sta = 0, channel = -1; len = skb->len - IEEE80211_MGMT_HDR_LEN; if (len < 8 + 2 + 2) { printk(KERN_DEBUG "handle_beacon - too short payload " "(len=%d)\n", len); return; } pos = (u16 *) body; left = len; /* Timestamp (8 octets) */ pos += 4; left -= 8; /* Beacon interval (2 octets) */ beacon_int = __le16_to_cpu(*pos); pos++; left -= 2; /* Capability information (2 octets) */ capability = __le16_to_cpu(*pos); pos++; left -= 2; if (local->ap->ap_policy != AP_OTHER_AP_EVEN_IBSS && capability & WLAN_CAPABILITY_IBSS) return; 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) { PDEBUG(DEBUG_AP, "SSID: overflow\n"); return; } if (local->ap->ap_policy == AP_OTHER_AP_SAME_SSID && (ileft != strlen(local->essid) || memcmp(local->essid, u, ileft) != 0)) { /* not our SSID */ return; } ssid = u; ssid_len = ileft; u += ileft; left -= ileft; } if (*u == WLAN_EID_SUPP_RATES) { u++; left--; ileft = *u; u++; left--; if (ileft > left || ileft == 0 || ileft > 8) { PDEBUG(DEBUG_AP, " - SUPP_RATES len error\n"); return; } supp_rates = u; supp_rates_len = ileft; u += ileft; left -= ileft; } if (*u == WLAN_EID_DS_PARAMS) { u++; left--; ileft = *u; u++; left--; if (ileft > left || ileft != 1) { PDEBUG(DEBUG_AP, " - DS_PARAMS len error\n"); return; } channel = *u; u += ileft; left -= ileft; } } spin_lock_bh(&local->ap->sta_table_lock); sta = ap_get_sta(local->ap, hdr->addr2); if (sta != NULL) atomic_inc(&sta->users); spin_unlock_bh(&local->ap->sta_table_lock); if (sta == NULL) { /* add new AP */ new_sta = 1; sta = ap_add_sta(local->ap, hdr->addr2); if (sta == NULL) { printk(KERN_INFO "prism2: kmalloc failed for AP " "data structure\n"); return; } hostap_event_new_sta(local->dev, sta); /* mark APs authentication and associated for pseudo ad-hoc * style communication */ sta->flags = WLAN_STA_AUTH | WLAN_STA_ASSOC; if (local->ap->autom_ap_wds) { hostap_wds_link_oper(local, sta->addr, WDS_ADD); } } sta->ap = 1; if (ssid) { sta->u.ap.ssid_len = ssid_len; memcpy(sta->u.ap.ssid, ssid, ssid_len); sta->u.ap.ssid[ssid_len] = '\0'; } else { sta->u.ap.ssid_len = 0; sta->u.ap.ssid[0] = '\0'; } sta->u.ap.channel = channel; sta->rx_packets++; sta->rx_bytes += len; sta->u.ap.last_beacon = sta->last_rx = jiffies; sta->capability = capability; sta->listen_interval = beacon_int; atomic_dec(&sta->users); if (new_sta) { memset(sta->supported_rates, 0, sizeof(sta->supported_rates)); memcpy(sta->supported_rates, supp_rates, supp_rates_len); prism2_check_tx_rates(sta); }}#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT *//* Called only as a tasklet. */static void handle_ap_item(local_info_t *local, struct sk_buff *skb, struct hostap_80211_rx_status *rx_stats){#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT struct net_device *dev = local->dev;#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ u16 fc, type, stype; struct ieee80211_hdr_4addr *hdr; /* FIX: should give skb->len to handler functions and check that the * buffer is long enough */ hdr = (struct ieee80211_hdr_4addr *) skb->data; fc = le16_to_cpu(hdr->frame_ctl); type = WLAN_FC_GET_TYPE(fc); stype = WLAN_FC_GET_STYPE(fc);#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT if (!local->hostapd && type == IEEE80211_FTYPE_DATA) { PDEBUG(DEBUG_AP, "handle_ap_item - data frame\n"); if (!(fc & IEEE80211_FCTL_TODS) || (fc & IEEE80211_FCTL_FROMDS)) { if (stype == IEEE80211_STYPE_NULLFUNC) { /* no ToDS nullfunc seems to be used to check * AP association; so send reject message to * speed up re-association */ ap_handle_dropped_data(local, hdr); goto done; } PDEBUG(DEBUG_AP, " not ToDS frame (fc=0x%04x)\n", fc); goto done; } if (memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN)) { PDEBUG(DEBUG_AP, "handle_ap_item - addr1(BSSID)=" MACSTR " not own MAC\n", MAC2STR(hdr->addr1)); goto done; } if (local->ap->nullfunc_ack && stype == IEEE80211_STYPE_NULLFUNC) ap_handle_data_nullfunc(local, hdr); else ap_handle_dropped_data(local, hdr); goto done; } if (type == IEEE80211_FTYPE_MGMT && stype == IEEE80211_STYPE_BEACON) { handle_beacon(local, skb, rx_stats); goto done; }#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ if (type == IEEE80211_FTYPE_CTL && stype == IEEE80211_STYPE_PSPOLL) { handle_pspoll(local, hdr, rx_stats); goto done; } if (local->hostapd) { PDEBUG(DEBUG_AP, "Unknown frame in AP queue: type=0x%02x " "subtype=0x%02x\n", type, stype); goto done; }#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT if (type != IEEE80211_FTYPE_MGMT) { PDEBUG(DEBUG_AP, "handle_ap_item - not a management frame?\n"); goto done; } if (memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN)) { PDEBUG(DEBUG_AP, "handle_ap_item - addr1(DA)=" MACSTR " not own MAC\n", MAC2STR(hdr->addr1)); goto done; } if (memcmp(hdr->addr3, dev->dev_addr, ETH_ALEN)) { PDEBUG(DEBUG_AP, "handle_ap_item - addr3(BSSID)=" MACSTR " not own MAC\n", MAC2STR(hdr->addr3)); goto done; } switch (stype) { case IEEE80211_STYPE_ASSOC_REQ: handle_assoc(local, skb, rx_stats, 0); break; case IEEE80211_STYPE_ASSOC_RESP: PDEBUG(DEBUG_AP, "==> ASSOC RESP (ignored)\n"); break; case IEEE80211_STYPE_REASSOC_REQ: handle_assoc(local, skb, rx_stats, 1); break; case IEEE80211_STYPE_REASSOC_RESP: PDEBUG(DEBUG_AP, "==> REASSOC RESP (ignored)\n"); break; case IEEE80211_STYPE_ATIM: PDEBUG(DEBUG_AP, "==> ATIM (ignored)\n"); break; case IEEE80211_STYPE_DISASSOC: handle_disassoc(local, skb, rx_stats); break; case IEEE80211_STYPE_AUTH: handle_authen(local, skb, rx_stats); break; case IEEE80211_STYPE_DEAUTH: handle_deauth(local, skb, rx_stats); break; default: PDEBUG(DEBUG_AP, "Unknown mgmt frame subtype 0x%02x\n", stype >> 4); break; }#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ done: dev_kfree_skb(skb);}/* Called only as a tasklet (software IRQ) */void hostap_rx(struct net_device *dev, struct sk_buff *skb, struct hostap_80211_rx_status *rx_stats){ struct hostap_interface *iface; local_info_t *local; u16 fc; struct ieee80211_hdr_4addr *hdr; iface = netdev_priv(dev); local = iface->local; if (skb->len < 16) goto drop; local->stats.rx_packets++; hdr = (struct ieee80211_hdr_4addr *) skb->data; fc = le16_to_cpu(hdr->frame_ctl); if (local->ap->ap_policy == AP_OTHER_AP_SKIP_ALL && WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_MGMT && WLAN_FC_GET_STYPE(fc) == IEEE80211_STYPE_BEACON) goto drop; skb->protocol = __constant_htons(ETH_P_HOSTAP); handle_ap_item(local, skb, rx_stats); return; drop: dev_kfree_skb(skb);}/* Called only as a tasklet (software IRQ) */static void schedule_packet_send(local_info_t *local, struct sta_info *sta){ struct sk_buff *skb; struct ieee80211_hdr_4addr *hdr; struct hostap_80211_rx_status rx_stats; if (skb_queue_empty(&sta->tx_buf)) return; skb = dev_alloc_skb(16); if (skb == NULL) { printk(KERN_DEBUG "%s: schedule_packet_send: skb alloc " "failed\n", local->dev->name); return; } hdr = (struct ieee80211_hdr_4addr *) skb_put(skb, 16); /* Generate a fake pspoll frame to start packet delivery */ hdr->frame_ctl = __constant_cpu_to_le16( IEEE80211_FTYPE_CTL | IEEE80211_STYPE_PSPOLL); memcpy(hdr->addr1, local->dev->dev_addr, ETH_ALEN); memcpy(hdr->addr2, sta->addr, ETH_ALEN); hdr->duration_id = cpu_to_le16(sta->aid | BIT(15) | BIT(14)); PDEBUG(DEBUG_PS2, "%s: Scheduling buffered packet delivery for " "STA " MACSTR "\n", local->dev->name, MAC2STR(sta->addr)); skb->dev = local->dev; memset(&rx_stats, 0, sizeof(rx_stats)); hostap_rx(local->dev, skb, &rx_stats);}static int prism2_ap_get_sta_qual(local_info_t *local, struct sockaddr addr[], struct iw_quality qual[], int buf_size, int aplist){ struct ap_data *ap = local->ap; struct list_head *ptr; int count = 0; spin_lock_bh(&ap->sta_table_lock); for (ptr = ap->sta_list.next; ptr != NULL && ptr != &ap->sta_list; ptr = ptr->next) { struct sta_info *sta = (struct sta_info *) ptr; if (aplist && !sta->ap) continue; addr[count].sa_family = ARPHRD_ETHER; memcpy(addr[count].sa_data, sta->addr, ETH_ALEN); if (sta->last_rx_silence == 0) qual[count].qual = sta->last_rx_signal < 27 ? 0 : (sta->last_rx_signal - 27) * 92 / 127; else qual[count].qual = sta->last_rx_signal - sta->last_rx_silence - 35; qual[count].level = HFA384X_LEVEL_TO_dBm(sta->last_rx_signal); qual[count].noise = HFA384X_LEVEL_TO_dBm(sta->last_rx_silence); qual[count].updated = sta->last_rx_updated; sta->last_rx_updated = IW_QUAL_DBM; count++; if (count >= buf_size) break; } spin_unlock_bh(&ap->sta_table_lock); return count;}/* Translate our list of Access Points & Stations to a card independant * format that the Wireless Tools will understand - Jean II */static int prism2_ap_translate_scan(struct net_device *dev, char *buffer){ struct hostap_interface *iface; local_info_t *local; struct ap_data *ap; struct list_head *ptr; struct iw_event iwe; char *current_ev = buffer; char *end_buf = buffer + IW_SCAN_MAX_DATA;#if !defined(PRISM2_NO_KERNEL_IEEE80211_MGMT) char buf[64];#endif iface = netdev_priv(dev); local = iface->local; ap = local->ap; spin_lock_bh(&ap->sta_table_lock); for (ptr = ap->sta_list.next; ptr != NULL && ptr != &ap->sta_list; ptr = ptr->next) { struct sta_info *sta = (struct sta_info *) ptr; /* First entry *MUST* be the AP MAC address */ memset(&iwe, 0, sizeof(iwe)); iwe.cmd = SIOCGIWAP; iwe.u.ap_addr.sa_family = ARPHRD_ETHER; memcpy(iwe.u.ap_addr.sa_data, sta->addr, ETH_ALEN); iwe.len = IW_EV_ADDR_LEN; current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_ADDR_LEN); /* Use the mode to indicate if it's a station or * an Access Point */ memset(&iwe, 0, sizeof(iwe)); iwe.cmd = SIOCGIWMODE; if (sta->ap) iwe.u.mode = IW_MODE_MASTER; else iwe.u.mode = IW_MODE_INFRA; iwe.len = IW_EV_UINT_LEN; current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_UINT_LEN); /* Some quality */ memset(&iwe, 0, sizeof(iwe)); iwe.cmd = IWEVQUAL; if (sta->last_rx_silence == 0) iwe.u.qual.qual = sta->last_rx_signal < 27 ? 0 : (sta->last_rx_signal - 27) * 92 / 127; else iwe.u.qual.qual = sta->last_rx_signal - sta->last_rx_silence - 35; iwe.u.qual.level = HFA384X_LEVEL_TO_dBm(sta->last_rx_signal); iwe.u.qual.noise = HFA384X_LEVEL_TO_dBm(sta->last_rx_silence); iwe.u.qual.updated = sta->last_rx_updated; iwe.len = IW_EV_QUAL_LEN;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -