From: Holger Hans Peter Freyther holger@moiji-mobile.com
--- src/gprs_bssgp_pcu.cpp | 90 +++++++++++++++++++++++++------------------------- 1 file changed, 45 insertions(+), 45 deletions(-)
diff --git a/src/gprs_bssgp_pcu.cpp b/src/gprs_bssgp_pcu.cpp index ae47fb2..4326303 100644 --- a/src/gprs_bssgp_pcu.cpp +++ b/src/gprs_bssgp_pcu.cpp @@ -365,51 +365,51 @@ int gprs_bssgp_pcu_rx_sign(struct msgb *msg, struct tlv_parsed *tp, struct bssgp DEBUGP(DBSSGP, "BSSGP BVCI=%u Rx BVC STATUS\n", bctx->bvci); /* FIXME: send NM_STATUS.ind to NM */ break; - case BSSGP_PDUT_SUSPEND_ACK: - LOGP(DBSSGP, LOGL_DEBUG, "rx BSSGP_PDUT_SUSPEND_ACK\n"); - break; - case BSSGP_PDUT_SUSPEND_NACK: - LOGP(DBSSGP, LOGL_DEBUG, "rx BSSGP_PDUT_SUSPEND_NACK\n"); - break; - case BSSGP_PDUT_BVC_RESET_ACK: - LOGP(DBSSGP, LOGL_DEBUG, "rx BSSGP_PDUT_BVC_RESET_ACK\n"); - if (!the_pcu.bvc_sig_reset) - the_pcu.bvc_sig_reset = 1; - else - the_pcu.bvc_reset = 1; - bvc_timeout(NULL); - break; - case BSSGP_PDUT_PAGING_PS: - LOGP(DBSSGP, LOGL_NOTICE, "RX: [SGSN->PCU] BSSGP_PDUT_PAGING_PS\n"); - gprs_bssgp_pcu_rx_paging_ps(msg, tp); - break; - case BSSGP_PDUT_PAGING_CS: - LOGP(DBSSGP, LOGL_DEBUG, "rx BSSGP_PDUT_PAGING_CS\n"); - break; - case BSSGP_PDUT_RESUME_ACK: - LOGP(DBSSGP, LOGL_DEBUG, "rx BSSGP_PDUT_RESUME_ACK\n"); - break; - case BSSGP_PDUT_RESUME_NACK: - LOGP(DBSSGP, LOGL_DEBUG, "rx BSSGP_PDUT_RESUME_NACK\n"); - break; - case BSSGP_PDUT_FLUSH_LL: - LOGP(DBSSGP, LOGL_DEBUG, "rx BSSGP_PDUT_FLUSH_LL\n"); - break; - case BSSGP_PDUT_BVC_BLOCK_ACK: - LOGP(DBSSGP, LOGL_DEBUG, "rx BSSGP_PDUT_SUSPEND_ACK\n"); - break; - case BSSGP_PDUT_BVC_UNBLOCK_ACK: - LOGP(DBSSGP, LOGL_DEBUG, "rx BSSGP_PDUT_BVC_UNBLOCK_ACK\n"); - the_pcu.bvc_unblocked = 1; - bvc_timeout(NULL); - break; - case BSSGP_PDUT_SGSN_INVOKE_TRACE: - LOGP(DBSSGP, LOGL_DEBUG, "rx BSSGP_PDUT_SGSN_INVOKE_TRACE\n"); - break; - default: - LOGP(DBSSGP, LOGL_NOTICE, "BSSGP BVCI=%u Rx PDU type 0x%02x unknown\n", bctx->bvci, bgph->pdu_type); - rc = bssgp_tx_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg); - break; + case BSSGP_PDUT_SUSPEND_ACK: + LOGP(DBSSGP, LOGL_DEBUG, "rx BSSGP_PDUT_SUSPEND_ACK\n"); + break; + case BSSGP_PDUT_SUSPEND_NACK: + LOGP(DBSSGP, LOGL_DEBUG, "rx BSSGP_PDUT_SUSPEND_NACK\n"); + break; + case BSSGP_PDUT_BVC_RESET_ACK: + LOGP(DBSSGP, LOGL_DEBUG, "rx BSSGP_PDUT_BVC_RESET_ACK\n"); + if (!the_pcu.bvc_sig_reset) + the_pcu.bvc_sig_reset = 1; + else + the_pcu.bvc_reset = 1; + bvc_timeout(NULL); + break; + case BSSGP_PDUT_PAGING_PS: + LOGP(DBSSGP, LOGL_NOTICE, "RX: [SGSN->PCU] BSSGP_PDUT_PAGING_PS\n"); + gprs_bssgp_pcu_rx_paging_ps(msg, tp); + break; + case BSSGP_PDUT_PAGING_CS: + LOGP(DBSSGP, LOGL_DEBUG, "rx BSSGP_PDUT_PAGING_CS\n"); + break; + case BSSGP_PDUT_RESUME_ACK: + LOGP(DBSSGP, LOGL_DEBUG, "rx BSSGP_PDUT_RESUME_ACK\n"); + break; + case BSSGP_PDUT_RESUME_NACK: + LOGP(DBSSGP, LOGL_DEBUG, "rx BSSGP_PDUT_RESUME_NACK\n"); + break; + case BSSGP_PDUT_FLUSH_LL: + LOGP(DBSSGP, LOGL_DEBUG, "rx BSSGP_PDUT_FLUSH_LL\n"); + break; + case BSSGP_PDUT_BVC_BLOCK_ACK: + LOGP(DBSSGP, LOGL_DEBUG, "rx BSSGP_PDUT_SUSPEND_ACK\n"); + break; + case BSSGP_PDUT_BVC_UNBLOCK_ACK: + LOGP(DBSSGP, LOGL_DEBUG, "rx BSSGP_PDUT_BVC_UNBLOCK_ACK\n"); + the_pcu.bvc_unblocked = 1; + bvc_timeout(NULL); + break; + case BSSGP_PDUT_SGSN_INVOKE_TRACE: + LOGP(DBSSGP, LOGL_DEBUG, "rx BSSGP_PDUT_SGSN_INVOKE_TRACE\n"); + break; + default: + LOGP(DBSSGP, LOGL_NOTICE, "BSSGP BVCI=%u Rx PDU type 0x%02x unknown\n", bctx->bvci, bgph->pdu_type); + rc = bssgp_tx_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg); + break; } return rc; }
From: Holger Hans Peter Freyther holger@moiji-mobile.com
--- src/gprs_bssgp_pcu.cpp | 8 ++++---- src/gprs_bssgp_pcu.h | 8 -------- 2 files changed, 4 insertions(+), 12 deletions(-)
diff --git a/src/gprs_bssgp_pcu.cpp b/src/gprs_bssgp_pcu.cpp index 4326303..a0ef206 100644 --- a/src/gprs_bssgp_pcu.cpp +++ b/src/gprs_bssgp_pcu.cpp @@ -112,7 +112,7 @@ static int parse_ra_cap_ms_class(struct tlv_parsed *tp) return ms_class; }
-int gprs_bssgp_pcu_rx_dl_ud(struct msgb *msg, struct tlv_parsed *tp) +static int gprs_bssgp_pcu_rx_dl_ud(struct msgb *msg, struct tlv_parsed *tp) { struct bssgp_ud_hdr *budh;
@@ -307,7 +307,7 @@ int gprs_bssgp_pcu_rx_paging_ps(struct msgb *msg, struct tlv_parsed *tp) }
/* Receive a BSSGP PDU from a BSS on a PTP BVCI */ -int gprs_bssgp_pcu_rx_ptp(struct msgb *msg, struct tlv_parsed *tp, struct bssgp_bvc_ctx *bctx) +static int gprs_bssgp_pcu_rx_ptp(struct msgb *msg, struct tlv_parsed *tp, struct bssgp_bvc_ctx *bctx) { struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msgb_bssgph(msg); uint8_t pdu_type = bgph->pdu_type; @@ -355,7 +355,7 @@ int gprs_bssgp_pcu_rx_ptp(struct msgb *msg, struct tlv_parsed *tp, struct bssgp_ }
/* Receive a BSSGP PDU from a SGSN on a SIGNALLING BVCI */ -int gprs_bssgp_pcu_rx_sign(struct msgb *msg, struct tlv_parsed *tp, struct bssgp_bvc_ctx *bctx) +static int gprs_bssgp_pcu_rx_sign(struct msgb *msg, struct tlv_parsed *tp, struct bssgp_bvc_ctx *bctx) { struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msgb_bssgph(msg); int rc = 0; @@ -414,7 +414,7 @@ int gprs_bssgp_pcu_rx_sign(struct msgb *msg, struct tlv_parsed *tp, struct bssgp return rc; }
-int gprs_bssgp_pcu_rcvmsg(struct msgb *msg) +static int gprs_bssgp_pcu_rcvmsg(struct msgb *msg) { struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msgb_bssgph(msg); struct bssgp_ud_hdr *budh = (struct bssgp_ud_hdr *) msgb_bssgph(msg); diff --git a/src/gprs_bssgp_pcu.h b/src/gprs_bssgp_pcu.h index b611a19..9f0adc9 100644 --- a/src/gprs_bssgp_pcu.h +++ b/src/gprs_bssgp_pcu.h @@ -41,14 +41,6 @@ struct bssgp_bvc_ctx *btsctx_alloc(uint16_t bvci, uint16_t nsei); #define NS_HDR_LEN 4 #define IE_LLC_PDU 14
-int gprs_bssgp_pcu_rx_dl_ud(struct msgb *msg, struct tlv_parsed *tp); - -int gprs_bssgp_pcu_rx_ptp(struct msgb *msg, struct tlv_parsed *tp, struct bssgp_bvc_ctx *bctx); - -int gprs_bssgp_pcu_rx_sign(struct msgb *msg, struct tlv_parsed *tp, struct bssgp_bvc_ctx *bctx); - -int gprs_bssgp_pcu_rcvmsg(struct msgb *msg); - int gprs_bssgp_create_and_connect(uint16_t local_port, uint32_t sgsn_ip, uint16_t sgsn_port, uint16_t nsei, uint16_t nsvci, uint16_t bvci, uint16_t mcc, uint16_t mnc, uint16_t lac, uint16_t rac,
From: Holger Hans Peter Freyther holger@moiji-mobile.com
For mocking/unit-testing/emulation (and a dual trx-systems) having global state is quite bad. Cut back on the usage of the global struct gprs_rlcmac_bts. It also makes the complexity of certain routines more clear. --- src/gprs_bssgp_pcu.cpp | 20 +++++++++++--------- src/gprs_bssgp_pcu.h | 8 ++++---- src/gprs_rlcmac.cpp | 27 +++++++++++++-------------- src/gprs_rlcmac.h | 19 ++++++++++++------- src/gprs_rlcmac_data.cpp | 15 ++++++++------- src/pcu_l1_if.cpp | 2 +- 6 files changed, 49 insertions(+), 42 deletions(-)
diff --git a/src/gprs_bssgp_pcu.cpp b/src/gprs_bssgp_pcu.cpp index a0ef206..acd30a4 100644 --- a/src/gprs_bssgp_pcu.cpp +++ b/src/gprs_bssgp_pcu.cpp @@ -25,6 +25,8 @@ struct osmo_pcu { struct gprs_nsvc *nsvc; struct bssgp_bvc_ctx *bctx;
+ struct gprs_rlcmac_bts *bts; + struct osmo_timer_list bvc_timer;
int nsvc_unblocked; @@ -187,15 +189,14 @@ static int gprs_bssgp_pcu_rx_dl_ud(struct msgb *msg, struct tlv_parsed *tp) } else { /* the TBF exists, so we must write it in the queue * we prepend lifetime in front of PDU */ - struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts; struct timeval *tv; struct msgb *llc_msg = msgb_alloc(len + sizeof(*tv), "llc_pdu_queue"); if (!llc_msg) return -ENOMEM; tv = (struct timeval *)msgb_put(llc_msg, sizeof(*tv)); - if (bts->force_llc_lifetime) - delay_csec = bts->force_llc_lifetime; + if (the_pcu.bts->force_llc_lifetime) + delay_csec = the_pcu.bts->force_llc_lifetime; /* keep timestap at 0 for infinite delay */ if (delay_csec != 0xffff) { /* calculate timestamp of timeout */ @@ -247,14 +248,14 @@ static int gprs_bssgp_pcu_rx_dl_ud(struct msgb *msg, struct tlv_parsed *tp) }
// Create new TBF (any TRX) - tfi = tfi_alloc(GPRS_RLCMAC_DL_TBF, &trx, use_trx); + tfi = tfi_alloc(the_pcu.bts, GPRS_RLCMAC_DL_TBF, &trx, use_trx); if (tfi < 0) { LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH resource\n"); /* FIXME: send reject */ return -EBUSY; } /* set number of downlink slots according to multislot class */ - tbf = tbf_alloc(tbf, GPRS_RLCMAC_DL_TBF, tfi, trx, ms_class, + tbf = tbf_alloc(the_pcu.bts, tbf, GPRS_RLCMAC_DL_TBF, tfi, trx, ms_class, ss); if (!tbf) { LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH ressource\n"); @@ -560,8 +561,6 @@ int gprs_bssgp_tx_fc_bvc(void)
static void bvc_timeout(void *_priv) { - struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts; - if (!the_pcu.bvc_sig_reset) { LOGP(DBSSGP, LOGL_INFO, "Sending reset on BVCI 0\n"); bssgp_tx_bvc_reset(the_pcu.bctx, 0, BSSGP_CAUSE_OML_INTERV); @@ -588,11 +587,12 @@ static void bvc_timeout(void *_priv) LOGP(DBSSGP, LOGL_DEBUG, "Sending flow control info on BVCI %d\n", the_pcu.bctx->bvci); gprs_bssgp_tx_fc_bvc(); - osmo_timer_schedule(&the_pcu.bvc_timer, bts->fc_interval, 0); + osmo_timer_schedule(&the_pcu.bvc_timer, the_pcu.bts->fc_interval, 0); }
/* create BSSGP/NS layer instances */ -int gprs_bssgp_create_and_connect(uint16_t local_port, uint32_t sgsn_ip, +int gprs_bssgp_create_and_connect(struct gprs_rlcmac_bts *bts, + uint16_t local_port, uint32_t sgsn_ip, uint16_t sgsn_port, uint16_t nsei, uint16_t nsvci, uint16_t bvci, uint16_t mcc, uint16_t mnc, uint16_t lac, uint16_t rac, uint16_t cell_id) @@ -607,6 +607,8 @@ int gprs_bssgp_create_and_connect(uint16_t local_port, uint32_t sgsn_ip, if (the_pcu.bctx) return 0; /* if already created, must return 0: no error */
+ the_pcu.bts = bts; + bssgp_nsi = gprs_ns_instantiate(&sgsn_ns_cb, tall_pcu_ctx); if (!bssgp_nsi) { LOGP(DBSSGP, LOGL_ERROR, "Failed to create NS instance\n"); diff --git a/src/gprs_bssgp_pcu.h b/src/gprs_bssgp_pcu.h index 9f0adc9..15c8d9f 100644 --- a/src/gprs_bssgp_pcu.h +++ b/src/gprs_bssgp_pcu.h @@ -41,10 +41,10 @@ struct bssgp_bvc_ctx *btsctx_alloc(uint16_t bvci, uint16_t nsei); #define NS_HDR_LEN 4 #define IE_LLC_PDU 14
-int gprs_bssgp_create_and_connect(uint16_t local_port, uint32_t sgsn_ip, uint16_t - sgsn_port, uint16_t nsei, uint16_t nsvci, uint16_t bvci, - uint16_t mcc, uint16_t mnc, uint16_t lac, uint16_t rac, - uint16_t cell_id); +int gprs_bssgp_create_and_connect(struct gprs_rlcmac_bts *bts, uint16_t local_port, + uint32_t sgsn_ip, uint16_t sgsn_port, uint16_t nsei, + uint16_t nsvci, uint16_t bvci, uint16_t mcc, uint16_t mnc, + uint16_t lac, uint16_t rac, uint16_t cell_id);
void gprs_bssgp_exit_on_destroy(void); void gprs_bssgp_destroy_or_exit(void); diff --git a/src/gprs_rlcmac.cpp b/src/gprs_rlcmac.cpp index f3a24f7..8874983 100644 --- a/src/gprs_rlcmac.cpp +++ b/src/gprs_rlcmac.cpp @@ -176,9 +176,9 @@ void debug_diagram(int diag, const char *format, ...) /* FIXME: spread ressources over multiple TRX. Also add option to use same * TRX in case of existing TBF for TLLI in the other direction. */ /* search for free TFI and return TFI, TRX */ -int tfi_alloc(enum gprs_rlcmac_tbf_direction dir, uint8_t *_trx, int8_t use_trx) +int tfi_alloc(struct gprs_rlcmac_bts *bts, enum gprs_rlcmac_tbf_direction dir, + uint8_t *_trx, int8_t use_trx) { - struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts; struct gprs_rlcmac_pdch *pdch; struct gprs_rlcmac_tbf **tbfp; uint8_t trx_from, trx_to, trx, ts, tfi; @@ -252,11 +252,10 @@ static inline int8_t find_free_usf(struct gprs_rlcmac_pdch *pdch, uint8_t ts) }
/* lookup TBF Entity (by TFI) */ -struct gprs_rlcmac_tbf *tbf_by_tfi(uint8_t tfi, uint8_t trx, - enum gprs_rlcmac_tbf_direction dir) +struct gprs_rlcmac_tbf *tbf_by_tfi(struct gprs_rlcmac_bts *bts, + uint8_t tfi, uint8_t trx, enum gprs_rlcmac_tbf_direction dir) { struct gprs_rlcmac_tbf *tbf; - struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts;
if (tfi >= 32 || trx >= 8) return NULL; @@ -318,11 +317,11 @@ struct gprs_rlcmac_tbf *tbf_by_poll_fn(uint32_t fn, uint8_t trx, uint8_t ts) return NULL; }
-struct gprs_rlcmac_tbf *tbf_alloc(struct gprs_rlcmac_tbf *old_tbf, - enum gprs_rlcmac_tbf_direction dir, uint8_t tfi, uint8_t trx, +struct gprs_rlcmac_tbf *tbf_alloc(struct gprs_rlcmac_bts *bts, + struct gprs_rlcmac_tbf *old_tbf, enum gprs_rlcmac_tbf_direction dir, + uint8_t tfi, uint8_t trx, uint8_t ms_class, uint8_t single_slot) { - struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts; struct gprs_rlcmac_tbf *tbf; int rc;
@@ -367,7 +366,7 @@ next_diagram: tbf->ws = 64; tbf->sns = 128; /* select algorithm */ - rc = bts->alloc_algorithm(old_tbf, tbf, bts->alloc_algorithm_curst, + rc = bts->alloc_algorithm(bts, old_tbf, tbf, bts->alloc_algorithm_curst, single_slot); /* if no ressource */ if (rc < 0) { @@ -406,10 +405,10 @@ next_diagram: * * Assign single slot for uplink and downlink */ -int alloc_algorithm_a(struct gprs_rlcmac_tbf *old_tbf, +int alloc_algorithm_a(struct gprs_rlcmac_bts *bts, + struct gprs_rlcmac_tbf *old_tbf, struct gprs_rlcmac_tbf *tbf, uint32_t cust, uint8_t single) { - struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts; struct gprs_rlcmac_pdch *pdch; uint8_t ts; int8_t usf; /* must be signed */ @@ -462,10 +461,10 @@ int alloc_algorithm_a(struct gprs_rlcmac_tbf *old_tbf, * Assign one uplink slot. (With free USF) * */ -int alloc_algorithm_b(struct gprs_rlcmac_tbf *old_tbf, +int alloc_algorithm_b(struct gprs_rlcmac_bts *bts, + struct gprs_rlcmac_tbf *old_tbf, struct gprs_rlcmac_tbf *tbf, uint32_t cust, uint8_t single) { - struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts; struct gprs_rlcmac_pdch *pdch; struct gprs_ms_multislot_class *ms_class; uint8_t Rx, Tx, Sum; /* Maximum Number of Slots: RX, Tx, Sum Rx+Tx */ @@ -964,7 +963,7 @@ int tbf_update(struct gprs_rlcmac_tbf *tbf) ul_tbf = tbf_by_tlli(tbf->tlli, GPRS_RLCMAC_UL_TBF);
tbf_unlink_pdch(tbf); - rc = bts->alloc_algorithm(ul_tbf, tbf, bts->alloc_algorithm_curst, 0); + rc = bts->alloc_algorithm(bts, ul_tbf, tbf, bts->alloc_algorithm_curst, 0); /* if no ressource */ if (rc < 0) { LOGP(DRLCMAC, LOGL_ERROR, "No ressource after update???\n"); diff --git a/src/gprs_rlcmac.h b/src/gprs_rlcmac.h index c5af602..ac437f5 100644 --- a/src/gprs_rlcmac.h +++ b/src/gprs_rlcmac.h @@ -84,7 +84,8 @@ struct gprs_rlcmac_bts { uint8_t n3103; uint8_t n3105; struct gprs_rlcmac_trx trx[8]; - int (*alloc_algorithm)(struct gprs_rlcmac_tbf *old_tbf, + int (*alloc_algorithm)(struct gprs_rlcmac_bts *bts, + struct gprs_rlcmac_tbf *old_tbf, struct gprs_rlcmac_tbf *tbf, uint32_t cust, uint8_t single); uint32_t alloc_algorithm_curst; /* options to customize algorithm */ uint8_t force_two_phase; @@ -308,14 +309,16 @@ int sba_alloc(uint8_t *_trx, uint8_t *_ts, uint32_t *_fn, uint8_t ta);
struct gprs_rlcmac_sba *sba_find(uint8_t trx, uint8_t ts, uint32_t fn);
-int tfi_alloc(enum gprs_rlcmac_tbf_direction dir, uint8_t *_trx, - int8_t use_trx); +int tfi_alloc(struct gprs_rlcmac_bts *bts, enum gprs_rlcmac_tbf_direction dir, + uint8_t *_trx, int8_t use_trx);
-struct gprs_rlcmac_tbf *tbf_alloc(struct gprs_rlcmac_tbf *old_tbf, +struct gprs_rlcmac_tbf *tbf_alloc(struct gprs_rlcmac_bts *bts, + struct gprs_rlcmac_tbf *old_tbf, enum gprs_rlcmac_tbf_direction dir, uint8_t tfi, uint8_t trx, uint8_t ms_class, uint8_t single_slot);
-struct gprs_rlcmac_tbf *tbf_by_tfi(uint8_t tfi, uint8_t trx, +struct gprs_rlcmac_tbf *tbf_by_tfi(struct gprs_rlcmac_bts *bts, + uint8_t tfi, uint8_t trx, enum gprs_rlcmac_tbf_direction dir);
struct gprs_rlcmac_tbf *tbf_by_tlli(uint32_t tlli, @@ -431,10 +434,12 @@ int flush_timing_advance(void);
extern "C" { #endif -int alloc_algorithm_a(struct gprs_rlcmac_tbf *old_tbf, +int alloc_algorithm_a(struct gprs_rlcmac_bts *bts, + struct gprs_rlcmac_tbf *old_tbf, struct gprs_rlcmac_tbf *tbf, uint32_t cust, uint8_t single);
-int alloc_algorithm_b(struct gprs_rlcmac_tbf *old_tbf, +int alloc_algorithm_b(struct gprs_rlcmac_bts *bts, + struct gprs_rlcmac_tbf *old_tbf, struct gprs_rlcmac_tbf *tbf, uint32_t cust, uint8_t single); #ifdef __cplusplus } diff --git a/src/gprs_rlcmac_data.cpp b/src/gprs_rlcmac_data.cpp index 99fac1b..4d5acb9 100644 --- a/src/gprs_rlcmac_data.cpp +++ b/src/gprs_rlcmac_data.cpp @@ -239,14 +239,14 @@ static struct gprs_rlcmac_tbf *alloc_ul_tbf(int8_t use_trx, uint8_t ms_class, uint8_t tfi;
/* create new TBF, use sme TRX as DL TBF */ - tfi = tfi_alloc(GPRS_RLCMAC_UL_TBF, &trx, use_trx); + tfi = tfi_alloc(bts, GPRS_RLCMAC_UL_TBF, &trx, use_trx); if (tfi < 0) { LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH ressource\n"); /* FIXME: send reject */ return NULL; } /* use multislot class of downlink TBF */ - tbf = tbf_alloc(dl_tbf, GPRS_RLCMAC_UL_TBF, tfi, trx, ms_class, 0); + tbf = tbf_alloc(bts, dl_tbf, GPRS_RLCMAC_UL_TBF, tfi, trx, ms_class, 0); if (!tbf) { LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH ressource\n"); /* FIXME: send reject */ @@ -273,6 +273,7 @@ int gprs_rlcmac_rcv_control_block(bitvec *rlc_block, uint8_t trx, uint8_t ts, uint32_t tlli = 0; struct gprs_rlcmac_tbf *tbf; struct gprs_rlcmac_sba *sba; + struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts; int rc;
RlcMacUplink_t * ul_control_block = (RlcMacUplink_t *)talloc_zero(tall_pcu_ctx, RlcMacUplink_t); @@ -478,14 +479,14 @@ int gprs_rlcmac_rcv_control_block(bitvec *rlc_block, uint8_t trx, uint8_t ts, } else { if (ul_control_block->u.Packet_Resource_Request.ID.u.Global_TFI.UnionType) { tfi = ul_control_block->u.Packet_Resource_Request.ID.u.Global_TFI.u.DOWNLINK_TFI; - tbf = tbf_by_tfi(tfi, trx, GPRS_RLCMAC_DL_TBF); + tbf = tbf_by_tfi(bts, tfi, trx, GPRS_RLCMAC_DL_TBF); if (!tbf) { LOGP(DRLCMAC, LOGL_NOTICE, "PACKET RESSOURCE REQ unknown downlink TBF=%d\n", tlli); break; } } else { tfi = ul_control_block->u.Packet_Resource_Request.ID.u.Global_TFI.u.UPLINK_TFI; - tbf = tbf_by_tfi(tfi, trx, GPRS_RLCMAC_UL_TBF); + tbf = tbf_by_tfi(bts, tfi, trx, GPRS_RLCMAC_UL_TBF); if (!tbf) { LOGP(DRLCMAC, LOGL_NOTICE, "PACKET RESSOURCE REQ unknown uplink TBF=%d\n", tlli); break; @@ -876,7 +877,7 @@ int gprs_rlcmac_rcv_data_block_acknowledged(uint8_t trx, uint8_t ts, }
/* find TBF inst from given TFI */ - tbf = tbf_by_tfi(rh->tfi, trx, GPRS_RLCMAC_UL_TBF); + tbf = tbf_by_tfi(bts, rh->tfi, trx, GPRS_RLCMAC_UL_TBF); if (!tbf) { LOGP(DRLCMACUL, LOGL_NOTICE, "UL DATA unknown TBF=%d\n", rh->tfi); @@ -1173,14 +1174,14 @@ int gprs_rlcmac_rcv_rach(uint8_t ra, uint32_t Fn, int16_t qta) "(AGCH)\n"); } else { // Create new TBF - tfi = tfi_alloc(GPRS_RLCMAC_UL_TBF, &trx, -1); + tfi = tfi_alloc(bts, GPRS_RLCMAC_UL_TBF, &trx, -1); if (tfi < 0) { LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH ressource\n"); /* FIXME: send reject */ return -EBUSY; } /* set class to 0, since we don't know the multislot class yet */ - tbf = tbf_alloc(NULL, GPRS_RLCMAC_UL_TBF, tfi, trx, 0, 1); + tbf = tbf_alloc(bts, NULL, GPRS_RLCMAC_UL_TBF, tfi, trx, 0, 1); if (!tbf) { LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH ressource\n"); /* FIXME: send reject */ diff --git a/src/pcu_l1_if.cpp b/src/pcu_l1_if.cpp index b7b0269..e53b683 100644 --- a/src/pcu_l1_if.cpp +++ b/src/pcu_l1_if.cpp @@ -418,7 +418,7 @@ bssgp_failed: ia.s_addr = htonl(info_ind->remote_ip[0]); LOGP(DL1IF, LOGL_DEBUG, " remote_ip=%s\n", inet_ntoa(ia));
- rc = gprs_bssgp_create_and_connect(info_ind->local_port[0], + rc = gprs_bssgp_create_and_connect(bts, info_ind->local_port[0], info_ind->remote_ip[0], info_ind->remote_port[0], info_ind->nsei, info_ind->nsvci[0], info_ind->bvci, info_ind->mcc, info_ind->mnc, info_ind->lac, info_ind->rac,
From: Holger Hans Peter Freyther holger@moiji-mobile.com
This can be used to install handlers/testcases to register callbacks and other data. --- src/gprs_bssgp_pcu.cpp | 33 +++++++++------------------------ src/gprs_bssgp_pcu.h | 19 ++++++++++++++++++- src/pcu_l1_if.cpp | 5 +++-- 3 files changed, 30 insertions(+), 27 deletions(-)
diff --git a/src/gprs_bssgp_pcu.cpp b/src/gprs_bssgp_pcu.cpp index acd30a4..c332786 100644 --- a/src/gprs_bssgp_pcu.cpp +++ b/src/gprs_bssgp_pcu.cpp @@ -21,23 +21,7 @@ #include <gprs_bssgp_pcu.h> #include <pcu_l1_if.h>
-struct osmo_pcu { - struct gprs_nsvc *nsvc; - struct bssgp_bvc_ctx *bctx; - - struct gprs_rlcmac_bts *bts; - - struct osmo_timer_list bvc_timer; - - int nsvc_unblocked; - - int bvc_sig_reset; - int bvc_reset; - int bvc_unblocked; - int exit_on_destroy; -}; - -static struct osmo_pcu the_pcu = { 0, }; +static struct gprs_bssgp_pcu the_pcu = { 0, };
extern void *tall_pcu_ctx; extern uint16_t spoof_mcc, spoof_mnc; @@ -591,7 +575,7 @@ static void bvc_timeout(void *_priv) }
/* create BSSGP/NS layer instances */ -int gprs_bssgp_create_and_connect(struct gprs_rlcmac_bts *bts, +struct gprs_bssgp_pcu *gprs_bssgp_create_and_connect(struct gprs_rlcmac_bts *bts, uint16_t local_port, uint32_t sgsn_ip, uint16_t sgsn_port, uint16_t nsei, uint16_t nsvci, uint16_t bvci, uint16_t mcc, uint16_t mnc, uint16_t lac, uint16_t rac, @@ -604,15 +588,16 @@ int gprs_bssgp_create_and_connect(struct gprs_rlcmac_bts *bts, mnc = ((mnc & 0xf00) >> 8) * 100 + ((mnc & 0x0f0) >> 4) * 10 + (mnc & 0x00f); cell_id = ntohs(cell_id);
+ /* if already created... return the current address */ if (the_pcu.bctx) - return 0; /* if already created, must return 0: no error */ + return &the_pcu;
the_pcu.bts = bts;
bssgp_nsi = gprs_ns_instantiate(&sgsn_ns_cb, tall_pcu_ctx); if (!bssgp_nsi) { LOGP(DBSSGP, LOGL_ERROR, "Failed to create NS instance\n"); - return -EINVAL; + return NULL; } gprs_ns_vty_init(bssgp_nsi); bssgp_nsi->nsip.local_port = local_port; @@ -621,7 +606,7 @@ int gprs_bssgp_create_and_connect(struct gprs_rlcmac_bts *bts, LOGP(DBSSGP, LOGL_ERROR, "Failed to create socket\n"); gprs_ns_destroy(bssgp_nsi); bssgp_nsi = NULL; - return -EINVAL; + return NULL; }
dest.sin_family = AF_INET; @@ -633,7 +618,7 @@ int gprs_bssgp_create_and_connect(struct gprs_rlcmac_bts *bts, LOGP(DBSSGP, LOGL_ERROR, "Failed to create NSVCt\n"); gprs_ns_destroy(bssgp_nsi); bssgp_nsi = NULL; - return -EINVAL; + return NULL; }
the_pcu.bctx = btsctx_alloc(bvci, nsei); @@ -642,7 +627,7 @@ int gprs_bssgp_create_and_connect(struct gprs_rlcmac_bts *bts, the_pcu.nsvc = NULL; gprs_ns_destroy(bssgp_nsi); bssgp_nsi = NULL; - return -EINVAL; + return NULL; } the_pcu.bctx->ra_id.mcc = spoof_mcc ? : mcc; the_pcu.bctx->ra_id.mnc = spoof_mnc ? : mnc; @@ -655,7 +640,7 @@ int gprs_bssgp_create_and_connect(struct gprs_rlcmac_bts *bts, the_pcu.bvc_timer.cb = bvc_timeout;
- return 0; + return &the_pcu; }
void gprs_bssgp_destroy_or_exit(void) diff --git a/src/gprs_bssgp_pcu.h b/src/gprs_bssgp_pcu.h index 15c8d9f..2d96032 100644 --- a/src/gprs_bssgp_pcu.h +++ b/src/gprs_bssgp_pcu.h @@ -41,7 +41,24 @@ struct bssgp_bvc_ctx *btsctx_alloc(uint16_t bvci, uint16_t nsei); #define NS_HDR_LEN 4 #define IE_LLC_PDU 14
-int gprs_bssgp_create_and_connect(struct gprs_rlcmac_bts *bts, uint16_t local_port, +struct gprs_bssgp_pcu { + struct gprs_nsvc *nsvc; + struct bssgp_bvc_ctx *bctx; + + struct gprs_rlcmac_bts *bts; + + struct osmo_timer_list bvc_timer; + + int nsvc_unblocked; + + int bvc_sig_reset; + int bvc_reset; + int bvc_unblocked; + int exit_on_destroy; +}; + +struct gprs_bssgp_pcu *gprs_bssgp_create_and_connect(struct gprs_rlcmac_bts *bts, + uint16_t local_port, uint32_t sgsn_ip, uint16_t sgsn_port, uint16_t nsei, uint16_t nsvci, uint16_t bvci, uint16_t mcc, uint16_t mnc, uint16_t lac, uint16_t rac, uint16_t cell_id); diff --git a/src/pcu_l1_if.cpp b/src/pcu_l1_if.cpp index e53b683..43bd36e 100644 --- a/src/pcu_l1_if.cpp +++ b/src/pcu_l1_if.cpp @@ -336,6 +336,7 @@ int flush_pdch(struct gprs_rlcmac_pdch *pdch, uint8_t trx, uint8_t ts) static int pcu_rx_info_ind(struct gsm_pcu_if_info_ind *info_ind) { struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts; + struct gprs_bssgp_pcu *pcu; struct gprs_rlcmac_pdch *pdch; struct in_addr ia; int rc = 0; @@ -418,12 +419,12 @@ bssgp_failed: ia.s_addr = htonl(info_ind->remote_ip[0]); LOGP(DL1IF, LOGL_DEBUG, " remote_ip=%s\n", inet_ntoa(ia));
- rc = gprs_bssgp_create_and_connect(bts, info_ind->local_port[0], + pcu = gprs_bssgp_create_and_connect(bts, info_ind->local_port[0], info_ind->remote_ip[0], info_ind->remote_port[0], info_ind->nsei, info_ind->nsvci[0], info_ind->bvci, info_ind->mcc, info_ind->mnc, info_ind->lac, info_ind->rac, info_ind->cell_id); - if (rc < 0) { + if (!pcu) { LOGP(DL1IF, LOGL_NOTICE, "SGSN not available\n"); goto bssgp_failed; }
From: Holger Hans Peter Freyther holger@moiji-mobile.com
Add a callback called when Unblock Ack is received. This can be used by a supervisor or the emulation test. --- src/gprs_bssgp_pcu.cpp | 2 ++ src/gprs_bssgp_pcu.h | 6 ++++++ 2 files changed, 8 insertions(+)
diff --git a/src/gprs_bssgp_pcu.cpp b/src/gprs_bssgp_pcu.cpp index c332786..cc66290 100644 --- a/src/gprs_bssgp_pcu.cpp +++ b/src/gprs_bssgp_pcu.cpp @@ -386,6 +386,8 @@ static int gprs_bssgp_pcu_rx_sign(struct msgb *msg, struct tlv_parsed *tp, struc case BSSGP_PDUT_BVC_UNBLOCK_ACK: LOGP(DBSSGP, LOGL_DEBUG, "rx BSSGP_PDUT_BVC_UNBLOCK_ACK\n"); the_pcu.bvc_unblocked = 1; + if (the_pcu.on_unblock_ack) + the_pcu.on_unblock_ack(&the_pcu); bvc_timeout(NULL); break; case BSSGP_PDUT_SGSN_INVOKE_TRACE: diff --git a/src/gprs_bssgp_pcu.h b/src/gprs_bssgp_pcu.h index 2d96032..413c056 100644 --- a/src/gprs_bssgp_pcu.h +++ b/src/gprs_bssgp_pcu.h @@ -1,6 +1,7 @@ /* gprs_bssgp_pcu.h * * Copyright (C) 2012 Ivan Klyuchnikov + * Copyright (C) 2013 by Holger Hans Peter Freyther * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -55,6 +56,11 @@ struct gprs_bssgp_pcu { int bvc_reset; int bvc_unblocked; int exit_on_destroy; + + /** callbacks below */ + + /* The BSSGP has been unblocked */ + void (*on_unblock_ack)(struct gprs_bssgp_pcu *pcu); };
struct gprs_bssgp_pcu *gprs_bssgp_create_and_connect(struct gprs_rlcmac_bts *bts,
From: Holger Hans Peter Freyther holger@moiji-mobile.com
--- src/gprs_bssgp_pcu.cpp | 3 +++ src/gprs_bssgp_pcu.h | 4 ++++ 2 files changed, 7 insertions(+)
diff --git a/src/gprs_bssgp_pcu.cpp b/src/gprs_bssgp_pcu.cpp index cc66290..6f67f52 100644 --- a/src/gprs_bssgp_pcu.cpp +++ b/src/gprs_bssgp_pcu.cpp @@ -1,6 +1,7 @@ /* gprs_bssgp_pcu.cpp * * Copyright (C) 2012 Ivan Klyuchnikov + * Copyright (C) 2013 by Holger Hans Peter Freyther * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -314,6 +315,8 @@ static int gprs_bssgp_pcu_rx_ptp(struct msgb *msg, struct tlv_parsed *tp, struct switch (pdu_type) { case BSSGP_PDUT_DL_UNITDATA: LOGP(DBSSGP, LOGL_DEBUG, "RX: [SGSN->PCU] BSSGP_PDUT_DL_UNITDATA\n"); + if (the_pcu.on_dl_unit_data) + the_pcu.on_dl_unit_data(&the_pcu, msg, tp); gprs_bssgp_pcu_rx_dl_ud(msg, tp); break; case BSSGP_PDUT_PAGING_PS: diff --git a/src/gprs_bssgp_pcu.h b/src/gprs_bssgp_pcu.h index 413c056..7156bf0 100644 --- a/src/gprs_bssgp_pcu.h +++ b/src/gprs_bssgp_pcu.h @@ -61,6 +61,10 @@ struct gprs_bssgp_pcu {
/* The BSSGP has been unblocked */ void (*on_unblock_ack)(struct gprs_bssgp_pcu *pcu); + + /* When BSSGP data arrives. The msgb is not only for reference */ + void (*on_dl_unit_data)(struct gprs_bssgp_pcu *pcu, struct msgb *msg, + struct tlv_parsed *tp); };
struct gprs_bssgp_pcu *gprs_bssgp_create_and_connect(struct gprs_rlcmac_bts *bts,
From: Holger Hans Peter Freyther holger@moiji-mobile.com
This code can open a BSSGP connection toward a SGSN and will inititate the unblocking. It does not send any user data. --- .gitignore | 3 +- tests/Makefile.am | 10 +++++ tests/emu/pcu_emu.cpp | 113 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 125 insertions(+), 1 deletion(-) create mode 100644 tests/emu/pcu_emu.cpp
diff --git a/.gitignore b/.gitignore index fec1b98..07fde56 100644 --- a/.gitignore +++ b/.gitignore @@ -29,9 +29,10 @@ src/osmo-pcu src/osmo-pcu-remote
# tests +.dirstamp tests/atconfig tests/package.m4 -tests/rlcmac/.dirstamp tests/rlcmac/RLCMACTest +tests/emu/pcu_emu tests/testsuite tests/testsuite.log diff --git a/tests/Makefile.am b/tests/Makefile.am index 1faa5f4..a037618 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,6 +1,7 @@ AM_CPPFLAGS = $(STD_DEFINES_AND_INCLUDES) $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGB_CFLAGS) $(LIBOSMOGSM_CFLAGS) -I$(top_srcdir)/src/
check_PROGRAMS = rlcmac/RLCMACTest +noinst_PROGRAMS = emu/pcu_emu
rlcmac_RLCMACTest_SOURCES = rlcmac/RLCMACTest.cpp rlcmac_RLCMACTest_LDADD = \ @@ -8,6 +9,15 @@ rlcmac_RLCMACTest_LDADD = \ $(LIBOSMOCORE_LIBS) \ $(COMMON_LA)
+emu_pcu_emu_SOURCES = emu/pcu_emu.cpp +emu_pcu_emu_LDADD = \ + $(top_builddir)/src/libgprs.la \ + $(LIBOSMOGB_LIBS) \ + $(LIBOSMOGSM_LIBS) \ + $(LIBOSMOCORE_LIBS) \ + $(COMMON_LA) + + # The `:;' works around a Bash 3.2 bug when the output is not writeable. $(srcdir)/package.m4: $(top_srcdir)/configure.ac :;{ \ diff --git a/tests/emu/pcu_emu.cpp b/tests/emu/pcu_emu.cpp new file mode 100644 index 0000000..f78285d --- /dev/null +++ b/tests/emu/pcu_emu.cpp @@ -0,0 +1,113 @@ +/* Code for a software PCU to test a SGSN.. */ + +/* (C) 2013 by Holger Hans Peter Freyther + * + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation; either version 3 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 Affero General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + * + */ + +extern "C" { +#include <osmocom/core/talloc.h> +#include <pcu_vty.h> +} + +#include <gprs_bssgp_pcu.h> +#include <gprs_rlcmac.h> + +#include <stdlib.h> +#include <sys/types.h> +#include <sys/socket.h> + +/* Extern data to please the underlying code */ +void *tall_pcu_ctx; +struct gprs_rlcmac_bts *gprs_rlcmac_bts; +int16_t spoof_mnc = 0, spoof_mcc = 0; + +struct gprs_rlcmac_bts *create_bts() +{ + struct gprs_rlcmac_bts *bts; + + bts = talloc_zero(tall_pcu_ctx, struct gprs_rlcmac_bts); + if (!bts) + return NULL; + bts->fc_interval = 100; + bts->initial_cs_dl = bts->initial_cs_ul = 1; + bts->cs1 = 1; + bts->t3142 = 20; + bts->t3169 = 5; + bts->t3191 = 5; + bts->t3193_msec = 100; + bts->t3195 = 5; + bts->n3101 = 10; + bts->n3103 = 4; + bts->n3105 = 8; + bts->alpha = 0; /* a = 0.0 */ + + if (!bts->alloc_algorithm) + bts->alloc_algorithm = alloc_algorithm_b; + + return bts; +} + +static void bvci_unblocked(struct gprs_bssgp_pcu *pci) +{ + printf("BVCI unblocked. We can begin with test cases.\n"); +} + +void create_and_connect_bssgp(struct gprs_rlcmac_bts *bts, + uint32_t sgsn_ip, uint16_t sgsn_port) +{ + struct gprs_bssgp_pcu *pcu; + + pcu = gprs_bssgp_create_and_connect(bts, 0, sgsn_ip, sgsn_port, + 20, 20, 20, 0x901, 0x99, 1, 0, 0); + pcu->on_unblock_ack = bvci_unblocked; +} + +int main(int argc, char **argv) +{ + struct gprs_rlcmac_bts *bts; + + tall_pcu_ctx = talloc_named_const(NULL, 1, "moiji-mobile Emu-PCU context"); + if (!tall_pcu_ctx) + abort(); + + msgb_set_talloc_ctx(tall_pcu_ctx); + osmo_init_logging(&gprs_log_info); + vty_init(&pcu_vty_info); + pcu_vty_init(&gprs_log_info); + + gprs_rlcmac_bts = create_bts(); + if (!gprs_rlcmac_bts) + abort(); + + create_and_connect_bssgp(gprs_rlcmac_bts, INADDR_LOOPBACK, 23000); + + for (;;) + osmo_select_main(0); + + return EXIT_SUCCESS; +} + +/* + * stubs that should not be reached + */ +extern "C" { +void l1if_pdch_req() { abort(); } +void l1if_connect_pdch() { abort(); } +void l1if_close_pdch() { abort(); } +void l1if_open_pdch() { abort(); } +}
From: Holger Hans Peter Freyther holger@moiji-mobile.com
This will send a static message. It will trigger the GMM code on the SGSN and might ask us for the IMEI/IMSI or send us an accept. As we are not replying at all the SGSN needs to send new requests and we can observe if the sequence number is increasing like it should. --- tests/Makefile.am | 2 +- tests/emu/pcu_emu.cpp | 5 +++- tests/emu/test_replay_gprs_attach.cpp | 56 +++++++++++++++++++++++++++++++++++ 3 files changed, 61 insertions(+), 2 deletions(-) create mode 100644 tests/emu/test_replay_gprs_attach.cpp
diff --git a/tests/Makefile.am b/tests/Makefile.am index a037618..7216d3b 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -9,7 +9,7 @@ rlcmac_RLCMACTest_LDADD = \ $(LIBOSMOCORE_LIBS) \ $(COMMON_LA)
-emu_pcu_emu_SOURCES = emu/pcu_emu.cpp +emu_pcu_emu_SOURCES = emu/pcu_emu.cpp emu/test_replay_gprs_attach.cpp emu_pcu_emu_LDADD = \ $(top_builddir)/src/libgprs.la \ $(LIBOSMOGB_LIBS) \ diff --git a/tests/emu/pcu_emu.cpp b/tests/emu/pcu_emu.cpp index f78285d..337c0c8 100644 --- a/tests/emu/pcu_emu.cpp +++ b/tests/emu/pcu_emu.cpp @@ -36,6 +36,8 @@ void *tall_pcu_ctx; struct gprs_rlcmac_bts *gprs_rlcmac_bts; int16_t spoof_mnc = 0, spoof_mcc = 0;
+extern void test_replay_gprs_attach(struct gprs_bssgp_pcu *pcu); + struct gprs_rlcmac_bts *create_bts() { struct gprs_rlcmac_bts *bts; @@ -62,9 +64,10 @@ struct gprs_rlcmac_bts *create_bts() return bts; }
-static void bvci_unblocked(struct gprs_bssgp_pcu *pci) +static void bvci_unblocked(struct gprs_bssgp_pcu *pcu) { printf("BVCI unblocked. We can begin with test cases.\n"); + test_replay_gprs_attach(pcu); }
void create_and_connect_bssgp(struct gprs_rlcmac_bts *bts, diff --git a/tests/emu/test_replay_gprs_attach.cpp b/tests/emu/test_replay_gprs_attach.cpp new file mode 100644 index 0000000..500b16e --- /dev/null +++ b/tests/emu/test_replay_gprs_attach.cpp @@ -0,0 +1,56 @@ +/* (C) 2013 by Holger Hans Peter Freyther + * + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation; either version 3 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 Affero General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + * + */ + +extern "C" { +#include <osmocom/core/msgb.h> +} + +#include <gprs_bssgp_pcu.h> + +#include <stdint.h> +#include <string.h> + +static const uint8_t gprs_attach_llc[] = { + /* LLC-PDU IE */ + 0x0e, 0x00, 0x2e, + + 0x01, 0xc0, 0x01, 0x08, 0x01, 0x02, 0xf5, 0x40, + 0x71, 0x08, 0x00, 0x05, 0xf4, 0x2d, 0xf1, 0x18, + 0x20, 0x62, 0xf2, 0x10, 0x09, 0x67, 0x00, 0x13, + 0x16, 0x73, 0x43, 0x2a, 0x80, 0x42, 0x00, 0x42, + 0x88, 0x0b, 0x04, 0x20, 0x04, 0x2e, 0x82, 0x30, + 0x42, 0x00, 0x40, 0xaa, 0xf3, 0x18 +}; + +struct msgb *create_msg(const uint8_t *data, size_t len) +{ + struct msgb *msg = msgb_alloc_headroom(4096, 128, "create msg"); + msg->l3h = msgb_put(msg, len); + memcpy(msg->l3h, data, len); + return msg; +} + +void test_replay_gprs_attach(struct gprs_bssgp_pcu *pcu) +{ + uint32_t tlli = 0xadf11820; + const uint8_t qos_profile[] = { 0x0, 0x0, 0x04 }; + + struct msgb *msg = create_msg(gprs_attach_llc, ARRAY_SIZE(gprs_attach_llc)); + bssgp_tx_ul_ud(pcu->bctx, tlli, qos_profile, msg); +}
From: Holger Hans Peter Freyther holger@moiji-mobile.com
Use the OpenBSC SGSN code to parse the LLC data and look into the data we receive. Add assertions to verify the the sequence number is increasing. --- tests/Makefile.am | 3 +- tests/emu/openbsc_clone.c | 216 ++++++++++++++++++++++++++++++++++ tests/emu/openbsc_clone.h | 64 ++++++++++ tests/emu/pcu_emu.cpp | 7 ++ tests/emu/test_replay_gprs_attach.cpp | 39 ++++++ 5 files changed, 328 insertions(+), 1 deletion(-) create mode 100644 tests/emu/openbsc_clone.c create mode 100644 tests/emu/openbsc_clone.h
diff --git a/tests/Makefile.am b/tests/Makefile.am index 7216d3b..0131e47 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -9,7 +9,8 @@ rlcmac_RLCMACTest_LDADD = \ $(LIBOSMOCORE_LIBS) \ $(COMMON_LA)
-emu_pcu_emu_SOURCES = emu/pcu_emu.cpp emu/test_replay_gprs_attach.cpp +emu_pcu_emu_SOURCES = emu/pcu_emu.cpp emu/test_replay_gprs_attach.cpp \ + emu/openbsc_clone.c emu/openbsc_clone.h emu_pcu_emu_LDADD = \ $(top_builddir)/src/libgprs.la \ $(LIBOSMOGB_LIBS) \ diff --git a/tests/emu/openbsc_clone.c b/tests/emu/openbsc_clone.c new file mode 100644 index 0000000..707819b --- /dev/null +++ b/tests/emu/openbsc_clone.c @@ -0,0 +1,216 @@ +/* (C) 2009-2010 by Harald Welte laforge@gnumonks.org + * + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation; either version 3 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + * + */ +#include "openbsc_clone.h" + +#include <gprs_debug.h> + +#include <osmocom/core/utils.h> + +#include <errno.h> + +/* Section 6.4 Commands and Responses */ +enum gprs_llc_u_cmd { + GPRS_LLC_U_DM_RESP = 0x01, + GPRS_LLC_U_DISC_CMD = 0x04, + GPRS_LLC_U_UA_RESP = 0x06, + GPRS_LLC_U_SABM_CMD = 0x07, + GPRS_LLC_U_FRMR_RESP = 0x08, + GPRS_LLC_U_XID = 0x0b, + GPRS_LLC_U_NULL_CMD = 0x00, +}; + +#define LLC_ALLOC_SIZE 16384 +#define UI_HDR_LEN 3 +#define N202 4 +#define CRC24_LENGTH 3 + +static const struct value_string llc_cmd_strs[] = { + { GPRS_LLC_NULL, "NULL" }, + { GPRS_LLC_RR, "RR" }, + { GPRS_LLC_ACK, "ACK" }, + { GPRS_LLC_RNR, "RNR" }, + { GPRS_LLC_SACK, "SACK" }, + { GPRS_LLC_DM, "DM" }, + { GPRS_LLC_DISC, "DISC" }, + { GPRS_LLC_UA, "UA" }, + { GPRS_LLC_SABM, "SABM" }, + { GPRS_LLC_FRMR, "FRMR" }, + { GPRS_LLC_XID, "XID" }, + { GPRS_LLC_UI, "UI" }, + { 0, NULL } +}; + +int gprs_llc_hdr_parse(struct gprs_llc_hdr_parsed *ghp, + const uint8_t *llc_hdr, int len) +{ + const uint8_t *ctrl = llc_hdr+1; + + if (len <= CRC24_LENGTH) + return -EIO; + + ghp->crc_length = len - CRC24_LENGTH; + + ghp->ack_req = 0; + + /* Section 5.5: FCS */ + ghp->fcs = *(llc_hdr + len - 3); + ghp->fcs |= *(llc_hdr + len - 2) << 8; + ghp->fcs |= *(llc_hdr + len - 1) << 16; + + /* Section 6.2.1: invalid PD field */ + if (llc_hdr[0] & 0x80) + return -EIO; + + /* This only works for the MS->SGSN direction */ + if (llc_hdr[0] & 0x40) + ghp->is_cmd = 0; + else + ghp->is_cmd = 1; + + ghp->sapi = llc_hdr[0] & 0xf; + + /* Section 6.2.3: check for reserved SAPI */ + switch (ghp->sapi) { + case 0: + case 4: + case 6: + case 0xa: + case 0xc: + case 0xd: + case 0xf: + return -EINVAL; + } + + if ((ctrl[0] & 0x80) == 0) { + /* I (Information transfer + Supervisory) format */ + uint8_t k; + + ghp->data = ctrl + 3; + + if (ctrl[0] & 0x40) + ghp->ack_req = 1; + + ghp->seq_tx = (ctrl[0] & 0x1f) << 4; + ghp->seq_tx |= (ctrl[1] >> 4); + + ghp->seq_rx = (ctrl[1] & 0x7) << 6; + ghp->seq_rx |= (ctrl[2] >> 2); + + switch (ctrl[2] & 0x03) { + case 0: + ghp->cmd = GPRS_LLC_RR; + break; + case 1: + ghp->cmd = GPRS_LLC_ACK; + break; + case 2: + ghp->cmd = GPRS_LLC_RNR; + break; + case 3: + ghp->cmd = GPRS_LLC_SACK; + k = ctrl[3] & 0x1f; + ghp->data += 1 + k; + break; + } + ghp->data_len = (llc_hdr + len - 3) - ghp->data; + } else if ((ctrl[0] & 0xc0) == 0x80) { + /* S (Supervisory) format */ + ghp->data = NULL; + ghp->data_len = 0; + + if (ctrl[0] & 0x20) + ghp->ack_req = 1; + ghp->seq_rx = (ctrl[0] & 0x7) << 6; + ghp->seq_rx |= (ctrl[1] >> 2); + + switch (ctrl[1] & 0x03) { + case 0: + ghp->cmd = GPRS_LLC_RR; + break; + case 1: + ghp->cmd = GPRS_LLC_ACK; + break; + case 2: + ghp->cmd = GPRS_LLC_RNR; + break; + case 3: + ghp->cmd = GPRS_LLC_SACK; + break; + } + } else if ((ctrl[0] & 0xe0) == 0xc0) { + /* UI (Unconfirmed Inforamtion) format */ + ghp->cmd = GPRS_LLC_UI; + ghp->data = ctrl + 2; + ghp->data_len = (llc_hdr + len - 3) - ghp->data; + + ghp->seq_tx = (ctrl[0] & 0x7) << 6; + ghp->seq_tx |= (ctrl[1] >> 2); + if (ctrl[1] & 0x02) { + ghp->is_encrypted = 1; + /* FIXME: encryption */ + } + if (ctrl[1] & 0x01) { + /* FCS over hdr + all inf fields */ + } else { + /* FCS over hdr + N202 octets (4) */ + if (ghp->crc_length > UI_HDR_LEN + N202) + ghp->crc_length = UI_HDR_LEN + N202; + } + } else { + /* U (Unnumbered) format: 1 1 1 P/F M4 M3 M2 M1 */ + ghp->data = NULL; + ghp->data_len = 0; + + switch (ctrl[0] & 0xf) { + case GPRS_LLC_U_NULL_CMD: + ghp->cmd = GPRS_LLC_NULL; + break; + case GPRS_LLC_U_DM_RESP: + ghp->cmd = GPRS_LLC_DM; + break; + case GPRS_LLC_U_DISC_CMD: + ghp->cmd = GPRS_LLC_DISC; + break; + case GPRS_LLC_U_UA_RESP: + ghp->cmd = GPRS_LLC_UA; + break; + case GPRS_LLC_U_SABM_CMD: + ghp->cmd = GPRS_LLC_SABM; + break; + case GPRS_LLC_U_FRMR_RESP: + ghp->cmd = GPRS_LLC_FRMR; + break; + case GPRS_LLC_U_XID: + ghp->cmd = GPRS_LLC_XID; + ghp->data = ctrl + 1; + ghp->data_len = (llc_hdr + len - 3) - ghp->data; + break; + default: + return -EIO; + } + } + + /* FIXME: parse sack frame */ + if (ghp->cmd == GPRS_LLC_SACK) { + LOGP(DPCU, LOGL_NOTICE, "Unsupported SACK frame\n"); + return -EIO; + } + + return 0; +} diff --git a/tests/emu/openbsc_clone.h b/tests/emu/openbsc_clone.h new file mode 100644 index 0000000..d62ff22 --- /dev/null +++ b/tests/emu/openbsc_clone.h @@ -0,0 +1,64 @@ +/* (C) 2009-2010 by Harald Welte laforge@gnumonks.org + * + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation; either version 3 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + * + */ +#ifndef OPENBSC_CLONE_H +#define OPENBSC_CLONE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stdint.h> + +enum gprs_llc_cmd { + GPRS_LLC_NULL, + GPRS_LLC_RR, + GPRS_LLC_ACK, + GPRS_LLC_RNR, + GPRS_LLC_SACK, + GPRS_LLC_DM, + GPRS_LLC_DISC, + GPRS_LLC_UA, + GPRS_LLC_SABM, + GPRS_LLC_FRMR, + GPRS_LLC_XID, + GPRS_LLC_UI, +}; + +struct gprs_llc_hdr_parsed { + uint8_t sapi; + uint8_t is_cmd:1, + ack_req:1, + is_encrypted:1; + uint32_t seq_rx; + uint32_t seq_tx; + uint32_t fcs; + uint32_t fcs_calc; + const uint8_t *data; + uint16_t data_len; + uint16_t crc_length; + enum gprs_llc_cmd cmd; +}; + +int gprs_llc_hdr_parse(struct gprs_llc_hdr_parsed *ghp, const uint8_t *llc_hdr, int len); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/tests/emu/pcu_emu.cpp b/tests/emu/pcu_emu.cpp index 337c0c8..f4d38cd 100644 --- a/tests/emu/pcu_emu.cpp +++ b/tests/emu/pcu_emu.cpp @@ -37,6 +37,7 @@ struct gprs_rlcmac_bts *gprs_rlcmac_bts; int16_t spoof_mnc = 0, spoof_mcc = 0;
extern void test_replay_gprs_attach(struct gprs_bssgp_pcu *pcu); +extern void test_replay_gprs_data(struct gprs_bssgp_pcu *, struct msgb *, struct tlv_parsed *);
struct gprs_rlcmac_bts *create_bts() { @@ -70,6 +71,11 @@ static void bvci_unblocked(struct gprs_bssgp_pcu *pcu) test_replay_gprs_attach(pcu); }
+static void bssgp_data(struct gprs_bssgp_pcu *pcu, struct msgb *msg, struct tlv_parsed *tp) +{ + test_replay_gprs_data(pcu, msg, tp); +} + void create_and_connect_bssgp(struct gprs_rlcmac_bts *bts, uint32_t sgsn_ip, uint16_t sgsn_port) { @@ -78,6 +84,7 @@ void create_and_connect_bssgp(struct gprs_rlcmac_bts *bts, pcu = gprs_bssgp_create_and_connect(bts, 0, sgsn_ip, sgsn_port, 20, 20, 20, 0x901, 0x99, 1, 0, 0); pcu->on_unblock_ack = bvci_unblocked; + pcu->on_dl_unit_data = bssgp_data; }
int main(int argc, char **argv) diff --git a/tests/emu/test_replay_gprs_attach.cpp b/tests/emu/test_replay_gprs_attach.cpp index 500b16e..fb1e77f 100644 --- a/tests/emu/test_replay_gprs_attach.cpp +++ b/tests/emu/test_replay_gprs_attach.cpp @@ -19,13 +19,18 @@
extern "C" { #include <osmocom/core/msgb.h> +#include <osmocom/core/backtrace.h> +#include <osmocom/gsm/gsm_utils.h> }
+#include "openbsc_clone.h" + #include <gprs_bssgp_pcu.h>
#include <stdint.h> #include <string.h>
+/* GPRS attach with a foreign TLLI */ static const uint8_t gprs_attach_llc[] = { /* LLC-PDU IE */ 0x0e, 0x00, 0x2e, @@ -38,6 +43,8 @@ static const uint8_t gprs_attach_llc[] = { 0x42, 0x00, 0x40, 0xaa, 0xf3, 0x18 };
+static int next_wanted_nu; + struct msgb *create_msg(const uint8_t *data, size_t len) { struct msgb *msg = msgb_alloc_headroom(4096, 128, "create msg"); @@ -51,6 +58,38 @@ void test_replay_gprs_attach(struct gprs_bssgp_pcu *pcu) uint32_t tlli = 0xadf11820; const uint8_t qos_profile[] = { 0x0, 0x0, 0x04 };
+ next_wanted_nu = 0; struct msgb *msg = create_msg(gprs_attach_llc, ARRAY_SIZE(gprs_attach_llc)); bssgp_tx_ul_ud(pcu->bctx, tlli, qos_profile, msg); } + +void test_replay_gprs_data(struct gprs_bssgp_pcu *pcu, struct msgb *msg, struct tlv_parsed *tp) +{ + struct bssgp_ud_hdr *budh; + struct gprs_llc_hdr_parsed ph; + uint32_t tlli; + + if (!TLVP_PRESENT(tp, BSSGP_IE_LLC_PDU)) + return; + + + gprs_llc_hdr_parse(&ph, TLVP_VAL(tp, BSSGP_IE_LLC_PDU), + TLVP_LEN(tp, BSSGP_IE_LLC_PDU)); + + budh = (struct bssgp_ud_hdr *)msgb_bssgph(msg); + tlli = ntohl(budh->tlli); + + /* all messages we should get, should be for a foreign tlli */ + OSMO_ASSERT(gprs_tlli_type(tlli) == TLLI_FOREIGN); + printf("TLLI(0x%08x) is foreign!\n", tlli); + + OSMO_ASSERT(ph.cmd == GPRS_LLC_UI); + OSMO_ASSERT(ph.sapi == 1); + OSMO_ASSERT(ph.seq_tx == next_wanted_nu++); + + /* this test just wants to see messages... no further data is sent */ + if (next_wanted_nu == 4) { + printf("Test done.\n"); + exit(EXIT_SUCCESS); + } +}
From: Holger Hans Peter Freyther holger@moiji-mobile.com
Introduce the concept of tests that will be ran one after the other. This new test will send static message that will lead to the opening of a PDP context. At this point one should use ping with a large packet size and suspend/stop the emulator. Once the NS connection is considered dead the SGSN will crash with a double free.
Reproduce: 0.) Add IMSI 901700000003094 to the ACL 1.) Stop/Suspend the emulation process so the NS Alive times out 2.) Use ping IP -s 2048
This will create a double free...
#4 0xb7bb2646 in talloc_abort_double_free () at talloc.c:175 #5 0xb7bbd41a in talloc_chunk_from_ptr (ptr=0x8091208) at talloc.c:190 #6 _talloc_free (ptr=0x8091208) at talloc.c:517 #7 talloc_free (ptr=ptr@entry=0x8091208) at talloc.c:990 #8 0xb7bb319b in msgb_free (m=m@entry=0x8091208) at msgb.c:72 #9 0x0804db54 in sndcp_send_ud_frag (fs=0xbfffcc6c) at gprs_sndcp.c:423 #10 sndcp_unitdata_req (msg=msg@entry=0x808eed8, lle=0x808fbc8, nsapi=5 '\005', mmcontext=mmcontext@entry=0x80903e8) at gprs_sndcp.c:471 --- tests/Makefile.am | 3 +- tests/emu/gprs_tests.h | 56 +++++++++++ tests/emu/openbsc_clone.c | 19 ++++ tests/emu/openbsc_clone.h | 32 +++++++ tests/emu/pcu_emu.cpp | 47 +++++++++- tests/emu/test_pdp_activation.cpp | 172 ++++++++++++++++++++++++++++++++++ tests/emu/test_replay_gprs_attach.cpp | 15 +-- 7 files changed, 330 insertions(+), 14 deletions(-) create mode 100644 tests/emu/gprs_tests.h create mode 100644 tests/emu/test_pdp_activation.cpp
diff --git a/tests/Makefile.am b/tests/Makefile.am index 0131e47..88be652 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -10,7 +10,8 @@ rlcmac_RLCMACTest_LDADD = \ $(COMMON_LA)
emu_pcu_emu_SOURCES = emu/pcu_emu.cpp emu/test_replay_gprs_attach.cpp \ - emu/openbsc_clone.c emu/openbsc_clone.h + emu/openbsc_clone.c emu/openbsc_clone.h emu/gprs_tests.h \ + emu/test_pdp_activation.cpp emu_pcu_emu_LDADD = \ $(top_builddir)/src/libgprs.la \ $(LIBOSMOGB_LIBS) \ diff --git a/tests/emu/gprs_tests.h b/tests/emu/gprs_tests.h new file mode 100644 index 0000000..eeb4f82 --- /dev/null +++ b/tests/emu/gprs_tests.h @@ -0,0 +1,56 @@ +/* (C) 2013 by Holger Hans Peter Freyther + * + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation; either version 3 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 Affero General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + * + */ + +#ifndef tests_h +#define tests_h + +#ifdef __cplusplus +extern "C" { +#endif + +#include <osmocom/core/msgb.h> +#include <string.h> + +struct gprs_bssgp_pcu; +struct tlv_parsed; +struct msgb; + +struct gprs_test { + const char *name; + const char *description; + void (*start)(struct gprs_bssgp_pcu *); + void (*data) (struct gprs_bssgp_pcu *, struct msgb *, struct tlv_parsed *); +}; + +void gprs_test_success(struct gprs_bssgp_pcu *); + +static inline struct msgb *create_msg(const uint8_t *data, size_t len) +{ + struct msgb *msg = msgb_alloc_headroom(4096, 128, "create msg"); + msg->l3h = msgb_put(msg, len); + memcpy(msg->l3h, data, len); + return msg; +} + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/tests/emu/openbsc_clone.c b/tests/emu/openbsc_clone.c index 707819b..b1052ff 100644 --- a/tests/emu/openbsc_clone.c +++ b/tests/emu/openbsc_clone.c @@ -21,6 +21,7 @@ #include <gprs_debug.h>
#include <osmocom/core/utils.h> +#include <osmocom/gsm/tlv.h>
#include <errno.h>
@@ -214,3 +215,21 @@ int gprs_llc_hdr_parse(struct gprs_llc_hdr_parsed *ghp,
return 0; } + +const struct tlv_definition gsm48_gmm_att_tlvdef = { + .def = { + [GSM48_IE_GMM_CIPH_CKSN] = { TLV_TYPE_FIXED, 1 }, + [GSM48_IE_GMM_TIMER_READY] = { TLV_TYPE_TV, 1 }, + [GSM48_IE_GMM_ALLOC_PTMSI] = { TLV_TYPE_TLV, 0 }, + [GSM48_IE_GMM_PTMSI_SIG] = { TLV_TYPE_FIXED, 3 }, + [GSM48_IE_GMM_AUTH_RAND] = { TLV_TYPE_FIXED, 16 }, + [GSM48_IE_GMM_AUTH_SRES] = { TLV_TYPE_FIXED, 4 }, + [GSM48_IE_GMM_IMEISV] = { TLV_TYPE_TLV, 0 }, + [GSM48_IE_GMM_DRX_PARAM] = { TLV_TYPE_FIXED, 2 }, + [GSM48_IE_GMM_MS_NET_CAPA] = { TLV_TYPE_TLV, 0 }, + [GSM48_IE_GMM_PDP_CTX_STATUS] = { TLV_TYPE_TLV, 0 }, + [GSM48_IE_GMM_PS_LCS_CAPA] = { TLV_TYPE_TLV, 0 }, + [GSM48_IE_GMM_GMM_MBMS_CTX_ST] = { TLV_TYPE_TLV, 0 }, + }, +}; + diff --git a/tests/emu/openbsc_clone.h b/tests/emu/openbsc_clone.h index d62ff22..b3cc033 100644 --- a/tests/emu/openbsc_clone.h +++ b/tests/emu/openbsc_clone.h @@ -23,6 +23,8 @@ extern "C" { #endif
+#include <osmocom/gsm/protocol/gsm_04_08.h> + #include <stdint.h>
enum gprs_llc_cmd { @@ -57,6 +59,36 @@ struct gprs_llc_hdr_parsed {
int gprs_llc_hdr_parse(struct gprs_llc_hdr_parsed *ghp, const uint8_t *llc_hdr, int len);
+/* Table 10.4 / 10.4a, GPRS Mobility Management (GMM) */ +#define GSM48_MT_GMM_ATTACH_ACK 0x02 + +/* Chapter 9.4.2 / Table 9.4.2 */ +struct gsm48_attach_ack { + uint8_t att_result:4, /* 10.5.5.7 */ + force_stby:4; /* 10.5.5.1 */ + uint8_t ra_upd_timer; /* 10.5.7.3 */ + uint8_t radio_prio; /* 10.5.7.2 */ + struct gsm48_ra_id ra_id; /* 10.5.5.15 */ + uint8_t data[0]; +} __attribute__((packed)); + +enum gsm48_gprs_ie_mm { + GSM48_IE_GMM_CIPH_CKSN = 0x08, /* 10.5.1.2 */ + GSM48_IE_GMM_TIMER_READY = 0x17, /* 10.5.7.3 */ + GSM48_IE_GMM_ALLOC_PTMSI = 0x18, /* 10.5.1.4 */ + GSM48_IE_GMM_PTMSI_SIG = 0x19, /* 10.5.5.8 */ + GSM48_IE_GMM_AUTH_RAND = 0x21, /* 10.5.3.1 */ + GSM48_IE_GMM_AUTH_SRES = 0x22, /* 10.5.3.2 */ + GSM48_IE_GMM_IMEISV = 0x23, /* 10.5.1.4 */ + GSM48_IE_GMM_DRX_PARAM = 0x27, /* 10.5.5.6 */ + GSM48_IE_GMM_MS_NET_CAPA = 0x31, /* 10.5.5.12 */ + GSM48_IE_GMM_PDP_CTX_STATUS = 0x32, /* 10.5.7.1 */ + GSM48_IE_GMM_PS_LCS_CAPA = 0x33, /* 10.5.5.22 */ + GSM48_IE_GMM_GMM_MBMS_CTX_ST = 0x35, /* 10.5.7.6 */ +}; + +extern const struct tlv_definition gsm48_gmm_att_tlvdef; + #ifdef __cplusplus } #endif diff --git a/tests/emu/pcu_emu.cpp b/tests/emu/pcu_emu.cpp index f4d38cd..4731a60 100644 --- a/tests/emu/pcu_emu.cpp +++ b/tests/emu/pcu_emu.cpp @@ -24,6 +24,9 @@ extern "C" { #include <pcu_vty.h> }
+#include "gprs_tests.h" + + #include <gprs_bssgp_pcu.h> #include <gprs_rlcmac.h>
@@ -31,6 +34,8 @@ extern "C" { #include <sys/types.h> #include <sys/socket.h>
+static int current_test; + /* Extern data to please the underlying code */ void *tall_pcu_ctx; struct gprs_rlcmac_bts *gprs_rlcmac_bts; @@ -39,6 +44,29 @@ int16_t spoof_mnc = 0, spoof_mcc = 0; extern void test_replay_gprs_attach(struct gprs_bssgp_pcu *pcu); extern void test_replay_gprs_data(struct gprs_bssgp_pcu *, struct msgb *, struct tlv_parsed *);
+extern void test_pdp_activation_start(struct gprs_bssgp_pcu *pcu); +extern void test_pdp_activation_data(struct gprs_bssgp_pcu *, struct msgb *, struct tlv_parsed*); + + +struct gprs_test all_tests[] = { + { + .name = "gprs_attach_with_tmsi", + .description = "A simple test that verifies that N(U) is " + "increasing across various messages. This makes " + "sure that no new LLE/LLME is created on the fly.", + .start = test_replay_gprs_attach, + .data = test_replay_gprs_data, + }, + { + .name = "gprs_full_attach_pdp_activation", + .description = "A simple test to do a GPRS attach and open a PDP " + "context. Then goes to sleep and waits for you to ping " + "the connection and hopefully re-produce a crash.", + .start = test_pdp_activation_start, + .data = test_pdp_activation_data, + }, +}; + struct gprs_rlcmac_bts *create_bts() { struct gprs_rlcmac_bts *bts; @@ -68,12 +96,12 @@ struct gprs_rlcmac_bts *create_bts() static void bvci_unblocked(struct gprs_bssgp_pcu *pcu) { printf("BVCI unblocked. We can begin with test cases.\n"); - test_replay_gprs_attach(pcu); + all_tests[current_test].start(pcu); }
static void bssgp_data(struct gprs_bssgp_pcu *pcu, struct msgb *msg, struct tlv_parsed *tp) { - test_replay_gprs_data(pcu, msg, tp); + all_tests[current_test].data(pcu, msg, tp); }
void create_and_connect_bssgp(struct gprs_rlcmac_bts *bts, @@ -112,6 +140,21 @@ int main(int argc, char **argv) return EXIT_SUCCESS; }
+ +/* + * Test handling.. + */ +void gprs_test_success(struct gprs_bssgp_pcu *pcu) +{ + current_test += 1; + if (current_test >= ARRAY_SIZE(all_tests)) { + printf("All tests executed.\n"); + exit(EXIT_SUCCESS); + } + + all_tests[current_test].start(pcu); +} + /* * stubs that should not be reached */ diff --git a/tests/emu/test_pdp_activation.cpp b/tests/emu/test_pdp_activation.cpp new file mode 100644 index 0000000..909b308 --- /dev/null +++ b/tests/emu/test_pdp_activation.cpp @@ -0,0 +1,172 @@ +/* (C) 2013 by Holger Hans Peter Freyther + * + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation; either version 3 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 Affero General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + * + */ + +extern "C" { +#include <osmocom/core/msgb.h> +#include <osmocom/core/backtrace.h> +#include <osmocom/gsm/gsm_utils.h> +} + +#include "openbsc_clone.h" +#include "gprs_tests.h" + +#include <gprs_bssgp_pcu.h> + +#include <stdint.h> +#include <string.h> + +static const uint8_t attach[] = { + 0x0e, 0x00, 0x26, + 0x01, 0xc0, 0x01, 0x08, 0x01, 0x02, 0xe5, 0x80, + 0x71, 0x0d, 0x01, 0x05, 0xf4, 0x02, 0x30, 0xef, + 0x0e, 0x09, 0xf1, 0x07, 0x00, 0x01, 0x00, 0x0b, + 0x34, 0xc7, 0x03, 0x2a, 0xa0, 0x42, 0x7c, 0xad, + 0xe1, 0x18, 0x0b, 0xf8, 0xef, 0xfc +}; + +static const uint8_t id_resp_imei[] = { + 0x0e, 0x00, 0x11, + 0x01, 0xc0, 0x05, 0x08, 0x16, 0x08, 0x3a, 0x49, + 0x50, 0x13, 0x28, 0x15, 0x80, 0x01, 0x21, 0x6c, + 0x22 +}; + +static const uint8_t id_resp_imsi[] = { + 0x0e, 0x00, 0x11, + 0x01, 0xc0, 0x09, 0x08, 0x16, 0x08, 0x99, 0x10, + 0x07, 0x00, 0x00, 0x00, 0x03, 0x49, 0xc7, 0x5b, + 0xb6 +}; + +static const uint8_t attach_complete[] = { + 0x0e, 0x00, 0x08, + 0x01, 0xc0, 0x0d, 0x08, 0x03, 0x55, 0x1c, 0xea +}; + +static const uint8_t pdp_context[] = { + 0x0e, 0x00, 0x5a, + 0x01, 0xc0, 0x11, 0x0a, 0x41, 0x05, 0x03, 0x0c, + 0x00, 0x00, 0x1f, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, 0x21, 0x28, + 0x12, 0x08, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, + 0x65, 0x74, 0x05, 0x65, 0x70, 0x6c, 0x75, 0x73, + 0x02, 0x64, 0x65, 0x27, 0x2a, 0x80, 0xc0, 0x23, + 0x13, 0x01, 0x00, 0x00, 0x13, 0x05, 0x65, 0x70, + 0x6c, 0x75, 0x73, 0x08, 0x69, 0x6e, 0x74, 0x65, + 0x72, 0x6e, 0x65, 0x74, 0x80, 0x21, 0x10, 0x01, + 0x00, 0x00, 0x10, 0x81, 0x06, 0x00, 0x00, 0x00, + 0x00, 0x83, 0x06, 0x00, 0x00, 0x00, 0x00, 0xcf, + 0x90, 0xcc +}; + +static const uint8_t qos_profile[] = { 0x0, 0x0, 0x04 }; +static uint32_t tlli = 0xadf11821; + +enum state { + Test_Start, + Test_IdRespIMEI, + Test_IdRespIMSI, + Test_AttachCompl, + Test_PDPAct, + Test_Done, +}; + +static enum state current_state = Test_Start; + +static void extract_tmsi_and_generate_tlli(struct msgb *msg, struct tlv_parsed *tp) +{ + uint32_t tmsi; + struct bssgp_ud_hdr *budh; + struct gprs_llc_hdr_parsed hp; + struct tlv_parsed ack_tp; + int rc; + + gprs_llc_hdr_parse(&hp, TLVP_VAL(tp, BSSGP_IE_LLC_PDU), + TLVP_LEN(tp, BSSGP_IE_LLC_PDU)); + msgb_gmmh(msg) = (unsigned char *) hp.data; + + struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg); + + OSMO_ASSERT(gh->msg_type == GSM48_MT_GMM_ATTACH_ACK); + struct gsm48_attach_ack *ack = (struct gsm48_attach_ack *) gh->data; + rc = tlv_parse(&ack_tp, &gsm48_gmm_att_tlvdef, ack->data, + (msg->data + msg->len) - ack->data, 0, 0); + + + OSMO_ASSERT(TLVP_PRESENT(&ack_tp, GSM48_IE_GMM_ALLOC_PTMSI)); + memcpy(&tmsi, TLVP_VAL(&ack_tp, GSM48_IE_GMM_ALLOC_PTMSI) + 1, 4); + tmsi = ntohl(tmsi); + tlli = gprs_tmsi2tlli(tmsi, TLLI_LOCAL); + printf("New TLLI(0x%08x) based on tmsi(0x%x)\n", tlli, tmsi); +} + +void test_pdp_activation_start(struct gprs_bssgp_pcu *pcu) +{ + struct msgb *msg = create_msg(attach, ARRAY_SIZE(attach)); + bssgp_tx_ul_ud(pcu->bctx, tlli, qos_profile, msg); + current_state = Test_IdRespIMEI; +} + + +void test_pdp_activation_data(struct gprs_bssgp_pcu *pcu, struct msgb *msg, struct tlv_parsed *tp) +{ + const uint8_t *data; + size_t len; + + switch (current_state) { + case Test_IdRespIMEI: + data = id_resp_imei; + len = ARRAY_SIZE(id_resp_imei); + current_state = Test_IdRespIMSI; + break; + case Test_IdRespIMSI: + data = id_resp_imsi; + len = ARRAY_SIZE(id_resp_imsi); + current_state = Test_AttachCompl; + break; + case Test_AttachCompl: + data = attach_complete; + len = ARRAY_SIZE(attach_complete); + extract_tmsi_and_generate_tlli(msg, tp); + current_state = Test_PDPAct; + break; + case Test_PDPAct: + printf("PDP context is active or not...\n"); + return; + break; + case Test_Done: + case Test_Start: /* fall through */ + return; + break; + default: + printf("Unknown state. %d\n", current_state); + return; + break; + }; + + struct msgb *out = create_msg(data, len); + bssgp_tx_ul_ud(pcu->bctx, tlli, qos_profile, out); + + /* send it after the PDP... */ + if (current_state == Test_PDPAct) { + out = create_msg(pdp_context, ARRAY_SIZE(pdp_context)); + bssgp_tx_ul_ud(pcu->bctx, tlli, qos_profile, out); + } +} + diff --git a/tests/emu/test_replay_gprs_attach.cpp b/tests/emu/test_replay_gprs_attach.cpp index fb1e77f..9bcab57 100644 --- a/tests/emu/test_replay_gprs_attach.cpp +++ b/tests/emu/test_replay_gprs_attach.cpp @@ -24,6 +24,7 @@ extern "C" { }
#include "openbsc_clone.h" +#include "gprs_tests.h"
#include <gprs_bssgp_pcu.h>
@@ -45,14 +46,6 @@ static const uint8_t gprs_attach_llc[] = {
static int next_wanted_nu;
-struct msgb *create_msg(const uint8_t *data, size_t len) -{ - struct msgb *msg = msgb_alloc_headroom(4096, 128, "create msg"); - msg->l3h = msgb_put(msg, len); - memcpy(msg->l3h, data, len); - return msg; -} - void test_replay_gprs_attach(struct gprs_bssgp_pcu *pcu) { uint32_t tlli = 0xadf11820; @@ -88,8 +81,8 @@ void test_replay_gprs_data(struct gprs_bssgp_pcu *pcu, struct msgb *msg, struct OSMO_ASSERT(ph.seq_tx == next_wanted_nu++);
/* this test just wants to see messages... no further data is sent */ - if (next_wanted_nu == 4) { - printf("Test done.\n"); - exit(EXIT_SUCCESS); + if (next_wanted_nu == 6) { + printf("GPRS attach with increasing N(U) done.\n"); + gprs_test_success(pcu); } }
Holger Freyther wrote:
.name = "gprs_attach_with_tmsi",
hi holger,
i tested your patches with my test environment. surfing via gprs works fine, except for some compiling error at pcu_emu.cpp:
emu/pcu_emu.cpp:53:3: error: expected primary-expression before '.' token
by now, i have no idea how to solve this.
regards,
andreas
On Fri, Aug 23, 2013 at 11:35:55AM +0200, Andreas Eversberg wrote:
Dear Andreas,
emu/pcu_emu.cpp:53:3: error: expected primary-expression before '.' token
which version of g++ are you using? which C++ standard is it using by default?
holger
Holger Hans Peter Freyther wrote:
which version of g++ are you using? which C++ standard is it using by default?
openbsc ~ # g++ -v Using built-in specs. COLLECT_GCC=/usr/i686-pc-linux-gnu/gcc-bin/4.5.4/g++ COLLECT_LTO_WRAPPER=/usr/libexec/gcc/i686-pc-linux-gnu/4.5.4/lto-wrapper Target: i686-pc-linux-gnu Configured with: /var/tmp/portage/sys-devel/gcc-4.5.4/work/gcc-4.5.4/configure --prefix=/usr --bindir=/usr/i686-pc-linux-gnu/gcc-bin/4.5.4 --includedir=/usr/lib/gcc/i686-pc-linux-gnu/4.5.4/include --datadir=/usr/share/gcc-data/i686-pc-linux-gnu/4.5.4 --mandir=/usr/share/gcc-data/i686-pc-linux-gnu/4.5.4/man --infodir=/usr/share/gcc-data/i686-pc-linux-gnu/4.5.4/info --with-gxx-include-dir=/usr/lib/gcc/i686-pc-linux-gnu/4.5.4/include/g++-v4 --host=i686-pc-linux-gnu --build=i686-pc-linux-gnu --disable-altivec --disable-fixed-point --without-ppl --without-cloog --disable-lto --enable-nls --without-included-gettext --with-system-zlib --enable-obsolete --disable-werror --enable-secureplt --disable-multilib --enable-libmudflap --disable-libssp --enable-libgomp --with-python-dir=/share/gcc-data/i686-pc-linux-gnu/4.5.4/python --enable-checking=release --disable-libgcj --with-arch=i686 --enable-languages=c,c++,fortran --enable-shared --enable-threads=posix --enable-__cxa_atexit --enable-clocale=gnu --enable-targets=all --with-bugurl=http://bugs.gentoo.org/ --with-pkgversion='Gentoo 4.5.4 p1.0, pie-0.4.7' Thread model: posix gcc version 4.5.4 (Gentoo 4.5.4 p1.0, pie-0.4.7)
how do i query the default C++ standard?
From: Holger Hans Peter Freyther holger@moiji-mobile.com
Introduce the concept of tests that will be ran one after the other. This new test will send static message that will lead to the opening of a PDP context. At this point one should use ping with a large packet size and suspend/stop the emulator. Once the NS connection is considered dead the SGSN will crash with a double free.
Reproduce: 0.) Add IMSI 901700000003094 to the ACL 1.) Stop/Suspend the emulation process so the NS Alive times out 2.) Use ping IP -s 2048
This will create a double free...
#4 0xb7bb2646 in talloc_abort_double_free () at talloc.c:175 #5 0xb7bbd41a in talloc_chunk_from_ptr (ptr=0x8091208) at talloc.c:190 #6 _talloc_free (ptr=0x8091208) at talloc.c:517 #7 talloc_free (ptr=ptr@entry=0x8091208) at talloc.c:990 #8 0xb7bb319b in msgb_free (m=m@entry=0x8091208) at msgb.c:72 #9 0x0804db54 in sndcp_send_ud_frag (fs=0xbfffcc6c) at gprs_sndcp.c:423 #10 sndcp_unitdata_req (msg=msg@entry=0x808eed8, lle=0x808fbc8, nsapi=5 '\005', mmcontext=mmcontext@entry=0x80903e8) at gprs_sndcp.c:471 --- tests/Makefile.am | 3 +- tests/emu/gprs_tests.h | 65 +++++++++++++ tests/emu/openbsc_clone.c | 18 ++++ tests/emu/openbsc_clone.h | 32 +++++++ tests/emu/pcu_emu.cpp | 42 ++++++++- tests/emu/test_pdp_activation.cpp | 171 ++++++++++++++++++++++++++++++++++ tests/emu/test_replay_gprs_attach.cpp | 15 +-- 7 files changed, 332 insertions(+), 14 deletions(-) create mode 100644 tests/emu/gprs_tests.h create mode 100644 tests/emu/test_pdp_activation.cpp
diff --git a/tests/Makefile.am b/tests/Makefile.am index 0131e47..88be652 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -10,7 +10,8 @@ rlcmac_RLCMACTest_LDADD = \ $(COMMON_LA)
emu_pcu_emu_SOURCES = emu/pcu_emu.cpp emu/test_replay_gprs_attach.cpp \ - emu/openbsc_clone.c emu/openbsc_clone.h + emu/openbsc_clone.c emu/openbsc_clone.h emu/gprs_tests.h \ + emu/test_pdp_activation.cpp emu_pcu_emu_LDADD = \ $(top_builddir)/src/libgprs.la \ $(LIBOSMOGB_LIBS) \ diff --git a/tests/emu/gprs_tests.h b/tests/emu/gprs_tests.h new file mode 100644 index 0000000..1f2c3fb --- /dev/null +++ b/tests/emu/gprs_tests.h @@ -0,0 +1,65 @@ +/* (C) 2013 by Holger Hans Peter Freyther + * + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation; either version 3 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 Affero General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + * + */ + +#ifndef tests_h +#define tests_h + +#ifdef __cplusplus +extern "C" { +#endif + +#include <osmocom/core/msgb.h> +#include <string.h> + +struct gprs_bssgp_pcu; +struct tlv_parsed; +struct msgb; + +struct gprs_test { + gprs_test(const char *name, const char *description, + void (*start)(struct gprs_bssgp_pcu *), + void (*data) (struct gprs_bssgp_pcu *, struct msgb *, struct tlv_parsed *parsed)) + : name(name) + , description(description) + , start(start) + , data(data) + {} + + const char *name; + const char *description; + void (*start)(struct gprs_bssgp_pcu *); + void (*data) (struct gprs_bssgp_pcu *, struct msgb *, struct tlv_parsed *); +}; + +void gprs_test_success(struct gprs_bssgp_pcu *); + +static inline struct msgb *create_msg(const uint8_t *data, size_t len) +{ + struct msgb *msg = msgb_alloc_headroom(4096, 128, "create msg"); + msg->l3h = msgb_put(msg, len); + memcpy(msg->l3h, data, len); + return msg; +} + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/tests/emu/openbsc_clone.c b/tests/emu/openbsc_clone.c index 707819b..575f4e1 100644 --- a/tests/emu/openbsc_clone.c +++ b/tests/emu/openbsc_clone.c @@ -21,6 +21,7 @@ #include <gprs_debug.h>
#include <osmocom/core/utils.h> +#include <osmocom/gsm/tlv.h>
#include <errno.h>
@@ -214,3 +215,20 @@ int gprs_llc_hdr_parse(struct gprs_llc_hdr_parsed *ghp,
return 0; } + +const struct tlv_definition gsm48_gmm_att_tlvdef = { + .def = { + [GSM48_IE_GMM_CIPH_CKSN] = { TLV_TYPE_FIXED, 1 }, + [GSM48_IE_GMM_TIMER_READY] = { TLV_TYPE_TV, 1 }, + [GSM48_IE_GMM_ALLOC_PTMSI] = { TLV_TYPE_TLV, 0 }, + [GSM48_IE_GMM_PTMSI_SIG] = { TLV_TYPE_FIXED, 3 }, + [GSM48_IE_GMM_AUTH_RAND] = { TLV_TYPE_FIXED, 16 }, + [GSM48_IE_GMM_AUTH_SRES] = { TLV_TYPE_FIXED, 4 }, + [GSM48_IE_GMM_IMEISV] = { TLV_TYPE_TLV, 0 }, + [GSM48_IE_GMM_DRX_PARAM] = { TLV_TYPE_FIXED, 2 }, + [GSM48_IE_GMM_MS_NET_CAPA] = { TLV_TYPE_TLV, 0 }, + [GSM48_IE_GMM_PDP_CTX_STATUS] = { TLV_TYPE_TLV, 0 }, + [GSM48_IE_GMM_PS_LCS_CAPA] = { TLV_TYPE_TLV, 0 }, + [GSM48_IE_GMM_GMM_MBMS_CTX_ST] = { TLV_TYPE_TLV, 0 }, + }, +}; diff --git a/tests/emu/openbsc_clone.h b/tests/emu/openbsc_clone.h index d62ff22..b3cc033 100644 --- a/tests/emu/openbsc_clone.h +++ b/tests/emu/openbsc_clone.h @@ -23,6 +23,8 @@ extern "C" { #endif
+#include <osmocom/gsm/protocol/gsm_04_08.h> + #include <stdint.h>
enum gprs_llc_cmd { @@ -57,6 +59,36 @@ struct gprs_llc_hdr_parsed {
int gprs_llc_hdr_parse(struct gprs_llc_hdr_parsed *ghp, const uint8_t *llc_hdr, int len);
+/* Table 10.4 / 10.4a, GPRS Mobility Management (GMM) */ +#define GSM48_MT_GMM_ATTACH_ACK 0x02 + +/* Chapter 9.4.2 / Table 9.4.2 */ +struct gsm48_attach_ack { + uint8_t att_result:4, /* 10.5.5.7 */ + force_stby:4; /* 10.5.5.1 */ + uint8_t ra_upd_timer; /* 10.5.7.3 */ + uint8_t radio_prio; /* 10.5.7.2 */ + struct gsm48_ra_id ra_id; /* 10.5.5.15 */ + uint8_t data[0]; +} __attribute__((packed)); + +enum gsm48_gprs_ie_mm { + GSM48_IE_GMM_CIPH_CKSN = 0x08, /* 10.5.1.2 */ + GSM48_IE_GMM_TIMER_READY = 0x17, /* 10.5.7.3 */ + GSM48_IE_GMM_ALLOC_PTMSI = 0x18, /* 10.5.1.4 */ + GSM48_IE_GMM_PTMSI_SIG = 0x19, /* 10.5.5.8 */ + GSM48_IE_GMM_AUTH_RAND = 0x21, /* 10.5.3.1 */ + GSM48_IE_GMM_AUTH_SRES = 0x22, /* 10.5.3.2 */ + GSM48_IE_GMM_IMEISV = 0x23, /* 10.5.1.4 */ + GSM48_IE_GMM_DRX_PARAM = 0x27, /* 10.5.5.6 */ + GSM48_IE_GMM_MS_NET_CAPA = 0x31, /* 10.5.5.12 */ + GSM48_IE_GMM_PDP_CTX_STATUS = 0x32, /* 10.5.7.1 */ + GSM48_IE_GMM_PS_LCS_CAPA = 0x33, /* 10.5.5.22 */ + GSM48_IE_GMM_GMM_MBMS_CTX_ST = 0x35, /* 10.5.7.6 */ +}; + +extern const struct tlv_definition gsm48_gmm_att_tlvdef; + #ifdef __cplusplus } #endif diff --git a/tests/emu/pcu_emu.cpp b/tests/emu/pcu_emu.cpp index f4d38cd..b68b856 100644 --- a/tests/emu/pcu_emu.cpp +++ b/tests/emu/pcu_emu.cpp @@ -24,6 +24,9 @@ extern "C" { #include <pcu_vty.h> }
+#include "gprs_tests.h" + + #include <gprs_bssgp_pcu.h> #include <gprs_rlcmac.h>
@@ -31,6 +34,8 @@ extern "C" { #include <sys/types.h> #include <sys/socket.h>
+static int current_test; + /* Extern data to please the underlying code */ void *tall_pcu_ctx; struct gprs_rlcmac_bts *gprs_rlcmac_bts; @@ -39,6 +44,24 @@ int16_t spoof_mnc = 0, spoof_mcc = 0; extern void test_replay_gprs_attach(struct gprs_bssgp_pcu *pcu); extern void test_replay_gprs_data(struct gprs_bssgp_pcu *, struct msgb *, struct tlv_parsed *);
+extern void test_pdp_activation_start(struct gprs_bssgp_pcu *pcu); +extern void test_pdp_activation_data(struct gprs_bssgp_pcu *, struct msgb *, struct tlv_parsed*); + +struct gprs_test all_tests[] = { + gprs_test("gprs_attach_with_tmsi", + "A simple test that verifies that N(U) is " + "increasing across various messages. This makes " + "sure that no new LLE/LLME is created on the fly.", + test_replay_gprs_attach, + test_replay_gprs_data), + gprs_test("gprs_full_attach_pdp_activation", + "A simple test to do a GPRS attach and open a PDP " + "context. Then goes to sleep and waits for you to ping " + "the connection and hopefully re-produce a crash.", + test_pdp_activation_start, + test_pdp_activation_data), +}; + struct gprs_rlcmac_bts *create_bts() { struct gprs_rlcmac_bts *bts; @@ -68,12 +91,12 @@ struct gprs_rlcmac_bts *create_bts() static void bvci_unblocked(struct gprs_bssgp_pcu *pcu) { printf("BVCI unblocked. We can begin with test cases.\n"); - test_replay_gprs_attach(pcu); + all_tests[current_test].start(pcu); }
static void bssgp_data(struct gprs_bssgp_pcu *pcu, struct msgb *msg, struct tlv_parsed *tp) { - test_replay_gprs_data(pcu, msg, tp); + all_tests[current_test].data(pcu, msg, tp); }
void create_and_connect_bssgp(struct gprs_rlcmac_bts *bts, @@ -112,6 +135,21 @@ int main(int argc, char **argv) return EXIT_SUCCESS; }
+ +/* + * Test handling.. + */ +void gprs_test_success(struct gprs_bssgp_pcu *pcu) +{ + current_test += 1; + if (current_test >= ARRAY_SIZE(all_tests)) { + printf("All tests executed.\n"); + exit(EXIT_SUCCESS); + } + + all_tests[current_test].start(pcu); +} + /* * stubs that should not be reached */ diff --git a/tests/emu/test_pdp_activation.cpp b/tests/emu/test_pdp_activation.cpp new file mode 100644 index 0000000..673874f --- /dev/null +++ b/tests/emu/test_pdp_activation.cpp @@ -0,0 +1,171 @@ +/* (C) 2013 by Holger Hans Peter Freyther + * + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation; either version 3 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 Affero General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + * + */ + +extern "C" { +#include <osmocom/core/msgb.h> +#include <osmocom/core/backtrace.h> +#include <osmocom/gsm/gsm_utils.h> +} + +#include "openbsc_clone.h" +#include "gprs_tests.h" + +#include <gprs_bssgp_pcu.h> + +#include <stdint.h> +#include <string.h> + +static const uint8_t attach[] = { + 0x0e, 0x00, 0x26, + 0x01, 0xc0, 0x01, 0x08, 0x01, 0x02, 0xe5, 0x80, + 0x71, 0x0d, 0x01, 0x05, 0xf4, 0x02, 0x30, 0xef, + 0x0e, 0x09, 0xf1, 0x07, 0x00, 0x01, 0x00, 0x0b, + 0x34, 0xc7, 0x03, 0x2a, 0xa0, 0x42, 0x7c, 0xad, + 0xe1, 0x18, 0x0b, 0xf8, 0xef, 0xfc +}; + +static const uint8_t id_resp_imei[] = { + 0x0e, 0x00, 0x11, + 0x01, 0xc0, 0x05, 0x08, 0x16, 0x08, 0x3a, 0x49, + 0x50, 0x13, 0x28, 0x15, 0x80, 0x01, 0x21, 0x6c, + 0x22 +}; + +static const uint8_t id_resp_imsi[] = { + 0x0e, 0x00, 0x11, + 0x01, 0xc0, 0x09, 0x08, 0x16, 0x08, 0x99, 0x10, + 0x07, 0x00, 0x00, 0x00, 0x03, 0x49, 0xc7, 0x5b, + 0xb6 +}; + +static const uint8_t attach_complete[] = { + 0x0e, 0x00, 0x08, + 0x01, 0xc0, 0x0d, 0x08, 0x03, 0x55, 0x1c, 0xea +}; + +static const uint8_t pdp_context[] = { + 0x0e, 0x00, 0x5a, + 0x01, 0xc0, 0x11, 0x0a, 0x41, 0x05, 0x03, 0x0c, + 0x00, 0x00, 0x1f, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, 0x21, 0x28, + 0x12, 0x08, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, + 0x65, 0x74, 0x05, 0x65, 0x70, 0x6c, 0x75, 0x73, + 0x02, 0x64, 0x65, 0x27, 0x2a, 0x80, 0xc0, 0x23, + 0x13, 0x01, 0x00, 0x00, 0x13, 0x05, 0x65, 0x70, + 0x6c, 0x75, 0x73, 0x08, 0x69, 0x6e, 0x74, 0x65, + 0x72, 0x6e, 0x65, 0x74, 0x80, 0x21, 0x10, 0x01, + 0x00, 0x00, 0x10, 0x81, 0x06, 0x00, 0x00, 0x00, + 0x00, 0x83, 0x06, 0x00, 0x00, 0x00, 0x00, 0xcf, + 0x90, 0xcc +}; + +static const uint8_t qos_profile[] = { 0x0, 0x0, 0x04 }; +static uint32_t tlli = 0xadf11821; + +enum state { + Test_Start, + Test_IdRespIMEI, + Test_IdRespIMSI, + Test_AttachCompl, + Test_PDPAct, + Test_Done, +}; + +static enum state current_state = Test_Start; + +static void extract_tmsi_and_generate_tlli(struct msgb *msg, struct tlv_parsed *tp) +{ + uint32_t tmsi; + struct bssgp_ud_hdr *budh; + struct gprs_llc_hdr_parsed hp; + struct tlv_parsed ack_tp; + int rc; + + gprs_llc_hdr_parse(&hp, TLVP_VAL(tp, BSSGP_IE_LLC_PDU), + TLVP_LEN(tp, BSSGP_IE_LLC_PDU)); + msgb_gmmh(msg) = (unsigned char *) hp.data; + + struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg); + + OSMO_ASSERT(gh->msg_type == GSM48_MT_GMM_ATTACH_ACK); + struct gsm48_attach_ack *ack = (struct gsm48_attach_ack *) gh->data; + rc = tlv_parse(&ack_tp, &gsm48_gmm_att_tlvdef, ack->data, + (msg->data + msg->len) - ack->data, 0, 0); + + + OSMO_ASSERT(TLVP_PRESENT(&ack_tp, GSM48_IE_GMM_ALLOC_PTMSI)); + memcpy(&tmsi, TLVP_VAL(&ack_tp, GSM48_IE_GMM_ALLOC_PTMSI) + 1, 4); + tmsi = ntohl(tmsi); + tlli = gprs_tmsi2tlli(tmsi, TLLI_LOCAL); + printf("New TLLI(0x%08x) based on tmsi(0x%x)\n", tlli, tmsi); +} + +void test_pdp_activation_start(struct gprs_bssgp_pcu *pcu) +{ + struct msgb *msg = create_msg(attach, ARRAY_SIZE(attach)); + bssgp_tx_ul_ud(pcu->bctx, tlli, qos_profile, msg); + current_state = Test_IdRespIMEI; +} + + +void test_pdp_activation_data(struct gprs_bssgp_pcu *pcu, struct msgb *msg, struct tlv_parsed *tp) +{ + const uint8_t *data; + size_t len; + + switch (current_state) { + case Test_IdRespIMEI: + data = id_resp_imei; + len = ARRAY_SIZE(id_resp_imei); + current_state = Test_IdRespIMSI; + break; + case Test_IdRespIMSI: + data = id_resp_imsi; + len = ARRAY_SIZE(id_resp_imsi); + current_state = Test_AttachCompl; + break; + case Test_AttachCompl: + data = attach_complete; + len = ARRAY_SIZE(attach_complete); + extract_tmsi_and_generate_tlli(msg, tp); + current_state = Test_PDPAct; + break; + case Test_PDPAct: + printf("PDP context is active or not...\n"); + return; + break; + case Test_Done: + case Test_Start: /* fall through */ + return; + break; + default: + printf("Unknown state. %d\n", current_state); + return; + break; + }; + + struct msgb *out = create_msg(data, len); + bssgp_tx_ul_ud(pcu->bctx, tlli, qos_profile, out); + + /* send it after the PDP... */ + if (current_state == Test_PDPAct) { + out = create_msg(pdp_context, ARRAY_SIZE(pdp_context)); + bssgp_tx_ul_ud(pcu->bctx, tlli, qos_profile, out); + } +} diff --git a/tests/emu/test_replay_gprs_attach.cpp b/tests/emu/test_replay_gprs_attach.cpp index fb1e77f..9bcab57 100644 --- a/tests/emu/test_replay_gprs_attach.cpp +++ b/tests/emu/test_replay_gprs_attach.cpp @@ -24,6 +24,7 @@ extern "C" { }
#include "openbsc_clone.h" +#include "gprs_tests.h"
#include <gprs_bssgp_pcu.h>
@@ -45,14 +46,6 @@ static const uint8_t gprs_attach_llc[] = {
static int next_wanted_nu;
-struct msgb *create_msg(const uint8_t *data, size_t len) -{ - struct msgb *msg = msgb_alloc_headroom(4096, 128, "create msg"); - msg->l3h = msgb_put(msg, len); - memcpy(msg->l3h, data, len); - return msg; -} - void test_replay_gprs_attach(struct gprs_bssgp_pcu *pcu) { uint32_t tlli = 0xadf11820; @@ -88,8 +81,8 @@ void test_replay_gprs_data(struct gprs_bssgp_pcu *pcu, struct msgb *msg, struct OSMO_ASSERT(ph.seq_tx == next_wanted_nu++);
/* this test just wants to see messages... no further data is sent */ - if (next_wanted_nu == 4) { - printf("Test done.\n"); - exit(EXIT_SUCCESS); + if (next_wanted_nu == 6) { + printf("GPRS attach with increasing N(U) done.\n"); + gprs_test_success(pcu); } }
On Thu, Aug 22, 2013 at 09:16:55AM +0200, Holger Freyther wrote:
From: Holger Hans Peter Freyther holger@moiji-mobile.com
ping? Ivan, any feedback on these patches?
Hi Holger,
Sorry for delay, I plan to test and review all these patches on Monday, after that I will merge them.
2013/8/30 Holger Hans Peter Freyther hfreyther@sysmocom.de:
On Thu, Aug 22, 2013 at 09:16:55AM +0200, Holger Freyther wrote:
From: Holger Hans Peter Freyther holger@moiji-mobile.com
ping? Ivan, any feedback on these patches?
--
- Holger Freyther hfreyther@sysmocom.de http://www.sysmocom.de/
=======================================================================
- sysmocom - systems for mobile communications GmbH
- Schivelbeiner Str. 5
- 10439 Berlin, Germany
- Sitz / Registered office: Berlin, HRB 134158 B
- Geschaeftsfuehrer / Managing Directors: Holger Freyther, Harald Welte
Hi Holger,
I tested and merged these patches to master.
2013/8/30 Ivan Kluchnikov Ivan.Kluchnikov@fairwaves.ru:
Hi Holger,
Sorry for delay, I plan to test and review all these patches on Monday, after that I will merge them.
2013/8/30 Holger Hans Peter Freyther hfreyther@sysmocom.de:
On Thu, Aug 22, 2013 at 09:16:55AM +0200, Holger Freyther wrote:
From: Holger Hans Peter Freyther holger@moiji-mobile.com
ping? Ivan, any feedback on these patches?
--
- Holger Freyther hfreyther@sysmocom.de http://www.sysmocom.de/
=======================================================================
- sysmocom - systems for mobile communications GmbH
- Schivelbeiner Str. 5
- 10439 Berlin, Germany
- Sitz / Registered office: Berlin, HRB 134158 B
- Geschaeftsfuehrer / Managing Directors: Holger Freyther, Harald Welte
-- Regards, Ivan Kluchnikov. http://fairwaves.ru
osmocom-net-gprs@lists.osmocom.org