diff --git a/include/openbsc/abis_rsl.h b/include/openbsc/abis_rsl.h index 219fdd3db..769672824 100644 --- a/include/openbsc/abis_rsl.h +++ b/include/openbsc/abis_rsl.h @@ -244,6 +244,22 @@ struct rsl_ie_chan_ident { #endif } __attribute__ ((packed)); +/* Chapter 9.3.22 */ +#define RLL_CAUSE_T200_EXPIRED 0x01 +#define RLL_CAUSE_REEST_REQ 0x02 +#define RLL_CAUSE_UNSOL_UA_RESP 0x03 +#define RLL_CAUSE_UNSOL_DM_RESP 0x04 +#define RLL_CAUSE_UNSOL_DM_RESP_MF 0x05 +#define RLL_CAUSE_UNSOL_SPRV_RESP 0x06 +#define RLL_CAUSE_SEQ_ERR 0x07 +#define RLL_CAUSE_UFRM_INC_PARAM 0x08 +#define RLL_CAUSE_SFRM_INC_PARAM 0x09 +#define RLL_CAUSE_IFRM_INC_MBITS 0x0a +#define RLL_CAUSE_IFRM_INC_LEN 0x0b +#define RLL_CAUSE_FRM_UNIMPL 0x0c +#define RLL_CAUSE_SABM_MF 0x0d +#define RLL_CAUSE_SABM_INFO_NOTALL 0x0e + /* Chapter 9.3.26 */ #define RSL_ERRCLS_NORMAL 0x00 #define RSL_ERRCLS_RESOURCE_UNAVAIL 0x20 diff --git a/include/openbsc/gsm_04_08.h b/include/openbsc/gsm_04_08.h index dc5eba9ae..389daf596 100644 --- a/include/openbsc/gsm_04_08.h +++ b/include/openbsc/gsm_04_08.h @@ -46,6 +46,7 @@ struct gsm48_imm_ass { u_int8_t mob_alloc[0]; }; +/* Chapter 10.5.1.3 */ struct gsm48_loc_area_id { u_int8_t digits[3]; /* BCD! */ u_int16_t lac; @@ -57,7 +58,6 @@ struct gsm48_loc_upd_req { key_seq:4; struct gsm48_loc_area_id lai; u_int8_t classmark1; - u_int8_t ie_mi; u_int8_t mi_len; u_int8_t mi[0]; } __attribute__ ((packed)); @@ -70,7 +70,7 @@ struct gsm48_hdr { } __attribute__ ((packed)); /* Section 10.2 */ -#define GSM48_PDISC_CC 0x02 +#define GSM48_PDISC_CC 0x03 #define GSM48_PDISC_MM 0x05 #define GSM48_PDISC_RR 0x06 #define GSM48_PDISC_MM_GPRS 0x08 @@ -235,6 +235,23 @@ struct gsm48_hdr { #define GSM_MI_TYPE_TMSI 0x04 #define GSM_MI_ODD 0x08 +#define GSM48_IE_MOBILE_ID 0x17 + +/* Section 10.5.4.11 / Table 10.5.122 */ +#define GSM48_CAUSE_CS_GSM 0x60 + +enum gsm48_cause_loc { + GSM48_CAUSE_LOC_USER = 0x00, + GSM48_CAUSE_LOC_PRN_S_LU = 0x01, + GSM48_CAUSE_LOC_PUN_S_LU = 0x02, + GSM48_CAUSE_LOC_TRANS_NET = 0x03, + GSM48_CAUSE_LOC_PUN_S_RU = 0x04, + GSM48_CAUSE_LOC_PRN_S_RU = 0x05, + /* not defined */ + GSM48_CAUSE_LOC_INN_NET = 0x07, + GSM48_CAUSE_LOC_NET_BEYOND = 0x0a, +}; + struct msgb; struct gsm_bts; diff --git a/include/openbsc/tlv.h b/include/openbsc/tlv.h index 38ca81150..70d0319e8 100644 --- a/include/openbsc/tlv.h +++ b/include/openbsc/tlv.h @@ -57,6 +57,15 @@ static inline u_int8_t *tv_put(u_int8_t *buf, u_int8_t tag, return buf; } +static inline u_int8_t *tv16_put(u_int8_t *buf, u_int8_t tag, + u_int16_t val) +{ + *buf++ = tag; + *buf++ = val >> 8; + *buf++ = val & 0xff; + return buf; +} + static inline u_int8_t *msgb_tlv_put(struct msgb *msg, u_int8_t tag, u_int8_t len, const u_int8_t *val) { u_int8_t *buf = msgb_put(msg, TLV_GROSS_LEN(len)); @@ -69,6 +78,12 @@ static inline u_int8_t *msgb_tv_put(struct msgb *msg, u_int8_t tag, u_int8_t val return tv_put(buf, tag, val); } +static inline u_int8_t *msgb_tv16_put(struct msgb *msg, u_int8_t tag, u_int16_t val) +{ + u_int8_t *buf = msgb_put(msg, 3); + return tv16_put(buf, tag, val); +} + static inline u_int8_t *msgb_tlv_push(struct msgb *msg, u_int8_t tag, u_int8_t len, const u_int8_t *val) { u_int8_t *buf = msgb_push(msg, TLV_GROSS_LEN(len)); @@ -81,4 +96,11 @@ static inline u_int8_t *msgb_tv_push(struct msgb *msg, u_int8_t tag, u_int8_t va return tv_put(buf, tag, val); } +static inline u_int8_t *msgb_tv16_push(struct msgb *msg, u_int8_t tag, u_int16_t val) +{ + u_int8_t *buf = msgb_push(msg, 3); + return tv16_put(buf, tag, val); +} + + #endif /* _TLV_H */ diff --git a/src/abis_rsl.c b/src/abis_rsl.c index df34929ac..f6f5f2fbf 100644 --- a/src/abis_rsl.c +++ b/src/abis_rsl.c @@ -336,6 +336,62 @@ int rsl_chan_activate_sdcch4(struct gsm_bts_trx_ts *ts, int subslot) return rsl_chan_activate(ts->trx->bts, chan_nr, 0x00, &cm, &ci, 0x01, 0x0f, 0x00); } +int rsl_chan_activate_lchan(struct gsm_lchan *lchan, u_int8_t act_type, u_int8_t ta) +{ + struct abis_rsl_dchan_hdr *dh; + struct msgb *msg = rsl_msgb_alloc(); + /* FXIME: don't hardcode these!! */ + u_int8_t encr_info = 0x01; + u_int8_t ms_power = 0x0f; + u_int8_t bs_power = 0x01; + + u_int8_t chan_nr = lchan2chan_nr(lchan); + u_int16_t arfcn = lchan->ts->trx->arfcn; + struct rsl_ie_chan_mode cm; + struct rsl_ie_chan_ident ci; + + /* FIXME: what to do with data calls ? */ + cm.dtx_dtu = 0x00; + switch (lchan->type) { + case GSM_LCHAN_SDCCH: + cm.spd_ind = RSL_CMOD_SPD_SIGN; + cm.chan_rt = RSL_CMOD_CRT_SDCCH; + cm.chan_rate = 0x00; + break; + case GSM_LCHAN_TCH_F: + cm.spd_ind = RSL_CMOD_SPD_SPEECH; + cm.chan_rt = RSL_CMOD_CRT_TCH_Bm; + cm.chan_rate = 0x11; /* speech coding alg version 2*/ + break; + } + + ci.chan_desc.iei = 0x64; + ci.chan_desc.chan_nr = chan_nr; + ci.chan_desc.oct3 = (TSC << 5) | ((arfcn & 0x3ff) >> 8); + ci.chan_desc.oct4 = arfcn & 0xff; + + dh = (struct abis_rsl_dchan_hdr *) msgb_put(msg, sizeof(*dh)); + init_dchan_hdr(dh, RSL_MT_CHAN_ACTIV); + dh->chan_nr = chan_nr; + + msgb_tv_put(msg, RSL_IE_ACT_TYPE, act_type); + /* For compatibility with Phase 1 */ + msgb_tlv_put(msg, RSL_IE_CHAN_MODE, sizeof(cm), + (u_int8_t *) &cm); + msgb_tlv_put(msg, RSL_IE_CHAN_IDENT, 4, + (u_int8_t *) &ci); + /* FIXME: this shoould be optional */ +#if 0 + msgb_tlv_put(msg, RSL_IE_ENCR_INFO, 1, + (u_int8_t *) &encr_info); + msgb_tv_put(msg, RSL_IE_BS_POWER, bs_power); +#endif + msgb_tv_put(msg, RSL_IE_MS_POWER, ms_power); + msgb_tv_put(msg, RSL_IE_TIMING_ADVANCE, ta); + + return abis_rsl_sendmsg(msg); +} + int rsl_chan_release(struct gsm_lchan *lchan) { struct abis_rsl_dchan_hdr *dh; @@ -427,7 +483,7 @@ int rsl_data_request(struct msgb *msg, u_int8_t link_id) } /* First push the L3 IE tag and length */ - msgb_tv_push(msg, RSL_IE_L3_INFO, l3_len); + msgb_tv16_push(msg, RSL_IE_L3_INFO, l3_len); /* Then push the RSL header */ rh = (struct abis_rsl_rll_hdr *) msgb_push(msg, sizeof(*rh)); @@ -447,8 +503,27 @@ static int rsl_rx_chan_act_ack(struct msgb *msg) /* BTS has confirmed channel activation, we now need * to assign the activated channel to the MS */ + if (rslh->ie_chan != RSL_IE_CHAN_NR) + return -EINVAL; + + DEBUGP(DRSL, "Channel Activate ACK Channel 0x%02x\n", rslh->chan_nr); + return 0; +} +/* Chapter 8.4.3: Channel Activate NACK */ +static int rsl_rx_chan_act_nack(struct msgb *msg) +{ + struct abis_rsl_dchan_hdr *rslh = msgb_l2(msg); + + /* BTS has confirmed channel activation, we now need + * to assign the activated channel to the MS */ + if (rslh->ie_chan != RSL_IE_CHAN_NR) + return -EINVAL; + + DEBUGP(DRSL, "Channel Activate NACK Channel 0x%02x\n", rslh->chan_nr); + + return 0; } static int abis_rsl_rx_dchan(struct msgb *msg) @@ -460,11 +535,11 @@ static int abis_rsl_rx_dchan(struct msgb *msg) switch (rslh->c.msg_type) { case RSL_MT_CHAN_ACTIV_ACK: - DEBUGP(DRSL, "rsl_rx_dchan: Channel Activate ACK\n"); + rc = rsl_rx_chan_act_ack(msg); rc = rsl_rx_chan_act_ack(msg); break; case RSL_MT_CHAN_ACTIV_NACK: - DEBUGP(DRSL, "rsl_rx_dchan: Channel Activate NACK\n"); + rc = rsl_rx_chan_act_nack(msg); break; case RSL_MT_CONN_FAIL: DEBUGP(DRSL, "rsl_rx_dchan: Connection Fail\n"); @@ -503,7 +578,7 @@ static int rsl_rx_error_rep(struct msgb *msg) return -EINVAL; cause_len = rslh->data[1]; - printf(stdout, "RSL ERROR REPORT, Cause "); + fprintf(stdout, "RSL ERROR REPORT, Cause "); hexdump(&rslh->data[2], cause_len); return 0; @@ -577,11 +652,15 @@ static int rsl_rx_chan_rqd(struct msgb *msg) DEBUGP(DRSL, "Activating ARFCN(%u) TS(%u) SS(%u) lctype %u\n", arfcn, ts_number, subch, lchan->type); +#if 0 /* send CHANNEL ACTIVATION on RSL to BTS */ if (lchan->ts->pchan == GSM_PCHAN_CCCH_SDCCH4) rsl_chan_activate_sdcch4(lchan->ts, subch); else rsl_chan_activate_tch_f(lchan->ts); +#else + rsl_chan_activate_lchan(lchan, 0x00, rqd_ta); +#endif /* create IMMEDIATE ASSIGN 04.08 messge */ memset(&ia, 0, sizeof(ia)); @@ -589,7 +668,7 @@ static int rsl_rx_chan_rqd(struct msgb *msg) ia.proto_discr = GSM48_PDISC_RR; ia.msg_type = GSM48_MT_RR_IMM_ASS; ia.page_mode = GSM48_PM_NORMAL; - ia.chan_desc.chan_nr = rsl_enc_chan_nr(RSL_CHAN_SDCCH4_ACCH, subch, ts_number); + ia.chan_desc.chan_nr = lchan2chan_nr(lchan); ia.chan_desc.h0.h = 0; ia.chan_desc.h0.arfcn_high = arfcn >> 8; ia.chan_desc.h0.arfcn_low = arfcn & 0xff; @@ -633,6 +712,16 @@ static int abis_rsl_rx_cchan(struct msgb *msg) return rc; } +static int rsl_rx_rll_err_ind(struct msgb *msg) +{ + struct abis_rsl_rll_hdr *rllh = msgb_l2(msg); + u_int8_t *rlm_cause = rllh->data; + + DEBUGP(DRLL, "RLL ERROR INDICATION: chan_nr=0x%02x cause=0x%02x\n", + rllh->chan_nr, rlm_cause[1]); + + return 0; +} /* ESTABLISH INDICATION, LOCATION AREA UPDATE REQUEST 0x02, 0x06, 0x01, 0x20, @@ -648,19 +737,25 @@ static int abis_rsl_rx_rll(struct msgb *msg) switch (rllh->c.msg_type) { case RSL_MT_DATA_IND: - DEBUGP(DRLL, "DATA INDICATION\n"); + DEBUGP(DRLL, "DATA INDICATION chan_nr=0x%02x\n", rllh->chan_nr); /* FIXME: Verify L3 info element */ msg->l3h = &rllh->data[3]; rc = gsm0408_rcvmsg(msg); break; case RSL_MT_EST_IND: - DEBUGP(DRLL, "ESTABLISH INDICATION\n"); + DEBUGP(DRLL, "ESTABLISH INDICATION chan_nr=0x%02x\n", rllh->chan_nr); /* FIXME: Verify L3 info element */ msg->l3h = &rllh->data[3]; rc = gsm0408_rcvmsg(msg); break; - case RSL_MT_ERROR_IND: case RSL_MT_REL_IND: + DEBUGP(DRLL, "RELEASE INDICATION chan_nr=0x%02x\n", rllh->chan_nr); + lchan_free(msg->lchan); + rc = 0; + break; + case RSL_MT_ERROR_IND: + rc = rsl_rx_rll_err_ind(msg); + break; case RSL_MT_UNIT_DATA_IND: fprintf(stderr, "unimplemented Abis RLL message type 0x%02x\n", rllh->c.msg_type); diff --git a/src/chan_alloc.c b/src/chan_alloc.c index ca8690899..4ef5ff902 100644 --- a/src/chan_alloc.c +++ b/src/chan_alloc.c @@ -27,6 +27,7 @@ #include #include +#include struct gsm_bts_trx_ts *ts_c0_alloc(struct gsm_bts *bts, enum gsm_phys_chan_config pchan) @@ -46,6 +47,14 @@ struct gsm_bts_trx_ts *ts_c0_alloc(struct gsm_bts *bts, return ts; } +static const enum abis_nm_chan_comb chcomb4pchan[] = { + [GSM_PCHAN_CCCH] = NM_CHANC_mainBCCH, + [GSM_PCHAN_CCCH_SDCCH4] = NM_CHANC_BCCCHComb, + [GSM_PCHAN_TCH_F] = NM_CHANC_TCHFull, + [GSM_PCHAN_TCH_H] = NM_CHANC_TCHHalf, + [GSM_PCHAN_SDCCH8_SACCH8C] = NM_CHANC_SDCCH, + /* FIXME: bounds check */ +}; /* Allocate a logical channel (TS) */ struct gsm_bts_trx_ts *ts_alloc(struct gsm_bts *bts, @@ -58,6 +67,8 @@ struct gsm_bts_trx_ts *ts_alloc(struct gsm_bts *bts, struct gsm_bts_trx_ts *ts = &trx->ts[j]; if (ts->pchan == GSM_PCHAN_NONE) { ts->pchan = pchan; + /* set channel attribute on OML */ + abis_nm_set_channel_attr(ts, chcomb4pchan[pchan]); return ts; } } diff --git a/src/gsm_04_08.c b/src/gsm_04_08.c index 212b4ad6b..b478bc7f5 100644 --- a/src/gsm_04_08.c +++ b/src/gsm_04_08.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -64,11 +65,11 @@ static void parse_lai(struct gsm_lai *lai, const struct gsm48_loc_area_id *lai48 static void to_bcd(u_int8_t *bcd, u_int16_t val) { - bcd[0] = val % 10; + bcd[2] = val % 10; val = val / 10; bcd[1] = val % 10; val = val / 10; - bcd[2] = val % 10; + bcd[0] = val % 10; val = val / 10; } @@ -82,10 +83,16 @@ static void generate_lai(struct gsm48_loc_area_id *lai48, u_int16_t mcc, lai48->digits[1] = bcd[2]; 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 - lai48->lac = lac; + lai48->lac = htons(lac); } #define TMSI_LEN 4 @@ -93,12 +100,13 @@ static void generate_lai(struct gsm48_loc_area_id *lai48, u_int16_t mcc, static void generate_mid_from_tmsi(u_int8_t *buf, u_int8_t *tmsi_bcd) { - buf[0] = MID_TMSI_LEN; - buf[1] = 0xf0 | GSM_MI_TYPE_TMSI; - buf[2] = tmsi_bcd[0]; - buf[3] = tmsi_bcd[1]; - buf[4] = tmsi_bcd[2]; - buf[5] = tmsi_bcd[3]; + buf[0] = GSM48_IE_MOBILE_ID; + buf[1] = MID_TMSI_LEN; + buf[2] = 0xf0 | GSM_MI_TYPE_TMSI; + buf[3] = tmsi_bcd[0]; + buf[4] = tmsi_bcd[1]; + buf[5] = tmsi_bcd[2]; + buf[6] = tmsi_bcd[3]; } static struct msgb *gsm48_msgb_alloc(void) @@ -111,14 +119,45 @@ static int gsm0408_sendmsg(struct msgb *msg) if (msg->lchan) msg->trx = msg->lchan->ts->trx; + msg->l3h = msg->data; + return rsl_data_request(msg, 0); } +static int gsm48_cc_tx_status(struct gsm_lchan *lchan) +{ + struct msgb *msg = gsm48_msgb_alloc(); + struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh)); + u_int8_t *cause, *call_state; + + msg->lchan = lchan; + + gh->proto_discr = GSM48_PDISC_CC; + gh->msg_type = GSM48_MT_CC_STATUS; + + cause = msgb_put(msg, 3); + cause[0] = 2; + cause[1] = GSM48_CAUSE_CS_GSM | GSM48_CAUSE_LOC_USER; + cause[2] = 0x80 | 30; /* response to status inquiry */ + + call_state = msgb_put(msg, 1); + call_state[0] = 0xc0 | 0x00; + + return gsm0408_sendmsg(msg); +} + +static int gsm48_cc_rx_status_enq(struct msgb *msg) +{ + return gsm48_cc_tx_status(msg->lchan); +} + static int gsm0408_rcv_cc(struct msgb *msg) { struct gsm48_hdr *gh = msgb_l3(msg); + u_int8_t msg_type = gh->msg_type & 0xbf; + int rc = 0; - switch (gh->msg_type & 0xbf) { + switch (msg_type) { case GSM48_MT_CC_CALL_CONF: /* Response to SETUP */ DEBUGP(DCC, "CALL CONFIRM\n"); @@ -137,18 +176,27 @@ static int gsm0408_rcv_cc(struct msgb *msg) DEBUGP(DCC, "RELEASE\n"); /* need to respond with RELEASE_COMPLETE */ break; - case GSM48_MT_CC_EMERG_SETUP: - //DEBUGP(DCC, "EMERGENCY SETUP\n"); + case GSM48_MT_CC_STATUS_ENQ: + rc = gsm48_cc_rx_status_enq(msg); + break; + case GSM48_MT_CC_DISCONNECT: + DEBUGP(DCC, "DISCONNECT\n"); + break; case GSM48_MT_CC_SETUP: - //DEBUGP(DCC, "SETUP\n"); + DEBUGP(DCC, "SETUP\n"); /* FIXME: continue with CALL_PROCEEDING, ALERTING, CONNECT, RELEASE_COMPLETE */ + break; + case GSM48_MT_CC_EMERG_SETUP: + DEBUGP(DCC, "EMERGENCY SETUP\n"); + /* FIXME: continue with CALL_PROCEEDING, ALERTING, CONNECT, RELEASE_COMPLETE */ + break; default: fprintf(stderr, "Unimplemented GSM 04.08 msg type 0x%02x\n", - gh->msg_type); + msg_type); break; } - return 0; + return rc; } /* Chapter 9.2.14 : Send LOCATION UPDATE REJECT */ @@ -209,11 +257,12 @@ static int mm_loc_upd_req(struct msgb *msg) mi_type = lu->mi[0] & GSM_MI_TYPE_MASK; + DEBUGP(DMM, "LUPDREQ: mi_type = 0x%02x\n", mi_type); switch (mi_type) { case GSM_MI_TYPE_IMSI: /* look up subscriber based on IMSI */ subscr = subscr_get_by_imsi(&lu->mi[1]); - break; + break; case GSM_MI_TYPE_TMSI: /* look up the subscriber based on TMSI, request IMSI if it fails */ subscr = subscr_get_by_tmsi(&lu->mi[1]); @@ -244,6 +293,29 @@ static int mm_loc_upd_req(struct msgb *msg) return gsm0408_loc_upd_acc(msg->lchan, subscr->tmsi); } +static int gsm48_tx_mm_serv_ack(struct gsm_lchan *lchan) +{ + struct msgb *msg = gsm48_msgb_alloc(); + struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh)); + + msg->lchan = lchan; + + gh->proto_discr = GSM48_PDISC_MM; + gh->msg_type = GSM48_MT_MM_CM_SERV_ACC; + + DEBUGP(DMM, "-> CM SERVICE ACK\n"); + + return gsm0408_sendmsg(msg); +} + +static int gsm48_rx_mm_serv_req(struct msgb *msg) +{ + struct gsm48_hdr *gh = msgb_l3(msg); + + DEBUGP(DMM, "CM SERVICE REQUEST\n"); + return gsm48_tx_mm_serv_ack(msg->lchan); +} + static int gsm0408_rcv_mm(struct msgb *msg) { struct gsm48_hdr *gh = msgb_l3(msg); @@ -259,6 +331,8 @@ static int gsm0408_rcv_mm(struct msgb *msg) case GSM48_MT_MM_AUTH_RESP: case GSM48_MT_MM_IMSI_DETACH_IND: case GSM48_MT_MM_CM_SERV_REQ: + rc = gsm48_rx_mm_serv_req(msg); + break; case GSM48_MT_MM_CM_REEST_REQ: fprintf(stderr, "Unimplemented GSM 04.08 MM msg type 0x%02x\n", gh->msg_type);