def retrieve_get_data_items(connection): item_tags = [ (0x1F, 0xFF), # APP MENU OPTIONS (0xFF, 0x20), (0x9F, 0x36), # ATC (0x9F, 0x13), # last online ATC register (0x9F, 0x17), # pin try counter (0x9F, 0x4F) # log format ] tlvs = [] for (p1, p2) in item_tags: tag = '%00X' % p1 + '%00X' % p2 ret_data, sw1, sw2 = select_and_requery(connection=connection, cla=GET_DATA.cla, ins=GET_DATA.ins, p1=p1, p2=p2, le=0x00) if (len(ret_data) == 0): logging.info('%s - sw1:sw2 = %s:%s' % (tag, '%00X' % sw1, '%00X' % sw2)) continue tlv = tlv_utils.parse_tlv(ret_data, known_tags=tag_meanings.emv_tags.keys()) tlvs.append(tlv) return tlvs
def retrieve_get_data_items(connection): item_tags = [ (0x1F, 0xFF), # APP MENU OPTIONS (0xFF, 0x20), (0x9F, 0x36), # ATC (0x9F, 0x13), # last online ATC register (0x9F, 0x17), # pin try counter (0x9F, 0x4F) # log format ] tlvs = [] for (p1, p2) in item_tags: tag = '%00X' % p1 + '%00X' % p2 ret_data, sw1, sw2 = select_and_requery(connection=connection, cla=GET_DATA.cla, ins=GET_DATA.ins, p1=p1, p2=p2, le=0x00) if (len(ret_data) == 0): # logging.info('%s - sw1:sw2 = %s:%s' % (tag, '%00X' % sw1, '%00X' % sw2)) continue tlv = tlv_utils.parse_tlv(ret_data, known_tags=tag_meanings.emv_tags.keys()) tlvs.append(tlv) return tlvs
def select_application_by_aid(connection, aid): ret_data, sw1, sw2 = select_and_requery(connection=connection, cla=SELECT.cla, ins=SELECT.ins, p1=0x04, p2=0x00, data=aid, le=0x00) if (len(ret_data) == 0): return None if DO_LOG: logging.info('\n' + 'SELECT (A)DF BY DF Name / AID') logging.info('AID = %s' % bit_tools.byte_list_to_hex_string(aid)) for x in report_on_reply(sw1, sw2, ret_data): logging.info(x) # Table 45 (EMV 4.2 Book 1) - FCI Returned by ADF Selection # # FCI Template # 6f 17 8407a0000000041010a50c500a4d617374657243617264 # DF Name = AID # 84 07 a0000000041010 # FCI PROP TEMPLATE # a5 0c 500a4d617374657243617264 # APP LABEL # 50 0a 4d617374657243617264 tlv_tree = tlv_utils.parse_tlv(ret_data, known_tags=tag_meanings.emv_tags.keys()) if DO_LOG: logging.info('') for line in tlv_tree.report(): logging.info(line) return tlv_tree
def get_application_ids_from_pse_elementary_dir_file_for_sfi(connection, sfi): ''' returns aids = list of aids ''' aids = [] # READ RECORD, PASSING IN SFI RETURNED BY PSE SELECTION record_number = 0x01 # REFERENCE CONTROL PARAMETER # LSB3 => P1 is a Record Number # 5 high order bits used to encode SFI ref_control_param = (0x04 | (sfi << 3)) ret_data, sw1, sw2 = select_and_requery(connection=connection, cla=READ_RECORD.cla, ins=READ_RECORD.ins, p1=record_number, p2=ref_control_param, le=0x00) # if DO_LOG: # logging.info('\n' + 'READ RECORD [PASSING IN SHORT FILE IDENTIFIER = SFI]') # for x in report_on_reply(sw1, sw2, ret_data): # logging.info(x) # # 70 1a 61 18 4f 07 a0 00 00 00 04 10 10 50 0a 4d 61 73 74 65 72 43 61 72 64 87 01 01 # 70 = [Payment System] Directory # 70 1a 61184f07a0000000041010500a4d617374657243617264870101 # 61 = Directory Entry = ADF or DDF # 61 18 4f07a0000000041010500a4d617374657243617264870101 # 4f = ADF Name = App ID = AID # 4f 07 a0000000041010 # 50 = Application Label # 50 0a 4d617374657243617264 [= MasterCard] # 87 = Application Priority Indicator # 87 01 01 tlv_tree = tlv_utils.parse_tlv(ret_data, known_tags=tag_meanings.emv_tags.keys()) # # if DO_LOG: # logging.info('') # for line in tlv_tree.report(): # logging.info(line) # nodes = tlv_tree.get_nodes_for_qtag('70.61.4F') for node in nodes: aids.append(node.value_byte_list) # TAG 79 => ISO 7816-6, and is part of EMV spec = Nedbank American Express return aids
def get_application_ids_from_pse_elementary_dir_file_for_sfi(connection, sfi): ''' returns aids = list of aids ''' aids = [] # READ RECORD, PASSING IN SFI RETURNED BY PSE SELECTION record_number = 0x01 # REFERENCE CONTROL PARAMETER # LSB3 => P1 is a Record Number # 5 high order bits used to encode SFI ref_control_param = (0x04 | (sfi << 3)) ret_data, sw1, sw2 = select_and_requery(connection=connection, cla=READ_RECORD.cla, ins=READ_RECORD.ins, p1=record_number, p2=ref_control_param, le=0x00) if DO_LOG: logging.info('\n' + 'READ RECORD [PASSING IN SHORT FILE IDENTIFIER = SFI]') for x in report_on_reply(sw1, sw2, ret_data): logging.info(x) # 70 1a 61 18 4f 07 a0 00 00 00 04 10 10 50 0a 4d 61 73 74 65 72 43 61 72 64 87 01 01 # 70 = [Payment System] Directory # 70 1a 61184f07a0000000041010500a4d617374657243617264870101 # 61 = Directory Entry = ADF or DDF # 61 18 4f07a0000000041010500a4d617374657243617264870101 # 4f = ADF Name = App ID = AID # 4f 07 a0000000041010 # 50 = Application Label # 50 0a 4d617374657243617264 [= MasterCard] # 87 = Application Priority Indicator # 87 01 01 tlv_tree = tlv_utils.parse_tlv(ret_data, known_tags=tag_meanings.emv_tags.keys()) if DO_LOG: logging.info('') for line in tlv_tree.report(): logging.info(line) nodes = tlv_tree.get_nodes_for_qtag('70.61.4F') for node in nodes: aids.append(node.value_byte_list) # TAG 79 => ISO 7816-6, and is part of EMV spec = Nedbank American Express return aids
def read_record_for_sfi(connection, sfi, record_number): ''' returns tlv_tree or None ''' global cardnumber tlv_tree = None ref_control_param = (sfi << 3) | 0x04 ret_data, sw1, sw2 = select_and_requery(connection=connection, cla=READ_RECORD.cla, ins=READ_RECORD.ins, p1=record_number, p2=ref_control_param, le=0x00) # if DO_LOG: # logging.info('\n' + 'READ RECORD') # for x in report_on_reply(sw1, sw2, ret_data): # logging.info(x) tlv_tree = tlv_utils.parse_tlv(ret_data, known_tags=tag_meanings.emv_tags.keys()) # if DO_LOG: ## logging.info('') for line in tlv_tree.report(): if line[0] == '7' and line[1] == '0' and line[2] == '.' and line[ 3] == '5' and line[4] == 'A': # h="h: " # a = line.find(h) # logging.info(a) line = line[90:113] line = line.replace('.', '') cardnumber = line # retcardnum(cardnumber) logging.info(line) break
def read_record_for_sfi(connection, sfi, record_number): ''' returns tlv_tree or None ''' tlv_tree = None ref_control_param = (sfi << 3) | 0x04 ret_data, sw1, sw2 = select_and_requery(connection=connection, cla=READ_RECORD.cla, ins=READ_RECORD.ins, p1=record_number, p2=ref_control_param, le=0x00) if DO_LOG: logging.info('\n' + 'READ RECORD') for x in report_on_reply(sw1, sw2, ret_data): logging.info(x) tlv_tree = tlv_utils.parse_tlv(ret_data, known_tags=tag_meanings.emv_tags.keys()) if DO_LOG: logging.info('') for line in tlv_tree.report(): logging.info(line) # PARSE DOL FIELDS for tag_str in tlv_tree.distinct_tag_list(): if (tag_str in tag_meanings.DOL_TAGS): node = tlv_tree.get_nodes_for_tag(tag_str)[0] dol_info, repeated_tag_counts = tlv_utils.parse_concatted_dol_list(node.value_byte_list) if DO_LOG: s = 'DOL List: %s - %s' % (tag_str, tag_meanings.emv_tags[tag_str]) logging.info('-'*len(s)) logging.info(s) logging.info('-'*len(s)) for dol_tag in dol_info.keys(): logging.info('%s - %s - 0x%00X' % (dol_tag, tag_meanings.emv_tags[dol_tag], dol_info[dol_tag])) return tlv_tree
def get_pse_sfi(connection): ''' attempt to retrieve SFI (Short File Identifier) of the Directory Elementary File of PSE (Payment System Environment) SUCCESS returns (sfi, tlv_tree, report) FAILURE returns (None, error_message) refer STRUCTURE OF THE PSE = 12.2.2 APPLICATION SELECTION = EMV 4.2 Book 1 12 - page 135 / 151 ''' report = [] # 3rd LSB bit-flag set => select by name ref_control_param = 0x04 # 00 => first-or-only-occurrence # 02 => next occurrence select_options = 0x00 data = [ord(c) for c in PSE_DDF_NAME] ret_data, sw1, sw2 = select_and_requery(connection=connection, cla=SELECT.cla, ins=SELECT.ins, p1=ref_control_param, p2=select_options, data=data, le=0x00) select_pse_error_tags = { '6A81' : 'card blocked, or select command not supported', '6A82' : 'no PSE / file not found', '6283' : 'PSE is blocked', } report.append('Attempting to Select PSE') report.append('DIRECTORY DEFINITION FILE = 1PAY.SYS.DDF01') for x in report_on_reply(sw1, sw2, ret_data): report.append(x) hex = '%00X%00X' % (sw1, sw2) # NO PSE if hex in select_pse_error_tags: report.append('Error - %s' % select_pse_error_tags[hex]) # PSE FOUND else: # EMV 4.2 Book 1 - 11.3 Select Command-Response APDUs, Table 44 # FCI Template returned by successful selection of a DDF # Response = 6f 19 84 0e 31 50 41 59 2e 53 59 53 2e 44 44 46 30 31 a5 07 88 01 01 9f 11 01 01 # FCI Template # 6f 19 840e315041592e5359532e4444463031a5078801019f110101 (length = 50) # DF Name # 84 0e 315041592e5359532e4444463031 # FCI Proprietary Template # a5 07 8801019f110101 # SFI of the Directory Elementary File # 88 01 01 # Issuer Code Table Index # 9f11 01 01 tlv_tree = tlv_utils.parse_tlv(ret_data, known_tags=tag_meanings.emv_tags.keys()) report.append('') for line in tlv_tree.report(): report.append(line) # '88':'Short File Identifier (SFI)', node = tlv_tree.get_nodes_for_qtag('6F.A5.88')[0] sfi = node.value_byte_list[0] report.append('SFI for PSE - %s' % bit_tools.byte_list_to_hex_string([sfi])) return (sfi, tlv_tree, report) return (None, select_pse_error_tags[hex], report)
def get_afl_aip_via_processing_options(connection, pdol=None): ''' return afl or None EMV 4.2 Book 3 - 6.5.8, 6.5.8.4 - App Interchange Profile - Appp File Locator EMV 4.2 Book 3 5.4 = Data Object List - DOL ---------------------------------------------------------------------------------------------- [ EMV 4.2 Book 3 - Application Specification - 10.1 Initiate Application Processing ] The PDOL is a list of tags and lengths of terminal-resident data elements needed by the ICC in processing the GET PROCESSING OPTIONS command. Only data elements having the terminal as the source of the data may be referenced in the PDOL. If the PDOL does not exist, the GET PROCESSING OPTIONS command uses a command data field of '8300', indicating that the length of the value field in the command data is zero. There may be some exceptions in the timing for this. For example, these bits could be set to 0 at the completion of the previous transaction or prior to application selection of this transaction. The intent here is that the processing steps as described in the Application Specification presume the bits have been initialised to 0. If the PDOL exists, the terminal extracts the PDOL from the FCI of the ADF and uses it to create a concatenated list of data elements without tags or lengths. The rules specified in section 5.4 apply to processing of the PDOL. If an amount field (either Amount, Authorised or Amount, Other) is referenced in the PDOL and the terminal is unable to provide the amount at this point in transaction processing, the amount field in the data element list shall be filled with hexadecimal zeroes. The terminal issues the GET PROCESSING OPTIONS command using either the command data field of '8300' (if there was no PDOL in the ICC) or a data object constructed with a tag of '83' and the appropriate length according to BER-TLV encoding rules and a value field that is the concatenated list of data elements resulting from processing the PDOL. The card returns either: - The Application Interchange Profile the Application File Locator (identifying the files and records containing the data to be used for the transaction), and status SW1 SW2 = '9000', or - Status SW1 SW2 = '6985' (Conditions of use not satisfied), indicating that the transaction cannot be performed with this application. The format of the response message is given in section 6.5.8. If the status words '6985' are returned, the terminal shall eliminate the current application from consideration and return to the Application Selection function to select another application. ''' # APDU = GET PROCESSING OPTIONS data = default_dol = [0x83, 0x00] # tag = 83, length = 0 if (pdol != None): data = [0x83] concatted = [] tags_with_length = tlv_utils.parse_concatted_dol_list_to_ordered_list_of_tag_and_length(pdol) for (tag, tag_length) in tags_with_length: # TERMINAL COUNTRY CODE if (tag == '9F1A'): terminal_country_code_ZAR = [0x07, 0x10] concatted.extend(terminal_country_code_ZAR) # '81':'Amount Authorised (Binary)', # '9F02':'Amount Authorised (Numeric)', # '9F03':'Amount Other (Numeric)', # '9F04':'Amount Other (Binary)', elif (tag in ['81', '9F02', '9F03', '9F04']): for i in range(tag_length): concatted.append(0x00) else: msg = '! Unknown PDOL Tag %s' % tag logging.info(msg) raise Exception(msg) data.append(len(concatted)) data.extend(concatted) ret_data, sw1, sw2 = select_and_requery(connection=connection, cla=GET_PROCESSING_OPTIONS.cla, ins=GET_PROCESSING_OPTIONS.ins, p1=0x00, p2=0x00, data=data, le=0x00) if DO_LOG: logging.info('\n' + 'GET PROCESSING OPTIONS - REQUEST PDOL') for x in report_on_reply(sw1, sw2, ret_data): logging.info(x) # 0x77 0x16 0x82 0x02 0x38 0x00 0x94 0x10 0x08 0x01 0x02 0x00 0x10 0x01 0x02 0x00 0x18 0x01 0x02 0x01 0x20 0x01 0x02 0x00 # 77 = Format 2 Type Response # 77 16 82023800941008010200100102001801020120010200 # 82 = AIP = Application Interchange Profile # 82 02 3800 # 94 = AFL = Application File Locator # 94 10 08010200100102001801020120010200 # # AFL = 08 01 02 00 # 10 01 02 00 # 18 01 02 01 # 20 01 02 00 # SFI 1st Last OMA-Involved # 08 = 8 => 00001000 => 1 01 02 00 # 10 = 16 => 00010000 => 2 01 02 00 # 18 = 24 => 00011000 => 3 01 02 01 # 20 = 32 => 00100000 => 4 01 02 00 get_proc_options_format_1_tags = ['80'] get_proc_options_format_2_tags = ['77', '82', '94'] combined_tags = [] combined_tags.extend(get_proc_options_format_1_tags) combined_tags.extend(get_proc_options_format_2_tags) ''' hex_string = bit_tools.byte_list_to_hex_string(ret_data) file = open('c:/dev/logs/pdol.txt', 'w') file.write(hex_string + '\n') file.close() ''' tlv_tree = tlv_utils.parse_tlv(ret_data, known_tags=combined_tags) afl = None # FORMAT 1 - Visa if (get_proc_options_format_1_tags[0] in tlv_tree.distinct_tag_list()): node = tlv_tree.get_nodes_for_qtag('80')[0] aip_afl = node.value_byte_list aip_length = 2 aip = aip_afl[0:aip_length] afl = aip_afl[aip_length:] if DO_LOG: logging.info('AIP_AFL = ' + '.'.join(['%02X' % b for b in aip_afl])) logging.info('AIP = ' + '.'.join(['%02X' % b for b in aip])) logging.info('AFL = ' + '.'.join(['%02X' % b for b in afl])) # FORMAT 2 - MasterCard else: node = tlv_tree.get_nodes_for_qtag('77.94')[0] afl = node.value_byte_list node = tlv_tree.get_nodes_for_qtag('77.82')[0] aip = node.value_byte_list if DO_LOG: logging.info('') for line in tlv_tree.report(): logging.info(line) return afl, aip
def get_pse_sfi(connection): ''' attempt to retrieve SFI (Short File Identifier) of the Directory Elementary File of PSE (Payment System Environment) SUCCESS returns (sfi, tlv_tree, report) FAILURE returns (None, error_message) refer STRUCTURE OF THE PSE = 12.2.2 APPLICATION SELECTION = EMV 4.2 Book 1 12 - page 135 / 151 ''' report = [] # 3rd LSB bit-flag set => select by name ref_control_param = 0x04 # 00 => first-or-only-occurrence # 02 => next occurrence select_options = 0x00 data = [ord(c) for c in PSE_DDF_NAME] ret_data, sw1, sw2 = select_and_requery(connection=connection, cla=SELECT.cla, ins=SELECT.ins, p1=ref_control_param, p2=select_options, data=data, le=0x00) select_pse_error_tags = { '6A81': 'card blocked, or select command not supported', '6A82': 'no PSE / file not found', '6283': 'PSE is blocked', } report.append('Attempting to Select PSE') report.append('DIRECTORY DEFINITION FILE = 1PAY.SYS.DDF01') for x in report_on_reply(sw1, sw2, ret_data): report.append(x) hex = '%00X%00X' % (sw1, sw2) # NO PSE if hex in select_pse_error_tags: report.append('Error - %s' % select_pse_error_tags[hex]) # PSE FOUND else: # EMV 4.2 Book 1 - 11.3 Select Command-Response APDUs, Table 44 # FCI Template returned by successful selection of a DDF # Response = 6f 19 84 0e 31 50 41 59 2e 53 59 53 2e 44 44 46 30 31 a5 07 88 01 01 9f 11 01 01 # FCI Template # 6f 19 840e315041592e5359532e4444463031a5078801019f110101 (length = 50) # DF Name # 84 0e 315041592e5359532e4444463031 # FCI Proprietary Template # a5 07 8801019f110101 # SFI of the Directory Elementary File # 88 01 01 # Issuer Code Table Index # 9f11 01 01 tlv_tree = tlv_utils.parse_tlv(ret_data, known_tags=tag_meanings.emv_tags.keys()) report.append('') for line in tlv_tree.report(): report.append(line) # '88':'Short File Identifier (SFI)', node = tlv_tree.get_nodes_for_qtag('6F.A5.88')[0] sfi = node.value_byte_list[0] report.append('SFI for PSE - %s' % bit_tools.byte_list_to_hex_string([sfi])) return (sfi, tlv_tree, report) return (None, select_pse_error_tags[hex], report)
def get_afl_aip_via_processing_options(connection, pdol=None): ''' return afl or None EMV 4.2 Book 3 - 6.5.8, 6.5.8.4 - App Interchange Profile - Appp File Locator EMV 4.2 Book 3 5.4 = Data Object List - DOL ---------------------------------------------------------------------------------------------- [ EMV 4.2 Book 3 - Application Specification - 10.1 Initiate Application Processing ] The PDOL is a list of tags and lengths of terminal-resident data elements needed by the ICC in processing the GET PROCESSING OPTIONS command. Only data elements having the terminal as the source of the data may be referenced in the PDOL. If the PDOL does not exist, the GET PROCESSING OPTIONS command uses a command data field of '8300', indicating that the length of the value field in the command data is zero. There may be some exceptions in the timing for this. For example, these bits could be set to 0 at the completion of the previous transaction or prior to application selection of this transaction. The intent here is that the processing steps as described in the Application Specification presume the bits have been initialised to 0. If the PDOL exists, the terminal extracts the PDOL from the FCI of the ADF and uses it to create a concatenated list of data elements without tags or lengths. The rules specified in section 5.4 apply to processing of the PDOL. If an amount field (either Amount, Authorised or Amount, Other) is referenced in the PDOL and the terminal is unable to provide the amount at this point in transaction processing, the amount field in the data element list shall be filled with hexadecimal zeroes. The terminal issues the GET PROCESSING OPTIONS command using either the command data field of '8300' (if there was no PDOL in the ICC) or a data object constructed with a tag of '83' and the appropriate length according to BER-TLV encoding rules and a value field that is the concatenated list of data elements resulting from processing the PDOL. The card returns either: - The Application Interchange Profile the Application File Locator (identifying the files and records containing the data to be used for the transaction), and status SW1 SW2 = '9000', or - Status SW1 SW2 = '6985' (Conditions of use not satisfied), indicating that the transaction cannot be performed with this application. The format of the response message is given in section 6.5.8. If the status words '6985' are returned, the terminal shall eliminate the current application from consideration and return to the Application Selection function to select another application. ''' # APDU = GET PROCESSING OPTIONS data = default_dol = [0x83, 0x00] # tag = 83, length = 0 if (pdol != None): data = [0x83] concatted = [] tags_with_length = tlv_utils.parse_concatted_dol_list_to_ordered_list_of_tag_and_length( pdol) for (tag, tag_length) in tags_with_length: # TERMINAL COUNTRY CODE if (tag == '9F1A'): terminal_country_code_ZAR = [0x07, 0x10] concatted.extend(terminal_country_code_ZAR) # '81':'Amount Authorised (Binary)', # '9F02':'Amount Authorised (Numeric)', # '9F03':'Amount Other (Numeric)', # '9F04':'Amount Other (Binary)', elif (tag in ['81', '9F02', '9F03', '9F04']): for i in range(tag_length): concatted.append(0x00) else: msg = '! Unknown PDOL Tag %s' % tag logging.info(msg) raise Exception(msg) data.append(len(concatted)) data.extend(concatted) ret_data, sw1, sw2 = select_and_requery(connection=connection, cla=GET_PROCESSING_OPTIONS.cla, ins=GET_PROCESSING_OPTIONS.ins, p1=0x00, p2=0x00, data=data, le=0x00) # if DO_LOG: # logging.info('\n' + 'GET PROCESSING OPTIONS - REQUEST PDOL') # for x in report_on_reply(sw1, sw2, ret_data): # logging.info(x) # 0x77 0x16 0x82 0x02 0x38 0x00 0x94 0x10 0x08 0x01 0x02 0x00 0x10 0x01 0x02 0x00 0x18 0x01 0x02 0x01 0x20 0x01 0x02 0x00 # 77 = Format 2 Type Response # 77 16 82023800941008010200100102001801020120010200 # 82 = AIP = Application Interchange Profile # 82 02 3800 # 94 = AFL = Application File Locator # 94 10 08010200100102001801020120010200 # # AFL = 08 01 02 00 # 10 01 02 00 # 18 01 02 01 # 20 01 02 00 # SFI 1st Last OMA-Involved # 08 = 8 => 00001000 => 1 01 02 00 # 10 = 16 => 00010000 => 2 01 02 00 # 18 = 24 => 00011000 => 3 01 02 01 # 20 = 32 => 00100000 => 4 01 02 00 get_proc_options_format_1_tags = ['80'] get_proc_options_format_2_tags = ['77', '82', '94'] combined_tags = [] combined_tags.extend(get_proc_options_format_1_tags) combined_tags.extend(get_proc_options_format_2_tags) ''' hex_string = bit_tools.byte_list_to_hex_string(ret_data) file = open('c:/dev/logs/pdol.txt', 'w') file.write(hex_string + '\n') file.close() ''' tlv_tree = tlv_utils.parse_tlv(ret_data, known_tags=combined_tags) afl = None # FORMAT 1 - Visa if (get_proc_options_format_1_tags[0] in tlv_tree.distinct_tag_list()): node = tlv_tree.get_nodes_for_qtag('80')[0] aip_afl = node.value_byte_list aip_length = 2 aip = aip_afl[0:aip_length] afl = aip_afl[aip_length:] # if DO_LOG: # logging.info('AIP_AFL = ' + '.'.join(['%02X' % b for b in aip_afl])) # logging.info('AIP = ' + '.'.join(['%02X' % b for b in aip])) # logging.info('AFL = ' + '.'.join(['%02X' % b for b in afl])) # FORMAT 2 - MasterCard else: node = tlv_tree.get_nodes_for_qtag('77.94')[0] afl = node.value_byte_list node = tlv_tree.get_nodes_for_qtag('77.82')[0] aip = node.value_byte_list # if DO_LOG: # logging.info('') # for line in tlv_tree.report(): # logging.info(line) # return afl, aip