Merge branch 'for-john' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next
This commit is contained in:
Коммит
55d1cad2ef
|
@ -1873,7 +1873,7 @@ int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb)
|
|||
brcmf_dbg(DATA, "tx proto=0x%X\n", ntohs(eh->h_proto));
|
||||
/* determine the priority */
|
||||
if (!skb->priority)
|
||||
skb->priority = cfg80211_classify8021d(skb);
|
||||
skb->priority = cfg80211_classify8021d(skb, NULL);
|
||||
|
||||
drvr->tx_multicast += !!multicast;
|
||||
if (pae)
|
||||
|
|
|
@ -749,7 +749,7 @@ static struct net_device_stats *mwifiex_get_stats(struct net_device *dev)
|
|||
static u16
|
||||
mwifiex_netdev_select_wmm_queue(struct net_device *dev, struct sk_buff *skb)
|
||||
{
|
||||
skb->priority = cfg80211_classify8021d(skb);
|
||||
skb->priority = cfg80211_classify8021d(skb, NULL);
|
||||
return mwifiex_1d_to_wmm_queue[skb->priority];
|
||||
}
|
||||
|
||||
|
|
|
@ -1971,6 +1971,50 @@ struct cfg80211_mgmt_tx_params {
|
|||
bool dont_wait_for_ack;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct cfg80211_dscp_exception - DSCP exception
|
||||
*
|
||||
* @dscp: DSCP value that does not adhere to the user priority range definition
|
||||
* @up: user priority value to which the corresponding DSCP value belongs
|
||||
*/
|
||||
struct cfg80211_dscp_exception {
|
||||
u8 dscp;
|
||||
u8 up;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct cfg80211_dscp_range - DSCP range definition for user priority
|
||||
*
|
||||
* @low: lowest DSCP value of this user priority range, inclusive
|
||||
* @high: highest DSCP value of this user priority range, inclusive
|
||||
*/
|
||||
struct cfg80211_dscp_range {
|
||||
u8 low;
|
||||
u8 high;
|
||||
};
|
||||
|
||||
/* QoS Map Set element length defined in IEEE Std 802.11-2012, 8.4.2.97 */
|
||||
#define IEEE80211_QOS_MAP_MAX_EX 21
|
||||
#define IEEE80211_QOS_MAP_LEN_MIN 16
|
||||
#define IEEE80211_QOS_MAP_LEN_MAX \
|
||||
(IEEE80211_QOS_MAP_LEN_MIN + 2 * IEEE80211_QOS_MAP_MAX_EX)
|
||||
|
||||
/**
|
||||
* struct cfg80211_qos_map - QoS Map Information
|
||||
*
|
||||
* This struct defines the Interworking QoS map setting for DSCP values
|
||||
*
|
||||
* @num_des: number of DSCP exceptions (0..21)
|
||||
* @dscp_exception: optionally up to maximum of 21 DSCP exceptions from
|
||||
* the user priority DSCP range definition
|
||||
* @up: DSCP range definition for a particular user priority
|
||||
*/
|
||||
struct cfg80211_qos_map {
|
||||
u8 num_des;
|
||||
struct cfg80211_dscp_exception dscp_exception[IEEE80211_QOS_MAP_MAX_EX];
|
||||
struct cfg80211_dscp_range up[8];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct cfg80211_ops - backend description for wireless configuration
|
||||
*
|
||||
|
@ -2213,6 +2257,8 @@ struct cfg80211_mgmt_tx_params {
|
|||
* @set_coalesce: Set coalesce parameters.
|
||||
*
|
||||
* @channel_switch: initiate channel-switch procedure (with CSA)
|
||||
*
|
||||
* @set_qos_map: Set QoS mapping information to the driver
|
||||
*/
|
||||
struct cfg80211_ops {
|
||||
int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
|
||||
|
@ -2454,6 +2500,9 @@ struct cfg80211_ops {
|
|||
int (*channel_switch)(struct wiphy *wiphy,
|
||||
struct net_device *dev,
|
||||
struct cfg80211_csa_settings *params);
|
||||
int (*set_qos_map)(struct wiphy *wiphy,
|
||||
struct net_device *dev,
|
||||
struct cfg80211_qos_map *qos_map);
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -2824,6 +2873,8 @@ struct wiphy_vendor_command {
|
|||
*
|
||||
* @vendor_commands: array of vendor commands supported by the hardware
|
||||
* @n_vendor_commands: number of vendor commands
|
||||
* @vendor_events: array of vendor events supported by the hardware
|
||||
* @n_vendor_events: number of vendor events
|
||||
*/
|
||||
struct wiphy {
|
||||
/* assign these fields before you register the wiphy */
|
||||
|
@ -2936,7 +2987,8 @@ struct wiphy {
|
|||
const struct wiphy_coalesce_support *coalesce;
|
||||
|
||||
const struct wiphy_vendor_command *vendor_commands;
|
||||
int n_vendor_commands;
|
||||
const struct nl80211_vendor_cmd_info *vendor_events;
|
||||
int n_vendor_commands, n_vendor_events;
|
||||
|
||||
char priv[0] __aligned(NETDEV_ALIGN);
|
||||
};
|
||||
|
@ -3429,9 +3481,11 @@ void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list,
|
|||
/**
|
||||
* cfg80211_classify8021d - determine the 802.1p/1d tag for a data frame
|
||||
* @skb: the data frame
|
||||
* @qos_map: Interworking QoS mapping or %NULL if not in use
|
||||
* Return: The 802.1p/1d tag.
|
||||
*/
|
||||
unsigned int cfg80211_classify8021d(struct sk_buff *skb);
|
||||
unsigned int cfg80211_classify8021d(struct sk_buff *skb,
|
||||
struct cfg80211_qos_map *qos_map);
|
||||
|
||||
/**
|
||||
* cfg80211_find_ie - find information element in data
|
||||
|
@ -3907,6 +3961,14 @@ struct sk_buff *__cfg80211_alloc_reply_skb(struct wiphy *wiphy,
|
|||
enum nl80211_attrs attr,
|
||||
int approxlen);
|
||||
|
||||
struct sk_buff *__cfg80211_alloc_event_skb(struct wiphy *wiphy,
|
||||
enum nl80211_commands cmd,
|
||||
enum nl80211_attrs attr,
|
||||
int vendor_event_idx,
|
||||
int approxlen, gfp_t gfp);
|
||||
|
||||
void __cfg80211_send_event_skb(struct sk_buff *skb, gfp_t gfp);
|
||||
|
||||
/**
|
||||
* cfg80211_vendor_cmd_alloc_reply_skb - allocate vendor command reply
|
||||
* @wiphy: the wiphy
|
||||
|
@ -3951,6 +4013,44 @@ cfg80211_vendor_cmd_alloc_reply_skb(struct wiphy *wiphy, int approxlen)
|
|||
*/
|
||||
int cfg80211_vendor_cmd_reply(struct sk_buff *skb);
|
||||
|
||||
/**
|
||||
* cfg80211_vendor_event_alloc - allocate vendor-specific event skb
|
||||
* @wiphy: the wiphy
|
||||
* @event_idx: index of the vendor event in the wiphy's vendor_events
|
||||
* @approxlen: an upper bound of the length of the data that will
|
||||
* be put into the skb
|
||||
* @gfp: allocation flags
|
||||
*
|
||||
* This function allocates and pre-fills an skb for an event on the
|
||||
* vendor-specific multicast group.
|
||||
*
|
||||
* When done filling the skb, call cfg80211_vendor_event() with the
|
||||
* skb to send the event.
|
||||
*
|
||||
* Return: An allocated and pre-filled skb. %NULL if any errors happen.
|
||||
*/
|
||||
static inline struct sk_buff *
|
||||
cfg80211_vendor_event_alloc(struct wiphy *wiphy, int approxlen,
|
||||
int event_idx, gfp_t gfp)
|
||||
{
|
||||
return __cfg80211_alloc_event_skb(wiphy, NL80211_CMD_VENDOR,
|
||||
NL80211_ATTR_VENDOR_DATA,
|
||||
event_idx, approxlen, gfp);
|
||||
}
|
||||
|
||||
/**
|
||||
* cfg80211_vendor_event - send the event
|
||||
* @skb: The skb, must have been allocated with cfg80211_vendor_event_alloc()
|
||||
* @gfp: allocation flags
|
||||
*
|
||||
* This function sends the given @skb, which must have been allocated
|
||||
* by cfg80211_vendor_event_alloc(), as an event. It always consumes it.
|
||||
*/
|
||||
static inline void cfg80211_vendor_event(struct sk_buff *skb, gfp_t gfp)
|
||||
{
|
||||
__cfg80211_send_event_skb(skb, gfp);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NL80211_TESTMODE
|
||||
/**
|
||||
* DOC: Test mode
|
||||
|
@ -4031,8 +4131,13 @@ static inline int cfg80211_testmode_reply(struct sk_buff *skb)
|
|||
*
|
||||
* Return: An allocated and pre-filled skb. %NULL if any errors happen.
|
||||
*/
|
||||
struct sk_buff *cfg80211_testmode_alloc_event_skb(struct wiphy *wiphy,
|
||||
int approxlen, gfp_t gfp);
|
||||
static inline struct sk_buff *
|
||||
cfg80211_testmode_alloc_event_skb(struct wiphy *wiphy, int approxlen, gfp_t gfp)
|
||||
{
|
||||
return __cfg80211_alloc_event_skb(wiphy, NL80211_CMD_TESTMODE,
|
||||
NL80211_ATTR_TESTDATA, -1,
|
||||
approxlen, gfp);
|
||||
}
|
||||
|
||||
/**
|
||||
* cfg80211_testmode_event - send the event
|
||||
|
@ -4044,7 +4149,10 @@ struct sk_buff *cfg80211_testmode_alloc_event_skb(struct wiphy *wiphy,
|
|||
* by cfg80211_testmode_alloc_event_skb(), as an event. It always
|
||||
* consumes it.
|
||||
*/
|
||||
void cfg80211_testmode_event(struct sk_buff *skb, gfp_t gfp);
|
||||
static inline void cfg80211_testmode_event(struct sk_buff *skb, gfp_t gfp)
|
||||
{
|
||||
__cfg80211_send_event_skb(skb, gfp);
|
||||
}
|
||||
|
||||
#define CFG80211_TESTMODE_CMD(cmd) .testmode_cmd = (cmd),
|
||||
#define CFG80211_TESTMODE_DUMP(cmd) .testmode_dump = (cmd),
|
||||
|
|
|
@ -4652,4 +4652,51 @@ bool ieee80211_tx_prepare_skb(struct ieee80211_hw *hw,
|
|||
struct ieee80211_vif *vif, struct sk_buff *skb,
|
||||
int band, struct ieee80211_sta **sta);
|
||||
|
||||
/**
|
||||
* struct ieee80211_noa_data - holds temporary data for tracking P2P NoA state
|
||||
*
|
||||
* @next_tsf: TSF timestamp of the next absent state change
|
||||
* @has_next_tsf: next absent state change event pending
|
||||
*
|
||||
* @absent: descriptor bitmask, set if GO is currently absent
|
||||
*
|
||||
* private:
|
||||
*
|
||||
* @count: count fields from the NoA descriptors
|
||||
* @desc: adjusted data from the NoA
|
||||
*/
|
||||
struct ieee80211_noa_data {
|
||||
u32 next_tsf;
|
||||
bool has_next_tsf;
|
||||
|
||||
u8 absent;
|
||||
|
||||
u8 count[IEEE80211_P2P_NOA_DESC_MAX];
|
||||
struct {
|
||||
u32 start;
|
||||
u32 duration;
|
||||
u32 interval;
|
||||
} desc[IEEE80211_P2P_NOA_DESC_MAX];
|
||||
};
|
||||
|
||||
/**
|
||||
* ieee80211_parse_p2p_noa - initialize NoA tracking data from P2P IE
|
||||
*
|
||||
* @attr: P2P NoA IE
|
||||
* @data: NoA tracking data
|
||||
* @tsf: current TSF timestamp
|
||||
*
|
||||
* Return: number of successfully parsed descriptors
|
||||
*/
|
||||
int ieee80211_parse_p2p_noa(const struct ieee80211_p2p_noa_attr *attr,
|
||||
struct ieee80211_noa_data *data, u32 tsf);
|
||||
|
||||
/**
|
||||
* ieee80211_update_p2p_noa - get next pending P2P GO absent state change
|
||||
*
|
||||
* @data: NoA tracking data
|
||||
* @tsf: current TSF timestamp
|
||||
*/
|
||||
void ieee80211_update_p2p_noa(struct ieee80211_noa_data *data, u32 tsf);
|
||||
|
||||
#endif /* MAC80211_H */
|
||||
|
|
|
@ -702,6 +702,12 @@
|
|||
* (&struct nl80211_vendor_cmd_info) of the supported vendor commands.
|
||||
* This may also be sent as an event with the same attributes.
|
||||
*
|
||||
* @NL80211_CMD_SET_QOS_MAP: Set Interworking QoS mapping for IP DSCP values.
|
||||
* The QoS mapping information is included in %NL80211_ATTR_QOS_MAP. If
|
||||
* that attribute is not included, QoS mapping is disabled. Since this
|
||||
* QoS mapping is relevant for IP packets, it is only valid during an
|
||||
* association. This is cleared on disassociation and AP restart.
|
||||
*
|
||||
* @NL80211_CMD_MAX: highest used command number
|
||||
* @__NL80211_CMD_AFTER_LAST: internal use
|
||||
*/
|
||||
|
@ -871,6 +877,8 @@ enum nl80211_commands {
|
|||
|
||||
NL80211_CMD_VENDOR,
|
||||
|
||||
NL80211_CMD_SET_QOS_MAP,
|
||||
|
||||
/* add new commands above here */
|
||||
|
||||
/* used to define NL80211_CMD_MAX below */
|
||||
|
@ -1540,6 +1548,12 @@ enum nl80211_commands {
|
|||
* @NL80211_ATTR_VENDOR_SUBCMD: vendor sub-command
|
||||
* @NL80211_ATTR_VENDOR_DATA: data for the vendor command, if any; this
|
||||
* attribute is also used for vendor command feature advertisement
|
||||
* @NL80211_ATTR_VENDOR_EVENTS: used for event list advertising in the wiphy
|
||||
* info, containing a nested array of possible events
|
||||
*
|
||||
* @NL80211_ATTR_QOS_MAP: IP DSCP mapping for Interworking QoS mapping. This
|
||||
* data is in the format defined for the payload of the QoS Map Set element
|
||||
* in IEEE Std 802.11-2012, 8.4.2.97.
|
||||
*
|
||||
* @NL80211_ATTR_MAX: highest attribute number currently defined
|
||||
* @__NL80211_ATTR_AFTER_LAST: internal use
|
||||
|
@ -1865,6 +1879,9 @@ enum nl80211_attrs {
|
|||
NL80211_ATTR_VENDOR_ID,
|
||||
NL80211_ATTR_VENDOR_SUBCMD,
|
||||
NL80211_ATTR_VENDOR_DATA,
|
||||
NL80211_ATTR_VENDOR_EVENTS,
|
||||
|
||||
NL80211_ATTR_QOS_MAP,
|
||||
|
||||
/* add attributes here, update the policy in nl80211.c */
|
||||
|
||||
|
|
|
@ -111,7 +111,7 @@ void ieee80211_aes_cmac(struct crypto_cipher *tfm, const u8 *aad,
|
|||
}
|
||||
|
||||
|
||||
struct crypto_cipher * ieee80211_aes_cmac_key_setup(const u8 key[])
|
||||
struct crypto_cipher *ieee80211_aes_cmac_key_setup(const u8 key[])
|
||||
{
|
||||
struct crypto_cipher *tfm;
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
#include <linux/crypto.h>
|
||||
|
||||
struct crypto_cipher * ieee80211_aes_cmac_key_setup(const u8 key[]);
|
||||
struct crypto_cipher *ieee80211_aes_cmac_key_setup(const u8 key[]);
|
||||
void ieee80211_aes_cmac(struct crypto_cipher *tfm, const u8 *aad,
|
||||
const u8 *data, size_t data_len, u8 *mic);
|
||||
void ieee80211_aes_cmac_key_free(struct crypto_cipher *tfm);
|
||||
|
|
|
@ -828,6 +828,7 @@ static int ieee80211_set_monitor_channel(struct wiphy *wiphy,
|
|||
if (cfg80211_chandef_identical(&local->monitor_chandef, chandef))
|
||||
return 0;
|
||||
|
||||
mutex_lock(&local->mtx);
|
||||
mutex_lock(&local->iflist_mtx);
|
||||
if (local->use_chanctx) {
|
||||
sdata = rcu_dereference_protected(
|
||||
|
@ -846,6 +847,7 @@ static int ieee80211_set_monitor_channel(struct wiphy *wiphy,
|
|||
if (ret == 0)
|
||||
local->monitor_chandef = *chandef;
|
||||
mutex_unlock(&local->iflist_mtx);
|
||||
mutex_unlock(&local->mtx);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -951,6 +953,7 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
|
|||
struct cfg80211_ap_settings *params)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct beacon_data *old;
|
||||
struct ieee80211_sub_if_data *vlan;
|
||||
u32 changed = BSS_CHANGED_BEACON_INT |
|
||||
|
@ -969,8 +972,10 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
|
|||
sdata->needed_rx_chains = sdata->local->rx_chains;
|
||||
sdata->radar_required = params->radar_required;
|
||||
|
||||
mutex_lock(&local->mtx);
|
||||
err = ieee80211_vif_use_channel(sdata, ¶ms->chandef,
|
||||
IEEE80211_CHANCTX_SHARED);
|
||||
mutex_unlock(&local->mtx);
|
||||
if (err)
|
||||
return err;
|
||||
ieee80211_vif_copy_chanctx_to_vlans(sdata, false);
|
||||
|
@ -1121,7 +1126,9 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev)
|
|||
skb_queue_purge(&sdata->u.ap.ps.bc_buf);
|
||||
|
||||
ieee80211_vif_copy_chanctx_to_vlans(sdata, true);
|
||||
mutex_lock(&local->mtx);
|
||||
ieee80211_vif_release_channel(sdata);
|
||||
mutex_unlock(&local->mtx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1944,8 +1951,10 @@ static int ieee80211_join_mesh(struct wiphy *wiphy, struct net_device *dev,
|
|||
sdata->smps_mode = IEEE80211_SMPS_OFF;
|
||||
sdata->needed_rx_chains = sdata->local->rx_chains;
|
||||
|
||||
mutex_lock(&sdata->local->mtx);
|
||||
err = ieee80211_vif_use_channel(sdata, &setup->chandef,
|
||||
IEEE80211_CHANCTX_SHARED);
|
||||
mutex_unlock(&sdata->local->mtx);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
|
@ -1957,7 +1966,9 @@ static int ieee80211_leave_mesh(struct wiphy *wiphy, struct net_device *dev)
|
|||
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
|
||||
ieee80211_stop_mesh(sdata);
|
||||
mutex_lock(&sdata->local->mtx);
|
||||
ieee80211_vif_release_channel(sdata);
|
||||
mutex_unlock(&sdata->local->mtx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -2895,26 +2906,29 @@ static int ieee80211_start_radar_detection(struct wiphy *wiphy,
|
|||
unsigned long timeout;
|
||||
int err;
|
||||
|
||||
if (!list_empty(&local->roc_list) || local->scanning)
|
||||
return -EBUSY;
|
||||
mutex_lock(&local->mtx);
|
||||
if (!list_empty(&local->roc_list) || local->scanning) {
|
||||
err = -EBUSY;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
/* whatever, but channel contexts should not complain about that one */
|
||||
sdata->smps_mode = IEEE80211_SMPS_OFF;
|
||||
sdata->needed_rx_chains = local->rx_chains;
|
||||
sdata->radar_required = true;
|
||||
|
||||
mutex_lock(&local->iflist_mtx);
|
||||
err = ieee80211_vif_use_channel(sdata, chandef,
|
||||
IEEE80211_CHANCTX_SHARED);
|
||||
mutex_unlock(&local->iflist_mtx);
|
||||
if (err)
|
||||
return err;
|
||||
goto out_unlock;
|
||||
|
||||
timeout = msecs_to_jiffies(IEEE80211_DFS_MIN_CAC_TIME_MS);
|
||||
ieee80211_queue_delayed_work(&sdata->local->hw,
|
||||
&sdata->dfs_cac_timer_work, timeout);
|
||||
|
||||
return 0;
|
||||
out_unlock:
|
||||
mutex_unlock(&local->mtx);
|
||||
return err;
|
||||
}
|
||||
|
||||
static struct cfg80211_beacon_data *
|
||||
|
@ -2990,7 +3004,9 @@ void ieee80211_csa_finalize_work(struct work_struct *work)
|
|||
goto unlock;
|
||||
|
||||
sdata->radar_required = sdata->csa_radar_required;
|
||||
mutex_lock(&local->mtx);
|
||||
err = ieee80211_vif_change_channel(sdata, &changed);
|
||||
mutex_unlock(&local->mtx);
|
||||
if (WARN_ON(err < 0))
|
||||
goto unlock;
|
||||
|
||||
|
@ -3821,6 +3837,31 @@ static void ieee80211_set_wakeup(struct wiphy *wiphy, bool enabled)
|
|||
}
|
||||
#endif
|
||||
|
||||
static int ieee80211_set_qos_map(struct wiphy *wiphy,
|
||||
struct net_device *dev,
|
||||
struct cfg80211_qos_map *qos_map)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
|
||||
struct mac80211_qos_map *new_qos_map, *old_qos_map;
|
||||
|
||||
if (qos_map) {
|
||||
new_qos_map = kzalloc(sizeof(*new_qos_map), GFP_KERNEL);
|
||||
if (!new_qos_map)
|
||||
return -ENOMEM;
|
||||
memcpy(&new_qos_map->qos_map, qos_map, sizeof(*qos_map));
|
||||
} else {
|
||||
/* A NULL qos_map was passed to disable QoS mapping */
|
||||
new_qos_map = NULL;
|
||||
}
|
||||
|
||||
old_qos_map = rtnl_dereference(sdata->qos_map);
|
||||
rcu_assign_pointer(sdata->qos_map, new_qos_map);
|
||||
if (old_qos_map)
|
||||
kfree_rcu(old_qos_map, rcu_head);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct cfg80211_ops mac80211_config_ops = {
|
||||
.add_virtual_intf = ieee80211_add_iface,
|
||||
.del_virtual_intf = ieee80211_del_iface,
|
||||
|
@ -3900,4 +3941,5 @@ struct cfg80211_ops mac80211_config_ops = {
|
|||
.get_channel = ieee80211_cfg_get_channel,
|
||||
.start_radar_detection = ieee80211_start_radar_detection,
|
||||
.channel_switch = ieee80211_channel_switch,
|
||||
.set_qos_map = ieee80211_set_qos_map,
|
||||
};
|
||||
|
|
|
@ -232,8 +232,8 @@ ieee80211_new_chanctx(struct ieee80211_local *local,
|
|||
if (!local->use_chanctx)
|
||||
local->hw.conf.radar_enabled = ctx->conf.radar_enabled;
|
||||
|
||||
/* acquire mutex to prevent idle from changing */
|
||||
mutex_lock(&local->mtx);
|
||||
/* we hold the mutex to prevent idle from changing */
|
||||
lockdep_assert_held(&local->mtx);
|
||||
/* turn idle off *before* setting channel -- some drivers need that */
|
||||
changed = ieee80211_idle_off(local);
|
||||
if (changed)
|
||||
|
@ -246,19 +246,14 @@ ieee80211_new_chanctx(struct ieee80211_local *local,
|
|||
err = drv_add_chanctx(local, ctx);
|
||||
if (err) {
|
||||
kfree(ctx);
|
||||
ctx = ERR_PTR(err);
|
||||
|
||||
ieee80211_recalc_idle(local);
|
||||
goto out;
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
}
|
||||
|
||||
/* and keep the mutex held until the new chanctx is on the list */
|
||||
list_add_rcu(&ctx->list, &local->chanctx_list);
|
||||
|
||||
out:
|
||||
mutex_unlock(&local->mtx);
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
|
@ -294,9 +289,7 @@ static void ieee80211_free_chanctx(struct ieee80211_local *local,
|
|||
/* throw a warning if this wasn't the only channel context. */
|
||||
WARN_ON(check_single_channel && !list_empty(&local->chanctx_list));
|
||||
|
||||
mutex_lock(&local->mtx);
|
||||
ieee80211_recalc_idle(local);
|
||||
mutex_unlock(&local->mtx);
|
||||
}
|
||||
|
||||
static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata,
|
||||
|
@ -358,6 +351,31 @@ static void ieee80211_recalc_chanctx_chantype(struct ieee80211_local *local,
|
|||
ieee80211_change_chanctx(local, ctx, compat);
|
||||
}
|
||||
|
||||
static void ieee80211_recalc_radar_chanctx(struct ieee80211_local *local,
|
||||
struct ieee80211_chanctx *chanctx)
|
||||
{
|
||||
bool radar_enabled;
|
||||
|
||||
lockdep_assert_held(&local->chanctx_mtx);
|
||||
/* for setting local->radar_detect_enabled */
|
||||
lockdep_assert_held(&local->mtx);
|
||||
|
||||
radar_enabled = ieee80211_is_radar_required(local);
|
||||
|
||||
if (radar_enabled == chanctx->conf.radar_enabled)
|
||||
return;
|
||||
|
||||
chanctx->conf.radar_enabled = radar_enabled;
|
||||
local->radar_detect_enabled = chanctx->conf.radar_enabled;
|
||||
|
||||
if (!local->use_chanctx) {
|
||||
local->hw.conf.radar_enabled = chanctx->conf.radar_enabled;
|
||||
ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
|
||||
}
|
||||
|
||||
drv_change_chanctx(local, chanctx, IEEE80211_CHANCTX_CHANGE_RADAR);
|
||||
}
|
||||
|
||||
static void ieee80211_unassign_vif_chanctx(struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_chanctx *ctx)
|
||||
{
|
||||
|
@ -404,29 +422,6 @@ static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata)
|
|||
ieee80211_free_chanctx(local, ctx);
|
||||
}
|
||||
|
||||
void ieee80211_recalc_radar_chanctx(struct ieee80211_local *local,
|
||||
struct ieee80211_chanctx *chanctx)
|
||||
{
|
||||
bool radar_enabled;
|
||||
|
||||
lockdep_assert_held(&local->chanctx_mtx);
|
||||
|
||||
radar_enabled = ieee80211_is_radar_required(local);
|
||||
|
||||
if (radar_enabled == chanctx->conf.radar_enabled)
|
||||
return;
|
||||
|
||||
chanctx->conf.radar_enabled = radar_enabled;
|
||||
local->radar_detect_enabled = chanctx->conf.radar_enabled;
|
||||
|
||||
if (!local->use_chanctx) {
|
||||
local->hw.conf.radar_enabled = chanctx->conf.radar_enabled;
|
||||
ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
|
||||
}
|
||||
|
||||
drv_change_chanctx(local, chanctx, IEEE80211_CHANCTX_CHANGE_RADAR);
|
||||
}
|
||||
|
||||
void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local,
|
||||
struct ieee80211_chanctx *chanctx)
|
||||
{
|
||||
|
@ -518,6 +513,8 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
|
|||
struct ieee80211_chanctx *ctx;
|
||||
int ret;
|
||||
|
||||
lockdep_assert_held(&local->mtx);
|
||||
|
||||
WARN_ON(sdata->dev && netif_carrier_ok(sdata->dev));
|
||||
|
||||
mutex_lock(&local->chanctx_mtx);
|
||||
|
@ -558,6 +555,8 @@ int ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata,
|
|||
int ret;
|
||||
u32 chanctx_changed = 0;
|
||||
|
||||
lockdep_assert_held(&local->mtx);
|
||||
|
||||
/* should never be called if not performing a channel switch. */
|
||||
if (WARN_ON(!sdata->vif.csa_active))
|
||||
return -EINVAL;
|
||||
|
@ -655,6 +654,8 @@ void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata)
|
|||
{
|
||||
WARN_ON(sdata->dev && netif_carrier_ok(sdata->dev));
|
||||
|
||||
lockdep_assert_held(&sdata->local->mtx);
|
||||
|
||||
mutex_lock(&sdata->local->chanctx_mtx);
|
||||
__ieee80211_vif_release_channel(sdata);
|
||||
mutex_unlock(&sdata->local->chanctx_mtx);
|
||||
|
|
|
@ -293,14 +293,17 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
|
|||
radar_required = true;
|
||||
}
|
||||
|
||||
mutex_lock(&local->mtx);
|
||||
ieee80211_vif_release_channel(sdata);
|
||||
if (ieee80211_vif_use_channel(sdata, &chandef,
|
||||
ifibss->fixed_channel ?
|
||||
IEEE80211_CHANCTX_SHARED :
|
||||
IEEE80211_CHANCTX_EXCLUSIVE)) {
|
||||
sdata_info(sdata, "Failed to join IBSS, no channel context\n");
|
||||
mutex_unlock(&local->mtx);
|
||||
return;
|
||||
}
|
||||
mutex_unlock(&local->mtx);
|
||||
|
||||
memcpy(ifibss->bssid, bssid, ETH_ALEN);
|
||||
|
||||
|
@ -363,7 +366,9 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
|
|||
sdata->vif.bss_conf.ssid_len = 0;
|
||||
RCU_INIT_POINTER(ifibss->presp, NULL);
|
||||
kfree_rcu(presp, rcu_head);
|
||||
mutex_lock(&local->mtx);
|
||||
ieee80211_vif_release_channel(sdata);
|
||||
mutex_unlock(&local->mtx);
|
||||
sdata_info(sdata, "Failed to join IBSS, driver failure: %d\n",
|
||||
err);
|
||||
return;
|
||||
|
@ -747,7 +752,9 @@ static void ieee80211_ibss_disconnect(struct ieee80211_sub_if_data *sdata)
|
|||
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED |
|
||||
BSS_CHANGED_IBSS);
|
||||
drv_leave_ibss(local, sdata);
|
||||
mutex_lock(&local->mtx);
|
||||
ieee80211_vif_release_channel(sdata);
|
||||
mutex_unlock(&local->mtx);
|
||||
}
|
||||
|
||||
static void ieee80211_csa_connection_drop_work(struct work_struct *work)
|
||||
|
|
|
@ -246,7 +246,8 @@ struct ps_data {
|
|||
/* yes, this looks ugly, but guarantees that we can later use
|
||||
* bitmap_empty :)
|
||||
* NB: don't touch this bitmap, use sta_info_{set,clear}_tim_bit */
|
||||
u8 tim[sizeof(unsigned long) * BITS_TO_LONGS(IEEE80211_MAX_AID + 1)];
|
||||
u8 tim[sizeof(unsigned long) * BITS_TO_LONGS(IEEE80211_MAX_AID + 1)]
|
||||
__aligned(__alignof__(unsigned long));
|
||||
struct sk_buff_head bc_buf;
|
||||
atomic_t num_sta_ps; /* number of stations in PS mode */
|
||||
int dtim_count;
|
||||
|
@ -693,6 +694,11 @@ struct ieee80211_chanctx {
|
|||
struct ieee80211_chanctx_conf conf;
|
||||
};
|
||||
|
||||
struct mac80211_qos_map {
|
||||
struct cfg80211_qos_map qos_map;
|
||||
struct rcu_head rcu_head;
|
||||
};
|
||||
|
||||
struct ieee80211_sub_if_data {
|
||||
struct list_head list;
|
||||
|
||||
|
@ -738,6 +744,7 @@ struct ieee80211_sub_if_data {
|
|||
int encrypt_headroom;
|
||||
|
||||
struct ieee80211_tx_queue_params tx_conf[IEEE80211_NUM_ACS];
|
||||
struct mac80211_qos_map __rcu *qos_map;
|
||||
|
||||
struct work_struct csa_finalize_work;
|
||||
int csa_counter_offset_beacon;
|
||||
|
@ -1775,8 +1782,6 @@ void ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata,
|
|||
|
||||
void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local,
|
||||
struct ieee80211_chanctx *chanctx);
|
||||
void ieee80211_recalc_radar_chanctx(struct ieee80211_local *local,
|
||||
struct ieee80211_chanctx *chanctx);
|
||||
void ieee80211_recalc_chanctx_min_def(struct ieee80211_local *local,
|
||||
struct ieee80211_chanctx *ctx);
|
||||
|
||||
|
|
|
@ -418,8 +418,10 @@ int ieee80211_add_virtual_monitor(struct ieee80211_local *local)
|
|||
return ret;
|
||||
}
|
||||
|
||||
mutex_lock(&local->mtx);
|
||||
ret = ieee80211_vif_use_channel(sdata, &local->monitor_chandef,
|
||||
IEEE80211_CHANCTX_EXCLUSIVE);
|
||||
mutex_unlock(&local->mtx);
|
||||
if (ret) {
|
||||
drv_remove_interface(local, sdata);
|
||||
kfree(sdata);
|
||||
|
@ -456,7 +458,9 @@ void ieee80211_del_virtual_monitor(struct ieee80211_local *local)
|
|||
|
||||
synchronize_net();
|
||||
|
||||
mutex_lock(&local->mtx);
|
||||
ieee80211_vif_release_channel(sdata);
|
||||
mutex_unlock(&local->mtx);
|
||||
|
||||
drv_remove_interface(local, sdata);
|
||||
|
||||
|
@ -826,9 +830,9 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
|
|||
if (sdata->wdev.cac_started) {
|
||||
chandef = sdata->vif.bss_conf.chandef;
|
||||
WARN_ON(local->suspended);
|
||||
mutex_lock(&local->iflist_mtx);
|
||||
mutex_lock(&local->mtx);
|
||||
ieee80211_vif_release_channel(sdata);
|
||||
mutex_unlock(&local->iflist_mtx);
|
||||
mutex_unlock(&local->mtx);
|
||||
cfg80211_cac_event(sdata->dev, &chandef,
|
||||
NL80211_RADAR_CAC_ABORTED,
|
||||
GFP_KERNEL);
|
||||
|
|
|
@ -888,7 +888,9 @@ static void ieee80211_chswitch_work(struct work_struct *work)
|
|||
if (!ifmgd->associated)
|
||||
goto out;
|
||||
|
||||
mutex_lock(&local->mtx);
|
||||
ret = ieee80211_vif_change_channel(sdata, &changed);
|
||||
mutex_unlock(&local->mtx);
|
||||
if (ret) {
|
||||
sdata_info(sdata,
|
||||
"vif channel switch failed, disconnecting\n");
|
||||
|
@ -1401,10 +1403,14 @@ void ieee80211_dfs_cac_timer_work(struct work_struct *work)
|
|||
dfs_cac_timer_work);
|
||||
struct cfg80211_chan_def chandef = sdata->vif.bss_conf.chandef;
|
||||
|
||||
ieee80211_vif_release_channel(sdata);
|
||||
cfg80211_cac_event(sdata->dev, &chandef,
|
||||
NL80211_RADAR_CAC_FINISHED,
|
||||
GFP_KERNEL);
|
||||
mutex_lock(&sdata->local->mtx);
|
||||
if (sdata->wdev.cac_started) {
|
||||
ieee80211_vif_release_channel(sdata);
|
||||
cfg80211_cac_event(sdata->dev, &chandef,
|
||||
NL80211_RADAR_CAC_FINISHED,
|
||||
GFP_KERNEL);
|
||||
}
|
||||
mutex_unlock(&sdata->local->mtx);
|
||||
}
|
||||
|
||||
/* MLME */
|
||||
|
@ -1747,7 +1753,9 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
|
|||
ifmgd->have_beacon = false;
|
||||
|
||||
ifmgd->flags = 0;
|
||||
mutex_lock(&local->mtx);
|
||||
ieee80211_vif_release_channel(sdata);
|
||||
mutex_unlock(&local->mtx);
|
||||
|
||||
sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM;
|
||||
}
|
||||
|
@ -2070,7 +2078,9 @@ static void ieee80211_destroy_auth_data(struct ieee80211_sub_if_data *sdata,
|
|||
memset(sdata->u.mgd.bssid, 0, ETH_ALEN);
|
||||
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID);
|
||||
sdata->u.mgd.flags = 0;
|
||||
mutex_lock(&sdata->local->mtx);
|
||||
ieee80211_vif_release_channel(sdata);
|
||||
mutex_unlock(&sdata->local->mtx);
|
||||
}
|
||||
|
||||
cfg80211_put_bss(sdata->local->hw.wiphy, auth_data->bss);
|
||||
|
@ -2319,7 +2329,9 @@ static void ieee80211_destroy_assoc_data(struct ieee80211_sub_if_data *sdata,
|
|||
memset(sdata->u.mgd.bssid, 0, ETH_ALEN);
|
||||
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID);
|
||||
sdata->u.mgd.flags = 0;
|
||||
mutex_lock(&sdata->local->mtx);
|
||||
ieee80211_vif_release_channel(sdata);
|
||||
mutex_unlock(&sdata->local->mtx);
|
||||
}
|
||||
|
||||
kfree(assoc_data);
|
||||
|
@ -3670,6 +3682,7 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
|
|||
/* will change later if needed */
|
||||
sdata->smps_mode = IEEE80211_SMPS_OFF;
|
||||
|
||||
mutex_lock(&local->mtx);
|
||||
/*
|
||||
* If this fails (possibly due to channel context sharing
|
||||
* on incompatible channels, e.g. 80+80 and 160 sharing the
|
||||
|
@ -3681,13 +3694,15 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
|
|||
/* don't downgrade for 5 and 10 MHz channels, though. */
|
||||
if (chandef.width == NL80211_CHAN_WIDTH_5 ||
|
||||
chandef.width == NL80211_CHAN_WIDTH_10)
|
||||
return ret;
|
||||
goto out;
|
||||
|
||||
while (ret && chandef.width != NL80211_CHAN_WIDTH_20_NOHT) {
|
||||
ifmgd->flags |= ieee80211_chandef_downgrade(&chandef);
|
||||
ret = ieee80211_vif_use_channel(sdata, &chandef,
|
||||
IEEE80211_CHANCTX_SHARED);
|
||||
}
|
||||
out:
|
||||
mutex_unlock(&local->mtx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -135,7 +135,7 @@ minstrel_update_stats(struct minstrel_priv *mp, struct minstrel_sta_info *mi)
|
|||
u32 usecs;
|
||||
int i;
|
||||
|
||||
for (i=0; i < MAX_THR_RATES; i++)
|
||||
for (i = 0; i < MAX_THR_RATES; i++)
|
||||
tmp_tp_rate[i] = 0;
|
||||
|
||||
for (i = 0; i < mi->n_rates; i++) {
|
||||
|
@ -190,7 +190,7 @@ minstrel_update_stats(struct minstrel_priv *mp, struct minstrel_sta_info *mi)
|
|||
* choose the maximum throughput rate as max_prob_rate
|
||||
* (2) if all success probabilities < 95%, the rate with
|
||||
* highest success probability is choosen as max_prob_rate */
|
||||
if (mr->probability >= MINSTREL_FRAC(95,100)) {
|
||||
if (mr->probability >= MINSTREL_FRAC(95, 100)) {
|
||||
if (mr->cur_tp >= mi->r[tmp_prob_rate].cur_tp)
|
||||
tmp_prob_rate = i;
|
||||
} else {
|
||||
|
@ -220,7 +220,7 @@ minstrel_update_stats(struct minstrel_priv *mp, struct minstrel_sta_info *mi)
|
|||
|
||||
static void
|
||||
minstrel_tx_status(void *priv, struct ieee80211_supported_band *sband,
|
||||
struct ieee80211_sta *sta, void *priv_sta,
|
||||
struct ieee80211_sta *sta, void *priv_sta,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct minstrel_priv *mp = priv;
|
||||
|
@ -260,7 +260,7 @@ minstrel_tx_status(void *priv, struct ieee80211_supported_band *sband,
|
|||
|
||||
static inline unsigned int
|
||||
minstrel_get_retry_count(struct minstrel_rate *mr,
|
||||
struct ieee80211_tx_info *info)
|
||||
struct ieee80211_tx_info *info)
|
||||
{
|
||||
unsigned int retry = mr->adjusted_retry_count;
|
||||
|
||||
|
|
|
@ -63,7 +63,7 @@
|
|||
|
||||
#define CCK_DURATION(_bitrate, _short, _len) \
|
||||
(1000 * (10 /* SIFS */ + \
|
||||
(_short ? 72 + 24 : 144 + 48 ) + \
|
||||
(_short ? 72 + 24 : 144 + 48) + \
|
||||
(8 * (_len + 4) * 10) / (_bitrate)))
|
||||
|
||||
#define CCK_ACK_DURATION(_bitrate, _short) \
|
||||
|
|
|
@ -186,7 +186,7 @@ void ieee80211_get_tkip_p1k_iv(struct ieee80211_key_conf *keyconf,
|
|||
EXPORT_SYMBOL(ieee80211_get_tkip_p1k_iv);
|
||||
|
||||
void ieee80211_get_tkip_rx_p1k(struct ieee80211_key_conf *keyconf,
|
||||
const u8 *ta, u32 iv32, u16 *p1k)
|
||||
const u8 *ta, u32 iv32, u16 *p1k)
|
||||
{
|
||||
const u8 *tk = &keyconf->key[NL80211_TKIP_DATA_OFFSET_ENCR_KEY];
|
||||
struct tkip_ctx ctx;
|
||||
|
|
|
@ -553,7 +553,7 @@ TRACE_EVENT(drv_update_tkip_key,
|
|||
|
||||
TP_printk(
|
||||
LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT " iv32:%#x",
|
||||
LOCAL_PR_ARG,VIF_PR_ARG,STA_PR_ARG, __entry->iv32
|
||||
LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->iv32
|
||||
)
|
||||
);
|
||||
|
||||
|
|
|
@ -2161,7 +2161,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
|
|||
if (ieee80211_is_data_qos(fc)) {
|
||||
__le16 *qos_control;
|
||||
|
||||
qos_control = (__le16*) skb_push(skb, 2);
|
||||
qos_control = (__le16 *) skb_push(skb, 2);
|
||||
memcpy(skb_push(skb, hdrlen - 2), &hdr, hdrlen - 2);
|
||||
/*
|
||||
* Maybe we could actually set some fields here, for now just
|
||||
|
@ -2323,7 +2323,7 @@ static void __ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata,
|
|||
if (atomic_read(&ps->num_sta_ps) > 0)
|
||||
/* in the hope that this is faster than
|
||||
* checking byte-for-byte */
|
||||
have_bits = !bitmap_empty((unsigned long*)ps->tim,
|
||||
have_bits = !bitmap_empty((unsigned long *)ps->tim,
|
||||
IEEE80211_MAX_AID+1);
|
||||
|
||||
if (ps->dtim_count == 0)
|
||||
|
|
|
@ -76,7 +76,7 @@ u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len,
|
|||
}
|
||||
|
||||
if (ieee80211_is_ctl(fc)) {
|
||||
if(ieee80211_is_pspoll(fc))
|
||||
if (ieee80211_is_pspoll(fc))
|
||||
return hdr->addr1;
|
||||
|
||||
if (ieee80211_is_back_req(fc)) {
|
||||
|
@ -2315,9 +2315,14 @@ void ieee80211_dfs_cac_cancel(struct ieee80211_local *local)
|
|||
struct ieee80211_sub_if_data *sdata;
|
||||
struct cfg80211_chan_def chandef;
|
||||
|
||||
mutex_lock(&local->mtx);
|
||||
mutex_lock(&local->iflist_mtx);
|
||||
list_for_each_entry(sdata, &local->interfaces, list) {
|
||||
cancel_delayed_work_sync(&sdata->dfs_cac_timer_work);
|
||||
/* it might be waiting for the local->mtx, but then
|
||||
* by the time it gets it, sdata->wdev.cac_started
|
||||
* will no longer be true
|
||||
*/
|
||||
cancel_delayed_work(&sdata->dfs_cac_timer_work);
|
||||
|
||||
if (sdata->wdev.cac_started) {
|
||||
chandef = sdata->vif.bss_conf.chandef;
|
||||
|
@ -2329,6 +2334,7 @@ void ieee80211_dfs_cac_cancel(struct ieee80211_local *local)
|
|||
}
|
||||
}
|
||||
mutex_unlock(&local->iflist_mtx);
|
||||
mutex_unlock(&local->mtx);
|
||||
}
|
||||
|
||||
void ieee80211_dfs_radar_detected_work(struct work_struct *work)
|
||||
|
@ -2588,3 +2594,143 @@ int ieee80211_cs_headroom(struct ieee80211_local *local,
|
|||
|
||||
return headroom;
|
||||
}
|
||||
|
||||
static bool
|
||||
ieee80211_extend_noa_desc(struct ieee80211_noa_data *data, u32 tsf, int i)
|
||||
{
|
||||
s32 end = data->desc[i].start + data->desc[i].duration - (tsf + 1);
|
||||
int skip;
|
||||
|
||||
if (end > 0)
|
||||
return false;
|
||||
|
||||
/* End time is in the past, check for repetitions */
|
||||
skip = DIV_ROUND_UP(-end, data->desc[i].interval);
|
||||
if (data->count[i] < 255) {
|
||||
if (data->count[i] <= skip) {
|
||||
data->count[i] = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
data->count[i] -= skip;
|
||||
}
|
||||
|
||||
data->desc[i].start += skip * data->desc[i].interval;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
ieee80211_extend_absent_time(struct ieee80211_noa_data *data, u32 tsf,
|
||||
s32 *offset)
|
||||
{
|
||||
bool ret = false;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < IEEE80211_P2P_NOA_DESC_MAX; i++) {
|
||||
s32 cur;
|
||||
|
||||
if (!data->count[i])
|
||||
continue;
|
||||
|
||||
if (ieee80211_extend_noa_desc(data, tsf + *offset, i))
|
||||
ret = true;
|
||||
|
||||
cur = data->desc[i].start - tsf;
|
||||
if (cur > *offset)
|
||||
continue;
|
||||
|
||||
cur = data->desc[i].start + data->desc[i].duration - tsf;
|
||||
if (cur > *offset)
|
||||
*offset = cur;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static u32
|
||||
ieee80211_get_noa_absent_time(struct ieee80211_noa_data *data, u32 tsf)
|
||||
{
|
||||
s32 offset = 0;
|
||||
int tries = 0;
|
||||
/*
|
||||
* arbitrary limit, used to avoid infinite loops when combined NoA
|
||||
* descriptors cover the full time period.
|
||||
*/
|
||||
int max_tries = 5;
|
||||
|
||||
ieee80211_extend_absent_time(data, tsf, &offset);
|
||||
do {
|
||||
if (!ieee80211_extend_absent_time(data, tsf, &offset))
|
||||
break;
|
||||
|
||||
tries++;
|
||||
} while (tries < max_tries);
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
void ieee80211_update_p2p_noa(struct ieee80211_noa_data *data, u32 tsf)
|
||||
{
|
||||
u32 next_offset = BIT(31) - 1;
|
||||
int i;
|
||||
|
||||
data->absent = 0;
|
||||
data->has_next_tsf = false;
|
||||
for (i = 0; i < IEEE80211_P2P_NOA_DESC_MAX; i++) {
|
||||
s32 start;
|
||||
|
||||
if (!data->count[i])
|
||||
continue;
|
||||
|
||||
ieee80211_extend_noa_desc(data, tsf, i);
|
||||
start = data->desc[i].start - tsf;
|
||||
if (start <= 0)
|
||||
data->absent |= BIT(i);
|
||||
|
||||
if (next_offset > start)
|
||||
next_offset = start;
|
||||
|
||||
data->has_next_tsf = true;
|
||||
}
|
||||
|
||||
if (data->absent)
|
||||
next_offset = ieee80211_get_noa_absent_time(data, tsf);
|
||||
|
||||
data->next_tsf = tsf + next_offset;
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_update_p2p_noa);
|
||||
|
||||
int ieee80211_parse_p2p_noa(const struct ieee80211_p2p_noa_attr *attr,
|
||||
struct ieee80211_noa_data *data, u32 tsf)
|
||||
{
|
||||
int ret = 0;
|
||||
int i;
|
||||
|
||||
memset(data, 0, sizeof(*data));
|
||||
|
||||
for (i = 0; i < IEEE80211_P2P_NOA_DESC_MAX; i++) {
|
||||
const struct ieee80211_p2p_noa_desc *desc = &attr->desc[i];
|
||||
|
||||
if (!desc->count || !desc->duration)
|
||||
continue;
|
||||
|
||||
data->count[i] = desc->count;
|
||||
data->desc[i].start = le32_to_cpu(desc->start_time);
|
||||
data->desc[i].duration = le32_to_cpu(desc->duration);
|
||||
data->desc[i].interval = le32_to_cpu(desc->interval);
|
||||
|
||||
if (data->count[i] > 1 &&
|
||||
data->desc[i].interval < data->desc[i].duration)
|
||||
continue;
|
||||
|
||||
ieee80211_extend_noa_desc(data, tsf, i);
|
||||
ret++;
|
||||
}
|
||||
|
||||
if (ret)
|
||||
ieee80211_update_p2p_noa(data, tsf);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_parse_p2p_noa);
|
||||
|
|
|
@ -106,6 +106,7 @@ u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata,
|
|||
struct sta_info *sta = NULL;
|
||||
const u8 *ra = NULL;
|
||||
bool qos = false;
|
||||
struct mac80211_qos_map *qos_map;
|
||||
|
||||
if (local->hw.queues < IEEE80211_NUM_ACS || skb->len < 6) {
|
||||
skb->priority = 0; /* required for correct WPA/11i MIC */
|
||||
|
@ -155,7 +156,11 @@ u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata,
|
|||
|
||||
/* use the data classifier to determine what 802.1d tag the
|
||||
* data frame has */
|
||||
skb->priority = cfg80211_classify8021d(skb);
|
||||
rcu_read_lock();
|
||||
qos_map = rcu_dereference(sdata->qos_map);
|
||||
skb->priority = cfg80211_classify8021d(skb, qos_map ?
|
||||
&qos_map->qos_map : NULL);
|
||||
rcu_read_unlock();
|
||||
|
||||
return ieee80211_downgrade_queue(sdata, skb);
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@ static int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev,
|
|||
wdev->beacon_interval = 0;
|
||||
wdev->channel = NULL;
|
||||
wdev->ssid_len = 0;
|
||||
rdev_set_qos_map(rdev, dev, NULL);
|
||||
}
|
||||
|
||||
return err;
|
||||
|
|
|
@ -183,6 +183,8 @@ static void __cfg80211_clear_ibss(struct net_device *dev, bool nowext)
|
|||
kfree(wdev->connect_keys);
|
||||
wdev->connect_keys = NULL;
|
||||
|
||||
rdev_set_qos_map(rdev, dev, NULL);
|
||||
|
||||
/*
|
||||
* Delete all the keys ... pairwise keys can't really
|
||||
* exist any more anyway, but default keys might.
|
||||
|
|
|
@ -277,6 +277,7 @@ static int __cfg80211_leave_mesh(struct cfg80211_registered_device *rdev,
|
|||
if (!err) {
|
||||
wdev->mesh_id_len = 0;
|
||||
wdev->channel = NULL;
|
||||
rdev_set_qos_map(rdev, dev, NULL);
|
||||
}
|
||||
|
||||
return err;
|
||||
|
|
|
@ -53,6 +53,7 @@ enum nl80211_multicast_groups {
|
|||
NL80211_MCGRP_SCAN,
|
||||
NL80211_MCGRP_REGULATORY,
|
||||
NL80211_MCGRP_MLME,
|
||||
NL80211_MCGRP_VENDOR,
|
||||
NL80211_MCGRP_TESTMODE /* keep last - ifdef! */
|
||||
};
|
||||
|
||||
|
@ -61,6 +62,7 @@ static const struct genl_multicast_group nl80211_mcgrps[] = {
|
|||
[NL80211_MCGRP_SCAN] = { .name = "scan", },
|
||||
[NL80211_MCGRP_REGULATORY] = { .name = "regulatory", },
|
||||
[NL80211_MCGRP_MLME] = { .name = "mlme", },
|
||||
[NL80211_MCGRP_VENDOR] = { .name = "vendor", },
|
||||
#ifdef CONFIG_NL80211_TESTMODE
|
||||
[NL80211_MCGRP_TESTMODE] = { .name = "testmode", }
|
||||
#endif
|
||||
|
@ -380,6 +382,8 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
|
|||
[NL80211_ATTR_VENDOR_ID] = { .type = NLA_U32 },
|
||||
[NL80211_ATTR_VENDOR_SUBCMD] = { .type = NLA_U32 },
|
||||
[NL80211_ATTR_VENDOR_DATA] = { .type = NLA_BINARY },
|
||||
[NL80211_ATTR_QOS_MAP] = { .type = NLA_BINARY,
|
||||
.len = IEEE80211_QOS_MAP_LEN_MAX },
|
||||
};
|
||||
|
||||
/* policy for the key attributes */
|
||||
|
@ -1188,7 +1192,6 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev,
|
|||
struct nlattr *nl_bands, *nl_band;
|
||||
struct nlattr *nl_freqs, *nl_freq;
|
||||
struct nlattr *nl_cmds;
|
||||
struct nlattr *nl_vendor_cmds;
|
||||
enum ieee80211_band band;
|
||||
struct ieee80211_channel *chan;
|
||||
int i;
|
||||
|
@ -1455,6 +1458,7 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev,
|
|||
if (dev->wiphy.flags & WIPHY_FLAG_HAS_CHANNEL_SWITCH)
|
||||
CMD(channel_switch, CHANNEL_SWITCH);
|
||||
}
|
||||
CMD(set_qos_map, SET_QOS_MAP);
|
||||
|
||||
#ifdef CONFIG_NL80211_TESTMODE
|
||||
CMD(testmode_cmd, TESTMODE);
|
||||
|
@ -1587,16 +1591,38 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev,
|
|||
state->split_start++;
|
||||
break;
|
||||
case 11:
|
||||
nl_vendor_cmds = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
|
||||
if (!nl_vendor_cmds)
|
||||
goto nla_put_failure;
|
||||
if (dev->wiphy.n_vendor_commands) {
|
||||
const struct nl80211_vendor_cmd_info *info;
|
||||
struct nlattr *nested;
|
||||
|
||||
for (i = 0; i < dev->wiphy.n_vendor_commands; i++)
|
||||
if (nla_put(msg, i + 1,
|
||||
sizeof(struct nl80211_vendor_cmd_info),
|
||||
&dev->wiphy.vendor_commands[i].info))
|
||||
nested = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
|
||||
if (!nested)
|
||||
goto nla_put_failure;
|
||||
nla_nest_end(msg, nl_vendor_cmds);
|
||||
|
||||
for (i = 0; i < dev->wiphy.n_vendor_commands; i++) {
|
||||
info = &dev->wiphy.vendor_commands[i].info;
|
||||
if (nla_put(msg, i + 1, sizeof(*info), info))
|
||||
goto nla_put_failure;
|
||||
}
|
||||
nla_nest_end(msg, nested);
|
||||
}
|
||||
|
||||
if (dev->wiphy.n_vendor_events) {
|
||||
const struct nl80211_vendor_cmd_info *info;
|
||||
struct nlattr *nested;
|
||||
|
||||
nested = nla_nest_start(msg,
|
||||
NL80211_ATTR_VENDOR_EVENTS);
|
||||
if (!nested)
|
||||
goto nla_put_failure;
|
||||
|
||||
for (i = 0; i < dev->wiphy.n_vendor_events; i++) {
|
||||
info = &dev->wiphy.vendor_events[i];
|
||||
if (nla_put(msg, i + 1, sizeof(*info), info))
|
||||
goto nla_put_failure;
|
||||
}
|
||||
nla_nest_end(msg, nested);
|
||||
}
|
||||
|
||||
/* done */
|
||||
state->split_start = 0;
|
||||
|
@ -6726,7 +6752,9 @@ static struct sk_buff *
|
|||
__cfg80211_alloc_vendor_skb(struct cfg80211_registered_device *rdev,
|
||||
int approxlen, u32 portid, u32 seq,
|
||||
enum nl80211_commands cmd,
|
||||
enum nl80211_attrs attr, gfp_t gfp)
|
||||
enum nl80211_attrs attr,
|
||||
const struct nl80211_vendor_cmd_info *info,
|
||||
gfp_t gfp)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
void *hdr;
|
||||
|
@ -6744,6 +6772,16 @@ __cfg80211_alloc_vendor_skb(struct cfg80211_registered_device *rdev,
|
|||
|
||||
if (nla_put_u32(skb, NL80211_ATTR_WIPHY, rdev->wiphy_idx))
|
||||
goto nla_put_failure;
|
||||
|
||||
if (info) {
|
||||
if (nla_put_u32(skb, NL80211_ATTR_VENDOR_ID,
|
||||
info->vendor_id))
|
||||
goto nla_put_failure;
|
||||
if (nla_put_u32(skb, NL80211_ATTR_VENDOR_SUBCMD,
|
||||
info->subcmd))
|
||||
goto nla_put_failure;
|
||||
}
|
||||
|
||||
data = nla_nest_start(skb, attr);
|
||||
|
||||
((void **)skb->cb)[0] = rdev;
|
||||
|
@ -6884,29 +6922,54 @@ static int nl80211_testmode_dump(struct sk_buff *skb,
|
|||
return err;
|
||||
}
|
||||
|
||||
struct sk_buff *cfg80211_testmode_alloc_event_skb(struct wiphy *wiphy,
|
||||
int approxlen, gfp_t gfp)
|
||||
struct sk_buff *__cfg80211_alloc_event_skb(struct wiphy *wiphy,
|
||||
enum nl80211_commands cmd,
|
||||
enum nl80211_attrs attr,
|
||||
int vendor_event_idx,
|
||||
int approxlen, gfp_t gfp)
|
||||
{
|
||||
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
|
||||
const struct nl80211_vendor_cmd_info *info;
|
||||
|
||||
switch (cmd) {
|
||||
case NL80211_CMD_TESTMODE:
|
||||
if (WARN_ON(vendor_event_idx != -1))
|
||||
return NULL;
|
||||
info = NULL;
|
||||
break;
|
||||
case NL80211_CMD_VENDOR:
|
||||
if (WARN_ON(vendor_event_idx < 0 ||
|
||||
vendor_event_idx >= wiphy->n_vendor_events))
|
||||
return NULL;
|
||||
info = &wiphy->vendor_events[vendor_event_idx];
|
||||
break;
|
||||
default:
|
||||
WARN_ON(1);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return __cfg80211_alloc_vendor_skb(rdev, approxlen, 0, 0,
|
||||
NL80211_CMD_TESTMODE,
|
||||
NL80211_ATTR_TESTDATA, gfp);
|
||||
cmd, attr, info, gfp);
|
||||
}
|
||||
EXPORT_SYMBOL(cfg80211_testmode_alloc_event_skb);
|
||||
EXPORT_SYMBOL(__cfg80211_alloc_event_skb);
|
||||
|
||||
void cfg80211_testmode_event(struct sk_buff *skb, gfp_t gfp)
|
||||
void __cfg80211_send_event_skb(struct sk_buff *skb, gfp_t gfp)
|
||||
{
|
||||
struct cfg80211_registered_device *rdev = ((void **)skb->cb)[0];
|
||||
void *hdr = ((void **)skb->cb)[1];
|
||||
struct nlattr *data = ((void **)skb->cb)[2];
|
||||
enum nl80211_multicast_groups mcgrp = NL80211_MCGRP_TESTMODE;
|
||||
|
||||
nla_nest_end(skb, data);
|
||||
genlmsg_end(skb, hdr);
|
||||
|
||||
if (data->nla_type == NL80211_ATTR_VENDOR_DATA)
|
||||
mcgrp = NL80211_MCGRP_VENDOR;
|
||||
|
||||
genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), skb, 0,
|
||||
NL80211_MCGRP_TESTMODE, gfp);
|
||||
mcgrp, gfp);
|
||||
}
|
||||
EXPORT_SYMBOL(cfg80211_testmode_event);
|
||||
EXPORT_SYMBOL(__cfg80211_send_event_skb);
|
||||
#endif
|
||||
|
||||
static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
|
||||
|
@ -9039,7 +9102,7 @@ struct sk_buff *__cfg80211_alloc_reply_skb(struct wiphy *wiphy,
|
|||
return __cfg80211_alloc_vendor_skb(rdev, approxlen,
|
||||
rdev->cur_cmd_info->snd_portid,
|
||||
rdev->cur_cmd_info->snd_seq,
|
||||
cmd, attr, GFP_KERNEL);
|
||||
cmd, attr, NULL, GFP_KERNEL);
|
||||
}
|
||||
EXPORT_SYMBOL(__cfg80211_alloc_reply_skb);
|
||||
|
||||
|
@ -9061,6 +9124,57 @@ int cfg80211_vendor_cmd_reply(struct sk_buff *skb)
|
|||
EXPORT_SYMBOL_GPL(cfg80211_vendor_cmd_reply);
|
||||
|
||||
|
||||
static int nl80211_set_qos_map(struct sk_buff *skb,
|
||||
struct genl_info *info)
|
||||
{
|
||||
struct cfg80211_registered_device *rdev = info->user_ptr[0];
|
||||
struct cfg80211_qos_map *qos_map = NULL;
|
||||
struct net_device *dev = info->user_ptr[1];
|
||||
u8 *pos, len, num_des, des_len, des;
|
||||
int ret;
|
||||
|
||||
if (!rdev->ops->set_qos_map)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (info->attrs[NL80211_ATTR_QOS_MAP]) {
|
||||
pos = nla_data(info->attrs[NL80211_ATTR_QOS_MAP]);
|
||||
len = nla_len(info->attrs[NL80211_ATTR_QOS_MAP]);
|
||||
|
||||
if (len % 2 || len < IEEE80211_QOS_MAP_LEN_MIN ||
|
||||
len > IEEE80211_QOS_MAP_LEN_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
qos_map = kzalloc(sizeof(struct cfg80211_qos_map), GFP_KERNEL);
|
||||
if (!qos_map)
|
||||
return -ENOMEM;
|
||||
|
||||
num_des = (len - IEEE80211_QOS_MAP_LEN_MIN) >> 1;
|
||||
if (num_des) {
|
||||
des_len = num_des *
|
||||
sizeof(struct cfg80211_dscp_exception);
|
||||
memcpy(qos_map->dscp_exception, pos, des_len);
|
||||
qos_map->num_des = num_des;
|
||||
for (des = 0; des < num_des; des++) {
|
||||
if (qos_map->dscp_exception[des].up > 7) {
|
||||
kfree(qos_map);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
pos += des_len;
|
||||
}
|
||||
memcpy(qos_map->up, pos, IEEE80211_QOS_MAP_LEN_MIN);
|
||||
}
|
||||
|
||||
wdev_lock(dev->ieee80211_ptr);
|
||||
ret = nl80211_key_allowed(dev->ieee80211_ptr);
|
||||
if (!ret)
|
||||
ret = rdev_set_qos_map(rdev, dev, qos_map);
|
||||
wdev_unlock(dev->ieee80211_ptr);
|
||||
|
||||
kfree(qos_map);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define NL80211_FLAG_NEED_WIPHY 0x01
|
||||
#define NL80211_FLAG_NEED_NETDEV 0x02
|
||||
#define NL80211_FLAG_NEED_RTNL 0x04
|
||||
|
@ -9793,6 +9907,14 @@ static const struct genl_ops nl80211_ops[] = {
|
|||
.internal_flags = NL80211_FLAG_NEED_WIPHY |
|
||||
NL80211_FLAG_NEED_RTNL,
|
||||
},
|
||||
{
|
||||
.cmd = NL80211_CMD_SET_QOS_MAP,
|
||||
.doit = nl80211_set_qos_map,
|
||||
.policy = nl80211_policy,
|
||||
.flags = GENL_ADMIN_PERM,
|
||||
.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
|
||||
NL80211_FLAG_NEED_RTNL,
|
||||
},
|
||||
};
|
||||
|
||||
/* notification functions */
|
||||
|
|
|
@ -932,4 +932,19 @@ static inline int rdev_channel_switch(struct cfg80211_registered_device *rdev,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static inline int rdev_set_qos_map(struct cfg80211_registered_device *rdev,
|
||||
struct net_device *dev,
|
||||
struct cfg80211_qos_map *qos_map)
|
||||
{
|
||||
int ret = -EOPNOTSUPP;
|
||||
|
||||
if (rdev->ops->set_qos_map) {
|
||||
trace_rdev_set_qos_map(&rdev->wiphy, dev, qos_map);
|
||||
ret = rdev->ops->set_qos_map(&rdev->wiphy, dev, qos_map);
|
||||
trace_rdev_return_int(&rdev->wiphy, ret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* __CFG80211_RDEV_OPS */
|
||||
|
|
|
@ -870,6 +870,8 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
|
|||
for (i = 0; i < 6; i++)
|
||||
rdev_del_key(rdev, dev, i, false, NULL);
|
||||
|
||||
rdev_set_qos_map(rdev, dev, NULL);
|
||||
|
||||
#ifdef CONFIG_CFG80211_WEXT
|
||||
memset(&wrqu, 0, sizeof(wrqu));
|
||||
wrqu.ap_addr.sa_family = ARPHRD_ETHER;
|
||||
|
|
|
@ -186,6 +186,28 @@
|
|||
|
||||
#define BOOL_TO_STR(bo) (bo) ? "true" : "false"
|
||||
|
||||
#define QOS_MAP_ENTRY __field(u8, num_des) \
|
||||
__array(u8, dscp_exception, \
|
||||
2 * IEEE80211_QOS_MAP_MAX_EX) \
|
||||
__array(u8, up, IEEE80211_QOS_MAP_LEN_MIN)
|
||||
#define QOS_MAP_ASSIGN(qos_map) \
|
||||
do { \
|
||||
if ((qos_map)) { \
|
||||
__entry->num_des = (qos_map)->num_des; \
|
||||
memcpy(__entry->dscp_exception, \
|
||||
&(qos_map)->dscp_exception, \
|
||||
2 * IEEE80211_QOS_MAP_MAX_EX); \
|
||||
memcpy(__entry->up, &(qos_map)->up, \
|
||||
IEEE80211_QOS_MAP_LEN_MIN); \
|
||||
} else { \
|
||||
__entry->num_des = 0; \
|
||||
memset(__entry->dscp_exception, 0, \
|
||||
2 * IEEE80211_QOS_MAP_MAX_EX); \
|
||||
memset(__entry->up, 0, \
|
||||
IEEE80211_QOS_MAP_LEN_MIN); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/*************************************************************
|
||||
* rdev->ops traces *
|
||||
*************************************************************/
|
||||
|
@ -1875,6 +1897,24 @@ TRACE_EVENT(rdev_channel_switch,
|
|||
__entry->counter_offset_presp)
|
||||
);
|
||||
|
||||
TRACE_EVENT(rdev_set_qos_map,
|
||||
TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
|
||||
struct cfg80211_qos_map *qos_map),
|
||||
TP_ARGS(wiphy, netdev, qos_map),
|
||||
TP_STRUCT__entry(
|
||||
WIPHY_ENTRY
|
||||
NETDEV_ENTRY
|
||||
QOS_MAP_ENTRY
|
||||
),
|
||||
TP_fast_assign(
|
||||
WIPHY_ASSIGN;
|
||||
NETDEV_ASSIGN;
|
||||
QOS_MAP_ASSIGN(qos_map);
|
||||
),
|
||||
TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", num_des: %u",
|
||||
WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->num_des)
|
||||
);
|
||||
|
||||
/*************************************************************
|
||||
* cfg80211 exported functions traces *
|
||||
*************************************************************/
|
||||
|
|
|
@ -689,7 +689,8 @@ void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list,
|
|||
EXPORT_SYMBOL(ieee80211_amsdu_to_8023s);
|
||||
|
||||
/* Given a data frame determine the 802.1p/1d tag to use. */
|
||||
unsigned int cfg80211_classify8021d(struct sk_buff *skb)
|
||||
unsigned int cfg80211_classify8021d(struct sk_buff *skb,
|
||||
struct cfg80211_qos_map *qos_map)
|
||||
{
|
||||
unsigned int dscp;
|
||||
unsigned char vlan_priority;
|
||||
|
@ -720,6 +721,21 @@ unsigned int cfg80211_classify8021d(struct sk_buff *skb)
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (qos_map) {
|
||||
unsigned int i, tmp_dscp = dscp >> 2;
|
||||
|
||||
for (i = 0; i < qos_map->num_des; i++) {
|
||||
if (tmp_dscp == qos_map->dscp_exception[i].dscp)
|
||||
return qos_map->dscp_exception[i].up;
|
||||
}
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
if (tmp_dscp >= qos_map->up[i].low &&
|
||||
tmp_dscp <= qos_map->up[i].high)
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return dscp >> 5;
|
||||
}
|
||||
EXPORT_SYMBOL(cfg80211_classify8021d);
|
||||
|
@ -863,6 +879,7 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
|
|||
|
||||
dev->ieee80211_ptr->use_4addr = false;
|
||||
dev->ieee80211_ptr->mesh_id_up_len = 0;
|
||||
rdev_set_qos_map(rdev, dev, NULL);
|
||||
|
||||
switch (otype) {
|
||||
case NL80211_IFTYPE_AP:
|
||||
|
|
Загрузка…
Ссылка в новой задаче