Skip to content

Commit

Permalink
wireless: T6318: move country-code to a system wide configuration
Browse files Browse the repository at this point in the history
Wireless devices are subject to regulations issued by authorities. For any
given AP or router, there will most likely be no case where one wireless NIC is
located in one country and another wireless NIC in the same device is located
in another country, resulting in different regulatory domains to apply to the
same box.

Currently, wireless regulatory domains in VyOS need to be configured per-NIC:
  set interfaces wireless wlan0 country-code us

This leads to several side-effects:
* When operating multiple WiFi NICs, they all can have different regulatory
  domains configured which might offend legislation.
* Some NICs need additional entries to /etc/modprobe.d/cfg80211.conf to apply
  regulatory domain settings, such as: "options cfg80211 ieee80211_regdom=US"
  This is true for the Compex WLE600VX. This setting cannot be done
  per-interface.

Migrate the first found wireless module country-code from the wireless
interface CLI to: "system wireless country-code"

(cherry picked from commit 9e22ab6)
  • Loading branch information
c-po committed Aug 23, 2024
1 parent de2bdd1 commit 549a16f
Show file tree
Hide file tree
Showing 10 changed files with 262 additions and 23 deletions.
3 changes: 3 additions & 0 deletions data/config-mode-dependencies/vyos-1x.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,5 +63,8 @@
"system_option": {
"ip": ["system_ip"],
"ipv6": ["system_ipv6"]
},
"system_wireless": {
"wireless": ["interfaces_wireless"]
}
}
1 change: 1 addition & 0 deletions data/configd-include.json
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@
"system_task-scheduler.py",
"system_timezone.py",
"system_update-check.py",
"system_wireless.py",
"vpn_ipsec.py",
"vpn_l2tp.py",
"vpn_openconnect.py",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
<!-- include start from include/version/interfaces-version.xml.i -->
<syntaxVersion component='interfaces' version='32'></syntaxVersion>
<syntaxVersion component='interfaces' version='33'></syntaxVersion>
<!-- include end -->
20 changes: 0 additions & 20 deletions interface-definitions/interfaces_wireless.xml.in
Original file line number Diff line number Diff line change
Expand Up @@ -570,26 +570,6 @@
</properties>
<defaultValue>0</defaultValue>
</leafNode>
<leafNode name="country-code">
<properties>
<help>Indicate country in which device is operating</help>
<completionHelp>
<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>
</completionHelp>
<valueHelp>
<format>00</format>
<description>World regulatory domain</description>
</valueHelp>
<valueHelp>
<format>txt</format>
<description>ISO/IEC 3166-1 Country Code</description>
</valueHelp>
<constraint>
<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>
</constraint>
<constraintErrorMessage>Invalid ISO/IEC 3166-1 Country Code</constraintErrorMessage>
</properties>
</leafNode>
#include <include/generic-description.xml.i>
#include <include/interface/dhcp-options.xml.i>
#include <include/interface/dhcpv6-options.xml.i>
Expand Down
36 changes: 36 additions & 0 deletions interface-definitions/system_wireless.xml.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?xml version="1.0"?>
<interfaceDefinition>
<node name="system">
<children>
<node name="wireless" owner="${vyos_conf_scripts_dir}/system_wireless.py">
<properties>
<help>Wireless (IEEE-802.11) subsystem settings</help>
<!-- must be before interface wireless, check /opt/vyatta/sbin/priority.pl -->
<priority>317</priority>
</properties>
<children>
<leafNode name="country-code">
<properties>
<help>Indicate country in which device is operating</help>
<completionHelp>
<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>
</completionHelp>
<valueHelp>
<format>00</format>
<description>World regulatory domain</description>
</valueHelp>
<valueHelp>
<format>txt</format>
<description>ISO/IEC 3166-1 Country Code</description>
</valueHelp>
<constraint>
<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>
</constraint>
<constraintErrorMessage>Invalid ISO/IEC 3166-1 Country Code</constraintErrorMessage>
</properties>
</leafNode>
</children>
</node>
</children>
</node>
</interfaceDefinition>
25 changes: 25 additions & 0 deletions smoketest/config-tests/wireless-basic
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
set interfaces ethernet eth0 duplex 'auto'
set interfaces ethernet eth0 speed 'auto'
set interfaces ethernet eth1 duplex 'auto'
set interfaces ethernet eth1 speed 'auto'
set interfaces wireless wlan0 address '192.168.0.1/24'
set interfaces wireless wlan0 channel '1'
set interfaces wireless wlan0 mode 'n'
set interfaces wireless wlan0 security wpa cipher 'CCMP'
set interfaces wireless wlan0 security wpa mode 'wpa2'
set interfaces wireless wlan0 security wpa passphrase '12345678'
set interfaces wireless wlan0 ssid 'VyOS'
set interfaces wireless wlan0 type 'access-point'
set interfaces wireless wlan1 address '192.168.1.1/24'
set interfaces wireless wlan1 channel '2'
set interfaces wireless wlan1 mode 'n'
set interfaces wireless wlan1 ssid 'VyOS-PUBLIC'
set interfaces wireless wlan1 type 'access-point'
set system config-management commit-revisions '200'
set system console device ttyS0 speed 115200
set system domain-name 'dev.vyos.net'
set system host-name 'WR1'
set system login user vyos authentication encrypted-password '$6$O5gJRlDYQpj$MtrCV9lxMnZPMbcxlU7.FI793MImNHznxGoMFgm3Q6QP3vfKJyOSRCt3Ka/GzFQyW1yZS4NS616NLHaIPPFHc0'
set system wireless country-code 'es'
set system syslog global facility all level 'info'
set system syslog global facility local7 level 'debug'
66 changes: 66 additions & 0 deletions smoketest/configs/wireless-basic
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
interfaces {
ethernet eth0 {
duplex "auto"
speed "auto"
}
ethernet eth1 {
duplex "auto"
speed "auto"
}
wireless wlan0 {
address 192.168.0.1/24
channel 1
country-code es
mode n
security {
wpa {
cipher CCMP
mode wpa2
passphrase 12345678
}
}
ssid VyOS
type access-point
}
wireless wlan1 {
address 192.168.1.1/24
channel 2
country-code de
mode n
ssid VyOS-PUBLIC
type access-point
}
}
system {
config-management {
commit-revisions "200"
}
console {
device ttyS0 {
speed 115200
}
}
domain-name "dev.vyos.net"
host-name "WR1"
login {
user vyos {
authentication {
encrypted-password "$6$O5gJRlDYQpj$MtrCV9lxMnZPMbcxlU7.FI793MImNHznxGoMFgm3Q6QP3vfKJyOSRCt3Ka/GzFQyW1yZS4NS616NLHaIPPFHc0"
}
}
}
syslog {
global {
facility all {
level "info"
}
facility local7 {
level "debug"
}
}
}
}

// Warning: Do not remove the following line.
// 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"
// Release version: 1.4.0
11 changes: 9 additions & 2 deletions src/conf_mode/interfaces_wireless.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@
hostapd_accept_station_conf = '/run/hostapd/{ifname}_station_accept.conf'
hostapd_deny_station_conf = '/run/hostapd/{ifname}_station_deny.conf'

country_code_path = ['system', 'wireless', 'country-code']

def find_other_stations(conf, base, ifname):
"""
Only one wireless interface per phy can be in station mode -
Expand Down Expand Up @@ -82,7 +84,11 @@ def get_config(config=None):
conf = Config()
base = ['interfaces', 'wireless']

ifname, wifi = get_interface_dict(conf, base)
_, wifi = get_interface_dict(conf, base)

# retrieve global Wireless regulatory domain setting
if conf.exists(country_code_path):
wifi['country_code'] = conf.return_value(country_code_path)

if 'deleted' not in wifi:
# then get_interface_dict provides default keys
Expand Down Expand Up @@ -149,7 +155,8 @@ def verify(wifi):

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

if 'channel' not in wifi:
raise ConfigError('Wireless channel must be configured!')
Expand Down
64 changes: 64 additions & 0 deletions src/conf_mode/system_wireless.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
#!/usr/bin/env python3
#
# Copyright (C) 2024 VyOS maintainers and contributors
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 or later as
# published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

from sys import exit

from vyos.config import Config
from vyos.configdep import set_dependents
from vyos.configdep import call_dependents
from vyos import ConfigError
from vyos import airbag
airbag.enable()

def get_config(config=None):
if config:
conf = config
else:
conf = Config()
base = ['system', 'wireless']
interface_base = ['interfaces', 'wireless']

wireless = conf.get_config_dict(base, key_mangling=('-', '_'),
get_first_key=True)


if conf.exists(interface_base):
wireless['interfaces'] = conf.list_nodes(interface_base)
for interface in wireless['interfaces']:
set_dependents('wireless', conf, interface)

return wireless

def verify(wireless):
pass

def generate(wireless):
pass

def apply(wireless):
if 'interfaces' in wireless:
call_dependents()
pass

if __name__ == '__main__':
try:
c = get_config()
verify(c)
generate(c)
apply(c)
except ConfigError as e:
print(e)
exit(1)
57 changes: 57 additions & 0 deletions src/migration-scripts/interfaces/32-to-33
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
#!/usr/bin/env python3
#
# Copyright (C) 2024 VyOS maintainers and contributors
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 or later as
# published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# T6318: WiFi country-code should be set system-wide instead of per-device

from sys import argv
from sys import exit
from vyos.configtree import ConfigTree

if len(argv) < 2:
print("Must specify file name!")
exit(1)

file_name = argv[1]
with open(file_name, 'r') as f:
config_file = f.read()

base = ['interfaces', 'wireless']

config = ConfigTree(config_file)
if not config.exists(base):
# Nothing to do
exit(0)

installed = False
for interface in config.list_nodes(base):
cc_path = base + [interface, 'country-code']
if config.exists(cc_path):
tmp = config.return_value(cc_path)
config.delete(cc_path)

# There can be only ONE wireless country-code per device, everything
# else makes no sense as a WIFI router can not operate in two
# different countries
if not installed:
config.set(['system', 'wireless', 'country-code'], value=tmp)
installed = True

try:
with open(file_name, 'w') as f:
f.write(config.to_string())
except OSError as e:
print(f'Failed to save the modified config: {e}')
exit(1)

0 comments on commit 549a16f

Please sign in to comment.