#!/bin/bash
# sbnb-configure-networking.sh (Revised)
# Configures host networking for SBNB, dynamically detecting and supporting
# the first available Ethernet and/or WiFi interface.
# Creates a bridge interface (br0) and attaches detected interfaces.
# Includes WPA Supplicant setup for WiFi.
# Aims for idempotency and provides informative output.
#
# To integrate with SBNB, this script can be added to the ESP partition
# as sbnb-cmds.sh during the SBNB installation process.
# --- Configuration Variables ---
# Adjust if wpa_supplicant is elsewhere or a different group is needed
WPA_SUPPLICANT_PATH=$(command -v wpa_supplicant)
WPA_CTRL_GROUP="wheel" # Common groups: wheel, netdev. Verify for your system.
WPA_CONF_DIR="/etc/wpa_supplicant"
NETWORKD_CONF_DIR="/etc/systemd/network"
# Exit on error, treat unset variables as errors, and ensure pipelines fail on error
set -euo pipefail
# --- Helper Functions ---
log_info() {
echo "[INFO] $1"
}
log_warn() {
echo "[WARN] $1"
}
log_error() {
echo "[ERROR] $1" >&2
exit 1
}
# Function to safely restart or reload systemd services
manage_service() {
local action="$1" # e.g., restart, reload, enable
local service="$2"
log_info "Attempting to $action $service..."
set +e # Temporarily disable exit on error
systemctl "$action" "$service"
local status=$?
set -e # Re-enable exit on error
if [ $status -ne 0 ]; then
log_warn "Command 'systemctl $action $service' failed with status $status. Check logs ('journalctl -u $service')."
else
log_info "Successfully executed 'systemctl $action $service'."
fi
return $status
}
# --- Main Configuration Logic ---
configure_host_networking() {
log_info "Starting SBNB network configuration..."
# Check prerequisites
if [ -z "$WPA_SUPPLICANT_PATH" ]; then
log_error "wpa_supplicant command not found. Please install it."
fi
command -v ip >/dev/null || log_error "'ip' command not found (iproute2 package?)."
command -v awk >/dev/null || log_error "'awk' command not found."
command -v cut >/dev/null || log_error "'cut' command not found."
# Ensure configuration directories exist
mkdir -p "$NETWORKD_CONF_DIR"
mkdir -p "$WPA_CONF_DIR"
# --- Bridge Configuration (br0) ---
local bridge_netdev_file="${NETWORKD_CONF_DIR}/25-br0.netdev"
local bridge_network_file="${NETWORKD_CONF_DIR}/25-br0.network"
local bridge_link_file="${NETWORKD_CONF_DIR}/25-br0.link"
if [ -f "$bridge_netdev_file" ]; then
log_info "Bridge br0 configuration files already exist. Skipping bridge creation."
else
log_info "Creating bridge br0 configuration files..."
# systemd-networkd processes files in lexical order. Prefixes ensure correct ordering.
# 25-* files define the bridge device and its network settings.
cat > "$bridge_netdev_file" << EOF
[NetDev]
Name=br0
Kind=bridge
EOF
cat > "$bridge_network_file" << EOF
[Match]
Name=br0
[Network]
DHCP=yes
# If static IP is needed, comment DHCP=yes and uncomment below:
# Address=192.168.1.100/24
# Gateway=192.168.1.1
# DNS=1.1.1.1
# DNS=8.8.8.8
EOF
cat > "$bridge_link_file" << EOF
[Match]
# Match based on the interface name generated by the .netdev file
OriginalName=br0
[Link]
# MACAddressPolicy=none: Prevent systemd-networkd from assigning a potentially
# unstable MAC based on the bridge name. The bridge will use the MAC of the
# first enslaved interface or remain 00:00:00:00:00:00 until an interface joins.
MACAddressPolicy=none
EOF
log_info "Bridge br0 configuration files created."
fi
# --- Ethernet Interface Configuration ---
# Find the first available Ethernet interface
ETH_INTERFACE=$(ip -o link show type ether | awk 'NR==1{print $2}' | cut -d: -f1 || true)
if [ -n "$ETH_INTERFACE" ]; then
log_info "Ethernet interface '$ETH_INTERFACE' detected."
local eth_network_file="${NETWORKD_CONF_DIR}/30-${ETH_INTERFACE}-br0.network"
if [ ! -f "$eth_network_file" ]; then
log_info "Configuring '$ETH_INTERFACE' to join bridge br0..."
# 30-* file attaches the physical interface to the bridge.
cat > "$eth_network_file" << EOF
[Match]
Name=${ETH_INTERFACE}
[Network]
Bridge=br0
EOF
else
log_info "Configuration for '$ETH_INTERFACE' already exists."
fi
else
log_info "No active Ethernet interface detected."
fi
# --- WiFi Interface Configuration ---
# Find the first available WiFi interface
WIFI_INTERFACE=$(ip -o link show type wlan | awk 'NR==1{print $2}' | cut -d: -f1 || true)
if [ -n "$WIFI_INTERFACE" ]; then
log_info "WiFi interface '$WIFI_INTERFACE' detected."
log_info "Note: Ensure necessary WiFi drivers and firmware are loaded for '${WIFI_INTERFACE}'."
log_info "Check 'dmesg | grep -i firmware' or 'lspci/lsusb' output if issues arise."
local wpa_conf_file="${WPA_CONF_DIR}/wpa_supplicant-${WIFI_INTERFACE}.conf"
local wpa_service_file="/etc/systemd/system/wpa_supplicant@${WIFI_INTERFACE}.service"
local wifi_network_file="${NETWORKD_CONF_DIR}/35-${WIFI_INTERFACE}-br0.network"
# Create WPA Supplicant configuration template if not present
if [ ! -f "$wpa_conf_file" ]; then
log_info "Creating WPA Supplicant configuration template at ${wpa_conf_file}..."
cat > "$wpa_conf_file" << EOF
# Configuration for ${WIFI_INTERFACE} managed by wpa_supplicant
ctrl_interface=/run/wpa_supplicant
ctrl_interface_group=${WPA_CTRL_GROUP}
update_config=1
network={
ssid="YOUR_WIFI_SSID"
psk="YOUR_WIFI_PASSWORD"
key_mgmt=WPA-PSK
# --- Example for WPA2/WPA3 Personal (SAE - optional) ---
# Adjust key_mgmt as needed, e.g., key_mgmt=WPA-PSK WPA-PSK-SHA256 SAE
# psk= can be replaced by a passphrase= for WPA3 SAE if supported
# --- Example for WPA Enterprise (EAP-PEAP/MSCHAPv2) ---
# For enterprise networks, comment out psk= and key_mgmt= above
# and add appropriate settings like below (adjust as needed):
# proto=RSN WPA
# key_mgmt=WPA-EAP
# pairwise=CCMP TKIP
# group=CCMP TKIP
# eap=PEAP
# identity="your_username"
# password="your_password"
# phase1="peaplabel=0"
# phase2="auth=MSCHAPV2"
}
EOF
chmod 600 "$wpa_conf_file"
log_warn "IMPORTANT: Edit ${wpa_conf_file} with your actual WiFi credentials."
else
log_info "WPA Supplicant configuration already exists at ${wpa_conf_file}."
fi
# Configure wlan interface to join bridge br0
if [ ! -f "$wifi_network_file" ]; then
log_info "Configuring '$WIFI_INTERFACE' to join bridge br0..."
# 35-* file attaches the WiFi interface to the bridge.
cat > "$wifi_network_file" << EOF
[Match]
Name=${WIFI_INTERFACE}
[Network]
Bridge=br0
EOF
else
log_info "Network configuration for '$WIFI_INTERFACE' already exists."
fi
# Create systemd service for WPA Supplicant if not present
local wpa_service_name="wpa_supplicant@${WIFI_INTERFACE}.service"
if [ ! -f "$wpa_service_file" ]; then
log_info "Creating systemd service file for ${wpa_service_name}..."
cat > "$wpa_service_file" << EOF
[Unit]
Description=WPA Supplicant daemon for ${WIFI_INTERFACE}
Requires=sys-subsystem-net-devices-${WIFI_INTERFACE}.device
After=sys-subsystem-net-devices-${WIFI_INTERFACE}.device
Before=network.target
Wants=network.target
[Service]
Type=simple
ExecStart=${WPA_SUPPLICANT_PATH} -c${wpa_conf_file} -i${WIFI_INTERFACE}
Restart=on-failure
RestartSec=1
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
manage_service "enable" "$wpa_service_name"
else
log_info "Systemd service file for ${wpa_service_name} already exists."
fi
# Always try to restart WPA supplicant if WiFi interface is detected and configured
manage_service “restart” “$wpa_service_name”
else
log_info “No active WiFi interface detected.”
fi
# — Apply Network Configuration —
log_info “Applying network configuration changes...”
# Use ‘networkctl reload’ which is often sufficient and less disruptive than restarting the whole service
networkctl reload || manage_service “restart” “systemd-networkd.service”
log_info “SBNB network configuration script finished.”
if [ -n “$WIFI_INTERFACE” ] && [ ! -f “$wpa_conf_file”.edited ]; then
log_warn “Remember to edit ‘${wpa_conf_file}’ with your WiFi credentials if you haven’t already.”
# Simple flag to avoid repeating the warning on subsequent runs
touch “$wpa_conf_file”.edited > /dev/null 2>&1 || true
fi
}
# — Execute Main Logic —
configure_host_networking
URL: https://ib.bsb.br/how-to-integrate-wifi-support-into-the-sbnb-bridge-based-networking-setup