Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[gtpv2] Easier IE handling #259

Merged
merged 2 commits into from
Dec 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions gtpv2/ie/ambr.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,6 @@ import (

// NewAggregateMaximumBitRate creates a new AggregateMaximumBitRate IE.
func NewAggregateMaximumBitRate(up, down uint32) *IE {
// this is more efficient but removed for consistency with other structured IEs.
// return newUint64ValIE(AggregateMaximumBitRate, (uint64(up)<<32 | uint64(down)))

v := NewAggregateMaximumBitRateFields(up, down)
b, err := v.Marshal()
if err != nil {
Expand Down
15 changes: 7 additions & 8 deletions gtpv2/ie/apn-restriction.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,9 @@

package ie

import "io"

// NewAPNRestriction creates a new APNRestriction IE.
func NewAPNRestriction(restriction uint8) *IE {
return newUint8ValIE(APNRestriction, restriction)
return NewUint8IE(APNRestriction, restriction)
}

// APNRestriction returns APNRestriction in uint8 if the type of IE matches.
Expand All @@ -17,11 +15,7 @@ func (i *IE) APNRestriction() (uint8, error) {
return 0, &InvalidTypeError{Type: i.Type}
}

if len(i.Payload) < 1 {
return 0, io.ErrUnexpectedEOF
}

return i.Payload[0], nil
return i.ValueAsUint8()
}

// MustAPNRestriction returns APNRestriction in uint8, ignoring errors.
Expand All @@ -30,3 +24,8 @@ func (i *IE) MustAPNRestriction() uint8 {
v, _ := i.APNRestriction()
return v
}

// RestrictionType returns RestrictionType in uint8 if the type of IE matches.
func (i *IE) RestrictionType() (uint8, error) {
return i.APNRestriction()
}
35 changes: 2 additions & 33 deletions gtpv2/ie/apn.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,48 +4,17 @@

package ie

import (
"strings"
)

// NewAccessPointName creates a new AccessPointName IE.
func NewAccessPointName(apn string) *IE {
i := New(AccessPointName, 0x00, make([]byte, len(apn)+1))
var offset = 0
for _, label := range strings.Split(apn, ".") {
l := len(label)
i.Payload[offset] = uint8(l)
copy(i.Payload[offset+1:], label)
offset += l + 1
}

return i
return NewFQDNIE(AccessPointName, apn)
}

// AccessPointName returns AccessPointName in string if the type of IE matches.
func (i *IE) AccessPointName() (string, error) {
if i.Type != AccessPointName {
return "", &InvalidTypeError{Type: i.Type}
}

var (
apn []string
offset int
)
max := len(i.Payload)
for {
if offset >= max {
break
}
l := int(i.Payload[offset])
if offset+l+1 > max {
break
}
apn = append(apn, string(i.Payload[offset+1:offset+l+1]))
offset += l + 1
}

return strings.Join(apn, "."), nil
return i.ValueAsFQDN()
}

// MustAccessPointName returns AccessPointName in string, ignoring errors.
Expand Down
9 changes: 2 additions & 7 deletions gtpv2/ie/arp.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,19 @@

package ie

import "io"

// NewAllocationRetensionPriority creates a new AllocationRetensionPriority IE.
func NewAllocationRetensionPriority(pci, pl, pvi uint8) *IE {
i := New(AllocationRetensionPriority, 0x00, make([]byte, 1))
i.Payload[0] |= (pci << 6 & 0x40) | (pl << 2 & 0x3c) | (pvi & 0x01)
return i
}

// AllocationRetensionPriority returns AllocationRetensionPriority in uint8 if the type of IE matches.
func (i *IE) AllocationRetensionPriority() (uint8, error) {
if i.Type != AllocationRetensionPriority {
return 0, &InvalidTypeError{Type: i.Type}
}
if len(i.Payload) < 1 {
return 0, io.ErrUnexpectedEOF
}

return i.Payload[0], nil
return i.ValueAsUint8()
}

// HasPVI reports whether an IE has PVI bit.
Expand Down
8 changes: 1 addition & 7 deletions gtpv2/ie/bearer-context.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,7 @@ import "io"

// NewBearerContext creates a new BearerContext IE.
func NewBearerContext(ies ...*IE) *IE {
var omitted []*IE
for _, ie := range ies {
if ie != nil {
omitted = append(omitted, ie)
}
}
return newGroupedIE(BearerContext, omitted...)
return NewGroupedIE(BearerContext, ies...)
}

// NewBearerContextWithinCreateBearerRequest creates a new BearerContext used within CreateBearerRequest.
Expand Down
53 changes: 14 additions & 39 deletions gtpv2/ie/bearer-flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,6 @@

package ie

import (
"fmt"
"io"
)

// NewBearerFlags creates a new BearerFlags IE.
func NewBearerFlags(asi, vInd, vb, ppc uint8) *IE {
i := New(BearerFlags, 0x00, make([]byte, 1))
Expand All @@ -20,15 +15,11 @@ func NewBearerFlags(asi, vInd, vb, ppc uint8) *IE {
func (i *IE) BearerFlags() (uint8, error) {
switch i.Type {
case BearerFlags:
if len(i.Payload) < 1 {
return 0, io.ErrUnexpectedEOF
}

return i.Payload[0], nil
return i.ValueAsUint8()
case BearerContext:
ies, err := i.BearerContext()
if err != nil {
return 0, fmt.Errorf("failed to retrieve BearerFlags: %w", err)
return 0, err
}

for _, child := range ies {
Expand Down Expand Up @@ -92,54 +83,38 @@ func (i *IE) HasASI() bool {
// ActivityStatusIndicator reports whether the bearer context is preserved in
// the CN without corresponding Radio Access Bearer established.
func (i *IE) ActivityStatusIndicator() bool {
if len(i.Payload) < 1 {
return false
}
switch i.Type {
case BearerFlags:
return i.Payload[0]&0x08 == 1
default:
v, err := i.BearerFlags()
if err != nil {
return false
}
return v&0x08 == 1
}

// VSRVCC reports whether this bearer is an IMS video bearer and is candidate
// for PS-to-CS vSRVCC handover.
func (i *IE) VSRVCC() bool {
if len(i.Payload) < 1 {
return false
}
switch i.Type {
case BearerFlags:
return i.Payload[0]&0x04 == 1
default:
v, err := i.BearerFlags()
if err != nil {
return false
}
return v&0x04 == 1
}

// VoiceBearer reports whether a voice bearer when doing PS-to-CS (v)SRVCC handover.
func (i *IE) VoiceBearer() bool {
if len(i.Payload) < 1 {
return false
}
switch i.Type {
case BearerFlags:
return i.Payload[0]&0x02 == 1
default:
v, err := i.BearerFlags()
if err != nil {
return false
}
return v&0x02 == 1
}

// ProhibitPayloadCompression reports whether an SGSN should attempt to
// compress the payload of user data when the users asks for it to be compressed.
func (i *IE) ProhibitPayloadCompression() bool {
if len(i.Payload) < 1 {
return false
}
switch i.Type {
case BearerFlags:
return i.Payload[0]&0x01 == 1
default:
v, err := i.BearerFlags()
if err != nil {
return false
}
return v&0x01 == 1
}
5 changes: 1 addition & 4 deletions gtpv2/ie/bearer-qos.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,10 +134,7 @@ func (i *IE) QCILabel() (uint8, error) {
}
return i.Payload[1], nil
case FlowQoS:
if len(i.Payload) < 1 {
return 0, io.ErrUnexpectedEOF
}
return i.Payload[0], nil
return i.ValueAsUint8()
default:
return 0, &InvalidTypeError{Type: i.Type}
}
Expand Down
6 changes: 1 addition & 5 deletions gtpv2/ie/cause.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,7 @@ func NewCause(cause uint8, pce, bce, cs uint8, offendingIE *IE) *IE {
func (i *IE) Cause() (uint8, error) {
switch i.Type {
case Cause:
if len(i.Payload) < 1 {
return 0, io.ErrUnexpectedEOF
}

return i.Payload[0], nil
return i.ValueAsUint8()
case BearerContext:
ies, err := i.BearerContext()
if err != nil {
Expand Down
13 changes: 2 additions & 11 deletions gtpv2/ie/charging-characteristics.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,17 @@

package ie

import (
"encoding/binary"
"io"
)

// NewChargingCharacteristics creates a new ChargingCharacteristics IE.
func NewChargingCharacteristics(chr uint16) *IE {
return newUint16ValIE(ChargingCharacteristics, chr)
return NewUint16IE(ChargingCharacteristics, chr)
}

// ChargingCharacteristics returns the ChargingCharacteristics value in uint16 if the type of IE matches.
func (i *IE) ChargingCharacteristics() (uint16, error) {
if i.Type != ChargingCharacteristics {
return 0, &InvalidTypeError{Type: i.Type}
}
if len(i.Payload) < 2 {
return 0, io.ErrUnexpectedEOF
}

return binary.BigEndian.Uint16(i.Payload), nil
return i.ValueAsUint16()
}

// MustChargingCharacteristics returns ChargingCharacteristics in uint16, ignoring errors.
Expand Down
16 changes: 3 additions & 13 deletions gtpv2/ie/charging-id.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,30 +4,20 @@

package ie

import (
"encoding/binary"
"fmt"
"io"
)

// NewChargingID creates a new ChargingID IE.
func NewChargingID(id uint32) *IE {
return newUint32ValIE(ChargingID, id)
return NewUint32IE(ChargingID, id)
}

// ChargingID returns the ChargingID value in uint32 if the type of IE matches.
func (i *IE) ChargingID() (uint32, error) {
switch i.Type {
case ChargingID:
if len(i.Payload) < 4 {
return 0, io.ErrUnexpectedEOF
}

return binary.BigEndian.Uint32(i.Payload[:4]), nil
return i.ValueAsUint32()
case BearerContext:
ies, err := i.BearerContext()
if err != nil {
return 0, fmt.Errorf("failed to retrieve ChargingID: %w", err)
return 0, err
}

for _, child := range ies {
Expand Down
10 changes: 3 additions & 7 deletions gtpv2/ie/cmi.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,19 @@ import "io"

// NewCSGMembershipIndication creates a new CSGMembershipIndication IE.
func NewCSGMembershipIndication(cmi uint8) *IE {
return newUint8ValIE(CSGMembershipIndication, cmi)
return NewUint8IE(CSGMembershipIndication, cmi)
}

// CMI returns CMI in uint8 if the type of IE matches.
func (i *IE) CMI() (uint8, error) {
if len(i.Payload) < 1 {
return 0, io.ErrUnexpectedEOF
}

switch i.Type {
case CSGMembershipIndication:
return i.Payload[0] & 0x01, nil
return i.ValueAsUint8()
case UserCSGInformation:
if len(i.Payload) < 8 {
return 0, io.ErrUnexpectedEOF
}
return i.Payload[7] & 0x01, nil
return i.Payload[7], nil
default:
return 0, &InvalidTypeError{Type: i.Type}
}
Expand Down
8 changes: 2 additions & 6 deletions gtpv2/ie/csg-id.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,14 @@ import (

// NewCSGID creates a new CSGID IE.
func NewCSGID(id uint32) *IE {
return newUint32ValIE(CSGID, id&0x7ffffff)
return NewUint32IE(CSGID, id&0x7ffffff)
}

// CSGID returns CSGID in uint32 if the type of IE matches.
func (i *IE) CSGID() (uint32, error) {
if len(i.Payload) < 4 {
return 0, io.ErrUnexpectedEOF
}

switch i.Type {
case CSGID:
return binary.BigEndian.Uint32(i.Payload[0:4]) & 0x7ffffff, nil
return i.ValueAsUint32()
case UserCSGInformation:
if len(i.Payload) < 7 {
return 0, io.ErrUnexpectedEOF
Expand Down
12 changes: 11 additions & 1 deletion gtpv2/ie/delay-value.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,20 @@ import (

// NewDelayValue creates a new DelayValue IE.
func NewDelayValue(delay time.Duration) *IE {
return newUint8ValIE(DelayValue, uint8(delay.Seconds()*1000/50))
return NewUint8IE(DelayValue, uint8(delay.Seconds()*1000/50))
}

// NewDelayValueRaw creates a new DelayValue IE from a uint8 value.
//
// The value should be in multiples of 50ms or zero.
func NewDelayValueRaw(delay uint8) *IE {
return NewUint8IE(DelayValue, delay)
}

// DelayValue returns DelayValue in time.Duration if the type of IE matches.
//
// The returned value is in time.Duration. To get the value in multiples of 50ms,
// use ValueAsUint8 or access Payload field directly instead.
func (i *IE) DelayValue() (time.Duration, error) {
if i.Type != DelayValue {
return 0, &InvalidTypeError{Type: i.Type}
Expand Down
Loading
Loading