mirror of
https://github.com/Kpa-clawbot/meshcore-analyzer.git
synced 2026-03-30 18:15:47 +00:00
Compare commits
1 Commits
fix/packet
...
fix/go-pac
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
db1122ef4b |
@@ -72,8 +72,8 @@ type Header struct {
|
|||||||
|
|
||||||
// TransportCodes are present on TRANSPORT_FLOOD and TRANSPORT_DIRECT routes.
|
// TransportCodes are present on TRANSPORT_FLOOD and TRANSPORT_DIRECT routes.
|
||||||
type TransportCodes struct {
|
type TransportCodes struct {
|
||||||
NextHop string `json:"nextHop"`
|
Code1 string `json:"code1"`
|
||||||
LastHop string `json:"lastHop"`
|
Code2 string `json:"code2"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Path holds decoded path/hop information.
|
// Path holds decoded path/hop information.
|
||||||
@@ -92,6 +92,8 @@ type AdvertFlags struct {
|
|||||||
Room bool `json:"room"`
|
Room bool `json:"room"`
|
||||||
Sensor bool `json:"sensor"`
|
Sensor bool `json:"sensor"`
|
||||||
HasLocation bool `json:"hasLocation"`
|
HasLocation bool `json:"hasLocation"`
|
||||||
|
HasFeat1 bool `json:"hasFeat1"`
|
||||||
|
HasFeat2 bool `json:"hasFeat2"`
|
||||||
HasName bool `json:"hasName"`
|
HasName bool `json:"hasName"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,6 +113,8 @@ type Payload struct {
|
|||||||
Lat *float64 `json:"lat,omitempty"`
|
Lat *float64 `json:"lat,omitempty"`
|
||||||
Lon *float64 `json:"lon,omitempty"`
|
Lon *float64 `json:"lon,omitempty"`
|
||||||
Name string `json:"name,omitempty"`
|
Name string `json:"name,omitempty"`
|
||||||
|
Feat1 *int `json:"feat1,omitempty"`
|
||||||
|
Feat2 *int `json:"feat2,omitempty"`
|
||||||
BatteryMv *int `json:"battery_mv,omitempty"`
|
BatteryMv *int `json:"battery_mv,omitempty"`
|
||||||
TemperatureC *float64 `json:"temperature_c,omitempty"`
|
TemperatureC *float64 `json:"temperature_c,omitempty"`
|
||||||
ChannelHash int `json:"channelHash,omitempty"`
|
ChannelHash int `json:"channelHash,omitempty"`
|
||||||
@@ -123,6 +127,8 @@ type Payload struct {
|
|||||||
EphemeralPubKey string `json:"ephemeralPubKey,omitempty"`
|
EphemeralPubKey string `json:"ephemeralPubKey,omitempty"`
|
||||||
PathData string `json:"pathData,omitempty"`
|
PathData string `json:"pathData,omitempty"`
|
||||||
Tag uint32 `json:"tag,omitempty"`
|
Tag uint32 `json:"tag,omitempty"`
|
||||||
|
AuthCode uint32 `json:"authCode,omitempty"`
|
||||||
|
TraceFlags *int `json:"traceFlags,omitempty"`
|
||||||
RawHex string `json:"raw,omitempty"`
|
RawHex string `json:"raw,omitempty"`
|
||||||
Error string `json:"error,omitempty"`
|
Error string `json:"error,omitempty"`
|
||||||
}
|
}
|
||||||
@@ -199,14 +205,13 @@ func decodeEncryptedPayload(typeName string, buf []byte) Payload {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func decodeAck(buf []byte) Payload {
|
func decodeAck(buf []byte) Payload {
|
||||||
if len(buf) < 6 {
|
if len(buf) < 4 {
|
||||||
return Payload{Type: "ACK", Error: "too short", RawHex: hex.EncodeToString(buf)}
|
return Payload{Type: "ACK", Error: "too short", RawHex: hex.EncodeToString(buf)}
|
||||||
}
|
}
|
||||||
|
checksum := binary.LittleEndian.Uint32(buf[0:4])
|
||||||
return Payload{
|
return Payload{
|
||||||
Type: "ACK",
|
Type: "ACK",
|
||||||
DestHash: hex.EncodeToString(buf[0:1]),
|
ExtraHash: fmt.Sprintf("%08x", checksum),
|
||||||
SrcHash: hex.EncodeToString(buf[1:2]),
|
|
||||||
ExtraHash: hex.EncodeToString(buf[2:6]),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -231,6 +236,8 @@ func decodeAdvert(buf []byte) Payload {
|
|||||||
if len(appdata) > 0 {
|
if len(appdata) > 0 {
|
||||||
flags := appdata[0]
|
flags := appdata[0]
|
||||||
advType := int(flags & 0x0F)
|
advType := int(flags & 0x0F)
|
||||||
|
hasFeat1 := flags&0x20 != 0
|
||||||
|
hasFeat2 := flags&0x40 != 0
|
||||||
p.Flags = &AdvertFlags{
|
p.Flags = &AdvertFlags{
|
||||||
Raw: int(flags),
|
Raw: int(flags),
|
||||||
Type: advType,
|
Type: advType,
|
||||||
@@ -239,6 +246,8 @@ func decodeAdvert(buf []byte) Payload {
|
|||||||
Room: advType == 3,
|
Room: advType == 3,
|
||||||
Sensor: advType == 4,
|
Sensor: advType == 4,
|
||||||
HasLocation: flags&0x10 != 0,
|
HasLocation: flags&0x10 != 0,
|
||||||
|
HasFeat1: hasFeat1,
|
||||||
|
HasFeat2: hasFeat2,
|
||||||
HasName: flags&0x80 != 0,
|
HasName: flags&0x80 != 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -252,6 +261,16 @@ func decodeAdvert(buf []byte) Payload {
|
|||||||
p.Lon = &lon
|
p.Lon = &lon
|
||||||
off += 8
|
off += 8
|
||||||
}
|
}
|
||||||
|
if hasFeat1 && len(appdata) >= off+2 {
|
||||||
|
feat1 := int(binary.LittleEndian.Uint16(appdata[off : off+2]))
|
||||||
|
p.Feat1 = &feat1
|
||||||
|
off += 2
|
||||||
|
}
|
||||||
|
if hasFeat2 && len(appdata) >= off+2 {
|
||||||
|
feat2 := int(binary.LittleEndian.Uint16(appdata[off : off+2]))
|
||||||
|
p.Feat2 = &feat2
|
||||||
|
off += 2
|
||||||
|
}
|
||||||
if p.Flags.HasName {
|
if p.Flags.HasName {
|
||||||
// Find null terminator to separate name from trailing telemetry bytes
|
// Find null terminator to separate name from trailing telemetry bytes
|
||||||
nameEnd := len(appdata)
|
nameEnd := len(appdata)
|
||||||
@@ -469,15 +488,22 @@ func decodePathPayload(buf []byte) Payload {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func decodeTrace(buf []byte) Payload {
|
func decodeTrace(buf []byte) Payload {
|
||||||
if len(buf) < 12 {
|
if len(buf) < 9 {
|
||||||
return Payload{Type: "TRACE", Error: "too short", RawHex: hex.EncodeToString(buf)}
|
return Payload{Type: "TRACE", Error: "too short", RawHex: hex.EncodeToString(buf)}
|
||||||
}
|
}
|
||||||
return Payload{
|
tag := binary.LittleEndian.Uint32(buf[0:4])
|
||||||
Type: "TRACE",
|
authCode := binary.LittleEndian.Uint32(buf[4:8])
|
||||||
DestHash: hex.EncodeToString(buf[5:11]),
|
flags := int(buf[8])
|
||||||
SrcHash: hex.EncodeToString(buf[11:12]),
|
p := Payload{
|
||||||
Tag: binary.LittleEndian.Uint32(buf[1:5]),
|
Type: "TRACE",
|
||||||
|
Tag: tag,
|
||||||
|
AuthCode: authCode,
|
||||||
|
TraceFlags: &flags,
|
||||||
}
|
}
|
||||||
|
if len(buf) > 9 {
|
||||||
|
p.PathData = hex.EncodeToString(buf[9:])
|
||||||
|
}
|
||||||
|
return p
|
||||||
}
|
}
|
||||||
|
|
||||||
func decodePayload(payloadType int, buf []byte, channelKeys map[string]string) Payload {
|
func decodePayload(payloadType int, buf []byte, channelKeys map[string]string) Payload {
|
||||||
@@ -520,8 +546,7 @@ func DecodePacket(hexString string, channelKeys map[string]string) (*DecodedPack
|
|||||||
}
|
}
|
||||||
|
|
||||||
header := decodeHeader(buf[0])
|
header := decodeHeader(buf[0])
|
||||||
pathByte := buf[1]
|
offset := 1
|
||||||
offset := 2
|
|
||||||
|
|
||||||
var tc *TransportCodes
|
var tc *TransportCodes
|
||||||
if isTransportRoute(header.RouteType) {
|
if isTransportRoute(header.RouteType) {
|
||||||
@@ -529,12 +554,18 @@ func DecodePacket(hexString string, channelKeys map[string]string) (*DecodedPack
|
|||||||
return nil, fmt.Errorf("packet too short for transport codes")
|
return nil, fmt.Errorf("packet too short for transport codes")
|
||||||
}
|
}
|
||||||
tc = &TransportCodes{
|
tc = &TransportCodes{
|
||||||
NextHop: strings.ToUpper(hex.EncodeToString(buf[offset : offset+2])),
|
Code1: strings.ToUpper(hex.EncodeToString(buf[offset : offset+2])),
|
||||||
LastHop: strings.ToUpper(hex.EncodeToString(buf[offset+2 : offset+4])),
|
Code2: strings.ToUpper(hex.EncodeToString(buf[offset+2 : offset+4])),
|
||||||
}
|
}
|
||||||
offset += 4
|
offset += 4
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if offset >= len(buf) {
|
||||||
|
return nil, fmt.Errorf("packet too short (no path byte)")
|
||||||
|
}
|
||||||
|
pathByte := buf[offset]
|
||||||
|
offset++
|
||||||
|
|
||||||
path, bytesConsumed := decodePath(pathByte, buf, offset)
|
path, bytesConsumed := decodePath(pathByte, buf, offset)
|
||||||
offset += bytesConsumed
|
offset += bytesConsumed
|
||||||
|
|
||||||
@@ -562,16 +593,24 @@ func ComputeContentHash(rawHex string) string {
|
|||||||
return rawHex
|
return rawHex
|
||||||
}
|
}
|
||||||
|
|
||||||
pathByte := buf[1]
|
headerByte := buf[0]
|
||||||
|
offset := 1
|
||||||
|
if isTransportRoute(int(headerByte & 0x03)) {
|
||||||
|
offset += 4
|
||||||
|
}
|
||||||
|
if offset >= len(buf) {
|
||||||
|
if len(rawHex) >= 16 {
|
||||||
|
return rawHex[:16]
|
||||||
|
}
|
||||||
|
return rawHex
|
||||||
|
}
|
||||||
|
pathByte := buf[offset]
|
||||||
|
offset++
|
||||||
hashSize := int((pathByte>>6)&0x3) + 1
|
hashSize := int((pathByte>>6)&0x3) + 1
|
||||||
hashCount := int(pathByte & 0x3F)
|
hashCount := int(pathByte & 0x3F)
|
||||||
pathBytes := hashSize * hashCount
|
pathBytes := hashSize * hashCount
|
||||||
|
|
||||||
headerByte := buf[0]
|
payloadStart := offset + pathBytes
|
||||||
payloadStart := 2 + pathBytes
|
|
||||||
if isTransportRoute(int(headerByte & 0x03)) {
|
|
||||||
payloadStart += 4
|
|
||||||
}
|
|
||||||
if payloadStart > len(buf) {
|
if payloadStart > len(buf) {
|
||||||
if len(rawHex) >= 16 {
|
if len(rawHex) >= 16 {
|
||||||
return rawHex[:16]
|
return rawHex[:16]
|
||||||
|
|||||||
@@ -129,7 +129,8 @@ func TestDecodePath3ByteHashes(t *testing.T) {
|
|||||||
|
|
||||||
func TestTransportCodes(t *testing.T) {
|
func TestTransportCodes(t *testing.T) {
|
||||||
// Route type 0 (TRANSPORT_FLOOD) should have transport codes
|
// Route type 0 (TRANSPORT_FLOOD) should have transport codes
|
||||||
hex := "1400" + "AABB" + "CCDD" + "1A" + strings.Repeat("00", 10)
|
// Firmware order: header + transport_codes(4) + path_len + path + payload
|
||||||
|
hex := "14" + "AABB" + "CCDD" + "00" + strings.Repeat("00", 10)
|
||||||
pkt, err := DecodePacket(hex, nil)
|
pkt, err := DecodePacket(hex, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@@ -140,11 +141,11 @@ func TestTransportCodes(t *testing.T) {
|
|||||||
if pkt.TransportCodes == nil {
|
if pkt.TransportCodes == nil {
|
||||||
t.Fatal("transportCodes should not be nil for TRANSPORT_FLOOD")
|
t.Fatal("transportCodes should not be nil for TRANSPORT_FLOOD")
|
||||||
}
|
}
|
||||||
if pkt.TransportCodes.NextHop != "AABB" {
|
if pkt.TransportCodes.Code1 != "AABB" {
|
||||||
t.Errorf("nextHop=%s, want AABB", pkt.TransportCodes.NextHop)
|
t.Errorf("code1=%s, want AABB", pkt.TransportCodes.Code1)
|
||||||
}
|
}
|
||||||
if pkt.TransportCodes.LastHop != "CCDD" {
|
if pkt.TransportCodes.Code2 != "CCDD" {
|
||||||
t.Errorf("lastHop=%s, want CCDD", pkt.TransportCodes.LastHop)
|
t.Errorf("code2=%s, want CCDD", pkt.TransportCodes.Code2)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Route type 1 (FLOOD) should NOT have transport codes
|
// Route type 1 (FLOOD) should NOT have transport codes
|
||||||
@@ -537,10 +538,11 @@ func TestDecodeTraceShort(t *testing.T) {
|
|||||||
|
|
||||||
func TestDecodeTraceValid(t *testing.T) {
|
func TestDecodeTraceValid(t *testing.T) {
|
||||||
buf := make([]byte, 16)
|
buf := make([]byte, 16)
|
||||||
buf[0] = 0x00
|
// tag(4) + authCode(4) + flags(1) + pathData
|
||||||
buf[1] = 0x01 // tag LE uint32 = 1
|
binary.LittleEndian.PutUint32(buf[0:4], 1) // tag = 1
|
||||||
buf[5] = 0xAA // destHash start
|
binary.LittleEndian.PutUint32(buf[4:8], 0xDEADBEEF) // authCode
|
||||||
buf[11] = 0xBB
|
buf[8] = 0x02 // flags
|
||||||
|
buf[9] = 0xAA // path data
|
||||||
p := decodeTrace(buf)
|
p := decodeTrace(buf)
|
||||||
if p.Error != "" {
|
if p.Error != "" {
|
||||||
t.Errorf("unexpected error: %s", p.Error)
|
t.Errorf("unexpected error: %s", p.Error)
|
||||||
@@ -548,9 +550,18 @@ func TestDecodeTraceValid(t *testing.T) {
|
|||||||
if p.Tag != 1 {
|
if p.Tag != 1 {
|
||||||
t.Errorf("tag=%d, want 1", p.Tag)
|
t.Errorf("tag=%d, want 1", p.Tag)
|
||||||
}
|
}
|
||||||
|
if p.AuthCode != 0xDEADBEEF {
|
||||||
|
t.Errorf("authCode=%d, want 0xDEADBEEF", p.AuthCode)
|
||||||
|
}
|
||||||
|
if p.TraceFlags == nil || *p.TraceFlags != 2 {
|
||||||
|
t.Errorf("traceFlags=%v, want 2", p.TraceFlags)
|
||||||
|
}
|
||||||
if p.Type != "TRACE" {
|
if p.Type != "TRACE" {
|
||||||
t.Errorf("type=%s, want TRACE", p.Type)
|
t.Errorf("type=%s, want TRACE", p.Type)
|
||||||
}
|
}
|
||||||
|
if p.PathData == "" {
|
||||||
|
t.Error("pathData should not be empty")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDecodeAdvertShort(t *testing.T) {
|
func TestDecodeAdvertShort(t *testing.T) {
|
||||||
@@ -833,10 +844,9 @@ func TestComputeContentHashShortHex(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestComputeContentHashTransportRoute(t *testing.T) {
|
func TestComputeContentHashTransportRoute(t *testing.T) {
|
||||||
// Route type 0 (TRANSPORT_FLOOD) with no path hops + 4 transport code bytes
|
// Route type 0 (TRANSPORT_FLOOD) with transport codes then path=0x00 (0 hops)
|
||||||
// header=0x14 (TRANSPORT_FLOOD, ADVERT), path=0x00 (0 hops)
|
// header=0x14 (TRANSPORT_FLOOD, ADVERT), transport(4), path=0x00
|
||||||
// transport codes = 4 bytes, then payload
|
hex := "14" + "AABBCCDD" + "00" + strings.Repeat("EE", 10)
|
||||||
hex := "1400" + "AABBCCDD" + strings.Repeat("EE", 10)
|
|
||||||
hash := ComputeContentHash(hex)
|
hash := ComputeContentHash(hex)
|
||||||
if len(hash) != 16 {
|
if len(hash) != 16 {
|
||||||
t.Errorf("hash length=%d, want 16", len(hash))
|
t.Errorf("hash length=%d, want 16", len(hash))
|
||||||
@@ -870,12 +880,10 @@ func TestComputeContentHashPayloadBeyondBufferLongHex(t *testing.T) {
|
|||||||
|
|
||||||
func TestComputeContentHashTransportBeyondBuffer(t *testing.T) {
|
func TestComputeContentHashTransportBeyondBuffer(t *testing.T) {
|
||||||
// Transport route (0x00 = TRANSPORT_FLOOD) with path claiming some bytes
|
// Transport route (0x00 = TRANSPORT_FLOOD) with path claiming some bytes
|
||||||
// total buffer too short for transport codes + path
|
// header=0x00, transport(4), pathByte=0x02 (2 hops, 1-byte hash)
|
||||||
// header=0x00, pathByte=0x02 (2 hops, 1-byte hash), then only 2 more bytes
|
// offset=1+4+1+2=8, buffer needs to be >= 8
|
||||||
// payloadStart = 2 + 2 + 4(transport) = 8, but buffer only 6 bytes
|
hex := "00" + "AABB" + "CCDD" + "02" + strings.Repeat("CC", 6) // 20 chars = 10 bytes
|
||||||
hex := "0002" + "AABB" + strings.Repeat("CC", 6) // 20 chars = 10 bytes
|
|
||||||
hash := ComputeContentHash(hex)
|
hash := ComputeContentHash(hex)
|
||||||
// payloadStart = 2 + 2 + 4 = 8, buffer is 10 bytes → should work
|
|
||||||
if len(hash) != 16 {
|
if len(hash) != 16 {
|
||||||
t.Errorf("hash length=%d, want 16", len(hash))
|
t.Errorf("hash length=%d, want 16", len(hash))
|
||||||
}
|
}
|
||||||
@@ -913,8 +921,8 @@ func TestDecodePacketWithNewlines(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestDecodePacketTransportRouteTooShort(t *testing.T) {
|
func TestDecodePacketTransportRouteTooShort(t *testing.T) {
|
||||||
// TRANSPORT_FLOOD (route=0) but only 3 bytes total → too short for transport codes
|
// TRANSPORT_FLOOD (route=0) but only 2 bytes total → too short for transport codes
|
||||||
_, err := DecodePacket("140011", nil)
|
_, err := DecodePacket("1400", nil)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Error("expected error for transport route with too-short buffer")
|
t.Error("expected error for transport route with too-short buffer")
|
||||||
}
|
}
|
||||||
@@ -931,16 +939,19 @@ func TestDecodeAckShort(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestDecodeAckValid(t *testing.T) {
|
func TestDecodeAckValid(t *testing.T) {
|
||||||
buf := []byte{0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF}
|
buf := []byte{0xAA, 0xBB, 0xCC, 0xDD}
|
||||||
p := decodeAck(buf)
|
p := decodeAck(buf)
|
||||||
if p.Error != "" {
|
if p.Error != "" {
|
||||||
t.Errorf("unexpected error: %s", p.Error)
|
t.Errorf("unexpected error: %s", p.Error)
|
||||||
}
|
}
|
||||||
if p.DestHash != "aa" {
|
if p.ExtraHash != "ddccbbaa" {
|
||||||
t.Errorf("destHash=%s, want aa", p.DestHash)
|
t.Errorf("extraHash=%s, want ddccbbaa", p.ExtraHash)
|
||||||
}
|
}
|
||||||
if p.ExtraHash != "ccddeeff" {
|
if p.DestHash != "" {
|
||||||
t.Errorf("extraHash=%s, want ccddeeff", p.ExtraHash)
|
t.Errorf("destHash should be empty, got %s", p.DestHash)
|
||||||
|
}
|
||||||
|
if p.SrcHash != "" {
|
||||||
|
t.Errorf("srcHash should be empty, got %s", p.SrcHash)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -54,8 +54,8 @@ type Header struct {
|
|||||||
|
|
||||||
// TransportCodes are present on TRANSPORT_FLOOD and TRANSPORT_DIRECT routes.
|
// TransportCodes are present on TRANSPORT_FLOOD and TRANSPORT_DIRECT routes.
|
||||||
type TransportCodes struct {
|
type TransportCodes struct {
|
||||||
NextHop string `json:"nextHop"`
|
Code1 string `json:"code1"`
|
||||||
LastHop string `json:"lastHop"`
|
Code2 string `json:"code2"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Path holds decoded path/hop information.
|
// Path holds decoded path/hop information.
|
||||||
@@ -74,6 +74,8 @@ type AdvertFlags struct {
|
|||||||
Room bool `json:"room"`
|
Room bool `json:"room"`
|
||||||
Sensor bool `json:"sensor"`
|
Sensor bool `json:"sensor"`
|
||||||
HasLocation bool `json:"hasLocation"`
|
HasLocation bool `json:"hasLocation"`
|
||||||
|
HasFeat1 bool `json:"hasFeat1"`
|
||||||
|
HasFeat2 bool `json:"hasFeat2"`
|
||||||
HasName bool `json:"hasName"`
|
HasName bool `json:"hasName"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,6 +99,8 @@ type Payload struct {
|
|||||||
EphemeralPubKey string `json:"ephemeralPubKey,omitempty"`
|
EphemeralPubKey string `json:"ephemeralPubKey,omitempty"`
|
||||||
PathData string `json:"pathData,omitempty"`
|
PathData string `json:"pathData,omitempty"`
|
||||||
Tag uint32 `json:"tag,omitempty"`
|
Tag uint32 `json:"tag,omitempty"`
|
||||||
|
AuthCode uint32 `json:"authCode,omitempty"`
|
||||||
|
TraceFlags *int `json:"traceFlags,omitempty"`
|
||||||
RawHex string `json:"raw,omitempty"`
|
RawHex string `json:"raw,omitempty"`
|
||||||
Error string `json:"error,omitempty"`
|
Error string `json:"error,omitempty"`
|
||||||
}
|
}
|
||||||
@@ -173,14 +177,13 @@ func decodeEncryptedPayload(typeName string, buf []byte) Payload {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func decodeAck(buf []byte) Payload {
|
func decodeAck(buf []byte) Payload {
|
||||||
if len(buf) < 6 {
|
if len(buf) < 4 {
|
||||||
return Payload{Type: "ACK", Error: "too short", RawHex: hex.EncodeToString(buf)}
|
return Payload{Type: "ACK", Error: "too short", RawHex: hex.EncodeToString(buf)}
|
||||||
}
|
}
|
||||||
|
checksum := binary.LittleEndian.Uint32(buf[0:4])
|
||||||
return Payload{
|
return Payload{
|
||||||
Type: "ACK",
|
Type: "ACK",
|
||||||
DestHash: hex.EncodeToString(buf[0:1]),
|
ExtraHash: fmt.Sprintf("%08x", checksum),
|
||||||
SrcHash: hex.EncodeToString(buf[1:2]),
|
|
||||||
ExtraHash: hex.EncodeToString(buf[2:6]),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -205,6 +208,8 @@ func decodeAdvert(buf []byte) Payload {
|
|||||||
if len(appdata) > 0 {
|
if len(appdata) > 0 {
|
||||||
flags := appdata[0]
|
flags := appdata[0]
|
||||||
advType := int(flags & 0x0F)
|
advType := int(flags & 0x0F)
|
||||||
|
hasFeat1 := flags&0x20 != 0
|
||||||
|
hasFeat2 := flags&0x40 != 0
|
||||||
p.Flags = &AdvertFlags{
|
p.Flags = &AdvertFlags{
|
||||||
Raw: int(flags),
|
Raw: int(flags),
|
||||||
Type: advType,
|
Type: advType,
|
||||||
@@ -213,6 +218,8 @@ func decodeAdvert(buf []byte) Payload {
|
|||||||
Room: advType == 3,
|
Room: advType == 3,
|
||||||
Sensor: advType == 4,
|
Sensor: advType == 4,
|
||||||
HasLocation: flags&0x10 != 0,
|
HasLocation: flags&0x10 != 0,
|
||||||
|
HasFeat1: hasFeat1,
|
||||||
|
HasFeat2: hasFeat2,
|
||||||
HasName: flags&0x80 != 0,
|
HasName: flags&0x80 != 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -226,6 +233,12 @@ func decodeAdvert(buf []byte) Payload {
|
|||||||
p.Lon = &lon
|
p.Lon = &lon
|
||||||
off += 8
|
off += 8
|
||||||
}
|
}
|
||||||
|
if hasFeat1 && len(appdata) >= off+2 {
|
||||||
|
off += 2 // skip feat1 bytes (reserved for future use)
|
||||||
|
}
|
||||||
|
if hasFeat2 && len(appdata) >= off+2 {
|
||||||
|
off += 2 // skip feat2 bytes (reserved for future use)
|
||||||
|
}
|
||||||
if p.Flags.HasName {
|
if p.Flags.HasName {
|
||||||
name := string(appdata[off:])
|
name := string(appdata[off:])
|
||||||
name = strings.TrimRight(name, "\x00")
|
name = strings.TrimRight(name, "\x00")
|
||||||
@@ -276,15 +289,22 @@ func decodePathPayload(buf []byte) Payload {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func decodeTrace(buf []byte) Payload {
|
func decodeTrace(buf []byte) Payload {
|
||||||
if len(buf) < 12 {
|
if len(buf) < 9 {
|
||||||
return Payload{Type: "TRACE", Error: "too short", RawHex: hex.EncodeToString(buf)}
|
return Payload{Type: "TRACE", Error: "too short", RawHex: hex.EncodeToString(buf)}
|
||||||
}
|
}
|
||||||
return Payload{
|
tag := binary.LittleEndian.Uint32(buf[0:4])
|
||||||
Type: "TRACE",
|
authCode := binary.LittleEndian.Uint32(buf[4:8])
|
||||||
DestHash: hex.EncodeToString(buf[5:11]),
|
flags := int(buf[8])
|
||||||
SrcHash: hex.EncodeToString(buf[11:12]),
|
p := Payload{
|
||||||
Tag: binary.LittleEndian.Uint32(buf[1:5]),
|
Type: "TRACE",
|
||||||
|
Tag: tag,
|
||||||
|
AuthCode: authCode,
|
||||||
|
TraceFlags: &flags,
|
||||||
}
|
}
|
||||||
|
if len(buf) > 9 {
|
||||||
|
p.PathData = hex.EncodeToString(buf[9:])
|
||||||
|
}
|
||||||
|
return p
|
||||||
}
|
}
|
||||||
|
|
||||||
func decodePayload(payloadType int, buf []byte) Payload {
|
func decodePayload(payloadType int, buf []byte) Payload {
|
||||||
@@ -327,8 +347,7 @@ func DecodePacket(hexString string) (*DecodedPacket, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
header := decodeHeader(buf[0])
|
header := decodeHeader(buf[0])
|
||||||
pathByte := buf[1]
|
offset := 1
|
||||||
offset := 2
|
|
||||||
|
|
||||||
var tc *TransportCodes
|
var tc *TransportCodes
|
||||||
if isTransportRoute(header.RouteType) {
|
if isTransportRoute(header.RouteType) {
|
||||||
@@ -336,12 +355,18 @@ func DecodePacket(hexString string) (*DecodedPacket, error) {
|
|||||||
return nil, fmt.Errorf("packet too short for transport codes")
|
return nil, fmt.Errorf("packet too short for transport codes")
|
||||||
}
|
}
|
||||||
tc = &TransportCodes{
|
tc = &TransportCodes{
|
||||||
NextHop: strings.ToUpper(hex.EncodeToString(buf[offset : offset+2])),
|
Code1: strings.ToUpper(hex.EncodeToString(buf[offset : offset+2])),
|
||||||
LastHop: strings.ToUpper(hex.EncodeToString(buf[offset+2 : offset+4])),
|
Code2: strings.ToUpper(hex.EncodeToString(buf[offset+2 : offset+4])),
|
||||||
}
|
}
|
||||||
offset += 4
|
offset += 4
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if offset >= len(buf) {
|
||||||
|
return nil, fmt.Errorf("packet too short (no path byte)")
|
||||||
|
}
|
||||||
|
pathByte := buf[offset]
|
||||||
|
offset++
|
||||||
|
|
||||||
path, bytesConsumed := decodePath(pathByte, buf, offset)
|
path, bytesConsumed := decodePath(pathByte, buf, offset)
|
||||||
offset += bytesConsumed
|
offset += bytesConsumed
|
||||||
|
|
||||||
@@ -367,16 +392,24 @@ func ComputeContentHash(rawHex string) string {
|
|||||||
return rawHex
|
return rawHex
|
||||||
}
|
}
|
||||||
|
|
||||||
pathByte := buf[1]
|
headerByte := buf[0]
|
||||||
|
offset := 1
|
||||||
|
if isTransportRoute(int(headerByte & 0x03)) {
|
||||||
|
offset += 4
|
||||||
|
}
|
||||||
|
if offset >= len(buf) {
|
||||||
|
if len(rawHex) >= 16 {
|
||||||
|
return rawHex[:16]
|
||||||
|
}
|
||||||
|
return rawHex
|
||||||
|
}
|
||||||
|
pathByte := buf[offset]
|
||||||
|
offset++
|
||||||
hashSize := int((pathByte>>6)&0x3) + 1
|
hashSize := int((pathByte>>6)&0x3) + 1
|
||||||
hashCount := int(pathByte & 0x3F)
|
hashCount := int(pathByte & 0x3F)
|
||||||
pathBytes := hashSize * hashCount
|
pathBytes := hashSize * hashCount
|
||||||
|
|
||||||
headerByte := buf[0]
|
payloadStart := offset + pathBytes
|
||||||
payloadStart := 2 + pathBytes
|
|
||||||
if isTransportRoute(int(headerByte & 0x03)) {
|
|
||||||
payloadStart += 4
|
|
||||||
}
|
|
||||||
if payloadStart > len(buf) {
|
if payloadStart > len(buf) {
|
||||||
if len(rawHex) >= 16 {
|
if len(rawHex) >= 16 {
|
||||||
return rawHex[:16]
|
return rawHex[:16]
|
||||||
|
|||||||
Reference in New Issue
Block a user