blob: 2c150a565c1d4eeb099617a15919eef14fd24bd0 [file] [log] [blame]
/*
* Copyright 2018-present Open Networking Foundation
* 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 omci
import (
"encoding/binary"
"encoding/hex"
"errors"
"fmt"
"github.com/google/gopacket"
"github.com/opencord/omci-lib-go/v2"
log "github.com/sirupsen/logrus"
)
const DeviceIdentifierPos = 3
// ParseOpenOltOmciPacket receive an OMCI packet in the openolt format and returns
// an OMCI Layer as per omci-lib-go
func ParseOpenOltOmciPacket(pkt []byte) (gopacket.Packet, *omci.OMCI, error) {
rxMsg := HexDecode(pkt)
if len(rxMsg) < 10 {
omciLogger.WithFields(log.Fields{"Length": len(rxMsg)}).Error("received omci message is generally too small - abort")
return nil, nil, errors.New("received omci message is generally too small - abort")
}
if rxMsg[DeviceIdentifierPos] == byte(omci.BaselineIdent) {
// NOTE this is may not be needed, VOLTHA sends the correct message
if len(rxMsg) >= 44 {
trailerLenData := rxMsg[42:44]
trailerLen := binary.BigEndian.Uint16(trailerLenData)
if trailerLen != 40 { // invalid base Format entry -> autocorrect
binary.BigEndian.PutUint16(rxMsg[42:44], 40)
omciLogger.Trace("cc-corrected-omci-message: trailer len inserted")
}
} else {
omciLogger.WithFields(log.Fields{"Length": len(rxMsg)}).Error("received omci-message too small for OmciBaseFormat - abort")
return nil, nil, errors.New("received omci-message too small for OmciBaseFormat - abort")
}
} else if rxMsg[DeviceIdentifierPos] == byte(omci.ExtendedIdent) {
if len(rxMsg) > 1980 {
omciLogger.WithFields(log.Fields{"Length": len(rxMsg)}).Error("received omci-message with wrong length for OmciExtendedFormat - abort")
return nil, nil, errors.New("received omci-message with wrong length for OmciExtendedFormat - abort")
}
} else {
omciLogger.WithFields(log.Fields{"DeviceIdent": rxMsg[DeviceIdentifierPos]}).Error("received omci-message with wrong Device Identifier - abort")
return nil, nil, errors.New("received omci-message with wrong Device Identifier - abort")
}
packet := gopacket.NewPacket(rxMsg, omci.LayerTypeOMCI, gopacket.NoCopy)
if packet == nil {
omciLogger.Error("omci-message could not be decoded")
return nil, nil, errors.New("omci-message could not be decoded")
}
omciLayer := packet.Layer(omci.LayerTypeOMCI)
if omciLayer == nil {
omciLogger.Error("omci-message could not decode omci layer")
return nil, nil, fmt.Errorf("omci-message could not decode omci layer")
}
parsed, ok := omciLayer.(*omci.OMCI)
if !ok {
omciLogger.Error("omci-message could not assign omci layer")
return nil, nil, errors.New("omci-message could not assign omci layer")
}
return packet, parsed, nil
}
// HexDecode converts the hex encoding to binary
func HexDecode(pkt []byte) []byte {
p := make([]byte, len(pkt)/2)
for i, j := 0, 0; i < len(pkt); i, j = i+2, j+1 {
// Go figure this ;)
u := (pkt[i] & 15) + (pkt[i]>>6)*9
l := (pkt[i+1] & 15) + (pkt[i+1]>>6)*9
p[j] = u<<4 + l
}
return p
}
//HexEncode convert binary to hex
func HexEncode(omciPkt []byte) ([]byte, error) {
dst := make([]byte, hex.EncodedLen(len(omciPkt)))
hex.Encode(dst, omciPkt)
return dst, nil
}