| 
									
										
										
										
											2007-05-05 11:45:53 -07:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * mac80211 configuration hooks for cfg80211 | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2007-12-19 02:03:31 +01:00
										 |  |  |  * Copyright 2006, 2007	Johannes Berg <johannes@sipsolutions.net> | 
					
						
							| 
									
										
										
										
											2007-05-05 11:45:53 -07:00
										 |  |  |  * | 
					
						
							|  |  |  |  * This file is GPLv2 as found in COPYING. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-12-19 02:03:30 +01:00
										 |  |  | #include <linux/ieee80211.h>
 | 
					
						
							| 
									
										
										
										
											2007-05-05 11:45:53 -07:00
										 |  |  | #include <linux/nl80211.h>
 | 
					
						
							|  |  |  | #include <linux/rtnetlink.h>
 | 
					
						
							| 
									
										
										
										
											2007-09-17 11:56:21 -07:00
										 |  |  | #include <net/net_namespace.h>
 | 
					
						
							| 
									
										
										
										
											2007-12-19 02:03:33 +01:00
										 |  |  | #include <linux/rcupdate.h>
 | 
					
						
							| 
									
										
										
										
											2007-05-05 11:45:53 -07:00
										 |  |  | #include <net/cfg80211.h>
 | 
					
						
							|  |  |  | #include "ieee80211_i.h"
 | 
					
						
							| 
									
										
										
										
											2007-09-18 17:29:21 -04:00
										 |  |  | #include "cfg.h"
 | 
					
						
							| 
									
										
										
										
											2008-04-08 15:14:40 -04:00
										 |  |  | #include "rate.h"
 | 
					
						
							| 
									
										
										
										
											2008-02-23 15:17:17 +01:00
										 |  |  | #include "mesh.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-09-09 23:19:48 -07:00
										 |  |  | struct ieee80211_hw *wiphy_to_hw(struct wiphy *wiphy) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct ieee80211_local *local = wiphy_priv(wiphy); | 
					
						
							|  |  |  | 	return &local->hw; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | EXPORT_SYMBOL(wiphy_to_hw); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-09-11 00:01:58 +02:00
										 |  |  | static bool nl80211_type_check(enum nl80211_iftype type) | 
					
						
							| 
									
										
										
										
											2007-09-28 21:52:27 +02:00
										 |  |  | { | 
					
						
							|  |  |  | 	switch (type) { | 
					
						
							|  |  |  | 	case NL80211_IFTYPE_ADHOC: | 
					
						
							|  |  |  | 	case NL80211_IFTYPE_STATION: | 
					
						
							|  |  |  | 	case NL80211_IFTYPE_MONITOR: | 
					
						
							| 
									
										
										
										
											2008-02-23 15:17:17 +01:00
										 |  |  | #ifdef CONFIG_MAC80211_MESH
 | 
					
						
							|  |  |  | 	case NL80211_IFTYPE_MESH_POINT: | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2008-04-14 15:37:03 +02:00
										 |  |  | 	case NL80211_IFTYPE_WDS: | 
					
						
							| 
									
										
										
										
											2008-09-11 00:01:58 +02:00
										 |  |  | 		return true; | 
					
						
							| 
									
										
										
										
											2007-09-28 21:52:27 +02:00
										 |  |  | 	default: | 
					
						
							| 
									
										
										
										
											2008-09-11 00:01:58 +02:00
										 |  |  | 		return false; | 
					
						
							| 
									
										
										
										
											2007-09-28 21:52:27 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-05-05 11:45:53 -07:00
										 |  |  | static int ieee80211_add_iface(struct wiphy *wiphy, char *name, | 
					
						
							| 
									
										
										
										
											2008-02-23 15:17:06 +01:00
										 |  |  | 			       enum nl80211_iftype type, u32 *flags, | 
					
						
							|  |  |  | 			       struct vif_params *params) | 
					
						
							| 
									
										
										
										
											2007-05-05 11:45:53 -07:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct ieee80211_local *local = wiphy_priv(wiphy); | 
					
						
							| 
									
										
										
										
											2008-01-31 19:48:23 +01:00
										 |  |  | 	struct net_device *dev; | 
					
						
							|  |  |  | 	struct ieee80211_sub_if_data *sdata; | 
					
						
							|  |  |  | 	int err; | 
					
						
							| 
									
										
										
										
											2007-05-05 11:45:53 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-09-11 00:01:58 +02:00
										 |  |  | 	if (!nl80211_type_check(type)) | 
					
						
							| 
									
										
										
										
											2007-05-05 11:45:53 -07:00
										 |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-09-11 00:01:58 +02:00
										 |  |  | 	err = ieee80211_if_add(local, name, &dev, type, params); | 
					
						
							|  |  |  | 	if (err || type != NL80211_IFTYPE_MONITOR || !flags) | 
					
						
							| 
									
										
										
										
											2008-01-31 19:48:23 +01:00
										 |  |  | 		return err; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 
					
						
							|  |  |  | 	sdata->u.mntr_flags = *flags; | 
					
						
							|  |  |  | 	return 0; | 
					
						
							| 
									
										
										
										
											2007-05-05 11:45:53 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int ieee80211_del_iface(struct wiphy *wiphy, int ifindex) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct net_device *dev; | 
					
						
							| 
									
										
										
										
											2008-08-03 12:04:37 +12:00
										 |  |  | 	struct ieee80211_sub_if_data *sdata; | 
					
						
							| 
									
										
										
										
											2007-05-05 11:45:53 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-09-28 21:52:27 +02:00
										 |  |  | 	/* we're under RTNL */ | 
					
						
							|  |  |  | 	dev = __dev_get_by_index(&init_net, ifindex); | 
					
						
							| 
									
										
										
										
											2007-05-05 11:45:53 -07:00
										 |  |  | 	if (!dev) | 
					
						
							| 
									
										
										
										
											2008-07-09 14:40:35 +02:00
										 |  |  | 		return -ENODEV; | 
					
						
							| 
									
										
										
										
											2007-05-05 11:45:53 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-08-03 12:04:37 +12:00
										 |  |  | 	sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ieee80211_if_remove(sdata); | 
					
						
							| 
									
										
										
										
											2007-05-05 11:45:53 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-07-09 14:40:35 +02:00
										 |  |  | 	return 0; | 
					
						
							| 
									
										
										
										
											2007-05-05 11:45:53 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-09-28 21:52:27 +02:00
										 |  |  | static int ieee80211_change_iface(struct wiphy *wiphy, int ifindex, | 
					
						
							| 
									
										
										
										
											2008-02-23 15:17:06 +01:00
										 |  |  | 				  enum nl80211_iftype type, u32 *flags, | 
					
						
							|  |  |  | 				  struct vif_params *params) | 
					
						
							| 
									
										
										
										
											2007-09-28 21:52:27 +02:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct net_device *dev; | 
					
						
							|  |  |  | 	struct ieee80211_sub_if_data *sdata; | 
					
						
							| 
									
										
										
										
											2008-07-09 14:40:36 +02:00
										 |  |  | 	int ret; | 
					
						
							| 
									
										
										
										
											2007-09-28 21:52:27 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* we're under RTNL */ | 
					
						
							|  |  |  | 	dev = __dev_get_by_index(&init_net, ifindex); | 
					
						
							|  |  |  | 	if (!dev) | 
					
						
							|  |  |  | 		return -ENODEV; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-09-11 00:01:58 +02:00
										 |  |  | 	if (!nl80211_type_check(type)) | 
					
						
							| 
									
										
										
										
											2007-09-28 21:52:27 +02:00
										 |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-09-11 00:01:58 +02:00
										 |  |  | 	ret = ieee80211_if_change_type(sdata, type); | 
					
						
							| 
									
										
										
										
											2008-07-09 14:40:36 +02:00
										 |  |  | 	if (ret) | 
					
						
							|  |  |  | 		return ret; | 
					
						
							| 
									
										
										
										
											2007-09-28 21:52:27 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-09-16 20:22:21 +02:00
										 |  |  | 	if (netif_running(sdata->dev)) | 
					
						
							|  |  |  | 		return -EBUSY; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-23 15:17:19 +01:00
										 |  |  | 	if (ieee80211_vif_is_mesh(&sdata->vif) && params->mesh_id_len) | 
					
						
							| 
									
										
										
										
											2008-09-11 00:01:49 +02:00
										 |  |  | 		ieee80211_sdata_set_mesh_id(sdata, | 
					
						
							|  |  |  | 					    params->mesh_id_len, | 
					
						
							|  |  |  | 					    params->mesh_id); | 
					
						
							| 
									
										
										
										
											2008-02-23 15:17:17 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-09-11 00:01:58 +02:00
										 |  |  | 	if (sdata->vif.type != NL80211_IFTYPE_MONITOR || !flags) | 
					
						
							| 
									
										
										
										
											2008-01-31 19:48:23 +01:00
										 |  |  | 		return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	sdata->u.mntr_flags = *flags; | 
					
						
							| 
									
										
										
										
											2007-09-28 21:52:27 +02:00
										 |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-12-19 02:03:30 +01:00
										 |  |  | static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, | 
					
						
							|  |  |  | 			     u8 key_idx, u8 *mac_addr, | 
					
						
							|  |  |  | 			     struct key_params *params) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct ieee80211_sub_if_data *sdata; | 
					
						
							|  |  |  | 	struct sta_info *sta = NULL; | 
					
						
							|  |  |  | 	enum ieee80211_key_alg alg; | 
					
						
							| 
									
										
										
										
											2008-02-25 16:27:45 +01:00
										 |  |  | 	struct ieee80211_key *key; | 
					
						
							| 
									
										
										
										
											2008-04-08 17:56:52 +02:00
										 |  |  | 	int err; | 
					
						
							| 
									
										
										
										
											2007-12-19 02:03:30 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	switch (params->cipher) { | 
					
						
							|  |  |  | 	case WLAN_CIPHER_SUITE_WEP40: | 
					
						
							|  |  |  | 	case WLAN_CIPHER_SUITE_WEP104: | 
					
						
							|  |  |  | 		alg = ALG_WEP; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case WLAN_CIPHER_SUITE_TKIP: | 
					
						
							|  |  |  | 		alg = ALG_TKIP; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case WLAN_CIPHER_SUITE_CCMP: | 
					
						
							|  |  |  | 		alg = ALG_CCMP; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-25 16:27:45 +01:00
										 |  |  | 	key = ieee80211_key_alloc(alg, key_idx, params->key_len, params->key); | 
					
						
							|  |  |  | 	if (!key) | 
					
						
							|  |  |  | 		return -ENOMEM; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-04-08 17:56:52 +02:00
										 |  |  | 	rcu_read_lock(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-12-19 02:03:30 +01:00
										 |  |  | 	if (mac_addr) { | 
					
						
							|  |  |  | 		sta = sta_info_get(sdata->local, mac_addr); | 
					
						
							| 
									
										
										
										
											2008-02-25 16:27:45 +01:00
										 |  |  | 		if (!sta) { | 
					
						
							|  |  |  | 			ieee80211_key_free(key); | 
					
						
							| 
									
										
										
										
											2008-04-08 17:56:52 +02:00
										 |  |  | 			err = -ENOENT; | 
					
						
							|  |  |  | 			goto out_unlock; | 
					
						
							| 
									
										
										
										
											2008-02-25 16:27:45 +01:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2007-12-19 02:03:30 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-25 16:27:45 +01:00
										 |  |  | 	ieee80211_key_link(key, sdata, sta); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-04-08 17:56:52 +02:00
										 |  |  | 	err = 0; | 
					
						
							|  |  |  |  out_unlock: | 
					
						
							|  |  |  | 	rcu_read_unlock(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return err; | 
					
						
							| 
									
										
										
										
											2007-12-19 02:03:30 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, | 
					
						
							|  |  |  | 			     u8 key_idx, u8 *mac_addr) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct ieee80211_sub_if_data *sdata; | 
					
						
							|  |  |  | 	struct sta_info *sta; | 
					
						
							|  |  |  | 	int ret; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-04-08 17:56:52 +02:00
										 |  |  | 	rcu_read_lock(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-12-19 02:03:30 +01:00
										 |  |  | 	if (mac_addr) { | 
					
						
							| 
									
										
										
										
											2008-04-08 17:56:52 +02:00
										 |  |  | 		ret = -ENOENT; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-12-19 02:03:30 +01:00
										 |  |  | 		sta = sta_info_get(sdata->local, mac_addr); | 
					
						
							|  |  |  | 		if (!sta) | 
					
						
							| 
									
										
										
										
											2008-04-08 17:56:52 +02:00
										 |  |  | 			goto out_unlock; | 
					
						
							| 
									
										
										
										
											2007-12-19 02:03:30 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-25 16:27:45 +01:00
										 |  |  | 		if (sta->key) { | 
					
						
							| 
									
										
										
										
											2008-02-25 16:27:46 +01:00
										 |  |  | 			ieee80211_key_free(sta->key); | 
					
						
							| 
									
										
										
										
											2008-02-25 16:27:45 +01:00
										 |  |  | 			WARN_ON(sta->key); | 
					
						
							| 
									
										
										
										
											2008-04-08 17:56:52 +02:00
										 |  |  | 			ret = 0; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2007-12-19 02:03:30 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-04-08 17:56:52 +02:00
										 |  |  | 		goto out_unlock; | 
					
						
							| 
									
										
										
										
											2007-12-19 02:03:30 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-04-08 17:56:52 +02:00
										 |  |  | 	if (!sdata->keys[key_idx]) { | 
					
						
							|  |  |  | 		ret = -ENOENT; | 
					
						
							|  |  |  | 		goto out_unlock; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2007-12-19 02:03:30 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-25 16:27:46 +01:00
										 |  |  | 	ieee80211_key_free(sdata->keys[key_idx]); | 
					
						
							| 
									
										
										
										
											2008-02-25 16:27:45 +01:00
										 |  |  | 	WARN_ON(sdata->keys[key_idx]); | 
					
						
							| 
									
										
										
										
											2007-12-19 02:03:30 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-04-08 17:56:52 +02:00
										 |  |  | 	ret = 0; | 
					
						
							|  |  |  |  out_unlock: | 
					
						
							|  |  |  | 	rcu_read_unlock(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return ret; | 
					
						
							| 
									
										
										
										
											2007-12-19 02:03:30 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-12-19 02:03:31 +01:00
										 |  |  | static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev, | 
					
						
							|  |  |  | 			     u8 key_idx, u8 *mac_addr, void *cookie, | 
					
						
							|  |  |  | 			     void (*callback)(void *cookie, | 
					
						
							|  |  |  | 					      struct key_params *params)) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2008-07-29 13:22:52 +02:00
										 |  |  | 	struct ieee80211_sub_if_data *sdata; | 
					
						
							| 
									
										
										
										
											2007-12-19 02:03:31 +01:00
										 |  |  | 	struct sta_info *sta = NULL; | 
					
						
							|  |  |  | 	u8 seq[6] = {0}; | 
					
						
							|  |  |  | 	struct key_params params; | 
					
						
							|  |  |  | 	struct ieee80211_key *key; | 
					
						
							|  |  |  | 	u32 iv32; | 
					
						
							|  |  |  | 	u16 iv16; | 
					
						
							|  |  |  | 	int err = -ENOENT; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-07-29 13:22:52 +02:00
										 |  |  | 	sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-04-08 17:56:52 +02:00
										 |  |  | 	rcu_read_lock(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-12-19 02:03:31 +01:00
										 |  |  | 	if (mac_addr) { | 
					
						
							|  |  |  | 		sta = sta_info_get(sdata->local, mac_addr); | 
					
						
							|  |  |  | 		if (!sta) | 
					
						
							|  |  |  | 			goto out; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		key = sta->key; | 
					
						
							|  |  |  | 	} else | 
					
						
							|  |  |  | 		key = sdata->keys[key_idx]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!key) | 
					
						
							|  |  |  | 		goto out; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	memset(¶ms, 0, sizeof(params)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	switch (key->conf.alg) { | 
					
						
							|  |  |  | 	case ALG_TKIP: | 
					
						
							|  |  |  | 		params.cipher = WLAN_CIPHER_SUITE_TKIP; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-14 16:26:19 -07:00
										 |  |  | 		iv32 = key->u.tkip.tx.iv32; | 
					
						
							|  |  |  | 		iv16 = key->u.tkip.tx.iv16; | 
					
						
							| 
									
										
										
										
											2007-12-19 02:03:31 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE && | 
					
						
							|  |  |  | 		    sdata->local->ops->get_tkip_seq) | 
					
						
							|  |  |  | 			sdata->local->ops->get_tkip_seq( | 
					
						
							|  |  |  | 				local_to_hw(sdata->local), | 
					
						
							|  |  |  | 				key->conf.hw_key_idx, | 
					
						
							|  |  |  | 				&iv32, &iv16); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		seq[0] = iv16 & 0xff; | 
					
						
							|  |  |  | 		seq[1] = (iv16 >> 8) & 0xff; | 
					
						
							|  |  |  | 		seq[2] = iv32 & 0xff; | 
					
						
							|  |  |  | 		seq[3] = (iv32 >> 8) & 0xff; | 
					
						
							|  |  |  | 		seq[4] = (iv32 >> 16) & 0xff; | 
					
						
							|  |  |  | 		seq[5] = (iv32 >> 24) & 0xff; | 
					
						
							|  |  |  | 		params.seq = seq; | 
					
						
							|  |  |  | 		params.seq_len = 6; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case ALG_CCMP: | 
					
						
							|  |  |  | 		params.cipher = WLAN_CIPHER_SUITE_CCMP; | 
					
						
							|  |  |  | 		seq[0] = key->u.ccmp.tx_pn[5]; | 
					
						
							|  |  |  | 		seq[1] = key->u.ccmp.tx_pn[4]; | 
					
						
							|  |  |  | 		seq[2] = key->u.ccmp.tx_pn[3]; | 
					
						
							|  |  |  | 		seq[3] = key->u.ccmp.tx_pn[2]; | 
					
						
							|  |  |  | 		seq[4] = key->u.ccmp.tx_pn[1]; | 
					
						
							|  |  |  | 		seq[5] = key->u.ccmp.tx_pn[0]; | 
					
						
							|  |  |  | 		params.seq = seq; | 
					
						
							|  |  |  | 		params.seq_len = 6; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case ALG_WEP: | 
					
						
							|  |  |  | 		if (key->conf.keylen == 5) | 
					
						
							|  |  |  | 			params.cipher = WLAN_CIPHER_SUITE_WEP40; | 
					
						
							|  |  |  | 		else | 
					
						
							|  |  |  | 			params.cipher = WLAN_CIPHER_SUITE_WEP104; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	params.key = key->conf.key; | 
					
						
							|  |  |  | 	params.key_len = key->conf.keylen; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	callback(cookie, ¶ms); | 
					
						
							|  |  |  | 	err = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  out: | 
					
						
							| 
									
										
										
										
											2008-04-08 17:56:52 +02:00
										 |  |  | 	rcu_read_unlock(); | 
					
						
							| 
									
										
										
										
											2007-12-19 02:03:31 +01:00
										 |  |  | 	return err; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-12-19 02:03:30 +01:00
										 |  |  | static int ieee80211_config_default_key(struct wiphy *wiphy, | 
					
						
							|  |  |  | 					struct net_device *dev, | 
					
						
							|  |  |  | 					u8 key_idx) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct ieee80211_sub_if_data *sdata; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-04-08 17:56:52 +02:00
										 |  |  | 	rcu_read_lock(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-12-19 02:03:30 +01:00
										 |  |  | 	sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 
					
						
							|  |  |  | 	ieee80211_set_default_key(sdata, key_idx); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-04-08 17:56:52 +02:00
										 |  |  | 	rcu_read_unlock(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-12-19 02:03:30 +01:00
										 |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-23 15:17:17 +01:00
										 |  |  | static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2008-02-25 16:27:46 +01:00
										 |  |  | 	struct ieee80211_sub_if_data *sdata = sta->sdata; | 
					
						
							| 
									
										
										
										
											2008-02-23 15:17:17 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	sinfo->filled = STATION_INFO_INACTIVE_TIME | | 
					
						
							|  |  |  | 			STATION_INFO_RX_BYTES | | 
					
						
							|  |  |  | 			STATION_INFO_TX_BYTES; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	sinfo->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx); | 
					
						
							|  |  |  | 	sinfo->rx_bytes = sta->rx_bytes; | 
					
						
							|  |  |  | 	sinfo->tx_bytes = sta->tx_bytes; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-23 15:17:19 +01:00
										 |  |  | 	if (ieee80211_vif_is_mesh(&sdata->vif)) { | 
					
						
							| 
									
										
										
										
											2008-02-23 15:17:17 +01:00
										 |  |  | #ifdef CONFIG_MAC80211_MESH
 | 
					
						
							|  |  |  | 		sinfo->filled |= STATION_INFO_LLID | | 
					
						
							|  |  |  | 				 STATION_INFO_PLID | | 
					
						
							|  |  |  | 				 STATION_INFO_PLINK_STATE; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		sinfo->llid = le16_to_cpu(sta->llid); | 
					
						
							|  |  |  | 		sinfo->plid = le16_to_cpu(sta->plid); | 
					
						
							|  |  |  | 		sinfo->plink_state = sta->plink_state; | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2008-02-23 15:17:19 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2008-02-23 15:17:17 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int ieee80211_dump_station(struct wiphy *wiphy, struct net_device *dev, | 
					
						
							|  |  |  | 				 int idx, u8 *mac, struct station_info *sinfo) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 
					
						
							|  |  |  | 	struct sta_info *sta; | 
					
						
							| 
									
										
										
										
											2008-02-25 16:27:46 +01:00
										 |  |  | 	int ret = -ENOENT; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	rcu_read_lock(); | 
					
						
							| 
									
										
										
										
											2008-02-23 15:17:17 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	sta = sta_info_get_by_idx(local, idx, dev); | 
					
						
							| 
									
										
										
										
											2008-02-25 16:27:46 +01:00
										 |  |  | 	if (sta) { | 
					
						
							|  |  |  | 		ret = 0; | 
					
						
							| 
									
										
										
										
											2008-09-11 00:02:02 +02:00
										 |  |  | 		memcpy(mac, sta->sta.addr, ETH_ALEN); | 
					
						
							| 
									
										
										
										
											2008-02-25 16:27:46 +01:00
										 |  |  | 		sta_set_sinfo(sta, sinfo); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2008-02-23 15:17:17 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-25 16:27:46 +01:00
										 |  |  | 	rcu_read_unlock(); | 
					
						
							| 
									
										
										
										
											2008-02-23 15:17:17 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-25 16:27:46 +01:00
										 |  |  | 	return ret; | 
					
						
							| 
									
										
										
										
											2008-02-23 15:17:17 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-12-19 02:03:37 +01:00
										 |  |  | static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev, | 
					
						
							| 
									
										
										
										
											2008-02-23 15:17:06 +01:00
										 |  |  | 				 u8 *mac, struct station_info *sinfo) | 
					
						
							| 
									
										
										
										
											2007-12-19 02:03:37 +01:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 
					
						
							|  |  |  | 	struct sta_info *sta; | 
					
						
							| 
									
										
										
										
											2008-02-25 16:27:46 +01:00
										 |  |  | 	int ret = -ENOENT; | 
					
						
							| 
									
										
										
										
											2007-12-19 02:03:37 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-25 16:27:46 +01:00
										 |  |  | 	rcu_read_lock(); | 
					
						
							| 
									
										
										
										
											2007-12-19 02:03:37 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* XXX: verify sta->dev == dev */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-25 16:27:46 +01:00
										 |  |  | 	sta = sta_info_get(local, mac); | 
					
						
							|  |  |  | 	if (sta) { | 
					
						
							|  |  |  | 		ret = 0; | 
					
						
							|  |  |  | 		sta_set_sinfo(sta, sinfo); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	rcu_read_unlock(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return ret; | 
					
						
							| 
									
										
										
										
											2007-12-19 02:03:37 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-12-19 02:03:33 +01:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * This handles both adding a beacon and setting new beacon info | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata, | 
					
						
							|  |  |  | 				   struct beacon_parameters *params) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct beacon_data *new, *old; | 
					
						
							|  |  |  | 	int new_head_len, new_tail_len; | 
					
						
							|  |  |  | 	int size; | 
					
						
							|  |  |  | 	int err = -EINVAL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	old = sdata->u.ap.beacon; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* head must not be zero-length */ | 
					
						
							|  |  |  | 	if (params->head && !params->head_len) | 
					
						
							|  |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * This is a kludge. beacon interval should really be part | 
					
						
							|  |  |  | 	 * of the beacon information. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	if (params->interval) { | 
					
						
							|  |  |  | 		sdata->local->hw.conf.beacon_int = params->interval; | 
					
						
							|  |  |  | 		if (ieee80211_hw_config(sdata->local)) | 
					
						
							|  |  |  | 			return -EINVAL; | 
					
						
							|  |  |  | 		/*
 | 
					
						
							|  |  |  | 		 * We updated some parameter so if below bails out | 
					
						
							|  |  |  | 		 * it's not an error. | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		err = 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Need to have a beacon head if we don't have one yet */ | 
					
						
							|  |  |  | 	if (!params->head && !old) | 
					
						
							|  |  |  | 		return err; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* sorry, no way to start beaconing without dtim period */ | 
					
						
							|  |  |  | 	if (!params->dtim_period && !old) | 
					
						
							|  |  |  | 		return err; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* new or old head? */ | 
					
						
							|  |  |  | 	if (params->head) | 
					
						
							|  |  |  | 		new_head_len = params->head_len; | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 		new_head_len = old->head_len; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* new or old tail? */ | 
					
						
							|  |  |  | 	if (params->tail || !old) | 
					
						
							|  |  |  | 		/* params->tail_len will be zero for !params->tail */ | 
					
						
							|  |  |  | 		new_tail_len = params->tail_len; | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 		new_tail_len = old->tail_len; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	size = sizeof(*new) + new_head_len + new_tail_len; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	new = kzalloc(size, GFP_KERNEL); | 
					
						
							|  |  |  | 	if (!new) | 
					
						
							|  |  |  | 		return -ENOMEM; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* start filling the new info now */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* new or old dtim period? */ | 
					
						
							|  |  |  | 	if (params->dtim_period) | 
					
						
							|  |  |  | 		new->dtim_period = params->dtim_period; | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 		new->dtim_period = old->dtim_period; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * pointers go into the block we allocated, | 
					
						
							|  |  |  | 	 * memory is | beacon_data | head | tail | | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	new->head = ((u8 *) new) + sizeof(*new); | 
					
						
							|  |  |  | 	new->tail = new->head + new_head_len; | 
					
						
							|  |  |  | 	new->head_len = new_head_len; | 
					
						
							|  |  |  | 	new->tail_len = new_tail_len; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* copy in head */ | 
					
						
							|  |  |  | 	if (params->head) | 
					
						
							|  |  |  | 		memcpy(new->head, params->head, new_head_len); | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 		memcpy(new->head, old->head, new_head_len); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* copy in optional tail */ | 
					
						
							|  |  |  | 	if (params->tail) | 
					
						
							|  |  |  | 		memcpy(new->tail, params->tail, new_tail_len); | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 		if (old) | 
					
						
							|  |  |  | 			memcpy(new->tail, old->tail, new_tail_len); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	rcu_assign_pointer(sdata->u.ap.beacon, new); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	synchronize_rcu(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	kfree(old); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-07-09 14:40:37 +02:00
										 |  |  | 	return ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON); | 
					
						
							| 
									
										
										
										
											2007-12-19 02:03:33 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int ieee80211_add_beacon(struct wiphy *wiphy, struct net_device *dev, | 
					
						
							|  |  |  | 				struct beacon_parameters *params) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2008-07-29 13:22:52 +02:00
										 |  |  | 	struct ieee80211_sub_if_data *sdata; | 
					
						
							| 
									
										
										
										
											2007-12-19 02:03:33 +01:00
										 |  |  | 	struct beacon_data *old; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-07-29 13:22:52 +02:00
										 |  |  | 	sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-09-11 00:01:58 +02:00
										 |  |  | 	if (sdata->vif.type != NL80211_IFTYPE_AP) | 
					
						
							| 
									
										
										
										
											2007-12-19 02:03:33 +01:00
										 |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	old = sdata->u.ap.beacon; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (old) | 
					
						
							|  |  |  | 		return -EALREADY; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return ieee80211_config_beacon(sdata, params); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int ieee80211_set_beacon(struct wiphy *wiphy, struct net_device *dev, | 
					
						
							|  |  |  | 				struct beacon_parameters *params) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2008-07-29 13:22:52 +02:00
										 |  |  | 	struct ieee80211_sub_if_data *sdata; | 
					
						
							| 
									
										
										
										
											2007-12-19 02:03:33 +01:00
										 |  |  | 	struct beacon_data *old; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-07-29 13:22:52 +02:00
										 |  |  | 	sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-09-11 00:01:58 +02:00
										 |  |  | 	if (sdata->vif.type != NL80211_IFTYPE_AP) | 
					
						
							| 
									
										
										
										
											2007-12-19 02:03:33 +01:00
										 |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	old = sdata->u.ap.beacon; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!old) | 
					
						
							|  |  |  | 		return -ENOENT; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return ieee80211_config_beacon(sdata, params); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int ieee80211_del_beacon(struct wiphy *wiphy, struct net_device *dev) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2008-07-29 13:22:52 +02:00
										 |  |  | 	struct ieee80211_sub_if_data *sdata; | 
					
						
							| 
									
										
										
										
											2007-12-19 02:03:33 +01:00
										 |  |  | 	struct beacon_data *old; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-07-29 13:22:52 +02:00
										 |  |  | 	sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-09-11 00:01:58 +02:00
										 |  |  | 	if (sdata->vif.type != NL80211_IFTYPE_AP) | 
					
						
							| 
									
										
										
										
											2007-12-19 02:03:33 +01:00
										 |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	old = sdata->u.ap.beacon; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!old) | 
					
						
							|  |  |  | 		return -ENOENT; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	rcu_assign_pointer(sdata->u.ap.beacon, NULL); | 
					
						
							|  |  |  | 	synchronize_rcu(); | 
					
						
							|  |  |  | 	kfree(old); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-07-09 14:40:37 +02:00
										 |  |  | 	return ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON); | 
					
						
							| 
									
										
										
										
											2007-12-19 02:03:33 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-12-19 02:03:35 +01:00
										 |  |  | /* Layer 2 Update frame (802.2 Type 1 LLC XID Update response) */ | 
					
						
							|  |  |  | struct iapp_layer2_update { | 
					
						
							|  |  |  | 	u8 da[ETH_ALEN];	/* broadcast */ | 
					
						
							|  |  |  | 	u8 sa[ETH_ALEN];	/* STA addr */ | 
					
						
							|  |  |  | 	__be16 len;		/* 6 */ | 
					
						
							|  |  |  | 	u8 dsap;		/* 0 */ | 
					
						
							|  |  |  | 	u8 ssap;		/* 0 */ | 
					
						
							|  |  |  | 	u8 control; | 
					
						
							|  |  |  | 	u8 xid_info[3]; | 
					
						
							|  |  |  | } __attribute__ ((packed)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void ieee80211_send_layer2_update(struct sta_info *sta) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct iapp_layer2_update *msg; | 
					
						
							|  |  |  | 	struct sk_buff *skb; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Send Level 2 Update Frame to update forwarding tables in layer 2
 | 
					
						
							|  |  |  | 	 * bridge devices */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	skb = dev_alloc_skb(sizeof(*msg)); | 
					
						
							|  |  |  | 	if (!skb) | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	msg = (struct iapp_layer2_update *)skb_put(skb, sizeof(*msg)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* 802.2 Type 1 Logical Link Control (LLC) Exchange Identifier (XID)
 | 
					
						
							|  |  |  | 	 * Update response frame; IEEE Std 802.2-1998, 5.4.1.2.1 */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	memset(msg->da, 0xff, ETH_ALEN); | 
					
						
							| 
									
										
										
										
											2008-09-11 00:02:02 +02:00
										 |  |  | 	memcpy(msg->sa, sta->sta.addr, ETH_ALEN); | 
					
						
							| 
									
										
										
										
											2007-12-19 02:03:35 +01:00
										 |  |  | 	msg->len = htons(6); | 
					
						
							|  |  |  | 	msg->dsap = 0; | 
					
						
							|  |  |  | 	msg->ssap = 0x01;	/* NULL LSAP, CR Bit: Response */ | 
					
						
							|  |  |  | 	msg->control = 0xaf;	/* XID response lsb.1111F101.
 | 
					
						
							|  |  |  | 				 * F=0 (no poll command; unsolicited frame) */ | 
					
						
							|  |  |  | 	msg->xid_info[0] = 0x81;	/* XID format identifier */ | 
					
						
							|  |  |  | 	msg->xid_info[1] = 1;	/* LLC types/classes: Type 1 LLC */ | 
					
						
							|  |  |  | 	msg->xid_info[2] = 0;	/* XID sender's receive window size (RW) */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-25 16:27:46 +01:00
										 |  |  | 	skb->dev = sta->sdata->dev; | 
					
						
							|  |  |  | 	skb->protocol = eth_type_trans(skb, sta->sdata->dev); | 
					
						
							| 
									
										
										
										
											2007-12-19 02:03:35 +01:00
										 |  |  | 	memset(skb->cb, 0, sizeof(skb->cb)); | 
					
						
							|  |  |  | 	netif_rx(skb); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void sta_apply_parameters(struct ieee80211_local *local, | 
					
						
							|  |  |  | 				 struct sta_info *sta, | 
					
						
							|  |  |  | 				 struct station_parameters *params) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	u32 rates; | 
					
						
							|  |  |  | 	int i, j; | 
					
						
							| 
									
										
										
										
											2008-01-24 19:38:38 +01:00
										 |  |  | 	struct ieee80211_supported_band *sband; | 
					
						
							| 
									
										
										
										
											2008-02-25 16:27:46 +01:00
										 |  |  | 	struct ieee80211_sub_if_data *sdata = sta->sdata; | 
					
						
							| 
									
										
										
										
											2007-12-19 02:03:35 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-25 16:27:47 +01:00
										 |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * FIXME: updating the flags is racy when this function is | 
					
						
							|  |  |  | 	 *	  called from ieee80211_change_station(), this will | 
					
						
							|  |  |  | 	 *	  be resolved in a future patch. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-12-19 02:03:35 +01:00
										 |  |  | 	if (params->station_flags & STATION_FLAG_CHANGED) { | 
					
						
							| 
									
										
										
										
											2008-05-03 01:02:02 +02:00
										 |  |  | 		spin_lock_bh(&sta->lock); | 
					
						
							| 
									
										
										
										
											2007-12-19 02:03:35 +01:00
										 |  |  | 		sta->flags &= ~WLAN_STA_AUTHORIZED; | 
					
						
							|  |  |  | 		if (params->station_flags & STATION_FLAG_AUTHORIZED) | 
					
						
							|  |  |  | 			sta->flags |= WLAN_STA_AUTHORIZED; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		sta->flags &= ~WLAN_STA_SHORT_PREAMBLE; | 
					
						
							|  |  |  | 		if (params->station_flags & STATION_FLAG_SHORT_PREAMBLE) | 
					
						
							|  |  |  | 			sta->flags |= WLAN_STA_SHORT_PREAMBLE; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		sta->flags &= ~WLAN_STA_WME; | 
					
						
							|  |  |  | 		if (params->station_flags & STATION_FLAG_WME) | 
					
						
							|  |  |  | 			sta->flags |= WLAN_STA_WME; | 
					
						
							| 
									
										
										
										
											2008-05-03 01:02:02 +02:00
										 |  |  | 		spin_unlock_bh(&sta->lock); | 
					
						
							| 
									
										
										
										
											2007-12-19 02:03:35 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-25 16:27:47 +01:00
										 |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * FIXME: updating the following information is racy when this | 
					
						
							|  |  |  | 	 *	  function is called from ieee80211_change_station(). | 
					
						
							|  |  |  | 	 *	  However, all this information should be static so | 
					
						
							|  |  |  | 	 *	  maybe we should just reject attemps to change it. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-12-19 02:03:35 +01:00
										 |  |  | 	if (params->aid) { | 
					
						
							| 
									
										
										
										
											2008-09-11 00:02:02 +02:00
										 |  |  | 		sta->sta.aid = params->aid; | 
					
						
							|  |  |  | 		if (sta->sta.aid > IEEE80211_MAX_AID) | 
					
						
							|  |  |  | 			sta->sta.aid = 0; /* XXX: should this be an error? */ | 
					
						
							| 
									
										
										
										
											2007-12-19 02:03:35 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (params->listen_interval >= 0) | 
					
						
							|  |  |  | 		sta->listen_interval = params->listen_interval; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (params->supported_rates) { | 
					
						
							|  |  |  | 		rates = 0; | 
					
						
							| 
									
										
										
										
											2008-01-24 19:38:38 +01:00
										 |  |  | 		sband = local->hw.wiphy->bands[local->oper_channel->band]; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-12-19 02:03:35 +01:00
										 |  |  | 		for (i = 0; i < params->supported_rates_len; i++) { | 
					
						
							|  |  |  | 			int rate = (params->supported_rates[i] & 0x7f) * 5; | 
					
						
							| 
									
										
										
										
											2008-01-24 19:38:38 +01:00
										 |  |  | 			for (j = 0; j < sband->n_bitrates; j++) { | 
					
						
							|  |  |  | 				if (sband->bitrates[j].bitrate == rate) | 
					
						
							| 
									
										
										
										
											2007-12-19 02:03:35 +01:00
										 |  |  | 					rates |= BIT(j); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2008-09-11 02:45:11 +02:00
										 |  |  | 		sta->sta.supp_rates[local->oper_channel->band] = rates; | 
					
						
							| 
									
										
										
										
											2007-12-19 02:03:35 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2008-02-23 15:17:17 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-08-25 11:58:58 +03:00
										 |  |  | 	if (params->ht_capa) { | 
					
						
							|  |  |  | 		ieee80211_ht_cap_ie_to_ht_info(params->ht_capa, | 
					
						
							| 
									
										
										
										
											2008-09-11 03:14:11 +02:00
										 |  |  | 					       &sta->sta.ht_info); | 
					
						
							| 
									
										
										
										
											2008-08-25 11:58:58 +03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-23 15:17:19 +01:00
										 |  |  | 	if (ieee80211_vif_is_mesh(&sdata->vif) && params->plink_action) { | 
					
						
							| 
									
										
										
										
											2008-02-23 15:17:17 +01:00
										 |  |  | 		switch (params->plink_action) { | 
					
						
							|  |  |  | 		case PLINK_ACTION_OPEN: | 
					
						
							|  |  |  | 			mesh_plink_open(sta); | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case PLINK_ACTION_BLOCK: | 
					
						
							|  |  |  | 			mesh_plink_block(sta); | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2008-02-23 15:17:19 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2007-12-19 02:03:35 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev, | 
					
						
							|  |  |  | 				 u8 *mac, struct station_parameters *params) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2008-07-29 13:22:52 +02:00
										 |  |  | 	struct ieee80211_local *local = wiphy_priv(wiphy); | 
					
						
							| 
									
										
										
										
											2007-12-19 02:03:35 +01:00
										 |  |  | 	struct sta_info *sta; | 
					
						
							|  |  |  | 	struct ieee80211_sub_if_data *sdata; | 
					
						
							| 
									
										
										
										
											2008-02-25 16:27:47 +01:00
										 |  |  | 	int err; | 
					
						
							| 
									
										
										
										
											2007-12-19 02:03:35 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* Prevent a race with changing the rate control algorithm */ | 
					
						
							|  |  |  | 	if (!netif_running(dev)) | 
					
						
							|  |  |  | 		return -ENETDOWN; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (params->vlan) { | 
					
						
							|  |  |  | 		sdata = IEEE80211_DEV_TO_SUB_IF(params->vlan); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-09-11 00:01:58 +02:00
										 |  |  | 		if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN && | 
					
						
							|  |  |  | 		    sdata->vif.type != NL80211_IFTYPE_AP) | 
					
						
							| 
									
										
										
										
											2007-12-19 02:03:35 +01:00
										 |  |  | 			return -EINVAL; | 
					
						
							|  |  |  | 	} else | 
					
						
							|  |  |  | 		sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-27 09:56:40 +01:00
										 |  |  | 	if (compare_ether_addr(mac, dev->dev_addr) == 0) | 
					
						
							|  |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (is_multicast_ether_addr(mac)) | 
					
						
							|  |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	sta = sta_info_alloc(sdata, mac, GFP_KERNEL); | 
					
						
							| 
									
										
										
										
											2008-02-25 16:27:47 +01:00
										 |  |  | 	if (!sta) | 
					
						
							|  |  |  | 		return -ENOMEM; | 
					
						
							| 
									
										
										
										
											2007-12-19 02:03:35 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	sta->flags = WLAN_STA_AUTH | WLAN_STA_ASSOC; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	sta_apply_parameters(local, sta, params); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-09-18 18:14:18 +02:00
										 |  |  | 	rate_control_rate_init(sta); | 
					
						
							| 
									
										
										
										
											2007-12-19 02:03:35 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-25 16:27:47 +01:00
										 |  |  | 	rcu_read_lock(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	err = sta_info_insert(sta); | 
					
						
							|  |  |  | 	if (err) { | 
					
						
							| 
									
										
										
										
											2008-04-01 15:21:00 +02:00
										 |  |  | 		/* STA has been freed */ | 
					
						
							| 
									
										
										
										
											2008-02-25 16:27:47 +01:00
										 |  |  | 		rcu_read_unlock(); | 
					
						
							|  |  |  | 		return err; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-09-11 00:01:58 +02:00
										 |  |  | 	if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN || | 
					
						
							|  |  |  | 	    sdata->vif.type == NL80211_IFTYPE_AP) | 
					
						
							| 
									
										
										
										
											2008-02-25 16:27:47 +01:00
										 |  |  | 		ieee80211_send_layer2_update(sta); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	rcu_read_unlock(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-12-19 02:03:35 +01:00
										 |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev, | 
					
						
							|  |  |  | 				 u8 *mac) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2008-07-29 13:22:52 +02:00
										 |  |  | 	struct ieee80211_local *local = wiphy_priv(wiphy); | 
					
						
							|  |  |  | 	struct ieee80211_sub_if_data *sdata; | 
					
						
							| 
									
										
										
										
											2007-12-19 02:03:35 +01:00
										 |  |  | 	struct sta_info *sta; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-07-29 13:22:52 +02:00
										 |  |  | 	sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-12-19 02:03:35 +01:00
										 |  |  | 	if (mac) { | 
					
						
							| 
									
										
										
										
											2008-04-10 15:36:09 +02:00
										 |  |  | 		rcu_read_lock(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-12-19 02:03:35 +01:00
										 |  |  | 		/* XXX: get sta belonging to dev */ | 
					
						
							|  |  |  | 		sta = sta_info_get(local, mac); | 
					
						
							| 
									
										
										
										
											2008-04-10 15:36:09 +02:00
										 |  |  | 		if (!sta) { | 
					
						
							|  |  |  | 			rcu_read_unlock(); | 
					
						
							| 
									
										
										
										
											2007-12-19 02:03:35 +01:00
										 |  |  | 			return -ENOENT; | 
					
						
							| 
									
										
										
										
											2008-04-10 15:36:09 +02:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2007-12-19 02:03:35 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-25 16:27:46 +01:00
										 |  |  | 		sta_info_unlink(&sta); | 
					
						
							| 
									
										
										
										
											2008-04-10 15:36:09 +02:00
										 |  |  | 		rcu_read_unlock(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-03-31 19:23:02 +02:00
										 |  |  | 		sta_info_destroy(sta); | 
					
						
							| 
									
										
										
										
											2007-12-19 02:03:35 +01:00
										 |  |  | 	} else | 
					
						
							| 
									
										
										
										
											2008-02-25 16:27:46 +01:00
										 |  |  | 		sta_info_flush(local, sdata); | 
					
						
							| 
									
										
										
										
											2007-12-19 02:03:35 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int ieee80211_change_station(struct wiphy *wiphy, | 
					
						
							|  |  |  | 				    struct net_device *dev, | 
					
						
							|  |  |  | 				    u8 *mac, | 
					
						
							|  |  |  | 				    struct station_parameters *params) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2008-07-29 13:22:52 +02:00
										 |  |  | 	struct ieee80211_local *local = wiphy_priv(wiphy); | 
					
						
							| 
									
										
										
										
											2007-12-19 02:03:35 +01:00
										 |  |  | 	struct sta_info *sta; | 
					
						
							|  |  |  | 	struct ieee80211_sub_if_data *vlansdata; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-04-10 15:36:09 +02:00
										 |  |  | 	rcu_read_lock(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-12-19 02:03:35 +01:00
										 |  |  | 	/* XXX: get sta belonging to dev */ | 
					
						
							|  |  |  | 	sta = sta_info_get(local, mac); | 
					
						
							| 
									
										
										
										
											2008-04-10 15:36:09 +02:00
										 |  |  | 	if (!sta) { | 
					
						
							|  |  |  | 		rcu_read_unlock(); | 
					
						
							| 
									
										
										
										
											2007-12-19 02:03:35 +01:00
										 |  |  | 		return -ENOENT; | 
					
						
							| 
									
										
										
										
											2008-04-10 15:36:09 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2007-12-19 02:03:35 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-25 16:27:46 +01:00
										 |  |  | 	if (params->vlan && params->vlan != sta->sdata->dev) { | 
					
						
							| 
									
										
										
										
											2007-12-19 02:03:35 +01:00
										 |  |  | 		vlansdata = IEEE80211_DEV_TO_SUB_IF(params->vlan); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-09-11 00:01:58 +02:00
										 |  |  | 		if (vlansdata->vif.type != NL80211_IFTYPE_AP_VLAN && | 
					
						
							|  |  |  | 		    vlansdata->vif.type != NL80211_IFTYPE_AP) { | 
					
						
							| 
									
										
										
										
											2008-04-10 15:36:09 +02:00
										 |  |  | 			rcu_read_unlock(); | 
					
						
							| 
									
										
										
										
											2007-12-19 02:03:35 +01:00
										 |  |  | 			return -EINVAL; | 
					
						
							| 
									
										
										
										
											2008-04-10 15:36:09 +02:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2007-12-19 02:03:35 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-07-29 13:22:52 +02:00
										 |  |  | 		sta->sdata = vlansdata; | 
					
						
							| 
									
										
										
										
											2007-12-19 02:03:35 +01:00
										 |  |  | 		ieee80211_send_layer2_update(sta); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	sta_apply_parameters(local, sta, params); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-04-10 15:36:09 +02:00
										 |  |  | 	rcu_read_unlock(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-12-19 02:03:35 +01:00
										 |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-23 15:17:17 +01:00
										 |  |  | #ifdef CONFIG_MAC80211_MESH
 | 
					
						
							|  |  |  | static int ieee80211_add_mpath(struct wiphy *wiphy, struct net_device *dev, | 
					
						
							|  |  |  | 				 u8 *dst, u8 *next_hop) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2008-07-29 13:22:52 +02:00
										 |  |  | 	struct ieee80211_local *local = wiphy_priv(wiphy); | 
					
						
							|  |  |  | 	struct ieee80211_sub_if_data *sdata; | 
					
						
							| 
									
										
										
										
											2008-02-23 15:17:17 +01:00
										 |  |  | 	struct mesh_path *mpath; | 
					
						
							|  |  |  | 	struct sta_info *sta; | 
					
						
							|  |  |  | 	int err; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!netif_running(dev)) | 
					
						
							|  |  |  | 		return -ENETDOWN; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-07-29 13:22:52 +02:00
										 |  |  | 	sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-09-11 00:01:58 +02:00
										 |  |  | 	if (sdata->vif.type != NL80211_IFTYPE_MESH_POINT) | 
					
						
							| 
									
										
										
										
											2008-02-23 15:17:17 +01:00
										 |  |  | 		return -ENOTSUPP; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-25 16:27:46 +01:00
										 |  |  | 	rcu_read_lock(); | 
					
						
							| 
									
										
										
										
											2008-02-23 15:17:17 +01:00
										 |  |  | 	sta = sta_info_get(local, next_hop); | 
					
						
							| 
									
										
										
										
											2008-02-25 16:27:46 +01:00
										 |  |  | 	if (!sta) { | 
					
						
							|  |  |  | 		rcu_read_unlock(); | 
					
						
							| 
									
										
										
										
											2008-02-23 15:17:17 +01:00
										 |  |  | 		return -ENOENT; | 
					
						
							| 
									
										
										
										
											2008-02-25 16:27:46 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2008-02-23 15:17:17 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-08-03 12:04:37 +12:00
										 |  |  | 	err = mesh_path_add(dst, sdata); | 
					
						
							| 
									
										
										
										
											2008-02-25 16:27:46 +01:00
										 |  |  | 	if (err) { | 
					
						
							|  |  |  | 		rcu_read_unlock(); | 
					
						
							| 
									
										
										
										
											2008-02-23 15:17:17 +01:00
										 |  |  | 		return err; | 
					
						
							| 
									
										
										
										
											2008-02-25 16:27:46 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2008-02-23 15:17:17 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-08-03 12:04:37 +12:00
										 |  |  | 	mpath = mesh_path_lookup(dst, sdata); | 
					
						
							| 
									
										
										
										
											2008-02-23 15:17:17 +01:00
										 |  |  | 	if (!mpath) { | 
					
						
							|  |  |  | 		rcu_read_unlock(); | 
					
						
							|  |  |  | 		return -ENXIO; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	mesh_path_fix_nexthop(mpath, sta); | 
					
						
							| 
									
										
										
										
											2008-02-25 16:27:46 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-23 15:17:17 +01:00
										 |  |  | 	rcu_read_unlock(); | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int ieee80211_del_mpath(struct wiphy *wiphy, struct net_device *dev, | 
					
						
							|  |  |  | 				 u8 *dst) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2008-08-03 12:04:37 +12:00
										 |  |  | 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-23 15:17:17 +01:00
										 |  |  | 	if (dst) | 
					
						
							| 
									
										
										
										
											2008-08-03 12:04:37 +12:00
										 |  |  | 		return mesh_path_del(dst, sdata); | 
					
						
							| 
									
										
										
										
											2008-02-23 15:17:17 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-08-03 12:04:37 +12:00
										 |  |  | 	mesh_path_flush(sdata); | 
					
						
							| 
									
										
										
										
											2008-02-23 15:17:17 +01:00
										 |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int ieee80211_change_mpath(struct wiphy *wiphy, | 
					
						
							|  |  |  | 				    struct net_device *dev, | 
					
						
							|  |  |  | 				    u8 *dst, u8 *next_hop) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2008-07-29 13:22:52 +02:00
										 |  |  | 	struct ieee80211_local *local = wiphy_priv(wiphy); | 
					
						
							|  |  |  | 	struct ieee80211_sub_if_data *sdata; | 
					
						
							| 
									
										
										
										
											2008-02-23 15:17:17 +01:00
										 |  |  | 	struct mesh_path *mpath; | 
					
						
							|  |  |  | 	struct sta_info *sta; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!netif_running(dev)) | 
					
						
							|  |  |  | 		return -ENETDOWN; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-07-29 13:22:52 +02:00
										 |  |  | 	sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-09-11 00:01:58 +02:00
										 |  |  | 	if (sdata->vif.type != NL80211_IFTYPE_MESH_POINT) | 
					
						
							| 
									
										
										
										
											2008-02-23 15:17:17 +01:00
										 |  |  | 		return -ENOTSUPP; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-25 16:27:46 +01:00
										 |  |  | 	rcu_read_lock(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-23 15:17:17 +01:00
										 |  |  | 	sta = sta_info_get(local, next_hop); | 
					
						
							| 
									
										
										
										
											2008-02-25 16:27:46 +01:00
										 |  |  | 	if (!sta) { | 
					
						
							|  |  |  | 		rcu_read_unlock(); | 
					
						
							| 
									
										
										
										
											2008-02-23 15:17:17 +01:00
										 |  |  | 		return -ENOENT; | 
					
						
							| 
									
										
										
										
											2008-02-25 16:27:46 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2008-02-23 15:17:17 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-08-03 12:04:37 +12:00
										 |  |  | 	mpath = mesh_path_lookup(dst, sdata); | 
					
						
							| 
									
										
										
										
											2008-02-23 15:17:17 +01:00
										 |  |  | 	if (!mpath) { | 
					
						
							|  |  |  | 		rcu_read_unlock(); | 
					
						
							|  |  |  | 		return -ENOENT; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	mesh_path_fix_nexthop(mpath, sta); | 
					
						
							| 
									
										
										
										
											2008-02-25 16:27:46 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-23 15:17:17 +01:00
										 |  |  | 	rcu_read_unlock(); | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void mpath_set_pinfo(struct mesh_path *mpath, u8 *next_hop, | 
					
						
							|  |  |  | 			    struct mpath_info *pinfo) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (mpath->next_hop) | 
					
						
							| 
									
										
										
										
											2008-09-11 00:02:02 +02:00
										 |  |  | 		memcpy(next_hop, mpath->next_hop->sta.addr, ETH_ALEN); | 
					
						
							| 
									
										
										
										
											2008-02-23 15:17:17 +01:00
										 |  |  | 	else | 
					
						
							|  |  |  | 		memset(next_hop, 0, ETH_ALEN); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	pinfo->filled = MPATH_INFO_FRAME_QLEN | | 
					
						
							|  |  |  | 			MPATH_INFO_DSN | | 
					
						
							|  |  |  | 			MPATH_INFO_METRIC | | 
					
						
							|  |  |  | 			MPATH_INFO_EXPTIME | | 
					
						
							|  |  |  | 			MPATH_INFO_DISCOVERY_TIMEOUT | | 
					
						
							|  |  |  | 			MPATH_INFO_DISCOVERY_RETRIES | | 
					
						
							|  |  |  | 			MPATH_INFO_FLAGS; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	pinfo->frame_qlen = mpath->frame_queue.qlen; | 
					
						
							|  |  |  | 	pinfo->dsn = mpath->dsn; | 
					
						
							|  |  |  | 	pinfo->metric = mpath->metric; | 
					
						
							|  |  |  | 	if (time_before(jiffies, mpath->exp_time)) | 
					
						
							|  |  |  | 		pinfo->exptime = jiffies_to_msecs(mpath->exp_time - jiffies); | 
					
						
							|  |  |  | 	pinfo->discovery_timeout = | 
					
						
							|  |  |  | 			jiffies_to_msecs(mpath->discovery_timeout); | 
					
						
							|  |  |  | 	pinfo->discovery_retries = mpath->discovery_retries; | 
					
						
							|  |  |  | 	pinfo->flags = 0; | 
					
						
							|  |  |  | 	if (mpath->flags & MESH_PATH_ACTIVE) | 
					
						
							|  |  |  | 		pinfo->flags |= NL80211_MPATH_FLAG_ACTIVE; | 
					
						
							|  |  |  | 	if (mpath->flags & MESH_PATH_RESOLVING) | 
					
						
							|  |  |  | 		pinfo->flags |= NL80211_MPATH_FLAG_RESOLVING; | 
					
						
							|  |  |  | 	if (mpath->flags & MESH_PATH_DSN_VALID) | 
					
						
							|  |  |  | 		pinfo->flags |= NL80211_MPATH_FLAG_DSN_VALID; | 
					
						
							|  |  |  | 	if (mpath->flags & MESH_PATH_FIXED) | 
					
						
							|  |  |  | 		pinfo->flags |= NL80211_MPATH_FLAG_FIXED; | 
					
						
							|  |  |  | 	if (mpath->flags & MESH_PATH_RESOLVING) | 
					
						
							|  |  |  | 		pinfo->flags |= NL80211_MPATH_FLAG_RESOLVING; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	pinfo->flags = mpath->flags; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int ieee80211_get_mpath(struct wiphy *wiphy, struct net_device *dev, | 
					
						
							|  |  |  | 			       u8 *dst, u8 *next_hop, struct mpath_info *pinfo) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2008-07-29 13:22:52 +02:00
										 |  |  | 	struct ieee80211_sub_if_data *sdata; | 
					
						
							| 
									
										
										
										
											2008-02-23 15:17:17 +01:00
										 |  |  | 	struct mesh_path *mpath; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-07-29 13:22:52 +02:00
										 |  |  | 	sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-09-11 00:01:58 +02:00
										 |  |  | 	if (sdata->vif.type != NL80211_IFTYPE_MESH_POINT) | 
					
						
							| 
									
										
										
										
											2008-02-23 15:17:17 +01:00
										 |  |  | 		return -ENOTSUPP; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	rcu_read_lock(); | 
					
						
							| 
									
										
										
										
											2008-08-03 12:04:37 +12:00
										 |  |  | 	mpath = mesh_path_lookup(dst, sdata); | 
					
						
							| 
									
										
										
										
											2008-02-23 15:17:17 +01:00
										 |  |  | 	if (!mpath) { | 
					
						
							|  |  |  | 		rcu_read_unlock(); | 
					
						
							|  |  |  | 		return -ENOENT; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	memcpy(dst, mpath->dst, ETH_ALEN); | 
					
						
							|  |  |  | 	mpath_set_pinfo(mpath, next_hop, pinfo); | 
					
						
							|  |  |  | 	rcu_read_unlock(); | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int ieee80211_dump_mpath(struct wiphy *wiphy, struct net_device *dev, | 
					
						
							|  |  |  | 				 int idx, u8 *dst, u8 *next_hop, | 
					
						
							|  |  |  | 				 struct mpath_info *pinfo) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2008-07-29 13:22:52 +02:00
										 |  |  | 	struct ieee80211_sub_if_data *sdata; | 
					
						
							| 
									
										
										
										
											2008-02-23 15:17:17 +01:00
										 |  |  | 	struct mesh_path *mpath; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-07-29 13:22:52 +02:00
										 |  |  | 	sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-09-11 00:01:58 +02:00
										 |  |  | 	if (sdata->vif.type != NL80211_IFTYPE_MESH_POINT) | 
					
						
							| 
									
										
										
										
											2008-02-23 15:17:17 +01:00
										 |  |  | 		return -ENOTSUPP; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	rcu_read_lock(); | 
					
						
							| 
									
										
										
										
											2008-08-03 12:04:37 +12:00
										 |  |  | 	mpath = mesh_path_lookup_by_idx(idx, sdata); | 
					
						
							| 
									
										
										
										
											2008-02-23 15:17:17 +01:00
										 |  |  | 	if (!mpath) { | 
					
						
							|  |  |  | 		rcu_read_unlock(); | 
					
						
							|  |  |  | 		return -ENOENT; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	memcpy(dst, mpath->dst, ETH_ALEN); | 
					
						
							|  |  |  | 	mpath_set_pinfo(mpath, next_hop, pinfo); | 
					
						
							|  |  |  | 	rcu_read_unlock(); | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-08-07 20:07:01 +03:00
										 |  |  | static int ieee80211_change_bss(struct wiphy *wiphy, | 
					
						
							|  |  |  | 				struct net_device *dev, | 
					
						
							|  |  |  | 				struct bss_parameters *params) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct ieee80211_sub_if_data *sdata; | 
					
						
							|  |  |  | 	u32 changed = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-09-11 00:01:58 +02:00
										 |  |  | 	if (sdata->vif.type != NL80211_IFTYPE_AP) | 
					
						
							| 
									
										
										
										
											2008-08-07 20:07:01 +03:00
										 |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (params->use_cts_prot >= 0) { | 
					
						
							|  |  |  | 		sdata->bss_conf.use_cts_prot = params->use_cts_prot; | 
					
						
							|  |  |  | 		changed |= BSS_CHANGED_ERP_CTS_PROT; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (params->use_short_preamble >= 0) { | 
					
						
							|  |  |  | 		sdata->bss_conf.use_short_preamble = | 
					
						
							|  |  |  | 			params->use_short_preamble; | 
					
						
							|  |  |  | 		changed |= BSS_CHANGED_ERP_PREAMBLE; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (params->use_short_slot_time >= 0) { | 
					
						
							|  |  |  | 		sdata->bss_conf.use_short_slot = | 
					
						
							|  |  |  | 			params->use_short_slot_time; | 
					
						
							|  |  |  | 		changed |= BSS_CHANGED_ERP_SLOT; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ieee80211_bss_info_change_notify(sdata, changed); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-05-05 11:45:53 -07:00
										 |  |  | struct cfg80211_ops mac80211_config_ops = { | 
					
						
							|  |  |  | 	.add_virtual_intf = ieee80211_add_iface, | 
					
						
							|  |  |  | 	.del_virtual_intf = ieee80211_del_iface, | 
					
						
							| 
									
										
										
										
											2007-09-28 21:52:27 +02:00
										 |  |  | 	.change_virtual_intf = ieee80211_change_iface, | 
					
						
							| 
									
										
										
										
											2007-12-19 02:03:30 +01:00
										 |  |  | 	.add_key = ieee80211_add_key, | 
					
						
							|  |  |  | 	.del_key = ieee80211_del_key, | 
					
						
							| 
									
										
										
										
											2007-12-19 02:03:31 +01:00
										 |  |  | 	.get_key = ieee80211_get_key, | 
					
						
							| 
									
										
										
										
											2007-12-19 02:03:30 +01:00
										 |  |  | 	.set_default_key = ieee80211_config_default_key, | 
					
						
							| 
									
										
										
										
											2007-12-19 02:03:33 +01:00
										 |  |  | 	.add_beacon = ieee80211_add_beacon, | 
					
						
							|  |  |  | 	.set_beacon = ieee80211_set_beacon, | 
					
						
							|  |  |  | 	.del_beacon = ieee80211_del_beacon, | 
					
						
							| 
									
										
										
										
											2007-12-19 02:03:35 +01:00
										 |  |  | 	.add_station = ieee80211_add_station, | 
					
						
							|  |  |  | 	.del_station = ieee80211_del_station, | 
					
						
							|  |  |  | 	.change_station = ieee80211_change_station, | 
					
						
							| 
									
										
										
										
											2007-12-19 02:03:37 +01:00
										 |  |  | 	.get_station = ieee80211_get_station, | 
					
						
							| 
									
										
										
										
											2008-02-23 15:17:17 +01:00
										 |  |  | 	.dump_station = ieee80211_dump_station, | 
					
						
							|  |  |  | #ifdef CONFIG_MAC80211_MESH
 | 
					
						
							|  |  |  | 	.add_mpath = ieee80211_add_mpath, | 
					
						
							|  |  |  | 	.del_mpath = ieee80211_del_mpath, | 
					
						
							|  |  |  | 	.change_mpath = ieee80211_change_mpath, | 
					
						
							|  |  |  | 	.get_mpath = ieee80211_get_mpath, | 
					
						
							|  |  |  | 	.dump_mpath = ieee80211_dump_mpath, | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2008-08-07 20:07:01 +03:00
										 |  |  | 	.change_bss = ieee80211_change_bss, | 
					
						
							| 
									
										
										
										
											2007-05-05 11:45:53 -07:00
										 |  |  | }; |