Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 277844
b: refs/heads/master
c: 79d3eef
h: refs/heads/master
v: v3
  • Loading branch information
Johannes Berg authored and John W. Linville committed Nov 11, 2011
1 parent df82b60 commit 11100e8
Show file tree
Hide file tree
Showing 5 changed files with 69 additions and 1 deletion.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 868a5f719d730866564d9bd73a8f4a8d89bdc71a
refs/heads/master: 79d3eef89190ee0a7ee585e3949873241bc382e3
46 changes: 46 additions & 0 deletions trunk/drivers/net/wireless/iwlwifi/iwl-agn-rx.c
Original file line number Diff line number Diff line change
Expand Up @@ -1032,6 +1032,50 @@ static int iwlagn_rx_reply_rx(struct iwl_priv *priv,
return 0;
}

static int iwlagn_rx_noa_notification(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb,
struct iwl_device_cmd *cmd)
{
struct iwl_wipan_noa_data *new_data, *old_data;
struct iwl_rx_packet *pkt = rxb_addr(rxb);
struct iwl_wipan_noa_notification *noa_notif = (void *)pkt->u.raw;

/* no condition -- we're in softirq */
old_data = rcu_dereference_protected(priv->noa_data, true);

if (noa_notif->noa_active) {
u32 len = le16_to_cpu(noa_notif->noa_attribute.length);
u32 copylen = len;

/* EID, len, OUI, subtype */
len += 1 + 1 + 3 + 1;
/* P2P id, P2P length */
len += 1 + 2;
copylen += 1 + 2;

new_data = kmalloc(sizeof(*new_data) + len, GFP_ATOMIC);
if (new_data) {
new_data->length = len;
new_data->data[0] = WLAN_EID_VENDOR_SPECIFIC;
new_data->data[1] = len - 2; /* not counting EID, len */
new_data->data[2] = (WLAN_OUI_WFA >> 16) & 0xff;
new_data->data[3] = (WLAN_OUI_WFA >> 8) & 0xff;
new_data->data[4] = (WLAN_OUI_WFA >> 0) & 0xff;
new_data->data[5] = WLAN_OUI_TYPE_WFA_P2P;
memcpy(&new_data->data[6], &noa_notif->noa_attribute,
copylen);
}
} else
new_data = NULL;

rcu_assign_pointer(priv->noa_data, new_data);

if (old_data)
kfree_rcu(old_data, rcu_head);

return 0;
}

/**
* iwl_setup_rx_handlers - Initialize Rx handler callbacks
*
Expand All @@ -1055,6 +1099,8 @@ void iwl_setup_rx_handlers(struct iwl_priv *priv)
handlers[BEACON_NOTIFICATION] = iwlagn_rx_beacon_notif;
handlers[REPLY_ADD_STA] = iwl_add_sta_callback;

handlers[REPLY_WIPAN_NOA_NOTIFICATION] = iwlagn_rx_noa_notification;

/*
* The same handler is used for both the REPLY to a discrete
* statistics request from the host as well as for the periodic
Expand Down
13 changes: 13 additions & 0 deletions trunk/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,19 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
IWL_DEBUG_TX(priv, "Sending REASSOC frame\n");
#endif

if (unlikely(ieee80211_is_probe_resp(fc))) {
struct iwl_wipan_noa_data *noa_data =
rcu_dereference(priv->noa_data);

if (noa_data &&
pskb_expand_head(skb, 0, noa_data->length,
GFP_ATOMIC) == 0) {
memcpy(skb_put(skb, noa_data->length),
noa_data->data, noa_data->length);
hdr = (struct ieee80211_hdr *)skb->data;
}
}

hdr_len = ieee80211_hdrlen(fc);

/* For management frames use broadcast id to do not break aggregation */
Expand Down
1 change: 1 addition & 0 deletions trunk/drivers/net/wireless/iwlwifi/iwl-agn.c
Original file line number Diff line number Diff line change
Expand Up @@ -3069,6 +3069,7 @@ static void iwl_uninit_drv(struct iwl_priv *priv)
kmem_cache_destroy(priv->tx_cmd_pool);
kfree(priv->scan_cmd);
kfree(priv->beacon_cmd);
kfree(rcu_dereference_raw(priv->noa_data));
#ifdef CONFIG_IWLWIFI_DEBUGFS
kfree(priv->wowlan_sram);
#endif
Expand Down
8 changes: 8 additions & 0 deletions trunk/drivers/net/wireless/iwlwifi/iwl-dev.h
Original file line number Diff line number Diff line change
Expand Up @@ -824,6 +824,12 @@ struct iwl_testmode_trace {
};
#endif

struct iwl_wipan_noa_data {
struct rcu_head rcu_head;
u32 length;
u8 data[];
};

struct iwl_priv {

/*data shared among all the driver's layers */
Expand Down Expand Up @@ -883,6 +889,8 @@ struct iwl_priv {
/* init calibration results */
struct iwl_calib_result calib_results[IWL_CALIB_MAX];

struct iwl_wipan_noa_data __rcu *noa_data;

/* Scan related variables */
unsigned long scan_start;
unsigned long scan_start_tsf;
Expand Down

0 comments on commit 11100e8

Please sign in to comment.