pycrate/pycrate_osmo/RRCTL.py

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