Example #1
0
 def decipher(self, key=16*'\0', dir=0):
     # key: K_NAS_enc
     # cnt: NAS uplink or downlink counter
     # dir: direction (uplink / downlink)
     # using self.EEA
     #
     # if no deciphering to apply
     if self.SH() not in (2, 3) \
     or self.EEA not in (None, EEA1, EEA2, EEA3):
         return
     if not hasattr(self, '_pay') \
     or (not isinstance(self[-1], Str) and self[-1].CallName != '_enc'):
         log(ERR, 'Layer3NAS - decipher: not ready for deciphering')
         return
     #
     if self.EEA is None:
         # null ciphering EEA0
         dec = str(self[-1])
     else:
         dec = self.EEA(key, self.SN(), 0, dir, str(self[-1]))
     #
     # get the complete packet buffer
     buf = str(self[:4]) + dec
     # reinsert NAS payload IEs
     self.remove(self[-1])
     self.extend(self._pay)
     # remap the complete deciphered buffer to the NAS layer
     Layer3.map(self, buf)
     self._map_eps_id()
Example #2
0
 def interpret_IE(self, field, cn):
     # interpret field as cn
     # cn is looked up in L3Mobile_IE, L3GSM_IE or L3GSM_RR libs
     if self.dbg >= DBG:
         log(DBG, 'Layer3 - interpret IE: %s' % cn)
     # check if direct field, or (T)LV-like field
     if hasattr(field, 'V'):
         # bypass IE interpretation in case of LV or TLV with null length
         if hasattr(field, 'L') and field.L() == 0:
             return
         f_val = field.V
     else:
         f_val = field
     # replace the raw field value by pointing to the retrieved IE
     buf = str(f_val)
     ie = IE_lookup[cn]()
     try:
         ie.map(buf)
     except:
         if self.dbg >= WNG:
             log(WNG, 'Layer3 - IE mapping failed for %s' % ie.__class__)
     else:
         # only update the field if we got correct length data for the IE
         if str(ie) == buf:
             #if len(ie) == len(buf):
             f_val < None
             f_val > ie
             # and go for human representation...
             f_val.Repr = 'hum'
Example #3
0
 def test_dict():
     e = 0
     for pd in L3Call:
         for msg in L3Call[pd]:
             error = ''
             cl = L3Call[pd][msg]
             if not issubclass(cl, Layer3):
                 log(WNG, 'message %s not subclass of Layer3' % repr(cl))
             else:
                 try:
                     m = cl(with_options=True)
                 except:
                     error = '__init__(with_options=True)'
                 else:
                     try:
                         buf = str(m)
                     except:
                         error = '__str__()'
                     else:
                         try:
                             m2 = cl(with_options=False)
                             m2.parse(buf)
                         except:
                             error = 'parse()'
                         else:
                             if str(m2) != buf:
                                 error = '__str__() result discrepancy ' + \
                                         ' with parse()d buffer'
                 if error:
                     log(ERR, 'message %s test returns error: %s' \
                              % (repr(cl), error))
                     e += 1
     return e
Example #4
0
 def test_dict():
     e = 0
     for pd in L3Call:
         for msg in L3Call[pd]:
             error = ''
             cl = L3Call[pd][msg]
             if not issubclass(cl, Layer3):
                 log(WNG, 'message %s not subclass of Layer3' % repr(cl))
             else:
                 try:
                     m = cl(with_options=True)
                 except:
                     error = '__init__(with_options=True)'
                 else:
                     try: 
                         buf = str(m)
                     except:
                         error = '__str__()'
                     else:
                         try:
                             m2 = cl(with_options=False)
                             m2.parse(buf)
                         except:
                             error = 'parse()'
                         else:
                             if str(m2) != buf:
                                 error = '__str__() result discrepancy ' + \
                                         ' with parse()d buffer'
                 if error:
                     log(ERR, 'message %s test returns error: %s' \
                              % (repr(cl), error))
                     e += 1
     return e
Example #5
0
 def _build_path(self, csn1iter):
     # WNG : there is probably an issue as the ._offset attribute
     # is not changed during the several recursive calls...
     #
     cnt=0
     # recursive loading of CSN.1 fields, following the path of conditions
     for f in csn1iter:
         if self.dbg >= DBG:
             log(DBG, '(_build_path - %s) iterating over: %s' \
                 % (self.__class__, repr(f)))
         if isinstance(f, CSN1FIELDS):
             #print('<<<<<<<<<<<<<<<<<<<<<< %s' % f.CallName)
             self._append_csn1_field(f)
         elif isinstance(f, tuple):
             self._build_path(f)
         #
         elif isinstance(f, dict):
             # in case there is no more conditions privided
             if not self._cur_path:
                 self._build_auto(csn1iter[cnt:])
                 return
             # this is the case were we need to consume the _cur_path
             # and append the values as of the provided conditions
             #
             self._build_from_dict(f)
         #
         cnt += 1
Example #6
0
 def interpret_IE(self, field, cn):
     # interpret field as cn
     # cn is looked up in L3Mobile_IE, L3GSM_IE or L3GSM_RR libs
     if self.dbg >= DBG:
         log(DBG, 'Layer3 - interpret IE: %s' % cn)
     # check if direct field, or (T)LV-like field
     if hasattr(field, 'V'):
         # bypass IE interpretation in case of LV or TLV with null length
         if hasattr(field, 'L') and field.L() == 0:
             return
         f_val = field.V
     else:
         f_val = field
     # replace the raw field value by pointing to the retrieved IE
     buf = str(f_val)
     ie = IE_lookup[cn]()
     try:
         ie.map(buf)
     except:
         if self.dbg >= WNG:
             log(WNG, 'Layer3 - IE mapping failed for %s' % ie.__class__) 
     else:
         # only update the field if we got correct length data for the IE
         if str(ie) == buf:
         #if len(ie) == len(buf):
             f_val < None
             f_val > ie
             # and go for human representation...
             f_val.Repr = 'hum'
Example #7
0
 def map(self, s=''):
     if not s:
         return
     # check the security header
     s0 = ord(s[0])
     sh, pd = s0>>4, s0&0xF
     # ESM, or EMM with no security header
     if pd == 2 or sh in (0, 12):
         self.__init__(with_security=False)
         Layer3.map(self, s)
         self._map_eps_id()
     # EMM with security header
     elif pd == 7 and sh in (1, 2, 3, 4):
         self.ins_sec_hdr()
         # if no ciphering applied
         if sh in (1, 3): 
         #if sh in (1, 3) or self.EEA not in (EEA1, EEA2, EEA3):
             # if no payload is already there, just add a ciphered-like one
             if len(self.elementList) == 4:
                 self << Str('_enc')
             # map directly the buffer onto the NAS payload
             Layer3.map(self, s)
             self._map_eps_id()
         else:
             # keep track of all IE of the original packet
             self._pay = self[4:]
             # replace them with a dummy string
             for ie in self._pay:
                 self.remove(ie)
             self << Str('_enc')
             Layer3.map(self, s)
     else:
         log(ERR, '[ERR] invalid Security Header value %i' % sh)
Example #8
0
 def _cond_error(self, condset):
     #if self.dbg >= ERR:
     #    log(ERR, '(CSN1._get_cond - %s) undefined CSN1 condition set: %s' \
     #             % (condset, self.__class__))
     log(ERR, '(CSN1._get_cond - %s) undefined CSN1 condition set: %s' \
                  % (condset, self.__class__))
     if self.safe:
         assert()
Example #9
0
 def _select_tag(self, s='\0', taglist=[]):
     # check for 4 bits and 8 bits tags
     t4, t8 = ord(s[0])>>4, ord(s[0])
     if self.dbg >= DBG:
         log(DBG, '(Layer3 - %s) t4, t8: %s, %s\ntaglist: %s' \
                  % (self.CallName, t4, t8, taglist))
     #
     # try another way:
     # prefer the tag which is 1st in the taglist, whatever tag length
     for t in taglist:
         if t in (t4, t8):
             return t
     return None
Example #10
0
 def _select_tag(self, s='\0', taglist=[]):
     # check for 4 bits and 8 bits tags
     t4, t8 = ord(s[0]) >> 4, ord(s[0])
     if self.dbg >= DBG:
         log(DBG, '(Layer3 - %s) t4, t8: %s, %s\ntaglist: %s' \
                  % (self.CallName, t4, t8, taglist))
     #
     # try another way:
     # prefer the tag which is 1st in the taglist, whatever tag length
     for t in taglist:
         if t in (t4, t8):
             return t
     return None
Example #11
0
 def _append_path(self, path):
     if self.dbg >= DBG:
         log(DBG, '(build - %s) going path: %s' \
             % (self.__class__, repr(path)))
     cond = ''
     for c in path:
         # if LH, get the correct value with self._offset
         if c in 'LH':
             L = self.L[self._offset%8]
             self.append(Bit('%s' % self.cond_name, \
                 Pt={'L':L, 'H':(1, 0)[L]}[c] , BitLen=1))
         elif c in '01':
             self.append(Bit('%s' % self.pad_name, Pt=int(c, 2), BitLen=1))
         else:
             self._cond_error(path)
         self._offset += 1
Example #12
0
 def _build_auto(self, csn1iter):
     #print self.CallName
     # recursive automatic loading of CSN.1 fields
     for f in csn1iter:
         if self.dbg >= DBG:
             log(DBG, '(_build_auto - %s) iterating over: %s' \
                 % (self.__class__, repr(f)))
         if isinstance(f, CSN1FIELDS):
             self._append_csn1_field(f)
         elif isinstance(f, tuple):
             self._build_auto(f)
         elif isinstance(f, dict):
             # select the shortest path: BREAK, BREAK_LOOP,
             # or the shortest value
             values = f.values()
             # easiest path is to get straight out of the dict
             if BREAK in values or BREAK_LOOP in values:
                 for i in f.items():
                     if i[1] in (BREAK, BREAK_LOOP):
                         self._append_path(i[0])
                         break
             # 2nd easiest path is to take a single CSN1FIELDS if exist
             elif True in [isinstance(i, CSN1FIELDS) for i in values]:
                 for i in f.items():
                     # "au petit bonheur la chance"
                     if isinstance(i[1], CSN1FIELDS):
                         self._append_path(i[0])
                         self._append_csn1_field(i[1])
                         break
             # 3rd easiest path is to take the shortest tuple available
             elif True in [isinstance(i, tuple) for i in values]:
                 min_tuple = min(map(len, values))
                 for i in f.items():
                     if len(i[1]) == min_tuple:
                         # "au petit bonheur la chance" again
                         self._append_path(i[0])
                         self._build_auto(i[1])
                         break
             # 4th easiest path is to enter the shortest dict available
             elif True in [isinstance(i, dict) for i in values]:
                 min_dict = min(map(len, values))
                 for i in f.items():
                     if len(i[1]) == min_dict:
                         # "au petit bonheur la chance" once again
                         self._append_path(i[0])
                         self._build_auto(i[1])
                         break
Example #13
0
 def _select_tag_old_(self, s='\0', taglist=[]):
     # check for 4 bits and 8 bits tags
     t4, t8 = ord(s[0]) >> 4, ord(s[0])
     if self.dbg >= DBG:
         log(DBG, '(Layer3 - %s) t4, t8: %s, %s\ntaglist: %s' \
                  % (self.CallName, t4, t8, taglist))
     #
     # handle 4 bits tag in priority
     # guessing from 3GPP spec:
     #   4 bits and 8 bits tags should never clash...
     # actually, this is not always the case
     #   e.g. for tag 4 (BearerCap) and 64 (SuppCodecs)
     # TODO: this is actually a real issue,
     # e.g. with GSM RR ASSIGNMENT_COMMAND
     if t4 in taglist:
         return t4
     elif t8 in taglist:
         return t8
     return None
Example #14
0
 def __get_opts(self):
     found_opt, opt_ie = False, []
     # we have at least 3 mandatory fields (L3 header: SI, PD, Type)
     # and we should not have any IE left, except StrRR for GSM RR
     if isinstance(self[-1], StrRR): ie_to_check = self[3:-1]
     else: ie_to_check = self[3:]
     #
     for ie in ie_to_check:
         if hasattr(ie, 'T') or isinstance(ie, (Type2, StrRR)):
             found_opt = True
             opt_ie.append(ie)
             # make all optional fields not transparent (so all of them
             # can be mapped, whatever Layer3.__init__() options given)
             ie.Trans = False
         elif found_opt and self.dbg >= ERR:
             # we should not find mandatory IE after optional
             log(ERR, '(Layer3 - %s) mandatory IE found after ' \
                 'optional ones' % self.CallName)
     return opt_ie
Example #15
0
 def __get_opts(self):
     found_opt, opt_ie = False, []
     # we have at least 3 mandatory fields (L3 header: SI, PD, Type)
     # and we should not have any IE left, except StrRR for GSM RR
     if isinstance(self[-1], StrRR): ie_to_check = self[3:-1]
     else: ie_to_check = self[3:]
     #
     for ie in ie_to_check:
         if hasattr(ie, 'T') or isinstance(ie, (Type2, StrRR)):
             found_opt = True
             opt_ie.append(ie)
             # make all optional fields not transparent (so all of them
             # can be mapped, whatever Layer3.__init__() options given)
             ie.Trans = False
         elif found_opt and self.dbg >= ERR:
             # we should not find mandatory IE after optional
             log(ERR, '(Layer3 - %s) mandatory IE found after ' \
                 'optional ones' % self.CallName)
     return opt_ie
Example #16
0
 def _select_tag_old_(self, s='\0', taglist=[]):
     # check for 4 bits and 8 bits tags
     t4, t8 = ord(s[0])>>4, ord(s[0])
     if self.dbg >= DBG:
         log(DBG, '(Layer3 - %s) t4, t8: %s, %s\ntaglist: %s' \
                  % (self.CallName, t4, t8, taglist))
     #
     # handle 4 bits tag in priority
     # guessing from 3GPP spec:
     #   4 bits and 8 bits tags should never clash...
     # actually, this is not always the case 
     #   e.g. for tag 4 (BearerCap) and 64 (SuppCodecs)
     # TODO: this is actually a real issue,
     # e.g. with GSM RR ASSIGNMENT_COMMAND
     if t4 in taglist:
         return t4
     elif t8 in taglist:
         return t8
     return None
Example #17
0
 def map(self, string='', byte_offset=0):
     # pop each member of the initial csn1List
     # and see what we have
     # 1) CSN1FIELD -> map it directly
     # 2) dict -> conditions -> CSN1FIELD | dict | tuple
     # 3) tuple -> CSN1FIELD | dict
     # consume the string buffer bit per bit depending of the 
     # csn1List member poped
     #
     # as a CSN1 field does not always start on a byte limit,
     # we need to keep track of the byte offset, 
     # for solving padding (L | H) adequately
     #
     # in case CSN1 list is empty
     if len(self.csn1List) == 0:
         return
     # initialize the string buffer to be mapped
     self.BUF, self._buflen = shtr(string), len(string)*8
     self._consumed, self._offset, self._map_exit = 0, byte_offset, False
     self.elementList = []
     #
     # MAIN loop
     # go over the string, bit per bit
     index = 0
     while (self._consumed + self._offset) < self._buflen:
         if self._map_exit:
             break
         # get csn1 fields 1 by 1
         self._eval_csn1(self.csn1List[index])
         index += 1
         # when csn1List is empty, finish with padding
         if index >= len(self.csn1List):
             break
     #
     # TODO: the padding should only be done when instructed so in CSN1
     remaining = self._buflen - (self._consumed + self._offset)
     if remaining:
         if self.dbg >= DBG:
             log(DBG, '(CSN1._eval_csn1_dict) bits are remaining unmapped')
     # clean temporary data
     del self.BUF, self._buflen, self._consumed, \
         self._offset, self._map_exit
Example #18
0
 def _WtoF(self, index, fmt):
     # J := GREATEST_POWER_OF_2_LESSER_OR_EQUAL_TO(INDEX);
     J = [j for j in [1, 2, 4, 8, 16, 32, 64, 128] if j <= index].pop()
     N = getattr(self, "W_%i" % index)()
     #
     while index > 1:
         if (2 * index) < (3 * J):
             index = index - (J / 2)
             # for range 1024, we have to take W(PARENT)
             par = self._get_W_parent(index, fmt)
             N = ((N + par + (fmt / J) - 2) % (((fmt * 2) / J) - 1)) + 1
         else:
             index = index - J
             # for range 1024, we have to take W(PARENT)
             par = self._get_W_parent(index, fmt)
             N = (N + par + ((fmt * 2) / J) - 2) % (((fmt * 2) / J) - 1) + 1
         J = J / 2
     if self.dbg >= DBG:
         log(DBG, "L3GSM_IE ARFCN WtoF - N: %i" % N)
     return N
Example #19
0
 def _append_from_dict(self, from_dict, condlen):
     # xtra verbose debugging
     if self.dbg > DBG:
         if type(from_dict) is tuple: obj = list(from_dict)
         elif hasattr(from_dict, 'CallName'): obj = from_dict.CallName
         else: obj = from_dict
         log(DBG, '(CSN1._eval_csn1_dict) selected from_dict: %s' % obj)
     # if condition lead to None: padding
     if from_dict == BREAK:
         self._append_map_csn1_field(Bit('%s' % self.pad_name, BitLen=condlen))
     # if condition lead to breaking a loop 
     # for crappy CSN1 syntax like {1 expr}**0
     elif from_dict == BREAK_LOOP:
         self._append_map_csn1_field(Bit('%s' % self.pad_name, BitLen=condlen))
         self._loop = False
     # if condition lead to something:
     else:
         self._append_map_csn1_field(Bit('%s' % self.cond_name, BitLen=condlen))
         # recurse to the main csn1 eval method applied to object from dict
         self._eval_csn1(from_dict)
Example #20
0
 def _append_csn1_field(self, field):
     if isinstance(field, LHFlag):
         #print self._offset
         if self.L[self._offset%8] == 1:
             field.LHdict = iad({1:'L', 0:'H'})
     if isinstance(field, CSN1):
         # initialize the field without building it any specific way
         f = field.__class__(False, None)
         # and then call build() in order to pass the _offset attribute
         path = self._cur_path if hasattr(self, '_cur_path') else None
         f.build(f.csn1List, self._offset, path)
         #
         if self.dbg >= DBG:
             log(DBG, '(_append_csn1_field) field %s with path %s'\
                 % (f.CallName, path))
         self.append(f)
         self._offset += f.bit_len()
         #
     else:
         self.append(field)
         self._offset += field.bit_len()
Example #21
0
 def get_deciphered(self, key=16*'\0', dir=0):
     # this is to get the deciphered stream of a NAS EMM message
     # 
     # no NAS security
     if self.SH() == 0 and not hasattr(self, 'MAC'):
         return str(self)
     #
     # NAS security, only integrity protection
     elif self.SH() in (1, 3) and hasattr(self, 'MAC'):
         return str(self[4:])
     #
     # NAS security, ciphered
     elif self.SH() in (2, 4) and hasattr(self, 'MAC'):
         if self.EEA is None:
             # null ciphering EEA0
             return str(self[4:])
         elif self[-1].CallName == '_enc':
             return self.EEA(key, self.SN(), 0, dir, str(self[-1]))
     #
     log(ERR, 'Layer3NAS - get_deciphered: could not retrieve NAS payload')
     return ''
Example #22
0
 def _get_ccch(self, string=''):
     # this is to decode reliably GSM broadcast
     #
     if len(string) < 3:
         self << RawLayer()
         self[-1].map(string)
         return
     #
     l = LengthRR()
     l.map(string[0:1])
     h = Header()
     h.map(string[1:3])
     # should check length (l) coherence here (including with M bit)
     # ...
     # check for non-RR protocol, or truncated string
     #print('L1CTL decoding ; h.PD %s, string length %s' % (h.PD(), len(string)))
     if h.PD() != 6 or len(string) < 22:
         self << l
         self | RawL3()
         self[-1].map(string[1:])
         return
     #
     # if we have the complete RR decoder
     if h.Type() in L3Call[6].keys():
         rr = L3Call[6][h.Type()]()
         try:
             rr.map(string)
             self << rr
             return
         except:
             pass
     #
     # otherwise, it's the generic RR decoder
     # what is not very smart... however !
     if self.dbg >= DBG:
         log(DBG, '(L1CTL - L3GSM_RR) message parsing failed with:\n%s' \
                   % hexlify(string))
     self << RR_gene()
     self[-1].map(string)
Example #23
0
 def _get_ccch(self, string=''):
     # this is to decode reliably GSM broadcast
     #
     if len(string) < 3:
         self << RawLayer()
         self[-1].map(string)
         return
     #
     l = LengthRR()
     l.map(string[0:1])
     h = Header()
     h.map(string[1:3])
     # should check length (l) coherence here (including with M bit)
     # ...
     # check for non-RR protocol, or truncated string
     #print('L1CTL decoding ; h.PD %s, string length %s' % (h.PD(), len(string)))
     if h.PD() != 6 or len(string) < 22:
         self << l
         self | RawL3()
         self[-1].map(string[1:])
         return
     #
     # if we have the complete RR decoder
     if h.Type() in L3Call[6].keys():
         rr = L3Call[6][h.Type()]()
         try:
             rr.map(string)
             self << rr
             return
         except:
             pass
     #
     # otherwise, it's the generic RR decoder
     # what is not very smart... however !
     if self.dbg >= DBG:
         log(DBG, '(L1CTL - L3GSM_RR) message parsing failed with:\n%s' \
                   % hexlify(string))
     self << RR_gene()
     self[-1].map(string)
Example #24
0
 def __map_opt(self, tag, string, opt_ie):
     # retrieve 1st optional IE for the given tag: in opt
     opt = None
     for ie in opt_ie:
         if ie[0]() == tag:
             opt = ie
             break
     # remove it from the opt_ie list that will be further processed
     # python's "remove()" remove the 1st iteration of an element in a list
     if not opt:
         log(ERR, '(Layer3 - %s) no remaining optional field for tag %i' \
                  % (self.CallName, tag))
         return '', opt_ie
     opt_ie.remove(opt)
     # force it to be not transparent, map it and truncate the string
     opt.Trans = False
     opt.map(string)
     if self.dbg >= DBG:
         log(DBG, '(Layer3 - %s) mapping %s on %s' \
                   % (self.__class__, hexlify(string), opt.CallName))
     string = string[opt.map_len():]
     return string, opt_ie
Example #25
0
 def __map_opt(self, tag, string, opt_ie):
     # retrieve 1st optional IE for the given tag: in opt
     opt = None
     for ie in opt_ie:
         if ie[0]() == tag:
             opt = ie
             break
     # remove it from the opt_ie list that will be further processed
     # python's "remove()" remove the 1st iteration of an element in a list
     if not opt:
         log(ERR, '(Layer3 - %s) no remaining optional field for tag %i' \
                  % (self.CallName, tag))
         return '', opt_ie
     opt_ie.remove(opt)
     # force it to be not transparent, map it and truncate the string
     opt.Trans = False
     opt.map(string)
     if self.dbg >= DBG:
         log(DBG, '(Layer3 - %s) mapping %s on %s' \
                   % (self.__class__, hexlify(string), opt.CallName))
     string = string[opt.map_len():]
     return string, opt_ie
Example #26
0
 def _decode_range(self, fmt):
     # go over all W fields and apply the computation algorithm
     # as of 10.5.2.3.13.3
     # some discrepancies exist between the 4 ranges:
     # 1) computing the next F
     # 2) initial and number of F
     if fmt == 1024:
         if self.F0():
             ar_list = [0]
         else:
             ar_list = []
         ind_max = 17
         app = lambda N: ar_list.append(N)
     elif fmt in (128, 256, 512):
         ar_list = [self.orig_arfcn()]
         if fmt == 128:
             ind_max = 29
         elif fmt == 256:
             ind_max = 22
         elif fmt == 512:
             ind_max = 18
         app = lambda N: ar_list.append((ar_list[0] + N) % 1024)
     #
     # loop over all non-null W values to compute corresponding F
     for ind in range(1, ind_max):
         if getattr(self, "W_%i" % ind)():
             app(self._WtoF(ind, fmt))
             #
             if self.dbg >= DBG:
                 log(
                     DBG,
                     "L3GSM_IE ARFCN WtoF - index %i; W %i; F %i"
                     % (ind, getattr(self, "W_%i" % ind)(), ar_list[-1]),
                 )
         else:
             break
     #
     return sorted(ar_list)
Example #27
0
 def _build_from_dict(self, d):
     # TODO: if BREAK_LOOP in the dict, 
     # we should iterate as much time as provided in the path list
     #
     conds = d.keys()
     #vals = d.values()
     #
     # select the value corresponding to the condition in _cur_path
     if self.dbg >= DBG:
         log(DBG, '(_build_path) _cur_path to process: %s' % self._cur_path)
     cond_from_path = self._cur_path.pop(0)
     if cond_from_path not in conds:
         raise(Exception('path %s does not correspond to any condition'\
               ' for building %s' % (cond_from_path, self.__class__)))
     #
     self._append_path(cond_from_path)
     field = d[cond_from_path]
     if field not in (BREAK, BREAK_LOOP):
         if isinstance(field, CSN1FIELDS):
             #print('<<<<<<<<<<<<<<<<<<<<<< %s' % field.CallName)
             self._append_csn1_field(field)
         else:
             # for tuple or dict, go the recursive way
             self._build_path(field)
Example #28
0
 def parse(self, s='', phy_included=True, fcs_included=True):
     #
     if self.PHY_INCL:
         # insert PHY() preamble and map the buffer to it
         if len(self.layerList) > 0 :
             self.layerList = []
             self << PHY()
         self[0].map(s)
         #
         # verify preamble
         if self[0].Preamble() != '\0\0\0\0' and self.dbg >= ERR:    
             log(ERR, 'bad 802.15.4 preamble in PHY')
         if len(s) != self.PHY.Length()+6 and self.dbg >= ERR:
             log(ERR, 'buffer longer than indicated in PHY header')
         # truncate string buffer
         s=s[6:6+self.PHY.Length()]
     else:
         if len(self.layerList) > 0:
             self.layerList = []
     #
     # standard 802.15.4 MAC header
     # insert MAC and map the buffer to it
     self << MAC()
     self[-1].map(s)
     s = s[len(self[-1]):]
     # insert DATA layer
     if self.FCS_INCL:
         if len(s) > 2:
             self << Data()
             self[-1].map(s[:-2])
         if len(s) >= 2:
             self >> FCS()
             self[-1].map(s[-2:])
             # verify CRC
             crc = self.FCS.FCS()
             self.FCS.FCS < None
             if self.FCS.FCS() != crc and self.dbg >= ERR:
                 log(ERR, 'bad 802.15.4 CRC16 in MAC suffix')
             # refill with the original value
             self.FCS.FCS < crc
         elif self.dbg >= ERR:
             log(ERR, 'buffer not long enough for FCS')
             
     elif len(s) > 0:
         self << Data()
         self[-1].map(s)
Example #29
0
 def _append_map_csn1_field(self, csn1f):
     # ensure there is still enough buffer to map on new fields
     if hasattr(csn1f, 'bit_len') \
     and csn1f.bit_len() > (self._buflen - (self._consumed+self._offset)):
         if self.dbg >= WNG:
             log(WNG, '(CSN1.map - %s) buffer not long enough for field: ' \
                      '%s from csn1List' % (self.__class__, csn1f.CallName))
         self._map_exit = True
         return
     # append the field to the layer
     if self.dbg >= DBG:
         log(DBG, '(CSN1._append_map_csn1_field) appending csn1 field: %s' \
             % csn1f.CallName)
     #
     # map the BUF on the element: this solves its bit length
     # moreover, we transmit the byte offset, for solving correctly L|H flags
     if type(csn1f) == type and issubclass(csn1f, CSN1):
         self.append(csn1f().clone())
     else:
         self.append(csn1f)
     #
     if isinstance(self[-1], CSN1):
         self[-1].map(self.BUF, (self._consumed+self._offset)%8)
         bitlen = self[-1].bit_len()
     else:
         self[-1].map(self.BUF)
         bitlen = self[-1].bit_len()
         # check if LHFlag to possibly update its LH dictionnary
         if isinstance(self[-1], LHFlag):
             l = self.L[(self._consumed+self._offset)%8]
             h = (1, 0)[l]
             self[-1].LHdict = iad({l:'L', h:'H'})
     #
     # update global BUFFER and consumed bit length 
     self.BUF = self.BUF << bitlen
     self._consumed += bitlen
Example #30
0
 def __map_opts(self, string=''):
     # retrieve all optional IE from the Layer3 into opt_ie list
     opt_ie = self.__get_opts()
     taglist = [ie[0]() for ie in opt_ie if not isinstance(ie, StrRR)]
     if self.dbg >= DBG:
         log(DBG, '(Layer3 - %s) opt_ie: %s' % (self.CallName, opt_ie))
     # go over the string and map to optional IE found
     while len(string) > 0:
         # check each iteration for the right tag
         t = self._select_tag(string[0], taglist)
         if t:
             string, opt_ie = self.__map_opt(t, string, opt_ie)
             taglist.remove(t)
         #
         else:
             if self.dbg >= ERR:
                 log(WNG, '(Layer3 - %s) unknown optional IE' \
                     % self.CallName)
             # could try to map it as a TLV, or TLVextended, or TV, or T...
             # check the TS 24.007, section 11.2.4, for being amazed...
             string2 = self.__map_unknown_opt(string)
             if string2 == string:
                 break
             string = string2
         #
     # optional IE that have not been mapped have to go "transparent"
     if len(opt_ie) > 0:
         [setattr(ie, 'Trans', True) for ie in opt_ie]
         if self.dbg >= DBG:
             log(DBG, '(Layer3 - %s) not all optional IE used\nremaining:' \
                 ' %s' % (self.CallName, opt_ie))
     # this should only happen when __map_unknown_opt() cannot 
     # consume remaining string.
     if len(string) > 0 and self.dbg >= ERR:
         log(ERR, '(Layer3 - %s) string not completely mapped\nremaining: ' \
             '%s' % (self.CallName, string))
Example #31
0
 def __map_opts(self, string=''):
     # retrieve all optional IE from the Layer3 into opt_ie list
     opt_ie = self.__get_opts()
     taglist = [ie[0]() for ie in opt_ie if not isinstance(ie, StrRR)]
     if self.dbg >= DBG:
         log(DBG, '(Layer3 - %s) opt_ie: %s' % (self.CallName, opt_ie))
     # go over the string and map to optional IE found
     while len(string) > 0:
         # check each iteration for the right tag
         t = self._select_tag(string[0], taglist)
         if t:
             string, opt_ie = self.__map_opt(t, string, opt_ie)
             taglist.remove(t)
         #
         else:
             if self.dbg >= ERR:
                 log(WNG, '(Layer3 - %s) unknown optional IE' \
                     % self.CallName)
             # could try to map it as a TLV, or TLVextended, or TV, or T...
             # check the TS 24.007, section 11.2.4, for being amazed...
             string2 = self.__map_unknown_opt(string)
             if string2 == string:
                 break
             string = string2
         #
     # optional IE that have not been mapped have to go "transparent"
     if len(opt_ie) > 0:
         [setattr(ie, 'Trans', True) for ie in opt_ie]
         if self.dbg >= DBG:
             log(DBG, '(Layer3 - %s) not all optional IE used\nremaining:' \
                 ' %s' % (self.CallName, opt_ie))
     # this should only happen when __map_unknown_opt() cannot
     # consume remaining string.
     if len(string) > 0 and self.dbg >= ERR:
         log(ERR, '(Layer3 - %s) string not completely mapped\nremaining: ' \
             '%s' % (self.CallName, string))
Example #32
0
 def map(self, string=''):
     # Layer3 have optional fields that need special processing
     # they all have a tag (attribute .T)
     opt_fields = (Type1_TV, Type2, Type3_TV, Type4_TLV, Type6_TLVE)
     GSM_RR = False
     # handle special string truncature for L3GSM_RR that is on CCCH
     # cause opts may not be there, but we still have rest octets to map
     if self.CallName in RR_in_CCCH:
         if self.safe:
             assert (isinstance(self[0], Bit) and self[0].CallName == 'len')
         GSM_RR, l2_len = True, self._len_gsmrr(string)
         string, rest = string[:l2_len + 1], string[l2_len + 1:]
         if self.dbg >= DBG:
             log(DBG, '(Layer3 GSM_RR - %s)\nl2len: %i\nstring: %s\nrest: %s' \
                 % (self.CallName, l2_len, hexlify(string), hexlify(rest)))
     # Otherwise we mimic standard Layer().map() behaviour
     self._Layer__BitStack = []
     self._Layer__BitStack_len = 0
     #
     for e in self:
         # special processing for Bit() element:
         if isinstance(e, Bit):
             self._Layer__add_to_bitstack(e)
             # if BitStack is byte aligned, map string to it:
             if self._Layer__BitStack_len % 8 == 0:
                 if self.dbg >= DBG:
                     log(DBG, '(Layer3 - %s) mapping %s to bitstack %s' \
                         % (self.__class__, hexlify(string), \
                            self._Layer__BitStack))
                 string = self._Layer__map_to_bitstack(string)
         else:
             if self._Layer__BitStack_len > 0 and self.dbg >= ERR:
                 log(ERR, '(Layer3 - %s) some of the Bit elements have not ' \
                     'been mapped in the "Layer": not byte-aligned' \
                     % self.CallName)
             ### special Layer3 processing ###
             # need to manage smartly optional / conditionnal fields
             # Tagged IE always come after mandatory IE
             # so we handle it in another sub method and break the parsing
             if isinstance(e, opt_fields):
                 # for standard L3 messages
                 self.__map_opts(string)
                 break
             ###
             # and for mandatory IE (not tagged)
             if isinstance(e, (Layer, Element)) and not e.is_transparent():
                 if self.dbg >= DBG:
                     log(DBG, '(Layer3 - %s) mapping %s on %s' \
                         % (self.__class__, hexlify(string), e.CallName))
                 e.map(string)
                 string = string[e.map_len():]
     # for GSM RR: map rest octets, that comes after tagged IE
     if GSM_RR and rest:
         if isinstance(self[-1], StrRR):
             self[-1].Trans = False
         else:
             self.append(StrRR('RestOctets', Repr='hex'))
         self[-1].map(rest)
     # delete .map() *internal* attributes
     del self._Layer__BitStack
     del self._Layer__BitStack_len
     #
     ### special Layer3 processing ###
     if not self._interpret_IE:
         return
     #
     # Go again through all L3 fields that are not transparent
     # (tested with their length, WNG: do not work for LV(), however,
     # LV field should always be there...)
     # and check if L3Mobile_IE is available for even more interpretation
     for e in [f for f in self if len(f)]:
         cn = e.CallName
         if self.dbg >= DBG:
             log(DBG, 'L3Mobile_24007 - map: checking for IE %s ' \
                 'interpretation' % cn)
         # truncate possible digit addition at the end of the CallName
         # 11/06/2012: this ugly hack is not supported anymore...
         # 13/06/2012: this ugly hack is back !
         # with an '_' in front of the digit
         digit = search('_[1-9]{1,}$', e.CallName)
         if digit:
             cn = cn[:digit.start()]
         # check for potential IE interpretation
         #if hasattr(L3Mobile_IE, cn) or hasattr(L3GSM_IE, cn):
         if cn in IE_list:
             self.interpret_IE(e, cn)
Example #33
0
 def map(self, string=''):
     # Layer3 have optional fields that need special processing
     # they all have a tag (attribute .T)
     opt_fields = (Type1_TV, Type2, Type3_TV, Type4_TLV, Type6_TLVE)
     GSM_RR = False
     # handle special string truncature for L3GSM_RR that is on CCCH
     # cause opts may not be there, but we still have rest octets to map
     if self.CallName in RR_in_CCCH:
         if self.safe:
             assert(isinstance(self[0], Bit) and self[0].CallName=='len')
         GSM_RR, l2_len = True, self._len_gsmrr(string)
         string, rest = string[:l2_len+1], string[l2_len+1:]
         if self.dbg >= DBG:
             log(DBG, '(Layer3 GSM_RR - %s)\nl2len: %i\nstring: %s\nrest: %s' \
                 % (self.CallName, l2_len, hexlify(string), hexlify(rest)))
     # Otherwise we mimic standard Layer().map() behaviour
     self._Layer__BitStack = []
     self._Layer__BitStack_len = 0
     #
     for e in self:
         # special processing for Bit() element:
         if isinstance(e, Bit):
             self._Layer__add_to_bitstack(e)
             # if BitStack is byte aligned, map string to it:
             if self._Layer__BitStack_len % 8 == 0:
                 if self.dbg >= DBG:
                     log(DBG, '(Layer3 - %s) mapping %s to bitstack %s' \
                         % (self.__class__, hexlify(string), \
                            self._Layer__BitStack))
                 string = self._Layer__map_to_bitstack(string)
         else:
             if self._Layer__BitStack_len > 0 and self.dbg >= ERR:
                 log(ERR, '(Layer3 - %s) some of the Bit elements have not ' \
                     'been mapped in the "Layer": not byte-aligned' \
                     % self.CallName)
             ### special Layer3 processing ###
             # need to manage smartly optional / conditionnal fields
             # Tagged IE always come after mandatory IE
             # so we handle it in another sub method and break the parsing
             if isinstance(e, opt_fields):
                 # for standard L3 messages
                 self.__map_opts(string)
                 break
             ###
             # and for mandatory IE (not tagged)
             if isinstance(e, (Layer, Element)) and not e.is_transparent():
                 if self.dbg >= DBG:
                     log(DBG, '(Layer3 - %s) mapping %s on %s' \
                         % (self.__class__, hexlify(string), e.CallName))
                 e.map(string)
                 string = string[e.map_len():]
     # for GSM RR: map rest octets, that comes after tagged IE
     if GSM_RR and rest:
         if isinstance(self[-1], StrRR):
             self[-1].Trans = False
         else:
             self.append(StrRR('RestOctets', Repr='hex'))
         self[-1].map(rest)
     # delete .map() *internal* attributes
     del self._Layer__BitStack
     del self._Layer__BitStack_len
     #
     ### special Layer3 processing ###
     if not self._interpret_IE:
         return
     #
     # Go again through all L3 fields that are not transparent
     # (tested with their length, WNG: do not work for LV(), however,
     # LV field should always be there...) 
     # and check if L3Mobile_IE is available for even more interpretation
     for e in [f for f in self if len(f)]:
         cn = e.CallName
         if self.dbg >= DBG:
             log(DBG, 'L3Mobile_24007 - map: checking for IE %s ' \
                 'interpretation' % cn)
         # truncate possible digit addition at the end of the CallName
         # 11/06/2012: this ugly hack is not supported anymore...
         # 13/06/2012: this ugly hack is back ! 
         # with an '_' in front of the digit
         digit = search('_[1-9]{1,}$', e.CallName)
         if digit:
             cn = cn[:digit.start()]
         # check for potential IE interpretation
         #if hasattr(L3Mobile_IE, cn) or hasattr(L3GSM_IE, cn):
         if cn in IE_list:
             self.interpret_IE(e, cn)
Example #34
0
def parse_L3(buf, L2_length_incl=0):
    '''
    This is a global parser for mobile layer 3 signalling.
    It works fine as is with MM, CC, GMM and SM protocols.
    For GSM RR signalling, the length of the L2 pseudo-length header (1 byte)
    needs to be passed as parameter "L2_length_incl" to retrieve correctly 
    the protocol discriminator and message type.
    E.g. for messages passed over GSM BCCH or CCCH: L2_length_incl=1
    
    parse_L3(string_buffer, L2_length_incl=0) -> Layer3 instance
    '''
    # select message from PD and Type
    if len(buf) < 2:
        log(ERR, '(parse_L3) message too short for L3 mobile')
        return RawLayer(buf)
    #
    ###
    # Protocol Discriminator
    ###
    # protocol discriminator is 4 last bits (LSB) of 1st byte
    PD = ord(buf[L2_length_incl]) & 0x0F
    #
    ###
    # Message Type
    ###
    # for MM, CC, SS and GSM RR, only 6 1st bits for the message type
    if PD in (3, 5, 6, 11):
        Type = ord(buf[L2_length_incl+1]) & 0x3F
    #
    # for LTE NAS messages: message content (including Type) can be ciphered
    # (the security processing is available in the Layer3NAS class)
    # EMM header has a security header
    elif PD == 7:
        # check Security Header
        SH = ord(buf[L2_length_incl]) >> 4
        # no security:
        if SH == 0:
            Type = ord(buf[1])
        # integrity protection only:
        elif SH in (1, 3):
            if len(buf) < 8:
                Type = None
            Type = ord(buf[7])
        # ciphering, hence not possible to know the payload Type
        elif SH in (2, 4):
            Type = None
        elif SH == 12 and len(buf) >= 4:
            # LTE NAS service request
            l3 = SERVICE_REQUEST()
            l3.map(buf)
            return l3
        else:
            log(WNG, '(parse_L3) unknown NAS EMM security header: %i' % SH)
            Type = None
    #
    # ESM header has bearer ID in the 4 MSB of 1st byte
    # and Transaction ID between PD and Type
    elif PD == 2:
        if len(buf) < 3:
            Type = None
        Type = ord(buf[2])
    #
    # for other 2G and 3G core protocols (GMM, SM, SMS, ...), nothing special
    else:
        Type = ord(buf[L2_length_incl+1])
    #
    if PD not in L3Call:
        if PD not in PD_dict:
            log(ERR, '(parse_L3) unknown L3 protocol discriminator: %i' % PD)
        else:
            log(WNG, '(parse_L3) L3 protocol %s not implemented' % PD_dict[PD])
        l3 = RawL3()
        l3.map(buf)
    #
    # get the right type from Type
    elif Type not in L3Call[PD] and Type is not None:
        log(ERR, '(parse_L3) L3 message type %i undefined for protocol %s' \
              % (Type, PD_dict[PD]))
        l3 = RawL3()
        l3.map(buf)
        # for L3GSM_RR, still use the msg type dict:
        # because GSM RR are not all implemented
        if PD == 6:
            l3.Type.Dict = GSM_RR_dict
    #
    # select the correct L3 signalling message
    else:
        # for LTE NAS, if ciphered
        #log(DBG, '(parse_L3) PD %i, Type %i' % (PD, Type))
        if Type is None:
            l3 = Layer3NAS(with_security=True)
        else:
            l3 = L3Call[PD][Type]()
        #
        try:
            #log(DBG, '(parse_L3) mapping ?')
            l3.map(buf)
            #log(DBG, '(parse_L3) mapped correctly')
        except:
            log(ERR, '(parse_L3) mapping buffer on L3 message failed')
            l3 = RawL3()
            l3.map(buf)
    #
    return l3
Example #35
0
def test_regr(print_infos=True):
    '''
    L3GSM_RR and L3Mobile_* regression testing:
    checking all signalling messages from the L3Call dictionnary
    '''
    # libmich settings
    e_safe = Element.safe
    l_safe = Layer.safe
    Element.safe = True
    Layer.safe = True
    Element.dbg = ERR
    Layer.dbg = ERR
    #
    glob_errors = 0

    #
    def test_dict():
        e = 0
        for pd in L3Call:
            for msg in L3Call[pd]:
                error = ''
                cl = L3Call[pd][msg]
                if not issubclass(cl, Layer3):
                    log(WNG, 'message %s not subclass of Layer3' % repr(cl))
                else:
                    try:
                        m = cl(with_options=True)
                    except:
                        error = '__init__(with_options=True)'
                    else:
                        try:
                            buf = str(m)
                        except:
                            error = '__str__()'
                        else:
                            try:
                                m2 = cl(with_options=False)
                                m2.parse(buf)
                            except:
                                error = 'parse()'
                            else:
                                if str(m2) != buf:
                                    error = '__str__() result discrepancy ' + \
                                            ' with parse()d buffer'
                    if error:
                        log(ERR, 'message %s test returns error: %s' \
                                 % (repr(cl), error))
                        e += 1
        return e

    #
    Layer3._initiator = 'Net'
    if print_infos:
        log(DBG, 'testing with Net initiator')
    glob_errors += test_dict()
    Layer3._initiator = 'ME'
    if print_infos:
        log(DBG, 'testing with ME initiator')
    glob_errors += test_dict()
    #
    Element.safe = e_safe
    Layer.safe = l_safe
    #
    if not glob_errors and print_infos:
        log(DBG, '[Heeeeha!!!] all L3Mobile tests passed successfully')
    return glob_errors
Example #36
0
def parse_L3(buf, L2_length_incl=0):
    '''
    This is a global parser for mobile layer 3 signalling.
    It works fine as is with MM, CC, GMM and SM protocols.
    For GSM RR signalling, the length of the L2 pseudo-length header (1 byte)
    needs to be passed as parameter "L2_length_incl" to retrieve correctly 
    the protocol discriminator and message type.
    E.g. for messages passed over GSM BCCH or CCCH: L2_length_incl=1
    
    parse_L3(string_buffer, L2_length_incl=0) -> Layer3 instance
    '''
    # select message from PD and Type
    if len(buf) < 2:
        log(ERR, '(parse_L3) message too short for L3 mobile')
        return RawLayer(buf)
    #
    ###
    # Protocol Discriminator
    ###
    # protocol discriminator is 4 last bits (LSB) of 1st byte
    PD = ord(buf[L2_length_incl]) & 0x0F
    #
    ###
    # Message Type
    ###
    # for MM, CC, SS and GSM RR, only 6 1st bits for the message type
    if PD in (3, 5, 6, 11):
        Type = ord(buf[L2_length_incl + 1]) & 0x3F
    #
    # for LTE NAS messages: message content (including Type) can be ciphered
    # (the security processing is available in the Layer3NAS class)
    # EMM header has a security header
    elif PD == 7:
        # check Security Header
        SH = ord(buf[L2_length_incl]) >> 4
        # no security:
        if SH == 0:
            Type = ord(buf[1])
        # integrity protection only:
        elif SH in (1, 3):
            if len(buf) < 8:
                Type = None
            Type = ord(buf[7])
        # ciphering, hence not possible to know the payload Type
        elif SH in (2, 4):
            Type = None
        elif SH == 12 and len(buf) >= 4:
            # LTE NAS service request
            l3 = SERVICE_REQUEST()
            l3.map(buf)
            return l3
        else:
            log(WNG, '(parse_L3) unknown NAS EMM security header: %i' % SH)
            Type = None
    #
    # ESM header has bearer ID in the 4 MSB of 1st byte
    # and Transaction ID between PD and Type
    elif PD == 2:
        if len(buf) < 3:
            Type = None
        Type = ord(buf[2])
    #
    # for other 2G and 3G core protocols (GMM, SM, SMS, ...), nothing special
    else:
        Type = ord(buf[L2_length_incl + 1])
    #
    if PD not in L3Call:
        if PD not in PD_dict:
            log(ERR, '(parse_L3) unknown L3 protocol discriminator: %i' % PD)
        else:
            log(WNG, '(parse_L3) L3 protocol %s not implemented' % PD_dict[PD])
        l3 = RawL3()
        l3.map(buf)
    #
    # get the right type from Type
    elif Type not in L3Call[PD] and Type is not None:
        log(ERR, '(parse_L3) L3 message type %i undefined for protocol %s' \
              % (Type, PD_dict[PD]))
        l3 = RawL3()
        l3.map(buf)
        # for L3GSM_RR, still use the msg type dict:
        # because GSM RR are not all implemented
        if PD == 6:
            l3.Type.Dict = GSM_RR_dict
    #
    # select the correct L3 signalling message
    else:
        # for LTE NAS, if ciphered
        #log(DBG, '(parse_L3) PD %i, Type %i' % (PD, Type))
        if Type is None:
            l3 = Layer3NAS(with_security=True)
        else:
            l3 = L3Call[PD][Type]()
        #
        try:
            #log(DBG, '(parse_L3) mapping ?')
            l3.map(buf)
            #log(DBG, '(parse_L3) mapped correctly')
        except:
            log(ERR, '(parse_L3) mapping buffer on L3 message failed')
            l3 = RawL3()
            l3.map(buf)
    #
    return l3
Example #37
0
def test_regr(print_infos=True):
    '''
    L3GSM_RR and L3Mobile_* regression testing:
    checking all signalling messages from the L3Call dictionnary
    '''
    # libmich settings
    e_safe = Element.safe
    l_safe = Layer.safe
    Element.safe = True
    Layer.safe = True
    Element.dbg = ERR
    Layer.dbg = ERR
    #
    glob_errors = 0
    #
    def test_dict():
        e = 0
        for pd in L3Call:
            for msg in L3Call[pd]:
                error = ''
                cl = L3Call[pd][msg]
                if not issubclass(cl, Layer3):
                    log(WNG, 'message %s not subclass of Layer3' % repr(cl))
                else:
                    try:
                        m = cl(with_options=True)
                    except:
                        error = '__init__(with_options=True)'
                    else:
                        try: 
                            buf = str(m)
                        except:
                            error = '__str__()'
                        else:
                            try:
                                m2 = cl(with_options=False)
                                m2.parse(buf)
                            except:
                                error = 'parse()'
                            else:
                                if str(m2) != buf:
                                    error = '__str__() result discrepancy ' + \
                                            ' with parse()d buffer'
                    if error:
                        log(ERR, 'message %s test returns error: %s' \
                                 % (repr(cl), error))
                        e += 1
        return e
    #
    Layer3._initiator = 'Net'
    if print_infos:
        log(DBG, 'testing with Net initiator')
    glob_errors += test_dict()
    Layer3._initiator = 'ME'
    if print_infos:
        log(DBG, 'testing with ME initiator')
    glob_errors += test_dict()
    #
    Element.safe = e_safe
    Layer.safe = l_safe
    #
    if not glob_errors and print_infos:
        log(DBG, '[Heeeeha!!!] all L3Mobile tests passed successfully')
    return glob_errors 
#
#
Example #38
0
 def unprotect(self, key_int=16*'\0', key_enc=16*'\0', dir=0):
     ret = self.verify_mac(key_int, dir)
     if not ret:
         log(WNG, 'Layer3NAS - unprotect: MAC verificaion failed')
     self.decipher(key_enc, dir)