>From Ivo van Doorn <[EMAIL PROTECTED]> Move all settings depending on the current association into a seperate interface structure. Altough we only support 1 association type at a time, we do support multiple monitor devices, keep track of the number using the monitor_count field.
Signed-off-by: Ivo van Doorn <[EMAIL PROTECTED]> --- diff -rU3 wireless-dev-style/drivers/net/wireless/d80211/rt2x00/rt2400pci.c wireless-dev-interface/drivers/net/wireless/d80211/rt2x00/rt2400pci.c --- wireless-dev-style/drivers/net/wireless/d80211/rt2x00/rt2400pci.c 2006-07-22 23:17:54.000000000 +0200 +++ wireless-dev-interface/drivers/net/wireless/d80211/rt2x00/rt2400pci.c 2006-07-23 14:54:53.000000000 +0200 @@ -411,7 +411,7 @@ rt2x00_set_field32(®, RXCSR0_DROP_TODS, 0); rt2x00_set_field32(®, RXCSR0_DROP_CRC, 1); - if (type == IEEE80211_IF_TYPE_MNTR) { + if (rt2x00pci->interface.monitor_count) { rt2x00_set_field32(®, RXCSR0_DROP_PHYSICAL, 0); rt2x00_set_field32(®, RXCSR0_DROP_CONTROL, 0); rt2x00_set_field32(®, RXCSR0_DROP_VERSION_ERROR, 0); @@ -426,7 +426,7 @@ /* * Enable promisc mode when in monitor mode. */ - if (type == IEEE80211_IF_TYPE_MNTR) + if (rt2x00pci->interface.monitor_count) rt2400pci_config_promisc(rt2x00pci, 1); /* @@ -445,7 +445,7 @@ /* * Update working mode. */ - rt2x00pci->type = type; + rt2x00pci->interface.type = type; } static void rt2400pci_config_channel(struct rt2x00_pci *rt2x00pci, @@ -897,7 +897,7 @@ memset(&beacon, 0x00, sizeof(beacon)); skb = ieee80211_beacon_get(ring->net_dev, - rt2x00pci->interface_id, &beacon); + rt2x00pci->interface.id, &beacon); if (!skb) return; @@ -1725,16 +1725,36 @@ struct rt2x00_pci *rt2x00pci = ieee80211_dev_hw_data(net_dev); /* - * We only support 1 single working mode. + * We only support 1 non-monitor interface. */ - if (GET_FLAG(rt2x00pci, INTERFACE_INITIALIZED)) + if (conf->type != IEEE80211_IF_TYPE_MNTR && + GET_FLAG(rt2x00pci, INTERFACE_INITIALIZED)) return -ENOBUFS; - rt2x00pci->interface_id = conf->if_id; + SET_FLAG(rt2x00pci, INTERFACE_INITIALIZED); + + rt2x00_add_interface(&rt2x00pci->interface, conf); + /* + * Enable configuration. + */ + rt2400pci_config_type(rt2x00pci, conf->type); rt2400pci_config_mac_address(rt2x00pci, conf->mac_addr); - SET_FLAG(rt2x00pci, INTERFACE_INITIALIZED); + /* + * In case of master mode, set the BSSID to our MAC. + */ + if (conf->type == IEEE80211_IF_TYPE_AP) { + memcpy(&rt2x00pci->interface.bssid, conf->mac_addr, ETH_ALEN); + rt2400pci_config_bssid(rt2x00pci, conf->mac_addr); + } + + /* + * Enable radio when this is the first + * interface that is brought up. + */ + if (!GET_FLAG(rt2x00pci, DEVICE_ENABLED_RADIO)) + return rt2400pci_enable_radio(rt2x00pci); return 0; } @@ -1745,14 +1765,22 @@ struct rt2x00_pci *rt2x00pci = ieee80211_dev_hw_data(net_dev); /* - * We only support 1 single working mode. + * We only support 1 non-monitor interface. */ - if (!GET_FLAG(rt2x00pci, INTERFACE_INITIALIZED)) + if (conf->type != IEEE80211_IF_TYPE_MNTR && + !GET_FLAG(rt2x00pci, INTERFACE_INITIALIZED)) return; - rt2x00pci->interface_id = 0; + rt2x00_remove_interface(&rt2x00pci->interface, conf); CLEAR_FLAG(rt2x00pci, INTERFACE_INITIALIZED); + + /* + * Disable radio if this was the last interface + * that was working with this device. + */ + if (!rt2x00pci->interface.monitor_count) + rt2400pci_disable_radio(rt2x00pci); } static void rt2400pci_config_update(void *data) @@ -1818,15 +1846,20 @@ { struct rt2x00_pci *rt2x00pci = ieee80211_dev_hw_data(net_dev); - rt2400pci_config_type(rt2x00pci, conf->type); - /* * When configuring monitor mode, we are done now. + * but if we are configuring another mode it must be + * equal to the interface that has been added. */ - if (rt2x00pci->type == IEEE80211_IF_TYPE_MNTR) + if (conf->type == IEEE80211_IF_TYPE_MNTR) return 0; + else if (conf->type != rt2x00pci->interface.type) + return -EINVAL; - rt2400pci_config_bssid(rt2x00pci, conf->bssid); + if (conf->bssid) { + memcpy(&rt2x00pci->interface.bssid, conf->bssid, ETH_ALEN); + rt2400pci_config_bssid(rt2x00pci, conf->bssid); + } return 0; } @@ -1835,21 +1868,27 @@ unsigned short flags, int mc_count) { struct rt2x00_pci *rt2x00pci = ieee80211_dev_hw_data(net_dev); + int update = 0; + + if (GET_FLAG(rt2x00pci, INTERFACE_PROMISC)) { + if (!(flags & IFF_PROMISC)) { + rt2x00pci->interface.promisc = 0; + update = 1; + } + } else { + if (flags & IFF_PROMISC) { + rt2x00pci->interface.promisc = 1; + update = 1; + } + } /* * Monitor mode works with PROMISC mode forced on, * so there is nothing to be done here. */ - if (rt2x00pci->type == IEEE80211_IF_TYPE_MNTR) - return; - - if (GET_FLAG(rt2x00pci, INTERFACE_PROMISC)) { - if (!(flags & IFF_PROMISC)) - rt2400pci_config_promisc(rt2x00pci, 0); - } else { - if (flags & IFF_PROMISC) - rt2400pci_config_promisc(rt2x00pci, 1); - } + if (update && !rt2x00pci->interface.monitor_count) + rt2400pci_config_promisc(rt2x00pci, + rt2x00pci->interface.promisc); } static void rt2400pci_scan(void *data) @@ -2419,6 +2458,11 @@ INIT_WORK(&rt2x00pci->config_work, rt2400pci_config_update, rt2x00pci); /* + * Reset current working type. + */ + rt2x00pci->interface.type = -EINVAL; + + /* * Intialize scanning attributes. */ INIT_WORK(&rt2x00pci->scan_work, rt2400pci_scan, rt2x00pci); diff -rU3 wireless-dev-style/drivers/net/wireless/d80211/rt2x00/rt2500pci.c wireless-dev-interface/drivers/net/wireless/d80211/rt2x00/rt2500pci.c --- wireless-dev-style/drivers/net/wireless/d80211/rt2x00/rt2500pci.c 2006-07-22 23:18:04.000000000 +0200 +++ wireless-dev-interface/drivers/net/wireless/d80211/rt2x00/rt2500pci.c 2006-07-23 14:55:00.000000000 +0200 @@ -411,7 +411,7 @@ rt2x00_set_field32(®, RXCSR0_DROP_TODS, 0); rt2x00_set_field32(®, RXCSR0_DROP_CRC, 1); - if (type == IEEE80211_IF_TYPE_MNTR) { + if (rt2x00pci->interface.monitor_count) { rt2x00_set_field32(®, RXCSR0_DROP_PHYSICAL, 0); rt2x00_set_field32(®, RXCSR0_DROP_CONTROL, 0); rt2x00_set_field32(®, RXCSR0_DROP_VERSION_ERROR, 0); @@ -429,7 +429,7 @@ /* * Enable promisc mode when in monitor mode. */ - if (type == IEEE80211_IF_TYPE_MNTR) + if (rt2x00pci->interface.monitor_count) rt2500pci_config_promisc(rt2x00pci, 1); /* @@ -448,7 +448,7 @@ /* * Update working mode. */ - rt2x00pci->type = type; + rt2x00pci->interface.type = type; } static void rt2500pci_config_channel(struct rt2x00_pci *rt2x00pci, @@ -976,7 +976,7 @@ memset(&beacon, 0x00, sizeof(beacon)); skb = ieee80211_beacon_get(ring->net_dev, - rt2x00pci->interface_id, &beacon); + rt2x00pci->interface.id, &beacon); if (!skb) return; @@ -1850,16 +1850,36 @@ struct rt2x00_pci *rt2x00pci = ieee80211_dev_hw_data(net_dev); /* - * We only support 1 single working mode. + * We only support 1 non-monitor interface. */ - if (GET_FLAG(rt2x00pci, INTERFACE_INITIALIZED)) + if (conf->type != IEEE80211_IF_TYPE_MNTR && + GET_FLAG(rt2x00pci, INTERFACE_INITIALIZED)) return -ENOBUFS; - rt2x00pci->interface_id = conf->if_id; + SET_FLAG(rt2x00pci, INTERFACE_INITIALIZED); + + rt2x00_add_interface(&rt2x00pci->interface, conf); + /* + * Enable configuration. + */ + rt2500pci_config_type(rt2x00pci, conf->type); rt2500pci_config_mac_address(rt2x00pci, conf->mac_addr); - SET_FLAG(rt2x00pci, INTERFACE_INITIALIZED); + /* + * In case of master mode, set the BSSID to our MAC. + */ + if (conf->type == IEEE80211_IF_TYPE_AP) { + memcpy(&rt2x00pci->interface.bssid, conf->mac_addr, ETH_ALEN); + rt2500pci_config_bssid(rt2x00pci, conf->mac_addr); + } + + /* + * Enable radio when this is the first + * interface that is brought up. + */ + if (!GET_FLAG(rt2x00pci, DEVICE_ENABLED_RADIO)) + return rt2500pci_enable_radio(rt2x00pci); return 0; } @@ -1870,14 +1890,22 @@ struct rt2x00_pci *rt2x00pci = ieee80211_dev_hw_data(net_dev); /* - * We only support 1 single working mode. + * We only support 1 non-monitor interface. */ - if (!GET_FLAG(rt2x00pci, INTERFACE_INITIALIZED)) + if (conf->type != IEEE80211_IF_TYPE_MNTR && + !GET_FLAG(rt2x00pci, INTERFACE_INITIALIZED)) return; - rt2x00pci->interface_id = 0; + rt2x00_remove_interface(&rt2x00pci->interface, conf); CLEAR_FLAG(rt2x00pci, INTERFACE_INITIALIZED); + + /* + * Disable radio if this was the last interface + * that was working with this device. + */ + if (!rt2x00pci->interface.monitor_count) + rt2500pci_disable_radio(rt2x00pci); } static void rt2500pci_config_update(void *data) @@ -1943,15 +1971,20 @@ { struct rt2x00_pci *rt2x00pci = ieee80211_dev_hw_data(net_dev); - rt2500pci_config_type(rt2x00pci, conf->type); - /* * When configuring monitor mode, we are done now. + * but if we are configuring another mode it must be + * equal to the interface that has been added. */ if (conf->type == IEEE80211_IF_TYPE_MNTR) return 0; + else if (conf->type != rt2x00pci->interface.type) + return -EINVAL; - rt2500pci_config_bssid(rt2x00pci, conf->bssid); + if (conf->bssid) { + memcpy(&rt2x00pci->interface.bssid, conf->bssid, ETH_ALEN); + rt2500pci_config_bssid(rt2x00pci, conf->bssid); + } return 0; } @@ -1960,21 +1993,27 @@ unsigned short flags, int mc_count) { struct rt2x00_pci *rt2x00pci = ieee80211_dev_hw_data(net_dev); + int update = 0; + + if (GET_FLAG(rt2x00pci, INTERFACE_PROMISC)) { + if (!(flags & IFF_PROMISC)) { + rt2x00pci->interface.promisc = 0; + update = 1; + } + } else { + if (flags & IFF_PROMISC) { + rt2x00pci->interface.promisc = 1; + update = 1; + } + } /* * Monitor mode works with PROMISC mode forced on, * so there is nothing to be done here. */ - if (rt2x00pci->type == IEEE80211_IF_TYPE_MNTR) - return; - - if (GET_FLAG(rt2x00pci, INTERFACE_PROMISC)) { - if (!(flags & IFF_PROMISC)) - rt2500pci_config_promisc(rt2x00pci, 0); - } else { - if (flags & IFF_PROMISC) - rt2500pci_config_promisc(rt2x00pci, 1); - } + if (update && !rt2x00pci->interface.monitor_count) + rt2500pci_config_promisc(rt2x00pci, + rt2x00pci->interface.promisc); } static void rt2500pci_scan(void *data) @@ -2722,6 +2761,11 @@ INIT_WORK(&rt2x00pci->config_work, rt2500pci_config_update, rt2x00pci); /* + * Reset current working type. + */ + rt2x00pci->interface.type = -EINVAL; + + /* * Intialize scanning attributes. */ INIT_WORK(&rt2x00pci->scan_work, rt2500pci_scan, rt2x00pci); diff -rU3 wireless-dev-style/drivers/net/wireless/d80211/rt2x00/rt2500usb.c wireless-dev-interface/drivers/net/wireless/d80211/rt2x00/rt2500usb.c --- wireless-dev-style/drivers/net/wireless/d80211/rt2x00/rt2500usb.c 2006-07-22 22:53:28.000000000 +0200 +++ wireless-dev-interface/drivers/net/wireless/d80211/rt2x00/rt2500usb.c 2006-07-23 14:54:29.000000000 +0200 @@ -261,7 +261,7 @@ rt2x00_set_field16_nb(®, TXRX_CSR2_DROP_TODS, 0); rt2x00_set_field16_nb(®, TXRX_CSR2_DROP_CRC, 1); - if (type == IEEE80211_IF_TYPE_MNTR) { + if (rt2x00usb->interface.monitor_count) { rt2x00_set_field16_nb(®, TXRX_CSR2_DROP_PHYSICAL, 0); rt2x00_set_field16_nb(®, TXRX_CSR2_DROP_CONTROL, 0); rt2x00_set_field16_nb(®, TXRX_CSR2_DROP_VERSION_ERROR, 0); @@ -276,7 +276,7 @@ /* * Enable promisc mode when in monitor mode. */ - if (type == IEEE80211_IF_TYPE_MNTR) + if (rt2x00usb->interface.monitor_count) rt2500usb_config_promisc(rt2x00usb, 1); /* @@ -295,7 +295,7 @@ /* * Update working mode. */ - rt2x00usb->type = type; + rt2x00usb->interface.type = type; } static void rt2500usb_config_channel(struct rt2x00_usb *rt2x00usb, @@ -796,7 +796,7 @@ memset(&beacon, 0x00, sizeof(beacon)); skb = ieee80211_beacon_get(ring->net_dev, - rt2x00usb->interface_id, &beacon); + rt2x00usb->interface.id, &beacon); if (!skb) return; @@ -1510,16 +1510,36 @@ struct rt2x00_usb *rt2x00usb = ieee80211_dev_hw_data(net_dev); /* - * We only support 1 single working mode. + * We only support 1 non-monitor interface. */ - if (GET_FLAG(rt2x00usb, INTERFACE_INITIALIZED)) + if (conf->type != IEEE80211_IF_TYPE_MNTR && + GET_FLAG(rt2x00usb, INTERFACE_INITIALIZED)) return -ENOBUFS; - rt2x00usb->interface_id = conf->if_id; + SET_FLAG(rt2x00usb, INTERFACE_INITIALIZED); + + rt2x00_add_interface(&rt2x00usb->interface, conf); + /* + * Enable configuration. + */ + rt2500usb_config_type(rt2x00usb, conf->type); rt2500usb_config_mac_address(rt2x00usb, conf->mac_addr); - SET_FLAG(rt2x00usb, INTERFACE_INITIALIZED); + /* + * In case of master mode, set the BSSID to our MAC. + */ + if (conf->type == IEEE80211_IF_TYPE_AP) { + memcpy(&rt2x00usb->interface.bssid, conf->mac_addr, ETH_ALEN); + rt2500usb_config_bssid(rt2x00usb, conf->mac_addr); + } + + /* + * Enable radio when this is the first + * interface that is brought up. + */ + if (!GET_FLAG(rt2x00usb, DEVICE_ENABLED_RADIO)) + return rt2500usb_enable_radio(rt2x00usb); return 0; } @@ -1530,14 +1550,22 @@ struct rt2x00_usb *rt2x00usb = ieee80211_dev_hw_data(net_dev); /* - * We only support 1 single working mode. + * We only support 1 non-monitor interface. */ - if (!GET_FLAG(rt2x00usb, INTERFACE_INITIALIZED)) + if (conf->type != IEEE80211_IF_TYPE_MNTR && + !GET_FLAG(rt2x00usb, INTERFACE_INITIALIZED)) return; - rt2x00usb->interface_id = 0; + rt2x00_remove_interface(&rt2x00usb->interface, conf); CLEAR_FLAG(rt2x00usb, INTERFACE_INITIALIZED); + + /* + * Disable radio if this was the last interface + * that was working with this device. + */ + if (!rt2x00usb->interface.monitor_count) + rt2500usb_disable_radio(rt2x00usb); } static void rt2500usb_config_update(void *data) @@ -1598,20 +1626,35 @@ return !queue_work(rt2x00usb->workqueue, &rt2x00usb->config_work); } +static void rt2500usb_interface_update(void *data) +{ + struct rt2x00_usb *rt2x00usb = data; + + rt2500usb_config_bssid(rt2x00usb, &rt2x00usb->interface.bssid[0]); + rt2500usb_config_promisc(rt2x00usb, (rt2x00usb->interface.promisc || + rt2x00usb->interface.monitor_count)); +} + static int rt2500usb_config_interface(struct net_device *net_dev, int if_id, struct ieee80211_if_conf *conf) { struct rt2x00_usb *rt2x00usb = ieee80211_dev_hw_data(net_dev); - rt2500usb_config_type(rt2x00usb, conf->type); - /* * When configuring monitor mode, we are done now. + * but if we are configuring another mode it must be + * equal to the interface that has been added. */ if (conf->type == IEEE80211_IF_TYPE_MNTR) return 0; + else if (conf->type != rt2x00usb->interface.type) + return -EINVAL; - rt2500usb_config_bssid(rt2x00usb, conf->bssid); + if (conf->bssid) { + memcpy(&rt2x00usb->interface.bssid, conf->bssid, ETH_ALEN); + return !queue_work(rt2x00usb->workqueue, + &rt2x00usb->interface.work); + } return 0; } @@ -1620,21 +1663,27 @@ unsigned short flags, int mc_count) { struct rt2x00_usb *rt2x00usb = ieee80211_dev_hw_data(net_dev); + int update = 0; + + if (GET_FLAG(rt2x00usb, INTERFACE_PROMISC)) { + if (!(flags & IFF_PROMISC)) { + rt2x00usb->interface.promisc = 0; + update = 1; + } + } else { + if (flags & IFF_PROMISC) { + rt2x00usb->interface.promisc = 1; + update = 1; + } + } /* * Monitor mode works with PROMISC mode forced on, * so there is nothing to be done here. */ - if (rt2x00usb->type == IEEE80211_IF_TYPE_MNTR) - return; - - if (GET_FLAG(rt2x00usb, INTERFACE_PROMISC)) { - if (!(flags & IFF_PROMISC)) - rt2500usb_config_promisc(rt2x00usb, 0); - } else { - if (flags & IFF_PROMISC) - rt2500usb_config_promisc(rt2x00usb, 1); - } + if (update && !rt2x00usb->interface.monitor_count) + queue_work(rt2x00usb->workqueue, + &rt2x00usb->interface.work); } static void rt2500usb_scan(void *data) @@ -2326,6 +2375,13 @@ * Initialize cofniguration work. */ INIT_WORK(&rt2x00usb->config_work, rt2500usb_config_update, rt2x00usb); + INIT_WORK(&rt2x00usb->interface.work, + rt2500usb_interface_update, rt2x00usb); + + /* + * Reset current working type. + */ + rt2x00usb->interface.type = -EINVAL; /* * Intialize scanning attributes. diff -rU3 wireless-dev-style/drivers/net/wireless/d80211/rt2x00/rt2x00.h wireless-dev-interface/drivers/net/wireless/d80211/rt2x00/rt2x00.h --- wireless-dev-style/drivers/net/wireless/d80211/rt2x00/rt2x00.h 2006-07-23 14:17:22.000000000 +0200 +++ wireless-dev-interface/drivers/net/wireless/d80211/rt2x00/rt2x00.h 2006-07-23 14:24:04.000000000 +0200 @@ -570,6 +570,90 @@ } /* + * Interface structure + * Configuration details about the current interface. + */ +struct interface { + /* + * Interface identification. The value is assigned + * to us by the 80211 stack, and is used to request + * new beacons. + */ + int id; + + /* + * Current working type (IEEE80211_IF_TYPE_*). + * This excludes the type IEEE80211_IF_TYPE_MNTR + * since that is counted seperately in the monitor_count + * field. + */ + int type; + + /* + * BBSID of the AP to associate with. + */ + u8 bssid[ETH_ALEN]; + + /* + * Store the promisc mode for the current interface. + * monitor mode always forces promisc mode to be enabled, + * so we need to store the promisc mode seperately. + */ + short promisc; + + /* + * Monitor mode count, the number of interfaces + * in monitor mode that that have been added. + */ + short monitor_count; + + /* + * Sequence number for software controled sequence counters. + */ + u16 sequence; + + /* + * Work structure in case interface configuration + * requires scheduling. + */ + struct work_struct work; +}; + +static inline void rt2x00_add_interface(struct interface *intf, + struct ieee80211_if_init_conf *conf) +{ + /* + * We support muliple monitor mode interfaces. + * All we need to do is increase the monitor_count. + */ + if (conf->type == IEEE80211_IF_TYPE_MNTR) { + intf->monitor_count++; + } else { + intf->id = conf->if_id; + intf->promisc = 0; + intf->sequence = 0; + } +} + +static inline void rt2x00_remove_interface(struct interface *intf, + struct ieee80211_if_init_conf *conf) +{ + /* + * We support muliple monitor mode interfaces. + * All we need to do is decrease the monitor_count. + */ + if (conf->type == IEEE80211_IF_TYPE_MNTR) { + intf->monitor_count--; + } else if (intf->type == conf->type) { + intf->id = 0; + intf->type = -EINVAL; + memset(&intf->bssid, 0x00, ETH_ALEN); + intf->promisc = 0; + intf->sequence = 0; + } +} + +/* * Scanning structure. * Swithing channel during scanning will be put * in a workqueue so we will be able to sleep diff -rU3 wireless-dev-style/drivers/net/wireless/d80211/rt2x00/rt2x00pci.h wireless-dev-interface/drivers/net/wireless/d80211/rt2x00/rt2x00pci.h --- wireless-dev-style/drivers/net/wireless/d80211/rt2x00/rt2x00pci.h 2006-07-22 23:04:01.000000000 +0200 +++ wireless-dev-interface/drivers/net/wireless/d80211/rt2x00/rt2x00pci.h 2006-07-23 14:24:46.000000000 +0200 @@ -155,15 +155,9 @@ struct workqueue_struct *workqueue; /* - * Interface identication required for requesting beacons - * from dscape stack. + * Interface we are connected with. */ - int interface_id; - - /* - * Current working mode. - */ - int type; + struct interface interface; /* * EEPROM bus width. diff -rU3 wireless-dev-style/drivers/net/wireless/d80211/rt2x00/rt2x00usb.h wireless-dev-interface/drivers/net/wireless/d80211/rt2x00/rt2x00usb.h --- wireless-dev-style/drivers/net/wireless/d80211/rt2x00/rt2x00usb.h 2006-07-22 23:04:13.000000000 +0200 +++ wireless-dev-interface/drivers/net/wireless/d80211/rt2x00/rt2x00usb.h 2006-07-23 14:25:07.000000000 +0200 @@ -150,15 +150,9 @@ struct workqueue_struct *workqueue; /* - * Interface identication required for requesting beacons - * from dscape stack. + * Interface we are connected with. */ - int interface_id; - - /* - * Current working mode. - */ - int type; + struct interface interface; /* * Frequency offset (for rt73usb). diff -rU3 wireless-dev-style/drivers/net/wireless/d80211/rt2x00/rt61pci.c wireless-dev-interface/drivers/net/wireless/d80211/rt2x00/rt61pci.c --- wireless-dev-style/drivers/net/wireless/d80211/rt2x00/rt61pci.c 2006-07-22 23:19:03.000000000 +0200 +++ wireless-dev-interface/drivers/net/wireless/d80211/rt2x00/rt61pci.c 2006-07-23 14:55:07.000000000 +0200 @@ -442,7 +442,7 @@ rt2x00_set_field32(®, TXRX_CSR0_DROP_TO_DS, 0); rt2x00_set_field32(®, TXRX_CSR0_DROP_CRC, 1); - if (type == IEEE80211_IF_TYPE_MNTR) { + if (rt2x00pci->interface.monitor_count) { rt2x00_set_field32(®, TXRX_CSR0_DROP_PHYSICAL, 0); rt2x00_set_field32(®, TXRX_CSR0_DROP_CONTROL, 0); rt2x00_set_field32(®, TXRX_CSR0_DROP_VERSION_ERROR, 0); @@ -460,7 +460,7 @@ /* * Enable promisc mode when in monitor mode. */ - if (type == IEEE80211_IF_TYPE_MNTR) + if (rt2x00pci->interface.monitor_count) rt61pci_config_promisc(rt2x00pci, 1); /* @@ -479,7 +479,7 @@ /* * Update working mode. */ - rt2x00pci->type = type; + rt2x00pci->interface.type = type; } static void rt61pci_config_channel(struct rt2x00_pci *rt2x00pci, @@ -1231,7 +1231,7 @@ memset(&beacon, 0x00, sizeof(beacon)); skb = ieee80211_beacon_get(ring->net_dev, - rt2x00pci->interface_id, &beacon); + rt2x00pci->interface.id, &beacon); if (!skb) return; @@ -2305,16 +2305,36 @@ struct rt2x00_pci *rt2x00pci = ieee80211_dev_hw_data(net_dev); /* - * We only support 1 single working mode. + * We only support 1 non-monitor interface. */ - if (GET_FLAG(rt2x00pci, INTERFACE_INITIALIZED)) + if (conf->type != IEEE80211_IF_TYPE_MNTR && + GET_FLAG(rt2x00pci, INTERFACE_INITIALIZED)) return -ENOBUFS; - rt2x00pci->interface_id = conf->if_id; + SET_FLAG(rt2x00pci, INTERFACE_INITIALIZED); + + rt2x00_add_interface(&rt2x00pci->interface, conf); + /* + * Enable configuration. + */ + rt61pci_config_type(rt2x00pci, conf->type); rt61pci_config_mac_address(rt2x00pci, conf->mac_addr); - SET_FLAG(rt2x00pci, INTERFACE_INITIALIZED); + /* + * In case of master mode, set the BSSID to our MAC. + */ + if (conf->type == IEEE80211_IF_TYPE_AP) { + memcpy(&rt2x00pci->interface.bssid, conf->mac_addr, ETH_ALEN); + rt61pci_config_bssid(rt2x00pci, conf->mac_addr); + } + + /* + * Enable radio when this is the first + * interface that is brought up. + */ + if (!GET_FLAG(rt2x00pci, DEVICE_ENABLED_RADIO)) + return rt61pci_enable_radio(rt2x00pci); return 0; } @@ -2325,14 +2345,22 @@ struct rt2x00_pci *rt2x00pci = ieee80211_dev_hw_data(net_dev); /* - * We only support 1 single working mode. + * We only support 1 non-monitor interface. */ - if (!GET_FLAG(rt2x00pci, INTERFACE_INITIALIZED)) + if (conf->type != IEEE80211_IF_TYPE_MNTR && + !GET_FLAG(rt2x00pci, INTERFACE_INITIALIZED)) return; - rt2x00pci->interface_id = 0; + rt2x00_remove_interface(&rt2x00pci->interface, conf); CLEAR_FLAG(rt2x00pci, INTERFACE_INITIALIZED); + + /* + * Disable radio if this was the last interface + * that was working with this device. + */ + if (!rt2x00pci->interface.monitor_count) + rt61pci_disable_radio(rt2x00pci); } static void rt61pci_config_update(void *data) @@ -2398,15 +2426,20 @@ { struct rt2x00_pci *rt2x00pci = ieee80211_dev_hw_data(net_dev); - rt61pci_config_type(rt2x00pci, conf->type); - /* * When configuring monitor mode, we are done now. + * but if we are configuring another mode it must be + * equal to the interface that has been added. */ if (conf->type == IEEE80211_IF_TYPE_MNTR) return 0; + else if (conf->type != rt2x00pci->interface.type) + return -EINVAL; - rt61pci_config_bssid(rt2x00pci, conf->bssid); + if (conf->bssid) { + memcpy(&rt2x00pci->interface.bssid, conf->bssid, ETH_ALEN); + rt61pci_config_bssid(rt2x00pci, conf->bssid); + } return 0; } @@ -2415,21 +2448,27 @@ unsigned short flags, int mc_count) { struct rt2x00_pci *rt2x00pci = ieee80211_dev_hw_data(net_dev); + int update = 0; + + if (GET_FLAG(rt2x00pci, INTERFACE_PROMISC)) { + if (!(flags & IFF_PROMISC)) { + rt2x00pci->interface.promisc = 0; + update = 1; + } + } else { + if (flags & IFF_PROMISC) { + rt2x00pci->interface.promisc = 1; + update = 1; + } + } /* * Monitor mode works with PROMISC mode forced on, * so there is nothing to be done here. */ - if (rt2x00pci->type == IEEE80211_IF_TYPE_MNTR) - return; - - if (GET_FLAG(rt2x00pci, INTERFACE_PROMISC)) { - if (!(flags & IFF_PROMISC)) - rt61pci_config_promisc(rt2x00pci, 0); - } else { - if (flags & IFF_PROMISC) - rt61pci_config_promisc(rt2x00pci, 1); - } + if (update && !rt2x00pci->interface.monitor_count) + rt61pci_config_promisc(rt2x00pci, + rt2x00pci->interface.promisc); } static void rt61pci_scan(void *data) @@ -3263,6 +3302,11 @@ INIT_WORK(&rt2x00pci->config_work, rt61pci_config_update, rt2x00pci); /* + * Reset current working type. + */ + rt2x00pci->interface.type = -EINVAL; + + /* * Initialize scanning attributes. */ INIT_WORK(&rt2x00pci->scan_work, rt61pci_scan, rt2x00pci); diff -rU3 wireless-dev-style/drivers/net/wireless/d80211/rt2x00/rt73usb.c wireless-dev-interface/drivers/net/wireless/d80211/rt2x00/rt73usb.c --- wireless-dev-style/drivers/net/wireless/d80211/rt2x00/rt73usb.c 2006-07-22 23:18:51.000000000 +0200 +++ wireless-dev-interface/drivers/net/wireless/d80211/rt2x00/rt73usb.c 2006-07-23 14:55:15.000000000 +0200 @@ -263,7 +263,7 @@ rt2x00_set_field32(®, TXRX_CSR0_DROP_TO_DS, 0); rt2x00_set_field32(®, TXRX_CSR0_DROP_CRC, 1); - if (type == IEEE80211_IF_TYPE_MNTR) { + if (rt2x00usb->interface.monitor_count) { rt2x00_set_field32(®, TXRX_CSR0_DROP_PHYSICAL, 0); rt2x00_set_field32(®, TXRX_CSR0_DROP_CONTROL, 0); rt2x00_set_field32(®, TXRX_CSR0_DROP_VERSION_ERROR, 0); @@ -281,7 +281,7 @@ /* * Enable promisc mode when in monitor mode. */ - if (type == IEEE80211_IF_TYPE_MNTR) + if (rt2x00usb->interface.monitor_count) rt73usb_config_promisc(rt2x00usb, 1); /* @@ -296,6 +296,11 @@ else rt2x00_set_field32(®, TXRX_CSR9_TSF_SYNC_MODE, 0); rt2x00_register_write(rt2x00usb, TXRX_CSR9, reg); + + /* + * Update working mode. + */ + rt2x00usb->interface.type = type; } static void rt73usb_config_channel(struct rt2x00_usb *rt2x00usb, @@ -959,7 +964,7 @@ memset(&beacon, 0x00, sizeof(beacon)); skb = ieee80211_beacon_get(ring->net_dev, - rt2x00usb->interface_id, &beacon); + rt2x00usb->interface.id, &beacon); if (!skb) return; @@ -1804,16 +1809,36 @@ struct rt2x00_usb *rt2x00usb = ieee80211_dev_hw_data(net_dev); /* - * We only support 1 single working mode. + * We only support 1 non-monitor interface. */ - if (GET_FLAG(rt2x00usb, INTERFACE_INITIALIZED)) + if (conf->type != IEEE80211_IF_TYPE_MNTR && + GET_FLAG(rt2x00usb, INTERFACE_INITIALIZED)) return -ENOBUFS; - rt2x00usb->interface_id = conf->if_id; + SET_FLAG(rt2x00usb, INTERFACE_INITIALIZED); + + rt2x00_add_interface(&rt2x00usb->interface, conf); + /* + * Enable configuration. + */ + rt73usb_config_type(rt2x00usb, conf->type); rt73usb_config_mac_address(rt2x00usb, conf->mac_addr); - SET_FLAG(rt2x00usb, INTERFACE_INITIALIZED); + /* + * In case of master mode, set the BSSID to our MAC. + */ + if (conf->type == IEEE80211_IF_TYPE_AP) { + memcpy(&rt2x00usb->interface.bssid, conf->mac_addr, ETH_ALEN); + rt73usb_config_bssid(rt2x00usb, conf->mac_addr); + } + + /* + * Enable radio when this is the first + * interface that is brought up. + */ + if (!GET_FLAG(rt2x00usb, DEVICE_ENABLED_RADIO)) + return rt73usb_enable_radio(rt2x00usb); return 0; } @@ -1824,14 +1849,22 @@ struct rt2x00_usb *rt2x00usb = ieee80211_dev_hw_data(net_dev); /* - * We only support 1 single working mode. + * We only support 1 non-monitor interface. */ - if (!GET_FLAG(rt2x00usb, INTERFACE_INITIALIZED)) + if (conf->type != IEEE80211_IF_TYPE_MNTR && + !GET_FLAG(rt2x00usb, INTERFACE_INITIALIZED)) return; - rt2x00usb->interface_id = 0; + rt2x00_remove_interface(&rt2x00usb->interface, conf); CLEAR_FLAG(rt2x00usb, INTERFACE_INITIALIZED); + + /* + * Disable radio if this was the last interface + * that was working with this device. + */ + if (!rt2x00usb->interface.monitor_count) + rt73usb_disable_radio(rt2x00usb); } static void rt73usb_config_update(void *data) @@ -1895,20 +1928,35 @@ return !queue_work(rt2x00usb->workqueue, &rt2x00usb->config_work); } +static void rt73usb_interface_update(void *data) +{ + struct rt2x00_usb *rt2x00usb = data; + + rt73usb_config_bssid(rt2x00usb, &rt2x00usb->interface.bssid[0]); + rt73usb_config_promisc(rt2x00usb, (rt2x00usb->interface.promisc || + rt2x00usb->interface.monitor_count)); +} + static int rt73usb_config_interface(struct net_device *net_dev, int if_id, struct ieee80211_if_conf *conf) { struct rt2x00_usb *rt2x00usb = ieee80211_dev_hw_data(net_dev); - rt73usb_config_type(rt2x00usb, conf->type); - /* * When configuring monitor mode, we are done now. + * but if we are configuring another mode it must be + * equal to the interface that has been added. */ if (conf->type == IEEE80211_IF_TYPE_MNTR) return 0; + else if (conf->type != rt2x00usb->interface.type) + return -EINVAL; - rt73usb_config_bssid(rt2x00usb, conf->bssid); + if (conf->bssid) { + memcpy(&rt2x00usb->interface.bssid, conf->bssid, ETH_ALEN); + return !queue_work(rt2x00usb->workqueue, + &rt2x00usb->interface.work); + } return 0; } @@ -1917,21 +1965,27 @@ unsigned short flags, int mc_count) { struct rt2x00_usb *rt2x00usb = ieee80211_dev_hw_data(net_dev); + int update = 0; + + if (GET_FLAG(rt2x00usb, INTERFACE_PROMISC)) { + if (!(flags & IFF_PROMISC)) { + rt2x00usb->interface.promisc = 0; + update = 1; + } + } else { + if (flags & IFF_PROMISC) { + rt2x00usb->interface.promisc = 1; + update = 1; + } + } /* * Monitor mode works with PROMISC mode forced on, * so there is nothing to be done here. */ - if (rt2x00usb->type == IEEE80211_IF_TYPE_MNTR) - return; - - if (GET_FLAG(rt2x00usb, INTERFACE_PROMISC)) { - if (!(flags & IFF_PROMISC)) - rt73usb_config_promisc(rt2x00usb, 0); - } else { - if (flags & IFF_PROMISC) - rt73usb_config_promisc(rt2x00usb, 1); - } + if (update && !rt2x00usb->interface.monitor_count) + queue_work(rt2x00usb->workqueue, + &rt2x00usb->interface.work); } static void rt73usb_scan(void *data) @@ -2730,6 +2784,13 @@ * Initialize cofniguration work. */ INIT_WORK(&rt2x00usb->config_work, rt73usb_config_update, rt2x00usb); + INIT_WORK(&rt2x00usb->interface.work, + rt73usb_interface_update, rt2x00usb); + + /* + * Reset current working type. + */ + rt2x00usb->interface.type = -EINVAL; /* * Intialize scanning attributes. - 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