From 5c1e458376a2a2a50ca2bc454b721013fe3f02ec Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 15 Feb 2009 11:57:29 +0000 Subject: [PATCH] Add support for ip.access RSL link on port 3003 --- include/openbsc/abis_nm.h | 13 +++- src/abis_nm.c | 71 ++++++++++++++++++-- src/bsc_hack.c | 8 +++ src/e1_config.c | 6 +- src/input/ipaccess.c | 132 +++++++++++++++++++++++++++----------- 5 files changed, 184 insertions(+), 46 deletions(-) diff --git a/include/openbsc/abis_nm.h b/include/openbsc/abis_nm.h index dfe0bf7b8..2592d4362 100644 --- a/include/openbsc/abis_nm.h +++ b/include/openbsc/abis_nm.h @@ -219,6 +219,11 @@ enum abis_nm_obj_class { NM_OC_BS11_ENVABTSE = 0xa8, NM_OC_BS11_BPORT = 0xa9, + NM_OC_GPRS_NSE = 0xf0, + NM_OC_GPRS_CELL = 0xf1, + NM_OC_GPRS_NSVC0 = 0xf2, + NM_OC_GPRS_NSVC1 = 0xf3, + NM_OC_NULL = 0xff, }; @@ -491,7 +496,7 @@ int abis_nm_set_bts_attr(struct gsm_bts *bts, u_int8_t *attr, int attr_len); int abis_nm_set_radio_attr(struct gsm_bts_trx *trx, u_int8_t *attr, int attr_len); int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, u_int8_t chan_comb); int abis_nm_sw_act_req_ack(struct gsm_bts *bts, u_int8_t obj_class, u_int8_t i1, - u_int8_t i2, u_int8_t i3, u_int8_t *attr, int att_len); + u_int8_t i2, u_int8_t i3, int nack, u_int8_t *attr, int att_len); int abis_nm_raw_msg(struct gsm_bts *bts, int len, u_int8_t *msg); int abis_nm_event_reports(struct gsm_bts *bts, int on); int abis_nm_reset_resource(struct gsm_bts *bts); @@ -522,6 +527,12 @@ int abis_nm_bs11_set_ext_time(struct gsm_bts *bts); int abis_nm_bs11_bsc_disconnect(struct gsm_bts *bts, int reconnect); int abis_nm_bs11_restart(struct gsm_bts *bts); +/* ip.access nanoBTS specific commands */ +int abis_nm_ipaccess_msg(struct gsm_bts *bts, u_int8_t msg_type, + u_int8_t obj_class, u_int8_t bts_nr, + u_int8_t trx_nr, u_int8_t ts_nr, + u_int8_t *attr, int attr_len); + /* Functions calling into other code parts */ enum nm_evt { EVT_STATECHG_OPER, diff --git a/src/abis_nm.c b/src/abis_nm.c index 159424aa8..e3346a6f4 100644 --- a/src/abis_nm.c +++ b/src/abis_nm.c @@ -537,16 +537,26 @@ static int abis_nm_rx_sw_act_req(struct msgb *mb) { struct abis_om_hdr *oh = msgb_l2(mb); struct abis_om_fom_hdr *foh = msgb_l3(mb); + int nack = 0; int ret; - DEBUGP(DNM, "Software Activate Request, ACKing and Activating\n"); + DEBUGP(DNM, "Software Activate Request "); - ret = abis_nm_sw_act_req_ack(mb->trx->bts, foh->obj_class, + if (foh->obj_class >= 0xf0 && foh->obj_class <= 0xf3) { + DEBUGPC(DNM, "NACKing for GPRS obj_class 0x%02x\n", foh->obj_class); + nack = 1; + } else + DEBUGPC(DNM, "ACKing and Activating\n"); + + ret = abis_nm_sw_act_req_ack(mb->trx->bts, foh->obj_class, foh->obj_inst.bts_nr, foh->obj_inst.trx_nr, - foh->obj_inst.ts_nr, + foh->obj_inst.ts_nr, nack, foh->data, oh->length-sizeof(*foh)); + if (nack) + return ret; + /* FIXME: properly parse attributes */ return ipacc_sw_activate(mb->trx->bts, foh->obj_class, foh->obj_inst.bts_nr, @@ -1290,18 +1300,27 @@ int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, u_int8_t chan_comb) } int abis_nm_sw_act_req_ack(struct gsm_bts *bts, u_int8_t obj_class, u_int8_t i1, - u_int8_t i2, u_int8_t i3, u_int8_t *attr, int att_len) + u_int8_t i2, u_int8_t i3, int nack, u_int8_t *attr, int att_len) { struct abis_om_hdr *oh; struct msgb *msg = nm_msgb_alloc(); + u_int8_t msgtype = NM_MT_SW_ACT_REQ_ACK; + u_int8_t len = att_len; + + if (nack) { + len += 2; + msgtype = NM_MT_SW_ACT_REQ_NACK; + } oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE); - fill_om_fom_hdr(oh, att_len, NM_MT_SW_ACT_REQ_ACK, obj_class, i1, i2, i3); - /* FIXME: don't send ARFCN list, hopping sequence, mAIO, ...*/ + fill_om_fom_hdr(oh, att_len, msgtype, obj_class, i1, i2, i3); + if (attr) { u_int8_t *ptr = msgb_put(msg, att_len); memcpy(ptr, attr, att_len); } + if (nack) + msgb_tv_put(msg, NM_ATT_NACK_CAUSES, NM_NACK_OBJCLASS_NOTSUPP); return abis_nm_sendmsg(bts, msg); } @@ -1779,3 +1798,43 @@ int abis_nm_bs11_set_ext_time(struct gsm_bts *bts) return abis_nm_sendmsg(bts, msg); } + +/* ip.access nanoBTS specific commands */ + +static const char ipaccess_magic[] = "com.ipaccess"; + +int abis_nm_ipaccess_msg(struct gsm_bts *bts, u_int8_t msg_type, + u_int8_t obj_class, u_int8_t bts_nr, + u_int8_t trx_nr, u_int8_t ts_nr, + u_int8_t *attr, int attr_len) +{ + struct msgb *msg = nm_msgb_alloc(); + struct abis_om_hdr *oh; + struct abis_om_fom_hdr *foh; + u_int8_t *data; + + /* construct the 12.21 OM header, observe the erroneous length */ + oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh)); + fill_om_hdr(oh, sizeof(*foh) + attr_len); + oh->mdisc = ABIS_OM_MDISC_MANUF; + + /* add the ip.access magic */ + data = msgb_put(msg, sizeof(ipaccess_magic)+1); + *data++ = sizeof(ipaccess_magic); + memcpy(data, ipaccess_magic, sizeof(ipaccess_magic)); + + /* fill the 12.21 FOM header */ + foh = (struct abis_om_fom_hdr *) msgb_put(msg, sizeof(*foh)); + foh->msg_type = msg_type; + foh->obj_class = obj_class; + foh->obj_inst.bts_nr = bts_nr; + foh->obj_inst.trx_nr = trx_nr; + foh->obj_inst.ts_nr = ts_nr; + + if (attr && attr_len) { + data = msgb_put(msg, attr_len); + memcpy(data, attr, attr_len); + } + + return abis_nm_sendmsg(bts, msg); +} diff --git a/src/bsc_hack.c b/src/bsc_hack.c index f3be6c26b..5b6e4a3e3 100644 --- a/src/bsc_hack.c +++ b/src/bsc_hack.c @@ -302,6 +302,11 @@ static unsigned char nanobts_attr_radio[] = { NM_ATT_ARFCN_LIST, 0x00, 0x02, HARDCODED_ARFCN >> 8, HARDCODED_ARFCN & 0xff, }; +static unsigned char nanobts_attr_e0[] = { + 0x85, 0x00, + 0x81, 0x0b, 0xbb, /* TCP PORT for RSL */ +}; + int nm_state_event(enum nm_evt evt, u_int8_t obj_class, void *obj, struct gsm_nm_state *old_state, struct gsm_nm_state *new_state) { @@ -362,6 +367,9 @@ int nm_state_event(enum nm_evt evt, u_int8_t obj_class, void *obj, case NM_OC_BASEB_TRANSC: trx = container_of(obj, struct gsm_bts_trx, bb_transc); if (new_state->availability == 5) { + abis_nm_ipaccess_msg(trx->bts, 0xe0, NM_OC_BASEB_TRANSC, + trx->bts->nr, trx->nr, 0xff, + nanobts_attr_e0, sizeof(nanobts_attr_e0)); abis_nm_opstart(trx->bts, NM_OC_BASEB_TRANSC, trx->bts->nr, trx->nr, 0xff); abis_nm_chg_adm_state(trx->bts, NM_OC_BASEB_TRANSC, diff --git a/src/e1_config.c b/src/e1_config.c index 9863c9e47..8d9ac66be 100644 --- a/src/e1_config.c +++ b/src/e1_config.c @@ -71,7 +71,7 @@ int e1_config(struct gsm_bts *bts) int ia_config(struct gsm_bts *bts) { struct e1inp_line *line; - struct e1inp_ts *sign_ts; + struct e1inp_ts *sign_ts, *rsl_ts; struct e1inp_sign_link *oml_link, *rsl_link; line = malloc(sizeof(*line)); @@ -81,12 +81,14 @@ int ia_config(struct gsm_bts *bts) /* create E1 timeslots for signalling and TRAU frames */ e1inp_ts_config(&line->ts[1-1], line, E1INP_TS_TYPE_SIGN); + e1inp_ts_config(&line->ts[2-1], line, E1INP_TS_TYPE_SIGN); /* create signalling links for TS1 */ sign_ts = &line->ts[1-1]; + rsl_ts = &line->ts[2-1]; oml_link = e1inp_sign_link_create(sign_ts, E1INP_SIGN_OML, bts->c0, 0, 0xff); - rsl_link = e1inp_sign_link_create(sign_ts, E1INP_SIGN_RSL, + rsl_link = e1inp_sign_link_create(rsl_ts, E1INP_SIGN_RSL, bts->c0, 0, 0); /* create back-links from bts/trx */ diff --git a/src/input/ipaccess.c b/src/input/ipaccess.c index 22582678f..bfccbc768 100644 --- a/src/input/ipaccess.c +++ b/src/input/ipaccess.c @@ -44,6 +44,7 @@ /* data structure for one E1 interface with A-bis */ struct ia_e1_handle { struct bsc_fd listen_fd; + struct bsc_fd rsl_listen_fd; }; #define TS1_ALLOC_SIZE 300 @@ -98,6 +99,7 @@ static int ipaccess_rcvmsg(struct msgb *msg, int fd) /* FIXME: this is per BTS */ static int oml_up = 0; +static int rsl_up = 0; static int handle_ts1_read(struct bsc_fd *bfd) { @@ -134,8 +136,8 @@ static int handle_ts1_read(struct bsc_fd *bfd) ret = recv(bfd->fd, msg->l2h, hh->len, 0); if (ret < hh->len) { fprintf(stderr, "short read!\n"); - //msgb_free(msg); - //return -EIO; + msgb_free(msg); + return -EIO; } msgb_put(msg, ret); @@ -143,7 +145,7 @@ static int handle_ts1_read(struct bsc_fd *bfd) return ipaccess_rcvmsg(msg, bfd->fd); if (debug_mask & DMI) { - fprintf(stdout, "RX: "); + fprintf(stdout, "RX %u: ", ts_nr); hexdump(msgb_l2(msg), ret); } @@ -157,6 +159,10 @@ static int handle_ts1_read(struct bsc_fd *bfd) switch (hh->proto) { case PROTO_RSL: + if (!rsl_up) { + e1inp_event(e1i_ts, EVT_E1_TEI_UP, 0, PROTO_RSL); + rsl_up = 1; + } ret = abis_rsl_rcvmsg(msg); break; case PROTO_OML: @@ -212,7 +218,7 @@ static int handle_ts1_write(struct bsc_fd *bfd) } if (debug_mask & DMI) { - fprintf(stdout, "TX: "); + fprintf(stdout, "TX %u: ", ts_nr); hexdump(l2_data, hh->len); } @@ -294,7 +300,7 @@ static int listen_fd_cb(struct bsc_fd *listen_bfd, unsigned int what) socklen_t sa_len = sizeof(sa); if (bfd->fd) { - printf("dumping old fd\n"); + printf("dumping old OML fd\n"); if (bfd->fd != -1) { bsc_unregister_fd(bfd); close(bfd->fd); @@ -305,7 +311,7 @@ static int listen_fd_cb(struct bsc_fd *listen_bfd, unsigned int what) perror("accept"); return bfd->fd; } - printf("accept()ed new RSL/OML fd\n"); + printf("accept()ed new OML fd\n"); bfd->data = line; bfd->priv_nr = 1; bfd->cb = ipaccess_fd_cb; @@ -319,11 +325,88 @@ static int listen_fd_cb(struct bsc_fd *listen_bfd, unsigned int what) return 0; } -int ipaccess_setup(struct e1inp_line *line) +static int rsl_listen_fd_cb(struct bsc_fd *listen_bfd, unsigned int what) +{ + struct e1inp_line *line = listen_bfd->data; + int ret; + + if (what & BSC_FD_READ) { + int idx = 1; + struct e1inp_ts *e1i_ts = &line->ts[idx]; + struct bsc_fd *bfd = &e1i_ts->driver.ipaccess.fd; + struct sockaddr_in sa; + socklen_t sa_len = sizeof(sa); + + if (bfd->fd) { + printf("dumping old RSL fd\n"); + if (bfd->fd != -1) { + bsc_unregister_fd(bfd); + close(bfd->fd); + } + } + bfd->fd = accept(listen_bfd->fd, (struct sockaddr *) &sa, &sa_len); + if (bfd->fd < 0) { + perror("accept"); + return bfd->fd; + } + printf("accept()ed new RSL fd\n"); + bfd->data = line; + bfd->priv_nr = 2; + bfd->cb = ipaccess_fd_cb; + bfd->when = BSC_FD_READ; + ret = bsc_register_fd(bfd); + if (ret < 0) { + fprintf(stderr, "could not register FD\n"); + return ret; + } + } + return 0; +} + +static int make_sock(struct bsc_fd *bfd, u_int16_t port, + struct e1inp_line *line, + int (*cb)(struct bsc_fd *fd, unsigned int what)) { struct sockaddr_in addr; + int ret, on = 1; + + bfd->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + bfd->cb = cb; + bfd->when = BSC_FD_READ; + bfd->data = line; + + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + addr.sin_addr.s_addr = INADDR_ANY; + + setsockopt(bfd->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); + + ret = bind(bfd->fd, (struct sockaddr *) &addr, sizeof(addr)); + if (ret < 0) { + fprintf(stderr, "could not bind l2 socket %s\n", + strerror(errno)); + return -EIO; + } + + ret = listen(bfd->fd, 1); + if (ret < 0) { + perror("listen"); + return ret; + } + + ret = bsc_register_fd(bfd); + if (ret < 0) { + perror("register_listen_fd"); + return ret; + } + return 0; +} + +int ipaccess_setup(struct e1inp_line *line) +{ struct ia_e1_handle *e1h; - int sk, ret, on = 1; + int ret; /* register the driver with the core */ /* FIXME: do this in the plugin initializer function */ @@ -339,36 +422,11 @@ int ipaccess_setup(struct e1inp_line *line) line->driver = &ipaccess_driver; line->driver_data = e1h; - e1h->listen_fd.fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - e1h->listen_fd.cb = listen_fd_cb; - e1h->listen_fd.when = BSC_FD_READ; - e1h->listen_fd.data = line; + /* Listen for OML connections */ + ret = make_sock(&e1h->listen_fd, 3002, line, listen_fd_cb); - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_port = htons(3002); - addr.sin_addr.s_addr = INADDR_ANY; - - setsockopt(e1h->listen_fd.fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); - - ret = bind(e1h->listen_fd.fd, (struct sockaddr *) &addr, sizeof(addr)); - if (ret < 0) { - fprintf(stderr, "could not bind l2 socket %s\n", - strerror(errno)); - return -EIO; - } - - ret = listen(e1h->listen_fd.fd, 1); - if (ret < 0) { - perror("listen"); - return ret; - } - - ret = bsc_register_fd(&e1h->listen_fd); - if (ret < 0) { - perror("register_listen_fd"); - return ret; - } + /* Listen for RSL connections */ + ret = make_sock(&e1h->rsl_listen_fd, 3003, line, rsl_listen_fd_cb); ret = ia_e1_setup(line); if (ret)