gluon-setup-mode: add remote setup-mode

This commit is contained in:
David Bauer 2023-01-31 22:57:28 +01:00
parent 1780bafafc
commit 83dbbc182f
9 changed files with 353 additions and 1 deletions

View File

@ -35,6 +35,9 @@ init_links := \
define Package/gluon-setup-mode/install
$(Gluon/Build/Install)
$(INSTALL_DIR) $(1)/lib/gluon/setup-mode
$(INSTALL_BIN) $(PKG_BUILD_DIR)/wait-network-request $(1)/lib/gluon/setup-mode
$(LN) S20network $(1)/lib/gluon/setup-mode/rc.d/K90network
for link in $(init_links); do \

View File

@ -0,0 +1,55 @@
#!/bin/sh
. /lib/functions.sh
device_supports_networked_setup_mode() {
local is_networked="$(lua -e 'print(require("gluon.setup-mode").supports_networked_activation())')"
if [ "${is_networked}" = "true" ]; then
return 0
fi
return 1
}
should_activate_networked() {
local setup_ifnames="$(lua -e 'print(require("gluon.sysconfig").setup_ifname)')"
local should_start=1
if ! device_supports_networked_setup_mode; then
return 1
fi
for iface in $setup_ifnames
do
ip link set dev "${iface}" up
done
# shellcheck disable=SC2086
if /lib/gluon/setup-mode/wait-network-request ${setup_ifnames}; then
should_start=0
fi
for iface in $setup_ifnames
do
ip link set dev "${iface}" down
done
return $should_start
}
network_setup_mode_enable() {
local enabled="$(uci -q get 'gluon-setup-mode.@setup_mode[0].enabled')"
local configured="$(uci -q get 'gluon-setup-mode.@setup_mode[0].configured')"
if [ "$enabled" = 1 ] || [ "$configured" != 1 ]; then
return 0
fi
if should_activate_networked; then
uci -q set 'gluon-setup-mode.@setup_mode[0].enabled=1'
fi
return 0
}
boot_hook_add preinit_main network_setup_mode_enable

View File

@ -1,6 +1,5 @@
#!/bin/sh
setup_mode_enable() {
local enabled="$(uci -q get 'gluon-setup-mode.@setup_mode[0].enabled')"
local configured="$(uci -q get 'gluon-setup-mode.@setup_mode[0].configured')"

View File

@ -0,0 +1,14 @@
local platform = require 'gluon.platform'
local M = {}
function M.supports_networked_activation()
if platform.match('ramips', 'mt7621', {
'zyxel,nwa55axe',
}) then
return true
end
end
return M

View File

@ -0,0 +1,2 @@
enter-setup-mode
check-setup-mode

View File

@ -0,0 +1,16 @@
CC:=gcc
CFLAGS:=
LDFLAGS:=
all: wait-network-request send-network-request
wait-network-request:
$(CC) $(CFLAGS) $(LDFLAGS) -o wait-network-request wait-network-request.c
send-network-request:
$(CC) $(CFLAGS) $(LDFLAGS) -o send-network-request send-network-request.c
clean:
rm -rf send-network-request wait-network-request
.PHONY: clean all

View File

@ -0,0 +1,18 @@
#pragma once
/* Seconds*/
#define REMOTE_SETUP_MODE_RX_TIMEOUT 5
#define REMOTE_SETUP_MODE_TX_INTERVAL 1
#define REMOTE_SETUP_MODE_MAC_LEN 6
#define REMOTE_SETUP_MODE_DST_MAC_OFFSET 0
#define REMOTE_SETUP_MODE_DST_MAC 0x01, 0x80, 0xc2, 0x00, 0x00, 0x0e
#define REMOTE_SETUP_MODE_SRC_MAC_OFFSET 6
#define REMOTE_SETUP_MODE_SRC_MAC 0xda, 0xec, 0xe5, 0x8f, 0x60, 0x14
#define REMOTE_SETUP_MODE_ETHERTYPE_OFFSET (REMOTE_SETUP_MODE_MAC_LEN + REMOTE_SETUP_MODE_MAC_LEN)
#define REMOTE_SETUP_MODE_ETHERTYPE_LEN 2
#define REMOTE_SETUP_MODE_ETHERTYPE 0x23, 0x42
#define REMOTE_SETUP_MODE_DATA_CMD_OFFSET (REMOTE_SETUP_MODE_ETHERTYPE_OFFSET + REMOTE_SETUP_MODE_ETHERTYPE_LEN)
#define REMOTE_SETUP_MODE_DATA_CMD_SETUP "SETUP"

View File

@ -0,0 +1,91 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Utility for performing remote setup-mode activation
*
* Copyright (c) David Bauer <mail@david-bauer.net>
*/
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <linux/if_packet.h>
#include <net/ethernet.h>
#include <string.h>
#include <net/if.h>
#include <errno.h>
#include <sys/ioctl.h>
#include "gluon-remote-setup-mode.h"
#define LLDP_DELAY (REMOTE_SETUP_MODE_TX_INTERVAL * 1000)
char buf[] = {
/* Destination - LLDP Multicast */
REMOTE_SETUP_MODE_DST_MAC,
/* Source */
REMOTE_SETUP_MODE_SRC_MAC,
/* Type */
REMOTE_SETUP_MODE_ETHERTYPE,
/* Magic*/
'S', 'E', 'T', 'U', 'P',
/* Trail */
0x00,
};
int get_ifindex(int sock, const char *ifname)
{
struct ifreq ifr;
strncpy((char *)ifr.ifr_name, ifname, IFNAMSIZ);
if (ioctl(sock, SIOCGIFINDEX, &ifr)) {
printf("IOCTL error: %s\n", strerror(errno));
return -1;
}
return ifr.ifr_ifindex;
}
int main(int argc, char *argv[])
{
struct sockaddr_ll sll;
int ifindex;
int s_fd;
if (argc < 2 || !strcmp("help", argv[1])) {
printf("Usage: %s <ifname>\n", argv[0]);
return 1;
}
s_fd = socket(AF_PACKET,SOCK_RAW,htons(ETH_P_ALL));
if (s_fd < 0) {
printf("Socket error: %s\n", strerror(errno));
return 1;
}
ifindex = get_ifindex(s_fd, argv[1]);
if (ifindex < 0) {
return 1;
}
memset(&sll, 0, sizeof(sll));
sll.sll_family = AF_PACKET;
sll.sll_ifindex = ifindex;
printf("Sending Reset command\n");
while (1) {
if (sendto(s_fd, buf, sizeof(buf), 0, (struct sockaddr *) &sll, sizeof(sll)) < 0) {
printf("Error sending packet: %s\n", strerror(errno));
return 1;
}
usleep(LLDP_DELAY);
}
close(s_fd);
return 0;
}

View File

@ -0,0 +1,154 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Utility for entering Setup_mode using network
*
* Copyright (c) David Bauer <mail@david-bauer.net>
*/
#include <fcntl.h>
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <linux/if_packet.h>
#include <net/ethernet.h>
#include <string.h>
#include <net/if.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <time.h>
#include "gluon-remote-setup-mode.h"
#define MAX_INTERFACES 64
#define BUFSIZE 1024
char destination[] = { REMOTE_SETUP_MODE_DST_MAC };
char type[] = { REMOTE_SETUP_MODE_ETHERTYPE };
static int bind_socket_to_device(int fd, int ifindex)
{
struct sockaddr_ll sll = {
.sll_family = AF_PACKET,
.sll_ifindex = ifindex,
.sll_protocol = htons(ETH_P_ALL)
};
if((bind(fd , (struct sockaddr *)&sll , sizeof(sll))) < 0) {
return 1;
}
return 0;
}
static int should_reset(char *buf, size_t size)
{
int should_reset;
char *tlv_ptr;
should_reset = 0;
if (size < REMOTE_SETUP_MODE_DATA_CMD_OFFSET + strlen(REMOTE_SETUP_MODE_DATA_CMD_SETUP) + 1) {
/* Length mismatch */
return 0;
}
if (buf[size - 1] != 0x00) {
/* Wrong trailer */
return 0;
}
if (memcmp(destination, &buf[REMOTE_SETUP_MODE_DST_MAC_OFFSET], sizeof(destination))) {
/* Wrong destination-etheraddr */
return 0;
}
if (memcmp(type, &buf[REMOTE_SETUP_MODE_ETHERTYPE_OFFSET], sizeof(type))) {
/* Wrong Ethertype */
return 0;
}
if (strcmp(&buf[REMOTE_SETUP_MODE_DATA_CMD_OFFSET], REMOTE_SETUP_MODE_DATA_CMD_SETUP)) {
/* Wrong Command */
return 0;
}
return 1;
}
int main(int argc, char *argv[])
{
time_t start_time, current_time;
int ifindex[MAX_INTERFACES];
int sockets[MAX_INTERFACES];
char recvbuf[BUFSIZE];
int num_interfaces;
int received;
int i;
start_time = time(NULL);
if (argc < 2) {
fprintf(stderr, "At least one Interface name is required\n", MAX_INTERFACES);
return 1;
}
if (argc > MAX_INTERFACES) {
fprintf(stderr, "Exceeded maximum number of supported interfaces of %d\n", MAX_INTERFACES);
return 1;
}
num_interfaces = 0;
for (i = 1; i < argc; i++) {
ifindex[num_interfaces] = if_nametoindex(argv[i]);
if (!ifindex[num_interfaces]) {
fprintf(stderr, "Interface %s not found!\n", argv[i]);
}
num_interfaces++;
}
for (i = 0; i < num_interfaces; i++) {
sockets[i] = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if (sockets[i] < 0) {
fprintf(stderr, "Could not create socket for ifindex %d\n", ifindex[i]);
return 1;
}
if (bind_socket_to_device(sockets[i], ifindex[i])) {
fprintf(stderr, "Error binding socket to Interface %d\n", ifindex[i]);
return 1;
}
}
/* Start receiving */
while (1) {
/* Check if timeout is exceeded */
current_time = time(NULL);
if (current_time - start_time > REMOTE_SETUP_MODE_RX_TIMEOUT) {
break;
}
for (i = 0; i < num_interfaces; i++) {
received = recv(sockets[i], recvbuf, BUFSIZE, MSG_DONTWAIT);
if (received < 0 && errno != EAGAIN && errno != EAGAIN) {
fprintf(stderr, "Error receiving from ifindex %d - ret %d\n", ifindex[i], errno);
continue;
}
if (received <= 0) {
continue;
}
if (!should_reset(recvbuf, received)) {
continue;
}
return 0;
}
}
return 1;
}