pycrate/pycrate_mobile/TS24526_UEPOL.py

945 lines
30 KiB
Python
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# -*- coding: UTF-8 -*-
#/**
# * Software Name : pycrate
# * Version : 0.4
# *
# * Copyright 2019. Benoit Michau. P1Sec.
# *
# * This library is free software; you can redistribute it and/or
# * modify it under the terms of the GNU Lesser General Public
# * License as published by the Free Software Foundation; either
# * version 2.1 of the License, or (at your option) any later version.
# *
# * This library is distributed in the hope that it will be useful,
# * but WITHOUT ANY WARRANTY; without even the implied warranty of
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# * Lesser General Public License for more details.
# *
# * You should have received a copy of the GNU Lesser General Public
# * License along with this library; if not, write to the Free Software
# * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
# * MA 02110-1301 USA
# *
# *--------------------------------------------------------
# * File Name : pycrate_mobile/TS24526_UEPOL.py
# * Created : 2019-12-05
# * Authors : Benoit Michau
# *--------------------------------------------------------
#*/
__all__ = [
'URSPRules',
'URSPRule',
'ANDSPInfos',
'ANDSPInfo',
'N3AN',
'WLANSPRule',
]
#------------------------------------------------------------------------------#
# 3GPP TS 24.526: User Equipment (UE) policies for 5G System (5GS)
# release 16 (g10)
#------------------------------------------------------------------------------#
from pycrate_core.utils import *
from pycrate_core.elt import *
from pycrate_core.base import *
from pycrate_ether.IP import IPProt_dict
from pycrate_ether.Ethernet import EtherType_dict
from .TS24008_IE import (
PLMN,
)
from .TS24501_IE import (
DNN, _SSCMode_dict, SNSSAI, PDUSessType, FGSTAIList,
)
#------------------------------------------------------------------------------#
# Encoding of UE policy part type URSP
# TS 24.526, section 5.2
#------------------------------------------------------------------------------#
# Table 5.2.1, Traffic descriptor component type identifier
_TrafficDescCompType_dict = {
1 : 'Match-all type',
8 : 'OS Id + OS App Id type',
16 : 'IPv4 remote address type',
17 : 'IPv4 local address type',
33 : 'IPv6 remote address/prefix length type',
35 : 'IPv6 local address/prefix length type',
48 : 'Protocol identifier/Next header type',
64 : 'Single local port type',
65 : 'Local port range type',
80 : 'Single remote port type',
81 : 'Remote port range type',
96 : 'Security parameter index type',
112 : 'Type of service/Traffic class type',
128 : 'Flow label type',
129 : 'Destination MAC address type',
130 : 'Source MAC address type',
131 : '802.1Q C-TAG VID type',
132 : '802.1Q S-TAG VID type',
133 : '802.1Q C-TAG PCP/DEI type',
134 : '802.1Q S-TAG PCP/DEI type',
135 : 'Ethertype type',
136 : 'DNN type',
144 : 'Connection capabilities type',
145 : 'Destination FQDN',
160 : 'OS App Id type'
}
_TrafficDescConCap_dict = {
1 : 'IMS',
2 : 'MMS',
4 : 'SUPL',
8 : 'Internet'
}
class _TrafficDescCompOSAppId(Envelope):
_GEN = (
Buf('OS_UUID', bl=128, rep=REPR_HEX),
Uint8('LenAppId'),
Buf('AppId')
)
def __init__(self, *args, **kwargs):
Envelope.__init__(self, *args, **kwargs)
self[1].set_valauto(lambda: self[2].get_len())
self[2].set_blauto(lambda: self[1].get_val()<<3)
class _TrafficDescCompIPv4(Envelope):
_GEN = (
Buf('Addr', bl=32, rep=REPR_HEX),
Buf('Mask', bl=32, rep=REPR_HEX)
)
class _TrafficDescCompIPv6(Envelope):
_GEN = (
Buf('Addr', bl=128, rep=REPR_HEX),
Uint8('Pref')
)
class _TrafficDescCompPortRange(Envelope):
_GEN = (
Uint16('Low'),
Uint16('High')
)
class _TrafficDescCompTrafficClass(Envelope):
_GEN = (
Uint8('Class'),
Uint8('Mask')
)
class _TrafficDescCompFlowLabel(Envelope):
_GEN = (
Uint('spare', bl=4),
Uint('Value', bl=20, rep=REPR_HEX)
)
class _TrafficDescCompVID(Envelope):
_GEN = (
Uint('spare', bl=4),
Uint('Value', bl=12)
)
class _TrafficDescCompPCPDEI(Envelope):
_GEN = (
Uint('spare', bl=4),
Uint('PCP', bl=3),
Uint('DEI', bl=1)
)
class _TrafficDescCompConCap(Envelope):
_GEN = (
Uint8('Num'),
Sequence('Caps', GEN=Uint8('Cap', dic=_TrafficDescConCap_dict))
)
def __init__(self, *args, **kwargs):
Envelope.__init__(self, *args, **kwargs)
self[0].set_valauto(lambda: self[1].get_num())
self[1].set_numauto(lambda: self[0].get_val())
class _TrafficDescCompFQDN(Envelope):
_GEN = (
Uint8('Len'),
Buf('Value', val=b'')
)
def __init__(self, *args, **kwargs):
Envelope.__init__(self, *args, **kwargs)
self[0].set_valauto(lambda: self[1].get_len())
self[1].set_blauto(lambda: self[0].get_val()<<3)
class _TrafficDescCompAppId(Envelope):
_GEN = (
Uint8('Len'),
Buf('AppId')
)
def __init__(self, *args, **kwargs):
Envelope.__init__(self, *args, **kwargs)
self[0].set_valauto(lambda: self[1].get_len())
self[1].set_blauto(lambda: self[0].get_val()<<3)
class TrafficDescComp(Envelope):
_GEN = (
Uint8('Type', dic=_TrafficDescCompType_dict),
Alt('Value', GEN={
1 : Buf('none', bl=0),
8 : _TrafficDescCompOSAppId('OSAppId'),
16 : _TrafficDescCompIPv4('IPv4'),
17 : _TrafficDescCompIPv4('IPv4'),
33 : _TrafficDescCompIPv6('IPv6Pref'),
35 : _TrafficDescCompIPv6('IPv6Pref'),
48 : Uint8('ProtId', dic=IPProt_dict),
64 : Uint16('Port'),
65 : _TrafficDescCompPortRange('PortRange'),
80 : Uint16('Port'),
81 : _TrafficDescCompPortRange('PortRange'),
96 : Uint32('SPI', rep=REPR_HEX),
112 : _TrafficDescCompTrafficClass('TrafficClass'),
128 : _TrafficDescCompFlowLabel('FlowLabel'),
129 : Buf('MACDest', bl=48, rep=REPR_HEX),
130 : Buf('MACSrc', bl=48, rep=REPR_HEX),
131 : _TrafficDescCompVID('CTagVID'),
132 : _TrafficDescCompVID('STagVID'),
133 : _TrafficDescCompPCPDEI('CTagPCPDEI'),
134 : _TrafficDescCompPCPDEI('STagPCPDEI'),
135 : Uint16('EtherType', dic=EtherType_dict),
136 : DNN(),
144 : _TrafficDescCompConCap('ConCap'),
145 : _TrafficDescCompFQDN('FQDN'),
160 : _TrafficDescCompAppId('AppId')
},
DEFAULT=Buf('unk', val=b'', rep=REPR_HEX),
sel=lambda self: self.get_env()['Type'].get_val())
)
# Table 5.2.1, SSC Mode Type
class _RouteSelectDescCompSSCMode(Envelope):
_GEN = (
Uint('spare', bl=5),
Uint('Value', bl=3, dict=_SSCMode_dict)
)
# Table 5.2.1, preferred access type type
class _RouteSelectDescCompAccessType(Envelope):
_GEN = (
Uint('spare', bl=6),
Uint('Value', bl=2, dic={1:'3GPP access', 2:'non-3GPP access'})
)
# Table 5.2.1, time window type
class _RouteSelectDescCompTimeWin(Envelope):
_GEN = (
Uint32('Second'),
Uint32('Fraction')
)
# Table 5.2.2: Location criteria
class _LocAreaEUTRACellID(Envelope):
_GEN = (
PLMN(),
Buf('EUTRACellID', bl=28, rep=REPR_HEX),
Uint('spare', bl=4, rep=REPR_HEX)
)
class _LocAreaCompEUtra(Envelope):
_GEN = (
Uint8('Num'),
Sequence('CellIDs', GEN=_LocAreaEUTRACellID('EUTRACellID'))
)
def __init__(self, *args, **kwargs):
Envelope.__init__(self, *args, **kwargs)
self[0].set_valauto(lambda: self[1].get_num())
self[1].set_numauto(lambda: self[0].get_num())
class _LocAreaEUTRACellID(Envelope):
_GEN = (
PLMN(),
Buf('NRCellID', bl=36, rep=REPR_HEX),
Uint('spare', bl=4, rep=REPR_HEX)
)
class _LocAreaCompNR(Envelope):
_GEN = (
Uint8('Num'),
Sequence('CellIDs', GEN=_LocAreaEUTRACellID('NRCellID'))
)
def __init__(self, *args, **kwargs):
Envelope.__init__(self, *args, **kwargs)
self[0].set_valauto(lambda: self[1].get_num())
self[1].set_numauto(lambda: self[0].get_num())
class _LocAreaGNID(Envelope):
_GEN = (
PLMN(),
Buf('gNBID', bl=32, rep=REPR_HEX)
)
class _LocAreaCompGNID(Envelope):
_GEN = (
Uint8('Num'),
Sequence('gNBIDs', GEN=_LocAreaGNID('gNBID'))
)
def __init__(self, *args, **kwargs):
Envelope.__init__(self, *args, **kwargs)
self[0].set_valauto(lambda: self[1].get_num())
self[1].set_numauto(lambda: self[0].get_num())
# Figure 5.2.6: Location area
_RouteSelectLocAreaType_dict = {
1 : 'E-UTRA cell identities list',
2 : 'NR cell identities list',
3 : 'Global RAN node identities list',
4 : 'TAI list'
}
class _LocAreaComp(Envelope):
_GEN = (
Uint8('Type', dic=_RouteSelectLocAreaType_dict),
Alt('Cont', GEN={
1 : _LocAreaCompEUtra('EUTRACellIDs'),
2 : _LocAreaCompNR('NRCellIDs'),
3 : _LocAreaCompGNID('gNBIDs'),
4 : FGSTAIList()
},
DEFAULT=Buf('unk', val=b'', rep=REPR_HEX),
sel=lambda self: self.get_env()['Type'].get_val())
)
# Figure 5.2.5: Location criteria
class _RouteSelectDescCompLocArea(Sequence):
_GEN = _LocAreaComp('LocAreaComp')
# Table 5.2.1, Route selection descriptor component type identifier
_RouteSelectDescCompType_dict = {
1 : 'SSC mode',
2 : 'S-NSSAI',
4 : 'DNN',
8 : 'PDU session type',
16 : 'Preferred access type',
17 : 'Multi-access preference',
128 : 'Time window',
64 : 'Location criteria',
32 : 'Non-seamless non-3GPP offload indication'
}
class RouteSelectDescComp(Envelope):
_GEN = (
Uint8('Type', dic=_RouteSelectDescCompType_dict),
Alt('Value', GEN={
1 : _RouteSelectDescCompSSCMode('SSCMode'),
2 : SNSSAI(),
4 : DNN(),
8 : PDUSessType(),
16 : _RouteSelectDescCompAccessType('AccessType'),
17 : Buf('none', bl=0),
32 : Buf('none', bl=0),
64 : _RouteSelectDescCompLocArea('LocArea'),
128 : _RouteSelectDescCompTimeWin('TimeWin')
},
DEFAULT=Buf('unk', val=b'', rep=REPR_HEX),
sel=lambda self: self.get_env()['Type'].get_val())
)
# Figure 5.2.4: Route selection descriptor
class RouteSelectDesc(Envelope):
_GEN = (
Uint16('Len'),
Uint8('Precedence'),
Uint16('LenCont'),
Sequence('Cont', GEN=RouteSelectDescComp())
)
def __init__(self, *args, **kwargs):
Envelope.__init__(self, *args, **kwargs)
self[0].set_valauto(lambda: 3 + self[3].get_len())
self[2].set_valauto(lambda: self[3].get_len())
self[3].set_blauto(lambda: self[2].get_val())
# Figure 5.2.2: URSP rule
class URSPRule(Envelope):
_GEN = (
Uint16('Len'),
Uint8('Precedence'),
Uint16('LenTrafficDesc'),
Sequence('TrafficDesc', GEN=TrafficDescComp()),
Uint16('LenRouteSelectDescList'),
Sequence('RouteSelectDescList', GEN=RouteSelectDesc())
)
def __init__(self, *args, **kwargs):
Envelope.__init__(self, *args, **kwargs)
self[0].set_valauto(lambda: 5 + self[3].get_len() + self[5].get_len())
self[2].set_valauto(lambda: self[3].get_len())
self[3].set_blauto(lambda: self[2].get_val())
self[4].set_valauto(lambda: self[5].get_len())
self[5].set_blauto(lambda: self[4].get_val())
# Figure 5.2.1: UE policy part contents including one or more URSP rules
class URSPRules(Sequence):
_GEN = URSPRule()
#------------------------------------------------------------------------------#
# Encoding of UE policy part type ANDSP
# TS 24.526, section 5.3
#------------------------------------------------------------------------------#
# Figure 5.3.2.4g: Selection criteria sub entry {selection criteria set type = minimum backhaul threshold}
class _WLANSelectionCriteriaMinBack(Envelope):
_GEN = (
Uint('spare', bl=5, rep=REPR_HEX),
Uint('ULBInd', bl=1),
Uint('DLBInd', bl=1),
Uint('NetworkType', bl=2, dic={0:'home', 1:'roaming'}),
Uint32('DLBW'),
Uint32('ULBW')
)
def __init__(self, *args, **kwargs):
Envelope.__init__(self, *args, **kwargs)
self['DLBW'].set_transauto(lambda: self['DLBInd'].get_val() == 0)
self['ULBW'].set_transauto(lambda: self['ULBInd'].get_val() == 0)
# Figure 5.3.2.4f: Selection criteria sub entry {selection criteria set type = SP exclusion list}
class _WLANSelectionCriteriaSPExcl(Envelope):
_GEN = (
Uint8('Len'),
Buf('SSID')
)
def __init__(self, *args, **kwargs):
Envelope.__init__(self, *args, **kwargs)
self[0].set_valauto(lambda: self[1].get_val())
self[1].set_blauto(lambda: self[0].get_val()<<3)
# Figure 5.3.2.4e: Selection criteria sub entry {selection criteria set type = required protocol port tuple}
class _WLANSelectionCriteriaPortTuple(Envelope):
_GEN = (
Uint8('Len'),
Uint8('PortId', dic=IPProt_dict),
Uint8('LenPort'),
Buf('Port', val=b'\0\1', rep=REPR_HEX), # see WiFi Alliance HotSpot 2.0
)
def __init__(self, *args, **kwargs):
Envelope.__init__(self, *args, **kwargs)
self[0].set_valauto(lambda: 2 + self[3].get_len())
self[2].set_valauto(lambda: self[3].get_len())
self[3].set_blauto(lambda: self[2].get_val()<<3)
# Figure 5.3.2.4d: Selection criteria sub entry {selection criteria set type = preferred roaming partner list}
class _WLANSelectionCriteriaPrefRoam(Envelope):
_GEN = (
Uint8('Len'),
Uint8('Priority'),
Uint8('LenFQDN'),
Buf('FQDNMatch', rep=REPR_HEX), # see WiFi Alliance HotSpot 2.0
Uint8('LenCountry'),
Buf('Country', rep=REPR_HEX), # see WiFi Alliance HotSpot 2.0
)
def __init__(self, *args, **kwargs):
Envelope.__init__(self, *args, **kwargs)
self[0].set_valauto(lambda: 3 + self['LenFQDN'].get_val() + self['LenCountry'].get_val())
self[2].set_valauto(lambda: self[3].get_len())
self[3].set_blauto(lambda: self[2].get_val()<<3)
self[4].set_valauto(lambda: self[5].get_len())
self[5].set_blauto(lambda: self[4].get_val()<<3)
# Figure 5.3.2.4c: Selection criteria sub entry {selection criteria set type = preferred SSID list}
class _WLANSelectionCriteriaPrefSSID(Envelope):
_GEN = (
Uint8('Len'),
Uint8('WLANPriority'),
Uint('spare', bl=6),
Uint('HESSIDInd', bl=1),
Uint('SSIDInd', bl=1),
Envelope('SSID', GEN=(
Uint8('Len'),
Buf('Value', val=b'', rep=REPR_HEX))
),
Buf('HESSID', bl=48, rep=REPR_HEX) # MAC addr
)
def __init__(self, *args, **kwargs):
Envelope.__init__(self, *args, **kwargs)
self[0].set_valauto(lambda: 2 + self[5].get_len() + self[6].get_len())
self['SSID'].set_transauto(lambda: self['SSIDInd'].get_val() == 0)
self['HESSID'].set_transauto(lambda: self['HESSIDInd'].get_val() == 0)
# SSID internal automation
self['SSID'][0].set_valauto(lambda: self['SSID'][1].get_len())
self['SSID'][1].set_blauto(lambda: self['SSID'][0].get_val()<<3)
# Figure 5.3.2.4b
_WLANSelCritType_dict = {
1 : 'preferred SSID list',
2 : 'preferred roaming partner list',
3 : 'required protocol port tuple',
4 : 'SP exclusion list',
5 : 'minimum backhaul threshold'
}
class _WLANSelectionCriteriaSet(Envelope):
_GEN = (
Uint16('Len'),
Uint('Type', bl=4, dic=_WLANSelCritType_dict),
Uint('Num', bl=4),
Sequence('SubEntries', GEN=Alt('CriteriaSubEntry', GEN={
1 : _WLANSelectionCriteriaPrefSSID('PrefSSID'),
2 : _WLANSelectionCriteriaPrefRoam('PrefRoaming'),
3 : _WLANSelectionCriteriaPortTuple('RequiredProtocolPort'),
4 : _WLANSelectionCriteriaSPExcl('SPExcl'),
5 : _WLANSelectionCriteriaMinBack('MinBackhaulThres')},
DEFAULT=Buf('unk', val=b'', rep=REPR_HEX),
sel=lambda self: self.get_env().get_env()['Type'].get_val()))
)
def __init__(self, *args, **kwargs):
Envelope.__init__(self, *args, **kwargs)
self[0].set_valauto(lambda: 1 + self[3].get_len())
self[2].set_valauto(lambda: self[3].get_num())
self[3].set_numauto(lambda: self[2].get_val())
self[3].set_blauto(lambda: (self[0].get_val()-1)<<3)
# Table 5.3.2.1: WLANSP information element, Home network ind
_HomeNetworkInd_dict = {
0 : 'all WLANs could match this selection criteria entry',
1 : 'only the WLANs that are operated by the home operator could match this selection criteria entry'
}
# Figure 5.3.2.4a
class _WLANSelectionCriteriaEntry(Envelope):
_GEN = (
Uint16('Len'),
Uint('spare', bl=1),
Uint('MaxBSSLoadInd', bl=1),
Uint('HomeNetworkInd', bl=1, dic=_HomeNetworkInd_dict),
Uint('CriteriaPriority', bl=5),
Uint16('MaxBSSLoad'),
Sequence('CriteriaSets', GEN=_WLANSelectionCriteriaSet('CriteriaSet'))
)
def __init__(self, *args, **kwargs):
Envelope.__init__(self, *args, **kwargs)
self[0].set_valauto(lambda: 3 + self[6].get_len() if self[2].get_val() == 1 else 1 + self[6].get_len())
self[5].set_transauto(lambda: self[2].get_val() == 0)
self[6].set_blauto(lambda: ((self[0].get_val()-3)<<3) if self[2].get_val() == 1 else ((self[0].get_val()-1)<<3))
# Figure 5.3.2.4
class _WLANSelectionCriteria(Envelope):
_GEN = (
Uint16('Len'),
Uint8('Num'),
Sequence('Entries', GEN=_WLANSelectionCriteriaEntry('CriteriaEntry'))
)
def __init__(self, *args, **kwargs):
Envelope.__init__(self, *args, **kwargs)
self[0].set_valauto(lambda: 1 + self[2].get_len())
self[1].set_valauto(lambda: self[2].get_num())
self[2].set_numauto(lambda: self[1].get_val())
# Figure 5.3.2.11c: Location field {entry type= WLAN location}
_LocFieldType_dict = {
1 : 'TAC',
2 : 'EUTRA CellID',
4 : 'NR CellID',
129 : 'HESSID',
130 : 'SSID',
132 : 'BSSID'
}
class _LocFieldWLAN(Envelope):
_GEN = (
Uint8('Len'),
Uint8('Type', dic=_LocFieldType_dict),
Alt('Cont', GEN={
129 : Buf('HESSID', bl=48, rep=REPR_HEX),
130 : Buf('SSID', rep=REPR_HEX),
132 : Buf('BSSID', bl=48, rep=REPR_HEX),
},
DEFAULT=Buf('unk', val=b'', rep=REPR_HEX),
sel=lambda self: self.get_env()['Type'].get_val()
)
)
def __init__(self, *args, **kwargs):
Envelope.__init__(self, *args, **kwargs)
self[0].set_valauto(lambda: 1 + self[2].get_len())
self[2].set_blauto(lambda: self[0].get_val() - 1)
# Figure 5.3.2.11b: Location field {entry type= 3GPP location}
class _LocField3GPP(Envelope):
_GEN = (
Uint8('Len'),
Uint8('Type', dic=_LocFieldType_dict),
Alt('Cont', GEN={
#1 : Buf('TAC'), # WNG: a TAC is not 8 bits (but 16 in 4G and 24 in 5G) !
#2 : Uint16('EUTRACellID'), # WNG: a LTE CellID is not 16 bits (but 28) !
#4 : Uint24('NRCellID'), # WNG: a NR CellID is not 24 bits (but 36) !
},
DEFAULT=Buf('unk', val=b'', rep=REPR_HEX),
sel=lambda self: self.get_env()['Type'].get_val()
)
)
def __init__(self, *args, **kwargs):
Envelope.__init__(self, *args, **kwargs)
self[0].set_valauto(lambda: 1 + self[2].get_len())
self[2].set_blauto(lambda: self[0].get_val() - 1)
# Figure 5.3.2.11a: Location field {entry type= Geo location}
class _LocFieldGeo(Envelope):
_GEN = (
Uint32('Lat'),
Uint32('Long'),
Uint16('Radius')
)
# Figure 5.3.2.10a: Location sub entry {entry type= WLAN location or Geo location}
class _LocSubentryGeo(Envelope):
_GEN = (
Uint16('Len'),
Uint8('Num'),
Sequence('Fields', GEN=_LocFieldGeo('LocGeo'))
)
def __init__(self, *args, **kwargs):
Envelope.__init__(self, *args, **kwargs)
self[0].set_valauto(lambda: 1 + self[2].get_len())
self[1].set_valauto(lambda: self[2].get_num())
self[2].set_numauto(lambda: self[1].get_val())
# Figure 5.3.2.10a: Location sub entry {entry type= WLAN location or Geo location}
class _LocSubentryWLAN(Envelope):
_GEN = (
Uint16('Len'),
Uint8('Num'),
Sequence('Fields', GEN=_LocFieldWLAN('LocWLAN'))
)
def __init__(self, *args, **kwargs):
Envelope.__init__(self, *args, **kwargs)
self[0].set_valauto(lambda: 1 + self[2].get_len())
self[1].set_valauto(lambda: self[2].get_num())
self[2].set_numauto(lambda: self[1].get_val())
# Figure 5.3.2.10: Location sub entry {entry type= 3GPP location}
class _LocSubentry3GPP(Envelope):
_GEN = (
Uint16('Len'),
PLMN(),
Uint8('Num'), # optional
Sequence('Fields', GEN=_LocField3GPP('Loc3GPP'))
)
def __init__(self, *args, **kwargs):
Envelope.__init__(self, *args, **kwargs)
self[0].set_valauto(lambda: 4 + self[3].get_len())
self[2].set_valauto(lambda: self[3].get_num())
self[3].set_numauto(lambda: self[2].get_val())
# Figure 5.3.2.6: Location entry
class LocationEntry(Envelope):
_GEN = (
Uint16('Len'),
Uint('Type', bl=2, dic={1:'3GPP', 2:'WLAN', 3:'Geo'}),
Uint('Num', bl=6),
Sequence('SubEntries', GEN=Alt('LocationSubEntry', GEN={
# TODO: verify Type values
1 : _LocSubentry3GPP('SubEntry3GPP'),
2 : _LocSubentryWLAN('SubEntryWLAN'),
3 : _LocSubentryGeo('SubEntryGeo')
},
DEFAULT=Buf('unk', val=b'', rep=REPR_HEX),
sel=lambda self: self.get_env().get_env()['Type'].get_val()))
)
def __init__(self, *args, **kwargs):
Envelope.__init__(self, *args, **kwargs)
self[0].set_valauto(lambda: 1 + self[3].get_len())
self[2].set_valauto(lambda: self[3].get_num())
self[3].set_numauto(lambda: self[2].get_val())
self[3].set_blauto(lambda: (self[0].get_val()-1)<<3)
# Figure 5.3.2.5: Validity area
class _WLANValidityArea(Envelope):
_GEN = (
Uint16('Len'),
Uint8('Num'),
Sequence('Entries', GEN=LocationEntry())
)
def __init__(self, *args, **kwargs):
Envelope.__init__(self, *args, **kwargs)
self[0].set_valauto(lambda: 1 + self[2].get_len())
self[1].set_valauto(lambda: self[2].get_num())
self[2].set_numauto(lambda: self[1].get_val())
# Figure 5.3.2.20: ToD sub field {field type = "day of the week"}
class _TimeOfDayDay(Envelope):
_GEN = (
Uint('spare', val=1, bl=1),
Uint('Mon', bl=1),
Uint('Tue', bl=1),
Uint('Wed', bl=1),
Uint('Thu', bl=1),
Uint('Fri', bl=1),
Uint('Sat', bl=1),
Uint('Sun', bl=1)
)
# Figure 5.3.2.17: ToD sub field
_TimeOfDayFieldType_dict = {
1 : 'time start',
2 : 'time stop',
4 : 'date start',
8 : 'date stop',
16 : 'day of the week'
}
class _TimeOfDayField(Envelope):
_GEN = (
Uint8('Len'),
Uint8('Type', dic=_TimeOfDayFieldType_dict),
Alt('Cont', GEN={
1 : Buf('TimeStart'),
2 : Buf('TimeStop'),
4 : Buf('DateStart'),
8 : Buf('DateStop'),
16 : _TimeOfDayDay('DayOfWeek')
},
DEFAULT=Buf('unk', val=b'', rep=REPR_HEX),
sel=lambda self: self.get_env().get_env()['Type'].get_val())
)
# Figure 5.3.2.16: Time of day sub field
class _TimeOfDayEntry(Envelope):
_GEN = (
Uint16('Len'),
Uint8('Num'),
Sequence('Fields', GEN=_TimeOfDayField('TimeOfDayField'))
)
def __init__(self, *args, **kwargs):
Envelope.__init__(self, *args, **kwargs)
self[0].set_valauto(lambda: 1 + self[2].get_len())
self[1].set_valauto(lambda: self[2].get_num())
self[2].set_numauto(lambda: self[1].get_val())
# Figure 5.3.2.15: Time of day
class _WLANTimeOfDay(Envelope):
_GEN = (
Uint16('Len'),
Uint8('Num'),
Sequence('Entries', GEN=_TimeOfDayEntry('TimeOfDayEntry'))
)
def __init__(self, *args, **kwargs):
Envelope.__init__(self, *args, **kwargs)
self[0].set_valauto(lambda: 1 + self[2].get_len())
self[1].set_valauto(lambda: self[2].get_num())
self[2].set_numauto(lambda: self[1].get_val())
# Figure 5.3.2.3
class WLANSPRule(Envelope):
_GEN = (
Uint16('Len'),
Uint8('Id'),
Uint8('Priority'),
Uint('Roaming', bl=1, dic={0:'rule only valid when UE is not roaming', 1:'rule only valid when UE is roaming'}),
Uint('ValidityAreaInd', bl=1),
Uint('3GPPLocInd', bl=1),
Uint('WLANLocInd', bl=1),
Uint('GeoLocInd', bl=1),
Uint('TimeOfDayInd', bl=1),
Uint('spare', bl=2),
_WLANSelectionCriteria('SelectionCriteria'),
_WLANValidityArea('ValidityArea'), # optional
_WLANTimeOfDay('TimeOfDay') # optional
)
def __init__(self, *args, **kwargs):
Envelope.__init__(self, *args, **kwargs)
self[0].set_valauto(lambda: 3 + self['SelectionCriteria'].get_len() + \
self['ValidityArea'].get_len() + self['TimeOfDay'].get_len())
#self['ValidityArea'].set_transauto(lambda: self['ValidityAreaInd'].get_val() == 0)
self['ValidityArea'].set_transauto(lambda: self['GeoLocInd'].get_val() == 0)
self['TimeOfDay'].set_transauto(lambda: self['TimeOfDayInd'].get_val() == 0)
# Figure 5.3.3.2.2: N3AN node selection information entry
_N3ANNodeSelFQDNFmt_dict = {
0 : 'Operator identifier based ePDG FQDN format or operator identifier based N3IWF FQDN',
1 : 'Tracking/location area identity based ePDG FQDN format or tracking area identity based N3IWF FQDN format'
}
class _N3ANNodeSelEntry(Envelope):
_GEN = (
Uint8('Len', val=4),
PLMN(),
Uint('FQDNFormat', bl=2, dic=_N3ANNodeSelFQDNFmt_dict),
Uint('Preference', bl=1, dic={0:'N3IWF is preferred', 1:'ePDG is preferred'}),
Uint('Priority', bl=5)
)
# Figure 5.3.3.2.1: Content of N3AN node selection information
class _N3ANNodeSelInfo(Envelope):
_GEN = (
Uint16('Len'),
Sequence('Entries', GEN=_N3ANNodeSelEntry('N3ANNodeSelEntry'))
)
def __init__(self, *args, **kwargs):
Envelope.__init__(self, *args, **kwargs)
self[0].set_valauto(lambda: self[1].get_len())
self[1].set_blauto(lambda: self[0].get_val()<<3)
# Table 5.3.3.3.1: Home N3IWF identifier entry (type = IP address type)
# Table 5.3.3.3.2: Home N3IWF identifier entry (type = FQDN)
class _HomeN3IWFIdentEntry(Envelope):
_GEN = (
Uint8('Type', val=1, dic={1:'IPv4', 2:'IPv6', 3:'IPv4v6', 4:'FQDN'}),
Alt('', GEN={
1 : Buf('IPv4', bl=32, rep=REPR_HEX),
2 : Buf('IPv6', bl=128, rep=REPR_HEX),
3 : Envelope('IPv4v6', GEN=(
Buf('IPv4', bl=32, rep=REPR_HEX),
Buf('IPv6', bl=128, rep=REPR_HEX))
),
4 : _TrafficDescCompFQDN('FQDN')
},
DEFAULT=Buf('unk', val=b'', rep=REPR_HEX),
sel=lambda self: self.get_env()['Type'].get_val())
)
# Figure 5.3.3.3.1: Content of home N3IWF identifier configuration
class _HomeN3IWFIdentConfig(Envelope):
_GEN = (
Uint8('Type', val=1),
Uint16('Len'),
Sequence('Entries', GEN=_HomeN3IWFIdentEntry('HomeN3IWFIdentEntry'))
)
def __init__(self, *args, **kwargs):
Envelope.__init__(self, *args, **kwargs)
self[1].set_valauto(lambda: self[2].get_len())
self[2].set_blauto(lambda: self[1].get_val()<<3)
# Figure 5.3.3.4.1: Content of home ePDG identifier configuration
class _HomeEPDGIdentConfig(Envelope):
_GEN = (
Uint8('Type', val=2),
Uint16('Len'),
Sequence('Entries', GEN=_HomeN3IWFIdentEntry('HomeEPDGIdentEntry'))
)
# Figure 5.3.3.1.1: ANDSP info containing N3AN node configuration information
class N3AN(Envelope):
_GEN = (
_N3ANNodeSelInfo('N3ANNodeSelInfo'),
_HomeN3IWFIdentConfig('HomeN3IWFIdentConfig'),
_HomeEPDGIdentConfig('HomeEPDGIdentConfig')
)
# Figure 5.3.2.1
_ANDSPInfoType_dict = {
0 : 'Reserved',
1 : 'WLANSP',
2 : 'N3AN node configuration information'
}
# Figure 5.3.1.3: ANDSP Info
class ANDSPInfo(Envelope):
_GEN = (
Uint('spare', bl=4, rep=REPR_HEX),
Uint('Type', bl=4, dic=_ANDSPInfoType_dict),
Uint16('Len'),
Alt('Cont', GEN={
1: Sequence('WLANSPRules', GEN=WLANSPRule()),
2: N3AN()
},
DEFAULT=Buf('unk', val=b'', rep=REPR_HEX),
sel=lambda self: self.get_env()['Type'].get_val())
)
def __init__(self, *args, **kwargs):
Envelope.__init__(self, *args, **kwargs)
self[2].set_valauto(lambda: self[3].get_len())
self[3].set_blauto(lambda: self[2].get_val()<<3)
# Figure 5.3.1.2: ANDSP contents
class ANDSPInfos(Sequence):
_GEN = ANDSPInfo()