Skip to content

Commit

Permalink
Merge pull request #259 from wmnsk/easier-ie-handling
Browse files Browse the repository at this point in the history
[gtpv2] Easier IE handling
  • Loading branch information
wmnsk authored Dec 29, 2023
2 parents f74fcab + 527b4d0 commit d2d4315
Show file tree
Hide file tree
Showing 38 changed files with 377 additions and 472 deletions.
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

0 comments on commit d2d4315

Please sign in to comment.