41f71fd217
scripts/pi-hotspot.sh turns the receiver into a WPA2 access point via NetworkManager (ipv4 shared mode gives the Pi built-in DHCP/NAT at 10.42.0.1), so a sender connects directly with no router in between — which also sidesteps LAN quirks like unreachable 6to4 addresses, since the direct link is plain private IPv4. The passphrase is generated on first use and stored root-only in /etc/screencast-hotspot.conf; on|off|status subcommands manage it, and off restores normal client Wi-Fi. The hotspot owns wlan0 while active (documented). No receiver changes were needed: it already announces on every interface. nmcli property syntax validated against NetworkManager 1.58 with a disposable never-activated profile; actual AP bring-up can only be validated on the Pi.
126 lines
4.0 KiB
Bash
Executable File
126 lines
4.0 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
#
|
|
# pi-hotspot.sh — turn the receiver into a Wi-Fi access point so a sender
|
|
# can connect directly, without any router in between.
|
|
#
|
|
# Usage (on the Pi):
|
|
#
|
|
# sudo scripts/pi-hotspot.sh on [--ssid NAME] [--psk KEY] [--band bg|a]
|
|
# sudo scripts/pi-hotspot.sh off
|
|
# sudo scripts/pi-hotspot.sh status
|
|
#
|
|
# The hotspot takes over the Wi-Fi interface: the Pi leaves your router's
|
|
# network while it is active. Connect to the SSID from the sending machine;
|
|
# the Pi is reachable at 10.42.0.1 (SSH, screencast) and the sender gets an
|
|
# address via the built-in DHCP. Discovery and streaming then run over the
|
|
# direct link.
|
|
#
|
|
# The passphrase is stored in /etc/screencast-hotspot.conf (root only) so
|
|
# `status` can show it again.
|
|
|
|
set -euo pipefail
|
|
|
|
CONNECTION_NAME="screencast-hotspot"
|
|
INTERFACE="${SC_HOTSPOT_INTERFACE:-wlan0}"
|
|
CONFIG_FILE="/etc/screencast-hotspot.conf"
|
|
|
|
log() { printf '\n=== %s\n' "$*"; }
|
|
die() { printf 'pi-hotspot: error: %s\n' "$*" >&2; exit 1; }
|
|
|
|
require_root() {
|
|
[ "$(id -u)" = 0 ] || die "run with sudo"
|
|
}
|
|
|
|
random_passphrase() {
|
|
if command -v openssl >/dev/null 2>&1; then
|
|
openssl rand -base64 12 | tr -d '=+/' | head -c 16
|
|
else
|
|
tr -dc 'A-Za-z0-9' </dev/urandom | head -c 16
|
|
fi
|
|
}
|
|
|
|
cmd_on() {
|
|
local ssid="screencast" psk="" band="bg"
|
|
while [ $# -gt 0 ]; do
|
|
case "$1" in
|
|
--ssid) ssid="$2"; shift 2 ;;
|
|
--psk) psk="$2"; shift 2 ;;
|
|
--band) band="$2"; shift 2 ;;
|
|
*) die "unknown option: $1" ;;
|
|
esac
|
|
done
|
|
|
|
command -v nmcli >/dev/null 2>&1 || die "NetworkManager (nmcli) not found"
|
|
systemctl is-active --quiet NetworkManager || die "NetworkManager is not running"
|
|
ip link show "$INTERFACE" >/dev/null 2>&1 || die "interface ${INTERFACE} does not exist"
|
|
|
|
if [ -z "$psk" ]; then
|
|
psk="$(random_passphrase)"
|
|
fi
|
|
|
|
log "warning: this takes over ${INTERFACE}; the Pi leaves any router Wi-Fi while the hotspot is active"
|
|
log "creating hotspot '${ssid}' (WPA2, band ${band})"
|
|
|
|
apt-get install -y --no-install-recommends network-manager dnsmasq-base >/dev/null 2>&1 || true
|
|
|
|
nmcli connection delete "$CONNECTION_NAME" >/dev/null 2>&1 || true
|
|
nmcli connection add \
|
|
type wifi \
|
|
ifname "$INTERFACE" \
|
|
con-name "$CONNECTION_NAME" \
|
|
autoconnect yes \
|
|
connection.autoconnect-priority 100 \
|
|
802-11-wireless.ssid "$ssid" \
|
|
802-11-wireless.mode ap \
|
|
802-11-wireless.band "$band" \
|
|
802-11-wireless-security.key-mgmt wpa-psk \
|
|
802-11-wireless-security.psk "$psk" \
|
|
ipv4.method shared \
|
|
ipv6.method disabled >/dev/null
|
|
|
|
nmcli connection up "$CONNECTION_NAME" >/dev/null
|
|
|
|
umask 077
|
|
printf 'ssid=%s\npsk=%s\n' "$ssid" "$psk" >"$CONFIG_FILE"
|
|
|
|
log "hotspot is up"
|
|
printf ' SSID: %s\n' "$ssid"
|
|
printf ' Password: %s\n' "$psk"
|
|
printf ' Pi address: 10.42.0.1 (also announced via mDNS)\n'
|
|
printf '\nOn the sending machine: connect to the Wi-Fi above, then\n'
|
|
printf ' screencast --send\n'
|
|
}
|
|
|
|
cmd_off() {
|
|
log "removing the hotspot (Wi-Fi returns to normal client mode)"
|
|
nmcli connection delete "$CONNECTION_NAME" >/dev/null 2>&1 || {
|
|
log "no hotspot configured"
|
|
exit 0
|
|
}
|
|
rm -f "$CONFIG_FILE"
|
|
log "done; the Pi will reconnect to any known router Wi-Fi"
|
|
}
|
|
|
|
cmd_status() {
|
|
if [ -f "$CONFIG_FILE" ]; then
|
|
log "hotspot configuration (${CONFIG_FILE})"
|
|
grep -E '^(ssid|psk)=' "$CONFIG_FILE" | sed -e 's/^/ /'
|
|
else
|
|
log "no hotspot configured (run: sudo scripts/pi-hotspot.sh on)"
|
|
fi
|
|
nmcli --get-values NAME,TYPE,DEVICE connection show --active 2>/dev/null | grep wifi | sed 's/^/ /' || true
|
|
}
|
|
|
|
case "${1:-}" in
|
|
on) require_root; shift; cmd_on "$@" ;;
|
|
off) require_root; shift; cmd_off "$@" ;;
|
|
status) cmd_status ;;
|
|
*)
|
|
cat <<'EOF'
|
|
usage: sudo scripts/pi-hotspot.sh on [--ssid NAME] [--psk KEY] [--band bg|a]
|
|
sudo scripts/pi-hotspot.sh off
|
|
sudo scripts/pi-hotspot.sh status
|
|
EOF
|
|
exit 1
|
|
;;
|
|
esac |