From 4c75f289479f7f34b42e08f2a1cead99644f6d01 Mon Sep 17 00:00:00 2001 From: Yoshiyuki Kurauchi Date: Sat, 30 Sep 2023 14:07:22 +0200 Subject: [PATCH] More helpers/better grouped IE handling --- README.md | 37 ++- ie/access-availability-information.go | 8 +- ie/activate-predefined-rules.go | 2 +- ie/activation-time.go | 8 +- ie/aggregated-urr-id.go | 11 +- ie/apn-dnn.go | 6 +- ie/application-id.go | 2 +- ie/application-instance-id.go | 2 +- ie/atsss-ll-control-information.go | 8 +- ie/atsss-ll-information.go | 8 +- ie/averaging-window.go | 11 +- ie/bar-id.go | 2 +- ie/bridge-management-information-container.go | 2 +- ie/cause.go | 2 +- ie/cp-function-features.go | 9 +- ie/create-bridge-info-for-tsc.go | 8 +- ie/cumulative-rate-ratio-measurement.go | 11 +- ie/cumulative-rate-ratio-threshold.go | 11 +- ie/data-network-access-identifier.go | 2 +- ie/data-status.go | 8 +- ie/deactivate-predefined-rules.go | 2 +- ie/deactivation-time.go | 8 +- ie/destination-interface.go | 8 +- ie/dl-buffering-suggested-packet-count.go | 9 +- ie/dl-data-packets-size.go | 6 +- ie/doc.go | 5 +- ie/dropped-dl-traffic-threshold.go | 7 +- ie/ds-tt-port-number.go | 11 +- ie/end-time.go | 8 +- ie/ethernet-filter-id.go | 11 +- ie/ethernet-filter-properties.go | 8 +- ie/ethernet-pdu-session-information.go | 2 +- ie/ethertype.go | 11 +- ie/event-quota.go | 11 +- ie/event-threshold.go | 11 +- ie/event-time-stamp.go | 8 +- ie/failed-rule-id.go | 5 +- ie/far-id.go | 11 +- ie/framed-ipv6-route.go | 2 +- ie/framed-route.go | 2 +- ie/framed-routing.go | 11 +- ie/gate-status.go | 8 +- ie/gtp-u-path-interface-type.go | 8 +- ie/ie.go | 309 +++++++----------- ie/ie_fuzz_test.go | 39 +++ ie/ie_grouped.go | 196 +++++++++++ ...ation_test.go => ie_time_duration_test.go} | 0 ie/inactivity-detection-time.go | 11 +- ie/ip-version.go | 8 +- ie/linked-urr-id.go | 11 +- ie/mar-id.go | 10 +- ie/measurement-information.go | 10 +- ie/measurement-method.go | 8 +- ie/metric.go | 11 +- ie/monitoring-time.go | 8 +- ie/mptcp-applicable-indication.go | 8 +- ie/mptcp-control-information.go | 8 +- ie/mt-edt-control-information.go | 8 +- ie/multiplier.go | 6 +- ie/network-instance.go | 2 +- ie/node-report-type.go | 9 +- ie/number-of-reports.go | 10 +- ie/nw-tt-port-number.go | 11 +- ie/oci-flags.go | 10 +- ie/offending-ie.go | 11 +- ...tion-and-detection-carry-on-information.go | 8 +- ie/pdn-type.go | 9 +- ie/pdr-id.go | 10 +- ie/pfcp-association-release-request.go | 2 +- ie/pfcpasreq-flags.go | 7 +- ie/pfcpasrsp-flags.go | 7 +- ie/pfcpaureq-flags.go | 2 +- ie/pfcpsereq-flags.go | 2 +- ie/pfcpsmreq-flags.go | 2 +- ie/pfcpsrreq-flags.go | 2 +- ie/pfcpsrrsp-flags.go | 2 +- ie/pmf-control-information.go | 8 +- ie/port-management-information-container.go | 2 +- ie/precedence.go | 10 +- ie/priority.go | 8 +- ie/proxying.go | 8 +- ie/qer-control-indications.go | 8 +- ie/qer-correlation-id.go | 10 +- ie/qer-id.go | 11 +- ie/qfi.go | 6 +- ie/qos-report-trigger.go | 8 +- ie/query-urr-reference.go | 11 +- ie/rds-configuration-information.go | 8 +- ie/recovery-time-stamp.go | 7 +- ie/report-type.go | 2 +- ie/reporting-frequency.go | 8 +- ...quested-access-availability-information.go | 8 +- ie/requested-clock-drift-information.go | 8 +- ie/requested-qos-monitoring.go | 8 +- ie/rqi.go | 8 +- ie/sequence-number.go | 11 +- ie/source-interface.go | 8 +- ie/srr-id.go | 8 +- ie/start-time.go | 8 +- ie/steering-functionality.go | 8 +- ie/steering-mode.go | 8 +- ie/subsequent-event-quota.go | 11 +- ie/subsequent-event-threshold.go | 11 +- ie/suggested-buffering-packets-count.go | 10 +- ie/time-of-first-packet.go | 8 +- ie/time-of-last-packet.go | 8 +- ie/traffic-endpoint-id.go | 10 +- ie/transport-level-marking.go | 10 +- ie/tsn-time-domain-number.go | 8 +- ie/ur-seqn.go | 11 +- ie/urr-id.go | 11 +- ie/usage-information.go | 8 +- ie/weight.go | 10 +- 113 files changed, 503 insertions(+), 899 deletions(-) create mode 100644 ie/ie_grouped.go rename ie/{ie_duration_test.go => ie_time_duration_test.go} (100%) diff --git a/README.md b/README.md index 423d3a9..da595fe 100644 --- a/README.md +++ b/README.md @@ -434,6 +434,15 @@ v, err := ni.NetworkInstance() In the example above, calling the `NetworkInstance()` method returns `"some.instance.example", nil`. However, if `ni` is not of type `ie.NetworkInstance` or the payload is not in right format, it returns `"", SomeError`. It's important to always check the returned error, as the value may be empty _as expected_. +The type of returned values are determined as friendly as possible for the built-in Go types. For example, `QuotaValidityTime()` returns the value as `time.Duration`. In the cases that this is undesirable, such as when you need to pass the raw value to another node, you can use `ValueAsUint32()` method instead, which returns the value as `uint32`. This could also be useful for handling vendor-specific IEs whose value retrieval methods are not available in this package. Available `ValueAs`-methods are `ValueAsUin8()`, `ValueAsUint16()`, `ValueAsUint32()`, `ValueAsUint64()`, `ValueAsString()`, and `ValueAsFQDN()`. + +```go +qvTime := ie.NewQuotaValidityTime(10 * time.Second) + +vDuration, err := qvTime.QuotaValidityTime() +vUint32, err := qvTime.ValueAsUint32() +``` + For IEs with more complex payloads, such as F-TEID, calling the `` method returns a `Fields` struct containing the values in its fields. ```go @@ -444,7 +453,7 @@ teid := fteidFields.TEID // TEID as uint32 v4 := fteidFields.IPv4Address // IPv4 address as net.IP ``` -For grouped IEs, calling `` method returns a list of IEs contained in the grouped IE. +For grouped IEs, accesing the `ChildIEs` field is the best way to retrieve the list of IEs contained. If you are not sure that the IE is already parsed, you can use `ValueAsGrouped()` method instead, which parses the payload into `[]*IE` and returns it if the `ChildIEs` field is empty. ```go cpdrIE := ie.NewCreatePDR( @@ -452,27 +461,41 @@ cpdrIE := ie.NewCreatePDR( // ... ) -cpdrChildren, err := cpdrIE.CreatePDR() // `[]*IE` containing IEs in CreatePDR IE +// most efficient way +cpdrChildren := cpdrIE.ChildIEs +// or use this if you are not sure that the IE is already parsed +cpdrChildren, err := cpdrIE.ValueAsGrouped() +``` + +_NOTE: if you have called `ie.Parse`, the child IEs are already parsed._ + +_To determine if an IE is grouped or not, this package uses the `defaultGroupedIEMap` in `ie_grouped.go`, which contains the list of grouped IEs. You can add your own IE type to this map using `ie.AddGroupedIEType()` function, or you can change the entire logic to determine if an IE is grouped or not by setting your own function to `ie.SetIsGroupedFun` function._ + +`` method is also available for consistency with non-grouped IEs, but it is not recommended to use it as it always parses the payload into `[]*IE` and returns it though the `ChildIEs` field is already populated. In the rare case that the payload can be modified after the IE is created or parsed, this method could be useful. + +```go +cpdrChildren, err := cpdrIE.CreatePDR() ``` -For convenience, helper methods of the child IEs can be called directly on the grouped IE. +For convenience, helper methods of the child IEs can be called directly on the grouped IE, or you can call `FindByType()` method to get the child IE of the specified type. ```go pdrID, err := cpdrIE.PDRID() + +// or +pdrID, err := cpdrIE.FindByType(ie.PDRID) ``` -This is useful when you only need a small number of IEs within a grouped IE. Since it calls `CreatePDR()` internally, retrieving everything using the child IE's method is very inefficient. When you need to check the value of many IEs, it is recommended to use the former method and iterate over the list of IEs in your own code. +This is useful when you only need a small number of IEs within a grouped IE. Since it iterates over all child IEs internally, retrieving everything using these method is very inefficient. When you need to retrieve the value of multiple IEs, it is recommended to iterate over the list of child IEs in your own code. ```go -cpdrChildren, err := cpdr.CreatePDR() - var ( pdrID uint16 farID uint32 // ... ) -for _, i := range cpdrChildren { +for _, i := range cpdrIE.ChildIEs { switch i.Type { case ie.PDRID: v, err = i.PDRID() diff --git a/ie/access-availability-information.go b/ie/access-availability-information.go index 9a0a770..94ac71d 100644 --- a/ie/access-availability-information.go +++ b/ie/access-availability-information.go @@ -4,8 +4,6 @@ package ie -import "io" - // AccessType definitions. const ( AccessType3GPP uint8 = 0 @@ -25,13 +23,9 @@ func NewAccessAvailabilityInformation(status, atype uint8) *IE { // AccessAvailabilityInformation returns AccessAvailabilityInformation in uint8 if the type of IE matches. func (i *IE) AccessAvailabilityInformation() (uint8, error) { - if len(i.Payload) < 1 { - return 0, io.ErrUnexpectedEOF - } - switch i.Type { case AccessAvailabilityInformation: - return i.Payload[0], nil + return i.ValueAsUint8() case AccessAvailabilityReport: ies, err := i.AccessAvailabilityReport() if err != nil { diff --git a/ie/activate-predefined-rules.go b/ie/activate-predefined-rules.go index d66e43d..5912c8a 100644 --- a/ie/activate-predefined-rules.go +++ b/ie/activate-predefined-rules.go @@ -13,7 +13,7 @@ func NewActivatePredefinedRules(name string) *IE { func (i *IE) ActivatePredefinedRules() (string, error) { switch i.Type { case ActivatePredefinedRules: - return string(i.Payload), nil + return i.ValueAsString() case CreatePDR: ies, err := i.CreatePDR() if err != nil { diff --git a/ie/activation-time.go b/ie/activation-time.go index ea737d1..2ddd4ad 100644 --- a/ie/activation-time.go +++ b/ie/activation-time.go @@ -5,8 +5,6 @@ package ie import ( - "encoding/binary" - "io" "time" ) @@ -18,13 +16,9 @@ func NewActivationTime(ts time.Time) *IE { // ActivationTime returns ActivationTime in time.Time if the type of IE matches. func (i *IE) ActivationTime() (time.Time, error) { - if len(i.Payload) < 4 { - return time.Time{}, io.ErrUnexpectedEOF - } - switch i.Type { case ActivationTime: - return time.Unix(int64(binary.BigEndian.Uint32(i.Payload[0:4])-2208988800), 0), nil + return i.valueAs3GPPTimestamp() case CreatePDR: ies, err := i.CreatePDR() if err != nil { diff --git a/ie/aggregated-urr-id.go b/ie/aggregated-urr-id.go index 91f3db5..2d92031 100644 --- a/ie/aggregated-urr-id.go +++ b/ie/aggregated-urr-id.go @@ -4,11 +4,6 @@ package ie -import ( - "encoding/binary" - "io" -) - // NewAggregatedURRID creates a new AggregatedURRID IE. func NewAggregatedURRID(id uint32) *IE { return newUint32ValIE(AggregatedURRID, id) @@ -18,11 +13,7 @@ func NewAggregatedURRID(id uint32) *IE { func (i *IE) AggregatedURRID() (uint32, error) { switch i.Type { case AggregatedURRID: - if len(i.Payload) < 4 { - return 0, io.ErrUnexpectedEOF - } - - return binary.BigEndian.Uint32(i.Payload[0:4]), nil + return i.ValueAsUint32() case AggregatedURRs: ies, err := i.AggregatedURRs() if err != nil { diff --git a/ie/apn-dnn.go b/ie/apn-dnn.go index 6707477..14dfb82 100644 --- a/ie/apn-dnn.go +++ b/ie/apn-dnn.go @@ -4,10 +4,6 @@ package ie -import ( - "github.com/wmnsk/go-pfcp/internal/utils" -) - // NewAPNDNN creates a new APNDNN IE. func NewAPNDNN(apn string) *IE { return newFQDNIE(APNDNN, apn) @@ -19,7 +15,7 @@ func (i *IE) APNDNN() (string, error) { return "", &InvalidTypeError{Type: i.Type} } - return utils.DecodeFQDN(i.Payload), nil + return i.ValueAsFQDN() } // MustAPNDNN returns APNDNN in string, ignoring errors. diff --git a/ie/application-id.go b/ie/application-id.go index 58ad84d..b652453 100644 --- a/ie/application-id.go +++ b/ie/application-id.go @@ -13,7 +13,7 @@ func NewApplicationID(instance string) *IE { func (i *IE) ApplicationID() (string, error) { switch i.Type { case ApplicationID: - return string(i.Payload), nil + return i.ValueAsString() case CreatePDR: ies, err := i.CreatePDR() if err != nil { diff --git a/ie/application-instance-id.go b/ie/application-instance-id.go index d1a5834..c7d1fe7 100644 --- a/ie/application-instance-id.go +++ b/ie/application-instance-id.go @@ -13,7 +13,7 @@ func NewApplicationInstanceID(id string) *IE { func (i *IE) ApplicationInstanceID() (string, error) { switch i.Type { case ApplicationInstanceID: - return string(i.Payload), nil + return i.ValueAsString() case ApplicationDetectionInformation: ies, err := i.ApplicationDetectionInformation() if err != nil { diff --git a/ie/atsss-ll-control-information.go b/ie/atsss-ll-control-information.go index 1b0347c..cdc7b9b 100644 --- a/ie/atsss-ll-control-information.go +++ b/ie/atsss-ll-control-information.go @@ -4,8 +4,6 @@ package ie -import "io" - // NewATSSSLLControlInformation creates a new ATSSSLLControlInformation IE. func NewATSSSLLControlInformation(lli uint8) *IE { return newUint8ValIE(ATSSSLLControlInformation, lli&0x01) @@ -13,13 +11,9 @@ func NewATSSSLLControlInformation(lli uint8) *IE { // ATSSSLLControlInformation returns ATSSSLLControlInformation in uint8 if the type of IE matches. func (i *IE) ATSSSLLControlInformation() (uint8, error) { - if len(i.Payload) < 1 { - return 0, io.ErrUnexpectedEOF - } - switch i.Type { case ATSSSLLControlInformation: - return i.Payload[0], nil + return i.ValueAsUint8() case ProvideATSSSControlInformation: ies, err := i.ProvideATSSSControlInformation() if err != nil { diff --git a/ie/atsss-ll-information.go b/ie/atsss-ll-information.go index 0e96d0d..f6c11bb 100644 --- a/ie/atsss-ll-information.go +++ b/ie/atsss-ll-information.go @@ -4,8 +4,6 @@ package ie -import "io" - // NewATSSSLLInformation creates a new ATSSSLLInformation IE. func NewATSSSLLInformation(lli uint8) *IE { return newUint8ValIE(ATSSSLLInformation, lli&0x01) @@ -13,13 +11,9 @@ func NewATSSSLLInformation(lli uint8) *IE { // ATSSSLLInformation returns ATSSSLLInformation in uint8 if the type of IE matches. func (i *IE) ATSSSLLInformation() (uint8, error) { - if len(i.Payload) < 1 { - return 0, io.ErrUnexpectedEOF - } - switch i.Type { case ATSSSLLInformation: - return i.Payload[0], nil + return i.ValueAsUint8() case ATSSSControlParameters: ies, err := i.ATSSSControlParameters() if err != nil { diff --git a/ie/averaging-window.go b/ie/averaging-window.go index caea211..139cecb 100644 --- a/ie/averaging-window.go +++ b/ie/averaging-window.go @@ -4,11 +4,6 @@ package ie -import ( - "encoding/binary" - "io" -) - // NewAveragingWindow creates a new AveragingWindow IE. func NewAveragingWindow(window uint32) *IE { return newUint32ValIE(AveragingWindow, window) @@ -16,13 +11,9 @@ func NewAveragingWindow(window uint32) *IE { // AveragingWindow returns AveragingWindow in uint32 if the type of IE matches. func (i *IE) AveragingWindow() (uint32, error) { - if len(i.Payload) < 4 { - return 0, io.ErrUnexpectedEOF - } - switch i.Type { case AveragingWindow: - return binary.BigEndian.Uint32(i.Payload[0:4]), nil + return i.ValueAsUint32() case CreateQER: ies, err := i.CreateQER() if err != nil { diff --git a/ie/bar-id.go b/ie/bar-id.go index caf79de..4680cf4 100644 --- a/ie/bar-id.go +++ b/ie/bar-id.go @@ -21,7 +21,7 @@ func (i *IE) BARID() (uint8, error) { return 0, io.ErrUnexpectedEOF } - return i.Payload[0], nil + return i.ValueAsUint8() case CreateFAR: ies, err := i.CreateFAR() if err != nil { diff --git a/ie/bridge-management-information-container.go b/ie/bridge-management-information-container.go index b6f26a8..6ba380b 100644 --- a/ie/bridge-management-information-container.go +++ b/ie/bridge-management-information-container.go @@ -13,7 +13,7 @@ func NewBridgeManagementInformationContainer(info string) *IE { func (i *IE) BridgeManagementInformationContainer() (string, error) { switch i.Type { case BridgeManagementInformationContainer: - return string(i.Payload), nil + return i.ValueAsString() case TSCManagementInformationWithinSessionModificationRequest, TSCManagementInformationWithinSessionModificationResponse, TSCManagementInformationWithinSessionReportRequest: diff --git a/ie/cause.go b/ie/cause.go index aaa173c..73a0cc2 100644 --- a/ie/cause.go +++ b/ie/cause.go @@ -41,5 +41,5 @@ func (i *IE) Cause() (uint8, error) { return 0, io.ErrUnexpectedEOF } - return i.Payload[0], nil + return i.ValueAsUint8() } diff --git a/ie/cp-function-features.go b/ie/cp-function-features.go index 0b9bec4..105763b 100644 --- a/ie/cp-function-features.go +++ b/ie/cp-function-features.go @@ -4,10 +4,6 @@ package ie -import ( - "io" -) - // NewCPFunctionFeatures creates a new CPFunctionFeatures IE. func NewCPFunctionFeatures(features uint8) *IE { return newUint8ValIE(CPFunctionFeatures, features) @@ -18,11 +14,8 @@ func (i *IE) CPFunctionFeatures() (uint8, error) { if i.Type != CPFunctionFeatures { return 0, &InvalidTypeError{Type: i.Type} } - if len(i.Payload) < 1 { - return 0, io.ErrUnexpectedEOF - } - return i.Payload[0], nil + return i.ValueAsUint8() } // HasLOAD reports whether an IE has LOAD bit. diff --git a/ie/create-bridge-info-for-tsc.go b/ie/create-bridge-info-for-tsc.go index 57d9677..43d6243 100644 --- a/ie/create-bridge-info-for-tsc.go +++ b/ie/create-bridge-info-for-tsc.go @@ -4,8 +4,6 @@ package ie -import "io" - // NewCreateBridgeInfoForTSC creates a new CreateBridgeInfoForTSC IE. func NewCreateBridgeInfoForTSC(bii uint8) *IE { return newUint8ValIE(CreateBridgeInfoForTSC, bii&0x01) @@ -13,13 +11,9 @@ func NewCreateBridgeInfoForTSC(bii uint8) *IE { // CreateBridgeInfoForTSC returns CreateBridgeInfoForTSC in uint8 if the type of IE matches. func (i *IE) CreateBridgeInfoForTSC() (uint8, error) { - if len(i.Payload) < 1 { - return 0, io.ErrUnexpectedEOF - } - switch i.Type { case CreateBridgeInfoForTSC: - return i.Payload[0], nil + return i.ValueAsUint8() default: return 0, &InvalidTypeError{Type: i.Type} } diff --git a/ie/cumulative-rate-ratio-measurement.go b/ie/cumulative-rate-ratio-measurement.go index b72833d..83929f0 100644 --- a/ie/cumulative-rate-ratio-measurement.go +++ b/ie/cumulative-rate-ratio-measurement.go @@ -4,11 +4,6 @@ package ie -import ( - "encoding/binary" - "io" -) - // NewCumulativeRateRatioMeasurement creates a new CumulativeRateRatioMeasurement IE. func NewCumulativeRateRatioMeasurement(measurement uint32) *IE { return newUint32ValIE(CumulativeRateRatioMeasurement, measurement) @@ -16,13 +11,9 @@ func NewCumulativeRateRatioMeasurement(measurement uint32) *IE { // CumulativeRateRatioMeasurement returns CumulativeRateRatioMeasurement in uint32 if the type of IE matches. func (i *IE) CumulativeRateRatioMeasurement() (uint32, error) { - if len(i.Payload) < 4 { - return 0, io.ErrUnexpectedEOF - } - switch i.Type { case CumulativeRateRatioMeasurement: - return binary.BigEndian.Uint32(i.Payload[0:4]), nil + return i.ValueAsUint32() default: return 0, &InvalidTypeError{Type: i.Type} } diff --git a/ie/cumulative-rate-ratio-threshold.go b/ie/cumulative-rate-ratio-threshold.go index 4a15b8e..f089481 100644 --- a/ie/cumulative-rate-ratio-threshold.go +++ b/ie/cumulative-rate-ratio-threshold.go @@ -4,11 +4,6 @@ package ie -import ( - "encoding/binary" - "io" -) - // NewCumulativeRateRatioThreshold creates a new CumulativeRateRatioThreshold IE. func NewCumulativeRateRatioThreshold(threshold uint32) *IE { return newUint32ValIE(CumulativeRateRatioThreshold, threshold) @@ -16,13 +11,9 @@ func NewCumulativeRateRatioThreshold(threshold uint32) *IE { // CumulativeRateRatioThreshold returns CumulativeRateRatioThreshold in uint32 if the type of IE matches. func (i *IE) CumulativeRateRatioThreshold() (uint32, error) { - if len(i.Payload) < 4 { - return 0, io.ErrUnexpectedEOF - } - switch i.Type { case CumulativeRateRatioThreshold: - return binary.BigEndian.Uint32(i.Payload[0:4]), nil + return i.ValueAsUint32() case ClockDriftControlInformation: ies, err := i.ClockDriftControlInformation() if err != nil { diff --git a/ie/data-network-access-identifier.go b/ie/data-network-access-identifier.go index 5ebb753..5956c78 100644 --- a/ie/data-network-access-identifier.go +++ b/ie/data-network-access-identifier.go @@ -13,7 +13,7 @@ func NewDataNetworkAccessIdentifier(id string) *IE { func (i *IE) DataNetworkAccessIdentifier() (string, error) { switch i.Type { case DataNetworkAccessIdentifier: - return string(i.Payload), nil + return i.ValueAsString() case ForwardingParameters: ies, err := i.ForwardingParameters() if err != nil { diff --git a/ie/data-status.go b/ie/data-status.go index 9ab6029..297f5ed 100644 --- a/ie/data-status.go +++ b/ie/data-status.go @@ -4,8 +4,6 @@ package ie -import "io" - // NewDataStatus creates a new DataStatus IE. func NewDataStatus(flag uint8) *IE { return newUint8ValIE(DataStatus, flag) @@ -13,13 +11,9 @@ func NewDataStatus(flag uint8) *IE { // DataStatus returns DataStatus in uint8 if the type of IE matches. func (i *IE) DataStatus() (uint8, error) { - if len(i.Payload) < 1 { - return 0, io.ErrUnexpectedEOF - } - switch i.Type { case DataStatus: - return i.Payload[0], nil + return i.ValueAsUint8() case DownlinkDataReport: ies, err := i.DownlinkDataReport() if err != nil { diff --git a/ie/deactivate-predefined-rules.go b/ie/deactivate-predefined-rules.go index 47cbe03..a30423f 100644 --- a/ie/deactivate-predefined-rules.go +++ b/ie/deactivate-predefined-rules.go @@ -13,7 +13,7 @@ func NewDeactivatePredefinedRules(name string) *IE { func (i *IE) DeactivatePredefinedRules() (string, error) { switch i.Type { case DeactivatePredefinedRules: - return string(i.Payload), nil + return i.ValueAsString() case UpdatePDR: ies, err := i.UpdatePDR() if err != nil { diff --git a/ie/deactivation-time.go b/ie/deactivation-time.go index 8fdc0b7..e6e99b8 100644 --- a/ie/deactivation-time.go +++ b/ie/deactivation-time.go @@ -5,8 +5,6 @@ package ie import ( - "encoding/binary" - "io" "time" ) @@ -18,13 +16,9 @@ func NewDeactivationTime(ts time.Time) *IE { // DeactivationTime returns DeactivationTime in time.Time if the type of IE matches. func (i *IE) DeactivationTime() (time.Time, error) { - if len(i.Payload) < 4 { - return time.Time{}, io.ErrUnexpectedEOF - } - switch i.Type { case DeactivationTime: - return time.Unix(int64(binary.BigEndian.Uint32(i.Payload[0:4])-2208988800), 0), nil + return i.valueAs3GPPTimestamp() case CreatePDR: ies, err := i.CreatePDR() if err != nil { diff --git a/ie/destination-interface.go b/ie/destination-interface.go index 5009599..1580567 100644 --- a/ie/destination-interface.go +++ b/ie/destination-interface.go @@ -4,8 +4,6 @@ package ie -import "io" - // Interface definitions. const ( DstInterfaceAccess uint8 = 0 @@ -23,13 +21,9 @@ func NewDestinationInterface(intf uint8) *IE { // DestinationInterface returns DestinationInterface in uint8 if the type of IE matches. func (i *IE) DestinationInterface() (uint8, error) { - if len(i.Payload) < 1 { - return 0, io.ErrUnexpectedEOF - } - switch i.Type { case DestinationInterface: - return i.Payload[0], nil + return i.ValueAsUint8() case ForwardingParameters: ies, err := i.ForwardingParameters() if err != nil { diff --git a/ie/dl-buffering-suggested-packet-count.go b/ie/dl-buffering-suggested-packet-count.go index 478dba1..e5e711c 100644 --- a/ie/dl-buffering-suggested-packet-count.go +++ b/ie/dl-buffering-suggested-packet-count.go @@ -5,7 +5,6 @@ package ie import ( - "encoding/binary" "io" "math" ) @@ -20,18 +19,14 @@ func NewDLBufferingSuggestedPacketCount(count uint16) *IE { // DLBufferingSuggestedPacketCount returns DLBufferingSuggestedPacketCount in uint16 if the type of IE matches. func (i *IE) DLBufferingSuggestedPacketCount() (uint16, error) { - if len(i.Payload) < 1 { - return 0, io.ErrUnexpectedEOF - } - switch i.Type { case DLBufferingSuggestedPacketCount: if i.Length == 1 { return uint16(i.Payload[0]), nil } - if i.Length >= 2 && len(i.Payload) >= 2 { - return binary.BigEndian.Uint16(i.Payload[0:2]), nil + if i.Length >= 2 { + return i.ValueAsUint16() } return 0, io.ErrUnexpectedEOF diff --git a/ie/dl-data-packets-size.go b/ie/dl-data-packets-size.go index 5523944..97fcffb 100644 --- a/ie/dl-data-packets-size.go +++ b/ie/dl-data-packets-size.go @@ -4,10 +4,6 @@ package ie -import ( - "encoding/binary" -) - // NewDLDataPacketsSize creates a new DLDataPacketsSize IE. func NewDLDataPacketsSize(size uint16) *IE { return newUint16ValIE(DLDataPacketsSize, size) @@ -21,7 +17,7 @@ func (i *IE) DLDataPacketsSize() (uint16, error) { switch i.Type { case DLDataPacketsSize: - return binary.BigEndian.Uint16(i.Payload[0:2]), nil + return i.ValueAsUint16() case DownlinkDataReport: ies, err := i.DownlinkDataReport() if err != nil { diff --git a/ie/doc.go b/ie/doc.go index a5394a4..144402a 100644 --- a/ie/doc.go +++ b/ie/doc.go @@ -2,5 +2,8 @@ // Use of this source code is governed by a MIT-style license that can be // found in the LICENSE file. -// Package ie provides encoding/decoding feature of PFCP Information Elements. +// Package ie provides the painless handling of of PFCP Information Elements. +// +// This document is a work in progress. +// Read the README.md at https://github.com/wmnsk/go-pfcp for further details. package ie diff --git a/ie/dropped-dl-traffic-threshold.go b/ie/dropped-dl-traffic-threshold.go index 19ecd20..499ab65 100644 --- a/ie/dropped-dl-traffic-threshold.go +++ b/ie/dropped-dl-traffic-threshold.go @@ -6,7 +6,6 @@ package ie import ( "encoding/binary" - "io" ) // NewDroppedDLTrafficThreshold creates a new DroppedDLTrafficThreshold IE. @@ -43,13 +42,9 @@ func NewDroppedDLTrafficThreshold(dlpa, dlby bool, packets, bytes uint64) *IE { // // TODO: implement! func (i *IE) DroppedDLTrafficThreshold() (uint8, error) { - if len(i.Payload) < 1 { - return 0, io.ErrUnexpectedEOF - } - switch i.Type { case DroppedDLTrafficThreshold: - return i.Payload[0], nil + return i.ValueAsUint8() case CreateURR: ies, err := i.CreateURR() if err != nil { diff --git a/ie/ds-tt-port-number.go b/ie/ds-tt-port-number.go index 30fcadc..6cbdb94 100644 --- a/ie/ds-tt-port-number.go +++ b/ie/ds-tt-port-number.go @@ -4,11 +4,6 @@ package ie -import ( - "encoding/binary" - "io" -) - // NewDSTTPortNumber creates a new DSTTPortNumber IE. func NewDSTTPortNumber(port uint32) *IE { return newUint32ValIE(DSTTPortNumber, port) @@ -16,13 +11,9 @@ func NewDSTTPortNumber(port uint32) *IE { // DSTTPortNumber returns DSTTPortNumber in uint32 if the type of IE matches. func (i *IE) DSTTPortNumber() (uint32, error) { - if len(i.Payload) < 4 { - return 0, io.ErrUnexpectedEOF - } - switch i.Type { case DSTTPortNumber: - return binary.BigEndian.Uint32(i.Payload[0:4]), nil + return i.ValueAsUint32() case CreatedBridgeInfoForTSC: ies, err := i.CreatedBridgeInfoForTSC() if err != nil { diff --git a/ie/end-time.go b/ie/end-time.go index 793faac..83329bc 100644 --- a/ie/end-time.go +++ b/ie/end-time.go @@ -5,8 +5,6 @@ package ie import ( - "encoding/binary" - "io" "time" ) @@ -18,13 +16,9 @@ func NewEndTime(ts time.Time) *IE { // EndTime returns EndTime in time.Time if the type of IE matches. func (i *IE) EndTime() (time.Time, error) { - if len(i.Payload) < 4 { - return time.Time{}, io.ErrUnexpectedEOF - } - switch i.Type { case EndTime: - return time.Unix(int64(binary.BigEndian.Uint32(i.Payload[0:4])-2208988800), 0), nil + return i.valueAs3GPPTimestamp() case UsageReportWithinSessionModificationResponse, UsageReportWithinSessionDeletionResponse, UsageReportWithinSessionReportRequest: diff --git a/ie/ethernet-filter-id.go b/ie/ethernet-filter-id.go index b79bdb3..dd7abf8 100644 --- a/ie/ethernet-filter-id.go +++ b/ie/ethernet-filter-id.go @@ -4,11 +4,6 @@ package ie -import ( - "encoding/binary" - "io" -) - // NewEthernetFilterID creates a new EthernetFilterID IE. func NewEthernetFilterID(id uint32) *IE { return newUint32ValIE(EthernetFilterID, id) @@ -16,13 +11,9 @@ func NewEthernetFilterID(id uint32) *IE { // EthernetFilterID returns EthernetFilterID in uint32 if the type of IE matches. func (i *IE) EthernetFilterID() (uint32, error) { - if len(i.Payload) < 4 { - return 0, io.ErrUnexpectedEOF - } - switch i.Type { case EthernetFilterID: - return binary.BigEndian.Uint32(i.Payload[0:4]), nil + return i.ValueAsUint32() case PDI: ies, err := i.PDI() if err != nil { diff --git a/ie/ethernet-filter-properties.go b/ie/ethernet-filter-properties.go index 7667c0e..215669a 100644 --- a/ie/ethernet-filter-properties.go +++ b/ie/ethernet-filter-properties.go @@ -4,8 +4,6 @@ package ie -import "io" - // NewEthernetFilterProperties creates a new EthernetFilterProperties IE. func NewEthernetFilterProperties(props uint8) *IE { return newUint8ValIE(EthernetFilterProperties, props) @@ -13,13 +11,9 @@ func NewEthernetFilterProperties(props uint8) *IE { // EthernetFilterProperties returns EthernetFilterProperties in uint8 if the type of IE matches. func (i *IE) EthernetFilterProperties() (uint8, error) { - if len(i.Payload) < 1 { - return 0, io.ErrUnexpectedEOF - } - switch i.Type { case EthernetFilterProperties: - return i.Payload[0], nil + return i.ValueAsUint8() case PDI: ies, err := i.PDI() if err != nil { diff --git a/ie/ethernet-pdu-session-information.go b/ie/ethernet-pdu-session-information.go index e9d540f..528bc86 100644 --- a/ie/ethernet-pdu-session-information.go +++ b/ie/ethernet-pdu-session-information.go @@ -13,7 +13,7 @@ func NewEthernetPDUSessionInformation(info uint8) *IE { func (i *IE) EthernetPDUSessionInformation() (uint8, error) { switch i.Type { case EthernetPDUSessionInformation: - return i.Payload[0], nil + return i.ValueAsUint8() case CreatePDR: ies, err := i.CreatePDR() if err != nil { diff --git a/ie/ethertype.go b/ie/ethertype.go index 6cc9e84..b7b3f07 100644 --- a/ie/ethertype.go +++ b/ie/ethertype.go @@ -4,11 +4,6 @@ package ie -import ( - "encoding/binary" - "io" -) - // NewEthertype creates a new Ethertype IE. func NewEthertype(typ uint16) *IE { return newUint16ValIE(Ethertype, typ) @@ -16,13 +11,9 @@ func NewEthertype(typ uint16) *IE { // Ethertype returns Ethertype in uint16 if the type of IE matches. func (i *IE) Ethertype() (uint16, error) { - if len(i.Payload) < 2 { - return 0, io.ErrUnexpectedEOF - } - switch i.Type { case Ethertype: - return binary.BigEndian.Uint16(i.Payload[0:2]), nil + return i.ValueAsUint16() case PDI: ies, err := i.PDI() if err != nil { diff --git a/ie/event-quota.go b/ie/event-quota.go index 12d2cd3..fad1af7 100644 --- a/ie/event-quota.go +++ b/ie/event-quota.go @@ -4,11 +4,6 @@ package ie -import ( - "encoding/binary" - "io" -) - // NewEventQuota creates a new EventQuota IE. func NewEventQuota(quota uint32) *IE { return newUint32ValIE(EventQuota, quota) @@ -16,13 +11,9 @@ func NewEventQuota(quota uint32) *IE { // EventQuota returns EventQuota in uint32 if the type of IE matches. func (i *IE) EventQuota() (uint32, error) { - if len(i.Payload) < 4 { - return 0, io.ErrUnexpectedEOF - } - switch i.Type { case EventQuota: - return binary.BigEndian.Uint32(i.Payload[0:4]), nil + return i.ValueAsUint32() case CreateURR: ies, err := i.CreateURR() if err != nil { diff --git a/ie/event-threshold.go b/ie/event-threshold.go index d92e621..30fe8ce 100644 --- a/ie/event-threshold.go +++ b/ie/event-threshold.go @@ -4,11 +4,6 @@ package ie -import ( - "encoding/binary" - "io" -) - // NewEventThreshold creates a new EventThreshold IE. func NewEventThreshold(quota uint32) *IE { return newUint32ValIE(EventThreshold, quota) @@ -16,13 +11,9 @@ func NewEventThreshold(quota uint32) *IE { // EventThreshold returns EventThreshold in uint32 if the type of IE matches. func (i *IE) EventThreshold() (uint32, error) { - if len(i.Payload) < 4 { - return 0, io.ErrUnexpectedEOF - } - switch i.Type { case EventThreshold: - return binary.BigEndian.Uint32(i.Payload[0:4]), nil + return i.ValueAsUint32() case CreateURR: ies, err := i.CreateURR() if err != nil { diff --git a/ie/event-time-stamp.go b/ie/event-time-stamp.go index a33a28d..d412c9a 100644 --- a/ie/event-time-stamp.go +++ b/ie/event-time-stamp.go @@ -5,8 +5,6 @@ package ie import ( - "encoding/binary" - "io" "time" ) @@ -18,13 +16,9 @@ func NewEventTimeStamp(ts time.Time) *IE { // EventTimeStamp returns EventTimeStamp in time.Time if the type of IE matches. func (i *IE) EventTimeStamp() (time.Time, error) { - if len(i.Payload) < 4 { - return time.Time{}, io.ErrUnexpectedEOF - } - switch i.Type { case EventTimeStamp: - return time.Unix(int64(binary.BigEndian.Uint32(i.Payload[0:4])-2208988800), 0), nil + return i.valueAs3GPPTimestamp() case UsageReportWithinSessionReportRequest: ies, err := i.UsageReport() if err != nil { diff --git a/ie/failed-rule-id.go b/ie/failed-rule-id.go index 7061a06..9639c06 100644 --- a/ie/failed-rule-id.go +++ b/ie/failed-rule-id.go @@ -43,11 +43,8 @@ func (i *IE) RuleIDType() (uint8, error) { if i.Type != FailedRuleID { return 0, &InvalidTypeError{Type: i.Type} } - if len(i.Payload) < 1 { - return 0, io.ErrUnexpectedEOF - } - return i.Payload[0], nil + return i.ValueAsUint8() } // FailedRuleID returns FailedRuleID in uint32 if the type of IE matches. diff --git a/ie/far-id.go b/ie/far-id.go index 32e5b40..ac1cfc3 100644 --- a/ie/far-id.go +++ b/ie/far-id.go @@ -4,11 +4,6 @@ package ie -import ( - "encoding/binary" - "io" -) - // NewFARID creates a new FARID IE. func NewFARID(id uint32) *IE { return newUint32ValIE(FARID, id) @@ -16,13 +11,9 @@ func NewFARID(id uint32) *IE { // FARID returns FARID in uint32 if the type of IE matches. func (i *IE) FARID() (uint32, error) { - if len(i.Payload) < 4 { - return 0, io.ErrUnexpectedEOF - } - switch i.Type { case FARID: - return binary.BigEndian.Uint32(i.Payload[0:4]), nil + return i.ValueAsUint32() case CreatePDR: ies, err := i.CreatePDR() if err != nil { diff --git a/ie/framed-ipv6-route.go b/ie/framed-ipv6-route.go index c70b5a5..ad2f61a 100644 --- a/ie/framed-ipv6-route.go +++ b/ie/framed-ipv6-route.go @@ -13,7 +13,7 @@ func NewFramedIPv6Route(name string) *IE { func (i *IE) FramedIPv6Route() (string, error) { switch i.Type { case FramedIPv6Route: - return string(i.Payload), nil + return i.ValueAsString() case CreateTrafficEndpoint: ies, err := i.CreateTrafficEndpoint() if err != nil { diff --git a/ie/framed-route.go b/ie/framed-route.go index cd1dffe..95d26b8 100644 --- a/ie/framed-route.go +++ b/ie/framed-route.go @@ -13,7 +13,7 @@ func NewFramedRoute(name string) *IE { func (i *IE) FramedRoute() (string, error) { switch i.Type { case FramedRoute: - return string(i.Payload), nil + return i.ValueAsString() case CreateTrafficEndpoint: ies, err := i.CreateTrafficEndpoint() if err != nil { diff --git a/ie/framed-routing.go b/ie/framed-routing.go index ee85f5a..e24452c 100644 --- a/ie/framed-routing.go +++ b/ie/framed-routing.go @@ -4,11 +4,6 @@ package ie -import ( - "encoding/binary" - "io" -) - // Framed-Routing definitions. // // Ref: https://tools.ietf.org/html/rfc2865#section-5.10 @@ -26,13 +21,9 @@ func NewFramedRouting(routing uint32) *IE { // FramedRouting returns FramedRouting in uint32 if the type of IE matches. func (i *IE) FramedRouting() (uint32, error) { - if len(i.Payload) < 4 { - return 0, io.ErrUnexpectedEOF - } - switch i.Type { case FramedRouting: - return binary.BigEndian.Uint32(i.Payload[0:4]), nil + return i.ValueAsUint32() case CreateTrafficEndpoint: ies, err := i.CreateTrafficEndpoint() if err != nil { diff --git a/ie/gate-status.go b/ie/gate-status.go index e1958d1..86c94a9 100644 --- a/ie/gate-status.go +++ b/ie/gate-status.go @@ -4,8 +4,6 @@ package ie -import "io" - // GateStatus definitions. const ( GateStatusOpen uint8 = 0 @@ -19,13 +17,9 @@ func NewGateStatus(ul, dl uint8) *IE { // GateStatus returns GateStatus in uint8 if the type of IE matches. func (i *IE) GateStatus() (uint8, error) { - if len(i.Payload) < 1 { - return 0, io.ErrUnexpectedEOF - } - switch i.Type { case GateStatus: - return i.Payload[0], nil + return i.ValueAsUint8() case CreateQER: ies, err := i.CreateQER() if err != nil { diff --git a/ie/gtp-u-path-interface-type.go b/ie/gtp-u-path-interface-type.go index bab3ad5..6203fbe 100644 --- a/ie/gtp-u-path-interface-type.go +++ b/ie/gtp-u-path-interface-type.go @@ -4,8 +4,6 @@ package ie -import "io" - // NewGTPUPathInterfaceType creates a new GTPUPathInterfaceType IE. func NewGTPUPathInterfaceType(n3, n9 int) *IE { return newUint8ValIE(GTPUPathInterfaceType, uint8((n3<<1)|n9)) @@ -13,13 +11,9 @@ func NewGTPUPathInterfaceType(n3, n9 int) *IE { // GTPUPathInterfaceType returns GTPUPathInterfaceType in uint8 if the type of IE matches. func (i *IE) GTPUPathInterfaceType() (uint8, error) { - if len(i.Payload) < 1 { - return 0, io.ErrUnexpectedEOF - } - switch i.Type { case GTPUPathInterfaceType: - return i.Payload[0], nil + return i.ValueAsUint8() case GTPUPathQoSControlInformation: ies, err := i.GTPUPathQoSControlInformation() if err != nil { diff --git a/ie/ie.go b/ie/ie.go index 774af7a..3d90f37 100644 --- a/ie/ie.go +++ b/ie/ie.go @@ -7,6 +7,7 @@ package ie import ( "encoding/binary" "io" + "time" "github.com/wmnsk/go-pfcp/internal/logger" "github.com/wmnsk/go-pfcp/internal/utils" @@ -363,6 +364,111 @@ func NewFQDNIE(itype uint16, v string) *IE { return newFQDNIE(itype, v) } +// ValueAsUint8 returns the value of IE as uint8. +func (i *IE) ValueAsUint8() (uint8, error) { + if i.IsGrouped() { + return 0, &InvalidTypeError{Type: i.Type} + } + if len(i.Payload) < 1 { + return 0, io.ErrUnexpectedEOF + } + + return i.Payload[0], nil +} + +// ValueAsUint16 returns the value of IE as uint16. +func (i *IE) ValueAsUint16() (uint16, error) { + if i.IsGrouped() { + return 0, &InvalidTypeError{Type: i.Type} + } + if len(i.Payload) < 2 { + return 0, io.ErrUnexpectedEOF + } + + return binary.BigEndian.Uint16(i.Payload[0:2]), nil +} + +// ValueAsUint32 returns the value of IE as uint32. +func (i *IE) ValueAsUint32() (uint32, error) { + if i.IsGrouped() { + return 0, &InvalidTypeError{Type: i.Type} + } + if len(i.Payload) < 4 { + return 0, io.ErrUnexpectedEOF + } + + return binary.BigEndian.Uint32(i.Payload[0:4]), nil +} + +// ValueAsUint64 returns the value of IE as uint64. +func (i *IE) ValueAsUint64() (uint64, error) { + if i.IsGrouped() { + return 0, &InvalidTypeError{Type: i.Type} + } + if len(i.Payload) < 8 { + return 0, io.ErrUnexpectedEOF + } + + return binary.BigEndian.Uint64(i.Payload[0:8]), nil +} + +// ValueAsString returns the value of IE as string. +func (i *IE) ValueAsString() (string, error) { + if i.IsGrouped() { + return "", &InvalidTypeError{Type: i.Type} + } + + return string(i.Payload), nil +} + +// ValueAsFQDN returns the value of IE as FQDN. +func (i *IE) ValueAsFQDN() (string, error) { + if i.IsGrouped() { + return "", &InvalidTypeError{Type: i.Type} + } + + return utils.DecodeFQDN(i.Payload), nil +} + +// ValueAsGrouped returns the value of IE as grouped IE. +// +// This method returns the ChildIEs field if it is already parsed. +// Otherwise, it parses the Payload field and returns the result. +// +// It is recommended to access the ChildIEs field directly if you know the payload is +// already parsed and not modified. If you need to parse the payload anyway, use the +// `()` method instead, which disregards the ChildIEs field. +// +// For vendor-specific IE, this method tries to parse as grouped IE. If it fails, it +// returns error. +func (i *IE) ValueAsGrouped() ([]*IE, error) { + if !(i.IsGrouped() || i.IsVendorSpecific()) { + return nil, &InvalidTypeError{Type: i.Type} + } + + if len(i.ChildIEs) < 1 { + return ParseMultiIEs(i.Payload) + } + return i.ChildIEs, nil +} + +// valueAs3GPPTimestamp returns the value of IE as time.Time, in the format of +// timestamp IEs defined in 3GPP TS 29.244 as follows: +// +// "a UTC time. Octets 5 to 8 shall be encoded in the same format as the first four octets +// of the 64-bit timestamp format as defined in clause 6 of IETF RFC 5905 [12]. +// NOTE: The encoding is defined as the time in seconds relative to 00:00:00 on 1 January 1900." +func (i *IE) valueAs3GPPTimestamp() (time.Time, error) { + if i.IsGrouped() { + return time.Time{}, &InvalidTypeError{Type: i.Type} + } + if len(i.Payload) < 4 { + return time.Time{}, io.ErrUnexpectedEOF + } + + return time.Unix(int64(binary.BigEndian.Uint32(i.Payload[0:4])-2208988800), 0), nil +} + // Parse parses b into IE. func Parse(b []byte) (*IE, error) { i := &IE{} @@ -372,6 +478,26 @@ func Parse(b []byte) (*IE, error) { return i, nil } +// ParseMultiIEs decodes multiple IEs at a time. +// This is easy and useful but slower than decoding one by one. +// When you don't know the number of IEs, this is the only way to decode them. +func ParseMultiIEs(b []byte) ([]*IE, error) { + var ies []*IE + for { + if len(b) == 0 { + break + } + + i, err := Parse(b) + if err != nil { + return nil, err + } + ies = append(ies, i) + b = b[i.MarshalLen():] + } + return ies, nil +} + // UnmarshalBinary parses b into IE. func (i *IE) UnmarshalBinary(b []byte) error { l := len(b) @@ -493,189 +619,6 @@ func (i *IE) IsVendorSpecific() bool { return i.Type&0x8000 != 0 } -// We're using map to avoid iterating over a list. -// The value is not actually used. -// TODO: consider using a slice with utils in slices package introduced in Go 1.21. -var groupedMap = map[uint16]bool{ - CreatePDR: true, - PDI: true, - CreateFAR: true, - ForwardingParameters: true, - DuplicatingParameters: true, - CreateURR: true, - CreateQER: true, - CreatedPDR: true, - UpdatePDR: true, - UpdateFAR: true, - UpdateForwardingParameters: true, - UpdateBARWithinSessionReportResponse: true, - UpdateURR: true, - UpdateQER: true, - RemovePDR: true, - RemoveFAR: true, - RemoveURR: true, - RemoveQER: true, - LoadControlInformation: true, - OverloadControlInformation: true, - ApplicationIDsPFDs: true, - PFDContext: true, - ApplicationDetectionInformation: true, - QueryURR: true, - UsageReportWithinSessionModificationResponse: true, - UsageReportWithinSessionDeletionResponse: true, - UsageReportWithinSessionReportRequest: true, - DownlinkDataReport: true, - CreateBAR: true, - UpdateBARWithinSessionModificationRequest: true, - RemoveBAR: true, - ErrorIndicationReport: true, - UserPlanePathFailureReport: true, - UpdateDuplicatingParameters: true, - AggregatedURRs: true, - CreateTrafficEndpoint: true, - CreatedTrafficEndpoint: true, - UpdateTrafficEndpoint: true, - RemoveTrafficEndpoint: true, - EthernetPacketFilter: true, - EthernetTrafficInformation: true, - AdditionalMonitoringTime: true, - CreateMAR: true, - TGPPAccessForwardingActionInformation: true, - NonTGPPAccessForwardingActionInformation: true, - RemoveMAR: true, - UpdateMAR: true, - UpdateTGPPAccessForwardingActionInformation: true, - UpdateNonTGPPAccessForwardingActionInformation: true, - PFCPSessionRetentionInformation: true, - UserPlanePathRecoveryReport: true, - IPMulticastAddressingInfo: true, - JoinIPMulticastInformationWithinUsageReport: true, - LeaveIPMulticastInformationWithinUsageReport: true, - CreatedBridgeInfoForTSC: true, - TSCManagementInformationWithinSessionModificationRequest: true, - TSCManagementInformationWithinSessionModificationResponse: true, - TSCManagementInformationWithinSessionReportRequest: true, - ClockDriftControlInformation: true, - ClockDriftReport: true, - RemoveSRR: true, - CreateSRR: true, - UpdateSRR: true, - SessionReport: true, - AccessAvailabilityControlInformation: true, - AccessAvailabilityReport: true, - ProvideATSSSControlInformation: true, - ATSSSControlParameters: true, - MPTCPParameters: true, - ATSSSLLParameters: true, - PMFParameters: true, - UEIPAddressPoolInformation: true, - GTPUPathQoSControlInformation: true, - GTPUPathQoSReport: true, - QoSInformationInGTPUPathQoSReport: true, - QoSMonitoringPerQoSFlowControlInformation: true, - QoSMonitoringReport: true, - PacketRateStatusReport: true, - EthernetContextInformation: true, - RedundantTransmissionParameters: true, - UpdatedPDR: true, - ProvideRDSConfigurationInformation: true, - QueryPacketRateStatusWithinSessionModificationRequest: true, - PacketRateStatusReportWithinSessionModificationResponse: true, - UEIPAddressUsageInformation: true, - RedundantTransmissionForwardingParameters: true, - TransportDelayReporting: true, -} - -// IsGrouped reports whether an IE is grouped type or not. -func (i *IE) IsGrouped() bool { - _, ok := groupedMap[i.Type] - return ok -} - -// Add adds variable number of IEs to a IE if the IE is grouped type and update length. -// Otherwise, this does nothing(no errors). -func (i *IE) Add(ies ...*IE) { - if !i.IsGrouped() { - return - } - - i.Payload = nil - i.ChildIEs = append(i.ChildIEs, ies...) - for _, ie := range i.ChildIEs { - serialized, err := ie.Marshal() - if err != nil { - continue - } - i.Payload = append(i.Payload, serialized...) - } - i.SetLength() -} - -// Remove removes an IE looked up by type and instance. -func (i *IE) Remove(typ uint16) { - if !i.IsGrouped() { - return - } - - i.Payload = nil - newChildren := make([]*IE, len(i.ChildIEs)) - idx := 0 - for _, ie := range i.ChildIEs { - if ie.Type == typ { - newChildren = newChildren[:len(newChildren)-1] - continue - } - newChildren[idx] = ie - idx++ - - serialized, err := ie.Marshal() - if err != nil { - continue - } - i.Payload = append(i.Payload, serialized...) - } - i.ChildIEs = newChildren - i.SetLength() -} - -// FindByType returns IE looked up by type and instance. -// -// The program may be slower when calling this method multiple times -// because this ranges over a ChildIEs each time it is called. -func (i *IE) FindByType(typ uint16) (*IE, error) { - if !i.IsGrouped() { - return nil, ErrInvalidType - } - - for _, ie := range i.ChildIEs { - if ie.Type == typ { - return ie, nil - } - } - return nil, ErrIENotFound -} - -// ParseMultiIEs decodes multiple IEs at a time. -// This is easy and useful but slower than decoding one by one. -// When you don't know the number of IEs, this is the only way to decode them. -// See benchmarks in diameter_test.go for the detail. -func ParseMultiIEs(b []byte) ([]*IE, error) { - var ies []*IE - for { - if len(b) == 0 { - break - } - - i, err := Parse(b) - if err != nil { - return nil, err - } - ies = append(ies, i) - b = b[i.MarshalLen():] - } - return ies, nil -} - func newUint8ValIE(t uint16, v uint8) *IE { return New(t, []byte{v}) } diff --git a/ie/ie_fuzz_test.go b/ie/ie_fuzz_test.go index 18bec85..462bfe1 100644 --- a/ie/ie_fuzz_test.go +++ b/ie/ie_fuzz_test.go @@ -13,3 +13,42 @@ func FuzzParse(f *testing.F) { } }) } + +func FuzzParseMultiIEs(f *testing.F) { + f.Fuzz(func(t *testing.T, b []byte) { + ie.SetIsGroupedFun(func(t uint16) bool { return true }) + if _, err := ie.ParseMultiIEs(b); err != nil { + t.Skip() + } + }) +} + +func FuzzValueAs(f *testing.F) { + f.Fuzz(func(t *testing.T, b []byte) { + for typ := uint16(0); typ <= 65535; typ++ { + i := ie.New(typ, b) + if _, err := i.ValueAsUint8(); err != nil { + t.Skip() + } + if _, err := i.ValueAsUint16(); err != nil { + t.Skip() + } + if _, err := i.ValueAsUint32(); err != nil { + t.Skip() + } + if _, err := i.ValueAsUint64(); err != nil { + t.Skip() + } + if _, err := i.ValueAsString(); err != nil { + t.Skip() + } + if _, err := i.ValueAsFQDN(); err != nil { + t.Skip() + } + ie.SetIsGroupedFun(func(t uint16) bool { return true }) + if _, err := i.ValueAsGrouped(); err != nil { + t.Skip() + } + } + }) +} diff --git a/ie/ie_grouped.go b/ie/ie_grouped.go new file mode 100644 index 0000000..24bce93 --- /dev/null +++ b/ie/ie_grouped.go @@ -0,0 +1,196 @@ +package ie + +import "sync" + +// We're using map to avoid iterating over a list. +// The value `true` is not actually used. +// TODO: consider using a slice with utils in slices package introduced in Go 1.21. +var ( + mu sync.RWMutex + defaultGroupedIEMap = map[uint16]bool{ + CreatePDR: true, + PDI: true, + CreateFAR: true, + ForwardingParameters: true, + DuplicatingParameters: true, + CreateURR: true, + CreateQER: true, + CreatedPDR: true, + UpdatePDR: true, + UpdateFAR: true, + UpdateForwardingParameters: true, + UpdateBARWithinSessionReportResponse: true, + UpdateURR: true, + UpdateQER: true, + RemovePDR: true, + RemoveFAR: true, + RemoveURR: true, + RemoveQER: true, + LoadControlInformation: true, + OverloadControlInformation: true, + ApplicationIDsPFDs: true, + PFDContext: true, + ApplicationDetectionInformation: true, + QueryURR: true, + UsageReportWithinSessionModificationResponse: true, + UsageReportWithinSessionDeletionResponse: true, + UsageReportWithinSessionReportRequest: true, + DownlinkDataReport: true, + CreateBAR: true, + UpdateBARWithinSessionModificationRequest: true, + RemoveBAR: true, + ErrorIndicationReport: true, + UserPlanePathFailureReport: true, + UpdateDuplicatingParameters: true, + AggregatedURRs: true, + CreateTrafficEndpoint: true, + CreatedTrafficEndpoint: true, + UpdateTrafficEndpoint: true, + RemoveTrafficEndpoint: true, + EthernetPacketFilter: true, + EthernetTrafficInformation: true, + AdditionalMonitoringTime: true, + CreateMAR: true, + TGPPAccessForwardingActionInformation: true, + NonTGPPAccessForwardingActionInformation: true, + RemoveMAR: true, + UpdateMAR: true, + UpdateTGPPAccessForwardingActionInformation: true, + UpdateNonTGPPAccessForwardingActionInformation: true, + PFCPSessionRetentionInformation: true, + UserPlanePathRecoveryReport: true, + IPMulticastAddressingInfo: true, + JoinIPMulticastInformationWithinUsageReport: true, + LeaveIPMulticastInformationWithinUsageReport: true, + CreatedBridgeInfoForTSC: true, + TSCManagementInformationWithinSessionModificationRequest: true, + TSCManagementInformationWithinSessionModificationResponse: true, + TSCManagementInformationWithinSessionReportRequest: true, + ClockDriftControlInformation: true, + ClockDriftReport: true, + RemoveSRR: true, + CreateSRR: true, + UpdateSRR: true, + SessionReport: true, + AccessAvailabilityControlInformation: true, + AccessAvailabilityReport: true, + ProvideATSSSControlInformation: true, + ATSSSControlParameters: true, + MPTCPParameters: true, + ATSSSLLParameters: true, + PMFParameters: true, + UEIPAddressPoolInformation: true, + GTPUPathQoSControlInformation: true, + GTPUPathQoSReport: true, + QoSInformationInGTPUPathQoSReport: true, + QoSMonitoringPerQoSFlowControlInformation: true, + QoSMonitoringReport: true, + PacketRateStatusReport: true, + EthernetContextInformation: true, + RedundantTransmissionParameters: true, + UpdatedPDR: true, + ProvideRDSConfigurationInformation: true, + QueryPacketRateStatusWithinSessionModificationRequest: true, + PacketRateStatusReportWithinSessionModificationResponse: true, + UEIPAddressUsageInformation: true, + RedundantTransmissionForwardingParameters: true, + TransportDelayReporting: true, + } + isGroupedFun = func(t uint16) bool { + mu.RLock() + defer mu.RUnlock() + _, ok := defaultGroupedIEMap[t] + return ok + } +) + +// SetIsGroupedFun sets a function to check if an IE is grouped type or not. +func SetIsGroupedFun(fun func(t uint16) bool) { + mu.Lock() + defer mu.Unlock() + isGroupedFun = fun +} + +// AddGroupedIEType adds IE type(s) to the defaultGroupedIEMap. +// This is useful when you want to add new IE types to the defaultGroupedIEMap, +// e.g., to handle vendor-specific IEs as grouped type. +func AddGroupedIEType(ts ...uint16) { + mu.Lock() + defer mu.Unlock() + for _, t := range ts { + defaultGroupedIEMap[t] = true + } +} + +// IsGrouped reports whether an IE is grouped type or not. +// +// By default, this package determines if an IE is grouped type or not by checking +// if the IE type is in the defaultGroupedIEMap. +// You can change this entire behavior by calling SetIsGroupedFun(), or you can add +// new IE types to the defaultGroupedIEMap by calling AddGroupedIEType(). +func (i *IE) IsGrouped() bool { + return isGroupedFun(i.Type) +} + +// Add adds variable number of IEs to a IE if the IE is grouped type and update length. +// Otherwise, this does nothing (no errors). +func (i *IE) Add(ies ...*IE) { + if !i.IsGrouped() { + return + } + + i.Payload = nil + i.ChildIEs = append(i.ChildIEs, ies...) + for _, ie := range i.ChildIEs { + serialized, err := ie.Marshal() + if err != nil { + continue + } + i.Payload = append(i.Payload, serialized...) + } + i.SetLength() +} + +// Remove removes an IE looked up by type. +func (i *IE) Remove(typ uint16) { + if !i.IsGrouped() { + return + } + + i.Payload = nil + newChildren := make([]*IE, len(i.ChildIEs)) + idx := 0 + for _, ie := range i.ChildIEs { + if ie.Type == typ { + newChildren = newChildren[:len(newChildren)-1] + continue + } + newChildren[idx] = ie + idx++ + + serialized, err := ie.Marshal() + if err != nil { + continue + } + i.Payload = append(i.Payload, serialized...) + } + i.ChildIEs = newChildren + i.SetLength() +} + +// FindByType returns IE looked up by type. +// +// The program may be slower when calling this method multiple times +// because this ranges over a ChildIEs each time it is called. +func (i *IE) FindByType(typ uint16) (*IE, error) { + if !i.IsGrouped() { + return nil, ErrInvalidType + } + + for _, ie := range i.ChildIEs { + if ie.Type == typ { + return ie, nil + } + } + return nil, ErrIENotFound +} diff --git a/ie/ie_duration_test.go b/ie/ie_time_duration_test.go similarity index 100% rename from ie/ie_duration_test.go rename to ie/ie_time_duration_test.go diff --git a/ie/inactivity-detection-time.go b/ie/inactivity-detection-time.go index 4e8d82d..bdde787 100644 --- a/ie/inactivity-detection-time.go +++ b/ie/inactivity-detection-time.go @@ -4,11 +4,6 @@ package ie -import ( - "encoding/binary" - "io" -) - // NewInactivityDetectionTime creates a new InactivityDetectionTime IE. func NewInactivityDetectionTime(threshold uint32) *IE { return newUint32ValIE(InactivityDetectionTime, threshold) @@ -16,13 +11,9 @@ func NewInactivityDetectionTime(threshold uint32) *IE { // InactivityDetectionTime returns InactivityDetectionTime in uint32 if the type of IE matches. func (i *IE) InactivityDetectionTime() (uint32, error) { - if len(i.Payload) < 4 { - return 0, io.ErrUnexpectedEOF - } - switch i.Type { case InactivityDetectionTime: - return binary.BigEndian.Uint32(i.Payload[0:4]), nil + return i.ValueAsUint32() case CreateURR: ies, err := i.CreateURR() if err != nil { diff --git a/ie/ip-version.go b/ie/ip-version.go index b0d5e77..5ccdde3 100644 --- a/ie/ip-version.go +++ b/ie/ip-version.go @@ -4,8 +4,6 @@ package ie -import "io" - // NewIPVersion creates a new IPVersion IE. func NewIPVersion(v4, v6 bool) *IE { i := New(IPVersion, make([]byte, 1)) @@ -20,13 +18,9 @@ func NewIPVersion(v4, v6 bool) *IE { // IPVersion returns IPVersion in uint8 if the type of IE matches. func (i *IE) IPVersion() (uint8, error) { - if len(i.Payload) < 1 { - return 0, io.ErrUnexpectedEOF - } - switch i.Type { case IPVersion: - return i.Payload[0], nil + return i.ValueAsUint8() case UEIPAddressPoolInformation: ies, err := i.UEIPAddressPoolInformation() if err != nil { diff --git a/ie/linked-urr-id.go b/ie/linked-urr-id.go index cbfec68..a7f66cd 100644 --- a/ie/linked-urr-id.go +++ b/ie/linked-urr-id.go @@ -4,11 +4,6 @@ package ie -import ( - "encoding/binary" - "io" -) - // NewLinkedURRID creates a new LinkedURRID IE. func NewLinkedURRID(id uint32) *IE { return newUint32ValIE(LinkedURRID, id) @@ -16,13 +11,9 @@ func NewLinkedURRID(id uint32) *IE { // LinkedURRID returns LinkedURRID in uint32 if the type of IE matches. func (i *IE) LinkedURRID() (uint32, error) { - if len(i.Payload) < 4 { - return 0, io.ErrUnexpectedEOF - } - switch i.Type { case LinkedURRID: - return binary.BigEndian.Uint32(i.Payload[0:4]), nil + return i.ValueAsUint32() case CreateURR: ies, err := i.CreateURR() if err != nil { diff --git a/ie/mar-id.go b/ie/mar-id.go index ee130f6..2016b82 100644 --- a/ie/mar-id.go +++ b/ie/mar-id.go @@ -4,10 +4,6 @@ package ie -import ( - "encoding/binary" -) - // NewMARID creates a new MARID IE. func NewMARID(id uint16) *IE { return newUint16ValIE(MARID, id) @@ -15,13 +11,9 @@ func NewMARID(id uint16) *IE { // MARID returns MARID in uint16 if the type of IE matches. func (i *IE) MARID() (uint16, error) { - if len(i.Payload) < 2 { - return 0, &InvalidTypeError{Type: i.Type} - } - switch i.Type { case MARID: - return binary.BigEndian.Uint16(i.Payload[0:2]), nil + return i.ValueAsUint16() case CreatePDR: ies, err := i.CreatePDR() if err != nil { diff --git a/ie/measurement-information.go b/ie/measurement-information.go index 5b4b041..53c766d 100644 --- a/ie/measurement-information.go +++ b/ie/measurement-information.go @@ -4,10 +4,6 @@ package ie -import ( - "io" -) - // NewMeasurementInformation creates a new MeasurementInformation IE. func NewMeasurementInformation(flags uint8) *IE { return newUint8ValIE(MeasurementInformation, flags) @@ -15,13 +11,9 @@ func NewMeasurementInformation(flags uint8) *IE { // MeasurementInformation returns MeasurementInformation in uint8 if the type of IE matches. func (i *IE) MeasurementInformation() (uint8, error) { - if len(i.Payload) < 1 { - return 0, io.ErrUnexpectedEOF - } - switch i.Type { case MeasurementInformation: - return i.Payload[0], nil + return i.ValueAsUint8() case CreateURR: ies, err := i.CreateURR() if err != nil { diff --git a/ie/measurement-method.go b/ie/measurement-method.go index c03dd56..f3b0a32 100644 --- a/ie/measurement-method.go +++ b/ie/measurement-method.go @@ -4,8 +4,6 @@ package ie -import "io" - // NewMeasurementMethod creates a new MeasurementMethod IE. func NewMeasurementMethod(event, volum, durat int) *IE { return newUint8ValIE(MeasurementMethod, uint8((event<<2)|(volum<<1)|(durat))) @@ -13,13 +11,9 @@ func NewMeasurementMethod(event, volum, durat int) *IE { // MeasurementMethod returns MeasurementMethod in uint8 if the type of IE matches. func (i *IE) MeasurementMethod() (uint8, error) { - if len(i.Payload) < 1 { - return 0, io.ErrUnexpectedEOF - } - switch i.Type { case MeasurementMethod: - return i.Payload[0], nil + return i.ValueAsUint8() case CreateURR: ies, err := i.CreateURR() if err != nil { diff --git a/ie/metric.go b/ie/metric.go index dcc242f..d067cd4 100644 --- a/ie/metric.go +++ b/ie/metric.go @@ -4,10 +4,6 @@ package ie -import ( - "io" -) - // NewMetric creates a new Metric IE. func NewMetric(metric uint8) *IE { return newUint8ValIE(Metric, metric) @@ -15,14 +11,9 @@ func NewMetric(metric uint8) *IE { // Metric returns Metric in uint8 if the type of IE matches. func (i *IE) Metric() (uint8, error) { - - if len(i.Payload) < 1 { - return 0, io.ErrUnexpectedEOF - } - switch i.Type { case Metric: - return i.Payload[0], nil + return i.ValueAsUint8() case LoadControlInformation: ies, err := i.LoadControlInformation() if err != nil { diff --git a/ie/monitoring-time.go b/ie/monitoring-time.go index 414ed1a..b4c91a7 100644 --- a/ie/monitoring-time.go +++ b/ie/monitoring-time.go @@ -5,8 +5,6 @@ package ie import ( - "encoding/binary" - "io" "time" ) @@ -18,13 +16,9 @@ func NewMonitoringTime(ts time.Time) *IE { // MonitoringTime returns MonitoringTime in time.Time if the type of IE matches. func (i *IE) MonitoringTime() (time.Time, error) { - if len(i.Payload) < 4 { - return time.Time{}, io.ErrUnexpectedEOF - } - switch i.Type { case MonitoringTime: - return time.Unix(int64(binary.BigEndian.Uint32(i.Payload[0:4])-2208988800), 0), nil + return i.valueAs3GPPTimestamp() case CreateURR: ies, err := i.CreateURR() if err != nil { diff --git a/ie/mptcp-applicable-indication.go b/ie/mptcp-applicable-indication.go index fd57205..8736ead 100644 --- a/ie/mptcp-applicable-indication.go +++ b/ie/mptcp-applicable-indication.go @@ -4,8 +4,6 @@ package ie -import "io" - // NewMPTCPApplicableIndication creates a new MPTCPApplicableIndication IE. func NewMPTCPApplicableIndication(flag uint8) *IE { return newUint8ValIE(MPTCPApplicableIndication, flag) @@ -13,13 +11,9 @@ func NewMPTCPApplicableIndication(flag uint8) *IE { // MPTCPApplicableIndication returns MPTCPApplicableIndication in uint8 if the type of IE matches. func (i *IE) MPTCPApplicableIndication() (uint8, error) { - if len(i.Payload) < 1 { - return 0, io.ErrUnexpectedEOF - } - switch i.Type { case MPTCPApplicableIndication: - return i.Payload[0], nil + return i.ValueAsUint8() case CreatePDR: ies, err := i.CreatePDR() if err != nil { diff --git a/ie/mptcp-control-information.go b/ie/mptcp-control-information.go index bd202b8..a89c974 100644 --- a/ie/mptcp-control-information.go +++ b/ie/mptcp-control-information.go @@ -4,8 +4,6 @@ package ie -import "io" - // NewMPTCPControlInformation creates a new MPTCPControlInformation IE. func NewMPTCPControlInformation(tci uint8) *IE { return newUint8ValIE(MPTCPControlInformation, tci&0x01) @@ -13,13 +11,9 @@ func NewMPTCPControlInformation(tci uint8) *IE { // MPTCPControlInformation returns MPTCPControlInformation in uint8 if the type of IE matches. func (i *IE) MPTCPControlInformation() (uint8, error) { - if len(i.Payload) < 1 { - return 0, io.ErrUnexpectedEOF - } - switch i.Type { case MPTCPControlInformation: - return i.Payload[0], nil + return i.ValueAsUint8() case ProvideATSSSControlInformation: ies, err := i.ProvideATSSSControlInformation() if err != nil { diff --git a/ie/mt-edt-control-information.go b/ie/mt-edt-control-information.go index 6367db5..01bb2bf 100644 --- a/ie/mt-edt-control-information.go +++ b/ie/mt-edt-control-information.go @@ -4,8 +4,6 @@ package ie -import "io" - // NewMTEDTControlInformation creates a new MTEDTControlInformation IE. func NewMTEDTControlInformation(rdsi uint8) *IE { return newUint8ValIE(MTEDTControlInformation, rdsi&0x01) @@ -13,13 +11,9 @@ func NewMTEDTControlInformation(rdsi uint8) *IE { // MTEDTControlInformation returns MTEDTControlInformation in uint8 if the type of IE matches. func (i *IE) MTEDTControlInformation() (uint8, error) { - if len(i.Payload) < 1 { - return 0, io.ErrUnexpectedEOF - } - switch i.Type { case MTEDTControlInformation: - return i.Payload[0], nil + return i.ValueAsUint8() case CreateBAR: ies, err := i.CreateBAR() if err != nil { diff --git a/ie/multiplier.go b/ie/multiplier.go index 92aa082..8cb42b6 100644 --- a/ie/multiplier.go +++ b/ie/multiplier.go @@ -41,13 +41,9 @@ func (i *IE) Multiplier() ([]byte, error) { // ValueDigits returns ValueDigits in uint64 if the type of IE matches. func (i *IE) ValueDigits() (uint64, error) { - if len(i.Payload) < 8 { - return 0, io.ErrUnexpectedEOF - } - switch i.Type { case Multiplier: - return binary.BigEndian.Uint64(i.Payload[0:8]), nil + return i.ValueAsUint64() case AggregatedURRs: ies, err := i.AggregatedURRs() if err != nil { diff --git a/ie/network-instance.go b/ie/network-instance.go index e2c7363..fec2e56 100644 --- a/ie/network-instance.go +++ b/ie/network-instance.go @@ -21,7 +21,7 @@ func NewNetworkInstanceFQDN(fqdn string) *IE { func (i *IE) NetworkInstance() (string, error) { switch i.Type { case NetworkInstance: - return string(i.Payload), nil + return i.ValueAsString() case PDI: ies, err := i.PDI() if err != nil { diff --git a/ie/node-report-type.go b/ie/node-report-type.go index 3b89c9b..fea851c 100644 --- a/ie/node-report-type.go +++ b/ie/node-report-type.go @@ -4,10 +4,6 @@ package ie -import ( - "io" -) - // NewNodeReportType creates a new NodeReportType IE. func NewNodeReportType(flags uint8) *IE { return newUint8ValIE(NodeReportType, flags) @@ -18,11 +14,8 @@ func (i *IE) NodeReportType() (uint8, error) { if i.Type != NodeReportType { return 0, &InvalidTypeError{Type: i.Type} } - if len(i.Payload) < 1 { - return 0, io.ErrUnexpectedEOF - } - return i.Payload[0], nil + return i.ValueAsUint8() } // HasUPFR reports whether an IE has UPFR bit. diff --git a/ie/number-of-reports.go b/ie/number-of-reports.go index dcb22be..9038cab 100644 --- a/ie/number-of-reports.go +++ b/ie/number-of-reports.go @@ -4,10 +4,6 @@ package ie -import ( - "encoding/binary" -) - // NewNumberOfReports creates a new NumberOfReports IE. func NewNumberOfReports(num uint16) *IE { return newUint16ValIE(NumberOfReports, num) @@ -15,13 +11,9 @@ func NewNumberOfReports(num uint16) *IE { // NumberOfReports returns NumberOfReports in uint16 if the type of IE matches. func (i *IE) NumberOfReports() (uint16, error) { - if len(i.Payload) < 2 { - return 0, &InvalidTypeError{Type: i.Type} - } - switch i.Type { case NumberOfReports: - return binary.BigEndian.Uint16(i.Payload[0:2]), nil + return i.ValueAsUint16() case CreateURR: ies, err := i.CreateURR() if err != nil { diff --git a/ie/nw-tt-port-number.go b/ie/nw-tt-port-number.go index d9cecda..d7887ee 100644 --- a/ie/nw-tt-port-number.go +++ b/ie/nw-tt-port-number.go @@ -4,11 +4,6 @@ package ie -import ( - "encoding/binary" - "io" -) - // NewNWTTPortNumber creates a new NWTTPortNumber IE. func NewNWTTPortNumber(port uint32) *IE { return newUint32ValIE(NWTTPortNumber, port) @@ -16,13 +11,9 @@ func NewNWTTPortNumber(port uint32) *IE { // NWTTPortNumber returns NWTTPortNumber in uint32 if the type of IE matches. func (i *IE) NWTTPortNumber() (uint32, error) { - if len(i.Payload) < 4 { - return 0, io.ErrUnexpectedEOF - } - switch i.Type { case NWTTPortNumber: - return binary.BigEndian.Uint32(i.Payload[0:4]), nil + return i.ValueAsUint32() case CreatedBridgeInfoForTSC: ies, err := i.CreatedBridgeInfoForTSC() if err != nil { diff --git a/ie/oci-flags.go b/ie/oci-flags.go index 29d3c97..b8d964d 100644 --- a/ie/oci-flags.go +++ b/ie/oci-flags.go @@ -4,10 +4,6 @@ package ie -import ( - "io" -) - // NewOCIFlags creates a new OCIFlags IE. func NewOCIFlags(flags uint8) *IE { return newUint8ValIE(OCIFlags, flags) @@ -15,13 +11,9 @@ func NewOCIFlags(flags uint8) *IE { // OCIFlags returns OCIFlags in uint8 if the type of IE matches. func (i *IE) OCIFlags() (uint8, error) { - if len(i.Payload) < 1 { - return 0, io.ErrUnexpectedEOF - } - switch i.Type { case OCIFlags: - return i.Payload[0], nil + return i.ValueAsUint8() case OverloadControlInformation: ies, err := i.OverloadControlInformation() if err != nil { diff --git a/ie/offending-ie.go b/ie/offending-ie.go index a6908b5..53f3369 100644 --- a/ie/offending-ie.go +++ b/ie/offending-ie.go @@ -4,11 +4,6 @@ package ie -import ( - "encoding/binary" - "io" -) - // NewOffendingIE creates a new OffendingIE IE. func NewOffendingIE(itype uint16) *IE { return newUint16ValIE(OffendingIE, itype) @@ -20,9 +15,5 @@ func (i *IE) OffendingIE() (uint16, error) { return 0, &InvalidTypeError{Type: i.Type} } - if len(i.Payload) < 2 { - return 0, io.ErrUnexpectedEOF - } - - return binary.BigEndian.Uint16(i.Payload[0:2]), nil + return i.ValueAsUint16() } diff --git a/ie/packet-replication-and-detection-carry-on-information.go b/ie/packet-replication-and-detection-carry-on-information.go index b83abfb..5987f34 100644 --- a/ie/packet-replication-and-detection-carry-on-information.go +++ b/ie/packet-replication-and-detection-carry-on-information.go @@ -4,8 +4,6 @@ package ie -import "io" - // NewPacketReplicationAndDetectionCarryOnInformation creates a new PacketReplicationAndDetectionCarryOnInformation IE. func NewPacketReplicationAndDetectionCarryOnInformation(flag uint8) *IE { return newUint8ValIE(PacketReplicationAndDetectionCarryOnInformation, flag) @@ -13,13 +11,9 @@ func NewPacketReplicationAndDetectionCarryOnInformation(flag uint8) *IE { // PacketReplicationAndDetectionCarryOnInformation returns PacketReplicationAndDetectionCarryOnInformation in uint8 if the type of IE matches. func (i *IE) PacketReplicationAndDetectionCarryOnInformation() (uint8, error) { - if len(i.Payload) < 1 { - return 0, io.ErrUnexpectedEOF - } - switch i.Type { case PacketReplicationAndDetectionCarryOnInformation: - return i.Payload[0], nil + return i.ValueAsUint8() case CreatePDR: ies, err := i.CreatePDR() if err != nil { diff --git a/ie/pdn-type.go b/ie/pdn-type.go index e35380d..ab212a2 100644 --- a/ie/pdn-type.go +++ b/ie/pdn-type.go @@ -4,10 +4,6 @@ package ie -import ( - "io" -) - // PDNType definitions. const ( _ uint8 = 0 @@ -28,9 +24,6 @@ func (i *IE) PDNType() (uint8, error) { if i.Type != PDNType { return 0, &InvalidTypeError{Type: i.Type} } - if len(i.Payload) < 1 { - return 0, io.ErrUnexpectedEOF - } - return i.Payload[0], nil + return i.ValueAsUint8() } diff --git a/ie/pdr-id.go b/ie/pdr-id.go index 8dfb3d7..1cf29ff 100644 --- a/ie/pdr-id.go +++ b/ie/pdr-id.go @@ -4,11 +4,6 @@ package ie -import ( - "encoding/binary" - "io" -) - // NewPDRID creates a new PDRID IE. func NewPDRID(id uint16) *IE { return newUint16ValIE(PDRID, id) @@ -18,10 +13,7 @@ func NewPDRID(id uint16) *IE { func (i *IE) PDRID() (uint16, error) { switch i.Type { case PDRID: - if len(i.Payload) < 2 { - return 0, io.ErrUnexpectedEOF - } - return binary.BigEndian.Uint16(i.Payload[0:2]), nil + return i.ValueAsUint16() case CreatePDR: ies, err := i.CreatePDR() if err != nil { diff --git a/ie/pfcp-association-release-request.go b/ie/pfcp-association-release-request.go index 3ff252c..2e086eb 100644 --- a/ie/pfcp-association-release-request.go +++ b/ie/pfcp-association-release-request.go @@ -15,7 +15,7 @@ func (i *IE) PFCPAssociationReleaseRequest() (uint8, error) { return 0, &InvalidTypeError{Type: i.Type} } - return i.Payload[0], nil + return i.ValueAsUint8() } // HasURSS reports whether an IE has URSS bit. diff --git a/ie/pfcpasreq-flags.go b/ie/pfcpasreq-flags.go index 54c089f..856864f 100644 --- a/ie/pfcpasreq-flags.go +++ b/ie/pfcpasreq-flags.go @@ -4,8 +4,6 @@ package ie -import "io" - // NewPFCPASReqFlags creates a new PFCPASReqFlags IE. func NewPFCPASReqFlags(flag uint8) *IE { return newUint8ValIE(PFCPASReqFlags, flag) @@ -16,11 +14,8 @@ func (i *IE) PFCPASReqFlags() (uint8, error) { if i.Type != PFCPASReqFlags { return 0, &InvalidTypeError{Type: i.Type} } - if len(i.Payload) < 1 { - return 0, io.ErrUnexpectedEOF - } - return i.Payload[0], nil + return i.ValueAsUint8() } // HasUUPSI reports whether an IE has UUPSI bit. diff --git a/ie/pfcpasrsp-flags.go b/ie/pfcpasrsp-flags.go index 68bd80d..2d8474e 100644 --- a/ie/pfcpasrsp-flags.go +++ b/ie/pfcpasrsp-flags.go @@ -4,8 +4,6 @@ package ie -import "io" - // NewPFCPASRspFlags creates a new PFCPASRspFlags IE. func NewPFCPASRspFlags(flag uint8) *IE { return newUint8ValIE(PFCPASRspFlags, flag) @@ -16,11 +14,8 @@ func (i *IE) PFCPASRspFlags() (uint8, error) { if i.Type != PFCPASRspFlags { return 0, &InvalidTypeError{Type: i.Type} } - if len(i.Payload) < 1 { - return 0, io.ErrUnexpectedEOF - } - return i.Payload[0], nil + return i.ValueAsUint8() } // HasPSREI reports whether an IE has PSREI bit. diff --git a/ie/pfcpaureq-flags.go b/ie/pfcpaureq-flags.go index a94264b..487b9d4 100644 --- a/ie/pfcpaureq-flags.go +++ b/ie/pfcpaureq-flags.go @@ -15,7 +15,7 @@ func (i *IE) PFCPAUReqFlags() (uint8, error) { return 0, &InvalidTypeError{Type: i.Type} } - return i.Payload[0], nil + return i.ValueAsUint8() } // HasPARPS reports whether an IE has PARPS bit. diff --git a/ie/pfcpsereq-flags.go b/ie/pfcpsereq-flags.go index 150b2fd..bdf5fe4 100644 --- a/ie/pfcpsereq-flags.go +++ b/ie/pfcpsereq-flags.go @@ -15,7 +15,7 @@ func (i *IE) PFCPSEReqFlags() (uint8, error) { return 0, &InvalidTypeError{Type: i.Type} } - return i.Payload[0], nil + return i.ValueAsUint8() } // HasRESTI reports whether an IE has RESTI bit. diff --git a/ie/pfcpsmreq-flags.go b/ie/pfcpsmreq-flags.go index 2303584..928f303 100644 --- a/ie/pfcpsmreq-flags.go +++ b/ie/pfcpsmreq-flags.go @@ -13,7 +13,7 @@ func NewPFCPSMReqFlags(flag uint8) *IE { func (i *IE) PFCPSMReqFlags() (uint8, error) { switch i.Type { case PFCPSMReqFlags: - return i.Payload[0], nil + return i.ValueAsUint8() case ForwardingParameters: ies, err := i.ForwardingParameters() if err != nil { diff --git a/ie/pfcpsrreq-flags.go b/ie/pfcpsrreq-flags.go index a3cdd73..934271a 100644 --- a/ie/pfcpsrreq-flags.go +++ b/ie/pfcpsrreq-flags.go @@ -15,7 +15,7 @@ func (i *IE) PFCPSRReqFlags() (uint8, error) { return 0, &InvalidTypeError{Type: i.Type} } - return i.Payload[0], nil + return i.ValueAsUint8() } // HasPSDBU reports whether an IE has PSDBU bit. diff --git a/ie/pfcpsrrsp-flags.go b/ie/pfcpsrrsp-flags.go index a315655..7065a5d 100644 --- a/ie/pfcpsrrsp-flags.go +++ b/ie/pfcpsrrsp-flags.go @@ -15,5 +15,5 @@ func (i *IE) PFCPSRRspFlags() (uint8, error) { return 0, &InvalidTypeError{Type: i.Type} } - return i.Payload[0], nil + return i.ValueAsUint8() } diff --git a/ie/pmf-control-information.go b/ie/pmf-control-information.go index 94a0c42..fcf07a5 100644 --- a/ie/pmf-control-information.go +++ b/ie/pmf-control-information.go @@ -4,8 +4,6 @@ package ie -import "io" - // NewPMFControlInformation creates a new PMFControlInformation IE. func NewPMFControlInformation(pmfi uint8) *IE { return newUint8ValIE(PMFControlInformation, pmfi&0x01) @@ -13,13 +11,9 @@ func NewPMFControlInformation(pmfi uint8) *IE { // PMFControlInformation returns PMFControlInformation in uint8 if the type of IE matches. func (i *IE) PMFControlInformation() (uint8, error) { - if len(i.Payload) < 1 { - return 0, io.ErrUnexpectedEOF - } - switch i.Type { case PMFControlInformation: - return i.Payload[0], nil + return i.ValueAsUint8() case ProvideATSSSControlInformation: ies, err := i.ProvideATSSSControlInformation() if err != nil { diff --git a/ie/port-management-information-container.go b/ie/port-management-information-container.go index 7f39e55..fca0ac9 100644 --- a/ie/port-management-information-container.go +++ b/ie/port-management-information-container.go @@ -13,7 +13,7 @@ func NewPortManagementInformationContainer(info string) *IE { func (i *IE) PortManagementInformationContainer() (string, error) { switch i.Type { case PortManagementInformationContainer: - return string(i.Payload), nil + return i.ValueAsString() case TSCManagementInformationWithinSessionModificationRequest, TSCManagementInformationWithinSessionModificationResponse, TSCManagementInformationWithinSessionReportRequest: diff --git a/ie/precedence.go b/ie/precedence.go index 3f87b86..b4ac08f 100644 --- a/ie/precedence.go +++ b/ie/precedence.go @@ -4,10 +4,6 @@ package ie -import ( - "encoding/binary" -) - // NewPrecedence creates a new Precedence IE. func NewPrecedence(id uint32) *IE { return newUint32ValIE(Precedence, id) @@ -15,13 +11,9 @@ func NewPrecedence(id uint32) *IE { // Precedence returns Precedence in uint32 if the type of IE matches. func (i *IE) Precedence() (uint32, error) { - if len(i.Payload) < 4 { - return 0, &InvalidTypeError{Type: i.Type} - } - switch i.Type { case Precedence: - return binary.BigEndian.Uint32(i.Payload[0:4]), nil + return i.ValueAsUint32() case CreatePDR: ies, err := i.CreatePDR() if err != nil { diff --git a/ie/priority.go b/ie/priority.go index 03723d9..8101d79 100644 --- a/ie/priority.go +++ b/ie/priority.go @@ -4,8 +4,6 @@ package ie -import "io" - // Priority definitions. const ( PriorityActive uint8 = 0 @@ -22,13 +20,9 @@ func NewPriority(priority uint8) *IE { // Priority returns Priority in uint8 if the type of IE matches. func (i *IE) Priority() (uint8, error) { - if len(i.Payload) < 1 { - return 0, io.ErrUnexpectedEOF - } - switch i.Type { case Priority: - return i.Payload[0], nil + return i.ValueAsUint8() case CreateMAR: ies, err := i.CreateMAR() if err != nil { diff --git a/ie/proxying.go b/ie/proxying.go index 083b1c7..a0458bf 100644 --- a/ie/proxying.go +++ b/ie/proxying.go @@ -4,8 +4,6 @@ package ie -import "io" - // NewProxying creates a new Proxying IE. func NewProxying(ins, arp uint8) *IE { return newUint8ValIE(Proxying, (ins<<1)|arp) @@ -13,13 +11,9 @@ func NewProxying(ins, arp uint8) *IE { // Proxying returns Proxying in uint8 if the type of IE matches. func (i *IE) Proxying() (uint8, error) { - if len(i.Payload) < 1 { - return 0, io.ErrUnexpectedEOF - } - switch i.Type { case Proxying: - return i.Payload[0], nil + return i.ValueAsUint8() case ForwardingParameters: ies, err := i.ForwardingParameters() if err != nil { diff --git a/ie/qer-control-indications.go b/ie/qer-control-indications.go index bd8f340..0e97323 100644 --- a/ie/qer-control-indications.go +++ b/ie/qer-control-indications.go @@ -4,8 +4,6 @@ package ie -import "io" - // NewQERControlIndications creates a new QERControlIndications IE. func NewQERControlIndications(nord, mode, rcsr int) *IE { return newUint8ValIE(QERControlIndications, uint8((nord<<2)|(mode<<1)|(rcsr))) @@ -13,13 +11,9 @@ func NewQERControlIndications(nord, mode, rcsr int) *IE { // QERControlIndications returns QERControlIndications in uint8 if the type of IE matches. func (i *IE) QERControlIndications() (uint8, error) { - if len(i.Payload) < 1 { - return 0, io.ErrUnexpectedEOF - } - switch i.Type { case QERControlIndications: - return i.Payload[0], nil + return i.ValueAsUint8() case CreateQER: ies, err := i.CreateQER() if err != nil { diff --git a/ie/qer-correlation-id.go b/ie/qer-correlation-id.go index aa787df..817936e 100644 --- a/ie/qer-correlation-id.go +++ b/ie/qer-correlation-id.go @@ -4,10 +4,6 @@ package ie -import ( - "encoding/binary" -) - // NewQERCorrelationID creates a new QERCorrelationID IE. func NewQERCorrelationID(id uint32) *IE { return newUint32ValIE(QERCorrelationID, id) @@ -15,13 +11,9 @@ func NewQERCorrelationID(id uint32) *IE { // QERCorrelationID returns QERCorrelationID in uint32 if the type of IE matches. func (i *IE) QERCorrelationID() (uint32, error) { - if len(i.Payload) < 4 { - return 0, &InvalidTypeError{Type: i.Type} - } - switch i.Type { case QERCorrelationID: - return binary.BigEndian.Uint32(i.Payload[0:4]), nil + return i.ValueAsUint32() case CreateQER: ies, err := i.CreateQER() if err != nil { diff --git a/ie/qer-id.go b/ie/qer-id.go index b12dde4..9d3b205 100644 --- a/ie/qer-id.go +++ b/ie/qer-id.go @@ -4,11 +4,6 @@ package ie -import ( - "encoding/binary" - "io" -) - // NewQERID creates a new QERID IE. func NewQERID(id uint32) *IE { return newUint32ValIE(QERID, id) @@ -16,13 +11,9 @@ func NewQERID(id uint32) *IE { // QERID returns QERID in uint32 if the type of IE matches. func (i *IE) QERID() (uint32, error) { - if len(i.Payload) < 4 { - return 0, io.ErrUnexpectedEOF - } - switch i.Type { case QERID: - return binary.BigEndian.Uint32(i.Payload[0:4]), nil + return i.ValueAsUint32() case CreatePDR: ies, err := i.CreatePDR() if err != nil { diff --git a/ie/qfi.go b/ie/qfi.go index f76d3bd..38b57b4 100644 --- a/ie/qfi.go +++ b/ie/qfi.go @@ -13,13 +13,9 @@ func NewQFI(qfi uint8) *IE { // QFI returns QFI in uint8 if the type of IE matches. func (i *IE) QFI() (uint8, error) { - if len(i.Payload) < 1 { - return 0, io.ErrUnexpectedEOF - } - switch i.Type { case QFI: - return i.Payload[0], nil + return i.ValueAsUint8() case DownlinkDataServiceInformation: if len(i.Payload) < 2 { return 0, io.ErrUnexpectedEOF diff --git a/ie/qos-report-trigger.go b/ie/qos-report-trigger.go index e90ec2e..3cc9ee4 100644 --- a/ie/qos-report-trigger.go +++ b/ie/qos-report-trigger.go @@ -4,8 +4,6 @@ package ie -import "io" - // NewQoSReportTrigger creates a new QoSReportTrigger IE. func NewQoSReportTrigger(ire, thr, per int) *IE { return newUint8ValIE(QoSReportTrigger, uint8((ire<<2)|(thr<<1)|(per))) @@ -13,13 +11,9 @@ func NewQoSReportTrigger(ire, thr, per int) *IE { // QoSReportTrigger returns QoSReportTrigger in uint8 if the type of IE matches. func (i *IE) QoSReportTrigger() (uint8, error) { - if len(i.Payload) < 1 { - return 0, io.ErrUnexpectedEOF - } - switch i.Type { case QoSReportTrigger: - return i.Payload[0], nil + return i.ValueAsUint8() case GTPUPathQoSControlInformation: ies, err := i.GTPUPathQoSControlInformation() if err != nil { diff --git a/ie/query-urr-reference.go b/ie/query-urr-reference.go index a778dda..eea6c55 100644 --- a/ie/query-urr-reference.go +++ b/ie/query-urr-reference.go @@ -4,11 +4,6 @@ package ie -import ( - "encoding/binary" - "io" -) - // NewQueryURRReference creates a new QueryURRReference IE. func NewQueryURRReference(id uint32) *IE { return newUint32ValIE(QueryURRReference, id) @@ -16,13 +11,9 @@ func NewQueryURRReference(id uint32) *IE { // QueryURRReference returns QueryURRReference in uint32 if the type of IE matches. func (i *IE) QueryURRReference() (uint32, error) { - if len(i.Payload) < 4 { - return 0, io.ErrUnexpectedEOF - } - switch i.Type { case QueryURRReference: - return binary.BigEndian.Uint32(i.Payload[0:4]), nil + return i.ValueAsUint32() case UsageReportWithinSessionModificationResponse, UsageReportWithinSessionReportRequest: ies, err := i.UsageReport() diff --git a/ie/rds-configuration-information.go b/ie/rds-configuration-information.go index af997fa..63f5c71 100644 --- a/ie/rds-configuration-information.go +++ b/ie/rds-configuration-information.go @@ -4,8 +4,6 @@ package ie -import "io" - // NewRDSConfigurationInformation creates a new RDSConfigurationInformation IE. func NewRDSConfigurationInformation(rds uint8) *IE { return newUint8ValIE(RDSConfigurationInformation, rds&0x01) @@ -13,13 +11,9 @@ func NewRDSConfigurationInformation(rds uint8) *IE { // RDSConfigurationInformation returns RDSConfigurationInformation in uint8 if the type of IE matches. func (i *IE) RDSConfigurationInformation() (uint8, error) { - if len(i.Payload) < 1 { - return 0, io.ErrUnexpectedEOF - } - switch i.Type { case RDSConfigurationInformation: - return i.Payload[0], nil + return i.ValueAsUint8() case ProvideRDSConfigurationInformation: ies, err := i.ProvideRDSConfigurationInformation() if err != nil { diff --git a/ie/recovery-time-stamp.go b/ie/recovery-time-stamp.go index 577fc49..cd6a7d3 100644 --- a/ie/recovery-time-stamp.go +++ b/ie/recovery-time-stamp.go @@ -5,8 +5,6 @@ package ie import ( - "encoding/binary" - "io" "time" ) @@ -22,8 +20,5 @@ func (i *IE) RecoveryTimeStamp() (time.Time, error) { return time.Time{}, &InvalidTypeError{Type: i.Type} } - if len(i.Payload) < 4 { - return time.Time{}, io.ErrUnexpectedEOF - } - return time.Unix(int64(binary.BigEndian.Uint32(i.Payload[0:4])-2208988800), 0), nil + return i.valueAs3GPPTimestamp() } diff --git a/ie/report-type.go b/ie/report-type.go index 55377bb..9cf04e9 100644 --- a/ie/report-type.go +++ b/ie/report-type.go @@ -15,7 +15,7 @@ func (i *IE) ReportType() (uint8, error) { return 0, &InvalidTypeError{Type: i.Type} } - return i.Payload[0], nil + return i.ValueAsUint8() } // HasUPIR reports whether an IE has UPIR bit. diff --git a/ie/reporting-frequency.go b/ie/reporting-frequency.go index 9721950..487bef8 100644 --- a/ie/reporting-frequency.go +++ b/ie/reporting-frequency.go @@ -4,8 +4,6 @@ package ie -import "io" - // NewReportingFrequency creates a new ReportingFrequency IE. func NewReportingFrequency(sesrl, perio, evett int) *IE { return newUint8ValIE(ReportingFrequency, uint8((sesrl<<2)|(perio<<1)|(evett))) @@ -13,13 +11,9 @@ func NewReportingFrequency(sesrl, perio, evett int) *IE { // ReportingFrequency returns ReportingFrequency in uint8 if the type of IE matches. func (i *IE) ReportingFrequency() (uint8, error) { - if len(i.Payload) < 1 { - return 0, io.ErrUnexpectedEOF - } - switch i.Type { case ReportingFrequency: - return i.Payload[0], nil + return i.ValueAsUint8() case QoSMonitoringPerQoSFlowControlInformation: ies, err := i.QoSMonitoringPerQoSFlowControlInformation() if err != nil { diff --git a/ie/requested-access-availability-information.go b/ie/requested-access-availability-information.go index 187b49b..c28e07c 100644 --- a/ie/requested-access-availability-information.go +++ b/ie/requested-access-availability-information.go @@ -4,8 +4,6 @@ package ie -import "io" - // NewRequestedAccessAvailabilityInformation creates a new RequestedAccessAvailabilityInformation IE. func NewRequestedAccessAvailabilityInformation(rrca uint8) *IE { return newUint8ValIE(RequestedAccessAvailabilityInformation, rrca&0x01) @@ -13,13 +11,9 @@ func NewRequestedAccessAvailabilityInformation(rrca uint8) *IE { // RequestedAccessAvailabilityInformation returns RequestedAccessAvailabilityInformation in uint8 if the type of IE matches. func (i *IE) RequestedAccessAvailabilityInformation() (uint8, error) { - if len(i.Payload) < 1 { - return 0, io.ErrUnexpectedEOF - } - switch i.Type { case RequestedAccessAvailabilityInformation: - return i.Payload[0], nil + return i.ValueAsUint8() case AccessAvailabilityControlInformation: ies, err := i.AccessAvailabilityControlInformation() if err != nil { diff --git a/ie/requested-clock-drift-information.go b/ie/requested-clock-drift-information.go index 9d899c6..ee54909 100644 --- a/ie/requested-clock-drift-information.go +++ b/ie/requested-clock-drift-information.go @@ -4,8 +4,6 @@ package ie -import "io" - // NewRequestedClockDriftInformation creates a new RequestedClockDriftInformation IE. func NewRequestedClockDriftInformation(rrcr, rrto uint8) *IE { return newUint8ValIE(RequestedClockDriftInformation, (rrcr<<1)|rrto) @@ -13,13 +11,9 @@ func NewRequestedClockDriftInformation(rrcr, rrto uint8) *IE { // RequestedClockDriftInformation returns RequestedClockDriftInformation in uint8 if the type of IE matches. func (i *IE) RequestedClockDriftInformation() (uint8, error) { - if len(i.Payload) < 1 { - return 0, io.ErrUnexpectedEOF - } - switch i.Type { case RequestedClockDriftInformation: - return i.Payload[0], nil + return i.ValueAsUint8() case ClockDriftControlInformation: ies, err := i.ClockDriftControlInformation() if err != nil { diff --git a/ie/requested-qos-monitoring.go b/ie/requested-qos-monitoring.go index d6a30f9..1c50f9a 100644 --- a/ie/requested-qos-monitoring.go +++ b/ie/requested-qos-monitoring.go @@ -4,8 +4,6 @@ package ie -import "io" - // NewRequestedQoSMonitoring creates a new RequestedQoSMonitoring IE. func NewRequestedQoSMonitoring(rp, ul, dl int) *IE { return newUint8ValIE(RequestedQoSMonitoring, uint8((rp<<2)|(ul<<1)|(dl))) @@ -13,13 +11,9 @@ func NewRequestedQoSMonitoring(rp, ul, dl int) *IE { // RequestedQoSMonitoring returns RequestedQoSMonitoring in uint8 if the type of IE matches. func (i *IE) RequestedQoSMonitoring() (uint8, error) { - if len(i.Payload) < 1 { - return 0, io.ErrUnexpectedEOF - } - switch i.Type { case RequestedQoSMonitoring: - return i.Payload[0], nil + return i.ValueAsUint8() case QoSMonitoringPerQoSFlowControlInformation: ies, err := i.QoSMonitoringPerQoSFlowControlInformation() if err != nil { diff --git a/ie/rqi.go b/ie/rqi.go index 3ae19f8..b283dfb 100644 --- a/ie/rqi.go +++ b/ie/rqi.go @@ -4,8 +4,6 @@ package ie -import "io" - // NewRQI creates a new RQI IE. func NewRQI(rqi uint8) *IE { return newUint8ValIE(RQI, rqi) @@ -13,13 +11,9 @@ func NewRQI(rqi uint8) *IE { // RQI returns RQI in uint8 if the type of IE matches. func (i *IE) RQI() (uint8, error) { - if len(i.Payload) < 1 { - return 0, io.ErrUnexpectedEOF - } - switch i.Type { case RQI: - return i.Payload[0], nil + return i.ValueAsUint8() case CreateQER: ies, err := i.CreateQER() if err != nil { diff --git a/ie/sequence-number.go b/ie/sequence-number.go index 0c1e636..9866068 100644 --- a/ie/sequence-number.go +++ b/ie/sequence-number.go @@ -4,11 +4,6 @@ package ie -import ( - "encoding/binary" - "io" -) - // NewSequenceNumber creates a new SequenceNumber IE. func NewSequenceNumber(seq uint32) *IE { return newUint32ValIE(SequenceNumber, seq) @@ -16,13 +11,9 @@ func NewSequenceNumber(seq uint32) *IE { // SequenceNumber returns SequenceNumber in uint32 if the type of IE matches. func (i *IE) SequenceNumber() (uint32, error) { - if len(i.Payload) < 4 { - return 0, io.ErrUnexpectedEOF - } - switch i.Type { case SequenceNumber: - return binary.BigEndian.Uint32(i.Payload[0:4]), nil + return i.ValueAsUint32() case LoadControlInformation: ies, err := i.LoadControlInformation() if err != nil { diff --git a/ie/source-interface.go b/ie/source-interface.go index 2178a66..ee9d9f6 100644 --- a/ie/source-interface.go +++ b/ie/source-interface.go @@ -4,8 +4,6 @@ package ie -import "io" - // Interface definitions. const ( SrcInterfaceAccess uint8 = 0 @@ -22,13 +20,9 @@ func NewSourceInterface(intf uint8) *IE { // SourceInterface returns SourceInterface in uint8 if the type of IE matches. func (i *IE) SourceInterface() (uint8, error) { - if len(i.Payload) < 1 { - return 0, io.ErrUnexpectedEOF - } - switch i.Type { case SourceInterface: - return i.Payload[0], nil + return i.ValueAsUint8() case CreatePDR: ies, err := i.CreatePDR() if err != nil { diff --git a/ie/srr-id.go b/ie/srr-id.go index d19e4ce..6094aeb 100644 --- a/ie/srr-id.go +++ b/ie/srr-id.go @@ -4,8 +4,6 @@ package ie -import "io" - // NewSRRID creates a new SRRID IE. func NewSRRID(id uint8) *IE { return newUint8ValIE(SRRID, id) @@ -13,13 +11,9 @@ func NewSRRID(id uint8) *IE { // SRRID returns SRRID in uint8 if the type of IE matches. func (i *IE) SRRID() (uint8, error) { - if len(i.Payload) < 1 { - return 0, io.ErrUnexpectedEOF - } - switch i.Type { case SRRID: - return i.Payload[0], nil + return i.ValueAsUint8() case RemoveSRR: ies, err := i.RemoveSRR() if err != nil { diff --git a/ie/start-time.go b/ie/start-time.go index 5d3e5c8..3bf010e 100644 --- a/ie/start-time.go +++ b/ie/start-time.go @@ -5,8 +5,6 @@ package ie import ( - "encoding/binary" - "io" "time" ) @@ -18,13 +16,9 @@ func NewStartTime(ts time.Time) *IE { // StartTime returns StartTime in time.Time if the type of IE matches. func (i *IE) StartTime() (time.Time, error) { - if len(i.Payload) < 4 { - return time.Time{}, io.ErrUnexpectedEOF - } - switch i.Type { case StartTime: - return time.Unix(int64(binary.BigEndian.Uint32(i.Payload[0:4])-2208988800), 0), nil + return i.valueAs3GPPTimestamp() case UsageReportWithinSessionModificationResponse, UsageReportWithinSessionDeletionResponse, UsageReportWithinSessionReportRequest: diff --git a/ie/steering-functionality.go b/ie/steering-functionality.go index 4b11d4b..d87c190 100644 --- a/ie/steering-functionality.go +++ b/ie/steering-functionality.go @@ -4,8 +4,6 @@ package ie -import "io" - // SteeringFunctionality definitions. const ( SteeringFunctionalityATSSSLL uint8 = 0 @@ -19,13 +17,9 @@ func NewSteeringFunctionality(sfunc uint8) *IE { // SteeringFunctionality returns SteeringFunctionality in uint8 if the type of IE matches. func (i *IE) SteeringFunctionality() (uint8, error) { - if len(i.Payload) < 1 { - return 0, io.ErrUnexpectedEOF - } - switch i.Type { case SteeringFunctionality: - return i.Payload[0], nil + return i.ValueAsUint8() case CreateMAR: ies, err := i.CreateMAR() if err != nil { diff --git a/ie/steering-mode.go b/ie/steering-mode.go index 4a09f62..3532e2d 100644 --- a/ie/steering-mode.go +++ b/ie/steering-mode.go @@ -4,8 +4,6 @@ package ie -import "io" - // SteeringMode definitions. const ( SteeringModeActiveStandby uint8 = 0 @@ -21,13 +19,9 @@ func NewSteeringMode(mode uint8) *IE { // SteeringMode returns SteeringMode in uint8 if the type of IE matches. func (i *IE) SteeringMode() (uint8, error) { - if len(i.Payload) < 1 { - return 0, io.ErrUnexpectedEOF - } - switch i.Type { case SteeringMode: - return i.Payload[0], nil + return i.ValueAsUint8() case CreateMAR: ies, err := i.CreateMAR() if err != nil { diff --git a/ie/subsequent-event-quota.go b/ie/subsequent-event-quota.go index 9259ef6..3c5ed66 100644 --- a/ie/subsequent-event-quota.go +++ b/ie/subsequent-event-quota.go @@ -4,11 +4,6 @@ package ie -import ( - "encoding/binary" - "io" -) - // NewSubsequentEventQuota creates a new SubsequentEventQuota IE. func NewSubsequentEventQuota(quota uint32) *IE { return newUint32ValIE(SubsequentEventQuota, quota) @@ -16,13 +11,9 @@ func NewSubsequentEventQuota(quota uint32) *IE { // SubsequentEventQuota returns SubsequentEventQuota in uint32 if the type of IE matches. func (i *IE) SubsequentEventQuota() (uint32, error) { - if len(i.Payload) < 4 { - return 0, io.ErrUnexpectedEOF - } - switch i.Type { case SubsequentEventQuota: - return binary.BigEndian.Uint32(i.Payload[0:4]), nil + return i.ValueAsUint32() case CreateURR: ies, err := i.CreateURR() if err != nil { diff --git a/ie/subsequent-event-threshold.go b/ie/subsequent-event-threshold.go index 69ec611..bccc62d 100644 --- a/ie/subsequent-event-threshold.go +++ b/ie/subsequent-event-threshold.go @@ -4,11 +4,6 @@ package ie -import ( - "encoding/binary" - "io" -) - // NewSubsequentEventThreshold creates a new SubsequentEventThreshold IE. func NewSubsequentEventThreshold(quota uint32) *IE { return newUint32ValIE(SubsequentEventThreshold, quota) @@ -16,13 +11,9 @@ func NewSubsequentEventThreshold(quota uint32) *IE { // SubsequentEventThreshold returns SubsequentEventThreshold in uint32 if the type of IE matches. func (i *IE) SubsequentEventThreshold() (uint32, error) { - if len(i.Payload) < 4 { - return 0, io.ErrUnexpectedEOF - } - switch i.Type { case SubsequentEventThreshold: - return binary.BigEndian.Uint32(i.Payload[0:4]), nil + return i.ValueAsUint32() case CreateURR: ies, err := i.CreateURR() if err != nil { diff --git a/ie/suggested-buffering-packets-count.go b/ie/suggested-buffering-packets-count.go index 73813a0..cd62984 100644 --- a/ie/suggested-buffering-packets-count.go +++ b/ie/suggested-buffering-packets-count.go @@ -4,10 +4,6 @@ package ie -import ( - "io" -) - // NewSuggestedBufferingPacketsCount creates a new SuggestedBufferingPacketsCount IE. func NewSuggestedBufferingPacketsCount(count uint8) *IE { return newUint8ValIE(SuggestedBufferingPacketsCount, count) @@ -15,13 +11,9 @@ func NewSuggestedBufferingPacketsCount(count uint8) *IE { // SuggestedBufferingPacketsCount returns SuggestedBufferingPacketsCount in uint8 if the type of IE matches. func (i *IE) SuggestedBufferingPacketsCount() (uint8, error) { - if len(i.Payload) < 1 { - return 0, io.ErrUnexpectedEOF - } - switch i.Type { case SuggestedBufferingPacketsCount: - return i.Payload[0], nil + return i.ValueAsUint8() case CreateBAR: ies, err := i.CreateBAR() if err != nil { diff --git a/ie/time-of-first-packet.go b/ie/time-of-first-packet.go index 1ae4efc..821c9b2 100644 --- a/ie/time-of-first-packet.go +++ b/ie/time-of-first-packet.go @@ -5,8 +5,6 @@ package ie import ( - "encoding/binary" - "io" "time" ) @@ -18,13 +16,9 @@ func NewTimeOfFirstPacket(ts time.Time) *IE { // TimeOfFirstPacket returns TimeOfFirstPacket in time.Time if the type of IE matches. func (i *IE) TimeOfFirstPacket() (time.Time, error) { - if len(i.Payload) < 4 { - return time.Time{}, io.ErrUnexpectedEOF - } - switch i.Type { case TimeOfFirstPacket: - return time.Unix(int64(binary.BigEndian.Uint32(i.Payload[0:4])-2208988800), 0), nil + return i.valueAs3GPPTimestamp() case UsageReportWithinSessionModificationResponse, UsageReportWithinSessionDeletionResponse, UsageReportWithinSessionReportRequest: diff --git a/ie/time-of-last-packet.go b/ie/time-of-last-packet.go index 07e5c58..b0f352d 100644 --- a/ie/time-of-last-packet.go +++ b/ie/time-of-last-packet.go @@ -5,8 +5,6 @@ package ie import ( - "encoding/binary" - "io" "time" ) @@ -18,13 +16,9 @@ func NewTimeOfLastPacket(ts time.Time) *IE { // TimeOfLastPacket returns TimeOfLastPacket in time.Time if the type of IE matches. func (i *IE) TimeOfLastPacket() (time.Time, error) { - if len(i.Payload) < 4 { - return time.Time{}, io.ErrUnexpectedEOF - } - switch i.Type { case TimeOfLastPacket: - return time.Unix(int64(binary.BigEndian.Uint32(i.Payload[0:4])-2208988800), 0), nil + return i.valueAs3GPPTimestamp() case UsageReportWithinSessionModificationResponse, UsageReportWithinSessionDeletionResponse, UsageReportWithinSessionReportRequest: diff --git a/ie/traffic-endpoint-id.go b/ie/traffic-endpoint-id.go index 99c47ad..899090e 100644 --- a/ie/traffic-endpoint-id.go +++ b/ie/traffic-endpoint-id.go @@ -4,10 +4,6 @@ package ie -import ( - "io" -) - // NewTrafficEndpointID creates a new TrafficEndpointID IE. func NewTrafficEndpointID(id uint8) *IE { return newUint8ValIE(TrafficEndpointID, id) @@ -15,13 +11,9 @@ func NewTrafficEndpointID(id uint8) *IE { // TrafficEndpointID returns TrafficEndpointID in uint8 if the type of IE matches. func (i *IE) TrafficEndpointID() (uint8, error) { - if len(i.Payload) < 1 { - return 0, io.ErrUnexpectedEOF - } - switch i.Type { case TrafficEndpointID: - return i.Payload[0], nil + return i.ValueAsUint8() case CreatePDR: ies, err := i.CreatePDR() if err != nil { diff --git a/ie/transport-level-marking.go b/ie/transport-level-marking.go index cb25598..cec1e1c 100644 --- a/ie/transport-level-marking.go +++ b/ie/transport-level-marking.go @@ -4,10 +4,6 @@ package ie -import ( - "encoding/binary" -) - // NewTransportLevelMarking creates a new TransportLevelMarking IE. func NewTransportLevelMarking(tos uint16) *IE { return newUint16ValIE(TransportLevelMarking, tos) @@ -15,13 +11,9 @@ func NewTransportLevelMarking(tos uint16) *IE { // TransportLevelMarking returns TransportLevelMarking in uint16 if the type of IE matches. func (i *IE) TransportLevelMarking() (uint16, error) { - if len(i.Payload) < 2 { - return 0, &InvalidTypeError{Type: i.Type} - } - switch i.Type { case TransportLevelMarking: - return binary.BigEndian.Uint16(i.Payload[0:2]), nil + return i.ValueAsUint16() case ForwardingParameters: ies, err := i.ForwardingParameters() if err != nil { diff --git a/ie/tsn-time-domain-number.go b/ie/tsn-time-domain-number.go index 2265867..abdb0a6 100644 --- a/ie/tsn-time-domain-number.go +++ b/ie/tsn-time-domain-number.go @@ -4,8 +4,6 @@ package ie -import "io" - // NewTSNTimeDomainNumber creates a new TSNTimeDomainNumber IE. func NewTSNTimeDomainNumber(num uint8) *IE { return newUint8ValIE(TSNTimeDomainNumber, num) @@ -13,13 +11,9 @@ func NewTSNTimeDomainNumber(num uint8) *IE { // TSNTimeDomainNumber returns TSNTimeDomainNumber in uint8 if the type of IE matches. func (i *IE) TSNTimeDomainNumber() (uint8, error) { - if len(i.Payload) < 1 { - return 0, io.ErrUnexpectedEOF - } - switch i.Type { case TSNTimeDomainNumber: - return i.Payload[0], nil + return i.ValueAsUint8() case ClockDriftControlInformation: ies, err := i.ClockDriftControlInformation() if err != nil { diff --git a/ie/ur-seqn.go b/ie/ur-seqn.go index 1922ea4..a93d96c 100644 --- a/ie/ur-seqn.go +++ b/ie/ur-seqn.go @@ -4,11 +4,6 @@ package ie -import ( - "encoding/binary" - "io" -) - // NewURSEQN creates a new URSEQN IE. func NewURSEQN(seq uint32) *IE { return newUint32ValIE(URSEQN, seq) @@ -16,13 +11,9 @@ func NewURSEQN(seq uint32) *IE { // URSEQN returns URSEQN in uint32 if the type of IE matches. func (i *IE) URSEQN() (uint32, error) { - if len(i.Payload) < 4 { - return 0, io.ErrUnexpectedEOF - } - switch i.Type { case URSEQN: - return binary.BigEndian.Uint32(i.Payload[0:4]), nil + return i.ValueAsUint32() case UsageReportWithinSessionModificationResponse, UsageReportWithinSessionDeletionResponse, UsageReportWithinSessionReportRequest: diff --git a/ie/urr-id.go b/ie/urr-id.go index 29c58ed..e5bd78d 100644 --- a/ie/urr-id.go +++ b/ie/urr-id.go @@ -4,11 +4,6 @@ package ie -import ( - "encoding/binary" - "io" -) - // NewURRID creates a new URRID IE. func NewURRID(id uint32) *IE { return newUint32ValIE(URRID, id) @@ -18,11 +13,7 @@ func NewURRID(id uint32) *IE { func (i *IE) URRID() (uint32, error) { switch i.Type { case URRID: - if len(i.Payload) < 4 { - return 0, io.ErrUnexpectedEOF - } - - return binary.BigEndian.Uint32(i.Payload[0:4]), nil + return i.ValueAsUint32() case CreatePDR: ies, err := i.CreatePDR() if err != nil { diff --git a/ie/usage-information.go b/ie/usage-information.go index e558b1f..87463b5 100644 --- a/ie/usage-information.go +++ b/ie/usage-information.go @@ -4,8 +4,6 @@ package ie -import "io" - // NewUsageInformation creates a new UsageInformation IE. func NewUsageInformation(bef, aft, uae, ube int) *IE { return newUint8ValIE(UsageInformation, uint8((ube<<3)|(uae<<2)|(aft<<1)|(bef))) @@ -13,13 +11,9 @@ func NewUsageInformation(bef, aft, uae, ube int) *IE { // UsageInformation returns UsageInformation in uint8 if the type of IE matches. func (i *IE) UsageInformation() (uint8, error) { - if len(i.Payload) < 1 { - return 0, io.ErrUnexpectedEOF - } - switch i.Type { case UsageInformation: - return i.Payload[0], nil + return i.ValueAsUint8() case UsageReportWithinSessionModificationResponse, UsageReportWithinSessionDeletionResponse, UsageReportWithinSessionReportRequest: diff --git a/ie/weight.go b/ie/weight.go index 24f1be9..5b3c258 100644 --- a/ie/weight.go +++ b/ie/weight.go @@ -4,10 +4,6 @@ package ie -import ( - "io" -) - // NewWeight creates a new Weight IE. func NewWeight(weight uint8) *IE { return newUint8ValIE(Weight, weight) @@ -15,13 +11,9 @@ func NewWeight(weight uint8) *IE { // Weight returns Weight in uint8 if the type of IE matches. func (i *IE) Weight() (uint8, error) { - if len(i.Payload) < 1 { - return 0, io.ErrUnexpectedEOF - } - switch i.Type { case Weight: - return i.Payload[0], nil + return i.ValueAsUint8() case CreateMAR: ies, err := i.CreateMAR() if err != nil {