From d2c4ca4fa91d9496f5b7a5f2dc1c6b66bb52ced8 Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Sun, 1 May 2016 19:51:56 +0200 Subject: Implementation of Advanced Mobile Phone Service (AMPS) --- src/amps/frame.c | 3671 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 3671 insertions(+) create mode 100644 src/amps/frame.c (limited to 'src/amps/frame.c') diff --git a/src/amps/frame.c b/src/amps/frame.c new file mode 100644 index 0000000..5aa8bbc --- /dev/null +++ b/src/amps/frame.c @@ -0,0 +1,3671 @@ +/* AMPS frame transcoding + * + * (C) 2016 by Andreas Eversberg + * All Rights Reserved + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include "../common/debug.h" +#include "../common/timer.h" +#include "amps.h" +#include "dsp.h" +#include "frame.h" + +/* uncomment this to debug bits */ +//#define BIT_DEBUGGING + +/* + * parity + */ + +uint64_t cut_bits[37] = { + 0x0, + 0x1, 0x3, 0x7, 0xf, 0x1f, 0x3f, 0x7f, 0xff, + 0x1ff, 0x3ff, 0x7ff, 0xfff, 0x1fff, 0x3fff, 0x7fff, 0xffff, + 0x1ffff, 0x3ffff, 0x7ffff, 0xfffff, 0x1fffff, 0x3fffff, 0x7fffff, 0xffffff, + 0x1ffffff, 0x3ffffff, 0x7ffffff, 0xfffffff, 0x1fffffff, 0x3fffffff, 0x7fffffff, 0xffffffff, + 0x1ffffffff, 0x3ffffffff, 0x7ffffffff, 0xfffffffff, +}; + +static char gp[12] = { 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1 }; + +/* do BCH(length+12,length,5) encoding: + * given data and length, return 12 bits redundancy + * all arrays are MSB first. + */ +const char *encode_bch(const char *data, int length) +{ + static char redun[13]; + int i, j, feedback; + + for (i = 0; i < 12; i++) + redun[i] = 0; + + for (i = 0; i < length; i++) { + feedback = (data[i] & 1) ^ redun[0]; + if (feedback) { + for (j = 11; j > 0; j--) { + if (gp[11 - j]) + redun[11 - j] = redun[12 - j] ^ feedback; + else + redun[11 - j] = redun[12 - j]; + } + redun[11] = gp[11]; + } else { + for (j = 11; j > 0; j--) + redun[11 - j] = redun[12 - j]; + redun[11] = 0; + } + } + for (i = 0; i < 12; i++) + redun[i] += '0'; + redun[12] = '\0'; + + return redun; +} + +/* same as above, but with binary data (without parity space holder) */ +uint16_t encode_bch_binary(uint64_t value, int length) +{ + char data[length + 1]; + const char *redun; + uint16_t p = 0; + int i; + + for (i = 0; i < length; i++) + data[i] = '0' + ((value >> (length - 1 - i)) & 1); + data[i] = '\0'; + + redun = encode_bch(data, length); + + for (i = 0; i < 12; i++) + p = (p << 1) | ((*redun++) & 1); + + return p; +} + +/* + * helper + */ + +/* convert amps digits to number digits */ +static char digit2number[16] = { + '\0', + '1', + '2', + '3', + '4', + '5', + '6', + '7', + '8', + '9', + '0', + '*', + '#', + '+', + '?', + '?', +}; + + +/* + * Word definitions + */ + +struct def_ie { + const char *name; + int bits; + enum amps_ie ie; +}; + +struct def_word { + const char *name; + struct def_ie ie[]; +}; + +struct def_message_set { + const char *name; + int num_bits; + struct def_word *word[]; +}; + + +/* FOCC - Mobile Station Control Message */ + +static struct def_word word1_abbreviated_address_word = { + "Word 1 - Abbreviated Address Word", + { + { "T1T2", 2, 0 }, + { "DCC", 2, 0 }, + { "MIN1", 24, 0 }, + { "P", 12, 0 }, + { NULL, 0, 0 } + } +}; + +static struct def_word word2_extended_address_word_a = { + "Word 2 - Extended Address Word (SCC == 11)", + { + { "T1T2", 2, 0 }, + { "SCC", 2, 0 }, + { "MIN2", 10, 0 }, + { "EF", 1, 0 }, + { "LOCAL/MSG TYPE", 5, 0 }, + { "ORDQ", 3, 0 }, + { "ORDER", 5, 0 }, + { "P", 12, 0 }, + { NULL, 0, 0 } + } +}; + +static struct def_word word2_extended_address_word_b = { + "Word 2 - Extended Address Word (SCC != 11)", + { + { "T1T2", 2, 0 }, + { "SCC", 2, 0 }, + { "MIN2", 10, 0 }, + { "VMAC", 3, 0 }, + { "CHAN", 11, 0 }, + { "P", 12, 0 }, + { NULL, 0, 0 } + } +}; + +static struct def_word word3_first_analog_channel_assignment_word = { + "Word 3 - First Analog Channel Assignment Word", + { + { "T1T2", 2, 0 }, + { "PVI", 1, 0 }, + { "MEM", 1, 0 }, + { "DTX Support", 2, 0 }, + { "RSVD", 6, 0 }, + { "SCC", 2, 0 }, + { "VMAC", 3, 0 }, + { "CHAN", 11, 0 }, + { "P", 12, 0 }, + { NULL, 0, 0 } + } +}; + +static struct def_word word3_first_digital_channel_assignment_word = { + "Word 3 - First Digital Channel Assignment Word", + { + { "T1T2", 2, 0 }, + { "PVI", 1, 0 }, + { "MEM", 1, 0 }, + { "DVCC", 8, 0 }, + { "PM", 1, 0 }, + { "DMAC", 4, 0 }, + { "CHAN", 11, 0 }, + { "P", 12, 0 }, + { NULL, 0, 0 } + } +}; + +static struct def_word word3_first_directed_retry_word = { + "Word 3 - First Directed-Retry Word", + { + { "T1T2", 2, 0 }, + { "SCC", 2, 0 }, + { "CHANPOS", 7, 0 }, + { "CHANPOS", 7, 0 }, + { "CHANPOS", 7, 0 }, + { "RSVD", 3, 0 }, + { "P", 12, 0 }, + { NULL, 0, 0 } + } +}; + +static struct def_word word3_base_station_challenge_order_confirmation_word = { + "Word 3 - Base Station Challenge Order Confirmation Word", + { + { "T1T2", 2, 0 }, + { "SCC", 2, 0 }, + { "RSVD", 2, 0 }, + { "AUTHBS", 18, 0 }, + { "RSVD", 4, 0 }, + { "P", 12, 0 }, + { NULL, 0, 0 } + } +}; + +static struct def_word word3_unique_challenge_order_word = { + "Word 3 - Unique Challenge Order Word", + { + { "T1T2", 2, 0 }, + { "SCC", 2, 0 }, + { "RANDU", 24, 0 }, + { "P", 12, 0 }, + { NULL, 0, 0 } + } +}; + +static struct def_word word3_first_ssd_update_order_word = { + "Word 3 - First SSD Update Order Word", + { + { "T1T2", 2, 0 }, + { "SCC", 2, 0 }, + { "RANDSSD_1", 24, 0 }, + { "P", 12, 0 }, + { NULL, 0, 0 } + } +}; + +static struct def_word word4_second_directed_retry_word = { + "Word 4 - Second Directed-Retry Word", + { + { "T1T2", 2, 0 }, + { "SCC", 2, 0 }, + { "CHANPOS", 7, 0 }, + { "CHANPOS", 7, 0 }, + { "CHANPOS", 7, 0 }, + { "RSVD", 3, 0 }, + { "P", 12, 0 }, + { NULL, 0, 0 } + } +}; + +static struct def_word word4_second_ssd_update_order_word = { + "Word 4 - Second SSD Update Order Word", + { + { "T1T2", 2, 0 }, + { "SCC", 2, 0 }, + { "RANDSSD_2", 24, 0 }, + { "P", 12, 0 }, + { NULL, 0, 0 } + } +}; + +static struct def_word word5_third_ssd_update_order_word = { + "Word 5 - Third SSD Update Order Word", + { + { "T1T2", 2, 0 }, + { "SCC", 2, 0 }, + { "RSVD", 12, 0 }, + { "RANDSSD_3", 8, 0 }, + { "RSVD", 4, 0 }, + { "P", 12, 0 }, + { NULL, 0, 0 } + } +}; + +/* FOCC - System Parameter Overhead Message */ + +static struct def_word word1_system_parameter_overhead = { + "Word 1 - System Parameter Overhead", + { + { "T1T2", 2, 0 }, + { "DCC", 2, 0 }, + { "SID1", 14, 0 }, + { "EP", 1, 0 }, + { "AUTH", 1, 0 }, + { "PCI", 1, 0 }, + { "NAWC", 4, 0 }, + { "OHD", 3, 0 }, + { "P", 12, 0 }, + { NULL, 0, 0 } + } +}; + + +static struct def_word word2_system_parameter_overhead = { + "Word 2 - System Parameter Overhead", + { + { "T1T2", 2, 0 }, + { "DCC", 2, 0 }, + { "S", 1, 0 }, + { "E", 1, 0 }, + { "REGH", 1, 0 }, + { "REGR", 1, 0 }, + { "DTX Support", 2, 0 }, + { "N-1", 5, 0 }, + { "RCF", 1, 0 }, + { "CPA", 1, 0 }, + { "CMAX-1", 7, 0 }, + { "END", 1, 0 }, + { "OHD", 3, 0 }, + { "P", 12, 0 }, + { NULL, 0, 0 } + } +}; + +/* FOCC - Global action Overhead Message */ + +static struct def_word rescan_global_action = { + "Rescan Global Action Message", + { + { "T1T2", 2, 0 }, + { "DCC", 2, 0 }, + { "ACT", 4, 0 }, + { "RSVD", 16, 0 }, + { "END", 1, 0 }, + { "OHD", 3, 0 }, + { "P", 12, 0 }, + { NULL, 0, 0 } + } +}; + +static struct def_word registration_increment_global_action = { + "Registration Increment Global Action Message", + { + { "T1T2", 2, 0 }, + { "DCC", 2, 0 }, + { "ACT", 4, 0 }, + { "REGINCR", 12, 0 }, + { "RSVD", 4, 0 }, + { "END", 1, 0 }, + { "OHD", 3, 0 }, + { "P", 12, 0 }, + { NULL, 0, 0 } + } +}; + +static struct def_word location_area_global_action = { + "Location Area Global Action Message", + { + { "T1T2", 2, 0 }, + { "DCC", 2, 0 }, + { "ACT", 4, 0 }, + { "PUREG", 1, 0 }, + { "PDREG", 1, 0 }, + { "LREG", 1, 0 }, + { "RSVD", 1, 0 }, + { "LOCAID", 12, 0 }, + { "END", 1, 0 }, + { "OHD", 3, 0 }, + { "P", 12, 0 }, + { NULL, 0, 0 } + } +}; + +static struct def_word new_access_channel_set_global_action = { + "New Access Channel Set Global Action Message", + { + { "T1T2", 2, 0 }, + { "DCC", 2, 0 }, + { "ACT", 4, 0 }, + { "NEWACC", 11, 0 }, + { "RSVD", 5, 0 }, + { "END", 1, 0 }, + { "OHD", 3, 0 }, + { "P", 12, 0 }, + { NULL, 0, 0 } + } +}; + +static struct def_word overload_control_global_action = { + "Overload Control Global Action Message", + { + { "T1T2", 2, 0 }, + { "DCC", 2, 0 }, + { "ACT", 4, 0 }, + { "OLC 0", 1, 0 }, + { "OLC 1", 1, 0 }, + { "OLC 2", 1, 0 }, + { "OLC 3", 1, 0 }, + { "OLC 4", 1, 0 }, + { "OLC 5", 1, 0 }, + { "OLC 6", 1, 0 }, + { "OLC 7", 1, 0 }, + { "OLC 8", 1, 0 }, + { "OLC 9", 1, 0 }, + { "OLC 10", 1, 0 }, + { "OLC 11", 1, 0 }, + { "OLC 12", 1, 0 }, + { "OLC 13", 1, 0 }, + { "OLC 14", 1, 0 }, + { "OLC 15", 1, 0 }, + { "END", 1, 0 }, + { "OHD", 3, 0 }, + { "P", 12, 0 }, + { NULL, 0, 0 } + } +}; + +static struct def_word access_type_parameters_global_action = { + "Access Type Parameters Global Action Message", + { + { "T1T2", 2, 0 }, + { "DCC", 2, 0 }, + { "ACT", 4, 0 }, + { "BIS", 1, 0 }, + { "PCI_HOME", 1, 0 }, + { "PCI_ROAM", 1, 0 }, + { "BSPC", 4, 0 }, + { "BSCAP", 3, 0 }, + { "RSVD", 6, 0 }, + { "END", 1, 0 }, + { "OHD", 3, 0 }, + { "P", 12, 0 }, + { NULL, 0, 0 } + } +}; + +static struct def_word access_attempt_parameters_global_action = { + "Access Attempt Parameters Global Action Message", + { + { "T1T2", 2, 0 }, + { "DCC", 2, 0 }, + { "ACT", 4, 0 }, + { "MAXBUSY-PGR", 4, 0 }, + { "MAXSZTR-PGR", 4, 0 }, + { "MAXBUSY-OTHER", 4, 0 }, + { "MAXSZTR-OTHER", 4, 0 }, + { "END", 1, 0 }, + { "OHD", 3, 0 }, + { "P", 12, 0 }, + { NULL, 0, 0 } + } +}; + +static struct def_word random_challenge_a_global_action = { + "Random Challenge A Global Action Message", + { + { "T1T2", 2, 0 }, + { "DCC", 2, 0 }, + { "ACT", 4, 0 }, + { "RAND1_A", 16, 0 }, + { "END", 1, 0 }, + { "OHD", 3, 0 }, + { "P", 12, 0 }, + { NULL, 0, 0 } + } +}; + +static struct def_word random_challenge_b_global_action = { + "Random Challenge B Global Action Message", + { + { "T1T2", 2, 0 }, + { "DCC", 2, 0 }, + { "ACT", 4, 0 }, + { "RAND1_B", 16, 0 }, + { "END", 1, 0 }, + { "OHD", 3, 0 }, + { "P", 12, 0 }, + { NULL, 0, 0 } + } +}; + +static struct def_word local_control_1 = { + "Local Control 1 Message", + { + { "T1T2", 2, 0 }, + { "DCC", 2, 0 }, + { "ACT", 4, 0 }, + { "LOCAL CONTROL", 16, 0 }, + { "END", 1, 0 }, + { "OHD", 3, 0 }, + { "P", 12, 0 }, + { NULL, 0, 0 } + } +}; + +static struct def_word local_control_2 = { + "Local Control 2 Message", + { + { "T1T2", 2, 0 }, + { "DCC", 2, 0 }, + { "ACT", 4, 0 }, + { "LOCAL CONTROL", 16, 0 }, + { "END", 1, 0 }, + { "OHD", 3, 0 }, + { "P", 12, 0 }, + { NULL, 0, 0 } + } +}; + +/* FOCC - Registration ID Message */ + +static struct def_word registration_id = { + "Registration ID Message", + { + { "T1T2", 2, 0 }, + { "DCC", 2, 0 }, + { "REGID", 20, 0 }, + { "END", 1, 0 }, + { "OHD", 3, 0 }, + { "P", 12, 0 }, + { NULL, 0, 0 } + } +}; + +/* FOCC - Control Filler Message */ + +static struct def_word control_filler = { + "Control-Filler Message", + { + { "T1T2", 2, 0 }, + { "DCC", 2, 0 }, + { "010111", 6, 0 }, + { "CMAC", 3, 0 }, + { "SDCC1", 2, 0 }, + { "11", 2, 0 }, + { "SDCC2", 2, 0 }, + { "1", 1, 0 }, + { "WFOM", 1, 0 }, + { "1111", 4, 0 }, + { "OHD", 3, 0 }, + { "P", 12, 0 }, + { NULL, 0, 0 } + } +}; + +/* FOCC - Control Channel Information Message */ + +static struct def_word control_channel_information = { + "Control Channel Information Message", + { + { "T1T2", 2, 0 }, + { "DCC", 2, 0 }, + { "CHAN", 11, 0 }, + { "Async Data", 1, 0 }, + { "G3 Fax", 1, 0 }, + { "Data Privacy", 1, 0 }, + { "HDVCC", 4, 0 }, + { "Hyperband", 2, 0 }, + { "END", 1, 0 }, + { "OHD", 3, 0 }, + { "P", 12, 0 }, + { NULL, 0, 0 } + } +}; + +static struct def_message_set focc_words = { + "FOCC Messages", 40, + { + &word1_abbreviated_address_word, + &word2_extended_address_word_a, + &word2_extended_address_word_b, + &word3_first_analog_channel_assignment_word, + &word3_first_digital_channel_assignment_word, + &word3_first_directed_retry_word, + &word3_base_station_challenge_order_confirmation_word, + &word3_unique_challenge_order_word, + &word3_first_ssd_update_order_word, + &word4_second_directed_retry_word, + &word4_second_ssd_update_order_word, + &word5_third_ssd_update_order_word, + + &word1_system_parameter_overhead, + &word2_system_parameter_overhead, + &rescan_global_action, + ®istration_increment_global_action, + &location_area_global_action, + &new_access_channel_set_global_action, + &overload_control_global_action, + &access_type_parameters_global_action, + &access_attempt_parameters_global_action, + &random_challenge_a_global_action, + &random_challenge_b_global_action, + &local_control_1, + &local_control_2, + ®istration_id, + &control_filler, + &control_channel_information, + NULL + } +}; + +/* RECC - Words */ + +static struct def_word abbreviated_address_word = { + "Word A - Abbreviated Address Word", + { + { "F", 1, 0 }, + { "NAWC", 3, 0 }, + { "T", 1, 0 }, + { "S", 1, 0 }, + { "E", 1, 0 }, + { "ER", 1, 0 }, + { "SCM", 4, 0 }, + { "MIN1", 24, 0 }, + { "P", 12, 0 }, + { NULL, 0, 0 } + } +}; + +static struct def_word extended_address_word = { + "Word B - Extended Address Word", + { + { "F", 1, 0 }, + { "NAWC", 3, 0 }, + { "LOCAL/MSG TYPE", 5, 0 }, + { "ORDQ", 3, 0 }, + { "ORDER", 5, 0 }, + { "LT", 1, 0 }, + { "EP", 1, 0 }, + { "SCM", 1, 0 }, + { "MPCI", 2, 0 }, + { "SDCC1", 2, 0 }, + { "SDCC2", 2, 0 }, + { "MIN2", 10, 0 }, + { "P", 12, 0 }, + { NULL, 0, 0 } + } +}; + +static struct def_word serial_number_word = { + "Word C - Serial Number Word", + { + { "F", 1, 0 }, + { "NAWC", 3, 0 }, + { "ESN", 32, 0 }, + { "P", 12, 0 }, + { NULL, 0, 0 } + } +}; + +static struct def_word authentication_word = { + "Word C - Authentication Word", + { + { "F", 1, 0 }, + { "NAWC", 3, 0 }, + { "COUNT", 6, 0 }, + { "RANDC", 8, 0 }, + { "AUTHR", 18, 0 }, + { "P", 12, 0 }, + { NULL, 0, 0 } + } +}; + +static struct def_word unique_challenge_order_confirmation_word = { + "Word C - Unique Challenge Order Confirmation Word", + { + { "F", 1, 0 }, + { "NAWC", 3, 0 }, + { "RSVD", 14, 0 }, + { "AUTHU", 18, 0 }, + { "P", 12, 0 }, + { NULL, 0, 0 } + } +}; + +static struct def_word base_station_challenge_word = { + "Word C - Base Station Challenge Word", + { + { "F", 1, 0 }, + { "NAWC", 3, 0 }, + { "RANDBS", 32, 0 }, + { "P", 12, 0 }, + { NULL, 0, 0 } + } +}; + +static struct def_word pci_report_registration_word = { + "Word C - PCI Report/Registration Word", + { + { "F", 1, 0 }, + { "NAWC", 3, 0 }, + { "MSPC", 4, 0 }, + { "MSCAP", 3, 0 }, + { "RSVD", 25, 0 }, + { "P", 12, 0 }, + { NULL, 0, 0 } + } +}; + +static struct def_word first_word_of_the_called_address = { + "Word D - First Word of the Called-Address (Origination - Voice Service)", + { + { "F", 1, 0 }, + { "NAWC", 3, 0 }, + { "DIGIT 1", 4, 0 }, + { "DIGIT 2", 4, 0 }, + { "DIGIT 3", 4, 0 }, + { "DIGIT 4", 4, 0 }, + { "DIGIT 5", 4, 0 }, + { "DIGIT 6", 4, 0 }, + { "DIGIT 7", 4, 0 }, + { "DIGIT 8", 4, 0 }, + { "P", 12, 0 }, + { NULL, 0, 0 } + } +}; + +static struct def_word service_code_word = { + "Word D - Service Code Word (Origination with Service and Page Response with 2 Service)", + { + { "F", 1, 0 }, + { "NAWC", 3, 0 }, + { "Service Code", 4, 0 }, + { "PM_D", 3, 0 }, + { "SAP", 1, 0 }, + { "Acked Data", 1, 0 }, + { "CRC", 2, 0 }, + { "Data Part", 3, 0 }, + { "RLP", 2, 0 }, + { "RSVD", 16, 0 }, + { "P", 12, 0 }, + { NULL, 0, 0 } + } +}; + +static struct def_word second_word_of_the_called_address = { + "Word E - Second Word of the Called-Address (Origination - Voice Service)", + { + { "F", 1, 0 }, + { "NAWC", 3, 0 }, + { "DIGIT 9", 4, 0 }, + { "DIGIT 10", 4, 0 }, + { "DIGIT 11", 4, 0 }, + { "DIGIT 12", 4, 0 }, + { "DIGIT 13", 4, 0 }, + { "DIGIT 14", 4, 0 }, + { "DIGIT 15", 4, 0 }, + { "DIGIT 16", 4, 0 }, + { "P", 12, 0 }, + { NULL, 0, 0 } + } +}; + +static struct def_word third_word_of_the_called_address = { + "Word F - Third Word of the Called-Address (Origination - Voice Service)", + { + { "F", 1, 0 }, + { "NAWC", 3, 0 }, + { "DIGIT 17", 4, 0 }, + { "DIGIT 18", 4, 0 }, + { "DIGIT 19", 4, 0 }, + { "DIGIT 20", 4, 0 }, + { "DIGIT 21", 4, 0 }, + { "DIGIT 22", 4, 0 }, + { "DIGIT 23", 4, 0 }, + { "DIGIT 24", 4, 0 }, + { "P", 12, 0 }, + { NULL, 0, 0 } + } +}; + +static struct def_word fourth_word_of_the_called_address = { + "Word G - Fourth Word of the Called-Address (Origination - Voice Service)", + { + { "F", 1, 0 }, + { "NAWC", 3, 0 }, + { "DIGIT 25", 4, 0 }, + { "DIGIT 26", 4, 0 }, + { "DIGIT 27", 4, 0 }, + { "DIGIT 28", 4, 0 }, + { "DIGIT 29", 4, 0 }, + { "DIGIT 30", 4, 0 }, + { "DIGIT 31", 4, 0 }, + { "DIGIT 32", 4, 0 }, + { "P", 12, 0 }, + { NULL, 0, 0 } + } +}; + +static struct def_message_set recc_words = { + "RECC Words", 48, + { + &abbreviated_address_word, + &extended_address_word, + &serial_number_word, + &authentication_word, + &unique_challenge_order_confirmation_word, + &base_station_challenge_word, + &pci_report_registration_word, + &first_word_of_the_called_address, + &service_code_word, + &second_word_of_the_called_address, + &third_word_of_the_called_address, + &fourth_word_of_the_called_address, + NULL + } +}; + +/* FVC - Mobile Station Control Message */ + +static struct def_word mobile_station_control_message_word1_a = { + "Mobile Station Control Message Word 1 (SCC == 11)", + { + { "T1T2", 2, 0 }, + { "SCC", 2, 0 }, + { "PSCC", 2, 0 }, + { "EF", 1, 0 }, + { "DVCC", 8, 0 }, + { "LOCAL/MSG TYPE", 5, 0 }, + { "ORDQ", 3, 0 }, + { "ORDER", 5, 0 }, + { "P", 12, 0 }, + { NULL, 0, 0 } + } +}; + +static struct def_word mobile_station_control_message_word1_b = { + "Mobile Station Control Message Word 1 (SCC != 11)", + { + { "T1T2", 2, 0 }, + { "SCC", 2, 0 }, + { "PSCC", 2, 0 }, + { "EF", 1, 0 }, + { "RSVD", 4, 0 }, + { "DTX", 1, 0 }, + { "PVI", 1, 0 }, + { "MEM", 1, 0 }, + { "VMAC", 3, 0 }, + { "CHAN", 11, 0 }, + { "P", 12, 0 }, + { NULL, 0, 0 } + } +}; + +static struct def_word word2_digital_channel_assignment = { + "Word 2 - Digital Channel Assignment", + { + { "T1T2", 2, 0 }, + { "MEM", 1, 0 }, + { "PM", 1, 0 }, + { "PSCC", 2, 0 }, + { "SBI", 2, 0 }, + { "TA", 5, 0 }, + { "DMAC", 4, 0 }, + { "CHAN", 11, 0 }, + { "P", 12, 0 }, + { NULL, 0, 0 } + } +}; + +static struct def_word word2_digital_control_channel_information_word = { + "Word 2 - Digital Control Channel Information Word", + { + { "T1T2", 2, 0 }, + { "RSVD", 5, 0 }, + { "Hyperband", 2, 0 }, + { "DVCC", 8, 0 }, + { "CHAN", 11, 0 }, + { "P", 12, 0 }, + { NULL, 0, 0 } + } +}; + +static struct def_word word2_base_station_challenge_order_confirmation = { + "Word 2 - Base Station Challenge Order Confirmation", + { + { "T1T2", 2, 0 }, + { "RSVD", 4, 0 }, + { "AUTHBS", 18, 0 }, + { "RSVD", 4, 0 }, + { "P", 12, 0 }, + { NULL, 0, 0 } + } +}; + +static struct def_word word2_unique_challenge_order_word = { + "Word 2 - Unique Challenge Order Word", + { + { "T1T2", 2, 0 }, + { "RSVD", 2, 0 }, + { "RANDU", 24, 0 }, + { "P", 12, 0 }, + { NULL, 0, 0 } + } +}; + +static struct def_word word2_first_ssd_update_order_word = { + "Word 2 - First SSD Update Order Word", + { + { "T1T2", 2, 0 }, + { "RANDSSD_1", 24, 0 }, + { "RSVD", 2, 0 }, + { "P", 12, 0 }, + { NULL, 0, 0 } + } +}; + +static struct def_word word2_first_alert_with_info_word = { + "Word 2 - First Alert With Info Word", + { + { "T1T2", 2, 0 }, + { "RL_W", 5, 0 }, + { "SIGNAL", 8, 0 }, + { "CPN_RL", 6, 0 }, + { "PI", 2, 0 }, + { "SI", 2, 0 }, + { "RSVD", 3, 0 }, + { "P", 12, 0 }, + { NULL, 0, 0 } + } +}; + +static struct def_word word2_first_flash_with_info_word = { + "Word 2 - First Flash With Info Word", + { + { "T1T2", 2, 0 }, + { "RL_W", 5, 0 }, + { "CPN_RL", 6, 0 }, + { "PI", 2, 0 }, + { "SI", 2, 0 }, + { "RSVD", 11, 0 }, + { "P", 12, 0 }, + { NULL, 0, 0 } + } +}; + +static struct def_word word3_second_ssd_update_oder_word = { + "Word 3 - Second SSD Update Order Word", + { + { "T1T2", 2, 0 }, + { "RANDSSD_2", 24, 0 }, + { "RSVD", 2, 0 }, + { "P", 12, 0 }, + { NULL, 0, 0 } + } +}; + +static struct def_word word3_second_alert_with_info_word = { + "Word 3 - Second Alert With Info Word", + { + { "T1T2", 2, 0 }, + { "RSVD", 2, 0 }, + { "CHARACTER 1", 8, 0 }, + { "CHARACTER 2", 8, 0 }, + { "CHARACTER 3", 8, 0 }, + { "P", 12, 0 }, + { NULL, 0, 0 } + } +}; + +static struct def_word word3_second_alert_with_info_cri_message_word = { + "Word 3 - Second Alert With Info CRI Message Word", + { + { "T1T2", 2, 0 }, + { "RSVD", 2, 0 }, + { "CRI E14", 4, 0 }, + { "CRI E13", 4, 0 }, + { "CRI E12", 4, 0 }, + { "CRI E11", 4, 0 }, + { "CRI E24", 4, 0 }, + { "CRI E23", 4, 0 }, + { "P", 12, 0 }, + { NULL, 0, 0 } + } +}; + +static struct def_word word3_second_alert_with_info_tci_message_word = { + "Word 3 - Second Alert With Info TCI Message Word", + { + { "T1T2", 2, 0 }, + { "RSVD", 2, 0 }, + { "TCI1", 7, 0 }, + { "TCI5", 1, 0 }, + { "TCI24", 4, 0 }, + { "TCI23", 4, 0 }, + { "TCI22", 4, 0 }, + { "TCI21", 4, 0 }, + { "P", 12, 0 }, + { NULL, 0, 0 } + } +}; + +static struct def_word word3_second_flash_with_info_word = { + "Word 3 - Second Flash With Info Word", + { + { "T1T2", 2, 0 }, + { "RSVD", 2, 0 }, + { "CHARACTER 1", 8, 0 }, + { "CHARACTER 2", 8, 0 }, + { "CHARACTER 3", 8, 0 }, + { "P", 12, 0 }, + { NULL, 0, 0 } + } +}; + +static struct def_word word3_second_flash_with_info_cri_message_word = { + "Word 3 - Second Flash With Info CRI Message Word", + { + { "T1T2", 2, 0 }, + { "RSVD", 2, 0 }, + { "CRI E14", 4, 0 }, + { "CRI E13", 4, 0 }, + { "CRI E12", 4, 0 }, + { "CRI E11", 4, 0 }, + { "CRI E24", 4, 0 }, + { "CRI E23", 4, 0 }, + { "P", 12, 0 }, + { NULL, 0, 0 } + } +}; + +static struct def_word word3_second_flash_with_info_tci_message_word = { + "Word 3 - Second Flash With Info TCI Message Word", + { + { "T1T2", 2, 0 }, + { "RSVD", 2, 0 }, + { "TCI1", 7, 0 }, + { "TCI5", 1, 0 }, + { "TCI24", 4, 0 }, + { "TCI23", 4, 0 }, + { "TCI22", 4, 0 }, + { "TCI21", 4, 0 }, + { "P", 12, 0 }, + { NULL, 0, 0 } + } +}; + +static struct def_word word4_third_ssd_update_order_word = { + "Word 4 - Third SSD Update Order Word", + { + { "T1T2", 2, 0 }, + { "RANDSSD_3", 8, 0 }, + { "RSVD", 18, 0 }, + { "P", 12, 0 }, + { NULL, 0, 0 } + } +}; + +static struct def_word word4_third_alert_with_info_word = { + "Word 4 - Third Alert With Info Word", + { + { "T1T2", 2, 0 }, + { "RSVD", 2, 0 }, + { "CHARACTER 1", 8, 0 }, + { "CHARACTER 2", 8, 0 }, + { "CHARACTER 3", 8, 0 }, + { "P", 12, 0 }, + { NULL, 0, 0 } + } +}; + +static struct def_word word4_third_alert_with_info_cri_message_word = { + "Word 4 - Third Alert With Info CRI Word", + { + { "T1T2", 2, 0 }, + { "RSVD", 2, 0 }, + { "CRI E22", 4, 0 }, + { "CRI E21", 4, 0 }, + { "CRI E34", 4, 0 }, + { "CRI E33", 4, 0 }, + { "CRI E32", 4, 0 }, + { "CRI E31", 4, 0 }, + { "P", 12, 0 }, + { NULL, 0, 0 } + } +}; + +static struct def_word word4_third_alert_with_info_tci_message_word = { + "Word 4 - Third Alert With Info TCI Message Word", + { + { "T1T2", 2, 0 }, + { "RSVD", 2, 0 }, + { "TCI34", 7, 0 }, + { "TCI33", 1, 0 }, + { "TCI32", 4, 0 }, + { "TCI31", 4, 0 }, + { "TCI44", 4, 0 }, + { "TCI43", 4, 0 }, + { "P", 12, 0 }, + { NULL, 0, 0 } + } +}; + +static struct def_word word4_third_flash_with_info_word = { + "Word 4 - Third Flash With Info Word", + { + { "T1T2", 2, 0 }, + { "RSVD", 2, 0 }, + { "CHARACTER 1", 8, 0 }, + { "CHARACTER 2", 8, 0 }, + { "CHARACTER 3", 8, 0 }, + { "P", 12, 0 }, + { NULL, 0, 0 } + } +}; + +static struct def_word word4_third_flash_with_info_cri_message_word = { + "Word 4 - Third Flash With Info CRI Message Word", + { + { "T1T2", 2, 0 }, + { "RSVD", 2, 0 }, + { "CRI E22", 4, 0 }, + { "CRI E21", 4, 0 }, + { "CRI E34", 4, 0 }, + { "CRI E33", 4, 0 }, + { "CRI E32", 4, 0 }, + { "CRI E31", 4, 0 }, + { "P", 12, 0 }, + { NULL, 0, 0 } + } +}; + +static struct def_word word4_third_flash_with_info_tci_message_word = { + "Word 4 - Third Flash With Info TCI Message Word", + { + { "T1T2", 2, 0 }, + { "RSVD", 2, 0 }, + { "TCI34", 4, 0 }, + { "TCI33", 4, 0 }, + { "TCI32", 4, 0 }, + { "TCI31", 4, 0 }, + { "TCI44", 4, 0 }, + { "TCI43", 4, 0 }, + { "P", 12, 0 }, + { NULL, 0, 0 } + } +}; + +static struct def_word word5_alert_with_info_word = { + "Word 5 - Fourth Alert With Info Word", + { + { "T1T2", 2, 0 }, + { "RSVD", 2, 0 }, + { "CHARACTER 1", 8, 0 }, + { "CHARACTER 2", 8, 0 }, + { "CHARACTER 3", 8, 0 }, + { "P", 12, 0 }, + { NULL, 0, 0 } + } +}; + +static struct def_word word5_alert_with_info_cri_message_word = { + "Word 5 - Fourth Alert With Info CRI Message Word", + { + { "T1T2", 2, 0 }, + { "RSVD", 2, 0 }, + { "CRI E44", 4, 0 }, + { "CRI E43", 4, 0 }, + { "CRI E42", 4, 0 }, + { "CRI E41", 4, 0 }, + { "CRI E54", 4, 0 }, + { "CRI E53", 4, 0 }, + { "P", 12, 0 }, + { NULL, 0, 0 } + } +}; + +static struct def_word word5_alert_with_info_tci_message_word = { + "Word 5 - Fourth Alert With Info TCI Message Word", + { + { "T1T2", 2, 0 }, + { "RSVD", 2, 0 }, + { "TCI42", 4, 0 }, + { "TCI41", 4, 0 }, + { "NULL", 8, 0 }, + { "NULL", 8, 0 }, + { "P", 12, 0 }, + { NULL, 0, 0 } + } +}; + +static struct def_word word5_flash_with_info_word = { + "Word 5 - Fourth Flash With Info Word", + { + { "T1T2", 2, 0 }, + { "RSVD", 2, 0 }, + { "CHARACTER 1", 8, 0 }, + { "CHARACTER 2", 8, 0 }, + { "CHARACTER 3", 8, 0 }, + { "P", 12, 0 }, + { NULL, 0, 0 } + } +}; + +static struct def_word word5_flash_with_info_cri_message_word = { + "Word 5 - Fourth Flash With Info CRI Message Word", + { + { "T1T2", 2, 0 }, + { "RSVD", 2, 0 }, + { "CRI E44", 4, 0 }, + { "CRI E43", 4, 0 }, + { "CRI E42", 4, 0 }, + { "CRI E41", 4, 0 }, + { "CRI E54", 4, 0 }, + { "CRI E53", 4, 0 }, + { "P", 12, 0 }, + { NULL, 0, 0 } + } +}; + +static struct def_word word5_flash_with_info_tci_message_word = { + "Word 5 - Fourth Flash With Info TCI Message Word", + { + { "T1T2", 2, 0 }, + { "RSVD", 2, 0 }, + { "TCI42", 4, 0 }, + { "TCI41", 4, 0 }, + { "NULL", 8, 0 }, + { "NULL", 8, 0 }, + { "P", 12, 0 }, + { NULL, 0, 0 } + } +}; + +static struct def_word wordn_n_minus_1th_alert_with_info_word = { + "Word N - (N-1)th Alert With Info Word", + { + { "T1T2", 2, 0 }, + { "RSVD", 2, 0 }, + { "CHARACTER 1", 8, 0 }, + { "CHARACTER 2", 8, 0 }, + { "CHARACTER 3", 8, 0 }, + { "P", 12, 0 }, + { NULL, 0, 0 } + } +}; + +static struct def_word word6_fifth_alert_with_info_cri_mesage_word = { + "Word 6 - Fifth Alert With Info CRI Message Word", + { + { "T1T2", 2, 0 }, + { "RSVD", 2, 0 }, + { "CRI E52", 4, 0 }, + { "CRI E51", 4, 0 }, + { "CRI E64", 4, 0 }, + { "CRI E63", 4, 0 }, + { "CRI E62", 4, 0 }, + { "CRI E61", 4, 0 }, + { "P", 12, 0 }, + { NULL, 0, 0 } + } +}; + +static struct def_word word7_sixth_alert_with_info_cri_mesage_word = { + "Word 7 - Sixth Alert With Info CRI Message Word", + { + { "T1T2", 2, 0 }, + { "RSVD", 2, 0 }, + { "CRI E74", 4, 0 }, + { "CRI E73", 4, 0 }, + { "CRI E72", 4, 0 }, + { "CRI E71", 4, 0 }, + { "CRI E84", 4, 0 }, + { "CRI E83", 4, 0 }, + { "P", 12, 0 }, + { NULL, 0, 0 } + } +}; + +static struct def_word word8_seventh_alert_with_info_cri_mesage_word = { + "Word 8 - Seventh Alert With Info CRI Message Word", + { + { "T1T2", 2, 0 }, + { "RSVD", 2, 0 }, + { "CRI E82", 4, 0 }, + { "CRI E81", 4, 0 }, + { "NULL", 8, 0 }, + { "NULL", 8, 0 }, + { "P", 12, 0 }, + { NULL, 0, 0 } + } +}; + +static struct def_word wordn_n_minus_1th_flash_with_info_word = { + "Word N - (N-1)th Flash With Info Word", + { + { "T1T2", 2, 0 }, + { "RSVD", 2, 0 }, + { "CHARACTER 1", 8, 0 }, + { "CHARACTER 2", 8, 0 }, + { "CHARACTER 3", 8, 0 }, + { "P", 12, 0 }, + { NULL, 0, 0 } + } +}; + +static struct def_word word6_fith_flash_with_info_cri_message_word = { + "Word 6 - Fifth Flash With Info CRI Message Word", + { + { "T1T2", 2, 0 }, + { "RSVD", 2, 0 }, + { "CRI E52", 4, 0 }, + { "CRI E51", 4, 0 }, + { "CRI E64", 4, 0 }, + { "CRI E63", 4, 0 }, + { "CRI E62", 4, 0 }, + { "CRI E61", 4, 0 }, + { "P", 12, 0 }, + { NULL, 0, 0 } + } +}; + +static struct def_word word7_sixth_flash_with_info_cri_message_word = { + "Word 7 - Sixth Flash With Info CRI Message Word", + { + { "T1T2", 2, 0 }, + { "RSVD", 2, 0 }, + { "CRI E74", 4, 0 }, + { "CRI E73", 4, 0 }, + { "CRI E72", 4, 0 }, + { "CRI E71", 4, 0 }, + { "CRI E84", 4, 0 }, + { "CRI E83", 4, 0 }, + { "P", 12, 0 }, + { NULL, 0, 0 } + } +}; + +static struct def_word word8_seventh_flash_with_info_cri_message_word = { + "Word 8 - Seventh Flash With Info CRI Message Word", + { + { "T1T2", 2, 0 }, + { "RSVD", 2, 0 }, + { "CRI E82", 4, 0 }, + { "CRI E81", 4, 0 }, + { "NULL", 8, 0 }, + { "NULL", 8, 0 }, + { "P", 12, 0 }, + { NULL, 0, 0 } + } +}; + +static struct def_message_set fvc_words = { + "FVC Words", 40, + { + &mobile_station_control_message_word1_a, + &mobile_station_control_message_word1_b, + &word2_digital_channel_assignment, + &word2_digital_control_channel_information_word, + &word2_base_station_challenge_order_confirmation, + &word2_unique_challenge_order_word, + &word2_first_ssd_update_order_word, + &word2_first_alert_with_info_word, + &word2_first_flash_with_info_word, + &word3_second_ssd_update_oder_word, + &word3_second_alert_with_info_word, + &word3_second_alert_with_info_cri_message_word, + &word3_second_alert_with_info_tci_message_word, + &word3_second_flash_with_info_word, + &word3_second_flash_with_info_cri_message_word, + &word3_second_flash_with_info_tci_message_word, + &word4_third_ssd_update_order_word, + &word4_third_alert_with_info_word, + &word4_third_alert_with_info_cri_message_word, + &word4_third_alert_with_info_tci_message_word, + &word4_third_flash_with_info_word, + &word4_third_flash_with_info_cri_message_word, + &word4_third_flash_with_info_tci_message_word, + &word5_alert_with_info_word, + &word5_alert_with_info_cri_message_word, + &word5_alert_with_info_tci_message_word, + &word5_flash_with_info_word, + &word5_flash_with_info_cri_message_word, + &word5_flash_with_info_tci_message_word, + &wordn_n_minus_1th_alert_with_info_word, + &word6_fifth_alert_with_info_cri_mesage_word, + &word7_sixth_alert_with_info_cri_mesage_word, + &word8_seventh_alert_with_info_cri_mesage_word, + &wordn_n_minus_1th_flash_with_info_word, + &word6_fith_flash_with_info_cri_message_word, + &word7_sixth_flash_with_info_cri_message_word, + &word8_seventh_flash_with_info_cri_message_word, + NULL + } +}; + +/* RVC - Order Confirmation Message */ + +static struct def_word order_confirmation_message = { + "Order/Order Confirmation Message", + { + { "F", 1, 0 }, + { "NAWC", 2, 0 }, + { "T", 1, 0 }, + { "LOCAL/MSG TYPE", 5, 0 }, + { "ORDQ", 3, 0 }, + { "ORDER", 5, 0 }, + { "RSVD", 19, 0 }, + { "P", 12, 0 }, + { NULL, 0, 0 } + } +}; + +/* RVC - Called-Address Message */ + +static struct def_word word1_called_address = { + "Word 1 - First Word of the Called-Address", + { + { "F", 1, 0 }, + { "NAWC", 2, 0 }, + { "T", 1, 0 }, + { "DIGIT 1", 4, 0 }, + { "DIGIT 2", 4, 0 }, + { "DIGIT 3", 4, 0 }, + { "DIGIT 4", 4, 0 }, + { "DIGIT 5", 4, 0 }, + { "DIGIT 6", 4, 0 }, + { "DIGIT 7", 4, 0 }, + { "DIGIT 8", 4, 0 }, + { "P", 12, 0 }, + { NULL, 0, 0 } + } +}; + +static struct def_word word2_called_address = { + "Word 2 - Second Word of the Called-Address", + { + { "F", 1, 0 }, + { "NAWC", 2, 0 }, + { "T", 1, 0 }, + { "DIGIT 9", 4, 0 }, + { "DIGIT 10", 4, 0 }, + { "DIGIT 11", 4, 0 }, + { "DIGIT 12", 4, 0 }, + { "DIGIT 13", 4, 0 }, + { "DIGIT 14", 4, 0 }, + { "DIGIT 15", 4, 0 }, + { "DIGIT 16", 4, 0 }, + { "P", 12, 0 }, + { NULL, 0, 0 } + } +}; + +static struct def_word word3_called_address = { + "Word 3 - Third Word of the Called-Address", + { + { "F", 1, 0 }, + { "NAWC", 2, 0 }, + { "T", 1, 0 }, + { "DIGIT 17", 4, 0 }, + { "DIGIT 18", 4, 0 }, + { "DIGIT 19", 4, 0 }, + { "DIGIT 20", 4, 0 }, + { "DIGIT 21", 4, 0 }, + { "DIGIT 22", 4, 0 }, + { "DIGIT 23", 4, 0 }, + { "DIGIT 24", 4, 0 }, + { "P", 12, 0 }, + { NULL, 0, 0 } + } +}; + +static struct def_word word4_called_address = { + "Word 4 - Fourth Word of the Called-Address", + { + { "F", 1, 0 }, + { "NAWC", 2, 0 }, + { "T", 1, 0 }, + { "DIGIT 25", 4, 0 }, + { "DIGIT 26", 4, 0 }, + { "DIGIT 27", 4, 0 }, + { "DIGIT 28", 4, 0 }, + { "DIGIT 29", 4, 0 }, + { "DIGIT 30", 4, 0 }, + { "DIGIT 31", 4, 0 }, + { "DIGIT 32", 4, 0 }, + { "P", 12, 0 }, + { NULL, 0, 0 } + } +}; + +/* RVC - Serial Number Response Message */ + +static struct def_word word1_serial_number_response_message = { + "Word 1 of Serial Number Response Message", + { + { "F", 1, 0 }, + { "NAWC", 2, 0 }, + { "T", 1, 0 }, + { "LOCAL/MSG TYPE", 5, 0 }, + { "ORDQ", 3, 0 }, + { "ORDER", 5, 0 }, + { "RSVD", 19, 0 }, + { "P", 12, 0 }, + { NULL, 0, 0 } + } +}; + +static struct def_word word2_serial_number_response_message = { + "Word 2 of Serial Number response message", + { + { "F", 1, 0 }, + { "NAWC", 2, 0 }, + { "T", 1, 0 }, + { "ESN", 32, 0 }, + { "P", 12, 0 }, + { NULL, 0, 0 } + } +}; + +static struct def_word page_response = { + "Page Response", + { + { "F", 1, 0 }, + { "NAWC", 2, 0 }, + { "T", 1, 0 }, + { "LOCAL/MSG TYPE", 5, 0 }, + { "ORDQ", 3, 0 }, + { "ORDER", 5, 0 }, + { "RSVD", 19, 0 }, + { "P", 12, 0 }, + { NULL, 0, 0 } + } +}; + +static struct def_word challenge_order_confirmation_message = { + "Unique Challenge Order Confirmation Message", + { + { "F", 1, 0 }, + { "NAWC", 2, 0 }, + { "T", 1, 0 }, + { "LOCAL/MSG TYPE", 5, 0 }, + { "ORDQ", 3, 0 }, + { "ORDER", 5, 0 }, + { "AUTHU", 18, 0 }, + { "RSVD", 1, 0 }, + { "P", 12, 0 }, + { NULL, 0, 0 } + } +}; + +/* RVC - Base Station Challenge Order Message */ + +static struct def_word word1_base_station_challenge_order_message = { + "Word 1 of Base Station Challenge Order Message", + { + { "F", 1, 0 }, + { "NAWC", 2, 0 }, + { "T", 1, 0 }, + { "LOCAL/MSG TYPE", 5, 0 }, + { "ORDQ", 3, 0 }, + { "ORDER", 5, 0 }, + { "RSVD", 19, 0 }, + { "P", 12, 0 }, + { NULL, 0, 0 } + } +}; + +static struct def_word word2_base_station_challenge_order_message = { + "Word 2 of Base Station Challenge Order Message", + { + { "F", 1, 0 }, + { "NAWC", 2, 0 }, + { "T", 1, 0 }, + { "RANDBS", 32, 0 }, + { "P", 12, 0 }, + { NULL, 0, 0 } + } +}; + +static struct def_message_set rvc_words = { + "RVC Words", 48, + { + &order_confirmation_message, + &word1_called_address, + &word2_called_address, + &word3_called_address, + &word4_called_address, + &word1_serial_number_response_message, + &word2_serial_number_response_message, + &page_response, + &challenge_order_confirmation_message, + &word1_base_station_challenge_order_message, + &word2_base_station_challenge_order_message, + NULL + } +}; + +static struct def_message_set *amps_message_sets[] = { + &focc_words, + &recc_words, + &fvc_words, + &rvc_words, + NULL +}; + +static const char *amps_act[16] = { + "Reserved", + "Rescan paging channels", + "Registration increment", + "Location Area", + "Reserved", + "Reserved", + "New access channel set", + "Random Challenge A", + "Overload control", + "Access type parameters", + "Access attempt parameters", + "Random Challenge B", + "Reserved", + "Reserved", + "Local Control 1", + "Local Control 2", +}; + +static const char *ie_hex(uint64_t value) +{ + static char string[64]; + + sprintf(string, "0x%" PRIx64, value); + return string; +} + +static const char *ie_act(uint64_t value) +{ + return amps_act[value & 0xf]; +} + +static const char *ie_yes(uint64_t value) +{ + if (value) + return "Yes"; + return "No"; +} + +static const char *ie_bis(uint64_t value) +{ + if (value) + return "Wait for Idle-Busy transition"; + return "Ignore Idle-Busy after access"; +} + +static const char *ie_bscap(uint64_t value) +{ + switch (value) { + case 0: + return "Reserved for backward compatibility"; + case 1: + return "ANSI TIA/EIA-553-A"; + } + return "Reserved"; +} + +static const char *ie_bspc(uint64_t value) +{ + switch (value) { + case 0: + return "Reserved for backward compatibility"; + case 2: + return "IS-91A or TIA/EIA-691"; + case 3: + return "TIA/EIA-136-B"; + case 4: + return "IS-95B or TIA/EIA-95"; + } + return "Reserved"; +} + +static const char *ie_chan(uint64_t value) +{ + static char string[32]; + + if (value == 0) + return "No channel"; + sprintf(string, "%" PRIu64 " = %.3f MHz", value, amps_channel2freq(value, 0)); + return string; +} + +static const char *ie_cmac(uint64_t value) +{ + switch (value) { + case 0: + return "6 dbW"; + case 1: + return "2 dbW"; + case 2: + return "-2 dbW"; + case 3: + return "-6 dbW"; + case 4: + return "-10 dbW"; + case 5: + return "-14 dbW"; + case 6: + return "-18 dbW"; + } + return "-22"; +} + +static const char *ie_cmax(uint64_t value) +{ + static char string[32]; + + sprintf(string, "%" PRIu64, value + 1); + return string; +} + +static const char *ie_n(uint64_t value) +{ + static char string[32]; + + sprintf(string, "%" PRIu64, value + 1); + return string; +} + +static const char *ie_dtx_support(uint64_t value) +{ + switch (value) { + case 0: + return "DTX Not Supported"; + case 2: + return "DTX Supported up to 8 dB attenuation"; + case 3: + return "DTX Supported with no limit on attenuation"; + } + return "Reserved"; +} + +static const char *ie_hyperband(uint64_t value) +{ + switch (value) { + case 0: + return "800 MHz"; + case 1: + return "1900 MHz"; + } + return "Reserved"; +} + +static const char *ie_enabled(uint64_t value) +{ + if (value) + return "Enabled"; + return "Disabled"; +} + +static const char *amps_ohd[8] = { + "Registration ID", + "Control-Filler", + "Control Channel Information", + "Reserved", + "Global action", + "Reserved", + "Word 1 of system parameter message", + "Word 2 of system parameter message", +}; + +static const char *ie_ohd(uint64_t value) +{ + return amps_ohd[value & 0x7]; +} + +static const char *amps_t1t2[4] = { + "Only Word 1", + "First Word", + "Next Word", + "Overhead Message", +}; + +static const char *ie_t1t2(uint64_t value) +{ + return amps_t1t2[value & 0x3]; +} + +static const char *ie_digit(uint64_t value) +{ + static char string[32]; + + switch (value) { + case 0: + return "NULL"; + case 10: + return "0"; + case 11: + return "*"; + case 12: + return "#"; + case 13: + return "+"; + case 14: + return "reserved 15"; + case 15: + return "reserved 16"; + } + sprintf(string, "%" PRIu64, value); + return string; +} + +static const char *ie_mscap(uint64_t value) +{ + switch (value) { + case 0: + return "Reserved for backward compatibility"; + case 1: + return "TIA/EIA-553-A"; + } + return "Reserved"; +} + +static const char *ie_mspc(uint64_t value) +{ + switch (value) { + case 0: + return "Reserved for backward compatibility"; + case 1: + return "TIA/EIA-553-A"; + case 2: + return "IS-91A"; + case 3: + return "TIA/EIA-136-B"; + case 4: + return "IS-95B"; + } + return "Reserved"; +} + +static const char *ie_service_code(uint64_t value) +{ + switch (value) { + case 4: + return "Async Data"; + case 5: + return "G3 Fax"; + case 6: + return "Service Rejected"; + case 8: + return "Direct Async Data Service"; + } + return "Reserved"; +} + +static const char *amps_scc[4] = { + "5970 Hz", + "6000 Hz", + "6030 Hz", + "Word 2 includes message", +}; + +static const char *ie_scc(uint64_t value) +{ + return amps_scc[value & 0x3]; +} + +static const char *amps_acked_data[2] = { + "Acknowledged data, unacknowledged data, or both", + "Unacknowledged data only", +}; + +static const char *ie_acked_data(uint64_t value) +{ + return amps_acked_data[value & 0x1]; +} + +static const char *ie_ascii(uint64_t value) +{ + static char string[32]; + + if (value >= 32 && value <= 126) + sprintf(string, "'%c'", (char)value); + else + sprintf(string, "0x%02x", (unsigned char)value); + + return string; +} + +static const char *amps_crc[4] = { + "16-bit CRC", + "24-bit CRC", + "No CRC", + "Reserved", +}; + +static const char *ie_crc(uint64_t value) +{ + return amps_crc[value & 0x3]; +} + +static const char *ie_data_part(uint64_t value) +{ + switch (value) { + case 0: + return "See TIA/EIA-136-350"; + case 1: + return "STU-II (Standard FSVS211)"; + } + return "Reserved"; +} + +static const char *amps_mpci[4] = { + "indicates TIA/EIA-553 or IS-54A mobile station", + "indicates TIA/EIA-627 dual-mode mobile station", + "reserved (see TIA/EIA IS-95)", + "indicates EIATIA/EIA-136 dual-mode mobile station", +}; + +static const char *ie_mpci(uint64_t value) +{ + return amps_mpci[value & 0x3]; +} + +static const char *amps_pi[4] = { + "Presentation Allowed", + "Presentation Restricted", + "Number Not Available", + "Reserved", +}; + +static const char *ie_pi(uint64_t value) +{ + return amps_pi[value & 0x3]; +} + +static const char *ie_pm_d(uint64_t value) +{ + switch (value) { + case 0: + return "No Data Privacy"; + case 1: + return "Data Privacy Algorithm A (ORYX)"; + case 2: + return "Data Privacy Algorithm B (SCEMA)"; + } + return "Reserved"; +} + +static const char *amps_pvi[2] = { + "TIA/EIA 627", + "TIA/EIA-136", +}; + +static const char *ie_pvi(uint64_t value) +{ + return amps_pvi[value & 0x1]; +} + +static const char *ie_rlp(uint64_t value) +{ + switch (value) { + case 0: + return "RLP1"; + case 1: + return "RLP2"; + } + return "Reserved"; +} + +static const char *amps_sap[2] = { + "SAP 0 only", + "SAP 0 and SAP 1", +}; + +static const char *ie_sap(uint64_t value) +{ + return amps_sap[value & 0x1]; +} + +static const char *ie_sbi(uint64_t value) +{ + switch (value) { + case 0: + return "Transmit normal burst after cell to cell handoff"; + case 1: + return "Transmit normal burst after handoff within cell"; + case 2: + return "Transmit shortened burst after cell to cell handoff"; + } + return "Reserved"; +} + +static const char *amps_ie_si[4] = { + "User-provided, not screened", + "User-provided, verified and passed", + "User-provided, verified and failed", + "Network-provided", +}; + +static const char *ie_si(uint64_t value) +{ + return amps_ie_si[value & 0x3]; +} + +static const char *ie_signal(uint64_t value) +{ + static char string[256]; + const char *pitch, *cadence; + + switch ((value >> 6) & 0x3) { + case 0: + pitch = "Medium pitch"; + break; + case 1: + pitch = "High pitch"; + break; + case 2: + pitch = "Low pitch"; + break; + default: + pitch = "Reserved"; + } + switch (value & 0x3f) { + case 0: + cadence = "No Tone"; + break; + case 1: + cadence = "Long"; + break; + case 2: + cadence = "Short-Short"; + break; + case 3: + cadence = "Short-Short-Long"; + break; + case 4: + cadence = "Short-Short-2"; + break; + case 5: + cadence = "Short-Long-Short"; + break; + case 6: + cadence = "Short-Short-Short-Short"; + break; + case 7: + cadence = "PBX Long"; + break; + case 8: + cadence = "PBX Short-Short"; + break; + case 9: + cadence = "PBX Short-Short-Long"; + break; + case 10: + cadence = "PBX Short-Long-Short"; + break; + case 11: + cadence = "PBX Short-Short-Short-Short"; + break; + default: + cadence = "Reserved"; + } + sprintf(string, "Pitch=%s, Cadence=%s", pitch, cadence); + + return string; +} + +static const char *ie_min1(uint64_t value) +{ + return amps_min12number(value); +} + +static const char *ie_min2(uint64_t value) +{ + return amps_min22number(value); +} + +static const char *ie_scm(uint64_t value) +{ + return amps_scm(value); +} + +struct amps_ie_desc { + enum amps_ie ie; + const char *name; + const char *desc; + const char *(*decoder)(uint64_t value); +}; + +struct amps_ie_desc amps_ie_desc[] = { + { AMPS_IE_010111, "010111", "bit combination 23", NULL }, + { AMPS_IE_1, "1", "bit combination 1", NULL }, + { AMPS_IE_11, "11", "bit combination 3", NULL }, + { AMPS_IE_1111, "1111", "bit combination 15", NULL }, + { AMPS_IE_ACT, "ACT", "Global action field", ie_act }, + { AMPS_IE_AUTH, "AUTH", "Support of authentication procedures described in TIA/EIA-136-510", ie_yes }, + { AMPS_IE_AUTHBS, "AUTHBS", "Output response of the authentication algorithm initiated by the Base Station Challenge Order", ie_hex }, + { AMPS_IE_AUTHR, "AUTHR", "Output response of the authentication algorithm", ie_hex }, + { AMPS_IE_AUTHU, "AUTHU", "Output of the authentication algorithm when responsing to a Unique Challenge Order", ie_hex }, + { AMPS_IE_Acked_Data, "Acked Data", "Used to identidy the selected privacy mode for a data/fax call", ie_acked_data }, + { AMPS_IE_Async_Data, "Async Data", "Async Data is supported on the current Analog Control Channel", ie_yes }, + { AMPS_IE_BIS, "BIS", "Busy-Idle status field", ie_bis }, + { AMPS_IE_BSCAP, "BSCAP", "Base Station Core Analog Protocol field", ie_bscap }, + { AMPS_IE_BSPC, "BSPC", "Base Station Protocol Capability field", ie_bspc }, + { AMPS_IE_CHAN, "CHAN", "Channel number field", ie_chan }, + { AMPS_IE_CHANPOS, "CHANPOS", "Channel position field (relative to FIRSTCHA)", NULL }, + { AMPS_IE_CHARACTER_1, "CHARACTER 1", "ASCII Character", ie_ascii }, + { AMPS_IE_CHARACTER_2, "CHARACTER 2", "ASCII Character", ie_ascii }, + { AMPS_IE_CHARACTER_3, "CHARACTER 3", "ASCII Character", ie_ascii }, + { AMPS_IE_CMAC, "CMAC", "Control mobile attenuation field", ie_cmac }, + { AMPS_IE_CMAX_1, "CMAX-1", "CMAX is the number of access channels in the system", ie_cmax }, + { AMPS_IE_COUNT, "COUNT", "A modulo-64 count for authenticaiton", NULL }, + { AMPS_IE_CPA, "CPA", "Combined paging/access field", ie_yes }, + { AMPS_IE_CPN_RL, "CPN_RL", "Number of Characters in Calling Party Number", NULL }, + { AMPS_IE_CRC, "CRC", "Identifies used CRC", ie_crc }, + { AMPS_IE_CRI_E11, "CRI E11", "Charing Rate Indication Element 1 Digit 1", NULL }, + { AMPS_IE_CRI_E12, "CRI E12", "Charing Rate Indication Element 1 Digit 2", NULL }, + { AMPS_IE_CRI_E13, "CRI E13", "Charing Rate Indication Element 1 Digit 3", NULL }, + { AMPS_IE_CRI_E14, "CRI E14", "Charing Rate Indication Element 1 Digit 4", NULL }, + { AMPS_IE_CRI_E21, "CRI E21", "Charing Rate Indication Element 2 Digit 1", NULL }, + { AMPS_IE_CRI_E22, "CRI E22", "Charing Rate Indication Element 2 Digit 2", NULL }, + { AMPS_IE_CRI_E23, "CRI E23", "Charing Rate Indication Element 2 Digit 3", NULL }, + { AMPS_IE_CRI_E24, "CRI E24", "Charing Rate Indication Element 2 Digit 4", NULL }, + { AMPS_IE_CRI_E31, "CRI E31", "Charing Rate Indication Element 3 Digit 1", NULL }, + { AMPS_IE_CRI_E32, "CRI E32", "Charing Rate Indication Element 3 Digit 2", NULL }, + { AMPS_IE_CRI_E33, "CRI E33", "Charing Rate Indication Element 3 Digit 3", NULL }, + { AMPS_IE_CRI_E34, "CRI E34", "Charing Rate Indication Element 3 Digit 4", NULL }, + { AMPS_IE_CRI_E41, "CRI E41", "Charing Rate Indication Element 4 Digit 1", NULL }, + { AMPS_IE_CRI_E42, "CRI E42", "Charing Rate Indication Element 4 Digit 2", NULL }, + { AMPS_IE_CRI_E43, "CRI E43", "Charing Rate Indication Element 4 Digit 3", NULL }, + { AMPS_IE_CRI_E44, "CRI E44", "Charing Rate Indication Element 4 Digit 4", NULL }, + { AMPS_IE_CRI_E51, "CRI E51", "Charing Rate Indication Element 5 Digit 1", NULL }, + { AMPS_IE_CRI_E52, "CRI E52", "Charing Rate Indication Element 5 Digit 2", NULL }, + { AMPS_IE_CRI_E53, "CRI E53", "Charing Rate Indication Element 5 Digit 3", NULL }, + { AMPS_IE_CRI_E54, "CRI E54", "Charing Rate Indication Element 5 Digit 4", NULL }, + { AMPS_IE_CRI_E61, "CRI E61", "Charing Rate Indication Element 6 Digit 1", NULL }, + { AMPS_IE_CRI_E62, "CRI E62", "Charing Rate Indication Element 6 Digit 2", NULL }, + { AMPS_IE_CRI_E63, "CRI E63", "Charing Rate Indication Element 6 Digit 3", NULL }, + { AMPS_IE_CRI_E64, "CRI E64", "Charing Rate Indication Element 6 Digit 4", NULL }, + { AMPS_IE_CRI_E71, "CRI E71", "Charing Rate Indication Element 7 Digit 1", NULL }, + { AMPS_IE_CRI_E72, "CRI E72", "Charing Rate Indication Element 7 Digit 2", NULL }, + { AMPS_IE_CRI_E73, "CRI E73", "Charing Rate Indication Element 7 Digit 3", NULL }, + { AMPS_IE_CRI_E74, "CRI E74", "Charing Rate Indication Element 7 Digit 4", NULL }, + { AMPS_IE_CRI_E81, "CRI E81", "Charing Rate Indication Element 8 Digit 1", NULL }, + { AMPS_IE_CRI_E82, "CRI E82", "Charing Rate Indication Element 8 Digit 2", NULL }, + { AMPS_IE_CRI_E83, "CRI E83", "Charing Rate Indication Element 8 Digit 3", NULL }, + { AMPS_IE_CRI_E84, "CRI E84", "Charing Rate Indication Element 8 Digit 4", NULL }, + { AMPS_IE_DCC, "DCC", "Digital color code field", NULL }, + { AMPS_IE_DIGIT_1, "DIGIT 1", "Digit field", ie_digit }, + { AMPS_IE_DIGIT_10, "DIGIT 10", "Digit field", ie_digit }, + { AMPS_IE_DIGIT_11, "DIGIT 11", "Digit field", ie_digit }, + { AMPS_IE_DIGIT_12, "DIGIT 12", "Digit field", ie_digit }, + { AMPS_IE_DIGIT_13, "DIGIT 13", "Digit field", ie_digit }, + { AMPS_IE_DIGIT_14, "DIGIT 14", "Digit field", ie_digit }, + { AMPS_IE_DIGIT_15, "DIGIT 15", "Digit field", ie_digit }, + { AMPS_IE_DIGIT_16, "DIGIT 16", "Digit field", ie_digit }, + { AMPS_IE_DIGIT_17, "DIGIT 17", "Digit field", ie_digit }, + { AMPS_IE_DIGIT_18, "DIGIT 18", "Digit field", ie_digit }, + { AMPS_IE_DIGIT_19, "DIGIT 19", "Digit field", ie_digit }, + { AMPS_IE_DIGIT_2, "DIGIT 2", "Digit field", ie_digit }, + { AMPS_IE_DIGIT_20, "DIGIT 20", "Digit field", ie_digit }, + { AMPS_IE_DIGIT_21, "DIGIT 21", "Digit field", ie_digit }, + { AMPS_IE_DIGIT_22, "DIGIT 22", "Digit field", ie_digit }, + { AMPS_IE_DIGIT_23, "DIGIT 23", "Digit field", ie_digit }, + { AMPS_IE_DIGIT_24, "DIGIT 24", "Digit field", ie_digit }, + { AMPS_IE_DIGIT_25, "DIGIT 25", "Digit field", ie_digit }, + { AMPS_IE_DIGIT_26, "DIGIT 26", "Digit field", ie_digit }, + { AMPS_IE_DIGIT_27, "DIGIT 27", "Digit field", ie_digit }, + { AMPS_IE_DIGIT_28, "DIGIT 28", "Digit field", ie_digit }, + { AMPS_IE_DIGIT_29, "DIGIT 29", "Digit field", ie_digit }, + { AMPS_IE_DIGIT_3, "DIGIT 3", "Digit field", ie_digit }, + { AMPS_IE_DIGIT_30, "DIGIT 30", "Digit field", ie_digit }, + { AMPS_IE_DIGIT_31, "DIGIT 31", "Digit field", ie_digit }, + { AMPS_IE_DIGIT_32, "DIGIT 32", "Digit field", ie_digit }, + { AMPS_IE_DIGIT_4, "DIGIT 4", "Digit field", ie_digit }, + { AMPS_IE_DIGIT_5, "DIGIT 5", "Digit field", ie_digit }, + { AMPS_IE_DIGIT_6, "DIGIT 6", "Digit field", ie_digit }, + { AMPS_IE_DIGIT_7, "DIGIT 7", "Digit field", ie_digit }, + { AMPS_IE_DIGIT_8, "DIGIT 8", "Digit field", ie_digit }, + { AMPS_IE_DIGIT_9, "DIGIT 9", "Digit field", ie_digit }, + { AMPS_IE_DMAC, "DMAC", "Digital mobile attenuation code field", ie_cmac }, + { AMPS_IE_DTX, "DTX", "Discontinuous-Transmission field", ie_yes }, + { AMPS_IE_DTX_Support, "DTX Support", "Indicates the nature of DTX supported on an analog voice", ie_dtx_support }, + { AMPS_IE_DVCC, "DVCC", "Digital Verfication Color Code", NULL}, + { AMPS_IE_Data_Part, "Data Part", "Identifies the Data Port associated with a data/fax call", ie_data_part }, + { AMPS_IE_Data_Privacy, "Data Privacy", "This field indicates whether or not Data Privacy is supported", ie_yes }, + { AMPS_IE_E, "E", "Extended address field", ie_yes }, + { AMPS_IE_EC, "EC", "Extended Protocol Reverse Channel", ie_yes }, + { AMPS_IE_EF, "EF", "Extended Protocol Forward Channel Indicator", ie_yes }, + { AMPS_IE_END, "END", "End indication field", ie_yes }, + { AMPS_IE_EP, "EP", "Extended Protocol Capability Indicator", ie_yes }, + { AMPS_IE_ER, "ER", "Extended Protocol Reverse Channel", ie_yes }, + { AMPS_IE_ESN, "ESN", "Electronic Serial Number field", NULL }, + { AMPS_IE_F, "F", "First word indication Field", ie_yes }, + { AMPS_IE_G3_Fax, "G3 Fax", "This field indicates whether or not G3 Fax is supported", ie_yes }, + { AMPS_IE_HDVCC, "HDVCC", "Half Digital Verification Color Code", NULL }, + { AMPS_IE_Hyperband, "Hyperband", "Designates Hyperband associated with the Digital Control Channel specified by the CHAN field", ie_hyperband }, + { AMPS_IE_LOCAID, "LOCAID", "Location area identity field", NULL }, + { AMPS_IE_LOCAL_CONTROL, "LOCAL CONTROL", "May be set to any bit pattern", NULL }, + { AMPS_IE_LOCAL_MSG_TYPE, "LOCAL/MSG TYPE", "Message Type field", NULL }, + { AMPS_IE_LREG, "LREG", "Location area ID registration status field", ie_enabled }, + { AMPS_IE_LT, "LT", "Last-try code field", ie_yes }, + { AMPS_IE_MAXBUSY_OTHER, "MAXBUSY-OTHER", "Maximum busy occurrences field (other accesses)", NULL }, + { AMPS_IE_MAXBUSY_PGR, "MAXBUSY-PGR", "Maximum busy occurrences field (page response)", NULL }, + { AMPS_IE_MAXSZTR_OTHER, "MAXSZTR-OTHER", "Maximum seizure tries field (other accesses)", NULL }, + { AMPS_IE_MAXSZTR_PGR, "MAXSZTR-PGR", "Maximum seizure tries field (page response)", NULL }, + { AMPS_IE_MEM, "MEM", "Message Encryption Mode", ie_yes }, + { AMPS_IE_MIN1, "MIN1", "First part of the mobile identification number field", ie_min1 }, + { AMPS_IE_MIN2, "MIN2", "Second part of the mobile identification number field", ie_min2 }, + { AMPS_IE_MPCI, "MPCI", "Mobile station Protocol Indicator", ie_mpci }, + { AMPS_IE_MSCAP, "MSCAP", "Mobile Station Core Analog Protocol field", ie_mscap }, + { AMPS_IE_MSPC, "MSPC", "Mobile Station Protocol Capability field", ie_mspc }, + { AMPS_IE_N_1, "N-1", "N is the number of paging channels in the system", ie_n }, + { AMPS_IE_NAWC , "NAWC", "Number of additional words coming field", NULL }, + { AMPS_IE_NEWACC, "NEWACC", "New access channel starting point field", ie_chan }, + { AMPS_IE_NULL, "NULL", "Null character", NULL }, + { AMPS_IE_OHD, "OHD", "Overhead Message Type field", ie_ohd }, + { AMPS_IE_OLC_0, "OLC 0", "Overload class field 0", NULL }, + { AMPS_IE_OLC_1, "OLC 1", "Overload class field 1", NULL }, + { AMPS_IE_OLC_10, "OLC 10", "Overload class field 10", NULL }, + { AMPS_IE_OLC_11, "OLC 11", "Overload class field 11", NULL }, + { AMPS_IE_OLC_12, "OLC 12", "Overload class field 12", NULL }, + { AMPS_IE_OLC_13, "OLC 13", "Overload class field 13", NULL }, + { AMPS_IE_OLC_14, "OLC 14", "Overload class field 14", NULL }, + { AMPS_IE_OLC_15, "OLC 15", "Overload class field 15", NULL }, + { AMPS_IE_OLC_2, "OLC 2", "Overload class field 2", NULL }, + { AMPS_IE_OLC_3, "OLC 3", "Overload class field 3", NULL }, + { AMPS_IE_OLC_4, "OLC 4", "Overload class field 4", NULL }, + { AMPS_IE_OLC_5, "OLC 5", "Overload class field 5", NULL }, + { AMPS_IE_OLC_6, "OLC 6", "Overload class field 6", NULL }, + { AMPS_IE_OLC_7, "OLC 7", "Overload class field 7", NULL }, + { AMPS_IE_OLC_8, "OLC 8", "Overload class field 8", NULL }, + { AMPS_IE_OLC_9, "OLC 9", "Overload class field 9", NULL }, + { AMPS_IE_ORDER, "ORDER", "Order field", NULL }, + { AMPS_IE_ORDQ, "ORDQ", "Order qualifier field", NULL }, + { AMPS_IE_P, "P", "Parity field", NULL }, + { AMPS_IE_PCI, "PCI", "Set to 1 if Control Channel can assign digital traffic channels", ie_yes }, + { AMPS_IE_PCI_HOME, "PCI_HOME", "Home Protocol Capability Indicator", ie_yes }, + { AMPS_IE_PCI_ROAM, "PCI_ROAM", "Roam Protocol Capability Indicator", ie_yes }, + { AMPS_IE_PDREG, "PDREG", "Power Down Registration status field (enabled = 1, disabled = 0)", ie_yes }, + { AMPS_IE_PI, "PI", "Presentation Indicator", ie_pi }, + { AMPS_IE_PM, "PM", "Privacy Mode indicator", ie_yes }, + { AMPS_IE_PM_D, "PM_D", "Privacy Mode indicator for Fax/Data", ie_pm_d }, + { AMPS_IE_PSCC, "PSCC", "Present SAT color code", ie_scc }, + { AMPS_IE_PUREG, "PUREG", "Power Up Registration status field (enabled = 1, disabled = 0)", ie_yes }, + { AMPS_IE_PVI, "PVI", "Protocol Version Indicator", ie_pvi }, + { AMPS_IE_RAND1_A, "RAND1_A", "The 16 most significant bits of the 32-bit RAND variable stored by a mobile station for use in the authentication process", ie_hex }, + { AMPS_IE_RAND1_B, "RAND1_B", "The 16 least significant bits of the 32-bit RAND variable stored by a mobile station for use in the authentication process", ie_hex }, + { AMPS_IE_RANDBS, "RANDBS", "Random number used in the SSD Update procedure", ie_hex }, + { AMPS_IE_RANDC, "RANDC", "Confirm the last RAND received by the mobile station", ie_hex }, + { AMPS_IE_RANDSSD_1, "RANDSSD_1", "The most significant 24 bits of the random number issued by the base station in the SSD Update Order", ie_hex }, + { AMPS_IE_RANDSSD_2, "RANDSSD_2", "The subsequent 24 bits (following RANDSSD_1) of the random number issued by the base station in the SSD Update Order", ie_hex }, + { AMPS_IE_RANDSSD_3, "RANDSSD_3", "The least significant 8 bits of the random number issued by the base station in the SSD Update Order", ie_hex }, + { AMPS_IE_RANDU, "RANDU", "The 24-bit random number issued by the base station in the Unique Challenge Order", ie_hex }, + { AMPS_IE_RCF, "RCF", "Read-control-filler field", ie_yes }, + { AMPS_IE_REGH, "REGH", "Registration field for home stations", ie_yes }, + { AMPS_IE_REGID, "REGID", "Registration ID field", NULL }, + { AMPS_IE_REGINCR, "REGINCR", "Registration increment field", NULL }, + { AMPS_IE_REGR, "REGR", "Registration field for roaming stations", ie_yes }, + { AMPS_IE_RLP, "RLP", "Identifies the layer 2 radio link protocol used for a data/fax call", ie_rlp }, + { AMPS_IE_RL_W, "RL_W", "The remaining length, in `Words' of the Alert With Info or Flash With Info order", NULL }, + { AMPS_IE_RSVD, "RSVD", "Reserved for future use", NULL }, + { AMPS_IE_S, "S", "Serial number field", ie_yes }, + { AMPS_IE_SAP, "SAP", "Service Access Point(s) used for data/fax call", ie_sap }, + { AMPS_IE_SBI, "SBI", "Short Burst Indication", ie_sbi }, + { AMPS_IE_SCC, "SCC", "SAT color code", ie_scc }, + { AMPS_IE_SCM, "SCM", "The station class mark field", ie_scm }, + { AMPS_IE_SDCC1, "SDCC1", "Supplementary Digital Color Codes", NULL }, + { AMPS_IE_SDCC2, "SDCC2", "Supplementary Digital Color Codes", NULL }, + { AMPS_IE_SI, "SI", "Screening Indicator", ie_si }, + { AMPS_IE_SID1, "SID1", "First part of the system identification field", NULL }, + { AMPS_IE_SIGNAL, "SIGNAL", "An 8-bit IE to cause MS to generate tones", ie_signal }, + { AMPS_IE_Service_Code, "Service Code", "Service Indicator", ie_service_code }, + { AMPS_IE_T, "T", "T field. 1 = Orig/Order 0 = (paging) response", NULL }, + { AMPS_IE_T1T2, "T1T2", "Type field", ie_t1t2 }, + { AMPS_IE_TA, "TA", "Time Alignment Offset", NULL }, + { AMPS_IE_TCI1, "TCI1", "Total Charing component", NULL }, + { AMPS_IE_TCI21, "TCI21", "Total Charing component", NULL }, + { AMPS_IE_TCI22, "TCI22", "Total Charing component", NULL }, + { AMPS_IE_TCI23, "TCI23", "Total Charing component", NULL }, + { AMPS_IE_TCI24, "TCI24", "Total Charing component", NULL }, + { AMPS_IE_TCI31, "TCI31", "Total Charing component", NULL }, + { AMPS_IE_TCI32, "TCI32", "Total Charing component", NULL }, + { AMPS_IE_TCI33, "TCI33", "Total Charing component", NULL }, + { AMPS_IE_TCI34, "TCI34", "Total Charing component", NULL }, + { AMPS_IE_TCI41, "TCI41", "Total Charing component", NULL }, + { AMPS_IE_TCI42, "TCI42", "Total Charing component", NULL }, + { AMPS_IE_TCI43, "TCI43", "Total Charing component", NULL }, + { AMPS_IE_TCI44, "TCI44", "Total Charing component", NULL }, + { AMPS_IE_TCI5, "TCI5", "Total Charing component", NULL }, + { AMPS_IE_VMAC, "VMAC", "Voice mobile attenuation code field", ie_cmac }, + { AMPS_IE_WFOM, "WFOM", "Wait-for-overhead-message field", ie_yes }, + { AMPS_IE_NUM, NULL, NULL } +}; + +static int ie_desc_max_len; + +/* decode 7 bit sequence to DCC code + * return -1 if failed */ +static int8_t dcc_decode[127]; + +/* encode DCC code to 7 bit sequence */ +static uint8_t dcc_encode[4] = { + 0x00, 0x1f, 0x63, 0x7c +}; + +struct amps_table4_def { + const char *order; + const char *ordq; + const char *msg_type; + const char *function; +} amps_table4_def[] = { + { "00001", "000", "00000", "Alert" }, + { "00001", "001", "00000", "Abbreviated Alert" }, + { "10001", "000", "00000", "Alert With Info" }, + { "10001", "001", "00000", "Alert with Info CRI Message" }, + { "10001", "010", "00000", "Alert with Info TCI Message" }, + { "10010", "000", "00000", "Flash With Info" }, + { "10010", "001", "00000", "Flash with Info CRI Message" }, + { "10010", "010", "00000", "Flash with Info TCI Message" }, + { "00011", "000", "00000", "Release" }, + { "00011", "010", "00000", "Release with Digital Control Channel Information" }, + { "00011", "011", "00000", "Release Complete" }, + { "00100", "000", "00000", "Reorder" }, + { "00101", "000", "XXXXX", "Voice Message Waiting (Message Type field indicates number of messages, 11111 = unknown number of messages waiting)" }, + { "00101", "001", "XXXXX", "SMS Message Waiting (Message Type field indicates number of messages, 11111 = unknown number of messages waiting)" }, + { "00101", "010", "XXXXX", "G3-Fax Message Waiting (Message Type field indicates number of messages, 11111 = unknown number of messages waiting)" }, + { "00110", "000", "00000", "Stop Alert" }, + { "00111", "000", "00000", "Audit" }, + { "01000", "000", "00000", "Send Called-address" }, + { "01001", "000", "00000", "Intercept" }, + { "01010", "000", "00000", "Maintenance" }, + { "01011", "000", "00000", "Change Power to Power Level 0 (see TIA/EIA-136-270)" }, + { "01011", "001", "00000", "Change Power to Power Level 1" }, + { "01011", "010", "00000", "Change Power to Power Level 2" }, + { "01011", "011", "00000", "Change Power to Power Level 3" }, + { "01011", "100", "00000", "Change Power to Power Level 4" }, + { "01011", "101", "00000", "Change Power to Power Level 5" }, + { "01011", "110", "00000", "Change Power to Power Level 6" }, + { "01011", "111", "00000", "Change Power to Power Level 7" }, + { "01100", "000", "00000", "Directed Retry - not last try" }, + { "01100", "000", "00001", "Directed Retry to Primary Dedicated Control Channels - analog channels only, Authentication disabled, not last try" }, + { "01100", "000", "00010", "Directed Retry to Primary Dedicated Control Channels - analog channels only, Authentication enabled, not last try" }, + { "01100", "001", "00000", "Directed Retry - last try" }, + { "01100", "001", "00001", "Directed Retry to Primary Dedicated Control Channels - analog channels only, Authentication disabled, last try" }, + { "01111", "001", "00000", "Serial Number Request / Response" }, + { "01100", "001", "00010", "Directed Retry to Primary Dedicated Control Channels - analog channels only, Authentication enabled, last try" }, + { "01101", "010", "00000", "Autonomous Registration - Do not make whereabouts known, Authentication Word C not included" }, + { "01101", "011", "00000", "Autonomous Registration - Make whereabouts known, Authentication Word C not included" }, + { "01101", "011", "00001", "Autonomous Registration - Power Down, Authentication Word C not included" }, + { "11000", "010", "00000", "Autonomous Registration - Do not make whereabouts known, Authentication Word C included" }, + { "11000", "011", "00000", "Autonomous Registration - Make whereabouts known, Authentication Word C included" }, + { "11000", "011", "00001", "Autonomous Registration - Power Down, Authentication Word C included" }, + { "11010", "100", "00000", "PCI Query (report) Order/Order Confirmation - Authentication Word C not included" }, + { "11010", "100", "00001", "PCI Query (report) Order/Order Confirmation - Authentication Word C included" }, + { "11110", "000", "XXXXX", "local control" }, + /* (Base station initiated messages only - Page and Call Mode Ack messages) */ + { "00000", "000", "00000", "Page Message (Voice Service)" }, + { "00000", "000", "00001", "Page Message (Async Data)" }, + { "00000", "000", "00010", "Page Message (Group 3 Fax)" }, + { "10000", "000", "XXXX0", "Call Mode Ack: Analog Voice channel permissible" }, + { "10000", "000", "XXXX1", "Call Mode Ack: Analog Voice channel not permissible" }, + { "10000", "000", "XXX0X", "Call Mode Ack: Full-rate digital traffic channel not permissible (VSELP)" }, + { "10000", "000", "XXX1X", "Call Mode Ack: Full -rate digital traffic channel permissible, voice privacy off (VSELP)" }, + { "10000", "100", "XXX1X", "Call Mode Ack: Full -rate digital traffic channel permissible, voice privacy on (VSELP)" }, + { "10000", "000", "XX0XX", "Call Mode Ack: Half-rate digital traffic channel not permissible" }, + { "10000", "000", "XX1XX", "Call Mode Ack: Half-rate digital traffic channel permissible, voice privacy off" }, + { "10000", "100", "XX1XX", "Call Mode Ack: Half-rate digital traffic channel permissible, voice privacy on" }, + { "10000", "000", "X0XXX", "Call Mode Ack: Other DQPSK channel not permissible" }, + { "10000", "000", "X1XXX", "Call Mode Ack: Other DQPSK channel permissible" }, + { "10000", "000", "0XXXX", "Call Mode Ack: Other voice coding not permissible (see TIA/EIA-136-410)" }, + { "10000", "000", "1XXXX", "Call Mode Ack: Other voice coding permissible (see TIA/EIA-136-410), voice privacy off" }, + { "10000", "100", "1XXXX", "Call Mode Ack: Other voice coding permissible (see TIA/EIA-136-410), voice privacy on" }, + { "10000", "001", "XXXXX", "Call Mode Ack: Extended modulation and framing permissible" }, + /* (Mobile station initiated messages only - Origination and Page Response messages) */ + { "00000", "000", "XXXX0", "Analog Voice channel acceptable, Authentication Word C not included" }, + { "00000", "000", "XXXX1", "Analog Voice channel not acceptable, Authentication Word C not included" }, + { "00000", "000", "XXX0X", "Full-rate digital traffic channel (VSELP) not acceptable, Authentication Word C not included" }, + { "00000", "000", "XXX1X", "Full-rate digital traffic channel (VSELP) acceptable (voice privacy off), Authentication Word C not included" }, + { "00000", "100", "XXX1X", "Full-rate digital traffic channel (VSELP) acceptable (voice privacy on), Authentication Word C not included" }, + { "00000", "000", "XX0XX", "Half-rate digital traffic channel not acceptable, Authentication Word C not included" }, + { "00000", "000", "XX1XX", "Half-rate digital traffic channel acceptable (voice privacy off), Authentication Word C not included" }, + { "00000", "100", "XX1XX", "Half-rate digital traffic channel acceptable (voice privacy on), Authentication Word C not included" }, + { "00000", "000", "X0XXX", "Other DQPSK channel not acceptable, Authentication Word C not included" }, + { "00000", "000", "X1XXX", "Other DQPSK channel acceptable, Authentication Word C not included" }, + { "00000", "000", "0XXXX", "Other voice coding not acceptable, (see TIA/EIA-136-410), Authentication Word C not included" }, + { "00000", "000", "1XXXX", "Other voice coding acceptable (see TIA/EIA-136-410), (voice privacy off), Authentication Word C not included" }, + { "00000", "100", "1XXXX", "Other voice coding acceptable (see TIA/EIA-136-410), (voice privacy on), Authentication Word C not included" }, + { "00000", "001", "XXXXX", "Extended Modulation and Framing, Authentication Word C not included" }, + { "00010", "000", "XXXX0", "Analog Voice Channel (AVC) acceptable, Authentication Word C included" }, + { "00010", "000", "XXXX1", "AVC not acceptable, Auth. Word C included" }, + { "00010", "000", "XXX0X", "Full-rate digital traffic channel (VSELP) not acceptable, Authentication Word C included" }, + { "00010", "000", "XXX1X", "Full-rate digital traffic channel (VSELP) acceptable (voice privacy off), Authentication Word C included" }, + { "00010", "100", "XXX1X", "Full-rate digital traffic channel (VSELP) acceptable (voice privacy on), Authentication Word C included" }, + { "00010", "000", "XX0XX", "Half-rate digital traffic channel not acceptable, Authentication Word C included" }, + { "00010", "000", "XX1XX", "Half-rate digital traffic channel acceptable (voice privacy off), Authentication Word C included" }, + { "00010", "100", "XX1XX", "Half-rate digital traffic channel acceptable (voice privacy on), Authentication Word C included" }, + /* (Mobile station initiated messages only - Origination and Page Response messages) */ + { "00010", "000", "X0XXX", "Other DQPSK channel not acceptable, Authentication Word C included" }, + { "00010", "000", "X1XXX", "Other DQPSK channel acceptable, Authentication Word C included" }, + { "00010", "000", "0XXXX", "Other voice coding not acceptable, (see TIA/EIA-136-410), Authentication Word C included" }, + { "00010", "000", "1XXXX", "Other voice coding acceptable (see TIA/EIA-136-410), (voice privacy off), Authentication Word C included" }, + { "00010", "100", "1XXXX", "Other voice coding acceptable (see TIA/EIA-136-410), (voice privacy on), Authentication Word C included" }, + { "00010", "001", "XXXXX", "Extended Modulation and Framing, Authentication Word C included" }, + /* (Mobile station initiated messages only - Origination with Service and Page Response with Service messages) */ + { "11101", "000", "XXX0X", "Full-rate DTC not acceptable, Authentication Word C not included" }, + { "11101", "000", "XXX1X", "Full-rate DTC acceptable, Authentication Word C not included" }, + { "11101", "000", "XX0XX", "Half-rate DTC not acceptable, Authentication Word C not included" }, + { "11101", "000", "XX1XX", "Half-rate DTC acceptable, Authentication Word C not included" }, + { "11101", "000", "X0XXX", "Other DQPSK channel not acceptable, Authentication Word C not included" }, + { "11101", "000", "X1XXX", "Other DQPSK channel acceptable, Authentication Word C not included" }, + { "11101", "000", "0XXXX", "Other voice coding not acceptable, Authentication Word C not included" }, + { "11101", "000", "1XXXX", "Other voice coding acceptable, Authentication Word C not included" }, + { "11101", "001", "XXXXX", "Extended Modulation and Framing, Authentication Word C not included" }, + { "11101", "010", "XXX0X", "Double Full-Rate or Full-Rate Digital Traffic Channel not acceptable, Authentication Word C not included" }, + { "11101", "010", "XXX1X", "Double Full-Rate or Full-Rate Digital Traffic Channel acceptable - Double-Rate Preferred, Authentication Word C not included" }, + { "11101", "010", "XX0XX", "Triple Full-Rate, Double Full-Rate, or Full-Rate Digital Traffic Channel not acceptable, Authentication Word C not included" }, + { "11101", "010", "XX1XX", "Triple Full-Rate, Double Full-Rate, or Full-Rate Digital Traffic Channel acceptable - Triple Rate Preferred, Authentication Word C not included" }, + { "11101", "010", "X0XXX", "Double Full-Rate Digital Traffic Channel not acceptable, Authentication Word C not included" }, + { "11101", "010", "X1XXX", "Double Full-Rate Digital Traffic Channel acceptable, Authentication Word C not included" }, + { "11101", "010", "0XXXX", "Triple Full-Rate Digital Traffic Channel not acceptable, Authentication Word C not included" }, + { "11101", "010", "1XXXX", "Triple Full-Rate Digital Traffic Channel acceptable, Authentication Word C not included" }, + { "11111", "000", "XXX0X", "Full-rate DTC not acceptable, Authentication Word C included" }, + /* (Mobile station initiated messages only - Origination with Service and Page Response with Service messages) */ + { "11111", "000", "XXX1X", "Full-rate DTC acceptable, Authentication Word C included" }, + { "11111", "000", "XX0XX", "Half-rate DTC not acceptable, Authentication Word C included" }, + { "11111", "000", "XX1XX", "Half-rate DTC acceptable, Authentication Word C included" }, + { "11111", "000", "X0XXX", "Other DQPSK channel not acceptable, Authentication Word C included" }, + { "11111", "000", "X1XXX", "Other DQPSK channel acceptable, Authentication Word C included" }, + { "11111", "000", "0XXXX", "Other voice coding not acceptable, Authentication Word C included" }, + { "11111", "000", "1XXXX", "Other voice coding acceptable, Authentication Word C included" }, + { "11111", "001", "XXXXX", "Extended Modulation and Framing, Authentication Word C included" }, + { "11111", "010", "XXX0X", "Double Full-Rate or Full-Rate Digital Traffic Channel not acceptable, Authentication Word C included" }, + { "11111", "010", "XXX1X", "Double Full-Rate Digital Traffic Channel acceptable - Double-Rate Preferred, Authentication Word C included" }, + { "11111", "010", "XX0XX", "Triple Full-Rate, Double Full-Rate, or Full-Rate Digital Traffic Channel not acceptable, Authentication Word C included" }, + { "11111", "010", "XX1XX", "Triple Full-Rate, Double Full-Rate, or Full-Rate Digital Traffic Channel acceptable - Triple Rate Preferred, Authentication Word C included" }, + { "11111", "010", "X0XXX", "Double Full-Rate Digital Traffic Channel not acceptable, Authentication Word C included" }, + { "11111", "010", "X1XXX", "Double Full-Rate Digital Traffic Channel acceptable, Authentication Word C included" }, + { "11111", "010", "0XXXX", "Triple Full-Rate Digital Traffic Channel not acceptable, Authentication Word C included" }, + { "11111", "010", "1XXXX", "Triple Full-Rate Digital Traffic Channel acceptable, Authentication Word C included" }, + /* (Base station initiated messages only - Initial Traffic Channel Designation message) */ + { "01110", "000", "00001", "DTC Assignment for TIA/EIA 627 Minimum Dual-Mode: Assigned to timeslot 1, full-rate (VSELP)" }, + { "01110", "000", "01001", "DTC Assignment for TIA/EIA 627 Minimum Dual-Mode: Assigned to timeslot 1, half-rate" }, + { "01110", "000", "00010", "DTC Assignment for TIA/EIA 627 Minimum Dual-Mode: Assigned to timeslot 2, full-rate (VSELP)" }, + { "01110", "000", "01010", "DTC Assignment for TIA/EIA 627 Minimum Dual-Mode: Assigned to timeslot 2 , half-rate" }, + { "01110", "000", "00011", "DTC Assignment for TIA/EIA 627 Minimum Dual-Mode: Assigned to timeslot 3, full-rate (VSELP)" }, + { "01110", "000", "01011", "DTC Assignment for TIA/EIA 627 Minimum Dual-Mode: Assigned to timeslot 3, half-rate" }, + { "01110", "000", "01100", "DTC Assignment for TIA/EIA 627 Minimum Dual-Mode: Assigned to timeslot 4, half-rate" }, + { "01110", "000", "01101", "DTC Assignment for TIA/EIA 627 Minimum Dual-Mode: Assigned to timeslot 5, half-rate" }, + { "01110", "000", "01110", "DTC Assignment for TIA/EIA 627 Minimum Dual-Mode: Assigned to timeslot 6, half-rate" }, + { "01110", "010", "00001", "DTC Assignment for IS-136: Assigned to timeslot 1, full-rate (VSELP)" }, + { "01110", "010", "01001", "DTC Assignment for IS-136: Assigned to timeslot 1, half-rate" }, + { "01110", "010", "00010", "DTC Assignment for IS-136: Assigned to timeslot 2, full-rate (VSELP)" }, + { "01110", "010", "01010", "DTC Assignment for IS-136: Assigned to timeslot 2 , half-rate" }, + { "01110", "010", "00011", "DTC Assignment for IS-136: Assigned to timeslot 3, full-rate (VSELP)" }, + { "01110", "010", "01011", "DTC Assignment for IS-136: Assigned to timeslot 3, half-rate" }, + { "01110", "010", "01100", "DTC Assignment for IS-136: Assigned to timeslot 4, half-rate" }, + { "01110", "010", "01101", "DTC Assignment for IS-136: Assigned to timeslot 5, half-rate" }, + { "01110", "010", "01110", "DTC Assignment for IS-136: Assigned to timeslot 6, half-rate" }, + /* (Base station initiated messages only - Initial Traffic Channel Designation message) */ + { "01110", "010", "10001", "DTC Assignment for TIA/EIA-136: Assigned to timeslot 1, full-rate (see TIA/EIA-136-410)" }, + { "01110", "010", "10010", "DTC Assignment for TIA/EIA-136: Assigned to timeslot 2, full-rate (see TIA/EIA-136-410)" }, + { "01110", "010", "10011", "DTC Assignment for TIA/EIA-136: Assigned to timeslot 3, full-rate (see TIA/EIA-136-410)" }, + { "01110", "100", "00001", "DTC Assignment for TIA/EIA-136: Assigned to timeslot 1, full-rate (Fax/Data)" }, + { "01110", "100", "00010", "DTC Assignment for TIA/EIA-136: Assigned to timeslot 2, full-rate (Fax/Data)" }, + { "01110", "100", "00011", "DTC Assignment for TIA/EIA-136: Assigned to timeslot 3, full-rate (Fax/Data)" }, + { "01110", "100", "00100", "DTC Assignment for TIA/EIA-136: Assigned to timeslots 1 & 2, double rate (Fax/Data)" }, + { "01110", "100", "00101", "DTC Assignment for TIA/EIA-136: Assigned to timeslots 1 & 3, double rate (Fax/Data)" }, + { "01110", "100", "00110", "DTC Assignment for TIA/EIA-136: Assigned to timeslots 2 & 3, double rate (Fax/Data)" }, + { "01110", "100", "00111", "DTC Assignment for TIA/EIA-136: Assigned to timeslots 1, 2 & 3, triple rate (Fax/Data)" }, + { "01110", "001", "XXXXX", "Digital Traffic Channel Assignment with Extended Modulation and Framing" }, + { "11010", "000", "00000", "Analog Voice Channel Assignment" }, + /* (Base station initiated messages only - Mobile Station Authentication and Privacy) */ + { "01111", "000", "00000", "Parameter Update Order" }, + { "10011", "000", "00000", "Base Station Challenge Order Confirmation" }, + { "10100", "000", "00000", "Unique Challenge Order" }, + { "10101", "000", "00000", "SSD Update Order" }, + { "10110", "000", "00000", "Disable DTMF Order" }, + { "10111", "000", "00000", "Message Encryption Mode Order with disable indication" }, + { "10111", "001", "00000", "Message Encryption Mode Order with enable indication" }, + /* (Mobile station initiated messages only - Mobile Station Authentication and Privacy) */ + { "01111", "000", "00000", "Parameter Update Order/Confirmation" }, + { "10011", "000", "00000", "Base Station Challenge Order" }, + { "10100", "000", "00000", "Unique Challenge Order Confirmation" }, + { "10101", "000", "00000", "SSD Update Order Confirmation with failure indication" }, + { "10101", "001", "00000", "SSD Update Order Confirmation with success indication" }, + { "10111", "000", "00000", "Message Encryption Mode Order Confirmation with disable indication" }, + { "10111", "001", "00000", "Message Encryption Mode Order Confirmation with enable indication" }, + { NULL, NULL, NULL, NULL } +}; + +struct amps_table4 { + uint8_t order; + uint8_t ordq; + uint8_t msg_type; + uint8_t msg_type_mask; + const char *function; +} *amps_table4; + +static void gen_table4(void) +{ + uint8_t value, mask; + int i, j; + + /* count entries including last one */ + for (i = 0; amps_table4_def[i].function; i++) + ; + amps_table4 = calloc(i + 1, sizeof(struct amps_table4)); + if (!amps_table4) { + fprintf(stderr, "No mem!\n"); + abort(); + } + + + for (i = 0; amps_table4_def[i].function; i++) { + if (strlen(amps_table4_def[i].order) != 5 + || strlen(amps_table4_def[i].ordq) != 3 + || strlen(amps_table4_def[i].msg_type) != 5) { + fprintf(stderr, "Error in table definition entry %d: Wrong length!\n", i); + abort(); + } + value = 0; + for (j = 0; j < 5; j++) { + if (amps_table4_def[i].order[j] == '1') + value = (value << 1) | 1; + else if (amps_table4_def[i].order[j] != '0') { + fprintf(stderr, "Error in table definition entry %d: Wrong digit!\n", i); + abort(); + } else + value = (value << 1); + } + amps_table4[i].order = value; + value = 0; + for (j = 0; j < 3; j++) { + if (amps_table4_def[i].ordq[j] == '1') + value = (value << 1) | 1; + else if (amps_table4_def[i].ordq[j] != '0') { + fprintf(stderr, "Error in table definition entry %d: Wrong digit!\n", i); + abort(); + } else + value = (value << 1); + } + amps_table4[i].ordq = value; + value = 0; + mask = 0; + for (j = 0; j < 5; j++) { + if (amps_table4_def[i].msg_type[j] == '1') { + value = (value << 1) | 1; + mask = (mask << 1) | 1; + } else if (amps_table4_def[i].msg_type[j] == '0') { + value = (value << 1); + mask = (mask << 1) | 1; + } else if (amps_table4_def[i].msg_type[j] == 'X') { + value = (value << 1); + mask = (mask << 1); + } else { + fprintf(stderr, "Error in table definition entry %d: Wrong digit!\n", i); + abort(); + } + } + amps_table4[i].msg_type = value; + amps_table4[i].msg_type_mask = mask; + amps_table4[i].function = amps_table4_def[i].function; + } +} + +static const char *amps_table4_name(uint8_t msg_type, uint8_t ordq, uint8_t order) +{ + int i; + + for (i = 0; amps_table4[i].function; i++) { +//printf("c %d %d %d with %d %d %d\n", msg_type, ordq, order, amps_table4[i].msg_type, amps_table4[i].ordq, amps_table4[i].order); + if (amps_table4[i].order == order + && amps_table4[i].ordq == ordq + && amps_table4[i].msg_type == (msg_type & amps_table4[i].msg_type_mask)) + return amps_table4[i].function; + } + return ("Unknown message type"); +} + +void init_frame(void) +{ + struct def_message_set **ms; + struct def_word **w; + struct def_ie *ie; + struct amps_ie_desc *ied; + int num_bits, bits; + int i, j; + uint8_t dcc; + + ie_desc_max_len = 0; + for (i = 0; amps_ie_desc[i].name; i++) { + if (strlen(amps_ie_desc[i].name) > ie_desc_max_len) + ie_desc_max_len = strlen(amps_ie_desc[i].name); + if (i != amps_ie_desc[i].ie) { + fprintf(stderr, "IEs #%d in amps_ie_desc is different from definitions AMPS_IE_xxx (%d), please fix!\n", i, amps_ie_desc[i].ie); + abort(); + } + if (amps_ie_desc[i + 1].name) { + if (strcmp(amps_ie_desc[i + 1].name, amps_ie_desc[i].name) <= 0) { + fprintf(stderr, "IE '%s' in amps_ie_desc list is not greater (unsorted) or is equal to '%s', please fix!\n", amps_ie_desc[i + 1].name, amps_ie_desc[i].name); + abort(); + } + } + } + if (i != AMPS_IE_NUM) { + fprintf(stderr, "number of IEs in amps_ie_desc (%d) is different from number of definitions AMPS_IE_xxx (%d), please fix!\n", i, AMPS_IE_NUM); + abort(); + } + + /* check message words */ + for (ms = amps_message_sets; *ms; ms++) { +// printf("Checking message set '%s'\n", (*ms)->name); + num_bits = (*ms)->num_bits; + for (w = (*ms)->word; *w; w++) { +// printf(" Checking message word '%s'\n", (*w)->name); + bits = 0; + for (ie = (*w)->ie; ie->name; ie++) { +// printf(" Checking ie '%s'\n", ie->name); + bits += ie->bits; + if (strchr(ie->name, '=')) { + fprintf(stderr, "IE name '%s' in '%s' has '=' character, please fix!\n", ie->name, (*w)->name); + abort(); + } + for (i = 0, ied = amps_ie_desc; ied->name; i++, ied++) { + if (!strcmp(ied->name, ie->name)) + break; + } + if (!ied->name) { + fprintf(stderr, "IE name '%s' not found in amps_ie_desc list, please fix!\n", ie->name); + abort(); + } + ie->ie = i; + } + if (bits != num_bits) { + fprintf(stderr, "Bits in '%s' is not %d, please fix!\n", (*w)->name, num_bits); + abort(); + } + } + } + + /* generate DCC decoding table */ + for (i = 0; i < 128; i++) + dcc_decode[i] = -1; + for (i = 0; i < 4; i++) { + dcc = dcc_encode[i]; + dcc_decode[dcc] = i; + /* one bit errors */ + for (j = 0; j < 7; j++) + dcc_decode[dcc ^ (1 << j)] = i; + } + + /* generate table 4 */ + gen_table4(); +} + + +/* + * encode and decode words + */ + +uint64_t amps_encode_word(frame_t *frame, struct def_word *w, int debug) +{ + uint64_t word, value; + char spaces[ie_desc_max_len + 1]; + int sum_bits, bits; + int i, t4 = 0; + + memset(spaces, ' ', ie_desc_max_len); + spaces[ie_desc_max_len] = '\0'; + + /* sum of bits */ + sum_bits = 0; + for (i = 0; w->ie[i].name; i++) + sum_bits += w->ie[i].bits; + + PDEBUG(DFRAME, (debug >= 0) ? DEBUG_INFO : DEBUG_DEBUG, "Transmit: %s\n", w->name); + word = 0; + for (i = 0; w->ie[i].name; i++) { + bits = w->ie[i].bits; + if (w->ie[i].name[0] == 'P' && w->ie[i].name[1] == '\0') + value = encode_bch_binary(word, sum_bits - bits); + else + value = frame->ie[w->ie[i].ie]; + word = (word << bits) | (value & cut_bits[bits]); + if (debug >= 0) { + if (amps_ie_desc[w->ie[i].ie].decoder) + PDEBUG(DFRAME, DEBUG_DEBUG, " %s%s: %" PRIu64 " = %s (%s)\n", spaces + strlen(w->ie[i].name), w->ie[i].name, value, amps_ie_desc[w->ie[i].ie].decoder(value), amps_ie_desc[w->ie[i].ie].desc); + else + PDEBUG(DFRAME, DEBUG_DEBUG, " %s%s: %" PRIu64 " (%s)\n", spaces + strlen(w->ie[i].name), w->ie[i].name, value, amps_ie_desc[w->ie[i].ie].desc); + } + /* show result for 3 IEs of table 4 */ + if (w->ie[i].ie == AMPS_IE_LOCAL_MSG_TYPE || w->ie[i].ie == AMPS_IE_ORDQ || w->ie[i].ie == AMPS_IE_ORDER) + t4++; + if (t4 == 3) { + t4 = 0; + if (debug >= 0) + PDEBUG(DFRAME, DEBUG_DEBUG, " %s--> %s\n", spaces, amps_table4_name(frame->ie[AMPS_IE_LOCAL_MSG_TYPE], frame->ie[AMPS_IE_ORDQ], frame->ie[AMPS_IE_ORDER])); + } + } + + return word; +} + +static uint64_t amps_encode_control_filler(uint8_t dcc, uint8_t cmac, uint8_t sdcc1, uint8_t sdcc2, uint8_t wfom) +{ + static frame_t frame; + + memset(&frame, 0, sizeof(frame)); + frame.ie[AMPS_IE_T1T2] = 3; + frame.ie[AMPS_IE_DCC] = dcc; + frame.ie[AMPS_IE_010111] = 23; + frame.ie[AMPS_IE_CMAC] = cmac; + frame.ie[AMPS_IE_SDCC1] = sdcc1; + frame.ie[AMPS_IE_11] = 3; + frame.ie[AMPS_IE_SDCC2] = sdcc2; + frame.ie[AMPS_IE_1] = 1; + frame.ie[AMPS_IE_WFOM] = wfom; + frame.ie[AMPS_IE_1111] = 15; + frame.ie[AMPS_IE_OHD] = 1; + return amps_encode_word(&frame, &control_filler, -1); +} + +uint64_t amps_encode_word1_system(uint8_t dcc, uint16_t sid1, uint8_t ep, uint8_t auth, uint8_t pci, uint8_t nawc) +{ + static frame_t frame; + + memset(&frame, 0, sizeof(frame)); + frame.ie[AMPS_IE_T1T2] = 3; + frame.ie[AMPS_IE_DCC] = dcc; + frame.ie[AMPS_IE_SID1] = sid1; + frame.ie[AMPS_IE_EP] = ep; + frame.ie[AMPS_IE_AUTH] = auth; + frame.ie[AMPS_IE_PCI] = pci; + frame.ie[AMPS_IE_NAWC] = nawc; + frame.ie[AMPS_IE_OHD] = 6; + return amps_encode_word(&frame, &word1_system_parameter_overhead, -1); +} + +uint64_t amps_encode_word2_system(uint8_t dcc, uint8_t s, uint8_t e, uint8_t regh, uint8_t regr, uint8_t dtx, uint8_t n_1, uint8_t rcf, uint8_t cpa, uint8_t cmax_1, uint8_t end) +{ + static frame_t frame; + + memset(&frame, 0, sizeof(frame)); + frame.ie[AMPS_IE_T1T2] = 3; + frame.ie[AMPS_IE_DCC] = dcc; + frame.ie[AMPS_IE_S] = s; + frame.ie[AMPS_IE_E] = e; + frame.ie[AMPS_IE_REGH] = regh; + frame.ie[AMPS_IE_REGR] = regr; + frame.ie[AMPS_IE_DTX] = dtx; + frame.ie[AMPS_IE_N_1] = n_1; + frame.ie[AMPS_IE_RCF] = rcf; + frame.ie[AMPS_IE_CPA] = cpa; + frame.ie[AMPS_IE_CMAX_1] = cmax_1; + frame.ie[AMPS_IE_END] = end; + frame.ie[AMPS_IE_OHD] = 7; + return amps_encode_word(&frame, &word2_system_parameter_overhead, -1); +} + +uint64_t amps_encode_registration_id(uint8_t dcc, uint32_t regid, uint8_t end) +{ + static frame_t frame; + + memset(&frame, 0, sizeof(frame)); + frame.ie[AMPS_IE_T1T2] = 3; + frame.ie[AMPS_IE_DCC] = dcc; + frame.ie[AMPS_IE_REGID] = regid; + frame.ie[AMPS_IE_END] = end; + frame.ie[AMPS_IE_OHD] = 0; + return amps_encode_word(&frame, ®istration_id, -1); +} + +uint64_t amps_encode_registration_increment(uint8_t dcc, uint16_t regincr, uint8_t end) +{ + static frame_t frame; + + memset(&frame, 0, sizeof(frame)); + frame.ie[AMPS_IE_T1T2] = 3; + frame.ie[AMPS_IE_DCC] = dcc; + frame.ie[AMPS_IE_ACT] = 2; + frame.ie[AMPS_IE_REGINCR] = regincr; + frame.ie[AMPS_IE_END] = end; + frame.ie[AMPS_IE_OHD] = 4; + return amps_encode_word(&frame, ®istration_increment_global_action, -1); +} + +uint64_t amps_encode_location_area(uint8_t dcc, uint8_t pureg, uint8_t pdreg, uint8_t lreg, uint16_t locaid, uint8_t end) +{ + static frame_t frame; + + memset(&frame, 0, sizeof(frame)); + frame.ie[AMPS_IE_T1T2] = 3; + frame.ie[AMPS_IE_DCC] = dcc; + frame.ie[AMPS_IE_ACT] = 3; + frame.ie[AMPS_IE_PUREG] = pureg; + frame.ie[AMPS_IE_PDREG] = pdreg; + frame.ie[AMPS_IE_LREG] = lreg; + frame.ie[AMPS_IE_LOCAID] = locaid; + frame.ie[AMPS_IE_END] = end; + frame.ie[AMPS_IE_OHD] = 4; + return amps_encode_word(&frame, &location_area_global_action, -1); +} + +uint64_t amps_encode_new_access_channel_set(uint8_t dcc, uint16_t newacc, uint8_t end) +{ + static frame_t frame; + + memset(&frame, 0, sizeof(frame)); + frame.ie[AMPS_IE_T1T2] = 3; + frame.ie[AMPS_IE_DCC] = dcc; + frame.ie[AMPS_IE_ACT] = 6; + frame.ie[AMPS_IE_NEWACC] = newacc; + frame.ie[AMPS_IE_END] = end; + frame.ie[AMPS_IE_OHD] = 4; + return amps_encode_word(&frame, &new_access_channel_set_global_action, -1); +} + +uint64_t amps_encode_overload_control(uint8_t dcc, uint8_t *olc, uint8_t end) +{ + static frame_t frame; + + memset(&frame, 0, sizeof(frame)); + frame.ie[AMPS_IE_T1T2] = 3; + frame.ie[AMPS_IE_DCC] = dcc; + frame.ie[AMPS_IE_ACT] = 8; + frame.ie[AMPS_IE_OLC_0] = olc[0]; + frame.ie[AMPS_IE_OLC_1] = olc[1]; + frame.ie[AMPS_IE_OLC_2] = olc[2]; + frame.ie[AMPS_IE_OLC_3] = olc[3]; + frame.ie[AMPS_IE_OLC_4] = olc[4]; + frame.ie[AMPS_IE_OLC_5] = olc[5]; + frame.ie[AMPS_IE_OLC_6] = olc[6]; + frame.ie[AMPS_IE_OLC_7] = olc[7]; + frame.ie[AMPS_IE_OLC_8] = olc[8]; + frame.ie[AMPS_IE_OLC_9] = olc[9]; + frame.ie[AMPS_IE_OLC_10] = olc[10]; + frame.ie[AMPS_IE_OLC_11] = olc[11]; + frame.ie[AMPS_IE_OLC_12] = olc[12]; + frame.ie[AMPS_IE_OLC_13] = olc[13]; + frame.ie[AMPS_IE_OLC_14] = olc[14]; + frame.ie[AMPS_IE_OLC_15] = olc[15]; + frame.ie[AMPS_IE_END] = end; + frame.ie[AMPS_IE_OHD] = 4; + return amps_encode_word(&frame, &overload_control_global_action, -1); +} + +uint64_t amps_encode_access_type(uint8_t dcc, uint8_t bis, uint8_t pci_home, uint8_t pci_roam, uint8_t bspc, uint8_t bscap, uint8_t end) +{ + static frame_t frame; + + memset(&frame, 0, sizeof(frame)); + frame.ie[AMPS_IE_T1T2] = 3; + frame.ie[AMPS_IE_DCC] = dcc; + frame.ie[AMPS_IE_ACT] = 9; + frame.ie[AMPS_IE_BIS] = bis; + frame.ie[AMPS_IE_PCI_HOME] = pci_home; + frame.ie[AMPS_IE_PCI_ROAM] = pci_roam; + frame.ie[AMPS_IE_BSPC] = bspc; + frame.ie[AMPS_IE_BSCAP] = bscap; + frame.ie[AMPS_IE_END] = end; + frame.ie[AMPS_IE_OHD] = 4; + return amps_encode_word(&frame, &access_type_parameters_global_action, -1); +} + +uint64_t amps_encode_access_attempt(uint8_t dcc, uint8_t maxbusy_pgr, uint8_t maxsztr_pgr, uint8_t maxbusy_other, uint8_t maxsztr_other, uint8_t end) +{ + static frame_t frame; + + memset(&frame, 0, sizeof(frame)); + frame.ie[AMPS_IE_T1T2] = 3; + frame.ie[AMPS_IE_DCC] = dcc; + frame.ie[AMPS_IE_ACT] = 10; + frame.ie[AMPS_IE_MAXBUSY_PGR] = maxbusy_pgr; + frame.ie[AMPS_IE_MAXSZTR_PGR] = maxsztr_pgr; + frame.ie[AMPS_IE_MAXBUSY_OTHER] = maxbusy_other; + frame.ie[AMPS_IE_MAXSZTR_OTHER] = maxsztr_other; + frame.ie[AMPS_IE_END] = end; + frame.ie[AMPS_IE_OHD] = 4; + return amps_encode_word(&frame, &access_attempt_parameters_global_action, -1); +} + +uint64_t amps_encode_word1_abbreviated_address_word(uint8_t dcc, uint32_t min1, int multiple) +{ + static frame_t frame; + + memset(&frame, 0, sizeof(frame)); + if (multiple) + frame.ie[AMPS_IE_T1T2] = 1; + else + frame.ie[AMPS_IE_T1T2] = 0; + frame.ie[AMPS_IE_DCC] = dcc; + frame.ie[AMPS_IE_MIN1] = min1; + return amps_encode_word(&frame, &word1_abbreviated_address_word, DEBUG_INFO); +} + +uint64_t amps_encode_word1_extended_address_word_a(uint16_t min2, uint8_t msg_type, uint8_t ordq, uint8_t order) +{ + static frame_t frame; + + memset(&frame, 0, sizeof(frame)); + frame.ie[AMPS_IE_T1T2] = 2; + frame.ie[AMPS_IE_SCC] = 11; + frame.ie[AMPS_IE_MIN2] = min2; + frame.ie[AMPS_IE_EF] = 0; + frame.ie[AMPS_IE_LOCAL_MSG_TYPE] = msg_type; + frame.ie[AMPS_IE_ORDQ] = ordq; + frame.ie[AMPS_IE_ORDER] = order; + return amps_encode_word(&frame, &word2_extended_address_word_a, DEBUG_INFO); +} + +uint64_t amps_encode_word1_extended_address_word_b(uint8_t scc, uint16_t min2, uint8_t vmac, uint16_t chan) +{ + static frame_t frame; + + memset(&frame, 0, sizeof(frame)); + frame.ie[AMPS_IE_T1T2] = 2; + frame.ie[AMPS_IE_SCC] = scc; + frame.ie[AMPS_IE_MIN2] = min2; + frame.ie[AMPS_IE_VMAC] = vmac; + frame.ie[AMPS_IE_CHAN] = chan; + return amps_encode_word(&frame, &word2_extended_address_word_b, DEBUG_INFO); +} + +uint64_t amps_encode_mobile_station_control_message_word1_a(uint8_t pscc, uint8_t msg_type, uint8_t ordq, uint8_t order) +{ + static frame_t frame; + + memset(&frame, 0, sizeof(frame)); + frame.ie[AMPS_IE_T1T2] = 2; + frame.ie[AMPS_IE_SCC] = 11; + frame.ie[AMPS_IE_PSCC] = pscc; + frame.ie[AMPS_IE_EF] = 0; + frame.ie[AMPS_IE_LOCAL_MSG_TYPE] = msg_type; + frame.ie[AMPS_IE_ORDQ] = ordq; + frame.ie[AMPS_IE_ORDER] = order; + return amps_encode_word(&frame, &mobile_station_control_message_word1_a, DEBUG_INFO); +} + +uint64_t amps_encode_mobile_station_control_message_word1_b(uint8_t scc, uint8_t pscc, uint8_t dtx, uint8_t pvi, uint8_t mem, uint8_t vmac, uint16_t chan) +{ + static frame_t frame; + + memset(&frame, 0, sizeof(frame)); + frame.ie[AMPS_IE_T1T2] = 2; + frame.ie[AMPS_IE_SCC] = scc; + frame.ie[AMPS_IE_PSCC] = pscc; + frame.ie[AMPS_IE_EF] = 0; + frame.ie[AMPS_IE_DTX] = dtx; + frame.ie[AMPS_IE_PVI] = pvi; + frame.ie[AMPS_IE_MEM] = mem; + frame.ie[AMPS_IE_VMAC] = vmac; + frame.ie[AMPS_IE_CHAN] = chan; + return amps_encode_word(&frame, &mobile_station_control_message_word1_b, DEBUG_INFO); +} + +/* decoder function of a word */ +static frame_t *amps_decode_word(uint64_t word, struct def_word *w) +{ + static frame_t frame; + char spaces[ie_desc_max_len + 1]; + int bits_left, bits; + uint64_t value; + int i, t4 = 0; + + memset(&frame, 0, sizeof(frame)); + + memset(spaces, ' ', ie_desc_max_len); + spaces[ie_desc_max_len] = '\0'; + + /* sum of bits */ + bits_left = 0; + for (i = 0; w->ie[i].name; i++) + bits_left += w->ie[i].bits; + + PDEBUG(DFRAME, DEBUG_INFO, "Received: %s\n", w->name); + for (i = 0; w->ie[i].name; i++) { + bits = w->ie[i].bits; + bits_left -= bits; + value = (word >> bits_left) & cut_bits[bits]; + frame.ie[w->ie[i].ie] = value; + if (amps_ie_desc[w->ie[i].ie].decoder) + PDEBUG(DFRAME, DEBUG_DEBUG, " %s%s: %" PRIu64 " = %s (%s)\n", spaces + strlen(w->ie[i].name), w->ie[i].name, value, amps_ie_desc[w->ie[i].ie].decoder(value), amps_ie_desc[w->ie[i].ie].desc); + else + PDEBUG(DFRAME, DEBUG_DEBUG, " %s%s: %" PRIu64 " (%s)\n", spaces + strlen(w->ie[i].name), w->ie[i].name, value, amps_ie_desc[w->ie[i].ie].desc); + /* show result for 3 IEs of table 4 */ + if (w->ie[i].ie == AMPS_IE_LOCAL_MSG_TYPE || w->ie[i].ie == AMPS_IE_ORDQ || w->ie[i].ie == AMPS_IE_ORDER) + t4++; + if (t4 == 3) { + t4 = 0; + PDEBUG(DFRAME, DEBUG_DEBUG, " %s--> %s\n", spaces, amps_table4_name(frame.ie[AMPS_IE_LOCAL_MSG_TYPE], frame.ie[AMPS_IE_ORDQ], frame.ie[AMPS_IE_ORDER])); + } + } + + return &frame; +} + +/* get word from data bits and call decoder function */ +static void amps_decode_word_focc(amps_t *amps, uint64_t word) +{ + struct def_word *w = NULL; + int t1t2, ohd, act, scc; + + t1t2 = (word >> 38) & 3; + + /* control message */ + if (t1t2 != 3) { + PDEBUG(DFRAME, DEBUG_INFO, "Received Mobile Station Control Message (T1T2 = %d)\n", t1t2); + if (t1t2 == 1) + amps->rx_focc_word_count = 1; + if (t1t2 == 0 || t1t2 == 1) { + w = &word1_abbreviated_address_word; + goto decode; + } + if (t1t2 == 2) { + amps->rx_focc_word_count++; + if (amps->rx_focc_word_count == 2) { + scc = (word >> 36) & 3; + if (scc == 3) + w = &word2_extended_address_word_a; + else + w = &word2_extended_address_word_b; + goto decode; + } + PDEBUG(DFRAME, DEBUG_INFO, "Decoding of more than 2 Control messages not supported\n"); + } + return; + } + + /* overhead message */ + ohd = (word >> 12) & 7; + switch (ohd) { + case 6: + w = &word1_system_parameter_overhead; + break; + case 7: + w = &word2_system_parameter_overhead; + break; + case 4: + act = (word >> 32) & 15; + switch (act) { + case 1: + w = &rescan_global_action; + break; + case 2: + w = ®istration_increment_global_action; + break; + case 3: + w = &location_area_global_action; + break; + case 6: + w = &new_access_channel_set_global_action; + break; + case 8: + w = &overload_control_global_action; + break; + case 9: + w = &access_type_parameters_global_action; + break; + case 10: + w = &access_attempt_parameters_global_action; + break; + case 7: + w = &random_challenge_a_global_action; + break; + case 11: + w = &random_challenge_b_global_action; + break; + case 14: + w = &local_control_1; + break; + case 15: + w = &local_control_2; + break; + } + break; + case 0: + w = ®istration_id; + break; + case 1: + w = &control_filler; + break; + case 2: + w = &control_channel_information; + break; + } + +decode: + if (!w) { + PDEBUG(DFRAME, DEBUG_INFO, "Received Illegal Overhead Message\n"); + return; + } + + amps_decode_word(word, w); +} + +/* get word from data bits and call decoder function + * return 1 if we expect more frames */ +static int amps_decode_word_recc(amps_t *amps, uint64_t word, int first) +{ + struct def_word *w = NULL; + int msg_count, f, nawc; + static frame_t *frame; + + f = (word >> 47) & 0x1; + nawc = (word >> 44) & 0x7; + + if (first) { + memset(amps->rx_recc_dialing, 0, sizeof(amps->rx_recc_dialing)); + amps->rx_recc_word_count = 0; + if (f == 0) { + PDEBUG(DFRAME, DEBUG_NOTICE, "Received first word, but F bit is not set.\n"); + return 0; + } + } else { + if (f == 1) { + PDEBUG(DFRAME, DEBUG_NOTICE, "Received additional word, but F bit is set.\n"); + return 0; + } + } + + msg_count = amps->rx_recc_word_count; + + if (msg_count == 8) { + PDEBUG(DFRAME, DEBUG_NOTICE, "Received too many words.\n"); + return 0; + } + +// amps->rx_recc_word[msg_count] = word; + + if (msg_count == 0) + w = &abbreviated_address_word; + + if (msg_count == 1) + w = &extended_address_word; + + if (amps->si.word2.s) { + if (msg_count == 2) + w = &serial_number_word; + } else + msg_count++; + + if (amps->si.word1.auth) { + if (msg_count == 3) + w = &authentication_word; + } else + msg_count++; + + // FIXME: other messages Word D + if (msg_count == 4) + w = &first_word_of_the_called_address; + + if (msg_count == 5) + w = &second_word_of_the_called_address; + + if (msg_count == 6) + w = &third_word_of_the_called_address; + + if (msg_count == 7) + w = &fourth_word_of_the_called_address; + + + if (!w) { + PDEBUG(DFRAME, DEBUG_INFO, "Received Illegal RECC Message\n"); + goto done; + } + + frame = amps_decode_word(word, w); + + if (amps->rx_recc_word_count == 0 && frame) { + amps->rx_recc_min1 = frame->ie[AMPS_IE_MIN1]; + amps->rx_recc_scm = frame->ie[AMPS_IE_SCM]; + } + if (amps->rx_recc_word_count == 1 && frame) { + amps->rx_recc_min2 = frame->ie[AMPS_IE_MIN2]; + amps->rx_recc_msg_type = frame->ie[AMPS_IE_LOCAL_MSG_TYPE]; + amps->rx_recc_ordq = frame->ie[AMPS_IE_ORDQ]; + amps->rx_recc_order = frame->ie[AMPS_IE_ORDER]; + amps->rx_recc_scm |= frame->ie[AMPS_IE_SCM] << 4; + } + if (amps->rx_recc_word_count == 2 && frame) { + if (amps->si.word2.s) + amps->rx_recc_esn = frame->ie[AMPS_IE_ESN]; + else + amps->rx_recc_esn = 0; + } + if (msg_count == 4 && frame) { + amps->rx_recc_dialing[0] = digit2number[frame->ie[AMPS_IE_DIGIT_1]]; + amps->rx_recc_dialing[1] = digit2number[frame->ie[AMPS_IE_DIGIT_2]]; + amps->rx_recc_dialing[2] = digit2number[frame->ie[AMPS_IE_DIGIT_3]]; + amps->rx_recc_dialing[3] = digit2number[frame->ie[AMPS_IE_DIGIT_4]]; + amps->rx_recc_dialing[4] = digit2number[frame->ie[AMPS_IE_DIGIT_5]]; + amps->rx_recc_dialing[5] = digit2number[frame->ie[AMPS_IE_DIGIT_6]]; + amps->rx_recc_dialing[6] = digit2number[frame->ie[AMPS_IE_DIGIT_7]]; + amps->rx_recc_dialing[7] = digit2number[frame->ie[AMPS_IE_DIGIT_8]]; + } + if (msg_count == 5 && frame) { + amps->rx_recc_dialing[8] = digit2number[frame->ie[AMPS_IE_DIGIT_9]]; + amps->rx_recc_dialing[9] = digit2number[frame->ie[AMPS_IE_DIGIT_10]]; + amps->rx_recc_dialing[10] = digit2number[frame->ie[AMPS_IE_DIGIT_11]]; + amps->rx_recc_dialing[11] = digit2number[frame->ie[AMPS_IE_DIGIT_12]]; + amps->rx_recc_dialing[12] = digit2number[frame->ie[AMPS_IE_DIGIT_13]]; + amps->rx_recc_dialing[13] = digit2number[frame->ie[AMPS_IE_DIGIT_14]]; + amps->rx_recc_dialing[14] = digit2number[frame->ie[AMPS_IE_DIGIT_15]]; + amps->rx_recc_dialing[15] = digit2number[frame->ie[AMPS_IE_DIGIT_16]]; + } + if (msg_count == 6 && frame) { + amps->rx_recc_dialing[16] = digit2number[frame->ie[AMPS_IE_DIGIT_17]]; + amps->rx_recc_dialing[17] = digit2number[frame->ie[AMPS_IE_DIGIT_18]]; + amps->rx_recc_dialing[18] = digit2number[frame->ie[AMPS_IE_DIGIT_19]]; + amps->rx_recc_dialing[19] = digit2number[frame->ie[AMPS_IE_DIGIT_20]]; + amps->rx_recc_dialing[20] = digit2number[frame->ie[AMPS_IE_DIGIT_21]]; + amps->rx_recc_dialing[21] = digit2number[frame->ie[AMPS_IE_DIGIT_22]]; + amps->rx_recc_dialing[22] = digit2number[frame->ie[AMPS_IE_DIGIT_23]]; + amps->rx_recc_dialing[23] = digit2number[frame->ie[AMPS_IE_DIGIT_24]]; + } + if (msg_count == 7 && frame) { + amps->rx_recc_dialing[24] = digit2number[frame->ie[AMPS_IE_DIGIT_25]]; + amps->rx_recc_dialing[25] = digit2number[frame->ie[AMPS_IE_DIGIT_26]]; + amps->rx_recc_dialing[26] = digit2number[frame->ie[AMPS_IE_DIGIT_27]]; + amps->rx_recc_dialing[27] = digit2number[frame->ie[AMPS_IE_DIGIT_28]]; + amps->rx_recc_dialing[28] = digit2number[frame->ie[AMPS_IE_DIGIT_29]]; + amps->rx_recc_dialing[29] = digit2number[frame->ie[AMPS_IE_DIGIT_30]]; + amps->rx_recc_dialing[30] = digit2number[frame->ie[AMPS_IE_DIGIT_31]]; + amps->rx_recc_dialing[31] = digit2number[frame->ie[AMPS_IE_DIGIT_32]]; + } + + if (msg_count >= 2 && nawc == 0) { + amps_rx_recc(amps, amps->rx_recc_scm, amps->rx_recc_esn, amps->rx_recc_min1, amps->rx_recc_min2, amps->rx_recc_msg_type, amps->rx_recc_ordq, amps->rx_recc_order, amps->rx_recc_dialing); + } + + amps->rx_recc_word_count++; + +done: +//printf("left=%d\n", (word >> 44) & 0x7); + if (nawc > 0) + return 1; + + return 0; +} + +/* + * encode and decode bits + */ + +static const char *dotting = "10101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101"; +static const char *sync_word = "11100010010"; + +char *test1 = "101011101000111001101110100111011111111110100000"; +char *test2 = "000100000011011010000000000110101101001110101011"; + +#if 0 +static uint64_t string2bin(const char *string) +{ + uint64_t bin = 0; + + while (*string) + bin = (bin << 1) | ((*string++) & 1); + + return bin; +} +#endif + +static char *amps_encode_focc_bits(amps_t *amps, uint64_t word_a, uint64_t word_b, int busy_idle) +{ + static char bits[463 + 1]; + int i, j, k; + + strncpy(bits + 0, dotting, 10); + bits[10] = (busy_idle) ? '1' : '0'; + strcpy(bits + 11, sync_word); + bits[22] = (busy_idle) ? '1' : '0'; + /* WORD A (msb first) */ + k = 23; + for (i = 0; i < 5; i++) { + for (j = 39; j >= 0; j--) { + bits[k++] = ((word_a >> j) & 1) + '0'; + if ((j % 10) == 0) + bits[k++] = (busy_idle) ? '1' : '0'; + } + } + /* WORD B (msb first) */ + for (i = 0; i < 5; i++) { + for (j = 39; j >= 0; j--) { + bits[k++] = ((word_b >> j) & 1) + '0'; + if ((j % 10) == 0) + bits[k++] = (busy_idle) ? '1' : '0'; + } + } + + if (k != 463) + abort(); + bits[463] = '\0'; + + if (debuglevel == DEBUG_DEBUG) { + char text[64]; + + strncpy(text, bits, 23); + text[23] = '\0'; +#ifdef BIT_DEBUGGING + PDEBUG(DFRAME, DEBUG_INFO, "TX FOCC: %s\n", text); + for (i = 0; i < 5; i++) { + strncpy(text, bits + 23 + i * 44, 44); + text[44] = '\0'; + PDEBUG(DFRAME, DEBUG_DEBUG, " word a - %s\n", text); + } + for (i = 5; i < 10; i++) { + strncpy(text, bits + 23 + i * 44, 44); + text[44] = '\0'; + PDEBUG(DFRAME, DEBUG_DEBUG, " word b - %s\n", text); + } +#endif + } + + return bits; +} + +static char *amps_encode_fvc_bits(amps_t *amps, uint64_t word_a) +{ + static char bits[1032 + 1]; + int i, j, k; + + + k = 0; + for (i = 0; i < 11; i++) { + if (i == 0) { + strncpy(bits + k, dotting, 101); + k += 101; + } else { + strncpy(bits + k, dotting, 37); + k += 37; + } + strcpy(bits + k, sync_word); + k += 11; + for (j = 39; j >= 0; j--) + bits[k++] = ((word_a >> j) & 1) + '0'; + } + if (k != 1032) + abort(); + + bits[1032] = '\0'; + +#ifdef BIT_DEBUGGING + if (debuglevel == DEBUG_DEBUG) { + PDEBUG(DFRAME, DEBUG_INFO, "TX FVC: %s\n", bits); + } +#endif + + return bits; +} + +const char *amps_encode_frame_focc(amps_t *amps) +{ + char *bits; + uint64_t word; + + /* init overhead train */ + if (amps->tx_focc_frame_count == 0) + prepare_sysinfo(&s->si); + /* send overhead train */ + if (amps->si.num) { + word = get_sysinfo(&s->si); + if (++amps->tx_focc_frame_count >= 17) + amps->tx_focc_frame_count = 0; + goto send; + } + + /* see if we can schedule a mobile control message */ + if (!amps->tx_focc_send) { + transaction_t *trans; + trans = amps_tx_frame_focc(amps); + if (trans) { + amps->tx_focc_min1 = trans->min1; + amps->tx_focc_min2 = trans->min2; + amps->tx_focc_msg_type = trans->msg_type; + amps->tx_focc_ordq = trans->ordq; + amps->tx_focc_order = trans->order; + amps->tx_focc_chan = trans->chan; + amps->tx_focc_send = 1; + amps->tx_focc_word_count = 0; + amps->tx_focc_word_repeat = 0; + } + /* on change of dsp mode */ + if (amps->dsp_mode != DSP_MODE_FRAME_RX_FRAME_TX) + return NULL; + } + /* send scheduled mobile control message */ + if (amps->tx_focc_send) { + if (amps->tx_focc_word_count == 0) + word = amps_encode_word1_abbreviated_address_word(amps->si.dcc, amps->tx_focc_min1, 1); + else { + if (amps->tx_focc_chan) + word = amps_encode_word1_extended_address_word_b(amps->sat, amps->tx_focc_min2, amps->si.vmac, amps->tx_focc_chan); + else + word = amps_encode_word1_extended_address_word_a(amps->tx_focc_min2, amps->tx_focc_msg_type, amps->tx_focc_ordq, amps->tx_focc_order); + } + /* dont wrap frame count until we are done */ + ++amps->tx_focc_frame_count; + if (++amps->tx_focc_word_count == 2) { + amps->tx_focc_word_count = 0; + if (++amps->tx_focc_word_repeat == 3) { + amps->tx_focc_word_repeat = 0; + amps->tx_focc_send = 0; + /* now we may wrap */ + if (amps->tx_focc_frame_count >= 17) + amps->tx_focc_frame_count = 0; + } + } + goto send; + } + + /* send filler */ + word = amps_encode_control_filler(amps->si.dcc, amps->si.filler.cmac, amps->si.filler.sdcc1, amps->si.filler.sdcc2, amps->si.filler.wfom); + if (++amps->tx_focc_frame_count >= 17) + amps->tx_focc_frame_count = 0; + +send: + bits = amps_encode_focc_bits(amps, word, word, 1); + + /* invert, if polarity of the cell is negative */ + if (amps->flip_polarity) { + int i; + + for (i = 0; bits[i]; i++) + bits[i] ^= 1; + } + + return bits; +} + +const char *amps_encode_frame_fvc(amps_t *amps) +{ + char *bits; + uint64_t word; + + /* see if we can schedule a mobile control message */ + if (!amps->tx_fvc_send) { + transaction_t *trans; + trans = amps_tx_frame_fvc(amps); + if (trans) { + amps->tx_fvc_msg_type = trans->msg_type; + amps->tx_fvc_ordq = trans->ordq; + amps->tx_fvc_order = trans->order; + amps->tx_fvc_chan = trans->chan; + amps->tx_fvc_send = 1; + } + /* on change of dsp mode */ + if (amps->dsp_mode != DSP_MODE_AUDIO_RX_FRAME_TX) + return NULL; + } + + /* send scheduled mobile control message */ + if (amps->tx_fvc_send) { + amps->tx_fvc_send = 0; + if (amps->tx_fvc_chan) + word = amps_encode_mobile_station_control_message_word1_b(amps->sat, amps->sat, 0, 0, 0, amps->si.vmac, amps->tx_fvc_chan); + else + word = amps_encode_mobile_station_control_message_word1_a(amps->sat, amps->tx_fvc_msg_type, amps->tx_fvc_ordq, amps->tx_fvc_order); + } else + return NULL; + + bits = amps_encode_fvc_bits(amps, word); + + /* invert, if polarity of the cell is negative */ + if (amps->flip_polarity) { + int i; + + for (i = 0; bits[i]; i++) + bits[i] ^= 1; + } + + return bits; +} + +/* assemble FOCC bits */ +void amps_decode_bits_focc(amps_t *amps, const char *bits) +{ + char word_string[41]; + uint64_t word_a[5], word_b[5], word; + int crc_a_ok[5], crc_b_ok[5], crc_ok; + int idle; + int i, j, k, crc_i, crc_j; + + bits++; /* skip B/I after sync */ + idle = 0; + for (i = 0; i < 10; i++) { + word = 0; + for (j = 0, k = 0; j < 44; j++) { + if (j % 11 == 10) { + idle += (*bits++) & 1; + continue; + } + word_string[k++] = *bits; + word = (word << 1) | ((*bits++) & 1); + } + word_string[k] = '\0'; + if (!strncmp(encode_bch(word_string, 28), word_string + 28, 12)) + crc_ok = 1; + else + crc_ok = 0; + if (i < 5) { + word_a[i % 5] = word; + crc_a_ok[i % 5] = crc_ok; + } else { + word_b[i % 5] = word; + crc_b_ok[i % 5] = crc_ok; + } + } + bits -= 440; + + if (idle > 20) + idle = 1; + else + idle = 0; + + PDEBUG(DFRAME, DEBUG_INFO, "RX FOCC: B/I = %s\n", (idle) ? "idle" : "busy"); + if (debuglevel == DEBUG_DEBUG) { + char text[64]; + + for (i = 0; i < 5; i++) { + strncpy(text, bits + i * 44, 44); + text[44] = '\0'; + PDEBUG(DFRAME, DEBUG_DEBUG, " word a - %s%s\n", text, (crc_a_ok[i % 5]) ? " ok" : " BAD CRC!"); + } + for (i = 5; i < 10; i++) { + strncpy(text, bits + i * 44, 44); + text[44] = '\0'; + PDEBUG(DFRAME, DEBUG_DEBUG, " word b - %s%s\n", text, (crc_b_ok[i % 5]) ? " ok" : " BAD CRC!"); + } + } + + for (crc_i = 0; crc_i < 5; crc_i++) { + if (crc_a_ok[crc_i]) + break; + } + if (crc_i < 5) { + amps_decode_word_focc(amps, word_a[crc_i]); + } + for (crc_j = 0; crc_j < 5; crc_j++) { + if (crc_b_ok[crc_j]) + break; + } + if (crc_j < 5 && word_b[crc_j] != word_a[crc_i]) { + amps_decode_word_focc(amps, word_b[crc_j]); + } +} + +/* assemble RECC bits, return true, if more bits are expected */ +int amps_decode_bits_recc(amps_t *amps, const char *bits, int first) +{ + char word_string[49]; + int8_t dcc = -1; + uint64_t word_a[5], word; + int crc_a_ok[5], crc_ok; + int i, j, k, crc_i; + const char *bits_ = bits; /* for extra check */ + + /* decode color code */ + if (first) { + dcc = 0; + for (j = 0; j < 7; j++) { + dcc = (dcc << 1) | ((*bits++) & 1); + } + dcc = dcc_decode[dcc]; + } + + /* assemble word */ + for (i = 0; i < 5; i++) { + word = 0; + for (j = 0, k = 0; j < 48; j++) { + word_string[k++] = *bits; + word = (word << 1) | ((*bits++) & 1); + } + word_string[k] = '\0'; + if (!strncmp(encode_bch(word_string, 36), word_string + 36, 12)) + crc_ok = 1; + else + crc_ok = 0; + word_a[i % 5] = word; + crc_a_ok[i % 5] = crc_ok; + } + bits -= 240; + + for (crc_i = 0; crc_i < 5; crc_i++) { + if (crc_a_ok[crc_i]) + break; + } + + if (crc_i == 5) { + /* check if we receive frame in a loop */ + crc_ok = 0; + bits_++; /* skip B/I after sync */ + for (i = 0; i < 5; i++) { + word = 0; + for (j = 0, k = 0; j < 44; j++) { + if (j % 11 == 10) { + bits_++; + continue; + } + word_string[k++] = *bits_; + word = (word << 1) | ((*bits_++) & 1); + } + word_string[k] = '\0'; + if (!strncmp(encode_bch(word_string, 28), word_string + 28, 12)) + crc_ok++; + } + if (crc_ok == i) { + PDEBUG(DFRAME, DEBUG_NOTICE, "Seems we RX FOCC frame due to loopback, ignoring!\n"); + return 0; + } + bits_ -= 221; + } + + if (first) { + if (debuglevel == DEBUG_DEBUG || crc_i < 5) { + PDEBUG(DFRAME, DEBUG_INFO, "RX RECC: DCC=%d\n", dcc); + if (dcc != amps->si.dcc) { + PDEBUG(DFRAME, DEBUG_INFO, "received DCC=%d missmatches the base station's DCC=%d\n", dcc, amps->si.dcc); + return 0; + } + } + } + if (debuglevel == DEBUG_DEBUG) { + char text[64]; + + for (i = 0; i < 5; i++) { + strncpy(text, bits + i * 48, 48); + text[48] = '\0'; + PDEBUG(DFRAME, DEBUG_DEBUG, " word - %s%s\n", text, (crc_a_ok[i % 5]) ? " ok" : " BAD CRC!"); + } + } + + if (crc_i < 5) + return amps_decode_word_recc(amps, word_a[crc_i], first); + return 0; +} + +int amps_decode_frame(amps_t *amps, const char *bits, int count, double level, double quality, int negative) +{ + int more = 0; + + /* not if additional words are received without sync */ + if (count != 240) + PDEBUG(DDSP, DEBUG_INFO, "RX Level: %.0f%% Quality: %.0f%% Polarity: %s\n", level * 100.0, quality * 100.0, (negative) ? "NEGATIVE" : "POSITIVE"); + if (count == 441) { + amps_decode_bits_focc(amps, bits); + } else if (count == 247) { + more = amps_decode_bits_recc(amps, bits, 1); + } else if (count == 240) { + more = amps_decode_bits_recc(amps, bits, 0); + } else { + PDEBUG(DFRAME, DEBUG_ERROR, "Frame with unknown lenght = %d, please fix!\n", count); + } + + return more; +} + -- cgit v1.2.3