feat(cli): add mac command to set the management MAC from the config

Add a `mac <aa:bb:cc:dd:ee:ff>` console command (and a bare `mac` to show
the current address) that overrides the management MAC at runtime. The
address is validated (unicast, globally administered, non-zero OUI) and
the static L2 management entry is re-registered so the change applies
without a reboot. Because it is a normal command, a line in the startup
config persists it across boots: execute_config() runs it before the final
static L2 entry and the derived hostname are set up.

Also point the keepLink KP-9000-9XHML-X V3.1 machine definition at the
factory MAC area (0x1FC000, same location other machines use) so a valid
factory MAC is picked up at boot instead of falling back to a locally
administered address.

The MAC parsing/printing lives in parse_mac()/print_mac() helpers next to
parse_ip()/print_ip() so future commands can reuse them, and a memcmp()
helper joins the project's own memcpy()/memset() (no libc is linked).
This commit is contained in:
gnacho committed 2026-09-08 22:46:14 +02:00
1 parent 6488433584
commit 6616a0c9ce
4 files changed
+109

No files matched your search

+94
View File
@@ -364,6 +364,98 @@ void print_ip(__xdata uint8_t * ptr)
}
}
// Prints a MAC address.
void print_mac(__xdata uint8_t *ptr)
{
uint8_t idx = 0;
uint8_t num;
while (1) {
num = *ptr++;
print_byte(num);
if (++idx == 6)
break;
write_char(':');
}
}
// Parses a MAC address (12 hex digits, ':' or '-' separators optional) from
// cmd_buffer starting at idx into mac[6]. Returns the number of bytes
// consumed, or 0 on error.
uint8_t parse_mac(uint8_t idx, __xdata uint8_t *mac)
{
uint8_t b = 0;
uint8_t hi = 0xff; /* 0xff = waiting for the high nibble */
uint8_t c;
while (b < 6) {
c = cmd_buffer[idx];
if (c == NUL || c == ' ' || c == '\r' || c == '\n')
break;
idx++;
if (c == ':' || c == '-')
continue;
c |= 0x20;
if (c >= '0' && c <= '9')
c -= '0';
else if (c >= 'a' && c <= 'f')
c -= 'a' - 10;
else
break;
if (hi == 0xff) {
hi = c;
} else {
mac[b++] = (hi << 4) | c;
hi = 0xff;
}
}
if (b != 6 || hi != 0xff)
return 0;
return idx;
}
// Sets the management MAC from a "mac <aa:bb:cc:dd:ee:ff>" command (or prints
// the current one with a bare "mac"). Refuses blank/multicast/locally
// administered/all-zero-OUI addresses so the running MAC stays reachable, and
// re-registers the static L2 management entry so the change applies without a
// reboot. As a regular command a "mac ..." line in the startup config applies
// on every boot (execute_config runs before the final static L2 entry).
void parse_mac_cmd(void)
{
__xdata uint8_t mac[6];
if (cmd_words_len == 1) {
print_string("Current MAC: ");
print_mac(uip_ethaddr.addr);
write_char('\n');
return;
}
if (cmd_words_len != 2 || !parse_mac(cmd_words_b[1], mac)) {
print_string("Error: mac [<aa:bb:cc:dd:ee:ff>]\n");
return;
}
if ((mac[0] & 0x03) || ((mac[0] | mac[1] | mac[2]) == 0)) {
print_string("refusing: must be unicast, globally administered\n");
return;
}
if (memcmp(mac, uip_ethaddr.addr, 6) == 0) {
print_string("MAC unchanged\n");
return;
}
// Swap the static management entry over to the new address: remove the
// old one (still in uip_ethaddr) before overwriting it.
port_l2_static_mgmt(uip_ethaddr.addr, management_vlan, true);
memcpy(uip_ethaddr.addr, mac, 6);
port_l2_static_mgmt(uip_ethaddr.addr, management_vlan, false);
print_string("MAC set to: ");
print_mac(uip_ethaddr.addr);
write_char('\n');
print_string("Save the startup config to keep it across reboots\n");
}
void parse_lag(void)
{
@@ -1694,6 +1786,8 @@ void cmd_parser(void) __banked
igmp_show();
else
print_string("Error: igmp on|off|show\n");
} else if (cmd_compare(0, "mac")) {
parse_mac_cmd();
} else if (cmd_compare(0, "hostname")) {
/* "hostname" alone reports the current name; "hostname <text>"
* sets it, sanitized to JSON-safe printable ASCII. A name with
+1
View File
@@ -247,6 +247,7 @@ __code const struct machine machine = {
.led_mux = {0x00, 0x01, 0x04, 0x05, 0x08, 0x09, 0x0c, 0x09, 0x0d, 0x10,
0x11, 0x0e, 0x14, 0x11, 0x12, 0x15, 0x15, 0x16, 0x18, 0x19,
0x1a, 0x19, 0x1d, 0x1e, 0x1c, 0x1d, 0x20, 0x21},
.mac_flash_offset = 0x1FC000,
};
#elif defined MACHINE_SWGT024_V2_0_MANAGED
+1
View File
@@ -173,6 +173,7 @@ void reset_chip(void);
void memcpy(__xdata void * __xdata dst, __xdata const void * __xdata src, uint16_t len);
void memcpyc(__xdata uint8_t *dst, __code uint8_t *src, uint16_t len);
void memset(__xdata uint8_t *dst, __xdata uint8_t v, uint8_t len);
int memcmp(__xdata const void *a, __xdata const void *b, uint16_t len);
uint16_t strlen(__code const char *s);
uint16_t strlen_x(__xdata const char *s);
uint16_t strtox(__xdata uint8_t *dst, __code const char *s);
+13
View File
@@ -359,6 +359,19 @@ void memcpy(__xdata void * __xdata dst, __xdata const void * __xdata src, uint16
*d++ = *s++;
}
int memcmp(__xdata const void *a, __xdata const void *b, uint16_t len)
{
__xdata const uint8_t *x = a;
__xdata const uint8_t *y = b;
while (len--) {
if (*x != *y)
return *x - *y;
x++;
y++;
}
return 0;
}
void memcpyc(__xdata uint8_t *dst, __code uint8_t *src, uint16_t len)
{
while (len--)