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

📄 hostap_ap.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * Intersil Prism2 driver with Host AP (software access point) support * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen * <jkmaline@cc.hut.fi> * Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.fi> * * This file is to be included into hostap.c when S/W AP functionality is * compiled. * * AP:  FIX: * - if unicast Class 2 (assoc,reassoc,disassoc) frame received from *   unauthenticated STA, send deauth. frame (8802.11: 5.5) * - if unicast Class 3 (data with to/from DS,deauth,pspoll) frame received *   from authenticated, but unassoc STA, send disassoc frame (8802.11: 5.5) * - if unicast Class 3 received from unauthenticated STA, send deauth. frame *   (8802.11: 5.5) */static int other_ap_policy[MAX_PARM_DEVICES] = { AP_OTHER_AP_SKIP_ALL,						 DEF_INTS };module_param_array(other_ap_policy, int, NULL, 0444);MODULE_PARM_DESC(other_ap_policy, "Other AP beacon monitoring policy (0-3)");static int ap_max_inactivity[MAX_PARM_DEVICES] = { AP_MAX_INACTIVITY_SEC,						   DEF_INTS };module_param_array(ap_max_inactivity, int, NULL, 0444);MODULE_PARM_DESC(ap_max_inactivity, "AP timeout (in seconds) for station "		 "inactivity");static int ap_bridge_packets[MAX_PARM_DEVICES] = { 1, DEF_INTS };module_param_array(ap_bridge_packets, int, NULL, 0444);MODULE_PARM_DESC(ap_bridge_packets, "Bridge packets directly between "		 "stations");static int autom_ap_wds[MAX_PARM_DEVICES] = { 0, DEF_INTS };module_param_array(autom_ap_wds, int, NULL, 0444);MODULE_PARM_DESC(autom_ap_wds, "Add WDS connections to other APs "		 "automatically");static struct sta_info* ap_get_sta(struct ap_data *ap, u8 *sta);static void hostap_event_expired_sta(struct net_device *dev,				     struct sta_info *sta);static void handle_add_proc_queue(void *data);#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMTstatic void handle_wds_oper_queue(void *data);static void prism2_send_mgmt(struct net_device *dev,			     u16 type_subtype, char *body,			     int body_len, u8 *addr, u16 tx_cb_idx);#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */#ifndef PRISM2_NO_PROCFS_DEBUGstatic int ap_debug_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;	if (off != 0) {		*eof = 1;		return 0;	}	p += sprintf(p, "BridgedUnicastFrames=%u\n", ap->bridged_unicast);	p += sprintf(p, "BridgedMulticastFrames=%u\n", ap->bridged_multicast);	p += sprintf(p, "max_inactivity=%u\n", ap->max_inactivity / HZ);	p += sprintf(p, "bridge_packets=%u\n", ap->bridge_packets);	p += sprintf(p, "nullfunc_ack=%u\n", ap->nullfunc_ack);	p += sprintf(p, "autom_ap_wds=%u\n", ap->autom_ap_wds);	p += sprintf(p, "auth_algs=%u\n", ap->local->auth_algs);	p += sprintf(p, "tx_drop_nonassoc=%u\n", ap->tx_drop_nonassoc);	return (p - page);}#endif /* PRISM2_NO_PROCFS_DEBUG */static void ap_sta_hash_add(struct ap_data *ap, struct sta_info *sta){	sta->hnext = ap->sta_hash[STA_HASH(sta->addr)];	ap->sta_hash[STA_HASH(sta->addr)] = sta;}static void ap_sta_hash_del(struct ap_data *ap, struct sta_info *sta){	struct sta_info *s;	s = ap->sta_hash[STA_HASH(sta->addr)];	if (s == NULL) return;	if (memcmp(s->addr, sta->addr, ETH_ALEN) == 0) {		ap->sta_hash[STA_HASH(sta->addr)] = s->hnext;		return;	}	while (s->hnext != NULL && memcmp(s->hnext->addr, sta->addr, ETH_ALEN)	       != 0)		s = s->hnext;	if (s->hnext != NULL)		s->hnext = s->hnext->hnext;	else		printk("AP: could not remove STA " MACSTR " from hash table\n",		       MAC2STR(sta->addr));}static void ap_free_sta(struct ap_data *ap, struct sta_info *sta){	if (sta->ap && sta->local)		hostap_event_expired_sta(sta->local->dev, sta);	if (ap->proc != NULL) {		char name[20];		sprintf(name, MACSTR, MAC2STR(sta->addr));		remove_proc_entry(name, ap->proc);	}	if (sta->crypt) {		sta->crypt->ops->deinit(sta->crypt->priv);		kfree(sta->crypt);		sta->crypt = NULL;	}	skb_queue_purge(&sta->tx_buf);	ap->num_sta--;#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT	if (sta->aid > 0)		ap->sta_aid[sta->aid - 1] = NULL;	if (!sta->ap && sta->u.sta.challenge)		kfree(sta->u.sta.challenge);	del_timer(&sta->timer);#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */	kfree(sta);}static void hostap_set_tim(local_info_t *local, int aid, int set){	if (local->func->set_tim)		local->func->set_tim(local->dev, aid, set);}static void hostap_event_new_sta(struct net_device *dev, struct sta_info *sta){	union iwreq_data wrqu;	memset(&wrqu, 0, sizeof(wrqu));	memcpy(wrqu.addr.sa_data, sta->addr, ETH_ALEN);	wrqu.addr.sa_family = ARPHRD_ETHER;	wireless_send_event(dev, IWEVREGISTERED, &wrqu, NULL);}static void hostap_event_expired_sta(struct net_device *dev,				     struct sta_info *sta){	union iwreq_data wrqu;	memset(&wrqu, 0, sizeof(wrqu));	memcpy(wrqu.addr.sa_data, sta->addr, ETH_ALEN);	wrqu.addr.sa_family = ARPHRD_ETHER;	wireless_send_event(dev, IWEVEXPIRED, &wrqu, NULL);}#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMTstatic void ap_handle_timer(unsigned long data){	struct sta_info *sta = (struct sta_info *) data;	local_info_t *local;	struct ap_data *ap;	unsigned long next_time = 0;	int was_assoc;	if (sta == NULL || sta->local == NULL || sta->local->ap == NULL) {		PDEBUG(DEBUG_AP, "ap_handle_timer() called with NULL data\n");		return;	}	local = sta->local;	ap = local->ap;	was_assoc = sta->flags & WLAN_STA_ASSOC;	if (atomic_read(&sta->users) != 0)		next_time = jiffies + HZ;	else if ((sta->flags & WLAN_STA_PERM) && !(sta->flags & WLAN_STA_AUTH))		next_time = jiffies + ap->max_inactivity;	if (time_before(jiffies, sta->last_rx + ap->max_inactivity)) {		/* station activity detected; reset timeout state */		sta->timeout_next = STA_NULLFUNC;		next_time = sta->last_rx + ap->max_inactivity;	} else if (sta->timeout_next == STA_DISASSOC &&		   !(sta->flags & WLAN_STA_PENDING_POLL)) {		/* STA ACKed data nullfunc frame poll */		sta->timeout_next = STA_NULLFUNC;		next_time = jiffies + ap->max_inactivity;	}	if (next_time) {		sta->timer.expires = next_time;		add_timer(&sta->timer);		return;	}	if (sta->ap)		sta->timeout_next = STA_DEAUTH;	if (sta->timeout_next == STA_DEAUTH && !(sta->flags & WLAN_STA_PERM)) {		spin_lock(&ap->sta_table_lock);		ap_sta_hash_del(ap, sta);		list_del(&sta->list);		spin_unlock(&ap->sta_table_lock);		sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);	} else if (sta->timeout_next == STA_DISASSOC)		sta->flags &= ~WLAN_STA_ASSOC;	if (was_assoc && !(sta->flags & WLAN_STA_ASSOC) && !sta->ap)		hostap_event_expired_sta(local->dev, sta);	if (sta->timeout_next == STA_DEAUTH && sta->aid > 0 &&	    !skb_queue_empty(&sta->tx_buf)) {		hostap_set_tim(local, sta->aid, 0);		sta->flags &= ~WLAN_STA_TIM;	}	if (sta->ap) {		if (ap->autom_ap_wds) {			PDEBUG(DEBUG_AP, "%s: removing automatic WDS "			       "connection to AP " MACSTR "\n",			       local->dev->name, MAC2STR(sta->addr));			hostap_wds_link_oper(local, sta->addr, WDS_DEL);		}	} else if (sta->timeout_next == STA_NULLFUNC) {		/* send data frame to poll STA and check whether this frame		 * is ACKed */		/* FIX: IEEE80211_STYPE_NULLFUNC would be more appropriate, but		 * it is apparently not retried so TX Exc events are not		 * received for it */		sta->flags |= WLAN_STA_PENDING_POLL;		prism2_send_mgmt(local->dev, IEEE80211_FTYPE_DATA |				 IEEE80211_STYPE_DATA, NULL, 0,				 sta->addr, ap->tx_callback_poll);	} else {		int deauth = sta->timeout_next == STA_DEAUTH;		u16 resp;		PDEBUG(DEBUG_AP, "%s: sending %s info to STA " MACSTR		       "(last=%lu, jiffies=%lu)\n",		       local->dev->name,		       deauth ? "deauthentication" : "disassociation",		       MAC2STR(sta->addr), sta->last_rx, jiffies);		resp = cpu_to_le16(deauth ? WLAN_REASON_PREV_AUTH_NOT_VALID :				   WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY);		prism2_send_mgmt(local->dev, IEEE80211_FTYPE_MGMT |				 (deauth ? IEEE80211_STYPE_DEAUTH :				  IEEE80211_STYPE_DISASSOC),				 (char *) &resp, 2, sta->addr, 0);	}	if (sta->timeout_next == STA_DEAUTH) {		if (sta->flags & WLAN_STA_PERM) {			PDEBUG(DEBUG_AP, "%s: STA " MACSTR " would have been "			       "removed, but it has 'perm' flag\n",			       local->dev->name, MAC2STR(sta->addr));		} else			ap_free_sta(ap, sta);		return;	}	if (sta->timeout_next == STA_NULLFUNC) {		sta->timeout_next = STA_DISASSOC;		sta->timer.expires = jiffies + AP_DISASSOC_DELAY;	} else {		sta->timeout_next = STA_DEAUTH;		sta->timer.expires = jiffies + AP_DEAUTH_DELAY;	}	add_timer(&sta->timer);}void hostap_deauth_all_stas(struct net_device *dev, struct ap_data *ap,			    int resend){	u8 addr[ETH_ALEN];	u16 resp;	int i;	PDEBUG(DEBUG_AP, "%s: Deauthenticate all stations\n", dev->name);	memset(addr, 0xff, ETH_ALEN);	resp = __constant_cpu_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);	/* deauth message sent; try to resend it few times; the message is	 * broadcast, so it may be delayed until next DTIM; there is not much	 * else we can do at this point since the driver is going to be shut	 * down */	for (i = 0; i < 5; i++) {		prism2_send_mgmt(dev, IEEE80211_FTYPE_MGMT |				 IEEE80211_STYPE_DEAUTH,				 (char *) &resp, 2, addr, 0);		if (!resend || ap->num_sta <= 0)			return;		mdelay(50);	}}static int ap_control_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;	char *policy_txt;	struct list_head *ptr;	struct mac_entry *entry;	if (off != 0) {		*eof = 1;		return 0;	}	switch (ap->mac_restrictions.policy) {	case MAC_POLICY_OPEN:		policy_txt = "open";		break;	case MAC_POLICY_ALLOW:		policy_txt = "allow";		break;	case MAC_POLICY_DENY:		policy_txt = "deny";		break;	default:		policy_txt = "unknown";		break;	};	p += sprintf(p, "MAC policy: %s\n", policy_txt);	p += sprintf(p, "MAC entries: %u\n", ap->mac_restrictions.entries);	p += sprintf(p, "MAC list:\n");	spin_lock_bh(&ap->mac_restrictions.lock);	for (ptr = ap->mac_restrictions.mac_list.next;	     ptr != &ap->mac_restrictions.mac_list; ptr = ptr->next) {		if (p - page > PAGE_SIZE - 80) {			p += sprintf(p, "All entries did not fit one page.\n");			break;		}		entry = list_entry(ptr, struct mac_entry, list);		p += sprintf(p, MACSTR "\n", MAC2STR(entry->addr));	}	spin_unlock_bh(&ap->mac_restrictions.lock);	return (p - page);}static int ap_control_add_mac(struct mac_restrictions *mac_restrictions,			      u8 *mac){	struct mac_entry *entry;	entry = kmalloc(sizeof(struct mac_entry), GFP_KERNEL);	if (entry == NULL)		return -1;	memcpy(entry->addr, mac, ETH_ALEN);	spin_lock_bh(&mac_restrictions->lock);	list_add_tail(&entry->list, &mac_restrictions->mac_list);	mac_restrictions->entries++;	spin_unlock_bh(&mac_restrictions->lock);	return 0;}static int ap_control_del_mac(struct mac_restrictions *mac_restrictions,			      u8 *mac){	struct list_head *ptr;	struct mac_entry *entry;	spin_lock_bh(&mac_restrictions->lock);	for (ptr = mac_restrictions->mac_list.next;	     ptr != &mac_restrictions->mac_list; ptr = ptr->next) {		entry = list_entry(ptr, struct mac_entry, list);		if (memcmp(entry->addr, mac, ETH_ALEN) == 0) {			list_del(ptr);			kfree(entry);			mac_restrictions->entries--;			spin_unlock_bh(&mac_restrictions->lock);			return 0;		}	}	spin_unlock_bh(&mac_restrictions->lock);	return -1;}static int ap_control_mac_deny(struct mac_restrictions *mac_restrictions,			       u8 *mac){	struct list_head *ptr;	struct mac_entry *entry;	int found = 0;	if (mac_restrictions->policy == MAC_POLICY_OPEN)		return 0;	spin_lock_bh(&mac_restrictions->lock);	for (ptr = mac_restrictions->mac_list.next;	     ptr != &mac_restrictions->mac_list; ptr = ptr->next) {		entry = list_entry(ptr, struct mac_entry, list);		if (memcmp(entry->addr, mac, ETH_ALEN) == 0) {			found = 1;			break;		}	}	spin_unlock_bh(&mac_restrictions->lock);	if (mac_restrictions->policy == MAC_POLICY_ALLOW)		return !found;	else		return found;}static void ap_control_flush_macs(struct mac_restrictions *mac_restrictions){	struct list_head *ptr, *n;	struct mac_entry *entry;	if (mac_restrictions->entries == 0)		return;	spin_lock_bh(&mac_restrictions->lock);	for (ptr = mac_restrictions->mac_list.next, n = ptr->next;	     ptr != &mac_restrictions->mac_list;	     ptr = n, n = ptr->next) {		entry = list_entry(ptr, struct mac_entry, list);		list_del(ptr);		kfree(entry);	}	mac_restrictions->entries = 0;	spin_unlock_bh(&mac_restrictions->lock);}static int ap_control_kick_mac(struct ap_data *ap, struct net_device *dev,			       u8 *mac){	struct sta_info *sta;	u16 resp;	spin_lock_bh(&ap->sta_table_lock);	sta = ap_get_sta(ap, mac);	if (sta) {		ap_sta_hash_del(ap, sta);		list_del(&sta->list);	}	spin_unlock_bh(&ap->sta_table_lock);	if (!sta)		return -EINVAL;	resp = cpu_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);	prism2_send_mgmt(dev, IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_DEAUTH,			 (char *) &resp, 2, sta->addr, 0);	if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap)		hostap_event_expired_sta(dev, sta);	ap_free_sta(ap, sta);	return 0;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -