mirror of
https://github.com/kernelkit/infix.git
synced 2026-07-30 12:33:02 +02:00
Merge pull request #1058 from kernelkit/wifi-support
This commit is contained in:
@@ -78,7 +78,7 @@ config QEMU_MACHINE
|
||||
|
||||
config QEMU_MACHINE_RAM
|
||||
string "RAM size (k/M/G)"
|
||||
default "384M"
|
||||
default "448M"
|
||||
help
|
||||
The default, 384 MiB, works for most configurations. However,
|
||||
if you get kernel panic with: "System is deadlocked on memory",
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
service name:wpa_supplicant :%i \
|
||||
[2345] wpa_supplicant -s -i %i -c /etc/wpa_supplicant-%i.conf -P/var/run/wpa_supplicant-%i.pid \
|
||||
-- WPA supplicant @%i
|
||||
|
||||
task name:wifi-scanner :%i [2345] <pid/wpa_supplicant:%i> /usr/libexec/infix/wifi-scanner %i -- Start scanning for SSID @ %i
|
||||
@@ -0,0 +1 @@
|
||||
SUBSYSTEM=="net", ACTION=="add", TEST=="/sys/class/net/$name/wireless", NAME="wifi%n"
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
#!/bin/sh
|
||||
|
||||
if [ $# -ne 1 ]; then
|
||||
echo "usage: $0 <ifname>"
|
||||
exit 1
|
||||
fi
|
||||
ifname=$1
|
||||
|
||||
TIMEOUT=300
|
||||
status=$(wpa_cli -i $ifname scan)
|
||||
while [ "$status" != "OK" ]; do
|
||||
status=$(wpa_cli -i $ifname scan)
|
||||
TIMEOUT=$((TIMEOUT-1))
|
||||
[ $TIMEOUT -eq 0 ] && logger -t wifi-scanner "Failed to start scanning $ifname" && exit 1
|
||||
sleep 0.5
|
||||
done
|
||||
@@ -165,6 +165,8 @@ BR2_PACKAGE_PODMAN_DRIVER_VFS=y
|
||||
BR2_PACKAGE_TETRIS=y
|
||||
BR2_PACKAGE_ROUSETTE=y
|
||||
BR2_PACKAGE_RAUC_INSTALLATION_STATUS=y
|
||||
BR2_PACKAGE_FEATURE_WIFI=y
|
||||
BR2_PACKAGE_FEATURE_WIFI_DONGLE_REALTEK=y
|
||||
BR2_PACKAGE_HOST_PYTHON_YANGDOC=y
|
||||
BR2_DOWNLOAD_FORCE_CHECK_HASHES=y
|
||||
BR2_PACKAGE_GETENT=y
|
||||
|
||||
@@ -167,6 +167,8 @@ BR2_PACKAGE_PODMAN_DRIVER_VFS=y
|
||||
BR2_PACKAGE_TETRIS=y
|
||||
BR2_PACKAGE_ROUSETTE=y
|
||||
BR2_PACKAGE_RAUC_INSTALLATION_STATUS=y
|
||||
BR2_PACKAGE_FEATURE_WIFI=y
|
||||
BR2_PACKAGE_FEATURE_WIFI_DONGLE_REALTEK=y
|
||||
BR2_PACKAGE_HOST_PYTHON_YANGDOC=y
|
||||
BR2_DOWNLOAD_FORCE_CHECK_HASHES=y
|
||||
BR2_PACKAGE_GETENT=y
|
||||
|
||||
+11
-1
@@ -3,11 +3,21 @@ Change Log
|
||||
|
||||
All notable changes to the project are documented in this file.
|
||||
|
||||
[v25.05.1][] - 2025-06-12
|
||||
[v25.06.0][UNRELEASED] -
|
||||
-------------------------
|
||||
|
||||
### Changes
|
||||
- Upgrade Linux kernel to 6.12.33 (LTS)
|
||||
- Add Wi-Fi client support and add support for some USB-Wi-Fi cards
|
||||
|
||||
### Fixes
|
||||
|
||||
|
||||
[v25.05.1][] - 2025-06-12
|
||||
-------------------------
|
||||
|
||||
### Changes
|
||||
- Upgrade Linux kernel to 6.12.32 (LTS)
|
||||
|
||||
### Fixes
|
||||
- Fix #1060: Restore of missing CLI commands, regression in Infix v25.05.0
|
||||
|
||||
+152
@@ -0,0 +1,152 @@
|
||||
# Wi-Fi (Wireless LAN)
|
||||
|
||||
Infix includes built-in Wi-Fi client support for connecting to
|
||||
wireless networks. When a compatible Wi-Fi adapter is detected, the
|
||||
system automatically begins scanning for available networks.
|
||||
|
||||
## Current Limitations
|
||||
|
||||
- Only client mode is supported (no access point functionality)
|
||||
- USB hotplug is not supported - adapters must be present at boot
|
||||
- Interface naming may be inconsistent with multiple USB Wi-Fi adapters
|
||||
|
||||
## Supported Wi-Fi Adapters
|
||||
|
||||
Wi-Fi support is primarily tested with Realtek chipset-based adapters.
|
||||
|
||||
### Known Working Chipsets
|
||||
|
||||
- RTL8821CU
|
||||
- Other Realtek chipsets may work but are not guaranteed
|
||||
|
||||
|
||||
> [!NOTE] Some Realtek chipsets require proprietary drivers not included in the standard kernel
|
||||
> Firmware requirements vary by chipset
|
||||
> Check kernel logs if your adapter is not detected
|
||||
|
||||
## Configuration
|
||||
|
||||
Add a supported Wi-Fi network device. To verify that it has been
|
||||
detected, look for `wifi0` in `show interfaces`
|
||||
|
||||
```
|
||||
admin@example:/> show interfaces
|
||||
INTERFACE PROTOCOL STATE DATA
|
||||
lo loopback UP
|
||||
ipv4 127.0.0.1/8 (static)
|
||||
ipv6 ::1/128 (static)
|
||||
e1 ethernet UP 02:00:00:00:00:01
|
||||
ipv6 fe80::ff:fe00:1/64 (link-layer)
|
||||
ipv6 fec0::ff:fe00:1/64 (link-layer)
|
||||
wifi0 ethernet DOWN f0:09:0d:36:5f:86
|
||||
wifi ssid: ------, signal: ------
|
||||
|
||||
```
|
||||
Add the new Wi-Fi interface to the configuration to start scanning.
|
||||
```
|
||||
admin@example:/config/> set interface wifi0
|
||||
admin@example:/config/> leave
|
||||
```
|
||||
Now the system will now start scanning in the background. To
|
||||
see the result read the operational datastore for interface `wifi0` or
|
||||
use the CLI
|
||||
|
||||
```
|
||||
admin@infix-00-00-00:/> show interfaces name wifi0
|
||||
name : wifi0
|
||||
type : wifi
|
||||
index : 3
|
||||
mtu : 1500
|
||||
operational status : down
|
||||
physical address : f0:09:0d:36:5f:86
|
||||
ipv4 addresses :
|
||||
ipv6 addresses :
|
||||
SSID : ----
|
||||
Signal : ----
|
||||
|
||||
SSID ENCRYPTION SIGNAL
|
||||
ssid1 WPA2-Personal excellent
|
||||
ssid2 WPA2-Personal excellent
|
||||
ssid3 WPA2-Personal excellent
|
||||
ssid4 WPA2-Personal good
|
||||
ssid5 WPA2-Personal good
|
||||
ssid6 WPA2-Personal good
|
||||
```
|
||||
|
||||
In the CLI, signal strength is reported as: excellent, good, poor or
|
||||
bad. For precise values, use NETCONF or RESTCONF, where the RSSI (in
|
||||
dBm) is available in the operational datastore.
|
||||
|
||||
Configure your Wi-Fi secret in the keystore, it should be between 8
|
||||
and 63 characters
|
||||
|
||||
```
|
||||
admin@example:/> configure
|
||||
admin@example:/config/> edit keystore symmetric-key example
|
||||
admin@example:/config/keystore/symmetric-key/example/> set key-format wifi-preshared-key-format
|
||||
admin@example:/config/keystore/symmetric-key/example/> set cleartext-key mysecret
|
||||
admin@example:/config/keystore/symmetric-key/example/> leave
|
||||
admin@example:/>
|
||||
```
|
||||
|
||||
Configure the Wi-Fi settings, set secret to the name selected above
|
||||
for the symmetric key, in this case `example`.
|
||||
|
||||
WPA2 or WPA3 encryption will be automatically selected based on what
|
||||
the access point supports. No manual selection is required unless
|
||||
connecting to an open network. No support for certificate based
|
||||
authentication yet.
|
||||
|
||||
Unencrypted network is also supported, to connect to an unencrypted
|
||||
network (generally not recommended):
|
||||
```
|
||||
admin@example:/config/interface/wifi0/> set wifi encryption disabled
|
||||
```
|
||||
|
||||
A valid `country-code` is also required for regulatory compliance, the
|
||||
valid codes are documented in the YANG model `infix-wifi-country-codes`
|
||||
|
||||
|
||||
```
|
||||
admin@example:/> configure
|
||||
admin@example:/config/> edit interface wifi0
|
||||
admin@example:/config/interface/wifi0/>
|
||||
admin@example:/config/interface/wifi0/> set wifi ssid ssid1
|
||||
admin@example:/config/interface/wifi0/> set wifi secret example
|
||||
admin@example:/config/interface/wifi0/> set wifi country-code SE
|
||||
admin@example:/config/interface/wifi0/> leave
|
||||
```
|
||||
|
||||
The Wi-Fi negotiation should now start immediately, provided that the
|
||||
SSID and pre-shared key are correct. You can verify the connection by
|
||||
running `show interfaces` again.
|
||||
|
||||
|
||||
```
|
||||
admin@example:/> show interfaces
|
||||
INTERFACE PROTOCOL STATE DATA
|
||||
lo loopback UP
|
||||
ipv4 127.0.0.1/8 (static)
|
||||
ipv6 ::1/128 (static)
|
||||
e1 ethernet UP 02:00:00:00:00:01
|
||||
ipv6 fe80::ff:fe00:1/64 (link-layer)
|
||||
ipv6 fec0::ff:fe00:1/64 (link-layer)
|
||||
wifi0 ethernet UP f0:09:0d:36:5f:86
|
||||
wifi ssid: ssid1, signal: excellent
|
||||
|
||||
admin@example:/>
|
||||
```
|
||||
|
||||
## Troubleshooting Connection Issues
|
||||
|
||||
Use `show wifi scan wifi0` and `show interfaces` to verify signal strength
|
||||
and connection status. If issues arise, try the following
|
||||
troubleshooting steps:
|
||||
|
||||
1. **Verify signal strength**: Check that the target network shows "good" or "excellent" signal
|
||||
2. **Check credentials**: Verify the preshared key in `ietf-keystore`
|
||||
3. **Review logs**: Check system logs with `show log` for Wi-Fi related errors
|
||||
4. **Regulatory compliance**: Ensure the country-code matches your location
|
||||
5. **Hardware detection**: Confirm the adapter appears in `show interfaces`
|
||||
|
||||
If issues persist, check the system log for specific error messages that can help identify the root cause.
|
||||
+1
-1
@@ -2,6 +2,7 @@ menu "Packages"
|
||||
|
||||
comment "Hardware Support"
|
||||
source "$BR2_EXTERNAL_INFIX_PATH/package/board/Config.in"
|
||||
source "$BR2_EXTERNAL_INFIX_PATH/package/feature-wifi/Config.in"
|
||||
|
||||
comment "Software Packages"
|
||||
source "$BR2_EXTERNAL_INFIX_PATH/package/bin/Config.in"
|
||||
@@ -42,5 +43,4 @@ source "$BR2_EXTERNAL_INFIX_PATH/package/rousette/Config.in"
|
||||
source "$BR2_EXTERNAL_INFIX_PATH/package/nghttp2-asio/Config.in"
|
||||
source "$BR2_EXTERNAL_INFIX_PATH/package/date-cpp/Config.in"
|
||||
source "$BR2_EXTERNAL_INFIX_PATH/package/rauc-installation-status/Config.in"
|
||||
|
||||
endmenu
|
||||
|
||||
@@ -25,6 +25,11 @@ else
|
||||
CONFD_CONF_OPTS += --disable-containers
|
||||
endif
|
||||
|
||||
ifeq ($(BR2_PACKAGE_FEATURE_WIFI),y)
|
||||
CONFD_CONF_OPTS += --enable-wifi
|
||||
else
|
||||
CONFD_CONF_OPTS += --disable-wifi
|
||||
endif
|
||||
define CONFD_INSTALL_EXTRA
|
||||
for fn in confd.conf resolvconf.conf; do \
|
||||
cp $(CONFD_PKGDIR)/$$fn $(FINIT_D)/available/; \
|
||||
@@ -69,6 +74,12 @@ define CONFD_INSTALL_YANG_MODULES_CONTAINERS
|
||||
$(BR2_EXTERNAL_INFIX_PATH)/utils/srload $(@D)/yang/containers.inc
|
||||
endef
|
||||
endif
|
||||
ifeq ($(BR2_PACKAGE_FEATURE_WIFI),y)
|
||||
define CONFD_INSTALL_YANG_MODULES_WIFI
|
||||
$(COMMON_SYSREPO_ENV) \
|
||||
$(BR2_EXTERNAL_INFIX_PATH)/utils/srload $(@D)/yang/wifi.inc
|
||||
endef
|
||||
endif
|
||||
|
||||
# PER_PACKAGE_DIR
|
||||
# Since the last package in the dependency chain that runs sysrepoctl is confd, we need to
|
||||
@@ -97,6 +108,7 @@ CONFD_PRE_BUILD_HOOKS += CONFD_CLEANUP
|
||||
CONFD_POST_INSTALL_TARGET_HOOKS += CONFD_INSTALL_EXTRA
|
||||
CONFD_POST_INSTALL_TARGET_HOOKS += CONFD_INSTALL_YANG_MODULES
|
||||
CONFD_POST_INSTALL_TARGET_HOOKS += CONFD_INSTALL_YANG_MODULES_CONTAINERS
|
||||
CONFD_POST_INSTALL_TARGET_HOOKS += CONFD_INSTALL_YANG_MODULES_WIFI
|
||||
CONFD_POST_INSTALL_TARGET_HOOKS += CONFD_INSTALL_IN_ROMFS
|
||||
CONFD_TARGET_FINALIZE_HOOKS += CONFD_CLEANUP
|
||||
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
config BR2_PACKAGE_FEATURE_WIFI
|
||||
bool "Feature Wi-Fi"
|
||||
select BR2_PACKAGE_WPA_SUPPLICANT
|
||||
select BR2_PACKAGE_WPA_SUPPLICANT_WPA3
|
||||
select BR2_PACKAGE_WPA_SUPPLICANT_DEBUG_SYSLOG
|
||||
select BR2_PACKAGE_WPA_SUPPLICANT_AUTOSCAN
|
||||
select BR2_PACKAGE_WPA_SUPPLICANT_CLI
|
||||
help
|
||||
Enables WiFi in Infix. Enables all requried applications.
|
||||
|
||||
config BR2_PACKAGE_FEATURE_WIFI_DONGLE_REALTEK
|
||||
bool "Realtek USB WiFi Dongles"
|
||||
depends on BR2_PACKAGE_FEATURE_WIFI
|
||||
select BR2_PACKAGE_LINUX_FIRMWARE
|
||||
select BR2_PACKAGE_LINUX_FIRMWARE_RTL_RTW88
|
||||
select BR2_PACKAGE_LINUX_FIRMWARE_RTL_RTW89
|
||||
help
|
||||
Enables Support for RTW88 and RTW89 USB dongles.
|
||||
@@ -0,0 +1,41 @@
|
||||
################################################################################
|
||||
#
|
||||
# Wi-Fi support
|
||||
#
|
||||
################################################################################
|
||||
|
||||
FEATURE_WIFI_PACKAGE_VERSION = 1.0
|
||||
FEATURE_WIFI_PACKAGE_LICENSE = MIT
|
||||
|
||||
define FEATURE_WIFI_LINUX_CONFIG_FIXUPS
|
||||
$(call KCONFIG_ENABLE_OPT,CONFIG_WLAN)
|
||||
$(call KCONFIG_ENABLE_OPT,CONFIG_RFKILL)
|
||||
$(call KCONFIG_ENABLE_OPT,CONFIG_MAC80211)
|
||||
$(call KCONFIG_ENABLE_OPT,CONFIG_CFG80211)
|
||||
$(if $(filter y,$(BR2_PACKAGE_FEATURE_WIFI_DONGLE_REALTEK)),
|
||||
$(call KCONFIG_ENABLE_OPT,CONFIG_WLAN_VENDOR_REALTEK)
|
||||
$(call KCONFIG_ENABLE_OPT,CONFIG_RTW88)
|
||||
$(call KCONFIG_ENABLE_OPT,CONFIG_RTW89)
|
||||
$(call KCONFIG_ENABLE_OPT,CONFIG_RTW88_8703B)
|
||||
$(call KCONFIG_ENABLE_OPT,CONFIG_RTW88_8723CS)
|
||||
$(call KCONFIG_ENABLE_OPT,CONFIG_RTW88_8723D)
|
||||
$(call KCONFIG_ENABLE_OPT,CONFIG_RTW88_8723DE)
|
||||
$(call KCONFIG_ENABLE_OPT,CONFIG_RTW88_8723DS)
|
||||
$(call KCONFIG_ENABLE_OPT,CONFIG_RTW88_8723DU)
|
||||
$(call KCONFIG_ENABLE_OPT,CONFIG_RTW88_8723X)
|
||||
$(call KCONFIG_ENABLE_OPT,CONFIG_RTW88_8821C)
|
||||
$(call KCONFIG_ENABLE_OPT,CONFIG_RTW88_8821CE)
|
||||
$(call KCONFIG_ENABLE_OPT,CONFIG_RTW88_8821CS)
|
||||
$(call KCONFIG_ENABLE_OPT,CONFIG_RTW88_8821CU)
|
||||
$(call KCONFIG_ENABLE_OPT,CONFIG_RTW88_8822B)
|
||||
$(call KCONFIG_ENABLE_OPT,CONFIG_RTW88_8822BE)
|
||||
$(call KCONFIG_ENABLE_OPT,CONFIG_RTW88_8822BS)
|
||||
$(call KCONFIG_ENABLE_OPT,CONFIG_RTW88_8822BU)
|
||||
$(call KCONFIG_ENABLE_OPT,CONFIG_RTW88_8822C)
|
||||
$(call KCONFIG_ENABLE_OPT,CONFIG_RTW88_8822CU)
|
||||
$(call KCONFIG_ENABLE_OPT,CONFIG_RTW88_8822CE)
|
||||
)
|
||||
endef
|
||||
|
||||
|
||||
$(eval $(generic-package))
|
||||
@@ -28,7 +28,6 @@ KLISH_PLUGIN_INFIX_CONF_OPTS += --enable-shell
|
||||
else
|
||||
KLISH_PLUGIN_INFIX_CONF_OPTS += --disable-shell
|
||||
endif
|
||||
|
||||
ifeq ($(BR2_PACKAGE_BASH),y)
|
||||
KLISH_PLUGIN_INFIX_CONF_OPTS += --with-shell=/bin/bash
|
||||
else
|
||||
|
||||
@@ -0,0 +1,232 @@
|
||||
From 9df1957e656940a50b844da879911ab5981ad1a9 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Mattias=20Walstr=C3=B6m?= <lazzer@gmail.com>
|
||||
Date: Wed, 18 Jun 2025 21:21:18 +0200
|
||||
Subject: [PATCH] Add pidfile support when not daemonize
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
Organization: Wires
|
||||
|
||||
Adds pidfile.c from libite
|
||||
|
||||
Signed-off-by: Mattias Walström <lazzer@gmail.com>
|
||||
---
|
||||
wpa_supplicant/Makefile | 1 +
|
||||
wpa_supplicant/pidfile.c | 153 ++++++++++++++++++++++++++++++++
|
||||
wpa_supplicant/wpa_supplicant.c | 7 +-
|
||||
3 files changed, 160 insertions(+), 1 deletion(-)
|
||||
create mode 100644 wpa_supplicant/pidfile.c
|
||||
|
||||
diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
|
||||
index fd7d7a0bd..e14c7732a 100644
|
||||
--- a/wpa_supplicant/Makefile
|
||||
+++ b/wpa_supplicant/Makefile
|
||||
@@ -104,6 +104,7 @@ endif
|
||||
OBJS = config.o
|
||||
OBJS += notify.o
|
||||
OBJS += bss.o
|
||||
+OBJS += pidfile.o
|
||||
OBJS += eap_register.o
|
||||
OBJS += ../src/utils/common.o
|
||||
OBJS += ../src/utils/config.o
|
||||
diff --git a/wpa_supplicant/pidfile.c b/wpa_supplicant/pidfile.c
|
||||
new file mode 100644
|
||||
index 000000000..29dfbe242
|
||||
--- /dev/null
|
||||
+++ b/wpa_supplicant/pidfile.c
|
||||
@@ -0,0 +1,153 @@
|
||||
+/* Updated by troglobit for libite/finit/uftpd projects 2016/07/04 */
|
||||
+/* $OpenBSD: pidfile.c,v 1.11 2015/06/03 02:24:36 millert Exp $ */
|
||||
+/* $NetBSD: pidfile.c,v 1.4 2001/02/19 22:43:42 cgd Exp $ */
|
||||
+
|
||||
+/*-
|
||||
+ * Copyright (c) 1999 The NetBSD Foundation, Inc.
|
||||
+ * All rights reserved.
|
||||
+ *
|
||||
+ * This code is derived from software contributed to The NetBSD Foundation
|
||||
+ * by Jason R. Thorpe.
|
||||
+ *
|
||||
+ * Redistribution and use in source and binary forms, with or without
|
||||
+ * modification, are permitted provided that the following conditions
|
||||
+ * are met:
|
||||
+ * 1. Redistributions of source code must retain the above copyright
|
||||
+ * notice, this list of conditions and the following disclaimer.
|
||||
+ * 2. Redistributions in binary form must reproduce the above copyright
|
||||
+ * notice, this list of conditions and the following disclaimer in the
|
||||
+ * documentation and/or other materials provided with the distribution.
|
||||
+ *
|
||||
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
+ * POSSIBILITY OF SUCH DAMAGE.
|
||||
+ */
|
||||
+
|
||||
+/**
|
||||
+ * @file pidfile.c
|
||||
+ * @author NetBSD Foundation Inc.
|
||||
+ * @date 1999
|
||||
+ * @copyright 2-clause BSD License
|
||||
+ */
|
||||
+
|
||||
+#include <sys/stat.h> /* utimensat() */
|
||||
+#include <sys/time.h> /* utimensat() on *BSD */
|
||||
+#include <sys/types.h>
|
||||
+#include <errno.h>
|
||||
+#include <paths.h>
|
||||
+#include <stdio.h>
|
||||
+#include <stdlib.h>
|
||||
+#include <unistd.h>
|
||||
+
|
||||
+#ifndef pidfile
|
||||
+static char *pidfile_path = NULL;
|
||||
+static pid_t pidfile_pid = 0;
|
||||
+
|
||||
+static void pidfile_cleanup(void);
|
||||
+
|
||||
+const char *__pidfile_path = _PATH_VARRUN; /* Note: includes trailing slash '/' */
|
||||
+const char *__pidfile_name = NULL;
|
||||
+extern char *__progname;
|
||||
+
|
||||
+/**
|
||||
+ * Create or update mtime of process PID file.
|
||||
+ * @param basename Program name, or @c NULL, may start with '/'
|
||||
+ *
|
||||
+ * This function is intended to be used by UNIX daemons to save the PID of the main process
|
||||
+ * responsible for handling signals. If @p basename is @c NULL the implicit @a __progname
|
||||
+ * variable from the C-library is used. The @p basename may also start with '/', in which
|
||||
+ * case it is interpreted as the absolute path to the PID file.
|
||||
+ *
|
||||
+ * @returns POSIX OK(0) on success, otherwise non-zero on error.
|
||||
+ */
|
||||
+int pidfile(const char *basename)
|
||||
+{
|
||||
+ int save_errno;
|
||||
+ int atexit_already;
|
||||
+ pid_t pid;
|
||||
+ FILE *f;
|
||||
+
|
||||
+ if (basename == NULL)
|
||||
+ basename = __progname;
|
||||
+
|
||||
+ pid = getpid();
|
||||
+ atexit_already = 0;
|
||||
+
|
||||
+ if (pidfile_path != NULL) {
|
||||
+ if (!access(pidfile_path, R_OK) && pid == pidfile_pid) {
|
||||
+ utimensat(0, pidfile_path, NULL, 0);
|
||||
+ return (0);
|
||||
+ }
|
||||
+ free(pidfile_path);
|
||||
+ pidfile_path = NULL;
|
||||
+ __pidfile_name = NULL;
|
||||
+ atexit_already = 1;
|
||||
+ }
|
||||
+
|
||||
+ if (basename[0] != '/') {
|
||||
+ if (asprintf(&pidfile_path, "%s.pid", basename) == -1)
|
||||
+ return (-1);
|
||||
+ } else {
|
||||
+ if (asprintf(&pidfile_path, "%s", basename) == -1)
|
||||
+ return (-1);
|
||||
+ }
|
||||
+
|
||||
+ if ((f = fopen(pidfile_path, "w")) == NULL) {
|
||||
+ save_errno = errno;
|
||||
+ free(pidfile_path);
|
||||
+ pidfile_path = NULL;
|
||||
+ errno = save_errno;
|
||||
+ return (-1);
|
||||
+ }
|
||||
+
|
||||
+ if (fprintf(f, "%ld\n", (long)pid) <= 0 || fflush(f) != 0) {
|
||||
+ save_errno = errno;
|
||||
+ (void) fclose(f);
|
||||
+ (void) unlink(pidfile_path);
|
||||
+ free(pidfile_path);
|
||||
+ pidfile_path = NULL;
|
||||
+ errno = save_errno;
|
||||
+ return (-1);
|
||||
+ }
|
||||
+ (void) fclose(f);
|
||||
+ __pidfile_name = pidfile_path;
|
||||
+
|
||||
+ /*
|
||||
+ * LITE extension, no need to set up another atexit() handler
|
||||
+ * if user only called us to update the mtime of the PID file
|
||||
+ */
|
||||
+ if (atexit_already)
|
||||
+ return (0);
|
||||
+
|
||||
+ pidfile_pid = pid;
|
||||
+ if (atexit(pidfile_cleanup) < 0) {
|
||||
+ save_errno = errno;
|
||||
+ (void) unlink(pidfile_path);
|
||||
+ free(pidfile_path);
|
||||
+ pidfile_path = NULL;
|
||||
+ pidfile_pid = 0;
|
||||
+ errno = save_errno;
|
||||
+ return (-1);
|
||||
+ }
|
||||
+
|
||||
+ return (0);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+pidfile_cleanup(void)
|
||||
+{
|
||||
+ if (pidfile_path != NULL && pidfile_pid == getpid()) {
|
||||
+ (void) unlink(pidfile_path);
|
||||
+ free(pidfile_path);
|
||||
+ pidfile_path = NULL;
|
||||
+ }
|
||||
+}
|
||||
+#endif
|
||||
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
|
||||
index dfbd63163..3a762ebc2 100644
|
||||
--- a/wpa_supplicant/wpa_supplicant.c
|
||||
+++ b/wpa_supplicant/wpa_supplicant.c
|
||||
@@ -123,6 +123,7 @@ const char *const wpa_supplicant_full_license5 =
|
||||
"\n";
|
||||
#endif /* CONFIG_NO_STDOUT_DEBUG */
|
||||
|
||||
+int pidfile(const char *basename);
|
||||
|
||||
static void wpa_bss_tmp_disallow_timeout(void *eloop_ctx, void *timeout_ctx);
|
||||
static void wpas_verify_ssid_beacon(void *eloop_ctx, void *timeout_ctx);
|
||||
@@ -1490,6 +1491,9 @@ static void wpa_supplicant_reconfig(int sig, void *signal_ctx)
|
||||
/* Ignore errors since we cannot really do much to fix this */
|
||||
wpa_printf(MSG_DEBUG, "Could not reopen debug log file");
|
||||
}
|
||||
+
|
||||
+ if (!global->params.daemonize)
|
||||
+ pidfile(global->params.pid_file);
|
||||
}
|
||||
|
||||
|
||||
@@ -8555,7 +8559,6 @@ struct wpa_global * wpa_supplicant_init(struct wpa_params *params)
|
||||
return global;
|
||||
}
|
||||
|
||||
-
|
||||
/**
|
||||
* wpa_supplicant_run - Run the %wpa_supplicant main event loop
|
||||
* @global: Pointer to global data from wpa_supplicant_init()
|
||||
@@ -8589,6 +8592,8 @@ int wpa_supplicant_run(struct wpa_global *global)
|
||||
eloop_register_signal_terminate(wpa_supplicant_terminate, global);
|
||||
eloop_register_signal_reconfig(wpa_supplicant_reconfig, global);
|
||||
|
||||
+ if (!global->params.daemonize)
|
||||
+ pidfile(global->params.pid_file);
|
||||
eloop_run();
|
||||
|
||||
return 0;
|
||||
--
|
||||
2.43.0
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
pkglibexec_SCRIPTS = bootstrap error load gen-service gen-hostname \
|
||||
gen-interfaces gen-motd gen-hardware gen-version \
|
||||
mstpd-wait-online
|
||||
mstpd-wait-online wait-interface
|
||||
sbin_SCRIPTS = dagger migrate
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
#!/bin/sh
|
||||
if [ $# -lt 2 ]; then
|
||||
echo "usage: $0 <ifname> <timeout>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
ifname=$1
|
||||
timeout=$2
|
||||
while true; do
|
||||
if ip link show $ifname &>/dev/null; then
|
||||
break
|
||||
fi
|
||||
|
||||
retries=$(($retries + 1))
|
||||
if [ $retries -ge $timeout ]; then
|
||||
logger -t wait-interface "Timeout: Interface $ifname not found after $timeout seconds"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
sleep 1
|
||||
done
|
||||
@@ -41,6 +41,10 @@ AC_ARG_ENABLE(containers,
|
||||
AS_HELP_STRING([--enable-containers], [Enable support for containers]),,[
|
||||
enable_containers=no])
|
||||
|
||||
AC_ARG_ENABLE(wifi,
|
||||
AS_HELP_STRING([--enable-wifi], [Enable support for Wi-Fi]),,[
|
||||
enable_wifi=no])
|
||||
|
||||
AC_ARG_WITH(login-shell,
|
||||
AS_HELP_STRING([--with-login-shell=shell], [Login shell for new users, default: /bin/false]),
|
||||
[login_shell=$withval], [login_shell=yes])
|
||||
@@ -52,6 +56,9 @@ AC_ARG_WITH(crypt,
|
||||
AS_IF([test "x$enable_containers" = "xyes"], [
|
||||
AC_DEFINE(CONTAINERS, 1, [Built with container support])])
|
||||
|
||||
AS_IF([test "x$enable_wifi" = "xyes"], [
|
||||
AC_DEFINE(HAVE_WIFI, 1, [Built with Wi-Fi support])])
|
||||
|
||||
AS_IF([test "x$with_login_shell" != "xno"], [
|
||||
AS_IF([test "x$login_shell" = "xyes"], [login_shell=/bin/false])
|
||||
AC_DEFINE_UNQUOTED(LOGIN_SHELL, "$login_shell", [Default: /bin/false])],[
|
||||
@@ -122,6 +129,7 @@ cat <<EOF
|
||||
|
||||
Optional features:
|
||||
Container support ....: $enable_containers
|
||||
Wi-Fi support ........: $enable_wifi
|
||||
Login shell ..........: $login_shell
|
||||
Default crypt algo ...: $crypt
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@ confd_plugin_la_SOURCES = \
|
||||
infix-if-vlan.c \
|
||||
infix-if-gre.c \
|
||||
infix-if-vxlan.c \
|
||||
infix-if-wifi.c \
|
||||
ietf-keystore.c \
|
||||
ietf-system.c \
|
||||
ietf-syslog.c \
|
||||
|
||||
+14
-9
@@ -12,6 +12,7 @@
|
||||
#include <sys/time.h>
|
||||
#include <sys/param.h>
|
||||
#include <unistd.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <libite/lite.h>
|
||||
#include <libite/queue.h>
|
||||
@@ -137,9 +138,20 @@ static inline int register_change(sr_session_ctx_t *session, const char *module,
|
||||
int flags, sr_module_change_cb cb, void *arg, sr_subscription_ctx_t **sub)
|
||||
{
|
||||
struct confd *ptr = (struct confd *)arg;
|
||||
bool need_core_hooks;
|
||||
int rc;
|
||||
|
||||
if (!flags) {
|
||||
/*
|
||||
* For standard subscribtions we hook into the callback chain
|
||||
* for all modules to figure out, per changeset, which of the
|
||||
* callbacks is the last one. This is where we want to call the
|
||||
* global commit-done hook for candidate -> running changes and
|
||||
* the startup-save hook for running -> startup copying.
|
||||
*/
|
||||
|
||||
need_core_hooks = !(flags & SR_SUBSCR_UPDATE);
|
||||
|
||||
if (need_core_hooks) {
|
||||
sr_module_change_subscribe(ptr->session, module, xpath, core_pre_hook, NULL,
|
||||
0, SR_SUBSCR_PASSIVE, sub);
|
||||
}
|
||||
@@ -151,14 +163,7 @@ static inline int register_change(sr_session_ctx_t *session, const char *module,
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* For standard subscribtions we hook into the callback chain
|
||||
* for all modules to figure out, per changeset, which of the
|
||||
* callbacks is the last one. This is where we want to call the
|
||||
* global commit-done hook for candidate -> running changes and
|
||||
* the startup-save hook for running -> startup copying.
|
||||
*/
|
||||
if (!flags) {
|
||||
if (need_core_hooks) {
|
||||
sr_module_change_subscribe(ptr->session, module, xpath, core_post_hook, NULL,
|
||||
core_hook_prio(), SR_SUBSCR_PASSIVE, sub);
|
||||
sr_module_change_subscribe(ptr->startup, module, xpath, core_startup_save, NULL,
|
||||
|
||||
@@ -52,6 +52,9 @@ enum netdag_exit {
|
||||
};
|
||||
|
||||
enum netdag_init {
|
||||
/* Timeout for slow interfaces */
|
||||
NETDAG_INIT_TIMEOUT = 00,
|
||||
|
||||
/* Configure link layer */
|
||||
NETDAG_INIT_PHYS = 10,
|
||||
|
||||
|
||||
@@ -114,23 +114,6 @@ int netdag_gen_ethtool(struct dagger *net, struct lyd_node *cif, struct lyd_node
|
||||
struct lyd_node *eth = lydx_get_child(dif, "ethernet");
|
||||
int err;
|
||||
|
||||
/*
|
||||
* Story time: when assigning a physical interface to a container, and then
|
||||
* removing it, even though our type may be 'etherlike' we will
|
||||
* get the following from sysrepo:
|
||||
*
|
||||
* "ieee802-ethernet-interface:ethernet": {
|
||||
* "@": {
|
||||
* "yang:operation": "delete"
|
||||
* },
|
||||
* "duplex": "full"
|
||||
* },
|
||||
*
|
||||
* Hence this "redundant" check.
|
||||
*/
|
||||
if (iftype_from_iface(cif) != IFT_ETH)
|
||||
return 0;
|
||||
|
||||
if (!eth)
|
||||
return 0;
|
||||
|
||||
|
||||
+111
-21
@@ -9,8 +9,11 @@
|
||||
#include <srx/common.h>
|
||||
#include <srx/lyx.h>
|
||||
#include <srx/srx_val.h>
|
||||
#include <libyang/libyang.h>
|
||||
|
||||
#include "ietf-interfaces.h"
|
||||
#define IFACE_PROBE_TIMEOUT 40
|
||||
|
||||
|
||||
bool iface_has_quirk(const char *ifname, const char *quirkname)
|
||||
{
|
||||
@@ -27,6 +30,7 @@ bool iface_has_quirk(const char *ifname, const char *quirkname)
|
||||
|
||||
return quirk ? json_is_true(quirk) : false;
|
||||
}
|
||||
|
||||
static bool iface_is_phys(const char *ifname)
|
||||
{
|
||||
bool is_phys = false;
|
||||
@@ -84,7 +88,9 @@ static int ifchange_cand_infer_type(sr_session_ctx_t *session, const char *path)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (iface_is_phys(ifname))
|
||||
if (!fnmatch("wifi+([0-9])", ifname, FNM_EXTMATCH))
|
||||
inferred.data.string_val = "infix-if-type:wifi";
|
||||
else if (iface_is_phys(ifname))
|
||||
inferred.data.string_val = "infix-if-type:ethernet";
|
||||
else if (!fnmatch("br+([0-9])", ifname, FNM_EXTMATCH))
|
||||
inferred.data.string_val = "infix-if-type:bridge";
|
||||
@@ -112,6 +118,7 @@ static int ifchange_cand_infer_type(sr_session_ctx_t *session, const char *path)
|
||||
inferred.data.string_val = "infix-if-type:gretap";
|
||||
else if (!fnmatch("vxlan+([0-9])", ifname, FNM_EXTMATCH))
|
||||
inferred.data.string_val = "infix-if-type:vxlan";
|
||||
|
||||
free(ifname);
|
||||
|
||||
if (inferred.data.string_val)
|
||||
@@ -416,9 +423,13 @@ static int netdag_gen_afspec_add(sr_session_ctx_t *session, struct dagger *net,
|
||||
return vlan_gen(NULL, cif, ip);
|
||||
case IFT_VXLAN:
|
||||
return vxlan_gen(NULL, cif, ip);
|
||||
|
||||
case IFT_WIFI:
|
||||
return wifi_gen(NULL, cif, net);
|
||||
case IFT_ETH:
|
||||
return netdag_gen_ethtool(net, cif, dif);
|
||||
case IFT_LO:
|
||||
return 0;
|
||||
|
||||
case IFT_UNKNOWN:
|
||||
sr_session_set_error_message(net->session, "%s: unsupported interface type \"%s\"",
|
||||
ifname, lydx_get_cattr(cif, "type"));
|
||||
@@ -440,16 +451,18 @@ static int netdag_gen_afspec_set(sr_session_ctx_t *session, struct dagger *net,
|
||||
return lag_gen(dif, cif, ip, 0);
|
||||
case IFT_VLAN:
|
||||
return vlan_gen(dif, cif, ip);
|
||||
|
||||
case IFT_ETH:
|
||||
return netdag_gen_ethtool(net, cif, dif);
|
||||
case IFT_WIFI:
|
||||
return wifi_gen(dif, cif, net);
|
||||
case IFT_DUMMY:
|
||||
case IFT_GRE:
|
||||
case IFT_GRETAP:
|
||||
case IFT_VETH:
|
||||
case IFT_VXLAN:
|
||||
case IFT_LO:
|
||||
return 0;
|
||||
|
||||
case IFT_ETH:
|
||||
case IFT_LO:
|
||||
case IFT_UNKNOWN:
|
||||
return ERR_IFACE(cif, -ENOSYS, "unsupported interface type \"%s\"",
|
||||
lydx_get_cattr(cif, "type"));
|
||||
@@ -466,10 +479,11 @@ static bool netdag_must_del(struct lyd_node *dif, struct lyd_node *cif)
|
||||
case IFT_DUMMY:
|
||||
case IFT_LO:
|
||||
break;
|
||||
|
||||
case IFT_WIFI:
|
||||
case IFT_ETH:
|
||||
/* case IFT_LAG: */
|
||||
/* ... REMEMBER WHEN ADDING BOND SUPPORT ... */
|
||||
return lydx_get_child(dif, "custom-phys-address");
|
||||
|
||||
case IFT_GRE:
|
||||
case IFT_GRETAP:
|
||||
return lydx_get_descendant(lyd_child(dif), "gre", NULL);
|
||||
@@ -519,12 +533,12 @@ static int link_gen_del(struct lyd_node *dif, FILE *ip)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int veth_gen_del(struct lyd_node *dif, FILE *ip)
|
||||
static int veth_gen_del(struct lyd_node *dif, FILE *sh)
|
||||
{
|
||||
if (!veth_is_primary(dif))
|
||||
return 0;
|
||||
|
||||
return link_gen_del(dif, ip);
|
||||
return link_gen_del(dif, sh);
|
||||
}
|
||||
|
||||
static int netdag_gen_iface_del(struct dagger *net, struct lyd_node *dif,
|
||||
@@ -554,6 +568,10 @@ static int netdag_gen_iface_del(struct dagger *net, struct lyd_node *dif,
|
||||
case IFT_LO:
|
||||
eth_gen_del(dif, ip);
|
||||
break;
|
||||
case IFT_WIFI:
|
||||
eth_gen_del(dif, ip);
|
||||
wifi_gen_del(dif, net);
|
||||
break;
|
||||
case IFT_VETH:
|
||||
veth_gen_del(dif, ip);
|
||||
break;
|
||||
@@ -573,16 +591,35 @@ static int netdag_gen_iface_del(struct dagger *net, struct lyd_node *dif,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static sr_error_t netdag_gen_iface_timeout(struct dagger *net, const char *ifname, const char *iftype)
|
||||
{
|
||||
if (!strcmp(iftype, "infix-if-type:ethernet") || !strcmp(iftype, "infix-if-type:wifi")) {
|
||||
FILE *wait = dagger_fopen_net_init(net, ifname, NETDAG_INIT_TIMEOUT, "wait-interface.sh");
|
||||
if (!wait) {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
fprintf(wait, "/usr/libexec/confd/wait-interface %s %d\n", ifname, IFACE_PROBE_TIMEOUT);
|
||||
fclose(wait);
|
||||
}
|
||||
return SR_ERR_OK;
|
||||
}
|
||||
|
||||
static sr_error_t netdag_gen_iface(sr_session_ctx_t *session, struct dagger *net,
|
||||
struct lyd_node *dif, struct lyd_node *cif)
|
||||
{
|
||||
const char *ifname = lydx_get_cattr(dif, "name");
|
||||
const char *iftype = lydx_get_cattr(dif, "type")?:lydx_get_cattr(cif, "type");
|
||||
enum lydx_op op = lydx_get_op(dif);
|
||||
const char *attr;
|
||||
int err = 0;
|
||||
bool fixed;
|
||||
FILE *ip;
|
||||
|
||||
|
||||
err = netdag_gen_iface_timeout(net, ifname, iftype);
|
||||
if (err)
|
||||
goto err;
|
||||
|
||||
if ((err = cni_netdag_gen_iface(net, ifname, dif, cif))) {
|
||||
/* error or managed by CNI/podman */
|
||||
if (err > 0)
|
||||
@@ -590,9 +627,7 @@ static sr_error_t netdag_gen_iface(sr_session_ctx_t *session, struct dagger *net
|
||||
goto err;
|
||||
}
|
||||
|
||||
fixed = iface_is_phys(ifname) || !strcmp(ifname, "lo");
|
||||
|
||||
DEBUG("%s(%s) %s", ifname, fixed ? "fixed" : "dynamic",
|
||||
DEBUG("%s %s", ifname,
|
||||
(op == LYDX_OP_NONE) ? "mod" : ((op == LYDX_OP_CREATE) ? "add" : "del"));
|
||||
|
||||
if (op == LYDX_OP_DELETE) {
|
||||
@@ -630,7 +665,7 @@ static sr_error_t netdag_gen_iface(sr_session_ctx_t *session, struct dagger *net
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!fixed && op == LYDX_OP_CREATE) {
|
||||
if (op == LYDX_OP_CREATE) {
|
||||
err = netdag_gen_afspec_add(session, net, dif, cif, ip);
|
||||
if (err)
|
||||
goto err_close_ip;
|
||||
@@ -655,7 +690,7 @@ static sr_error_t netdag_gen_iface(sr_session_ctx_t *session, struct dagger *net
|
||||
goto err_close_ip;
|
||||
|
||||
/* Set type specific attributes */
|
||||
if (!fixed && op != LYDX_OP_CREATE) {
|
||||
if (op != LYDX_OP_CREATE) {
|
||||
err = netdag_gen_afspec_set(session, net, dif, cif, ip);
|
||||
if (err)
|
||||
goto err_close_ip;
|
||||
@@ -679,8 +714,6 @@ static sr_error_t netdag_gen_iface(sr_session_ctx_t *session, struct dagger *net
|
||||
|
||||
err = err ? : netdag_gen_sysctl(net, cif, dif);
|
||||
|
||||
err = err ? : netdag_gen_ethtool(net, cif, dif);
|
||||
|
||||
err_close_ip:
|
||||
fclose(ip);
|
||||
err:
|
||||
@@ -710,6 +743,7 @@ static int netdag_init_iface(struct lyd_node *cif)
|
||||
|
||||
case IFT_DUMMY:
|
||||
case IFT_ETH:
|
||||
case IFT_WIFI:
|
||||
case IFT_GRE:
|
||||
case IFT_GRETAP:
|
||||
case IFT_LO:
|
||||
@@ -790,7 +824,7 @@ static int ifchange(sr_session_ctx_t *session, uint32_t sub_id, const char *modu
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = sr_get_data(session, "/interfaces/interface", 0, 0, 0, &cfg);
|
||||
err = sr_get_data(session, "//.", 0, 0, 0, &cfg);
|
||||
if (err || !cfg)
|
||||
goto err_abandon;
|
||||
|
||||
@@ -800,7 +834,6 @@ static int ifchange(sr_session_ctx_t *session, uint32_t sub_id, const char *modu
|
||||
|
||||
cifs = lydx_get_descendant(cfg->tree, "interfaces", "interface", NULL);
|
||||
difs = lydx_get_descendant(diff, "interfaces", "interface", NULL);
|
||||
|
||||
err = netdag_init(session, &confd->netdag, cifs, difs);
|
||||
if (err)
|
||||
goto err_free_diff;
|
||||
@@ -829,15 +862,72 @@ err_abandon:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int keystorecb(sr_session_ctx_t *session, uint32_t sub_id, const char *module,
|
||||
const char *xpath, sr_event_t event, unsigned request_id, void *_confd)
|
||||
{
|
||||
const struct lyd_node *diff;
|
||||
const char *secret_name;
|
||||
struct confd *confd = _confd;
|
||||
struct lyd_node *interfaces, *interface, *dkeys, *dkey, *wifi;
|
||||
sr_data_t *cfg = NULL;
|
||||
int err = SR_ERR_OK;
|
||||
|
||||
switch (event) {
|
||||
case SR_EV_CHANGE:
|
||||
break;
|
||||
default:
|
||||
return SR_ERR_OK;
|
||||
}
|
||||
|
||||
err = sr_get_data(session, "/interfaces/interface", 0, 0, 0, &cfg);
|
||||
if (err || !cfg)
|
||||
return err;
|
||||
|
||||
diff = sr_get_change_diff(session);
|
||||
if (!diff)
|
||||
goto cleanup;
|
||||
|
||||
interfaces = lydx_get_descendant(cfg->tree, "interfaces", "interface", NULL);
|
||||
dkeys = lydx_get_descendant((struct lyd_node*) diff, "keystore", "symmetric-keys", "symmetric-key", NULL);
|
||||
|
||||
LYX_LIST_FOR_EACH(dkeys, dkey, "symmetric-key") {
|
||||
secret_name = lydx_get_cattr(dkey, "name");
|
||||
if (!secret_name)
|
||||
continue;
|
||||
|
||||
LYX_LIST_FOR_EACH(interfaces, interface, "interface") {
|
||||
const char *name;
|
||||
|
||||
if (iftype_from_iface(interface) != IFT_WIFI)
|
||||
continue;
|
||||
|
||||
wifi = lydx_get_child(interface, "wifi");
|
||||
if (!wifi)
|
||||
continue;
|
||||
|
||||
name = lydx_get_cattr(wifi, "secret");
|
||||
if (!name || strcmp(name, secret_name))
|
||||
continue;
|
||||
wifi_gen(NULL, interface, &confd->netdag);
|
||||
}
|
||||
}
|
||||
|
||||
cleanup:
|
||||
if (cfg)
|
||||
sr_release_data(cfg);
|
||||
return err;
|
||||
}
|
||||
|
||||
int ietf_interfaces_init(struct confd *confd)
|
||||
{
|
||||
int rc;
|
||||
|
||||
REGISTER_CHANGE(confd->session, "ietf-interfaces", "/ietf-interfaces:interfaces//.",
|
||||
0, ifchange, confd, &confd->sub);
|
||||
SR_SUBSCR_CHANGE_ALL_MODULES, ifchange, confd, &confd->sub);
|
||||
REGISTER_CHANGE(confd->session, "ietf-keystore", "//*",
|
||||
SR_SUBSCR_CHANGE_ALL_MODULES, keystorecb, confd, &confd->sub);
|
||||
REGISTER_CHANGE(confd->cand, "ietf-interfaces", "/ietf-interfaces:interfaces//.",
|
||||
SR_SUBSCR_UPDATE, ifchange_cand, confd, &confd->sub);
|
||||
|
||||
return SR_ERR_OK;
|
||||
fail:
|
||||
ERROR("failed, error %d: %s", rc, sr_strerror(rc));
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
_map(IFT_BRIDGE, "infix-if-type:bridge") \
|
||||
_map(IFT_DUMMY, "infix-if-type:dummy") \
|
||||
_map(IFT_ETH, "infix-if-type:ethernet") \
|
||||
_map(IFT_WIFI, "infix-if-type:wifi") \
|
||||
_map(IFT_GRE, "infix-if-type:gre") \
|
||||
_map(IFT_GRETAP, "infix-if-type:gretap") \
|
||||
_map(IFT_LAG, "infix-if-type:lag") \
|
||||
@@ -119,6 +120,10 @@ int bridge_mcd_gen(struct lyd_node *cifs);
|
||||
/* infix-if-bridge-port.c */
|
||||
int bridge_port_gen(struct lyd_node *dif, struct lyd_node *cif, FILE *ip);
|
||||
|
||||
/* infix-if-wifi.c */
|
||||
int wifi_gen(struct lyd_node *dif, struct lyd_node *cif, struct dagger *net);
|
||||
int wifi_gen_del(struct lyd_node *dif, struct dagger *net);
|
||||
|
||||
/* infix-if-gre.c */
|
||||
int gre_gen(struct lyd_node *dif, struct lyd_node *cif, FILE *ip);
|
||||
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause */
|
||||
#include <srx/lyx.h>
|
||||
|
||||
#include "ietf-interfaces.h"
|
||||
|
||||
#define WPA_SUPPLICANT_FINIT_CONF "/etc/finit.d/available/wpa_supplicant-%s.conf"
|
||||
#define WPA_SUPPLICANT_CONF "/etc/wpa_supplicant-%s.conf"
|
||||
|
||||
static int wifi_gen_config(const char *ifname, const char *ssid, const char *country, const char *secret, const char* encryption, struct dagger *net)
|
||||
{
|
||||
FILE *wpa_supplicant = NULL, *wpa = NULL;
|
||||
char *encryption_str;
|
||||
int rc = SR_ERR_OK;
|
||||
|
||||
if (!secret || !ssid || !country || !encryption) {
|
||||
/* Not an error, updated from two ways, interface cb and keystore cb. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
wpa = dagger_fopen_net_init(net, ifname, NETDAG_INIT_POST, "wpa_supplicant.sh");
|
||||
if (!wpa) {
|
||||
rc = SR_ERR_INTERNAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
fprintf(wpa, "# Generated by Infix confd\n");
|
||||
fprintf(wpa, "initctl -bfqn enable wifi@%s\n", ifname);
|
||||
fclose(wpa);
|
||||
|
||||
wpa_supplicant = fopenf("w", WPA_SUPPLICANT_CONF, ifname);
|
||||
if (!wpa_supplicant) {
|
||||
rc = SR_ERR_INTERNAL;
|
||||
goto out;
|
||||
}
|
||||
if (ssid) {
|
||||
if (!strcmp(encryption, "disabled")) {
|
||||
asprintf(&encryption_str, "key_mgmt=NONE");
|
||||
} else {
|
||||
asprintf(&encryption_str, "key_mgmt=SAE WPA-PSK\npsk=\"%s\"", secret);
|
||||
}
|
||||
fprintf(wpa_supplicant,
|
||||
"country=%s\n"
|
||||
"ctrl_interface=/run/wpa_supplicant\n"
|
||||
"autoscan=periodic:10\n"
|
||||
"ap_scan=1\n"
|
||||
"network={\n"
|
||||
"bgscan=\"simple: 30:-45:300\"\n"
|
||||
"ssid=\"%s\"\n"
|
||||
"%s\n"
|
||||
"}\n", country, ssid, encryption_str);
|
||||
free(encryption_str);
|
||||
} else {
|
||||
fprintf(wpa_supplicant,
|
||||
"ctrl_interface=/run/wpa_supplicant\n"
|
||||
"autoscan=periodic:10\n"
|
||||
"ap_scan=1\n");
|
||||
|
||||
|
||||
}
|
||||
fclose(wpa_supplicant);
|
||||
|
||||
out:
|
||||
return rc;
|
||||
|
||||
}
|
||||
int wifi_gen(struct lyd_node *dif, struct lyd_node *cif, struct dagger *net)
|
||||
{
|
||||
const char *ssid, *secret_name, *secret, *ifname, *country, *encryption;
|
||||
struct lyd_node *wifi, *secret_node;
|
||||
|
||||
bool enabled;
|
||||
ifname = lydx_get_cattr(cif, "name");
|
||||
|
||||
if (cif && !lydx_get_child(cif, "wifi")) {
|
||||
return wifi_gen_config(ifname, NULL, NULL, NULL, NULL, net);
|
||||
}
|
||||
|
||||
if (dif && !lydx_get_child(dif, "wifi")) {
|
||||
return SR_ERR_OK;
|
||||
}
|
||||
|
||||
|
||||
enabled = lydx_get_bool(cif, "enabled");
|
||||
wifi = lydx_get_child(cif, "wifi");
|
||||
|
||||
ssid = lydx_get_cattr(wifi, "ssid");
|
||||
secret_name = lydx_get_cattr(wifi, "secret");
|
||||
country = lydx_get_cattr(wifi, "country-code");
|
||||
encryption = lydx_get_cattr(wifi, "encryption");
|
||||
secret_node = lydx_get_xpathf(cif, "../../keystore/symmetric-keys/symmetric-key[name='%s']", secret_name);
|
||||
secret = lydx_get_cattr(secret_node, "cleartext-key");
|
||||
|
||||
if (!enabled)
|
||||
return wifi_gen_del(cif, net);
|
||||
|
||||
return wifi_gen_config(ifname, ssid, country, secret, encryption, net);
|
||||
}
|
||||
|
||||
int wifi_gen_del(struct lyd_node *dif, struct dagger *net)
|
||||
{
|
||||
const char *ifname = lydx_get_cattr(dif, "name");
|
||||
FILE *iw = dagger_fopen_net_exit(net, ifname, NETDAG_EXIT_PRE, "iw.sh");
|
||||
|
||||
fprintf(iw, "# Generated by Infix confd\n");
|
||||
fprintf(iw, "iw dev %s disconnect\n", ifname);
|
||||
fprintf(iw, "initctl -bfqn disable wifi@%s\n", ifname);
|
||||
fclose(iw);
|
||||
erasef(WPA_SUPPLICANT_CONF, ifname);
|
||||
|
||||
return SR_ERR_OK;
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
# -*- sh -*-
|
||||
# REMEMBER TO UPDATE infix-interfaces ALSO IN containers.inc
|
||||
|
||||
MODULES=(
|
||||
"ietf-system@2014-08-06.yang -e authentication -e local-users -e ntp -e ntp-udp-port -e timezone-name"
|
||||
@@ -35,7 +34,9 @@ MODULES=(
|
||||
"ieee802-ethernet-interface@2019-06-21.yang"
|
||||
"infix-ethernet-interface@2024-02-27.yang"
|
||||
"infix-factory-default@2023-06-28.yang"
|
||||
"infix-interfaces@2025-01-09.yang -e vlan-filtering"
|
||||
"infix-crypto-types@2025-02-04.yang"
|
||||
"infix-keystore@2025-02-04.yang"
|
||||
"infix-interfaces@2025-06-17.yang -e vlan-filtering"
|
||||
"ietf-crypto-types -e cleartext-symmetric-keys"
|
||||
"infix-crypto-types@2025-06-17.yang"
|
||||
"ietf-keystore -e symmetric-keys"
|
||||
"infix-keystore@2025-06-17.yang"
|
||||
)
|
||||
|
||||
@@ -5,6 +5,10 @@ module infix-crypto-types {
|
||||
import ietf-crypto-types {
|
||||
prefix ct;
|
||||
}
|
||||
|
||||
revision 2025-06-17 {
|
||||
description "Add Wi-Fi secret support.";
|
||||
}
|
||||
revision 2025-02-04 {
|
||||
description "Initial";
|
||||
}
|
||||
@@ -24,4 +28,14 @@ module infix-crypto-types {
|
||||
base public-key-format;
|
||||
base ct:ssh-public-key-format;
|
||||
}
|
||||
identity symmetric-key-format {
|
||||
description
|
||||
"Base for symmetric key format";
|
||||
}
|
||||
identity wifi-preshared-key-format {
|
||||
base ct:symmetric-key-format;
|
||||
base symmetric-key-format;
|
||||
description
|
||||
"WiFi secret key";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,6 +38,14 @@ module infix-if-type {
|
||||
reference "internal";
|
||||
}
|
||||
|
||||
/*
|
||||
* Features
|
||||
*/
|
||||
|
||||
feature wifi {
|
||||
description "WiFi support is an optional build-time feature in Infix.";
|
||||
}
|
||||
|
||||
/*
|
||||
* Identities
|
||||
*/
|
||||
@@ -98,4 +106,10 @@ module infix-if-type {
|
||||
base ianaift:l2vlan;
|
||||
description "Layer 2 Virtual LAN using 802.1Q.";
|
||||
}
|
||||
identity wifi {
|
||||
if-feature wifi;
|
||||
base infix-interface-type;
|
||||
base ianaift:ieee80211;
|
||||
description "WiFi interface";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,185 @@
|
||||
submodule infix-if-wifi {
|
||||
yang-version 1.1;
|
||||
belongs-to infix-interfaces {
|
||||
prefix infix-if;
|
||||
}
|
||||
import ietf-interfaces {
|
||||
prefix if;
|
||||
}
|
||||
import ietf-yang-types {
|
||||
prefix yang;
|
||||
}
|
||||
import ietf-netconf-acm {
|
||||
prefix nacm;
|
||||
}
|
||||
import ietf-keystore {
|
||||
prefix ks;
|
||||
}
|
||||
import infix-crypto-types {
|
||||
prefix ixct;
|
||||
}
|
||||
import infix-if-type {
|
||||
prefix infixift;
|
||||
}
|
||||
import infix-wifi-country-codes {
|
||||
prefix iwcc;
|
||||
}
|
||||
|
||||
organization "KernelKit";
|
||||
contact "kernelkit@googlegroups.com";
|
||||
description
|
||||
"WiFi-specific extensions to the standard IETF interfaces model.
|
||||
|
||||
This submodule defines configuration and operational data relevant to
|
||||
WiFi interfaces, including security settings, network
|
||||
discovery, and regulatory compliance.
|
||||
|
||||
It supports WiFi client mode and enables comprehensive management of
|
||||
wireless connections, including encryption, country codes, and scanning.";
|
||||
|
||||
revision 2025-05-27 {
|
||||
description "Initial revision.";
|
||||
reference "internal";
|
||||
}
|
||||
|
||||
feature wifi {
|
||||
description "WiFi support is an optional build-time feature in Infix.";
|
||||
}
|
||||
|
||||
typedef encryption {
|
||||
type enumeration {
|
||||
enum auto {
|
||||
description
|
||||
"Enables WPA/WPA2/WPA3 encryption with automatic protocol
|
||||
negotiation. The system uses the strongest supported variant supported by Access Point.";
|
||||
}
|
||||
enum disabled {
|
||||
description
|
||||
"Disables encryption for an open network.
|
||||
|
||||
WARNING: Open networks transmit data unencrypted and should only
|
||||
be used in trusted environments.";
|
||||
}
|
||||
}
|
||||
description
|
||||
"Encryption modes available for WiFi connections.
|
||||
|
||||
- auto: Secure connection using WPA3/WPA2/WPA (auto-selected)
|
||||
- disabled: Open network (unencrypted)";
|
||||
}
|
||||
|
||||
|
||||
augment "/if:interfaces/if:interface" {
|
||||
when "derived-from-or-self(if:type, 'infixift:wifi')" {
|
||||
description
|
||||
"Applies only to interfaces of type 'wifi'.";
|
||||
}
|
||||
|
||||
container wifi {
|
||||
if-feature wifi;
|
||||
presence "Configure Wi-Fi settings";
|
||||
|
||||
description
|
||||
"WiFi-specific configuration and operational data.";
|
||||
|
||||
leaf country-code {
|
||||
type iwcc:country-code;
|
||||
mandatory true;
|
||||
description
|
||||
"Two-letter ISO 3166-1 country code for regulatory compliance.
|
||||
|
||||
Examples: 'US', 'DE', 'JP'.
|
||||
|
||||
WARNING: Incorrect values may violate local laws.";
|
||||
|
||||
|
||||
}
|
||||
|
||||
leaf encryption {
|
||||
default auto;
|
||||
type encryption;
|
||||
|
||||
description
|
||||
"WiFi encryption method.
|
||||
|
||||
- auto (default): Enables WPA2/WPA3 auto-negotiation
|
||||
- disabled: Disables encryption (open network)";
|
||||
}
|
||||
|
||||
leaf ssid {
|
||||
type string {
|
||||
length "1..32";
|
||||
}
|
||||
mandatory true;
|
||||
|
||||
description
|
||||
"WiFi network name (SSID).
|
||||
|
||||
Case-sensitive, must match the target network.
|
||||
|
||||
Length: 1–32 characters.";
|
||||
}
|
||||
|
||||
leaf secret {
|
||||
type ks:symmetric-key-ref;
|
||||
mandatory true;
|
||||
must "../encryption != 'disabled'" {
|
||||
error-message
|
||||
"Pre-shared key required unless encryption is disabled.";
|
||||
}
|
||||
|
||||
description
|
||||
"Pre-shared key (PSK) for WPA-secured networks.";
|
||||
}
|
||||
|
||||
leaf rssi {
|
||||
config false;
|
||||
type int16;
|
||||
units "dBm";
|
||||
description
|
||||
"Current received signal strength (RSSI) in dBm.
|
||||
|
||||
Lower (more negative) values indicate stronger signals.";
|
||||
}
|
||||
|
||||
list scan-results {
|
||||
config false;
|
||||
key ssid;
|
||||
description
|
||||
"List of discovered networks.";
|
||||
|
||||
leaf ssid {
|
||||
type string;
|
||||
description
|
||||
"SSID of the discovered network.";
|
||||
}
|
||||
|
||||
leaf bssid {
|
||||
type string;
|
||||
description
|
||||
"BSSID of the discovered network.";
|
||||
}
|
||||
|
||||
leaf rssi {
|
||||
type int16;
|
||||
units "dBm";
|
||||
description
|
||||
"Signal strength of the network.";
|
||||
}
|
||||
|
||||
leaf channel {
|
||||
type int16;
|
||||
description
|
||||
"Channel on which the network was detected.";
|
||||
}
|
||||
|
||||
leaf-list encryption {
|
||||
ordered-by user;
|
||||
type string;
|
||||
description
|
||||
"Human-readable description of the detected security.";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
infix-if-wifi.yang
|
||||
@@ -3,9 +3,6 @@ module infix-interfaces {
|
||||
namespace "urn:infix:interfaces:ns:yang:1.0";
|
||||
prefix infix-if;
|
||||
|
||||
import infix-if-type {
|
||||
prefix infix-ift;
|
||||
}
|
||||
import ietf-interfaces {
|
||||
prefix if;
|
||||
}
|
||||
@@ -15,6 +12,12 @@ module infix-interfaces {
|
||||
import ietf-inet-types {
|
||||
prefix inet;
|
||||
}
|
||||
import ietf-keystore {
|
||||
prefix ks;
|
||||
}
|
||||
import infix-if-type {
|
||||
prefix infix-ift;
|
||||
}
|
||||
|
||||
include infix-if-base;
|
||||
include infix-if-bridge;
|
||||
@@ -24,12 +27,18 @@ module infix-interfaces {
|
||||
include infix-if-vlan;
|
||||
include infix-if-gre;
|
||||
include infix-if-vxlan;
|
||||
include infix-if-wifi;
|
||||
|
||||
organization "KernelKit";
|
||||
contact "kernelkit@googlegroups.com";
|
||||
description "Linux bridge and lag extensions for ietf-interfaces.";
|
||||
|
||||
revision 2025-01-09 {
|
||||
revision 2025-06-17 {
|
||||
description "Add support for Wi-Fi client.";
|
||||
reference "internal";
|
||||
}
|
||||
|
||||
revision 2025-01-09 {
|
||||
description "Add support for link aggregation, static and LACP.";
|
||||
reference "internal";
|
||||
}
|
||||
|
||||
@@ -5,9 +5,15 @@ module infix-keystore {
|
||||
import ietf-keystore {
|
||||
prefix ks;
|
||||
}
|
||||
import ietf-crypto-types {
|
||||
prefix ct;
|
||||
}
|
||||
import infix-crypto-types {
|
||||
prefix infix-ct;
|
||||
}
|
||||
revision 2025-06-17 {
|
||||
description "Add Wi-Fi secrets support";
|
||||
}
|
||||
revision 2025-02-04 {
|
||||
description "Initial";
|
||||
}
|
||||
@@ -25,4 +31,35 @@ module infix-keystore {
|
||||
}
|
||||
}
|
||||
}
|
||||
deviation "/ks:keystore/ks:symmetric-keys/ks:symmetric-key/ks:key-format" {
|
||||
deviate not-supported;
|
||||
}
|
||||
augment "/ks:keystore/ks:symmetric-keys/ks:symmetric-key" {
|
||||
leaf key-format {
|
||||
type identityref {
|
||||
base infix-ct:symmetric-key-format;
|
||||
}
|
||||
description
|
||||
"Identifies the symmetric key's format
|
||||
|
||||
Valid symmetric key formats are:
|
||||
wifi-preshared-key-format - WiFi preshared key";
|
||||
}
|
||||
}
|
||||
deviation "/ks:keystore/ks:symmetric-keys/ks:symmetric-key/ks:key-type/ks:cleartext-key/ks:cleartext-key" {
|
||||
deviate not-supported;
|
||||
}
|
||||
augment "/ks:keystore/ks:symmetric-keys/ks:symmetric-key/ks:key-type" {
|
||||
case cleartext-key {
|
||||
leaf cleartext-key {
|
||||
type string;
|
||||
must "../../ks:key-format != 'infix-ct:wifi-preshared-key-format' or " +
|
||||
"(string-length(.) >= 8 and string-length(.) <= 63)" {
|
||||
error-message "WiFi pre-shared key must be 8-63 characters long";
|
||||
}
|
||||
description "WiFi pre-shared key: 8-63 printable ASCII characters";
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,10 +3,15 @@ module infix-meta {
|
||||
namespace "urn:infix:meta:ns:yang:1.0";
|
||||
prefix infix-meta;
|
||||
|
||||
import ietf-yang-metadata {
|
||||
prefix md;
|
||||
}
|
||||
|
||||
organization "KernelKit";
|
||||
contact "kernelkit@googlegroups.com";
|
||||
description "Infix metadata.";
|
||||
|
||||
|
||||
revision 2024-10-18 {
|
||||
description "Mark entire meta container obsolete.";
|
||||
reference "internal";
|
||||
@@ -16,6 +21,12 @@ module infix-meta {
|
||||
reference "internal";
|
||||
}
|
||||
|
||||
md:annotation dirty {
|
||||
type string;
|
||||
description
|
||||
"data";
|
||||
}
|
||||
|
||||
container meta {
|
||||
description "Meta data";
|
||||
status obsolete;
|
||||
|
||||
@@ -0,0 +1,287 @@
|
||||
module infix-wifi-country-codes {
|
||||
yang-version 1.1;
|
||||
namespace "urn:infix:wifi-country-codes";
|
||||
prefix iwcc;
|
||||
|
||||
organization "KernelKit";
|
||||
|
||||
contact "kernelkit@googlegroups.com";
|
||||
|
||||
description
|
||||
"This module defines country codes for WiFi regulatory domain
|
||||
configuration based on ISO 3166-1 alpha-2 standard.
|
||||
|
||||
This model provides country code definitions for use in
|
||||
802.11 wireless LAN regulatory compliance configuration.
|
||||
|
||||
The regulatory domain configuration follows the principles
|
||||
established in IETF RFCs for wireless access point management.";
|
||||
|
||||
revision 2025-06-02 {
|
||||
description
|
||||
"Initial revision for WiFi country code support.";
|
||||
reference
|
||||
"RFC 5415: Control And Provisioning of Wireless Access Points (CAPWAP) Protocol Specification
|
||||
RFC 5416: Control and Provisioning of Wireless Access Points (CAPWAP) Protocol Binding for IEEE 802.11";
|
||||
}
|
||||
|
||||
typedef country-code {
|
||||
type enumeration {
|
||||
enum "AD" { description "Andorra"; }
|
||||
enum "AE" { description "United Arab Emirates"; }
|
||||
enum "AF" { description "Afghanistan"; }
|
||||
enum "AG" { description "Antigua and Barbuda"; }
|
||||
enum "AI" { description "Anguilla"; }
|
||||
enum "AL" { description "Albania"; }
|
||||
enum "AM" { description "Armenia"; }
|
||||
enum "AO" { description "Angola"; }
|
||||
enum "AQ" { description "Antarctica"; }
|
||||
enum "AR" { description "Argentina"; }
|
||||
enum "AS" { description "American Samoa"; }
|
||||
enum "AT" { description "Austria"; }
|
||||
enum "AU" { description "Australia"; }
|
||||
enum "AW" { description "Aruba"; }
|
||||
enum "AX" { description "Åland Islands"; }
|
||||
enum "AZ" { description "Azerbaijan"; }
|
||||
enum "BA" { description "Bosnia and Herzegovina"; }
|
||||
enum "BB" { description "Barbados"; }
|
||||
enum "BD" { description "Bangladesh"; }
|
||||
enum "BE" { description "Belgium"; }
|
||||
enum "BF" { description "Burkina Faso"; }
|
||||
enum "BG" { description "Bulgaria"; }
|
||||
enum "BH" { description "Bahrain"; }
|
||||
enum "BI" { description "Burundi"; }
|
||||
enum "BJ" { description "Benin"; }
|
||||
enum "BL" { description "Saint Barthélemy"; }
|
||||
enum "BM" { description "Bermuda"; }
|
||||
enum "BN" { description "Brunei Darussalam"; }
|
||||
enum "BO" { description "Bolivia"; }
|
||||
enum "BQ" { description "Bonaire, Sint Eustatius and Saba"; }
|
||||
enum "BR" { description "Brazil"; }
|
||||
enum "BS" { description "Bahamas"; }
|
||||
enum "BT" { description "Bhutan"; }
|
||||
enum "BV" { description "Bouvet Island"; }
|
||||
enum "BW" { description "Botswana"; }
|
||||
enum "BY" { description "Belarus"; }
|
||||
enum "BZ" { description "Belize"; }
|
||||
enum "CA" { description "Canada"; }
|
||||
enum "CC" { description "Cocos (Keeling) Islands"; }
|
||||
enum "CD" { description "Congo, Democratic Republic of the"; }
|
||||
enum "CF" { description "Central African Republic"; }
|
||||
enum "CG" { description "Congo"; }
|
||||
enum "CH" { description "Switzerland"; }
|
||||
enum "CI" { description "Côte d'Ivoire"; }
|
||||
enum "CK" { description "Cook Islands"; }
|
||||
enum "CL" { description "Chile"; }
|
||||
enum "CM" { description "Cameroon"; }
|
||||
enum "CN" { description "China"; }
|
||||
enum "CO" { description "Colombia"; }
|
||||
enum "CR" { description "Costa Rica"; }
|
||||
enum "CU" { description "Cuba"; }
|
||||
enum "CV" { description "Cabo Verde"; }
|
||||
enum "CW" { description "Curaçao"; }
|
||||
enum "CX" { description "Christmas Island"; }
|
||||
enum "CY" { description "Cyprus"; }
|
||||
enum "CZ" { description "Czechia"; }
|
||||
enum "DE" { description "Germany"; }
|
||||
enum "DJ" { description "Djibouti"; }
|
||||
enum "DK" { description "Denmark"; }
|
||||
enum "DM" { description "Dominica"; }
|
||||
enum "DO" { description "Dominican Republic"; }
|
||||
enum "DZ" { description "Algeria"; }
|
||||
enum "EC" { description "Ecuador"; }
|
||||
enum "EE" { description "Estonia"; }
|
||||
enum "EG" { description "Egypt"; }
|
||||
enum "EH" { description "Western Sahara"; }
|
||||
enum "ER" { description "Eritrea"; }
|
||||
enum "ES" { description "Spain"; }
|
||||
enum "ET" { description "Ethiopia"; }
|
||||
enum "FI" { description "Finland"; }
|
||||
enum "FJ" { description "Fiji"; }
|
||||
enum "FK" { description "Falkland Islands (Malvinas)"; }
|
||||
enum "FM" { description "Micronesia"; }
|
||||
enum "FO" { description "Faroe Islands"; }
|
||||
enum "FR" { description "France"; }
|
||||
enum "GA" { description "Gabon"; }
|
||||
enum "GB" { description "United Kingdom"; }
|
||||
enum "GD" { description "Grenada"; }
|
||||
enum "GE" { description "Georgia"; }
|
||||
enum "GF" { description "French Guiana"; }
|
||||
enum "GG" { description "Guernsey"; }
|
||||
enum "GH" { description "Ghana"; }
|
||||
enum "GI" { description "Gibraltar"; }
|
||||
enum "GL" { description "Greenland"; }
|
||||
enum "GM" { description "Gambia"; }
|
||||
enum "GN" { description "Guinea"; }
|
||||
enum "GP" { description "Guadeloupe"; }
|
||||
enum "GQ" { description "Equatorial Guinea"; }
|
||||
enum "GR" { description "Greece"; }
|
||||
enum "GS" { description "South Georgia and the South Sandwich Islands"; }
|
||||
enum "GT" { description "Guatemala"; }
|
||||
enum "GU" { description "Guam"; }
|
||||
enum "GW" { description "Guinea-Bissau"; }
|
||||
enum "GY" { description "Guyana"; }
|
||||
enum "HK" { description "Hong Kong"; }
|
||||
enum "HM" { description "Heard Island and McDonald Islands"; }
|
||||
enum "HN" { description "Honduras"; }
|
||||
enum "HR" { description "Croatia"; }
|
||||
enum "HT" { description "Haiti"; }
|
||||
enum "HU" { description "Hungary"; }
|
||||
enum "ID" { description "Indonesia"; }
|
||||
enum "IE" { description "Ireland"; }
|
||||
enum "IL" { description "Israel"; }
|
||||
enum "IM" { description "Isle of Man"; }
|
||||
enum "IN" { description "India"; }
|
||||
enum "IO" { description "British Indian Ocean Territory"; }
|
||||
enum "IQ" { description "Iraq"; }
|
||||
enum "IR" { description "Iran"; }
|
||||
enum "IS" { description "Iceland"; }
|
||||
enum "IT" { description "Italy"; }
|
||||
enum "JE" { description "Jersey"; }
|
||||
enum "JM" { description "Jamaica"; }
|
||||
enum "JO" { description "Jordan"; }
|
||||
enum "JP" { description "Japan"; }
|
||||
enum "KE" { description "Kenya"; }
|
||||
enum "KG" { description "Kyrgyzstan"; }
|
||||
enum "KH" { description "Cambodia"; }
|
||||
enum "KI" { description "Kiribati"; }
|
||||
enum "KM" { description "Comoros"; }
|
||||
enum "KN" { description "Saint Kitts and Nevis"; }
|
||||
enum "KP" { description "Korea, Democratic People's Republic of"; }
|
||||
enum "KR" { description "Korea, Republic of"; }
|
||||
enum "KW" { description "Kuwait"; }
|
||||
enum "KY" { description "Cayman Islands"; }
|
||||
enum "KZ" { description "Kazakhstan"; }
|
||||
enum "LA" { description "Lao People's Democratic Republic"; }
|
||||
enum "LB" { description "Lebanon"; }
|
||||
enum "LC" { description "Saint Lucia"; }
|
||||
enum "LI" { description "Liechtenstein"; }
|
||||
enum "LK" { description "Sri Lanka"; }
|
||||
enum "LR" { description "Liberia"; }
|
||||
enum "LS" { description "Lesotho"; }
|
||||
enum "LT" { description "Lithuania"; }
|
||||
enum "LU" { description "Luxembourg"; }
|
||||
enum "LV" { description "Latvia"; }
|
||||
enum "LY" { description "Libya"; }
|
||||
enum "MA" { description "Morocco"; }
|
||||
enum "MC" { description "Monaco"; }
|
||||
enum "MD" { description "Moldova"; }
|
||||
enum "ME" { description "Montenegro"; }
|
||||
enum "MF" { description "Saint Martin (French part)"; }
|
||||
enum "MG" { description "Madagascar"; }
|
||||
enum "MH" { description "Marshall Islands"; }
|
||||
enum "MK" { description "North Macedonia"; }
|
||||
enum "ML" { description "Mali"; }
|
||||
enum "MM" { description "Myanmar"; }
|
||||
enum "MN" { description "Mongolia"; }
|
||||
enum "MO" { description "Macao"; }
|
||||
enum "MP" { description "Northern Mariana Islands"; }
|
||||
enum "MQ" { description "Martinique"; }
|
||||
enum "MR" { description "Mauritania"; }
|
||||
enum "MS" { description "Montserrat"; }
|
||||
enum "MT" { description "Malta"; }
|
||||
enum "MU" { description "Mauritius"; }
|
||||
enum "MV" { description "Maldives"; }
|
||||
enum "MW" { description "Malawi"; }
|
||||
enum "MX" { description "Mexico"; }
|
||||
enum "MY" { description "Malaysia"; }
|
||||
enum "MZ" { description "Mozambique"; }
|
||||
enum "NA" { description "Namibia"; }
|
||||
enum "NC" { description "New Caledonia"; }
|
||||
enum "NE" { description "Niger"; }
|
||||
enum "NF" { description "Norfolk Island"; }
|
||||
enum "NG" { description "Nigeria"; }
|
||||
enum "NI" { description "Nicaragua"; }
|
||||
enum "NL" { description "Netherlands"; }
|
||||
enum "NO" { description "Norway"; }
|
||||
enum "NP" { description "Nepal"; }
|
||||
enum "NR" { description "Nauru"; }
|
||||
enum "NU" { description "Niue"; }
|
||||
enum "NZ" { description "New Zealand"; }
|
||||
enum "OM" { description "Oman"; }
|
||||
enum "PA" { description "Panama"; }
|
||||
enum "PE" { description "Peru"; }
|
||||
enum "PF" { description "French Polynesia"; }
|
||||
enum "PG" { description "Papua New Guinea"; }
|
||||
enum "PH" { description "Philippines"; }
|
||||
enum "PK" { description "Pakistan"; }
|
||||
enum "PL" { description "Poland"; }
|
||||
enum "PM" { description "Saint Pierre and Miquelon"; }
|
||||
enum "PN" { description "Pitcairn"; }
|
||||
enum "PR" { description "Puerto Rico"; }
|
||||
enum "PS" { description "Palestine, State of"; }
|
||||
enum "PT" { description "Portugal"; }
|
||||
enum "PW" { description "Palau"; }
|
||||
enum "PY" { description "Paraguay"; }
|
||||
enum "QA" { description "Qatar"; }
|
||||
enum "RE" { description "Réunion"; }
|
||||
enum "RO" { description "Romania"; }
|
||||
enum "RS" { description "Serbia"; }
|
||||
enum "RU" { description "Russian Federation"; }
|
||||
enum "RW" { description "Rwanda"; }
|
||||
enum "SA" { description "Saudi Arabia"; }
|
||||
enum "SB" { description "Solomon Islands"; }
|
||||
enum "SC" { description "Seychelles"; }
|
||||
enum "SD" { description "Sudan"; }
|
||||
enum "SE" { description "Sweden"; }
|
||||
enum "SG" { description "Singapore"; }
|
||||
enum "SH" { description "Saint Helena, Ascension and Tristan da Cunha"; }
|
||||
enum "SI" { description "Slovenia"; }
|
||||
enum "SJ" { description "Svalbard and Jan Mayen"; }
|
||||
enum "SK" { description "Slovakia"; }
|
||||
enum "SL" { description "Sierra Leone"; }
|
||||
enum "SM" { description "San Marino"; }
|
||||
enum "SN" { description "Senegal"; }
|
||||
enum "SO" { description "Somalia"; }
|
||||
enum "SR" { description "Suriname"; }
|
||||
enum "SS" { description "South Sudan"; }
|
||||
enum "ST" { description "Sao Tome and Principe"; }
|
||||
enum "SV" { description "El Salvador"; }
|
||||
enum "SX" { description "Sint Maarten (Dutch part)"; }
|
||||
enum "SY" { description "Syrian Arab Republic"; }
|
||||
enum "SZ" { description "Eswatini"; }
|
||||
enum "TC" { description "Turks and Caicos Islands"; }
|
||||
enum "TD" { description "Chad"; }
|
||||
enum "TF" { description "French Southern Territories"; }
|
||||
enum "TG" { description "Togo"; }
|
||||
enum "TH" { description "Thailand"; }
|
||||
enum "TJ" { description "Tajikistan"; }
|
||||
enum "TK" { description "Tokelau"; }
|
||||
enum "TL" { description "Timor-Leste"; }
|
||||
enum "TM" { description "Turkmenistan"; }
|
||||
enum "TN" { description "Tunisia"; }
|
||||
enum "TO" { description "Tonga"; }
|
||||
enum "TR" { description "Turkey"; }
|
||||
enum "TT" { description "Trinidad and Tobago"; }
|
||||
enum "TV" { description "Tuvalu"; }
|
||||
enum "TW" { description "Taiwan"; }
|
||||
enum "TZ" { description "Tanzania"; }
|
||||
enum "UA" { description "Ukraine"; }
|
||||
enum "UG" { description "Uganda"; }
|
||||
enum "UM" { description "United States Minor Outlying Islands"; }
|
||||
enum "US" { description "United States of America"; }
|
||||
enum "UY" { description "Uruguay"; }
|
||||
enum "UZ" { description "Uzbekistan"; }
|
||||
enum "VA" { description "Holy See (Vatican City State)"; }
|
||||
enum "VC" { description "Saint Vincent and the Grenadines"; }
|
||||
enum "VE" { description "Venezuela"; }
|
||||
enum "VG" { description "Virgin Islands, British"; }
|
||||
enum "VI" { description "Virgin Islands, U.S."; }
|
||||
enum "VN" { description "Viet Nam"; }
|
||||
enum "VU" { description "Vanuatu"; }
|
||||
enum "WF" { description "Wallis and Futuna"; }
|
||||
enum "WS" { description "Samoa"; }
|
||||
enum "YE" { description "Yemen"; }
|
||||
enum "YT" { description "Mayotte"; }
|
||||
enum "ZA" { description "South Africa"; }
|
||||
enum "ZM" { description "Zambia"; }
|
||||
enum "ZW" { description "Zimbabwe"; }
|
||||
}
|
||||
description
|
||||
"Complete list of ISO 3166-1 alpha-2 country codes for
|
||||
regulatory domain configuration.";
|
||||
reference
|
||||
"ISO 3166-1:2020 Codes for the representation of names of countries
|
||||
and their subdivisions -- Part 1: Country codes";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
infix-wifi-country-codes.yang
|
||||
@@ -1,6 +1,5 @@
|
||||
# -*- sh -*-
|
||||
# REMEMBER TO UPDATE infix-interfaces ALSO IN confd.inc
|
||||
MODULES=(
|
||||
"infix-interfaces@2025-01-09.yang -e vlan-filtering -e containers"
|
||||
"infix-interfaces -e containers"
|
||||
"infix-containers@2025-05-14.yang"
|
||||
)
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
MODULES=(
|
||||
"infix-interfaces -e wifi"
|
||||
"infix-if-type -e wifi"
|
||||
)
|
||||
@@ -164,6 +164,20 @@ def lldp(args: List[str]):
|
||||
return
|
||||
cli_pretty(data, "show-lldp")
|
||||
|
||||
def wifi(args: List[str]):
|
||||
iface = args[0]
|
||||
if len(args) == 0:
|
||||
print("Illigal usage")
|
||||
return
|
||||
if is_valid_interface_name(iface):
|
||||
if not os.path.exists(f"/sys/class/net/{iface}/wireless"):
|
||||
print("Not a Wi-Fi interface")
|
||||
return
|
||||
data = run_sysrepocfg("/ietf-interfaces:interfaces")
|
||||
cli_pretty(data, "show-wifi-scan", "-n", iface)
|
||||
else:
|
||||
print(f"Invalid interface name: {iface}")
|
||||
|
||||
def execute_command(command: str, args: List[str]):
|
||||
command_mapping = {
|
||||
'dhcp': dhcp,
|
||||
@@ -174,6 +188,7 @@ def execute_command(command: str, args: List[str]):
|
||||
'lldp': lldp,
|
||||
'software' : software,
|
||||
'stp': stp,
|
||||
'wifi': wifi
|
||||
}
|
||||
|
||||
if command in command_mapping:
|
||||
|
||||
@@ -82,6 +82,20 @@ class PadNtpSource:
|
||||
poll = 14
|
||||
|
||||
|
||||
class PadWifiScan:
|
||||
ssid = 40
|
||||
encryption = 30
|
||||
signal = 9
|
||||
|
||||
|
||||
class PadLldp:
|
||||
interface = 16
|
||||
rem_idx = 10
|
||||
time = 12
|
||||
chassis_id = 20
|
||||
port_id = 20
|
||||
|
||||
|
||||
class Decore():
|
||||
@staticmethod
|
||||
def decorate(sgr, txt, restore="0"):
|
||||
@@ -103,6 +117,10 @@ class Decore():
|
||||
def green(txt):
|
||||
return Decore.decorate("32", txt, "39")
|
||||
|
||||
@staticmethod
|
||||
def bright_green(txt):
|
||||
return Decore.decorate("1;32", txt, "39")
|
||||
|
||||
@staticmethod
|
||||
def yellow(txt):
|
||||
return Decore.decorate("33", txt, "39")
|
||||
@@ -116,12 +134,17 @@ class Decore():
|
||||
return Decore.decorate("100", txt)
|
||||
|
||||
|
||||
class PadLldp:
|
||||
interface = 16
|
||||
rem_idx = 10
|
||||
time = 12
|
||||
chassis_id = 20
|
||||
port_id = 20
|
||||
def rssi_to_status(rssi):
|
||||
if rssi <= -75:
|
||||
status = Decore.bright_green("excellent")
|
||||
elif rssi <= -65:
|
||||
status = Decore.green("good")
|
||||
elif rssi <= -50:
|
||||
status = Decore.yellow("poor")
|
||||
else:
|
||||
status = Decore.red("bad")
|
||||
|
||||
return status
|
||||
|
||||
|
||||
def datetime_now():
|
||||
@@ -196,7 +219,6 @@ class Date(datetime):
|
||||
tz = tz.replace(":", "")
|
||||
return cls.strptime(f"{date}+{tz}", "%Y-%m-%dT%H:%M:%S%z")
|
||||
|
||||
|
||||
class Route:
|
||||
def __init__(self, data, ip):
|
||||
self.data = data
|
||||
@@ -524,12 +546,16 @@ class Iface:
|
||||
|
||||
self.gre = self.data.get('infix-interfaces:gre')
|
||||
self.vxlan = self.data.get('infix-interfaces:vxlan')
|
||||
self.wifi = self.data.get('infix-interfaces:wifi')
|
||||
|
||||
if self.data.get('infix-interfaces:vlan'):
|
||||
self.lower_if = self.data.get('infix-interfaces:vlan', None).get('lower-layer-if',None)
|
||||
else:
|
||||
self.lower_if = ''
|
||||
|
||||
def is_wifi(self):
|
||||
return self.type == "infix-if-type:wifi"
|
||||
|
||||
def is_vlan(self):
|
||||
return self.type == "infix-if-type:vlan"
|
||||
|
||||
@@ -554,7 +580,7 @@ class Iface:
|
||||
|
||||
def is_gretap(self):
|
||||
return self.data['type'] == "infix-if-type:gretap"
|
||||
|
||||
|
||||
def oper(self, detail=False):
|
||||
"""Remap in brief overview to fit column widths."""
|
||||
if not detail and self.oper_status == "lower-layer-down":
|
||||
@@ -625,6 +651,47 @@ class Iface:
|
||||
row = self._pr_proto_common("loopback", False, pipe);
|
||||
print(row)
|
||||
|
||||
def pr_wifi_ssids(self):
|
||||
hdr = (f"{'SSID':<{PadWifiScan.ssid}}"
|
||||
f"{'ENCRYPTION':<{PadWifiScan.encryption}}"
|
||||
f"{'SIGNAL':<{PadWifiScan.signal}}"
|
||||
)
|
||||
|
||||
print(Decore.invert(hdr))
|
||||
results=self.wifi.get("scan-results", {})
|
||||
for result in results:
|
||||
encstr = ",".join(result["encryption"])
|
||||
status=rssi_to_status(result["rssi"])
|
||||
row = f"{result['ssid']:<{PadWifiScan.ssid}}"
|
||||
row += f"{encstr:<{PadWifiScan.encryption}}"
|
||||
row += f"{status:<{PadWifiScan.signal}}"
|
||||
|
||||
print(row)
|
||||
|
||||
|
||||
def pr_proto_wifi(self, pipe=''):
|
||||
row = self._pr_proto_common("ethernet", True, pipe);
|
||||
print(row)
|
||||
ssid = None
|
||||
rssi = None
|
||||
|
||||
if self.wifi:
|
||||
rssi=self.wifi.get("rssi")
|
||||
ssid=self.wifi.get("ssid")
|
||||
if ssid is None:
|
||||
ssid="------"
|
||||
|
||||
if rssi is None:
|
||||
signal="------"
|
||||
else:
|
||||
signal=rssi_to_status(rssi)
|
||||
data_str = f"ssid: {ssid}, signal: {signal}"
|
||||
|
||||
row = f"{'':<{Pad.iface}}"
|
||||
row += f"{'wifi':<{Pad.proto}}"
|
||||
row += f"{'':<{Pad.state}}{data_str}"
|
||||
print(row)
|
||||
|
||||
def pr_proto_br(self, br_vlans):
|
||||
data_str = ""
|
||||
|
||||
@@ -765,6 +832,12 @@ class Iface:
|
||||
self.pr_proto_ipv4()
|
||||
self.pr_proto_ipv6()
|
||||
|
||||
def pr_wifi(self):
|
||||
self.pr_name(pipe="")
|
||||
self.pr_proto_wifi()
|
||||
self.pr_proto_ipv4()
|
||||
self.pr_proto_ipv6()
|
||||
|
||||
def pr_vlan(self, _ifaces):
|
||||
self.pr_name(pipe="")
|
||||
self.pr_proto_eth()
|
||||
@@ -874,6 +947,14 @@ class Iface:
|
||||
else:
|
||||
print(f"{'ipv6 addresses':<{20}}:")
|
||||
|
||||
if self.wifi:
|
||||
ssid=self.wifi.get('ssid', "----")
|
||||
rssi=self.wifi.get('rssi', "----")
|
||||
print(f"{'SSID':<{20}}: {ssid}")
|
||||
print(f"{'Signal':<{20}}: {rssi}")
|
||||
print("")
|
||||
self.pr_wifi_ssids()
|
||||
|
||||
if self.gre:
|
||||
print(f"{'local address':<{20}}: {self.gre['local']}")
|
||||
print(f"{'remote address':<{20}}: {self.gre['remote']}")
|
||||
@@ -1045,6 +1126,10 @@ def pr_interface_list(json):
|
||||
iface.pr_vxlan()
|
||||
continue
|
||||
|
||||
if iface.is_wifi():
|
||||
iface.pr_wifi()
|
||||
continue
|
||||
|
||||
if iface.is_vlan():
|
||||
iface.pr_vlan(ifaces)
|
||||
continue
|
||||
@@ -1320,13 +1405,13 @@ def show_lldp(json):
|
||||
f"{'CHASSIS-ID':<{PadLldp.chassis_id}}"
|
||||
f"{'PORT-ID':<{PadLldp.port_id}}"
|
||||
)
|
||||
|
||||
|
||||
print(Decore.invert(header))
|
||||
|
||||
for port_data in lldp_ports:
|
||||
port_name = port_data["name"]
|
||||
neighbors = port_data.get("remote-systems-data", [])
|
||||
|
||||
|
||||
for neighbor in neighbors:
|
||||
entry = LldpNeighbor(port_name, neighbor)
|
||||
entry.print()
|
||||
@@ -1394,6 +1479,7 @@ def main():
|
||||
show_routing_table(json_data, args.ip)
|
||||
elif args.command == "show-software":
|
||||
show_software(json_data, args.name)
|
||||
|
||||
else:
|
||||
print(f"Error, unknown command '{args.command}'")
|
||||
sys.exit(1)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
from ..host import HOST
|
||||
from . import common
|
||||
|
||||
from . import bridge
|
||||
@@ -7,6 +8,7 @@ from . import lag
|
||||
from . import tun
|
||||
from . import veth
|
||||
from . import vlan
|
||||
from . import wifi
|
||||
|
||||
|
||||
def statistics(iplink):
|
||||
@@ -24,13 +26,16 @@ def statistics(iplink):
|
||||
|
||||
|
||||
def iplink2yang_type(iplink):
|
||||
ifname=iplink["ifname"]
|
||||
match iplink["link_type"]:
|
||||
case "loopback":
|
||||
return "infix-if-type:loopback"
|
||||
case "gre"|"gre6":
|
||||
return "infix-if-type:gre"
|
||||
case "ether":
|
||||
pass
|
||||
data = HOST.run(tuple(f"ls /sys/class/net/{ifname}/wireless/".split()), default="no")
|
||||
if data != "no":
|
||||
return "infix-if-type:wifi"
|
||||
case _:
|
||||
return "infix-if-type:other"
|
||||
|
||||
@@ -133,6 +138,9 @@ def interface(iplink, ipaddr):
|
||||
case "infix-if-type:vlan":
|
||||
if v := vlan.vlan(iplink):
|
||||
interface["infix-interfaces:vlan"] = v
|
||||
case "infix-if-type:wifi":
|
||||
if w := wifi.wifi(iplink["ifname"]):
|
||||
interface["infix-interfaces:wifi"] = w
|
||||
|
||||
match iplink2yang_lower(iplink):
|
||||
case "infix-interfaces:bridge-port":
|
||||
|
||||
@@ -0,0 +1,160 @@
|
||||
from ..host import HOST
|
||||
import json
|
||||
import re
|
||||
|
||||
def wifi(ifname):
|
||||
data=HOST.run(tuple(f"wpa_cli -i {ifname} status".split()), default="")
|
||||
wifi_data={}
|
||||
|
||||
if data != "":
|
||||
for line in data.splitlines():
|
||||
k,v = line.split("=")
|
||||
if k == "ssid":
|
||||
wifi_data["ssid"] = v
|
||||
if k == "wpa_state" and v == "DISCONNECTED": # wpa_suppicant has most likely restarted, restart scanning
|
||||
HOST.run(tuple(f"wpa_cli -i {ifname} scan".split()), default="")
|
||||
|
||||
data=HOST.run(tuple(f"wpa_cli -i {ifname} signal_poll".split()), default="FAIL")
|
||||
|
||||
# signal_poll return FAIL not connected
|
||||
if data.strip() != "FAIL":
|
||||
for line in data.splitlines():
|
||||
k,v = line.strip().split("=")
|
||||
if k == "RSSI":
|
||||
wifi_data["rssi"]=int(v)
|
||||
data=HOST.run(tuple(f"wpa_cli -i {ifname} scan_result".split()), default="FAIL")
|
||||
|
||||
if data != "FAIL":
|
||||
wifi_data["scan-results"] = parse_wpa_scan_result(data)
|
||||
|
||||
return wifi_data
|
||||
|
||||
|
||||
def parse_wpa_scan_result(scan_output):
|
||||
networks = {}
|
||||
lines = scan_output.strip().split('\n')
|
||||
|
||||
# Skip header line and any empty lines
|
||||
for line in lines:
|
||||
line = line.strip()
|
||||
if not line or 'bssid / frequency' in line.lower():
|
||||
continue
|
||||
|
||||
# Split by tabs or multiple spaces
|
||||
parts = re.split(r'\t+|\s{2,}', line)
|
||||
|
||||
if len(parts) >= 5:
|
||||
bssid = parts[0].strip()
|
||||
frequency = int(parts[1].strip())
|
||||
rssi = int(parts[2].strip())
|
||||
flags = parts[3].strip()
|
||||
ssid = parts[4].strip() if len(parts) > 4 else ""
|
||||
|
||||
# Skip hidden SSIDs (empty or whitespace only)
|
||||
if not ssid or ssid.isspace() or '\\x00' in ssid:
|
||||
continue
|
||||
|
||||
# Extract encryption information from flags
|
||||
encryption = extract_encryption(flags)
|
||||
|
||||
# Convert frequency to channel
|
||||
channel = frequency_to_channel(frequency)
|
||||
|
||||
# Keep only the network with best (highest) RSSI per SSID
|
||||
if ssid not in networks or rssi < networks[ssid]['rssi']:
|
||||
networks[ssid] = {
|
||||
'bssid': bssid,
|
||||
'ssid': ssid,
|
||||
'rssi': rssi,
|
||||
'encryption': encryption,
|
||||
'channel': channel
|
||||
}
|
||||
# Convert to list and sort by RSSI (best first)
|
||||
result = list(networks.values())
|
||||
result.sort(key=lambda x: x['rssi'], reverse=False)
|
||||
|
||||
return result
|
||||
|
||||
def frequency_to_channel(frequency):
|
||||
"""Convert frequency (MHz) to WiFi channel number"""
|
||||
freq = int(frequency)
|
||||
|
||||
# 2.4 GHz band (channels 1-14)
|
||||
if 2412 <= freq <= 2484: # Channel 14 is special
|
||||
if freq == 2484:
|
||||
return 14
|
||||
return (freq - 2412) // 5 + 1
|
||||
|
||||
# 5 GHz band (channels 36-165)
|
||||
elif 5170 <= freq <= 5825:
|
||||
return (freq - 5000) // 5
|
||||
|
||||
# 6 GHz band (channels 1-233)
|
||||
elif 5955 <= freq <= 7115:
|
||||
return (freq - 5950) // 5
|
||||
|
||||
else:
|
||||
return f"Unknown ({freq} MHz)"
|
||||
|
||||
def extract_encryption(flags):
|
||||
"""Extract detailed encryption information from flags string"""
|
||||
flags = flags.upper()
|
||||
encryption_info = {
|
||||
'protocols': [],
|
||||
'key_mgmt': [],
|
||||
'ciphers': [],
|
||||
'auth_type': 'Unknown'
|
||||
}
|
||||
|
||||
# Extract WPA protocols
|
||||
if 'WPA3' in flags:
|
||||
encryption_info['protocols'].append('WPA3')
|
||||
if 'WPA2' in flags:
|
||||
encryption_info['protocols'].append('WPA2')
|
||||
if 'WPA-' in flags and 'WPA2' not in flags and 'WPA3' not in flags:
|
||||
encryption_info['protocols'].append('WPA')
|
||||
|
||||
# Extract key management methods
|
||||
if 'PSK' in flags:
|
||||
encryption_info['key_mgmt'].append('PSK')
|
||||
encryption_info['auth_type'] = 'Personal'
|
||||
if 'EAP' in flags:
|
||||
encryption_info['key_mgmt'].append('EAP')
|
||||
encryption_info['auth_type'] = 'Enterprise'
|
||||
if 'SAE' in flags: # WPA3 Personal
|
||||
encryption_info['key_mgmt'].append('SAE')
|
||||
encryption_info['auth_type'] = 'Personal'
|
||||
if 'OWE' in flags: # Enhanced Open (WPA3)
|
||||
encryption_info['key_mgmt'].append('OWE')
|
||||
encryption_info['auth_type'] = 'Enhanced Open'
|
||||
if 'FT' in flags:
|
||||
encryption_info['key_mgmt'].append('FT')
|
||||
|
||||
# Extract cipher suites
|
||||
if 'CCMP' in flags:
|
||||
encryption_info['ciphers'].append('CCMP')
|
||||
if 'TKIP' in flags:
|
||||
encryption_info['ciphers'].append('TKIP')
|
||||
if 'GCMP' in flags:
|
||||
encryption_info['ciphers'].append('GCMP')
|
||||
|
||||
# Handle special cases
|
||||
if 'WEP' in flags:
|
||||
return ['WEP']
|
||||
|
||||
if not encryption_info['protocols'] and 'ESS' in flags:
|
||||
return ['Open']
|
||||
|
||||
# Return array of supported protocols with auth type
|
||||
result = []
|
||||
for protocol in encryption_info['protocols']:
|
||||
if encryption_info['auth_type'] == 'Enterprise':
|
||||
result.append(f"{protocol}-Enterprise")
|
||||
elif encryption_info['auth_type'] == 'Personal':
|
||||
result.append(f"{protocol}-Personal")
|
||||
elif encryption_info['auth_type'] == 'Enhanced Open':
|
||||
result.append(f"{protocol}-Enhanced-Open")
|
||||
else:
|
||||
result.append(protocol)
|
||||
|
||||
return result if result else ['Unknown']
|
||||
@@ -90,7 +90,6 @@ with infamy.Test() as test:
|
||||
"interface": [
|
||||
{
|
||||
"name": server_link,
|
||||
"type": "infix-if-type:bridge",
|
||||
"enabled": True,
|
||||
"ipv4": {
|
||||
"address": [
|
||||
|
||||
+13
-6
@@ -82,7 +82,10 @@ chperm()
|
||||
|
||||
enable()
|
||||
{
|
||||
$SYSREPOCTL -c "$1" -e "$2" -v2
|
||||
local module=$1
|
||||
local feature=$2
|
||||
echo "*** Enable feature $feature in $module."
|
||||
$SYSREPOCTL -c $module -e $feature -v2
|
||||
local rc=$?
|
||||
if [ $rc -ne 0 ]; then
|
||||
exit $rc
|
||||
@@ -93,7 +96,7 @@ enable()
|
||||
SCTL_MODULES=$($SYSREPOCTL -l |tail -n +5 |head -n -3)
|
||||
|
||||
for module in "${MODULES[@]}"; do
|
||||
name=$(echo "$module" | awk -F'[@.]' '{print $1}')
|
||||
name=$(echo "$module" | awk '{match($1, /[^@.]+/); print substr($1, RSTART, RLENGTH)}')
|
||||
date=$(echo "$module" | awk -F'[@.]' '{print $2}')
|
||||
for dir in $SEARCH_PATH; do
|
||||
if [ -n "${date}" ]; then
|
||||
@@ -105,10 +108,15 @@ for module in "${MODULES[@]}"; do
|
||||
MODDIR="${dir}"
|
||||
fi
|
||||
done
|
||||
[ -z "${MODDIR}" ] && echo "Could not find ${yang} in ${SEARCH_PATH}" && exit 1
|
||||
|
||||
# If no .yang we just modfify an existing model
|
||||
if [[ "$module" == *.yang* && -z "$MODDIR" ]]; then
|
||||
echo "Could not find ${yang} in ${SEARCH_PATH}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
SCTL_MODULE=$(echo "$SCTL_MODULES" | grep "^$name \+|[^|]*| I")
|
||||
|
||||
if [ -z "$SCTL_MODULE" ]; then
|
||||
# prepare command to install module with all its features
|
||||
echo "*** Installing YANG model $name ..."
|
||||
@@ -117,7 +125,7 @@ for module in "${MODULES[@]}"; do
|
||||
fi
|
||||
|
||||
rev=$(echo "$SCTL_MODULE" | awk '{print $3}')
|
||||
if [ "$rev" != "$date" ] || echo "$FORCE_UPDATE" | grep -qw "$name"; then
|
||||
if [ -n "$date" ] && [ "$rev" != "$date" ] || echo "$FORCE_UPDATE" | grep -qw "$name"; then
|
||||
# update module without any features
|
||||
file=$(echo "$module" | cut -d' ' -f 1)
|
||||
echo "*** Updating YANG model $name ($file) ..."
|
||||
@@ -133,8 +141,7 @@ for module in "${MODULES[@]}"; do
|
||||
chperm "$name"
|
||||
fi
|
||||
|
||||
# parse sysrepoctl features and add extra space at the end for easier matching
|
||||
sctl_features="`echo "$SCTL_MODULE" | sed 's/\([^|]*|\)\{6\}\(.*\)/\2/'` "
|
||||
sctl_features="`echo "$SCTL_MODULE" | awk -F '|' '{print $NF}' | xargs`"
|
||||
# parse features we want to enable
|
||||
features=`echo "$module" | sed 's/[^ ]* \(.*\)/\1/'`
|
||||
while [ "${features:0:3}" = "-e " ]; do
|
||||
|
||||
Reference in New Issue
Block a user