|
48 | 48 |
|
49 | 49 | #define BRCMF_SCB_TIMEOUT_VALUE 20 |
50 | 50 |
|
| 51 | +#define P2P_VER 9 /* P2P version: 9=WiFi P2P v1.0 */ |
| 52 | +#define P2P_PUB_AF_CATEGORY 0x04 |
| 53 | +#define P2P_PUB_AF_ACTION 0x09 |
| 54 | +#define P2P_AF_CATEGORY 0x7f |
| 55 | +#define P2P_OUI "\x50\x6F\x9A" /* P2P OUI */ |
| 56 | +#define P2P_OUI_LEN 3 /* P2P OUI length */ |
| 57 | + |
| 58 | +/* WiFi P2P Public Action Frame OUI Subtypes */ |
| 59 | +#define P2P_PAF_GON_REQ 0 /* Group Owner Negotiation Req */ |
| 60 | +#define P2P_PAF_GON_RSP 1 /* Group Owner Negotiation Rsp */ |
| 61 | +#define P2P_PAF_GON_CONF 2 /* Group Owner Negotiation Confirm */ |
| 62 | +#define P2P_PAF_INVITE_REQ 3 /* P2P Invitation Request */ |
| 63 | +#define P2P_PAF_INVITE_RSP 4 /* P2P Invitation Response */ |
| 64 | +#define P2P_PAF_DEVDIS_REQ 5 /* Device Discoverability Request */ |
| 65 | +#define P2P_PAF_DEVDIS_RSP 6 /* Device Discoverability Response */ |
| 66 | +#define P2P_PAF_PROVDIS_REQ 7 /* Provision Discovery Request */ |
| 67 | +#define P2P_PAF_PROVDIS_RSP 8 /* Provision Discovery Response */ |
| 68 | +#define P2P_PAF_SUBTYPE_INVALID 255 /* Invalid Subtype */ |
| 69 | + |
| 70 | +/* WiFi P2P Action Frame OUI Subtypes */ |
| 71 | +#define P2P_AF_NOTICE_OF_ABSENCE 0 /* Notice of Absence */ |
| 72 | +#define P2P_AF_PRESENCE_REQ 1 /* P2P Presence Request */ |
| 73 | +#define P2P_AF_PRESENCE_RSP 2 /* P2P Presence Response */ |
| 74 | +#define P2P_AF_GO_DISC_REQ 3 /* GO Discoverability Request */ |
| 75 | + |
| 76 | +/* P2P Service Discovery related */ |
| 77 | +#define P2PSD_ACTION_CATEGORY 0x04 /* Public action frame */ |
| 78 | +#define P2PSD_ACTION_ID_GAS_IREQ 0x0a /* GAS Initial Request AF */ |
| 79 | +#define P2PSD_ACTION_ID_GAS_IRESP 0x0b /* GAS Initial Response AF */ |
| 80 | +#define P2PSD_ACTION_ID_GAS_CREQ 0x0c /* GAS Comback Request AF */ |
| 81 | +#define P2PSD_ACTION_ID_GAS_CRESP 0x0d /* GAS Comback Response AF */ |
| 82 | + |
51 | 83 | /** |
52 | 84 | * struct brcmf_p2p_disc_st_le - set discovery state in firmware. |
53 | 85 | * |
@@ -91,6 +123,261 @@ struct brcmf_p2p_scan_le { |
91 | 123 | }; |
92 | 124 | }; |
93 | 125 |
|
| 126 | +/** |
| 127 | + * struct brcmf_p2p_pub_act_frame - WiFi P2P Public Action Frame |
| 128 | + * |
| 129 | + * @category: P2P_PUB_AF_CATEGORY |
| 130 | + * @action: P2P_PUB_AF_ACTION |
| 131 | + * @oui[3]: P2P_OUI |
| 132 | + * @oui_type: OUI type - P2P_VER |
| 133 | + * @subtype: OUI subtype - P2P_TYPE_* |
| 134 | + * @dialog_token: nonzero, identifies req/rsp transaction |
| 135 | + * @elts[1]: Variable length information elements. |
| 136 | + */ |
| 137 | +struct brcmf_p2p_pub_act_frame { |
| 138 | + u8 category; |
| 139 | + u8 action; |
| 140 | + u8 oui[3]; |
| 141 | + u8 oui_type; |
| 142 | + u8 subtype; |
| 143 | + u8 dialog_token; |
| 144 | + u8 elts[1]; |
| 145 | +}; |
| 146 | + |
| 147 | +/** |
| 148 | + * struct brcmf_p2p_action_frame - WiFi P2P Action Frame |
| 149 | + * |
| 150 | + * @category: P2P_AF_CATEGORY |
| 151 | + * @OUI[3]: OUI - P2P_OUI |
| 152 | + * @type: OUI Type - P2P_VER |
| 153 | + * @subtype: OUI Subtype - P2P_AF_* |
| 154 | + * @dialog_token: nonzero, identifies req/resp tranaction |
| 155 | + * @elts[1]: Variable length information elements. |
| 156 | + */ |
| 157 | +struct brcmf_p2p_action_frame { |
| 158 | + u8 category; |
| 159 | + u8 oui[3]; |
| 160 | + u8 type; |
| 161 | + u8 subtype; |
| 162 | + u8 dialog_token; |
| 163 | + u8 elts[1]; |
| 164 | +}; |
| 165 | + |
| 166 | +/** |
| 167 | + * struct brcmf_p2psd_gas_pub_act_frame - Wi-Fi GAS Public Action Frame |
| 168 | + * |
| 169 | + * @category: 0x04 Public Action Frame |
| 170 | + * @action: 0x6c Advertisement Protocol |
| 171 | + * @dialog_token: nonzero, identifies req/rsp transaction |
| 172 | + * @query_data[1]: Query Data. SD gas ireq SD gas iresp |
| 173 | + */ |
| 174 | +struct brcmf_p2psd_gas_pub_act_frame { |
| 175 | + u8 category; |
| 176 | + u8 action; |
| 177 | + u8 dialog_token; |
| 178 | + u8 query_data[1]; |
| 179 | +}; |
| 180 | + |
| 181 | + |
| 182 | +/** |
| 183 | + * brcmf_p2p_is_pub_action() - true if p2p public type frame. |
| 184 | + * |
| 185 | + * @frame: action frame data. |
| 186 | + * @frame_len: length of action frame data. |
| 187 | + * |
| 188 | + * Determine if action frame is p2p public action type |
| 189 | + */ |
| 190 | +static bool brcmf_p2p_is_pub_action(void *frame, u32 frame_len) |
| 191 | +{ |
| 192 | + struct brcmf_p2p_pub_act_frame *pact_frm; |
| 193 | + |
| 194 | + if (frame == NULL) |
| 195 | + return false; |
| 196 | + |
| 197 | + pact_frm = (struct brcmf_p2p_pub_act_frame *)frame; |
| 198 | + if (frame_len < sizeof(struct brcmf_p2p_pub_act_frame) - 1) |
| 199 | + return false; |
| 200 | + |
| 201 | + if (pact_frm->category == P2P_PUB_AF_CATEGORY && |
| 202 | + pact_frm->action == P2P_PUB_AF_ACTION && |
| 203 | + pact_frm->oui_type == P2P_VER && |
| 204 | + memcmp(pact_frm->oui, P2P_OUI, P2P_OUI_LEN) == 0) |
| 205 | + return true; |
| 206 | + |
| 207 | + return false; |
| 208 | +} |
| 209 | + |
| 210 | +/** |
| 211 | + * brcmf_p2p_is_p2p_action() - true if p2p action type frame. |
| 212 | + * |
| 213 | + * @frame: action frame data. |
| 214 | + * @frame_len: length of action frame data. |
| 215 | + * |
| 216 | + * Determine if action frame is p2p action type |
| 217 | + */ |
| 218 | +static bool brcmf_p2p_is_p2p_action(void *frame, u32 frame_len) |
| 219 | +{ |
| 220 | + struct brcmf_p2p_action_frame *act_frm; |
| 221 | + |
| 222 | + if (frame == NULL) |
| 223 | + return false; |
| 224 | + |
| 225 | + act_frm = (struct brcmf_p2p_action_frame *)frame; |
| 226 | + if (frame_len < sizeof(struct brcmf_p2p_action_frame) - 1) |
| 227 | + return false; |
| 228 | + |
| 229 | + if (act_frm->category == P2P_AF_CATEGORY && |
| 230 | + act_frm->type == P2P_VER && |
| 231 | + memcmp(act_frm->oui, P2P_OUI, P2P_OUI_LEN) == 0) |
| 232 | + return true; |
| 233 | + |
| 234 | + return false; |
| 235 | +} |
| 236 | + |
| 237 | +/** |
| 238 | + * brcmf_p2p_is_gas_action() - true if p2p gas action type frame. |
| 239 | + * |
| 240 | + * @frame: action frame data. |
| 241 | + * @frame_len: length of action frame data. |
| 242 | + * |
| 243 | + * Determine if action frame is p2p gas action type |
| 244 | + */ |
| 245 | +static bool brcmf_p2p_is_gas_action(void *frame, u32 frame_len) |
| 246 | +{ |
| 247 | + struct brcmf_p2psd_gas_pub_act_frame *sd_act_frm; |
| 248 | + |
| 249 | + if (frame == NULL) |
| 250 | + return false; |
| 251 | + |
| 252 | + sd_act_frm = (struct brcmf_p2psd_gas_pub_act_frame *)frame; |
| 253 | + if (frame_len < sizeof(struct brcmf_p2psd_gas_pub_act_frame) - 1) |
| 254 | + return false; |
| 255 | + |
| 256 | + if (sd_act_frm->category != P2PSD_ACTION_CATEGORY) |
| 257 | + return false; |
| 258 | + |
| 259 | + if (sd_act_frm->action == P2PSD_ACTION_ID_GAS_IREQ || |
| 260 | + sd_act_frm->action == P2PSD_ACTION_ID_GAS_IRESP || |
| 261 | + sd_act_frm->action == P2PSD_ACTION_ID_GAS_CREQ || |
| 262 | + sd_act_frm->action == P2PSD_ACTION_ID_GAS_CRESP) |
| 263 | + return true; |
| 264 | + |
| 265 | + return false; |
| 266 | +} |
| 267 | + |
| 268 | +/** |
| 269 | + * brcmf_p2p_print_actframe() - debug print routine. |
| 270 | + * |
| 271 | + * @tx: Received or to be transmitted |
| 272 | + * @frame: action frame data. |
| 273 | + * @frame_len: length of action frame data. |
| 274 | + * |
| 275 | + * Print information about the p2p action frame |
| 276 | + */ |
| 277 | +static void brcmf_p2p_print_actframe(bool tx, void *frame, u32 frame_len) |
| 278 | +{ |
| 279 | + struct brcmf_p2p_pub_act_frame *pact_frm; |
| 280 | + struct brcmf_p2p_action_frame *act_frm; |
| 281 | + struct brcmf_p2psd_gas_pub_act_frame *sd_act_frm; |
| 282 | + |
| 283 | + if (!frame || frame_len <= 2) |
| 284 | + return; |
| 285 | + |
| 286 | + if (brcmf_p2p_is_pub_action(frame, frame_len)) { |
| 287 | + pact_frm = (struct brcmf_p2p_pub_act_frame *)frame; |
| 288 | + switch (pact_frm->subtype) { |
| 289 | + case P2P_PAF_GON_REQ: |
| 290 | + brcmf_dbg(TRACE, "%s P2P Group Owner Negotiation Req Frame\n", |
| 291 | + (tx) ? "TX" : "RX"); |
| 292 | + break; |
| 293 | + case P2P_PAF_GON_RSP: |
| 294 | + brcmf_dbg(TRACE, "%s P2P Group Owner Negotiation Rsp Frame\n", |
| 295 | + (tx) ? "TX" : "RX"); |
| 296 | + break; |
| 297 | + case P2P_PAF_GON_CONF: |
| 298 | + brcmf_dbg(TRACE, "%s P2P Group Owner Negotiation Confirm Frame\n", |
| 299 | + (tx) ? "TX" : "RX"); |
| 300 | + break; |
| 301 | + case P2P_PAF_INVITE_REQ: |
| 302 | + brcmf_dbg(TRACE, "%s P2P Invitation Request Frame\n", |
| 303 | + (tx) ? "TX" : "RX"); |
| 304 | + break; |
| 305 | + case P2P_PAF_INVITE_RSP: |
| 306 | + brcmf_dbg(TRACE, "%s P2P Invitation Response Frame\n", |
| 307 | + (tx) ? "TX" : "RX"); |
| 308 | + break; |
| 309 | + case P2P_PAF_DEVDIS_REQ: |
| 310 | + brcmf_dbg(TRACE, "%s P2P Device Discoverability Request Frame\n", |
| 311 | + (tx) ? "TX" : "RX"); |
| 312 | + break; |
| 313 | + case P2P_PAF_DEVDIS_RSP: |
| 314 | + brcmf_dbg(TRACE, "%s P2P Device Discoverability Response Frame\n", |
| 315 | + (tx) ? "TX" : "RX"); |
| 316 | + break; |
| 317 | + case P2P_PAF_PROVDIS_REQ: |
| 318 | + brcmf_dbg(TRACE, "%s P2P Provision Discovery Request Frame\n", |
| 319 | + (tx) ? "TX" : "RX"); |
| 320 | + break; |
| 321 | + case P2P_PAF_PROVDIS_RSP: |
| 322 | + brcmf_dbg(TRACE, "%s P2P Provision Discovery Response Frame\n", |
| 323 | + (tx) ? "TX" : "RX"); |
| 324 | + break; |
| 325 | + default: |
| 326 | + brcmf_dbg(TRACE, "%s Unknown P2P Public Action Frame\n", |
| 327 | + (tx) ? "TX" : "RX"); |
| 328 | + break; |
| 329 | + } |
| 330 | + } else if (brcmf_p2p_is_p2p_action(frame, frame_len)) { |
| 331 | + act_frm = (struct brcmf_p2p_action_frame *)frame; |
| 332 | + switch (act_frm->subtype) { |
| 333 | + case P2P_AF_NOTICE_OF_ABSENCE: |
| 334 | + brcmf_dbg(TRACE, "%s P2P Notice of Absence Frame\n", |
| 335 | + (tx) ? "TX" : "RX"); |
| 336 | + break; |
| 337 | + case P2P_AF_PRESENCE_REQ: |
| 338 | + brcmf_dbg(TRACE, "%s P2P Presence Request Frame\n", |
| 339 | + (tx) ? "TX" : "RX"); |
| 340 | + break; |
| 341 | + case P2P_AF_PRESENCE_RSP: |
| 342 | + brcmf_dbg(TRACE, "%s P2P Presence Response Frame\n", |
| 343 | + (tx) ? "TX" : "RX"); |
| 344 | + break; |
| 345 | + case P2P_AF_GO_DISC_REQ: |
| 346 | + brcmf_dbg(TRACE, "%s P2P Discoverability Request Frame\n", |
| 347 | + (tx) ? "TX" : "RX"); |
| 348 | + break; |
| 349 | + default: |
| 350 | + brcmf_dbg(TRACE, "%s Unknown P2P Action Frame\n", |
| 351 | + (tx) ? "TX" : "RX"); |
| 352 | + } |
| 353 | + |
| 354 | + } else if (brcmf_p2p_is_gas_action(frame, frame_len)) { |
| 355 | + sd_act_frm = (struct brcmf_p2psd_gas_pub_act_frame *)frame; |
| 356 | + switch (sd_act_frm->action) { |
| 357 | + case P2PSD_ACTION_ID_GAS_IREQ: |
| 358 | + brcmf_dbg(TRACE, "%s P2P GAS Initial Request\n", |
| 359 | + (tx) ? "TX" : "RX"); |
| 360 | + break; |
| 361 | + case P2PSD_ACTION_ID_GAS_IRESP: |
| 362 | + brcmf_dbg(TRACE, "%s P2P GAS Initial Response\n", |
| 363 | + (tx) ? "TX" : "RX"); |
| 364 | + break; |
| 365 | + case P2PSD_ACTION_ID_GAS_CREQ: |
| 366 | + brcmf_dbg(TRACE, "%s P2P GAS Comback Request\n", |
| 367 | + (tx) ? "TX" : "RX"); |
| 368 | + break; |
| 369 | + case P2PSD_ACTION_ID_GAS_CRESP: |
| 370 | + brcmf_dbg(TRACE, "%s P2P GAS Comback Response\n", |
| 371 | + (tx) ? "TX" : "RX"); |
| 372 | + break; |
| 373 | + default: |
| 374 | + brcmf_dbg(TRACE, "%s Unknown P2P GAS Frame\n", |
| 375 | + (tx) ? "TX" : "RX"); |
| 376 | + break; |
| 377 | + } |
| 378 | + } |
| 379 | +} |
| 380 | + |
94 | 381 | /** |
95 | 382 | * brcmf_p2p_set_firmware() - prepare firmware for peer-to-peer operation. |
96 | 383 | * |
@@ -686,6 +973,64 @@ void brcmf_p2p_cancel_remain_on_channel(struct brcmf_if *ifp) |
686 | 973 | } |
687 | 974 |
|
688 | 975 |
|
| 976 | +/** |
| 977 | + * brcmf_p2p_notify_action_frame_rx() - received action frame. |
| 978 | + * |
| 979 | + * @ifp: interfac control. |
| 980 | + * @e: event message. Not used, to make it usable for fweh event dispatcher. |
| 981 | + * @data: payload of message, containing action frame data. |
| 982 | + * |
| 983 | + */ |
| 984 | +int brcmf_p2p_notify_action_frame_rx(struct brcmf_if *ifp, |
| 985 | + const struct brcmf_event_msg *e, |
| 986 | + void *data) |
| 987 | +{ |
| 988 | + struct wireless_dev *wdev; |
| 989 | + u32 mgmt_frame_len = e->datalen - sizeof(struct brcmf_rx_mgmt_data); |
| 990 | + struct brcmf_rx_mgmt_data *rxframe = (struct brcmf_rx_mgmt_data *)data; |
| 991 | + u16 chanspec = be16_to_cpu(rxframe->chanspec); |
| 992 | + struct ieee80211_mgmt *mgmt_frame; |
| 993 | + s32 err; |
| 994 | + s32 freq; |
| 995 | + u16 mgmt_type; |
| 996 | + |
| 997 | + /* Check if wpa_supplicant has registered for this frame */ |
| 998 | + brcmf_dbg(INFO, "ifp->vif->mgmt_rx_reg %04x\n", ifp->vif->mgmt_rx_reg); |
| 999 | + mgmt_type = (IEEE80211_STYPE_ACTION & IEEE80211_FCTL_STYPE) >> 4; |
| 1000 | + if ((ifp->vif->mgmt_rx_reg & BIT(mgmt_type)) == 0) |
| 1001 | + return 0; |
| 1002 | + |
| 1003 | + brcmf_p2p_print_actframe(false, (u8 *)(rxframe + 1), mgmt_frame_len); |
| 1004 | + |
| 1005 | + mgmt_frame = kzalloc(offsetof(struct ieee80211_mgmt, u) + |
| 1006 | + mgmt_frame_len, GFP_KERNEL); |
| 1007 | + if (!mgmt_frame) { |
| 1008 | + brcmf_err("No memory available for action frame\n"); |
| 1009 | + return -ENOMEM; |
| 1010 | + } |
| 1011 | + memcpy(mgmt_frame->da, ifp->mac_addr, ETH_ALEN); |
| 1012 | + err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSSID, mgmt_frame->bssid, |
| 1013 | + ETH_ALEN); |
| 1014 | + if (err < 0) |
| 1015 | + brcmf_err("BRCMF_C_GET_BSSID error %d\n", err); |
| 1016 | + memcpy(mgmt_frame->sa, e->addr, ETH_ALEN); |
| 1017 | + mgmt_frame->frame_control = cpu_to_le16(IEEE80211_STYPE_ACTION); |
| 1018 | + memcpy(&mgmt_frame->u, (u8 *)(rxframe + 1), mgmt_frame_len); |
| 1019 | + mgmt_frame_len += offsetof(struct ieee80211_mgmt, u); |
| 1020 | + |
| 1021 | + freq = ieee80211_channel_to_frequency(CHSPEC_CHANNEL(chanspec), |
| 1022 | + CHSPEC_IS2G(chanspec) ? |
| 1023 | + IEEE80211_BAND_2GHZ : |
| 1024 | + IEEE80211_BAND_5GHZ); |
| 1025 | + wdev = ifp->ndev->ieee80211_ptr; |
| 1026 | + cfg80211_rx_mgmt(wdev, freq, 0, (u8 *)mgmt_frame, mgmt_frame_len, |
| 1027 | + GFP_ATOMIC); |
| 1028 | + |
| 1029 | + kfree(mgmt_frame); |
| 1030 | + return 0; |
| 1031 | +} |
| 1032 | + |
| 1033 | + |
689 | 1034 | /** |
690 | 1035 | * brcmf_p2p_attach() - attach for P2P. |
691 | 1036 | * |
|
0 commit comments