This is an automated email from the ASF dual-hosted git repository.

acassis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx-apps.git

commit e7053c18a1f791767bb40d351065e64c459ca8cc
Author: Daniel P. Carvalho <[email protected]>
AuthorDate: Sun Oct 18 18:11:27 2026 -0300

    system/wifibridge: add a Wi-Fi SoftAP to Ethernet bridge command.
    
    Add the 'wifibridge' command and the netutils/wifibridge library behind
    it.  They turn a Wi-Fi interface into a SoftAP and bridge it to an
    Ethernet interface at layer 2, so that Ethernet devices reach the
    wireless network without routing.  The bridge interface itself carries
    the IP address and, optionally, a DHCP server.
    
      wifibridge start [-s ssid] [-p passphrase] [-c channel] [-3]
                       [-a ipaddr] [-d]
      wifibridge stop
      wifibridge status
    
    start sets up the SoftAP (WPA2-PSK or WPA3-SAE with CCMP) with wapi,
    creates the bridge and adds the Ethernet and Wi-Fi interfaces to it, and
    undoes everything if a step fails.  The defaults come from Kconfig.
    
    It needs NET_BRIDGE and a wireless driver that supports the master mode.
    
    Tested on an EV49N51A (PIC32MZ-W1) with the Ethernet port on a host and
    a Wi-Fi station on the SoftAP: five start/stop cycles without a memory
    leak, DHCP from the board to the station, and ping between the station
    and the Ethernet host through the bridge.  WPA3 was not tested.
    
    Assisted-by: Claude Code:claude-sonnet-5-5
    Signed-off-by: Daniel P. Carvalho <[email protected]>
---
 include/netutils/wifibridge.h       | 133 ++++++++++++++
 netutils/wifibridge/CMakeLists.txt  |  25 +++
 netutils/wifibridge/Kconfig         |  32 ++++
 netutils/wifibridge/Make.defs       |  25 +++
 netutils/wifibridge/Makefile        |  29 +++
 netutils/wifibridge/wifibridge.c    | 348 ++++++++++++++++++++++++++++++++++++
 system/wifibridge/CMakeLists.txt    |  35 ++++
 system/wifibridge/Kconfig           |  57 ++++++
 system/wifibridge/Make.defs         |  25 +++
 system/wifibridge/Makefile          |  32 ++++
 system/wifibridge/wifibridge_main.c | 202 +++++++++++++++++++++
 11 files changed, 943 insertions(+)

diff --git a/include/netutils/wifibridge.h b/include/netutils/wifibridge.h
new file mode 100644
index 000000000..f0b96996b
--- /dev/null
+++ b/include/netutils/wifibridge.h
@@ -0,0 +1,133 @@
+/****************************************************************************
+ * apps/include/netutils/wifibridge.h
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+#ifndef __APPS_INCLUDE_NETUTILS_WIFIBRIDGE_H
+#define __APPS_INCLUDE_NETUTILS_WIFIBRIDGE_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <netinet/in.h>
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+/* Security of the SoftAP */
+
+enum wifibridge_security_e
+{
+  WIFIBRIDGE_SEC_WPA2 = 0,    /* WPA2-Personal (PSK), CCMP */
+  WIFIBRIDGE_SEC_WPA3         /* WPA3-Personal (SAE), CCMP */
+};
+
+/* The bridge, its two ports and the SoftAP parameters */
+
+struct wifibridge_config_s
+{
+  FAR const char *bridge;     /* Bridge interface to create, e.g. "br0" */
+  FAR const char *ethif;      /* Ethernet port, e.g. "eth0" */
+  FAR const char *wlanif;     /* Wi-Fi port, e.g. "wlan0" */
+  FAR const char *ssid;       /* SoftAP SSID */
+  FAR const char *passphrase; /* SoftAP passphrase, 8..63 characters */
+  uint8_t channel;            /* 2.4 GHz channel, 1..13 */
+  enum wifibridge_security_e security;
+  in_addr_t ipaddr;           /* Bridge address, network byte order */
+  in_addr_t netmask;          /* Bridge netmask, network byte order */
+  bool dhcpd;                 /* Run the DHCP server on the bridge */
+};
+
+struct wifibridge_status_s
+{
+  bool exists;                /* The bridge interface exists */
+  bool eth_up;                /* The Ethernet port is up */
+  bool wlan_up;               /* The Wi-Fi port is up */
+  char ssid[33];              /* SSID the Wi-Fi port is set to */
+  struct in_addr ipaddr;      /* Bridge address */
+};
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+#ifdef __cplusplus
+#define EXTERN extern "C"
+extern "C"
+{
+#else
+#define EXTERN extern
+#endif
+
+/****************************************************************************
+ * Name: wifibridge_start
+ *
+ * Description:
+ *   Configure the Wi-Fi interface as a SoftAP, create the bridge, add the
+ *   Ethernet and Wi-Fi interfaces to it and give the bridge its address.
+ *   On failure everything done so far is undone.
+ *
+ * Returned Value:
+ *   Zero (OK) on success; a negated errno value on failure.
+ *
+ ****************************************************************************/
+
+int wifibridge_start(FAR const struct wifibridge_config_s *config);
+
+/****************************************************************************
+ * Name: wifibridge_stop
+ *
+ * Description:
+ *   Stop the DHCP server, remove the ports from the bridge, delete it and
+ *   bring the Wi-Fi interface down.
+ *
+ * Returned Value:
+ *   Zero (OK) on success; a negated errno value on failure.
+ *
+ ****************************************************************************/
+
+int wifibridge_stop(FAR const struct wifibridge_config_s *config);
+
+/****************************************************************************
+ * Name: wifibridge_status
+ *
+ * Description:
+ *   Report the state of the bridge and of its ports.
+ *
+ * Returned Value:
+ *   Zero (OK) on success; a negated errno value on failure.
+ *
+ ****************************************************************************/
+
+int wifibridge_status(FAR const struct wifibridge_config_s *config,
+                      FAR struct wifibridge_status_s *status);
+
+#undef EXTERN
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __APPS_INCLUDE_NETUTILS_WIFIBRIDGE_H */
diff --git a/netutils/wifibridge/CMakeLists.txt 
b/netutils/wifibridge/CMakeLists.txt
new file mode 100644
index 000000000..34c55abe3
--- /dev/null
+++ b/netutils/wifibridge/CMakeLists.txt
@@ -0,0 +1,25 @@
+# 
##############################################################################
+# apps/netutils/wifibridge/CMakeLists.txt
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more 
contributor
+# license agreements.  See the NOTICE file distributed with this work for
+# additional information regarding copyright ownership.  The ASF licenses this
+# file to you under the Apache License, Version 2.0 (the "License"); you may 
not
+# use this file except in compliance with the License.  You may obtain a copy 
of
+# the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations under
+# the License.
+#
+# 
##############################################################################
+
+if(CONFIG_NETUTILS_WIFIBRIDGE)
+  target_sources(apps PRIVATE wifibridge.c)
+endif()
diff --git a/netutils/wifibridge/Kconfig b/netutils/wifibridge/Kconfig
new file mode 100644
index 000000000..e7b384605
--- /dev/null
+++ b/netutils/wifibridge/Kconfig
@@ -0,0 +1,32 @@
+#
+# For a description of the syntax of this configuration file,
+# see the file kconfig-language.txt in the NuttX tools repository.
+#
+
+config NETUTILS_WIFIBRIDGE
+       bool "Wi-Fi SoftAP to Ethernet bridge"
+       default n
+       depends on NET_IPv4 && NET_BRIDGE && WIRELESS_WAPI
+       select NETUTILS_NETLIB
+       ---help---
+               Library that turns a Wi-Fi interface into a SoftAP and bridges 
it
+               to an Ethernet interface at layer 2, so that Ethernet devices
+               reach the wireless network without any routing.  The bridge
+               interface carries the IP address and, optionally, a DHCP server.
+
+               The wireless driver must support the master (SoftAP) mode and 
the
+               Ethernet driver must accept frames for any destination address
+               (NET_PROMISCUOUS).
+
+if NETUTILS_WIFIBRIDGE
+
+config NETUTILS_WIFIBRIDGE_DHCPD
+       bool "Run the DHCP server on the bridge"
+       default n
+       depends on NETUTILS_DHCPD
+       ---help---
+               Allow the library to start the DHCP server on the bridge
+               interface.  Leave it unused when another DHCP server is
+               reachable through the Ethernet port.
+
+endif # NETUTILS_WIFIBRIDGE
diff --git a/netutils/wifibridge/Make.defs b/netutils/wifibridge/Make.defs
new file mode 100644
index 000000000..ca565eec1
--- /dev/null
+++ b/netutils/wifibridge/Make.defs
@@ -0,0 +1,25 @@
+############################################################################
+# apps/netutils/wifibridge/Make.defs
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+#
+############################################################################
+
+ifneq ($(CONFIG_NETUTILS_WIFIBRIDGE),)
+CONFIGURED_APPS += $(APPDIR)/netutils/wifibridge
+endif
diff --git a/netutils/wifibridge/Makefile b/netutils/wifibridge/Makefile
new file mode 100644
index 000000000..5bb7fded7
--- /dev/null
+++ b/netutils/wifibridge/Makefile
@@ -0,0 +1,29 @@
+############################################################################
+# apps/netutils/wifibridge/Makefile
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+#
+############################################################################
+
+include $(APPDIR)/Make.defs
+
+# Wi-Fi SoftAP to Ethernet bridge
+
+CSRCS = wifibridge.c
+
+include $(APPDIR)/Application.mk
diff --git a/netutils/wifibridge/wifibridge.c b/netutils/wifibridge/wifibridge.c
new file mode 100644
index 000000000..4612f47c3
--- /dev/null
+++ b/netutils/wifibridge/wifibridge.c
@@ -0,0 +1,348 @@
+/****************************************************************************
+ * apps/netutils/wifibridge/wifibridge.c
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <sys/socket.h>
+
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <net/if.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+
+#include "netutils/netlib.h"
+#include "netutils/wifibridge.h"
+#include "wireless/wapi.h"
+
+#ifdef CONFIG_NETUTILS_WIFIBRIDGE_DHCPD
+#  include "netutils/dhcpd.h"
+#endif
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: wifibridge_setup_softap
+ *
+ * Description:
+ *   Put the Wi-Fi interface in master mode with the requested security,
+ *   channel and SSID.
+ *
+ ****************************************************************************/
+
+static int wifibridge_setup_softap(int sock,
+                                   FAR const struct wifibridge_config_s *cfg)
+{
+  size_t passlen = strnlen(cfg->passphrase, 64);
+  int version;
+  int ret;
+
+  if (passlen < 8 || passlen > 63 || cfg->channel < 1 || cfg->channel > 13)
+    {
+      return -EINVAL;
+    }
+
+  version = cfg->security == WIFIBRIDGE_SEC_WPA3 ?
+            IW_AUTH_WPA_VERSION_WPA3 : IW_AUTH_WPA_VERSION_WPA2;
+
+  ret = wapi_set_mode(sock, cfg->wlanif, WAPI_MODE_MASTER);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  ret = wpa_driver_wext_set_auth_param(sock, cfg->wlanif,
+                                       IW_AUTH_WPA_VERSION, version);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  ret = wpa_driver_wext_set_auth_param(sock, cfg->wlanif,
+                                       IW_AUTH_CIPHER_PAIRWISE,
+                                       IW_AUTH_CIPHER_CCMP);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  ret = wpa_driver_wext_set_key_ext(sock, cfg->wlanif, WPA_ALG_CCMP,
+                                    cfg->passphrase, passlen);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  ret = wapi_set_freq(sock, cfg->wlanif, cfg->channel, WAPI_FREQ_FIXED);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  return wapi_set_essid(sock, cfg->wlanif, cfg->ssid, WAPI_ESSID_ON);
+}
+
+/****************************************************************************
+ * Name: wifibridge_teardown
+ *
+ * Description:
+ *   Undo the steps of wifibridge_start() in reverse order.  Each step is
+ *   tried even if an earlier one failed, since this also cleans up a
+ *   partially started bridge.
+ *
+ ****************************************************************************/
+
+static int wifibridge_teardown(int sock,
+                               FAR const struct wifibridge_config_s *cfg)
+{
+  int ret;
+
+#ifdef CONFIG_NETUTILS_WIFIBRIDGE_DHCPD
+  dhcpd_stop();
+#endif
+
+  netlib_ifdown(cfg->bridge);
+
+  netlib_bridge_delif(cfg->bridge, cfg->wlanif);
+  netlib_bridge_delif(cfg->bridge, cfg->ethif);
+
+  ret = netlib_del_bridge(cfg->bridge);
+
+  /* Bringing the interface down does not stop the AP, an ESSID set with the
+   * off flag does.
+   */
+
+  wapi_set_essid(sock, cfg->wlanif, "", WAPI_ESSID_OFF);
+  wapi_set_ifdown(sock, cfg->wlanif);
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: wifibridge_isup
+ ****************************************************************************/
+
+static bool wifibridge_isup(int sock, FAR const char *ifname)
+{
+  int is_up;
+
+  return wapi_get_ifup(sock, ifname, &is_up) >= 0 && is_up != 0;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: wifibridge_start
+ ****************************************************************************/
+
+int wifibridge_start(FAR const struct wifibridge_config_s *config)
+{
+  struct in_addr none;
+  struct in_addr addr;
+  int sock;
+  int ret;
+
+  if (config == NULL || config->bridge == NULL || config->ethif == NULL ||
+      config->wlanif == NULL || config->ssid == NULL ||
+      config->passphrase == NULL)
+    {
+      return -EINVAL;
+    }
+
+  if (if_nametoindex(config->bridge) != 0)
+    {
+      return -EEXIST;
+    }
+
+  sock = wapi_make_socket();
+  if (sock < 0)
+    {
+      return sock;
+    }
+
+  ret = wifibridge_setup_softap(sock, config);
+  if (ret < 0)
+    {
+      goto errout;
+    }
+
+  /* The ports carry no address, only the bridge does */
+
+  none.s_addr = INADDR_ANY;
+
+  ret = netlib_set_ipv4addr(config->wlanif, &none);
+  if (ret < 0)
+    {
+      goto errout;
+    }
+
+  ret = netlib_set_ipv4addr(config->ethif, &none);
+  if (ret < 0)
+    {
+      goto errout;
+    }
+
+  /* A bridge port must be up to carry traffic */
+
+  ret = netlib_ifup(config->ethif);
+  if (ret < 0)
+    {
+      goto errout;
+    }
+
+  ret = netlib_ifup(config->wlanif);
+  if (ret < 0)
+    {
+      goto errout;
+    }
+
+  ret = netlib_add_bridge(config->bridge);
+  if (ret < 0)
+    {
+      goto errout;
+    }
+
+  ret = netlib_bridge_addif(config->bridge, config->ethif);
+  if (ret < 0)
+    {
+      goto errout_bridge;
+    }
+
+  ret = netlib_bridge_addif(config->bridge, config->wlanif);
+  if (ret < 0)
+    {
+      goto errout_bridge;
+    }
+
+  addr.s_addr = config->ipaddr;
+  ret = netlib_set_ipv4addr(config->bridge, &addr);
+  if (ret < 0)
+    {
+      goto errout_bridge;
+    }
+
+  addr.s_addr = config->netmask;
+  ret = netlib_set_ipv4netmask(config->bridge, &addr);
+  if (ret < 0)
+    {
+      goto errout_bridge;
+    }
+
+  ret = netlib_ifup(config->bridge);
+  if (ret < 0)
+    {
+      goto errout_bridge;
+    }
+
+#ifdef CONFIG_NETUTILS_WIFIBRIDGE_DHCPD
+  if (config->dhcpd)
+    {
+      ret = dhcpd_start(config->bridge);
+      if (ret < 0)
+        {
+          goto errout_bridge;
+        }
+    }
+#endif
+
+  close(sock);
+  return OK;
+
+errout_bridge:
+  wifibridge_teardown(sock, config);
+
+errout:
+  close(sock);
+  return ret;
+}
+
+/****************************************************************************
+ * Name: wifibridge_stop
+ ****************************************************************************/
+
+int wifibridge_stop(FAR const struct wifibridge_config_s *config)
+{
+  int sock;
+  int ret;
+
+  if (config == NULL || config->bridge == NULL || config->ethif == NULL ||
+      config->wlanif == NULL)
+    {
+      return -EINVAL;
+    }
+
+  sock = wapi_make_socket();
+  if (sock < 0)
+    {
+      return sock;
+    }
+
+  ret = wifibridge_teardown(sock, config);
+
+  close(sock);
+  return ret;
+}
+
+/****************************************************************************
+ * Name: wifibridge_status
+ ****************************************************************************/
+
+int wifibridge_status(FAR const struct wifibridge_config_s *config,
+                      FAR struct wifibridge_status_s *status)
+{
+  enum wapi_essid_flag_e flag;
+  int sock;
+
+  if (config == NULL || status == NULL)
+    {
+      return -EINVAL;
+    }
+
+  memset(status, 0, sizeof(*status));
+
+  sock = wapi_make_socket();
+  if (sock < 0)
+    {
+      return sock;
+    }
+
+  status->exists = netlib_get_ipv4addr(config->bridge, &status->ipaddr) >= 0;
+
+  status->eth_up  = wifibridge_isup(sock, config->ethif);
+  status->wlan_up = wifibridge_isup(sock, config->wlanif);
+
+  wapi_get_essid(sock, config->wlanif, status->ssid, &flag);
+  status->ssid[sizeof(status->ssid) - 1] = '\0';
+
+  close(sock);
+  return OK;
+}
diff --git a/system/wifibridge/CMakeLists.txt b/system/wifibridge/CMakeLists.txt
new file mode 100644
index 000000000..5bf85f22e
--- /dev/null
+++ b/system/wifibridge/CMakeLists.txt
@@ -0,0 +1,35 @@
+# 
##############################################################################
+# apps/system/wifibridge/CMakeLists.txt
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more 
contributor
+# license agreements.  See the NOTICE file distributed with this work for
+# additional information regarding copyright ownership.  The ASF licenses this
+# file to you under the Apache License, Version 2.0 (the "License"); you may 
not
+# use this file except in compliance with the License.  You may obtain a copy 
of
+# the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations under
+# the License.
+#
+# 
##############################################################################
+
+if(CONFIG_SYSTEM_WIFIBRIDGE)
+  nuttx_add_application(
+    MODULE
+    ${CONFIG_SYSTEM_WIFIBRIDGE}
+    NAME
+    wifibridge
+    STACKSIZE
+    ${CONFIG_SYSTEM_WIFIBRIDGE_STACKSIZE}
+    PRIORITY
+    ${CONFIG_SYSTEM_WIFIBRIDGE_PRIORITY}
+    SRCS
+    wifibridge_main.c)
+endif()
diff --git a/system/wifibridge/Kconfig b/system/wifibridge/Kconfig
new file mode 100644
index 000000000..96f8065cd
--- /dev/null
+++ b/system/wifibridge/Kconfig
@@ -0,0 +1,57 @@
+#
+# For a description of the syntax of this configuration file,
+# see the file kconfig-language.txt in the NuttX tools repository.
+#
+
+config SYSTEM_WIFIBRIDGE
+       tristate "Wi-Fi to Ethernet bridge 'wifibridge' command"
+       default n
+       depends on NET_IPv4 && NET_BRIDGE && WIRELESS_WAPI
+       select NETUTILS_WIFIBRIDGE
+       ---help---
+               Enable the 'wifibridge' command to start, stop and inspect a 
Wi-Fi
+               SoftAP bridged to an Ethernet interface.
+
+if SYSTEM_WIFIBRIDGE
+
+config SYSTEM_WIFIBRIDGE_PRIORITY
+       int "wifibridge task priority"
+       default 100
+
+config SYSTEM_WIFIBRIDGE_STACKSIZE
+       int "wifibridge stack size"
+       default DEFAULT_TASK_STACKSIZE
+
+config SYSTEM_WIFIBRIDGE_BRIDGE
+       string "Bridge interface name"
+       default "br0"
+
+config SYSTEM_WIFIBRIDGE_ETHIF
+       string "Ethernet interface name"
+       default "eth0"
+
+config SYSTEM_WIFIBRIDGE_WLANIF
+       string "Wi-Fi interface name"
+       default "wlan0"
+
+config SYSTEM_WIFIBRIDGE_SSID
+       string "Default SoftAP SSID"
+       default "NuttX-BR"
+
+config SYSTEM_WIFIBRIDGE_PASSPHRASE
+       string "Default SoftAP passphrase (8..63 characters)"
+       default "nuttxbridge"
+
+config SYSTEM_WIFIBRIDGE_CHANNEL
+       int "Default SoftAP 2.4 GHz channel"
+       default 6
+       range 1 13
+
+config SYSTEM_WIFIBRIDGE_IPADDR
+       hex "Default bridge IPv4 address"
+       default 0x0a000002
+       ---help---
+               Address of the bridge interface itself (the ports stay at
+               0.0.0.0).  The netmask is 255.255.255.0.
+
+endif # SYSTEM_WIFIBRIDGE
diff --git a/system/wifibridge/Make.defs b/system/wifibridge/Make.defs
new file mode 100644
index 000000000..fd642ed48
--- /dev/null
+++ b/system/wifibridge/Make.defs
@@ -0,0 +1,25 @@
+############################################################################
+# apps/system/wifibridge/Make.defs
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+#
+############################################################################
+
+ifneq ($(CONFIG_SYSTEM_WIFIBRIDGE),)
+CONFIGURED_APPS += $(APPDIR)/system/wifibridge
+endif
diff --git a/system/wifibridge/Makefile b/system/wifibridge/Makefile
new file mode 100644
index 000000000..1afc84381
--- /dev/null
+++ b/system/wifibridge/Makefile
@@ -0,0 +1,32 @@
+############################################################################
+# apps/system/wifibridge/Makefile
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.  The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+# License for the specific language governing permissions and limitations
+# under the License.
+#
+############################################################################
+
+include $(APPDIR)/Make.defs
+
+PROGNAME = wifibridge
+PRIORITY = $(CONFIG_SYSTEM_WIFIBRIDGE_PRIORITY)
+STACKSIZE = $(CONFIG_SYSTEM_WIFIBRIDGE_STACKSIZE)
+MODULE = $(CONFIG_SYSTEM_WIFIBRIDGE)
+
+MAINSRC = wifibridge_main.c
+
+include $(APPDIR)/Application.mk
diff --git a/system/wifibridge/wifibridge_main.c 
b/system/wifibridge/wifibridge_main.c
new file mode 100644
index 000000000..181d993b1
--- /dev/null
+++ b/system/wifibridge/wifibridge_main.c
@@ -0,0 +1,202 @@
+/****************************************************************************
+ * apps/system/wifibridge/wifibridge_main.c
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <arpa/inet.h>
+
+#include "netutils/wifibridge.h"
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static void wifibridge_usage(FAR const char *progname)
+{
+  fprintf(stderr, "Usage:\n");
+  fprintf(stderr, "  %s start [-s <ssid>] [-p <passphrase>] [-c <channel>]"
+          " [-3] [-a <ipaddr>] [-d]\n", progname);
+  fprintf(stderr, "  %s stop\n", progname);
+  fprintf(stderr, "  %s status\n", progname);
+  fprintf(stderr, "\nstart options:\n");
+  fprintf(stderr, "  -s  SoftAP SSID (default %s)\n",
+          CONFIG_SYSTEM_WIFIBRIDGE_SSID);
+  fprintf(stderr, "  -p  SoftAP passphrase, 8..63 characters\n");
+  fprintf(stderr, "  -c  2.4 GHz channel, 1..13 (default %d)\n",
+          CONFIG_SYSTEM_WIFIBRIDGE_CHANNEL);
+  fprintf(stderr, "  -3  WPA3-Personal instead of WPA2-PSK\n");
+  fprintf(stderr, "  -a  bridge IPv4 address, netmask 255.255.255.0\n");
+  fprintf(stderr, "  -d  run the DHCP server on the bridge\n");
+}
+
+static int wifibridge_start_cmd(FAR struct wifibridge_config_s *config,
+                                int argc, FAR char **argv)
+{
+  struct in_addr addr;
+  int option;
+  int ret;
+
+  optind = 1;
+  while ((option = getopt(argc, argv, "s:p:c:3a:d")) != ERROR)
+    {
+      switch (option)
+        {
+          case 's':
+            config->ssid = optarg;
+            break;
+
+          case 'p':
+            config->passphrase = optarg;
+            break;
+
+          case 'c':
+            config->channel = atoi(optarg);
+            break;
+
+          case '3':
+            config->security = WIFIBRIDGE_SEC_WPA3;
+            break;
+
+          case 'a':
+            if (inet_pton(AF_INET, optarg, &addr) != 1)
+              {
+                fprintf(stderr, "Invalid IPv4 address: %s\n", optarg);
+                return EXIT_FAILURE;
+              }
+
+            config->ipaddr = addr.s_addr;
+            break;
+
+          case 'd':
+#ifdef CONFIG_NETUTILS_WIFIBRIDGE_DHCPD
+            config->dhcpd = true;
+            break;
+#else
+            fprintf(stderr, "The DHCP server is not enabled\n");
+            return EXIT_FAILURE;
+#endif
+
+          default:
+            return EXIT_FAILURE;
+        }
+    }
+
+  ret = wifibridge_start(config);
+  if (ret < 0)
+    {
+      fprintf(stderr, "Failed to start the bridge: %d\n", ret);
+      return EXIT_FAILURE;
+    }
+
+  return EXIT_SUCCESS;
+}
+
+static int
+wifibridge_status_cmd(FAR const struct wifibridge_config_s *config)
+{
+  struct wifibridge_status_s status;
+  char addr[INET_ADDRSTRLEN];
+  int ret;
+
+  ret = wifibridge_status(config, &status);
+  if (ret < 0)
+    {
+      fprintf(stderr, "Failed to read the status: %d\n", ret);
+      return EXIT_FAILURE;
+    }
+
+  printf("%-5s %s", config->bridge, status.exists ? "present" : "absent");
+  if (status.exists &&
+      inet_ntop(AF_INET, &status.ipaddr, addr, sizeof(addr)) != NULL)
+    {
+      printf(" %s", addr);
+    }
+
+  printf("\n%-5s %s\n", config->ethif, status.eth_up ? "up" : "down");
+  printf("%-5s %s ssid \"%s\"\n", config->wlanif,
+         status.wlan_up ? "up" : "down", status.ssid);
+  return EXIT_SUCCESS;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: main
+ ****************************************************************************/
+
+int main(int argc, FAR char *argv[])
+{
+  struct wifibridge_config_s config;
+  int ret;
+
+  memset(&config, 0, sizeof(config));
+  config.bridge     = CONFIG_SYSTEM_WIFIBRIDGE_BRIDGE;
+  config.ethif      = CONFIG_SYSTEM_WIFIBRIDGE_ETHIF;
+  config.wlanif     = CONFIG_SYSTEM_WIFIBRIDGE_WLANIF;
+  config.ssid       = CONFIG_SYSTEM_WIFIBRIDGE_SSID;
+  config.passphrase = CONFIG_SYSTEM_WIFIBRIDGE_PASSPHRASE;
+  config.channel    = CONFIG_SYSTEM_WIFIBRIDGE_CHANNEL;
+  config.security   = WIFIBRIDGE_SEC_WPA2;
+  config.ipaddr     = htonl(CONFIG_SYSTEM_WIFIBRIDGE_IPADDR);
+  config.netmask    = htonl(0xffffff00);
+
+  if (argc < 2)
+    {
+      wifibridge_usage(argv[0]);
+      return EXIT_FAILURE;
+    }
+
+  if (strcmp(argv[1], "start") == 0)
+    {
+      return wifibridge_start_cmd(&config, argc - 1, argv + 1);
+    }
+  else if (strcmp(argv[1], "stop") == 0)
+    {
+      ret = wifibridge_stop(&config);
+      if (ret < 0)
+        {
+          fprintf(stderr, "Failed to stop the bridge: %d\n", ret);
+          return EXIT_FAILURE;
+        }
+
+      return EXIT_SUCCESS;
+    }
+  else if (strcmp(argv[1], "status") == 0)
+    {
+      return wifibridge_status_cmd(&config);
+    }
+
+  wifibridge_usage(argv[0]);
+  return EXIT_FAILURE;
+}

Reply via email to