From d0374541c5c660a0dd6aff1dbe5c8e2a8399fdea Mon Sep 17 00:00:00 2001 From: bloqaudio Date: Mon, 21 Sep 2026 11:05:07 -0500 Subject: [PATCH 01/34] uip: rate-limit the dropped-fragment log uip has no reassembly, so every fragment it receives is discarded and logged. A neighbour that broadcasts fragmented traffic therefore produces a continuous stream of "ip: fragment dropped." rather than an occasional one, at roughly thirteen lines a second on a quiet segment, which buries every other console message. The message carries real information: a sudden burst of it says something about the network. What carries none is repeating it per fragment. Report the count once per five second window instead, which keeps the signal and ends the flood. The count is printed through the no_syslog primitives, as the original message was, so the flood cannot move from the console into the log ring. itoa() writes through write_char(), which also feeds the ring, so it gets a no_syslog twin beside it rather than a private copy of its digits. --- rtl837x_common.h | 1 + rtlplayground.c | 13 +++++++++++++ test/test_httpd_tx.c | 2 ++ uip/uip.c | 20 +++++++++++++++++++- 4 files changed, 35 insertions(+), 1 deletion(-) diff --git a/rtl837x_common.h b/rtl837x_common.h index 5e1373f8..75325c28 100644 --- a/rtl837x_common.h +++ b/rtl837x_common.h @@ -143,6 +143,7 @@ void print_long(uint32_t a); void print_short(uint16_t a); void print_byte(uint8_t a); void itoa(uint8_t v); +void itoa_no_syslog(uint8_t v); void itoa_short(uint16_t v); void print_sfr_data(void); void print_phy_data(void); diff --git a/rtlplayground.c b/rtlplayground.c index 6b0bf2df..9de5f4d4 100644 --- a/rtlplayground.c +++ b/rtlplayground.c @@ -277,6 +277,19 @@ void itoa(uint8_t v) } +void itoa_no_syslog(uint8_t v) +{ + uint8_t t = (v / 100); + uint8_t print_zeros = t; + if (print_zeros) + write_char_no_syslog('0' + t); + t = (v / 10) % 10; + print_zeros |= t; + if (print_zeros) + write_char_no_syslog('0' + t); + write_char_no_syslog('0' + (v % 10)); +} + /* Same as itoa(), one decade wider: enough for a port number. Kept separate * rather than widening itoa() itself, because every existing caller passes a * byte and would start paying for 16-bit divisions it does not need. */ diff --git a/test/test_httpd_tx.c b/test/test_httpd_tx.c index 6f464d2b..7fae3afd 100644 --- a/test/test_httpd_tx.c +++ b/test/test_httpd_tx.c @@ -98,7 +98,9 @@ void reset_chip(void) { } void delay(uint16_t t) { (void)t; } void write_char(char c) { (void)c; } void write_char_no_syslog(char c) { (void)c; } +void itoa_no_syslog(uint8_t v) { (void)v; } void print_string(const char *p) { (void)p; } +void print_string_no_syslog(const char *p) { (void)p; } void print_string_newline_no_syslog(const char *p) { (void)p; } void set_sys_led_state(uint8_t state) { (void)state; } void cmd_parser(void) { } diff --git a/uip/uip.c b/uip/uip.c index 774067da..86fb4be8 100644 --- a/uip/uip.c +++ b/uip/uip.c @@ -98,6 +98,7 @@ #include "../rtl837x_regs.h" extern __xdata uint8_t rx_headers[16]; +extern volatile __xdata uint32_t ticks; /*---------------------------------------------------------------------------*/ /* Variable definitions. */ @@ -243,6 +244,9 @@ __xdata struct uip_stats uip_stat; #if UIP_LOGGING == 1 #define UIP_LOG(m) print_string_newline_no_syslog(m); +#define FRAGDROP_WINDOW (5 * SYS_TICK_HZ) +static __xdata u16_t fragdrop_mark; +static __xdata u8_t fragdrop_count; #else #define UIP_LOG(m) #endif /* UIP_LOGGING == 1 */ @@ -710,6 +714,17 @@ uip_process(u8_t flag) __banked /* Check if we were invoked because of the perodic timer fireing. */ } else if(flag == UIP_TIMER) { // print_string("T1\n"); +#if UIP_LOGGING == 1 + if(fragdrop_count && (u16_t)ticks - fragdrop_mark >= FRAGDROP_WINDOW) { + print_string_no_syslog("ip: fragments dropped: "); + itoa_no_syslog(fragdrop_count); + if(fragdrop_count == 0xff) + write_char_no_syslog('+'); + write_char_no_syslog('\n'); + fragdrop_mark = (u16_t)ticks; + fragdrop_count = 0; + } +#endif /* UIP_LOGGING == 1 */ #if UIP_IDLE_TIMEOUT if(uip_connr == uip_conns) { uip_idle_age = 0; @@ -915,7 +930,10 @@ uip_process(u8_t flag) __banked #else /* UIP_REASSEMBLY */ UIP_STAT(++uip_stat.ip.drop); UIP_STAT(++uip_stat.ip.fragerr); - UIP_LOG("ip: fragment dropped."); +#if UIP_LOGGING == 1 + if(fragdrop_count != 0xff) + ++fragdrop_count; +#endif /* UIP_LOGGING == 1 */ goto drop; #endif /* UIP_REASSEMBLY */ } From c2980e42d8c974524fd2dfbb3b31a7ff1cf8db96 Mon Sep 17 00:00:00 2001 From: bloqaudio Date: Mon, 12 Oct 2026 12:02:02 -0500 Subject: [PATCH 02/34] mirror: show the configured monitor port in "mirror status" "mirror status" printed the local mirroring_port, which is still 0 at that point, so it named the same port whatever was configured. Print the port from RTL837x_MIRROR_CTRL instead, which the function has already read to tell whether mirroring is enabled. send_mirror() decodes the register the same way for the web interface. --- cmd_parser.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd_parser.c b/cmd_parser.c index e16fa108..940b42ec 100644 --- a/cmd_parser.c +++ b/cmd_parser.c @@ -826,7 +826,7 @@ void parse_mirror(void) print_string("NOT Enabled: "); } print_string("Mirroring port: "); - print_phys_port(mirroring_port); + print_phys_port(mPort >> 1); reg_read_m(RTL837x_MIRROR_CONF); uint16_t m = sfr_data[0]; m = (m << 8) | sfr_data[1]; From d5ccd38dd34fe0bb5213ec67b8d9940d04b3b8cb Mon Sep 17 00:00:00 2001 From: bloqaudio Date: Wed, 14 Oct 2026 23:48:46 -0500 Subject: [PATCH 03/34] web: right-align the headers of number columns "table.t th" sets text-align:left and is more specific than ".num", so the headers of the counter columns on the dashboard and the statistics page stayed left-aligned above right-aligned values. --- html/index.html | 1 + 1 file changed, 1 insertion(+) diff --git a/html/index.html b/html/index.html index 21b7d17f..09790902 100644 --- a/html/index.html +++ b/html/index.html @@ -89,6 +89,7 @@ table.t th{ padding:6px 8px;border-bottom:1px solid var(--bd);white-space:nowrap; } table.t th[data-sort]{cursor:pointer;user-select:none} +table.t th.num{text-align:right} table.t td{padding:6px 8px;border-bottom:1px solid var(--bd);vertical-align:middle} table.t tr:last-child td{border-bottom:0} table.t tr:hover td{background:var(--sel)} From 97b15f402282a61bf63c253a8d09021ddc8530dd Mon Sep 17 00:00:00 2001 From: bloqaudio Date: Thu, 15 Oct 2026 00:11:04 -0500 Subject: [PATCH 04/34] web: give each packet counter of a port its own line The port tooltip and the port details showed "TX good / bad: 8794 / 0 pkts", which reads as 8794 bad packets. Each counter now has its own line, labelled as on the Statistics page, and the two strings only that line used are removed from every language. --- html/app.js | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/html/app.js b/html/app.js index 626e522c..63f76ad5 100644 --- a/html/app.js +++ b/html/app.js @@ -16,7 +16,7 @@ d_ports:"Ports",d_ports_h:"click a port for details",d_system:"System",d_traffic d_traffic_h:"packets/s, live",d_txpps:"TX pps",d_rxpps:"RX pps",d_txbad:"TX bad",d_rxbad:"RX bad", i_host:"Hostname",i_ip:"IP address",i_mask:"Netmask",i_gw:"Gateway",i_mac:"MAC",i_fw:"Firmware", i_built:"Built",i_hw:"Hardware",i_temp:"Temperature",i_flash:"Flash",i_syslog:"Syslog", -p_state:"State",p_disabled:"disabled",p_up:"up",p_txgb:"TX good / bad",p_rxgb:"RX good / bad", +p_state:"State",p_disabled:"disabled",p_up:"up", p_pkts:"pkts",p_module:"Module",p_temp:"Temperature",p_vcc:"Vcc",p_txbias:"TX bias",p_txpower:"TX power", p_rxpower:"RX power",p_txfault:"TX fault",p_txdis:"TX disabled",p_rxlos:"RX LOS",p_adv:"Advertising", pt_title:"Port configuration",pt_conn:"Connected",pt_speed:"Speed",pt_mtu:"MTU", @@ -147,7 +147,7 @@ d_ports:"ポート",d_ports_h:"ポートをクリックすると詳細を表示" d_traffic_h:"パケット/秒、リアルタイム",d_txpps:"TX pps",d_rxpps:"RX pps",d_txbad:"TX 異常",d_rxbad:"RX 異常", i_host:"ホスト名",i_ip:"IP アドレス",i_mask:"ネットマスク",i_gw:"ゲートウェイ",i_mac:"MAC",i_fw:"ファームウェア", i_built:"ビルド日",i_hw:"ハードウェア",i_temp:"温度",i_flash:"フラッシュ",i_syslog:"Syslog", -p_state:"状態",p_disabled:"無効",p_up:"アップ",p_txgb:"TX 正常 / 異常",p_rxgb:"RX 正常 / 異常", +p_state:"状態",p_disabled:"無効",p_up:"アップ", p_pkts:"pkts",p_module:"モジュール",p_temp:"温度",p_vcc:"電圧",p_txbias:"TX バイアス",p_txpower:"TX 電力", p_rxpower:"RX 電力",p_txfault:"TX 障害",p_txdis:"TX 無効",p_rxlos:"RX 信号ロス",p_adv:"アドバタイズ", pt_title:"ポート設定",pt_conn:"接続デバイス",pt_speed:"速度",pt_mtu:"MTU", @@ -260,7 +260,7 @@ d_ports:"端口",d_ports_h:"点击端口查看详情",d_system:"系统",d_traffi d_traffic_h:"包/秒,实时",d_txpps:"TX pps",d_rxpps:"RX pps",d_txbad:"TX 错误",d_rxbad:"RX 错误", i_host:"主机名",i_ip:"IP 地址",i_mask:"子网掩码",i_gw:"网关",i_mac:"MAC",i_fw:"固件", i_built:"构建日期",i_hw:"硬件",i_temp:"温度",i_flash:"Flash",i_syslog:"Syslog", -p_state:"状态",p_disabled:"已禁用",p_up:"已连接",p_txgb:"TX 正常 / 错误",p_rxgb:"RX 正常 / 错误", +p_state:"状态",p_disabled:"已禁用",p_up:"已连接", p_pkts:"个包",p_module:"模块",p_temp:"温度",p_vcc:"供电电压",p_txbias:"TX 偏置电流",p_txpower:"TX 光功率", p_rxpower:"RX 光功率",p_txfault:"TX 故障",p_txdis:"TX 禁用",p_rxlos:"RX 信号丢失",p_adv:"通告能力", pt_title:"端口配置",pt_conn:"已连接设备",pt_speed:"速率",pt_mtu:"MTU", @@ -373,7 +373,7 @@ d_ports:"Puertos",d_ports_h:"pulsa un puerto para ver detalles",d_system:"Sistem d_traffic_h:"paquetes/s, en vivo",d_txpps:"TX pps",d_rxpps:"RX pps",d_txbad:"TX erróneos",d_rxbad:"RX erróneos", i_host:"Nombre de host",i_ip:"Dirección IP",i_mask:"Máscara de red",i_gw:"Puerta de enlace",i_mac:"MAC",i_fw:"Firmware", i_built:"Compilado",i_hw:"Hardware",i_flash:"Flash",i_syslog:"Syslog", -p_state:"Estado",p_disabled:"deshabilitado",p_up:"activo",p_txgb:"TX correctos / erróneos",p_rxgb:"RX correctos / erróneos", +p_state:"Estado",p_disabled:"deshabilitado",p_up:"activo", p_pkts:"paquetes",p_module:"Módulo",p_temp:"Temperatura",p_vcc:"Vcc",p_txbias:"Polarización TX",p_txpower:"Potencia TX", p_rxpower:"Potencia RX",p_txfault:"Fallo TX",p_txdis:"TX deshabilitado",p_rxlos:"Pérdida RX (LOS)",p_adv:"Anunciado", pt_title:"Configuración de puerto",pt_conn:"Conectado",pt_speed:"Velocidad",pt_mtu:"MTU", @@ -485,7 +485,7 @@ d_ports:"Ports",d_ports_h:"Cliquez ou survollez pour plus de détails",d_system: d_traffic_h:"paquets/s (en direct)",d_txpps:"TX pps",d_rxpps:"RX pps",d_txbad:"TX KO",d_rxbad:"RX KO", i_host:"Nom d'hote",i_ip:"Adresse IP",i_mask:"Masque réseau",i_gw:"Passerelle",i_mac:"Adresse MAC",i_fw:"Micro logiciel", i_built:"Compilé le",i_hw:"Matériel",i_temp:"Température",i_flash:"Taille Flash",i_syslog:"Journal système", -p_state:"Etat",p_disabled:"Inactif",p_up:"Actif",p_txgb:"TX bon / mauvais",p_rxgb:"RX bon / mauvais", +p_state:"Etat",p_disabled:"Inactif",p_up:"Actif", p_pkts:"paquets",p_module:"Module",p_temp:"Température",p_vcc:"Vcc",p_txbias:"TX biais",p_txpower:"TX puissance", p_rxpower:"RX puissance",p_txfault:"TX erreur",p_txdis:"TX désactivé",p_rxlos:"RX pertes de signaux",p_adv:"Capacités", pt_title:"Configuration du port",pt_conn:"Connecté à",pt_speed:"Vitesse",pt_mtu:"MTU", @@ -602,7 +602,7 @@ d_ports:"Ports",d_ports_h:"Port anklicken für Details",d_system:"System",d_traf d_traffic_h:"Pakete/s, live",d_txpps:"TX Pakete/s",d_rxpps:"RX Pakete/s",d_txbad:"TX fehlerhaft",d_rxbad:"RX fehlerhaft", i_host:"Hostname",i_ip:"IP-Adresse",i_mask:"Netzmaske",i_gw:"Gateway",i_mac:"MAC",i_fw:"Firmware", i_built:"Erstellt",i_hw:"Hardware",i_temp:"Temperatur",i_flash:"Flash",i_syslog:"Syslog", -p_state:"Zustand",p_disabled:"deaktiviert",p_up:"verbunden",p_txgb:"TX gut / fehlerhaft",p_rxgb:"RX gut / fehlerhaft", +p_state:"Zustand",p_disabled:"deaktiviert",p_up:"verbunden", p_pkts:"Pakete",p_module:"Modul",p_temp:"Temperatur",p_vcc:"Vcc",p_txbias:"TX-Bias",p_txpower:"Sendeleistung", p_rxpower:"Empfangsleistung",p_txfault:"TX-Fehler",p_txdis:"TX deaktiviert",p_rxlos:"RX LOS",p_adv:"Angeboten", pt_title:"Port-Konfiguration",pt_conn:"Verbunden",pt_speed:"Geschwindigkeit",pt_mtu:"MTU", @@ -1023,8 +1023,10 @@ function portRows(p){ var rows=[[t("c_port"),String(p.portNum)],[t("c_type"),p.isSFP?"SFP":"RJ45"]]; if(p.name)rows.push([t("c_name"),p.name]); rows.push([t("p_state"),!p.enabled?t("p_disabled"):(p.link>0?t("p_up")+" "+LINKS[p.link]:t("c_down"))]); - rows.push([t("p_txgb"),BigInt(p.txG)+" / "+BigInt(p.txB)+" "+t("p_pkts")]); - rows.push([t("p_rxgb"),BigInt(p.rxG)+" / "+BigInt(p.rxB)+" "+t("p_pkts")]); + rows.push([t("st_txg"),BigInt(p.txG)+" "+t("p_pkts")]); + rows.push([t("st_txb"),BigInt(p.txB)+" "+t("p_pkts")]); + rows.push([t("st_rxg"),BigInt(p.rxG)+" "+t("p_pkts")]); + rows.push([t("st_rxb"),BigInt(p.rxB)+" "+t("p_pkts")]); if(p.isSFP){ if(p.sfp_vendor)rows.push([t("p_module"),[p.sfp_vendor,p.sfp_model,p.sfp_serial].filter(Boolean).join(" / ")]); var ext=p.sfp_options&0x40; From 680a40dab5fe295c89bbc93a07851140c7b311c1 Mon Sep 17 00:00:00 2001 From: bloqaudio Date: Thu, 15 Oct 2026 00:12:14 -0500 Subject: [PATCH 05/34] web: highlight Save to flash only when there are unsaved changes The button in the header was always drawn as the primary action, on every page, so it competed with each page's own buttons, for example the upload button on the Firmware page. It is now a plain button and turns primary together with the "unsaved changes" badge. --- html/app.js | 1 + html/index.html | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/html/app.js b/html/app.js index 626e522c..528cae21 100644 --- a/html/app.js +++ b/html/app.js @@ -836,6 +836,7 @@ function isConfCmd(line){ function setDirty(d){ S.dirty=d; $("dirty").classList.toggle("show",d); + $("saveBtn").classList.toggle("pri",d); } function postCmd(cmd,quiet){ return api("/cmd",{method:"POST",body:cmd}).then(function(r){ diff --git a/html/index.html b/html/index.html index 21b7d17f..6e8c782a 100644 --- a/html/index.html +++ b/html/index.html @@ -216,7 +216,7 @@ button.danger{background:var(--bad);color:#fff;border-color:transparent} unsaved changes - +
From 196d22d7c3421e74074f8fc856d6fb8b826eb4d9 Mon Sep 17 00:00:00 2001 From: bloqaudio Date: Fri, 16 Oct 2026 10:43:08 -0500 Subject: [PATCH 06/34] web: keep LLDP lines from piling up in the saved configuration Save to flash merges the running log into the startup configuration. Neither its toggle nor its overwrite rules knew "lldp on|off", so every switch of LLDP added another line: four switches left four lines. "port lldp permit|block" fell under the rule for "port ", so setting a port's speed dropped its LLDP setting from the saved configuration, and the other way round. "lldp on|off" is now a toggle, and a per-port LLDP setting replaces only an earlier per-port LLDP setting of that port. --- html/app.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/html/app.js b/html/app.js index 626e522c..db525237 100644 --- a/html/app.js +++ b/html/app.js @@ -2264,14 +2264,14 @@ var CONF_OVERWRITE=[ /^ntp\s+server\b/,/^ntp\s+interval\b/,/^ntp\s+timezone\b/,/^ntp\s+dst\b/, /^vlan\s+\d{1,4}\s+mgmt$/,/^vlan\s+\d{1,4}(?!\s+mgmt\b)/, /^pvid\s+\d{1,2}\b/, - /^port\s+\d{1,2}(?!\s+name\b)/,/^port\s+\d{1,2}\s+name\b/, + /^port\s+\d{1,2}(?!\s+(name|lldp)\b)/,/^port\s+\d{1,2}\s+name\b/, /^mirror\b/, /^lag\s+\d\b/,/^laghash\s+\d\b/,/^isolate\s+\d{1,2}\b/, /^stp\s+(prio|hello|maxage|fwd|txhold|version)\b/, /^stp\s+(port\s+\d{1,2}|lag\s+[1-4])\s+(edge|cost|prio|guard|filter|p2p)\b/, /^igmp\b/,/^mtu\s+\d{1,2}\b/,/^storm\s+\d{1,2}\s+(bcast|mcast|ucast|umcast)\b/, ]; -var CONF_TOGGLE=[/^(syslog)\s+(on|off)$/,/^(ntp)\s+(on|off)$/,/^(stp)\s+(on|off)$/,/^(stp\s+(port\s+\d{1,2}|lag\s+[1-4]))\s+(on|off)$/]; +var CONF_TOGGLE=[/^(syslog)\s+(on|off)$/,/^(ntp)\s+(on|off)$/,/^(stp)\s+(on|off)$/,/^(lldp)\s+(on|off)$/,/^(stp\s+(port\s+\d{1,2}|lag\s+[1-4]))\s+(on|off)$/]; function mergeConf(base,texts){ var conf=base.slice(); function drop(rx){conf=conf.filter(function(c){return!rx.test(c)})} @@ -2289,6 +2289,7 @@ function mergeConf(base,texts){ } if((m=line.match(/^lag (\d) lacp off$/))){drop(new RegExp("^lag "+m[1]+" lacp( |$)"));return;} if(line==="mirror off"){drop(/^mirror /);return;} + if((m=line.match(/^(port \d{1,2} lldp) (permit|block)$/))){drop(new RegExp("^"+m[1]+" (permit|block)$"));conf.push(line);return;} if(!isConfCmd(line))return; if((m=line.match(/^ingress (.+)$/))){ if(/^[tua]$/.test(m[1])){drop(/^ingress /);conf.push(line);return;} @@ -2321,7 +2322,7 @@ function mergeConf(base,texts){ var key=line.match(rx)[0]; conf=conf.filter(function(item){ return!(item===key||(item.indexOf(key+" ")===0 - &&!/\smgmt$/.test(item)&&item.indexOf(key+" name ")!==0)); + &&!/\smgmt$/.test(item)&&item.indexOf(key+" name ")!==0&&item.indexOf(key+" lldp ")!==0)); }); break; } From f0c672418c5637110df30efd9a008d37ff119877 Mon Sep 17 00:00:00 2001 From: HL Yi Date: Sun, 18 Oct 2026 08:44:37 -0500 Subject: [PATCH 07/34] hygiene clean up for httpd.c --- httpd/httpd.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/httpd/httpd.c b/httpd/httpd.c index f2ca2d36..fbe280d2 100644 --- a/httpd/httpd.c +++ b/httpd/httpd.c @@ -109,7 +109,8 @@ void httpd_init(void) __banked uip_listen(HTONS(80)); // Not through uip_conn: it only points at a connection while uIP is // handling one, and nothing has set it yet at init time. - uip_conns[0].appstate.tstate = TSTATE_CLOSED; + for (uint8_t i = 0; i < UIP_CONNS; i++) + uip_conns[i].appstate.tstate = TSTATE_CLOSED; fw_reset_pending = 0; // xdata is not zeroed by the startup code } @@ -874,7 +875,7 @@ void httpd_appcall(void) print_byte(s->tstate); write_char(' '); #endif - if(uip_connected() && s->tstate == TSTATE_CLOSED) { + if(uip_connected()) { dbg_string("Connected...\n"); s->tstate = TSTATE_NONE; } else if (uip_closed()) { From d104b3129db07804bfb60d8278845c87e2befb29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Silva?= Date: Thu, 15 Oct 2026 15:44:10 +0100 Subject: [PATCH 08/34] httpd: handle headers split across segments correctly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: João Silva --- httpd/httpd.c | 60 +++++++++++++-- test/test_httpd_tx.c | 176 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 229 insertions(+), 7 deletions(-) diff --git a/httpd/httpd.c b/httpd/httpd.c index f2ca2d36..733f681b 100644 --- a/httpd/httpd.c +++ b/httpd/httpd.c @@ -90,6 +90,7 @@ __xdata uint32_t last_session_use; #define TSTATE_POST 4 #define TSTATE_MULTIPART 5 #define TSTATE_POSTBODY 6 +#define TSTATE_POSTHEADER 7 extern __xdata uint16_t crc_value; __xdata uint16_t crc_final; @@ -746,11 +747,47 @@ static void post_body_continue(void) } + +/* + * Buffer a POST request header across TCP receive events. Stop copying at + * CRLFCRLF so any body bytes in the final segment stay in uip_appdata. + * + * Return the body offset in the current receive buffer, 0 while incomplete, + * or 0xffff after sending an error response. + */ +static uint16_t post_header_take(void) +{ + uint16_t i; + + for (i = 0; i < uip_len; i++) { + if (pre_acc + 1 >= CONFIG_UPLOAD_BUF) { + uip_conn->appstate.tstate = TSTATE_NONE; + send_bad_request(); + return 0xffff; + } + config_buf[pre_acc++] = ((__xdata uint8_t *)uip_appdata)[i]; + config_buf[pre_acc] = NUL; + if (pre_acc >= 4 + && config_buf[pre_acc - 4] == '\r' + && config_buf[pre_acc - 3] == '\n' + && config_buf[pre_acc - 2] == '\r' + && config_buf[pre_acc - 1] == '\n') { + uip_conn->appstate.tstate = TSTATE_NONE; + return i + 1; + } + } + + postbody_start = ticks; + uip_conn->appstate.tstate = TSTATE_POSTHEADER; + return 0; +} + void handle_post(void) { __xdata struct httpd_state * __xdata s = &(uip_conn->appstate); __xdata uint8_t *p = uip_appdata; __xdata uint8_t *request_path = p + 6; + uint16_t body_off; if (s->tstate == TSTATE_POSTBODY) { post_body_continue(); @@ -759,6 +796,14 @@ void handle_post(void) // Was the multipart header sent in multiple packets? if (s->tstate != TSTATE_MULTIPART) { + if (s->tstate != TSTATE_POSTHEADER) + pre_acc = 0; + body_off = post_header_take(); + if (!body_off || body_off == 0xffff) + return; + p = config_buf; + request_path = p + 6; + dbg_string("Is POST\n"); p += 5; // Skip post // Find end of request path @@ -772,9 +817,12 @@ void handle_post(void) dbg_string("Boundary: >"); dbg_string_x(boundary); dbg_string("<\n"); if (!*p || !content_type) { dbg_string("Bad Request!\n"); - send_not_found(); + send_bad_request(); return; } + + pre_acc = 0; + p = (__xdata uint8_t *)uip_appdata + body_off; if (is_word(request_path, "upload")) { if (!authenticated) { send_unauthorized(); @@ -824,7 +872,6 @@ void handle_post(void) handle_firmware_fragment(p); return; } else if (is_word(request_path, "cmd")) { - p += 4; if (!authenticated) { send_unauthorized(); return; @@ -843,7 +890,6 @@ void handle_post(void) return; } - p += 4; postbody_endpoint = POSTBODY_LOGIN; if (!post_body_take(p)) return; @@ -890,9 +936,9 @@ void httpd_appcall(void) dbg_string("Closing because everything has been transmitted\n"); uip_close(); s->tstate = TSTATE_CLOSED; - } else if (s->tstate == TSTATE_POSTBODY + } else if ((s->tstate == TSTATE_POSTBODY || s->tstate == TSTATE_POSTHEADER) && (uint16_t)ticks - postbody_start > POSTBODY_TIMEOUT) { - dbg_string("Body never arrived\n"); + dbg_string("POST request never completed\n"); uip_abort(); s->tstate = TSTATE_CLOSED; } @@ -964,11 +1010,11 @@ void httpd_appcall(void) #endif p = uip_appdata; if (is_word(p, "POST") || s->tstate == TSTATE_MULTIPART - || s->tstate == TSTATE_POSTBODY) { + || s->tstate == TSTATE_POSTBODY || s->tstate == TSTATE_POSTHEADER) { handle_post(); // If this is an ongoing post stream, then wait for the next packet if (s->tstate == TSTATE_POST || s->tstate == TSTATE_MULTIPART - || s->tstate == TSTATE_POSTBODY) { + || s->tstate == TSTATE_POSTBODY || s->tstate == TSTATE_POSTHEADER) { uip_len = 0; return; } diff --git a/test/test_httpd_tx.c b/test/test_httpd_tx.c index 3f056030..7aa97f33 100644 --- a/test/test_httpd_tx.c +++ b/test/test_httpd_tx.c @@ -156,6 +156,7 @@ void send_vlanlist(void) { } void send_lldp(void) {} extern uint8_t authenticated; +extern char passwd[21]; /* uip.c defines the listen table but no header declares it; the bench reads it * to confirm the port httpd_init() asked for is the one uIP is watching. */ @@ -362,6 +363,22 @@ static int first_body_mismatch(void) return -1; } +static int stream_contains(const char *needle) +{ + size_t n = strlen(needle); + + for (int i = 0; i + (int)n <= stream_len; i++) + if (!memcmp(stream + i, needle, n)) + return 1; + return 0; +} + +static void login_session_start(void) +{ + session_start(MSS_FULL); + strcpy(passwd, "1234"); +} + static void report(const char *tag) { if (verbose) @@ -493,6 +510,157 @@ static void scenario_bad_l4_checksum(void) "bad checksum control: the file that follows is intact"); } + +static void scenario_fragmented_post_header(void) +{ + static const char first[] = + "POST /login HTTP/1.1\r\n" + "Host: sw\r\n" + "Content-Len"; + static const char second[] = + "gth: 8\r\n" + "Content-Type: application/x-www-form-urlencoded\r\n" + "\r\n" + "pwd=1234"; + + login_session_start(); + client_send(TCP_ACK | TCP_PSH, first, (int)strlen(first)); + CHECK(stream_len == 0, + "fragmented header: incomplete first fragment has no response"); + + client_send(TCP_ACK | TCP_PSH, second, (int)strlen(second)); + CHECK(stream_contains("HTTP/1.1 302 Found\r\n"), + "fragmented header: split Content-Length is accepted"); + CHECK(stream_contains("Location: index.html\r\n"), + "fragmented header: login body is parsed after reassembly"); +} + +static void scenario_split_content_type(void) +{ + static const char first[] = + "POST /login HTTP/1.1\r\n" + "Content-Length: 8\r\n" + "Content-Ty"; + static const char second[] = + "pe: application/x-www-form-urlencoded\r\n" + "\r\n" + "pwd=1234"; + + login_session_start(); + client_send(TCP_ACK | TCP_PSH, first, (int)strlen(first)); + CHECK(stream_len == 0, + "split Content-Type: incomplete header has no response"); + client_send(TCP_ACK | TCP_PSH, second, (int)strlen(second)); + CHECK(stream_contains("Location: index.html\r\n"), + "split Content-Type: field name can span receive events"); +} + +static void scenario_split_header_terminator(void) +{ + static const char first[] = + "POST /login HTTP/1.1\r\n" + "Content-Length: 8\r\n" + "Content-Type: application/x-www-form-urlencoded\r\n" + "\r"; + static const char second[] = "\npwd=1234"; + + login_session_start(); + client_send(TCP_ACK | TCP_PSH, first, (int)strlen(first)); + CHECK(stream_len == 0, + "split terminator: CRLFCR fragment has no premature response"); + client_send(TCP_ACK | TCP_PSH, second, (int)strlen(second)); + CHECK(stream_contains("Location: index.html\r\n"), + "split terminator: CRLFCRLF can span receive events"); +} + +static void scenario_header_then_body(void) +{ + static const char header[] = + "POST /login HTTP/1.1\r\n" + "Content-Length: 8\r\n" + "Content-Type: application/x-www-form-urlencoded\r\n" + "\r\n"; + + login_session_start(); + client_send(TCP_ACK | TCP_PSH, header, (int)strlen(header)); + CHECK(stream_len == 0, + "header-only segment: waits for the declared body"); + client_send(TCP_ACK | TCP_PSH, "pwd=1234", 8); + CHECK(stream_contains("Location: index.html\r\n"), + "header-only segment: following body completes login"); +} + +static void scenario_header_with_partial_body(void) +{ + static const char first[] = + "POST /login HTTP/1.1\r\n" + "Content-Length: 8\r\n" + "Content-Type: application/x-www-form-urlencoded\r\n" + "\r\n" + "pwd="; + + login_session_start(); + client_send(TCP_ACK | TCP_PSH, first, (int)strlen(first)); + CHECK(stream_len == 0, + "partial body: waits when final header segment has only part of body"); + client_send(TCP_ACK | TCP_PSH, "1234", 4); + CHECK(stream_contains("Location: index.html\r\n"), + "partial body: existing body reassembly takes over correctly"); +} + +static void scenario_post_header_timeout(void) +{ + static const char partial[] = + "POST /login HTTP/1.1\r\n" + "Content-Length: 8\r\n" + "Content-Type: application/x-www-form-urlencoded\r\n"; + + login_session_start(); + ticks = 0; + client_send(TCP_ACK | TCP_PSH, partial, (int)strlen(partial)); + CHECK(stream_len == 0, + "header timeout: incomplete header has no immediate response"); + + /* The firmware timeout is 5 seconds; 2000 host ticks is safely beyond it. */ + ticks = 2000; + run_periodic(1); + CHECK(!uip_conn_active(0), + "header timeout: connection is aborted when the header never completes"); +} + +static void scenario_oversized_post_header(void) +{ + static const char start[] = + "POST /login HTTP/1.1\r\n" + "X-Fill: "; + char fill[1200]; + + login_session_start(); + memset(fill, 'a', sizeof(fill)); + client_send(TCP_ACK | TCP_PSH, start, (int)strlen(start)); + + /* Keep extending a header with no CRLFCRLF until the fixed buffer refuses it. */ + for (int i = 0; i < 16 && !stream_contains("400 Bad Request"); i++) + client_send(TCP_ACK | TCP_PSH, fill, (int)sizeof(fill)); + + CHECK(stream_contains("HTTP/1.1 400 Bad Request\r\n"), + "oversized header: rejected before the header buffer overflows"); +} + +static void scenario_fragmented_missing_content_length(void) +{ + static const char first[] = + "POST /login HTTP/1.1\r\n" + "Content-Type: application/x-www-form-urlencoded\r\n"; + static const char second[] = "\r\npwd=1234"; + + login_session_start(); + client_send(TCP_ACK | TCP_PSH, first, (int)strlen(first)); + client_send(TCP_ACK | TCP_PSH, second, (int)strlen(second)); + CHECK(stream_contains("HTTP/1.1 411 Length Required\r\n"), + "fragmented header: missing Content-Length still returns 411"); +} + int main(int argc, char **argv) { if (argc > 1 && !strcmp(argv[1], "-v")) @@ -504,6 +672,14 @@ int main(int argc, char **argv) scenario_growing_window(); scenario_rexmit_after_shrink(); scenario_bad_l4_checksum(); + scenario_fragmented_post_header(); + scenario_split_content_type(); + scenario_split_header_terminator(); + scenario_header_then_body(); + scenario_header_with_partial_body(); + scenario_post_header_timeout(); + scenario_oversized_post_header(); + scenario_fragmented_missing_content_length(); printf("\n%s (%d failure%s)\n", failures ? "BENCH: FAILURES" : "BENCH: ALL PASS", From b06ff76a218f7df3bf338eb7769cf269d3c899a5 Mon Sep 17 00:00:00 2001 From: HL Yi Date: Sat, 17 Oct 2026 09:05:04 -0500 Subject: [PATCH 09/34] add MACHINE_CHIPSET in header files, and add common settings in machine_defs.h --- doc/adding-a-device.md | 37 +++++++++++++++---------- machine.h | 40 ++++++++++++++++++++++++++++ machine/2G08110GSN.h | 1 + machine/2G5F4_10G2_V1_01.c | 5 +--- machine/2G5F4_10G2_V1_01.h | 1 + machine/DEFAULT_8C_1SFP.h | 1 + machine/F7008_2_5.c | 5 +--- machine/F7008_2_5.h | 1 + machine/FG_4GT_2SX_V2_0.c | 5 +--- machine/FG_4GT_2SX_V2_0.h | 1 + machine/FG_8GT_1SX.c | 5 +--- machine/FG_8GT_1SX.h | 1 + machine/FNS1200P.h | 1 + machine/GT_ST018M.h | 1 + machine/GT_ST024M.h | 1 + machine/HASIVO_S1100WP_8GT_1SX_SE.h | 1 + machine/HASIVO_S600W_4GT_2XGT_SE.c | 5 +--- machine/HASIVO_S600W_4GT_2XGT_SE.h | 1 + machine/HC_SWTG124AS.h | 1 + machine/HG0402XG_V1_1.c | 5 +--- machine/HG0402XG_V1_1.h | 1 + machine/HI_K0402WS.c | 5 +--- machine/HI_K0402WS.h | 1 + machine/HI_K0801WS.c | 5 +--- machine/HI_K0801WS.h | 1 + machine/K0501W_V2_0.c | 5 +--- machine/K0501W_V2_0.h | 1 + machine/KP_9000_6XHML_X2.c | 5 +--- machine/KP_9000_6XHML_X2.h | 1 + machine/KP_9000_6XHML_X2_V1_1.h | 1 + machine/KP_9000_6XHML_X2_V1_2.h | 1 + machine/KP_9000_6XHML_X2_V2_1.h | 1 + machine/KP_9000_6XH_X.c | 5 +--- machine/KP_9000_6XH_X.h | 1 + machine/KP_9000_6XH_X2.c | 5 +--- machine/KP_9000_6XH_X2.h | 1 + machine/KP_9000_6XH_X2_V1_1.h | 1 + machine/KP_9000_6XH_X2_V1_2.h | 1 + machine/KP_9000_6XH_X2_V2_1.h | 1 + machine/KP_9000_9XHML_X_V2_2.c | 5 +--- machine/KP_9000_9XHML_X_V2_2.h | 1 + machine/KP_9000_9XHML_X_V3_1.c | 5 +--- machine/KP_9000_9XHML_X_V3_1.h | 1 + machine/KP_9000_9XHML_X_V3_2.h | 1 + machine/KP_9000_9XH_X_EU.c | 5 +--- machine/KP_9000_9XH_X_EU.h | 1 + machine/LIANGUO_HYWS_SGT0108S.c | 5 +--- machine/LIANGUO_HYWS_SGT0108S.h | 1 + machine/LIANGUO_ZX_SWTGW215AS.c | 5 +--- machine/LIANGUO_ZX_SWTGW215AS.h | 1 + machine/ONT_S207CW_62TS_SE.c | 5 +--- machine/ONT_S207CW_62TS_SE.h | 1 + machine/PB_2132.c | 5 +--- machine/PB_2132.h | 1 + machine/PCB_K0402WS_V1.c | 5 +--- machine/PCB_K0402WS_V1.h | 1 + machine/PCB_K0402WS_V2.c | 5 +--- machine/PCB_K0402WS_V2.h | 1 + machine/PCB_K0402WS_V3.h | 1 + machine/PCB_SWTG018AS_V2_1_0.c | 5 +--- machine/PCB_SWTG018AS_V2_1_0.h | 1 + machine/PCB_SWTG024AS_A_2_0_1.c | 5 +--- machine/PCB_SWTG024AS_A_2_0_1.h | 1 + machine/POE_2G080110GS.c | 5 +--- machine/POE_2G080110GS.h | 1 + machine/SIRIVISION_S25G2206FP_V1_1.c | 5 +--- machine/SIRIVISION_S25G2206FP_V1_1.h | 1 + machine/SKS3200_8E1X.h | 1 + machine/STEAMEMO_IG204_V1.c | 5 +--- machine/STEAMEMO_IG204_V1.h | 1 + machine/SWGT024_V2_0_MANAGED.c | 5 +--- machine/SWGT024_V2_0_MANAGED.h | 1 + machine/SWGT024_V2_0_UNMANAGED.c | 5 +--- machine/SWGT024_V2_0_UNMANAGED.h | 1 + machine/SWTG018AS_A_V_2_0.c | 5 +--- machine/SWTG018AS_A_V_2_0.h | 1 + machine/SWTG024AS_A_2_0_1_5C_1SFP.c | 5 +--- machine/SWTG024AS_A_2_0_1_5C_1SFP.h | 1 + machine/SWTG024AS_V2_0.c | 5 +--- machine/SWTG024AS_V2_0.h | 1 + machine/SWTGW218AS.c | 5 +--- machine/SWTGW218AS.h | 1 + machine/TRENDNET_TEG_S562.c | 5 +--- machine/TRENDNET_TEG_S562.h | 1 + machine/YS25_0402M.h | 1 + machine/ZX310S_4T2XH.c | 5 +--- machine/ZX310S_4T2XH.h | 1 + machine/ZX310S_4T2XT.c | 5 +--- machine/ZX310S_4T2XT.h | 1 + machine/default_machine.h | 6 ++++- machine/machine_defs.h | 6 +++++ 91 files changed, 161 insertions(+), 155 deletions(-) diff --git a/doc/adding-a-device.md b/doc/adding-a-device.md index 8d45d198..312f318f 100644 --- a/doc/adding-a-device.md +++ b/doc/adding-a-device.md @@ -1,6 +1,6 @@ # Adding a new device -A device is supported by adding one board definition `.h` and board configuration `.c` file +A device is supported by adding one board header `.h` and board definition `.c` file under `machine/`. the build selects the definition by name, and CI compiles every file it finds. @@ -14,27 +14,34 @@ make MACHINE= | File | Purpose | |------|---------| | `machine/.c` | the `struct machine machine` board definition | -| `machine/.h` | `MACHINE_MODEL`, the model string shown in the UI and the CLI | +| `machine/.h` | `MACHINE_MODEL` (the model string shown in the UI and the CLI) and `MACHINE_CHIPSET` (`RTL8372` or `RTL8373`) | | `doc/devices/.md` + `doc/supported_devices.md` | (only if the board is verified and you want to support it publicly) user-facing documentation | `` is the machine symbol without its `MACHINE_` prefix, so `MACHINE` is passed exactly as spelled on the command line: `make MACHINE=MY_BOARD_1_0` needs `machine/MY_BOARD_1_0.c` and `machine/MY_BOARD_1_0.h`. -## Step 1: the model header +## Step 1: the board header -`machine/.h` only carries the product string. Use the existing files as -the template: +`machine/.h` carries the product string and the SoC family. Use the +existing files as the template: ```c #ifndef _MACHINE_MY_BOARD_1_0_H_ #define _MACHINE_MY_BOARD_1_0_H_ #define MACHINE_MODEL "Brand Model V1.0" +#define MACHINE_CHIPSET RTL8373 #endif ``` +`MACHINE_CHIPSET` is `RTL8373` or `RTL8372`; a build without it will fail. It selects the default +logical port range: `min_port` is `0` for RTL8373 and `3` for RTL8372, while `max_port` is `8`, +the highest logical port index. A board with a different range defines +`MACHINE_MIN_PORT` and/or `MACHINE_MAX_PORT` in its header to override the +defaults. + The device product string is what the CLI or the Web-Interface will print to identify the device; `machine.h` includes it by name. > [!NOTE] @@ -55,10 +62,7 @@ ports and the same number of SFP+ cages. #include "machine_defs.h" __code const struct machine machine = { - .machine_name = MACHINE_MODEL, - .isRTL8373 = 1, - .min_port = 0, - .max_port = 8, + MACHINE_COMMON_SETTING, .n_sfp = 1, .log_to_phys_port = {1, 2, 3, 4, 5, 6, 7, 8, 9}, .phys_to_log_port = {0, 1, 2, 3, 4, 5, 6, 7, 8}, @@ -89,13 +93,16 @@ __code const struct machine machine = { }; ``` +`MACHINE_COMMON_SETTING` (from `machine_defs.h`) initializes `machine_name`, +`isRTL8373`, `min_port` and `max_port` from the header's `MACHINE_MODEL` and +`MACHINE_CHIPSET`. Keep it as the first initializer and list the +board-specific fields after it. + ### Fields | Field | Meaning | |-------|---------| -| `machine_name` | always `MACHINE_MODEL` | -| `isRTL8373` | `1` for an RTL8373 SoC, `0` for RTL8372 | -| `min_port` / `max_port` | range of logical port numbers the device has; `min_port` is `0` for RTL8373 boards and `3` for RTL8372 boards (logical ports 1–2 are the SoC's internal ports on the 8372), `max_port` is usually 8. | +| `MACHINE_COMMON_SETTING` | expands to `machine_name` (`MACHINE_MODEL`), `isRTL8373` (`1` for `RTL8373`, `0` for `RTL8372`), `min_port` and `max_port`; all are derived from the header's `MACHINE_CHIPSET` (see Step 1) | | `n_sfp` | number of SFP+ cages | | `n_10g` | SerDes 10G capability used by the RTL837xN init: `0` none, `1` one, `2` two 10G-capable SerDes | | `log_to_phys_port[9]` | logical port (0-based index) → physical front-panel port number | @@ -130,8 +137,10 @@ apart: ln -s KP_9000_6XHML_X2.c machine/MY_BOARD_1_0.c ``` -The new board still needs `machine/MY_BOARD_1_0.h` (pick the version number on the PCB) with its own -`MACHINE_MODEL`, because `MACHINE_MODEL` is what distinguishes the products. +The new board still needs `machine/MY_BOARD_1_0.h` (pick the version number on +the PCB) with its own `MACHINE_MODEL` and `MACHINE_CHIPSET`: `MACHINE_MODEL` is +what distinguishes the products, and `MACHINE_CHIPSET` must match the SoC of +the board definition being reused. Existing examples: `machine/PCB_K0402WS_V3.c`, `machine/KP_9000_9XHML_X_V3_2.c` and the six `KP_9000_*` revision variants. diff --git a/machine.h b/machine.h index c0e10cd5..c55fb634 100644 --- a/machine.h +++ b/machine.h @@ -15,8 +15,48 @@ #define MACHINE_INC(dir,file) MACHINE_STR(dir/file) +#define RTL8370 0x70 +#define RTL8372 0x72 +#define RTL8373 0x73 + #include MACHINE_INC(MACHINE_DEF_DIR,MACHINE_NAME.h) + +#ifndef MACHINE_CHIPSET +#error "MACHINE_CHIPSET shall be defined in .h file" +#endif + +#ifndef MACHINE_MIN_PORT +#if MACHINE_CHIPSET == RTL8372 +#define MACHINE_MIN_PORT 3 +#else +#define MACHINE_MIN_PORT 0 +#endif +#endif + +#ifndef MACHINE_MAX_PORT +#if MACHINE_CHIPSET == RTL8370 +#define MACHINE_MAX_PORT 7 +#else +#define MACHINE_MAX_PORT 8 +#endif +#endif + +// auto derive SOC_FAMILY +#define RTL836X 6 +#define RTL837X 7 + +#ifdef SOC_FAMILY +#error "SOC_FAMILY can not define manually, shall be auto derived" +#endif +#if (MACHINE_CHIPSET == RTL8372) || (MACHINE_CHIPSET == RTL8373) +#define SOC_FAMILY RTL837X +#elif (MACHINE_CHIPSET == RTL8370 ) +#define SOC_FAMILY RTL836X +#else +#error "Unsupport MACHINE_CHIPSET is specified!" +#endif + #define LED_27 1 // SYSTEM LED #define LED_28_SYS 2 diff --git a/machine/2G08110GSN.h b/machine/2G08110GSN.h index f54133d0..46cd230f 100644 --- a/machine/2G08110GSN.h +++ b/machine/2G08110GSN.h @@ -2,5 +2,6 @@ #define _MACHINE_2G08110GSN_H_ #define MACHINE_MODEL "MokerLink 2G08110GSN" +#define MACHINE_CHIPSET RTL8373 #endif diff --git a/machine/2G5F4_10G2_V1_01.c b/machine/2G5F4_10G2_V1_01.c index 9a08e19f..e4a78ad1 100644 --- a/machine/2G5F4_10G2_V1_01.c +++ b/machine/2G5F4_10G2_V1_01.c @@ -1,10 +1,7 @@ #include "machine_defs.h" __code const struct machine machine = { - .machine_name = MACHINE_MODEL, - .isRTL8373 = 0, - .min_port = 3, - .max_port = 8, + MACHINE_COMMON_SETTING, .n_sfp = 2, /* Same 2M-PCB43-V1.1 board family as the KP-9000-6XH-X2 (see * machine/KP_9000_6XHML_X2.c), but the two SFP+ cages (physical ports 5 and diff --git a/machine/2G5F4_10G2_V1_01.h b/machine/2G5F4_10G2_V1_01.h index d372b58a..80a90fbd 100644 --- a/machine/2G5F4_10G2_V1_01.h +++ b/machine/2G5F4_10G2_V1_01.h @@ -2,5 +2,6 @@ #define _MACHINE_2G5F4_10G2_V1_01_H_ #define MACHINE_MODEL "2G5F4_10G2_V1.01 / SGT0204S" +#define MACHINE_CHIPSET RTL8372 #endif diff --git a/machine/DEFAULT_8C_1SFP.h b/machine/DEFAULT_8C_1SFP.h index 2b802a30..f19507e1 100644 --- a/machine/DEFAULT_8C_1SFP.h +++ b/machine/DEFAULT_8C_1SFP.h @@ -2,5 +2,6 @@ #define _MACHINE_DEFAULT_8C_1SFP_H_ #define MACHINE_MODEL "8+1 SFP Port Switch" +#define MACHINE_CHIPSET RTL8373 #endif diff --git a/machine/F7008_2_5.c b/machine/F7008_2_5.c index e2d08e61..df6643cc 100644 --- a/machine/F7008_2_5.c +++ b/machine/F7008_2_5.c @@ -1,10 +1,7 @@ #include "machine_defs.h" __code const struct machine machine = { - .machine_name = MACHINE_MODEL, - .isRTL8373 = 1, - .min_port = 0, - .max_port = 8, + MACHINE_COMMON_SETTING, .n_sfp = 1, .log_to_phys_port = {1, 2, 3, 4, 5, 6, 7, 8, 9}, .phys_to_log_port = {0, 1, 2, 3, 4, 5, 6, 7, 8}, diff --git a/machine/F7008_2_5.h b/machine/F7008_2_5.h index c3b0cbbf..f8c78cae 100644 --- a/machine/F7008_2_5.h +++ b/machine/F7008_2_5.h @@ -2,5 +2,6 @@ #define _MACHINE_F7008_2_5_H_ #define MACHINE_MODEL "F7008-2.5 8+1 SFP Port Switch" +#define MACHINE_CHIPSET RTL8373 #endif diff --git a/machine/FG_4GT_2SX_V2_0.c b/machine/FG_4GT_2SX_V2_0.c index 9590c6f0..9931a1a1 100644 --- a/machine/FG_4GT_2SX_V2_0.c +++ b/machine/FG_4GT_2SX_V2_0.c @@ -1,10 +1,7 @@ #include "machine_defs.h" __code const struct machine machine = { - .machine_name = MACHINE_MODEL, - .isRTL8373 = 0, - .min_port = 3, - .max_port = 8, + MACHINE_COMMON_SETTING, .n_sfp = 2, .log_to_phys_port = {0, 0, 0, 6, 1, 2, 3, 4, 5}, .phys_to_log_port = {4, 5, 6, 7, 8, 3, 0, 0, 0}, diff --git a/machine/FG_4GT_2SX_V2_0.h b/machine/FG_4GT_2SX_V2_0.h index 8f9697e7..8c819abf 100644 --- a/machine/FG_4GT_2SX_V2_0.h +++ b/machine/FG_4GT_2SX_V2_0.h @@ -2,5 +2,6 @@ #define _MACHINE_FG_4GT_2SX_V2_0_H_ #define MACHINE_MODEL "FG-4GT-2SX_V2.0" +#define MACHINE_CHIPSET RTL8372 #endif diff --git a/machine/FG_8GT_1SX.c b/machine/FG_8GT_1SX.c index 0fd3dee0..c232d92a 100644 --- a/machine/FG_8GT_1SX.c +++ b/machine/FG_8GT_1SX.c @@ -1,10 +1,7 @@ #include "machine_defs.h" __code const struct machine machine = { - .machine_name = MACHINE_MODEL, - .isRTL8373 = 1, - .min_port = 0, - .max_port = 8, + MACHINE_COMMON_SETTING, .n_sfp = 1, .log_to_phys_port = {1, 2, 3, 4, 5, 6, 7, 8, 9}, .phys_to_log_port = {0, 1, 2, 3, 4, 5, 6, 7, 8}, diff --git a/machine/FG_8GT_1SX.h b/machine/FG_8GT_1SX.h index e75a9946..789d8a9b 100644 --- a/machine/FG_8GT_1SX.h +++ b/machine/FG_8GT_1SX.h @@ -2,5 +2,6 @@ #define _MACHINE_FG_8GT_1SX_H_ #define MACHINE_MODEL "FG-8GT-1SX" +#define MACHINE_CHIPSET RTL8373 #endif diff --git a/machine/FNS1200P.h b/machine/FNS1200P.h index e5691b48..f058e5eb 100644 --- a/machine/FNS1200P.h +++ b/machine/FNS1200P.h @@ -2,5 +2,6 @@ #define _MACHINE_FNS1200P_H_ #define MACHINE_MODEL "FNS-1200P" +#define MACHINE_CHIPSET RTL8372 #endif diff --git a/machine/GT_ST018M.h b/machine/GT_ST018M.h index c4550c26..66b0c51f 100644 --- a/machine/GT_ST018M.h +++ b/machine/GT_ST018M.h @@ -2,5 +2,6 @@ #define _MACHINE_GT_ST018M_H_ #define MACHINE_MODEL "GoodTop GT-ST018M" +#define MACHINE_CHIPSET RTL8373 #endif diff --git a/machine/GT_ST024M.h b/machine/GT_ST024M.h index be57f788..8662bb31 100644 --- a/machine/GT_ST024M.h +++ b/machine/GT_ST024M.h @@ -2,5 +2,6 @@ #define _MACHINE_GT_ST024M_H_ #define MACHINE_MODEL "GoodTop GT-ST024M" +#define MACHINE_CHIPSET RTL8372 #endif diff --git a/machine/HASIVO_S1100WP_8GT_1SX_SE.h b/machine/HASIVO_S1100WP_8GT_1SX_SE.h index d50dfc22..433a42f2 100644 --- a/machine/HASIVO_S1100WP_8GT_1SX_SE.h +++ b/machine/HASIVO_S1100WP_8GT_1SX_SE.h @@ -2,5 +2,6 @@ #define _MACHINE_HASIVO_S1100WP_8GT_1SX_SE_H_ #define MACHINE_MODEL "Hasivo S1100WP-8GT-1SX-SE" +#define MACHINE_CHIPSET RTL8373 #endif diff --git a/machine/HASIVO_S600W_4GT_2XGT_SE.c b/machine/HASIVO_S600W_4GT_2XGT_SE.c index e43477d8..223c990f 100644 --- a/machine/HASIVO_S600W_4GT_2XGT_SE.c +++ b/machine/HASIVO_S600W_4GT_2XGT_SE.c @@ -1,10 +1,7 @@ #include "machine_defs.h" __code const struct machine machine = { - .machine_name = MACHINE_MODEL, - .isRTL8373 = 0, - .min_port = 3, - .max_port = 8, + MACHINE_COMMON_SETTING, .n_sfp = 0, .n_10g = 2, .log_to_phys_port = {0, 0, 0, 5, 1, 2, 3, 4, 6}, diff --git a/machine/HASIVO_S600W_4GT_2XGT_SE.h b/machine/HASIVO_S600W_4GT_2XGT_SE.h index 97beb686..dcb40306 100644 --- a/machine/HASIVO_S600W_4GT_2XGT_SE.h +++ b/machine/HASIVO_S600W_4GT_2XGT_SE.h @@ -2,5 +2,6 @@ #define _MACHINE_HASIVO_S600W_4GT_2XGT_SE_H_ #define MACHINE_MODEL "Hasivo S600W-4GT-2XGT-SE" +#define MACHINE_CHIPSET RTL8372 #endif diff --git a/machine/HC_SWTG124AS.h b/machine/HC_SWTG124AS.h index 8d4dd648..f1936317 100644 --- a/machine/HC_SWTG124AS.h +++ b/machine/HC_SWTG124AS.h @@ -2,5 +2,6 @@ #define _MACHINE_HC_SWTG124AS_H_ #define MACHINE_MODEL "Horaco HC-SWTG124AS" +#define MACHINE_CHIPSET RTL8372 #endif diff --git a/machine/HG0402XG_V1_1.c b/machine/HG0402XG_V1_1.c index 5d7be1e9..5f20e295 100644 --- a/machine/HG0402XG_V1_1.c +++ b/machine/HG0402XG_V1_1.c @@ -1,10 +1,7 @@ #include "machine_defs.h" __code const struct machine machine = { - .machine_name = MACHINE_MODEL, - .isRTL8373 = 0, - .min_port = 3, - .max_port = 8, + MACHINE_COMMON_SETTING, .n_sfp = 2, .log_to_phys_port = {0, 0, 0, 5, 1, 2, 3, 4, 6}, .phys_to_log_port = {4, 5, 6, 7, 3, 8, 0, 0, 0}, diff --git a/machine/HG0402XG_V1_1.h b/machine/HG0402XG_V1_1.h index 628dc168..5b578acc 100644 --- a/machine/HG0402XG_V1_1.h +++ b/machine/HG0402XG_V1_1.h @@ -2,5 +2,6 @@ #define _MACHINE_HG0402XG_V1_1_H_ #define MACHINE_MODEL "HG0402XG V1.1" +#define MACHINE_CHIPSET RTL8372 #endif diff --git a/machine/HI_K0402WS.c b/machine/HI_K0402WS.c index 3ad7b241..2c59d8bc 100644 --- a/machine/HI_K0402WS.c +++ b/machine/HI_K0402WS.c @@ -1,10 +1,7 @@ #include "machine_defs.h" __code const struct machine machine = { - .machine_name = MACHINE_MODEL, - .isRTL8373 = 0, - .min_port = 3, - .max_port = 8, + MACHINE_COMMON_SETTING, .n_sfp = 2, .log_to_phys_port = {0, 0, 0, 6, 1, 2, 3, 4, 5}, .phys_to_log_port = {4, 5, 6, 7, 8, 3, 0, 0, 0}, diff --git a/machine/HI_K0402WS.h b/machine/HI_K0402WS.h index d930fce9..18416117 100644 --- a/machine/HI_K0402WS.h +++ b/machine/HI_K0402WS.h @@ -2,5 +2,6 @@ #define _MACHINE_HI_K0402WS_H_ #define MACHINE_MODEL "PCB-K0402WS-V3.0" +#define MACHINE_CHIPSET RTL8372 #endif diff --git a/machine/HI_K0801WS.c b/machine/HI_K0801WS.c index 8fba5e82..cc06d550 100644 --- a/machine/HI_K0801WS.c +++ b/machine/HI_K0801WS.c @@ -1,10 +1,7 @@ #include "machine_defs.h" __code const struct machine machine = { - .machine_name = MACHINE_MODEL, - .isRTL8373 = 1, - .min_port = 0, - .max_port = 8, + MACHINE_COMMON_SETTING, .n_sfp = 1, .log_to_phys_port = {1, 2, 3, 4, 5, 6, 7, 8, 9}, .phys_to_log_port = {0, 1, 2, 3, 4, 5, 6, 7, 8}, diff --git a/machine/HI_K0801WS.h b/machine/HI_K0801WS.h index 4321d0fe..ff5a7721 100644 --- a/machine/HI_K0801WS.h +++ b/machine/HI_K0801WS.h @@ -2,5 +2,6 @@ #define _MACHINE_HI_K0801WS_H_ #define MACHINE_MODEL "Hi-Source HI-k0801WS" +#define MACHINE_CHIPSET RTL8373 #endif diff --git a/machine/K0501W_V2_0.c b/machine/K0501W_V2_0.c index 75f36c6b..51224523 100644 --- a/machine/K0501W_V2_0.c +++ b/machine/K0501W_V2_0.c @@ -1,10 +1,7 @@ #include "machine_defs.h" __code const struct machine machine = { - .machine_name = MACHINE_MODEL, - .isRTL8373 = 0, - .min_port = 3, - .max_port = 8, + MACHINE_COMMON_SETTING, .n_sfp = 1, .log_to_phys_port = {0, 0, 0, 5, 1, 2, 3, 4, 6}, .phys_to_log_port = {4, 5, 6, 7, 3, 8, 0, 0, 0}, diff --git a/machine/K0501W_V2_0.h b/machine/K0501W_V2_0.h index dbe10df6..b657edf4 100644 --- a/machine/K0501W_V2_0.h +++ b/machine/K0501W_V2_0.h @@ -2,5 +2,6 @@ #define _MACHINE_K0501W_V2_0_H_ #define MACHINE_MODEL "K0501W V2.0" +#define MACHINE_CHIPSET RTL8372 #endif diff --git a/machine/KP_9000_6XHML_X2.c b/machine/KP_9000_6XHML_X2.c index a6520f01..850d7e2a 100644 --- a/machine/KP_9000_6XHML_X2.c +++ b/machine/KP_9000_6XHML_X2.c @@ -1,10 +1,7 @@ #include "machine_defs.h" __code const struct machine machine = { - .machine_name = MACHINE_MODEL, - .isRTL8373 = 0, - .min_port = 3, - .max_port = 8, + MACHINE_COMMON_SETTING, .n_sfp = 2, .log_to_phys_port = {0, 0, 0, 5, 1, 2, 3, 4, 6}, .phys_to_log_port = {4, 5, 6, 7, 3, 8, 0, 0, 0}, diff --git a/machine/KP_9000_6XHML_X2.h b/machine/KP_9000_6XHML_X2.h index da850ae4..67551b56 100644 --- a/machine/KP_9000_6XHML_X2.h +++ b/machine/KP_9000_6XHML_X2.h @@ -2,5 +2,6 @@ #define _MACHINE_KP_9000_6XHML_X2_H_ #define MACHINE_MODEL "keepLink KP-9000-6XHML-X2" +#define MACHINE_CHIPSET RTL8372 #endif diff --git a/machine/KP_9000_6XHML_X2_V1_1.h b/machine/KP_9000_6XHML_X2_V1_1.h index 1e8b2c49..8d491998 100644 --- a/machine/KP_9000_6XHML_X2_V1_1.h +++ b/machine/KP_9000_6XHML_X2_V1_1.h @@ -2,5 +2,6 @@ #define _MACHINE_KP_9000_6XHML_X2_V1_1_H_ #define MACHINE_MODEL "keepLink KP-9000-6XHML V1.1" +#define MACHINE_CHIPSET RTL8372 #endif diff --git a/machine/KP_9000_6XHML_X2_V1_2.h b/machine/KP_9000_6XHML_X2_V1_2.h index 484ff3e2..df5fd559 100644 --- a/machine/KP_9000_6XHML_X2_V1_2.h +++ b/machine/KP_9000_6XHML_X2_V1_2.h @@ -2,5 +2,6 @@ #define _MACHINE_KP_9000_6XHML_X2_V1_2_H_ #define MACHINE_MODEL "keepLink KP-9000-6XHML V1.2" +#define MACHINE_CHIPSET RTL8372 #endif diff --git a/machine/KP_9000_6XHML_X2_V2_1.h b/machine/KP_9000_6XHML_X2_V2_1.h index 4cea1de7..3b276ac7 100644 --- a/machine/KP_9000_6XHML_X2_V2_1.h +++ b/machine/KP_9000_6XHML_X2_V2_1.h @@ -2,5 +2,6 @@ #define _MACHINE_KP_9000_6XHML_X2_V2_1_H_ #define MACHINE_MODEL "keepLink KP-9000-6XHML V2.1" +#define MACHINE_CHIPSET RTL8372 #endif diff --git a/machine/KP_9000_6XH_X.c b/machine/KP_9000_6XH_X.c index 50dcc10b..bd4b52a3 100644 --- a/machine/KP_9000_6XH_X.c +++ b/machine/KP_9000_6XH_X.c @@ -1,10 +1,7 @@ #include "machine_defs.h" __code const struct machine machine = { - .machine_name = MACHINE_MODEL, - .isRTL8373 = 0, - .min_port = 3, - .max_port = 8, + MACHINE_COMMON_SETTING, .n_sfp = 1, .log_to_phys_port = {0, 0, 0, 5, 1, 2, 3, 4, 6}, .phys_to_log_port = {4, 5, 6, 7, 3, 8, 0, 0, 0}, diff --git a/machine/KP_9000_6XH_X.h b/machine/KP_9000_6XH_X.h index f52d0ad6..664c830b 100644 --- a/machine/KP_9000_6XH_X.h +++ b/machine/KP_9000_6XH_X.h @@ -2,5 +2,6 @@ #define _MACHINE_KP_9000_6XH_X_H_ #define MACHINE_MODEL "keepLink KP-9000-6XH-X" +#define MACHINE_CHIPSET RTL8372 #endif diff --git a/machine/KP_9000_6XH_X2.c b/machine/KP_9000_6XH_X2.c index aa6a2655..9ea09451 100644 --- a/machine/KP_9000_6XH_X2.c +++ b/machine/KP_9000_6XH_X2.c @@ -1,10 +1,7 @@ #include "machine_defs.h" __code const struct machine machine = { - .machine_name = MACHINE_MODEL, - .isRTL8373 = 0, - .min_port = 3, - .max_port = 8, + MACHINE_COMMON_SETTING, .n_sfp = 2, .log_to_phys_port = {0, 0, 0, 6, 1, 2, 3, 4, 5}, .phys_to_log_port = {4, 5, 6, 7, 8, 3, 0, 0, 0}, diff --git a/machine/KP_9000_6XH_X2.h b/machine/KP_9000_6XH_X2.h index 5493dc79..2d7a8374 100644 --- a/machine/KP_9000_6XH_X2.h +++ b/machine/KP_9000_6XH_X2.h @@ -2,5 +2,6 @@ #define _MACHINE_KP_9000_6XH_X2_H_ #define MACHINE_MODEL "keepLink KP-9000-6XH-X2" +#define MACHINE_CHIPSET RTL8372 #endif diff --git a/machine/KP_9000_6XH_X2_V1_1.h b/machine/KP_9000_6XH_X2_V1_1.h index 183cc276..f3d2d068 100644 --- a/machine/KP_9000_6XH_X2_V1_1.h +++ b/machine/KP_9000_6XH_X2_V1_1.h @@ -2,5 +2,6 @@ #define _MACHINE_KP_9000_6XH_X2_V1_1_H_ #define MACHINE_MODEL "keepLink KP-9000-6XH V1.1" +#define MACHINE_CHIPSET RTL8372 #endif diff --git a/machine/KP_9000_6XH_X2_V1_2.h b/machine/KP_9000_6XH_X2_V1_2.h index 4fcd94af..2de3183e 100644 --- a/machine/KP_9000_6XH_X2_V1_2.h +++ b/machine/KP_9000_6XH_X2_V1_2.h @@ -2,5 +2,6 @@ #define _MACHINE_KP_9000_6XH_X2_V1_2_H_ #define MACHINE_MODEL "keepLink KP-9000-6XH V1.2" +#define MACHINE_CHIPSET RTL8372 #endif diff --git a/machine/KP_9000_6XH_X2_V2_1.h b/machine/KP_9000_6XH_X2_V2_1.h index a144dc96..dd1a954c 100644 --- a/machine/KP_9000_6XH_X2_V2_1.h +++ b/machine/KP_9000_6XH_X2_V2_1.h @@ -2,5 +2,6 @@ #define _MACHINE_KP_9000_6XH_X2_V2_1_H_ #define MACHINE_MODEL "keepLink KP-9000-6XH-X2 V2.1" +#define MACHINE_CHIPSET RTL8372 #endif diff --git a/machine/KP_9000_9XHML_X_V2_2.c b/machine/KP_9000_9XHML_X_V2_2.c index e73a7514..6c8338b0 100644 --- a/machine/KP_9000_9XHML_X_V2_2.c +++ b/machine/KP_9000_9XHML_X_V2_2.c @@ -1,10 +1,7 @@ #include "machine_defs.h" __code const struct machine machine = { - .machine_name = MACHINE_MODEL, - .isRTL8373 = 1, - .min_port = 0, - .max_port = 8, + MACHINE_COMMON_SETTING, .n_sfp = 1, .log_to_phys_port = { 1, 2, 3, 4, 5, 6, 7, 8, 9 }, .phys_to_log_port = { 0, 1, 2, 3, 4, 5, 6, 7, 8 }, diff --git a/machine/KP_9000_9XHML_X_V2_2.h b/machine/KP_9000_9XHML_X_V2_2.h index 2d6d0a7f..4bb261ac 100644 --- a/machine/KP_9000_9XHML_X_V2_2.h +++ b/machine/KP_9000_9XHML_X_V2_2.h @@ -2,5 +2,6 @@ #define _MACHINE_KP_9000_9XHML_X_V2_2_H_ #define MACHINE_MODEL "keepLink KP-9000-9XHML-X V2.2" +#define MACHINE_CHIPSET RTL8373 #endif diff --git a/machine/KP_9000_9XHML_X_V3_1.c b/machine/KP_9000_9XHML_X_V3_1.c index 26ea751f..515b59ac 100644 --- a/machine/KP_9000_9XHML_X_V3_1.c +++ b/machine/KP_9000_9XHML_X_V3_1.c @@ -2,10 +2,7 @@ // 2M-PCB23-V3.2 is wired like V3.1 (SFP detection, LEDs, factory MAC location) __code const struct machine machine = { - .machine_name = MACHINE_MODEL, - .isRTL8373 = 1, - .min_port = 0, - .max_port = 8, + MACHINE_COMMON_SETTING, .n_sfp = 1, .log_to_phys_port = {1, 2, 3, 4, 5, 6, 7, 8, 9}, .phys_to_log_port = {0, 1, 2, 3, 4, 5, 6, 7, 8}, diff --git a/machine/KP_9000_9XHML_X_V3_1.h b/machine/KP_9000_9XHML_X_V3_1.h index c100b5f8..ae5e8e55 100644 --- a/machine/KP_9000_9XHML_X_V3_1.h +++ b/machine/KP_9000_9XHML_X_V3_1.h @@ -2,5 +2,6 @@ #define _MACHINE_KP_9000_9XHML_X_V3_1_H_ #define MACHINE_MODEL "keepLink KP-9000-9XHML-X V3.1" +#define MACHINE_CHIPSET RTL8373 #endif diff --git a/machine/KP_9000_9XHML_X_V3_2.h b/machine/KP_9000_9XHML_X_V3_2.h index e3b4eec2..416cb327 100644 --- a/machine/KP_9000_9XHML_X_V3_2.h +++ b/machine/KP_9000_9XHML_X_V3_2.h @@ -2,5 +2,6 @@ #define _MACHINE_KP_9000_9XHML_X_V3_2_H_ #define MACHINE_MODEL "keepLink KP-9000-9XHML-X V3.2" +#define MACHINE_CHIPSET RTL8373 #endif diff --git a/machine/KP_9000_9XH_X_EU.c b/machine/KP_9000_9XH_X_EU.c index 7209e82b..17562565 100644 --- a/machine/KP_9000_9XH_X_EU.c +++ b/machine/KP_9000_9XH_X_EU.c @@ -1,10 +1,7 @@ #include "machine_defs.h" __code const struct machine machine = { - .machine_name = MACHINE_MODEL, - .isRTL8373 = 1, - .min_port = 0, - .max_port = 8, + MACHINE_COMMON_SETTING, .n_sfp = 1, .log_to_phys_port = {1, 2, 3, 4, 5, 6, 7, 8, 9}, .phys_to_log_port = {0, 1, 2, 3, 4, 5, 6, 7, 8}, diff --git a/machine/KP_9000_9XH_X_EU.h b/machine/KP_9000_9XH_X_EU.h index 2269b8fb..74c20b33 100644 --- a/machine/KP_9000_9XH_X_EU.h +++ b/machine/KP_9000_9XH_X_EU.h @@ -2,5 +2,6 @@ #define _MACHINE_KP_9000_9XH_X_EU_H_ #define MACHINE_MODEL "keepLink KP-9000-9XH-X-EU" +#define MACHINE_CHIPSET RTL8373 #endif diff --git a/machine/LIANGUO_HYWS_SGT0108S.c b/machine/LIANGUO_HYWS_SGT0108S.c index aff1713c..1160585a 100644 --- a/machine/LIANGUO_HYWS_SGT0108S.c +++ b/machine/LIANGUO_HYWS_SGT0108S.c @@ -1,10 +1,7 @@ #include "machine_defs.h" __code const struct machine machine = { - .machine_name = MACHINE_MODEL, - .isRTL8373 = 1, - .min_port = 0, - .max_port = 8, + MACHINE_COMMON_SETTING, .n_sfp = 1, .log_to_phys_port = {2, 1, 4, 3, 5, 6, 7, 8, 9}, .phys_to_log_port = {1, 0, 3, 2, 4, 5, 6, 7, 8}, diff --git a/machine/LIANGUO_HYWS_SGT0108S.h b/machine/LIANGUO_HYWS_SGT0108S.h index f82bd128..310ee653 100644 --- a/machine/LIANGUO_HYWS_SGT0108S.h +++ b/machine/LIANGUO_HYWS_SGT0108S.h @@ -2,5 +2,6 @@ #define _MACHINE_LIANGUO_HYWS_SGT0108S_H_ #define MACHINE_MODEL "Lianguo HYWS-SGT0108S" +#define MACHINE_CHIPSET RTL8373 #endif diff --git a/machine/LIANGUO_ZX_SWTGW215AS.c b/machine/LIANGUO_ZX_SWTGW215AS.c index 70414eca..dfd48f49 100644 --- a/machine/LIANGUO_ZX_SWTGW215AS.c +++ b/machine/LIANGUO_ZX_SWTGW215AS.c @@ -1,11 +1,8 @@ #include "machine_defs.h" __code const struct machine machine = { - .machine_name = MACHINE_MODEL, - .isRTL8373 = 0, + MACHINE_COMMON_SETTING, .mac_flash_offset = 0x1FC000, - .min_port = 3, - .max_port = 8, .n_sfp = 1, .log_to_phys_port = {0, 0, 0, 5, 1, 2, 3, 4, 6}, .phys_to_log_port = {4, 5, 6, 7, 3, 8, 0, 0, 0}, diff --git a/machine/LIANGUO_ZX_SWTGW215AS.h b/machine/LIANGUO_ZX_SWTGW215AS.h index 6c4e2210..840acd4a 100644 --- a/machine/LIANGUO_ZX_SWTGW215AS.h +++ b/machine/LIANGUO_ZX_SWTGW215AS.h @@ -2,5 +2,6 @@ #define _MACHINE_LIANGUO_ZX_SWTGW215AS_H_ #define MACHINE_MODEL "Lianguo ZX-SWTGW215AS" +#define MACHINE_CHIPSET RTL8372 #endif diff --git a/machine/ONT_S207CW_62TS_SE.c b/machine/ONT_S207CW_62TS_SE.c index 6ba60778..65e339e6 100644 --- a/machine/ONT_S207CW_62TS_SE.c +++ b/machine/ONT_S207CW_62TS_SE.c @@ -1,10 +1,7 @@ #include "machine_defs.h" __code const struct machine machine = { - .machine_name = MACHINE_MODEL, - .isRTL8373 = 0, - .min_port = 3, - .max_port = 8, + MACHINE_COMMON_SETTING, .n_sfp = 2, .log_to_phys_port = {0, 0, 0, 5, 4, 3, 2, 1, 6}, .phys_to_log_port = {7, 6, 5, 4, 3, 8, 0, 0, 0}, diff --git a/machine/ONT_S207CW_62TS_SE.h b/machine/ONT_S207CW_62TS_SE.h index 9938b004..1367900c 100644 --- a/machine/ONT_S207CW_62TS_SE.h +++ b/machine/ONT_S207CW_62TS_SE.h @@ -2,5 +2,6 @@ #define _MACHINE_ONT_S207CW_62TS_SE_H_ #define MACHINE_MODEL "ONT-S207CW-62TS-SE / Binardat 2G06-04210GSM / Binardat 2G06-04210GS" +#define MACHINE_CHIPSET RTL8372 #endif diff --git a/machine/PB_2132.c b/machine/PB_2132.c index 8822c066..55388d98 100644 --- a/machine/PB_2132.c +++ b/machine/PB_2132.c @@ -1,10 +1,7 @@ #include "machine_defs.h" __code const struct machine machine = { - .machine_name = MACHINE_MODEL, - .isRTL8373 = 1, - .min_port = 0, - .max_port = 8, + MACHINE_COMMON_SETTING, .n_sfp = 1, .log_to_phys_port = {1, 2, 3, 4, 5, 6, 7, 8, 9}, .phys_to_log_port = {0, 1, 2, 3, 4, 5, 6, 7, 8}, diff --git a/machine/PB_2132.h b/machine/PB_2132.h index a3668767..ac50906b 100644 --- a/machine/PB_2132.h +++ b/machine/PB_2132.h @@ -2,5 +2,6 @@ #define _MACHINE_PB_2132_H_ #define MACHINE_MODEL "PB-2132" +#define MACHINE_CHIPSET RTL8373 #endif diff --git a/machine/PCB_K0402WS_V1.c b/machine/PCB_K0402WS_V1.c index 0f365025..59b62387 100644 --- a/machine/PCB_K0402WS_V1.c +++ b/machine/PCB_K0402WS_V1.c @@ -1,10 +1,7 @@ #include "machine_defs.h" __code const struct machine machine = { - .machine_name = MACHINE_MODEL, - .isRTL8373 = 0, - .min_port = 3, - .max_port = 8, + MACHINE_COMMON_SETTING, .n_sfp = 2, .log_to_phys_port = {0, 0, 0, 6, 1, 2, 3, 4, 5}, .phys_to_log_port = {4, 5, 6, 7, 8, 3, 0, 0, 0}, diff --git a/machine/PCB_K0402WS_V1.h b/machine/PCB_K0402WS_V1.h index d1170aa7..189da400 100644 --- a/machine/PCB_K0402WS_V1.h +++ b/machine/PCB_K0402WS_V1.h @@ -2,5 +2,6 @@ #define _MACHINE_PCB_K0402WS_V1_H_ #define MACHINE_MODEL "PCB-K0402WS-V1.0" +#define MACHINE_CHIPSET RTL8372 #endif diff --git a/machine/PCB_K0402WS_V2.c b/machine/PCB_K0402WS_V2.c index 71334029..33a9a93d 100644 --- a/machine/PCB_K0402WS_V2.c +++ b/machine/PCB_K0402WS_V2.c @@ -1,10 +1,7 @@ #include "machine_defs.h" __code const struct machine machine = { - .machine_name = MACHINE_MODEL, - .isRTL8373 = 0, - .min_port = 3, - .max_port = 8, + MACHINE_COMMON_SETTING, .n_sfp = 2, .log_to_phys_port = {0, 0, 0, 6, 1, 2, 3, 4, 5}, .phys_to_log_port = {4, 5, 6, 7, 8, 3, 0, 0, 0}, diff --git a/machine/PCB_K0402WS_V2.h b/machine/PCB_K0402WS_V2.h index eb5337ab..36352e43 100644 --- a/machine/PCB_K0402WS_V2.h +++ b/machine/PCB_K0402WS_V2.h @@ -2,5 +2,6 @@ #define _MACHINE_PCB_K0402WS_V2_H_ #define MACHINE_MODEL "PCB-K0402WS-V2.0" +#define MACHINE_CHIPSET RTL8372 #endif diff --git a/machine/PCB_K0402WS_V3.h b/machine/PCB_K0402WS_V3.h index f206079d..b31bd3bb 100644 --- a/machine/PCB_K0402WS_V3.h +++ b/machine/PCB_K0402WS_V3.h @@ -2,5 +2,6 @@ #define _MACHINE_PCB_K0402WS_V3_H_ #define MACHINE_MODEL "PCB-K0402WS-V3.0" +#define MACHINE_CHIPSET RTL8372 #endif diff --git a/machine/PCB_SWTG018AS_V2_1_0.c b/machine/PCB_SWTG018AS_V2_1_0.c index 1501de45..1eb77872 100644 --- a/machine/PCB_SWTG018AS_V2_1_0.c +++ b/machine/PCB_SWTG018AS_V2_1_0.c @@ -2,11 +2,8 @@ __code const struct machine machine = { - .machine_name = MACHINE_MODEL, - .isRTL8373 = 1, + MACHINE_COMMON_SETTING, .mac_flash_offset = 0x1FC000, - .min_port = 0, - .max_port = 8, .n_sfp = 1, .log_to_phys_port = {1, 2, 3, 4, 5, 6, 7, 8, 9}, .phys_to_log_port = {0, 1, 2, 3, 4, 5, 6, 7, 8}, diff --git a/machine/PCB_SWTG018AS_V2_1_0.h b/machine/PCB_SWTG018AS_V2_1_0.h index fce78470..546fe4d0 100644 --- a/machine/PCB_SWTG018AS_V2_1_0.h +++ b/machine/PCB_SWTG018AS_V2_1_0.h @@ -2,5 +2,6 @@ #define _MACHINE_PCB_SWTG018AS_V2_1_0_H_ #define MACHINE_MODEL "SWTGW218AS (SWTG018AS-V2.1.0)" +#define MACHINE_CHIPSET RTL8373 #endif diff --git a/machine/PCB_SWTG024AS_A_2_0_1.c b/machine/PCB_SWTG024AS_A_2_0_1.c index 169e479a..0d20de50 100644 --- a/machine/PCB_SWTG024AS_A_2_0_1.c +++ b/machine/PCB_SWTG024AS_A_2_0_1.c @@ -1,10 +1,7 @@ #include "machine_defs.h" __code const struct machine machine = { - .machine_name = MACHINE_MODEL, - .isRTL8373 = 0, - .min_port = 3, - .max_port = 8, + MACHINE_COMMON_SETTING, .n_sfp = 2, .log_to_phys_port = {0, 0, 0, 5, 1, 2, 3, 4, 6}, .phys_to_log_port = {4, 5, 6, 7, 3, 8, 0, 0, 0}, diff --git a/machine/PCB_SWTG024AS_A_2_0_1.h b/machine/PCB_SWTG024AS_A_2_0_1.h index 2d3b5c22..6785140a 100644 --- a/machine/PCB_SWTG024AS_A_2_0_1.h +++ b/machine/PCB_SWTG024AS_A_2_0_1.h @@ -2,5 +2,6 @@ #define _MACHINE_PCB_SWTG024AS_A_2_0_1_H_ #define MACHINE_MODEL "PCB-SWTG024AS-A-2.0.1" +#define MACHINE_CHIPSET RTL8372 #endif diff --git a/machine/POE_2G080110GS.c b/machine/POE_2G080110GS.c index 73f6dc8c..acd4129f 100644 --- a/machine/POE_2G080110GS.c +++ b/machine/POE_2G080110GS.c @@ -1,10 +1,7 @@ #include "machine_defs.h" __code const struct machine machine = { - .machine_name = MACHINE_MODEL, - .isRTL8373 = 1, - .min_port = 0, - .max_port = 8, + MACHINE_COMMON_SETTING, .n_sfp = 1, .log_to_phys_port = {1, 2, 3, 4, 5, 6, 7, 8, 9}, .phys_to_log_port = {0, 1, 2, 3, 4, 5, 6, 7, 8}, diff --git a/machine/POE_2G080110GS.h b/machine/POE_2G080110GS.h index 40ce3415..3fafc0d5 100644 --- a/machine/POE_2G080110GS.h +++ b/machine/POE_2G080110GS.h @@ -2,5 +2,6 @@ #define _MACHINE_POE_2G080110GS_H_ #define MACHINE_MODEL "MokerLink POE-2G080110GS" +#define MACHINE_CHIPSET RTL8373 #endif diff --git a/machine/SIRIVISION_S25G2206FP_V1_1.c b/machine/SIRIVISION_S25G2206FP_V1_1.c index fde745b5..3f0db022 100644 --- a/machine/SIRIVISION_S25G2206FP_V1_1.c +++ b/machine/SIRIVISION_S25G2206FP_V1_1.c @@ -1,10 +1,7 @@ #include "machine_defs.h" __code const struct machine machine = { - .machine_name = MACHINE_MODEL, - .isRTL8373 = 0, - .min_port = 3, - .max_port = 8, + MACHINE_COMMON_SETTING, .n_sfp = 2, .log_to_phys_port = {0, 0, 0, 6, 1, 2, 3, 4, 5}, .phys_to_log_port = {4, 5, 6, 7, 8, 3, 0, 0, 0}, diff --git a/machine/SIRIVISION_S25G2206FP_V1_1.h b/machine/SIRIVISION_S25G2206FP_V1_1.h index 6dbb7c71..7bb5c9a2 100644 --- a/machine/SIRIVISION_S25G2206FP_V1_1.h +++ b/machine/SIRIVISION_S25G2206FP_V1_1.h @@ -2,5 +2,6 @@ #define _MACHINE_SIRIVISION_S25G2206FP_V1_1_H_ #define MACHINE_MODEL "SIRIVISION S25G2206FP V1.1" +#define MACHINE_CHIPSET RTL8372 #endif diff --git a/machine/SKS3200_8E1X.h b/machine/SKS3200_8E1X.h index e644baf4..ca1e7846 100644 --- a/machine/SKS3200_8E1X.h +++ b/machine/SKS3200_8E1X.h @@ -2,6 +2,7 @@ #define _MACHINE_SKS3200_8E1X_H_ #define MACHINE_MODEL "XikeStor SKS3200-8E1X" +#define MACHINE_CHIPSET RTL8373 #endif diff --git a/machine/STEAMEMO_IG204_V1.c b/machine/STEAMEMO_IG204_V1.c index 23d876a7..a7d765e3 100644 --- a/machine/STEAMEMO_IG204_V1.c +++ b/machine/STEAMEMO_IG204_V1.c @@ -1,10 +1,7 @@ #include "machine_defs.h" __code const struct machine machine = { - .machine_name = MACHINE_MODEL, - .isRTL8373 = 0, - .min_port = 3, - .max_port = 8, + MACHINE_COMMON_SETTING, .n_sfp = 2, .log_to_phys_port = {0, 0, 0, 6, 1, 2, 3, 4, 5}, .phys_to_log_port = {4, 5, 6, 7, 8, 3, 0, 0, 0}, diff --git a/machine/STEAMEMO_IG204_V1.h b/machine/STEAMEMO_IG204_V1.h index 170840d7..752493d2 100644 --- a/machine/STEAMEMO_IG204_V1.h +++ b/machine/STEAMEMO_IG204_V1.h @@ -2,5 +2,6 @@ #define _MACHINE_STEAMEMO_IG204_V1_H_ #define MACHINE_MODEL "Steamemo IG204 V1" +#define MACHINE_CHIPSET RTL8372 #endif diff --git a/machine/SWGT024_V2_0_MANAGED.c b/machine/SWGT024_V2_0_MANAGED.c index ad52bc5b..b3997fd3 100644 --- a/machine/SWGT024_V2_0_MANAGED.c +++ b/machine/SWGT024_V2_0_MANAGED.c @@ -1,10 +1,7 @@ #include "machine_defs.h" __code const struct machine machine = { - .machine_name = MACHINE_MODEL, - .isRTL8373 = 0, - .min_port = 3, - .max_port = 8, + MACHINE_COMMON_SETTING, .n_sfp = 2, .log_to_phys_port = {0, 0, 0, 6, 1, 2, 3, 4, 5}, .phys_to_log_port = {4, 5, 6, 7, 8, 3, 0, 0, 0}, diff --git a/machine/SWGT024_V2_0_MANAGED.h b/machine/SWGT024_V2_0_MANAGED.h index c5f95a04..4ee99e67 100644 --- a/machine/SWGT024_V2_0_MANAGED.h +++ b/machine/SWGT024_V2_0_MANAGED.h @@ -2,5 +2,6 @@ #define _MACHINE_SWGT024_V2_0_MANAGED_H_ #define MACHINE_MODEL "SWGT024 V2.0 Managed" +#define MACHINE_CHIPSET RTL8372 #endif diff --git a/machine/SWGT024_V2_0_UNMANAGED.c b/machine/SWGT024_V2_0_UNMANAGED.c index 9008bb4b..b07f6d8f 100644 --- a/machine/SWGT024_V2_0_UNMANAGED.c +++ b/machine/SWGT024_V2_0_UNMANAGED.c @@ -1,10 +1,7 @@ #include "machine_defs.h" __code const struct machine machine = { - .machine_name = MACHINE_MODEL, - .isRTL8373 = 0, - .min_port = 3, - .max_port = 8, + MACHINE_COMMON_SETTING, .n_sfp = 2, .log_to_phys_port = {0, 0, 0, 6, 1, 2, 3, 4, 5}, .phys_to_log_port = {4, 5, 6, 7, 8, 3, 0, 0, 0}, diff --git a/machine/SWGT024_V2_0_UNMANAGED.h b/machine/SWGT024_V2_0_UNMANAGED.h index 8391b42a..cf286b04 100644 --- a/machine/SWGT024_V2_0_UNMANAGED.h +++ b/machine/SWGT024_V2_0_UNMANAGED.h @@ -2,5 +2,6 @@ #define _MACHINE_SWGT024_V2_0_UNMANAGED_H_ #define MACHINE_MODEL "SWGT024 V2.0 Unmanaged" +#define MACHINE_CHIPSET RTL8372 #endif diff --git a/machine/SWTG018AS_A_V_2_0.c b/machine/SWTG018AS_A_V_2_0.c index 8304bf7e..7d749fde 100644 --- a/machine/SWTG018AS_A_V_2_0.c +++ b/machine/SWTG018AS_A_V_2_0.c @@ -1,10 +1,7 @@ #include "machine_defs.h" __code const struct machine machine = { - .machine_name = MACHINE_MODEL, - .isRTL8373 = 1, - .min_port = 0, - .max_port = 8, + MACHINE_COMMON_SETTING, .n_sfp = 1, .log_to_phys_port = {1, 2, 3, 4, 5, 6, 7, 8, 9}, .phys_to_log_port = {0, 1, 2, 3, 4, 5, 6, 7, 8}, diff --git a/machine/SWTG018AS_A_V_2_0.h b/machine/SWTG018AS_A_V_2_0.h index 82b7f632..60c499ec 100644 --- a/machine/SWTG018AS_A_V_2_0.h +++ b/machine/SWTG018AS_A_V_2_0.h @@ -2,5 +2,6 @@ #define _MACHINE_SWTG018AS_A_V_2_0_H_ #define MACHINE_MODEL "SWTG018AS-A V2.0" +#define MACHINE_CHIPSET RTL8373 #endif diff --git a/machine/SWTG024AS_A_2_0_1_5C_1SFP.c b/machine/SWTG024AS_A_2_0_1_5C_1SFP.c index 2a3ad97b..de37693e 100644 --- a/machine/SWTG024AS_A_2_0_1_5C_1SFP.c +++ b/machine/SWTG024AS_A_2_0_1_5C_1SFP.c @@ -1,10 +1,7 @@ #include "machine_defs.h" __code const struct machine machine = { - .machine_name = MACHINE_MODEL, - .isRTL8373 = 0, - .min_port = 3, - .max_port = 8, + MACHINE_COMMON_SETTING, .n_sfp = 1, .log_to_phys_port = {0, 0, 0, 5, 1, 2, 3, 4, 6}, .phys_to_log_port = {4, 5, 6, 7, 3, 8, 0, 0, 0}, diff --git a/machine/SWTG024AS_A_2_0_1_5C_1SFP.h b/machine/SWTG024AS_A_2_0_1_5C_1SFP.h index f492765f..6345a9ce 100644 --- a/machine/SWTG024AS_A_2_0_1_5C_1SFP.h +++ b/machine/SWTG024AS_A_2_0_1_5C_1SFP.h @@ -2,5 +2,6 @@ #define _MACHINE_SWTG024AS_A_2_0_1_5C_1SFP_H_ #define MACHINE_MODEL "SWTG024AS-A-V2.0.1-5C-1SFP" +#define MACHINE_CHIPSET RTL8372 #endif diff --git a/machine/SWTG024AS_V2_0.c b/machine/SWTG024AS_V2_0.c index eb0652e2..b1902329 100644 --- a/machine/SWTG024AS_V2_0.c +++ b/machine/SWTG024AS_V2_0.c @@ -1,10 +1,7 @@ #include "machine_defs.h" __code const struct machine machine = { - .machine_name = MACHINE_MODEL, - .isRTL8373 = 0, - .min_port = 3, - .max_port = 8, + MACHINE_COMMON_SETTING, .n_sfp = 1, .log_to_phys_port = {0, 0, 0, 5, 1, 2, 3, 4, 6}, .phys_to_log_port = {4, 5, 6, 7, 3, 8, 0, 0, 0}, diff --git a/machine/SWTG024AS_V2_0.h b/machine/SWTG024AS_V2_0.h index bd37eece..53287e84 100644 --- a/machine/SWTG024AS_V2_0.h +++ b/machine/SWTG024AS_V2_0.h @@ -2,5 +2,6 @@ #define _MACHINE_SWTG024AS_V2_0_H_ #define MACHINE_MODEL "SWTG024AS-V2.0" +#define MACHINE_CHIPSET RTL8372 #endif diff --git a/machine/SWTGW218AS.c b/machine/SWTGW218AS.c index cbb2a2f0..0d9d3f6e 100644 --- a/machine/SWTGW218AS.c +++ b/machine/SWTGW218AS.c @@ -2,11 +2,8 @@ __code const struct machine machine = { - .machine_name = MACHINE_MODEL, - .isRTL8373 = 1, + MACHINE_COMMON_SETTING, .mac_flash_offset = 0x1FC000, - .min_port = 0, - .max_port = 8, .n_sfp = 1, .log_to_phys_port = {1, 2, 3, 4, 5, 6, 7, 8, 9}, .phys_to_log_port = {0, 1, 2, 3, 4, 5, 6, 7, 8}, diff --git a/machine/SWTGW218AS.h b/machine/SWTGW218AS.h index ed9c9e54..33812670 100644 --- a/machine/SWTGW218AS.h +++ b/machine/SWTGW218AS.h @@ -2,5 +2,6 @@ #define _MACHINE_SWTGW218AS_H_ #define MACHINE_MODEL "SWTGW218AS 8+1 Managed Switch" +#define MACHINE_CHIPSET RTL8373 #endif diff --git a/machine/TRENDNET_TEG_S562.c b/machine/TRENDNET_TEG_S562.c index 3cfc12c5..a37bc84a 100644 --- a/machine/TRENDNET_TEG_S562.c +++ b/machine/TRENDNET_TEG_S562.c @@ -1,10 +1,7 @@ #include "machine_defs.h" __code const struct machine machine = { - .machine_name = MACHINE_MODEL, - .isRTL8373 = 0, - .min_port = 3, - .max_port = 8, + MACHINE_COMMON_SETTING, .n_sfp = 2, .log_to_phys_port = {0, 0, 0, 6, 1, 2, 3, 4, 5}, .phys_to_log_port = {4, 5, 6, 7, 8, 3, 0, 0, 0}, diff --git a/machine/TRENDNET_TEG_S562.h b/machine/TRENDNET_TEG_S562.h index c08ae7a9..724369ea 100644 --- a/machine/TRENDNET_TEG_S562.h +++ b/machine/TRENDNET_TEG_S562.h @@ -2,5 +2,6 @@ #define _MACHINE_TRENDNET_TEG_S562_H_ #define MACHINE_MODEL "Trendnet TEG-S562" +#define MACHINE_CHIPSET RTL8372 #endif diff --git a/machine/YS25_0402M.h b/machine/YS25_0402M.h index 1df79241..67550200 100644 --- a/machine/YS25_0402M.h +++ b/machine/YS25_0402M.h @@ -2,5 +2,6 @@ #define _MACHINE_YS25_0402M_H_ #define MACHINE_MODEL "YuanLey YS25-0402M" +#define MACHINE_CHIPSET RTL8372 #endif diff --git a/machine/ZX310S_4T2XH.c b/machine/ZX310S_4T2XH.c index f5313e02..583263e4 100644 --- a/machine/ZX310S_4T2XH.c +++ b/machine/ZX310S_4T2XH.c @@ -1,10 +1,7 @@ #include "machine_defs.h" __code const struct machine machine = { - .machine_name = MACHINE_MODEL, - .isRTL8373 = 0, - .min_port = 3, - .max_port = 8, + MACHINE_COMMON_SETTING, .n_sfp = 1, .n_10g = 1, .log_to_phys_port = {0, 0, 0, 5, 1, 2, 3, 4, 6}, diff --git a/machine/ZX310S_4T2XH.h b/machine/ZX310S_4T2XH.h index f0873be3..1f51c9dd 100644 --- a/machine/ZX310S_4T2XH.h +++ b/machine/ZX310S_4T2XH.h @@ -2,5 +2,6 @@ #define _MACHINE_ZX310S_4T2XH_H_ #define MACHINE_MODEL "ZX310S-4T2XH" +#define MACHINE_CHIPSET RTL8372 #endif diff --git a/machine/ZX310S_4T2XT.c b/machine/ZX310S_4T2XT.c index c7ec95b9..825cf810 100644 --- a/machine/ZX310S_4T2XT.c +++ b/machine/ZX310S_4T2XT.c @@ -1,10 +1,7 @@ #include "machine_defs.h" __code const struct machine machine = { - .machine_name = MACHINE_MODEL, - .isRTL8373 = 0, - .min_port = 3, - .max_port = 8, + MACHINE_COMMON_SETTING, .n_sfp = 0, .n_10g = 2, .log_to_phys_port = {0, 0, 0, 5, 1, 2, 3, 4, 6}, diff --git a/machine/ZX310S_4T2XT.h b/machine/ZX310S_4T2XT.h index 15b76217..8903d9f6 100644 --- a/machine/ZX310S_4T2XT.h +++ b/machine/ZX310S_4T2XT.h @@ -2,5 +2,6 @@ #define _MACHINE_ZX310S_4T2XT_H_ #define MACHINE_MODEL "ZX310S_4T2XT" +#define MACHINE_CHIPSET RTL8372 #endif diff --git a/machine/default_machine.h b/machine/default_machine.h index 0919674f..56233fee 100644 --- a/machine/default_machine.h +++ b/machine/default_machine.h @@ -11,7 +11,11 @@ * MACHINE_MODEL is deliberately not defined here: a build that reaches this * header must not silently pick up some default model string. Any code that * needs MACHINE_MODEL therefore fails to compile unless a real machine is - * selected. + * selected. MACHINE_CHIPSET has to be present because machine.h requires it; + * the tests supply their own `machine` object, so the chipset-derived port + * defaults below it are unused. */ +#define MACHINE_CHIPSET RTL8373 + #endif diff --git a/machine/machine_defs.h b/machine/machine_defs.h index 94b989c4..4775a58f 100644 --- a/machine/machine_defs.h +++ b/machine/machine_defs.h @@ -41,4 +41,10 @@ (scl_pin) == GPIO50_I2C_SCL2_UART1_TX ? 2 : \ (scl_pin) == GPIO40_I2C_SCL3_MDC1 ? 3 : I2CBUS_INVALID) +#define MACHINE_COMMON_SETTING \ + .machine_name = MACHINE_MODEL, \ + .isRTL8373 = MACHINE_CHIPSET == RTL8373, \ + .min_port = MACHINE_MIN_PORT, \ + .max_port = MACHINE_MAX_PORT + #endif From 9561f239b4b98aa8230a246c2d14f0c14f07dce1 Mon Sep 17 00:00:00 2001 From: HL Yi Date: Mon, 19 Oct 2026 23:59:17 -0500 Subject: [PATCH 10/34] fixed verbiage in machine.h --- machine.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/machine.h b/machine.h index c55fb634..70d75e8b 100644 --- a/machine.h +++ b/machine.h @@ -47,14 +47,14 @@ #define RTL837X 7 #ifdef SOC_FAMILY -#error "SOC_FAMILY can not define manually, shall be auto derived" +#error "SOC_FAMILY can not be manually defined, shall be auto derived" #endif #if (MACHINE_CHIPSET == RTL8372) || (MACHINE_CHIPSET == RTL8373) #define SOC_FAMILY RTL837X #elif (MACHINE_CHIPSET == RTL8370 ) #define SOC_FAMILY RTL836X #else -#error "Unsupport MACHINE_CHIPSET is specified!" +#error "Unsupported MACHINE_CHIPSET is specified!" #endif #define LED_27 1 From 0a3d7d360ae132ee545a857afec1739dcd3092d2 Mon Sep 17 00:00:00 2001 From: HL Yi Date: Tue, 20 Oct 2026 07:52:36 -0500 Subject: [PATCH 11/34] add MACHINE_CHIPSET to HASIVO_S1100P_8GT_1SX_S --- machine/HASIVO_S1100P_8GT_1SX_S.c | 5 +---- machine/HASIVO_S1100P_8GT_1SX_S.h | 1 + 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/machine/HASIVO_S1100P_8GT_1SX_S.c b/machine/HASIVO_S1100P_8GT_1SX_S.c index 4db8de17..9af4d8c3 100644 --- a/machine/HASIVO_S1100P_8GT_1SX_S.c +++ b/machine/HASIVO_S1100P_8GT_1SX_S.c @@ -1,11 +1,8 @@ #include "machine_defs.h" __code const struct machine machine = { - .machine_name = MACHINE_MODEL, - .isRTL8373 = 1, + MACHINE_COMMON_SETTING, .mac_flash_offset = 0x1FC000, - .min_port = 0, - .max_port = 8, .n_sfp = 1, .log_to_phys_port = {1, 2, 3, 4, 5, 6, 7, 8, 9}, .phys_to_log_port = {0, 1, 2, 3, 4, 5, 6, 7, 8}, diff --git a/machine/HASIVO_S1100P_8GT_1SX_S.h b/machine/HASIVO_S1100P_8GT_1SX_S.h index b34d03ef..89f03ce5 100644 --- a/machine/HASIVO_S1100P_8GT_1SX_S.h +++ b/machine/HASIVO_S1100P_8GT_1SX_S.h @@ -2,5 +2,6 @@ #define _MACHINE_HASIVO_S1100P_8GT_1SX_S_H_ #define MACHINE_MODEL "Hasivo S1100P-8GT-1SX-S" +#define MACHINE_CHIPSET RTL8373 #endif From 2588965eee07a6ed456e846502341c350c74c13a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Silva?= Date: Thu, 15 Oct 2026 17:08:28 +0100 Subject: [PATCH 12/34] httpd: handle header buffering for GET requests and add extra test cases httpd: handle config upload boundary and add regression tests httpd: handle split method names and add regression tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: João Silva --- httpd/httpd.c | 53 +++++---- test/test_httpd_tx.c | 248 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 277 insertions(+), 24 deletions(-) diff --git a/httpd/httpd.c b/httpd/httpd.c index 733f681b..fd44f628 100644 --- a/httpd/httpd.c +++ b/httpd/httpd.c @@ -55,8 +55,8 @@ __xdata uint8_t boundary[72]; #define CONFIG_UPLOAD_BUF (CONFIG_LEN + 384) __xdata uint8_t config_upload; __xdata uint8_t config_buf[CONFIG_UPLOAD_BUF]; -// bytes buffered in config_buf so far (config body, or a firmware part -// header); accumulates across TCP segments +// bytes buffered in config_buf so far (HTTP header, POST body, or a firmware +// part header); accumulates across TCP segments __xdata uint16_t pre_acc; __xdata uint8_t * __xdata content_type = 0; __xdata uint8_t * __xdata session = 0; @@ -90,7 +90,7 @@ __xdata uint32_t last_session_use; #define TSTATE_POST 4 #define TSTATE_MULTIPART 5 #define TSTATE_POSTBODY 6 -#define TSTATE_POSTHEADER 7 +#define TSTATE_HEADER 7 extern __xdata uint16_t crc_value; __xdata uint16_t crc_final; @@ -749,13 +749,13 @@ static void post_body_continue(void) /* - * Buffer a POST request header across TCP receive events. Stop copying at + * Buffer an HTTP request header across TCP receive events. Stop copying at * CRLFCRLF so any body bytes in the final segment stay in uip_appdata. * * Return the body offset in the current receive buffer, 0 while incomplete, * or 0xffff after sending an error response. */ -static uint16_t post_header_take(void) +static uint16_t request_header_take(void) { uint16_t i; @@ -778,16 +778,15 @@ static uint16_t post_header_take(void) } postbody_start = ticks; - uip_conn->appstate.tstate = TSTATE_POSTHEADER; + uip_conn->appstate.tstate = TSTATE_HEADER; return 0; } -void handle_post(void) +void handle_post(uint16_t body_off) { __xdata struct httpd_state * __xdata s = &(uip_conn->appstate); __xdata uint8_t *p = uip_appdata; __xdata uint8_t *request_path = p + 6; - uint16_t body_off; if (s->tstate == TSTATE_POSTBODY) { post_body_continue(); @@ -796,11 +795,6 @@ void handle_post(void) // Was the multipart header sent in multiple packets? if (s->tstate != TSTATE_MULTIPART) { - if (s->tstate != TSTATE_POSTHEADER) - pre_acc = 0; - body_off = post_header_take(); - if (!body_off || body_off == 0xffff) - return; p = config_buf; request_path = p + 6; @@ -848,7 +842,10 @@ void handle_post(void) dbg_string("Configuration upload\n"); verify_crc = 0; config_upload = 1; - pre_acc = 0; + // config_take() matches CRLF-prefixed delimiters, including the first. + config_buf[0] = '\r'; + config_buf[1] = '\n'; + pre_acc = 2; } // Check for other POST requests, which are not multipart, below } else { @@ -936,9 +933,9 @@ void httpd_appcall(void) dbg_string("Closing because everything has been transmitted\n"); uip_close(); s->tstate = TSTATE_CLOSED; - } else if ((s->tstate == TSTATE_POSTBODY || s->tstate == TSTATE_POSTHEADER) + } else if ((s->tstate == TSTATE_POSTBODY || s->tstate == TSTATE_HEADER) && (uint16_t)ticks - postbody_start > POSTBODY_TIMEOUT) { - dbg_string("POST request never completed\n"); + dbg_string("HTTP request never completed\n"); uip_abort(); s->tstate = TSTATE_CLOSED; } @@ -1001,6 +998,7 @@ void httpd_appcall(void) cont_len = 0; dbg_char('<'); dbg_short(uip_len); dbg_char('\n'); __xdata uint8_t *p = uip_appdata; + uint16_t body_off = 0; // Mark end of request header with \0 p[uip_len] = 0; #ifdef DEBUG @@ -1009,24 +1007,35 @@ void httpd_appcall(void) dbg_char('\n'); #endif p = uip_appdata; - if (is_word(p, "POST") || s->tstate == TSTATE_MULTIPART - || s->tstate == TSTATE_POSTBODY || s->tstate == TSTATE_POSTHEADER) { - handle_post(); + if (s->tstate != TSTATE_MULTIPART && s->tstate != TSTATE_POSTBODY) { + if (s->tstate != TSTATE_HEADER) + pre_acc = 0; + body_off = request_header_take(); + if (!body_off) { + uip_len = 0; + return; + } + if (body_off == 0xffff) + goto do_send; + } + + if (s->tstate == TSTATE_MULTIPART || s->tstate == TSTATE_POSTBODY + || is_word(config_buf, "POST")) { + handle_post(body_off); // If this is an ongoing post stream, then wait for the next packet if (s->tstate == TSTATE_POST || s->tstate == TSTATE_MULTIPART - || s->tstate == TSTATE_POSTBODY || s->tstate == TSTATE_POSTHEADER) { + || s->tstate == TSTATE_POSTBODY) { uip_len = 0; return; } goto do_send; } - // We only expect a GET request here. + p = config_buf; if (!is_word(p, "GET")) { send_bad_request(); goto do_send; } - dbg_string("GET request "); p += 4; scan_header(p); diff --git a/test/test_httpd_tx.c b/test/test_httpd_tx.c index 7aa97f33..ffd12b3d 100644 --- a/test/test_httpd_tx.c +++ b/test/test_httpd_tx.c @@ -46,6 +46,9 @@ #define FILE_START FDATA_START_login_html #define FILE_NAME "/login.html" #define FILE_LEN 6000 +#define PROTECTED_FILE_NAME "/index.html" +#define PROTECTED_FILE_START (FILE_START + FILE_LEN + 64) +#define PROTECTED_FILE_LEN 64 #define STREAM_MAX 16384 static int failures; @@ -75,11 +78,17 @@ uint8_t flash_buf[FLASH_BUF_SIZE]; uint8_t rx_headers[16]; struct flash_region_t flash_region; +static uint8_t written_config[CONFIG_LEN]; +static uint16_t written_config_len; +static uint32_t config_erase_addr, config_write_addr; +static int config_erases, config_writes; + const char * const mime_strings[] = { "text/html", "image/svg+xml", "image/x-icon", "image/png", "text/javascript", "text/css", "text/plain" }; const struct f_data f_data[] = { { FILE_NAME, FILE_START, FILE_LEN, mime_HTML, 0 }, + { PROTECTED_FILE_NAME, PROTECTED_FILE_START, PROTECTED_FILE_LEN, mime_HTML, 0 }, { 0, 0, 0, mime_HTML, 0 }, }; @@ -90,8 +99,20 @@ void flash_read_bulk(uint8_t *dst) } void flash_init(uint8_t enable_dio) { (void)enable_dio; } -void flash_sector_erase(void) { } -void flash_write_bytes(uint8_t *ptr) { (void)ptr; } +void flash_sector_erase(void) +{ + config_erases++; + config_erase_addr = flash_region.addr; +} + +void flash_write_bytes(uint8_t *ptr) +{ + config_writes++; + config_write_addr = flash_region.addr; + written_config_len = flash_region.len; + if (written_config_len <= sizeof(written_config)) + memcpy(written_config, ptr, written_config_len); +} const char *get_flash_size_str(void) { return "512 kB"; } void crc16_bank1(uint8_t *v) { (void)v; } void reset_chip(void) { } @@ -156,6 +177,7 @@ void send_vlanlist(void) { } void send_lldp(void) {} extern uint8_t authenticated; +extern char session_id[]; extern char passwd[21]; /* uip.c defines the listen table but no header declares it; the bench reads it @@ -661,6 +683,220 @@ static void scenario_fragmented_missing_content_length(void) "fragmented header: missing Content-Length still returns 411"); } + +static void scenario_fragmented_get_cookie(void) +{ + static const char first[] = + "GET " PROTECTED_FILE_NAME " HTTP/1.1\r\n" + "Host: sw\r\n" + "Cook"; + static const char second[] = + "ie: session=0123456789ab\r\n" + "\r\n"; + + session_start(MSS_FULL); + strcpy(session_id, "0123456789ab"); + + client_send(TCP_ACK | TCP_PSH, first, (int)strlen(first)); + CHECK(stream_len == 0, + "fragmented GET cookie: no redirect before the header completes"); + + client_send(TCP_ACK | TCP_PSH, second, (int)strlen(second)); + CHECK(stream_contains("HTTP/1.1 200 OK\r\n"), + "fragmented GET cookie: protected index is served"); + CHECK(!stream_contains("Location: login.html\r\n"), + "fragmented GET cookie: session is not lost on the redirected GET"); +} + +static void scenario_fragmented_get_cookie_value(void) +{ + static const char first[] = + "GET " PROTECTED_FILE_NAME " HTTP/1.1\r\n" + "Host: sw\r\n" + "Cookie: session=012345"; + static const char second[] = + "6789ab\r\n" + "\r\n"; + + session_start(MSS_FULL); + strcpy(session_id, "0123456789ab"); + + client_send(TCP_ACK | TCP_PSH, first, (int)strlen(first)); + CHECK(stream_len == 0, + "fragmented GET cookie value: waits for the rest of the header"); + client_send(TCP_ACK | TCP_PSH, second, (int)strlen(second)); + CHECK(stream_contains("HTTP/1.1 200 OK\r\n"), + "fragmented GET cookie value: split session value authenticates"); +} + +static void scenario_split_get_header_terminator(void) +{ + static const char first[] = + "GET " PROTECTED_FILE_NAME " HTTP/1.1\r\n" + "Cookie: session=0123456789ab\r\n" + "\r"; + static const char second[] = "\n"; + + session_start(MSS_FULL); + strcpy(session_id, "0123456789ab"); + + client_send(TCP_ACK | TCP_PSH, first, (int)strlen(first)); + CHECK(stream_len == 0, + "fragmented GET terminator: CRLFCR does not trigger parsing"); + client_send(TCP_ACK | TCP_PSH, second, 1); + CHECK(stream_contains("HTTP/1.1 200 OK\r\n"), + "fragmented GET terminator: CRLFCRLF may span receive events"); +} + +static void scenario_fragmented_get_without_cookie(void) +{ + static const char first[] = + "GET " PROTECTED_FILE_NAME " HTTP/1.1\r\n" + "Host: sw\r\n"; + static const char second[] = "\r\n"; + + session_start(MSS_FULL); + strcpy(session_id, "0123456789ab"); + + client_send(TCP_ACK | TCP_PSH, first, (int)strlen(first)); + client_send(TCP_ACK | TCP_PSH, second, (int)strlen(second)); + CHECK(stream_contains("HTTP/1.1 302 Found\r\n"), + "fragmented GET without cookie: protected file still redirects"); + CHECK(stream_contains("Location: login.html\r\n"), + "fragmented GET without cookie: authentication is not carried over"); +} + +static void scenario_get_header_timeout(void) +{ + static const char partial[] = + "GET " PROTECTED_FILE_NAME " HTTP/1.1\r\n" + "Host: sw\r\n" + "Cookie: session=012345"; + + session_start(MSS_FULL); + strcpy(session_id, "0123456789ab"); + ticks = 0; + + client_send(TCP_ACK | TCP_PSH, partial, (int)strlen(partial)); + CHECK(stream_len == 0, + "fragmented GET timeout: incomplete header has no immediate response"); + + ticks = 2000; + run_periodic(1); + CHECK(!uip_conn_active(0), + "fragmented GET timeout: incomplete request is eventually aborted"); +} + +static void scenario_oversized_get_header(void) +{ + static const char start[] = + "GET " PROTECTED_FILE_NAME " HTTP/1.1\r\n" + "X-Fill: "; + char fill[1200]; + + session_start(MSS_FULL); + memset(fill, 'a', sizeof(fill)); + + client_send(TCP_ACK | TCP_PSH, start, (int)strlen(start)); + for (int i = 0; i < 16 && !stream_contains("400 Bad Request"); i++) + client_send(TCP_ACK | TCP_PSH, fill, (int)sizeof(fill)); + + CHECK(stream_contains("HTTP/1.1 400 Bad Request\r\n"), + "oversized GET header: fixed header buffer is bounds checked"); +} + +static void scenario_split_method_names(void) +{ + static const char get[] = + "GET " PROTECTED_FILE_NAME " HTTP/1.1\r\n" + "Cookie: session=0123456789ab\r\n\r\n"; + static const char post[] = + "POST /login HTTP/1.1\r\n" + "Content-Length: 8\r\n" + "Content-Type: application/x-www-form-urlencoded\r\n\r\n" + "pwd=1234"; + int get_waits = 1, get_ok = 1, post_waits = 1, post_ok = 1; + + for (int split = 1; split < 3; split++) { + session_start(MSS_FULL); + strcpy(session_id, "0123456789ab"); + client_send(TCP_ACK | TCP_PSH, get, split); + if (stream_len) + get_waits = 0; + client_send(TCP_ACK | TCP_PSH, get + split, (int)strlen(get) - split); + if (!stream_contains("HTTP/1.1 200 OK\r\n")) + get_ok = 0; + } + CHECK(get_waits, "split GET method: incomplete verb waits for the header"); + CHECK(get_ok, "split GET method: every split inside GET serves the file"); + + for (int split = 1; split < 4; split++) { + login_session_start(); + client_send(TCP_ACK | TCP_PSH, post, split); + if (stream_len) + post_waits = 0; + client_send(TCP_ACK | TCP_PSH, post + split, (int)strlen(post) - split); + if (!stream_contains("Location: index.html\r\n")) + post_ok = 0; + } + CHECK(post_waits, "split POST method: incomplete verb waits for the header"); + CHECK(post_ok, "split POST method: every split inside POST completes login"); +} + +static void scenario_config_upload(void) +{ + static const char expected[] = "hostname upload-test\nip 10.0.0.1\n"; + static const char body[] = + "--upload-boundary\r\n" + "Content-Disposition: form-data; name=\"file\"; filename=\"config.txt\"\r\n" + "Content-Type: text/plain\r\n\r\n" + "hostname upload-test\nip 10.0.0.1\n" + "\r\n--upload-boundary--\r\n"; + char request[768]; + int request_len, first_bad_response = -1, first_bad_flash = -1; + + request_len = snprintf(request, sizeof(request), + "POST /config HTTP/1.1\r\n" + "Host: sw\r\n" + "Cookie: session=0123456789ab\r\n" + "Content-Type: multipart/form-data; boundary=upload-boundary\r\n" + "Content-Length: %zu\r\n\r\n%s", sizeof(body) - 1, body); + if (request_len < 0 || request_len >= (int)sizeof(request)) { + CHECK(0, "multipart/config: test request fits the client buffer"); + return; + } + + /* The same well-formed request must work in one event and with a split + * anywhere in its HTTP header, first multipart delimiter, part headers, + * configuration, or closing delimiter. No extra CRLF is added to the body. */ + for (int split = 0; split <= request_len; split++) { + session_start(MSS_FULL); + strcpy(session_id, "0123456789ab"); + config_erases = config_writes = 0; + written_config_len = 0; + memset(written_config, 0xa5, sizeof(written_config)); + if (split) + client_send(TCP_ACK | TCP_PSH, request, split); + if (split < request_len) + client_send(TCP_ACK | TCP_PSH, request + split, request_len - split); + if (!stream_contains("HTTP/1.1 200 OK\r\n") && first_bad_response < 0) + first_bad_response = split; + if ((config_erases != 1 || config_writes != 1 + || config_erase_addr != CONFIG_START || config_write_addr != CONFIG_START + || written_config_len != sizeof(expected) + || memcmp(written_config, expected, sizeof(expected))) && first_bad_flash < 0) + first_bad_flash = split; + } + if (first_bad_response >= 0) + printf(" multipart/config: first rejected request split at byte %d\n", first_bad_response); + if (first_bad_flash >= 0) + printf(" multipart/config: first incorrect flash write at split %d\n", first_bad_flash); + CHECK(first_bad_response < 0, + "multipart/config: complete request and every two-event split return 200"); + CHECK(first_bad_flash < 0, + "multipart/config: every split writes the exact configuration and NUL to its sector"); +} + int main(int argc, char **argv) { if (argc > 1 && !strcmp(argv[1], "-v")) @@ -680,6 +916,14 @@ int main(int argc, char **argv) scenario_post_header_timeout(); scenario_oversized_post_header(); scenario_fragmented_missing_content_length(); + scenario_fragmented_get_cookie(); + scenario_fragmented_get_cookie_value(); + scenario_split_get_header_terminator(); + scenario_fragmented_get_without_cookie(); + scenario_get_header_timeout(); + scenario_oversized_get_header(); + scenario_split_method_names(); + scenario_config_upload(); printf("\n%s (%d failure%s)\n", failures ? "BENCH: FAILURES" : "BENCH: ALL PASS", From 491a91910576dba5819e678e5d08c4adbb4f88c3 Mon Sep 17 00:00:00 2001 From: avicarmeli <32562196+avicarmeli@users.noreply.github.com> Date: Tue, 20 Oct 2026 18:47:33 +0300 Subject: [PATCH 13/34] httpd: clear upload reset intent when the TCP slot is reused With UIP_CONF_MAX_CONNECTIONS set to one, a verified upload can leave reset intent set when its response is never acknowledged. A subsequent TCP connection reuses that slot, and ACKing its plain GET response can otherwise trigger reset_chip(). This is sequential slot reuse, not concurrent HTTP connections. Store reset intent in the connection appstate and initialize both tstate and fw_reset_pending on every uip_connected() event, regardless of stale appstate contents. Reset only after the verified upload response is fully acknowledged. Exercise the real HTTP callback for all stale tstate bytes, sequential slot reuse and a later GET, partial/final ACKs, abort, timeout and CRC failure. Keep the regression tests in the existing tab-indented style. --- httpd/httpd.c | 11 ++-- httpd/httpd.h | 1 + test/test_httpd_tx.c | 118 ++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 122 insertions(+), 8 deletions(-) diff --git a/httpd/httpd.c b/httpd/httpd.c index f2ca2d36..6d70828a 100644 --- a/httpd/httpd.c +++ b/httpd/httpd.c @@ -75,9 +75,6 @@ __xdata uint8_t postbody_endpoint; __xdata uint16_t postbody_start; __xdata char passwd[21]; -// Set when a verified firmware upload awaits its response ACK, after -// which the chip resets to apply the staged image -__xdata uint8_t fw_reset_pending; __xdata char session_id[SESSION_ID_LENGTH + 1]; __xdata uint8_t authenticated; __xdata uint32_t now; @@ -110,7 +107,6 @@ void httpd_init(void) __banked // Not through uip_conn: it only points at a connection while uIP is // handling one, and nothing has set it yet at init time. uip_conns[0].appstate.tstate = TSTATE_CLOSED; - fw_reset_pending = 0; // xdata is not zeroed by the startup code } @@ -511,7 +507,7 @@ uint8_t stream_upload(void) "Content-Type: text/plain\r\n\r\n" "OK: checksum verified, rebooting\n"); // Reset once the response is fully ACKed - fw_reset_pending = 1; + s->fw_reset_pending = 1; } else { print_string("Checksum incorrect! Aborting.\n"); slen = strtox(outbuf, "HTTP/1.1 400 Bad Request\r\nContent-Length: 33\r\n" @@ -874,9 +870,10 @@ void httpd_appcall(void) print_byte(s->tstate); write_char(' '); #endif - if(uip_connected() && s->tstate == TSTATE_CLOSED) { + if(uip_connected()) { dbg_string("Connected...\n"); s->tstate = TSTATE_NONE; + s->fw_reset_pending = 0; // explicitly initialize reused XDATA appstate } else if (uip_closed()) { dbg_string("Connection closed\n"); s->tstate = TSTATE_CLOSED; @@ -928,7 +925,7 @@ void httpd_appcall(void) cont_len -= slen; cont_addr += slen; s->tstate = TSTATE_TX; - } else if (fw_reset_pending) { + } else if (s->fw_reset_pending) { // The upload verdict has been fully ACKed by the client; // now it is safe to reset and apply the staged image print_string("Resetting to apply update\n"); diff --git a/httpd/httpd.h b/httpd/httpd.h index 91b83b22..5cabe3d5 100644 --- a/httpd/httpd.h +++ b/httpd/httpd.h @@ -12,6 +12,7 @@ for each TCP connection. */ typedef struct httpd_state { uint8_t tstate; + uint8_t fw_reset_pending; } uip_tcp_appstate_t; /* Finally we define the application function to be called by uIP. */ diff --git a/test/test_httpd_tx.c b/test/test_httpd_tx.c index 9b31141d..a35d9267 100644 --- a/test/test_httpd_tx.c +++ b/test/test_httpd_tx.c @@ -94,7 +94,8 @@ void flash_sector_erase(void) { } void flash_write_bytes(uint8_t *ptr) { (void)ptr; } const char *get_flash_size_str(void) { return "512 kB"; } void crc16_bank1(uint8_t *v) { (void)v; } -void reset_chip(void) { } +static unsigned reset_calls; +void reset_chip(void) { reset_calls++; } void delay(uint16_t t) { (void)t; } void write_char(char c) { (void)c; } void write_char_no_syslog(char c) { (void)c; } @@ -493,6 +494,120 @@ static void scenario_bad_l4_checksum(void) "bad checksum control: the file that follows is intact"); } + +/* Private HTTP lifecycle values; drive the real callback, not a model. */ +enum { TSTATE_NONE = 0, TSTATE_TX = 1 }; +extern uint16_t slen, cont_len, sent_len, bindex, crc_final, write_len; +extern uint8_t boundary[], verify_crc, outbuf[]; +extern struct { uint8_t *p; uint16_t bptr, plen; } upload_settings; +extern uint8_t stream_upload(void); + +static void scenario_upload_reset_owner(void) +{ + uint8_t byte = 0; + uint8_t get[] = "GET " FILE_NAME " HTTP/1.1\r\nHost: sw\r\n\r\n"; + int initialized = 1; + + /* The firmware has one TCP slot. Its appstate can contain stale bytes. */ + uip_conn = &uip_conns[0]; + reset_calls = 0; + for (unsigned state = 0; state <= 0xff; state++) { + uip_conn->appstate.tstate = state; + uip_conn->appstate.fw_reset_pending = 0xaa; + uip_flags = UIP_CONNECTED; + httpd_appcall(); + if (uip_conn->appstate.tstate != TSTATE_NONE + || uip_conn->appstate.fw_reset_pending != 0) + initialized = 0; + } + CHECK(initialized, "connect initializes both fields for every stale state"); + CHECK(reset_calls == 0, "connection initialization does not reset"); + + /* End-of-part verdict with flash/CRC hardware edges mocked. */ + boundary[0] = 0; + bindex = 0; + verify_crc = 1; + crc_final = 0xb001; + write_len = 0; + upload_settings.p = &byte; + upload_settings.bptr = 0; + upload_settings.plen = 1; + stream_upload(); + CHECK(uip_conn->appstate.fw_reset_pending == 1, + "verified upload records reset intent in its slot"); + + uip_conn->appstate.tstate = TSTATE_TX; + uip_conn->mss = MSS_FULL; + slen = 10; + sent_len = 5; + cont_len = 0; + uip_flags = UIP_ACKDATA; + httpd_appcall(); + CHECK(reset_calls == 0 && slen == 5 && sent_len == 5, + "partial verdict ACK sends the remainder without resetting"); + uip_flags = UIP_ACKDATA; + httpd_appcall(); + CHECK(reset_calls == 1 && slen == 0, + "final verdict ACK resets after all response bytes are acknowledged"); + + /* No verdict ACK: a later connection reuses the same slot. */ + reset_calls = 0; + uip_conn->appstate.tstate = TSTATE_TX; + uip_conn->appstate.fw_reset_pending = 1; + uip_flags = UIP_CONNECTED; + httpd_appcall(); + CHECK(uip_conn->appstate.tstate == TSTATE_NONE + && uip_conn->appstate.fw_reset_pending == 0, + "slot reuse clears an unacknowledged upload's reset intent"); + uip_appdata = get; + uip_len = strlen((char *)get); + uip_flags = UIP_NEWDATA; + httpd_appcall(); + CHECK(uip_conn->appstate.tstate == TSTATE_TX && slen > 0, + "reused slot serves a subsequent plain GET"); + for (unsigned i = 0; i < 20 && uip_conn->appstate.tstate == TSTATE_TX; i++) { + uip_flags = UIP_ACKDATA; + httpd_appcall(); + } + CHECK(reset_calls == 0 && slen == 0 && cont_len == 0, + "subsequent GET response ACKs cannot inherit reset intent"); + + for (unsigned i = 0; i < 2; i++) { + uip_conn->appstate.tstate = TSTATE_TX; + uip_conn->appstate.fw_reset_pending = 1; + reset_calls = 0; + uip_flags = i ? UIP_TIMEDOUT : UIP_ABORT; + httpd_appcall(); + CHECK(reset_calls == 0, "abort/timeout does not reset"); + uip_flags = UIP_CONNECTED; + httpd_appcall(); + CHECK(uip_conn->appstate.tstate == TSTATE_NONE + && uip_conn->appstate.fw_reset_pending == 0, + "connect after abort/timeout clears old upload intent"); + uip_conn->appstate.tstate = TSTATE_TX; + slen = 0; + cont_len = 0; + sent_len = 0; + uip_flags = UIP_ACKDATA; + httpd_appcall(); + CHECK(reset_calls == 0, "new connection ACK cannot inherit reset"); + } + + crc_final = 0; + bindex = 0; + stream_upload(); + CHECK(uip_conn->appstate.fw_reset_pending == 0, + "failed CRC does not request reset"); + CHECK(strstr((char *)outbuf, "HTTP/1.1 400 Bad Request") != NULL, + "failed CRC returns an error verdict"); + uip_conn->appstate.tstate = TSTATE_TX; + sent_len = slen; + cont_len = 0; + uip_flags = UIP_ACKDATA; + httpd_appcall(); + CHECK(reset_calls == 0, "failed CRC verdict ACK does not reset"); +} + int main(int argc, char **argv) { if (argc > 1 && !strcmp(argv[1], "-v")) @@ -504,6 +619,7 @@ int main(int argc, char **argv) scenario_growing_window(); scenario_rexmit_after_shrink(); scenario_bad_l4_checksum(); + scenario_upload_reset_owner(); printf("\n%s (%d failure%s)\n", failures ? "BENCH: FAILURES" : "BENCH: ALL PASS", From 413d10bbcc8b5b1dec7378c3c0ec683979b38aee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Silva?= Date: Tue, 20 Oct 2026 18:56:31 +0100 Subject: [PATCH 14/34] nit: add test build directories to gitignore MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: João Silva --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index f5c8e8c7..11f5c4ed 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ version.h tools/httpd_sim tools/injector tools/fileadder +build/ # host-test stand-ins for the two generated headers !test/stub/html_data.h From 620edafd62504a5bd8f8ae4a5b2a6fabb48fffb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Silva?= Date: Tue, 20 Oct 2026 19:01:00 +0100 Subject: [PATCH 15/34] sfp: force higher rate SFP modules to 10G sds: validate mode before touching anything MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: João Silva --- boot.c | 27 +++++++++++++++------------ sfp.c | 3 ++- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/boot.c b/boot.c index adcb192b..18e9a79d 100644 --- a/boot.c +++ b/boot.c @@ -125,18 +125,6 @@ void early_boot_handle_button(void) __banked void sds_config(uint8_t sds, uint8_t mode) __banked { print_string("sds_config sds: "); print_byte(sds); print_string(", mode: "); print_byte(mode); write_char('\n'); - sds_config_mac(sds, mode); - - if (mode == SDS_10GR || mode == SDS_QXGMII) - sds_write_v(sds, 0x21, 0x10, 0x4480); // Q002110:6480 - else - sds_write_v(sds, 0x21, 0x10, 0x6480); // Q002110:6480 - sds_write_v(sds, 0x21, 0x13, 0x0400); // Q002113:0400 - sds_write_v(sds, 0x21, 0x18, 0x6d02); // Q002118:6d02 - sds_write_v(sds, 0x21, 0x1b, 0x424e); // Q00211b:424e - sds_write_v(sds, 0x21, 0x1d, 0x0002); // Q00211d:0002 - sds_write_v(sds, 0x36, 0x1c, 0x1390); // Q00361c:1390 - sds_write_v(sds, 0x36, 0x14, 0x003f); // Q003614:003f uint8_t page = 0; uint16_t v = 0; @@ -165,6 +153,21 @@ void sds_config(uint8_t sds, uint8_t mode) __banked print_string("Error in SDS Mode\n"); return; } + + sds_config_mac(sds, mode); + + if (mode == SDS_10GR || mode == SDS_QXGMII) + sds_write_v(sds, 0x21, 0x10, 0x4480); // Q002110:6480 + else + sds_write_v(sds, 0x21, 0x10, 0x6480); // Q002110:6480 + + sds_write_v(sds, 0x21, 0x13, 0x0400); // Q002113:0400 + sds_write_v(sds, 0x21, 0x18, 0x6d02); // Q002118:6d02 + sds_write_v(sds, 0x21, 0x1b, 0x424e); // Q00211b:424e + sds_write_v(sds, 0x21, 0x1d, 0x0002); // Q00211d:0002 + sds_write_v(sds, 0x36, 0x1c, 0x1390); // Q00361c:1390 + sds_write_v(sds, 0x36, 0x14, 0x003f); // Q003614:003f + sds_write_v(sds, 0x36, 0x10, v); // Q003610:0200 if (page == 0x2e) { // 10G Fiber / SDS_QXGMII diff --git a/sfp.c b/sfp.c index 05599717..57065289 100644 --- a/sfp.c +++ b/sfp.c @@ -59,8 +59,9 @@ static inline uint8_t sfp_rate_to_sds_config(uint8_t rate) return SDS_1000BX_FIBER; if (rate >= 0x19 && rate <= 0x20) // Ethernet 2.5 GBit return SDS_HSG; - if (rate >= 0x62 && rate < 0x70) + if (rate >= 0x62 /* && rate < 0x70 */) // Force higher rates to 10G (e.g., 25G, 50G) return SDS_10GR; + return 0xff; } From 7673ef8322867ccb2e7994fce3563470ecac0774 Mon Sep 17 00:00:00 2001 From: HL Yi Date: Wed, 21 Oct 2026 15:20:56 -0500 Subject: [PATCH 16/34] desolve machine_init.c similar to what we did for machine.c --- Makefile | 29 ++++--- doc/adding-a-device.md | 17 ++++- machine/2G5F4_10G2_V1_01.c | 4 +- machine/2G5F4_10G2_V1_01_init.c | 1 + machine/FG_4GT_2SX_V2_0_init.c | 6 ++ machine/FNS1200P_init.c | 1 + machine/HI_K0402WS_init.c | 1 + machine/KP_9000_6XHML_X2_V2_1_init.c | 1 + machine/KP_9000_6XH_X2_V2_1_init.c | 1 + machine/KP_9000_6XH_X2_init.c | 6 ++ machine/PCB_K0402WS_V2_init.c | 1 + machine/PCB_K0402WS_V3_init.c | 1 + machine/PCB_SWTG018AS_V2_1_0_init.c | 18 +++++ machine/PCB_SWTG024AS_A_2_0_1_init.c | 9 +++ machine/SWTG024AS_A_2_0_1_5C_1SFP_init.c | 1 + machine/SWTG024AS_V2_0_init.c | 20 +++++ machine/ZX310S_4T2XT_init.c | 8 ++ machine/default_machine_init.c | 6 ++ machine/machine_init_defs.h | 10 +++ machine_init.c | 96 ------------------------ 20 files changed, 128 insertions(+), 109 deletions(-) create mode 120000 machine/2G5F4_10G2_V1_01_init.c create mode 100644 machine/FG_4GT_2SX_V2_0_init.c create mode 120000 machine/FNS1200P_init.c create mode 120000 machine/HI_K0402WS_init.c create mode 120000 machine/KP_9000_6XHML_X2_V2_1_init.c create mode 120000 machine/KP_9000_6XH_X2_V2_1_init.c create mode 100644 machine/KP_9000_6XH_X2_init.c create mode 120000 machine/PCB_K0402WS_V2_init.c create mode 120000 machine/PCB_K0402WS_V3_init.c create mode 100644 machine/PCB_SWTG018AS_V2_1_0_init.c create mode 100644 machine/PCB_SWTG024AS_A_2_0_1_init.c create mode 120000 machine/SWTG024AS_A_2_0_1_5C_1SFP_init.c create mode 100644 machine/SWTG024AS_V2_0_init.c create mode 100644 machine/ZX310S_4T2XT_init.c create mode 100644 machine/default_machine_init.c create mode 100644 machine/machine_init_defs.h delete mode 100644 machine_init.c diff --git a/Makefile b/Makefile index c95f12af..96c07024 100644 --- a/Makefile +++ b/Makefile @@ -15,11 +15,10 @@ SUBDIRS := tools SUBDIRSCLEAN=$(addsuffix clean,$(SUBDIRS)) # $MACHINE selects machine/$(MACHINE).c as the board definition and is passed -# on as -DMACHINE_$(MACHINE), which the rest of the firmware tests with -# #if defined(MACHINE_...), and as -DMACHINE_NAME, which machine.h uses to -# include machine/$(MACHINE).h. Both take the same value, so they cannot drift. +# on as -DMACHINE_NAME, which machine.h uses to include machine/$(MACHINE).h. +# Board selection itself needs no MACHINE_* symbol for #if chains, so the +# definition is all the compiler has to know. ifneq ($(MACHINE),) - CC_FLAGS += -DMACHINE_$(MACHINE) CC_FLAGS += -DMACHINE_NAME=$(MACHINE) endif # Health instrumentation and the "health" console command: HEALTH=1 gmake ... @@ -34,6 +33,12 @@ endif # The board definition being built: one file per MACHINE_* symbol in machine.h. MACHINE_SRC = machine/$(MACHINE).c +MACHINE_INIT_DEFAULT := machine/default_machine_init.c +MACHINE_INIT_SRC := $(wildcard machine/$(MACHINE)_init.c) +ifeq ($(MACHINE_INIT_SRC),) + MACHINE_INIT_SRC := $(MACHINE_INIT_DEFAULT) +endif + BUILDDIR = output/$(MACHINE) VERSION_HEADER := version.h @@ -81,7 +86,7 @@ $(MACHINE_SRC): # invalid $MACHINE value SRCS = \ $(MACHINE_SRC) \ - machine_init.c \ + $(MACHINE_INIT_SRC) \ cmd_editor.c \ cmd_parser.c \ dhcp.c \ @@ -203,21 +208,25 @@ $(BUILDDIR)/rtlplayground-$(FILENAME_EXTENSION).bin: $(BUILDDIR)/rtlplayground.i .PHONY: clean distclean all $(SUBDIRS) $(SUBDIRSCLEAN) create_build_dir # Every machine/ definition is compiled, so a machine added to machine/ is -# covered without registering it anywhere. The machine-specific defines are +# covered without registering it anywhere. The _init.c files are excluded here: +# they are the boot hooks, compiled separately below (the board's own if it +# exists, otherwise default_machine_init.c). The machine-specific defines are # filtered out of $(CC_FLAGS) and supplied per iteration instead, so this also # works as "make machine_check MACHINE=...". -MACHINE_DEFS := $(sort $(patsubst machine/%.c,%,$(wildcard machine/*.c))) +MACHINE_DEFS := $(sort $(patsubst machine/%.c,%,$(filter-out machine/%_init.c,$(wildcard machine/*.c)))) MACHINE_LESS_CC_FLAGS = $(filter-out -DMACHINE_%,$(CC_FLAGS)) -.PHONY: +.PHONY: machine_check machine_check: @mkdir -p $(BUILDDIR)/tmp @set -eo pipefail; \ for MACHINE in $(MACHINE_DEFS); \ do \ echo "Checking $${MACHINE}"; \ - $(CC) $(MACHINE_LESS_CC_FLAGS) -DMACHINE_$${MACHINE} -DMACHINE_NAME=$${MACHINE} -MMD -o $(BUILDDIR)/tmp/machine_check -c machine/$${MACHINE}.c; \ - $(CC) $(MACHINE_LESS_CC_FLAGS) -DMACHINE_$${MACHINE} -DMACHINE_NAME=$${MACHINE} -MMD -o $(BUILDDIR)/tmp/machine_check -c machine_init.c; \ + $(CC) $(MACHINE_LESS_CC_FLAGS) -DMACHINE_NAME=$${MACHINE} -MMD -o $(BUILDDIR)/tmp/machine_check -c machine/$${MACHINE}.c; \ + INIT=machine/$${MACHINE}_init.c; \ + if [ ! -e $$INIT ] && [ ! -L $$INIT ]; then INIT=$(MACHINE_INIT_DEFAULT); fi; \ + $(CC) $(MACHINE_LESS_CC_FLAGS) -DMACHINE_NAME=$${MACHINE} -MMD -o $(BUILDDIR)/tmp/machine_check -c $$INIT; \ done @rm -rf $(BUILDDIR)/tmp diff --git a/doc/adding-a-device.md b/doc/adding-a-device.md index 312f318f..0f950b81 100644 --- a/doc/adding-a-device.md +++ b/doc/adding-a-device.md @@ -15,6 +15,7 @@ make MACHINE= |------|---------| | `machine/.c` | the `struct machine machine` board definition | | `machine/.h` | `MACHINE_MODEL` (the model string shown in the UI and the CLI) and `MACHINE_CHIPSET` (`RTL8372` or `RTL8373`) | +| `machine/_init.c` | optional `machine_custom_init()` boot hook, for registers the machine definition cannot express | | `doc/devices/.md` + `doc/supported_devices.md` | (only if the board is verified and you want to support it publicly) user-facing documentation | `` is the machine symbol without its `MACHINE_` prefix, so `MACHINE` is @@ -147,6 +148,20 @@ and the six `KP_9000_*` revision variants. Two files that differ only in whitespace or comments are duplicates and should be collapsed this way. +### Optional custom init hook + +If the board needs custom initialization, add +`machine/_init.c` defining `machine_custom_init()`. The Makefile picks the +file up by name and compiles it. + +Boards that need the same hook share one file: keep the code in a single +`machine/_init.c` whose `machine/.c` is a real file (not a symlink), +and make the other boards' `_init.c` symlinks to it, for example: + +``` +ln -s KP_9000_6XH_X2_init.c machine/MY_BOARD_1_0_init.c +``` + ## Step 3: build and verify ``` @@ -160,7 +175,7 @@ file, before anything is compiled. Then run the checks CI runs: ``` -make machine_check # compiles machine/.c and machine_init.c for every machine +make machine_check # compiles machine/.c and its optional _init.c for every machine make -C test # host-side unit tests ``` diff --git a/machine/2G5F4_10G2_V1_01.c b/machine/2G5F4_10G2_V1_01.c index e4a78ad1..caca361d 100644 --- a/machine/2G5F4_10G2_V1_01.c +++ b/machine/2G5F4_10G2_V1_01.c @@ -41,8 +41,8 @@ __code const struct machine machine = { * at 2.5G only) and LED-ID2 carries the SFP single LED. The "solid" * conditions (LINK/speed) barely drive the LEDs here and ACT is what * actually lights them, which is why the white LED used to glow faintly at - * non-2.5G speeds; the fix for that is LED_GLB_IO_EN bit 6, set in - * machine_init.c. */ + * non-2.5G speeds; the fix for that is LED_GLB_IO_EN bit 6, set in the + * shared machine_custom_init() hook (machine/2G5F4_10G2_V1_01_init.c). */ .led_sets = { { LEDS_2G5 | LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT | LEDS_10G, LEDS_2G5 | LEDS_LINK | LEDS_10G, LEDS_1G | LEDS_LINK, diff --git a/machine/2G5F4_10G2_V1_01_init.c b/machine/2G5F4_10G2_V1_01_init.c new file mode 120000 index 00000000..37370e2a --- /dev/null +++ b/machine/2G5F4_10G2_V1_01_init.c @@ -0,0 +1 @@ +KP_9000_6XH_X2_init.c \ No newline at end of file diff --git a/machine/FG_4GT_2SX_V2_0_init.c b/machine/FG_4GT_2SX_V2_0_init.c new file mode 100644 index 00000000..c9b9ddab --- /dev/null +++ b/machine/FG_4GT_2SX_V2_0_init.c @@ -0,0 +1,6 @@ +#include "machine_init_defs.h" + +void machine_custom_init(void) __banked +{ + REG_SET(RTL837X_REG_LED_GLB_IO_EN, 0x7624155b); +} diff --git a/machine/FNS1200P_init.c b/machine/FNS1200P_init.c new file mode 120000 index 00000000..37370e2a --- /dev/null +++ b/machine/FNS1200P_init.c @@ -0,0 +1 @@ +KP_9000_6XH_X2_init.c \ No newline at end of file diff --git a/machine/HI_K0402WS_init.c b/machine/HI_K0402WS_init.c new file mode 120000 index 00000000..37370e2a --- /dev/null +++ b/machine/HI_K0402WS_init.c @@ -0,0 +1 @@ +KP_9000_6XH_X2_init.c \ No newline at end of file diff --git a/machine/KP_9000_6XHML_X2_V2_1_init.c b/machine/KP_9000_6XHML_X2_V2_1_init.c new file mode 120000 index 00000000..37370e2a --- /dev/null +++ b/machine/KP_9000_6XHML_X2_V2_1_init.c @@ -0,0 +1 @@ +KP_9000_6XH_X2_init.c \ No newline at end of file diff --git a/machine/KP_9000_6XH_X2_V2_1_init.c b/machine/KP_9000_6XH_X2_V2_1_init.c new file mode 120000 index 00000000..37370e2a --- /dev/null +++ b/machine/KP_9000_6XH_X2_V2_1_init.c @@ -0,0 +1 @@ +KP_9000_6XH_X2_init.c \ No newline at end of file diff --git a/machine/KP_9000_6XH_X2_init.c b/machine/KP_9000_6XH_X2_init.c new file mode 100644 index 00000000..394f71ef --- /dev/null +++ b/machine/KP_9000_6XH_X2_init.c @@ -0,0 +1,6 @@ +#include "machine_init_defs.h" + +void machine_custom_init(void) __banked +{ + reg_bit_set(RTL837X_REG_LED_GLB_IO_EN, 6); +} diff --git a/machine/PCB_K0402WS_V2_init.c b/machine/PCB_K0402WS_V2_init.c new file mode 120000 index 00000000..37370e2a --- /dev/null +++ b/machine/PCB_K0402WS_V2_init.c @@ -0,0 +1 @@ +KP_9000_6XH_X2_init.c \ No newline at end of file diff --git a/machine/PCB_K0402WS_V3_init.c b/machine/PCB_K0402WS_V3_init.c new file mode 120000 index 00000000..37370e2a --- /dev/null +++ b/machine/PCB_K0402WS_V3_init.c @@ -0,0 +1 @@ +KP_9000_6XH_X2_init.c \ No newline at end of file diff --git a/machine/PCB_SWTG018AS_V2_1_0_init.c b/machine/PCB_SWTG018AS_V2_1_0_init.c new file mode 100644 index 00000000..bce0b814 --- /dev/null +++ b/machine/PCB_SWTG018AS_V2_1_0_init.c @@ -0,0 +1,18 @@ +#include "machine_init_defs.h" + +static __code const struct { uint16_t reg; uint32_t val; } custom_init_regs[] = { + { RTL837X_REG_LED3_0_SET1, 0x00100000UL }, + { RTL837X_REG_LED1_0_SET1, 0x01400155UL }, + { RTL837X_REG_LED1_0_SET0, 0x01740141UL }, + { RTL837X_REG_LED_GLB_IO_EN, 0x7f24977fUL }, + { RTL837X_PIN_MUX_0, 0x20db6880UL }, +}; + +void machine_custom_init(void) __banked +{ + uint8_t i; + // REG_SET is a multi-statement macro without a do-while wrapper: braces required + for (i = 0; i < sizeof(custom_init_regs) / sizeof(custom_init_regs[0]); i++) { + REG_SET(custom_init_regs[i].reg, custom_init_regs[i].val); + } +} diff --git a/machine/PCB_SWTG024AS_A_2_0_1_init.c b/machine/PCB_SWTG024AS_A_2_0_1_init.c new file mode 100644 index 00000000..311bda3e --- /dev/null +++ b/machine/PCB_SWTG024AS_A_2_0_1_init.c @@ -0,0 +1,9 @@ +#include "machine_init_defs.h" + +void machine_custom_init(void) __banked +{ + reg_bit_set(RTL837X_REG_LED_GLB_IO_EN, 6); + reg_bit_set(RTL837X_REG_LED_MODE, 17); + reg_bit_clear(RTL837X_REG_LED_MODE, 9); + reg_bit_clear(RTL837X_REG_LED_MODE, 7); +} diff --git a/machine/SWTG024AS_A_2_0_1_5C_1SFP_init.c b/machine/SWTG024AS_A_2_0_1_5C_1SFP_init.c new file mode 120000 index 00000000..6297e789 --- /dev/null +++ b/machine/SWTG024AS_A_2_0_1_5C_1SFP_init.c @@ -0,0 +1 @@ +SWTG024AS_V2_0_init.c \ No newline at end of file diff --git a/machine/SWTG024AS_V2_0_init.c b/machine/SWTG024AS_V2_0_init.c new file mode 100644 index 00000000..98d2f0c6 --- /dev/null +++ b/machine/SWTG024AS_V2_0_init.c @@ -0,0 +1,20 @@ +#include "machine_init_defs.h" + +void machine_custom_init(void) __banked +{ + uint16_t pval; + + reg_bit_set(RTL837X_REG_LED_GLB_IO_EN, 6); + reg_bit_set(RTL837X_REG_LED_MODE, 17); + reg_bit_clear(RTL837X_REG_LED_MODE, 9); + reg_bit_clear(RTL837X_REG_LED_MODE, 7); + + // OEM firmware sets these companion SDS0 polarity bits for the RTL8221B. + sds_read(0, 0, 0); + pval = SFR_DATA_U16; + sds_write_v(0, 0, 0, pval | 0x100); + + sds_read(0, 6, 2); + pval = SFR_DATA_U16; + sds_write_v(0, 6, 2, pval | 0x4000); +} diff --git a/machine/ZX310S_4T2XT_init.c b/machine/ZX310S_4T2XT_init.c new file mode 100644 index 00000000..38a96e25 --- /dev/null +++ b/machine/ZX310S_4T2XT_init.c @@ -0,0 +1,8 @@ +#include "machine_init_defs.h" + +void machine_custom_init(void) __banked +{ + // For this device, the reset value of RTL837X_PIN_MUX_0 is 0x30000000, + // which would disables all LEDS, enable them manually: + REG_SET(RTL837X_PIN_MUX_0, 0x30db68bf); +} diff --git a/machine/default_machine_init.c b/machine/default_machine_init.c new file mode 100644 index 00000000..1ee200f5 --- /dev/null +++ b/machine/default_machine_init.c @@ -0,0 +1,6 @@ +/* + * Fallback boot hook for boards without a machine/_init.c. + */ +#include "machine_init_defs.h" + +void machine_custom_init(void) __banked { } diff --git a/machine/machine_init_defs.h b/machine/machine_init_defs.h new file mode 100644 index 00000000..b3507d25 --- /dev/null +++ b/machine/machine_init_defs.h @@ -0,0 +1,10 @@ +#ifndef _MACHINE_INIT_DEFS_H_ +#define _MACHINE_INIT_DEFS_H_ + + +#include "machine_defs.h" + +#pragma codeseg BANK2 +#pragma constseg BANK2 + +#endif diff --git a/machine_init.c b/machine_init.c deleted file mode 100644 index efb16e61..00000000 --- a/machine_init.c +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Per-machine one-shot boot hooks, hosted in BANK2 so board-specific - * tables and code do not consume the common bank. - */ -#include -#include "machine.h" -#include "rtl837x_pins.h" -#include "rtl837x_leds.h" -#include "rtl837x_sfr.h" -#include "rtl837x_regs.h" -#include "rtl837x_common.h" - -#pragma codeseg BANK2 -#pragma constseg BANK2 - -#if defined(MACHINE_KP_9000_6XH_X2) || \ - defined(MACHINE_KP_9000_6XH_X2_V2_1) || \ - defined(MACHINE_KP_9000_6XHML_X2_V2_1) || \ - defined(MACHINE_HI_K0402WS) || \ - defined(MACHINE_PCB_K0402WS_V2) || \ - defined(MACHINE_PCB_K0402WS_V3) || \ - defined(MACHINE_2G5F4_10G2_V1_01) || \ - defined(MACHINE_FNS1200P) -void machine_custom_init(void) __banked -{ - reg_bit_set(RTL837X_REG_LED_GLB_IO_EN, 6); -} - -#elif defined MACHINE_PCB_SWTG018AS_V2_1_0 -// Stock-firmware values for what the LED-set encoding cannot express: the -// bi-color SFP LED (blue pin at 10G) and the PIN_MUX_0 routing of that pin -// to the LED controller. Runs after leds_setup(), which covers the rest. -static __code const struct { uint16_t reg; uint32_t val; } custom_init_regs[] = { - { RTL837X_REG_LED3_0_SET1, 0x00100000UL }, - { RTL837X_REG_LED1_0_SET1, 0x01400155UL }, - { RTL837X_REG_LED1_0_SET0, 0x01740141UL }, - { RTL837X_REG_LED_GLB_IO_EN, 0x7f24977fUL }, - { RTL837X_PIN_MUX_0, 0x20db6880UL }, -}; - -void machine_custom_init(void) __banked -{ - uint8_t i; - // REG_SET is a multi-statement macro without a do-while wrapper: braces required - for (i = 0; i < sizeof(custom_init_regs) / sizeof(custom_init_regs[0]); i++) { - REG_SET(custom_init_regs[i].reg, custom_init_regs[i].val); - } -} - -#elif defined MACHINE_PCB_SWTG024AS_A_2_0_1 -void machine_custom_init(void) __banked -{ - reg_bit_set(RTL837X_REG_LED_GLB_IO_EN, 6); - reg_bit_set(RTL837X_REG_LED_MODE, 17); - reg_bit_clear(RTL837X_REG_LED_MODE, 9); - reg_bit_clear(RTL837X_REG_LED_MODE, 7); -} - -#elif defined(MACHINE_SWTG024AS_A_2_0_1_5C_1SFP) || \ - defined(MACHINE_SWTG024AS_V2_0) -void machine_custom_init(void) __banked -{ - uint16_t pval; - - reg_bit_set(RTL837X_REG_LED_GLB_IO_EN, 6); - reg_bit_set(RTL837X_REG_LED_MODE, 17); - reg_bit_clear(RTL837X_REG_LED_MODE, 9); - reg_bit_clear(RTL837X_REG_LED_MODE, 7); - - // OEM firmware sets these companion SDS0 polarity bits for the RTL8221B. - sds_read(0, 0, 0); - pval = SFR_DATA_U16; - sds_write_v(0, 0, 0, pval | 0x100); - - sds_read(0, 6, 2); - pval = SFR_DATA_U16; - sds_write_v(0, 6, 2, pval | 0x4000); -} - -#elif defined MACHINE_ZX310S_4T2XT -void machine_custom_init(void) __banked -{ - // For this device, the reset value of RTL837X_PIN_MUX_0 is 0x30000000, - // which would disables all LEDS, enable them manually: - REG_SET(RTL837X_PIN_MUX_0, 0x30db68bf); -} - -#elif defined MACHINE_FG_4GT_2SX_V2_0 -void machine_custom_init(void) __banked -{ - REG_SET(RTL837X_REG_LED_GLB_IO_EN, 0x7624155b); -} - -#else -void machine_custom_init(void) __banked { } -#endif From 7346977f914eddf4562b3be59192b2f36eb9d9a7 Mon Sep 17 00:00:00 2001 From: HL Yi Date: Tue, 20 Oct 2026 17:09:10 -0500 Subject: [PATCH 17/34] use macro for min_port and max_port for code optimization --- cmd_parser.c | 8 ++++---- httpd/page_impl.c | 36 ++++++++++++++++++------------------ machine.h | 3 +++ rtl837x_igmp.c | 6 +++--- rtl837x_init.c | 2 +- rtl837x_lacp.c | 14 +++++++------- rtl837x_leds.c | 6 +++--- rtl837x_leds_dump.c | 2 +- rtl837x_lldp.c | 2 +- rtl837x_port.c | 22 +++++++++++----------- rtl837x_storm.c | 2 +- rtl837x_stp.c | 22 +++++++++++----------- 12 files changed, 64 insertions(+), 61 deletions(-) diff --git a/cmd_parser.c b/cmd_parser.c index afc7831a..6355837a 100644 --- a/cmd_parser.c +++ b/cmd_parser.c @@ -266,7 +266,7 @@ uint8_t cmd_parse_port(uint8_t idx) { return 0; port = machine.phys_to_log_port[port]; - if (port < machine.min_port || port > machine.max_port) + if (!MACHINE_PORT_VALID(port)) return 0; atoi_results_u8 = port; @@ -743,7 +743,7 @@ void parse_isolate(void) } if (cmd_compare(2, "off")) { - for (uint8_t i = machine.min_port; i <= machine.max_port; i++) + for (uint8_t i = MACHINE_MIN_PORT; i <= MACHINE_MAX_PORT; i++) members |= ((uint16_t)1) << i; members |= PMASK_CPU; // CPU-port port_isolate(port_configured, members); @@ -797,7 +797,7 @@ void parse_ingress(void) if (!cmd_is_space_or_nul(idx)) goto err; // Setting mode for all ports at once - for (log_port = machine.min_port; log_port <= machine.max_port; log_port++) { + for (log_port = MACHINE_MIN_PORT; log_port <= MACHINE_MAX_PORT; log_port++) { if (!port_ingress_filter(log_port, mode)) { cmd_error("cannot set the ingress filter for port "); print_phys_port(log_port); write_char('\n'); return; @@ -1019,7 +1019,7 @@ void parse_mtu(void) uint8_t p; if (cmd_compare(1, "show")) { - for (p = machine.min_port; p <= machine.max_port; p++) { + for (p = MACHINE_MIN_PORT; p <= MACHINE_MAX_PORT; p++) { reg_read_m(RTL8373_REG_MAC_L2_PORT_MAX_LEN + ((uint16_t) p << 8)); uint16_t mtu = SFR_DATA_U16 & 0x3fff; print_string("Port "); print_phys_port(p); diff --git a/httpd/page_impl.c b/httpd/page_impl.c index 006d2dbe..7f107b7d 100644 --- a/httpd/page_impl.c +++ b/httpd/page_impl.c @@ -341,7 +341,7 @@ void send_vlan(uint16_t vlan) } slen += strtox(outbuf + slen, "\",\"pvid\":\"0x"); uint16_t pvid_mask = 0; - for (uint8_t i = machine.min_port; i <= machine.max_port; i++) { + for (uint8_t i = MACHINE_MIN_PORT; i <= MACHINE_MAX_PORT; i++) { if (port_pvid_get(i) == vlan) pvid_mask |= (1 << i); } @@ -357,7 +357,7 @@ void send_vlan(uint16_t vlan) bool send_counters(uint8_t phys_port) { uint8_t phys_port_idx = phys_port - 1; - if (phys_port_idx > (machine.max_port - machine.min_port)) + if (phys_port_idx > (MACHINE_MAX_PORT - MACHINE_MIN_PORT)) goto err; uint8_t log_port = machine.phys_to_log_port[phys_port_idx]; @@ -676,7 +676,7 @@ void send_stp(void) slen += strtox(outbuf + slen, "\",\"ports\":["); reg_read_m(RTL837X_MSTP_STATES); for (i = 0; i < STP_ENTITIES; i++) { - if (i < STP_LAG_BASE && (i < machine.min_port || i > machine.max_port)) + if (i < STP_LAG_BASE && !MACHINE_PORT_VALID(i)) continue; if (i < STP_LAG_BASE && stp_ent_of[i] != i) continue; @@ -761,7 +761,7 @@ void send_lacp(void) } slen -= 1; // remove comma slen += strtox(outbuf + slen, "],\"ports\":["); - for (uint8_t i = machine.min_port; i <= machine.max_port; i++) { + for (uint8_t i = MACHINE_MIN_PORT; i <= MACHINE_MAX_PORT; i++) { slen += strtox(outbuf + slen, "{\"p\":"); itoa_html(machine.log_to_phys_port[i]); slen += strtox(outbuf + slen, ",\"lag\":"); @@ -793,7 +793,7 @@ void send_lldp(void) bool_to_html(lldp_enabled); slen += strtox(outbuf + slen, ",\"portStatus\":["); - for (uint8_t i = machine.min_port; i <= machine.max_port; i++) { + for (uint8_t i = MACHINE_MIN_PORT; i <= MACHINE_MAX_PORT; i++) { slen += strtox(outbuf + slen, "{\"portNum\":"); itoa_html(machine.log_to_phys_port[i]); @@ -808,7 +808,7 @@ void send_lldp(void) bool_to_html(1 & (lldp_logical_port_status >> i)); slen += strtox(outbuf + slen, "}"); - if (i < machine.max_port) + if (i < MACHINE_MAX_PORT) char_to_html(','); else char_to_html(']'); @@ -825,7 +825,7 @@ void send_eee(void) uint8_t eee_ablty = sfr_data[3]; char_to_html('['); - for (uint8_t i = machine.min_port; i <= machine.max_port; i++) { + for (uint8_t i = MACHINE_MIN_PORT; i <= MACHINE_MAX_PORT; i++) { slen += strtox(outbuf + slen, "{\"portNum\":"); itoa_html(machine.log_to_phys_port[i]); @@ -857,7 +857,7 @@ void send_eee(void) bool_to_html(eee_ablty & (1 << i)); } char_to_html('}'); - if (i < machine.max_port) + if (i < MACHINE_MAX_PORT) char_to_html(','); else char_to_html(']'); @@ -870,7 +870,7 @@ void send_bandwidth(void) dbg_string("send_bandwidth called\n"); slen = strtox(outbuf, HTTP_RESPONCE_JSON); char_to_html('['); - for (uint8_t i = machine.min_port; i <= machine.max_port; i++) { + for (uint8_t i = MACHINE_MIN_PORT; i <= MACHINE_MAX_PORT; i++) { slen += strtox(outbuf + slen, "{\"portNum\":"); itoa_html(machine.log_to_phys_port[i]); slen += strtox(outbuf + slen, ",\"iLimited\":"); @@ -900,7 +900,7 @@ void send_bandwidth(void) byte_to_html(sfr_data[3]); char_to_html('"'); char_to_html('}'); - if (i < machine.max_port) + if (i < MACHINE_MAX_PORT) char_to_html(','); else char_to_html(']'); @@ -914,7 +914,7 @@ void send_storm(void) slen = strtox(outbuf, HTTP_RESPONCE_JSON); char_to_html('['); - for (i = machine.min_port; i <= machine.max_port; i++) { + for (i = MACHINE_MIN_PORT; i <= MACHINE_MAX_PORT; i++) { slen += strtox(outbuf + slen, "{\"portNum\":"); itoa_html(machine.log_to_phys_port[i]); slen += strtox(outbuf + slen, ",\"en\":\""); @@ -934,7 +934,7 @@ void send_storm(void) } char_to_html('"'); char_to_html('}'); - if (i < machine.max_port) + if (i < MACHINE_MAX_PORT) char_to_html(','); else char_to_html(']'); @@ -949,7 +949,7 @@ void send_isolation(void) dbg_string("send_isolation called\n"); slen = strtox(outbuf, HTTP_RESPONCE_JSON); char_to_html('['); - for (uint8_t i = machine.min_port; i <= machine.max_port; i++) { + for (uint8_t i = MACHINE_MIN_PORT; i <= MACHINE_MAX_PORT; i++) { slen += strtox(outbuf + slen, "{\"portNum\":"); itoa_html(machine.log_to_phys_port[i]); slen += strtox(outbuf + slen, ",\"allow\":\""); @@ -958,7 +958,7 @@ void send_isolation(void) byte_to_html(allow & 0xff); char_to_html('"'); char_to_html('}'); - if (i < machine.max_port) + if (i < MACHINE_MAX_PORT) char_to_html(','); } char_to_html(']'); @@ -970,7 +970,7 @@ void send_mtu(void) dbg_string("send_mtu called\n"); slen = strtox(outbuf, HTTP_RESPONCE_JSON); char_to_html('['); - for (uint8_t i = machine.min_port; i <= machine.max_port; i++) { + for (uint8_t i = MACHINE_MIN_PORT; i <= MACHINE_MAX_PORT; i++) { slen += strtox(outbuf + slen, "{\"portNum\":"); itoa_html(machine.log_to_phys_port[i]); slen += strtox(outbuf + slen, ",\"mtu\":\"0x"); @@ -980,7 +980,7 @@ void send_mtu(void) byte_to_html(mtu & 0xff); char_to_html('"'); char_to_html('}'); - if (i < machine.max_port) + if (i < MACHINE_MAX_PORT) char_to_html(','); else char_to_html(']'); @@ -994,7 +994,7 @@ void send_status(void) dbg_string("sending status\n"); char_to_html('['); - for (uint8_t i = machine.min_port; i <= machine.max_port; i++) { + for (uint8_t i = MACHINE_MIN_PORT; i <= MACHINE_MAX_PORT; i++) { slen += strtox(outbuf + slen, "{\"portNum\":"); itoa_html(machine.log_to_phys_port[i]); slen += strtox(outbuf + slen, ",\"logPort\":"); @@ -1115,7 +1115,7 @@ void send_status(void) slen += strtox(outbuf + slen, "\",\"macs\":\"0x"); reg_to_html(RTL837X_L2_LRN_PORT_CONSTRT_CNT + (i << 2)); slen += strtox(outbuf + slen, "\"}"); - if (i < machine.max_port) + if (i < MACHINE_MAX_PORT) char_to_html(','); else char_to_html(']'); diff --git a/machine.h b/machine.h index 70d75e8b..b7b3f63f 100644 --- a/machine.h +++ b/machine.h @@ -42,6 +42,9 @@ #endif #endif +#define MACHINE_PORT_VALID(p) \ + ((uint8_t)((p) - MACHINE_MIN_PORT) <= (MACHINE_MAX_PORT - MACHINE_MIN_PORT)) + // auto derive SOC_FAMILY #define RTL836X 6 #define RTL837X 7 diff --git a/rtl837x_igmp.c b/rtl837x_igmp.c index 35940446..f996cd3f 100644 --- a/rtl837x_igmp.c +++ b/rtl837x_igmp.c @@ -126,7 +126,7 @@ void igmp_setup(void) __banked * For now the IGMP protocols are flooded (01), MLD which MAC-based is handled by ASIC * All messages are allowed and maximum MC group is 0xff */ - for (i = machine.min_port; i <= machine.max_port; i++) + for (i = MACHINE_MIN_PORT; i <= MACHINE_MAX_PORT; i++) REG_SET(RTL837X_IGMP_PORT_CFG + (i << 2), IGMP_MAX_GROUP | IGMP_PROTOCOL_ENABLE | IGMP_FLOOD); /* // Allow all physical ports to be dynamic router ports @@ -155,7 +155,7 @@ void igmp_enable(void) __banked // Configure per-port IGMP configuration, bits 0-10 enable MC protocol snooping, // bits 16-24 configure max MC group used by that port. Trap to CPU (10) - for (uint8_t i = machine.min_port; i <= machine.max_port; i++) { + for (uint8_t i = MACHINE_MIN_PORT; i <= MACHINE_MAX_PORT; i++) { REG_SET(RTL837X_IGMP_PORT_CFG + (i << 2), IGMP_MAX_GROUP | IGMP_PROTOCOL_ENABLE | IGMP_TRAP); } } @@ -180,7 +180,7 @@ void igmp_router_port_set(uint16_t pmask) __banked void igmp_show(void) __banked { print_string("igmp_show called\n"); - for (uint8_t i = machine.min_port; i <= machine.max_port; i++) { + for (uint8_t i = MACHINE_MIN_PORT; i <= MACHINE_MAX_PORT; i++) { write_char('0' + i); write_char(':'); reg_read_m(RTL837X_IGMP_PORT_CFG + (i << 2)); print_sfr_data(); diff --git a/rtl837x_init.c b/rtl837x_init.c index c7b7e71e..73498642 100644 --- a/rtl837x_init.c +++ b/rtl837x_init.c @@ -246,7 +246,7 @@ void rtl8372_init(void) __banked // [...] /// uint16_t reg = 0x1238 + 0x300; // Port base register for the bits we set - for (char i = machine.min_port; i <= machine.max_port; i++) { + for (char i = MACHINE_MIN_PORT; i <= MACHINE_MAX_PORT; i++) { // Bit 7 (0x40) enables replacement of the RTL-VLAN tag with an 802.1Q VLAN tag REG_SET(reg, 0xe77); reg += 0x100; diff --git a/rtl837x_lacp.c b/rtl837x_lacp.c index 2573bc34..c8d6b1d6 100644 --- a/rtl837x_lacp.c +++ b/rtl837x_lacp.c @@ -165,7 +165,7 @@ void lacp_mux_update(void) __banked if (!lacp_lag_ports[lag]) continue; lacp_scratch_mask = 0; - for (uint8_t i = machine.min_port; i <= machine.max_port; i++) { + for (uint8_t i = MACHINE_MIN_PORT; i <= MACHINE_MAX_PORT; i++) { if (lacp_port_lag[i] != lag) continue; if ((lacp_actor_state[i] & LACP_STATE_FULL) == LACP_STATE_FULL @@ -248,7 +248,7 @@ void lacp_in(void) __banked return; port = ((uint8_t)HTONS(LACP_H->rtl_tag.pmask)) & 0x0f; - if (port < machine.min_port || port > machine.max_port) + if (!MACHINE_PORT_VALID(port)) return; lag = lacp_port_lag[port]; @@ -298,7 +298,7 @@ void lacp_in(void) __banked static void lacp_step(void) { - for (uint8_t i = machine.min_port; i <= machine.max_port; i++) { + for (uint8_t i = MACHINE_MIN_PORT; i <= MACHINE_MAX_PORT; i++) { if (lacp_port_lag[i] == LACP_LAG_NONE) continue; @@ -328,7 +328,7 @@ static void lacp_step(void) if (!lacp_agg_valid[lag]) continue; - for (uint8_t i = machine.min_port; i <= machine.max_port; i++) { + for (uint8_t i = MACHINE_MIN_PORT; i <= MACHINE_MAX_PORT; i++) { if (lacp_port_lag[i] == lag && lacp_rx_state[i] == LACP_RX_CURRENT && lacp_sys_eq(lacp_partner_sys[i], lacp_agg_sys[lag])) { any_current = 1; @@ -422,7 +422,7 @@ void lacp_lag_set(uint8_t lag, __xdata uint16_t ports) __banked return; lacp_scratch_flag = lacp_any_lag(); - for (uint8_t i = machine.min_port; i <= machine.max_port; i++) { + for (uint8_t i = MACHINE_MIN_PORT; i <= MACHINE_MAX_PORT; i++) { if (lacp_port_lag[i] == lag && !(ports & PORT_BIT(i))) { lacp_port_lag[i] = LACP_LAG_NONE; lacp_port_release(i); @@ -438,7 +438,7 @@ void lacp_lag_set(uint8_t lag, __xdata uint16_t ports) __banked if (ports && !lacp_scratch_flag) lacp_engine_on(); - for (uint8_t i = machine.min_port; i <= machine.max_port; i++) { + for (uint8_t i = MACHINE_MIN_PORT; i <= MACHINE_MAX_PORT; i++) { if (!(ports & PORT_BIT(i))) continue; lacp_scratch_lag = lacp_port_lag[i]; @@ -490,7 +490,7 @@ void lacp_show(void) __banked print_string(" members "); print_short(lacp_members_last[l]); write_char('\n'); } - for (uint8_t i = machine.min_port; i <= machine.max_port; i++) { + for (uint8_t i = MACHINE_MIN_PORT; i <= MACHINE_MAX_PORT; i++) { print_string("port "); print_byte(machine.log_to_phys_port[i]); print_string(" actor "); print_byte(lacp_actor_state[i]); print_string(" partner "); print_byte(lacp_partner_state[i]); diff --git a/rtl837x_leds.c b/rtl837x_leds.c index d1b8cf91..5757060c 100644 --- a/rtl837x_leds.c +++ b/rtl837x_leds.c @@ -37,10 +37,10 @@ void leds_setup(void) __banked // Set up all Port-LEDs to belong to RLDP sfr_data[3] = sfr_data[2] = sfr_data[1] = sfr_data[0] = 0; - for (uint8_t i = machine.min_port; i <= (machine.max_port > 7 ? 7 : machine.max_port); i++) + for (uint8_t i = MACHINE_MIN_PORT; i <= (MACHINE_MAX_PORT > 7 ? 7 : MACHINE_MAX_PORT); i++) sfr_data[3 - (i >> 2)] |= i & 1 ? 0xf0 : 0x0f; reg_write_m(RTL837X_REG_LED_RLDP_2); - if (machine.max_port == 8) + if (MACHINE_MAX_PORT == 8) REG_SET(RTL837X_REG_LED_RLDP_3, 0x0000000f); // Port 8 // Configure high LEDs 27-29: mux and LED enable @@ -110,7 +110,7 @@ void leds_setup(void) __banked // Configure the LED-set of a port sfr_data[3] = sfr_data[2] = sfr_data[1] = sfr_data[0] = 0; - for (uint8_t i = machine.min_port; i <= machine.max_port; i++) + for (uint8_t i = MACHINE_MIN_PORT; i <= MACHINE_MAX_PORT; i++) sfr_data[3 - (i >> 2)] |= machine.port_led_set[i] << ((i & 3) << 1); reg_write_m(RTL837X_LED_PORT_SET_SEL); diff --git a/rtl837x_leds_dump.c b/rtl837x_leds_dump.c index 8a820e3a..5bf04d0f 100644 --- a/rtl837x_leds_dump.c +++ b/rtl837x_leds_dump.c @@ -87,7 +87,7 @@ void leds_dump(void) __banked } write_char('\n'); } - for (uint8_t i = machine.min_port; i <= machine.max_port; i++) { + for (uint8_t i = MACHINE_MIN_PORT; i <= MACHINE_MAX_PORT; i++) { reg_read_m(RTL837X_LED_PORT_SET_SEL); __xdata uint8_t set = sfr_data[3 - (i >> 2)]; set = (set >> ((i & 3) << 1)); diff --git a/rtl837x_lldp.c b/rtl837x_lldp.c index 84208433..441e7eb4 100644 --- a/rtl837x_lldp.c +++ b/rtl837x_lldp.c @@ -108,7 +108,7 @@ void lldp_send(void) __banked __reentrant */ uip_len = MAC_ADDR_LEN + MAC_ADDR_LEN + sizeof(struct rtl_tag) + LLDP_ETHERTYPE_LENGTH + (p - LLDP_O->payload); - for (uint8_t port = machine.min_port; port <= machine.max_port; port++) { + for (uint8_t port = MACHINE_MIN_PORT; port <= MACHINE_MAX_PORT; port++) { if ((1 << port) & lldp_logical_port_status) { LLDP_O->payload[port_position] = '0' + machine.log_to_phys_port[port]; diff --git a/rtl837x_port.c b/rtl837x_port.c index d4a5b9f5..6874685f 100644 --- a/rtl837x_port.c +++ b/rtl837x_port.c @@ -271,7 +271,7 @@ void vlan_setup(void) __banked wait_table_ready(); // Set PVID 1 for every port. TODO: Skip unused ports! - for (uint8_t i = machine.min_port; i <= machine.max_port + 1; i++) { // Do this also for the CPU port (+1) + for (uint8_t i = MACHINE_MIN_PORT; i <= MACHINE_MAX_PORT + 1; i++) { // Do this also for the CPU port (+1) uint16_t reg = RTL837x_PVID_BASE_REG + ((i >> 1) << 2); #ifdef DEBUG print_byte(i); write_char(':'); write_char(' '); print_short(reg); write_char('='); @@ -459,7 +459,7 @@ void port_l2_setup(void) __banked port_l2_forget(); - for (uint8_t i = machine.min_port; i <= machine.max_port; i++) { + for (uint8_t i = MACHINE_MIN_PORT; i <= MACHINE_MAX_PORT; i++) { // Limit the number of automatically learned MAC-Entries per port to 0x1040 uint8_t idx = (i << 2); REG_SET(RTL837X_L2_LRN_PORT_CONSTRAINT + idx, 0x00001040); @@ -511,7 +511,7 @@ void port_media_show(uint8_t port) __banked void port_stats_print(void) __banked { print_string("\nPort\tState\tLink\tTxGood\t\tTxBad\t\tRxGood\t\tRxBad\t\tMACs\n"); - for (uint8_t i = machine.min_port; i <= machine.max_port; i++) { + for (uint8_t i = MACHINE_MIN_PORT; i <= MACHINE_MAX_PORT; i++) { print_phys_port(i); write_char('\t'); if (!machine.is_sfp[i]) { @@ -594,14 +594,14 @@ void port_stats_print(void) __banked void port_isolate(uint8_t port, __xdata uint16_t pmask) __banked { - if (port <= machine.max_port) + if (port <= MACHINE_MAX_PORT) REG_SET(RTL837X_PORT_ISOLATION_BASE + (port << 2), pmask); } uint16_t port_isolation_get(uint8_t port) __banked { - if (port > machine.max_port) + if (port > MACHINE_MAX_PORT) return 0; reg_read_m(RTL837X_PORT_ISOLATION_BASE + (port << 2)); @@ -775,7 +775,7 @@ void port_eee_status(uint8_t port) __banked void port_eee_enable_all(__xdata uint8_t speed) __banked { - for (uint8_t i = machine.min_port; i <= machine.max_port; i++) { + for (uint8_t i = MACHINE_MIN_PORT; i <= MACHINE_MAX_PORT; i++) { if (i == 3 && machine.n_10g) { port_eee_enable(i, speed); } else if (i == 8 && machine.n_10g == 2) { @@ -792,7 +792,7 @@ void port_eee_enable_all(__xdata uint8_t speed) __banked void port_eee_disable_all(void) __banked { - for (uint8_t i = machine.min_port; i <= machine.max_port; i++) { + for (uint8_t i = MACHINE_MIN_PORT; i <= MACHINE_MAX_PORT; i++) { port_eee_disable(i); } } @@ -800,7 +800,7 @@ void port_eee_disable_all(void) __banked void port_eee_status_all(void) __banked { - for (uint8_t i = machine.min_port; i <= machine.max_port; i++) { + for (uint8_t i = MACHINE_MIN_PORT; i <= MACHINE_MAX_PORT; i++) { port_eee_status(i); } } @@ -908,7 +908,7 @@ void vlan_dump(void) __banked { print_string("Ingress VLAN configuration:\n"); print_string("Port\tPVID\tType\tFiltering\n"); - for (uint8_t port = machine.min_port; port <= machine.max_port; port++) { + for (uint8_t port = MACHINE_MIN_PORT; port <= MACHINE_MAX_PORT; port++) { print_vlan_ingress_port(port); } print_vlan_ingress_port(9); @@ -923,7 +923,7 @@ void vlan_dump(void) __banked /** Set the ingress VLAN filtering */ bool port_ingress_vlan_filter_set(uint8_t port, __xdata bool enabled) __banked { - if (port < machine.min_port || (port > machine.max_port && port != CPU_PORT)) { + if (!MACHINE_PORT_VALID(port) && port != CPU_PORT) { return false; } if (enabled) @@ -937,7 +937,7 @@ bool port_ingress_vlan_filter_set(uint8_t port, __xdata bool enabled) __banked /** Get the ingress VLAN filtering status */ bool port_ingress_vlan_filter_get(uint8_t port) __banked { - if (port < machine.min_port || (port > machine.max_port && port != CPU_PORT)) { + if (!MACHINE_PORT_VALID(port) && port != CPU_PORT) { return false; } diff --git a/rtl837x_storm.c b/rtl837x_storm.c index 2308b210..23cfc83a 100644 --- a/rtl837x_storm.c +++ b/rtl837x_storm.c @@ -67,7 +67,7 @@ void storm_show(void) __banked { uint8_t i, t, idx; - for (i = machine.min_port; i <= machine.max_port; i++) { + for (i = MACHINE_MIN_PORT; i <= MACHINE_MAX_PORT; i++) { print_string("port "); write_char('0' + machine.log_to_phys_port[i]); for (t = 0; t < STORM_TYPES; t++) { diff --git a/rtl837x_stp.c b/rtl837x_stp.c index bc810d96..118e265c 100644 --- a/rtl837x_stp.c +++ b/rtl837x_stp.c @@ -335,7 +335,7 @@ static uint8_t stp_ent_active(uint8_t e) __reentrant return 0; if (e >= STP_LAG_BASE) return stp_lag_mask[e - STP_LAG_BASE] != 0; - return e >= machine.min_port && e <= machine.max_port && stp_ent_of[e] == e; + return MACHINE_PORT_VALID(e) && stp_ent_of[e] == e; } @@ -410,7 +410,7 @@ static void stp_topology_change(uint8_t port) __reentrant stp_tc_count++; stp_tc_while = ((uint16_t)stp_maxage_s + stp_fwddelay_s) * STP_HZ; if (port >= STP_LAG_BASE) { - for (uint8_t i = machine.min_port; i <= machine.max_port; i++) + for (uint8_t i = MACHINE_MIN_PORT; i <= MACHINE_MAX_PORT; i++) if (stp_ent_has(port, i)) port_l2_forget_port(i); } else { @@ -565,7 +565,7 @@ void stp_in(void) __banked /* Ingress port: low nibble of the CPU tag's pmask on RX */ stp_scratch = ((uint8_t)HTONS(STP_H->rtl_tag.pmask)) & 0x0f; - if (stp_scratch < machine.min_port || stp_scratch > machine.max_port) + if (!MACHINE_PORT_VALID(stp_scratch)) return; port = stp_ent_of[stp_scratch]; @@ -658,7 +658,7 @@ void stp_in(void) __banked if (!stp_tc_while) { uint8_t i; stp_tc_count++; - for (i = machine.min_port; i <= machine.max_port; i++) + for (i = MACHINE_MIN_PORT; i <= MACHINE_MAX_PORT; i++) if (!stp_ent_has(port, i) && (stp_pflags[stp_ent_of[i]] & STP_PF_ENABLED) && !(stp_pflags[stp_ent_of[i]] & STP_PF_OPEREDGE)) @@ -714,7 +714,7 @@ void stp_timers(void) __banked if (stp_map_dirty) { stp_map_dirty = 0; for (stp_i = 0; stp_i < STP_LAG_BASE; stp_i++) { - if (stp_i < machine.min_port || stp_i > machine.max_port) + if (!MACHINE_PORT_VALID(stp_i)) continue; if (stp_ent_of[stp_i] != stp_i) { stp_loop_held[stp_i] = 0; @@ -747,14 +747,14 @@ void stp_timers(void) __banked { __xdata static uint16_t eff; eff = 0; - for (stp_i = machine.min_port; stp_i <= machine.max_port; stp_i++) + for (stp_i = MACHINE_MIN_PORT; stp_i <= MACHINE_MAX_PORT; stp_i++) if ((stp_link_now >> stp_i) & 1) eff |= (uint16_t)1 << stp_ent_of[stp_i]; stp_link_now = eff; } if (stp_link_now != stp_link_prev) { for (stp_i = 0; stp_i < STP_ENTITIES; stp_i++) { - if (stp_i < STP_PORTS && (stp_i < machine.min_port || stp_i > machine.max_port)) + if (stp_i < STP_PORTS && !MACHINE_PORT_VALID(stp_i)) continue; if (stp_i < STP_PORTS && stp_ent_of[stp_i] != stp_i) continue; @@ -890,7 +890,7 @@ static void stp_fdb_update(__xdata uint16_t pmask) continue; port_l2mc_set(0x00, stp_fdb_vid, pmask); } - for (stp_fdb_i = machine.min_port; stp_fdb_i <= machine.max_port; stp_fdb_i++) { + for (stp_fdb_i = MACHINE_MIN_PORT; stp_fdb_i <= MACHINE_MAX_PORT; stp_fdb_i++) { stp_fdb_vid = port_pvid_get(stp_fdb_i); port_l2mc_set(0x00, stp_fdb_vid, pmask); } @@ -910,7 +910,7 @@ void stp_setup(void) __banked stp_tx_count[stp_i] = 0; port_timers[stp_i] = 0; port_hello[stp_i] = (uint16_t)stp_hello_s * STP_HZ; - if (stp_i < STP_PORTS && (stp_i < machine.min_port || stp_i > machine.max_port)) + if (stp_i < STP_PORTS && !MACHINE_PORT_VALID(stp_i)) continue; if (stp_i >= STP_LAG_BASE && !stp_lag_mask[stp_i - STP_LAG_BASE]) continue; @@ -939,7 +939,7 @@ void stp_setup(void) __banked reg_read_m(RTL837X_REG_LINKS_STS); stp_link_now = (uint16_t)sfr_data[1] | ((uint16_t)sfr_data[2] << 8); stp_link_prev = 0; - for (stp_i = machine.min_port; stp_i <= machine.max_port; stp_i++) + for (stp_i = MACHINE_MIN_PORT; stp_i <= MACHINE_MAX_PORT; stp_i++) if ((stp_link_now >> stp_i) & 1) stp_link_prev |= (uint16_t)1 << stp_ent_of[stp_i]; @@ -952,7 +952,7 @@ void stp_setup(void) __banked void stp_off(void) __banked { sfr_data[0] = sfr_data[1] = sfr_data[2] = sfr_data[3] = 0; - for (stp_i = machine.min_port; stp_i <= machine.max_port; stp_i++) { + for (stp_i = MACHINE_MIN_PORT; stp_i <= MACHINE_MAX_PORT; stp_i++) { // Set STP port state to forwarding // States are: 00 disable, 01 blocking, 10 learning, 11 forwarding sfr_data[3 - (stp_i >> 2)] |= (uint8_t)(STP_ST_FORWARDING << ((stp_i << 1) & 0x7)); From aea537f8e77bd979151889c7fe0d3a2992eb3edd Mon Sep 17 00:00:00 2001 From: Rob Emery Date: Sun, 27 Sep 2026 07:52:26 +0100 Subject: [PATCH 18/34] Storing the output of the build in tmp files so we can extract the bits we need But we need both main and branch checked out and the action can do it for us Pulling the bank occupancy from the map produced by sdcc rather than the output of the build as it appears the output number is only the maximum size of the banks BANK0 isn't output, but what I'm guessing are the consituents for it are --- .github/workflows/build.yml | 44 ++++++++++++++++++++++++++++++++----- 1 file changed, 39 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 31a94891..b1bfb084 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -5,6 +5,10 @@ on: branches: ['**'] pull_request: +permissions: + contents: read + pull-requests: write + jobs: build: runs-on: ubuntu-latest @@ -13,18 +17,48 @@ jobs: steps: - uses: actions/checkout@v6 + with: + path: branch + + - uses: actions/checkout@v6 + with: + path: main + ref: main - name: Install dependencies run: | apt update apt install make gcc sdcc xxd python-is-python3 libjson-c-dev zlib1g-dev -y - name: Run the host-side unit tests - run: make -C test + run: cd branch && make -C test - name: Check that every machine definition can be compiled - run: make machine_check + run: cd branch && make machine_check - name: Make project (4x2/RTL8372) - run: make CI=1 MACHINE="KP_9000_6XHML_X2" + run: cd branch && make CI=1 MACHINE="KP_9000_6XHML_X2" && cp output/KP_9000_6XHML_X2/rtlplayground.map /tmp/branch.map - name: Make project (8x1/RTL8373) - run: make CI=1 MACHINE="KP_9000_9XHML_X_V3_1" + run: cd branch && make CI=1 MACHINE="KP_9000_9XHML_X_V3_1" - name: Make project with the health instrumentation - run: make clean && make CI=1 MACHINE="KP_9000_6XHML_X2" HEALTH=1 + run: cd branch && make clean && make CI=1 MACHINE="KP_9000_6XHML_X2" HEALTH=1 + - name: Make main + run: cd main && make CI=1 MACHINE="KP_9000_6XHML_X2" && cp output/KP_9000_6XHML_X2/rtlplayground.map /tmp/main.map + - name: Calculate bank growth + run: | + sed -rn 's/^([XCD]SEG|(BANK[0-9])).*=\s+([0-9]+)\. bytes.*$/MAIN_\1=\3/p' /tmp/main.map | sort | uniq >> "$GITHUB_ENV" + sed -rn 's/^([XCD]SEG|(BANK[0-9])).*=\s+([0-9]+)\. bytes.*$/BRANCH_\1=\3/p' /tmp/branch.map | sort | uniq >> "$GITHUB_ENV" + - name: Update PR comment + uses: marocchino/sticky-pull-request-comment@v2 + with: + header: Sizes + message: | + ## Image Growth + + Commit: ${{ github.sha }} + + | Bank # | Main | Branch | + | --- | --- | --- | + | XSEG | ${{ env.MAIN_XSEG }} bytes | ${{ env.BRANCH_XSEG }} bytes | + | CSEG | ${{ env.MAIN_CSEG }} bytes | ${{ env.BRANCH_CSEG }} bytes | + | DSEG | ${{ env.MAIN_DSEG }} bytes | ${{ env.BRANCH_DSEG }} bytes | + | 1 | ${{ env.MAIN_BANK1 }} bytes | ${{ env.BRANCH_BANK1 }} bytes | + | 2 | ${{ env.MAIN_BANK2 }} bytes | ${{ env.BRANCH_BANK2 }} bytes | + | 3 | ${{ env.MAIN_BANK3 }} bytes | ${{ env.BRANCH_BANK3 }} bytes | From 2bc6939f86ed4006961f5db60b5e2f7e3a3ea422 Mon Sep 17 00:00:00 2001 From: Rob Emery Date: Sun, 4 Oct 2026 09:56:39 +0100 Subject: [PATCH 19/34] Sort -u and use v3 to silence nodejs v20 warnings --- .github/workflows/build.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b1bfb084..c211d357 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -43,10 +43,10 @@ jobs: run: cd main && make CI=1 MACHINE="KP_9000_6XHML_X2" && cp output/KP_9000_6XHML_X2/rtlplayground.map /tmp/main.map - name: Calculate bank growth run: | - sed -rn 's/^([XCD]SEG|(BANK[0-9])).*=\s+([0-9]+)\. bytes.*$/MAIN_\1=\3/p' /tmp/main.map | sort | uniq >> "$GITHUB_ENV" - sed -rn 's/^([XCD]SEG|(BANK[0-9])).*=\s+([0-9]+)\. bytes.*$/BRANCH_\1=\3/p' /tmp/branch.map | sort | uniq >> "$GITHUB_ENV" + sed -rn 's/^([XCD]SEG|(BANK[0-9])).*=\s+([0-9]+)\. bytes.*$/MAIN_\1=\3/p' /tmp/main.map | sort -u >> "$GITHUB_ENV" + sed -rn 's/^([XCD]SEG|(BANK[0-9])).*=\s+([0-9]+)\. bytes.*$/BRANCH_\1=\3/p' /tmp/branch.map | sort -u >> "$GITHUB_ENV" - name: Update PR comment - uses: marocchino/sticky-pull-request-comment@v2 + uses: marocchino/sticky-pull-request-comment@v3 with: header: Sizes message: | From 69714c8a75e172a140062fffacef6b1449fa0487 Mon Sep 17 00:00:00 2001 From: Rob Emery Date: Sat, 10 Oct 2026 21:46:47 +0100 Subject: [PATCH 20/34] Adding the ability to override the BUILDDIR so I can store branch-builds elsewhere --- .gitignore | 1 + Makefile | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 11f5c4ed..5b169b0f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ .gitignore .idea/ output/ +output-main/ html_data.c html_data.h version.h diff --git a/Makefile b/Makefile index c95f12af..5ebd9ddf 100644 --- a/Makefile +++ b/Makefile @@ -34,7 +34,10 @@ endif # The board definition being built: one file per MACHINE_* symbol in machine.h. MACHINE_SRC = machine/$(MACHINE).c -BUILDDIR = output/$(MACHINE) +ifndef BUILDDIR + BUILDDIR = output/$(MACHINE) +endif + VERSION_HEADER := version.h GIT_VERSION := $(shell git rev-parse --short HEAD) From 94ca35f65eb2dd21b643f6d35ede26fee6bc9cc9 Mon Sep 17 00:00:00 2001 From: Rob Emery Date: Sat, 10 Oct 2026 22:09:21 +0100 Subject: [PATCH 21/34] First version of a local "make bank_size" --- .gitignore | 1 + Makefile | 3 +++ tools/bank_occupancy.sh | 21 +++++++++++++++++++++ 3 files changed, 25 insertions(+) create mode 100755 tools/bank_occupancy.sh diff --git a/.gitignore b/.gitignore index 5b169b0f..9f544835 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,4 @@ build/ # host-test stand-ins for the two generated headers !test/stub/html_data.h !test/stub/version.h +.vscode diff --git a/Makefile b/Makefile index 5ebd9ddf..aa31af35 100644 --- a/Makefile +++ b/Makefile @@ -64,6 +64,9 @@ endif # is built, including the tools/ subdirectory. all: create_build_dir $(VERSION_HEADER) $(MACHINE_SRC) $(SUBDIRS) $(BUILDDIR)/rtlplayground-$(FILENAME_EXTENSION).bin +bank_size: + tools/bank_occupancy.sh "$(MACHINE)" + create_build_dir: mkdir -p "$(BUILDDIR)" mkdir -p "$(BUILDDIR)/uip" diff --git a/tools/bank_occupancy.sh b/tools/bank_occupancy.sh new file mode 100755 index 00000000..c0dece81 --- /dev/null +++ b/tools/bank_occupancy.sh @@ -0,0 +1,21 @@ +#!/bin/bash +MACHINE="$1" +if [[ ! -s output-main/rtlplayground.map ]]; then + original_branch=$(git branch --show-current) + #trap 'git switch "$original_branch"' EXIT + git switch main && make CI=1 MACHINE="$MACHINE" BUILDDIR=output-main + git switch "$original_branch" +fi +source <(sed -rn 's/^([XCD]SEG|(BANK[0-9])).*=\s+([0-9]+)\. bytes.*$/main_\1=\3/p' output-main/rtlplayground.map | sort -u) +if [[ ! -s "output/$MACHINE/rtlplayground.map" ]]; then + make CI=1 MACHINE="$MACHINE" +fi +source <(sed -rn 's/^([XCD]SEG|(BANK[0-9])).*=\s+([0-9]+)\. bytes.*$/branch_\1=\3/p' output/"$MACHINE"/rtlplayground.map | sort -u) + +printf '%-20s %-20s %-20s %-20s\n' "segment" "main" "branch" "change" +printf '%-20s %-20s %-20s %-20s\n' "BANK1" "$main_BANK1" "$branch_BANK1" "$(($branch_BANK1-$main_BANK1))" +printf '%-20s %-20s %-20s %-20s\n' "BANK2" "$main_BANK2" "$branch_BANK2" "$(($branch_BANK2-$main_BANK2))" +printf '%-20s %-20s %-20s %-20s\n' "BANK3" "$main_BANK3" "$branch_BANK3" "$(($branch_BANK3-$main_BANK3))" +printf '%-20s %-20s %-20s %-20s\n' "CSEG" "$main_CSEG" "$branch_CSEG" "$(($branch_CSEG-$main_CSEG))" +printf '%-20s %-20s %-20s %-20s\n' "DSEG" "$main_DSEG" "$branch_DSEG" "$(($branch_DSEG-$main_DSEG))" +printf '%-20s %-20s %-20s %-20s\n' "XSEG" "$main_XSEG" "$branch_XSEG" "$(($branch_XSEG-$main_XSEG))" From 13801241ca14bd1b5e464d4daf53f7970ea63b0b Mon Sep 17 00:00:00 2001 From: Andre Brait Date: Mon, 19 Oct 2026 15:57:44 +0200 Subject: [PATCH 22/34] fix: accept firmware uploads independent of part MIME type Chrome on macOS labels .bin files application/macbinary. Searching for application/octet-stream mistakes the image bytes for more part headers and aborts when the preamble buffer fills. Find the multipart header terminator instead, after the HTTP separator retained by handle_post. Keep authentication, CRC checks and staging limits unchanged. Cover MacBinary, an omitted part Content-Type, and a split header terminator with exact staged-byte checks. --- CHANGELOG.md | 4 ++ httpd/httpd.c | 10 +---- test/test_httpd_tx.c | 91 +++++++++++++++++++++++++++++++++++++++----- 3 files changed, 88 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b66c3013..8f019c10 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,10 @@ ## Fixed +- Web UI + - Accept firmware uploads regardless of the file part's MIME type, including + `application/macbinary` sent by Chrome on macOS for `.bin` files. + - Config - A startup configuration line longer than the command buffer no longer stops the replay: the offending line is skipped and the following lines are still applied. diff --git a/httpd/httpd.c b/httpd/httpd.c index d167d30e..688513f8 100644 --- a/httpd/httpd.c +++ b/httpd/httpd.c @@ -448,15 +448,9 @@ static uint8_t config_take(void) // unlike scan_header(), keeps no auth state, so it may run on every buffered segment static uint16_t preamble_payload_start(uint16_t n) { - uint16_t pos; + // Skip the HTTP header separator retained by handle_post(). + uint16_t pos = 4; - for (pos = 0; pos + 24 <= n; pos++) { - if (strstart(&config_buf[pos], "application/octet-stream")) - break; - } - if (pos + 24 > n) - return 0; - pos += 24; while (pos + 3 < n && !strstart(&config_buf[pos], "\r\n\r\n")) pos++; if (pos + 3 >= n) diff --git a/test/test_httpd_tx.c b/test/test_httpd_tx.c index f2ea4172..e088716d 100644 --- a/test/test_httpd_tx.c +++ b/test/test_httpd_tx.c @@ -1,11 +1,10 @@ /* - * Host-side bench for the httpd transmit path. + * Host-side bench for the httpd transmit and firmware upload paths. * * Compiles the UNMODIFIED httpd/httpd.c and uip/uip.c and drives them through a - * real handshake and a real GET from a client that moves its receive window. + * real handshake, GETs with moving receive windows, and multipart POSTs. * Everything below the two modules - flash, console, JSON pages - is mocked - * here, so what the bench observes is the byte stream the firmware would put on - * the wire. + * here, so the bench observes the wire response and the bytes staged to flash. * * The file served out of the simulated flash carries a position-dependent * pattern, so a duplicated or skipped range shows up as a mismatch at a known @@ -82,6 +81,9 @@ static uint8_t written_config[CONFIG_LEN]; static uint16_t written_config_len; static uint32_t config_erase_addr, config_write_addr; static int config_erases, config_writes; +static uint8_t flash_written[64]; +static size_t flash_written_len; +static int flash_write_bad; const char * const mime_strings[] = { "text/html", "image/svg+xml", "image/x-icon", "image/png", "text/javascript", "text/css", "text/plain" }; @@ -107,11 +109,21 @@ void flash_sector_erase(void) void flash_write_bytes(uint8_t *ptr) { - config_writes++; - config_write_addr = flash_region.addr; - written_config_len = flash_region.len; - if (written_config_len <= sizeof(written_config)) - memcpy(written_config, ptr, written_config_len); + if (flash_region.addr < FIRMWARE_UPLOAD_START) { + config_writes++; + config_write_addr = flash_region.addr; + written_config_len = flash_region.len; + if (written_config_len <= sizeof(written_config)) + memcpy(written_config, ptr, written_config_len); + return; + } + if (flash_region.addr != FIRMWARE_UPLOAD_START + flash_written_len || + flash_region.len > sizeof(flash_written) - flash_written_len) { + flash_write_bad = 1; + return; + } + memcpy(flash_written + flash_written_len, ptr, flash_region.len); + flash_written_len += flash_region.len; } const char *get_flash_size_str(void) { return "512 kB"; } void crc16_bank1(uint8_t *v) { (void)v; } @@ -180,6 +192,8 @@ void send_lldp(void) {} extern uint8_t authenticated; extern char session_id[]; extern char passwd[21]; +extern uint16_t session_timeout; +extern uint32_t last_session_use; /* uip.c defines the listen table but no header declares it; the bench reads it * to confirm the port httpd_init() asked for is the one uIP is watching. */ @@ -1012,6 +1026,62 @@ static void scenario_config_upload(void) "multipart/config: every split writes the exact configuration and NUL to its sector"); } +/* Requiring octet-stream would leave alternate or absent MIME types buffered + * as headers forever instead of staging the binary and checking its CRC. */ +static void scenario_upload(const char *name, const char *part_type, int split) +{ + static const uint8_t payload[] = { 0x00, 0xff, 'R', '\r', '\n', '-', 0x80, 0x00 }; + static const uint8_t staged[] = { 0x00, 0xff, 'R', '\r', '\n', '-', 0x80, 0x00, 0x00 }; + static const char closing[] = "\r\n--upload-boundary--\r\n"; + char preamble[256], request[512]; + uint32_t saved_flash_size = flash_size; + int preamble_len, header_len, request_len; + + printf("\n-- upload: %s --\n", name); + session_start(MSS_FULL); + strcpy(session_id, "0123456789ab"); + session_timeout = 200; + last_session_use = 0; /* read_reg_timer() returns zero in this bench. */ + flash_size = 0x100000; + flash_written_len = 0; + flash_write_bad = 0; + reset_calls = 0; + + preamble_len = snprintf(preamble, sizeof(preamble), + "--upload-boundary\r\n" + "Content-Disposition: form-data; name=\"file\"; filename=\"firmware.bin\"\r\n" + "%s\r\n", part_type); + header_len = snprintf(request, sizeof(request), + "POST /upload HTTP/1.1\r\nHost: sw\r\n" + "Cookie: session=0123456789ab\r\n" + "Content-Type: multipart/form-data; boundary=upload-boundary\r\n" + "Content-Length: %zu\r\n\r\n%s", + (size_t)preamble_len + sizeof(payload) + sizeof(closing) - 1, preamble); + memcpy(request + header_len, payload, sizeof(payload)); + memcpy(request + header_len + sizeof(payload), closing, sizeof(closing) - 1); + request_len = header_len + sizeof(payload) + sizeof(closing) - 1; + if (split) { + /* Cut the part's CRLFCRLF between its final CR and LF. */ + client_send(TCP_ACK | TCP_PSH, request, header_len - 1); + CHECK(stream_len == 0 && flash_written_len == 0, + "upload: incomplete part headers stage nothing and await more data"); + client_send(TCP_ACK | TCP_PSH, request + header_len - 1, + request_len - header_len + 1); + } else { + client_send(TCP_ACK | TCP_PSH, request, request_len); + } + drain(MSS_FULL); + + CHECK(!flash_write_bad && flash_written_len == sizeof(staged) && + !memcmp(flash_written, staged, sizeof(staged)), + "upload: exact binary payload plus zero terminator staged at image address"); + CHECK(stream_len >= 12 && !memcmp(stream, "HTTP/1.1 400", 12), + "upload: invalid firmware is rejected with HTTP 400"); + CHECK(!uip_conn->appstate.fw_reset_pending && reset_calls == 0, + "upload: deliberately invalid CRC never schedules or triggers reset"); + flash_size = saved_flash_size; +} + int main(int argc, char **argv) { if (argc > 1 && !strcmp(argv[1], "-v")) @@ -1040,6 +1110,9 @@ int main(int argc, char **argv) scenario_oversized_get_header(); scenario_split_method_names(); scenario_config_upload(); + scenario_upload("octet-stream control", "Content-Type: application/octet-stream\r\n", 0); + scenario_upload("MacBinary, split part terminator", "Content-Type: application/macbinary\r\n", 1); + scenario_upload("no part Content-Type", "", 0); printf("\n%s (%d failure%s)\n", failures ? "BENCH: FAILURES" : "BENCH: ALL PASS", From 7d7585fa6de5d6d029895aa6ef396003c8d6ea3a Mon Sep 17 00:00:00 2001 From: Andre Brait Date: Mon, 19 Oct 2026 17:32:34 +0200 Subject: [PATCH 23/34] fix(health): give the LLDP phase a valid slot in the phase arrays In HEALTH=1 builds health_phase(HEALTH_LLDP) used id 7 while ph_max[] and ph_slow[] had HEALTH_PHASES = 6 entries. The LLDP checkpoint therefore wrote one byte past ph_max (into the high byte of ph_slow[0]) and, when the phase took two ticks or more, incremented two bytes past ph_slow (dhcp_state.state and transaction_id on KP_9000_6XHML_X2). Rename it HEALTH_PH_LLDP = 6, derive HEALTH_PHASES from it so the arrays always cover the last phase, print an lldp line in "health" and document it. Fixes #658 --- CHANGELOG.md | 3 +++ cmd_parser.c | 1 + cmd_parser.h | 4 ++-- doc/health.md | 3 ++- rtlplayground.c | 2 +- 5 files changed, 9 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b66c3013..2a27ca20 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,9 @@ ## Fixed +- Health + - `HEALTH=1` builds no longer write past the phase timing arrays at the LLDP checkpoint, which + corrupted the `link` slow counter and the DHCP client state. #658 - Config - A startup configuration line longer than the command buffer no longer stops the replay: the offending line is skipped and the following lines are still applied. diff --git a/cmd_parser.c b/cmd_parser.c index afc7831a..f8420379 100644 --- a/cmd_parser.c +++ b/cmd_parser.c @@ -2329,6 +2329,7 @@ void health_show(void) __banked ph_line("tx ", HEALTH_PH_TX); ph_line("stp ", HEALTH_PH_STP); ph_line("cmd ", HEALTH_PH_CMD); + ph_line("lldp", HEALTH_PH_LLDP); /* Stack: current depth plus how much of the painted area is untouched */ print_string("sp "); diff --git a/cmd_parser.h b/cmd_parser.h index 2359eb16..e6a073ab 100644 --- a/cmd_parser.h +++ b/cmd_parser.h @@ -19,8 +19,8 @@ extern __xdata uint8_t err_status; #define HEALTH_PH_TX 3 #define HEALTH_PH_STP 4 #define HEALTH_PH_CMD 5 -#define HEALTH_PHASES 6 -#define HEALTH_LLDP 7 +#define HEALTH_PH_LLDP 6 +#define HEALTH_PHASES (HEALTH_PH_LLDP + 1) /* last id + 1: sizes the arrays in cmd_parser.c */ extern __xdata uint16_t health_rx_frames; #define health_rx_frame() health_rx_frames++ diff --git a/doc/health.md b/doc/health.md index 736d52b7..af6b8a28 100644 --- a/doc/health.md +++ b/doc/health.md @@ -14,6 +14,7 @@ rx max 00 slow 0x0000 tx max 00 slow 0x0000 stp max 04 slow 0x0001 cmd max 02 slow 0x0001 +lldp max 00 slow 0x0000 sp 80 untouched 62 tcp st 00 tmr 00 rtx 00 rto 00 len 0x0000 mss 0x05b4 lport 0x0000 rport 0x0000 rip 0x0000 0x0000 @@ -46,7 +47,7 @@ a flooded CPU port from a stalled loop, which look identical from outside. ## Phases Each line is one section of the main loop: the link poll, SFP handling, -frame reception, TCP transmission, the STP timers and the command dispatch. +frame reception, TCP transmission, the STP timers, the LLDP timer and the command dispatch. `max` is the worst time that section has taken, in ticks of 5 ms; `slow` counts the passes that took two ticks or more. A misbehaving subsystem names itself here, which is the difference between knowing that the loop is diff --git a/rtlplayground.c b/rtlplayground.c index 0afa93c8..fbb94d76 100644 --- a/rtlplayground.c +++ b/rtlplayground.c @@ -1203,7 +1203,7 @@ static void handle_tick(void) lacp_timers(); health_phase(HEALTH_PH_STP); lldp_tick(); - health_phase(HEALTH_LLDP); + health_phase(HEALTH_PH_LLDP); cabletest_tick(); } From ef0d9d872ef54a27766d715592ac1caf57c79eb5 Mon Sep 17 00:00:00 2001 From: Rob Emery Date: Thu, 22 Oct 2026 09:48:53 +0100 Subject: [PATCH 24/34] adding the HTML/JS compressed sizes to the comment --- .github/workflows/build.yml | 6 +++++- tools/bank_occupancy.sh | 22 ++++++++++++++++------ 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c211d357..89a2a029 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -45,6 +45,9 @@ jobs: run: | sed -rn 's/^([XCD]SEG|(BANK[0-9])).*=\s+([0-9]+)\. bytes.*$/MAIN_\1=\3/p' /tmp/main.map | sort -u >> "$GITHUB_ENV" sed -rn 's/^([XCD]SEG|(BANK[0-9])).*=\s+([0-9]+)\. bytes.*$/BRANCH_\1=\3/p' /tmp/branch.map | sort -u >> "$GITHUB_ENV" + du -sb main/output/html_min | awk '{print "MAIN_WEB="$1}' >> "$GITHUB_ENV" + du -sb branch/output/html_min | awk '{print "BRANCH_WEB="$1}' >>"$GITHUB_ENV" + - name: Update PR comment uses: marocchino/sticky-pull-request-comment@v3 with: @@ -54,7 +57,7 @@ jobs: Commit: ${{ github.sha }} - | Bank # | Main | Branch | + | Name | Main | Branch | | --- | --- | --- | | XSEG | ${{ env.MAIN_XSEG }} bytes | ${{ env.BRANCH_XSEG }} bytes | | CSEG | ${{ env.MAIN_CSEG }} bytes | ${{ env.BRANCH_CSEG }} bytes | @@ -62,3 +65,4 @@ jobs: | 1 | ${{ env.MAIN_BANK1 }} bytes | ${{ env.BRANCH_BANK1 }} bytes | | 2 | ${{ env.MAIN_BANK2 }} bytes | ${{ env.BRANCH_BANK2 }} bytes | | 3 | ${{ env.MAIN_BANK3 }} bytes | ${{ env.BRANCH_BANK3 }} bytes | + | HTML/JS | ${{ env.MAIN_WEB }} bytes | ${{ env.BRANCH_WEB }} bytes | \ No newline at end of file diff --git a/tools/bank_occupancy.sh b/tools/bank_occupancy.sh index c0dece81..8638d390 100755 --- a/tools/bank_occupancy.sh +++ b/tools/bank_occupancy.sh @@ -7,15 +7,25 @@ if [[ ! -s output-main/rtlplayground.map ]]; then git switch "$original_branch" fi source <(sed -rn 's/^([XCD]SEG|(BANK[0-9])).*=\s+([0-9]+)\. bytes.*$/main_\1=\3/p' output-main/rtlplayground.map | sort -u) + +main_WEB=$(du -sb output-main/html_min | awk '{print $1}') if [[ ! -s "output/$MACHINE/rtlplayground.map" ]]; then make CI=1 MACHINE="$MACHINE" fi source <(sed -rn 's/^([XCD]SEG|(BANK[0-9])).*=\s+([0-9]+)\. bytes.*$/branch_\1=\3/p' output/"$MACHINE"/rtlplayground.map | sort -u) +branch_WEB=$(du -sb output/html_min | awk '{print $1}') + +print_line() { + local name=$1 main=$2 branch=$3 + printf '%-20s %-20s %-20s %-20s\n' "$name" "$main" "$branch" "$((branch - main))" +} printf '%-20s %-20s %-20s %-20s\n' "segment" "main" "branch" "change" -printf '%-20s %-20s %-20s %-20s\n' "BANK1" "$main_BANK1" "$branch_BANK1" "$(($branch_BANK1-$main_BANK1))" -printf '%-20s %-20s %-20s %-20s\n' "BANK2" "$main_BANK2" "$branch_BANK2" "$(($branch_BANK2-$main_BANK2))" -printf '%-20s %-20s %-20s %-20s\n' "BANK3" "$main_BANK3" "$branch_BANK3" "$(($branch_BANK3-$main_BANK3))" -printf '%-20s %-20s %-20s %-20s\n' "CSEG" "$main_CSEG" "$branch_CSEG" "$(($branch_CSEG-$main_CSEG))" -printf '%-20s %-20s %-20s %-20s\n' "DSEG" "$main_DSEG" "$branch_DSEG" "$(($branch_DSEG-$main_DSEG))" -printf '%-20s %-20s %-20s %-20s\n' "XSEG" "$main_XSEG" "$branch_XSEG" "$(($branch_XSEG-$main_XSEG))" + +print_line "BANK1" "$main_BANK1" "$branch_BANK1" +print_line "BANK2" "$main_BANK2" "$branch_BANK2" +print_line "BANK3" "$main_BANK3" "$branch_BANK3" +print_line "CSEG" "$main_CSEG" "$branch_CSEG" +print_line "DSEG" "$main_DSEG" "$branch_DSEG" +print_line "XSEG" "$main_XSEG" "$branch_XSEG" +print_line "WEB" "$main_WEB" "$branch_WEB" From 98965b73f694cc6ab4aa12d85a15b6324a95eb40 Mon Sep 17 00:00:00 2001 From: Rob Emery Date: Thu, 22 Oct 2026 12:55:51 +0100 Subject: [PATCH 25/34] Fixes to BUILDDIR --- Makefile | 6 +++--- tools/Makefile | 4 +++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index aa31af35..54660495 100644 --- a/Makefile +++ b/Makefile @@ -139,7 +139,7 @@ HTML := $(shell find html -name '*.js' -or -name '*.html' -or -name '*.svg' -or # Minified copy of the web UI sources, used as the fileadder input. # The raw html/ sources stay untouched for development; the minified # copy is a build artifact under output/. -HTML_MIN := output/html_min +HTML_MIN := $(BUILDDIR)/html_min .PHONY: html_min html_min: $(HTML) rm -rf $(HTML_MIN) @@ -161,7 +161,7 @@ $(VERSION_HEADER): FORCE httpd: html_data.h $(SUBDIRS): - $(MAKE) -C $@ + $(MAKE) -C $@ BUILDDIR=$(BUILDDIR) clean: $(SUBDIRSCLEAN) -rm -f html_data.c html_data.h $(VERSION_HEADER) @@ -204,7 +204,7 @@ $(BUILDDIR)/rtlplayground-$(FILENAME_EXTENSION).bin: $(BUILDDIR)/rtlplayground.i tools/output/fileadder -a $(CONFIG_LOCATION) -s $(IMAGESIZE) -d config.txt $@ tools/output/fileadder -a $(HTML_LOCATION) -s $(IMAGESIZE) -z -d $(HTML_MIN) -b BANK1 $@ tools/output/crc_calculator -u $@ - ln -sf $(MACHINE)/rtlplayground-$(FILENAME_EXTENSION).bin output/rtlplayground.bin + ln -sf $(MACHINE)/rtlplayground-$(FILENAME_EXTENSION).bin $(BUILDDIR)/../rtlplayground.bin .PHONY: clean distclean all $(SUBDIRS) $(SUBDIRSCLEAN) create_build_dir diff --git a/tools/Makefile b/tools/Makefile index 1b1c6685..80ac9743 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -1,6 +1,8 @@ CC = gcc CCFLAGS = -Wall -o -BUILDDIR = output +ifndef BUILDDIR + BUILDDIR = output +endif all: create_build_dir $(BUILDDIR)/injector $(BUILDDIR)/fileadder $(BUILDDIR)/httpd_sim\ $(BUILDDIR)/crc_calculator $(BUILDDIR)/imagebuilder From 6e5617c82f4c81ce351e70d5562268e30040263d Mon Sep 17 00:00:00 2001 From: Rob Emery Date: Thu, 22 Oct 2026 18:12:23 +0100 Subject: [PATCH 26/34] Fixing path to tools builds now they have injected BUILDDIR from the main Makefile --- Makefile | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index 54660495..546a2870 100644 --- a/Makefile +++ b/Makefile @@ -147,7 +147,7 @@ html_min: $(HTML) @for f in $(HTML); do python3 tools/minify.py $$f $(HTML_MIN)/$$(basename $$f) || exit 1; done html_data.c html_data.h &: $(HTML) | tools html_min - tools/output/fileadder -a $(HTML_LOCATION) -s $(IMAGESIZE) -b BANK1 -z -d $(HTML_MIN) -p html_data + tools/$(BUILDDIR)/fileadder -a $(HTML_LOCATION) -s $(IMAGESIZE) -b BANK1 -z -d $(HTML_MIN) -p html_data $(VERSION_HEADER): FORCE @printf '%s\n' "#ifndef VERSION_H" "#define VERSION_H" \ @@ -199,11 +199,11 @@ $(BUILDDIR)/rtlplayground.img: $(BUILDDIR)/rtlplayground.ihx $(BUILDDIR)/rtlplayground-$(FILENAME_EXTENSION).bin: $(BUILDDIR)/rtlplayground.img | tools if [ -e $@ ]; then rm $@; fi - tools/output/imagebuilder -i $^ $@ - tools/output/fileadder -a $(DEFAULT_CONFIG_LOCATION) -s $(IMAGESIZE) -d config.txt $@ - tools/output/fileadder -a $(CONFIG_LOCATION) -s $(IMAGESIZE) -d config.txt $@ - tools/output/fileadder -a $(HTML_LOCATION) -s $(IMAGESIZE) -z -d $(HTML_MIN) -b BANK1 $@ - tools/output/crc_calculator -u $@ + tools/$(BUILDDIR)/imagebuilder -i $^ $@ + tools/$(BUILDDIR)/fileadder -a $(DEFAULT_CONFIG_LOCATION) -s $(IMAGESIZE) -d config.txt $@ + tools/$(BUILDDIR)/fileadder -a $(CONFIG_LOCATION) -s $(IMAGESIZE) -d config.txt $@ + tools/$(BUILDDIR)/fileadder -a $(HTML_LOCATION) -s $(IMAGESIZE) -z -d $(HTML_MIN) -b BANK1 $@ + tools/$(BUILDDIR)/crc_calculator -u $@ ln -sf $(MACHINE)/rtlplayground-$(FILENAME_EXTENSION).bin $(BUILDDIR)/../rtlplayground.bin .PHONY: clean distclean all $(SUBDIRS) $(SUBDIRSCLEAN) create_build_dir From 9731a33fa9579745cae2d0e6816b3b9f404e1ab0 Mon Sep 17 00:00:00 2001 From: Rob Emery Date: Thu, 22 Oct 2026 19:16:50 +0100 Subject: [PATCH 27/34] Adding missing? permission to fix the build --- .github/workflows/build.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 89a2a029..64543b4c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -8,6 +8,7 @@ on: permissions: contents: read pull-requests: write + issues: write jobs: build: @@ -65,4 +66,4 @@ jobs: | 1 | ${{ env.MAIN_BANK1 }} bytes | ${{ env.BRANCH_BANK1 }} bytes | | 2 | ${{ env.MAIN_BANK2 }} bytes | ${{ env.BRANCH_BANK2 }} bytes | | 3 | ${{ env.MAIN_BANK3 }} bytes | ${{ env.BRANCH_BANK3 }} bytes | - | HTML/JS | ${{ env.MAIN_WEB }} bytes | ${{ env.BRANCH_WEB }} bytes | \ No newline at end of file + | HTML/JS | ${{ env.MAIN_WEB }} bytes | ${{ env.BRANCH_WEB }} bytes | From a94be7d524e2a938e9ad54458b989f5fd78d444f Mon Sep 17 00:00:00 2001 From: Rob Emery Date: Thu, 22 Oct 2026 19:30:29 +0100 Subject: [PATCH 28/34] Fixing path on the du command to respect new structure --- .github/workflows/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 64543b4c..73559db2 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -46,8 +46,8 @@ jobs: run: | sed -rn 's/^([XCD]SEG|(BANK[0-9])).*=\s+([0-9]+)\. bytes.*$/MAIN_\1=\3/p' /tmp/main.map | sort -u >> "$GITHUB_ENV" sed -rn 's/^([XCD]SEG|(BANK[0-9])).*=\s+([0-9]+)\. bytes.*$/BRANCH_\1=\3/p' /tmp/branch.map | sort -u >> "$GITHUB_ENV" - du -sb main/output/html_min | awk '{print "MAIN_WEB="$1}' >> "$GITHUB_ENV" - du -sb branch/output/html_min | awk '{print "BRANCH_WEB="$1}' >>"$GITHUB_ENV" + du -sb main/output/KP_9000_6XHML_X2/html_min | awk '{print "MAIN_WEB="$1}' >> "$GITHUB_ENV" + du -sb branch/output/KP_9000_6XHML_X2/html_min | awk '{print "BRANCH_WEB="$1}' >>"$GITHUB_ENV" - name: Update PR comment uses: marocchino/sticky-pull-request-comment@v3 From 63a3bc50d64f05743adc3f270b026e9df8d04620 Mon Sep 17 00:00:00 2001 From: Rob Emery Date: Thu, 22 Oct 2026 19:51:50 +0100 Subject: [PATCH 29/34] Removing the comment step as this is erroring with Error: Resource not accessible by integration and I think the repository owner will need to check the settings on the repo --- .github/workflows/build.yml | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 73559db2..7097ef48 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -48,22 +48,3 @@ jobs: sed -rn 's/^([XCD]SEG|(BANK[0-9])).*=\s+([0-9]+)\. bytes.*$/BRANCH_\1=\3/p' /tmp/branch.map | sort -u >> "$GITHUB_ENV" du -sb main/output/KP_9000_6XHML_X2/html_min | awk '{print "MAIN_WEB="$1}' >> "$GITHUB_ENV" du -sb branch/output/KP_9000_6XHML_X2/html_min | awk '{print "BRANCH_WEB="$1}' >>"$GITHUB_ENV" - - - name: Update PR comment - uses: marocchino/sticky-pull-request-comment@v3 - with: - header: Sizes - message: | - ## Image Growth - - Commit: ${{ github.sha }} - - | Name | Main | Branch | - | --- | --- | --- | - | XSEG | ${{ env.MAIN_XSEG }} bytes | ${{ env.BRANCH_XSEG }} bytes | - | CSEG | ${{ env.MAIN_CSEG }} bytes | ${{ env.BRANCH_CSEG }} bytes | - | DSEG | ${{ env.MAIN_DSEG }} bytes | ${{ env.BRANCH_DSEG }} bytes | - | 1 | ${{ env.MAIN_BANK1 }} bytes | ${{ env.BRANCH_BANK1 }} bytes | - | 2 | ${{ env.MAIN_BANK2 }} bytes | ${{ env.BRANCH_BANK2 }} bytes | - | 3 | ${{ env.MAIN_BANK3 }} bytes | ${{ env.BRANCH_BANK3 }} bytes | - | HTML/JS | ${{ env.MAIN_WEB }} bytes | ${{ env.BRANCH_WEB }} bytes | From c043c671d73fab717fcac92e0f6dc7eb2f9a88e4 Mon Sep 17 00:00:00 2001 From: HL Yi Date: Thu, 22 Oct 2026 18:34:44 -0500 Subject: [PATCH 30/34] clean up min_port and max_port from struct after PR#684 --- doc/adding-a-device.md | 14 +++++++------- machine.h | 4 ---- machine/machine_defs.h | 4 +--- test/env_tables.c | 2 -- test/test_lacp.c | 7 +++++-- 5 files changed, 13 insertions(+), 18 deletions(-) diff --git a/doc/adding-a-device.md b/doc/adding-a-device.md index 0f950b81..7e2aa150 100644 --- a/doc/adding-a-device.md +++ b/doc/adding-a-device.md @@ -38,8 +38,8 @@ existing files as the template: ``` `MACHINE_CHIPSET` is `RTL8373` or `RTL8372`; a build without it will fail. It selects the default -logical port range: `min_port` is `0` for RTL8373 and `3` for RTL8372, while `max_port` is `8`, -the highest logical port index. A board with a different range defines +logical port range: `MACHINE_MIN_PORT` is `0` for RTL8373 and `3` for RTL8372, while +`MACHINE_MAX_PORT` is `8`, the highest logical port index. A board with a different range defines `MACHINE_MIN_PORT` and/or `MACHINE_MAX_PORT` in its header to override the defaults. @@ -94,16 +94,16 @@ __code const struct machine machine = { }; ``` -`MACHINE_COMMON_SETTING` (from `machine_defs.h`) initializes `machine_name`, -`isRTL8373`, `min_port` and `max_port` from the header's `MACHINE_MODEL` and -`MACHINE_CHIPSET`. Keep it as the first initializer and list the -board-specific fields after it. +`MACHINE_COMMON_SETTING` (from `machine_defs.h`) initializes `machine_name` and +`isRTL8373` from the header's `MACHINE_MODEL` and `MACHINE_CHIPSET`. The logical +port range comes from `MACHINE_MIN_PORT` and `MACHINE_MAX_PORT` in `machine.h`. +Keep it as the first initializer and list the board-specific fields after it. ### Fields | Field | Meaning | |-------|---------| -| `MACHINE_COMMON_SETTING` | expands to `machine_name` (`MACHINE_MODEL`), `isRTL8373` (`1` for `RTL8373`, `0` for `RTL8372`), `min_port` and `max_port`; all are derived from the header's `MACHINE_CHIPSET` (see Step 1) | +| `MACHINE_COMMON_SETTING` | expands to `machine_name` (`MACHINE_MODEL`) and `isRTL8373` (`1` for `RTL8373`, `0` for `RTL8372`); both are derived from the header's `MACHINE_CHIPSET` (see Step 1) | | `n_sfp` | number of SFP+ cages | | `n_10g` | SerDes 10G capability used by the RTL837xN init: `0` none, `1` one, `2` two 10G-capable SerDes | | `log_to_phys_port[9]` | logical port (0-based index) → physical front-panel port number | diff --git a/machine.h b/machine.h index b7b3f63f..78dfd77a 100644 --- a/machine.h +++ b/machine.h @@ -84,10 +84,6 @@ struct sfp_port struct machine { char machine_name[30]; uint8_t isRTL8373; - // Lowest logical port number - uint8_t min_port; - // Highest logical port number - uint8_t max_port; uint8_t n_sfp; uint8_t n_10g; uint8_t log_to_phys_port[9]; diff --git a/machine/machine_defs.h b/machine/machine_defs.h index 4775a58f..be77636d 100644 --- a/machine/machine_defs.h +++ b/machine/machine_defs.h @@ -43,8 +43,6 @@ #define MACHINE_COMMON_SETTING \ .machine_name = MACHINE_MODEL, \ - .isRTL8373 = MACHINE_CHIPSET == RTL8373, \ - .min_port = MACHINE_MIN_PORT, \ - .max_port = MACHINE_MAX_PORT + .isRTL8373 = MACHINE_CHIPSET == RTL8373 #endif diff --git a/test/env_tables.c b/test/env_tables.c index 719e045a..e4d23c37 100644 --- a/test/env_tables.c +++ b/test/env_tables.c @@ -59,8 +59,6 @@ uint8_t *hex = (uint8_t *)hex_chars; /* ---- a 9-port RTL8373 whose logical ports map to themselves ---- */ const struct machine machine = { .machine_name = "HOSTTEST", - .min_port = 0, - .max_port = 8, .n_sfp = 0, .log_to_phys_port = { 1, 2, 3, 4, 5, 6, 7, 8, 9 }, .phys_to_log_port = { 0, 1, 2, 3, 4, 5, 6, 7, 8 }, diff --git a/test/test_lacp.c b/test/test_lacp.c index 160c773e..56b8e56f 100644 --- a/test/test_lacp.c +++ b/test/test_lacp.c @@ -14,8 +14,11 @@ uint8_t uip_buf[UIP_CONF_BUFFER_ALLOC_SIZE]; uint16_t uip_len; struct uip_eth_addr uip_ethaddr = { .addr = {0x02,0x11,0x22,0x33,0x44,0x55} }; -const struct machine machine = { .min_port = 0, .max_port = 7, +const struct machine machine = { .log_to_phys_port = {5, 1, 2, 3, 4, 6, 7, 8, 9} }; +/* Logical ports of the mock machine above */ +#define TEST_MIN_PORT 0 +#define TEST_MAX_PORT 7 struct machine_runtime machine_detected = { .isRTL8373 = 1 }; uint8_t lacpEnabled; uint16_t management_vlan; /* mocked; slow-protocol path zeroes it per-frame */ @@ -216,7 +219,7 @@ int main(int argc, char **argv) lacp_lag_set(0, 0x00ff); step(8); int all_tx = 1, sane = 1; - for (int i = machine.min_port; i <= machine.max_port; i++) { + for (int i = TEST_MIN_PORT; i <= TEST_MAX_PORT; i++) { if (!tx_count[i]) all_tx = 0; if (last_tx[i].ethertype != HTONS(0x8809) || last_tx[i].subtype != 1 || last_tx[i].dst[5] != 0x02 From d13a5d125d1d055b122c033bf420a797288c36db Mon Sep 17 00:00:00 2001 From: "Luca S." Date: Sat, 24 Oct 2026 00:16:35 +0200 Subject: [PATCH 31/34] Add KeepLink KP-9000-9XHP-X as brand of POE-2G080110GS --- doc/devices/2M-PCB51-ML-V1_1.md | 2 ++ doc/supported_devices.md | 1 + 2 files changed, 3 insertions(+) diff --git a/doc/devices/2M-PCB51-ML-V1_1.md b/doc/devices/2M-PCB51-ML-V1_1.md index d2c6cb9c..f621f3c3 100644 --- a/doc/devices/2M-PCB51-ML-V1_1.md +++ b/doc/devices/2M-PCB51-ML-V1_1.md @@ -1,11 +1,13 @@ # MokerLink POE-2G080110GS The `POE-2G080110GS` is an unmanaged 8x2.5G RJ45 and 1xSFP+ PoE switch sold by Mokerlink. There is also a `POE-2G080110GSM` managed version of the switch which may be similar but this has not been verified on actual hardware. +The`KP-9000-9XHP-X` is the KeepLink rebrand for same product. ## Brands | Brand | Type |Managed| PCB | Flash | Chip RTL | |--------|------------------|-------|------------------|-----------------|---------------| | Mokerlink | POE-2G080110GS | No | 2M-PCB51-ML-V1.1 | 4MB (W25Q32JV) | 8373N + 8224N | +| KeepLink | KP-9000-9XHP-X | No | 2M-PCB51-ML-V1.1 | 4MB (W25Q32JV) | 8373N + 8224N | ## Hardware overview Front diff --git a/doc/supported_devices.md b/doc/supported_devices.md index 3d3d5ba2..5e918c1d 100644 --- a/doc/supported_devices.md +++ b/doc/supported_devices.md @@ -29,6 +29,7 @@ The following devices have been tested and are fully working: | keepLINK | KP-9000-9XHML-X | Yes | [2M-PCB23-V2.2](devices/2M-PCB23-V2_2.md) | 2M | 8 + 1 | | keepLINK | KP-9000-9XHML-X | Yes | [2M-PCB23-V3.1](devices/2M-PCB23-V3_1.md) | 2M | 8 + 1 | | keepLINK | KP-9000-9XHML-X | Yes | [2M-PCB23-V3.2](devices/2M-PCB23-V3_2.md) | 2M | 8 + 1 | +| keepLINK | KP-9000-9XHP-X | No | [2M-PCB51-ML-V1.1](devices/2M-PCB51-ML-V1_1.md) | 4M | 8 + 1 | | LIANGUO | HYWS-SGT0108S | No | [2G5F_20G_V1.01](devices/HYWS-SGT0108S.md) | 0.5M | 8 + 1 | | LIANGUO | SWTG024AS | No | [SWTG024AS-v2.0-17452](devices/SWTG024AS.md) | 0.5M | 4 + 2 | | LIANGUO | ZX-SWTGW215AS | Yes | [PCB-SWTG115AS-V2.0 / PCB-SWTG115AS-V2.1](devices/SWTGW215AS.md) | 2M | 5 + 1 | From 0da63187775e992a43d15f815344c29c3ca82ab3 Mon Sep 17 00:00:00 2001 From: robs Date: Sat, 24 Oct 2026 01:20:45 +0200 Subject: [PATCH 32/34] Web UI: keep Firefox from autofilling the new admin password Firefox filled a saved login into the System tab's password fields and its user name into the NTP poll interval, the input before them. That input event marked the Time card as edited, so ntpLoad() left NTP off, the server empty and the time zone at UTC-12:00. --- CHANGELOG.md | 3 +++ html/index.html | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 879a6682..fdbd770f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,9 @@ ## Fixed - Web UI + - Firefox no longer fills a saved login into the new admin password fields. It also put the + user name into the NTP poll interval, which marked the Time card as edited, so it kept its + defaults (NTP off, no server, UTC-12:00) instead of the switch's settings. - Accept firmware uploads regardless of the file part's MIME type, including `application/macbinary` sent by Chrome on macOS for `.bin` files. diff --git a/html/index.html b/html/index.html index f95c8219..09c18d66 100644 --- a/html/index.html +++ b/html/index.html @@ -437,8 +437,8 @@ button.danger{background:var(--bad);color:#fff;border-color:transparent}

The switch has no battery backed clock.

Admin password

- - + +

Takes effect immediately; save to flash to keep it after reboot.

From 51ed063dcb6da15d2a7bdc08a0160b5795a415f3 Mon Sep 17 00:00:00 2001 From: robs Date: Sat, 24 Oct 2026 08:30:27 +0200 Subject: [PATCH 33/34] rtl8372_init: set SDS 0 to SGMII as the stock firmware does The masks were 0, so 0x3e2 was ORed into the reset value 0xbff and both SerDes stayed off on boards without 10G ports (n_10g == 0), e.g. the HC-SWTG124AS. With SDS 0 off RTL837X_REG_SEC_COUNTER does not hold a written value: it reads 0, so NTP never retried after a failed first attempt at boot and froze the clock after a sync. Tested with regset on an HC-SWTG124AS: the register keeps a write with SDS 0 in SGMII or 10GR, not with SDS 0 off (also not with only SDS 1 on). --- rtl837x_init.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/rtl837x_init.c b/rtl837x_init.c index 73498642..cc2adfcd 100644 --- a/rtl837x_init.c +++ b/rtl837x_init.c @@ -221,9 +221,11 @@ void rtl8372_init(void) __banked } else if(machine.n_10g == 2) { REG_SET(RTL837X_REG_SDS_MODES, 0x1ad); // Both 10g ports use SDS_QXGMII } else { + // Replace the reset value 0xbff (both SDS off) instead of ORing into it: + // RTL837X_REG_SEC_COUNTER only holds a written value while SDS 0 is on reg_read_m(RTL837X_REG_SDS_MODES); - sfr_mask_data(1, 0, 0x03); - sfr_mask_data(0, 0, 0xe2); + sfr_mask_data(1, 0xff, 0x03); + sfr_mask_data(0, 0xff, 0xe2); reg_write_m(RTL837X_REG_SDS_MODES); } From 884a1ac016831e73880e5c42f029f082afeeedbc Mon Sep 17 00:00:00 2001 From: robs Date: Sat, 24 Oct 2026 08:45:03 +0200 Subject: [PATCH 34/34] CHANGELOG: SDS 0 init on RTL8372 boards without 10G ports --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 879a6682..8d7dc466 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,12 @@ ## Fixed +- Time + - `rtl8372_init()` sets SDS 0 to SGMII as the stock firmware does. The masks were 0, so on RTL8372 + boards without 10G ports both SerDes stayed off, and with SDS 0 off `RTL837X_REG_SEC_COUNTER` + does not hold a written value: NTP never retried after a failed first attempt at boot and + froze the clock after a sync. + - Web UI - Accept firmware uploads regardless of the file part's MIME type, including `application/macbinary` sent by Chrome on macOS for `.bin` files.