Skip to content

Commit 444728b

Browse files
authored
Merge pull request #3656 from c-po/wireless-regdomain
wireless: T6318: move country-code to a system wide configuration
2 parents 2224890 + 9e22ab6 commit 444728b

File tree

11 files changed

+292
-43
lines changed

11 files changed

+292
-43
lines changed

data/config-mode-dependencies/vyos-1x.json

+3
Original file line numberDiff line numberDiff line change
@@ -59,5 +59,8 @@
5959
"wireguard": ["interfaces_wireguard"],
6060
"wireless": ["interfaces_wireless"],
6161
"wwan": ["interfaces_wwan"]
62+
},
63+
"system_wireless": {
64+
"wireless": ["interfaces_wireless"]
6265
}
6366
}

data/configd-include.json

+1
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@
102102
"system_task-scheduler.py",
103103
"system_timezone.py",
104104
"system_update-check.py",
105+
"system_wireless.py",
105106
"vpn_ipsec.py",
106107
"vpn_l2tp.py",
107108
"vpn_openconnect.py",
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
<!-- include start from include/version/interfaces-version.xml.i -->
2-
<syntaxVersion component='interfaces' version='32'></syntaxVersion>
2+
<syntaxVersion component='interfaces' version='33'></syntaxVersion>
33
<!-- include end -->

interface-definitions/interfaces_wireless.xml.in

-20
Original file line numberDiff line numberDiff line change
@@ -451,26 +451,6 @@
451451
</properties>
452452
<defaultValue>0</defaultValue>
453453
</leafNode>
454-
<leafNode name="country-code">
455-
<properties>
456-
<help>Indicate country in which device is operating</help>
457-
<completionHelp>
458-
<list>00 ad ae af ai al am an ar as at au aw az ba bb bd be bf bg bh bl bm bn bo br bs bt by bz ca cf ch ci cl cn co cr cu cx cy cz de dk dm do dz ec ee eg es et fi fm fr gb gd ge gf gh gl gp gr gt gu gy hk hn hr ht hu id ie il in ir is it jm jo jp ke kh kn kp kr kw ky kz lb lc li lk ls lt lu lv ma mc md me mf mh mk mn mo mp mq mr mt mu mv mw mx my ng ni nl no np nz om pa pe pf pg ph pk pl pm pr pt pw py qa re ro rs ru rw sa se sg si sk sn sr sv sy tc td tg th tn tr tt tw tz ua ug us uy uz vc ve vi vn vu wf ws ye yt za zw</list>
459-
</completionHelp>
460-
<valueHelp>
461-
<format>00</format>
462-
<description>World regulatory domain</description>
463-
</valueHelp>
464-
<valueHelp>
465-
<format>txt</format>
466-
<description>ISO/IEC 3166-1 Country Code</description>
467-
</valueHelp>
468-
<constraint>
469-
<regex>(00|ad|ae|af|ai|al|am|an|ar|as|at|au|aw|az|ba|bb|bd|be|bf|bg|bh|bl|bm|bn|bo|br|bs|bt|by|bz|ca|cf|ch|ci|cl|cn|co|cr|cu|cx|cy|cz|de|dk|dm|do|dz|ec|ee|eg|es|et|fi|fm|fr|gb|gd|ge|gf|gh|gl|gp|gr|gt|gu|gy|hk|hn|hr|ht|hu|id|ie|il|in|ir|is|it|jm|jo|jp|ke|kh|kn|kp|kr|kw|ky|kz|lb|lc|li|lk|ls|lt|lu|lv|ma|mc|md|me|mf|mh|mk|mn|mo|mp|mq|mr|mt|mu|mv|mw|mx|my|ng|ni|nl|no|np|nz|om|pa|pe|pf|pg|ph|pk|pl|pm|pr|pt|pw|py|qa|re|ro|rs|ru|rw|sa|se|sg|si|sk|sn|sr|sv|sy|tc|td|tg|th|tn|tr|tt|tw|tz|ua|ug|us|uy|uz|vc|ve|vi|vn|vu|wf|ws|ye|yt|za|zw)</regex>
470-
</constraint>
471-
<constraintErrorMessage>Invalid ISO/IEC 3166-1 Country Code</constraintErrorMessage>
472-
</properties>
473-
</leafNode>
474454
#include <include/generic-description.xml.i>
475455
#include <include/interface/dhcp-options.xml.i>
476456
#include <include/interface/dhcpv6-options.xml.i>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?xml version="1.0"?>
2+
<interfaceDefinition>
3+
<node name="system">
4+
<children>
5+
<node name="wireless" owner="${vyos_conf_scripts_dir}/system_wireless.py">
6+
<properties>
7+
<help>Wireless (IEEE-802.11) subsystem settings</help>
8+
<!-- must be before interface wireless, check /opt/vyatta/sbin/priority.pl -->
9+
<priority>317</priority>
10+
</properties>
11+
<children>
12+
<leafNode name="country-code">
13+
<properties>
14+
<help>Indicate country in which device is operating</help>
15+
<completionHelp>
16+
<list>00 ad ae af ai al am an ar as at au aw az ba bb bd be bf bg bh bl bm bn bo br bs bt by bz ca cf ch ci cl cn co cr cu cx cy cz de dk dm do dz ec ee eg es et fi fm fr gb gd ge gf gh gl gp gr gt gu gy hk hn hr ht hu id ie il in ir is it jm jo jp ke kh kn kp kr kw ky kz lb lc li lk ls lt lu lv ma mc md me mf mh mk mn mo mp mq mr mt mu mv mw mx my ng ni nl no np nz om pa pe pf pg ph pk pl pm pr pt pw py qa re ro rs ru rw sa se sg si sk sn sr sv sy tc td tg th tn tr tt tw tz ua ug us uy uz vc ve vi vn vu wf ws ye yt za zw</list>
17+
</completionHelp>
18+
<valueHelp>
19+
<format>00</format>
20+
<description>World regulatory domain</description>
21+
</valueHelp>
22+
<valueHelp>
23+
<format>txt</format>
24+
<description>ISO/IEC 3166-1 Country Code</description>
25+
</valueHelp>
26+
<constraint>
27+
<regex>(00|ad|ae|af|ai|al|am|an|ar|as|at|au|aw|az|ba|bb|bd|be|bf|bg|bh|bl|bm|bn|bo|br|bs|bt|by|bz|ca|cf|ch|ci|cl|cn|co|cr|cu|cx|cy|cz|de|dk|dm|do|dz|ec|ee|eg|es|et|fi|fm|fr|gb|gd|ge|gf|gh|gl|gp|gr|gt|gu|gy|hk|hn|hr|ht|hu|id|ie|il|in|ir|is|it|jm|jo|jp|ke|kh|kn|kp|kr|kw|ky|kz|lb|lc|li|lk|ls|lt|lu|lv|ma|mc|md|me|mf|mh|mk|mn|mo|mp|mq|mr|mt|mu|mv|mw|mx|my|ng|ni|nl|no|np|nz|om|pa|pe|pf|pg|ph|pk|pl|pm|pr|pt|pw|py|qa|re|ro|rs|ru|rw|sa|se|sg|si|sk|sn|sr|sv|sy|tc|td|tg|th|tn|tr|tt|tw|tz|ua|ug|us|uy|uz|vc|ve|vi|vn|vu|wf|ws|ye|yt|za|zw)</regex>
28+
</constraint>
29+
<constraintErrorMessage>Invalid ISO/IEC 3166-1 Country Code</constraintErrorMessage>
30+
</properties>
31+
</leafNode>
32+
</children>
33+
</node>
34+
</children>
35+
</node>
36+
</interfaceDefinition>

smoketest/config-tests/wireless-basic

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
set interfaces ethernet eth0 duplex 'auto'
2+
set interfaces ethernet eth0 speed 'auto'
3+
set interfaces ethernet eth1 duplex 'auto'
4+
set interfaces ethernet eth1 speed 'auto'
5+
set interfaces wireless wlan0 address '192.168.0.1/24'
6+
set interfaces wireless wlan0 channel '1'
7+
set interfaces wireless wlan0 mode 'n'
8+
set interfaces wireless wlan0 security wpa cipher 'CCMP'
9+
set interfaces wireless wlan0 security wpa mode 'wpa2'
10+
set interfaces wireless wlan0 security wpa passphrase '12345678'
11+
set interfaces wireless wlan0 ssid 'VyOS'
12+
set interfaces wireless wlan0 type 'access-point'
13+
set interfaces wireless wlan1 address '192.168.1.1/24'
14+
set interfaces wireless wlan1 channel '2'
15+
set interfaces wireless wlan1 mode 'n'
16+
set interfaces wireless wlan1 ssid 'VyOS-PUBLIC'
17+
set interfaces wireless wlan1 type 'access-point'
18+
set system config-management commit-revisions '200'
19+
set system console device ttyS0 speed 115200
20+
set system domain-name 'dev.vyos.net'
21+
set system host-name 'WR1'
22+
set system login user vyos authentication encrypted-password '$6$O5gJRlDYQpj$MtrCV9lxMnZPMbcxlU7.FI793MImNHznxGoMFgm3Q6QP3vfKJyOSRCt3Ka/GzFQyW1yZS4NS616NLHaIPPFHc0'
23+
set system wireless country-code 'es'
24+
set system syslog global facility all level 'info'
25+
set system syslog global facility local7 level 'debug'

smoketest/configs/wireless-basic

+66
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
interfaces {
2+
ethernet eth0 {
3+
duplex "auto"
4+
speed "auto"
5+
}
6+
ethernet eth1 {
7+
duplex "auto"
8+
speed "auto"
9+
}
10+
wireless wlan0 {
11+
address 192.168.0.1/24
12+
channel 1
13+
country-code es
14+
mode n
15+
security {
16+
wpa {
17+
cipher CCMP
18+
mode wpa2
19+
passphrase 12345678
20+
}
21+
}
22+
ssid VyOS
23+
type access-point
24+
}
25+
wireless wlan1 {
26+
address 192.168.1.1/24
27+
channel 2
28+
country-code de
29+
mode n
30+
ssid VyOS-PUBLIC
31+
type access-point
32+
}
33+
}
34+
system {
35+
config-management {
36+
commit-revisions "200"
37+
}
38+
console {
39+
device ttyS0 {
40+
speed 115200
41+
}
42+
}
43+
domain-name "dev.vyos.net"
44+
host-name "WR1"
45+
login {
46+
user vyos {
47+
authentication {
48+
encrypted-password "$6$O5gJRlDYQpj$MtrCV9lxMnZPMbcxlU7.FI793MImNHznxGoMFgm3Q6QP3vfKJyOSRCt3Ka/GzFQyW1yZS4NS616NLHaIPPFHc0"
49+
}
50+
}
51+
}
52+
syslog {
53+
global {
54+
facility all {
55+
level "info"
56+
}
57+
facility local7 {
58+
level "debug"
59+
}
60+
}
61+
}
62+
}
63+
64+
// Warning: Do not remove the following line.
65+
// vyos-config-version: "bgp@5:broadcast-relay@1:cluster@2:config-management@1:conntrack@5:conntrack-sync@2:container@2:dhcp-relay@2:dhcp-server@8:dhcpv6-server@1:dns-dynamic@4:dns-forwarding@4:firewall@15:flow-accounting@1:https@6:ids@1:interfaces@32:ipoe-server@3:ipsec@13:isis@3:l2tp@9:lldp@2:mdns@1:monitoring@1:nat@8:nat66@3:ntp@3:openconnect@3:ospf@2:pim@1:policy@8:pppoe-server@10:pptp@5:qos@2:quagga@11:reverse-proxy@1:rip@1:rpki@2:salt@1:snmp@3:ssh@2:sstp@6:system@27:vrf@3:vrrp@4:vyos-accel-ppp@2:wanloadbalance@3:webproxy@2"
66+
// Release version: 1.4.0

smoketest/scripts/cli/test_interfaces_wireless.py

+30-20
Original file line numberDiff line numberDiff line change
@@ -32,19 +32,31 @@ def get_config_value(interface, key):
3232
tmp = re.findall(f'{key}=+(.*)', tmp)
3333
return tmp[0]
3434

35+
wifi_cc_path = ['system', 'wireless', 'country-code']
36+
3537
class WirelessInterfaceTest(BasicInterfaceTest.TestCase):
3638
@classmethod
3739
def setUpClass(cls):
3840
cls._base_path = ['interfaces', 'wireless']
3941
cls._options = {
40-
'wlan0': ['physical-device phy0', 'ssid VyOS-WIFI-0',
41-
'type station', 'address 192.0.2.1/30'],
42-
'wlan1': ['physical-device phy0', 'ssid VyOS-WIFI-1', 'country-code se',
43-
'type access-point', 'address 192.0.2.5/30', 'channel 0'],
44-
'wlan10': ['physical-device phy1', 'ssid VyOS-WIFI-2',
45-
'type station', 'address 192.0.2.9/30'],
46-
'wlan11': ['physical-device phy1', 'ssid VyOS-WIFI-3', 'country-code se',
47-
'type access-point', 'address 192.0.2.13/30', 'channel 0'],
42+
'wlan0': ['physical-device phy0',
43+
'ssid VyOS-WIFI-0',
44+
'type station',
45+
'address 192.0.2.1/30'],
46+
'wlan1': ['physical-device phy0',
47+
'ssid VyOS-WIFI-1',
48+
'type access-point',
49+
'address 192.0.2.5/30',
50+
'channel 0'],
51+
'wlan10': ['physical-device phy1',
52+
'ssid VyOS-WIFI-2',
53+
'type station',
54+
'address 192.0.2.9/30'],
55+
'wlan11': ['physical-device phy1',
56+
'ssid VyOS-WIFI-3',
57+
'type access-point',
58+
'address 192.0.2.13/30',
59+
'channel 0'],
4860
}
4961
cls._interfaces = list(cls._options)
5062
# call base-classes classmethod
@@ -54,6 +66,8 @@ def setUpClass(cls):
5466
cls._test_ipv6 = False
5567
cls._test_vlan = False
5668

69+
cls.cli_set(cls, wifi_cc_path + ['es'])
70+
5771
def test_wireless_add_single_ip_address(self):
5872
# derived method to check if member interfaces are enslaved properly
5973
super().test_add_single_ip_address()
@@ -74,7 +88,6 @@ def test_wireless_hostapd_config(self):
7488
ssid = 'ssid'
7589

7690
self.cli_set(self._base_path + [interface, 'ssid', ssid])
77-
self.cli_set(self._base_path + [interface, 'country-code', 'se'])
7891
self.cli_set(self._base_path + [interface, 'type', 'access-point'])
7992

8093
# auto-powersave is special
@@ -150,7 +163,7 @@ def test_wireless_hostapd_wpa_config(self):
150163
# Only set the hostapd (access-point) options
151164
interface = 'wlan0'
152165
phy = 'phy0'
153-
ssid = 'ssid'
166+
ssid = 'VyOS-SMOKETEST'
154167
channel = '1'
155168
wpa_key = 'VyOSVyOSVyOS'
156169
mode = 'n'
@@ -160,21 +173,20 @@ def test_wireless_hostapd_wpa_config(self):
160173
self.cli_set(self._base_path + [interface, 'type', 'access-point'])
161174
self.cli_set(self._base_path + [interface, 'mode', mode])
162175

176+
# Country-Code must be set
177+
self.cli_delete(wifi_cc_path)
178+
with self.assertRaises(ConfigSessionError):
179+
self.cli_commit()
180+
self.cli_set(wifi_cc_path + [country])
181+
163182
# SSID must be set
164183
with self.assertRaises(ConfigSessionError):
165184
self.cli_commit()
166185
self.cli_set(self._base_path + [interface, 'ssid', ssid])
167186

168187
# Channel must be set
169-
with self.assertRaises(ConfigSessionError):
170-
self.cli_commit()
171188
self.cli_set(self._base_path + [interface, 'channel', channel])
172189

173-
# Country-Code must be set
174-
with self.assertRaises(ConfigSessionError):
175-
self.cli_commit()
176-
self.cli_set(self._base_path + [interface, 'country-code', country])
177-
178190
self.cli_set(self._base_path + [interface, 'security', 'wpa', 'mode', 'wpa2'])
179191
self.cli_set(self._base_path + [interface, 'security', 'wpa', 'passphrase', wpa_key])
180192

@@ -222,7 +234,6 @@ def test_wireless_access_point_bridge(self):
222234
self.cli_set(bridge_path + ['member', 'interface', interface])
223235

224236
self.cli_set(self._base_path + [interface, 'ssid', ssid])
225-
self.cli_set(self._base_path + [interface, 'country-code', 'se'])
226237
self.cli_set(self._base_path + [interface, 'type', 'access-point'])
227238

228239
self.cli_commit()
@@ -260,7 +271,6 @@ def test_wireless_security_station_address(self):
260271
deny_mac = ['00:00:00:00:de:01', '00:00:00:00:de:02', '00:00:00:00:de:03', '00:00:00:00:de:04']
261272

262273
self.cli_set(self._base_path + [interface, 'ssid', ssid])
263-
self.cli_set(self._base_path + [interface, 'country-code', 'se'])
264274
self.cli_set(self._base_path + [interface, 'type', 'access-point'])
265275
self.cli_set(self._base_path + [interface, 'security', 'station-address', 'mode', 'accept'])
266276

@@ -295,4 +305,4 @@ def test_wireless_security_station_address(self):
295305

296306
if __name__ == '__main__':
297307
check_kmod('mac80211_hwsim')
298-
unittest.main(verbosity=2)
308+
unittest.main(verbosity=2, failfast=True)

src/conf_mode/interfaces_wireless.py

+9-2
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@
4444
hostapd_accept_station_conf = '/run/hostapd/{ifname}_station_accept.conf'
4545
hostapd_deny_station_conf = '/run/hostapd/{ifname}_station_deny.conf'
4646

47+
country_code_path = ['system', 'wireless', 'country-code']
48+
4749
def find_other_stations(conf, base, ifname):
4850
"""
4951
Only one wireless interface per phy can be in station mode -
@@ -78,7 +80,11 @@ def get_config(config=None):
7880
conf = Config()
7981
base = ['interfaces', 'wireless']
8082

81-
ifname, wifi = get_interface_dict(conf, base)
83+
_, wifi = get_interface_dict(conf, base)
84+
85+
# retrieve global Wireless regulatory domain setting
86+
if conf.exists(country_code_path):
87+
wifi['country_code'] = conf.return_value(country_code_path)
8288

8389
if 'deleted' not in wifi:
8490
# then get_interface_dict provides default keys
@@ -131,7 +137,8 @@ def verify(wifi):
131137

132138
if wifi['type'] == 'access-point':
133139
if 'country_code' not in wifi:
134-
raise ConfigError('Wireless country-code is mandatory')
140+
raise ConfigError(f'Wireless country-code is mandatory, use: '\
141+
f'"set {" ".join(country_code_path)}"!')
135142

136143
if 'channel' not in wifi:
137144
raise ConfigError('Wireless channel must be configured!')

src/conf_mode/system_wireless.py

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
#!/usr/bin/env python3
2+
#
3+
# Copyright (C) 2024 VyOS maintainers and contributors
4+
#
5+
# This program is free software; you can redistribute it and/or modify
6+
# it under the terms of the GNU General Public License version 2 or later as
7+
# published by the Free Software Foundation.
8+
#
9+
# This program is distributed in the hope that it will be useful,
10+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
# GNU General Public License for more details.
13+
#
14+
# You should have received a copy of the GNU General Public License
15+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
16+
17+
from sys import exit
18+
19+
from vyos.config import Config
20+
from vyos.configdep import set_dependents
21+
from vyos.configdep import call_dependents
22+
from vyos import ConfigError
23+
from vyos import airbag
24+
airbag.enable()
25+
26+
def get_config(config=None):
27+
if config:
28+
conf = config
29+
else:
30+
conf = Config()
31+
base = ['system', 'wireless']
32+
interface_base = ['interfaces', 'wireless']
33+
34+
wireless = conf.get_config_dict(base, key_mangling=('-', '_'),
35+
get_first_key=True)
36+
37+
38+
if conf.exists(interface_base):
39+
wireless['interfaces'] = conf.list_nodes(interface_base)
40+
for interface in wireless['interfaces']:
41+
set_dependents('wireless', conf, interface)
42+
43+
return wireless
44+
45+
def verify(wireless):
46+
pass
47+
48+
def generate(wireless):
49+
pass
50+
51+
def apply(wireless):
52+
if 'interfaces' in wireless:
53+
call_dependents()
54+
pass
55+
56+
if __name__ == '__main__':
57+
try:
58+
c = get_config()
59+
verify(c)
60+
generate(c)
61+
apply(c)
62+
except ConfigError as e:
63+
print(e)
64+
exit(1)

0 commit comments

Comments
 (0)