Subject: [PATCH, RFT] bcm43xx: AccessPoint mode

From: Michael Buesch <[email-masked]>
Date: Mon, 19 Jun 2006 11:07:34 +0200

Hi,

This patch enables the usage of a bcm43xx card as AP with
the Devicescape 802.11 stack.

Well, it does not work 100%, but at least it's very promising.
We are able to create a bssid and correctly send beacon frames out.

This patch is tested on BE and LE machines.

There seem to be issues with Devicescape and/or hostap.
Trying to authenticate from a STA to the AP does not work. The
packet is simply not processed. I was able to catch the auth
request on the AP (using the wonderful dscape virtual interfaces).
So the AP receives the packet, but loses it somewhere in the
stack or hostapd.

Well, thanks to Alexander Tsvyashchenko and the OpenWRT team for
the hard work to figure out how this all works.
My part on this patch is mainly endianess fixes.

Please give it a testrun.
Final note about hostapd:
"hostapd snapshot 0.5-2006-06-10" seems to "work" in the sense
that it is able to bring up the device.
"hostapd snapshot 0.5-2006-06-11" seems to fail.

I did not look into this more close, yet.

Important notes from Alexander Tsvyashchenko's initial mail follow:
------

1) This version deals with TIM in cleaner way (though, PS mode is still
not supported) - instead of patching dscape stack to skip TIM
generation, it strips TIM when writing probe response template and
leaves it when writing beacon template.

2) As in current dscape stack management interface seems to be no longer
passed to the driver, all interface handling is left as it is, no
changes there should be made anymore.

...

Known limitations:

1) PS mode is not supported.

Testing instructions:

Although my previous patch to hostapd to make it interoperable with
bcm43xx & dscape has been merged already in their CVS version, due to
the subsequent changes in dscape stack current hostapd is again
incompartible :-( So, to test this patch, the patch to hostapd should be
applied.
I used hostapd snapshot 0.5-2006-06-10, patch for it is attached.
The patch is very hacky and requires tricky way to bring everything up,
but as dscape stack is changed quite constantly, I just do not want to
waste time fixing it in "proper" way only to find a week later that
dscape handling of master interface was changed completely once more and
everything is broken again ;-)

The patch for dscape stack that is attached is not 100% necessary, but it
seems to allow operating clients that request PS mode to be enabled at
AP (verified with PDA client), the only thing it contains is disabling
actual PS handling in dscape.

So, the following sequence should be used to test AP mode:

1) take hostapd snapshot 0.5-2006-06-10 (other recent versions should
work OK also, though), apply the hostapd patch attached.

2) Insert modules (80211, rate_control and bcm43xx-d80211)

3) "iwconfig wlan0 mode master"

4) "ifconfig wlan0 up" (this should be done by hostapd actually, but
its operation with current dscape stack seems to be broken)

5) Start hostapd (f.e. "hostapd -B /etc/hostapd.conf"), config file can
look like:
=====
interface=wlan0
driver=devicescape
ssid=OpenWrt
channel=1
send_probe_response=0
logger_syslog=-1
logger_syslog_level=2
logger_stdout=-1
logger_stdout_level=2
debug=4
=====

6) "iwconfig wlan0 essid <your-SSID-name>" (this also should not be
required, but current combination of hostapd + dscape doesn't seem to
generate config_interface callback when setting beacon, so this is
required just to force call of config_interface).

Index: wireless-dev-dscapeports/drivers/net/wireless/d80211/bcm43xx/bcm43xx_main.c
===================================================================
--- wireless-dev-dscapeports.orig/drivers/net/wireless/d80211/bcm43xx/bcm43xx_main.c	2006-06-17 21:26:10.000000000 +0200
+++ wireless-dev-dscapeports/drivers/net/wireless/d80211/bcm43xx/bcm43xx_main.c	2006-06-18 23:36:31.000000000 +0200
@@ -152,7 +152,7 @@
 	u32 status;
 
 	status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
-	if (!(status & BCM43xx_SBF_XFER_REG_BYTESWAP))
+	if (status & BCM43xx_SBF_XFER_REG_BYTESWAP)
 		val = swab32(val);
 
 	bcm43xx_write32(bcm, BCM43xx_MMIO_RAM_CONTROL, offset);
@@ -312,7 +312,7 @@
 	}
 }
 
-void bcm43xx_tsf_write(struct bcm43xx_private *bcm, u64 tsf)
+static void bcm43xx_time_lock(struct bcm43xx_private *bcm)
 {
 	u32 status;
 
@@ -320,7 +320,19 @@
 	status |= BCM43xx_SBF_TIME_UPDATE;
 	bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status);
 	mmiowb();
+}
+
+static void bcm43xx_time_unlock(struct bcm43xx_private *bcm)
+{
+	u32 status;
+
+	status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
+	status &= ~BCM43xx_SBF_TIME_UPDATE;
+	bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status);
+}
 
+static void bcm43xx_tsf_write_locked(struct bcm43xx_private *bcm, u64 tsf)
+{
 	/* Be careful with the in-progress timer.
 	 * First zero out the low register, so we have a full
 	 * register-overflow duration to complete the operation.
@@ -350,10 +362,13 @@
 		mmiowb();
 		bcm43xx_write16(bcm, BCM43xx_MMIO_TSF_0, v0);
 	}
+}
 
-	status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
-	status &= ~BCM43xx_SBF_TIME_UPDATE;
-	bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status);
+void bcm43xx_tsf_write(struct bcm43xx_private *bcm, u64 tsf)
+{
+	bcm43xx_time_lock(bcm);
+	bcm43xx_tsf_write_locked(bcm, tsf);
+	bcm43xx_time_unlock(bcm);
 }
 
 static void bcm43xx_measure_channel_change_time(struct bcm43xx_private *bcm)
@@ -415,10 +430,11 @@
 static void bcm43xx_write_mac_bssid_templates(struct bcm43xx_private *bcm)
 {
 	static const u8 zero_addr[ETH_ALEN] = { 0 };
-	const u8 *mac = NULL;
-	const u8 *bssid = NULL;
+	const u8 *mac;
+	const u8 *bssid;
 	u8 mac_bssid[ETH_ALEN * 2];
 	int i;
+	u32 tmp;
 
 	bssid = bcm->interface.bssid;
 	if (!bssid)
@@ -431,12 +447,13 @@
 	memcpy(mac_bssid + ETH_ALEN, bssid, ETH_ALEN);
 
 	/* Write our MAC address and BSSID to template ram */
-	for (i = 0; i < ARRAY_SIZE(mac_bssid); i += sizeof(u32))
-		bcm43xx_ram_write(bcm, 0x20 + i, *((u32 *)(mac_bssid + i)));
-	for (i = 0; i < ARRAY_SIZE(mac_bssid); i += sizeof(u32))
-		bcm43xx_ram_write(bcm, 0x78 + i, *((u32 *)(mac_bssid + i)));
-	for (i = 0; i < ARRAY_SIZE(mac_bssid); i += sizeof(u32))
-		bcm43xx_ram_write(bcm, 0x478 + i, *((u32 *)(mac_bssid + i)));
+	for (i = 0; i < ARRAY_SIZE(mac_bssid); i += sizeof(u32)) {
+		tmp =  (u32)(mac_bssid[i + 0]);
+		tmp |= (u32)(mac_bssid[i + 1]) << 8;
+		tmp |= (u32)(mac_bssid[i + 2]) << 16;
+		tmp |= (u32)(mac_bssid[i + 3]) << 24;
+		bcm43xx_ram_write(bcm, 0x20 + i, tmp);
+	}
 }
 
 static void bcm43xx_set_slot_time(struct bcm43xx_private *bcm, u16 slot_time)
@@ -460,49 +477,6 @@
 	bcm->short_slot = 0;
 }
 
-/* FIXME: To get the MAC-filter working, we need to implement the
- *        following functions (and rename them :)
- */
-#if 0
-static void bcm43xx_disassociate(struct bcm43xx_private *bcm)
-{
-	bcm43xx_mac_suspend(bcm);
-	bcm43xx_macfilter_clear(bcm, BCM43xx_MACFILTER_ASSOC);
-
-	bcm43xx_ram_write(bcm, 0x0026, 0x0000);
-	bcm43xx_ram_write(bcm, 0x0028, 0x0000);
-	bcm43xx_ram_write(bcm, 0x007E, 0x0000);
-	bcm43xx_ram_write(bcm, 0x0080, 0x0000);
-	bcm43xx_ram_write(bcm, 0x047E, 0x0000);
-	bcm43xx_ram_write(bcm, 0x0480, 0x0000);
-
-	if (bcm->current_core->rev < 3) {
-		bcm43xx_write16(bcm, 0x0610, 0x8000);
-		bcm43xx_write16(bcm, 0x060E, 0x0000);
-	} else
-		bcm43xx_write32(bcm, 0x0188, 0x80000000);
-
-	bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0004, 0x000003ff);
-
-#if 0
-	if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_G &&
-	    ieee80211_is_ofdm_rate(bcm->softmac->txrates.default_rate))
-		bcm43xx_short_slot_timing_enable(bcm);
-#endif
-
-	bcm43xx_mac_enable(bcm);
-}
-
-static void bcm43xx_associate(struct bcm43xx_private *bcm,
-			      const u8 *mac)
-{
-	bcm43xx_mac_suspend(bcm);
-	bcm43xx_macfilter_set(bcm, BCM43xx_MACFILTER_ASSOC, mac);
-	bcm43xx_write_mac_bssid_templates(bcm);
-	bcm43xx_mac_enable(bcm);
-}
-#endif
-
 /* Enable a Generic IRQ. "mask" is the mask of which IRQs to enable.
  * Returns the _previously_ enabled IRQ mask.
  */
@@ -758,12 +732,29 @@
 	return -ENODEV;
 }
 
+#ifdef CONFIG_BCM947XX
+static void bcm43xx_aton(const char *str, char *dest)
+{
+	int i = 0;
+	u16 *d = (u16 *)dest;
+
+	for (;;) {
+		dest[i++] = (char)simple_strtoul(str, NULL, 16);
+		str += 2;
+		if (!*str++ || i == 6)
+			break;
+	}
+	for (i = 0; i < 3; i++)
+		d[i] = be16_to_cpu(d[i]);
+}
+#endif
+
 static int bcm43xx_sprom_extract(struct bcm43xx_private *bcm)
 {
 	u16 value;
 	u16 *sprom;
 #ifdef CONFIG_BCM947XX
-	char *c;
+	const char *c;
 #endif
 
 	sprom = kzalloc(BCM43xx_SPROM_SIZE * sizeof(u16),
@@ -772,27 +763,46 @@
 		printk(KERN_ERR PFX "sprom_extract OOM\n");
 		return -ENOMEM;
 	}
-#ifdef CONFIG_BCM947XX
-	sprom[BCM43xx_SPROM_BOARDFLAGS2] = atoi(nvram_get("boardflags2"));
-	sprom[BCM43xx_SPROM_BOARDFLAGS] = atoi(nvram_get("boardflags"));
-
-	if ((c = nvram_get("il0macaddr")) != NULL)
-		e_aton(c, (char *) &(sprom[BCM43xx_SPROM_IL0MACADDR]));
-
-	if ((c = nvram_get("et1macaddr")) != NULL)
-		e_aton(c, (char *) &(sprom[BCM43xx_SPROM_ET1MACADDR]));
-
-	sprom[BCM43xx_SPROM_PA0B0] = atoi(nvram_get("pa0b0"));
-	sprom[BCM43xx_SPROM_PA0B1] = atoi(nvram_get("pa0b1"));
-	sprom[BCM43xx_SPROM_PA0B2] = atoi(nvram_get("pa0b2"));
-
-	sprom[BCM43xx_SPROM_PA1B0] = atoi(nvram_get("pa1b0"));
-	sprom[BCM43xx_SPROM_PA1B1] = atoi(nvram_get("pa1b1"));
-	sprom[BCM43xx_SPROM_PA1B2] = atoi(nvram_get("pa1b2"));
 
-	sprom[BCM43xx_SPROM_BOARDREV] = atoi(nvram_get("boardrev"));
-#else
 	bcm43xx_sprom_read(bcm, sprom);
+
+#ifdef CONFIG_BCM947XX
+	/* In the case some settings are found in nvram, use them
+	 * to override those read from sprom.
+	 */
+	c = nvram_get("boardflags2");
+	if (c)
+		sprom[BCM43xx_SPROM_BOARDFLAGS2] = simple_strtoul(c, NULL, 0);
+        c = nvram_get("boardflags");
+	if (c)
+		sprom[BCM43xx_SPROM_BOARDFLAGS] = simple_strtoul(c, NULL, 0);
+	c = nvram_get("il0macaddr");
+	if (c)
+		bcm43xx_aton(c, (char *)&(sprom[BCM43xx_SPROM_IL0MACADDR]));
+	c = nvram_get("et1macaddr");
+	if (c)
+		bcm43xx_aton(c, (char *)&(sprom[BCM43xx_SPROM_ET1MACADDR]));
+	c = nvram_get("pa0b0");
+	if (c)
+		sprom[BCM43xx_SPROM_PA0B0] = simple_strtoul(c, NULL, 0);
+	c = nvram_get("pa0b1");
+	if (c)
+		sprom[BCM43xx_SPROM_PA0B1] = simple_strtoul(c, NULL, 0);
+	c = nvram_get("pa0b2");
+	if (c)
+		sprom[BCM43xx_SPROM_PA0B2] = simple_strtoul(c, NULL, 0);
+	c = nvram_get("pa1b0");
+	if (c)
+		sprom[BCM43xx_SPROM_PA1B0] = simple_strtoul(c, NULL, 0);
+	c = nvram_get("pa1b1");
+	if (c)
+		sprom[BCM43xx_SPROM_PA1B1] = simple_strtoul(c, NULL, 0);
+	c = nvram_get("pa1b2");
+	if (c)
+		sprom[BCM43xx_SPROM_PA1B2] = simple_strtoul(c, NULL, 0);
+	c = nvram_get("boardrev");
+	if (c)
+		sprom[BCM43xx_SPROM_BOARDREV] = simple_strtoul(c, NULL, 0);
 #endif
 
 	/* boardflags2 */
@@ -914,21 +924,21 @@
 	u16 value = 0;
 	u32 buffer[5] = {
 		0x00000000,
-		0x0000D400,
+		0x00D40000,
 		0x00000000,
-		0x00000001,
+		0x01000000,
 		0x00000000,
 	};
 
 	switch (phy->type) {
 	case BCM43xx_PHYTYPE_A:
 		max_loop = 0x1E;
-		buffer[0] = 0xCC010200;
+		buffer[0] = 0x000201CC;
 		break;
 	case BCM43xx_PHYTYPE_B:
 	case BCM43xx_PHYTYPE_G:
 		max_loop = 0xFA;
-		buffer[0] = 0x6E840B00; 
+		buffer[0] = 0x000B846E;
 		break;
 	default:
 		assert(0);
@@ -1521,48 +1531,274 @@
 	bcm43xx_write16(bcm, BCM43xx_MMIO_PS_STATUS, 0x0002);
 }
 
+static void bcm43xx_write_template_common(struct bcm43xx_private *bcm,
+					  const u8* data, u16 size,
+					  u16 ram_offset,
+					  u16 shm_size_offset, u8 rate)
+{
+	u32 i, tmp;
+	struct bcm43xx_plcp_hdr4 plcp;
+
+	plcp.data = 0;
+	bcm43xx_generate_plcp_hdr(&plcp, size + FCS_LEN, rate);
+	bcm43xx_ram_write(bcm, ram_offset, le32_to_cpu(plcp.data));
+	ram_offset += sizeof(u32);
+	/* The PLCP is 6 bytes long, but we only wrote 4 bytes, yet.
+	 * So leave the first two bytes of the next write blank.
+	 */
+	tmp = (u32)(data[0]) << 16;
+	tmp |= (u32)(data[1]) << 24;
+	bcm43xx_ram_write(bcm, ram_offset, tmp);
+	ram_offset += sizeof(u32);
+	for (i = 2; i < size; i += sizeof(u32)) {
+		tmp = (u32)(data[i + 0]);
+		if (i + 1 < size)
+			tmp |= (u32)(data[i + 1]) << 8;
+		if (i + 2 < size)
+			tmp |= (u32)(data[i + 2]) << 16;
+		if (i + 3 < size)
+			tmp |= (u32)(data[i + 3]) << 24;
+		bcm43xx_ram_write(bcm, ram_offset + i, tmp);
+	}
+	bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, shm_size_offset,
+			    size + sizeof(struct bcm43xx_plcp_hdr6));
+}
+
 static void bcm43xx_write_beacon_template(struct bcm43xx_private *bcm,
 					  u16 ram_offset,
-					  u16 shm_size_offset)
+					  u16 shm_size_offset, u8 rate)
 {
-	u32 tmp;
-	u16 i, size;
+	int len;
 	const u8 *data;
 
+	assert(bcm->cached_beacon);
+	len = min((size_t)bcm->cached_beacon->len,
+		  0x200 - sizeof(struct bcm43xx_plcp_hdr6));
 	data = (const u8 *)(bcm->cached_beacon->data);
-	size = min(bcm->cached_beacon->len, (unsigned int)17);
+	bcm43xx_write_template_common(bcm, data,
+				      len, ram_offset,
+				      shm_size_offset, rate);
+}
 
-	for (i = 0; i < size; i += sizeof(u32)) {
-		tmp = (u32)((data + i)[0]);
-		tmp |= (u32)((data + i)[1]) << 8;
-		tmp |= (u32)((data + i)[2]) << 16;
-		tmp |= (u32)((data + i)[3]) << 24;
-		bcm43xx_ram_write(bcm, ram_offset + i, tmp);
+static void bcm43xx_write_probe_resp_plcp(struct bcm43xx_private *bcm,
+					  u16 shm_offset, u16 size, u8 rate)
+{
+	struct bcm43xx_plcp_hdr4 plcp;
+	u32 tmp;
+	u16 packet_time;
+
+	plcp.data = 0;
+	bcm43xx_generate_plcp_hdr(&plcp, size + FCS_LEN, rate);
+	/*
+	 * 144 + 48 + 10 = preamble + PLCP + SIFS,
+	 * taken from d80211 timings calculation.
+	 *
+	 * FIXME: long preamble assumed!
+	 *
+	 */
+	packet_time = 202 + (size + FCS_LEN) * 16 / rate;
+	if ((size + FCS_LEN) * 16 % rate >= rate / 2)
+		++packet_time;
+
+	/* Write PLCP in two parts and timing for packet transfer */
+	tmp = le32_to_cpu(plcp.data);
+	bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, shm_offset,
+			    tmp & 0xFFFF);
+	bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, shm_offset + 2,
+			    tmp >> 16);
+	bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, shm_offset + 6,
+			    packet_time);
+}
+
+/* Instead of using custom probe response template, this function
+ * just patches custom beacon template by:
+ * 1) Changing packet type
+ * 2) Patching duration field
+ * 3) Stripping TIM
+ */
+static u8 * bcm43xx_generate_probe_resp(struct bcm43xx_private *bcm,
+					u16* dest_size, u8 rate)
+{
+	const u8 *src_data;
+	u8 *dest_data;
+	u16 src_size, elem_size, src_pos, dest_pos, tmp;
+
+	assert(bcm->cached_beacon);
+	src_size = bcm->cached_beacon->len;
+	src_data = (const u8*)bcm->cached_beacon->data;
+
+	if (unlikely(src_size < 0x24)) {
+		dprintk(KERN_ERR PFX "bcm43xx_generate_probe_resp: "
+				     "invalid beacon\n");
+		return NULL;
+	}
+
+	dest_data = kmalloc(src_size, GFP_ATOMIC);
+	if (unlikely(!dest_data))
+		return NULL;
+
+	/* 0x24 is offset of first variable-len Information-Element
+	 * in beacon frame.
+	 */
+	memcpy(dest_data, src_data, 0x24);
+	src_pos = dest_pos = 0x24;
+	for ( ; src_pos < src_size - 2; src_pos += elem_size) {
+		elem_size = src_data[src_pos + 1] + 2;
+		if (src_data[src_pos] != 0x05) { /* TIM */
+			memcpy(dest_data + dest_pos, src_data + src_pos,
+			       elem_size);
+			dest_pos += elem_size;
+		}
 	}
-	bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, shm_size_offset, size);
+	*dest_size = dest_pos;
+
+	/* Set the frame control. */
+	dest_data[0] = ((WLAN_FC_TYPE_MGMT << 2) |
+			(WLAN_FC_STYPE_PROBE_RESP << 4));
+	dest_data[1] = 0;
+
+	/* Set the duration field.
+	 *
+	 * 144 + 48 + 10 = preamble + PLCP + SIFS,
+	 * taken from d80211 timings calculation.
+	 *
+	 * FIXME: long preamble assumed!
+	 *
+	 */
+	tmp = 202 + (14 + FCS_LEN) * 16 / rate;
+	if ((14 + FCS_LEN) * 16 % rate >= rate / 2)
+		++tmp;
+
+	dest_data[2] = tmp & 0xFF;
+	dest_data[3] = (tmp >> 8) & 0xFF;
+
+	return dest_data;
+}
+
+static void bcm43xx_write_probe_resp_template(struct bcm43xx_private *bcm,
+					      u16 ram_offset,
+					      u16 shm_size_offset, u8 rate)
+{
+	u8* probe_resp_data;
+	u16 size;
+
+	assert(bcm->cached_beacon);
+	size = bcm->cached_beacon->len;
+	probe_resp_data = bcm43xx_generate_probe_resp(bcm, &size, rate);
+	if (unlikely(!probe_resp_data))
+		return;
+
+	/* Looks like PLCP headers plus packet timings are stored for
+	 * all possible basic rates
+	 */
+	bcm43xx_write_probe_resp_plcp(bcm, 0x31A, size,
+				      BCM43xx_CCK_RATE_1MB);
+	bcm43xx_write_probe_resp_plcp(bcm, 0x32C, size,
+				      BCM43xx_CCK_RATE_2MB);
+	bcm43xx_write_probe_resp_plcp(bcm, 0x33E, size,
+				      BCM43xx_CCK_RATE_5MB);
+	bcm43xx_write_probe_resp_plcp(bcm, 0x350, size,
+				      BCM43xx_CCK_RATE_11MB);
+
+	size = min((size_t)size,
+		   0x200 - sizeof(struct bcm43xx_plcp_hdr6));
+	bcm43xx_write_template_common(bcm, probe_resp_data,
+				      size, ram_offset,
+				      shm_size_offset, rate);
+	kfree(probe_resp_data);
+}
+
+static int bcm43xx_refresh_cached_beacon(struct bcm43xx_private *bcm)
+{
+	struct ieee80211_tx_control control;
+
+	if (bcm->cached_beacon)
+		kfree_skb(bcm->cached_beacon);
+	bcm->cached_beacon = ieee80211_beacon_get(bcm->net_dev,
+						  bcm->interface.if_id,
+						  &control);
+	if (unlikely(!bcm->cached_beacon))
+		return -ENOMEM;
+
+	return 0;
+}
+
+static void bcm43xx_update_templates(struct bcm43xx_private *bcm)
+{
+	u32 status;
+
+	assert(bcm->cached_beacon);
+
+	bcm43xx_write_beacon_template(bcm, 0x68, 0x18,
+				      BCM43xx_CCK_RATE_1MB);
+	bcm43xx_write_beacon_template(bcm, 0x468, 0x1A,
+				      BCM43xx_CCK_RATE_1MB);
+	bcm43xx_write_probe_resp_template(bcm, 0x268, 0x4A,
+					  BCM43xx_CCK_RATE_11MB);
+
+	status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD);
+	status |= 0x03;
+	bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD, status);
+}
+
+static void bcm43xx_refresh_templates(struct bcm43xx_private *bcm)
+{
+	int err;
+
+	err = bcm43xx_refresh_cached_beacon(bcm);
+	if (unlikely(err))
+		return;
+	bcm43xx_update_templates(bcm);
+	kfree_skb(bcm->cached_beacon);
+	bcm->cached_beacon = NULL;
+}
+
+static void bcm43xx_set_ssid(struct bcm43xx_private *bcm,
+			     const u8 *ssid, u8 ssid_len)
+{
+	u32 tmp;
+	u16 i, len;
+
+	len = min((u16)ssid_len, (u16)0x100);
+	for (i = 0; i < len; i += sizeof(u32)) {
+		tmp = (u32)(ssid[i + 0]);
+		if (i + 1 < len)
+			tmp |= (u32)(ssid[i + 1]) << 8;
+		if (i + 2 < len)
+			tmp |= (u32)(ssid[i + 2]) << 16;
+		if (i + 3 < len)
+			tmp |= (u32)(ssid[i + 3]) << 24;
+		bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED,
+				    0x380 + i, tmp);
+	}
+	bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED,
+			    0x48, len);
+}
+
+static void bcm43xx_set_beacon_int(struct bcm43xx_private *bcm, u16 beacon_int)
+{
+	bcm43xx_time_lock(bcm);
+	if (bcm->current_core->rev >= 3) {
+		bcm43xx_write32(bcm, 0x188, (beacon_int << 16));
+	} else {
+		bcm43xx_write16(bcm, 0x606, (beacon_int >> 6));
+		bcm43xx_write16(bcm, 0x610, beacon_int);
+	}
+	bcm43xx_time_unlock(bcm);
 }
 
 static void handle_irq_beacon(struct bcm43xx_private *bcm)
 {
 	u32 status;
+	int err;
 
 	bcm->irq_savedstate &= ~BCM43xx_IRQ_BEACON;
 	status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD);
 
 	if (!bcm->cached_beacon) {
-		struct ieee80211_tx_control control;
-
-		/* No cached template available, yet.
-		 * Request the 80211 subsystem to generate a new beacon
-		 * frame and use it as template.
-		 */
-		bcm->cached_beacon = ieee80211_beacon_get(bcm->net_dev,
-							  bcm->interface.if_id,
-							  &control);
-		if (unlikely(!bcm->cached_beacon)) {
-			dprintkl(KERN_WARNING PFX "Could not generate beacon template.\n");
+		err = bcm43xx_refresh_cached_beacon(bcm);
+		if (unlikely(err))
 			goto ack;
-		}
 	}
 
 	if ((status & 0x1) && (status & 0x2)) {
@@ -1571,18 +1807,20 @@
 		bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON,
 				BCM43xx_IRQ_BEACON);
 		bcm->irq_savedstate |= BCM43xx_IRQ_BEACON;
-		if (likely(bcm->cached_beacon))
+		if (bcm->cached_beacon)
 			kfree_skb(bcm->cached_beacon);
 		bcm->cached_beacon = NULL;
 		return;
 	}
 	if (!(status & 0x1)) {
-		bcm43xx_write_beacon_template(bcm, 0x68, 0x18);
+		bcm43xx_write_beacon_template(bcm, 0x68, 0x18,
+					      BCM43xx_CCK_RATE_1MB);
 		status |= 0x1;
 		bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD, status);
 	}
 	if (!(status & 0x2)) {
-		bcm43xx_write_beacon_template(bcm, 0x468, 0x1A);
+		bcm43xx_write_beacon_template(bcm, 0x468, 0x1A,
+					      BCM43xx_CCK_RATE_1MB);
 		status |= 0x2;
 		bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD, status);
 	}
@@ -4114,6 +4352,17 @@
 		radio->power_level = conf->power_level;
 		bcm43xx_phy_xmitpower(bcm);
 	}
+
+	if (conf->ssid_hidden) {
+		bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
+				bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD)
+				| BCM43xx_SBF_NO_SSID_BCAST);
+	} else {
+		bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
+				bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD)
+				& ~BCM43xx_SBF_NO_SSID_BCAST);
+	}
+
 //FIXME: This does not seem to wake up:
 #if 0
 	if (conf->power_level == 0) {
@@ -4128,6 +4377,11 @@
 	//TODO: phymode
 	//TODO: antennas
 
+	if (bcm43xx_is_mode(bcm, IEEE80211_IF_TYPE_AP)) {
+		bcm43xx_set_beacon_int(bcm, conf->beacon_int);
+		bcm43xx_refresh_templates(bcm);
+	}
+
 	bcm43xx_unlock_irqonly(bcm, flags);
 
 	return 0;
@@ -4293,8 +4547,11 @@
 		bcm->interface.mac_addr = conf->mac_addr;
 		bcm->interface.type = conf->type;
 	}
-	if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED)
+	if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) {
 		bcm43xx_select_opmode(bcm);
+		if (bcm43xx_is_mode(bcm, IEEE80211_IF_TYPE_AP))
+			bcm43xx_refresh_templates(bcm);
+	}
 	err = 0;
 
 	dprintk(KERN_INFO PFX "Virtual interface added "
@@ -4343,6 +4600,11 @@
 	if (conf->type != IEEE80211_IF_TYPE_MNTR) {
 		assert(bcm->interface.if_id == if_id);
 		bcm->interface.bssid = conf->bssid;
+		if (bcm43xx_is_mode(bcm, IEEE80211_IF_TYPE_AP)) {
+			assert(conf->type == IEEE80211_IF_TYPE_AP);
+			bcm43xx_set_ssid(bcm, conf->ssid, conf->ssid_len);
+			bcm43xx_refresh_templates(bcm);
+		}
 	}
 	bcm43xx_unlock_irqsafe(bcm, flags);
 
Index: wireless-dev-dscapeports/drivers/net/wireless/d80211/bcm43xx/bcm43xx_xmit.c
===================================================================
--- wireless-dev-dscapeports.orig/drivers/net/wireless/d80211/bcm43xx/bcm43xx_xmit.c	2006-06-13 21:06:01.000000000 +0200
+++ wireless-dev-dscapeports/drivers/net/wireless/d80211/bcm43xx/bcm43xx_xmit.c	2006-06-18 18:43:12.000000000 +0200
@@ -112,14 +112,13 @@
 	return 0;
 }
 
-static void bcm43xx_generate_plcp_hdr(struct bcm43xx_plcp_hdr4 *plcp,
-				      const u16 octets, const u8 bitrate,
-				      const int ofdm_modulation)
+void bcm43xx_generate_plcp_hdr(struct bcm43xx_plcp_hdr4 *plcp,
+			       const u16 octets, const u8 bitrate)
 {
 	__le32 *data = &(plcp->data);
 	__u8 *raw = plcp->raw;
 
-	if (ofdm_modulation) {
+	if (bcm43xx_is_ofdm_rate(bitrate)) {
 		*data = bcm43xx_plcp_get_ratecode_ofdm(bitrate);
 		assert(!(octets & 0xF000));
 		*data |= (octets << 5);
@@ -224,11 +223,9 @@
 
 	flen = sizeof(u16) + sizeof(u16) + ETH_ALEN + ETH_ALEN + FCS_LEN,
 	bcm43xx_generate_plcp_hdr((struct bcm43xx_plcp_hdr4 *)(&txhdr->rts_cts_plcp),
-				  flen, bitrate,
-				  !bcm43xx_is_cck_rate(bitrate));
+				  flen, bitrate);
 	bcm43xx_generate_plcp_hdr((struct bcm43xx_plcp_hdr4 *)(&txhdr->rts_cts_fallback_plcp),
-				  flen, fallback_bitrate,
-				  !bcm43xx_is_cck_rate(fallback_bitrate));
+				  flen, fallback_bitrate);
 	fctl = WLAN_FC_TYPE_CTRL << 2;
 	fctl |= WLAN_FC_STYPE_RTS << 4;
 	dur = le16_to_cpu(wlhdr->duration_id);
@@ -332,10 +329,9 @@
 	}
 	/* Generate the PLCP header and the fallback PLCP header. */
 	bcm43xx_generate_plcp_hdr((struct bcm43xx_plcp_hdr4 *)(&txhdr->plcp),
-				  plcp_fragment_len,
-				  bitrate, ofdm_modulation);
+				  plcp_fragment_len, bitrate);
 	bcm43xx_generate_plcp_hdr(&txhdr->fallback_plcp, plcp_fragment_len,
-				  fallback_bitrate, fallback_ofdm_modulation);
+				  fallback_bitrate);
 
 	/* Set the CONTROL field */
 	if (ofdm_modulation)
Index: wireless-dev-dscapeports/drivers/net/wireless/d80211/bcm43xx/bcm43xx_xmit.h
===================================================================
--- wireless-dev-dscapeports.orig/drivers/net/wireless/d80211/bcm43xx/bcm43xx_xmit.h	2006-06-13 14:43:08.000000000 +0200
+++ wireless-dev-dscapeports/drivers/net/wireless/d80211/bcm43xx/bcm43xx_xmit.h	2006-06-18 18:41:27.000000000 +0200
@@ -154,4 +154,7 @@
 		struct sk_buff *skb,
 		struct bcm43xx_rxhdr *rxhdr);
 
+void bcm43xx_generate_plcp_hdr(struct bcm43xx_plcp_hdr4 *plcp,
+			       const u16 octets, const u8 bitrate);
+
 #endif /* BCM43xx_XMIT_H_ */
Index: wireless-dev-dscapeports/drivers/net/wireless/d80211/bcm43xx/bcm43xx_main.h
===================================================================
--- wireless-dev-dscapeports.orig/drivers/net/wireless/d80211/bcm43xx/bcm43xx_main.h	2006-06-13 14:43:08.000000000 +0200
+++ wireless-dev-dscapeports/drivers/net/wireless/d80211/bcm43xx/bcm43xx_main.h	2006-06-18 18:41:03.000000000 +0200
@@ -33,24 +33,6 @@
 
 #include "bcm43xx.h"
 
-#ifdef CONFIG_BCM947XX
-#define atoi(str) simple_strtoul(((str != NULL) ? str : ""), NULL, 0)
-
-static inline void e_aton(char *str, char *dest)
-{
-	int i = 0;
-	u16 *d = (u16 *) dest;
-
-	for (;;) {
-		dest[i++] = (char) simple_strtoul(str, NULL, 16);
-		str += 2;
-		if (!*str++ || i == 6)
-			break;
-	}
-	for (i = 0; i < 3; i++)
-		d[i] = cpu_to_be16(d[i]);
-}
-#endif
 
 #define P4D_BYT3S(magic, nr_bytes)	u8 __p4dding##magic[nr_bytes]
 #define P4D_BYTES(line, nr_bytes)	P4D_BYT3S(line, nr_bytes)
@@ -143,6 +125,12 @@
 		rate == BCM43xx_CCK_RATE_11MB);
 }
 
+static inline
+int bcm43xx_is_ofdm_rate(int rate)
+{
+	return !bcm43xx_is_cck_rate(rate);
+}
+
 void bcm43xx_tsf_read(struct bcm43xx_private *bcm, u64 *tsf);
 void bcm43xx_tsf_write(struct bcm43xx_private *bcm, u64 tsf);

-- 
Greetings Michael.
diff -urN hostapd-0.5-2006-06-10/driver_devicescape.c hostapd.new/driver_devicescape.c
--- hostapd-0.5-2006-06-10/driver_devicescape.c	2006-05-03 03:04:24.000000000 +0000
+++ hostapd.new/driver_devicescape.c	2006-06-12 21:17:10.000000000 +0000
@@ -1338,8 +1338,12 @@
 		return -1;
 	}
 
-        memset(&ifr, 0, sizeof(ifr));
-        snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s", drv->mgmt_iface);
+	/* Enable management interface */
+	hostap_ioctl_prism2param(drv, PRISM2_PARAM_MGMT_IF, 1);
+	strcpy(drv->mgmt_iface, "wmgmt0");
+	
+	memset(&ifr, 0, sizeof(ifr));
+	snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s", drv->mgmt_iface);
         if (ioctl(drv->ioctl_sock, SIOCGIFINDEX, &ifr) != 0) {
 		perror("ioctl(SIOCGIFINDEX)");
 		return -1;
@@ -1747,6 +1751,9 @@
 	/* Disable the radio. */
 	(void) hostap_ioctl_prism2param(drv, PRISM2_PARAM_RADIO_ENABLED, 0);
 
+	/* Disable management interface */
+	hostap_ioctl_prism2param(drv, PRISM2_PARAM_MGMT_IF, 0);
+
 	drv->hapd->driver = NULL;
 
 	(void) hostapd_set_iface_flags(drv, 0);
Files hostapd-0.5-2006-06-10/hostapd and hostapd.new/hostapd differ
diff -urN d80211.orig/ieee80211.c d80211/ieee80211.c
--- d80211.orig/ieee80211.c	2006-05-29 10:30:12.000000000 +0000
+++ d80211/ieee80211.c	2006-06-12 20:39:47.000000000 +0000
@@ -2534,7 +2534,7 @@
 
 	if (sdata->bss)
 		atomic_inc(&sdata->bss->num_sta_ps);
-	sta->flags |= WLAN_STA_PS;
+	/* sta->flags |= WLAN_STA_PS; */
 	sta->pspoll = 0;
 #ifdef IEEE80211_VERBOSE_DEBUG_PS
 	printk(KERN_DEBUG "%s: STA " MACSTR " aid %d enters power "