#include <stdio.h> // perror, printf, fprintf, snprintf #include <stdlib.h> // exit, free #include <string.h> // memset, strncpy #include "conf2uedata.h" #include "user_api.h" #include "utils.h" char * make_filename(const char *output_dir, const char *filename, int ueid); int get_config_from_file(const char *filename, config_t *config); int main(int argc, char**argv) { int rc = EXIT_SUCCESS; int option; const char* conf_file = NULL; while ((option = getopt(argc, argv, options)) != -1) { switch (option) { case 'c': parse_data = TRUE; conf_file = optarg; break; case 'o': output_dir = optarg; output = TRUE; break; case 'h': _display_usage(); return EXIT_SUCCESS; break; default: break; } } if (output == FALSE && parse_data == TRUE) { printf("No output option found\n"); _display_usage(); return EXIT_FAILURE; } if (output == TRUE && parse_data == FALSE) { printf("No Configuration file is given\n"); _display_usage(); return EXIT_FAILURE; } if (parse_data == FALSE && print_data == FALSE) { printf("No options found\n"); _display_usage(); return EXIT_FAILURE; } if (parse_data) { int ret; int ue_nb = 0; config_setting_t *root_setting = NULL; config_setting_t *ue_setting = NULL; config_setting_t *all_plmn_setting = NULL; char user[10]; config_t cfg; ret = get_config_from_file(conf_file, &cfg); if (ret == EXIT_FAILURE) { exit(1); } root_setting = config_root_setting(&cfg); ue_nb = config_setting_length(root_setting) - 1; all_plmn_setting = config_setting_get_member(root_setting, PLMN); if (all_plmn_setting == NULL) { printf("NO PLMN SECTION...EXITING...\n"); return (EXIT_FAILURE); } rc = parse_plmns(all_plmn_setting); if (rc == EXIT_FAILURE) { return rc; } fill_network_record_list(); for (int i = 0; i < ue_nb; i++) { sprintf(user, "%s%d", UE, i); ue_setting = config_setting_get_member(root_setting, user); if (ue_setting == NULL) { printf("Check UE%d settings\n", i); return EXIT_FAILURE; } rc = parse_ue_user_param(ue_setting, i); if (rc != EXIT_SUCCESS) { printf("Problem in USER section for UE%d. EXITING...\n", i); return EXIT_FAILURE; } _display_ue_data(i); rc = parse_ue_sim_param(ue_setting, i); if (rc != EXIT_SUCCESS) { printf("Problem in SIM section for UE%d. EXITING...\n", i); return EXIT_FAILURE; } rc = parse_ue_plmn_param(ue_setting, i); if (rc != EXIT_SUCCESS) { return EXIT_FAILURE; } gen_emm_data(i); _display_emm_data(i); gen_usim_data(i); _display_usim_data(i); } config_destroy(&cfg); } exit(EXIT_SUCCESS); } int get_config_from_file(const char *filename, config_t *config) { config_init(config); if (filename == NULL) { // XXX write error message ? exit(EXIT_FAILURE); } /* Read the file. If there is an error, report it and exit. */ if (!config_read_file(config, filename)) { fprintf(stderr, "Cant read config file '%s': %s\n", filename, config_error_text(config)); if ( config_error_type(config) == CONFIG_ERR_PARSE ) { fprintf(stderr, "This is line %d\n", config_error_line(config)); } config_destroy(config); return (EXIT_FAILURE); } return EXIT_SUCCESS; } void gen_usim_data(int user_id) { usim_data_t usim_data = { }; memset(&usim_data, 0, sizeof(usim_data_t)); usim_data.imsi.length = 8; usim_data.imsi.u.num.parity = get_msin_parity(msin); usim_data.imsi.u.num.digit1 = user_plmn_list[hplmn_index].mcc[0]; usim_data.imsi.u.num.digit2 = user_plmn_list[hplmn_index].mcc[1]; usim_data.imsi.u.num.digit3 = user_plmn_list[hplmn_index].mcc[2]; usim_data.imsi.u.num.digit4 = user_plmn_list[hplmn_index].mnc[0]; usim_data.imsi.u.num.digit5 = user_plmn_list[hplmn_index].mnc[1]; if (strlen(user_plmn_list[hplmn_index].mnc) == 2) { usim_data.imsi.u.num.digit6 = msin[0]; usim_data.imsi.u.num.digit7 = msin[1]; usim_data.imsi.u.num.digit8 = msin[2]; usim_data.imsi.u.num.digit9 = msin[3]; usim_data.imsi.u.num.digit10 = msin[4]; usim_data.imsi.u.num.digit11 = msin[5]; usim_data.imsi.u.num.digit12 = msin[6]; usim_data.imsi.u.num.digit13 = msin[7]; usim_data.imsi.u.num.digit14 = msin[8]; usim_data.imsi.u.num.digit15 = msin[9]; } else { usim_data.imsi.u.num.digit6 = user_plmn_list[hplmn_index].mnc[2]; usim_data.imsi.u.num.digit7 = msin[0]; usim_data.imsi.u.num.digit8 = msin[1]; usim_data.imsi.u.num.digit9 = msin[2]; usim_data.imsi.u.num.digit10 = msin[3]; usim_data.imsi.u.num.digit11 = msin[4]; usim_data.imsi.u.num.digit12 = msin[5]; usim_data.imsi.u.num.digit13 = msin[6]; usim_data.imsi.u.num.digit14 = msin[7]; usim_data.imsi.u.num.digit15 = msin[8]; } /* * Ciphering and Integrity Keys */ usim_data.keys.ksi = KSI; memset(&usim_data.keys.ck, 0, USIM_CK_SIZE); memset(&usim_data.keys.ik, 0, USIM_IK_SIZE); /* * Higher Priority PLMN search period */ usim_data.hpplmn = 0x00; /* Disable timer */ /* * List of Forbidden PLMNs */ for (int i = 0; i < USIM_FPLMN_MAX; i++) { memset(&usim_data.fplmn[i], 0xff, sizeof(plmn_t)); } if (fplmn_nb > 0) { for (int i = 0; i < fplmn_nb; i++) { usim_data.fplmn[i] = user_network_record_list[fplmn[i]].plmn; } } /* * Location Information */ usim_data.loci.tmsi = DEFAULT_TMSI; usim_data.loci.lai.plmn = user_network_record_list[hplmn_index].plmn; usim_data.loci.lai.lac = DEFAULT_LAC; usim_data.loci.status = USIM_LOCI_NOT_UPDATED; /* * Packet Switched Location Information */ usim_data.psloci.p_tmsi = DEFAULT_P_TMSI; usim_data.psloci.signature[0] = 0x01; usim_data.psloci.signature[1] = 0x02; usim_data.psloci.signature[2] = 0x03; usim_data.psloci.rai.plmn = user_network_record_list[hplmn_index].plmn; usim_data.psloci.rai.lac = DEFAULT_LAC; usim_data.psloci.rai.rac = DEFAULT_RAC; usim_data.psloci.status = USIM_PSLOCI_NOT_UPDATED; /* * Administrative Data */ usim_data.ad.UE_Operation_Mode = USIM_NORMAL_MODE; usim_data.ad.Additional_Info = 0xffff; usim_data.ad.MNC_Length = strlen(user_plmn_list[hplmn_index].mnc); /* * EPS NAS security context */ usim_data.securityctx.length = 52; usim_data.securityctx.KSIasme.type = USIM_KSI_ASME_TAG; usim_data.securityctx.KSIasme.length = 1; usim_data.securityctx.KSIasme.value[0] = KSI_ASME; usim_data.securityctx.Kasme.type = USIM_K_ASME_TAG; usim_data.securityctx.Kasme.length = USIM_K_ASME_SIZE; memset(usim_data.securityctx.Kasme.value, 0, usim_data.securityctx.Kasme.length); usim_data.securityctx.ulNAScount.type = USIM_UL_NAS_COUNT_TAG; usim_data.securityctx.ulNAScount.length = USIM_UL_NAS_COUNT_SIZE; memset(usim_data.securityctx.ulNAScount.value, 0, usim_data.securityctx.ulNAScount.length); usim_data.securityctx.dlNAScount.type = USIM_DL_NAS_COUNT_TAG; usim_data.securityctx.dlNAScount.length = USIM_DL_NAS_COUNT_SIZE; memset(usim_data.securityctx.dlNAScount.value, 0, usim_data.securityctx.dlNAScount.length); usim_data.securityctx.algorithmID.type = USIM_INT_ENC_ALGORITHMS_TAG; usim_data.securityctx.algorithmID.length = 1; usim_data.securityctx.algorithmID.value[0] = SECURITY_ALGORITHMS; /* * Subcriber's Number */ usim_data.msisdn.length = 7; usim_data.msisdn.number.ext = 1; usim_data.msisdn.number.ton = MSISDN_TON_UNKNOWKN; usim_data.msisdn.number.npi = MSISDN_NPI_ISDN_TELEPHONY; usim_data.msisdn.conf1_record_id = 0xff; /* Not used */ usim_data.msisdn.ext1_record_id = 0xff; /* Not used */ int j = 0; for (int i = 0; i < strlen(msisdn); i += 2) { usim_data.msisdn.number.digit[j].msb = msisdn[i]; j++; } j = 0; for (int i = 1; i < strlen(msisdn); i += 2) { usim_data.msisdn.number.digit[j].lsb = msisdn[i]; j++; } if (strlen(msisdn) % 2 == 0) { for (int i = strlen(msisdn) / 2; i < 10; i++) { usim_data.msisdn.number.digit[i].msb = 0xf; usim_data.msisdn.number.digit[i].lsb = 0xf; } } else { usim_data.msisdn.number.digit[strlen(msisdn) / 2].lsb = 0xf; for (int i = (strlen(msisdn) / 2) + 1; i < 10; i++) { usim_data.msisdn.number.digit[i].msb = 0xf; usim_data.msisdn.number.digit[i].lsb = 0xf; } } /* * PLMN Network Name and Operator PLMN List */ for (int i = 0; i < oplmn_nb; i++) { network_record_t record = user_network_record_list[oplmn[i]]; usim_data.pnn[i].fullname.type = USIM_PNN_FULLNAME_TAG; usim_data.pnn[i].fullname.length = strlen(record.fullname); strncpy((char*) usim_data.pnn[i].fullname.value, record.fullname, usim_data.pnn[i].fullname.length); usim_data.pnn[i].shortname.type = USIM_PNN_SHORTNAME_TAG; usim_data.pnn[i].shortname.length = strlen(record.shortname); strncpy((char*) usim_data.pnn[i].shortname.value, record.shortname, usim_data.pnn[i].shortname.length); usim_data.opl[i].plmn = record.plmn; usim_data.opl[i].start = record.tac_start; usim_data.opl[i].end = record.tac_end; usim_data.opl[i].record_id = i; } if (oplmn_nb < USIM_OPL_MAX) { for (int i = oplmn_nb; i < USIM_OPL_MAX; i++) { memset(&usim_data.opl[i].plmn, 0xff, sizeof(plmn_t)); } } /* * List of Equivalent HPLMNs */ for (int i = 0; i < ehplmn_nb; i++) { usim_data.ehplmn[i] = user_network_record_list[ehplmn[i]].plmn; } if (ehplmn_nb < USIM_EHPLMN_MAX) { for (int i = ehplmn_nb; i < USIM_EHPLMN_MAX; i++) { memset(&usim_data.ehplmn[i], 0xff, sizeof(plmn_t)); } } /* * Home PLMN Selector with Access Technology */ usim_data.hplmn.plmn = user_network_record_list[hplmn_index].plmn; usim_data.hplmn.AcT = (USIM_ACT_GSM | USIM_ACT_UTRAN | USIM_ACT_EUTRAN); /* * List of user controlled PLMN selector with Access Technology */ for (int i = 0; i < USIM_PLMN_MAX; i++) { memset(&usim_data.plmn[i], 0xff, sizeof(plmn_t)); } if (ucplmn_nb > 0) { for (int i = 0; i < ucplmn_nb; i++) { usim_data.plmn[i].plmn = user_network_record_list[ucplmn[i]].plmn; } } // List of operator controlled PLMN selector with Access Technology for (int i = 0; i < USIM_OPLMN_MAX; i++) { memset(&usim_data.oplmn[i], 0xff, sizeof(plmn_t)); } if (ocplmn_nb > 0) { for (int i = 0; i < ocplmn_nb; i++) { usim_data.oplmn[i].plmn = user_network_record_list[ocplmn[i]].plmn; usim_data.oplmn[i].AcT = (USIM_ACT_GSM | USIM_ACT_UTRAN | USIM_ACT_EUTRAN); } } /* * EPS Location Information */ usim_data.epsloci.guti.gummei.plmn = user_network_record_list[hplmn_index].plmn; usim_data.epsloci.guti.gummei.MMEgid = DEFAULT_MME_ID; usim_data.epsloci.guti.gummei.MMEcode = DEFAULT_MME_CODE; usim_data.epsloci.guti.m_tmsi = DEFAULT_M_TMSI; usim_data.epsloci.tai.plmn = usim_data.epsloci.guti.gummei.plmn; usim_data.epsloci.tai.tac = DEFAULT_TAC; usim_data.epsloci.status = USIM_EPSLOCI_UPDATED; /* * Non-Access Stratum configuration */ usim_data.nasconfig.NAS_SignallingPriority.type = USIM_NAS_SIGNALLING_PRIORITY_TAG; usim_data.nasconfig.NAS_SignallingPriority.length = 1; usim_data.nasconfig.NAS_SignallingPriority.value[0] = 0x00; usim_data.nasconfig.NMO_I_Behaviour.type = USIM_NMO_I_BEHAVIOUR_TAG; usim_data.nasconfig.NMO_I_Behaviour.length = 1; usim_data.nasconfig.NMO_I_Behaviour.value[0] = 0x00; usim_data.nasconfig.AttachWithImsi.type = USIM_ATTACH_WITH_IMSI_TAG; usim_data.nasconfig.AttachWithImsi.length = 1; #if defined(START_WITH_GUTI) usim_data.nasconfig.AttachWithImsi.value[0] = 0x00; #else usim_data.nasconfig.AttachWithImsi.value[0] = 0x01; #endif usim_data.nasconfig.MinimumPeriodicSearchTimer.type = USIM_MINIMUM_PERIODIC_SEARCH_TIMER_TAG; usim_data.nasconfig.MinimumPeriodicSearchTimer.length = 1; usim_data.nasconfig.MinimumPeriodicSearchTimer.value[0] = 0x00; usim_data.nasconfig.ExtendedAccessBarring.type = USIM_EXTENDED_ACCESS_BARRING_TAG; usim_data.nasconfig.ExtendedAccessBarring.length = 1; usim_data.nasconfig.ExtendedAccessBarring.value[0] = 0x00; usim_data.nasconfig.Timer_T3245_Behaviour.type = USIM_TIMER_T3245_BEHAVIOUR_TAG; usim_data.nasconfig.Timer_T3245_Behaviour.length = 1; usim_data.nasconfig.Timer_T3245_Behaviour.value[0] = 0x00; /* initialize the subscriber authentication security key */ hex_string_to_hex_value(usim_data.keys.usim_api_k, usim_api_k, USIM_API_K_SIZE); hex_string_to_hex_value(usim_data.keys.opc, opc, OPC_SIZE); char *path = make_filename(output_dir, USIM_API_NVRAM_FILENAME, user_id); usim_api_write(path, &usim_data); free(path); } void gen_emm_data(int user_id) { hplmn_index = get_plmn_index(hplmn); emm_nvdata_t emm_data; int rc; memset(&emm_data, 0, sizeof(emm_nvdata_t)); int hplmn_index = get_plmn_index(hplmn); emm_data.imsi.length = 8; emm_data.imsi.u.num.parity = get_msin_parity(msin); emm_data.imsi.u.num.digit1 = user_plmn_list[hplmn_index].mcc[0]; emm_data.imsi.u.num.digit2 = user_plmn_list[hplmn_index].mcc[1]; emm_data.imsi.u.num.digit3 = user_plmn_list[hplmn_index].mcc[2]; emm_data.imsi.u.num.digit4 = user_plmn_list[hplmn_index].mnc[0]; emm_data.imsi.u.num.digit5 = user_plmn_list[hplmn_index].mnc[1]; if (strlen(user_plmn_list[hplmn_index].mnc) == 3) { emm_data.rplmn.MNCdigit3 = user_plmn_list[hplmn_index].mnc[2]; emm_data.imsi.u.num.digit6 = user_plmn_list[hplmn_index].mnc[2]; emm_data.imsi.u.num.digit7 = msin[0]; emm_data.imsi.u.num.digit8 = msin[1]; emm_data.imsi.u.num.digit9 = msin[2]; emm_data.imsi.u.num.digit10 = msin[3]; emm_data.imsi.u.num.digit11 = msin[4]; emm_data.imsi.u.num.digit12 = msin[5]; emm_data.imsi.u.num.digit13 = msin[6]; emm_data.imsi.u.num.digit14 = msin[7]; emm_data.imsi.u.num.digit15 = msin[8]; } else { emm_data.rplmn.MNCdigit3 = 0xf; emm_data.imsi.u.num.digit6 = msin[0]; emm_data.imsi.u.num.digit7 = msin[1]; emm_data.imsi.u.num.digit8 = msin[2]; emm_data.imsi.u.num.digit9 = msin[3]; emm_data.imsi.u.num.digit10 = msin[4]; emm_data.imsi.u.num.digit11 = msin[5]; emm_data.imsi.u.num.digit12 = msin[6]; emm_data.imsi.u.num.digit13 = msin[7]; emm_data.imsi.u.num.digit14 = msin[8]; emm_data.imsi.u.num.digit15 = msin[9]; } emm_data.rplmn.MCCdigit1 = user_plmn_list[hplmn_index].mcc[0]; emm_data.rplmn.MCCdigit2 = user_plmn_list[hplmn_index].mcc[1]; emm_data.rplmn.MCCdigit3 = user_plmn_list[hplmn_index].mcc[2]; emm_data.rplmn.MNCdigit1 = user_plmn_list[hplmn_index].mnc[0]; emm_data.rplmn.MNCdigit2 = user_plmn_list[hplmn_index].mnc[1]; emm_data.eplmn.n_plmns = ehplmn_nb; char* path = make_filename(output_dir, EMM_NVRAM_FILENAME, user_id); rc = memory_write(path, &emm_data, sizeof(emm_nvdata_t)); free(path); if (rc != RETURNok) { perror("ERROR\t: memory_write() failed"); exit(EXIT_FAILURE); } } int parse_plmn_param(config_setting_t *plmn_setting, int index) { int rc = 0; rc = config_setting_lookup_string(plmn_setting, FULLNAME, &user_plmn_list[index].fullname); if (rc != 1) { printf("Check PLMN%d FULLNAME. Exiting\n", index); return EXIT_FAILURE; } rc = config_setting_lookup_string(plmn_setting, SHORTNAME, &user_plmn_list[index].shortname); if (rc != 1) { printf("Check PLMN%d SHORTNAME. Exiting\n", index); return EXIT_FAILURE; } rc = config_setting_lookup_string(plmn_setting, MNC, &user_plmn_list[index].mnc); if (rc != 1 || strlen(user_plmn_list[index].mnc) > 3 || strlen(user_plmn_list[index].mnc) < 2) { printf("Check PLMN%d MNC. Exiting\n", index); return EXIT_FAILURE; } rc = config_setting_lookup_string(plmn_setting, MCC, &user_plmn_list[index].mcc); if (rc != 1 || strlen(user_plmn_list[index].mcc) != 3) { printf("Check PLMN%d MCC. Exiting\n", index); return EXIT_FAILURE; } return EXIT_SUCCESS; } int parse_plmns(config_setting_t *all_plmn_setting) { config_setting_t *plmn_setting = NULL; char plmn[10]; int rc = EXIT_SUCCESS; plmn_nb = config_setting_length(all_plmn_setting); user_plmn_list = malloc(sizeof(plmn_conf_param_t) * plmn_nb); user_network_record_list = malloc(sizeof(network_record_t) * plmn_nb); for (int i = 0; i < plmn_nb; i++) { memset(&user_network_record_list[i], 0xff, sizeof(network_record_t)); memset(&user_plmn_list[i], 0xff, sizeof(plmn_conf_param_t)); } for (int i = 0; i < plmn_nb; i++) { sprintf(plmn, "%s%d", PLMN, i); plmn_setting = config_setting_get_member(all_plmn_setting, plmn); if (plmn_setting != NULL) { rc = parse_plmn_param(plmn_setting, i); if (rc == EXIT_FAILURE) { return rc; } } else { printf("Problem in PLMN%d. Exiting...\n", i); return EXIT_FAILURE; } } return rc; } int parse_ue_plmn_param(config_setting_t *ue_setting, int user_id) { int rc = EXIT_SUCCESS; config_setting_t *setting = NULL; rc = config_setting_lookup_string(ue_setting, HPLMN, &hplmn); if (rc != 1) { printf("Check HPLMN section for UE%d. Exiting\n", user_id); return EXIT_FAILURE; } else if (get_plmn_index(hplmn) == -1) { printf("HPLMN for UE%d is not defined in PLMN section. Exiting\n", user_id); return EXIT_FAILURE; } setting = config_setting_get_member(ue_setting, UCPLMN); if (setting == NULL) { printf("Check UCPLMN section for UE%d. Exiting\n", user_id); return EXIT_FAILURE; } rc = fill_ucplmn(setting, user_id); if (rc != EXIT_SUCCESS) { printf("Check UCPLMN section for UE%d. Exiting\n", user_id); return EXIT_FAILURE; } setting = config_setting_get_member(ue_setting, OPLMN); if (setting == NULL) { printf("Check OPLMN section for UE%d. Exiting\n", user_id); return EXIT_FAILURE; } rc = fill_oplmn(setting, user_id); if (rc != EXIT_SUCCESS) { printf("Check OPLMN section for UE%d. Exiting\n", user_id); return EXIT_FAILURE; } setting = config_setting_get_member(ue_setting, OCPLMN); if (setting == NULL) { printf("Check OCPLMN section for UE%d. Exiting\n", user_id); return EXIT_FAILURE; } rc = fill_ocplmn(setting, user_id); if (rc != EXIT_SUCCESS) { printf("Check OCPLMN section for UE%d. Exiting\n", user_id); return EXIT_FAILURE; } setting = config_setting_get_member(ue_setting, FPLMN); if (setting == NULL) { printf("Check FPLMN section for UE%d. Exiting\n", user_id); return EXIT_FAILURE; } rc = fill_fplmn(setting, user_id); if (rc != EXIT_SUCCESS) { printf("Check FPLMN section for UE%d. Exiting\n", user_id); return EXIT_FAILURE; } setting = config_setting_get_member(ue_setting, EHPLMN); if (setting == NULL) { printf("Check EHPLMN section for UE%d. Exiting\n", user_id); return EXIT_FAILURE; } rc = fill_ehplmn(setting, user_id); if (rc != EXIT_SUCCESS) { printf("Check EHPLMN section for UE%d. Exiting\n", user_id); return EXIT_FAILURE; } return EXIT_SUCCESS; } int parse_ue_sim_param(config_setting_t *ue_setting, int user_id) { int rc = EXIT_SUCCESS; config_setting_t *ue_param_setting = NULL; ue_param_setting = config_setting_get_member(ue_setting, SIM); if (ue_param_setting == NULL) { printf("Check SIM section for UE%d. EXITING...\n", user_id); return EXIT_FAILURE; } rc = config_setting_lookup_string(ue_param_setting, MSIN, &msin); if (rc != 1 || strlen(msin) > 10 || strlen(msin) < 9) { printf("Check SIM MSIN section for UE%d. Exiting\n", user_id); return EXIT_FAILURE; } rc = config_setting_lookup_string(ue_param_setting, USIM_API_K, &usim_api_k); if (rc != 1) { printf("Check SIM USIM_API_K section for UE%d. Exiting\n", user_id); return EXIT_FAILURE; } rc = config_setting_lookup_string(ue_param_setting, OPC, &opc); if (rc != 1) { printf("Check SIM OPC section for UE%d. Exiting\n", user_id); return EXIT_FAILURE; } rc = config_setting_lookup_string(ue_param_setting, MSISDN, &msisdn); if (rc != 1) { printf("Check SIM MSISDN section for UE%d. Exiting\n", user_id); return EXIT_FAILURE; } return EXIT_SUCCESS; } int parse_ue_user_param(config_setting_t *ue_setting, int user_id) { config_setting_t *ue_param_setting = NULL; user_nvdata_t user_data; const char* imei = NULL; const char* manufacturer = NULL; const char* model = NULL; const char* pin = NULL; int rc = EXIT_SUCCESS; ue_param_setting = config_setting_get_member(ue_setting, USER); if (ue_param_setting == NULL) { printf("Check USER section of UE%d. EXITING...\n", user_id); return EXIT_FAILURE; } rc = config_setting_lookup_string(ue_param_setting, UE_IMEI, &imei); if (rc != 1) { printf("Check USER IMEI section for UE%d. Exiting\n", user_id); return EXIT_FAILURE; } rc = config_setting_lookup_string(ue_param_setting, MANUFACTURER, &manufacturer); if (rc != 1) { printf("Check USER MANUFACTURER for UE%d FULLNAME. Exiting\n", user_id); return EXIT_FAILURE; } rc = config_setting_lookup_string(ue_param_setting, MODEL, &model); if (rc != 1) { printf("Check USER MODEL for UE%d FULLNAME. Exiting\n", user_id); return EXIT_FAILURE; } rc = config_setting_lookup_string(ue_param_setting, PINCODE, &pin); if (rc != 1) { printf("Check USER PIN for UE%d FULLNAME. Exiting\n", user_id); return EXIT_FAILURE; } memset(&user_data, 0, sizeof(user_nvdata_t)); snprintf(user_data.IMEI, USER_IMEI_SIZE + 1, "%s%d", imei, _luhn(imei)); /* * Manufacturer identifier */ strncpy(user_data.manufacturer, manufacturer, USER_MANUFACTURER_SIZE); /* * Model identifier */ strncpy(user_data.model, model, USER_MODEL_SIZE); /* * SIM Personal Identification Number */ strncpy(user_data.PIN, pin, USER_PIN_SIZE); char* path = make_filename(output_dir, USER_NVRAM_FILENAME, user_id); rc = memory_write(path, &user_data, sizeof(user_nvdata_t)); free(path); if (rc != RETURNok) { perror("ERROR\t: memory_write() failed"); exit(EXIT_FAILURE); } return EXIT_SUCCESS; } int fill_ucplmn(config_setting_t* setting, int user_id) { int rc; ucplmn_nb = config_setting_length(setting); ucplmn = malloc(ucplmn_nb * sizeof(int)); for (int i = 0; i < ucplmn_nb; i++) { const char *mccmnc = config_setting_get_string_elem(setting, i); if (mccmnc == NULL) { printf("Check UCPLMN section for UE%d. Exiting\n", user_id); return EXIT_FAILURE; } rc = get_plmn_index(mccmnc); if (rc == -1) { printf("The PLMN %s is not defined in PLMN section. Exiting...\n", mccmnc); return EXIT_FAILURE; } ucplmn[i] = rc; } return EXIT_SUCCESS; } int fill_oplmn(config_setting_t* setting, int user_id) { int rc; oplmn_nb = config_setting_length(setting); oplmn = malloc(oplmn_nb * sizeof(int)); for (int i = 0; i < oplmn_nb; i++) { const char *mccmnc = config_setting_get_string_elem(setting, i); if (mccmnc == NULL) { printf("Check OPLMN section for UE%d. Exiting\n", user_id); return EXIT_FAILURE; } rc = get_plmn_index(mccmnc); if (rc == -1) { printf("The PLMN %s is not defined in PLMN section. Exiting...\n", mccmnc); return EXIT_FAILURE; } oplmn[i] = rc; } return EXIT_SUCCESS; } int fill_ocplmn(config_setting_t* setting, int user_id) { int rc; ocplmn_nb = config_setting_length(setting); ocplmn = malloc(ocplmn_nb * sizeof(int)); for (int i = 0; i < ocplmn_nb; i++) { const char *mccmnc = config_setting_get_string_elem(setting, i); if (mccmnc == NULL) { printf("Check OCPLMN section for UE%d. Exiting\n", user_id); return EXIT_FAILURE; } rc = get_plmn_index(mccmnc); if (rc == -1) { printf("The PLMN %s is not defined in PLMN section. Exiting...\n", mccmnc); return EXIT_FAILURE; } ocplmn[i] = rc; } return EXIT_SUCCESS; } int fill_fplmn(config_setting_t* setting, int user_id) { int rc; fplmn_nb = config_setting_length(setting); fplmn = malloc(fplmn_nb * sizeof(int)); for (int i = 0; i < fplmn_nb; i++) { const char *mccmnc = config_setting_get_string_elem(setting, i); if (mccmnc == NULL) { printf("Check FPLMN section for UE%d. Exiting\n", user_id); return EXIT_FAILURE; } rc = get_plmn_index(mccmnc); if (rc == -1) { printf("The PLMN %s is not defined in PLMN section. Exiting...\n", mccmnc); return EXIT_FAILURE; } fplmn[i] = rc; } return EXIT_SUCCESS; } int fill_ehplmn(config_setting_t* setting, int user_id) { int rc; ehplmn_nb = config_setting_length(setting); ehplmn = malloc(ehplmn_nb * sizeof(int)); for (int i = 0; i < ehplmn_nb; i++) { const char *mccmnc = config_setting_get_string_elem(setting, i); if (mccmnc == NULL) { printf("Check EHPLMN section for UE%d. Exiting\n", user_id); return EXIT_FAILURE; } rc = get_plmn_index(mccmnc); if (rc == -1) { printf("The PLMN %s is not defined in PLMN section. Exiting...\n", mccmnc); return EXIT_FAILURE; } ehplmn[i] = rc; } return EXIT_SUCCESS; } int get_plmn_index(const char * mccmnc) { char mcc[4]; char mnc[strlen(mccmnc) - 2]; strncpy(mcc, mccmnc, 3); mcc[3] = '\0'; strncpy(mnc, mccmnc + 3, 3); mnc[strlen(mccmnc) - 3] = '\0'; for (int i = 0; i < plmn_nb; i++) { if (strcmp(user_plmn_list[i].mcc, mcc) == 0) { if (strcmp(user_plmn_list[i].mnc, mnc) == 0) { return i; } } } return -1; } int get_msin_parity(const char * msin) { int imsi_size = strlen(msin) + strlen(user_plmn_list[hplmn_index].mcc) + strlen(user_plmn_list[hplmn_index].mnc); int result = (imsi_size % 2 == 0) ? 0 : 1; return result; } void fill_network_record_list() { for (int i = 0; i < plmn_nb; i++) { strcpy(user_network_record_list[i].fullname, user_plmn_list[i].fullname); strcpy(user_network_record_list[i].shortname, user_plmn_list[i].shortname); char num[6]; sprintf(num, "%s%s", user_plmn_list[i].mcc, user_plmn_list[i].mnc); user_network_record_list[i].num = atoi(num); user_network_record_list[i].plmn.MCCdigit2 = user_plmn_list[i].mcc[1]; user_network_record_list[i].plmn.MCCdigit1 = user_plmn_list[i].mcc[0]; user_network_record_list[i].plmn.MCCdigit3 = user_plmn_list[i].mcc[2]; user_network_record_list[i].plmn.MNCdigit2 = user_plmn_list[i].mnc[1]; user_network_record_list[i].plmn.MNCdigit1 = user_plmn_list[i].mnc[0]; user_network_record_list[i].tac_end = 0xfffd; user_network_record_list[i].tac_start = 0x0001; if (strlen(user_plmn_list[i].mnc) > 2) { user_network_record_list[i].plmn.MNCdigit3 = user_plmn_list[i].mnc[2]; } } } /* * Computes the check digit using Luhn algorithm */ int _luhn(const char* cc) { const int m[] = { 0, 2, 4, 6, 8, 1, 3, 5, 7, 9 }; int odd = 1, sum = 0; for (int i = strlen(cc); i--; odd = !odd) { int digit = cc[i] - '0'; sum += odd ? m[digit] : digit; } return 10 - (sum % 10); } void _display_usim_data(int user_id) { int rc; usim_data_t data = { }; /* * Read USIM application data */ memset(&data, 0, sizeof(usim_data_t)); char *path = make_filename(output_dir, USIM_API_NVRAM_FILENAME, user_id); rc = usim_api_read(path, &data); free(path); if (rc != RETURNok) { perror("ERROR\t: usim_api_read() failed"); exit(EXIT_FAILURE); } /* * Display USIM application data */ printf("\nUSIM data:\n\n"); int digits; printf("Administrative Data:\n"); printf("\tUE_Operation_Mode\t= 0x%.2x\n", data.ad.UE_Operation_Mode); printf("\tAdditional_Info\t\t= 0x%.4x\n", data.ad.Additional_Info); printf("\tMNC_Length\t\t= %d\n\n", data.ad.MNC_Length); printf("IMSI:\n"); printf("\tlength\t= %d\n", data.imsi.length); printf("\tparity\t= %s\n", data.imsi.u.num.parity == EVEN_PARITY ? "Even" : "Odd"); digits = (data.imsi.length * 2) - 1 - (data.imsi.u.num.parity == EVEN_PARITY ? 1 : 0); printf("\tdigits\t= %d\n", digits); printf("\tdigits\t= %u%u%u%u%u%x%u%u%u%u", data.imsi.u.num.digit1, // MCC digit 1 data.imsi.u.num.digit2, // MCC digit 2 data.imsi.u.num.digit3, // MCC digit 3 data.imsi.u.num.digit4, // MNC digit 1 data.imsi.u.num.digit5, // MNC digit 2 data.imsi.u.num.digit6, // MNC digit 3 data.imsi.u.num.digit7, data.imsi.u.num.digit8, data.imsi.u.num.digit9, data.imsi.u.num.digit10); if (digits >= 11) printf("%x", data.imsi.u.num.digit11); if (digits >= 12) printf("%x", data.imsi.u.num.digit12); if (digits >= 13) printf("%x", data.imsi.u.num.digit13); if (digits >= 14) printf("%x", data.imsi.u.num.digit14); if (digits >= 15) printf("%x", data.imsi.u.num.digit15); printf("\n\n"); printf("Ciphering and Integrity Keys:\n"); printf("\tKSI\t: 0x%.2x\n", data.keys.ksi); char key[USIM_CK_SIZE + 1]; key[USIM_CK_SIZE] = '\0'; memcpy(key, data.keys.ck, USIM_CK_SIZE); printf("\tCK\t: \"%s\"\n", key); memcpy(key, data.keys.ik, USIM_IK_SIZE); printf("\tIK\t: \"%s\"\n", key); printf("EPS NAS security context:\n"); printf("\tKSIasme\t: 0x%.2x\n", data.securityctx.KSIasme.value[0]); char kasme[USIM_K_ASME_SIZE + 1]; kasme[USIM_K_ASME_SIZE] = '\0'; memcpy(kasme, data.securityctx.Kasme.value, USIM_K_ASME_SIZE); printf("\tKasme\t: \"%s\"\n", kasme); printf("\tulNAScount\t: 0x%.8x\n", *(uint32_t*) data.securityctx.ulNAScount.value); printf("\tdlNAScount\t: 0x%.8x\n", *(uint32_t*) data.securityctx.dlNAScount.value); printf("\talgorithmID\t: 0x%.2x\n\n", data.securityctx.algorithmID.value[0]); printf("MSISDN\t= %u%u%u %u%u%u%u %u%u%u%u\n\n", data.msisdn.number.digit[0].msb, data.msisdn.number.digit[0].lsb, data.msisdn.number.digit[1].msb, data.msisdn.number.digit[1].lsb, data.msisdn.number.digit[2].msb, data.msisdn.number.digit[2].lsb, data.msisdn.number.digit[3].msb, data.msisdn.number.digit[3].lsb, data.msisdn.number.digit[4].msb, data.msisdn.number.digit[4].lsb, data.msisdn.number.digit[5].msb); for (int i = 0; i < USIM_PNN_MAX; i++) { printf("PNN[%d]\t= {%s, %s}\n", i, data.pnn[i].fullname.value, data.pnn[i].shortname.value); } printf("\n"); for (int i = 0; i < USIM_OPL_MAX; i++) { printf("OPL[%d]\t= ", i); PRINT_PLMN(data.opl[i].plmn); printf(", TAC = [%.4x - %.4x], record_id = %d\n", data.opl[i].start, data.opl[i].end, data.opl[i].record_id); } printf("\n"); printf("HPLMN\t\t= "); PRINT_PLMN(data.hplmn.plmn); printf(", AcT = 0x%x\n\n", data.hplmn.AcT); for (int i = 0; i < USIM_FPLMN_MAX; i++) { printf("FPLMN[%d]\t= ", i); PRINT_PLMN(data.fplmn[i]); printf("\n"); } printf("\n"); for (int i = 0; i < USIM_EHPLMN_MAX; i++) { printf("EHPLMN[%d]\t= ", i); PRINT_PLMN(data.ehplmn[i]); printf("\n"); } printf("\n"); for (int i = 0; i < USIM_PLMN_MAX; i++) { printf("PLMN[%d]\t\t= ", i); PRINT_PLMN(data.plmn[i].plmn); printf(", AcTPLMN = 0x%x", data.plmn[i].AcT); printf("\n"); } printf("\n"); for (int i = 0; i < USIM_OPLMN_MAX; i++) { printf("OPLMN[%d]\t= ", i); PRINT_PLMN(data.oplmn[i].plmn); printf(", AcTPLMN = 0x%x", data.oplmn[i].AcT); printf("\n"); } printf("\n"); printf("HPPLMN\t\t= 0x%.2x (%d minutes)\n\n", data.hpplmn, data.hpplmn); printf("LOCI:\n"); printf("\tTMSI = 0x%.4x\n", data.loci.tmsi); printf("\tLAI\t: PLMN = "); PRINT_PLMN(data.loci.lai.plmn); printf(", LAC = 0x%.2x\n", data.loci.lai.lac); printf("\tstatus\t= %d\n\n", data.loci.status); printf("PSLOCI:\n"); printf("\tP-TMSI = 0x%.4x\n", data.psloci.p_tmsi); printf("\tsignature = 0x%x 0x%x 0x%x\n", data.psloci.signature[0], data.psloci.signature[1], data.psloci.signature[2]); printf("\tRAI\t: PLMN = "); PRINT_PLMN(data.psloci.rai.plmn); printf(", LAC = 0x%.2x, RAC = 0x%.1x\n", data.psloci.rai.lac, data.psloci.rai.rac); printf("\tstatus\t= %d\n\n", data.psloci.status); printf("EPSLOCI:\n"); printf("\tGUTI\t: GUMMEI\t: (PLMN = "); PRINT_PLMN(data.epsloci.guti.gummei.plmn); printf(", MMEgid = 0x%.2x, MMEcode = 0x%.1x)", data.epsloci.guti.gummei.MMEgid, data.epsloci.guti.gummei.MMEcode); printf(", M-TMSI = 0x%.4x\n", data.epsloci.guti.m_tmsi); printf("\tTAI\t: PLMN = "); PRINT_PLMN(data.epsloci.tai.plmn); printf(", TAC = 0x%.2x\n", data.epsloci.tai.tac); printf("\tstatus\t= %d\n\n", data.epsloci.status); printf("NASCONFIG:\n"); printf("\tNAS_SignallingPriority\t\t: 0x%.2x\n", data.nasconfig.NAS_SignallingPriority.value[0]); printf("\tNMO_I_Behaviour\t\t\t: 0x%.2x\n", data.nasconfig.NMO_I_Behaviour.value[0]); printf("\tAttachWithImsi\t\t\t: 0x%.2x\n", data.nasconfig.AttachWithImsi.value[0]); printf("\tMinimumPeriodicSearchTimer\t: 0x%.2x\n", data.nasconfig.MinimumPeriodicSearchTimer.value[0]); printf("\tExtendedAccessBarring\t\t: 0x%.2x\n", data.nasconfig.ExtendedAccessBarring.value[0]); printf("\tTimer_T3245_Behaviour\t\t: 0x%.2x\n", data.nasconfig.Timer_T3245_Behaviour.value[0]); } void _display_ue_data(int user_id) { user_nvdata_t data; int rc; char* path = make_filename(output_dir, USER_NVRAM_FILENAME, user_id); /* * Read UE's non-volatile data */ memset(&data, 0, sizeof(user_nvdata_t)); rc = memory_read(path, &data, sizeof(user_nvdata_t)); free(path); if (rc != RETURNok) { perror("ERROR\t: memory_read() failed"); exit(EXIT_FAILURE); } /* * Display UE's non-volatile data */ printf("\nUE's non-volatile data:\n\n"); printf("IMEI\t\t= %s\n", data.IMEI); printf("manufacturer\t= %s\n", data.manufacturer); printf("model\t\t= %s\n", data.model); printf("PIN\t\t= %s\n", data.PIN); } /* * Displays UE's non-volatile EMM data */ void _display_emm_data(int user_id) { int rc; emm_nvdata_t data; char* path = make_filename(output_dir, EMM_NVRAM_FILENAME, user_id); /* * Read EMM non-volatile data */ memset(&data, 0, sizeof(emm_nvdata_t)); rc = memory_read(path, &data, sizeof(emm_nvdata_t)); free(path); if (rc != RETURNok) { perror("ERROR\t: memory_read() failed "); exit(EXIT_FAILURE); } /* * Display EMM non-volatile data */ printf("\nEMM non-volatile data:\n\n"); printf("IMSI\t\t= "); if (data.imsi.u.num.digit6 == 0b1111) { if (data.imsi.u.num.digit15 == 0b1111) { printf("%u%u%u.%u%u.%u%u%u%u%u%u%u%u\n", data.imsi.u.num.digit1, data.imsi.u.num.digit2, data.imsi.u.num.digit3, data.imsi.u.num.digit4, data.imsi.u.num.digit5, data.imsi.u.num.digit7, data.imsi.u.num.digit8, data.imsi.u.num.digit9, data.imsi.u.num.digit10, data.imsi.u.num.digit11, data.imsi.u.num.digit12, data.imsi.u.num.digit13, data.imsi.u.num.digit14); } else { printf("%u%u%u.%u%u.%u%u%u%u%u%u%u%u%u\n", data.imsi.u.num.digit1, data.imsi.u.num.digit2, data.imsi.u.num.digit3, data.imsi.u.num.digit4, data.imsi.u.num.digit5, data.imsi.u.num.digit7, data.imsi.u.num.digit8, data.imsi.u.num.digit9, data.imsi.u.num.digit10, data.imsi.u.num.digit11, data.imsi.u.num.digit12, data.imsi.u.num.digit13, data.imsi.u.num.digit14, data.imsi.u.num.digit15); } } else { if (data.imsi.u.num.digit15 == 0b1111) { printf("%u%u%u.%u%u%u.%u%u%u%u%u%u%u%u\n", data.imsi.u.num.digit1, data.imsi.u.num.digit2, data.imsi.u.num.digit3, data.imsi.u.num.digit4, data.imsi.u.num.digit5, data.imsi.u.num.digit6, data.imsi.u.num.digit7, data.imsi.u.num.digit8, data.imsi.u.num.digit9, data.imsi.u.num.digit10, data.imsi.u.num.digit11, data.imsi.u.num.digit12, data.imsi.u.num.digit13, data.imsi.u.num.digit14); } else { printf("%u%u%u.%u%u%u.%u%u%u%u%u%u%u%u%u\n", data.imsi.u.num.digit1, data.imsi.u.num.digit2, data.imsi.u.num.digit3, data.imsi.u.num.digit4, data.imsi.u.num.digit5, data.imsi.u.num.digit6, data.imsi.u.num.digit7, data.imsi.u.num.digit8, data.imsi.u.num.digit9, data.imsi.u.num.digit10, data.imsi.u.num.digit11, data.imsi.u.num.digit12, data.imsi.u.num.digit13, data.imsi.u.num.digit14, data.imsi.u.num.digit15); } } printf("RPLMN\t\t= "); PRINT_PLMN(data.rplmn); printf("\n"); for (int i = 0; i < data.eplmn.n_plmns; i++) { printf("EPLMN[%d]\t= ", i); PRINT_PLMN(data.eplmn.plmn[i]); printf("\n"); } } /* * Displays command line usage */ void _display_usage(void) { fprintf(stderr, "usage: conf2uedata [OPTION] [directory] ...\n"); fprintf(stderr, "\t[-c]\tConfig file to use\n"); fprintf(stderr, "\t[-o]\toutput file directory\n"); fprintf(stderr, "\t[-h]\tDisplay this usage\n"); } char * make_filename(const char *output_dir, const char *filename, int ueid) { size_t size; char *str_ueid, *str; str_ueid = itoa(ueid); if (str_ueid == NULL) { perror("ERROR\t: itoa() failed"); exit(EXIT_FAILURE); } size = strlen(output_dir)+strlen(filename) + sizeof(ueid) + 1 + 1; // for \0 and for '/' str = malloc(size); if (str == NULL) { perror("ERROR\t: make_filename() failed"); exit(EXIT_FAILURE); } snprintf(str, size, "%s/%s%s",output_dir, filename, str_ueid); free(str_ueid); return str; }