Branch data Line data Source code
1 : : // SPDX-License-Identifier: ISC 2 : : /* 3 : : * Copyright (c) 2015 Qualcomm Atheros, Inc. 4 : : */ 5 : : 6 : : #include "core.h" 7 : : #include "wmi.h" 8 : : #include "mac.h" 9 : : #include "p2p.h" 10 : : 11 : 0 : static void ath10k_p2p_noa_ie_fill(u8 *data, size_t len, 12 : : const struct wmi_p2p_noa_info *noa) 13 : : { 14 : 0 : struct ieee80211_p2p_noa_attr *noa_attr; 15 : 0 : u8 ctwindow_oppps = noa->ctwindow_oppps; 16 : 0 : u8 ctwindow = ctwindow_oppps >> WMI_P2P_OPPPS_CTWINDOW_OFFSET; 17 : 0 : bool oppps = !!(ctwindow_oppps & WMI_P2P_OPPPS_ENABLE_BIT); 18 : 0 : __le16 *noa_attr_len; 19 : 0 : u16 attr_len; 20 : 0 : u8 noa_descriptors = noa->num_descriptors; 21 : 0 : int i; 22 : : 23 : : /* P2P IE */ 24 : 0 : data[0] = WLAN_EID_VENDOR_SPECIFIC; 25 : 0 : data[1] = len - 2; 26 : 0 : data[2] = (WLAN_OUI_WFA >> 16) & 0xff; 27 : 0 : data[3] = (WLAN_OUI_WFA >> 8) & 0xff; 28 : 0 : data[4] = (WLAN_OUI_WFA >> 0) & 0xff; 29 : 0 : data[5] = WLAN_OUI_TYPE_WFA_P2P; 30 : : 31 : : /* NOA ATTR */ 32 : 0 : data[6] = IEEE80211_P2P_ATTR_ABSENCE_NOTICE; 33 : 0 : noa_attr_len = (__le16 *)&data[7]; /* 2 bytes */ 34 : 0 : noa_attr = (struct ieee80211_p2p_noa_attr *)&data[9]; 35 : : 36 : 0 : noa_attr->index = noa->index; 37 : 0 : noa_attr->oppps_ctwindow = ctwindow; 38 [ # # ]: 0 : if (oppps) 39 : 0 : noa_attr->oppps_ctwindow |= IEEE80211_P2P_OPPPS_ENABLE_BIT; 40 : : 41 [ # # ]: 0 : for (i = 0; i < noa_descriptors; i++) { 42 : 0 : noa_attr->desc[i].count = 43 : 0 : __le32_to_cpu(noa->descriptors[i].type_count); 44 : 0 : noa_attr->desc[i].duration = noa->descriptors[i].duration; 45 : 0 : noa_attr->desc[i].interval = noa->descriptors[i].interval; 46 : 0 : noa_attr->desc[i].start_time = noa->descriptors[i].start_time; 47 : : } 48 : : 49 : 0 : attr_len = 2; /* index + oppps_ctwindow */ 50 : 0 : attr_len += noa_descriptors * sizeof(struct ieee80211_p2p_noa_desc); 51 : 0 : *noa_attr_len = __cpu_to_le16(attr_len); 52 : 0 : } 53 : : 54 : 0 : static size_t ath10k_p2p_noa_ie_len_compute(const struct wmi_p2p_noa_info *noa) 55 : : { 56 : 0 : size_t len = 0; 57 : : 58 [ # # ]: 0 : if (!noa->num_descriptors && 59 : : !(noa->ctwindow_oppps & WMI_P2P_OPPPS_ENABLE_BIT)) 60 : : return 0; 61 : : 62 : 0 : len += 1 + 1 + 4; /* EID + len + OUI */ 63 : 0 : len += 1 + 2; /* noa attr + attr len */ 64 : 0 : len += 1 + 1; /* index + oppps_ctwindow */ 65 : 0 : len += noa->num_descriptors * sizeof(struct ieee80211_p2p_noa_desc); 66 : : 67 : 0 : return len; 68 : : } 69 : : 70 : 0 : static void ath10k_p2p_noa_ie_assign(struct ath10k_vif *arvif, void *ie, 71 : : size_t len) 72 : : { 73 : 0 : struct ath10k *ar = arvif->ar; 74 : : 75 : 0 : lockdep_assert_held(&ar->data_lock); 76 : : 77 : 0 : kfree(arvif->u.ap.noa_data); 78 : : 79 : 0 : arvif->u.ap.noa_data = ie; 80 : 0 : arvif->u.ap.noa_len = len; 81 : 0 : } 82 : : 83 : 0 : static void __ath10k_p2p_noa_update(struct ath10k_vif *arvif, 84 : : const struct wmi_p2p_noa_info *noa) 85 : : { 86 : 0 : struct ath10k *ar = arvif->ar; 87 : 0 : void *ie; 88 : 0 : size_t len; 89 : : 90 : 0 : lockdep_assert_held(&ar->data_lock); 91 : : 92 : 0 : ath10k_p2p_noa_ie_assign(arvif, NULL, 0); 93 : : 94 [ # # ]: 0 : len = ath10k_p2p_noa_ie_len_compute(noa); 95 : 0 : if (!len) 96 : : return; 97 : : 98 [ # # ]: 0 : ie = kmalloc(len, GFP_ATOMIC); 99 [ # # ]: 0 : if (!ie) 100 : : return; 101 : : 102 : 0 : ath10k_p2p_noa_ie_fill(ie, len, noa); 103 : 0 : ath10k_p2p_noa_ie_assign(arvif, ie, len); 104 : : } 105 : : 106 : 0 : void ath10k_p2p_noa_update(struct ath10k_vif *arvif, 107 : : const struct wmi_p2p_noa_info *noa) 108 : : { 109 : 0 : struct ath10k *ar = arvif->ar; 110 : : 111 : 0 : spin_lock_bh(&ar->data_lock); 112 : 0 : __ath10k_p2p_noa_update(arvif, noa); 113 : 0 : spin_unlock_bh(&ar->data_lock); 114 : 0 : } 115 : : 116 : : struct ath10k_p2p_noa_arg { 117 : : u32 vdev_id; 118 : : const struct wmi_p2p_noa_info *noa; 119 : : }; 120 : : 121 : 0 : static void ath10k_p2p_noa_update_vdev_iter(void *data, u8 *mac, 122 : : struct ieee80211_vif *vif) 123 : : { 124 : 0 : struct ath10k_vif *arvif = (void *)vif->drv_priv; 125 : 0 : struct ath10k_p2p_noa_arg *arg = data; 126 : : 127 [ # # ]: 0 : if (arvif->vdev_id != arg->vdev_id) 128 : : return; 129 : : 130 : 0 : ath10k_p2p_noa_update(arvif, arg->noa); 131 : : } 132 : : 133 : 0 : void ath10k_p2p_noa_update_by_vdev_id(struct ath10k *ar, u32 vdev_id, 134 : : const struct wmi_p2p_noa_info *noa) 135 : : { 136 : 0 : struct ath10k_p2p_noa_arg arg = { 137 : : .vdev_id = vdev_id, 138 : : .noa = noa, 139 : : }; 140 : : 141 : 0 : ieee80211_iterate_active_interfaces_atomic(ar->hw, 142 : : IEEE80211_IFACE_ITER_NORMAL, 143 : : ath10k_p2p_noa_update_vdev_iter, 144 : : &arg); 145 : 0 : }