Skip to content

Commit

Permalink
wl12xx: fix roaming
Browse files Browse the repository at this point in the history
The wl12xx device normally drops all frames coming from BSSID
it is not joined with.

This behavior is configured today by the wl12xx driver in response
to a handful of ieee80211_bss_change and ieee80211_conf_changed
notification flags, such as BSS_CHANGED_ASSOC, BSS_CHANGED_BSSID,
IEEE80211_CONF_CHANGE_IDLE, etc..

This breaks when we roam to a new BSSID, where authentication frames
are sent before any BSS_CHANGED/CONF_CHANGED flags are received.
When this happens the hardware silently drops the authentication
responses, and the roaming fails.

Ideally this aggressive filtering behavior of the device should be disabled
upon a notification from mac80211. Such notification will take place
after multi-channel support will be added: mac80211 will likely send a
remain-on-channel notification to drivers when entering sensitive
states (like authentication), otherwise the firmware might jump to
different channels (to serve a different role).

Until those notifications materialize, disable the hw BSSID filter
when authentication requests are sent, so roaming would work.

Signed-off-by: Ohad Ben-Cohen <ohad@wizery.com>
Reviewed-by: Luciano Coelho <coelho@ti.com>
Signed-off-by: Luciano Coelho <coelho@ti.com>
  • Loading branch information
Ohad Ben-Cohen authored and Luciano Coelho committed Apr 19, 2011
1 parent 13026de commit c574518
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 2 deletions.
1 change: 1 addition & 0 deletions drivers/net/wireless/wl12xx/io.h
Original file line number Diff line number Diff line change
Expand Up @@ -171,5 +171,6 @@ int wl1271_free_hw(struct wl1271 *wl);
irqreturn_t wl1271_irq(int irq, void *data);
bool wl1271_set_block_size(struct wl1271 *wl);
int wl1271_tx_dummy_packet(struct wl1271 *wl);
void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters);

#endif
4 changes: 2 additions & 2 deletions drivers/net/wireless/wl12xx/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -1528,7 +1528,7 @@ static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
cancel_work_sync(&wl->recovery_work);
}

static void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters)
void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters)
{
wl1271_set_default_filters(wl);

Expand Down Expand Up @@ -1650,7 +1650,7 @@ static int wl1271_unjoin(struct wl1271 *wl)
clear_bit(WL1271_FLAG_JOINED, &wl->flags);
memset(wl->bssid, 0, ETH_ALEN);

/* stop filterting packets based on bssid */
/* stop filtering packets based on bssid */
wl1271_configure_filters(wl, FIF_OTHER_BSS);

out:
Expand Down
24 changes: 24 additions & 0 deletions drivers/net/wireless/wl12xx/tx.c
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,28 @@ static void wl1271_free_tx_id(struct wl1271 *wl, int id)
}
}

static int wl1271_tx_update_filters(struct wl1271 *wl,
struct sk_buff *skb)
{
struct ieee80211_hdr *hdr;

hdr = (struct ieee80211_hdr *)(skb->data +
sizeof(struct wl1271_tx_hw_descr));

/*
* stop bssid-based filtering before transmitting authentication
* requests. this way the hw will never drop authentication
* responses coming from BSSIDs it isn't familiar with (e.g. on
* roaming)
*/
if (!ieee80211_is_auth(hdr->frame_control))
return 0;

wl1271_configure_filters(wl, FIF_OTHER_BSS);

return wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
}

static void wl1271_tx_ap_update_inconnection_sta(struct wl1271 *wl,
struct sk_buff *skb)
{
Expand Down Expand Up @@ -350,6 +372,8 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb,
if (wl->bss_type == BSS_TYPE_AP_BSS) {
wl1271_tx_ap_update_inconnection_sta(wl, skb);
wl1271_tx_regulate_link(wl, hlid);
} else {
wl1271_tx_update_filters(wl, skb);
}

wl1271_tx_fill_hdr(wl, skb, extra, info, hlid);
Expand Down

0 comments on commit c574518

Please sign in to comment.