/*
* Copyright 2002-2005, Instant802 Networks, Inc.
* Copyright 2005-2006, Devicescape Software, Inc.
* Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <net/mac80211.h>
#include <net/ieee80211_radiotap.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/netdevice.h>
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/skbuff.h>
#include <linux/etherdevice.h>
#include <linux/if_arp.h>
#include <linux/wireless.h>
#include <linux/rtnetlink.h>
#include <linux/bitmap.h>
#include <linux/pm_qos_params.h>
#include <net/net_namespace.h>
#include <net/cfg80211.h>
#include "ieee80211_i.h"
#include "driver-ops.h"
#include "rate.h"
#include "mesh.h"
#include "wep.h"
#include "wme.h"
#include "aes_ccm.h"
#include "led.h"
#include "cfg.h"
#include "debugfs.h"
#include "debugfs_netdev.h"
/*
* For seeing transmitted packets on monitor interfaces
* we have a radiotap header too.
*/
struct ieee80211_tx_status_rtap_hdr {
struct ieee80211_radiotap_header hdr;
u8 rate;
u8 padding_for_rate;
__le16 tx_flags;
u8 data_retries;
} __attribute__ ((packed));
/* must be called under mdev tx lock */
void ieee80211_configure_filter(struct ieee80211_local *local)
{
unsigned int changed_flags;
unsigned int new_flags = 0;
if (atomic_read(&local->iff_promiscs))
new_flags |= FIF_PROMISC_IN_BSS;
if (atomic_read(&local->iff_allmultis))
new_flags |= FIF_ALLMULTI;
if (local->monitors)
new_flags |= FIF_BCN_PRBRESP_PROMISC;
if (local->fif_fcsfail)
new_flags |= FIF_FCSFAIL;
if (local->fif_plcpfail)
new_flags |= FIF_PLCPFAIL;
if (local->fif_control)
new_flags |= FIF_CONTROL;
if (local->fif_other_bss)
new_flags |= FIF_OTHER_BSS;
changed_flags = local->filter_flags ^ new_flags;
/* be a bit nasty */
new_flags |= (1<<31);
drv_configure_filter(local, changed_flags, &new_flags,
local->mc_count,
local->mc_list);
WARN_ON(new_flags & (1<<31));
local->filter_flags = new_flags & ~(1<<31);
}
int ieee80211_hw_config(struct ieee80211_local *local, u32 changed)
{
struct ieee80211_channel *chan, *scan_chan;
int ret = 0;
int power;
enum nl80211_channel_type channel_type;
might_sleep();
scan_chan = local->scan_channel;
if (scan_chan) {
chan = scan_chan;
channel_type = NL80211_CHAN_NO_HT;
} else {
chan = local->oper_channel;
channel_type = local->oper_channel_type;
}
if (chan != local->hw.conf.channel ||
channel_type != local->hw.conf.channel_type) {
local->hw.conf.channel = chan;
local->hw.conf.channel_type = channel_type;
changed |= IEEE80211_CONF_CHANGE_CHANNEL;
}
if (scan_chan)
power = chan->max_power;
else
power = local->power_constr_level ?
(chan->max_power - local->power_constr_level) :
chan->max_power;
if (local->user_power_level >= 0)
power = min(power, local->user_power_level);
if (local->hw.conf.power_level != power) {
changed |= IEEE80211_CONF_CHANGE_POWER;
local->hw.conf.power_level = power;
}
if (changed && local->open_count) {
ret = drv_config(local, changed);
/*
* Goal:
* HW reconfiguration should never fail, the driver has told
* us what it can support so it should live up to that promise.
*
* Current status:
* rfkill is not integrated with mac80211 and a
* configuration command can thus fail if hardware rfkill
* is enabled
*
* FIXME: integrate rfkill with mac80211 and then add this
* WARN_ON() back
*
*/
/* WARN_ON(ret); */
}
return ret;
}
void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata,
u32 changed)
{
struct ieee80211_local *local = sdata->local;
static const u8 zero[ETH_ALEN] = { 0 };
if (!changed)
return;
if (sdata->vif.type == NL80211_IFTYPE_STATION) {
/*
* While not associated, claim a BSSID of all-zeroes
* so that drivers don't do any weird things with the
* BSSID at that time.
*/
if (sdata->vif.bss_conf.assoc)
sdata->vif.bss_conf.bssid = sdata->u.mgd.bssid;
else
sdata->vif.bss_conf.bssid =