diff options
author | Arend van Spriel <arend@broadcom.com> | 2013-04-05 04:57:50 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2013-04-08 15:28:46 -0400 |
commit | 27f10e380ad912c7928e08c4d04b246e66022cc4 (patch) | |
tree | 93f8f52d32db0e78e5821e1dedfabb234b17d9e4 /drivers/net/wireless/brcm80211/brcmfmac/p2p.c | |
parent | a0f472aca2ff1d241afc5ac1e804b50b5f3be6a4 (diff) |
brcmfmac: support creation of P2P_DEVICE through user-space
The current driver code creates a P2P_DEVICE through a module
parameter. This device has a dummy netdevice which is not how this
interface type is intended. This patch add proper support for the
P2P_DEVICE interface type. This requires a wpa_supplicant with such
support as well.
Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
Reviewed-by: Piotr Haber <phaber@broadcom.com>
Reviewed-by: Hante Meuleman <meuleman@broadcom.com>
Signed-off-by: Arend van Spriel <arend@broadcom.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/brcm80211/brcmfmac/p2p.c')
-rw-r--r-- | drivers/net/wireless/brcm80211/brcmfmac/p2p.c | 148 |
1 files changed, 139 insertions, 9 deletions
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/p2p.c b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c index e587dfb5d256..5d5d1e48a383 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/p2p.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c | |||
@@ -15,6 +15,7 @@ | |||
15 | */ | 15 | */ |
16 | #include <linux/slab.h> | 16 | #include <linux/slab.h> |
17 | #include <linux/netdevice.h> | 17 | #include <linux/netdevice.h> |
18 | #include <linux/etherdevice.h> | ||
18 | #include <net/cfg80211.h> | 19 | #include <net/cfg80211.h> |
19 | 20 | ||
20 | #include <brcmu_wifi.h> | 21 | #include <brcmu_wifi.h> |
@@ -455,7 +456,9 @@ static int brcmf_p2p_set_firmware(struct brcmf_if *ifp, u8 *p2p_mac) | |||
455 | { | 456 | { |
456 | s32 ret = 0; | 457 | s32 ret = 0; |
457 | 458 | ||
459 | brcmf_fil_cmd_int_set(ifp, BRCMF_C_DOWN, 1); | ||
458 | brcmf_fil_iovar_int_set(ifp, "apsta", 1); | 460 | brcmf_fil_iovar_int_set(ifp, "apsta", 1); |
461 | brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1); | ||
459 | 462 | ||
460 | /* In case of COB type, firmware has default mac address | 463 | /* In case of COB type, firmware has default mac address |
461 | * After Initializing firmware, we have to set current mac address to | 464 | * After Initializing firmware, we have to set current mac address to |
@@ -473,21 +476,29 @@ static int brcmf_p2p_set_firmware(struct brcmf_if *ifp, u8 *p2p_mac) | |||
473 | * brcmf_p2p_generate_bss_mac() - derive mac addresses for P2P. | 476 | * brcmf_p2p_generate_bss_mac() - derive mac addresses for P2P. |
474 | * | 477 | * |
475 | * @p2p: P2P specific data. | 478 | * @p2p: P2P specific data. |
479 | * @dev_addr: optional device address. | ||
476 | * | 480 | * |
477 | * P2P needs mac addresses for P2P device and interface. These are | 481 | * P2P needs mac addresses for P2P device and interface. If no device |
478 | * derived from the primary net device, ie. the permanent ethernet | 482 | * address it specified, these are derived from the primary net device, ie. |
479 | * address of the device. | 483 | * the permanent ethernet address of the device. |
480 | */ | 484 | */ |
481 | static void brcmf_p2p_generate_bss_mac(struct brcmf_p2p_info *p2p) | 485 | static void brcmf_p2p_generate_bss_mac(struct brcmf_p2p_info *p2p, u8 *dev_addr) |
482 | { | 486 | { |
483 | struct brcmf_if *pri_ifp = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp; | 487 | 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; | 488 | struct brcmf_if *p2p_ifp = p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif->ifp; |
489 | bool local_admin = false; | ||
490 | |||
491 | if (!dev_addr || is_zero_ether_addr(dev_addr)) { | ||
492 | dev_addr = pri_ifp->mac_addr; | ||
493 | local_admin = true; | ||
494 | } | ||
485 | 495 | ||
486 | /* Generate the P2P Device Address. This consists of the device's | 496 | /* Generate the P2P Device Address. This consists of the device's |
487 | * primary MAC address with the locally administered bit set. | 497 | * primary MAC address with the locally administered bit set. |
488 | */ | 498 | */ |
489 | memcpy(p2p->dev_addr, pri_ifp->mac_addr, ETH_ALEN); | 499 | memcpy(p2p->dev_addr, dev_addr, ETH_ALEN); |
490 | p2p->dev_addr[0] |= 0x02; | 500 | if (local_admin) |
501 | p2p->dev_addr[0] |= 0x02; | ||
491 | memcpy(p2p_ifp->mac_addr, p2p->dev_addr, ETH_ALEN); | 502 | memcpy(p2p_ifp->mac_addr, p2p->dev_addr, ETH_ALEN); |
492 | 503 | ||
493 | /* Generate the P2P Interface Address. If the discovery and connection | 504 | /* Generate the P2P Interface Address. If the discovery and connection |
@@ -495,6 +506,7 @@ static void brcmf_p2p_generate_bss_mac(struct brcmf_p2p_info *p2p) | |||
495 | * different from the P2P Device Address, but also locally administered. | 506 | * different from the P2P Device Address, but also locally administered. |
496 | */ | 507 | */ |
497 | memcpy(p2p->int_addr, p2p->dev_addr, ETH_ALEN); | 508 | memcpy(p2p->int_addr, p2p->dev_addr, ETH_ALEN); |
509 | p2p->int_addr[0] |= 0x02; | ||
498 | p2p->int_addr[4] ^= 0x80; | 510 | p2p->int_addr[4] ^= 0x80; |
499 | } | 511 | } |
500 | 512 | ||
@@ -1935,7 +1947,7 @@ s32 brcmf_p2p_attach(struct brcmf_cfg80211_info *cfg) | |||
1935 | 1947 | ||
1936 | p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif = p2p_vif; | 1948 | p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif = p2p_vif; |
1937 | 1949 | ||
1938 | brcmf_p2p_generate_bss_mac(p2p); | 1950 | brcmf_p2p_generate_bss_mac(p2p, NULL); |
1939 | brcmf_p2p_set_firmware(pri_ifp, p2p->dev_addr); | 1951 | brcmf_p2p_set_firmware(pri_ifp, p2p->dev_addr); |
1940 | 1952 | ||
1941 | /* Initialize P2P Discovery in the firmware */ | 1953 | /* Initialize P2P Discovery in the firmware */ |
@@ -2125,13 +2137,96 @@ static int brcmf_p2p_release_p2p_if(struct brcmf_cfg80211_vif *vif) | |||
2125 | } | 2137 | } |
2126 | 2138 | ||
2127 | /** | 2139 | /** |
2140 | * brcmf_p2p_create_p2pdev() - create a P2P_DEVICE virtual interface. | ||
2141 | * | ||
2142 | * @p2p: P2P specific data. | ||
2143 | * @wiphy: wiphy device of new interface. | ||
2144 | * @addr: mac address for this new interface. | ||
2145 | */ | ||
2146 | static struct wireless_dev *brcmf_p2p_create_p2pdev(struct brcmf_p2p_info *p2p, | ||
2147 | struct wiphy *wiphy, | ||
2148 | u8 *addr) | ||
2149 | { | ||
2150 | struct brcmf_cfg80211_vif *p2p_vif; | ||
2151 | struct brcmf_if *p2p_ifp; | ||
2152 | struct brcmf_if *pri_ifp; | ||
2153 | int err; | ||
2154 | u32 bssidx; | ||
2155 | |||
2156 | if (p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif) | ||
2157 | return ERR_PTR(-ENOSPC); | ||
2158 | |||
2159 | p2p_vif = brcmf_alloc_vif(p2p->cfg, NL80211_IFTYPE_P2P_DEVICE, | ||
2160 | false); | ||
2161 | if (IS_ERR(p2p_vif)) { | ||
2162 | brcmf_err("could not create discovery vif\n"); | ||
2163 | return (struct wireless_dev *)p2p_vif; | ||
2164 | } | ||
2165 | |||
2166 | /* create ifp here */ | ||
2167 | p2p_ifp = kzalloc(sizeof(*p2p_ifp), GFP_KERNEL); | ||
2168 | if (!p2p_ifp) | ||
2169 | return ERR_PTR(-ENOMEM); | ||
2170 | |||
2171 | p2p_vif->ifp = p2p_ifp; | ||
2172 | p2p_ifp->vif = p2p_vif; | ||
2173 | |||
2174 | p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif = p2p_vif; | ||
2175 | brcmf_p2p_generate_bss_mac(p2p, addr); | ||
2176 | memcpy(&p2p_vif->wdev.address, p2p->dev_addr, sizeof(p2p->dev_addr)); | ||
2177 | |||
2178 | pri_ifp = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp; | ||
2179 | brcmf_p2p_set_firmware(pri_ifp, p2p->dev_addr); | ||
2180 | |||
2181 | /* Initialize P2P Discovery in the firmware */ | ||
2182 | err = brcmf_fil_iovar_int_set(pri_ifp, "p2p_disc", 1); | ||
2183 | if (err < 0) { | ||
2184 | brcmf_err("set p2p_disc error\n"); | ||
2185 | brcmf_free_vif(p2p_vif); | ||
2186 | return ERR_PTR(err); | ||
2187 | } | ||
2188 | /* obtain bsscfg index for P2P discovery */ | ||
2189 | err = brcmf_fil_iovar_int_get(pri_ifp, "p2p_dev", &bssidx); | ||
2190 | if (err < 0) { | ||
2191 | brcmf_err("retrieving discover bsscfg index failed\n"); | ||
2192 | brcmf_free_vif(p2p_vif); | ||
2193 | return ERR_PTR(err); | ||
2194 | } | ||
2195 | |||
2196 | p2p_ifp->drvr = p2p->cfg->pub; | ||
2197 | p2p_ifp->bssidx = bssidx; | ||
2198 | |||
2199 | init_completion(&p2p->send_af_done); | ||
2200 | INIT_WORK(&p2p->afx_hdl.afx_work, brcmf_p2p_afx_handler); | ||
2201 | init_completion(&p2p->afx_hdl.act_frm_scan); | ||
2202 | init_completion(&p2p->wait_next_af); | ||
2203 | |||
2204 | return &p2p_vif->wdev; | ||
2205 | } | ||
2206 | |||
2207 | /** | ||
2208 | * brcmf_p2p_delete_p2pdev() - delete P2P_DEVICE virtual interface. | ||
2209 | * | ||
2210 | * @vif: virtual interface object to delete. | ||
2211 | */ | ||
2212 | static void brcmf_p2p_delete_p2pdev(struct brcmf_cfg80211_vif *vif) | ||
2213 | { | ||
2214 | struct brcmf_p2p_info *p2p = &vif->ifp->drvr->config->p2p; | ||
2215 | |||
2216 | cfg80211_unregister_wdev(&vif->wdev); | ||
2217 | p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif = NULL; | ||
2218 | kfree(vif->ifp); | ||
2219 | brcmf_free_vif(vif); | ||
2220 | } | ||
2221 | |||
2222 | /** | ||
2128 | * brcmf_p2p_add_vif() - create a new P2P virtual interface. | 2223 | * brcmf_p2p_add_vif() - create a new P2P virtual interface. |
2129 | * | 2224 | * |
2130 | * @wiphy: wiphy device of new interface. | 2225 | * @wiphy: wiphy device of new interface. |
2131 | * @name: name of the new interface. | 2226 | * @name: name of the new interface. |
2132 | * @type: nl80211 interface type. | 2227 | * @type: nl80211 interface type. |
2133 | * @flags: TBD | 2228 | * @flags: not used. |
2134 | * @params: TBD | 2229 | * @params: contains mac address for P2P device. |
2135 | */ | 2230 | */ |
2136 | struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name, | 2231 | struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name, |
2137 | enum nl80211_iftype type, u32 *flags, | 2232 | enum nl80211_iftype type, u32 *flags, |
@@ -2158,6 +2253,9 @@ struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name, | |||
2158 | iftype = BRCMF_FIL_P2P_IF_GO; | 2253 | iftype = BRCMF_FIL_P2P_IF_GO; |
2159 | mode = WL_MODE_AP; | 2254 | mode = WL_MODE_AP; |
2160 | break; | 2255 | break; |
2256 | case NL80211_IFTYPE_P2P_DEVICE: | ||
2257 | return brcmf_p2p_create_p2pdev(&cfg->p2p, wiphy, | ||
2258 | params->macaddr); | ||
2161 | default: | 2259 | default: |
2162 | return ERR_PTR(-EOPNOTSUPP); | 2260 | return ERR_PTR(-EOPNOTSUPP); |
2163 | } | 2261 | } |
@@ -2245,6 +2343,8 @@ int brcmf_p2p_del_vif(struct wiphy *wiphy, struct wireless_dev *wdev) | |||
2245 | break; | 2343 | break; |
2246 | 2344 | ||
2247 | case NL80211_IFTYPE_P2P_DEVICE: | 2345 | case NL80211_IFTYPE_P2P_DEVICE: |
2346 | brcmf_p2p_delete_p2pdev(vif); | ||
2347 | return 0; | ||
2248 | default: | 2348 | default: |
2249 | return -ENOTSUPP; | 2349 | return -ENOTSUPP; |
2250 | break; | 2350 | break; |
@@ -2276,3 +2376,33 @@ int brcmf_p2p_del_vif(struct wiphy *wiphy, struct wireless_dev *wdev) | |||
2276 | 2376 | ||
2277 | return err; | 2377 | return err; |
2278 | } | 2378 | } |
2379 | |||
2380 | int brcmf_p2p_start_device(struct wiphy *wiphy, struct wireless_dev *wdev) | ||
2381 | { | ||
2382 | struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); | ||
2383 | struct brcmf_p2p_info *p2p = &cfg->p2p; | ||
2384 | struct brcmf_cfg80211_vif *vif; | ||
2385 | int err; | ||
2386 | |||
2387 | vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev); | ||
2388 | mutex_lock(&cfg->usr_sync); | ||
2389 | err = brcmf_p2p_enable_discovery(p2p); | ||
2390 | if (!err) | ||
2391 | set_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state); | ||
2392 | mutex_unlock(&cfg->usr_sync); | ||
2393 | return err; | ||
2394 | } | ||
2395 | |||
2396 | void brcmf_p2p_stop_device(struct wiphy *wiphy, struct wireless_dev *wdev) | ||
2397 | { | ||
2398 | struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); | ||
2399 | struct brcmf_p2p_info *p2p = &cfg->p2p; | ||
2400 | struct brcmf_cfg80211_vif *vif; | ||
2401 | |||
2402 | vif = container_of(wdev, struct brcmf_cfg80211_vif, wdev); | ||
2403 | mutex_lock(&cfg->usr_sync); | ||
2404 | (void)brcmf_p2p_deinit_discovery(p2p); | ||
2405 | brcmf_abort_scanning(cfg); | ||
2406 | clear_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state); | ||
2407 | mutex_unlock(&cfg->usr_sync); | ||
2408 | } | ||