},
};
+/* RR elements */
+const struct tlv_definition gsm48_rr_att_tlvdef = {
+ .def = {
+ /* NOTE: Don't add IE 17 = MOBILE_ID here, it already used. */
+ [GSM48_IE_VGCS_TARGET] = { TLV_TYPE_TLV },
+ [GSM48_IE_FRQSHORT_AFTER] = { TLV_TYPE_FIXED, 9 },
+ [GSM48_IE_MUL_RATE_CFG] = { TLV_TYPE_TLV },
+ [GSM48_IE_FREQ_L_AFTER] = { TLV_TYPE_TLV },
+ [GSM48_IE_MSLOT_DESC] = { TLV_TYPE_TLV },
+ [GSM48_IE_CHANMODE_2] = { TLV_TYPE_TV },
+ [GSM48_IE_FRQSHORT_BEFORE] = { TLV_TYPE_FIXED, 9 },
+ [GSM48_IE_CHANMODE_3] = { TLV_TYPE_TV },
+ [GSM48_IE_CHANMODE_4] = { TLV_TYPE_TV },
+ [GSM48_IE_CHANMODE_5] = { TLV_TYPE_TV },
+ [GSM48_IE_CHANMODE_6] = { TLV_TYPE_TV },
+ [GSM48_IE_CHANMODE_7] = { TLV_TYPE_TV },
+ [GSM48_IE_CHANMODE_8] = { TLV_TYPE_TV },
+ [GSM48_IE_FREQ_L_BEFORE] = { TLV_TYPE_TLV },
+ [GSM48_IE_CH_DESC_1_BEFORE] = { TLV_TYPE_FIXED, 3 },
+ [GSM48_IE_CH_DESC_2_BEFORE] = { TLV_TYPE_FIXED, 3 },
+ [GSM48_IE_F_CH_SEQ_BEFORE] = { TLV_TYPE_FIXED, 9 },
+ [GSM48_IE_CLASSMARK3] = { TLV_TYPE_TLV },
+ [GSM48_IE_MA_BEFORE] = { TLV_TYPE_TLV },
+ [GSM48_IE_RR_PACKET_UL] = { TLV_TYPE_TLV },
+ [GSM48_IE_RR_PACKET_DL] = { TLV_TYPE_TLV },
+ [GSM48_IE_CELL_CH_DESC] = { TLV_TYPE_FIXED, 16 },
+ [GSM48_IE_CHANMODE_1] = { TLV_TYPE_TV },
+ [GSM48_IE_CHDES_2_AFTER] = { TLV_TYPE_FIXED, 3 },
+ [GSM48_IE_MODE_SEC_CH] = { TLV_TYPE_TV },
+ [GSM48_IE_F_CH_SEQ_AFTER] = { TLV_TYPE_FIXED, 9 },
+ [GSM48_IE_MA_AFTER] = { TLV_TYPE_TLV },
+ [GSM48_IE_BA_RANGE] = { TLV_TYPE_TLV },
+ [GSM48_IE_GROUP_CHDES] = { TLV_TYPE_TLV },
+ [GSM48_IE_BA_LIST_PREF] = { TLV_TYPE_TLV },
+ [GSM48_IE_MOB_OVSERV_DIF] = { TLV_TYPE_TLV },
+ [GSM48_IE_REALTIME_DIFF] = { TLV_TYPE_TLV },
+ [GSM48_IE_START_TIME] = { TLV_TYPE_FIXED, 2 },
+ [GSM48_IE_TIMING_ADVANCE] = { TLV_TYPE_TV },
+ [GSM48_IE_GROUP_CIP_SEQ] = { TLV_TYPE_SINGLE_TV },
+ [GSM48_IE_CIP_MODE_SET] = { TLV_TYPE_SINGLE_TV },
+ [GSM48_IE_GPRS_RESUMPT] = { TLV_TYPE_SINGLE_TV },
+ [GSM48_IE_SYNC_IND] = { TLV_TYPE_SINGLE_TV },
+ },
+};
+
+/* MM elements */
+const struct tlv_definition gsm48_mm_att_tlvdef = {
+ .def = {
+ [GSM48_IE_MOBILE_ID] = { TLV_TYPE_TLV },
+ [GSM48_IE_NAME_LONG] = { TLV_TYPE_TLV },
+ [GSM48_IE_NAME_SHORT] = { TLV_TYPE_TLV },
+ [GSM48_IE_UTC] = { TLV_TYPE_TV },
+ [GSM48_IE_NET_TIME_TZ] = { TLV_TYPE_FIXED, 7 },
+ [GSM48_IE_LSA_IDENT] = { TLV_TYPE_TLV },
+
+ [GSM48_IE_LOCATION_AREA] = { TLV_TYPE_FIXED, 5 },
+ [GSM48_IE_PRIORITY_LEV] = { TLV_TYPE_SINGLE_TV },
+ [GSM48_IE_FOLLOW_ON_PROC] = { TLV_TYPE_T },
+ [GSM48_IE_CTS_PERMISSION] = { TLV_TYPE_T },
+ },
+};
+
static const struct value_string rr_cause_names[] = {
{ GSM48_RR_CAUSE_NORMAL, "Normal event" },
{ GSM48_RR_CAUSE_ABNORMAL_UNSPEC, "Abnormal release, unspecified" },
};
/* FIXME: convert to value_string */
-static const char *cc_state_names[33] = {
+static const char *cc_state_names[32] = {
"NULL",
"INITIATED",
"MM_CONNECTION_PEND",
to_bcd(bcd, mnc);
/* FIXME: do we need three-digit MNC? See Table 10.5.3 */
-#if 0
- lai48->digits[1] |= bcd[2] << 4;
- lai48->digits[2] = bcd[0] | (bcd[1] << 4);
-#else
- lai48->digits[1] |= 0xf << 4;
- lai48->digits[2] = bcd[1] | (bcd[2] << 4);
-#endif
+ if (mnc > 99) {
+ lai48->digits[1] |= bcd[2] << 4;
+ lai48->digits[2] = bcd[0] | (bcd[1] << 4);
+ } else {
+ lai48->digits[1] |= 0xf << 4;
+ lai48->digits[2] = bcd[1] | (bcd[2] << 4);
+ }
lai48->lac = htons(lac);
}
}
/* Convert Mobile Identity (10.5.1.4) to string */
-int gsm48_mi_to_string(char *string, const int str_len, const u_int8_t *mi, const int mi_len)
+int gsm48_mi_to_string(char *string, const int str_len, const uint8_t *mi,
+ const int mi_len)
{
int i;
- u_int8_t mi_type;
+ uint8_t mi_type;
char *str_cur = string;
- u_int32_t tmsi;
+ uint32_t tmsi;
mi_type = mi[0] & GSM_MI_TYPE_MASK;
return str_cur - string;
}
+
+void gsm48_parse_ra(struct gprs_ra_id *raid, const uint8_t *buf)
+{
+ raid->mcc = (buf[0] & 0xf) * 100;
+ raid->mcc += (buf[0] >> 4) * 10;
+ raid->mcc += (buf[1] & 0xf) * 1;
+
+ /* I wonder who came up with the stupidity of encoding the MNC
+ * differently depending on how many digits its decimal number has! */
+ if ((buf[1] >> 4) == 0xf) {
+ raid->mnc = (buf[2] & 0xf) * 10;
+ raid->mnc += (buf[2] >> 4) * 1;
+ } else {
+ raid->mnc = (buf[2] & 0xf) * 100;
+ raid->mnc += (buf[2] >> 4) * 10;
+ raid->mnc += (buf[1] >> 4) * 1;
+ }
+
+ raid->lac = ntohs(*(uint16_t *)(buf + 3));
+ raid->rac = buf[5];
+}
+
+int gsm48_construct_ra(uint8_t *buf, const struct gprs_ra_id *raid)
+{
+ uint16_t mcc = raid->mcc;
+ uint16_t mnc = raid->mnc;
+
+ buf[0] = ((mcc / 100) % 10) | (((mcc / 10) % 10) << 4);
+ buf[1] = (mcc % 10);
+
+ /* I wonder who came up with the stupidity of encoding the MNC
+ * differently depending on how many digits its decimal number has! */
+ if (mnc < 100) {
+ buf[1] |= 0xf0;
+ buf[2] = ((mnc / 10) % 10) | ((mnc % 10) << 4);
+ } else {
+ buf[1] |= (mnc % 10) << 4;
+ buf[2] = ((mnc / 100) % 10) | (((mcc / 10) % 10) << 4);
+ }
+
+ *(uint16_t *)(buf+3) = htons(raid->lac);
+
+ buf[5] = raid->rac;
+
+ return 6;
+}