aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/openbsc/abis_nm.h13
-rw-r--r--src/abis_nm.c71
-rw-r--r--src/bsc_hack.c8
-rw-r--r--src/e1_config.c6
-rw-r--r--src/input/ipaccess.c120
5 files changed, 178 insertions, 40 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,56 +325,108 @@ 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 sockaddr_in addr;
- struct ia_e1_handle *e1h;
- int sk, ret, on = 1;
-
- /* register the driver with the core */
- /* FIXME: do this in the plugin initializer function */
- ret = e1inp_driver_register(&ipaccess_driver);
- if (ret)
- return ret;
+ struct e1inp_line *line = listen_bfd->data;
+ int ret;
- /* create the actual line instance */
- /* FIXME: do this independent of driver registration */
- e1h = malloc(sizeof(*e1h));
- memset(e1h, 0, sizeof(*e1h));
+ 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);
- line->driver = &ipaccess_driver;
- line->driver_data = e1h;
+ 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;
+}
- 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;
+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(3002);
+ addr.sin_port = htons(port);
addr.sin_addr.s_addr = INADDR_ANY;
- setsockopt(e1h->listen_fd.fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
+ setsockopt(bfd->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
- ret = bind(e1h->listen_fd.fd, (struct sockaddr *) &addr, sizeof(addr));
+ 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(e1h->listen_fd.fd, 1);
+ ret = listen(bfd->fd, 1);
if (ret < 0) {
perror("listen");
return ret;
}
- ret = bsc_register_fd(&e1h->listen_fd);
+ 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 ret;
+
+ /* register the driver with the core */
+ /* FIXME: do this in the plugin initializer function */
+ ret = e1inp_driver_register(&ipaccess_driver);
+ if (ret)
+ return ret;
+
+ /* create the actual line instance */
+ /* FIXME: do this independent of driver registration */
+ e1h = malloc(sizeof(*e1h));
+ memset(e1h, 0, sizeof(*e1h));
+
+ line->driver = &ipaccess_driver;
+ line->driver_data = e1h;
+
+ /* Listen for OML connections */
+ ret = make_sock(&e1h->listen_fd, 3002, line, listen_fd_cb);
+
+ /* Listen for RSL connections */
+ ret = make_sock(&e1h->rsl_listen_fd, 3003, line, rsl_listen_fd_cb);
ret = ia_e1_setup(line);
if (ret)