pycrate/tools/pycrate_map_op_info.py

250 lines
9.0 KiB
Python
Executable File

#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
#/**
# * Software Name : pycrate
# * Version : 0.4
# *
# * Copyright 2018. Benoit Michau. P1sec
# *
# * This program is free software: you can redistribute it and/or modify
# * it under the terms of the GNU General Public License version 2 as published
# * by the Free Software Foundation.
# *
# * This program 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 General Public License for more details.
# *
# * You will find a copy of the terms and conditions of the GNU General Public
# * License version 2 in the "license.txt" file or
# * see http://www.gnu.org/licenses/ or write to the Free Software Foundation,
# * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
# *
# *--------------------------------------------------------
# * File Name : tools/pycrate_map_op_info.py
# * Created : 2018-12-13
# * Authors : Benoit Michau
# *--------------------------------------------------------
#*/
import sys
import argparse
import pprint
pp = pprint.PrettyPrinter(indent=2)
from pycrate_asn1rt.asnobj import ASN1Obj
ASN1Obj._SILENT = True
#
from pycrate_asn1dir.TCAP_MAPv2v3 import *
from pycrate_mobile.TS29002_MAPAppCtx import *
def load_cap_mod():
from pycrate_asn1dir.TCAP_CAP import GLOBAL
# this does not work perfectly, because get_construct_info() is not recursive
# but call get_proto() for SEQUENCE / SET inner components
PRINT_PROTO_EXTCONTAINER = False
SPACE_MARGIN = ' '
SPACE_CONSTRUCT = ' '
TYPE_CONSTRUCT = {
TYPE_SEQ,
TYPE_SEQ_OF,
TYPE_SET,
TYPE_SET_OF,
TYPE_CHOICE,
TYPE_ENUM
}
def get_error_info(err, info, wext=True):
info.append(' errorCode: (local, %.2i)' % err['errorCode'][1])
if 'ParameterType' in err:
par = err['ParameterType']
try:
info.append(' ParameterType: %s (%s)' % (par._typeref.called[1], par.TYPE))
except Exception:
info.append(' ParameterType: %s (%s)' % (par._name, par.TYPE))
get_construct_info(par, info, wext=wext, space=SPACE_CONSTRUCT)
info.append('')
def get_construct_info(obj, info, wext=True, space=SPACE_CONSTRUCT):
if PRINT_PROTO_EXTCONTAINER:
bl = set()
else:
bl = set(('extensionContainer', ))
#
if obj.TYPE in (TYPE_SEQ, TYPE_SET):
for c in obj._cont.values():
info.append(SPACE_MARGIN + '- %s (%s)' % (c._name, c.TYPE))
if wext and c.TYPE in TYPE_CONSTRUCT and \
(c._name != 'extensionContainer' or PRINT_PROTO_EXTCONTAINER):
info.append( SPACE_MARGIN + space + pp.pformat(
c.get_proto(w_open=wext, w_opt=wext, w_enum=wext, blacklist=bl)[1]
).replace('\n', '\n' + SPACE_MARGIN + space) )
info.append(space + 'mandatory : %s' % ', '.join(obj._root_mand))
#
elif obj.TYPE in (TYPE_SEQ_OF, TYPE_SET_OF):
c = obj._cont
info.append(SPACE_MARGIN + '- %s (%s)' % (c._typeref.called[1], c.TYPE))
if wext and c.TYPE in TYPE_CONSTRUCT:
info.append( SPACE_MARGIN + space + pp.pformat(
c.get_proto(w_open=wext, w_opt=wext, w_enum=wext, blacklist=bl)[1]
).replace('\n', '\n' + SPACE_MARGIN + space) )
#
elif obj.TYPE == TYPE_CHOICE:
for c in obj._cont.values():
info.append(SPACE_MARGIN + '- %s (%s)' % (c._name, c.TYPE))
if wext and c.TYPE in TYPE_CONSTRUCT:
info.append( SPACE_MARGIN + space + pp.pformat(
c.get_proto(w_open=wext, w_opt=wext, w_enum=wext, blacklist=bl)[1]
).replace('\n', '\n' + SPACE_MARGIN + space) )
#
elif obj.TYPE == TYPE_ENUM and wext:
cont = obj._root[:]
if obj._ext is not None:
cont.append('...')
cont.extend(obj._ext)
info.append( SPACE_MARGIN + space + repr(cont) )
def show_infos(val, werr, wext, cap=False):
print()
vers = ''
info = ['OPERATION content: %s\n' % ' - '.join(sorted(val.keys()))]
if 'ArgumentType' in val:
arg = val['ArgumentType']
vers = arg._typeref.called[0].split('-')[0]
info.append(' ArgumentType: %s (%s)' % (arg._typeref.called[1], arg.TYPE))
get_construct_info(arg, info, wext)
info.append('')
if 'ResultType' in val:
res = val['ResultType']
if res._typeref.called[0].split('-')[0] != vers:
print('[ERR] version error')
info.append(' ResultType: %s (%s)' % (res._typeref.called[1], res.TYPE))
get_construct_info(res, info, wext)
info.append('')
if werr and 'Errors' in val:
err = val['Errors']
for e in err.getv():
get_error_info(e, info, wext)
if cap:
for name in GLOBAL.MOD['CAP-operationcodes']['_val_']:
if GLOBAL.MOD['CAP-operationcodes'][name]._val == val['operationCode']:
info.insert(0, 'CAP-operationcodes name: %s' % name)
break
else:
if vers == 'MAPv2':
info.insert(0, 'MAP version 1 and 2')
elif vers:
info.insert(0, 'MAP version 3 and over')
else:
info.insert(0, 'MAP version unknown')
print('\n'.join(info))
def show_appctx(oc):
aci = get_application_ctxs(oc, 'I')
if aci:
print()
print('Initiator in MAP application context:')
for acname, ac in aci.items():
print(' - %-40s (%s)' % (acname, ' '.join(map(str, ac['code']))))
print(' {%s} -> {%s}' % (', '.join(ac['InitiatorIn'].getv()), ', '.join(ac['ResponderIn'].getv())))
acr = get_application_ctxs(oc, 'R')
if acr:
print()
print('Responder in MAP application context:')
for acname, ac in acr.items():
print(' - %-40s (%s)' % (acname, ' '.join(map(str, ac['code']))))
ocini = []
if 'InitiatorConsumerOf' in ac:
for opval in ac['InitiatorConsumerOf'].getv():
if 'Supplier' in opval:
for oval in opval['Supplier'].getv():
ocini.append(oval['operationCode'][1])
print(' MAP opcode initiating: %s' % ', '.join(map(str, ocini)))
print(' {%s} -> {%s}' % (', '.join(ac['InitiatorIn'].getv()), ', '.join(ac['ResponderIn'].getv())))
def print_operation_infos(args):
if args.c:
Op = GLOBAL.MOD['TCAP-CAP-Messages']['AllCAPInvokable']
prot = 'CAP'
else:
Op = GLOBAL.MOD['MAPv2v3-Protocol']['Supported-MAP-Operations']
prot = 'MAP'
#
if args.o == []:
oc = list(range(0x100))
else:
oc = args.o[:]
for i in oc:
vals = Op.get('operationCode', ('local', i))
if args.l:
if vals[0] == 'U':
if 'ArgumentType' in vals[1]:
mod, name = vals[1]['ArgumentType']._typeref.called
print('%s operation code (local, %.2i): %s.%s' % (prot, i, mod, name))
else:
print('%s operation code (local, %.2i): no argument' % (prot, i))
elif vals[0] == 'M':
for v in vals[1]:
if 'ArgumentType' in v:
mod, name = v['ArgumentType']._typeref.called
print('%s operation code (local, %.2i): %s.%s' % (prot, i, mod, name))
else:
print('%s operation code (local, %.2i): no argument' % (prot, i))
else:
if vals[0] == 'U':
print()
print('-'*80)
print('-'*23, ' %s operationCode: (local, %.2i) ' % (prot, i), '-'*23)
print('-'*80)
val = vals[1]
show_infos(val, args.e, args.x, cap=args.c)
elif vals[0] == 'M':
print()
print('-'*80)
print('-'*23, ' %s operationCode: (local, %.2i) ' % (prot, i), '-'*23)
print('-'*80)
for val in vals[1]:
show_infos(val, args.e, args.x)
if not args.c:
show_appctx(i)
def main():
parser = argparse.ArgumentParser(description='print information related to MAP '\
'procedures providing their operation code integral value')
parser.add_argument('-o', type=int, nargs='+', help='MAP operation code', default=[])
parser.add_argument('-l', action='store_true', help='only list MAP argument name associated to operation codes')
parser.add_argument('-e', action='store_true', help='add procedure-related errors')
parser.add_argument('-x', action='store_true', help='add extended data structures')
parser.add_argument('-c', action='store_true', help='switch to the CAP / Camel protocol instead of MAP')
args = parser.parse_args()
if args.c:
load_cap_mod()
#
print_operation_infos(args)
return 0
if __name__ == '__main__':
sys.exit(main())