From 8470bf200de094ec362f3f7565ab3ccdf26ee664 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 25 Dec 2008 23:28:35 +0000 Subject: [PATCH] no reasonable commit message possible. tons of changes of the last 2 days --- include/openbsc/abis_nm.h | 4 +- include/openbsc/abis_rsl.h | 12 +- include/openbsc/chan_alloc.h | 22 +++ include/openbsc/gsm_04_08.h | 7 + include/openbsc/gsm_data.h | 56 +++++++ include/openbsc/gsm_subscriber.h | 2 +- include/openbsc/msgb.h | 27 ++- include/openbsc/select.h | 5 + src/abis_nm.c | 58 ++++--- src/abis_rsl.c | 278 ++++++++++++++++++++++++------- src/bsc_hack.c | 10 +- src/chan_alloc.c | 150 +++++++++++++++++ src/gsm_04_08.c | 139 +++++++++++++--- src/gsm_data.c | 15 +- src/gsm_subscriber.c | 3 +- src/misdn.c | 161 ++++++++++++++---- src/msgb.c | 21 ++- src/select.c | 4 +- 18 files changed, 818 insertions(+), 156 deletions(-) create mode 100644 include/openbsc/chan_alloc.h create mode 100644 src/chan_alloc.c diff --git a/include/openbsc/abis_nm.h b/include/openbsc/abis_nm.h index 1108aa443..ca4de85a4 100644 --- a/include/openbsc/abis_nm.h +++ b/include/openbsc/abis_nm.h @@ -275,7 +275,7 @@ enum abis_nm_chan_comb { }; /* Section 9.4.1 */ -struct abis_nm_abis_channel { +struct abis_nm_channel { u_int8_t attrib; u_int8_t bts_port; u_int8_t timeslot; @@ -294,7 +294,7 @@ struct abis_nm_cfg { int (*sw_act_req)(struct msgb *); }; -extern int abis_nm_rx(struct msgb *msg); +extern int abis_nm_rcvmsg(struct msgb *msg); //extern struct abis_nm_h *abis_nm_init(struct abis_nm_cfg *cfg); //extern void abis_nm_fini(struct abis_nm_h *nmh); diff --git a/include/openbsc/abis_rsl.h b/include/openbsc/abis_rsl.h index 9413f6577..cbbb797fb 100644 --- a/include/openbsc/abis_rsl.h +++ b/include/openbsc/abis_rsl.h @@ -105,7 +105,7 @@ enum abis_rsl_msgtype { RSL_MT_PHY_CONTEXT_CONF, RSL_MT_RF_CHAN_REL, RSL_MT_MS_POWER_CONTROL, - RSL_MT_BS_POWER_CONTROL, + RSL_MT_BS_POWER_CONTROL, /* 0x30 */ RSL_MT_PREPROC_CONFIG, RSL_MT_PREPROC_MEAS_RES, RSL_MT_RF_CHAN_REL_ACK, @@ -290,14 +290,18 @@ int rsl_chan_activate(struct gsm_bts *bts, u_int8_t chan_nr, u_int8_t ta); int rsl_chan_activate_tch_f(struct gsm_bts_trx_ts *ts); int rsl_chan_activate_sdcch(struct gsm_bts_trx_ts *ts); -int rsl_chan_release(struct gsm_bts_trx_ts *ts, u_int8_t chan_nr); +int rsl_chan_release(struct gsm_lchan *lchan); int rsl_paging_cmd(struct gsm_bts *bts, u_int8_t paging_group, u_int8_t len, u_int8_t *ms_ident, u_int8_t chan_needed); int rsl_paging_cmd_imsi(struct gsm_bts *bts, u_int8_t chan_needed, const char *imsi_str); int rsl_imm_assign_cmd(struct gsm_bts *bts, u_int8_t len, u_int8_t *val); -int rsl_data_request(struct gsm_bts *bts, struct msgb *msg); -int abis_rsl_rx(struct msgb *msg); +int rsl_data_request(struct msgb *msg, u_int8_t link_id); + +int abis_rsl_rcvmsg(struct msgb *msg); + +/* to be provided by external code */ +int abis_rsl_sendmsg(struct msgb *msg); #endif /* RSL_MT_H */ diff --git a/include/openbsc/chan_alloc.h b/include/openbsc/chan_alloc.h new file mode 100644 index 000000000..0cbd03e72 --- /dev/null +++ b/include/openbsc/chan_alloc.h @@ -0,0 +1,22 @@ +#ifndef _CHAN_ALLOC_H +#define _CHAN_ALLOC_H + +/* Special allocator for C0 of BTS */ +struct gsm_bts_trx_ts *ts_c0_alloc(struct gsm_bts *bts, + enum gsm_phys_chan_config pchan); + +/* Regular physical channel allocator */ +struct gsm_bts_trx_ts *ts_alloc(struct gsm_bts *bts, + enum gsm_phys_chan_config pchan); + +/* Regular physical channel (TS) */ +void ts_free(struct gsm_bts_trx_ts *ts); + + +/* Allocate a logical channel (SDCCH, TCH, ...) */ +struct gsm_lchan *lchan_alloc(struct gsm_bts *bts, enum gsm_chan_t type); + +/* Free a logical channel (SDCCH, TCH, ...) */ +void lchan_free(struct gsm_lchan *lchan); + +#endif /* _CHAN_ALLOC_H */ diff --git a/include/openbsc/gsm_04_08.h b/include/openbsc/gsm_04_08.h index 7c51969dc..dc5eba9ae 100644 --- a/include/openbsc/gsm_04_08.h +++ b/include/openbsc/gsm_04_08.h @@ -235,4 +235,11 @@ struct gsm48_hdr { #define GSM_MI_TYPE_TMSI 0x04 #define GSM_MI_ODD 0x08 +struct msgb; +struct gsm_bts; + +int gsm0408_rcvmsg(struct msgb *msg); +enum gsm_chan_t get_ctype_by_chreq(struct gsm_bts *bts, u_int8_t ra); + + #endif diff --git a/include/openbsc/gsm_data.h b/include/openbsc/gsm_data.h index 51e246c2d..8bb219a11 100644 --- a/include/openbsc/gsm_data.h +++ b/include/openbsc/gsm_data.h @@ -3,8 +3,11 @@ #include +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) + #define GSM_MAX_BTS 8 #define BTS_MAX_TRX 8 +#define TS_MAX_LCHAN 8 #define HARDCODED_ARFCN 123 @@ -13,6 +16,35 @@ struct gsm_bts_link { struct gsm_bts *bts; }; +enum gsm_phys_chan_config { + GSM_PCHAN_NONE, + GSM_PCHAN_CCCH, + GSM_PCHAN_CCCH_SDCCH4, + GSM_PCHAN_TCH_F, + GSM_PCHAN_TCH_H, + GSM_PCHAN_SDCCH8_SACCH8C, + GSM_PCHAN_UNKNOWN, +}; + +enum gsm_chan_t { + GSM_LCHAN_NONE, + GSM_LCHAN_SDCCH, + GSM_LCHAN_TCH_F, + GSM_LCHAN_TCH_H, + GSM_LCHAN_UNKNOWN, +}; + +struct gsm_lchan { + /* The TS that we're part of */ + struct gsm_bts_trx_ts *ts; + /* The logical subslot number in the TS */ + u_int8_t nr; + /* The lotical channel type */ + enum gsm_chan_t type; + /* To whom we are allocated at the moment */ + struct gsm_subscriber *subscr; +}; + #define BTS_TRX_F_ACTIVATED 0x0001 /* One Timeslot in a TRX */ struct gsm_bts_trx_ts { @@ -20,7 +52,11 @@ struct gsm_bts_trx_ts { /* number of this timeslot at the TRX */ u_int8_t nr; + enum gsm_phys_chan_config pchan; + unsigned int flags; + + struct gsm_lchan lchan[TS_MAX_LCHAN]; }; /* One TRX in a BTS */ @@ -71,4 +107,24 @@ struct gsm_network { struct gsm_network *gsm_network_init(unsigned int num_bts, u_int8_t country_code, u_int8_t network_code); + +enum gsm_call_type { + GSM_CT_NONE, + GSM_CT_MO, + GSM_CT_MT, +}; + +enum gsm_call_state { + GSM_CSTATE_NONE, +}; + +/* One end of a call */ +struct gsm_call { + enum gsm_call_type type; + enum gsm_call_state state; + + /* the 'local' subscriber */ + struct gsm_subscriber *subscr; +}; + #endif diff --git a/include/openbsc/gsm_subscriber.h b/include/openbsc/gsm_subscriber.h index d5c6eff7a..5bdf57952 100644 --- a/include/openbsc/gsm_subscriber.h +++ b/include/openbsc/gsm_subscriber.h @@ -5,7 +5,7 @@ #include "gsm_data.h" struct gsm_subscriber { - u_int8_t *name; + char *name; u_int8_t tmsi[4]; }; diff --git a/include/openbsc/msgb.h b/include/openbsc/msgb.h index b0740edab..13631e7bc 100644 --- a/include/openbsc/msgb.h +++ b/include/openbsc/msgb.h @@ -20,12 +20,20 @@ * */ +#include + struct bts_link; struct msgb { - /* ptr to the incoming (RX) or outgoing (TX) BTS link */ + struct llist_head list; + + /* ptr to the physical E1 link to the BTS(s) */ struct gsm_bts_link *bts_link; + /* Part of which TRX logical channel we were received / transmitted */ + struct gsm_bts_trx *trx; + struct gsm_lchan *lchan; + u_int8_t l2_off; u_int8_t l3_off; @@ -40,6 +48,8 @@ struct msgb { extern struct msgb *msgb_alloc(u_int16_t size); extern void msgb_free(struct msgb *m); +extern void msgb_enqueue(struct llist_head *queue, struct msgb *msg); +extern struct msgb *msgb_dequeue(struct llist_head *queue); #define msgb_l2(m) ((void *)(m->data + m->l2_off)) #define msgb_l3(m) ((void *)(m->data + m->l3_off)) @@ -71,4 +81,19 @@ static inline int msgb_tailroom(const struct msgb *msgb) return (msgb->data + msgb->data_len) - msgb->tail; } +/* increase the headroom of an empty msgb, reducing the tailroom */ +static inline void msgb_reserve(struct msgb *msg, int len) +{ + msg->data += len; + msg->tail += len; +} + +static inline struct msgb *msgb_alloc_headroom(int size, int headroom) +{ + struct msgb *msg = msgb_alloc(size); + if (msg) + msgb_reserve(msg, headroom); + return msg; +} + #endif /* _MSGB_H */ diff --git a/include/openbsc/select.h b/include/openbsc/select.h index f98f72c61..b677162e6 100644 --- a/include/openbsc/select.h +++ b/include/openbsc/select.h @@ -1,6 +1,8 @@ #ifndef _BSC_SELECT_H #define _BSC_SELECT_H +#include + #define BSC_FD_READ 0x0001 #define BSC_FD_WRITE 0x0002 #define BSC_FD_EXCEPT 0x0004 @@ -14,4 +16,7 @@ struct bsc_fd { unsigned int priv_nr; }; +int bsc_register_fd(struct bsc_fd *fd); +void bsc_unregister_fd(struct bsc_fd *fd); +int bsc_select_main(void); #endif /* _BSC_SELECT_H */ diff --git a/src/abis_nm.c b/src/abis_nm.c index c873b95a7..bf442fa43 100644 --- a/src/abis_nm.c +++ b/src/abis_nm.c @@ -2,6 +2,7 @@ * 3GPP TS 12.21 version 8.0.0 Release 1999 / ETSI TS 100 623 V8.0.0 */ /* (C) 2008 by Harald Welte + * * All Rights Reserved * * This program is free software; you can redistribute it and/or modify @@ -24,13 +25,16 @@ #include #include #include +#include -#include "gsm_data.h" -#include "debug.h" -#include "msgb.h" -#include "abis_nm.h" +#include +#include +#include +#include +#include -#define OM_ALLOC_SIZE 1024 +#define OM_ALLOC_SIZE 1024 +#define OM_HEADROOM_SIZE 128 /* unidirectional messages from BTS to BSC */ static const enum abis_nm_msgtype reports[] = { @@ -97,7 +101,7 @@ static int is_ack_nack(enum abis_nm_msgtype mt) /* is this msgtype a report ? */ static int is_report(enum abis_nm_msgtype mt) { - return is_in_arr(mt, reports, ARRA_YSIZE(reports)); + return is_in_arr(mt, reports, ARRAY_SIZE(reports)); } #define MT_ACK(x) (x+1) @@ -126,6 +130,11 @@ static void fill_om_fom_hdr(struct abis_om_hdr *oh, u_int8_t len, foh->obj_inst.ts_nr = ts_nr; } +static struct msgb *nm_msgb_alloc(void) +{ + return msgb_alloc_headroom(OM_ALLOC_SIZE, OM_HEADROOM_SIZE); +} + /* Send a OML NM Message from BSC to BTS */ int abis_nm_sendmsg(struct gsm_bts *bts, struct msgb *msg) { @@ -133,7 +142,7 @@ int abis_nm_sendmsg(struct gsm_bts *bts, struct msgb *msg) } /* Receive a OML NM Message from BTS */ -static int abis_nm_rcvmsg(struct msgb *mb) +static int abis_nm_rcvmsg_fom(struct msgb *mb) { struct abis_om_fom_hdr *foh = msgb_l3(mb); u_int8_t mt = foh->msg_type; @@ -164,11 +173,11 @@ static int abis_nm_rcvmsg(struct msgb *mb) /* High-Level API */ /* Entry-point where L2 OML from BTS enters the NM code */ -int abis_nm_rx(struct msgb *msg) +int abis_nm_rcvmsg(struct msgb *msg) { int rc; struct abis_om_hdr *oh = msgb_l2(msg); - unsigned int l2_len = msg->tail - msg_l2(msg); + unsigned int l2_len = msg->tail - (u_int8_t *)msgb_l2(msg); /* Various consistency checks */ if (oh->placement != ABIS_OM_PLACEMENT_ONLY) { @@ -193,7 +202,7 @@ int abis_nm_rx(struct msgb *msg) switch (oh->mdisc) { case ABIS_OM_MDISC_FOM: - rc = abis_nm_rcvmsg(msg); + rc = abis_nm_rcvmsg_fom(msg); break; case ABIS_OM_MDISC_MMI: case ABIS_OM_MDISC_TRAU: @@ -264,7 +273,7 @@ int abis_nm_sw_activate(struct abis_nm_h *h) } #endif -static fill_nm_channel(struct abis_nm_channel *ch, u_int8_t bts_port, +static void fill_nm_channel(struct abis_nm_channel *ch, u_int8_t bts_port, u_int8_t ts_nr, u_int8_t subslot_nr) { ch->attrib = NM_ATT_CHANNEL; @@ -281,13 +290,13 @@ int abis_nm_establish_tei(struct gsm_bts *bts, u_int8_t trx_nr, struct abis_nm_channel *ch; u_int8_t *tei_attr; u_int8_t len = 2 + sizeof(*ch); - struct mgsb *msg = msgb_alloc(OM_ALLOC_SIZE); + struct msgb *msg = nm_msgb_alloc(); oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE); fill_om_fom_hdr(oh, len, NM_MT_ESTABLISH_TEI, NM_OC_RADIO_CARRIER, bts->bts_nr, trx_nr, 0xff); - msgb_tv_put(msgb, NM_ATT_TEI, tei); + msgb_tv_put(msg, NM_ATT_TEI, tei); ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch)); fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot); @@ -299,10 +308,10 @@ int abis_nm_establish_tei(struct gsm_bts *bts, u_int8_t trx_nr, int abis_nm_conn_terr_sign(struct gsm_bts_trx *trx, u_int8_t e1_port, u_int8_t e1_timeslot, u_int8_t e1_subslot) { - struct gsm_bts *bts = ts->trx->bts; + struct gsm_bts *bts = trx->bts; struct abis_om_hdr *oh; struct abis_nm_channel *ch; - struct mgsb *msg = msgb_alloc(OM_ALLOC_SIZE); + struct msgb *msg = nm_msgb_alloc(); oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE); fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_SIGN, @@ -328,7 +337,7 @@ int abis_nm_conn_terr_traf(struct gsm_bts_trx_ts *ts, struct gsm_bts *bts = ts->trx->bts; struct abis_om_hdr *oh; struct abis_nm_channel *ch; - struct msgb *msg = msgb_alloc(OM_ALLOC_SIZE); + struct msgb *msg = nm_msgb_alloc(); oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE); fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_TRAF, @@ -352,12 +361,12 @@ int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, u_int8_t chan_comb) { struct gsm_bts *bts = ts->trx->bts; struct abis_om_hdr *oh; - u_int8_t arfcn = htons(ts->trx->arfcn); + u_int16_t arfcn = htons(ts->trx->arfcn); u_int8_t zero = 0x00; - struct msgb *msg = msgb_alloc(OM_ALLOC_SIZE); + struct msgb *msg = nm_msgb_alloc(); oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE); - fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_SET_CHAN_ATTR, + fill_om_fom_hdr(oh, sizeof(*oh), NM_MT_SET_CHAN_ATTR, NM_OC_BASEB_TRANSC, bts->bts_nr, ts->trx->nr, ts->nr); /* FIXME: don't send ARFCN list, hopping sequence, mAIO, ...*/ @@ -371,15 +380,16 @@ int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, u_int8_t chan_comb) return abis_nm_sendmsg(bts, msg); } -int abis_nm_raw_msg(struct gsm_bts *bts, int len, u_int8_t *msg) +int abis_nm_raw_msg(struct gsm_bts *bts, int len, u_int8_t *rawmsg) { - struct msgb *msg = msgb_alloc(OM_ALLOC_SIZE); + struct msgb *msg = nm_msgb_alloc(); + struct abis_om_hdr *oh; u_int8_t *data; oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh)); fill_om_hdr(oh, len); data = msgb_put(msg, len); - memcpy(msgb->data, msg, len); + memcpy(msg->data, rawmsg, len); return abis_nm_sendmsg(bts, msg); } @@ -388,10 +398,10 @@ int abis_nm_raw_msg(struct gsm_bts *bts, int len, u_int8_t *msg) static int __simple_cmd(struct gsm_bts *bts, u_int8_t msg_type) { struct abis_om_hdr *oh; - struct msg = msgb_alloc(OM_ALLOC_SIZE); + struct msgb *msg = nm_msgb_alloc(); oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE); - fill_om_fom_hdr(oh, sizeof(*ch), msg_type, NM_OC_SITE_MANAGER, + fill_om_fom_hdr(oh, sizeof(*oh), msg_type, NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff); return abis_nm_sendmsg(bts, msg); diff --git a/src/abis_rsl.c b/src/abis_rsl.c index f503684f7..79f83abf4 100644 --- a/src/abis_rsl.c +++ b/src/abis_rsl.c @@ -2,6 +2,7 @@ * 3GPP TS 08.58 version 8.6.0 Release 1999 / ETSI TS 100 596 V8.6.0 */ /* (C) 2008 by Harald Welte + * * All Rights Reserved * * This program is free software; you can redistribute it and/or modify @@ -21,31 +22,34 @@ */ #include +#include #include #include -#include "gsm_data.h" -#include "gsm_04_08.h" -#include "abis_rsl.h" -#include "debug.h" -#include "tlv.h" +#include +#include +#include +#include +#include +#include -#define RSL_ALLOC_SIZE 1024 +#define RSL_ALLOC_SIZE 1024 +#define RSL_ALLOC_HEADROOM 128 static u_int8_t mdisc_by_msgtype(u_int8_t msg_type) { /* mask off the transparent bit ? */ msg_type &= 0xfe; - if (msg_type & 0xf0 == 0x00) + if ((msg_type & 0xf0) == 0x00) return ABIS_RSL_MDISC_RLL; - if (msg_type & 0xf0 == 0x10) { + if ((msg_type & 0xf0) == 0x10) { if (msg_type >= 0x19 && msg_type <= 0x22) return ABIS_RSL_MDISC_TRX; else return ABIS_RSL_MDISC_COM_CHAN; } - if (msg_type & 0xc == 0x00) + if ((msg_type & 0xc) == 0x00) return ABIS_RSL_MDISC_DED_CHAN; return ABIS_RSL_MDISC_LOC; @@ -97,6 +101,84 @@ u_int8_t rsl_enc_chan_nr(u_int8_t type, u_int8_t subch, u_int8_t timeslot) return ret; } +/* determine logical channel based on TRX and channel number IE */ +struct gsm_lchan *lchan_lookup(struct gsm_bts_trx *trx, u_int8_t chan_nr) +{ + struct gsm_lchan *lchan; + u_int8_t ts_nr = chan_nr & 0x07; + u_int8_t cbits = chan_nr >> 3; + u_int8_t lch_idx; + struct gsm_bts_trx_ts *ts = &trx->ts[ts_nr]; + + if (cbits == 0x01) { + lch_idx = 0; /* TCH/F */ + if (ts->pchan != GSM_PCHAN_TCH_F) + fprintf(stderr, "chan_nr=0x%02x but pchan=%u\n", + chan_nr, ts->pchan); + } else if ((cbits & 0x1e) == 0x02) { + lch_idx = cbits & 0x1; /* TCH/H */ + if (ts->pchan != GSM_PCHAN_TCH_H) + fprintf(stderr, "chan_nr=0x%02x but pchan=%u\n", + chan_nr, ts->pchan); + } else if ((cbits & 0x1c) == 0x04) { + lch_idx = cbits & 0x3; /* SDCCH/4 */ + if (ts->pchan != GSM_PCHAN_CCCH_SDCCH4) + fprintf(stderr, "chan_nr=0x%02x but pchan=%u\n", + chan_nr, ts->pchan); + } else if ((cbits & 0x18) == 0x08) { + lch_idx = cbits & 0x7; /* SDCCH/8 */ + if (ts->pchan != GSM_PCHAN_SDCCH8_SACCH8C) + fprintf(stderr, "chan_nr=0x%02x but pchan=%u\n", + chan_nr, ts->pchan); + } else if (cbits == 0x10 || cbits == 0x11 || cbits == 0x12) { + lch_idx = 0; + if (ts->pchan != GSM_PCHAN_CCCH && + ts->pchan != GSM_PCHAN_CCCH_SDCCH4) + fprintf(stderr, "chan_nr=0x%02x but pchan=%u\n", + chan_nr, ts->pchan); + /* FIXME: we should not return first sdcch4 !!! */ + } else { + fprintf(stderr, "unknown chan_nr=0x%02x\n", chan_nr); + return NULL; + } + + lchan = &ts->lchan[lch_idx]; + + return lchan; +} + +u_int8_t lchan2chan_nr(struct gsm_lchan *lchan) +{ + struct gsm_bts_trx_ts *ts = lchan->ts; + u_int8_t cbits, chan_nr; + + switch (ts->pchan) { + case GSM_PCHAN_TCH_F: + cbits = 0x01; + break; + case GSM_PCHAN_TCH_H: + cbits = 0x02; + cbits += lchan->nr; + break; + case GSM_PCHAN_CCCH_SDCCH4: + cbits = 0x04; + cbits += lchan->nr; + break; + case GSM_PCHAN_SDCCH8_SACCH8C: + cbits = 0x08; + cbits += lchan->nr; + break; + default: + case GSM_PCHAN_CCCH: + cbits = 0x10; + break; + } + + chan_nr = (cbits << 3) | (ts->nr & 0x7); + + return chan_nr; +} + /* As per TS 03.03 Section 2.2, the IMSI has 'not more than 15 digits' */ u_int64_t str_to_imsi(const char *imsi_str) { @@ -130,12 +212,17 @@ unsigned int get_paging_group(u_int64_t imsi, unsigned int bs_cc_chans, return (imsi % 1000) % (bs_cc_chans * n_pag_blocks) % n_pag_blocks; } +static struct msgb *rsl_msgb_alloc(void) +{ + return msgb_alloc_headroom(RSL_ALLOC_SIZE, RSL_ALLOC_HEADROOM); +} + /* Send a BCCH_INFO message as per Chapter 8.5.1 */ int rsl_bcch_info(struct gsm_bts *bts, u_int8_t type, const u_int8_t *data, int len) { struct abis_rsl_dchan_hdr *dh; - struct msgb *msg = msgb_alloc(RSL_ALLOC_SIZE); + struct msgb *msg = rsl_msgb_alloc(); dh = (struct abis_rsl_dchan_hdr *) msgb_put(msg, sizeof*dh); init_dchan_hdr(dh, RSL_MT_BCCH_INFO); @@ -144,14 +231,16 @@ int rsl_bcch_info(struct gsm_bts *bts, u_int8_t type, msgb_tv_put(msg, RSL_IE_SYSINFO_TYPE, type); msgb_tlv_put(msg, RSL_IE_FULL_BCCH_INFO, len, data); - return abis_rsl_sendmsg(bts, msg); + msg->trx = bts->c0; + + return abis_rsl_sendmsg(msg); } int rsl_sacch_filling(struct gsm_bts *bts, u_int8_t type, const u_int8_t *data, int len) { struct abis_rsl_common_hdr *ch; - struct msgb *msg = msgb_alloc(RSL_ALLOC_SIZE); + struct msgb *msg = rsl_msgb_alloc(); ch = (struct abis_rsl_common_hdr *) msgb_put(msg, sizeof(*ch)); ch->msg_discr = ABIS_RSL_MDISC_TRX; @@ -160,7 +249,9 @@ int rsl_sacch_filling(struct gsm_bts *bts, u_int8_t type, msgb_tv_put(msg, RSL_IE_SYSINFO_TYPE, type); msgb_tlv_put(msg, RSL_IE_L3_INFO, len, data); - return abis_rsl_sendmsg(bts, msg); + msg->trx = bts->c0; + + return abis_rsl_sendmsg(msg); } /* Chapter 8.4.1 */ @@ -172,7 +263,7 @@ int rsl_chan_activate(struct gsm_bts *bts, u_int8_t chan_nr, u_int8_t ta) { struct abis_rsl_dchan_hdr *dh; - struct msgb *msg = msgb_alloc(RSL_ALLOC_SIZE); + struct msgb *msg = rsl_msgb_alloc(); u_int8_t encr_info = 0x01; dh = (struct abis_rsl_dchan_hdr *) msgb_put(msg, sizeof(*dh)); @@ -192,7 +283,7 @@ int rsl_chan_activate(struct gsm_bts *bts, u_int8_t chan_nr, msgb_tv_put(msg, RSL_IE_MS_POWER, ms_power); msgb_tv_put(msg, RSL_IE_TIMING_ADVANCE, ta); - return abis_rsl_sendmsg(bts, msg); + return abis_rsl_sendmsg(msg); } #define TSC 7 @@ -243,23 +334,26 @@ int rsl_chan_activate_sdcch(struct gsm_bts_trx_ts *ts) return rsl_chan_activate(ts->trx->bts, chan_nr, 0x00, &cm, &ci, 0x01, 0x0f, 0x00); } -int rsl_chan_release(struct gsm_bts_trx_ts *ts, u_int8_t chan_nr) +int rsl_chan_release(struct gsm_lchan *lchan) { struct abis_rsl_dchan_hdr *dh; - struct msgb *msg = msgb_alloc(RSL_ALLOC_SIZE); + struct msgb *msg = rsl_msgb_alloc(); dh = (struct abis_rsl_dchan_hdr *) msgb_put(msg, sizeof(*dh)); init_dchan_hdr(dh, RSL_MT_RF_CHAN_REL); - dh->chan_nr = chan_nr; + dh->chan_nr = lchan2chan_nr(lchan); - return abis_rsl_sendmsg(ts->trx->bts, msg); + msg->lchan = lchan; + msg->trx = lchan->ts->trx; + + return abis_rsl_sendmsg(msg); } int rsl_paging_cmd(struct gsm_bts *bts, u_int8_t paging_group, u_int8_t len, u_int8_t *ms_ident, u_int8_t chan_needed) { struct abis_rsl_dchan_hdr *dh; - struct msgb *msg = msgb_alloc(RSL_ALLOC_SIZE); + struct msgb *msg = rsl_msgb_alloc(); dh = (struct abis_rsl_dchan_hdr *) msgb_put(msg, sizeof(*dh)); init_dchan_hdr(dh, RSL_MT_PAGING_CMD); @@ -269,7 +363,9 @@ int rsl_paging_cmd(struct gsm_bts *bts, u_int8_t paging_group, u_int8_t len, msgb_tlv_put(msg, RSL_IE_MS_IDENTITY, len, ms_ident); msgb_tv_put(msg, RSL_IE_CHAN_NEEDED, chan_needed); - return abis_rsl_sendmsg(bts, msg); + msg->trx = bts->c0; + + return abis_rsl_sendmsg(msg); } int imsi_str2bcd(u_int8_t *bcd_out, const char *str_in) @@ -299,7 +395,7 @@ int rsl_paging_cmd_imsi(struct gsm_bts *bts, u_int8_t chan_needed, const char *i int rsl_imm_assign_cmd(struct gsm_bts *bts, u_int8_t len, u_int8_t *val) { - struct msgb *msg = msgb_alloc(RSL_ALLOC_SIZE); + struct msgb *msg = rsl_msgb_alloc(); struct abis_rsl_dchan_hdr *dh; dh = (struct abis_rsl_dchan_hdr *) msgb_put(msg, sizeof(*dh)); @@ -310,34 +406,57 @@ int rsl_imm_assign_cmd(struct gsm_bts *bts, u_int8_t len, u_int8_t *val) msgb_tlv_put(msg, RSL_IE_IMM_ASS_INFO, len, val); - return abis_rsl_sendmsg(bts, msg); + msg->trx = bts->c0; + + return abis_rsl_sendmsg(msg); } +/* Send "DATA REQUEST" message with given L3 Info payload */ /* Chapter 8.3.1 */ -int rsl_data_request(struct gsm_bts *bts, struct msgb *msg) +int rsl_data_request(struct msgb *msg, u_int8_t link_id) { - /* FIXME: prepend RSL header to layer 3 message */ - u_int8_t len = msg->len; + u_int8_t l3_len = msg->tail - (u_int8_t *)msgb_l3(msg); struct abis_rsl_rll_hdr *rh; - msgb_tv_push(msg, RSL_IE_L3_INFO, len); + if (msg->lchan == NULL) { + fprintf(stderr, "cannot send DATA REQUEST to unknown lchan\n"); + return -EINVAL; + } + /* First push the L3 IE tag and length */ + msgb_tv_push(msg, RSL_IE_L3_INFO, l3_len); + + /* Then push the RSL header */ rh = (struct abis_rsl_rll_hdr *) msgb_push(msg, sizeof(*rh)); init_llm_hdr(rh, RSL_MT_DATA_REQ); - rh->chan_nr = RSL_CHAN_SDCCH4_ACCH; /* FIXME: don't harcode */ + rh->chan_nr = lchan2chan_nr(msg->lchan); + rh->link_id = link_id; - return abis_rsl_sendmsg(bts, msg); + msg->trx = msg->lchan->ts->trx; + + return abis_rsl_sendmsg(msg); } static int abis_rsl_rx_dchan(struct msgb *msg) { - struct abis_rsl_common_hdr *rslh = msgb_l2(msg) ; + struct abis_rsl_dchan_hdr *rslh = msgb_l2(msg); + int rc = 0; - switch (rslh->msg_type) { + msg->lchan = lchan_lookup(msg->trx, rslh->chan_nr); + + switch (rslh->c.msg_type) { case RSL_MT_CHAN_ACTIV_ACK: + DEBUGP(DRSL, "rsl_rx_dchan: Channel Activate ACK\n"); + break; case RSL_MT_CHAN_ACTIV_NACK: + DEBUGP(DRSL, "rsl_rx_dchan: Channel Activate NACK\n"); + break; case RSL_MT_CONN_FAIL: + DEBUGP(DRSL, "rsl_rx_dchan: Connection Fail\n"); + break; case RSL_MT_MEAS_RES: + DEBUGP(DRSL, "rsl_rx_dchan: Measurement Result\n"); + break; case RSL_MT_MODE_MODIFY_ACK: case RSL_MT_MODE_MODIFY_NACK: case RSL_MT_PHY_CONTEXT_CONF: @@ -350,18 +469,20 @@ static int abis_rsl_rx_dchan(struct msgb *msg) case RSL_MT_MR_CODEC_MOD_NACK: case RSL_MT_MR_CODEC_MOD_PER: fprintf(stderr, "Unimplemented Abis RSL DChan msg 0x%02x\n", - rslh->msg_type); + rslh->c.msg_type); break; default: fprintf(stderr, "unknown Abis RSL DChan msg 0x%02x\n", - rslh->msg_type); + rslh->c.msg_type); return -EINVAL; } + return rc; } static int abis_rsl_rx_trx(struct msgb *msg) { struct abis_rsl_common_hdr *rslh = msgb_l2(msg) ; + int rc = 0; switch (rslh->msg_type) { case RSL_MT_RF_RES_IND: @@ -377,25 +498,58 @@ static int abis_rsl_rx_trx(struct msgb *msg) rslh->msg_type); return -EINVAL; } - + return rc; } +/* MS has requested a channel on the RACH */ static int rsl_rx_chan_rqd(struct msgb *msg) { struct gsm_bts *bts = msg->bts_link->bts; + struct abis_rsl_dchan_hdr *rqd_hdr = msgb_l2(msg); + struct gsm48_req_ref *rqd_ref; struct gsm48_imm_ass ia; + enum gsm_chan_t lctype; + struct gsm_lchan *lchan; + u_int8_t rqd_ta; + u_int16_t arfcn; u_int8_t ts_number, subch; - /* MS has requested a channel on the RACH */ - /* parse channel number, request reference, access delay */ - /* FIXME: check permission/availability */ - ts_number = 0; - arfcn = HARDCODED_ARFCN; - subch = 0; + /* parse request reference to be used in immediate assign */ + if (rqd_hdr->data[0] != RSL_IE_REQ_REFERENCE) + return -EINVAL; + + rqd_ref = (struct gsm48_req_ref *) &rqd_hdr->data[1]; + + /* parse access delay and use as TA */ + if (rqd_hdr->data[sizeof(struct gsm48_req_ref)+1] != RSL_IE_ACCESS_DELAY) + return -EINVAL; + rqd_ta = rqd_hdr->data[sizeof(struct gsm48_req_ref)+2]; + + /* determine channel type (SDCCH/TCH_F/TCH_H) based on + * request reference RA */ + lctype = get_ctype_by_chreq(bts, rqd_ref->ra); + + /* check availability / allocate channel */ + lchan = lchan_alloc(bts, lctype); + if (!lchan) { + fprintf(stderr, "CHAN RQD: no resources\n"); + /* FIXME: send some kind of reject ?!? */ + return -ENOMEM; + } + + ts_number = lchan->ts->nr; + arfcn = lchan->ts->trx->arfcn; + subch = lchan->nr; + DEBUGP(DRSL, "Activating ARFCN(%u) TS(%u) SS(%u) lctype %u\n", + arfcn, ts_number, subch, lchan->type); + /* send CHANNEL ACTIVATION on RSL to BTS */ - rsl_chan_activate_sdcch(&bts->trx[0].ts[ts_number]); + if (lchan->ts->pchan == GSM_PCHAN_SDCCH8_SACCH8C) + rsl_chan_activate_sdcch(lchan->ts); + else + rsl_chan_activate_tch_f(lchan->ts); /* create IMMEDIATE ASSIGN 04.08 messge */ memset(&ia, 0, sizeof(ia)); @@ -403,18 +557,14 @@ 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 = rsl_enc_chan_nr(lchan->ts->pchan, subch, ts_number); ia.chan_desc.h0.h = 0; ia.chan_desc.h0.arfcn_high = arfcn >> 8; ia.chan_desc.h0.arfcn_low = arfcn & 0xff; ia.chan_desc.h0.tsc = 7; - /* FIXME: use real request reference extracted from CHAN_RQD */ - ia.req_ref.ra = 0x80 | 0x1e; - ia.req_ref.t2 = 0x0c; - ia.req_ref.t1_ = 0x12; - ia.req_ref.t3_low = 0x19 & 3; - ia.req_ref.t3_high = 0x19 >> 3; - ia.timing_advance = 0; + /* use request reference extracted from CHAN_RQD */ + memcpy(&ia.req_ref, rqd_ref, sizeof(ia.req_ref)); + ia.timing_advance = rqd_ta; ia.mob_alloc_len = 0; /* send IMMEDIATE ASSIGN CMD on RSL to BTS (to send on CCCH to MS) */ @@ -423,10 +573,12 @@ static int rsl_rx_chan_rqd(struct msgb *msg) static int abis_rsl_rx_cchan(struct msgb *msg) { - struct abis_rsl_common_hdr *rslh = msgb_l2(msg) ; - int rc; + struct abis_rsl_dchan_hdr *rslh = msgb_l2(msg) ; + int rc = 0; - switch (rslh->msg_type) { + msg->lchan = lchan_lookup(msg->trx, rslh->chan_nr); + + switch (rslh->c.msg_type) { case RSL_MT_CHAN_RQD: /* MS has requested a channel on the RACH */ rc = rsl_rx_chan_rqd(msg); @@ -438,13 +590,15 @@ static int abis_rsl_rx_cchan(struct msgb *msg) case RSL_MT_CCCH_LOAD_IND: /* current load on the CCCH */ fprintf(stderr, "Unimplemented Abis RSL TRX message type 0x%02x\n", - rslh->msg_type); + rslh->c.msg_type); break; default: fprintf(stderr, "Unknown Abis RSL TRX message type 0x%02x\n", - rslh->msg_type); + rslh->c.msg_type); return -EINVAL; } + + return rc; } /* ESTABLISH INDICATION, LOCATION AREA UPDATE REQUEST @@ -457,16 +611,20 @@ static int abis_rsl_rx_rll(struct msgb *msg) { struct abis_rsl_rll_hdr *rllh = msgb_l2(msg); int rc; + + msg->lchan = lchan_lookup(msg->trx, rllh->chan_nr); switch (rllh->c.msg_type) { case RSL_MT_DATA_IND: DEBUGP(DRLL, "DATA INDICATION\n"); - /* FIXME: parse L3 info element */ + /* FIXME: Verify L3 info element */ + msg->l3_off = &rllh->data[2] - msg->data; rc = gsm0408_rcvmsg(msg); break; case RSL_MT_EST_IND: DEBUGP(DRLL, "ESTABLISH INDICATION\n"); - /* FIXME: parse L3 info element */ + /* FIXME: Verify L3 info element */ + msg->l3_off = &rllh->data[2] - msg->data; rc = gsm0408_rcvmsg(msg); break; case RSL_MT_ERROR_IND: @@ -479,10 +637,11 @@ static int abis_rsl_rx_rll(struct msgb *msg) fprintf(stderr, "unknown Abis RLL message type 0x%02x\n", rllh->c.msg_type); } + return rc; } /* Entry-point where L2 RSL from BTS enters */ -int abis_rsl_rx(struct msgb *msg) +int abis_rsl_rcvmsg(struct msgb *msg) { struct abis_rsl_common_hdr *rslh = msgb_l2(msg) ; unsigned int l2_len = (void *)msg->tail - msgb_l2(msg); @@ -496,13 +655,16 @@ int abis_rsl_rx(struct msgb *msg) rc = abis_rsl_rx_dchan(msg); break; case ABIS_RSL_MDISC_COM_CHAN: - case ABIS_RSL_MDISC_TRX: rc = abis_rsl_rx_cchan(msg); break; + case ABIS_RSL_MDISC_TRX: + rc = abis_rsl_rx_trx(msg); + break; case ABIS_RSL_MDISC_LOC: default: fprintf(stderr, "unknown RSL message discriminator 0x%02x\n", rslh->msg_discr); return -EINVAL; } + return rc; } diff --git a/src/bsc_hack.c b/src/bsc_hack.c index 0f237cc8f..9bec0b4b7 100644 --- a/src/bsc_hack.c +++ b/src/bsc_hack.c @@ -21,9 +21,9 @@ -#include "gsm_data.h" -#include "abis_rsl.h" -#include "abis_nm.h" +#include +#include +#include /* global pointer to the gsm network data structure */ static struct gsm_network *gsmnet; @@ -536,8 +536,8 @@ static void bootstrap_network() bts->location_area_code = 1; bts->trx[0].arfcn = HARDCODED_ARFCN; + mi_setup(); + /* initialize the BTS */ bootstrap_bts(&gsmnet->bts[0]); - - } diff --git a/src/chan_alloc.c b/src/chan_alloc.c new file mode 100644 index 000000000..ca8690899 --- /dev/null +++ b/src/chan_alloc.c @@ -0,0 +1,150 @@ +/* GSM Channel allocation routines + * + * (C) 2008 by Harald Welte + * + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#include +#include +#include +#include + +#include +#include + +struct gsm_bts_trx_ts *ts_c0_alloc(struct gsm_bts *bts, + enum gsm_phys_chan_config pchan) +{ + struct gsm_bts_trx *trx = &bts->trx[0]; + struct gsm_bts_trx_ts *ts = &trx->ts[0]; + + if (pchan != GSM_PCHAN_CCCH && + pchan != GSM_PCHAN_CCCH_SDCCH4) + return NULL; + + if (ts->pchan != GSM_PCHAN_NONE) + return NULL; + + ts->pchan = pchan; + + return ts; +} + + +/* Allocate a logical channel (TS) */ +struct gsm_bts_trx_ts *ts_alloc(struct gsm_bts *bts, + enum gsm_phys_chan_config pchan) +{ + int i, j; + for (i = 0; i < bts->num_trx; i++) { + struct gsm_bts_trx *trx = &bts->trx[i]; + for (j = 0; j < 8; j++) { + struct gsm_bts_trx_ts *ts = &trx->ts[j]; + if (ts->pchan == GSM_PCHAN_NONE) { + ts->pchan = pchan; + return ts; + } + } + } + return NULL; +} + +/* Free a physical channel (TS) */ +void ts_free(struct gsm_bts_trx_ts *ts) +{ + ts->pchan = GSM_PCHAN_NONE; +} + +static const u_int8_t subslots_per_pchan[] = { + [GSM_PCHAN_NONE] = 0, + [GSM_PCHAN_CCCH] = 0, + [GSM_PCHAN_CCCH_SDCCH4] = 4, + [GSM_PCHAN_TCH_F] = 1, + [GSM_PCHAN_TCH_H] = 2, + [GSM_PCHAN_SDCCH8_SACCH8C] = 8. +}; + +static struct gsm_lchan * +_lc_find(struct gsm_bts *bts, enum gsm_phys_chan_config pchan) +{ + struct gsm_bts_trx *trx; + struct gsm_bts_trx_ts *ts; + int i, j, ss; + for (i = 0; i < bts->num_trx; i++) { + trx = &bts->trx[i]; + for (j = 0; j < 8; j++) { + ts = &trx->ts[j]; + if (ts->pchan != pchan) + continue; + /* check if all sub-slots are allocated yet */ + for (ss = 0; ss < subslots_per_pchan[pchan]; ss++) { + struct gsm_lchan *lc = &ts->lchan[ss]; + if (lc->type == GSM_LCHAN_NONE) + return lc; + } + } + } + /* we cannot allocate more of these */ + if (pchan == GSM_PCHAN_CCCH_SDCCH4) + return NULL; + + /* if we've reached here, we need to allocate a new physical + * channel for the logical channel type requested */ + ts = ts_alloc(bts, pchan); + if (!ts) { + /* no more radio resources */ + return NULL; + } + return &ts->lchan[0]; +} + +/* Allocate a logical channel */ +struct gsm_lchan *lchan_alloc(struct gsm_bts *bts, enum gsm_chan_t type) +{ + struct gsm_lchan *lchan = NULL; + + switch (type) { + case GSM_LCHAN_SDCCH: + lchan = _lc_find(bts, GSM_PCHAN_CCCH_SDCCH4); + if (lchan == NULL) + lchan = _lc_find(bts, GSM_PCHAN_SDCCH8_SACCH8C); + break; + case GSM_LCHAN_TCH_F: + lchan = _lc_find(bts, GSM_PCHAN_TCH_F); + break; + case GSM_LCHAN_TCH_H: + lchan =_lc_find(bts, GSM_PCHAN_TCH_H); + break; + default: + fprintf(stderr, "Unknown gsm_chan_t %u\n", type); + } + + if (lchan) + lchan->type = type; + + return lchan; +} + +/* Free a logical channel */ +void lchan_free(struct gsm_lchan *lchan) +{ + lchan->type = GSM_LCHAN_NONE; + /* FIXME: ts_free() the timeslot, if we're the last logical + * channel using it */ +} diff --git a/src/gsm_04_08.c b/src/gsm_04_08.c index 4165b78e6..397f13118 100644 --- a/src/gsm_04_08.c +++ b/src/gsm_04_08.c @@ -2,6 +2,7 @@ * 3GPP TS 04.08 version 7.21.0 Release 1998 / ETSI TS 100 940 V7.21.0 */ /* (C) 2008 by Harald Welte + * * All Rights Reserved * * This program is free software; you can redistribute it and/or modify @@ -26,13 +27,15 @@ #include #include -#include "msgb.h" -#include "debug.h" -#include "gsm_data.h" -#include "gsm_subscriber.h" -#include "gsm_04_08.h" +#include +#include +#include +#include +#include +#include -#define GSM0408_ALLOC_SIZE 1024 +#define GSM48_ALLOC_SIZE 1024 +#define GSM48_ALLOC_HEADROOM 128 struct gsm_lai { u_int16_t mcc; @@ -79,8 +82,8 @@ static void generate_lai(struct gsm48_loc_area_id *lai48, u_int16_t mcc, lai48->digits[1] = bcd[2]; to_bcd(bcd, mnc); - lai48->digits[2] |= bcd[2] << 4; - lai48->digits[3] = bcd[0] | (bcd[1] << 4); + lai48->digits[1] |= bcd[2] << 4; + lai48->digits[2] = bcd[0] | (bcd[1] << 4); lai48->lac = lac; } @@ -98,11 +101,17 @@ static void generate_mid_from_tmsi(u_int8_t *buf, u_int8_t *tmsi_bcd) buf[5] = tmsi_bcd[3]; } +static struct msgb *gsm48_msgb_alloc(void) +{ + return msgb_alloc_headroom(GSM48_ALLOC_SIZE, GSM48_ALLOC_HEADROOM); +} + static int gsm0408_sendmsg(struct msgb *msg) { - /* FIXME: set data pointer to beginning of L3 data object */ + if (msg->lchan) + msg->trx = msg->lchan->ts->trx; - return rsl_data_request(msg); + return rsl_data_request(msg, 0); } static int gsm0408_rcv_cc(struct msgb *msg) @@ -138,15 +147,17 @@ static int gsm0408_rcv_cc(struct msgb *msg) gh->msg_type); break; } + + return 0; } /* Chapter 9.2.14 : Send LOCATION UPDATE REJECT */ -int gsm0408_loc_upd_rej(struct gsm_bts_link *bts_link, u_int8_t cause) +int gsm0408_loc_upd_rej(struct gsm_lchan *lchan, u_int8_t cause) { - struct msgb *msg = msgb_alloc(GSM0408_ALLOC_SIZE); + struct msgb *msg = gsm48_msgb_alloc(); struct gsm48_hdr *gh; - msg->bts_link = bts_link; + msg->lchan = lchan; gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1); gh->proto_discr = GSM48_PDISC_MM; @@ -159,15 +170,15 @@ int gsm0408_loc_upd_rej(struct gsm_bts_link *bts_link, u_int8_t cause) } /* Chapter 9.2.13 : Send LOCATION UPDATE ACCEPT */ -int gsm0408_loc_upd_acc(struct gsm_bts_link *bts_link, u_int8_t *tmsi) +int gsm0408_loc_upd_acc(struct gsm_lchan *lchan, u_int8_t *tmsi) { - struct gsm_bts *bts = bts_link->bts; - struct msgb *msg = msgb_alloc(GSM0408_ALLOC_SIZE); + struct gsm_bts *bts = lchan->ts->trx->bts; + struct msgb *msg = gsm48_msgb_alloc(); struct gsm48_hdr *gh; struct gsm48_loc_area_id *lai; u_int8_t *mid; - msg->bts_link = bts_link; + msg->lchan = lchan; gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh)); gh->proto_discr = GSM48_PDISC_MM; @@ -185,15 +196,18 @@ int gsm0408_loc_upd_acc(struct gsm_bts_link *bts_link, u_int8_t *tmsi) return gsm0408_sendmsg(msg); } - /* Chapter 9.2.15 */ static int mm_loc_upd_req(struct msgb *msg) { + struct gsm48_hdr *gh = msgb_l3(msg); struct gsm_bts *bts = msg->bts_link->bts; struct gsm48_loc_upd_req *lu; struct gsm_subscriber *subscr; + u_int8_t mi_type; - u_int8_t mi_type = lu->mi[0] & GSM_MI_TYPE_MASK; + lu = (struct gsm48_loc_upd_req *) gh->data; + + mi_type = lu->mi[0] & GSM_MI_TYPE_MASK; switch (mi_type) { case GSM_MI_TYPE_IMSI: @@ -220,12 +234,14 @@ static int mm_loc_upd_req(struct msgb *msg) if (!subscr) { /* 0x16 is congestion */ - gsm0408_loc_upd_rej(msg->bts_link, 0x16); + gsm0408_loc_upd_rej(msg->lchan, 0x16); return -EINVAL; } + msg->lchan->subscr = subscr; subscr_update(subscr, bts); - return gsm0408_loc_upd_acc(msg->bts_link, subscr->tmsi); + + return gsm0408_loc_upd_acc(msg->lchan, subscr->tmsi); } static int gsm0408_rcv_mm(struct msgb *msg) @@ -279,7 +295,7 @@ int gsm0408_rcvmsg(struct msgb *msg) { struct gsm48_hdr *gh = msgb_l3(msg); u_int8_t pdisc = gh->proto_discr & 0x0f; - int rc; + int rc = 0; switch (pdisc) { case GSM48_PDISC_CC: @@ -304,3 +320,82 @@ int gsm0408_rcvmsg(struct msgb *msg) return rc; } + +enum chreq_type { + CHREQ_T_EMERG_CALL, + CHREQ_T_CALL_REEST_TCH_F, + CHREQ_T_CALL_REEST_TCH_H, + CHREQ_T_CALL_REEST_TCH_H_DBL, + CHREQ_T_SDCCH, + CHREQ_T_TCH_F, + CHREQ_T_VOICE_CALL_TCH_H, + CHREQ_T_DATA_CALL_TCH_H, + CHREQ_T_LOCATION_UPD, + CHREQ_T_PAG_R_ANY, + CHREQ_T_PAG_R_TCH_F, + CHREQ_T_PAG_R_TCH_FH, +}; + +/* Section 9.1.8 / Table 9.9 */ +struct chreq { + u_int8_t val; + u_int8_t mask; + enum chreq_type type; +}; + +/* If SYSTEM INFORMATION TYPE 4 NECI bit == 1 */ +static const struct chreq chreq_type_neci1[] = { + { 0xa0, 0xe0, CHREQ_T_EMERG_CALL }, + { 0xc0, 0xe0, CHREQ_T_CALL_REEST_TCH_F }, + { 0x68, 0xfc, CHREQ_T_CALL_REEST_TCH_H }, + { 0x6c, 0xfc, CHREQ_T_CALL_REEST_TCH_H_DBL }, + { 0xe0, 0xe0, CHREQ_T_SDCCH }, + { 0x40, 0xf0, CHREQ_T_VOICE_CALL_TCH_H }, + { 0x50, 0xf0, CHREQ_T_DATA_CALL_TCH_H }, + { 0x00, 0xf0, CHREQ_T_LOCATION_UPD }, + { 0x10, 0xf0, CHREQ_T_SDCCH }, + { 0x80, 0xe0, CHREQ_T_PAG_R_ANY }, + { 0x20, 0xf0, CHREQ_T_PAG_R_TCH_F }, + { 0x30, 0xf0, CHREQ_T_PAG_R_TCH_FH }, +}; + +/* If SYSTEM INFORMATION TYPE 4 NECI bit == 0 */ +static const struct chreq chreq_type_neci0[] = { + { 0xa0, 0xe0, CHREQ_T_EMERG_CALL }, + { 0xc0, 0xe0, CHREQ_T_CALL_REEST_TCH_H }, + { 0xe0, 0xe0, CHREQ_T_TCH_F }, + { 0x50, 0xf0, CHREQ_T_DATA_CALL_TCH_H }, + { 0x00, 0xe0, CHREQ_T_LOCATION_UPD }, + { 0x80, 0xe0, CHREQ_T_PAG_R_ANY }, + { 0x20, 0xf0, CHREQ_T_PAG_R_TCH_F }, + { 0x30, 0xf0, CHREQ_T_PAG_R_TCH_FH }, +}; + +static const enum gsm_chan_t ctype_by_chreq[] = { + [CHREQ_T_EMERG_CALL] = GSM_LCHAN_TCH_F, + [CHREQ_T_CALL_REEST_TCH_F] = GSM_LCHAN_TCH_F, + [CHREQ_T_CALL_REEST_TCH_H] = GSM_LCHAN_TCH_H, + [CHREQ_T_CALL_REEST_TCH_H_DBL] = GSM_LCHAN_TCH_H, + [CHREQ_T_SDCCH] = GSM_LCHAN_SDCCH, + [CHREQ_T_TCH_F] = GSM_LCHAN_TCH_F, + [CHREQ_T_VOICE_CALL_TCH_H] = GSM_LCHAN_TCH_H, + [CHREQ_T_DATA_CALL_TCH_H] = GSM_LCHAN_TCH_H, + [CHREQ_T_LOCATION_UPD] = GSM_LCHAN_SDCCH, + [CHREQ_T_PAG_R_ANY] = GSM_LCHAN_SDCCH, + [CHREQ_T_PAG_R_TCH_F] = GSM_LCHAN_TCH_F, + [CHREQ_T_PAG_R_TCH_FH] = GSM_LCHAN_TCH_F, +}; + +enum gsm_chan_t get_ctype_by_chreq(struct gsm_bts *bts, u_int8_t ra) +{ + int i; + /* FIXME: determine if we set NECI = 0 in the BTS SI4 */ + + for (i = 0; i < ARRAY_SIZE(chreq_type_neci0); i++) { + const struct chreq *chr = &chreq_type_neci0[i]; + if ((ra & chr->mask) == chr->val) + return ctype_by_chreq[chr->type]; + } + fprintf(stderr, "Unknown CHANNEL REQUEST RQD 0x%02x\n", ra); + return GSM_LCHAN_SDCCH; +} diff --git a/src/gsm_data.c b/src/gsm_data.c index a4d0e8b9e..e5ba906b0 100644 --- a/src/gsm_data.c +++ b/src/gsm_data.c @@ -1,4 +1,5 @@ /* (C) 2008 by Harald Welte + * * All Rights Reserved * * This program is free software; you can redistribute it and/or modify @@ -21,7 +22,7 @@ #include #include -#include "gsm_data.h" +#include struct gsm_network *gsm_network_init(unsigned int num_bts, u_int8_t country_code, u_int8_t network_code) @@ -57,12 +58,24 @@ struct gsm_network *gsm_network_init(unsigned int num_bts, u_int8_t country_code for (k = 0; k < 8; k++) { struct gsm_bts_trx_ts *ts = &trx->ts[k]; + int l; ts->trx = trx; ts->nr = k; + ts->pchan = GSM_PCHAN_NONE; + + for (l = 0; l < TS_MAX_LCHAN; l++) { + struct gsm_lchan *lchan; + lchan = &ts->lchan[l]; + + lchan->ts = ts; + lchan->nr = l; + lchan->type = GSM_LCHAN_NONE; + } } } bts->num_trx = 1; /* FIXME */ } + return net; } diff --git a/src/gsm_subscriber.c b/src/gsm_subscriber.c index 76d2e355a..6a67c49e3 100644 --- a/src/gsm_subscriber.c +++ b/src/gsm_subscriber.c @@ -1,6 +1,7 @@ /* Dummy implementation of a subscriber database, roghly HLR/VLR functionality */ /* (C) 2008 by Harald Welte + * * All Rights Reserved * * This program is free software; you can redistribute it and/or modify @@ -20,7 +21,7 @@ */ -#include "gsm_subscriber.h" +#include static struct gsm_subscriber subscr = { .name = "Test User 1", diff --git a/src/misdn.c b/src/misdn.c index 6b232233c..49b858ff1 100644 --- a/src/misdn.c +++ b/src/misdn.c @@ -1,6 +1,6 @@ -/* OpenBSC Abis interface to mISDNuser - * - * (C) 2008 by Harald Welte +/* OpenBSC Abis interface to mISDNuser */ + +/* (C) 2008 by Harald Welte * * All Rights Reserved * @@ -30,27 +30,39 @@ #include #include -#define AF_COMPATIBILITY_FUNC -#include +//#define AF_COMPATIBILITY_FUNC +//#include +#define AF_ISDN 34 +#define PF_ISDN AF_ISDN + +#include +#include +#include +#include +#include +#include #define NUM_E1_TS 32 /* data structure for one E1 interface with A-bis */ struct mi_e1_handle { struct gsm_bts *bts; - /* The mISDN card number of the card we use */ int cardnr; - /* The RSL adress */ struct sockaddr_mISDN l2addr; - /* The OML adress */ struct sockaddr_mISDN omladdr; + /* list (queue) of to-be-sent msgb's */ + struct llist_head rsl_tx_list; + struct llist_head oml_tx_list; - struct gsm_fd fd[NUM_E1_TS]; + struct bsc_fd fd[NUM_E1_TS]; }; +/* FIXME: this needs to go */ +static struct mi_e1_handle *global_e1h; + #define SAPI_L2ML 0 #define SAPI_OML 62 #define SAPI_RSL 63 @@ -74,13 +86,18 @@ static int handle_ts1_read(struct bsc_fd *bfd) { struct mi_e1_handle *e1h = bfd->data; struct msgb *msg = msgb_alloc(TS1_ALLOC_SIZE); - struct sockaddr_mISDN l2dadr; + struct sockaddr_mISDN l2addr; + struct mISDNhead *hh; socklen_t alen; + int ret; if (!msg) return -ENOMEM; - msg->bts = e1h->bts; + hh = (struct mISDNhead *) msg->data; + + /* FIXME: Map TEI/SAPI to TRX */ + msg->trx = e1h->bts->c0; alen = sizeof(l2addr); ret = recvfrom(bfd->fd, msg->data, 300, 0, @@ -104,7 +121,7 @@ static int handle_ts1_read(struct bsc_fd *bfd) switch (hh->prim) { case DL_INFORMATION_IND: DEBUGP(DMI, "got DL_INFORMATION_IND\n"); - struct sockaddr_mISDN *sa; + struct sockaddr_mISDN *sa = NULL; char *lstr = "UNKN"; switch (l2addr.tei) { @@ -117,11 +134,13 @@ static int handle_ts1_read(struct bsc_fd *bfd) lstr = "RSL"; break; default: - continue; + break; + } + if (sa) { + DEBUGP(DMI, "%s use channel(%d) sapi(%d) tei(%d) for now\n", + lstr, l2addr.channel, l2addr.sapi, l2addr.tei); + memcpy(sa, &l2addr, sizeof(l2addr)); } - DEBUGP(DMI, "%s use channel(%d) sapi(%d) tei(%d) for now\n", - lstr, l2addr.channel, l2addr.sapi, l2addr.tei); - memcpy(sa, &l2addr, sizeof(l2addr)); break; case DL_ESTABLISH_IND: DEBUGP(DMI, "got DL_ESTABLISH_IND\n"); @@ -164,14 +183,39 @@ static int handle_ts1_read(struct bsc_fd *bfd) static int handle_ts1_write(struct bsc_fd *bfd) { struct mi_e1_handle *e1h = bfd->data; + struct msgb *msg; + struct mISDNhead *hh; + int ret, no_rsl = 0; - /* FIXME: dequeue a pending msgb for RSL / OML */ - - /* prepend the mISDNhead */ - hh = (struct mISDNhed *) msg_ - hh->prim = DL_DATA_REQ; + msg = msgb_dequeue(&e1h->rsl_tx_list); + if (!msg) + no_rsl = 1; + else { + /* prepend the mISDNhead */ + hh = (struct mISDNhead *) msgb_push(msg, sizeof(*hh)); + hh->prim = DL_DATA_REQ; - /* FIXME: send it off */ + ret = sendto(bfd->fd, msg->data, msg->len, 0, + (struct sockaddr *)&e1h->l2addr, + sizeof(e1h->l2addr)); + usleep(100000); + } + msg = msgb_dequeue(&e1h->rsl_tx_list); + if (!msg) { + if (no_rsl) + bfd->when &= ~BSC_FD_WRITE; + } else { + /* prepend the mISDNhead */ + hh = (struct mISDNhead *) msgb_push(msg, sizeof(*hh)); + hh->prim = DL_DATA_REQ; + + ret = sendto(bfd->fd, msg->data, msg->len, 0, + (struct sockaddr *)&e1h->omladdr, + sizeof(e1h->omladdr)); + usleep(100000); + } + + return ret; } static int handle_tsX_read(struct bsc_fd *bfd) @@ -179,13 +223,13 @@ static int handle_tsX_read(struct bsc_fd *bfd) /* FIXME: read from a B channel TS */ } -static int handle_TsX_write(struct bsc_fd *bfd) +static int handle_tsX_write(struct bsc_fd *bfd) { /* FIXME: write to a B channel TS */ } /* callback from select.c in case one of the fd's can be read/written */ -static int misdn_fd_cb(struct gsm_fd *bfd, unsigned int what) +static int misdn_fd_cb(struct bsc_fd *bfd, unsigned int what) { unsigned int e1_ts = bfd->priv_nr; int rc = 0; @@ -208,13 +252,33 @@ static int misdn_fd_cb(struct gsm_fd *bfd, unsigned int what) return rc; } -static int mi_setup(devinfo_t *di) +int abis_rsl_sendmsg(struct msgb *msg) { - int ts, sk, ret; - struct mISDN_devinfo devinfo; + struct mi_e1_handle *e1h = global_e1h; + + msgb_enqueue(&e1h->rsl_tx_list, msg); + e1h->fd[0].when |= BSC_FD_WRITE; + + return 0; +} + +int abis_nm_sendmsg(struct msgb *msg) +{ + struct mi_e1_handle *e1h = global_e1h; + + msgb_enqueue(&e1h->oml_tx_list, msg); + e1h->fd[0].when |= BSC_FD_WRITE; + + return 0; +} + +static int mi_e1_setup(struct mi_e1_handle *e1h) +{ + int ts, sk, ret, cnt; + struct mISDN_devinfo devinfo; sk = socket(PF_ISDN, SOCK_RAW, ISDN_P_BASE); - if (sk < 0) + if (sk < 0) { fprintf(stderr, "could not open socket %s\n", strerror(errno)); return sk; } @@ -245,16 +309,22 @@ static int mi_setup(devinfo_t *di) /* TS0 is CRC4, don't need any fd for it */ for (ts = 1; ts < NUM_E1_TS; ts++) { - unsigned int idx = i-1; + unsigned int idx = ts-1; struct bsc_fd *bfd = &e1h->fd[idx]; struct sockaddr_mISDN addr; - if (ts == 1) + bfd->data = e1h; + bfd->priv_nr = ts; + bfd->cb = misdn_fd_cb; + + if (ts == 1) { bfd->fd = socket(PF_ISDN, SOCK_RAW, ISDN_P_LAPD_NT); - else + bfd->when = BSC_FD_READ; + } else bfd->fd = socket(PF_ISDN, SOCK_DGRAM, ISDN_P_B_RAW); - if (bfd->fd < 0) + + if (bfd->fd < 0) { fprintf(stderr, "could not open socket %s\n", strerror(errno)); return bfd->fd; @@ -272,10 +342,35 @@ static int mi_setup(devinfo_t *di) ret = bind(bfd->fd, (struct sockaddr *) &addr, sizeof(addr)); if (ret < 0) { - fprintf(stdout, "could not bind l2 socket %s\n", + fprintf(stderr, "could not bind l2 socket %s\n", strerror(errno)); return -EIO; } + + ret = bsc_register_fd(bfd); + if (ret < 0) { + fprintf(stderr, "could not register FD: %s\n", + strerror(ret)); + return ret; + } } + + return 0; } +int mi_setup(struct gsm_bts *bts, int cardnr) +{ + struct mi_e1_handle *e1h; + + e1h = malloc(sizeof(*e1h)); + memset(e1h, 0, sizeof(*e1h)); + + e1h->cardnr = cardnr; + e1h->bts = bts; + INIT_LLIST_HEAD(&e1h->oml_tx_list); + INIT_LLIST_HEAD(&e1h->rsl_tx_list); + + global_e1h = e1h; + + return mi_e1_setup(e1h); +} diff --git a/src/msgb.c b/src/msgb.c index ab356de95..f5330c38b 100644 --- a/src/msgb.c +++ b/src/msgb.c @@ -22,7 +22,7 @@ #include #include -#include "msgb.h" +#include struct msgb *msgb_alloc(u_int16_t size) { @@ -38,7 +38,7 @@ struct msgb *msgb_alloc(u_int16_t size) msg->head = msg->data; msg->data = msg->data; /* reset tail pointer */ - msg->tail = msg->data - msg->head; + msg->tail = msg->data; //msg->end = msg->tail + size; return msg; @@ -48,3 +48,20 @@ void msgb_free(struct msgb *m) { free(m); } + +void msgb_enqueue(struct llist_head *queue, struct msgb *msg) +{ + llist_add_tail(&msg->list, queue); +} + +struct msgb *msgb_dequeue(struct llist_head *queue) +{ + struct llist_head *lh; + + if (llist_empty(queue)) + return NULL; + + lh = queue->next; + + return llist_entry(lh, struct msgb, list); +} diff --git a/src/select.c b/src/select.c index 0d95cfbe4..4af167047 100644 --- a/src/select.c +++ b/src/select.c @@ -32,11 +32,11 @@ int bsc_register_fd(struct bsc_fd *fd) /* make FD nonblocking */ flags = fcntl(fd->fd, F_GETFL); if (flags < 0) - return -1; + return flags; flags |= O_NONBLOCK; flags = fcntl(fd->fd, F_SETFL, flags); if (flags < 0) - return -1; + return flags; /* Register FD */ if (fd->fd > maxfd)