Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[feature] Added WiFi 6 client capability #492 #509

Merged
merged 4 commits into from
May 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 17 additions & 8 deletions openwisp_monitoring/device/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -352,15 +352,20 @@ def _get_boolean_html(self, value):
icon = static(f'admin/img/icon-{icon_type}.svg')
return mark_safe(f'<img src="{icon}">')

def ht(self, obj):
return self._get_boolean_html(obj.wifi_client.ht)
def he(self, obj):
return self._get_boolean_html(obj.wifi_client.he)

ht.short_description = 'HT'
he.short_description = 'WiFi 6 (802.11ax)'

def vht(self, obj):
return self._get_boolean_html(obj.wifi_client.vht)

vht.short_description = 'VHT'
vht.short_description = 'WiFi 5 (802.11ac)'

def ht(self, obj):
return self._get_boolean_html(obj.wifi_client.ht)

ht.short_description = 'WiFi 4 (802.11n)'

def wmm(self, obj):
return self._get_boolean_html(obj.wifi_client.wmm)
Expand Down Expand Up @@ -409,8 +414,9 @@ class WiFiSessionInline(WifiSessionAdminHelperMixin, admin.TabularInline):
'vendor',
'ssid',
'interface_name',
'ht',
'he',
'vht',
'ht',
'start_time',
'get_stop_time',
]
Expand Down Expand Up @@ -463,8 +469,9 @@ class WifiSessionAdmin(
'related_organization',
'related_device',
'ssid',
'ht',
'he',
'vht',
'ht',
'start_time',
'get_stop_time',
]
Expand All @@ -475,8 +482,9 @@ class WifiSessionAdmin(
'related_device',
'ssid',
'interface_name',
'ht',
'he',
'vht',
'ht',
'wmm',
'wds',
'wps',
Expand All @@ -499,8 +507,9 @@ def get_readonly_fields(self, request, obj=None):
'related_organization',
'mac_address',
'vendor',
'ht',
'he',
'vht',
'ht',
'wmm',
'wds',
'wps',
Expand Down
44 changes: 24 additions & 20 deletions openwisp_monitoring/device/base/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -183,27 +183,30 @@ def _transform_data(self):
for signal_key, signal_values in interface['mobile']['signal'].items():
for key, value in signal_values.items():
signal_values[key] = float(value)
# If HT/VHT is not being used ie. htmode = 'NOHT',
# set the HT/VHT field of WiFi clients to None.
# If HT/VHT/HE is not being used ie. htmode = 'NOHT',
# set the HT/VHT/HE field of WiFi clients to None.
# This is necessary because some clients may be
# VHT capable but VHT is not enabled at the radio level,
# which can mislead into thinking the client is not HT/VHT capable.
if (
'wireless' in interface
and 'htmode' in interface['wireless']
and 'clients' in interface['wireless']
):
for client in interface['wireless']['clients']:
# NOHT : disables 11n (ie. ht and vht both are False)
if interface['wireless']['htmode'] == 'NOHT':
client['ht'] = None
client['vht'] = None
# If only HT is enabled, set client vht to None
elif (
interface['wireless']['htmode'].startswith('HT')
and not client['vht']
):
client['vht'] = None
# which can mislead into thinking the client is not HT/VHT/HE capable.
wireless = interface.get('wireless')
if wireless and all(key in wireless for key in ('htmode', 'clients')):
for client in wireless['clients']:
htmode = wireless['htmode']
ht_enabled = htmode.startswith('HT')
vht_enabled = htmode.startswith('VHT')
noht_enabled = htmode == 'NOHT'
if noht_enabled:
client['ht'] = client['vht'] = None
# since 'he' field is optional
if 'he' in client:
Aryamanz29 marked this conversation as resolved.
Show resolved Hide resolved
client['he'] = None
elif ht_enabled:
if client['vht'] is False:
client['vht'] = None
if client.get('he') is False:
client['he'] = None
elif vht_enabled and client.get('he') is False:
client['he'] = None
# add mac vendor to wireless clients if present
if (
not mac_detection
Expand Down Expand Up @@ -371,8 +374,9 @@ class AbstractWifiClient(TimeStampedEditableModel):
help_text=_('MAC address'),
)
vendor = models.CharField(max_length=200, blank=True, null=True)
ht = models.BooleanField(null=True, blank=True, default=None, verbose_name='HT')
he = models.BooleanField(null=True, blank=True, default=None, verbose_name='HE')
vht = models.BooleanField(null=True, blank=True, default=None, verbose_name='VHT')
ht = models.BooleanField(null=True, blank=True, default=None, verbose_name='HT')
wmm = models.BooleanField(default=False, verbose_name='WMM')
wds = models.BooleanField(default=False, verbose_name='WDS')
wps = models.BooleanField(default=False, verbose_name='WPS')
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Generated by Django 3.2.18 on 2023-04-20 11:07

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('device_monitoring', '0006_alter_wificlient_field_ht_vht'),
]

operations = [
migrations.AddField(
model_name='wificlient',
name='he',
field=models.BooleanField(
blank=True, default=None, null=True, verbose_name='HE'
),
),
]
1 change: 1 addition & 0 deletions openwisp_monitoring/device/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,7 @@
"authorized": {"type": "boolean"},
"ht": {"type": "boolean"},
"vht": {"type": "boolean"},
"he": {"type": "boolean"},
"wds": {"type": "boolean"},
"wmm": {"type": "boolean"},
"wps": {"type": "boolean"},
Expand Down
2 changes: 1 addition & 1 deletion openwisp_monitoring/device/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ def trigger_device_checks(pk, recovery=True):

@shared_task(base=OpenwispCeleryTask)
def save_wifi_clients_and_sessions(device_data, device_pk):
_WIFICLIENT_FIELDS = ['vendor', 'ht', 'vht', 'wmm', 'wds', 'wps']
_WIFICLIENT_FIELDS = ['vendor', 'ht', 'vht', 'he', 'wmm', 'wds', 'wps']
WifiClient = load_model('device_monitoring', 'WifiClient')
WifiSession = load_model('device_monitoring', 'WifiSession')

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -401,11 +401,14 @@ <h2>{% trans 'Interface status' %}: {{ interface.name }}</h2>
{% trans 'Vendor' %}
</th>
{% endif %}
<th class="ht" title="{% trans 'High Throughput (802.11n)' %}">
HT
<th class="vht" title="{% trans 'High Efficiency (802.11ax)' %}">
WiFi 6 (802.11ax)
</th>
<th class="vht" title="{% trans 'Very High Throughput (802.11ac)' %}">
VHT
WiFi 5 (802.11ac)
</th>
<th class="ht" title="{% trans 'High Throughput (802.11n)' %}">
WiFi 4 (802.11n)
</th>
<th class="wmm" title="{% trans 'Wi-Fi Multimedia' %}">
WMM
Expand All @@ -426,11 +429,14 @@ <h2>{% trans 'Interface status' %}: {{ interface.name }}</h2>
{{ client.vendor }}
</td>
{% endif %}
<td class="ht">
<img src="{% get_static_prefix %}admin/img/icon-{{ client.ht|yesno:'yes,no,unknown' }}.svg">
<td class="he">
<img src="{% get_static_prefix %}admin/img/icon-{{ client.he|yesno:'yes,no,unknown' }}.svg">
</td>
<td class="vht">
<img src="{% get_static_prefix %}admin/img/icon-{{ client.vht|yesno:'yes,no,unknown' }}.svg">
<img src="{% get_static_prefix %}admin/img/icon-{{ client.vht|yesno:'yes,no,unknown' }}.svg">
</td>
<td class="ht">
<img src="{% get_static_prefix %}admin/img/icon-{{ client.ht|yesno:'yes,no,unknown' }}.svg">
</td>
<td class="wmm">
<img src="{% get_static_prefix %}admin/img/icon-{{ client.wmm|yesno:'yes,no,no' }}.svg">
Expand Down
45 changes: 21 additions & 24 deletions openwisp_monitoring/device/tests/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,30 +53,26 @@ def _create_device_monitoring(self):
return dm

def _transform_wireless_interface_test_data(self, data):
interfaces = data.get('interfaces', [])
wireless_interfaces = [
interface
for interface in interfaces
if 'wireless' in interface
and 'htmode' in interface['wireless']
and 'clients' in interface['wireless']
]
for interface in wireless_interfaces:
for client in interface['wireless']['clients']:
if (
interface['wireless']['htmode'] == 'NOHT'
and not client['ht']
and not client['vht']
):
client['ht'] = None
client['vht'] = None
elif (
interface['wireless']['htmode'].startswith('HT')
and client['ht']
and not client['vht']
):
client['vht'] = None

for interface in data.get('interfaces', []):
wireless = interface.get('wireless')
if wireless and all(key in wireless for key in ('htmode', 'clients')):
for client in wireless['clients']:
htmode = wireless['htmode']
ht_enabled = htmode.startswith('HT')
vht_enabled = htmode.startswith('VHT')
noht_enabled = htmode == 'NOHT'
if noht_enabled:
client['ht'] = client['vht'] = None
# since 'he' field is optional
if 'he' in client:
client['he'] = None
elif ht_enabled:
if client['vht'] is False:
client['vht'] = None
if client.get('he') is False:
client['he'] = None
elif vht_enabled and client.get('he') is False:
client['he'] = None
return data

def assertDataDict(self, dd_data, data):
Expand Down Expand Up @@ -247,6 +243,7 @@ def _data(self):
'assoc': True,
'authorized': True,
'vht': False,
'he': False,
'wmm': True,
'aid': 1,
'mfp': False,
Expand Down
Loading