diff --git a/include/openbsc/abis_rsl.h b/include/openbsc/abis_rsl.h index b3318d32f..160e2807d 100644 --- a/include/openbsc/abis_rsl.h +++ b/include/openbsc/abis_rsl.h @@ -54,6 +54,7 @@ struct abis_rsl_dchan_hdr { #define ABIS_RSL_MDISC_COM_CHAN 0x0c #define ABIS_RSL_MDISC_TRX 0x10 #define ABIS_RSL_MDISC_LOC 0x20 +#define ABIS_RSL_MDISC_IPACCESS 0x7e #define ABIS_RSL_MDISC_IS_TRANSP(x) (x & 0x01) @@ -121,6 +122,16 @@ enum abis_rsl_msgtype { RSL_MT_MR_CODEC_MOD_PER, RSL_MT_TFO_REP, RSL_MT_TFO_MOD_REQ, /* 0x3f */ + + /* ip.access specific RSL message types */ + RSL_MT_IPAC_BIND = 0x70, /* Bind to local BTS RTP port */ + RSL_MT_IPAC_BIND_ACK, + RSL_MT_IPAC_BIND_NACK, + RSL_MT_IPAC_CONNECT = 0x73, + RSL_MT_IPAC_CONNECT_ACK, + RSL_MT_IPAC_CONNECT_NACK, + RSL_MT_IPAC_DISCONNECT_IND = 0x76, + }; /* Chapter 9.3 */ @@ -185,6 +196,11 @@ enum abis_rsl_ie { RSL_IE_RTD, RSL_IE_TFO_STATUS, RSL_IE_LLP_APDU, + + RSL_IE_IPAC_REMOTE_IP = 0xf0, + RSL_IE_IPAC_REMOTE_PORT = 0xf1, + RSL_IE_IPAC_LOCAL_PORT = 0xf3, + RSL_IE_IPAC_LOCAL_IP = 0xf5, }; /* Chapter 9.3.1 */ @@ -371,6 +387,11 @@ int rsl_imm_assign_cmd(struct gsm_bts *bts, u_int8_t len, u_int8_t *val); int rsl_data_request(struct msgb *msg, u_int8_t link_id); +/* ip.access specfic RSL extensions */ +int rsl_ipacc_bind(struct gsm_lchan *lchan); +int rsl_ipacc_connect(struct gsm_lchan *lchan, u_int32_t ip, + u_int16_t port, u_int16_t f8, u_int8_t fc); + int abis_rsl_rcvmsg(struct msgb *msg); unsigned int get_paging_group(u_int64_t imsi, unsigned int bs_cc_chans, diff --git a/include/openbsc/gsm_data.h b/include/openbsc/gsm_data.h index 0aa3c59b7..2048abc1f 100644 --- a/include/openbsc/gsm_data.h +++ b/include/openbsc/gsm_data.h @@ -174,6 +174,12 @@ struct gsm_bts_trx_ts { /* To which E1 subslot are we connected */ struct gsm_e1_subslot e1_link; + struct { + u_int32_t bound_ip; + u_int16_t bound_port; + u_int8_t attr_fc; + u_int16_t attr_f8; + } abis_ip; struct gsm_lchan lchan[TS_MAX_LCHAN]; }; diff --git a/src/abis_rsl.c b/src/abis_rsl.c index 53d638612..90d43608d 100644 --- a/src/abis_rsl.c +++ b/src/abis_rsl.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -39,6 +40,78 @@ #define MAX(a, b) (a) >= (b) ? (a) : (b) +static const struct tlv_definition rsl_att_tlvdef = { + .def = { + [RSL_IE_CHAN_NR] = { TLV_TYPE_TV }, + [RSL_IE_LINK_IDENT] = { TLV_TYPE_TV }, + [RSL_IE_ACT_TYPE] = { TLV_TYPE_TV }, + [RSL_IE_BS_POWER] = { TLV_TYPE_TV }, + [RSL_IE_CHAN_IDENT] = { TLV_TYPE_TLV }, + [RSL_IE_CHAN_MODE] = { TLV_TYPE_TLV }, + [RSL_IE_ENCR_INFO] = { TLV_TYPE_TLV }, + [RSL_IE_FRAME_NUMBER] = { TLV_TYPE_FIXED, 2 }, + [RSL_IE_HANDO_REF] = { TLV_TYPE_TV }, + [RSL_IE_L1_INFO] = { TLV_TYPE_FIXED, 2 }, + [RSL_IE_L3_INFO] = { TLV_TYPE_TL16V }, + [RSL_IE_MS_IDENTITY] = { TLV_TYPE_TLV }, + [RSL_IE_MS_POWER] = { TLV_TYPE_TV }, + [RSL_IE_PAGING_GROUP] = { TLV_TYPE_TV }, + [RSL_IE_PAGING_LOAD] = { TLV_TYPE_FIXED, 2 }, + [RSL_IE_PYHS_CONTEXT] = { TLV_TYPE_TLV }, + [RSL_IE_ACCESS_DELAY] = { TLV_TYPE_TV }, + [RSL_IE_RACH_LOAD] = { TLV_TYPE_TLV }, + [RSL_IE_REQ_REFERENCE] = { TLV_TYPE_FIXED, 3 }, + [RSL_IE_RELEASE_MODE] = { TLV_TYPE_TV }, + [RSL_IE_RESOURCE_INFO] = { TLV_TYPE_TLV }, + [RSL_IE_RLM_CAUSE] = { TLV_TYPE_TLV }, + [RSL_IE_STARTNG_TIME] = { TLV_TYPE_FIXED, 2 }, + [RSL_IE_TIMING_ADVANCE] = { TLV_TYPE_TV }, + [RSL_IE_UPLINK_MEAS] = { TLV_TYPE_TLV }, + [RSL_IE_CAUSE] = { TLV_TYPE_TLV }, + [RSL_IE_MEAS_RES_NR] = { TLV_TYPE_TV }, + [RSL_IE_MSG_ID] = { TLV_TYPE_TV }, + [RSL_IE_SYSINFO_TYPE] = { TLV_TYPE_TV }, + [RSL_IE_MS_POWER_PARAM] = { TLV_TYPE_TLV }, + [RSL_IE_BS_POWER_PARAM] = { TLV_TYPE_TLV }, + [RSL_IE_PREPROC_PARAM] = { TLV_TYPE_TLV }, + [RSL_IE_PREPROC_MEAS] = { TLV_TYPE_TLV }, + [RSL_IE_IMM_ASS_INFO] = { TLV_TYPE_TLV }, + [RSL_IE_SMSCB_INFO] = { TLV_TYPE_FIXED, 23 }, + [RSL_IE_MS_TIMING_OFFSET] = { TLV_TYPE_TV }, + [RSL_IE_ERR_MSG] = { TLV_TYPE_TLV }, + [RSL_IE_FULL_BCCH_INFO] = { TLV_TYPE_TLV }, + [RSL_IE_CHAN_NEEDED] = { TLV_TYPE_TV }, + [RSL_IE_CB_CMD_TYPE] = { TLV_TYPE_TV }, + [RSL_IE_SMSCB_MSG] = { TLV_TYPE_TLV }, + [RSL_IE_FULL_IMM_ASS_INFO] = { TLV_TYPE_TLV }, + [RSL_IE_SACCH_INFO] = { TLV_TYPE_TLV }, + [RSL_IE_CBCH_LOAD_INFO] = { TLV_TYPE_TV }, + [RSL_IE_SMSCB_CHAN_INDICATOR] = { TLV_TYPE_TV }, + [RSL_IE_GROUP_CALL_REF] = { TLV_TYPE_TLV }, + [RSL_IE_CHAN_DESC] = { TLV_TYPE_TLV }, + [RSL_IE_NCH_DRX_INFO] = { TLV_TYPE_TLV }, + [RSL_IE_CMD_INDICATOR] = { TLV_TYPE_TLV }, + [RSL_IE_EMLPP_PRIO] = { TLV_TYPE_TV }, + [RSL_IE_UIC] = { TLV_TYPE_TLV }, + [RSL_IE_MAIN_CHAN_REF] = { TLV_TYPE_TV }, + [RSL_IE_MR_CONFIG] = { TLV_TYPE_TLV }, + [RSL_IE_MR_CONTROL] = { TLV_TYPE_TV }, + [RSL_IE_SUP_CODEC_TYPES] = { TLV_TYPE_TLV }, + [RSL_IE_CODEC_CONFIG] = { TLV_TYPE_TLV }, + [RSL_IE_RTD] = { TLV_TYPE_TV }, + [RSL_IE_TFO_STATUS] = { TLV_TYPE_TV }, + [RSL_IE_LLP_APDU] = { TLV_TYPE_TLV }, + [RSL_IE_IPAC_REMOTE_IP] = { TLV_TYPE_FIXED, 4 }, + [RSL_IE_IPAC_REMOTE_PORT] = { TLV_TYPE_FIXED, 2 }, + [RSL_IE_IPAC_LOCAL_IP] = { TLV_TYPE_FIXED, 4 }, + [RSL_IE_IPAC_LOCAL_PORT] = { TLV_TYPE_FIXED, 2 }, + [0xf4] = { TLV_TYPE_TV }, + [0xf8] = { TLV_TYPE_FIXED, 2 }, + [0xfc] = { TLV_TYPE_TV }, + }, +}; +#define rsl_tlv_parse(dec, buf, len) tlv_parse(dec, &rsl_att_tlvdef, buf, len) + static u_int8_t mdisc_by_msgtype(u_int8_t msg_type) { /* mask off the transparent bit ? */ @@ -793,6 +866,145 @@ static int abis_rsl_rx_rll(struct msgb *msg) return rc; } +/* ip.access specific RSL extensions */ +int rsl_ipacc_bind(struct gsm_lchan *lchan) +{ + struct msgb *msg = rsl_msgb_alloc(); + struct abis_rsl_dchan_hdr *dh; + + dh = (struct abis_rsl_dchan_hdr *) msgb_put(msg, sizeof(*dh)); + init_dchan_hdr(dh, RSL_MT_IPAC_BIND); + dh->c.msg_discr = ABIS_RSL_MDISC_IPACCESS; + dh->chan_nr = lchan2chan_nr(lchan); + + msg->trx = lchan->ts->trx; + + return abis_rsl_sendmsg(msg); +} + +int rsl_ipacc_connect(struct gsm_lchan *lchan, u_int32_t ip, u_int16_t port, u_int16_t f8, u_int8_t fc) +{ + struct msgb *msg = rsl_msgb_alloc(); + struct abis_rsl_dchan_hdr *dh; + u_int8_t *att_f8, *att_ip, *att_port; + + dh = (struct abis_rsl_dchan_hdr *) msgb_put(msg, sizeof(*dh)); + init_dchan_hdr(dh, RSL_MT_IPAC_CONNECT); + dh->c.msg_discr = ABIS_RSL_MDISC_IPACCESS; + dh->chan_nr = lchan2chan_nr(lchan); + + att_f8 = msgb_put(msg, sizeof(f8)+1); + att_f8[0] = 0xf8; + att_f8[1] = f8 >> 8; + att_f8[2] = f8 & 0xff; + + att_ip = msgb_put(msg, sizeof(ip)+1); + att_ip[0] = RSL_IE_IPAC_REMOTE_IP; + att_ip[1] = ip >> 24; + att_ip[2] = ip >> 16; + att_ip[3] = ip >> 8; + att_ip[4] = ip & 0xff; + + att_port = msgb_put(msg, sizeof(port)+1); + att_port[0] = RSL_IE_IPAC_REMOTE_PORT; + att_port[1] = port >> 8; + att_port[2] = port & 0xff; + + msgb_tv_put(msg, 0xf4, 1); /* F4 01 */ + msgb_tv_put(msg, 0xfc, fc); /* FC 7F */ + msg->trx = lchan->ts->trx; + + return abis_rsl_sendmsg(msg); +} + +static int abis_rsl_rx_ipacc_bindack(struct msgb *msg) +{ + struct abis_rsl_dchan_hdr *dh = msgb_l2(msg); + struct tlv_parsed tv; + struct gsm_bts_trx_ts *ts = msg->lchan->ts; + u_int32_t ip; + u_int16_t port, attr_f8; + + /* the BTS has acknowledged a local bind, it now tells us the IP + * address and port number to which it has bound the given logical + * channel */ + + rsl_tlv_parse(&tv, dh->data, msgb_l2len(msg)-sizeof(*dh)); + if (!TLVP_PRESENT(&tv, RSL_IE_IPAC_LOCAL_PORT) || + !TLVP_PRESENT(&tv, RSL_IE_IPAC_LOCAL_IP) || + !TLVP_PRESENT(&tv, 0xfc) || + !TLVP_PRESENT(&tv, 0xf8)) { + DEBUGP(DRSL, "mandatory IE missing\n"); + return -EINVAL; + } + ip = *((u_int32_t *) TLVP_VAL(&tv, RSL_IE_IPAC_LOCAL_IP)); + port = *((u_int16_t *) TLVP_VAL(&tv, RSL_IE_IPAC_LOCAL_PORT)); + attr_f8 = *((u_int16_t *) TLVP_VAL(&tv, 0xf8)); + + /* update our local information about this TS */ + ts->abis_ip.bound_ip = ntohl(ip); + ts->abis_ip.bound_port = ntohl(port); + ts->abis_ip.attr_f8 = ntohs(attr_f8); + ts->abis_ip.attr_fc = *TLVP_VAL(&tv, 0xfc); + + return 0; +} + +static int abis_rsl_rx_ipacc_disc_ind(struct msgb *msg) +{ + struct abis_rsl_dchan_hdr *dh = msgb_l2(msg); + struct tlv_parsed tv; + + rsl_tlv_parse(&tv, dh->data, msgb_l2len(msg)-sizeof(*dh)); + if (!TLVP_PRESENT(&tv, RSL_IE_CAUSE)) { + DEBUGP(DRSL, "mandatory IE missing\n"); + return -EINVAL; + } + + DEBUGP(DNM, "cause=0x%02x\n", *TLVP_VAL(&tv, RSL_IE_CAUSE)); + + return 0; +} + +static int abis_rsl_rx_ipacc(struct msgb *msg) +{ + struct abis_rsl_rll_hdr *rllh = msgb_l2(msg); + int rc = 0; + + msg->lchan = lchan_lookup(msg->trx, rllh->chan_nr); + + switch (rllh->c.msg_type) { + case RSL_MT_IPAC_BIND_ACK: + DEBUGP(DRSL, "IPAC_BIND_ACK\n"); + rc = abis_rsl_rx_ipacc_bindack(msg); + break; + case RSL_MT_IPAC_BIND_NACK: + /* somehow the BTS was unable to bind the lchan to its local + * port?!? */ + DEBUGP(DRSL, "IPAC_BIND_NACK\n"); + break; + case RSL_MT_IPAC_CONNECT_ACK: + /* the BTS tells us that a connect operation was successful */ + DEBUGP(DRSL, "IPAC_CONNECT_ACK\n"); + break; + case RSL_MT_IPAC_CONNECT_NACK: + /* somehow the BTS was unable to connect the lchan to a remote + * port */ + DEBUGP(DRSL, "IPAC_BIND_NACK\n"); + break; + case RSL_MT_IPAC_DISCONNECT_IND: + DEBUGP(DRSL, "IPAC_DISCONNECT_IND\n"); + rc = abis_rsl_rx_ipacc_disc_ind(msg); + break; + default: + DEBUGP(DRSL, "Unknown ip.access msg_type 0x%02x\n", rllh->c.msg_type); + break; + } + + return rc; +} + + /* Entry-point where L2 RSL from BTS enters */ int abis_rsl_rcvmsg(struct msgb *msg) { @@ -816,6 +1028,9 @@ int abis_rsl_rcvmsg(struct msgb *msg) fprintf(stderr, "unimplemented RSL msg disc 0x%02x\n", rslh->msg_discr); break; + case ABIS_RSL_MDISC_IPACCESS: + rc = abis_rsl_rx_ipacc(msg); + break; default: fprintf(stderr, "unknown RSL message discriminator 0x%02x\n", rslh->msg_discr);