NETMGR_DESIGN.md 期1范围(→ M6.0)落地: - meow_netmgrd 守护:svcd 托管 trigger=boot/restart=on-fail,进程内 HibyOS 只读降级 (/tmp/meow_boot_mode != meow → 读可查/写拒+日志,热切换)。 - 接口统一层(§3):iface 枚举(/sys/class/net+/proc/net/dev,lo/wlan0/usb-eth 热插拔节拍检测); WiFi 状态/扫描/网络列表/连接/断开(wpa_cli popen 有界收割防挂死,257 教训);IP/路由/DNS 只读 (ip 优先 /proc/net/route+resolv.conf);BT 状态/开关/已配对(hciconfig/bluetoothctl);rfkill 读写;udhcpc 续租/释放(MeowOS)。 - IPC 0x00E0-0x00E7(STATUS/IFACE/WIFI_CTL/BT_CTL+各自 RESULT):读级任意、写级仅系统身份(SO_PEERCRED 同 svc_power),0xE8-0xEF 期2/3 预留(仅注释)。 - CLI 双形态 meow_net(status/iface/wifi/bt/rfkill/help):IPC 薄壳,help 本地必可用。 - 日志框架:TF MeowOS/logs/net_<bootts>.log(无卡降级 /tmp),接口状态变化/写操作必记。 - 单线程 poll、静态表、热路径禁 malloc;mipsel 静态(0 warning),宿主+qemu-mipsel 全过, 真机只读验证 status/wifi scan/bt status 正确。 meow_ipc.h 仅追加 0x00E0-0x00E7 段(不改既有行)。
219 lines
12 KiB
C
219 lines
12 KiB
C
/* netmgrd_authtest.c — meow_netmgrd IPC 鉴权/写级决策 宿主自测(本程序非生产代码)。
|
||
*
|
||
* 通过 #include 生产源文件(meow_netmgrd.c,用 #define main 改名避免入口冲突),在同一 TU 内直接
|
||
* 访问其 FILE-STATIC 函数/全局:classify_exe / is_sys_identity / wifi_cmd_is_write / bt_cmd_is_write /
|
||
* wifi_write_authorize / bt_write_authorize / rfkill_set_block / wifi_networks / wifi_scan / bt_status,
|
||
* 验证鉴别/分级/授权决策表与接口层动作(假 sysfs/proc + 桩命令)。
|
||
* 覆盖「真机需特权路径 /proc/pid/exe 判定」之外的所有纯逻辑分支;真实 pid→exe 解析留真机验证。
|
||
*
|
||
* 用途:dev docs 复现级宿主自测;不进入固件/不部署。用法:
|
||
* cc -Wall -Wextra -I../meow_launcherd netmgrd_authtest.c -o netmgrd_authtest && ./netmgrd_authtest
|
||
*/
|
||
#define main meow_netmgrd_prod_main_unused
|
||
#include "meow_netmgrd.c"
|
||
#undef main
|
||
|
||
#include <stdio.h>
|
||
#include <string.h>
|
||
#include <stdlib.h>
|
||
#include <sys/stat.h>
|
||
#include <unistd.h>
|
||
|
||
static int g_fail = 0;
|
||
#define CHECK(cond) do { if (!(cond)) { printf(" FAIL: %s (line %d)\n", #cond, __LINE__); g_fail++; } \
|
||
else { printf(" ok : %s\n", #cond); } } while (0)
|
||
|
||
static void wf(const char *p, const char *s)
|
||
{
|
||
FILE *f = fopen(p, "w");
|
||
if (f) { fputs(s, f); fclose(f); }
|
||
}
|
||
|
||
int main(void)
|
||
{
|
||
static const char *T = "/tmp/nmg_authtest";
|
||
char p[192];
|
||
caller_t c;
|
||
|
||
printf("== classify_exe ==\n");
|
||
memset(&c, 0, sizeof c);
|
||
classify_exe("/usr/data/mnt/sd_0/MeowAPPs/os.meow.tst/meow", &c);
|
||
CHECK(c.kind == CALL_PKG && strcmp(c.pkg, "os.meow.tst") == 0);
|
||
memset(&c, 0, sizeof c);
|
||
classify_exe("/usr/data/mnt/sd_0/MeowAPPs/com.example.tool/meow", &c);
|
||
CHECK(c.kind == CALL_PKG && strcmp(c.pkg, "com.example.tool") == 0);
|
||
memset(&c, 0, sizeof c);
|
||
classify_exe("/usr/data/mnt/sd_0/MeowAPPs/os.meow.tst/sub/meow", &c);
|
||
CHECK(c.kind == CALL_PKG && strcmp(c.pkg, "os.meow.tst") == 0);
|
||
memset(&c, 0, sizeof c);
|
||
classify_exe("/usr/bin/meow_net", &c);
|
||
CHECK(c.kind == CALL_SYS && strcmp(c.pkg, "meow_net") == 0); /* /usr/bin/meow_* 前缀 → 系统 */
|
||
memset(&c, 0, sizeof c);
|
||
classify_exe("/usr/bin/meow_launcherd", &c);
|
||
CHECK(c.kind == CALL_SYS && strcmp(c.pkg, "os.meow.launcher") == 0);
|
||
memset(&c, 0, sizeof c);
|
||
classify_exe("/usr/bin/wpa_cli", &c);
|
||
CHECK(c.kind == CALL_OTHER); /* 非 meow_* 系统二进制 */
|
||
memset(&c, 0, sizeof c);
|
||
classify_exe("/usr/data/mnt/sd_0/MeowAPPs/justadirty/k", &c);
|
||
CHECK(c.kind == CALL_PKG && strcmp(c.pkg, "justadirty") == 0); /* 第三方包(非 os.meow.*) */
|
||
CHECK(is_sys_identity(&c) == 0);
|
||
|
||
printf("== is_sys_identity ==\n");
|
||
c.kind = CALL_PKG; snprintf(c.pkg, sizeof c.pkg, "%s", "os.meow.tst");
|
||
CHECK(is_sys_identity(&c) == 1);
|
||
c.kind = CALL_PKG; snprintf(c.pkg, sizeof c.pkg, "%s", "com.example.tool");
|
||
CHECK(is_sys_identity(&c) == 0);
|
||
c.kind = CALL_SYS; snprintf(c.pkg, sizeof c.pkg, "%s", "os.meow.launcher");
|
||
CHECK(is_sys_identity(&c) == 1);
|
||
c.kind = CALL_OTHER; c.pkg[0] = 0;
|
||
CHECK(is_sys_identity(&c) == 0);
|
||
|
||
printf("== wifi_cmd_is_write / bt_cmd_is_write ==\n");
|
||
CHECK(wifi_cmd_is_write("status", NULL) == 0);
|
||
CHECK(wifi_cmd_is_write("networks", NULL) == 0);
|
||
CHECK(wifi_cmd_is_write("scan", NULL) == 1);
|
||
CHECK(wifi_cmd_is_write("connect", "ssid") == 1);
|
||
CHECK(wifi_cmd_is_write("disconnect", NULL) == 1);
|
||
CHECK(wifi_cmd_is_write("on", NULL) == 1);
|
||
CHECK(wifi_cmd_is_write("off", NULL) == 1);
|
||
CHECK(wifi_cmd_is_write("rfkill", "list") == 0);
|
||
CHECK(wifi_cmd_is_write("rfkill", "wlan on") == 1);
|
||
CHECK(wifi_cmd_is_write("udhcpc", "renew wlan0") == 1);
|
||
CHECK(bt_cmd_is_write("status") == 0);
|
||
CHECK(bt_cmd_is_write("paired") == 0);
|
||
CHECK(bt_cmd_is_write("on") == 1);
|
||
CHECK(bt_cmd_is_write("off") == 1);
|
||
|
||
printf("== authorize 决策(系统身份 × MeowOS 模式)==\n");
|
||
caller_t sys; memset(&sys, 0, sizeof sys); sys.kind = CALL_SYS; snprintf(sys.pkg, sizeof sys.pkg, "%s", "meow_net");
|
||
caller_t pkgm; memset(&pkgm, 0, sizeof pkgm); pkgm.kind = CALL_PKG; snprintf(pkgm.pkg, sizeof pkgm.pkg, "%s", "os.meow.panel");
|
||
caller_t third; memset(&third, 0, sizeof third); third.kind = CALL_PKG; snprintf(third.pkg, sizeof third.pkg, "%s", "com.example.tool");
|
||
caller_t other; memset(&other, 0, sizeof other); other.kind = CALL_OTHER; other.uid = 1000;
|
||
/* 读级:任意放行,与身份/模式无关 */
|
||
CHECK(wifi_write_authorize(&other, 0, "networks", NULL) == MEOW_OK);
|
||
CHECK(bt_write_authorize(&other, 0, "status") == MEOW_OK);
|
||
CHECK(wifi_write_authorize(&third, 1, "rfkill", "list") == MEOW_OK);
|
||
/* 写级:only 系统身份 + meow 模式 */
|
||
CHECK(wifi_write_authorize(&sys, 1, "on", NULL) == MEOW_OK);
|
||
CHECK(wifi_write_authorize(&pkgm, 1, "connect", "ssid") == MEOW_OK);
|
||
CHECK(bt_write_authorize(&sys, 1, "off") == MEOW_OK);
|
||
CHECK(wifi_write_authorize(&third, 1, "scan", NULL) == MEOW_ERR_PERM); /* 第三方包 → 拒 */
|
||
CHECK(wifi_write_authorize(&other, 1, "on", NULL) == MEOW_ERR_PERM); /* CALL_OTHER + uid → 拒 */
|
||
CHECK(wifi_write_authorize(&sys, 0, "on", NULL) == MEOW_ERR_PERM); /* HibyOS 只读 → 拒 */
|
||
CHECK(bt_write_authorize(&sys, 0, "on") == MEOW_ERR_PERM); /* HibyOS 只读 → 拒 */
|
||
CHECK(bt_write_authorize(&pkgm, 1, "off") == MEOW_OK);
|
||
|
||
printf("== 接口层动作(假 sysfs + 桩命令)==\n");
|
||
/* 搭假 /sys/class/net + rfkill + bt(先建祖先目录) */
|
||
mkdir(T, 0755);
|
||
snprintf(p, sizeof p, "%s/net", T); mkdir(p, 0755);
|
||
snprintf(p, sizeof p, "%s/net/lo", T); mkdir(p, 0755);
|
||
snprintf(p, sizeof p, "%s/net/wlan0", T); mkdir(p, 0755);
|
||
snprintf(p, sizeof p, "%s/rfkill", T); mkdir(p, 0755);
|
||
snprintf(p, sizeof p, "%s/rfkill/rfkill0", T); mkdir(p, 0755);
|
||
snprintf(p, sizeof p, "%s/bt", T); mkdir(p, 0755);
|
||
snprintf(p, sizeof p, "%s/bt/hci0", T); mkdir(p, 0755);
|
||
snprintf(p, sizeof p, "%s/net/lo/operstate", T); wf(p, "up\n");
|
||
snprintf(p, sizeof p, "%s/net/wlan0/operstate", T); wf(p, "up\n");
|
||
snprintf(p, sizeof p, "%s/rfkill/rfkill0/type", T); wf(p, "wlan\n");
|
||
snprintf(p, sizeof p, "%s/rfkill/rfkill0/soft", T); wf(p, "0\n");
|
||
snprintf(p, sizeof p, "%s/rfkill/rfkill0/hard", T); wf(p, "0\n");
|
||
snprintf(p, sizeof p, "%s/bt/hci0/address", T); wf(p, "00:1A:7D:DA:71:13\n");
|
||
snprintf(p, sizeof p, "%s/bt/hci0/power", T); wf(p, "on\n");
|
||
snprintf(p, sizeof p, "%s/netdev", T); wf(p, "Inter-| Receive | Transmit\n lo: 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0\n wlan0: 5000000 5000 0 0 0 0 0 0 1000000 1000 0 0 0 0 0 0\n");
|
||
snprintf(p, sizeof p, "%s/route", T); wf(p, "Iface\tDestination\tGateway \tFlags\nwlan0\t005EC20A\t6F3DC20A\t0003\nlo\t0100007F\t00000000\t0001\n");
|
||
snprintf(p, sizeof p, "%s/resolv", T); wf(p, "nameserver 223.5.5.5\nnameserver 10.78.193.1\n");
|
||
snprintf(p, sizeof p, "%s/boot_mode", T); wf(p, "meow\n");
|
||
/* 桩工具 */
|
||
snprintf(p, sizeof p, "%s/wpa_cli", T); wf(p,
|
||
"#!/bin/sh\n"
|
||
"case \"$1\" in\n"
|
||
" status) echo 'wpa_state=COMPLETED'; echo 'ssid=MyWiFi'; echo 'ip_address=10.78.193.50'; echo 'signal=-45';;\n"
|
||
" scan) echo OK;;\n"
|
||
" scan_results) echo 'bssid / frequency / signal / flags / ssid'; echo 'xx:xx / 2412 / -50 / WPA2 / TestAP';;\n"
|
||
" list_networks) echo 'network id / ssid / bssid / flags'; echo '0\tMyWiFi\tany\t[CURRENT]';;\n"
|
||
" add_network) echo 5;;\n"
|
||
" set_network) echo OK;;\n"
|
||
" enable_network) echo OK;;\n"
|
||
" select_network) echo OK;;\n"
|
||
" disconnect) echo OK;;\n"
|
||
"esac\n"
|
||
"exit 0\n");
|
||
snprintf(p, sizeof p, "%s/hciconfig", T); wf(p,
|
||
"#!/bin/sh\n"
|
||
"echo 'hci0: Type: Primary Bus: USB'\n"
|
||
"echo ' BD Address: 00:1A:7D:DA:71:13 ACL MTU: 1021:8'\n"
|
||
"echo ' UP RUNNING PSCAN'\n");
|
||
snprintf(p, sizeof p, "%s/bluetoothctl", T); wf(p,
|
||
"#!/bin/sh\n"
|
||
"echo 'Device 00:1A:7D:DA:71:13 My Headset'\n"
|
||
"echo 'Device 11:22:33:44:55:66 Speaker'\n");
|
||
snprintf(p, sizeof p, "%s/ip", T); wf(p,
|
||
"#!/bin/sh\n"
|
||
"if [ \"$6\" = \"wlan0\" ]; then echo \"2: wlan0 inet 10.78.193.50/24 brd 255.255.255.255 scope global wlan0\"; fi\n"
|
||
"exit 0\n");
|
||
snprintf(p, sizeof p, "%s/wpa_cli", T); chmod(p, 0755);
|
||
snprintf(p, sizeof p, "%s/hciconfig", T); chmod(p, 0755);
|
||
snprintf(p, sizeof p, "%s/bluetoothctl", T); chmod(p, 0755);
|
||
snprintf(p, sizeof p, "%s/ip", T); chmod(p, 0755);
|
||
|
||
g_net_dir[0] = 0; snprintf(g_net_dir, sizeof g_net_dir, "%s/net", T);
|
||
g_netdev[0] = 0; snprintf(g_netdev, sizeof g_netdev, "%s/netdev", T);
|
||
g_net_route[0] = 0; snprintf(g_net_route, sizeof g_net_route, "%s/route", T);
|
||
g_resolv[0] = 0; snprintf(g_resolv, sizeof g_resolv, "%s/resolv", T);
|
||
g_rfkill_dir[0] = 0; snprintf(g_rfkill_dir, sizeof g_rfkill_dir, "%s/rfkill", T);
|
||
g_bt_dir[0] = 0; snprintf(g_bt_dir, sizeof g_bt_dir, "%s/bt", T);
|
||
g_boot_mode[0] = 0; snprintf(g_boot_mode, sizeof g_boot_mode, "%s/boot_mode", T);
|
||
g_wpa_cli = ""; { char x[160]; snprintf(x, sizeof x, "%s/wpa_cli", T); static char wc[160]; snprintf(wc, sizeof wc, "%s", x); g_wpa_cli = wc; }
|
||
g_hciconfig = ""; { char x[160]; snprintf(x, sizeof x, "%s/hciconfig", T); static char hc[160]; snprintf(hc, sizeof hc, "%s", x); g_hciconfig = hc; }
|
||
g_bluetoothctl = ""; { char x[160]; snprintf(x, sizeof x, "%s/bluetoothctl", T); static char bc[160]; snprintf(bc, sizeof bc, "%s", x); g_bluetoothctl = bc; }
|
||
g_ip = ""; { char x[160]; snprintf(x, sizeof x, "%s/ip", T); static char ip[160]; snprintf(ip, sizeof ip, "%s", x); g_ip = ip; }
|
||
|
||
/* rfkill_set_block:wlan → soft=1 */
|
||
CHECK(rfkill_set_block("wlan", 1) == 0);
|
||
snprintf(p, sizeof p, "%s/rfkill/rfkill0/soft", T);
|
||
char rb[8]; read_file_txt(p, rb, sizeof rb);
|
||
CHECK(strcmp(rb, "1") == 0);
|
||
|
||
/* enum_ifaces(detail=1):ip/gw/rx/tx */
|
||
enum_ifaces(1);
|
||
CHECK(g_iface_n >= 2);
|
||
int wlan = -1;
|
||
for (int i = 0; i < g_iface_n; i++) if (!strcmp(g_ifaces[i].name, "wlan0")) wlan = i;
|
||
CHECK(wlan >= 0);
|
||
CHECK(strcmp(g_ifaces[wlan].kind, "wifi") == 0);
|
||
CHECK(g_ifaces[wlan].up == 1);
|
||
CHECK(strcmp(g_ifaces[wlan].gw, "10.194.61.111") == 0); /* 0x6F3DC20A LE → 10.194.61.111 */
|
||
CHECK(g_ifaces[wlan].rx == 5000000);
|
||
|
||
/* wifi_networks(读) + wifi_scan(写执行路径) */
|
||
ctl_result_t r;
|
||
wifi_networks(&r);
|
||
CHECK(r.code == MEOW_OK && strstr(r.text, "MyWiFi") != NULL);
|
||
wifi_scan(&r);
|
||
CHECK(r.code == MEOW_OK && strstr(r.text, "TestAP") != NULL);
|
||
|
||
/* bt_status:available=1 powered=1 address=... paired=2 */
|
||
bt_t b;
|
||
bt_status(&b);
|
||
CHECK(b.available == 1 && b.powered == 1);
|
||
CHECK(strcmp(b.address, "00:1A:7D:DA:71:13") == 0);
|
||
CHECK(b.paired_n == 2);
|
||
|
||
/* 写级执行(wifi_onoff off → rfkill block wlan)已在 rfkill_set_block 覆盖;此处联调 wifi_ctl_execute */
|
||
wifi_ctl_execute("networks", NULL, &r);
|
||
CHECK(r.code == MEOW_OK && strstr(r.text, "MyWiFi") != NULL);
|
||
/* connect:现有 ssid 复用(enable+select,network_id=0);新 ssid 走 add/set/enable/select(id=5)。 */
|
||
wifi_ctl_execute("connect", "MyWiFi", &r);
|
||
CHECK(r.code == MEOW_OK && strstr(r.text, "ssid=MyWiFi") != NULL && strstr(r.text, "network_id=0") != NULL);
|
||
wifi_ctl_execute("connect", "NewAP,secret", &r);
|
||
CHECK(r.code == MEOW_OK && strstr(r.text, "ssid=NewAP") != NULL && strstr(r.text, "network_id=5") != NULL);
|
||
wifi_ctl_execute("disconnect", NULL, &r);
|
||
CHECK(r.code == MEOW_OK);
|
||
|
||
if (g_fail) { printf("\nNETMGR AUTH TEST: %d FAIL\n", g_fail); return 1; }
|
||
printf("\nNETMGR AUTH TEST: ALL PASS\n");
|
||
return 0;
|
||
}
|