1#   Copyright 2017 - The Android Open Source Project
2#
3#   Licensed under the Apache License, Version 2.0 (the "License");
4#   you may not use this file except in compliance with the License.
5#   You may obtain a copy of the License at
6#
7#       http://www.apache.org/licenses/LICENSE-2.0
8#
9#   Unless required by applicable law or agreed to in writing, software
10#   distributed under the License is distributed on an "AS IS" BASIS,
11#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12#   See the License for the specific language governing permissions and
13#   limitations under the License.
14
15from acts import utils
16
17import acts.controllers.ap_lib.third_party_ap_profiles.actiontec as actiontec
18import acts.controllers.ap_lib.third_party_ap_profiles.asus as asus
19import acts.controllers.ap_lib.third_party_ap_profiles.belkin as belkin
20import acts.controllers.ap_lib.third_party_ap_profiles.linksys as linksys
21import acts.controllers.ap_lib.third_party_ap_profiles.netgear as netgear
22import acts.controllers.ap_lib.third_party_ap_profiles.securifi as securifi
23import acts.controllers.ap_lib.third_party_ap_profiles.tplink as tplink
24
25from acts.controllers.ap_lib import hostapd_config
26from acts.controllers.ap_lib import hostapd_constants
27from acts.controllers.ap_lib import hostapd_utils
28
29
30def _get_or_default(var, default_value):
31    """Check variable and return non-null value.
32
33   Args:
34        var: Any variable.
35        default_value: Value to return if the var is None.
36
37   Returns:
38        Variable value if not None, default value otherwise.
39    """
40    return var if var is not None else default_value
41
42
43def create_ap_preset(profile_name='whirlwind',
44                     iface_wlan_2g=None,
45                     iface_wlan_5g=None,
46                     channel=None,
47                     mode=None,
48                     frequency=None,
49                     security=None,
50                     pmf_support=None,
51                     ssid=None,
52                     hidden=None,
53                     dtim_period=None,
54                     frag_threshold=None,
55                     rts_threshold=None,
56                     force_wmm=None,
57                     beacon_interval=None,
58                     short_preamble=None,
59                     n_capabilities=None,
60                     ac_capabilities=None,
61                     vht_bandwidth=None,
62                     bss_settings=[]):
63    """AP preset config generator.  This a wrapper for hostapd_config but
64       but supplies the default settings for the preset that is selected.
65
66        You may specify channel or frequency, but not both.  Both options
67        are checked for validity (i.e. you can't specify an invalid channel
68        or a frequency that will not be accepted).
69
70    Args:
71        profile_name: The name of the device want the preset for.
72                      Options: whirlwind
73        channel: int, channel number.
74        dtim: int, DTIM value of the AP, default is 2.
75        frequency: int, frequency of channel.
76        security: Security, the secuirty settings to use.
77        ssid: string, The name of the ssid to brodcast.
78        pmf_support: int, whether pmf is disabled, enabled, or required
79        vht_bandwidth: VHT bandwidth for 11ac operation.
80        bss_settings: The settings for all bss.
81        iface_wlan_2g: the wlan 2g interface name of the AP.
82        iface_wlan_5g: the wlan 5g interface name of the AP.
83        mode: The hostapd 802.11 mode of operation.
84        ssid: The ssid for the wireless network.
85        hidden: Whether to include the ssid in the beacons.
86        dtim_period: The dtim period for the BSS
87        frag_threshold: Max size of packet before fragmenting the packet.
88        rts_threshold: Max size of packet before requiring protection for
89            rts/cts or cts to self.
90        n_capabilities: 802.11n capabilities for for BSS to advertise.
91        ac_capabilities: 802.11ac capabilities for for BSS to advertise.
92
93    Returns: A hostapd_config object that can be used by the hostapd object.
94    """
95
96    # Verify interfaces
97    hostapd_utils.verify_interface(iface_wlan_2g,
98                                   hostapd_constants.INTERFACE_2G_LIST)
99    hostapd_utils.verify_interface(iface_wlan_5g,
100                                   hostapd_constants.INTERFACE_5G_LIST)
101
102    if channel:
103        frequency = hostapd_config.get_frequency_for_channel(channel)
104    elif frequency:
105        channel = hostapd_config.get_channel_for_frequency(frequency)
106    else:
107        raise ValueError('Specify either frequency or channel.')
108
109    if profile_name == 'whirlwind':
110        # profile indicates phy mode is 11bgn for 2.4Ghz or 11acn for 5Ghz
111        hidden = _get_or_default(hidden, False)
112        force_wmm = _get_or_default(force_wmm, True)
113        beacon_interval = _get_or_default(beacon_interval, 100)
114        short_preamble = _get_or_default(short_preamble, True)
115        dtim_period = _get_or_default(dtim_period, 2)
116        frag_threshold = _get_or_default(frag_threshold, 2346)
117        rts_threshold = _get_or_default(rts_threshold, 2347)
118        if frequency < 5000:
119            interface = iface_wlan_2g
120            mode = _get_or_default(mode, hostapd_constants.MODE_11N_MIXED)
121            n_capabilities = _get_or_default(n_capabilities, [
122                hostapd_constants.N_CAPABILITY_LDPC,
123                hostapd_constants.N_CAPABILITY_SGI20,
124                hostapd_constants.N_CAPABILITY_SGI40,
125                hostapd_constants.N_CAPABILITY_TX_STBC,
126                hostapd_constants.N_CAPABILITY_RX_STBC1,
127                hostapd_constants.N_CAPABILITY_DSSS_CCK_40
128            ])
129            config = hostapd_config.HostapdConfig(
130                ssid=ssid,
131                hidden=hidden,
132                security=security,
133                pmf_support=pmf_support,
134                interface=interface,
135                mode=mode,
136                force_wmm=force_wmm,
137                beacon_interval=beacon_interval,
138                dtim_period=dtim_period,
139                short_preamble=short_preamble,
140                frequency=frequency,
141                n_capabilities=n_capabilities,
142                frag_threshold=frag_threshold,
143                rts_threshold=rts_threshold,
144                bss_settings=bss_settings)
145        else:
146            interface = iface_wlan_5g
147            vht_bandwidth = _get_or_default(vht_bandwidth, 80)
148            mode = _get_or_default(mode, hostapd_constants.MODE_11AC_MIXED)
149            if hostapd_config.ht40_plus_allowed(channel):
150                extended_channel = hostapd_constants.N_CAPABILITY_HT40_PLUS
151            elif hostapd_config.ht40_minus_allowed(channel):
152                extended_channel = hostapd_constants.N_CAPABILITY_HT40_MINUS
153            # Channel 165 operates in 20MHz with n or ac modes.
154            if channel == 165:
155                mode = hostapd_constants.MODE_11N_MIXED
156                extended_channel = hostapd_constants.N_CAPABILITY_HT20
157            # Define the n capability vector for 20 MHz and higher bandwidth
158            if not vht_bandwidth:
159                pass
160            elif vht_bandwidth >= 40:
161                n_capabilities = _get_or_default(n_capabilities, [
162                    hostapd_constants.N_CAPABILITY_LDPC, extended_channel,
163                    hostapd_constants.N_CAPABILITY_SGI20,
164                    hostapd_constants.N_CAPABILITY_SGI40,
165                    hostapd_constants.N_CAPABILITY_TX_STBC,
166                    hostapd_constants.N_CAPABILITY_RX_STBC1
167                ])
168            else:
169                n_capabilities = _get_or_default(n_capabilities, [
170                    hostapd_constants.N_CAPABILITY_LDPC,
171                    hostapd_constants.N_CAPABILITY_SGI20,
172                    hostapd_constants.N_CAPABILITY_SGI40,
173                    hostapd_constants.N_CAPABILITY_TX_STBC,
174                    hostapd_constants.N_CAPABILITY_RX_STBC1,
175                    hostapd_constants.N_CAPABILITY_HT20
176                ])
177            ac_capabilities = _get_or_default(ac_capabilities, [
178                hostapd_constants.AC_CAPABILITY_MAX_MPDU_11454,
179                hostapd_constants.AC_CAPABILITY_RXLDPC,
180                hostapd_constants.AC_CAPABILITY_SHORT_GI_80,
181                hostapd_constants.AC_CAPABILITY_TX_STBC_2BY1,
182                hostapd_constants.AC_CAPABILITY_RX_STBC_1,
183                hostapd_constants.AC_CAPABILITY_MAX_A_MPDU_LEN_EXP7,
184                hostapd_constants.AC_CAPABILITY_RX_ANTENNA_PATTERN,
185                hostapd_constants.AC_CAPABILITY_TX_ANTENNA_PATTERN
186            ])
187            config = hostapd_config.HostapdConfig(
188                ssid=ssid,
189                hidden=hidden,
190                security=security,
191                pmf_support=pmf_support,
192                interface=interface,
193                mode=mode,
194                force_wmm=force_wmm,
195                vht_channel_width=vht_bandwidth,
196                beacon_interval=beacon_interval,
197                dtim_period=dtim_period,
198                short_preamble=short_preamble,
199                frequency=frequency,
200                frag_threshold=frag_threshold,
201                rts_threshold=rts_threshold,
202                n_capabilities=n_capabilities,
203                ac_capabilities=ac_capabilities,
204                bss_settings=bss_settings)
205    elif profile_name == 'whirlwind_11ab_legacy':
206        if frequency < 5000:
207            mode = hostapd_constants.MODE_11B
208        else:
209            mode = hostapd_constants.MODE_11A
210
211        config = create_ap_preset(iface_wlan_2g=iface_wlan_2g,
212                                  iface_wlan_5g=iface_wlan_5g,
213                                  ssid=ssid,
214                                  channel=channel,
215                                  mode=mode,
216                                  security=security,
217                                  pmf_support=pmf_support,
218                                  hidden=hidden,
219                                  force_wmm=force_wmm,
220                                  beacon_interval=beacon_interval,
221                                  short_preamble=short_preamble,
222                                  dtim_period=dtim_period,
223                                  rts_threshold=rts_threshold,
224                                  frag_threshold=frag_threshold,
225                                  n_capabilities=[],
226                                  ac_capabilities=[],
227                                  vht_bandwidth=None)
228    elif profile_name == 'whirlwind_11ag_legacy':
229        if frequency < 5000:
230            mode = hostapd_constants.MODE_11G
231        else:
232            mode = hostapd_constants.MODE_11A
233
234        config = create_ap_preset(iface_wlan_2g=iface_wlan_2g,
235                                  iface_wlan_5g=iface_wlan_5g,
236                                  ssid=ssid,
237                                  channel=channel,
238                                  mode=mode,
239                                  security=security,
240                                  pmf_support=pmf_support,
241                                  hidden=hidden,
242                                  force_wmm=force_wmm,
243                                  beacon_interval=beacon_interval,
244                                  short_preamble=short_preamble,
245                                  dtim_period=dtim_period,
246                                  rts_threshold=rts_threshold,
247                                  frag_threshold=frag_threshold,
248                                  n_capabilities=[],
249                                  ac_capabilities=[],
250                                  vht_bandwidth=None)
251    elif profile_name == 'mistral':
252        hidden = _get_or_default(hidden, False)
253        force_wmm = _get_or_default(force_wmm, True)
254        beacon_interval = _get_or_default(beacon_interval, 100)
255        short_preamble = _get_or_default(short_preamble, True)
256        dtim_period = _get_or_default(dtim_period, 2)
257        frag_threshold = None
258        rts_threshold = None
259
260        # Google IE
261        # Country Code IE ('us' lowercase)
262        vendor_elements = {
263            'vendor_elements':
264            'dd0cf4f5e80505ff0000ffffffff'
265            '070a75732024041e95051e00'
266        }
267        default_configs = {'bridge': 'br-lan', 'iapp_interface': 'br-lan'}
268
269        if frequency < 5000:
270            interface = iface_wlan_2g
271            mode = _get_or_default(mode, hostapd_constants.MODE_11N_MIXED)
272            n_capabilities = _get_or_default(n_capabilities, [
273                hostapd_constants.N_CAPABILITY_LDPC,
274                hostapd_constants.N_CAPABILITY_SGI20,
275                hostapd_constants.N_CAPABILITY_SGI40,
276                hostapd_constants.N_CAPABILITY_TX_STBC,
277                hostapd_constants.N_CAPABILITY_RX_STBC1,
278                hostapd_constants.N_CAPABILITY_DSSS_CCK_40
279            ])
280
281            additional_params = utils.merge_dicts(
282                vendor_elements, hostapd_constants.ENABLE_RRM_BEACON_REPORT,
283                hostapd_constants.ENABLE_RRM_NEIGHBOR_REPORT, default_configs)
284            config = hostapd_config.HostapdConfig(
285                ssid=ssid,
286                hidden=hidden,
287                security=security,
288                pmf_support=pmf_support,
289                interface=interface,
290                mode=mode,
291                force_wmm=force_wmm,
292                beacon_interval=beacon_interval,
293                dtim_period=dtim_period,
294                short_preamble=short_preamble,
295                frequency=frequency,
296                n_capabilities=n_capabilities,
297                frag_threshold=frag_threshold,
298                rts_threshold=rts_threshold,
299                bss_settings=bss_settings,
300                additional_parameters=additional_params,
301                set_ap_defaults_profile=profile_name)
302        else:
303            interface = iface_wlan_5g
304            vht_bandwidth = _get_or_default(vht_bandwidth, 80)
305            mode = _get_or_default(mode, hostapd_constants.MODE_11AC_MIXED)
306            if hostapd_config.ht40_plus_allowed(channel):
307                extended_channel = hostapd_constants.N_CAPABILITY_HT40_PLUS
308            elif hostapd_config.ht40_minus_allowed(channel):
309                extended_channel = hostapd_constants.N_CAPABILITY_HT40_MINUS
310            # Channel 165 operates in 20MHz with n or ac modes.
311            if channel == 165:
312                mode = hostapd_constants.MODE_11N_MIXED
313                extended_channel = hostapd_constants.N_CAPABILITY_HT20
314            if vht_bandwidth >= 40:
315                n_capabilities = _get_or_default(n_capabilities, [
316                    hostapd_constants.N_CAPABILITY_LDPC, extended_channel,
317                    hostapd_constants.N_CAPABILITY_SGI20,
318                    hostapd_constants.N_CAPABILITY_SGI40,
319                    hostapd_constants.N_CAPABILITY_TX_STBC,
320                    hostapd_constants.N_CAPABILITY_RX_STBC1
321                ])
322            else:
323                n_capabilities = _get_or_default(n_capabilities, [
324                    hostapd_constants.N_CAPABILITY_LDPC,
325                    hostapd_constants.N_CAPABILITY_SGI20,
326                    hostapd_constants.N_CAPABILITY_SGI40,
327                    hostapd_constants.N_CAPABILITY_TX_STBC,
328                    hostapd_constants.N_CAPABILITY_RX_STBC1,
329                    hostapd_constants.N_CAPABILITY_HT20
330                ])
331            ac_capabilities = _get_or_default(ac_capabilities, [
332                hostapd_constants.AC_CAPABILITY_MAX_MPDU_11454,
333                hostapd_constants.AC_CAPABILITY_RXLDPC,
334                hostapd_constants.AC_CAPABILITY_SHORT_GI_80,
335                hostapd_constants.AC_CAPABILITY_TX_STBC_2BY1,
336                hostapd_constants.AC_CAPABILITY_RX_STBC_1,
337                hostapd_constants.AC_CAPABILITY_MAX_A_MPDU_LEN_EXP7,
338                hostapd_constants.AC_CAPABILITY_RX_ANTENNA_PATTERN,
339                hostapd_constants.AC_CAPABILITY_TX_ANTENNA_PATTERN,
340                hostapd_constants.AC_CAPABILITY_SU_BEAMFORMER,
341                hostapd_constants.AC_CAPABILITY_SU_BEAMFORMEE,
342                hostapd_constants.AC_CAPABILITY_MU_BEAMFORMER,
343                hostapd_constants.AC_CAPABILITY_SOUNDING_DIMENSION_4,
344                hostapd_constants.AC_CAPABILITY_BF_ANTENNA_4
345            ])
346
347            additional_params = utils.merge_dicts(
348                vendor_elements, hostapd_constants.ENABLE_RRM_BEACON_REPORT,
349                hostapd_constants.ENABLE_RRM_NEIGHBOR_REPORT, default_configs)
350            config = hostapd_config.HostapdConfig(
351                ssid=ssid,
352                hidden=hidden,
353                security=security,
354                pmf_support=pmf_support,
355                interface=interface,
356                mode=mode,
357                force_wmm=force_wmm,
358                vht_channel_width=vht_bandwidth,
359                beacon_interval=beacon_interval,
360                dtim_period=dtim_period,
361                short_preamble=short_preamble,
362                frequency=frequency,
363                frag_threshold=frag_threshold,
364                rts_threshold=rts_threshold,
365                n_capabilities=n_capabilities,
366                ac_capabilities=ac_capabilities,
367                bss_settings=bss_settings,
368                additional_parameters=additional_params,
369                set_ap_defaults_profile=profile_name)
370    elif profile_name == 'actiontec_pk5000':
371        config = actiontec.actiontec_pk5000(iface_wlan_2g=iface_wlan_2g,
372                                            channel=channel,
373                                            ssid=ssid,
374                                            security=security)
375    elif profile_name == 'actiontec_mi424wr':
376        config = actiontec.actiontec_mi424wr(iface_wlan_2g=iface_wlan_2g,
377                                             channel=channel,
378                                             ssid=ssid,
379                                             security=security)
380    elif profile_name == 'asus_rtac66u':
381        config = asus.asus_rtac66u(iface_wlan_2g=iface_wlan_2g,
382                                   iface_wlan_5g=iface_wlan_5g,
383                                   channel=channel,
384                                   ssid=ssid,
385                                   security=security)
386    elif profile_name == 'asus_rtac86u':
387        config = asus.asus_rtac86u(iface_wlan_2g=iface_wlan_2g,
388                                   iface_wlan_5g=iface_wlan_5g,
389                                   channel=channel,
390                                   ssid=ssid,
391                                   security=security)
392    elif profile_name == 'asus_rtac5300':
393        config = asus.asus_rtac5300(iface_wlan_2g=iface_wlan_2g,
394                                    iface_wlan_5g=iface_wlan_5g,
395                                    channel=channel,
396                                    ssid=ssid,
397                                    security=security)
398    elif profile_name == 'asus_rtn56u':
399        config = asus.asus_rtn56u(iface_wlan_2g=iface_wlan_2g,
400                                  iface_wlan_5g=iface_wlan_5g,
401                                  channel=channel,
402                                  ssid=ssid,
403                                  security=security)
404    elif profile_name == 'asus_rtn66u':
405        config = asus.asus_rtn66u(iface_wlan_2g=iface_wlan_2g,
406                                  iface_wlan_5g=iface_wlan_5g,
407                                  channel=channel,
408                                  ssid=ssid,
409                                  security=security)
410    elif profile_name == 'belkin_f9k1001v5':
411        config = belkin.belkin_f9k1001v5(iface_wlan_2g=iface_wlan_2g,
412                                         channel=channel,
413                                         ssid=ssid,
414                                         security=security)
415    elif profile_name == 'linksys_ea4500':
416        config = linksys.linksys_ea4500(iface_wlan_2g=iface_wlan_2g,
417                                        iface_wlan_5g=iface_wlan_5g,
418                                        channel=channel,
419                                        ssid=ssid,
420                                        security=security)
421    elif profile_name == 'linksys_ea9500':
422        config = linksys.linksys_ea9500(iface_wlan_2g=iface_wlan_2g,
423                                        iface_wlan_5g=iface_wlan_5g,
424                                        channel=channel,
425                                        ssid=ssid,
426                                        security=security)
427    elif profile_name == 'linksys_wrt1900acv2':
428        config = linksys.linksys_wrt1900acv2(iface_wlan_2g=iface_wlan_2g,
429                                             iface_wlan_5g=iface_wlan_5g,
430                                             channel=channel,
431                                             ssid=ssid,
432                                             security=security)
433    elif profile_name == 'netgear_r7000':
434        config = netgear.netgear_r7000(iface_wlan_2g=iface_wlan_2g,
435                                       iface_wlan_5g=iface_wlan_5g,
436                                       channel=channel,
437                                       ssid=ssid,
438                                       security=security)
439    elif profile_name == 'netgear_wndr3400':
440        config = netgear.netgear_wndr3400(iface_wlan_2g=iface_wlan_2g,
441                                          iface_wlan_5g=iface_wlan_5g,
442                                          channel=channel,
443                                          ssid=ssid,
444                                          security=security)
445    elif profile_name == 'securifi_almond':
446        config = securifi.securifi_almond(iface_wlan_2g=iface_wlan_2g,
447                                          channel=channel,
448                                          ssid=ssid,
449                                          security=security)
450    elif profile_name == 'tplink_archerc5':
451        config = tplink.tplink_archerc5(iface_wlan_2g=iface_wlan_2g,
452                                        iface_wlan_5g=iface_wlan_5g,
453                                        channel=channel,
454                                        ssid=ssid,
455                                        security=security)
456    elif profile_name == 'tplink_archerc7':
457        config = tplink.tplink_archerc7(iface_wlan_2g=iface_wlan_2g,
458                                        iface_wlan_5g=iface_wlan_5g,
459                                        channel=channel,
460                                        ssid=ssid,
461                                        security=security)
462    elif profile_name == 'tplink_c1200':
463        config = tplink.tplink_c1200(iface_wlan_2g=iface_wlan_2g,
464                                     iface_wlan_5g=iface_wlan_5g,
465                                     channel=channel,
466                                     ssid=ssid,
467                                     security=security)
468    elif profile_name == 'tplink_tlwr940n':
469        config = tplink.tplink_tlwr940n(iface_wlan_2g=iface_wlan_2g,
470                                        channel=channel,
471                                        ssid=ssid,
472                                        security=security)
473    else:
474        raise ValueError('Invalid ap model specified (%s)' % profile_name)
475
476    return config
477