implement more ZIP packets (ATP)
This commit is contained in:
parent
c7d5ecec49
commit
8771139a4f
2 changed files with 131 additions and 0 deletions
125
atalk/zip/getzonelist.go
Normal file
125
atalk/zip/getzonelist.go
Normal file
|
@ -0,0 +1,125 @@
|
||||||
|
/*
|
||||||
|
Copyright 2024 Josh Deprez
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package zip
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/binary"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"gitea.drjosh.dev/josh/jrouter/atalk/atp"
|
||||||
|
)
|
||||||
|
|
||||||
|
type GetZonesPacket struct {
|
||||||
|
// "These requests always ask for a single response packet."
|
||||||
|
// TReq = 0b01000000
|
||||||
|
// Bitmap = 0b00000001
|
||||||
|
TID uint16
|
||||||
|
// --- ATP user bytes
|
||||||
|
Function Function // 7, 8, or 9
|
||||||
|
// Pad uint8 = 0
|
||||||
|
StartIndex uint16 // always 0 for
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *GetZonesPacket) MarshalTReq() (*atp.TReq, error) {
|
||||||
|
return &atp.TReq{
|
||||||
|
Bitmap: 0b00000001,
|
||||||
|
TransactionID: p.TID,
|
||||||
|
UserBytes: [4]byte{
|
||||||
|
byte(p.Function), 0, byte(p.StartIndex >> 8), byte(p.StartIndex & 0xFF),
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type GetZonesReplyPacket struct {
|
||||||
|
// TResp = 0b10000000
|
||||||
|
// Sequence = 0
|
||||||
|
TID uint16
|
||||||
|
// --- ATP user bytes
|
||||||
|
LastFlag bool // not used for GetMyZone
|
||||||
|
// Pad uint8 = 0
|
||||||
|
// ZoneCount uint16
|
||||||
|
// --- ATP data bytes
|
||||||
|
Zones []string // length-prefixed
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *GetZonesReplyPacket) MarshalTResp() (*atp.TResp, error) {
|
||||||
|
r := &atp.TResp{
|
||||||
|
EndOfMessage: true,
|
||||||
|
Sequence: 0,
|
||||||
|
TransactionID: p.TID,
|
||||||
|
}
|
||||||
|
if p.LastFlag {
|
||||||
|
r.UserBytes[0] = 1
|
||||||
|
}
|
||||||
|
zc := uint16(len(p.Zones))
|
||||||
|
r.UserBytes[2] = byte(zc >> 8)
|
||||||
|
r.UserBytes[3] = byte(zc & 0xFF)
|
||||||
|
b := bytes.NewBuffer(nil)
|
||||||
|
for _, z := range p.Zones {
|
||||||
|
if len(z) > 32 {
|
||||||
|
return nil, fmt.Errorf("zone name %q too long [%d > 32]", z, len(z))
|
||||||
|
}
|
||||||
|
b.WriteByte(byte(len(z)))
|
||||||
|
b.WriteString(z)
|
||||||
|
}
|
||||||
|
r.Data = b.Bytes()
|
||||||
|
return r, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func UnmarshalTReq(treq *atp.TReq) (*GetZonesPacket, error) {
|
||||||
|
if treq == nil {
|
||||||
|
return nil, fmt.Errorf("nil *TReq")
|
||||||
|
}
|
||||||
|
fn := treq.UserBytes[0]
|
||||||
|
if fn != FunctionGetZoneList && fn != FunctionGetLocalZones && fn != FunctionGetMyZone {
|
||||||
|
return nil, fmt.Errorf("invalid ZIP function %d", fn)
|
||||||
|
}
|
||||||
|
return &GetZonesPacket{
|
||||||
|
TID: treq.TransactionID,
|
||||||
|
Function: Function(treq.UserBytes[0]),
|
||||||
|
StartIndex: binary.BigEndian.Uint16(treq.UserBytes[2:4]),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func UnmarshalTResp(tresp *atp.TResp) (*GetZonesReplyPacket, error) {
|
||||||
|
if tresp == nil {
|
||||||
|
return nil, fmt.Errorf("nil *TResp")
|
||||||
|
}
|
||||||
|
p := &GetZonesReplyPacket{
|
||||||
|
TID: tresp.TransactionID,
|
||||||
|
LastFlag: tresp.UserBytes[0] != 0,
|
||||||
|
}
|
||||||
|
data := tresp.Data
|
||||||
|
zc := binary.BigEndian.Uint16(tresp.UserBytes[2:4])
|
||||||
|
for range zc {
|
||||||
|
if len(data) < 1 {
|
||||||
|
return nil, fmt.Errorf("insufficient remaining TResp data length %d for length-prefixed string", len(data))
|
||||||
|
}
|
||||||
|
slen := data[0]
|
||||||
|
data = data[1:]
|
||||||
|
if len(data) < int(slen) {
|
||||||
|
return nil, fmt.Errorf("insufficient remaining TResp data length %d for length-%d prefixed string", len(data), slen)
|
||||||
|
}
|
||||||
|
p.Zones = append(p.Zones, string(data[:slen]))
|
||||||
|
data = data[slen:]
|
||||||
|
}
|
||||||
|
if len(data) > 0 {
|
||||||
|
return nil, fmt.Errorf("%d bytes left over at end of packet", len(data))
|
||||||
|
}
|
||||||
|
return p, nil
|
||||||
|
}
|
|
@ -24,12 +24,18 @@ import (
|
||||||
type Function uint8
|
type Function uint8
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
// ZIP packets
|
||||||
FunctionQuery = 1
|
FunctionQuery = 1
|
||||||
FunctionReply = 2
|
FunctionReply = 2
|
||||||
FunctionGetNetInfo = 5
|
FunctionGetNetInfo = 5
|
||||||
FunctionGetNetInfoReply = 6
|
FunctionGetNetInfoReply = 6
|
||||||
FunctionNotify = 7
|
FunctionNotify = 7
|
||||||
FunctionExtendedReply = 8
|
FunctionExtendedReply = 8
|
||||||
|
|
||||||
|
// ATP packets
|
||||||
|
FunctionGetMyZone = 7
|
||||||
|
FunctionGetZoneList = 8
|
||||||
|
FunctionGetLocalZones = 9
|
||||||
)
|
)
|
||||||
|
|
||||||
// Non-ATP packets only
|
// Non-ATP packets only
|
||||||
|
|
Loading…
Reference in a new issue