Add support for ip.access RSL link on port 3003

This commit is contained in:
Harald Welte 2009-02-15 11:57:29 +00:00
parent 7782c14295
commit 5c1e458376
5 changed files with 184 additions and 46 deletions

View File

@ -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,

View File

@ -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);
}

View File

@ -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,

View File

@ -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 */

View File

@ -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)