945 lines
30 KiB
Python
945 lines
30 KiB
Python
# -*- 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()
|
||
|