| Index: server/site_linux_router.py | 
| diff --git a/server/site_linux_router.py b/server/site_linux_router.py | 
| index b17c0666767a82ff13f0b2c6fee7dfef9e24184c..0e89b8fbc133a25e2e2e35b5d512448441e42c9e 100644 | 
| --- a/server/site_linux_router.py | 
| +++ b/server/site_linux_router.py | 
| @@ -85,7 +85,12 @@ class LinuxRouter(object): | 
| 'hw_mode': 'g' | 
| } | 
| } | 
| - | 
| +        self.station = { | 
| +            'configured': False, | 
| +            'conf': { | 
| +                'ssid': defssid, | 
| +            } | 
| +        } | 
| # Kill hostapd if already running. | 
| self.router.run("pkill hostapd >/dev/null 2>&1", ignore_status=True) | 
|  | 
| @@ -120,8 +125,9 @@ class LinuxRouter(object): | 
| # iw wants) | 
| # | 
| # map from bsd types to iw types | 
| -        if params['type'] == "ap" or params['type'] == "hostap": | 
| -            self.apmode = True | 
| +        self.apmode = params['type'] in ("ap", "hostap") | 
| +        if not self.apmode: | 
| +            self.station['type'] = params['type'] | 
| phytype = { | 
| "sta"       : "managed", | 
| "monitor"   : "monitor", | 
| @@ -146,187 +152,264 @@ class LinuxRouter(object): | 
|  | 
|  | 
|  | 
| -    def config(self, params): | 
| +    def hostap_config(self, params): | 
| """ Configure the AP per test requirements """ | 
|  | 
| multi_interface = 'multi_interface' in params | 
| if multi_interface: | 
| params.pop('multi_interface') | 
| -        elif self.hostapd['configured']: | 
| +        elif self.hostapd['configured'] or self.station['configured']: | 
| self.deconfig({}) | 
|  | 
| -        if self.apmode: | 
| -            # Construct the hostapd.conf file and start hostapd. | 
| -            conf = self.hostapd['conf'] | 
| -            tx_power_params = {} | 
| -            htcaps = set() | 
| - | 
| -            conf['driver'] = params.get('hostapd_driver', | 
| -                self.hostapd['driver']) | 
| - | 
| -            for k, v in params.iteritems(): | 
| -                if k == 'ssid': | 
| -                    conf['ssid'] = v | 
| -                elif k == 'ssid_suffix': | 
| -                    conf['ssid'] = self.defssid + v | 
| -                elif k == 'channel': | 
| -                    freq = int(v) | 
| - | 
| -                    # 2.4GHz | 
| -                    if freq <= 2484: | 
| -                        # Make sure hw_mode is set | 
| -                        if conf.get('hw_mode') == 'a': | 
| -                            conf['hw_mode'] = 'g' | 
| - | 
| -                        # Freq = 5 * chan + 2407, except channel 14 | 
| -                        if freq == 2484: | 
| -                            conf['channel'] = 14 | 
| -                        else: | 
| -                            conf['channel'] = (freq - 2407) / 5 | 
| -                    # 5GHz | 
| -                    else: | 
| -                        # Make sure hw_mode is set | 
| -                        conf['hw_mode'] = 'a' | 
| -                        # Freq = 5 * chan + 4000 | 
| -                        if freq < 5000: | 
| -                            conf['channel'] = (freq - 4000) / 5 | 
| -                        # Freq = 5 * chan + 5000 | 
| -                        else: | 
| -                            conf['channel'] = (freq - 5000) / 5 | 
| - | 
| -                elif k == 'country': | 
| -                    conf['country_code'] = v | 
| -                elif k == 'dotd': | 
| -                    conf['ieee80211d'] = 1 | 
| -                elif k == '-dotd': | 
| -                    conf['ieee80211d'] = 0 | 
| -                elif k == 'mode': | 
| -                    if v == '11a': | 
| -                        conf['hw_mode'] = 'a' | 
| -                    elif v == '11g': | 
| +        # Construct the hostapd.conf file and start hostapd. | 
| +        conf = self.hostapd['conf'] | 
| +        tx_power_params = {} | 
| +        htcaps = set() | 
| + | 
| +        conf['driver'] = params.get('hostapd_driver', | 
| +            self.hostapd['driver']) | 
| + | 
| +        for k, v in params.iteritems(): | 
| +            if k == 'ssid': | 
| +                conf['ssid'] = v | 
| +            elif k == 'ssid_suffix': | 
| +                conf['ssid'] = self.defssid + v | 
| +            elif k == 'channel': | 
| +                freq = int(v) | 
| + | 
| +                # 2.4GHz | 
| +                if freq <= 2484: | 
| +                    # Make sure hw_mode is set | 
| +                    if conf.get('hw_mode') == 'a': | 
| conf['hw_mode'] = 'g' | 
| -                    elif v == '11b': | 
| -                        conf['hw_mode'] = 'b' | 
| -                    elif v == '11n': | 
| -                        conf['ieee80211n'] = 1 | 
| -                elif k == 'bintval': | 
| -                    conf['beacon_int'] = v | 
| -                elif k == 'dtimperiod': | 
| -                    conf['dtim_period'] = v | 
| -                elif k == 'rtsthreshold': | 
| -                    conf['rts_threshold'] = v | 
| -                elif k == 'fragthreshold': | 
| -                    conf['fragm_threshold'] = v | 
| -                elif k == 'shortpreamble': | 
| -                    conf['preamble'] = 1 | 
| -                elif k == 'authmode': | 
| -                    if v == "open": | 
| -                        conf['auth_algs'] = 1 | 
| -                    elif v == "shared": | 
| -                        conf['auth_algs'] = 2 | 
| -                elif k == 'hidessid': | 
| -                    conf['ignore_broadcast_ssid'] = 1 | 
| -                elif k == 'wme': | 
| -                    conf['wmm_enabled'] = 1 | 
| -                elif k == '-wme': | 
| -                    conf['wmm_enabled'] = 0 | 
| -                elif k == 'deftxkey': | 
| -                    conf['wep_default_key'] = v | 
| -                elif k == 'ht20': | 
| -                    htcaps.add('')  # NB: ensure 802.11n setup below | 
| -                    conf['wmm_enabled'] = 1 | 
| -                elif k == 'ht40': | 
| -                    htcaps.add('[HT40-]') | 
| -                    htcaps.add('[HT40+]') | 
| -                    conf['wmm_enabled'] = 1 | 
| -                elif k == 'shortgi': | 
| -                    htcaps.add('[SHORT-GI-20]') | 
| -                    htcaps.add('[SHORT-GI-40]') | 
| -                elif k == 'pureg': | 
| -                    pass        # TODO(sleffler) need hostapd support | 
| -                elif k == 'puren': | 
| -                    pass        # TODO(sleffler) need hostapd support | 
| -                elif k == 'protmode': | 
| -                    pass        # TODO(sleffler) need hostapd support | 
| -                elif k == 'ht': | 
| -                    htcaps.add('')  # NB: ensure 802.11n setup below | 
| -                elif k == 'htprotmode': | 
| -                    pass        # TODO(sleffler) need hostapd support | 
| -                elif k == 'rifs': | 
| -                    pass        # TODO(sleffler) need hostapd support | 
| -                elif k == 'wepmode': | 
| -                    pass        # NB: meaningless for hostapd; ignore | 
| -                elif k == '-ampdu': | 
| -                    pass        # TODO(sleffler) need hostapd support | 
| -                elif k == 'txpower': | 
| -                    tx_power_params['power'] = v | 
| -                else: | 
| -                    conf[k] = v | 
| - | 
| -            # Aggregate ht_capab. | 
| -            if htcaps: | 
| -                conf['ieee80211n'] = 1 | 
| -                conf['ht_capab'] = ''.join(htcaps) | 
|  | 
| -            # Figure out the correct interface. | 
| -            if conf.get('hw_mode', 'b') == 'a': | 
| -                conf['interface'] = self.wlanif5 | 
| -            else: | 
| -                conf['interface'] = self.wlanif2 | 
| - | 
| -            # Generate hostapd.conf. | 
| -            self.router.run("cat <<EOF >%s\n%s\nEOF\n" % | 
| -                (self.hostapd['file'], '\n'.join( | 
| -                "%s=%s" % kv for kv in conf.iteritems()))) | 
| - | 
| -            if not multi_interface: | 
| -                logging.info("Initializing bridge...") | 
| -                self.router.run("%s addbr %s" % | 
| -                                (self.cmd_brctl, self.bridgeif)) | 
| -                self.router.run("%s setfd %s %d" % | 
| -                                (self.cmd_brctl, self.bridgeif, 0)) | 
| -                self.router.run("%s stp %s %d" % | 
| -                                (self.cmd_brctl, self.bridgeif, 0)) | 
| - | 
| -            # Run hostapd. | 
| -            logging.info("Starting hostapd...") | 
| -            self.router.run("%s -B %s" % | 
| -                (self.cmd_hostapd, self.hostapd['file'])) | 
| - | 
| - | 
| -            # Set up the bridge. | 
| -            if not multi_interface: | 
| -                logging.info("Setting up the bridge...") | 
| -                self.router.run("%s addif %s %s" % | 
| -                                (self.cmd_brctl, self.bridgeif, self.wiredif)) | 
| -                self.router.run("%s link set %s up" % | 
| -                                (self.cmd_ip, self.wiredif)) | 
| -                self.router.run("%s link set %s up" % | 
| -                                (self.cmd_ip, self.bridgeif)) | 
| -                self.hostapd['interface'] = conf['interface'] | 
| +                    # Freq = 5 * chan + 2407, except channel 14 | 
| +                    if freq == 2484: | 
| +                        conf['channel'] = 14 | 
| +                    else: | 
| +                        conf['channel'] = (freq - 2407) / 5 | 
| +                # 5GHz | 
| +                else: | 
| +                    # Make sure hw_mode is set | 
| +                    conf['hw_mode'] = 'a' | 
| +                    # Freq = 5 * chan + 4000 | 
| +                    if freq < 5000: | 
| +                        conf['channel'] = (freq - 4000) / 5 | 
| +                    # Freq = 5 * chan + 5000 | 
| +                    else: | 
| +                        conf['channel'] = (freq - 5000) / 5 | 
| + | 
| +            elif k == 'country': | 
| +                conf['country_code'] = v | 
| +            elif k == 'dotd': | 
| +                conf['ieee80211d'] = 1 | 
| +            elif k == '-dotd': | 
| +                conf['ieee80211d'] = 0 | 
| +            elif k == 'mode': | 
| +                if v == '11a': | 
| +                    conf['hw_mode'] = 'a' | 
| +                elif v == '11g': | 
| +                    conf['hw_mode'] = 'g' | 
| +                elif v == '11b': | 
| +                    conf['hw_mode'] = 'b' | 
| +                elif v == '11n': | 
| +                    conf['ieee80211n'] = 1 | 
| +            elif k == 'bintval': | 
| +                conf['beacon_int'] = v | 
| +            elif k == 'dtimperiod': | 
| +                conf['dtim_period'] = v | 
| +            elif k == 'rtsthreshold': | 
| +                conf['rts_threshold'] = v | 
| +            elif k == 'fragthreshold': | 
| +                conf['fragm_threshold'] = v | 
| +            elif k == 'shortpreamble': | 
| +                conf['preamble'] = 1 | 
| +            elif k == 'authmode': | 
| +                if v == "open": | 
| +                    conf['auth_algs'] = 1 | 
| +                elif v == "shared": | 
| +                    conf['auth_algs'] = 2 | 
| +            elif k == 'hidessid': | 
| +                conf['ignore_broadcast_ssid'] = 1 | 
| +            elif k == 'wme': | 
| +                conf['wmm_enabled'] = 1 | 
| +            elif k == '-wme': | 
| +                conf['wmm_enabled'] = 0 | 
| +            elif k == 'deftxkey': | 
| +                conf['wep_default_key'] = v | 
| +            elif k == 'ht20': | 
| +                htcaps.add('')  # NB: ensure 802.11n setup below | 
| +                conf['wmm_enabled'] = 1 | 
| +            elif k == 'ht40': | 
| +                htcaps.add('[HT40-]') | 
| +                htcaps.add('[HT40+]') | 
| +                conf['wmm_enabled'] = 1 | 
| +            elif k == 'shortgi': | 
| +                htcaps.add('[SHORT-GI-20]') | 
| +                htcaps.add('[SHORT-GI-40]') | 
| +            elif k == 'pureg': | 
| +                pass        # TODO(sleffler) need hostapd support | 
| +            elif k == 'puren': | 
| +                pass        # TODO(sleffler) need hostapd support | 
| +            elif k == 'protmode': | 
| +                pass        # TODO(sleffler) need hostapd support | 
| +            elif k == 'ht': | 
| +                htcaps.add('')  # NB: ensure 802.11n setup below | 
| +            elif k == 'htprotmode': | 
| +                pass        # TODO(sleffler) need hostapd support | 
| +            elif k == 'rifs': | 
| +                pass        # TODO(sleffler) need hostapd support | 
| +            elif k == 'wepmode': | 
| +                pass        # NB: meaningless for hostapd; ignore | 
| +            elif k == '-ampdu': | 
| +                pass        # TODO(sleffler) need hostapd support | 
| +            elif k == 'txpower': | 
| +                tx_power_params['power'] = v | 
| else: | 
| -                tx_power_params['interface'] = conf['interface'] | 
| +                conf[k] = v | 
|  | 
| -            # Configure transmit power | 
| -            self.set_txpower(tx_power_params) | 
| +        # Aggregate ht_capab. | 
| +        if htcaps: | 
| +            conf['ieee80211n'] = 1 | 
| +            conf['ht_capab'] = ''.join(htcaps) | 
|  | 
| -            logging.info("AP configured.") | 
| +        # Figure out the correct interface. | 
| +        if conf.get('hw_mode', 'b') == 'a': | 
| +            conf['interface'] = self.wlanif5 | 
| +        else: | 
| +            conf['interface'] = self.wlanif2 | 
| + | 
| +        # Generate hostapd.conf. | 
| +        self.router.run("cat <<EOF >%s\n%s\nEOF\n" % | 
| +            (self.hostapd['file'], '\n'.join( | 
| +            "%s=%s" % kv for kv in conf.iteritems()))) | 
| + | 
| +        if not multi_interface: | 
| +            logging.info("Initializing bridge...") | 
| +            self.router.run("%s addbr %s" % | 
| +                            (self.cmd_brctl, self.bridgeif)) | 
| +            self.router.run("%s setfd %s %d" % | 
| +                            (self.cmd_brctl, self.bridgeif, 0)) | 
| +            self.router.run("%s stp %s %d" % | 
| +                            (self.cmd_brctl, self.bridgeif, 0)) | 
| + | 
| +        # Run hostapd. | 
| +        logging.info("Starting hostapd...") | 
| +        self.router.run("%s -B %s" % | 
| +            (self.cmd_hostapd, self.hostapd['file'])) | 
| + | 
| + | 
| +        # Set up the bridge. | 
| +        if not multi_interface: | 
| +            logging.info("Setting up the bridge...") | 
| +            self.router.run("%s addif %s %s" % | 
| +                            (self.cmd_brctl, self.bridgeif, self.wiredif)) | 
| +            self.router.run("%s link set %s up" % | 
| +                            (self.cmd_ip, self.wiredif)) | 
| +            self.router.run("%s link set %s up" % | 
| +                            (self.cmd_ip, self.bridgeif)) | 
| +            self.hostapd['interface'] = conf['interface'] | 
| +        else: | 
| +            tx_power_params['interface'] = conf['interface'] | 
|  | 
| -#        else: | 
| -#            # use iw to manually configure interface | 
| +        # Configure transmit power | 
| +        self.set_txpower(tx_power_params) | 
| + | 
| +        logging.info("AP configured.") | 
|  | 
| self.hostapd['configured'] = True | 
|  | 
|  | 
| +    def station_config(self, params): | 
| +        multi_interface = 'multi_interface' in params | 
| +        if multi_interface: | 
| +            params.pop('multi_interface') | 
| +        elif self.station['configured'] or self.hostapd['configured']: | 
| +            self.deconfig({}) | 
| + | 
| +        interface = self.wlanif2 | 
| +        conf = self.station['conf'] | 
| +        for k, v in params.iteritems(): | 
| +            if k == 'ssid_suffix': | 
| +                conf['ssid'] = self.defssid + v | 
| +            elif k == 'channel': | 
| +                freq = int(v) | 
| +                if freq > 2484: | 
| +                    interface = self.wlanif5 | 
| +            elif k == 'mode': | 
| +                if v == '11a': | 
| +                    interface = self.wlanif5 | 
| +            else: | 
| +                conf[k] = v | 
| + | 
| +        if not multi_interface: | 
| +            logging.info("Initializing bridge...") | 
| +            self.router.run("%s addbr %s" % | 
| +                            (self.cmd_brctl, self.bridgeif)) | 
| +            self.router.run("%s setfd %s %d" % | 
| +                            (self.cmd_brctl, self.bridgeif, 0)) | 
| +            self.router.run("%s stp %s %d" % | 
| +                            (self.cmd_brctl, self.bridgeif, 0)) | 
| + | 
| +        # Run interface configuration commands | 
| +        for k, v in conf.iteritems(): | 
| +            if k != 'ssid': | 
| +                self.router.run("%s dev %s set %s %s" % | 
| +                                (self.cmd_iw, interface, k, v)) | 
| + | 
| +        # Connect the station | 
| +        self.router.run("%s link set %s up" % (self.cmd_ip, interface)) | 
| +        connect_cmd = ('ibss join' if self.station['type'] == 'ibss' | 
| +                       else 'connect') | 
| +        self.router.run("%s dev %s %s %s %d" % | 
| +                        (self.cmd_iw, interface, connect_cmd, | 
| +                         conf['ssid'], freq)) | 
| + | 
| +        # Add wireless interface to the bridge | 
| +        self.router.run("%s addif %s %s" % | 
| +                        (self.cmd_brctl, self.bridgeif, interface)) | 
| + | 
| +        # Add interface to the bridge. | 
| +        # Bring up the bridge | 
| +        if not multi_interface: | 
| +            logging.info("Setting up the bridge...") | 
| +            self.router.run("%s addif %s %s" % | 
| +                            (self.cmd_brctl, self.bridgeif, self.wiredif)) | 
| +            self.router.run("%s link set %s up" % | 
| +                            (self.cmd_ip, self.wiredif)) | 
| +            self.router.run("%s link set %s up" % | 
| +                            (self.cmd_ip, self.bridgeif)) | 
| + | 
| +        self.station['configured'] = True | 
| +        self.station['interface'] = interface | 
| + | 
| + | 
| +    def config(self, params): | 
| +        if self.apmode: | 
| +            self.hostap_config(params) | 
| +        else: | 
| +            self.station_config(params) | 
| + | 
| + | 
| def deconfig(self, params): | 
| """ De-configure the AP (will also bring wlan and the bridge down) """ | 
|  | 
| -        if not self.hostapd['configured']: | 
| +        if not self.hostapd['configured'] and not self.station['configured']: | 
| return | 
|  | 
| # Taking down hostapd takes wlan0 and mon.wlan0 down. | 
| -        self.router.run("pkill hostapd >/dev/null 2>&1", ignore_status=True) | 
| -#        self.router.run("rm -f %s" % self.hostapd['file']) | 
| +        if self.hostapd['configured']: | 
| +            self.router.run("pkill hostapd >/dev/null 2>&1", ignore_status=True) | 
| +#           self.router.run("rm -f %s" % self.hostapd['file']) | 
| +        if self.station['configured']: | 
| +            if self.station['type'] == 'ibss': | 
| +                self.router.run("%s dev %s ibss leave" % | 
| +                                (self.cmd_iw, self.station['interface'])) | 
| +            else: | 
| +                self.router.run("%s dev %s disconnect" % | 
| +                                (self.cmd_iw, self.station['interface'])) | 
| +            self.router.run("%s link set %s down" % (self.cmd_ip, | 
| +                                                     self.station['interface'])) | 
|  | 
| # Try a couple times to remove the bridge; hostapd may still be exiting | 
| for attempt in range(3): | 
| @@ -345,6 +428,7 @@ class LinuxRouter(object): | 
|  | 
|  | 
| self.hostapd['configured'] = False | 
| +        self.station['configured'] = False | 
|  | 
|  | 
| def get_ssid(self): | 
|  |