Commit d1b46b0f authored by Zhu Yi's avatar Zhu Yi Committed by John W. Linville

[PATCH] ieee80211: Add 802.11h information element parsing

Added default handlers for various 802.11h DFS and TPC information
elements.  Moved all information elements into single location (called
from two places).  Added debug message with information on unparsed IEs
if debug_level set.  Added code to reset network IBSS DFS information
when appropriate.  Added code to invoke driver callback for 802.11h
ACTION STYPE.  Changed a few printk's to IEEE80211_DEBUG_MGMT.
Signed-off-by: default avatarJames Ketrenos <jketreno@linux.intel.com>
Signed-off-by: default avatarZhu Yi <yi.zhu@intel.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 15f38598
...@@ -937,6 +937,45 @@ static int ieee80211_parse_qos_info_param_IE(struct ieee80211_info_element ...@@ -937,6 +937,45 @@ static int ieee80211_parse_qos_info_param_IE(struct ieee80211_info_element
return rc; return rc;
} }
#ifdef CONFIG_IEEE80211_DEBUG
#define MFIE_STRING(x) case MFIE_TYPE_ ##x: return #x
static const char *get_info_element_string(u16 id)
{
switch (id) {
MFIE_STRING(SSID);
MFIE_STRING(RATES);
MFIE_STRING(FH_SET);
MFIE_STRING(DS_SET);
MFIE_STRING(CF_SET);
MFIE_STRING(TIM);
MFIE_STRING(IBSS_SET);
MFIE_STRING(COUNTRY);
MFIE_STRING(HOP_PARAMS);
MFIE_STRING(HOP_TABLE);
MFIE_STRING(REQUEST);
MFIE_STRING(CHALLENGE);
MFIE_STRING(POWER_CONSTRAINT);
MFIE_STRING(POWER_CAPABILITY);
MFIE_STRING(TPC_REQUEST);
MFIE_STRING(TPC_REPORT);
MFIE_STRING(SUPP_CHANNELS);
MFIE_STRING(CSA);
MFIE_STRING(MEASURE_REQUEST);
MFIE_STRING(MEASURE_REPORT);
MFIE_STRING(QUIET);
MFIE_STRING(IBSS_DFS);
MFIE_STRING(ERP_INFO);
MFIE_STRING(RSN);
MFIE_STRING(RATES_EX);
MFIE_STRING(GENERIC);
MFIE_STRING(QOS_PARAMETER);
default:
return "UNKNOWN";
}
}
#endif
static int ieee80211_parse_info_param(struct ieee80211_info_element static int ieee80211_parse_info_param(struct ieee80211_info_element
*info_element, u16 length, *info_element, u16 length,
struct ieee80211_network *network) struct ieee80211_network *network)
...@@ -1100,10 +1139,49 @@ static int ieee80211_parse_info_param(struct ieee80211_info_element ...@@ -1100,10 +1139,49 @@ static int ieee80211_parse_info_param(struct ieee80211_info_element
printk(KERN_ERR printk(KERN_ERR
"QoS Error need to parse QOS_PARAMETER IE\n"); "QoS Error need to parse QOS_PARAMETER IE\n");
break; break;
/* 802.11h */
case MFIE_TYPE_POWER_CONSTRAINT:
network->power_constraint = info_element->data[0];
network->flags |= NETWORK_HAS_POWER_CONSTRAINT;
break;
case MFIE_TYPE_CSA:
network->power_constraint = info_element->data[0];
network->flags |= NETWORK_HAS_CSA;
break;
case MFIE_TYPE_QUIET:
network->quiet.count = info_element->data[0];
network->quiet.period = info_element->data[1];
network->quiet.duration = info_element->data[2];
network->quiet.offset = info_element->data[3];
network->flags |= NETWORK_HAS_QUIET;
break;
case MFIE_TYPE_IBSS_DFS:
if (network->ibss_dfs)
break;
network->ibss_dfs =
kmalloc(info_element->len, GFP_ATOMIC);
if (!network->ibss_dfs)
return 1;
memcpy(network->ibss_dfs, info_element->data,
info_element->len);
network->flags |= NETWORK_HAS_IBSS_DFS;
break;
case MFIE_TYPE_TPC_REPORT:
network->tpc_report.transmit_power =
info_element->data[0];
network->tpc_report.link_margin = info_element->data[1];
network->flags |= NETWORK_HAS_TPC_REPORT;
break;
default: default:
IEEE80211_DEBUG_MGMT("unsupported IE %d\n", IEEE80211_DEBUG_MGMT
info_element->id); ("Unsupported info element: %s (%d)\n",
get_info_element_string(info_element->id),
info_element->id);
break; break;
} }
...@@ -1119,7 +1197,9 @@ static int ieee80211_parse_info_param(struct ieee80211_info_element ...@@ -1119,7 +1197,9 @@ static int ieee80211_parse_info_param(struct ieee80211_info_element
static int ieee80211_handle_assoc_resp(struct ieee80211_device *ieee, struct ieee80211_assoc_response static int ieee80211_handle_assoc_resp(struct ieee80211_device *ieee, struct ieee80211_assoc_response
*frame, struct ieee80211_rx_stats *stats) *frame, struct ieee80211_rx_stats *stats)
{ {
struct ieee80211_network network_resp; struct ieee80211_network network_resp = {
.ibss_dfs = NULL,
};
struct ieee80211_network *network = &network_resp; struct ieee80211_network *network = &network_resp;
struct net_device *dev = ieee->dev; struct net_device *dev = ieee->dev;
...@@ -1262,6 +1342,9 @@ static void update_network(struct ieee80211_network *dst, ...@@ -1262,6 +1342,9 @@ static void update_network(struct ieee80211_network *dst,
int qos_active; int qos_active;
u8 old_param; u8 old_param;
ieee80211_network_reset(dst);
dst->ibss_dfs = src->ibss_dfs;
memcpy(&dst->stats, &src->stats, sizeof(struct ieee80211_rx_stats)); memcpy(&dst->stats, &src->stats, sizeof(struct ieee80211_rx_stats));
dst->capability = src->capability; dst->capability = src->capability;
memcpy(dst->rates, src->rates, src->rates_len); memcpy(dst->rates, src->rates, src->rates_len);
...@@ -1323,7 +1406,9 @@ static void ieee80211_process_probe_response(struct ieee80211_device ...@@ -1323,7 +1406,9 @@ static void ieee80211_process_probe_response(struct ieee80211_device
*stats) *stats)
{ {
struct net_device *dev = ieee->dev; struct net_device *dev = ieee->dev;
struct ieee80211_network network; struct ieee80211_network network = {
.ibss_dfs = NULL,
};
struct ieee80211_network *target; struct ieee80211_network *target;
struct ieee80211_network *oldest = NULL; struct ieee80211_network *oldest = NULL;
#ifdef CONFIG_IEEE80211_DEBUG #ifdef CONFIG_IEEE80211_DEBUG
...@@ -1398,6 +1483,7 @@ static void ieee80211_process_probe_response(struct ieee80211_device ...@@ -1398,6 +1483,7 @@ static void ieee80211_process_probe_response(struct ieee80211_device
escape_essid(target->ssid, escape_essid(target->ssid,
target->ssid_len), target->ssid_len),
MAC_ARG(target->bssid)); MAC_ARG(target->bssid));
ieee80211_network_reset(target);
} else { } else {
/* Otherwise just pull from the free list */ /* Otherwise just pull from the free list */
target = list_entry(ieee->network_free_list.next, target = list_entry(ieee->network_free_list.next,
...@@ -1416,6 +1502,7 @@ static void ieee80211_process_probe_response(struct ieee80211_device ...@@ -1416,6 +1502,7 @@ static void ieee80211_process_probe_response(struct ieee80211_device
"BEACON" : "PROBE RESPONSE"); "BEACON" : "PROBE RESPONSE");
#endif #endif
memcpy(target, &network, sizeof(*target)); memcpy(target, &network, sizeof(*target));
network.ibss_dfs = NULL;
list_add_tail(&target->list, &ieee->network_list); list_add_tail(&target->list, &ieee->network_list);
} else { } else {
IEEE80211_DEBUG_SCAN("Updating '%s' (" MAC_FMT ") via %s.\n", IEEE80211_DEBUG_SCAN("Updating '%s' (" MAC_FMT ") via %s.\n",
...@@ -1427,6 +1514,7 @@ static void ieee80211_process_probe_response(struct ieee80211_device ...@@ -1427,6 +1514,7 @@ static void ieee80211_process_probe_response(struct ieee80211_device
frame_ctl)) ? frame_ctl)) ?
"BEACON" : "PROBE RESPONSE"); "BEACON" : "PROBE RESPONSE");
update_network(target, &network); update_network(target, &network);
network.ibss_dfs = NULL;
} }
spin_unlock_irqrestore(&ieee->lock, flags); spin_unlock_irqrestore(&ieee->lock, flags);
...@@ -1511,10 +1599,19 @@ void ieee80211_rx_mgt(struct ieee80211_device *ieee, ...@@ -1511,10 +1599,19 @@ void ieee80211_rx_mgt(struct ieee80211_device *ieee,
header); header);
break; break;
case IEEE80211_STYPE_ACTION:
IEEE80211_DEBUG_MGMT("ACTION\n");
if (ieee->handle_action)
ieee->handle_action(ieee->dev,
(struct ieee80211_action *)
header, stats);
break;
case IEEE80211_STYPE_DEAUTH: case IEEE80211_STYPE_DEAUTH:
printk("DEAUTH from AP\n"); IEEE80211_DEBUG_MGMT("DEAUTH\n");
if (ieee->handle_deauth != NULL) if (ieee->handle_deauth != NULL)
ieee->handle_deauth(ieee->dev, (struct ieee80211_deauth *) ieee->handle_deauth(ieee->dev,
(struct ieee80211_deauth *)
header); header);
break; break;
default: default:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment