Skip to content

Commit 9dbbbf0

Browse files
codesankalppandafy
andauthored
[feature] Add support for new wireless radio syntax band #235
Closes #235 Co-authored-by: Gagan Deep <pandafy.dev@gmail.com>
1 parent 3238df8 commit 9dbbbf0

10 files changed

Lines changed: 1323 additions & 77 deletions

File tree

docs/source/backends/openwrt.rst

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1849,7 +1849,7 @@ Will be rendered as follows::
18491849
option channel '11'
18501850
option country 'IT'
18511851
option htmode 'HT20'
1852-
option hwmode '11g'
1852+
option band '2g'
18531853
option phy 'phy0'
18541854
option txpower '5'
18551855
option type 'mac80211'
@@ -1859,7 +1859,7 @@ Will be rendered as follows::
18591859
option country 'IT'
18601860
option disabled '0'
18611861
option htmode 'HT20'
1862-
option hwmode '11a'
1862+
option band '5g'
18631863
option phy 'phy1'
18641864
option txpower '4'
18651865
option type 'mac80211'
@@ -1868,8 +1868,8 @@ Automatic channel selection example
18681868
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
18691869

18701870
If you need to use the "automatic channel selection" feature of OpenWRT, you must set
1871-
the channel to ``0``. You must also set the ``hwmode`` property to tell OpenWRT which
1872-
band to use (11g for 2.4 Ghz, 11a for 5 GHz).
1871+
the channel to ``0``. You must also set the ``band`` property to tell OpenWRT which
1872+
band to use (``2g`` for 2.4 Ghz, ``5g`` for 5 GHz, ``6g`` for 6 GHz, ``60g`` for 60 GHz).
18731873

18741874
The following example sets "automatic channel selection" for two radios, the first radio uses
18751875
**802.11n** in the 2.4 GHz band, while the second uses **802.11ac** in the 5 GHz band.
@@ -1884,7 +1884,7 @@ The following example sets "automatic channel selection" for two radios, the fir
18841884
"driver": "mac80211",
18851885
"protocol": "802.11n",
18861886
"channel": 0, # 0 stands for auto
1887-
"hwmode": "11g", # must set this explicitly, 11g means 2.4 GHz band
1887+
"band": "2g", # must set this explicitly, 2g means 2.4 GHz band
18881888
"channel_width": 20
18891889
},
18901890
{
@@ -1893,9 +1893,9 @@ The following example sets "automatic channel selection" for two radios, the fir
18931893
"driver": "mac80211",
18941894
"protocol": "802.11ac",
18951895
"channel": 0, # 0 stands for auto
1896-
"hwmode": "11a", # must set this explicitly, 11a means 5 GHz band,
1897-
# but this is optional for "802.11ac" because it only
1898-
# support 5 GHz band.
1896+
"band": "5g", # must set this explicitly, 5g means 5 GHz band,
1897+
# but this is optional for "802.11ac" because it only
1898+
# support 5 GHz band.
18991899
"channel_width": 80
19001900
}
19011901
]
@@ -1908,14 +1908,14 @@ UCI output::
19081908
config wifi-device 'radio0'
19091909
option channel 'auto'
19101910
option htmode 'HT20'
1911-
option hwmode '11g'
1911+
option band '2g'
19121912
option phy 'phy0'
19131913
option type 'mac80211'
19141914

19151915
config wifi-device 'radio1'
19161916
option channel 'auto'
19171917
option htmode 'VHT80'
1918-
option hwmode '11a'
1918+
option band '5g'
19191919
option phy 'phy1'
19201920
option type 'mac80211'
19211921

@@ -1946,7 +1946,7 @@ UCI output::
19461946
config wifi-device 'radio0'
19471947
option channel '36'
19481948
option htmode 'VHT80'
1949-
option hwmode '11a'
1949+
option band '5g'
19501950
option phy 'phy0'
19511951
option type 'mac80211'
19521952

@@ -1977,7 +1977,7 @@ UCI output::
19771977
config wifi-device 'radio0'
19781978
option channel '36'
19791979
option htmode 'HE80'
1980-
option hwmode '11a'
1980+
option band '5g'
19811981
option phy 'phy0'
19821982
option type 'mac80211'
19831983

@@ -2596,7 +2596,7 @@ UCI output::
25962596
list ht_capab 'SMPS-STATIC'
25972597
list ht_capab 'SHORT-GI-20'
25982598
option htmode 'HT20'
2599-
option hwmode '11g'
2599+
option band '2g'
26002600
option phy 'phy0'
26012601
option type 'mac80211'
26022602

docs/source/general/basics.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -339,7 +339,7 @@ Will generater the following output::
339339
option country 'US'
340340
option disabled '0'
341341
option htmode 'HT20'
342-
option hwmode '11g'
342+
option band '2g'
343343
option phy 'phy0'
344344
option type 'mac80211'
345345

@@ -418,7 +418,7 @@ Will generater the following output::
418418
option country 'US'
419419
option disabled '0'
420420
option htmode 'HT20'
421-
option hwmode '11g'
421+
option band '2g'
422422
option phy 'phy0'
423423
option type 'mac80211'
424424

netjsonconfig/backends/openwrt/converters/radios.py

Lines changed: 80 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
from .... import channels
12
from ..schema import default_radio_driver
23
from .base import OpenWrtConverter
34

@@ -20,8 +21,7 @@ def __intermediate_radio(self, radio):
2021
radio['txpower'] = radio.pop('tx_power')
2122
# rename driver to type
2223
radio['type'] = radio.pop('driver', default_radio_driver)
23-
# determine hwmode option
24-
radio['hwmode'] = self.__intermediate_hwmode(radio)
24+
self.__set_intermediate_band(radio)
2525
# check if using channel 0, that means "auto"
2626
if radio['channel'] == 0:
2727
radio['channel'] = 'auto'
@@ -35,10 +35,78 @@ def __intermediate_radio(self, radio):
3535
radio['country'] = radio['country'].upper()
3636
return self.sorted_dict(radio)
3737

38+
def __set_intermediate_band(self, radio):
39+
if self.dsa:
40+
radio['band'] = self.__intermediate_band(radio)
41+
else:
42+
radio['hwmode'] = self.__intermediate_hwmode(radio)
43+
44+
def __intermediate_band(self, radio):
45+
"""
46+
Returns value for "band" option (introduced in OpenWrt 21)
47+
48+
Backward compatibility: If the configuration defines
49+
"hwmode" instead of "band", then the value for "band" is inferred
50+
from "hwmode".
51+
52+
If both "band" and "hwmode" are absent, then value for "band"
53+
is inferred from "protocal" or "channel".
54+
"""
55+
hwmode = radio.pop('hwmode', None)
56+
band = radio.pop('band', None)
57+
if band:
58+
return band
59+
if hwmode:
60+
return self.__intermediate_band_from_hwmode(hwmode)
61+
channel = radio.get('channel')
62+
protocol = radio.get('protocol')
63+
# Infer radio frequency from protocol if possible
64+
if protocol == '802.11ad':
65+
return '60g'
66+
elif protocol in ['802.11b', '802.11g']:
67+
return '2g'
68+
elif protocol in ['802.11a', '802.11ac']:
69+
return '5g'
70+
# Infer radio frequency from channel of the radio
71+
if channel in channels.channels_2ghz:
72+
return '2g'
73+
elif channel in channels.channels_5ghz:
74+
return '5g'
75+
elif channel in channels.channels_6ghz:
76+
return '6g'
77+
78+
def __intermediate_band_from_hwmode(self, hwmode):
79+
# Using "hwmode" we can only predict 2GHz and 5GHz radios.
80+
# Support for 802.11ax (2/5/6 GHz) and 802.11ad (60 GHz)
81+
# was added in OpenWrt 21.
82+
if hwmode == '11a':
83+
return '5g'
84+
elif hwmode in ['11b', '11g']:
85+
return '2g'
86+
3887
def __intermediate_hwmode(self, radio):
3988
"""
40-
possible return values are: 11a, 11b, 11g
89+
Returns value for "hwmode" option (OpenWrt < 21)
90+
91+
Backward compatibility: If the configuration defines
92+
"band" (introduced in OpenWrt 21) instead of "hwmode",
93+
then the value for "hwmode" is inferred from "band".
4194
"""
95+
hwmode = radio.pop('hwmode', None)
96+
band = radio.pop('band', None)
97+
if hwmode:
98+
return hwmode
99+
if band:
100+
# 802.11ax and 802.11ad were not supported in OpenWrt < 21.
101+
# Hence, we ignore "6g" and "60g" values.
102+
if band == '2g':
103+
if radio['protocol'] == '802.11b':
104+
return '11b'
105+
else:
106+
return '11g'
107+
elif band == '5g':
108+
return '11a'
109+
# Use protocol to infer "hwmode"
42110
protocol = radio['protocol']
43111
if protocol in ['802.11a', '802.11b', '802.11g']:
44112
# return 11a, 11b or 11g
@@ -97,14 +165,20 @@ def __netjson_protocol(self, radio):
97165
determines NetJSON protocol radio attribute
98166
"""
99167
htmode = radio.get('htmode')
100-
hwmode = radio.get('hwmode', None)
101168
if htmode.startswith('HT'):
102169
return '802.11n'
103170
elif htmode.startswith('VHT'):
104171
return '802.11ac'
105172
elif htmode.startswith('HE'):
106173
return '802.11ax'
107-
return '802.{0}'.format(hwmode)
174+
elif htmode == 'NONE':
175+
band = radio.get('band')
176+
if self.dsa and band:
177+
band_map = {'2g': '802.11g', '5g': '802.11a', '60g': '802.11ad'}
178+
return band_map[band]
179+
else:
180+
hwmode = radio.get('hwmode', None)
181+
return '802.{0}'.format(hwmode)
108182

109183
def __netjson_channel(self, radio):
110184
"""
@@ -114,7 +188,7 @@ def __netjson_channel(self, radio):
114188
return 0
115189
# delete hwmode because is needed
116190
# only when channel is auto
117-
del radio['hwmode']
191+
radio.pop('hwmode', None)
118192
return int(radio['channel'])
119193

120194
def __netjson_channel_width(self, radio):

netjsonconfig/backends/openwrt/openwrt.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from jsonschema.exceptions import ValidationError
2+
13
from ..base.backend import BaseBackend
24
from ..vxlan.vxlan_wireguard import VxlanWireguard
35
from ..wireguard.wireguard import Wireguard
@@ -139,3 +141,27 @@ def vxlan_wireguard_auto_client(cls, **kwargs):
139141
}
140142
config['interfaces'].append(vxlan_interface)
141143
return config
144+
145+
def validate(self):
146+
self._validate_radios()
147+
super().validate()
148+
149+
def _validate_radios(self):
150+
# We use "hwmode" or "band" property of "radio" configuration
151+
# to predict the radio frequency. If both of these
152+
# properties are absent from the configuration, then channels
153+
# are used to predict the radio frequency. If the channel is
154+
# set to "auto" (0) in the configuration, then netjsonconfig
155+
# cannot predict the radio frequency. Thus, raises an error.
156+
for radio in self.config.get('radios', []):
157+
if radio['protocol'] not in ['802.11n', '802.11ax']:
158+
continue
159+
if (
160+
radio.get('band') is None
161+
and radio.get('hwmode') is None
162+
and radio.get('channel') == 0
163+
):
164+
raise ValidationError(
165+
'"channel" cannot be set to "auto" when'
166+
' "hwmode" or "band" property is not configured.'
167+
)

netjsonconfig/backends/openwrt/schema.py

Lines changed: 81 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -601,8 +601,8 @@
601601
"propertyOrder": 8,
602602
"default": "11g",
603603
"enum": ["11g"],
604-
}
605-
}
604+
},
605+
},
606606
},
607607
"radio_hwmode_11a": {
608608
"properties": {
@@ -614,22 +614,95 @@
614614
"default": "11a",
615615
"enum": ["11a"],
616616
}
617-
}
617+
},
618+
},
619+
"radio_2g_band": {
620+
"properties": {
621+
"band": {
622+
"type": "string",
623+
"title": "band",
624+
"readOnly": True,
625+
"propertyOrder": 9,
626+
"default": "2g",
627+
"enum": ["2g"],
628+
}
629+
},
630+
},
631+
"radio_5g_band": {
632+
"properties": {
633+
"band": {
634+
"type": "string",
635+
"title": "band",
636+
"readOnly": True,
637+
"propertyOrder": 9,
638+
"default": "5g",
639+
"enum": ["5g"],
640+
}
641+
},
642+
},
643+
"radio_6g_band": {
644+
"properties": {
645+
"band": {
646+
"type": "string",
647+
"title": "band",
648+
"readOnly": True,
649+
"propertyOrder": 9,
650+
"default": "6g",
651+
"enum": ["6g"],
652+
}
653+
},
654+
},
655+
"radio_60g_band": {
656+
"properties": {
657+
"band": {
658+
"type": "string",
659+
"title": "band",
660+
"readOnly": True,
661+
"propertyOrder": 8,
662+
"default": "60g",
663+
"enum": ["60g"],
664+
}
665+
},
618666
},
619667
"radio_80211gn_settings": {
620-
"allOf": [{"$ref": "#/definitions/radio_hwmode_11g"}]
668+
"allOf": [
669+
{"$ref": "#/definitions/radio_hwmode_11g"},
670+
{"$ref": "#/definitions/radio_2g_band"},
671+
]
621672
},
622673
"radio_80211an_settings": {
623-
"allOf": [{"$ref": "#/definitions/radio_hwmode_11a"}]
674+
"allOf": [
675+
{"$ref": "#/definitions/radio_hwmode_11a"},
676+
{"$ref": "#/definitions/radio_5g_band"},
677+
]
624678
},
625679
"radio_80211ac_5ghz_settings": {
626-
"allOf": [{"$ref": "#/definitions/radio_hwmode_11a"}]
680+
"allOf": [
681+
{"$ref": "#/definitions/radio_hwmode_11a"},
682+
{"$ref": "#/definitions/radio_5g_band"},
683+
]
627684
},
628685
"radio_80211ax_2ghz_settings": {
629-
"allOf": [{"$ref": "#/definitions/radio_hwmode_11g"}]
686+
"allOf": [
687+
{"$ref": "#/definitions/radio_hwmode_11g"},
688+
{"$ref": "#/definitions/radio_2g_band"},
689+
]
630690
},
631691
"radio_80211ax_5ghz_settings": {
632-
"allOf": [{"$ref": "#/definitions/radio_hwmode_11a"}]
692+
"allOf": [
693+
{"$ref": "#/definitions/radio_hwmode_11a"},
694+
{"$ref": "#/definitions/radio_5g_band"},
695+
]
696+
},
697+
"radio_80211ax_6ghz_settings": {
698+
"allOf": [
699+
{"$ref": "#/definitions/radio_6g_band"},
700+
]
701+
},
702+
"radio_80211ad_60ghz_settings": {
703+
"allOf": [
704+
{"$ref": "#/definitions/radio_60g_band"},
705+
]
633706
},
634707
},
635708
"properties": {

netjsonconfig/channels.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,7 @@
88
)
99
channels_2and5 = list(channels_2ghz + channels_5ghz)
1010
channels_5ghz.insert(0, 0)
11+
channels_6ghz = list(range(37, 69, 4)) + list(range(101, 149, 4))
12+
channels_60ghz = (
13+
list(range(1, 7)) + list(range(9, 14)) + list(range(17, 21)) + list(range(25, 28))
14+
)

0 commit comments

Comments
 (0)