gluon-setup-mode: add remote setup-mode
This commit is contained in:
parent
1780bafafc
commit
83dbbc182f
@ -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 \
|
||||
|
@ -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
|
@ -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')"
|
||||
|
@ -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
|
2
package/gluon-setup-mode/src/.gitignore
vendored
Normal file
2
package/gluon-setup-mode/src/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
enter-setup-mode
|
||||
check-setup-mode
|
16
package/gluon-setup-mode/src/Makefile
Normal file
16
package/gluon-setup-mode/src/Makefile
Normal 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
|
18
package/gluon-setup-mode/src/gluon-remote-setup-mode.h
Normal file
18
package/gluon-setup-mode/src/gluon-remote-setup-mode.h
Normal 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"
|
91
package/gluon-setup-mode/src/send-network-request.c
Normal file
91
package/gluon-setup-mode/src/send-network-request.c
Normal 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;
|
||||
}
|
154
package/gluon-setup-mode/src/wait-network-request.c
Normal file
154
package/gluon-setup-mode/src/wait-network-request.c
Normal 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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user