ptp/protocol/unicast.go (202 lines of code) (raw):
/*
Copyright (c) Facebook, Inc. and its affiliates.
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 protocol
import (
"bytes"
"encoding/binary"
"fmt"
)
// UnicastMsgTypeAndFlags is a uint8 where first 4 bites contain MessageType and last 4 bits contain some flags
type UnicastMsgTypeAndFlags uint8
// MsgType extracts MessageType from UnicastMsgTypeAndFlags
func (m UnicastMsgTypeAndFlags) MsgType() MessageType {
return MessageType(m >> 4)
}
// NewUnicastMsgTypeAndFlags builds new UnicastMsgTypeAndFlags from MessageType and flags
func NewUnicastMsgTypeAndFlags(msgType MessageType, flags uint8) UnicastMsgTypeAndFlags {
return UnicastMsgTypeAndFlags(uint8(msgType)<<4 | (flags & 0x0f))
}
// Signaling packet. As it's of variable size, we cannot just binary.Read/Write it.
type Signaling struct {
Header
TargetPortIdentity PortIdentity
TLVs []TLV
}
// MarshalBinaryTo marshals bytes to Signaling
func (p *Signaling) MarshalBinaryTo(b []byte) (int, error) {
if len(p.TLVs) == 0 {
return 0, fmt.Errorf("no TLVs in Signaling message, at least one required")
}
n := headerMarshalBinaryTo(&p.Header, b)
binary.BigEndian.PutUint64(b[n:], uint64(p.TargetPortIdentity.ClockIdentity))
binary.BigEndian.PutUint16(b[n+8:], p.TargetPortIdentity.PortNumber)
pos := n + 10
for _, tlv := range p.TLVs {
if ttlv, ok := tlv.(BinaryMarshalerTo); ok {
nn, err := ttlv.MarshalBinaryTo(b[pos:])
if err != nil {
return 0, err
}
pos += nn
continue
}
// very inefficient path for TLVs that don't support MarshalBinaryTo
buf := new(bytes.Buffer)
if err := binary.Write(buf, binary.BigEndian, tlv); err != nil {
return 0, err
}
bbytes := buf.Bytes()
copy(b[pos:], bbytes)
pos += len(bbytes)
}
return pos, nil
}
// MarshalBinary converts packet to []bytes
func (p *Signaling) MarshalBinary() ([]byte, error) {
buf := make([]byte, 200)
n, err := p.MarshalBinaryTo(buf)
return buf[:n], err
}
func unmarshalTLVHeader(p *TLVHead, b []byte) error {
if len(b) < tlvHeadSize {
return fmt.Errorf("not enough data to decode PTP header")
}
p.TLVType = TLVType(binary.BigEndian.Uint16(b[0:]))
p.LengthField = binary.BigEndian.Uint16(b[2:])
return nil
}
// UnmarshalBinary parses []byte and populates struct fields
func (p *Signaling) UnmarshalBinary(b []byte) error {
if len(b) < headerSize+10+tlvHeadSize {
return fmt.Errorf("not enough data to decode Signaling")
}
unmarshalHeader(&p.Header, b)
if p.SdoIDAndMsgType.MsgType() != MessageSignaling {
return fmt.Errorf("not a signaling message %v", b)
}
p.TargetPortIdentity.ClockIdentity = ClockIdentity(binary.BigEndian.Uint64(b[headerSize:]))
p.TargetPortIdentity.PortNumber = binary.BigEndian.Uint16(b[headerSize+8:])
pos := headerSize + 10
var tlvType TLVType
for {
head := TLVHead{}
// packet can have trailing bytes, let's make sure we don't try to read past given length
if pos+tlvHeadSize > int(p.MessageLength) {
break
}
tlvType = TLVType(binary.BigEndian.Uint16(b[pos:]))
switch tlvType {
case TLVAcknowledgeCancelUnicastTransmission:
tlv := &AcknowledgeCancelUnicastTransmissionTLV{}
if err := tlv.UnmarshalBinary(b[pos:]); err != nil {
return err
}
p.TLVs = append(p.TLVs, tlv)
pos += tlvHeadSize + int(tlv.LengthField)
case TLVGrantUnicastTransmission:
tlv := &GrantUnicastTransmissionTLV{}
if err := tlv.UnmarshalBinary(b[pos:]); err != nil {
return err
}
p.TLVs = append(p.TLVs, tlv)
pos += tlvHeadSize + int(tlv.LengthField)
case TLVRequestUnicastTransmission:
tlv := &RequestUnicastTransmissionTLV{}
if err := tlv.UnmarshalBinary(b[pos:]); err != nil {
return err
}
p.TLVs = append(p.TLVs, tlv)
pos += tlvHeadSize + int(tlv.LengthField)
case TLVCancelUnicastTransmission:
tlv := &CancelUnicastTransmissionTLV{}
if err := tlv.UnmarshalBinary(b[pos:]); err != nil {
return err
}
p.TLVs = append(p.TLVs, tlv)
pos += tlvHeadSize + int(tlv.LengthField)
default:
return fmt.Errorf("reading TLV %s (%d) is not yet implemented", head.TLVType, head.TLVType)
}
}
if len(p.TLVs) == 0 {
return fmt.Errorf("no TLVs read for Signaling message, at least one required")
}
return nil
}
// Unicast TLVs
// RequestUnicastTransmissionTLV Table 110 REQUEST_UNICAST_TRANSMISSION TLV format
type RequestUnicastTransmissionTLV struct {
TLVHead
MsgTypeAndReserved UnicastMsgTypeAndFlags // first 4 bits only, same enums as with normal message type
LogInterMessagePeriod LogInterval
DurationField uint32
}
// MarshalBinaryTo marshals bytes to RequestUnicastTransmissionTLV
func (t *RequestUnicastTransmissionTLV) MarshalBinaryTo(b []byte) (int, error) {
tlvHeadMarshalBinaryTo(&t.TLVHead, b)
b[tlvHeadSize] = byte(t.MsgTypeAndReserved)
b[tlvHeadSize+1] = byte(t.LogInterMessagePeriod)
binary.BigEndian.PutUint32(b[tlvHeadSize+2:], t.DurationField)
return tlvHeadSize + 6, nil
}
// UnmarshalBinary parses []byte and populates struct fields
func (t *RequestUnicastTransmissionTLV) UnmarshalBinary(b []byte) error {
if err := unmarshalTLVHeader(&t.TLVHead, b); err != nil {
return err
}
t.MsgTypeAndReserved = UnicastMsgTypeAndFlags(b[4])
t.LogInterMessagePeriod = LogInterval(b[5])
t.DurationField = binary.BigEndian.Uint32(b[6:])
return nil
}
// GrantUnicastTransmissionTLV Table 111 GRANT_UNICAST_TRANSMISSION TLV format
type GrantUnicastTransmissionTLV struct {
TLVHead
MsgTypeAndReserved UnicastMsgTypeAndFlags // first 4 bits only, same enums as with normal message type
LogInterMessagePeriod LogInterval
DurationField uint32
Reserved uint8
Renewal uint8
}
// MarshalBinaryTo marshals bytes to GrantUnicastTransmissionTLV
func (t *GrantUnicastTransmissionTLV) MarshalBinaryTo(b []byte) (int, error) {
tlvHeadMarshalBinaryTo(&t.TLVHead, b)
b[tlvHeadSize] = byte(t.MsgTypeAndReserved)
b[tlvHeadSize+1] = byte(t.LogInterMessagePeriod)
binary.BigEndian.PutUint32(b[tlvHeadSize+2:], t.DurationField)
b[tlvHeadSize+6] = t.Reserved
b[tlvHeadSize+7] = t.Renewal
return tlvHeadSize + 8, nil
}
// UnmarshalBinary parses []byte and populates struct fields
func (t *GrantUnicastTransmissionTLV) UnmarshalBinary(b []byte) error {
if err := unmarshalTLVHeader(&t.TLVHead, b); err != nil {
return err
}
t.MsgTypeAndReserved = UnicastMsgTypeAndFlags(b[4])
t.LogInterMessagePeriod = LogInterval(b[5])
t.DurationField = binary.BigEndian.Uint32(b[6:])
t.Reserved = b[10]
t.Renewal = b[11]
return nil
}
// CancelUnicastTransmissionTLV Table 112 CANCEL_UNICAST_TRANSMISSION TLV format
type CancelUnicastTransmissionTLV struct {
TLVHead
MsgTypeAndFlags UnicastMsgTypeAndFlags // first 4 bits is msg type, then flags R and/or G
Reserved uint8
}
// MarshalBinaryTo marshals bytes to CancelUnicastTransmissionTLV
func (t *CancelUnicastTransmissionTLV) MarshalBinaryTo(b []byte) (int, error) {
tlvHeadMarshalBinaryTo(&t.TLVHead, b)
b[tlvHeadSize] = byte(t.MsgTypeAndFlags)
b[tlvHeadSize+1] = byte(t.Reserved)
return tlvHeadSize + 2, nil
}
// UnmarshalBinary parses []byte and populates struct fields
func (t *CancelUnicastTransmissionTLV) UnmarshalBinary(b []byte) error {
if err := unmarshalTLVHeader(&t.TLVHead, b); err != nil {
return err
}
t.MsgTypeAndFlags = UnicastMsgTypeAndFlags(b[4])
t.Reserved = b[5]
return nil
}
// AcknowledgeCancelUnicastTransmissionTLV Table 113 ACKNOWLEDGE_CANCEL_UNICAST_TRANSMISSION TLV format
type AcknowledgeCancelUnicastTransmissionTLV struct {
TLVHead
MsgTypeAndFlags UnicastMsgTypeAndFlags // first 4 bits is msg type, then flags R and/or G
Reserved uint8
}
// MarshalBinaryTo marshals bytes to AcknowledgeCancelUnicastTransmissionTLV
func (t *AcknowledgeCancelUnicastTransmissionTLV) MarshalBinaryTo(b []byte) (int, error) {
tlvHeadMarshalBinaryTo(&t.TLVHead, b)
b[tlvHeadSize] = byte(t.MsgTypeAndFlags)
b[tlvHeadSize+1] = byte(t.Reserved)
return tlvHeadSize + 2, nil
}
// UnmarshalBinary parses []byte and populates struct fields
func (t *AcknowledgeCancelUnicastTransmissionTLV) UnmarshalBinary(b []byte) error {
if err := unmarshalTLVHeader(&t.TLVHead, b); err != nil {
return err
}
t.MsgTypeAndFlags = UnicastMsgTypeAndFlags(b[4])
t.Reserved = b[5]
return nil
}