Date: Sun, 25 Jan 2009 10:39:05 +0000 (GMT) From: wpaul@FreeBSD.ORG (Bill Paul) To: freebsd-current@freebsd.org Subject: net80211 hostap vs powersave Message-ID: <20090125103905.378CA106570E@hub.freebsd.org>
next in thread | raw e-mail | index | archive | help
So. Recently, I decided to trade in my Hiptop for a Blackberry Curve 8320. It does many spiffy things. I even got it to do tethering with FreeBSD via USB. (See here for more details: http://www.freebsd.org/~wpaul/bb/ ) There was just thing I had trouble with. The 8320 is a wifi-enabled phone, and I thought it would be nice to use it with my wifi setup at home. My "access point" is actually a soekris board running FreeBSD 7.0 with a Linksys cardbus adapter that uses an Atheros 5212 chipset. Normally, I run it in adhoc mode. Unfortunately, for whatever the reason, the Blackberry doesn't support adhoc networks: you can only connect to BSS networks. "Well, ok," says I, "I guess I'll set ath0 to hostap mode instead." But that didn't work quite right either. The Blackberry could detect the AP now, and it could associate and acquire a DHCP lease, but after that, it seemed that it would only send frames, not receive them. Actually, it seemed that it was the ath0 interface that wasn't sending the frames: using tcpdump I could see traffic coming in, but nothing going out. A bit of investigation showed that the problem had to do with the fact that the Blackberry operates in powersave mode. This is sensible enough since it's a portable device with limited battery power. However it doesn't offer the option to turn it off. It looked like either the ath(4) driver or net80211 had a problem supporting power save in hostap mode. I dug around a bit, and there was one thing that looked a little strange to me. In FreeBSD 7.0, the ieee80211_power.c module has the following two functions: void ieee80211_power_attach(struct ieee80211com *ic) { if (ic->ic_opmode == IEEE80211_M_HOSTAP || ic->ic_opmode == IEEE80211_M_IBSS) { /* NB: driver should override */ ic->ic_set_tim = ieee80211_set_tim; } } void ieee80211_power_lateattach(struct ieee80211com *ic) { /* * Allocate these only if needed. Beware that we * know adhoc mode doesn't support ATIM yet... */ if (ic->ic_opmode == IEEE80211_M_HOSTAP) { ic->ic_tim_len = howmany(ic->ic_max_aid,8) * sizeof(uint8_t); MALLOC(ic->ic_tim_bitmap, uint8_t *, ic->ic_tim_len, M_DEVBUF, M_NOWAIT | M_ZERO); if (ic->ic_tim_bitmap == NULL) { printf("%s: no memory for TIM bitmap!\n", __func__); /* XXX good enough to keep from crashing? */ ic->ic_tim_len = 0; } } } Both of these are effectivelly called from the driver's attach routine, which is run early on when an interface is initialized. Here's what's strange. Both functions hook up some of the plumbing that powersave requires, but only if ic_opmode == IEEE80211_M_HOSTAP (or in the case of ieee80211_power_attach, if ic_opmode is either IEEE80211_M_HOSTAP or IEEE80211_M_IBSS). But none of the wireless drivers set ic_opmode to IEEE80211_M_HOSTAP or IEEE80211_M_IBSS by default: it's up to the user or a startup script to change the operating mode to one of these after the interfaces are attached. This means that at the time these routines are run, ic_opmode can _never_ be IEEE80211_M_HOSTAP or IEEE80211_M_IBSS, so the required setup never happens. I changed these functions to look like this: void ieee80211_power_attach(struct ieee80211com *ic) { if (ic->ic_caps & IEEE80211_C_HOSTAP || ic->ic_caps & IEEE80211_C_IBSS) { /* NB: driver should override */ ic->ic_set_tim = ieee80211_set_tim; } } void ieee80211_power_lateattach(struct ieee80211com *ic) { /* * Allocate these only if needed. Beware that we * know adhoc mode doesn't support ATIM yet... */ if (ic->ic_caps & IEEE80211_C_HOSTAP) { ic->ic_tim_len = howmany(ic->ic_max_aid,8) * sizeof(uint8_t); MALLOC(ic->ic_tim_bitmap, uint8_t *, ic->ic_tim_len, M_DEVBUF, M_NOWAIT | M_ZERO); if (ic->ic_tim_bitmap == NULL) { printf("%s: no memory for TIM bitmap!\n", __func__); /* XXX good enough to keep from crashing? */ ic->ic_tim_len = 0; } } } Note that now they test the interface capabilities (ic_caps) rather than the current operating mode (ic_opmode). With this change, the powersave support now seems to work well enough that the Blackberry can associate and exchange traffic with the ath0 interface as expected. Looking at the code in -current, there have been some changes, but I think the same bug is still there: void ieee80211_power_vattach(struct ieee80211vap *vap) { if (vap->iv_opmode == IEEE80211_M_HOSTAP || vap->iv_opmode == IEEE80211_M_IBSS) { /* NB: driver should override */ vap->iv_update_ps = ieee80211_update_ps; vap->iv_set_tim = ieee80211_set_tim; } } void ieee80211_power_latevattach(struct ieee80211vap *vap) { /* * Allocate these only if needed. Beware that we * know adhoc mode doesn't support ATIM yet... */ if (vap->iv_opmode == IEEE80211_M_HOSTAP) { vap->iv_tim_len = howmany(vap->iv_max_aid,8) * sizeof(uint8_t); vap->iv_tim_bitmap = (uint8_t *) malloc(vap->iv_tim_len, M_80211_POWER, M_NOWAIT | M_ZERO); if (vap->iv_tim_bitmap == NULL) { printf("%s: no memory for TIM bitmap!\n", __func__); /* XXX good enough to keep from crashing? */ vap->iv_tim_len = 0; } } } Unfortunately, I don't have the ability to test the same fix against -current, but it seems to me that it still applies. -Bill -- ============================================================================= -Bill Paul (510) 749-2329 | Senior Engineer, Master of Unix-Fu wpaul@windriver.com | Wind River Systems ============================================================================= "I put a dollar in a change machine. Nothing changed." - George Carlin =============================================================================
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20090125103905.378CA106570E>