305 lines
10 KiB
Python
305 lines
10 KiB
Python
# -*- coding: UTF-8 -*-
|
|
#/**
|
|
# * Software Name : pycrate
|
|
# * Version : 0.4
|
|
# *
|
|
# * Copyright 2022. Vadim Yanitskiy
|
|
# *
|
|
# * 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_osmo/RRCTL.py
|
|
# * Created : 2022-02-01
|
|
# * Authors : Vadim Yanitskiy
|
|
# *--------------------------------------------------------
|
|
#*/
|
|
|
|
import enum
|
|
|
|
from pycrate_core.utils import *
|
|
from pycrate_core.elt import *
|
|
from pycrate_core.base import *
|
|
from pycrate_core.repr import *
|
|
|
|
from pycrate_mobile.TS24008_IE import BufBCD
|
|
|
|
#------------------------------------------------------------------------------#
|
|
# Enumerations
|
|
#------------------------------------------------------------------------------#
|
|
|
|
class RRCTLMsgType(enum.IntEnum):
|
|
''' RRCTL message type '''
|
|
Reset = 0x00
|
|
ConnData = 0x01
|
|
NetworkSearch = 0x02
|
|
NetworkSelect = 0x03
|
|
ConnEstabish = 0x04
|
|
ConnRelease = 0x05
|
|
Paging = 0x06
|
|
Param = 0x07
|
|
SecMode = 0x08
|
|
# RRCTL protocol extensions (0b11xxxx) follow
|
|
ExtUSIM = 0x3e
|
|
RFU = 0x3f # 0b111111
|
|
|
|
RRCTLMsgType_dict = { e.value : e.name for e in RRCTLMsgType }
|
|
|
|
class RRCTLMsgDisc(enum.IntEnum):
|
|
''' RRCTL message type discriminator '''
|
|
Req = 0x00
|
|
Ind = 0x01
|
|
Cnf = 0x02 # a.k.a Res
|
|
Res = 0x02 # a.k.a Cnf
|
|
Err = 0x03
|
|
|
|
RRCTLMsgDisc_dict = { e.value : e.name for e in RRCTLMsgDisc }
|
|
|
|
class RRCTLConnEstCause(enum.IntEnum):
|
|
''' RRCTL connection establishment cause '''
|
|
Emergency = 0x00
|
|
HighPriorityAccess = 0x01
|
|
MT_Access = 0x02
|
|
MO_Signalling = 0x03
|
|
MO_Data = 0x04
|
|
DelayTolerantAccess_v1020 = 0x05
|
|
MO_VoiceCall_v1280 = 0x06
|
|
|
|
RRCTLConnEstCause_dict = { e.value : e.name for e in RRCTLConnEstCause }
|
|
|
|
class RRCTLParamType(enum.IntEnum):
|
|
''' RRCTL parameter type for RRCTLMsgType.Param '''
|
|
UEID = 0x00
|
|
|
|
RRCTLParamType_dict = { e.value : e.name for e in RRCTLParamType }
|
|
|
|
#------------------------------------------------------------------------------#
|
|
# RRCTL message payload
|
|
#------------------------------------------------------------------------------#
|
|
|
|
class PLMNInfo(Envelope):
|
|
_GEN = (
|
|
BufBCD('MCC', bl=16),
|
|
BufBCD('MNC', bl=16),
|
|
Uint16('TAC'),
|
|
)
|
|
|
|
class PLMNSearchRes(Envelope):
|
|
_GEN = (
|
|
Uint8('NofPLMNs'),
|
|
Array('PLMNs', GEN=PLMNInfo()),
|
|
)
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
Envelope.__init__(self, *args, **kwargs)
|
|
self['NofPLMNs'].set_valauto(lambda: self['PLMNs'].get_num())
|
|
self['PLMNs'].set_numauto(lambda: self['NofPLMNs'].get_val())
|
|
|
|
class PLMNSelectReq(Envelope):
|
|
_GEN = (
|
|
BufBCD('MCC', bl=16),
|
|
BufBCD('MNC', bl=16),
|
|
)
|
|
|
|
class ConnEstablishReq(Envelope):
|
|
_GEN = (
|
|
Uint8('Cause', dic=RRCTLConnEstCause_dict),
|
|
Buf('PDU'),
|
|
)
|
|
|
|
class ConnDataReqInd(Envelope):
|
|
_GEN = (
|
|
Uint32('LCID'),
|
|
Buf('PDU'),
|
|
)
|
|
|
|
class MMESubscrId(Envelope):
|
|
_GEN = (
|
|
Uint8('MMEC'),
|
|
Uint32('M_TMSI'),
|
|
)
|
|
|
|
class PagingInd(MMESubscrId):
|
|
pass
|
|
|
|
class ParamReq(Envelope):
|
|
_GEN = (
|
|
Uint8('Type', dic=RRCTLParamType_dict),
|
|
Uint8('Len'),
|
|
Alt('Data', hier=1, GEN={
|
|
RRCTLParamType.UEID : MMESubscrId()
|
|
},
|
|
sel=lambda self: self.get_env()['Type'].get_val())
|
|
)
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
Envelope.__init__(self, *args, **kwargs)
|
|
self['Len'].set_valauto(lambda: self['Data'].get_len())
|
|
|
|
class SecModeReq(Envelope):
|
|
_GEN = (
|
|
Uint('EEA', bl=3),
|
|
Uint('EIA', bl=3),
|
|
Uint('ResetTxCTR', bl=1),
|
|
Uint('ResetRxCTR', bl=1),
|
|
Buf('Spare', bl=24),
|
|
Buf('KASME', bl=32 * 8), # optional
|
|
)
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
Envelope.__init__(self, *args, **kwargs)
|
|
# KASME is absent when neither encryption nor integrity protection is active
|
|
self['KASME'].set_transauto(lambda: not self['EEA']() and not self['EIA']())
|
|
|
|
#------------------------------------------------------------------------------#
|
|
# RRCTL protocol extensions
|
|
#------------------------------------------------------------------------------#
|
|
|
|
class L16V(Envelope):
|
|
_GEN = (
|
|
Uint16('L'),
|
|
Buf('V'),
|
|
)
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
Envelope.__init__(self, *args, **kwargs)
|
|
self['L'].set_valauto(lambda: self['V'].get_bl() >> 3)
|
|
self['V'].set_blauto(lambda: self['L'].get_val() << 3)
|
|
|
|
class ExtUSIM:
|
|
''' RRCTL protocol extension for (U)SIM specific sommands '''
|
|
class MsgType(enum.IntEnum):
|
|
RawAPDU = 0x00
|
|
ReadFile = 0x01
|
|
UpdateFile = 0x02
|
|
GenAuthVector = 0x03
|
|
Reserved = 0xff
|
|
|
|
MsgType_dict = { e.value : e.name for e in MsgType }
|
|
|
|
class RawAPDU(L16V):
|
|
pass
|
|
|
|
class ReadFileReq(Envelope):
|
|
_GEN = (
|
|
Uint16('DF'), # Dedicated File
|
|
Uint16('EF'), # Elementary File
|
|
)
|
|
|
|
class ReadFileRes(L16V):
|
|
pass
|
|
|
|
class UpdateFileReq(Envelope):
|
|
_GEN = (
|
|
Uint16('DF'), # Dedicated File
|
|
Uint16('EF'), # Elementary File
|
|
L16V('Data'),
|
|
)
|
|
|
|
class GenAuthVectorReq(Envelope):
|
|
_GEN = (
|
|
Buf('Rand', bl=16 * 8),
|
|
Buf('Autn', bl=16 * 8),
|
|
BufBCD('MCC', bl=16),
|
|
BufBCD('MNC', bl=16),
|
|
)
|
|
|
|
class GenAuthVectorRes(Envelope):
|
|
_GEN = (
|
|
Uint8('OutOfSync'),
|
|
Uint8('KASMELen'),
|
|
Buf('Spare', bl=16),
|
|
Buf('KASME'),
|
|
)
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
Envelope.__init__(self, *args, **kwargs)
|
|
self['KASMELen'].set_valauto(lambda: self['KASME'].get_bl() >> 3)
|
|
self['KASME'].set_blauto(lambda: self['KASMELen'].get_val() << 3)
|
|
|
|
class ExtUSIMMsgReq(Envelope):
|
|
_GEN = (
|
|
Uint8('Type', dic=ExtUSIM.MsgType_dict),
|
|
Buf('Spare', bl=24),
|
|
Alt('Data', hier=1, GEN={
|
|
ExtUSIM.MsgType.RawAPDU : ExtUSIM.RawAPDU(),
|
|
ExtUSIM.MsgType.ReadFile : ExtUSIM.ReadFileReq(),
|
|
ExtUSIM.MsgType.UpdateFile : ExtUSIM.UpdateFileReq(),
|
|
ExtUSIM.MsgType.GenAuthVector : ExtUSIM.GenAuthVectorReq(),
|
|
},
|
|
sel=lambda self: self.get_env()['Type'].get_val())
|
|
)
|
|
|
|
class ExtUSIMMsgRes(Envelope):
|
|
_GEN = (
|
|
Uint8('Type', dic=ExtUSIM.MsgType_dict),
|
|
Buf('Spare', bl=24),
|
|
Alt('Data', hier=1, GEN={
|
|
ExtUSIM.MsgType.RawAPDU : ExtUSIM.RawAPDU(),
|
|
ExtUSIM.MsgType.ReadFile : ExtUSIM.ReadFileRes(),
|
|
ExtUSIM.MsgType.GenAuthVector : ExtUSIM.GenAuthVectorRes(),
|
|
},
|
|
sel=lambda self: self.get_env()['Type'].get_val())
|
|
)
|
|
|
|
#------------------------------------------------------------------------------#
|
|
# RRCTL message definition
|
|
#------------------------------------------------------------------------------#
|
|
|
|
class RRCTLMsgHdr(Envelope):
|
|
''' RRCTL message header '''
|
|
_GEN = (
|
|
Uint('Type', bl=6, dic=RRCTLMsgType_dict),
|
|
Uint('Disc', bl=2, dic=RRCTLMsgDisc_dict),
|
|
Uint('Spare', bl=8), # RFU
|
|
Uint16('Len'),
|
|
)
|
|
|
|
class RRCTLMsg(Envelope):
|
|
_GEN = (
|
|
RRCTLMsgHdr('Hdr'),
|
|
Alt('Data', hier=1, GEN={
|
|
(RRCTLMsgType.NetworkSearch, RRCTLMsgDisc.Res) : PLMNSearchRes(),
|
|
(RRCTLMsgType.NetworkSelect, RRCTLMsgDisc.Req) : PLMNSelectReq(),
|
|
(RRCTLMsgType.ConnEstabish, RRCTLMsgDisc.Req) : ConnEstablishReq(),
|
|
(RRCTLMsgType.ConnData, RRCTLMsgDisc.Req) : ConnDataReqInd(),
|
|
(RRCTLMsgType.ConnData, RRCTLMsgDisc.Ind) : ConnDataReqInd(),
|
|
(RRCTLMsgType.Paging, RRCTLMsgDisc.Ind) : PagingInd(),
|
|
(RRCTLMsgType.Param, RRCTLMsgDisc.Req) : ParamReq(),
|
|
(RRCTLMsgType.SecMode, RRCTLMsgDisc.Req) : SecModeReq(),
|
|
# RRCTL protocol extensions follow
|
|
(RRCTLMsgType.ExtUSIM, RRCTLMsgDisc.Req) : ExtUSIMMsgReq(),
|
|
(RRCTLMsgType.ExtUSIM, RRCTLMsgDisc.Res) : ExtUSIMMsgRes(),
|
|
},
|
|
sel=lambda self: (self.get_env()['Hdr']['Type'].get_val(),
|
|
self.get_env()['Hdr']['Disc'].get_val()))
|
|
)
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
Envelope.__init__(self, *args, **kwargs)
|
|
self['Hdr']['Len'].set_valauto(lambda: self['Data'].get_len())
|
|
self['Data'].set_transauto(lambda: not self['Hdr']['Len'].get_val())
|
|
|
|
def set_type(self, msg_type, msg_disc=RRCTLMsgDisc.Req):
|
|
self['Hdr']['Type'].set_val(msg_type)
|
|
self['Hdr']['Disc'].set_val(msg_disc)
|
|
|
|
def match(self, msg_type, msg_disc):
|
|
if self['Hdr']['Type'].get_val() != msg_type:
|
|
return False
|
|
if self['Hdr']['Disc'].get_val() != msg_disc:
|
|
return False
|
|
return True
|