📄 hostap_ap.c
字号:
#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */static void ap_control_kickall(struct ap_data *ap){ struct list_head *ptr, *n; struct sta_info *sta; spin_lock_bh(&ap->sta_table_lock); for (ptr = ap->sta_list.next, n = ptr->next; ptr != &ap->sta_list; ptr = n, n = ptr->next) { sta = list_entry(ptr, struct sta_info, list); ap_sta_hash_del(ap, sta); list_del(&sta->list); if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap && sta->local) hostap_event_expired_sta(sta->local->dev, sta); ap_free_sta(ap, sta); } spin_unlock_bh(&ap->sta_table_lock);}#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT#define PROC_LIMIT (PAGE_SIZE - 80)static int prism2_ap_proc_read(char *page, char **start, off_t off, int count, int *eof, void *data){ char *p = page; struct ap_data *ap = (struct ap_data *) data; struct list_head *ptr; int i; if (off > PROC_LIMIT) { *eof = 1; return 0; } p += sprintf(p, "# BSSID CHAN SIGNAL NOISE RATE SSID FLAGS\n"); spin_lock_bh(&ap->sta_table_lock); for (ptr = ap->sta_list.next; ptr != &ap->sta_list; ptr = ptr->next) { struct sta_info *sta = (struct sta_info *) ptr; if (!sta->ap) continue; p += sprintf(p, MACSTR " %d %d %d %d '", MAC2STR(sta->addr), sta->u.ap.channel, sta->last_rx_signal, sta->last_rx_silence, sta->last_rx_rate); 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, "'"); if (sta->capability & WLAN_CAPABILITY_ESS) p += sprintf(p, " [ESS]"); if (sta->capability & WLAN_CAPABILITY_IBSS) p += sprintf(p, " [IBSS]"); if (sta->capability & WLAN_CAPABILITY_PRIVACY) p += sprintf(p, " [WEP]"); p += sprintf(p, "\n"); if ((p - page) > PROC_LIMIT) { printk(KERN_DEBUG "hostap: ap proc did not fit\n"); break; } } spin_unlock_bh(&ap->sta_table_lock); if ((p - page) <= off) { *eof = 1; return 0; } *start = page + off; return (p - page - off);}#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */void hostap_check_sta_fw_version(struct ap_data *ap, int sta_fw_ver){ if (!ap) return; if (sta_fw_ver == PRISM2_FW_VER(0,8,0)) { PDEBUG(DEBUG_AP, "Using data::nullfunc ACK workaround - " "firmware upgrade recommended\n"); ap->nullfunc_ack = 1; } else ap->nullfunc_ack = 0; if (sta_fw_ver == PRISM2_FW_VER(1,4,2)) { printk(KERN_WARNING "%s: Warning: secondary station firmware " "version 1.4.2 does not seem to work in Host AP mode\n", ap->local->dev->name); }}/* Called only as a tasklet (software IRQ) */static void hostap_ap_tx_cb(struct sk_buff *skb, int ok, void *data){ struct ap_data *ap = data; u16 fc; struct ieee80211_hdr_4addr *hdr; if (!ap->local->hostapd || !ap->local->apdev) { dev_kfree_skb(skb); return; } hdr = (struct ieee80211_hdr_4addr *) skb->data; fc = le16_to_cpu(hdr->frame_ctl); /* Pass the TX callback frame to the hostapd; use 802.11 header version * 1 to indicate failure (no ACK) and 2 success (frame ACKed) */ fc &= ~IEEE80211_FCTL_VERS; fc |= ok ? BIT(1) : BIT(0); hdr->frame_ctl = cpu_to_le16(fc); skb->dev = ap->local->apdev; skb_pull(skb, hostap_80211_get_hdrlen(fc)); skb->pkt_type = PACKET_OTHERHOST; skb->protocol = __constant_htons(ETH_P_802_2); memset(skb->cb, 0, sizeof(skb->cb)); netif_rx(skb);}#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT/* Called only as a tasklet (software IRQ) */static void hostap_ap_tx_cb_auth(struct sk_buff *skb, int ok, void *data){ struct ap_data *ap = data; struct net_device *dev = ap->local->dev; struct ieee80211_hdr_4addr *hdr; u16 fc, *pos, auth_alg, auth_transaction, status; struct sta_info *sta = NULL; char *txt = NULL; if (ap->local->hostapd) { dev_kfree_skb(skb); return; } hdr = (struct ieee80211_hdr_4addr *) skb->data; fc = le16_to_cpu(hdr->frame_ctl); if (WLAN_FC_GET_TYPE(fc) != IEEE80211_FTYPE_MGMT || WLAN_FC_GET_STYPE(fc) != IEEE80211_STYPE_AUTH || skb->len < IEEE80211_MGMT_HDR_LEN + 6) { printk(KERN_DEBUG "%s: hostap_ap_tx_cb_auth received invalid " "frame\n", dev->name); dev_kfree_skb(skb); return; } pos = (u16 *) (skb->data + IEEE80211_MGMT_HDR_LEN); auth_alg = le16_to_cpu(*pos++); auth_transaction = le16_to_cpu(*pos++); status = le16_to_cpu(*pos++); if (!ok) { txt = "frame was not ACKed"; goto done; } spin_lock(&ap->sta_table_lock); sta = ap_get_sta(ap, hdr->addr1); if (sta) atomic_inc(&sta->users); spin_unlock(&ap->sta_table_lock); if (!sta) { txt = "STA not found"; goto done; } if (status == WLAN_STATUS_SUCCESS && ((auth_alg == WLAN_AUTH_OPEN && auth_transaction == 2) || (auth_alg == WLAN_AUTH_SHARED_KEY && auth_transaction == 4))) { txt = "STA authenticated"; sta->flags |= WLAN_STA_AUTH; sta->last_auth = jiffies; } else if (status != WLAN_STATUS_SUCCESS) txt = "authentication failed"; done: if (sta) atomic_dec(&sta->users); if (txt) { PDEBUG(DEBUG_AP, "%s: " MACSTR " auth_cb - alg=%d trans#=%d " "status=%d - %s\n", dev->name, MAC2STR(hdr->addr1), auth_alg, auth_transaction, status, txt); } dev_kfree_skb(skb);}/* Called only as a tasklet (software IRQ) */static void hostap_ap_tx_cb_assoc(struct sk_buff *skb, int ok, void *data){ struct ap_data *ap = data; struct net_device *dev = ap->local->dev; struct ieee80211_hdr_4addr *hdr; u16 fc, *pos, status; struct sta_info *sta = NULL; char *txt = NULL; if (ap->local->hostapd) { dev_kfree_skb(skb); return; } hdr = (struct ieee80211_hdr_4addr *) skb->data; fc = le16_to_cpu(hdr->frame_ctl); if (WLAN_FC_GET_TYPE(fc) != IEEE80211_FTYPE_MGMT || (WLAN_FC_GET_STYPE(fc) != IEEE80211_STYPE_ASSOC_RESP && WLAN_FC_GET_STYPE(fc) != IEEE80211_STYPE_REASSOC_RESP) || skb->len < IEEE80211_MGMT_HDR_LEN + 4) { printk(KERN_DEBUG "%s: hostap_ap_tx_cb_assoc received invalid " "frame\n", dev->name); dev_kfree_skb(skb); return; } if (!ok) { txt = "frame was not ACKed"; goto done; } spin_lock(&ap->sta_table_lock); sta = ap_get_sta(ap, hdr->addr1); if (sta) atomic_inc(&sta->users); spin_unlock(&ap->sta_table_lock); if (!sta) { txt = "STA not found"; goto done; } pos = (u16 *) (skb->data + IEEE80211_MGMT_HDR_LEN); pos++; status = le16_to_cpu(*pos++); if (status == WLAN_STATUS_SUCCESS) { if (!(sta->flags & WLAN_STA_ASSOC)) hostap_event_new_sta(dev, sta); txt = "STA associated"; sta->flags |= WLAN_STA_ASSOC; sta->last_assoc = jiffies; } else txt = "association failed"; done: if (sta) atomic_dec(&sta->users); if (txt) { PDEBUG(DEBUG_AP, "%s: " MACSTR " assoc_cb - %s\n", dev->name, MAC2STR(hdr->addr1), txt); } dev_kfree_skb(skb);}/* Called only as a tasklet (software IRQ); TX callback for poll frames used * in verifying whether the STA is still present. */static void hostap_ap_tx_cb_poll(struct sk_buff *skb, int ok, void *data){ struct ap_data *ap = data; struct ieee80211_hdr_4addr *hdr; struct sta_info *sta; if (skb->len < 24) goto fail; hdr = (struct ieee80211_hdr_4addr *) skb->data; if (ok) { spin_lock(&ap->sta_table_lock); sta = ap_get_sta(ap, hdr->addr1); if (sta) sta->flags &= ~WLAN_STA_PENDING_POLL; spin_unlock(&ap->sta_table_lock); } else { PDEBUG(DEBUG_AP, "%s: STA " MACSTR " did not ACK activity " "poll frame\n", ap->local->dev->name, MAC2STR(hdr->addr1)); } fail: dev_kfree_skb(skb);}#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */void hostap_init_data(local_info_t *local){ struct ap_data *ap = local->ap; if (ap == NULL) { printk(KERN_WARNING "hostap_init_data: ap == NULL\n"); return; } memset(ap, 0, sizeof(struct ap_data)); ap->local = local; ap->ap_policy = GET_INT_PARM(other_ap_policy, local->card_idx); ap->bridge_packets = GET_INT_PARM(ap_bridge_packets, local->card_idx); ap->max_inactivity = GET_INT_PARM(ap_max_inactivity, local->card_idx) * HZ; ap->autom_ap_wds = GET_INT_PARM(autom_ap_wds, local->card_idx); spin_lock_init(&ap->sta_table_lock); INIT_LIST_HEAD(&ap->sta_list); /* Initialize task queue structure for AP management */ INIT_WORK(&local->ap->add_sta_proc_queue, handle_add_proc_queue, ap); ap->tx_callback_idx = hostap_tx_callback_register(local, hostap_ap_tx_cb, ap); if (ap->tx_callback_idx == 0) printk(KERN_WARNING "%s: failed to register TX callback for " "AP\n", local->dev->name);#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT INIT_WORK(&local->ap->wds_oper_queue, handle_wds_oper_queue, local); ap->tx_callback_auth = hostap_tx_callback_register(local, hostap_ap_tx_cb_auth, ap); ap->tx_callback_assoc = hostap_tx_callback_register(local, hostap_ap_tx_cb_assoc, ap); ap->tx_callback_poll = hostap_tx_callback_register(local, hostap_ap_tx_cb_poll, ap); if (ap->tx_callback_auth == 0 || ap->tx_callback_assoc == 0 || ap->tx_callback_poll == 0) printk(KERN_WARNING "%s: failed to register TX callback for " "AP\n", local->dev->name); spin_lock_init(&ap->mac_restrictions.lock); INIT_LIST_HEAD(&ap->mac_restrictions.mac_list);#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ ap->initialized = 1;}void hostap_init_ap_proc(local_info_t *local){ struct ap_data *ap = local->ap; ap->proc = local->proc; if (ap->proc == NULL) return;#ifndef PRISM2_NO_PROCFS_DEBUG create_proc_read_entry("ap_debug", 0, ap->proc, ap_debug_proc_read, ap);#endif /* PRISM2_NO_PROCFS_DEBUG */#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT create_proc_read_entry("ap_control", 0, ap->proc, ap_control_proc_read, ap); create_proc_read_entry("ap", 0, ap->proc, prism2_ap_proc_read, ap);#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */}void hostap_free_data(struct ap_data *ap){ struct list_head *n, *ptr; if (ap == NULL || !ap->initialized) { printk(KERN_DEBUG "hostap_free_data: ap has not yet been " "initialized - skip resource freeing\n"); return; }#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT if (ap->crypt) ap->crypt->deinit(ap->crypt_priv); ap->crypt = ap->crypt_priv = NULL;#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ list_for_each_safe(ptr, n, &ap->sta_list) { struct sta_info *sta = list_entry(ptr, struct sta_info, list); ap_sta_hash_del(ap, sta); list_del(&sta->list); if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap && sta->local) hostap_event_expired_sta(sta->local->dev, sta); ap_free_sta(ap, sta); }#ifndef PRISM2_NO_PROCFS_DEBUG if (ap->proc != NULL) { remove_proc_entry("ap_debug", ap->proc); }#endif /* PRISM2_NO_PROCFS_DEBUG */#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT if (ap->proc != NULL) { remove_proc_entry("ap", ap->proc); remove_proc_entry("ap_control", ap->proc); } ap_control_flush_macs(&ap->mac_restrictions);#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ ap->initialized = 0;}/* caller should have mutex for AP STA list handling */static struct sta_info* ap_get_sta(struct ap_data *ap, u8 *sta){ struct sta_info *s; s = ap->sta_hash[STA_HASH(sta)]; while (s != NULL && memcmp(s->addr, sta, ETH_ALEN) != 0) s = s->hnext; return s;}#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT/* Called from timer handler and from scheduled AP queue handlers */static void prism2_send_mgmt(struct net_device *dev, u16 type_subtype, char *body, int body_len, u8 *addr, u16 tx_cb_idx){ struct hostap_interface *iface; local_info_t *local; struct ieee80211_hdr_4addr *hdr; u16 fc; struct sk_buff *skb; struct hostap_skb_tx_data *meta; int hdrlen; iface = netdev_priv(dev); local = iface->local; dev = local->dev; /* always use master radio device */ iface = netdev_priv(dev); if (!(dev->flags & IFF_UP)) { PDEBUG(DEBUG_AP, "%s: prism2_send_mgmt - device is not UP - " "cannot send frame\n", dev->name); return; } skb = dev_alloc_skb(sizeof(*hdr) + body_len); if (skb == NULL) { PDEBUG(DEBUG_AP, "%s: prism2_send_mgmt failed to allocate " "skb\n", dev->name); return; } fc = type_subtype; hdrlen = hostap_80211_get_hdrlen(fc); hdr = (struct ieee80211_hdr_4addr *) skb_put(skb, hdrlen); if (body) memcpy(skb_put(skb, body_len), body, body_len); memset(hdr, 0, hdrlen); /* FIX: ctrl::ack sending used special HFA384X_TX_CTRL_802_11 * tx_control instead of using local->tx_control */ memcpy(hdr->addr1, addr, ETH_ALEN); /* DA / RA */ if (WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_DATA) { fc |= IEEE80211_FCTL_FROMDS; memcpy(hdr->addr2, dev->dev_addr, ETH_ALEN); /* BSSID */ memcpy(hdr->addr3, dev->dev_addr, ETH_ALEN); /* SA */ } else if (WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_CTL) { /* control:ACK does not have addr2 or addr3 */ memset(hdr->addr2, 0, ETH_ALEN); memset(hdr->addr3, 0, ETH_ALEN); } else { memcpy(hdr->addr2, dev->dev_addr, ETH_ALEN); /* SA */ memcpy(hdr->addr3, dev->dev_addr, ETH_ALEN); /* BSSID */ }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -