⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 hostap_ap.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 5 页
字号:
		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 + -