diff --git a/uePolicyContainer/NAS_UePolicyDeliveryServiceMsgType.go b/uePolicyContainer/NAS_UePolicyDeliveryServiceMsgType.go new file mode 100644 index 0000000..2ee88fe --- /dev/null +++ b/uePolicyContainer/NAS_UePolicyDeliveryServiceMsgType.go @@ -0,0 +1,14 @@ +package uePolicyContainer + +// TS24.501 v17.7.1, D.6.1 +type UePolicyDeliveryServiceMsgType struct { + Octet uint8 +} + +func (m *UePolicyDeliveryServiceMsgType) SetMessageIdentity(MessageIdentity uint8) { + m.Octet = MessageIdentity +} + +func (m *UePolicyDeliveryServiceMsgType) GetMessageIdentity(MessageIdentity uint8) uint8 { + return m.Octet +} diff --git a/uePolicyContainer/UPSC_Generator.go b/uePolicyContainer/UPSC_Generator.go new file mode 100644 index 0000000..24662bc --- /dev/null +++ b/uePolicyContainer/UPSC_Generator.go @@ -0,0 +1,101 @@ +package uePolicyContainer + +// idgenerator is used for generating ID from minValue to maxValue. +// It will allocate IDs in range [minValue, maxValue] +// It is thread-safe when allocating IDs + +import ( + "errors" +) + +type IDGenerator struct { + // lock sync.Mutex + minValue int64 + maxValue int64 + valueRange int64 + offset int64 + usedMap map[int64]bool +} + +// Initialize an IDGenerator with minValue and maxValue. +func NewGenerator(minValue, maxValue int64) *IDGenerator { + idGenerator := &IDGenerator{} + idGenerator.init(minValue, maxValue) + return idGenerator +} + +func (idGenerator *IDGenerator) init(minValue, maxValue int64) { + idGenerator.minValue = minValue + idGenerator.maxValue = maxValue + idGenerator.valueRange = maxValue - minValue + 1 + idGenerator.offset = 0 + idGenerator.usedMap = make(map[int64]bool) +} + +// Allocate and return an id in range [minValue, maxValue] +func (idGenerator *IDGenerator) Allocate() (int64, error) { + // idGenerator.lock.Lock() + // defer idGenerator.lock.Unlock() + + offsetBegin := idGenerator.offset + for { + if _, ok := idGenerator.usedMap[idGenerator.offset]; ok { + idGenerator.updateOffset() + + if idGenerator.offset == offsetBegin { + return 0, errors.New("no available value range to allocate id") + } + } else { + break + } + } + idGenerator.usedMap[idGenerator.offset] = true + id := idGenerator.offset + idGenerator.minValue + idGenerator.updateOffset() + return id, nil +} + +// Allocate and return an id in from certain range [inputMin, inputMAX] +func (idGenerator *IDGenerator) Allocate_inRange(min, max int64) (int64, error) { + // idGenerator.lock.Lock() + // defer idGenerator.lock.Unlock() + + offsetBegin := idGenerator.offset + idGenerator.setOffset(min) + for { + if _, ok := idGenerator.usedMap[idGenerator.offset]; ok { + idGenerator.updateOffset() + + if idGenerator.offset == offsetBegin || idGenerator.offset == max { + return 0, errors.New("no available value range to allocate id") + } + } else { + break + } + } + idGenerator.usedMap[idGenerator.offset] = true + id := idGenerator.offset + idGenerator.minValue + idGenerator.updateOffset() + return id, nil +} + +// param: +// - id: id to free +func (idGenerator *IDGenerator) FreeID(id int64) { + if id < idGenerator.minValue || id > idGenerator.maxValue { + return + } + // idGenerator.lock.Lock() + // defer idGenerator.lock.Unlock() + delete(idGenerator.usedMap, id-idGenerator.minValue) +} + +func (idGenerator *IDGenerator) updateOffset() { + idGenerator.offset++ + idGenerator.offset = idGenerator.offset % idGenerator.valueRange +} + +func (idGenerator *IDGenerator) setOffset(newoffset int64) { + idGenerator.offset = newoffset + idGenerator.offset = idGenerator.offset % idGenerator.valueRange +} diff --git a/uePolicyContainer/UePolicyContainer.go b/uePolicyContainer/UePolicyContainer.go new file mode 100644 index 0000000..7bd2278 --- /dev/null +++ b/uePolicyContainer/UePolicyContainer.go @@ -0,0 +1,125 @@ +package uePolicyContainer + +import ( + "bytes" + "encoding/binary" + "fmt" +) + +// UePolicyContainer is a kind of NAS_DLTransport message +// UePolicyContainer maps to UE_policy_delivery_service +// TS 124 501 V17.7.1, page.760, Table 9.11.3.39.1: Payload container information element +type UePolicyContainer = UePolDeliverySer + +// TS 124 501 V17.7.1, page.893, UE policy delivery service +type UePolDeliverySer struct { + UePolDeliveryHeader + *ManageUEPolicyCommand // D.2.1.2 Network-requested UE policy management procedure initiation + *ManageUEPolicyComplete // D.2.1.3 Network-requested UE policy management procedure accepted by the UE + *ManageUEPolicyReject // D.2.1.4 Network-requested UE policy management procedure not accepted by the UE + // TODO: add below encoding way + // *nasMessage.UEStateIndication // D.2.2 UE-initiated UE state indication procedure +} + +func NewUePolDeliverySer() *UePolDeliverySer { + uePolDeliverySer := &UePolDeliverySer{} + return uePolDeliverySer +} + +type UePolDeliveryHeader struct { + Octet [2]uint8 +} + +// PTI(Procedure transaction identity) is assign by PCF +func (u *UePolDeliveryHeader) SetHeaderPTI(PTI uint8) { + u.Octet[0] = PTI +} + +// PTI(Procedure transaction identity) +func (u *UePolDeliveryHeader) GetHeaderPTI() (pTI uint8) { + pTI = u.Octet[0] + return pTI +} + +func (u *UePolDeliveryHeader) GetHeaderMessageType() (messageType uint8) { + messageType = u.Octet[1] + return messageType +} + +func (u *UePolDeliveryHeader) SetHeaderMessageType(messageType uint8) { + u.Octet[1] = messageType +} + +const ( + MsgTypeManageUEPolicyCommand uint8 = 1 + MsgTypeManageUEPolicyComplete uint8 = 2 + MsgTypeManageUEPolicyReject uint8 = 3 + MsgTypeUEStateIndication uint8 = 4 + MsgTypeUEPolicyProvisioningRequest uint8 = 5 + MsgTypeUEPolicyProvisioningReject uint8 = 6 +) + +// TODO: add other Decoding processes +func (u *UePolDeliverySer) UePolDeliverySerDecode(byteArray []byte) error { + buffer := bytes.NewBuffer(byteArray) + if err := binary.Read(buffer, binary.BigEndian, &u.UePolDeliveryHeader); err != nil { + return fmt.Errorf("uePolicyContainer-UePolDeliveryHeader decode Fail:%+v", err) + } + + switch u.GetHeaderMessageType() { + case MsgTypeManageUEPolicyCommand: + u.ManageUEPolicyCommand = NewManageUEPolicyCommand(MsgTypeManageUEPolicyCommand) + if err := u.DecodeManageUEPolicyCommand(byteArray); err != nil { + return err + } + case MsgTypeManageUEPolicyComplete: + u.ManageUEPolicyComplete = NewManageUEPolicyComplete(MsgTypeManageUEPolicyComplete) + if err := u.DecodeManageUEPolicyComplete(byteArray); err != nil { + return err + } + case MsgTypeManageUEPolicyReject: + u.ManageUEPolicyReject = NewManageUEPolicyReject(MsgTypeManageUEPolicyReject) + if err := u.DecodeManageUEPolicyReject(byteArray); err != nil { + return err + } + case MsgTypeUEStateIndication: + // TODO + case MsgTypeUEPolicyProvisioningRequest: + // TODO + case MsgTypeUEPolicyProvisioningReject: + // TODO + default: + return fmt.Errorf("ue Policy Delivery Service decode Fail: MsgType[%d] doesn't exist", + u.GetHeaderMessageType()) + } + return nil +} + +// TODO: add other Encoding processes +func (u *UePolDeliverySer) UePolDeliverySerEncode() ([]byte, error) { + buf := bytes.NewBuffer(nil) + switch u.GetHeaderMessageType() { + case MsgTypeManageUEPolicyCommand: + if err := u.EncodeManageUEPolicyCommand(buf); err != nil { + return nil, err + } + case MsgTypeManageUEPolicyComplete: + if err := u.EncodeManageUEPolicyComplete(buf); err != nil { + return nil, err + } + case MsgTypeManageUEPolicyReject: + if err := u.EncodeManageUEPolicyReject(buf); err != nil { + return nil, err + } + case MsgTypeUEStateIndication: + // TODO + case MsgTypeUEPolicyProvisioningRequest: + // TODO + case MsgTypeUEPolicyProvisioningReject: + // TODO + default: + return nil, fmt.Errorf("ue Policy Delivery Service Encode Fail: MsgType[%d] doesn't exist", + u.GetHeaderMessageType()) + } + return buf.Bytes(), nil +} diff --git a/uePolicyContainer/UePolicyContainer_Instruction.go b/uePolicyContainer/UePolicyContainer_Instruction.go new file mode 100644 index 0000000..956a5cd --- /dev/null +++ b/uePolicyContainer/UePolicyContainer_Instruction.go @@ -0,0 +1,112 @@ +package uePolicyContainer + +import ( + "bytes" + "encoding/binary" + "io" +) + +type UEPolicySectionManagementSubListContents []Instruction + +type Instruction struct { + Len uint16 + Upsc uint16 // a UE policy section code (UPSC) containing a value assigned by the PCF. + UEPolicySectionContents UEPolicySectionContents +} + +func (u *UEPolicySectionManagementSubListContents) AppendInstruction(ins Instruction) { + *u = append(*u, ins) +} + +// Marshal Strcuture into byte slice +func (u *UEPolicySectionManagementSubListContents) MarshalBinary() ([]byte, error) { + buf := bytes.NewBuffer(nil) + for i, instruct := range *u { + if instrucBuf, err := instruct.MarshalBinary(); err != nil { + return nil, err + } else { + _, err = buf.Write(instrucBuf) + if err != nil { + return nil, err + } + (*u)[i] = instruct + } + } + return buf.Bytes(), nil +} + +// UnMarshal byte slice into Strctute +func (u *UEPolicySectionManagementSubListContents) UnmarshalBinary(b []byte) error { + // initial an empty slice that length and capacity = 0 + // *u = make(UEPolicySectionManagementSubListContents, 0) + buf := bytes.NewBuffer(b) + for { + if instrcut, err := parseInstruction(buf); err != nil { + if err == io.EOF { + return nil + } else { + return err + } + } else { + *u = append(*u, *instrcut) + } + } +} + +func (i *Instruction) SetLen(length uint16) { + i.Len = length +} + +func (i *Instruction) GetLen() uint16 { + return i.Len +} + +func (i *Instruction) SetUpsc(upsc uint16) { + i.Upsc = upsc +} + +func (i *Instruction) GetUpsc() uint16 { + return i.Upsc +} + +func (i *Instruction) MarshalBinary() ([]byte, error) { + buf := bytes.NewBuffer(nil) + // Preprocess the content into byte slice, but append to buffer at the end + policySectionContentBuf, err := i.UEPolicySectionContents.MarshalBinary() + if err != nil { + return nil, err + } + i.SetLen(uint16(len(policySectionContentBuf) + 2)) + + // len + if err := binary.Write(buf, binary.BigEndian, i.Len); err != nil { + return nil, err + } + // UPSC + if err := binary.Write(buf, binary.BigEndian, i.Upsc); err != nil { + return nil, err + } + // Policy Section Content + if _, err := buf.Write(policySectionContentBuf); err != nil { + return nil, err + } + return buf.Bytes(), nil +} + +func parseInstruction(buf *bytes.Buffer) (*Instruction, error) { + var instruction Instruction + // Len + if err := binary.Read(buf, binary.BigEndian, &instruction.Len); err != nil { + return nil, err + } + // UPSC + if err := binary.Read(buf, binary.BigEndian, &instruction.Upsc); err != nil { + return nil, err + } + // Ue policy section contents + if err := instruction.UEPolicySectionContents.UnmarshalBinary(buf.Next(int(instruction.Len) - 2)); err != nil { + return nil, err + } + + return &instruction, nil +} diff --git a/uePolicyContainer/UePolicyContainer_ManageUEPolicyCommand.go b/uePolicyContainer/UePolicyContainer_ManageUEPolicyCommand.go new file mode 100644 index 0000000..8bbfa5c --- /dev/null +++ b/uePolicyContainer/UePolicyContainer_ManageUEPolicyCommand.go @@ -0,0 +1,106 @@ +package uePolicyContainer + +import ( + "bytes" + "encoding/binary" + "errors" + + "github.com/free5gc/nas/nasType" +) + +// TS24.501 v17.7.1, sec D.5.1 +type ManageUEPolicyCommand struct { + nasType.PTI + UePolicyDeliveryServiceMsgType + UEPolicySectionManagementList + *UEPolicyNetworkClassmark +} + +func NewManageUEPolicyCommand(msgType uint8) (manageUEPolicyCommand *ManageUEPolicyCommand) { + manageUEPolicyCommand = &ManageUEPolicyCommand{} + manageUEPolicyCommand.UePolicyDeliveryServiceMsgType.SetMessageIdentity(msgType) + return manageUEPolicyCommand +} + +func (m *ManageUEPolicyCommand) EncodeManageUEPolicyCommand(buffer *bytes.Buffer) error { + if err := binary.Write(buffer, binary.BigEndian, m.PTI.Octet); err != nil { + return err + } + if err := binary.Write(buffer, binary.BigEndian, m.UePolicyDeliveryServiceMsgType.Octet); err != nil { + return err + } + // structure: UEPolicySectionManagementList + { + if err := binary.Write(buffer, binary.BigEndian, m.UEPolicySectionManagementList.GetIei()); err != nil { + return err + } + if err := binary.Write(buffer, binary.BigEndian, m.UEPolicySectionManagementList.GetLen()); err != nil { + return err + } + if err := binary.Write(buffer, binary.BigEndian, + m.UEPolicySectionManagementList.GetUEPolicySectionManagementListContent()); err != nil { + return err + } + } + // Optinal structure: UEPolicyNetworkClassmark + if m.UEPolicyNetworkClassmark != nil { + if err := binary.Write(buffer, binary.BigEndian, m.UEPolicyNetworkClassmark.GetIei()); err != nil { + return err + } + if err := binary.Write(buffer, binary.BigEndian, m.UEPolicyNetworkClassmark.GetLen()); err != nil { + return err + } + if err := binary.Write(buffer, binary.BigEndian, m.UEPolicyNetworkClassmark.GetNSSUI()); err != nil { + return err + } + if err := binary.Write(buffer, binary.BigEndian, m.UEPolicyNetworkClassmark.GetSpare()); err != nil { + return err + } + } + return nil +} + +func (m *ManageUEPolicyCommand) DecodeManageUEPolicyCommand(byteArray []byte) error { + buffer := bytes.NewBuffer(byteArray) + if err := binary.Read(buffer, binary.BigEndian, &m.PTI.Octet); err != nil { + return err + } + if err := binary.Read(buffer, binary.BigEndian, &m.UePolicyDeliveryServiceMsgType.Octet); err != nil { + return err + } + + { // structure: UEPolicySectionManagementList + if err := binary.Read(buffer, binary.BigEndian, &m.UEPolicySectionManagementList.Iei); err != nil { + return err + } + if err := binary.Read(buffer, binary.BigEndian, &m.UEPolicySectionManagementList.Len); err != nil { + return err + } + m.UEPolicySectionManagementList.Buffer = make([]uint8, m.UEPolicySectionManagementList.Len) + if err := binary.Read(buffer, binary.BigEndian, + m.UEPolicySectionManagementList.Buffer[:m.UEPolicySectionManagementList.GetLen()]); err != nil { + return err + } + } + // optinal structure: UEPolicyNetworkClassmark + if buffer.Len() > 0 { + // initial pointer type element + m.UEPolicyNetworkClassmark = NewUEPolicyNetworkClassmark() + if err := binary.Read(buffer, binary.BigEndian, &m.UEPolicyNetworkClassmark.Iei); err != nil { + return err + } + if err := binary.Read(buffer, binary.BigEndian, &m.UEPolicyNetworkClassmark.Len); err != nil { + return err + } + if err := binary.Read(buffer, binary.BigEndian, &m.UEPolicyNetworkClassmark.NSSUI); err != nil { + return err + } + if err := binary.Read(buffer, binary.BigEndian, &m.UEPolicyNetworkClassmark.Spare); err != nil { + return err + } + if buffer.Len() > 0 { + return errors.New("deecode [Manage UE Policy Command] Error: nas msg out of range") + } + } + return nil +} diff --git a/uePolicyContainer/UePolicyContainer_ManageUEPolicyComplete.go b/uePolicyContainer/UePolicyContainer_ManageUEPolicyComplete.go new file mode 100644 index 0000000..54982aa --- /dev/null +++ b/uePolicyContainer/UePolicyContainer_ManageUEPolicyComplete.go @@ -0,0 +1,40 @@ +package uePolicyContainer + +import ( + "bytes" + "encoding/binary" + + "github.com/free5gc/nas/nasType" +) + +type ManageUEPolicyComplete struct { + nasType.PTI + UePolicyDeliveryServiceMsgType +} + +func NewManageUEPolicyComplete(msgType uint8) (manageUEPolicyComplete *ManageUEPolicyComplete) { + manageUEPolicyComplete = &ManageUEPolicyComplete{} + manageUEPolicyComplete.UePolicyDeliveryServiceMsgType.SetMessageIdentity(msgType) + return manageUEPolicyComplete +} + +func (m *ManageUEPolicyComplete) EncodeManageUEPolicyComplete(buffer *bytes.Buffer) error { + if err := binary.Write(buffer, binary.BigEndian, m.PTI.Octet); err != nil { + return err + } + if err := binary.Write(buffer, binary.BigEndian, m.UePolicyDeliveryServiceMsgType.Octet); err != nil { + return err + } + return nil +} + +func (m *ManageUEPolicyComplete) DecodeManageUEPolicyComplete(byteArray []byte) error { + buffer := bytes.NewBuffer(byteArray) + if err := binary.Read(buffer, binary.BigEndian, &m.PTI.Octet); err != nil { + return err + } + if err := binary.Read(buffer, binary.BigEndian, &m.UePolicyDeliveryServiceMsgType.Octet); err != nil { + return err + } + return nil +} diff --git a/uePolicyContainer/UePolicyContainer_ManageUEPolicyReject.go b/uePolicyContainer/UePolicyContainer_ManageUEPolicyReject.go new file mode 100644 index 0000000..37751b1 --- /dev/null +++ b/uePolicyContainer/UePolicyContainer_ManageUEPolicyReject.go @@ -0,0 +1,52 @@ +package uePolicyContainer + +import ( + "bytes" + "encoding/binary" + + "github.com/free5gc/nas/nasType" +) + +type ManageUEPolicyReject struct { + nasType.PTI + UePolicyDeliveryServiceMsgType + UEPolicySectionManagementResult +} + +func NewManageUEPolicyReject(msgType uint8) (manageUEPolicyReject *ManageUEPolicyReject) { + manageUEPolicyReject = &ManageUEPolicyReject{} + manageUEPolicyReject.UePolicyDeliveryServiceMsgType.SetMessageIdentity(msgType) + return manageUEPolicyReject +} + +func (m *ManageUEPolicyReject) EncodeManageUEPolicyReject(buffer *bytes.Buffer) error { + if err := binary.Write(buffer, binary.BigEndian, m.PTI.Octet); err != nil { + return err + } + if err := binary.Write(buffer, binary.BigEndian, m.UePolicyDeliveryServiceMsgType.Octet); err != nil { + return err + } + // UEPolicySectionManagementResult + uePolSecMngRsult, err := m.UEPolicySectionManagementResult.MarshalBinary() + if err != nil { + return err + } + if err := binary.Write(buffer, binary.BigEndian, uePolSecMngRsult); err != nil { + return err + } + return nil +} + +func (m *ManageUEPolicyReject) DecodeManageUEPolicyReject(byteArray []byte) error { + buffer := bytes.NewBuffer(byteArray) + if err := binary.Read(buffer, binary.BigEndian, &m.PTI.Octet); err != nil { + return err + } + if err := binary.Read(buffer, binary.BigEndian, &m.UePolicyDeliveryServiceMsgType.Octet); err != nil { + return err + } + if err := m.UEPolicySectionManagementResult.UnmarshalBinary(buffer); err != nil { + return err + } + return nil +} diff --git a/uePolicyContainer/UePolicyContainer_Result.go b/uePolicyContainer/UePolicyContainer_Result.go new file mode 100644 index 0000000..b33e279 --- /dev/null +++ b/uePolicyContainer/UePolicyContainer_Result.go @@ -0,0 +1,112 @@ +package uePolicyContainer + +import ( + "bytes" + "encoding/binary" + "io" +) + +type UEPolicySectionManagementSubResultContents []Result + +// Refer to TS23501 v17.7.1,Table D.6.3.1 +type Result struct { + Upsc uint16 // a UE policy section code (UPSC) containing a value assigned by the PCF. + // FailInstructionOrder: This field contains the binary encoding of the order of the failed instruction + // in the UE policy section management sublist. + FailInstructionOrder uint16 + // Cause: The receiving entity shall treat any other value as 0110 1111, "protocol error, unspecified". + Cause uint8 +} + +func (u *UEPolicySectionManagementSubResultContents) AppendResult(ins Result) { + *u = append(*u, ins) +} + +// Marshal Strcuture into byte slice +func (u *UEPolicySectionManagementSubResultContents) MarshalBinary() ([]byte, error) { + buf := bytes.NewBuffer(nil) + for i, result := range *u { + if resultBuf, err := result.MarshalBinary(); err != nil { + return nil, err + } else { + _, err = buf.Write(resultBuf) + if err != nil { + return nil, err + } + (*u)[i] = result + } + } + return buf.Bytes(), nil +} + +// UnMarshal byte slice into Strctute +func (u *UEPolicySectionManagementSubResultContents) UnmarshalBinary(b []byte) error { + buf := bytes.NewBuffer(b) + for { + if result, err := parseResult(buf); err != nil { + if err == io.EOF { + return nil + } else { + return err + } + } else { + *u = append(*u, *result) + } + } +} + +func NewResult() Result { + return Result{ + Cause: 0b01101111, + } +} + +func (r *Result) SetUpsc(upsc uint16) { + r.Upsc = upsc +} + +func (r *Result) GetUpsc() uint16 { + return r.Upsc +} + +func (r *Result) MarshalBinary() ([]byte, error) { + buf := bytes.NewBuffer(nil) + + // UPSC + if err := binary.Write(buf, binary.BigEndian, r.Upsc); err != nil { + return nil, err + } + // FailInstructionOrder + if err := binary.Write(buf, binary.BigEndian, r.FailInstructionOrder); err != nil { + return nil, err + } + // Cause + if r.Cause != 0b01101111 { + r.Cause = 0b01101111 + } + if err := binary.Write(buf, binary.BigEndian, r.Cause); err != nil { + return nil, err + } + return buf.Bytes(), nil +} + +func parseResult(buf *bytes.Buffer) (*Result, error) { + var result Result + // UPSC + if err := binary.Read(buf, binary.BigEndian, &result.Upsc); err != nil { + return nil, err + } + // FailInstructionOrder + if err := binary.Read(buf, binary.BigEndian, &result.FailInstructionOrder); err != nil { + return nil, err + } + // Ue policy section contents + if err := binary.Read(buf, binary.BigEndian, &result.Cause); err != nil { + return nil, err + } + if result.Cause != 0b01101111 { + result.Cause = 0b01101111 + } + + return &result, nil +} diff --git a/uePolicyContainer/UePolicyContainer_UEPolicyNetworkClassmark.go b/uePolicyContainer/UePolicyContainer_UEPolicyNetworkClassmark.go new file mode 100644 index 0000000..ebf2d82 --- /dev/null +++ b/uePolicyContainer/UePolicyContainer_UEPolicyNetworkClassmark.go @@ -0,0 +1,64 @@ +package uePolicyContainer + +import "errors" + +type UEPolicyNetworkClassmark struct { + Iei uint8 + Len uint8 + NSSUI uint8 // Non-subscribed SNPN signalled URSP handling indication + Spare uint8 // always set to zero +} + +func NewUEPolicyNetworkClassmark() (uEPolicyNetworkClassmark *UEPolicyNetworkClassmark) { + uEPolicyNetworkClassmark = &UEPolicyNetworkClassmark{} + uEPolicyNetworkClassmark.SetLen(2) + return uEPolicyNetworkClassmark +} + +// D.6.7 UE policy network classmark +// Iei Row, sBit, len = [], 8, 8 +func (a *UEPolicyNetworkClassmark) GetIei() uint8 { + return a.Iei +} + +// D.6.7 UE policy network classmark +// Iei Row, sBit, len = [], 8, 8 +func (a *UEPolicyNetworkClassmark) SetIei(iei uint8) { + a.Iei = iei +} + +// D.6.7 UE policy network classmark +// Len Row, sBit, len = [], 8, 8 +func (a *UEPolicyNetworkClassmark) GetLen() uint8 { + return a.Len +} + +// D.6.7 UE policy network classmark +// Len Row, sBit, len = [], 8, 8 +func (a *UEPolicyNetworkClassmark) SetLen(length uint8) { + a.Len = length +} + +// D.6.7 UE policy network classmark +// Len Row, sBit, len = 1, 8, 8 +// Bits of NSSUI +// 0 UE is allowed to accept URSP signalled by non-subscribed SNPNs +// 1 UE is not allowed to accept URSP signalled by non-subscribed SNPNs +func (a *UEPolicyNetworkClassmark) SetNSSUI(allowAcceptURSP uint8) error { + if allowAcceptURSP == 0 { + a.NSSUI = 0 + } else if allowAcceptURSP == 1 { + a.NSSUI = 1 + } else { + return errors.New("only allowed to set NSSUI as 0 or 1") + } + return nil +} + +func (a *UEPolicyNetworkClassmark) GetNSSUI() uint8 { + return a.NSSUI +} + +func (a *UEPolicyNetworkClassmark) GetSpare() uint8 { + return a.Spare +} diff --git a/uePolicyContainer/UePolicyContainer_UEPolicyPartType.go b/uePolicyContainer/UePolicyContainer_UEPolicyPartType.go new file mode 100644 index 0000000..8276a0d --- /dev/null +++ b/uePolicyContainer/UePolicyContainer_UEPolicyPartType.go @@ -0,0 +1,20 @@ +package uePolicyContainer + +type UEPolicyPartType struct { + Octet uint8 +} + +const ( + UEPolicyPartType_URSP uint8 = 0x01 + UEPolicyPartType_ANDSP uint8 = 0x02 + UEPolicyPartType_V2XP uint8 = 0x03 + UEPolicyPartType_ProSeP uint8 = 0x04 +) + +func (u *UEPolicyPartType) SetPartType(partType byte) { + u.Octet = partType +} + +func (u *UEPolicyPartType) GetPartType() byte { + return u.Octet +} diff --git a/uePolicyContainer/UePolicyContainer_UEPolicyParts.go b/uePolicyContainer/UePolicyContainer_UEPolicyParts.go new file mode 100644 index 0000000..cc828db --- /dev/null +++ b/uePolicyContainer/UePolicyContainer_UEPolicyParts.go @@ -0,0 +1,118 @@ +package uePolicyContainer + +import ( + "bytes" + "encoding/binary" + "io" +) + +type UEPolicySectionContents []UEPolicyPart + +type UEPolicyPart struct { + Len uint16 + UEPolicyPartType UEPolicyPartType + UEPolicyPartContents []byte + // the encoding way of content is specifiled in other specs according to 'UEPolicyPartType', + // like "URSP encoding" sepific in TS 24.526 R17 +} + +func (u *UEPolicySectionContents) AppendUEPolicyPart(policyPart *UEPolicyPart) { + *u = append(*u, *policyPart) +} + +func (u *UEPolicySectionContents) MarshalBinary() ([]byte, error) { + buf := bytes.NewBuffer(nil) + for i, uePolicyPart := range *u { + if uePolicyPartBuf, err := uePolicyPart.MarshalBinary(); err != nil { + return nil, err + } else { + _, err = buf.Write(uePolicyPartBuf) + if err != nil { + return nil, err + } + (*u)[i] = uePolicyPart + } + } + return buf.Bytes(), nil +} + +func (u *UEPolicySectionContents) UnmarshalBinary(b []byte) error { + buf := bytes.NewBuffer(b) + for { + if policyPart, err := parseUEPolicyPart(buf); err != nil { + if err == io.EOF { + break + } + return err + } else { + *u = append(*u, *policyPart) + } + } + return nil +} + +func (u *UEPolicyPart) SetLen(length uint16) { + u.Len = length +} + +func (u *UEPolicyPart) SetLen_byContent() uint16 { + var ctnLen uint16 + // UEPolicyPartType + ctnLen = uint16(1) + // UEPolicyPartContents + ctnLen += uint16(len(u.UEPolicyPartContents)) + u.Len = ctnLen + return ctnLen +} + +func (u *UEPolicyPart) GetLen() uint16 { + return u.Len +} + +func (u *UEPolicyPart) SetPartContent(encoding_content []uint8) { + u.UEPolicyPartContents = encoding_content +} + +func (u *UEPolicyPart) GetPartContent() []uint8 { + return u.UEPolicyPartContents +} + +func (u *UEPolicyPart) MarshalBinary() ([]byte, error) { + buf := bytes.NewBuffer(nil) + // len + if u.Len == 0 { + _ = u.SetLen_byContent() + } + if err := binary.Write(buf, binary.BigEndian, u.Len); err != nil { + return nil, err + } + // UE policy part type + if err := binary.Write(buf, binary.BigEndian, u.UEPolicyPartType); err != nil { + return nil, err + } + // UE Policy Part Contents + if err := binary.Write(buf, binary.BigEndian, u.UEPolicyPartContents); err != nil { + return nil, err + } + return buf.Bytes(), nil +} + +func parseUEPolicyPart(buf *bytes.Buffer) (*UEPolicyPart, error) { + var uEPolicyPart UEPolicyPart + // len + if err := binary.Read(buf, binary.BigEndian, &uEPolicyPart.Len); err != nil { + return nil, err + } + + // UEPolicyPartType + if err := binary.Read(buf, binary.BigEndian, &uEPolicyPart.UEPolicyPartType); err != nil { + return nil, err + } + + // UEPolicyPartContents + uEPolicyPart.UEPolicyPartContents = make([]byte, uEPolicyPart.GetLen()-1) + if err := binary.Read(buf, binary.BigEndian, uEPolicyPart.UEPolicyPartContents[:uEPolicyPart.GetLen()-1]); err != nil { + return nil, err + } + return &uEPolicyPart, nil +} diff --git a/uePolicyContainer/UePolicyContainer_UEPolicySectionManagementList.go b/uePolicyContainer/UePolicyContainer_UEPolicySectionManagementList.go new file mode 100644 index 0000000..2ee7911 --- /dev/null +++ b/uePolicyContainer/UePolicyContainer_UEPolicySectionManagementList.go @@ -0,0 +1,85 @@ +package uePolicyContainer + +import ( + "bytes" + "encoding/binary" +) + +// refer to TS24501 v17, section D.6.2 +type UEPolicySectionManagementList struct { + Iei uint8 + Len uint16 + Buffer []uint8 +} + +func NewUEPolicySectionManagementList(iei uint8) (uEPolicySectionManagementList *UEPolicySectionManagementList) { + uEPolicySectionManagementList = &UEPolicySectionManagementList{} + uEPolicySectionManagementList.SetIei(iei) + return uEPolicySectionManagementList +} + +func (u *UEPolicySectionManagementList) MarshalBinary() ([]uint8, error) { + buf := bytes.NewBuffer(nil) + if err := binary.Write(buf, binary.BigEndian, u.Iei); err != nil { + return nil, err + } + if err := binary.Write(buf, binary.BigEndian, u.Len); err != nil { + return nil, err + } + if err := binary.Write(buf, binary.BigEndian, u.Buffer); err != nil { + return nil, err + } + return buf.Bytes(), nil +} + +func (u *UEPolicySectionManagementList) UnmarshalBinary(buf *bytes.Buffer) error { + if err := binary.Read(buf, binary.BigEndian, &u.Iei); err != nil { + return err + } + if err := binary.Read(buf, binary.BigEndian, &u.Len); err != nil { + return err + } + u.Buffer = make([]uint8, u.Len) + if err := binary.Read(buf, binary.BigEndian, u.Buffer[:u.Len]); err != nil { + return err + } + return nil +} + +// UEPolicySectionManagementList element D.6.2.1 +// Iei Row, sBit, len = [], 8, 8 +func (a *UEPolicySectionManagementList) GetIei() uint8 { + return a.Iei +} + +// UEPolicySectionManagementList element D.6.2.1 +// Iei Row, sBit, len = [], 8, 8 +func (a *UEPolicySectionManagementList) SetIei(iei uint8) { + a.Iei = iei +} + +// UEPolicySectionManagementList element D.6.2.1 +// Len Row, sBit, len = [], 8, 16 +func (a *UEPolicySectionManagementList) GetLen() uint16 { + return a.Len +} + +// UEPolicySectionManagementList element D.6.2.1 +// Len Row, sBit, len = [], 8, 16 +func (a *UEPolicySectionManagementList) SetLen(length uint16) { + a.Len = length +} + +// UEPolicySectionManagementList element D.6.2.1 +// QoSFlowDescriptions Row, sBit, len = [0, 0], 8 , INF +func (a *UEPolicySectionManagementList) GetUEPolicySectionManagementListContent() (ctnByte []uint8) { + ctnByte = make([]uint8, len(a.Buffer)) + copy(ctnByte, a.Buffer) + return ctnByte +} + +// set a byte list(consit of one or many sublist) to list content +func (a *UEPolicySectionManagementList) SetUEPolicySectionManagementListContent(ctnByte []uint8) { + a.Buffer = make([]uint8, len(ctnByte)) + copy(a.Buffer, ctnByte) +} diff --git a/uePolicyContainer/UePolicyContainer_UEPolicySectionManagementResult.go b/uePolicyContainer/UePolicyContainer_UEPolicySectionManagementResult.go new file mode 100644 index 0000000..6fa9ff4 --- /dev/null +++ b/uePolicyContainer/UePolicyContainer_UEPolicySectionManagementResult.go @@ -0,0 +1,75 @@ +package uePolicyContainer + +import ( + "bytes" + "encoding/binary" +) + +// refer to TS24501 v17, section D.6.3 +type UEPolicySectionManagementResult struct { + Iei uint8 + Len uint16 + Buffer []uint8 +} + +func NewUEPolicySectionManagementResult(iei uint8) (uEPolicySectionManagementResult *UEPolicySectionManagementResult) { + uEPolicySectionManagementResult = &UEPolicySectionManagementResult{} + uEPolicySectionManagementResult.SetIei(iei) + return uEPolicySectionManagementResult +} + +func (u *UEPolicySectionManagementResult) MarshalBinary() ([]uint8, error) { + buf := bytes.NewBuffer(nil) + if err := binary.Write(buf, binary.BigEndian, u.Iei); err != nil { + return nil, err + } + if err := binary.Write(buf, binary.BigEndian, u.Len); err != nil { + return nil, err + } + if err := binary.Write(buf, binary.BigEndian, u.Buffer); err != nil { + return nil, err + } + return buf.Bytes(), nil +} + +func (u *UEPolicySectionManagementResult) UnmarshalBinary(buf *bytes.Buffer) error { + if err := binary.Read(buf, binary.BigEndian, &u.Iei); err != nil { + return err + } + if err := binary.Read(buf, binary.BigEndian, &u.Len); err != nil { + return err + } + u.Buffer = make([]uint8, u.Len) + if err := binary.Read(buf, binary.BigEndian, u.Buffer[:u.Len]); err != nil { + return err + } + return nil +} + +func (u *UEPolicySectionManagementResult) GetIei() uint8 { + return u.Iei +} + +func (u *UEPolicySectionManagementResult) SetIei(iei uint8) { + u.Iei = iei +} + +func (u *UEPolicySectionManagementResult) GetLen() uint16 { + return u.Len +} + +func (u *UEPolicySectionManagementResult) SetLen(length uint16) { + u.Len = length +} + +// UEPolicySectionManagementResult element D.6.3.1 +func (a *UEPolicySectionManagementResult) GetUEPolicySectionManagementResultContent() (ctnByte []uint8) { + ctnByte = make([]uint8, len(a.Buffer)) + copy(ctnByte, a.Buffer) + return +} + +func (a *UEPolicySectionManagementResult) SetUEPolicySectionManagementResultContent(ctnByte []uint8) { + a.Buffer = make([]uint8, len(ctnByte)) + copy(a.Buffer, ctnByte) +} diff --git a/uePolicyContainer/UePolicyContainer_UEPolicySectionManagementSubList.go b/uePolicyContainer/UePolicyContainer_UEPolicySectionManagementSubList.go new file mode 100644 index 0000000..ee65c8a --- /dev/null +++ b/uePolicyContainer/UePolicyContainer_UEPolicySectionManagementSubList.go @@ -0,0 +1,203 @@ +package uePolicyContainer + +import ( + "bytes" + "encoding/binary" + "fmt" + "io" +) + +type UEPolicySectionManagementListContent []UEPolicySectionManagementSubList + +type UEPolicySectionManagementSubList struct { + Len uint16 + PlmnDigit1 uint8 // ref D.6.2.3, PLMN1=MCC digit 2 + MCC digit 1 + PlmnDigit2 uint8 // PLMN2=MNC digit 3 + MCC digit 3 + PlmnDigit3 uint8 // PLMN3=MNC digit 2 + MNC digit 1 + Mcc *int // not specific in specm just recode the origin MCC before encoding + Mnc *int // not specific in specm just recode the origin MNC before encoding + UEPolicySectionManagementSubListContents UEPolicySectionManagementSubListContents + // a UE policy section code (UPSC) containing a unique value within the PLMN or SNPN selected by the PCF. + UpscGenerator IDGenerator +} + +func (u *UEPolicySectionManagementListContent) AppendSublist(sublist UEPolicySectionManagementSubList) { + *u = append(*u, sublist) +} + +// Marshal Strcuture into byte slice +func (u *UEPolicySectionManagementListContent) MarshalBinary() ([]byte, error) { + buf := bytes.NewBuffer(nil) + for i, sublist := range *u { + if sublistBuf, err := sublist.MarshalBinary(); err != nil { + return nil, err + } else { + _, err = buf.Write(sublistBuf) + if err != nil { + return nil, err + } + (*u)[i] = sublist + } + } + return buf.Bytes(), nil +} + +// UnMarshal byte slice into Strctute +func (u *UEPolicySectionManagementListContent) UnmarshalBinary(b []byte) error { + // initial an empty slice that length and capacity = 0 + // *u = make(UEPolicySectionManagementListContent, 0) + buf := bytes.NewBuffer(b) + for { + if sublist, err := parseUEPlcSublist(buf); err != nil { + if err == io.EOF { + return nil + } else { + return err + } + } else { + *u = append(*u, *sublist) + } + } +} + +func (u *UEPolicySectionManagementSubList) SetLen(length uint16) { + u.Len = length +} + +func (u *UEPolicySectionManagementSubList) GetLen() uint16 { + return u.Len +} + +func (u *UEPolicySectionManagementSubList) SetPlmnDigit(mcc, mnc int) error { + u.Mcc = &mcc + u.Mnc = &mnc + if *u.Mcc < 99 || *u.Mcc > 999 { + return fmt.Errorf("MCC must be positive 3-digit, mcc:%d", u.Mcc) + } + if *u.Mnc < 9 || *u.Mcc > 999 { + return fmt.Errorf("MCC must be positive 2 or 3-digit, mnc:%d", u.Mnc) + } + // PlmnDigit1 + u.PlmnDigit1 = (uint8((*u.Mcc%100)/10) << 4) | (uint8(*u.Mcc % 10)) + + // PlmnDigit2 + if *u.Mnc < 100 { + u.PlmnDigit2 = (0xF0) | (uint8(*u.Mcc / 100)) + } else { + u.PlmnDigit2 = (uint8(*u.Mnc/100) << 4) | (uint8(*u.Mcc / 100)) + } + + // PlmnDigit3 + u.PlmnDigit3 = (uint8((*u.Mnc%100)/10) << 4) | (uint8(*u.Mnc % 10)) + + return nil +} + +func (u *UEPolicySectionManagementSubList) GetPlmnDigit() (int, int) { + return *u.Mcc, *u.Mnc +} + +func (u *UEPolicySectionManagementSubList) MarshalBinary() ([]byte, error) { + buf := bytes.NewBuffer(nil) + // Preprocess the content to count for length, then encode length first and content last + contentByte, err := u.UEPolicySectionManagementSubListContents.MarshalBinary() + if err != nil { + return nil, err + } + // Set byte length of UEPolicySectionManagementSubList--plmn1、2、3+content length + u.SetLen(uint16(1 + 1 + 1 + len(contentByte))) + + // len + if err := binary.Write(buf, binary.BigEndian, u.Len); err != nil { + return nil, err + } + // PlmnDigit1 + if err := binary.Write(buf, binary.BigEndian, u.PlmnDigit1); err != nil { + return nil, err + } + // PlmnDigit2 + if err := binary.Write(buf, binary.BigEndian, u.PlmnDigit2); err != nil { + return nil, err + } + // PlmnDigit3 + if err := binary.Write(buf, binary.BigEndian, u.PlmnDigit3); err != nil { + return nil, err + } + // SubListContents + if _, err := buf.Write(contentByte); err != nil { + return nil, err + } + + return buf.Bytes(), nil +} + +func parseUEPlcSublist(buf *bytes.Buffer) (*UEPolicySectionManagementSubList, error) { + var u UEPolicySectionManagementSubList + + // Len + if err := binary.Read(buf, binary.BigEndian, &u.Len); err != nil { + return nil, err + } + + // PlmnDigit1 + if err := binary.Read(buf, binary.BigEndian, &u.PlmnDigit1); err != nil { + return nil, err + } + var mccDig1, mccDig2 uint8 + mccDig1 = (0x0F) & u.PlmnDigit1 + mccDig2 = ((0xF0) & u.PlmnDigit1) >> 4 + if mccDig1 > 9 { + return nil, fmt.Errorf("MCC Digit1 larger than 9") + } + if mccDig2 > 9 { + return nil, fmt.Errorf("MCC Digit2 larger than 9") + } + + // PlmnDigit2 + if err := binary.Read(buf, binary.BigEndian, &u.PlmnDigit2); err != nil { + return nil, err + } + var mncDig3, mccDig3 uint8 + mccDig3 = (0x0F) & u.PlmnDigit2 + mncDig3 = ((0xF0) & u.PlmnDigit2) >> 4 + if mccDig3 > 9 { + return nil, fmt.Errorf("MCC Digit3 larger than 9") + } + if mncDig3 > 9 { + if mncDig3 == 15 { + // If a network operator decides to use only two digits in the MNC, MNC digit 3 shall be coded as "1111" + mncDig3 = 0 + } else { + return nil, fmt.Errorf("MNC Digit3 larger than 9") + } + } + + // PlmnDigit3 + if err := binary.Read(buf, binary.BigEndian, &u.PlmnDigit3); err != nil { + return nil, err + } + var mncDig1, mncDig2 uint8 + mncDig1 = (0x0F) & u.PlmnDigit3 + mncDig2 = ((0xF0) & u.PlmnDigit3) >> 4 + if mncDig1 > 9 { + return nil, fmt.Errorf("MCC Digit1 larger than 9") + } + if mncDig2 > 9 { + return nil, fmt.Errorf("MNC Digit2 larger than 9") + } + u.Mcc = new(int) + u.Mnc = new(int) + *u.Mcc = int(mccDig1) + int(mccDig2)*10 + int(mccDig3)*100 + *u.Mnc = int(mncDig1) + int(mncDig2)*10 + int(mncDig3)*100 + + // UEPolicySectionManagementSubListContents + if int(u.Len-3) < 0 { + return nil, fmt.Errorf("UEPolicySectionManagementSubList length should not less than 3") + } + err := u.UEPolicySectionManagementSubListContents.UnmarshalBinary(buf.Next(int(u.Len - 3))) + if err != nil { + return nil, err + } + + return &u, nil +} diff --git a/uePolicyContainer/UePolicyContainer_UEPolicySectionManagementSubResult.go b/uePolicyContainer/UePolicyContainer_UEPolicySectionManagementSubResult.go new file mode 100644 index 0000000..ce11a1d --- /dev/null +++ b/uePolicyContainer/UePolicyContainer_UEPolicySectionManagementSubResult.go @@ -0,0 +1,201 @@ +package uePolicyContainer + +import ( + "bytes" + "encoding/binary" + "fmt" + "io" +) + +type UEPolicySectionManagementResultContent []UEPolicySectionManagementSubResult + +type UEPolicySectionManagementSubResult struct { + Len uint16 + PlmnDigit1 uint8 // ref D.6.3.3, PLMN1=MCC digit 2 + MCC digit 1 + PlmnDigit2 uint8 // PLMN2=MNC digit 3 + MCC digit 3 + PlmnDigit3 uint8 // PLMN3=MNC digit 2 + MNC digit 1 + Mcc *int // not specific in specm just recode the origin MCC before encoding + Mnc *int // not specific in specm just recode the origin MNC before encoding + UEPolicySectionManagementSubResultContents UEPolicySectionManagementSubResultContents + // a UE policy section code (UPSC) containing a unique value within the PLMN or SNPN selected by the PCF. + UpscGenerator IDGenerator +} + +func (u *UEPolicySectionManagementResultContent) AppendSublist(sublist UEPolicySectionManagementSubResult) { + *u = append(*u, sublist) +} + +// Marshal Strcuture into byte slice +func (u *UEPolicySectionManagementResultContent) MarshalBinary() ([]byte, error) { + buf := bytes.NewBuffer(nil) + for i, sublist := range *u { + if sublistBuf, err := sublist.MarshalBinary(); err != nil { + return nil, err + } else { + _, err = buf.Write(sublistBuf) + if err != nil { + return nil, err + } + (*u)[i] = sublist + } + } + return buf.Bytes(), nil +} + +// UnMarshal byte slice into Strctute +func (u *UEPolicySectionManagementResultContent) UnmarshalBinary(b []byte) error { + buf := bytes.NewBuffer(b) + for { + if subResult, err := parseUEPlcSubResult(buf); err != nil { + if err == io.EOF { + return nil + } else { + return err + } + } else { + *u = append(*u, *subResult) + } + } +} + +func (u *UEPolicySectionManagementSubResult) SetLen(length uint16) { + u.Len = length +} + +func (u *UEPolicySectionManagementSubResult) GetLen() uint16 { + return u.Len +} + +func (u *UEPolicySectionManagementSubResult) SetPlmnDigit(mcc, mnc int) error { + u.Mcc = &mcc + u.Mnc = &mnc + if *u.Mcc < 99 || *u.Mcc > 999 { + return fmt.Errorf("MCC must be positive 3-digit, mcc:%d", u.Mcc) + } + if *u.Mnc < 9 || *u.Mcc > 999 { + return fmt.Errorf("MCC must be positive 2 or 3-digit, mnc:%d", u.Mnc) + } + // PlmnDigit1 + u.PlmnDigit1 = (uint8((*u.Mcc%100)/10) << 4) | (uint8(*u.Mcc % 10)) + + // PlmnDigit2 + if *u.Mnc < 100 { + u.PlmnDigit2 = (0xF0) | (uint8(*u.Mcc / 100)) + } else { + u.PlmnDigit2 = (uint8(*u.Mnc/100) << 4) | (uint8(*u.Mcc / 100)) + } + + // PlmnDigit3 + u.PlmnDigit3 = (uint8((*u.Mnc%100)/10) << 4) | (uint8(*u.Mnc % 10)) + + return nil +} + +func (u *UEPolicySectionManagementSubResult) GetPlmnDigit() (int, int) { + return *u.Mcc, *u.Mnc +} + +func (u *UEPolicySectionManagementSubResult) MarshalBinary() ([]byte, error) { + buf := bytes.NewBuffer(nil) + // Preprocess the content to count for length, then encode length first and content last + contentByte, err := u.UEPolicySectionManagementSubResultContents.MarshalBinary() + if err != nil { + return nil, err + } + // Set byte length of UEPolicySectionManagementSubResult--plmn1、2、3+content length + u.SetLen(uint16(1 + 1 + 1 + len(contentByte))) + + // len + if err := binary.Write(buf, binary.BigEndian, u.Len); err != nil { + return nil, err + } + // PlmnDigit1 + if err := binary.Write(buf, binary.BigEndian, u.PlmnDigit1); err != nil { + return nil, err + } + // PlmnDigit2 + if err := binary.Write(buf, binary.BigEndian, u.PlmnDigit2); err != nil { + return nil, err + } + // PlmnDigit3 + if err := binary.Write(buf, binary.BigEndian, u.PlmnDigit3); err != nil { + return nil, err + } + // SubListContents + if _, err := buf.Write(contentByte); err != nil { + return nil, err + } + + return buf.Bytes(), nil +} + +func parseUEPlcSubResult(buf *bytes.Buffer) (*UEPolicySectionManagementSubResult, error) { + var u UEPolicySectionManagementSubResult + + // Len + if err := binary.Read(buf, binary.BigEndian, &u.Len); err != nil { + return nil, err + } + + // PlmnDigit1 + if err := binary.Read(buf, binary.BigEndian, &u.PlmnDigit1); err != nil { + return nil, err + } + var mccDig1, mccDig2 uint8 + mccDig1 = (0x0F) & u.PlmnDigit1 + mccDig2 = ((0xF0) & u.PlmnDigit1) >> 4 + if mccDig1 > 9 { + return nil, fmt.Errorf("MCC Digit1 larger than 9") + } + if mccDig2 > 9 { + return nil, fmt.Errorf("MCC Digit2 larger than 9") + } + + // PlmnDigit2 + if err := binary.Read(buf, binary.BigEndian, &u.PlmnDigit2); err != nil { + return nil, err + } + var mncDig3, mccDig3 uint8 + mccDig3 = (0x0F) & u.PlmnDigit2 + mncDig3 = ((0xF0) & u.PlmnDigit2) >> 4 + if mccDig3 > 9 { + return nil, fmt.Errorf("MCC Digit3 larger than 9") + } + if mncDig3 > 9 { + if mncDig3 == 15 { + // If a network operator decides to use only two digits in the MNC, MNC digit 3 shall be coded as "1111" + mncDig3 = 0 + } else { + return nil, fmt.Errorf("MNC Digit3 larger than 9") + } + } + + // PlmnDigit3 + if err := binary.Read(buf, binary.BigEndian, &u.PlmnDigit3); err != nil { + return nil, err + } + var mncDig1, mncDig2 uint8 + mncDig1 = (0x0F) & u.PlmnDigit3 + mncDig2 = ((0xF0) & u.PlmnDigit3) >> 4 + if mncDig1 > 9 { + return nil, fmt.Errorf("MCC Digit1 larger than 9") + } + if mncDig2 > 9 { + return nil, fmt.Errorf("MNC Digit2 larger than 9") + } + u.Mcc = new(int) + u.Mnc = new(int) + *u.Mcc = int(mccDig1) + int(mccDig2)*10 + int(mccDig3)*100 + *u.Mnc = int(mncDig1) + int(mncDig2)*10 + int(mncDig3)*100 + + // UEPolicySectionManagementSubResultContents + if int(u.Len-3) < 0 { + return nil, fmt.Errorf("UEPolicySectionManagementSubResult length should not less than 3") + } + err := u.UEPolicySectionManagementSubResultContents.UnmarshalBinary(buf.Next(int(u.Len - 3))) + if err != nil { + return nil, err + } + + return &u, nil +}