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