fsp-server: implement GET_PRO (0x47), which Swiss asks for first
Swiss sent CC_GET_PRO 'swiss/patches' and the server replied "unsupported".
Reply shape, from fsplib's fsp_getpro:
* pos MUST equal FSP_PRO_BYTES (1), or fsplib fails with ENOMSG
* the flags byte is at buf[len] -- the first byte of the EXTRA region,
after the echoed name, NOT inside the data field
* a missing directory must be CC_ERR so fsplib reports ENOENT, because
Swiss probes "swiss/patches", then "swiss", then "" and relies on that
fallback chain
Those bits are not cosmetic. deviceHandler-FSP.c does:
if ((pro & (MKDIR|ADD|DEL|GET)) == (MKDIR|ADD|DEL) || (pro & OWNER)) {
features |= FEAT_PATCHES; emulable |= EMU_ETHERNET;
} else { ... clears both ... }
so a plain read-only answer makes Swiss DISABLE patch support on this device.
Default is therefore the honest GET|LIST (0x50) with patches disabled, and
--claim-owner reports OWNER to turn them back on -- flagged in the help as
unsafe for now, because this server has no UP_LOAD or MAKE_DIR, so Swiss
believing it can write here would make a patch write fail rather than degrade.
Try without it first.
T9 checks pos == 1 and that the flags land at buf[len] with GET|LIST and
without OWNER; T10 checks a missing directory gives CC_ERR so the fallback
chain works.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -124,6 +124,36 @@ try:
|
||||
fails.append(f"T8 traversal escaped the root: type {ty} size {sz}")
|
||||
else:
|
||||
print("T8 ../../etc/passwd refused")
|
||||
# T9 GET_PRO: flags go in the EXTRA region at buf[len], and pos must
|
||||
# equal FSP_PRO_BYTES (1) or fsplib returns ENOMSG.
|
||||
CC_GET_PRO = 0x47
|
||||
r = rt(req(CC_GET_PRO, 20, 0, ""))
|
||||
if r["cmd"] != CC_GET_PRO:
|
||||
fails.append(f"T9 GET_PRO cmd {r['cmd']:#04x}")
|
||||
elif r["pos"] != 1:
|
||||
fails.append(f"T9 GET_PRO pos {r['pos']}, want 1 (FSP_PRO_BYTES) "
|
||||
f"- fsplib returns ENOMSG otherwise")
|
||||
else:
|
||||
s.sendto(req(CC_GET_PRO, 21, 0, ""), A)
|
||||
raw = s.recv(2048)
|
||||
ln = struct.unpack("!H", raw[8:10])[0]
|
||||
pro = raw[HSIZE + ln] # buf[len] -- the first extra byte
|
||||
if not (pro & 0x10) or not (pro & 0x40):
|
||||
fails.append(f"T9 GET_PRO flags {pro:#04x} lack GET|LIST")
|
||||
elif pro & 0x01:
|
||||
fails.append(f"T9 GET_PRO claims OWNER without --claim-owner")
|
||||
else:
|
||||
print(f"T9 GET_PRO -> pos=1, flags {pro:#04x} (GET|LIST) at buf[len]")
|
||||
|
||||
# T10 a missing directory must be CC_ERR, so fsplib reports ENOENT and
|
||||
# Swiss falls back from "swiss/patches" to "swiss" to "".
|
||||
r = rt(req(CC_GET_PRO, 22, 0, "swiss/patches"))
|
||||
if r["cmd"] != CC_ERR:
|
||||
fails.append(f"T10 GET_PRO on a missing dir returned {r['cmd']:#04x}, "
|
||||
f"want CC_ERR -- Swiss's fallback chain needs ENOENT")
|
||||
else:
|
||||
print("T10 GET_PRO 'swiss/patches' -> CC_ERR (Swiss falls back to root)")
|
||||
|
||||
finally:
|
||||
srv.terminate()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user