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

📄 hostap_ap.c

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