Hi John, Please apply to wireless-dev.
-- Rewrite the virtual interface handling. With this monitor_during_oper is made possible. Signed-off-by: Michael Buesch <[EMAIL PROTECTED]> Index: wireless-dev/drivers/net/wireless/d80211/bcm43xx/bcm43xx.h =================================================================== --- wireless-dev.orig/drivers/net/wireless/d80211/bcm43xx/bcm43xx.h 2006-04-28 16:13:40.000000000 +0200 +++ wireless-dev/drivers/net/wireless/d80211/bcm43xx/bcm43xx.h 2006-05-03 18:02:55.000000000 +0200 @@ -626,10 +626,32 @@ u8 algorithm; }; +struct bcm43xx_interface { + /* Opaque ID of the operating interface (!= monitor + * interface) from the ieee80211 subsystem. + * Do not modify. + */ + int if_id; + /* MAC address. */ + u8 *mac_addr; + /* Current BSSID (if any). */ + u8 *bssid; + + /* Interface type. (IEEE80211_IF_TYPE_XXX) */ + int type; + /* Counter of active monitor interfaces. */ + int monitor; + /* Is the card operating in AP, STA or IBSS mode? */ + unsigned int operating:1; + /* Promisc mode active? + * Note that (monitor != 0) implies promisc. + */ + unsigned int promisc:1; +}; + struct bcm43xx_private { struct ieee80211_hw *ieee; struct ieee80211_low_level_stats ieee_stats; - int iw_mode; struct net_device *net_dev; struct pci_dev *pci_dev; @@ -653,6 +675,13 @@ short_slot:1, /* TRUE, if short slot timing is enabled. */ firmware_norelease:1; /* Do not release the firmware. Used on suspend. */ + /* One physical device can have one operating interface + * and a virtually infinite amount of monitoring interfaces. + * This keeps track of the interfaces and the corresponding + * hardware modes. + */ + struct bcm43xx_interface interface; + /* Various statistics about the physical device. */ struct bcm43xx_stats stats; /* Bus type we are connected to. @@ -716,8 +745,6 @@ /* Informational stuff. */ char nick[IW_ESSID_MAX_SIZE + 1]; - u8 bssid[ETH_ALEN]; - int interfaces; /* encryption/decryption */ u16 security_offset; @@ -854,6 +881,15 @@ return bcm; } +/* Is the device operating in a specified mode (IEEE80211_IF_TYPE_XXX). */ +static inline +int bcm43xx_is_mode(struct bcm43xx_private *bcm, int type) +{ + if (type == IEEE80211_IF_TYPE_MNTR) + return !!bcm->interface.monitor; + return (bcm->interface.operating && + bcm->interface.type == type); +} static inline u16 bcm43xx_read16(struct bcm43xx_private *bcm, u16 offset) Index: wireless-dev/drivers/net/wireless/d80211/bcm43xx/bcm43xx_leds.c =================================================================== --- wireless-dev.orig/drivers/net/wireless/d80211/bcm43xx/bcm43xx_leds.c 2006-04-28 16:13:40.000000000 +0200 +++ wireless-dev/drivers/net/wireless/d80211/bcm43xx/bcm43xx_leds.c 2006-05-03 18:00:46.000000000 +0200 @@ -217,7 +217,7 @@ bcm43xx_led_blink_stop(led, 0); continue; case BCM43xx_LED_APTRANSFER: - if (bcm->iw_mode == IW_MODE_MASTER) { + if (bcm43xx_is_mode(bcm, IEEE80211_IF_TYPE_AP)) { if (transferring) { interval = BCM43xx_LEDBLINK_FAST; turn_on = 1; Index: wireless-dev/drivers/net/wireless/d80211/bcm43xx/bcm43xx_main.c =================================================================== --- wireless-dev.orig/drivers/net/wireless/d80211/bcm43xx/bcm43xx_main.c 2006-04-28 16:13:40.000000000 +0200 +++ wireless-dev/drivers/net/wireless/d80211/bcm43xx/bcm43xx_main.c 2006-05-03 18:12:27.000000000 +0200 @@ -378,18 +378,26 @@ static void bcm43xx_macfilter_clear(struct bcm43xx_private *bcm, u16 offset) { - const u8 zero_addr[ETH_ALEN] = { 0 }; + static const u8 zero_addr[ETH_ALEN] = { 0 }; bcm43xx_macfilter_set(bcm, offset, zero_addr); } static void bcm43xx_write_mac_bssid_templates(struct bcm43xx_private *bcm) { - const u8 *mac = (const u8 *)(bcm->net_dev->dev_addr); - const u8 *bssid = bcm->bssid; + static const u8 zero_addr[ETH_ALEN] = { 0 }; + const u8 *mac = NULL; + const u8 *bssid = NULL; u8 mac_bssid[ETH_ALEN * 2]; int i; + bssid = bcm->interface.bssid; + if (!bssid) + bssid = zero_addr; + mac = bcm->interface.mac_addr; + if (!mac) + mac = zero_addr; + memcpy(mac_bssid, mac, ETH_ALEN); memcpy(mac_bssid + ETH_ALEN, bssid, ETH_ALEN); @@ -1438,15 +1446,15 @@ static void handle_irq_ps(struct bcm43xx_private *bcm) { - if (bcm->iw_mode == IW_MODE_MASTER) { + if (bcm43xx_is_mode(bcm, IEEE80211_IF_TYPE_AP)) { ///TODO: PS TBTT } else { if (1/*FIXME: the last PSpoll frame was sent successfully */) bcm43xx_power_saving_ctl_bits(bcm, -1, -1); } - if (bcm->iw_mode == IW_MODE_ADHOC) + bcm->reg124_set_0x4 = 0; + if (bcm43xx_is_mode(bcm, IEEE80211_IF_TYPE_IBSS)) bcm->reg124_set_0x4 = 1; - //FIXME else set to false? } static void handle_irq_reg124(struct bcm43xx_private *bcm) @@ -1456,7 +1464,6 @@ bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD, bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD) | 0x4); - //FIXME: reset reg124_set_0x4 to false? } static void handle_irq_pmq(struct bcm43xx_private *bcm) @@ -1509,7 +1516,9 @@ * Request the 80211 subsystem to generate a new beacon * frame and use it as template. */ - bcm->cached_beacon = ieee80211_beacon_get(bcm->net_dev, 0, &control); + 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"); goto ack; @@ -1603,7 +1612,7 @@ } if (reason & BCM43xx_IRQ_BEACON) { - if (bcm->iw_mode == IW_MODE_MASTER) + if (bcm43xx_is_mode(bcm, IEEE80211_IF_TYPE_AP)) handle_irq_beacon(bcm); bcmirq_handled(BCM43xx_IRQ_BEACON); } @@ -2147,55 +2156,49 @@ printkl(KERN_ERR PFX "MAC suspend failed\n"); } -void bcm43xx_set_iwmode(struct bcm43xx_private *bcm, - int iw_mode) +static void bcm43xx_select_opmode(struct bcm43xx_private *bcm) { - struct net_device *net_dev = bcm->net_dev; u32 status; u16 value; - bcm->iw_mode = iw_mode; - if (iw_mode == IW_MODE_MONITOR) - net_dev->type = ARPHRD_IEEE80211; - else - net_dev->type = ARPHRD_ETHER; - status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); - /* Reset status to infrastructured mode */ - status &= ~(BCM43xx_SBF_MODE_AP | BCM43xx_SBF_MODE_MONITOR); + /* Reset status to default STA mode */ + status &= ~BCM43xx_SBF_MODE_AP; + status &= ~BCM43xx_SBF_MODE_MONITOR; status &= ~BCM43xx_SBF_MODE_PROMISC; status |= BCM43xx_SBF_MODE_NOTADHOC; -/* FIXME: Always enable promisc mode, until we get the MAC filters working correctly. */ -status |= BCM43xx_SBF_MODE_PROMISC; - - switch (iw_mode) { - case IW_MODE_MONITOR: + if (bcm->interface.operating) { + switch (bcm->interface.type) { + case IEEE80211_IF_TYPE_AP: + status |= BCM43xx_SBF_MODE_AP; + break; + case IEEE80211_IF_TYPE_IBSS: + status &= ~BCM43xx_SBF_MODE_NOTADHOC; + break; + case IEEE80211_IF_TYPE_STA: + case IEEE80211_IF_TYPE_MNTR: + case IEEE80211_IF_TYPE_WDS: + break; + default: + assert(0); + } + } + if (bcm->interface.monitor) { status |= BCM43xx_SBF_MODE_MONITOR; status |= BCM43xx_SBF_MODE_PROMISC; - break; - case IW_MODE_ADHOC: - status &= ~BCM43xx_SBF_MODE_NOTADHOC; - break; - case IW_MODE_MASTER: - status |= BCM43xx_SBF_MODE_AP; - break; - case IW_MODE_SECOND: - case IW_MODE_REPEAT: - TODO(); /* TODO */ - break; - case IW_MODE_INFRA: - /* nothing to be done here... */ - break; - default: - dprintk(KERN_ERR PFX "Unknown mode in set_iwmode: %d\n", iw_mode); } - if (net_dev->flags & IFF_PROMISC) + if (bcm->interface.promisc) status |= BCM43xx_SBF_MODE_PROMISC; + +/* FIXME: Always enable promisc mode, until we get the MAC filters working correctly. */ +status |= BCM43xx_SBF_MODE_PROMISC; + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status); value = 0x0002; - if (iw_mode != IW_MODE_ADHOC && iw_mode != IW_MODE_MASTER) { + if ((status & BCM43xx_SBF_MODE_NOTADHOC) && + !(status & BCM43xx_SBF_MODE_AP)) { if (bcm->chip_id == 0x4306 && bcm->chip_rev == 3) value = 0x0064; else @@ -2291,7 +2294,7 @@ bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0074, 0x0000); /* Initially set the wireless operation mode. */ - bcm43xx_set_iwmode(bcm, bcm->iw_mode); + bcm43xx_select_opmode(bcm); if (bcm->current_core->rev < 3) { bcm43xx_write16(bcm, 0x060E, 0x0000); @@ -2599,27 +2602,6 @@ return err; } -static void bcm43xx_gen_bssid(struct bcm43xx_private *bcm) -{ - const u8 *mac = (const u8*)(bcm->net_dev->dev_addr); - u8 *bssid = bcm->bssid; - - switch (bcm->iw_mode) { - case IW_MODE_ADHOC: - random_ether_addr(bssid); - break; - case IW_MODE_MASTER: - case IW_MODE_INFRA: - case IW_MODE_REPEAT: - case IW_MODE_SECOND: - case IW_MODE_MONITOR: - memcpy(bssid, mac, ETH_ALEN); - break; - default: - assert(0); - } -} - static void bcm43xx_rate_memory_write(struct bcm43xx_private *bcm, u16 rate, int is_ofdm) @@ -2746,7 +2728,6 @@ /* Maximum Contention Window */ bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0004, 0x000003ff); - bcm43xx_gen_bssid(bcm); bcm43xx_write_mac_bssid_templates(bcm); if (bcm->current_core->rev >= 5) @@ -4169,13 +4150,8 @@ static int bcm43xx_net_open(struct net_device *net_dev) { struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); - int res; - res = bcm43xx_init_board(bcm); - if (!res) - return res; - bcm43xx_set_iwmode(bcm, bcm->iw_mode); - return 0; + return bcm43xx_init_board(bcm); } static int bcm43xx_net_stop(struct net_device *net_dev) @@ -4194,33 +4170,91 @@ struct ieee80211_if_init_conf *conf) { struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + unsigned long flags; + int err = -EOPNOTSUPP; + + bcm43xx_lock_mmio(bcm, flags); - if (bcm->interfaces > 0) - return -ENOBUFS; if (conf->type == IEEE80211_IF_TYPE_MNTR) { - bcm->iw_mode = IW_MODE_MONITOR; + bcm->interface.monitor++; } else { - if (memcmp(bcm->net_dev->dev_addr, conf->mac_addr, ETH_ALEN) != 0) - return -EADDRNOTAVAIL; - if (conf->type == IEEE80211_IF_TYPE_STA) - bcm->iw_mode = IW_MODE_INFRA; - else if (conf->type == IEEE80211_IF_TYPE_IBSS) - bcm->iw_mode = IW_MODE_ADHOC; - else if (conf->type == IEEE80211_IF_TYPE_AP) - bcm->iw_mode = IW_MODE_MASTER; - else - return -EOPNOTSUPP; + if (bcm->interface.operating) + goto out_unlock; + bcm->interface.operating = 1; + bcm->interface.if_id = conf->if_id; + bcm->interface.mac_addr = conf->mac_addr; + bcm->interface.type = conf->type; } - bcm->interfaces++; - return 0; + if (bcm->initialized) + bcm43xx_select_opmode(bcm); + err = 0; + + dprintk(KERN_INFO PFX "Virtual interface added " + "(type: 0x%08X, ID: %d, MAC: " + BCM43xx_MACFMT ")\n", + conf->type, conf->if_id, + BCM43xx_MACARG(conf->mac_addr)); + +out_unlock: + bcm43xx_unlock_mmio(bcm, flags); + + return err; } static void bcm43xx_remove_interface(struct net_device *net_dev, struct ieee80211_if_init_conf *conf) { struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + unsigned long flags; + + bcm43xx_lock_mmio(bcm, flags); + if (conf->type == IEEE80211_IF_TYPE_MNTR) { + bcm->interface.monitor--; + assert(bcm->interface.monitor >= 0); + } else + bcm->interface.operating = 0; + if (bcm->initialized) + bcm43xx_select_opmode(bcm); + bcm43xx_unlock_mmio(bcm, flags); + + dprintk(KERN_INFO PFX "Virtual interface removed " + "(type: 0x%08X, ID: %d, MAC: " + BCM43xx_MACFMT ")\n", + conf->type, conf->if_id, + BCM43xx_MACARG(conf->mac_addr)); +} - bcm->interfaces--; +static int bcm43xx_config_interface(struct net_device *net_dev, + int if_id, + struct ieee80211_if_conf *conf) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + unsigned long flags; + + bcm43xx_lock(bcm, flags); + if (conf->type != IEEE80211_IF_TYPE_MNTR) { + assert(bcm->interface.if_id == if_id); + bcm->interface.bssid = conf->bssid; + } + bcm43xx_unlock(bcm, flags); + + return 0; +} + +static void bcm43xx_set_multicast_list(struct net_device *net_dev, + unsigned short netflags, + int mc_count) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + unsigned long flags; + + bcm43xx_lock_mmio(bcm, flags); + if (bcm->interface.promisc != !!(netflags & IFF_PROMISC)) { + bcm->interface.promisc = !!(netflags & IFF_PROMISC); + if (bcm->initialized) + bcm43xx_select_opmode(bcm); + } + bcm43xx_unlock_mmio(bcm, flags); } /* Initialization of struct net_device, just after allocation. */ @@ -4294,6 +4328,8 @@ ieee->name = KBUILD_MODNAME; ieee->host_gen_beacon = 1; ieee->rx_includes_fcs = 1; + ieee->monitor_during_oper = 1; + ieee->channel_change_time = 20000; ieee->tx = bcm43xx_net_hard_start_xmit; ieee->open = bcm43xx_net_open; ieee->stop = bcm43xx_net_stop; @@ -4301,6 +4337,8 @@ ieee->remove_interface = bcm43xx_remove_interface; ieee->reset = bcm43xx_net_reset; ieee->config = bcm43xx_net_config; + ieee->config_interface = bcm43xx_config_interface; + ieee->set_multicast_list = bcm43xx_set_multicast_list; //TODO ieee->set_key = bcm43xx_net_set_key; ieee->get_stats = bcm43xx_net_get_stats; ieee->queues = 1; Index: wireless-dev/drivers/net/wireless/d80211/bcm43xx/bcm43xx_phy.c =================================================================== --- wireless-dev.orig/drivers/net/wireless/d80211/bcm43xx/bcm43xx_phy.c 2006-04-28 16:13:40.000000000 +0200 +++ wireless-dev/drivers/net/wireless/d80211/bcm43xx/bcm43xx_phy.c 2006-05-03 17:59:58.000000000 +0200 @@ -94,7 +94,7 @@ bcm43xx_mac_suspend(bcm); spin_lock(&phy->lock); } else { - if (bcm->iw_mode != IW_MODE_MASTER) + if (!bcm43xx_is_mode(bcm, IEEE80211_IF_TYPE_AP)) bcm43xx_power_saving_ctl_bits(bcm, -1, 1); } phy->is_locked = 1; @@ -111,7 +111,7 @@ bcm43xx_mac_enable(bcm); } } else { - if (bcm->iw_mode != IW_MODE_MASTER) + if (!bcm43xx_is_mode(bcm, IEEE80211_IF_TYPE_AP)) bcm43xx_power_saving_ctl_bits(bcm, -1, -1); } phy->is_locked = 0; -- Greetings Michael. - To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html