diff options
author | John W. Linville <linville@tuxdriver.com> | 2013-02-18 13:47:13 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2013-02-18 13:47:13 -0500 |
commit | 98d5fac2330779e6eea6431a90b44c7476260dcc (patch) | |
tree | 99870656d835fc6c12093bc67517956cc7b3d6ec /drivers/net/wireless/brcm80211 | |
parent | 4153577a8d318ae02b3791341e10e78416de402f (diff) | |
parent | 9e97d14b4923da524d202f2e005d5d30b70db9d6 (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next into for-davem
Conflicts:
drivers/net/wireless/iwlwifi/dvm/tx.c
drivers/net/wireless/ti/wlcore/sdio.c
drivers/net/wireless/ti/wlcore/spi.c
Diffstat (limited to 'drivers/net/wireless/brcm80211')
17 files changed, 3940 insertions, 594 deletions
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/Makefile b/drivers/net/wireless/brcm80211/brcmfmac/Makefile index 1a6661a9f008..756e19fc2795 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/Makefile +++ b/drivers/net/wireless/brcm80211/brcmfmac/Makefile | |||
@@ -26,6 +26,7 @@ brcmfmac-objs += \ | |||
26 | wl_cfg80211.o \ | 26 | wl_cfg80211.o \ |
27 | fwil.o \ | 27 | fwil.o \ |
28 | fweh.o \ | 28 | fweh.o \ |
29 | p2p.o \ | ||
29 | dhd_cdc.o \ | 30 | dhd_cdc.o \ |
30 | dhd_common.o \ | 31 | dhd_common.o \ |
31 | dhd_linux.o | 32 | dhd_linux.o |
@@ -37,4 +38,4 @@ brcmfmac-$(CONFIG_BRCMFMAC_SDIO) += \ | |||
37 | brcmfmac-$(CONFIG_BRCMFMAC_USB) += \ | 38 | brcmfmac-$(CONFIG_BRCMFMAC_USB) += \ |
38 | usb.o | 39 | usb.o |
39 | brcmfmac-$(CONFIG_BRCMDBG) += \ | 40 | brcmfmac-$(CONFIG_BRCMDBG) += \ |
40 | dhd_dbg.o \ No newline at end of file | 41 | dhd_dbg.o |
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h index a2f32fb990fa..ef6f23be6d32 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h | |||
@@ -72,6 +72,7 @@ | |||
72 | #define BRCMF_C_SET_WSEC 134 | 72 | #define BRCMF_C_SET_WSEC 134 |
73 | #define BRCMF_C_GET_PHY_NOISE 135 | 73 | #define BRCMF_C_GET_PHY_NOISE 135 |
74 | #define BRCMF_C_GET_BSS_INFO 136 | 74 | #define BRCMF_C_GET_BSS_INFO 136 |
75 | #define BRCMF_C_SET_SCB_TIMEOUT 158 | ||
75 | #define BRCMF_C_GET_PHYLIST 180 | 76 | #define BRCMF_C_GET_PHYLIST 180 |
76 | #define BRCMF_C_SET_SCAN_CHANNEL_TIME 185 | 77 | #define BRCMF_C_SET_SCAN_CHANNEL_TIME 185 |
77 | #define BRCMF_C_SET_SCAN_UNASSOC_TIME 187 | 78 | #define BRCMF_C_SET_SCAN_UNASSOC_TIME 187 |
@@ -149,6 +150,7 @@ | |||
149 | #define BRCMF_E_REASON_MINTXRATE 9 | 150 | #define BRCMF_E_REASON_MINTXRATE 9 |
150 | #define BRCMF_E_REASON_TXFAIL 10 | 151 | #define BRCMF_E_REASON_TXFAIL 10 |
151 | 152 | ||
153 | #define BRCMF_E_REASON_LINK_BSSCFG_DIS 4 | ||
152 | #define BRCMF_E_REASON_FAST_ROAM_FAILED 5 | 154 | #define BRCMF_E_REASON_FAST_ROAM_FAILED 5 |
153 | #define BRCMF_E_REASON_DIRECTED_ROAM 6 | 155 | #define BRCMF_E_REASON_DIRECTED_ROAM 6 |
154 | #define BRCMF_E_REASON_TSPEC_REJECTED 7 | 156 | #define BRCMF_E_REASON_TSPEC_REJECTED 7 |
@@ -375,6 +377,28 @@ struct brcmf_join_params { | |||
375 | struct brcmf_assoc_params_le params_le; | 377 | struct brcmf_assoc_params_le params_le; |
376 | }; | 378 | }; |
377 | 379 | ||
380 | /* scan params for extended join */ | ||
381 | struct brcmf_join_scan_params_le { | ||
382 | u8 scan_type; /* 0 use default, active or passive scan */ | ||
383 | __le32 nprobes; /* -1 use default, nr of probes per channel */ | ||
384 | __le32 active_time; /* -1 use default, dwell time per channel for | ||
385 | * active scanning | ||
386 | */ | ||
387 | __le32 passive_time; /* -1 use default, dwell time per channel | ||
388 | * for passive scanning | ||
389 | */ | ||
390 | __le32 home_time; /* -1 use default, dwell time for the home | ||
391 | * channel between channel scans | ||
392 | */ | ||
393 | }; | ||
394 | |||
395 | /* extended join params */ | ||
396 | struct brcmf_ext_join_params_le { | ||
397 | struct brcmf_ssid_le ssid_le; /* {0, ""}: wildcard scan */ | ||
398 | struct brcmf_join_scan_params_le scan_le; | ||
399 | struct brcmf_assoc_params_le assoc_le; | ||
400 | }; | ||
401 | |||
378 | struct brcmf_wsec_key { | 402 | struct brcmf_wsec_key { |
379 | u32 index; /* key index */ | 403 | u32 index; /* key index */ |
380 | u32 len; /* key length */ | 404 | u32 len; /* key length */ |
@@ -451,6 +475,19 @@ struct brcmf_sta_info_le { | |||
451 | __le32 rx_decrypt_failures; /* # of packet decrypted failed */ | 475 | __le32 rx_decrypt_failures; /* # of packet decrypted failed */ |
452 | }; | 476 | }; |
453 | 477 | ||
478 | /* | ||
479 | * WLC_E_PROBRESP_MSG | ||
480 | * WLC_E_P2P_PROBREQ_MSG | ||
481 | * WLC_E_ACTION_FRAME_RX | ||
482 | */ | ||
483 | struct brcmf_rx_mgmt_data { | ||
484 | __be16 version; | ||
485 | __be16 chanspec; | ||
486 | __be32 rssi; | ||
487 | __be32 mactime; | ||
488 | __be32 rate; | ||
489 | }; | ||
490 | |||
454 | /* Bus independent dongle command */ | 491 | /* Bus independent dongle command */ |
455 | struct brcmf_dcmd { | 492 | struct brcmf_dcmd { |
456 | uint cmd; /* common dongle cmd definition */ | 493 | uint cmd; /* common dongle cmd definition */ |
@@ -489,9 +526,6 @@ struct brcmf_pub { | |||
489 | struct mutex proto_block; | 526 | struct mutex proto_block; |
490 | unsigned char proto_buf[BRCMF_DCMD_MAXLEN]; | 527 | unsigned char proto_buf[BRCMF_DCMD_MAXLEN]; |
491 | 528 | ||
492 | atomic_t pend_8021x_cnt; | ||
493 | wait_queue_head_t pend_8021x_wait; | ||
494 | |||
495 | struct brcmf_fweh_info fweh; | 529 | struct brcmf_fweh_info fweh; |
496 | #ifdef DEBUG | 530 | #ifdef DEBUG |
497 | struct dentry *dbgfs_dir; | 531 | struct dentry *dbgfs_dir; |
@@ -515,9 +549,11 @@ struct brcmf_cfg80211_vif; | |||
515 | * @vif: points to cfg80211 specific interface information. | 549 | * @vif: points to cfg80211 specific interface information. |
516 | * @ndev: associated network device. | 550 | * @ndev: associated network device. |
517 | * @stats: interface specific network statistics. | 551 | * @stats: interface specific network statistics. |
518 | * @idx: interface index in device firmware. | 552 | * @ifidx: interface index in device firmware. |
519 | * @bssidx: index of bss associated with this interface. | 553 | * @bssidx: index of bss associated with this interface. |
520 | * @mac_addr: assigned mac address. | 554 | * @mac_addr: assigned mac address. |
555 | * @pend_8021x_cnt: tracks outstanding number of 802.1x frames. | ||
556 | * @pend_8021x_wait: used for signalling change in count. | ||
521 | */ | 557 | */ |
522 | struct brcmf_if { | 558 | struct brcmf_if { |
523 | struct brcmf_pub *drvr; | 559 | struct brcmf_pub *drvr; |
@@ -526,9 +562,11 @@ struct brcmf_if { | |||
526 | struct net_device_stats stats; | 562 | struct net_device_stats stats; |
527 | struct work_struct setmacaddr_work; | 563 | struct work_struct setmacaddr_work; |
528 | struct work_struct multicast_work; | 564 | struct work_struct multicast_work; |
529 | int idx; | 565 | int ifidx; |
530 | s32 bssidx; | 566 | s32 bssidx; |
531 | u8 mac_addr[ETH_ALEN]; | 567 | u8 mac_addr[ETH_ALEN]; |
568 | atomic_t pend_8021x_cnt; | ||
569 | wait_queue_head_t pend_8021x_wait; | ||
532 | }; | 570 | }; |
533 | 571 | ||
534 | 572 | ||
@@ -547,9 +585,10 @@ extern int brcmf_proto_cdc_set_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd, | |||
547 | extern int brcmf_proto_hdrpull(struct brcmf_pub *drvr, u8 *ifidx, | 585 | extern int brcmf_proto_hdrpull(struct brcmf_pub *drvr, u8 *ifidx, |
548 | struct sk_buff *rxp); | 586 | struct sk_buff *rxp); |
549 | 587 | ||
550 | extern int brcmf_net_attach(struct brcmf_if *ifp); | 588 | extern int brcmf_net_attach(struct brcmf_if *ifp, bool rtnl_locked); |
551 | extern struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, int ifidx, | 589 | extern struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bssidx, |
552 | s32 bssidx, char *name, u8 *mac_addr); | 590 | s32 ifidx, char *name, u8 *mac_addr); |
553 | extern void brcmf_del_if(struct brcmf_pub *drvr, int ifidx); | 591 | extern void brcmf_del_if(struct brcmf_pub *drvr, s32 bssidx); |
592 | extern u32 brcmf_get_chip_info(struct brcmf_if *ifp); | ||
554 | 593 | ||
555 | #endif /* _BRCMF_H_ */ | 594 | #endif /* _BRCMF_H_ */ |
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h index 64c38f4226a3..ad25c3408b59 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h | |||
@@ -24,18 +24,6 @@ enum brcmf_bus_state { | |||
24 | BRCMF_BUS_DATA /* Ready for frame transfers */ | 24 | BRCMF_BUS_DATA /* Ready for frame transfers */ |
25 | }; | 25 | }; |
26 | 26 | ||
27 | struct dngl_stats { | ||
28 | unsigned long rx_packets; /* total packets received */ | ||
29 | unsigned long tx_packets; /* total packets transmitted */ | ||
30 | unsigned long rx_bytes; /* total bytes received */ | ||
31 | unsigned long tx_bytes; /* total bytes transmitted */ | ||
32 | unsigned long rx_errors; /* bad packets received */ | ||
33 | unsigned long tx_errors; /* packet transmit problems */ | ||
34 | unsigned long rx_dropped; /* packets dropped by dongle */ | ||
35 | unsigned long tx_dropped; /* packets dropped by dongle */ | ||
36 | unsigned long multicast; /* multicast packets received */ | ||
37 | }; | ||
38 | |||
39 | struct brcmf_bus_dcmd { | 27 | struct brcmf_bus_dcmd { |
40 | char *name; | 28 | char *name; |
41 | char *param; | 29 | char *param; |
@@ -72,11 +60,12 @@ struct brcmf_bus_ops { | |||
72 | * @drvr: public driver information. | 60 | * @drvr: public driver information. |
73 | * @state: operational state of the bus interface. | 61 | * @state: operational state of the bus interface. |
74 | * @maxctl: maximum size for rxctl request message. | 62 | * @maxctl: maximum size for rxctl request message. |
75 | * @drvr_up: indicates driver up/down status. | ||
76 | * @tx_realloc: number of tx packets realloced for headroom. | 63 | * @tx_realloc: number of tx packets realloced for headroom. |
77 | * @dstats: dongle-based statistical data. | 64 | * @dstats: dongle-based statistical data. |
78 | * @align: alignment requirement for the bus. | 65 | * @align: alignment requirement for the bus. |
79 | * @dcmd_list: bus/device specific dongle initialization commands. | 66 | * @dcmd_list: bus/device specific dongle initialization commands. |
67 | * @chip: device identifier of the dongle chip. | ||
68 | * @chiprev: revision of the dongle chip. | ||
80 | */ | 69 | */ |
81 | struct brcmf_bus { | 70 | struct brcmf_bus { |
82 | union { | 71 | union { |
@@ -87,10 +76,10 @@ struct brcmf_bus { | |||
87 | struct brcmf_pub *drvr; | 76 | struct brcmf_pub *drvr; |
88 | enum brcmf_bus_state state; | 77 | enum brcmf_bus_state state; |
89 | uint maxctl; | 78 | uint maxctl; |
90 | bool drvr_up; | ||
91 | unsigned long tx_realloc; | 79 | unsigned long tx_realloc; |
92 | struct dngl_stats dstats; | ||
93 | u8 align; | 80 | u8 align; |
81 | u32 chip; | ||
82 | u32 chiprev; | ||
94 | struct list_head dcmd_list; | 83 | struct list_head dcmd_list; |
95 | 84 | ||
96 | struct brcmf_bus_ops *ops; | 85 | struct brcmf_bus_ops *ops; |
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c index bb454cdab29d..a2354d951dd7 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c | |||
@@ -303,6 +303,14 @@ int brcmf_proto_hdrpull(struct brcmf_pub *drvr, u8 *ifidx, | |||
303 | brcmf_err("rx data ifnum out of range (%d)\n", *ifidx); | 303 | brcmf_err("rx data ifnum out of range (%d)\n", *ifidx); |
304 | return -EBADE; | 304 | return -EBADE; |
305 | } | 305 | } |
306 | /* The ifidx is the idx to map to matching netdev/ifp. When receiving | ||
307 | * events this is easy because it contains the bssidx which maps | ||
308 | * 1-on-1 to the netdev/ifp. But for data frames the ifidx is rcvd. | ||
309 | * bssidx 1 is used for p2p0 and no data can be received or | ||
310 | * transmitted on it. Therefor bssidx is ifidx + 1 if ifidx > 0 | ||
311 | */ | ||
312 | if (*ifidx) | ||
313 | (*ifidx)++; | ||
306 | 314 | ||
307 | if (((h->flags & BDC_FLAG_VER_MASK) >> BDC_FLAG_VER_SHIFT) != | 315 | if (((h->flags & BDC_FLAG_VER_MASK) >> BDC_FLAG_VER_SHIFT) != |
308 | BDC_PROTO_VER) { | 316 | BDC_PROTO_VER) { |
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c index 14b8fdde6954..c06cea88df0d 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c | |||
@@ -26,6 +26,8 @@ | |||
26 | #include "dhd_bus.h" | 26 | #include "dhd_bus.h" |
27 | #include "dhd_proto.h" | 27 | #include "dhd_proto.h" |
28 | #include "dhd_dbg.h" | 28 | #include "dhd_dbg.h" |
29 | #include "fwil_types.h" | ||
30 | #include "p2p.h" | ||
29 | #include "wl_cfg80211.h" | 31 | #include "wl_cfg80211.h" |
30 | #include "fwil.h" | 32 | #include "fwil.h" |
31 | 33 | ||
@@ -40,6 +42,12 @@ MODULE_LICENSE("Dual BSD/GPL"); | |||
40 | int brcmf_msg_level; | 42 | int brcmf_msg_level; |
41 | module_param(brcmf_msg_level, int, 0); | 43 | module_param(brcmf_msg_level, int, 0); |
42 | 44 | ||
45 | /* P2P0 enable */ | ||
46 | static int brcmf_p2p_enable; | ||
47 | #ifdef CONFIG_BRCMDBG | ||
48 | module_param_named(p2pon, brcmf_p2p_enable, int, 0); | ||
49 | MODULE_PARM_DESC(p2pon, "enable p2p management functionality"); | ||
50 | #endif | ||
43 | 51 | ||
44 | char *brcmf_ifname(struct brcmf_pub *drvr, int ifidx) | 52 | char *brcmf_ifname(struct brcmf_pub *drvr, int ifidx) |
45 | { | 53 | { |
@@ -70,9 +78,10 @@ static void _brcmf_set_multicast_list(struct work_struct *work) | |||
70 | u32 buflen; | 78 | u32 buflen; |
71 | s32 err; | 79 | s32 err; |
72 | 80 | ||
73 | brcmf_dbg(TRACE, "enter\n"); | ||
74 | |||
75 | ifp = container_of(work, struct brcmf_if, multicast_work); | 81 | ifp = container_of(work, struct brcmf_if, multicast_work); |
82 | |||
83 | brcmf_dbg(TRACE, "Enter, idx=%d\n", ifp->bssidx); | ||
84 | |||
76 | ndev = ifp->ndev; | 85 | ndev = ifp->ndev; |
77 | 86 | ||
78 | /* Determine initial value of allmulti flag */ | 87 | /* Determine initial value of allmulti flag */ |
@@ -129,9 +138,10 @@ _brcmf_set_mac_address(struct work_struct *work) | |||
129 | struct brcmf_if *ifp; | 138 | struct brcmf_if *ifp; |
130 | s32 err; | 139 | s32 err; |
131 | 140 | ||
132 | brcmf_dbg(TRACE, "enter\n"); | ||
133 | |||
134 | ifp = container_of(work, struct brcmf_if, setmacaddr_work); | 141 | ifp = container_of(work, struct brcmf_if, setmacaddr_work); |
142 | |||
143 | brcmf_dbg(TRACE, "Enter, idx=%d\n", ifp->bssidx); | ||
144 | |||
135 | err = brcmf_fil_iovar_data_set(ifp, "cur_etheraddr", ifp->mac_addr, | 145 | err = brcmf_fil_iovar_data_set(ifp, "cur_etheraddr", ifp->mac_addr, |
136 | ETH_ALEN); | 146 | ETH_ALEN); |
137 | if (err < 0) { | 147 | if (err < 0) { |
@@ -168,7 +178,7 @@ static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb, | |||
168 | struct brcmf_pub *drvr = ifp->drvr; | 178 | struct brcmf_pub *drvr = ifp->drvr; |
169 | struct ethhdr *eh; | 179 | struct ethhdr *eh; |
170 | 180 | ||
171 | brcmf_dbg(TRACE, "Enter\n"); | 181 | brcmf_dbg(TRACE, "Enter, idx=%d\n", ifp->bssidx); |
172 | 182 | ||
173 | /* Can the device send data? */ | 183 | /* Can the device send data? */ |
174 | if (drvr->bus_if->state != BRCMF_BUS_DATA) { | 184 | if (drvr->bus_if->state != BRCMF_BUS_DATA) { |
@@ -179,8 +189,8 @@ static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb, | |||
179 | goto done; | 189 | goto done; |
180 | } | 190 | } |
181 | 191 | ||
182 | if (!drvr->iflist[ifp->idx]) { | 192 | if (!drvr->iflist[ifp->bssidx]) { |
183 | brcmf_err("bad ifidx %d\n", ifp->idx); | 193 | brcmf_err("bad ifidx %d\n", ifp->bssidx); |
184 | netif_stop_queue(ndev); | 194 | netif_stop_queue(ndev); |
185 | dev_kfree_skb(skb); | 195 | dev_kfree_skb(skb); |
186 | ret = -ENODEV; | 196 | ret = -ENODEV; |
@@ -192,14 +202,14 @@ static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb, | |||
192 | struct sk_buff *skb2; | 202 | struct sk_buff *skb2; |
193 | 203 | ||
194 | brcmf_dbg(INFO, "%s: insufficient headroom\n", | 204 | brcmf_dbg(INFO, "%s: insufficient headroom\n", |
195 | brcmf_ifname(drvr, ifp->idx)); | 205 | brcmf_ifname(drvr, ifp->bssidx)); |
196 | drvr->bus_if->tx_realloc++; | 206 | drvr->bus_if->tx_realloc++; |
197 | skb2 = skb_realloc_headroom(skb, drvr->hdrlen); | 207 | skb2 = skb_realloc_headroom(skb, drvr->hdrlen); |
198 | dev_kfree_skb(skb); | 208 | dev_kfree_skb(skb); |
199 | skb = skb2; | 209 | skb = skb2; |
200 | if (skb == NULL) { | 210 | if (skb == NULL) { |
201 | brcmf_err("%s: skb_realloc_headroom failed\n", | 211 | brcmf_err("%s: skb_realloc_headroom failed\n", |
202 | brcmf_ifname(drvr, ifp->idx)); | 212 | brcmf_ifname(drvr, ifp->bssidx)); |
203 | ret = -ENOMEM; | 213 | ret = -ENOMEM; |
204 | goto done; | 214 | goto done; |
205 | } | 215 | } |
@@ -217,19 +227,21 @@ static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb, | |||
217 | if (is_multicast_ether_addr(eh->h_dest)) | 227 | if (is_multicast_ether_addr(eh->h_dest)) |
218 | drvr->tx_multicast++; | 228 | drvr->tx_multicast++; |
219 | if (ntohs(eh->h_proto) == ETH_P_PAE) | 229 | if (ntohs(eh->h_proto) == ETH_P_PAE) |
220 | atomic_inc(&drvr->pend_8021x_cnt); | 230 | atomic_inc(&ifp->pend_8021x_cnt); |
221 | 231 | ||
222 | /* If the protocol uses a data header, apply it */ | 232 | /* If the protocol uses a data header, apply it */ |
223 | brcmf_proto_hdrpush(drvr, ifp->idx, skb); | 233 | brcmf_proto_hdrpush(drvr, ifp->ifidx, skb); |
224 | 234 | ||
225 | /* Use bus module to send data frame */ | 235 | /* Use bus module to send data frame */ |
226 | ret = brcmf_bus_txdata(drvr->bus_if, skb); | 236 | ret = brcmf_bus_txdata(drvr->bus_if, skb); |
227 | 237 | ||
228 | done: | 238 | done: |
229 | if (ret) | 239 | if (ret) { |
230 | drvr->bus_if->dstats.tx_dropped++; | 240 | ifp->stats.tx_dropped++; |
231 | else | 241 | } else { |
232 | drvr->bus_if->dstats.tx_packets++; | 242 | ifp->stats.tx_packets++; |
243 | ifp->stats.tx_bytes += skb->len; | ||
244 | } | ||
233 | 245 | ||
234 | /* Return ok: we always eat the packet */ | 246 | /* Return ok: we always eat the packet */ |
235 | return NETDEV_TX_OK; | 247 | return NETDEV_TX_OK; |
@@ -270,12 +282,13 @@ void brcmf_rx_frames(struct device *dev, struct sk_buff_head *skb_list) | |||
270 | skb_queue_walk_safe(skb_list, skb, pnext) { | 282 | skb_queue_walk_safe(skb_list, skb, pnext) { |
271 | skb_unlink(skb, skb_list); | 283 | skb_unlink(skb, skb_list); |
272 | 284 | ||
273 | /* process and remove protocol-specific header | 285 | /* process and remove protocol-specific header */ |
274 | */ | ||
275 | ret = brcmf_proto_hdrpull(drvr, &ifidx, skb); | 286 | ret = brcmf_proto_hdrpull(drvr, &ifidx, skb); |
276 | if (ret < 0) { | 287 | ifp = drvr->iflist[ifidx]; |
277 | if (ret != -ENODATA) | 288 | |
278 | bus_if->dstats.rx_errors++; | 289 | if (ret || !ifp || !ifp->ndev) { |
290 | if ((ret != -ENODATA) && ifp) | ||
291 | ifp->stats.rx_errors++; | ||
279 | brcmu_pkt_buf_free_skb(skb); | 292 | brcmu_pkt_buf_free_skb(skb); |
280 | continue; | 293 | continue; |
281 | } | 294 | } |
@@ -295,21 +308,11 @@ void brcmf_rx_frames(struct device *dev, struct sk_buff_head *skb_list) | |||
295 | eth = skb->data; | 308 | eth = skb->data; |
296 | len = skb->len; | 309 | len = skb->len; |
297 | 310 | ||
298 | ifp = drvr->iflist[ifidx]; | ||
299 | if (ifp == NULL) | ||
300 | ifp = drvr->iflist[0]; | ||
301 | |||
302 | if (!ifp || !ifp->ndev || | ||
303 | ifp->ndev->reg_state != NETREG_REGISTERED) { | ||
304 | brcmu_pkt_buf_free_skb(skb); | ||
305 | continue; | ||
306 | } | ||
307 | |||
308 | skb->dev = ifp->ndev; | 311 | skb->dev = ifp->ndev; |
309 | skb->protocol = eth_type_trans(skb, skb->dev); | 312 | skb->protocol = eth_type_trans(skb, skb->dev); |
310 | 313 | ||
311 | if (skb->pkt_type == PACKET_MULTICAST) | 314 | if (skb->pkt_type == PACKET_MULTICAST) |
312 | bus_if->dstats.multicast++; | 315 | ifp->stats.multicast++; |
313 | 316 | ||
314 | skb->data = eth; | 317 | skb->data = eth; |
315 | skb->len = len; | 318 | skb->len = len; |
@@ -325,8 +328,13 @@ void brcmf_rx_frames(struct device *dev, struct sk_buff_head *skb_list) | |||
325 | ifp->ndev->last_rx = jiffies; | 328 | ifp->ndev->last_rx = jiffies; |
326 | } | 329 | } |
327 | 330 | ||
328 | bus_if->dstats.rx_bytes += skb->len; | 331 | if (!(ifp->ndev->flags & IFF_UP)) { |
329 | bus_if->dstats.rx_packets++; /* Local count */ | 332 | brcmu_pkt_buf_free_skb(skb); |
333 | continue; | ||
334 | } | ||
335 | |||
336 | ifp->stats.rx_bytes += skb->len; | ||
337 | ifp->stats.rx_packets++; | ||
330 | 338 | ||
331 | if (in_interrupt()) | 339 | if (in_interrupt()) |
332 | netif_rx(skb); | 340 | netif_rx(skb); |
@@ -348,36 +356,31 @@ void brcmf_txcomplete(struct device *dev, struct sk_buff *txp, bool success) | |||
348 | u16 type; | 356 | u16 type; |
349 | struct brcmf_bus *bus_if = dev_get_drvdata(dev); | 357 | struct brcmf_bus *bus_if = dev_get_drvdata(dev); |
350 | struct brcmf_pub *drvr = bus_if->drvr; | 358 | struct brcmf_pub *drvr = bus_if->drvr; |
359 | struct brcmf_if *ifp; | ||
351 | 360 | ||
352 | brcmf_proto_hdrpull(drvr, &ifidx, txp); | 361 | brcmf_proto_hdrpull(drvr, &ifidx, txp); |
353 | 362 | ||
363 | ifp = drvr->iflist[ifidx]; | ||
364 | if (!ifp) | ||
365 | return; | ||
366 | |||
354 | eh = (struct ethhdr *)(txp->data); | 367 | eh = (struct ethhdr *)(txp->data); |
355 | type = ntohs(eh->h_proto); | 368 | type = ntohs(eh->h_proto); |
356 | 369 | ||
357 | if (type == ETH_P_PAE) { | 370 | if (type == ETH_P_PAE) { |
358 | atomic_dec(&drvr->pend_8021x_cnt); | 371 | atomic_dec(&ifp->pend_8021x_cnt); |
359 | if (waitqueue_active(&drvr->pend_8021x_wait)) | 372 | if (waitqueue_active(&ifp->pend_8021x_wait)) |
360 | wake_up(&drvr->pend_8021x_wait); | 373 | wake_up(&ifp->pend_8021x_wait); |
361 | } | 374 | } |
375 | if (!success) | ||
376 | ifp->stats.tx_errors++; | ||
362 | } | 377 | } |
363 | 378 | ||
364 | static struct net_device_stats *brcmf_netdev_get_stats(struct net_device *ndev) | 379 | static struct net_device_stats *brcmf_netdev_get_stats(struct net_device *ndev) |
365 | { | 380 | { |
366 | struct brcmf_if *ifp = netdev_priv(ndev); | 381 | struct brcmf_if *ifp = netdev_priv(ndev); |
367 | struct brcmf_bus *bus_if = ifp->drvr->bus_if; | ||
368 | |||
369 | brcmf_dbg(TRACE, "Enter\n"); | ||
370 | 382 | ||
371 | /* Copy dongle stats to net device stats */ | 383 | brcmf_dbg(TRACE, "Enter, idx=%d\n", ifp->bssidx); |
372 | ifp->stats.rx_packets = bus_if->dstats.rx_packets; | ||
373 | ifp->stats.tx_packets = bus_if->dstats.tx_packets; | ||
374 | ifp->stats.rx_bytes = bus_if->dstats.rx_bytes; | ||
375 | ifp->stats.tx_bytes = bus_if->dstats.tx_bytes; | ||
376 | ifp->stats.rx_errors = bus_if->dstats.rx_errors; | ||
377 | ifp->stats.tx_errors = bus_if->dstats.tx_errors; | ||
378 | ifp->stats.rx_dropped = bus_if->dstats.rx_dropped; | ||
379 | ifp->stats.tx_dropped = bus_if->dstats.tx_dropped; | ||
380 | ifp->stats.multicast = bus_if->dstats.multicast; | ||
381 | 384 | ||
382 | return &ifp->stats; | 385 | return &ifp->stats; |
383 | } | 386 | } |
@@ -431,7 +434,7 @@ static int brcmf_ethtool(struct brcmf_if *ifp, void __user *uaddr) | |||
431 | u32 toe_cmpnt, csum_dir; | 434 | u32 toe_cmpnt, csum_dir; |
432 | int ret; | 435 | int ret; |
433 | 436 | ||
434 | brcmf_dbg(TRACE, "Enter\n"); | 437 | brcmf_dbg(TRACE, "Enter, idx=%d\n", ifp->bssidx); |
435 | 438 | ||
436 | /* all ethtool calls start with a cmd word */ | 439 | /* all ethtool calls start with a cmd word */ |
437 | if (copy_from_user(&cmd, uaddr, sizeof(u32))) | 440 | if (copy_from_user(&cmd, uaddr, sizeof(u32))) |
@@ -454,13 +457,7 @@ static int brcmf_ethtool(struct brcmf_if *ifp, void __user *uaddr) | |||
454 | sprintf(info.driver, "dhd"); | 457 | sprintf(info.driver, "dhd"); |
455 | strcpy(info.version, BRCMF_VERSION_STR); | 458 | strcpy(info.version, BRCMF_VERSION_STR); |
456 | } | 459 | } |
457 | 460 | /* report dongle driver type */ | |
458 | /* otherwise, require dongle to be up */ | ||
459 | else if (!drvr->bus_if->drvr_up) { | ||
460 | brcmf_err("dongle is not up\n"); | ||
461 | return -ENODEV; | ||
462 | } | ||
463 | /* finally, report dongle driver type */ | ||
464 | else | 461 | else |
465 | sprintf(info.driver, "wl"); | 462 | sprintf(info.driver, "wl"); |
466 | 463 | ||
@@ -534,9 +531,9 @@ static int brcmf_netdev_ioctl_entry(struct net_device *ndev, struct ifreq *ifr, | |||
534 | struct brcmf_if *ifp = netdev_priv(ndev); | 531 | struct brcmf_if *ifp = netdev_priv(ndev); |
535 | struct brcmf_pub *drvr = ifp->drvr; | 532 | struct brcmf_pub *drvr = ifp->drvr; |
536 | 533 | ||
537 | brcmf_dbg(TRACE, "ifidx %d, cmd 0x%04x\n", ifp->idx, cmd); | 534 | brcmf_dbg(TRACE, "Enter, idx=%d, cmd=0x%04x\n", ifp->bssidx, cmd); |
538 | 535 | ||
539 | if (!drvr->iflist[ifp->idx]) | 536 | if (!drvr->iflist[ifp->bssidx]) |
540 | return -1; | 537 | return -1; |
541 | 538 | ||
542 | if (cmd == SIOCETHTOOL) | 539 | if (cmd == SIOCETHTOOL) |
@@ -548,17 +545,12 @@ static int brcmf_netdev_ioctl_entry(struct net_device *ndev, struct ifreq *ifr, | |||
548 | static int brcmf_netdev_stop(struct net_device *ndev) | 545 | static int brcmf_netdev_stop(struct net_device *ndev) |
549 | { | 546 | { |
550 | struct brcmf_if *ifp = netdev_priv(ndev); | 547 | struct brcmf_if *ifp = netdev_priv(ndev); |
551 | struct brcmf_pub *drvr = ifp->drvr; | ||
552 | |||
553 | brcmf_dbg(TRACE, "Enter\n"); | ||
554 | 548 | ||
555 | if (drvr->bus_if->drvr_up == 0) | 549 | brcmf_dbg(TRACE, "Enter, idx=%d\n", ifp->bssidx); |
556 | return 0; | ||
557 | 550 | ||
558 | brcmf_cfg80211_down(ndev); | 551 | brcmf_cfg80211_down(ndev); |
559 | 552 | ||
560 | /* Set state and stop OS transmissions */ | 553 | /* Set state and stop OS transmissions */ |
561 | drvr->bus_if->drvr_up = false; | ||
562 | netif_stop_queue(ndev); | 554 | netif_stop_queue(ndev); |
563 | 555 | ||
564 | return 0; | 556 | return 0; |
@@ -572,7 +564,7 @@ static int brcmf_netdev_open(struct net_device *ndev) | |||
572 | u32 toe_ol; | 564 | u32 toe_ol; |
573 | s32 ret = 0; | 565 | s32 ret = 0; |
574 | 566 | ||
575 | brcmf_dbg(TRACE, "ifidx %d\n", ifp->idx); | 567 | brcmf_dbg(TRACE, "Enter, idx=%d\n", ifp->bssidx); |
576 | 568 | ||
577 | /* If bus is not ready, can't continue */ | 569 | /* If bus is not ready, can't continue */ |
578 | if (bus_if->state != BRCMF_BUS_DATA) { | 570 | if (bus_if->state != BRCMF_BUS_DATA) { |
@@ -580,9 +572,7 @@ static int brcmf_netdev_open(struct net_device *ndev) | |||
580 | return -EAGAIN; | 572 | return -EAGAIN; |
581 | } | 573 | } |
582 | 574 | ||
583 | atomic_set(&drvr->pend_8021x_cnt, 0); | 575 | atomic_set(&ifp->pend_8021x_cnt, 0); |
584 | |||
585 | memcpy(ndev->dev_addr, drvr->mac, ETH_ALEN); | ||
586 | 576 | ||
587 | /* Get current TOE mode from dongle */ | 577 | /* Get current TOE mode from dongle */ |
588 | if (brcmf_fil_iovar_int_get(ifp, "toe_ol", &toe_ol) >= 0 | 578 | if (brcmf_fil_iovar_int_get(ifp, "toe_ol", &toe_ol) >= 0 |
@@ -593,7 +583,6 @@ static int brcmf_netdev_open(struct net_device *ndev) | |||
593 | 583 | ||
594 | /* Allow transmit calls */ | 584 | /* Allow transmit calls */ |
595 | netif_start_queue(ndev); | 585 | netif_start_queue(ndev); |
596 | drvr->bus_if->drvr_up = true; | ||
597 | if (brcmf_cfg80211_up(ndev)) { | 586 | if (brcmf_cfg80211_up(ndev)) { |
598 | brcmf_err("failed to bring up cfg80211\n"); | 587 | brcmf_err("failed to bring up cfg80211\n"); |
599 | return -1; | 588 | return -1; |
@@ -612,29 +601,18 @@ static const struct net_device_ops brcmf_netdev_ops_pri = { | |||
612 | .ndo_set_rx_mode = brcmf_netdev_set_multicast_list | 601 | .ndo_set_rx_mode = brcmf_netdev_set_multicast_list |
613 | }; | 602 | }; |
614 | 603 | ||
615 | static const struct net_device_ops brcmf_netdev_ops_virt = { | 604 | int brcmf_net_attach(struct brcmf_if *ifp, bool rtnl_locked) |
616 | .ndo_open = brcmf_cfg80211_up, | ||
617 | .ndo_stop = brcmf_cfg80211_down, | ||
618 | .ndo_get_stats = brcmf_netdev_get_stats, | ||
619 | .ndo_do_ioctl = brcmf_netdev_ioctl_entry, | ||
620 | .ndo_start_xmit = brcmf_netdev_start_xmit, | ||
621 | .ndo_set_mac_address = brcmf_netdev_set_mac_address, | ||
622 | .ndo_set_rx_mode = brcmf_netdev_set_multicast_list | ||
623 | }; | ||
624 | |||
625 | int brcmf_net_attach(struct brcmf_if *ifp) | ||
626 | { | 605 | { |
627 | struct brcmf_pub *drvr = ifp->drvr; | 606 | struct brcmf_pub *drvr = ifp->drvr; |
628 | struct net_device *ndev; | 607 | struct net_device *ndev; |
608 | s32 err; | ||
629 | 609 | ||
630 | brcmf_dbg(TRACE, "ifidx %d mac %pM\n", ifp->idx, ifp->mac_addr); | 610 | brcmf_dbg(TRACE, "Enter, idx=%d mac=%pM\n", ifp->bssidx, |
611 | ifp->mac_addr); | ||
631 | ndev = ifp->ndev; | 612 | ndev = ifp->ndev; |
632 | 613 | ||
633 | /* set appropriate operations */ | 614 | /* set appropriate operations */ |
634 | if (!ifp->idx) | 615 | ndev->netdev_ops = &brcmf_netdev_ops_pri; |
635 | ndev->netdev_ops = &brcmf_netdev_ops_pri; | ||
636 | else | ||
637 | ndev->netdev_ops = &brcmf_netdev_ops_virt; | ||
638 | 616 | ||
639 | ndev->hard_header_len = ETH_HLEN + drvr->hdrlen; | 617 | ndev->hard_header_len = ETH_HLEN + drvr->hdrlen; |
640 | ndev->ethtool_ops = &brcmf_ethtool_ops; | 618 | ndev->ethtool_ops = &brcmf_ethtool_ops; |
@@ -645,7 +623,14 @@ int brcmf_net_attach(struct brcmf_if *ifp) | |||
645 | /* set the mac address */ | 623 | /* set the mac address */ |
646 | memcpy(ndev->dev_addr, ifp->mac_addr, ETH_ALEN); | 624 | memcpy(ndev->dev_addr, ifp->mac_addr, ETH_ALEN); |
647 | 625 | ||
648 | if (register_netdev(ndev) != 0) { | 626 | INIT_WORK(&ifp->setmacaddr_work, _brcmf_set_mac_address); |
627 | INIT_WORK(&ifp->multicast_work, _brcmf_set_multicast_list); | ||
628 | |||
629 | if (rtnl_locked) | ||
630 | err = register_netdevice(ndev); | ||
631 | else | ||
632 | err = register_netdev(ndev); | ||
633 | if (err != 0) { | ||
649 | brcmf_err("couldn't register the net device\n"); | 634 | brcmf_err("couldn't register the net device\n"); |
650 | goto fail; | 635 | goto fail; |
651 | } | 636 | } |
@@ -659,16 +644,78 @@ fail: | |||
659 | return -EBADE; | 644 | return -EBADE; |
660 | } | 645 | } |
661 | 646 | ||
662 | struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, int ifidx, s32 bssidx, | 647 | static int brcmf_net_p2p_open(struct net_device *ndev) |
663 | char *name, u8 *addr_mask) | 648 | { |
649 | brcmf_dbg(TRACE, "Enter\n"); | ||
650 | |||
651 | return brcmf_cfg80211_up(ndev); | ||
652 | } | ||
653 | |||
654 | static int brcmf_net_p2p_stop(struct net_device *ndev) | ||
655 | { | ||
656 | brcmf_dbg(TRACE, "Enter\n"); | ||
657 | |||
658 | return brcmf_cfg80211_down(ndev); | ||
659 | } | ||
660 | |||
661 | static int brcmf_net_p2p_do_ioctl(struct net_device *ndev, | ||
662 | struct ifreq *ifr, int cmd) | ||
663 | { | ||
664 | brcmf_dbg(TRACE, "Enter\n"); | ||
665 | return 0; | ||
666 | } | ||
667 | |||
668 | static netdev_tx_t brcmf_net_p2p_start_xmit(struct sk_buff *skb, | ||
669 | struct net_device *ndev) | ||
670 | { | ||
671 | if (skb) | ||
672 | dev_kfree_skb_any(skb); | ||
673 | |||
674 | return NETDEV_TX_OK; | ||
675 | } | ||
676 | |||
677 | static const struct net_device_ops brcmf_netdev_ops_p2p = { | ||
678 | .ndo_open = brcmf_net_p2p_open, | ||
679 | .ndo_stop = brcmf_net_p2p_stop, | ||
680 | .ndo_do_ioctl = brcmf_net_p2p_do_ioctl, | ||
681 | .ndo_start_xmit = brcmf_net_p2p_start_xmit | ||
682 | }; | ||
683 | |||
684 | static int brcmf_net_p2p_attach(struct brcmf_if *ifp) | ||
685 | { | ||
686 | struct net_device *ndev; | ||
687 | |||
688 | brcmf_dbg(TRACE, "Enter, idx=%d mac=%pM\n", ifp->bssidx, | ||
689 | ifp->mac_addr); | ||
690 | ndev = ifp->ndev; | ||
691 | |||
692 | ndev->netdev_ops = &brcmf_netdev_ops_p2p; | ||
693 | |||
694 | /* set the mac address */ | ||
695 | memcpy(ndev->dev_addr, ifp->mac_addr, ETH_ALEN); | ||
696 | |||
697 | if (register_netdev(ndev) != 0) { | ||
698 | brcmf_err("couldn't register the p2p net device\n"); | ||
699 | goto fail; | ||
700 | } | ||
701 | |||
702 | brcmf_dbg(INFO, "%s: Broadcom Dongle Host Driver\n", ndev->name); | ||
703 | |||
704 | return 0; | ||
705 | |||
706 | fail: | ||
707 | return -EBADE; | ||
708 | } | ||
709 | |||
710 | struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bssidx, s32 ifidx, | ||
711 | char *name, u8 *mac_addr) | ||
664 | { | 712 | { |
665 | struct brcmf_if *ifp; | 713 | struct brcmf_if *ifp; |
666 | struct net_device *ndev; | 714 | struct net_device *ndev; |
667 | int i; | ||
668 | 715 | ||
669 | brcmf_dbg(TRACE, "idx %d\n", ifidx); | 716 | brcmf_dbg(TRACE, "Enter, idx=%d, ifidx=%d\n", bssidx, ifidx); |
670 | 717 | ||
671 | ifp = drvr->iflist[ifidx]; | 718 | ifp = drvr->iflist[bssidx]; |
672 | /* | 719 | /* |
673 | * Delete the existing interface before overwriting it | 720 | * Delete the existing interface before overwriting it |
674 | * in case we missed the BRCMF_E_IF_DEL event. | 721 | * in case we missed the BRCMF_E_IF_DEL event. |
@@ -680,7 +727,7 @@ struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, int ifidx, s32 bssidx, | |||
680 | netif_stop_queue(ifp->ndev); | 727 | netif_stop_queue(ifp->ndev); |
681 | unregister_netdev(ifp->ndev); | 728 | unregister_netdev(ifp->ndev); |
682 | free_netdev(ifp->ndev); | 729 | free_netdev(ifp->ndev); |
683 | drvr->iflist[ifidx] = NULL; | 730 | drvr->iflist[bssidx] = NULL; |
684 | } else { | 731 | } else { |
685 | brcmf_err("ignore IF event\n"); | 732 | brcmf_err("ignore IF event\n"); |
686 | return ERR_PTR(-EINVAL); | 733 | return ERR_PTR(-EINVAL); |
@@ -697,16 +744,15 @@ struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, int ifidx, s32 bssidx, | |||
697 | ifp = netdev_priv(ndev); | 744 | ifp = netdev_priv(ndev); |
698 | ifp->ndev = ndev; | 745 | ifp->ndev = ndev; |
699 | ifp->drvr = drvr; | 746 | ifp->drvr = drvr; |
700 | drvr->iflist[ifidx] = ifp; | 747 | drvr->iflist[bssidx] = ifp; |
701 | ifp->idx = ifidx; | 748 | ifp->ifidx = ifidx; |
702 | ifp->bssidx = bssidx; | 749 | ifp->bssidx = bssidx; |
703 | 750 | ||
704 | INIT_WORK(&ifp->setmacaddr_work, _brcmf_set_mac_address); | ||
705 | INIT_WORK(&ifp->multicast_work, _brcmf_set_multicast_list); | ||
706 | 751 | ||
707 | if (addr_mask != NULL) | 752 | init_waitqueue_head(&ifp->pend_8021x_wait); |
708 | for (i = 0; i < ETH_ALEN; i++) | 753 | |
709 | ifp->mac_addr[i] = drvr->mac[i] ^ addr_mask[i]; | 754 | if (mac_addr != NULL) |
755 | memcpy(ifp->mac_addr, mac_addr, ETH_ALEN); | ||
710 | 756 | ||
711 | brcmf_dbg(TRACE, " ==== pid:%x, if:%s (%pM) created ===\n", | 757 | brcmf_dbg(TRACE, " ==== pid:%x, if:%s (%pM) created ===\n", |
712 | current->pid, ifp->ndev->name, ifp->mac_addr); | 758 | current->pid, ifp->ndev->name, ifp->mac_addr); |
@@ -714,19 +760,18 @@ struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, int ifidx, s32 bssidx, | |||
714 | return ifp; | 760 | return ifp; |
715 | } | 761 | } |
716 | 762 | ||
717 | void brcmf_del_if(struct brcmf_pub *drvr, int ifidx) | 763 | void brcmf_del_if(struct brcmf_pub *drvr, s32 bssidx) |
718 | { | 764 | { |
719 | struct brcmf_if *ifp; | 765 | struct brcmf_if *ifp; |
720 | 766 | ||
721 | brcmf_dbg(TRACE, "idx %d\n", ifidx); | 767 | ifp = drvr->iflist[bssidx]; |
722 | |||
723 | ifp = drvr->iflist[ifidx]; | ||
724 | if (!ifp) { | 768 | if (!ifp) { |
725 | brcmf_err("Null interface\n"); | 769 | brcmf_err("Null interface, idx=%d\n", bssidx); |
726 | return; | 770 | return; |
727 | } | 771 | } |
772 | brcmf_dbg(TRACE, "Enter, idx=%d, ifidx=%d\n", bssidx, ifp->ifidx); | ||
728 | if (ifp->ndev) { | 773 | if (ifp->ndev) { |
729 | if (ifidx == 0) { | 774 | if (bssidx == 0) { |
730 | if (ifp->ndev->netdev_ops == &brcmf_netdev_ops_pri) { | 775 | if (ifp->ndev->netdev_ops == &brcmf_netdev_ops_pri) { |
731 | rtnl_lock(); | 776 | rtnl_lock(); |
732 | brcmf_netdev_stop(ifp->ndev); | 777 | brcmf_netdev_stop(ifp->ndev); |
@@ -736,12 +781,14 @@ void brcmf_del_if(struct brcmf_pub *drvr, int ifidx) | |||
736 | netif_stop_queue(ifp->ndev); | 781 | netif_stop_queue(ifp->ndev); |
737 | } | 782 | } |
738 | 783 | ||
739 | cancel_work_sync(&ifp->setmacaddr_work); | 784 | if (ifp->ndev->netdev_ops == &brcmf_netdev_ops_pri) { |
740 | cancel_work_sync(&ifp->multicast_work); | 785 | cancel_work_sync(&ifp->setmacaddr_work); |
786 | cancel_work_sync(&ifp->multicast_work); | ||
787 | } | ||
741 | 788 | ||
742 | unregister_netdev(ifp->ndev); | 789 | unregister_netdev(ifp->ndev); |
743 | drvr->iflist[ifidx] = NULL; | 790 | drvr->iflist[bssidx] = NULL; |
744 | if (ifidx == 0) | 791 | if (bssidx == 0) |
745 | brcmf_cfg80211_detach(drvr->config); | 792 | brcmf_cfg80211_detach(drvr->config); |
746 | free_netdev(ifp->ndev); | 793 | free_netdev(ifp->ndev); |
747 | } | 794 | } |
@@ -781,8 +828,6 @@ int brcmf_attach(uint bus_hdrlen, struct device *dev) | |||
781 | 828 | ||
782 | INIT_LIST_HEAD(&drvr->bus_if->dcmd_list); | 829 | INIT_LIST_HEAD(&drvr->bus_if->dcmd_list); |
783 | 830 | ||
784 | init_waitqueue_head(&drvr->pend_8021x_wait); | ||
785 | |||
786 | return ret; | 831 | return ret; |
787 | 832 | ||
788 | fail: | 833 | fail: |
@@ -797,6 +842,7 @@ int brcmf_bus_start(struct device *dev) | |||
797 | struct brcmf_bus *bus_if = dev_get_drvdata(dev); | 842 | struct brcmf_bus *bus_if = dev_get_drvdata(dev); |
798 | struct brcmf_pub *drvr = bus_if->drvr; | 843 | struct brcmf_pub *drvr = bus_if->drvr; |
799 | struct brcmf_if *ifp; | 844 | struct brcmf_if *ifp; |
845 | struct brcmf_if *p2p_ifp; | ||
800 | 846 | ||
801 | brcmf_dbg(TRACE, "\n"); | 847 | brcmf_dbg(TRACE, "\n"); |
802 | 848 | ||
@@ -812,6 +858,13 @@ int brcmf_bus_start(struct device *dev) | |||
812 | if (IS_ERR(ifp)) | 858 | if (IS_ERR(ifp)) |
813 | return PTR_ERR(ifp); | 859 | return PTR_ERR(ifp); |
814 | 860 | ||
861 | if (brcmf_p2p_enable) | ||
862 | p2p_ifp = brcmf_add_if(drvr, 1, 0, "p2p%d", NULL); | ||
863 | else | ||
864 | p2p_ifp = NULL; | ||
865 | if (IS_ERR(p2p_ifp)) | ||
866 | p2p_ifp = NULL; | ||
867 | |||
815 | /* signal bus ready */ | 868 | /* signal bus ready */ |
816 | bus_if->state = BRCMF_BUS_DATA; | 869 | bus_if->state = BRCMF_BUS_DATA; |
817 | 870 | ||
@@ -830,16 +883,22 @@ int brcmf_bus_start(struct device *dev) | |||
830 | if (ret < 0) | 883 | if (ret < 0) |
831 | goto fail; | 884 | goto fail; |
832 | 885 | ||
833 | ret = brcmf_net_attach(ifp); | 886 | ret = brcmf_net_attach(ifp, false); |
834 | fail: | 887 | fail: |
835 | if (ret < 0) { | 888 | if (ret < 0) { |
836 | brcmf_err("failed: %d\n", ret); | 889 | brcmf_err("failed: %d\n", ret); |
837 | if (drvr->config) | 890 | if (drvr->config) |
838 | brcmf_cfg80211_detach(drvr->config); | 891 | brcmf_cfg80211_detach(drvr->config); |
839 | free_netdev(drvr->iflist[0]->ndev); | 892 | free_netdev(ifp->ndev); |
840 | drvr->iflist[0] = NULL; | 893 | drvr->iflist[0] = NULL; |
894 | if (p2p_ifp) { | ||
895 | free_netdev(p2p_ifp->ndev); | ||
896 | drvr->iflist[1] = NULL; | ||
897 | } | ||
841 | return ret; | 898 | return ret; |
842 | } | 899 | } |
900 | if ((brcmf_p2p_enable) && (p2p_ifp)) | ||
901 | brcmf_net_p2p_attach(p2p_ifp); | ||
843 | 902 | ||
844 | return 0; | 903 | return 0; |
845 | } | 904 | } |
@@ -865,12 +924,13 @@ void brcmf_dev_reset(struct device *dev) | |||
865 | if (drvr == NULL) | 924 | if (drvr == NULL) |
866 | return; | 925 | return; |
867 | 926 | ||
868 | brcmf_fil_cmd_int_set(drvr->iflist[0], BRCMF_C_TERMINATED, 1); | 927 | if (drvr->iflist[0]) |
928 | brcmf_fil_cmd_int_set(drvr->iflist[0], BRCMF_C_TERMINATED, 1); | ||
869 | } | 929 | } |
870 | 930 | ||
871 | void brcmf_detach(struct device *dev) | 931 | void brcmf_detach(struct device *dev) |
872 | { | 932 | { |
873 | int i; | 933 | s32 i; |
874 | struct brcmf_bus *bus_if = dev_get_drvdata(dev); | 934 | struct brcmf_bus *bus_if = dev_get_drvdata(dev); |
875 | struct brcmf_pub *drvr = bus_if->drvr; | 935 | struct brcmf_pub *drvr = bus_if->drvr; |
876 | 936 | ||
@@ -897,19 +957,18 @@ void brcmf_detach(struct device *dev) | |||
897 | kfree(drvr); | 957 | kfree(drvr); |
898 | } | 958 | } |
899 | 959 | ||
900 | static int brcmf_get_pend_8021x_cnt(struct brcmf_pub *drvr) | 960 | static int brcmf_get_pend_8021x_cnt(struct brcmf_if *ifp) |
901 | { | 961 | { |
902 | return atomic_read(&drvr->pend_8021x_cnt); | 962 | return atomic_read(&ifp->pend_8021x_cnt); |
903 | } | 963 | } |
904 | 964 | ||
905 | int brcmf_netdev_wait_pend8021x(struct net_device *ndev) | 965 | int brcmf_netdev_wait_pend8021x(struct net_device *ndev) |
906 | { | 966 | { |
907 | struct brcmf_if *ifp = netdev_priv(ndev); | 967 | struct brcmf_if *ifp = netdev_priv(ndev); |
908 | struct brcmf_pub *drvr = ifp->drvr; | ||
909 | int err; | 968 | int err; |
910 | 969 | ||
911 | err = wait_event_timeout(drvr->pend_8021x_wait, | 970 | err = wait_event_timeout(ifp->pend_8021x_wait, |
912 | !brcmf_get_pend_8021x_cnt(drvr), | 971 | !brcmf_get_pend_8021x_cnt(ifp), |
913 | msecs_to_jiffies(MAX_WAIT_FOR_8021X_TX)); | 972 | msecs_to_jiffies(MAX_WAIT_FOR_8021X_TX)); |
914 | 973 | ||
915 | WARN_ON(!err); | 974 | WARN_ON(!err); |
@@ -917,6 +976,16 @@ int brcmf_netdev_wait_pend8021x(struct net_device *ndev) | |||
917 | return !err; | 976 | return !err; |
918 | } | 977 | } |
919 | 978 | ||
979 | /* | ||
980 | * return chip id and rev of the device encoded in u32. | ||
981 | */ | ||
982 | u32 brcmf_get_chip_info(struct brcmf_if *ifp) | ||
983 | { | ||
984 | struct brcmf_bus *bus = ifp->drvr->bus_if; | ||
985 | |||
986 | return bus->chip << 4 | bus->chiprev; | ||
987 | } | ||
988 | |||
920 | static void brcmf_driver_init(struct work_struct *work) | 989 | static void brcmf_driver_init(struct work_struct *work) |
921 | { | 990 | { |
922 | brcmf_debugfs_init(); | 991 | brcmf_debugfs_init(); |
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c index 6d786a281f1e..4469321c0eb3 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c | |||
@@ -1096,7 +1096,6 @@ static int brcmf_sdio_hdparser(struct brcmf_sdio *bus, u8 *header, | |||
1096 | if (len > MAX_RX_DATASZ && rd->channel != SDPCM_CONTROL_CHANNEL && | 1096 | if (len > MAX_RX_DATASZ && rd->channel != SDPCM_CONTROL_CHANNEL && |
1097 | type != BRCMF_SDIO_FT_SUPER) { | 1097 | type != BRCMF_SDIO_FT_SUPER) { |
1098 | brcmf_err("HW header length too long\n"); | 1098 | brcmf_err("HW header length too long\n"); |
1099 | bus->sdiodev->bus_if->dstats.rx_errors++; | ||
1100 | bus->sdcnt.rx_toolong++; | 1099 | bus->sdcnt.rx_toolong++; |
1101 | brcmf_sdbrcm_rxfail(bus, false, false); | 1100 | brcmf_sdbrcm_rxfail(bus, false, false); |
1102 | rd->len = 0; | 1101 | rd->len = 0; |
@@ -1298,7 +1297,6 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq) | |||
1298 | if (errcode < 0) { | 1297 | if (errcode < 0) { |
1299 | brcmf_err("glom read of %d bytes failed: %d\n", | 1298 | brcmf_err("glom read of %d bytes failed: %d\n", |
1300 | dlen, errcode); | 1299 | dlen, errcode); |
1301 | bus->sdiodev->bus_if->dstats.rx_errors++; | ||
1302 | 1300 | ||
1303 | sdio_claim_host(bus->sdiodev->func[1]); | 1301 | sdio_claim_host(bus->sdiodev->func[1]); |
1304 | if (bus->glomerr++ < 3) { | 1302 | if (bus->glomerr++ < 3) { |
@@ -1477,7 +1475,6 @@ brcmf_sdbrcm_read_control(struct brcmf_sdio *bus, u8 *hdr, uint len, uint doff) | |||
1477 | if ((rdlen + BRCMF_FIRSTREAD) > bus->sdiodev->bus_if->maxctl) { | 1475 | if ((rdlen + BRCMF_FIRSTREAD) > bus->sdiodev->bus_if->maxctl) { |
1478 | brcmf_err("%d-byte control read exceeds %d-byte buffer\n", | 1476 | brcmf_err("%d-byte control read exceeds %d-byte buffer\n", |
1479 | rdlen, bus->sdiodev->bus_if->maxctl); | 1477 | rdlen, bus->sdiodev->bus_if->maxctl); |
1480 | bus->sdiodev->bus_if->dstats.rx_errors++; | ||
1481 | brcmf_sdbrcm_rxfail(bus, false, false); | 1478 | brcmf_sdbrcm_rxfail(bus, false, false); |
1482 | goto done; | 1479 | goto done; |
1483 | } | 1480 | } |
@@ -1485,7 +1482,6 @@ brcmf_sdbrcm_read_control(struct brcmf_sdio *bus, u8 *hdr, uint len, uint doff) | |||
1485 | if ((len - doff) > bus->sdiodev->bus_if->maxctl) { | 1482 | if ((len - doff) > bus->sdiodev->bus_if->maxctl) { |
1486 | brcmf_err("%d-byte ctl frame (%d-byte ctl data) exceeds %d-byte limit\n", | 1483 | brcmf_err("%d-byte ctl frame (%d-byte ctl data) exceeds %d-byte limit\n", |
1487 | len, len - doff, bus->sdiodev->bus_if->maxctl); | 1484 | len, len - doff, bus->sdiodev->bus_if->maxctl); |
1488 | bus->sdiodev->bus_if->dstats.rx_errors++; | ||
1489 | bus->sdcnt.rx_toolong++; | 1485 | bus->sdcnt.rx_toolong++; |
1490 | brcmf_sdbrcm_rxfail(bus, false, false); | 1486 | brcmf_sdbrcm_rxfail(bus, false, false); |
1491 | goto done; | 1487 | goto done; |
@@ -1633,7 +1629,6 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes) | |||
1633 | if (!pkt) { | 1629 | if (!pkt) { |
1634 | /* Give up on data, request rtx of events */ | 1630 | /* Give up on data, request rtx of events */ |
1635 | brcmf_err("brcmu_pkt_buf_get_skb failed\n"); | 1631 | brcmf_err("brcmu_pkt_buf_get_skb failed\n"); |
1636 | bus->sdiodev->bus_if->dstats.rx_dropped++; | ||
1637 | brcmf_sdbrcm_rxfail(bus, false, | 1632 | brcmf_sdbrcm_rxfail(bus, false, |
1638 | RETRYCHAN(rd->channel)); | 1633 | RETRYCHAN(rd->channel)); |
1639 | sdio_release_host(bus->sdiodev->func[1]); | 1634 | sdio_release_host(bus->sdiodev->func[1]); |
@@ -1651,7 +1646,6 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes) | |||
1651 | brcmf_err("read %d bytes from channel %d failed: %d\n", | 1646 | brcmf_err("read %d bytes from channel %d failed: %d\n", |
1652 | rd->len, rd->channel, sdret); | 1647 | rd->len, rd->channel, sdret); |
1653 | brcmu_pkt_buf_free_skb(pkt); | 1648 | brcmu_pkt_buf_free_skb(pkt); |
1654 | bus->sdiodev->bus_if->dstats.rx_errors++; | ||
1655 | sdio_claim_host(bus->sdiodev->func[1]); | 1649 | sdio_claim_host(bus->sdiodev->func[1]); |
1656 | brcmf_sdbrcm_rxfail(bus, true, | 1650 | brcmf_sdbrcm_rxfail(bus, true, |
1657 | RETRYCHAN(rd->channel)); | 1651 | RETRYCHAN(rd->channel)); |
@@ -1939,10 +1933,6 @@ static uint brcmf_sdbrcm_sendfromq(struct brcmf_sdio *bus, uint maxframes) | |||
1939 | datalen = pkt->len - SDPCM_HDRLEN; | 1933 | datalen = pkt->len - SDPCM_HDRLEN; |
1940 | 1934 | ||
1941 | ret = brcmf_sdbrcm_txpkt(bus, pkt, SDPCM_DATA_CHANNEL, true); | 1935 | ret = brcmf_sdbrcm_txpkt(bus, pkt, SDPCM_DATA_CHANNEL, true); |
1942 | if (ret) | ||
1943 | bus->sdiodev->bus_if->dstats.tx_errors++; | ||
1944 | else | ||
1945 | bus->sdiodev->bus_if->dstats.tx_bytes += datalen; | ||
1946 | 1936 | ||
1947 | /* In poll mode, need to check for other events */ | 1937 | /* In poll mode, need to check for other events */ |
1948 | if (!bus->intr && cnt) { | 1938 | if (!bus->intr && cnt) { |
@@ -1961,8 +1951,7 @@ static uint brcmf_sdbrcm_sendfromq(struct brcmf_sdio *bus, uint maxframes) | |||
1961 | } | 1951 | } |
1962 | 1952 | ||
1963 | /* Deflow-control stack if needed */ | 1953 | /* Deflow-control stack if needed */ |
1964 | if (bus->sdiodev->bus_if->drvr_up && | 1954 | if ((bus->sdiodev->bus_if->state == BRCMF_BUS_DATA) && |
1965 | (bus->sdiodev->bus_if->state == BRCMF_BUS_DATA) && | ||
1966 | bus->txoff && (pktq_len(&bus->txq) < TXLOW)) { | 1955 | bus->txoff && (pktq_len(&bus->txq) < TXLOW)) { |
1967 | bus->txoff = false; | 1956 | bus->txoff = false; |
1968 | brcmf_txflowblock(bus->sdiodev->dev, false); | 1957 | brcmf_txflowblock(bus->sdiodev->dev, false); |
@@ -2709,9 +2698,10 @@ static int brcmf_sdio_readshared(struct brcmf_sdio *bus, | |||
2709 | * address of sdpcm_shared structure | 2698 | * address of sdpcm_shared structure |
2710 | */ | 2699 | */ |
2711 | sdio_claim_host(bus->sdiodev->func[1]); | 2700 | sdio_claim_host(bus->sdiodev->func[1]); |
2701 | brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false); | ||
2712 | rv = brcmf_sdbrcm_membytes(bus, false, shaddr, | 2702 | rv = brcmf_sdbrcm_membytes(bus, false, shaddr, |
2713 | (u8 *)&addr_le, 4); | 2703 | (u8 *)&addr_le, 4); |
2714 | sdio_claim_host(bus->sdiodev->func[1]); | 2704 | sdio_release_host(bus->sdiodev->func[1]); |
2715 | if (rv < 0) | 2705 | if (rv < 0) |
2716 | return rv; | 2706 | return rv; |
2717 | 2707 | ||
@@ -2730,10 +2720,8 @@ static int brcmf_sdio_readshared(struct brcmf_sdio *bus, | |||
2730 | } | 2720 | } |
2731 | 2721 | ||
2732 | /* Read hndrte_shared structure */ | 2722 | /* Read hndrte_shared structure */ |
2733 | sdio_claim_host(bus->sdiodev->func[1]); | ||
2734 | rv = brcmf_sdbrcm_membytes(bus, false, addr, (u8 *)&sh_le, | 2723 | rv = brcmf_sdbrcm_membytes(bus, false, addr, (u8 *)&sh_le, |
2735 | sizeof(struct sdpcm_shared_le)); | 2724 | sizeof(struct sdpcm_shared_le)); |
2736 | sdio_release_host(bus->sdiodev->func[1]); | ||
2737 | if (rv < 0) | 2725 | if (rv < 0) |
2738 | return rv; | 2726 | return rv; |
2739 | 2727 | ||
@@ -2835,14 +2823,12 @@ static int brcmf_sdio_trap_info(struct brcmf_sdio *bus, struct sdpcm_shared *sh, | |||
2835 | if ((sh->flags & SDPCM_SHARED_TRAP) == 0) | 2823 | if ((sh->flags & SDPCM_SHARED_TRAP) == 0) |
2836 | return 0; | 2824 | return 0; |
2837 | 2825 | ||
2838 | sdio_claim_host(bus->sdiodev->func[1]); | ||
2839 | error = brcmf_sdbrcm_membytes(bus, false, sh->trap_addr, (u8 *)&tr, | 2826 | error = brcmf_sdbrcm_membytes(bus, false, sh->trap_addr, (u8 *)&tr, |
2840 | sizeof(struct brcmf_trap_info)); | 2827 | sizeof(struct brcmf_trap_info)); |
2841 | if (error < 0) | 2828 | if (error < 0) |
2842 | return error; | 2829 | return error; |
2843 | 2830 | ||
2844 | nbytes = brcmf_sdio_dump_console(bus, sh, data, count); | 2831 | nbytes = brcmf_sdio_dump_console(bus, sh, data, count); |
2845 | sdio_release_host(bus->sdiodev->func[1]); | ||
2846 | if (nbytes < 0) | 2832 | if (nbytes < 0) |
2847 | return nbytes; | 2833 | return nbytes; |
2848 | 2834 | ||
@@ -3307,9 +3293,6 @@ static int brcmf_sdbrcm_download_nvram(struct brcmf_sdio *bus) | |||
3307 | { | 3293 | { |
3308 | int ret; | 3294 | int ret; |
3309 | 3295 | ||
3310 | if (bus->sdiodev->bus_if->drvr_up) | ||
3311 | return -EISCONN; | ||
3312 | |||
3313 | ret = request_firmware(&bus->firmware, BRCMF_SDIO_NV_NAME, | 3296 | ret = request_firmware(&bus->firmware, BRCMF_SDIO_NV_NAME, |
3314 | &bus->sdiodev->func[2]->dev); | 3297 | &bus->sdiodev->func[2]->dev); |
3315 | if (ret) { | 3298 | if (ret) { |
@@ -3940,6 +3923,8 @@ void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev) | |||
3940 | /* Assign bus interface call back */ | 3923 | /* Assign bus interface call back */ |
3941 | bus->sdiodev->bus_if->dev = bus->sdiodev->dev; | 3924 | bus->sdiodev->bus_if->dev = bus->sdiodev->dev; |
3942 | bus->sdiodev->bus_if->ops = &brcmf_sdio_bus_ops; | 3925 | bus->sdiodev->bus_if->ops = &brcmf_sdio_bus_ops; |
3926 | bus->sdiodev->bus_if->chip = bus->ci->chip; | ||
3927 | bus->sdiodev->bus_if->chiprev = bus->ci->chiprev; | ||
3943 | 3928 | ||
3944 | /* Attach to the brcmf/OS/network interface */ | 3929 | /* Attach to the brcmf/OS/network interface */ |
3945 | ret = brcmf_attach(SDPCM_RESERVE, bus->sdiodev->dev); | 3930 | ret = brcmf_attach(SDPCM_RESERVE, bus->sdiodev->dev); |
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fweh.c b/drivers/net/wireless/brcm80211/brcmfmac/fweh.c index ba0b22512f12..e9d6f91a1f2b 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/fweh.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/fweh.c | |||
@@ -189,24 +189,24 @@ static void brcmf_fweh_handle_if_event(struct brcmf_pub *drvr, | |||
189 | return; | 189 | return; |
190 | } | 190 | } |
191 | 191 | ||
192 | ifp = drvr->iflist[ifevent->ifidx]; | 192 | ifp = drvr->iflist[ifevent->bssidx]; |
193 | 193 | ||
194 | if (ifevent->action == BRCMF_E_IF_ADD) { | 194 | if (ifevent->action == BRCMF_E_IF_ADD) { |
195 | brcmf_dbg(EVENT, "adding %s (%pM)\n", emsg->ifname, | 195 | brcmf_dbg(EVENT, "adding %s (%pM)\n", emsg->ifname, |
196 | emsg->addr); | 196 | emsg->addr); |
197 | ifp = brcmf_add_if(drvr, ifevent->ifidx, ifevent->bssidx, | 197 | ifp = brcmf_add_if(drvr, ifevent->bssidx, ifevent->ifidx, |
198 | emsg->ifname, emsg->addr); | 198 | emsg->ifname, emsg->addr); |
199 | if (IS_ERR(ifp)) | 199 | if (IS_ERR(ifp)) |
200 | return; | 200 | return; |
201 | 201 | ||
202 | if (!drvr->fweh.evt_handler[BRCMF_E_IF]) | 202 | if (!drvr->fweh.evt_handler[BRCMF_E_IF]) |
203 | err = brcmf_net_attach(ifp); | 203 | err = brcmf_net_attach(ifp, false); |
204 | } | 204 | } |
205 | 205 | ||
206 | err = brcmf_fweh_call_event_handler(ifp, emsg->event_code, emsg, data); | 206 | err = brcmf_fweh_call_event_handler(ifp, emsg->event_code, emsg, data); |
207 | 207 | ||
208 | if (ifevent->action == BRCMF_E_IF_DEL) | 208 | if (ifevent->action == BRCMF_E_IF_DEL) |
209 | brcmf_del_if(drvr, ifevent->ifidx); | 209 | brcmf_del_if(drvr, ifevent->bssidx); |
210 | } | 210 | } |
211 | 211 | ||
212 | /** | 212 | /** |
@@ -250,8 +250,6 @@ static void brcmf_fweh_event_worker(struct work_struct *work) | |||
250 | drvr = container_of(fweh, struct brcmf_pub, fweh); | 250 | drvr = container_of(fweh, struct brcmf_pub, fweh); |
251 | 251 | ||
252 | while ((event = brcmf_fweh_dequeue_event(fweh))) { | 252 | while ((event = brcmf_fweh_dequeue_event(fweh))) { |
253 | ifp = drvr->iflist[event->ifidx]; | ||
254 | |||
255 | brcmf_dbg(EVENT, "event %s (%u) ifidx %u bsscfg %u addr %pM\n", | 253 | brcmf_dbg(EVENT, "event %s (%u) ifidx %u bsscfg %u addr %pM\n", |
256 | brcmf_fweh_event_name(event->code), event->code, | 254 | brcmf_fweh_event_name(event->code), event->code, |
257 | event->emsg.ifidx, event->emsg.bsscfgidx, | 255 | event->emsg.ifidx, event->emsg.bsscfgidx, |
@@ -283,6 +281,7 @@ static void brcmf_fweh_event_worker(struct work_struct *work) | |||
283 | goto event_free; | 281 | goto event_free; |
284 | } | 282 | } |
285 | 283 | ||
284 | ifp = drvr->iflist[emsg.bsscfgidx]; | ||
286 | err = brcmf_fweh_call_event_handler(ifp, event->code, &emsg, | 285 | err = brcmf_fweh_call_event_handler(ifp, event->code, &emsg, |
287 | event->data); | 286 | event->data); |
288 | if (err) { | 287 | if (err) { |
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fweh.h b/drivers/net/wireless/brcm80211/brcmfmac/fweh.h index 36901f76a3b5..8c39b51dcccf 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/fweh.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/fweh.h | |||
@@ -83,6 +83,7 @@ struct brcmf_event; | |||
83 | BRCMF_ENUM_DEF(MULTICAST_DECODE_ERROR, 51) \ | 83 | BRCMF_ENUM_DEF(MULTICAST_DECODE_ERROR, 51) \ |
84 | BRCMF_ENUM_DEF(TRACE, 52) \ | 84 | BRCMF_ENUM_DEF(TRACE, 52) \ |
85 | BRCMF_ENUM_DEF(IF, 54) \ | 85 | BRCMF_ENUM_DEF(IF, 54) \ |
86 | BRCMF_ENUM_DEF(P2P_DISC_LISTEN_COMPLETE, 55) \ | ||
86 | BRCMF_ENUM_DEF(RSSI, 56) \ | 87 | BRCMF_ENUM_DEF(RSSI, 56) \ |
87 | BRCMF_ENUM_DEF(PFN_SCAN_COMPLETE, 57) \ | 88 | BRCMF_ENUM_DEF(PFN_SCAN_COMPLETE, 57) \ |
88 | BRCMF_ENUM_DEF(EXTLOG_MSG, 58) \ | 89 | BRCMF_ENUM_DEF(EXTLOG_MSG, 58) \ |
@@ -96,8 +97,11 @@ struct brcmf_event; | |||
96 | BRCMF_ENUM_DEF(DFS_AP_RESUME, 66) \ | 97 | BRCMF_ENUM_DEF(DFS_AP_RESUME, 66) \ |
97 | BRCMF_ENUM_DEF(ESCAN_RESULT, 69) \ | 98 | BRCMF_ENUM_DEF(ESCAN_RESULT, 69) \ |
98 | BRCMF_ENUM_DEF(ACTION_FRAME_OFF_CHAN_COMPLETE, 70) \ | 99 | BRCMF_ENUM_DEF(ACTION_FRAME_OFF_CHAN_COMPLETE, 70) \ |
100 | BRCMF_ENUM_DEF(PROBERESP_MSG, 71) \ | ||
101 | BRCMF_ENUM_DEF(P2P_PROBEREQ_MSG, 72) \ | ||
99 | BRCMF_ENUM_DEF(DCS_REQUEST, 73) \ | 102 | BRCMF_ENUM_DEF(DCS_REQUEST, 73) \ |
100 | BRCMF_ENUM_DEF(FIFO_CREDIT_MAP, 74) | 103 | BRCMF_ENUM_DEF(FIFO_CREDIT_MAP, 74) \ |
104 | BRCMF_ENUM_DEF(ACTION_FRAME_RX, 75) | ||
101 | 105 | ||
102 | #define BRCMF_ENUM_DEF(id, val) \ | 106 | #define BRCMF_ENUM_DEF(id, val) \ |
103 | BRCMF_E_##id = (val), | 107 | BRCMF_E_##id = (val), |
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwil.c b/drivers/net/wireless/brcm80211/brcmfmac/fwil.c index d8d8b6549dc5..8d1def935b8d 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/fwil.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/fwil.c | |||
@@ -45,9 +45,10 @@ brcmf_fil_cmd_data(struct brcmf_if *ifp, u32 cmd, void *data, u32 len, bool set) | |||
45 | if (data != NULL) | 45 | if (data != NULL) |
46 | len = min_t(uint, len, BRCMF_DCMD_MAXLEN); | 46 | len = min_t(uint, len, BRCMF_DCMD_MAXLEN); |
47 | if (set) | 47 | if (set) |
48 | err = brcmf_proto_cdc_set_dcmd(drvr, ifp->idx, cmd, data, len); | 48 | err = brcmf_proto_cdc_set_dcmd(drvr, ifp->ifidx, cmd, data, |
49 | len); | ||
49 | else | 50 | else |
50 | err = brcmf_proto_cdc_query_dcmd(drvr, ifp->idx, cmd, data, | 51 | err = brcmf_proto_cdc_query_dcmd(drvr, ifp->ifidx, cmd, data, |
51 | len); | 52 | len); |
52 | 53 | ||
53 | if (err >= 0) | 54 | if (err >= 0) |
@@ -100,6 +101,7 @@ brcmf_fil_cmd_int_set(struct brcmf_if *ifp, u32 cmd, u32 data) | |||
100 | __le32 data_le = cpu_to_le32(data); | 101 | __le32 data_le = cpu_to_le32(data); |
101 | 102 | ||
102 | mutex_lock(&ifp->drvr->proto_block); | 103 | mutex_lock(&ifp->drvr->proto_block); |
104 | brcmf_dbg(FIL, "cmd=%d, value=%d\n", cmd, data); | ||
103 | err = brcmf_fil_cmd_data(ifp, cmd, &data_le, sizeof(data_le), true); | 105 | err = brcmf_fil_cmd_data(ifp, cmd, &data_le, sizeof(data_le), true); |
104 | mutex_unlock(&ifp->drvr->proto_block); | 106 | mutex_unlock(&ifp->drvr->proto_block); |
105 | 107 | ||
@@ -116,6 +118,7 @@ brcmf_fil_cmd_int_get(struct brcmf_if *ifp, u32 cmd, u32 *data) | |||
116 | err = brcmf_fil_cmd_data(ifp, cmd, &data_le, sizeof(data_le), false); | 118 | err = brcmf_fil_cmd_data(ifp, cmd, &data_le, sizeof(data_le), false); |
117 | mutex_unlock(&ifp->drvr->proto_block); | 119 | mutex_unlock(&ifp->drvr->proto_block); |
118 | *data = le32_to_cpu(data_le); | 120 | *data = le32_to_cpu(data_le); |
121 | brcmf_dbg(FIL, "cmd=%d, value=%d\n", cmd, *data); | ||
119 | 122 | ||
120 | return err; | 123 | return err; |
121 | } | 124 | } |
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h b/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h new file mode 100644 index 000000000000..0f2c83bc95dc --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h | |||
@@ -0,0 +1,66 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2012 Broadcom Corporation | ||
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 ANY | ||
11 | * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION | ||
13 | * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | ||
14 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
15 | */ | ||
16 | |||
17 | |||
18 | #ifndef FWIL_TYPES_H_ | ||
19 | #define FWIL_TYPES_H_ | ||
20 | |||
21 | #include <linux/if_ether.h> | ||
22 | |||
23 | |||
24 | #define BRCMF_FIL_ACTION_FRAME_SIZE 1800 | ||
25 | |||
26 | |||
27 | enum brcmf_fil_p2p_if_types { | ||
28 | BRCMF_FIL_P2P_IF_CLIENT, | ||
29 | BRCMF_FIL_P2P_IF_GO, | ||
30 | BRCMF_FIL_P2P_IF_DYNBCN_GO, | ||
31 | BRCMF_FIL_P2P_IF_DEV, | ||
32 | }; | ||
33 | |||
34 | struct brcmf_fil_p2p_if_le { | ||
35 | u8 addr[ETH_ALEN]; | ||
36 | __le16 type; | ||
37 | __le16 chspec; | ||
38 | }; | ||
39 | |||
40 | struct brcmf_fil_chan_info_le { | ||
41 | __le32 hw_channel; | ||
42 | __le32 target_channel; | ||
43 | __le32 scan_channel; | ||
44 | }; | ||
45 | |||
46 | struct brcmf_fil_action_frame_le { | ||
47 | u8 da[ETH_ALEN]; | ||
48 | __le16 len; | ||
49 | __le32 packet_id; | ||
50 | u8 data[BRCMF_FIL_ACTION_FRAME_SIZE]; | ||
51 | }; | ||
52 | |||
53 | struct brcmf_fil_af_params_le { | ||
54 | __le32 channel; | ||
55 | __le32 dwell_time; | ||
56 | u8 bssid[ETH_ALEN]; | ||
57 | u8 pad[2]; | ||
58 | struct brcmf_fil_action_frame_le action_frame; | ||
59 | }; | ||
60 | |||
61 | struct brcmf_fil_bss_enable_le { | ||
62 | __le32 bsscfg_idx; | ||
63 | __le32 enable; | ||
64 | }; | ||
65 | |||
66 | #endif /* FWIL_TYPES_H_ */ | ||
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/p2p.c b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c new file mode 100644 index 000000000000..4166e642068b --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c | |||
@@ -0,0 +1,2277 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2012 Broadcom Corporation | ||
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 ANY | ||
11 | * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION | ||
13 | * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | ||
14 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
15 | */ | ||
16 | #include <linux/slab.h> | ||
17 | #include <linux/netdevice.h> | ||
18 | #include <net/cfg80211.h> | ||
19 | |||
20 | #include <brcmu_wifi.h> | ||
21 | #include <brcmu_utils.h> | ||
22 | #include <defs.h> | ||
23 | #include <dhd.h> | ||
24 | #include <dhd_dbg.h> | ||
25 | #include "fwil.h" | ||
26 | #include "fwil_types.h" | ||
27 | #include "p2p.h" | ||
28 | #include "wl_cfg80211.h" | ||
29 | |||
30 | /* parameters used for p2p escan */ | ||
31 | #define P2PAPI_SCAN_NPROBES 1 | ||
32 | #define P2PAPI_SCAN_DWELL_TIME_MS 80 | ||
33 | #define P2PAPI_SCAN_SOCIAL_DWELL_TIME_MS 40 | ||
34 | #define P2PAPI_SCAN_HOME_TIME_MS 60 | ||
35 | #define P2PAPI_SCAN_NPROBS_TIME_MS 30 | ||
36 | #define P2PAPI_SCAN_AF_SEARCH_DWELL_TIME_MS 100 | ||
37 | #define WL_SCAN_CONNECT_DWELL_TIME_MS 200 | ||
38 | #define WL_SCAN_JOIN_PROBE_INTERVAL_MS 20 | ||
39 | |||
40 | #define BRCMF_P2P_WILDCARD_SSID "DIRECT-" | ||
41 | #define BRCMF_P2P_WILDCARD_SSID_LEN (sizeof(BRCMF_P2P_WILDCARD_SSID) - 1) | ||
42 | |||
43 | #define SOCIAL_CHAN_1 1 | ||
44 | #define SOCIAL_CHAN_2 6 | ||
45 | #define SOCIAL_CHAN_3 11 | ||
46 | #define IS_P2P_SOCIAL_CHANNEL(channel) ((channel == SOCIAL_CHAN_1) || \ | ||
47 | (channel == SOCIAL_CHAN_2) || \ | ||
48 | (channel == SOCIAL_CHAN_3)) | ||
49 | #define SOCIAL_CHAN_CNT 3 | ||
50 | #define AF_PEER_SEARCH_CNT 2 | ||
51 | |||
52 | #define BRCMF_SCB_TIMEOUT_VALUE 20 | ||
53 | |||
54 | #define P2P_VER 9 /* P2P version: 9=WiFi P2P v1.0 */ | ||
55 | #define P2P_PUB_AF_CATEGORY 0x04 | ||
56 | #define P2P_PUB_AF_ACTION 0x09 | ||
57 | #define P2P_AF_CATEGORY 0x7f | ||
58 | #define P2P_OUI "\x50\x6F\x9A" /* P2P OUI */ | ||
59 | #define P2P_OUI_LEN 3 /* P2P OUI length */ | ||
60 | |||
61 | /* Action Frame Constants */ | ||
62 | #define DOT11_ACTION_HDR_LEN 2 /* action frame category + action */ | ||
63 | #define DOT11_ACTION_CAT_OFF 0 /* category offset */ | ||
64 | #define DOT11_ACTION_ACT_OFF 1 /* action offset */ | ||
65 | |||
66 | #define P2P_AF_DWELL_TIME 200 | ||
67 | #define P2P_AF_MIN_DWELL_TIME 100 | ||
68 | #define P2P_AF_MED_DWELL_TIME 400 | ||
69 | #define P2P_AF_LONG_DWELL_TIME 1000 | ||
70 | #define P2P_AF_TX_MAX_RETRY 1 | ||
71 | #define P2P_AF_MAX_WAIT_TIME 2000 | ||
72 | #define P2P_INVALID_CHANNEL -1 | ||
73 | #define P2P_CHANNEL_SYNC_RETRY 5 | ||
74 | #define P2P_AF_FRM_SCAN_MAX_WAIT 1500 | ||
75 | #define P2P_DEFAULT_SLEEP_TIME_VSDB 200 | ||
76 | |||
77 | /* WiFi P2P Public Action Frame OUI Subtypes */ | ||
78 | #define P2P_PAF_GON_REQ 0 /* Group Owner Negotiation Req */ | ||
79 | #define P2P_PAF_GON_RSP 1 /* Group Owner Negotiation Rsp */ | ||
80 | #define P2P_PAF_GON_CONF 2 /* Group Owner Negotiation Confirm */ | ||
81 | #define P2P_PAF_INVITE_REQ 3 /* P2P Invitation Request */ | ||
82 | #define P2P_PAF_INVITE_RSP 4 /* P2P Invitation Response */ | ||
83 | #define P2P_PAF_DEVDIS_REQ 5 /* Device Discoverability Request */ | ||
84 | #define P2P_PAF_DEVDIS_RSP 6 /* Device Discoverability Response */ | ||
85 | #define P2P_PAF_PROVDIS_REQ 7 /* Provision Discovery Request */ | ||
86 | #define P2P_PAF_PROVDIS_RSP 8 /* Provision Discovery Response */ | ||
87 | #define P2P_PAF_SUBTYPE_INVALID 255 /* Invalid Subtype */ | ||
88 | |||
89 | /* WiFi P2P Action Frame OUI Subtypes */ | ||
90 | #define P2P_AF_NOTICE_OF_ABSENCE 0 /* Notice of Absence */ | ||
91 | #define P2P_AF_PRESENCE_REQ 1 /* P2P Presence Request */ | ||
92 | #define P2P_AF_PRESENCE_RSP 2 /* P2P Presence Response */ | ||
93 | #define P2P_AF_GO_DISC_REQ 3 /* GO Discoverability Request */ | ||
94 | |||
95 | /* P2P Service Discovery related */ | ||
96 | #define P2PSD_ACTION_CATEGORY 0x04 /* Public action frame */ | ||
97 | #define P2PSD_ACTION_ID_GAS_IREQ 0x0a /* GAS Initial Request AF */ | ||
98 | #define P2PSD_ACTION_ID_GAS_IRESP 0x0b /* GAS Initial Response AF */ | ||
99 | #define P2PSD_ACTION_ID_GAS_CREQ 0x0c /* GAS Comback Request AF */ | ||
100 | #define P2PSD_ACTION_ID_GAS_CRESP 0x0d /* GAS Comback Response AF */ | ||
101 | |||
102 | /** | ||
103 | * struct brcmf_p2p_disc_st_le - set discovery state in firmware. | ||
104 | * | ||
105 | * @state: requested discovery state (see enum brcmf_p2p_disc_state). | ||
106 | * @chspec: channel parameter for %WL_P2P_DISC_ST_LISTEN state. | ||
107 | * @dwell: dwell time in ms for %WL_P2P_DISC_ST_LISTEN state. | ||
108 | */ | ||
109 | struct brcmf_p2p_disc_st_le { | ||
110 | u8 state; | ||
111 | __le16 chspec; | ||
112 | __le16 dwell; | ||
113 | }; | ||
114 | |||
115 | /** | ||
116 | * enum brcmf_p2p_disc_state - P2P discovery state values | ||
117 | * | ||
118 | * @WL_P2P_DISC_ST_SCAN: P2P discovery with wildcard SSID and P2P IE. | ||
119 | * @WL_P2P_DISC_ST_LISTEN: P2P discovery off-channel for specified time. | ||
120 | * @WL_P2P_DISC_ST_SEARCH: P2P discovery with P2P wildcard SSID and P2P IE. | ||
121 | */ | ||
122 | enum brcmf_p2p_disc_state { | ||
123 | WL_P2P_DISC_ST_SCAN, | ||
124 | WL_P2P_DISC_ST_LISTEN, | ||
125 | WL_P2P_DISC_ST_SEARCH | ||
126 | }; | ||
127 | |||
128 | /** | ||
129 | * struct brcmf_p2p_scan_le - P2P specific scan request. | ||
130 | * | ||
131 | * @type: type of scan method requested (values: 'E' or 'S'). | ||
132 | * @reserved: reserved (ignored). | ||
133 | * @eparams: parameters used for type 'E'. | ||
134 | * @sparams: parameters used for type 'S'. | ||
135 | */ | ||
136 | struct brcmf_p2p_scan_le { | ||
137 | u8 type; | ||
138 | u8 reserved[3]; | ||
139 | union { | ||
140 | struct brcmf_escan_params_le eparams; | ||
141 | struct brcmf_scan_params_le sparams; | ||
142 | }; | ||
143 | }; | ||
144 | |||
145 | /** | ||
146 | * struct brcmf_p2p_pub_act_frame - WiFi P2P Public Action Frame | ||
147 | * | ||
148 | * @category: P2P_PUB_AF_CATEGORY | ||
149 | * @action: P2P_PUB_AF_ACTION | ||
150 | * @oui[3]: P2P_OUI | ||
151 | * @oui_type: OUI type - P2P_VER | ||
152 | * @subtype: OUI subtype - P2P_TYPE_* | ||
153 | * @dialog_token: nonzero, identifies req/rsp transaction | ||
154 | * @elts[1]: Variable length information elements. | ||
155 | */ | ||
156 | struct brcmf_p2p_pub_act_frame { | ||
157 | u8 category; | ||
158 | u8 action; | ||
159 | u8 oui[3]; | ||
160 | u8 oui_type; | ||
161 | u8 subtype; | ||
162 | u8 dialog_token; | ||
163 | u8 elts[1]; | ||
164 | }; | ||
165 | |||
166 | /** | ||
167 | * struct brcmf_p2p_action_frame - WiFi P2P Action Frame | ||
168 | * | ||
169 | * @category: P2P_AF_CATEGORY | ||
170 | * @OUI[3]: OUI - P2P_OUI | ||
171 | * @type: OUI Type - P2P_VER | ||
172 | * @subtype: OUI Subtype - P2P_AF_* | ||
173 | * @dialog_token: nonzero, identifies req/resp tranaction | ||
174 | * @elts[1]: Variable length information elements. | ||
175 | */ | ||
176 | struct brcmf_p2p_action_frame { | ||
177 | u8 category; | ||
178 | u8 oui[3]; | ||
179 | u8 type; | ||
180 | u8 subtype; | ||
181 | u8 dialog_token; | ||
182 | u8 elts[1]; | ||
183 | }; | ||
184 | |||
185 | /** | ||
186 | * struct brcmf_p2psd_gas_pub_act_frame - Wi-Fi GAS Public Action Frame | ||
187 | * | ||
188 | * @category: 0x04 Public Action Frame | ||
189 | * @action: 0x6c Advertisement Protocol | ||
190 | * @dialog_token: nonzero, identifies req/rsp transaction | ||
191 | * @query_data[1]: Query Data. SD gas ireq SD gas iresp | ||
192 | */ | ||
193 | struct brcmf_p2psd_gas_pub_act_frame { | ||
194 | u8 category; | ||
195 | u8 action; | ||
196 | u8 dialog_token; | ||
197 | u8 query_data[1]; | ||
198 | }; | ||
199 | |||
200 | /** | ||
201 | * struct brcmf_config_af_params - Action Frame Parameters for tx. | ||
202 | * | ||
203 | * @mpc_onoff: To make sure to send successfully action frame, we have to | ||
204 | * turn off mpc 0: off, 1: on, (-1): do nothing | ||
205 | * @search_channel: 1: search peer's channel to send af | ||
206 | * extra_listen: keep the dwell time to get af response frame. | ||
207 | */ | ||
208 | struct brcmf_config_af_params { | ||
209 | s32 mpc_onoff; | ||
210 | bool search_channel; | ||
211 | bool extra_listen; | ||
212 | }; | ||
213 | |||
214 | /** | ||
215 | * brcmf_p2p_is_pub_action() - true if p2p public type frame. | ||
216 | * | ||
217 | * @frame: action frame data. | ||
218 | * @frame_len: length of action frame data. | ||
219 | * | ||
220 | * Determine if action frame is p2p public action type | ||
221 | */ | ||
222 | static bool brcmf_p2p_is_pub_action(void *frame, u32 frame_len) | ||
223 | { | ||
224 | struct brcmf_p2p_pub_act_frame *pact_frm; | ||
225 | |||
226 | if (frame == NULL) | ||
227 | return false; | ||
228 | |||
229 | pact_frm = (struct brcmf_p2p_pub_act_frame *)frame; | ||
230 | if (frame_len < sizeof(struct brcmf_p2p_pub_act_frame) - 1) | ||
231 | return false; | ||
232 | |||
233 | if (pact_frm->category == P2P_PUB_AF_CATEGORY && | ||
234 | pact_frm->action == P2P_PUB_AF_ACTION && | ||
235 | pact_frm->oui_type == P2P_VER && | ||
236 | memcmp(pact_frm->oui, P2P_OUI, P2P_OUI_LEN) == 0) | ||
237 | return true; | ||
238 | |||
239 | return false; | ||
240 | } | ||
241 | |||
242 | /** | ||
243 | * brcmf_p2p_is_p2p_action() - true if p2p action type frame. | ||
244 | * | ||
245 | * @frame: action frame data. | ||
246 | * @frame_len: length of action frame data. | ||
247 | * | ||
248 | * Determine if action frame is p2p action type | ||
249 | */ | ||
250 | static bool brcmf_p2p_is_p2p_action(void *frame, u32 frame_len) | ||
251 | { | ||
252 | struct brcmf_p2p_action_frame *act_frm; | ||
253 | |||
254 | if (frame == NULL) | ||
255 | return false; | ||
256 | |||
257 | act_frm = (struct brcmf_p2p_action_frame *)frame; | ||
258 | if (frame_len < sizeof(struct brcmf_p2p_action_frame) - 1) | ||
259 | return false; | ||
260 | |||
261 | if (act_frm->category == P2P_AF_CATEGORY && | ||
262 | act_frm->type == P2P_VER && | ||
263 | memcmp(act_frm->oui, P2P_OUI, P2P_OUI_LEN) == 0) | ||
264 | return true; | ||
265 | |||
266 | return false; | ||
267 | } | ||
268 | |||
269 | /** | ||
270 | * brcmf_p2p_is_gas_action() - true if p2p gas action type frame. | ||
271 | * | ||
272 | * @frame: action frame data. | ||
273 | * @frame_len: length of action frame data. | ||
274 | * | ||
275 | * Determine if action frame is p2p gas action type | ||
276 | */ | ||
277 | static bool brcmf_p2p_is_gas_action(void *frame, u32 frame_len) | ||
278 | { | ||
279 | struct brcmf_p2psd_gas_pub_act_frame *sd_act_frm; | ||
280 | |||
281 | if (frame == NULL) | ||
282 | return false; | ||
283 | |||
284 | sd_act_frm = (struct brcmf_p2psd_gas_pub_act_frame *)frame; | ||
285 | if (frame_len < sizeof(struct brcmf_p2psd_gas_pub_act_frame) - 1) | ||
286 | return false; | ||
287 | |||
288 | if (sd_act_frm->category != P2PSD_ACTION_CATEGORY) | ||
289 | return false; | ||
290 | |||
291 | if (sd_act_frm->action == P2PSD_ACTION_ID_GAS_IREQ || | ||
292 | sd_act_frm->action == P2PSD_ACTION_ID_GAS_IRESP || | ||
293 | sd_act_frm->action == P2PSD_ACTION_ID_GAS_CREQ || | ||
294 | sd_act_frm->action == P2PSD_ACTION_ID_GAS_CRESP) | ||
295 | return true; | ||
296 | |||
297 | return false; | ||
298 | } | ||
299 | |||
300 | /** | ||
301 | * brcmf_p2p_print_actframe() - debug print routine. | ||
302 | * | ||
303 | * @tx: Received or to be transmitted | ||
304 | * @frame: action frame data. | ||
305 | * @frame_len: length of action frame data. | ||
306 | * | ||
307 | * Print information about the p2p action frame | ||
308 | */ | ||
309 | |||
310 | #ifdef DEBUG | ||
311 | |||
312 | static void brcmf_p2p_print_actframe(bool tx, void *frame, u32 frame_len) | ||
313 | { | ||
314 | struct brcmf_p2p_pub_act_frame *pact_frm; | ||
315 | struct brcmf_p2p_action_frame *act_frm; | ||
316 | struct brcmf_p2psd_gas_pub_act_frame *sd_act_frm; | ||
317 | |||
318 | if (!frame || frame_len <= 2) | ||
319 | return; | ||
320 | |||
321 | if (brcmf_p2p_is_pub_action(frame, frame_len)) { | ||
322 | pact_frm = (struct brcmf_p2p_pub_act_frame *)frame; | ||
323 | switch (pact_frm->subtype) { | ||
324 | case P2P_PAF_GON_REQ: | ||
325 | brcmf_dbg(TRACE, "%s P2P Group Owner Negotiation Req Frame\n", | ||
326 | (tx) ? "TX" : "RX"); | ||
327 | break; | ||
328 | case P2P_PAF_GON_RSP: | ||
329 | brcmf_dbg(TRACE, "%s P2P Group Owner Negotiation Rsp Frame\n", | ||
330 | (tx) ? "TX" : "RX"); | ||
331 | break; | ||
332 | case P2P_PAF_GON_CONF: | ||
333 | brcmf_dbg(TRACE, "%s P2P Group Owner Negotiation Confirm Frame\n", | ||
334 | (tx) ? "TX" : "RX"); | ||
335 | break; | ||
336 | case P2P_PAF_INVITE_REQ: | ||
337 | brcmf_dbg(TRACE, "%s P2P Invitation Request Frame\n", | ||
338 | (tx) ? "TX" : "RX"); | ||
339 | break; | ||
340 | case P2P_PAF_INVITE_RSP: | ||
341 | brcmf_dbg(TRACE, "%s P2P Invitation Response Frame\n", | ||
342 | (tx) ? "TX" : "RX"); | ||
343 | break; | ||
344 | case P2P_PAF_DEVDIS_REQ: | ||
345 | brcmf_dbg(TRACE, "%s P2P Device Discoverability Request Frame\n", | ||
346 | (tx) ? "TX" : "RX"); | ||
347 | break; | ||
348 | case P2P_PAF_DEVDIS_RSP: | ||
349 | brcmf_dbg(TRACE, "%s P2P Device Discoverability Response Frame\n", | ||
350 | (tx) ? "TX" : "RX"); | ||
351 | break; | ||
352 | case P2P_PAF_PROVDIS_REQ: | ||
353 | brcmf_dbg(TRACE, "%s P2P Provision Discovery Request Frame\n", | ||
354 | (tx) ? "TX" : "RX"); | ||
355 | break; | ||
356 | case P2P_PAF_PROVDIS_RSP: | ||
357 | brcmf_dbg(TRACE, "%s P2P Provision Discovery Response Frame\n", | ||
358 | (tx) ? "TX" : "RX"); | ||
359 | break; | ||
360 | default: | ||
361 | brcmf_dbg(TRACE, "%s Unknown P2P Public Action Frame\n", | ||
362 | (tx) ? "TX" : "RX"); | ||
363 | break; | ||
364 | } | ||
365 | } else if (brcmf_p2p_is_p2p_action(frame, frame_len)) { | ||
366 | act_frm = (struct brcmf_p2p_action_frame *)frame; | ||
367 | switch (act_frm->subtype) { | ||
368 | case P2P_AF_NOTICE_OF_ABSENCE: | ||
369 | brcmf_dbg(TRACE, "%s P2P Notice of Absence Frame\n", | ||
370 | (tx) ? "TX" : "RX"); | ||
371 | break; | ||
372 | case P2P_AF_PRESENCE_REQ: | ||
373 | brcmf_dbg(TRACE, "%s P2P Presence Request Frame\n", | ||
374 | (tx) ? "TX" : "RX"); | ||
375 | break; | ||
376 | case P2P_AF_PRESENCE_RSP: | ||
377 | brcmf_dbg(TRACE, "%s P2P Presence Response Frame\n", | ||
378 | (tx) ? "TX" : "RX"); | ||
379 | break; | ||
380 | case P2P_AF_GO_DISC_REQ: | ||
381 | brcmf_dbg(TRACE, "%s P2P Discoverability Request Frame\n", | ||
382 | (tx) ? "TX" : "RX"); | ||
383 | break; | ||
384 | default: | ||
385 | brcmf_dbg(TRACE, "%s Unknown P2P Action Frame\n", | ||
386 | (tx) ? "TX" : "RX"); | ||
387 | } | ||
388 | |||
389 | } else if (brcmf_p2p_is_gas_action(frame, frame_len)) { | ||
390 | sd_act_frm = (struct brcmf_p2psd_gas_pub_act_frame *)frame; | ||
391 | switch (sd_act_frm->action) { | ||
392 | case P2PSD_ACTION_ID_GAS_IREQ: | ||
393 | brcmf_dbg(TRACE, "%s P2P GAS Initial Request\n", | ||
394 | (tx) ? "TX" : "RX"); | ||
395 | break; | ||
396 | case P2PSD_ACTION_ID_GAS_IRESP: | ||
397 | brcmf_dbg(TRACE, "%s P2P GAS Initial Response\n", | ||
398 | (tx) ? "TX" : "RX"); | ||
399 | break; | ||
400 | case P2PSD_ACTION_ID_GAS_CREQ: | ||
401 | brcmf_dbg(TRACE, "%s P2P GAS Comback Request\n", | ||
402 | (tx) ? "TX" : "RX"); | ||
403 | break; | ||
404 | case P2PSD_ACTION_ID_GAS_CRESP: | ||
405 | brcmf_dbg(TRACE, "%s P2P GAS Comback Response\n", | ||
406 | (tx) ? "TX" : "RX"); | ||
407 | break; | ||
408 | default: | ||
409 | brcmf_dbg(TRACE, "%s Unknown P2P GAS Frame\n", | ||
410 | (tx) ? "TX" : "RX"); | ||
411 | break; | ||
412 | } | ||
413 | } | ||
414 | } | ||
415 | |||
416 | #else | ||
417 | |||
418 | static void brcmf_p2p_print_actframe(bool tx, void *frame, u32 frame_len) | ||
419 | { | ||
420 | } | ||
421 | |||
422 | #endif | ||
423 | |||
424 | |||
425 | /** | ||
426 | * brcmf_p2p_chnr_to_chspec() - convert channel number to chanspec. | ||
427 | * | ||
428 | * @channel: channel number | ||
429 | */ | ||
430 | static u16 brcmf_p2p_chnr_to_chspec(u16 channel) | ||
431 | { | ||
432 | u16 chanspec; | ||
433 | |||
434 | chanspec = channel & WL_CHANSPEC_CHAN_MASK; | ||
435 | |||
436 | if (channel <= CH_MAX_2G_CHANNEL) | ||
437 | chanspec |= WL_CHANSPEC_BAND_2G; | ||
438 | else | ||
439 | chanspec |= WL_CHANSPEC_BAND_5G; | ||
440 | |||
441 | chanspec |= WL_CHANSPEC_BW_20; | ||
442 | chanspec |= WL_CHANSPEC_CTL_SB_NONE; | ||
443 | |||
444 | return chanspec; | ||
445 | } | ||
446 | |||
447 | |||
448 | /** | ||
449 | * brcmf_p2p_set_firmware() - prepare firmware for peer-to-peer operation. | ||
450 | * | ||
451 | * @ifp: ifp to use for iovars (primary). | ||
452 | * @p2p_mac: mac address to configure for p2p_da_override | ||
453 | */ | ||
454 | static int brcmf_p2p_set_firmware(struct brcmf_if *ifp, u8 *p2p_mac) | ||
455 | { | ||
456 | s32 ret = 0; | ||
457 | |||
458 | brcmf_fil_iovar_int_set(ifp, "apsta", 1); | ||
459 | |||
460 | /* In case of COB type, firmware has default mac address | ||
461 | * After Initializing firmware, we have to set current mac address to | ||
462 | * firmware for P2P device address | ||
463 | */ | ||
464 | ret = brcmf_fil_iovar_data_set(ifp, "p2p_da_override", p2p_mac, | ||
465 | ETH_ALEN); | ||
466 | if (ret) | ||
467 | brcmf_err("failed to update device address ret %d\n", ret); | ||
468 | |||
469 | return ret; | ||
470 | } | ||
471 | |||
472 | /** | ||
473 | * brcmf_p2p_generate_bss_mac() - derive mac addresses for P2P. | ||
474 | * | ||
475 | * @p2p: P2P specific data. | ||
476 | * | ||
477 | * P2P needs mac addresses for P2P device and interface. These are | ||
478 | * derived from the primary net device, ie. the permanent ethernet | ||
479 | * address of the device. | ||
480 | */ | ||
481 | static void brcmf_p2p_generate_bss_mac(struct brcmf_p2p_info *p2p) | ||
482 | { | ||
483 | struct brcmf_if *pri_ifp = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp; | ||
484 | struct brcmf_if *p2p_ifp = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif->ifp; | ||
485 | |||
486 | /* Generate the P2P Device Address. This consists of the device's | ||
487 | * primary MAC address with the locally administered bit set. | ||
488 | */ | ||
489 | memcpy(p2p->dev_addr, pri_ifp->mac_addr, ETH_ALEN); | ||
490 | p2p->dev_addr[0] |= 0x02; | ||
491 | memcpy(p2p_ifp->mac_addr, p2p->dev_addr, ETH_ALEN); | ||
492 | |||
493 | /* Generate the P2P Interface Address. If the discovery and connection | ||
494 | * BSSCFGs need to simultaneously co-exist, then this address must be | ||
495 | * different from the P2P Device Address, but also locally administered. | ||
496 | */ | ||
497 | memcpy(p2p->int_addr, p2p->dev_addr, ETH_ALEN); | ||
498 | p2p->int_addr[4] ^= 0x80; | ||
499 | } | ||
500 | |||
501 | /** | ||
502 | * brcmf_p2p_scan_is_p2p_request() - is cfg80211 scan request a P2P scan. | ||
503 | * | ||
504 | * @request: the scan request as received from cfg80211. | ||
505 | * | ||
506 | * returns true if one of the ssids in the request matches the | ||
507 | * P2P wildcard ssid; otherwise returns false. | ||
508 | */ | ||
509 | static bool brcmf_p2p_scan_is_p2p_request(struct cfg80211_scan_request *request) | ||
510 | { | ||
511 | struct cfg80211_ssid *ssids = request->ssids; | ||
512 | int i; | ||
513 | |||
514 | for (i = 0; i < request->n_ssids; i++) { | ||
515 | if (ssids[i].ssid_len != BRCMF_P2P_WILDCARD_SSID_LEN) | ||
516 | continue; | ||
517 | |||
518 | brcmf_dbg(INFO, "comparing ssid \"%s\"", ssids[i].ssid); | ||
519 | if (!memcmp(BRCMF_P2P_WILDCARD_SSID, ssids[i].ssid, | ||
520 | BRCMF_P2P_WILDCARD_SSID_LEN)) | ||
521 | return true; | ||
522 | } | ||
523 | return false; | ||
524 | } | ||
525 | |||
526 | /** | ||
527 | * brcmf_p2p_set_discover_state - set discover state in firmware. | ||
528 | * | ||
529 | * @ifp: low-level interface object. | ||
530 | * @state: discover state to set. | ||
531 | * @chanspec: channel parameters (for state @WL_P2P_DISC_ST_LISTEN only). | ||
532 | * @listen_ms: duration to listen (for state @WL_P2P_DISC_ST_LISTEN only). | ||
533 | */ | ||
534 | static s32 brcmf_p2p_set_discover_state(struct brcmf_if *ifp, u8 state, | ||
535 | u16 chanspec, u16 listen_ms) | ||
536 | { | ||
537 | struct brcmf_p2p_disc_st_le discover_state; | ||
538 | s32 ret = 0; | ||
539 | brcmf_dbg(TRACE, "enter\n"); | ||
540 | |||
541 | discover_state.state = state; | ||
542 | discover_state.chspec = cpu_to_le16(chanspec); | ||
543 | discover_state.dwell = cpu_to_le16(listen_ms); | ||
544 | ret = brcmf_fil_bsscfg_data_set(ifp, "p2p_state", &discover_state, | ||
545 | sizeof(discover_state)); | ||
546 | return ret; | ||
547 | } | ||
548 | |||
549 | /** | ||
550 | * brcmf_p2p_deinit_discovery() - disable P2P device discovery. | ||
551 | * | ||
552 | * @p2p: P2P specific data. | ||
553 | * | ||
554 | * Resets the discovery state and disables it in firmware. | ||
555 | */ | ||
556 | static s32 brcmf_p2p_deinit_discovery(struct brcmf_p2p_info *p2p) | ||
557 | { | ||
558 | struct brcmf_cfg80211_vif *vif; | ||
559 | |||
560 | brcmf_dbg(TRACE, "enter\n"); | ||
561 | |||
562 | /* Set the discovery state to SCAN */ | ||
563 | vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif; | ||
564 | (void)brcmf_p2p_set_discover_state(vif->ifp, WL_P2P_DISC_ST_SCAN, 0, 0); | ||
565 | |||
566 | /* Disable P2P discovery in the firmware */ | ||
567 | vif = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif; | ||
568 | (void)brcmf_fil_iovar_int_set(vif->ifp, "p2p_disc", 0); | ||
569 | |||
570 | return 0; | ||
571 | } | ||
572 | |||
573 | /** | ||
574 | * brcmf_p2p_enable_discovery() - initialize and configure discovery. | ||
575 | * | ||
576 | * @p2p: P2P specific data. | ||
577 | * | ||
578 | * Initializes the discovery device and configure the virtual interface. | ||
579 | */ | ||
580 | static int brcmf_p2p_enable_discovery(struct brcmf_p2p_info *p2p) | ||
581 | { | ||
582 | struct brcmf_cfg80211_vif *vif; | ||
583 | s32 ret = 0; | ||
584 | |||
585 | brcmf_dbg(TRACE, "enter\n"); | ||
586 | vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif; | ||
587 | if (!vif) { | ||
588 | brcmf_err("P2P config device not available\n"); | ||
589 | ret = -EPERM; | ||
590 | goto exit; | ||
591 | } | ||
592 | |||
593 | if (test_bit(BRCMF_P2P_STATUS_ENABLED, &p2p->status)) { | ||
594 | brcmf_dbg(INFO, "P2P config device already configured\n"); | ||
595 | goto exit; | ||
596 | } | ||
597 | |||
598 | /* Re-initialize P2P Discovery in the firmware */ | ||
599 | vif = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif; | ||
600 | ret = brcmf_fil_iovar_int_set(vif->ifp, "p2p_disc", 1); | ||
601 | if (ret < 0) { | ||
602 | brcmf_err("set p2p_disc error\n"); | ||
603 | goto exit; | ||
604 | } | ||
605 | vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif; | ||
606 | ret = brcmf_p2p_set_discover_state(vif->ifp, WL_P2P_DISC_ST_SCAN, 0, 0); | ||
607 | if (ret < 0) { | ||
608 | brcmf_err("unable to set WL_P2P_DISC_ST_SCAN\n"); | ||
609 | goto exit; | ||
610 | } | ||
611 | |||
612 | /* | ||
613 | * Set wsec to any non-zero value in the discovery bsscfg | ||
614 | * to ensure our P2P probe responses have the privacy bit | ||
615 | * set in the 802.11 WPA IE. Some peer devices may not | ||
616 | * initiate WPS with us if this bit is not set. | ||
617 | */ | ||
618 | ret = brcmf_fil_bsscfg_int_set(vif->ifp, "wsec", AES_ENABLED); | ||
619 | if (ret < 0) { | ||
620 | brcmf_err("wsec error %d\n", ret); | ||
621 | goto exit; | ||
622 | } | ||
623 | |||
624 | set_bit(BRCMF_P2P_STATUS_ENABLED, &p2p->status); | ||
625 | exit: | ||
626 | return ret; | ||
627 | } | ||
628 | |||
629 | /** | ||
630 | * brcmf_p2p_escan() - initiate a P2P scan. | ||
631 | * | ||
632 | * @p2p: P2P specific data. | ||
633 | * @num_chans: number of channels to scan. | ||
634 | * @chanspecs: channel parameters for @num_chans channels. | ||
635 | * @search_state: P2P discover state to use. | ||
636 | * @action: scan action to pass to firmware. | ||
637 | * @bss_type: type of P2P bss. | ||
638 | */ | ||
639 | static s32 brcmf_p2p_escan(struct brcmf_p2p_info *p2p, u32 num_chans, | ||
640 | u16 chanspecs[], s32 search_state, u16 action, | ||
641 | enum p2p_bss_type bss_type) | ||
642 | { | ||
643 | s32 ret = 0; | ||
644 | s32 memsize = offsetof(struct brcmf_p2p_scan_le, | ||
645 | eparams.params_le.channel_list); | ||
646 | s32 nprobes; | ||
647 | s32 active; | ||
648 | u32 i; | ||
649 | u8 *memblk; | ||
650 | struct brcmf_cfg80211_vif *vif; | ||
651 | struct brcmf_p2p_scan_le *p2p_params; | ||
652 | struct brcmf_scan_params_le *sparams; | ||
653 | struct brcmf_ssid ssid; | ||
654 | |||
655 | memsize += num_chans * sizeof(__le16); | ||
656 | memblk = kzalloc(memsize, GFP_KERNEL); | ||
657 | if (!memblk) | ||
658 | return -ENOMEM; | ||
659 | |||
660 | vif = p2p->bss_idx[bss_type].vif; | ||
661 | if (vif == NULL) { | ||
662 | brcmf_err("no vif for bss type %d\n", bss_type); | ||
663 | ret = -EINVAL; | ||
664 | goto exit; | ||
665 | } | ||
666 | |||
667 | switch (search_state) { | ||
668 | case WL_P2P_DISC_ST_SEARCH: | ||
669 | /* | ||
670 | * If we in SEARCH STATE, we don't need to set SSID explictly | ||
671 | * because dongle use P2P WILDCARD internally by default | ||
672 | */ | ||
673 | /* use null ssid */ | ||
674 | ssid.SSID_len = 0; | ||
675 | memset(ssid.SSID, 0, sizeof(ssid.SSID)); | ||
676 | break; | ||
677 | case WL_P2P_DISC_ST_SCAN: | ||
678 | /* | ||
679 | * wpa_supplicant has p2p_find command with type social or | ||
680 | * progressive. For progressive, we need to set the ssid to | ||
681 | * P2P WILDCARD because we just do broadcast scan unless | ||
682 | * setting SSID. | ||
683 | */ | ||
684 | ssid.SSID_len = BRCMF_P2P_WILDCARD_SSID_LEN; | ||
685 | memcpy(ssid.SSID, BRCMF_P2P_WILDCARD_SSID, ssid.SSID_len); | ||
686 | break; | ||
687 | default: | ||
688 | brcmf_err(" invalid search state %d\n", search_state); | ||
689 | ret = -EINVAL; | ||
690 | goto exit; | ||
691 | } | ||
692 | |||
693 | brcmf_p2p_set_discover_state(vif->ifp, search_state, 0, 0); | ||
694 | |||
695 | /* | ||
696 | * set p2p scan parameters. | ||
697 | */ | ||
698 | p2p_params = (struct brcmf_p2p_scan_le *)memblk; | ||
699 | p2p_params->type = 'E'; | ||
700 | |||
701 | /* determine the scan engine parameters */ | ||
702 | sparams = &p2p_params->eparams.params_le; | ||
703 | sparams->bss_type = DOT11_BSSTYPE_ANY; | ||
704 | if (p2p->cfg->active_scan) | ||
705 | sparams->scan_type = 0; | ||
706 | else | ||
707 | sparams->scan_type = 1; | ||
708 | |||
709 | memset(&sparams->bssid, 0xFF, ETH_ALEN); | ||
710 | if (ssid.SSID_len) | ||
711 | memcpy(sparams->ssid_le.SSID, ssid.SSID, ssid.SSID_len); | ||
712 | sparams->ssid_le.SSID_len = cpu_to_le32(ssid.SSID_len); | ||
713 | sparams->home_time = cpu_to_le32(P2PAPI_SCAN_HOME_TIME_MS); | ||
714 | |||
715 | /* | ||
716 | * SOCIAL_CHAN_CNT + 1 takes care of the Progressive scan | ||
717 | * supported by the supplicant. | ||
718 | */ | ||
719 | if (num_chans == SOCIAL_CHAN_CNT || num_chans == (SOCIAL_CHAN_CNT + 1)) | ||
720 | active = P2PAPI_SCAN_SOCIAL_DWELL_TIME_MS; | ||
721 | else if (num_chans == AF_PEER_SEARCH_CNT) | ||
722 | active = P2PAPI_SCAN_AF_SEARCH_DWELL_TIME_MS; | ||
723 | else if (wl_get_vif_state_all(p2p->cfg, BRCMF_VIF_STATUS_CONNECTED)) | ||
724 | active = -1; | ||
725 | else | ||
726 | active = P2PAPI_SCAN_DWELL_TIME_MS; | ||
727 | |||
728 | /* Override scan params to find a peer for a connection */ | ||
729 | if (num_chans == 1) { | ||
730 | active = WL_SCAN_CONNECT_DWELL_TIME_MS; | ||
731 | /* WAR to sync with presence period of VSDB GO. | ||
732 | * send probe request more frequently | ||
733 | */ | ||
734 | nprobes = active / WL_SCAN_JOIN_PROBE_INTERVAL_MS; | ||
735 | } else { | ||
736 | nprobes = active / P2PAPI_SCAN_NPROBS_TIME_MS; | ||
737 | } | ||
738 | |||
739 | if (nprobes <= 0) | ||
740 | nprobes = 1; | ||
741 | |||
742 | brcmf_dbg(INFO, "nprobes # %d, active_time %d\n", nprobes, active); | ||
743 | sparams->active_time = cpu_to_le32(active); | ||
744 | sparams->nprobes = cpu_to_le32(nprobes); | ||
745 | sparams->passive_time = cpu_to_le32(-1); | ||
746 | sparams->channel_num = cpu_to_le32(num_chans & | ||
747 | BRCMF_SCAN_PARAMS_COUNT_MASK); | ||
748 | for (i = 0; i < num_chans; i++) | ||
749 | sparams->channel_list[i] = cpu_to_le16(chanspecs[i]); | ||
750 | |||
751 | /* set the escan specific parameters */ | ||
752 | p2p_params->eparams.version = cpu_to_le32(BRCMF_ESCAN_REQ_VERSION); | ||
753 | p2p_params->eparams.action = cpu_to_le16(action); | ||
754 | p2p_params->eparams.sync_id = cpu_to_le16(0x1234); | ||
755 | /* perform p2p scan on primary device */ | ||
756 | ret = brcmf_fil_bsscfg_data_set(vif->ifp, "p2p_scan", memblk, memsize); | ||
757 | if (!ret) | ||
758 | set_bit(BRCMF_SCAN_STATUS_BUSY, &p2p->cfg->scan_status); | ||
759 | exit: | ||
760 | kfree(memblk); | ||
761 | return ret; | ||
762 | } | ||
763 | |||
764 | /** | ||
765 | * brcmf_p2p_run_escan() - escan callback for peer-to-peer. | ||
766 | * | ||
767 | * @cfg: driver private data for cfg80211 interface. | ||
768 | * @ndev: net device for which scan is requested. | ||
769 | * @request: scan request from cfg80211. | ||
770 | * @action: scan action. | ||
771 | * | ||
772 | * Determines the P2P discovery state based to scan request parameters and | ||
773 | * validates the channels in the request. | ||
774 | */ | ||
775 | static s32 brcmf_p2p_run_escan(struct brcmf_cfg80211_info *cfg, | ||
776 | struct net_device *ndev, | ||
777 | struct cfg80211_scan_request *request, | ||
778 | u16 action) | ||
779 | { | ||
780 | struct brcmf_p2p_info *p2p = &cfg->p2p; | ||
781 | s32 err = 0; | ||
782 | s32 search_state = WL_P2P_DISC_ST_SCAN; | ||
783 | struct brcmf_cfg80211_vif *vif; | ||
784 | struct net_device *dev = NULL; | ||
785 | int i, num_nodfs = 0; | ||
786 | u16 *chanspecs; | ||
787 | |||
788 | brcmf_dbg(TRACE, "enter\n"); | ||
789 | |||
790 | if (!request) { | ||
791 | err = -EINVAL; | ||
792 | goto exit; | ||
793 | } | ||
794 | |||
795 | if (request->n_channels) { | ||
796 | chanspecs = kcalloc(request->n_channels, sizeof(*chanspecs), | ||
797 | GFP_KERNEL); | ||
798 | if (!chanspecs) { | ||
799 | err = -ENOMEM; | ||
800 | goto exit; | ||
801 | } | ||
802 | vif = p2p->bss_idx[P2PAPI_BSSCFG_CONNECTION].vif; | ||
803 | if (vif) | ||
804 | dev = vif->wdev.netdev; | ||
805 | if (request->n_channels == 3 && | ||
806 | request->channels[0]->hw_value == SOCIAL_CHAN_1 && | ||
807 | request->channels[1]->hw_value == SOCIAL_CHAN_2 && | ||
808 | request->channels[2]->hw_value == SOCIAL_CHAN_3) { | ||
809 | /* SOCIAL CHANNELS 1, 6, 11 */ | ||
810 | search_state = WL_P2P_DISC_ST_SEARCH; | ||
811 | brcmf_dbg(INFO, "P2P SEARCH PHASE START\n"); | ||
812 | } else if (dev != NULL && vif->mode == WL_MODE_AP) { | ||
813 | /* If you are already a GO, then do SEARCH only */ | ||
814 | brcmf_dbg(INFO, "Already a GO. Do SEARCH Only\n"); | ||
815 | search_state = WL_P2P_DISC_ST_SEARCH; | ||
816 | } else { | ||
817 | brcmf_dbg(INFO, "P2P SCAN STATE START\n"); | ||
818 | } | ||
819 | |||
820 | /* | ||
821 | * no P2P scanning on passive or DFS channels. | ||
822 | */ | ||
823 | for (i = 0; i < request->n_channels; i++) { | ||
824 | struct ieee80211_channel *chan = request->channels[i]; | ||
825 | |||
826 | if (chan->flags & (IEEE80211_CHAN_RADAR | | ||
827 | IEEE80211_CHAN_PASSIVE_SCAN)) | ||
828 | continue; | ||
829 | |||
830 | chanspecs[i] = channel_to_chanspec(chan); | ||
831 | brcmf_dbg(INFO, "%d: chan=%d, channel spec=%x\n", | ||
832 | num_nodfs, chan->hw_value, chanspecs[i]); | ||
833 | num_nodfs++; | ||
834 | } | ||
835 | err = brcmf_p2p_escan(p2p, num_nodfs, chanspecs, search_state, | ||
836 | action, P2PAPI_BSSCFG_DEVICE); | ||
837 | } | ||
838 | exit: | ||
839 | if (err) | ||
840 | brcmf_err("error (%d)\n", err); | ||
841 | return err; | ||
842 | } | ||
843 | |||
844 | |||
845 | /** | ||
846 | * brcmf_p2p_find_listen_channel() - find listen channel in ie string. | ||
847 | * | ||
848 | * @ie: string of information elements. | ||
849 | * @ie_len: length of string. | ||
850 | * | ||
851 | * Scan ie for p2p ie and look for attribute 6 channel. If available determine | ||
852 | * channel and return it. | ||
853 | */ | ||
854 | static s32 brcmf_p2p_find_listen_channel(const u8 *ie, u32 ie_len) | ||
855 | { | ||
856 | u8 channel_ie[5]; | ||
857 | s32 listen_channel; | ||
858 | s32 err; | ||
859 | |||
860 | err = cfg80211_get_p2p_attr(ie, ie_len, | ||
861 | IEEE80211_P2P_ATTR_LISTEN_CHANNEL, | ||
862 | channel_ie, sizeof(channel_ie)); | ||
863 | if (err < 0) | ||
864 | return err; | ||
865 | |||
866 | /* listen channel subel length format: */ | ||
867 | /* 3(country) + 1(op. class) + 1(chan num) */ | ||
868 | listen_channel = (s32)channel_ie[3 + 1]; | ||
869 | |||
870 | if (listen_channel == SOCIAL_CHAN_1 || | ||
871 | listen_channel == SOCIAL_CHAN_2 || | ||
872 | listen_channel == SOCIAL_CHAN_3) { | ||
873 | brcmf_dbg(INFO, "Found my Listen Channel %d\n", listen_channel); | ||
874 | return listen_channel; | ||
875 | } | ||
876 | |||
877 | return -EPERM; | ||
878 | } | ||
879 | |||
880 | |||
881 | /** | ||
882 | * brcmf_p2p_scan_prep() - prepare scan based on request. | ||
883 | * | ||
884 | * @wiphy: wiphy device. | ||
885 | * @request: scan request from cfg80211. | ||
886 | * @vif: vif on which scan request is to be executed. | ||
887 | * | ||
888 | * Prepare the scan appropriately for type of scan requested. Overrides the | ||
889 | * escan .run() callback for peer-to-peer scanning. | ||
890 | */ | ||
891 | int brcmf_p2p_scan_prep(struct wiphy *wiphy, | ||
892 | struct cfg80211_scan_request *request, | ||
893 | struct brcmf_cfg80211_vif *vif) | ||
894 | { | ||
895 | struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); | ||
896 | struct brcmf_p2p_info *p2p = &cfg->p2p; | ||
897 | int err = 0; | ||
898 | |||
899 | if (brcmf_p2p_scan_is_p2p_request(request)) { | ||
900 | /* find my listen channel */ | ||
901 | err = brcmf_p2p_find_listen_channel(request->ie, | ||
902 | request->ie_len); | ||
903 | if (err < 0) | ||
904 | return err; | ||
905 | |||
906 | p2p->afx_hdl.my_listen_chan = err; | ||
907 | |||
908 | clear_bit(BRCMF_P2P_STATUS_GO_NEG_PHASE, &p2p->status); | ||
909 | brcmf_dbg(INFO, "P2P: GO_NEG_PHASE status cleared\n"); | ||
910 | |||
911 | err = brcmf_p2p_enable_discovery(p2p); | ||
912 | if (err) | ||
913 | return err; | ||
914 | |||
915 | vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif; | ||
916 | |||
917 | /* override .run_escan() callback. */ | ||
918 | cfg->escan_info.run = brcmf_p2p_run_escan; | ||
919 | } | ||
920 | err = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_PRBREQ_FLAG, | ||
921 | request->ie, request->ie_len); | ||
922 | return err; | ||
923 | } | ||
924 | |||
925 | |||
926 | /** | ||
927 | * brcmf_p2p_discover_listen() - set firmware to discover listen state. | ||
928 | * | ||
929 | * @p2p: p2p device. | ||
930 | * @channel: channel nr for discover listen. | ||
931 | * @duration: time in ms to stay on channel. | ||
932 | * | ||
933 | */ | ||
934 | static s32 | ||
935 | brcmf_p2p_discover_listen(struct brcmf_p2p_info *p2p, u16 channel, u32 duration) | ||
936 | { | ||
937 | struct brcmf_cfg80211_vif *vif; | ||
938 | s32 err = 0; | ||
939 | u16 chanspec; | ||
940 | |||
941 | vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif; | ||
942 | if (!vif) { | ||
943 | brcmf_err("Discovery is not set, so we have nothing to do\n"); | ||
944 | err = -EPERM; | ||
945 | goto exit; | ||
946 | } | ||
947 | |||
948 | if (test_bit(BRCMF_P2P_STATUS_DISCOVER_LISTEN, &p2p->status)) { | ||
949 | brcmf_err("Previous LISTEN is not completed yet\n"); | ||
950 | /* WAR: prevent cookie mismatch in wpa_supplicant return OK */ | ||
951 | goto exit; | ||
952 | } | ||
953 | |||
954 | chanspec = brcmf_p2p_chnr_to_chspec(channel); | ||
955 | err = brcmf_p2p_set_discover_state(vif->ifp, WL_P2P_DISC_ST_LISTEN, | ||
956 | chanspec, (u16)duration); | ||
957 | if (!err) { | ||
958 | set_bit(BRCMF_P2P_STATUS_DISCOVER_LISTEN, &p2p->status); | ||
959 | p2p->remain_on_channel_cookie++; | ||
960 | } | ||
961 | exit: | ||
962 | return err; | ||
963 | } | ||
964 | |||
965 | |||
966 | /** | ||
967 | * brcmf_p2p_remain_on_channel() - put device on channel and stay there. | ||
968 | * | ||
969 | * @wiphy: wiphy device. | ||
970 | * @channel: channel to stay on. | ||
971 | * @duration: time in ms to remain on channel. | ||
972 | * | ||
973 | */ | ||
974 | int brcmf_p2p_remain_on_channel(struct wiphy *wiphy, struct wireless_dev *wdev, | ||
975 | struct ieee80211_channel *channel, | ||
976 | unsigned int duration, u64 *cookie) | ||
977 | { | ||
978 | struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); | ||
979 | struct brcmf_p2p_info *p2p = &cfg->p2p; | ||
980 | s32 err; | ||
981 | u16 channel_nr; | ||
982 | |||
983 | channel_nr = ieee80211_frequency_to_channel(channel->center_freq); | ||
984 | brcmf_dbg(TRACE, "Enter, channel: %d, duration ms (%d)\n", channel_nr, | ||
985 | duration); | ||
986 | |||
987 | err = brcmf_p2p_enable_discovery(p2p); | ||
988 | if (err) | ||
989 | goto exit; | ||
990 | err = brcmf_p2p_discover_listen(p2p, channel_nr, duration); | ||
991 | if (err) | ||
992 | goto exit; | ||
993 | |||
994 | memcpy(&p2p->remain_on_channel, channel, sizeof(*channel)); | ||
995 | *cookie = p2p->remain_on_channel_cookie; | ||
996 | cfg80211_ready_on_channel(wdev, *cookie, channel, duration, GFP_KERNEL); | ||
997 | |||
998 | exit: | ||
999 | return err; | ||
1000 | } | ||
1001 | |||
1002 | |||
1003 | /** | ||
1004 | * brcmf_p2p_notify_listen_complete() - p2p listen has completed. | ||
1005 | * | ||
1006 | * @ifp: interfac control. | ||
1007 | * @e: event message. Not used, to make it usable for fweh event dispatcher. | ||
1008 | * @data: payload of message. Not used. | ||
1009 | * | ||
1010 | */ | ||
1011 | int brcmf_p2p_notify_listen_complete(struct brcmf_if *ifp, | ||
1012 | const struct brcmf_event_msg *e, | ||
1013 | void *data) | ||
1014 | { | ||
1015 | struct brcmf_cfg80211_info *cfg = ifp->drvr->config; | ||
1016 | struct brcmf_p2p_info *p2p = &cfg->p2p; | ||
1017 | |||
1018 | brcmf_dbg(TRACE, "Enter\n"); | ||
1019 | if (test_and_clear_bit(BRCMF_P2P_STATUS_DISCOVER_LISTEN, | ||
1020 | &p2p->status)) { | ||
1021 | if (test_and_clear_bit(BRCMF_P2P_STATUS_WAITING_NEXT_AF_LISTEN, | ||
1022 | &p2p->status)) { | ||
1023 | clear_bit(BRCMF_P2P_STATUS_WAITING_NEXT_ACT_FRAME, | ||
1024 | &p2p->status); | ||
1025 | brcmf_dbg(INFO, "Listen DONE, wake up wait_next_af\n"); | ||
1026 | complete(&p2p->wait_next_af); | ||
1027 | } | ||
1028 | |||
1029 | cfg80211_remain_on_channel_expired(&ifp->vif->wdev, | ||
1030 | p2p->remain_on_channel_cookie, | ||
1031 | &p2p->remain_on_channel, | ||
1032 | GFP_KERNEL); | ||
1033 | } | ||
1034 | return 0; | ||
1035 | } | ||
1036 | |||
1037 | |||
1038 | /** | ||
1039 | * brcmf_p2p_cancel_remain_on_channel() - cancel p2p listen state. | ||
1040 | * | ||
1041 | * @ifp: interfac control. | ||
1042 | * | ||
1043 | */ | ||
1044 | void brcmf_p2p_cancel_remain_on_channel(struct brcmf_if *ifp) | ||
1045 | { | ||
1046 | if (!ifp) | ||
1047 | return; | ||
1048 | brcmf_p2p_set_discover_state(ifp, WL_P2P_DISC_ST_SCAN, 0, 0); | ||
1049 | brcmf_p2p_notify_listen_complete(ifp, NULL, NULL); | ||
1050 | } | ||
1051 | |||
1052 | |||
1053 | /** | ||
1054 | * brcmf_p2p_act_frm_search() - search function for action frame. | ||
1055 | * | ||
1056 | * @p2p: p2p device. | ||
1057 | * channel: channel on which action frame is to be trasmitted. | ||
1058 | * | ||
1059 | * search function to reach at common channel to send action frame. When | ||
1060 | * channel is 0 then all social channels will be used to send af | ||
1061 | */ | ||
1062 | static s32 brcmf_p2p_act_frm_search(struct brcmf_p2p_info *p2p, u16 channel) | ||
1063 | { | ||
1064 | s32 err; | ||
1065 | u32 channel_cnt; | ||
1066 | u16 *default_chan_list; | ||
1067 | u32 i; | ||
1068 | |||
1069 | brcmf_dbg(TRACE, "Enter\n"); | ||
1070 | |||
1071 | if (channel) | ||
1072 | channel_cnt = AF_PEER_SEARCH_CNT; | ||
1073 | else | ||
1074 | channel_cnt = SOCIAL_CHAN_CNT; | ||
1075 | default_chan_list = kzalloc(channel_cnt * sizeof(*default_chan_list), | ||
1076 | GFP_KERNEL); | ||
1077 | if (default_chan_list == NULL) { | ||
1078 | brcmf_err("channel list allocation failed\n"); | ||
1079 | err = -ENOMEM; | ||
1080 | goto exit; | ||
1081 | } | ||
1082 | if (channel) { | ||
1083 | /* insert same channel to the chan_list */ | ||
1084 | for (i = 0; i < channel_cnt; i++) | ||
1085 | default_chan_list[i] = | ||
1086 | brcmf_p2p_chnr_to_chspec(channel); | ||
1087 | } else { | ||
1088 | default_chan_list[0] = brcmf_p2p_chnr_to_chspec(SOCIAL_CHAN_1); | ||
1089 | default_chan_list[1] = brcmf_p2p_chnr_to_chspec(SOCIAL_CHAN_2); | ||
1090 | default_chan_list[2] = brcmf_p2p_chnr_to_chspec(SOCIAL_CHAN_3); | ||
1091 | } | ||
1092 | err = brcmf_p2p_escan(p2p, channel_cnt, default_chan_list, | ||
1093 | WL_P2P_DISC_ST_SEARCH, WL_ESCAN_ACTION_START, | ||
1094 | P2PAPI_BSSCFG_DEVICE); | ||
1095 | kfree(default_chan_list); | ||
1096 | exit: | ||
1097 | return err; | ||
1098 | } | ||
1099 | |||
1100 | |||
1101 | /** | ||
1102 | * brcmf_p2p_afx_handler() - afx worker thread. | ||
1103 | * | ||
1104 | * @work: | ||
1105 | * | ||
1106 | */ | ||
1107 | static void brcmf_p2p_afx_handler(struct work_struct *work) | ||
1108 | { | ||
1109 | struct afx_hdl *afx_hdl = container_of(work, struct afx_hdl, afx_work); | ||
1110 | struct brcmf_p2p_info *p2p = container_of(afx_hdl, | ||
1111 | struct brcmf_p2p_info, | ||
1112 | afx_hdl); | ||
1113 | s32 err; | ||
1114 | |||
1115 | if (!afx_hdl->is_active) | ||
1116 | return; | ||
1117 | |||
1118 | if (afx_hdl->is_listen && afx_hdl->my_listen_chan) | ||
1119 | /* 100ms ~ 300ms */ | ||
1120 | err = brcmf_p2p_discover_listen(p2p, afx_hdl->my_listen_chan, | ||
1121 | 100 * (1 + (random32() % 3))); | ||
1122 | else | ||
1123 | err = brcmf_p2p_act_frm_search(p2p, afx_hdl->peer_listen_chan); | ||
1124 | |||
1125 | if (err) { | ||
1126 | brcmf_err("ERROR occurred! value is (%d)\n", err); | ||
1127 | if (test_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL, | ||
1128 | &p2p->status)) | ||
1129 | complete(&afx_hdl->act_frm_scan); | ||
1130 | } | ||
1131 | } | ||
1132 | |||
1133 | |||
1134 | /** | ||
1135 | * brcmf_p2p_af_searching_channel() - search channel. | ||
1136 | * | ||
1137 | * @p2p: p2p device info struct. | ||
1138 | * | ||
1139 | */ | ||
1140 | static s32 brcmf_p2p_af_searching_channel(struct brcmf_p2p_info *p2p) | ||
1141 | { | ||
1142 | struct afx_hdl *afx_hdl = &p2p->afx_hdl; | ||
1143 | struct brcmf_cfg80211_vif *pri_vif; | ||
1144 | unsigned long duration; | ||
1145 | s32 retry; | ||
1146 | |||
1147 | brcmf_dbg(TRACE, "Enter\n"); | ||
1148 | |||
1149 | pri_vif = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif; | ||
1150 | |||
1151 | INIT_COMPLETION(afx_hdl->act_frm_scan); | ||
1152 | set_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL, &p2p->status); | ||
1153 | afx_hdl->is_active = true; | ||
1154 | afx_hdl->peer_chan = P2P_INVALID_CHANNEL; | ||
1155 | |||
1156 | /* Loop to wait until we find a peer's channel or the | ||
1157 | * pending action frame tx is cancelled. | ||
1158 | */ | ||
1159 | retry = 0; | ||
1160 | duration = msecs_to_jiffies(P2P_AF_FRM_SCAN_MAX_WAIT); | ||
1161 | while ((retry < P2P_CHANNEL_SYNC_RETRY) && | ||
1162 | (afx_hdl->peer_chan == P2P_INVALID_CHANNEL)) { | ||
1163 | afx_hdl->is_listen = false; | ||
1164 | brcmf_dbg(TRACE, "Scheduling action frame for sending.. (%d)\n", | ||
1165 | retry); | ||
1166 | /* search peer on peer's listen channel */ | ||
1167 | schedule_work(&afx_hdl->afx_work); | ||
1168 | wait_for_completion_timeout(&afx_hdl->act_frm_scan, duration); | ||
1169 | if ((afx_hdl->peer_chan != P2P_INVALID_CHANNEL) || | ||
1170 | (!test_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL, | ||
1171 | &p2p->status))) | ||
1172 | break; | ||
1173 | |||
1174 | if (afx_hdl->my_listen_chan) { | ||
1175 | brcmf_dbg(TRACE, "Scheduling listen peer, channel=%d\n", | ||
1176 | afx_hdl->my_listen_chan); | ||
1177 | /* listen on my listen channel */ | ||
1178 | afx_hdl->is_listen = true; | ||
1179 | schedule_work(&afx_hdl->afx_work); | ||
1180 | wait_for_completion_timeout(&afx_hdl->act_frm_scan, | ||
1181 | duration); | ||
1182 | } | ||
1183 | if ((afx_hdl->peer_chan != P2P_INVALID_CHANNEL) || | ||
1184 | (!test_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL, | ||
1185 | &p2p->status))) | ||
1186 | break; | ||
1187 | retry++; | ||
1188 | |||
1189 | /* if sta is connected or connecting, sleep for a while before | ||
1190 | * retry af tx or finding a peer | ||
1191 | */ | ||
1192 | if (test_bit(BRCMF_VIF_STATUS_CONNECTED, &pri_vif->sme_state) || | ||
1193 | test_bit(BRCMF_VIF_STATUS_CONNECTING, &pri_vif->sme_state)) | ||
1194 | msleep(P2P_DEFAULT_SLEEP_TIME_VSDB); | ||
1195 | } | ||
1196 | |||
1197 | brcmf_dbg(TRACE, "Completed search/listen peer_chan=%d\n", | ||
1198 | afx_hdl->peer_chan); | ||
1199 | afx_hdl->is_active = false; | ||
1200 | |||
1201 | clear_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL, &p2p->status); | ||
1202 | |||
1203 | return afx_hdl->peer_chan; | ||
1204 | } | ||
1205 | |||
1206 | |||
1207 | /** | ||
1208 | * brcmf_p2p_scan_finding_common_channel() - was escan used for finding channel | ||
1209 | * | ||
1210 | * @cfg: common configuration struct. | ||
1211 | * @bi: bss info struct, result from scan. | ||
1212 | * | ||
1213 | */ | ||
1214 | bool brcmf_p2p_scan_finding_common_channel(struct brcmf_cfg80211_info *cfg, | ||
1215 | struct brcmf_bss_info_le *bi) | ||
1216 | |||
1217 | { | ||
1218 | struct brcmf_p2p_info *p2p = &cfg->p2p; | ||
1219 | struct afx_hdl *afx_hdl = &p2p->afx_hdl; | ||
1220 | u8 *ie; | ||
1221 | s32 err; | ||
1222 | u8 p2p_dev_addr[ETH_ALEN]; | ||
1223 | |||
1224 | if (!test_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL, &p2p->status)) | ||
1225 | return false; | ||
1226 | |||
1227 | if (bi == NULL) { | ||
1228 | brcmf_dbg(TRACE, "ACTION FRAME SCAN Done\n"); | ||
1229 | if (afx_hdl->peer_chan == P2P_INVALID_CHANNEL) | ||
1230 | complete(&afx_hdl->act_frm_scan); | ||
1231 | return true; | ||
1232 | } | ||
1233 | |||
1234 | ie = ((u8 *)bi) + le16_to_cpu(bi->ie_offset); | ||
1235 | memset(p2p_dev_addr, 0, sizeof(p2p_dev_addr)); | ||
1236 | err = cfg80211_get_p2p_attr(ie, le32_to_cpu(bi->ie_length), | ||
1237 | IEEE80211_P2P_ATTR_DEVICE_INFO, | ||
1238 | p2p_dev_addr, sizeof(p2p_dev_addr)); | ||
1239 | if (err < 0) | ||
1240 | err = cfg80211_get_p2p_attr(ie, le32_to_cpu(bi->ie_length), | ||
1241 | IEEE80211_P2P_ATTR_DEVICE_ID, | ||
1242 | p2p_dev_addr, sizeof(p2p_dev_addr)); | ||
1243 | if ((err >= 0) && | ||
1244 | (!memcmp(p2p_dev_addr, afx_hdl->tx_dst_addr, ETH_ALEN))) { | ||
1245 | afx_hdl->peer_chan = bi->ctl_ch ? bi->ctl_ch : | ||
1246 | CHSPEC_CHANNEL(le16_to_cpu(bi->chanspec)); | ||
1247 | brcmf_dbg(TRACE, "ACTION FRAME SCAN : Peer %pM found, channel : %d\n", | ||
1248 | afx_hdl->tx_dst_addr, afx_hdl->peer_chan); | ||
1249 | complete(&afx_hdl->act_frm_scan); | ||
1250 | } | ||
1251 | return true; | ||
1252 | } | ||
1253 | |||
1254 | /** | ||
1255 | * brcmf_p2p_stop_wait_next_action_frame() - finish scan if af tx complete. | ||
1256 | * | ||
1257 | * @cfg: common configuration struct. | ||
1258 | * | ||
1259 | */ | ||
1260 | static void | ||
1261 | brcmf_p2p_stop_wait_next_action_frame(struct brcmf_cfg80211_info *cfg) | ||
1262 | { | ||
1263 | struct brcmf_p2p_info *p2p = &cfg->p2p; | ||
1264 | struct net_device *ndev = cfg->escan_info.ndev; | ||
1265 | |||
1266 | if (test_bit(BRCMF_P2P_STATUS_SENDING_ACT_FRAME, &p2p->status) && | ||
1267 | (test_bit(BRCMF_P2P_STATUS_ACTION_TX_COMPLETED, &p2p->status) || | ||
1268 | test_bit(BRCMF_P2P_STATUS_ACTION_TX_NOACK, &p2p->status))) { | ||
1269 | brcmf_dbg(TRACE, "*** Wake UP ** abort actframe iovar\n"); | ||
1270 | /* if channel is not zero, "actfame" uses off channel scan. | ||
1271 | * So abort scan for off channel completion. | ||
1272 | */ | ||
1273 | if (p2p->af_sent_channel) | ||
1274 | brcmf_notify_escan_complete(cfg, ndev, true, true); | ||
1275 | } else if (test_bit(BRCMF_P2P_STATUS_WAITING_NEXT_AF_LISTEN, | ||
1276 | &p2p->status)) { | ||
1277 | brcmf_dbg(TRACE, "*** Wake UP ** abort listen for next af frame\n"); | ||
1278 | /* So abort scan to cancel listen */ | ||
1279 | brcmf_notify_escan_complete(cfg, ndev, true, true); | ||
1280 | } | ||
1281 | } | ||
1282 | |||
1283 | |||
1284 | /** | ||
1285 | * brcmf_p2p_gon_req_collision() - Check if go negotiaton collission | ||
1286 | * | ||
1287 | * @p2p: p2p device info struct. | ||
1288 | * | ||
1289 | * return true if recevied action frame is to be dropped. | ||
1290 | */ | ||
1291 | static bool | ||
1292 | brcmf_p2p_gon_req_collision(struct brcmf_p2p_info *p2p, u8 *mac) | ||
1293 | { | ||
1294 | struct brcmf_cfg80211_info *cfg = p2p->cfg; | ||
1295 | struct brcmf_if *ifp; | ||
1296 | |||
1297 | brcmf_dbg(TRACE, "Enter\n"); | ||
1298 | |||
1299 | if (!test_bit(BRCMF_P2P_STATUS_WAITING_NEXT_ACT_FRAME, &p2p->status) || | ||
1300 | !p2p->gon_req_action) | ||
1301 | return false; | ||
1302 | |||
1303 | brcmf_dbg(TRACE, "GO Negotiation Request COLLISION !!!\n"); | ||
1304 | /* if sa(peer) addr is less than da(my) addr, then this device | ||
1305 | * process peer's gon request and block to send gon req. | ||
1306 | * if not (sa addr > da addr), | ||
1307 | * this device will process gon request and drop gon req of peer. | ||
1308 | */ | ||
1309 | ifp = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif->ifp; | ||
1310 | if (memcmp(mac, ifp->mac_addr, ETH_ALEN) < 0) { | ||
1311 | brcmf_dbg(INFO, "Block transmit gon req !!!\n"); | ||
1312 | p2p->block_gon_req_tx = true; | ||
1313 | /* if we are finding a common channel for sending af, | ||
1314 | * do not scan more to block to send current gon req | ||
1315 | */ | ||
1316 | if (test_and_clear_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL, | ||
1317 | &p2p->status)) | ||
1318 | complete(&p2p->afx_hdl.act_frm_scan); | ||
1319 | if (test_and_clear_bit(BRCMF_P2P_STATUS_WAITING_NEXT_ACT_FRAME, | ||
1320 | &p2p->status)) | ||
1321 | brcmf_p2p_stop_wait_next_action_frame(cfg); | ||
1322 | return false; | ||
1323 | } | ||
1324 | |||
1325 | /* drop gon request of peer to process gon request by this device. */ | ||
1326 | brcmf_dbg(INFO, "Drop received gon req !!!\n"); | ||
1327 | |||
1328 | return true; | ||
1329 | } | ||
1330 | |||
1331 | |||
1332 | /** | ||
1333 | * brcmf_p2p_notify_action_frame_rx() - received action frame. | ||
1334 | * | ||
1335 | * @ifp: interfac control. | ||
1336 | * @e: event message. Not used, to make it usable for fweh event dispatcher. | ||
1337 | * @data: payload of message, containing action frame data. | ||
1338 | * | ||
1339 | */ | ||
1340 | int brcmf_p2p_notify_action_frame_rx(struct brcmf_if *ifp, | ||
1341 | const struct brcmf_event_msg *e, | ||
1342 | void *data) | ||
1343 | { | ||
1344 | struct brcmf_cfg80211_info *cfg = ifp->drvr->config; | ||
1345 | struct brcmf_p2p_info *p2p = &cfg->p2p; | ||
1346 | struct afx_hdl *afx_hdl = &p2p->afx_hdl; | ||
1347 | struct wireless_dev *wdev; | ||
1348 | u32 mgmt_frame_len = e->datalen - sizeof(struct brcmf_rx_mgmt_data); | ||
1349 | struct brcmf_rx_mgmt_data *rxframe = (struct brcmf_rx_mgmt_data *)data; | ||
1350 | u8 *frame = (u8 *)(rxframe + 1); | ||
1351 | struct brcmf_p2p_pub_act_frame *act_frm; | ||
1352 | struct brcmf_p2psd_gas_pub_act_frame *sd_act_frm; | ||
1353 | u16 chanspec = be16_to_cpu(rxframe->chanspec); | ||
1354 | struct ieee80211_mgmt *mgmt_frame; | ||
1355 | s32 freq; | ||
1356 | u16 mgmt_type; | ||
1357 | u8 action; | ||
1358 | |||
1359 | /* Check if wpa_supplicant has registered for this frame */ | ||
1360 | brcmf_dbg(INFO, "ifp->vif->mgmt_rx_reg %04x\n", ifp->vif->mgmt_rx_reg); | ||
1361 | mgmt_type = (IEEE80211_STYPE_ACTION & IEEE80211_FCTL_STYPE) >> 4; | ||
1362 | if ((ifp->vif->mgmt_rx_reg & BIT(mgmt_type)) == 0) | ||
1363 | return 0; | ||
1364 | |||
1365 | brcmf_p2p_print_actframe(false, frame, mgmt_frame_len); | ||
1366 | |||
1367 | action = P2P_PAF_SUBTYPE_INVALID; | ||
1368 | if (brcmf_p2p_is_pub_action(frame, mgmt_frame_len)) { | ||
1369 | act_frm = (struct brcmf_p2p_pub_act_frame *)frame; | ||
1370 | action = act_frm->subtype; | ||
1371 | if ((action == P2P_PAF_GON_REQ) && | ||
1372 | (brcmf_p2p_gon_req_collision(p2p, (u8 *)e->addr))) { | ||
1373 | if (test_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL, | ||
1374 | &p2p->status) && | ||
1375 | (memcmp(afx_hdl->tx_dst_addr, e->addr, | ||
1376 | ETH_ALEN) == 0)) { | ||
1377 | afx_hdl->peer_chan = CHSPEC_CHANNEL(chanspec); | ||
1378 | brcmf_dbg(INFO, "GON request: Peer found, channel=%d\n", | ||
1379 | afx_hdl->peer_chan); | ||
1380 | complete(&afx_hdl->act_frm_scan); | ||
1381 | } | ||
1382 | return 0; | ||
1383 | } | ||
1384 | /* After complete GO Negotiation, roll back to mpc mode */ | ||
1385 | if ((action == P2P_PAF_GON_CONF) || | ||
1386 | (action == P2P_PAF_PROVDIS_RSP)) | ||
1387 | brcmf_set_mpc(ifp->ndev, 1); | ||
1388 | if (action == P2P_PAF_GON_CONF) { | ||
1389 | brcmf_dbg(TRACE, "P2P: GO_NEG_PHASE status cleared\n"); | ||
1390 | clear_bit(BRCMF_P2P_STATUS_GO_NEG_PHASE, &p2p->status); | ||
1391 | } | ||
1392 | } else if (brcmf_p2p_is_gas_action(frame, mgmt_frame_len)) { | ||
1393 | sd_act_frm = (struct brcmf_p2psd_gas_pub_act_frame *)frame; | ||
1394 | action = sd_act_frm->action; | ||
1395 | } | ||
1396 | |||
1397 | if (test_bit(BRCMF_P2P_STATUS_WAITING_NEXT_ACT_FRAME, &p2p->status) && | ||
1398 | (p2p->next_af_subtype == action)) { | ||
1399 | brcmf_dbg(TRACE, "We got a right next frame! (%d)\n", action); | ||
1400 | clear_bit(BRCMF_P2P_STATUS_WAITING_NEXT_ACT_FRAME, | ||
1401 | &p2p->status); | ||
1402 | /* Stop waiting for next AF. */ | ||
1403 | brcmf_p2p_stop_wait_next_action_frame(cfg); | ||
1404 | } | ||
1405 | |||
1406 | mgmt_frame = kzalloc(offsetof(struct ieee80211_mgmt, u) + | ||
1407 | mgmt_frame_len, GFP_KERNEL); | ||
1408 | if (!mgmt_frame) { | ||
1409 | brcmf_err("No memory available for action frame\n"); | ||
1410 | return -ENOMEM; | ||
1411 | } | ||
1412 | memcpy(mgmt_frame->da, ifp->mac_addr, ETH_ALEN); | ||
1413 | brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_BSSID, mgmt_frame->bssid, | ||
1414 | ETH_ALEN); | ||
1415 | memcpy(mgmt_frame->sa, e->addr, ETH_ALEN); | ||
1416 | mgmt_frame->frame_control = cpu_to_le16(IEEE80211_STYPE_ACTION); | ||
1417 | memcpy(&mgmt_frame->u, frame, mgmt_frame_len); | ||
1418 | mgmt_frame_len += offsetof(struct ieee80211_mgmt, u); | ||
1419 | |||
1420 | freq = ieee80211_channel_to_frequency(CHSPEC_CHANNEL(chanspec), | ||
1421 | CHSPEC_IS2G(chanspec) ? | ||
1422 | IEEE80211_BAND_2GHZ : | ||
1423 | IEEE80211_BAND_5GHZ); | ||
1424 | wdev = ifp->ndev->ieee80211_ptr; | ||
1425 | cfg80211_rx_mgmt(wdev, freq, 0, (u8 *)mgmt_frame, mgmt_frame_len, | ||
1426 | GFP_ATOMIC); | ||
1427 | |||
1428 | kfree(mgmt_frame); | ||
1429 | return 0; | ||
1430 | } | ||
1431 | |||
1432 | |||
1433 | /** | ||
1434 | * brcmf_p2p_notify_action_tx_complete() - transmit action frame complete | ||
1435 | * | ||
1436 | * @ifp: interfac control. | ||
1437 | * @e: event message. Not used, to make it usable for fweh event dispatcher. | ||
1438 | * @data: not used. | ||
1439 | * | ||
1440 | */ | ||
1441 | int brcmf_p2p_notify_action_tx_complete(struct brcmf_if *ifp, | ||
1442 | const struct brcmf_event_msg *e, | ||
1443 | void *data) | ||
1444 | { | ||
1445 | struct brcmf_cfg80211_info *cfg = ifp->drvr->config; | ||
1446 | struct brcmf_p2p_info *p2p = &cfg->p2p; | ||
1447 | |||
1448 | brcmf_dbg(INFO, "Enter: event %s, status=%d\n", | ||
1449 | e->event_code == BRCMF_E_ACTION_FRAME_OFF_CHAN_COMPLETE ? | ||
1450 | "ACTION_FRAME_OFF_CHAN_COMPLETE" : "ACTION_FRAME_COMPLETE", | ||
1451 | e->status); | ||
1452 | |||
1453 | if (!test_bit(BRCMF_P2P_STATUS_SENDING_ACT_FRAME, &p2p->status)) | ||
1454 | return 0; | ||
1455 | |||
1456 | if (e->event_code == BRCMF_E_ACTION_FRAME_COMPLETE) { | ||
1457 | if (e->status == BRCMF_E_STATUS_SUCCESS) | ||
1458 | set_bit(BRCMF_P2P_STATUS_ACTION_TX_COMPLETED, | ||
1459 | &p2p->status); | ||
1460 | else { | ||
1461 | set_bit(BRCMF_P2P_STATUS_ACTION_TX_NOACK, &p2p->status); | ||
1462 | /* If there is no ack, we don't need to wait for | ||
1463 | * WLC_E_ACTION_FRAME_OFFCHAN_COMPLETE event | ||
1464 | */ | ||
1465 | brcmf_p2p_stop_wait_next_action_frame(cfg); | ||
1466 | } | ||
1467 | |||
1468 | } else { | ||
1469 | complete(&p2p->send_af_done); | ||
1470 | } | ||
1471 | return 0; | ||
1472 | } | ||
1473 | |||
1474 | |||
1475 | /** | ||
1476 | * brcmf_p2p_tx_action_frame() - send action frame over fil. | ||
1477 | * | ||
1478 | * @p2p: p2p info struct for vif. | ||
1479 | * @af_params: action frame data/info. | ||
1480 | * | ||
1481 | * Send an action frame immediately without doing channel synchronization. | ||
1482 | * | ||
1483 | * This function waits for a completion event before returning. | ||
1484 | * The WLC_E_ACTION_FRAME_COMPLETE event will be received when the action | ||
1485 | * frame is transmitted. | ||
1486 | */ | ||
1487 | static s32 brcmf_p2p_tx_action_frame(struct brcmf_p2p_info *p2p, | ||
1488 | struct brcmf_fil_af_params_le *af_params) | ||
1489 | { | ||
1490 | struct brcmf_cfg80211_vif *vif; | ||
1491 | s32 err = 0; | ||
1492 | s32 timeout = 0; | ||
1493 | |||
1494 | brcmf_dbg(TRACE, "Enter\n"); | ||
1495 | |||
1496 | INIT_COMPLETION(p2p->send_af_done); | ||
1497 | clear_bit(BRCMF_P2P_STATUS_ACTION_TX_COMPLETED, &p2p->status); | ||
1498 | clear_bit(BRCMF_P2P_STATUS_ACTION_TX_NOACK, &p2p->status); | ||
1499 | |||
1500 | vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif; | ||
1501 | err = brcmf_fil_bsscfg_data_set(vif->ifp, "actframe", af_params, | ||
1502 | sizeof(*af_params)); | ||
1503 | if (err) { | ||
1504 | brcmf_err(" sending action frame has failed\n"); | ||
1505 | goto exit; | ||
1506 | } | ||
1507 | |||
1508 | p2p->af_sent_channel = le32_to_cpu(af_params->channel); | ||
1509 | p2p->af_tx_sent_jiffies = jiffies; | ||
1510 | |||
1511 | timeout = wait_for_completion_timeout(&p2p->send_af_done, | ||
1512 | msecs_to_jiffies(P2P_AF_MAX_WAIT_TIME)); | ||
1513 | |||
1514 | if (test_bit(BRCMF_P2P_STATUS_ACTION_TX_COMPLETED, &p2p->status)) { | ||
1515 | brcmf_dbg(TRACE, "TX action frame operation is success\n"); | ||
1516 | } else { | ||
1517 | err = -EIO; | ||
1518 | brcmf_dbg(TRACE, "TX action frame operation has failed\n"); | ||
1519 | } | ||
1520 | /* clear status bit for action tx */ | ||
1521 | clear_bit(BRCMF_P2P_STATUS_ACTION_TX_COMPLETED, &p2p->status); | ||
1522 | clear_bit(BRCMF_P2P_STATUS_ACTION_TX_NOACK, &p2p->status); | ||
1523 | |||
1524 | exit: | ||
1525 | return err; | ||
1526 | } | ||
1527 | |||
1528 | |||
1529 | /** | ||
1530 | * brcmf_p2p_pub_af_tx() - public action frame tx routine. | ||
1531 | * | ||
1532 | * @cfg: driver private data for cfg80211 interface. | ||
1533 | * @af_params: action frame data/info. | ||
1534 | * @config_af_params: configuration data for action frame. | ||
1535 | * | ||
1536 | * routine which transmits ation frame public type. | ||
1537 | */ | ||
1538 | static s32 brcmf_p2p_pub_af_tx(struct brcmf_cfg80211_info *cfg, | ||
1539 | struct brcmf_fil_af_params_le *af_params, | ||
1540 | struct brcmf_config_af_params *config_af_params) | ||
1541 | { | ||
1542 | struct brcmf_p2p_info *p2p = &cfg->p2p; | ||
1543 | struct brcmf_fil_action_frame_le *action_frame; | ||
1544 | struct brcmf_p2p_pub_act_frame *act_frm; | ||
1545 | s32 err = 0; | ||
1546 | u16 ie_len; | ||
1547 | |||
1548 | action_frame = &af_params->action_frame; | ||
1549 | act_frm = (struct brcmf_p2p_pub_act_frame *)(action_frame->data); | ||
1550 | |||
1551 | config_af_params->extra_listen = true; | ||
1552 | |||
1553 | switch (act_frm->subtype) { | ||
1554 | case P2P_PAF_GON_REQ: | ||
1555 | brcmf_dbg(TRACE, "P2P: GO_NEG_PHASE status set\n"); | ||
1556 | set_bit(BRCMF_P2P_STATUS_GO_NEG_PHASE, &p2p->status); | ||
1557 | config_af_params->mpc_onoff = 0; | ||
1558 | config_af_params->search_channel = true; | ||
1559 | p2p->next_af_subtype = act_frm->subtype + 1; | ||
1560 | p2p->gon_req_action = true; | ||
1561 | /* increase dwell time to wait for RESP frame */ | ||
1562 | af_params->dwell_time = cpu_to_le32(P2P_AF_MED_DWELL_TIME); | ||
1563 | break; | ||
1564 | case P2P_PAF_GON_RSP: | ||
1565 | p2p->next_af_subtype = act_frm->subtype + 1; | ||
1566 | /* increase dwell time to wait for CONF frame */ | ||
1567 | af_params->dwell_time = cpu_to_le32(P2P_AF_MED_DWELL_TIME); | ||
1568 | break; | ||
1569 | case P2P_PAF_GON_CONF: | ||
1570 | /* If we reached till GO Neg confirmation reset the filter */ | ||
1571 | brcmf_dbg(TRACE, "P2P: GO_NEG_PHASE status cleared\n"); | ||
1572 | clear_bit(BRCMF_P2P_STATUS_GO_NEG_PHASE, &p2p->status); | ||
1573 | /* turn on mpc again if go nego is done */ | ||
1574 | config_af_params->mpc_onoff = 1; | ||
1575 | /* minimize dwell time */ | ||
1576 | af_params->dwell_time = cpu_to_le32(P2P_AF_MIN_DWELL_TIME); | ||
1577 | config_af_params->extra_listen = false; | ||
1578 | break; | ||
1579 | case P2P_PAF_INVITE_REQ: | ||
1580 | config_af_params->search_channel = true; | ||
1581 | p2p->next_af_subtype = act_frm->subtype + 1; | ||
1582 | /* increase dwell time */ | ||
1583 | af_params->dwell_time = cpu_to_le32(P2P_AF_MED_DWELL_TIME); | ||
1584 | break; | ||
1585 | case P2P_PAF_INVITE_RSP: | ||
1586 | /* minimize dwell time */ | ||
1587 | af_params->dwell_time = cpu_to_le32(P2P_AF_MIN_DWELL_TIME); | ||
1588 | config_af_params->extra_listen = false; | ||
1589 | break; | ||
1590 | case P2P_PAF_DEVDIS_REQ: | ||
1591 | config_af_params->search_channel = true; | ||
1592 | p2p->next_af_subtype = act_frm->subtype + 1; | ||
1593 | /* maximize dwell time to wait for RESP frame */ | ||
1594 | af_params->dwell_time = cpu_to_le32(P2P_AF_LONG_DWELL_TIME); | ||
1595 | break; | ||
1596 | case P2P_PAF_DEVDIS_RSP: | ||
1597 | /* minimize dwell time */ | ||
1598 | af_params->dwell_time = cpu_to_le32(P2P_AF_MIN_DWELL_TIME); | ||
1599 | config_af_params->extra_listen = false; | ||
1600 | break; | ||
1601 | case P2P_PAF_PROVDIS_REQ: | ||
1602 | ie_len = le16_to_cpu(action_frame->len) - | ||
1603 | offsetof(struct brcmf_p2p_pub_act_frame, elts); | ||
1604 | if (cfg80211_get_p2p_attr(&act_frm->elts[0], ie_len, | ||
1605 | IEEE80211_P2P_ATTR_GROUP_ID, | ||
1606 | NULL, 0) < 0) | ||
1607 | config_af_params->search_channel = true; | ||
1608 | config_af_params->mpc_onoff = 0; | ||
1609 | p2p->next_af_subtype = act_frm->subtype + 1; | ||
1610 | /* increase dwell time to wait for RESP frame */ | ||
1611 | af_params->dwell_time = cpu_to_le32(P2P_AF_MED_DWELL_TIME); | ||
1612 | break; | ||
1613 | case P2P_PAF_PROVDIS_RSP: | ||
1614 | /* wpa_supplicant send go nego req right after prov disc */ | ||
1615 | p2p->next_af_subtype = P2P_PAF_GON_REQ; | ||
1616 | /* increase dwell time to MED level */ | ||
1617 | af_params->dwell_time = cpu_to_le32(P2P_AF_MED_DWELL_TIME); | ||
1618 | config_af_params->extra_listen = false; | ||
1619 | break; | ||
1620 | default: | ||
1621 | brcmf_err("Unknown p2p pub act frame subtype: %d\n", | ||
1622 | act_frm->subtype); | ||
1623 | err = -EINVAL; | ||
1624 | } | ||
1625 | return err; | ||
1626 | } | ||
1627 | |||
1628 | /** | ||
1629 | * brcmf_p2p_send_action_frame() - send action frame . | ||
1630 | * | ||
1631 | * @cfg: driver private data for cfg80211 interface. | ||
1632 | * @ndev: net device to transmit on. | ||
1633 | * @af_params: configuration data for action frame. | ||
1634 | */ | ||
1635 | bool brcmf_p2p_send_action_frame(struct brcmf_cfg80211_info *cfg, | ||
1636 | struct net_device *ndev, | ||
1637 | struct brcmf_fil_af_params_le *af_params) | ||
1638 | { | ||
1639 | struct brcmf_p2p_info *p2p = &cfg->p2p; | ||
1640 | struct brcmf_fil_action_frame_le *action_frame; | ||
1641 | struct brcmf_config_af_params config_af_params; | ||
1642 | struct afx_hdl *afx_hdl = &p2p->afx_hdl; | ||
1643 | u16 action_frame_len; | ||
1644 | bool ack = false; | ||
1645 | u8 category; | ||
1646 | u8 action; | ||
1647 | s32 tx_retry; | ||
1648 | s32 extra_listen_time; | ||
1649 | uint delta_ms; | ||
1650 | |||
1651 | action_frame = &af_params->action_frame; | ||
1652 | action_frame_len = le16_to_cpu(action_frame->len); | ||
1653 | |||
1654 | brcmf_p2p_print_actframe(true, action_frame->data, action_frame_len); | ||
1655 | |||
1656 | /* Add the default dwell time. Dwell time to stay off-channel */ | ||
1657 | /* to wait for a response action frame after transmitting an */ | ||
1658 | /* GO Negotiation action frame */ | ||
1659 | af_params->dwell_time = cpu_to_le32(P2P_AF_DWELL_TIME); | ||
1660 | |||
1661 | category = action_frame->data[DOT11_ACTION_CAT_OFF]; | ||
1662 | action = action_frame->data[DOT11_ACTION_ACT_OFF]; | ||
1663 | |||
1664 | /* initialize variables */ | ||
1665 | p2p->next_af_subtype = P2P_PAF_SUBTYPE_INVALID; | ||
1666 | p2p->gon_req_action = false; | ||
1667 | |||
1668 | /* config parameters */ | ||
1669 | config_af_params.mpc_onoff = -1; | ||
1670 | config_af_params.search_channel = false; | ||
1671 | config_af_params.extra_listen = false; | ||
1672 | |||
1673 | if (brcmf_p2p_is_pub_action(action_frame->data, action_frame_len)) { | ||
1674 | /* p2p public action frame process */ | ||
1675 | if (brcmf_p2p_pub_af_tx(cfg, af_params, &config_af_params)) { | ||
1676 | /* Just send unknown subtype frame with */ | ||
1677 | /* default parameters. */ | ||
1678 | brcmf_err("P2P Public action frame, unknown subtype.\n"); | ||
1679 | } | ||
1680 | } else if (brcmf_p2p_is_gas_action(action_frame->data, | ||
1681 | action_frame_len)) { | ||
1682 | /* service discovery process */ | ||
1683 | if (action == P2PSD_ACTION_ID_GAS_IREQ || | ||
1684 | action == P2PSD_ACTION_ID_GAS_CREQ) { | ||
1685 | /* configure service discovery query frame */ | ||
1686 | config_af_params.search_channel = true; | ||
1687 | |||
1688 | /* save next af suptype to cancel */ | ||
1689 | /* remaining dwell time */ | ||
1690 | p2p->next_af_subtype = action + 1; | ||
1691 | |||
1692 | af_params->dwell_time = | ||
1693 | cpu_to_le32(P2P_AF_MED_DWELL_TIME); | ||
1694 | } else if (action == P2PSD_ACTION_ID_GAS_IRESP || | ||
1695 | action == P2PSD_ACTION_ID_GAS_CRESP) { | ||
1696 | /* configure service discovery response frame */ | ||
1697 | af_params->dwell_time = | ||
1698 | cpu_to_le32(P2P_AF_MIN_DWELL_TIME); | ||
1699 | } else { | ||
1700 | brcmf_err("Unknown action type: %d\n", action); | ||
1701 | goto exit; | ||
1702 | } | ||
1703 | } else if (brcmf_p2p_is_p2p_action(action_frame->data, | ||
1704 | action_frame_len)) { | ||
1705 | /* do not configure anything. it will be */ | ||
1706 | /* sent with a default configuration */ | ||
1707 | } else { | ||
1708 | brcmf_err("Unknown Frame: category 0x%x, action 0x%x\n", | ||
1709 | category, action); | ||
1710 | return false; | ||
1711 | } | ||
1712 | |||
1713 | /* if connecting on primary iface, sleep for a while before sending | ||
1714 | * af tx for VSDB | ||
1715 | */ | ||
1716 | if (test_bit(BRCMF_VIF_STATUS_CONNECTING, | ||
1717 | &p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->sme_state)) | ||
1718 | msleep(50); | ||
1719 | |||
1720 | /* if scan is ongoing, abort current scan. */ | ||
1721 | if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) | ||
1722 | brcmf_abort_scanning(cfg); | ||
1723 | |||
1724 | memcpy(afx_hdl->tx_dst_addr, action_frame->da, ETH_ALEN); | ||
1725 | |||
1726 | /* To make sure to send successfully action frame, turn off mpc */ | ||
1727 | if (config_af_params.mpc_onoff == 0) | ||
1728 | brcmf_set_mpc(ndev, 0); | ||
1729 | |||
1730 | /* set status and destination address before sending af */ | ||
1731 | if (p2p->next_af_subtype != P2P_PAF_SUBTYPE_INVALID) { | ||
1732 | /* set status to cancel the remained dwell time in rx process */ | ||
1733 | set_bit(BRCMF_P2P_STATUS_WAITING_NEXT_ACT_FRAME, &p2p->status); | ||
1734 | } | ||
1735 | |||
1736 | p2p->af_sent_channel = 0; | ||
1737 | set_bit(BRCMF_P2P_STATUS_SENDING_ACT_FRAME, &p2p->status); | ||
1738 | /* validate channel and p2p ies */ | ||
1739 | if (config_af_params.search_channel && | ||
1740 | IS_P2P_SOCIAL_CHANNEL(le32_to_cpu(af_params->channel)) && | ||
1741 | p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif->saved_ie.probe_req_ie_len) { | ||
1742 | afx_hdl = &p2p->afx_hdl; | ||
1743 | afx_hdl->peer_listen_chan = le32_to_cpu(af_params->channel); | ||
1744 | |||
1745 | if (brcmf_p2p_af_searching_channel(p2p) == | ||
1746 | P2P_INVALID_CHANNEL) { | ||
1747 | brcmf_err("Couldn't find peer's channel.\n"); | ||
1748 | goto exit; | ||
1749 | } | ||
1750 | |||
1751 | /* Abort scan even for VSDB scenarios. Scan gets aborted in | ||
1752 | * firmware but after the check of piggyback algorithm. To take | ||
1753 | * care of current piggback algo, lets abort the scan here | ||
1754 | * itself. | ||
1755 | */ | ||
1756 | brcmf_notify_escan_complete(cfg, ndev, true, true); | ||
1757 | |||
1758 | /* update channel */ | ||
1759 | af_params->channel = cpu_to_le32(afx_hdl->peer_chan); | ||
1760 | } | ||
1761 | |||
1762 | tx_retry = 0; | ||
1763 | while (!p2p->block_gon_req_tx && | ||
1764 | (ack == false) && (tx_retry < P2P_AF_TX_MAX_RETRY)) { | ||
1765 | ack = !brcmf_p2p_tx_action_frame(p2p, af_params); | ||
1766 | tx_retry++; | ||
1767 | } | ||
1768 | if (ack == false) { | ||
1769 | brcmf_err("Failed to send Action Frame(retry %d)\n", tx_retry); | ||
1770 | clear_bit(BRCMF_P2P_STATUS_GO_NEG_PHASE, &p2p->status); | ||
1771 | } | ||
1772 | |||
1773 | exit: | ||
1774 | clear_bit(BRCMF_P2P_STATUS_SENDING_ACT_FRAME, &p2p->status); | ||
1775 | |||
1776 | /* WAR: sometimes dongle does not keep the dwell time of 'actframe'. | ||
1777 | * if we coundn't get the next action response frame and dongle does | ||
1778 | * not keep the dwell time, go to listen state again to get next action | ||
1779 | * response frame. | ||
1780 | */ | ||
1781 | if (ack && config_af_params.extra_listen && !p2p->block_gon_req_tx && | ||
1782 | test_bit(BRCMF_P2P_STATUS_WAITING_NEXT_ACT_FRAME, &p2p->status) && | ||
1783 | p2p->af_sent_channel == afx_hdl->my_listen_chan) { | ||
1784 | delta_ms = jiffies_to_msecs(jiffies - p2p->af_tx_sent_jiffies); | ||
1785 | if (le32_to_cpu(af_params->dwell_time) > delta_ms) | ||
1786 | extra_listen_time = le32_to_cpu(af_params->dwell_time) - | ||
1787 | delta_ms; | ||
1788 | else | ||
1789 | extra_listen_time = 0; | ||
1790 | if (extra_listen_time > 50) { | ||
1791 | set_bit(BRCMF_P2P_STATUS_WAITING_NEXT_AF_LISTEN, | ||
1792 | &p2p->status); | ||
1793 | brcmf_dbg(INFO, "Wait more time! actual af time:%d, calculated extra listen:%d\n", | ||
1794 | le32_to_cpu(af_params->dwell_time), | ||
1795 | extra_listen_time); | ||
1796 | extra_listen_time += 100; | ||
1797 | if (!brcmf_p2p_discover_listen(p2p, | ||
1798 | p2p->af_sent_channel, | ||
1799 | extra_listen_time)) { | ||
1800 | unsigned long duration; | ||
1801 | |||
1802 | extra_listen_time += 100; | ||
1803 | duration = msecs_to_jiffies(extra_listen_time); | ||
1804 | wait_for_completion_timeout(&p2p->wait_next_af, | ||
1805 | duration); | ||
1806 | } | ||
1807 | clear_bit(BRCMF_P2P_STATUS_WAITING_NEXT_AF_LISTEN, | ||
1808 | &p2p->status); | ||
1809 | } | ||
1810 | } | ||
1811 | |||
1812 | if (p2p->block_gon_req_tx) { | ||
1813 | /* if ack is true, supplicant will wait more time(100ms). | ||
1814 | * so we will return it as a success to get more time . | ||
1815 | */ | ||
1816 | p2p->block_gon_req_tx = false; | ||
1817 | ack = true; | ||
1818 | } | ||
1819 | |||
1820 | clear_bit(BRCMF_P2P_STATUS_WAITING_NEXT_ACT_FRAME, &p2p->status); | ||
1821 | /* if all done, turn mpc on again */ | ||
1822 | if (config_af_params.mpc_onoff == 1) | ||
1823 | brcmf_set_mpc(ndev, 1); | ||
1824 | |||
1825 | return ack; | ||
1826 | } | ||
1827 | |||
1828 | /** | ||
1829 | * brcmf_p2p_notify_rx_mgmt_p2p_probereq() - Event handler for p2p probe req. | ||
1830 | * | ||
1831 | * @ifp: interface pointer for which event was received. | ||
1832 | * @e: even message. | ||
1833 | * @data: payload of event message (probe request). | ||
1834 | */ | ||
1835 | s32 brcmf_p2p_notify_rx_mgmt_p2p_probereq(struct brcmf_if *ifp, | ||
1836 | const struct brcmf_event_msg *e, | ||
1837 | void *data) | ||
1838 | { | ||
1839 | struct brcmf_cfg80211_info *cfg = ifp->drvr->config; | ||
1840 | struct brcmf_p2p_info *p2p = &cfg->p2p; | ||
1841 | struct afx_hdl *afx_hdl = &p2p->afx_hdl; | ||
1842 | struct wireless_dev *wdev; | ||
1843 | struct brcmf_cfg80211_vif *vif = ifp->vif; | ||
1844 | struct brcmf_rx_mgmt_data *rxframe = (struct brcmf_rx_mgmt_data *)data; | ||
1845 | u16 chanspec = be16_to_cpu(rxframe->chanspec); | ||
1846 | u8 *mgmt_frame; | ||
1847 | u32 mgmt_frame_len; | ||
1848 | s32 freq; | ||
1849 | u16 mgmt_type; | ||
1850 | |||
1851 | brcmf_dbg(INFO, "Enter: event %d reason %d\n", e->event_code, | ||
1852 | e->reason); | ||
1853 | |||
1854 | if (test_bit(BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL, &p2p->status) && | ||
1855 | (memcmp(afx_hdl->tx_dst_addr, e->addr, ETH_ALEN) == 0)) { | ||
1856 | afx_hdl->peer_chan = CHSPEC_CHANNEL(chanspec); | ||
1857 | brcmf_dbg(INFO, "PROBE REQUEST: Peer found, channel=%d\n", | ||
1858 | afx_hdl->peer_chan); | ||
1859 | complete(&afx_hdl->act_frm_scan); | ||
1860 | } | ||
1861 | |||
1862 | /* Firmware sends us two proberesponses for each idx one. At the */ | ||
1863 | /* moment anything but bsscfgidx 0 is passed up to supplicant */ | ||
1864 | if (e->bsscfgidx == 0) | ||
1865 | return 0; | ||
1866 | |||
1867 | /* Filter any P2P probe reqs arriving during the GO-NEG Phase */ | ||
1868 | if (test_bit(BRCMF_P2P_STATUS_GO_NEG_PHASE, &p2p->status)) { | ||
1869 | brcmf_dbg(INFO, "Filtering P2P probe_req in GO-NEG phase\n"); | ||
1870 | return 0; | ||
1871 | } | ||
1872 | |||
1873 | /* Check if wpa_supplicant has registered for this frame */ | ||
1874 | brcmf_dbg(INFO, "vif->mgmt_rx_reg %04x\n", vif->mgmt_rx_reg); | ||
1875 | mgmt_type = (IEEE80211_STYPE_PROBE_REQ & IEEE80211_FCTL_STYPE) >> 4; | ||
1876 | if ((vif->mgmt_rx_reg & BIT(mgmt_type)) == 0) | ||
1877 | return 0; | ||
1878 | |||
1879 | mgmt_frame = (u8 *)(rxframe + 1); | ||
1880 | mgmt_frame_len = e->datalen - sizeof(*rxframe); | ||
1881 | freq = ieee80211_channel_to_frequency(CHSPEC_CHANNEL(chanspec), | ||
1882 | CHSPEC_IS2G(chanspec) ? | ||
1883 | IEEE80211_BAND_2GHZ : | ||
1884 | IEEE80211_BAND_5GHZ); | ||
1885 | wdev = ifp->ndev->ieee80211_ptr; | ||
1886 | cfg80211_rx_mgmt(wdev, freq, 0, mgmt_frame, mgmt_frame_len, GFP_ATOMIC); | ||
1887 | |||
1888 | brcmf_dbg(INFO, "mgmt_frame_len (%d) , e->datalen (%d), chanspec (%04x), freq (%d)\n", | ||
1889 | mgmt_frame_len, e->datalen, chanspec, freq); | ||
1890 | |||
1891 | return 0; | ||
1892 | } | ||
1893 | |||
1894 | |||
1895 | /** | ||
1896 | * brcmf_p2p_attach() - attach for P2P. | ||
1897 | * | ||
1898 | * @cfg: driver private data for cfg80211 interface. | ||
1899 | */ | ||
1900 | s32 brcmf_p2p_attach(struct brcmf_cfg80211_info *cfg) | ||
1901 | { | ||
1902 | struct brcmf_if *pri_ifp; | ||
1903 | struct brcmf_if *p2p_ifp; | ||
1904 | struct brcmf_cfg80211_vif *p2p_vif; | ||
1905 | struct brcmf_p2p_info *p2p; | ||
1906 | struct brcmf_pub *drvr; | ||
1907 | s32 bssidx; | ||
1908 | s32 err = 0; | ||
1909 | |||
1910 | p2p = &cfg->p2p; | ||
1911 | p2p->cfg = cfg; | ||
1912 | |||
1913 | drvr = cfg->pub; | ||
1914 | |||
1915 | pri_ifp = drvr->iflist[0]; | ||
1916 | p2p_ifp = drvr->iflist[1]; | ||
1917 | |||
1918 | p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif = pri_ifp->vif; | ||
1919 | |||
1920 | if (p2p_ifp) { | ||
1921 | p2p_vif = brcmf_alloc_vif(cfg, NL80211_IFTYPE_P2P_DEVICE, | ||
1922 | false); | ||
1923 | if (IS_ERR(p2p_vif)) { | ||
1924 | brcmf_err("could not create discovery vif\n"); | ||
1925 | err = -ENOMEM; | ||
1926 | goto exit; | ||
1927 | } | ||
1928 | |||
1929 | p2p_vif->ifp = p2p_ifp; | ||
1930 | p2p_ifp->vif = p2p_vif; | ||
1931 | p2p_vif->wdev.netdev = p2p_ifp->ndev; | ||
1932 | p2p_ifp->ndev->ieee80211_ptr = &p2p_vif->wdev; | ||
1933 | SET_NETDEV_DEV(p2p_ifp->ndev, wiphy_dev(cfg->wiphy)); | ||
1934 | |||
1935 | p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif = p2p_vif; | ||
1936 | |||
1937 | brcmf_p2p_generate_bss_mac(p2p); | ||
1938 | brcmf_p2p_set_firmware(pri_ifp, p2p->dev_addr); | ||
1939 | |||
1940 | /* Initialize P2P Discovery in the firmware */ | ||
1941 | err = brcmf_fil_iovar_int_set(pri_ifp, "p2p_disc", 1); | ||
1942 | if (err < 0) { | ||
1943 | brcmf_err("set p2p_disc error\n"); | ||
1944 | brcmf_free_vif(p2p_vif); | ||
1945 | goto exit; | ||
1946 | } | ||
1947 | /* obtain bsscfg index for P2P discovery */ | ||
1948 | err = brcmf_fil_iovar_int_get(pri_ifp, "p2p_dev", &bssidx); | ||
1949 | if (err < 0) { | ||
1950 | brcmf_err("retrieving discover bsscfg index failed\n"); | ||
1951 | brcmf_free_vif(p2p_vif); | ||
1952 | goto exit; | ||
1953 | } | ||
1954 | /* Verify that firmware uses same bssidx as driver !! */ | ||
1955 | if (p2p_ifp->bssidx != bssidx) { | ||
1956 | brcmf_err("Incorrect bssidx=%d, compared to p2p_ifp->bssidx=%d\n", | ||
1957 | bssidx, p2p_ifp->bssidx); | ||
1958 | brcmf_free_vif(p2p_vif); | ||
1959 | goto exit; | ||
1960 | } | ||
1961 | |||
1962 | init_completion(&p2p->send_af_done); | ||
1963 | INIT_WORK(&p2p->afx_hdl.afx_work, brcmf_p2p_afx_handler); | ||
1964 | init_completion(&p2p->afx_hdl.act_frm_scan); | ||
1965 | init_completion(&p2p->wait_next_af); | ||
1966 | } | ||
1967 | exit: | ||
1968 | return err; | ||
1969 | } | ||
1970 | |||
1971 | |||
1972 | /** | ||
1973 | * brcmf_p2p_detach() - detach P2P. | ||
1974 | * | ||
1975 | * @p2p: P2P specific data. | ||
1976 | */ | ||
1977 | void brcmf_p2p_detach(struct brcmf_p2p_info *p2p) | ||
1978 | { | ||
1979 | struct brcmf_cfg80211_vif *vif; | ||
1980 | |||
1981 | vif = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif; | ||
1982 | if (vif != NULL) { | ||
1983 | brcmf_p2p_cancel_remain_on_channel(vif->ifp); | ||
1984 | brcmf_p2p_deinit_discovery(p2p); | ||
1985 | /* remove discovery interface */ | ||
1986 | brcmf_free_vif(vif); | ||
1987 | p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif = NULL; | ||
1988 | } | ||
1989 | /* just set it all to zero */ | ||
1990 | memset(p2p, 0, sizeof(*p2p)); | ||
1991 | } | ||
1992 | |||
1993 | /** | ||
1994 | * brcmf_p2p_get_current_chanspec() - Get current operation channel. | ||
1995 | * | ||
1996 | * @p2p: P2P specific data. | ||
1997 | * @chanspec: chanspec to be returned. | ||
1998 | */ | ||
1999 | static void brcmf_p2p_get_current_chanspec(struct brcmf_p2p_info *p2p, | ||
2000 | u16 *chanspec) | ||
2001 | { | ||
2002 | struct brcmf_if *ifp; | ||
2003 | struct brcmf_fil_chan_info_le ci; | ||
2004 | s32 err; | ||
2005 | |||
2006 | ifp = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp; | ||
2007 | |||
2008 | *chanspec = 11 & WL_CHANSPEC_CHAN_MASK; | ||
2009 | |||
2010 | err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_CHANNEL, &ci, sizeof(ci)); | ||
2011 | if (!err) { | ||
2012 | *chanspec = le32_to_cpu(ci.hw_channel) & WL_CHANSPEC_CHAN_MASK; | ||
2013 | if (*chanspec < CH_MAX_2G_CHANNEL) | ||
2014 | *chanspec |= WL_CHANSPEC_BAND_2G; | ||
2015 | else | ||
2016 | *chanspec |= WL_CHANSPEC_BAND_5G; | ||
2017 | } | ||
2018 | *chanspec |= WL_CHANSPEC_BW_20 | WL_CHANSPEC_CTL_SB_NONE; | ||
2019 | } | ||
2020 | |||
2021 | /** | ||
2022 | * Change a P2P Role. | ||
2023 | * Parameters: | ||
2024 | * @mac: MAC address of the BSS to change a role | ||
2025 | * Returns 0 if success. | ||
2026 | */ | ||
2027 | int brcmf_p2p_ifchange(struct brcmf_cfg80211_info *cfg, | ||
2028 | enum brcmf_fil_p2p_if_types if_type) | ||
2029 | { | ||
2030 | struct brcmf_p2p_info *p2p = &cfg->p2p; | ||
2031 | struct brcmf_cfg80211_vif *vif; | ||
2032 | struct brcmf_fil_p2p_if_le if_request; | ||
2033 | s32 err; | ||
2034 | u16 chanspec; | ||
2035 | |||
2036 | brcmf_dbg(TRACE, "Enter\n"); | ||
2037 | |||
2038 | vif = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif; | ||
2039 | if (!vif) { | ||
2040 | brcmf_err("vif for P2PAPI_BSSCFG_PRIMARY does not exist\n"); | ||
2041 | return -EPERM; | ||
2042 | } | ||
2043 | brcmf_notify_escan_complete(cfg, vif->ifp->ndev, true, true); | ||
2044 | vif = p2p->bss_idx[P2PAPI_BSSCFG_CONNECTION].vif; | ||
2045 | if (!vif) { | ||
2046 | brcmf_err("vif for P2PAPI_BSSCFG_CONNECTION does not exist\n"); | ||
2047 | return -EPERM; | ||
2048 | } | ||
2049 | brcmf_set_mpc(vif->ifp->ndev, 0); | ||
2050 | |||
2051 | /* In concurrency case, STA may be already associated in a particular */ | ||
2052 | /* channel. so retrieve the current channel of primary interface and */ | ||
2053 | /* then start the virtual interface on that. */ | ||
2054 | brcmf_p2p_get_current_chanspec(p2p, &chanspec); | ||
2055 | |||
2056 | if_request.type = cpu_to_le16((u16)if_type); | ||
2057 | if_request.chspec = cpu_to_le16(chanspec); | ||
2058 | memcpy(if_request.addr, p2p->int_addr, sizeof(if_request.addr)); | ||
2059 | |||
2060 | brcmf_cfg80211_arm_vif_event(cfg, vif); | ||
2061 | err = brcmf_fil_iovar_data_set(vif->ifp, "p2p_ifupd", &if_request, | ||
2062 | sizeof(if_request)); | ||
2063 | if (err) { | ||
2064 | brcmf_err("p2p_ifupd FAILED, err=%d\n", err); | ||
2065 | brcmf_cfg80211_arm_vif_event(cfg, NULL); | ||
2066 | return err; | ||
2067 | } | ||
2068 | err = brcmf_cfg80211_wait_vif_event_timeout(cfg, BRCMF_E_IF_CHANGE, | ||
2069 | msecs_to_jiffies(1500)); | ||
2070 | brcmf_cfg80211_arm_vif_event(cfg, NULL); | ||
2071 | if (!err) { | ||
2072 | brcmf_err("No BRCMF_E_IF_CHANGE event received\n"); | ||
2073 | return -EIO; | ||
2074 | } | ||
2075 | |||
2076 | err = brcmf_fil_cmd_int_set(vif->ifp, BRCMF_C_SET_SCB_TIMEOUT, | ||
2077 | BRCMF_SCB_TIMEOUT_VALUE); | ||
2078 | |||
2079 | return err; | ||
2080 | } | ||
2081 | |||
2082 | static int brcmf_p2p_request_p2p_if(struct brcmf_p2p_info *p2p, | ||
2083 | struct brcmf_if *ifp, u8 ea[ETH_ALEN], | ||
2084 | enum brcmf_fil_p2p_if_types iftype) | ||
2085 | { | ||
2086 | struct brcmf_fil_p2p_if_le if_request; | ||
2087 | int err; | ||
2088 | u16 chanspec; | ||
2089 | |||
2090 | /* we need a default channel */ | ||
2091 | brcmf_p2p_get_current_chanspec(p2p, &chanspec); | ||
2092 | |||
2093 | /* fill the firmware request */ | ||
2094 | memcpy(if_request.addr, ea, ETH_ALEN); | ||
2095 | if_request.type = cpu_to_le16((u16)iftype); | ||
2096 | if_request.chspec = cpu_to_le16(chanspec); | ||
2097 | |||
2098 | err = brcmf_fil_iovar_data_set(ifp, "p2p_ifadd", &if_request, | ||
2099 | sizeof(if_request)); | ||
2100 | if (err) | ||
2101 | return err; | ||
2102 | |||
2103 | return err; | ||
2104 | } | ||
2105 | |||
2106 | static int brcmf_p2p_disable_p2p_if(struct brcmf_cfg80211_vif *vif) | ||
2107 | { | ||
2108 | struct brcmf_cfg80211_info *cfg = wdev_to_cfg(&vif->wdev); | ||
2109 | struct net_device *pri_ndev = cfg_to_ndev(cfg); | ||
2110 | struct brcmf_if *ifp = netdev_priv(pri_ndev); | ||
2111 | u8 *addr = vif->wdev.netdev->dev_addr; | ||
2112 | |||
2113 | return brcmf_fil_iovar_data_set(ifp, "p2p_ifdis", addr, ETH_ALEN); | ||
2114 | } | ||
2115 | |||
2116 | static int brcmf_p2p_release_p2p_if(struct brcmf_cfg80211_vif *vif) | ||
2117 | { | ||
2118 | struct brcmf_cfg80211_info *cfg = wdev_to_cfg(&vif->wdev); | ||
2119 | struct net_device *pri_ndev = cfg_to_ndev(cfg); | ||
2120 | struct brcmf_if *ifp = netdev_priv(pri_ndev); | ||
2121 | u8 *addr = vif->wdev.netdev->dev_addr; | ||
2122 | |||
2123 | return brcmf_fil_iovar_data_set(ifp, "p2p_ifdel", addr, ETH_ALEN); | ||
2124 | } | ||
2125 | |||
2126 | /** | ||
2127 | * brcmf_p2p_add_vif() - create a new P2P virtual interface. | ||
2128 | * | ||
2129 | * @wiphy: wiphy device of new interface. | ||
2130 | * @name: name of the new interface. | ||
2131 | * @type: nl80211 interface type. | ||
2132 | * @flags: TBD | ||
2133 | * @params: TBD | ||
2134 | */ | ||
2135 | struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name, | ||
2136 | enum nl80211_iftype type, u32 *flags, | ||
2137 | struct vif_params *params) | ||
2138 | { | ||
2139 | struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); | ||
2140 | struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg)); | ||
2141 | struct brcmf_cfg80211_vif *vif; | ||
2142 | enum brcmf_fil_p2p_if_types iftype; | ||
2143 | enum wl_mode mode; | ||
2144 | int err; | ||
2145 | |||
2146 | if (brcmf_cfg80211_vif_event_armed(cfg)) | ||
2147 | return ERR_PTR(-EBUSY); | ||
2148 | |||
2149 | brcmf_dbg(INFO, "adding vif \"%s\" (type=%d)\n", name, type); | ||
2150 | |||
2151 | switch (type) { | ||
2152 | case NL80211_IFTYPE_P2P_CLIENT: | ||
2153 | iftype = BRCMF_FIL_P2P_IF_CLIENT; | ||
2154 | mode = WL_MODE_BSS; | ||
2155 | break; | ||
2156 | case NL80211_IFTYPE_P2P_GO: | ||
2157 | iftype = BRCMF_FIL_P2P_IF_GO; | ||
2158 | mode = WL_MODE_AP; | ||
2159 | break; | ||
2160 | default: | ||
2161 | return ERR_PTR(-EOPNOTSUPP); | ||
2162 | } | ||
2163 | |||
2164 | vif = brcmf_alloc_vif(cfg, type, false); | ||
2165 | if (IS_ERR(vif)) | ||
2166 | return (struct wireless_dev *)vif; | ||
2167 | brcmf_cfg80211_arm_vif_event(cfg, vif); | ||
2168 | |||
2169 | err = brcmf_p2p_request_p2p_if(&cfg->p2p, ifp, cfg->p2p.int_addr, | ||
2170 | iftype); | ||
2171 | if (err) { | ||
2172 | brcmf_cfg80211_arm_vif_event(cfg, NULL); | ||
2173 | goto fail; | ||
2174 | } | ||
2175 | |||
2176 | /* wait for firmware event */ | ||
2177 | err = brcmf_cfg80211_wait_vif_event_timeout(cfg, BRCMF_E_IF_ADD, | ||
2178 | msecs_to_jiffies(1500)); | ||
2179 | brcmf_cfg80211_arm_vif_event(cfg, NULL); | ||
2180 | if (!err) { | ||
2181 | brcmf_err("timeout occurred\n"); | ||
2182 | err = -EIO; | ||
2183 | goto fail; | ||
2184 | } | ||
2185 | |||
2186 | /* interface created in firmware */ | ||
2187 | ifp = vif->ifp; | ||
2188 | if (!ifp) { | ||
2189 | brcmf_err("no if pointer provided\n"); | ||
2190 | err = -ENOENT; | ||
2191 | goto fail; | ||
2192 | } | ||
2193 | |||
2194 | strncpy(ifp->ndev->name, name, sizeof(ifp->ndev->name) - 1); | ||
2195 | err = brcmf_net_attach(ifp, true); | ||
2196 | if (err) { | ||
2197 | brcmf_err("Registering netdevice failed\n"); | ||
2198 | goto fail; | ||
2199 | } | ||
2200 | cfg->p2p.bss_idx[P2PAPI_BSSCFG_CONNECTION].vif = vif; | ||
2201 | /* Disable firmware roaming for P2P interface */ | ||
2202 | brcmf_fil_iovar_int_set(ifp, "roam_off", 1); | ||
2203 | if (iftype == BRCMF_FIL_P2P_IF_GO) { | ||
2204 | /* set station timeout for p2p */ | ||
2205 | brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_SCB_TIMEOUT, | ||
2206 | BRCMF_SCB_TIMEOUT_VALUE); | ||
2207 | } | ||
2208 | return &ifp->vif->wdev; | ||
2209 | |||
2210 | fail: | ||
2211 | brcmf_free_vif(vif); | ||
2212 | return ERR_PTR(err); | ||
2213 | } | ||
2214 | |||
2215 | /** | ||
2216 | * brcmf_p2p_del_vif() - delete a P2P virtual interface. | ||
2217 | * | ||
2218 | * @wiphy: wiphy device of interface. | ||
2219 | * @wdev: wireless device of interface. | ||
2220 | * | ||
2221 | * TODO: not yet supported. | ||
2222 | */ | ||
2223 | int brcmf_p2p_del_vif(struct wiphy *wiphy, struct wireless_dev *wdev) | ||
2224 | { | ||
2225 | struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy); | ||
2226 | struct brcmf_p2p_info *p2p = &cfg->p2p; | ||
2227 | struct brcmf_cfg80211_vif *vif; | ||
2228 | unsigned long jiffie_timeout = msecs_to_jiffies(1500); | ||
2229 | bool wait_for_disable = false; | ||
2230 | int err; | ||
2231 | |||
2232 | brcmf_dbg(TRACE, "delete P2P vif\n"); | ||
2233 | vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev); | ||
2234 | |||
2235 | switch (vif->wdev.iftype) { | ||
2236 | case NL80211_IFTYPE_P2P_CLIENT: | ||
2237 | if (test_bit(BRCMF_VIF_STATUS_DISCONNECTING, &vif->sme_state)) | ||
2238 | wait_for_disable = true; | ||
2239 | break; | ||
2240 | |||
2241 | case NL80211_IFTYPE_P2P_GO: | ||
2242 | if (!brcmf_p2p_disable_p2p_if(vif)) | ||
2243 | wait_for_disable = true; | ||
2244 | break; | ||
2245 | |||
2246 | case NL80211_IFTYPE_P2P_DEVICE: | ||
2247 | default: | ||
2248 | return -ENOTSUPP; | ||
2249 | break; | ||
2250 | } | ||
2251 | |||
2252 | clear_bit(BRCMF_P2P_STATUS_GO_NEG_PHASE, &p2p->status); | ||
2253 | brcmf_dbg(INFO, "P2P: GO_NEG_PHASE status cleared\n"); | ||
2254 | |||
2255 | if (wait_for_disable) | ||
2256 | wait_for_completion_timeout(&cfg->vif_disabled, | ||
2257 | msecs_to_jiffies(500)); | ||
2258 | |||
2259 | brcmf_vif_clear_mgmt_ies(vif); | ||
2260 | |||
2261 | brcmf_cfg80211_arm_vif_event(cfg, vif); | ||
2262 | err = brcmf_p2p_release_p2p_if(vif); | ||
2263 | if (!err) { | ||
2264 | /* wait for firmware event */ | ||
2265 | err = brcmf_cfg80211_wait_vif_event_timeout(cfg, BRCMF_E_IF_DEL, | ||
2266 | jiffie_timeout); | ||
2267 | if (!err) | ||
2268 | err = -EIO; | ||
2269 | else | ||
2270 | err = 0; | ||
2271 | } | ||
2272 | brcmf_cfg80211_arm_vif_event(cfg, NULL); | ||
2273 | brcmf_free_vif(vif); | ||
2274 | p2p->bss_idx[P2PAPI_BSSCFG_CONNECTION].vif = NULL; | ||
2275 | |||
2276 | return err; | ||
2277 | } | ||
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/p2p.h b/drivers/net/wireless/brcm80211/brcmfmac/p2p.h new file mode 100644 index 000000000000..6821b26224be --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmfmac/p2p.h | |||
@@ -0,0 +1,183 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2012 Broadcom Corporation | ||
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 ANY | ||
11 | * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION | ||
13 | * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | ||
14 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
15 | */ | ||
16 | #ifndef WL_CFGP2P_H_ | ||
17 | #define WL_CFGP2P_H_ | ||
18 | |||
19 | #include <net/cfg80211.h> | ||
20 | |||
21 | struct brcmf_cfg80211_info; | ||
22 | |||
23 | /** | ||
24 | * enum p2p_bss_type - different type of BSS configurations. | ||
25 | * | ||
26 | * @P2PAPI_BSSCFG_PRIMARY: maps to driver's primary bsscfg. | ||
27 | * @P2PAPI_BSSCFG_DEVICE: maps to driver's P2P device discovery bsscfg. | ||
28 | * @P2PAPI_BSSCFG_CONNECTION: maps to driver's P2P connection bsscfg. | ||
29 | * @P2PAPI_BSSCFG_MAX: used for range checking. | ||
30 | */ | ||
31 | enum p2p_bss_type { | ||
32 | P2PAPI_BSSCFG_PRIMARY, /* maps to driver's primary bsscfg */ | ||
33 | P2PAPI_BSSCFG_DEVICE, /* maps to driver's P2P device discovery bsscfg */ | ||
34 | P2PAPI_BSSCFG_CONNECTION, /* maps to driver's P2P connection bsscfg */ | ||
35 | P2PAPI_BSSCFG_MAX | ||
36 | }; | ||
37 | |||
38 | /** | ||
39 | * struct p2p_bss - peer-to-peer bss related information. | ||
40 | * | ||
41 | * @vif: virtual interface of this P2P bss. | ||
42 | * @private_data: TBD | ||
43 | */ | ||
44 | struct p2p_bss { | ||
45 | struct brcmf_cfg80211_vif *vif; | ||
46 | void *private_data; | ||
47 | }; | ||
48 | |||
49 | /** | ||
50 | * enum brcmf_p2p_status - P2P specific dongle status. | ||
51 | * | ||
52 | * @BRCMF_P2P_STATUS_IF_ADD: peer-to-peer vif add sent to dongle. | ||
53 | * @BRCMF_P2P_STATUS_IF_DEL: NOT-USED? | ||
54 | * @BRCMF_P2P_STATUS_IF_DELETING: peer-to-peer vif delete sent to dongle. | ||
55 | * @BRCMF_P2P_STATUS_IF_CHANGING: peer-to-peer vif change sent to dongle. | ||
56 | * @BRCMF_P2P_STATUS_IF_CHANGED: peer-to-peer vif change completed on dongle. | ||
57 | * @BRCMF_P2P_STATUS_ACTION_TX_COMPLETED: action frame tx completed. | ||
58 | * @BRCMF_P2P_STATUS_ACTION_TX_NOACK: action frame tx not acked. | ||
59 | * @BRCMF_P2P_STATUS_GO_NEG_PHASE: P2P GO negotiation ongoing. | ||
60 | * @BRCMF_P2P_STATUS_DISCOVER_LISTEN: P2P listen, remaining on channel. | ||
61 | * @BRCMF_P2P_STATUS_SENDING_ACT_FRAME: In the process of sending action frame. | ||
62 | * @BRCMF_P2P_STATUS_WAITING_NEXT_AF_LISTEN: extra listen time for af tx. | ||
63 | * @BRCMF_P2P_STATUS_WAITING_NEXT_ACT_FRAME: waiting for action frame response. | ||
64 | * @BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL: search channel for AF active. | ||
65 | */ | ||
66 | enum brcmf_p2p_status { | ||
67 | BRCMF_P2P_STATUS_ENABLED, | ||
68 | BRCMF_P2P_STATUS_IF_ADD, | ||
69 | BRCMF_P2P_STATUS_IF_DEL, | ||
70 | BRCMF_P2P_STATUS_IF_DELETING, | ||
71 | BRCMF_P2P_STATUS_IF_CHANGING, | ||
72 | BRCMF_P2P_STATUS_IF_CHANGED, | ||
73 | BRCMF_P2P_STATUS_ACTION_TX_COMPLETED, | ||
74 | BRCMF_P2P_STATUS_ACTION_TX_NOACK, | ||
75 | BRCMF_P2P_STATUS_GO_NEG_PHASE, | ||
76 | BRCMF_P2P_STATUS_DISCOVER_LISTEN, | ||
77 | BRCMF_P2P_STATUS_SENDING_ACT_FRAME, | ||
78 | BRCMF_P2P_STATUS_WAITING_NEXT_AF_LISTEN, | ||
79 | BRCMF_P2P_STATUS_WAITING_NEXT_ACT_FRAME, | ||
80 | BRCMF_P2P_STATUS_FINDING_COMMON_CHANNEL | ||
81 | }; | ||
82 | |||
83 | /** | ||
84 | * struct afx_hdl - action frame off channel storage. | ||
85 | * | ||
86 | * @afx_work: worker thread for searching channel | ||
87 | * @act_frm_scan: thread synchronizing struct. | ||
88 | * @is_active: channel searching active. | ||
89 | * @peer_chan: current channel. | ||
90 | * @is_listen: sets mode for afx worker. | ||
91 | * @my_listen_chan: this peers listen channel. | ||
92 | * @peer_listen_chan: remote peers listen channel. | ||
93 | * @tx_dst_addr: mac address where tx af should be sent to. | ||
94 | */ | ||
95 | struct afx_hdl { | ||
96 | struct work_struct afx_work; | ||
97 | struct completion act_frm_scan; | ||
98 | bool is_active; | ||
99 | s32 peer_chan; | ||
100 | bool is_listen; | ||
101 | u16 my_listen_chan; | ||
102 | u16 peer_listen_chan; | ||
103 | u8 tx_dst_addr[ETH_ALEN]; | ||
104 | }; | ||
105 | |||
106 | /** | ||
107 | * struct brcmf_p2p_info - p2p specific driver information. | ||
108 | * | ||
109 | * @cfg: driver private data for cfg80211 interface. | ||
110 | * @status: status of P2P (see enum brcmf_p2p_status). | ||
111 | * @dev_addr: P2P device address. | ||
112 | * @int_addr: P2P interface address. | ||
113 | * @bss_idx: informate for P2P bss types. | ||
114 | * @listen_timer: timer for @WL_P2P_DISC_ST_LISTEN discover state. | ||
115 | * @ssid: ssid for P2P GO. | ||
116 | * @listen_channel: channel for @WL_P2P_DISC_ST_LISTEN discover state. | ||
117 | * @remain_on_channel: contains copy of struct used by cfg80211. | ||
118 | * @remain_on_channel_cookie: cookie counter for remain on channel cmd | ||
119 | * @next_af_subtype: expected action frame subtype. | ||
120 | * @send_af_done: indication that action frame tx is complete. | ||
121 | * @afx_hdl: action frame search handler info. | ||
122 | * @af_sent_channel: channel action frame is sent. | ||
123 | * @af_tx_sent_jiffies: jiffies time when af tx was transmitted. | ||
124 | * @wait_next_af: thread synchronizing struct. | ||
125 | * @gon_req_action: about to send go negotiation requets frame. | ||
126 | * @block_gon_req_tx: drop tx go negotiation requets frame. | ||
127 | */ | ||
128 | struct brcmf_p2p_info { | ||
129 | struct brcmf_cfg80211_info *cfg; | ||
130 | unsigned long status; | ||
131 | u8 dev_addr[ETH_ALEN]; | ||
132 | u8 int_addr[ETH_ALEN]; | ||
133 | struct p2p_bss bss_idx[P2PAPI_BSSCFG_MAX]; | ||
134 | struct timer_list listen_timer; | ||
135 | struct brcmf_ssid ssid; | ||
136 | u8 listen_channel; | ||
137 | struct ieee80211_channel remain_on_channel; | ||
138 | u32 remain_on_channel_cookie; | ||
139 | u8 next_af_subtype; | ||
140 | struct completion send_af_done; | ||
141 | struct afx_hdl afx_hdl; | ||
142 | u32 af_sent_channel; | ||
143 | unsigned long af_tx_sent_jiffies; | ||
144 | struct completion wait_next_af; | ||
145 | bool gon_req_action; | ||
146 | bool block_gon_req_tx; | ||
147 | }; | ||
148 | |||
149 | s32 brcmf_p2p_attach(struct brcmf_cfg80211_info *cfg); | ||
150 | void brcmf_p2p_detach(struct brcmf_p2p_info *p2p); | ||
151 | struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name, | ||
152 | enum nl80211_iftype type, u32 *flags, | ||
153 | struct vif_params *params); | ||
154 | int brcmf_p2p_del_vif(struct wiphy *wiphy, struct wireless_dev *wdev); | ||
155 | int brcmf_p2p_ifchange(struct brcmf_cfg80211_info *cfg, | ||
156 | enum brcmf_fil_p2p_if_types if_type); | ||
157 | int brcmf_p2p_start_device(struct wiphy *wiphy, struct wireless_dev *wdev); | ||
158 | void brcmf_p2p_stop_device(struct wiphy *wiphy, struct wireless_dev *wdev); | ||
159 | int brcmf_p2p_scan_prep(struct wiphy *wiphy, | ||
160 | struct cfg80211_scan_request *request, | ||
161 | struct brcmf_cfg80211_vif *vif); | ||
162 | int brcmf_p2p_remain_on_channel(struct wiphy *wiphy, struct wireless_dev *wdev, | ||
163 | struct ieee80211_channel *channel, | ||
164 | unsigned int duration, u64 *cookie); | ||
165 | int brcmf_p2p_notify_listen_complete(struct brcmf_if *ifp, | ||
166 | const struct brcmf_event_msg *e, | ||
167 | void *data); | ||
168 | void brcmf_p2p_cancel_remain_on_channel(struct brcmf_if *ifp); | ||
169 | int brcmf_p2p_notify_action_frame_rx(struct brcmf_if *ifp, | ||
170 | const struct brcmf_event_msg *e, | ||
171 | void *data); | ||
172 | int brcmf_p2p_notify_action_tx_complete(struct brcmf_if *ifp, | ||
173 | const struct brcmf_event_msg *e, | ||
174 | void *data); | ||
175 | bool brcmf_p2p_send_action_frame(struct brcmf_cfg80211_info *cfg, | ||
176 | struct net_device *ndev, | ||
177 | struct brcmf_fil_af_params_le *af_params); | ||
178 | bool brcmf_p2p_scan_finding_common_channel(struct brcmf_cfg80211_info *cfg, | ||
179 | struct brcmf_bss_info_le *bi); | ||
180 | s32 brcmf_p2p_notify_rx_mgmt_p2p_probereq(struct brcmf_if *ifp, | ||
181 | const struct brcmf_event_msg *e, | ||
182 | void *data); | ||
183 | #endif /* WL_CFGP2P_H_ */ | ||
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/brcm80211/brcmfmac/usb.c index bc5a042c9a96..42289e9ea886 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/usb.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/usb.c | |||
@@ -420,10 +420,6 @@ static void brcmf_usb_tx_complete(struct urb *urb) | |||
420 | brcmf_dbg(USB, "Enter, urb->status=%d, skb=%p\n", urb->status, | 420 | brcmf_dbg(USB, "Enter, urb->status=%d, skb=%p\n", urb->status, |
421 | req->skb); | 421 | req->skb); |
422 | brcmf_usb_del_fromq(devinfo, req); | 422 | brcmf_usb_del_fromq(devinfo, req); |
423 | if (urb->status == 0) | ||
424 | devinfo->bus_pub.bus->dstats.tx_packets++; | ||
425 | else | ||
426 | devinfo->bus_pub.bus->dstats.tx_errors++; | ||
427 | 423 | ||
428 | brcmf_txcomplete(devinfo->dev, req->skb, urb->status == 0); | 424 | brcmf_txcomplete(devinfo->dev, req->skb, urb->status == 0); |
429 | 425 | ||
@@ -450,10 +446,7 @@ static void brcmf_usb_rx_complete(struct urb *urb) | |||
450 | req->skb = NULL; | 446 | req->skb = NULL; |
451 | 447 | ||
452 | /* zero lenght packets indicate usb "failure". Do not refill */ | 448 | /* zero lenght packets indicate usb "failure". Do not refill */ |
453 | if (urb->status == 0 && urb->actual_length) { | 449 | if (urb->status != 0 || !urb->actual_length) { |
454 | devinfo->bus_pub.bus->dstats.rx_packets++; | ||
455 | } else { | ||
456 | devinfo->bus_pub.bus->dstats.rx_errors++; | ||
457 | brcmu_pkt_buf_free_skb(skb); | 450 | brcmu_pkt_buf_free_skb(skb); |
458 | brcmf_usb_enq(devinfo, &devinfo->rx_freeq, req, NULL); | 451 | brcmf_usb_enq(devinfo, &devinfo->rx_freeq, req, NULL); |
459 | return; | 452 | return; |
@@ -1256,6 +1249,8 @@ static int brcmf_usb_probe_cb(struct brcmf_usbdev_info *devinfo) | |||
1256 | bus->bus_priv.usb = bus_pub; | 1249 | bus->bus_priv.usb = bus_pub; |
1257 | dev_set_drvdata(dev, bus); | 1250 | dev_set_drvdata(dev, bus); |
1258 | bus->ops = &brcmf_usb_bus_ops; | 1251 | bus->ops = &brcmf_usb_bus_ops; |
1252 | bus->chip = bus_pub->devid; | ||
1253 | bus->chiprev = bus_pub->chiprev; | ||
1259 | 1254 | ||
1260 | /* Attach to the common driver interface */ | 1255 | /* Attach to the common driver interface */ |
1261 | ret = brcmf_attach(0, dev); | 1256 | ret = brcmf_attach(0, dev); |
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c index 62a528e8b958..cecc3eff72e9 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c | |||
@@ -26,6 +26,8 @@ | |||
26 | #include <brcmu_wifi.h> | 26 | #include <brcmu_wifi.h> |
27 | #include "dhd.h" | 27 | #include "dhd.h" |
28 | #include "dhd_dbg.h" | 28 | #include "dhd_dbg.h" |
29 | #include "fwil_types.h" | ||
30 | #include "p2p.h" | ||
29 | #include "wl_cfg80211.h" | 31 | #include "wl_cfg80211.h" |
30 | #include "fwil.h" | 32 | #include "fwil.h" |
31 | 33 | ||
@@ -41,16 +43,13 @@ | |||
41 | #define BRCMF_PNO_SCAN_COMPLETE 1 | 43 | #define BRCMF_PNO_SCAN_COMPLETE 1 |
42 | #define BRCMF_PNO_SCAN_INCOMPLETE 0 | 44 | #define BRCMF_PNO_SCAN_INCOMPLETE 0 |
43 | 45 | ||
44 | #define BRCMF_IFACE_MAX_CNT 2 | 46 | #define BRCMF_IFACE_MAX_CNT 3 |
45 | 47 | ||
46 | #define TLV_LEN_OFF 1 /* length offset */ | ||
47 | #define TLV_HDR_LEN 2 /* header length */ | ||
48 | #define TLV_BODY_OFF 2 /* body offset */ | ||
49 | #define TLV_OUI_LEN 3 /* oui id length */ | ||
50 | #define WPA_OUI "\x00\x50\xF2" /* WPA OUI */ | 48 | #define WPA_OUI "\x00\x50\xF2" /* WPA OUI */ |
51 | #define WPA_OUI_TYPE 1 | 49 | #define WPA_OUI_TYPE 1 |
52 | #define RSN_OUI "\x00\x0F\xAC" /* RSN OUI */ | 50 | #define RSN_OUI "\x00\x0F\xAC" /* RSN OUI */ |
53 | #define WME_OUI_TYPE 2 | 51 | #define WME_OUI_TYPE 2 |
52 | #define WPS_OUI_TYPE 4 | ||
54 | 53 | ||
55 | #define VS_IE_FIXED_HDR_LEN 6 | 54 | #define VS_IE_FIXED_HDR_LEN 6 |
56 | #define WPA_IE_VERSION_LEN 2 | 55 | #define WPA_IE_VERSION_LEN 2 |
@@ -76,13 +75,15 @@ | |||
76 | #define VNDR_IE_PKTFLAG_OFFSET 8 | 75 | #define VNDR_IE_PKTFLAG_OFFSET 8 |
77 | #define VNDR_IE_VSIE_OFFSET 12 | 76 | #define VNDR_IE_VSIE_OFFSET 12 |
78 | #define VNDR_IE_HDR_SIZE 12 | 77 | #define VNDR_IE_HDR_SIZE 12 |
79 | #define VNDR_IE_BEACON_FLAG 0x1 | 78 | #define VNDR_IE_PARSE_LIMIT 5 |
80 | #define VNDR_IE_PRBRSP_FLAG 0x2 | ||
81 | #define MAX_VNDR_IE_NUMBER 5 | ||
82 | 79 | ||
83 | #define DOT11_MGMT_HDR_LEN 24 /* d11 management header len */ | 80 | #define DOT11_MGMT_HDR_LEN 24 /* d11 management header len */ |
84 | #define DOT11_BCN_PRB_FIXED_LEN 12 /* beacon/probe fixed length */ | 81 | #define DOT11_BCN_PRB_FIXED_LEN 12 /* beacon/probe fixed length */ |
85 | 82 | ||
83 | #define BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS 320 | ||
84 | #define BRCMF_SCAN_JOIN_PASSIVE_DWELL_TIME_MS 400 | ||
85 | #define BRCMF_SCAN_JOIN_PROBE_INTERVAL_MS 20 | ||
86 | |||
86 | #define BRCMF_ASSOC_PARAMS_FIXED_SIZE \ | 87 | #define BRCMF_ASSOC_PARAMS_FIXED_SIZE \ |
87 | (sizeof(struct brcmf_assoc_params_le) - sizeof(u16)) | 88 | (sizeof(struct brcmf_assoc_params_le) - sizeof(u16)) |
88 | 89 | ||
@@ -271,13 +272,6 @@ static const u32 __wl_cipher_suites[] = { | |||
271 | WLAN_CIPHER_SUITE_AES_CMAC, | 272 | WLAN_CIPHER_SUITE_AES_CMAC, |
272 | }; | 273 | }; |
273 | 274 | ||
274 | /* tag_ID/length/value_buffer tuple */ | ||
275 | struct brcmf_tlv { | ||
276 | u8 id; | ||
277 | u8 len; | ||
278 | u8 data[1]; | ||
279 | }; | ||
280 | |||
281 | /* Vendor specific ie. id = 221, oui and type defines exact ie */ | 275 | /* Vendor specific ie. id = 221, oui and type defines exact ie */ |
282 | struct brcmf_vs_tlv { | 276 | struct brcmf_vs_tlv { |
283 | u8 id; | 277 | u8 id; |
@@ -294,7 +288,7 @@ struct parsed_vndr_ie_info { | |||
294 | 288 | ||
295 | struct parsed_vndr_ies { | 289 | struct parsed_vndr_ies { |
296 | u32 count; | 290 | u32 count; |
297 | struct parsed_vndr_ie_info ie_info[MAX_VNDR_IE_NUMBER]; | 291 | struct parsed_vndr_ie_info ie_info[VNDR_IE_PARSE_LIMIT]; |
298 | }; | 292 | }; |
299 | 293 | ||
300 | /* Quarter dBm units to mW | 294 | /* Quarter dBm units to mW |
@@ -381,7 +375,7 @@ static u8 brcmf_mw_to_qdbm(u16 mw) | |||
381 | return qdbm; | 375 | return qdbm; |
382 | } | 376 | } |
383 | 377 | ||
384 | static u16 channel_to_chanspec(struct ieee80211_channel *ch) | 378 | u16 channel_to_chanspec(struct ieee80211_channel *ch) |
385 | { | 379 | { |
386 | u16 chanspec; | 380 | u16 chanspec; |
387 | 381 | ||
@@ -393,19 +387,92 @@ static u16 channel_to_chanspec(struct ieee80211_channel *ch) | |||
393 | else | 387 | else |
394 | chanspec |= WL_CHANSPEC_BAND_5G; | 388 | chanspec |= WL_CHANSPEC_BAND_5G; |
395 | 389 | ||
396 | if (ch->flags & IEEE80211_CHAN_NO_HT40) { | 390 | chanspec |= WL_CHANSPEC_BW_20; |
397 | chanspec |= WL_CHANSPEC_BW_20; | 391 | chanspec |= WL_CHANSPEC_CTL_SB_NONE; |
398 | chanspec |= WL_CHANSPEC_CTL_SB_NONE; | 392 | |
399 | } else { | ||
400 | chanspec |= WL_CHANSPEC_BW_40; | ||
401 | if (ch->flags & IEEE80211_CHAN_NO_HT40PLUS) | ||
402 | chanspec |= WL_CHANSPEC_CTL_SB_LOWER; | ||
403 | else | ||
404 | chanspec |= WL_CHANSPEC_CTL_SB_UPPER; | ||
405 | } | ||
406 | return chanspec; | 393 | return chanspec; |
407 | } | 394 | } |
408 | 395 | ||
396 | /* Traverse a string of 1-byte tag/1-byte length/variable-length value | ||
397 | * triples, returning a pointer to the substring whose first element | ||
398 | * matches tag | ||
399 | */ | ||
400 | struct brcmf_tlv *brcmf_parse_tlvs(void *buf, int buflen, uint key) | ||
401 | { | ||
402 | struct brcmf_tlv *elt; | ||
403 | int totlen; | ||
404 | |||
405 | elt = (struct brcmf_tlv *)buf; | ||
406 | totlen = buflen; | ||
407 | |||
408 | /* find tagged parameter */ | ||
409 | while (totlen >= TLV_HDR_LEN) { | ||
410 | int len = elt->len; | ||
411 | |||
412 | /* validate remaining totlen */ | ||
413 | if ((elt->id == key) && (totlen >= (len + TLV_HDR_LEN))) | ||
414 | return elt; | ||
415 | |||
416 | elt = (struct brcmf_tlv *)((u8 *)elt + (len + TLV_HDR_LEN)); | ||
417 | totlen -= (len + TLV_HDR_LEN); | ||
418 | } | ||
419 | |||
420 | return NULL; | ||
421 | } | ||
422 | |||
423 | /* Is any of the tlvs the expected entry? If | ||
424 | * not update the tlvs buffer pointer/length. | ||
425 | */ | ||
426 | static bool | ||
427 | brcmf_tlv_has_ie(u8 *ie, u8 **tlvs, u32 *tlvs_len, | ||
428 | u8 *oui, u32 oui_len, u8 type) | ||
429 | { | ||
430 | /* If the contents match the OUI and the type */ | ||
431 | if (ie[TLV_LEN_OFF] >= oui_len + 1 && | ||
432 | !memcmp(&ie[TLV_BODY_OFF], oui, oui_len) && | ||
433 | type == ie[TLV_BODY_OFF + oui_len]) { | ||
434 | return true; | ||
435 | } | ||
436 | |||
437 | if (tlvs == NULL) | ||
438 | return false; | ||
439 | /* point to the next ie */ | ||
440 | ie += ie[TLV_LEN_OFF] + TLV_HDR_LEN; | ||
441 | /* calculate the length of the rest of the buffer */ | ||
442 | *tlvs_len -= (int)(ie - *tlvs); | ||
443 | /* update the pointer to the start of the buffer */ | ||
444 | *tlvs = ie; | ||
445 | |||
446 | return false; | ||
447 | } | ||
448 | |||
449 | static struct brcmf_vs_tlv * | ||
450 | brcmf_find_wpaie(u8 *parse, u32 len) | ||
451 | { | ||
452 | struct brcmf_tlv *ie; | ||
453 | |||
454 | while ((ie = brcmf_parse_tlvs(parse, len, WLAN_EID_VENDOR_SPECIFIC))) { | ||
455 | if (brcmf_tlv_has_ie((u8 *)ie, &parse, &len, | ||
456 | WPA_OUI, TLV_OUI_LEN, WPA_OUI_TYPE)) | ||
457 | return (struct brcmf_vs_tlv *)ie; | ||
458 | } | ||
459 | return NULL; | ||
460 | } | ||
461 | |||
462 | static struct brcmf_vs_tlv * | ||
463 | brcmf_find_wpsie(u8 *parse, u32 len) | ||
464 | { | ||
465 | struct brcmf_tlv *ie; | ||
466 | |||
467 | while ((ie = brcmf_parse_tlvs(parse, len, WLAN_EID_VENDOR_SPECIFIC))) { | ||
468 | if (brcmf_tlv_has_ie((u8 *)ie, &parse, &len, | ||
469 | WPA_OUI, TLV_OUI_LEN, WPS_OUI_TYPE)) | ||
470 | return (struct brcmf_vs_tlv *)ie; | ||
471 | } | ||
472 | return NULL; | ||
473 | } | ||
474 | |||
475 | |||
409 | static void convert_key_from_CPU(struct brcmf_wsec_key *key, | 476 | static void convert_key_from_CPU(struct brcmf_wsec_key *key, |
410 | struct brcmf_wsec_key_le *key_le) | 477 | struct brcmf_wsec_key_le *key_le) |
411 | { | 478 | { |
@@ -438,11 +505,153 @@ send_key_to_dongle(struct net_device *ndev, struct brcmf_wsec_key *key) | |||
438 | return err; | 505 | return err; |
439 | } | 506 | } |
440 | 507 | ||
508 | static struct wireless_dev *brcmf_cfg80211_add_iface(struct wiphy *wiphy, | ||
509 | const char *name, | ||
510 | enum nl80211_iftype type, | ||
511 | u32 *flags, | ||
512 | struct vif_params *params) | ||
513 | { | ||
514 | brcmf_dbg(TRACE, "enter: %s type %d\n", name, type); | ||
515 | switch (type) { | ||
516 | case NL80211_IFTYPE_ADHOC: | ||
517 | case NL80211_IFTYPE_STATION: | ||
518 | case NL80211_IFTYPE_AP: | ||
519 | case NL80211_IFTYPE_AP_VLAN: | ||
520 | case NL80211_IFTYPE_WDS: | ||
521 | case NL80211_IFTYPE_MONITOR: | ||
522 | case NL80211_IFTYPE_MESH_POINT: | ||
523 | return ERR_PTR(-EOPNOTSUPP); | ||
524 | case NL80211_IFTYPE_P2P_CLIENT: | ||
525 | case NL80211_IFTYPE_P2P_GO: | ||
526 | return brcmf_p2p_add_vif(wiphy, name, type, flags, params); | ||
527 | case NL80211_IFTYPE_UNSPECIFIED: | ||
528 | case NL80211_IFTYPE_P2P_DEVICE: | ||
529 | default: | ||
530 | return ERR_PTR(-EINVAL); | ||
531 | } | ||
532 | } | ||
533 | |||
534 | void brcmf_set_mpc(struct net_device *ndev, int mpc) | ||
535 | { | ||
536 | struct brcmf_if *ifp = netdev_priv(ndev); | ||
537 | s32 err = 0; | ||
538 | |||
539 | if (check_vif_up(ifp->vif)) { | ||
540 | err = brcmf_fil_iovar_int_set(ifp, "mpc", mpc); | ||
541 | if (err) { | ||
542 | brcmf_err("fail to set mpc\n"); | ||
543 | return; | ||
544 | } | ||
545 | brcmf_dbg(INFO, "MPC : %d\n", mpc); | ||
546 | } | ||
547 | } | ||
548 | |||
549 | s32 | ||
550 | brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg, | ||
551 | struct net_device *ndev, | ||
552 | bool aborted, bool fw_abort) | ||
553 | { | ||
554 | struct brcmf_scan_params_le params_le; | ||
555 | struct cfg80211_scan_request *scan_request; | ||
556 | s32 err = 0; | ||
557 | |||
558 | brcmf_dbg(SCAN, "Enter\n"); | ||
559 | |||
560 | /* clear scan request, because the FW abort can cause a second call */ | ||
561 | /* to this functon and might cause a double cfg80211_scan_done */ | ||
562 | scan_request = cfg->scan_request; | ||
563 | cfg->scan_request = NULL; | ||
564 | |||
565 | if (timer_pending(&cfg->escan_timeout)) | ||
566 | del_timer_sync(&cfg->escan_timeout); | ||
567 | |||
568 | if (fw_abort) { | ||
569 | /* Do a scan abort to stop the driver's scan engine */ | ||
570 | brcmf_dbg(SCAN, "ABORT scan in firmware\n"); | ||
571 | memset(¶ms_le, 0, sizeof(params_le)); | ||
572 | memset(params_le.bssid, 0xFF, ETH_ALEN); | ||
573 | params_le.bss_type = DOT11_BSSTYPE_ANY; | ||
574 | params_le.scan_type = 0; | ||
575 | params_le.channel_num = cpu_to_le32(1); | ||
576 | params_le.nprobes = cpu_to_le32(1); | ||
577 | params_le.active_time = cpu_to_le32(-1); | ||
578 | params_le.passive_time = cpu_to_le32(-1); | ||
579 | params_le.home_time = cpu_to_le32(-1); | ||
580 | /* Scan is aborted by setting channel_list[0] to -1 */ | ||
581 | params_le.channel_list[0] = cpu_to_le16(-1); | ||
582 | /* E-Scan (or anyother type) can be aborted by SCAN */ | ||
583 | err = brcmf_fil_cmd_data_set(netdev_priv(ndev), BRCMF_C_SCAN, | ||
584 | ¶ms_le, sizeof(params_le)); | ||
585 | if (err) | ||
586 | brcmf_err("Scan abort failed\n"); | ||
587 | } | ||
588 | /* | ||
589 | * e-scan can be initiated by scheduled scan | ||
590 | * which takes precedence. | ||
591 | */ | ||
592 | if (cfg->sched_escan) { | ||
593 | brcmf_dbg(SCAN, "scheduled scan completed\n"); | ||
594 | cfg->sched_escan = false; | ||
595 | if (!aborted) | ||
596 | cfg80211_sched_scan_results(cfg_to_wiphy(cfg)); | ||
597 | brcmf_set_mpc(ndev, 1); | ||
598 | } else if (scan_request) { | ||
599 | brcmf_dbg(SCAN, "ESCAN Completed scan: %s\n", | ||
600 | aborted ? "Aborted" : "Done"); | ||
601 | cfg80211_scan_done(scan_request, aborted); | ||
602 | brcmf_set_mpc(ndev, 1); | ||
603 | } | ||
604 | if (!test_and_clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) | ||
605 | brcmf_dbg(SCAN, "Scan complete, probably P2P scan\n"); | ||
606 | |||
607 | return err; | ||
608 | } | ||
609 | |||
610 | static | ||
611 | int brcmf_cfg80211_del_iface(struct wiphy *wiphy, struct wireless_dev *wdev) | ||
612 | { | ||
613 | struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy); | ||
614 | struct net_device *ndev = wdev->netdev; | ||
615 | |||
616 | /* vif event pending in firmware */ | ||
617 | if (brcmf_cfg80211_vif_event_armed(cfg)) | ||
618 | return -EBUSY; | ||
619 | |||
620 | if (ndev) { | ||
621 | if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status) && | ||
622 | cfg->escan_info.ndev == ndev) | ||
623 | brcmf_notify_escan_complete(cfg, ndev, true, | ||
624 | true); | ||
625 | |||
626 | brcmf_fil_iovar_int_set(netdev_priv(ndev), "mpc", 1); | ||
627 | } | ||
628 | |||
629 | switch (wdev->iftype) { | ||
630 | case NL80211_IFTYPE_ADHOC: | ||
631 | case NL80211_IFTYPE_STATION: | ||
632 | case NL80211_IFTYPE_AP: | ||
633 | case NL80211_IFTYPE_AP_VLAN: | ||
634 | case NL80211_IFTYPE_WDS: | ||
635 | case NL80211_IFTYPE_MONITOR: | ||
636 | case NL80211_IFTYPE_MESH_POINT: | ||
637 | return -EOPNOTSUPP; | ||
638 | case NL80211_IFTYPE_P2P_CLIENT: | ||
639 | case NL80211_IFTYPE_P2P_GO: | ||
640 | return brcmf_p2p_del_vif(wiphy, wdev); | ||
641 | case NL80211_IFTYPE_UNSPECIFIED: | ||
642 | case NL80211_IFTYPE_P2P_DEVICE: | ||
643 | default: | ||
644 | return -EINVAL; | ||
645 | } | ||
646 | return -EOPNOTSUPP; | ||
647 | } | ||
648 | |||
441 | static s32 | 649 | static s32 |
442 | brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev, | 650 | brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev, |
443 | enum nl80211_iftype type, u32 *flags, | 651 | enum nl80211_iftype type, u32 *flags, |
444 | struct vif_params *params) | 652 | struct vif_params *params) |
445 | { | 653 | { |
654 | struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy); | ||
446 | struct brcmf_if *ifp = netdev_priv(ndev); | 655 | struct brcmf_if *ifp = netdev_priv(ndev); |
447 | struct brcmf_cfg80211_vif *vif = ifp->vif; | 656 | struct brcmf_cfg80211_vif *vif = ifp->vif; |
448 | s32 infra = 0; | 657 | s32 infra = 0; |
@@ -462,10 +671,23 @@ brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev, | |||
462 | infra = 0; | 671 | infra = 0; |
463 | break; | 672 | break; |
464 | case NL80211_IFTYPE_STATION: | 673 | case NL80211_IFTYPE_STATION: |
674 | /* Ignore change for p2p IF. Unclear why supplicant does this */ | ||
675 | if ((vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT) || | ||
676 | (vif->wdev.iftype == NL80211_IFTYPE_P2P_GO)) { | ||
677 | brcmf_dbg(TRACE, "Ignoring cmd for p2p if\n"); | ||
678 | /* WAR: It is unexpected to get a change of VIF for P2P | ||
679 | * IF, but it happens. The request can not be handled | ||
680 | * but returning EPERM causes a crash. Returning 0 | ||
681 | * without setting ieee80211_ptr->iftype causes trace | ||
682 | * (WARN_ON) but it works with wpa_supplicant | ||
683 | */ | ||
684 | return 0; | ||
685 | } | ||
465 | vif->mode = WL_MODE_BSS; | 686 | vif->mode = WL_MODE_BSS; |
466 | infra = 1; | 687 | infra = 1; |
467 | break; | 688 | break; |
468 | case NL80211_IFTYPE_AP: | 689 | case NL80211_IFTYPE_AP: |
690 | case NL80211_IFTYPE_P2P_GO: | ||
469 | vif->mode = WL_MODE_AP; | 691 | vif->mode = WL_MODE_AP; |
470 | ap = 1; | 692 | ap = 1; |
471 | break; | 693 | break; |
@@ -475,8 +697,14 @@ brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev, | |||
475 | } | 697 | } |
476 | 698 | ||
477 | if (ap) { | 699 | if (ap) { |
478 | set_bit(BRCMF_VIF_STATUS_AP_CREATING, &vif->sme_state); | 700 | if (type == NL80211_IFTYPE_P2P_GO) { |
479 | brcmf_dbg(INFO, "IF Type = AP\n"); | 701 | brcmf_dbg(INFO, "IF Type = P2P GO\n"); |
702 | err = brcmf_p2p_ifchange(cfg, BRCMF_FIL_P2P_IF_GO); | ||
703 | } | ||
704 | if (!err) { | ||
705 | set_bit(BRCMF_VIF_STATUS_AP_CREATING, &vif->sme_state); | ||
706 | brcmf_dbg(INFO, "IF Type = AP\n"); | ||
707 | } | ||
480 | } else { | 708 | } else { |
481 | err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, infra); | 709 | err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, infra); |
482 | if (err) { | 710 | if (err) { |
@@ -495,21 +723,6 @@ done: | |||
495 | return err; | 723 | return err; |
496 | } | 724 | } |
497 | 725 | ||
498 | static void brcmf_set_mpc(struct net_device *ndev, int mpc) | ||
499 | { | ||
500 | struct brcmf_if *ifp = netdev_priv(ndev); | ||
501 | s32 err = 0; | ||
502 | |||
503 | if (check_vif_up(ifp->vif)) { | ||
504 | err = brcmf_fil_iovar_int_set(ifp, "mpc", mpc); | ||
505 | if (err) { | ||
506 | brcmf_err("fail to set mpc\n"); | ||
507 | return; | ||
508 | } | ||
509 | brcmf_dbg(INFO, "MPC : %d\n", mpc); | ||
510 | } | ||
511 | } | ||
512 | |||
513 | static void brcmf_escan_prep(struct brcmf_scan_params_le *params_le, | 726 | static void brcmf_escan_prep(struct brcmf_scan_params_le *params_le, |
514 | struct cfg80211_scan_request *request) | 727 | struct cfg80211_scan_request *request) |
515 | { | 728 | { |
@@ -590,69 +803,6 @@ static void brcmf_escan_prep(struct brcmf_scan_params_le *params_le, | |||
590 | } | 803 | } |
591 | 804 | ||
592 | static s32 | 805 | static s32 |
593 | brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg, | ||
594 | struct net_device *ndev, | ||
595 | bool aborted, bool fw_abort) | ||
596 | { | ||
597 | struct brcmf_scan_params_le params_le; | ||
598 | struct cfg80211_scan_request *scan_request; | ||
599 | s32 err = 0; | ||
600 | |||
601 | brcmf_dbg(SCAN, "Enter\n"); | ||
602 | |||
603 | /* clear scan request, because the FW abort can cause a second call */ | ||
604 | /* to this functon and might cause a double cfg80211_scan_done */ | ||
605 | scan_request = cfg->scan_request; | ||
606 | cfg->scan_request = NULL; | ||
607 | |||
608 | if (timer_pending(&cfg->escan_timeout)) | ||
609 | del_timer_sync(&cfg->escan_timeout); | ||
610 | |||
611 | if (fw_abort) { | ||
612 | /* Do a scan abort to stop the driver's scan engine */ | ||
613 | brcmf_dbg(SCAN, "ABORT scan in firmware\n"); | ||
614 | memset(¶ms_le, 0, sizeof(params_le)); | ||
615 | memset(params_le.bssid, 0xFF, ETH_ALEN); | ||
616 | params_le.bss_type = DOT11_BSSTYPE_ANY; | ||
617 | params_le.scan_type = 0; | ||
618 | params_le.channel_num = cpu_to_le32(1); | ||
619 | params_le.nprobes = cpu_to_le32(1); | ||
620 | params_le.active_time = cpu_to_le32(-1); | ||
621 | params_le.passive_time = cpu_to_le32(-1); | ||
622 | params_le.home_time = cpu_to_le32(-1); | ||
623 | /* Scan is aborted by setting channel_list[0] to -1 */ | ||
624 | params_le.channel_list[0] = cpu_to_le16(-1); | ||
625 | /* E-Scan (or anyother type) can be aborted by SCAN */ | ||
626 | err = brcmf_fil_cmd_data_set(netdev_priv(ndev), BRCMF_C_SCAN, | ||
627 | ¶ms_le, sizeof(params_le)); | ||
628 | if (err) | ||
629 | brcmf_err("Scan abort failed\n"); | ||
630 | } | ||
631 | /* | ||
632 | * e-scan can be initiated by scheduled scan | ||
633 | * which takes precedence. | ||
634 | */ | ||
635 | if (cfg->sched_escan) { | ||
636 | brcmf_dbg(SCAN, "scheduled scan completed\n"); | ||
637 | cfg->sched_escan = false; | ||
638 | if (!aborted) | ||
639 | cfg80211_sched_scan_results(cfg_to_wiphy(cfg)); | ||
640 | brcmf_set_mpc(ndev, 1); | ||
641 | } else if (scan_request) { | ||
642 | brcmf_dbg(SCAN, "ESCAN Completed scan: %s\n", | ||
643 | aborted ? "Aborted" : "Done"); | ||
644 | cfg80211_scan_done(scan_request, aborted); | ||
645 | brcmf_set_mpc(ndev, 1); | ||
646 | } | ||
647 | if (!test_and_clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) { | ||
648 | brcmf_err("Scan complete while device not scanning\n"); | ||
649 | return -EPERM; | ||
650 | } | ||
651 | |||
652 | return err; | ||
653 | } | ||
654 | |||
655 | static s32 | ||
656 | brcmf_run_escan(struct brcmf_cfg80211_info *cfg, struct net_device *ndev, | 806 | brcmf_run_escan(struct brcmf_cfg80211_info *cfg, struct net_device *ndev, |
657 | struct cfg80211_scan_request *request, u16 action) | 807 | struct cfg80211_scan_request *request, u16 action) |
658 | { | 808 | { |
@@ -703,11 +853,12 @@ brcmf_do_escan(struct brcmf_cfg80211_info *cfg, struct wiphy *wiphy, | |||
703 | s32 err; | 853 | s32 err; |
704 | u32 passive_scan; | 854 | u32 passive_scan; |
705 | struct brcmf_scan_results *results; | 855 | struct brcmf_scan_results *results; |
856 | struct escan_info *escan = &cfg->escan_info; | ||
706 | 857 | ||
707 | brcmf_dbg(SCAN, "Enter\n"); | 858 | brcmf_dbg(SCAN, "Enter\n"); |
708 | cfg->escan_info.ndev = ndev; | 859 | escan->ndev = ndev; |
709 | cfg->escan_info.wiphy = wiphy; | 860 | escan->wiphy = wiphy; |
710 | cfg->escan_info.escan_state = WL_ESCAN_STATE_SCANNING; | 861 | escan->escan_state = WL_ESCAN_STATE_SCANNING; |
711 | passive_scan = cfg->active_scan ? 0 : 1; | 862 | passive_scan = cfg->active_scan ? 0 : 1; |
712 | err = brcmf_fil_cmd_int_set(netdev_priv(ndev), BRCMF_C_SET_PASSIVE_SCAN, | 863 | err = brcmf_fil_cmd_int_set(netdev_priv(ndev), BRCMF_C_SET_PASSIVE_SCAN, |
713 | passive_scan); | 864 | passive_scan); |
@@ -721,7 +872,7 @@ brcmf_do_escan(struct brcmf_cfg80211_info *cfg, struct wiphy *wiphy, | |||
721 | results->count = 0; | 872 | results->count = 0; |
722 | results->buflen = WL_ESCAN_RESULTS_FIXED_SIZE; | 873 | results->buflen = WL_ESCAN_RESULTS_FIXED_SIZE; |
723 | 874 | ||
724 | err = brcmf_run_escan(cfg, ndev, request, WL_ESCAN_ACTION_START); | 875 | err = escan->run(cfg, ndev, request, WL_ESCAN_ACTION_START); |
725 | if (err) | 876 | if (err) |
726 | brcmf_set_mpc(ndev, 1); | 877 | brcmf_set_mpc(ndev, 1); |
727 | return err; | 878 | return err; |
@@ -758,6 +909,12 @@ brcmf_cfg80211_escan(struct wiphy *wiphy, struct net_device *ndev, | |||
758 | return -EAGAIN; | 909 | return -EAGAIN; |
759 | } | 910 | } |
760 | 911 | ||
912 | /* If scan req comes for p2p0, send it over primary I/F */ | ||
913 | if (ifp->vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif) { | ||
914 | ifp = cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp; | ||
915 | ndev = ifp->ndev; | ||
916 | } | ||
917 | |||
761 | /* Arm scan timeout timer */ | 918 | /* Arm scan timeout timer */ |
762 | mod_timer(&cfg->escan_timeout, jiffies + | 919 | mod_timer(&cfg->escan_timeout, jiffies + |
763 | WL_ESCAN_TIMER_INTERVAL_MS * HZ / 1000); | 920 | WL_ESCAN_TIMER_INTERVAL_MS * HZ / 1000); |
@@ -776,6 +933,11 @@ brcmf_cfg80211_escan(struct wiphy *wiphy, struct net_device *ndev, | |||
776 | cfg->scan_request = request; | 933 | cfg->scan_request = request; |
777 | set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status); | 934 | set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status); |
778 | if (escan_req) { | 935 | if (escan_req) { |
936 | cfg->escan_info.run = brcmf_run_escan; | ||
937 | err = brcmf_p2p_scan_prep(wiphy, request, ifp->vif); | ||
938 | if (err) | ||
939 | goto scan_out; | ||
940 | |||
779 | err = brcmf_do_escan(cfg, wiphy, ndev, request); | 941 | err = brcmf_do_escan(cfg, wiphy, ndev, request); |
780 | if (err) | 942 | if (err) |
781 | goto scan_out; | 943 | goto scan_out; |
@@ -933,31 +1095,6 @@ static void brcmf_init_prof(struct brcmf_cfg80211_profile *prof) | |||
933 | memset(prof, 0, sizeof(*prof)); | 1095 | memset(prof, 0, sizeof(*prof)); |
934 | } | 1096 | } |
935 | 1097 | ||
936 | static void brcmf_ch_to_chanspec(int ch, struct brcmf_join_params *join_params, | ||
937 | size_t *join_params_size) | ||
938 | { | ||
939 | u16 chanspec = 0; | ||
940 | |||
941 | if (ch != 0) { | ||
942 | if (ch <= CH_MAX_2G_CHANNEL) | ||
943 | chanspec |= WL_CHANSPEC_BAND_2G; | ||
944 | else | ||
945 | chanspec |= WL_CHANSPEC_BAND_5G; | ||
946 | |||
947 | chanspec |= WL_CHANSPEC_BW_20; | ||
948 | chanspec |= WL_CHANSPEC_CTL_SB_NONE; | ||
949 | |||
950 | *join_params_size += BRCMF_ASSOC_PARAMS_FIXED_SIZE + | ||
951 | sizeof(u16); | ||
952 | |||
953 | chanspec |= (ch & WL_CHANSPEC_CHAN_MASK); | ||
954 | join_params->params_le.chanspec_list[0] = cpu_to_le16(chanspec); | ||
955 | join_params->params_le.chanspec_num = cpu_to_le32(1); | ||
956 | |||
957 | brcmf_dbg(CONN, "channel %d, chanspec %#X\n", ch, chanspec); | ||
958 | } | ||
959 | } | ||
960 | |||
961 | static void brcmf_link_down(struct brcmf_cfg80211_vif *vif) | 1098 | static void brcmf_link_down(struct brcmf_cfg80211_vif *vif) |
962 | { | 1099 | { |
963 | s32 err = 0; | 1100 | s32 err = 0; |
@@ -988,6 +1125,7 @@ brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev, | |||
988 | s32 err = 0; | 1125 | s32 err = 0; |
989 | s32 wsec = 0; | 1126 | s32 wsec = 0; |
990 | s32 bcnprd; | 1127 | s32 bcnprd; |
1128 | u16 chanspec; | ||
991 | 1129 | ||
992 | brcmf_dbg(TRACE, "Enter\n"); | 1130 | brcmf_dbg(TRACE, "Enter\n"); |
993 | if (!check_vif_up(ifp->vif)) | 1131 | if (!check_vif_up(ifp->vif)) |
@@ -1091,8 +1229,11 @@ brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev, | |||
1091 | params->chandef.chan->center_freq); | 1229 | params->chandef.chan->center_freq); |
1092 | if (params->channel_fixed) { | 1230 | if (params->channel_fixed) { |
1093 | /* adding chanspec */ | 1231 | /* adding chanspec */ |
1094 | brcmf_ch_to_chanspec(cfg->channel, | 1232 | chanspec = channel_to_chanspec(params->chandef.chan); |
1095 | &join_params, &join_params_size); | 1233 | join_params.params_le.chanspec_list[0] = |
1234 | cpu_to_le16(chanspec); | ||
1235 | join_params.params_le.chanspec_num = cpu_to_le32(1); | ||
1236 | join_params_size += sizeof(join_params.params_le); | ||
1096 | } | 1237 | } |
1097 | 1238 | ||
1098 | /* set channel for starter */ | 1239 | /* set channel for starter */ |
@@ -1155,7 +1296,7 @@ static s32 brcmf_set_wpa_version(struct net_device *ndev, | |||
1155 | else | 1296 | else |
1156 | val = WPA_AUTH_DISABLED; | 1297 | val = WPA_AUTH_DISABLED; |
1157 | brcmf_dbg(CONN, "setting wpa_auth to 0x%0x\n", val); | 1298 | brcmf_dbg(CONN, "setting wpa_auth to 0x%0x\n", val); |
1158 | err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "wpa_auth", val); | 1299 | err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wpa_auth", val); |
1159 | if (err) { | 1300 | if (err) { |
1160 | brcmf_err("set wpa_auth failed (%d)\n", err); | 1301 | brcmf_err("set wpa_auth failed (%d)\n", err); |
1161 | return err; | 1302 | return err; |
@@ -1194,7 +1335,7 @@ static s32 brcmf_set_auth_type(struct net_device *ndev, | |||
1194 | break; | 1335 | break; |
1195 | } | 1336 | } |
1196 | 1337 | ||
1197 | err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "auth", val); | 1338 | err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "auth", val); |
1198 | if (err) { | 1339 | if (err) { |
1199 | brcmf_err("set auth failed (%d)\n", err); | 1340 | brcmf_err("set auth failed (%d)\n", err); |
1200 | return err; | 1341 | return err; |
@@ -1258,7 +1399,12 @@ brcmf_set_set_cipher(struct net_device *ndev, | |||
1258 | } | 1399 | } |
1259 | 1400 | ||
1260 | brcmf_dbg(CONN, "pval (%d) gval (%d)\n", pval, gval); | 1401 | brcmf_dbg(CONN, "pval (%d) gval (%d)\n", pval, gval); |
1261 | err = brcmf_fil_iovar_int_set(netdev_priv(ndev), "wsec", pval | gval); | 1402 | /* In case of privacy, but no security and WPS then simulate */ |
1403 | /* setting AES. WPS-2.0 allows no security */ | ||
1404 | if (brcmf_find_wpsie(sme->ie, sme->ie_len) && !pval && !gval && | ||
1405 | sme->privacy) | ||
1406 | pval = AES_ENABLED; | ||
1407 | err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wsec", pval | gval); | ||
1262 | if (err) { | 1408 | if (err) { |
1263 | brcmf_err("error (%d)\n", err); | 1409 | brcmf_err("error (%d)\n", err); |
1264 | return err; | 1410 | return err; |
@@ -1280,8 +1426,8 @@ brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme) | |||
1280 | s32 err = 0; | 1426 | s32 err = 0; |
1281 | 1427 | ||
1282 | if (sme->crypto.n_akm_suites) { | 1428 | if (sme->crypto.n_akm_suites) { |
1283 | err = brcmf_fil_iovar_int_get(netdev_priv(ndev), | 1429 | err = brcmf_fil_bsscfg_int_get(netdev_priv(ndev), |
1284 | "wpa_auth", &val); | 1430 | "wpa_auth", &val); |
1285 | if (err) { | 1431 | if (err) { |
1286 | brcmf_err("could not get wpa_auth (%d)\n", err); | 1432 | brcmf_err("could not get wpa_auth (%d)\n", err); |
1287 | return err; | 1433 | return err; |
@@ -1315,8 +1461,8 @@ brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme) | |||
1315 | } | 1461 | } |
1316 | 1462 | ||
1317 | brcmf_dbg(CONN, "setting wpa_auth to %d\n", val); | 1463 | brcmf_dbg(CONN, "setting wpa_auth to %d\n", val); |
1318 | err = brcmf_fil_iovar_int_set(netdev_priv(ndev), | 1464 | err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), |
1319 | "wpa_auth", val); | 1465 | "wpa_auth", val); |
1320 | if (err) { | 1466 | if (err) { |
1321 | brcmf_err("could not set wpa_auth (%d)\n", err); | 1467 | brcmf_err("could not set wpa_auth (%d)\n", err); |
1322 | return err; | 1468 | return err; |
@@ -1393,9 +1539,28 @@ brcmf_set_sharedkey(struct net_device *ndev, | |||
1393 | return err; | 1539 | return err; |
1394 | } | 1540 | } |
1395 | 1541 | ||
1542 | static | ||
1543 | enum nl80211_auth_type brcmf_war_auth_type(struct brcmf_if *ifp, | ||
1544 | enum nl80211_auth_type type) | ||
1545 | { | ||
1546 | u32 ci; | ||
1547 | if (type == NL80211_AUTHTYPE_AUTOMATIC) { | ||
1548 | /* shift to ignore chip revision */ | ||
1549 | ci = brcmf_get_chip_info(ifp) >> 4; | ||
1550 | switch (ci) { | ||
1551 | case 43236: | ||
1552 | brcmf_dbg(CONN, "43236 WAR: use OPEN instead of AUTO\n"); | ||
1553 | return NL80211_AUTHTYPE_OPEN_SYSTEM; | ||
1554 | default: | ||
1555 | break; | ||
1556 | } | ||
1557 | } | ||
1558 | return type; | ||
1559 | } | ||
1560 | |||
1396 | static s32 | 1561 | static s32 |
1397 | brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev, | 1562 | brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev, |
1398 | struct cfg80211_connect_params *sme) | 1563 | struct cfg80211_connect_params *sme) |
1399 | { | 1564 | { |
1400 | struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); | 1565 | struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); |
1401 | struct brcmf_if *ifp = netdev_priv(ndev); | 1566 | struct brcmf_if *ifp = netdev_priv(ndev); |
@@ -1403,7 +1568,12 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev, | |||
1403 | struct ieee80211_channel *chan = sme->channel; | 1568 | struct ieee80211_channel *chan = sme->channel; |
1404 | struct brcmf_join_params join_params; | 1569 | struct brcmf_join_params join_params; |
1405 | size_t join_params_size; | 1570 | size_t join_params_size; |
1406 | struct brcmf_ssid ssid; | 1571 | struct brcmf_tlv *rsn_ie; |
1572 | struct brcmf_vs_tlv *wpa_ie; | ||
1573 | void *ie; | ||
1574 | u32 ie_len; | ||
1575 | struct brcmf_ext_join_params_le *ext_join_params; | ||
1576 | u16 chanspec; | ||
1407 | 1577 | ||
1408 | s32 err = 0; | 1578 | s32 err = 0; |
1409 | 1579 | ||
@@ -1416,15 +1586,46 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev, | |||
1416 | return -EOPNOTSUPP; | 1586 | return -EOPNOTSUPP; |
1417 | } | 1587 | } |
1418 | 1588 | ||
1589 | if (ifp->vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif) { | ||
1590 | /* A normal (non P2P) connection request setup. */ | ||
1591 | ie = NULL; | ||
1592 | ie_len = 0; | ||
1593 | /* find the WPA_IE */ | ||
1594 | wpa_ie = brcmf_find_wpaie((u8 *)sme->ie, sme->ie_len); | ||
1595 | if (wpa_ie) { | ||
1596 | ie = wpa_ie; | ||
1597 | ie_len = wpa_ie->len + TLV_HDR_LEN; | ||
1598 | } else { | ||
1599 | /* find the RSN_IE */ | ||
1600 | rsn_ie = brcmf_parse_tlvs((u8 *)sme->ie, sme->ie_len, | ||
1601 | WLAN_EID_RSN); | ||
1602 | if (rsn_ie) { | ||
1603 | ie = rsn_ie; | ||
1604 | ie_len = rsn_ie->len + TLV_HDR_LEN; | ||
1605 | } | ||
1606 | } | ||
1607 | brcmf_fil_iovar_data_set(ifp, "wpaie", ie, ie_len); | ||
1608 | } | ||
1609 | |||
1610 | err = brcmf_vif_set_mgmt_ie(ifp->vif, BRCMF_VNDR_IE_ASSOCREQ_FLAG, | ||
1611 | sme->ie, sme->ie_len); | ||
1612 | if (err) | ||
1613 | brcmf_err("Set Assoc REQ IE Failed\n"); | ||
1614 | else | ||
1615 | brcmf_dbg(TRACE, "Applied Vndr IEs for Assoc request\n"); | ||
1616 | |||
1419 | set_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state); | 1617 | set_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state); |
1420 | 1618 | ||
1421 | if (chan) { | 1619 | if (chan) { |
1422 | cfg->channel = | 1620 | cfg->channel = |
1423 | ieee80211_frequency_to_channel(chan->center_freq); | 1621 | ieee80211_frequency_to_channel(chan->center_freq); |
1424 | brcmf_dbg(CONN, "channel (%d), center_req (%d)\n", | 1622 | chanspec = channel_to_chanspec(chan); |
1425 | cfg->channel, chan->center_freq); | 1623 | brcmf_dbg(CONN, "channel=%d, center_req=%d, chanspec=0x%04x\n", |
1426 | } else | 1624 | cfg->channel, chan->center_freq, chanspec); |
1625 | } else { | ||
1427 | cfg->channel = 0; | 1626 | cfg->channel = 0; |
1627 | chanspec = 0; | ||
1628 | } | ||
1428 | 1629 | ||
1429 | brcmf_dbg(INFO, "ie (%p), ie_len (%zd)\n", sme->ie, sme->ie_len); | 1630 | brcmf_dbg(INFO, "ie (%p), ie_len (%zd)\n", sme->ie, sme->ie_len); |
1430 | 1631 | ||
@@ -1434,6 +1635,7 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev, | |||
1434 | goto done; | 1635 | goto done; |
1435 | } | 1636 | } |
1436 | 1637 | ||
1638 | sme->auth_type = brcmf_war_auth_type(ifp, sme->auth_type); | ||
1437 | err = brcmf_set_auth_type(ndev, sme); | 1639 | err = brcmf_set_auth_type(ndev, sme); |
1438 | if (err) { | 1640 | if (err) { |
1439 | brcmf_err("wl_set_auth_type failed (%d)\n", err); | 1641 | brcmf_err("wl_set_auth_type failed (%d)\n", err); |
@@ -1458,27 +1660,88 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev, | |||
1458 | goto done; | 1660 | goto done; |
1459 | } | 1661 | } |
1460 | 1662 | ||
1663 | profile->ssid.SSID_len = min_t(u32, (u32)sizeof(profile->ssid.SSID), | ||
1664 | (u32)sme->ssid_len); | ||
1665 | memcpy(&profile->ssid.SSID, sme->ssid, profile->ssid.SSID_len); | ||
1666 | if (profile->ssid.SSID_len < IEEE80211_MAX_SSID_LEN) { | ||
1667 | profile->ssid.SSID[profile->ssid.SSID_len] = 0; | ||
1668 | brcmf_dbg(CONN, "SSID \"%s\", len (%d)\n", profile->ssid.SSID, | ||
1669 | profile->ssid.SSID_len); | ||
1670 | } | ||
1671 | |||
1672 | /* Join with specific BSSID and cached SSID | ||
1673 | * If SSID is zero join based on BSSID only | ||
1674 | */ | ||
1675 | join_params_size = offsetof(struct brcmf_ext_join_params_le, assoc_le) + | ||
1676 | offsetof(struct brcmf_assoc_params_le, chanspec_list); | ||
1677 | if (cfg->channel) | ||
1678 | join_params_size += sizeof(u16); | ||
1679 | ext_join_params = kzalloc(join_params_size, GFP_KERNEL); | ||
1680 | if (ext_join_params == NULL) { | ||
1681 | err = -ENOMEM; | ||
1682 | goto done; | ||
1683 | } | ||
1684 | ext_join_params->ssid_le.SSID_len = cpu_to_le32(profile->ssid.SSID_len); | ||
1685 | memcpy(&ext_join_params->ssid_le.SSID, sme->ssid, | ||
1686 | profile->ssid.SSID_len); | ||
1687 | /*increase dwell time to receive probe response or detect Beacon | ||
1688 | * from target AP at a noisy air only during connect command | ||
1689 | */ | ||
1690 | ext_join_params->scan_le.active_time = | ||
1691 | cpu_to_le32(BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS); | ||
1692 | ext_join_params->scan_le.passive_time = | ||
1693 | cpu_to_le32(BRCMF_SCAN_JOIN_PASSIVE_DWELL_TIME_MS); | ||
1694 | /* Set up join scan parameters */ | ||
1695 | ext_join_params->scan_le.scan_type = -1; | ||
1696 | /* to sync with presence period of VSDB GO. | ||
1697 | * Send probe request more frequently. Probe request will be stopped | ||
1698 | * when it gets probe response from target AP/GO. | ||
1699 | */ | ||
1700 | ext_join_params->scan_le.nprobes = | ||
1701 | cpu_to_le32(BRCMF_SCAN_JOIN_ACTIVE_DWELL_TIME_MS / | ||
1702 | BRCMF_SCAN_JOIN_PROBE_INTERVAL_MS); | ||
1703 | ext_join_params->scan_le.home_time = cpu_to_le32(-1); | ||
1704 | |||
1705 | if (sme->bssid) | ||
1706 | memcpy(&ext_join_params->assoc_le.bssid, sme->bssid, ETH_ALEN); | ||
1707 | else | ||
1708 | memset(&ext_join_params->assoc_le.bssid, 0xFF, ETH_ALEN); | ||
1709 | |||
1710 | if (cfg->channel) { | ||
1711 | ext_join_params->assoc_le.chanspec_num = cpu_to_le32(1); | ||
1712 | |||
1713 | ext_join_params->assoc_le.chanspec_list[0] = | ||
1714 | cpu_to_le16(chanspec); | ||
1715 | } | ||
1716 | |||
1717 | err = brcmf_fil_bsscfg_data_set(ifp, "join", ext_join_params, | ||
1718 | join_params_size); | ||
1719 | kfree(ext_join_params); | ||
1720 | if (!err) | ||
1721 | /* This is it. join command worked, we are done */ | ||
1722 | goto done; | ||
1723 | |||
1724 | /* join command failed, fallback to set ssid */ | ||
1461 | memset(&join_params, 0, sizeof(join_params)); | 1725 | memset(&join_params, 0, sizeof(join_params)); |
1462 | join_params_size = sizeof(join_params.ssid_le); | 1726 | join_params_size = sizeof(join_params.ssid_le); |
1463 | 1727 | ||
1464 | profile->ssid.SSID_len = min_t(u32, | ||
1465 | sizeof(ssid.SSID), (u32)sme->ssid_len); | ||
1466 | memcpy(&join_params.ssid_le.SSID, sme->ssid, profile->ssid.SSID_len); | 1728 | memcpy(&join_params.ssid_le.SSID, sme->ssid, profile->ssid.SSID_len); |
1467 | memcpy(&profile->ssid.SSID, sme->ssid, profile->ssid.SSID_len); | ||
1468 | join_params.ssid_le.SSID_len = cpu_to_le32(profile->ssid.SSID_len); | 1729 | join_params.ssid_le.SSID_len = cpu_to_le32(profile->ssid.SSID_len); |
1469 | 1730 | ||
1470 | memset(join_params.params_le.bssid, 0xFF, ETH_ALEN); | 1731 | if (sme->bssid) |
1471 | 1732 | memcpy(join_params.params_le.bssid, sme->bssid, ETH_ALEN); | |
1472 | if (ssid.SSID_len < IEEE80211_MAX_SSID_LEN) | 1733 | else |
1473 | brcmf_dbg(CONN, "ssid \"%s\", len (%d)\n", | 1734 | memset(join_params.params_le.bssid, 0xFF, ETH_ALEN); |
1474 | ssid.SSID, ssid.SSID_len); | ||
1475 | 1735 | ||
1476 | brcmf_ch_to_chanspec(cfg->channel, | 1736 | if (cfg->channel) { |
1477 | &join_params, &join_params_size); | 1737 | join_params.params_le.chanspec_list[0] = cpu_to_le16(chanspec); |
1738 | join_params.params_le.chanspec_num = cpu_to_le32(1); | ||
1739 | join_params_size += sizeof(join_params.params_le); | ||
1740 | } | ||
1478 | err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID, | 1741 | err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID, |
1479 | &join_params, join_params_size); | 1742 | &join_params, join_params_size); |
1480 | if (err) | 1743 | if (err) |
1481 | brcmf_err("WLC_SET_SSID failed (%d)\n", err); | 1744 | brcmf_err("BRCMF_C_SET_SSID failed (%d)\n", err); |
1482 | 1745 | ||
1483 | done: | 1746 | done: |
1484 | if (err) | 1747 | if (err) |
@@ -1937,7 +2200,7 @@ brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev, | |||
1937 | goto done; | 2200 | goto done; |
1938 | } | 2201 | } |
1939 | /* Report the current tx rate */ | 2202 | /* Report the current tx rate */ |
1940 | err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_RATE, &rate); | 2203 | err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_RATE, &rate); |
1941 | if (err) { | 2204 | if (err) { |
1942 | brcmf_err("Could not get rate (%d)\n", err); | 2205 | brcmf_err("Could not get rate (%d)\n", err); |
1943 | goto done; | 2206 | goto done; |
@@ -2060,7 +2323,7 @@ static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_info *cfg, | |||
2060 | if (!bss) | 2323 | if (!bss) |
2061 | return -ENOMEM; | 2324 | return -ENOMEM; |
2062 | 2325 | ||
2063 | cfg80211_put_bss(bss); | 2326 | cfg80211_put_bss(wiphy, bss); |
2064 | 2327 | ||
2065 | return err; | 2328 | return err; |
2066 | } | 2329 | } |
@@ -2166,7 +2429,7 @@ static s32 wl_inform_ibss(struct brcmf_cfg80211_info *cfg, | |||
2166 | goto CleanUp; | 2429 | goto CleanUp; |
2167 | } | 2430 | } |
2168 | 2431 | ||
2169 | cfg80211_put_bss(bss); | 2432 | cfg80211_put_bss(wiphy, bss); |
2170 | 2433 | ||
2171 | CleanUp: | 2434 | CleanUp: |
2172 | 2435 | ||
@@ -2182,78 +2445,10 @@ static bool brcmf_is_ibssmode(struct brcmf_cfg80211_vif *vif) | |||
2182 | return vif->mode == WL_MODE_IBSS; | 2445 | return vif->mode == WL_MODE_IBSS; |
2183 | } | 2446 | } |
2184 | 2447 | ||
2185 | /* | 2448 | static s32 brcmf_update_bss_info(struct brcmf_cfg80211_info *cfg, |
2186 | * Traverse a string of 1-byte tag/1-byte length/variable-length value | 2449 | struct brcmf_if *ifp) |
2187 | * triples, returning a pointer to the substring whose first element | ||
2188 | * matches tag | ||
2189 | */ | ||
2190 | static struct brcmf_tlv *brcmf_parse_tlvs(void *buf, int buflen, uint key) | ||
2191 | { | ||
2192 | struct brcmf_tlv *elt; | ||
2193 | int totlen; | ||
2194 | |||
2195 | elt = (struct brcmf_tlv *) buf; | ||
2196 | totlen = buflen; | ||
2197 | |||
2198 | /* find tagged parameter */ | ||
2199 | while (totlen >= TLV_HDR_LEN) { | ||
2200 | int len = elt->len; | ||
2201 | |||
2202 | /* validate remaining totlen */ | ||
2203 | if ((elt->id == key) && (totlen >= (len + TLV_HDR_LEN))) | ||
2204 | return elt; | ||
2205 | |||
2206 | elt = (struct brcmf_tlv *) ((u8 *) elt + (len + TLV_HDR_LEN)); | ||
2207 | totlen -= (len + TLV_HDR_LEN); | ||
2208 | } | ||
2209 | |||
2210 | return NULL; | ||
2211 | } | ||
2212 | |||
2213 | /* Is any of the tlvs the expected entry? If | ||
2214 | * not update the tlvs buffer pointer/length. | ||
2215 | */ | ||
2216 | static bool | ||
2217 | brcmf_tlv_has_ie(u8 *ie, u8 **tlvs, u32 *tlvs_len, | ||
2218 | u8 *oui, u32 oui_len, u8 type) | ||
2219 | { | ||
2220 | /* If the contents match the OUI and the type */ | ||
2221 | if (ie[TLV_LEN_OFF] >= oui_len + 1 && | ||
2222 | !memcmp(&ie[TLV_BODY_OFF], oui, oui_len) && | ||
2223 | type == ie[TLV_BODY_OFF + oui_len]) { | ||
2224 | return true; | ||
2225 | } | ||
2226 | |||
2227 | if (tlvs == NULL) | ||
2228 | return false; | ||
2229 | /* point to the next ie */ | ||
2230 | ie += ie[TLV_LEN_OFF] + TLV_HDR_LEN; | ||
2231 | /* calculate the length of the rest of the buffer */ | ||
2232 | *tlvs_len -= (int)(ie - *tlvs); | ||
2233 | /* update the pointer to the start of the buffer */ | ||
2234 | *tlvs = ie; | ||
2235 | |||
2236 | return false; | ||
2237 | } | ||
2238 | |||
2239 | static struct brcmf_vs_tlv * | ||
2240 | brcmf_find_wpaie(u8 *parse, u32 len) | ||
2241 | { | 2450 | { |
2242 | struct brcmf_tlv *ie; | 2451 | struct brcmf_cfg80211_profile *profile = ndev_to_prof(ifp->ndev); |
2243 | |||
2244 | while ((ie = brcmf_parse_tlvs(parse, len, WLAN_EID_VENDOR_SPECIFIC))) { | ||
2245 | if (brcmf_tlv_has_ie((u8 *)ie, &parse, &len, | ||
2246 | WPA_OUI, TLV_OUI_LEN, WPA_OUI_TYPE)) | ||
2247 | return (struct brcmf_vs_tlv *)ie; | ||
2248 | } | ||
2249 | return NULL; | ||
2250 | } | ||
2251 | |||
2252 | static s32 brcmf_update_bss_info(struct brcmf_cfg80211_info *cfg) | ||
2253 | { | ||
2254 | struct net_device *ndev = cfg_to_ndev(cfg); | ||
2255 | struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev); | ||
2256 | struct brcmf_if *ifp = netdev_priv(ndev); | ||
2257 | struct brcmf_bss_info_le *bi; | 2452 | struct brcmf_bss_info_le *bi; |
2258 | struct brcmf_ssid *ssid; | 2453 | struct brcmf_ssid *ssid; |
2259 | struct brcmf_tlv *tim; | 2454 | struct brcmf_tlv *tim; |
@@ -2309,7 +2504,7 @@ update_bss_info_out: | |||
2309 | return err; | 2504 | return err; |
2310 | } | 2505 | } |
2311 | 2506 | ||
2312 | static void brcmf_abort_scanning(struct brcmf_cfg80211_info *cfg) | 2507 | void brcmf_abort_scanning(struct brcmf_cfg80211_info *cfg) |
2313 | { | 2508 | { |
2314 | struct escan_info *escan = &cfg->escan_info; | 2509 | struct escan_info *escan = &cfg->escan_info; |
2315 | 2510 | ||
@@ -2328,8 +2523,7 @@ static void brcmf_cfg80211_escan_timeout_worker(struct work_struct *work) | |||
2328 | container_of(work, struct brcmf_cfg80211_info, | 2523 | container_of(work, struct brcmf_cfg80211_info, |
2329 | escan_timeout_work); | 2524 | escan_timeout_work); |
2330 | 2525 | ||
2331 | brcmf_notify_escan_complete(cfg, | 2526 | brcmf_notify_escan_complete(cfg, cfg->escan_info.ndev, true, true); |
2332 | cfg->escan_info.ndev, true, true); | ||
2333 | } | 2527 | } |
2334 | 2528 | ||
2335 | static void brcmf_escan_timeout(unsigned long data) | 2529 | static void brcmf_escan_timeout(unsigned long data) |
@@ -2406,11 +2600,6 @@ brcmf_cfg80211_escan_handler(struct brcmf_if *ifp, | |||
2406 | brcmf_err("Invalid escan result (NULL pointer)\n"); | 2600 | brcmf_err("Invalid escan result (NULL pointer)\n"); |
2407 | goto exit; | 2601 | goto exit; |
2408 | } | 2602 | } |
2409 | if (!cfg->scan_request) { | ||
2410 | brcmf_dbg(SCAN, "result without cfg80211 request\n"); | ||
2411 | goto exit; | ||
2412 | } | ||
2413 | |||
2414 | if (le16_to_cpu(escan_result_le->bss_count) != 1) { | 2603 | if (le16_to_cpu(escan_result_le->bss_count) != 1) { |
2415 | brcmf_err("Invalid bss_count %d: ignoring\n", | 2604 | brcmf_err("Invalid bss_count %d: ignoring\n", |
2416 | escan_result_le->bss_count); | 2605 | escan_result_le->bss_count); |
@@ -2418,6 +2607,14 @@ brcmf_cfg80211_escan_handler(struct brcmf_if *ifp, | |||
2418 | } | 2607 | } |
2419 | bss_info_le = &escan_result_le->bss_info_le; | 2608 | bss_info_le = &escan_result_le->bss_info_le; |
2420 | 2609 | ||
2610 | if (brcmf_p2p_scan_finding_common_channel(cfg, bss_info_le)) | ||
2611 | goto exit; | ||
2612 | |||
2613 | if (!cfg->scan_request) { | ||
2614 | brcmf_dbg(SCAN, "result without cfg80211 request\n"); | ||
2615 | goto exit; | ||
2616 | } | ||
2617 | |||
2421 | bi_length = le32_to_cpu(bss_info_le->length); | 2618 | bi_length = le32_to_cpu(bss_info_le->length); |
2422 | if (bi_length != (le32_to_cpu(escan_result_le->buflen) - | 2619 | if (bi_length != (le32_to_cpu(escan_result_le->buflen) - |
2423 | WL_ESCAN_RESULTS_FIXED_SIZE)) { | 2620 | WL_ESCAN_RESULTS_FIXED_SIZE)) { |
@@ -2456,6 +2653,8 @@ brcmf_cfg80211_escan_handler(struct brcmf_if *ifp, | |||
2456 | list->count++; | 2653 | list->count++; |
2457 | } else { | 2654 | } else { |
2458 | cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE; | 2655 | cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE; |
2656 | if (brcmf_p2p_scan_finding_common_channel(cfg, NULL)) | ||
2657 | goto exit; | ||
2459 | if (cfg->scan_request) { | 2658 | if (cfg->scan_request) { |
2460 | cfg->bss_list = (struct brcmf_scan_results *) | 2659 | cfg->bss_list = (struct brcmf_scan_results *) |
2461 | cfg->escan_info.escan_buf; | 2660 | cfg->escan_info.escan_buf; |
@@ -2464,7 +2663,8 @@ brcmf_cfg80211_escan_handler(struct brcmf_if *ifp, | |||
2464 | brcmf_notify_escan_complete(cfg, ndev, aborted, | 2663 | brcmf_notify_escan_complete(cfg, ndev, aborted, |
2465 | false); | 2664 | false); |
2466 | } else | 2665 | } else |
2467 | brcmf_err("Unexpected scan result 0x%x\n", status); | 2666 | brcmf_dbg(SCAN, "Ignored scan complete result 0x%x\n", |
2667 | status); | ||
2468 | } | 2668 | } |
2469 | exit: | 2669 | exit: |
2470 | return err; | 2670 | return err; |
@@ -2968,9 +3168,8 @@ static int brcmf_cfg80211_testmode(struct wiphy *wiphy, void *data, int len) | |||
2968 | } | 3168 | } |
2969 | #endif | 3169 | #endif |
2970 | 3170 | ||
2971 | static s32 brcmf_configure_opensecurity(struct net_device *ndev, s32 bssidx) | 3171 | static s32 brcmf_configure_opensecurity(struct brcmf_if *ifp) |
2972 | { | 3172 | { |
2973 | struct brcmf_if *ifp = netdev_priv(ndev); | ||
2974 | s32 err; | 3173 | s32 err; |
2975 | 3174 | ||
2976 | /* set auth */ | 3175 | /* set auth */ |
@@ -3229,7 +3428,7 @@ brcmf_parse_vndr_ies(const u8 *vndr_ie_buf, u32 vndr_ie_len, | |||
3229 | parsed_info->vndrie.oui[2], | 3428 | parsed_info->vndrie.oui[2], |
3230 | parsed_info->vndrie.oui_type); | 3429 | parsed_info->vndrie.oui_type); |
3231 | 3430 | ||
3232 | if (vndr_ies->count >= MAX_VNDR_IE_NUMBER) | 3431 | if (vndr_ies->count >= VNDR_IE_PARSE_LIMIT) |
3233 | break; | 3432 | break; |
3234 | next: | 3433 | next: |
3235 | remaining_len -= (ie->len + TLV_HDR_LEN); | 3434 | remaining_len -= (ie->len + TLV_HDR_LEN); |
@@ -3263,7 +3462,6 @@ brcmf_vndr_ie(u8 *iebuf, s32 pktflag, u8 *ie_ptr, u32 ie_len, s8 *add_del_cmd) | |||
3263 | return ie_len + VNDR_IE_HDR_SIZE; | 3462 | return ie_len + VNDR_IE_HDR_SIZE; |
3264 | } | 3463 | } |
3265 | 3464 | ||
3266 | static | ||
3267 | s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag, | 3465 | s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag, |
3268 | const u8 *vndr_ie_buf, u32 vndr_ie_len) | 3466 | const u8 *vndr_ie_buf, u32 vndr_ie_len) |
3269 | { | 3467 | { |
@@ -3295,24 +3493,28 @@ s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag, | |||
3295 | if (!iovar_ie_buf) | 3493 | if (!iovar_ie_buf) |
3296 | return -ENOMEM; | 3494 | return -ENOMEM; |
3297 | curr_ie_buf = iovar_ie_buf; | 3495 | curr_ie_buf = iovar_ie_buf; |
3298 | if (ifp->vif->mode == WL_MODE_AP) { | 3496 | switch (pktflag) { |
3299 | switch (pktflag) { | 3497 | case BRCMF_VNDR_IE_PRBREQ_FLAG: |
3300 | case VNDR_IE_PRBRSP_FLAG: | 3498 | mgmt_ie_buf = saved_ie->probe_req_ie; |
3301 | mgmt_ie_buf = saved_ie->probe_res_ie; | 3499 | mgmt_ie_len = &saved_ie->probe_req_ie_len; |
3302 | mgmt_ie_len = &saved_ie->probe_res_ie_len; | 3500 | mgmt_ie_buf_len = sizeof(saved_ie->probe_req_ie); |
3303 | mgmt_ie_buf_len = sizeof(saved_ie->probe_res_ie); | 3501 | break; |
3304 | break; | 3502 | case BRCMF_VNDR_IE_PRBRSP_FLAG: |
3305 | case VNDR_IE_BEACON_FLAG: | 3503 | mgmt_ie_buf = saved_ie->probe_res_ie; |
3306 | mgmt_ie_buf = saved_ie->beacon_ie; | 3504 | mgmt_ie_len = &saved_ie->probe_res_ie_len; |
3307 | mgmt_ie_len = &saved_ie->beacon_ie_len; | 3505 | mgmt_ie_buf_len = sizeof(saved_ie->probe_res_ie); |
3308 | mgmt_ie_buf_len = sizeof(saved_ie->beacon_ie); | 3506 | break; |
3309 | break; | 3507 | case BRCMF_VNDR_IE_BEACON_FLAG: |
3310 | default: | 3508 | mgmt_ie_buf = saved_ie->beacon_ie; |
3311 | err = -EPERM; | 3509 | mgmt_ie_len = &saved_ie->beacon_ie_len; |
3312 | brcmf_err("not suitable type\n"); | 3510 | mgmt_ie_buf_len = sizeof(saved_ie->beacon_ie); |
3313 | goto exit; | 3511 | break; |
3314 | } | 3512 | case BRCMF_VNDR_IE_ASSOCREQ_FLAG: |
3315 | } else { | 3513 | mgmt_ie_buf = saved_ie->assoc_req_ie; |
3514 | mgmt_ie_len = &saved_ie->assoc_req_ie_len; | ||
3515 | mgmt_ie_buf_len = sizeof(saved_ie->assoc_req_ie); | ||
3516 | break; | ||
3517 | default: | ||
3316 | err = -EPERM; | 3518 | err = -EPERM; |
3317 | brcmf_err("not suitable type\n"); | 3519 | brcmf_err("not suitable type\n"); |
3318 | goto exit; | 3520 | goto exit; |
@@ -3421,6 +3623,49 @@ exit: | |||
3421 | return err; | 3623 | return err; |
3422 | } | 3624 | } |
3423 | 3625 | ||
3626 | s32 brcmf_vif_clear_mgmt_ies(struct brcmf_cfg80211_vif *vif) | ||
3627 | { | ||
3628 | s32 pktflags[] = { | ||
3629 | BRCMF_VNDR_IE_PRBREQ_FLAG, | ||
3630 | BRCMF_VNDR_IE_PRBRSP_FLAG, | ||
3631 | BRCMF_VNDR_IE_BEACON_FLAG | ||
3632 | }; | ||
3633 | int i; | ||
3634 | |||
3635 | for (i = 0; i < ARRAY_SIZE(pktflags); i++) | ||
3636 | brcmf_vif_set_mgmt_ie(vif, pktflags[i], NULL, 0); | ||
3637 | |||
3638 | memset(&vif->saved_ie, 0, sizeof(vif->saved_ie)); | ||
3639 | return 0; | ||
3640 | } | ||
3641 | |||
3642 | static s32 | ||
3643 | brcmf_config_ap_mgmt_ie(struct brcmf_cfg80211_vif *vif, | ||
3644 | struct cfg80211_beacon_data *beacon) | ||
3645 | { | ||
3646 | s32 err; | ||
3647 | |||
3648 | /* Set Beacon IEs to FW */ | ||
3649 | err = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_BEACON_FLAG, | ||
3650 | beacon->tail, beacon->tail_len); | ||
3651 | if (err) { | ||
3652 | brcmf_err("Set Beacon IE Failed\n"); | ||
3653 | return err; | ||
3654 | } | ||
3655 | brcmf_dbg(TRACE, "Applied Vndr IEs for Beacon\n"); | ||
3656 | |||
3657 | /* Set Probe Response IEs to FW */ | ||
3658 | err = brcmf_vif_set_mgmt_ie(vif, BRCMF_VNDR_IE_PRBRSP_FLAG, | ||
3659 | beacon->proberesp_ies, | ||
3660 | beacon->proberesp_ies_len); | ||
3661 | if (err) | ||
3662 | brcmf_err("Set Probe Resp IE Failed\n"); | ||
3663 | else | ||
3664 | brcmf_dbg(TRACE, "Applied Vndr IEs for Probe Resp\n"); | ||
3665 | |||
3666 | return err; | ||
3667 | } | ||
3668 | |||
3424 | static s32 | 3669 | static s32 |
3425 | brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, | 3670 | brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, |
3426 | struct cfg80211_ap_settings *settings) | 3671 | struct cfg80211_ap_settings *settings) |
@@ -3433,7 +3678,8 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, | |||
3433 | struct brcmf_tlv *rsn_ie; | 3678 | struct brcmf_tlv *rsn_ie; |
3434 | struct brcmf_vs_tlv *wpa_ie; | 3679 | struct brcmf_vs_tlv *wpa_ie; |
3435 | struct brcmf_join_params join_params; | 3680 | struct brcmf_join_params join_params; |
3436 | s32 bssidx = 0; | 3681 | enum nl80211_iftype dev_role; |
3682 | struct brcmf_fil_bss_enable_le bss_enable; | ||
3437 | 3683 | ||
3438 | brcmf_dbg(TRACE, "channel_type=%d, beacon_interval=%d, dtim_period=%d,\n", | 3684 | brcmf_dbg(TRACE, "channel_type=%d, beacon_interval=%d, dtim_period=%d,\n", |
3439 | cfg80211_get_chandef_type(&settings->chandef), | 3685 | cfg80211_get_chandef_type(&settings->chandef), |
@@ -3443,10 +3689,7 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, | |||
3443 | settings->ssid, settings->ssid_len, settings->auth_type, | 3689 | settings->ssid, settings->ssid_len, settings->auth_type, |
3444 | settings->inactivity_timeout); | 3690 | settings->inactivity_timeout); |
3445 | 3691 | ||
3446 | if (!test_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state)) { | 3692 | dev_role = ifp->vif->wdev.iftype; |
3447 | brcmf_err("Not in AP creation mode\n"); | ||
3448 | return -EPERM; | ||
3449 | } | ||
3450 | 3693 | ||
3451 | memset(&ssid_le, 0, sizeof(ssid_le)); | 3694 | memset(&ssid_le, 0, sizeof(ssid_le)); |
3452 | if (settings->ssid == NULL || settings->ssid_len == 0) { | 3695 | if (settings->ssid == NULL || settings->ssid_len == 0) { |
@@ -3467,21 +3710,6 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, | |||
3467 | } | 3710 | } |
3468 | 3711 | ||
3469 | brcmf_set_mpc(ndev, 0); | 3712 | brcmf_set_mpc(ndev, 0); |
3470 | err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1); | ||
3471 | if (err < 0) { | ||
3472 | brcmf_err("BRCMF_C_DOWN error %d\n", err); | ||
3473 | goto exit; | ||
3474 | } | ||
3475 | err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 1); | ||
3476 | if (err < 0) { | ||
3477 | brcmf_err("SET INFRA error %d\n", err); | ||
3478 | goto exit; | ||
3479 | } | ||
3480 | err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 1); | ||
3481 | if (err < 0) { | ||
3482 | brcmf_err("setting AP mode failed %d\n", err); | ||
3483 | goto exit; | ||
3484 | } | ||
3485 | 3713 | ||
3486 | /* find the RSN_IE */ | 3714 | /* find the RSN_IE */ |
3487 | rsn_ie = brcmf_parse_tlvs((u8 *)settings->beacon.tail, | 3715 | rsn_ie = brcmf_parse_tlvs((u8 *)settings->beacon.tail, |
@@ -3507,27 +3735,10 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, | |||
3507 | } | 3735 | } |
3508 | } else { | 3736 | } else { |
3509 | brcmf_dbg(TRACE, "No WPA(2) IEs found\n"); | 3737 | brcmf_dbg(TRACE, "No WPA(2) IEs found\n"); |
3510 | brcmf_configure_opensecurity(ndev, bssidx); | 3738 | brcmf_configure_opensecurity(ifp); |
3511 | } | 3739 | } |
3512 | /* Set Beacon IEs to FW */ | ||
3513 | err = brcmf_vif_set_mgmt_ie(ndev_to_vif(ndev), | ||
3514 | VNDR_IE_BEACON_FLAG, | ||
3515 | settings->beacon.tail, | ||
3516 | settings->beacon.tail_len); | ||
3517 | if (err) | ||
3518 | brcmf_err("Set Beacon IE Failed\n"); | ||
3519 | else | ||
3520 | brcmf_dbg(TRACE, "Applied Vndr IEs for Beacon\n"); | ||
3521 | 3740 | ||
3522 | /* Set Probe Response IEs to FW */ | 3741 | brcmf_config_ap_mgmt_ie(ifp->vif, &settings->beacon); |
3523 | err = brcmf_vif_set_mgmt_ie(ndev_to_vif(ndev), | ||
3524 | VNDR_IE_PRBRSP_FLAG, | ||
3525 | settings->beacon.proberesp_ies, | ||
3526 | settings->beacon.proberesp_ies_len); | ||
3527 | if (err) | ||
3528 | brcmf_err("Set Probe Resp IE Failed\n"); | ||
3529 | else | ||
3530 | brcmf_dbg(TRACE, "Applied Vndr IEs for Probe Resp\n"); | ||
3531 | 3742 | ||
3532 | if (settings->beacon_interval) { | 3743 | if (settings->beacon_interval) { |
3533 | err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD, | 3744 | err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD, |
@@ -3545,22 +3756,62 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, | |||
3545 | goto exit; | 3756 | goto exit; |
3546 | } | 3757 | } |
3547 | } | 3758 | } |
3548 | err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1); | 3759 | |
3549 | if (err < 0) { | 3760 | if (dev_role == NL80211_IFTYPE_AP) { |
3550 | brcmf_err("BRCMF_C_UP error (%d)\n", err); | 3761 | err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1); |
3551 | goto exit; | 3762 | if (err < 0) { |
3763 | brcmf_err("BRCMF_C_DOWN error %d\n", err); | ||
3764 | goto exit; | ||
3765 | } | ||
3766 | brcmf_fil_iovar_int_set(ifp, "apsta", 0); | ||
3552 | } | 3767 | } |
3553 | 3768 | ||
3554 | memset(&join_params, 0, sizeof(join_params)); | 3769 | err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_INFRA, 1); |
3555 | /* join parameters starts with ssid */ | ||
3556 | memcpy(&join_params.ssid_le, &ssid_le, sizeof(ssid_le)); | ||
3557 | /* create softap */ | ||
3558 | err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID, | ||
3559 | &join_params, sizeof(join_params)); | ||
3560 | if (err < 0) { | 3770 | if (err < 0) { |
3561 | brcmf_err("SET SSID error (%d)\n", err); | 3771 | brcmf_err("SET INFRA error %d\n", err); |
3562 | goto exit; | 3772 | goto exit; |
3563 | } | 3773 | } |
3774 | if (dev_role == NL80211_IFTYPE_AP) { | ||
3775 | err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_AP, 1); | ||
3776 | if (err < 0) { | ||
3777 | brcmf_err("setting AP mode failed %d\n", err); | ||
3778 | goto exit; | ||
3779 | } | ||
3780 | err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1); | ||
3781 | if (err < 0) { | ||
3782 | brcmf_err("BRCMF_C_UP error (%d)\n", err); | ||
3783 | goto exit; | ||
3784 | } | ||
3785 | |||
3786 | memset(&join_params, 0, sizeof(join_params)); | ||
3787 | /* join parameters starts with ssid */ | ||
3788 | memcpy(&join_params.ssid_le, &ssid_le, sizeof(ssid_le)); | ||
3789 | /* create softap */ | ||
3790 | err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SSID, | ||
3791 | &join_params, sizeof(join_params)); | ||
3792 | if (err < 0) { | ||
3793 | brcmf_err("SET SSID error (%d)\n", err); | ||
3794 | goto exit; | ||
3795 | } | ||
3796 | brcmf_dbg(TRACE, "AP mode configuration complete\n"); | ||
3797 | } else { | ||
3798 | err = brcmf_fil_bsscfg_data_set(ifp, "ssid", &ssid_le, | ||
3799 | sizeof(ssid_le)); | ||
3800 | if (err < 0) { | ||
3801 | brcmf_err("setting ssid failed %d\n", err); | ||
3802 | goto exit; | ||
3803 | } | ||
3804 | bss_enable.bsscfg_idx = cpu_to_le32(ifp->bssidx); | ||
3805 | bss_enable.enable = cpu_to_le32(1); | ||
3806 | err = brcmf_fil_iovar_data_set(ifp, "bss", &bss_enable, | ||
3807 | sizeof(bss_enable)); | ||
3808 | if (err < 0) { | ||
3809 | brcmf_err("bss_enable config failed %d\n", err); | ||
3810 | goto exit; | ||
3811 | } | ||
3812 | |||
3813 | brcmf_dbg(TRACE, "GO mode configuration complete\n"); | ||
3814 | } | ||
3564 | clear_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state); | 3815 | clear_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state); |
3565 | set_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state); | 3816 | set_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state); |
3566 | 3817 | ||
@@ -3574,10 +3825,11 @@ static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev) | |||
3574 | { | 3825 | { |
3575 | struct brcmf_if *ifp = netdev_priv(ndev); | 3826 | struct brcmf_if *ifp = netdev_priv(ndev); |
3576 | s32 err = -EPERM; | 3827 | s32 err = -EPERM; |
3828 | struct brcmf_fil_bss_enable_le bss_enable; | ||
3577 | 3829 | ||
3578 | brcmf_dbg(TRACE, "Enter\n"); | 3830 | brcmf_dbg(TRACE, "Enter\n"); |
3579 | 3831 | ||
3580 | if (ifp->vif->mode == WL_MODE_AP) { | 3832 | if (ifp->vif->wdev.iftype == NL80211_IFTYPE_AP) { |
3581 | /* Due to most likely deauths outstanding we sleep */ | 3833 | /* Due to most likely deauths outstanding we sleep */ |
3582 | /* first to make sure they get processed by fw. */ | 3834 | /* first to make sure they get processed by fw. */ |
3583 | msleep(400); | 3835 | msleep(400); |
@@ -3591,18 +3843,41 @@ static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev) | |||
3591 | brcmf_err("BRCMF_C_UP error %d\n", err); | 3843 | brcmf_err("BRCMF_C_UP error %d\n", err); |
3592 | goto exit; | 3844 | goto exit; |
3593 | } | 3845 | } |
3594 | brcmf_set_mpc(ndev, 1); | 3846 | } else { |
3595 | clear_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state); | 3847 | bss_enable.bsscfg_idx = cpu_to_le32(ifp->bssidx); |
3596 | clear_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state); | 3848 | bss_enable.enable = cpu_to_le32(0); |
3849 | err = brcmf_fil_iovar_data_set(ifp, "bss", &bss_enable, | ||
3850 | sizeof(bss_enable)); | ||
3851 | if (err < 0) | ||
3852 | brcmf_err("bss_enable config failed %d\n", err); | ||
3597 | } | 3853 | } |
3854 | brcmf_set_mpc(ndev, 1); | ||
3855 | set_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state); | ||
3856 | clear_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state); | ||
3857 | |||
3598 | exit: | 3858 | exit: |
3599 | return err; | 3859 | return err; |
3600 | } | 3860 | } |
3601 | 3861 | ||
3862 | static s32 | ||
3863 | brcmf_cfg80211_change_beacon(struct wiphy *wiphy, struct net_device *ndev, | ||
3864 | struct cfg80211_beacon_data *info) | ||
3865 | { | ||
3866 | struct brcmf_if *ifp = netdev_priv(ndev); | ||
3867 | s32 err; | ||
3868 | |||
3869 | brcmf_dbg(TRACE, "Enter\n"); | ||
3870 | |||
3871 | err = brcmf_config_ap_mgmt_ie(ifp->vif, info); | ||
3872 | |||
3873 | return err; | ||
3874 | } | ||
3875 | |||
3602 | static int | 3876 | static int |
3603 | brcmf_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev, | 3877 | brcmf_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev, |
3604 | u8 *mac) | 3878 | u8 *mac) |
3605 | { | 3879 | { |
3880 | struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); | ||
3606 | struct brcmf_scb_val_le scbval; | 3881 | struct brcmf_scb_val_le scbval; |
3607 | struct brcmf_if *ifp = netdev_priv(ndev); | 3882 | struct brcmf_if *ifp = netdev_priv(ndev); |
3608 | s32 err; | 3883 | s32 err; |
@@ -3612,6 +3887,8 @@ brcmf_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev, | |||
3612 | 3887 | ||
3613 | brcmf_dbg(TRACE, "Enter %pM\n", mac); | 3888 | brcmf_dbg(TRACE, "Enter %pM\n", mac); |
3614 | 3889 | ||
3890 | if (ifp->vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif) | ||
3891 | ifp = cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp; | ||
3615 | if (!check_vif_up(ifp->vif)) | 3892 | if (!check_vif_up(ifp->vif)) |
3616 | return -EIO; | 3893 | return -EIO; |
3617 | 3894 | ||
@@ -3626,7 +3903,147 @@ brcmf_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev, | |||
3626 | return err; | 3903 | return err; |
3627 | } | 3904 | } |
3628 | 3905 | ||
3906 | |||
3907 | static void | ||
3908 | brcmf_cfg80211_mgmt_frame_register(struct wiphy *wiphy, | ||
3909 | struct wireless_dev *wdev, | ||
3910 | u16 frame_type, bool reg) | ||
3911 | { | ||
3912 | struct brcmf_if *ifp = netdev_priv(wdev->netdev); | ||
3913 | struct brcmf_cfg80211_vif *vif = ifp->vif; | ||
3914 | u16 mgmt_type; | ||
3915 | |||
3916 | brcmf_dbg(TRACE, "Enter, frame_type %04x, reg=%d\n", frame_type, reg); | ||
3917 | |||
3918 | mgmt_type = (frame_type & IEEE80211_FCTL_STYPE) >> 4; | ||
3919 | if (reg) | ||
3920 | vif->mgmt_rx_reg |= BIT(mgmt_type); | ||
3921 | else | ||
3922 | vif->mgmt_rx_reg &= ~BIT(mgmt_type); | ||
3923 | } | ||
3924 | |||
3925 | |||
3926 | static int | ||
3927 | brcmf_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, | ||
3928 | struct ieee80211_channel *chan, bool offchan, | ||
3929 | unsigned int wait, const u8 *buf, size_t len, | ||
3930 | bool no_cck, bool dont_wait_for_ack, u64 *cookie) | ||
3931 | { | ||
3932 | struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); | ||
3933 | const struct ieee80211_mgmt *mgmt; | ||
3934 | struct brcmf_if *ifp; | ||
3935 | struct brcmf_cfg80211_vif *vif; | ||
3936 | s32 err = 0; | ||
3937 | s32 ie_offset; | ||
3938 | s32 ie_len; | ||
3939 | struct brcmf_fil_action_frame_le *action_frame; | ||
3940 | struct brcmf_fil_af_params_le *af_params; | ||
3941 | bool ack; | ||
3942 | s32 chan_nr; | ||
3943 | |||
3944 | brcmf_dbg(TRACE, "Enter\n"); | ||
3945 | |||
3946 | *cookie = 0; | ||
3947 | |||
3948 | mgmt = (const struct ieee80211_mgmt *)buf; | ||
3949 | |||
3950 | if (!ieee80211_is_mgmt(mgmt->frame_control)) { | ||
3951 | brcmf_err("Driver only allows MGMT packet type\n"); | ||
3952 | return -EPERM; | ||
3953 | } | ||
3954 | |||
3955 | if (ieee80211_is_probe_resp(mgmt->frame_control)) { | ||
3956 | /* Right now the only reason to get a probe response */ | ||
3957 | /* is for p2p listen response or for p2p GO from */ | ||
3958 | /* wpa_supplicant. Unfortunately the probe is send */ | ||
3959 | /* on primary ndev, while dongle wants it on the p2p */ | ||
3960 | /* vif. Since this is only reason for a probe */ | ||
3961 | /* response to be sent, the vif is taken from cfg. */ | ||
3962 | /* If ever desired to send proberesp for non p2p */ | ||
3963 | /* response then data should be checked for */ | ||
3964 | /* "DIRECT-". Note in future supplicant will take */ | ||
3965 | /* dedicated p2p wdev to do this and then this 'hack'*/ | ||
3966 | /* is not needed anymore. */ | ||
3967 | ie_offset = DOT11_MGMT_HDR_LEN + | ||
3968 | DOT11_BCN_PRB_FIXED_LEN; | ||
3969 | ie_len = len - ie_offset; | ||
3970 | ifp = netdev_priv(wdev->netdev); | ||
3971 | vif = ifp->vif; | ||
3972 | if (vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif) | ||
3973 | vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif; | ||
3974 | err = brcmf_vif_set_mgmt_ie(vif, | ||
3975 | BRCMF_VNDR_IE_PRBRSP_FLAG, | ||
3976 | &buf[ie_offset], | ||
3977 | ie_len); | ||
3978 | cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, true, | ||
3979 | GFP_KERNEL); | ||
3980 | } else if (ieee80211_is_action(mgmt->frame_control)) { | ||
3981 | af_params = kzalloc(sizeof(*af_params), GFP_KERNEL); | ||
3982 | if (af_params == NULL) { | ||
3983 | brcmf_err("unable to allocate frame\n"); | ||
3984 | err = -ENOMEM; | ||
3985 | goto exit; | ||
3986 | } | ||
3987 | action_frame = &af_params->action_frame; | ||
3988 | /* Add the packet Id */ | ||
3989 | action_frame->packet_id = cpu_to_le32(*cookie); | ||
3990 | /* Add BSSID */ | ||
3991 | memcpy(&action_frame->da[0], &mgmt->da[0], ETH_ALEN); | ||
3992 | memcpy(&af_params->bssid[0], &mgmt->bssid[0], ETH_ALEN); | ||
3993 | /* Add the length exepted for 802.11 header */ | ||
3994 | action_frame->len = cpu_to_le16(len - DOT11_MGMT_HDR_LEN); | ||
3995 | /* Add the channel */ | ||
3996 | chan_nr = ieee80211_frequency_to_channel(chan->center_freq); | ||
3997 | af_params->channel = cpu_to_le32(chan_nr); | ||
3998 | |||
3999 | memcpy(action_frame->data, &buf[DOT11_MGMT_HDR_LEN], | ||
4000 | le16_to_cpu(action_frame->len)); | ||
4001 | |||
4002 | brcmf_dbg(TRACE, "Action frame, cookie=%lld, len=%d, freq=%d\n", | ||
4003 | *cookie, le16_to_cpu(action_frame->len), | ||
4004 | chan->center_freq); | ||
4005 | |||
4006 | ack = brcmf_p2p_send_action_frame(cfg, wdev->netdev, | ||
4007 | af_params); | ||
4008 | |||
4009 | cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, ack, | ||
4010 | GFP_KERNEL); | ||
4011 | kfree(af_params); | ||
4012 | } else { | ||
4013 | brcmf_dbg(TRACE, "Unhandled, fc=%04x!!\n", mgmt->frame_control); | ||
4014 | brcmf_dbg_hex_dump(true, buf, len, "payload, len=%Zu\n", len); | ||
4015 | } | ||
4016 | |||
4017 | exit: | ||
4018 | return err; | ||
4019 | } | ||
4020 | |||
4021 | |||
4022 | static int | ||
4023 | brcmf_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy, | ||
4024 | struct wireless_dev *wdev, | ||
4025 | u64 cookie) | ||
4026 | { | ||
4027 | struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); | ||
4028 | struct brcmf_cfg80211_vif *vif; | ||
4029 | int err = 0; | ||
4030 | |||
4031 | brcmf_dbg(TRACE, "Enter p2p listen cancel\n"); | ||
4032 | |||
4033 | vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif; | ||
4034 | if (vif == NULL) { | ||
4035 | brcmf_err("No p2p device available for probe response\n"); | ||
4036 | err = -ENODEV; | ||
4037 | goto exit; | ||
4038 | } | ||
4039 | brcmf_p2p_cancel_remain_on_channel(vif->ifp); | ||
4040 | exit: | ||
4041 | return err; | ||
4042 | } | ||
4043 | |||
3629 | static struct cfg80211_ops wl_cfg80211_ops = { | 4044 | static struct cfg80211_ops wl_cfg80211_ops = { |
4045 | .add_virtual_intf = brcmf_cfg80211_add_iface, | ||
4046 | .del_virtual_intf = brcmf_cfg80211_del_iface, | ||
3630 | .change_virtual_intf = brcmf_cfg80211_change_iface, | 4047 | .change_virtual_intf = brcmf_cfg80211_change_iface, |
3631 | .scan = brcmf_cfg80211_scan, | 4048 | .scan = brcmf_cfg80211_scan, |
3632 | .set_wiphy_params = brcmf_cfg80211_set_wiphy_params, | 4049 | .set_wiphy_params = brcmf_cfg80211_set_wiphy_params, |
@@ -3650,28 +4067,43 @@ static struct cfg80211_ops wl_cfg80211_ops = { | |||
3650 | .flush_pmksa = brcmf_cfg80211_flush_pmksa, | 4067 | .flush_pmksa = brcmf_cfg80211_flush_pmksa, |
3651 | .start_ap = brcmf_cfg80211_start_ap, | 4068 | .start_ap = brcmf_cfg80211_start_ap, |
3652 | .stop_ap = brcmf_cfg80211_stop_ap, | 4069 | .stop_ap = brcmf_cfg80211_stop_ap, |
4070 | .change_beacon = brcmf_cfg80211_change_beacon, | ||
3653 | .del_station = brcmf_cfg80211_del_station, | 4071 | .del_station = brcmf_cfg80211_del_station, |
3654 | .sched_scan_start = brcmf_cfg80211_sched_scan_start, | 4072 | .sched_scan_start = brcmf_cfg80211_sched_scan_start, |
3655 | .sched_scan_stop = brcmf_cfg80211_sched_scan_stop, | 4073 | .sched_scan_stop = brcmf_cfg80211_sched_scan_stop, |
4074 | .mgmt_frame_register = brcmf_cfg80211_mgmt_frame_register, | ||
4075 | .mgmt_tx = brcmf_cfg80211_mgmt_tx, | ||
4076 | .remain_on_channel = brcmf_p2p_remain_on_channel, | ||
4077 | .cancel_remain_on_channel = brcmf_cfg80211_cancel_remain_on_channel, | ||
3656 | #ifdef CONFIG_NL80211_TESTMODE | 4078 | #ifdef CONFIG_NL80211_TESTMODE |
3657 | .testmode_cmd = brcmf_cfg80211_testmode | 4079 | .testmode_cmd = brcmf_cfg80211_testmode |
3658 | #endif | 4080 | #endif |
3659 | }; | 4081 | }; |
3660 | 4082 | ||
3661 | static s32 brcmf_mode_to_nl80211_iftype(s32 mode) | 4083 | static s32 brcmf_nl80211_iftype_to_mode(enum nl80211_iftype type) |
3662 | { | 4084 | { |
3663 | s32 err = 0; | 4085 | switch (type) { |
3664 | 4086 | case NL80211_IFTYPE_AP_VLAN: | |
3665 | switch (mode) { | 4087 | case NL80211_IFTYPE_WDS: |
3666 | case WL_MODE_BSS: | 4088 | case NL80211_IFTYPE_MONITOR: |
3667 | return NL80211_IFTYPE_STATION; | 4089 | case NL80211_IFTYPE_MESH_POINT: |
3668 | case WL_MODE_IBSS: | 4090 | return -ENOTSUPP; |
3669 | return NL80211_IFTYPE_ADHOC; | 4091 | case NL80211_IFTYPE_ADHOC: |
4092 | return WL_MODE_IBSS; | ||
4093 | case NL80211_IFTYPE_STATION: | ||
4094 | case NL80211_IFTYPE_P2P_CLIENT: | ||
4095 | return WL_MODE_BSS; | ||
4096 | case NL80211_IFTYPE_AP: | ||
4097 | case NL80211_IFTYPE_P2P_GO: | ||
4098 | return WL_MODE_AP; | ||
4099 | case NL80211_IFTYPE_P2P_DEVICE: | ||
4100 | return WL_MODE_P2P; | ||
4101 | case NL80211_IFTYPE_UNSPECIFIED: | ||
3670 | default: | 4102 | default: |
3671 | return NL80211_IFTYPE_UNSPECIFIED; | 4103 | break; |
3672 | } | 4104 | } |
3673 | 4105 | ||
3674 | return err; | 4106 | return -EINVAL; |
3675 | } | 4107 | } |
3676 | 4108 | ||
3677 | static void brcmf_wiphy_pno_params(struct wiphy *wiphy) | 4109 | static void brcmf_wiphy_pno_params(struct wiphy *wiphy) |
@@ -3683,6 +4115,56 @@ static void brcmf_wiphy_pno_params(struct wiphy *wiphy) | |||
3683 | wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN; | 4115 | wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN; |
3684 | } | 4116 | } |
3685 | 4117 | ||
4118 | static const struct ieee80211_iface_limit brcmf_iface_limits[] = { | ||
4119 | { | ||
4120 | .max = 2, | ||
4121 | .types = BIT(NL80211_IFTYPE_STATION) | | ||
4122 | BIT(NL80211_IFTYPE_ADHOC) | | ||
4123 | BIT(NL80211_IFTYPE_AP) | ||
4124 | }, | ||
4125 | { | ||
4126 | .max = 1, | ||
4127 | .types = BIT(NL80211_IFTYPE_P2P_DEVICE) | ||
4128 | }, | ||
4129 | { | ||
4130 | .max = 1, | ||
4131 | .types = BIT(NL80211_IFTYPE_P2P_CLIENT) | | ||
4132 | BIT(NL80211_IFTYPE_P2P_GO) | ||
4133 | }, | ||
4134 | }; | ||
4135 | static const struct ieee80211_iface_combination brcmf_iface_combos[] = { | ||
4136 | { | ||
4137 | .max_interfaces = BRCMF_IFACE_MAX_CNT, | ||
4138 | .num_different_channels = 1, /* no multi-channel for now */ | ||
4139 | .n_limits = ARRAY_SIZE(brcmf_iface_limits), | ||
4140 | .limits = brcmf_iface_limits | ||
4141 | } | ||
4142 | }; | ||
4143 | |||
4144 | static const struct ieee80211_txrx_stypes | ||
4145 | brcmf_txrx_stypes[NUM_NL80211_IFTYPES] = { | ||
4146 | [NL80211_IFTYPE_STATION] = { | ||
4147 | .tx = 0xffff, | ||
4148 | .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | | ||
4149 | BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | ||
4150 | }, | ||
4151 | [NL80211_IFTYPE_P2P_CLIENT] = { | ||
4152 | .tx = 0xffff, | ||
4153 | .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | | ||
4154 | BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | ||
4155 | }, | ||
4156 | [NL80211_IFTYPE_P2P_GO] = { | ||
4157 | .tx = 0xffff, | ||
4158 | .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) | | ||
4159 | BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) | | ||
4160 | BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | | ||
4161 | BIT(IEEE80211_STYPE_DISASSOC >> 4) | | ||
4162 | BIT(IEEE80211_STYPE_AUTH >> 4) | | ||
4163 | BIT(IEEE80211_STYPE_DEAUTH >> 4) | | ||
4164 | BIT(IEEE80211_STYPE_ACTION >> 4) | ||
4165 | } | ||
4166 | }; | ||
4167 | |||
3686 | static struct wiphy *brcmf_setup_wiphy(struct device *phydev) | 4168 | static struct wiphy *brcmf_setup_wiphy(struct device *phydev) |
3687 | { | 4169 | { |
3688 | struct wiphy *wiphy; | 4170 | struct wiphy *wiphy; |
@@ -3695,10 +4177,16 @@ static struct wiphy *brcmf_setup_wiphy(struct device *phydev) | |||
3695 | } | 4177 | } |
3696 | set_wiphy_dev(wiphy, phydev); | 4178 | set_wiphy_dev(wiphy, phydev); |
3697 | wiphy->max_scan_ssids = WL_NUM_SCAN_MAX; | 4179 | wiphy->max_scan_ssids = WL_NUM_SCAN_MAX; |
4180 | wiphy->max_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX; | ||
3698 | wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX; | 4181 | wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX; |
3699 | wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | | 4182 | wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | |
3700 | BIT(NL80211_IFTYPE_ADHOC) | | 4183 | BIT(NL80211_IFTYPE_ADHOC) | |
3701 | BIT(NL80211_IFTYPE_AP); | 4184 | BIT(NL80211_IFTYPE_AP) | |
4185 | BIT(NL80211_IFTYPE_P2P_CLIENT) | | ||
4186 | BIT(NL80211_IFTYPE_P2P_GO) | | ||
4187 | BIT(NL80211_IFTYPE_P2P_DEVICE); | ||
4188 | wiphy->iface_combinations = brcmf_iface_combos; | ||
4189 | wiphy->n_iface_combinations = ARRAY_SIZE(brcmf_iface_combos); | ||
3702 | wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz; | 4190 | wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz; |
3703 | wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_a; /* Set | 4191 | wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_a; /* Set |
3704 | * it as 11a by default. | 4192 | * it as 11a by default. |
@@ -3710,10 +4198,11 @@ static struct wiphy *brcmf_setup_wiphy(struct device *phydev) | |||
3710 | wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; | 4198 | wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; |
3711 | wiphy->cipher_suites = __wl_cipher_suites; | 4199 | wiphy->cipher_suites = __wl_cipher_suites; |
3712 | wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites); | 4200 | wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites); |
3713 | wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT; /* enable power | 4201 | wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT | |
3714 | * save mode | 4202 | WIPHY_FLAG_OFFCHAN_TX | |
3715 | * by default | 4203 | WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; |
3716 | */ | 4204 | wiphy->mgmt_stypes = brcmf_txrx_stypes; |
4205 | wiphy->max_remain_on_channel_duration = 5000; | ||
3717 | brcmf_wiphy_pno_params(wiphy); | 4206 | brcmf_wiphy_pno_params(wiphy); |
3718 | err = wiphy_register(wiphy); | 4207 | err = wiphy_register(wiphy); |
3719 | if (err < 0) { | 4208 | if (err < 0) { |
@@ -3724,31 +4213,25 @@ static struct wiphy *brcmf_setup_wiphy(struct device *phydev) | |||
3724 | return wiphy; | 4213 | return wiphy; |
3725 | } | 4214 | } |
3726 | 4215 | ||
3727 | static | ||
3728 | struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg, | 4216 | struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg, |
3729 | struct net_device *netdev, | 4217 | enum nl80211_iftype type, |
3730 | s32 mode, bool pm_block) | 4218 | bool pm_block) |
3731 | { | 4219 | { |
3732 | struct brcmf_cfg80211_vif *vif; | 4220 | struct brcmf_cfg80211_vif *vif; |
3733 | 4221 | ||
3734 | if (cfg->vif_cnt == BRCMF_IFACE_MAX_CNT) | 4222 | if (cfg->vif_cnt == BRCMF_IFACE_MAX_CNT) |
3735 | return ERR_PTR(-ENOSPC); | 4223 | return ERR_PTR(-ENOSPC); |
3736 | 4224 | ||
4225 | brcmf_dbg(TRACE, "allocating virtual interface (size=%zu)\n", | ||
4226 | sizeof(*vif)); | ||
3737 | vif = kzalloc(sizeof(*vif), GFP_KERNEL); | 4227 | vif = kzalloc(sizeof(*vif), GFP_KERNEL); |
3738 | if (!vif) | 4228 | if (!vif) |
3739 | return ERR_PTR(-ENOMEM); | 4229 | return ERR_PTR(-ENOMEM); |
3740 | 4230 | ||
3741 | vif->wdev.wiphy = cfg->wiphy; | 4231 | vif->wdev.wiphy = cfg->wiphy; |
3742 | vif->wdev.netdev = netdev; | 4232 | vif->wdev.iftype = type; |
3743 | vif->wdev.iftype = brcmf_mode_to_nl80211_iftype(mode); | ||
3744 | |||
3745 | if (netdev) { | ||
3746 | vif->ifp = netdev_priv(netdev); | ||
3747 | netdev->ieee80211_ptr = &vif->wdev; | ||
3748 | SET_NETDEV_DEV(netdev, wiphy_dev(cfg->wiphy)); | ||
3749 | } | ||
3750 | 4233 | ||
3751 | vif->mode = mode; | 4234 | vif->mode = brcmf_nl80211_iftype_to_mode(type); |
3752 | vif->pm_block = pm_block; | 4235 | vif->pm_block = pm_block; |
3753 | vif->roam_off = -1; | 4236 | vif->roam_off = -1; |
3754 | 4237 | ||
@@ -3759,7 +4242,7 @@ struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg, | |||
3759 | return vif; | 4242 | return vif; |
3760 | } | 4243 | } |
3761 | 4244 | ||
3762 | static void brcmf_free_vif(struct brcmf_cfg80211_vif *vif) | 4245 | void brcmf_free_vif(struct brcmf_cfg80211_vif *vif) |
3763 | { | 4246 | { |
3764 | struct brcmf_cfg80211_info *cfg; | 4247 | struct brcmf_cfg80211_info *cfg; |
3765 | struct wiphy *wiphy; | 4248 | struct wiphy *wiphy; |
@@ -3833,9 +4316,9 @@ static void brcmf_clear_assoc_ies(struct brcmf_cfg80211_info *cfg) | |||
3833 | conn_info->resp_ie_len = 0; | 4316 | conn_info->resp_ie_len = 0; |
3834 | } | 4317 | } |
3835 | 4318 | ||
3836 | static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg) | 4319 | static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_info *cfg, |
4320 | struct brcmf_if *ifp) | ||
3837 | { | 4321 | { |
3838 | struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg)); | ||
3839 | struct brcmf_cfg80211_assoc_ielen_le *assoc_info; | 4322 | struct brcmf_cfg80211_assoc_ielen_le *assoc_info; |
3840 | struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg); | 4323 | struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg); |
3841 | u32 req_len; | 4324 | u32 req_len; |
@@ -3911,9 +4394,9 @@ brcmf_bss_roaming_done(struct brcmf_cfg80211_info *cfg, | |||
3911 | 4394 | ||
3912 | brcmf_dbg(TRACE, "Enter\n"); | 4395 | brcmf_dbg(TRACE, "Enter\n"); |
3913 | 4396 | ||
3914 | brcmf_get_assoc_ies(cfg); | 4397 | brcmf_get_assoc_ies(cfg, ifp); |
3915 | memcpy(profile->bssid, e->addr, ETH_ALEN); | 4398 | memcpy(profile->bssid, e->addr, ETH_ALEN); |
3916 | brcmf_update_bss_info(cfg); | 4399 | brcmf_update_bss_info(cfg, ifp); |
3917 | 4400 | ||
3918 | buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL); | 4401 | buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL); |
3919 | if (buf == NULL) { | 4402 | if (buf == NULL) { |
@@ -3968,9 +4451,11 @@ brcmf_bss_connect_done(struct brcmf_cfg80211_info *cfg, | |||
3968 | if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTING, | 4451 | if (test_and_clear_bit(BRCMF_VIF_STATUS_CONNECTING, |
3969 | &ifp->vif->sme_state)) { | 4452 | &ifp->vif->sme_state)) { |
3970 | if (completed) { | 4453 | if (completed) { |
3971 | brcmf_get_assoc_ies(cfg); | 4454 | brcmf_get_assoc_ies(cfg, ifp); |
3972 | memcpy(profile->bssid, e->addr, ETH_ALEN); | 4455 | memcpy(profile->bssid, e->addr, ETH_ALEN); |
3973 | brcmf_update_bss_info(cfg); | 4456 | brcmf_update_bss_info(cfg, ifp); |
4457 | set_bit(BRCMF_VIF_STATUS_CONNECTED, | ||
4458 | &ifp->vif->sme_state); | ||
3974 | } | 4459 | } |
3975 | cfg80211_connect_result(ndev, | 4460 | cfg80211_connect_result(ndev, |
3976 | (u8 *)profile->bssid, | 4461 | (u8 *)profile->bssid, |
@@ -3981,9 +4466,6 @@ brcmf_bss_connect_done(struct brcmf_cfg80211_info *cfg, | |||
3981 | completed ? WLAN_STATUS_SUCCESS : | 4466 | completed ? WLAN_STATUS_SUCCESS : |
3982 | WLAN_STATUS_AUTH_TIMEOUT, | 4467 | WLAN_STATUS_AUTH_TIMEOUT, |
3983 | GFP_KERNEL); | 4468 | GFP_KERNEL); |
3984 | if (completed) | ||
3985 | set_bit(BRCMF_VIF_STATUS_CONNECTED, | ||
3986 | &ifp->vif->sme_state); | ||
3987 | brcmf_dbg(CONN, "Report connect result - connection %s\n", | 4469 | brcmf_dbg(CONN, "Report connect result - connection %s\n", |
3988 | completed ? "succeeded" : "failed"); | 4470 | completed ? "succeeded" : "failed"); |
3989 | } | 4471 | } |
@@ -3996,38 +4478,38 @@ brcmf_notify_connect_status_ap(struct brcmf_cfg80211_info *cfg, | |||
3996 | struct net_device *ndev, | 4478 | struct net_device *ndev, |
3997 | const struct brcmf_event_msg *e, void *data) | 4479 | const struct brcmf_event_msg *e, void *data) |
3998 | { | 4480 | { |
3999 | s32 err = 0; | 4481 | static int generation; |
4000 | u32 event = e->event_code; | 4482 | u32 event = e->event_code; |
4001 | u32 reason = e->reason; | 4483 | u32 reason = e->reason; |
4002 | u32 len = e->datalen; | ||
4003 | static int generation; | ||
4004 | |||
4005 | struct station_info sinfo; | 4484 | struct station_info sinfo; |
4006 | 4485 | ||
4007 | brcmf_dbg(CONN, "event %d, reason %d\n", event, reason); | 4486 | brcmf_dbg(CONN, "event %d, reason %d\n", event, reason); |
4008 | memset(&sinfo, 0, sizeof(sinfo)); | 4487 | if (event == BRCMF_E_LINK && reason == BRCMF_E_REASON_LINK_BSSCFG_DIS && |
4488 | ndev != cfg_to_ndev(cfg)) { | ||
4489 | brcmf_dbg(CONN, "AP mode link down\n"); | ||
4490 | complete(&cfg->vif_disabled); | ||
4491 | return 0; | ||
4492 | } | ||
4009 | 4493 | ||
4010 | sinfo.filled = 0; | ||
4011 | if (((event == BRCMF_E_ASSOC_IND) || (event == BRCMF_E_REASSOC_IND)) && | 4494 | if (((event == BRCMF_E_ASSOC_IND) || (event == BRCMF_E_REASSOC_IND)) && |
4012 | reason == BRCMF_E_STATUS_SUCCESS) { | 4495 | (reason == BRCMF_E_STATUS_SUCCESS)) { |
4496 | memset(&sinfo, 0, sizeof(sinfo)); | ||
4013 | sinfo.filled = STATION_INFO_ASSOC_REQ_IES; | 4497 | sinfo.filled = STATION_INFO_ASSOC_REQ_IES; |
4014 | if (!data) { | 4498 | if (!data) { |
4015 | brcmf_err("No IEs present in ASSOC/REASSOC_IND"); | 4499 | brcmf_err("No IEs present in ASSOC/REASSOC_IND"); |
4016 | return -EINVAL; | 4500 | return -EINVAL; |
4017 | } | 4501 | } |
4018 | sinfo.assoc_req_ies = data; | 4502 | sinfo.assoc_req_ies = data; |
4019 | sinfo.assoc_req_ies_len = len; | 4503 | sinfo.assoc_req_ies_len = e->datalen; |
4020 | generation++; | 4504 | generation++; |
4021 | sinfo.generation = generation; | 4505 | sinfo.generation = generation; |
4022 | cfg80211_new_sta(ndev, e->addr, &sinfo, GFP_ATOMIC); | 4506 | cfg80211_new_sta(ndev, e->addr, &sinfo, GFP_KERNEL); |
4023 | } else if ((event == BRCMF_E_DISASSOC_IND) || | 4507 | } else if ((event == BRCMF_E_DISASSOC_IND) || |
4024 | (event == BRCMF_E_DEAUTH_IND) || | 4508 | (event == BRCMF_E_DEAUTH_IND) || |
4025 | (event == BRCMF_E_DEAUTH)) { | 4509 | (event == BRCMF_E_DEAUTH)) { |
4026 | generation++; | 4510 | cfg80211_del_sta(ndev, e->addr, GFP_KERNEL); |
4027 | sinfo.generation = generation; | ||
4028 | cfg80211_del_sta(ndev, e->addr, GFP_ATOMIC); | ||
4029 | } | 4511 | } |
4030 | return err; | 4512 | return 0; |
4031 | } | 4513 | } |
4032 | 4514 | ||
4033 | static s32 | 4515 | static s32 |
@@ -4064,6 +4546,8 @@ brcmf_notify_connect_status(struct brcmf_if *ifp, | |||
4064 | } | 4546 | } |
4065 | brcmf_link_down(ifp->vif); | 4547 | brcmf_link_down(ifp->vif); |
4066 | brcmf_init_prof(ndev_to_prof(ndev)); | 4548 | brcmf_init_prof(ndev_to_prof(ndev)); |
4549 | if (ndev != cfg_to_ndev(cfg)) | ||
4550 | complete(&cfg->vif_disabled); | ||
4067 | } else if (brcmf_is_nonetwork(cfg, e)) { | 4551 | } else if (brcmf_is_nonetwork(cfg, e)) { |
4068 | if (brcmf_is_ibssmode(ifp->vif)) | 4552 | if (brcmf_is_ibssmode(ifp->vif)) |
4069 | clear_bit(BRCMF_VIF_STATUS_CONNECTING, | 4553 | clear_bit(BRCMF_VIF_STATUS_CONNECTING, |
@@ -4112,6 +4596,57 @@ brcmf_notify_mic_status(struct brcmf_if *ifp, | |||
4112 | return 0; | 4596 | return 0; |
4113 | } | 4597 | } |
4114 | 4598 | ||
4599 | static s32 brcmf_notify_vif_event(struct brcmf_if *ifp, | ||
4600 | const struct brcmf_event_msg *e, void *data) | ||
4601 | { | ||
4602 | struct brcmf_cfg80211_info *cfg = ifp->drvr->config; | ||
4603 | struct brcmf_if_event *ifevent = (struct brcmf_if_event *)data; | ||
4604 | struct brcmf_cfg80211_vif_event *event = &cfg->vif_event; | ||
4605 | struct brcmf_cfg80211_vif *vif; | ||
4606 | |||
4607 | brcmf_dbg(TRACE, "Enter: action %u flags %u ifidx %u bsscfg %u\n", | ||
4608 | ifevent->action, ifevent->flags, ifevent->ifidx, | ||
4609 | ifevent->bssidx); | ||
4610 | |||
4611 | mutex_lock(&event->vif_event_lock); | ||
4612 | event->action = ifevent->action; | ||
4613 | vif = event->vif; | ||
4614 | |||
4615 | switch (ifevent->action) { | ||
4616 | case BRCMF_E_IF_ADD: | ||
4617 | /* waiting process may have timed out */ | ||
4618 | if (!cfg->vif_event.vif) | ||
4619 | return -EBADF; | ||
4620 | |||
4621 | ifp->vif = vif; | ||
4622 | vif->ifp = ifp; | ||
4623 | vif->wdev.netdev = ifp->ndev; | ||
4624 | ifp->ndev->ieee80211_ptr = &vif->wdev; | ||
4625 | SET_NETDEV_DEV(ifp->ndev, wiphy_dev(cfg->wiphy)); | ||
4626 | mutex_unlock(&event->vif_event_lock); | ||
4627 | wake_up(&event->vif_wq); | ||
4628 | return 0; | ||
4629 | |||
4630 | case BRCMF_E_IF_DEL: | ||
4631 | ifp->vif = NULL; | ||
4632 | mutex_unlock(&event->vif_event_lock); | ||
4633 | /* event may not be upon user request */ | ||
4634 | if (brcmf_cfg80211_vif_event_armed(cfg)) | ||
4635 | wake_up(&event->vif_wq); | ||
4636 | return 0; | ||
4637 | |||
4638 | case BRCMF_E_IF_CHANGE: | ||
4639 | mutex_unlock(&event->vif_event_lock); | ||
4640 | wake_up(&event->vif_wq); | ||
4641 | return 0; | ||
4642 | |||
4643 | default: | ||
4644 | mutex_unlock(&event->vif_event_lock); | ||
4645 | break; | ||
4646 | } | ||
4647 | return -EINVAL; | ||
4648 | } | ||
4649 | |||
4115 | static void brcmf_init_conf(struct brcmf_cfg80211_conf *conf) | 4650 | static void brcmf_init_conf(struct brcmf_cfg80211_conf *conf) |
4116 | { | 4651 | { |
4117 | conf->frag_threshold = (u32)-1; | 4652 | conf->frag_threshold = (u32)-1; |
@@ -4143,6 +4678,18 @@ static void brcmf_register_event_handlers(struct brcmf_cfg80211_info *cfg) | |||
4143 | brcmf_notify_connect_status); | 4678 | brcmf_notify_connect_status); |
4144 | brcmf_fweh_register(cfg->pub, BRCMF_E_PFN_NET_FOUND, | 4679 | brcmf_fweh_register(cfg->pub, BRCMF_E_PFN_NET_FOUND, |
4145 | brcmf_notify_sched_scan_results); | 4680 | brcmf_notify_sched_scan_results); |
4681 | brcmf_fweh_register(cfg->pub, BRCMF_E_IF, | ||
4682 | brcmf_notify_vif_event); | ||
4683 | brcmf_fweh_register(cfg->pub, BRCMF_E_P2P_PROBEREQ_MSG, | ||
4684 | brcmf_p2p_notify_rx_mgmt_p2p_probereq); | ||
4685 | brcmf_fweh_register(cfg->pub, BRCMF_E_P2P_DISC_LISTEN_COMPLETE, | ||
4686 | brcmf_p2p_notify_listen_complete); | ||
4687 | brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_RX, | ||
4688 | brcmf_p2p_notify_action_frame_rx); | ||
4689 | brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_COMPLETE, | ||
4690 | brcmf_p2p_notify_action_tx_complete); | ||
4691 | brcmf_fweh_register(cfg->pub, BRCMF_E_ACTION_FRAME_OFF_CHAN_COMPLETE, | ||
4692 | brcmf_p2p_notify_action_tx_complete); | ||
4146 | } | 4693 | } |
4147 | 4694 | ||
4148 | static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_info *cfg) | 4695 | static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_info *cfg) |
@@ -4198,7 +4745,7 @@ static s32 wl_init_priv(struct brcmf_cfg80211_info *cfg) | |||
4198 | mutex_init(&cfg->usr_sync); | 4745 | mutex_init(&cfg->usr_sync); |
4199 | brcmf_init_escan(cfg); | 4746 | brcmf_init_escan(cfg); |
4200 | brcmf_init_conf(cfg->conf); | 4747 | brcmf_init_conf(cfg->conf); |
4201 | 4748 | init_completion(&cfg->vif_disabled); | |
4202 | return err; | 4749 | return err; |
4203 | } | 4750 | } |
4204 | 4751 | ||
@@ -4209,6 +4756,12 @@ static void wl_deinit_priv(struct brcmf_cfg80211_info *cfg) | |||
4209 | brcmf_deinit_priv_mem(cfg); | 4756 | brcmf_deinit_priv_mem(cfg); |
4210 | } | 4757 | } |
4211 | 4758 | ||
4759 | static void init_vif_event(struct brcmf_cfg80211_vif_event *event) | ||
4760 | { | ||
4761 | init_waitqueue_head(&event->vif_wq); | ||
4762 | mutex_init(&event->vif_event_lock); | ||
4763 | } | ||
4764 | |||
4212 | struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr, | 4765 | struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr, |
4213 | struct device *busdev) | 4766 | struct device *busdev) |
4214 | { | 4767 | { |
@@ -4232,25 +4785,41 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr, | |||
4232 | cfg = wiphy_priv(wiphy); | 4785 | cfg = wiphy_priv(wiphy); |
4233 | cfg->wiphy = wiphy; | 4786 | cfg->wiphy = wiphy; |
4234 | cfg->pub = drvr; | 4787 | cfg->pub = drvr; |
4788 | init_vif_event(&cfg->vif_event); | ||
4235 | INIT_LIST_HEAD(&cfg->vif_list); | 4789 | INIT_LIST_HEAD(&cfg->vif_list); |
4236 | 4790 | ||
4237 | vif = brcmf_alloc_vif(cfg, ndev, WL_MODE_BSS, false); | 4791 | vif = brcmf_alloc_vif(cfg, NL80211_IFTYPE_STATION, false); |
4238 | if (IS_ERR(vif)) { | 4792 | if (IS_ERR(vif)) { |
4239 | wiphy_free(wiphy); | 4793 | wiphy_free(wiphy); |
4240 | return NULL; | 4794 | return NULL; |
4241 | } | 4795 | } |
4242 | 4796 | ||
4797 | vif->ifp = ifp; | ||
4798 | vif->wdev.netdev = ndev; | ||
4799 | ndev->ieee80211_ptr = &vif->wdev; | ||
4800 | SET_NETDEV_DEV(ndev, wiphy_dev(cfg->wiphy)); | ||
4801 | |||
4243 | err = wl_init_priv(cfg); | 4802 | err = wl_init_priv(cfg); |
4244 | if (err) { | 4803 | if (err) { |
4245 | brcmf_err("Failed to init iwm_priv (%d)\n", err); | 4804 | brcmf_err("Failed to init iwm_priv (%d)\n", err); |
4246 | goto cfg80211_attach_out; | 4805 | goto cfg80211_attach_out; |
4247 | } | 4806 | } |
4248 | |||
4249 | ifp->vif = vif; | 4807 | ifp->vif = vif; |
4808 | |||
4809 | err = brcmf_p2p_attach(cfg); | ||
4810 | if (err) { | ||
4811 | brcmf_err("P2P initilisation failed (%d)\n", err); | ||
4812 | goto cfg80211_p2p_attach_out; | ||
4813 | } | ||
4814 | |||
4250 | return cfg; | 4815 | return cfg; |
4251 | 4816 | ||
4817 | cfg80211_p2p_attach_out: | ||
4818 | wl_deinit_priv(cfg); | ||
4819 | |||
4252 | cfg80211_attach_out: | 4820 | cfg80211_attach_out: |
4253 | brcmf_free_vif(vif); | 4821 | brcmf_free_vif(vif); |
4822 | wiphy_free(wiphy); | ||
4254 | return NULL; | 4823 | return NULL; |
4255 | } | 4824 | } |
4256 | 4825 | ||
@@ -4489,3 +5058,57 @@ s32 brcmf_cfg80211_down(struct net_device *ndev) | |||
4489 | return err; | 5058 | return err; |
4490 | } | 5059 | } |
4491 | 5060 | ||
5061 | u32 wl_get_vif_state_all(struct brcmf_cfg80211_info *cfg, unsigned long state) | ||
5062 | { | ||
5063 | struct brcmf_cfg80211_vif *vif; | ||
5064 | bool result = 0; | ||
5065 | |||
5066 | list_for_each_entry(vif, &cfg->vif_list, list) { | ||
5067 | if (test_bit(state, &vif->sme_state)) | ||
5068 | result++; | ||
5069 | } | ||
5070 | return result; | ||
5071 | } | ||
5072 | |||
5073 | static inline bool vif_event_equals(struct brcmf_cfg80211_vif_event *event, | ||
5074 | u8 action) | ||
5075 | { | ||
5076 | u8 evt_action; | ||
5077 | |||
5078 | mutex_lock(&event->vif_event_lock); | ||
5079 | evt_action = event->action; | ||
5080 | mutex_unlock(&event->vif_event_lock); | ||
5081 | return evt_action == action; | ||
5082 | } | ||
5083 | |||
5084 | void brcmf_cfg80211_arm_vif_event(struct brcmf_cfg80211_info *cfg, | ||
5085 | struct brcmf_cfg80211_vif *vif) | ||
5086 | { | ||
5087 | struct brcmf_cfg80211_vif_event *event = &cfg->vif_event; | ||
5088 | |||
5089 | mutex_lock(&event->vif_event_lock); | ||
5090 | event->vif = vif; | ||
5091 | event->action = 0; | ||
5092 | mutex_unlock(&event->vif_event_lock); | ||
5093 | } | ||
5094 | |||
5095 | bool brcmf_cfg80211_vif_event_armed(struct brcmf_cfg80211_info *cfg) | ||
5096 | { | ||
5097 | struct brcmf_cfg80211_vif_event *event = &cfg->vif_event; | ||
5098 | bool armed; | ||
5099 | |||
5100 | mutex_lock(&event->vif_event_lock); | ||
5101 | armed = event->vif != NULL; | ||
5102 | mutex_unlock(&event->vif_event_lock); | ||
5103 | |||
5104 | return armed; | ||
5105 | } | ||
5106 | int brcmf_cfg80211_wait_vif_event_timeout(struct brcmf_cfg80211_info *cfg, | ||
5107 | u8 action, ulong timeout) | ||
5108 | { | ||
5109 | struct brcmf_cfg80211_vif_event *event = &cfg->vif_event; | ||
5110 | |||
5111 | return wait_event_timeout(event->vif_wq, | ||
5112 | vif_event_equals(event, action), timeout); | ||
5113 | } | ||
5114 | |||
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h index e4d9cc7a8e63..8b5d4989906c 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h | |||
@@ -41,6 +41,38 @@ | |||
41 | #define WL_AUTH_SHARED_KEY 1 /* d11 shared authentication */ | 41 | #define WL_AUTH_SHARED_KEY 1 /* d11 shared authentication */ |
42 | #define IE_MAX_LEN 512 | 42 | #define IE_MAX_LEN 512 |
43 | 43 | ||
44 | /* IE TLV processing */ | ||
45 | #define TLV_LEN_OFF 1 /* length offset */ | ||
46 | #define TLV_HDR_LEN 2 /* header length */ | ||
47 | #define TLV_BODY_OFF 2 /* body offset */ | ||
48 | #define TLV_OUI_LEN 3 /* oui id length */ | ||
49 | |||
50 | /* 802.11 Mgmt Packet flags */ | ||
51 | #define BRCMF_VNDR_IE_BEACON_FLAG 0x1 | ||
52 | #define BRCMF_VNDR_IE_PRBRSP_FLAG 0x2 | ||
53 | #define BRCMF_VNDR_IE_ASSOCRSP_FLAG 0x4 | ||
54 | #define BRCMF_VNDR_IE_AUTHRSP_FLAG 0x8 | ||
55 | #define BRCMF_VNDR_IE_PRBREQ_FLAG 0x10 | ||
56 | #define BRCMF_VNDR_IE_ASSOCREQ_FLAG 0x20 | ||
57 | /* vendor IE in IW advertisement protocol ID field */ | ||
58 | #define BRCMF_VNDR_IE_IWAPID_FLAG 0x40 | ||
59 | /* allow custom IE id */ | ||
60 | #define BRCMF_VNDR_IE_CUSTOM_FLAG 0x100 | ||
61 | |||
62 | /* P2P Action Frames flags (spec ordered) */ | ||
63 | #define BRCMF_VNDR_IE_GONREQ_FLAG 0x001000 | ||
64 | #define BRCMF_VNDR_IE_GONRSP_FLAG 0x002000 | ||
65 | #define BRCMF_VNDR_IE_GONCFM_FLAG 0x004000 | ||
66 | #define BRCMF_VNDR_IE_INVREQ_FLAG 0x008000 | ||
67 | #define BRCMF_VNDR_IE_INVRSP_FLAG 0x010000 | ||
68 | #define BRCMF_VNDR_IE_DISREQ_FLAG 0x020000 | ||
69 | #define BRCMF_VNDR_IE_DISRSP_FLAG 0x040000 | ||
70 | #define BRCMF_VNDR_IE_PRDREQ_FLAG 0x080000 | ||
71 | #define BRCMF_VNDR_IE_PRDRSP_FLAG 0x100000 | ||
72 | |||
73 | #define BRCMF_VNDR_IE_P2PAF_SHIFT 12 | ||
74 | |||
75 | |||
44 | /** | 76 | /** |
45 | * enum brcmf_scan_status - dongle scan status | 77 | * enum brcmf_scan_status - dongle scan status |
46 | * | 78 | * |
@@ -52,11 +84,19 @@ enum brcmf_scan_status { | |||
52 | BRCMF_SCAN_STATUS_ABORT, | 84 | BRCMF_SCAN_STATUS_ABORT, |
53 | }; | 85 | }; |
54 | 86 | ||
55 | /* wi-fi mode */ | 87 | /** |
88 | * enum wl_mode - driver mode of virtual interface. | ||
89 | * | ||
90 | * @WL_MODE_BSS: connects to BSS. | ||
91 | * @WL_MODE_IBSS: operate as ad-hoc. | ||
92 | * @WL_MODE_AP: operate as access-point. | ||
93 | * @WL_MODE_P2P: provide P2P discovery. | ||
94 | */ | ||
56 | enum wl_mode { | 95 | enum wl_mode { |
57 | WL_MODE_BSS, | 96 | WL_MODE_BSS, |
58 | WL_MODE_IBSS, | 97 | WL_MODE_IBSS, |
59 | WL_MODE_AP | 98 | WL_MODE_AP, |
99 | WL_MODE_P2P | ||
60 | }; | 100 | }; |
61 | 101 | ||
62 | /* dongle configuration */ | 102 | /* dongle configuration */ |
@@ -108,6 +148,7 @@ struct brcmf_cfg80211_profile { | |||
108 | * @BRCMF_VIF_STATUS_READY: ready for operation. | 148 | * @BRCMF_VIF_STATUS_READY: ready for operation. |
109 | * @BRCMF_VIF_STATUS_CONNECTING: connect/join in progress. | 149 | * @BRCMF_VIF_STATUS_CONNECTING: connect/join in progress. |
110 | * @BRCMF_VIF_STATUS_CONNECTED: connected/joined succesfully. | 150 | * @BRCMF_VIF_STATUS_CONNECTED: connected/joined succesfully. |
151 | * @BRCMF_VIF_STATUS_DISCONNECTING: disconnect/disable in progress. | ||
111 | * @BRCMF_VIF_STATUS_AP_CREATING: interface configured for AP operation. | 152 | * @BRCMF_VIF_STATUS_AP_CREATING: interface configured for AP operation. |
112 | * @BRCMF_VIF_STATUS_AP_CREATED: AP operation started. | 153 | * @BRCMF_VIF_STATUS_AP_CREATED: AP operation started. |
113 | */ | 154 | */ |
@@ -115,6 +156,7 @@ enum brcmf_vif_status { | |||
115 | BRCMF_VIF_STATUS_READY, | 156 | BRCMF_VIF_STATUS_READY, |
116 | BRCMF_VIF_STATUS_CONNECTING, | 157 | BRCMF_VIF_STATUS_CONNECTING, |
117 | BRCMF_VIF_STATUS_CONNECTED, | 158 | BRCMF_VIF_STATUS_CONNECTED, |
159 | BRCMF_VIF_STATUS_DISCONNECTING, | ||
118 | BRCMF_VIF_STATUS_AP_CREATING, | 160 | BRCMF_VIF_STATUS_AP_CREATING, |
119 | BRCMF_VIF_STATUS_AP_CREATED | 161 | BRCMF_VIF_STATUS_AP_CREATED |
120 | }; | 162 | }; |
@@ -122,16 +164,22 @@ enum brcmf_vif_status { | |||
122 | /** | 164 | /** |
123 | * struct vif_saved_ie - holds saved IEs for a virtual interface. | 165 | * struct vif_saved_ie - holds saved IEs for a virtual interface. |
124 | * | 166 | * |
167 | * @probe_req_ie: IE info for probe request. | ||
125 | * @probe_res_ie: IE info for probe response. | 168 | * @probe_res_ie: IE info for probe response. |
126 | * @beacon_ie: IE info for beacon frame. | 169 | * @beacon_ie: IE info for beacon frame. |
170 | * @probe_req_ie_len: IE info length for probe request. | ||
127 | * @probe_res_ie_len: IE info length for probe response. | 171 | * @probe_res_ie_len: IE info length for probe response. |
128 | * @beacon_ie_len: IE info length for beacon frame. | 172 | * @beacon_ie_len: IE info length for beacon frame. |
129 | */ | 173 | */ |
130 | struct vif_saved_ie { | 174 | struct vif_saved_ie { |
175 | u8 probe_req_ie[IE_MAX_LEN]; | ||
131 | u8 probe_res_ie[IE_MAX_LEN]; | 176 | u8 probe_res_ie[IE_MAX_LEN]; |
132 | u8 beacon_ie[IE_MAX_LEN]; | 177 | u8 beacon_ie[IE_MAX_LEN]; |
178 | u8 assoc_req_ie[IE_MAX_LEN]; | ||
179 | u32 probe_req_ie_len; | ||
133 | u32 probe_res_ie_len; | 180 | u32 probe_res_ie_len; |
134 | u32 beacon_ie_len; | 181 | u32 beacon_ie_len; |
182 | u32 assoc_req_ie_len; | ||
135 | }; | 183 | }; |
136 | 184 | ||
137 | /** | 185 | /** |
@@ -145,6 +193,7 @@ struct vif_saved_ie { | |||
145 | * @sme_state: SME state using enum brcmf_vif_status bits. | 193 | * @sme_state: SME state using enum brcmf_vif_status bits. |
146 | * @pm_block: power-management blocked. | 194 | * @pm_block: power-management blocked. |
147 | * @list: linked list. | 195 | * @list: linked list. |
196 | * @mgmt_rx_reg: registered rx mgmt frame types. | ||
148 | */ | 197 | */ |
149 | struct brcmf_cfg80211_vif { | 198 | struct brcmf_cfg80211_vif { |
150 | struct brcmf_if *ifp; | 199 | struct brcmf_if *ifp; |
@@ -156,6 +205,7 @@ struct brcmf_cfg80211_vif { | |||
156 | bool pm_block; | 205 | bool pm_block; |
157 | struct vif_saved_ie saved_ie; | 206 | struct vif_saved_ie saved_ie; |
158 | struct list_head list; | 207 | struct list_head list; |
208 | u16 mgmt_rx_reg; | ||
159 | }; | 209 | }; |
160 | 210 | ||
161 | /* association inform */ | 211 | /* association inform */ |
@@ -189,6 +239,9 @@ struct escan_info { | |||
189 | u8 escan_buf[WL_ESCAN_BUF_SIZE]; | 239 | u8 escan_buf[WL_ESCAN_BUF_SIZE]; |
190 | struct wiphy *wiphy; | 240 | struct wiphy *wiphy; |
191 | struct net_device *ndev; | 241 | struct net_device *ndev; |
242 | s32 (*run)(struct brcmf_cfg80211_info *cfg, | ||
243 | struct net_device *ndev, | ||
244 | struct cfg80211_scan_request *request, u16 action); | ||
192 | }; | 245 | }; |
193 | 246 | ||
194 | /** | 247 | /** |
@@ -273,10 +326,27 @@ struct brcmf_pno_scanresults_le { | |||
273 | }; | 326 | }; |
274 | 327 | ||
275 | /** | 328 | /** |
329 | * struct brcmf_cfg80211_vif_event - virtual interface event information. | ||
330 | * | ||
331 | * @vif_wq: waitqueue awaiting interface event from firmware. | ||
332 | * @vif_event_lock: protects other members in this structure. | ||
333 | * @vif_complete: completion for net attach. | ||
334 | * @action: either add, change, or delete. | ||
335 | * @vif: virtual interface object related to the event. | ||
336 | */ | ||
337 | struct brcmf_cfg80211_vif_event { | ||
338 | wait_queue_head_t vif_wq; | ||
339 | struct mutex vif_event_lock; | ||
340 | u8 action; | ||
341 | struct brcmf_cfg80211_vif *vif; | ||
342 | }; | ||
343 | |||
344 | /** | ||
276 | * struct brcmf_cfg80211_info - dongle private data of cfg80211 interface | 345 | * struct brcmf_cfg80211_info - dongle private data of cfg80211 interface |
277 | * | 346 | * |
278 | * @wiphy: wiphy object for cfg80211 interface. | 347 | * @wiphy: wiphy object for cfg80211 interface. |
279 | * @conf: dongle configuration. | 348 | * @conf: dongle configuration. |
349 | * @p2p: peer-to-peer specific information. | ||
280 | * @scan_request: cfg80211 scan request object. | 350 | * @scan_request: cfg80211 scan request object. |
281 | * @usr_sync: mainly for dongle up/down synchronization. | 351 | * @usr_sync: mainly for dongle up/down synchronization. |
282 | * @bss_list: bss_list holding scanned ap information. | 352 | * @bss_list: bss_list holding scanned ap information. |
@@ -304,10 +374,12 @@ struct brcmf_pno_scanresults_le { | |||
304 | * @escan_ioctl_buf: dongle command buffer for escan commands. | 374 | * @escan_ioctl_buf: dongle command buffer for escan commands. |
305 | * @vif_list: linked list of vif instances. | 375 | * @vif_list: linked list of vif instances. |
306 | * @vif_cnt: number of vif instances. | 376 | * @vif_cnt: number of vif instances. |
377 | * @vif_event: vif event signalling. | ||
307 | */ | 378 | */ |
308 | struct brcmf_cfg80211_info { | 379 | struct brcmf_cfg80211_info { |
309 | struct wiphy *wiphy; | 380 | struct wiphy *wiphy; |
310 | struct brcmf_cfg80211_conf *conf; | 381 | struct brcmf_cfg80211_conf *conf; |
382 | struct brcmf_p2p_info p2p; | ||
311 | struct cfg80211_scan_request *scan_request; | 383 | struct cfg80211_scan_request *scan_request; |
312 | struct mutex usr_sync; | 384 | struct mutex usr_sync; |
313 | struct brcmf_scan_results *bss_list; | 385 | struct brcmf_scan_results *bss_list; |
@@ -335,6 +407,21 @@ struct brcmf_cfg80211_info { | |||
335 | u8 *escan_ioctl_buf; | 407 | u8 *escan_ioctl_buf; |
336 | struct list_head vif_list; | 408 | struct list_head vif_list; |
337 | u8 vif_cnt; | 409 | u8 vif_cnt; |
410 | struct brcmf_cfg80211_vif_event vif_event; | ||
411 | struct completion vif_disabled; | ||
412 | }; | ||
413 | |||
414 | /** | ||
415 | * struct brcmf_tlv - tag_ID/length/value_buffer tuple. | ||
416 | * | ||
417 | * @id: tag identifier. | ||
418 | * @len: number of bytes in value buffer. | ||
419 | * @data: value buffer. | ||
420 | */ | ||
421 | struct brcmf_tlv { | ||
422 | u8 id; | ||
423 | u8 len; | ||
424 | u8 data[1]; | ||
338 | }; | 425 | }; |
339 | 426 | ||
340 | static inline struct wiphy *cfg_to_wiphy(struct brcmf_cfg80211_info *cfg) | 427 | static inline struct wiphy *cfg_to_wiphy(struct brcmf_cfg80211_info *cfg) |
@@ -389,4 +476,26 @@ void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg); | |||
389 | s32 brcmf_cfg80211_up(struct net_device *ndev); | 476 | s32 brcmf_cfg80211_up(struct net_device *ndev); |
390 | s32 brcmf_cfg80211_down(struct net_device *ndev); | 477 | s32 brcmf_cfg80211_down(struct net_device *ndev); |
391 | 478 | ||
479 | struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg, | ||
480 | enum nl80211_iftype type, | ||
481 | bool pm_block); | ||
482 | void brcmf_free_vif(struct brcmf_cfg80211_vif *vif); | ||
483 | |||
484 | s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag, | ||
485 | const u8 *vndr_ie_buf, u32 vndr_ie_len); | ||
486 | s32 brcmf_vif_clear_mgmt_ies(struct brcmf_cfg80211_vif *vif); | ||
487 | struct brcmf_tlv *brcmf_parse_tlvs(void *buf, int buflen, uint key); | ||
488 | u16 channel_to_chanspec(struct ieee80211_channel *ch); | ||
489 | u32 wl_get_vif_state_all(struct brcmf_cfg80211_info *cfg, unsigned long state); | ||
490 | void brcmf_cfg80211_arm_vif_event(struct brcmf_cfg80211_info *cfg, | ||
491 | struct brcmf_cfg80211_vif *vif); | ||
492 | bool brcmf_cfg80211_vif_event_armed(struct brcmf_cfg80211_info *cfg); | ||
493 | int brcmf_cfg80211_wait_vif_event_timeout(struct brcmf_cfg80211_info *cfg, | ||
494 | u8 action, ulong timeout); | ||
495 | s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg, | ||
496 | struct net_device *ndev, | ||
497 | bool aborted, bool fw_abort); | ||
498 | void brcmf_set_mpc(struct net_device *ndev, int mpc); | ||
499 | void brcmf_abort_scanning(struct brcmf_cfg80211_info *cfg); | ||
500 | |||
392 | #endif /* _wl_cfg80211_h_ */ | 501 | #endif /* _wl_cfg80211_h_ */ |
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/channel.c b/drivers/net/wireless/brcm80211/brcmsmac/channel.c index cdb62b8ccc79..10ee314c4229 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/channel.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/channel.c | |||
@@ -183,8 +183,7 @@ static bool brcms_c_country_valid(const char *ccode) | |||
183 | * chars. | 183 | * chars. |
184 | */ | 184 | */ |
185 | if (!((0x80 & ccode[0]) == 0 && ccode[0] >= 0x41 && ccode[0] <= 0x5A && | 185 | if (!((0x80 & ccode[0]) == 0 && ccode[0] >= 0x41 && ccode[0] <= 0x5A && |
186 | (0x80 & ccode[1]) == 0 && ccode[1] >= 0x41 && ccode[1] <= 0x5A && | 186 | (0x80 & ccode[1]) == 0 && ccode[1] >= 0x41 && ccode[1] <= 0x5A)) |
187 | ccode[2] == '\0')) | ||
188 | return false; | 187 | return false; |
189 | 188 | ||
190 | /* | 189 | /* |
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/main.c b/drivers/net/wireless/brcm80211/brcmsmac/main.c index 62be5502b95d..8ef02dca8f8c 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/main.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/main.c | |||
@@ -101,8 +101,6 @@ | |||
101 | #define DOT11_RTS_LEN 16 | 101 | #define DOT11_RTS_LEN 16 |
102 | #define DOT11_CTS_LEN 10 | 102 | #define DOT11_CTS_LEN 10 |
103 | #define DOT11_BA_BITMAP_LEN 128 | 103 | #define DOT11_BA_BITMAP_LEN 128 |
104 | #define DOT11_MIN_BEACON_PERIOD 1 | ||
105 | #define DOT11_MAX_BEACON_PERIOD 0xFFFF | ||
106 | #define DOT11_MAXNUMFRAGS 16 | 104 | #define DOT11_MAXNUMFRAGS 16 |
107 | #define DOT11_MAX_FRAG_LEN 2346 | 105 | #define DOT11_MAX_FRAG_LEN 2346 |
108 | 106 | ||
@@ -3140,8 +3138,7 @@ void brcms_c_reset(struct brcms_c_info *wlc) | |||
3140 | brcms_c_statsupd(wlc); | 3138 | brcms_c_statsupd(wlc); |
3141 | 3139 | ||
3142 | /* reset our snapshot of macstat counters */ | 3140 | /* reset our snapshot of macstat counters */ |
3143 | memset((char *)wlc->core->macstat_snapshot, 0, | 3141 | memset(wlc->core->macstat_snapshot, 0, sizeof(struct macstat)); |
3144 | sizeof(struct macstat)); | ||
3145 | 3142 | ||
3146 | brcms_b_reset(wlc->hw); | 3143 | brcms_b_reset(wlc->hw); |
3147 | } | 3144 | } |
@@ -4054,7 +4051,7 @@ void brcms_c_wme_setparams(struct brcms_c_info *wlc, u16 aci, | |||
4054 | return; | 4051 | return; |
4055 | } | 4052 | } |
4056 | 4053 | ||
4057 | memset((char *)&acp_shm, 0, sizeof(struct shm_acparams)); | 4054 | memset(&acp_shm, 0, sizeof(struct shm_acparams)); |
4058 | /* fill in shm ac params struct */ | 4055 | /* fill in shm ac params struct */ |
4059 | acp_shm.txop = params->txop; | 4056 | acp_shm.txop = params->txop; |
4060 | /* convert from units of 32us to us for ucode */ | 4057 | /* convert from units of 32us to us for ucode */ |
@@ -4770,7 +4767,7 @@ static void brcms_c_bss_default_init(struct brcms_c_info *wlc) | |||
4770 | struct brcms_bss_info *bi = wlc->default_bss; | 4767 | struct brcms_bss_info *bi = wlc->default_bss; |
4771 | 4768 | ||
4772 | /* init default and target BSS with some sane initial values */ | 4769 | /* init default and target BSS with some sane initial values */ |
4773 | memset((char *)(bi), 0, sizeof(struct brcms_bss_info)); | 4770 | memset(bi, 0, sizeof(*bi)); |
4774 | bi->beacon_period = BEACON_INTERVAL_DEFAULT; | 4771 | bi->beacon_period = BEACON_INTERVAL_DEFAULT; |
4775 | 4772 | ||
4776 | /* fill the default channel as the first valid channel | 4773 | /* fill the default channel as the first valid channel |
@@ -5299,7 +5296,7 @@ int brcms_c_set_gmode(struct brcms_c_info *wlc, u8 gmode, bool config) | |||
5299 | brcms_c_protection_upd(wlc, BRCMS_PROT_G_USER, gmode); | 5296 | brcms_c_protection_upd(wlc, BRCMS_PROT_G_USER, gmode); |
5300 | 5297 | ||
5301 | /* Clear rateset override */ | 5298 | /* Clear rateset override */ |
5302 | memset(&rs, 0, sizeof(struct brcms_c_rateset)); | 5299 | memset(&rs, 0, sizeof(rs)); |
5303 | 5300 | ||
5304 | switch (gmode) { | 5301 | switch (gmode) { |
5305 | case GMODE_LEGACY_B: | 5302 | case GMODE_LEGACY_B: |
@@ -5522,7 +5519,7 @@ int brcms_c_set_rateset(struct brcms_c_info *wlc, struct brcm_rateset *rs) | |||
5522 | if (rs->count > BRCMS_NUMRATES) | 5519 | if (rs->count > BRCMS_NUMRATES) |
5523 | return -ENOBUFS; | 5520 | return -ENOBUFS; |
5524 | 5521 | ||
5525 | memset(&internal_rs, 0, sizeof(struct brcms_c_rateset)); | 5522 | memset(&internal_rs, 0, sizeof(internal_rs)); |
5526 | 5523 | ||
5527 | /* Copy only legacy rateset section */ | 5524 | /* Copy only legacy rateset section */ |
5528 | internal_rs.count = rs->count; | 5525 | internal_rs.count = rs->count; |
@@ -5548,8 +5545,7 @@ int brcms_c_set_rateset(struct brcms_c_info *wlc, struct brcm_rateset *rs) | |||
5548 | 5545 | ||
5549 | int brcms_c_set_beacon_period(struct brcms_c_info *wlc, u16 period) | 5546 | int brcms_c_set_beacon_period(struct brcms_c_info *wlc, u16 period) |
5550 | { | 5547 | { |
5551 | if (period < DOT11_MIN_BEACON_PERIOD || | 5548 | if (period == 0) |
5552 | period > DOT11_MAX_BEACON_PERIOD) | ||
5553 | return -EINVAL; | 5549 | return -EINVAL; |
5554 | 5550 | ||
5555 | wlc->default_bss->beacon_period = period; | 5551 | wlc->default_bss->beacon_period = period; |
@@ -5626,7 +5622,7 @@ int brcms_c_module_unregister(struct brcms_pub *pub, const char *name, | |||
5626 | for (i = 0; i < BRCMS_MAXMODULES; i++) { | 5622 | for (i = 0; i < BRCMS_MAXMODULES; i++) { |
5627 | if (!strcmp(wlc->modulecb[i].name, name) && | 5623 | if (!strcmp(wlc->modulecb[i].name, name) && |
5628 | (wlc->modulecb[i].hdl == hdl)) { | 5624 | (wlc->modulecb[i].hdl == hdl)) { |
5629 | memset(&wlc->modulecb[i], 0, sizeof(struct modulecb)); | 5625 | memset(&wlc->modulecb[i], 0, sizeof(wlc->modulecb[i])); |
5630 | return 0; | 5626 | return 0; |
5631 | } | 5627 | } |
5632 | } | 5628 | } |
@@ -6446,10 +6442,9 @@ brcms_c_d11hdrs_mac80211(struct brcms_c_info *wlc, struct ieee80211_hw *hw, | |||
6446 | 6442 | ||
6447 | if ((txrate[k]->flags & IEEE80211_TX_RC_MCS) | 6443 | if ((txrate[k]->flags & IEEE80211_TX_RC_MCS) |
6448 | && (!is_mcs_rate(rspec[k]))) { | 6444 | && (!is_mcs_rate(rspec[k]))) { |
6449 | brcms_err(wlc->hw->d11core, | 6445 | brcms_warn(wlc->hw->d11core, |
6450 | "wl%d: %s: IEEE80211_TX_" | 6446 | "wl%d: %s: IEEE80211_TX_RC_MCS != is_mcs_rate(rspec)\n", |
6451 | "RC_MCS != is_mcs_rate(rspec)\n", | 6447 | wlc->pub->unit, __func__); |
6452 | wlc->pub->unit, __func__); | ||
6453 | } | 6448 | } |
6454 | 6449 | ||
6455 | if (is_mcs_rate(rspec[k])) { | 6450 | if (is_mcs_rate(rspec[k])) { |
@@ -6682,11 +6677,9 @@ brcms_c_d11hdrs_mac80211(struct brcms_c_info *wlc, struct ieee80211_hw *hw, | |||
6682 | (struct ofdm_phy_hdr *) rts_plcp) : | 6677 | (struct ofdm_phy_hdr *) rts_plcp) : |
6683 | rts_plcp[0]) << 8; | 6678 | rts_plcp[0]) << 8; |
6684 | } else { | 6679 | } else { |
6685 | memset((char *)txh->RTSPhyHeader, 0, D11_PHY_HDR_LEN); | 6680 | memset(txh->RTSPhyHeader, 0, D11_PHY_HDR_LEN); |
6686 | memset((char *)&txh->rts_frame, 0, | 6681 | memset(&txh->rts_frame, 0, sizeof(struct ieee80211_rts)); |
6687 | sizeof(struct ieee80211_rts)); | 6682 | memset(txh->RTSPLCPFallback, 0, sizeof(txh->RTSPLCPFallback)); |
6688 | memset((char *)txh->RTSPLCPFallback, 0, | ||
6689 | sizeof(txh->RTSPLCPFallback)); | ||
6690 | txh->RTSDurFallback = 0; | 6683 | txh->RTSDurFallback = 0; |
6691 | } | 6684 | } |
6692 | 6685 | ||
@@ -6841,21 +6834,19 @@ brcms_c_d11hdrs_mac80211(struct brcms_c_info *wlc, struct ieee80211_hw *hw, | |||
6841 | wlc->fragthresh[queue] = | 6834 | wlc->fragthresh[queue] = |
6842 | (u16) newfragthresh; | 6835 | (u16) newfragthresh; |
6843 | } else { | 6836 | } else { |
6844 | brcms_err(wlc->hw->d11core, | 6837 | brcms_warn(wlc->hw->d11core, |
6845 | "wl%d: %s txop invalid " | 6838 | "wl%d: %s txop invalid for rate %d\n", |
6846 | "for rate %d\n", | 6839 | wlc->pub->unit, fifo_names[queue], |
6847 | wlc->pub->unit, fifo_names[queue], | 6840 | rspec2rate(rspec[0])); |
6848 | rspec2rate(rspec[0])); | ||
6849 | } | 6841 | } |
6850 | 6842 | ||
6851 | if (dur > wlc->edcf_txop[ac]) | 6843 | if (dur > wlc->edcf_txop[ac]) |
6852 | brcms_err(wlc->hw->d11core, | 6844 | brcms_warn(wlc->hw->d11core, |
6853 | "wl%d: %s: %s txop " | 6845 | "wl%d: %s: %s txop exceeded phylen %d/%d dur %d/%d\n", |
6854 | "exceeded phylen %d/%d dur %d/%d\n", | 6846 | wlc->pub->unit, __func__, |
6855 | wlc->pub->unit, __func__, | 6847 | fifo_names[queue], |
6856 | fifo_names[queue], | 6848 | phylen, wlc->fragthresh[queue], |
6857 | phylen, wlc->fragthresh[queue], | 6849 | dur, wlc->edcf_txop[ac]); |
6858 | dur, wlc->edcf_txop[ac]); | ||
6859 | } | 6850 | } |
6860 | } | 6851 | } |
6861 | 6852 | ||
@@ -7330,7 +7321,7 @@ brcms_c_bcn_prb_template(struct brcms_c_info *wlc, u16 type, | |||
7330 | *len = hdr_len + body_len; | 7321 | *len = hdr_len + body_len; |
7331 | 7322 | ||
7332 | /* format PHY and MAC headers */ | 7323 | /* format PHY and MAC headers */ |
7333 | memset((char *)buf, 0, hdr_len); | 7324 | memset(buf, 0, hdr_len); |
7334 | 7325 | ||
7335 | plcp = (struct cck_phy_hdr *) buf; | 7326 | plcp = (struct cck_phy_hdr *) buf; |
7336 | 7327 | ||
@@ -7401,9 +7392,13 @@ brcms_c_bss_update_probe_resp(struct brcms_c_info *wlc, | |||
7401 | struct brcms_bss_cfg *cfg, | 7392 | struct brcms_bss_cfg *cfg, |
7402 | bool suspend) | 7393 | bool suspend) |
7403 | { | 7394 | { |
7404 | u16 prb_resp[BCN_TMPL_LEN / 2]; | 7395 | u16 *prb_resp; |
7405 | int len = BCN_TMPL_LEN; | 7396 | int len = BCN_TMPL_LEN; |
7406 | 7397 | ||
7398 | prb_resp = kmalloc(BCN_TMPL_LEN, GFP_ATOMIC); | ||
7399 | if (!prb_resp) | ||
7400 | return; | ||
7401 | |||
7407 | /* | 7402 | /* |
7408 | * write the probe response to hardware, or save in | 7403 | * write the probe response to hardware, or save in |
7409 | * the config structure | 7404 | * the config structure |
@@ -7437,6 +7432,8 @@ brcms_c_bss_update_probe_resp(struct brcms_c_info *wlc, | |||
7437 | 7432 | ||
7438 | if (suspend) | 7433 | if (suspend) |
7439 | brcms_c_enable_mac(wlc); | 7434 | brcms_c_enable_mac(wlc); |
7435 | |||
7436 | kfree(prb_resp); | ||
7440 | } | 7437 | } |
7441 | 7438 | ||
7442 | void brcms_c_update_probe_resp(struct brcms_c_info *wlc, bool suspend) | 7439 | void brcms_c_update_probe_resp(struct brcms_c_info *wlc, bool suspend) |