nx_iot_sc_broadcast.nx source
↩ module page · 90 lines · 3946 B
1// nx_iot_sc_broadcast.nx -- SOVEREIGN ESP-Touch v1 BROADCASTER (R1b-live). Sends the U8 length
2// sequence from nx_iot_smartconfig as real UDP packets so a Tuya/ESP device in pairing mode sniffs
3// the Wi-Fi creds off the 2.4GHz air. NO app, NO Windows tooling on the program path.
4//
5// Mechanism (verified from sovereignly-fetched Espressif source, knowledge/fetched/sc_java_*.raw):
6// - each U8 length L -> one UDP packet whose PAYLOAD is L bytes of '1' (ByteUtil.genSpecBytes:
7// `byte[] data=new byte[len]; for(i) data[i]='1';` -- only the LENGTH carries data)
8// - device sniffs in promiscuous mode (sc_idf_device.raw) so the dest addr only has to put the
9// frame on the air: multicast 234.x:7001 or broadcast 255.255.255.255 both work
10// - send the 4 guide lengths repeatedly until the device locks, then loop the datum block
11//
12// Sockets via nx_syscalls.nx (the @ifdef TARGET_X86_64 path: SYS_SOCKET=41/SYS_SENDTO=44 -- the
13// WORKING path; nx_syscalls_x86_64.nx's socket() dies with ENOSYS in WSL). Runs on any x86_64 Linux
14// host that can transmit on the 2.4GHz (NishiOS box on the IoT SSID, or a Wi-Fi-client rung). The
15// ARM router has no Nishi backend yet -> that deployment seam is documented, not faked.
16// NEVER-BRICK #26: emits reversible Wi-Fi creds only; no firmware write. license_tier: ORIGINAL
17import "nx_syscalls.nx"
18import "nx_iot_smartconfig.nx"
19const SO_MAGIC_1024: i64 = 1024
20
21const SO_BROADCAST: i64 = 6
22
23// genSpecBytes(L): payload of L bytes, all '1' (0x31). Verified byte-exact vs ByteUtil.genSpecBytes.
24func nx_sc_genspec(buf: *u8, len: i64) -> i64 {
25 var i: i64 = 0
26 while i < len { buf[i] = 0x31 as u8; i = i + 1 }
27 return len
28}
29
30// Build a 16-byte sockaddr_in: family AF_INET, port (big-endian), addr a.b.c.d (network order), sin_zero.
31func nx_sc_sockaddr(sa: *u8, a: i64, b: i64, c: i64, d: i64, port: i64) -> i64 {
32 sa[0] = (AF_INET & 0xff) as u8
33 sa[1] = ((AF_INET >> 8) & 0xff) as u8
34 sa[2] = ((port >> 8) & 0xff) as u8
35 sa[3] = (port & 0xff) as u8
36 sa[4] = a as u8
37 sa[5] = b as u8
38 sa[6] = c as u8
39 sa[7] = d as u8
40 var i: i64 = 8
41 while i < 16 { sa[i] = 0 as u8; i = i + 1 }
42 return 16
43}
44
45// Open a UDP socket with SO_BROADCAST enabled (so 255.255.255.255 works); returns fd or <0.
46func nx_sc_open() -> i64 {
47 let fd: i64 = sys_socket(AF_INET, SOCK_DGRAM, 0)
48 if fd < 0 { return fd }
49 let one: *i64 = sys_mmap(8) as *i64
50 one[0] = 1
51 sys_setsockopt(fd, SOL_SOCKET, SO_BROADCAST, one as *u8, 4)
52 return fd
53}
54
55// Send one packet of length L (payload = '1'*L) to sa. Returns sys_sendto result (L on success).
56func nx_sc_send_one(fd: i64, sa: *u8, scratch: *u8, len: i64) -> i64 {
57 nx_sc_genspec(scratch, len)
58 return sys_sendto(fd, scratch, len, 0, sa, 16)
59}
60
61// Broadcast the full ESP-Touch sequence to a.b.c.d:port: guide block x guide_reps, then datum block
62// x datum_reps. Returns total packets sent (>=0), or negative on encode/socket failure.
63func nx_sc_broadcast(ssid: *u8, ssid_n: i64, bssid: *u8, pwd: *u8, pwd_n: i64, ip: *u8,
64 a: i64, b: i64, c: i64, d: i64, port: i64,
65 guide_reps: i64, datum_reps: i64) -> i64 {
66 let u8s: *i64 = sys_mmap(512 * 8) as *i64
67 let n: i64 = nx_sc_encode(ssid, ssid_n, bssid, pwd, pwd_n, ip, u8s, 512)
68 if n < 0 { return 0 - 2 }
69 let fd: i64 = nx_sc_open()
70 if fd < 0 { return 0 - 3 }
71 let sa: *u8 = sys_mmap(16)
72 nx_sc_sockaddr(sa, a, b, c, d, port)
73 let scratch: *u8 = sys_mmap(SO_MAGIC_1024)
74 var sent: i64 = 0
75
76 var r: i64 = 0
77 while r < guide_reps {
78 var i: i64 = 0
79 while i < 4 { nx_sc_send_one(fd, sa, scratch, u8s[i]); sent = sent + 1; i = i + 1 }
80 r = r + 1
81 }
82 r = 0
83 while r < datum_reps {
84 var j: i64 = 4
85 while j < n { nx_sc_send_one(fd, sa, scratch, u8s[j]); sent = sent + 1; j = j + 1 }
86 r = r + 1
87 }
88 sys_close(fd)
89 return sent
90}