Hi, Jiri, please review this patch for things that might look strange to you. :)
-- This replaces the bcm43xx-d80211 virtual interfaces hack by a correct implementation with support for monitor during oper. 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-01 20:25:31.000000000 +0200 @@ -626,10 +626,34 @@ u8 algorithm; }; +struct bcm43xx_interface { + struct list_head list; + /* Interface type (IEEE80211_IF_TYPE_XXX). */ + int type; + /* Opaque ID from the ieee80211 subsystem. Do not modify. */ + int if_id; + /* MAC address for this interface. */ + u8 *mac_addr; + /* BSSID (if any). */ + u8 *bssid; +}; + +struct bcm43xx_interface_list { + /* Linked list of active interfaces. */ + struct list_head list; + /* Shortcut pointer to the AP interface (if any). */ + struct bcm43xx_interface *ap_if; + + /* Usage counters of the internal operation modes. */ + u16 opmode_ap; + u16 opmode_adhoc; + u16 opmode_monitor; + u16 opmode_promisc; +}; + 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 +677,11 @@ 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 or more virtual + * interfaces. This stores and manages the virtual interfaces. + */ + struct bcm43xx_interface_list interfaces; + /* 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; 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-01 18:57:26.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 (bcm->interfaces.opmode_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-01 20:25:24.000000000 +0200 @@ -378,18 +378,30 @@ 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) { + static const u8 zero_addr[ETH_ALEN] = { 0 }; + struct bcm43xx_interface *iface; const u8 *mac = (const u8 *)(bcm->net_dev->dev_addr); - const u8 *bssid = bcm->bssid; + const u8 *bssid = NULL; u8 mac_bssid[ETH_ALEN * 2]; int i; + list_for_each_entry(iface, &bcm->interfaces.list, list) { + if (iface->type != IEEE80211_IF_TYPE_MNTR && + iface->bssid) { + bssid = iface->bssid; + break; + } + } + if (!bssid) + bssid = zero_addr; + memcpy(mac_bssid, mac, ETH_ALEN); memcpy(mac_bssid + ETH_ALEN, bssid, ETH_ALEN); @@ -1438,15 +1450,15 @@ static void handle_irq_ps(struct bcm43xx_private *bcm) { - if (bcm->iw_mode == IW_MODE_MASTER) { + if (bcm->interfaces.opmode_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 (bcm->interfaces.opmode_adhoc) bcm->reg124_set_0x4 = 1; - //FIXME else set to false? } static void handle_irq_reg124(struct bcm43xx_private *bcm) @@ -1456,7 +1468,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 +1520,10 @@ * 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); + assert(bcm->interfaces.ap_if); + bcm->cached_beacon = ieee80211_beacon_get(bcm->net_dev, + bcm->interfaces.ap_if->if_id, + &control); if (unlikely(!bcm->cached_beacon)) { dprintkl(KERN_WARNING PFX "Could not generate beacon template.\n"); goto ack; @@ -1603,7 +1617,7 @@ } if (reason & BCM43xx_IRQ_BEACON) { - if (bcm->iw_mode == IW_MODE_MASTER) + if (bcm->interfaces.opmode_ap) handle_irq_beacon(bcm); bcmirq_handled(BCM43xx_IRQ_BEACON); } @@ -2147,55 +2161,35 @@ printkl(KERN_ERR PFX "MAC suspend failed\n"); } -void bcm43xx_set_iwmode(struct bcm43xx_private *bcm, - int iw_mode) +static void bcm43xx_select_opmodes(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; + if (bcm->interfaces.opmode_ap) + status |= BCM43xx_SBF_MODE_AP; + if (bcm->interfaces.opmode_adhoc) + status &= ~BCM43xx_SBF_MODE_NOTADHOC; + if (bcm->interfaces.opmode_monitor) + status |= BCM43xx_SBF_MODE_MONITOR; + if (bcm->interfaces.opmode_promisc) + status |= BCM43xx_SBF_MODE_PROMISC; + /* 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: - 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) - 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 (bcm->interfaces.opmode_adhoc == 0 && + bcm->interfaces.opmode_ap == 0) { if (bcm->chip_id == 0x4306 && bcm->chip_rev == 3) value = 0x0064; else @@ -2291,7 +2285,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_opmodes(bcm); if (bcm->current_core->rev < 3) { bcm43xx_write16(bcm, 0x060E, 0x0000); @@ -2599,27 +2593,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 +2719,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 +4141,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 +4161,170 @@ struct ieee80211_if_init_conf *conf) { struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + unsigned long flags; + int err = -ENOBUFS; + struct bcm43xx_interface *iface; - if (bcm->interfaces > 0) - return -ENOBUFS; - if (conf->type == IEEE80211_IF_TYPE_MNTR) { - bcm->iw_mode = IW_MODE_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; + iface = kzalloc(sizeof(*iface), GFP_KERNEL); + if (!iface) + return -ENOMEM; + INIT_LIST_HEAD(&iface->list); + iface->type = conf->type; + iface->if_id = conf->if_id; + iface->mac_addr = conf->mac_addr; + + bcm43xx_lock_mmio(bcm, flags); + switch (conf->type) { + case IEEE80211_IF_TYPE_AP: + /* Cannot run more than one AP or concurrently + * with IBSS mode. + */ + if (bcm->interfaces.opmode_ap) + break; + if (bcm->interfaces.opmode_adhoc) + break; + bcm->interfaces.opmode_ap++; + bcm->interfaces.ap_if = iface; + err = 0; + break; + case IEEE80211_IF_TYPE_STA: + /* Cannot run STA and AP or IBSS mode concurrently. */ + if (bcm->interfaces.opmode_ap) + break; + if (bcm->interfaces.opmode_adhoc) + break; + err = 0; + break; + case IEEE80211_IF_TYPE_IBSS: + /* Cannot run more than one IBSS or concurrently + * with AP mode. + */ + if (bcm->interfaces.opmode_ap) + break; + if (bcm->interfaces.opmode_adhoc) + break; + bcm->interfaces.opmode_adhoc++; + err = 0; + break; + case IEEE80211_IF_TYPE_MNTR: + bcm->interfaces.opmode_monitor++; + err = 0; + break; + case IEEE80211_IF_TYPE_WDS: + //TODO: Uhm..., well. + break; + default: + assert(0); } - bcm->interfaces++; - return 0; + if (!err) { + list_add_tail(&iface->list, &bcm->interfaces.list); + if (bcm->initialized) + bcm43xx_select_opmodes(bcm); + + 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)); + } + + bcm43xx_unlock_mmio(bcm, flags); + + if (err) + kfree(iface); + + 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; + struct bcm43xx_interface *iface, *tmp_iface; + + bcm43xx_lock_mmio(bcm, flags); + list_for_each_entry_safe(iface, tmp_iface, &bcm->interfaces.list, list) { + if (iface->if_id != conf->if_id) + continue; + assert(conf->type == iface->type); + + switch (iface->type) { + case IEEE80211_IF_TYPE_AP: + bcm->interfaces.opmode_ap--; + assert(bcm->interfaces.opmode_ap == 0); + bcm->interfaces.ap_if = NULL; + break; + case IEEE80211_IF_TYPE_STA: + break; + case IEEE80211_IF_TYPE_IBSS: + bcm->interfaces.opmode_adhoc--; + assert(bcm->interfaces.opmode_adhoc == 0); + break; + case IEEE80211_IF_TYPE_MNTR: + assert(bcm->interfaces.opmode_monitor > 0); + bcm->interfaces.opmode_monitor--; + break; + case IEEE80211_IF_TYPE_WDS: + //TODO: Uhm..., well. + break; + default: + assert(0); + } + list_del(&iface->list); + kfree(iface); + if (bcm->initialized) + bcm43xx_select_opmodes(bcm); + + 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)); + break; + } + bcm43xx_unlock_mmio(bcm, flags); +} + +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; + struct bcm43xx_interface *iface; + + bcm43xx_lock_mmio(bcm, flags); + list_for_each_entry(iface, &bcm->interfaces.list, list) { + if (iface->if_id == if_id) + goto found; + } + bcm43xx_unlock_mmio(bcm, flags); + + return -ENODEV; +found: + iface->bssid = conf->bssid; + //TODO + + 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; + u16 old_promisc; - bcm->interfaces--; + bcm43xx_lock_mmio(bcm, flags); + old_promisc = bcm->interfaces.opmode_promisc; + bcm->interfaces.opmode_promisc = !!(netflags & IFF_PROMISC); + if (bcm->interfaces.opmode_promisc != old_promisc) { + if (bcm->initialized) + bcm43xx_select_opmodes(bcm); + } + bcm43xx_unlock_mmio(bcm, flags); } /* Initialization of struct net_device, just after allocation. */ @@ -4240,6 +4344,7 @@ int err; bcm->ieee = ieee; + INIT_LIST_HEAD(&bcm->interfaces.list); bcm->irq_savedstate = BCM43xx_IRQ_INITIAL; bcm->pci_dev = pci_dev; bcm->net_dev = net_dev; @@ -4294,6 +4399,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 +4408,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-01 18:56:17.000000000 +0200 @@ -94,7 +94,7 @@ bcm43xx_mac_suspend(bcm); spin_lock(&phy->lock); } else { - if (bcm->iw_mode != IW_MODE_MASTER) + if (bcm->interfaces.opmode_ap == 0) 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 (bcm->interfaces.opmode_ap == 0) bcm43xx_power_saving_ctl_bits(bcm, -1, -1); } phy->is_locked = 0; -- Greetings Michael.
pgp51Lntltbxn.pgp
Description: PGP signature