linux/drivers/net/wireless/ath/ath10k/p2p.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2015 Qualcomm Atheros, Inc.
   3 *
   4 * Permission to use, copy, modify, and/or distribute this software for any
   5 * purpose with or without fee is hereby granted, provided that the above
   6 * copyright notice and this permission notice appear in all copies.
   7 *
   8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
   9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15 */
  16
  17#include "core.h"
  18#include "wmi.h"
  19#include "mac.h"
  20#include "p2p.h"
  21
  22static void ath10k_p2p_noa_ie_fill(u8 *data, size_t len,
  23                                   const struct wmi_p2p_noa_info *noa)
  24{
  25        struct ieee80211_p2p_noa_attr *noa_attr;
  26        u8  ctwindow_oppps = noa->ctwindow_oppps;
  27        u8 ctwindow = ctwindow_oppps >> WMI_P2P_OPPPS_CTWINDOW_OFFSET;
  28        bool oppps = !!(ctwindow_oppps & WMI_P2P_OPPPS_ENABLE_BIT);
  29        __le16 *noa_attr_len;
  30        u16 attr_len;
  31        u8 noa_descriptors = noa->num_descriptors;
  32        int i;
  33
  34        /* P2P IE */
  35        data[0] = WLAN_EID_VENDOR_SPECIFIC;
  36        data[1] = len - 2;
  37        data[2] = (WLAN_OUI_WFA >> 16) & 0xff;
  38        data[3] = (WLAN_OUI_WFA >> 8) & 0xff;
  39        data[4] = (WLAN_OUI_WFA >> 0) & 0xff;
  40        data[5] = WLAN_OUI_TYPE_WFA_P2P;
  41
  42        /* NOA ATTR */
  43        data[6] = IEEE80211_P2P_ATTR_ABSENCE_NOTICE;
  44        noa_attr_len = (__le16 *)&data[7]; /* 2 bytes */
  45        noa_attr = (struct ieee80211_p2p_noa_attr *)&data[9];
  46
  47        noa_attr->index = noa->index;
  48        noa_attr->oppps_ctwindow = ctwindow;
  49        if (oppps)
  50                noa_attr->oppps_ctwindow |= IEEE80211_P2P_OPPPS_ENABLE_BIT;
  51
  52        for (i = 0; i < noa_descriptors; i++) {
  53                noa_attr->desc[i].count =
  54                        __le32_to_cpu(noa->descriptors[i].type_count);
  55                noa_attr->desc[i].duration = noa->descriptors[i].duration;
  56                noa_attr->desc[i].interval = noa->descriptors[i].interval;
  57                noa_attr->desc[i].start_time = noa->descriptors[i].start_time;
  58        }
  59
  60        attr_len = 2; /* index + oppps_ctwindow */
  61        attr_len += noa_descriptors * sizeof(struct ieee80211_p2p_noa_desc);
  62        *noa_attr_len = __cpu_to_le16(attr_len);
  63}
  64
  65static size_t ath10k_p2p_noa_ie_len_compute(const struct wmi_p2p_noa_info *noa)
  66{
  67        size_t len = 0;
  68
  69        if (!noa->num_descriptors &&
  70            !(noa->ctwindow_oppps & WMI_P2P_OPPPS_ENABLE_BIT))
  71                return 0;
  72
  73        len += 1 + 1 + 4; /* EID + len + OUI */
  74        len += 1 + 2; /* noa attr + attr len */
  75        len += 1 + 1; /* index + oppps_ctwindow */
  76        len += noa->num_descriptors * sizeof(struct ieee80211_p2p_noa_desc);
  77
  78        return len;
  79}
  80
  81static void ath10k_p2p_noa_ie_assign(struct ath10k_vif *arvif, void *ie,
  82                                     size_t len)
  83{
  84        struct ath10k *ar = arvif->ar;
  85
  86        lockdep_assert_held(&ar->data_lock);
  87
  88        kfree(arvif->u.ap.noa_data);
  89
  90        arvif->u.ap.noa_data = ie;
  91        arvif->u.ap.noa_len = len;
  92}
  93
  94static void __ath10k_p2p_noa_update(struct ath10k_vif *arvif,
  95                                    const struct wmi_p2p_noa_info *noa)
  96{
  97        struct ath10k *ar = arvif->ar;
  98        void *ie;
  99        size_t len;
 100
 101        lockdep_assert_held(&ar->data_lock);
 102
 103        ath10k_p2p_noa_ie_assign(arvif, NULL, 0);
 104
 105        len = ath10k_p2p_noa_ie_len_compute(noa);
 106        if (!len)
 107                return;
 108
 109        ie = kmalloc(len, GFP_ATOMIC);
 110        if (!ie)
 111                return;
 112
 113        ath10k_p2p_noa_ie_fill(ie, len, noa);
 114        ath10k_p2p_noa_ie_assign(arvif, ie, len);
 115}
 116
 117void ath10k_p2p_noa_update(struct ath10k_vif *arvif,
 118                           const struct wmi_p2p_noa_info *noa)
 119{
 120        struct ath10k *ar = arvif->ar;
 121
 122        spin_lock_bh(&ar->data_lock);
 123        __ath10k_p2p_noa_update(arvif, noa);
 124        spin_unlock_bh(&ar->data_lock);
 125}
 126
 127struct ath10k_p2p_noa_arg {
 128        u32 vdev_id;
 129        const struct wmi_p2p_noa_info *noa;
 130};
 131
 132static void ath10k_p2p_noa_update_vdev_iter(void *data, u8 *mac,
 133                                            struct ieee80211_vif *vif)
 134{
 135        struct ath10k_vif *arvif = (void *)vif->drv_priv;
 136        struct ath10k_p2p_noa_arg *arg = data;
 137
 138        if (arvif->vdev_id != arg->vdev_id)
 139                return;
 140
 141        ath10k_p2p_noa_update(arvif, arg->noa);
 142}
 143
 144void ath10k_p2p_noa_update_by_vdev_id(struct ath10k *ar, u32 vdev_id,
 145                                      const struct wmi_p2p_noa_info *noa)
 146{
 147        struct ath10k_p2p_noa_arg arg = {
 148                .vdev_id = vdev_id,
 149                .noa = noa,
 150        };
 151
 152        ieee80211_iterate_active_interfaces_atomic(ar->hw,
 153                                                   IEEE80211_IFACE_ITER_NORMAL,
 154                                                   ath10k_p2p_noa_update_vdev_iter,
 155                                                   &arg);
 156}
 157