From cc6313cc697f4c90cf0fc1c5b01cb1871a075f26 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Fri, 26 Mar 2010 22:04:03 +0800 Subject: logging: fix default initialization of per-category loglevels Before this patch, there was a bug in the code caused by a memcpy from one data structure to another. unfortuantely the data structures were not the same, so we have to explicitly iterate over the array and assign the structure members manually. --- src/logging.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/logging.c b/src/logging.c index 508ccfd3e..2a132eb5a 100644 --- a/src/logging.c +++ b/src/logging.c @@ -311,16 +311,26 @@ static void _stderr_output(struct log_target *target, const char *log) struct log_target *log_target_create(void) { struct log_target *target; + unsigned int i; target = talloc_zero(tall_log_ctx, struct log_target); if (!target) return NULL; INIT_LLIST_HEAD(&target->entry); - memcpy(target->categories, log_info->cat, - sizeof(struct log_category)*log_info->num_cat); + + /* initialize the per-category enabled/loglevel from defaults */ + for (i = 0; i < log_info->num_cat; i++) { + struct log_category *cat = &target->categories[i]; + cat->enabled = log_info->cat[i].enabled; + cat->loglevel = log_info->cat[i].loglevel; + } + + /* global settings */ target->use_color = 1; target->print_timestamp = 0; + + /* global log level */ target->loglevel = 0; return target; } -- cgit v1.2.3 From 01fd5cb3f0da802ca82d3b6aef46d2a3d8e6c15c Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Fri, 26 Mar 2010 23:51:31 +0800 Subject: only include strings.h if it is actually preent --- src/logging.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/logging.c b/src/logging.c index 2a132eb5a..ea03d3033 100644 --- a/src/logging.c +++ b/src/logging.c @@ -20,11 +20,16 @@ * */ +#include "../config.h" + #include #include #include #include + +#ifdef HAVE_STRINGS_H #include +#endif #include #include -- cgit v1.2.3 From a3b844cf45dc4d6a6a3686e8ce6e2447643b878e Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 27 Mar 2010 00:04:40 +0800 Subject: logging: only compile stderr target if we actualy have stderr --- src/logging.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/logging.c b/src/logging.c index ea03d3033..7c508771f 100644 --- a/src/logging.c +++ b/src/logging.c @@ -307,11 +307,14 @@ void log_set_category_filter(struct log_target *target, int category, target->categories[category].loglevel = level; } +/* since C89/C99 says stderr is a macro, we can safely do this! */ +#ifdef stderr static void _stderr_output(struct log_target *target, const char *log) { fprintf(target->tgt_stdout.out, "%s", log); fflush(target->tgt_stdout.out); } +#endif struct log_target *log_target_create(void) { @@ -342,6 +345,8 @@ struct log_target *log_target_create(void) struct log_target *log_target_create_stderr(void) { +/* since C89/C99 says stderr is a macro, we can safely do this! */ +#ifdef stderr struct log_target *target; target = log_target_create(); @@ -351,6 +356,9 @@ struct log_target *log_target_create_stderr(void) target->tgt_stdout.out = stderr; target->output = _stderr_output; return target; +#else + return NULL; +#endif /* stderr */ } void log_init(const struct log_info *cat) -- cgit v1.2.3 From 9bb553ee40104c47f9a27d7662eb2867dd2b5d1e Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 28 Mar 2010 18:14:50 +0800 Subject: import gsm48_mi_to_string() from OpenBSC --- include/osmocore/gsm48.h | 4 ++++ src/gsm48.c | 43 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/include/osmocore/gsm48.h b/include/osmocore/gsm48.h index 1e963573c..b752ee00e 100644 --- a/include/osmocore/gsm48.h +++ b/include/osmocore/gsm48.h @@ -14,4 +14,8 @@ void gsm48_generate_lai(struct gsm48_loc_area_id *lai48, uint16_t mcc, int gsm48_generate_mid_from_tmsi(uint8_t *buf, uint32_t tmsi); int gsm48_generate_mid_from_imsi(uint8_t *buf, const char *imsi); +/* Convert Mobile Identity (10.5.1.4) to string */ +int gsm48_mi_to_string(char *string, const int str_len, + const u_int8_t *mi, const int mi_len); + #endif diff --git a/src/gsm48.c b/src/gsm48.c index 5761c67b4..d024109b7 100644 --- a/src/gsm48.c +++ b/src/gsm48.c @@ -261,3 +261,46 @@ int gsm48_generate_mid_from_imsi(uint8_t *buf, const char *imsi) return 2 + buf[1]; } + +/* Convert Mobile Identity (10.5.1.4) to string */ +int gsm48_mi_to_string(char *string, const int str_len, const u_int8_t *mi, const int mi_len) +{ + int i; + u_int8_t mi_type; + char *str_cur = string; + u_int32_t tmsi; + + mi_type = mi[0] & GSM_MI_TYPE_MASK; + + switch (mi_type) { + case GSM_MI_TYPE_NONE: + break; + case GSM_MI_TYPE_TMSI: + /* Table 10.5.4.3, reverse generate_mid_from_tmsi */ + if (mi_len == GSM48_TMSI_LEN && mi[0] == (0xf0 | GSM_MI_TYPE_TMSI)) { + memcpy(&tmsi, &mi[1], 4); + tmsi = ntohl(tmsi); + return snprintf(string, str_len, "%u", tmsi); + } + break; + case GSM_MI_TYPE_IMSI: + case GSM_MI_TYPE_IMEI: + case GSM_MI_TYPE_IMEISV: + *str_cur++ = bcd2char(mi[0] >> 4); + + for (i = 1; i < mi_len; i++) { + if (str_cur + 2 >= string + str_len) + return str_cur - string; + *str_cur++ = bcd2char(mi[i] & 0xf); + /* skip last nibble in last input byte when GSM_EVEN */ + if( (i != mi_len-1) || (mi[0] & GSM_MI_ODD)) + *str_cur++ = bcd2char(mi[i] >> 4); + } + break; + default: + break; + } + *str_cur++ = '\0'; + + return str_cur - string; +} -- cgit v1.2.3 From 19bab73d7903d0718979aca1463503fcc185166b Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Fri, 20 Nov 2009 15:14:01 +0100 Subject: [rsl] Speculative crash fix in the RSL rcv message The theory is that the BTS is almost dead and sends out a incomplete message and we crash with that. I have not been able to completely verify that. --- openbsc/src/abis_rsl.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c index 0e572ccce..0e385c18c 100644 --- a/openbsc/src/abis_rsl.c +++ b/openbsc/src/abis_rsl.c @@ -1652,9 +1652,21 @@ static int abis_rsl_rx_ipacc(struct msgb *msg) /* Entry-point where L2 RSL from BTS enters */ int abis_rsl_rcvmsg(struct msgb *msg) { - struct abis_rsl_common_hdr *rslh = msgb_l2(msg) ; + struct abis_rsl_common_hdr *rslh; int rc = 0; + if (!msg) { + DEBUGP(DRSL, "Empty RSL msg?..\n"); + return -1; + } + + if (msgb_l2len(msg) < sizeof(*rslh)) { + DEBUGP(DRSL, "Truncated RSL message with l2len: %u\n", msgb_l2len(msg)); + return -1; + } + + rslh = msgb_l2(msg); + switch (rslh->msg_discr & 0xfe) { case ABIS_RSL_MDISC_RLL: rc = abis_rsl_rx_rll(msg); -- cgit v1.2.3 From 6c8c0ddbe21c45f16ed996a9cb38b0fb3b9bc66f Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Sun, 4 Apr 2010 18:12:37 +0200 Subject: [ipa] When including MGCP our messages might be bigger than 300 byte The length field of the IPA header allows to have 16bit numbers and I just ran into the 300 byte limit with MGCP messages. Make it three times the size and see how long this is going to be enough. --- openbsc/src/input/ipaccess.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openbsc/src/input/ipaccess.c b/openbsc/src/input/ipaccess.c index 323540f48..2449e261d 100644 --- a/openbsc/src/input/ipaccess.c +++ b/openbsc/src/input/ipaccess.c @@ -57,7 +57,7 @@ struct ia_e1_handle { static struct ia_e1_handle *e1h; -#define TS1_ALLOC_SIZE 300 +#define TS1_ALLOC_SIZE 900 static const u_int8_t pong[] = { 0, 1, IPAC_PROTO_IPACCESS, IPAC_MSGT_PONG }; static const u_int8_t id_ack[] = { 0, 1, IPAC_PROTO_IPACCESS, IPAC_MSGT_ID_ACK }; -- cgit v1.2.3 From d4e7888ae3b3b5d195b75fe317d97bfd3606e4cb Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Wed, 27 Jan 2010 09:10:05 +0100 Subject: [paging] Increase the time used to send paging messages to the BTS Send a Paging Request to the BTS every two seconds. This way it is unlikely that a phone will try to respond to two paging requests as it is currently happening. --- openbsc/src/paging.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openbsc/src/paging.c b/openbsc/src/paging.c index 7c3750d66..9c978bee6 100644 --- a/openbsc/src/paging.c +++ b/openbsc/src/paging.c @@ -160,7 +160,7 @@ static void paging_handle_pending_requests(struct gsm_bts_paging_state *paging_b } while (paging_bts->available_slots > 0 && initial_request != current_request); - bsc_schedule_timer(&paging_bts->work_timer, 1, 0); + bsc_schedule_timer(&paging_bts->work_timer, 2, 0); } static void paging_worker(void *data) @@ -245,7 +245,7 @@ static int _paging_request(struct gsm_bts *bts, struct gsm_subscriber *subscr, llist_add_tail(&req->entry, &bts_entry->pending_requests); if (!bsc_timer_pending(&bts_entry->work_timer)) - bsc_schedule_timer(&bts_entry->work_timer, 1, 0); + bsc_schedule_timer(&bts_entry->work_timer, 2, 0); return 0; } -- cgit v1.2.3 From 4052c811a9b205908f041b5eabe698850cd2048e Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Thu, 8 Apr 2010 10:58:20 +0200 Subject: write_queue: Add callback for exceptions as well. --- include/osmocore/write_queue.h | 1 + src/write_queue.c | 3 +++ 2 files changed, 4 insertions(+) diff --git a/include/osmocore/write_queue.h b/include/osmocore/write_queue.h index 64d4159a0..ef244c32a 100644 --- a/include/osmocore/write_queue.h +++ b/include/osmocore/write_queue.h @@ -35,6 +35,7 @@ struct write_queue { int (*read_cb)(struct bsc_fd *fd); int (*write_cb)(struct bsc_fd *fd, struct msgb *msg); + int (*except_cb)(struct bsc_fd *fd); }; void write_queue_init(struct write_queue *queue, int max_length); diff --git a/src/write_queue.c b/src/write_queue.c index a0ac2d6fd..618a8c0b3 100644 --- a/src/write_queue.c +++ b/src/write_queue.c @@ -32,6 +32,9 @@ int write_queue_bfd_cb(struct bsc_fd *fd, unsigned int what) if (what & BSC_FD_READ) queue->read_cb(fd); + if (what & BSC_FD_EXCEPT) + queue->except_cb(fd); + if (what & BSC_FD_WRITE) { struct msgb *msg; -- cgit v1.2.3 From 07d838a3bf866692f15d6d3bbc17e91451ace216 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Thu, 8 Apr 2010 16:48:46 +0200 Subject: [paging] Do not use request after it was was destroyed.. Increment the counter before we call the remove request which is freeing the request... --- openbsc/src/paging.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openbsc/src/paging.c b/openbsc/src/paging.c index 9c978bee6..3d16a21fb 100644 --- a/openbsc/src/paging.c +++ b/openbsc/src/paging.c @@ -208,11 +208,11 @@ static void paging_T3113_expired(void *data) sig_data.lchan = NULL; /* must be destroyed before calling cbfn, to prevent double free */ + counter_inc(req->bts->network->stats.paging.expired); cbfn_param = req->cbfn_param; cbfn = req->cbfn; paging_remove_request(&req->bts->paging, req); - counter_inc(req->bts->network->stats.paging.expired); dispatch_signal(SS_PAGING, S_PAGING_EXPIRED, &sig_data); if (cbfn) -- cgit v1.2.3 From b1ac2b96f85969f3a1e9d37aa421a25313c5e0f8 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Fri, 9 Apr 2010 07:50:18 +0200 Subject: gsm48-ie.c: Fix year in copyright message --- src/gsm48_ie.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gsm48_ie.c b/src/gsm48_ie.c index 4ca5fb800..3c2a1f7b6 100644 --- a/src/gsm48_ie.c +++ b/src/gsm48_ie.c @@ -2,7 +2,7 @@ * 3GPP TS 04.08 version 7.21.0 Release 1998 / ETSI TS 100 940 V7.21.0 */ /* (C) 2008 by Harald Welte - * (C) 2008-2010 by Andreas Eversberg + * (C) 2009-2010 by Andreas Eversberg * * All Rights Reserved * -- cgit v1.2.3 From 1ef041ff1e390adcd0f97075f1ed52177b7ed3e0 Mon Sep 17 00:00:00 2001 From: Andreas Eversberg Date: Fri, 9 Apr 2010 07:52:12 +0200 Subject: gsm48: introduce MM_CONNECTION_PEND state --- include/osmocore/protocol/gsm_04_08.h | 1 + src/gsm48.c | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/include/osmocore/protocol/gsm_04_08.h b/include/osmocore/protocol/gsm_04_08.h index 801b9b54c..47b98b292 100644 --- a/include/osmocore/protocol/gsm_04_08.h +++ b/include/osmocore/protocol/gsm_04_08.h @@ -685,6 +685,7 @@ enum chreq_type { /* Chapter 5.1.2.2 */ #define GSM_CSTATE_NULL 0 #define GSM_CSTATE_INITIATED 1 +#define GSM_CSTATE_MM_CONNECTION_PEND 2 /* see 10.5.4.6 */ #define GSM_CSTATE_MO_CALL_PROC 3 #define GSM_CSTATE_CALL_DELIVERED 4 #define GSM_CSTATE_CALL_PRESENT 6 diff --git a/src/gsm48.c b/src/gsm48.c index d024109b7..e0cba15e7 100644 --- a/src/gsm48.c +++ b/src/gsm48.c @@ -97,10 +97,10 @@ static const struct value_string rr_cause_names[] = { }; /* FIXME: convert to value_string */ -static const char *cc_state_names[32] = { +static const char *cc_state_names[33] = { "NULL", "INITIATED", - "illegal state 2", + "MM_CONNECTION_PEND", "MO_CALL_PROC", "CALL_DELIVERED", "illegal state 5", -- cgit v1.2.3 From 163d0ea85b99a2c581b1f861bf9445a9a14bfc6f Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Fri, 9 Apr 2010 07:57:40 +0200 Subject: remove references to u_int*_t and use uint*_t instead --- include/osmocore/gsm48.h | 2 +- src/gsm48.c | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/include/osmocore/gsm48.h b/include/osmocore/gsm48.h index b752ee00e..e3a1defa7 100644 --- a/include/osmocore/gsm48.h +++ b/include/osmocore/gsm48.h @@ -16,6 +16,6 @@ int gsm48_generate_mid_from_imsi(uint8_t *buf, const char *imsi); /* Convert Mobile Identity (10.5.1.4) to string */ int gsm48_mi_to_string(char *string, const int str_len, - const u_int8_t *mi, const int mi_len); + const uint8_t *mi, const int mi_len); #endif diff --git a/src/gsm48.c b/src/gsm48.c index e0cba15e7..783ff6a5d 100644 --- a/src/gsm48.c +++ b/src/gsm48.c @@ -263,12 +263,13 @@ int gsm48_generate_mid_from_imsi(uint8_t *buf, const char *imsi) } /* Convert Mobile Identity (10.5.1.4) to string */ -int gsm48_mi_to_string(char *string, const int str_len, const u_int8_t *mi, const int mi_len) +int gsm48_mi_to_string(char *string, const int str_len, const uint8_t *mi, + const int mi_len) { int i; - u_int8_t mi_type; + uint8_t mi_type; char *str_cur = string; - u_int32_t tmsi; + uint32_t tmsi; mi_type = mi[0] & GSM_MI_TYPE_MASK; -- cgit v1.2.3 From 19722d44116353c14de8cb1f09eb45b9f8ec8ae2 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Fri, 9 Apr 2010 18:38:06 +0200 Subject: paging: Avoid integer underflow on ipaccess On the nanoBTS we do not receive any load indication for the paging channel and we just decrement our available slots and the unsigned int wraps to the maximum value. Together with a not yet understood bug this makes us go amock. For the nanoBTS and even the Siemens BS11 resetting the load to 20 after two seconds should be just fine. For the nanoBTS we would need to reset the 20 a lot more earlier but we need to take a look at how often we run low. --- openbsc/src/paging.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/openbsc/src/paging.c b/openbsc/src/paging.c index 3d16a21fb..2ae3fc6bf 100644 --- a/openbsc/src/paging.c +++ b/openbsc/src/paging.c @@ -133,6 +133,20 @@ static void paging_handle_pending_requests(struct gsm_bts_paging_state *paging_b return; } + /* + * In case the BTS does not provide us with load indication just fill + * up our slots for this round. We should be able to page 20 subscribers + * every two seconds. So we will just give the BTS some extra credit. + * We will have to see how often we run out of this credit, so we might + * need a low watermark and then add credit or give 20 every run when + * the bts sets an option for that. + */ + if (paging_bts->available_slots == 0) { + LOGP(DPAG, LOGL_NOTICE, "No slots available on bts nr %d\n", + paging_bts->bts->nr); + paging_bts->available_slots = 20; + } + if (!paging_bts->last_request) paging_bts->last_request = (struct gsm_paging_request *)paging_bts->pending_requests.next; -- cgit v1.2.3 From 754e801826207fb0c5ff490bbd8c36eb134aae5e Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Fri, 9 Apr 2010 21:53:35 +0200 Subject: [paging] Simplify the last request and treat llist as a queue The current code was overly complex. It tried to iterate over the list in a round robin and we had to keep track of the last element, see if we remove that one, check if the list becomes empty... This can all replaced by treating the double linked list as a queue. We take the item at the front, do something on it and then and then put it back to the list at the end. --- openbsc/include/openbsc/gsm_data.h | 1 - openbsc/src/paging.c | 43 ++++++++------------------------------ 2 files changed, 9 insertions(+), 35 deletions(-) diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index 8dfa5886b..ef0b50768 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -368,7 +368,6 @@ struct gsm_paging_request { struct gsm_bts_paging_state { /* pending requests */ struct llist_head pending_requests; - struct gsm_paging_request *last_request; struct gsm_bts *bts; struct timer_list work_timer; diff --git a/openbsc/src/paging.c b/openbsc/src/paging.c index 2ae3fc6bf..ece71ca7f 100644 --- a/openbsc/src/paging.c +++ b/openbsc/src/paging.c @@ -70,14 +70,6 @@ static unsigned int calculate_group(struct gsm_bts *bts, struct gsm_subscriber * static void paging_remove_request(struct gsm_bts_paging_state *paging_bts, struct gsm_paging_request *to_be_deleted) { - /* Update the last_request if that is necessary */ - if (to_be_deleted == paging_bts->last_request) { - paging_bts->last_request = - (struct gsm_paging_request *)paging_bts->last_request->entry.next; - if (&to_be_deleted->entry == &paging_bts->pending_requests) - paging_bts->last_request = NULL; - } - bsc_del_timer(&to_be_deleted->T3113); llist_del(&to_be_deleted->entry); subscr_put(to_be_deleted->subscr); @@ -103,14 +95,6 @@ static void page_ms(struct gsm_paging_request *request) request->chan_type); } -static void paging_move_to_next(struct gsm_bts_paging_state *paging_bts) -{ - paging_bts->last_request = - (struct gsm_paging_request *)paging_bts->last_request->entry.next; - if (&paging_bts->last_request->entry == &paging_bts->pending_requests) - paging_bts->last_request = NULL; -} - /* * This is kicked by the periodic PAGING LOAD Indicator * coming from abis_rsl.c @@ -128,7 +112,6 @@ static void paging_handle_pending_requests(struct gsm_bts_paging_state *paging_b * return then. */ if (llist_empty(&paging_bts->pending_requests)) { - paging_bts->last_request = NULL; /* since the list is empty, no need to reschedule the timer */ return; } @@ -147,12 +130,8 @@ static void paging_handle_pending_requests(struct gsm_bts_paging_state *paging_b paging_bts->available_slots = 20; } - if (!paging_bts->last_request) - paging_bts->last_request = - (struct gsm_paging_request *)paging_bts->pending_requests.next; - - assert(paging_bts->last_request); - initial_request = paging_bts->last_request; + initial_request = llist_entry(paging_bts->pending_requests.next, + struct gsm_paging_request, entry); current_request = initial_request; do { @@ -160,17 +139,13 @@ static void paging_handle_pending_requests(struct gsm_bts_paging_state *paging_b page_ms(current_request); paging_bts->available_slots--; - /* - * move to the next item. We might wrap around - * this means last_request will be NULL and we just - * call paging_page_to_next again. It it guranteed - * that the list is not empty. - */ - paging_move_to_next(paging_bts); - if (!paging_bts->last_request) - paging_bts->last_request = - (struct gsm_paging_request *)paging_bts->pending_requests.next; - current_request = paging_bts->last_request; + /* take the current and add it to the back */ + llist_del(¤t_request->entry); + llist_add_tail(¤t_request->entry, &paging_bts->pending_requests); + + /* take the next request */ + current_request = llist_entry(paging_bts->pending_requests.next, + struct gsm_paging_request, entry); } while (paging_bts->available_slots > 0 && initial_request != current_request); -- cgit v1.2.3 From c50b83654030732416dda8dc8053efcdc3a8480c Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Fri, 9 Apr 2010 22:02:39 +0200 Subject: [paging] Move code to use LOGP and print some more information --- openbsc/src/paging.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/openbsc/src/paging.c b/openbsc/src/paging.c index ece71ca7f..e0cb5313d 100644 --- a/openbsc/src/paging.c +++ b/openbsc/src/paging.c @@ -82,7 +82,7 @@ static void page_ms(struct gsm_paging_request *request) unsigned int mi_len; unsigned int page_group; - DEBUGP(DPAG, "Going to send paging commands: imsi: '%s' tmsi: '0x%x'\n", + LOGP(DPAG, LOGL_INFO, "Going to send paging commands: imsi: '%s' tmsi: '0x%x'\n", request->subscr->imsi, request->subscr->tmsi); if (request->subscr->tmsi == GSM_RESERVED_TMSI) @@ -189,7 +189,7 @@ static void paging_T3113_expired(void *data) void *cbfn_param; gsm_cbfn *cbfn; - DEBUGP(DPAG, "T3113 expired for request %p (%s)\n", + LOGP(DPAG, LOGL_INFO, "T3113 expired for request %p (%s)\n", req, req->subscr->imsi); sig_data.subscr = req->subscr; @@ -216,11 +216,11 @@ static int _paging_request(struct gsm_bts *bts, struct gsm_subscriber *subscr, struct gsm_paging_request *req; if (paging_pending_request(bts_entry, subscr)) { - DEBUGP(DPAG, "Paging request already pending\n"); + LOGP(DPAG, LOGL_INFO, "Paging request already pending for %s\n", subscr->imsi); return -EEXIST; } - DEBUGP(DPAG, "Start paging of subscriber %llu on bts %d.\n", + LOGP(DPAG, LOGL_DEBUG, "Start paging of subscriber %llu on bts %d.\n", subscr->id, bts->nr); req = talloc_zero(tall_paging_ctx, struct gsm_paging_request); req->subscr = subscr_get(subscr); @@ -285,11 +285,11 @@ static void _paging_request_stop(struct gsm_bts *bts, struct gsm_subscriber *sub entry) { if (req->subscr == subscr) { if (lchan && req->cbfn) { - DEBUGP(DPAG, "Stop paging on bts %d, calling cbfn.\n", bts->nr); + LOGP(DPAG, LOGL_DEBUG, "Stop paging on bts %d, calling cbfn.\n", bts->nr); req->cbfn(GSM_HOOK_RR_PAGING, GSM_PAGING_SUCCEEDED, NULL, lchan, req->cbfn_param); } else - DEBUGP(DPAG, "Stop paging on bts %d silently.\n", bts->nr); + LOGP(DPAG, LOGL_DEBUG, "Stop paging on bts %d silently.\n", bts->nr); paging_remove_request(&bts->paging, req); break; } -- cgit v1.2.3 From 1469600b0dcde77eaa4322b480b677fdf03e9cd0 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Fri, 9 Apr 2010 22:55:55 +0200 Subject: [paging] Start with a smaller paging limit... The value 20 is just a random number and it really depends on the number of TRX on a bts to be a sane or insane limit. --- openbsc/src/paging.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openbsc/src/paging.c b/openbsc/src/paging.c index e0cb5313d..9a4f3657b 100644 --- a/openbsc/src/paging.c +++ b/openbsc/src/paging.c @@ -167,7 +167,7 @@ void paging_init(struct gsm_bts *bts) bts->paging.work_timer.data = &bts->paging; /* Large number, until we get a proper message */ - bts->paging.available_slots = 100; + bts->paging.available_slots = 20; } static int paging_pending_request(struct gsm_bts_paging_state *bts, -- cgit v1.2.3 From ae80f9291a8d6d4824ece720b9fecf9d669b116d Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Sat, 10 Apr 2010 00:05:16 +0200 Subject: Return anything from append_lsa_params. --- openbsc/src/rest_octets.c | 1 + 1 file changed, 1 insertion(+) diff --git a/openbsc/src/rest_octets.c b/openbsc/src/rest_octets.c index 16996cec2..df27cf21e 100644 --- a/openbsc/src/rest_octets.c +++ b/openbsc/src/rest_octets.c @@ -133,6 +133,7 @@ static int append_lsa_params(struct bitvec *bv, const struct gsm48_lsa_params *lsa_params) { /* FIXME */ + return -1; } /* Generate SI4 Rest Octets (Chapter 10.5.2.35) */ -- cgit v1.2.3 From ef8117883b425995d5c05cecd47de4b454641e5b Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Sat, 10 Apr 2010 00:06:17 +0200 Subject: [paging] Include chan_alloc.h to silence a compiler warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit paging.c:259: warning: implicit declaration of function ‘trx_is_usable’ --- openbsc/src/paging.c | 1 + 1 file changed, 1 insertion(+) diff --git a/openbsc/src/paging.c b/openbsc/src/paging.c index 9a4f3657b..314d3d135 100644 --- a/openbsc/src/paging.c +++ b/openbsc/src/paging.c @@ -45,6 +45,7 @@ #include #include #include +#include void *tall_paging_ctx; -- cgit v1.2.3 From e1ffc08f724c678dc76b6c7a36dda280f065db47 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Sat, 10 Apr 2010 00:08:28 +0200 Subject: [vty] Forward declare the extra init function the base is calling --- openbsc/src/vty_interface.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c index b5bdbc8c2..480b65836 100644 --- a/openbsc/src/vty_interface.c +++ b/openbsc/src/vty_interface.c @@ -1740,6 +1740,8 @@ DEFUN(cfg_ts_e1_subslot, return CMD_SUCCESS; } +extern int bsc_vty_init_extra(struct gsm_network *net); + int bsc_vty_init(struct gsm_network *net) { gsmnet = net; -- cgit v1.2.3 From 07ba16fe03594827e659b07fa25fb5c5c942422d Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Sat, 10 Apr 2010 00:08:59 +0200 Subject: [vty] Remove unused variables due them only being used in the layer3 I moved the extra code to the layer3 VTY implementation but didn't remove the variables while doign so, silent compiler warnings. --- openbsc/src/vty_interface.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c index 480b65836..f74a041b6 100644 --- a/openbsc/src/vty_interface.c +++ b/openbsc/src/vty_interface.c @@ -540,10 +540,6 @@ DEFUN(show_ts, static void subscr_dump_vty(struct vty *vty, struct gsm_subscriber *subscr) { - int rc; - struct gsm_auth_info ainfo; - struct gsm_auth_tuple atuple; - vty_out(vty, " ID: %llu, Authorized: %d%s", subscr->id, subscr->authorized, VTY_NEWLINE); if (subscr->name) -- cgit v1.2.3 From ccfd57264786a513b81429d7d7064e216c4461af Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Fri, 9 Apr 2010 13:06:56 +0200 Subject: [rsl] Remove method that is not called by anything. --- openbsc/include/openbsc/abis_rsl.h | 1 - 1 file changed, 1 deletion(-) diff --git a/openbsc/include/openbsc/abis_rsl.h b/openbsc/include/openbsc/abis_rsl.h index e6973eef0..ac0a17978 100644 --- a/openbsc/include/openbsc/abis_rsl.h +++ b/openbsc/include/openbsc/abis_rsl.h @@ -73,7 +73,6 @@ int rsl_release_request(struct gsm_lchan *lchan, u_int8_t link_id); /* to be provided by external code */ int abis_rsl_sendmsg(struct msgb *msg); int rsl_deact_sacch(struct gsm_lchan *lchan); -int rsl_chan_release(struct gsm_lchan *lchan); /* BCCH related code */ int rsl_ccch_conf_to_bs_cc_chans(int ccch_conf); -- cgit v1.2.3 From 74419497fccc93ef5acf6bc0d64f683c8bf25617 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Sat, 10 Apr 2010 00:12:31 +0200 Subject: [rsl] Introduce a method to set the state of the lchan Setting the state through a dedicated method allows us to track the state transitions and check if they are done in a proper way. --- openbsc/include/openbsc/abis_rsl.h | 2 ++ openbsc/src/abis_rsl.c | 18 ++++++++++++------ openbsc/src/handover_logic.c | 2 +- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/openbsc/include/openbsc/abis_rsl.h b/openbsc/include/openbsc/abis_rsl.h index ac0a17978..8e6774d15 100644 --- a/openbsc/include/openbsc/abis_rsl.h +++ b/openbsc/include/openbsc/abis_rsl.h @@ -70,6 +70,8 @@ u_int64_t str_to_imsi(const char *imsi_str); u_int8_t lchan2chan_nr(const struct gsm_lchan *lchan); int rsl_release_request(struct gsm_lchan *lchan, u_int8_t link_id); +int rsl_lchan_set_state(struct gsm_lchan *lchan, int); + /* to be provided by external code */ int abis_rsl_sendmsg(struct msgb *msg); int rsl_deact_sacch(struct gsm_lchan *lchan); diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c index 0e385c18c..9cf34b497 100644 --- a/openbsc/src/abis_rsl.c +++ b/openbsc/src/abis_rsl.c @@ -727,7 +727,7 @@ int rsl_release_request(struct gsm_lchan *lchan, u_int8_t link_id) link_id, 0); msgb_tv_put(msg, RSL_IE_RELEASE_MODE, 0); /* normal release */ - lchan->state = LCHAN_S_REL_REQ; + rsl_lchan_set_state(lchan, LCHAN_S_REL_REQ); /* FIXME: start some timer in case we don't receive a REL ACK ? */ msg->trx = lchan->ts->trx; @@ -735,6 +735,12 @@ int rsl_release_request(struct gsm_lchan *lchan, u_int8_t link_id) return abis_rsl_sendmsg(msg); } +int rsl_lchan_set_state(struct gsm_lchan *lchan, int state) +{ + lchan->state = state; + return 0; +} + /* Chapter 8.4.2: Channel Activate Acknowledge */ static int rsl_rx_chan_act_ack(struct msgb *msg) { @@ -749,7 +755,7 @@ static int rsl_rx_chan_act_ack(struct msgb *msg) LOGP(DRSL, LOGL_NOTICE, "%s CHAN ACT ACK, but state %s\n", gsm_lchan_name(msg->lchan), gsm_lchans_name(msg->lchan->state)); - msg->lchan->state = LCHAN_S_ACTIVE; + rsl_lchan_set_state(msg->lchan, LCHAN_S_ACTIVE); dispatch_signal(SS_LCHAN, S_LCHAN_ACTIVATE_ACK, msg->lchan); @@ -775,9 +781,9 @@ static int rsl_rx_chan_act_nack(struct msgb *msg) print_rsl_cause(LOGL_ERROR, cause, TLVP_LEN(&tp, RSL_IE_CAUSE)); if (*cause != RSL_ERR_RCH_ALR_ACTV_ALLOC) - msg->lchan->state = LCHAN_S_NONE; + rsl_lchan_set_state(msg->lchan, LCHAN_S_NONE); } else - msg->lchan->state = LCHAN_S_NONE; + rsl_lchan_set_state(msg->lchan, LCHAN_S_NONE); LOGPC(DRSL, LOGL_ERROR, "\n"); @@ -981,7 +987,7 @@ static int abis_rsl_rx_dchan(struct msgb *msg) LOGP(DRSL, LOGL_NOTICE, "%s CHAN REL ACK but state %s\n", gsm_lchan_name(msg->lchan), gsm_lchans_name(msg->lchan->state)); - msg->lchan->state = LCHAN_S_NONE; + rsl_lchan_set_state(msg->lchan, LCHAN_S_NONE); lchan_free(msg->lchan); break; case RSL_MT_MODE_MODIFY_ACK: @@ -1124,7 +1130,7 @@ static int rsl_rx_chan_rqd(struct msgb *msg) LOGP(DRSL, LOGL_NOTICE, "%s lchan_alloc() returned channel " "in state %s\n", gsm_lchan_name(lchan), gsm_lchans_name(lchan->state)); - lchan->state = LCHAN_S_ACT_REQ; + rsl_lchan_set_state(lchan, LCHAN_S_ACT_REQ); ts_number = lchan->ts->nr; arfcn = lchan->ts->trx->arfcn; diff --git a/openbsc/src/handover_logic.c b/openbsc/src/handover_logic.c index 7fb0b13e1..7352d6464 100644 --- a/openbsc/src/handover_logic.c +++ b/openbsc/src/handover_logic.c @@ -229,7 +229,7 @@ static int ho_gsm48_ho_compl(struct gsm_lchan *new_lchan) /* update lchan pointer of transaction */ trans_lchan_change(&ho->old_lchan->conn, &new_lchan->conn); - ho->old_lchan->state = LCHAN_S_INACTIVE; + rsl_lchan_set_state(ho->old_lchan, LCHAN_S_INACTIVE); lchan_auto_release(ho->old_lchan); /* do something to re-route the actual speech frames ! */ -- cgit v1.2.3 From 63d18b51a7fe76e05a0a3167205c5d61205fca98 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Sat, 10 Apr 2010 00:14:55 +0200 Subject: [rsl] Set the release state from within the lchan class Currently our GSM04.11 code is closing the link for SAPI=3 and this would mean that the whole channel would be scheduled for close... where we only want to close everything when freeing the lchan or handling an error. --- openbsc/src/abis_rsl.c | 1 - openbsc/src/chan_alloc.c | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c index 9cf34b497..ba1be99c8 100644 --- a/openbsc/src/abis_rsl.c +++ b/openbsc/src/abis_rsl.c @@ -727,7 +727,6 @@ int rsl_release_request(struct gsm_lchan *lchan, u_int8_t link_id) link_id, 0); msgb_tv_put(msg, RSL_IE_RELEASE_MODE, 0); /* normal release */ - rsl_lchan_set_state(lchan, LCHAN_S_REL_REQ); /* FIXME: start some timer in case we don't receive a REL ACK ? */ msg->trx = lchan->ts->trx; diff --git a/openbsc/src/chan_alloc.c b/openbsc/src/chan_alloc.c index cd48e4359..118deca10 100644 --- a/openbsc/src/chan_alloc.c +++ b/openbsc/src/chan_alloc.c @@ -348,6 +348,7 @@ int lchan_auto_release(struct gsm_lchan *lchan) lchan->conn.use_count); DEBUGP(DRLL, "%s Recycling Channel\n", gsm_lchan_name(lchan)); + rsl_lchan_set_state(lchan, LCHAN_S_REL_REQ); rsl_release_request(lchan, 0); return 1; } -- cgit v1.2.3 From 5eec9d91d85edc7aac5c326f30d67036513c2dcf Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Sat, 10 Apr 2010 00:16:04 +0200 Subject: [rsl] Set the right state when asking for the activation. Set the state to activation to avoid a warning about the getting a CHAN ACK without waiting for it. We set it in the code to make sure it is set after all error checking to avoid inconsistent state as the state is only set back to NONE/ACT due replies from the BTS. --- openbsc/src/handover_logic.c | 1 + 1 file changed, 1 insertion(+) diff --git a/openbsc/src/handover_logic.c b/openbsc/src/handover_logic.c index 7352d6464..b2ffe4616 100644 --- a/openbsc/src/handover_logic.c +++ b/openbsc/src/handover_logic.c @@ -134,6 +134,7 @@ int bsc_handover_start(struct gsm_lchan *old_lchan, struct gsm_bts *bts) return rc; } + rsl_lchan_set_state(new_lchan, LCHAN_S_ACT_REQ); llist_add(&ho->list, &bsc_handovers); /* we continue in the SS_LCHAN handler / ho_chan_activ_ack */ -- cgit v1.2.3 From 63cb447fd509954d5c32d3cf17a9f45d8ff0203e Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Sun, 11 Apr 2010 10:10:04 +0200 Subject: Revert "ipa: Reduce the throttling of the IPA msges" Reducing the throttling to this value created a regression with bringing up RSL on the nanoBTS 900. We do seem to have a bug/issue in the bsc_init code and might send a command too early without this longer wait period and then the state transition does not happen. For now it is agreed that reverting is the best thing to do. Debugged-by: Sylvain Munaut <246tnt@gmail.com> This reverts commit f5284ae1cf8babc1567b33f469e20a66a73fcd9e. --- openbsc/src/input/ipaccess.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/openbsc/src/input/ipaccess.c b/openbsc/src/input/ipaccess.c index 2449e261d..8722791bc 100644 --- a/openbsc/src/input/ipaccess.c +++ b/openbsc/src/input/ipaccess.c @@ -475,7 +475,9 @@ static int handle_ts1_write(struct bsc_fd *bfd) /* set tx delay timer for next event */ e1i_ts->sign.tx_timer.cb = timeout_ts1_write; e1i_ts->sign.tx_timer.data = e1i_ts; - bsc_schedule_timer(&e1i_ts->sign.tx_timer, 0, 100); + + /* Reducing this might break the nanoBTS 900 init. */ + bsc_schedule_timer(&e1i_ts->sign.tx_timer, 0, 100000); return ret; } -- cgit v1.2.3 From 23ba4747d17a0d89aa3c0b661a102f01216427fd Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Sun, 11 Apr 2010 17:33:19 +0200 Subject: select.c: Make the ugly hacker uglier... Right now I'm seeing crashes when removing a link and deleting it and I need this hack to make it not crash. We will have to understand if llist_for_each_entry_safe has a bug or if we are doing something bad with the list (anchors not properly initialized). --- src/select.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/select.c b/src/select.c index 9517778ce..2f6afa7f5 100644 --- a/src/select.c +++ b/src/select.c @@ -121,7 +121,8 @@ restart: /* ugly, ugly hack. If more than one filedescriptors were * unregistered, they might have been consecutive and * llist_for_each_entry_safe() is no longer safe */ - if (unregistered_count > 1) + /* this seems to happen with the last element of the list as well */ + if (unregistered_count >= 1) goto restart; } return work; -- cgit v1.2.3 From b998d7b219d66ab3e89e263aa345856e0bf97cbb Mon Sep 17 00:00:00 2001 From: Sylvain Munaut Date: Sun, 25 Oct 2009 17:48:42 +0100 Subject: abis_nm: Fix ACTIVATE SW parameters The previous code only sent the FILE_ID tag data part, but according to the GSM 12.21 spec, section 8.3.6, the full SW Description 'object' must be sent so that includes the NM_ATT_SW_DESCR tag, the whole FILE_ID and the whole FILE_VERSION (including tags & length fields). Note that functionnaly on a nanoBTS 139 I couldn't see any difference ... whatever I send in there it works ... Signed-off-by: Sylvain Munaut --- openbsc/src/abis_nm.c | 61 +++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 49 insertions(+), 12 deletions(-) diff --git a/openbsc/src/abis_nm.c b/openbsc/src/abis_nm.c index 5e6e8196c..c78ee5699 100644 --- a/openbsc/src/abis_nm.c +++ b/openbsc/src/abis_nm.c @@ -822,15 +822,56 @@ static int ipacc_sw_activate(struct gsm_bts *bts, u_int8_t obj_class, u_int8_t i return abis_nm_sendmsg(bts, msg); } +static int abis_nm_parse_sw_descr(const u_int8_t *sw_descr, int sw_descr_len) +{ + static const struct tlv_definition sw_descr_def = { + .def = { + [NM_ATT_FILE_ID] = { TLV_TYPE_TL16V, }, + [NM_ATT_FILE_VERSION] = { TLV_TYPE_TL16V, }, + }, + }; + + u_int8_t tag; + u_int16_t tag_len; + const u_int8_t *val; + int ofs = 0, len; + + /* Classic TLV parsing doesn't work well with SW_DESCR because of it's + * nested nature and the fact you have to assume it contains only two sub + * tags NM_ATT_FILE_VERSION & NM_ATT_FILE_ID to parse it */ + + if (sw_descr[0] != NM_ATT_SW_DESCR) { + DEBUGP(DNM, "SW_DESCR attribute identifier not found!\n"); + return -1; + } + ofs += 1; + + len = tlv_parse_one(&tag, &tag_len, &val, + &sw_descr_def, &sw_descr[ofs], sw_descr_len-ofs); + if (len < 0 || (tag != NM_ATT_FILE_ID)) { + DEBUGP(DNM, "FILE_ID attribute identifier not found!\n"); + return -2; + } + ofs += len; + + len = tlv_parse_one(&tag, &tag_len, &val, + &sw_descr_def, &sw_descr[ofs], sw_descr_len-ofs); + if (len < 0 || (tag != NM_ATT_FILE_VERSION)) { + DEBUGP(DNM, "FILE_VERSION attribute identifier not found!\n"); + return -3; + } + ofs += len; + + return ofs; +} + static int abis_nm_rx_sw_act_req(struct msgb *mb) { struct abis_om_hdr *oh = msgb_l2(mb); struct abis_om_fom_hdr *foh = msgb_l3(mb); struct tlv_parsed tp; const u_int8_t *sw_config; - int sw_config_len; - int file_id_len; - int ret; + int ret, sw_config_len, sw_descr_len; debugp_foh(foh); @@ -854,20 +895,16 @@ static int abis_nm_rx_sw_act_req(struct msgb *mb) DEBUGP(DNM, "Found SW config: %s\n", hexdump(sw_config, sw_config_len)); } - if (sw_config[0] != NM_ATT_SW_DESCR) - DEBUGP(DNM, "SW_DESCR attribute identifier not found!\n"); - if (sw_config[1] != NM_ATT_FILE_ID) - DEBUGP(DNM, "FILE_ID attribute identifier not found!\n"); - file_id_len = sw_config[2] * 256 + sw_config[3]; + /* Use the first SW_DESCR present in SW config */ + sw_descr_len = abis_nm_parse_sw_descr(sw_config, sw_config_len); + if (sw_descr_len < 0) + return -EINVAL; - /* Assumes first SW file in list is the one to be activated */ - /* sw_config + 4 to skip over 2 attribute ID bytes and 16-bit length field */ return ipacc_sw_activate(mb->trx->bts, foh->obj_class, foh->obj_inst.bts_nr, foh->obj_inst.trx_nr, foh->obj_inst.ts_nr, - sw_config + 4, - file_id_len); + sw_config, sw_descr_len); } /* Receive a CHANGE_ADM_STATE_ACK, parse the TLV and update local state */ -- cgit v1.2.3 From b54dda4cefe89665d98074cf3767858fa6ecdb6e Mon Sep 17 00:00:00 2001 From: Sylvain Munaut Date: Sun, 20 Dec 2009 22:06:40 +0100 Subject: ipaccess: Send RTP Payload IE for CRCX & MDCX For GSM V1 FR, the payload type is fixed to 3 in the RFC. But for the other codecs, the payload type is dynamically assigned between 96 and 127. Here, we use a static mapping internal to OpenBSC. This patch is needed to make a rather old 139 unit (with sw version 120a002_v149b42d0) work with something else than FR codec. I also tested this patch on a newer 139 (with sw version 120a352_v267b22d0) to make sure it didn't add a regression. More testing with newer EDGE units should be done by whoever has some of theses. Signed-off-by: Sylvain Munaut --- openbsc/include/openbsc/gsm_data.h | 1 + openbsc/include/openbsc/rtp_proxy.h | 6 +++++ openbsc/src/abis_rsl.c | 54 +++++++++++++++++++++++++++++++++---- openbsc/src/rtp_proxy.c | 3 --- 4 files changed, 56 insertions(+), 8 deletions(-) diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index ef0b50768..68d3deebf 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -250,6 +250,7 @@ struct gsm_lchan { u_int16_t bound_port; u_int16_t connect_port; u_int16_t conn_id; + u_int8_t rtp_payload; u_int8_t rtp_payload2; u_int8_t speech_mode; struct rtp_socket *rtp_socket; diff --git a/openbsc/include/openbsc/rtp_proxy.h b/openbsc/include/openbsc/rtp_proxy.h index f82711a8e..65b1a5fac 100644 --- a/openbsc/include/openbsc/rtp_proxy.h +++ b/openbsc/include/openbsc/rtp_proxy.h @@ -28,6 +28,12 @@ #include #include +#define RTP_PT_GSM_FULL 3 +#define RTP_PT_GSM_HALF 96 +#define RTP_PT_GSM_EFR 97 +#define RTP_PT_AMR_FULL 98 +#define RTP_PT_AMR_HALF 99 + enum rtp_rx_action { RTP_NONE, RTP_PROXY, diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c index ba1be99c8..343347aa5 100644 --- a/openbsc/src/abis_rsl.c +++ b/openbsc/src/abis_rsl.c @@ -1368,6 +1368,44 @@ static u_int8_t ipa_smod_s_for_lchan(struct gsm_lchan *lchan) return 0; } +static u_int8_t ipa_rtp_pt_for_lchan(struct gsm_lchan *lchan) +{ + switch (lchan->tch_mode) { + case GSM48_CMODE_SPEECH_V1: + switch (lchan->type) { + case GSM_LCHAN_TCH_F: + return RTP_PT_GSM_FULL; + case GSM_LCHAN_TCH_H: + return RTP_PT_GSM_HALF; + default: + break; + } + case GSM48_CMODE_SPEECH_EFR: + switch (lchan->type) { + case GSM_LCHAN_TCH_F: + return RTP_PT_GSM_EFR; + /* there's no half-rate EFR */ + default: + break; + } + case GSM48_CMODE_SPEECH_AMR: + switch (lchan->type) { + case GSM_LCHAN_TCH_F: + return RTP_PT_AMR_FULL; + case GSM_LCHAN_TCH_H: + return RTP_PT_AMR_HALF; + default: + break; + } + default: + break; + } + LOGP(DRSL, LOGL_ERROR, "Cannot determine ip.access rtp payload type for " + "tch_mode == 0x%02x\n & lchan_type == %d", + lchan->tch_mode, lchan->type); + return 0; +} + /* ip.access specific RSL extensions */ static void ipac_parse_rtp(struct gsm_lchan *lchan, struct tlv_parsed *tv) { @@ -1434,10 +1472,13 @@ int rsl_ipacc_crcx(struct gsm_lchan *lchan) /* 0x1- == receive-only, 0x-1 == EFR codec */ lchan->abis_ip.speech_mode = 0x10 | ipa_smod_s_for_lchan(lchan); + lchan->abis_ip.rtp_payload = ipa_rtp_pt_for_lchan(lchan); msgb_tv_put(msg, RSL_IE_IPAC_SPEECH_MODE, lchan->abis_ip.speech_mode); + msgb_tv_put(msg, RSL_IE_IPAC_RTP_PAYLOAD, lchan->abis_ip.rtp_payload); - DEBUGP(DRSL, "%s IPAC_BIND speech_mode=0x%02x\n", - gsm_lchan_name(lchan), lchan->abis_ip.speech_mode); + DEBUGP(DRSL, "%s IPAC_BIND speech_mode=0x%02x RTP_PAYLOAD=%d\n", + gsm_lchan_name(lchan), lchan->abis_ip.speech_mode, + lchan->abis_ip.rtp_payload); msg->trx = lchan->ts->trx; @@ -1464,11 +1505,13 @@ int rsl_ipacc_mdcx(struct gsm_lchan *lchan, u_int32_t ip, u_int16_t port, /* 0x0- == both directions, 0x-1 == EFR codec */ lchan->abis_ip.speech_mode = 0x00 | ipa_smod_s_for_lchan(lchan); + lchan->abis_ip.rtp_payload = ipa_rtp_pt_for_lchan(lchan); ia.s_addr = htonl(ip); - DEBUGP(DRSL, "%s IPAC_MDCX IP=%s PORT=%d RTP_PAYLOAD2=%d CONN_ID=%d " - "speech_mode=0x%02x\n", gsm_lchan_name(lchan), inet_ntoa(ia), port, - rtp_payload2, lchan->abis_ip.conn_id, lchan->abis_ip.speech_mode); + DEBUGP(DRSL, "%s IPAC_MDCX IP=%s PORT=%d RTP_PAYLOAD=%d RTP_PAYLOAD2=%d " + "CONN_ID=%d speech_mode=0x%02x\n", gsm_lchan_name(lchan), + inet_ntoa(ia), port, lchan->abis_ip.rtp_payload, rtp_payload2, + lchan->abis_ip.conn_id, lchan->abis_ip.speech_mode); msgb_tv16_put(msg, RSL_IE_IPAC_CONN_ID, lchan->abis_ip.conn_id); msgb_v_put(msg, RSL_IE_IPAC_REMOTE_IP); @@ -1476,6 +1519,7 @@ int rsl_ipacc_mdcx(struct gsm_lchan *lchan, u_int32_t ip, u_int16_t port, *att_ip = ia.s_addr; msgb_tv16_put(msg, RSL_IE_IPAC_REMOTE_PORT, port); msgb_tv_put(msg, RSL_IE_IPAC_SPEECH_MODE, lchan->abis_ip.speech_mode); + msgb_tv_put(msg, RSL_IE_IPAC_RTP_PAYLOAD, lchan->abis_ip.rtp_payload); if (rtp_payload2) msgb_tv_put(msg, RSL_IE_IPAC_RTP_PAYLOAD2, rtp_payload2); diff --git a/openbsc/src/rtp_proxy.c b/openbsc/src/rtp_proxy.c index 375204e97..924173dd2 100644 --- a/openbsc/src/rtp_proxy.c +++ b/openbsc/src/rtp_proxy.c @@ -91,9 +91,6 @@ struct rtp_x_hdr { #define RTP_VERSION 2 -#define RTP_PT_GSM_FULL 3 -#define RTP_PT_GSM_EFR 97 - /* decode an rtp frame and create a new buffer with payload */ static int rtp_decode(struct msgb *msg, u_int32_t callref, struct msgb **data) { -- cgit v1.2.3 From ebaed74e17506b8cb900c6c17eadecd6cb95769d Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Thu, 15 Apr 2010 03:14:51 +0200 Subject: Add GSM08.08 protocol header. This header is copied from bssap.h of the on-waves/bsc-master branch and only contains the protocol specific information. --- include/osmocore/protocol/gsm_08_08.h | 306 ++++++++++++++++++++++++++++++++++ 1 file changed, 306 insertions(+) create mode 100644 include/osmocore/protocol/gsm_08_08.h diff --git a/include/osmocore/protocol/gsm_08_08.h b/include/osmocore/protocol/gsm_08_08.h new file mode 100644 index 000000000..b1af24ac8 --- /dev/null +++ b/include/osmocore/protocol/gsm_08_08.h @@ -0,0 +1,306 @@ +/* From GSM08.08 */ + +#ifndef GSM_0808_H +#define GSM_0808_H + +#include + +#include +#include + +/* + * this is from GSM 03.03 CGI but is copied in GSM 08.08 + * in § 3.2.2.27 for Cell Identifier List + */ +enum CELL_IDENT { + CELL_IDENT_WHOLE_GLOBAL = 0, + CELL_IDENT_LAC_AND_CI = 1, + CELL_IDENT_CI = 2, + CELL_IDENT_NO_CELL = 3, + CELL_IDENT_LAI_AND_LAC = 4, + CELL_IDENT_LAC = 5, + CELL_IDENT_BSS = 6, + CELL_IDENT_UTRAN_PLMN_LAC_RNC = 8, + CELL_IDENT_UTRAN_RNC = 9, + CELL_IDENT_UTRAN_LAC_RNC = 10, +}; + + +/* GSM 08.06 § 6.3 */ +enum BSSAP_MSG_TYPE { + BSSAP_MSG_BSS_MANAGEMENT = 0x0, + BSSAP_MSG_DTAP = 0x1, +}; + +struct bssmap_header { + u_int8_t type; + u_int8_t length; +} __attribute__((packed)); + +struct dtap_header { + u_int8_t type; + u_int8_t link_id; + u_int8_t length; +} __attribute__((packed)); + + +enum BSS_MAP_MSG_TYPE { + BSS_MAP_MSG_RESERVED_0 = 0, + + /* ASSIGNMENT MESSAGES */ + BSS_MAP_MSG_ASSIGMENT_RQST = 1, + BSS_MAP_MSG_ASSIGMENT_COMPLETE = 2, + BSS_MAP_MSG_ASSIGMENT_FAILURE = 3, + + /* HANDOVER MESSAGES */ + BSS_MAP_MSG_HANDOVER_RQST = 16, + BSS_MAP_MSG_HANDOVER_REQUIRED = 17, + BSS_MAP_MSG_HANDOVER_RQST_ACKNOWLEDGE= 18, + BSS_MAP_MSG_HANDOVER_CMD = 19, + BSS_MAP_MSG_HANDOVER_COMPLETE = 20, + BSS_MAP_MSG_HANDOVER_SUCCEEDED = 21, + BSS_MAP_MSG_HANDOVER_FAILURE = 22, + BSS_MAP_MSG_HANDOVER_PERFORMED = 23, + BSS_MAP_MSG_HANDOVER_CANDIDATE_ENQUIRE = 24, + BSS_MAP_MSG_HANDOVER_CANDIDATE_RESPONSE = 25, + BSS_MAP_MSG_HANDOVER_REQUIRED_REJECT = 26, + BSS_MAP_MSG_HANDOVER_DETECT = 27, + + /* RELEASE MESSAGES */ + BSS_MAP_MSG_CLEAR_CMD = 32, + BSS_MAP_MSG_CLEAR_COMPLETE = 33, + BSS_MAP_MSG_CLEAR_RQST = 34, + BSS_MAP_MSG_RESERVED_1 = 35, + BSS_MAP_MSG_RESERVED_2 = 36, + BSS_MAP_MSG_SAPI_N_REJECT = 37, + BSS_MAP_MSG_CONFUSION = 38, + + /* OTHER CONNECTION RELATED MESSAGES */ + BSS_MAP_MSG_SUSPEND = 40, + BSS_MAP_MSG_RESUME = 41, + BSS_MAP_MSG_CONNECTION_ORIENTED_INFORMATION = 42, + BSS_MAP_MSG_PERFORM_LOCATION_RQST = 43, + BSS_MAP_MSG_LSA_INFORMATION = 44, + BSS_MAP_MSG_PERFORM_LOCATION_RESPONSE = 45, + BSS_MAP_MSG_PERFORM_LOCATION_ABORT = 46, + BSS_MAP_MSG_COMMON_ID = 47, + + /* GENERAL MESSAGES */ + BSS_MAP_MSG_RESET = 48, + BSS_MAP_MSG_RESET_ACKNOWLEDGE = 49, + BSS_MAP_MSG_OVERLOAD = 50, + BSS_MAP_MSG_RESERVED_3 = 51, + BSS_MAP_MSG_RESET_CIRCUIT = 52, + BSS_MAP_MSG_RESET_CIRCUIT_ACKNOWLEDGE = 53, + BSS_MAP_MSG_MSC_INVOKE_TRACE = 54, + BSS_MAP_MSG_BSS_INVOKE_TRACE = 55, + BSS_MAP_MSG_CONNECTIONLESS_INFORMATION = 58, + + /* TERRESTRIAL RESOURCE MESSAGES */ + BSS_MAP_MSG_BLOCK = 64, + BSS_MAP_MSG_BLOCKING_ACKNOWLEDGE = 65, + BSS_MAP_MSG_UNBLOCK = 66, + BSS_MAP_MSG_UNBLOCKING_ACKNOWLEDGE = 67, + BSS_MAP_MSG_CIRCUIT_GROUP_BLOCK = 68, + BSS_MAP_MSG_CIRCUIT_GROUP_BLOCKING_ACKNOWLEDGE = 69, + BSS_MAP_MSG_CIRCUIT_GROUP_UNBLOCK = 70, + BSS_MAP_MSG_CIRCUIT_GROUP_UNBLOCKING_ACKNOWLEDGE = 71, + BSS_MAP_MSG_UNEQUIPPED_CIRCUIT = 72, + BSS_MAP_MSG_CHANGE_CIRCUIT = 78, + BSS_MAP_MSG_CHANGE_CIRCUIT_ACKNOWLEDGE = 79, + + /* RADIO RESOURCE MESSAGES */ + BSS_MAP_MSG_RESOURCE_RQST = 80, + BSS_MAP_MSG_RESOURCE_INDICATION = 81, + BSS_MAP_MSG_PAGING = 82, + BSS_MAP_MSG_CIPHER_MODE_CMD = 83, + BSS_MAP_MSG_CLASSMARK_UPDATE = 84, + BSS_MAP_MSG_CIPHER_MODE_COMPLETE = 85, + BSS_MAP_MSG_QUEUING_INDICATION = 86, + BSS_MAP_MSG_COMPLETE_LAYER_3 = 87, + BSS_MAP_MSG_CLASSMARK_RQST = 88, + BSS_MAP_MSG_CIPHER_MODE_REJECT = 89, + BSS_MAP_MSG_LOAD_INDICATION = 90, + + /* VGCS/VBS */ + BSS_MAP_MSG_VGCS_VBS_SETUP = 4, + BSS_MAP_MSG_VGCS_VBS_SETUP_ACK = 5, + BSS_MAP_MSG_VGCS_VBS_SETUP_REFUSE = 6, + BSS_MAP_MSG_VGCS_VBS_ASSIGNMENT_RQST = 7, + BSS_MAP_MSG_VGCS_VBS_ASSIGNMENT_RESULT = 28, + BSS_MAP_MSG_VGCS_VBS_ASSIGNMENT_FAILURE = 29, + BSS_MAP_MSG_VGCS_VBS_QUEUING_INDICATION = 30, + BSS_MAP_MSG_UPLINK_RQST = 31, + BSS_MAP_MSG_UPLINK_RQST_ACKNOWLEDGE = 39, + BSS_MAP_MSG_UPLINK_RQST_CONFIRMATION = 73, + BSS_MAP_MSG_UPLINK_RELEASE_INDICATION = 74, + BSS_MAP_MSG_UPLINK_REJECT_CMD = 75, + BSS_MAP_MSG_UPLINK_RELEASE_CMD = 76, + BSS_MAP_MSG_UPLINK_SEIZED_CMD = 77, +}; + +enum GSM0808_IE_CODING { + GSM0808_IE_CIRCUIT_IDENTITY_CODE = 1, + GSM0808_IE_RESERVED_0 = 2, + GSM0808_IE_RESOURCE_AVAILABLE = 3, + GSM0808_IE_CAUSE = 4, + GSM0808_IE_CELL_IDENTIFIER = 5, + GSM0808_IE_PRIORITY = 6, + GSM0808_IE_LAYER_3_HEADER_INFORMATION = 7, + GSM0808_IE_IMSI = 8, + GSM0808_IE_TMSI = 9, + GSM0808_IE_ENCRYPTION_INFORMATION = 10, + GSM0808_IE_CHANNEL_TYPE = 11, + GSM0808_IE_PERIODICITY = 12, + GSM0808_IE_EXTENDED_RESOURCE_INDICATOR = 13, + GSM0808_IE_NUMBER_OF_MSS = 14, + GSM0808_IE_RESERVED_1 = 15, + GSM0808_IE_RESERVED_2 = 16, + GSM0808_IE_RESERVED_3 = 17, + GSM0808_IE_CLASSMARK_INFORMATION_T2 = 18, + GSM0808_IE_CLASSMARK_INFORMATION_T3 = 19, + GSM0808_IE_INTERFERENCE_BAND_TO_USE = 20, + GSM0808_IE_RR_CAUSE = 21, + GSM0808_IE_RESERVED_4 = 22, + GSM0808_IE_LAYER_3_INFORMATION = 23, + GSM0808_IE_DLCI = 24, + GSM0808_IE_DOWNLINK_DTX_FLAG = 25, + GSM0808_IE_CELL_IDENTIFIER_LIST = 26, + GSM0808_IE_RESPONSE_RQST = 27, + GSM0808_IE_RESOURCE_INDICATION_METHOD = 28, + GSM0808_IE_CLASSMARK_INFORMATION_TYPE_1 = 29, + GSM0808_IE_CIRCUIT_IDENTITY_CODE_LIST = 30, + GSM0808_IE_DIAGNOSTIC = 31, + GSM0808_IE_LAYER_3_MESSAGE_CONTENTS = 32, + GSM0808_IE_CHOSEN_CHANNEL = 33, + GSM0808_IE_TOTAL_RESOURCE_ACCESSIBLE = 34, + GSM0808_IE_CIPHER_RESPONSE_MODE = 35, + GSM0808_IE_CHANNEL_NEEDED = 36, + GSM0808_IE_TRACE_TYPE = 37, + GSM0808_IE_TRIGGERID = 38, + GSM0808_IE_TRACE_REFERENCE = 39, + GSM0808_IE_TRANSACTIONID = 40, + GSM0808_IE_MOBILE_IDENTITY = 41, + GSM0808_IE_OMCID = 42, + GSM0808_IE_FORWARD_INDICATOR = 43, + GSM0808_IE_CHOSEN_ENCR_ALG = 44, + GSM0808_IE_CIRCUIT_POOL = 45, + GSM0808_IE_CIRCUIT_POOL_LIST = 46, + GSM0808_IE_TIME_INDICATION = 47, + GSM0808_IE_RESOURCE_SITUATION = 48, + GSM0808_IE_CURRENT_CHANNEL_TYPE_1 = 49, + GSM0808_IE_QUEUEING_INDICATOR = 50, + GSM0808_IE_SPEECH_VERSION = 64, + GSM0808_IE_ASSIGNMENT_REQUIREMENT = 51, + GSM0808_IE_TALKER_FLAG = 53, + GSM0808_IE_CONNECTION_RELEASE_RQSTED = 54, + GSM0808_IE_GROUP_CALL_REFERENCE = 55, + GSM0808_IE_EMLPP_PRIORITY = 56, + GSM0808_IE_CONFIG_EVO_INDI = 57, + GSM0808_IE_OLD_BSS_TO_NEW_BSS_INFORMATION = 58, + GSM0808_IE_LSA_IDENTIFIER = 59, + GSM0808_IE_LSA_IDENTIFIER_LIST = 60, + GSM0808_IE_LSA_INFORMATION = 61, + GSM0808_IE_LCS_QOS = 62, + GSM0808_IE_LSA_ACCESS_CTRL_SUPPR = 63, + GSM0808_IE_LCS_PRIORITY = 67, + GSM0808_IE_LOCATION_TYPE = 68, + GSM0808_IE_LOCATION_ESTIMATE = 69, + GSM0808_IE_POSITIONING_DATA = 70, + GSM0808_IE_LCS_CAUSE = 71, + GSM0808_IE_LCS_CLIENT_TYPE = 72, + GSM0808_IE_APDU = 73, + GSM0808_IE_NETWORK_ELEMENT_IDENTITY = 74, + GSM0808_IE_GPS_ASSISTANCE_DATA = 75, + GSM0808_IE_DECIPHERING_KEYS = 76, + GSM0808_IE_RETURN_ERROR_RQST = 77, + GSM0808_IE_RETURN_ERROR_CAUSE = 78, + GSM0808_IE_SEGMENTATION = 79, + GSM0808_IE_SERVICE_HANDOVER = 80, + GSM0808_IE_SOURCE_RNC_TO_TARGET_RNC_TRANSPARENT_UMTS = 81, + GSM0808_IE_SOURCE_RNC_TO_TARGET_RNC_TRANSPARENT_CDMA2000= 82, + GSM0808_IE_RESERVED_5 = 65, + GSM0808_IE_RESERVED_6 = 66, +}; + +enum gsm0808_cause { + GSM0808_CAUSE_RADIO_INTERFACE_MESSAGE_FAILURE = 0, + GSM0808_CAUSE_RADIO_INTERFACE_FAILURE = 1, + GSM0808_CAUSE_UPLINK_QUALITY = 2, + GSM0808_CAUSE_UPLINK_STRENGTH = 3, + GSM0808_CAUSE_DOWNLINK_QUALITY = 4, + GSM0808_CAUSE_DOWNLINK_STRENGTH = 5, + GSM0808_CAUSE_DISTANCE = 6, + GSM0808_CAUSE_O_AND_M_INTERVENTION = 7, + GSM0808_CAUSE_RESPONSE_TO_MSC_INVOCATION = 8, + GSM0808_CAUSE_CALL_CONTROL = 9, + GSM0808_CAUSE_RADIO_INTERFACE_FAILURE_REVERSION = 10, + GSM0808_CAUSE_HANDOVER_SUCCESSFUL = 11, + GSM0808_CAUSE_BETTER_CELL = 12, + GSM0808_CAUSE_DIRECTED_RETRY = 13, + GSM0808_CAUSE_JOINED_GROUP_CALL_CHANNEL = 14, + GSM0808_CAUSE_TRAFFIC = 15, + GSM0808_CAUSE_EQUIPMENT_FAILURE = 32, + GSM0808_CAUSE_NO_RADIO_RESOURCE_AVAILABLE = 33, + GSM0808_CAUSE_RQSTED_TERRESTRIAL_RESOURCE_UNAVAILABLE = 34, + GSM0808_CAUSE_CCCH_OVERLOAD = 35, + GSM0808_CAUSE_PROCESSOR_OVERLOAD = 36, + GSM0808_CAUSE_BSS_NOT_EQUIPPED = 37, + GSM0808_CAUSE_MS_NOT_EQUIPPED = 38, + GSM0808_CAUSE_INVALID_CELL = 39, + GSM0808_CAUSE_TRAFFIC_LOAD = 40, + GSM0808_CAUSE_PREEMPTION = 41, + GSM0808_CAUSE_RQSTED_TRANSCODING_RATE_ADAPTION_UNAVAILABLE = 48, + GSM0808_CAUSE_CIRCUIT_POOL_MISMATCH = 49, + GSM0808_CAUSE_SWITCH_CIRCUIT_POOL = 50, + GSM0808_CAUSE_RQSTED_SPEECH_VERSION_UNAVAILABLE = 51, + GSM0808_CAUSE_LSA_NOT_ALLOWED = 52, + GSM0808_CAUSE_CIPHERING_ALGORITHM_NOT_SUPPORTED = 64, + GSM0808_CAUSE_TERRESTRIAL_CIRCUIT_ALREADY_ALLOCATED = 80, + GSM0808_CAUSE_INVALID_MESSAGE_CONTENTS = 81, + GSM0808_CAUSE_INFORMATION_ELEMENT_OR_FIELD_MISSING = 82, + GSM0808_CAUSE_INCORRECT_VALUE = 83, + GSM0808_CAUSE_UNKNOWN_MESSAGE_TYPE = 84, + GSM0808_CAUSE_UNKNOWN_INFORMATION_ELEMENT = 85, + GSM0808_CAUSE_PROTOCOL_ERROR_BETWEEN_BSS_AND_MSC = 96, +}; + +/* GSM 08.08 3.2.2.11 Channel Type */ +enum gsm0808_chan_indicator { + GSM0808_CHAN_SPEECH = 1, + GSM0808_CHAN_DATA = 2, + GSM0808_CHAN_SIGN = 3, +}; + +enum gsm0808_chan_rate_type_data { + GSM0808_DATA_FULL_BM = 0x8, + GSM0808_DATA_HALF_LM = 0x9, + GSM0808_DATA_FULL_RPREF = 0xa, + GSM0808_DATA_HALF_PREF = 0xb, + GSM0808_DATA_FULL_PREF_NO_CHANGE = 0x1a, + GSM0808_DATA_HALF_PREF_NO_CHANGE = 0x1b, + GSM0808_DATA_MULTI_MASK = 0x20, + GSM0808_DATA_MULTI_MASK_NO_CHANGE = 0x30, +}; + +enum gsm0808_chan_rate_type_speech { + GSM0808_SPEECH_FULL_BM = 0x8, + GSM0808_SPEECH_HALF_LM = 0x9, + GSM0808_SPEECH_FULL_PREF= 0xa, + GSM0808_SPEECH_HALF_PREF= 0xb, + GSM0808_SPEECH_FULL_PREF_NO_CHANGE = 0x1a, + GSM0808_SPEECH_HALF_PREF_NO_CHANGE = 0x1b, + GSM0808_SPEECH_PERM = 0xf, + GSM0808_SPEECH_PERM_NO_CHANGE = 0x1f, +}; + +enum gsm0808_permitted_speech { + GSM0808_PERM_FR1 = 0x01, + GSM0808_PERM_FR2 = 0x11, + GSM0808_PERM_FR3 = 0x21, + GSM0808_PERM_HR1 = GSM0808_PERM_FR1 | 0x4, + GSM0808_PERM_HR2 = GSM0808_PERM_FR2 | 0x4, + GSM0808_PERM_HR3 = GSM0808_PERM_FR3 | 0x4, +}; + +#endif -- cgit v1.2.3 From 2c86c2a726a9736254d98f37e0bf21e1159db749 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Thu, 15 Apr 2010 10:01:39 +0200 Subject: gsm_08_08.h: Remove OpenBSC include file from the header. --- include/osmocore/protocol/gsm_08_08.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/include/osmocore/protocol/gsm_08_08.h b/include/osmocore/protocol/gsm_08_08.h index b1af24ac8..9c29ba9c8 100644 --- a/include/osmocore/protocol/gsm_08_08.h +++ b/include/osmocore/protocol/gsm_08_08.h @@ -5,9 +5,6 @@ #include -#include -#include - /* * this is from GSM 03.03 CGI but is copied in GSM 08.08 * in § 3.2.2.27 for Cell Identifier List -- cgit v1.2.3 From 280cd5153f1387c462fa93cd1a2ca77260015024 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Thu, 15 Apr 2010 10:10:39 +0200 Subject: Add GSM0808 utilities to Osmocore. The code is coming from the on-waves/bsc-master branch. --- include/osmocore/Makefile.am | 2 +- include/osmocore/gsm0808.h | 43 ++++++++++ src/Makefile.am | 2 +- src/gsm0808.c | 188 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 233 insertions(+), 2 deletions(-) create mode 100644 include/osmocore/gsm0808.h create mode 100644 src/gsm0808.c diff --git a/include/osmocore/Makefile.am b/include/osmocore/Makefile.am index 1c3a33f33..56f926bcf 100644 --- a/include/osmocore/Makefile.am +++ b/include/osmocore/Makefile.am @@ -1,7 +1,7 @@ osmocore_HEADERS = signal.h linuxlist.h timer.h select.h msgb.h \ tlv.h bitvec.h comp128.h statistics.h gsm_utils.h utils.h \ gsmtap.h write_queue.h rsl.h gsm48.h rxlev_stat.h mncc.h \ - gsm48_ie.h logging.h + gsm48_ie.h logging.h gsm0808.h if ENABLE_TALLOC osmocore_HEADERS += talloc.h diff --git a/include/osmocore/gsm0808.h b/include/osmocore/gsm0808.h new file mode 100644 index 000000000..0ea78da47 --- /dev/null +++ b/include/osmocore/gsm0808.h @@ -0,0 +1,43 @@ +/* (C) 2009,2010 by Holger Hans Peter Freyther + * (C) 2009,2010 by On-Waves + * 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. + * + */ +#ifndef OSMOCORE_GSM0808_H +#define OSMOCORE_GSM0808_H + +#include "tlv.h" + +struct msgb; + +struct msgb *gsm0808_create_layer3(struct msgb *msg, uint16_t netcode, uint16_t countrycode, int lac, int ci); +struct msgb *gsm0808_create_reset(void); +struct msgb *gsm0808_create_clear_complete(void); +struct msgb *gsm0808_create_cipher_reject(uint8_t cause); +struct msgb *gsm0808_create_classmark_update(const uint8_t *classmark, uint8_t length); +struct msgb *gsm0808_create_sapi_reject(uint8_t link_id); +struct msgb *gsm0808_create_assignment_failure(uint8_t cause, uint8_t *rr_cause); + +const struct tlv_definition *gsm0808_att_tlvdef(); + +/* needs to be ported */ +#if 0 +struct msgb *bssmap_create_assignment_completed(struct gsm_lchan *lchan, uint8_t rr_cause); +struct msgb *bssmap_create_cipher_complete(struct msgb *layer3); +#endif + +#endif diff --git a/src/Makefile.am b/src/Makefile.am index 16978074a..20e99db30 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -10,7 +10,7 @@ lib_LTLIBRARIES = libosmocore.la libosmocore_la_SOURCES = timer.c select.c signal.c msgb.c rxlev_stat.c \ tlv_parser.c bitvec.c comp128.c gsm_utils.c statistics.c \ write_queue.c utils.c rsl.c gsm48.c gsm48_ie.c \ - logging.c + logging.c gsm0808.c if ENABLE_TALLOC libosmocore_la_SOURCES += talloc.c diff --git a/src/gsm0808.c b/src/gsm0808.c new file mode 100644 index 000000000..ea772b4c9 --- /dev/null +++ b/src/gsm0808.c @@ -0,0 +1,188 @@ +/* (C) 2009,2010 by Holger Hans Peter Freyther + * (C) 2009,2010 by On-Waves + * 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 + +#define BSSMAP_MSG_SIZE 512 +#define BSSMAP_MSG_HEADROOM 128 + +struct msgb *gsm0808_create_layer3(struct msgb *msg_l3, uint16_t nc, uint16_t cc, int lac, int _ci) +{ + uint8_t *data; + uint16_t *ci; + struct msgb* msg; + struct gsm48_loc_area_id *lai; + + msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM, + "bssmap cmpl l3"); + if (!msg) + return NULL; + + /* create the bssmap header */ + msg->l3h = msgb_put(msg, 2); + msg->l3h[0] = 0x0; + + /* create layer 3 header */ + data = msgb_put(msg, 1); + data[0] = BSS_MAP_MSG_COMPLETE_LAYER_3; + + /* create the cell header */ + data = msgb_put(msg, 3); + data[0] = GSM0808_IE_CELL_IDENTIFIER; + data[1] = 1 + sizeof(*lai) + 2; + data[2] = CELL_IDENT_WHOLE_GLOBAL; + + lai = (struct gsm48_loc_area_id *) msgb_put(msg, sizeof(*lai)); + gsm48_generate_lai(lai, cc, nc, lac); + + ci = (uint16_t *) msgb_put(msg, 2); + *ci = htons(_ci); + + /* copy the layer3 data */ + data = msgb_put(msg, msgb_l3len(msg_l3) + 2); + data[0] = GSM0808_IE_LAYER_3_INFORMATION; + data[1] = msgb_l3len(msg_l3); + memcpy(&data[2], msg_l3->l3h, data[1]); + + /* update the size */ + msg->l3h[1] = msgb_l3len(msg) - 2; + + return msg; +} + +struct msgb *gsm0808_create_reset(void) +{ + struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM, + "bssmap: reset"); + if (!msg) + return NULL; + + msg->l3h = msgb_put(msg, 6); + msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT; + msg->l3h[1] = 0x04; + msg->l3h[2] = 0x30; + msg->l3h[3] = 0x04; + msg->l3h[4] = 0x01; + msg->l3h[5] = 0x20; + return msg; +} + +struct msgb *gsm0808_create_clear_complete(void) +{ + struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM, + "bssmap: clear complete"); + if (!msg) + return NULL; + + msg->l3h = msgb_put(msg, 3); + msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT; + msg->l3h[1] = 1; + msg->l3h[2] = BSS_MAP_MSG_CLEAR_COMPLETE; + + return msg; +} + +struct msgb *gsm0808_create_cipher_reject(uint8_t cause) +{ + struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM, + "bssmap: clear complete"); + if (!msg) + return NULL; + + msg->l3h = msgb_put(msg, 3); + msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT; + msg->l3h[1] = 2; + msg->l3h[2] = BSS_MAP_MSG_CIPHER_MODE_REJECT; + msg->l3h[3] = cause; + + return msg; +} + +struct msgb *gsm0808_create_classmark_update(const uint8_t *classmark_data, u_int8_t length) +{ + struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM, + "classmark-update"); + if (!msg) + return NULL; + + msg->l3h = msgb_put(msg, 3); + msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT; + msg->l3h[1] = 0xff; + msg->l3h[2] = BSS_MAP_MSG_CLASSMARK_UPDATE; + + msg->l4h = msgb_put(msg, length); + memcpy(msg->l4h, classmark_data, length); + + /* update the size */ + msg->l3h[1] = msgb_l3len(msg) - 2; + return msg; +} + +struct msgb *gsm0808_create_sapi_reject(uint8_t link_id) +{ + struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM, + "bssmap: sapi 'n' reject"); + if (!msg) + return NULL; + + msg->l3h = msgb_put(msg, 5); + msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT; + msg->l3h[1] = 3; + msg->l3h[2] = BSS_MAP_MSG_SAPI_N_REJECT; + msg->l3h[3] = link_id; + msg->l3h[4] = GSM0808_CAUSE_BSS_NOT_EQUIPPED; + + return msg; +} + +struct msgb *gsm0808_create_assignment_failure(uint8_t cause, uint8_t *rr_cause) +{ + uint8_t *data; + struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM, + "bssmap: ass fail"); + if (!msg) + return NULL; + + msg->l3h = msgb_put(msg, 6); + msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT; + msg->l3h[1] = 0xff; + msg->l3h[2] = BSS_MAP_MSG_ASSIGMENT_FAILURE; + msg->l3h[3] = GSM0808_IE_CAUSE; + msg->l3h[4] = 1; + msg->l3h[5] = cause; + + /* RR cause 3.2.2.22 */ + if (rr_cause) { + data = msgb_put(msg, 2); + data[0] = GSM0808_IE_RR_CAUSE; + data[1] = *rr_cause; + } + + /* Circuit pool 3.22.45 */ + /* Circuit pool list 3.2.2.46 */ + + /* update the size */ + msg->l3h[1] = msgb_l3len(msg) - 2; + return msg; +} -- cgit v1.2.3 From 70402a4e4ddc0f7ee584445c9c3ac7dc91fe374b Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Thu, 15 Apr 2010 11:17:24 +0200 Subject: [ipa] Handle losing the RSL/OML connection.. This is addressing multiple issues regarding the loss of the OML/RSL link to the BTS. 1.) When we lose the OML link, close down all RSL connections on all TRXs (only tested with one TRX) and free the e1inp_line allocated for the OML connection. 2.) When we lose the RSL link on any TRX and we know to which lines this connection belongs, we will close down the OML connection as we have a problem to just reactivate one RSL link. 3.) When we lose the RSL link on any TRX and we do not know where it belongs to we will free the bfd we have allocated in the rsl listen/accept method and we properly close the socket (i could not test this one properly). This is made under the assumption the BTS has not responded to the ID request. 4.) When we already have a bts->oml_link we will throw it away and use the new link (it should not happen) and the same applies to the rsl link. --- openbsc/include/openbsc/ipaccess.h | 2 + openbsc/src/input/ipaccess.c | 147 ++++++++++++++++++++++++++++++------- 2 files changed, 123 insertions(+), 26 deletions(-) diff --git a/openbsc/include/openbsc/ipaccess.h b/openbsc/include/openbsc/ipaccess.h index 86248aae5..f8ddfd467 100644 --- a/openbsc/include/openbsc/ipaccess.h +++ b/openbsc/include/openbsc/ipaccess.h @@ -53,6 +53,8 @@ int ipaccess_send_id_req(int fd); int ipaccess_idtag_parse(struct tlv_parsed *dec, unsigned char *buf, int len); +int ipaccess_drop_oml(struct gsm_bts *bts); +int ipaccess_drop_rsl(struct gsm_bts_trx *trx); /* * Firmware specific header diff --git a/openbsc/src/input/ipaccess.c b/openbsc/src/input/ipaccess.c index 8722791bc..8fb9d3a8e 100644 --- a/openbsc/src/input/ipaccess.c +++ b/openbsc/src/input/ipaccess.c @@ -1,6 +1,8 @@ /* OpenBSC Abis input driver for ip.access */ /* (C) 2009 by Harald Welte + * (C) 2010 by Holger Hans Peter Freyther + * (C) 2010 by On-Waves * * All Rights Reserved * @@ -234,6 +236,8 @@ static int ipaccess_rcvmsg(struct e1inp_line *line, struct msgb *msg, } DEBUGP(DINP, "Identified BTS %u/%u/%u\n", site_id, bts_id, trx_id); if (bfd->priv_nr == PRIV_OML) { + /* drop any old oml connection */ + ipaccess_drop_oml(bts); bts->oml_link = e1inp_sign_link_create(&line->ts[PRIV_OML - 1], E1INP_SIGN_OML, bts->c0, bts->oml_tei, 0); @@ -241,7 +245,18 @@ static int ipaccess_rcvmsg(struct e1inp_line *line, struct msgb *msg, struct e1inp_ts *e1i_ts; struct bsc_fd *newbfd; struct gsm_bts_trx *trx = gsm_bts_trx_num(bts, trx_id); - + + /* drop any old rsl connection */ + ipaccess_drop_rsl(trx); + + if (!bts->oml_link) { + bsc_unregister_fd(bfd); + close(bfd->fd); + bfd->fd = -1; + talloc_free(bfd); + return 0; + } + bfd->data = line = bts->oml_link->ts->line; e1i_ts = &line->ts[PRIV_RSL + trx_id - 1]; newbfd = &e1i_ts->driver.ipaccess.fd; @@ -251,19 +266,13 @@ static int ipaccess_rcvmsg(struct e1inp_line *line, struct msgb *msg, E1INP_SIGN_RSL, trx, trx->rsl_tei, 0); - if (newbfd->fd >= 0) { - LOGP(DINP, LOGL_ERROR, "BTS is still registered. Closing old connection.\n"); - bsc_unregister_fd(newbfd); - close(newbfd->fd); - newbfd->fd = -1; - } - /* get rid of our old temporary bfd */ memcpy(newbfd, bfd, sizeof(*newbfd)); newbfd->priv_nr = PRIV_RSL + trx_id; bsc_unregister_fd(bfd); - bsc_register_fd(newbfd); + bfd->fd = -1; talloc_free(bfd); + bsc_register_fd(newbfd); } break; } @@ -328,6 +337,103 @@ struct msgb *ipaccess_read_msg(struct bsc_fd *bfd, int *error) return msg; } +int ipaccess_drop_oml(struct gsm_bts *bts) +{ + struct gsm_bts_trx *trx; + struct e1inp_ts *ts; + struct e1inp_line *line; + struct bsc_fd *bfd; + + if (!bts || !bts->oml_link) + return -1; + + /* send OML down */ + ts = bts->oml_link->ts; + line = ts->line; + e1inp_event(ts, EVT_E1_TEI_DN, 0, IPAC_PROTO_OML); + + bfd = &ts->driver.ipaccess.fd; + bsc_unregister_fd(bfd); + close(bfd->fd); + bfd->fd = -1; + + /* clean up OML and RSL */ + e1inp_sign_link_destroy(bts->oml_link); + bts->oml_link = NULL; + bts->ip_access.flags = 0; + + /* drop all RSL connections too */ + llist_for_each_entry(trx, &bts->trx_list, list) + ipaccess_drop_rsl(trx); + + /* kill the E1 line now... as we have no one left to use it */ + talloc_free(line); + + return -1; +} + +static int ipaccess_drop(struct e1inp_ts *ts, struct bsc_fd *bfd) +{ + struct e1inp_sign_link *link; + int bts_nr; + + if (!ts) { + /* + * If we don't have a TS this means that this is a RSL + * connection but we are not past the authentication + * handling yet. So we can safely delete this bfd and + * wait for a reconnect. + */ + bsc_unregister_fd(bfd); + close(bfd->fd); + bfd->fd = -1; + talloc_free(bfd); + return -1; + } + + /* attempt to find a signalling link */ + if (ts->type == E1INP_TS_TYPE_SIGN) { + llist_for_each_entry(link, &ts->sign.sign_links, list) { + bts_nr = link->trx->bts->bts_nr; + /* we have issues just reconnecting RLS so we drop OML */ + ipaccess_drop_oml(link->trx->bts); + return bts_nr; + } + } + + /* error case */ + LOGP(DINP, LOGL_ERROR, "Failed to find a signalling link for ts: %p\n", ts); + bsc_unregister_fd(bfd); + close(bfd->fd); + bfd->fd = -1; + return -1; +} + +int ipaccess_drop_rsl(struct gsm_bts_trx *trx) +{ + struct bsc_fd *bfd; + struct e1inp_ts *ts; + + if (!trx || !trx->rsl_link) + return -1; + + /* send RSL down */ + ts = trx->rsl_link->ts; + e1inp_event(ts, EVT_E1_TEI_DN, 0, IPAC_PROTO_RSL); + + /* close the socket */ + bfd = &ts->driver.ipaccess.fd; + bsc_unregister_fd(bfd); + close(bfd->fd); + bfd->fd = -1; + + /* destroy */ + e1inp_sign_link_destroy(trx->rsl_link); + trx->rsl_link = NULL; + + return -1; +} + static int handle_ts1_read(struct bsc_fd *bfd) { struct e1inp_line *line = bfd->data; @@ -341,18 +447,12 @@ static int handle_ts1_read(struct bsc_fd *bfd) msg = ipaccess_read_msg(bfd, &error); if (!msg) { if (error == 0) { - link = e1inp_lookup_sign_link(e1i_ts, IPAC_PROTO_OML, 0); - if (link) { - link->trx->bts->ip_access.flags = 0; + int ret = ipaccess_drop(e1i_ts, bfd); + if (ret >= 0) LOGP(DINP, LOGL_NOTICE, "BTS %u disappeared, dead socket\n", - link->trx->bts->nr); - } else + ret); + else LOGP(DINP, LOGL_NOTICE, "unknown BTS disappeared, dead socket\n"); - e1inp_event(e1i_ts, EVT_E1_TEI_DN, 0, IPAC_PROTO_RSL); - e1inp_event(e1i_ts, EVT_E1_TEI_DN, 0, IPAC_PROTO_OML); - bsc_unregister_fd(bfd); - close(bfd->fd); - bfd->fd = -1; } return error; } @@ -362,13 +462,8 @@ static int handle_ts1_read(struct bsc_fd *bfd) hh = (struct ipaccess_head *) msg->data; if (hh->proto == IPAC_PROTO_IPACCESS) { ret = ipaccess_rcvmsg(line, msg, bfd); - if (ret < 0) { - e1inp_event(e1i_ts, EVT_E1_TEI_DN, 0, IPAC_PROTO_RSL); - e1inp_event(e1i_ts, EVT_E1_TEI_DN, 0, IPAC_PROTO_OML); - bsc_unregister_fd(bfd); - close(bfd->fd); - bfd->fd = -1; - } + if (ret < 0) + ipaccess_drop(e1i_ts, bfd); msgb_free(msg); return ret; } -- cgit v1.2.3 From f8eff2e4b537c00cfc8a17991759df0f58a29148 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Sun, 11 Apr 2010 18:54:58 +0200 Subject: [ipa] Fix the reporting of link down... Now bsc_init.c is able to handle the link down messages. --- openbsc/src/input/ipaccess.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openbsc/src/input/ipaccess.c b/openbsc/src/input/ipaccess.c index 8fb9d3a8e..8a8a1987d 100644 --- a/openbsc/src/input/ipaccess.c +++ b/openbsc/src/input/ipaccess.c @@ -350,7 +350,7 @@ int ipaccess_drop_oml(struct gsm_bts *bts) /* send OML down */ ts = bts->oml_link->ts; line = ts->line; - e1inp_event(ts, EVT_E1_TEI_DN, 0, IPAC_PROTO_OML); + e1inp_event(ts, EVT_E1_TEI_DN, bts->oml_link->tei, bts->oml_link->sapi); bfd = &ts->driver.ipaccess.fd; bsc_unregister_fd(bfd); @@ -419,7 +419,7 @@ int ipaccess_drop_rsl(struct gsm_bts_trx *trx) /* send RSL down */ ts = trx->rsl_link->ts; - e1inp_event(ts, EVT_E1_TEI_DN, 0, IPAC_PROTO_RSL); + e1inp_event(ts, EVT_E1_TEI_DN, trx->rsl_link->tei, trx->rsl_link->sapi); /* close the socket */ bfd = &ts->driver.ipaccess.fd; -- cgit v1.2.3 From 135f797a3711d317a9aef43f0efa9fb8764a0d10 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Thu, 15 Apr 2010 11:21:02 +0200 Subject: [bsc_init] When the RSL/OML connection drops, free all lchans Free all allocated channels on the TRX that failed, go through lchan_free to signal higher layers and then force a reset of the channel. Make the TRX and TS unusable by setting the operational set to 0 (not really defined) which should be reset once the RSL is coming up again. --- openbsc/include/openbsc/chan_alloc.h | 1 + openbsc/src/bsc_init.c | 29 +++++++++++++++++++++++++++-- openbsc/src/chan_alloc.c | 14 ++++++++++++++ 3 files changed, 42 insertions(+), 2 deletions(-) diff --git a/openbsc/include/openbsc/chan_alloc.h b/openbsc/include/openbsc/chan_alloc.h index f564e9e4d..d4f5858b7 100644 --- a/openbsc/include/openbsc/chan_alloc.h +++ b/openbsc/include/openbsc/chan_alloc.h @@ -45,6 +45,7 @@ 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); +void lchan_reset(struct gsm_lchan *lchan); /* Consider releasing the channel */ int lchan_auto_release(struct gsm_lchan *lchan); diff --git a/openbsc/src/bsc_init.c b/openbsc/src/bsc_init.c index f3436621f..fccdb0cd8 100644 --- a/openbsc/src/bsc_init.c +++ b/openbsc/src/bsc_init.c @@ -31,6 +31,7 @@ #include #include #include +#include #include /* global pointer to the gsm network data structure */ @@ -899,6 +900,8 @@ static void bootstrap_rsl(struct gsm_bts_trx *trx) void input_event(int event, enum e1inp_sign_type type, struct gsm_bts_trx *trx) { + int ts_no, lchan_no; + switch (event) { case EVT_E1_TEI_UP: switch (type) { @@ -913,8 +916,30 @@ void input_event(int event, enum e1inp_sign_type type, struct gsm_bts_trx *trx) } break; case EVT_E1_TEI_DN: - LOGP(DMI, LOGL_NOTICE, "Lost some E1 TEI link\n"); - /* FIXME: deal with TEI or L1 link loss */ + LOGP(DMI, LOGL_ERROR, "Lost some E1 TEI link: %d %p\n", type, trx); + + /* + * free all allocated channels. change the nm_state so the + * trx and trx_ts becomes unusable and chan_alloc.c can not + * allocate from it. + */ + for (ts_no = 0; ts_no < ARRAY_SIZE(trx->ts); ++ts_no) { + struct gsm_bts_trx_ts *ts = &trx->ts[ts_no]; + + for (lchan_no = 0; lchan_no < ARRAY_SIZE(ts->lchan); ++lchan_no) { + if (ts->lchan[lchan_no].state != GSM_LCHAN_NONE) + lchan_free(&ts->lchan[lchan_no]); + lchan_reset(&ts->lchan[lchan_no]); + } + + ts->nm_state.operational = 0; + ts->nm_state.availability = 0; + } + + trx->nm_state.operational = 0; + trx->nm_state.availability = 0; + trx->bb_transc.nm_state.operational = 0; + trx->bb_transc.nm_state.availability = 0; break; default: break; diff --git a/openbsc/src/chan_alloc.c b/openbsc/src/chan_alloc.c index 118deca10..107abdc92 100644 --- a/openbsc/src/chan_alloc.c +++ b/openbsc/src/chan_alloc.c @@ -330,6 +330,20 @@ void lchan_free(struct gsm_lchan *lchan) * channel using it */ } +/* + * There was an error with the TRX and we need to forget + * any state so that a lchan can be allocated again after + * the trx is fully usable. + */ +void lchan_reset(struct gsm_lchan *lchan) +{ + bsc_del_timer(&lchan->T3101); + + lchan->type = GSM_LCHAN_NONE; + lchan->state = LCHAN_S_NONE; +} + + /* Consider releasing the channel now */ int lchan_auto_release(struct gsm_lchan *lchan) { -- cgit v1.2.3 From e0ec32686792bd962f4efb6122be8769b1b832b9 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Thu, 15 Apr 2010 11:28:14 +0200 Subject: [vty] Separate BSC and MSC statistics. Make it easy to print them. Move the statistics command into the MSC part and move the BSC statistics printing into a subroutine. --- openbsc/include/openbsc/vty.h | 4 ++++ openbsc/src/vty_interface.c | 41 -------------------------------------- openbsc/src/vty_interface_cmds.c | 11 ++++++++++ openbsc/src/vty_interface_layer3.c | 37 ++++++++++++++++++++++++++++++++++ 4 files changed, 52 insertions(+), 41 deletions(-) diff --git a/openbsc/include/openbsc/vty.h b/openbsc/include/openbsc/vty.h index 40e219162..f1b1148ad 100644 --- a/openbsc/include/openbsc/vty.h +++ b/openbsc/include/openbsc/vty.h @@ -1,6 +1,10 @@ #ifndef OPENBSC_VTY_H #define OPENBSC_VTY_H +struct gsm_network; +struct vty; + void openbsc_vty_add_cmds(void); +void openbsc_vty_print_statistics(struct vty *vty, struct gsm_network *); #endif diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c index f74a041b6..bcf4a87ff 100644 --- a/openbsc/src/vty_interface.c +++ b/openbsc/src/vty_interface.c @@ -875,46 +875,6 @@ DEFUN(show_paging, return CMD_SUCCESS; } -DEFUN(show_stats, - show_stats_cmd, - "show statistics", - SHOW_STR "Display network statistics\n") -{ - struct gsm_network *net = gsmnet; - - vty_out(vty, "Channel Requests : %lu total, %lu no channel%s", - counter_get(net->stats.chreq.total), - counter_get(net->stats.chreq.no_channel), VTY_NEWLINE); - vty_out(vty, "Location Update : %lu attach, %lu normal, %lu periodic%s", - counter_get(net->stats.loc_upd_type.attach), - counter_get(net->stats.loc_upd_type.normal), - counter_get(net->stats.loc_upd_type.periodic), VTY_NEWLINE); - vty_out(vty, "IMSI Detach Indications : %lu%s", - counter_get(net->stats.loc_upd_type.detach), VTY_NEWLINE); - vty_out(vty, "Location Update Response: %lu accept, %lu reject%s", - counter_get(net->stats.loc_upd_resp.accept), - counter_get(net->stats.loc_upd_resp.reject), VTY_NEWLINE); - vty_out(vty, "Paging : %lu attempted, %lu complete, %lu expired%s", - counter_get(net->stats.paging.attempted), - counter_get(net->stats.paging.completed), - counter_get(net->stats.paging.expired), VTY_NEWLINE); - vty_out(vty, "Handover : %lu attempted, %lu no_channel, %lu timeout, " - "%lu completed, %lu failed%s", - counter_get(net->stats.handover.attempted), - counter_get(net->stats.handover.no_channel), - counter_get(net->stats.handover.timeout), - counter_get(net->stats.handover.completed), - counter_get(net->stats.handover.failed), VTY_NEWLINE); - vty_out(vty, "SMS MO : %lu submitted, %lu no receiver%s", - counter_get(net->stats.sms.submitted), - counter_get(net->stats.sms.no_receiver), VTY_NEWLINE); - vty_out(vty, "SMS MT : %lu delivered, %lu no memory, %lu other error%s", - counter_get(net->stats.sms.delivered), - counter_get(net->stats.sms.rp_err_mem), - counter_get(net->stats.sms.rp_err_other), VTY_NEWLINE); - return CMD_SUCCESS; -} - DEFUN(cfg_net, cfg_net_cmd, "network", @@ -1756,7 +1716,6 @@ int bsc_vty_init(struct gsm_network *net) install_element(VIEW_NODE, &show_e1ts_cmd); install_element(VIEW_NODE, &show_paging_cmd); - install_element(VIEW_NODE, &show_stats_cmd); openbsc_vty_add_cmds(); diff --git a/openbsc/src/vty_interface_cmds.c b/openbsc/src/vty_interface_cmds.c index d4945840e..623aa30df 100644 --- a/openbsc/src/vty_interface_cmds.c +++ b/openbsc/src/vty_interface_cmds.c @@ -228,6 +228,17 @@ DEFUN(diable_logging, return CMD_SUCCESS; } +void openbsc_vty_print_statistics(struct vty *vty, struct gsm_network *net) +{ + vty_out(vty, "Channel Requests : %lu total, %lu no channel%s", + counter_get(net->stats.chreq.total), + counter_get(net->stats.chreq.no_channel), VTY_NEWLINE); + vty_out(vty, "Paging : %lu attempted, %lu complete, %lu expired%s", + counter_get(net->stats.paging.attempted), + counter_get(net->stats.paging.completed), + counter_get(net->stats.paging.expired), VTY_NEWLINE); +} + void openbsc_vty_add_cmds() { install_element(VIEW_NODE, &enable_logging_cmd); diff --git a/openbsc/src/vty_interface_layer3.c b/openbsc/src/vty_interface_layer3.c index b824c3db6..5e3098289 100644 --- a/openbsc/src/vty_interface_layer3.c +++ b/openbsc/src/vty_interface_layer3.c @@ -41,6 +41,7 @@ #include #include #include +#include static struct gsm_network *gsmnet; @@ -502,6 +503,41 @@ static int scall_cbfn(unsigned int subsys, unsigned int signal, return 0; } +DEFUN(show_stats, + show_stats_cmd, + "show statistics", + SHOW_STR "Display network statistics\n") +{ + struct gsm_network *net = gsmnet; + + openbsc_vty_print_statistics(vty, net); + vty_out(vty, "Location Update : %lu attach, %lu normal, %lu periodic%s", + counter_get(net->stats.loc_upd_type.attach), + counter_get(net->stats.loc_upd_type.normal), + counter_get(net->stats.loc_upd_type.periodic), VTY_NEWLINE); + vty_out(vty, "IMSI Detach Indications : %lu%s", + counter_get(net->stats.loc_upd_type.detach), VTY_NEWLINE); + vty_out(vty, "Location Update Response: %lu accept, %lu reject%s", + counter_get(net->stats.loc_upd_resp.accept), + counter_get(net->stats.loc_upd_resp.reject), VTY_NEWLINE); + vty_out(vty, "Handover : %lu attempted, %lu no_channel, %lu timeout, " + "%lu completed, %lu failed%s", + counter_get(net->stats.handover.attempted), + counter_get(net->stats.handover.no_channel), + counter_get(net->stats.handover.timeout), + counter_get(net->stats.handover.completed), + counter_get(net->stats.handover.failed), VTY_NEWLINE); + vty_out(vty, "SMS MO : %lu submitted, %lu no receiver%s", + counter_get(net->stats.sms.submitted), + counter_get(net->stats.sms.no_receiver), VTY_NEWLINE); + vty_out(vty, "SMS MT : %lu delivered, %lu no memory, %lu other error%s", + counter_get(net->stats.sms.delivered), + counter_get(net->stats.sms.rp_err_mem), + counter_get(net->stats.sms.rp_err_other), VTY_NEWLINE); + return CMD_SUCCESS; +} + + int bsc_vty_init_extra(struct gsm_network *net) { gsmnet = net; @@ -517,6 +553,7 @@ int bsc_vty_init_extra(struct gsm_network *net) install_element(VIEW_NODE, &subscriber_silent_sms_cmd); install_element(VIEW_NODE, &subscriber_silent_call_start_cmd); install_element(VIEW_NODE, &subscriber_silent_call_stop_cmd); + install_element(VIEW_NODE, &show_stats_cmd); install_element(CONFIG_NODE, &cfg_subscr_cmd); install_node(&subscr_node, dummy_config_write); -- cgit v1.2.3 From 7daa01c434a20fa497a41393e53b894c7f1ed364 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Sat, 17 Apr 2010 05:14:36 +0200 Subject: gsm0808: Add the TLV definition for some of the 0808 IEs --- src/gsm0808.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/gsm0808.c b/src/gsm0808.c index ea772b4c9..67e622884 100644 --- a/src/gsm0808.c +++ b/src/gsm0808.c @@ -186,3 +186,31 @@ struct msgb *gsm0808_create_assignment_failure(uint8_t cause, uint8_t *rr_cause) msg->l3h[1] = msgb_l3len(msg) - 2; return msg; } + +static const struct tlv_definition bss_att_tlvdef = { + .def = { + [GSM0808_IE_IMSI] = { TLV_TYPE_TLV }, + [GSM0808_IE_TMSI] = { TLV_TYPE_TLV }, + [GSM0808_IE_CELL_IDENTIFIER_LIST] = { TLV_TYPE_TLV }, + [GSM0808_IE_CHANNEL_NEEDED] = { TLV_TYPE_TV }, + [GSM0808_IE_EMLPP_PRIORITY] = { TLV_TYPE_TV }, + [GSM0808_IE_CHANNEL_TYPE] = { TLV_TYPE_TLV }, + [GSM0808_IE_PRIORITY] = { TLV_TYPE_TLV }, + [GSM0808_IE_CIRCUIT_IDENTITY_CODE] = { TLV_TYPE_TV }, + [GSM0808_IE_DOWNLINK_DTX_FLAG] = { TLV_TYPE_TV }, + [GSM0808_IE_INTERFERENCE_BAND_TO_USE] = { TLV_TYPE_TV }, + [GSM0808_IE_CLASSMARK_INFORMATION_T2] = { TLV_TYPE_TLV }, + [GSM0808_IE_GROUP_CALL_REFERENCE] = { TLV_TYPE_TLV }, + [GSM0808_IE_TALKER_FLAG] = { TLV_TYPE_T }, + [GSM0808_IE_CONFIG_EVO_INDI] = { TLV_TYPE_TV }, + [GSM0808_IE_LSA_ACCESS_CTRL_SUPPR] = { TLV_TYPE_TV }, + [GSM0808_IE_SERVICE_HANDOVER] = { TLV_TYPE_TV}, + [GSM0808_IE_ENCRYPTION_INFORMATION] = { TLV_TYPE_TLV }, + [GSM0808_IE_CIPHER_RESPONSE_MODE] = { TLV_TYPE_TV }, + }, +}; + +const struct tlv_definition *gsm0808_att_tlvdef() +{ + return &bss_att_tlvdef; +} -- cgit v1.2.3 From 81716d5fa865acebcf632549cb6979d6ffaeebb8 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Sat, 17 Apr 2010 06:16:35 +0200 Subject: gsm0808: Port cipher_complete to be part of libosmocore. --- include/osmocore/gsm0808.h | 2 +- src/gsm0808.c | 31 +++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/include/osmocore/gsm0808.h b/include/osmocore/gsm0808.h index 0ea78da47..65c665046 100644 --- a/include/osmocore/gsm0808.h +++ b/include/osmocore/gsm0808.h @@ -27,6 +27,7 @@ struct msgb; struct msgb *gsm0808_create_layer3(struct msgb *msg, uint16_t netcode, uint16_t countrycode, int lac, int ci); struct msgb *gsm0808_create_reset(void); struct msgb *gsm0808_create_clear_complete(void); +struct msgb *gsm0808_create_cipher_complete(struct msgb *layer3, uint8_t alg_id); struct msgb *gsm0808_create_cipher_reject(uint8_t cause); struct msgb *gsm0808_create_classmark_update(const uint8_t *classmark, uint8_t length); struct msgb *gsm0808_create_sapi_reject(uint8_t link_id); @@ -37,7 +38,6 @@ const struct tlv_definition *gsm0808_att_tlvdef(); /* needs to be ported */ #if 0 struct msgb *bssmap_create_assignment_completed(struct gsm_lchan *lchan, uint8_t rr_cause); -struct msgb *bssmap_create_cipher_complete(struct msgb *layer3); #endif #endif diff --git a/src/gsm0808.c b/src/gsm0808.c index 67e622884..ab32a8308 100644 --- a/src/gsm0808.c +++ b/src/gsm0808.c @@ -103,6 +103,37 @@ struct msgb *gsm0808_create_clear_complete(void) return msg; } +struct msgb *gsm0808_create_cipher_complete(struct msgb *layer3, uint8_t alg_id) +{ + struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM, + "cipher-complete"); + if (!msg) + return NULL; + + /* send response with BSS override for A5/1... cheating */ + msg->l3h = msgb_put(msg, 3); + msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT; + msg->l3h[1] = 0xff; + msg->l3h[2] = BSS_MAP_MSG_CIPHER_MODE_COMPLETE; + + /* include layer3 in case we have at least two octets */ + if (layer3 && msgb_l3len(layer3) > 2) { + msg->l4h = msgb_put(msg, msgb_l3len(layer3) + 2); + msg->l4h[0] = GSM0808_IE_LAYER_3_MESSAGE_CONTENTS; + msg->l4h[1] = msgb_l3len(layer3); + memcpy(&msg->l4h[2], layer3->l3h, msgb_l3len(layer3)); + } + + /* and the optional BSS message */ + msg->l4h = msgb_put(msg, 2); + msg->l4h[0] = GSM0808_IE_CHOSEN_ENCR_ALG; + msg->l4h[1] = alg_id; + + /* update the size */ + msg->l3h[1] = msgb_l3len(msg) - 2; + return msg; +} + struct msgb *gsm0808_create_cipher_reject(uint8_t cause) { struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM, -- cgit v1.2.3 From ba6172a7fd3e4fcb609ca1e0ac693022e4810dad Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Sat, 17 Apr 2010 06:21:49 +0200 Subject: gsm0808: Port asiggnment_complete msg creation to libosmocore. --- include/osmocore/gsm0808.h | 8 +++----- src/gsm0808.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 5 deletions(-) diff --git a/include/osmocore/gsm0808.h b/include/osmocore/gsm0808.h index 65c665046..a40713f77 100644 --- a/include/osmocore/gsm0808.h +++ b/include/osmocore/gsm0808.h @@ -31,13 +31,11 @@ struct msgb *gsm0808_create_cipher_complete(struct msgb *layer3, uint8_t alg_id) struct msgb *gsm0808_create_cipher_reject(uint8_t cause); struct msgb *gsm0808_create_classmark_update(const uint8_t *classmark, uint8_t length); struct msgb *gsm0808_create_sapi_reject(uint8_t link_id); +struct msgb *gsm0808_create_assignment_completed(struct gsm_lchan *lchan, uint8_t rr_cause, + uint8_t chosen_channel, uint8_t encr_alg_id, + uint8_t speech_mode); struct msgb *gsm0808_create_assignment_failure(uint8_t cause, uint8_t *rr_cause); const struct tlv_definition *gsm0808_att_tlvdef(); -/* needs to be ported */ -#if 0 -struct msgb *bssmap_create_assignment_completed(struct gsm_lchan *lchan, uint8_t rr_cause); -#endif - #endif diff --git a/src/gsm0808.c b/src/gsm0808.c index ab32a8308..9f6f0059d 100644 --- a/src/gsm0808.c +++ b/src/gsm0808.c @@ -187,6 +187,54 @@ struct msgb *gsm0808_create_sapi_reject(uint8_t link_id) return msg; } +struct msgb *gsm0808_create_assignment_completed(struct gsm_lchan *lchan, uint8_t rr_cause, + uint8_t chosen_channel, uint8_t encr_alg_id, + uint8_t speech_mode) +{ + u_int8_t *data; + + struct msgb *msg = msgb_alloc(35, "bssmap: ass compl"); + if (!msg) + return NULL; + + msg->l3h = msgb_put(msg, 3); + msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT; + msg->l3h[1] = 0xff; + msg->l3h[2] = BSS_MAP_MSG_ASSIGMENT_COMPLETE; + + /* write 3.2.2.22 */ + data = msgb_put(msg, 2); + data[0] = GSM0808_IE_RR_CAUSE; + data[1] = rr_cause; + + /* write cirtcuit identity code 3.2.2.2 */ + /* write cell identifier 3.2.2.17 */ + /* write chosen channel 3.2.2.33 when BTS picked it */ + data = msgb_put(msg, 2); + data[0] = GSM0808_IE_CHOSEN_CHANNEL; + data[1] = chosen_channel; + + /* write chosen encryption algorithm 3.2.2.44 */ + data = msgb_put(msg, 2); + data[0] = GSM0808_IE_CHOSEN_ENCR_ALG; + data[1] = encr_alg_id; + + /* write circuit pool 3.2.2.45 */ + /* write speech version chosen: 3.2.2.51 when BTS picked it */ + if (speech_mode != 0) { + data = msgb_put(msg, 2); + data[0] = GSM0808_IE_SPEECH_VERSION; + data[1] = speech_mode; + } + + /* write LSA identifier 3.2.2.15 */ + + + /* update the size */ + msg->l3h[1] = msgb_l3len(msg) - 2; + return msg; +} + struct msgb *gsm0808_create_assignment_failure(uint8_t cause, uint8_t *rr_cause) { uint8_t *data; -- cgit v1.2.3 From 2ba40afc36c1abfa4b0777fb5dc4eb6ac8179d3a Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Sat, 17 Apr 2010 06:42:07 +0200 Subject: Add rf_locked to the configuration writing. --- openbsc/src/vty_interface.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c index bcf4a87ff..2f8c1b3e0 100644 --- a/openbsc/src/vty_interface.c +++ b/openbsc/src/vty_interface.c @@ -266,6 +266,9 @@ static void config_write_trx_single(struct vty *vty, struct gsm_bts_trx *trx) int i; vty_out(vty, " trx %u%s", trx->nr, VTY_NEWLINE); + vty_out(vty, " rf_locked %u%s", + trx->nm_state.administrative == NM_STATE_LOCKED ? 1 : 0, + VTY_NEWLINE); vty_out(vty, " arfcn %u%s", trx->arfcn, VTY_NEWLINE); vty_out(vty, " nominal power %u%s", trx->nominal_power, VTY_NEWLINE); vty_out(vty, " max_power_red %u%s", trx->max_power_red, VTY_NEWLINE); -- cgit v1.2.3 From 3ba36d5b57f5964b9bdc2fd1e5ee7d0d9fd398dd Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Sat, 17 Apr 2010 06:48:29 +0200 Subject: [statistics] Keep track of rf failures and rll release failures Add two new counters to count the RF Failures and the RLL Release failure and make them available via the vty interface. --- openbsc/include/openbsc/gsm_data.h | 4 ++++ openbsc/src/abis_rsl.c | 5 ++++- openbsc/src/gsm_data.c | 2 ++ openbsc/src/vty_interface_cmds.c | 3 +++ 4 files changed, 13 insertions(+), 1 deletion(-) diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index 68d3deebf..2db98de97 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -535,6 +535,10 @@ struct gsmnet_stats { struct counter *alerted; /* we alerted the other end */ struct counter *connected;/* how many calls were accepted */ } call; + struct { + struct counter *rf_fail; + struct counter *rll_err; + } chan; }; enum gsm_auth_policy { diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c index 343347aa5..bbce67a96 100644 --- a/openbsc/src/abis_rsl.c +++ b/openbsc/src/abis_rsl.c @@ -810,6 +810,7 @@ static int rsl_rx_conn_fail(struct msgb *msg) LOGPC(DRSL, LOGL_NOTICE, "\n"); /* FIXME: only free it after channel release ACK */ + counter_inc(msg->lchan->ts->trx->bts->network->stats.chan.rf_fail); return rsl_rf_chan_release(msg->lchan); } @@ -1245,8 +1246,10 @@ static int rsl_rx_rll_err_ind(struct msgb *msg) rll_indication(msg->lchan, rllh->link_id, BSC_RLLR_IND_ERR_IND); - if (rlm_cause[1] == RLL_CAUSE_T200_EXPIRED) + if (rlm_cause[1] == RLL_CAUSE_T200_EXPIRED) { + counter_inc(msg->lchan->ts->trx->bts->network->stats.chan.rll_err); return rsl_rf_chan_release(msg->lchan); + } return 0; } diff --git a/openbsc/src/gsm_data.c b/openbsc/src/gsm_data.c index 176367dc7..f837c2709 100644 --- a/openbsc/src/gsm_data.c +++ b/openbsc/src/gsm_data.c @@ -280,6 +280,8 @@ struct gsm_network *gsm_network_init(u_int16_t country_code, u_int16_t network_c net->stats.call.dialled = counter_alloc("net.call.dialled"); net->stats.call.alerted = counter_alloc("net.call.alerted"); net->stats.call.connected = counter_alloc("net.call.connected"); + net->stats.chan.rf_fail = counter_alloc("net.chan.rf_fail"); + net->stats.chan.rll_err = counter_alloc("net.chan.rll_err"); net->mncc_recv = mncc_recv; diff --git a/openbsc/src/vty_interface_cmds.c b/openbsc/src/vty_interface_cmds.c index 623aa30df..8ade51851 100644 --- a/openbsc/src/vty_interface_cmds.c +++ b/openbsc/src/vty_interface_cmds.c @@ -233,6 +233,9 @@ void openbsc_vty_print_statistics(struct vty *vty, struct gsm_network *net) vty_out(vty, "Channel Requests : %lu total, %lu no channel%s", counter_get(net->stats.chreq.total), counter_get(net->stats.chreq.no_channel), VTY_NEWLINE); + vty_out(vty, "Channel Failures : %lu rf_failures, %lu rll failures%s", + counter_get(net->stats.chan.rf_fail), + counter_get(net->stats.chan.rll_err), VTY_NEWLINE); vty_out(vty, "Paging : %lu attempted, %lu complete, %lu expired%s", counter_get(net->stats.paging.attempted), counter_get(net->stats.paging.completed), -- cgit v1.2.3 From bb110f91e8fd5c190f974ef3b9cb9a1118beb592 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Mon, 12 Apr 2010 10:45:52 +0200 Subject: [statistics] Keep track of OML/RSL failures of the BTS. --- openbsc/include/openbsc/gsm_data.h | 4 ++++ openbsc/src/bsc_init.c | 5 +++++ openbsc/src/gsm_data.c | 2 ++ openbsc/src/vty_interface_cmds.c | 3 +++ 4 files changed, 14 insertions(+) diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index 2db98de97..a2f0e406c 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -539,6 +539,10 @@ struct gsmnet_stats { struct counter *rf_fail; struct counter *rll_err; } chan; + struct { + struct counter *oml_fail; + struct counter *rsl_fail; + } bts; }; enum gsm_auth_policy { diff --git a/openbsc/src/bsc_init.c b/openbsc/src/bsc_init.c index fccdb0cd8..94576b796 100644 --- a/openbsc/src/bsc_init.c +++ b/openbsc/src/bsc_init.c @@ -918,6 +918,11 @@ void input_event(int event, enum e1inp_sign_type type, struct gsm_bts_trx *trx) case EVT_E1_TEI_DN: LOGP(DMI, LOGL_ERROR, "Lost some E1 TEI link: %d %p\n", type, trx); + if (type == E1INP_SIGN_OML) + counter_inc(trx->bts->network->stats.bts.oml_fail); + else if (type == E1INP_SIGN_RSL) + counter_inc(trx->bts->network->stats.bts.rsl_fail); + /* * free all allocated channels. change the nm_state so the * trx and trx_ts becomes unusable and chan_alloc.c can not diff --git a/openbsc/src/gsm_data.c b/openbsc/src/gsm_data.c index f837c2709..4af46e487 100644 --- a/openbsc/src/gsm_data.c +++ b/openbsc/src/gsm_data.c @@ -282,6 +282,8 @@ struct gsm_network *gsm_network_init(u_int16_t country_code, u_int16_t network_c net->stats.call.connected = counter_alloc("net.call.connected"); net->stats.chan.rf_fail = counter_alloc("net.chan.rf_fail"); net->stats.chan.rll_err = counter_alloc("net.chan.rll_err"); + net->stats.bts.oml_fail = counter_alloc("net.bts.oml_fail"); + net->stats.bts.rsl_fail = counter_alloc("net.bts.rsl_fail"); net->mncc_recv = mncc_recv; diff --git a/openbsc/src/vty_interface_cmds.c b/openbsc/src/vty_interface_cmds.c index 8ade51851..671351e1c 100644 --- a/openbsc/src/vty_interface_cmds.c +++ b/openbsc/src/vty_interface_cmds.c @@ -240,6 +240,9 @@ void openbsc_vty_print_statistics(struct vty *vty, struct gsm_network *net) counter_get(net->stats.paging.attempted), counter_get(net->stats.paging.completed), counter_get(net->stats.paging.expired), VTY_NEWLINE); + vty_out(vty, "BTS failures : %lu OML, %lu RSL%s", + counter_get(net->stats.bts.oml_fail), + counter_get(net->stats.bts.rsl_fail), VTY_NEWLINE); } void openbsc_vty_add_cmds() -- cgit v1.2.3 From 6ba3bcbbc69050f1a336c416db7a42d90b2948b0 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 16 Mar 2010 00:56:08 +0800 Subject: BVCI 0 is not within the permitted range --- openbsc/src/vty_interface.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c index 2f8c1b3e0..e5290c98f 100644 --- a/openbsc/src/vty_interface.c +++ b/openbsc/src/vty_interface.c @@ -1392,7 +1392,7 @@ DEFUN(cfg_bts_per_loc_upd, cfg_bts_per_loc_upd_cmd, } DEFUN(cfg_bts_prs_bvci, cfg_bts_gprs_bvci_cmd, - "gprs cell bvci <0-65535>", + "gprs cell bvci <1-65535>", "GPRS BSSGP VC Identifier") { struct gsm_bts *bts = vty->index; -- cgit v1.2.3 From 57ba7e30936ccb5ea2e341113d2eb9810ce42e20 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 18 Apr 2010 14:00:26 +0200 Subject: GPRS: BVCI 0 and 1 are not permitted. According to TS 08.18, BVCI=0 is for the SIGNALLING entity, and BVCI=1 is for the PTM entity. Both should not be used by the PTP entity that we're configuring here. --- openbsc/src/vty_interface.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c index e5290c98f..2f034e74a 100644 --- a/openbsc/src/vty_interface.c +++ b/openbsc/src/vty_interface.c @@ -1392,7 +1392,7 @@ DEFUN(cfg_bts_per_loc_upd, cfg_bts_per_loc_upd_cmd, } DEFUN(cfg_bts_prs_bvci, cfg_bts_gprs_bvci_cmd, - "gprs cell bvci <1-65535>", + "gprs cell bvci <2-65535>", "GPRS BSSGP VC Identifier") { struct gsm_bts *bts = vty->index; -- cgit v1.2.3 From ad9f7830fbb7d7a1d5eb7810bad5d808c0856a8d Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 18 Apr 2010 21:08:26 +0200 Subject: update the openbts.cfg.nanobts example --- openbsc/src/openbsc.cfg.nanobts | 41 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 38 insertions(+), 3 deletions(-) diff --git a/openbsc/src/openbsc.cfg.nanobts b/openbsc/src/openbsc.cfg.nanobts index a1ceaec79..4c5cf805a 100644 --- a/openbsc/src/openbsc.cfg.nanobts +++ b/openbsc/src/openbsc.cfg.nanobts @@ -1,6 +1,6 @@ ! ! OpenBSC configuration saved from vty -! +! ! password foo ! line vty @@ -11,17 +11,52 @@ network mobile network code 1 short name OpenBSC long name OpenBSC + auth policy closed + location updating reject cause 13 + encryption a5 0 + neci 0 + rrlp mode none + mm info 1 + handover 0 + handover window rxlev averaging 10 + handover window rxqual averaging 1 + handover window rxlev neighbor averaging 10 + handover power budget interval 6 + handover power budget hysteresis 3 + handover maximum distance 9999 timer t3101 10 + timer t3103 0 + timer t3105 0 + timer t3107 0 + timer t3109 0 + timer t3111 0 timer t3113 60 + timer t3115 0 + timer t3117 0 + timer t3119 0 + timer t3141 0 bts 0 type nanobts - ip.access unit_id 1801 0 - band GSM1800 + band DCS1800 + cell_identity 0 location_area_code 1 training_sequence_code 7 base_station_id_code 63 + ms max power 15 + cell reselection hysteresis 4 + rxlev access min 0 + channel allocator ascending + rach tx integer 9 + rach max transmission 7 + ip.access unit_id 1801 0 + oml ip.access stream_id 255 + gprs enabled 0 trx 0 + rf_locked 0 arfcn 514 + nominal power 23 + max_power_red 20 + rsl e1 tei 0 timeslot 0 phys_chan_config CCCH+SDCCH4 timeslot 1 -- cgit v1.2.3 From 2c57232489d8551a54741b883bcc39b527602b1b Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 18 Apr 2010 21:25:18 +0200 Subject: add an example config file for nanoBTS multi-trx case --- openbsc/src/openbsc.cfg.nanobts.multitrx | 97 ++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 openbsc/src/openbsc.cfg.nanobts.multitrx diff --git a/openbsc/src/openbsc.cfg.nanobts.multitrx b/openbsc/src/openbsc.cfg.nanobts.multitrx new file mode 100644 index 000000000..2bd6e3f0b --- /dev/null +++ b/openbsc/src/openbsc.cfg.nanobts.multitrx @@ -0,0 +1,97 @@ +! +! OpenBSC configuration saved from vty +! ! +password foo +! +line vty + no login +! +network + network country code 1 + mobile network code 1 + short name OpenBSC + long name OpenBSC + auth policy closed + location updating reject cause 13 + encryption a5 0 + neci 0 + rrlp mode none + mm info 0 + handover 0 + handover window rxlev averaging 10 + handover window rxqual averaging 1 + handover window rxlev neighbor averaging 10 + handover power budget interval 6 + handover power budget hysteresis 3 + handover maximum distance 9999 + timer t3101 10 + timer t3103 0 + timer t3105 0 + timer t3107 0 + timer t3109 0 + timer t3111 0 + timer t3113 60 + timer t3115 0 + timer t3117 0 + timer t3119 0 + timer t3141 0 + bts 0 + type nanobts + band DCS1800 + cell_identity 0 + location_area_code 1 + training_sequence_code 7 + base_station_id_code 63 + ms max power 15 + cell reselection hysteresis 4 + rxlev access min 0 + channel allocator ascending + rach tx integer 9 + rach max transmission 7 + ip.access unit_id 1800 0 + oml ip.access stream_id 255 + gprs enabled 0 + trx 0 + rf_locked 0 + arfcn 871 + nominal power 23 + max_power_red 0 + rsl e1 tei 0 + timeslot 0 + phys_chan_config CCCH+SDCCH4 + timeslot 1 + phys_chan_config SDCCH8 + timeslot 2 + phys_chan_config TCH/F + timeslot 3 + phys_chan_config TCH/F + timeslot 4 + phys_chan_config TCH/F + timeslot 5 + phys_chan_config TCH/F + timeslot 6 + phys_chan_config TCH/F + timeslot 7 + phys_chan_config TCH/F + trx 1 + rf_locked 0 + arfcn 873 + nominal power 23 + max_power_red 0 + rsl e1 tei 0 + timeslot 0 + phys_chan_config CCCH+SDCCH4 + timeslot 1 + phys_chan_config SDCCH8 + timeslot 2 + phys_chan_config TCH/F + timeslot 3 + phys_chan_config TCH/F + timeslot 4 + phys_chan_config TCH/F + timeslot 5 + phys_chan_config TCH/F + timeslot 6 + phys_chan_config TCH/F + timeslot 7 + phys_chan_config TCH/F -- cgit v1.2.3 From da0586a83810f43b061f7b12ad079b264bc03781 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 18 Apr 2010 14:49:05 +0200 Subject: GPRS: Add Support for the GPRS Cell Option Extension Info IE Extension Information is part of the GPRS Cell Options IE, as specified in Chapter 12.24 of TS 04.60. It is needed for indicating EDGE capabilities of the BTS to the MS. This simply adds the code to encode this IE as part of SI13, but does not actually use the code yet. --- openbsc/include/openbsc/rest_octets.h | 11 +++++++++++ openbsc/src/rest_octets.c | 27 +++++++++++++++++++++++++-- openbsc/src/system_information.c | 10 ++++++++++ 3 files changed, 46 insertions(+), 2 deletions(-) diff --git a/openbsc/include/openbsc/rest_octets.h b/openbsc/include/openbsc/rest_octets.h index 4e72c0f87..6d9011963 100644 --- a/openbsc/include/openbsc/rest_octets.h +++ b/openbsc/include/openbsc/rest_octets.h @@ -71,6 +71,7 @@ enum gprs_nmo { GPRS_NMO_III = 2, /* no paging coordination */ }; +/* TS 04.60 12.24 */ struct gprs_cell_options { enum gprs_nmo nmo; /* T3168: wait for packet uplink assignment message */ @@ -79,6 +80,16 @@ struct gprs_cell_options { u_int32_t t3192; /* in milliseconds */ u_int32_t drx_timer_max;/* in seconds */ u_int32_t bs_cv_max; + + u_int8_t ext_info_present; + struct { + u_int8_t egprs_supported; + u_int8_t use_egprs_p_ch_req; + u_int8_t bep_period; + u_int8_t pfc_supported; + u_int8_t dtm_supported; + u_int8_t bss_paging_coordination; + } ext_info; }; /* TS 04.60 Table 12.9.2 */ diff --git a/openbsc/src/rest_octets.c b/openbsc/src/rest_octets.c index df27cf21e..0aac8d51f 100644 --- a/openbsc/src/rest_octets.c +++ b/openbsc/src/rest_octets.c @@ -319,8 +319,31 @@ static int append_gprs_cell_opt(struct bitvec *bv, /* hard-code no PAN_{DEC,INC,MAX} */ bitvec_set_bit(bv, 0); - /* no extension information (EDGE) */ - bitvec_set_bit(bv, 0); + if (!gco->ext_info_present) { + /* no extension information */ + bitvec_set_bit(bv, 0); + } else { + /* extension information */ + bitvec_set_bit(bv, 1); + if (!gco->ext_info.egprs_supported) { + /* 6bit length of extension */ + bitvec_set_uint(bv, 1 + 3, 6); + /* EGPRS supported in the cell */ + bitvec_set_bit(bv, 0); + } else { + /* 6bit length of extension */ + bitvec_set_uint(bv, 1 + 5 + 3, 6); + /* EGPRS supported in the cell */ + bitvec_set_bit(bv, 1); + /* 1bit EGPRS PACKET CHANNEL REQUEST */ + bitvec_set_bit(bv, gco->ext_info.use_egprs_p_ch_req); + /* 4bit BEP PERIOD */ + bitvec_set_uint(bv, gco->ext_info.bep_period, 4); + } + bitvec_set_bit(bv, gco->ext_info.pfc_supported); + bitvec_set_bit(bv, gco->ext_info.dtm_supported); + bitvec_set_bit(bv, gco->ext_info.bss_paging_coordination); + } return 0; } diff --git a/openbsc/src/system_information.c b/openbsc/src/system_information.c index 3f9d60954..de0e287c9 100644 --- a/openbsc/src/system_information.c +++ b/openbsc/src/system_information.c @@ -402,6 +402,16 @@ static struct gsm48_si13_info si13_default = { .t3192 = 500, .drx_timer_max = 3, .bs_cv_max = 15, + .ext_info_present = 0, + .ext_info = { + /* The values below are just guesses ! */ + .egprs_supported = 1, + .use_egprs_p_ch_req = 1, + .bep_period = 4, + .pfc_supported = 0, + .dtm_supported = 0, + .bss_paging_coordination = 0, + }, }, .pwr_ctrl_pars = { .alpha = 10, /* a = 1.0 */ -- cgit v1.2.3 From 4511d891ddf221eeea32d33f6199fa76c17df9c3 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 18 Apr 2010 15:51:20 +0200 Subject: GPRS: change 'gprs enabled <0-1>' to 'gprs mode (none|gprs|egprs)' This causes some config file breakage but sounds like a much cleaner approach than to have two separate config variables for this. --- openbsc/include/openbsc/gsm_data.h | 11 ++++++++++- openbsc/src/bsc_init.c | 8 ++++---- openbsc/src/gsm_data.c | 17 +++++++++++++++++ openbsc/src/system_information.c | 10 +++++++++- openbsc/src/vty_interface.c | 29 +++++++++++++++-------------- 5 files changed, 55 insertions(+), 20 deletions(-) diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index a2f0e406c..52b82c062 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -73,6 +73,12 @@ enum gsm_paging_event { GSM_PAGING_OOM, }; +enum bts_gprs_mode { + BTS_GPRS_NONE = 0, + BTS_GPRS_GPRS = 1, + BTS_GPRS_EGPRS = 2, +}; + struct msgb; typedef int gsm_cbfn(unsigned int hooknum, unsigned int event, @@ -476,7 +482,7 @@ struct gsm_bts { /* Not entirely sure how ip.access specific this is */ struct { - int enabled; + enum bts_gprs_mode mode; struct { struct gsm_nm_state nm_state; u_int16_t nsei; @@ -705,6 +711,9 @@ const char *gsm_auth_policy_name(enum gsm_auth_policy policy); enum rrlp_mode rrlp_mode_parse(const char *arg); const char *rrlp_mode_name(enum rrlp_mode mode); +enum bts_gprs_mode bts_gprs_mode_parse(const char *arg); +const char *bts_gprs_mode_name(enum bts_gprs_mode mode); + void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked); /* A parsed GPRS routing area */ diff --git a/openbsc/src/bsc_init.c b/openbsc/src/bsc_init.c index 94576b796..1711aeb13 100644 --- a/openbsc/src/bsc_init.c +++ b/openbsc/src/bsc_init.c @@ -462,7 +462,7 @@ int nm_state_event(enum nm_evt evt, u_int8_t obj_class, void *obj, break; case NM_OC_GPRS_NSE: bts = container_of(obj, struct gsm_bts, gprs.nse); - if (!bts->gprs.enabled) + if (bts->gprs.mode == BTS_GPRS_NONE) break; if (new_state->availability == 5) { abis_nm_ipaccess_set_attr(bts, obj_class, bts->bts_nr, @@ -476,7 +476,7 @@ int nm_state_event(enum nm_evt evt, u_int8_t obj_class, void *obj, break; case NM_OC_GPRS_CELL: bts = container_of(obj, struct gsm_bts, gprs.cell); - if (!bts->gprs.enabled) + if (bts->gprs.mode == BTS_GPRS_NONE) break; if (new_state->availability == 5) { abis_nm_ipaccess_set_attr(bts, obj_class, bts->bts_nr, @@ -491,7 +491,7 @@ int nm_state_event(enum nm_evt evt, u_int8_t obj_class, void *obj, case NM_OC_GPRS_NSVC: nsvc = obj; bts = nsvc->bts; - if (!bts->gprs.enabled) + if (bts->gprs.mode == BTS_GPRS_NONE) break; /* We skip NSVC1 since we only use NSVC0 */ if (nsvc->id == 1) @@ -799,7 +799,7 @@ static int set_system_infos(struct gsm_bts_trx *trx) DEBUGP(DRR, "SI%2u: %s\n", i, hexdump(si_tmp, rc)); rsl_bcch_info(trx, i, si_tmp, sizeof(si_tmp)); } - if (bts->gprs.enabled) { + if (bts->gprs.mode != BTS_GPRS_NONE) { i = 13; rc = gsm_generate_si(si_tmp, trx->bts, RSL_SYSTEM_INFO_13); if (rc < 0) diff --git a/openbsc/src/gsm_data.c b/openbsc/src/gsm_data.c index 4af46e487..4d8fa1747 100644 --- a/openbsc/src/gsm_data.c +++ b/openbsc/src/gsm_data.c @@ -502,6 +502,23 @@ const char *rrlp_mode_name(enum rrlp_mode mode) return get_value_string(rrlp_mode_names, mode); } +static const struct value_string bts_gprs_mode_names[] = { + { BTS_GPRS_NONE, "none" }, + { BTS_GPRS_GPRS, "gprs" }, + { BTS_GPRS_EGPRS, "egprs" }, + { 0, NULL } +}; + +enum bts_gprs_mode bts_gprs_mode_parse(const char *arg) +{ + return get_string_value(bts_gprs_mode_names, arg); +} + +const char *bts_gprs_mode_name(enum bts_gprs_mode mode) +{ + return get_value_string(bts_gprs_mode_names, mode); +} + struct gsm_meas_rep *lchan_next_meas_rep(struct gsm_lchan *lchan) { struct gsm_meas_rep *meas_rep; diff --git a/openbsc/src/system_information.c b/openbsc/src/system_information.c index de0e287c9..8072ba2d4 100644 --- a/openbsc/src/system_information.c +++ b/openbsc/src/system_information.c @@ -458,7 +458,15 @@ static int generate_si13(u_int8_t *output, struct gsm_bts *bts) int gsm_generate_si(u_int8_t *output, struct gsm_bts *bts, int type) { - si_info.gprs_ind.present = bts->gprs.enabled; + switch (bts->gprs.mode) { + case BTS_GPRS_EGPRS: + case BTS_GPRS_GPRS: + si_info.gprs_ind.present = 1; + break; + case BTS_GPRS_NONE: + si_info.gprs_ind.present = 0; + break; + } switch (type) { case RSL_SYSTEM_INFO_1: diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c index 2f034e74a..dd35372ca 100644 --- a/openbsc/src/vty_interface.c +++ b/openbsc/src/vty_interface.c @@ -318,8 +318,9 @@ static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts) config_write_e1_link(vty, &bts->oml_e1_link, " oml "); vty_out(vty, " oml e1 tei %u%s", bts->oml_tei, VTY_NEWLINE); } - vty_out(vty, " gprs enabled %u%s", bts->gprs.enabled, VTY_NEWLINE); - if (bts->gprs.enabled) { + vty_out(vty, " gprs mode %s%s", bts_gprs_mode_name(bts->gprs.mode), + VTY_NEWLINE); + if (bts->gprs.mode != BTS_GPRS_NONE) { vty_out(vty, " gprs routing area %u%s", bts->gprs.rac, VTY_NEWLINE); vty_out(vty, " gprs cell bvci %u%s", bts->gprs.cell.bvci, @@ -1397,7 +1398,7 @@ DEFUN(cfg_bts_prs_bvci, cfg_bts_gprs_bvci_cmd, { struct gsm_bts *bts = vty->index; - if (!bts->gprs.enabled) { + if (bts->gprs.mode == BTS_GPRS_NONE) { vty_out(vty, "%% GPRS not enabled on this BTS%s", VTY_NEWLINE); return CMD_WARNING; } @@ -1413,7 +1414,7 @@ DEFUN(cfg_bts_gprs_nsei, cfg_bts_gprs_nsei_cmd, { struct gsm_bts *bts = vty->index; - if (!bts->gprs.enabled) { + if (bts->gprs.mode == BTS_GPRS_NONE) { vty_out(vty, "%% GPRS not enabled on this BTS%s", VTY_NEWLINE); return CMD_WARNING; } @@ -1431,7 +1432,7 @@ DEFUN(cfg_bts_gprs_nsvci, cfg_bts_gprs_nsvci_cmd, struct gsm_bts *bts = vty->index; int idx = atoi(argv[0]); - if (!bts->gprs.enabled) { + if (bts->gprs.mode == BTS_GPRS_NONE) { vty_out(vty, "%% GPRS not enabled on this BTS%s", VTY_NEWLINE); return CMD_WARNING; } @@ -1448,7 +1449,7 @@ DEFUN(cfg_bts_gprs_nsvc_lport, cfg_bts_gprs_nsvc_lport_cmd, struct gsm_bts *bts = vty->index; int idx = atoi(argv[0]); - if (!bts->gprs.enabled) { + if (bts->gprs.mode == BTS_GPRS_NONE) { vty_out(vty, "%% GPRS not enabled on this BTS%s", VTY_NEWLINE); return CMD_WARNING; } @@ -1465,7 +1466,7 @@ DEFUN(cfg_bts_gprs_nsvc_rport, cfg_bts_gprs_nsvc_rport_cmd, struct gsm_bts *bts = vty->index; int idx = atoi(argv[0]); - if (!bts->gprs.enabled) { + if (bts->gprs.mode == BTS_GPRS_NONE) { vty_out(vty, "%% GPRS not enabled on this BTS%s", VTY_NEWLINE); return CMD_WARNING; } @@ -1483,7 +1484,7 @@ DEFUN(cfg_bts_gprs_nsvc_rip, cfg_bts_gprs_nsvc_rip_cmd, int idx = atoi(argv[0]); struct in_addr ia; - if (!bts->gprs.enabled) { + if (bts->gprs.mode == BTS_GPRS_NONE) { vty_out(vty, "%% GPRS not enabled on this BTS%s", VTY_NEWLINE); return CMD_WARNING; } @@ -1500,7 +1501,7 @@ DEFUN(cfg_bts_gprs_rac, cfg_bts_gprs_rac_cmd, { struct gsm_bts *bts = vty->index; - if (!bts->gprs.enabled) { + if (bts->gprs.mode == BTS_GPRS_NONE) { vty_out(vty, "%% GPRS not enabled on this BTS%s", VTY_NEWLINE); return CMD_WARNING; } @@ -1510,13 +1511,13 @@ DEFUN(cfg_bts_gprs_rac, cfg_bts_gprs_rac_cmd, return CMD_SUCCESS; } -DEFUN(cfg_bts_gprs_enabled, cfg_bts_gprs_enabled_cmd, - "gprs enabled <0-1>", - "GPRS Enabled on this BTS") +DEFUN(cfg_bts_gprs_mode, cfg_bts_gprs_mode_cmd, + "gprs mode (none|gprs|egprs)", + "GPRS Mode for this BTS") { struct gsm_bts *bts = vty->index; - bts->gprs.enabled = atoi(argv[0]); + bts->gprs.mode = bts_gprs_mode_parse(argv[0]); return CMD_SUCCESS; } @@ -1775,7 +1776,7 @@ int bsc_vty_init(struct gsm_network *net) install_element(BTS_NODE, &cfg_bts_per_loc_upd_cmd); install_element(BTS_NODE, &cfg_bts_cell_resel_hyst_cmd); install_element(BTS_NODE, &cfg_bts_rxlev_acc_min_cmd); - install_element(BTS_NODE, &cfg_bts_gprs_enabled_cmd); + install_element(BTS_NODE, &cfg_bts_gprs_mode_cmd); install_element(BTS_NODE, &cfg_bts_gprs_rac_cmd); install_element(BTS_NODE, &cfg_bts_gprs_bvci_cmd); install_element(BTS_NODE, &cfg_bts_gprs_nsei_cmd); -- cgit v1.2.3 From a06fea020d593f79337b4582bddebe9c9c3593cc Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 18 Apr 2010 15:53:40 +0200 Subject: GPRS: actually enable indicating EDGE capability in SI13 --- openbsc/src/system_information.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/openbsc/src/system_information.c b/openbsc/src/system_information.c index 8072ba2d4..3bd833a93 100644 --- a/openbsc/src/system_information.c +++ b/openbsc/src/system_information.c @@ -405,7 +405,7 @@ static struct gsm48_si13_info si13_default = { .ext_info_present = 0, .ext_info = { /* The values below are just guesses ! */ - .egprs_supported = 1, + .egprs_supported = 0, .use_egprs_p_ch_req = 1, .bep_period = 4, .pfc_supported = 0, @@ -460,6 +460,9 @@ int gsm_generate_si(u_int8_t *output, struct gsm_bts *bts, int type) { switch (bts->gprs.mode) { case BTS_GPRS_EGPRS: + si13_default.cell_opts.ext_info_present = 1; + si13_default.cell_opts.ext_info.egprs_supported = 1; + /* fallthrough */ case BTS_GPRS_GPRS: si_info.gprs_ind.present = 1; break; -- cgit v1.2.3 From 439bb828f9568bfd6272ac82b4b36b7efe55f060 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 18 Apr 2010 16:50:11 +0200 Subject: GPRS: Enable EGPRS coding schemes in Cell Attributes if 'gprs mode egprs' --- openbsc/src/bsc_init.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/openbsc/src/bsc_init.c b/openbsc/src/bsc_init.c index 1711aeb13..a39bc198a 100644 --- a/openbsc/src/bsc_init.c +++ b/openbsc/src/bsc_init.c @@ -378,11 +378,11 @@ static unsigned char nanobts_attr_cell[] = { 4, /* N3103 */ 8, /* N3105 */ 15, /* RLC CV countdown */ - NM_ATT_IPACC_CODING_SCHEMES, 0, 2, 0x0f, 0x00, + NM_ATT_IPACC_CODING_SCHEMES, 0, 2, 0x0f, 0x00, /* CS1..CS4 */ NM_ATT_IPACC_RLC_CFG_2, 0, 5, - 0x00, 250, - 0x00, 250, - 2, /* MCS2 */ + 0x00, 250, /* T downlink TBF extension (0..500) */ + 0x00, 250, /* T uplink TBF extension (0..500) */ + 2, /* CS2 */ #if 0 /* EDGE model only, breaks older models. * Should inquire the BTS capabilities */ @@ -886,6 +886,11 @@ static void patch_nm_tables(struct gsm_bts *bts) /* patch RAC */ nanobts_attr_cell[3] = bts->gprs.rac; + if (bts->gprs.mode == BTS_GPRS_EGPRS) { + /* patch EGPRS coding schemes MCS 1..9 */ + nanobts_attr_cell[29] = 0x8f; + nanobts_attr_cell[30] = 0xff; + } } static void bootstrap_rsl(struct gsm_bts_trx *trx) -- cgit v1.2.3 From 18038180927c9ffd3f8f1da18bada698e6afcefb Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 18 Apr 2010 21:33:00 +0200 Subject: update openbsc.cfg examples for new gprs syntax --- openbsc/src/openbsc.cfg.nanobts | 2 +- openbsc/src/openbsc.cfg.nanobts.multitrx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/openbsc/src/openbsc.cfg.nanobts b/openbsc/src/openbsc.cfg.nanobts index 4c5cf805a..da0ba74e1 100644 --- a/openbsc/src/openbsc.cfg.nanobts +++ b/openbsc/src/openbsc.cfg.nanobts @@ -50,7 +50,7 @@ network rach max transmission 7 ip.access unit_id 1801 0 oml ip.access stream_id 255 - gprs enabled 0 + gprs mode none trx 0 rf_locked 0 arfcn 514 diff --git a/openbsc/src/openbsc.cfg.nanobts.multitrx b/openbsc/src/openbsc.cfg.nanobts.multitrx index 2bd6e3f0b..d9fb54b49 100644 --- a/openbsc/src/openbsc.cfg.nanobts.multitrx +++ b/openbsc/src/openbsc.cfg.nanobts.multitrx @@ -50,7 +50,7 @@ network rach max transmission 7 ip.access unit_id 1800 0 oml ip.access stream_id 255 - gprs enabled 0 + gprs mode none trx 0 rf_locked 0 arfcn 871 -- cgit v1.2.3 From 5fda90816f0623b32ddb60f1cf4d9d67119de811 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 18 Apr 2010 22:41:01 +0200 Subject: GPRS: Indicate the SGSN is Release 99 as this is the first with EDGE --- openbsc/src/rest_octets.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/openbsc/src/rest_octets.c b/openbsc/src/rest_octets.c index 0aac8d51f..fd56caf81 100644 --- a/openbsc/src/rest_octets.c +++ b/openbsc/src/rest_octets.c @@ -358,7 +358,7 @@ static void append_gprs_pwr_ctrl_pars(struct bitvec *bv, bitvec_set_uint(bv, pcp->n_avg_i, 4); } -/* Generate SI13 Rest Octests (Chapter 10.5.2.37b) */ +/* Generate SI13 Rest Octests (04.08 Chapter 10.5.2.37b) */ int rest_octets_si13(u_int8_t *data, const struct gsm48_si13_info *si13) { struct bitvec bv; @@ -414,6 +414,11 @@ int rest_octets_si13(u_int8_t *data, const struct gsm48_si13_info *si13) break; } } + /* 3GPP TS 44.018 Release 6 / 10.5.2.37b */ + bitvec_set_bit(&bv, H); /* added Release 99 */ + /* claim our SGSN is compatible with Release 99, as EDGE and EGPRS + * was only added in this Release */ + bitvec_set_bit(&bv, 1); } bitvec_spare_padding(&bv, (bv.data_len*8)-1); return bv.data_len; -- cgit v1.2.3 From 39608dc04557ac050de6a05a6d41239fc18d9eb8 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 18 Apr 2010 22:47:22 +0200 Subject: GPRS: Fix calculation of 'Extension Length' in GPRS Cell Options The actual 'Extension Length' field in the 'GPRS Cell Options' IE is coded the length - 1, not the full length. Without this fix, the code has an off-by-one error. --- openbsc/src/rest_octets.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openbsc/src/rest_octets.c b/openbsc/src/rest_octets.c index fd56caf81..039d2c83a 100644 --- a/openbsc/src/rest_octets.c +++ b/openbsc/src/rest_octets.c @@ -327,12 +327,12 @@ static int append_gprs_cell_opt(struct bitvec *bv, bitvec_set_bit(bv, 1); if (!gco->ext_info.egprs_supported) { /* 6bit length of extension */ - bitvec_set_uint(bv, 1 + 3, 6); + bitvec_set_uint(bv, (1 + 3)-1, 6); /* EGPRS supported in the cell */ bitvec_set_bit(bv, 0); } else { /* 6bit length of extension */ - bitvec_set_uint(bv, 1 + 5 + 3, 6); + bitvec_set_uint(bv, (1 + 5 + 3)-1, 6); /* EGPRS supported in the cell */ bitvec_set_bit(bv, 1); /* 1bit EGPRS PACKET CHANNEL REQUEST */ -- cgit v1.2.3 From 38e9c821143a9b86227ae02b1830de43b67facab Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 19 Apr 2010 10:24:07 +0200 Subject: RSL: inmplement ip.access paging load indication 'below threshold' This is an ip.access specific 08.58 oddity. It reports 0xffff available paging buffers if the paging load is below the 12.21 CCCH LOAD INDICATION THRESHOLD. We use 50, since that is what it reports if the threshold == 0. --- openbsc/src/abis_rsl.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c index bbce67a96..53b29823e 100644 --- a/openbsc/src/abis_rsl.c +++ b/openbsc/src/abis_rsl.c @@ -1187,6 +1187,10 @@ static int rsl_rx_ccch_load(struct msgb *msg) switch (rslh->data[0]) { case RSL_IE_PAGING_LOAD: pg_buf_space = rslh->data[1] << 8 | rslh->data[2]; + if (is_ipaccess_bts(msg->trx->bts) && pg_buf_space == 0xffff) { + /* paging load below configured threshold, use 50 as default */ + pg_buf_space = 50; + } paging_update_buffer_space(msg->trx->bts, pg_buf_space); break; case RSL_IE_RACH_LOAD: -- cgit v1.2.3 From 2fb7ccf95f381534d08710bc5064ce1423a87384 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Wed, 21 Apr 2010 20:37:53 +0800 Subject: wireshark: Fix the patches and rebase against a recent wireshark version My previous attempt to only add the hunks I changed broke the format of the patch and this time I am just dumping my current patch on top of these patches. --- wireshark/abis_oml.patch | 37 ++++++++++++----- wireshark/rsl-ipaccess.patch | 96 +++++++++++++++++++++++++------------------- 2 files changed, 81 insertions(+), 52 deletions(-) diff --git a/wireshark/abis_oml.patch b/wireshark/abis_oml.patch index 9f06b4d82..40132110e 100644 --- a/wireshark/abis_oml.patch +++ b/wireshark/abis_oml.patch @@ -1,8 +1,21 @@ -Index: wireshark/epan/dissectors/Makefile.common -=================================================================== ---- wireshark.orig/epan/dissectors/Makefile.common -+++ wireshark/epan/dissectors/Makefile.common -@@ -474,6 +474,7 @@ +From 5857518be87641fdab45e593bc9fd5ef5595e619 Mon Sep 17 00:00:00 2001 +From: Holger Hans Peter Freyther +Date: Mon, 19 Apr 2010 13:23:51 +0800 +Subject: [PATCH 1/2] Add the Abis OML patch. + +--- + epan/dissectors/Makefile.common | 1 + + epan/dissectors/packet-gsm_abis_oml.c | 1382 +++++++++++++++++++++++++++++++++ + epan/dissectors/packet-gsm_abis_oml.h | 787 +++++++++++++++++++ + 3 files changed, 2170 insertions(+), 0 deletions(-) + create mode 100644 epan/dissectors/packet-gsm_abis_oml.c + create mode 100644 epan/dissectors/packet-gsm_abis_oml.h + +diff --git a/epan/dissectors/Makefile.common b/epan/dissectors/Makefile.common +index dbc3726..98dcdc3 100644 +--- a/epan/dissectors/Makefile.common ++++ b/epan/dissectors/Makefile.common +@@ -481,6 +481,7 @@ DISSECTOR_SRC = \ packet-gsm_a_gm.c \ packet-gsm_a_rp.c \ packet-gsm_a_rr.c \ @@ -12,7 +25,7 @@ Index: wireshark/epan/dissectors/Makefile.common packet-gsm_bssmap_le.c \ diff --git a/epan/dissectors/packet-gsm_abis_oml.c b/epan/dissectors/packet-gsm_abis_oml.c new file mode 100644 -index 0000000..2de9dca +index 0000000..fa46ab5 --- /dev/null +++ b/epan/dissectors/packet-gsm_abis_oml.c @@ -0,0 +1,1382 @@ @@ -1398,11 +1411,12 @@ index 0000000..2de9dca + abis_oml_handle = create_dissector_handle(dissect_abis_oml, proto_abis_oml); + dissector_add("lapd.gsm.sapi", LAPD_GSM_SAPI_OM_PROC, abis_oml_handle); +} -Index: wireshark/epan/dissectors/packet-gsm_abis_oml.h -=================================================================== +diff --git a/epan/dissectors/packet-gsm_abis_oml.h b/epan/dissectors/packet-gsm_abis_oml.h +new file mode 100644 +index 0000000..d523e96 --- /dev/null -+++ wireshark/epan/dissectors/packet-gsm_abis_oml.h -@@ -0,0 +1,786 @@ ++++ b/epan/dissectors/packet-gsm_abis_oml.h +@@ -0,0 +1,787 @@ +/* GSM Network Management messages on the A-bis interface + * 3GPP TS 12.21 version 8.0.0 Release 1999 / ETSI TS 100 623 V8.0.0 */ + @@ -2190,3 +2204,6 @@ Index: wireshark/epan/dissectors/packet-gsm_abis_oml.h +}; + +#endif /* _NM_H */ +-- +1.7.0.1 + diff --git a/wireshark/rsl-ipaccess.patch b/wireshark/rsl-ipaccess.patch index 36c09c57b..29220b87b 100644 --- a/wireshark/rsl-ipaccess.patch +++ b/wireshark/rsl-ipaccess.patch @@ -1,16 +1,25 @@ -Index: wireshark/epan/dissectors/packet-rsl.c -=================================================================== ---- wireshark.orig/epan/dissectors/packet-rsl.c 2009-10-21 23:03:41.000000000 +0200 -+++ wireshark/epan/dissectors/packet-rsl.c 2009-10-22 10:02:51.000000000 +0200 +From 8f35d623641dbba90e6186604c11e892bf515ecc Mon Sep 17 00:00:00 2001 +From: Holger Hans Peter Freyther +Date: Mon, 19 Apr 2010 13:32:58 +0800 +Subject: [PATCH 2/2] RSL patch + +--- + epan/dissectors/packet-rsl.c | 522 +++++++++++++++++++++++++++++++++++++++++- + 1 files changed, 515 insertions(+), 7 deletions(-) + +diff --git a/epan/dissectors/packet-rsl.c b/epan/dissectors/packet-rsl.c +index b10a671..a455cf3 100644 +--- a/epan/dissectors/packet-rsl.c ++++ b/epan/dissectors/packet-rsl.c @@ -2,6 +2,7 @@ * Routines for Radio Signalling Link (RSL) dissection. * * Copyright 2007, Anders Broman + * Copyright 2009, Harald Welte * - * $Id: packet-rsl.c 29944 2009-09-16 13:39:37Z morriss $ + * $Id$ * -@@ -44,6 +45,8 @@ +@@ -42,6 +43,8 @@ #include #include "packet-gsm_a_common.h" @@ -19,7 +28,7 @@ Index: wireshark/epan/dissectors/packet-rsl.c /* Initialize the protocol and registered fields */ static int proto_rsl = -1; -@@ -117,6 +120,24 @@ +@@ -115,6 +118,24 @@ static int hf_rsl_emlpp_prio = -1; static int hf_rsl_rtd = -1; static int hf_rsl_delay_ind = -1; static int hf_rsl_tfo = -1; @@ -44,7 +53,7 @@ Index: wireshark/epan/dissectors/packet-rsl.c /* Initialize the subtree pointers */ static int ett_rsl = -1; -@@ -174,6 +195,15 @@ +@@ -172,6 +193,15 @@ static int ett_ie_cause = -1; static int ett_ie_meas_res_no = -1; static int ett_ie_message_id = -1; static int ett_ie_sys_info_type = -1; @@ -60,7 +69,7 @@ Index: wireshark/epan/dissectors/packet-rsl.c proto_tree *top_tree; dissector_handle_t gsm_a_ccch_handle; -@@ -209,8 +239,11 @@ +@@ -207,8 +237,11 @@ static const value_string rsl_msg_disc_vals[] = { { 0x06, "Common Channel Management messages" }, { 0x08, "TRX Management messages" }, { 0x16, "Location Services messages" }, @@ -72,7 +81,7 @@ Index: wireshark/epan/dissectors/packet-rsl.c /* * 9.2 MESSAGE TYPE */ -@@ -277,6 +310,49 @@ +@@ -275,6 +308,49 @@ static const value_string rsl_msg_disc_vals[] = { /* 0 1 - - - - - - Location Services messages: */ #define RSL_MSG_LOC_INF 65 /* 8.7.1 */ @@ -90,16 +99,16 @@ Index: wireshark/epan/dissectors/packet-rsl.c +#define RSL_MSG_TYPE_IPAC_PDCH_DEACT_ACK 0x4c +#define RSL_MSG_TYPE_IPAC_PDCH_DEACT_NACK 0x4d + -+#define RSL_MSG_TYPE_IPAC_BIND 0x70 -+#define RSL_MSG_TYPE_IPAC_BIND_ACK 0x71 -+#define RSL_MSG_TYPE_IPAC_BIND_NACK 0x72 -+#define RSL_MSG_TYPE_IPAC_CONNECT 0x73 -+#define RSL_MSG_TYPE_IPAC_CONNECT_ACK 0x74 -+#define RSL_MSG_TYPE_IPAC_CONNECT_NACK 0x75 -+#define RSL_MSG_TYPE_IPAC_DISC_IND 0x76 -+#define RSL_MSG_TYPE_IPAC_DISC 0x77 -+#define RSL_MSG_TYPE_IPAC_DISC_ACK 0x78 -+#define RSL_MSG_TYPE_IPAC_DISC_NACK 0x79 ++#define RSL_MSG_TYPE_IPAC_CRCX 0x70 ++#define RSL_MSG_TYPE_IPAC_CRCX_ACK 0x71 ++#define RSL_MSG_TYPE_IPAC_CRCX_NACK 0x72 ++#define RSL_MSG_TYPE_IPAC_MDCX 0x73 ++#define RSL_MSG_TYPE_IPAC_MDCX_ACK 0x74 ++#define RSL_MSG_TYPE_IPAC_MDCX_NACK 0x75 ++#define RSL_MSG_TYPE_IPAC_DLCX_IND 0x76 ++#define RSL_MSG_TYPE_IPAC_DLCX 0x77 ++#define RSL_MSG_TYPE_IPAC_DLCX_ACK 0x78 ++#define RSL_MSG_TYPE_IPAC_DLCX_NACK 0x79 + +#define RSL_IE_IPAC_SRTP_CONFIG 0xe0 +#define RSL_IE_IPAC_PROXY_UDP 0xe1 @@ -122,7 +131,7 @@ Index: wireshark/epan/dissectors/packet-rsl.c static const value_string rsl_msg_type_vals[] = { /* 0 0 0 0 - - - - Radio Link Layer Management messages: */ -@@ -339,6 +415,26 @@ +@@ -337,6 +413,26 @@ static const value_string rsl_msg_type_vals[] = { { 0x3f, "TFO MODification REQuest" }, /* 8.4.31 */ /* 0 1 - - - - - - Location Services messages: */ { 0x41, "Location Information" }, /* 8.7.1 */ @@ -149,7 +158,7 @@ Index: wireshark/epan/dissectors/packet-rsl.c { 0, NULL } }; -@@ -372,10 +468,10 @@ static const value_string rsl_msg_type_vals[] = { +@@ -370,10 +466,10 @@ static const value_string rsl_msg_type_vals[] = { #define RSL_IE_MESSAGE_ID 28 #define RSL_IE_SYS_INFO_TYPE 30 @@ -164,7 +173,7 @@ Index: wireshark/epan/dissectors/packet-rsl.c #define RSL_IE_FULL_IMM_ASS_INF 35 #define RSL_IE_SMSCB_INF 36 #define RSL_IE_FULL_MS_TIMING_OFFSET 37 -@@ -478,6 +574,24 @@ +@@ -476,6 +572,24 @@ static const value_string rsl_ie_type_vals[] = { Not used */ @@ -189,7 +198,7 @@ Index: wireshark/epan/dissectors/packet-rsl.c { 0, NULL } }; -@@ -514,6 +628,96 @@ +@@ -512,6 +626,96 @@ static const value_string rsl_ch_no_Cbits_vals[] = { { 0, NULL } }; @@ -286,7 +295,7 @@ Index: wireshark/epan/dissectors/packet-rsl.c /* 9.3.1 Channel number 9.3.1 M TV 2 */ static int dissect_rsl_ie_ch_no(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree, int offset, gboolean is_mandatory) -@@ -2044,7 +2248,6 @@ +@@ -2042,7 +2246,6 @@ dissect_rsl_ie_err_msg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int proto_item_set_len(ti, length+2); proto_tree_add_item(ie_tree, hf_rsl_ie_length, tvb, offset, 1, FALSE); @@ -294,7 +303,7 @@ Index: wireshark/epan/dissectors/packet-rsl.c /* Received Message */ offset = dissct_rsl_msg(tvb, pinfo, ie_tree, offset); -@@ -2909,12 +3112,183 @@ +@@ -2907,12 +3110,184 @@ dissect_rsl_ie_tfo_transp_cont(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree } static int @@ -310,16 +319,16 @@ Index: wireshark/epan/dissectors/packet-rsl.c + +#if 0 + switch (msg_type) { -+ case RSL_MSG_TYPE_IPAC_BIND: -+ case RSL_MSG_TYPE_IPAC_BIND_ACK: -+ case RSL_MSG_TYPE_IPAC_BIND_NACK: -+ case RSL_MSG_TYPE_IPAC_CONNECT: -+ case RSL_MSG_TYPE_IPAC_CONNECT_ACK: -+ case RSL_MSG_TYPE_IPAC_CONNECT_NACK: -+ case RSL_MSG_TYPE_IPAC_DISC_IND: -+ case RSL_MSG_TYPE_IPAC_DISC: -+ case RSL_MSG_TYPE_IPAC_DISC_ACK: -+ case RSL_MSG_TYPE_IPAC_DISC_NACK: ++ case RSL_MSG_TYPE_IPAC_CRCX: ++ case RSL_MSG_TYPE_IPAC_CRCX_ACK: ++ case RSL_MSG_TYPE_IPAC_CRCX_NACK: ++ case RSL_MSG_TYPE_IPAC_MDCX: ++ case RSL_MSG_TYPE_IPAC_MDCX_ACK: ++ case RSL_MSG_TYPE_IPAC_MDCX_NACK: ++ case RSL_MSG_TYPE_IPAC_DLCX_IND: ++ case RSL_MSG_TYPE_IPAC_DLCX: ++ case RSL_MSG_TYPE_IPAC_DLCX_ACK: ++ case RSL_MSG_TYPE_IPAC_DLCX_NACK: + case RSL_MSG_TYPE_IPAC_PDCH_ACT: + case RSL_MSG_TYPE_IPAC_PDCH_ACT_ACK: + case RSL_MSG_TYPE_IPAC_PDCH_ACT_NACK: @@ -449,7 +458,7 @@ Index: wireshark/epan/dissectors/packet-rsl.c + } + + switch (msg_type) { -+ case RSL_MSG_TYPE_IPAC_BIND_ACK: ++ case RSL_MSG_TYPE_IPAC_CRCX_ACK: + /* Notify the RTP and RTCP dissectors about a new RTP stream */ + src_addr.type = AT_IPv4; + src_addr.len = 4; @@ -480,7 +489,7 @@ Index: wireshark/epan/dissectors/packet-rsl.c offset++; switch (msg_type){ -@@ -3482,6 +3856,18 @@ +@@ -3480,6 +3855,18 @@ dissct_rsl_msg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset) /* LLP APDU 9.3.58 M LV 2-N */ offset = dissect_rsl_ie_llp_apdu(tvb, pinfo, tree, offset, TRUE); break; @@ -499,7 +508,7 @@ Index: wireshark/epan/dissectors/packet-rsl.c default: break; } -@@ -3489,6 +3875,40 @@ +@@ -3487,6 +3874,40 @@ dissct_rsl_msg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset) return offset; } @@ -540,7 +549,7 @@ Index: wireshark/epan/dissectors/packet-rsl.c static void dissect_rsl(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) { -@@ -3516,7 +3936,6 @@ +@@ -3514,7 +3935,6 @@ dissect_rsl(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) /* 9.1 Message discriminator */ proto_tree_add_item(rsl_tree, hf_rsl_msg_dsc, tvb, offset, 1, FALSE); proto_tree_add_item(rsl_tree, hf_rsl_T_bit, tvb, offset, 1, FALSE); @@ -548,7 +557,7 @@ Index: wireshark/epan/dissectors/packet-rsl.c offset = dissct_rsl_msg(tvb, pinfo, rsl_tree, offset); -@@ -3886,6 +4305,86 @@ +@@ -3884,6 +4304,86 @@ void proto_register_rsl(void) FT_UINT8, BASE_DEC, VALS(rsl_emlpp_prio_vals), 0x03, NULL, HFILL } }, @@ -635,7 +644,7 @@ Index: wireshark/epan/dissectors/packet-rsl.c }; static gint *ett[] = { &ett_rsl, -@@ -3943,6 +4442,14 @@ +@@ -3941,6 +4441,14 @@ void proto_register_rsl(void) &ett_ie_meas_res_no, &ett_ie_message_id, &ett_ie_sys_info_type, @@ -650,3 +659,6 @@ Index: wireshark/epan/dissectors/packet-rsl.c }; /* Register the protocol name and description */ +-- +1.7.0.1 + -- cgit v1.2.3 From 2cdda72b3c79458e91e0ce96995ad0e546c8a79b Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Wed, 21 Apr 2010 15:38:16 +0800 Subject: [sccp] Parse the error message and add a unit test for it. --- openbsc/include/sccp/sccp_types.h | 6 ++++++ openbsc/src/sccp/sccp.c | 20 ++++++++++++++++++++ openbsc/tests/sccp/sccp_test.c | 21 ++++++++++++++++++++- 3 files changed, 46 insertions(+), 1 deletion(-) diff --git a/openbsc/include/sccp/sccp_types.h b/openbsc/include/sccp/sccp_types.h index 42fda96ae..22bd70f21 100644 --- a/openbsc/include/sccp/sccp_types.h +++ b/openbsc/include/sccp/sccp_types.h @@ -411,4 +411,10 @@ struct sccp_data_it { u_int8_t credit; } __attribute__((packed)); +struct sccp_proto_err { + u_int8_t type; + struct sccp_source_reference destination_local_reference; + u_int8_t error_cause; +}; + #endif diff --git a/openbsc/src/sccp/sccp.c b/openbsc/src/sccp/sccp.c index e0fd02e0e..d869bfaeb 100644 --- a/openbsc/src/sccp/sccp.c +++ b/openbsc/src/sccp/sccp.c @@ -490,6 +490,23 @@ static int _sccp_parse_it(struct msgb *msgb, struct sccp_parse_result *result) return 0; } +static int _sccp_parse_err(struct msgb *msgb, struct sccp_parse_result *result) +{ + static const u_int32_t header_size = sizeof(struct sccp_proto_err); + + struct sccp_proto_err *err; + + if (msgb_l2len(msgb) < header_size) { + LOGP(DSCCP, LOGL_ERROR, "msgb < header_size %u %u\n", + msgb_l2len(msgb), header_size); + return -1; + } + + err = (struct sccp_proto_err *) msgb->l2h; + result->data_len = 0; + result->destination_local_reference = &err->destination_local_reference; + return 0; +} /* * Send UDT. Currently we have a fixed address... @@ -1318,6 +1335,9 @@ int sccp_parse_header(struct msgb *msg, struct sccp_parse_result *result) case SCCP_MSG_TYPE_IT: return _sccp_parse_it(msg, result); break; + case SCCP_MSG_TYPE_ERR: + return _sccp_parse_err(msg, result); + break; }; LOGP(DSCCP, LOGL_ERROR, "Unimplemented MSG Type: 0x%x\n", type); diff --git a/openbsc/tests/sccp/sccp_test.c b/openbsc/tests/sccp/sccp_test.c index 0c2adc83f..31eb47f9f 100644 --- a/openbsc/tests/sccp/sccp_test.c +++ b/openbsc/tests/sccp/sccp_test.c @@ -264,6 +264,10 @@ static const u_int8_t it_test[] = { 0x10, 0x01, 0x07, 0x94, 0x01, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00 }; +static const u_int8_t proto_err[] = { +0x0f, 0x0c, 0x04, 0x00, 0x00, +}; + static const struct sccp_parse_header_result parse_result[] = { { .msg_type = SCCP_MSG_TYPE_IT, @@ -287,6 +291,21 @@ static const struct sccp_parse_header_result parse_result[] = { .input = it_test, .input_len = sizeof(it_test), }, + { + .msg_type = SCCP_MSG_TYPE_ERR, + .wanted_len = 0, + .src_ssn = -1, + .dst_ssn = -1, + .has_src_ref = 0, + .has_dst_ref = 1, + .dst_ref = { + .octet1 = 0x0c, + .octet2 = 0x04, + .octet3 = 0x00, + }, + .input = proto_err, + .input_len = sizeof(proto_err), + }, }; @@ -777,7 +796,7 @@ static void test_sccp_parsing(void) memset(&result, 0, sizeof(result)); if (sccp_parse_header(msg, &result) != 0) { - fprintf(stderr, "Failed to parse test: %d\n", current_test); + fprintf(stderr, "Failed to sccp parse test: %d\n", current_test); } else { if (parse_result[current_test].wanted_len != result.data_len) { fprintf(stderr, "Unexpected data length.\n"); -- cgit v1.2.3 From 277f035dee8e851732174fa41e261854fade4674 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Wed, 21 Apr 2010 21:08:58 +0800 Subject: [sccp] Move from DEBUGP to LOGP in sccp.c --- openbsc/src/sccp/sccp.c | 106 ++++++++++++++++++++++++------------------------ 1 file changed, 54 insertions(+), 52 deletions(-) diff --git a/openbsc/src/sccp/sccp.c b/openbsc/src/sccp/sccp.c index d869bfaeb..de18614c3 100644 --- a/openbsc/src/sccp/sccp.c +++ b/openbsc/src/sccp/sccp.c @@ -81,7 +81,7 @@ static struct sccp_data_callback *_find_ssn(u_int8_t ssn) /* need to add one */ cb = talloc_zero(tall_sccp_ctx, struct sccp_data_callback); if (!cb) { - DEBUGP(DSCCP, "Failed to allocate sccp callback.\n"); + LOGP(DSCCP, LOGL_ERROR, "Failed to allocate sccp callback.\n"); return NULL; } @@ -108,13 +108,13 @@ static int copy_address(struct sccp_address *addr, u_int8_t offset, struct msgb u_int8_t length; if (room <= 0) { - DEBUGP(DSCCP, "Not enough room for an address: %u\n", room); + LOGP(DSCCP, LOGL_ERROR, "Not enough room for an address: %u\n", room); return -1; } length = msgb->l2h[offset]; if (room <= length) { - DEBUGP(DSCCP, "Not enough room for optional data %u %u\n", room, length); + LOGP(DSCCP, LOGL_ERROR, "Not enough room for optional data %u %u\n", room, length); return -1; } @@ -122,7 +122,7 @@ static int copy_address(struct sccp_address *addr, u_int8_t offset, struct msgb party = (struct sccp_called_party_address *)(msgb->l2h + offset + 1); if (party->point_code_indicator) { if (length <= read + 2) { - DEBUGP(DSCCP, "POI does not fit %u\n", length); + LOGP(DSCCP, LOGL_ERROR, "POI does not fit %u\n", length); return -1; } @@ -133,7 +133,7 @@ static int copy_address(struct sccp_address *addr, u_int8_t offset, struct msgb if (party->ssn_indicator) { if (length <= read + 1) { - DEBUGP(DSCCP, "SSN does not fit %u\n", length); + LOGP(DSCCP, LOGL_ERROR, "SSN does not fit %u\n", length); return -1; } @@ -142,7 +142,7 @@ static int copy_address(struct sccp_address *addr, u_int8_t offset, struct msgb } if (party->global_title_indicator) { - DEBUGP(DSCCP, "GTI not supported %u\n", *(u_int8_t *)party); + LOGP(DSCCP, LOGL_ERROR, "GTI not supported %u\n", *(u_int8_t *)party); return -1; } @@ -156,7 +156,8 @@ static int check_address(struct sccp_address *addr) if (addr->address.ssn_indicator != 1 || addr->address.global_title_indicator == 1 || addr->address.routing_indicator != 1) { - DEBUGP(DSCCP, "Invalid called address according to 08.06: 0x%x 0x%x\n", + LOGP(DSCCP, LOGL_ERROR, + "Invalid called address according to 08.06: 0x%x 0x%x\n", *(u_int8_t *)&addr->address, addr->ssn); return -1; } @@ -176,7 +177,7 @@ static int _sccp_parse_optional_data(const int offset, return 0; if (read + 1 >= room) { - DEBUGP(DSCCP, "no place for length\n"); + LOGP(DSCCP, LOGL_ERROR, "no place for length\n"); return 0; } @@ -185,7 +186,8 @@ static int _sccp_parse_optional_data(const int offset, if (room <= read) { - DEBUGP(DSCCP, "no space for the data: type: %d read: %d room: %d l2: %d\n", + LOGP(DSCCP, LOGL_ERROR, + "no space for the data: type: %d read: %d room: %d l2: %d\n", type, read, room, msgb_l2len(msgb)); return 0; } @@ -214,7 +216,7 @@ int _sccp_parse_connection_request(struct msgb *msgb, struct sccp_parse_result * /* header check */ if (msgb_l2len(msgb) < header_size) { - DEBUGP(DSCCP, "msgb < header_size %u %u\n", + LOGP(DSCCP, LOGL_ERROR, "msgb < header_size %u %u\n", msgb_l2len(msgb), header_size); return -1; } @@ -224,7 +226,7 @@ int _sccp_parse_connection_request(struct msgb *msgb, struct sccp_parse_result * return -1; if (check_address(&result->called) != 0) { - DEBUGP(DSCCP, "Invalid called address according to 08.06: 0x%x 0x%x\n", + LOGP(DSCCP, LOGL_ERROR, "Invalid called address according to 08.06: 0x%x 0x%x\n", *(u_int8_t *)&result->called.address, result->called.ssn); return -1; } @@ -236,7 +238,7 @@ int _sccp_parse_connection_request(struct msgb *msgb, struct sccp_parse_result * */ memset(&optional_data, 0, sizeof(optional_data)); if (_sccp_parse_optional_data(optional_offset + req->optional_start, msgb, &optional_data) != 0) { - DEBUGP(DSCCP, "parsing of optional data failed.\n"); + LOGP(DSCCP, LOGL_ERROR, "parsing of optional data failed.\n"); return -1; } @@ -260,14 +262,14 @@ int _sccp_parse_connection_released(struct msgb *msgb, struct sccp_parse_result /* we don't have enough size for the struct */ if (msgb_l2len(msgb) < header_size) { - DEBUGP(DSCCP, "msgb > header_size %u %u\n", + LOGP(DSCCP, LOGL_ERROR, "msgb > header_size %u %u\n", msgb_l2len(msgb), header_size); return -1; } memset(&optional_data, 0, sizeof(optional_data)); if (_sccp_parse_optional_data(optional_offset + rls->optional_start, msgb, &optional_data) != 0) { - DEBUGP(DSCCP, "parsing of optional data failed.\n"); + LOGP(DSCCP, LOGL_ERROR, "parsing of optional data failed.\n"); return -1; } @@ -295,7 +297,7 @@ int _sccp_parse_connection_refused(struct msgb *msgb, struct sccp_parse_result * /* header check */ if (msgb_l2len(msgb) < header_size) { - DEBUGP(DSCCP, "msgb < header_size %u %u\n", + LOGP(DSCCP, LOGL_ERROR, "msgb < header_size %u %u\n", msgb_l2len(msgb), header_size); return -1; } @@ -306,7 +308,7 @@ int _sccp_parse_connection_refused(struct msgb *msgb, struct sccp_parse_result * memset(&optional_data, 0, sizeof(optional_data)); if (_sccp_parse_optional_data(optional_offset + ref->optional_start, msgb, &optional_data) != 0) { - DEBUGP(DSCCP, "parsing of optional data failed.\n"); + LOGP(DSCCP, LOGL_ERROR, "parsing of optional data failed.\n"); return -1; } @@ -333,7 +335,7 @@ int _sccp_parse_connection_confirm(struct msgb *msgb, struct sccp_parse_result * /* header check */ if (msgb_l2len(msgb) < header_size) { - DEBUGP(DSCCP, "msgb < header_size %u %u\n", + LOGP(DSCCP, LOGL_ERROR, "msgb < header_size %u %u\n", msgb_l2len(msgb), header_size); return -1; } @@ -344,7 +346,7 @@ int _sccp_parse_connection_confirm(struct msgb *msgb, struct sccp_parse_result * memset(&optional_data, 0, sizeof(optional_data)); if (_sccp_parse_optional_data(optional_offset + con->optional_start, msgb, &optional_data) != 0) { - DEBUGP(DSCCP, "parsing of optional data failed.\n"); + LOGP(DSCCP, LOGL_ERROR, "parsing of optional data failed.\n"); return -1; } @@ -366,7 +368,7 @@ int _sccp_parse_connection_release_complete(struct msgb *msgb, struct sccp_parse /* header check */ if (msgb_l2len(msgb) < header_size) { - DEBUGP(DSCCP, "msgb < header_size %u %u\n", + LOGP(DSCCP, LOGL_ERROR, "msgb < header_size %u %u\n", msgb_l2len(msgb), header_size); return -1; } @@ -387,13 +389,13 @@ int _sccp_parse_connection_dt1(struct msgb *msgb, struct sccp_parse_result *resu /* we don't have enough size for the struct */ if (msgb_l2len(msgb) < header_size) { - DEBUGP(DSCCP, "msgb > header_size %u %u\n", + LOGP(DSCCP, LOGL_ERROR, "msgb > header_size %u %u\n", msgb_l2len(msgb), header_size); return -1; } if (dt1->segmenting != 0) { - DEBUGP(DSCCP, "This packet has segmenting, not supported: %d\n", dt1->segmenting); + LOGP(DSCCP, LOGL_ERROR, "This packet has segmenting, not supported: %d\n", dt1->segmenting); return -1; } @@ -401,7 +403,7 @@ int _sccp_parse_connection_dt1(struct msgb *msgb, struct sccp_parse_result *resu /* some more size checks in here */ if (msgb_l2len(msgb) < variable_offset + dt1->variable_start + 1) { - DEBUGP(DSCCP, "Not enough space for variable start: %u %u\n", + LOGP(DSCCP, LOGL_ERROR, "Not enough space for variable start: %u %u\n", msgb_l2len(msgb), dt1->variable_start); return -1; } @@ -410,7 +412,7 @@ int _sccp_parse_connection_dt1(struct msgb *msgb, struct sccp_parse_result *resu msgb->l3h = &msgb->l2h[dt1->variable_start + variable_offset + 1]; if (msgb_l3len(msgb) < result->data_len) { - DEBUGP(DSCCP, "Not enough room for the payload: %u %u\n", + LOGP(DSCCP, LOGL_ERROR, "Not enough room for the payload: %u %u\n", msgb_l3len(msgb), result->data_len); return -1; } @@ -428,7 +430,7 @@ int _sccp_parse_udt(struct msgb *msgb, struct sccp_parse_result *result) struct sccp_data_unitdata *udt = (struct sccp_data_unitdata *)msgb->l2h; if (msgb_l2len(msgb) < header_size) { - DEBUGP(DSCCP, "msgb < header_size %u %u\n", + LOGP(DSCCP, LOGL_ERROR, "msgb < header_size %u %u\n", msgb_l2len(msgb), header_size); return -1; } @@ -438,7 +440,7 @@ int _sccp_parse_udt(struct msgb *msgb, struct sccp_parse_result *result) return -1; if (check_address(&result->called) != 0) { - DEBUGP(DSCCP, "Invalid called address according to 08.06: 0x%x 0x%x\n", + LOGP(DSCCP, LOGL_ERROR, "Invalid called address according to 08.06: 0x%x 0x%x\n", *(u_int8_t *)&result->called.address, result->called.ssn); return -1; } @@ -447,13 +449,13 @@ int _sccp_parse_udt(struct msgb *msgb, struct sccp_parse_result *result) return -1; if (check_address(&result->calling) != 0) { - DEBUGP(DSCCP, "Invalid called address according to 08.06: 0x%x 0x%x\n", + LOGP(DSCCP, LOGL_ERROR, "Invalid called address according to 08.06: 0x%x 0x%x\n", *(u_int8_t *)&result->called.address, result->called.ssn); } /* we don't have enough size for the data */ if (msgb_l2len(msgb) < data_offset + udt->variable_data + 1) { - DEBUGP(DSCCP, "msgb < header + offset %u %u %u\n", + LOGP(DSCCP, LOGL_ERROR, "msgb < header + offset %u %u %u\n", msgb_l2len(msgb), header_size, udt->variable_data); return -1; } @@ -463,7 +465,7 @@ int _sccp_parse_udt(struct msgb *msgb, struct sccp_parse_result *result) result->data_len = msgb_l3len(msgb); if (msgb_l3len(msgb) != msgb->l3h[-1]) { - DEBUGP(DSCCP, "msgb is truncated is: %u should: %u\n", + LOGP(DSCCP, LOGL_ERROR, "msgb is truncated is: %u should: %u\n", msgb_l3len(msgb), msgb->l3h[-1]); return -1; } @@ -478,7 +480,7 @@ static int _sccp_parse_it(struct msgb *msgb, struct sccp_parse_result *result) struct sccp_data_it *it; if (msgb_l2len(msgb) < header_size) { - DEBUGP(DSCCP, "msgb < header_size %u %u\n", + LOGP(DSCCP, LOGL_ERROR, "msgb < header_size %u %u\n", msgb_l2len(msgb), header_size); return -1; } @@ -518,7 +520,7 @@ static int _sccp_send_data(int class, const struct sockaddr_sccp *in, u_int8_t *data; if (msgb_l3len(payload) > 256) { - DEBUGP(DSCCP, "The payload is too big for one udt\n"); + LOGP(DSCCP, LOGL_ERROR, "The payload is too big for one udt\n"); return -1; } @@ -563,7 +565,7 @@ static int _sccp_handle_read(struct msgb *msgb) cb = _find_ssn(result.called.ssn); if (!cb || !cb->read_cb) { - DEBUGP(DSCCP, "No routing for UDT for called SSN: %u\n", result.called.ssn); + LOGP(DSCCP, LOGL_ERROR, "No routing for UDT for called SSN: %u\n", result.called.ssn); return -1; } @@ -612,7 +614,7 @@ static int assign_source_local_reference(struct sccp_connection *connection) ++last_ref; /* do not use the reversed word and wrap around */ if ((last_ref & 0x00FFFFFF) == 0x00FFFFFF) { - DEBUGP(DSCCP, "Wrapped searching for a free code\n"); + LOGP(DSCCP, LOGL_DEBUG, "Wrapped searching for a free code\n"); last_ref = 0; ++wrapped; } @@ -623,7 +625,7 @@ static int assign_source_local_reference(struct sccp_connection *connection) } } while (wrapped != 2); - DEBUGP(DSCCP, "Finding a free reference failed\n"); + LOGP(DSCCP, LOGL_ERROR, "Finding a free reference failed\n"); return -1; } @@ -703,13 +705,13 @@ static int _sccp_send_connection_request(struct sccp_connection *connection, if (msg && (msgb_l3len(msg) < 3 || msgb_l3len(msg) > 130)) { - DEBUGP(DSCCP, "Invalid amount of data... %d\n", msgb_l3len(msg)); + LOGP(DSCCP, LOGL_ERROR, "Invalid amount of data... %d\n", msgb_l3len(msg)); return -1; } /* try to find a id */ if (assign_source_local_reference(connection) != 0) { - DEBUGP(DSCCP, "Assigning a local reference failed.\n"); + LOGP(DSCCP, LOGL_ERROR, "Assigning a local reference failed.\n"); _sccp_set_connection_state(connection, SCCP_CONNECTION_STATE_SETUP_ERROR); return -1; } @@ -761,7 +763,7 @@ static int _sccp_send_connection_data(struct sccp_connection *conn, struct msgb int extra_size; if (msgb_l3len(_data) < 2 || msgb_l3len(_data) > 256) { - DEBUGP(DSCCP, "data size too big, segmenting unimplemented.\n"); + LOGP(DSCCP, LOGL_ERROR, "data size too big, segmenting unimplemented.\n"); return -1; } @@ -857,14 +859,14 @@ static int _sccp_handle_connection_request(struct msgb *msgb) cb = _find_ssn(result.called.ssn); if (!cb || !cb->accept_cb) { - DEBUGP(DSCCP, "No routing for CR for called SSN: %u\n", result.called.ssn); + LOGP(DSCCP, LOGL_ERROR, "No routing for CR for called SSN: %u\n", result.called.ssn); return -1; } /* check if the system wants this connection */ connection = talloc_zero(tall_sccp_ctx, struct sccp_connection); if (!connection) { - DEBUGP(DSCCP, "Allocation failed\n"); + LOGP(DSCCP, LOGL_ERROR, "Allocation failed\n"); return -1; } @@ -876,7 +878,7 @@ static int _sccp_handle_connection_request(struct msgb *msgb) * one.... */ if (destination_local_reference_is_free(result.source_local_reference) != 0) { - DEBUGP(DSCCP, "Need to reject connection with existing reference\n"); + LOGP(DSCCP, LOGL_ERROR, "Need to reject connection with existing reference\n"); _sccp_send_refuse(result.source_local_reference, SCCP_REFUSAL_SCCP_FAILURE); talloc_free(connection); return -1; @@ -896,7 +898,7 @@ static int _sccp_handle_connection_request(struct msgb *msgb) llist_add_tail(&connection->list, &sccp_connections); if (_sccp_send_connection_confirm(connection) != 0) { - DEBUGP(DSCCP, "Sending confirm failed... no available source reference?\n"); + LOGP(DSCCP, LOGL_ERROR, "Sending confirm failed... no available source reference?\n"); _sccp_send_refuse(result.source_local_reference, SCCP_REFUSAL_SCCP_FAILURE); _sccp_set_connection_state(connection, SCCP_CONNECTION_STATE_REFUSED); @@ -939,7 +941,7 @@ static int _sccp_handle_connection_release_complete(struct msgb *msgb) } - DEBUGP(DSCCP, "Release complete of unknown connection\n"); + LOGP(DSCCP, LOGL_ERROR, "Release complete of unknown connection\n"); return -1; found: @@ -967,7 +969,7 @@ static int _sccp_handle_connection_dt1(struct msgb *msgb) } } - DEBUGP(DSCCP, "No connection found for dt1 data\n"); + LOGP(DSCCP, LOGL_ERROR, "No connection found for dt1 data\n"); return -1; found: @@ -1026,7 +1028,7 @@ static int _sccp_handle_connection_released(struct msgb *msgb) } - DEBUGP(DSCCP, "Unknown connection was released.\n"); + LOGP(DSCCP, LOGL_ERROR, "Unknown connection was released.\n"); return -1; /* we have found a connection */ @@ -1038,7 +1040,7 @@ found: /* generate a response */ if (_sccp_send_connection_release_complete(conn) != 0) { - DEBUGP(DSCCP, "Sending release confirmed failed\n"); + LOGP(DSCCP, LOGL_ERROR, "Sending release confirmed failed\n"); return -1; } @@ -1063,7 +1065,7 @@ static int _sccp_handle_connection_refused(struct msgb *msgb) } } - DEBUGP(DSCCP, "Refused but no connection found\n"); + LOGP(DSCCP, LOGL_ERROR, "Refused but no connection found\n"); return -1; found: @@ -1096,7 +1098,7 @@ static int _sccp_handle_connection_confirm(struct msgb *msgb) } } - DEBUGP(DSCCP, "Confirmed but no connection found\n"); + LOGP(DSCCP, LOGL_ERROR, "Confirmed but no connection found\n"); return -1; found: @@ -1125,7 +1127,7 @@ int sccp_system_init(void (*outgoing)(struct msgb *data, void *ctx), void *ctx) int sccp_system_incoming(struct msgb *msgb) { if (msgb_l2len(msgb) < 1 ) { - DEBUGP(DSCCP, "Too short packet\n"); + LOGP(DSCCP, LOGL_ERROR, "Too short packet\n"); return -1; } @@ -1154,7 +1156,7 @@ int sccp_system_incoming(struct msgb *msgb) return _sccp_handle_read(msgb); break; default: - DEBUGP(DSCCP, "unimplemented msg type: %d\n", type); + LOGP(DSCCP, LOGL_ERROR, "unimplemented msg type: %d\n", type); }; return -1; @@ -1165,7 +1167,7 @@ int sccp_connection_write(struct sccp_connection *connection, struct msgb *data) { if (connection->connection_state < SCCP_CONNECTION_STATE_CONFIRM || connection->connection_state > SCCP_CONNECTION_STATE_ESTABLISHED) { - DEBUGP(DSCCP, "sccp_connection_write: Wrong connection state: %p %d\n", + LOGP(DSCCP, LOGL_ERROR, "sccp_connection_write: Wrong connection state: %p %d\n", connection, connection->connection_state); return -1; } @@ -1182,7 +1184,7 @@ int sccp_connection_send_it(struct sccp_connection *connection) { if (connection->connection_state < SCCP_CONNECTION_STATE_CONFIRM || connection->connection_state > SCCP_CONNECTION_STATE_ESTABLISHED) { - DEBUGP(DSCCP, "sccp_connection_write: Wrong connection state: %p %d\n", + LOGP(DSCCP, LOGL_ERROR, "sccp_connection_write: Wrong connection state: %p %d\n", connection, connection->connection_state); return -1; } @@ -1195,7 +1197,7 @@ int sccp_connection_close(struct sccp_connection *connection, int cause) { if (connection->connection_state < SCCP_CONNECTION_STATE_CONFIRM || connection->connection_state > SCCP_CONNECTION_STATE_ESTABLISHED) { - DEBUGPC(DSCCP, "Can not close the connection. It was never opened: %p %d\n", + LOGP(DSCCP, LOGL_ERROR, "Can not close the connection. It was never opened: %p %d\n", connection, connection->connection_state); return -1; } @@ -1207,7 +1209,7 @@ int sccp_connection_free(struct sccp_connection *connection) { if (connection->connection_state > SCCP_CONNECTION_STATE_NONE && connection->connection_state < SCCP_CONNECTION_STATE_RELEASE_COMPLETE) { - DEBUGP(DSCCP, "The connection needs to be released before it is freed"); + LOGP(DSCCP, LOGL_ERROR, "The connection needs to be released before it is freed"); return -1; } -- cgit v1.2.3 From 95c229006ef9e0a55139a3e80f6212189e4f4408 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Sun, 25 Apr 2010 23:08:39 +0800 Subject: [vty] Allow to set the RACH NM attributes on a per BTS basis Be able to tune the RACH settings of the BTS via the vty interface, by default they are initialized to -1 which means we will use the content of the static array (BTS default) and can be changed via the VTY interface. I have verified the setting on the nanoBTS with wireshark and I have tested writing the config file. --- openbsc/include/openbsc/gsm_data.h | 4 ++++ openbsc/src/bsc_init.c | 16 ++++++++++++++++ openbsc/src/gsm_data.c | 2 ++ openbsc/src/vty_interface.c | 29 +++++++++++++++++++++++++++++ 4 files changed, 51 insertions(+) diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index 52b82c062..34d1118ac 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -494,6 +494,10 @@ struct gsm_bts { struct gsm_bts_gprs_nsvc nsvc[2]; u_int8_t rac; } gprs; + + /* RACH NM values */ + int rach_b_thresh; + int rach_ldavg_slots; /* transceivers */ int num_trx; diff --git a/openbsc/src/bsc_init.c b/openbsc/src/bsc_init.c index a39bc198a..bdbff7b85 100644 --- a/openbsc/src/bsc_init.c +++ b/openbsc/src/bsc_init.c @@ -853,6 +853,22 @@ static void patch_nm_tables(struct gsm_bts *bts) bs11_attr_radio[2] |= arfcn_high; bs11_attr_radio[3] = arfcn_low; + /* patch the RACH attributes */ + if (bts->rach_b_thresh != -1) { + nanobts_attr_bts[33] = bts->rach_b_thresh & 0xff; + bs11_attr_bts[33] = bts->rach_b_thresh & 0xff; + } + + if (bts->rach_ldavg_slots != -1) { + u_int8_t avg_high = bts->rach_ldavg_slots & 0xff; + u_int8_t avg_low = (bts->rach_ldavg_slots >> 8) & 0x0f; + + nanobts_attr_bts[35] = avg_high; + nanobts_attr_bts[36] = avg_low; + bs11_attr_bts[35] = avg_high; + bs11_attr_bts[36] = avg_low; + } + /* patch BSIC */ bs11_attr_bts[1] = bts->bsic; nanobts_attr_bts[sizeof(nanobts_attr_bts)-11] = bts->bsic; diff --git a/openbsc/src/gsm_data.c b/openbsc/src/gsm_data.c index 4d8fa1747..9cb5647cb 100644 --- a/openbsc/src/gsm_data.c +++ b/openbsc/src/gsm_data.c @@ -221,6 +221,8 @@ struct gsm_bts *gsm_bts_alloc(struct gsm_network *net, enum gsm_bts_type type, } bts->c0->ts[0].pchan = GSM_PCHAN_CCCH_SDCCH4; + bts->rach_b_thresh = -1; + bts->rach_ldavg_slots = -1; llist_add_tail(&bts->list, &net->bts_list); return bts; diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c index dd35372ca..851a6039d 100644 --- a/openbsc/src/vty_interface.c +++ b/openbsc/src/vty_interface.c @@ -308,6 +308,13 @@ static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts) vty_out(vty, " rach max transmission %u%s", rach_max_trans_raw2val(bts->si_common.rach_control.max_trans), VTY_NEWLINE); + + if (bts->rach_b_thresh != -1) + vty_out(vty, " rach nm busy threshold %u%s", + bts->rach_b_thresh, VTY_NEWLINE); + if (bts->rach_ldavg_slots != -1) + vty_out(vty, " rach nm load average %u%s", + bts->rach_ldavg_slots, VTY_NEWLINE); if (bts->si_common.rach_control.cell_bar) vty_out(vty, " cell barred 1%s", VTY_NEWLINE); if (is_ipaccess_bts(bts)) { @@ -1337,6 +1344,26 @@ DEFUN(cfg_bts_rach_max_trans, return CMD_SUCCESS; } +DEFUN(cfg_bts_rach_nm_b_thresh, + cfg_bts_rach_nm_b_thresh_cmd, + "rach nm busy threshold <0-255>", + "Set the NM Busy Threshold in DB") +{ + struct gsm_bts *bts = vty->index; + bts->rach_b_thresh = atoi(argv[0]); + return CMD_SUCCESS; +} + +DEFUN(cfg_bts_rach_nm_ldavg, + cfg_bts_rach_nm_ldavg_cmd, + "rach nm load average <0-65535>", + "Set the NM Loadaver Slots value") +{ + struct gsm_bts *bts = vty->index; + bts->rach_ldavg_slots = atoi(argv[0]); + return CMD_SUCCESS; +} + DEFUN(cfg_bts_cell_barred, cfg_bts_cell_barred_cmd, "cell barred (0|1)", "Should this cell be barred from access?") @@ -1771,6 +1798,8 @@ int bsc_vty_init(struct gsm_network *net) install_element(BTS_NODE, &cfg_bts_challoc_cmd); install_element(BTS_NODE, &cfg_bts_rach_tx_integer_cmd); install_element(BTS_NODE, &cfg_bts_rach_max_trans_cmd); + install_element(BTS_NODE, &cfg_bts_rach_nm_b_thresh_cmd); + install_element(BTS_NODE, &cfg_bts_rach_nm_ldavg_cmd); install_element(BTS_NODE, &cfg_bts_cell_barred_cmd); install_element(BTS_NODE, &cfg_bts_ms_max_power_cmd); install_element(BTS_NODE, &cfg_bts_per_loc_upd_cmd); -- cgit v1.2.3 From 4ac100ec248c6431c12cae725b5759aed43066ea Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Sun, 11 Apr 2010 14:13:10 +0200 Subject: [e1_input] When destroying a link clear all pending messages --- openbsc/src/e1_input.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/openbsc/src/e1_input.c b/openbsc/src/e1_input.c index fba59a784..7ddd40559 100644 --- a/openbsc/src/e1_input.c +++ b/openbsc/src/e1_input.c @@ -420,7 +420,14 @@ e1inp_sign_link_create(struct e1inp_ts *ts, enum e1inp_sign_type type, void e1inp_sign_link_destroy(struct e1inp_sign_link *link) { + struct msgb *msg; + llist_del(&link->list); + while (!llist_empty(&link->tx_list)) { + msg = msgb_dequeue(&link->tx_list); + msgb_free(msg); + } + talloc_free(link); } -- cgit v1.2.3 From f51b9006a18432019fa788a8f139c4e30b87ecaa Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Sun, 11 Apr 2010 17:18:02 +0200 Subject: e1_input: Stop the timer when deleting the signalling link on the TS Stop the tx_timer when deleting the link on top of that ts. Otherwise bad things might happen. E.g. when scheduling a write on OML and then the OML link vanishes... This is a slight layering violation as there could be more than one signalling link on the timeslot (at least in theory) so the queue and the timer should move to the e1inp_sign_link. --- openbsc/src/e1_input.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/openbsc/src/e1_input.c b/openbsc/src/e1_input.c index 7ddd40559..b1dfe9b1d 100644 --- a/openbsc/src/e1_input.c +++ b/openbsc/src/e1_input.c @@ -428,6 +428,9 @@ void e1inp_sign_link_destroy(struct e1inp_sign_link *link) msgb_free(msg); } + if (link->ts->type == E1INP_TS_TYPE_SIGN) + bsc_del_timer(&link->ts->sign.tx_timer); + talloc_free(link); } -- cgit v1.2.3 From 221030fc85c9e0232eb0adcf1142ac1c48c8778a Mon Sep 17 00:00:00 2001 From: Sylvain Munaut Date: Tue, 27 Apr 2010 21:48:40 +0200 Subject: gsm_utils: Just add some constant and timekeeping utils Signed-off-by: Sylvain Munaut --- include/osmocore/gsm_utils.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/include/osmocore/gsm_utils.h b/include/osmocore/gsm_utils.h index c87e967bd..195e865ca 100644 --- a/include/osmocore/gsm_utils.h +++ b/include/osmocore/gsm_utils.h @@ -27,6 +27,13 @@ #include +#define ADD_MODULO(sum, delta, modulo) do { \ + if ((sum += delta) >= modulo) \ + sum -= modulo; \ + } while (0) + +#define GSM_MAX_FN (26*51*2048) + struct gsm_time { uint32_t fn; /* FN count */ uint16_t t1; /* FN div (26*51) */ -- cgit v1.2.3 From a074ec4b893af1eda06144b8b857a09cc9b1c375 Mon Sep 17 00:00:00 2001 From: Sylvain Munaut Date: Wed, 28 Apr 2010 10:05:29 +0200 Subject: gsm 08.08: Fix some u_int8_t -> uint8_t This breaks the ARM build in osmocom-bb. Besides uint??_t seems to be the preferred type in osmocore. (coming from stdint.h vs sys/types.h) Signed-off-by: Sylvain Munaut --- include/osmocore/protocol/gsm_08_08.h | 10 +++++----- src/gsm0808.c | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/include/osmocore/protocol/gsm_08_08.h b/include/osmocore/protocol/gsm_08_08.h index 9c29ba9c8..6b8f93595 100644 --- a/include/osmocore/protocol/gsm_08_08.h +++ b/include/osmocore/protocol/gsm_08_08.h @@ -30,14 +30,14 @@ enum BSSAP_MSG_TYPE { }; struct bssmap_header { - u_int8_t type; - u_int8_t length; + uint8_t type; + uint8_t length; } __attribute__((packed)); struct dtap_header { - u_int8_t type; - u_int8_t link_id; - u_int8_t length; + uint8_t type; + uint8_t link_id; + uint8_t length; } __attribute__((packed)); diff --git a/src/gsm0808.c b/src/gsm0808.c index 9f6f0059d..7a7eb3a08 100644 --- a/src/gsm0808.c +++ b/src/gsm0808.c @@ -150,7 +150,7 @@ struct msgb *gsm0808_create_cipher_reject(uint8_t cause) return msg; } -struct msgb *gsm0808_create_classmark_update(const uint8_t *classmark_data, u_int8_t length) +struct msgb *gsm0808_create_classmark_update(const uint8_t *classmark_data, uint8_t length) { struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM, "classmark-update"); @@ -191,7 +191,7 @@ struct msgb *gsm0808_create_assignment_completed(struct gsm_lchan *lchan, uint8_ uint8_t chosen_channel, uint8_t encr_alg_id, uint8_t speech_mode) { - u_int8_t *data; + uint8_t *data; struct msgb *msg = msgb_alloc(35, "bssmap: ass compl"); if (!msg) -- cgit v1.2.3 From 100224df0b711c7bf6c1150ce18cf595350cf0bd Mon Sep 17 00:00:00 2001 From: Sylvain Munaut Date: Wed, 28 Apr 2010 10:10:47 +0200 Subject: Update .gitignore m4/*.m4 -> autoreconf adds stuff there tests -> Build product Signed-off-by: Sylvain Munaut --- .gitignore | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.gitignore b/.gitignore index d61cdc589..06904fa09 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ Makefile.in *.la *.pc aclocal.m4 +m4/*.m4 autom4te.cache config.h* config.sub @@ -23,3 +24,7 @@ libtool .tarball-version .version + +tests/sms/sms_test +tests/timer/timer_test + -- cgit v1.2.3 From 50f81b022f0675bc2ae93d2f7998fd15d602ae91 Mon Sep 17 00:00:00 2001 From: Sylvain Munaut Date: Wed, 28 Apr 2010 21:31:29 +0200 Subject: bsc_init: Fix ccch description in SI messages The previous code just hardcoded RSL_BCCH_CCCH_CONF_1_C, but we need to inspect the timeslot config to know what to use. Signed-off-by: Sylvain Munaut --- openbsc/src/bsc_init.c | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/openbsc/src/bsc_init.c b/openbsc/src/bsc_init.c index bdbff7b85..3381ac5f8 100644 --- a/openbsc/src/bsc_init.c +++ b/openbsc/src/bsc_init.c @@ -974,6 +974,8 @@ void input_event(int event, enum e1inp_sign_type type, struct gsm_bts_trx *trx) static int bootstrap_bts(struct gsm_bts *bts) { + int i, n; + switch (bts->band) { case GSM_BAND_1800: if (bts->c0->arfcn < 512 || bts->c0->arfcn > 885) { @@ -1010,9 +1012,33 @@ static int bootstrap_bts(struct gsm_bts *bts) /* Control Channel Description */ bts->si_common.chan_desc.att = 1; - bts->si_common.chan_desc.ccch_conf = RSL_BCCH_CCCH_CONF_1_C; bts->si_common.chan_desc.bs_pa_mfrms = RSL_BS_PA_MFRMS_5; - /* T3212 is set from vty/config */ + /* T3212 is set from vty/config */ + + /* Set ccch config by looking at ts config */ + for (n=0, i=0; i<8; i++) + n += bts->c0->ts[i].pchan == GSM_PCHAN_CCCH ? 1 : 0; + + switch (n) { + case 0: + bts->si_common.chan_desc.ccch_conf = RSL_BCCH_CCCH_CONF_1_C; + break; + case 1: + bts->si_common.chan_desc.ccch_conf = RSL_BCCH_CCCH_CONF_1_NC; + break; + case 2: + bts->si_common.chan_desc.ccch_conf = RSL_BCCH_CCCH_CONF_2_NC; + break; + case 3: + bts->si_common.chan_desc.ccch_conf = RSL_BCCH_CCCH_CONF_3_NC; + break; + case 4: + bts->si_common.chan_desc.ccch_conf = RSL_BCCH_CCCH_CONF_4_NC; + break; + default: + LOGP(DNM, LOGL_ERROR, "Unsupported CCCH timeslot configuration\n"); + return -EINVAL; + } /* some defaults for our system information */ bts->si_common.cell_options.radio_link_timeout = 2; /* 12 */ -- cgit v1.2.3 From 22ca95cf9a8ebb5fc4ecafad162004730ad49b19 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Fri, 30 Apr 2010 11:33:08 +0800 Subject: [vty] Remove FIXME as it appears to do the right thing. --- openbsc/src/vty/vty.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/openbsc/src/vty/vty.c b/openbsc/src/vty/vty.c index 0ac9530f5..66e7d05d8 100644 --- a/openbsc/src/vty/vty.c +++ b/openbsc/src/vty/vty.c @@ -170,8 +170,7 @@ void vty_close(struct vty *vty) /* Check configure. */ vty_config_unlock(vty); - /* FIXME: memory leak. We need to call telnet_close_client() but don't - * have bfd */ + /* VTY_CLOSED is handled by the telnet_interface */ vty_event(VTY_CLOSED, vty->fd, vty); /* OK free vty. */ -- cgit v1.2.3 From 9e282de7c8c856975aa41ab100e38f1891962936 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Fri, 30 Apr 2010 12:18:32 +0800 Subject: [vty] Move some allocations into the context of the vty. --- openbsc/src/vty/vty.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/openbsc/src/vty/vty.c b/openbsc/src/vty/vty.c index 66e7d05d8..8455b0e3d 100644 --- a/openbsc/src/vty/vty.c +++ b/openbsc/src/vty/vty.c @@ -54,7 +54,7 @@ struct vty *vty_new() new->obuf = buffer_new(0); /* Use default buffer size. */ if (!new->obuf) goto out_new; - new->buf = _talloc_zero(tall_vty_ctx, VTY_BUFSIZ, "vty_new->buf"); + new->buf = _talloc_zero(new, VTY_BUFSIZ, "vty_new->buf"); if (!new->buf) goto out_obuf; @@ -210,7 +210,7 @@ int vty_out(struct vty *vty, const char *format, ...) else size = size * 2; - p = talloc_realloc_size(tall_vty_ctx, p, size); + p = talloc_realloc_size(vty, p, size); if (!p) return -1; @@ -357,7 +357,7 @@ static void vty_ensure(struct vty *vty, int length) { if (vty->max <= length) { vty->max *= 2; - vty->buf = talloc_realloc_size(tall_vty_ctx, vty->buf, vty->max); + vty->buf = talloc_realloc_size(vty, vty->buf, vty->max); // FIXME: check return } } @@ -458,7 +458,7 @@ static void vty_hist_add(struct vty *vty) /* Insert history entry. */ if (vty->hist[vty->hindex]) talloc_free(vty->hist[vty->hindex]); - vty->hist[vty->hindex] = talloc_strdup(tall_vty_ctx, vty->buf); + vty->hist[vty->hindex] = talloc_strdup(vty, vty->buf); /* History index rotation. */ vty->hindex++; @@ -965,7 +965,7 @@ vty_describe_fold(struct vty *vty, int cmd_width, return; } - buf = _talloc_zero(tall_vty_ctx, strlen(desc->str) + 1, "describe_fold"); + buf = _talloc_zero(vty, strlen(desc->str) + 1, "describe_fold"); if (!buf) return; -- cgit v1.2.3 From 1700c933f202260345caf733c5d147a1243aef48 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Fri, 30 Apr 2010 12:26:52 +0800 Subject: [vty] Allow to create a buffer in a given context. Stop using the global vty context for all allocations and allow to embed the buffer into a given context, and allocate sub buffers with the context of its parent. --- openbsc/include/vty/buffer.h | 2 +- openbsc/src/vty/buffer.c | 6 +++--- openbsc/src/vty/vty.c | 2 +- openbsc/src/vty_interface_layer3.c | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/openbsc/include/vty/buffer.h b/openbsc/include/vty/buffer.h index 31519400f..c9467a91d 100644 --- a/openbsc/include/vty/buffer.h +++ b/openbsc/include/vty/buffer.h @@ -28,7 +28,7 @@ /* Create a new buffer. Memory will be allocated in chunks of the given size. If the argument is 0, the library will supply a reasonable default size suitable for buffering socket I/O. */ -struct buffer *buffer_new(size_t); +struct buffer *buffer_new(void *ctx, size_t); /* Free all data in the buffer. */ void buffer_reset(struct buffer *); diff --git a/openbsc/src/vty/buffer.c b/openbsc/src/vty/buffer.c index 195d06209..0bc1760cc 100644 --- a/openbsc/src/vty/buffer.c +++ b/openbsc/src/vty/buffer.c @@ -65,11 +65,11 @@ struct buffer_data { #define BUFFER_DATA_FREE(D) talloc_free((D)) /* Make new buffer. */ -struct buffer *buffer_new(size_t size) +struct buffer *buffer_new(void *ctx, size_t size) { struct buffer *b; - b = talloc_zero(tall_vty_ctx, struct buffer); + b = talloc_zero(ctx, struct buffer); if (size) b->size = size; @@ -138,7 +138,7 @@ static struct buffer_data *buffer_add(struct buffer *b) { struct buffer_data *d; - d = _talloc_zero(tall_vty_ctx, + d = _talloc_zero(b, offsetof(struct buffer_data, data[b->size]), "buffer_add"); if (!d) diff --git a/openbsc/src/vty/vty.c b/openbsc/src/vty/vty.c index 8455b0e3d..5e4902441 100644 --- a/openbsc/src/vty/vty.c +++ b/openbsc/src/vty/vty.c @@ -51,7 +51,7 @@ struct vty *vty_new() if (!new) goto out; - new->obuf = buffer_new(0); /* Use default buffer size. */ + new->obuf = buffer_new(new, 0); /* Use default buffer size. */ if (!new->obuf) goto out_new; new->buf = _talloc_zero(new, VTY_BUFSIZ, "vty_new->buf"); diff --git a/openbsc/src/vty_interface_layer3.c b/openbsc/src/vty_interface_layer3.c index 5e3098289..fee5baee5 100644 --- a/openbsc/src/vty_interface_layer3.c +++ b/openbsc/src/vty_interface_layer3.c @@ -58,7 +58,7 @@ static int dummy_config_write(struct vty *v) static struct buffer *argv_to_buffer(int argc, const char *argv[], int base) { - struct buffer *b = buffer_new(1024); + struct buffer *b = buffer_new(NULL, 1024); int i; if (!b) -- cgit v1.2.3 From f1af306c94358c0de62d0487e543e518083d5710 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Fri, 30 Apr 2010 13:18:05 +0800 Subject: [vty] Plug memory leak on auto completion. I assume the original code crashed with a double free as we have a cleanup at the end of the method. Return from the routine like the case label below. This is fixing a memory leak I am experimenting. --- openbsc/src/vty/vty.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/openbsc/src/vty/vty.c b/openbsc/src/vty/vty.c index 5e4902441..fffa649c7 100644 --- a/openbsc/src/vty/vty.c +++ b/openbsc/src/vty/vty.c @@ -915,7 +915,9 @@ static void vty_complete_command(struct vty *vty) vty_backward_pure_word(vty); vty_insert_word_overwrite(vty, matched[0]); vty_self_insert(vty, ' '); - //talloc_free(matched[0]); + talloc_free(matched[0]); + vector_only_index_free(matched); + return; break; case CMD_COMPLETE_MATCH: vty_prompt(vty); -- cgit v1.2.3 From a4b446b4596a243363b386ca8f26b63d0fb005dc Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Fri, 30 Apr 2010 13:24:09 +0800 Subject: [vty] Free the matched at the end of the routine. Remove the return from the case labels and cleanup at the end matched array at the end of the routine. --- openbsc/src/vty/vty.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/openbsc/src/vty/vty.c b/openbsc/src/vty/vty.c index fffa649c7..08068560b 100644 --- a/openbsc/src/vty/vty.c +++ b/openbsc/src/vty/vty.c @@ -916,8 +916,6 @@ static void vty_complete_command(struct vty *vty) vty_insert_word_overwrite(vty, matched[0]); vty_self_insert(vty, ' '); talloc_free(matched[0]); - vector_only_index_free(matched); - return; break; case CMD_COMPLETE_MATCH: vty_prompt(vty); @@ -925,8 +923,6 @@ static void vty_complete_command(struct vty *vty) vty_backward_pure_word(vty); vty_insert_word_overwrite(vty, matched[0]); talloc_free(matched[0]); - vector_only_index_free(matched); - return; break; case CMD_COMPLETE_LIST_MATCH: for (i = 0; matched[i] != NULL; i++) { -- cgit v1.2.3 From a581136f73e16592b33f726464518803ea45bd72 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Fri, 30 Apr 2010 13:32:05 +0800 Subject: [misc] Remove spaces, fix indention. --- openbsc/src/bsc_init.c | 6 +++--- openbsc/src/mgcp/mgcp_network.c | 2 +- openbsc/src/mgcp/mgcp_vty.c | 4 ++-- openbsc/src/paging.c | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/openbsc/src/bsc_init.c b/openbsc/src/bsc_init.c index 3381ac5f8..9bc02c486 100644 --- a/openbsc/src/bsc_init.c +++ b/openbsc/src/bsc_init.c @@ -493,7 +493,7 @@ int nm_state_event(enum nm_evt evt, u_int8_t obj_class, void *obj, bts = nsvc->bts; if (bts->gprs.mode == BTS_GPRS_NONE) break; - /* We skip NSVC1 since we only use NSVC0 */ + /* We skip NSVC1 since we only use NSVC0 */ if (nsvc->id == 1) break; if (new_state->availability == NM_AVSTATE_OFF_LINE) { @@ -1013,9 +1013,9 @@ static int bootstrap_bts(struct gsm_bts *bts) /* Control Channel Description */ bts->si_common.chan_desc.att = 1; bts->si_common.chan_desc.bs_pa_mfrms = RSL_BS_PA_MFRMS_5; - /* T3212 is set from vty/config */ + /* T3212 is set from vty/config */ - /* Set ccch config by looking at ts config */ + /* Set ccch config by looking at ts config */ for (n=0, i=0; i<8; i++) n += bts->c0->ts[i].pchan == GSM_PCHAN_CCCH ? 1 : 0; diff --git a/openbsc/src/mgcp/mgcp_network.c b/openbsc/src/mgcp/mgcp_network.c index 73356f759..cd745a7c4 100644 --- a/openbsc/src/mgcp/mgcp_network.c +++ b/openbsc/src/mgcp/mgcp_network.c @@ -151,7 +151,7 @@ static int rtp_data_cb(struct bsc_fd *fd, unsigned int what) */ #warning "Slight spec violation. With connection mode recvonly we should attempt to forward." dest = memcmp(&addr.sin_addr, &endp->remote, sizeof(addr.sin_addr)) == 0 && - (endp->net_rtp == addr.sin_port || endp->net_rtcp == addr.sin_port) + (endp->net_rtp == addr.sin_port || endp->net_rtcp == addr.sin_port) ? DEST_BTS : DEST_NETWORK; proto = fd == &endp->local_rtp ? PROTO_RTP : PROTO_RTCP; diff --git a/openbsc/src/mgcp/mgcp_vty.c b/openbsc/src/mgcp/mgcp_vty.c index bf5d15f0b..5b90d524b 100644 --- a/openbsc/src/mgcp/mgcp_vty.c +++ b/openbsc/src/mgcp/mgcp_vty.c @@ -306,8 +306,8 @@ int mgcp_parse_config(const char *config_file, struct mgcp_config *cfg) /* * This application supports two modes. - * 1.) a true MGCP gateway with support for AUEP, CRCX, MDCX, DLCX - * 2.) plain forwarding of RTP packets on the endpoints. + * 1.) a true MGCP gateway with support for AUEP, CRCX, MDCX, DLCX + * 2.) plain forwarding of RTP packets on the endpoints. * both modes are mutual exclusive */ if (g_cfg->forward_ip) { diff --git a/openbsc/src/paging.c b/openbsc/src/paging.c index 314d3d135..12ed90341 100644 --- a/openbsc/src/paging.c +++ b/openbsc/src/paging.c @@ -318,7 +318,7 @@ void paging_request_stop(struct gsm_bts *_bts, struct gsm_subscriber *subscr, break; /* Stop paging */ - if (bts != _bts) + if (bts != _bts) _paging_request_stop(bts, subscr, NULL); } while (1); } -- cgit v1.2.3 From 52e8da6ea134944d1b9dae48f6f280cbe9fcb212 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Fri, 30 Apr 2010 14:04:01 +0200 Subject: remove any reference to 'struct gsm_bts_link' --- openbsc/include/openbsc/gsm_data.h | 5 ----- openbsc/src/gsm_04_80.c | 2 -- 2 files changed, 7 deletions(-) diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index 34d1118ac..47f194f87 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -105,11 +105,6 @@ typedef int gsm_cbfn(unsigned int hooknum, } while(0); -/* communications link with a BTS */ -struct gsm_bts_link { - struct gsm_bts *bts; -}; - /* Real authentication information containing Ki */ enum gsm_auth_algo { AUTH_ALGO_NONE, diff --git a/openbsc/src/gsm_04_80.c b/openbsc/src/gsm_04_80.c index 2112e3f99..ef10b1702 100644 --- a/openbsc/src/gsm_04_80.c +++ b/openbsc/src/gsm_04_80.c @@ -257,7 +257,6 @@ int gsm0480_send_ussd_response(const struct msgb *in_msg, const char *response_t if (((strlen(response_text) * 7) % 8) != 0) response_len += 1; - msg->bts_link = in_msg->bts_link; msg->lchan = in_msg->lchan; /* First put the payload text into the message */ @@ -304,7 +303,6 @@ int gsm0480_send_ussd_reject(const struct msgb *in_msg, struct msgb *msg = gsm48_msgb_alloc(); struct gsm48_hdr *gh; - msg->bts_link = in_msg->bts_link; msg->lchan = in_msg->lchan; /* First insert the problem code */ -- cgit v1.2.3 From 3120ac3f78ded9483b9ca8a2bc1e113eff78baf7 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Fri, 30 Apr 2010 14:19:48 +0200 Subject: remove the unneeded bts_link pointer from msgb --- include/osmocore/msgb.h | 5 ----- src/msgb.c | 1 - 2 files changed, 6 deletions(-) diff --git a/include/osmocore/msgb.h b/include/osmocore/msgb.h index 31db71942..31e54dcd4 100644 --- a/include/osmocore/msgb.h +++ b/include/osmocore/msgb.h @@ -23,14 +23,9 @@ #include #include "linuxlist.h" -struct bts_link; - struct msgb { 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; diff --git a/src/msgb.c b/src/msgb.c index 60af373eb..aea92d443 100644 --- a/src/msgb.c +++ b/src/msgb.c @@ -80,7 +80,6 @@ void msgb_reset(struct msgb *msg) msg->head = msg->_data; msg->tail = msg->_data; - msg->bts_link = NULL; msg->trx = NULL; msg->lchan = NULL; msg->l2h = NULL; -- cgit v1.2.3 From bb77c9d6cc6c1353817629f45b1414c9b0668b39 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Fri, 30 Apr 2010 14:26:12 +0200 Subject: msgb: remove smsh, llch, tlli and gmmh This is a lot of GSM/GPRS specific stuff in struct msgb which we want to avoid. The 'control buffer' will replace them. --- include/osmocore/msgb.h | 13 ++----------- src/msgb.c | 2 +- 2 files changed, 3 insertions(+), 12 deletions(-) diff --git a/include/osmocore/msgb.h b/include/osmocore/msgb.h index 31e54dcd4..61c224fec 100644 --- a/include/osmocore/msgb.h +++ b/include/osmocore/msgb.h @@ -36,17 +36,8 @@ struct msgb { unsigned char *l2h; /* the layer 3 header. For OML: FOM; RSL: 04.08; GPRS: BSSGP */ unsigned char *l3h; - /* the layer 4 header */ - union { - unsigned char *smsh; - unsigned char *llch; - unsigned char *l4h; - }; - - /* the layer 5 header, GPRS: GMM header */ - unsigned char *gmmh; - uint32_t tlli; + unsigned char *l4h; uint16_t data_len; uint16_t len; @@ -66,7 +57,7 @@ extern void msgb_reset(struct msgb *m); #define msgb_l1(m) ((void *)(m->l1h)) #define msgb_l2(m) ((void *)(m->l2h)) #define msgb_l3(m) ((void *)(m->l3h)) -#define msgb_sms(m) ((void *)(m->smsh)) +#define msgb_sms(m) ((void *)(m->l4h)) static inline unsigned int msgb_l1len(const struct msgb *msgb) { diff --git a/src/msgb.c b/src/msgb.c index aea92d443..9117a0ad0 100644 --- a/src/msgb.c +++ b/src/msgb.c @@ -84,5 +84,5 @@ void msgb_reset(struct msgb *msg) msg->lchan = NULL; msg->l2h = NULL; msg->l3h = NULL; - msg->smsh = NULL; + msg->l4h = NULL; } -- cgit v1.2.3 From e9dd9b047590064eec1c618475ece7f9627e0312 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Fri, 30 Apr 2010 14:27:05 +0200 Subject: gsm_04_11.c: Use msgb->l4h instead of sms->smsh, as the latter is gone --- openbsc/src/gsm_04_11.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openbsc/src/gsm_04_11.c b/openbsc/src/gsm_04_11.c index 511ad47e7..3492f1f3b 100644 --- a/openbsc/src/gsm_04_11.c +++ b/openbsc/src/gsm_04_11.c @@ -675,7 +675,7 @@ static int gsm411_rx_rp_ud(struct msgb *msg, struct gsm_trans *trans, GSM411_RP_CAUSE_INV_MAND_INF); return -EIO; } - msg->smsh = tpdu; + msg->l4h = tpdu; DEBUGP(DSMS, "DST(%u,%s)\n", dst_len, hexdump(dst, dst_len)); -- cgit v1.2.3 From 074c9f904cb5e4f6ab014d76e4abc079c16fc5d7 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Fri, 30 Apr 2010 14:29:11 +0200 Subject: msgb: introduce msgb->cb (the control buffer) --- include/osmocore/msgb.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/osmocore/msgb.h b/include/osmocore/msgb.h index 61c224fec..2841dc56e 100644 --- a/include/osmocore/msgb.h +++ b/include/osmocore/msgb.h @@ -27,6 +27,7 @@ struct msgb { struct llist_head list; /* Part of which TRX logical channel we were received / transmitted */ + /* FIXME: move them into the control buffer */ struct gsm_bts_trx *trx; struct gsm_lchan *lchan; @@ -39,6 +40,9 @@ struct msgb { /* the layer 4 header */ unsigned char *l4h; + /* the 'control buffer', large enough to contain 5 pointers */ + unsigned long cb[5]; + uint16_t data_len; uint16_t len; -- cgit v1.2.3 From 0809d79ef805fe21cb4bc4b55c78439b625b5b3d Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Fri, 30 Apr 2010 14:36:25 +0200 Subject: define 'struct openbsc_msgb_cb' and accessor macro OBSC_MSGB_CB() --- openbsc/include/openbsc/gsm_data.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index 47f194f87..70f5cdea1 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -79,6 +79,13 @@ enum bts_gprs_mode { BTS_GPRS_EGPRS = 2, }; +/* the data structure stored in msgb->cb for openbsc apps */ +struct openbsc_msgb_cb { + unsigned char *gmmh; + u_int32_t tlli; +}; +#define OBSC_MSGB_CB(__msgb) ((struct openbsc_msgb_cb *)&((__msgb)->cb[0])) + struct msgb; typedef int gsm_cbfn(unsigned int hooknum, unsigned int event, -- cgit v1.2.3 From 5ba4dc171b0d86ae3032c3732334481d9d399188 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Sat, 1 May 2010 15:09:48 +0800 Subject: Add missing file. --- include/osmocore/protocol/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/osmocore/protocol/Makefile.am b/include/osmocore/protocol/Makefile.am index 6d8883e61..557950ec8 100644 --- a/include/osmocore/protocol/Makefile.am +++ b/include/osmocore/protocol/Makefile.am @@ -1,3 +1,3 @@ -osmocore_proto_HEADERS = gsm_04_08.h gsm_04_11.h gsm_04_80.h gsm_08_58.h gsm_12_21.h +osmocore_proto_HEADERS = gsm_04_08.h gsm_04_11.h gsm_04_80.h gsm_08_58.h gsm_12_21.h gsm_08_08.h osmocore_protodir = $(includedir)/osmocore/protocol -- cgit v1.2.3 From a1c4f765eca695bf3d9c41d741bcab81989c8d48 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 1 May 2010 11:59:42 +0200 Subject: import gsm48_parse_ra() and gprs_tlli_type() from openbsc --- include/osmocore/gsm48.h | 11 +++++++++++ include/osmocore/gsm_utils.h | 12 ++++++++++++ include/osmocore/protocol/gsm_04_08.h | 9 ++++++++- src/gsm48.c | 21 +++++++++++++++++++++ src/gsm_utils.c | 15 +++++++++++++++ 5 files changed, 67 insertions(+), 1 deletion(-) diff --git a/include/osmocore/gsm48.h b/include/osmocore/gsm48.h index e3a1defa7..9015c25b9 100644 --- a/include/osmocore/gsm48.h +++ b/include/osmocore/gsm48.h @@ -4,6 +4,14 @@ #include #include +/* A parsed GPRS routing area */ +struct gprs_ra_id { + uint16_t mnc; + uint16_t mcc; + uint16_t lac; + uint8_t rac; +}; + extern const struct tlv_definition gsm48_att_tlvdef; const char *gsm48_cc_state_name(uint8_t state); const char *gsm48_cc_msg_name(uint8_t msgtype); @@ -18,4 +26,7 @@ int gsm48_generate_mid_from_imsi(uint8_t *buf, const char *imsi); int gsm48_mi_to_string(char *string, const int str_len, const uint8_t *mi, const int mi_len); +/* Parse Routeing Area Identifier */ +void gsm48_parse_ra(struct gprs_ra_id *raid, const uint8_t *buf); + #endif diff --git a/include/osmocore/gsm_utils.h b/include/osmocore/gsm_utils.h index 195e865ca..51e9f2e6a 100644 --- a/include/osmocore/gsm_utils.h +++ b/include/osmocore/gsm_utils.h @@ -87,5 +87,17 @@ void gsm_fn2gsmtime(struct gsm_time *time, uint32_t fn); /* Convert from GSM time to frame number */ uint32_t gsm_gsmtime2fn(struct gsm_time *time); +/* GSM TS 03.03 Chapter 2.6 */ +enum gprs_tlli_tyoe { + TLLI_LOCAL, + TLLI_FOREIGN, + TLLI_RANDOM, + TLLI_AUXILIARY, + TLLI_RESERVED, +}; + +/* TS 03.03 Chapter 2.6 */ +int gprs_tlli_type(uint32_t tlli); + void generate_backtrace(); #endif diff --git a/include/osmocore/protocol/gsm_04_08.h b/include/osmocore/protocol/gsm_04_08.h index 47b98b292..1a112a085 100644 --- a/include/osmocore/protocol/gsm_04_08.h +++ b/include/osmocore/protocol/gsm_04_08.h @@ -735,10 +735,17 @@ enum gsm48_bcap_rrq { GSM48_BCAP_RRQ_DUAL_FR = 3, }; - #define GSM48_TMSI_LEN 5 #define GSM48_MID_TMSI_LEN (GSM48_TMSI_LEN + 2) #define GSM48_MI_SIZE 32 +/* Chapter 10.4.4.15 */ +struct gsm48_ra_id { + uint8_t digits[3]; /* MCC + MNC BCD digits */ + uint16_t lac; /* Location Area Code */ + uint8_t rac; /* Routing Area Code */ +} __attribute__ ((packed)); + + #endif /* PROTO_GSM_04_08_H */ diff --git a/src/gsm48.c b/src/gsm48.c index 783ff6a5d..7e510664b 100644 --- a/src/gsm48.c +++ b/src/gsm48.c @@ -305,3 +305,24 @@ int gsm48_mi_to_string(char *string, const int str_len, const uint8_t *mi, return str_cur - string; } + +void gsm48_parse_ra(struct gprs_ra_id *raid, const uint8_t *buf) +{ + raid->mcc = (buf[0] & 0xf) * 100; + raid->mcc += (buf[0] >> 4) * 10; + raid->mcc += (buf[1] & 0xf) * 1; + + /* I wonder who came up with the stupidity of encoding the MNC + * differently depending on how many digits its decimal number has! */ + if ((buf[1] >> 4) == 0xf) { + raid->mnc = (buf[2] & 0xf) * 10; + raid->mnc += (buf[2] >> 4) * 1; + } else { + raid->mnc = (buf[2] & 0xf) * 100; + raid->mnc += (buf[2] >> 4) * 10; + raid->mnc += (buf[1] >> 4) * 1; + } + + raid->lac = ntohs(*(uint16_t *)(buf + 3)); + raid->rac = buf[5]; +} diff --git a/src/gsm_utils.c b/src/gsm_utils.c index 593dd5c94..b392fd37c 100644 --- a/src/gsm_utils.c +++ b/src/gsm_utils.c @@ -359,3 +359,18 @@ uint32_t gsm_gsmtime2fn(struct gsm_time *time) /* TS 05.02 Chapter 4.3.3 TDMA frame number */ return (51 * ((time->t3 - time->t2 + 26) % 26) + time->t3 + (26 * 51 * time->t1)); } + +/* TS 03.03 Chapter 2.6 */ +int gprs_tlli_type(uint32_t tlli) +{ + if ((tlli & 0xc0000000) == 0xc0000000) + return TLLI_LOCAL; + else if ((tlli & 0xc0000000) == 0x80000000) + return TLLI_FOREIGN; + else if ((tlli & 0xf8000000) == 0x78000000) + return TLLI_RANDOM; + else if ((tlli & 0xf8000000) == 0x70000000) + return TLLI_AUXILIARY; + + return TLLI_RESERVED; +} -- cgit v1.2.3 From debf95507461965aa82be2fa2bf34119343cfb0e Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 1 May 2010 12:06:48 +0200 Subject: gsm48.h: Prevent accidental re-inclusion of same header file --- include/osmocore/gsm48.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/osmocore/gsm48.h b/include/osmocore/gsm48.h index 9015c25b9..a509a0965 100644 --- a/include/osmocore/gsm48.h +++ b/include/osmocore/gsm48.h @@ -1,4 +1,5 @@ #ifndef _OSMOCORE_GSM48_H +#define _OSMOCORE_GSM48_H #include #include -- cgit v1.2.3 From f32cc4bee55da4ff20be095eb5f4e883f2f54de6 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 1 May 2010 11:01:46 +0200 Subject: VTY: ensure all cmd_elements are declared 'static' While doing 'nm' on a VTY-using object file I noticed that all cmd_elements are global symbols, which is not good. Unfortuantely there are some vty-internal cmd_elements that need to span across object files, so I had to introduce gDEFUN() and gALIAS(). The old macros now all declare static structures. --- openbsc/include/vty/command.h | 21 +++++++++++++++++++++ openbsc/src/vty/command.c | 10 +++++----- 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/openbsc/include/vty/command.h b/openbsc/include/vty/command.h index 03b071f70..738cce4f1 100644 --- a/openbsc/include/vty/command.h +++ b/openbsc/include/vty/command.h @@ -173,6 +173,17 @@ struct desc { /* helper defines for end-user DEFUN* macros */ #define DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, attrs, dnum) \ + static struct cmd_element cmdname = \ + { \ + .string = cmdstr, \ + .func = funcname, \ + .doc = helpstr, \ + .attr = attrs, \ + .daemon = dnum, \ + }; + +/* global (non static) cmd_element */ +#define gDEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, attrs, dnum) \ struct cmd_element cmdname = \ { \ .string = cmdstr, \ @@ -195,6 +206,12 @@ struct desc { DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, 0, 0) \ DEFUN_CMD_FUNC_TEXT(funcname) +/* global (non static) cmd_element */ +#define gDEFUN(funcname, cmdname, cmdstr, helpstr) \ + DEFUN_CMD_FUNC_DECL(funcname) \ + gDEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, 0, 0) \ + DEFUN_CMD_FUNC_TEXT(funcname) + #define DEFUN_ATTR(funcname, cmdname, cmdstr, helpstr, attr) \ DEFUN_CMD_FUNC_DECL(funcname) \ DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, attr, 0) \ @@ -236,6 +253,10 @@ struct desc { #define ALIAS(funcname, cmdname, cmdstr, helpstr) \ DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, 0, 0) +/* global (non static) cmd_element */ +#define gALIAS(funcname, cmdname, cmdstr, helpstr) \ + gDEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, 0, 0) + #define ALIAS_ATTR(funcname, cmdname, cmdstr, helpstr, attr) \ DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, attr, 0) diff --git a/openbsc/src/vty/command.c b/openbsc/src/vty/command.c index a38ed0424..278d980e9 100644 --- a/openbsc/src/vty/command.c +++ b/openbsc/src/vty/command.c @@ -2311,7 +2311,7 @@ DEFUN(disable, } /* Down vty node level. */ -DEFUN(config_exit, +gDEFUN(config_exit, config_exit_cmd, "exit", "Exit current mode and down to previous mode\n") { switch (vty->node) { @@ -2372,11 +2372,11 @@ DEFUN(config_exit, } /* quit is alias of exit. */ -ALIAS(config_exit, +gALIAS(config_exit, config_quit_cmd, "quit", "Exit current mode and down to previous mode\n") /* End of configuration. */ - DEFUN(config_end, + gDEFUN(config_end, config_end_cmd, "end", "End current mode and change to enable mode.") { switch (vty->node) { @@ -2407,7 +2407,7 @@ DEFUN(show_version, } /* Help display function for all node. */ -DEFUN(config_help, +gDEFUN(config_help, config_help_cmd, "help", "Description of the interactive help system\n") { vty_out(vty, @@ -2428,7 +2428,7 @@ argument.%s\ } /* Help display function for all node. */ -DEFUN(config_list, config_list_cmd, "list", "Print command list\n") +gDEFUN(config_list, config_list_cmd, "list", "Print command list\n") { unsigned int i; struct cmd_node *cnode = vector_slot(cmdvec, vty->node); -- cgit v1.2.3 From 9624364b4eed534d99ddd4bb77d8f7fdab1bdb03 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 1 May 2010 14:01:23 +0200 Subject: 'struct gprs_ra_id' is now defined in libosmocore --- openbsc/include/openbsc/gsm_data.h | 8 -------- 1 file changed, 8 deletions(-) diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index 70f5cdea1..ab555797a 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -722,14 +722,6 @@ const char *bts_gprs_mode_name(enum bts_gprs_mode mode); void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked); -/* A parsed GPRS routing area */ -struct gprs_ra_id { - u_int16_t mnc; - u_int16_t mcc; - u_int16_t lac; - u_int8_t rac; -}; - int gsm48_ra_id_by_bts(u_int8_t *buf, struct gsm_bts *bts); void gprs_ra_id_by_bts(struct gprs_ra_id *raid, struct gsm_bts *bts); struct gsm_meas_rep *lchan_next_meas_rep(struct gsm_lchan *lchan); -- cgit v1.2.3 From 0b484a4fb1641be2dadc822dbd9ad184268dcf9e Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 1 May 2010 14:02:25 +0200 Subject: Makefile cleanup move vty_interface_cmds.c and telnet_interface.c into libvty rather than explicitly linking the C files for every program --- openbsc/src/Makefile.am | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/openbsc/src/Makefile.am b/openbsc/src/Makefile.am index 2c1d37a04..38150a9bf 100644 --- a/openbsc/src/Makefile.am +++ b/openbsc/src/Makefile.am @@ -17,14 +17,15 @@ libbsc_a_SOURCES = abis_rsl.c abis_nm.c gsm_data.c gsm_04_08_utils.c \ input/misdn.c input/ipaccess.c \ talloc_ctx.c system_information.c rest_octets.c \ rtp_proxy.c bts_siemens_bs11.c bts_ipaccess_nanobts.c \ - bts_unknown.c bsc_version.c bsc_api.c vty_interface_cmds.c + bts_unknown.c bsc_version.c bsc_api.c -libmsc_a_SOURCES = gsm_subscriber.c db.c telnet_interface.c \ +libmsc_a_SOURCES = gsm_subscriber.c db.c \ mncc.c gsm_04_08.c gsm_04_11.c transaction.c \ token_auth.c rrlp.c gsm_04_80.c ussd.c silent_call.c \ handover_logic.c handover_decision.c meas_rep.c -libvty_a_SOURCES = vty/buffer.c vty/command.c vty/vector.c vty/vty.c +libvty_a_SOURCES = vty/buffer.c vty/command.c vty/vector.c vty/vty.c \ + telnet_interface.c vty_interface_cmds.c libsccp_a_SOURCES = sccp/sccp.c @@ -42,7 +43,7 @@ ipaccess_config_LDADD = libbsc.a libmsc.a libbsc.a libvty.a -ldl -ldbi $(LIBCRYP isdnsync_SOURCES = isdnsync.c bsc_mgcp_SOURCES = mgcp/mgcp_main.c mgcp/mgcp_protocol.c mgcp/mgcp_network.c mgcp/mgcp_vty.c \ - debug.c telnet_interface.c vty_interface_cmds.c + debug.c bsc_mgcp_LDADD = libvty.a ipaccess_proxy_SOURCES = ipaccess/ipaccess-proxy.c debug.c -- cgit v1.2.3 From 35a939463eee58492c88cbe7531288237cdcf454 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 1 May 2010 14:25:22 +0200 Subject: Import gsm48_construct_ra() from openbsc --- include/osmocore/gsm48.h | 1 + src/gsm48.c | 25 +++++++++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/include/osmocore/gsm48.h b/include/osmocore/gsm48.h index a509a0965..be9fbbd14 100644 --- a/include/osmocore/gsm48.h +++ b/include/osmocore/gsm48.h @@ -29,5 +29,6 @@ int gsm48_mi_to_string(char *string, const int str_len, /* Parse Routeing Area Identifier */ void gsm48_parse_ra(struct gprs_ra_id *raid, const uint8_t *buf); +int gsm48_construct_ra(uint8_t *buf, const struct gprs_ra_id *raid); #endif diff --git a/src/gsm48.c b/src/gsm48.c index 7e510664b..d957aef60 100644 --- a/src/gsm48.c +++ b/src/gsm48.c @@ -326,3 +326,28 @@ void gsm48_parse_ra(struct gprs_ra_id *raid, const uint8_t *buf) raid->lac = ntohs(*(uint16_t *)(buf + 3)); raid->rac = buf[5]; } + +int gsm48_construct_ra(uint8_t *buf, const struct gprs_ra_id *raid) +{ + uint16_t mcc = raid->mcc; + uint16_t mnc = raid->mnc; + + buf[0] = ((mcc / 100) % 10) | (((mcc / 10) % 10) << 4); + buf[1] = (mcc % 10); + + /* I wonder who came up with the stupidity of encoding the MNC + * differently depending on how many digits its decimal number has! */ + if (mnc < 100) { + buf[1] |= 0xf0; + buf[2] = ((mnc / 10) % 10) | ((mnc % 10) << 4); + } else { + buf[1] |= (mnc % 10) << 4; + buf[2] = ((mnc / 100) % 10) | (((mcc / 10) % 10) << 4); + } + + *(uint16_t *)(buf+3) = htons(raid->lac); + + buf[5] = raid->rac; + + return 6; +} -- cgit v1.2.3 From 72267f01fdfe87ec458378f4b2f1aaa610f7b0f0 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 1 May 2010 14:26:36 +0200 Subject: move gsm48_construct_ra() to libosmocore --- openbsc/src/gsm_data.c | 27 --------------------------- 1 file changed, 27 deletions(-) diff --git a/openbsc/src/gsm_data.c b/openbsc/src/gsm_data.c index 9cb5647cb..f9cca490d 100644 --- a/openbsc/src/gsm_data.c +++ b/openbsc/src/gsm_data.c @@ -442,33 +442,6 @@ const char *gsm_auth_policy_name(enum gsm_auth_policy policy) return get_value_string(auth_policy_names, policy); } -/* this should not be here but in gsm_04_08... but that creates - in turn a dependency nightmare (abis_nm depending on 04_08, ...) */ -static int gsm48_construct_ra(u_int8_t *buf, const struct gprs_ra_id *raid) -{ - u_int16_t mcc = raid->mcc; - u_int16_t mnc = raid->mnc; - - buf[0] = ((mcc / 100) % 10) | (((mcc / 10) % 10) << 4); - buf[1] = (mcc % 10); - - /* I wonder who came up with the stupidity of encoding the MNC - * differently depending on how many digits its decimal number has! */ - if (mnc < 100) { - buf[1] |= 0xf0; - buf[2] = ((mnc / 10) % 10) | ((mnc % 10) << 4); - } else { - buf[1] |= (mnc % 10) << 4; - buf[2] = ((mnc / 100) % 10) | (((mcc / 10) % 10) << 4); - } - - *(u_int16_t *)(buf+3) = htons(raid->lac); - - buf[5] = raid->rac; - - return 6; -} - void gprs_ra_id_by_bts(struct gprs_ra_id *raid, struct gsm_bts *bts) { raid->mcc = bts->network->country_code; -- cgit v1.2.3 From 95df5c0179f6b24d31c6720a43434755ed58aa22 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 1 May 2010 23:53:26 +0200 Subject: msgb: initialize cb[] to zero during msgb_reset() --- src/msgb.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/msgb.c b/src/msgb.c index 9117a0ad0..a60e2ffa5 100644 --- a/src/msgb.c +++ b/src/msgb.c @@ -85,4 +85,6 @@ void msgb_reset(struct msgb *msg) msg->l2h = NULL; msg->l3h = NULL; msg->l4h = NULL; + + memset(&msg->cb, 0, sizeof(msg->cb)); } -- cgit v1.2.3 From bde050e8f825541c3c44b295278d165c0eaa98da Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 19 Apr 2010 10:49:30 +0200 Subject: multi-trx config: Don't configure CCCH on 2nd TRX ;) --- openbsc/src/openbsc.cfg.nanobts.multitrx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openbsc/src/openbsc.cfg.nanobts.multitrx b/openbsc/src/openbsc.cfg.nanobts.multitrx index d9fb54b49..6e27ff514 100644 --- a/openbsc/src/openbsc.cfg.nanobts.multitrx +++ b/openbsc/src/openbsc.cfg.nanobts.multitrx @@ -80,9 +80,9 @@ network max_power_red 0 rsl e1 tei 0 timeslot 0 - phys_chan_config CCCH+SDCCH4 - timeslot 1 phys_chan_config SDCCH8 + timeslot 1 + phys_chan_config TCH/F timeslot 2 phys_chan_config TCH/F timeslot 3 -- cgit v1.2.3 From 3c69a4cdbeed5cd877d3e688c0066acfa2b7b180 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 1 May 2010 14:22:44 +0200 Subject: make gsm48_msgb_alloc() a static inline function This resolves some dependency problems (i.e. osmo_sgsn not needing to link gsm_04_08_utils.o which has RSL dependencies) --- openbsc/include/openbsc/gsm_04_08.h | 10 +++++++++- openbsc/src/gsm_04_08_utils.c | 9 --------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/openbsc/include/openbsc/gsm_04_08.h b/openbsc/include/openbsc/gsm_04_08.h index daf3bd780..74dcbe52a 100644 --- a/openbsc/include/openbsc/gsm_04_08.h +++ b/openbsc/include/openbsc/gsm_04_08.h @@ -12,6 +12,15 @@ struct gsm_subscriber; struct gsm_network; struct gsm_trans; +#define GSM48_ALLOC_SIZE 1024 +#define GSM48_ALLOC_HEADROOM 128 + +static inline struct msgb *gsm48_msgb_alloc(void) +{ + return msgb_alloc_headroom(GSM48_ALLOC_SIZE, GSM48_ALLOC_HEADROOM, + "GSM 04.08"); +} + /* config options controlling the behaviour of the lower leves */ void gsm0408_allow_everyone(int allow); @@ -22,7 +31,6 @@ enum gsm_chreq_reason_t get_reason_by_chreq(struct gsm_bts *bts, u_int8_t ra, in int gsm48_tx_mm_info(struct gsm_lchan *lchan); int gsm48_tx_mm_auth_req(struct gsm_lchan *lchan, u_int8_t *rand, int key_seq); int gsm48_tx_mm_auth_rej(struct gsm_lchan *lchan); -struct msgb *gsm48_msgb_alloc(void); int gsm48_sendmsg(struct msgb *msg, struct gsm_trans *trans); int gsm48_send_rr_release(struct gsm_lchan *lchan); diff --git a/openbsc/src/gsm_04_08_utils.c b/openbsc/src/gsm_04_08_utils.c index b770b52fc..0ee06ca56 100644 --- a/openbsc/src/gsm_04_08_utils.c +++ b/openbsc/src/gsm_04_08_utils.c @@ -36,19 +36,10 @@ #include #include -#define GSM48_ALLOC_SIZE 1024 -#define GSM48_ALLOC_HEADROOM 128 - /* should ip.access BTS use direct RTP streams between each other (1), * or should OpenBSC always act as RTP relay/proxy in between (0) ? */ int ipacc_rtp_direct = 1; -struct msgb *gsm48_msgb_alloc(void) -{ - return msgb_alloc_headroom(GSM48_ALLOC_SIZE, GSM48_ALLOC_HEADROOM, - "GSM 04.08"); -} - int gsm48_sendmsg(struct msgb *msg, struct gsm_trans *trans) { struct gsm48_hdr *gh = (struct gsm48_hdr *) msg->data; -- cgit v1.2.3 From 9b455bf801411d0d3297febab68011e8ab6c13d9 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 14 Mar 2010 15:45:01 +0800 Subject: Create new 'gprs-sgsn' branch on top of 'gprs-conf' This branch contains the partial SGSN/GGSN implementation that was originally developed as part of the gprs branch. --- openbsc/include/openbsc/crc24.h | 8 + openbsc/include/openbsc/debug.h | 1 + openbsc/include/openbsc/gprs_bssgp.h | 138 ++++++ openbsc/include/openbsc/gprs_llc.h | 20 + openbsc/include/openbsc/gprs_ns.h | 61 +++ openbsc/include/openbsc/gprs_sgsn.h | 107 +++++ openbsc/include/openbsc/gsm_04_08_gprs.h | 203 +++++++++ openbsc/src/Makefile.am | 7 +- openbsc/src/crc24.c | 69 +++ openbsc/src/gprs_bssgp.c | 397 +++++++++++++++++ openbsc/src/gprs_llc.c | 420 ++++++++++++++++++ openbsc/src/gprs_ns.c | 348 +++++++++++++++ openbsc/src/gprs_sgsn.c | 93 ++++ openbsc/src/gsm_04_08_gprs.c | 716 +++++++++++++++++++++++++++++++ openbsc/src/input/ipaccess.c | 112 ++++- openbsc/src/vty_interface_cmds.c | 2 +- 16 files changed, 2690 insertions(+), 12 deletions(-) create mode 100644 openbsc/include/openbsc/crc24.h create mode 100644 openbsc/include/openbsc/gprs_bssgp.h create mode 100644 openbsc/include/openbsc/gprs_llc.h create mode 100644 openbsc/include/openbsc/gprs_ns.h create mode 100644 openbsc/include/openbsc/gprs_sgsn.h create mode 100644 openbsc/include/openbsc/gsm_04_08_gprs.h create mode 100644 openbsc/src/crc24.c create mode 100644 openbsc/src/gprs_bssgp.c create mode 100644 openbsc/src/gprs_llc.c create mode 100644 openbsc/src/gprs_ns.c create mode 100644 openbsc/src/gprs_sgsn.c create mode 100644 openbsc/src/gsm_04_08_gprs.c diff --git a/openbsc/include/openbsc/crc24.h b/openbsc/include/openbsc/crc24.h new file mode 100644 index 000000000..358fcb58f --- /dev/null +++ b/openbsc/include/openbsc/crc24.h @@ -0,0 +1,8 @@ +#ifndef _CRC24_H +#define _CRC24_H + +#define INIT_CRC24 0xffffff + +u_int32_t crc24_calc(u_int32_t fcs, u_int8_t *cp, unsigned int len); + +#endif diff --git a/openbsc/include/openbsc/debug.h b/openbsc/include/openbsc/debug.h index f1c5a699a..49b417e26 100644 --- a/openbsc/include/openbsc/debug.h +++ b/openbsc/include/openbsc/debug.h @@ -29,6 +29,7 @@ enum { DHO, DDB, DREF, + DGPRS, Debug_LastEntry, }; diff --git a/openbsc/include/openbsc/gprs_bssgp.h b/openbsc/include/openbsc/gprs_bssgp.h new file mode 100644 index 000000000..f85ac48ec --- /dev/null +++ b/openbsc/include/openbsc/gprs_bssgp.h @@ -0,0 +1,138 @@ +#ifndef _GPRS_BSSGP_H +#define _GPRS_BSSGP_H + +/* Section 11.3.26 / Table 11.27 */ +enum bssgp_pdu_type { + /* PDUs between RL and BSSGP SAPs */ + BSSGP_PDUT_DL_UNITDATA = 0x00, + BSSGP_PDUT_UL_UNITDATA = 0x01, + BSSGP_PDUT_RA_CAPABILITY = 0x02, + BSSGP_PDUT_PTM_UNITDATA = 0x03, + /* PDUs between GMM SAPs */ + BSSGP_PDUT_PAGING_PS = 0x06, + BSSGP_PDUT_PAGING_CS = 0x07, + BSSGP_PDUT_RA_CAPA_UDPATE = 0x08, + BSSGP_PDUT_RA_CAPA_UPDATE_ACK = 0x09, + BSSGP_PDUT_RADIO_STATUS = 0x0a, + BSSGP_PDUT_SUSPEND = 0x0b, + BSSGP_PDUT_SUSPEND_ACK = 0x0c, + BSSGP_PDUT_SUSPEND_NACK = 0x0d, + BSSGP_PDUT_RESUME = 0x0e, + BSSGP_PDUT_RESUME_ACK = 0x0f, + BSSGP_PDUT_RESUME_NACK = 0x10, + /* PDus between NM SAPs */ + BSSGP_PDUT_BVC_BLOCK = 0x20, + BSSGP_PDUT_BVC_BLOCK_ACK = 0x21, + BSSGP_PDUT_BVC_RESET = 0x22, + BSSGP_PDUT_BVC_RESET_ACK = 0x23, + BSSGP_PDUT_BVC_UNBLOCK = 0x24, + BSSGP_PDUT_BVC_UNBLOCK_ACK = 0x25, + BSSGP_PDUT_FLOW_CONTROL_BVC = 0x26, + BSSGP_PDUT_FLOW_CONTROL_BVC_ACK = 0x27, + BSSGP_PDUT_FLOW_CONTROL_MS = 0x28, + BSSGP_PDUT_FLOW_CONTROL_MS_ACK = 0x29, + BSSGP_PDUT_FLUSH_LL = 0x2a, + BSSGP_PDUT_FLUSH_LL_ACK = 0x2b, + BSSGP_PDUT_LLC_DISCARD = 0x2c, + BSSGP_PDUT_SGSN_INVOKE_TRACE = 0x40, + BSSGP_PDUT_STATUS = 0x41, + /* PDUs between PFM SAP's */ + BSSGP_PDUT_DOWNLOAD_BSS_PFC = 0x50, + BSSGP_PDUT_CREATE_BSS_PFC = 0x51, + BSSGP_PDUT_CREATE_BSS_PFC_ACK = 0x52, + BSSGP_PDUT_CREATE_BSS_PFC_NACK = 0x53, + BSSGP_PDUT_MODIFY_BSS_PFC = 0x54, + BSSGP_PDUT_MODIFY_BSS_PFC_ACK = 0x55, + BSSGP_PDUT_DELETE_BSS_PFC = 0x56, + BSSGP_PDUT_DELETE_BSS_PFC_ACK = 0x57, +}; + +/* Section 10.2.1 and 10.2.2 */ +struct bssgp_ud_hdr { + u_int8_t pdu_type; + u_int32_t tlli; + u_int8_t qos_profile[3]; + u_int8_t data[0]; /* TLV's */ +} __attribute__((packed)); + +struct bssgp_normal_hdr { + u_int8_t pdu_type; + u_int8_t data[0]; /* TLV's */ +}; + +enum bssgp_iei_type { + BSSGP_IE_ALIGNMENT = 0x00, + BSSGP_IE_BMAX_DEFAULT_MS = 0x01, + BSSGP_IE_BSS_AREA_ID = 0x02, + BSSGP_IE_BUCKET_LEAK_RATE = 0x03, + BSSGP_IE_BVCI = 0x04, + BSSGP_IE_BVC_BUCKET_SIZE = 0x05, + BSSGP_IE_BVC_MEASUREMENT = 0x06, + BSSGP_IE_CAUSE = 0x07, + BSSGP_IE_CELL_ID = 0x08, + BSSGP_IE_CHAN_NEEDED = 0x09, + BSSGP_IE_DRX_PARAMS = 0x0a, + BSSGP_IE_EMLPP_PRIO = 0x0b, + BSSGP_IE_FLUSH_ACTION = 0x0c, + BSSGP_IE_IMSI = 0x0d, + BSSGP_IE_LLC_PDU = 0x0e, + BSSGP_IE_LLC_FRAMES_DISCARDED = 0x0f, + BSSGP_IE_LOCATION_AREA = 0x10, + BSSGP_IE_MOBILE_ID = 0x11, + BSSGP_IE_MS_BUCKET_SIZE = 0x12, + BSSGP_IE_MS_RADIO_ACCESS_CAP = 0x13, + BSSGP_IE_OMC_ID = 0x14, + BSSGP_IE_PDU_IN_ERROR = 0x15, + BSSGP_IE_PDU_LIFETIME = 0x16, + BSSGP_IE_PRIORITY = 0x17, + BSSGP_IE_QOS_PROFILE = 0x18, + BSSGP_IE_RADIO_CAUSE = 0x19, + BSSGP_IE_RA_CAP_UPD_CAUSE = 0x1a, + BSSGP_IE_ROUTEING_AREA = 0x1b, + BSSGP_IE_R_DEFAULT_MS = 0x1c, + BSSGP_IE_SUSPEND_REF_NR = 0x1d, + BSSGP_IE_TAG = 0x1e, + BSSGP_IE_TLLI = 0x1f, + BSSGP_IE_TMSI = 0x20, + BSSGP_IE_TRACE_REFERENC = 0x21, + BSSGP_IE_TRACE_TYPE = 0x22, + BSSGP_IE_TRANSACTION_ID = 0x23, + BSSGP_IE_TRIGGER_ID = 0x24, + BSSGP_IE_NUM_OCT_AFF = 0x25, + BSSGP_IE_LSA_ID_LIST = 0x26, + BSSGP_IE_LSA_INFORMATION = 0x27, + BSSGP_IE_PACKET_FLOW_ID = 0x28, + BSSGP_IE_PACKET_FLOW_TIMER = 0x29, + BSSGP_IE_AGG_BSS_QOS_PROFILE = 0x3a, + BSSGP_IE_FEATURE_BITMAP = 0x3b, + BSSGP_IE_BUCKET_FULL_RATIO = 0x3c, + BSSGP_IE_SERVICE_UTRAN_CCO = 0x3d, +}; + +/* Section 11.3.8 / Table 11.10: Cause coding */ +enum gprs_bssgp_cause { + BSSGP_CAUSE_PROC_OVERLOAD = 0x00, + BSSGP_CAUSE_EQUIP_FAIL = 0x01, + BSSGP_CAUSE_TRASIT_NET_FAIL = 0x02, + BSSGP_CAUSE_CAPA_GREATER_0KPBS = 0x03, + BSSGP_CAUSE_UNKNOWN_MS = 0x04, + BSSGP_CAUSE_UNKNOWN_BVCI = 0x05, + BSSGP_CAUSE_CELL_TRAF_CONG = 0x06, + BSSGP_CAUSE_SGSN_CONG = 0x07, + BSSGP_CAUSE_OML_INTERV = 0x08, + BSSGP_CAUSE_BVCI_BLOCKED = 0x09, + BSSGP_CAUSE_PFC_CREATE_FAIL = 0x0a, + BSSGP_CAUSE_SEM_INCORR_PDU = 0x20, + BSSGP_CAUSE_INV_MAND_INF = 0x21, + BSSGP_CAUSE_MISSING_MAND_IE = 0x22, + BSSGP_CAUSE_MISSING_COND_IE = 0x23, + BSSGP_CAUSE_UNEXP_COND_IE = 0x24, + BSSGP_CAUSE_COND_IE_ERR = 0x25, + BSSGP_CAUSE_PDU_INCOMP_STATE = 0x26, + BSSGP_CAUSE_PROTO_ERR_UNSPEC = 0x27, + BSSGP_CAUSE_PDU_INCOMP_FEAT = 0x28, +}; + +extern int gprs_bssgp_rcvmsg(struct msgb *msg, u_int16_t bvci); + +#endif /* _GPRS_BSSGP_H */ diff --git a/openbsc/include/openbsc/gprs_llc.h b/openbsc/include/openbsc/gprs_llc.h new file mode 100644 index 000000000..cd4e21523 --- /dev/null +++ b/openbsc/include/openbsc/gprs_llc.h @@ -0,0 +1,20 @@ +#ifndef _GPRS_LLC_H +#define _GPRS_LLC_H + +/* Section 4.7 LLC Layer Structure */ +enum gprs_llc_sapi { + GPRS_SAPI_GMM = 1, + GPRS_SAPI_TOM2 = 2, + GPRS_SAPI_SNDCP3 = 3, + GPRS_SAPI_SNDCP5 = 5, + GPRS_SAPI_SMS = 7, + GPRS_SAPI_TOM8 = 8, + GPRS_SAPI_SNDCP9 = 9, + GPRS_SAPI_SNDCP11 = 11, +}; + + +int gprs_llc_rcvmsg(struct msgb *msg, struct tlv_parsed *tv); +int gprs_llc_tx_ui(struct msgb *msg, u_int8_t sapi, int command); + +#endif diff --git a/openbsc/include/openbsc/gprs_ns.h b/openbsc/include/openbsc/gprs_ns.h new file mode 100644 index 000000000..90f1adf3e --- /dev/null +++ b/openbsc/include/openbsc/gprs_ns.h @@ -0,0 +1,61 @@ +#ifndef _GPRS_NS_H +#define _GPRS_NS_H + +struct gprs_ns_hdr { + u_int8_t pdu_type; + u_int8_t data[0]; +} __attribute__((packed)); + +/* TS 08.16, Section 10.3.7, Table 14 */ +enum ns_pdu_type { + NS_PDUT_UNITDATA = 0x00, + NS_PDUT_RESET = 0x02, + NS_PDUT_RESET_ACK = 0x03, + NS_PDUT_BLOCK = 0x04, + NS_PDUT_BLOCK_ACK = 0x05, + NS_PDUT_UNBLOCK = 0x06, + NS_PDUT_UNBLOCK_ACK = 0x07, + NS_PDUT_STATUS = 0x08, + NS_PDUT_ALIVE = 0x0a, + NS_PDUT_ALIVE_ACK = 0x0b, +}; + +/* TS 08.16, Section 10.3, Table 12 */ +enum ns_ctrl_ie { + NS_IE_CAUSE = 0x00, + NS_IE_VCI = 0x01, + NS_IE_PDU = 0x02, + NS_IE_BVCI = 0x03, + NS_IE_NSEI = 0x04, +}; + +/* TS 08.16, Section 10.3.2, Table 13 */ +enum ns_cause { + NS_CAUSE_TRANSIT_FAIL = 0x00, + NS_CAUSE_OM_INTERVENTION = 0x01, + NS_CAUSE_EQUIP_FAIL = 0x02, + NS_CAUSE_NSVC_BLOCKED = 0x03, + NS_CAUSE_NSVC_UNKNOWN = 0x04, + NS_CAUSE_BVCI_UNKNOWN = 0x05, + NS_CAUSE_SEM_INCORR_PDU = 0x08, + NS_CAUSE_PDU_INCOMP_PSTATE = 0x0a, + NS_CAUSE_PROTO_ERR_UNSPEC = 0x0b, + NS_CAUSE_INVAL_ESSENT_IE = 0x0c, + NS_CAUSE_MISSING_ESSENT_IE = 0x0d, +}; + +/* a layer 1 entity transporting NS frames */ +struct gprs_ns_link { + union { + struct { + int fd; + } ip; + }; +}; + + +int gprs_ns_rcvmsg(struct msgb *msg); + +int gprs_ns_sendmsg(struct gprs_ns_link *link, u_int16_t bvci, + struct msgb *msg); +#endif diff --git a/openbsc/include/openbsc/gprs_sgsn.h b/openbsc/include/openbsc/gprs_sgsn.h new file mode 100644 index 000000000..87c7fa874 --- /dev/null +++ b/openbsc/include/openbsc/gprs_sgsn.h @@ -0,0 +1,107 @@ +#ifndef _GPRS_SGSN_H +#define _GPRS_SGSN_H + +/* TS 04.08 4.1.3.3 GMM mobility management states on the network side */ +enum gprs_mm_state { + GMM_DEREGISTERED, /* 4.1.3.3.1.1 */ + GMM_COMMON_PROC_INIT, /* 4.1.3.3.1.2 */ + GMM_REGISTERED_NORMAL, /* 4.1.3.3.2.1 */ + GMM_REGISTERED_SUSPENDED, /* 4.1.3.3.2.2 */ + GMM_DEREGISTERED_INIT, /* 4.1.3.3.1.4 */ +}; + +enum gprs_ciph_algo { + GPRS_ALGO_GEA0, + GPRS_ALGO_GEA1, + GPRS_ALGO_GEA2, +}; + +#define MS_RADIO_ACCESS_CAPA + +/* According to TS 03.60, Table 5: SGSN MM and PDP Contexts */ +struct sgsn_mm_ctx { + struct llist_head list; + + char imsi[GSM_IMSI_LENGTH]; + enum gprs_mm_state mm_state; + u_int32_t p_tmsi; + u_int32_t p_tmsi_sig; + char imei[GSM_IMEI_LENGTH]; + char msisdn[GSM_EXTENSION_LENGTH]; + struct gprs_ra_id ra; + u_int16_t cell_id; + u_int32_t cell_id_age; + /* VLR number */ + u_int32_t new_sgsn_addr; + /* Authentication Triplets */ + /* Kc */ + /* CKSN */ + enum gprs_ciph_algo ciph_algo; + struct { + u_int8_t buf[14]; /* 10.5.5.12a */ + u_int8_t len; + } ms_radio_access_capa; + struct { + u_int8_t buf[4]; /* 10.5.5.12 */ + u_int8_t len; + } ms_network_capa; + u_int16_t drx_parms; + int mnrg; /* MS reported to HLR? */ + int ngaf; /* MS reported to MSC/VLR? */ + int ppf; /* paging for GPRS + non-GPRS? */ + /* SMS Parameters */ + int recovery; + u_int8_t radio_prio_sms; + + struct llist_head pdp_list; + + /* Additional bits not present in the GSM TS */ + u_int32_t tlli; + struct timer_list timer; + unsigned int T; +}; + +enum pdp_ctx_state { + PDP_STAE_NONE, +}; + +enum pdp_type { + PDP_TYPE_NONE, +}; + +struct sgsn_pdp_ctx { + struct llist_head list; + + unsigned int id; + enum pdp_ctx_state state; + enum pdp_type type; + u_int32_t addresss; + char *apn_subscribed; + char *apn_used; + u_int16_t nsapi; + u_int8_t ti; /* transaction identifier */ + u_int32_t ggsn_in_use; + int vplmn_allowed; + u_int32_t qos_profile_subscr; + u_int32_t qos_profile_req; + u_int32_t qos_profile_neg; + u_int8_t radio_prio; + u_int32_t tx_npdu_nr; + u_int32_t rx_npdu_nr; + u_int32_t tx_gtp_snd; + u_int32_t rx_gtp_snu; + u_int32_t charging_id; + int reordering_reqd; +}; + +/* look-up a SGSN MM context based on TLLI + RAI */ +struct sgsn_mm_ctx *sgsn_mm_ctx_by_tlli(u_int32_t tlli, + const struct gprs_ra_id *raid); +struct sgsn_mm_ctx *sgsn_mm_ctx_by_ptmsi(u_int32_t tmsi); +struct sgsn_mm_ctx *sgsn_mm_ctx_by_imsi(const char *imsi); + +/* Allocate a new SGSN MM context */ +struct sgsn_mm_ctx *sgsn_mm_ctx_alloc(u_int32_t tlli, + const struct gprs_ra_id *raid); + +#endif /* _GPRS_SGSN_H */ diff --git a/openbsc/include/openbsc/gsm_04_08_gprs.h b/openbsc/include/openbsc/gsm_04_08_gprs.h new file mode 100644 index 000000000..20ab04432 --- /dev/null +++ b/openbsc/include/openbsc/gsm_04_08_gprs.h @@ -0,0 +1,203 @@ +#ifndef _GSM48_GPRS_H +#define _GSM48_GPRS_H + +/* Table 10.4 / 10.4a, GPRS Mobility Management (GMM) */ +#define GSM48_MT_GMM_ATTACH_REQ 0x01 +#define GSM48_MT_GMM_ATTACH_ACK 0x02 +#define GSM48_MT_GMM_ATTACH_COMPL 0x03 +#define GSM48_MT_GMM_ATTACH_REJ 0x04 +#define GSM48_MT_GMM_DETACH_REQ 0x05 +#define GSM48_MT_GMM_DETACH_ACK 0x06 + +#define GSM48_MT_GMM_RA_UPD_REQ 0x08 +#define GSM48_MT_GMM_RA_UPD_ACK 0x09 +#define GSM48_MT_GMM_RA_UPD_COMPL 0x0a +#define GSM48_MT_GMM_RA_UPD_REJ 0x0b + +#define GSM48_MT_GMM_PTMSI_REALL_CMD 0x10 +#define GSM48_MT_GMM_PTMSI_REALL_COMPL 0x11 +#define GSM48_MT_GMM_AUTH_CIPH_REQ 0x12 +#define GSM48_MT_GMM_AUTH_CIPH_RESP 0x13 +#define GSM48_MT_GMM_AUTH_CIPH_REJ 0x14 +#define GSM48_MT_GMM_ID_REQ 0x15 +#define GSM48_MT_GMM_ID_RESP 0x16 +#define GSM48_MT_GMM_STATUS 0x20 +#define GSM48_MT_GMM_INFO 0x21 + +/* Table 10.4a, GPRS Session Management (GSM) */ +#define GSM48_MT_GSM_ACT_PDP_REQ 0x41 +#define GSM48_MT_GSM_ACT_PDP_ACK 0x42 +#define GSM48_MT_GSM_ACT_PDP_REJ 0x43 +#define GSM48_MT_GSM_REQ_PDP_ACT 0x44 +#define GSM48_MT_GSM_REQ_PDP_ACT_REJ 0x45 +#define GSM48_MT_GSM_DEACT_PDP_REQ 0x46 +#define GSM48_MT_GSM_DEACT_PDP_ACK 0x47 +#define GSM48_MT_GSM_ACT_AA_PDP_REQ 0x50 +#define GSM48_MT_GSM_ACT_AA_PDP_ACK 0x51 +#define GSM48_MT_GSM_ACT_AA_PDP_REJ 0x52 +#define GSM48_MT_GSM_DEACT_AA_PDP_REQ 0x53 +#define GSM48_MT_GSM_DEACT_AA_PDP_ACK 0x54 +#define GSM48_MT_GSM_STATUS 0x55 + +/* Chapter 10.5.5.2 / Table 10.5.135 */ +#define GPRS_ATT_T_ATTACH 1 +#define GPRS_ATT_T_ATT_WHILE_IMSI 2 +#define GPRS_ATT_T_COMBINED 3 + +/* Chapter 10.5.5.18 / Table 105.150 */ +#define GPRS_UPD_T_RA 0 +#define GPRS_UPD_T_RA_LA 1 +#define GPRS_UPD_T_RA_LA_IMSI_ATT 2 +#define GPRS_UPD_T_PERIODIC 3 + +enum gsm48_gprs_ie_mm { + GSM48_IE_GMM_TIMER_READY = 0x17, /* 10.5.7.3 */ + 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 */ +}; + +enum gsm48_gprs_ie_sm { + GSM48_IE_GSM_APN = 0x28, /* 10.5.6.1 */ + GSM48_IE_GSM_PROTO_CONF_OPT = 0x27, /* 10.5.6.3 */ + GSM48_IE_GSM_PDP_ADDR = 0x2b, /* 10.5.6.4 */ + GSM48_IE_GSM_AA_TMR = 0x29, /* 10.5.7.3 */ + GSM48_IE_GSM_NAME_FULL = 0x43, /* 10.5.3.5a */ + GSM48_IE_GSM_NAME_SHORT = 0x45, /* 10.5.3.5a */ + GSM48_IE_GSM_TIMEZONE = 0x46, /* 10.5.3.8 */ + GSM48_IE_GSM_UTC_AND_TZ = 0x47, /* 10.5.3.9 */ + GSM48_IE_GSM_LSA_ID = 0x48, /* 10.5.3.11 */ +}; + +/* Chapter 10.4.4.15 */ +struct gsm48_ra_id { + u_int8_t digits[3]; /* MCC + MNC BCD digits */ + u_int16_t lac; /* Location Area Code */ + u_int8_t rac; /* Routing Area Code */ +} __attribute__ ((packed)); + +/* Chapter 9.4.15 / Table 9.4.15 */ +struct gsm48_ra_upd_ack { + u_int8_t force_stby:4, /* 10.5.5.7 */ + upd_result:4; /* 10.5.5.17 */ + u_int8_t ra_upd_timer; /* 10.5.7.3 */ + struct gsm48_ra_id ra_id; /* 10.5.5.15 */ + u_int8_t data[0]; +} __attribute__((packed)); + +/* Chapter 10.5.7.3 */ +enum gsm48_gprs_tmr_unit { + GPRS_TMR_2SECONDS = 0 << 5, + GPRS_TMR_MINUTE = 1 << 5, + GPRS_TMR_6MINUTE = 2 << 5, + GPRS_TMR_DEACTIVATED = 3 << 5, +}; + +/* Chapter 9.4.2 / Table 9.4.2 */ +struct gsm48_attach_ack { + u_int8_t att_result:4, /* 10.5.5.7 */ + force_stby:4; /* 10.5.5.1 */ + u_int8_t ra_upd_timer; /* 10.5.7.3 */ + u_int8_t radio_prio; /* 10.5.7.2 */ + struct gsm48_ra_id ra_id; /* 10.5.5.15 */ + u_int8_t data[0]; +} __attribute__((packed)); + +/* Chapter 9.5.1 / Table 9.5.1 */ +struct gsm48_act_pdp_ctx_req { + u_int8_t req_nsapi; + u_int8_t req_llc_sapi; + u_int8_t req_qos_lv[4]; + u_int8_t data[0]; +} __attribute__((packed)); + +/* Chapter 9.5.2 / Table 9.5.2 */ +struct gsm48_act_pdp_ctx_ack { + u_int8_t llc_sapi; + u_int8_t qos_lv[4]; + u_int8_t radio_prio:4, + spare:4; + u_int8_t data[0]; +} __attribute__((packed)); + +/* Chapter 10.5.5.14 / Table 10.5.147 */ +enum gsm48_gmm_cause { + GMM_CAUSE_IMSI_UNKNOWN = 0x02, + GMM_CAUSE_ILLEGAL_MS = 0x03, + GMM_CAUSE_ILLEGAL_ME = 0x06, + GMM_CAUSE_GPRS_NOTALLOWED = 0x07, + GMM_CAUSE_GPRS_OTHER_NOTALLOWED = 0x08, + GMM_CAUSE_MS_ID_NOT_DERIVED = 0x09, + GMM_CAUSE_IMPL_DETACHED = 0x0a, + GMM_CAUSE_PLMN_NOTALLOWED = 0x0b, + GMM_CAUSE_LA_NOTALLOWED = 0x0c, + GMM_CAUSE_ROAMING_NOTALLOWED = 0x0d, + GMM_CAUSE_NO_GPRS_PLMN = 0x0e, + GMM_CAUSE_MSC_TEMP_NOTREACH = 0x10, + GMM_CAUSE_NET_FAIL = 0x11, + GMM_CAUSE_CONGESTION = 0x16, + GMM_CAUSE_SEM_INCORR_MSG = 0x5f, + GMM_CAUSE_INV_MAND_INFO = 0x60, + GMM_CAUSE_MSGT_NOTEXIST_NOTIMPL = 0x61, + GMM_CAUSE_MSGT_INCOMP_P_STATE = 0x62, + GMM_CAUSE_IE_NOTEXIST_NOTIMPL = 0x63, + GMM_CAUSE_COND_IE_ERR = 0x64, + GMM_CAUSE_MSG_INCOMP_P_STATE = 0x65, + GMM_CAUSE_PROTO_ERR_UNSPEC = 0x6f, +}; + +/* Chapter 10.4.6.6 / Table 10.5.157 */ +enum gsm48_gsm_cause { + GSM_CAUSE_INSUFF_RSRC = 0x1a, + GSM_CAUSE_MISSING_APN = 0x1b, + GSM_CAUSE_UNKNOWN_PDP = 0x1c, + GSM_CAUSE_AUTH_FAILED = 0x1d, + GSM_CAUSE_ACT_REJ_GGSN = 0x1e, + GSM_CAUSE_ACT_REJ_UNSPEC = 0x1f, + GSM_CAUSE_SERV_OPT_NOTSUPP = 0x20, + GSM_CAUSE_REQ_SERV_OPT_NOTSUB = 0x21, + GSM_CAUSE_SERV_OPT_TEMP_OOO = 0x22, + GSM_CAUSE_NSAPI_IN_USE = 0x23, + GSM_CAUSE_DEACT_REGULAR = 0x24, + GSM_CAUSE_QOS_NOT_ACCEPTED = 0x25, + GSM_CAUSE_NET_FAIL = 0x26, + GSM_CAUSE_REACT_RQD = 0x27, + GSM_CAUSE_FEATURE_NOTSUPP = 0x28, + GSM_CAUSE_INVALID_TRANS_ID = 0x51, + GSM_CAUSE_SEM_INCORR_MSG = 0x5f, + GSM_CAUSE_INV_MAND_INFO = 0x60, + GSM_CAUSE_MSGT_NOTEXIST_NOTIMPL = 0x61, + GSM_CAUSE_MSGT_INCOMP_P_STATE = 0x62, + GSM_CAUSE_IE_NOTEXIST_NOTIMPL = 0x63, + GSM_CAUSE_COND_IE_ERR = 0x64, + GSM_CAUSE_MSG_INCOMP_P_STATE = 0x65, + GSM_CAUSE_PROTO_ERR_UNSPEC = 0x6f, +}; + +/* GSM TS 03.03 Chapter 2.6 */ +enum gprs_tlli_tyoe { + TLLI_LOCAL, + TLLI_FOREIGN, + TLLI_RANDOM, + TLLI_AUXILIARY, + TLLI_RESERVED, +}; + +/* Section 6.1.2.2: Session management states on the network side */ +enum gsm48_pdp_state { + PDP_S_INACTIVE, + PDP_S_ACTIVE_PENDING, + PDP_S_ACTIVE, + PDP_S_INACTIVE_PENDING, + PDP_S_MODIFY_PENDING, +}; + +int gprs_tlli_type(u_int32_t tlli); + +struct gsm_bts *gsm48_bts_by_ra_id(struct gsm_network *net, + const u_int8_t *buf, unsigned int len); + +#endif /* _GSM48_GPRS_H */ diff --git a/openbsc/src/Makefile.am b/openbsc/src/Makefile.am index 38150a9bf..718252f77 100644 --- a/openbsc/src/Makefile.am +++ b/openbsc/src/Makefile.am @@ -4,7 +4,7 @@ AM_LDFLAGS = $(LIBOSMOCORE_LIBS) sbin_PROGRAMS = bsc_hack bs11_config ipaccess-find ipaccess-config \ isdnsync bsc_mgcp ipaccess-proxy -noinst_LIBRARIES = libbsc.a libmsc.a libvty.a +noinst_LIBRARIES = libbsc.a libmsc.a libvty.a libsccp.a libsgsn.a noinst_HEADERS = vty/cardshell.h bscdir = $(libdir) @@ -19,6 +19,9 @@ libbsc_a_SOURCES = abis_rsl.c abis_nm.c gsm_data.c gsm_04_08_utils.c \ rtp_proxy.c bts_siemens_bs11.c bts_ipaccess_nanobts.c \ bts_unknown.c bsc_version.c bsc_api.c +libsgsn_a_SOURCES = gprs_ns.c gprs_bssgp.c gprs_llc.c gsm_04_08_gprs.c \ + crc24.c gprs_sgsn.c + libmsc_a_SOURCES = gsm_subscriber.c db.c \ mncc.c gsm_04_08.c gsm_04_11.c transaction.c \ token_auth.c rrlp.c gsm_04_80.c ussd.c silent_call.c \ @@ -30,7 +33,7 @@ libvty_a_SOURCES = vty/buffer.c vty/command.c vty/vector.c vty/vty.c \ libsccp_a_SOURCES = sccp/sccp.c bsc_hack_SOURCES = bsc_hack.c bsc_init.c vty_interface.c vty_interface_layer3.c -bsc_hack_LDADD = libmsc.a libbsc.a libmsc.a libvty.a -ldl -ldbi $(LIBCRYPT) +bsc_hack_LDADD = libmsc.a libbsc.a libmsc.a libsgsn.a libvty.a -ldl -ldbi $(LIBCRYPT) bs11_config_SOURCES = bs11_config.c abis_nm.c gsm_data.c debug.c \ rs232.c bts_siemens_bs11.c diff --git a/openbsc/src/crc24.c b/openbsc/src/crc24.c new file mode 100644 index 000000000..108212083 --- /dev/null +++ b/openbsc/src/crc24.c @@ -0,0 +1,69 @@ +/* GPRS LLC CRC-24 Implementation */ + +/* (C) 2008-2009 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 + +/* CRC24 table - FCS */ +static const u_int32_t tbl_crc24[256] = { + 0x00000000, 0x00d6a776, 0x00f64557, 0x0020e221, 0x00b78115, 0x00612663, 0x0041c442, 0x00976334, + 0x00340991, 0x00e2aee7, 0x00c24cc6, 0x0014ebb0, 0x00838884, 0x00552ff2, 0x0075cdd3, 0x00a36aa5, + 0x00681322, 0x00beb454, 0x009e5675, 0x0048f103, 0x00df9237, 0x00093541, 0x0029d760, 0x00ff7016, + 0x005c1ab3, 0x008abdc5, 0x00aa5fe4, 0x007cf892, 0x00eb9ba6, 0x003d3cd0, 0x001ddef1, 0x00cb7987, + 0x00d02644, 0x00068132, 0x00266313, 0x00f0c465, 0x0067a751, 0x00b10027, 0x0091e206, 0x00474570, + 0x00e42fd5, 0x003288a3, 0x00126a82, 0x00c4cdf4, 0x0053aec0, 0x008509b6, 0x00a5eb97, 0x00734ce1, + 0x00b83566, 0x006e9210, 0x004e7031, 0x0098d747, 0x000fb473, 0x00d91305, 0x00f9f124, 0x002f5652, + 0x008c3cf7, 0x005a9b81, 0x007a79a0, 0x00acded6, 0x003bbde2, 0x00ed1a94, 0x00cdf8b5, 0x001b5fc3, + 0x00fb4733, 0x002de045, 0x000d0264, 0x00dba512, 0x004cc626, 0x009a6150, 0x00ba8371, 0x006c2407, + 0x00cf4ea2, 0x0019e9d4, 0x00390bf5, 0x00efac83, 0x0078cfb7, 0x00ae68c1, 0x008e8ae0, 0x00582d96, + 0x00935411, 0x0045f367, 0x00651146, 0x00b3b630, 0x0024d504, 0x00f27272, 0x00d29053, 0x00043725, + 0x00a75d80, 0x0071faf6, 0x005118d7, 0x0087bfa1, 0x0010dc95, 0x00c67be3, 0x00e699c2, 0x00303eb4, + 0x002b6177, 0x00fdc601, 0x00dd2420, 0x000b8356, 0x009ce062, 0x004a4714, 0x006aa535, 0x00bc0243, + 0x001f68e6, 0x00c9cf90, 0x00e92db1, 0x003f8ac7, 0x00a8e9f3, 0x007e4e85, 0x005eaca4, 0x00880bd2, + 0x00437255, 0x0095d523, 0x00b53702, 0x00639074, 0x00f4f340, 0x00225436, 0x0002b617, 0x00d41161, + 0x00777bc4, 0x00a1dcb2, 0x00813e93, 0x005799e5, 0x00c0fad1, 0x00165da7, 0x0036bf86, 0x00e018f0, + 0x00ad85dd, 0x007b22ab, 0x005bc08a, 0x008d67fc, 0x001a04c8, 0x00cca3be, 0x00ec419f, 0x003ae6e9, + 0x00998c4c, 0x004f2b3a, 0x006fc91b, 0x00b96e6d, 0x002e0d59, 0x00f8aa2f, 0x00d8480e, 0x000eef78, + 0x00c596ff, 0x00133189, 0x0033d3a8, 0x00e574de, 0x007217ea, 0x00a4b09c, 0x008452bd, 0x0052f5cb, + 0x00f19f6e, 0x00273818, 0x0007da39, 0x00d17d4f, 0x00461e7b, 0x0090b90d, 0x00b05b2c, 0x0066fc5a, + 0x007da399, 0x00ab04ef, 0x008be6ce, 0x005d41b8, 0x00ca228c, 0x001c85fa, 0x003c67db, 0x00eac0ad, + 0x0049aa08, 0x009f0d7e, 0x00bfef5f, 0x00694829, 0x00fe2b1d, 0x00288c6b, 0x00086e4a, 0x00dec93c, + 0x0015b0bb, 0x00c317cd, 0x00e3f5ec, 0x0035529a, 0x00a231ae, 0x007496d8, 0x005474f9, 0x0082d38f, + 0x0021b92a, 0x00f71e5c, 0x00d7fc7d, 0x00015b0b, 0x0096383f, 0x00409f49, 0x00607d68, 0x00b6da1e, + 0x0056c2ee, 0x00806598, 0x00a087b9, 0x007620cf, 0x00e143fb, 0x0037e48d, 0x001706ac, 0x00c1a1da, + 0x0062cb7f, 0x00b46c09, 0x00948e28, 0x0042295e, 0x00d54a6a, 0x0003ed1c, 0x00230f3d, 0x00f5a84b, + 0x003ed1cc, 0x00e876ba, 0x00c8949b, 0x001e33ed, 0x008950d9, 0x005ff7af, 0x007f158e, 0x00a9b2f8, + 0x000ad85d, 0x00dc7f2b, 0x00fc9d0a, 0x002a3a7c, 0x00bd5948, 0x006bfe3e, 0x004b1c1f, 0x009dbb69, + 0x0086e4aa, 0x005043dc, 0x0070a1fd, 0x00a6068b, 0x003165bf, 0x00e7c2c9, 0x00c720e8, 0x0011879e, + 0x00b2ed3b, 0x00644a4d, 0x0044a86c, 0x00920f1a, 0x00056c2e, 0x00d3cb58, 0x00f32979, 0x00258e0f, + 0x00eef788, 0x003850fe, 0x0018b2df, 0x00ce15a9, 0x0059769d, 0x008fd1eb, 0x00af33ca, 0x007994bc, + 0x00dafe19, 0x000c596f, 0x002cbb4e, 0x00fa1c38, 0x006d7f0c, 0x00bbd87a, 0x009b3a5b, 0x004d9d2d +}; + +#define INIT_CRC24 0xffffff + +u_int32_t crc24_calc(u_int32_t fcs, u_int8_t *cp, unsigned int len) +{ + while (len--) + fcs = (fcs >> 8) ^ tbl_crc24[(fcs ^ *cp++) & 0xff]; + return fcs; +} diff --git a/openbsc/src/gprs_bssgp.c b/openbsc/src/gprs_bssgp.c new file mode 100644 index 000000000..de57d25df --- /dev/null +++ b/openbsc/src/gprs_bssgp.c @@ -0,0 +1,397 @@ +/* GPRS BSSGP protocol implementation as per 3GPP TS 08.18 */ + +/* (C) 2009 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 +#include +#include +#include +#include +#include + +/* global pointer to the gsm network data structure */ +/* FIXME: this must go! */ +extern struct gsm_network *bsc_gsmnet; + +/* Chapter 11.3.9 / Table 11.10: Cause coding */ +static const char *bssgp_cause_strings[] = { + [BSSGP_CAUSE_PROC_OVERLOAD] = "Processor overload", + [BSSGP_CAUSE_EQUIP_FAIL] = "Equipment Failure", + [BSSGP_CAUSE_TRASIT_NET_FAIL] = "Transit netowkr service failure", + [BSSGP_CAUSE_CAPA_GREATER_0KPBS]= "Transmission capacity modified", + [BSSGP_CAUSE_UNKNOWN_MS] = "Unknown MS", + [BSSGP_CAUSE_UNKNOWN_BVCI] = "Unknown BVCI", + [BSSGP_CAUSE_CELL_TRAF_CONG] = "Cell traffic congestion", + [BSSGP_CAUSE_SGSN_CONG] = "SGSN congestion", + [BSSGP_CAUSE_OML_INTERV] = "O&M intervention", + [BSSGP_CAUSE_BVCI_BLOCKED] = "BVCI blocked", + [BSSGP_CAUSE_PFC_CREATE_FAIL] = "PFC create failure", + [BSSGP_CAUSE_SEM_INCORR_PDU] = "Semantically incorrect PDU", + [BSSGP_CAUSE_INV_MAND_INF] = "Invalid mandatory information", + [BSSGP_CAUSE_MISSING_MAND_IE] = "Missing mandatory IE", + [BSSGP_CAUSE_MISSING_COND_IE] = "Missing conditional IE", + [BSSGP_CAUSE_UNEXP_COND_IE] = "Unexpected conditional IE", + [BSSGP_CAUSE_COND_IE_ERR] = "Conditional IE error", + [BSSGP_CAUSE_PDU_INCOMP_STATE] = "PDU incompatible with protocol state", + [BSSGP_CAUSE_PROTO_ERR_UNSPEC] = "Protocol error - unspecified", + [BSSGP_CAUSE_PDU_INCOMP_FEAT] = "PDU not compatible with feature set", +}; + +static const char *bssgp_cause_str(enum gprs_bssgp_cause cause) +{ + if (cause >= ARRAY_SIZE(bssgp_cause_strings)) + return "undefined"; + + if (bssgp_cause_strings[cause]) + return bssgp_cause_strings[cause]; + + return "undefined"; +} + +static inline int bssgp_tlv_parse(struct tlv_parsed *tp, u_int8_t *buf, int len) +{ + return tlv_parse(tp, &tvlv_att_def, buf, len, 0, 0); +} + +static inline struct msgb *bssgp_msgb_alloc(void) +{ + return msgb_alloc_headroom(4096, 128, "BSSGP"); +} + +/* Transmit a simple response such as BLOCK/UNBLOCK/RESET ACK/NACK */ +static int bssgp_tx_simple_bvci(u_int8_t pdu_type, u_int16_t bvci, u_int16_t ns_bvci) +{ + struct msgb *msg = bssgp_msgb_alloc(); + struct bssgp_normal_hdr *bgph = + (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph)); + u_int16_t _bvci; + + bgph->pdu_type = pdu_type; + _bvci = htons(bvci); + msgb_tvlv_put(msg, BSSGP_IE_BVCI, 2, (u_int8_t *) &_bvci); + + return gprs_ns_sendmsg(NULL, ns_bvci, msg); +} + +/* Chapter 10.4.5: Flow Control BVC ACK */ +static int bssgp_tx_fc_bvc_ack(u_int8_t tag, u_int16_t ns_bvci) +{ + struct msgb *msg = bssgp_msgb_alloc(); + struct bssgp_normal_hdr *bgph = + (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph)); + + bgph->pdu_type = BSSGP_PDUT_FLOW_CONTROL_BVC_ACK; + msgb_tvlv_put(msg, BSSGP_IE_TAG, 1, &tag); + + return gprs_ns_sendmsg(NULL, ns_bvci, msg); +} + +/* Chapter 10.4.14: Status */ +static int bssgp_tx_status(u_int8_t cause, u_int16_t *bvci, struct msgb *orig_msg) +{ + struct msgb *msg = bssgp_msgb_alloc(); + struct bssgp_normal_hdr *bgph = + (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph)); + + DEBUGPC(DGPRS, "BSSGP: TX STATUS, cause=%s\n", bssgp_cause_str(cause)); + + bgph->pdu_type = BSSGP_PDUT_STATUS; + msgb_tvlv_put(msg, BSSGP_IE_CAUSE, 1, &cause); + if (bvci) { + u_int16_t _bvci = htons(*bvci); + msgb_tvlv_put(msg, BSSGP_IE_BVCI, 2, (u_int8_t *) &_bvci); + } + if (orig_msg) + msgb_tvlv_put(msg, BSSGP_IE_PDU_IN_ERROR, + msgb_l3len(orig_msg), orig_msg->l3h); + + return gprs_ns_sendmsg(NULL, 0, msg); +} + +/* Uplink unit-data */ +static int bssgp_rx_ul_ud(struct msgb *msg, u_int16_t bvci) +{ + struct bssgp_ud_hdr *budh = (struct bssgp_ud_hdr *) msg->l3h; + struct gsm_bts *bts; + int data_len = msgb_l3len(msg) - sizeof(*budh); + struct tlv_parsed tp; + int rc; + + DEBUGP(DGPRS, "BSSGP UL-UD\n"); + + msg->tlli = ntohl(budh->tlli); + rc = bssgp_tlv_parse(&tp, budh->data, data_len); + + /* Cell ID and LLC_PDU are the only mandatory IE */ + if (!TLVP_PRESENT(&tp, BSSGP_IE_CELL_ID) || + !TLVP_PRESENT(&tp, BSSGP_IE_LLC_PDU)) + return -EIO; + + /* Determine the BTS based on the Cell ID */ + bts = gsm48_bts_by_ra_id(bsc_gsmnet, + TLVP_VAL(&tp, BSSGP_IE_CELL_ID), + TLVP_LEN(&tp, BSSGP_IE_CELL_ID)); + if (bts) + msg->trx = bts->c0; + + msg->llch = TLVP_VAL(&tp, BSSGP_IE_LLC_PDU); + + return gprs_llc_rcvmsg(msg, &tp); +} + +static int bssgp_rx_suspend(struct msgb *msg, u_int16_t bvci) +{ + struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msg->l3h; + int data_len = msgb_l3len(msg) - sizeof(*bgph); + struct tlv_parsed tp; + int rc; + + DEBUGP(DGPRS, "BSSGP SUSPEND\n"); + + rc = bssgp_tlv_parse(&tp, bgph->data, data_len); + if (rc < 0) + return rc; + + if (!TLVP_PRESENT(&tp, BSSGP_IE_TLLI) || + !TLVP_PRESENT(&tp, BSSGP_IE_ROUTEING_AREA)) + return -EIO; + + /* SEND SUSPEND_ACK or SUSPEND_NACK */ + /* FIXME */ +} + +static int bssgp_rx_resume(struct msgb *msg, u_int16_t bvci) +{ + struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msg->l3h; + int data_len = msgb_l3len(msg) - sizeof(*bgph); + struct tlv_parsed tp; + int rc; + + DEBUGP(DGPRS, "BSSGP RESUME\n"); + + rc = bssgp_tlv_parse(&tp, bgph->data, data_len); + if (rc < 0) + return rc; + + if (!TLVP_PRESENT(&tp, BSSGP_IE_TLLI) || + !TLVP_PRESENT(&tp, BSSGP_IE_ROUTEING_AREA) || + !TLVP_PRESENT(&tp, BSSGP_IE_SUSPEND_REF_NR)) + return -EIO; + + /* SEND RESUME_ACK or RESUME_NACK */ + /* FIXME */ +} + +static int bssgp_rx_fc_bvc(struct msgb *msg, struct tlv_parsed *tp, + u_int16_t ns_bvci) +{ + + DEBUGP(DGPRS, "BSSGP FC BVC\n"); + + if (!TLVP_PRESENT(tp, BSSGP_IE_TAG) || + !TLVP_PRESENT(tp, BSSGP_IE_BVC_BUCKET_SIZE) || + !TLVP_PRESENT(tp, BSSGP_IE_BUCKET_LEAK_RATE) || + !TLVP_PRESENT(tp, BSSGP_IE_BMAX_DEFAULT_MS) || + !TLVP_PRESENT(tp, BSSGP_IE_R_DEFAULT_MS)) + return bssgp_tx_status(BSSGP_CAUSE_MISSING_MAND_IE, NULL, msg); + + /* Send FLOW_CONTROL_BVC_ACK */ + return bssgp_tx_fc_bvc_ack(*TLVP_VAL(tp, BSSGP_IE_TAG), ns_bvci); +} +/* We expect msg->l3h to point to the BSSGP header */ +int gprs_bssgp_rcvmsg(struct msgb *msg, u_int16_t ns_bvci) +{ + struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msg->l3h; + struct tlv_parsed tp; + u_int8_t pdu_type = bgph->pdu_type; + int data_len = msgb_l3len(msg) - sizeof(*bgph); + u_int16_t bvci; + int rc = 0; + + if (pdu_type != BSSGP_PDUT_UL_UNITDATA && + pdu_type != BSSGP_PDUT_DL_UNITDATA) + rc = bssgp_tlv_parse(&tp, bgph->data, data_len); + + switch (pdu_type) { + case BSSGP_PDUT_UL_UNITDATA: + /* some LLC data from the MS */ + rc = bssgp_rx_ul_ud(msg, ns_bvci); + break; + case BSSGP_PDUT_RA_CAPABILITY: + /* BSS requests RA capability or IMSI */ + DEBUGP(DGPRS, "BSSGP RA CAPABILITY UPDATE\n"); + /* FIXME: send RA_CAPA_UPDATE_ACK */ + break; + case BSSGP_PDUT_RADIO_STATUS: + DEBUGP(DGPRS, "BSSGP RADIO STATUS\n"); + /* BSS informs us of some exception */ + break; + case BSSGP_PDUT_SUSPEND: + /* MS wants to suspend */ + rc = bssgp_rx_suspend(msg, ns_bvci); + break; + case BSSGP_PDUT_RESUME: + /* MS wants to resume */ + rc = bssgp_rx_resume(msg, ns_bvci); + break; + case BSSGP_PDUT_FLUSH_LL: + /* BSS informs MS has moved to one cell to other cell */ + DEBUGP(DGPRS, "BSSGP FLUSH LL\n"); + /* Send FLUSH_LL_ACK */ + break; + case BSSGP_PDUT_LLC_DISCARD: + /* BSS informs that some LLC PDU's have been discarded */ + DEBUGP(DGPRS, "BSSGP LLC DISCARDED\n"); + break; + case BSSGP_PDUT_FLOW_CONTROL_BVC: + /* BSS informs us of available bandwidth in Gb interface */ + rc = bssgp_rx_fc_bvc(msg, &tp, ns_bvci); + break; + case BSSGP_PDUT_FLOW_CONTROL_MS: + /* BSS informs us of available bandwidth to one MS */ + DEBUGP(DGPRS, "BSSGP FC MS\n"); + /* Send FLOW_CONTROL_MS_ACK */ + break; + case BSSGP_PDUT_BVC_BLOCK: + /* BSS tells us that BVC shall be blocked */ + DEBUGP(DGPRS, "BSSGP BVC BLOCK "); + if (!TLVP_PRESENT(&tp, BSSGP_IE_BVCI) || + !TLVP_PRESENT(&tp, BSSGP_IE_CAUSE)) + goto err_mand_ie; + bvci = ntohs(*(u_int16_t *)TLVP_VAL(&tp, BSSGP_IE_BVCI)); + DEBUGPC(DGPRS, "BVCI=%u, cause=%s\n", bvci, + bssgp_cause_str(*TLVP_VAL(&tp, BSSGP_IE_CAUSE))); + rc = bssgp_tx_simple_bvci(BSSGP_PDUT_BVC_BLOCK_ACK, + bvci, ns_bvci); + break; + case BSSGP_PDUT_BVC_UNBLOCK: + /* BSS tells us that BVC shall be unblocked */ + DEBUGP(DGPRS, "BSSGP BVC UNBLOCK "); + if (!TLVP_PRESENT(&tp, BSSGP_IE_BVCI)) + goto err_mand_ie; + bvci = ntohs(*(u_int16_t *)TLVP_VAL(&tp, BSSGP_IE_BVCI)); + DEBUGPC(DGPRS, "BVCI=%u\n", bvci); + rc = bssgp_tx_simple_bvci(BSSGP_PDUT_BVC_UNBLOCK_ACK, + bvci, ns_bvci); + break; + case BSSGP_PDUT_BVC_RESET: + /* BSS tells us that BVC init is required */ + DEBUGP(DGPRS, "BSSGP BVC RESET "); + if (!TLVP_PRESENT(&tp, BSSGP_IE_BVCI) || + !TLVP_PRESENT(&tp, BSSGP_IE_CAUSE)) + goto err_mand_ie; + bvci = ntohs(*(u_int16_t *)TLVP_VAL(&tp, BSSGP_IE_BVCI)); + DEBUGPC(DGPRS, "BVCI=%u, cause=%s\n", bvci, + bssgp_cause_str(*TLVP_VAL(&tp, BSSGP_IE_CAUSE))); + rc = bssgp_tx_simple_bvci(BSSGP_PDUT_BVC_RESET_ACK, + bvci, ns_bvci); + break; + case BSSGP_PDUT_STATUS: + /* Some exception has occurred */ + case BSSGP_PDUT_DOWNLOAD_BSS_PFC: + case BSSGP_PDUT_CREATE_BSS_PFC_ACK: + case BSSGP_PDUT_CREATE_BSS_PFC_NACK: + case BSSGP_PDUT_MODIFY_BSS_PFC: + case BSSGP_PDUT_DELETE_BSS_PFC_ACK: + DEBUGP(DGPRS, "BSSGP PDU type 0x%02x not [yet] implemented\n", + pdu_type); + break; + /* those only exist in the SGSN -> BSS direction */ + case BSSGP_PDUT_DL_UNITDATA: + case BSSGP_PDUT_PAGING_PS: + case BSSGP_PDUT_PAGING_CS: + case BSSGP_PDUT_RA_CAPA_UPDATE_ACK: + case BSSGP_PDUT_SUSPEND_ACK: + case BSSGP_PDUT_SUSPEND_NACK: + case BSSGP_PDUT_RESUME_ACK: + case BSSGP_PDUT_RESUME_NACK: + case BSSGP_PDUT_FLUSH_LL_ACK: + case BSSGP_PDUT_FLOW_CONTROL_BVC_ACK: + case BSSGP_PDUT_FLOW_CONTROL_MS_ACK: + case BSSGP_PDUT_BVC_BLOCK_ACK: + case BSSGP_PDUT_BVC_UNBLOCK_ACK: + case BSSGP_PDUT_SGSN_INVOKE_TRACE: + DEBUGP(DGPRS, "BSSGP PDU type 0x%02x only exists in DL\n", + pdu_type); + rc = -EINVAL; + break; + default: + DEBUGP(DGPRS, "BSSGP PDU type 0x%02x unknown\n", pdu_type); + break; + } + + return rc; +err_mand_ie: + return bssgp_tx_status(BSSGP_CAUSE_MISSING_MAND_IE, NULL, msg); +} + +int gprs_bssgp_tx_dl_ud(struct msgb *msg) +{ + struct gsm_bts *bts; + struct bssgp_ud_hdr *budh; + u_int8_t llc_pdu_tlv_hdr_len = 2; + u_int8_t *llc_pdu_tlv, *qos_profile; + u_int16_t pdu_lifetime = 1000; /* centi-seconds */ + u_int8_t qos_profile_default[3] = { 0x00, 0x00, 0x21 }; + u_int16_t msg_len = msg->len; + + if (!msg->trx) { + DEBUGP(DGPRS, "Cannot transmit DL-UD without TRX assigned\n"); + return -EINVAL; + } + + bts = msg->trx->bts; + + if (msg->len > TVLV_MAX_ONEBYTE) + llc_pdu_tlv_hdr_len += 1; + + /* prepend the tag and length of the LLC-PDU TLV */ + llc_pdu_tlv = msgb_push(msg, llc_pdu_tlv_hdr_len); + llc_pdu_tlv[0] = BSSGP_IE_LLC_PDU; + if (llc_pdu_tlv_hdr_len > 2) { + llc_pdu_tlv[1] = msg_len >> 8; + llc_pdu_tlv[2] = msg_len & 0xff; + } else { + llc_pdu_tlv[1] = msg_len & 0x3f; + llc_pdu_tlv[1] |= 0x80; + } + + /* FIXME: optional elements */ + + /* prepend the pdu lifetime */ + pdu_lifetime = htons(pdu_lifetime); + msgb_tvlv_push(msg, BSSGP_IE_PDU_LIFETIME, 2, (u_int8_t *)&pdu_lifetime); + + /* prepend the QoS profile, TLLI and pdu type */ + budh = (struct bssgp_ud_hdr *) msgb_push(msg, sizeof(*budh)); + memcpy(budh->qos_profile, qos_profile_default, sizeof(qos_profile_default)); + budh->tlli = htonl(msg->tlli); + budh->pdu_type = BSSGP_PDUT_DL_UNITDATA; + + return gprs_ns_sendmsg(NULL, bts->gprs.cell.bvci, msg); +} diff --git a/openbsc/src/gprs_llc.c b/openbsc/src/gprs_llc.c new file mode 100644 index 000000000..2c927c6cf --- /dev/null +++ b/openbsc/src/gprs_llc.c @@ -0,0 +1,420 @@ +/* GPRS LLC protocol implementation as per 3GPP TS 04.64 */ + +/* (C) 2009 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 +#include +#include +#include + +/* Section 4.5.2 Logical Link States + Annex C.2 */ +enum gprs_llc_ll_state { + GPRS_LLS_UNASSIGNED = 1, /* No TLLI yet */ + GPRS_LLS_ASSIGNED_ADM = 2, /* TLLI assigned */ + GPRS_LLS_LOCAL_EST = 3, /* Local Establishment */ + GPRS_LLS_REMOTE_EST = 4, /* Remote Establishment */ + GPRS_LLS_ABM = 5, + GPRS_LLS_LOCAL_REL = 6, /* Local Release */ + GPRS_LLS_TIMER_REC = 7, /* Timer Recovery */ +}; + +/* Section 4.7.1: Logical Link Entity: One per DLCI (TLLI + SAPI) */ +struct gprs_llc_lle { + struct llist_head list; + struct timer_list t200; + struct timer_list t201; /* wait for acknowledgement */ + + enum gprs_llc_ll_state state; + + u_int32_t tlli; + u_int32_t sapi; + + u_int8_t v_sent; + u_int8_t v_ack; + u_int8_t v_recv; + + unsigned int n200; + unsigned int retrans_ctr; +}; + +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, +}; + +struct gprs_llc_hdr_parsed { + u_int8_t sapi; + u_int8_t is_cmd:1, + ack_req:1, + is_encrypted:1; + u_int32_t seq_rx; + u_int32_t seq_tx; + u_int32_t fcs; + u_int32_t fcs_calc; + u_int8_t *data; + enum gprs_llc_cmd cmd; +}; + +#define LLC_ALLOC_SIZE 16384 +#define UI_HDR_LEN 3 +#define N202 4 +#define CRC24_LENGTH 3 + +static int gprs_llc_fcs(u_int8_t *data, unsigned int len) +{ + u_int32_t fcs_calc; + + fcs_calc = crc24_calc(INIT_CRC24, data, len); + fcs_calc = ~fcs_calc; + fcs_calc &= 0xffffff; + + return fcs_calc; +} + +/* transmit a simple U frame */ +static int gprs_llc_tx_u() +{ + struct msgb *msg = msgb_alloc(LLC_ALLOC_SIZE, "GPRS/LLC"); + + if (!msg) + return -ENOMEM; + + + + /* transmit the frame via BSSGP->NS->... */ +} + +static void t200_expired(void *data) +{ + struct gprs_llc_lle *lle = data; + + /* 8.5.1.3: Expiry of T200 */ + + if (lle->retrans_ctr >= lle->n200) { + /* FIXME: LLGM-STATUS-IND, LL-RELEASE-IND/CNF */ + lle->state = GPRS_LLS_ASSIGNED_ADM; + } + + switch (lle->state) { + case GPRS_LLS_LOCAL_EST: + /* retransmit SABM */ + /* re-start T200 */ + lle->retrans_ctr++; + break; + case GPRS_LLS_LOCAL_REL: + /* retransmit DISC */ + /* re-start T200 */ + lle->retrans_ctr++; + break; + } + +} + +static void t201_expired(void *data) +{ + struct gprs_llc_lle *lle = data; + + if (lle->retrans_ctr < lle->n200) { + /* transmit apropriate supervisory frame (8.6.4.1) */ + /* set timer T201 */ + lle->retrans_ctr++; + } +} + +/* Transmit a UI frame over the given SAPI */ +int gprs_llc_tx_ui(struct msgb *msg, u_int8_t sapi, int command) +{ + u_int8_t *fcs, *llch; + u_int8_t addr, ctrl[2]; + u_int32_t fcs_calc; + u_int16_t nu = 0; + + /* Address Field */ + addr = sapi & 0xf; + if (command) + addr |= 0x40; + + /* Control Field */ + ctrl[0] = 0xc0; + ctrl[0] |= nu >> 6; + ctrl[1] = (nu << 2) & 0xfc; + ctrl[1] |= 0x01; /* Protected Mode */ + + /* prepend LLC UI header */ + llch = msgb_push(msg, 3); + llch[0] = addr; + llch[1] = ctrl[0]; + llch[2] = ctrl[1]; + + /* append FCS to end of frame */ + fcs = msgb_put(msg, 3); + fcs_calc = gprs_llc_fcs(llch, fcs - llch); + fcs[0] = fcs_calc & 0xff; + fcs[1] = (fcs_calc >> 8) & 0xff; + fcs[2] = (fcs_calc >> 16) & 0xff; + + return gprs_bssgp_tx_dl_ud(msg); +} + +static int gprs_llc_hdr_dump(struct gprs_llc_hdr_parsed *gph) +{ + DEBUGP(DGPRS, "LLC SAPI=%u %c %c FCS=0x%06x(%s) ", + gph->sapi, gph->is_cmd ? 'C' : 'R', gph->ack_req ? 'A' : ' ', + gph->fcs, gph->fcs_calc == gph->fcs ? "correct" : "WRONG"); + + if (gph->cmd) + DEBUGPC(DGPRS, "CMD=%u ", gph->cmd); + + if (gph->data) + DEBUGPC(DGPRS, "DATA "); + + DEBUGPC(DGPRS, "\n"); +} +static int gprs_llc_hdr_rx(struct gprs_llc_hdr_parsed *gph, + struct gprs_llc_lle *lle) +{ + switch (gph->cmd) { + case GPRS_LLC_SABM: /* Section 6.4.1.1 */ + lle->v_sent = lle->v_ack = lle->v_recv = 0; + if (lle->state == GPRS_LLS_ASSIGNED_ADM) { + /* start re-establishment (8.7.1) */ + } + lle->state = GPRS_LLS_REMOTE_EST; + /* FIXME: Send UA */ + lle->state = GPRS_LLS_ABM; + /* FIXME: process data */ + break; + case GPRS_LLC_DISC: /* Section 6.4.1.2 */ + /* FIXME: Send UA */ + /* terminate ABM */ + lle->state = GPRS_LLS_ASSIGNED_ADM; + break; + case GPRS_LLC_UA: /* Section 6.4.1.3 */ + if (lle->state == GPRS_LLS_LOCAL_EST) + lle->state = GPRS_LLS_ABM; + break; + case GPRS_LLC_DM: /* Section 6.4.1.4: ABM cannot be performed */ + if (lle->state == GPRS_LLS_LOCAL_EST) + lle->state = GPRS_LLS_ASSIGNED_ADM; + break; + case GPRS_LLC_FRMR: /* Section 6.4.1.5 */ + break; + case GPRS_LLC_XID: /* Section 6.4.1.6 */ + break; + } + + return 0; +} + +/* parse a GPRS LLC header, also check for invalid frames */ +static int gprs_llc_hdr_parse(struct gprs_llc_hdr_parsed *ghp, + const u_int8_t *llc_hdr, int len) +{ + u_int8_t *ctrl = llc_hdr+1; + int is_sack = 0; + unsigned int crc_length; + u_int32_t fcs_calc; + + if (len <= CRC24_LENGTH) + return -EIO; + + 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 */ + u_int8_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; + } + } else if ((ctrl[0] & 0xc0) == 0x80) { + /* S (Supervisory) format */ + ghp->data = NULL; + + 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->data = ctrl + 2; + + 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 (crc_length > UI_HDR_LEN + N202) + crc_length = UI_HDR_LEN + N202; + } + } else { + /* U (Unnumbered) format: 1 1 1 P/F M4 M3 M2 M1 */ + ghp->data = NULL; + + switch (ctrl[0] & 0xf) { + case 0: + ghp->cmd = GPRS_LLC_NULL; + break; + case 0x1: + ghp->cmd = GPRS_LLC_DM; + break; + case 0x4: + ghp->cmd = GPRS_LLC_DISC; + break; + case 0x6: + ghp->cmd = GPRS_LLC_UA; + break; + case 0x7: + ghp->cmd = GPRS_LLC_SABM; + break; + case 0x8: + ghp->cmd = GPRS_LLC_FRMR; + break; + case 0xb: + ghp->cmd = GPRS_LLC_XID; + break; + default: + return -EIO; + } + } + + /* calculate what FCS we expect */ + ghp->fcs_calc = gprs_llc_fcs(llc_hdr, crc_length); + + /* FIXME: parse sack frame */ +} + +/* receive an incoming LLC PDU */ +int gprs_llc_rcvmsg(struct msgb *msg, struct tlv_parsed *tv) +{ + struct bssgp_ud_hdr *udh = (struct bssgp_ud_hdr *) msg->l3h; + struct gprs_llc_hdr *lh = msg->llch; + struct gprs_llc_hdr_parsed llhp; + struct gprs_llc_entity *lle; + int rc; + + rc = gprs_llc_hdr_parse(&llhp, lh, TLVP_LEN(tv, BSSGP_IE_LLC_PDU)); + + /* FIXME: find LLC Entity */ + + gprs_llc_hdr_dump(&llhp); + rc = gprs_llc_hdr_rx(&llhp, lle); + + if (llhp.data) { + msg->gmmh = llhp.data; + switch (llhp.sapi) { + case GPRS_SAPI_GMM: + rc = gsm0408_gprs_rcvmsg(msg); + } + } + + return 0; +} diff --git a/openbsc/src/gprs_ns.c b/openbsc/src/gprs_ns.c new file mode 100644 index 000000000..a686a22aa --- /dev/null +++ b/openbsc/src/gprs_ns.c @@ -0,0 +1,348 @@ +/* GPRS Networks Service (NS) messages on the Gb interface + * 3GPP TS 08.16 version 8.0.1 Release 1999 / ETSI TS 101 299 V8.0.1 (2002-05) */ + +/* (C) 2009 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. + * + */ + +/* Some introduction into NS: NS is used typically on top of frame relay, + * but in the ip.access world it is encapsulated in UDP packets. It serves + * as an intermediate shim betwen BSSGP and the underlying medium. It doesn't + * do much, apart from providing congestion notification and status indication. + * + * Terms: + * NS Network Service + * NSVC NS Virtual Connection + * NSEI NS Entity Identifier + * NSVL NS Virtual Link + * NSVLI NS Virtual Link Identifier + * BVC BSSGP Virtual Connection + * BVCI BSSGP Virtual Connection Identifier + * NSVCG NS Virtual Connection Goup + * Blocked NS-VC cannot be used for user traffic + * Alive Ability of a NS-VC to provide communication + * + * There can be multiple BSSGP virtual connections over one (group of) NSVC's. BSSGP will + * therefore identify the BSSGP virtual connection by a BVCI passed down to NS. + * NS then has to firgure out which NSVC's are responsible for this BVCI. + * Those mappings are administratively configured. + */ + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#define NS_ALLOC_SIZE 1024 + +static const struct tlv_definition ns_att_tlvdef = { + .def = { + [NS_IE_CAUSE] = { TLV_TYPE_TvLV, 0 }, + [NS_IE_VCI] = { TLV_TYPE_TvLV, 0 }, + [NS_IE_PDU] = { TLV_TYPE_TvLV, 0 }, + [NS_IE_BVCI] = { TLV_TYPE_TvLV, 0 }, + [NS_IE_NSEI] = { TLV_TYPE_TvLV, 0 }, + }, +}; + +#define NSE_S_BLOCKED 0x0001 +#define NSE_S_ALIVE 0x0002 + +struct gprs_nsvc { + struct llist_head list; + + u_int16_t nsei; /* end-to-end significance */ + u_int16_t nsvci; /* uniquely identifies NS-VC at SGSN */ + + u_int32_t state; + + struct timer_list alive_timer; + int timer_is_tns_alive; + int alive_retries; +}; + +/* FIXME: dynamically search for the matching NSVC */ +static struct gprs_nsvc dummy_nsvc = { .state = NSE_S_BLOCKED | NSE_S_ALIVE }; + +/* Section 10.3.2, Table 13 */ +static const char *ns_cause_str[] = { + [NS_CAUSE_TRANSIT_FAIL] = "Transit network failure", + [NS_CAUSE_OM_INTERVENTION] = "O&M intervention", + [NS_CAUSE_EQUIP_FAIL] = "Equipment failure", + [NS_CAUSE_NSVC_BLOCKED] = "NS-VC blocked", + [NS_CAUSE_NSVC_UNKNOWN] = "NS-VC unknown", + [NS_CAUSE_BVCI_UNKNOWN] = "BVCI unknown", + [NS_CAUSE_SEM_INCORR_PDU] = "Semantically incorrect PDU", + [NS_CAUSE_PDU_INCOMP_PSTATE] = "PDU not compatible with protocol state", + [NS_CAUSE_PROTO_ERR_UNSPEC] = "Protocol error, unspecified", + [NS_CAUSE_INVAL_ESSENT_IE] = "Invalid essential IE", + [NS_CAUSE_MISSING_ESSENT_IE] = "Missing essential IE", +}; + +static const char *gprs_ns_cause_str(enum ns_cause cause) +{ + if (cause >= ARRAY_SIZE(ns_cause_str)) + return "undefined"; + + if (ns_cause_str[cause]) + return ns_cause_str[cause]; + + return "undefined"; +} + +static int gprs_ns_tx(struct msgb *msg) +{ + return ipac_gprs_send(msg); +} + +static int gprs_ns_tx_simple(struct gprs_ns_link *link, u_int8_t pdu_type) +{ + struct msgb *msg = msgb_alloc(NS_ALLOC_SIZE, "GPRS/NS"); + struct gprs_ns_hdr *nsh; + + if (!msg) + return -ENOMEM; + + nsh = (struct gprs_ns_hdr *) msgb_put(msg, sizeof(*nsh)); + + nsh->pdu_type = pdu_type; + + return gprs_ns_tx(msg); +} + +#define NS_TIMER_ALIVE 3, 0 /* after 3 seconds without response, we retry */ +#define NS_TIMER_TEST 30, 0 /* every 10 seconds we check if the BTS is still alive */ +#define NS_ALIVE_RETRIES 10 /* after 3 failed retransmit we declare BTS as dead */ + +static void gprs_ns_alive_cb(void *data) +{ + struct gprs_nsvc *nsvc = data; + + if (nsvc->timer_is_tns_alive) { + /* Tns-alive case: we expired without response ! */ + nsvc->alive_retries++; + if (nsvc->alive_retries > NS_ALIVE_RETRIES) { + /* mark as dead and blocked */ + nsvc->state = NSE_S_BLOCKED; + DEBUGP(DGPRS, "Tns-alive more then %u retries, " + " blocking NS-VC\n", NS_ALIVE_RETRIES); + /* FIXME: inform higher layers */ + return; + } + } else { + /* Tns-test case: send NS-ALIVE PDU */ + gprs_ns_tx_simple(NULL, NS_PDUT_ALIVE); + /* start Tns-alive timer */ + nsvc->timer_is_tns_alive = 1; + } + bsc_schedule_timer(&nsvc->alive_timer, NS_TIMER_ALIVE); +} + +/* Section 9.2.6 */ +static int gprs_ns_tx_reset_ack(u_int16_t nsvci, u_int16_t nsei) +{ + struct msgb *msg = msgb_alloc(NS_ALLOC_SIZE, "GPRS/NS"); + struct gprs_ns_hdr *nsh; + + if (!msg) + return -ENOMEM; + + nsvci = htons(nsvci); + nsei = htons(nsei); + + nsh = (struct gprs_ns_hdr *) msgb_put(msg, sizeof(*nsh)); + + nsh->pdu_type = NS_PDUT_RESET_ACK; + + msgb_tvlv_put(msg, NS_IE_VCI, 2, (u_int8_t *)&nsvci); + msgb_tvlv_put(msg, NS_IE_NSEI, 2, (u_int8_t *)&nsei); + + return gprs_ns_tx(msg); +} + +/* Section 9.2.10: transmit side */ +int gprs_ns_sendmsg(struct gprs_ns_link *link, u_int16_t bvci, + struct msgb *msg) +{ + struct gprs_ns_hdr *nsh; + + nsh = (struct gprs_ns_hdr *) msgb_push(msg, sizeof(*nsh) + 3); + if (!nsh) { + DEBUGP(DGPRS, "Not enough headroom for NS header\n"); + return -EIO; + } + + nsh->pdu_type = NS_PDUT_UNITDATA; + /* spare octet in data[0] */ + nsh->data[1] = bvci >> 8; + nsh->data[2] = bvci & 0xff; + + return gprs_ns_tx(msg); +} + +/* Section 9.2.10: receive side */ +static int gprs_ns_rx_unitdata(struct msgb *msg) +{ + struct gprs_ns_hdr *nsh = (struct gprs_ns_hdr *)msg->l2h; + u_int16_t bvci; + + /* spare octet in data[0] */ + bvci = nsh->data[1] << 8 | nsh->data[2]; + msg->l3h = &nsh->data[3]; + + /* call upper layer (BSSGP) */ + return gprs_bssgp_rcvmsg(msg, bvci); +} + +/* Section 9.2.7 */ +static int gprs_ns_rx_status(struct msgb *msg) +{ + struct gprs_ns_hdr *nsh = msg->l2h; + struct tlv_parsed tp; + u_int8_t cause; + int rc; + + DEBUGP(DGPRS, "NS STATUS "); + + rc = tlv_parse(&tp, &ns_att_tlvdef, nsh->data, msgb_l2len(msg), 0, 0); + + if (!TLVP_PRESENT(&tp, NS_IE_CAUSE)) { + DEBUGPC(DGPRS, "missing cause IE\n"); + return -EINVAL; + } + + cause = *TLVP_VAL(&tp, NS_IE_CAUSE); + DEBUGPC(DGPRS, "cause=%s\n", gprs_ns_cause_str(cause)); + + return 0; +} + +/* Section 7.3 */ +static int gprs_ns_rx_reset(struct msgb *msg) +{ + struct gprs_ns_hdr *nsh = (struct gprs_ns_hdr *) msg->l2h; + struct gprs_nsvc *nsvc = &dummy_nsvc; + struct tlv_parsed tp; + u_int8_t *cause; + u_int16_t *nsvci, *nsei; + int rc; + + DEBUGP(DGPRS, "NS RESET "); + + rc = tlv_parse(&tp, &ns_att_tlvdef, nsh->data, msgb_l2len(msg), 0, 0); + + if (!TLVP_PRESENT(&tp, NS_IE_CAUSE) || + !TLVP_PRESENT(&tp, NS_IE_VCI) || + !TLVP_PRESENT(&tp, NS_IE_NSEI)) { + /* FIXME: respond with NS_CAUSE_MISSING_ESSENT_IE */ + DEBUGPC(DGPRS, "Missing mandatory IE\n"); + return -EINVAL; + } + + cause = (u_int8_t *) TLVP_VAL(&tp, NS_IE_CAUSE); + nsvci = (u_int16_t *) TLVP_VAL(&tp, NS_IE_VCI); + nsei = (u_int16_t *) TLVP_VAL(&tp, NS_IE_NSEI); + + *nsvci = ntohs(*nsvci); + *nsei = ntohs(*nsei); + + DEBUGPC(DGPRS, "cause=%s, NSVCI=%u, NSEI=%u\n", + gprs_ns_cause_str(*cause), *nsvci, *nsei); + + /* mark the NS-VC as blocked and alive */ + nsvc->state = NSE_S_BLOCKED | NSE_S_ALIVE; + nsvc->nsei = *nsei; + nsvc->nsvci = *nsvci; + + /* start the test procedure */ + nsvc->alive_timer.cb = gprs_ns_alive_cb; + nsvc->alive_timer.data = nsvc; + bsc_schedule_timer(&nsvc->alive_timer, NS_TIMER_ALIVE); + + return gprs_ns_tx_reset_ack(*nsvci, *nsei); +} + +/* main entry point, here incoming NS frames enter */ +int gprs_ns_rcvmsg(struct msgb *msg) +{ + struct gprs_ns_hdr *nsh = (struct gprs_ns_hdr *) msg->l2h; + struct gprs_nsvc *nsvc = &dummy_nsvc; + int rc = 0; + + switch (nsh->pdu_type) { + case NS_PDUT_ALIVE: + /* remote end inquires whether we're still alive, + * we need to respond with ALIVE_ACK */ + rc = gprs_ns_tx_simple(NULL, NS_PDUT_ALIVE_ACK); + break; + case NS_PDUT_ALIVE_ACK: + /* stop Tns-alive */ + bsc_del_timer(&nsvc->alive_timer); + /* start Tns-test */ + nsvc->timer_is_tns_alive = 0; + bsc_schedule_timer(&nsvc->alive_timer, NS_TIMER_TEST); + break; + case NS_PDUT_UNITDATA: + /* actual user data */ + rc = gprs_ns_rx_unitdata(msg); + break; + case NS_PDUT_STATUS: + rc = gprs_ns_rx_status(msg); + break; + case NS_PDUT_RESET: + rc = gprs_ns_rx_reset(msg); + break; + case NS_PDUT_RESET_ACK: + /* FIXME: mark remote NS-VC as blocked + active */ + break; + case NS_PDUT_UNBLOCK: + /* Section 7.2: unblocking procedure */ + DEBUGP(DGPRS, "NS UNBLOCK\n"); + nsvc->state &= ~NSE_S_BLOCKED; + rc = gprs_ns_tx_simple(NULL, NS_PDUT_UNBLOCK_ACK); + break; + case NS_PDUT_UNBLOCK_ACK: + /* FIXME: mark remote NS-VC as unblocked + active */ + break; + case NS_PDUT_BLOCK: + DEBUGP(DGPRS, "NS BLOCK\n"); + nsvc->state |= NSE_S_BLOCKED; + rc = gprs_ns_tx_simple(NULL, NS_PDUT_UNBLOCK_ACK); + break; + case NS_PDUT_BLOCK_ACK: + /* FIXME: mark remote NS-VC as blocked + active */ + break; + default: + DEBUGP(DGPRS, "Unknown NS PDU type 0x%02x\n", nsh->pdu_type); + rc = -EINVAL; + break; + } + return rc; +} + diff --git a/openbsc/src/gprs_sgsn.c b/openbsc/src/gprs_sgsn.c new file mode 100644 index 000000000..477e448be --- /dev/null +++ b/openbsc/src/gprs_sgsn.c @@ -0,0 +1,93 @@ +/* GPRS SGSN functionality */ + +/* (C) 2009 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 + +static LLIST_HEAD(sgsn_mm_ctxts); + +static int ra_id_equals(const struct gprs_ra_id *id1, + const struct gprs_ra_id *id2) +{ + return (id1->mcc == id2->mcc && id1->mnc == id2->mnc && + id1->lac == id2->lac && id1->rac == id2->rac); +} + +/* look-up a SGSN MM context based on TLLI + RAI */ +struct sgsn_mm_ctx *sgsn_mm_ctx_by_tlli(u_int32_t tlli, + const struct gprs_ra_id *raid) +{ + struct sgsn_mm_ctx *ctx; + + llist_for_each_entry(ctx, &sgsn_mm_ctxts, list) { + if (tlli == ctx->tlli && + ra_id_equals(raid, &ctx->ra)) + return ctx; + } + return NULL; +} + +struct sgsn_mm_ctx *sgsn_mm_ctx_by_ptmsi(u_int32_t p_tmsi) +{ + struct sgsn_mm_ctx *ctx; + + llist_for_each_entry(ctx, &sgsn_mm_ctxts, list) { + if (p_tmsi == ctx->p_tmsi) + return ctx; + } + return NULL; +} + +struct sgsn_mm_ctx *sgsn_mm_ctx_by_imsi(const char *imsi) +{ + struct sgsn_mm_ctx *ctx; + + llist_for_each_entry(ctx, &sgsn_mm_ctxts, list) { + if (!strcmp(imsi, ctx->imsi)) + return ctx; + } + return NULL; + +} + +/* Allocate a new SGSN MM context */ +struct sgsn_mm_ctx *sgsn_mm_ctx_alloc(u_int32_t tlli, + const struct gprs_ra_id *raid) +{ + struct sgsn_mm_ctx *ctx = talloc_zero(NULL, struct sgsn_mm_ctx); + + if (!ctx) + return NULL; + + memcpy(&ctx->ra, raid, sizeof(ctx->ra)); + ctx->tlli = tlli; + ctx->mm_state = GMM_DEREGISTERED; + + llist_add(&ctx->list, &sgsn_mm_ctxts); + + return ctx; +} diff --git a/openbsc/src/gsm_04_08_gprs.c b/openbsc/src/gsm_04_08_gprs.c new file mode 100644 index 000000000..af6a481cb --- /dev/null +++ b/openbsc/src/gsm_04_08_gprs.c @@ -0,0 +1,716 @@ +/* GSM Mobile Radio Interface Layer 3 messages on the A-bis interface + * 3GPP TS 04.08 version 7.21.0 Release 1998 / ETSI TS 100 940 V7.21.0 */ + +/* (C) 2009 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* 10.5.5.14 GPRS MM Cause / Table 10.5.147 */ +struct value_string gmm_cause_names[] = { + /* FIXME */ + { GMM_CAUSE_SEM_INCORR_MSG, "Semantically incorrect message" }, + { GMM_CAUSE_INV_MAND_INFO, "Invalid mandatory information" }, + { GMM_CAUSE_MSGT_NOTEXIST_NOTIMPL, + "Message type non-existant or not implemented" }, + { GMM_CAUSE_MSGT_INCOMP_P_STATE, + "Message type not compatible with protocol state" }, + { GMM_CAUSE_IE_NOTEXIST_NOTIMPL, + "Information element non-existent or not implemented" }, + { GMM_CAUSE_COND_IE_ERR, "Conditional IE error" }, + { GMM_CAUSE_MSG_INCOMP_P_STATE, + "Message not compatible with protocol state " }, + { GMM_CAUSE_PROTO_ERR_UNSPEC, "Protocol error, unspecified" }, + { 0, NULL } +}; + +/* 10.5.6.6 SM Cause / Table 10.5.157 */ +struct value_string gsm_cause_names[] = { + { GSM_CAUSE_INSUFF_RSRC, "Insufficient resources" }, + { GSM_CAUSE_MISSING_APN, "Missing or unknown APN" }, + { GSM_CAUSE_UNKNOWN_PDP, "Unknown PDP address or PDP type" }, + { GSM_CAUSE_AUTH_FAILED, "User Authentication failed" }, + { GSM_CAUSE_ACT_REJ_GGSN, "Activation rejected by GGSN" }, + { GSM_CAUSE_ACT_REJ_UNSPEC, "Activation rejected, unspecified" }, + { GSM_CAUSE_SERV_OPT_NOTSUPP, "Service option not supported" }, + { GSM_CAUSE_REQ_SERV_OPT_NOTSUB, + "Requested service option not subscribed" }, + { GSM_CAUSE_SERV_OPT_TEMP_OOO, + "Service option temporarily out of order" }, + { GSM_CAUSE_NSAPI_IN_USE, "NSAPI already used" }, + { GSM_CAUSE_DEACT_REGULAR, "Regular deactivation" }, + { GSM_CAUSE_QOS_NOT_ACCEPTED, "QoS not accepted" }, + { GSM_CAUSE_NET_FAIL, "Network Failure" }, + { GSM_CAUSE_REACT_RQD, "Reactivation required" }, + { GSM_CAUSE_FEATURE_NOTSUPP, "Feature not supported " }, + { GSM_CAUSE_INVALID_TRANS_ID, "Invalid transaction identifier" }, + { GSM_CAUSE_SEM_INCORR_MSG, "Semantically incorrect message" }, + { GSM_CAUSE_INV_MAND_INFO, "Invalid mandatory information" }, + { GSM_CAUSE_MSGT_NOTEXIST_NOTIMPL, + "Message type non-existant or not implemented" }, + { GSM_CAUSE_MSGT_INCOMP_P_STATE, + "Message type not compatible with protocol state" }, + { GSM_CAUSE_IE_NOTEXIST_NOTIMPL, + "Information element non-existent or not implemented" }, + { GSM_CAUSE_COND_IE_ERR, "Conditional IE error" }, + { GSM_CAUSE_MSG_INCOMP_P_STATE, + "Message not compatible with protocol state " }, + { GSM_CAUSE_PROTO_ERR_UNSPEC, "Protocol error, unspecified" }, + { 0, NULL } +}; + +static const char *att_name(u_int8_t type) +{ + switch (type) { + case GPRS_ATT_T_ATTACH: + return "GPRS attach"; + case GPRS_ATT_T_ATT_WHILE_IMSI: + return "GPRS attach while IMSI attached"; + case GPRS_ATT_T_COMBINED: + return "Combined GPRS/IMSI attach"; + default: + return "unknown"; + } +} + +static const char *upd_name(u_int8_t type) +{ + switch (type) { + case GPRS_UPD_T_RA: + return "RA updating"; + case GPRS_UPD_T_RA_LA: + return "combined RA/LA updating"; + case GPRS_UPD_T_RA_LA_IMSI_ATT: + return "combined RA/LA updating + IMSI attach"; + case GPRS_UPD_T_PERIODIC: + return "periodic updating"; + } + return "unknown"; +} + +void gsm48_parse_ra(struct gprs_ra_id *raid, const u_int8_t *buf) +{ + raid->mcc = (buf[0] & 0xf) * 100; + raid->mcc += (buf[0] >> 4) * 10; + raid->mcc += (buf[1] & 0xf) * 1; + + /* I wonder who came up with the stupidity of encoding the MNC + * differently depending on how many digits its decimal number has! */ + if ((buf[1] >> 4) == 0xf) { + raid->mnc = (buf[2] & 0xf) * 10; + raid->mnc += (buf[2] >> 4) * 1; + } else { + raid->mnc = (buf[2] & 0xf) * 100; + raid->mnc += (buf[2] >> 4) * 10; + raid->mnc += (buf[1] >> 4) * 1; + } + + raid->lac = ntohs(*(u_int16_t *)(buf + 3)); + raid->rac = buf[5]; +} + +/* Send a message through the underlying layer */ +static int gsm48_gmm_sendmsg(struct msgb *msg, int command) +{ + return gprs_llc_tx_ui(msg, GPRS_SAPI_GMM, command); +} + +/* TS 03.03 Chapter 2.6 */ +int gprs_tlli_type(u_int32_t tlli) +{ + if ((tlli & 0xc0000000) == 0xc0000000) + return TLLI_LOCAL; + else if ((tlli & 0xc0000000) == 0x80000000) + return TLLI_FOREIGN; + else if ((tlli & 0xf8000000) == 0x78000000) + return TLLI_RANDOM; + else if ((tlli & 0xf8000000) == 0x70000000) + return TLLI_AUXILIARY; + + return TLLI_RESERVED; +} + +/* Chapter 9.4.2: Attach accept */ +static int gsm48_tx_gmm_att_ack(struct msgb *old_msg) +{ + struct msgb *msg = gsm48_msgb_alloc(); + struct gsm48_hdr *gh; + struct gsm48_attach_ack *aa; + + DEBUGP(DMM, "<- GPRS ATTACH ACCEPT\n"); + + msg->tlli = old_msg->tlli; + msg->trx = old_msg->trx; + + gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh)); + gh->proto_discr = GSM48_PDISC_MM_GPRS; + gh->msg_type = GSM48_MT_GMM_ATTACH_ACK; + + aa = (struct gsm48_attach_ack *) msgb_put(msg, sizeof(*aa)); + aa->force_stby = 0; /* not indicated */ + aa->att_result = 1; /* GPRS only */ + aa->ra_upd_timer = GPRS_TMR_MINUTE | 10; + aa->radio_prio = 4; /* lowest */ + gsm48_ra_id_by_bts(aa->ra_id.digits, old_msg->trx->bts); + + /* Option: P-TMSI signature, allocated P-TMSI, MS ID, ... */ + return gsm48_gmm_sendmsg(msg, 0); +} + +/* Chapter 9.4.5: Attach reject */ +static int gsm48_tx_gmm_att_rej(struct msgb *old_msg, u_int8_t gmm_cause) +{ + struct msgb *msg = gsm48_msgb_alloc(); + struct gsm48_hdr *gh; + + DEBUGP(DMM, "<- GPRS ATTACH REJECT\n"); + + msg->tlli = old_msg->tlli; + msg->trx = old_msg->trx; + + gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1); + gh->proto_discr = GSM48_PDISC_MM_GPRS; + gh->msg_type = GSM48_MT_GMM_ATTACH_REJ; + gh->data[0] = gmm_cause; + + return gsm48_gmm_sendmsg(msg, 0); +} + +/* Transmit Chapter 9.4.12 Identity Request */ +static int gsm48_tx_gmm_id_req(struct msgb *old_msg, u_int8_t id_type) +{ + struct msgb *msg = gsm48_msgb_alloc(); + struct gsm48_hdr *gh; + + DEBUGP(DMM, "-> GPRS IDENTITY REQUEST: mi_type=%02x\n", id_type); + + msg->tlli = old_msg->tlli; + msg->trx = old_msg->trx; + + gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1); + gh->proto_discr = GSM48_PDISC_MM_GPRS; + gh->msg_type = GSM48_MT_GMM_ID_REQ; + /* 10.5.5.9 ID type 2 + identity type and 10.5.5.7 'force to standby' IE */ + gh->data[0] = id_type & 0xf; + + return gsm48_gmm_sendmsg(msg, 0); +} + +/* Check if we can already authorize a subscriber */ +static int gsm48_gmm_authorize(struct sgsn_mm_ctx *ctx, struct msgb *msg) +{ + if (strlen(ctx->imei) && strlen(ctx->imsi)) { + ctx->mm_state = GMM_REGISTERED_NORMAL; + return gsm48_tx_gmm_att_ack(msg); + } + if (!strlen(ctx->imei)) + return gsm48_tx_gmm_id_req(msg, GSM_MI_TYPE_IMEI); + + if (!strlen(ctx->imsi)) + return gsm48_tx_gmm_id_req(msg, GSM_MI_TYPE_IMSI); + + return 0; +} + +/* Parse Chapter 9.4.13 Identity Response */ +static int gsm48_rx_gmm_id_resp(struct msgb *msg) +{ + struct gsm48_hdr *gh = (struct gsm48_hdr *) msg->gmmh; + u_int8_t mi_type = gh->data[1] & GSM_MI_TYPE_MASK; + char mi_string[GSM48_MI_SIZE]; + struct gprs_ra_id ra_id; + struct sgsn_mm_ctx *ctx; + + gsm48_mi_to_string(mi_string, sizeof(mi_string), &gh->data[1], gh->data[0]); + DEBUGP(DMM, "GMM IDENTITY RESPONSE: mi_type=0x%02x MI(%s) ", + mi_type, mi_string); + + gprs_ra_id_by_bts(&ra_id, msg->trx->bts); + ctx = sgsn_mm_ctx_by_tlli(msg->tlli, &ra_id); + if (!ctx) { + DEBUGP(DMM, "from unknown TLLI 0x%08x?!?\n", msg->tlli); + return -EINVAL; + } + + switch (mi_type) { + case GSM_MI_TYPE_IMSI: + /* we already have a mm context with current TLLI, but no + * P-TMSI / IMSI yet. What we now need to do is to fill + * this initial context with data from the HLR */ + strncpy(ctx->imsi, mi_string, sizeof(ctx->imei)); + break; + case GSM_MI_TYPE_IMEI: + strncpy(ctx->imei, mi_string, sizeof(ctx->imei)); + break; + case GSM_MI_TYPE_IMEISV: + break; + } + + DEBUGPC(DMM, "\n"); + /* Check if we can let the mobile station enter */ + return gsm48_gmm_authorize(ctx, msg); +} + +static void attach_rej_cb(void *data) +{ + struct sgsn_mm_ctx *ctx = data; + + /* FIXME: determine through which BTS/TRX to send this */ + //gsm48_tx_gmm_att_rej(ctx->tlli, GMM_CAUSE_MS_ID_NOT_DERIVED); + ctx->mm_state = GMM_DEREGISTERED; + /* FIXME: release the context */ +} + +static void schedule_reject(struct sgsn_mm_ctx *ctx) +{ + ctx->T = 3370; + ctx->timer.cb = attach_rej_cb; + ctx->timer.data = ctx; + bsc_schedule_timer(&ctx->timer, 6, 0); +} + +/* Section 9.4.1 Attach request */ +static int gsm48_rx_gmm_att_req(struct msgb *msg) +{ + struct gsm48_hdr *gh = (struct gsm48_hdr *) msg->gmmh; + u_int8_t *cur = gh->data, *msnc, *mi, *old_ra_info; + u_int8_t msnc_len, att_type, mi_len, mi_type; + u_int16_t drx_par; + u_int32_t tmsi; + char mi_string[GSM48_MI_SIZE]; + struct gprs_ra_id ra_id; + struct sgsn_mm_ctx *ctx; + + DEBUGP(DMM, "GMM ATTACH REQUEST "); + + /* As per TS 04.08 Chapter 4.7.1.4, the attach request arrives either + * with a foreign TLLI (P-TMSI that was allocated to the MS before), + * or with random TLLI. */ + + gprs_ra_id_by_bts(&ra_id, msg->trx->bts); + + /* MS network capability 10.5.5.12 */ + msnc_len = *cur++; + msnc = cur; + if (msnc_len > 2) + goto err_inval; + cur += msnc_len; + + /* aTTACH Type 10.5.5.2 */ + att_type = *cur++ & 0x0f; + + /* DRX parameter 10.5.5.6 */ + drx_par = *cur++; + drx_par |= *cur++ << 8; + + /* Mobile Identity (P-TMSI or IMSI) 10.5.1.4 */ + mi_len = *cur++; + mi = cur; + if (mi_len > 8) + goto err_inval; + mi_type = *mi & GSM_MI_TYPE_MASK; + cur += mi_len; + + gsm48_mi_to_string(mi_string, sizeof(mi_string), mi, mi_len); + + DEBUGPC(DMM, "MI(%s) type=\"%s\" ", mi_string, att_name(att_type)); + + /* Old routing area identification 10.5.5.15 */ + old_ra_info = cur; + cur += 6; + + /* MS Radio Access Capability 10.5.5.12a */ + + /* Optional: Old P-TMSI Signature, Requested READY timer, TMSI Status */ + + switch (mi_type) { + case GSM_MI_TYPE_IMSI: + /* Try to find MM context based on IMSI */ + ctx = sgsn_mm_ctx_by_imsi(mi_string); + if (!ctx) { +#if 0 + return gsm48_tx_gmm_att_rej(msg, GMM_CAUSE_IMSI_UNKNOWN); +#else + /* As a temorary hack, we simply assume that the IMSI exists */ + ctx = sgsn_mm_ctx_alloc(0, &ra_id); + if (!ctx) + return gsm48_tx_gmm_att_rej(msg, GMM_CAUSE_NET_FAIL); + strncpy(ctx->imsi, mi_string, sizeof(ctx->imsi)); +#endif + } + /* FIXME: Start some timer */ + ctx->mm_state = GMM_COMMON_PROC_INIT; + ctx->tlli = msg->tlli; + break; + case GSM_MI_TYPE_TMSI: + tmsi = strtoul(mi_string, NULL, 10); + /* Try to find MM context based on P-TMSI */ + ctx = sgsn_mm_ctx_by_ptmsi(tmsi); + if (!ctx) { + ctx = sgsn_mm_ctx_alloc(msg->tlli, &ra_id); + /* FIXME: Start some timer */ + ctx->mm_state = GMM_COMMON_PROC_INIT; + ctx->tlli = msg->tlli; + } + break; + default: + break; + } + + /* FIXME: allocate a new P-TMSI (+ P-TMSI signature) */ + /* FIXME: update the TLLI with the new local TLLI based on the P-TMSI */ + + DEBUGPC(DMM, "\n"); + + return ctx ? gsm48_gmm_authorize(ctx, msg) : 0; + +err_inval: + DEBUGPC(DMM, "\n"); + return gsm48_tx_gmm_att_rej(msg, GMM_CAUSE_SEM_INCORR_MSG); +} + +/* Chapter 9.4.15: Routing area update accept */ +static int gsm48_tx_gmm_ra_upd_ack(struct msgb *old_msg) +{ + struct msgb *msg = gsm48_msgb_alloc(); + struct gsm48_hdr *gh; + struct gsm48_ra_upd_ack *rua; + + DEBUGP(DMM, "<- ROUTING AREA UPDATE ACCEPT\n"); + + msg->tlli = old_msg->tlli; + msg->trx = old_msg->trx; + + gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh)); + gh->proto_discr = GSM48_PDISC_MM_GPRS; + gh->msg_type = GSM48_MT_GMM_RA_UPD_ACK; + + rua = (struct gsm48_ra_upd_ack *) msgb_put(msg, sizeof(*rua)); + rua->force_stby = 0; /* not indicated */ + rua->upd_result = 0; /* RA updated */ + rua->ra_upd_timer = GPRS_TMR_MINUTE | 10; + gsm48_ra_id_by_bts(rua->ra_id.digits, old_msg->trx->bts); + + /* Option: P-TMSI signature, allocated P-TMSI, MS ID, ... */ + return gsm48_gmm_sendmsg(msg, 0); +} + +/* Chapter 9.4.17: Routing area update reject */ +static int gsm48_tx_gmm_ra_upd_rej(struct msgb *old_msg, u_int8_t cause) +{ + struct msgb *msg = gsm48_msgb_alloc(); + struct gsm48_hdr *gh; + + DEBUGP(DMM, "<- ROUTING AREA UPDATE REJECT\n"); + + msg->tlli = old_msg->tlli; + msg->trx = old_msg->trx; + + gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 2); + gh->proto_discr = GSM48_PDISC_MM_GPRS; + gh->msg_type = GSM48_MT_GMM_RA_UPD_REJ; + gh->data[0] = cause; + gh->data[1] = 0; /* ? */ + + /* Option: P-TMSI signature, allocated P-TMSI, MS ID, ... */ + return gsm48_gmm_sendmsg(msg, 0); +} + +/* Chapter 9.4.14: Routing area update request */ +static int gsm48_rx_gmm_ra_upd_req(struct msgb *msg) +{ + struct gsm48_hdr *gh = (struct gsm48_hdr *) msg->gmmh; + struct sgsn_mm_ctx *mmctx; + u_int8_t *cur = gh->data; + struct gprs_ra_id old_ra_id; + u_int8_t upd_type; + + /* Update Type 10.5.5.18 */ + upd_type = *cur++ & 0x0f; + + DEBUGP(DMM, "GMM RA UPDATE REQUEST type=\"%s\" ", upd_name(upd_type)); + + /* Old routing area identification 10.5.5.15 */ + gsm48_parse_ra(&old_ra_id, cur); + cur += 6; + + /* MS Radio Access Capability 10.5.5.12a */ + + /* Optional: Old P-TMSI Signature, Requested READY timer, TMSI Status, + * DRX parameter, MS network capability */ + + switch (upd_type) { + case GPRS_UPD_T_RA_LA: + case GPRS_UPD_T_RA_LA_IMSI_ATT: + DEBUGPC(DMM, " unsupported in Mode III, is your SI13 corrupt?\n"); + return gsm48_tx_gmm_ra_upd_rej(msg, GMM_CAUSE_PROTO_ERR_UNSPEC); + break; + case GPRS_UPD_T_RA: + case GPRS_UPD_T_PERIODIC: + break; + } + + /* Look-up the MM context based on old RA-ID and TLLI */ + mmctx = sgsn_mm_ctx_by_tlli(msg->tlli, &old_ra_id); + if (!mmctx || mmctx->mm_state == GMM_DEREGISTERED) { + /* The MS has to perform GPRS attach */ + DEBUGPC(DMM, " REJECT\n"); + return gsm48_tx_gmm_ra_upd_rej(msg, GMM_CAUSE_IMPL_DETACHED); + } + + /* FIXME: Update the MM context with the new RA-ID */ + /* FIXME: Update the MM context with the new TLLI */ + /* FIXME: Update the MM context with the MS radio acc capabilities */ + /* FIXME: Update the MM context with the MS network capabilities */ + + DEBUGPC(DMM, " ACCEPT\n"); + return gsm48_tx_gmm_ra_upd_ack(msg); +} + +static int gsm48_rx_gmm_status(struct msgb *msg) +{ + struct gsm48_hdr *gh = msgb_l3(msg); + + DEBUGP(DMM, "GPRS MM STATUS (cause: %s)\n", + get_value_string(gmm_cause_names, gh->data[0])); + + return 0; +} + +/* GPRS Mobility Management */ +static int gsm0408_rcv_gmm(struct msgb *msg) +{ + struct gsm48_hdr *gh = (struct gsm48_hdr *) msg->gmmh; + int rc; + + switch (gh->msg_type) { + case GSM48_MT_GMM_RA_UPD_REQ: + rc = gsm48_rx_gmm_ra_upd_req(msg); + break; + case GSM48_MT_GMM_ATTACH_REQ: + rc = gsm48_rx_gmm_att_req(msg); + break; + case GSM48_MT_GMM_ID_RESP: + rc = gsm48_rx_gmm_id_resp(msg); + break; + case GSM48_MT_GMM_STATUS: + rc = gsm48_rx_gmm_status(msg); + break; + case GSM48_MT_GMM_RA_UPD_COMPL: + /* only in case SGSN offered new P-TMSI */ + case GSM48_MT_GMM_ATTACH_COMPL: + /* only in case SGSN offered new P-TMSI */ + case GSM48_MT_GMM_DETACH_REQ: + case GSM48_MT_GMM_PTMSI_REALL_COMPL: + case GSM48_MT_GMM_AUTH_CIPH_RESP: + DEBUGP(DMM, "Unimplemented GSM 04.08 GMM msg type 0x%02x\n", + gh->msg_type); + break; + default: + DEBUGP(DMM, "Unknown GSM 04.08 GMM msg type 0x%02x\n", + gh->msg_type); + break; + } + + return rc; +} + +/* Section 9.5.2: Ativate PDP Context Accept */ +static int gsm48_tx_gsm_act_pdp_acc(struct msgb *old_msg, struct gsm48_act_pdp_ctx_req *req) +{ + struct gsm48_hdr *old_gh = (struct gsm48_hdr *) old_msg->gmmh; + struct msgb *msg = gsm48_msgb_alloc(); + struct gsm48_act_pdp_ctx_ack *act_ack; + struct gsm48_hdr *gh; + u_int8_t transaction_id = ((old_gh->proto_discr >> 4) ^ 0x8); /* flip */ + + DEBUGP(DMM, "<- ACTIVATE PDP CONTEXT ACK\n"); + + msg->tlli = old_msg->tlli; + msg->trx = old_msg->trx; + + gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh)); + gh->proto_discr = GSM48_PDISC_SM_GPRS | (transaction_id << 4); + gh->msg_type = GSM48_MT_GSM_ACT_PDP_ACK; + act_ack = (struct gsm48_act_pdp_ctx_ack *) + msgb_put(msg, sizeof(*act_ack)); + act_ack->llc_sapi = req->req_llc_sapi; + memcpy(act_ack->qos_lv, req->req_qos_lv, sizeof(act_ack->qos_lv)); + //act_ack->radio_prio = 4; + + return gsm48_gmm_sendmsg(msg, 0); +} + +/* Section 9.5.9: Deactivate PDP Context Accept */ +static int gsm48_tx_gsm_deact_pdp_acc(struct msgb *old_msg) +{ + struct gsm48_hdr *old_gh = (struct gsm48_hdr *) old_msg->gmmh; + struct msgb *msg = gsm48_msgb_alloc(); + struct gsm48_hdr *gh; + u_int8_t transaction_id = ((old_gh->proto_discr >> 4) ^ 0x8); /* flip */ + + DEBUGP(DMM, "<- DEACTIVATE PDP CONTEXT ACK\n"); + + msg->tlli = old_msg->tlli; + msg->trx = old_msg->trx; + + gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh)); + gh->proto_discr = GSM48_PDISC_SM_GPRS | (transaction_id << 4); + gh->msg_type = GSM48_MT_GSM_DEACT_PDP_ACK; + + return gsm48_gmm_sendmsg(msg, 0); +} + +/* Section 9.5.1: Activate PDP Context Request */ +static int gsm48_rx_gsm_act_pdp_req(struct msgb *msg) +{ + struct gsm48_hdr *gh = (struct gsm48_hdr *) msg->gmmh; + struct gsm48_act_pdp_ctx_req *act_req = (struct gsm48_act_pdp_ctx_req *) gh->data; + u_int8_t *pdp_addr_lv = act_req->data; + + DEBUGP(DMM, "ACTIVATE PDP CONTEXT REQ\n"); + + /* FIXME: parse access point name + IPCP config options */ + + return gsm48_tx_gsm_act_pdp_acc(msg, act_req); +} + +/* Section 9.5.8: Deactivate PDP Context Request */ +static int gsm48_rx_gsm_deact_pdp_req(struct msgb *msg) +{ + struct gsm48_hdr *gh = (struct gsm48_hdr *) msg->gmmh; + + DEBUGP(DMM, "DEACTIVATE PDP CONTEXT REQ (cause: %s)\n", + get_value_string(gsm_cause_names, gh->data[0])); + + return gsm48_tx_gsm_deact_pdp_acc(msg); +} + +static int gsm48_rx_gsm_status(struct msgb *msg) +{ + struct gsm48_hdr *gh = msgb_l3(msg); + + DEBUGP(DMM, "GPRS SM STATUS (cause: %s)\n", + get_value_string(gsm_cause_names, gh->data[0])); + + return 0; +} + +/* GPRS Session Management */ +static int gsm0408_rcv_gsm(struct msgb *msg) +{ + struct gsm48_hdr *gh = (struct gsm48_hdr *) msg->gmmh; + int rc; + + switch (gh->msg_type) { + case GSM48_MT_GSM_ACT_PDP_REQ: + rc = gsm48_rx_gsm_act_pdp_req(msg); + break; + case GSM48_MT_GSM_DEACT_PDP_REQ: + rc = gsm48_rx_gsm_deact_pdp_req(msg); + case GSM48_MT_GSM_STATUS: + rc = gsm48_rx_gsm_status(msg); + break; + case GSM48_MT_GSM_REQ_PDP_ACT_REJ: + case GSM48_MT_GSM_ACT_AA_PDP_REQ: + case GSM48_MT_GSM_DEACT_AA_PDP_REQ: + DEBUGP(DMM, "Unimplemented GSM 04.08 GSM msg type 0x%02x\n", + gh->msg_type); + break; + default: + DEBUGP(DMM, "Unknown GSM 04.08 GSM msg type 0x%02x\n", + gh->msg_type); + break; + + } + + return rc; +} + +/* Main entry point for incoming 04.08 GPRS messages */ +int gsm0408_gprs_rcvmsg(struct msgb *msg) +{ + struct gsm48_hdr *gh = (struct gsm48_hdr *) msg->gmmh; + u_int8_t pdisc = gh->proto_discr & 0x0f; + int rc = -EINVAL; + + switch (pdisc) { + case GSM48_PDISC_MM_GPRS: + rc = gsm0408_rcv_gmm(msg); + break; + case GSM48_PDISC_SM_GPRS: + rc = gsm0408_rcv_gsm(msg); + break; + default: + DEBUGP(DMM, "Unknown GSM 04.08 discriminator 0x%02x\n", + pdisc); + break; + } + + return rc; +} + +/* Determine the 'struct gsm_bts' from a RA ID */ +struct gsm_bts *gsm48_bts_by_ra_id(struct gsm_network *net, + const u_int8_t *buf, unsigned int len) +{ + struct gprs_ra_id raid; + struct gsm_bts *bts; + + if (len < 6) + return NULL; + + gsm48_parse_ra(&raid, buf); + + if (net->country_code != raid.mcc || + net->network_code != raid.mnc) + return NULL; + + llist_for_each_entry(bts, &net->bts_list, list) { + /* FIXME: we actually also need to check the + * routing area code! */ + if (bts->location_area_code == raid.lac) + return bts; + } + + return NULL; +} + diff --git a/openbsc/src/input/ipaccess.c b/openbsc/src/input/ipaccess.c index 8a8a1987d..fae9428da 100644 --- a/openbsc/src/input/ipaccess.c +++ b/openbsc/src/input/ipaccess.c @@ -53,6 +53,7 @@ struct ia_e1_handle { struct bsc_fd listen_fd; struct bsc_fd rsl_listen_fd; + struct bsc_fd gprs_fd; struct gsm_network *gsmnet; }; @@ -602,6 +603,87 @@ static int ipaccess_fd_cb(struct bsc_fd *bfd, unsigned int what) return rc; } +/* declare this as a weak symbol to ensure code will still build + * even if it does not provide this function */ +extern int gprs_ns_rcvmsg(struct msgb *msg) __attribute__((weak)); + +static struct msgb *read_gprs_msg(struct bsc_fd *bfd, int *error) +{ + struct msgb *msg = msgb_alloc(TS1_ALLOC_SIZE, "Abis/IP/GPRS"); + int ret = 0; + + if (!msg) { + *error = -ENOMEM; + return NULL; + } + + ret = recv(bfd->fd, msg->data, TS1_ALLOC_SIZE, 0); + if (ret < 0) { + fprintf(stderr, "recv error %s\n", strerror(errno)); + msgb_free(msg); + *error = ret; + return NULL; + } else if (ret == 0) { + msgb_free(msg); + *error = ret; + return NULL; + } + + msg->l2h = msg->data; + msgb_put(msg, ret); + + return msg; +} + +static int handle_gprs_read(struct bsc_fd *bfd) +{ + int error; + struct msgb *msg = read_gprs_msg(bfd, &error); + + if (!msg) + return error; + + if (gprs_ns_rcvmsg) + return gprs_ns_rcvmsg(msg); + else { + msgb_free(msg); + return 0; + } +} + +static int handle_gprs_write(struct bsc_fd *bfd) +{ +} + +int ipac_gprs_send(struct msgb *msg) +{ + struct sockaddr_in sin; + int rc; + + sin.sin_family = AF_INET; + inet_aton("192.168.100.111", &sin.sin_addr); + sin.sin_port = htons(23000); + + rc = sendto(e1h->gprs_fd.fd, msg->data, msg->len, 0, + (struct sockaddr *)&sin, sizeof(sin)); + + talloc_free(msg); + + return rc; +} + +/* UDP Port 23000 carries the LLC-in-BSSGP-in-NS protocol stack */ +static int gprs_fd_cb(struct bsc_fd *bfd, unsigned int what) +{ + int rc; + + if (what & BSC_FD_READ) + rc = handle_gprs_read(bfd); + if (what & BSC_FD_WRITE) + rc = handle_gprs_write(bfd); + + return rc; +} struct e1inp_driver ipaccess_driver = { .name = "ip.access", @@ -708,13 +790,17 @@ static int rsl_listen_fd_cb(struct bsc_fd *listen_bfd, unsigned int what) return 0; } -static int make_sock(struct bsc_fd *bfd, u_int16_t port, +static int make_sock(struct bsc_fd *bfd, int proto, u_int16_t port, int (*cb)(struct bsc_fd *fd, unsigned int what)) { struct sockaddr_in addr; int ret, on = 1; + int type = SOCK_STREAM; + + if (proto == IPPROTO_UDP) + type = SOCK_DGRAM; - bfd->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + bfd->fd = socket(AF_INET, type, proto); bfd->cb = cb; bfd->when = BSC_FD_READ; //bfd->data = line; @@ -739,11 +825,12 @@ static int make_sock(struct bsc_fd *bfd, u_int16_t port, return -EIO; } - ret = listen(bfd->fd, 1); - if (ret < 0) { - perror("listen"); - close(bfd->fd); - return ret; + if (proto != IPPROTO_UDP) { + ret = listen(bfd->fd, 1); + if (ret < 0) { + perror("listen"); + return ret; + } } ret = bsc_register_fd(bfd); @@ -811,12 +898,19 @@ int ipaccess_setup(struct gsm_network *gsmnet) e1h->gsmnet = gsmnet; /* Listen for OML connections */ - ret = make_sock(&e1h->listen_fd, IPA_TCP_PORT_OML, listen_fd_cb); + ret = make_sock(&e1h->listen_fd, IPPROTO_TCP, IPA_TCP_PORT_OML, + listen_fd_cb); if (ret < 0) return ret; /* Listen for RSL connections */ - ret = make_sock(&e1h->rsl_listen_fd, IPA_TCP_PORT_RSL, rsl_listen_fd_cb); + ret = make_sock(&e1h->rsl_listen_fd, IPPROTO_TCP, + IPA_TCP_PORT_RSL, rsl_listen_fd_cb); + if (ret < 0) + return ret; + + /* Listen for incoming GPRS packets */ + ret = make_sock(&e1h->gprs_fd, IPPROTO_UDP, 23000, gprs_fd_cb); return ret; } diff --git a/openbsc/src/vty_interface_cmds.c b/openbsc/src/vty_interface_cmds.c index 671351e1c..efcd6547b 100644 --- a/openbsc/src/vty_interface_cmds.c +++ b/openbsc/src/vty_interface_cmds.c @@ -142,7 +142,7 @@ DEFUN(logging_prnt_timestamp, } /* FIXME: those have to be kept in sync with the log levels and categories */ -#define VTY_DEBUG_CATEGORIES "(rll|cc|mm|rr|rsl|nm|sms|pag|mncc|inp|mi|mib|mux|meas|sccp|msc|mgcp|ho|db|ref)" +#define VTY_DEBUG_CATEGORIES "(rll|cc|mm|rr|rsl|nm|sms|pag|mncc|inp|mi|mib|mux|meas|sccp|msc|mgcp|ho|db|ref|gprs)" #define VTY_DEBUG_LEVELS "(everything|debug|info|notice|error|fatal)" DEFUN(logging_level, logging_level_cmd, -- cgit v1.2.3 From ab88a62f6615e172f93b0be67f466e04181ca190 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 18 Mar 2010 00:01:23 +0800 Subject: some more GPRS related comments --- openbsc/include/openbsc/gsm_data.h | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index ab555797a..70f352b0b 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -391,11 +391,14 @@ struct gsm_envabtse { struct gsm_bts_gprs_nsvc { struct gsm_bts *bts; + /* data read via VTY config file, to configure the BTS + * via OML from BSC */ int id; u_int16_t nsvci; - u_int16_t local_port; - u_int16_t remote_port; - u_int32_t remote_ip; + u_int16_t local_port; /* on the BTS */ + u_int16_t remote_port; /* on the SGSN */ + u_int32_t remote_ip; /* on the SGSN */ + struct gsm_nm_state nm_state; }; -- cgit v1.2.3 From 5434d7ec8dd3b56d126b601e7805350a58deff36 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 18 Mar 2010 00:01:43 +0800 Subject: GPRS: remove hard-coded IP address for NSIP responses from SGSN->BTS --- openbsc/include/openbsc/gprs_ns.h | 2 +- openbsc/src/gprs_ns.c | 54 +++++++++++++++++++++++---------------- openbsc/src/input/ipaccess.c | 30 ++++++++-------------- 3 files changed, 43 insertions(+), 43 deletions(-) diff --git a/openbsc/include/openbsc/gprs_ns.h b/openbsc/include/openbsc/gprs_ns.h index 90f1adf3e..9ea4d6752 100644 --- a/openbsc/include/openbsc/gprs_ns.h +++ b/openbsc/include/openbsc/gprs_ns.h @@ -54,7 +54,7 @@ struct gprs_ns_link { }; -int gprs_ns_rcvmsg(struct msgb *msg); +int gprs_ns_rcvmsg(struct msgb *msg, struct sockaddr_in *saddr); int gprs_ns_sendmsg(struct gprs_ns_link *link, u_int16_t bvci, struct msgb *msg); diff --git a/openbsc/src/gprs_ns.c b/openbsc/src/gprs_ns.c index a686a22aa..6fb7d1d93 100644 --- a/openbsc/src/gprs_ns.c +++ b/openbsc/src/gprs_ns.c @@ -85,6 +85,12 @@ struct gprs_nsvc { struct timer_list alive_timer; int timer_is_tns_alive; int alive_retries; + + union { + struct { + struct sockaddr_in bts_addr; + } ip; + }; }; /* FIXME: dynamically search for the matching NSVC */ @@ -116,12 +122,12 @@ static const char *gprs_ns_cause_str(enum ns_cause cause) return "undefined"; } -static int gprs_ns_tx(struct msgb *msg) +static int gprs_ns_tx(struct msgb *msg, struct gprs_nsvc *nsvc) { - return ipac_gprs_send(msg); + return ipac_gprs_send(msg, &nsvc->ip.bts_addr); } -static int gprs_ns_tx_simple(struct gprs_ns_link *link, u_int8_t pdu_type) +static int gprs_ns_tx_simple(struct gprs_nsvc *nsvc, u_int8_t pdu_type) { struct msgb *msg = msgb_alloc(NS_ALLOC_SIZE, "GPRS/NS"); struct gprs_ns_hdr *nsh; @@ -133,7 +139,7 @@ static int gprs_ns_tx_simple(struct gprs_ns_link *link, u_int8_t pdu_type) nsh->pdu_type = pdu_type; - return gprs_ns_tx(msg); + return gprs_ns_tx(msg, nsvc); } #define NS_TIMER_ALIVE 3, 0 /* after 3 seconds without response, we retry */ @@ -157,7 +163,7 @@ static void gprs_ns_alive_cb(void *data) } } else { /* Tns-test case: send NS-ALIVE PDU */ - gprs_ns_tx_simple(NULL, NS_PDUT_ALIVE); + gprs_ns_tx_simple(nsvc, NS_PDUT_ALIVE); /* start Tns-alive timer */ nsvc->timer_is_tns_alive = 1; } @@ -165,25 +171,28 @@ static void gprs_ns_alive_cb(void *data) } /* Section 9.2.6 */ -static int gprs_ns_tx_reset_ack(u_int16_t nsvci, u_int16_t nsei) +static int gprs_ns_tx_reset_ack(struct gprs_nsvc *nsvc) { struct msgb *msg = msgb_alloc(NS_ALLOC_SIZE, "GPRS/NS"); struct gprs_ns_hdr *nsh; + u_int16_t nsvci, nsei; if (!msg) return -ENOMEM; - nsvci = htons(nsvci); - nsei = htons(nsei); + nsvci = htons(nsvc->nsvci); + nsei = htons(nsvc->nsei); nsh = (struct gprs_ns_hdr *) msgb_put(msg, sizeof(*nsh)); nsh->pdu_type = NS_PDUT_RESET_ACK; + DEBUGP(DGPRS, "nsvci=%u, nsei=%u\n", nsvc->nsvci, nsvc->nsei); + msgb_tvlv_put(msg, NS_IE_VCI, 2, (u_int8_t *)&nsvci); msgb_tvlv_put(msg, NS_IE_NSEI, 2, (u_int8_t *)&nsei); - return gprs_ns_tx(msg); + return gprs_ns_tx(msg, nsvc); } /* Section 9.2.10: transmit side */ @@ -191,6 +200,7 @@ int gprs_ns_sendmsg(struct gprs_ns_link *link, u_int16_t bvci, struct msgb *msg) { struct gprs_ns_hdr *nsh; + struct gprs_nsvc *nsvc = &dummy_nsvc; nsh = (struct gprs_ns_hdr *) msgb_push(msg, sizeof(*nsh) + 3); if (!nsh) { @@ -203,7 +213,7 @@ int gprs_ns_sendmsg(struct gprs_ns_link *link, u_int16_t bvci, nsh->data[1] = bvci >> 8; nsh->data[2] = bvci & 0xff; - return gprs_ns_tx(msg); + return gprs_ns_tx(msg, nsvc); } /* Section 9.2.10: receive side */ @@ -269,37 +279,37 @@ static int gprs_ns_rx_reset(struct msgb *msg) nsvci = (u_int16_t *) TLVP_VAL(&tp, NS_IE_VCI); nsei = (u_int16_t *) TLVP_VAL(&tp, NS_IE_NSEI); - *nsvci = ntohs(*nsvci); - *nsei = ntohs(*nsei); + nsvc->state = NSE_S_BLOCKED | NSE_S_ALIVE; + nsvc->nsei = ntohs(*nsei); + nsvc->nsvci = ntohs(*nsvci); DEBUGPC(DGPRS, "cause=%s, NSVCI=%u, NSEI=%u\n", - gprs_ns_cause_str(*cause), *nsvci, *nsei); + gprs_ns_cause_str(*cause), nsvc->nsvci, nsvc->nsei); /* mark the NS-VC as blocked and alive */ - nsvc->state = NSE_S_BLOCKED | NSE_S_ALIVE; - nsvc->nsei = *nsei; - nsvc->nsvci = *nsvci; - /* start the test procedure */ nsvc->alive_timer.cb = gprs_ns_alive_cb; nsvc->alive_timer.data = nsvc; bsc_schedule_timer(&nsvc->alive_timer, NS_TIMER_ALIVE); - return gprs_ns_tx_reset_ack(*nsvci, *nsei); + return gprs_ns_tx_reset_ack(nsvc); } /* main entry point, here incoming NS frames enter */ -int gprs_ns_rcvmsg(struct msgb *msg) +int gprs_ns_rcvmsg(struct msgb *msg, struct sockaddr_in *saddr) { struct gprs_ns_hdr *nsh = (struct gprs_ns_hdr *) msg->l2h; struct gprs_nsvc *nsvc = &dummy_nsvc; int rc = 0; + /* FIXME: do this properly! */ + nsvc->ip.bts_addr = *saddr; + switch (nsh->pdu_type) { case NS_PDUT_ALIVE: /* remote end inquires whether we're still alive, * we need to respond with ALIVE_ACK */ - rc = gprs_ns_tx_simple(NULL, NS_PDUT_ALIVE_ACK); + rc = gprs_ns_tx_simple(nsvc, NS_PDUT_ALIVE_ACK); break; case NS_PDUT_ALIVE_ACK: /* stop Tns-alive */ @@ -325,7 +335,7 @@ int gprs_ns_rcvmsg(struct msgb *msg) /* Section 7.2: unblocking procedure */ DEBUGP(DGPRS, "NS UNBLOCK\n"); nsvc->state &= ~NSE_S_BLOCKED; - rc = gprs_ns_tx_simple(NULL, NS_PDUT_UNBLOCK_ACK); + rc = gprs_ns_tx_simple(nsvc, NS_PDUT_UNBLOCK_ACK); break; case NS_PDUT_UNBLOCK_ACK: /* FIXME: mark remote NS-VC as unblocked + active */ @@ -333,7 +343,7 @@ int gprs_ns_rcvmsg(struct msgb *msg) case NS_PDUT_BLOCK: DEBUGP(DGPRS, "NS BLOCK\n"); nsvc->state |= NSE_S_BLOCKED; - rc = gprs_ns_tx_simple(NULL, NS_PDUT_UNBLOCK_ACK); + rc = gprs_ns_tx_simple(nsvc, NS_PDUT_UNBLOCK_ACK); break; case NS_PDUT_BLOCK_ACK: /* FIXME: mark remote NS-VC as blocked + active */ diff --git a/openbsc/src/input/ipaccess.c b/openbsc/src/input/ipaccess.c index fae9428da..80055ad9f 100644 --- a/openbsc/src/input/ipaccess.c +++ b/openbsc/src/input/ipaccess.c @@ -603,21 +603,20 @@ static int ipaccess_fd_cb(struct bsc_fd *bfd, unsigned int what) return rc; } -/* declare this as a weak symbol to ensure code will still build - * even if it does not provide this function */ -extern int gprs_ns_rcvmsg(struct msgb *msg) __attribute__((weak)); - -static struct msgb *read_gprs_msg(struct bsc_fd *bfd, int *error) +static struct msgb *read_gprs_msg(struct bsc_fd *bfd, int *error, + struct sockaddr_in *saddr) { struct msgb *msg = msgb_alloc(TS1_ALLOC_SIZE, "Abis/IP/GPRS"); int ret = 0; + socklen_t saddr_len = sizeof(*saddr); if (!msg) { *error = -ENOMEM; return NULL; } - ret = recv(bfd->fd, msg->data, TS1_ALLOC_SIZE, 0); + ret = recvfrom(bfd->fd, msg->data, TS1_ALLOC_SIZE, 0, + (struct sockaddr *)saddr, &saddr_len); if (ret < 0) { fprintf(stderr, "recv error %s\n", strerror(errno)); msgb_free(msg); @@ -638,34 +637,25 @@ static struct msgb *read_gprs_msg(struct bsc_fd *bfd, int *error) static int handle_gprs_read(struct bsc_fd *bfd) { int error; - struct msgb *msg = read_gprs_msg(bfd, &error); + struct sockaddr_in saddr; + struct msgb *msg = read_gprs_msg(bfd, &error, &saddr); if (!msg) return error; - if (gprs_ns_rcvmsg) - return gprs_ns_rcvmsg(msg); - else { - msgb_free(msg); - return 0; - } + return gprs_ns_rcvmsg(msg, &saddr); } static int handle_gprs_write(struct bsc_fd *bfd) { } -int ipac_gprs_send(struct msgb *msg) +int ipac_gprs_send(struct msgb *msg, struct sockaddr_in *daddr) { - struct sockaddr_in sin; int rc; - sin.sin_family = AF_INET; - inet_aton("192.168.100.111", &sin.sin_addr); - sin.sin_port = htons(23000); - rc = sendto(e1h->gprs_fd.fd, msg->data, msg->len, 0, - (struct sockaddr *)&sin, sizeof(sin)); + (struct sockaddr *)daddr, sizeof(*daddr)); talloc_free(msg); -- cgit v1.2.3 From 2977d67d489564736da6771cbbd6214d3d4541db Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 28 Mar 2010 17:44:55 +0800 Subject: GPRS: add DGPRS to new debug api --- openbsc/src/debug.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/openbsc/src/debug.c b/openbsc/src/debug.c index a55d79013..181756de5 100644 --- a/openbsc/src/debug.c +++ b/openbsc/src/debug.c @@ -146,6 +146,11 @@ static const struct log_info_cat default_categories[] = { .description = "Reference Counting", .enabled = 0, .loglevel = LOGL_NOTICE, }, + [DGPRS] = { + .name = "DGPRS", + .description = "GPRS Packet Service", + .enabled = 1, .loglevel = LOGL_DEBUG, + }, }; enum log_ctxt { -- cgit v1.2.3 From 943c5bc595eed5cd8f26204030f833e4450b4a0f Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Fri, 30 Apr 2010 16:33:12 +0200 Subject: gprs: Update gprs-sgsn branch to use new msgb->cb layout The explicit 'tlli, gmmh' members of struct msgb are gone from current libosmocore and have been replaced by the more generic 'control buffer' mechanism. --- openbsc/include/openbsc/gsm_data.h | 3 +++ openbsc/src/gprs_bssgp.c | 6 ++--- openbsc/src/gprs_llc.c | 4 ++-- openbsc/src/gsm_04_08_gprs.c | 46 +++++++++++++++++++------------------- 4 files changed, 31 insertions(+), 28 deletions(-) diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index 70f352b0b..4344bf8a3 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -85,6 +85,9 @@ struct openbsc_msgb_cb { u_int32_t tlli; }; #define OBSC_MSGB_CB(__msgb) ((struct openbsc_msgb_cb *)&((__msgb)->cb[0])) +#define msgb_tlli(__x) OBSC_MSGB_CB(__x)->tlli +#define msgb_gmmh(__x) OBSC_MSGB_CB(__x)->gmmh +#define msgb_llch(__x) (__x)->l4h struct msgb; typedef int gsm_cbfn(unsigned int hooknum, diff --git a/openbsc/src/gprs_bssgp.c b/openbsc/src/gprs_bssgp.c index de57d25df..b4436294d 100644 --- a/openbsc/src/gprs_bssgp.c +++ b/openbsc/src/gprs_bssgp.c @@ -144,7 +144,7 @@ static int bssgp_rx_ul_ud(struct msgb *msg, u_int16_t bvci) DEBUGP(DGPRS, "BSSGP UL-UD\n"); - msg->tlli = ntohl(budh->tlli); + msgb_tlli(msg) = ntohl(budh->tlli); rc = bssgp_tlv_parse(&tp, budh->data, data_len); /* Cell ID and LLC_PDU are the only mandatory IE */ @@ -159,7 +159,7 @@ static int bssgp_rx_ul_ud(struct msgb *msg, u_int16_t bvci) if (bts) msg->trx = bts->c0; - msg->llch = TLVP_VAL(&tp, BSSGP_IE_LLC_PDU); + msgb_llch(msg) = TLVP_VAL(&tp, BSSGP_IE_LLC_PDU); return gprs_llc_rcvmsg(msg, &tp); } @@ -390,7 +390,7 @@ int gprs_bssgp_tx_dl_ud(struct msgb *msg) /* prepend the QoS profile, TLLI and pdu type */ budh = (struct bssgp_ud_hdr *) msgb_push(msg, sizeof(*budh)); memcpy(budh->qos_profile, qos_profile_default, sizeof(qos_profile_default)); - budh->tlli = htonl(msg->tlli); + budh->tlli = htonl(msgb_tlli(msg)); budh->pdu_type = BSSGP_PDUT_DL_UNITDATA; return gprs_ns_sendmsg(NULL, bts->gprs.cell.bvci, msg); diff --git a/openbsc/src/gprs_llc.c b/openbsc/src/gprs_llc.c index 2c927c6cf..91b0239f0 100644 --- a/openbsc/src/gprs_llc.c +++ b/openbsc/src/gprs_llc.c @@ -396,7 +396,7 @@ static int gprs_llc_hdr_parse(struct gprs_llc_hdr_parsed *ghp, int gprs_llc_rcvmsg(struct msgb *msg, struct tlv_parsed *tv) { struct bssgp_ud_hdr *udh = (struct bssgp_ud_hdr *) msg->l3h; - struct gprs_llc_hdr *lh = msg->llch; + struct gprs_llc_hdr *lh = msgb_llch(msg); struct gprs_llc_hdr_parsed llhp; struct gprs_llc_entity *lle; int rc; @@ -409,7 +409,7 @@ int gprs_llc_rcvmsg(struct msgb *msg, struct tlv_parsed *tv) rc = gprs_llc_hdr_rx(&llhp, lle); if (llhp.data) { - msg->gmmh = llhp.data; + msgb_gmmh(msg) = llhp.data; switch (llhp.sapi) { case GPRS_SAPI_GMM: rc = gsm0408_gprs_rcvmsg(msg); diff --git a/openbsc/src/gsm_04_08_gprs.c b/openbsc/src/gsm_04_08_gprs.c index af6a481cb..150322872 100644 --- a/openbsc/src/gsm_04_08_gprs.c +++ b/openbsc/src/gsm_04_08_gprs.c @@ -177,7 +177,7 @@ static int gsm48_tx_gmm_att_ack(struct msgb *old_msg) DEBUGP(DMM, "<- GPRS ATTACH ACCEPT\n"); - msg->tlli = old_msg->tlli; + msgb_tlli(msg) = msgb_tlli(old_msg); msg->trx = old_msg->trx; gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh)); @@ -203,7 +203,7 @@ static int gsm48_tx_gmm_att_rej(struct msgb *old_msg, u_int8_t gmm_cause) DEBUGP(DMM, "<- GPRS ATTACH REJECT\n"); - msg->tlli = old_msg->tlli; + msgb_tlli(msg) = msgb_tlli(old_msg); msg->trx = old_msg->trx; gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1); @@ -222,7 +222,7 @@ static int gsm48_tx_gmm_id_req(struct msgb *old_msg, u_int8_t id_type) DEBUGP(DMM, "-> GPRS IDENTITY REQUEST: mi_type=%02x\n", id_type); - msg->tlli = old_msg->tlli; + msgb_tlli(msg) = msgb_tlli(old_msg); msg->trx = old_msg->trx; gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1); @@ -253,7 +253,7 @@ static int gsm48_gmm_authorize(struct sgsn_mm_ctx *ctx, struct msgb *msg) /* Parse Chapter 9.4.13 Identity Response */ static int gsm48_rx_gmm_id_resp(struct msgb *msg) { - struct gsm48_hdr *gh = (struct gsm48_hdr *) msg->gmmh; + struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg); u_int8_t mi_type = gh->data[1] & GSM_MI_TYPE_MASK; char mi_string[GSM48_MI_SIZE]; struct gprs_ra_id ra_id; @@ -264,9 +264,9 @@ static int gsm48_rx_gmm_id_resp(struct msgb *msg) mi_type, mi_string); gprs_ra_id_by_bts(&ra_id, msg->trx->bts); - ctx = sgsn_mm_ctx_by_tlli(msg->tlli, &ra_id); + ctx = sgsn_mm_ctx_by_tlli(msgb_tlli(msg), &ra_id); if (!ctx) { - DEBUGP(DMM, "from unknown TLLI 0x%08x?!?\n", msg->tlli); + DEBUGP(DMM, "from unknown TLLI 0x%08x?!?\n", msgb_tlli(msg)); return -EINVAL; } @@ -310,7 +310,7 @@ static void schedule_reject(struct sgsn_mm_ctx *ctx) /* Section 9.4.1 Attach request */ static int gsm48_rx_gmm_att_req(struct msgb *msg) { - struct gsm48_hdr *gh = (struct gsm48_hdr *) msg->gmmh; + struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg); u_int8_t *cur = gh->data, *msnc, *mi, *old_ra_info; u_int8_t msnc_len, att_type, mi_len, mi_type; u_int16_t drx_par; @@ -378,17 +378,17 @@ static int gsm48_rx_gmm_att_req(struct msgb *msg) } /* FIXME: Start some timer */ ctx->mm_state = GMM_COMMON_PROC_INIT; - ctx->tlli = msg->tlli; + ctx->tlli = msgb_tlli(msg); break; case GSM_MI_TYPE_TMSI: tmsi = strtoul(mi_string, NULL, 10); /* Try to find MM context based on P-TMSI */ ctx = sgsn_mm_ctx_by_ptmsi(tmsi); if (!ctx) { - ctx = sgsn_mm_ctx_alloc(msg->tlli, &ra_id); + ctx = sgsn_mm_ctx_alloc(msgb_tlli(msg), &ra_id); /* FIXME: Start some timer */ ctx->mm_state = GMM_COMMON_PROC_INIT; - ctx->tlli = msg->tlli; + ctx->tlli = msgb_tlli(msg); } break; default: @@ -416,7 +416,7 @@ static int gsm48_tx_gmm_ra_upd_ack(struct msgb *old_msg) DEBUGP(DMM, "<- ROUTING AREA UPDATE ACCEPT\n"); - msg->tlli = old_msg->tlli; + msgb_tlli(msg) = msgb_tlli(old_msg); msg->trx = old_msg->trx; gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh)); @@ -441,7 +441,7 @@ static int gsm48_tx_gmm_ra_upd_rej(struct msgb *old_msg, u_int8_t cause) DEBUGP(DMM, "<- ROUTING AREA UPDATE REJECT\n"); - msg->tlli = old_msg->tlli; + msgb_tlli(msg) = msgb_tlli(old_msg); msg->trx = old_msg->trx; gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 2); @@ -457,7 +457,7 @@ static int gsm48_tx_gmm_ra_upd_rej(struct msgb *old_msg, u_int8_t cause) /* Chapter 9.4.14: Routing area update request */ static int gsm48_rx_gmm_ra_upd_req(struct msgb *msg) { - struct gsm48_hdr *gh = (struct gsm48_hdr *) msg->gmmh; + struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg); struct sgsn_mm_ctx *mmctx; u_int8_t *cur = gh->data; struct gprs_ra_id old_ra_id; @@ -489,7 +489,7 @@ static int gsm48_rx_gmm_ra_upd_req(struct msgb *msg) } /* Look-up the MM context based on old RA-ID and TLLI */ - mmctx = sgsn_mm_ctx_by_tlli(msg->tlli, &old_ra_id); + mmctx = sgsn_mm_ctx_by_tlli(msgb_tlli(msg), &old_ra_id); if (!mmctx || mmctx->mm_state == GMM_DEREGISTERED) { /* The MS has to perform GPRS attach */ DEBUGPC(DMM, " REJECT\n"); @@ -518,7 +518,7 @@ static int gsm48_rx_gmm_status(struct msgb *msg) /* GPRS Mobility Management */ static int gsm0408_rcv_gmm(struct msgb *msg) { - struct gsm48_hdr *gh = (struct gsm48_hdr *) msg->gmmh; + struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg); int rc; switch (gh->msg_type) { @@ -556,7 +556,7 @@ static int gsm0408_rcv_gmm(struct msgb *msg) /* Section 9.5.2: Ativate PDP Context Accept */ static int gsm48_tx_gsm_act_pdp_acc(struct msgb *old_msg, struct gsm48_act_pdp_ctx_req *req) { - struct gsm48_hdr *old_gh = (struct gsm48_hdr *) old_msg->gmmh; + struct gsm48_hdr *old_gh = (struct gsm48_hdr *) msgb_gmmh(old_msg); struct msgb *msg = gsm48_msgb_alloc(); struct gsm48_act_pdp_ctx_ack *act_ack; struct gsm48_hdr *gh; @@ -564,7 +564,7 @@ static int gsm48_tx_gsm_act_pdp_acc(struct msgb *old_msg, struct gsm48_act_pdp_c DEBUGP(DMM, "<- ACTIVATE PDP CONTEXT ACK\n"); - msg->tlli = old_msg->tlli; + msgb_tlli(msg) = msgb_tlli(old_msg); msg->trx = old_msg->trx; gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh)); @@ -582,14 +582,14 @@ static int gsm48_tx_gsm_act_pdp_acc(struct msgb *old_msg, struct gsm48_act_pdp_c /* Section 9.5.9: Deactivate PDP Context Accept */ static int gsm48_tx_gsm_deact_pdp_acc(struct msgb *old_msg) { - struct gsm48_hdr *old_gh = (struct gsm48_hdr *) old_msg->gmmh; + struct gsm48_hdr *old_gh = (struct gsm48_hdr *) msgb_gmmh(old_msg); struct msgb *msg = gsm48_msgb_alloc(); struct gsm48_hdr *gh; u_int8_t transaction_id = ((old_gh->proto_discr >> 4) ^ 0x8); /* flip */ DEBUGP(DMM, "<- DEACTIVATE PDP CONTEXT ACK\n"); - msg->tlli = old_msg->tlli; + msgb_tlli(msg) = msgb_tlli(old_msg); msg->trx = old_msg->trx; gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh)); @@ -602,7 +602,7 @@ static int gsm48_tx_gsm_deact_pdp_acc(struct msgb *old_msg) /* Section 9.5.1: Activate PDP Context Request */ static int gsm48_rx_gsm_act_pdp_req(struct msgb *msg) { - struct gsm48_hdr *gh = (struct gsm48_hdr *) msg->gmmh; + struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg); struct gsm48_act_pdp_ctx_req *act_req = (struct gsm48_act_pdp_ctx_req *) gh->data; u_int8_t *pdp_addr_lv = act_req->data; @@ -616,7 +616,7 @@ static int gsm48_rx_gsm_act_pdp_req(struct msgb *msg) /* Section 9.5.8: Deactivate PDP Context Request */ static int gsm48_rx_gsm_deact_pdp_req(struct msgb *msg) { - struct gsm48_hdr *gh = (struct gsm48_hdr *) msg->gmmh; + struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg); DEBUGP(DMM, "DEACTIVATE PDP CONTEXT REQ (cause: %s)\n", get_value_string(gsm_cause_names, gh->data[0])); @@ -637,7 +637,7 @@ static int gsm48_rx_gsm_status(struct msgb *msg) /* GPRS Session Management */ static int gsm0408_rcv_gsm(struct msgb *msg) { - struct gsm48_hdr *gh = (struct gsm48_hdr *) msg->gmmh; + struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg); int rc; switch (gh->msg_type) { @@ -668,7 +668,7 @@ static int gsm0408_rcv_gsm(struct msgb *msg) /* Main entry point for incoming 04.08 GPRS messages */ int gsm0408_gprs_rcvmsg(struct msgb *msg) { - struct gsm48_hdr *gh = (struct gsm48_hdr *) msg->gmmh; + struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg); u_int8_t pdisc = gh->proto_discr & 0x0f; int rc = -EINVAL; -- cgit v1.2.3 From cb991632496cb36e059db96493d73bc625fed9dd Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 26 Apr 2010 19:18:54 +0200 Subject: GPRS: Modularize the NS implementation * move UDP listener code for NSIP from input/ipaccess.c and into gprs_ns.c * add PDU type, IE and CAUSE values for later IP based 3GPP TS 48.016 * support multiple NS-VCs and their lookup based on NSVC and sockaddr_in * maintain the remote_state (blocked/alive) for each NSVC * introduce the concept of GPRS_NS instances, move all global vars to instance * remove hardcoded calls to gprs_bssgp_rcvmsg() and replace it by callback WARNING: This is not finished code. While it will compile, it will not work yet, as BSSGP needs to be converted to properly indicate the NSVC to which it needs to send data. --- openbsc/include/openbsc/gprs_ns.h | 62 ++++++++-- openbsc/src/gprs_ns.c | 253 ++++++++++++++++++++++++++++++++++---- openbsc/src/gprs_sgsn.c | 35 ++++++ openbsc/src/input/ipaccess.c | 80 +----------- 4 files changed, 321 insertions(+), 109 deletions(-) diff --git a/openbsc/include/openbsc/gprs_ns.h b/openbsc/include/openbsc/gprs_ns.h index 9ea4d6752..98b31f8da 100644 --- a/openbsc/include/openbsc/gprs_ns.h +++ b/openbsc/include/openbsc/gprs_ns.h @@ -1,6 +1,10 @@ #ifndef _GPRS_NS_H #define _GPRS_NS_H +/* GPRS Networks Service (NS) messages on the Gb interface + * 3GPP TS 08.16 version 8.0.1 Release 1999 / ETSI TS 101 299 V8.0.1 (2002-05) + * 3GPP TS 48.016 version 6.5.0 Release 6 / ETSI TS 148 016 V6.5.0 (2005-11) */ + struct gprs_ns_hdr { u_int8_t pdu_type; u_int8_t data[0]; @@ -18,6 +22,15 @@ enum ns_pdu_type { NS_PDUT_STATUS = 0x08, NS_PDUT_ALIVE = 0x0a, NS_PDUT_ALIVE_ACK = 0x0b, + /* TS 48.016 Section 10.3.7, Table 10.3.7.1 */ + SNS_PDUT_ACK = 0x0c, + SNS_PDUT_ADD = 0x0d, + SNS_PDUT_CHANGE_WEIGHT = 0x0e, + SNS_PDUT_CONFIG = 0x0f, + SNS_PDUT_CONFIG_ACK = 0x10, + SNS_PDUT_DELETE = 0x11, + SNS_PDUT_SIZE = 0x12, + SNS_PDUT_SIZE_ACK = 0x13, }; /* TS 08.16, Section 10.3, Table 12 */ @@ -27,6 +40,14 @@ enum ns_ctrl_ie { NS_IE_PDU = 0x02, NS_IE_BVCI = 0x03, NS_IE_NSEI = 0x04, + /* TS 48.016 Section 10.3, Table 10.3.1 */ + NS_IE_IPv4_LIST = 0x05, + NS_IE_IPv6_LIST = 0x06, + NS_IE_MAX_NR_NSVC = 0x07, + NS_IE_IPv4_EP_NR = 0x08, + NS_IE_IPv6_EP_NR = 0x09, + NS_IE_RESET_FLAG = 0x0a, + NS_IE_IP_ADDR = 0x0b, }; /* TS 08.16, Section 10.3.2, Table 13 */ @@ -42,20 +63,43 @@ enum ns_cause { NS_CAUSE_PROTO_ERR_UNSPEC = 0x0b, NS_CAUSE_INVAL_ESSENT_IE = 0x0c, NS_CAUSE_MISSING_ESSENT_IE = 0x0d, + /* TS 48.016 Section 10.3.2, Table 10.3.2.1 */ + NS_CAUSE_INVAL_NR_IPv4_EP = 0x0e, + NS_CAUSE_INVAL_NR_IPv6_EP = 0x0f, + NS_CAUSE_INVAL_NR_NS_VC = 0x10, + NS_CAUSE_INVAL_WEIGH = 0x11, + NS_CAUSE_UNKN_IP_EP = 0x12, + NS_CAUSE_UNKN_IP_ADDR = 0x13, + NS_CAUSE_UNKN_IP_TEST_FAILED = 0x14, }; -/* a layer 1 entity transporting NS frames */ -struct gprs_ns_link { - union { - struct { - int fd; - } ip; - }; +struct gprs_nsvc; +struct gprs_ns_inst; + +enum gprs_ns_evt { + GPRS_NS_EVT_UNIT_DATA, }; +typedef int gprs_ns_cb_t(enum gprs_ns_evt event, struct gprs_nsvc *nsvc, + struct msgb *msg, u_int16_t bvci); + +/* Create a new NS protocol instance */ +struct gprs_ns_inst *gprs_ns_instantiate(gprs_ns_cb_t *cb); + +/* Destroy a NS protocol instance */ +void gprs_ns_destroy(struct gprs_ns_inst *nsi); -int gprs_ns_rcvmsg(struct msgb *msg, struct sockaddr_in *saddr); +/* Listen for incoming GPRS packets */ +int nsip_listen(struct gprs_ns_inst *nsi, uint16_t udp_port); -int gprs_ns_sendmsg(struct gprs_ns_link *link, u_int16_t bvci, +struct sockaddr_in; + +/* main entry point, here incoming NS frames enter */ +int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, + struct sockaddr_in *saddr); + +/* main function for higher layers (BSSGP) to send NS messages */ +int gprs_ns_sendmsg(struct gprs_nsvc *nsvc, u_int16_t bvci, struct msgb *msg); + #endif diff --git a/openbsc/src/gprs_ns.c b/openbsc/src/gprs_ns.c index 6fb7d1d93..c5166fa53 100644 --- a/openbsc/src/gprs_ns.c +++ b/openbsc/src/gprs_ns.c @@ -1,7 +1,7 @@ /* GPRS Networks Service (NS) messages on the Gb interface * 3GPP TS 08.16 version 8.0.1 Release 1999 / ETSI TS 101 299 V8.0.1 (2002-05) */ -/* (C) 2009 by Harald Welte +/* (C) 2009-2010 by Harald Welte * * All Rights Reserved * @@ -55,6 +55,7 @@ #include #include #include +#include #include #include #include @@ -76,11 +77,13 @@ static const struct tlv_definition ns_att_tlvdef = { struct gprs_nsvc { struct llist_head list; + struct gprs_ns_inst *nsi; u_int16_t nsei; /* end-to-end significance */ u_int16_t nsvci; /* uniquely identifies NS-VC at SGSN */ u_int32_t state; + u_int32_t remote_state; struct timer_list alive_timer; int timer_is_tns_alive; @@ -93,8 +96,67 @@ struct gprs_nsvc { }; }; -/* FIXME: dynamically search for the matching NSVC */ -static struct gprs_nsvc dummy_nsvc = { .state = NSE_S_BLOCKED | NSE_S_ALIVE }; +enum gprs_ns_ll { + GPRS_NS_LL_UDP, + GPRS_NS_LL_E1, +}; + +/* An instance of the NS protocol stack */ +struct gprs_ns_inst { + /* callback to the user for incoming UNIT DATA IND */ + gprs_ns_cb_t *cb; + + /* linked lists of all NSVC in this instance */ + struct llist_head gprs_nsvcs; + + /* which link-layer are we based on? */ + enum gprs_ns_ll ll; + + union { + /* NS-over-IP specific bits */ + struct { + struct bsc_fd fd; + } nsip; + }; +}; + +/* Lookup struct gprs_nsvc based on NSVCI */ +static struct gprs_nsvc *nsvc_by_nsvci(struct gprs_ns_inst *nsi, + u_int16_t nsvci) +{ + struct gprs_nsvc *nsvc; + llist_for_each_entry(nsvc, &nsi->gprs_nsvcs, list) { + if (nsvc->nsvci == nsvci) + return nsvc; + } + return NULL; +} + +/* Lookup struct gprs_nsvc based on remote peer socket addr */ +static struct gprs_nsvc *nsvc_by_rem_addr(struct gprs_ns_inst *nsi, + struct sockaddr_in *sin) +{ + struct gprs_nsvc *nsvc; + llist_for_each_entry(nsvc, &nsi->gprs_nsvcs, list) { + if (!memcmp(&nsvc->ip.bts_addr, sin, sizeof(*sin))) + return nsvc; + } + return NULL; +} + +static struct gprs_nsvc *nsvc_create(struct gprs_ns_inst *nsi, u_int16_t nsvci) +{ + struct gprs_nsvc *nsvc; + + nsvc = talloc_zero(nsi, struct gprs_nsvc); + nsvc->nsvci = nsvci; + /* before RESET procedure: BLOCKED and DEAD */ + nsvc->state = NSE_S_BLOCKED; + nsvc->nsi = nsi; + llist_add(&nsvc->list, &nsi->gprs_nsvcs); + + return nsvc; +} /* Section 10.3.2, Table 13 */ static const char *ns_cause_str[] = { @@ -122,9 +184,23 @@ static const char *gprs_ns_cause_str(enum ns_cause cause) return "undefined"; } +static int nsip_sendmsg(struct msgb *msg, struct gprs_nsvc *nsvc); + static int gprs_ns_tx(struct msgb *msg, struct gprs_nsvc *nsvc) { - return ipac_gprs_send(msg, &nsvc->ip.bts_addr); + int ret; + + switch (nsvc->nsi->ll) { + case GPRS_NS_LL_UDP: + ret = nsip_sendmsg(msg, nsvc); + break; + default: + LOGP(DGPRS, LOGL_ERROR, "unsupported NS linklayer %u\n", nsvc->nsi->ll); + msgb_free(msg); + ret = -EIO; + break; + } + return ret; } static int gprs_ns_tx_simple(struct gprs_nsvc *nsvc, u_int8_t pdu_type) @@ -196,11 +272,10 @@ static int gprs_ns_tx_reset_ack(struct gprs_nsvc *nsvc) } /* Section 9.2.10: transmit side */ -int gprs_ns_sendmsg(struct gprs_ns_link *link, u_int16_t bvci, +int gprs_ns_sendmsg(struct gprs_nsvc *nsvc, u_int16_t bvci, struct msgb *msg) { struct gprs_ns_hdr *nsh; - struct gprs_nsvc *nsvc = &dummy_nsvc; nsh = (struct gprs_ns_hdr *) msgb_push(msg, sizeof(*nsh) + 3); if (!nsh) { @@ -217,7 +292,7 @@ int gprs_ns_sendmsg(struct gprs_ns_link *link, u_int16_t bvci, } /* Section 9.2.10: receive side */ -static int gprs_ns_rx_unitdata(struct msgb *msg) +static int gprs_ns_rx_unitdata(struct msgb *msg, struct gprs_nsvc *nsvc) { struct gprs_ns_hdr *nsh = (struct gprs_ns_hdr *)msg->l2h; u_int16_t bvci; @@ -227,13 +302,13 @@ static int gprs_ns_rx_unitdata(struct msgb *msg) msg->l3h = &nsh->data[3]; /* call upper layer (BSSGP) */ - return gprs_bssgp_rcvmsg(msg, bvci); + return nsvc->nsi->cb(GPRS_NS_EVT_UNIT_DATA, nsvc, msg, bvci); } /* Section 9.2.7 */ -static int gprs_ns_rx_status(struct msgb *msg) +static int gprs_ns_rx_status(struct msgb *msg, struct gprs_nsvc *nsvc) { - struct gprs_ns_hdr *nsh = msg->l2h; + struct gprs_ns_hdr *nsh = (struct gprs_ns_hdr *) msg->l2h; struct tlv_parsed tp; u_int8_t cause; int rc; @@ -254,10 +329,9 @@ static int gprs_ns_rx_status(struct msgb *msg) } /* Section 7.3 */ -static int gprs_ns_rx_reset(struct msgb *msg) +static int gprs_ns_rx_reset(struct msgb *msg, struct gprs_nsvc *nsvc) { struct gprs_ns_hdr *nsh = (struct gprs_ns_hdr *) msg->l2h; - struct gprs_nsvc *nsvc = &dummy_nsvc; struct tlv_parsed tp; u_int8_t *cause; u_int16_t *nsvci, *nsei; @@ -296,14 +370,24 @@ static int gprs_ns_rx_reset(struct msgb *msg) } /* main entry point, here incoming NS frames enter */ -int gprs_ns_rcvmsg(struct msgb *msg, struct sockaddr_in *saddr) +int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, + struct sockaddr_in *saddr) { struct gprs_ns_hdr *nsh = (struct gprs_ns_hdr *) msg->l2h; - struct gprs_nsvc *nsvc = &dummy_nsvc; + struct gprs_nsvc *nsvc; int rc = 0; - /* FIXME: do this properly! */ - nsvc->ip.bts_addr = *saddr; + /* look up the NSVC based on source address */ + nsvc = nsvc_by_rem_addr(nsi, saddr); + if (!nsvc) { + /* Only the RESET procedure creates a new NSVC */ + if (nsh->pdu_type != NS_PDUT_RESET) + return -EIO; + nsvc = nsvc_create(nsi, 0xffff); + nsvc->ip.bts_addr = *saddr; + rc = gprs_ns_rx_reset(msg, nsvc); + return rc; + } switch (nsh->pdu_type) { case NS_PDUT_ALIVE: @@ -320,16 +404,18 @@ int gprs_ns_rcvmsg(struct msgb *msg, struct sockaddr_in *saddr) break; case NS_PDUT_UNITDATA: /* actual user data */ - rc = gprs_ns_rx_unitdata(msg); + rc = gprs_ns_rx_unitdata(msg, nsvc); break; case NS_PDUT_STATUS: - rc = gprs_ns_rx_status(msg); + rc = gprs_ns_rx_status(msg, nsvc); break; case NS_PDUT_RESET: - rc = gprs_ns_rx_reset(msg); + rc = gprs_ns_rx_reset(msg, nsvc); break; case NS_PDUT_RESET_ACK: - /* FIXME: mark remote NS-VC as blocked + active */ + DEBUGP(DGPRS, "NS RESET ACK\n"); + /* mark remote NS-VC as blocked + active */ + nsvc->remote_state = NSE_S_BLOCKED | NSE_S_ALIVE; break; case NS_PDUT_UNBLOCK: /* Section 7.2: unblocking procedure */ @@ -338,7 +424,9 @@ int gprs_ns_rcvmsg(struct msgb *msg, struct sockaddr_in *saddr) rc = gprs_ns_tx_simple(nsvc, NS_PDUT_UNBLOCK_ACK); break; case NS_PDUT_UNBLOCK_ACK: - /* FIXME: mark remote NS-VC as unblocked + active */ + DEBUGP(DGPRS, "NS UNBLOCK ACK\n"); + /* mark remote NS-VC as unblocked + active */ + nsvc->remote_state = NSE_S_ALIVE; break; case NS_PDUT_BLOCK: DEBUGP(DGPRS, "NS BLOCK\n"); @@ -346,7 +434,9 @@ int gprs_ns_rcvmsg(struct msgb *msg, struct sockaddr_in *saddr) rc = gprs_ns_tx_simple(nsvc, NS_PDUT_UNBLOCK_ACK); break; case NS_PDUT_BLOCK_ACK: - /* FIXME: mark remote NS-VC as blocked + active */ + DEBUGP(DGPRS, "NS BLOCK ACK\n"); + /* mark remote NS-VC as blocked + active */ + nsvc->remote_state = NSE_S_BLOCKED | NSE_S_ALIVE; break; default: DEBUGP(DGPRS, "Unknown NS PDU type 0x%02x\n", nsh->pdu_type); @@ -356,3 +446,122 @@ int gprs_ns_rcvmsg(struct msgb *msg, struct sockaddr_in *saddr) return rc; } +struct gprs_ns_inst *gprs_ns_instantiate(gprs_ns_cb_t *cb) +{ + struct gprs_ns_inst *nsi = talloc_zero(tall_bsc_ctx, struct gprs_ns_inst); + + nsi->cb = cb; + INIT_LLIST_HEAD(&nsi->gprs_nsvcs); + + return NULL; +} + +void gprs_ns_destroy(struct gprs_ns_inst *nsi) +{ + /* FIXME: clear all timers */ + + /* recursively free the NSI and all its NSVCs */ + talloc_free(nsi); +} + + +/* NS-over-IP code, according to 3GPP TS 48.016 Chapter 6.2 + * We don't support Size Procedure, Configuration Procedure, ChangeWeight Procedure */ + +/* Read a single NS-over-IP message */ +static struct msgb *read_nsip_msg(struct bsc_fd *bfd, int *error, + struct sockaddr_in *saddr) +{ + struct msgb *msg = msgb_alloc(NS_ALLOC_SIZE, "Abis/IP/GPRS-NS"); + int ret = 0; + socklen_t saddr_len = sizeof(*saddr); + + if (!msg) { + *error = -ENOMEM; + return NULL; + } + + ret = recvfrom(bfd->fd, msg->data, NS_ALLOC_SIZE, 0, + (struct sockaddr *)saddr, &saddr_len); + if (ret < 0) { + fprintf(stderr, "recv error %s\n", strerror(errno)); + msgb_free(msg); + *error = ret; + return NULL; + } else if (ret == 0) { + msgb_free(msg); + *error = ret; + return NULL; + } + + msg->l2h = msg->data; + msgb_put(msg, ret); + + return msg; +} + +static int handle_nsip_read(struct bsc_fd *bfd) +{ + int error; + struct sockaddr_in saddr; + struct gprs_ns_inst *nsi = bfd->data; + struct msgb *msg = read_nsip_msg(bfd, &error, &saddr); + + if (!msg) + return error; + + return gprs_ns_rcvmsg(nsi, msg, &saddr); +} + +static int handle_nsip_write(struct bsc_fd *bfd) +{ + /* FIXME: actually send the data here instead of nsip_sendmsg() */ + return -EIO; +} + +int nsip_sendmsg(struct msgb *msg, struct gprs_nsvc *nsvc) +{ + int rc; + struct gprs_ns_inst *nsi = nsvc->nsi; + struct sockaddr_in *daddr = &nsvc->ip.bts_addr; + + rc = sendto(nsi->nsip.fd.fd, msg->data, msg->len, 0, + (struct sockaddr *)daddr, sizeof(*daddr)); + + talloc_free(msg); + + return rc; +} + +/* UDP Port 23000 carries the LLC-in-BSSGP-in-NS protocol stack */ +static int nsip_fd_cb(struct bsc_fd *bfd, unsigned int what) +{ + int rc = 0; + + if (what & BSC_FD_READ) + rc = handle_nsip_read(bfd); + if (what & BSC_FD_WRITE) + rc = handle_nsip_write(bfd); + + return rc; +} + + +/* FIXME: this is currently in input/ipaccess.c */ +extern int make_sock(struct bsc_fd *bfd, int proto, u_int16_t port, + int (*cb)(struct bsc_fd *fd, unsigned int what)); + +/* Listen for incoming GPRS packets */ +int nsip_listen(struct gprs_ns_inst *nsi, uint16_t udp_port) +{ + int ret; + + ret = make_sock(&nsi->nsip.fd, IPPROTO_UDP, udp_port, nsip_fd_cb); + if (ret < 0) + return ret; + + nsi->ll = GPRS_NS_LL_UDP; + nsi->nsip.fd.data = nsi; + + return ret; +} diff --git a/openbsc/src/gprs_sgsn.c b/openbsc/src/gprs_sgsn.c index 477e448be..3f7f61e20 100644 --- a/openbsc/src/gprs_sgsn.c +++ b/openbsc/src/gprs_sgsn.c @@ -26,7 +26,10 @@ #include #include #include +#include #include +#include +#include static LLIST_HEAD(sgsn_mm_ctxts); @@ -91,3 +94,35 @@ struct sgsn_mm_ctx *sgsn_mm_ctx_alloc(u_int32_t tlli, return ctx; } + +/* call-back function for the NS protocol */ +static int gprs_ns_cb(enum gprs_ns_evt event, struct gprs_nsvc *nsvc, + struct msgb *msg, u_int16_t bvci) +{ + int rc = 0; + + switch (event) { + case GPRS_NS_EVT_UNIT_DATA: + /* hand the message into the BSSGP implementation */ + rc = gprs_bssgp_rcvmsg(msg, bvci); + break; + default: + LOGP(DGPRS, LOGL_ERROR, "SGSN: Unknown event %u from NS\n", event); + if (msg) + talloc_free(msg); + rc = -EIO; + break; + } + return rc; +} + +int sgsn_init(void) +{ + struct gprs_ns_inst *nsi; + + nsi = gprs_ns_instantiate(&gprs_ns_cb); + if (!nsi) + return -EIO; + + return nsip_listen(nsi, 23000); +} diff --git a/openbsc/src/input/ipaccess.c b/openbsc/src/input/ipaccess.c index 80055ad9f..2b5bf21a6 100644 --- a/openbsc/src/input/ipaccess.c +++ b/openbsc/src/input/ipaccess.c @@ -53,7 +53,6 @@ struct ia_e1_handle { struct bsc_fd listen_fd; struct bsc_fd rsl_listen_fd; - struct bsc_fd gprs_fd; struct gsm_network *gsmnet; }; @@ -603,78 +602,6 @@ static int ipaccess_fd_cb(struct bsc_fd *bfd, unsigned int what) return rc; } -static struct msgb *read_gprs_msg(struct bsc_fd *bfd, int *error, - struct sockaddr_in *saddr) -{ - struct msgb *msg = msgb_alloc(TS1_ALLOC_SIZE, "Abis/IP/GPRS"); - int ret = 0; - socklen_t saddr_len = sizeof(*saddr); - - if (!msg) { - *error = -ENOMEM; - return NULL; - } - - ret = recvfrom(bfd->fd, msg->data, TS1_ALLOC_SIZE, 0, - (struct sockaddr *)saddr, &saddr_len); - if (ret < 0) { - fprintf(stderr, "recv error %s\n", strerror(errno)); - msgb_free(msg); - *error = ret; - return NULL; - } else if (ret == 0) { - msgb_free(msg); - *error = ret; - return NULL; - } - - msg->l2h = msg->data; - msgb_put(msg, ret); - - return msg; -} - -static int handle_gprs_read(struct bsc_fd *bfd) -{ - int error; - struct sockaddr_in saddr; - struct msgb *msg = read_gprs_msg(bfd, &error, &saddr); - - if (!msg) - return error; - - return gprs_ns_rcvmsg(msg, &saddr); -} - -static int handle_gprs_write(struct bsc_fd *bfd) -{ -} - -int ipac_gprs_send(struct msgb *msg, struct sockaddr_in *daddr) -{ - int rc; - - rc = sendto(e1h->gprs_fd.fd, msg->data, msg->len, 0, - (struct sockaddr *)daddr, sizeof(*daddr)); - - talloc_free(msg); - - return rc; -} - -/* UDP Port 23000 carries the LLC-in-BSSGP-in-NS protocol stack */ -static int gprs_fd_cb(struct bsc_fd *bfd, unsigned int what) -{ - int rc; - - if (what & BSC_FD_READ) - rc = handle_gprs_read(bfd); - if (what & BSC_FD_WRITE) - rc = handle_gprs_write(bfd); - - return rc; -} - struct e1inp_driver ipaccess_driver = { .name = "ip.access", .want_write = ts_want_write, @@ -780,8 +707,8 @@ static int rsl_listen_fd_cb(struct bsc_fd *listen_bfd, unsigned int what) return 0; } -static int make_sock(struct bsc_fd *bfd, int proto, u_int16_t port, - int (*cb)(struct bsc_fd *fd, unsigned int what)) +int make_sock(struct bsc_fd *bfd, int proto, u_int16_t port, + int (*cb)(struct bsc_fd *fd, unsigned int what)) { struct sockaddr_in addr; int ret, on = 1; @@ -899,8 +826,5 @@ int ipaccess_setup(struct gsm_network *gsmnet) if (ret < 0) return ret; - /* Listen for incoming GPRS packets */ - ret = make_sock(&e1h->gprs_fd, IPPROTO_UDP, 23000, gprs_fd_cb); - return ret; } -- cgit v1.2.3 From b7bd65ea01960ae532f8901dd8f03003ebf30e6f Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 26 Apr 2010 21:55:29 +0200 Subject: signal.h: Don't include gsm_subscriber but rather declare it --- openbsc/include/openbsc/signal.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openbsc/include/openbsc/signal.h b/openbsc/include/openbsc/signal.h index 1b974e288..73f3fe31a 100644 --- a/openbsc/include/openbsc/signal.h +++ b/openbsc/include/openbsc/signal.h @@ -26,7 +26,6 @@ #include #include -#include #include @@ -118,6 +117,8 @@ enum signal_global { S_GLOBAL_SHUTDOWN, }; +struct gsm_subscriber; + struct paging_signal_data { struct gsm_subscriber *subscr; struct gsm_bts *bts; -- cgit v1.2.3 From 06aa111fda8caadd312756fe280d808da12379f0 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Fri, 30 Apr 2010 16:43:39 +0200 Subject: gprs: Use new msgb->cb[] for storing a pointer to the NS-VC through which it was received --- openbsc/include/openbsc/gsm_data.h | 3 +++ openbsc/src/gprs_ns.c | 18 +++++++++++------- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index 4344bf8a3..79e77e803 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -79,14 +79,17 @@ enum bts_gprs_mode { BTS_GPRS_EGPRS = 2, }; +struct gprs_nsvc; /* the data structure stored in msgb->cb for openbsc apps */ struct openbsc_msgb_cb { unsigned char *gmmh; + struct gprs_nsvc *nsvc; u_int32_t tlli; }; #define OBSC_MSGB_CB(__msgb) ((struct openbsc_msgb_cb *)&((__msgb)->cb[0])) #define msgb_tlli(__x) OBSC_MSGB_CB(__x)->tlli #define msgb_gmmh(__x) OBSC_MSGB_CB(__x)->gmmh +#define msgb_nsvc(__x) OBSC_MSGB_CB(__x)->nsvc #define msgb_llch(__x) (__x)->l4h struct msgb; diff --git a/openbsc/src/gprs_ns.c b/openbsc/src/gprs_ns.c index c5166fa53..b57de1d72 100644 --- a/openbsc/src/gprs_ns.c +++ b/openbsc/src/gprs_ns.c @@ -292,9 +292,10 @@ int gprs_ns_sendmsg(struct gprs_nsvc *nsvc, u_int16_t bvci, } /* Section 9.2.10: receive side */ -static int gprs_ns_rx_unitdata(struct msgb *msg, struct gprs_nsvc *nsvc) +static int gprs_ns_rx_unitdata(struct msgb *msg) { struct gprs_ns_hdr *nsh = (struct gprs_ns_hdr *)msg->l2h; + struct gprs_nsvc *nsvc = msgb_nsvc(msg); u_int16_t bvci; /* spare octet in data[0] */ @@ -306,9 +307,10 @@ static int gprs_ns_rx_unitdata(struct msgb *msg, struct gprs_nsvc *nsvc) } /* Section 9.2.7 */ -static int gprs_ns_rx_status(struct msgb *msg, struct gprs_nsvc *nsvc) +static int gprs_ns_rx_status(struct msgb *msg) { struct gprs_ns_hdr *nsh = (struct gprs_ns_hdr *) msg->l2h; + struct gprs_nsvc *nsvc = msgb_nsvc(msg); struct tlv_parsed tp; u_int8_t cause; int rc; @@ -329,9 +331,10 @@ static int gprs_ns_rx_status(struct msgb *msg, struct gprs_nsvc *nsvc) } /* Section 7.3 */ -static int gprs_ns_rx_reset(struct msgb *msg, struct gprs_nsvc *nsvc) +static int gprs_ns_rx_reset(struct msgb *msg) { struct gprs_ns_hdr *nsh = (struct gprs_ns_hdr *) msg->l2h; + struct gprs_nsvc *nsvc = msgb_nsvc(msg); struct tlv_parsed tp; u_int8_t *cause; u_int16_t *nsvci, *nsei; @@ -385,9 +388,10 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, return -EIO; nsvc = nsvc_create(nsi, 0xffff); nsvc->ip.bts_addr = *saddr; - rc = gprs_ns_rx_reset(msg, nsvc); + rc = gprs_ns_rx_reset(msg); return rc; } + msgb_nsvc(msg) = nsvc; switch (nsh->pdu_type) { case NS_PDUT_ALIVE: @@ -404,13 +408,13 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, break; case NS_PDUT_UNITDATA: /* actual user data */ - rc = gprs_ns_rx_unitdata(msg, nsvc); + rc = gprs_ns_rx_unitdata(msg); break; case NS_PDUT_STATUS: - rc = gprs_ns_rx_status(msg, nsvc); + rc = gprs_ns_rx_status(msg); break; case NS_PDUT_RESET: - rc = gprs_ns_rx_reset(msg, nsvc); + rc = gprs_ns_rx_reset(msg); break; case NS_PDUT_RESET_ACK: DEBUGP(DGPRS, "NS RESET ACK\n"); -- cgit v1.2.3 From 44f1c27460325924e0391677ca76798951289f53 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Fri, 30 Apr 2010 19:54:29 +0200 Subject: gprs: remove msgb->nsvc pointer and replace it with NSEI and BVCI According to TS 08.16, the BSSGP layer needs to specify NSEI and BVCI when executing the NS UNITDATA REQUEST primitive of the underlying NS layer. Rather than passing around a pointer to the 'struct gprs_nsvc', we now have NSEI and BVCI as members of 'struct obsc_msgb_cb' and set them when BSSGP hands a message down to NS. NS then does a lookup of the 'gprs_nsvc' based on the NSEI parameter. --- openbsc/include/openbsc/gprs_ns.h | 3 +- openbsc/include/openbsc/gsm_data.h | 11 ++++--- openbsc/src/gprs_bssgp.c | 34 ++++++++++++++------- openbsc/src/gprs_ns.c | 61 ++++++++++++++++++++++++-------------- 4 files changed, 71 insertions(+), 38 deletions(-) diff --git a/openbsc/include/openbsc/gprs_ns.h b/openbsc/include/openbsc/gprs_ns.h index 98b31f8da..34a3e581f 100644 --- a/openbsc/include/openbsc/gprs_ns.h +++ b/openbsc/include/openbsc/gprs_ns.h @@ -99,7 +99,6 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, struct sockaddr_in *saddr); /* main function for higher layers (BSSGP) to send NS messages */ -int gprs_ns_sendmsg(struct gprs_nsvc *nsvc, u_int16_t bvci, - struct msgb *msg); +int gprs_ns_sendmsg(struct gprs_ns_inst *nsi, struct msgb *msg); #endif diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index 79e77e803..c124fae5e 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -79,17 +79,20 @@ enum bts_gprs_mode { BTS_GPRS_EGPRS = 2, }; -struct gprs_nsvc; /* the data structure stored in msgb->cb for openbsc apps */ struct openbsc_msgb_cb { unsigned char *gmmh; - struct gprs_nsvc *nsvc; + + u_int16_t nsei; + u_int16_t bvci; + u_int32_t tlli; -}; +} __attribute__((packed)); #define OBSC_MSGB_CB(__msgb) ((struct openbsc_msgb_cb *)&((__msgb)->cb[0])) #define msgb_tlli(__x) OBSC_MSGB_CB(__x)->tlli #define msgb_gmmh(__x) OBSC_MSGB_CB(__x)->gmmh -#define msgb_nsvc(__x) OBSC_MSGB_CB(__x)->nsvc +#define msgb_nsei(__x) OBSC_MSGB_CB(__x)->nsei +#define msgb_bvci(__x) OBSC_MSGB_CB(__x)->bvci #define msgb_llch(__x) (__x)->l4h struct msgb; diff --git a/openbsc/src/gprs_bssgp.c b/openbsc/src/gprs_bssgp.c index b4436294d..650d7d45d 100644 --- a/openbsc/src/gprs_bssgp.c +++ b/openbsc/src/gprs_bssgp.c @@ -37,6 +37,7 @@ /* global pointer to the gsm network data structure */ /* FIXME: this must go! */ extern struct gsm_network *bsc_gsmnet; +struct gprs_ns_inst *bssgp_nsi; /* Chapter 11.3.9 / Table 11.10: Cause coding */ static const char *bssgp_cause_strings[] = { @@ -84,31 +85,38 @@ static inline struct msgb *bssgp_msgb_alloc(void) } /* Transmit a simple response such as BLOCK/UNBLOCK/RESET ACK/NACK */ -static int bssgp_tx_simple_bvci(u_int8_t pdu_type, u_int16_t bvci, u_int16_t ns_bvci) +static int bssgp_tx_simple_bvci(u_int8_t pdu_type, u_int16_t nsei, + u_int16_t bvci, u_int16_t ns_bvci) { struct msgb *msg = bssgp_msgb_alloc(); struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph)); u_int16_t _bvci; + msgb_nsei(msg) = nsei; + msgb_bvci(msg) = ns_bvci; + bgph->pdu_type = pdu_type; _bvci = htons(bvci); msgb_tvlv_put(msg, BSSGP_IE_BVCI, 2, (u_int8_t *) &_bvci); - return gprs_ns_sendmsg(NULL, ns_bvci, msg); + return gprs_ns_sendmsg(bssgp_nsi, msg); } /* Chapter 10.4.5: Flow Control BVC ACK */ -static int bssgp_tx_fc_bvc_ack(u_int8_t tag, u_int16_t ns_bvci) +static int bssgp_tx_fc_bvc_ack(u_int16_t nsei, u_int8_t tag, u_int16_t ns_bvci) { struct msgb *msg = bssgp_msgb_alloc(); struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph)); + msgb_nsei(msg) = nsei; + msgb_bvci(msg) = ns_bvci; + bgph->pdu_type = BSSGP_PDUT_FLOW_CONTROL_BVC_ACK; msgb_tvlv_put(msg, BSSGP_IE_TAG, 1, &tag); - return gprs_ns_sendmsg(NULL, ns_bvci, msg); + return gprs_ns_sendmsg(bssgp_nsi, msg); } /* Chapter 10.4.14: Status */ @@ -119,6 +127,8 @@ static int bssgp_tx_status(u_int8_t cause, u_int16_t *bvci, struct msgb *orig_ms (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph)); DEBUGPC(DGPRS, "BSSGP: TX STATUS, cause=%s\n", bssgp_cause_str(cause)); + msgb_nsei(msg) = msgb_nsei(orig_msg); + msgb_bvci(msg) = 0; bgph->pdu_type = BSSGP_PDUT_STATUS; msgb_tvlv_put(msg, BSSGP_IE_CAUSE, 1, &cause); @@ -130,7 +140,7 @@ static int bssgp_tx_status(u_int8_t cause, u_int16_t *bvci, struct msgb *orig_ms msgb_tvlv_put(msg, BSSGP_IE_PDU_IN_ERROR, msgb_l3len(orig_msg), orig_msg->l3h); - return gprs_ns_sendmsg(NULL, 0, msg); + return gprs_ns_sendmsg(bssgp_nsi, msg); } /* Uplink unit-data */ @@ -221,7 +231,8 @@ static int bssgp_rx_fc_bvc(struct msgb *msg, struct tlv_parsed *tp, return bssgp_tx_status(BSSGP_CAUSE_MISSING_MAND_IE, NULL, msg); /* Send FLOW_CONTROL_BVC_ACK */ - return bssgp_tx_fc_bvc_ack(*TLVP_VAL(tp, BSSGP_IE_TAG), ns_bvci); + return bssgp_tx_fc_bvc_ack(msgb_nsei(msg), *TLVP_VAL(tp, BSSGP_IE_TAG), + ns_bvci); } /* We expect msg->l3h to point to the BSSGP header */ int gprs_bssgp_rcvmsg(struct msgb *msg, u_int16_t ns_bvci) @@ -287,7 +298,7 @@ int gprs_bssgp_rcvmsg(struct msgb *msg, u_int16_t ns_bvci) DEBUGPC(DGPRS, "BVCI=%u, cause=%s\n", bvci, bssgp_cause_str(*TLVP_VAL(&tp, BSSGP_IE_CAUSE))); rc = bssgp_tx_simple_bvci(BSSGP_PDUT_BVC_BLOCK_ACK, - bvci, ns_bvci); + msgb_nsei(msg), bvci, ns_bvci); break; case BSSGP_PDUT_BVC_UNBLOCK: /* BSS tells us that BVC shall be unblocked */ @@ -297,7 +308,7 @@ int gprs_bssgp_rcvmsg(struct msgb *msg, u_int16_t ns_bvci) bvci = ntohs(*(u_int16_t *)TLVP_VAL(&tp, BSSGP_IE_BVCI)); DEBUGPC(DGPRS, "BVCI=%u\n", bvci); rc = bssgp_tx_simple_bvci(BSSGP_PDUT_BVC_UNBLOCK_ACK, - bvci, ns_bvci); + msgb_nsei(msg), bvci, ns_bvci); break; case BSSGP_PDUT_BVC_RESET: /* BSS tells us that BVC init is required */ @@ -309,7 +320,7 @@ int gprs_bssgp_rcvmsg(struct msgb *msg, u_int16_t ns_bvci) DEBUGPC(DGPRS, "BVCI=%u, cause=%s\n", bvci, bssgp_cause_str(*TLVP_VAL(&tp, BSSGP_IE_CAUSE))); rc = bssgp_tx_simple_bvci(BSSGP_PDUT_BVC_RESET_ACK, - bvci, ns_bvci); + msgb_nsei(msg), bvci, ns_bvci); break; case BSSGP_PDUT_STATUS: /* Some exception has occurred */ @@ -393,5 +404,8 @@ int gprs_bssgp_tx_dl_ud(struct msgb *msg) budh->tlli = htonl(msgb_tlli(msg)); budh->pdu_type = BSSGP_PDUT_DL_UNITDATA; - return gprs_ns_sendmsg(NULL, bts->gprs.cell.bvci, msg); + msgb_nsei(msg) = bts->gprs.nse.nsei; + msgb_bvci(msg) = bts->gprs.cell.bvci; + + return gprs_ns_sendmsg(bssgp_nsi, msg); } diff --git a/openbsc/src/gprs_ns.c b/openbsc/src/gprs_ns.c index b57de1d72..6c495b01e 100644 --- a/openbsc/src/gprs_ns.c +++ b/openbsc/src/gprs_ns.c @@ -1,4 +1,4 @@ -/* GPRS Networks Service (NS) messages on the Gb interface +/* GPRS Networks Service (NS) messages on the Gb interfacebvci = msgb_bvci(msg); * 3GPP TS 08.16 version 8.0.1 Release 1999 / ETSI TS 101 299 V8.0.1 (2002-05) */ /* (C) 2009-2010 by Harald Welte @@ -132,6 +132,19 @@ static struct gprs_nsvc *nsvc_by_nsvci(struct gprs_ns_inst *nsi, return NULL; } +/* Lookup struct gprs_nsvc based on NSVCI */ +static struct gprs_nsvc *nsvc_by_nsei(struct gprs_ns_inst *nsi, + u_int16_t nsei) +{ + struct gprs_nsvc *nsvc; + llist_for_each_entry(nsvc, &nsi->gprs_nsvcs, list) { + if (nsvc->nsei == nsei) + return nsvc; + } + return NULL; +} + + /* Lookup struct gprs_nsvc based on remote peer socket addr */ static struct gprs_nsvc *nsvc_by_rem_addr(struct gprs_ns_inst *nsi, struct sockaddr_in *sin) @@ -184,15 +197,15 @@ static const char *gprs_ns_cause_str(enum ns_cause cause) return "undefined"; } -static int nsip_sendmsg(struct msgb *msg, struct gprs_nsvc *nsvc); +static int nsip_sendmsg(struct gprs_nsvc *nsvc, struct msgb *msg); -static int gprs_ns_tx(struct msgb *msg, struct gprs_nsvc *nsvc) +static int gprs_ns_tx(struct gprs_nsvc *nsvc, struct msgb *msg) { int ret; switch (nsvc->nsi->ll) { case GPRS_NS_LL_UDP: - ret = nsip_sendmsg(msg, nsvc); + ret = nsip_sendmsg(nsvc, msg); break; default: LOGP(DGPRS, LOGL_ERROR, "unsupported NS linklayer %u\n", nsvc->nsi->ll); @@ -215,7 +228,7 @@ static int gprs_ns_tx_simple(struct gprs_nsvc *nsvc, u_int8_t pdu_type) nsh->pdu_type = pdu_type; - return gprs_ns_tx(msg, nsvc); + return gprs_ns_tx(nsvc, msg); } #define NS_TIMER_ALIVE 3, 0 /* after 3 seconds without response, we retry */ @@ -268,14 +281,21 @@ static int gprs_ns_tx_reset_ack(struct gprs_nsvc *nsvc) msgb_tvlv_put(msg, NS_IE_VCI, 2, (u_int8_t *)&nsvci); msgb_tvlv_put(msg, NS_IE_NSEI, 2, (u_int8_t *)&nsei); - return gprs_ns_tx(msg, nsvc); + return gprs_ns_tx(nsvc, msg); } -/* Section 9.2.10: transmit side */ -int gprs_ns_sendmsg(struct gprs_nsvc *nsvc, u_int16_t bvci, - struct msgb *msg) +/* Section 9.2.10: transmit side / NS-UNITDATA-REQUEST primitive */ +int gprs_ns_sendmsg(struct gprs_ns_inst *nsi, struct msgb *msg) { + struct gprs_nsvc *nsvc; struct gprs_ns_hdr *nsh; + u_int16_t bvci = msgb_bvci(msg); + + nsvc = nsvc_by_nsei(nsi, msgb_nsei(msg)); + if (!nsvc) { + DEBUGP(DGPRS, "Unable to resolve NSEI %u to NS-VC!\n", msgb_nsei(msg)); + return -EINVAL; + } nsh = (struct gprs_ns_hdr *) msgb_push(msg, sizeof(*nsh) + 3); if (!nsh) { @@ -288,14 +308,13 @@ int gprs_ns_sendmsg(struct gprs_nsvc *nsvc, u_int16_t bvci, nsh->data[1] = bvci >> 8; nsh->data[2] = bvci & 0xff; - return gprs_ns_tx(msg, nsvc); + return gprs_ns_tx(nsvc, msg); } /* Section 9.2.10: receive side */ -static int gprs_ns_rx_unitdata(struct msgb *msg) +static int gprs_ns_rx_unitdata(struct gprs_nsvc *nsvc, struct msgb *msg) { struct gprs_ns_hdr *nsh = (struct gprs_ns_hdr *)msg->l2h; - struct gprs_nsvc *nsvc = msgb_nsvc(msg); u_int16_t bvci; /* spare octet in data[0] */ @@ -307,10 +326,9 @@ static int gprs_ns_rx_unitdata(struct msgb *msg) } /* Section 9.2.7 */ -static int gprs_ns_rx_status(struct msgb *msg) +static int gprs_ns_rx_status(struct gprs_nsvc *nsvc, struct msgb *msg) { struct gprs_ns_hdr *nsh = (struct gprs_ns_hdr *) msg->l2h; - struct gprs_nsvc *nsvc = msgb_nsvc(msg); struct tlv_parsed tp; u_int8_t cause; int rc; @@ -331,10 +349,9 @@ static int gprs_ns_rx_status(struct msgb *msg) } /* Section 7.3 */ -static int gprs_ns_rx_reset(struct msgb *msg) +static int gprs_ns_rx_reset(struct gprs_nsvc *nsvc, struct msgb *msg) { struct gprs_ns_hdr *nsh = (struct gprs_ns_hdr *) msg->l2h; - struct gprs_nsvc *nsvc = msgb_nsvc(msg); struct tlv_parsed tp; u_int8_t *cause; u_int16_t *nsvci, *nsei; @@ -388,10 +405,10 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, return -EIO; nsvc = nsvc_create(nsi, 0xffff); nsvc->ip.bts_addr = *saddr; - rc = gprs_ns_rx_reset(msg); + rc = gprs_ns_rx_reset(nsvc, msg); return rc; } - msgb_nsvc(msg) = nsvc; + msgb_nsei(msg) = nsvc->nsei; switch (nsh->pdu_type) { case NS_PDUT_ALIVE: @@ -408,13 +425,13 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, break; case NS_PDUT_UNITDATA: /* actual user data */ - rc = gprs_ns_rx_unitdata(msg); + rc = gprs_ns_rx_unitdata(nsvc, msg); break; case NS_PDUT_STATUS: - rc = gprs_ns_rx_status(msg); + rc = gprs_ns_rx_status(nsvc, msg); break; case NS_PDUT_RESET: - rc = gprs_ns_rx_reset(msg); + rc = gprs_ns_rx_reset(nsvc, msg); break; case NS_PDUT_RESET_ACK: DEBUGP(DGPRS, "NS RESET ACK\n"); @@ -523,7 +540,7 @@ static int handle_nsip_write(struct bsc_fd *bfd) return -EIO; } -int nsip_sendmsg(struct msgb *msg, struct gprs_nsvc *nsvc) +int nsip_sendmsg(struct gprs_nsvc *nsvc, struct msgb *msg) { int rc; struct gprs_ns_inst *nsi = nsvc->nsi; -- cgit v1.2.3 From 9f75c35eb3cf796366b7452538a1d3113cd6b546 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Fri, 30 Apr 2010 20:26:32 +0200 Subject: GPRS: Introduce a GPRS Gb Proxy The ida of the Gb proxy is to aggregate Gb links with a number of BSS and then present all the BSSGP-VC's together inside one NS-VC to the actual SGSN. The code is not yet expected to be complete. --- openbsc/include/openbsc/gprs_bssgp.h | 10 ++ openbsc/include/openbsc/gprs_ns.h | 39 ++++- openbsc/src/Makefile.am | 9 +- openbsc/src/gb_proxy.c | 315 +++++++++++++++++++++++++++++++++++ openbsc/src/gb_proxy_main.c | 140 ++++++++++++++++ openbsc/src/gprs_bssgp.c | 7 +- openbsc/src/gprs_ns.c | 47 +++--- openbsc/src/input/ipaccess.c | 52 ------ openbsc/src/socket.c | 94 +++++++++++ 9 files changed, 627 insertions(+), 86 deletions(-) create mode 100644 openbsc/src/gb_proxy.c create mode 100644 openbsc/src/gb_proxy_main.c create mode 100644 openbsc/src/socket.c diff --git a/openbsc/include/openbsc/gprs_bssgp.h b/openbsc/include/openbsc/gprs_bssgp.h index f85ac48ec..3040e6a0e 100644 --- a/openbsc/include/openbsc/gprs_bssgp.h +++ b/openbsc/include/openbsc/gprs_bssgp.h @@ -133,6 +133,16 @@ enum gprs_bssgp_cause { BSSGP_CAUSE_PDU_INCOMP_FEAT = 0x28, }; +/* Our implementation */ + +#include + extern int gprs_bssgp_rcvmsg(struct msgb *msg, u_int16_t bvci); +/* Wrapper around TLV parser to parse BSSGP IEs */ +static inline int bssgp_tlv_parse(struct tlv_parsed *tp, u_int8_t *buf, int len) +{ + return tlv_parse(tp, &tvlv_att_def, buf, len, 0, 0); +} + #endif /* _GPRS_BSSGP_H */ diff --git a/openbsc/include/openbsc/gprs_ns.h b/openbsc/include/openbsc/gprs_ns.h index 34a3e581f..dd10d3339 100644 --- a/openbsc/include/openbsc/gprs_ns.h +++ b/openbsc/include/openbsc/gprs_ns.h @@ -73,7 +73,37 @@ enum ns_cause { NS_CAUSE_UNKN_IP_TEST_FAILED = 0x14, }; -struct gprs_nsvc; + +/* Our Implementation */ +#include + +#define NSE_S_BLOCKED 0x0001 +#define NSE_S_ALIVE 0x0002 + +struct gprs_nsvc { + struct llist_head list; + struct gprs_ns_inst *nsi; + + u_int16_t nsei; /* end-to-end significance */ + u_int16_t nsvci; /* uniquely identifies NS-VC at SGSN */ + + u_int32_t state; + u_int32_t remote_state; + + struct timer_list alive_timer; + int timer_is_tns_alive; + int alive_retries; + + int remote_end_is_sgsn; + + union { + struct { + struct sockaddr_in bts_addr; + } ip; + }; +}; + + struct gprs_ns_inst; enum gprs_ns_evt { @@ -101,4 +131,11 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, /* main function for higher layers (BSSGP) to send NS messages */ int gprs_ns_sendmsg(struct gprs_ns_inst *nsi, struct msgb *msg); + +/* Listen for incoming GPRS packets */ +int nsip_listen(struct gprs_ns_inst *nsi, uint16_t udp_port); + +/* Establish a connection (from the BSS) to the SGSN */ +struct gprs_nsvc *nsip_connect(struct gprs_ns_inst *nsi, + struct sockaddr_in *dest, uint16_t nsvci); #endif diff --git a/openbsc/src/Makefile.am b/openbsc/src/Makefile.am index 718252f77..ac418707a 100644 --- a/openbsc/src/Makefile.am +++ b/openbsc/src/Makefile.am @@ -3,7 +3,7 @@ AM_CFLAGS=-Wall $(LIBOSMOCORE_CFLAGS) AM_LDFLAGS = $(LIBOSMOCORE_LIBS) sbin_PROGRAMS = bsc_hack bs11_config ipaccess-find ipaccess-config \ - isdnsync bsc_mgcp ipaccess-proxy + isdnsync bsc_mgcp ipaccess-proxy osmo-gb_proxy noinst_LIBRARIES = libbsc.a libmsc.a libvty.a libsccp.a libsgsn.a noinst_HEADERS = vty/cardshell.h @@ -11,7 +11,7 @@ bscdir = $(libdir) bsc_LIBRARIES = libsccp.a libbsc_a_SOURCES = abis_rsl.c abis_nm.c gsm_data.c gsm_04_08_utils.c \ - chan_alloc.c debug.c \ + chan_alloc.c debug.c socket.c \ gsm_subscriber_base.c subchan_demux.c bsc_rll.c transaction.c \ trau_frame.c trau_mux.c paging.c e1_config.c e1_input.c \ input/misdn.c input/ipaccess.c \ @@ -50,3 +50,8 @@ bsc_mgcp_SOURCES = mgcp/mgcp_main.c mgcp/mgcp_protocol.c mgcp/mgcp_network.c mgc bsc_mgcp_LDADD = libvty.a ipaccess_proxy_SOURCES = ipaccess/ipaccess-proxy.c debug.c + +osmo_gb_proxy_SOURCES = gb_proxy.c gb_proxy_main.c \ + gprs_ns.c \ + socket.c debug.c telnet_interface.c vty_interface_cmds.c +osmo_gb_proxy_LDADD = libvty.a diff --git a/openbsc/src/gb_proxy.c b/openbsc/src/gb_proxy.c new file mode 100644 index 000000000..77cc8caf9 --- /dev/null +++ b/openbsc/src/gb_proxy.c @@ -0,0 +1,315 @@ +/* NS-over-IP proxy */ + +/* (C) 2010 by Harald Welte + * (C) 2010 by On Waves + * 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 +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +struct gbprox_peer { + struct llist_head list; + + /* NS-VC over which we send/receive data to this BVC */ + struct gprs_nsvc *nsvc; + + /* BVCI used for Point-to-Point to this peer */ + uint16_t bvci; + + /* Routeing Area that this peer is part of (raw 04.08 encoding) */ + uint8_t ra[6]; +}; + +/* Linked list of all Gb peers (except SGSN) */ +static LLIST_HEAD(gbprox_bts_peers); + +/* Pointer to the SGSN peer */ +struct gbprox_peer *gbprox_peer_sgsn; + +/* The NS protocol stack instance we're using */ +extern struct gprs_ns_inst *gbprox_nsi; + +/* Find the gbprox_peer by its BVCI */ +static struct gbprox_peer *peer_by_bvci(uint16_t bvci) +{ + struct gbprox_peer *peer; + llist_for_each_entry(peer, &gbprox_bts_peers, list) { + if (peer->bvci == bvci) + return peer; + } + return NULL; +} + +static struct gbprox_peer *peer_by_nsvc(struct gprs_nsvc *nsvc) +{ + struct gbprox_peer *peer; + llist_for_each_entry(peer, &gbprox_bts_peers, list) { + if (peer->nsvc == nsvc) + return peer; + } + return NULL; +} + +/* look-up a peer by its Routeing Area Code (RAC) */ +static struct gbprox_peer *peer_by_rac(uint8_t *ra) +{ + struct gbprox_peer *peer; + llist_for_each_entry(peer, &gbprox_bts_peers, list) { + if (!memcmp(&peer->ra, ra, 6)) + return peer; + } + return NULL; +} + +/* look-up a peer by its Location Area Code (LAC) */ +static struct gbprox_peer *peer_by_lac(uint8_t *la) +{ + struct gbprox_peer *peer; + llist_for_each_entry(peer, &gbprox_bts_peers, list) { + if (!memcmp(&peer->ra, la, 5)) + return peer; + } + return NULL; +} + +static struct gbprox_peer *peer_alloc(uint16_t bvci) +{ + struct gbprox_peer *peer; + + peer = talloc_zero(tall_bsc_ctx, struct gbprox_peer); + if (!peer) + return NULL; + + peer->bvci = bvci; + llist_add(&peer->list, &gbprox_bts_peers); + + return peer; +} + +static void peer_free(struct gbprox_peer *peer) +{ + llist_del(&peer->list); + talloc_free(peer); +} + +/* feed a message down the NS-VC associated with the specified peer */ +static int gbprox_tx2peer(struct msgb *msg, struct gbprox_peer *peer, + uint16_t ns_bvci) +{ + msgb_bvci(msg) = ns_bvci; + msgb_nsei(msg) = peer->nsvc->nsei; + + return gprs_ns_sendmsg(gbprox_nsi, msg); +} + +/* Send a message to a peer identified by ptp_bvci but using ns_bvci + * in the NS hdr */ +static int gbprox_tx2bvci(struct msgb *msg, uint16_t ptp_bvci, + uint16_t ns_bvci) +{ + struct gbprox_peer *peer; + + peer = peer_by_bvci(ptp_bvci); + if (!peer) + return -ENOENT; + + return gbprox_tx2peer(msg, peer, ns_bvci); +} + +/* Receive an incoming signalling message from a BSS-side NS-VC */ +static int gbprox_rx_sig_from_bss(struct msgb *msg, struct gprs_nsvc *nsvc, + uint16_t ns_bvci) +{ + struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msg->l3h; + struct tlv_parsed tp; + uint8_t pdu_type = bgph->pdu_type; + int data_len = msgb_l3len(msg) - sizeof(*bgph); + struct gbprox_peer *from_peer; + + if (ns_bvci != 0) { + LOGP(DGPRS, LOGL_NOTICE, "BVCI %u not signalling\n", ns_bvci); + return -EINVAL; + } + + /* we actually should never see those two for BVCI == 0, but double-check + * just to make sure */ + if (pdu_type == BSSGP_PDUT_UL_UNITDATA || + pdu_type == BSSGP_PDUT_DL_UNITDATA) { + LOGP(DGPRS, LOGL_NOTICE, "UNITDATA not allowed in signalling\n"); + return -EINVAL; + } + + bssgp_tlv_parse(&tp, bgph->data, data_len); + + switch (pdu_type) { + case BSSGP_PDUT_SUSPEND: + case BSSGP_PDUT_RESUME: + /* RAC snooping for SUSPEND/RESUME */ + if (!TLVP_PRESENT(&tp, BSSGP_IE_ROUTEING_AREA)) + goto err_mand_ie; + from_peer = peer_by_nsvc(nsvc); + if (!from_peer) + goto err_no_peer; + memcpy(&from_peer->ra, TLVP_VAL(&tp, BSSGP_IE_ROUTEING_AREA), + sizeof(&from_peer->ra)); + /* FIXME: This only supports one BSS per RA */ + break; + } + + /* Normally, we can simply pass on all signalling messages from BSS to SGSN */ + return gbprox_tx2peer(msg, gbprox_peer_sgsn, ns_bvci); +err_no_peer: +err_mand_ie: + /* FIXME: do something */ + ; +} + +/* Receive paging request from SGSN, we need to relay to proper BSS */ +static int gbprox_rx_paging(struct msgb *msg, struct tlv_parsed *tp, + struct gprs_nsvc *nsvc, uint16_t ns_bvci) +{ + struct gbprox_peer *peer; + + if (TLVP_PRESENT(tp, BSSGP_IE_BVCI)) { + uint16_t bvci = ntohs(*(uint16_t *)TLVP_VAL(tp, BSSGP_IE_BVCI)); + return gbprox_tx2bvci(msg, bvci, ns_bvci); + } else if (TLVP_PRESENT(tp, BSSGP_IE_ROUTEING_AREA)) { + peer = peer_by_rac(TLVP_VAL(tp, BSSGP_IE_ROUTEING_AREA)); + return gbprox_tx2peer(msg, peer, ns_bvci); + } else if (TLVP_PRESENT(tp, BSSGP_IE_LOCATION_AREA)) { + peer = peer_by_lac(TLVP_VAL(tp, BSSGP_IE_LOCATION_AREA)); + return gbprox_tx2peer(msg, peer, ns_bvci); + } else + return -EINVAL; +} + +/* Receive an incoming signalling message from the SGSN-side NS-VC */ +static int gbprox_rx_sig_from_sgsn(struct msgb *msg, struct gprs_nsvc *nsvc, + uint16_t ns_bvci) +{ + struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msg->l3h; + struct tlv_parsed tp; + uint8_t pdu_type = bgph->pdu_type; + int data_len = msgb_l3len(msg) - sizeof(*bgph); + struct gbprox_peer *peer; + uint16_t bvci; + int rc = 0; + + if (ns_bvci != 0) { + LOGP(DGPRS, LOGL_NOTICE, "BVCI %u not signalling\n", ns_bvci); + return -EINVAL; + } + + /* we actually should never see those two for BVCI == 0, but double-check + * just to make sure */ + if (pdu_type == BSSGP_PDUT_UL_UNITDATA || + pdu_type == BSSGP_PDUT_DL_UNITDATA) { + LOGP(DGPRS, LOGL_NOTICE, "UNITDATA not allowed in signalling\n"); + return -EINVAL; + } + + rc = bssgp_tlv_parse(&tp, bgph->data, data_len); + + switch (pdu_type) { + case BSSGP_PDUT_FLUSH_LL: + case BSSGP_PDUT_BVC_BLOCK_ACK: + case BSSGP_PDUT_BVC_UNBLOCK_ACK: + case BSSGP_PDUT_BVC_RESET: + case BSSGP_PDUT_BVC_RESET_ACK: + /* simple case: BVCI IE is mandatory */ + if (!TLVP_PRESENT(&tp, BSSGP_IE_BVCI)) + goto err_mand_ie; + bvci = ntohs(*(uint16_t *)TLVP_VAL(&tp, BSSGP_IE_BVCI)); + rc = gbprox_tx2bvci(msg, bvci, ns_bvci); + break; + case BSSGP_PDUT_PAGING_PS: + case BSSGP_PDUT_PAGING_CS: + /* process the paging request (LAC/RAC lookup) */ + rc = gbprox_rx_paging(msg, &tp, nsvc, ns_bvci); + break; + case BSSGP_PDUT_STATUS: + /* FIXME: Some exception has occurred */ + LOGP(DGPRS, LOGL_NOTICE, "STATUS not implemented yet\n"); + break; + /* those only exist in the SGSN -> BSS direction */ + case BSSGP_PDUT_SUSPEND_ACK: + case BSSGP_PDUT_SUSPEND_NACK: + case BSSGP_PDUT_RESUME_ACK: + case BSSGP_PDUT_RESUME_NACK: + /* RAC IE is mandatory */ + if (!TLVP_PRESENT(&tp, BSSGP_IE_ROUTEING_AREA)) + goto err_mand_ie; + peer = peer_by_rac(TLVP_VAL(&tp, BSSGP_IE_ROUTEING_AREA)); + if (!peer) + goto err_no_peer; + rc = gbprox_tx2peer(msg, peer, ns_bvci); + break; + case BSSGP_PDUT_SGSN_INVOKE_TRACE: + LOGP(DGPRS, LOGL_ERROR, "SGSN INVOKE TRACE not supported\n"); + break; + default: + DEBUGP(DGPRS, "BSSGP PDU type 0x%02x unknown\n", pdu_type); + break; + } + + return rc; +err_mand_ie: + ; /* FIXME: this would pull gprs_bssgp.c in, which in turn has dependencies */ + //return bssgp_tx_status(BSSGP_CAUSE_MISSING_MAND_IE, NULL, msg); +err_no_peer: + ; /* FIXME */ +} + +/* Main input function for Gb proxy */ +int gbprox_rcvmsg(struct msgb *msg, struct gprs_nsvc *nsvc, uint16_t ns_bvci) +{ + struct gbprox_peer *peer; + + /* Only BVCI=0 messages need special treatment */ + if (ns_bvci == 0 || ns_bvci == 1) { + if (nsvc->remote_end_is_sgsn) + return gbprox_rx_sig_from_sgsn(msg, nsvc, ns_bvci); + else + return gbprox_rx_sig_from_bss(msg, nsvc, ns_bvci); + } + + /* All other BVCI are PTP and thus can be simply forwarded */ + peer = peer_by_bvci(ns_bvci); + if (!peer) { + LOGP(DGPRS, LOGL_ERROR, "Couldn't find peer for BVCI %u\n", ns_bvci); + return -EIO; + } + + return gbprox_tx2peer(msg, peer, ns_bvci); +} diff --git a/openbsc/src/gb_proxy_main.c b/openbsc/src/gb_proxy_main.c new file mode 100644 index 000000000..c624cf8a4 --- /dev/null +++ b/openbsc/src/gb_proxy_main.c @@ -0,0 +1,140 @@ +/* NS-over-IP proxy */ + +/* (C) 2010 by Harald Welte + * (C) 2010 by On Waves + * 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 +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include "../bscconfig.h" + +/* this is here for the vty... it will never be called */ +void subscr_put() { abort(); } + +#define _GNU_SOURCE +#include + +void *tall_bsc_ctx; + +struct gprs_ns_inst *gbprox_nsi; +static u_int16_t nsip_listen_port; + +const char *openbsc_version = "Osmocom NSIP Proxy " PACKAGE_VERSION; +const char *openbsc_copyright = + "Copyright (C) 2010 Harald Welte and On-Waves\n" + "Contributions by Daniel Willmann, Jan Lübbe, Stefan Schmidt\n" + "Dieter Spaar, Andreas Eversberg, Holger Freyther\n\n" + "License GPLv2+: GNU GPL version 2 or later \n" + "This is free software: you are free to change and redistribute it.\n" + "There is NO WARRANTY, to the extent permitted by law.\n"; + +static char *config_file = "nsip_proxy.cfg"; + +/* Pointer to the SGSN peer */ +extern struct gbprox_peer *gbprox_peer_sgsn; + +/* call-back function for the NS protocol */ +static int proxy_ns_cb(enum gprs_ns_evt event, struct gprs_nsvc *nsvc, + struct msgb *msg, u_int16_t bvci) +{ + int rc = 0; + + switch (event) { + case GPRS_NS_EVT_UNIT_DATA: + rc = gbprox_rcvmsg(msg, nsvc, bvci); + break; + default: + LOGP(DGPRS, LOGL_ERROR, "SGSN: Unknown event %u from NS\n", event); + if (msg) + talloc_free(msg); + rc = -EIO; + break; + } + return rc; +} + + +int main(int argc, char **argv) +{ + struct gsm_network dummy_network; + struct log_target *stderr_target; + struct sockaddr_in sin; + int rc; + + tall_bsc_ctx = talloc_named_const(NULL, 0, "nsip_proxy"); + + log_init(&log_info); + stderr_target = log_target_create_stderr(); + log_add_target(stderr_target); + log_set_all_filter(stderr_target, 1); + + telnet_init(&dummy_network, 4244); + + gbprox_nsi = gprs_ns_instantiate(&proxy_ns_cb); + if (!gbprox_nsi) { + LOGP(DGPRS, LOGL_ERROR, "Unable to instantiate NS\n"); + exit(1); + } + nsip_listen(gbprox_nsi, nsip_listen_port); + + /* 'establish' the outgoing connection to the SGSN */ + sin.sin_port = ntohs(23000); + inet_aton("192.168.100.239", &sin.sin_addr); + gbprox_peer_sgsn = nsip_connect(gbprox_nsi, &sin, 2342); + + while (1) { + rc = bsc_select_main(0); + if (rc < 0) + exit(3); + } + + exit(0); +} + +struct gsm_network; +int bsc_vty_init(struct gsm_network *dummy) +{ + cmd_init(1); + vty_init(); + + openbsc_vty_add_cmds(); + //mgcp_vty_init(); + return 0; +} + diff --git a/openbsc/src/gprs_bssgp.c b/openbsc/src/gprs_bssgp.c index 650d7d45d..a2181b124 100644 --- a/openbsc/src/gprs_bssgp.c +++ b/openbsc/src/gprs_bssgp.c @@ -74,11 +74,6 @@ static const char *bssgp_cause_str(enum gprs_bssgp_cause cause) return "undefined"; } -static inline int bssgp_tlv_parse(struct tlv_parsed *tp, u_int8_t *buf, int len) -{ - return tlv_parse(tp, &tvlv_att_def, buf, len, 0, 0); -} - static inline struct msgb *bssgp_msgb_alloc(void) { return msgb_alloc_headroom(4096, 128, "BSSGP"); @@ -120,7 +115,7 @@ static int bssgp_tx_fc_bvc_ack(u_int16_t nsei, u_int8_t tag, u_int16_t ns_bvci) } /* Chapter 10.4.14: Status */ -static int bssgp_tx_status(u_int8_t cause, u_int16_t *bvci, struct msgb *orig_msg) +int bssgp_tx_status(u_int8_t cause, u_int16_t *bvci, struct msgb *orig_msg) { struct msgb *msg = bssgp_msgb_alloc(); struct bssgp_normal_hdr *bgph = diff --git a/openbsc/src/gprs_ns.c b/openbsc/src/gprs_ns.c index 6c495b01e..3bb0bf94d 100644 --- a/openbsc/src/gprs_ns.c +++ b/openbsc/src/gprs_ns.c @@ -72,30 +72,6 @@ static const struct tlv_definition ns_att_tlvdef = { }, }; -#define NSE_S_BLOCKED 0x0001 -#define NSE_S_ALIVE 0x0002 - -struct gprs_nsvc { - struct llist_head list; - struct gprs_ns_inst *nsi; - - u_int16_t nsei; /* end-to-end significance */ - u_int16_t nsvci; /* uniquely identifies NS-VC at SGSN */ - - u_int32_t state; - u_int32_t remote_state; - - struct timer_list alive_timer; - int timer_is_tns_alive; - int alive_retries; - - union { - struct { - struct sockaddr_in bts_addr; - } ip; - }; -}; - enum gprs_ns_ll { GPRS_NS_LL_UDP, GPRS_NS_LL_E1, @@ -474,7 +450,7 @@ struct gprs_ns_inst *gprs_ns_instantiate(gprs_ns_cb_t *cb) nsi->cb = cb; INIT_LLIST_HEAD(&nsi->gprs_nsvcs); - return NULL; + return nsi; } void gprs_ns_destroy(struct gprs_ns_inst *nsi) @@ -586,3 +562,24 @@ int nsip_listen(struct gprs_ns_inst *nsi, uint16_t udp_port) return ret; } + +/* Establish a connection (from the BSS) to the SGSN */ +struct gprs_nsvc *nsip_connect(struct gprs_ns_inst *nsi, + struct sockaddr_in *dest, uint16_t nsvci) +{ + struct gprs_nsvc *nsvc; + + nsvc = nsvc_by_rem_addr(nsi, dest); + if (!nsvc) { + nsvc = nsvc_create(nsi, nsvci); + nsvc->ip.bts_addr = *dest; + } + nsvc->remote_end_is_sgsn = 1; + + /* Initiate a RESET procedure */ + if (gprs_ns_tx_simple(nsvc, NS_PDUT_RESET) < 0) + return NULL; + /* FIXME: should we run a timer and re-transmit the reset request? */ + + return nsvc; +} diff --git a/openbsc/src/input/ipaccess.c b/openbsc/src/input/ipaccess.c index 2b5bf21a6..721cadd23 100644 --- a/openbsc/src/input/ipaccess.c +++ b/openbsc/src/input/ipaccess.c @@ -707,58 +707,6 @@ static int rsl_listen_fd_cb(struct bsc_fd *listen_bfd, unsigned int what) return 0; } -int make_sock(struct bsc_fd *bfd, int proto, u_int16_t port, - int (*cb)(struct bsc_fd *fd, unsigned int what)) -{ - struct sockaddr_in addr; - int ret, on = 1; - int type = SOCK_STREAM; - - if (proto == IPPROTO_UDP) - type = SOCK_DGRAM; - - bfd->fd = socket(AF_INET, type, proto); - bfd->cb = cb; - bfd->when = BSC_FD_READ; - //bfd->data = line; - - if (bfd->fd < 0) { - LOGP(DINP, LOGL_ERROR, "could not create TCP socket.\n"); - return -EIO; - } - - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_port = htons(port); - addr.sin_addr.s_addr = INADDR_ANY; - - setsockopt(bfd->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); - - ret = bind(bfd->fd, (struct sockaddr *) &addr, sizeof(addr)); - if (ret < 0) { - LOGP(DINP, LOGL_ERROR, "could not bind l2 socket %s\n", - strerror(errno)); - close(bfd->fd); - return -EIO; - } - - if (proto != IPPROTO_UDP) { - ret = listen(bfd->fd, 1); - if (ret < 0) { - perror("listen"); - return ret; - } - } - - ret = bsc_register_fd(bfd); - if (ret < 0) { - perror("register_listen_fd"); - close(bfd->fd); - return ret; - } - return 0; -} - /* Actively connect to a BTS. Currently used by ipaccess-config.c */ int ipaccess_connect(struct e1inp_line *line, struct sockaddr_in *sa) { diff --git a/openbsc/src/socket.c b/openbsc/src/socket.c new file mode 100644 index 000000000..3ed4d425a --- /dev/null +++ b/openbsc/src/socket.c @@ -0,0 +1,94 @@ +/* OpenBSC sokcet code, taken from Abis input driver for ip.access */ + +/* (C) 2009 by Harald Welte + * (C) 2010 by Holger Hans Peter Freyther + * (C) 2010 by On-Waves + * + * 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 +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +int make_sock(struct bsc_fd *bfd, int proto, u_int16_t port, + int (*cb)(struct bsc_fd *fd, unsigned int what)) +{ + struct sockaddr_in addr; + int ret, on = 1; + int type = SOCK_STREAM; + + if (proto == IPPROTO_UDP) + type = SOCK_DGRAM; + + bfd->fd = socket(AF_INET, type, proto); + bfd->cb = cb; + bfd->when = BSC_FD_READ; + //bfd->data = line; + + if (bfd->fd < 0) { + LOGP(DINP, LOGL_ERROR, "could not create TCP socket.\n"); + return -EIO; + } + + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + addr.sin_addr.s_addr = INADDR_ANY; + + setsockopt(bfd->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); + + ret = bind(bfd->fd, (struct sockaddr *) &addr, sizeof(addr)); + if (ret < 0) { + LOGP(DINP, LOGL_ERROR, "could not bind l2 socket %s\n", + strerror(errno)); + close(bfd->fd); + return -EIO; + } + + if (proto != IPPROTO_UDP) { + ret = listen(bfd->fd, 1); + if (ret < 0) { + perror("listen"); + return ret; + } + } + + ret = bsc_register_fd(bfd); + if (ret < 0) { + perror("register_listen_fd"); + close(bfd->fd); + return ret; + } + return 0; +} -- cgit v1.2.3 From 7b8255c52d440fc8c802e58a21815473cf2fd3be Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Fri, 30 Apr 2010 20:42:42 +0200 Subject: gb_proxy: listen on UDP port 23000, use AF_INET --- openbsc/src/gb_proxy_main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openbsc/src/gb_proxy_main.c b/openbsc/src/gb_proxy_main.c index c624cf8a4..7ef613f24 100644 --- a/openbsc/src/gb_proxy_main.c +++ b/openbsc/src/gb_proxy_main.c @@ -53,7 +53,7 @@ void subscr_put() { abort(); } void *tall_bsc_ctx; struct gprs_ns_inst *gbprox_nsi; -static u_int16_t nsip_listen_port; +static u_int16_t nsip_listen_port = 23000; const char *openbsc_version = "Osmocom NSIP Proxy " PACKAGE_VERSION; const char *openbsc_copyright = @@ -114,6 +114,7 @@ int main(int argc, char **argv) nsip_listen(gbprox_nsi, nsip_listen_port); /* 'establish' the outgoing connection to the SGSN */ + sin.sin_family = AF_INET; sin.sin_port = ntohs(23000); inet_aton("192.168.100.239", &sin.sin_addr); gbprox_peer_sgsn = nsip_connect(gbprox_nsi, &sin, 2342); -- cgit v1.2.3 From a977b3d1ee392e2c3714a5564bc0cec06b75a89d Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Fri, 30 Apr 2010 21:14:05 +0200 Subject: gbproxy: add VTY node --- openbsc/include/vty/command.h | 1 + openbsc/src/vty/command.c | 1 + 2 files changed, 2 insertions(+) diff --git a/openbsc/include/vty/command.h b/openbsc/include/vty/command.h index 738cce4f1..35e1b299c 100644 --- a/openbsc/include/vty/command.h +++ b/openbsc/include/vty/command.h @@ -107,6 +107,7 @@ enum node_type { TS_NODE, SUBSCR_NODE, MGCP_NODE, + GBPROXY_NODE, }; /* Node which has some commands and prompt string and configuration diff --git a/openbsc/src/vty/command.c b/openbsc/src/vty/command.c index 278d980e9..62144eeb6 100644 --- a/openbsc/src/vty/command.c +++ b/openbsc/src/vty/command.c @@ -2363,6 +2363,7 @@ gDEFUN(config_exit, vty->node = CONFIG_NODE; break; case MGCP_NODE: + case GBPROXY_NODE: vty->node = CONFIG_NODE; vty->index = NULL; default: -- cgit v1.2.3 From 799e0c92c640db7e0418cc90eff6326898c1e147 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Fri, 30 Apr 2010 21:49:24 +0200 Subject: gb_proxy: Add initial VTY configuration code --- openbsc/src/Makefile.am | 2 +- openbsc/src/gb_proxy_main.c | 2 +- openbsc/src/gb_proxy_vty.c | 201 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 203 insertions(+), 2 deletions(-) create mode 100644 openbsc/src/gb_proxy_vty.c diff --git a/openbsc/src/Makefile.am b/openbsc/src/Makefile.am index ac418707a..25d34ac31 100644 --- a/openbsc/src/Makefile.am +++ b/openbsc/src/Makefile.am @@ -51,7 +51,7 @@ bsc_mgcp_LDADD = libvty.a ipaccess_proxy_SOURCES = ipaccess/ipaccess-proxy.c debug.c -osmo_gb_proxy_SOURCES = gb_proxy.c gb_proxy_main.c \ +osmo_gb_proxy_SOURCES = gb_proxy.c gb_proxy_main.c gb_proxy_vty.c \ gprs_ns.c \ socket.c debug.c telnet_interface.c vty_interface_cmds.c osmo_gb_proxy_LDADD = libvty.a diff --git a/openbsc/src/gb_proxy_main.c b/openbsc/src/gb_proxy_main.c index 7ef613f24..1793757fb 100644 --- a/openbsc/src/gb_proxy_main.c +++ b/openbsc/src/gb_proxy_main.c @@ -135,7 +135,7 @@ int bsc_vty_init(struct gsm_network *dummy) vty_init(); openbsc_vty_add_cmds(); - //mgcp_vty_init(); + gbproxy_vty_init(); return 0; } diff --git a/openbsc/src/gb_proxy_vty.c b/openbsc/src/gb_proxy_vty.c new file mode 100644 index 000000000..ae6be5e4b --- /dev/null +++ b/openbsc/src/gb_proxy_vty.c @@ -0,0 +1,201 @@ +/* + * (C) 2010 by Harald Welte + * (C) 2010 by On-Waves + * 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 + +#include +#include + +struct gbproxy_config { + u_int32_t nsip_listen_ip; + u_int16_t nsip_listen_port; + + u_int32_t nsip_sgsn_ip; + u_int16_t nsip_sgsn_port; + + u_int16_t nsip_sgsn_nsei; + u_int16_t nsip_sgsn_nsvci; +}; + +static struct gbproxy_config *g_cfg = NULL; + +/* + * vty code for mgcp below + */ +struct cmd_node gbproxy_node = { + GBPROXY_NODE, + "%s(gbproxy)#", + 1, +}; + +static int config_write_gbproxy(struct vty *vty) +{ + struct in_addr ia; + + vty_out(vty, "gbproxy%s", VTY_NEWLINE); + + if (g_cfg->nsip_listen_ip) { + ia.s_addr = htonl(g_cfg->nsip_listen_ip); + vty_out(vty, " nsip bss local ip %s%s", inet_ntoa(ia), + VTY_NEWLINE); + } + vty_out(vty, " nsip bss local port %u%s", g_cfg->nsip_listen_port, + VTY_NEWLINE); + ia.s_addr = htonl(g_cfg->nsip_sgsn_ip); + vty_out(vty, " nsip sgsn remote ip %s%s", inet_ntoa(ia), + VTY_NEWLINE); + vty_out(vty, " nsip sgsn remote port %u%s", g_cfg->nsip_sgsn_port, + VTY_NEWLINE); + vty_out(vty, " nsip sgsn nsei %u%s", g_cfg->nsip_sgsn_nsei, + VTY_NEWLINE); + vty_out(vty, " nsip sgsn nsvci %u%s", g_cfg->nsip_sgsn_nsvci, + VTY_NEWLINE); + + return CMD_SUCCESS; +} + +DEFUN(show_gbproxy, show_gbproxy_cmd, "show gbproxy", + SHOW_STR "Display information about the Gb proxy") +{ + /* FIXME: iterate over list of NS-VC's and display their state */ + + return CMD_SUCCESS; +} + +DEFUN(cfg_gbproxy, + cfg_gbproxy_cmd, + "gbproxy", + "Configure the Gb proxy") +{ + vty->node = GBPROXY_NODE; + return CMD_SUCCESS; +} + +DEFUN(cfg_nsip_bss_local_ip, + cfg_nsip_bss_local_ip_cmd, + "nsip bss local ip A.B.C.D", + "Set the IP address on which we listen for BSS connects") +{ + struct in_addr ia; + + inet_aton(argv[0], &ia); + g_cfg->nsip_listen_ip = ntohl(ia.s_addr); + + return CMD_SUCCESS; +} + +DEFUN(cfg_nsip_bss_local_port, + cfg_nsip_bss_local_port_cmd, + "nsip bss local port <0-65534>", + "Set the UDP port on which we listen for BSS connects") +{ + unsigned int port = atoi(argv[0]); + + g_cfg->nsip_listen_port = port; + return CMD_SUCCESS; +} + + +DEFUN(cfg_nsip_sgsn_ip, + cfg_nsip_sgsn_ip_cmd, + "nsip sgsn remote ip A.B.C.D", + "Set the IP of the SGSN to which the proxy shall connect") +{ + struct in_addr ia; + + inet_aton(argv[0], &ia); + g_cfg->nsip_sgsn_ip = ntohl(ia.s_addr); + + return CMD_SUCCESS; +} + +DEFUN(cfg_nsip_sgsn_port, + cfg_nsip_sgsn_port_cmd, + "nsip sgsn remote port <0-65534>", + "Set the UDP port of the SGSN to which the proxy shall connect") +{ + unsigned int port = atoi(argv[0]); + + g_cfg->nsip_sgsn_port = port; + return CMD_SUCCESS; +} + +DEFUN(cfg_nsip_sgsn_nsei, + cfg_nsip_sgsn_nsei_cmd, + "nsip sgsn nsei <0-65534>", + "Set the NSEI to be used in the connection with the SGSN") +{ + unsigned int port = atoi(argv[0]); + + g_cfg->nsip_sgsn_nsei = port; + return CMD_SUCCESS; +} + +DEFUN(cfg_nsip_sgsn_nsvci, + cfg_nsip_sgsn_nsvci_cmd, + "nsip sgsn nsvci <0-65534>", + "Set the NSVCI to be used in the connection with the SGSN") +{ + unsigned int port = atoi(argv[0]); + + g_cfg->nsip_sgsn_nsvci = port; + return CMD_SUCCESS; +} + + +int gbproxy_vty_init(void) +{ + install_element(VIEW_NODE, &show_gbproxy_cmd); + + install_element(CONFIG_NODE, &cfg_gbproxy_cmd); + install_node(&gbproxy_node, config_write_gbproxy); + install_default(GBPROXY_NODE); + install_element(GBPROXY_NODE, &cfg_nsip_bss_local_ip_cmd); + install_element(GBPROXY_NODE, &cfg_nsip_bss_local_port_cmd); + install_element(GBPROXY_NODE, &cfg_nsip_sgsn_ip_cmd); + install_element(GBPROXY_NODE, &cfg_nsip_sgsn_port_cmd); + install_element(GBPROXY_NODE, &cfg_nsip_sgsn_nsei_cmd); + install_element(GBPROXY_NODE, &cfg_nsip_sgsn_nsvci_cmd); + + return 0; +} + +int gbproxy_parse_config(const char *config_file, struct gbproxy_config *cfg) +{ + int rc; + + g_cfg = cfg; + rc = vty_read_config_file(config_file); + if (rc < 0) { + fprintf(stderr, "Failed to parse the config file: '%s'\n", config_file); + return rc; + } + + return 0; +} + -- cgit v1.2.3 From b77c697c0b86a17870da5dda8f0f17007f5e35b4 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 1 May 2010 11:28:43 +0200 Subject: [gprs] fully integrate VTY configuration into Gb proxy The Gb-proxy is now fully configured by config file / VTY --- openbsc/include/openbsc/gb_proxy.h | 37 ++++++++++++++++++++++++++++ openbsc/include/openbsc/gprs_ns.h | 49 +++++++++++++++++++++++++++++--------- openbsc/src/gb_proxy_main.c | 21 +++++++++++----- openbsc/src/gb_proxy_vty.c | 30 +++++++++++++---------- openbsc/src/gprs_ns.c | 29 ++++------------------ 5 files changed, 112 insertions(+), 54 deletions(-) create mode 100644 openbsc/include/openbsc/gb_proxy.h diff --git a/openbsc/include/openbsc/gb_proxy.h b/openbsc/include/openbsc/gb_proxy.h new file mode 100644 index 000000000..8194d2a8b --- /dev/null +++ b/openbsc/include/openbsc/gb_proxy.h @@ -0,0 +1,37 @@ +#ifndef _GB_PROXY_H +#define _GB_PROXY_H + +#include + +#include + +#include + +struct gbproxy_config { + /* parsed from config file */ + u_int32_t nsip_listen_ip; + u_int16_t nsip_listen_port; + + u_int32_t nsip_sgsn_ip; + u_int16_t nsip_sgsn_port; + + u_int16_t nsip_sgsn_nsei; + u_int16_t nsip_sgsn_nsvci; + + /* misc */ + struct gprs_ns_inst *nsi; +}; + + +/* gb_proxy_vty .c */ + +int gbproxy_vty_init(void); +int gbproxy_parse_config(const char *config_file, struct gbproxy_config *cfg); + + +/* gb_proxy.c */ + +/* Main input function for Gb proxy */ +int gbprox_rcvmsg(struct msgb *msg, struct gprs_nsvc *nsvc, uint16_t ns_bvci); + +#endif diff --git a/openbsc/include/openbsc/gprs_ns.h b/openbsc/include/openbsc/gprs_ns.h index dd10d3339..ca02c4b5d 100644 --- a/openbsc/include/openbsc/gprs_ns.h +++ b/openbsc/include/openbsc/gprs_ns.h @@ -76,10 +76,46 @@ enum ns_cause { /* Our Implementation */ #include +#include +#include +#include +#include #define NSE_S_BLOCKED 0x0001 #define NSE_S_ALIVE 0x0002 +enum gprs_ns_ll { + GPRS_NS_LL_UDP, + GPRS_NS_LL_E1, +}; + +enum gprs_ns_evt { + GPRS_NS_EVT_UNIT_DATA, +}; + +struct gprs_nsvc; +typedef int gprs_ns_cb_t(enum gprs_ns_evt event, struct gprs_nsvc *nsvc, + struct msgb *msg, u_int16_t bvci); + +/* An instance of the NS protocol stack */ +struct gprs_ns_inst { + /* callback to the user for incoming UNIT DATA IND */ + gprs_ns_cb_t *cb; + + /* linked lists of all NSVC in this instance */ + struct llist_head gprs_nsvcs; + + /* which link-layer are we based on? */ + enum gprs_ns_ll ll; + + union { + /* NS-over-IP specific bits */ + struct { + struct bsc_fd fd; + } nsip; + }; +}; + struct gprs_nsvc { struct llist_head list; struct gprs_ns_inst *nsi; @@ -103,16 +139,6 @@ struct gprs_nsvc { }; }; - -struct gprs_ns_inst; - -enum gprs_ns_evt { - GPRS_NS_EVT_UNIT_DATA, -}; - -typedef int gprs_ns_cb_t(enum gprs_ns_evt event, struct gprs_nsvc *nsvc, - struct msgb *msg, u_int16_t bvci); - /* Create a new NS protocol instance */ struct gprs_ns_inst *gprs_ns_instantiate(gprs_ns_cb_t *cb); @@ -137,5 +163,6 @@ int nsip_listen(struct gprs_ns_inst *nsi, uint16_t udp_port); /* Establish a connection (from the BSS) to the SGSN */ struct gprs_nsvc *nsip_connect(struct gprs_ns_inst *nsi, - struct sockaddr_in *dest, uint16_t nsvci); + struct sockaddr_in *dest, uint16_t nsei, + uint16_t nsvci); #endif diff --git a/openbsc/src/gb_proxy_main.c b/openbsc/src/gb_proxy_main.c index 1793757fb..8f0306091 100644 --- a/openbsc/src/gb_proxy_main.c +++ b/openbsc/src/gb_proxy_main.c @@ -41,6 +41,7 @@ #include #include #include +#include #include "../bscconfig.h" @@ -53,7 +54,6 @@ void subscr_put() { abort(); } void *tall_bsc_ctx; struct gprs_ns_inst *gbprox_nsi; -static u_int16_t nsip_listen_port = 23000; const char *openbsc_version = "Osmocom NSIP Proxy " PACKAGE_VERSION; const char *openbsc_copyright = @@ -64,7 +64,8 @@ const char *openbsc_copyright = "This is free software: you are free to change and redistribute it.\n" "There is NO WARRANTY, to the extent permitted by law.\n"; -static char *config_file = "nsip_proxy.cfg"; +static char *config_file = "gb_proxy.cfg"; +static struct gbproxy_config gbcfg; /* Pointer to the SGSN peer */ extern struct gbprox_peer *gbprox_peer_sgsn; @@ -105,19 +106,27 @@ int main(int argc, char **argv) log_set_all_filter(stderr_target, 1); telnet_init(&dummy_network, 4244); + rc = gbproxy_parse_config(config_file, &gbcfg); + if (rc < 0) { + LOGP(DGPRS, LOGL_FATAL, "Cannot parse config file\n"); + exit(2); + } gbprox_nsi = gprs_ns_instantiate(&proxy_ns_cb); if (!gbprox_nsi) { LOGP(DGPRS, LOGL_ERROR, "Unable to instantiate NS\n"); exit(1); } - nsip_listen(gbprox_nsi, nsip_listen_port); + gbcfg.nsi = gbprox_nsi; + nsip_listen(gbprox_nsi, gbcfg.nsip_listen_port); /* 'establish' the outgoing connection to the SGSN */ sin.sin_family = AF_INET; - sin.sin_port = ntohs(23000); - inet_aton("192.168.100.239", &sin.sin_addr); - gbprox_peer_sgsn = nsip_connect(gbprox_nsi, &sin, 2342); + sin.sin_port = htons(gbcfg.nsip_sgsn_port); + sin.sin_addr.s_addr = htonl(gbcfg.nsip_sgsn_ip); + gbprox_peer_sgsn = nsip_connect(gbprox_nsi, &sin, + gbcfg.nsip_sgsn_nsei, + gbcfg.nsip_sgsn_nsvci); while (1) { rc = bsc_select_main(0); diff --git a/openbsc/src/gb_proxy_vty.c b/openbsc/src/gb_proxy_vty.c index ae6be5e4b..16f6a1e0e 100644 --- a/openbsc/src/gb_proxy_vty.c +++ b/openbsc/src/gb_proxy_vty.c @@ -27,27 +27,18 @@ #include #include +#include +#include #include #include -struct gbproxy_config { - u_int32_t nsip_listen_ip; - u_int16_t nsip_listen_port; - - u_int32_t nsip_sgsn_ip; - u_int16_t nsip_sgsn_port; - - u_int16_t nsip_sgsn_nsei; - u_int16_t nsip_sgsn_nsvci; -}; - static struct gbproxy_config *g_cfg = NULL; /* * vty code for mgcp below */ -struct cmd_node gbproxy_node = { +static struct cmd_node gbproxy_node = { GBPROXY_NODE, "%s(gbproxy)#", 1, @@ -83,6 +74,21 @@ DEFUN(show_gbproxy, show_gbproxy_cmd, "show gbproxy", SHOW_STR "Display information about the Gb proxy") { /* FIXME: iterate over list of NS-VC's and display their state */ + struct gprs_ns_inst *nsi = g_cfg->nsi; + struct gprs_nsvc *nsvc; + + llist_for_each_entry(nsvc, &nsi->gprs_nsvcs, list) { + vty_out(vty, "NSEI %5u, NS-VC %5u, %s-mode, %s %s%s", + nsvc->nsei, nsvc->nsvci, + nsvc->remote_end_is_sgsn ? "BSS" : "SGSN", + nsvc->state & NSE_S_ALIVE ? "ALIVE" : "DEAD", + nsvc->state & NSE_S_BLOCKED ? "BLOCKED" : "UNBLOCKED", + VTY_NEWLINE); + if (nsvc->nsi->ll == GPRS_NS_LL_UDP) + vty_out(vty, " remote peer %s:%u%s", + inet_ntoa(nsvc->ip.bts_addr.sin_addr), + ntohs(nsvc->ip.bts_addr.sin_port), VTY_NEWLINE); + } return CMD_SUCCESS; } diff --git a/openbsc/src/gprs_ns.c b/openbsc/src/gprs_ns.c index 3bb0bf94d..18d189f5a 100644 --- a/openbsc/src/gprs_ns.c +++ b/openbsc/src/gprs_ns.c @@ -72,30 +72,6 @@ static const struct tlv_definition ns_att_tlvdef = { }, }; -enum gprs_ns_ll { - GPRS_NS_LL_UDP, - GPRS_NS_LL_E1, -}; - -/* An instance of the NS protocol stack */ -struct gprs_ns_inst { - /* callback to the user for incoming UNIT DATA IND */ - gprs_ns_cb_t *cb; - - /* linked lists of all NSVC in this instance */ - struct llist_head gprs_nsvcs; - - /* which link-layer are we based on? */ - enum gprs_ns_ll ll; - - union { - /* NS-over-IP specific bits */ - struct { - struct bsc_fd fd; - } nsip; - }; -}; - /* Lookup struct gprs_nsvc based on NSVCI */ static struct gprs_nsvc *nsvc_by_nsvci(struct gprs_ns_inst *nsi, u_int16_t nsvci) @@ -565,7 +541,8 @@ int nsip_listen(struct gprs_ns_inst *nsi, uint16_t udp_port) /* Establish a connection (from the BSS) to the SGSN */ struct gprs_nsvc *nsip_connect(struct gprs_ns_inst *nsi, - struct sockaddr_in *dest, uint16_t nsvci) + struct sockaddr_in *dest, uint16_t nsei, + uint16_t nsvci) { struct gprs_nsvc *nsvc; @@ -574,6 +551,8 @@ struct gprs_nsvc *nsip_connect(struct gprs_ns_inst *nsi, nsvc = nsvc_create(nsi, nsvci); nsvc->ip.bts_addr = *dest; } + nsvc->nsei = nsei; + nsvc->nsvci = nsvci; nsvc->remote_end_is_sgsn = 1; /* Initiate a RESET procedure */ -- cgit v1.2.3 From 79fc392751b9551abd3dae702ce28318fa48d637 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 1 May 2010 11:59:10 +0200 Subject: move gsm48_parse_ra() and gprs_tlli_type() to libosmocore --- openbsc/include/openbsc/gsm_04_08_gprs.h | 16 -------------- openbsc/src/gsm_04_08_gprs.c | 36 -------------------------------- 2 files changed, 52 deletions(-) diff --git a/openbsc/include/openbsc/gsm_04_08_gprs.h b/openbsc/include/openbsc/gsm_04_08_gprs.h index 20ab04432..afc5abc93 100644 --- a/openbsc/include/openbsc/gsm_04_08_gprs.h +++ b/openbsc/include/openbsc/gsm_04_08_gprs.h @@ -72,13 +72,6 @@ enum gsm48_gprs_ie_sm { GSM48_IE_GSM_LSA_ID = 0x48, /* 10.5.3.11 */ }; -/* Chapter 10.4.4.15 */ -struct gsm48_ra_id { - u_int8_t digits[3]; /* MCC + MNC BCD digits */ - u_int16_t lac; /* Location Area Code */ - u_int8_t rac; /* Routing Area Code */ -} __attribute__ ((packed)); - /* Chapter 9.4.15 / Table 9.4.15 */ struct gsm48_ra_upd_ack { u_int8_t force_stby:4, /* 10.5.5.7 */ @@ -177,15 +170,6 @@ enum gsm48_gsm_cause { GSM_CAUSE_PROTO_ERR_UNSPEC = 0x6f, }; -/* GSM TS 03.03 Chapter 2.6 */ -enum gprs_tlli_tyoe { - TLLI_LOCAL, - TLLI_FOREIGN, - TLLI_RANDOM, - TLLI_AUXILIARY, - TLLI_RESERVED, -}; - /* Section 6.1.2.2: Session management states on the network side */ enum gsm48_pdp_state { PDP_S_INACTIVE, diff --git a/openbsc/src/gsm_04_08_gprs.c b/openbsc/src/gsm_04_08_gprs.c index 150322872..ffc3303a3 100644 --- a/openbsc/src/gsm_04_08_gprs.c +++ b/openbsc/src/gsm_04_08_gprs.c @@ -126,48 +126,12 @@ static const char *upd_name(u_int8_t type) return "unknown"; } -void gsm48_parse_ra(struct gprs_ra_id *raid, const u_int8_t *buf) -{ - raid->mcc = (buf[0] & 0xf) * 100; - raid->mcc += (buf[0] >> 4) * 10; - raid->mcc += (buf[1] & 0xf) * 1; - - /* I wonder who came up with the stupidity of encoding the MNC - * differently depending on how many digits its decimal number has! */ - if ((buf[1] >> 4) == 0xf) { - raid->mnc = (buf[2] & 0xf) * 10; - raid->mnc += (buf[2] >> 4) * 1; - } else { - raid->mnc = (buf[2] & 0xf) * 100; - raid->mnc += (buf[2] >> 4) * 10; - raid->mnc += (buf[1] >> 4) * 1; - } - - raid->lac = ntohs(*(u_int16_t *)(buf + 3)); - raid->rac = buf[5]; -} - /* Send a message through the underlying layer */ static int gsm48_gmm_sendmsg(struct msgb *msg, int command) { return gprs_llc_tx_ui(msg, GPRS_SAPI_GMM, command); } -/* TS 03.03 Chapter 2.6 */ -int gprs_tlli_type(u_int32_t tlli) -{ - if ((tlli & 0xc0000000) == 0xc0000000) - return TLLI_LOCAL; - else if ((tlli & 0xc0000000) == 0x80000000) - return TLLI_FOREIGN; - else if ((tlli & 0xf8000000) == 0x78000000) - return TLLI_RANDOM; - else if ((tlli & 0xf8000000) == 0x70000000) - return TLLI_AUXILIARY; - - return TLLI_RESERVED; -} - /* Chapter 9.4.2: Attach accept */ static int gsm48_tx_gmm_att_ack(struct msgb *old_msg) { -- cgit v1.2.3 From 70f38d2a3b24d053e98e6c11e086b784662df88f Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 1 May 2010 12:10:57 +0200 Subject: [gprs] gb_proxy: Actually create our gbprox_peers also extend the logging verbosity and fix some compiler warnings --- openbsc/src/gb_proxy.c | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/openbsc/src/gb_proxy.c b/openbsc/src/gb_proxy.c index 77cc8caf9..a9aa7549c 100644 --- a/openbsc/src/gb_proxy.c +++ b/openbsc/src/gb_proxy.c @@ -82,7 +82,7 @@ static struct gbprox_peer *peer_by_nsvc(struct gprs_nsvc *nsvc) } /* look-up a peer by its Routeing Area Code (RAC) */ -static struct gbprox_peer *peer_by_rac(uint8_t *ra) +static struct gbprox_peer *peer_by_rac(const uint8_t *ra) { struct gbprox_peer *peer; llist_for_each_entry(peer, &gbprox_bts_peers, list) { @@ -93,7 +93,7 @@ static struct gbprox_peer *peer_by_rac(uint8_t *ra) } /* look-up a peer by its Location Area Code (LAC) */ -static struct gbprox_peer *peer_by_lac(uint8_t *la) +static struct gbprox_peer *peer_by_lac(const uint8_t *la) { struct gbprox_peer *peer; llist_for_each_entry(peer, &gbprox_bts_peers, list) { @@ -156,9 +156,10 @@ static int gbprox_rx_sig_from_bss(struct msgb *msg, struct gprs_nsvc *nsvc, uint8_t pdu_type = bgph->pdu_type; int data_len = msgb_l3len(msg) - sizeof(*bgph); struct gbprox_peer *from_peer; + struct gprs_ra_id raid; if (ns_bvci != 0) { - LOGP(DGPRS, LOGL_NOTICE, "BVCI %u not signalling\n", ns_bvci); + LOGP(DGPRS, LOGL_NOTICE, "BVCI %u is not signalling\n", ns_bvci); return -EINVAL; } @@ -175,7 +176,11 @@ static int gbprox_rx_sig_from_bss(struct msgb *msg, struct gprs_nsvc *nsvc, switch (pdu_type) { case BSSGP_PDUT_SUSPEND: case BSSGP_PDUT_RESUME: - /* RAC snooping for SUSPEND/RESUME */ + /* We implement RAC snooping during SUSPEND/RESUME, since + * it establishes a relationsip between BVCI/peer and the + * routeing area code. The snooped information is then + * used for routing the {SUSPEND,RESUME}_[N]ACK back to + * the correct BSSGP */ if (!TLVP_PRESENT(&tp, BSSGP_IE_ROUTEING_AREA)) goto err_mand_ie; from_peer = peer_by_nsvc(nsvc); @@ -183,6 +188,10 @@ static int gbprox_rx_sig_from_bss(struct msgb *msg, struct gprs_nsvc *nsvc, goto err_no_peer; memcpy(&from_peer->ra, TLVP_VAL(&tp, BSSGP_IE_ROUTEING_AREA), sizeof(&from_peer->ra)); + gsm48_parse_ra(&raid, &from_peer->ra); + DEBUGP(DGPRS, "RAC snooping: RAC %u/%u/%u/%u behind BVCI=%u, " + "NSVCI=%u, NSEI=%u\n", raid.mcc, raid.mnc, raid.lac, + raid.rac , from_peer->bvci, nsvc->nsvci, nsvc->nsei); /* FIXME: This only supports one BSS per RA */ break; } @@ -227,7 +236,7 @@ static int gbprox_rx_sig_from_sgsn(struct msgb *msg, struct gprs_nsvc *nsvc, int rc = 0; if (ns_bvci != 0) { - LOGP(DGPRS, LOGL_NOTICE, "BVCI %u not signalling\n", ns_bvci); + LOGP(DGPRS, LOGL_NOTICE, "BVCI %u is not signalling\n", ns_bvci); return -EINVAL; } @@ -307,8 +316,19 @@ int gbprox_rcvmsg(struct msgb *msg, struct gprs_nsvc *nsvc, uint16_t ns_bvci) /* All other BVCI are PTP and thus can be simply forwarded */ peer = peer_by_bvci(ns_bvci); if (!peer) { - LOGP(DGPRS, LOGL_ERROR, "Couldn't find peer for BVCI %u\n", ns_bvci); - return -EIO; + if (!nsvc->remote_end_is_sgsn) { + LOGP(DGPRS, LOGL_NOTICE, "Allocationg new peer for " + "BVCI=%u via NSVC=%u/NSEI=%u\n", ns_bvci, + nsvc->nsvci, nsvc->nsei); + peer = peer_alloc(ns_bvci); + peer->nsvc = nsvc; + } else { + LOGP(DGPRS, LOGL_ERROR, "Couldn't find peer for " + "BVCI %u\n", ns_bvci); + /* FIXME: do we really have to free the message here? */ + msgb_free(msg); + return -EIO; + } } return gbprox_tx2peer(msg, peer, ns_bvci); -- cgit v1.2.3 From 169a00403f6452359a0cb1e3f3f77470daba2a91 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 1 May 2010 14:04:58 +0200 Subject: [gprs] Makefile reorganization We don't need to explicitly link telnet_interface.c and vty_interface_cmds.c as they're now part of libvty.a --- openbsc/src/Makefile.am | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/openbsc/src/Makefile.am b/openbsc/src/Makefile.am index 25d34ac31..6e4e506ff 100644 --- a/openbsc/src/Makefile.am +++ b/openbsc/src/Makefile.am @@ -52,6 +52,5 @@ bsc_mgcp_LDADD = libvty.a ipaccess_proxy_SOURCES = ipaccess/ipaccess-proxy.c debug.c osmo_gb_proxy_SOURCES = gb_proxy.c gb_proxy_main.c gb_proxy_vty.c \ - gprs_ns.c \ - socket.c debug.c telnet_interface.c vty_interface_cmds.c + gprs_ns.c socket.c debug.c osmo_gb_proxy_LDADD = libvty.a -- cgit v1.2.3 From f533e13c14905ec140646e85b155988c1b33b9fd Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 1 May 2010 16:45:46 +0200 Subject: [gprs] add some Iu specific SGSN MM state fields --- openbsc/include/openbsc/gprs_sgsn.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/openbsc/include/openbsc/gprs_sgsn.h b/openbsc/include/openbsc/gprs_sgsn.h index 87c7fa874..92ce34d42 100644 --- a/openbsc/include/openbsc/gprs_sgsn.h +++ b/openbsc/include/openbsc/gprs_sgsn.h @@ -19,6 +19,7 @@ enum gprs_ciph_algo { #define MS_RADIO_ACCESS_CAPA /* According to TS 03.60, Table 5: SGSN MM and PDP Contexts */ +/* Extended by 3GPP TS 23.060, Table 6: SGSN MM and PDP Contexts */ struct sgsn_mm_ctx { struct llist_head list; @@ -27,14 +28,18 @@ struct sgsn_mm_ctx { u_int32_t p_tmsi; u_int32_t p_tmsi_sig; char imei[GSM_IMEI_LENGTH]; + /* Opt: Software Version Numbber / TS 23.195 */ char msisdn[GSM_EXTENSION_LENGTH]; struct gprs_ra_id ra; u_int16_t cell_id; u_int32_t cell_id_age; + u_int16_t sac; /* Iu: Service Area Code */ + u_int32_t sac_age;/* Iu: Service Area Code age */ /* VLR number */ u_int32_t new_sgsn_addr; /* Authentication Triplets */ /* Kc */ + /* Iu: CK, IK, KSI */ /* CKSN */ enum gprs_ciph_algo ciph_algo; struct { -- cgit v1.2.3 From a67cbd6f061e28ca0e4f6f10cf481b6685d84613 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 1 May 2010 16:46:11 +0200 Subject: [gpprs] Add VTY node for SGSN --- openbsc/include/vty/command.h | 1 + openbsc/src/vty/command.c | 1 + 2 files changed, 2 insertions(+) diff --git a/openbsc/include/vty/command.h b/openbsc/include/vty/command.h index 35e1b299c..5f7c819bb 100644 --- a/openbsc/include/vty/command.h +++ b/openbsc/include/vty/command.h @@ -108,6 +108,7 @@ enum node_type { SUBSCR_NODE, MGCP_NODE, GBPROXY_NODE, + SGSN_NODE, }; /* Node which has some commands and prompt string and configuration diff --git a/openbsc/src/vty/command.c b/openbsc/src/vty/command.c index 62144eeb6..67e6804fe 100644 --- a/openbsc/src/vty/command.c +++ b/openbsc/src/vty/command.c @@ -2364,6 +2364,7 @@ gDEFUN(config_exit, break; case MGCP_NODE: case GBPROXY_NODE: + case SGSN_NODE: vty->node = CONFIG_NODE; vty->index = NULL; default: -- cgit v1.2.3 From 288be16587e83332e51c8ab1c876c235391c5655 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 1 May 2010 16:48:27 +0200 Subject: [gprs] Build the SGSN stand-alone and not as part of bsc_hack Instead of continuing to add more and more functionality to the bsc_hack binary, we should have the new SGSN code run as a separate executable. After this commit we now build a 'osmo_sgsn' executable, using its own osmo_sgsn.cfg config file. However, the SGSN is not yet functional, mainly due to the fact that the BSSGP and GMM code are written with the assumption that there is a msgb->trx->bts and the according 'sturct gsm_bts' data model around - which clearly is no longer the case outside of bsc_hack. --- openbsc/include/openbsc/sgsn.h | 30 +++++++++ openbsc/src/Makefile.am | 12 ++-- openbsc/src/gb_proxy_main.c | 2 +- openbsc/src/gprs_bssgp.c | 28 ++++++-- openbsc/src/gprs_sgsn.c | 32 --------- openbsc/src/gsm_04_08_gprs.c | 8 +-- openbsc/src/osmo_gbproxy.cfg | 13 ++++ openbsc/src/osmo_sgsn.cfg | 9 +++ openbsc/src/sgsn_main.c | 141 +++++++++++++++++++++++++++++++++++++++ openbsc/src/sgsn_vty.c | 146 +++++++++++++++++++++++++++++++++++++++++ 10 files changed, 375 insertions(+), 46 deletions(-) create mode 100644 openbsc/include/openbsc/sgsn.h create mode 100644 openbsc/src/osmo_gbproxy.cfg create mode 100644 openbsc/src/osmo_sgsn.cfg create mode 100644 openbsc/src/sgsn_main.c create mode 100644 openbsc/src/sgsn_vty.c diff --git a/openbsc/include/openbsc/sgsn.h b/openbsc/include/openbsc/sgsn.h new file mode 100644 index 000000000..2dc53c13d --- /dev/null +++ b/openbsc/include/openbsc/sgsn.h @@ -0,0 +1,30 @@ +#ifndef _SGSN_H +#define _SGSN_H + +#include + +#include + +#include + +struct sgsn_config { + /* parsed from config file */ + u_int32_t nsip_listen_ip; + u_int16_t nsip_listen_port; + + /* misc */ + struct gprs_ns_inst *nsi; +}; + + +/* sgsn_vty.c */ + +int sgsn_vty_init(void); +int sgsn_parse_config(const char *config_file, struct sgsn_config *cfg); + +/* sgsn.c */ + +/* Main input function for Gb proxy */ +int sgsn_rcvmsg(struct msgb *msg, struct gprs_nsvc *nsvc, uint16_t ns_bvci); + +#endif diff --git a/openbsc/src/Makefile.am b/openbsc/src/Makefile.am index 6e4e506ff..18245ed5e 100644 --- a/openbsc/src/Makefile.am +++ b/openbsc/src/Makefile.am @@ -3,7 +3,7 @@ AM_CFLAGS=-Wall $(LIBOSMOCORE_CFLAGS) AM_LDFLAGS = $(LIBOSMOCORE_LIBS) sbin_PROGRAMS = bsc_hack bs11_config ipaccess-find ipaccess-config \ - isdnsync bsc_mgcp ipaccess-proxy osmo-gb_proxy + isdnsync bsc_mgcp ipaccess-proxy osmo-gbproxy osmo-sgsn noinst_LIBRARIES = libbsc.a libmsc.a libvty.a libsccp.a libsgsn.a noinst_HEADERS = vty/cardshell.h @@ -33,7 +33,7 @@ libvty_a_SOURCES = vty/buffer.c vty/command.c vty/vector.c vty/vty.c \ libsccp_a_SOURCES = sccp/sccp.c bsc_hack_SOURCES = bsc_hack.c bsc_init.c vty_interface.c vty_interface_layer3.c -bsc_hack_LDADD = libmsc.a libbsc.a libmsc.a libsgsn.a libvty.a -ldl -ldbi $(LIBCRYPT) +bsc_hack_LDADD = libmsc.a libbsc.a libmsc.a libvty.a -ldl -ldbi $(LIBCRYPT) bs11_config_SOURCES = bs11_config.c abis_nm.c gsm_data.c debug.c \ rs232.c bts_siemens_bs11.c @@ -51,6 +51,10 @@ bsc_mgcp_LDADD = libvty.a ipaccess_proxy_SOURCES = ipaccess/ipaccess-proxy.c debug.c -osmo_gb_proxy_SOURCES = gb_proxy.c gb_proxy_main.c gb_proxy_vty.c \ +osmo_gbproxy_SOURCES = gb_proxy.c gb_proxy_main.c gb_proxy_vty.c \ gprs_ns.c socket.c debug.c -osmo_gb_proxy_LDADD = libvty.a +osmo_gbproxy_LDADD = libvty.a + +osmo_sgsn_SOURCES = sgsn_main.c sgsn_vty.c \ + socket.c debug.c +osmo_sgsn_LDADD = libvty.a libsgsn.a diff --git a/openbsc/src/gb_proxy_main.c b/openbsc/src/gb_proxy_main.c index 8f0306091..fe72e0214 100644 --- a/openbsc/src/gb_proxy_main.c +++ b/openbsc/src/gb_proxy_main.c @@ -64,7 +64,7 @@ const char *openbsc_copyright = "This is free software: you are free to change and redistribute it.\n" "There is NO WARRANTY, to the extent permitted by law.\n"; -static char *config_file = "gb_proxy.cfg"; +static char *config_file = "osmo_gbproxy.cfg"; static struct gbproxy_config gbcfg; /* Pointer to the SGSN peer */ diff --git a/openbsc/src/gprs_bssgp.c b/openbsc/src/gprs_bssgp.c index a2181b124..ab6d1a098 100644 --- a/openbsc/src/gprs_bssgp.c +++ b/openbsc/src/gprs_bssgp.c @@ -138,6 +138,25 @@ int bssgp_tx_status(u_int8_t cause, u_int16_t *bvci, struct msgb *orig_msg) return gprs_ns_sendmsg(bssgp_nsi, msg); } +/* Chapter 8.4 BVC-Reset Procedure */ +static int bssgp_rx_bvc_reset(struct msgb *msg, struct tlv_parsed *tp, + uint16_t ns_bvci) +{ + uint8_t bvci; + int rc; + + bvci = ntohs(*(u_int16_t *)TLVP_VAL(tp, BSSGP_IE_BVCI)); + DEBUGPC(DGPRS, "BVCI=%u, cause=%s\n", bvci, + bssgp_cause_str(*TLVP_VAL(tp, BSSGP_IE_CAUSE))); + + /* When we receive a BVC-RESET PDU (at least of a PTP BVCI), the BSS + * informs us about its RAC + Cell ID, so we can create a mapping */ + + rc = bssgp_tx_simple_bvci(BSSGP_PDUT_BVC_RESET_ACK, + msgb_nsei(msg), bvci, ns_bvci); + return 0; +} + /* Uplink unit-data */ static int bssgp_rx_ul_ud(struct msgb *msg, u_int16_t bvci) { @@ -157,10 +176,12 @@ static int bssgp_rx_ul_ud(struct msgb *msg, u_int16_t bvci) !TLVP_PRESENT(&tp, BSSGP_IE_LLC_PDU)) return -EIO; +#if 0 //FIXME /* Determine the BTS based on the Cell ID */ bts = gsm48_bts_by_ra_id(bsc_gsmnet, TLVP_VAL(&tp, BSSGP_IE_CELL_ID), TLVP_LEN(&tp, BSSGP_IE_CELL_ID)); +#endif if (bts) msg->trx = bts->c0; @@ -229,6 +250,7 @@ static int bssgp_rx_fc_bvc(struct msgb *msg, struct tlv_parsed *tp, return bssgp_tx_fc_bvc_ack(msgb_nsei(msg), *TLVP_VAL(tp, BSSGP_IE_TAG), ns_bvci); } + /* We expect msg->l3h to point to the BSSGP header */ int gprs_bssgp_rcvmsg(struct msgb *msg, u_int16_t ns_bvci) { @@ -311,11 +333,7 @@ int gprs_bssgp_rcvmsg(struct msgb *msg, u_int16_t ns_bvci) if (!TLVP_PRESENT(&tp, BSSGP_IE_BVCI) || !TLVP_PRESENT(&tp, BSSGP_IE_CAUSE)) goto err_mand_ie; - bvci = ntohs(*(u_int16_t *)TLVP_VAL(&tp, BSSGP_IE_BVCI)); - DEBUGPC(DGPRS, "BVCI=%u, cause=%s\n", bvci, - bssgp_cause_str(*TLVP_VAL(&tp, BSSGP_IE_CAUSE))); - rc = bssgp_tx_simple_bvci(BSSGP_PDUT_BVC_RESET_ACK, - msgb_nsei(msg), bvci, ns_bvci); + rc = bssgp_rx_bvc_reset(msg, &tp, ns_bvci); break; case BSSGP_PDUT_STATUS: /* Some exception has occurred */ diff --git a/openbsc/src/gprs_sgsn.c b/openbsc/src/gprs_sgsn.c index 3f7f61e20..9844f8808 100644 --- a/openbsc/src/gprs_sgsn.c +++ b/openbsc/src/gprs_sgsn.c @@ -94,35 +94,3 @@ struct sgsn_mm_ctx *sgsn_mm_ctx_alloc(u_int32_t tlli, return ctx; } - -/* call-back function for the NS protocol */ -static int gprs_ns_cb(enum gprs_ns_evt event, struct gprs_nsvc *nsvc, - struct msgb *msg, u_int16_t bvci) -{ - int rc = 0; - - switch (event) { - case GPRS_NS_EVT_UNIT_DATA: - /* hand the message into the BSSGP implementation */ - rc = gprs_bssgp_rcvmsg(msg, bvci); - break; - default: - LOGP(DGPRS, LOGL_ERROR, "SGSN: Unknown event %u from NS\n", event); - if (msg) - talloc_free(msg); - rc = -EIO; - break; - } - return rc; -} - -int sgsn_init(void) -{ - struct gprs_ns_inst *nsi; - - nsi = gprs_ns_instantiate(&gprs_ns_cb); - if (!nsi) - return -EIO; - - return nsip_listen(nsi, 23000); -} diff --git a/openbsc/src/gsm_04_08_gprs.c b/openbsc/src/gsm_04_08_gprs.c index ffc3303a3..db439daa7 100644 --- a/openbsc/src/gsm_04_08_gprs.c +++ b/openbsc/src/gsm_04_08_gprs.c @@ -153,7 +153,7 @@ static int gsm48_tx_gmm_att_ack(struct msgb *old_msg) aa->att_result = 1; /* GPRS only */ aa->ra_upd_timer = GPRS_TMR_MINUTE | 10; aa->radio_prio = 4; /* lowest */ - gsm48_ra_id_by_bts(aa->ra_id.digits, old_msg->trx->bts); + //FIXME gsm48_ra_id_by_bts(aa->ra_id.digits, old_msg->trx->bts); /* Option: P-TMSI signature, allocated P-TMSI, MS ID, ... */ return gsm48_gmm_sendmsg(msg, 0); @@ -227,7 +227,7 @@ static int gsm48_rx_gmm_id_resp(struct msgb *msg) DEBUGP(DMM, "GMM IDENTITY RESPONSE: mi_type=0x%02x MI(%s) ", mi_type, mi_string); - gprs_ra_id_by_bts(&ra_id, msg->trx->bts); + //FIXME gprs_ra_id_by_bts(&ra_id, msg->trx->bts); ctx = sgsn_mm_ctx_by_tlli(msgb_tlli(msg), &ra_id); if (!ctx) { DEBUGP(DMM, "from unknown TLLI 0x%08x?!?\n", msgb_tlli(msg)); @@ -289,7 +289,7 @@ static int gsm48_rx_gmm_att_req(struct msgb *msg) * with a foreign TLLI (P-TMSI that was allocated to the MS before), * or with random TLLI. */ - gprs_ra_id_by_bts(&ra_id, msg->trx->bts); + //FIXME gprs_ra_id_by_bts(&ra_id, msg->trx->bts); /* MS network capability 10.5.5.12 */ msnc_len = *cur++; @@ -391,7 +391,7 @@ static int gsm48_tx_gmm_ra_upd_ack(struct msgb *old_msg) rua->force_stby = 0; /* not indicated */ rua->upd_result = 0; /* RA updated */ rua->ra_upd_timer = GPRS_TMR_MINUTE | 10; - gsm48_ra_id_by_bts(rua->ra_id.digits, old_msg->trx->bts); + //FIXME gsm48_ra_id_by_bts(rua->ra_id.digits, old_msg->trx->bts); /* Option: P-TMSI signature, allocated P-TMSI, MS ID, ... */ return gsm48_gmm_sendmsg(msg, 0); diff --git a/openbsc/src/osmo_gbproxy.cfg b/openbsc/src/osmo_gbproxy.cfg new file mode 100644 index 000000000..f2ef1411f --- /dev/null +++ b/openbsc/src/osmo_gbproxy.cfg @@ -0,0 +1,13 @@ +! +! OpenBSC configuration saved from vty +! ! +! +line vty + no login +! +gbproxy + nsip bss local port 23000 + nsip sgsn remote ip 192.168.100.239 + nsip sgsn remote port 23000 + nsip sgsn nsei 1 + nsip sgsn nsvci 11 diff --git a/openbsc/src/osmo_sgsn.cfg b/openbsc/src/osmo_sgsn.cfg new file mode 100644 index 000000000..f39e8536f --- /dev/null +++ b/openbsc/src/osmo_sgsn.cfg @@ -0,0 +1,9 @@ +! +! OpenBSC configuration saved from vty +! ! +! +line vty + no login +! +sgsn + nsip local port 23000 diff --git a/openbsc/src/sgsn_main.c b/openbsc/src/sgsn_main.c new file mode 100644 index 000000000..5c56ca7ff --- /dev/null +++ b/openbsc/src/sgsn_main.c @@ -0,0 +1,141 @@ +/* GPRS SGSN Implementation */ + +/* (C) 2010 by Harald Welte + * (C) 2010 by On Waves + * 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 +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "../bscconfig.h" + +/* this is here for the vty... it will never be called */ +void subscr_put() { abort(); } + +#define _GNU_SOURCE +#include + +void *tall_bsc_ctx; + +struct gprs_ns_inst *sgsn_nsi; + +const char *openbsc_version = "Osmocom NSIP Proxy " PACKAGE_VERSION; +const char *openbsc_copyright = + "Copyright (C) 2010 Harald Welte and On-Waves\n" + "Contributions by Daniel Willmann, Jan Lübbe, Stefan Schmidt\n" + "Dieter Spaar, Andreas Eversberg, Holger Freyther\n\n" + "License GPLv2+: GNU GPL version 2 or later \n" + "This is free software: you are free to change and redistribute it.\n" + "There is NO WARRANTY, to the extent permitted by law.\n"; + +static char *config_file = "osmo_sgsn.cfg"; +static struct sgsn_config sgcfg; + +/* call-back function for the NS protocol */ +static int sgsn_ns_cb(enum gprs_ns_evt event, struct gprs_nsvc *nsvc, + struct msgb *msg, u_int16_t bvci) +{ + int rc = 0; + + switch (event) { + case GPRS_NS_EVT_UNIT_DATA: + /* hand the message into the BSSGP implementation */ + rc = gprs_bssgp_rcvmsg(msg, bvci); + break; + default: + LOGP(DGPRS, LOGL_ERROR, "SGSN: Unknown event %u from NS\n", event); + if (msg) + talloc_free(msg); + rc = -EIO; + break; + } + return rc; +} + + +int main(int argc, char **argv) +{ + struct gsm_network dummy_network; + struct log_target *stderr_target; + struct sockaddr_in sin; + int rc; + + tall_bsc_ctx = talloc_named_const(NULL, 0, "osmo_sgsn"); + + log_init(&log_info); + stderr_target = log_target_create_stderr(); + log_add_target(stderr_target); + log_set_all_filter(stderr_target, 1); + + telnet_init(&dummy_network, 4245); + rc = sgsn_parse_config(config_file, &sgcfg); + if (rc < 0) { + LOGP(DGPRS, LOGL_FATAL, "Cannot parse config file\n"); + exit(2); + } + + sgsn_nsi = gprs_ns_instantiate(&sgsn_ns_cb); + if (!sgsn_nsi) { + LOGP(DGPRS, LOGL_ERROR, "Unable to instantiate NS\n"); + exit(1); + } + sgcfg.nsi = sgsn_nsi; + nsip_listen(sgsn_nsi, sgcfg.nsip_listen_port); + + while (1) { + rc = bsc_select_main(0); + if (rc < 0) + exit(3); + } + + exit(0); +} + +struct gsm_network; +int bsc_vty_init(struct gsm_network *dummy) +{ + cmd_init(1); + vty_init(); + + openbsc_vty_add_cmds(); + sgsn_vty_init(); + return 0; +} + diff --git a/openbsc/src/sgsn_vty.c b/openbsc/src/sgsn_vty.c new file mode 100644 index 000000000..ec18fcbf9 --- /dev/null +++ b/openbsc/src/sgsn_vty.c @@ -0,0 +1,146 @@ +/* + * (C) 2010 by Harald Welte + * (C) 2010 by On-Waves + * 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 +#include +#include + +#include +#include + +static struct sgsn_config *g_cfg = NULL; + +static struct cmd_node sgsn_node = { + SGSN_NODE, + "%s(sgsn)#", + 1, +}; + +static int config_write_sgsn(struct vty *vty) +{ + struct in_addr ia; + + vty_out(vty, "sgsn%s", VTY_NEWLINE); + + if (g_cfg->nsip_listen_ip) { + ia.s_addr = htonl(g_cfg->nsip_listen_ip); + vty_out(vty, " nsip local ip %s%s", inet_ntoa(ia), + VTY_NEWLINE); + } + vty_out(vty, " nsip local port %u%s", g_cfg->nsip_listen_port, + VTY_NEWLINE); + + return CMD_SUCCESS; +} + +DEFUN(show_sgsn, show_sgsn_cmd, "show sgsn", + SHOW_STR "Display information about the SGSN") +{ + /* FIXME: iterate over list of NS-VC's and display their state */ + struct gprs_ns_inst *nsi = g_cfg->nsi; + struct gprs_nsvc *nsvc; + + llist_for_each_entry(nsvc, &nsi->gprs_nsvcs, list) { + vty_out(vty, "NSEI %5u, NS-VC %5u, %s-mode, %s %s%s", + nsvc->nsei, nsvc->nsvci, + nsvc->remote_end_is_sgsn ? "BSS" : "SGSN", + nsvc->state & NSE_S_ALIVE ? "ALIVE" : "DEAD", + nsvc->state & NSE_S_BLOCKED ? "BLOCKED" : "UNBLOCKED", + VTY_NEWLINE); + if (nsvc->nsi->ll == GPRS_NS_LL_UDP) + vty_out(vty, " remote peer %s:%u%s", + inet_ntoa(nsvc->ip.bts_addr.sin_addr), + ntohs(nsvc->ip.bts_addr.sin_port), VTY_NEWLINE); + } + + return CMD_SUCCESS; +} + +DEFUN(cfg_sgsn, + cfg_sgsn_cmd, + "sgsn", + "Configure the SGSN") +{ + vty->node = SGSN_NODE; + return CMD_SUCCESS; +} + + +DEFUN(cfg_nsip_local_ip, + cfg_nsip_local_ip_cmd, + "nsip local ip A.B.C.D", + "Set the IP address on which we listen for BSS connects") +{ + struct in_addr ia; + + inet_aton(argv[0], &ia); + g_cfg->nsip_listen_ip = ntohl(ia.s_addr); + + return CMD_SUCCESS; +} + +DEFUN(cfg_nsip_local_port, + cfg_nsip_local_port_cmd, + "nsip local port <0-65534>", + "Set the UDP port on which we listen for BSS connects") +{ + unsigned int port = atoi(argv[0]); + + g_cfg->nsip_listen_port = port; + return CMD_SUCCESS; +} + + + + +int sgsn_vty_init(void) +{ + install_element(VIEW_NODE, &show_sgsn_cmd); + + install_element(CONFIG_NODE, &cfg_sgsn_cmd); + install_node(&sgsn_node, config_write_sgsn); + install_default(SGSN_NODE); + install_element(SGSN_NODE, &cfg_nsip_local_ip_cmd); + install_element(SGSN_NODE, &cfg_nsip_local_port_cmd); + + return 0; +} + +int sgsn_parse_config(const char *config_file, struct sgsn_config *cfg) +{ + int rc; + + g_cfg = cfg; + rc = vty_read_config_file(config_file); + if (rc < 0) { + fprintf(stderr, "Failed to parse the config file: '%s'\n", config_file); + return rc; + } + + return 0; +} -- cgit v1.2.3 From 6557cd05174a96f18bc41ea3343a9af3e6c0cda7 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 2 May 2010 09:23:16 +0200 Subject: [gprs] introduce BSSGP concept of BTS contextx A BTS context represents the mapping betewen (RA-ID, Cell-ID) and (BVCI, NSEI) as well as the per-BVC local state. --- openbsc/src/gprs_bssgp.c | 133 +++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 110 insertions(+), 23 deletions(-) diff --git a/openbsc/src/gprs_bssgp.c b/openbsc/src/gprs_bssgp.c index ab6d1a098..44e0a35c0 100644 --- a/openbsc/src/gprs_bssgp.c +++ b/openbsc/src/gprs_bssgp.c @@ -1,6 +1,6 @@ /* GPRS BSSGP protocol implementation as per 3GPP TS 08.18 */ -/* (C) 2009 by Harald Welte +/* (C) 2009-2010 by Harald Welte * * All Rights Reserved * @@ -27,6 +27,8 @@ #include #include +#include + #include #include #include @@ -39,6 +41,8 @@ extern struct gsm_network *bsc_gsmnet; struct gprs_ns_inst *bssgp_nsi; +void *bssgp_tall_ctx = NULL; + /* Chapter 11.3.9 / Table 11.10: Cause coding */ static const char *bssgp_cause_strings[] = { [BSSGP_CAUSE_PROC_OVERLOAD] = "Processor overload", @@ -74,6 +78,68 @@ static const char *bssgp_cause_str(enum gprs_bssgp_cause cause) return "undefined"; } +#define BVC_F_BLOCKED 0x0001 + +/* The per-BTS context that we keep on the SGSN side of the BSSGP link */ +struct bssgp_bts_ctx { + struct llist_head list; + + /* parsed RA ID and Cell ID of the remote BTS */ + struct gprs_ra_id ra_id; + uint16_t cell_id; + + /* NSEI and BVCI of underlying Gb link. Together they + * uniquely identify a link to a BTS (5.4.4) */ + uint16_t bvci; + uint16_t nsei; + + uint32_t bvc_state; + + /* we might want to add this as a shortcut later, avoiding the NSVC + * lookup for every packet, similar to a routing cache */ + //struct gprs_nsvc *nsvc; +}; +LLIST_HEAD(bts_ctxts); + +/* Find a BTS Context based on parsed RA ID and Cell ID */ +struct bssgp_bts_ctx *btsctx_by_raid_cid(const struct gprs_ra_id *raid, uint16_t cid) +{ + struct bssgp_bts_ctx *bctx; + + llist_for_each_entry(bctx, &bts_ctxts, list) { + if (!memcmp(&bctx->ra_id, raid, sizeof(bctx->ra_id)) && + bctx->cell_id == cid) + return bctx; + } + return NULL; +} + +/* Find a BTS context based on BVCI+NSEI tuple */ +struct bssgp_bts_ctx *btsctx_by_bvci_nsei(uint16_t bvci, uint16_t nsei) +{ + struct bssgp_bts_ctx *bctx; + + llist_for_each_entry(bctx, &bts_ctxts, list) { + if (bctx->nsei == nsei && bctx->bvci == bvci) + return bctx; + } + return NULL; +} + +struct bssgp_btx_ctx *btsctx_alloc(uint16_t bvci, uint16_t nsei) +{ + struct bssgp_bts_ctx *ctx; + + ctx = talloc_zero(bssgp_tall_ctx, struct bssgp_bts_ctx); + if (!ctx) + return NULL; + ctx->bvci = bvci; + ctx->nsei = nsei; + llist_add(&ctx->list, &bts_ctxts); + + return ctx; +} + static inline struct msgb *bssgp_msgb_alloc(void) { return msgb_alloc_headroom(4096, 128, "BSSGP"); @@ -138,22 +204,52 @@ int bssgp_tx_status(u_int8_t cause, u_int16_t *bvci, struct msgb *orig_msg) return gprs_ns_sendmsg(bssgp_nsi, msg); } +static void bssgp_parse_cell_id(struct gprs_ra_id *raid, uint16_t *cid, + const uint8_t *buf) +{ + /* 6 octets RAC */ + gsm48_parse_ra(raid, buf); + /* 2 octets CID */ + *cid = ntohs(*(uint16_t *) (buf+6)); +} + /* Chapter 8.4 BVC-Reset Procedure */ static int bssgp_rx_bvc_reset(struct msgb *msg, struct tlv_parsed *tp, uint16_t ns_bvci) { - uint8_t bvci; + struct bssgp_bts_ctx *bctx; + uint16_t nsei = msgb_nsei(msg); + uint16_t bvci; int rc; bvci = ntohs(*(u_int16_t *)TLVP_VAL(tp, BSSGP_IE_BVCI)); DEBUGPC(DGPRS, "BVCI=%u, cause=%s\n", bvci, bssgp_cause_str(*TLVP_VAL(tp, BSSGP_IE_CAUSE))); + /* look-up or create the BTS context for this BVC */ + bctx = btsctx_by_bvci_nsei(bvci, nsei); + if (!bctx) + bctx = btsctx_alloc(bvci, nsei); + /* When we receive a BVC-RESET PDU (at least of a PTP BVCI), the BSS * informs us about its RAC + Cell ID, so we can create a mapping */ + if (bvci != 0 && bvci != 1) { + if (!TLVP_PRESENT(tp, BSSGP_IE_CELL_ID)) { + LOGP(DGPRS, LOGL_ERROR, "BSSGP RESET BVCI=%u " + "missing mandatory IE\n", bvci); + return -EINVAL; + } + /* actually extract RAC / CID */ + bssgp_parse_cell_id(&bctx->ra_id, &bctx->cell_id, + TLVP_VAL(tp, BSSGP_IE_CELL_ID)); + LOGP(DGPRS, LOGL_NOTICE, "Cell %u-%u-%u-%u CI %u on BVCI %u\n", + bctx->ra_id.mcc, bctx->ra_id.mnc, bctx->ra_id.lac, + bctx->ra_id.rac, bctx->cell_id, bvci); + } + /* Acknowledge the RESET to the BTS */ rc = bssgp_tx_simple_bvci(BSSGP_PDUT_BVC_RESET_ACK, - msgb_nsei(msg), bvci, ns_bvci); + nsei, bvci, ns_bvci); return 0; } @@ -161,13 +257,13 @@ static int bssgp_rx_bvc_reset(struct msgb *msg, struct tlv_parsed *tp, static int bssgp_rx_ul_ud(struct msgb *msg, u_int16_t bvci) { struct bssgp_ud_hdr *budh = (struct bssgp_ud_hdr *) msg->l3h; - struct gsm_bts *bts; int data_len = msgb_l3len(msg) - sizeof(*budh); struct tlv_parsed tp; int rc; DEBUGP(DGPRS, "BSSGP UL-UD\n"); + /* extract TLLI and parse TLV IEs */ msgb_tlli(msg) = ntohl(budh->tlli); rc = bssgp_tlv_parse(&tp, budh->data, data_len); @@ -176,15 +272,6 @@ static int bssgp_rx_ul_ud(struct msgb *msg, u_int16_t bvci) !TLVP_PRESENT(&tp, BSSGP_IE_LLC_PDU)) return -EIO; -#if 0 //FIXME - /* Determine the BTS based on the Cell ID */ - bts = gsm48_bts_by_ra_id(bsc_gsmnet, - TLVP_VAL(&tp, BSSGP_IE_CELL_ID), - TLVP_LEN(&tp, BSSGP_IE_CELL_ID)); -#endif - if (bts) - msg->trx = bts->c0; - msgb_llch(msg) = TLVP_VAL(&tp, BSSGP_IE_LLC_PDU); return gprs_llc_rcvmsg(msg, &tp); @@ -261,6 +348,7 @@ int gprs_bssgp_rcvmsg(struct msgb *msg, u_int16_t ns_bvci) u_int16_t bvci; int rc = 0; + /* UNITDATA BSSGP headers have TLLI in front */ if (pdu_type != BSSGP_PDUT_UL_UNITDATA && pdu_type != BSSGP_PDUT_DL_UNITDATA) rc = bssgp_tlv_parse(&tp, bgph->data, data_len); @@ -314,6 +402,7 @@ int gprs_bssgp_rcvmsg(struct msgb *msg, u_int16_t ns_bvci) bvci = ntohs(*(u_int16_t *)TLVP_VAL(&tp, BSSGP_IE_BVCI)); DEBUGPC(DGPRS, "BVCI=%u, cause=%s\n", bvci, bssgp_cause_str(*TLVP_VAL(&tp, BSSGP_IE_CAUSE))); + /* We always acknowledge the BLOCKing */ rc = bssgp_tx_simple_bvci(BSSGP_PDUT_BVC_BLOCK_ACK, msgb_nsei(msg), bvci, ns_bvci); break; @@ -324,6 +413,7 @@ int gprs_bssgp_rcvmsg(struct msgb *msg, u_int16_t ns_bvci) goto err_mand_ie; bvci = ntohs(*(u_int16_t *)TLVP_VAL(&tp, BSSGP_IE_BVCI)); DEBUGPC(DGPRS, "BVCI=%u\n", bvci); + /* We always acknowledge the unBLOCKing */ rc = bssgp_tx_simple_bvci(BSSGP_PDUT_BVC_UNBLOCK_ACK, msgb_nsei(msg), bvci, ns_bvci); break; @@ -374,9 +464,11 @@ err_mand_ie: return bssgp_tx_status(BSSGP_CAUSE_MISSING_MAND_IE, NULL, msg); } -int gprs_bssgp_tx_dl_ud(struct msgb *msg) +/* Entry function from upper level (LLC), asking us to transmit a BSSGP PDU + * to a remote MS (identified by TLLI) at a BTS identified by its RAC and CID */ +int gprs_bssgp_tx_dl_ud(struct msgb *msg, const struct gprs_ra_id *raid, uint16_t cid) { - struct gsm_bts *bts; + struct bssgp_bts_ctx *bctx; struct bssgp_ud_hdr *budh; u_int8_t llc_pdu_tlv_hdr_len = 2; u_int8_t *llc_pdu_tlv, *qos_profile; @@ -384,12 +476,7 @@ int gprs_bssgp_tx_dl_ud(struct msgb *msg) u_int8_t qos_profile_default[3] = { 0x00, 0x00, 0x21 }; u_int16_t msg_len = msg->len; - if (!msg->trx) { - DEBUGP(DGPRS, "Cannot transmit DL-UD without TRX assigned\n"); - return -EINVAL; - } - - bts = msg->trx->bts; + bctx = btsctx_by_raid_cid(raid, cid); if (msg->len > TVLV_MAX_ONEBYTE) llc_pdu_tlv_hdr_len += 1; @@ -417,8 +504,8 @@ int gprs_bssgp_tx_dl_ud(struct msgb *msg) budh->tlli = htonl(msgb_tlli(msg)); budh->pdu_type = BSSGP_PDUT_DL_UNITDATA; - msgb_nsei(msg) = bts->gprs.nse.nsei; - msgb_bvci(msg) = bts->gprs.cell.bvci; + msgb_nsei(msg) = bctx->nsei; + msgb_bvci(msg) = bctx->bvci; return gprs_ns_sendmsg(bssgp_nsi, msg); } -- cgit v1.2.3 From a26655426d11b8ff619510f52bd5234304520d4c Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 2 May 2010 09:28:11 +0200 Subject: [gprs] LLC: Introduce the allocation and lookup of LLC Entities (LLE) --- openbsc/src/gprs_llc.c | 71 ++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 63 insertions(+), 8 deletions(-) diff --git a/openbsc/src/gprs_llc.c b/openbsc/src/gprs_llc.c index 91b0239f0..aea40d360 100644 --- a/openbsc/src/gprs_llc.c +++ b/openbsc/src/gprs_llc.c @@ -1,6 +1,6 @@ /* GPRS LLC protocol implementation as per 3GPP TS 04.64 */ -/* (C) 2009 by Harald Welte +/* (C) 2009-2010 by Harald Welte * * All Rights Reserved * @@ -22,11 +22,13 @@ #include -#include #include -#include #include #include +#include + +#include +#include #include #include #include @@ -61,6 +63,37 @@ struct gprs_llc_lle { unsigned int retrans_ctr; }; +static LLIST_HEAD(gprs_llc_lles); +void *llc_tall_ctx; + +/* lookup LLC Entity based on DLCI (TLLI+SAPI tuple) */ +static struct gprs_llc_lle *lle_by_tlli_sapi(uint32_t tlli, uint32_t sapi) +{ + struct gprs_llc_lle *lle; + + llist_for_each_entry(lle, &gprs_llc_lles, list) { + if (lle->tlli == tlli && lle->sapi == sapi) + return lle; + } + return NULL; +} + +static struct gprs_llc_lle *lle_alloc(uint32_t tlli, uint32_t sapi) +{ + struct gprs_llc_lle *lle; + + lle = talloc_zero(llc_tall_ctx, struct gprs_llc_lle); + if (!lle) + return NULL; + + lle->tlli = tlli; + lle->sapi = sapi; + lle->state = GPRS_LLS_UNASSIGNED; + llist_add(&lle->list, &gprs_llc_lles); + + return lle; +} + enum gprs_llc_cmd { GPRS_LLC_NULL, GPRS_LLC_RR, @@ -392,29 +425,51 @@ static int gprs_llc_hdr_parse(struct gprs_llc_hdr_parsed *ghp, /* FIXME: parse sack frame */ } -/* receive an incoming LLC PDU */ +/* receive an incoming LLC PDU (BSSGP-UL-UNITDATA-IND, 7.2.4.2) */ int gprs_llc_rcvmsg(struct msgb *msg, struct tlv_parsed *tv) { struct bssgp_ud_hdr *udh = (struct bssgp_ud_hdr *) msg->l3h; struct gprs_llc_hdr *lh = msgb_llch(msg); struct gprs_llc_hdr_parsed llhp; struct gprs_llc_entity *lle; - int rc; + int rc = 0; rc = gprs_llc_hdr_parse(&llhp, lh, TLVP_LEN(tv, BSSGP_IE_LLC_PDU)); - - /* FIXME: find LLC Entity */ + /* FIXME */ gprs_llc_hdr_dump(&llhp); + + /* find the LLC Entity for this TLLI+SAPI tuple */ + lle = lle_by_tlli_sapi(msgb_tlli(msg), llhp.sapi); + /* allocate a new LLE if needed */ + if (!lle) + lle = lle_alloc(msgb_tlli(msg), llhp.sapi); + rc = gprs_llc_hdr_rx(&llhp, lle); + /* FIXME */ if (llhp.data) { msgb_gmmh(msg) = llhp.data; switch (llhp.sapi) { case GPRS_SAPI_GMM: rc = gsm0408_gprs_rcvmsg(msg); + break; + case GPRS_SAPI_TOM2: + case GPRS_SAPI_TOM8: + /* FIXME */ + case GPRS_SAPI_SNDCP3: + case GPRS_SAPI_SNDCP5: + case GPRS_SAPI_SNDCP9: + case GPRS_SAPI_SNDCP11: + /* FIXME */ + case GPRS_SAPI_SMS: + /* FIXME */ + default: + LOGP(DGPRS, LOGL_NOTICE, "Unsupported SAPI %u\n", llhp.sapi); + rc = -EINVAL; + break; } } - return 0; + return rc; } -- cgit v1.2.3 From dbab1c79e7cb8e2c5141f20b6b9ef4a52f33ab40 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 2 May 2010 09:34:20 +0200 Subject: [gprs] BSSGP: convert cause strings to value_string --- openbsc/src/gprs_bssgp.c | 57 ++++++++++++++++++++++++------------------------ 1 file changed, 29 insertions(+), 28 deletions(-) diff --git a/openbsc/src/gprs_bssgp.c b/openbsc/src/gprs_bssgp.c index 44e0a35c0..4b5821343 100644 --- a/openbsc/src/gprs_bssgp.c +++ b/openbsc/src/gprs_bssgp.c @@ -43,40 +43,41 @@ struct gprs_ns_inst *bssgp_nsi; void *bssgp_tall_ctx = NULL; +/* BSSGP Protocol specific, not implementation specific */ +/* FIXME: This needs to go into libosmocore after finished */ + /* Chapter 11.3.9 / Table 11.10: Cause coding */ -static const char *bssgp_cause_strings[] = { - [BSSGP_CAUSE_PROC_OVERLOAD] = "Processor overload", - [BSSGP_CAUSE_EQUIP_FAIL] = "Equipment Failure", - [BSSGP_CAUSE_TRASIT_NET_FAIL] = "Transit netowkr service failure", - [BSSGP_CAUSE_CAPA_GREATER_0KPBS]= "Transmission capacity modified", - [BSSGP_CAUSE_UNKNOWN_MS] = "Unknown MS", - [BSSGP_CAUSE_UNKNOWN_BVCI] = "Unknown BVCI", - [BSSGP_CAUSE_CELL_TRAF_CONG] = "Cell traffic congestion", - [BSSGP_CAUSE_SGSN_CONG] = "SGSN congestion", - [BSSGP_CAUSE_OML_INTERV] = "O&M intervention", - [BSSGP_CAUSE_BVCI_BLOCKED] = "BVCI blocked", - [BSSGP_CAUSE_PFC_CREATE_FAIL] = "PFC create failure", - [BSSGP_CAUSE_SEM_INCORR_PDU] = "Semantically incorrect PDU", - [BSSGP_CAUSE_INV_MAND_INF] = "Invalid mandatory information", - [BSSGP_CAUSE_MISSING_MAND_IE] = "Missing mandatory IE", - [BSSGP_CAUSE_MISSING_COND_IE] = "Missing conditional IE", - [BSSGP_CAUSE_UNEXP_COND_IE] = "Unexpected conditional IE", - [BSSGP_CAUSE_COND_IE_ERR] = "Conditional IE error", - [BSSGP_CAUSE_PDU_INCOMP_STATE] = "PDU incompatible with protocol state", - [BSSGP_CAUSE_PROTO_ERR_UNSPEC] = "Protocol error - unspecified", - [BSSGP_CAUSE_PDU_INCOMP_FEAT] = "PDU not compatible with feature set", +static const struct value_string bssgp_cause_strings[] = { + { BSSGP_CAUSE_PROC_OVERLOAD, "Processor overload" }, + { BSSGP_CAUSE_EQUIP_FAIL, "Equipment Failure" }, + { BSSGP_CAUSE_TRASIT_NET_FAIL, "Transit netowkr service failure" }, + { BSSGP_CAUSE_CAPA_GREATER_0KPBS,"Transmission capacity modified" }, + { BSSGP_CAUSE_UNKNOWN_MS, "Unknown MS" }, + { BSSGP_CAUSE_UNKNOWN_BVCI, "Unknown BVCI" }, + { BSSGP_CAUSE_CELL_TRAF_CONG, "Cell traffic congestion" }, + { BSSGP_CAUSE_SGSN_CONG, "SGSN congestion" }, + { BSSGP_CAUSE_OML_INTERV, "O&M intervention" }, + { BSSGP_CAUSE_BVCI_BLOCKED, "BVCI blocked" }, + { BSSGP_CAUSE_PFC_CREATE_FAIL, "PFC create failure" }, + { BSSGP_CAUSE_SEM_INCORR_PDU, "Semantically incorrect PDU" }, + { BSSGP_CAUSE_INV_MAND_INF, "Invalid mandatory information" }, + { BSSGP_CAUSE_MISSING_MAND_IE, "Missing mandatory IE" }, + { BSSGP_CAUSE_MISSING_COND_IE, "Missing conditional IE" }, + { BSSGP_CAUSE_UNEXP_COND_IE, "Unexpected conditional IE" }, + { BSSGP_CAUSE_COND_IE_ERR, "Conditional IE error" }, + { BSSGP_CAUSE_PDU_INCOMP_STATE, "PDU incompatible with protocol state" }, + { BSSGP_CAUSE_PROTO_ERR_UNSPEC, "Protocol error - unspecified" }, + { BSSGP_CAUSE_PDU_INCOMP_FEAT, "PDU not compatible with feature set" }, + { 0, NULL }, }; -static const char *bssgp_cause_str(enum gprs_bssgp_cause cause) +const char *bssgp_cause_str(enum gprs_bssgp_cause cause) { - if (cause >= ARRAY_SIZE(bssgp_cause_strings)) - return "undefined"; + return get_value_string(bssgp_cause_strings, cause); +} - if (bssgp_cause_strings[cause]) - return bssgp_cause_strings[cause]; - return "undefined"; -} +/* Our actual implementation */ #define BVC_F_BLOCKED 0x0001 -- cgit v1.2.3 From 345223ee9e48a5490bac7db9a0b54a3639b2e332 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 2 May 2010 09:37:45 +0200 Subject: [gprs] convert ns_cause_str to value_string --- openbsc/src/gprs_ns.c | 35 +++++++++++++++-------------------- 1 file changed, 15 insertions(+), 20 deletions(-) diff --git a/openbsc/src/gprs_ns.c b/openbsc/src/gprs_ns.c index 18d189f5a..7f94b97b1 100644 --- a/openbsc/src/gprs_ns.c +++ b/openbsc/src/gprs_ns.c @@ -124,29 +124,24 @@ static struct gprs_nsvc *nsvc_create(struct gprs_ns_inst *nsi, u_int16_t nsvci) } /* Section 10.3.2, Table 13 */ -static const char *ns_cause_str[] = { - [NS_CAUSE_TRANSIT_FAIL] = "Transit network failure", - [NS_CAUSE_OM_INTERVENTION] = "O&M intervention", - [NS_CAUSE_EQUIP_FAIL] = "Equipment failure", - [NS_CAUSE_NSVC_BLOCKED] = "NS-VC blocked", - [NS_CAUSE_NSVC_UNKNOWN] = "NS-VC unknown", - [NS_CAUSE_BVCI_UNKNOWN] = "BVCI unknown", - [NS_CAUSE_SEM_INCORR_PDU] = "Semantically incorrect PDU", - [NS_CAUSE_PDU_INCOMP_PSTATE] = "PDU not compatible with protocol state", - [NS_CAUSE_PROTO_ERR_UNSPEC] = "Protocol error, unspecified", - [NS_CAUSE_INVAL_ESSENT_IE] = "Invalid essential IE", - [NS_CAUSE_MISSING_ESSENT_IE] = "Missing essential IE", +static const struct value_string ns_cause_str[] = { + { NS_CAUSE_TRANSIT_FAIL, "Transit network failure" }, + { NS_CAUSE_OM_INTERVENTION, "O&M intervention" }, + { NS_CAUSE_EQUIP_FAIL, "Equipment failure" }, + { NS_CAUSE_NSVC_BLOCKED, "NS-VC blocked" }, + { NS_CAUSE_NSVC_UNKNOWN, "NS-VC unknown" }, + { NS_CAUSE_BVCI_UNKNOWN, "BVCI unknown" }, + { NS_CAUSE_SEM_INCORR_PDU, "Semantically incorrect PDU" }, + { NS_CAUSE_PDU_INCOMP_PSTATE, "PDU not compatible with protocol state" }, + { NS_CAUSE_PROTO_ERR_UNSPEC, "Protocol error }, unspecified" }, + { NS_CAUSE_INVAL_ESSENT_IE, "Invalid essential IE" }, + { NS_CAUSE_MISSING_ESSENT_IE, "Missing essential IE" }, + { 0, NULL } }; -static const char *gprs_ns_cause_str(enum ns_cause cause) +const char *gprs_ns_cause_str(enum ns_cause cause) { - if (cause >= ARRAY_SIZE(ns_cause_str)) - return "undefined"; - - if (ns_cause_str[cause]) - return ns_cause_str[cause]; - - return "undefined"; + return get_value_string(ns_cause_str, cause); } static int nsip_sendmsg(struct gprs_nsvc *nsvc, struct msgb *msg); -- cgit v1.2.3 From fd3fa1d4e0aaf06e523d3f36ce5d983b77569fbc Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 2 May 2010 09:50:42 +0200 Subject: [gprs] Ensure msgb->l3h points to Layer3 (04.08) In the old code l3h = BSSGP, l4h = LLC, cb[gmmh] = 04.08 Now, this has been changed to cb[bssgph] = BSSGP, cb[llch] = LLC, l3h = 04.08 This way, GSM general 04.08 and GPRS 04.08 code can expect a GSM 04.08 header at msgb->l3h --- openbsc/include/openbsc/gsm_data.h | 8 +++++--- openbsc/src/gprs_bssgp.c | 15 +++++++++------ openbsc/src/gprs_llc.c | 2 +- openbsc/src/gprs_ns.c | 2 +- 4 files changed, 16 insertions(+), 11 deletions(-) diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index c124fae5e..f011041e5 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -81,7 +81,8 @@ enum bts_gprs_mode { /* the data structure stored in msgb->cb for openbsc apps */ struct openbsc_msgb_cb { - unsigned char *gmmh; + unsigned char *bssgph; + unsigned char *llch; u_int16_t nsei; u_int16_t bvci; @@ -90,10 +91,11 @@ struct openbsc_msgb_cb { } __attribute__((packed)); #define OBSC_MSGB_CB(__msgb) ((struct openbsc_msgb_cb *)&((__msgb)->cb[0])) #define msgb_tlli(__x) OBSC_MSGB_CB(__x)->tlli -#define msgb_gmmh(__x) OBSC_MSGB_CB(__x)->gmmh #define msgb_nsei(__x) OBSC_MSGB_CB(__x)->nsei #define msgb_bvci(__x) OBSC_MSGB_CB(__x)->bvci -#define msgb_llch(__x) (__x)->l4h +#define msgb_gmmh(__x) (__x)->l3h +#define msgb_bssgph(__x) OBSC_MSGB_CB(__x)->bssgph +#define msgb_llch(__x) OBSC_MSGB_CB(__x)->llch struct msgb; typedef int gsm_cbfn(unsigned int hooknum, diff --git a/openbsc/src/gprs_bssgp.c b/openbsc/src/gprs_bssgp.c index 4b5821343..330d8c875 100644 --- a/openbsc/src/gprs_bssgp.c +++ b/openbsc/src/gprs_bssgp.c @@ -200,7 +200,7 @@ int bssgp_tx_status(u_int8_t cause, u_int16_t *bvci, struct msgb *orig_msg) } if (orig_msg) msgb_tvlv_put(msg, BSSGP_IE_PDU_IN_ERROR, - msgb_l3len(orig_msg), orig_msg->l3h); + msgb_l3len(orig_msg), msgb_bssgph(orig_msg)); return gprs_ns_sendmsg(bssgp_nsi, msg); } @@ -257,7 +257,7 @@ static int bssgp_rx_bvc_reset(struct msgb *msg, struct tlv_parsed *tp, /* Uplink unit-data */ static int bssgp_rx_ul_ud(struct msgb *msg, u_int16_t bvci) { - struct bssgp_ud_hdr *budh = (struct bssgp_ud_hdr *) msg->l3h; + struct bssgp_ud_hdr *budh = (struct bssgp_ud_hdr *) msgb_bssgph(msg); int data_len = msgb_l3len(msg) - sizeof(*budh); struct tlv_parsed tp; int rc; @@ -280,7 +280,8 @@ static int bssgp_rx_ul_ud(struct msgb *msg, u_int16_t bvci) static int bssgp_rx_suspend(struct msgb *msg, u_int16_t bvci) { - struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msg->l3h; + struct bssgp_normal_hdr *bgph = + (struct bssgp_normal_hdr *) msgb_bssgph(msg); int data_len = msgb_l3len(msg) - sizeof(*bgph); struct tlv_parsed tp; int rc; @@ -301,7 +302,8 @@ static int bssgp_rx_suspend(struct msgb *msg, u_int16_t bvci) static int bssgp_rx_resume(struct msgb *msg, u_int16_t bvci) { - struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msg->l3h; + struct bssgp_normal_hdr *bgph = + (struct bssgp_normal_hdr *) msgb_bssgph(msg); int data_len = msgb_l3len(msg) - sizeof(*bgph); struct tlv_parsed tp; int rc; @@ -339,10 +341,11 @@ static int bssgp_rx_fc_bvc(struct msgb *msg, struct tlv_parsed *tp, ns_bvci); } -/* We expect msg->l3h to point to the BSSGP header */ +/* We expect msgb_bssgph() to point to the BSSGP header */ int gprs_bssgp_rcvmsg(struct msgb *msg, u_int16_t ns_bvci) { - struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msg->l3h; + struct bssgp_normal_hdr *bgph = + (struct bssgp_normal_hdr *) msgb_bssgph(msg); struct tlv_parsed tp; u_int8_t pdu_type = bgph->pdu_type; int data_len = msgb_l3len(msg) - sizeof(*bgph); diff --git a/openbsc/src/gprs_llc.c b/openbsc/src/gprs_llc.c index aea40d360..883eedb05 100644 --- a/openbsc/src/gprs_llc.c +++ b/openbsc/src/gprs_llc.c @@ -428,7 +428,7 @@ static int gprs_llc_hdr_parse(struct gprs_llc_hdr_parsed *ghp, /* receive an incoming LLC PDU (BSSGP-UL-UNITDATA-IND, 7.2.4.2) */ int gprs_llc_rcvmsg(struct msgb *msg, struct tlv_parsed *tv) { - struct bssgp_ud_hdr *udh = (struct bssgp_ud_hdr *) msg->l3h; + struct bssgp_ud_hdr *udh = (struct bssgp_ud_hdr *) msgb_bssgph(msg); struct gprs_llc_hdr *lh = msgb_llch(msg); struct gprs_llc_hdr_parsed llhp; struct gprs_llc_entity *lle; diff --git a/openbsc/src/gprs_ns.c b/openbsc/src/gprs_ns.c index 7f94b97b1..470ccb080 100644 --- a/openbsc/src/gprs_ns.c +++ b/openbsc/src/gprs_ns.c @@ -266,7 +266,7 @@ static int gprs_ns_rx_unitdata(struct gprs_nsvc *nsvc, struct msgb *msg) /* spare octet in data[0] */ bvci = nsh->data[1] << 8 | nsh->data[2]; - msg->l3h = &nsh->data[3]; + msgb_bssgph(msg) = &nsh->data[3]; /* call upper layer (BSSGP) */ return nsvc->nsi->cb(GPRS_NS_EVT_UNIT_DATA, nsvc, msg, bvci); -- cgit v1.2.3 From e6afd6077999406b91be9163e454f993929c2317 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 2 May 2010 11:19:37 +0200 Subject: [gprs] SGSN: Expect all Identifiers to be stored at highest level We now expect the highest level (actual SGSN GMM code) to know all identifiers for every element in the protocol stack, i.e. TLLI, SAPI, BVCI and NSEI. The layer-inetrnal state is looked up based on those identifiers. The reason for this is to ensure only the highest level state needs to be persistent, while everything else can be regenerated dynamically (e.g. in a SGSN restart) --- openbsc/include/openbsc/gprs_bssgp.h | 2 +- openbsc/include/openbsc/gsm_data.h | 2 ++ openbsc/src/gprs_bssgp.c | 63 ++++++++++++++++++++++++------------ openbsc/src/gprs_llc.c | 17 ++++++++++ openbsc/src/gprs_ns.c | 1 + openbsc/src/sgsn_main.c | 2 +- 6 files changed, 64 insertions(+), 23 deletions(-) diff --git a/openbsc/include/openbsc/gprs_bssgp.h b/openbsc/include/openbsc/gprs_bssgp.h index 3040e6a0e..a00481e4e 100644 --- a/openbsc/include/openbsc/gprs_bssgp.h +++ b/openbsc/include/openbsc/gprs_bssgp.h @@ -137,7 +137,7 @@ enum gprs_bssgp_cause { #include -extern int gprs_bssgp_rcvmsg(struct msgb *msg, u_int16_t bvci); +extern int gprs_bssgp_rcvmsg(struct msgb *msg); /* Wrapper around TLV parser to parse BSSGP IEs */ static inline int bssgp_tlv_parse(struct tlv_parsed *tp, u_int8_t *buf, int len) diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index f011041e5..3dd7a18c2 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -84,9 +84,11 @@ struct openbsc_msgb_cb { unsigned char *bssgph; unsigned char *llch; + /* Identifiers of a BTS, equal to 'struct bssgp_bts_ctx' */ u_int16_t nsei; u_int16_t bvci; + /* Identifier of a MS (inside BTS), equal to 'struct sgsn_mm_ctx' */ u_int32_t tlli; } __attribute__((packed)); #define OBSC_MSGB_CB(__msgb) ((struct openbsc_msgb_cb *)&((__msgb)->cb[0])) diff --git a/openbsc/src/gprs_bssgp.c b/openbsc/src/gprs_bssgp.c index 330d8c875..6bba1af8a 100644 --- a/openbsc/src/gprs_bssgp.c +++ b/openbsc/src/gprs_bssgp.c @@ -255,7 +255,7 @@ static int bssgp_rx_bvc_reset(struct msgb *msg, struct tlv_parsed *tp, } /* Uplink unit-data */ -static int bssgp_rx_ul_ud(struct msgb *msg, u_int16_t bvci) +static int bssgp_rx_ul_ud(struct msgb *msg) { struct bssgp_ud_hdr *budh = (struct bssgp_ud_hdr *) msgb_bssgph(msg); int data_len = msgb_l3len(msg) - sizeof(*budh); @@ -273,12 +273,14 @@ static int bssgp_rx_ul_ud(struct msgb *msg, u_int16_t bvci) !TLVP_PRESENT(&tp, BSSGP_IE_LLC_PDU)) return -EIO; + /* FIXME: lookup bssgp_bts_ctx based on BVCI + NSEI */ + msgb_llch(msg) = TLVP_VAL(&tp, BSSGP_IE_LLC_PDU); return gprs_llc_rcvmsg(msg, &tp); } -static int bssgp_rx_suspend(struct msgb *msg, u_int16_t bvci) +static int bssgp_rx_suspend(struct msgb *msg) { struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msgb_bssgph(msg); @@ -296,11 +298,11 @@ static int bssgp_rx_suspend(struct msgb *msg, u_int16_t bvci) !TLVP_PRESENT(&tp, BSSGP_IE_ROUTEING_AREA)) return -EIO; + /* FIXME: pass the SUSPEND request to GMM */ /* SEND SUSPEND_ACK or SUSPEND_NACK */ - /* FIXME */ } -static int bssgp_rx_resume(struct msgb *msg, u_int16_t bvci) +static int bssgp_rx_resume(struct msgb *msg) { struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msgb_bssgph(msg); @@ -319,12 +321,11 @@ static int bssgp_rx_resume(struct msgb *msg, u_int16_t bvci) !TLVP_PRESENT(&tp, BSSGP_IE_SUSPEND_REF_NR)) return -EIO; + /* FIXME: pass the RESUME request to GMM */ /* SEND RESUME_ACK or RESUME_NACK */ - /* FIXME */ } -static int bssgp_rx_fc_bvc(struct msgb *msg, struct tlv_parsed *tp, - u_int16_t ns_bvci) +static int bssgp_rx_fc_bvc(struct msgb *msg, struct tlv_parsed *tp) { DEBUGP(DGPRS, "BSSGP FC BVC\n"); @@ -336,22 +337,27 @@ static int bssgp_rx_fc_bvc(struct msgb *msg, struct tlv_parsed *tp, !TLVP_PRESENT(tp, BSSGP_IE_R_DEFAULT_MS)) return bssgp_tx_status(BSSGP_CAUSE_MISSING_MAND_IE, NULL, msg); + /* FIXME: actually implement flow control */ + /* Send FLOW_CONTROL_BVC_ACK */ return bssgp_tx_fc_bvc_ack(msgb_nsei(msg), *TLVP_VAL(tp, BSSGP_IE_TAG), - ns_bvci); + msgb_bvci(msg)); } /* We expect msgb_bssgph() to point to the BSSGP header */ -int gprs_bssgp_rcvmsg(struct msgb *msg, u_int16_t ns_bvci) +int gprs_bssgp_rcvmsg(struct msgb *msg) { struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msgb_bssgph(msg); struct tlv_parsed tp; - u_int8_t pdu_type = bgph->pdu_type; + uint8_t pdu_type = bgph->pdu_type; int data_len = msgb_l3len(msg) - sizeof(*bgph); - u_int16_t bvci; + uint16_t bvci; /* PTP BVCI */ + uint16_t ns_bvci = msgb_bvci(msg); int rc = 0; + /* Identifiers from DOWN: NSEI, BVCI (both in msg->cb) */ + /* UNITDATA BSSGP headers have TLLI in front */ if (pdu_type != BSSGP_PDUT_UL_UNITDATA && pdu_type != BSSGP_PDUT_DL_UNITDATA) @@ -360,7 +366,7 @@ int gprs_bssgp_rcvmsg(struct msgb *msg, u_int16_t ns_bvci) switch (pdu_type) { case BSSGP_PDUT_UL_UNITDATA: /* some LLC data from the MS */ - rc = bssgp_rx_ul_ud(msg, ns_bvci); + rc = bssgp_rx_ul_ud(msg); break; case BSSGP_PDUT_RA_CAPABILITY: /* BSS requests RA capability or IMSI */ @@ -370,32 +376,36 @@ int gprs_bssgp_rcvmsg(struct msgb *msg, u_int16_t ns_bvci) case BSSGP_PDUT_RADIO_STATUS: DEBUGP(DGPRS, "BSSGP RADIO STATUS\n"); /* BSS informs us of some exception */ + /* FIXME: notify GMM */ break; case BSSGP_PDUT_SUSPEND: /* MS wants to suspend */ - rc = bssgp_rx_suspend(msg, ns_bvci); + rc = bssgp_rx_suspend(msg); break; case BSSGP_PDUT_RESUME: /* MS wants to resume */ - rc = bssgp_rx_resume(msg, ns_bvci); + rc = bssgp_rx_resume(msg); break; case BSSGP_PDUT_FLUSH_LL: /* BSS informs MS has moved to one cell to other cell */ DEBUGP(DGPRS, "BSSGP FLUSH LL\n"); + /* FIXME: notify GMM */ /* Send FLUSH_LL_ACK */ break; case BSSGP_PDUT_LLC_DISCARD: /* BSS informs that some LLC PDU's have been discarded */ DEBUGP(DGPRS, "BSSGP LLC DISCARDED\n"); + /* FIXME: notify GMM */ break; case BSSGP_PDUT_FLOW_CONTROL_BVC: /* BSS informs us of available bandwidth in Gb interface */ - rc = bssgp_rx_fc_bvc(msg, &tp, ns_bvci); + rc = bssgp_rx_fc_bvc(msg, &tp); break; case BSSGP_PDUT_FLOW_CONTROL_MS: /* BSS informs us of available bandwidth to one MS */ DEBUGP(DGPRS, "BSSGP FC MS\n"); - /* Send FLOW_CONTROL_MS_ACK */ + /* FIXME: actually implement flow control */ + /* FIXME: Send FLOW_CONTROL_MS_ACK */ break; case BSSGP_PDUT_BVC_BLOCK: /* BSS tells us that BVC shall be blocked */ @@ -431,6 +441,7 @@ int gprs_bssgp_rcvmsg(struct msgb *msg, u_int16_t ns_bvci) break; case BSSGP_PDUT_STATUS: /* Some exception has occurred */ + /* FIXME: notify GMM */ case BSSGP_PDUT_DOWNLOAD_BSS_PFC: case BSSGP_PDUT_CREATE_BSS_PFC_ACK: case BSSGP_PDUT_CREATE_BSS_PFC_NACK: @@ -469,8 +480,8 @@ err_mand_ie: } /* Entry function from upper level (LLC), asking us to transmit a BSSGP PDU - * to a remote MS (identified by TLLI) at a BTS identified by its RAC and CID */ -int gprs_bssgp_tx_dl_ud(struct msgb *msg, const struct gprs_ra_id *raid, uint16_t cid) + * to a remote MS (identified by TLLI) at a BTS identified by its BVCI and NSEI */ +int gprs_bssgp_tx_dl_ud(struct msgb *msg) { struct bssgp_bts_ctx *bctx; struct bssgp_ud_hdr *budh; @@ -479,8 +490,19 @@ int gprs_bssgp_tx_dl_ud(struct msgb *msg, const struct gprs_ra_id *raid, uint16_ u_int16_t pdu_lifetime = 1000; /* centi-seconds */ u_int8_t qos_profile_default[3] = { 0x00, 0x00, 0x21 }; u_int16_t msg_len = msg->len; + uint16_t bvci = msgb_bvci(msg); + uint16_t nsei = msgb_nsei(msg); - bctx = btsctx_by_raid_cid(raid, cid); + /* Identifiers from UP: TLLI, BVCI, NSEI (all in msgb->cb) */ + if (bvci < 2) { + LOGP(DGPRS, LOGL_ERROR, "Cannot send DL-UD to BVCI %u\n", + bvci); + return -EINVAL; + } + + bctx = btsctx_by_bvci_nsei(bvci, nsei); + if (!bctx) + bctx = btsctx_alloc(bvci, nsei); if (msg->len > TVLV_MAX_ONEBYTE) llc_pdu_tlv_hdr_len += 1; @@ -508,8 +530,7 @@ int gprs_bssgp_tx_dl_ud(struct msgb *msg, const struct gprs_ra_id *raid, uint16_ budh->tlli = htonl(msgb_tlli(msg)); budh->pdu_type = BSSGP_PDUT_DL_UNITDATA; - msgb_nsei(msg) = bctx->nsei; - msgb_bvci(msg) = bctx->bvci; + /* Identifiers down: BVCI, NSEI (in msgb->cb) */ return gprs_ns_sendmsg(bssgp_nsi, msg); } diff --git a/openbsc/src/gprs_llc.c b/openbsc/src/gprs_llc.c index 883eedb05..ba031a2ec 100644 --- a/openbsc/src/gprs_llc.c +++ b/openbsc/src/gprs_llc.c @@ -61,6 +61,10 @@ struct gprs_llc_lle { unsigned int n200; unsigned int retrans_ctr; + + /* over which BSSGP BTS ctx do we need to transmit */ + uint16_t bvci; + uint16_t nsei; }; static LLIST_HEAD(gprs_llc_lles); @@ -190,11 +194,22 @@ static void t201_expired(void *data) /* Transmit a UI frame over the given SAPI */ int gprs_llc_tx_ui(struct msgb *msg, u_int8_t sapi, int command) { + struct gprs_llc_lle *lle; u_int8_t *fcs, *llch; u_int8_t addr, ctrl[2]; u_int32_t fcs_calc; u_int16_t nu = 0; + /* Identifiers from UP: (TLLI, SAPI) + (BVCI, NSEI) */ + + /* look-up or create the LL Entity for this (TLLI, SAPI) tuple */ + lle = lle_by_tlli_sapi(msgb_tlli(msg), sapi); + if (!lle) + lle = lle_alloc(msgb_tlli(msg), sapi); + /* Update LLE's (BVCI, NSEI) tuple */ + lle->bvci = msgb_bvci(msg); + lle->nsei = msgb_nsei(msg); + /* Address Field */ addr = sapi & 0xf; if (command) @@ -219,6 +234,8 @@ int gprs_llc_tx_ui(struct msgb *msg, u_int8_t sapi, int command) fcs[1] = (fcs_calc >> 8) & 0xff; fcs[2] = (fcs_calc >> 16) & 0xff; + /* Identifiers passed down: (BVCI, NSEI) */ + return gprs_bssgp_tx_dl_ud(msg); } diff --git a/openbsc/src/gprs_ns.c b/openbsc/src/gprs_ns.c index 470ccb080..1558ca146 100644 --- a/openbsc/src/gprs_ns.c +++ b/openbsc/src/gprs_ns.c @@ -267,6 +267,7 @@ static int gprs_ns_rx_unitdata(struct gprs_nsvc *nsvc, struct msgb *msg) /* spare octet in data[0] */ bvci = nsh->data[1] << 8 | nsh->data[2]; msgb_bssgph(msg) = &nsh->data[3]; + msgb_bvci(msg) = bvci; /* call upper layer (BSSGP) */ return nsvc->nsi->cb(GPRS_NS_EVT_UNIT_DATA, nsvc, msg, bvci); diff --git a/openbsc/src/sgsn_main.c b/openbsc/src/sgsn_main.c index 5c56ca7ff..66d8efc4b 100644 --- a/openbsc/src/sgsn_main.c +++ b/openbsc/src/sgsn_main.c @@ -77,7 +77,7 @@ static int sgsn_ns_cb(enum gprs_ns_evt event, struct gprs_nsvc *nsvc, switch (event) { case GPRS_NS_EVT_UNIT_DATA: /* hand the message into the BSSGP implementation */ - rc = gprs_bssgp_rcvmsg(msg, bvci); + rc = gprs_bssgp_rcvmsg(msg); break; default: LOGP(DGPRS, LOGL_ERROR, "SGSN: Unknown event %u from NS\n", event); -- cgit v1.2.3 From eaa614cb9e7e72701e6ac479ff570c04bae497e0 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 2 May 2010 11:26:34 +0200 Subject: [gprs] Use stdint.h types (uintXX_t instead of u_intXX_t) libosmocore already uses them, it's time (at least for new code) in openbsc to do the same. --- openbsc/include/openbsc/gprs_bssgp.h | 16 +++++---- openbsc/include/openbsc/gprs_llc.h | 4 ++- openbsc/include/openbsc/gprs_ns.h | 16 +++++---- openbsc/include/openbsc/gprs_sgsn.h | 62 ++++++++++++++++---------------- openbsc/include/openbsc/gsm_04_08_gprs.h | 36 ++++++++++--------- openbsc/src/gprs_bssgp.c | 36 +++++++++---------- openbsc/src/gprs_llc.c | 47 ++++++++++++------------ openbsc/src/gprs_ns.c | 34 +++++++++--------- openbsc/src/gprs_sgsn.c | 8 ++--- openbsc/src/gsm_04_08_gprs.c | 35 +++++++++--------- 10 files changed, 153 insertions(+), 141 deletions(-) diff --git a/openbsc/include/openbsc/gprs_bssgp.h b/openbsc/include/openbsc/gprs_bssgp.h index a00481e4e..c70868af3 100644 --- a/openbsc/include/openbsc/gprs_bssgp.h +++ b/openbsc/include/openbsc/gprs_bssgp.h @@ -1,6 +1,8 @@ #ifndef _GPRS_BSSGP_H #define _GPRS_BSSGP_H +#include + /* Section 11.3.26 / Table 11.27 */ enum bssgp_pdu_type { /* PDUs between RL and BSSGP SAPs */ @@ -49,15 +51,15 @@ enum bssgp_pdu_type { /* Section 10.2.1 and 10.2.2 */ struct bssgp_ud_hdr { - u_int8_t pdu_type; - u_int32_t tlli; - u_int8_t qos_profile[3]; - u_int8_t data[0]; /* TLV's */ + uint8_t pdu_type; + uint32_t tlli; + uint8_t qos_profile[3]; + uint8_t data[0]; /* TLV's */ } __attribute__((packed)); struct bssgp_normal_hdr { - u_int8_t pdu_type; - u_int8_t data[0]; /* TLV's */ + uint8_t pdu_type; + uint8_t data[0]; /* TLV's */ }; enum bssgp_iei_type { @@ -140,7 +142,7 @@ enum gprs_bssgp_cause { extern int gprs_bssgp_rcvmsg(struct msgb *msg); /* Wrapper around TLV parser to parse BSSGP IEs */ -static inline int bssgp_tlv_parse(struct tlv_parsed *tp, u_int8_t *buf, int len) +static inline int bssgp_tlv_parse(struct tlv_parsed *tp, uint8_t *buf, int len) { return tlv_parse(tp, &tvlv_att_def, buf, len, 0, 0); } diff --git a/openbsc/include/openbsc/gprs_llc.h b/openbsc/include/openbsc/gprs_llc.h index cd4e21523..2ed2d12ea 100644 --- a/openbsc/include/openbsc/gprs_llc.h +++ b/openbsc/include/openbsc/gprs_llc.h @@ -1,6 +1,8 @@ #ifndef _GPRS_LLC_H #define _GPRS_LLC_H +#include + /* Section 4.7 LLC Layer Structure */ enum gprs_llc_sapi { GPRS_SAPI_GMM = 1, @@ -15,6 +17,6 @@ enum gprs_llc_sapi { int gprs_llc_rcvmsg(struct msgb *msg, struct tlv_parsed *tv); -int gprs_llc_tx_ui(struct msgb *msg, u_int8_t sapi, int command); +int gprs_llc_tx_ui(struct msgb *msg, uint8_t sapi, int command); #endif diff --git a/openbsc/include/openbsc/gprs_ns.h b/openbsc/include/openbsc/gprs_ns.h index ca02c4b5d..573536d11 100644 --- a/openbsc/include/openbsc/gprs_ns.h +++ b/openbsc/include/openbsc/gprs_ns.h @@ -1,13 +1,15 @@ #ifndef _GPRS_NS_H #define _GPRS_NS_H +#include + /* GPRS Networks Service (NS) messages on the Gb interface * 3GPP TS 08.16 version 8.0.1 Release 1999 / ETSI TS 101 299 V8.0.1 (2002-05) * 3GPP TS 48.016 version 6.5.0 Release 6 / ETSI TS 148 016 V6.5.0 (2005-11) */ struct gprs_ns_hdr { - u_int8_t pdu_type; - u_int8_t data[0]; + uint8_t pdu_type; + uint8_t data[0]; } __attribute__((packed)); /* TS 08.16, Section 10.3.7, Table 14 */ @@ -95,7 +97,7 @@ enum gprs_ns_evt { struct gprs_nsvc; typedef int gprs_ns_cb_t(enum gprs_ns_evt event, struct gprs_nsvc *nsvc, - struct msgb *msg, u_int16_t bvci); + struct msgb *msg, uint16_t bvci); /* An instance of the NS protocol stack */ struct gprs_ns_inst { @@ -120,11 +122,11 @@ struct gprs_nsvc { struct llist_head list; struct gprs_ns_inst *nsi; - u_int16_t nsei; /* end-to-end significance */ - u_int16_t nsvci; /* uniquely identifies NS-VC at SGSN */ + uint16_t nsei; /* end-to-end significance */ + uint16_t nsvci; /* uniquely identifies NS-VC at SGSN */ - u_int32_t state; - u_int32_t remote_state; + uint32_t state; + uint32_t remote_state; struct timer_list alive_timer; int timer_is_tns_alive; diff --git a/openbsc/include/openbsc/gprs_sgsn.h b/openbsc/include/openbsc/gprs_sgsn.h index 92ce34d42..a3c7c78f4 100644 --- a/openbsc/include/openbsc/gprs_sgsn.h +++ b/openbsc/include/openbsc/gprs_sgsn.h @@ -1,6 +1,8 @@ #ifndef _GPRS_SGSN_H #define _GPRS_SGSN_H +#include + /* TS 04.08 4.1.3.3 GMM mobility management states on the network side */ enum gprs_mm_state { GMM_DEREGISTERED, /* 4.1.3.3.1.1 */ @@ -25,43 +27,43 @@ struct sgsn_mm_ctx { char imsi[GSM_IMSI_LENGTH]; enum gprs_mm_state mm_state; - u_int32_t p_tmsi; - u_int32_t p_tmsi_sig; + uint32_t p_tmsi; + uint32_t p_tmsi_sig; char imei[GSM_IMEI_LENGTH]; /* Opt: Software Version Numbber / TS 23.195 */ char msisdn[GSM_EXTENSION_LENGTH]; struct gprs_ra_id ra; - u_int16_t cell_id; - u_int32_t cell_id_age; - u_int16_t sac; /* Iu: Service Area Code */ - u_int32_t sac_age;/* Iu: Service Area Code age */ + uint16_t cell_id; + uint32_t cell_id_age; + uint16_t sac; /* Iu: Service Area Code */ + uint32_t sac_age;/* Iu: Service Area Code age */ /* VLR number */ - u_int32_t new_sgsn_addr; + uint32_t new_sgsn_addr; /* Authentication Triplets */ /* Kc */ /* Iu: CK, IK, KSI */ /* CKSN */ enum gprs_ciph_algo ciph_algo; struct { - u_int8_t buf[14]; /* 10.5.5.12a */ - u_int8_t len; + uint8_t buf[14]; /* 10.5.5.12a */ + uint8_t len; } ms_radio_access_capa; struct { - u_int8_t buf[4]; /* 10.5.5.12 */ - u_int8_t len; + uint8_t buf[4]; /* 10.5.5.12 */ + uint8_t len; } ms_network_capa; - u_int16_t drx_parms; + uint16_t drx_parms; int mnrg; /* MS reported to HLR? */ int ngaf; /* MS reported to MSC/VLR? */ int ppf; /* paging for GPRS + non-GPRS? */ /* SMS Parameters */ int recovery; - u_int8_t radio_prio_sms; + uint8_t radio_prio_sms; struct llist_head pdp_list; /* Additional bits not present in the GSM TS */ - u_int32_t tlli; + uint32_t tlli; struct timer_list timer; unsigned int T; }; @@ -80,33 +82,33 @@ struct sgsn_pdp_ctx { unsigned int id; enum pdp_ctx_state state; enum pdp_type type; - u_int32_t addresss; + uint32_t addresss; char *apn_subscribed; char *apn_used; - u_int16_t nsapi; - u_int8_t ti; /* transaction identifier */ - u_int32_t ggsn_in_use; + uint16_t nsapi; + uint8_t ti; /* transaction identifier */ + uint32_t ggsn_in_use; int vplmn_allowed; - u_int32_t qos_profile_subscr; - u_int32_t qos_profile_req; - u_int32_t qos_profile_neg; - u_int8_t radio_prio; - u_int32_t tx_npdu_nr; - u_int32_t rx_npdu_nr; - u_int32_t tx_gtp_snd; - u_int32_t rx_gtp_snu; - u_int32_t charging_id; + uint32_t qos_profile_subscr; + uint32_t qos_profile_req; + uint32_t qos_profile_neg; + uint8_t radio_prio; + uint32_t tx_npdu_nr; + uint32_t rx_npdu_nr; + uint32_t tx_gtp_snd; + uint32_t rx_gtp_snu; + uint32_t charging_id; int reordering_reqd; }; /* look-up a SGSN MM context based on TLLI + RAI */ -struct sgsn_mm_ctx *sgsn_mm_ctx_by_tlli(u_int32_t tlli, +struct sgsn_mm_ctx *sgsn_mm_ctx_by_tlli(uint32_t tlli, const struct gprs_ra_id *raid); -struct sgsn_mm_ctx *sgsn_mm_ctx_by_ptmsi(u_int32_t tmsi); +struct sgsn_mm_ctx *sgsn_mm_ctx_by_ptmsi(uint32_t tmsi); struct sgsn_mm_ctx *sgsn_mm_ctx_by_imsi(const char *imsi); /* Allocate a new SGSN MM context */ -struct sgsn_mm_ctx *sgsn_mm_ctx_alloc(u_int32_t tlli, +struct sgsn_mm_ctx *sgsn_mm_ctx_alloc(uint32_t tlli, const struct gprs_ra_id *raid); #endif /* _GPRS_SGSN_H */ diff --git a/openbsc/include/openbsc/gsm_04_08_gprs.h b/openbsc/include/openbsc/gsm_04_08_gprs.h index afc5abc93..7f9aa76e1 100644 --- a/openbsc/include/openbsc/gsm_04_08_gprs.h +++ b/openbsc/include/openbsc/gsm_04_08_gprs.h @@ -1,6 +1,8 @@ #ifndef _GSM48_GPRS_H #define _GSM48_GPRS_H +#include + /* Table 10.4 / 10.4a, GPRS Mobility Management (GMM) */ #define GSM48_MT_GMM_ATTACH_REQ 0x01 #define GSM48_MT_GMM_ATTACH_ACK 0x02 @@ -74,11 +76,11 @@ enum gsm48_gprs_ie_sm { /* Chapter 9.4.15 / Table 9.4.15 */ struct gsm48_ra_upd_ack { - u_int8_t force_stby:4, /* 10.5.5.7 */ + uint8_t force_stby:4, /* 10.5.5.7 */ upd_result:4; /* 10.5.5.17 */ - u_int8_t ra_upd_timer; /* 10.5.7.3 */ + uint8_t ra_upd_timer; /* 10.5.7.3 */ struct gsm48_ra_id ra_id; /* 10.5.5.15 */ - u_int8_t data[0]; + uint8_t data[0]; } __attribute__((packed)); /* Chapter 10.5.7.3 */ @@ -91,29 +93,29 @@ enum gsm48_gprs_tmr_unit { /* Chapter 9.4.2 / Table 9.4.2 */ struct gsm48_attach_ack { - u_int8_t att_result:4, /* 10.5.5.7 */ + uint8_t att_result:4, /* 10.5.5.7 */ force_stby:4; /* 10.5.5.1 */ - u_int8_t ra_upd_timer; /* 10.5.7.3 */ - u_int8_t radio_prio; /* 10.5.7.2 */ + 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 */ - u_int8_t data[0]; + uint8_t data[0]; } __attribute__((packed)); /* Chapter 9.5.1 / Table 9.5.1 */ struct gsm48_act_pdp_ctx_req { - u_int8_t req_nsapi; - u_int8_t req_llc_sapi; - u_int8_t req_qos_lv[4]; - u_int8_t data[0]; + uint8_t req_nsapi; + uint8_t req_llc_sapi; + uint8_t req_qos_lv[4]; + uint8_t data[0]; } __attribute__((packed)); /* Chapter 9.5.2 / Table 9.5.2 */ struct gsm48_act_pdp_ctx_ack { - u_int8_t llc_sapi; - u_int8_t qos_lv[4]; - u_int8_t radio_prio:4, + uint8_t llc_sapi; + uint8_t qos_lv[4]; + uint8_t radio_prio:4, spare:4; - u_int8_t data[0]; + uint8_t data[0]; } __attribute__((packed)); /* Chapter 10.5.5.14 / Table 10.5.147 */ @@ -179,9 +181,9 @@ enum gsm48_pdp_state { PDP_S_MODIFY_PENDING, }; -int gprs_tlli_type(u_int32_t tlli); +int gprs_tlli_type(uint32_t tlli); struct gsm_bts *gsm48_bts_by_ra_id(struct gsm_network *net, - const u_int8_t *buf, unsigned int len); + const uint8_t *buf, unsigned int len); #endif /* _GSM48_GPRS_H */ diff --git a/openbsc/src/gprs_bssgp.c b/openbsc/src/gprs_bssgp.c index 6bba1af8a..a3fa3ecca 100644 --- a/openbsc/src/gprs_bssgp.c +++ b/openbsc/src/gprs_bssgp.c @@ -21,7 +21,7 @@ */ #include -#include +#include #include @@ -147,26 +147,26 @@ static inline struct msgb *bssgp_msgb_alloc(void) } /* Transmit a simple response such as BLOCK/UNBLOCK/RESET ACK/NACK */ -static int bssgp_tx_simple_bvci(u_int8_t pdu_type, u_int16_t nsei, - u_int16_t bvci, u_int16_t ns_bvci) +static int bssgp_tx_simple_bvci(uint8_t pdu_type, uint16_t nsei, + uint16_t bvci, uint16_t ns_bvci) { struct msgb *msg = bssgp_msgb_alloc(); struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph)); - u_int16_t _bvci; + uint16_t _bvci; msgb_nsei(msg) = nsei; msgb_bvci(msg) = ns_bvci; bgph->pdu_type = pdu_type; _bvci = htons(bvci); - msgb_tvlv_put(msg, BSSGP_IE_BVCI, 2, (u_int8_t *) &_bvci); + msgb_tvlv_put(msg, BSSGP_IE_BVCI, 2, (uint8_t *) &_bvci); return gprs_ns_sendmsg(bssgp_nsi, msg); } /* Chapter 10.4.5: Flow Control BVC ACK */ -static int bssgp_tx_fc_bvc_ack(u_int16_t nsei, u_int8_t tag, u_int16_t ns_bvci) +static int bssgp_tx_fc_bvc_ack(uint16_t nsei, uint8_t tag, uint16_t ns_bvci) { struct msgb *msg = bssgp_msgb_alloc(); struct bssgp_normal_hdr *bgph = @@ -182,7 +182,7 @@ static int bssgp_tx_fc_bvc_ack(u_int16_t nsei, u_int8_t tag, u_int16_t ns_bvci) } /* Chapter 10.4.14: Status */ -int bssgp_tx_status(u_int8_t cause, u_int16_t *bvci, struct msgb *orig_msg) +int bssgp_tx_status(uint8_t cause, uint16_t *bvci, struct msgb *orig_msg) { struct msgb *msg = bssgp_msgb_alloc(); struct bssgp_normal_hdr *bgph = @@ -195,8 +195,8 @@ int bssgp_tx_status(u_int8_t cause, u_int16_t *bvci, struct msgb *orig_msg) bgph->pdu_type = BSSGP_PDUT_STATUS; msgb_tvlv_put(msg, BSSGP_IE_CAUSE, 1, &cause); if (bvci) { - u_int16_t _bvci = htons(*bvci); - msgb_tvlv_put(msg, BSSGP_IE_BVCI, 2, (u_int8_t *) &_bvci); + uint16_t _bvci = htons(*bvci); + msgb_tvlv_put(msg, BSSGP_IE_BVCI, 2, (uint8_t *) &_bvci); } if (orig_msg) msgb_tvlv_put(msg, BSSGP_IE_PDU_IN_ERROR, @@ -223,7 +223,7 @@ static int bssgp_rx_bvc_reset(struct msgb *msg, struct tlv_parsed *tp, uint16_t bvci; int rc; - bvci = ntohs(*(u_int16_t *)TLVP_VAL(tp, BSSGP_IE_BVCI)); + bvci = ntohs(*(uint16_t *)TLVP_VAL(tp, BSSGP_IE_BVCI)); DEBUGPC(DGPRS, "BVCI=%u, cause=%s\n", bvci, bssgp_cause_str(*TLVP_VAL(tp, BSSGP_IE_CAUSE))); @@ -413,7 +413,7 @@ int gprs_bssgp_rcvmsg(struct msgb *msg) if (!TLVP_PRESENT(&tp, BSSGP_IE_BVCI) || !TLVP_PRESENT(&tp, BSSGP_IE_CAUSE)) goto err_mand_ie; - bvci = ntohs(*(u_int16_t *)TLVP_VAL(&tp, BSSGP_IE_BVCI)); + bvci = ntohs(*(uint16_t *)TLVP_VAL(&tp, BSSGP_IE_BVCI)); DEBUGPC(DGPRS, "BVCI=%u, cause=%s\n", bvci, bssgp_cause_str(*TLVP_VAL(&tp, BSSGP_IE_CAUSE))); /* We always acknowledge the BLOCKing */ @@ -425,7 +425,7 @@ int gprs_bssgp_rcvmsg(struct msgb *msg) DEBUGP(DGPRS, "BSSGP BVC UNBLOCK "); if (!TLVP_PRESENT(&tp, BSSGP_IE_BVCI)) goto err_mand_ie; - bvci = ntohs(*(u_int16_t *)TLVP_VAL(&tp, BSSGP_IE_BVCI)); + bvci = ntohs(*(uint16_t *)TLVP_VAL(&tp, BSSGP_IE_BVCI)); DEBUGPC(DGPRS, "BVCI=%u\n", bvci); /* We always acknowledge the unBLOCKing */ rc = bssgp_tx_simple_bvci(BSSGP_PDUT_BVC_UNBLOCK_ACK, @@ -485,11 +485,11 @@ int gprs_bssgp_tx_dl_ud(struct msgb *msg) { struct bssgp_bts_ctx *bctx; struct bssgp_ud_hdr *budh; - u_int8_t llc_pdu_tlv_hdr_len = 2; - u_int8_t *llc_pdu_tlv, *qos_profile; - u_int16_t pdu_lifetime = 1000; /* centi-seconds */ - u_int8_t qos_profile_default[3] = { 0x00, 0x00, 0x21 }; - u_int16_t msg_len = msg->len; + uint8_t llc_pdu_tlv_hdr_len = 2; + uint8_t *llc_pdu_tlv, *qos_profile; + uint16_t pdu_lifetime = 1000; /* centi-seconds */ + uint8_t qos_profile_default[3] = { 0x00, 0x00, 0x21 }; + uint16_t msg_len = msg->len; uint16_t bvci = msgb_bvci(msg); uint16_t nsei = msgb_nsei(msg); @@ -522,7 +522,7 @@ int gprs_bssgp_tx_dl_ud(struct msgb *msg) /* prepend the pdu lifetime */ pdu_lifetime = htons(pdu_lifetime); - msgb_tvlv_push(msg, BSSGP_IE_PDU_LIFETIME, 2, (u_int8_t *)&pdu_lifetime); + msgb_tvlv_push(msg, BSSGP_IE_PDU_LIFETIME, 2, (uint8_t *)&pdu_lifetime); /* prepend the QoS profile, TLLI and pdu type */ budh = (struct bssgp_ud_hdr *) msgb_push(msg, sizeof(*budh)); diff --git a/openbsc/src/gprs_llc.c b/openbsc/src/gprs_llc.c index ba031a2ec..fdaa7b3f7 100644 --- a/openbsc/src/gprs_llc.c +++ b/openbsc/src/gprs_llc.c @@ -21,6 +21,7 @@ */ #include +#include #include #include @@ -52,12 +53,12 @@ struct gprs_llc_lle { enum gprs_llc_ll_state state; - u_int32_t tlli; - u_int32_t sapi; + uint32_t tlli; + uint32_t sapi; - u_int8_t v_sent; - u_int8_t v_ack; - u_int8_t v_recv; + uint8_t v_sent; + uint8_t v_ack; + uint8_t v_recv; unsigned int n200; unsigned int retrans_ctr; @@ -113,15 +114,15 @@ enum gprs_llc_cmd { }; struct gprs_llc_hdr_parsed { - u_int8_t sapi; - u_int8_t is_cmd:1, + uint8_t sapi; + uint8_t is_cmd:1, ack_req:1, is_encrypted:1; - u_int32_t seq_rx; - u_int32_t seq_tx; - u_int32_t fcs; - u_int32_t fcs_calc; - u_int8_t *data; + uint32_t seq_rx; + uint32_t seq_tx; + uint32_t fcs; + uint32_t fcs_calc; + uint8_t *data; enum gprs_llc_cmd cmd; }; @@ -130,9 +131,9 @@ struct gprs_llc_hdr_parsed { #define N202 4 #define CRC24_LENGTH 3 -static int gprs_llc_fcs(u_int8_t *data, unsigned int len) +static int gprs_llc_fcs(uint8_t *data, unsigned int len) { - u_int32_t fcs_calc; + uint32_t fcs_calc; fcs_calc = crc24_calc(INIT_CRC24, data, len); fcs_calc = ~fcs_calc; @@ -192,13 +193,13 @@ static void t201_expired(void *data) } /* Transmit a UI frame over the given SAPI */ -int gprs_llc_tx_ui(struct msgb *msg, u_int8_t sapi, int command) +int gprs_llc_tx_ui(struct msgb *msg, uint8_t sapi, int command) { struct gprs_llc_lle *lle; - u_int8_t *fcs, *llch; - u_int8_t addr, ctrl[2]; - u_int32_t fcs_calc; - u_int16_t nu = 0; + uint8_t *fcs, *llch; + uint8_t addr, ctrl[2]; + uint32_t fcs_calc; + uint16_t nu = 0; /* Identifiers from UP: (TLLI, SAPI) + (BVCI, NSEI) */ @@ -291,12 +292,12 @@ static int gprs_llc_hdr_rx(struct gprs_llc_hdr_parsed *gph, /* parse a GPRS LLC header, also check for invalid frames */ static int gprs_llc_hdr_parse(struct gprs_llc_hdr_parsed *ghp, - const u_int8_t *llc_hdr, int len) + const uint8_t *llc_hdr, int len) { - u_int8_t *ctrl = llc_hdr+1; + uint8_t *ctrl = llc_hdr+1; int is_sack = 0; unsigned int crc_length; - u_int32_t fcs_calc; + uint32_t fcs_calc; if (len <= CRC24_LENGTH) return -EIO; @@ -336,7 +337,7 @@ static int gprs_llc_hdr_parse(struct gprs_llc_hdr_parsed *ghp, if ((ctrl[0] & 0x80) == 0) { /* I (Information transfer + Supervisory) format */ - u_int8_t k; + uint8_t k; ghp->data = ctrl + 3; diff --git a/openbsc/src/gprs_ns.c b/openbsc/src/gprs_ns.c index 1558ca146..0db06c3f0 100644 --- a/openbsc/src/gprs_ns.c +++ b/openbsc/src/gprs_ns.c @@ -47,7 +47,7 @@ #include #include #include -#include +#include #include @@ -74,7 +74,7 @@ static const struct tlv_definition ns_att_tlvdef = { /* Lookup struct gprs_nsvc based on NSVCI */ static struct gprs_nsvc *nsvc_by_nsvci(struct gprs_ns_inst *nsi, - u_int16_t nsvci) + uint16_t nsvci) { struct gprs_nsvc *nsvc; llist_for_each_entry(nsvc, &nsi->gprs_nsvcs, list) { @@ -86,7 +86,7 @@ static struct gprs_nsvc *nsvc_by_nsvci(struct gprs_ns_inst *nsi, /* Lookup struct gprs_nsvc based on NSVCI */ static struct gprs_nsvc *nsvc_by_nsei(struct gprs_ns_inst *nsi, - u_int16_t nsei) + uint16_t nsei) { struct gprs_nsvc *nsvc; llist_for_each_entry(nsvc, &nsi->gprs_nsvcs, list) { @@ -109,7 +109,7 @@ static struct gprs_nsvc *nsvc_by_rem_addr(struct gprs_ns_inst *nsi, return NULL; } -static struct gprs_nsvc *nsvc_create(struct gprs_ns_inst *nsi, u_int16_t nsvci) +static struct gprs_nsvc *nsvc_create(struct gprs_ns_inst *nsi, uint16_t nsvci) { struct gprs_nsvc *nsvc; @@ -163,7 +163,7 @@ static int gprs_ns_tx(struct gprs_nsvc *nsvc, struct msgb *msg) return ret; } -static int gprs_ns_tx_simple(struct gprs_nsvc *nsvc, u_int8_t pdu_type) +static int gprs_ns_tx_simple(struct gprs_nsvc *nsvc, uint8_t pdu_type) { struct msgb *msg = msgb_alloc(NS_ALLOC_SIZE, "GPRS/NS"); struct gprs_ns_hdr *nsh; @@ -211,7 +211,7 @@ static int gprs_ns_tx_reset_ack(struct gprs_nsvc *nsvc) { struct msgb *msg = msgb_alloc(NS_ALLOC_SIZE, "GPRS/NS"); struct gprs_ns_hdr *nsh; - u_int16_t nsvci, nsei; + uint16_t nsvci, nsei; if (!msg) return -ENOMEM; @@ -225,8 +225,8 @@ static int gprs_ns_tx_reset_ack(struct gprs_nsvc *nsvc) DEBUGP(DGPRS, "nsvci=%u, nsei=%u\n", nsvc->nsvci, nsvc->nsei); - msgb_tvlv_put(msg, NS_IE_VCI, 2, (u_int8_t *)&nsvci); - msgb_tvlv_put(msg, NS_IE_NSEI, 2, (u_int8_t *)&nsei); + msgb_tvlv_put(msg, NS_IE_VCI, 2, (uint8_t *)&nsvci); + msgb_tvlv_put(msg, NS_IE_NSEI, 2, (uint8_t *)&nsei); return gprs_ns_tx(nsvc, msg); } @@ -236,7 +236,7 @@ int gprs_ns_sendmsg(struct gprs_ns_inst *nsi, struct msgb *msg) { struct gprs_nsvc *nsvc; struct gprs_ns_hdr *nsh; - u_int16_t bvci = msgb_bvci(msg); + uint16_t bvci = msgb_bvci(msg); nsvc = nsvc_by_nsei(nsi, msgb_nsei(msg)); if (!nsvc) { @@ -262,7 +262,7 @@ int gprs_ns_sendmsg(struct gprs_ns_inst *nsi, struct msgb *msg) static int gprs_ns_rx_unitdata(struct gprs_nsvc *nsvc, struct msgb *msg) { struct gprs_ns_hdr *nsh = (struct gprs_ns_hdr *)msg->l2h; - u_int16_t bvci; + uint16_t bvci; /* spare octet in data[0] */ bvci = nsh->data[1] << 8 | nsh->data[2]; @@ -278,7 +278,7 @@ static int gprs_ns_rx_status(struct gprs_nsvc *nsvc, struct msgb *msg) { struct gprs_ns_hdr *nsh = (struct gprs_ns_hdr *) msg->l2h; struct tlv_parsed tp; - u_int8_t cause; + uint8_t cause; int rc; DEBUGP(DGPRS, "NS STATUS "); @@ -301,8 +301,8 @@ static int gprs_ns_rx_reset(struct gprs_nsvc *nsvc, struct msgb *msg) { struct gprs_ns_hdr *nsh = (struct gprs_ns_hdr *) msg->l2h; struct tlv_parsed tp; - u_int8_t *cause; - u_int16_t *nsvci, *nsei; + uint8_t *cause; + uint16_t *nsvci, *nsei; int rc; DEBUGP(DGPRS, "NS RESET "); @@ -317,9 +317,9 @@ static int gprs_ns_rx_reset(struct gprs_nsvc *nsvc, struct msgb *msg) return -EINVAL; } - cause = (u_int8_t *) TLVP_VAL(&tp, NS_IE_CAUSE); - nsvci = (u_int16_t *) TLVP_VAL(&tp, NS_IE_VCI); - nsei = (u_int16_t *) TLVP_VAL(&tp, NS_IE_NSEI); + cause = (uint8_t *) TLVP_VAL(&tp, NS_IE_CAUSE); + nsvci = (uint16_t *) TLVP_VAL(&tp, NS_IE_VCI); + nsei = (uint16_t *) TLVP_VAL(&tp, NS_IE_NSEI); nsvc->state = NSE_S_BLOCKED | NSE_S_ALIVE; nsvc->nsei = ntohs(*nsei); @@ -517,7 +517,7 @@ static int nsip_fd_cb(struct bsc_fd *bfd, unsigned int what) /* FIXME: this is currently in input/ipaccess.c */ -extern int make_sock(struct bsc_fd *bfd, int proto, u_int16_t port, +extern int make_sock(struct bsc_fd *bfd, int proto, uint16_t port, int (*cb)(struct bsc_fd *fd, unsigned int what)); /* Listen for incoming GPRS packets */ diff --git a/openbsc/src/gprs_sgsn.c b/openbsc/src/gprs_sgsn.c index 9844f8808..ba4671955 100644 --- a/openbsc/src/gprs_sgsn.c +++ b/openbsc/src/gprs_sgsn.c @@ -20,7 +20,7 @@ * */ -#include +#include #include #include @@ -41,7 +41,7 @@ static int ra_id_equals(const struct gprs_ra_id *id1, } /* look-up a SGSN MM context based on TLLI + RAI */ -struct sgsn_mm_ctx *sgsn_mm_ctx_by_tlli(u_int32_t tlli, +struct sgsn_mm_ctx *sgsn_mm_ctx_by_tlli(uint32_t tlli, const struct gprs_ra_id *raid) { struct sgsn_mm_ctx *ctx; @@ -54,7 +54,7 @@ struct sgsn_mm_ctx *sgsn_mm_ctx_by_tlli(u_int32_t tlli, return NULL; } -struct sgsn_mm_ctx *sgsn_mm_ctx_by_ptmsi(u_int32_t p_tmsi) +struct sgsn_mm_ctx *sgsn_mm_ctx_by_ptmsi(uint32_t p_tmsi) { struct sgsn_mm_ctx *ctx; @@ -78,7 +78,7 @@ struct sgsn_mm_ctx *sgsn_mm_ctx_by_imsi(const char *imsi) } /* Allocate a new SGSN MM context */ -struct sgsn_mm_ctx *sgsn_mm_ctx_alloc(u_int32_t tlli, +struct sgsn_mm_ctx *sgsn_mm_ctx_alloc(uint32_t tlli, const struct gprs_ra_id *raid) { struct sgsn_mm_ctx *ctx = talloc_zero(NULL, struct sgsn_mm_ctx); diff --git a/openbsc/src/gsm_04_08_gprs.c b/openbsc/src/gsm_04_08_gprs.c index db439daa7..7d2465730 100644 --- a/openbsc/src/gsm_04_08_gprs.c +++ b/openbsc/src/gsm_04_08_gprs.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -97,7 +98,7 @@ struct value_string gsm_cause_names[] = { { 0, NULL } }; -static const char *att_name(u_int8_t type) +static const char *att_name(uint8_t type) { switch (type) { case GPRS_ATT_T_ATTACH: @@ -111,7 +112,7 @@ static const char *att_name(u_int8_t type) } } -static const char *upd_name(u_int8_t type) +static const char *upd_name(uint8_t type) { switch (type) { case GPRS_UPD_T_RA: @@ -160,7 +161,7 @@ static int gsm48_tx_gmm_att_ack(struct msgb *old_msg) } /* Chapter 9.4.5: Attach reject */ -static int gsm48_tx_gmm_att_rej(struct msgb *old_msg, u_int8_t gmm_cause) +static int gsm48_tx_gmm_att_rej(struct msgb *old_msg, uint8_t gmm_cause) { struct msgb *msg = gsm48_msgb_alloc(); struct gsm48_hdr *gh; @@ -179,7 +180,7 @@ static int gsm48_tx_gmm_att_rej(struct msgb *old_msg, u_int8_t gmm_cause) } /* Transmit Chapter 9.4.12 Identity Request */ -static int gsm48_tx_gmm_id_req(struct msgb *old_msg, u_int8_t id_type) +static int gsm48_tx_gmm_id_req(struct msgb *old_msg, uint8_t id_type) { struct msgb *msg = gsm48_msgb_alloc(); struct gsm48_hdr *gh; @@ -218,7 +219,7 @@ static int gsm48_gmm_authorize(struct sgsn_mm_ctx *ctx, struct msgb *msg) static int gsm48_rx_gmm_id_resp(struct msgb *msg) { struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg); - u_int8_t mi_type = gh->data[1] & GSM_MI_TYPE_MASK; + uint8_t mi_type = gh->data[1] & GSM_MI_TYPE_MASK; char mi_string[GSM48_MI_SIZE]; struct gprs_ra_id ra_id; struct sgsn_mm_ctx *ctx; @@ -275,10 +276,10 @@ static void schedule_reject(struct sgsn_mm_ctx *ctx) static int gsm48_rx_gmm_att_req(struct msgb *msg) { struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg); - u_int8_t *cur = gh->data, *msnc, *mi, *old_ra_info; - u_int8_t msnc_len, att_type, mi_len, mi_type; - u_int16_t drx_par; - u_int32_t tmsi; + uint8_t *cur = gh->data, *msnc, *mi, *old_ra_info; + uint8_t msnc_len, att_type, mi_len, mi_type; + uint16_t drx_par; + uint32_t tmsi; char mi_string[GSM48_MI_SIZE]; struct gprs_ra_id ra_id; struct sgsn_mm_ctx *ctx; @@ -398,7 +399,7 @@ static int gsm48_tx_gmm_ra_upd_ack(struct msgb *old_msg) } /* Chapter 9.4.17: Routing area update reject */ -static int gsm48_tx_gmm_ra_upd_rej(struct msgb *old_msg, u_int8_t cause) +static int gsm48_tx_gmm_ra_upd_rej(struct msgb *old_msg, uint8_t cause) { struct msgb *msg = gsm48_msgb_alloc(); struct gsm48_hdr *gh; @@ -423,9 +424,9 @@ static int gsm48_rx_gmm_ra_upd_req(struct msgb *msg) { struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg); struct sgsn_mm_ctx *mmctx; - u_int8_t *cur = gh->data; + uint8_t *cur = gh->data; struct gprs_ra_id old_ra_id; - u_int8_t upd_type; + uint8_t upd_type; /* Update Type 10.5.5.18 */ upd_type = *cur++ & 0x0f; @@ -524,7 +525,7 @@ static int gsm48_tx_gsm_act_pdp_acc(struct msgb *old_msg, struct gsm48_act_pdp_c struct msgb *msg = gsm48_msgb_alloc(); struct gsm48_act_pdp_ctx_ack *act_ack; struct gsm48_hdr *gh; - u_int8_t transaction_id = ((old_gh->proto_discr >> 4) ^ 0x8); /* flip */ + uint8_t transaction_id = ((old_gh->proto_discr >> 4) ^ 0x8); /* flip */ DEBUGP(DMM, "<- ACTIVATE PDP CONTEXT ACK\n"); @@ -549,7 +550,7 @@ static int gsm48_tx_gsm_deact_pdp_acc(struct msgb *old_msg) struct gsm48_hdr *old_gh = (struct gsm48_hdr *) msgb_gmmh(old_msg); struct msgb *msg = gsm48_msgb_alloc(); struct gsm48_hdr *gh; - u_int8_t transaction_id = ((old_gh->proto_discr >> 4) ^ 0x8); /* flip */ + uint8_t transaction_id = ((old_gh->proto_discr >> 4) ^ 0x8); /* flip */ DEBUGP(DMM, "<- DEACTIVATE PDP CONTEXT ACK\n"); @@ -568,7 +569,7 @@ static int gsm48_rx_gsm_act_pdp_req(struct msgb *msg) { struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg); struct gsm48_act_pdp_ctx_req *act_req = (struct gsm48_act_pdp_ctx_req *) gh->data; - u_int8_t *pdp_addr_lv = act_req->data; + uint8_t *pdp_addr_lv = act_req->data; DEBUGP(DMM, "ACTIVATE PDP CONTEXT REQ\n"); @@ -633,7 +634,7 @@ static int gsm0408_rcv_gsm(struct msgb *msg) int gsm0408_gprs_rcvmsg(struct msgb *msg) { struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg); - u_int8_t pdisc = gh->proto_discr & 0x0f; + uint8_t pdisc = gh->proto_discr & 0x0f; int rc = -EINVAL; switch (pdisc) { @@ -654,7 +655,7 @@ int gsm0408_gprs_rcvmsg(struct msgb *msg) /* Determine the 'struct gsm_bts' from a RA ID */ struct gsm_bts *gsm48_bts_by_ra_id(struct gsm_network *net, - const u_int8_t *buf, unsigned int len) + const uint8_t *buf, unsigned int len) { struct gprs_ra_id raid; struct gsm_bts *bts; -- cgit v1.2.3 From 11d7c105f8693daf91f533064e415d723768af3b Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 2 May 2010 11:54:55 +0200 Subject: [gprs] pass BSSGP UL-UNITDATA Cell ID up into GMM layer BSSGP stores a pointer to the Cell Identifier IE in msgb->cb, which is later used by the GMM layer to identify the cell that has sent a given message. This now also means that the gsm_04_08_gprs.c code is free of any legacy references to msg->trx or struct gsm_bts. --- openbsc/include/openbsc/gprs_bssgp.h | 1 + openbsc/include/openbsc/gsm_data.h | 4 ++ openbsc/src/gprs_bssgp.c | 11 +++--- openbsc/src/gprs_llc.c | 2 + openbsc/src/gsm_04_08_gprs.c | 72 ++++++++++++++---------------------- 5 files changed, 40 insertions(+), 50 deletions(-) diff --git a/openbsc/include/openbsc/gprs_bssgp.h b/openbsc/include/openbsc/gprs_bssgp.h index c70868af3..c1094b351 100644 --- a/openbsc/include/openbsc/gprs_bssgp.h +++ b/openbsc/include/openbsc/gprs_bssgp.h @@ -140,6 +140,7 @@ enum gprs_bssgp_cause { #include extern int gprs_bssgp_rcvmsg(struct msgb *msg); +uint16_t bssgp_parse_cell_id(struct gprs_ra_id *raid, const uint8_t *buf); /* Wrapper around TLV parser to parse BSSGP IEs */ static inline int bssgp_tlv_parse(struct tlv_parsed *tp, uint8_t *buf, int len) diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index 3dd7a18c2..ac0426556 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -84,6 +84,9 @@ struct openbsc_msgb_cb { unsigned char *bssgph; unsigned char *llch; + /* Cell Identifier */ + unsigned char *bssgp_cell_id; + /* Identifiers of a BTS, equal to 'struct bssgp_bts_ctx' */ u_int16_t nsei; u_int16_t bvci; @@ -97,6 +100,7 @@ struct openbsc_msgb_cb { #define msgb_bvci(__x) OBSC_MSGB_CB(__x)->bvci #define msgb_gmmh(__x) (__x)->l3h #define msgb_bssgph(__x) OBSC_MSGB_CB(__x)->bssgph +#define msgb_bcid(__x) OBSC_MSGB_CB(__x)->bssgp_cell_id #define msgb_llch(__x) OBSC_MSGB_CB(__x)->llch struct msgb; diff --git a/openbsc/src/gprs_bssgp.c b/openbsc/src/gprs_bssgp.c index a3fa3ecca..aceedb589 100644 --- a/openbsc/src/gprs_bssgp.c +++ b/openbsc/src/gprs_bssgp.c @@ -205,13 +205,12 @@ int bssgp_tx_status(uint8_t cause, uint16_t *bvci, struct msgb *orig_msg) return gprs_ns_sendmsg(bssgp_nsi, msg); } -static void bssgp_parse_cell_id(struct gprs_ra_id *raid, uint16_t *cid, - const uint8_t *buf) +uint16_t bssgp_parse_cell_id(struct gprs_ra_id *raid, const uint8_t *buf) { /* 6 octets RAC */ gsm48_parse_ra(raid, buf); /* 2 octets CID */ - *cid = ntohs(*(uint16_t *) (buf+6)); + return ntohs(*(uint16_t *) (buf+6)); } /* Chapter 8.4 BVC-Reset Procedure */ @@ -241,8 +240,8 @@ static int bssgp_rx_bvc_reset(struct msgb *msg, struct tlv_parsed *tp, return -EINVAL; } /* actually extract RAC / CID */ - bssgp_parse_cell_id(&bctx->ra_id, &bctx->cell_id, - TLVP_VAL(tp, BSSGP_IE_CELL_ID)); + bctx->cell_id = bssgp_parse_cell_id(&bctx->ra_id, + TLVP_VAL(tp, BSSGP_IE_CELL_ID)); LOGP(DGPRS, LOGL_NOTICE, "Cell %u-%u-%u-%u CI %u on BVCI %u\n", bctx->ra_id.mcc, bctx->ra_id.mnc, bctx->ra_id.lac, bctx->ra_id.rac, bctx->cell_id, bvci); @@ -275,7 +274,9 @@ static int bssgp_rx_ul_ud(struct msgb *msg) /* FIXME: lookup bssgp_bts_ctx based on BVCI + NSEI */ + /* store pointer to LLC header and CELL ID in msgb->cb */ msgb_llch(msg) = TLVP_VAL(&tp, BSSGP_IE_LLC_PDU); + msgb_bcid(msg) = TLVP_VAL(&tp, BSSGP_IE_CELL_ID); return gprs_llc_rcvmsg(msg, &tp); } diff --git a/openbsc/src/gprs_llc.c b/openbsc/src/gprs_llc.c index fdaa7b3f7..6d1563621 100644 --- a/openbsc/src/gprs_llc.c +++ b/openbsc/src/gprs_llc.c @@ -452,6 +452,8 @@ int gprs_llc_rcvmsg(struct msgb *msg, struct tlv_parsed *tv) struct gprs_llc_entity *lle; int rc = 0; + /* Identifiers from DOWN: NSEI, BVCI, TLLI */ + rc = gprs_llc_hdr_parse(&llhp, lh, TLVP_LEN(tv, BSSGP_IE_LLC_PDU)); /* FIXME */ diff --git a/openbsc/src/gsm_04_08_gprs.c b/openbsc/src/gsm_04_08_gprs.c index 7d2465730..ef61adecc 100644 --- a/openbsc/src/gsm_04_08_gprs.c +++ b/openbsc/src/gsm_04_08_gprs.c @@ -42,6 +42,7 @@ #include #include #include +#include #include #include @@ -130,20 +131,30 @@ static const char *upd_name(uint8_t type) /* Send a message through the underlying layer */ static int gsm48_gmm_sendmsg(struct msgb *msg, int command) { + /* caller needs to provide TLLI, BVCI and NSEI */ return gprs_llc_tx_ui(msg, GPRS_SAPI_GMM, command); } +/* copy identifiers from old message to new message, this + * is required so lower layers can route it correctly */ +static void gmm_copy_id(struct msgb *msg, const struct msgb *old) +{ + msgb_tlli(msg) = msgb_tlli(old); + msgb_bvci(msg) = msgb_bvci(old); + msgb_nsei(msg) = msgb_nsei(old); +} + /* Chapter 9.4.2: Attach accept */ static int gsm48_tx_gmm_att_ack(struct msgb *old_msg) { struct msgb *msg = gsm48_msgb_alloc(); struct gsm48_hdr *gh; struct gsm48_attach_ack *aa; + struct gprs_ra_id ra_id; DEBUGP(DMM, "<- GPRS ATTACH ACCEPT\n"); - msgb_tlli(msg) = msgb_tlli(old_msg); - msg->trx = old_msg->trx; + gmm_copy_id(msg, old_msg); gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh)); gh->proto_discr = GSM48_PDISC_MM_GPRS; @@ -154,7 +165,8 @@ static int gsm48_tx_gmm_att_ack(struct msgb *old_msg) aa->att_result = 1; /* GPRS only */ aa->ra_upd_timer = GPRS_TMR_MINUTE | 10; aa->radio_prio = 4; /* lowest */ - //FIXME gsm48_ra_id_by_bts(aa->ra_id.digits, old_msg->trx->bts); + bssgp_parse_cell_id(&ra_id, msgb_bcid(msg)); + gsm48_construct_ra(aa->ra_id.digits, &ra_id); /* Option: P-TMSI signature, allocated P-TMSI, MS ID, ... */ return gsm48_gmm_sendmsg(msg, 0); @@ -168,8 +180,7 @@ static int gsm48_tx_gmm_att_rej(struct msgb *old_msg, uint8_t gmm_cause) DEBUGP(DMM, "<- GPRS ATTACH REJECT\n"); - msgb_tlli(msg) = msgb_tlli(old_msg); - msg->trx = old_msg->trx; + gmm_copy_id(msg, old_msg); gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1); gh->proto_discr = GSM48_PDISC_MM_GPRS; @@ -187,8 +198,7 @@ static int gsm48_tx_gmm_id_req(struct msgb *old_msg, uint8_t id_type) DEBUGP(DMM, "-> GPRS IDENTITY REQUEST: mi_type=%02x\n", id_type); - msgb_tlli(msg) = msgb_tlli(old_msg); - msg->trx = old_msg->trx; + gmm_copy_id(msg, old_msg); gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1); gh->proto_discr = GSM48_PDISC_MM_GPRS; @@ -228,7 +238,7 @@ static int gsm48_rx_gmm_id_resp(struct msgb *msg) DEBUGP(DMM, "GMM IDENTITY RESPONSE: mi_type=0x%02x MI(%s) ", mi_type, mi_string); - //FIXME gprs_ra_id_by_bts(&ra_id, msg->trx->bts); + bssgp_parse_cell_id(&ra_id, msgb_bcid(msg)); ctx = sgsn_mm_ctx_by_tlli(msgb_tlli(msg), &ra_id); if (!ctx) { DEBUGP(DMM, "from unknown TLLI 0x%08x?!?\n", msgb_tlli(msg)); @@ -290,7 +300,7 @@ static int gsm48_rx_gmm_att_req(struct msgb *msg) * with a foreign TLLI (P-TMSI that was allocated to the MS before), * or with random TLLI. */ - //FIXME gprs_ra_id_by_bts(&ra_id, msg->trx->bts); + bssgp_parse_cell_id(&ra_id, msgb_bcid(msg)); /* MS network capability 10.5.5.12 */ msnc_len = *cur++; @@ -378,11 +388,11 @@ static int gsm48_tx_gmm_ra_upd_ack(struct msgb *old_msg) struct msgb *msg = gsm48_msgb_alloc(); struct gsm48_hdr *gh; struct gsm48_ra_upd_ack *rua; + struct gprs_ra_id ra_id; DEBUGP(DMM, "<- ROUTING AREA UPDATE ACCEPT\n"); - msgb_tlli(msg) = msgb_tlli(old_msg); - msg->trx = old_msg->trx; + gmm_copy_id(msg, old_msg); gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh)); gh->proto_discr = GSM48_PDISC_MM_GPRS; @@ -392,7 +402,9 @@ static int gsm48_tx_gmm_ra_upd_ack(struct msgb *old_msg) rua->force_stby = 0; /* not indicated */ rua->upd_result = 0; /* RA updated */ rua->ra_upd_timer = GPRS_TMR_MINUTE | 10; - //FIXME gsm48_ra_id_by_bts(rua->ra_id.digits, old_msg->trx->bts); + + bssgp_parse_cell_id(&ra_id, msgb_bcid(msg)); + gsm48_construct_ra(rua->ra_id.digits, &ra_id); /* Option: P-TMSI signature, allocated P-TMSI, MS ID, ... */ return gsm48_gmm_sendmsg(msg, 0); @@ -406,8 +418,7 @@ static int gsm48_tx_gmm_ra_upd_rej(struct msgb *old_msg, uint8_t cause) DEBUGP(DMM, "<- ROUTING AREA UPDATE REJECT\n"); - msgb_tlli(msg) = msgb_tlli(old_msg); - msg->trx = old_msg->trx; + gmm_copy_id(msg, old_msg); gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 2); gh->proto_discr = GSM48_PDISC_MM_GPRS; @@ -529,8 +540,7 @@ static int gsm48_tx_gsm_act_pdp_acc(struct msgb *old_msg, struct gsm48_act_pdp_c DEBUGP(DMM, "<- ACTIVATE PDP CONTEXT ACK\n"); - msgb_tlli(msg) = msgb_tlli(old_msg); - msg->trx = old_msg->trx; + gmm_copy_id(msg, old_msg); gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh)); gh->proto_discr = GSM48_PDISC_SM_GPRS | (transaction_id << 4); @@ -554,8 +564,7 @@ static int gsm48_tx_gsm_deact_pdp_acc(struct msgb *old_msg) DEBUGP(DMM, "<- DEACTIVATE PDP CONTEXT ACK\n"); - msgb_tlli(msg) = msgb_tlli(old_msg); - msg->trx = old_msg->trx; + gmm_copy_id(msg, old_msg); gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh)); gh->proto_discr = GSM48_PDISC_SM_GPRS | (transaction_id << 4); @@ -652,30 +661,3 @@ int gsm0408_gprs_rcvmsg(struct msgb *msg) return rc; } - -/* Determine the 'struct gsm_bts' from a RA ID */ -struct gsm_bts *gsm48_bts_by_ra_id(struct gsm_network *net, - const uint8_t *buf, unsigned int len) -{ - struct gprs_ra_id raid; - struct gsm_bts *bts; - - if (len < 6) - return NULL; - - gsm48_parse_ra(&raid, buf); - - if (net->country_code != raid.mcc || - net->network_code != raid.mnc) - return NULL; - - llist_for_each_entry(bts, &net->bts_list, list) { - /* FIXME: we actually also need to check the - * routing area code! */ - if (bts->location_area_code == raid.lac) - return bts; - } - - return NULL; -} - -- cgit v1.2.3 From 9f1f3ad7bb2826057292bfc9a29245041aeff9b5 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 2 May 2010 12:56:57 +0200 Subject: [gprs] GMM: update MM context RA ID / TLLI when appropriate --- openbsc/src/gsm_04_08_gprs.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/openbsc/src/gsm_04_08_gprs.c b/openbsc/src/gsm_04_08_gprs.c index ef61adecc..1980c2266 100644 --- a/openbsc/src/gsm_04_08_gprs.c +++ b/openbsc/src/gsm_04_08_gprs.c @@ -1,7 +1,7 @@ /* GSM Mobile Radio Interface Layer 3 messages on the A-bis interface * 3GPP TS 04.08 version 7.21.0 Release 1998 / ETSI TS 100 940 V7.21.0 */ -/* (C) 2009 by Harald Welte +/* (C) 2009-2010 by Harald Welte * * All Rights Reserved * @@ -292,6 +292,7 @@ static int gsm48_rx_gmm_att_req(struct msgb *msg) uint32_t tmsi; char mi_string[GSM48_MI_SIZE]; struct gprs_ra_id ra_id; + uint16_t cid; struct sgsn_mm_ctx *ctx; DEBUGP(DMM, "GMM ATTACH REQUEST "); @@ -300,7 +301,7 @@ static int gsm48_rx_gmm_att_req(struct msgb *msg) * with a foreign TLLI (P-TMSI that was allocated to the MS before), * or with random TLLI. */ - bssgp_parse_cell_id(&ra_id, msgb_bcid(msg)); + cid = bssgp_parse_cell_id(&ra_id, msgb_bcid(msg)); /* MS network capability 10.5.5.12 */ msnc_len = *cur++; @@ -367,8 +368,11 @@ static int gsm48_rx_gmm_att_req(struct msgb *msg) } break; default: - break; + return 0; } + /* Update MM Context with currient RA and Cell ID */ + ctx->ra = ra_id; + ctx->cell_id = cid; /* FIXME: allocate a new P-TMSI (+ P-TMSI signature) */ /* FIXME: update the TLLI with the new local TLLI based on the P-TMSI */ @@ -472,8 +476,10 @@ static int gsm48_rx_gmm_ra_upd_req(struct msgb *msg) return gsm48_tx_gmm_ra_upd_rej(msg, GMM_CAUSE_IMPL_DETACHED); } - /* FIXME: Update the MM context with the new RA-ID */ - /* FIXME: Update the MM context with the new TLLI */ + /* Update the MM context with the new RA-ID */ + bssgp_parse_cell_id(&mmctx->ra, msgb_bcid(msg)); + /* Update the MM context with the new TLLI */ + mmctx->tlli = msgb_tlli(msg); /* FIXME: Update the MM context with the MS radio acc capabilities */ /* FIXME: Update the MM context with the MS network capabilities */ -- cgit v1.2.3 From d60570991fd5a5454306752af8eb4b37c2ce5b6e Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 2 May 2010 12:57:45 +0200 Subject: [gprs] header file ordering (cosmetic) --- openbsc/src/gsm_04_08_gprs.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/openbsc/src/gsm_04_08_gprs.c b/openbsc/src/gsm_04_08_gprs.c index 1980c2266..8dc96a22a 100644 --- a/openbsc/src/gsm_04_08_gprs.c +++ b/openbsc/src/gsm_04_08_gprs.c @@ -32,15 +32,16 @@ #include #include #include +#include +#include +#include + #include #include -#include #include #include #include #include -#include -#include #include #include #include -- cgit v1.2.3 From 0c3eae0011af64f3fdf8619bfaf97bc459bc5c11 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 2 May 2010 21:07:14 +0200 Subject: [gprs] GMM: print more details about PDP context activation request --- openbsc/include/openbsc/gsm_04_08_gprs.h | 1 - openbsc/src/gsm_04_08_gprs.c | 47 ++++++++++++++++++++++++++++++-- 2 files changed, 44 insertions(+), 4 deletions(-) diff --git a/openbsc/include/openbsc/gsm_04_08_gprs.h b/openbsc/include/openbsc/gsm_04_08_gprs.h index 7f9aa76e1..86adea156 100644 --- a/openbsc/include/openbsc/gsm_04_08_gprs.h +++ b/openbsc/include/openbsc/gsm_04_08_gprs.h @@ -105,7 +105,6 @@ struct gsm48_attach_ack { struct gsm48_act_pdp_ctx_req { uint8_t req_nsapi; uint8_t req_llc_sapi; - uint8_t req_qos_lv[4]; uint8_t data[0]; } __attribute__((packed)); diff --git a/openbsc/src/gsm_04_08_gprs.c b/openbsc/src/gsm_04_08_gprs.c index 8dc96a22a..c0fe45de2 100644 --- a/openbsc/src/gsm_04_08_gprs.c +++ b/openbsc/src/gsm_04_08_gprs.c @@ -555,7 +555,7 @@ static int gsm48_tx_gsm_act_pdp_acc(struct msgb *old_msg, struct gsm48_act_pdp_c act_ack = (struct gsm48_act_pdp_ctx_ack *) msgb_put(msg, sizeof(*act_ack)); act_ack->llc_sapi = req->req_llc_sapi; - memcpy(act_ack->qos_lv, req->req_qos_lv, sizeof(act_ack->qos_lv)); + memcpy(act_ack->qos_lv, req->data, sizeof(act_ack->qos_lv)); //act_ack->radio_prio = 4; return gsm48_gmm_sendmsg(msg, 0); @@ -586,10 +586,51 @@ static int gsm48_rx_gsm_act_pdp_req(struct msgb *msg) struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg); struct gsm48_act_pdp_ctx_req *act_req = (struct gsm48_act_pdp_ctx_req *) gh->data; uint8_t *pdp_addr_lv = act_req->data; + uint8_t req_qos_len, req_pdpa_len; + uint8_t *req_qos, *req_pdpa; + struct tlv_parsed tp; + + DEBUGP(DMM, "ACTIVATE PDP CONTEXT REQ: "); + req_qos_len = act_req->data[0]; + req_qos = act_req->data + 1; /* 10.5.6.5 */ + req_pdpa_len = act_req->data[1 + req_qos_len]; + req_pdpa = act_req->data + 1 + req_qos_len + 1; /* 10.5.6.4 */ + + switch (req_pdpa[0] & 0xf) { + case 0x0: + DEBUGPC(DMM, "ETSI "); + break; + case 0x1: + DEBUGPC(DMM, "IETF "); + break; + case 0xf: + DEBUGPC(DMM, "Empty "); + break; + } - DEBUGP(DMM, "ACTIVATE PDP CONTEXT REQ\n"); + switch (req_pdpa[1]) { + case 0x21: + DEBUGPC(DMM, "IPv4 "); + if (req_pdpa_len >= 6) { + struct in_addr ia; + ia.s_addr = ntohl(*((uint32_t *) (req_pdpa+2))); + DEBUGPC(DMM, "%s ", inet_ntoa(ia)); + } + break; + case 0x57: + DEBUGPC(DMM, "IPv6 "); + if (req_pdpa_len >= 18) { + /* FIXME: print IPv6 address */ + } + break; + default: + DEBUGPC(DMM, "0x%02x ", req_pdpa[1]); + break; + } - /* FIXME: parse access point name + IPCP config options */ + /* FIXME: parse TLV for AP name and protocol config options */ + if (TLVP_PRESENT(&tp, GSM48_IE_GSM_APN)) {} + if (TLVP_PRESENT(&tp, GSM48_IE_GSM_PROTO_CONF_OPT)) {} return gsm48_tx_gsm_act_pdp_acc(msg, act_req); } -- cgit v1.2.3 From d6c7416c32f5d68f66c83d5b8f37ab3fa0cc148d Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 2 May 2010 21:29:17 +0200 Subject: [gprs] correctly set the NS instance that BSSGP should use --- openbsc/src/sgsn_main.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/openbsc/src/sgsn_main.c b/openbsc/src/sgsn_main.c index 66d8efc4b..d9ea6a8cf 100644 --- a/openbsc/src/sgsn_main.c +++ b/openbsc/src/sgsn_main.c @@ -89,6 +89,8 @@ static int sgsn_ns_cb(enum gprs_ns_evt event, struct gprs_nsvc *nsvc, return rc; } +/* NSI that BSSGP uses when transmitting on NS */ +extern struct gprs_ns_inst *bssgp_nsi; int main(int argc, char **argv) { @@ -116,7 +118,7 @@ int main(int argc, char **argv) LOGP(DGPRS, LOGL_ERROR, "Unable to instantiate NS\n"); exit(1); } - sgcfg.nsi = sgsn_nsi; + bssgp_nsi = sgcfg.nsi = sgsn_nsi; nsip_listen(sgsn_nsi, sgcfg.nsip_listen_port); while (1) { -- cgit v1.2.3 From 721961cf5006e9376cdf2a60041ccb241d61edad Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 2 May 2010 21:29:36 +0200 Subject: [gprs] correctly calculate the length of the BSSGP PDUs --- openbsc/include/openbsc/gsm_data.h | 1 + openbsc/src/gprs_bssgp.c | 10 +++++----- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index ac0426556..03794c2f8 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -100,6 +100,7 @@ struct openbsc_msgb_cb { #define msgb_bvci(__x) OBSC_MSGB_CB(__x)->bvci #define msgb_gmmh(__x) (__x)->l3h #define msgb_bssgph(__x) OBSC_MSGB_CB(__x)->bssgph +#define msgb_bssgp_len(__x) ((__x)->tail - (uint8_t *)msgb_bssgph(__x)) #define msgb_bcid(__x) OBSC_MSGB_CB(__x)->bssgp_cell_id #define msgb_llch(__x) OBSC_MSGB_CB(__x)->llch diff --git a/openbsc/src/gprs_bssgp.c b/openbsc/src/gprs_bssgp.c index aceedb589..554738b56 100644 --- a/openbsc/src/gprs_bssgp.c +++ b/openbsc/src/gprs_bssgp.c @@ -200,7 +200,7 @@ int bssgp_tx_status(uint8_t cause, uint16_t *bvci, struct msgb *orig_msg) } if (orig_msg) msgb_tvlv_put(msg, BSSGP_IE_PDU_IN_ERROR, - msgb_l3len(orig_msg), msgb_bssgph(orig_msg)); + msgb_bssgp_len(orig_msg), msgb_bssgph(orig_msg)); return gprs_ns_sendmsg(bssgp_nsi, msg); } @@ -257,7 +257,7 @@ static int bssgp_rx_bvc_reset(struct msgb *msg, struct tlv_parsed *tp, static int bssgp_rx_ul_ud(struct msgb *msg) { struct bssgp_ud_hdr *budh = (struct bssgp_ud_hdr *) msgb_bssgph(msg); - int data_len = msgb_l3len(msg) - sizeof(*budh); + int data_len = msgb_bssgp_len(msg) - sizeof(*budh); struct tlv_parsed tp; int rc; @@ -285,7 +285,7 @@ static int bssgp_rx_suspend(struct msgb *msg) { struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msgb_bssgph(msg); - int data_len = msgb_l3len(msg) - sizeof(*bgph); + int data_len = msgb_bssgp_len(msg) - sizeof(*bgph); struct tlv_parsed tp; int rc; @@ -307,7 +307,7 @@ static int bssgp_rx_resume(struct msgb *msg) { struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msgb_bssgph(msg); - int data_len = msgb_l3len(msg) - sizeof(*bgph); + int data_len = msgb_bssgp_len(msg) - sizeof(*bgph); struct tlv_parsed tp; int rc; @@ -352,7 +352,7 @@ int gprs_bssgp_rcvmsg(struct msgb *msg) (struct bssgp_normal_hdr *) msgb_bssgph(msg); struct tlv_parsed tp; uint8_t pdu_type = bgph->pdu_type; - int data_len = msgb_l3len(msg) - sizeof(*bgph); + int data_len = msgb_bssgp_len(msg) - sizeof(*bgph); uint16_t bvci; /* PTP BVCI */ uint16_t ns_bvci = msgb_bvci(msg); int rc = 0; -- cgit v1.2.3 From ba021109183f45815b54b00fab1f1cc9692b004e Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 2 May 2010 21:36:36 +0200 Subject: [gprs] use old (uplink) message when parsing the routeing area --- openbsc/src/gsm_04_08_gprs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openbsc/src/gsm_04_08_gprs.c b/openbsc/src/gsm_04_08_gprs.c index c0fe45de2..1eb4ab213 100644 --- a/openbsc/src/gsm_04_08_gprs.c +++ b/openbsc/src/gsm_04_08_gprs.c @@ -166,7 +166,7 @@ static int gsm48_tx_gmm_att_ack(struct msgb *old_msg) aa->att_result = 1; /* GPRS only */ aa->ra_upd_timer = GPRS_TMR_MINUTE | 10; aa->radio_prio = 4; /* lowest */ - bssgp_parse_cell_id(&ra_id, msgb_bcid(msg)); + bssgp_parse_cell_id(&ra_id, msgb_bcid(old_msg)); gsm48_construct_ra(aa->ra_id.digits, &ra_id); /* Option: P-TMSI signature, allocated P-TMSI, MS ID, ... */ @@ -408,7 +408,7 @@ static int gsm48_tx_gmm_ra_upd_ack(struct msgb *old_msg) rua->upd_result = 0; /* RA updated */ rua->ra_upd_timer = GPRS_TMR_MINUTE | 10; - bssgp_parse_cell_id(&ra_id, msgb_bcid(msg)); + bssgp_parse_cell_id(&ra_id, msgb_bcid(old_msg)); gsm48_construct_ra(rua->ra_id.digits, &ra_id); /* Option: P-TMSI signature, allocated P-TMSI, MS ID, ... */ -- cgit v1.2.3 From ba850c529e31c1a48dd7fa9db677061f80510b2a Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 2 May 2010 14:40:32 +0200 Subject: [gprs] cosmetic updates in header file --- openbsc/include/openbsc/gprs_sgsn.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/openbsc/include/openbsc/gprs_sgsn.h b/openbsc/include/openbsc/gprs_sgsn.h index a3c7c78f4..bdc0b1c8f 100644 --- a/openbsc/include/openbsc/gprs_sgsn.h +++ b/openbsc/include/openbsc/gprs_sgsn.h @@ -58,7 +58,7 @@ struct sgsn_mm_ctx { int ppf; /* paging for GPRS + non-GPRS? */ /* SMS Parameters */ int recovery; - uint8_t radio_prio_sms; + uint8_t radio_prio_sms; struct llist_head pdp_list; @@ -86,13 +86,13 @@ struct sgsn_pdp_ctx { char *apn_subscribed; char *apn_used; uint16_t nsapi; - uint8_t ti; /* transaction identifier */ + uint8_t ti; /* transaction identifier */ uint32_t ggsn_in_use; int vplmn_allowed; uint32_t qos_profile_subscr; uint32_t qos_profile_req; uint32_t qos_profile_neg; - uint8_t radio_prio; + uint8_t radio_prio; uint32_t tx_npdu_nr; uint32_t rx_npdu_nr; uint32_t tx_gtp_snd; -- cgit v1.2.3 From 421cba4b08e3a179aa9297bd67fe192d99751277 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 2 May 2010 23:11:50 +0200 Subject: [gprs] SGSN SM: Provide IPv4 PDP address in PDP CTX ACT ACCEPT The message looks now fine (from wireshark point of view). However, we cannot simply echo back the QoS parameters, as the meaning in uplink and downlink connection is not the same. --- openbsc/include/openbsc/gsm_04_08_gprs.h | 21 ++++++++++-------- openbsc/src/gsm_04_08_gprs.c | 38 +++++++++++++++++++++++++++----- 2 files changed, 45 insertions(+), 14 deletions(-) diff --git a/openbsc/include/openbsc/gsm_04_08_gprs.h b/openbsc/include/openbsc/gsm_04_08_gprs.h index 86adea156..c953742cc 100644 --- a/openbsc/include/openbsc/gsm_04_08_gprs.h +++ b/openbsc/include/openbsc/gsm_04_08_gprs.h @@ -108,15 +108,6 @@ struct gsm48_act_pdp_ctx_req { uint8_t data[0]; } __attribute__((packed)); -/* Chapter 9.5.2 / Table 9.5.2 */ -struct gsm48_act_pdp_ctx_ack { - uint8_t llc_sapi; - uint8_t qos_lv[4]; - uint8_t radio_prio:4, - spare:4; - uint8_t data[0]; -} __attribute__((packed)); - /* Chapter 10.5.5.14 / Table 10.5.147 */ enum gsm48_gmm_cause { GMM_CAUSE_IMSI_UNKNOWN = 0x02, @@ -180,6 +171,18 @@ enum gsm48_pdp_state { PDP_S_MODIFY_PENDING, }; +/* Table 10.5.155/3GPP TS 24.008 */ +enum gsm48_pdp_type_org { + PDP_TYPE_ORG_ETSI = 0x00, + PDP_TYPE_ORG_IETF = 0x01, +}; +enum gsm48_pdp_type_nr { + PDP_TYPE_N_ETSI_RESERVED = 0x00, + PDP_TYPE_N_ETSI_PPP = 0x01, + PDP_TYPE_N_IETF_IPv4 = 0x21, + PDP_TYPE_N_IETF_IPv6 = 0x57, +}; + int gprs_tlli_type(uint32_t tlli); struct gsm_bts *gsm48_bts_by_ra_id(struct gsm_network *net, diff --git a/openbsc/src/gsm_04_08_gprs.c b/openbsc/src/gsm_04_08_gprs.c index 1eb4ab213..16c1a2574 100644 --- a/openbsc/src/gsm_04_08_gprs.c +++ b/openbsc/src/gsm_04_08_gprs.c @@ -28,6 +28,7 @@ #include #include +#include #include #include @@ -536,6 +537,27 @@ static int gsm0408_rcv_gmm(struct msgb *msg) return rc; } +static void msgb_put_pdp_addr_ipv4(struct msgb *msg, uint32_t ipaddr) +{ + uint8_t v[6]; + + v[0] = PDP_TYPE_ORG_IETF; + v[1] = PDP_TYPE_N_IETF_IPv4; + *(uint32_t *)(v+2) = htonl(ipaddr); + + msgb_tlv_put(msg, GSM48_IE_GSM_PDP_ADDR, sizeof(v), v); +} + +static void msgb_put_pdp_addr_ppp(struct msgb *msg) +{ + uint8_t v[2]; + + v[0] = PDP_TYPE_ORG_ETSI; + v[1] = PDP_TYPE_N_ETSI_PPP; + + msgb_tlv_put(msg, GSM48_IE_GSM_PDP_ADDR, sizeof(v), v); +} + /* Section 9.5.2: Ativate PDP Context Accept */ static int gsm48_tx_gsm_act_pdp_acc(struct msgb *old_msg, struct gsm48_act_pdp_ctx_req *req) { @@ -552,11 +574,17 @@ static int gsm48_tx_gsm_act_pdp_acc(struct msgb *old_msg, struct gsm48_act_pdp_c gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh)); gh->proto_discr = GSM48_PDISC_SM_GPRS | (transaction_id << 4); gh->msg_type = GSM48_MT_GSM_ACT_PDP_ACK; - act_ack = (struct gsm48_act_pdp_ctx_ack *) - msgb_put(msg, sizeof(*act_ack)); - act_ack->llc_sapi = req->req_llc_sapi; - memcpy(act_ack->qos_lv, req->data, sizeof(act_ack->qos_lv)); - //act_ack->radio_prio = 4; + + /* Negotiated LLC SAPI */ + msgb_v_put(msg, req->req_llc_sapi); + /* copy QoS parameters from original request */ + msgb_lv_put(msg, req->data[0], req->data+1); + /* Radio priority 10.5.7.2 */ + msgb_v_put(msg, 4); + /* PDP address */ + msgb_put_pdp_addr_ipv4(msg, 0x01020304); + /* Optional: Protocol configuration options */ + /* Optional: Packet Flow Identifier */ return gsm48_gmm_sendmsg(msg, 0); } -- cgit v1.2.3 From 86fda90d036e30615c2930073e964a11952c7c9f Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 3 May 2010 10:54:35 +0200 Subject: [gprs] Include a valid QoS attribute in ACT PDP CTX ACCEPT At least a Motorola ROKR E6 now accepts the PDP context activation and proceeds to XID on LL3. --- openbsc/include/openbsc/gsm_04_08_gprs.h | 159 +++++++++++++++++++++++++++++++ openbsc/src/gsm_04_08_gprs.c | 25 ++++- 2 files changed, 183 insertions(+), 1 deletion(-) diff --git a/openbsc/include/openbsc/gsm_04_08_gprs.h b/openbsc/include/openbsc/gsm_04_08_gprs.h index c953742cc..344b2774b 100644 --- a/openbsc/include/openbsc/gsm_04_08_gprs.h +++ b/openbsc/include/openbsc/gsm_04_08_gprs.h @@ -183,6 +183,165 @@ enum gsm48_pdp_type_nr { PDP_TYPE_N_IETF_IPv6 = 0x57, }; +/* Figure 10.5.138/24.008 / Chapter 10.5.6.5 */ +enum gsm48_qos_reliab_class { + GSM48_QOS_RC_LLC_ACK_RLC_ACK_DATA_PROT = 2, + GSM48_QOS_RC_LLC_UN_RLC_ACK_DATA_PROT = 3, + GSM48_QOS_RC_LLC_UN_RLC_UN_PROT_DATA = 4, + GSM48_QOS_RC_LLC_UN_RLC_UN_DATA_UN = 5, +}; + +/* Figure 10.5.138/24.008 / Chapter 10.5.6.5 */ +enum gsm48_qos_preced_class { + GSM48_QOS_PC_HIGH = 1, + GSM48_QOS_PC_NORMAL = 2, + GSM48_QOS_PC_LOW = 3, +}; + +/* Figure 10.5.138/24.008 / Chapter 10.5.6.5 */ +enum gsm48_qos_peak_tput { + GSM48_QOS_PEAK_TPUT_1000bps = 1, + GSM48_QOS_PEAK_TPUT_2000bps = 2, + GSM48_QOS_PEAK_TPUT_4000bps = 3, + GSM48_QOS_PEAK_TPUT_8000bps = 4, + GSM48_QOS_PEAK_TPUT_16000bps = 5, + GSM48_QOS_PEAK_TPUT_32000bps = 6, + GSM48_QOS_PEAK_TPUT_64000bps = 7, + GSM48_QOS_PEAK_TPUT_128000bps = 8, + GSM48_QOS_PEAK_TPUT_256000bps = 9, +}; + +/* Figure 10.5.138/24.008 / Chapter 10.5.6.5 */ +enum gsm48_qos_mean_tput { + GSM48_QOS_MEAN_TPUT_100bph = 1, + GSM48_QOS_MEAN_TPUT_200bph = 2, + GSM48_QOS_MEAN_TPUT_500bph = 3, + GSM48_QOS_MEAN_TPUT_1000bph = 4, + GSM48_QOS_MEAN_TPUT_2000bph = 5, + GSM48_QOS_MEAN_TPUT_5000bph = 6, + GSM48_QOS_MEAN_TPUT_10000bph = 7, + GSM48_QOS_MEAN_TPUT_20000bph = 8, + GSM48_QOS_MEAN_TPUT_50000bph = 9, + GSM48_QOS_MEAN_TPUT_100kbph = 10, + GSM48_QOS_MEAN_TPUT_200kbph = 11, + GSM48_QOS_MEAN_TPUT_500kbph = 0xc, + GSM48_QOS_MEAN_TPUT_1Mbph = 0xd, + GSM48_QOS_MEAN_TPUT_2Mbph = 0xe, + GSM48_QOS_MEAN_TPUT_5Mbph = 0xf, + GSM48_QOS_MEAN_TPUT_10Mbph = 0x10, + GSM48_QOS_MEAN_TPUT_20Mbph = 0x11, + GSM48_QOS_MEAN_TPUT_50Mbph = 0x12, + GSM48_QOS_MEAN_TPUT_BEST_EFFORT = 0x1f, +}; + +/* Figure 10.5.138/24.008 / Chapter 10.5.6.5 */ +enum gsm48_qos_err_sdu { + GSM48_QOS_ERRSDU_NODETECT = 1, + GSM48_QOS_ERRSDU_YES = 2, + GSM48_QOS_ERRSDU_NO = 3, +}; + +/* Figure 10.5.138/24.008 / Chapter 10.5.6.5 */ +enum gsm48_qos_deliv_order { + GSM48_QOS_DO_ORDERED = 1, + GSM48_QOS_DO_UNORDERED = 2, +}; + +/* Figure 10.5.138/24.008 / Chapter 10.5.6.5 */ +enum gsm48_qos_traf_class { + GSM48_QOS_TC_CONVERSATIONAL = 1, + GSM48_QOS_TC_STREAMING = 2, + GSM48_QOS_TC_INTERACTIVE = 3, + GSM48_QOS_TC_BACKGROUND = 4, +}; + +/* Figure 10.5.138/24.008 / Chapter 10.5.6.5 */ +enum gsm48_qos_max_sdu_size { + /* values below in 10 octet granularity */ + GSM48_QOS_MAXSDU_1502 = 0x97, + GSM48_QOS_MAXSDU_1510 = 0x98, + GSM48_QOS_MAXSDU_1520 = 0x99, +}; + +/* Figure 10.5.138/24.008 / Chapter 10.5.6.5 */ +enum gsm48_qos_max_bitrate { + GSM48_QOS_MBRATE_1k = 0x01, + GSM48_QOS_MBRATE_63k = 0x3f, + GSM48_QOS_MBRATE_64k = 0x40, + GSM48_QOS_MBRATE_568k = 0x7f, + GSM48_QOS_MBRATE_576k = 0x80, + GSM48_QOS_MBRATE_8640k = 0xfe, + GSM48_QOS_MBRATE_0k = 0xff, +}; + +/* Figure 10.5.138/24.008 / Chapter 10.5.6.5 */ +enum gsm48_qos_resid_ber { + GSM48_QOS_RBER_5e_2 = 0x01, + GSM48_QOS_RBER_1e_2 = 0x02, + GSM48_QOS_RBER_5e_3 = 0x03, + GSM48_QOS_RBER_4e_3 = 0x04, + GSM48_QOS_RBER_1e_3 = 0x05, + GSM48_QOS_RBER_1e_4 = 0x06, + GSM48_QOS_RBER_1e_5 = 0x07, + GSM48_QOS_RBER_1e_6 = 0x08, + GSM48_QOS_RBER_6e_8 = 0x09, +}; + +/* Figure 10.5.138/24.008 / Chapter 10.5.6.5 */ +enum gsm48_qos_sdu_err { + GSM48_QOS_SERR_1e_2 = 0x01, + GSM48_QOS_SERR_7e_2 = 0x02, + GSM48_QOS_SERR_1e_3 = 0x03, + GSM48_QOS_SERR_1e_4 = 0x04, + GSM48_QOS_SERR_1e_5 = 0x05, + GSM48_QOS_SERR_1e_6 = 0x06, + GSM48_QOS_SERR_1e_1 = 0x07, +}; + +/* Figure 10.5.138/24.008 / Chapter 10.5.6.5 */ +struct gsm48_qos { + /* octet 3 */ + uint8_t reliab_class:3; + uint8_t delay_class:3; + uint8_t spare:2; + /* octet 4 */ + uint8_t preced_class:3; + uint8_t spare2:1; + uint8_t peak_tput:4; + /* octet 5 */ + uint8_t mean_tput:5; + uint8_t spare3:3; + /* octet 6 */ + uint8_t deliv_err_sdu:3; + uint8_t deliv_order:2; + uint8_t traf_class:3; + /* octet 7 */ + uint8_t max_sdu_size; + /* octet 8 */ + uint8_t max_bitrate_up; + /* octet 9 */ + uint8_t max_bitrate_down; + /* octet 10 */ + uint8_t sdu_err_ratio:4; + uint8_t resid_ber:4; + /* octet 11 */ + uint8_t handling_prio:2; + uint8_t xfer_delay:6; + /* octet 12 */ + uint8_t guar_bitrate_up; + /* octet 13 */ + uint8_t guar_bitrate_down; + /* octet 14 */ + uint8_t src_stats_desc:4; + uint8_t sig_ind:1; + uint8_t spare5:3; + /* octet 15 */ + uint8_t max_bitrate_down_ext; + /* octet 16 */ + uint8_t guar_bitrate_down_ext; +}; + + int gprs_tlli_type(uint32_t tlli); struct gsm_bts *gsm48_bts_by_ra_id(struct gsm_network *net, diff --git a/openbsc/src/gsm_04_08_gprs.c b/openbsc/src/gsm_04_08_gprs.c index 16c1a2574..4a42113f0 100644 --- a/openbsc/src/gsm_04_08_gprs.c +++ b/openbsc/src/gsm_04_08_gprs.c @@ -146,6 +146,29 @@ static void gmm_copy_id(struct msgb *msg, const struct msgb *old) msgb_nsei(msg) = msgb_nsei(old); } +static struct gsm48_qos default_qos = { + .delay_class = 4, /* best effort */ + .reliab_class = GSM48_QOS_RC_LLC_UN_RLC_ACK_DATA_PROT, + .peak_tput = GSM48_QOS_PEAK_TPUT_32000bps, + .preced_class = GSM48_QOS_PC_NORMAL, + .mean_tput = GSM48_QOS_MEAN_TPUT_BEST_EFFORT, + .traf_class = GSM48_QOS_TC_INTERACTIVE, + .deliv_order = GSM48_QOS_DO_UNORDERED, + .deliv_err_sdu = GSM48_QOS_ERRSDU_YES, + .max_sdu_size = GSM48_QOS_MAXSDU_1520, + .max_bitrate_up = GSM48_QOS_MBRATE_63k, + .max_bitrate_down = GSM48_QOS_MBRATE_63k, + .resid_ber = GSM48_QOS_RBER_5e_2, + .sdu_err_ratio = GSM48_QOS_SERR_1e_2, + .handling_prio = 3, + .xfer_delay = 0x10, /* 200ms */ + .guar_bitrate_up = GSM48_QOS_MBRATE_0k, + .guar_bitrate_down = GSM48_QOS_MBRATE_0k, + .sig_ind = 0, /* not optimised for signalling */ + .max_bitrate_down_ext = 0, /* use octet 9 */ + .guar_bitrate_down_ext = 0, /* use octet 13 */ +}; + /* Chapter 9.4.2: Attach accept */ static int gsm48_tx_gmm_att_ack(struct msgb *old_msg) { @@ -578,7 +601,7 @@ static int gsm48_tx_gsm_act_pdp_acc(struct msgb *old_msg, struct gsm48_act_pdp_c /* Negotiated LLC SAPI */ msgb_v_put(msg, req->req_llc_sapi); /* copy QoS parameters from original request */ - msgb_lv_put(msg, req->data[0], req->data+1); + msgb_lv_put(msg, sizeof(default_qos), (uint8_t *)&default_qos); /* Radio priority 10.5.7.2 */ msgb_v_put(msg, 4); /* PDP address */ -- cgit v1.2.3 From 10997d0b9bbc63a4480b4e95fb4312fc0401685b Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 3 May 2010 12:28:12 +0200 Subject: [gprs] LLC: API to send XID responses to XID commands --- openbsc/include/openbsc/gprs_llc.h | 10 ++++++ openbsc/src/gprs_llc.c | 71 ++++++++++++++++++++++++++++++-------- 2 files changed, 67 insertions(+), 14 deletions(-) diff --git a/openbsc/include/openbsc/gprs_llc.h b/openbsc/include/openbsc/gprs_llc.h index 2ed2d12ea..5a6682d80 100644 --- a/openbsc/include/openbsc/gprs_llc.h +++ b/openbsc/include/openbsc/gprs_llc.h @@ -15,6 +15,16 @@ enum gprs_llc_sapi { GPRS_SAPI_SNDCP11 = 11, }; +/* 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, +}; int gprs_llc_rcvmsg(struct msgb *msg, struct tlv_parsed *tv); int gprs_llc_tx_ui(struct msgb *msg, uint8_t sapi, int command); diff --git a/openbsc/src/gprs_llc.c b/openbsc/src/gprs_llc.c index 6d1563621..dffca5e21 100644 --- a/openbsc/src/gprs_llc.c +++ b/openbsc/src/gprs_llc.c @@ -142,19 +142,6 @@ static int gprs_llc_fcs(uint8_t *data, unsigned int len) return fcs_calc; } -/* transmit a simple U frame */ -static int gprs_llc_tx_u() -{ - struct msgb *msg = msgb_alloc(LLC_ALLOC_SIZE, "GPRS/LLC"); - - if (!msg) - return -ENOMEM; - - - - /* transmit the frame via BSSGP->NS->... */ -} - static void t200_expired(void *data) { struct gprs_llc_lle *lle = data; @@ -192,6 +179,53 @@ static void t201_expired(void *data) } } +int gprs_llc_tx_u(struct msgb *msg, uint8_t sapi, int command, + enum gprs_llc_u_cmd u_cmd, int pf_bit) +{ + uint8_t *fcs, *llch; + uint8_t addr, ctrl; + uint32_t fcs_calc; + + /* Identifiers from UP: (TLLI, SAPI) + (BVCI, NSEI) */ + + /* Address Field */ + addr = sapi & 0xf; + if (command) + addr |= 0x40; + + /* 6.3 Figure 8 */ + ctrl = 0xe0 | u_cmd; + if (pf_bit) + ctrl |= 0x10; + + /* prepend LLC UI header */ + llch = msgb_push(msg, 2); + llch[0] = addr; + llch[1] = ctrl; + + /* append FCS to end of frame */ + fcs = msgb_put(msg, 3); + fcs_calc = gprs_llc_fcs(llch, fcs - llch); + fcs[0] = fcs_calc & 0xff; + fcs[1] = (fcs_calc >> 8) & 0xff; + fcs[2] = (fcs_calc >> 16) & 0xff; + + /* Identifiers passed down: (BVCI, NSEI) */ + + return gprs_bssgp_tx_dl_ud(msg); +} + +/* Send XID response to LLE */ +static int gprs_llc_tx_xid(struct gprs_llc_lle *lle, struct msgb *msg) +{ + /* copy identifiers from LLE to ensure lower layers can route */ + msgb_tlli(msg) = lle->tlli; + msgb_bvci(msg) = lle->bvci; + msgb_nsei(msg) = lle->nsei; + + return gprs_llc_tx_u(msg, lle->sapi, 0, GPRS_LLC_U_XID, 1); +} + /* Transmit a UI frame over the given SAPI */ int gprs_llc_tx_ui(struct msgb *msg, uint8_t sapi, int command) { @@ -257,6 +291,8 @@ static int gprs_llc_hdr_dump(struct gprs_llc_hdr_parsed *gph) static int gprs_llc_hdr_rx(struct gprs_llc_hdr_parsed *gph, struct gprs_llc_lle *lle) { + struct msgb *resp; + switch (gph->cmd) { case GPRS_LLC_SABM: /* Section 6.4.1.1 */ lle->v_sent = lle->v_ack = lle->v_recv = 0; @@ -284,6 +320,9 @@ static int gprs_llc_hdr_rx(struct gprs_llc_hdr_parsed *gph, case GPRS_LLC_FRMR: /* Section 6.4.1.5 */ break; case GPRS_LLC_XID: /* Section 6.4.1.6 */ + /* FIXME: implement XID negotiation */ + resp = msgb_alloc_headroom(4096, 1024, "LLC_XID"); + gprs_llc_tx_xid(lle, resp); break; } @@ -449,7 +488,7 @@ int gprs_llc_rcvmsg(struct msgb *msg, struct tlv_parsed *tv) struct bssgp_ud_hdr *udh = (struct bssgp_ud_hdr *) msgb_bssgph(msg); struct gprs_llc_hdr *lh = msgb_llch(msg); struct gprs_llc_hdr_parsed llhp; - struct gprs_llc_entity *lle; + struct gprs_llc_lle *lle; int rc = 0; /* Identifiers from DOWN: NSEI, BVCI, TLLI */ @@ -465,6 +504,10 @@ int gprs_llc_rcvmsg(struct msgb *msg, struct tlv_parsed *tv) if (!lle) lle = lle_alloc(msgb_tlli(msg), llhp.sapi); + /* Update LLE's (BVCI, NSEI) tuple */ + lle->bvci = msgb_bvci(msg); + lle->nsei = msgb_nsei(msg); + rc = gprs_llc_hdr_rx(&llhp, lle); /* FIXME */ -- cgit v1.2.3 From 5658a1a76618b61c647c243653f16fc379c9d0bd Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 3 May 2010 13:25:07 +0200 Subject: [gprs] LLC: Echo back the XID parameters that the MS requested In order to finish PDP context activation and start the transfer of SNDCP N-PDUs, we simply confirm to the MS whatever XID parameters it requests. This of course has to be implemented with a proper XID handshake at some other point. --- openbsc/src/gprs_llc.c | 35 +++++++++++++++++++++++------------ 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/openbsc/src/gprs_llc.c b/openbsc/src/gprs_llc.c index dffca5e21..9c75a3d4e 100644 --- a/openbsc/src/gprs_llc.c +++ b/openbsc/src/gprs_llc.c @@ -123,6 +123,7 @@ struct gprs_llc_hdr_parsed { uint32_t fcs; uint32_t fcs_calc; uint8_t *data; + uint16_t data_len; enum gprs_llc_cmd cmd; }; @@ -291,8 +292,6 @@ static int gprs_llc_hdr_dump(struct gprs_llc_hdr_parsed *gph) static int gprs_llc_hdr_rx(struct gprs_llc_hdr_parsed *gph, struct gprs_llc_lle *lle) { - struct msgb *resp; - switch (gph->cmd) { case GPRS_LLC_SABM: /* Section 6.4.1.1 */ lle->v_sent = lle->v_ack = lle->v_recv = 0; @@ -320,9 +319,15 @@ static int gprs_llc_hdr_rx(struct gprs_llc_hdr_parsed *gph, case GPRS_LLC_FRMR: /* Section 6.4.1.5 */ break; case GPRS_LLC_XID: /* Section 6.4.1.6 */ - /* FIXME: implement XID negotiation */ - resp = msgb_alloc_headroom(4096, 1024, "LLC_XID"); - gprs_llc_tx_xid(lle, resp); + /* FIXME: implement XID negotiation using SNDCP */ + { + struct msgb *resp; + uint8_t *xid; + resp = msgb_alloc_headroom(4096, 1024, "LLC_XID"); + xid = msgb_put(resp, gph->data_len); + memcpy(xid, gph->data, gph->data_len); + gprs_llc_tx_xid(lle, resp); + } break; } @@ -405,9 +410,11 @@ static int gprs_llc_hdr_parse(struct gprs_llc_hdr_parsed *ghp, 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; @@ -431,6 +438,7 @@ static int gprs_llc_hdr_parse(struct gprs_llc_hdr_parsed *ghp, } else if ((ctrl[0] & 0xe0) == 0xc0) { /* UI (Unconfirmed Inforamtion) format */ 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); @@ -448,28 +456,31 @@ static int gprs_llc_hdr_parse(struct gprs_llc_hdr_parsed *ghp, } 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 0: + case GPRS_LLC_U_NULL_CMD: ghp->cmd = GPRS_LLC_NULL; break; - case 0x1: + case GPRS_LLC_U_DM_RESP: ghp->cmd = GPRS_LLC_DM; break; - case 0x4: + case GPRS_LLC_U_DISC_CMD: ghp->cmd = GPRS_LLC_DISC; break; - case 0x6: + case GPRS_LLC_U_UA_RESP: ghp->cmd = GPRS_LLC_UA; break; - case 0x7: + case GPRS_LLC_U_SABM_CMD: ghp->cmd = GPRS_LLC_SABM; break; - case 0x8: + case GPRS_LLC_U_FRMR_RESP: ghp->cmd = GPRS_LLC_FRMR; break; - case 0xb: + 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; -- cgit v1.2.3 From ca3620a70775a1a7f97f2792d7f59982daccc74d Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 3 May 2010 16:30:59 +0200 Subject: [gprs] gb_proxy: use new msgb_bssgph() and msgb_bssgp_len() macros The proxy code still operated on msg->l3h, which is no longer the BSSGP header now. --- openbsc/src/gb_proxy.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/openbsc/src/gb_proxy.c b/openbsc/src/gb_proxy.c index a9aa7549c..4d8f27f01 100644 --- a/openbsc/src/gb_proxy.c +++ b/openbsc/src/gb_proxy.c @@ -151,10 +151,10 @@ static int gbprox_tx2bvci(struct msgb *msg, uint16_t ptp_bvci, static int gbprox_rx_sig_from_bss(struct msgb *msg, struct gprs_nsvc *nsvc, uint16_t ns_bvci) { - struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msg->l3h; + struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msgb_bssgph(msg); struct tlv_parsed tp; uint8_t pdu_type = bgph->pdu_type; - int data_len = msgb_l3len(msg) - sizeof(*bgph); + int data_len = msgb_bssgp_len(msg) - sizeof(*bgph); struct gbprox_peer *from_peer; struct gprs_ra_id raid; @@ -227,10 +227,10 @@ static int gbprox_rx_paging(struct msgb *msg, struct tlv_parsed *tp, static int gbprox_rx_sig_from_sgsn(struct msgb *msg, struct gprs_nsvc *nsvc, uint16_t ns_bvci) { - struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msg->l3h; + struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msgb_bssgph(msg); struct tlv_parsed tp; uint8_t pdu_type = bgph->pdu_type; - int data_len = msgb_l3len(msg) - sizeof(*bgph); + int data_len = msgb_bssgp_len(msg) - sizeof(*bgph); struct gbprox_peer *peer; uint16_t bvci; int rc = 0; -- cgit v1.2.3 From 239cf056f074c2918288616c85547a6824ca61e5 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 3 May 2010 18:54:12 +0200 Subject: [gprs] Unify log messages of the NS protocol implementation --- openbsc/src/gprs_ns.c | 50 ++++++++++++++++++++++++++++---------------------- 1 file changed, 28 insertions(+), 22 deletions(-) diff --git a/openbsc/src/gprs_ns.c b/openbsc/src/gprs_ns.c index 0db06c3f0..619a82904 100644 --- a/openbsc/src/gprs_ns.c +++ b/openbsc/src/gprs_ns.c @@ -223,7 +223,8 @@ static int gprs_ns_tx_reset_ack(struct gprs_nsvc *nsvc) nsh->pdu_type = NS_PDUT_RESET_ACK; - DEBUGP(DGPRS, "nsvci=%u, nsei=%u\n", nsvc->nsvci, nsvc->nsei); + DEBUGP(DGPRS, "NSEI=%u Tx NS RESET ACK (NSVCI=%u)\n", + nsvc->nsei, nsvc->nsvci); msgb_tvlv_put(msg, NS_IE_VCI, 2, (uint8_t *)&nsvci); msgb_tvlv_put(msg, NS_IE_NSEI, 2, (uint8_t *)&nsei); @@ -240,13 +241,14 @@ int gprs_ns_sendmsg(struct gprs_ns_inst *nsi, struct msgb *msg) nsvc = nsvc_by_nsei(nsi, msgb_nsei(msg)); if (!nsvc) { - DEBUGP(DGPRS, "Unable to resolve NSEI %u to NS-VC!\n", msgb_nsei(msg)); + LOGP(DGPRS, LOGL_ERROR, "Unable to resolve NSEI %u " + "to NS-VC!\n", msgb_nsei(msg)); return -EINVAL; } nsh = (struct gprs_ns_hdr *) msgb_push(msg, sizeof(*nsh) + 3); if (!nsh) { - DEBUGP(DGPRS, "Not enough headroom for NS header\n"); + LOGP(DGPRS, LOGL_ERROR, "Not enough headroom for NS header\n"); return -EIO; } @@ -281,7 +283,7 @@ static int gprs_ns_rx_status(struct gprs_nsvc *nsvc, struct msgb *msg) uint8_t cause; int rc; - DEBUGP(DGPRS, "NS STATUS "); + DEBUGP(DGPRS, "NSEI=%u NS STATUS ", nsvc->nsei); rc = tlv_parse(&tp, &ns_att_tlvdef, nsh->data, msgb_l2len(msg), 0, 0); @@ -305,15 +307,13 @@ static int gprs_ns_rx_reset(struct gprs_nsvc *nsvc, struct msgb *msg) uint16_t *nsvci, *nsei; int rc; - DEBUGP(DGPRS, "NS RESET "); - rc = tlv_parse(&tp, &ns_att_tlvdef, nsh->data, msgb_l2len(msg), 0, 0); if (!TLVP_PRESENT(&tp, NS_IE_CAUSE) || !TLVP_PRESENT(&tp, NS_IE_VCI) || !TLVP_PRESENT(&tp, NS_IE_NSEI)) { /* FIXME: respond with NS_CAUSE_MISSING_ESSENT_IE */ - DEBUGPC(DGPRS, "Missing mandatory IE\n"); + LOGP(DGPRS, LOGL_ERROR, "NS RESET Missing mandatory IE\n"); return -EINVAL; } @@ -321,13 +321,13 @@ static int gprs_ns_rx_reset(struct gprs_nsvc *nsvc, struct msgb *msg) nsvci = (uint16_t *) TLVP_VAL(&tp, NS_IE_VCI); nsei = (uint16_t *) TLVP_VAL(&tp, NS_IE_NSEI); + DEBUGP(DGPRS, "NSEI=%u NS RESET (NSVCI=%u, cause=%s)\n", + nsvc->nsvci, nsvc->nsei, gprs_ns_cause_str(*cause)); + nsvc->state = NSE_S_BLOCKED | NSE_S_ALIVE; nsvc->nsei = ntohs(*nsei); nsvc->nsvci = ntohs(*nsvci); - DEBUGPC(DGPRS, "cause=%s, NSVCI=%u, NSEI=%u\n", - gprs_ns_cause_str(*cause), nsvc->nsvci, nsvc->nsei); - /* mark the NS-VC as blocked and alive */ /* start the test procedure */ nsvc->alive_timer.cb = gprs_ns_alive_cb; @@ -349,14 +349,18 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, nsvc = nsvc_by_rem_addr(nsi, saddr); if (!nsvc) { /* Only the RESET procedure creates a new NSVC */ - if (nsh->pdu_type != NS_PDUT_RESET) + if (nsh->pdu_type != NS_PDUT_RESET) { + LOGP(DGPRS, LOGL_INFO, "Ignoring NS PDU type 0x%0x " + "from %s for non-existing NS-VC\n", + nsh->pdu_type, inet_ntoa(saddr->sin_addr)); return -EIO; + } + LOGP(DGPRS, LOGL_INFO, "Creating NS-VC for BSS at %s:%u\n", + inet_ntoa(saddr->sin_addr), ntohs(saddr->sin_port)); nsvc = nsvc_create(nsi, 0xffff); nsvc->ip.bts_addr = *saddr; - rc = gprs_ns_rx_reset(nsvc, msg); - return rc; - } - msgb_nsei(msg) = nsvc->nsei; + } else + msgb_nsei(msg) = nsvc->nsei; switch (nsh->pdu_type) { case NS_PDUT_ALIVE: @@ -382,33 +386,34 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, rc = gprs_ns_rx_reset(nsvc, msg); break; case NS_PDUT_RESET_ACK: - DEBUGP(DGPRS, "NS RESET ACK\n"); + DEBUGP(DGPRS, "NSEI=%u Rx NS RESET ACK\n", nsvc->nsei); /* mark remote NS-VC as blocked + active */ nsvc->remote_state = NSE_S_BLOCKED | NSE_S_ALIVE; break; case NS_PDUT_UNBLOCK: /* Section 7.2: unblocking procedure */ - DEBUGP(DGPRS, "NS UNBLOCK\n"); + DEBUGP(DGPRS, "NSEI=%u Rx NS UNBLOCK\n", nsvc->nsei); nsvc->state &= ~NSE_S_BLOCKED; rc = gprs_ns_tx_simple(nsvc, NS_PDUT_UNBLOCK_ACK); break; case NS_PDUT_UNBLOCK_ACK: - DEBUGP(DGPRS, "NS UNBLOCK ACK\n"); + DEBUGP(DGPRS, "NSEI=%u Rx NS UNBLOCK ACK\n", nsvc->nsei); /* mark remote NS-VC as unblocked + active */ nsvc->remote_state = NSE_S_ALIVE; break; case NS_PDUT_BLOCK: - DEBUGP(DGPRS, "NS BLOCK\n"); + DEBUGP(DGPRS, "NSEI=%u Rx NS BLOCK\n", nsvc->nsei); nsvc->state |= NSE_S_BLOCKED; rc = gprs_ns_tx_simple(nsvc, NS_PDUT_UNBLOCK_ACK); break; case NS_PDUT_BLOCK_ACK: - DEBUGP(DGPRS, "NS BLOCK ACK\n"); + DEBUGP(DGPRS, "NSEI=%u Rx NS BLOCK ACK\n", nsvc->nsei); /* mark remote NS-VC as blocked + active */ nsvc->remote_state = NSE_S_BLOCKED | NSE_S_ALIVE; break; default: - DEBUGP(DGPRS, "Unknown NS PDU type 0x%02x\n", nsh->pdu_type); + DEBUGP(DGPRS, "NSEI=%u Rx Unknown NS PDU type 0x%02x\n", + nsvc->nsei, nsh->pdu_type); rc = -EINVAL; break; } @@ -453,7 +458,8 @@ static struct msgb *read_nsip_msg(struct bsc_fd *bfd, int *error, ret = recvfrom(bfd->fd, msg->data, NS_ALLOC_SIZE, 0, (struct sockaddr *)saddr, &saddr_len); if (ret < 0) { - fprintf(stderr, "recv error %s\n", strerror(errno)); + LOGP(DGPRS, LOGL_ERROR, "recv error %s during NSIP recv\n", + strerror(errno)); msgb_free(msg); *error = ret; return NULL; -- cgit v1.2.3 From 672f5c4dfd8ee572b9d59dd1d4f9d435353837ad Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 3 May 2010 18:54:58 +0200 Subject: [gprs] gb_proxy: Fix proxying of BSS messages to SGSN We don't keep a superfluous gbprox_peer for the SGSN anymore. --- openbsc/include/openbsc/gb_proxy.h | 1 + openbsc/src/gb_proxy.c | 60 ++++++++++++++++++++++---------------- openbsc/src/gb_proxy_main.c | 7 ++--- 3 files changed, 39 insertions(+), 29 deletions(-) diff --git a/openbsc/include/openbsc/gb_proxy.h b/openbsc/include/openbsc/gb_proxy.h index 8194d2a8b..60dd5ca80 100644 --- a/openbsc/include/openbsc/gb_proxy.h +++ b/openbsc/include/openbsc/gb_proxy.h @@ -22,6 +22,7 @@ struct gbproxy_config { struct gprs_ns_inst *nsi; }; +extern struct gbproxy_config gbcfg; /* gb_proxy_vty .c */ diff --git a/openbsc/src/gb_proxy.c b/openbsc/src/gb_proxy.c index 4d8f27f01..93b8f6719 100644 --- a/openbsc/src/gb_proxy.c +++ b/openbsc/src/gb_proxy.c @@ -37,6 +37,7 @@ #include #include #include +#include struct gbprox_peer { struct llist_head list; @@ -54,10 +55,6 @@ struct gbprox_peer { /* Linked list of all Gb peers (except SGSN) */ static LLIST_HEAD(gbprox_bts_peers); -/* Pointer to the SGSN peer */ -struct gbprox_peer *gbprox_peer_sgsn; - -/* The NS protocol stack instance we're using */ extern struct gprs_ns_inst *gbprox_nsi; /* Find the gbprox_peer by its BVCI */ @@ -123,6 +120,19 @@ static void peer_free(struct gbprox_peer *peer) talloc_free(peer); } +/* feed a message down the NS-VC associated with the specified peer */ +static int gbprox_tx2sgsn(struct msgb *msg, uint16_t ns_bvci) +{ + msgb_bvci(msg) = ns_bvci; + msgb_nsei(msg) = gbcfg.nsip_sgsn_nsei; + + DEBUGP(DGPRS, "proxying message to SGSN (NS_BVCI=%u, NSEI=%u)\n", + ns_bvci, gbcfg.nsip_sgsn_nsei); + + return gprs_ns_sendmsg(gbprox_nsi, msg); +} + + /* feed a message down the NS-VC associated with the specified peer */ static int gbprox_tx2peer(struct msgb *msg, struct gbprox_peer *peer, uint16_t ns_bvci) @@ -130,6 +140,9 @@ static int gbprox_tx2peer(struct msgb *msg, struct gbprox_peer *peer, msgb_bvci(msg) = ns_bvci; msgb_nsei(msg) = peer->nsvc->nsei; + DEBUGP(DGPRS, "proxying message to BSS (NS_BVCI=%u, NSEI=%u)\n", + ns_bvci, peer->nsvc->nsei); + return gprs_ns_sendmsg(gbprox_nsi, msg); } @@ -197,7 +210,7 @@ static int gbprox_rx_sig_from_bss(struct msgb *msg, struct gprs_nsvc *nsvc, } /* Normally, we can simply pass on all signalling messages from BSS to SGSN */ - return gbprox_tx2peer(msg, gbprox_peer_sgsn, ns_bvci); + return gbprox_tx2sgsn(msg, ns_bvci); err_no_peer: err_mand_ie: /* FIXME: do something */ @@ -303,33 +316,30 @@ err_no_peer: /* Main input function for Gb proxy */ int gbprox_rcvmsg(struct msgb *msg, struct gprs_nsvc *nsvc, uint16_t ns_bvci) { - struct gbprox_peer *peer; + int rc; /* Only BVCI=0 messages need special treatment */ if (ns_bvci == 0 || ns_bvci == 1) { if (nsvc->remote_end_is_sgsn) - return gbprox_rx_sig_from_sgsn(msg, nsvc, ns_bvci); + rc = gbprox_rx_sig_from_sgsn(msg, nsvc, ns_bvci); else - return gbprox_rx_sig_from_bss(msg, nsvc, ns_bvci); - } - - /* All other BVCI are PTP and thus can be simply forwarded */ - peer = peer_by_bvci(ns_bvci); - if (!peer) { - if (!nsvc->remote_end_is_sgsn) { - LOGP(DGPRS, LOGL_NOTICE, "Allocationg new peer for " - "BVCI=%u via NSVC=%u/NSEI=%u\n", ns_bvci, - nsvc->nsvci, nsvc->nsei); - peer = peer_alloc(ns_bvci); - peer->nsvc = nsvc; + rc = gbprox_rx_sig_from_bss(msg, nsvc, ns_bvci); + } else { + /* All other BVCI are PTP and thus can be simply forwarded */ + if (nsvc->remote_end_is_sgsn) { + rc = gbprox_tx2sgsn(msg, ns_bvci); } else { - LOGP(DGPRS, LOGL_ERROR, "Couldn't find peer for " - "BVCI %u\n", ns_bvci); - /* FIXME: do we really have to free the message here? */ - msgb_free(msg); - return -EIO; + struct gbprox_peer *peer = peer_by_bvci(ns_bvci); + if (!peer) { + LOGP(DGPRS, LOGL_NOTICE, "Allocationg new peer for " + "BVCI=%u via NSVC=%u/NSEI=%u\n", ns_bvci, + nsvc->nsvci, nsvc->nsei); + peer = peer_alloc(ns_bvci); + peer->nsvc = nsvc; + } + rc = gbprox_tx2peer(msg, peer, ns_bvci); } } - return gbprox_tx2peer(msg, peer, ns_bvci); + return rc; } diff --git a/openbsc/src/gb_proxy_main.c b/openbsc/src/gb_proxy_main.c index fe72e0214..549b6cece 100644 --- a/openbsc/src/gb_proxy_main.c +++ b/openbsc/src/gb_proxy_main.c @@ -65,7 +65,7 @@ const char *openbsc_copyright = "There is NO WARRANTY, to the extent permitted by law.\n"; static char *config_file = "osmo_gbproxy.cfg"; -static struct gbproxy_config gbcfg; +struct gbproxy_config gbcfg; /* Pointer to the SGSN peer */ extern struct gbprox_peer *gbprox_peer_sgsn; @@ -124,9 +124,8 @@ int main(int argc, char **argv) sin.sin_family = AF_INET; sin.sin_port = htons(gbcfg.nsip_sgsn_port); sin.sin_addr.s_addr = htonl(gbcfg.nsip_sgsn_ip); - gbprox_peer_sgsn = nsip_connect(gbprox_nsi, &sin, - gbcfg.nsip_sgsn_nsei, - gbcfg.nsip_sgsn_nsvci); + nsip_connect(gbprox_nsi, &sin, gbcfg.nsip_sgsn_nsei, + gbcfg.nsip_sgsn_nsvci); while (1) { rc = bsc_select_main(0); -- cgit v1.2.3 From 69619e397030236aefa4d128c970bb21ce84e713 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 3 May 2010 19:05:10 +0200 Subject: [gprs] gb_proxy: Strip NS header before relaying message We don't want two NS headers, do we? --- openbsc/src/gb_proxy.c | 36 +++++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/openbsc/src/gb_proxy.c b/openbsc/src/gb_proxy.c index 93b8f6719..c737a6dbb 100644 --- a/openbsc/src/gb_proxy.c +++ b/openbsc/src/gb_proxy.c @@ -120,8 +120,15 @@ static void peer_free(struct gbprox_peer *peer) talloc_free(peer); } +/* strip off the NS header */ +static void strip_ns_hdr(struct msgb *msg) +{ + int strip_len = msgb_bssgph(msg) - msg->data; + msgb_pull(msg, strip_len); +} + /* feed a message down the NS-VC associated with the specified peer */ -static int gbprox_tx2sgsn(struct msgb *msg, uint16_t ns_bvci) +static int gbprox_relay2sgsn(struct msgb *msg, uint16_t ns_bvci) { msgb_bvci(msg) = ns_bvci; msgb_nsei(msg) = gbcfg.nsip_sgsn_nsei; @@ -129,12 +136,13 @@ static int gbprox_tx2sgsn(struct msgb *msg, uint16_t ns_bvci) DEBUGP(DGPRS, "proxying message to SGSN (NS_BVCI=%u, NSEI=%u)\n", ns_bvci, gbcfg.nsip_sgsn_nsei); + strip_ns_hdr(msg); + return gprs_ns_sendmsg(gbprox_nsi, msg); } - /* feed a message down the NS-VC associated with the specified peer */ -static int gbprox_tx2peer(struct msgb *msg, struct gbprox_peer *peer, +static int gbprox_relay2peer(struct msgb *msg, struct gbprox_peer *peer, uint16_t ns_bvci) { msgb_bvci(msg) = ns_bvci; @@ -143,12 +151,14 @@ static int gbprox_tx2peer(struct msgb *msg, struct gbprox_peer *peer, DEBUGP(DGPRS, "proxying message to BSS (NS_BVCI=%u, NSEI=%u)\n", ns_bvci, peer->nsvc->nsei); + strip_ns_hdr(msg); + return gprs_ns_sendmsg(gbprox_nsi, msg); } /* Send a message to a peer identified by ptp_bvci but using ns_bvci * in the NS hdr */ -static int gbprox_tx2bvci(struct msgb *msg, uint16_t ptp_bvci, +static int gbprox_relay2bvci(struct msgb *msg, uint16_t ptp_bvci, uint16_t ns_bvci) { struct gbprox_peer *peer; @@ -157,7 +167,7 @@ static int gbprox_tx2bvci(struct msgb *msg, uint16_t ptp_bvci, if (!peer) return -ENOENT; - return gbprox_tx2peer(msg, peer, ns_bvci); + return gbprox_relay2peer(msg, peer, ns_bvci); } /* Receive an incoming signalling message from a BSS-side NS-VC */ @@ -210,7 +220,7 @@ static int gbprox_rx_sig_from_bss(struct msgb *msg, struct gprs_nsvc *nsvc, } /* Normally, we can simply pass on all signalling messages from BSS to SGSN */ - return gbprox_tx2sgsn(msg, ns_bvci); + return gbprox_relay2sgsn(msg, ns_bvci); err_no_peer: err_mand_ie: /* FIXME: do something */ @@ -225,13 +235,13 @@ static int gbprox_rx_paging(struct msgb *msg, struct tlv_parsed *tp, if (TLVP_PRESENT(tp, BSSGP_IE_BVCI)) { uint16_t bvci = ntohs(*(uint16_t *)TLVP_VAL(tp, BSSGP_IE_BVCI)); - return gbprox_tx2bvci(msg, bvci, ns_bvci); + return gbprox_relay2bvci(msg, bvci, ns_bvci); } else if (TLVP_PRESENT(tp, BSSGP_IE_ROUTEING_AREA)) { peer = peer_by_rac(TLVP_VAL(tp, BSSGP_IE_ROUTEING_AREA)); - return gbprox_tx2peer(msg, peer, ns_bvci); + return gbprox_relay2peer(msg, peer, ns_bvci); } else if (TLVP_PRESENT(tp, BSSGP_IE_LOCATION_AREA)) { peer = peer_by_lac(TLVP_VAL(tp, BSSGP_IE_LOCATION_AREA)); - return gbprox_tx2peer(msg, peer, ns_bvci); + return gbprox_relay2peer(msg, peer, ns_bvci); } else return -EINVAL; } @@ -273,7 +283,7 @@ static int gbprox_rx_sig_from_sgsn(struct msgb *msg, struct gprs_nsvc *nsvc, if (!TLVP_PRESENT(&tp, BSSGP_IE_BVCI)) goto err_mand_ie; bvci = ntohs(*(uint16_t *)TLVP_VAL(&tp, BSSGP_IE_BVCI)); - rc = gbprox_tx2bvci(msg, bvci, ns_bvci); + rc = gbprox_relay2bvci(msg, bvci, ns_bvci); break; case BSSGP_PDUT_PAGING_PS: case BSSGP_PDUT_PAGING_CS: @@ -295,7 +305,7 @@ static int gbprox_rx_sig_from_sgsn(struct msgb *msg, struct gprs_nsvc *nsvc, peer = peer_by_rac(TLVP_VAL(&tp, BSSGP_IE_ROUTEING_AREA)); if (!peer) goto err_no_peer; - rc = gbprox_tx2peer(msg, peer, ns_bvci); + rc = gbprox_relay2peer(msg, peer, ns_bvci); break; case BSSGP_PDUT_SGSN_INVOKE_TRACE: LOGP(DGPRS, LOGL_ERROR, "SGSN INVOKE TRACE not supported\n"); @@ -327,7 +337,7 @@ int gbprox_rcvmsg(struct msgb *msg, struct gprs_nsvc *nsvc, uint16_t ns_bvci) } else { /* All other BVCI are PTP and thus can be simply forwarded */ if (nsvc->remote_end_is_sgsn) { - rc = gbprox_tx2sgsn(msg, ns_bvci); + rc = gbprox_relay2sgsn(msg, ns_bvci); } else { struct gbprox_peer *peer = peer_by_bvci(ns_bvci); if (!peer) { @@ -337,7 +347,7 @@ int gbprox_rcvmsg(struct msgb *msg, struct gprs_nsvc *nsvc, uint16_t ns_bvci) peer = peer_alloc(ns_bvci); peer->nsvc = nsvc; } - rc = gbprox_tx2peer(msg, peer, ns_bvci); + rc = gbprox_relay2peer(msg, peer, ns_bvci); } } -- cgit v1.2.3 From 44c4830d5b88af73f7b7b4172d9be3a78cd28bc3 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 3 May 2010 19:22:32 +0200 Subject: [gprs] gb_proxy: locally acknowledge BVC RESET for BVCI=0 If a BSS resets BVCI=0, we don't want to reset the SGSN, as BVCI=0 is shared signalling between all BSS. --- openbsc/src/gb_proxy.c | 75 ++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 60 insertions(+), 15 deletions(-) diff --git a/openbsc/src/gb_proxy.c b/openbsc/src/gb_proxy.c index c737a6dbb..f04d05792 100644 --- a/openbsc/src/gb_proxy.c +++ b/openbsc/src/gb_proxy.c @@ -127,15 +127,39 @@ static void strip_ns_hdr(struct msgb *msg) msgb_pull(msg, strip_len); } +/* FIXME: this is copy+paste from gprs_bssgp.c */ +static inline struct msgb *bssgp_msgb_alloc(void) +{ + return msgb_alloc_headroom(4096, 128, "BSSGP"); +} +static int bssgp_tx_simple_bvci(uint8_t pdu_type, uint16_t nsei, + uint16_t bvci, uint16_t ns_bvci) +{ + struct msgb *msg = bssgp_msgb_alloc(); + struct bssgp_normal_hdr *bgph = + (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph)); + uint16_t _bvci; + + msgb_nsei(msg) = nsei; + msgb_bvci(msg) = ns_bvci; + + bgph->pdu_type = pdu_type; + _bvci = htons(bvci); + msgb_tvlv_put(msg, BSSGP_IE_BVCI, 2, (uint8_t *) &_bvci); + + return gprs_ns_sendmsg(gbprox_nsi, msg); +} + + /* feed a message down the NS-VC associated with the specified peer */ static int gbprox_relay2sgsn(struct msgb *msg, uint16_t ns_bvci) { + DEBUGP(DGPRS, "NSEI=%u proxying to SGSN (NS_BVCI=%u, NSEI=%u)\n", + ns_bvci, gbcfg.nsip_sgsn_nsei); + msgb_bvci(msg) = ns_bvci; msgb_nsei(msg) = gbcfg.nsip_sgsn_nsei; - DEBUGP(DGPRS, "proxying message to SGSN (NS_BVCI=%u, NSEI=%u)\n", - ns_bvci, gbcfg.nsip_sgsn_nsei); - strip_ns_hdr(msg); return gprs_ns_sendmsg(gbprox_nsi, msg); @@ -145,12 +169,12 @@ static int gbprox_relay2sgsn(struct msgb *msg, uint16_t ns_bvci) static int gbprox_relay2peer(struct msgb *msg, struct gbprox_peer *peer, uint16_t ns_bvci) { + DEBUGP(DGPRS, "NSEI=%u proxying to to BSS (NS_BVCI=%u, NSEI=%u)\n", + ns_bvci, peer->nsvc->nsei); + msgb_bvci(msg) = ns_bvci; msgb_nsei(msg) = peer->nsvc->nsei; - DEBUGP(DGPRS, "proxying message to BSS (NS_BVCI=%u, NSEI=%u)\n", - ns_bvci, peer->nsvc->nsei); - strip_ns_hdr(msg); return gprs_ns_sendmsg(gbprox_nsi, msg); @@ -182,7 +206,8 @@ static int gbprox_rx_sig_from_bss(struct msgb *msg, struct gprs_nsvc *nsvc, struct gprs_ra_id raid; if (ns_bvci != 0) { - LOGP(DGPRS, LOGL_NOTICE, "BVCI %u is not signalling\n", ns_bvci); + LOGP(DGPRS, LOGL_NOTICE, "NSEI=%u BVCI %u is not signalling\n", + nsvc->nsei, ns_bvci); return -EINVAL; } @@ -190,7 +215,8 @@ static int gbprox_rx_sig_from_bss(struct msgb *msg, struct gprs_nsvc *nsvc, * just to make sure */ if (pdu_type == BSSGP_PDUT_UL_UNITDATA || pdu_type == BSSGP_PDUT_DL_UNITDATA) { - LOGP(DGPRS, LOGL_NOTICE, "UNITDATA not allowed in signalling\n"); + LOGP(DGPRS, LOGL_NOTICE, "NSEI=%u UNITDATA not allowed in " + "signalling\n", nsvc->nsei); return -EINVAL; } @@ -212,11 +238,26 @@ static int gbprox_rx_sig_from_bss(struct msgb *msg, struct gprs_nsvc *nsvc, memcpy(&from_peer->ra, TLVP_VAL(&tp, BSSGP_IE_ROUTEING_AREA), sizeof(&from_peer->ra)); gsm48_parse_ra(&raid, &from_peer->ra); - DEBUGP(DGPRS, "RAC snooping: RAC %u/%u/%u/%u behind BVCI=%u, " - "NSVCI=%u, NSEI=%u\n", raid.mcc, raid.mnc, raid.lac, - raid.rac , from_peer->bvci, nsvc->nsvci, nsvc->nsei); + DEBUGP(DGPRS, "NSEI=%u RAC snooping: RAC %u/%u/%u/%u behind BVCI=%u, " + "NSVCI=%u\n", nsvc->nsei, raid.mcc, raid.mnc, raid.lac, + raid.rac , from_peer->bvci, nsvc->nsvci); /* FIXME: This only supports one BSS per RA */ break; + case BSSGP_PDUT_BVC_RESET: + /* If we receive a BVC reset on the signalling endpoint, we + * don't want the SGSN to reset, as the signalling endpoint + * is common for all point-to-point BVCs (and thus all BTS) */ + if (TLVP_PRESENT(&tp, BSSGP_IE_BVCI)) { + uint16_t bvci = ntohs(*(uint16_t *)TLVP_VAL(&tp, BSSGP_IE_BVCI)); + if (bvci == 0) { + /* FIXME: only do this if SGSN is alive! */ + LOGP(DGPRS, LOGL_INFO, "NSEI=%u Sending fake " + "BVC RESET ACK of BVCI=0\n", nsvc->nsei); + return bssgp_tx_simple_bvci(BSSGP_PDUT_BVC_RESET_ACK, + nsvc->nsei, 0, ns_bvci); + } + } + break; } /* Normally, we can simply pass on all signalling messages from BSS to SGSN */ @@ -259,7 +300,8 @@ static int gbprox_rx_sig_from_sgsn(struct msgb *msg, struct gprs_nsvc *nsvc, int rc = 0; if (ns_bvci != 0) { - LOGP(DGPRS, LOGL_NOTICE, "BVCI %u is not signalling\n", ns_bvci); + LOGP(DGPRS, LOGL_NOTICE, "NSEI=%u(SGSN) BVCI %u is not " + "signalling\n", nsvc->nsei, ns_bvci); return -EINVAL; } @@ -267,7 +309,8 @@ static int gbprox_rx_sig_from_sgsn(struct msgb *msg, struct gprs_nsvc *nsvc, * just to make sure */ if (pdu_type == BSSGP_PDUT_UL_UNITDATA || pdu_type == BSSGP_PDUT_DL_UNITDATA) { - LOGP(DGPRS, LOGL_NOTICE, "UNITDATA not allowed in signalling\n"); + LOGP(DGPRS, LOGL_NOTICE, "NSEI=%u(SGSN) UNITDATA not allowed in " + "signalling\n", nsvc->nsei); return -EINVAL; } @@ -292,7 +335,8 @@ static int gbprox_rx_sig_from_sgsn(struct msgb *msg, struct gprs_nsvc *nsvc, break; case BSSGP_PDUT_STATUS: /* FIXME: Some exception has occurred */ - LOGP(DGPRS, LOGL_NOTICE, "STATUS not implemented yet\n"); + LOGP(DGPRS, LOGL_NOTICE, + "NSEI=%u(SGSN) STATUS not implemented yet\n", nsvc->nsei); break; /* those only exist in the SGSN -> BSS direction */ case BSSGP_PDUT_SUSPEND_ACK: @@ -308,7 +352,8 @@ static int gbprox_rx_sig_from_sgsn(struct msgb *msg, struct gprs_nsvc *nsvc, rc = gbprox_relay2peer(msg, peer, ns_bvci); break; case BSSGP_PDUT_SGSN_INVOKE_TRACE: - LOGP(DGPRS, LOGL_ERROR, "SGSN INVOKE TRACE not supported\n"); + LOGP(DGPRS, LOGL_ERROR, + "NSEI=%u(SGSN) INVOKE TRACE not supported\n", nsvc->nsei); break; default: DEBUGP(DGPRS, "BSSGP PDU type 0x%02x unknown\n", pdu_type); -- cgit v1.2.3 From 96f71f28ebc169ae6ea684371b0cc1961a65189e Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 3 May 2010 19:28:05 +0200 Subject: [gprs] gb_proxy: fix NSEI value printed in some debug statements --- openbsc/src/gb_proxy.c | 4 +-- openbsc/src/gprs_sndcp.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+), 2 deletions(-) create mode 100644 openbsc/src/gprs_sndcp.c diff --git a/openbsc/src/gb_proxy.c b/openbsc/src/gb_proxy.c index f04d05792..a4b432e80 100644 --- a/openbsc/src/gb_proxy.c +++ b/openbsc/src/gb_proxy.c @@ -155,7 +155,7 @@ static int bssgp_tx_simple_bvci(uint8_t pdu_type, uint16_t nsei, static int gbprox_relay2sgsn(struct msgb *msg, uint16_t ns_bvci) { DEBUGP(DGPRS, "NSEI=%u proxying to SGSN (NS_BVCI=%u, NSEI=%u)\n", - ns_bvci, gbcfg.nsip_sgsn_nsei); + msgb_nsei(msg), ns_bvci, gbcfg.nsip_sgsn_nsei); msgb_bvci(msg) = ns_bvci; msgb_nsei(msg) = gbcfg.nsip_sgsn_nsei; @@ -170,7 +170,7 @@ static int gbprox_relay2peer(struct msgb *msg, struct gbprox_peer *peer, uint16_t ns_bvci) { DEBUGP(DGPRS, "NSEI=%u proxying to to BSS (NS_BVCI=%u, NSEI=%u)\n", - ns_bvci, peer->nsvc->nsei); + msgb_nsei(msg), ns_bvci, peer->nsvc->nsei); msgb_bvci(msg) = ns_bvci; msgb_nsei(msg) = peer->nsvc->nsei; diff --git a/openbsc/src/gprs_sndcp.c b/openbsc/src/gprs_sndcp.c new file mode 100644 index 000000000..0d1a39004 --- /dev/null +++ b/openbsc/src/gprs_sndcp.c @@ -0,0 +1,70 @@ +/* GPRS SNDCP protocol implementation as per 3GPP TS 04.65 */ + +/* (C) 2010 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 + +#include +#include +#include +#include + +/* Chapter 7.2: SN-PDU Formats */ +struct sndcp_common_hdr { + /* octet 1 */ + uint8_t nsapi:4; + uint8_t more:1; + uint8_t type:1; + uint8_t first:1; + uint8_t spare:1; + /* octet 2 */ + uint8_t pcomp; + uint8_t dcomp; +}; + +struct sndcp_udata_hdr { + /* octet 3 */ + uint8_t npdu_high:4; + uint8_t seg_nr:4; + /* octet 4 */ + uint8_t npdu_low; +}; + +/* Entry point for the LL-UNITDATA.indication */ +int sndcp_unitdata_ind(struct msgb *msg, uint8_t sapi, uint8_t *hdr, uint8_t len) +{ + struct sndcp_udata_hdr *suh; + uint16_t npdu; + + if (suh->type == 0) { + LOGP(DGPRS, LOGL_ERROR, "SN-DATA PDU at unitdata_ind() function\n"); + return -EINVAL; + } + + npdu = (suh->npdu_high << 8) | suh->npdu_low; +} + -- cgit v1.2.3 From 05b320a4e36fd5ea64e4362b7a497f84e1d5cff7 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 3 May 2010 20:16:13 +0200 Subject: [gprs] NS: replace nsvc->timer_is_tns_alive with nsvc->timer_mode This will allow to use the timer in more than 2 modes --- openbsc/include/openbsc/gprs_ns.h | 12 ++++++++++-- openbsc/src/gprs_ns.c | 25 ++++++++++++++----------- 2 files changed, 24 insertions(+), 13 deletions(-) diff --git a/openbsc/include/openbsc/gprs_ns.h b/openbsc/include/openbsc/gprs_ns.h index 573536d11..407840491 100644 --- a/openbsc/include/openbsc/gprs_ns.h +++ b/openbsc/include/openbsc/gprs_ns.h @@ -118,6 +118,14 @@ struct gprs_ns_inst { }; }; +enum nsvc_timer_mode { + /* standard timers */ + NSVC_TIMER_TNS_TEST, + NSVC_TIMER_TNS_ALIVE, + /* custom timer */ + NSVC_TIMER_RESET, +}; + struct gprs_nsvc { struct llist_head list; struct gprs_ns_inst *nsi; @@ -128,8 +136,8 @@ struct gprs_nsvc { uint32_t state; uint32_t remote_state; - struct timer_list alive_timer; - int timer_is_tns_alive; + struct timer_list timer; + enum nsvc_timer_mode timer_mode; int alive_retries; int remote_end_is_sgsn; diff --git a/openbsc/src/gprs_ns.c b/openbsc/src/gprs_ns.c index 619a82904..9c198ad9a 100644 --- a/openbsc/src/gprs_ns.c +++ b/openbsc/src/gprs_ns.c @@ -182,11 +182,12 @@ static int gprs_ns_tx_simple(struct gprs_nsvc *nsvc, uint8_t pdu_type) #define NS_TIMER_TEST 30, 0 /* every 10 seconds we check if the BTS is still alive */ #define NS_ALIVE_RETRIES 10 /* after 3 failed retransmit we declare BTS as dead */ -static void gprs_ns_alive_cb(void *data) +static void gprs_ns_timer_cb(void *data) { struct gprs_nsvc *nsvc = data; - if (nsvc->timer_is_tns_alive) { + switch (nsvc->timer_mode) { + case NSVC_TIMER_TNS_ALIVE: /* Tns-alive case: we expired without response ! */ nsvc->alive_retries++; if (nsvc->alive_retries > NS_ALIVE_RETRIES) { @@ -197,13 +198,15 @@ static void gprs_ns_alive_cb(void *data) /* FIXME: inform higher layers */ return; } - } else { + break; + case NSVC_TIMER_TNS_TEST: /* Tns-test case: send NS-ALIVE PDU */ gprs_ns_tx_simple(nsvc, NS_PDUT_ALIVE); /* start Tns-alive timer */ - nsvc->timer_is_tns_alive = 1; + nsvc->timer_mode = NSVC_TIMER_TNS_ALIVE; + break; } - bsc_schedule_timer(&nsvc->alive_timer, NS_TIMER_ALIVE); + bsc_schedule_timer(&nsvc->timer, NS_TIMER_ALIVE); } /* Section 9.2.6 */ @@ -330,9 +333,9 @@ static int gprs_ns_rx_reset(struct gprs_nsvc *nsvc, struct msgb *msg) /* mark the NS-VC as blocked and alive */ /* start the test procedure */ - nsvc->alive_timer.cb = gprs_ns_alive_cb; - nsvc->alive_timer.data = nsvc; - bsc_schedule_timer(&nsvc->alive_timer, NS_TIMER_ALIVE); + nsvc->timer.cb = gprs_ns_timer_cb; + nsvc->timer.data = nsvc; + bsc_schedule_timer(&nsvc->timer, NS_TIMER_ALIVE); return gprs_ns_tx_reset_ack(nsvc); } @@ -370,10 +373,10 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, break; case NS_PDUT_ALIVE_ACK: /* stop Tns-alive */ - bsc_del_timer(&nsvc->alive_timer); + bsc_del_timer(&nsvc->timer); /* start Tns-test */ - nsvc->timer_is_tns_alive = 0; - bsc_schedule_timer(&nsvc->alive_timer, NS_TIMER_TEST); + nsvc->timer_mode = NSVC_TIMER_TNS_TEST; + bsc_schedule_timer(&nsvc->timer, NS_TIMER_TEST); break; case NS_PDUT_UNITDATA: /* actual user data */ -- cgit v1.2.3 From 199d9df0bb3f0c63def6cc7e214b15d836fc545a Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 3 May 2010 20:55:10 +0200 Subject: [gprs] NS: improved timer handling for RESET --- openbsc/include/openbsc/gprs_ns.h | 4 +- openbsc/src/gprs_ns.c | 93 ++++++++++++++++++++++++++++++++------- 2 files changed, 80 insertions(+), 17 deletions(-) diff --git a/openbsc/include/openbsc/gprs_ns.h b/openbsc/include/openbsc/gprs_ns.h index 407840491..27c54cb13 100644 --- a/openbsc/include/openbsc/gprs_ns.h +++ b/openbsc/include/openbsc/gprs_ns.h @@ -122,8 +122,8 @@ enum nsvc_timer_mode { /* standard timers */ NSVC_TIMER_TNS_TEST, NSVC_TIMER_TNS_ALIVE, - /* custom timer */ - NSVC_TIMER_RESET, + NSVC_TIMER_TNS_RESET, + _NSVC_TIMER_NR, }; struct gprs_nsvc { diff --git a/openbsc/src/gprs_ns.c b/openbsc/src/gprs_ns.c index 9c198ad9a..39ca8101f 100644 --- a/openbsc/src/gprs_ns.c +++ b/openbsc/src/gprs_ns.c @@ -109,6 +109,8 @@ static struct gprs_nsvc *nsvc_by_rem_addr(struct gprs_ns_inst *nsi, return NULL; } +static void gprs_ns_timer_cb(void *data); + static struct gprs_nsvc *nsvc_create(struct gprs_ns_inst *nsi, uint16_t nsvci) { struct gprs_nsvc *nsvc; @@ -118,6 +120,9 @@ static struct gprs_nsvc *nsvc_create(struct gprs_ns_inst *nsi, uint16_t nsvci) /* before RESET procedure: BLOCKED and DEAD */ nsvc->state = NSE_S_BLOCKED; nsvc->nsi = nsi; + nsvc->timer.cb = gprs_ns_timer_cb; + nsvc->timer.data = nsvc; + llist_add(&nsvc->list, &nsi->gprs_nsvcs); return nsvc; @@ -133,7 +138,7 @@ static const struct value_string ns_cause_str[] = { { NS_CAUSE_BVCI_UNKNOWN, "BVCI unknown" }, { NS_CAUSE_SEM_INCORR_PDU, "Semantically incorrect PDU" }, { NS_CAUSE_PDU_INCOMP_PSTATE, "PDU not compatible with protocol state" }, - { NS_CAUSE_PROTO_ERR_UNSPEC, "Protocol error }, unspecified" }, + { NS_CAUSE_PROTO_ERR_UNSPEC, "Protocol error, unspecified" }, { NS_CAUSE_INVAL_ESSENT_IE, "Invalid essential IE" }, { NS_CAUSE_MISSING_ESSENT_IE, "Missing essential IE" }, { 0, NULL } @@ -178,10 +183,47 @@ static int gprs_ns_tx_simple(struct gprs_nsvc *nsvc, uint8_t pdu_type) return gprs_ns_tx(nsvc, msg); } -#define NS_TIMER_ALIVE 3, 0 /* after 3 seconds without response, we retry */ -#define NS_TIMER_TEST 30, 0 /* every 10 seconds we check if the BTS is still alive */ +static int gprs_ns_tx_reset(struct gprs_nsvc *nsvc) +{ + struct msgb *msg = msgb_alloc(NS_ALLOC_SIZE, "GPRS/NS"); + struct gprs_ns_hdr *nsh; + uint8_t cause = NS_CAUSE_OM_INTERVENTION; + uint16_t nsvci = htons(nsvc->nsvci); + uint16_t nsei = htons(nsvc->nsei); + + if (!msg) + return -ENOMEM; + + nsh = (struct gprs_ns_hdr *) msgb_put(msg, sizeof(*nsh)); + nsh->pdu_type = NS_PDUT_RESET; + + msgb_tvlv_put(msg, NS_IE_CAUSE, 1, &cause); + msgb_tvlv_put(msg, NS_IE_VCI, 2, (uint8_t *) &nsvci); + msgb_tvlv_put(msg, NS_IE_NSEI, 2, (uint8_t *) &nsei); + + return gprs_ns_tx(nsvc, msg); + +} + #define NS_ALIVE_RETRIES 10 /* after 3 failed retransmit we declare BTS as dead */ +static const uint8_t timer_mode_tout[_NSVC_TIMER_NR] = { + [NSVC_TIMER_TNS_RESET] = 60, + [NSVC_TIMER_TNS_ALIVE] = 3, + [NSVC_TIMER_TNS_TEST] = 30, +}; + +static void nsvc_start_timer(struct gprs_nsvc *nsvc, enum nsvc_timer_mode mode) +{ + nsvc->alive_retries = 0; + + if (bsc_timer_pending(&nsvc->timer)) + bsc_del_timer(&nsvc->timer); + + nsvc->timer_mode = mode; + bsc_schedule_timer(&nsvc->timer, timer_mode_tout[mode], 0); +} + static void gprs_ns_timer_cb(void *data) { struct gprs_nsvc *nsvc = data; @@ -193,20 +235,26 @@ static void gprs_ns_timer_cb(void *data) if (nsvc->alive_retries > NS_ALIVE_RETRIES) { /* mark as dead and blocked */ nsvc->state = NSE_S_BLOCKED; - DEBUGP(DGPRS, "Tns-alive more then %u retries, " - " blocking NS-VC\n", NS_ALIVE_RETRIES); + DEBUGP(DGPRS, "NSEI=%u Tns-alive expired more then " + "%u times, blocking NS-VC\n", nsvc->nsei, + NS_ALIVE_RETRIES); /* FIXME: inform higher layers */ return; } + nsvc_start_timer(nsvc, NSVC_TIMER_TNS_ALIVE); break; case NSVC_TIMER_TNS_TEST: /* Tns-test case: send NS-ALIVE PDU */ gprs_ns_tx_simple(nsvc, NS_PDUT_ALIVE); /* start Tns-alive timer */ - nsvc->timer_mode = NSVC_TIMER_TNS_ALIVE; + nsvc_start_timer(nsvc, NSVC_TIMER_TNS_ALIVE); + break; + case NSVC_TIMER_TNS_RESET: + /* Chapter 7.3: Re-send the RESET */ + gprs_ns_tx_reset(nsvc); + nsvc_start_timer(nsvc, NSVC_TIMER_TNS_RESET); break; } - bsc_schedule_timer(&nsvc->timer, NS_TIMER_ALIVE); } /* Section 9.2.6 */ @@ -249,6 +297,17 @@ int gprs_ns_sendmsg(struct gprs_ns_inst *nsi, struct msgb *msg) return -EINVAL; } + if (!(nsvc->state & NSE_S_ALIVE)) { + LOGP(DGPRS, LOGL_ERROR, "NSEI=%u is not alive, cannot send\n", + nsvc->nsei); + return -EBUSY; + } + if (nsvc->state & NSE_S_BLOCKED) { + LOGP(DGPRS, LOGL_ERROR, "NSEI=%u is blocked, cannot send\n", + nsvc->nsei); + return -EBUSY; + } + nsh = (struct gprs_ns_hdr *) msgb_push(msg, sizeof(*nsh) + 3); if (!nsh) { LOGP(DGPRS, LOGL_ERROR, "Not enough headroom for NS header\n"); @@ -333,9 +392,7 @@ static int gprs_ns_rx_reset(struct gprs_nsvc *nsvc, struct msgb *msg) /* mark the NS-VC as blocked and alive */ /* start the test procedure */ - nsvc->timer.cb = gprs_ns_timer_cb; - nsvc->timer.data = nsvc; - bsc_schedule_timer(&nsvc->timer, NS_TIMER_ALIVE); + nsvc_start_timer(nsvc, NSVC_TIMER_TNS_ALIVE); return gprs_ns_tx_reset_ack(nsvc); } @@ -375,8 +432,7 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, /* stop Tns-alive */ bsc_del_timer(&nsvc->timer); /* start Tns-test */ - nsvc->timer_mode = NSVC_TIMER_TNS_TEST; - bsc_schedule_timer(&nsvc->timer, NS_TIMER_TEST); + nsvc_start_timer(nsvc, NSVC_TIMER_TNS_TEST); break; case NS_PDUT_UNITDATA: /* actual user data */ @@ -392,6 +448,10 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, DEBUGP(DGPRS, "NSEI=%u Rx NS RESET ACK\n", nsvc->nsei); /* mark remote NS-VC as blocked + active */ nsvc->remote_state = NSE_S_BLOCKED | NSE_S_ALIVE; + if (nsvc->remote_end_is_sgsn) { + /* stop RESET timer */ + bsc_del_timer(&nsvc->timer); + } break; case NS_PDUT_UNBLOCK: /* Section 7.2: unblocking procedure */ @@ -561,9 +621,12 @@ struct gprs_nsvc *nsip_connect(struct gprs_ns_inst *nsi, nsvc->remote_end_is_sgsn = 1; /* Initiate a RESET procedure */ - if (gprs_ns_tx_simple(nsvc, NS_PDUT_RESET) < 0) - return NULL; - /* FIXME: should we run a timer and re-transmit the reset request? */ + if (gprs_ns_tx_reset(nsvc) < 0) { + LOGP(DGPRS, LOGL_ERROR, "NSEI=%u, error resetting NS-VC\n", + nsei); + } + /* run a timer and re-transmit the reset request? */ + nsvc_start_timer(nsvc, NSVC_TIMER_TNS_RESET); return nsvc; } -- cgit v1.2.3 From 90de93e1227aa768ff7260d2304a164ab1beeebf Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 3 May 2010 21:05:24 +0200 Subject: [gprs] NS: Start ALIVE Procedure after receiving RESET_ACK --- openbsc/src/gprs_ns.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/openbsc/src/gprs_ns.c b/openbsc/src/gprs_ns.c index 39ca8101f..72558ca42 100644 --- a/openbsc/src/gprs_ns.c +++ b/openbsc/src/gprs_ns.c @@ -183,11 +183,10 @@ static int gprs_ns_tx_simple(struct gprs_nsvc *nsvc, uint8_t pdu_type) return gprs_ns_tx(nsvc, msg); } -static int gprs_ns_tx_reset(struct gprs_nsvc *nsvc) +static int gprs_ns_tx_reset(struct gprs_nsvc *nsvc, uint8_t cause) { struct msgb *msg = msgb_alloc(NS_ALLOC_SIZE, "GPRS/NS"); struct gprs_ns_hdr *nsh; - uint8_t cause = NS_CAUSE_OM_INTERVENTION; uint16_t nsvci = htons(nsvc->nsvci); uint16_t nsei = htons(nsvc->nsei); @@ -251,7 +250,7 @@ static void gprs_ns_timer_cb(void *data) break; case NSVC_TIMER_TNS_RESET: /* Chapter 7.3: Re-send the RESET */ - gprs_ns_tx_reset(nsvc); + gprs_ns_tx_reset(nsvc, NS_CAUSE_OM_INTERVENTION); nsvc_start_timer(nsvc, NSVC_TIMER_TNS_RESET); break; } @@ -413,6 +412,7 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, LOGP(DGPRS, LOGL_INFO, "Ignoring NS PDU type 0x%0x " "from %s for non-existing NS-VC\n", nsh->pdu_type, inet_ntoa(saddr->sin_addr)); + //gprs_ns_tx_reset(nsvc, NS_CAUSE_NSVC_UNKNOWN); return -EIO; } LOGP(DGPRS, LOGL_INFO, "Creating NS-VC for BSS at %s:%u\n", @@ -451,6 +451,9 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, if (nsvc->remote_end_is_sgsn) { /* stop RESET timer */ bsc_del_timer(&nsvc->timer); + /* send ALIVE PDU */ + rc = gprs_ns_tx_simple(nsvc, NS_PDUT_ALIVE); + nsvc_start_timer(nsvc, NSVC_TIMER_TNS_ALIVE); } break; case NS_PDUT_UNBLOCK: @@ -621,7 +624,7 @@ struct gprs_nsvc *nsip_connect(struct gprs_ns_inst *nsi, nsvc->remote_end_is_sgsn = 1; /* Initiate a RESET procedure */ - if (gprs_ns_tx_reset(nsvc) < 0) { + if (gprs_ns_tx_reset(nsvc, NS_CAUSE_OM_INTERVENTION) < 0) { LOGP(DGPRS, LOGL_ERROR, "NSEI=%u, error resetting NS-VC\n", nsei); } -- cgit v1.2.3 From 24b31313e877da26cd4ba9d23d75c5cb89270702 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 3 May 2010 21:11:22 +0200 Subject: [gprs] NS: If we are the BSS side, UNBLOCK the connection after it is ALIVE After RESET / RESET-ACK and ALIVE / ALIVE-ACK, the connection needs to be unblocked from the BSS side to the SGSN. --- openbsc/src/gprs_ns.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/openbsc/src/gprs_ns.c b/openbsc/src/gprs_ns.c index 72558ca42..3d9bb8963 100644 --- a/openbsc/src/gprs_ns.c +++ b/openbsc/src/gprs_ns.c @@ -433,6 +433,11 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, bsc_del_timer(&nsvc->timer); /* start Tns-test */ nsvc_start_timer(nsvc, NSVC_TIMER_TNS_TEST); + if (nsvc->remote_end_is_sgsn) { + /* FIXME: this should be one level higher */ + if (nsvc->state & NSE_S_BLOCKED) + rc = gprs_ns_tx_simple(nsvc, NS_PDUT_UNBLOCK); + } break; case NS_PDUT_UNITDATA: /* actual user data */ @@ -454,6 +459,8 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, /* send ALIVE PDU */ rc = gprs_ns_tx_simple(nsvc, NS_PDUT_ALIVE); nsvc_start_timer(nsvc, NSVC_TIMER_TNS_ALIVE); + /* mark local state as BLOCKED + ALIVE */ + nsvc->state = NSE_S_BLOCKED | NSE_S_ALIVE; } break; case NS_PDUT_UNBLOCK: @@ -466,6 +473,8 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, DEBUGP(DGPRS, "NSEI=%u Rx NS UNBLOCK ACK\n", nsvc->nsei); /* mark remote NS-VC as unblocked + active */ nsvc->remote_state = NSE_S_ALIVE; + if (nsvc->remote_end_is_sgsn) + nsvc->state = NSE_S_ALIVE; break; case NS_PDUT_BLOCK: DEBUGP(DGPRS, "NSEI=%u Rx NS BLOCK\n", nsvc->nsei); -- cgit v1.2.3 From 1c77c6e4c20cdace00e8e31f174c31a992017bab Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 3 May 2010 21:37:11 +0200 Subject: [gprs] gb_proxy: Fix message looping bug We don't want to loop back the BSS messages to the BSS itself. --- openbsc/src/gb_proxy.c | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/openbsc/src/gb_proxy.c b/openbsc/src/gb_proxy.c index a4b432e80..fe5ad702f 100644 --- a/openbsc/src/gb_proxy.c +++ b/openbsc/src/gb_proxy.c @@ -169,7 +169,7 @@ static int gbprox_relay2sgsn(struct msgb *msg, uint16_t ns_bvci) static int gbprox_relay2peer(struct msgb *msg, struct gbprox_peer *peer, uint16_t ns_bvci) { - DEBUGP(DGPRS, "NSEI=%u proxying to to BSS (NS_BVCI=%u, NSEI=%u)\n", + DEBUGP(DGPRS, "NSEI=%u proxying to BSS (NS_BVCI=%u, NSEI=%u)\n", msgb_nsei(msg), ns_bvci, peer->nsvc->nsei); msgb_bvci(msg) = ns_bvci; @@ -188,8 +188,11 @@ static int gbprox_relay2bvci(struct msgb *msg, uint16_t ptp_bvci, struct gbprox_peer *peer; peer = peer_by_bvci(ptp_bvci); - if (!peer) + if (!peer) { + LOGP(DGPRS, LOGL_ERROR, "Cannot find BSS for BVCI %u\n", + ptp_bvci); return -ENOENT; + } return gbprox_relay2peer(msg, peer, ns_bvci); } @@ -255,6 +258,14 @@ static int gbprox_rx_sig_from_bss(struct msgb *msg, struct gprs_nsvc *nsvc, "BVC RESET ACK of BVCI=0\n", nsvc->nsei); return bssgp_tx_simple_bvci(BSSGP_PDUT_BVC_RESET_ACK, nsvc->nsei, 0, ns_bvci); + } else if (!peer_by_bvci(bvci)) { + /* if a PTP-BVC is reset, and we don't know that + * PTP-BVCI yet, we should allocate a new peer */ + LOGP(DGPRS, LOGL_INFO, "Allocationg new peer for " + "BVCI=%u via NSVCI=%u/NSEI=%u\n", bvci, + nsvc->nsvci, nsvc->nsei); + from_peer = peer_alloc(bvci); + from_peer->nsvc = nsvc; } } break; @@ -362,10 +373,15 @@ static int gbprox_rx_sig_from_sgsn(struct msgb *msg, struct gprs_nsvc *nsvc, return rc; err_mand_ie: - ; /* FIXME: this would pull gprs_bssgp.c in, which in turn has dependencies */ + LOGP(DGPRS, LOGL_ERROR, "NSEI=%u(SGSN) missing mandatory IE\n", + nsvc->nsei); + /* FIXME: this would pull gprs_bssgp.c in, which in turn has dependencies */ //return bssgp_tx_status(BSSGP_CAUSE_MISSING_MAND_IE, NULL, msg); + return; err_no_peer: - ; /* FIXME */ + LOGP(DGPRS, LOGL_ERROR, "NSEI=%u(SGSN) cannot find peer based on RAC\n"); + /* FIXME */ + return; } /* Main input function for Gb proxy */ @@ -381,7 +397,7 @@ int gbprox_rcvmsg(struct msgb *msg, struct gprs_nsvc *nsvc, uint16_t ns_bvci) rc = gbprox_rx_sig_from_bss(msg, nsvc, ns_bvci); } else { /* All other BVCI are PTP and thus can be simply forwarded */ - if (nsvc->remote_end_is_sgsn) { + if (!nsvc->remote_end_is_sgsn) { rc = gbprox_relay2sgsn(msg, ns_bvci); } else { struct gbprox_peer *peer = peer_by_bvci(ns_bvci); -- cgit v1.2.3 From ce662943f3a0d49606ca6563aa700b2660abe3d4 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 4 May 2010 07:40:09 +0200 Subject: [gprs] Add GPRS header files to noinst_HEADERS --- openbsc/include/openbsc/Makefile.am | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index 259e6d6f5..afb62dec2 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -6,7 +6,9 @@ noinst_HEADERS = abis_nm.h abis_rsl.h db.h gsm_04_08.h gsm_data.h \ bsc_rll.h mncc.h transaction.h ussd.h gsm_04_80.h \ silent_call.h mgcp.h meas_rep.h rest_octets.h \ system_information.h handover.h mgcp_internal.h \ - vty.h + vty.h \ + crc24.h gprs_bssgp.h gprs_llc.h gprs_ns.h \ + gb_proxy.h gprs_sgsn.h gsm_04_08_gprs.h sgsn.h openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h openbscdir = $(includedir)/openbsc -- cgit v1.2.3 From e236596bf42aec7520f2d7a879bb8d2aef7afad0 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 4 May 2010 07:41:59 +0200 Subject: [gprs] Move all GPRS related code to src/gprs subdirectory --- openbsc/configure.in | 1 + openbsc/src/Makefile.am | 18 +- openbsc/src/crc24.c | 69 ---- openbsc/src/gb_proxy.c | 416 --------------------- openbsc/src/gb_proxy_main.c | 149 -------- openbsc/src/gb_proxy_vty.c | 207 ----------- openbsc/src/gprs/Makefile.am | 17 + openbsc/src/gprs/crc24.c | 69 ++++ openbsc/src/gprs/gb_proxy.c | 416 +++++++++++++++++++++ openbsc/src/gprs/gb_proxy_main.c | 149 ++++++++ openbsc/src/gprs/gb_proxy_vty.c | 207 +++++++++++ openbsc/src/gprs/gprs_bssgp.c | 537 +++++++++++++++++++++++++++ openbsc/src/gprs/gprs_llc.c | 549 +++++++++++++++++++++++++++ openbsc/src/gprs/gprs_ns.c | 644 ++++++++++++++++++++++++++++++++ openbsc/src/gprs/gprs_sgsn.c | 96 +++++ openbsc/src/gprs/gprs_sndcp.c | 70 ++++ openbsc/src/gprs/gsm_04_08_gprs.c | 762 ++++++++++++++++++++++++++++++++++++++ openbsc/src/gprs/osmo_gbproxy.cfg | 13 + openbsc/src/gprs/osmo_sgsn.cfg | 9 + openbsc/src/gprs/sgsn_main.c | 143 +++++++ openbsc/src/gprs/sgsn_vty.c | 146 ++++++++ openbsc/src/gprs_bssgp.c | 537 --------------------------- openbsc/src/gprs_llc.c | 549 --------------------------- openbsc/src/gprs_ns.c | 644 -------------------------------- openbsc/src/gprs_sgsn.c | 96 ----- openbsc/src/gprs_sndcp.c | 70 ---- openbsc/src/gsm_04_08_gprs.c | 762 -------------------------------------- openbsc/src/osmo_gbproxy.cfg | 13 - openbsc/src/osmo_sgsn.cfg | 9 - openbsc/src/sgsn_main.c | 143 ------- openbsc/src/sgsn_vty.c | 146 -------- 31 files changed, 3833 insertions(+), 3823 deletions(-) delete mode 100644 openbsc/src/crc24.c delete mode 100644 openbsc/src/gb_proxy.c delete mode 100644 openbsc/src/gb_proxy_main.c delete mode 100644 openbsc/src/gb_proxy_vty.c create mode 100644 openbsc/src/gprs/Makefile.am create mode 100644 openbsc/src/gprs/crc24.c create mode 100644 openbsc/src/gprs/gb_proxy.c create mode 100644 openbsc/src/gprs/gb_proxy_main.c create mode 100644 openbsc/src/gprs/gb_proxy_vty.c create mode 100644 openbsc/src/gprs/gprs_bssgp.c create mode 100644 openbsc/src/gprs/gprs_llc.c create mode 100644 openbsc/src/gprs/gprs_ns.c create mode 100644 openbsc/src/gprs/gprs_sgsn.c create mode 100644 openbsc/src/gprs/gprs_sndcp.c create mode 100644 openbsc/src/gprs/gsm_04_08_gprs.c create mode 100644 openbsc/src/gprs/osmo_gbproxy.cfg create mode 100644 openbsc/src/gprs/osmo_sgsn.cfg create mode 100644 openbsc/src/gprs/sgsn_main.c create mode 100644 openbsc/src/gprs/sgsn_vty.c delete mode 100644 openbsc/src/gprs_bssgp.c delete mode 100644 openbsc/src/gprs_llc.c delete mode 100644 openbsc/src/gprs_ns.c delete mode 100644 openbsc/src/gprs_sgsn.c delete mode 100644 openbsc/src/gprs_sndcp.c delete mode 100644 openbsc/src/gsm_04_08_gprs.c delete mode 100644 openbsc/src/osmo_gbproxy.cfg delete mode 100644 openbsc/src/osmo_sgsn.cfg delete mode 100644 openbsc/src/sgsn_main.c delete mode 100644 openbsc/src/sgsn_vty.c diff --git a/openbsc/configure.in b/openbsc/configure.in index 615e59d91..98a93fc6b 100644 --- a/openbsc/configure.in +++ b/openbsc/configure.in @@ -48,6 +48,7 @@ AC_OUTPUT( include/sccp/Makefile include/Makefile src/Makefile + src/gprs/Makefile tests/Makefile tests/debug/Makefile tests/gsm0408/Makefile diff --git a/openbsc/src/Makefile.am b/openbsc/src/Makefile.am index 18245ed5e..9dcdea02f 100644 --- a/openbsc/src/Makefile.am +++ b/openbsc/src/Makefile.am @@ -2,9 +2,12 @@ INCLUDES = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir) AM_CFLAGS=-Wall $(LIBOSMOCORE_CFLAGS) AM_LDFLAGS = $(LIBOSMOCORE_LIBS) +# build current directory before building gprs +SUBDIRS = . gprs + sbin_PROGRAMS = bsc_hack bs11_config ipaccess-find ipaccess-config \ - isdnsync bsc_mgcp ipaccess-proxy osmo-gbproxy osmo-sgsn -noinst_LIBRARIES = libbsc.a libmsc.a libvty.a libsccp.a libsgsn.a + isdnsync bsc_mgcp ipaccess-proxy +noinst_LIBRARIES = libbsc.a libmsc.a libvty.a libsccp.a noinst_HEADERS = vty/cardshell.h bscdir = $(libdir) @@ -19,9 +22,6 @@ libbsc_a_SOURCES = abis_rsl.c abis_nm.c gsm_data.c gsm_04_08_utils.c \ rtp_proxy.c bts_siemens_bs11.c bts_ipaccess_nanobts.c \ bts_unknown.c bsc_version.c bsc_api.c -libsgsn_a_SOURCES = gprs_ns.c gprs_bssgp.c gprs_llc.c gsm_04_08_gprs.c \ - crc24.c gprs_sgsn.c - libmsc_a_SOURCES = gsm_subscriber.c db.c \ mncc.c gsm_04_08.c gsm_04_11.c transaction.c \ token_auth.c rrlp.c gsm_04_80.c ussd.c silent_call.c \ @@ -50,11 +50,3 @@ bsc_mgcp_SOURCES = mgcp/mgcp_main.c mgcp/mgcp_protocol.c mgcp/mgcp_network.c mgc bsc_mgcp_LDADD = libvty.a ipaccess_proxy_SOURCES = ipaccess/ipaccess-proxy.c debug.c - -osmo_gbproxy_SOURCES = gb_proxy.c gb_proxy_main.c gb_proxy_vty.c \ - gprs_ns.c socket.c debug.c -osmo_gbproxy_LDADD = libvty.a - -osmo_sgsn_SOURCES = sgsn_main.c sgsn_vty.c \ - socket.c debug.c -osmo_sgsn_LDADD = libvty.a libsgsn.a diff --git a/openbsc/src/crc24.c b/openbsc/src/crc24.c deleted file mode 100644 index 108212083..000000000 --- a/openbsc/src/crc24.c +++ /dev/null @@ -1,69 +0,0 @@ -/* GPRS LLC CRC-24 Implementation */ - -/* (C) 2008-2009 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 - -/* CRC24 table - FCS */ -static const u_int32_t tbl_crc24[256] = { - 0x00000000, 0x00d6a776, 0x00f64557, 0x0020e221, 0x00b78115, 0x00612663, 0x0041c442, 0x00976334, - 0x00340991, 0x00e2aee7, 0x00c24cc6, 0x0014ebb0, 0x00838884, 0x00552ff2, 0x0075cdd3, 0x00a36aa5, - 0x00681322, 0x00beb454, 0x009e5675, 0x0048f103, 0x00df9237, 0x00093541, 0x0029d760, 0x00ff7016, - 0x005c1ab3, 0x008abdc5, 0x00aa5fe4, 0x007cf892, 0x00eb9ba6, 0x003d3cd0, 0x001ddef1, 0x00cb7987, - 0x00d02644, 0x00068132, 0x00266313, 0x00f0c465, 0x0067a751, 0x00b10027, 0x0091e206, 0x00474570, - 0x00e42fd5, 0x003288a3, 0x00126a82, 0x00c4cdf4, 0x0053aec0, 0x008509b6, 0x00a5eb97, 0x00734ce1, - 0x00b83566, 0x006e9210, 0x004e7031, 0x0098d747, 0x000fb473, 0x00d91305, 0x00f9f124, 0x002f5652, - 0x008c3cf7, 0x005a9b81, 0x007a79a0, 0x00acded6, 0x003bbde2, 0x00ed1a94, 0x00cdf8b5, 0x001b5fc3, - 0x00fb4733, 0x002de045, 0x000d0264, 0x00dba512, 0x004cc626, 0x009a6150, 0x00ba8371, 0x006c2407, - 0x00cf4ea2, 0x0019e9d4, 0x00390bf5, 0x00efac83, 0x0078cfb7, 0x00ae68c1, 0x008e8ae0, 0x00582d96, - 0x00935411, 0x0045f367, 0x00651146, 0x00b3b630, 0x0024d504, 0x00f27272, 0x00d29053, 0x00043725, - 0x00a75d80, 0x0071faf6, 0x005118d7, 0x0087bfa1, 0x0010dc95, 0x00c67be3, 0x00e699c2, 0x00303eb4, - 0x002b6177, 0x00fdc601, 0x00dd2420, 0x000b8356, 0x009ce062, 0x004a4714, 0x006aa535, 0x00bc0243, - 0x001f68e6, 0x00c9cf90, 0x00e92db1, 0x003f8ac7, 0x00a8e9f3, 0x007e4e85, 0x005eaca4, 0x00880bd2, - 0x00437255, 0x0095d523, 0x00b53702, 0x00639074, 0x00f4f340, 0x00225436, 0x0002b617, 0x00d41161, - 0x00777bc4, 0x00a1dcb2, 0x00813e93, 0x005799e5, 0x00c0fad1, 0x00165da7, 0x0036bf86, 0x00e018f0, - 0x00ad85dd, 0x007b22ab, 0x005bc08a, 0x008d67fc, 0x001a04c8, 0x00cca3be, 0x00ec419f, 0x003ae6e9, - 0x00998c4c, 0x004f2b3a, 0x006fc91b, 0x00b96e6d, 0x002e0d59, 0x00f8aa2f, 0x00d8480e, 0x000eef78, - 0x00c596ff, 0x00133189, 0x0033d3a8, 0x00e574de, 0x007217ea, 0x00a4b09c, 0x008452bd, 0x0052f5cb, - 0x00f19f6e, 0x00273818, 0x0007da39, 0x00d17d4f, 0x00461e7b, 0x0090b90d, 0x00b05b2c, 0x0066fc5a, - 0x007da399, 0x00ab04ef, 0x008be6ce, 0x005d41b8, 0x00ca228c, 0x001c85fa, 0x003c67db, 0x00eac0ad, - 0x0049aa08, 0x009f0d7e, 0x00bfef5f, 0x00694829, 0x00fe2b1d, 0x00288c6b, 0x00086e4a, 0x00dec93c, - 0x0015b0bb, 0x00c317cd, 0x00e3f5ec, 0x0035529a, 0x00a231ae, 0x007496d8, 0x005474f9, 0x0082d38f, - 0x0021b92a, 0x00f71e5c, 0x00d7fc7d, 0x00015b0b, 0x0096383f, 0x00409f49, 0x00607d68, 0x00b6da1e, - 0x0056c2ee, 0x00806598, 0x00a087b9, 0x007620cf, 0x00e143fb, 0x0037e48d, 0x001706ac, 0x00c1a1da, - 0x0062cb7f, 0x00b46c09, 0x00948e28, 0x0042295e, 0x00d54a6a, 0x0003ed1c, 0x00230f3d, 0x00f5a84b, - 0x003ed1cc, 0x00e876ba, 0x00c8949b, 0x001e33ed, 0x008950d9, 0x005ff7af, 0x007f158e, 0x00a9b2f8, - 0x000ad85d, 0x00dc7f2b, 0x00fc9d0a, 0x002a3a7c, 0x00bd5948, 0x006bfe3e, 0x004b1c1f, 0x009dbb69, - 0x0086e4aa, 0x005043dc, 0x0070a1fd, 0x00a6068b, 0x003165bf, 0x00e7c2c9, 0x00c720e8, 0x0011879e, - 0x00b2ed3b, 0x00644a4d, 0x0044a86c, 0x00920f1a, 0x00056c2e, 0x00d3cb58, 0x00f32979, 0x00258e0f, - 0x00eef788, 0x003850fe, 0x0018b2df, 0x00ce15a9, 0x0059769d, 0x008fd1eb, 0x00af33ca, 0x007994bc, - 0x00dafe19, 0x000c596f, 0x002cbb4e, 0x00fa1c38, 0x006d7f0c, 0x00bbd87a, 0x009b3a5b, 0x004d9d2d -}; - -#define INIT_CRC24 0xffffff - -u_int32_t crc24_calc(u_int32_t fcs, u_int8_t *cp, unsigned int len) -{ - while (len--) - fcs = (fcs >> 8) ^ tbl_crc24[(fcs ^ *cp++) & 0xff]; - return fcs; -} diff --git a/openbsc/src/gb_proxy.c b/openbsc/src/gb_proxy.c deleted file mode 100644 index fe5ad702f..000000000 --- a/openbsc/src/gb_proxy.c +++ /dev/null @@ -1,416 +0,0 @@ -/* NS-over-IP proxy */ - -/* (C) 2010 by Harald Welte - * (C) 2010 by On Waves - * 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 -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include - -struct gbprox_peer { - struct llist_head list; - - /* NS-VC over which we send/receive data to this BVC */ - struct gprs_nsvc *nsvc; - - /* BVCI used for Point-to-Point to this peer */ - uint16_t bvci; - - /* Routeing Area that this peer is part of (raw 04.08 encoding) */ - uint8_t ra[6]; -}; - -/* Linked list of all Gb peers (except SGSN) */ -static LLIST_HEAD(gbprox_bts_peers); - -extern struct gprs_ns_inst *gbprox_nsi; - -/* Find the gbprox_peer by its BVCI */ -static struct gbprox_peer *peer_by_bvci(uint16_t bvci) -{ - struct gbprox_peer *peer; - llist_for_each_entry(peer, &gbprox_bts_peers, list) { - if (peer->bvci == bvci) - return peer; - } - return NULL; -} - -static struct gbprox_peer *peer_by_nsvc(struct gprs_nsvc *nsvc) -{ - struct gbprox_peer *peer; - llist_for_each_entry(peer, &gbprox_bts_peers, list) { - if (peer->nsvc == nsvc) - return peer; - } - return NULL; -} - -/* look-up a peer by its Routeing Area Code (RAC) */ -static struct gbprox_peer *peer_by_rac(const uint8_t *ra) -{ - struct gbprox_peer *peer; - llist_for_each_entry(peer, &gbprox_bts_peers, list) { - if (!memcmp(&peer->ra, ra, 6)) - return peer; - } - return NULL; -} - -/* look-up a peer by its Location Area Code (LAC) */ -static struct gbprox_peer *peer_by_lac(const uint8_t *la) -{ - struct gbprox_peer *peer; - llist_for_each_entry(peer, &gbprox_bts_peers, list) { - if (!memcmp(&peer->ra, la, 5)) - return peer; - } - return NULL; -} - -static struct gbprox_peer *peer_alloc(uint16_t bvci) -{ - struct gbprox_peer *peer; - - peer = talloc_zero(tall_bsc_ctx, struct gbprox_peer); - if (!peer) - return NULL; - - peer->bvci = bvci; - llist_add(&peer->list, &gbprox_bts_peers); - - return peer; -} - -static void peer_free(struct gbprox_peer *peer) -{ - llist_del(&peer->list); - talloc_free(peer); -} - -/* strip off the NS header */ -static void strip_ns_hdr(struct msgb *msg) -{ - int strip_len = msgb_bssgph(msg) - msg->data; - msgb_pull(msg, strip_len); -} - -/* FIXME: this is copy+paste from gprs_bssgp.c */ -static inline struct msgb *bssgp_msgb_alloc(void) -{ - return msgb_alloc_headroom(4096, 128, "BSSGP"); -} -static int bssgp_tx_simple_bvci(uint8_t pdu_type, uint16_t nsei, - uint16_t bvci, uint16_t ns_bvci) -{ - struct msgb *msg = bssgp_msgb_alloc(); - struct bssgp_normal_hdr *bgph = - (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph)); - uint16_t _bvci; - - msgb_nsei(msg) = nsei; - msgb_bvci(msg) = ns_bvci; - - bgph->pdu_type = pdu_type; - _bvci = htons(bvci); - msgb_tvlv_put(msg, BSSGP_IE_BVCI, 2, (uint8_t *) &_bvci); - - return gprs_ns_sendmsg(gbprox_nsi, msg); -} - - -/* feed a message down the NS-VC associated with the specified peer */ -static int gbprox_relay2sgsn(struct msgb *msg, uint16_t ns_bvci) -{ - DEBUGP(DGPRS, "NSEI=%u proxying to SGSN (NS_BVCI=%u, NSEI=%u)\n", - msgb_nsei(msg), ns_bvci, gbcfg.nsip_sgsn_nsei); - - msgb_bvci(msg) = ns_bvci; - msgb_nsei(msg) = gbcfg.nsip_sgsn_nsei; - - strip_ns_hdr(msg); - - return gprs_ns_sendmsg(gbprox_nsi, msg); -} - -/* feed a message down the NS-VC associated with the specified peer */ -static int gbprox_relay2peer(struct msgb *msg, struct gbprox_peer *peer, - uint16_t ns_bvci) -{ - DEBUGP(DGPRS, "NSEI=%u proxying to BSS (NS_BVCI=%u, NSEI=%u)\n", - msgb_nsei(msg), ns_bvci, peer->nsvc->nsei); - - msgb_bvci(msg) = ns_bvci; - msgb_nsei(msg) = peer->nsvc->nsei; - - strip_ns_hdr(msg); - - return gprs_ns_sendmsg(gbprox_nsi, msg); -} - -/* Send a message to a peer identified by ptp_bvci but using ns_bvci - * in the NS hdr */ -static int gbprox_relay2bvci(struct msgb *msg, uint16_t ptp_bvci, - uint16_t ns_bvci) -{ - struct gbprox_peer *peer; - - peer = peer_by_bvci(ptp_bvci); - if (!peer) { - LOGP(DGPRS, LOGL_ERROR, "Cannot find BSS for BVCI %u\n", - ptp_bvci); - return -ENOENT; - } - - return gbprox_relay2peer(msg, peer, ns_bvci); -} - -/* Receive an incoming signalling message from a BSS-side NS-VC */ -static int gbprox_rx_sig_from_bss(struct msgb *msg, struct gprs_nsvc *nsvc, - uint16_t ns_bvci) -{ - struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msgb_bssgph(msg); - struct tlv_parsed tp; - uint8_t pdu_type = bgph->pdu_type; - int data_len = msgb_bssgp_len(msg) - sizeof(*bgph); - struct gbprox_peer *from_peer; - struct gprs_ra_id raid; - - if (ns_bvci != 0) { - LOGP(DGPRS, LOGL_NOTICE, "NSEI=%u BVCI %u is not signalling\n", - nsvc->nsei, ns_bvci); - return -EINVAL; - } - - /* we actually should never see those two for BVCI == 0, but double-check - * just to make sure */ - if (pdu_type == BSSGP_PDUT_UL_UNITDATA || - pdu_type == BSSGP_PDUT_DL_UNITDATA) { - LOGP(DGPRS, LOGL_NOTICE, "NSEI=%u UNITDATA not allowed in " - "signalling\n", nsvc->nsei); - return -EINVAL; - } - - bssgp_tlv_parse(&tp, bgph->data, data_len); - - switch (pdu_type) { - case BSSGP_PDUT_SUSPEND: - case BSSGP_PDUT_RESUME: - /* We implement RAC snooping during SUSPEND/RESUME, since - * it establishes a relationsip between BVCI/peer and the - * routeing area code. The snooped information is then - * used for routing the {SUSPEND,RESUME}_[N]ACK back to - * the correct BSSGP */ - if (!TLVP_PRESENT(&tp, BSSGP_IE_ROUTEING_AREA)) - goto err_mand_ie; - from_peer = peer_by_nsvc(nsvc); - if (!from_peer) - goto err_no_peer; - memcpy(&from_peer->ra, TLVP_VAL(&tp, BSSGP_IE_ROUTEING_AREA), - sizeof(&from_peer->ra)); - gsm48_parse_ra(&raid, &from_peer->ra); - DEBUGP(DGPRS, "NSEI=%u RAC snooping: RAC %u/%u/%u/%u behind BVCI=%u, " - "NSVCI=%u\n", nsvc->nsei, raid.mcc, raid.mnc, raid.lac, - raid.rac , from_peer->bvci, nsvc->nsvci); - /* FIXME: This only supports one BSS per RA */ - break; - case BSSGP_PDUT_BVC_RESET: - /* If we receive a BVC reset on the signalling endpoint, we - * don't want the SGSN to reset, as the signalling endpoint - * is common for all point-to-point BVCs (and thus all BTS) */ - if (TLVP_PRESENT(&tp, BSSGP_IE_BVCI)) { - uint16_t bvci = ntohs(*(uint16_t *)TLVP_VAL(&tp, BSSGP_IE_BVCI)); - if (bvci == 0) { - /* FIXME: only do this if SGSN is alive! */ - LOGP(DGPRS, LOGL_INFO, "NSEI=%u Sending fake " - "BVC RESET ACK of BVCI=0\n", nsvc->nsei); - return bssgp_tx_simple_bvci(BSSGP_PDUT_BVC_RESET_ACK, - nsvc->nsei, 0, ns_bvci); - } else if (!peer_by_bvci(bvci)) { - /* if a PTP-BVC is reset, and we don't know that - * PTP-BVCI yet, we should allocate a new peer */ - LOGP(DGPRS, LOGL_INFO, "Allocationg new peer for " - "BVCI=%u via NSVCI=%u/NSEI=%u\n", bvci, - nsvc->nsvci, nsvc->nsei); - from_peer = peer_alloc(bvci); - from_peer->nsvc = nsvc; - } - } - break; - } - - /* Normally, we can simply pass on all signalling messages from BSS to SGSN */ - return gbprox_relay2sgsn(msg, ns_bvci); -err_no_peer: -err_mand_ie: - /* FIXME: do something */ - ; -} - -/* Receive paging request from SGSN, we need to relay to proper BSS */ -static int gbprox_rx_paging(struct msgb *msg, struct tlv_parsed *tp, - struct gprs_nsvc *nsvc, uint16_t ns_bvci) -{ - struct gbprox_peer *peer; - - if (TLVP_PRESENT(tp, BSSGP_IE_BVCI)) { - uint16_t bvci = ntohs(*(uint16_t *)TLVP_VAL(tp, BSSGP_IE_BVCI)); - return gbprox_relay2bvci(msg, bvci, ns_bvci); - } else if (TLVP_PRESENT(tp, BSSGP_IE_ROUTEING_AREA)) { - peer = peer_by_rac(TLVP_VAL(tp, BSSGP_IE_ROUTEING_AREA)); - return gbprox_relay2peer(msg, peer, ns_bvci); - } else if (TLVP_PRESENT(tp, BSSGP_IE_LOCATION_AREA)) { - peer = peer_by_lac(TLVP_VAL(tp, BSSGP_IE_LOCATION_AREA)); - return gbprox_relay2peer(msg, peer, ns_bvci); - } else - return -EINVAL; -} - -/* Receive an incoming signalling message from the SGSN-side NS-VC */ -static int gbprox_rx_sig_from_sgsn(struct msgb *msg, struct gprs_nsvc *nsvc, - uint16_t ns_bvci) -{ - struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msgb_bssgph(msg); - struct tlv_parsed tp; - uint8_t pdu_type = bgph->pdu_type; - int data_len = msgb_bssgp_len(msg) - sizeof(*bgph); - struct gbprox_peer *peer; - uint16_t bvci; - int rc = 0; - - if (ns_bvci != 0) { - LOGP(DGPRS, LOGL_NOTICE, "NSEI=%u(SGSN) BVCI %u is not " - "signalling\n", nsvc->nsei, ns_bvci); - return -EINVAL; - } - - /* we actually should never see those two for BVCI == 0, but double-check - * just to make sure */ - if (pdu_type == BSSGP_PDUT_UL_UNITDATA || - pdu_type == BSSGP_PDUT_DL_UNITDATA) { - LOGP(DGPRS, LOGL_NOTICE, "NSEI=%u(SGSN) UNITDATA not allowed in " - "signalling\n", nsvc->nsei); - return -EINVAL; - } - - rc = bssgp_tlv_parse(&tp, bgph->data, data_len); - - switch (pdu_type) { - case BSSGP_PDUT_FLUSH_LL: - case BSSGP_PDUT_BVC_BLOCK_ACK: - case BSSGP_PDUT_BVC_UNBLOCK_ACK: - case BSSGP_PDUT_BVC_RESET: - case BSSGP_PDUT_BVC_RESET_ACK: - /* simple case: BVCI IE is mandatory */ - if (!TLVP_PRESENT(&tp, BSSGP_IE_BVCI)) - goto err_mand_ie; - bvci = ntohs(*(uint16_t *)TLVP_VAL(&tp, BSSGP_IE_BVCI)); - rc = gbprox_relay2bvci(msg, bvci, ns_bvci); - break; - case BSSGP_PDUT_PAGING_PS: - case BSSGP_PDUT_PAGING_CS: - /* process the paging request (LAC/RAC lookup) */ - rc = gbprox_rx_paging(msg, &tp, nsvc, ns_bvci); - break; - case BSSGP_PDUT_STATUS: - /* FIXME: Some exception has occurred */ - LOGP(DGPRS, LOGL_NOTICE, - "NSEI=%u(SGSN) STATUS not implemented yet\n", nsvc->nsei); - break; - /* those only exist in the SGSN -> BSS direction */ - case BSSGP_PDUT_SUSPEND_ACK: - case BSSGP_PDUT_SUSPEND_NACK: - case BSSGP_PDUT_RESUME_ACK: - case BSSGP_PDUT_RESUME_NACK: - /* RAC IE is mandatory */ - if (!TLVP_PRESENT(&tp, BSSGP_IE_ROUTEING_AREA)) - goto err_mand_ie; - peer = peer_by_rac(TLVP_VAL(&tp, BSSGP_IE_ROUTEING_AREA)); - if (!peer) - goto err_no_peer; - rc = gbprox_relay2peer(msg, peer, ns_bvci); - break; - case BSSGP_PDUT_SGSN_INVOKE_TRACE: - LOGP(DGPRS, LOGL_ERROR, - "NSEI=%u(SGSN) INVOKE TRACE not supported\n", nsvc->nsei); - break; - default: - DEBUGP(DGPRS, "BSSGP PDU type 0x%02x unknown\n", pdu_type); - break; - } - - return rc; -err_mand_ie: - LOGP(DGPRS, LOGL_ERROR, "NSEI=%u(SGSN) missing mandatory IE\n", - nsvc->nsei); - /* FIXME: this would pull gprs_bssgp.c in, which in turn has dependencies */ - //return bssgp_tx_status(BSSGP_CAUSE_MISSING_MAND_IE, NULL, msg); - return; -err_no_peer: - LOGP(DGPRS, LOGL_ERROR, "NSEI=%u(SGSN) cannot find peer based on RAC\n"); - /* FIXME */ - return; -} - -/* Main input function for Gb proxy */ -int gbprox_rcvmsg(struct msgb *msg, struct gprs_nsvc *nsvc, uint16_t ns_bvci) -{ - int rc; - - /* Only BVCI=0 messages need special treatment */ - if (ns_bvci == 0 || ns_bvci == 1) { - if (nsvc->remote_end_is_sgsn) - rc = gbprox_rx_sig_from_sgsn(msg, nsvc, ns_bvci); - else - rc = gbprox_rx_sig_from_bss(msg, nsvc, ns_bvci); - } else { - /* All other BVCI are PTP and thus can be simply forwarded */ - if (!nsvc->remote_end_is_sgsn) { - rc = gbprox_relay2sgsn(msg, ns_bvci); - } else { - struct gbprox_peer *peer = peer_by_bvci(ns_bvci); - if (!peer) { - LOGP(DGPRS, LOGL_NOTICE, "Allocationg new peer for " - "BVCI=%u via NSVC=%u/NSEI=%u\n", ns_bvci, - nsvc->nsvci, nsvc->nsei); - peer = peer_alloc(ns_bvci); - peer->nsvc = nsvc; - } - rc = gbprox_relay2peer(msg, peer, ns_bvci); - } - } - - return rc; -} diff --git a/openbsc/src/gb_proxy_main.c b/openbsc/src/gb_proxy_main.c deleted file mode 100644 index 549b6cece..000000000 --- a/openbsc/src/gb_proxy_main.c +++ /dev/null @@ -1,149 +0,0 @@ -/* NS-over-IP proxy */ - -/* (C) 2010 by Harald Welte - * (C) 2010 by On Waves - * 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 -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "../bscconfig.h" - -/* this is here for the vty... it will never be called */ -void subscr_put() { abort(); } - -#define _GNU_SOURCE -#include - -void *tall_bsc_ctx; - -struct gprs_ns_inst *gbprox_nsi; - -const char *openbsc_version = "Osmocom NSIP Proxy " PACKAGE_VERSION; -const char *openbsc_copyright = - "Copyright (C) 2010 Harald Welte and On-Waves\n" - "Contributions by Daniel Willmann, Jan Lübbe, Stefan Schmidt\n" - "Dieter Spaar, Andreas Eversberg, Holger Freyther\n\n" - "License GPLv2+: GNU GPL version 2 or later \n" - "This is free software: you are free to change and redistribute it.\n" - "There is NO WARRANTY, to the extent permitted by law.\n"; - -static char *config_file = "osmo_gbproxy.cfg"; -struct gbproxy_config gbcfg; - -/* Pointer to the SGSN peer */ -extern struct gbprox_peer *gbprox_peer_sgsn; - -/* call-back function for the NS protocol */ -static int proxy_ns_cb(enum gprs_ns_evt event, struct gprs_nsvc *nsvc, - struct msgb *msg, u_int16_t bvci) -{ - int rc = 0; - - switch (event) { - case GPRS_NS_EVT_UNIT_DATA: - rc = gbprox_rcvmsg(msg, nsvc, bvci); - break; - default: - LOGP(DGPRS, LOGL_ERROR, "SGSN: Unknown event %u from NS\n", event); - if (msg) - talloc_free(msg); - rc = -EIO; - break; - } - return rc; -} - - -int main(int argc, char **argv) -{ - struct gsm_network dummy_network; - struct log_target *stderr_target; - struct sockaddr_in sin; - int rc; - - tall_bsc_ctx = talloc_named_const(NULL, 0, "nsip_proxy"); - - log_init(&log_info); - stderr_target = log_target_create_stderr(); - log_add_target(stderr_target); - log_set_all_filter(stderr_target, 1); - - telnet_init(&dummy_network, 4244); - rc = gbproxy_parse_config(config_file, &gbcfg); - if (rc < 0) { - LOGP(DGPRS, LOGL_FATAL, "Cannot parse config file\n"); - exit(2); - } - - gbprox_nsi = gprs_ns_instantiate(&proxy_ns_cb); - if (!gbprox_nsi) { - LOGP(DGPRS, LOGL_ERROR, "Unable to instantiate NS\n"); - exit(1); - } - gbcfg.nsi = gbprox_nsi; - nsip_listen(gbprox_nsi, gbcfg.nsip_listen_port); - - /* 'establish' the outgoing connection to the SGSN */ - sin.sin_family = AF_INET; - sin.sin_port = htons(gbcfg.nsip_sgsn_port); - sin.sin_addr.s_addr = htonl(gbcfg.nsip_sgsn_ip); - nsip_connect(gbprox_nsi, &sin, gbcfg.nsip_sgsn_nsei, - gbcfg.nsip_sgsn_nsvci); - - while (1) { - rc = bsc_select_main(0); - if (rc < 0) - exit(3); - } - - exit(0); -} - -struct gsm_network; -int bsc_vty_init(struct gsm_network *dummy) -{ - cmd_init(1); - vty_init(); - - openbsc_vty_add_cmds(); - gbproxy_vty_init(); - return 0; -} - diff --git a/openbsc/src/gb_proxy_vty.c b/openbsc/src/gb_proxy_vty.c deleted file mode 100644 index 16f6a1e0e..000000000 --- a/openbsc/src/gb_proxy_vty.c +++ /dev/null @@ -1,207 +0,0 @@ -/* - * (C) 2010 by Harald Welte - * (C) 2010 by On-Waves - * 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 -#include -#include - -#include -#include - -static struct gbproxy_config *g_cfg = NULL; - -/* - * vty code for mgcp below - */ -static struct cmd_node gbproxy_node = { - GBPROXY_NODE, - "%s(gbproxy)#", - 1, -}; - -static int config_write_gbproxy(struct vty *vty) -{ - struct in_addr ia; - - vty_out(vty, "gbproxy%s", VTY_NEWLINE); - - if (g_cfg->nsip_listen_ip) { - ia.s_addr = htonl(g_cfg->nsip_listen_ip); - vty_out(vty, " nsip bss local ip %s%s", inet_ntoa(ia), - VTY_NEWLINE); - } - vty_out(vty, " nsip bss local port %u%s", g_cfg->nsip_listen_port, - VTY_NEWLINE); - ia.s_addr = htonl(g_cfg->nsip_sgsn_ip); - vty_out(vty, " nsip sgsn remote ip %s%s", inet_ntoa(ia), - VTY_NEWLINE); - vty_out(vty, " nsip sgsn remote port %u%s", g_cfg->nsip_sgsn_port, - VTY_NEWLINE); - vty_out(vty, " nsip sgsn nsei %u%s", g_cfg->nsip_sgsn_nsei, - VTY_NEWLINE); - vty_out(vty, " nsip sgsn nsvci %u%s", g_cfg->nsip_sgsn_nsvci, - VTY_NEWLINE); - - return CMD_SUCCESS; -} - -DEFUN(show_gbproxy, show_gbproxy_cmd, "show gbproxy", - SHOW_STR "Display information about the Gb proxy") -{ - /* FIXME: iterate over list of NS-VC's and display their state */ - struct gprs_ns_inst *nsi = g_cfg->nsi; - struct gprs_nsvc *nsvc; - - llist_for_each_entry(nsvc, &nsi->gprs_nsvcs, list) { - vty_out(vty, "NSEI %5u, NS-VC %5u, %s-mode, %s %s%s", - nsvc->nsei, nsvc->nsvci, - nsvc->remote_end_is_sgsn ? "BSS" : "SGSN", - nsvc->state & NSE_S_ALIVE ? "ALIVE" : "DEAD", - nsvc->state & NSE_S_BLOCKED ? "BLOCKED" : "UNBLOCKED", - VTY_NEWLINE); - if (nsvc->nsi->ll == GPRS_NS_LL_UDP) - vty_out(vty, " remote peer %s:%u%s", - inet_ntoa(nsvc->ip.bts_addr.sin_addr), - ntohs(nsvc->ip.bts_addr.sin_port), VTY_NEWLINE); - } - - return CMD_SUCCESS; -} - -DEFUN(cfg_gbproxy, - cfg_gbproxy_cmd, - "gbproxy", - "Configure the Gb proxy") -{ - vty->node = GBPROXY_NODE; - return CMD_SUCCESS; -} - -DEFUN(cfg_nsip_bss_local_ip, - cfg_nsip_bss_local_ip_cmd, - "nsip bss local ip A.B.C.D", - "Set the IP address on which we listen for BSS connects") -{ - struct in_addr ia; - - inet_aton(argv[0], &ia); - g_cfg->nsip_listen_ip = ntohl(ia.s_addr); - - return CMD_SUCCESS; -} - -DEFUN(cfg_nsip_bss_local_port, - cfg_nsip_bss_local_port_cmd, - "nsip bss local port <0-65534>", - "Set the UDP port on which we listen for BSS connects") -{ - unsigned int port = atoi(argv[0]); - - g_cfg->nsip_listen_port = port; - return CMD_SUCCESS; -} - - -DEFUN(cfg_nsip_sgsn_ip, - cfg_nsip_sgsn_ip_cmd, - "nsip sgsn remote ip A.B.C.D", - "Set the IP of the SGSN to which the proxy shall connect") -{ - struct in_addr ia; - - inet_aton(argv[0], &ia); - g_cfg->nsip_sgsn_ip = ntohl(ia.s_addr); - - return CMD_SUCCESS; -} - -DEFUN(cfg_nsip_sgsn_port, - cfg_nsip_sgsn_port_cmd, - "nsip sgsn remote port <0-65534>", - "Set the UDP port of the SGSN to which the proxy shall connect") -{ - unsigned int port = atoi(argv[0]); - - g_cfg->nsip_sgsn_port = port; - return CMD_SUCCESS; -} - -DEFUN(cfg_nsip_sgsn_nsei, - cfg_nsip_sgsn_nsei_cmd, - "nsip sgsn nsei <0-65534>", - "Set the NSEI to be used in the connection with the SGSN") -{ - unsigned int port = atoi(argv[0]); - - g_cfg->nsip_sgsn_nsei = port; - return CMD_SUCCESS; -} - -DEFUN(cfg_nsip_sgsn_nsvci, - cfg_nsip_sgsn_nsvci_cmd, - "nsip sgsn nsvci <0-65534>", - "Set the NSVCI to be used in the connection with the SGSN") -{ - unsigned int port = atoi(argv[0]); - - g_cfg->nsip_sgsn_nsvci = port; - return CMD_SUCCESS; -} - - -int gbproxy_vty_init(void) -{ - install_element(VIEW_NODE, &show_gbproxy_cmd); - - install_element(CONFIG_NODE, &cfg_gbproxy_cmd); - install_node(&gbproxy_node, config_write_gbproxy); - install_default(GBPROXY_NODE); - install_element(GBPROXY_NODE, &cfg_nsip_bss_local_ip_cmd); - install_element(GBPROXY_NODE, &cfg_nsip_bss_local_port_cmd); - install_element(GBPROXY_NODE, &cfg_nsip_sgsn_ip_cmd); - install_element(GBPROXY_NODE, &cfg_nsip_sgsn_port_cmd); - install_element(GBPROXY_NODE, &cfg_nsip_sgsn_nsei_cmd); - install_element(GBPROXY_NODE, &cfg_nsip_sgsn_nsvci_cmd); - - return 0; -} - -int gbproxy_parse_config(const char *config_file, struct gbproxy_config *cfg) -{ - int rc; - - g_cfg = cfg; - rc = vty_read_config_file(config_file); - if (rc < 0) { - fprintf(stderr, "Failed to parse the config file: '%s'\n", config_file); - return rc; - } - - return 0; -} - diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am new file mode 100644 index 000000000..ac177f7fd --- /dev/null +++ b/openbsc/src/gprs/Makefile.am @@ -0,0 +1,17 @@ +INCLUDES = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir) +AM_CFLAGS=-Wall $(LIBOSMOCORE_CFLAGS) +AM_LDFLAGS = $(LIBOSMOCORE_LIBS) + +sbin_PROGRAMS = osmo-gbproxy osmo-sgsn +noinst_LIBRARIES = libsgsn.a + +libsgsn_a_SOURCES = gprs_ns.c gprs_bssgp.c gprs_llc.c gsm_04_08_gprs.c \ + crc24.c gprs_sgsn.c + +osmo_gbproxy_SOURCES = gb_proxy.c gb_proxy_main.c gb_proxy_vty.c \ + gprs_ns.c ../socket.c ../debug.c +osmo_gbproxy_LDADD = ../libvty.a + +osmo_sgsn_SOURCES = sgsn_main.c sgsn_vty.c \ + ../socket.c ../debug.c +osmo_sgsn_LDADD = ../libvty.a libsgsn.a diff --git a/openbsc/src/gprs/crc24.c b/openbsc/src/gprs/crc24.c new file mode 100644 index 000000000..108212083 --- /dev/null +++ b/openbsc/src/gprs/crc24.c @@ -0,0 +1,69 @@ +/* GPRS LLC CRC-24 Implementation */ + +/* (C) 2008-2009 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 + +/* CRC24 table - FCS */ +static const u_int32_t tbl_crc24[256] = { + 0x00000000, 0x00d6a776, 0x00f64557, 0x0020e221, 0x00b78115, 0x00612663, 0x0041c442, 0x00976334, + 0x00340991, 0x00e2aee7, 0x00c24cc6, 0x0014ebb0, 0x00838884, 0x00552ff2, 0x0075cdd3, 0x00a36aa5, + 0x00681322, 0x00beb454, 0x009e5675, 0x0048f103, 0x00df9237, 0x00093541, 0x0029d760, 0x00ff7016, + 0x005c1ab3, 0x008abdc5, 0x00aa5fe4, 0x007cf892, 0x00eb9ba6, 0x003d3cd0, 0x001ddef1, 0x00cb7987, + 0x00d02644, 0x00068132, 0x00266313, 0x00f0c465, 0x0067a751, 0x00b10027, 0x0091e206, 0x00474570, + 0x00e42fd5, 0x003288a3, 0x00126a82, 0x00c4cdf4, 0x0053aec0, 0x008509b6, 0x00a5eb97, 0x00734ce1, + 0x00b83566, 0x006e9210, 0x004e7031, 0x0098d747, 0x000fb473, 0x00d91305, 0x00f9f124, 0x002f5652, + 0x008c3cf7, 0x005a9b81, 0x007a79a0, 0x00acded6, 0x003bbde2, 0x00ed1a94, 0x00cdf8b5, 0x001b5fc3, + 0x00fb4733, 0x002de045, 0x000d0264, 0x00dba512, 0x004cc626, 0x009a6150, 0x00ba8371, 0x006c2407, + 0x00cf4ea2, 0x0019e9d4, 0x00390bf5, 0x00efac83, 0x0078cfb7, 0x00ae68c1, 0x008e8ae0, 0x00582d96, + 0x00935411, 0x0045f367, 0x00651146, 0x00b3b630, 0x0024d504, 0x00f27272, 0x00d29053, 0x00043725, + 0x00a75d80, 0x0071faf6, 0x005118d7, 0x0087bfa1, 0x0010dc95, 0x00c67be3, 0x00e699c2, 0x00303eb4, + 0x002b6177, 0x00fdc601, 0x00dd2420, 0x000b8356, 0x009ce062, 0x004a4714, 0x006aa535, 0x00bc0243, + 0x001f68e6, 0x00c9cf90, 0x00e92db1, 0x003f8ac7, 0x00a8e9f3, 0x007e4e85, 0x005eaca4, 0x00880bd2, + 0x00437255, 0x0095d523, 0x00b53702, 0x00639074, 0x00f4f340, 0x00225436, 0x0002b617, 0x00d41161, + 0x00777bc4, 0x00a1dcb2, 0x00813e93, 0x005799e5, 0x00c0fad1, 0x00165da7, 0x0036bf86, 0x00e018f0, + 0x00ad85dd, 0x007b22ab, 0x005bc08a, 0x008d67fc, 0x001a04c8, 0x00cca3be, 0x00ec419f, 0x003ae6e9, + 0x00998c4c, 0x004f2b3a, 0x006fc91b, 0x00b96e6d, 0x002e0d59, 0x00f8aa2f, 0x00d8480e, 0x000eef78, + 0x00c596ff, 0x00133189, 0x0033d3a8, 0x00e574de, 0x007217ea, 0x00a4b09c, 0x008452bd, 0x0052f5cb, + 0x00f19f6e, 0x00273818, 0x0007da39, 0x00d17d4f, 0x00461e7b, 0x0090b90d, 0x00b05b2c, 0x0066fc5a, + 0x007da399, 0x00ab04ef, 0x008be6ce, 0x005d41b8, 0x00ca228c, 0x001c85fa, 0x003c67db, 0x00eac0ad, + 0x0049aa08, 0x009f0d7e, 0x00bfef5f, 0x00694829, 0x00fe2b1d, 0x00288c6b, 0x00086e4a, 0x00dec93c, + 0x0015b0bb, 0x00c317cd, 0x00e3f5ec, 0x0035529a, 0x00a231ae, 0x007496d8, 0x005474f9, 0x0082d38f, + 0x0021b92a, 0x00f71e5c, 0x00d7fc7d, 0x00015b0b, 0x0096383f, 0x00409f49, 0x00607d68, 0x00b6da1e, + 0x0056c2ee, 0x00806598, 0x00a087b9, 0x007620cf, 0x00e143fb, 0x0037e48d, 0x001706ac, 0x00c1a1da, + 0x0062cb7f, 0x00b46c09, 0x00948e28, 0x0042295e, 0x00d54a6a, 0x0003ed1c, 0x00230f3d, 0x00f5a84b, + 0x003ed1cc, 0x00e876ba, 0x00c8949b, 0x001e33ed, 0x008950d9, 0x005ff7af, 0x007f158e, 0x00a9b2f8, + 0x000ad85d, 0x00dc7f2b, 0x00fc9d0a, 0x002a3a7c, 0x00bd5948, 0x006bfe3e, 0x004b1c1f, 0x009dbb69, + 0x0086e4aa, 0x005043dc, 0x0070a1fd, 0x00a6068b, 0x003165bf, 0x00e7c2c9, 0x00c720e8, 0x0011879e, + 0x00b2ed3b, 0x00644a4d, 0x0044a86c, 0x00920f1a, 0x00056c2e, 0x00d3cb58, 0x00f32979, 0x00258e0f, + 0x00eef788, 0x003850fe, 0x0018b2df, 0x00ce15a9, 0x0059769d, 0x008fd1eb, 0x00af33ca, 0x007994bc, + 0x00dafe19, 0x000c596f, 0x002cbb4e, 0x00fa1c38, 0x006d7f0c, 0x00bbd87a, 0x009b3a5b, 0x004d9d2d +}; + +#define INIT_CRC24 0xffffff + +u_int32_t crc24_calc(u_int32_t fcs, u_int8_t *cp, unsigned int len) +{ + while (len--) + fcs = (fcs >> 8) ^ tbl_crc24[(fcs ^ *cp++) & 0xff]; + return fcs; +} diff --git a/openbsc/src/gprs/gb_proxy.c b/openbsc/src/gprs/gb_proxy.c new file mode 100644 index 000000000..fe5ad702f --- /dev/null +++ b/openbsc/src/gprs/gb_proxy.c @@ -0,0 +1,416 @@ +/* NS-over-IP proxy */ + +/* (C) 2010 by Harald Welte + * (C) 2010 by On Waves + * 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 +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +struct gbprox_peer { + struct llist_head list; + + /* NS-VC over which we send/receive data to this BVC */ + struct gprs_nsvc *nsvc; + + /* BVCI used for Point-to-Point to this peer */ + uint16_t bvci; + + /* Routeing Area that this peer is part of (raw 04.08 encoding) */ + uint8_t ra[6]; +}; + +/* Linked list of all Gb peers (except SGSN) */ +static LLIST_HEAD(gbprox_bts_peers); + +extern struct gprs_ns_inst *gbprox_nsi; + +/* Find the gbprox_peer by its BVCI */ +static struct gbprox_peer *peer_by_bvci(uint16_t bvci) +{ + struct gbprox_peer *peer; + llist_for_each_entry(peer, &gbprox_bts_peers, list) { + if (peer->bvci == bvci) + return peer; + } + return NULL; +} + +static struct gbprox_peer *peer_by_nsvc(struct gprs_nsvc *nsvc) +{ + struct gbprox_peer *peer; + llist_for_each_entry(peer, &gbprox_bts_peers, list) { + if (peer->nsvc == nsvc) + return peer; + } + return NULL; +} + +/* look-up a peer by its Routeing Area Code (RAC) */ +static struct gbprox_peer *peer_by_rac(const uint8_t *ra) +{ + struct gbprox_peer *peer; + llist_for_each_entry(peer, &gbprox_bts_peers, list) { + if (!memcmp(&peer->ra, ra, 6)) + return peer; + } + return NULL; +} + +/* look-up a peer by its Location Area Code (LAC) */ +static struct gbprox_peer *peer_by_lac(const uint8_t *la) +{ + struct gbprox_peer *peer; + llist_for_each_entry(peer, &gbprox_bts_peers, list) { + if (!memcmp(&peer->ra, la, 5)) + return peer; + } + return NULL; +} + +static struct gbprox_peer *peer_alloc(uint16_t bvci) +{ + struct gbprox_peer *peer; + + peer = talloc_zero(tall_bsc_ctx, struct gbprox_peer); + if (!peer) + return NULL; + + peer->bvci = bvci; + llist_add(&peer->list, &gbprox_bts_peers); + + return peer; +} + +static void peer_free(struct gbprox_peer *peer) +{ + llist_del(&peer->list); + talloc_free(peer); +} + +/* strip off the NS header */ +static void strip_ns_hdr(struct msgb *msg) +{ + int strip_len = msgb_bssgph(msg) - msg->data; + msgb_pull(msg, strip_len); +} + +/* FIXME: this is copy+paste from gprs_bssgp.c */ +static inline struct msgb *bssgp_msgb_alloc(void) +{ + return msgb_alloc_headroom(4096, 128, "BSSGP"); +} +static int bssgp_tx_simple_bvci(uint8_t pdu_type, uint16_t nsei, + uint16_t bvci, uint16_t ns_bvci) +{ + struct msgb *msg = bssgp_msgb_alloc(); + struct bssgp_normal_hdr *bgph = + (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph)); + uint16_t _bvci; + + msgb_nsei(msg) = nsei; + msgb_bvci(msg) = ns_bvci; + + bgph->pdu_type = pdu_type; + _bvci = htons(bvci); + msgb_tvlv_put(msg, BSSGP_IE_BVCI, 2, (uint8_t *) &_bvci); + + return gprs_ns_sendmsg(gbprox_nsi, msg); +} + + +/* feed a message down the NS-VC associated with the specified peer */ +static int gbprox_relay2sgsn(struct msgb *msg, uint16_t ns_bvci) +{ + DEBUGP(DGPRS, "NSEI=%u proxying to SGSN (NS_BVCI=%u, NSEI=%u)\n", + msgb_nsei(msg), ns_bvci, gbcfg.nsip_sgsn_nsei); + + msgb_bvci(msg) = ns_bvci; + msgb_nsei(msg) = gbcfg.nsip_sgsn_nsei; + + strip_ns_hdr(msg); + + return gprs_ns_sendmsg(gbprox_nsi, msg); +} + +/* feed a message down the NS-VC associated with the specified peer */ +static int gbprox_relay2peer(struct msgb *msg, struct gbprox_peer *peer, + uint16_t ns_bvci) +{ + DEBUGP(DGPRS, "NSEI=%u proxying to BSS (NS_BVCI=%u, NSEI=%u)\n", + msgb_nsei(msg), ns_bvci, peer->nsvc->nsei); + + msgb_bvci(msg) = ns_bvci; + msgb_nsei(msg) = peer->nsvc->nsei; + + strip_ns_hdr(msg); + + return gprs_ns_sendmsg(gbprox_nsi, msg); +} + +/* Send a message to a peer identified by ptp_bvci but using ns_bvci + * in the NS hdr */ +static int gbprox_relay2bvci(struct msgb *msg, uint16_t ptp_bvci, + uint16_t ns_bvci) +{ + struct gbprox_peer *peer; + + peer = peer_by_bvci(ptp_bvci); + if (!peer) { + LOGP(DGPRS, LOGL_ERROR, "Cannot find BSS for BVCI %u\n", + ptp_bvci); + return -ENOENT; + } + + return gbprox_relay2peer(msg, peer, ns_bvci); +} + +/* Receive an incoming signalling message from a BSS-side NS-VC */ +static int gbprox_rx_sig_from_bss(struct msgb *msg, struct gprs_nsvc *nsvc, + uint16_t ns_bvci) +{ + struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msgb_bssgph(msg); + struct tlv_parsed tp; + uint8_t pdu_type = bgph->pdu_type; + int data_len = msgb_bssgp_len(msg) - sizeof(*bgph); + struct gbprox_peer *from_peer; + struct gprs_ra_id raid; + + if (ns_bvci != 0) { + LOGP(DGPRS, LOGL_NOTICE, "NSEI=%u BVCI %u is not signalling\n", + nsvc->nsei, ns_bvci); + return -EINVAL; + } + + /* we actually should never see those two for BVCI == 0, but double-check + * just to make sure */ + if (pdu_type == BSSGP_PDUT_UL_UNITDATA || + pdu_type == BSSGP_PDUT_DL_UNITDATA) { + LOGP(DGPRS, LOGL_NOTICE, "NSEI=%u UNITDATA not allowed in " + "signalling\n", nsvc->nsei); + return -EINVAL; + } + + bssgp_tlv_parse(&tp, bgph->data, data_len); + + switch (pdu_type) { + case BSSGP_PDUT_SUSPEND: + case BSSGP_PDUT_RESUME: + /* We implement RAC snooping during SUSPEND/RESUME, since + * it establishes a relationsip between BVCI/peer and the + * routeing area code. The snooped information is then + * used for routing the {SUSPEND,RESUME}_[N]ACK back to + * the correct BSSGP */ + if (!TLVP_PRESENT(&tp, BSSGP_IE_ROUTEING_AREA)) + goto err_mand_ie; + from_peer = peer_by_nsvc(nsvc); + if (!from_peer) + goto err_no_peer; + memcpy(&from_peer->ra, TLVP_VAL(&tp, BSSGP_IE_ROUTEING_AREA), + sizeof(&from_peer->ra)); + gsm48_parse_ra(&raid, &from_peer->ra); + DEBUGP(DGPRS, "NSEI=%u RAC snooping: RAC %u/%u/%u/%u behind BVCI=%u, " + "NSVCI=%u\n", nsvc->nsei, raid.mcc, raid.mnc, raid.lac, + raid.rac , from_peer->bvci, nsvc->nsvci); + /* FIXME: This only supports one BSS per RA */ + break; + case BSSGP_PDUT_BVC_RESET: + /* If we receive a BVC reset on the signalling endpoint, we + * don't want the SGSN to reset, as the signalling endpoint + * is common for all point-to-point BVCs (and thus all BTS) */ + if (TLVP_PRESENT(&tp, BSSGP_IE_BVCI)) { + uint16_t bvci = ntohs(*(uint16_t *)TLVP_VAL(&tp, BSSGP_IE_BVCI)); + if (bvci == 0) { + /* FIXME: only do this if SGSN is alive! */ + LOGP(DGPRS, LOGL_INFO, "NSEI=%u Sending fake " + "BVC RESET ACK of BVCI=0\n", nsvc->nsei); + return bssgp_tx_simple_bvci(BSSGP_PDUT_BVC_RESET_ACK, + nsvc->nsei, 0, ns_bvci); + } else if (!peer_by_bvci(bvci)) { + /* if a PTP-BVC is reset, and we don't know that + * PTP-BVCI yet, we should allocate a new peer */ + LOGP(DGPRS, LOGL_INFO, "Allocationg new peer for " + "BVCI=%u via NSVCI=%u/NSEI=%u\n", bvci, + nsvc->nsvci, nsvc->nsei); + from_peer = peer_alloc(bvci); + from_peer->nsvc = nsvc; + } + } + break; + } + + /* Normally, we can simply pass on all signalling messages from BSS to SGSN */ + return gbprox_relay2sgsn(msg, ns_bvci); +err_no_peer: +err_mand_ie: + /* FIXME: do something */ + ; +} + +/* Receive paging request from SGSN, we need to relay to proper BSS */ +static int gbprox_rx_paging(struct msgb *msg, struct tlv_parsed *tp, + struct gprs_nsvc *nsvc, uint16_t ns_bvci) +{ + struct gbprox_peer *peer; + + if (TLVP_PRESENT(tp, BSSGP_IE_BVCI)) { + uint16_t bvci = ntohs(*(uint16_t *)TLVP_VAL(tp, BSSGP_IE_BVCI)); + return gbprox_relay2bvci(msg, bvci, ns_bvci); + } else if (TLVP_PRESENT(tp, BSSGP_IE_ROUTEING_AREA)) { + peer = peer_by_rac(TLVP_VAL(tp, BSSGP_IE_ROUTEING_AREA)); + return gbprox_relay2peer(msg, peer, ns_bvci); + } else if (TLVP_PRESENT(tp, BSSGP_IE_LOCATION_AREA)) { + peer = peer_by_lac(TLVP_VAL(tp, BSSGP_IE_LOCATION_AREA)); + return gbprox_relay2peer(msg, peer, ns_bvci); + } else + return -EINVAL; +} + +/* Receive an incoming signalling message from the SGSN-side NS-VC */ +static int gbprox_rx_sig_from_sgsn(struct msgb *msg, struct gprs_nsvc *nsvc, + uint16_t ns_bvci) +{ + struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msgb_bssgph(msg); + struct tlv_parsed tp; + uint8_t pdu_type = bgph->pdu_type; + int data_len = msgb_bssgp_len(msg) - sizeof(*bgph); + struct gbprox_peer *peer; + uint16_t bvci; + int rc = 0; + + if (ns_bvci != 0) { + LOGP(DGPRS, LOGL_NOTICE, "NSEI=%u(SGSN) BVCI %u is not " + "signalling\n", nsvc->nsei, ns_bvci); + return -EINVAL; + } + + /* we actually should never see those two for BVCI == 0, but double-check + * just to make sure */ + if (pdu_type == BSSGP_PDUT_UL_UNITDATA || + pdu_type == BSSGP_PDUT_DL_UNITDATA) { + LOGP(DGPRS, LOGL_NOTICE, "NSEI=%u(SGSN) UNITDATA not allowed in " + "signalling\n", nsvc->nsei); + return -EINVAL; + } + + rc = bssgp_tlv_parse(&tp, bgph->data, data_len); + + switch (pdu_type) { + case BSSGP_PDUT_FLUSH_LL: + case BSSGP_PDUT_BVC_BLOCK_ACK: + case BSSGP_PDUT_BVC_UNBLOCK_ACK: + case BSSGP_PDUT_BVC_RESET: + case BSSGP_PDUT_BVC_RESET_ACK: + /* simple case: BVCI IE is mandatory */ + if (!TLVP_PRESENT(&tp, BSSGP_IE_BVCI)) + goto err_mand_ie; + bvci = ntohs(*(uint16_t *)TLVP_VAL(&tp, BSSGP_IE_BVCI)); + rc = gbprox_relay2bvci(msg, bvci, ns_bvci); + break; + case BSSGP_PDUT_PAGING_PS: + case BSSGP_PDUT_PAGING_CS: + /* process the paging request (LAC/RAC lookup) */ + rc = gbprox_rx_paging(msg, &tp, nsvc, ns_bvci); + break; + case BSSGP_PDUT_STATUS: + /* FIXME: Some exception has occurred */ + LOGP(DGPRS, LOGL_NOTICE, + "NSEI=%u(SGSN) STATUS not implemented yet\n", nsvc->nsei); + break; + /* those only exist in the SGSN -> BSS direction */ + case BSSGP_PDUT_SUSPEND_ACK: + case BSSGP_PDUT_SUSPEND_NACK: + case BSSGP_PDUT_RESUME_ACK: + case BSSGP_PDUT_RESUME_NACK: + /* RAC IE is mandatory */ + if (!TLVP_PRESENT(&tp, BSSGP_IE_ROUTEING_AREA)) + goto err_mand_ie; + peer = peer_by_rac(TLVP_VAL(&tp, BSSGP_IE_ROUTEING_AREA)); + if (!peer) + goto err_no_peer; + rc = gbprox_relay2peer(msg, peer, ns_bvci); + break; + case BSSGP_PDUT_SGSN_INVOKE_TRACE: + LOGP(DGPRS, LOGL_ERROR, + "NSEI=%u(SGSN) INVOKE TRACE not supported\n", nsvc->nsei); + break; + default: + DEBUGP(DGPRS, "BSSGP PDU type 0x%02x unknown\n", pdu_type); + break; + } + + return rc; +err_mand_ie: + LOGP(DGPRS, LOGL_ERROR, "NSEI=%u(SGSN) missing mandatory IE\n", + nsvc->nsei); + /* FIXME: this would pull gprs_bssgp.c in, which in turn has dependencies */ + //return bssgp_tx_status(BSSGP_CAUSE_MISSING_MAND_IE, NULL, msg); + return; +err_no_peer: + LOGP(DGPRS, LOGL_ERROR, "NSEI=%u(SGSN) cannot find peer based on RAC\n"); + /* FIXME */ + return; +} + +/* Main input function for Gb proxy */ +int gbprox_rcvmsg(struct msgb *msg, struct gprs_nsvc *nsvc, uint16_t ns_bvci) +{ + int rc; + + /* Only BVCI=0 messages need special treatment */ + if (ns_bvci == 0 || ns_bvci == 1) { + if (nsvc->remote_end_is_sgsn) + rc = gbprox_rx_sig_from_sgsn(msg, nsvc, ns_bvci); + else + rc = gbprox_rx_sig_from_bss(msg, nsvc, ns_bvci); + } else { + /* All other BVCI are PTP and thus can be simply forwarded */ + if (!nsvc->remote_end_is_sgsn) { + rc = gbprox_relay2sgsn(msg, ns_bvci); + } else { + struct gbprox_peer *peer = peer_by_bvci(ns_bvci); + if (!peer) { + LOGP(DGPRS, LOGL_NOTICE, "Allocationg new peer for " + "BVCI=%u via NSVC=%u/NSEI=%u\n", ns_bvci, + nsvc->nsvci, nsvc->nsei); + peer = peer_alloc(ns_bvci); + peer->nsvc = nsvc; + } + rc = gbprox_relay2peer(msg, peer, ns_bvci); + } + } + + return rc; +} diff --git a/openbsc/src/gprs/gb_proxy_main.c b/openbsc/src/gprs/gb_proxy_main.c new file mode 100644 index 000000000..0054b7844 --- /dev/null +++ b/openbsc/src/gprs/gb_proxy_main.c @@ -0,0 +1,149 @@ +/* NS-over-IP proxy */ + +/* (C) 2010 by Harald Welte + * (C) 2010 by On Waves + * 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 +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "../../bscconfig.h" + +/* this is here for the vty... it will never be called */ +void subscr_put() { abort(); } + +#define _GNU_SOURCE +#include + +void *tall_bsc_ctx; + +struct gprs_ns_inst *gbprox_nsi; + +const char *openbsc_version = "Osmocom NSIP Proxy " PACKAGE_VERSION; +const char *openbsc_copyright = + "Copyright (C) 2010 Harald Welte and On-Waves\n" + "Contributions by Daniel Willmann, Jan Lübbe, Stefan Schmidt\n" + "Dieter Spaar, Andreas Eversberg, Holger Freyther\n\n" + "License GPLv2+: GNU GPL version 2 or later \n" + "This is free software: you are free to change and redistribute it.\n" + "There is NO WARRANTY, to the extent permitted by law.\n"; + +static char *config_file = "osmo_gbproxy.cfg"; +struct gbproxy_config gbcfg; + +/* Pointer to the SGSN peer */ +extern struct gbprox_peer *gbprox_peer_sgsn; + +/* call-back function for the NS protocol */ +static int proxy_ns_cb(enum gprs_ns_evt event, struct gprs_nsvc *nsvc, + struct msgb *msg, u_int16_t bvci) +{ + int rc = 0; + + switch (event) { + case GPRS_NS_EVT_UNIT_DATA: + rc = gbprox_rcvmsg(msg, nsvc, bvci); + break; + default: + LOGP(DGPRS, LOGL_ERROR, "SGSN: Unknown event %u from NS\n", event); + if (msg) + talloc_free(msg); + rc = -EIO; + break; + } + return rc; +} + + +int main(int argc, char **argv) +{ + struct gsm_network dummy_network; + struct log_target *stderr_target; + struct sockaddr_in sin; + int rc; + + tall_bsc_ctx = talloc_named_const(NULL, 0, "nsip_proxy"); + + log_init(&log_info); + stderr_target = log_target_create_stderr(); + log_add_target(stderr_target); + log_set_all_filter(stderr_target, 1); + + telnet_init(&dummy_network, 4244); + rc = gbproxy_parse_config(config_file, &gbcfg); + if (rc < 0) { + LOGP(DGPRS, LOGL_FATAL, "Cannot parse config file\n"); + exit(2); + } + + gbprox_nsi = gprs_ns_instantiate(&proxy_ns_cb); + if (!gbprox_nsi) { + LOGP(DGPRS, LOGL_ERROR, "Unable to instantiate NS\n"); + exit(1); + } + gbcfg.nsi = gbprox_nsi; + nsip_listen(gbprox_nsi, gbcfg.nsip_listen_port); + + /* 'establish' the outgoing connection to the SGSN */ + sin.sin_family = AF_INET; + sin.sin_port = htons(gbcfg.nsip_sgsn_port); + sin.sin_addr.s_addr = htonl(gbcfg.nsip_sgsn_ip); + nsip_connect(gbprox_nsi, &sin, gbcfg.nsip_sgsn_nsei, + gbcfg.nsip_sgsn_nsvci); + + while (1) { + rc = bsc_select_main(0); + if (rc < 0) + exit(3); + } + + exit(0); +} + +struct gsm_network; +int bsc_vty_init(struct gsm_network *dummy) +{ + cmd_init(1); + vty_init(); + + openbsc_vty_add_cmds(); + gbproxy_vty_init(); + return 0; +} + diff --git a/openbsc/src/gprs/gb_proxy_vty.c b/openbsc/src/gprs/gb_proxy_vty.c new file mode 100644 index 000000000..16f6a1e0e --- /dev/null +++ b/openbsc/src/gprs/gb_proxy_vty.c @@ -0,0 +1,207 @@ +/* + * (C) 2010 by Harald Welte + * (C) 2010 by On-Waves + * 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 +#include +#include + +#include +#include + +static struct gbproxy_config *g_cfg = NULL; + +/* + * vty code for mgcp below + */ +static struct cmd_node gbproxy_node = { + GBPROXY_NODE, + "%s(gbproxy)#", + 1, +}; + +static int config_write_gbproxy(struct vty *vty) +{ + struct in_addr ia; + + vty_out(vty, "gbproxy%s", VTY_NEWLINE); + + if (g_cfg->nsip_listen_ip) { + ia.s_addr = htonl(g_cfg->nsip_listen_ip); + vty_out(vty, " nsip bss local ip %s%s", inet_ntoa(ia), + VTY_NEWLINE); + } + vty_out(vty, " nsip bss local port %u%s", g_cfg->nsip_listen_port, + VTY_NEWLINE); + ia.s_addr = htonl(g_cfg->nsip_sgsn_ip); + vty_out(vty, " nsip sgsn remote ip %s%s", inet_ntoa(ia), + VTY_NEWLINE); + vty_out(vty, " nsip sgsn remote port %u%s", g_cfg->nsip_sgsn_port, + VTY_NEWLINE); + vty_out(vty, " nsip sgsn nsei %u%s", g_cfg->nsip_sgsn_nsei, + VTY_NEWLINE); + vty_out(vty, " nsip sgsn nsvci %u%s", g_cfg->nsip_sgsn_nsvci, + VTY_NEWLINE); + + return CMD_SUCCESS; +} + +DEFUN(show_gbproxy, show_gbproxy_cmd, "show gbproxy", + SHOW_STR "Display information about the Gb proxy") +{ + /* FIXME: iterate over list of NS-VC's and display their state */ + struct gprs_ns_inst *nsi = g_cfg->nsi; + struct gprs_nsvc *nsvc; + + llist_for_each_entry(nsvc, &nsi->gprs_nsvcs, list) { + vty_out(vty, "NSEI %5u, NS-VC %5u, %s-mode, %s %s%s", + nsvc->nsei, nsvc->nsvci, + nsvc->remote_end_is_sgsn ? "BSS" : "SGSN", + nsvc->state & NSE_S_ALIVE ? "ALIVE" : "DEAD", + nsvc->state & NSE_S_BLOCKED ? "BLOCKED" : "UNBLOCKED", + VTY_NEWLINE); + if (nsvc->nsi->ll == GPRS_NS_LL_UDP) + vty_out(vty, " remote peer %s:%u%s", + inet_ntoa(nsvc->ip.bts_addr.sin_addr), + ntohs(nsvc->ip.bts_addr.sin_port), VTY_NEWLINE); + } + + return CMD_SUCCESS; +} + +DEFUN(cfg_gbproxy, + cfg_gbproxy_cmd, + "gbproxy", + "Configure the Gb proxy") +{ + vty->node = GBPROXY_NODE; + return CMD_SUCCESS; +} + +DEFUN(cfg_nsip_bss_local_ip, + cfg_nsip_bss_local_ip_cmd, + "nsip bss local ip A.B.C.D", + "Set the IP address on which we listen for BSS connects") +{ + struct in_addr ia; + + inet_aton(argv[0], &ia); + g_cfg->nsip_listen_ip = ntohl(ia.s_addr); + + return CMD_SUCCESS; +} + +DEFUN(cfg_nsip_bss_local_port, + cfg_nsip_bss_local_port_cmd, + "nsip bss local port <0-65534>", + "Set the UDP port on which we listen for BSS connects") +{ + unsigned int port = atoi(argv[0]); + + g_cfg->nsip_listen_port = port; + return CMD_SUCCESS; +} + + +DEFUN(cfg_nsip_sgsn_ip, + cfg_nsip_sgsn_ip_cmd, + "nsip sgsn remote ip A.B.C.D", + "Set the IP of the SGSN to which the proxy shall connect") +{ + struct in_addr ia; + + inet_aton(argv[0], &ia); + g_cfg->nsip_sgsn_ip = ntohl(ia.s_addr); + + return CMD_SUCCESS; +} + +DEFUN(cfg_nsip_sgsn_port, + cfg_nsip_sgsn_port_cmd, + "nsip sgsn remote port <0-65534>", + "Set the UDP port of the SGSN to which the proxy shall connect") +{ + unsigned int port = atoi(argv[0]); + + g_cfg->nsip_sgsn_port = port; + return CMD_SUCCESS; +} + +DEFUN(cfg_nsip_sgsn_nsei, + cfg_nsip_sgsn_nsei_cmd, + "nsip sgsn nsei <0-65534>", + "Set the NSEI to be used in the connection with the SGSN") +{ + unsigned int port = atoi(argv[0]); + + g_cfg->nsip_sgsn_nsei = port; + return CMD_SUCCESS; +} + +DEFUN(cfg_nsip_sgsn_nsvci, + cfg_nsip_sgsn_nsvci_cmd, + "nsip sgsn nsvci <0-65534>", + "Set the NSVCI to be used in the connection with the SGSN") +{ + unsigned int port = atoi(argv[0]); + + g_cfg->nsip_sgsn_nsvci = port; + return CMD_SUCCESS; +} + + +int gbproxy_vty_init(void) +{ + install_element(VIEW_NODE, &show_gbproxy_cmd); + + install_element(CONFIG_NODE, &cfg_gbproxy_cmd); + install_node(&gbproxy_node, config_write_gbproxy); + install_default(GBPROXY_NODE); + install_element(GBPROXY_NODE, &cfg_nsip_bss_local_ip_cmd); + install_element(GBPROXY_NODE, &cfg_nsip_bss_local_port_cmd); + install_element(GBPROXY_NODE, &cfg_nsip_sgsn_ip_cmd); + install_element(GBPROXY_NODE, &cfg_nsip_sgsn_port_cmd); + install_element(GBPROXY_NODE, &cfg_nsip_sgsn_nsei_cmd); + install_element(GBPROXY_NODE, &cfg_nsip_sgsn_nsvci_cmd); + + return 0; +} + +int gbproxy_parse_config(const char *config_file, struct gbproxy_config *cfg) +{ + int rc; + + g_cfg = cfg; + rc = vty_read_config_file(config_file); + if (rc < 0) { + fprintf(stderr, "Failed to parse the config file: '%s'\n", config_file); + return rc; + } + + return 0; +} + diff --git a/openbsc/src/gprs/gprs_bssgp.c b/openbsc/src/gprs/gprs_bssgp.c new file mode 100644 index 000000000..554738b56 --- /dev/null +++ b/openbsc/src/gprs/gprs_bssgp.c @@ -0,0 +1,537 @@ +/* GPRS BSSGP protocol implementation as per 3GPP TS 08.18 */ + +/* (C) 2009-2010 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 + +#include +#include +#include +#include +#include +#include + +/* global pointer to the gsm network data structure */ +/* FIXME: this must go! */ +extern struct gsm_network *bsc_gsmnet; +struct gprs_ns_inst *bssgp_nsi; + +void *bssgp_tall_ctx = NULL; + +/* BSSGP Protocol specific, not implementation specific */ +/* FIXME: This needs to go into libosmocore after finished */ + +/* Chapter 11.3.9 / Table 11.10: Cause coding */ +static const struct value_string bssgp_cause_strings[] = { + { BSSGP_CAUSE_PROC_OVERLOAD, "Processor overload" }, + { BSSGP_CAUSE_EQUIP_FAIL, "Equipment Failure" }, + { BSSGP_CAUSE_TRASIT_NET_FAIL, "Transit netowkr service failure" }, + { BSSGP_CAUSE_CAPA_GREATER_0KPBS,"Transmission capacity modified" }, + { BSSGP_CAUSE_UNKNOWN_MS, "Unknown MS" }, + { BSSGP_CAUSE_UNKNOWN_BVCI, "Unknown BVCI" }, + { BSSGP_CAUSE_CELL_TRAF_CONG, "Cell traffic congestion" }, + { BSSGP_CAUSE_SGSN_CONG, "SGSN congestion" }, + { BSSGP_CAUSE_OML_INTERV, "O&M intervention" }, + { BSSGP_CAUSE_BVCI_BLOCKED, "BVCI blocked" }, + { BSSGP_CAUSE_PFC_CREATE_FAIL, "PFC create failure" }, + { BSSGP_CAUSE_SEM_INCORR_PDU, "Semantically incorrect PDU" }, + { BSSGP_CAUSE_INV_MAND_INF, "Invalid mandatory information" }, + { BSSGP_CAUSE_MISSING_MAND_IE, "Missing mandatory IE" }, + { BSSGP_CAUSE_MISSING_COND_IE, "Missing conditional IE" }, + { BSSGP_CAUSE_UNEXP_COND_IE, "Unexpected conditional IE" }, + { BSSGP_CAUSE_COND_IE_ERR, "Conditional IE error" }, + { BSSGP_CAUSE_PDU_INCOMP_STATE, "PDU incompatible with protocol state" }, + { BSSGP_CAUSE_PROTO_ERR_UNSPEC, "Protocol error - unspecified" }, + { BSSGP_CAUSE_PDU_INCOMP_FEAT, "PDU not compatible with feature set" }, + { 0, NULL }, +}; + +const char *bssgp_cause_str(enum gprs_bssgp_cause cause) +{ + return get_value_string(bssgp_cause_strings, cause); +} + + +/* Our actual implementation */ + +#define BVC_F_BLOCKED 0x0001 + +/* The per-BTS context that we keep on the SGSN side of the BSSGP link */ +struct bssgp_bts_ctx { + struct llist_head list; + + /* parsed RA ID and Cell ID of the remote BTS */ + struct gprs_ra_id ra_id; + uint16_t cell_id; + + /* NSEI and BVCI of underlying Gb link. Together they + * uniquely identify a link to a BTS (5.4.4) */ + uint16_t bvci; + uint16_t nsei; + + uint32_t bvc_state; + + /* we might want to add this as a shortcut later, avoiding the NSVC + * lookup for every packet, similar to a routing cache */ + //struct gprs_nsvc *nsvc; +}; +LLIST_HEAD(bts_ctxts); + +/* Find a BTS Context based on parsed RA ID and Cell ID */ +struct bssgp_bts_ctx *btsctx_by_raid_cid(const struct gprs_ra_id *raid, uint16_t cid) +{ + struct bssgp_bts_ctx *bctx; + + llist_for_each_entry(bctx, &bts_ctxts, list) { + if (!memcmp(&bctx->ra_id, raid, sizeof(bctx->ra_id)) && + bctx->cell_id == cid) + return bctx; + } + return NULL; +} + +/* Find a BTS context based on BVCI+NSEI tuple */ +struct bssgp_bts_ctx *btsctx_by_bvci_nsei(uint16_t bvci, uint16_t nsei) +{ + struct bssgp_bts_ctx *bctx; + + llist_for_each_entry(bctx, &bts_ctxts, list) { + if (bctx->nsei == nsei && bctx->bvci == bvci) + return bctx; + } + return NULL; +} + +struct bssgp_btx_ctx *btsctx_alloc(uint16_t bvci, uint16_t nsei) +{ + struct bssgp_bts_ctx *ctx; + + ctx = talloc_zero(bssgp_tall_ctx, struct bssgp_bts_ctx); + if (!ctx) + return NULL; + ctx->bvci = bvci; + ctx->nsei = nsei; + llist_add(&ctx->list, &bts_ctxts); + + return ctx; +} + +static inline struct msgb *bssgp_msgb_alloc(void) +{ + return msgb_alloc_headroom(4096, 128, "BSSGP"); +} + +/* Transmit a simple response such as BLOCK/UNBLOCK/RESET ACK/NACK */ +static int bssgp_tx_simple_bvci(uint8_t pdu_type, uint16_t nsei, + uint16_t bvci, uint16_t ns_bvci) +{ + struct msgb *msg = bssgp_msgb_alloc(); + struct bssgp_normal_hdr *bgph = + (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph)); + uint16_t _bvci; + + msgb_nsei(msg) = nsei; + msgb_bvci(msg) = ns_bvci; + + bgph->pdu_type = pdu_type; + _bvci = htons(bvci); + msgb_tvlv_put(msg, BSSGP_IE_BVCI, 2, (uint8_t *) &_bvci); + + return gprs_ns_sendmsg(bssgp_nsi, msg); +} + +/* Chapter 10.4.5: Flow Control BVC ACK */ +static int bssgp_tx_fc_bvc_ack(uint16_t nsei, uint8_t tag, uint16_t ns_bvci) +{ + struct msgb *msg = bssgp_msgb_alloc(); + struct bssgp_normal_hdr *bgph = + (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph)); + + msgb_nsei(msg) = nsei; + msgb_bvci(msg) = ns_bvci; + + bgph->pdu_type = BSSGP_PDUT_FLOW_CONTROL_BVC_ACK; + msgb_tvlv_put(msg, BSSGP_IE_TAG, 1, &tag); + + return gprs_ns_sendmsg(bssgp_nsi, msg); +} + +/* Chapter 10.4.14: Status */ +int bssgp_tx_status(uint8_t cause, uint16_t *bvci, struct msgb *orig_msg) +{ + struct msgb *msg = bssgp_msgb_alloc(); + struct bssgp_normal_hdr *bgph = + (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph)); + + DEBUGPC(DGPRS, "BSSGP: TX STATUS, cause=%s\n", bssgp_cause_str(cause)); + msgb_nsei(msg) = msgb_nsei(orig_msg); + msgb_bvci(msg) = 0; + + bgph->pdu_type = BSSGP_PDUT_STATUS; + msgb_tvlv_put(msg, BSSGP_IE_CAUSE, 1, &cause); + if (bvci) { + uint16_t _bvci = htons(*bvci); + msgb_tvlv_put(msg, BSSGP_IE_BVCI, 2, (uint8_t *) &_bvci); + } + if (orig_msg) + msgb_tvlv_put(msg, BSSGP_IE_PDU_IN_ERROR, + msgb_bssgp_len(orig_msg), msgb_bssgph(orig_msg)); + + return gprs_ns_sendmsg(bssgp_nsi, msg); +} + +uint16_t bssgp_parse_cell_id(struct gprs_ra_id *raid, const uint8_t *buf) +{ + /* 6 octets RAC */ + gsm48_parse_ra(raid, buf); + /* 2 octets CID */ + return ntohs(*(uint16_t *) (buf+6)); +} + +/* Chapter 8.4 BVC-Reset Procedure */ +static int bssgp_rx_bvc_reset(struct msgb *msg, struct tlv_parsed *tp, + uint16_t ns_bvci) +{ + struct bssgp_bts_ctx *bctx; + uint16_t nsei = msgb_nsei(msg); + uint16_t bvci; + int rc; + + bvci = ntohs(*(uint16_t *)TLVP_VAL(tp, BSSGP_IE_BVCI)); + DEBUGPC(DGPRS, "BVCI=%u, cause=%s\n", bvci, + bssgp_cause_str(*TLVP_VAL(tp, BSSGP_IE_CAUSE))); + + /* look-up or create the BTS context for this BVC */ + bctx = btsctx_by_bvci_nsei(bvci, nsei); + if (!bctx) + bctx = btsctx_alloc(bvci, nsei); + + /* When we receive a BVC-RESET PDU (at least of a PTP BVCI), the BSS + * informs us about its RAC + Cell ID, so we can create a mapping */ + if (bvci != 0 && bvci != 1) { + if (!TLVP_PRESENT(tp, BSSGP_IE_CELL_ID)) { + LOGP(DGPRS, LOGL_ERROR, "BSSGP RESET BVCI=%u " + "missing mandatory IE\n", bvci); + return -EINVAL; + } + /* actually extract RAC / CID */ + bctx->cell_id = bssgp_parse_cell_id(&bctx->ra_id, + TLVP_VAL(tp, BSSGP_IE_CELL_ID)); + LOGP(DGPRS, LOGL_NOTICE, "Cell %u-%u-%u-%u CI %u on BVCI %u\n", + bctx->ra_id.mcc, bctx->ra_id.mnc, bctx->ra_id.lac, + bctx->ra_id.rac, bctx->cell_id, bvci); + } + + /* Acknowledge the RESET to the BTS */ + rc = bssgp_tx_simple_bvci(BSSGP_PDUT_BVC_RESET_ACK, + nsei, bvci, ns_bvci); + return 0; +} + +/* Uplink unit-data */ +static int bssgp_rx_ul_ud(struct msgb *msg) +{ + struct bssgp_ud_hdr *budh = (struct bssgp_ud_hdr *) msgb_bssgph(msg); + int data_len = msgb_bssgp_len(msg) - sizeof(*budh); + struct tlv_parsed tp; + int rc; + + DEBUGP(DGPRS, "BSSGP UL-UD\n"); + + /* extract TLLI and parse TLV IEs */ + msgb_tlli(msg) = ntohl(budh->tlli); + rc = bssgp_tlv_parse(&tp, budh->data, data_len); + + /* Cell ID and LLC_PDU are the only mandatory IE */ + if (!TLVP_PRESENT(&tp, BSSGP_IE_CELL_ID) || + !TLVP_PRESENT(&tp, BSSGP_IE_LLC_PDU)) + return -EIO; + + /* FIXME: lookup bssgp_bts_ctx based on BVCI + NSEI */ + + /* store pointer to LLC header and CELL ID in msgb->cb */ + msgb_llch(msg) = TLVP_VAL(&tp, BSSGP_IE_LLC_PDU); + msgb_bcid(msg) = TLVP_VAL(&tp, BSSGP_IE_CELL_ID); + + return gprs_llc_rcvmsg(msg, &tp); +} + +static int bssgp_rx_suspend(struct msgb *msg) +{ + struct bssgp_normal_hdr *bgph = + (struct bssgp_normal_hdr *) msgb_bssgph(msg); + int data_len = msgb_bssgp_len(msg) - sizeof(*bgph); + struct tlv_parsed tp; + int rc; + + DEBUGP(DGPRS, "BSSGP SUSPEND\n"); + + rc = bssgp_tlv_parse(&tp, bgph->data, data_len); + if (rc < 0) + return rc; + + if (!TLVP_PRESENT(&tp, BSSGP_IE_TLLI) || + !TLVP_PRESENT(&tp, BSSGP_IE_ROUTEING_AREA)) + return -EIO; + + /* FIXME: pass the SUSPEND request to GMM */ + /* SEND SUSPEND_ACK or SUSPEND_NACK */ +} + +static int bssgp_rx_resume(struct msgb *msg) +{ + struct bssgp_normal_hdr *bgph = + (struct bssgp_normal_hdr *) msgb_bssgph(msg); + int data_len = msgb_bssgp_len(msg) - sizeof(*bgph); + struct tlv_parsed tp; + int rc; + + DEBUGP(DGPRS, "BSSGP RESUME\n"); + + rc = bssgp_tlv_parse(&tp, bgph->data, data_len); + if (rc < 0) + return rc; + + if (!TLVP_PRESENT(&tp, BSSGP_IE_TLLI) || + !TLVP_PRESENT(&tp, BSSGP_IE_ROUTEING_AREA) || + !TLVP_PRESENT(&tp, BSSGP_IE_SUSPEND_REF_NR)) + return -EIO; + + /* FIXME: pass the RESUME request to GMM */ + /* SEND RESUME_ACK or RESUME_NACK */ +} + +static int bssgp_rx_fc_bvc(struct msgb *msg, struct tlv_parsed *tp) +{ + + DEBUGP(DGPRS, "BSSGP FC BVC\n"); + + if (!TLVP_PRESENT(tp, BSSGP_IE_TAG) || + !TLVP_PRESENT(tp, BSSGP_IE_BVC_BUCKET_SIZE) || + !TLVP_PRESENT(tp, BSSGP_IE_BUCKET_LEAK_RATE) || + !TLVP_PRESENT(tp, BSSGP_IE_BMAX_DEFAULT_MS) || + !TLVP_PRESENT(tp, BSSGP_IE_R_DEFAULT_MS)) + return bssgp_tx_status(BSSGP_CAUSE_MISSING_MAND_IE, NULL, msg); + + /* FIXME: actually implement flow control */ + + /* Send FLOW_CONTROL_BVC_ACK */ + return bssgp_tx_fc_bvc_ack(msgb_nsei(msg), *TLVP_VAL(tp, BSSGP_IE_TAG), + msgb_bvci(msg)); +} + +/* We expect msgb_bssgph() to point to the BSSGP header */ +int gprs_bssgp_rcvmsg(struct msgb *msg) +{ + struct bssgp_normal_hdr *bgph = + (struct bssgp_normal_hdr *) msgb_bssgph(msg); + struct tlv_parsed tp; + uint8_t pdu_type = bgph->pdu_type; + int data_len = msgb_bssgp_len(msg) - sizeof(*bgph); + uint16_t bvci; /* PTP BVCI */ + uint16_t ns_bvci = msgb_bvci(msg); + int rc = 0; + + /* Identifiers from DOWN: NSEI, BVCI (both in msg->cb) */ + + /* UNITDATA BSSGP headers have TLLI in front */ + if (pdu_type != BSSGP_PDUT_UL_UNITDATA && + pdu_type != BSSGP_PDUT_DL_UNITDATA) + rc = bssgp_tlv_parse(&tp, bgph->data, data_len); + + switch (pdu_type) { + case BSSGP_PDUT_UL_UNITDATA: + /* some LLC data from the MS */ + rc = bssgp_rx_ul_ud(msg); + break; + case BSSGP_PDUT_RA_CAPABILITY: + /* BSS requests RA capability or IMSI */ + DEBUGP(DGPRS, "BSSGP RA CAPABILITY UPDATE\n"); + /* FIXME: send RA_CAPA_UPDATE_ACK */ + break; + case BSSGP_PDUT_RADIO_STATUS: + DEBUGP(DGPRS, "BSSGP RADIO STATUS\n"); + /* BSS informs us of some exception */ + /* FIXME: notify GMM */ + break; + case BSSGP_PDUT_SUSPEND: + /* MS wants to suspend */ + rc = bssgp_rx_suspend(msg); + break; + case BSSGP_PDUT_RESUME: + /* MS wants to resume */ + rc = bssgp_rx_resume(msg); + break; + case BSSGP_PDUT_FLUSH_LL: + /* BSS informs MS has moved to one cell to other cell */ + DEBUGP(DGPRS, "BSSGP FLUSH LL\n"); + /* FIXME: notify GMM */ + /* Send FLUSH_LL_ACK */ + break; + case BSSGP_PDUT_LLC_DISCARD: + /* BSS informs that some LLC PDU's have been discarded */ + DEBUGP(DGPRS, "BSSGP LLC DISCARDED\n"); + /* FIXME: notify GMM */ + break; + case BSSGP_PDUT_FLOW_CONTROL_BVC: + /* BSS informs us of available bandwidth in Gb interface */ + rc = bssgp_rx_fc_bvc(msg, &tp); + break; + case BSSGP_PDUT_FLOW_CONTROL_MS: + /* BSS informs us of available bandwidth to one MS */ + DEBUGP(DGPRS, "BSSGP FC MS\n"); + /* FIXME: actually implement flow control */ + /* FIXME: Send FLOW_CONTROL_MS_ACK */ + break; + case BSSGP_PDUT_BVC_BLOCK: + /* BSS tells us that BVC shall be blocked */ + DEBUGP(DGPRS, "BSSGP BVC BLOCK "); + if (!TLVP_PRESENT(&tp, BSSGP_IE_BVCI) || + !TLVP_PRESENT(&tp, BSSGP_IE_CAUSE)) + goto err_mand_ie; + bvci = ntohs(*(uint16_t *)TLVP_VAL(&tp, BSSGP_IE_BVCI)); + DEBUGPC(DGPRS, "BVCI=%u, cause=%s\n", bvci, + bssgp_cause_str(*TLVP_VAL(&tp, BSSGP_IE_CAUSE))); + /* We always acknowledge the BLOCKing */ + rc = bssgp_tx_simple_bvci(BSSGP_PDUT_BVC_BLOCK_ACK, + msgb_nsei(msg), bvci, ns_bvci); + break; + case BSSGP_PDUT_BVC_UNBLOCK: + /* BSS tells us that BVC shall be unblocked */ + DEBUGP(DGPRS, "BSSGP BVC UNBLOCK "); + if (!TLVP_PRESENT(&tp, BSSGP_IE_BVCI)) + goto err_mand_ie; + bvci = ntohs(*(uint16_t *)TLVP_VAL(&tp, BSSGP_IE_BVCI)); + DEBUGPC(DGPRS, "BVCI=%u\n", bvci); + /* We always acknowledge the unBLOCKing */ + rc = bssgp_tx_simple_bvci(BSSGP_PDUT_BVC_UNBLOCK_ACK, + msgb_nsei(msg), bvci, ns_bvci); + break; + case BSSGP_PDUT_BVC_RESET: + /* BSS tells us that BVC init is required */ + DEBUGP(DGPRS, "BSSGP BVC RESET "); + if (!TLVP_PRESENT(&tp, BSSGP_IE_BVCI) || + !TLVP_PRESENT(&tp, BSSGP_IE_CAUSE)) + goto err_mand_ie; + rc = bssgp_rx_bvc_reset(msg, &tp, ns_bvci); + break; + case BSSGP_PDUT_STATUS: + /* Some exception has occurred */ + /* FIXME: notify GMM */ + case BSSGP_PDUT_DOWNLOAD_BSS_PFC: + case BSSGP_PDUT_CREATE_BSS_PFC_ACK: + case BSSGP_PDUT_CREATE_BSS_PFC_NACK: + case BSSGP_PDUT_MODIFY_BSS_PFC: + case BSSGP_PDUT_DELETE_BSS_PFC_ACK: + DEBUGP(DGPRS, "BSSGP PDU type 0x%02x not [yet] implemented\n", + pdu_type); + break; + /* those only exist in the SGSN -> BSS direction */ + case BSSGP_PDUT_DL_UNITDATA: + case BSSGP_PDUT_PAGING_PS: + case BSSGP_PDUT_PAGING_CS: + case BSSGP_PDUT_RA_CAPA_UPDATE_ACK: + case BSSGP_PDUT_SUSPEND_ACK: + case BSSGP_PDUT_SUSPEND_NACK: + case BSSGP_PDUT_RESUME_ACK: + case BSSGP_PDUT_RESUME_NACK: + case BSSGP_PDUT_FLUSH_LL_ACK: + case BSSGP_PDUT_FLOW_CONTROL_BVC_ACK: + case BSSGP_PDUT_FLOW_CONTROL_MS_ACK: + case BSSGP_PDUT_BVC_BLOCK_ACK: + case BSSGP_PDUT_BVC_UNBLOCK_ACK: + case BSSGP_PDUT_SGSN_INVOKE_TRACE: + DEBUGP(DGPRS, "BSSGP PDU type 0x%02x only exists in DL\n", + pdu_type); + rc = -EINVAL; + break; + default: + DEBUGP(DGPRS, "BSSGP PDU type 0x%02x unknown\n", pdu_type); + break; + } + + return rc; +err_mand_ie: + return bssgp_tx_status(BSSGP_CAUSE_MISSING_MAND_IE, NULL, msg); +} + +/* Entry function from upper level (LLC), asking us to transmit a BSSGP PDU + * to a remote MS (identified by TLLI) at a BTS identified by its BVCI and NSEI */ +int gprs_bssgp_tx_dl_ud(struct msgb *msg) +{ + struct bssgp_bts_ctx *bctx; + struct bssgp_ud_hdr *budh; + uint8_t llc_pdu_tlv_hdr_len = 2; + uint8_t *llc_pdu_tlv, *qos_profile; + uint16_t pdu_lifetime = 1000; /* centi-seconds */ + uint8_t qos_profile_default[3] = { 0x00, 0x00, 0x21 }; + uint16_t msg_len = msg->len; + uint16_t bvci = msgb_bvci(msg); + uint16_t nsei = msgb_nsei(msg); + + /* Identifiers from UP: TLLI, BVCI, NSEI (all in msgb->cb) */ + if (bvci < 2) { + LOGP(DGPRS, LOGL_ERROR, "Cannot send DL-UD to BVCI %u\n", + bvci); + return -EINVAL; + } + + bctx = btsctx_by_bvci_nsei(bvci, nsei); + if (!bctx) + bctx = btsctx_alloc(bvci, nsei); + + if (msg->len > TVLV_MAX_ONEBYTE) + llc_pdu_tlv_hdr_len += 1; + + /* prepend the tag and length of the LLC-PDU TLV */ + llc_pdu_tlv = msgb_push(msg, llc_pdu_tlv_hdr_len); + llc_pdu_tlv[0] = BSSGP_IE_LLC_PDU; + if (llc_pdu_tlv_hdr_len > 2) { + llc_pdu_tlv[1] = msg_len >> 8; + llc_pdu_tlv[2] = msg_len & 0xff; + } else { + llc_pdu_tlv[1] = msg_len & 0x3f; + llc_pdu_tlv[1] |= 0x80; + } + + /* FIXME: optional elements */ + + /* prepend the pdu lifetime */ + pdu_lifetime = htons(pdu_lifetime); + msgb_tvlv_push(msg, BSSGP_IE_PDU_LIFETIME, 2, (uint8_t *)&pdu_lifetime); + + /* prepend the QoS profile, TLLI and pdu type */ + budh = (struct bssgp_ud_hdr *) msgb_push(msg, sizeof(*budh)); + memcpy(budh->qos_profile, qos_profile_default, sizeof(qos_profile_default)); + budh->tlli = htonl(msgb_tlli(msg)); + budh->pdu_type = BSSGP_PDUT_DL_UNITDATA; + + /* Identifiers down: BVCI, NSEI (in msgb->cb) */ + + return gprs_ns_sendmsg(bssgp_nsi, msg); +} diff --git a/openbsc/src/gprs/gprs_llc.c b/openbsc/src/gprs/gprs_llc.c new file mode 100644 index 000000000..9c75a3d4e --- /dev/null +++ b/openbsc/src/gprs/gprs_llc.c @@ -0,0 +1,549 @@ +/* GPRS LLC protocol implementation as per 3GPP TS 04.64 */ + +/* (C) 2009-2010 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 + +#include +#include +#include +#include +#include + +/* Section 4.5.2 Logical Link States + Annex C.2 */ +enum gprs_llc_ll_state { + GPRS_LLS_UNASSIGNED = 1, /* No TLLI yet */ + GPRS_LLS_ASSIGNED_ADM = 2, /* TLLI assigned */ + GPRS_LLS_LOCAL_EST = 3, /* Local Establishment */ + GPRS_LLS_REMOTE_EST = 4, /* Remote Establishment */ + GPRS_LLS_ABM = 5, + GPRS_LLS_LOCAL_REL = 6, /* Local Release */ + GPRS_LLS_TIMER_REC = 7, /* Timer Recovery */ +}; + +/* Section 4.7.1: Logical Link Entity: One per DLCI (TLLI + SAPI) */ +struct gprs_llc_lle { + struct llist_head list; + struct timer_list t200; + struct timer_list t201; /* wait for acknowledgement */ + + enum gprs_llc_ll_state state; + + uint32_t tlli; + uint32_t sapi; + + uint8_t v_sent; + uint8_t v_ack; + uint8_t v_recv; + + unsigned int n200; + unsigned int retrans_ctr; + + /* over which BSSGP BTS ctx do we need to transmit */ + uint16_t bvci; + uint16_t nsei; +}; + +static LLIST_HEAD(gprs_llc_lles); +void *llc_tall_ctx; + +/* lookup LLC Entity based on DLCI (TLLI+SAPI tuple) */ +static struct gprs_llc_lle *lle_by_tlli_sapi(uint32_t tlli, uint32_t sapi) +{ + struct gprs_llc_lle *lle; + + llist_for_each_entry(lle, &gprs_llc_lles, list) { + if (lle->tlli == tlli && lle->sapi == sapi) + return lle; + } + return NULL; +} + +static struct gprs_llc_lle *lle_alloc(uint32_t tlli, uint32_t sapi) +{ + struct gprs_llc_lle *lle; + + lle = talloc_zero(llc_tall_ctx, struct gprs_llc_lle); + if (!lle) + return NULL; + + lle->tlli = tlli; + lle->sapi = sapi; + lle->state = GPRS_LLS_UNASSIGNED; + llist_add(&lle->list, &gprs_llc_lles); + + return lle; +} + +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, +}; + +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; + uint8_t *data; + uint16_t data_len; + enum gprs_llc_cmd cmd; +}; + +#define LLC_ALLOC_SIZE 16384 +#define UI_HDR_LEN 3 +#define N202 4 +#define CRC24_LENGTH 3 + +static int gprs_llc_fcs(uint8_t *data, unsigned int len) +{ + uint32_t fcs_calc; + + fcs_calc = crc24_calc(INIT_CRC24, data, len); + fcs_calc = ~fcs_calc; + fcs_calc &= 0xffffff; + + return fcs_calc; +} + +static void t200_expired(void *data) +{ + struct gprs_llc_lle *lle = data; + + /* 8.5.1.3: Expiry of T200 */ + + if (lle->retrans_ctr >= lle->n200) { + /* FIXME: LLGM-STATUS-IND, LL-RELEASE-IND/CNF */ + lle->state = GPRS_LLS_ASSIGNED_ADM; + } + + switch (lle->state) { + case GPRS_LLS_LOCAL_EST: + /* retransmit SABM */ + /* re-start T200 */ + lle->retrans_ctr++; + break; + case GPRS_LLS_LOCAL_REL: + /* retransmit DISC */ + /* re-start T200 */ + lle->retrans_ctr++; + break; + } + +} + +static void t201_expired(void *data) +{ + struct gprs_llc_lle *lle = data; + + if (lle->retrans_ctr < lle->n200) { + /* transmit apropriate supervisory frame (8.6.4.1) */ + /* set timer T201 */ + lle->retrans_ctr++; + } +} + +int gprs_llc_tx_u(struct msgb *msg, uint8_t sapi, int command, + enum gprs_llc_u_cmd u_cmd, int pf_bit) +{ + uint8_t *fcs, *llch; + uint8_t addr, ctrl; + uint32_t fcs_calc; + + /* Identifiers from UP: (TLLI, SAPI) + (BVCI, NSEI) */ + + /* Address Field */ + addr = sapi & 0xf; + if (command) + addr |= 0x40; + + /* 6.3 Figure 8 */ + ctrl = 0xe0 | u_cmd; + if (pf_bit) + ctrl |= 0x10; + + /* prepend LLC UI header */ + llch = msgb_push(msg, 2); + llch[0] = addr; + llch[1] = ctrl; + + /* append FCS to end of frame */ + fcs = msgb_put(msg, 3); + fcs_calc = gprs_llc_fcs(llch, fcs - llch); + fcs[0] = fcs_calc & 0xff; + fcs[1] = (fcs_calc >> 8) & 0xff; + fcs[2] = (fcs_calc >> 16) & 0xff; + + /* Identifiers passed down: (BVCI, NSEI) */ + + return gprs_bssgp_tx_dl_ud(msg); +} + +/* Send XID response to LLE */ +static int gprs_llc_tx_xid(struct gprs_llc_lle *lle, struct msgb *msg) +{ + /* copy identifiers from LLE to ensure lower layers can route */ + msgb_tlli(msg) = lle->tlli; + msgb_bvci(msg) = lle->bvci; + msgb_nsei(msg) = lle->nsei; + + return gprs_llc_tx_u(msg, lle->sapi, 0, GPRS_LLC_U_XID, 1); +} + +/* Transmit a UI frame over the given SAPI */ +int gprs_llc_tx_ui(struct msgb *msg, uint8_t sapi, int command) +{ + struct gprs_llc_lle *lle; + uint8_t *fcs, *llch; + uint8_t addr, ctrl[2]; + uint32_t fcs_calc; + uint16_t nu = 0; + + /* Identifiers from UP: (TLLI, SAPI) + (BVCI, NSEI) */ + + /* look-up or create the LL Entity for this (TLLI, SAPI) tuple */ + lle = lle_by_tlli_sapi(msgb_tlli(msg), sapi); + if (!lle) + lle = lle_alloc(msgb_tlli(msg), sapi); + /* Update LLE's (BVCI, NSEI) tuple */ + lle->bvci = msgb_bvci(msg); + lle->nsei = msgb_nsei(msg); + + /* Address Field */ + addr = sapi & 0xf; + if (command) + addr |= 0x40; + + /* Control Field */ + ctrl[0] = 0xc0; + ctrl[0] |= nu >> 6; + ctrl[1] = (nu << 2) & 0xfc; + ctrl[1] |= 0x01; /* Protected Mode */ + + /* prepend LLC UI header */ + llch = msgb_push(msg, 3); + llch[0] = addr; + llch[1] = ctrl[0]; + llch[2] = ctrl[1]; + + /* append FCS to end of frame */ + fcs = msgb_put(msg, 3); + fcs_calc = gprs_llc_fcs(llch, fcs - llch); + fcs[0] = fcs_calc & 0xff; + fcs[1] = (fcs_calc >> 8) & 0xff; + fcs[2] = (fcs_calc >> 16) & 0xff; + + /* Identifiers passed down: (BVCI, NSEI) */ + + return gprs_bssgp_tx_dl_ud(msg); +} + +static int gprs_llc_hdr_dump(struct gprs_llc_hdr_parsed *gph) +{ + DEBUGP(DGPRS, "LLC SAPI=%u %c %c FCS=0x%06x(%s) ", + gph->sapi, gph->is_cmd ? 'C' : 'R', gph->ack_req ? 'A' : ' ', + gph->fcs, gph->fcs_calc == gph->fcs ? "correct" : "WRONG"); + + if (gph->cmd) + DEBUGPC(DGPRS, "CMD=%u ", gph->cmd); + + if (gph->data) + DEBUGPC(DGPRS, "DATA "); + + DEBUGPC(DGPRS, "\n"); +} +static int gprs_llc_hdr_rx(struct gprs_llc_hdr_parsed *gph, + struct gprs_llc_lle *lle) +{ + switch (gph->cmd) { + case GPRS_LLC_SABM: /* Section 6.4.1.1 */ + lle->v_sent = lle->v_ack = lle->v_recv = 0; + if (lle->state == GPRS_LLS_ASSIGNED_ADM) { + /* start re-establishment (8.7.1) */ + } + lle->state = GPRS_LLS_REMOTE_EST; + /* FIXME: Send UA */ + lle->state = GPRS_LLS_ABM; + /* FIXME: process data */ + break; + case GPRS_LLC_DISC: /* Section 6.4.1.2 */ + /* FIXME: Send UA */ + /* terminate ABM */ + lle->state = GPRS_LLS_ASSIGNED_ADM; + break; + case GPRS_LLC_UA: /* Section 6.4.1.3 */ + if (lle->state == GPRS_LLS_LOCAL_EST) + lle->state = GPRS_LLS_ABM; + break; + case GPRS_LLC_DM: /* Section 6.4.1.4: ABM cannot be performed */ + if (lle->state == GPRS_LLS_LOCAL_EST) + lle->state = GPRS_LLS_ASSIGNED_ADM; + break; + case GPRS_LLC_FRMR: /* Section 6.4.1.5 */ + break; + case GPRS_LLC_XID: /* Section 6.4.1.6 */ + /* FIXME: implement XID negotiation using SNDCP */ + { + struct msgb *resp; + uint8_t *xid; + resp = msgb_alloc_headroom(4096, 1024, "LLC_XID"); + xid = msgb_put(resp, gph->data_len); + memcpy(xid, gph->data, gph->data_len); + gprs_llc_tx_xid(lle, resp); + } + break; + } + + return 0; +} + +/* parse a GPRS LLC header, also check for invalid frames */ +static int gprs_llc_hdr_parse(struct gprs_llc_hdr_parsed *ghp, + const uint8_t *llc_hdr, int len) +{ + uint8_t *ctrl = llc_hdr+1; + int is_sack = 0; + unsigned int crc_length; + uint32_t fcs_calc; + + if (len <= CRC24_LENGTH) + return -EIO; + + 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->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 (crc_length > UI_HDR_LEN + N202) + 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; + } + } + + /* calculate what FCS we expect */ + ghp->fcs_calc = gprs_llc_fcs(llc_hdr, crc_length); + + /* FIXME: parse sack frame */ +} + +/* receive an incoming LLC PDU (BSSGP-UL-UNITDATA-IND, 7.2.4.2) */ +int gprs_llc_rcvmsg(struct msgb *msg, struct tlv_parsed *tv) +{ + struct bssgp_ud_hdr *udh = (struct bssgp_ud_hdr *) msgb_bssgph(msg); + struct gprs_llc_hdr *lh = msgb_llch(msg); + struct gprs_llc_hdr_parsed llhp; + struct gprs_llc_lle *lle; + int rc = 0; + + /* Identifiers from DOWN: NSEI, BVCI, TLLI */ + + rc = gprs_llc_hdr_parse(&llhp, lh, TLVP_LEN(tv, BSSGP_IE_LLC_PDU)); + /* FIXME */ + + gprs_llc_hdr_dump(&llhp); + + /* find the LLC Entity for this TLLI+SAPI tuple */ + lle = lle_by_tlli_sapi(msgb_tlli(msg), llhp.sapi); + /* allocate a new LLE if needed */ + if (!lle) + lle = lle_alloc(msgb_tlli(msg), llhp.sapi); + + /* Update LLE's (BVCI, NSEI) tuple */ + lle->bvci = msgb_bvci(msg); + lle->nsei = msgb_nsei(msg); + + rc = gprs_llc_hdr_rx(&llhp, lle); + /* FIXME */ + + if (llhp.data) { + msgb_gmmh(msg) = llhp.data; + switch (llhp.sapi) { + case GPRS_SAPI_GMM: + rc = gsm0408_gprs_rcvmsg(msg); + break; + case GPRS_SAPI_TOM2: + case GPRS_SAPI_TOM8: + /* FIXME */ + case GPRS_SAPI_SNDCP3: + case GPRS_SAPI_SNDCP5: + case GPRS_SAPI_SNDCP9: + case GPRS_SAPI_SNDCP11: + /* FIXME */ + case GPRS_SAPI_SMS: + /* FIXME */ + default: + LOGP(DGPRS, LOGL_NOTICE, "Unsupported SAPI %u\n", llhp.sapi); + rc = -EINVAL; + break; + } + } + + return rc; +} diff --git a/openbsc/src/gprs/gprs_ns.c b/openbsc/src/gprs/gprs_ns.c new file mode 100644 index 000000000..3d9bb8963 --- /dev/null +++ b/openbsc/src/gprs/gprs_ns.c @@ -0,0 +1,644 @@ +/* GPRS Networks Service (NS) messages on the Gb interfacebvci = msgb_bvci(msg); + * 3GPP TS 08.16 version 8.0.1 Release 1999 / ETSI TS 101 299 V8.0.1 (2002-05) */ + +/* (C) 2009-2010 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. + * + */ + +/* Some introduction into NS: NS is used typically on top of frame relay, + * but in the ip.access world it is encapsulated in UDP packets. It serves + * as an intermediate shim betwen BSSGP and the underlying medium. It doesn't + * do much, apart from providing congestion notification and status indication. + * + * Terms: + * NS Network Service + * NSVC NS Virtual Connection + * NSEI NS Entity Identifier + * NSVL NS Virtual Link + * NSVLI NS Virtual Link Identifier + * BVC BSSGP Virtual Connection + * BVCI BSSGP Virtual Connection Identifier + * NSVCG NS Virtual Connection Goup + * Blocked NS-VC cannot be used for user traffic + * Alive Ability of a NS-VC to provide communication + * + * There can be multiple BSSGP virtual connections over one (group of) NSVC's. BSSGP will + * therefore identify the BSSGP virtual connection by a BVCI passed down to NS. + * NS then has to firgure out which NSVC's are responsible for this BVCI. + * Those mappings are administratively configured. + */ + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#define NS_ALLOC_SIZE 1024 + +static const struct tlv_definition ns_att_tlvdef = { + .def = { + [NS_IE_CAUSE] = { TLV_TYPE_TvLV, 0 }, + [NS_IE_VCI] = { TLV_TYPE_TvLV, 0 }, + [NS_IE_PDU] = { TLV_TYPE_TvLV, 0 }, + [NS_IE_BVCI] = { TLV_TYPE_TvLV, 0 }, + [NS_IE_NSEI] = { TLV_TYPE_TvLV, 0 }, + }, +}; + +/* Lookup struct gprs_nsvc based on NSVCI */ +static struct gprs_nsvc *nsvc_by_nsvci(struct gprs_ns_inst *nsi, + uint16_t nsvci) +{ + struct gprs_nsvc *nsvc; + llist_for_each_entry(nsvc, &nsi->gprs_nsvcs, list) { + if (nsvc->nsvci == nsvci) + return nsvc; + } + return NULL; +} + +/* Lookup struct gprs_nsvc based on NSVCI */ +static struct gprs_nsvc *nsvc_by_nsei(struct gprs_ns_inst *nsi, + uint16_t nsei) +{ + struct gprs_nsvc *nsvc; + llist_for_each_entry(nsvc, &nsi->gprs_nsvcs, list) { + if (nsvc->nsei == nsei) + return nsvc; + } + return NULL; +} + + +/* Lookup struct gprs_nsvc based on remote peer socket addr */ +static struct gprs_nsvc *nsvc_by_rem_addr(struct gprs_ns_inst *nsi, + struct sockaddr_in *sin) +{ + struct gprs_nsvc *nsvc; + llist_for_each_entry(nsvc, &nsi->gprs_nsvcs, list) { + if (!memcmp(&nsvc->ip.bts_addr, sin, sizeof(*sin))) + return nsvc; + } + return NULL; +} + +static void gprs_ns_timer_cb(void *data); + +static struct gprs_nsvc *nsvc_create(struct gprs_ns_inst *nsi, uint16_t nsvci) +{ + struct gprs_nsvc *nsvc; + + nsvc = talloc_zero(nsi, struct gprs_nsvc); + nsvc->nsvci = nsvci; + /* before RESET procedure: BLOCKED and DEAD */ + nsvc->state = NSE_S_BLOCKED; + nsvc->nsi = nsi; + nsvc->timer.cb = gprs_ns_timer_cb; + nsvc->timer.data = nsvc; + + llist_add(&nsvc->list, &nsi->gprs_nsvcs); + + return nsvc; +} + +/* Section 10.3.2, Table 13 */ +static const struct value_string ns_cause_str[] = { + { NS_CAUSE_TRANSIT_FAIL, "Transit network failure" }, + { NS_CAUSE_OM_INTERVENTION, "O&M intervention" }, + { NS_CAUSE_EQUIP_FAIL, "Equipment failure" }, + { NS_CAUSE_NSVC_BLOCKED, "NS-VC blocked" }, + { NS_CAUSE_NSVC_UNKNOWN, "NS-VC unknown" }, + { NS_CAUSE_BVCI_UNKNOWN, "BVCI unknown" }, + { NS_CAUSE_SEM_INCORR_PDU, "Semantically incorrect PDU" }, + { NS_CAUSE_PDU_INCOMP_PSTATE, "PDU not compatible with protocol state" }, + { NS_CAUSE_PROTO_ERR_UNSPEC, "Protocol error, unspecified" }, + { NS_CAUSE_INVAL_ESSENT_IE, "Invalid essential IE" }, + { NS_CAUSE_MISSING_ESSENT_IE, "Missing essential IE" }, + { 0, NULL } +}; + +const char *gprs_ns_cause_str(enum ns_cause cause) +{ + return get_value_string(ns_cause_str, cause); +} + +static int nsip_sendmsg(struct gprs_nsvc *nsvc, struct msgb *msg); + +static int gprs_ns_tx(struct gprs_nsvc *nsvc, struct msgb *msg) +{ + int ret; + + switch (nsvc->nsi->ll) { + case GPRS_NS_LL_UDP: + ret = nsip_sendmsg(nsvc, msg); + break; + default: + LOGP(DGPRS, LOGL_ERROR, "unsupported NS linklayer %u\n", nsvc->nsi->ll); + msgb_free(msg); + ret = -EIO; + break; + } + return ret; +} + +static int gprs_ns_tx_simple(struct gprs_nsvc *nsvc, uint8_t pdu_type) +{ + struct msgb *msg = msgb_alloc(NS_ALLOC_SIZE, "GPRS/NS"); + struct gprs_ns_hdr *nsh; + + if (!msg) + return -ENOMEM; + + nsh = (struct gprs_ns_hdr *) msgb_put(msg, sizeof(*nsh)); + + nsh->pdu_type = pdu_type; + + return gprs_ns_tx(nsvc, msg); +} + +static int gprs_ns_tx_reset(struct gprs_nsvc *nsvc, uint8_t cause) +{ + struct msgb *msg = msgb_alloc(NS_ALLOC_SIZE, "GPRS/NS"); + struct gprs_ns_hdr *nsh; + uint16_t nsvci = htons(nsvc->nsvci); + uint16_t nsei = htons(nsvc->nsei); + + if (!msg) + return -ENOMEM; + + nsh = (struct gprs_ns_hdr *) msgb_put(msg, sizeof(*nsh)); + nsh->pdu_type = NS_PDUT_RESET; + + msgb_tvlv_put(msg, NS_IE_CAUSE, 1, &cause); + msgb_tvlv_put(msg, NS_IE_VCI, 2, (uint8_t *) &nsvci); + msgb_tvlv_put(msg, NS_IE_NSEI, 2, (uint8_t *) &nsei); + + return gprs_ns_tx(nsvc, msg); + +} + +#define NS_ALIVE_RETRIES 10 /* after 3 failed retransmit we declare BTS as dead */ + +static const uint8_t timer_mode_tout[_NSVC_TIMER_NR] = { + [NSVC_TIMER_TNS_RESET] = 60, + [NSVC_TIMER_TNS_ALIVE] = 3, + [NSVC_TIMER_TNS_TEST] = 30, +}; + +static void nsvc_start_timer(struct gprs_nsvc *nsvc, enum nsvc_timer_mode mode) +{ + nsvc->alive_retries = 0; + + if (bsc_timer_pending(&nsvc->timer)) + bsc_del_timer(&nsvc->timer); + + nsvc->timer_mode = mode; + bsc_schedule_timer(&nsvc->timer, timer_mode_tout[mode], 0); +} + +static void gprs_ns_timer_cb(void *data) +{ + struct gprs_nsvc *nsvc = data; + + switch (nsvc->timer_mode) { + case NSVC_TIMER_TNS_ALIVE: + /* Tns-alive case: we expired without response ! */ + nsvc->alive_retries++; + if (nsvc->alive_retries > NS_ALIVE_RETRIES) { + /* mark as dead and blocked */ + nsvc->state = NSE_S_BLOCKED; + DEBUGP(DGPRS, "NSEI=%u Tns-alive expired more then " + "%u times, blocking NS-VC\n", nsvc->nsei, + NS_ALIVE_RETRIES); + /* FIXME: inform higher layers */ + return; + } + nsvc_start_timer(nsvc, NSVC_TIMER_TNS_ALIVE); + break; + case NSVC_TIMER_TNS_TEST: + /* Tns-test case: send NS-ALIVE PDU */ + gprs_ns_tx_simple(nsvc, NS_PDUT_ALIVE); + /* start Tns-alive timer */ + nsvc_start_timer(nsvc, NSVC_TIMER_TNS_ALIVE); + break; + case NSVC_TIMER_TNS_RESET: + /* Chapter 7.3: Re-send the RESET */ + gprs_ns_tx_reset(nsvc, NS_CAUSE_OM_INTERVENTION); + nsvc_start_timer(nsvc, NSVC_TIMER_TNS_RESET); + break; + } +} + +/* Section 9.2.6 */ +static int gprs_ns_tx_reset_ack(struct gprs_nsvc *nsvc) +{ + struct msgb *msg = msgb_alloc(NS_ALLOC_SIZE, "GPRS/NS"); + struct gprs_ns_hdr *nsh; + uint16_t nsvci, nsei; + + if (!msg) + return -ENOMEM; + + nsvci = htons(nsvc->nsvci); + nsei = htons(nsvc->nsei); + + nsh = (struct gprs_ns_hdr *) msgb_put(msg, sizeof(*nsh)); + + nsh->pdu_type = NS_PDUT_RESET_ACK; + + DEBUGP(DGPRS, "NSEI=%u Tx NS RESET ACK (NSVCI=%u)\n", + nsvc->nsei, nsvc->nsvci); + + msgb_tvlv_put(msg, NS_IE_VCI, 2, (uint8_t *)&nsvci); + msgb_tvlv_put(msg, NS_IE_NSEI, 2, (uint8_t *)&nsei); + + return gprs_ns_tx(nsvc, msg); +} + +/* Section 9.2.10: transmit side / NS-UNITDATA-REQUEST primitive */ +int gprs_ns_sendmsg(struct gprs_ns_inst *nsi, struct msgb *msg) +{ + struct gprs_nsvc *nsvc; + struct gprs_ns_hdr *nsh; + uint16_t bvci = msgb_bvci(msg); + + nsvc = nsvc_by_nsei(nsi, msgb_nsei(msg)); + if (!nsvc) { + LOGP(DGPRS, LOGL_ERROR, "Unable to resolve NSEI %u " + "to NS-VC!\n", msgb_nsei(msg)); + return -EINVAL; + } + + if (!(nsvc->state & NSE_S_ALIVE)) { + LOGP(DGPRS, LOGL_ERROR, "NSEI=%u is not alive, cannot send\n", + nsvc->nsei); + return -EBUSY; + } + if (nsvc->state & NSE_S_BLOCKED) { + LOGP(DGPRS, LOGL_ERROR, "NSEI=%u is blocked, cannot send\n", + nsvc->nsei); + return -EBUSY; + } + + nsh = (struct gprs_ns_hdr *) msgb_push(msg, sizeof(*nsh) + 3); + if (!nsh) { + LOGP(DGPRS, LOGL_ERROR, "Not enough headroom for NS header\n"); + return -EIO; + } + + nsh->pdu_type = NS_PDUT_UNITDATA; + /* spare octet in data[0] */ + nsh->data[1] = bvci >> 8; + nsh->data[2] = bvci & 0xff; + + return gprs_ns_tx(nsvc, msg); +} + +/* Section 9.2.10: receive side */ +static int gprs_ns_rx_unitdata(struct gprs_nsvc *nsvc, struct msgb *msg) +{ + struct gprs_ns_hdr *nsh = (struct gprs_ns_hdr *)msg->l2h; + uint16_t bvci; + + /* spare octet in data[0] */ + bvci = nsh->data[1] << 8 | nsh->data[2]; + msgb_bssgph(msg) = &nsh->data[3]; + msgb_bvci(msg) = bvci; + + /* call upper layer (BSSGP) */ + return nsvc->nsi->cb(GPRS_NS_EVT_UNIT_DATA, nsvc, msg, bvci); +} + +/* Section 9.2.7 */ +static int gprs_ns_rx_status(struct gprs_nsvc *nsvc, struct msgb *msg) +{ + struct gprs_ns_hdr *nsh = (struct gprs_ns_hdr *) msg->l2h; + struct tlv_parsed tp; + uint8_t cause; + int rc; + + DEBUGP(DGPRS, "NSEI=%u NS STATUS ", nsvc->nsei); + + rc = tlv_parse(&tp, &ns_att_tlvdef, nsh->data, msgb_l2len(msg), 0, 0); + + if (!TLVP_PRESENT(&tp, NS_IE_CAUSE)) { + DEBUGPC(DGPRS, "missing cause IE\n"); + return -EINVAL; + } + + cause = *TLVP_VAL(&tp, NS_IE_CAUSE); + DEBUGPC(DGPRS, "cause=%s\n", gprs_ns_cause_str(cause)); + + return 0; +} + +/* Section 7.3 */ +static int gprs_ns_rx_reset(struct gprs_nsvc *nsvc, struct msgb *msg) +{ + struct gprs_ns_hdr *nsh = (struct gprs_ns_hdr *) msg->l2h; + struct tlv_parsed tp; + uint8_t *cause; + uint16_t *nsvci, *nsei; + int rc; + + rc = tlv_parse(&tp, &ns_att_tlvdef, nsh->data, msgb_l2len(msg), 0, 0); + + if (!TLVP_PRESENT(&tp, NS_IE_CAUSE) || + !TLVP_PRESENT(&tp, NS_IE_VCI) || + !TLVP_PRESENT(&tp, NS_IE_NSEI)) { + /* FIXME: respond with NS_CAUSE_MISSING_ESSENT_IE */ + LOGP(DGPRS, LOGL_ERROR, "NS RESET Missing mandatory IE\n"); + return -EINVAL; + } + + cause = (uint8_t *) TLVP_VAL(&tp, NS_IE_CAUSE); + nsvci = (uint16_t *) TLVP_VAL(&tp, NS_IE_VCI); + nsei = (uint16_t *) TLVP_VAL(&tp, NS_IE_NSEI); + + DEBUGP(DGPRS, "NSEI=%u NS RESET (NSVCI=%u, cause=%s)\n", + nsvc->nsvci, nsvc->nsei, gprs_ns_cause_str(*cause)); + + nsvc->state = NSE_S_BLOCKED | NSE_S_ALIVE; + nsvc->nsei = ntohs(*nsei); + nsvc->nsvci = ntohs(*nsvci); + + /* mark the NS-VC as blocked and alive */ + /* start the test procedure */ + nsvc_start_timer(nsvc, NSVC_TIMER_TNS_ALIVE); + + return gprs_ns_tx_reset_ack(nsvc); +} + +/* main entry point, here incoming NS frames enter */ +int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, + struct sockaddr_in *saddr) +{ + struct gprs_ns_hdr *nsh = (struct gprs_ns_hdr *) msg->l2h; + struct gprs_nsvc *nsvc; + int rc = 0; + + /* look up the NSVC based on source address */ + nsvc = nsvc_by_rem_addr(nsi, saddr); + if (!nsvc) { + /* Only the RESET procedure creates a new NSVC */ + if (nsh->pdu_type != NS_PDUT_RESET) { + LOGP(DGPRS, LOGL_INFO, "Ignoring NS PDU type 0x%0x " + "from %s for non-existing NS-VC\n", + nsh->pdu_type, inet_ntoa(saddr->sin_addr)); + //gprs_ns_tx_reset(nsvc, NS_CAUSE_NSVC_UNKNOWN); + return -EIO; + } + LOGP(DGPRS, LOGL_INFO, "Creating NS-VC for BSS at %s:%u\n", + inet_ntoa(saddr->sin_addr), ntohs(saddr->sin_port)); + nsvc = nsvc_create(nsi, 0xffff); + nsvc->ip.bts_addr = *saddr; + } else + msgb_nsei(msg) = nsvc->nsei; + + switch (nsh->pdu_type) { + case NS_PDUT_ALIVE: + /* remote end inquires whether we're still alive, + * we need to respond with ALIVE_ACK */ + rc = gprs_ns_tx_simple(nsvc, NS_PDUT_ALIVE_ACK); + break; + case NS_PDUT_ALIVE_ACK: + /* stop Tns-alive */ + bsc_del_timer(&nsvc->timer); + /* start Tns-test */ + nsvc_start_timer(nsvc, NSVC_TIMER_TNS_TEST); + if (nsvc->remote_end_is_sgsn) { + /* FIXME: this should be one level higher */ + if (nsvc->state & NSE_S_BLOCKED) + rc = gprs_ns_tx_simple(nsvc, NS_PDUT_UNBLOCK); + } + break; + case NS_PDUT_UNITDATA: + /* actual user data */ + rc = gprs_ns_rx_unitdata(nsvc, msg); + break; + case NS_PDUT_STATUS: + rc = gprs_ns_rx_status(nsvc, msg); + break; + case NS_PDUT_RESET: + rc = gprs_ns_rx_reset(nsvc, msg); + break; + case NS_PDUT_RESET_ACK: + DEBUGP(DGPRS, "NSEI=%u Rx NS RESET ACK\n", nsvc->nsei); + /* mark remote NS-VC as blocked + active */ + nsvc->remote_state = NSE_S_BLOCKED | NSE_S_ALIVE; + if (nsvc->remote_end_is_sgsn) { + /* stop RESET timer */ + bsc_del_timer(&nsvc->timer); + /* send ALIVE PDU */ + rc = gprs_ns_tx_simple(nsvc, NS_PDUT_ALIVE); + nsvc_start_timer(nsvc, NSVC_TIMER_TNS_ALIVE); + /* mark local state as BLOCKED + ALIVE */ + nsvc->state = NSE_S_BLOCKED | NSE_S_ALIVE; + } + break; + case NS_PDUT_UNBLOCK: + /* Section 7.2: unblocking procedure */ + DEBUGP(DGPRS, "NSEI=%u Rx NS UNBLOCK\n", nsvc->nsei); + nsvc->state &= ~NSE_S_BLOCKED; + rc = gprs_ns_tx_simple(nsvc, NS_PDUT_UNBLOCK_ACK); + break; + case NS_PDUT_UNBLOCK_ACK: + DEBUGP(DGPRS, "NSEI=%u Rx NS UNBLOCK ACK\n", nsvc->nsei); + /* mark remote NS-VC as unblocked + active */ + nsvc->remote_state = NSE_S_ALIVE; + if (nsvc->remote_end_is_sgsn) + nsvc->state = NSE_S_ALIVE; + break; + case NS_PDUT_BLOCK: + DEBUGP(DGPRS, "NSEI=%u Rx NS BLOCK\n", nsvc->nsei); + nsvc->state |= NSE_S_BLOCKED; + rc = gprs_ns_tx_simple(nsvc, NS_PDUT_UNBLOCK_ACK); + break; + case NS_PDUT_BLOCK_ACK: + DEBUGP(DGPRS, "NSEI=%u Rx NS BLOCK ACK\n", nsvc->nsei); + /* mark remote NS-VC as blocked + active */ + nsvc->remote_state = NSE_S_BLOCKED | NSE_S_ALIVE; + break; + default: + DEBUGP(DGPRS, "NSEI=%u Rx Unknown NS PDU type 0x%02x\n", + nsvc->nsei, nsh->pdu_type); + rc = -EINVAL; + break; + } + return rc; +} + +struct gprs_ns_inst *gprs_ns_instantiate(gprs_ns_cb_t *cb) +{ + struct gprs_ns_inst *nsi = talloc_zero(tall_bsc_ctx, struct gprs_ns_inst); + + nsi->cb = cb; + INIT_LLIST_HEAD(&nsi->gprs_nsvcs); + + return nsi; +} + +void gprs_ns_destroy(struct gprs_ns_inst *nsi) +{ + /* FIXME: clear all timers */ + + /* recursively free the NSI and all its NSVCs */ + talloc_free(nsi); +} + + +/* NS-over-IP code, according to 3GPP TS 48.016 Chapter 6.2 + * We don't support Size Procedure, Configuration Procedure, ChangeWeight Procedure */ + +/* Read a single NS-over-IP message */ +static struct msgb *read_nsip_msg(struct bsc_fd *bfd, int *error, + struct sockaddr_in *saddr) +{ + struct msgb *msg = msgb_alloc(NS_ALLOC_SIZE, "Abis/IP/GPRS-NS"); + int ret = 0; + socklen_t saddr_len = sizeof(*saddr); + + if (!msg) { + *error = -ENOMEM; + return NULL; + } + + ret = recvfrom(bfd->fd, msg->data, NS_ALLOC_SIZE, 0, + (struct sockaddr *)saddr, &saddr_len); + if (ret < 0) { + LOGP(DGPRS, LOGL_ERROR, "recv error %s during NSIP recv\n", + strerror(errno)); + msgb_free(msg); + *error = ret; + return NULL; + } else if (ret == 0) { + msgb_free(msg); + *error = ret; + return NULL; + } + + msg->l2h = msg->data; + msgb_put(msg, ret); + + return msg; +} + +static int handle_nsip_read(struct bsc_fd *bfd) +{ + int error; + struct sockaddr_in saddr; + struct gprs_ns_inst *nsi = bfd->data; + struct msgb *msg = read_nsip_msg(bfd, &error, &saddr); + + if (!msg) + return error; + + return gprs_ns_rcvmsg(nsi, msg, &saddr); +} + +static int handle_nsip_write(struct bsc_fd *bfd) +{ + /* FIXME: actually send the data here instead of nsip_sendmsg() */ + return -EIO; +} + +int nsip_sendmsg(struct gprs_nsvc *nsvc, struct msgb *msg) +{ + int rc; + struct gprs_ns_inst *nsi = nsvc->nsi; + struct sockaddr_in *daddr = &nsvc->ip.bts_addr; + + rc = sendto(nsi->nsip.fd.fd, msg->data, msg->len, 0, + (struct sockaddr *)daddr, sizeof(*daddr)); + + talloc_free(msg); + + return rc; +} + +/* UDP Port 23000 carries the LLC-in-BSSGP-in-NS protocol stack */ +static int nsip_fd_cb(struct bsc_fd *bfd, unsigned int what) +{ + int rc = 0; + + if (what & BSC_FD_READ) + rc = handle_nsip_read(bfd); + if (what & BSC_FD_WRITE) + rc = handle_nsip_write(bfd); + + return rc; +} + + +/* FIXME: this is currently in input/ipaccess.c */ +extern int make_sock(struct bsc_fd *bfd, int proto, uint16_t port, + int (*cb)(struct bsc_fd *fd, unsigned int what)); + +/* Listen for incoming GPRS packets */ +int nsip_listen(struct gprs_ns_inst *nsi, uint16_t udp_port) +{ + int ret; + + ret = make_sock(&nsi->nsip.fd, IPPROTO_UDP, udp_port, nsip_fd_cb); + if (ret < 0) + return ret; + + nsi->ll = GPRS_NS_LL_UDP; + nsi->nsip.fd.data = nsi; + + return ret; +} + +/* Establish a connection (from the BSS) to the SGSN */ +struct gprs_nsvc *nsip_connect(struct gprs_ns_inst *nsi, + struct sockaddr_in *dest, uint16_t nsei, + uint16_t nsvci) +{ + struct gprs_nsvc *nsvc; + + nsvc = nsvc_by_rem_addr(nsi, dest); + if (!nsvc) { + nsvc = nsvc_create(nsi, nsvci); + nsvc->ip.bts_addr = *dest; + } + nsvc->nsei = nsei; + nsvc->nsvci = nsvci; + nsvc->remote_end_is_sgsn = 1; + + /* Initiate a RESET procedure */ + if (gprs_ns_tx_reset(nsvc, NS_CAUSE_OM_INTERVENTION) < 0) { + LOGP(DGPRS, LOGL_ERROR, "NSEI=%u, error resetting NS-VC\n", + nsei); + } + /* run a timer and re-transmit the reset request? */ + nsvc_start_timer(nsvc, NSVC_TIMER_TNS_RESET); + + return nsvc; +} diff --git a/openbsc/src/gprs/gprs_sgsn.c b/openbsc/src/gprs/gprs_sgsn.c new file mode 100644 index 000000000..ba4671955 --- /dev/null +++ b/openbsc/src/gprs/gprs_sgsn.c @@ -0,0 +1,96 @@ +/* GPRS SGSN functionality */ + +/* (C) 2009 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 +#include +#include +#include + +static LLIST_HEAD(sgsn_mm_ctxts); + +static int ra_id_equals(const struct gprs_ra_id *id1, + const struct gprs_ra_id *id2) +{ + return (id1->mcc == id2->mcc && id1->mnc == id2->mnc && + id1->lac == id2->lac && id1->rac == id2->rac); +} + +/* look-up a SGSN MM context based on TLLI + RAI */ +struct sgsn_mm_ctx *sgsn_mm_ctx_by_tlli(uint32_t tlli, + const struct gprs_ra_id *raid) +{ + struct sgsn_mm_ctx *ctx; + + llist_for_each_entry(ctx, &sgsn_mm_ctxts, list) { + if (tlli == ctx->tlli && + ra_id_equals(raid, &ctx->ra)) + return ctx; + } + return NULL; +} + +struct sgsn_mm_ctx *sgsn_mm_ctx_by_ptmsi(uint32_t p_tmsi) +{ + struct sgsn_mm_ctx *ctx; + + llist_for_each_entry(ctx, &sgsn_mm_ctxts, list) { + if (p_tmsi == ctx->p_tmsi) + return ctx; + } + return NULL; +} + +struct sgsn_mm_ctx *sgsn_mm_ctx_by_imsi(const char *imsi) +{ + struct sgsn_mm_ctx *ctx; + + llist_for_each_entry(ctx, &sgsn_mm_ctxts, list) { + if (!strcmp(imsi, ctx->imsi)) + return ctx; + } + return NULL; + +} + +/* Allocate a new SGSN MM context */ +struct sgsn_mm_ctx *sgsn_mm_ctx_alloc(uint32_t tlli, + const struct gprs_ra_id *raid) +{ + struct sgsn_mm_ctx *ctx = talloc_zero(NULL, struct sgsn_mm_ctx); + + if (!ctx) + return NULL; + + memcpy(&ctx->ra, raid, sizeof(ctx->ra)); + ctx->tlli = tlli; + ctx->mm_state = GMM_DEREGISTERED; + + llist_add(&ctx->list, &sgsn_mm_ctxts); + + return ctx; +} diff --git a/openbsc/src/gprs/gprs_sndcp.c b/openbsc/src/gprs/gprs_sndcp.c new file mode 100644 index 000000000..0d1a39004 --- /dev/null +++ b/openbsc/src/gprs/gprs_sndcp.c @@ -0,0 +1,70 @@ +/* GPRS SNDCP protocol implementation as per 3GPP TS 04.65 */ + +/* (C) 2010 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 + +#include +#include +#include +#include + +/* Chapter 7.2: SN-PDU Formats */ +struct sndcp_common_hdr { + /* octet 1 */ + uint8_t nsapi:4; + uint8_t more:1; + uint8_t type:1; + uint8_t first:1; + uint8_t spare:1; + /* octet 2 */ + uint8_t pcomp; + uint8_t dcomp; +}; + +struct sndcp_udata_hdr { + /* octet 3 */ + uint8_t npdu_high:4; + uint8_t seg_nr:4; + /* octet 4 */ + uint8_t npdu_low; +}; + +/* Entry point for the LL-UNITDATA.indication */ +int sndcp_unitdata_ind(struct msgb *msg, uint8_t sapi, uint8_t *hdr, uint8_t len) +{ + struct sndcp_udata_hdr *suh; + uint16_t npdu; + + if (suh->type == 0) { + LOGP(DGPRS, LOGL_ERROR, "SN-DATA PDU at unitdata_ind() function\n"); + return -EINVAL; + } + + npdu = (suh->npdu_high << 8) | suh->npdu_low; +} + diff --git a/openbsc/src/gprs/gsm_04_08_gprs.c b/openbsc/src/gprs/gsm_04_08_gprs.c new file mode 100644 index 000000000..4a42113f0 --- /dev/null +++ b/openbsc/src/gprs/gsm_04_08_gprs.c @@ -0,0 +1,762 @@ +/* GSM Mobile Radio Interface Layer 3 messages on the A-bis interface + * 3GPP TS 04.08 version 7.21.0 Release 1998 / ETSI TS 100 940 V7.21.0 */ + +/* (C) 2009-2010 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 +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* 10.5.5.14 GPRS MM Cause / Table 10.5.147 */ +struct value_string gmm_cause_names[] = { + /* FIXME */ + { GMM_CAUSE_SEM_INCORR_MSG, "Semantically incorrect message" }, + { GMM_CAUSE_INV_MAND_INFO, "Invalid mandatory information" }, + { GMM_CAUSE_MSGT_NOTEXIST_NOTIMPL, + "Message type non-existant or not implemented" }, + { GMM_CAUSE_MSGT_INCOMP_P_STATE, + "Message type not compatible with protocol state" }, + { GMM_CAUSE_IE_NOTEXIST_NOTIMPL, + "Information element non-existent or not implemented" }, + { GMM_CAUSE_COND_IE_ERR, "Conditional IE error" }, + { GMM_CAUSE_MSG_INCOMP_P_STATE, + "Message not compatible with protocol state " }, + { GMM_CAUSE_PROTO_ERR_UNSPEC, "Protocol error, unspecified" }, + { 0, NULL } +}; + +/* 10.5.6.6 SM Cause / Table 10.5.157 */ +struct value_string gsm_cause_names[] = { + { GSM_CAUSE_INSUFF_RSRC, "Insufficient resources" }, + { GSM_CAUSE_MISSING_APN, "Missing or unknown APN" }, + { GSM_CAUSE_UNKNOWN_PDP, "Unknown PDP address or PDP type" }, + { GSM_CAUSE_AUTH_FAILED, "User Authentication failed" }, + { GSM_CAUSE_ACT_REJ_GGSN, "Activation rejected by GGSN" }, + { GSM_CAUSE_ACT_REJ_UNSPEC, "Activation rejected, unspecified" }, + { GSM_CAUSE_SERV_OPT_NOTSUPP, "Service option not supported" }, + { GSM_CAUSE_REQ_SERV_OPT_NOTSUB, + "Requested service option not subscribed" }, + { GSM_CAUSE_SERV_OPT_TEMP_OOO, + "Service option temporarily out of order" }, + { GSM_CAUSE_NSAPI_IN_USE, "NSAPI already used" }, + { GSM_CAUSE_DEACT_REGULAR, "Regular deactivation" }, + { GSM_CAUSE_QOS_NOT_ACCEPTED, "QoS not accepted" }, + { GSM_CAUSE_NET_FAIL, "Network Failure" }, + { GSM_CAUSE_REACT_RQD, "Reactivation required" }, + { GSM_CAUSE_FEATURE_NOTSUPP, "Feature not supported " }, + { GSM_CAUSE_INVALID_TRANS_ID, "Invalid transaction identifier" }, + { GSM_CAUSE_SEM_INCORR_MSG, "Semantically incorrect message" }, + { GSM_CAUSE_INV_MAND_INFO, "Invalid mandatory information" }, + { GSM_CAUSE_MSGT_NOTEXIST_NOTIMPL, + "Message type non-existant or not implemented" }, + { GSM_CAUSE_MSGT_INCOMP_P_STATE, + "Message type not compatible with protocol state" }, + { GSM_CAUSE_IE_NOTEXIST_NOTIMPL, + "Information element non-existent or not implemented" }, + { GSM_CAUSE_COND_IE_ERR, "Conditional IE error" }, + { GSM_CAUSE_MSG_INCOMP_P_STATE, + "Message not compatible with protocol state " }, + { GSM_CAUSE_PROTO_ERR_UNSPEC, "Protocol error, unspecified" }, + { 0, NULL } +}; + +static const char *att_name(uint8_t type) +{ + switch (type) { + case GPRS_ATT_T_ATTACH: + return "GPRS attach"; + case GPRS_ATT_T_ATT_WHILE_IMSI: + return "GPRS attach while IMSI attached"; + case GPRS_ATT_T_COMBINED: + return "Combined GPRS/IMSI attach"; + default: + return "unknown"; + } +} + +static const char *upd_name(uint8_t type) +{ + switch (type) { + case GPRS_UPD_T_RA: + return "RA updating"; + case GPRS_UPD_T_RA_LA: + return "combined RA/LA updating"; + case GPRS_UPD_T_RA_LA_IMSI_ATT: + return "combined RA/LA updating + IMSI attach"; + case GPRS_UPD_T_PERIODIC: + return "periodic updating"; + } + return "unknown"; +} + +/* Send a message through the underlying layer */ +static int gsm48_gmm_sendmsg(struct msgb *msg, int command) +{ + /* caller needs to provide TLLI, BVCI and NSEI */ + return gprs_llc_tx_ui(msg, GPRS_SAPI_GMM, command); +} + +/* copy identifiers from old message to new message, this + * is required so lower layers can route it correctly */ +static void gmm_copy_id(struct msgb *msg, const struct msgb *old) +{ + msgb_tlli(msg) = msgb_tlli(old); + msgb_bvci(msg) = msgb_bvci(old); + msgb_nsei(msg) = msgb_nsei(old); +} + +static struct gsm48_qos default_qos = { + .delay_class = 4, /* best effort */ + .reliab_class = GSM48_QOS_RC_LLC_UN_RLC_ACK_DATA_PROT, + .peak_tput = GSM48_QOS_PEAK_TPUT_32000bps, + .preced_class = GSM48_QOS_PC_NORMAL, + .mean_tput = GSM48_QOS_MEAN_TPUT_BEST_EFFORT, + .traf_class = GSM48_QOS_TC_INTERACTIVE, + .deliv_order = GSM48_QOS_DO_UNORDERED, + .deliv_err_sdu = GSM48_QOS_ERRSDU_YES, + .max_sdu_size = GSM48_QOS_MAXSDU_1520, + .max_bitrate_up = GSM48_QOS_MBRATE_63k, + .max_bitrate_down = GSM48_QOS_MBRATE_63k, + .resid_ber = GSM48_QOS_RBER_5e_2, + .sdu_err_ratio = GSM48_QOS_SERR_1e_2, + .handling_prio = 3, + .xfer_delay = 0x10, /* 200ms */ + .guar_bitrate_up = GSM48_QOS_MBRATE_0k, + .guar_bitrate_down = GSM48_QOS_MBRATE_0k, + .sig_ind = 0, /* not optimised for signalling */ + .max_bitrate_down_ext = 0, /* use octet 9 */ + .guar_bitrate_down_ext = 0, /* use octet 13 */ +}; + +/* Chapter 9.4.2: Attach accept */ +static int gsm48_tx_gmm_att_ack(struct msgb *old_msg) +{ + struct msgb *msg = gsm48_msgb_alloc(); + struct gsm48_hdr *gh; + struct gsm48_attach_ack *aa; + struct gprs_ra_id ra_id; + + DEBUGP(DMM, "<- GPRS ATTACH ACCEPT\n"); + + gmm_copy_id(msg, old_msg); + + gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh)); + gh->proto_discr = GSM48_PDISC_MM_GPRS; + gh->msg_type = GSM48_MT_GMM_ATTACH_ACK; + + aa = (struct gsm48_attach_ack *) msgb_put(msg, sizeof(*aa)); + aa->force_stby = 0; /* not indicated */ + aa->att_result = 1; /* GPRS only */ + aa->ra_upd_timer = GPRS_TMR_MINUTE | 10; + aa->radio_prio = 4; /* lowest */ + bssgp_parse_cell_id(&ra_id, msgb_bcid(old_msg)); + gsm48_construct_ra(aa->ra_id.digits, &ra_id); + + /* Option: P-TMSI signature, allocated P-TMSI, MS ID, ... */ + return gsm48_gmm_sendmsg(msg, 0); +} + +/* Chapter 9.4.5: Attach reject */ +static int gsm48_tx_gmm_att_rej(struct msgb *old_msg, uint8_t gmm_cause) +{ + struct msgb *msg = gsm48_msgb_alloc(); + struct gsm48_hdr *gh; + + DEBUGP(DMM, "<- GPRS ATTACH REJECT\n"); + + gmm_copy_id(msg, old_msg); + + gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1); + gh->proto_discr = GSM48_PDISC_MM_GPRS; + gh->msg_type = GSM48_MT_GMM_ATTACH_REJ; + gh->data[0] = gmm_cause; + + return gsm48_gmm_sendmsg(msg, 0); +} + +/* Transmit Chapter 9.4.12 Identity Request */ +static int gsm48_tx_gmm_id_req(struct msgb *old_msg, uint8_t id_type) +{ + struct msgb *msg = gsm48_msgb_alloc(); + struct gsm48_hdr *gh; + + DEBUGP(DMM, "-> GPRS IDENTITY REQUEST: mi_type=%02x\n", id_type); + + gmm_copy_id(msg, old_msg); + + gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1); + gh->proto_discr = GSM48_PDISC_MM_GPRS; + gh->msg_type = GSM48_MT_GMM_ID_REQ; + /* 10.5.5.9 ID type 2 + identity type and 10.5.5.7 'force to standby' IE */ + gh->data[0] = id_type & 0xf; + + return gsm48_gmm_sendmsg(msg, 0); +} + +/* Check if we can already authorize a subscriber */ +static int gsm48_gmm_authorize(struct sgsn_mm_ctx *ctx, struct msgb *msg) +{ + if (strlen(ctx->imei) && strlen(ctx->imsi)) { + ctx->mm_state = GMM_REGISTERED_NORMAL; + return gsm48_tx_gmm_att_ack(msg); + } + if (!strlen(ctx->imei)) + return gsm48_tx_gmm_id_req(msg, GSM_MI_TYPE_IMEI); + + if (!strlen(ctx->imsi)) + return gsm48_tx_gmm_id_req(msg, GSM_MI_TYPE_IMSI); + + return 0; +} + +/* Parse Chapter 9.4.13 Identity Response */ +static int gsm48_rx_gmm_id_resp(struct msgb *msg) +{ + struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg); + uint8_t mi_type = gh->data[1] & GSM_MI_TYPE_MASK; + char mi_string[GSM48_MI_SIZE]; + struct gprs_ra_id ra_id; + struct sgsn_mm_ctx *ctx; + + gsm48_mi_to_string(mi_string, sizeof(mi_string), &gh->data[1], gh->data[0]); + DEBUGP(DMM, "GMM IDENTITY RESPONSE: mi_type=0x%02x MI(%s) ", + mi_type, mi_string); + + bssgp_parse_cell_id(&ra_id, msgb_bcid(msg)); + ctx = sgsn_mm_ctx_by_tlli(msgb_tlli(msg), &ra_id); + if (!ctx) { + DEBUGP(DMM, "from unknown TLLI 0x%08x?!?\n", msgb_tlli(msg)); + return -EINVAL; + } + + switch (mi_type) { + case GSM_MI_TYPE_IMSI: + /* we already have a mm context with current TLLI, but no + * P-TMSI / IMSI yet. What we now need to do is to fill + * this initial context with data from the HLR */ + strncpy(ctx->imsi, mi_string, sizeof(ctx->imei)); + break; + case GSM_MI_TYPE_IMEI: + strncpy(ctx->imei, mi_string, sizeof(ctx->imei)); + break; + case GSM_MI_TYPE_IMEISV: + break; + } + + DEBUGPC(DMM, "\n"); + /* Check if we can let the mobile station enter */ + return gsm48_gmm_authorize(ctx, msg); +} + +static void attach_rej_cb(void *data) +{ + struct sgsn_mm_ctx *ctx = data; + + /* FIXME: determine through which BTS/TRX to send this */ + //gsm48_tx_gmm_att_rej(ctx->tlli, GMM_CAUSE_MS_ID_NOT_DERIVED); + ctx->mm_state = GMM_DEREGISTERED; + /* FIXME: release the context */ +} + +static void schedule_reject(struct sgsn_mm_ctx *ctx) +{ + ctx->T = 3370; + ctx->timer.cb = attach_rej_cb; + ctx->timer.data = ctx; + bsc_schedule_timer(&ctx->timer, 6, 0); +} + +/* Section 9.4.1 Attach request */ +static int gsm48_rx_gmm_att_req(struct msgb *msg) +{ + struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg); + uint8_t *cur = gh->data, *msnc, *mi, *old_ra_info; + uint8_t msnc_len, att_type, mi_len, mi_type; + uint16_t drx_par; + uint32_t tmsi; + char mi_string[GSM48_MI_SIZE]; + struct gprs_ra_id ra_id; + uint16_t cid; + struct sgsn_mm_ctx *ctx; + + DEBUGP(DMM, "GMM ATTACH REQUEST "); + + /* As per TS 04.08 Chapter 4.7.1.4, the attach request arrives either + * with a foreign TLLI (P-TMSI that was allocated to the MS before), + * or with random TLLI. */ + + cid = bssgp_parse_cell_id(&ra_id, msgb_bcid(msg)); + + /* MS network capability 10.5.5.12 */ + msnc_len = *cur++; + msnc = cur; + if (msnc_len > 2) + goto err_inval; + cur += msnc_len; + + /* aTTACH Type 10.5.5.2 */ + att_type = *cur++ & 0x0f; + + /* DRX parameter 10.5.5.6 */ + drx_par = *cur++; + drx_par |= *cur++ << 8; + + /* Mobile Identity (P-TMSI or IMSI) 10.5.1.4 */ + mi_len = *cur++; + mi = cur; + if (mi_len > 8) + goto err_inval; + mi_type = *mi & GSM_MI_TYPE_MASK; + cur += mi_len; + + gsm48_mi_to_string(mi_string, sizeof(mi_string), mi, mi_len); + + DEBUGPC(DMM, "MI(%s) type=\"%s\" ", mi_string, att_name(att_type)); + + /* Old routing area identification 10.5.5.15 */ + old_ra_info = cur; + cur += 6; + + /* MS Radio Access Capability 10.5.5.12a */ + + /* Optional: Old P-TMSI Signature, Requested READY timer, TMSI Status */ + + switch (mi_type) { + case GSM_MI_TYPE_IMSI: + /* Try to find MM context based on IMSI */ + ctx = sgsn_mm_ctx_by_imsi(mi_string); + if (!ctx) { +#if 0 + return gsm48_tx_gmm_att_rej(msg, GMM_CAUSE_IMSI_UNKNOWN); +#else + /* As a temorary hack, we simply assume that the IMSI exists */ + ctx = sgsn_mm_ctx_alloc(0, &ra_id); + if (!ctx) + return gsm48_tx_gmm_att_rej(msg, GMM_CAUSE_NET_FAIL); + strncpy(ctx->imsi, mi_string, sizeof(ctx->imsi)); +#endif + } + /* FIXME: Start some timer */ + ctx->mm_state = GMM_COMMON_PROC_INIT; + ctx->tlli = msgb_tlli(msg); + break; + case GSM_MI_TYPE_TMSI: + tmsi = strtoul(mi_string, NULL, 10); + /* Try to find MM context based on P-TMSI */ + ctx = sgsn_mm_ctx_by_ptmsi(tmsi); + if (!ctx) { + ctx = sgsn_mm_ctx_alloc(msgb_tlli(msg), &ra_id); + /* FIXME: Start some timer */ + ctx->mm_state = GMM_COMMON_PROC_INIT; + ctx->tlli = msgb_tlli(msg); + } + break; + default: + return 0; + } + /* Update MM Context with currient RA and Cell ID */ + ctx->ra = ra_id; + ctx->cell_id = cid; + + /* FIXME: allocate a new P-TMSI (+ P-TMSI signature) */ + /* FIXME: update the TLLI with the new local TLLI based on the P-TMSI */ + + DEBUGPC(DMM, "\n"); + + return ctx ? gsm48_gmm_authorize(ctx, msg) : 0; + +err_inval: + DEBUGPC(DMM, "\n"); + return gsm48_tx_gmm_att_rej(msg, GMM_CAUSE_SEM_INCORR_MSG); +} + +/* Chapter 9.4.15: Routing area update accept */ +static int gsm48_tx_gmm_ra_upd_ack(struct msgb *old_msg) +{ + struct msgb *msg = gsm48_msgb_alloc(); + struct gsm48_hdr *gh; + struct gsm48_ra_upd_ack *rua; + struct gprs_ra_id ra_id; + + DEBUGP(DMM, "<- ROUTING AREA UPDATE ACCEPT\n"); + + gmm_copy_id(msg, old_msg); + + gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh)); + gh->proto_discr = GSM48_PDISC_MM_GPRS; + gh->msg_type = GSM48_MT_GMM_RA_UPD_ACK; + + rua = (struct gsm48_ra_upd_ack *) msgb_put(msg, sizeof(*rua)); + rua->force_stby = 0; /* not indicated */ + rua->upd_result = 0; /* RA updated */ + rua->ra_upd_timer = GPRS_TMR_MINUTE | 10; + + bssgp_parse_cell_id(&ra_id, msgb_bcid(old_msg)); + gsm48_construct_ra(rua->ra_id.digits, &ra_id); + + /* Option: P-TMSI signature, allocated P-TMSI, MS ID, ... */ + return gsm48_gmm_sendmsg(msg, 0); +} + +/* Chapter 9.4.17: Routing area update reject */ +static int gsm48_tx_gmm_ra_upd_rej(struct msgb *old_msg, uint8_t cause) +{ + struct msgb *msg = gsm48_msgb_alloc(); + struct gsm48_hdr *gh; + + DEBUGP(DMM, "<- ROUTING AREA UPDATE REJECT\n"); + + gmm_copy_id(msg, old_msg); + + gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 2); + gh->proto_discr = GSM48_PDISC_MM_GPRS; + gh->msg_type = GSM48_MT_GMM_RA_UPD_REJ; + gh->data[0] = cause; + gh->data[1] = 0; /* ? */ + + /* Option: P-TMSI signature, allocated P-TMSI, MS ID, ... */ + return gsm48_gmm_sendmsg(msg, 0); +} + +/* Chapter 9.4.14: Routing area update request */ +static int gsm48_rx_gmm_ra_upd_req(struct msgb *msg) +{ + struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg); + struct sgsn_mm_ctx *mmctx; + uint8_t *cur = gh->data; + struct gprs_ra_id old_ra_id; + uint8_t upd_type; + + /* Update Type 10.5.5.18 */ + upd_type = *cur++ & 0x0f; + + DEBUGP(DMM, "GMM RA UPDATE REQUEST type=\"%s\" ", upd_name(upd_type)); + + /* Old routing area identification 10.5.5.15 */ + gsm48_parse_ra(&old_ra_id, cur); + cur += 6; + + /* MS Radio Access Capability 10.5.5.12a */ + + /* Optional: Old P-TMSI Signature, Requested READY timer, TMSI Status, + * DRX parameter, MS network capability */ + + switch (upd_type) { + case GPRS_UPD_T_RA_LA: + case GPRS_UPD_T_RA_LA_IMSI_ATT: + DEBUGPC(DMM, " unsupported in Mode III, is your SI13 corrupt?\n"); + return gsm48_tx_gmm_ra_upd_rej(msg, GMM_CAUSE_PROTO_ERR_UNSPEC); + break; + case GPRS_UPD_T_RA: + case GPRS_UPD_T_PERIODIC: + break; + } + + /* Look-up the MM context based on old RA-ID and TLLI */ + mmctx = sgsn_mm_ctx_by_tlli(msgb_tlli(msg), &old_ra_id); + if (!mmctx || mmctx->mm_state == GMM_DEREGISTERED) { + /* The MS has to perform GPRS attach */ + DEBUGPC(DMM, " REJECT\n"); + return gsm48_tx_gmm_ra_upd_rej(msg, GMM_CAUSE_IMPL_DETACHED); + } + + /* Update the MM context with the new RA-ID */ + bssgp_parse_cell_id(&mmctx->ra, msgb_bcid(msg)); + /* Update the MM context with the new TLLI */ + mmctx->tlli = msgb_tlli(msg); + /* FIXME: Update the MM context with the MS radio acc capabilities */ + /* FIXME: Update the MM context with the MS network capabilities */ + + DEBUGPC(DMM, " ACCEPT\n"); + return gsm48_tx_gmm_ra_upd_ack(msg); +} + +static int gsm48_rx_gmm_status(struct msgb *msg) +{ + struct gsm48_hdr *gh = msgb_l3(msg); + + DEBUGP(DMM, "GPRS MM STATUS (cause: %s)\n", + get_value_string(gmm_cause_names, gh->data[0])); + + return 0; +} + +/* GPRS Mobility Management */ +static int gsm0408_rcv_gmm(struct msgb *msg) +{ + struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg); + int rc; + + switch (gh->msg_type) { + case GSM48_MT_GMM_RA_UPD_REQ: + rc = gsm48_rx_gmm_ra_upd_req(msg); + break; + case GSM48_MT_GMM_ATTACH_REQ: + rc = gsm48_rx_gmm_att_req(msg); + break; + case GSM48_MT_GMM_ID_RESP: + rc = gsm48_rx_gmm_id_resp(msg); + break; + case GSM48_MT_GMM_STATUS: + rc = gsm48_rx_gmm_status(msg); + break; + case GSM48_MT_GMM_RA_UPD_COMPL: + /* only in case SGSN offered new P-TMSI */ + case GSM48_MT_GMM_ATTACH_COMPL: + /* only in case SGSN offered new P-TMSI */ + case GSM48_MT_GMM_DETACH_REQ: + case GSM48_MT_GMM_PTMSI_REALL_COMPL: + case GSM48_MT_GMM_AUTH_CIPH_RESP: + DEBUGP(DMM, "Unimplemented GSM 04.08 GMM msg type 0x%02x\n", + gh->msg_type); + break; + default: + DEBUGP(DMM, "Unknown GSM 04.08 GMM msg type 0x%02x\n", + gh->msg_type); + break; + } + + return rc; +} + +static void msgb_put_pdp_addr_ipv4(struct msgb *msg, uint32_t ipaddr) +{ + uint8_t v[6]; + + v[0] = PDP_TYPE_ORG_IETF; + v[1] = PDP_TYPE_N_IETF_IPv4; + *(uint32_t *)(v+2) = htonl(ipaddr); + + msgb_tlv_put(msg, GSM48_IE_GSM_PDP_ADDR, sizeof(v), v); +} + +static void msgb_put_pdp_addr_ppp(struct msgb *msg) +{ + uint8_t v[2]; + + v[0] = PDP_TYPE_ORG_ETSI; + v[1] = PDP_TYPE_N_ETSI_PPP; + + msgb_tlv_put(msg, GSM48_IE_GSM_PDP_ADDR, sizeof(v), v); +} + +/* Section 9.5.2: Ativate PDP Context Accept */ +static int gsm48_tx_gsm_act_pdp_acc(struct msgb *old_msg, struct gsm48_act_pdp_ctx_req *req) +{ + struct gsm48_hdr *old_gh = (struct gsm48_hdr *) msgb_gmmh(old_msg); + struct msgb *msg = gsm48_msgb_alloc(); + struct gsm48_act_pdp_ctx_ack *act_ack; + struct gsm48_hdr *gh; + uint8_t transaction_id = ((old_gh->proto_discr >> 4) ^ 0x8); /* flip */ + + DEBUGP(DMM, "<- ACTIVATE PDP CONTEXT ACK\n"); + + gmm_copy_id(msg, old_msg); + + gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh)); + gh->proto_discr = GSM48_PDISC_SM_GPRS | (transaction_id << 4); + gh->msg_type = GSM48_MT_GSM_ACT_PDP_ACK; + + /* Negotiated LLC SAPI */ + msgb_v_put(msg, req->req_llc_sapi); + /* copy QoS parameters from original request */ + msgb_lv_put(msg, sizeof(default_qos), (uint8_t *)&default_qos); + /* Radio priority 10.5.7.2 */ + msgb_v_put(msg, 4); + /* PDP address */ + msgb_put_pdp_addr_ipv4(msg, 0x01020304); + /* Optional: Protocol configuration options */ + /* Optional: Packet Flow Identifier */ + + return gsm48_gmm_sendmsg(msg, 0); +} + +/* Section 9.5.9: Deactivate PDP Context Accept */ +static int gsm48_tx_gsm_deact_pdp_acc(struct msgb *old_msg) +{ + struct gsm48_hdr *old_gh = (struct gsm48_hdr *) msgb_gmmh(old_msg); + struct msgb *msg = gsm48_msgb_alloc(); + struct gsm48_hdr *gh; + uint8_t transaction_id = ((old_gh->proto_discr >> 4) ^ 0x8); /* flip */ + + DEBUGP(DMM, "<- DEACTIVATE PDP CONTEXT ACK\n"); + + gmm_copy_id(msg, old_msg); + + gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh)); + gh->proto_discr = GSM48_PDISC_SM_GPRS | (transaction_id << 4); + gh->msg_type = GSM48_MT_GSM_DEACT_PDP_ACK; + + return gsm48_gmm_sendmsg(msg, 0); +} + +/* Section 9.5.1: Activate PDP Context Request */ +static int gsm48_rx_gsm_act_pdp_req(struct msgb *msg) +{ + struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg); + struct gsm48_act_pdp_ctx_req *act_req = (struct gsm48_act_pdp_ctx_req *) gh->data; + uint8_t *pdp_addr_lv = act_req->data; + uint8_t req_qos_len, req_pdpa_len; + uint8_t *req_qos, *req_pdpa; + struct tlv_parsed tp; + + DEBUGP(DMM, "ACTIVATE PDP CONTEXT REQ: "); + req_qos_len = act_req->data[0]; + req_qos = act_req->data + 1; /* 10.5.6.5 */ + req_pdpa_len = act_req->data[1 + req_qos_len]; + req_pdpa = act_req->data + 1 + req_qos_len + 1; /* 10.5.6.4 */ + + switch (req_pdpa[0] & 0xf) { + case 0x0: + DEBUGPC(DMM, "ETSI "); + break; + case 0x1: + DEBUGPC(DMM, "IETF "); + break; + case 0xf: + DEBUGPC(DMM, "Empty "); + break; + } + + switch (req_pdpa[1]) { + case 0x21: + DEBUGPC(DMM, "IPv4 "); + if (req_pdpa_len >= 6) { + struct in_addr ia; + ia.s_addr = ntohl(*((uint32_t *) (req_pdpa+2))); + DEBUGPC(DMM, "%s ", inet_ntoa(ia)); + } + break; + case 0x57: + DEBUGPC(DMM, "IPv6 "); + if (req_pdpa_len >= 18) { + /* FIXME: print IPv6 address */ + } + break; + default: + DEBUGPC(DMM, "0x%02x ", req_pdpa[1]); + break; + } + + /* FIXME: parse TLV for AP name and protocol config options */ + if (TLVP_PRESENT(&tp, GSM48_IE_GSM_APN)) {} + if (TLVP_PRESENT(&tp, GSM48_IE_GSM_PROTO_CONF_OPT)) {} + + return gsm48_tx_gsm_act_pdp_acc(msg, act_req); +} + +/* Section 9.5.8: Deactivate PDP Context Request */ +static int gsm48_rx_gsm_deact_pdp_req(struct msgb *msg) +{ + struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg); + + DEBUGP(DMM, "DEACTIVATE PDP CONTEXT REQ (cause: %s)\n", + get_value_string(gsm_cause_names, gh->data[0])); + + return gsm48_tx_gsm_deact_pdp_acc(msg); +} + +static int gsm48_rx_gsm_status(struct msgb *msg) +{ + struct gsm48_hdr *gh = msgb_l3(msg); + + DEBUGP(DMM, "GPRS SM STATUS (cause: %s)\n", + get_value_string(gsm_cause_names, gh->data[0])); + + return 0; +} + +/* GPRS Session Management */ +static int gsm0408_rcv_gsm(struct msgb *msg) +{ + struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg); + int rc; + + switch (gh->msg_type) { + case GSM48_MT_GSM_ACT_PDP_REQ: + rc = gsm48_rx_gsm_act_pdp_req(msg); + break; + case GSM48_MT_GSM_DEACT_PDP_REQ: + rc = gsm48_rx_gsm_deact_pdp_req(msg); + case GSM48_MT_GSM_STATUS: + rc = gsm48_rx_gsm_status(msg); + break; + case GSM48_MT_GSM_REQ_PDP_ACT_REJ: + case GSM48_MT_GSM_ACT_AA_PDP_REQ: + case GSM48_MT_GSM_DEACT_AA_PDP_REQ: + DEBUGP(DMM, "Unimplemented GSM 04.08 GSM msg type 0x%02x\n", + gh->msg_type); + break; + default: + DEBUGP(DMM, "Unknown GSM 04.08 GSM msg type 0x%02x\n", + gh->msg_type); + break; + + } + + return rc; +} + +/* Main entry point for incoming 04.08 GPRS messages */ +int gsm0408_gprs_rcvmsg(struct msgb *msg) +{ + struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg); + uint8_t pdisc = gh->proto_discr & 0x0f; + int rc = -EINVAL; + + switch (pdisc) { + case GSM48_PDISC_MM_GPRS: + rc = gsm0408_rcv_gmm(msg); + break; + case GSM48_PDISC_SM_GPRS: + rc = gsm0408_rcv_gsm(msg); + break; + default: + DEBUGP(DMM, "Unknown GSM 04.08 discriminator 0x%02x\n", + pdisc); + break; + } + + return rc; +} diff --git a/openbsc/src/gprs/osmo_gbproxy.cfg b/openbsc/src/gprs/osmo_gbproxy.cfg new file mode 100644 index 000000000..f2ef1411f --- /dev/null +++ b/openbsc/src/gprs/osmo_gbproxy.cfg @@ -0,0 +1,13 @@ +! +! OpenBSC configuration saved from vty +! ! +! +line vty + no login +! +gbproxy + nsip bss local port 23000 + nsip sgsn remote ip 192.168.100.239 + nsip sgsn remote port 23000 + nsip sgsn nsei 1 + nsip sgsn nsvci 11 diff --git a/openbsc/src/gprs/osmo_sgsn.cfg b/openbsc/src/gprs/osmo_sgsn.cfg new file mode 100644 index 000000000..f39e8536f --- /dev/null +++ b/openbsc/src/gprs/osmo_sgsn.cfg @@ -0,0 +1,9 @@ +! +! OpenBSC configuration saved from vty +! ! +! +line vty + no login +! +sgsn + nsip local port 23000 diff --git a/openbsc/src/gprs/sgsn_main.c b/openbsc/src/gprs/sgsn_main.c new file mode 100644 index 000000000..15f760d5c --- /dev/null +++ b/openbsc/src/gprs/sgsn_main.c @@ -0,0 +1,143 @@ +/* GPRS SGSN Implementation */ + +/* (C) 2010 by Harald Welte + * (C) 2010 by On Waves + * 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 +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "../../bscconfig.h" + +/* this is here for the vty... it will never be called */ +void subscr_put() { abort(); } + +#define _GNU_SOURCE +#include + +void *tall_bsc_ctx; + +struct gprs_ns_inst *sgsn_nsi; + +const char *openbsc_version = "Osmocom NSIP Proxy " PACKAGE_VERSION; +const char *openbsc_copyright = + "Copyright (C) 2010 Harald Welte and On-Waves\n" + "Contributions by Daniel Willmann, Jan Lübbe, Stefan Schmidt\n" + "Dieter Spaar, Andreas Eversberg, Holger Freyther\n\n" + "License GPLv2+: GNU GPL version 2 or later \n" + "This is free software: you are free to change and redistribute it.\n" + "There is NO WARRANTY, to the extent permitted by law.\n"; + +static char *config_file = "osmo_sgsn.cfg"; +static struct sgsn_config sgcfg; + +/* call-back function for the NS protocol */ +static int sgsn_ns_cb(enum gprs_ns_evt event, struct gprs_nsvc *nsvc, + struct msgb *msg, u_int16_t bvci) +{ + int rc = 0; + + switch (event) { + case GPRS_NS_EVT_UNIT_DATA: + /* hand the message into the BSSGP implementation */ + rc = gprs_bssgp_rcvmsg(msg); + break; + default: + LOGP(DGPRS, LOGL_ERROR, "SGSN: Unknown event %u from NS\n", event); + if (msg) + talloc_free(msg); + rc = -EIO; + break; + } + return rc; +} + +/* NSI that BSSGP uses when transmitting on NS */ +extern struct gprs_ns_inst *bssgp_nsi; + +int main(int argc, char **argv) +{ + struct gsm_network dummy_network; + struct log_target *stderr_target; + struct sockaddr_in sin; + int rc; + + tall_bsc_ctx = talloc_named_const(NULL, 0, "osmo_sgsn"); + + log_init(&log_info); + stderr_target = log_target_create_stderr(); + log_add_target(stderr_target); + log_set_all_filter(stderr_target, 1); + + telnet_init(&dummy_network, 4245); + rc = sgsn_parse_config(config_file, &sgcfg); + if (rc < 0) { + LOGP(DGPRS, LOGL_FATAL, "Cannot parse config file\n"); + exit(2); + } + + sgsn_nsi = gprs_ns_instantiate(&sgsn_ns_cb); + if (!sgsn_nsi) { + LOGP(DGPRS, LOGL_ERROR, "Unable to instantiate NS\n"); + exit(1); + } + bssgp_nsi = sgcfg.nsi = sgsn_nsi; + nsip_listen(sgsn_nsi, sgcfg.nsip_listen_port); + + while (1) { + rc = bsc_select_main(0); + if (rc < 0) + exit(3); + } + + exit(0); +} + +struct gsm_network; +int bsc_vty_init(struct gsm_network *dummy) +{ + cmd_init(1); + vty_init(); + + openbsc_vty_add_cmds(); + sgsn_vty_init(); + return 0; +} + diff --git a/openbsc/src/gprs/sgsn_vty.c b/openbsc/src/gprs/sgsn_vty.c new file mode 100644 index 000000000..ec18fcbf9 --- /dev/null +++ b/openbsc/src/gprs/sgsn_vty.c @@ -0,0 +1,146 @@ +/* + * (C) 2010 by Harald Welte + * (C) 2010 by On-Waves + * 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 +#include +#include + +#include +#include + +static struct sgsn_config *g_cfg = NULL; + +static struct cmd_node sgsn_node = { + SGSN_NODE, + "%s(sgsn)#", + 1, +}; + +static int config_write_sgsn(struct vty *vty) +{ + struct in_addr ia; + + vty_out(vty, "sgsn%s", VTY_NEWLINE); + + if (g_cfg->nsip_listen_ip) { + ia.s_addr = htonl(g_cfg->nsip_listen_ip); + vty_out(vty, " nsip local ip %s%s", inet_ntoa(ia), + VTY_NEWLINE); + } + vty_out(vty, " nsip local port %u%s", g_cfg->nsip_listen_port, + VTY_NEWLINE); + + return CMD_SUCCESS; +} + +DEFUN(show_sgsn, show_sgsn_cmd, "show sgsn", + SHOW_STR "Display information about the SGSN") +{ + /* FIXME: iterate over list of NS-VC's and display their state */ + struct gprs_ns_inst *nsi = g_cfg->nsi; + struct gprs_nsvc *nsvc; + + llist_for_each_entry(nsvc, &nsi->gprs_nsvcs, list) { + vty_out(vty, "NSEI %5u, NS-VC %5u, %s-mode, %s %s%s", + nsvc->nsei, nsvc->nsvci, + nsvc->remote_end_is_sgsn ? "BSS" : "SGSN", + nsvc->state & NSE_S_ALIVE ? "ALIVE" : "DEAD", + nsvc->state & NSE_S_BLOCKED ? "BLOCKED" : "UNBLOCKED", + VTY_NEWLINE); + if (nsvc->nsi->ll == GPRS_NS_LL_UDP) + vty_out(vty, " remote peer %s:%u%s", + inet_ntoa(nsvc->ip.bts_addr.sin_addr), + ntohs(nsvc->ip.bts_addr.sin_port), VTY_NEWLINE); + } + + return CMD_SUCCESS; +} + +DEFUN(cfg_sgsn, + cfg_sgsn_cmd, + "sgsn", + "Configure the SGSN") +{ + vty->node = SGSN_NODE; + return CMD_SUCCESS; +} + + +DEFUN(cfg_nsip_local_ip, + cfg_nsip_local_ip_cmd, + "nsip local ip A.B.C.D", + "Set the IP address on which we listen for BSS connects") +{ + struct in_addr ia; + + inet_aton(argv[0], &ia); + g_cfg->nsip_listen_ip = ntohl(ia.s_addr); + + return CMD_SUCCESS; +} + +DEFUN(cfg_nsip_local_port, + cfg_nsip_local_port_cmd, + "nsip local port <0-65534>", + "Set the UDP port on which we listen for BSS connects") +{ + unsigned int port = atoi(argv[0]); + + g_cfg->nsip_listen_port = port; + return CMD_SUCCESS; +} + + + + +int sgsn_vty_init(void) +{ + install_element(VIEW_NODE, &show_sgsn_cmd); + + install_element(CONFIG_NODE, &cfg_sgsn_cmd); + install_node(&sgsn_node, config_write_sgsn); + install_default(SGSN_NODE); + install_element(SGSN_NODE, &cfg_nsip_local_ip_cmd); + install_element(SGSN_NODE, &cfg_nsip_local_port_cmd); + + return 0; +} + +int sgsn_parse_config(const char *config_file, struct sgsn_config *cfg) +{ + int rc; + + g_cfg = cfg; + rc = vty_read_config_file(config_file); + if (rc < 0) { + fprintf(stderr, "Failed to parse the config file: '%s'\n", config_file); + return rc; + } + + return 0; +} diff --git a/openbsc/src/gprs_bssgp.c b/openbsc/src/gprs_bssgp.c deleted file mode 100644 index 554738b56..000000000 --- a/openbsc/src/gprs_bssgp.c +++ /dev/null @@ -1,537 +0,0 @@ -/* GPRS BSSGP protocol implementation as per 3GPP TS 08.18 */ - -/* (C) 2009-2010 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 - -#include -#include -#include -#include -#include -#include - -/* global pointer to the gsm network data structure */ -/* FIXME: this must go! */ -extern struct gsm_network *bsc_gsmnet; -struct gprs_ns_inst *bssgp_nsi; - -void *bssgp_tall_ctx = NULL; - -/* BSSGP Protocol specific, not implementation specific */ -/* FIXME: This needs to go into libosmocore after finished */ - -/* Chapter 11.3.9 / Table 11.10: Cause coding */ -static const struct value_string bssgp_cause_strings[] = { - { BSSGP_CAUSE_PROC_OVERLOAD, "Processor overload" }, - { BSSGP_CAUSE_EQUIP_FAIL, "Equipment Failure" }, - { BSSGP_CAUSE_TRASIT_NET_FAIL, "Transit netowkr service failure" }, - { BSSGP_CAUSE_CAPA_GREATER_0KPBS,"Transmission capacity modified" }, - { BSSGP_CAUSE_UNKNOWN_MS, "Unknown MS" }, - { BSSGP_CAUSE_UNKNOWN_BVCI, "Unknown BVCI" }, - { BSSGP_CAUSE_CELL_TRAF_CONG, "Cell traffic congestion" }, - { BSSGP_CAUSE_SGSN_CONG, "SGSN congestion" }, - { BSSGP_CAUSE_OML_INTERV, "O&M intervention" }, - { BSSGP_CAUSE_BVCI_BLOCKED, "BVCI blocked" }, - { BSSGP_CAUSE_PFC_CREATE_FAIL, "PFC create failure" }, - { BSSGP_CAUSE_SEM_INCORR_PDU, "Semantically incorrect PDU" }, - { BSSGP_CAUSE_INV_MAND_INF, "Invalid mandatory information" }, - { BSSGP_CAUSE_MISSING_MAND_IE, "Missing mandatory IE" }, - { BSSGP_CAUSE_MISSING_COND_IE, "Missing conditional IE" }, - { BSSGP_CAUSE_UNEXP_COND_IE, "Unexpected conditional IE" }, - { BSSGP_CAUSE_COND_IE_ERR, "Conditional IE error" }, - { BSSGP_CAUSE_PDU_INCOMP_STATE, "PDU incompatible with protocol state" }, - { BSSGP_CAUSE_PROTO_ERR_UNSPEC, "Protocol error - unspecified" }, - { BSSGP_CAUSE_PDU_INCOMP_FEAT, "PDU not compatible with feature set" }, - { 0, NULL }, -}; - -const char *bssgp_cause_str(enum gprs_bssgp_cause cause) -{ - return get_value_string(bssgp_cause_strings, cause); -} - - -/* Our actual implementation */ - -#define BVC_F_BLOCKED 0x0001 - -/* The per-BTS context that we keep on the SGSN side of the BSSGP link */ -struct bssgp_bts_ctx { - struct llist_head list; - - /* parsed RA ID and Cell ID of the remote BTS */ - struct gprs_ra_id ra_id; - uint16_t cell_id; - - /* NSEI and BVCI of underlying Gb link. Together they - * uniquely identify a link to a BTS (5.4.4) */ - uint16_t bvci; - uint16_t nsei; - - uint32_t bvc_state; - - /* we might want to add this as a shortcut later, avoiding the NSVC - * lookup for every packet, similar to a routing cache */ - //struct gprs_nsvc *nsvc; -}; -LLIST_HEAD(bts_ctxts); - -/* Find a BTS Context based on parsed RA ID and Cell ID */ -struct bssgp_bts_ctx *btsctx_by_raid_cid(const struct gprs_ra_id *raid, uint16_t cid) -{ - struct bssgp_bts_ctx *bctx; - - llist_for_each_entry(bctx, &bts_ctxts, list) { - if (!memcmp(&bctx->ra_id, raid, sizeof(bctx->ra_id)) && - bctx->cell_id == cid) - return bctx; - } - return NULL; -} - -/* Find a BTS context based on BVCI+NSEI tuple */ -struct bssgp_bts_ctx *btsctx_by_bvci_nsei(uint16_t bvci, uint16_t nsei) -{ - struct bssgp_bts_ctx *bctx; - - llist_for_each_entry(bctx, &bts_ctxts, list) { - if (bctx->nsei == nsei && bctx->bvci == bvci) - return bctx; - } - return NULL; -} - -struct bssgp_btx_ctx *btsctx_alloc(uint16_t bvci, uint16_t nsei) -{ - struct bssgp_bts_ctx *ctx; - - ctx = talloc_zero(bssgp_tall_ctx, struct bssgp_bts_ctx); - if (!ctx) - return NULL; - ctx->bvci = bvci; - ctx->nsei = nsei; - llist_add(&ctx->list, &bts_ctxts); - - return ctx; -} - -static inline struct msgb *bssgp_msgb_alloc(void) -{ - return msgb_alloc_headroom(4096, 128, "BSSGP"); -} - -/* Transmit a simple response such as BLOCK/UNBLOCK/RESET ACK/NACK */ -static int bssgp_tx_simple_bvci(uint8_t pdu_type, uint16_t nsei, - uint16_t bvci, uint16_t ns_bvci) -{ - struct msgb *msg = bssgp_msgb_alloc(); - struct bssgp_normal_hdr *bgph = - (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph)); - uint16_t _bvci; - - msgb_nsei(msg) = nsei; - msgb_bvci(msg) = ns_bvci; - - bgph->pdu_type = pdu_type; - _bvci = htons(bvci); - msgb_tvlv_put(msg, BSSGP_IE_BVCI, 2, (uint8_t *) &_bvci); - - return gprs_ns_sendmsg(bssgp_nsi, msg); -} - -/* Chapter 10.4.5: Flow Control BVC ACK */ -static int bssgp_tx_fc_bvc_ack(uint16_t nsei, uint8_t tag, uint16_t ns_bvci) -{ - struct msgb *msg = bssgp_msgb_alloc(); - struct bssgp_normal_hdr *bgph = - (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph)); - - msgb_nsei(msg) = nsei; - msgb_bvci(msg) = ns_bvci; - - bgph->pdu_type = BSSGP_PDUT_FLOW_CONTROL_BVC_ACK; - msgb_tvlv_put(msg, BSSGP_IE_TAG, 1, &tag); - - return gprs_ns_sendmsg(bssgp_nsi, msg); -} - -/* Chapter 10.4.14: Status */ -int bssgp_tx_status(uint8_t cause, uint16_t *bvci, struct msgb *orig_msg) -{ - struct msgb *msg = bssgp_msgb_alloc(); - struct bssgp_normal_hdr *bgph = - (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph)); - - DEBUGPC(DGPRS, "BSSGP: TX STATUS, cause=%s\n", bssgp_cause_str(cause)); - msgb_nsei(msg) = msgb_nsei(orig_msg); - msgb_bvci(msg) = 0; - - bgph->pdu_type = BSSGP_PDUT_STATUS; - msgb_tvlv_put(msg, BSSGP_IE_CAUSE, 1, &cause); - if (bvci) { - uint16_t _bvci = htons(*bvci); - msgb_tvlv_put(msg, BSSGP_IE_BVCI, 2, (uint8_t *) &_bvci); - } - if (orig_msg) - msgb_tvlv_put(msg, BSSGP_IE_PDU_IN_ERROR, - msgb_bssgp_len(orig_msg), msgb_bssgph(orig_msg)); - - return gprs_ns_sendmsg(bssgp_nsi, msg); -} - -uint16_t bssgp_parse_cell_id(struct gprs_ra_id *raid, const uint8_t *buf) -{ - /* 6 octets RAC */ - gsm48_parse_ra(raid, buf); - /* 2 octets CID */ - return ntohs(*(uint16_t *) (buf+6)); -} - -/* Chapter 8.4 BVC-Reset Procedure */ -static int bssgp_rx_bvc_reset(struct msgb *msg, struct tlv_parsed *tp, - uint16_t ns_bvci) -{ - struct bssgp_bts_ctx *bctx; - uint16_t nsei = msgb_nsei(msg); - uint16_t bvci; - int rc; - - bvci = ntohs(*(uint16_t *)TLVP_VAL(tp, BSSGP_IE_BVCI)); - DEBUGPC(DGPRS, "BVCI=%u, cause=%s\n", bvci, - bssgp_cause_str(*TLVP_VAL(tp, BSSGP_IE_CAUSE))); - - /* look-up or create the BTS context for this BVC */ - bctx = btsctx_by_bvci_nsei(bvci, nsei); - if (!bctx) - bctx = btsctx_alloc(bvci, nsei); - - /* When we receive a BVC-RESET PDU (at least of a PTP BVCI), the BSS - * informs us about its RAC + Cell ID, so we can create a mapping */ - if (bvci != 0 && bvci != 1) { - if (!TLVP_PRESENT(tp, BSSGP_IE_CELL_ID)) { - LOGP(DGPRS, LOGL_ERROR, "BSSGP RESET BVCI=%u " - "missing mandatory IE\n", bvci); - return -EINVAL; - } - /* actually extract RAC / CID */ - bctx->cell_id = bssgp_parse_cell_id(&bctx->ra_id, - TLVP_VAL(tp, BSSGP_IE_CELL_ID)); - LOGP(DGPRS, LOGL_NOTICE, "Cell %u-%u-%u-%u CI %u on BVCI %u\n", - bctx->ra_id.mcc, bctx->ra_id.mnc, bctx->ra_id.lac, - bctx->ra_id.rac, bctx->cell_id, bvci); - } - - /* Acknowledge the RESET to the BTS */ - rc = bssgp_tx_simple_bvci(BSSGP_PDUT_BVC_RESET_ACK, - nsei, bvci, ns_bvci); - return 0; -} - -/* Uplink unit-data */ -static int bssgp_rx_ul_ud(struct msgb *msg) -{ - struct bssgp_ud_hdr *budh = (struct bssgp_ud_hdr *) msgb_bssgph(msg); - int data_len = msgb_bssgp_len(msg) - sizeof(*budh); - struct tlv_parsed tp; - int rc; - - DEBUGP(DGPRS, "BSSGP UL-UD\n"); - - /* extract TLLI and parse TLV IEs */ - msgb_tlli(msg) = ntohl(budh->tlli); - rc = bssgp_tlv_parse(&tp, budh->data, data_len); - - /* Cell ID and LLC_PDU are the only mandatory IE */ - if (!TLVP_PRESENT(&tp, BSSGP_IE_CELL_ID) || - !TLVP_PRESENT(&tp, BSSGP_IE_LLC_PDU)) - return -EIO; - - /* FIXME: lookup bssgp_bts_ctx based on BVCI + NSEI */ - - /* store pointer to LLC header and CELL ID in msgb->cb */ - msgb_llch(msg) = TLVP_VAL(&tp, BSSGP_IE_LLC_PDU); - msgb_bcid(msg) = TLVP_VAL(&tp, BSSGP_IE_CELL_ID); - - return gprs_llc_rcvmsg(msg, &tp); -} - -static int bssgp_rx_suspend(struct msgb *msg) -{ - struct bssgp_normal_hdr *bgph = - (struct bssgp_normal_hdr *) msgb_bssgph(msg); - int data_len = msgb_bssgp_len(msg) - sizeof(*bgph); - struct tlv_parsed tp; - int rc; - - DEBUGP(DGPRS, "BSSGP SUSPEND\n"); - - rc = bssgp_tlv_parse(&tp, bgph->data, data_len); - if (rc < 0) - return rc; - - if (!TLVP_PRESENT(&tp, BSSGP_IE_TLLI) || - !TLVP_PRESENT(&tp, BSSGP_IE_ROUTEING_AREA)) - return -EIO; - - /* FIXME: pass the SUSPEND request to GMM */ - /* SEND SUSPEND_ACK or SUSPEND_NACK */ -} - -static int bssgp_rx_resume(struct msgb *msg) -{ - struct bssgp_normal_hdr *bgph = - (struct bssgp_normal_hdr *) msgb_bssgph(msg); - int data_len = msgb_bssgp_len(msg) - sizeof(*bgph); - struct tlv_parsed tp; - int rc; - - DEBUGP(DGPRS, "BSSGP RESUME\n"); - - rc = bssgp_tlv_parse(&tp, bgph->data, data_len); - if (rc < 0) - return rc; - - if (!TLVP_PRESENT(&tp, BSSGP_IE_TLLI) || - !TLVP_PRESENT(&tp, BSSGP_IE_ROUTEING_AREA) || - !TLVP_PRESENT(&tp, BSSGP_IE_SUSPEND_REF_NR)) - return -EIO; - - /* FIXME: pass the RESUME request to GMM */ - /* SEND RESUME_ACK or RESUME_NACK */ -} - -static int bssgp_rx_fc_bvc(struct msgb *msg, struct tlv_parsed *tp) -{ - - DEBUGP(DGPRS, "BSSGP FC BVC\n"); - - if (!TLVP_PRESENT(tp, BSSGP_IE_TAG) || - !TLVP_PRESENT(tp, BSSGP_IE_BVC_BUCKET_SIZE) || - !TLVP_PRESENT(tp, BSSGP_IE_BUCKET_LEAK_RATE) || - !TLVP_PRESENT(tp, BSSGP_IE_BMAX_DEFAULT_MS) || - !TLVP_PRESENT(tp, BSSGP_IE_R_DEFAULT_MS)) - return bssgp_tx_status(BSSGP_CAUSE_MISSING_MAND_IE, NULL, msg); - - /* FIXME: actually implement flow control */ - - /* Send FLOW_CONTROL_BVC_ACK */ - return bssgp_tx_fc_bvc_ack(msgb_nsei(msg), *TLVP_VAL(tp, BSSGP_IE_TAG), - msgb_bvci(msg)); -} - -/* We expect msgb_bssgph() to point to the BSSGP header */ -int gprs_bssgp_rcvmsg(struct msgb *msg) -{ - struct bssgp_normal_hdr *bgph = - (struct bssgp_normal_hdr *) msgb_bssgph(msg); - struct tlv_parsed tp; - uint8_t pdu_type = bgph->pdu_type; - int data_len = msgb_bssgp_len(msg) - sizeof(*bgph); - uint16_t bvci; /* PTP BVCI */ - uint16_t ns_bvci = msgb_bvci(msg); - int rc = 0; - - /* Identifiers from DOWN: NSEI, BVCI (both in msg->cb) */ - - /* UNITDATA BSSGP headers have TLLI in front */ - if (pdu_type != BSSGP_PDUT_UL_UNITDATA && - pdu_type != BSSGP_PDUT_DL_UNITDATA) - rc = bssgp_tlv_parse(&tp, bgph->data, data_len); - - switch (pdu_type) { - case BSSGP_PDUT_UL_UNITDATA: - /* some LLC data from the MS */ - rc = bssgp_rx_ul_ud(msg); - break; - case BSSGP_PDUT_RA_CAPABILITY: - /* BSS requests RA capability or IMSI */ - DEBUGP(DGPRS, "BSSGP RA CAPABILITY UPDATE\n"); - /* FIXME: send RA_CAPA_UPDATE_ACK */ - break; - case BSSGP_PDUT_RADIO_STATUS: - DEBUGP(DGPRS, "BSSGP RADIO STATUS\n"); - /* BSS informs us of some exception */ - /* FIXME: notify GMM */ - break; - case BSSGP_PDUT_SUSPEND: - /* MS wants to suspend */ - rc = bssgp_rx_suspend(msg); - break; - case BSSGP_PDUT_RESUME: - /* MS wants to resume */ - rc = bssgp_rx_resume(msg); - break; - case BSSGP_PDUT_FLUSH_LL: - /* BSS informs MS has moved to one cell to other cell */ - DEBUGP(DGPRS, "BSSGP FLUSH LL\n"); - /* FIXME: notify GMM */ - /* Send FLUSH_LL_ACK */ - break; - case BSSGP_PDUT_LLC_DISCARD: - /* BSS informs that some LLC PDU's have been discarded */ - DEBUGP(DGPRS, "BSSGP LLC DISCARDED\n"); - /* FIXME: notify GMM */ - break; - case BSSGP_PDUT_FLOW_CONTROL_BVC: - /* BSS informs us of available bandwidth in Gb interface */ - rc = bssgp_rx_fc_bvc(msg, &tp); - break; - case BSSGP_PDUT_FLOW_CONTROL_MS: - /* BSS informs us of available bandwidth to one MS */ - DEBUGP(DGPRS, "BSSGP FC MS\n"); - /* FIXME: actually implement flow control */ - /* FIXME: Send FLOW_CONTROL_MS_ACK */ - break; - case BSSGP_PDUT_BVC_BLOCK: - /* BSS tells us that BVC shall be blocked */ - DEBUGP(DGPRS, "BSSGP BVC BLOCK "); - if (!TLVP_PRESENT(&tp, BSSGP_IE_BVCI) || - !TLVP_PRESENT(&tp, BSSGP_IE_CAUSE)) - goto err_mand_ie; - bvci = ntohs(*(uint16_t *)TLVP_VAL(&tp, BSSGP_IE_BVCI)); - DEBUGPC(DGPRS, "BVCI=%u, cause=%s\n", bvci, - bssgp_cause_str(*TLVP_VAL(&tp, BSSGP_IE_CAUSE))); - /* We always acknowledge the BLOCKing */ - rc = bssgp_tx_simple_bvci(BSSGP_PDUT_BVC_BLOCK_ACK, - msgb_nsei(msg), bvci, ns_bvci); - break; - case BSSGP_PDUT_BVC_UNBLOCK: - /* BSS tells us that BVC shall be unblocked */ - DEBUGP(DGPRS, "BSSGP BVC UNBLOCK "); - if (!TLVP_PRESENT(&tp, BSSGP_IE_BVCI)) - goto err_mand_ie; - bvci = ntohs(*(uint16_t *)TLVP_VAL(&tp, BSSGP_IE_BVCI)); - DEBUGPC(DGPRS, "BVCI=%u\n", bvci); - /* We always acknowledge the unBLOCKing */ - rc = bssgp_tx_simple_bvci(BSSGP_PDUT_BVC_UNBLOCK_ACK, - msgb_nsei(msg), bvci, ns_bvci); - break; - case BSSGP_PDUT_BVC_RESET: - /* BSS tells us that BVC init is required */ - DEBUGP(DGPRS, "BSSGP BVC RESET "); - if (!TLVP_PRESENT(&tp, BSSGP_IE_BVCI) || - !TLVP_PRESENT(&tp, BSSGP_IE_CAUSE)) - goto err_mand_ie; - rc = bssgp_rx_bvc_reset(msg, &tp, ns_bvci); - break; - case BSSGP_PDUT_STATUS: - /* Some exception has occurred */ - /* FIXME: notify GMM */ - case BSSGP_PDUT_DOWNLOAD_BSS_PFC: - case BSSGP_PDUT_CREATE_BSS_PFC_ACK: - case BSSGP_PDUT_CREATE_BSS_PFC_NACK: - case BSSGP_PDUT_MODIFY_BSS_PFC: - case BSSGP_PDUT_DELETE_BSS_PFC_ACK: - DEBUGP(DGPRS, "BSSGP PDU type 0x%02x not [yet] implemented\n", - pdu_type); - break; - /* those only exist in the SGSN -> BSS direction */ - case BSSGP_PDUT_DL_UNITDATA: - case BSSGP_PDUT_PAGING_PS: - case BSSGP_PDUT_PAGING_CS: - case BSSGP_PDUT_RA_CAPA_UPDATE_ACK: - case BSSGP_PDUT_SUSPEND_ACK: - case BSSGP_PDUT_SUSPEND_NACK: - case BSSGP_PDUT_RESUME_ACK: - case BSSGP_PDUT_RESUME_NACK: - case BSSGP_PDUT_FLUSH_LL_ACK: - case BSSGP_PDUT_FLOW_CONTROL_BVC_ACK: - case BSSGP_PDUT_FLOW_CONTROL_MS_ACK: - case BSSGP_PDUT_BVC_BLOCK_ACK: - case BSSGP_PDUT_BVC_UNBLOCK_ACK: - case BSSGP_PDUT_SGSN_INVOKE_TRACE: - DEBUGP(DGPRS, "BSSGP PDU type 0x%02x only exists in DL\n", - pdu_type); - rc = -EINVAL; - break; - default: - DEBUGP(DGPRS, "BSSGP PDU type 0x%02x unknown\n", pdu_type); - break; - } - - return rc; -err_mand_ie: - return bssgp_tx_status(BSSGP_CAUSE_MISSING_MAND_IE, NULL, msg); -} - -/* Entry function from upper level (LLC), asking us to transmit a BSSGP PDU - * to a remote MS (identified by TLLI) at a BTS identified by its BVCI and NSEI */ -int gprs_bssgp_tx_dl_ud(struct msgb *msg) -{ - struct bssgp_bts_ctx *bctx; - struct bssgp_ud_hdr *budh; - uint8_t llc_pdu_tlv_hdr_len = 2; - uint8_t *llc_pdu_tlv, *qos_profile; - uint16_t pdu_lifetime = 1000; /* centi-seconds */ - uint8_t qos_profile_default[3] = { 0x00, 0x00, 0x21 }; - uint16_t msg_len = msg->len; - uint16_t bvci = msgb_bvci(msg); - uint16_t nsei = msgb_nsei(msg); - - /* Identifiers from UP: TLLI, BVCI, NSEI (all in msgb->cb) */ - if (bvci < 2) { - LOGP(DGPRS, LOGL_ERROR, "Cannot send DL-UD to BVCI %u\n", - bvci); - return -EINVAL; - } - - bctx = btsctx_by_bvci_nsei(bvci, nsei); - if (!bctx) - bctx = btsctx_alloc(bvci, nsei); - - if (msg->len > TVLV_MAX_ONEBYTE) - llc_pdu_tlv_hdr_len += 1; - - /* prepend the tag and length of the LLC-PDU TLV */ - llc_pdu_tlv = msgb_push(msg, llc_pdu_tlv_hdr_len); - llc_pdu_tlv[0] = BSSGP_IE_LLC_PDU; - if (llc_pdu_tlv_hdr_len > 2) { - llc_pdu_tlv[1] = msg_len >> 8; - llc_pdu_tlv[2] = msg_len & 0xff; - } else { - llc_pdu_tlv[1] = msg_len & 0x3f; - llc_pdu_tlv[1] |= 0x80; - } - - /* FIXME: optional elements */ - - /* prepend the pdu lifetime */ - pdu_lifetime = htons(pdu_lifetime); - msgb_tvlv_push(msg, BSSGP_IE_PDU_LIFETIME, 2, (uint8_t *)&pdu_lifetime); - - /* prepend the QoS profile, TLLI and pdu type */ - budh = (struct bssgp_ud_hdr *) msgb_push(msg, sizeof(*budh)); - memcpy(budh->qos_profile, qos_profile_default, sizeof(qos_profile_default)); - budh->tlli = htonl(msgb_tlli(msg)); - budh->pdu_type = BSSGP_PDUT_DL_UNITDATA; - - /* Identifiers down: BVCI, NSEI (in msgb->cb) */ - - return gprs_ns_sendmsg(bssgp_nsi, msg); -} diff --git a/openbsc/src/gprs_llc.c b/openbsc/src/gprs_llc.c deleted file mode 100644 index 9c75a3d4e..000000000 --- a/openbsc/src/gprs_llc.c +++ /dev/null @@ -1,549 +0,0 @@ -/* GPRS LLC protocol implementation as per 3GPP TS 04.64 */ - -/* (C) 2009-2010 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 - -#include -#include -#include -#include -#include - -/* Section 4.5.2 Logical Link States + Annex C.2 */ -enum gprs_llc_ll_state { - GPRS_LLS_UNASSIGNED = 1, /* No TLLI yet */ - GPRS_LLS_ASSIGNED_ADM = 2, /* TLLI assigned */ - GPRS_LLS_LOCAL_EST = 3, /* Local Establishment */ - GPRS_LLS_REMOTE_EST = 4, /* Remote Establishment */ - GPRS_LLS_ABM = 5, - GPRS_LLS_LOCAL_REL = 6, /* Local Release */ - GPRS_LLS_TIMER_REC = 7, /* Timer Recovery */ -}; - -/* Section 4.7.1: Logical Link Entity: One per DLCI (TLLI + SAPI) */ -struct gprs_llc_lle { - struct llist_head list; - struct timer_list t200; - struct timer_list t201; /* wait for acknowledgement */ - - enum gprs_llc_ll_state state; - - uint32_t tlli; - uint32_t sapi; - - uint8_t v_sent; - uint8_t v_ack; - uint8_t v_recv; - - unsigned int n200; - unsigned int retrans_ctr; - - /* over which BSSGP BTS ctx do we need to transmit */ - uint16_t bvci; - uint16_t nsei; -}; - -static LLIST_HEAD(gprs_llc_lles); -void *llc_tall_ctx; - -/* lookup LLC Entity based on DLCI (TLLI+SAPI tuple) */ -static struct gprs_llc_lle *lle_by_tlli_sapi(uint32_t tlli, uint32_t sapi) -{ - struct gprs_llc_lle *lle; - - llist_for_each_entry(lle, &gprs_llc_lles, list) { - if (lle->tlli == tlli && lle->sapi == sapi) - return lle; - } - return NULL; -} - -static struct gprs_llc_lle *lle_alloc(uint32_t tlli, uint32_t sapi) -{ - struct gprs_llc_lle *lle; - - lle = talloc_zero(llc_tall_ctx, struct gprs_llc_lle); - if (!lle) - return NULL; - - lle->tlli = tlli; - lle->sapi = sapi; - lle->state = GPRS_LLS_UNASSIGNED; - llist_add(&lle->list, &gprs_llc_lles); - - return lle; -} - -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, -}; - -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; - uint8_t *data; - uint16_t data_len; - enum gprs_llc_cmd cmd; -}; - -#define LLC_ALLOC_SIZE 16384 -#define UI_HDR_LEN 3 -#define N202 4 -#define CRC24_LENGTH 3 - -static int gprs_llc_fcs(uint8_t *data, unsigned int len) -{ - uint32_t fcs_calc; - - fcs_calc = crc24_calc(INIT_CRC24, data, len); - fcs_calc = ~fcs_calc; - fcs_calc &= 0xffffff; - - return fcs_calc; -} - -static void t200_expired(void *data) -{ - struct gprs_llc_lle *lle = data; - - /* 8.5.1.3: Expiry of T200 */ - - if (lle->retrans_ctr >= lle->n200) { - /* FIXME: LLGM-STATUS-IND, LL-RELEASE-IND/CNF */ - lle->state = GPRS_LLS_ASSIGNED_ADM; - } - - switch (lle->state) { - case GPRS_LLS_LOCAL_EST: - /* retransmit SABM */ - /* re-start T200 */ - lle->retrans_ctr++; - break; - case GPRS_LLS_LOCAL_REL: - /* retransmit DISC */ - /* re-start T200 */ - lle->retrans_ctr++; - break; - } - -} - -static void t201_expired(void *data) -{ - struct gprs_llc_lle *lle = data; - - if (lle->retrans_ctr < lle->n200) { - /* transmit apropriate supervisory frame (8.6.4.1) */ - /* set timer T201 */ - lle->retrans_ctr++; - } -} - -int gprs_llc_tx_u(struct msgb *msg, uint8_t sapi, int command, - enum gprs_llc_u_cmd u_cmd, int pf_bit) -{ - uint8_t *fcs, *llch; - uint8_t addr, ctrl; - uint32_t fcs_calc; - - /* Identifiers from UP: (TLLI, SAPI) + (BVCI, NSEI) */ - - /* Address Field */ - addr = sapi & 0xf; - if (command) - addr |= 0x40; - - /* 6.3 Figure 8 */ - ctrl = 0xe0 | u_cmd; - if (pf_bit) - ctrl |= 0x10; - - /* prepend LLC UI header */ - llch = msgb_push(msg, 2); - llch[0] = addr; - llch[1] = ctrl; - - /* append FCS to end of frame */ - fcs = msgb_put(msg, 3); - fcs_calc = gprs_llc_fcs(llch, fcs - llch); - fcs[0] = fcs_calc & 0xff; - fcs[1] = (fcs_calc >> 8) & 0xff; - fcs[2] = (fcs_calc >> 16) & 0xff; - - /* Identifiers passed down: (BVCI, NSEI) */ - - return gprs_bssgp_tx_dl_ud(msg); -} - -/* Send XID response to LLE */ -static int gprs_llc_tx_xid(struct gprs_llc_lle *lle, struct msgb *msg) -{ - /* copy identifiers from LLE to ensure lower layers can route */ - msgb_tlli(msg) = lle->tlli; - msgb_bvci(msg) = lle->bvci; - msgb_nsei(msg) = lle->nsei; - - return gprs_llc_tx_u(msg, lle->sapi, 0, GPRS_LLC_U_XID, 1); -} - -/* Transmit a UI frame over the given SAPI */ -int gprs_llc_tx_ui(struct msgb *msg, uint8_t sapi, int command) -{ - struct gprs_llc_lle *lle; - uint8_t *fcs, *llch; - uint8_t addr, ctrl[2]; - uint32_t fcs_calc; - uint16_t nu = 0; - - /* Identifiers from UP: (TLLI, SAPI) + (BVCI, NSEI) */ - - /* look-up or create the LL Entity for this (TLLI, SAPI) tuple */ - lle = lle_by_tlli_sapi(msgb_tlli(msg), sapi); - if (!lle) - lle = lle_alloc(msgb_tlli(msg), sapi); - /* Update LLE's (BVCI, NSEI) tuple */ - lle->bvci = msgb_bvci(msg); - lle->nsei = msgb_nsei(msg); - - /* Address Field */ - addr = sapi & 0xf; - if (command) - addr |= 0x40; - - /* Control Field */ - ctrl[0] = 0xc0; - ctrl[0] |= nu >> 6; - ctrl[1] = (nu << 2) & 0xfc; - ctrl[1] |= 0x01; /* Protected Mode */ - - /* prepend LLC UI header */ - llch = msgb_push(msg, 3); - llch[0] = addr; - llch[1] = ctrl[0]; - llch[2] = ctrl[1]; - - /* append FCS to end of frame */ - fcs = msgb_put(msg, 3); - fcs_calc = gprs_llc_fcs(llch, fcs - llch); - fcs[0] = fcs_calc & 0xff; - fcs[1] = (fcs_calc >> 8) & 0xff; - fcs[2] = (fcs_calc >> 16) & 0xff; - - /* Identifiers passed down: (BVCI, NSEI) */ - - return gprs_bssgp_tx_dl_ud(msg); -} - -static int gprs_llc_hdr_dump(struct gprs_llc_hdr_parsed *gph) -{ - DEBUGP(DGPRS, "LLC SAPI=%u %c %c FCS=0x%06x(%s) ", - gph->sapi, gph->is_cmd ? 'C' : 'R', gph->ack_req ? 'A' : ' ', - gph->fcs, gph->fcs_calc == gph->fcs ? "correct" : "WRONG"); - - if (gph->cmd) - DEBUGPC(DGPRS, "CMD=%u ", gph->cmd); - - if (gph->data) - DEBUGPC(DGPRS, "DATA "); - - DEBUGPC(DGPRS, "\n"); -} -static int gprs_llc_hdr_rx(struct gprs_llc_hdr_parsed *gph, - struct gprs_llc_lle *lle) -{ - switch (gph->cmd) { - case GPRS_LLC_SABM: /* Section 6.4.1.1 */ - lle->v_sent = lle->v_ack = lle->v_recv = 0; - if (lle->state == GPRS_LLS_ASSIGNED_ADM) { - /* start re-establishment (8.7.1) */ - } - lle->state = GPRS_LLS_REMOTE_EST; - /* FIXME: Send UA */ - lle->state = GPRS_LLS_ABM; - /* FIXME: process data */ - break; - case GPRS_LLC_DISC: /* Section 6.4.1.2 */ - /* FIXME: Send UA */ - /* terminate ABM */ - lle->state = GPRS_LLS_ASSIGNED_ADM; - break; - case GPRS_LLC_UA: /* Section 6.4.1.3 */ - if (lle->state == GPRS_LLS_LOCAL_EST) - lle->state = GPRS_LLS_ABM; - break; - case GPRS_LLC_DM: /* Section 6.4.1.4: ABM cannot be performed */ - if (lle->state == GPRS_LLS_LOCAL_EST) - lle->state = GPRS_LLS_ASSIGNED_ADM; - break; - case GPRS_LLC_FRMR: /* Section 6.4.1.5 */ - break; - case GPRS_LLC_XID: /* Section 6.4.1.6 */ - /* FIXME: implement XID negotiation using SNDCP */ - { - struct msgb *resp; - uint8_t *xid; - resp = msgb_alloc_headroom(4096, 1024, "LLC_XID"); - xid = msgb_put(resp, gph->data_len); - memcpy(xid, gph->data, gph->data_len); - gprs_llc_tx_xid(lle, resp); - } - break; - } - - return 0; -} - -/* parse a GPRS LLC header, also check for invalid frames */ -static int gprs_llc_hdr_parse(struct gprs_llc_hdr_parsed *ghp, - const uint8_t *llc_hdr, int len) -{ - uint8_t *ctrl = llc_hdr+1; - int is_sack = 0; - unsigned int crc_length; - uint32_t fcs_calc; - - if (len <= CRC24_LENGTH) - return -EIO; - - 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->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 (crc_length > UI_HDR_LEN + N202) - 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; - } - } - - /* calculate what FCS we expect */ - ghp->fcs_calc = gprs_llc_fcs(llc_hdr, crc_length); - - /* FIXME: parse sack frame */ -} - -/* receive an incoming LLC PDU (BSSGP-UL-UNITDATA-IND, 7.2.4.2) */ -int gprs_llc_rcvmsg(struct msgb *msg, struct tlv_parsed *tv) -{ - struct bssgp_ud_hdr *udh = (struct bssgp_ud_hdr *) msgb_bssgph(msg); - struct gprs_llc_hdr *lh = msgb_llch(msg); - struct gprs_llc_hdr_parsed llhp; - struct gprs_llc_lle *lle; - int rc = 0; - - /* Identifiers from DOWN: NSEI, BVCI, TLLI */ - - rc = gprs_llc_hdr_parse(&llhp, lh, TLVP_LEN(tv, BSSGP_IE_LLC_PDU)); - /* FIXME */ - - gprs_llc_hdr_dump(&llhp); - - /* find the LLC Entity for this TLLI+SAPI tuple */ - lle = lle_by_tlli_sapi(msgb_tlli(msg), llhp.sapi); - /* allocate a new LLE if needed */ - if (!lle) - lle = lle_alloc(msgb_tlli(msg), llhp.sapi); - - /* Update LLE's (BVCI, NSEI) tuple */ - lle->bvci = msgb_bvci(msg); - lle->nsei = msgb_nsei(msg); - - rc = gprs_llc_hdr_rx(&llhp, lle); - /* FIXME */ - - if (llhp.data) { - msgb_gmmh(msg) = llhp.data; - switch (llhp.sapi) { - case GPRS_SAPI_GMM: - rc = gsm0408_gprs_rcvmsg(msg); - break; - case GPRS_SAPI_TOM2: - case GPRS_SAPI_TOM8: - /* FIXME */ - case GPRS_SAPI_SNDCP3: - case GPRS_SAPI_SNDCP5: - case GPRS_SAPI_SNDCP9: - case GPRS_SAPI_SNDCP11: - /* FIXME */ - case GPRS_SAPI_SMS: - /* FIXME */ - default: - LOGP(DGPRS, LOGL_NOTICE, "Unsupported SAPI %u\n", llhp.sapi); - rc = -EINVAL; - break; - } - } - - return rc; -} diff --git a/openbsc/src/gprs_ns.c b/openbsc/src/gprs_ns.c deleted file mode 100644 index 3d9bb8963..000000000 --- a/openbsc/src/gprs_ns.c +++ /dev/null @@ -1,644 +0,0 @@ -/* GPRS Networks Service (NS) messages on the Gb interfacebvci = msgb_bvci(msg); - * 3GPP TS 08.16 version 8.0.1 Release 1999 / ETSI TS 101 299 V8.0.1 (2002-05) */ - -/* (C) 2009-2010 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. - * - */ - -/* Some introduction into NS: NS is used typically on top of frame relay, - * but in the ip.access world it is encapsulated in UDP packets. It serves - * as an intermediate shim betwen BSSGP and the underlying medium. It doesn't - * do much, apart from providing congestion notification and status indication. - * - * Terms: - * NS Network Service - * NSVC NS Virtual Connection - * NSEI NS Entity Identifier - * NSVL NS Virtual Link - * NSVLI NS Virtual Link Identifier - * BVC BSSGP Virtual Connection - * BVCI BSSGP Virtual Connection Identifier - * NSVCG NS Virtual Connection Goup - * Blocked NS-VC cannot be used for user traffic - * Alive Ability of a NS-VC to provide communication - * - * There can be multiple BSSGP virtual connections over one (group of) NSVC's. BSSGP will - * therefore identify the BSSGP virtual connection by a BVCI passed down to NS. - * NS then has to firgure out which NSVC's are responsible for this BVCI. - * Those mappings are administratively configured. - */ - -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#define NS_ALLOC_SIZE 1024 - -static const struct tlv_definition ns_att_tlvdef = { - .def = { - [NS_IE_CAUSE] = { TLV_TYPE_TvLV, 0 }, - [NS_IE_VCI] = { TLV_TYPE_TvLV, 0 }, - [NS_IE_PDU] = { TLV_TYPE_TvLV, 0 }, - [NS_IE_BVCI] = { TLV_TYPE_TvLV, 0 }, - [NS_IE_NSEI] = { TLV_TYPE_TvLV, 0 }, - }, -}; - -/* Lookup struct gprs_nsvc based on NSVCI */ -static struct gprs_nsvc *nsvc_by_nsvci(struct gprs_ns_inst *nsi, - uint16_t nsvci) -{ - struct gprs_nsvc *nsvc; - llist_for_each_entry(nsvc, &nsi->gprs_nsvcs, list) { - if (nsvc->nsvci == nsvci) - return nsvc; - } - return NULL; -} - -/* Lookup struct gprs_nsvc based on NSVCI */ -static struct gprs_nsvc *nsvc_by_nsei(struct gprs_ns_inst *nsi, - uint16_t nsei) -{ - struct gprs_nsvc *nsvc; - llist_for_each_entry(nsvc, &nsi->gprs_nsvcs, list) { - if (nsvc->nsei == nsei) - return nsvc; - } - return NULL; -} - - -/* Lookup struct gprs_nsvc based on remote peer socket addr */ -static struct gprs_nsvc *nsvc_by_rem_addr(struct gprs_ns_inst *nsi, - struct sockaddr_in *sin) -{ - struct gprs_nsvc *nsvc; - llist_for_each_entry(nsvc, &nsi->gprs_nsvcs, list) { - if (!memcmp(&nsvc->ip.bts_addr, sin, sizeof(*sin))) - return nsvc; - } - return NULL; -} - -static void gprs_ns_timer_cb(void *data); - -static struct gprs_nsvc *nsvc_create(struct gprs_ns_inst *nsi, uint16_t nsvci) -{ - struct gprs_nsvc *nsvc; - - nsvc = talloc_zero(nsi, struct gprs_nsvc); - nsvc->nsvci = nsvci; - /* before RESET procedure: BLOCKED and DEAD */ - nsvc->state = NSE_S_BLOCKED; - nsvc->nsi = nsi; - nsvc->timer.cb = gprs_ns_timer_cb; - nsvc->timer.data = nsvc; - - llist_add(&nsvc->list, &nsi->gprs_nsvcs); - - return nsvc; -} - -/* Section 10.3.2, Table 13 */ -static const struct value_string ns_cause_str[] = { - { NS_CAUSE_TRANSIT_FAIL, "Transit network failure" }, - { NS_CAUSE_OM_INTERVENTION, "O&M intervention" }, - { NS_CAUSE_EQUIP_FAIL, "Equipment failure" }, - { NS_CAUSE_NSVC_BLOCKED, "NS-VC blocked" }, - { NS_CAUSE_NSVC_UNKNOWN, "NS-VC unknown" }, - { NS_CAUSE_BVCI_UNKNOWN, "BVCI unknown" }, - { NS_CAUSE_SEM_INCORR_PDU, "Semantically incorrect PDU" }, - { NS_CAUSE_PDU_INCOMP_PSTATE, "PDU not compatible with protocol state" }, - { NS_CAUSE_PROTO_ERR_UNSPEC, "Protocol error, unspecified" }, - { NS_CAUSE_INVAL_ESSENT_IE, "Invalid essential IE" }, - { NS_CAUSE_MISSING_ESSENT_IE, "Missing essential IE" }, - { 0, NULL } -}; - -const char *gprs_ns_cause_str(enum ns_cause cause) -{ - return get_value_string(ns_cause_str, cause); -} - -static int nsip_sendmsg(struct gprs_nsvc *nsvc, struct msgb *msg); - -static int gprs_ns_tx(struct gprs_nsvc *nsvc, struct msgb *msg) -{ - int ret; - - switch (nsvc->nsi->ll) { - case GPRS_NS_LL_UDP: - ret = nsip_sendmsg(nsvc, msg); - break; - default: - LOGP(DGPRS, LOGL_ERROR, "unsupported NS linklayer %u\n", nsvc->nsi->ll); - msgb_free(msg); - ret = -EIO; - break; - } - return ret; -} - -static int gprs_ns_tx_simple(struct gprs_nsvc *nsvc, uint8_t pdu_type) -{ - struct msgb *msg = msgb_alloc(NS_ALLOC_SIZE, "GPRS/NS"); - struct gprs_ns_hdr *nsh; - - if (!msg) - return -ENOMEM; - - nsh = (struct gprs_ns_hdr *) msgb_put(msg, sizeof(*nsh)); - - nsh->pdu_type = pdu_type; - - return gprs_ns_tx(nsvc, msg); -} - -static int gprs_ns_tx_reset(struct gprs_nsvc *nsvc, uint8_t cause) -{ - struct msgb *msg = msgb_alloc(NS_ALLOC_SIZE, "GPRS/NS"); - struct gprs_ns_hdr *nsh; - uint16_t nsvci = htons(nsvc->nsvci); - uint16_t nsei = htons(nsvc->nsei); - - if (!msg) - return -ENOMEM; - - nsh = (struct gprs_ns_hdr *) msgb_put(msg, sizeof(*nsh)); - nsh->pdu_type = NS_PDUT_RESET; - - msgb_tvlv_put(msg, NS_IE_CAUSE, 1, &cause); - msgb_tvlv_put(msg, NS_IE_VCI, 2, (uint8_t *) &nsvci); - msgb_tvlv_put(msg, NS_IE_NSEI, 2, (uint8_t *) &nsei); - - return gprs_ns_tx(nsvc, msg); - -} - -#define NS_ALIVE_RETRIES 10 /* after 3 failed retransmit we declare BTS as dead */ - -static const uint8_t timer_mode_tout[_NSVC_TIMER_NR] = { - [NSVC_TIMER_TNS_RESET] = 60, - [NSVC_TIMER_TNS_ALIVE] = 3, - [NSVC_TIMER_TNS_TEST] = 30, -}; - -static void nsvc_start_timer(struct gprs_nsvc *nsvc, enum nsvc_timer_mode mode) -{ - nsvc->alive_retries = 0; - - if (bsc_timer_pending(&nsvc->timer)) - bsc_del_timer(&nsvc->timer); - - nsvc->timer_mode = mode; - bsc_schedule_timer(&nsvc->timer, timer_mode_tout[mode], 0); -} - -static void gprs_ns_timer_cb(void *data) -{ - struct gprs_nsvc *nsvc = data; - - switch (nsvc->timer_mode) { - case NSVC_TIMER_TNS_ALIVE: - /* Tns-alive case: we expired without response ! */ - nsvc->alive_retries++; - if (nsvc->alive_retries > NS_ALIVE_RETRIES) { - /* mark as dead and blocked */ - nsvc->state = NSE_S_BLOCKED; - DEBUGP(DGPRS, "NSEI=%u Tns-alive expired more then " - "%u times, blocking NS-VC\n", nsvc->nsei, - NS_ALIVE_RETRIES); - /* FIXME: inform higher layers */ - return; - } - nsvc_start_timer(nsvc, NSVC_TIMER_TNS_ALIVE); - break; - case NSVC_TIMER_TNS_TEST: - /* Tns-test case: send NS-ALIVE PDU */ - gprs_ns_tx_simple(nsvc, NS_PDUT_ALIVE); - /* start Tns-alive timer */ - nsvc_start_timer(nsvc, NSVC_TIMER_TNS_ALIVE); - break; - case NSVC_TIMER_TNS_RESET: - /* Chapter 7.3: Re-send the RESET */ - gprs_ns_tx_reset(nsvc, NS_CAUSE_OM_INTERVENTION); - nsvc_start_timer(nsvc, NSVC_TIMER_TNS_RESET); - break; - } -} - -/* Section 9.2.6 */ -static int gprs_ns_tx_reset_ack(struct gprs_nsvc *nsvc) -{ - struct msgb *msg = msgb_alloc(NS_ALLOC_SIZE, "GPRS/NS"); - struct gprs_ns_hdr *nsh; - uint16_t nsvci, nsei; - - if (!msg) - return -ENOMEM; - - nsvci = htons(nsvc->nsvci); - nsei = htons(nsvc->nsei); - - nsh = (struct gprs_ns_hdr *) msgb_put(msg, sizeof(*nsh)); - - nsh->pdu_type = NS_PDUT_RESET_ACK; - - DEBUGP(DGPRS, "NSEI=%u Tx NS RESET ACK (NSVCI=%u)\n", - nsvc->nsei, nsvc->nsvci); - - msgb_tvlv_put(msg, NS_IE_VCI, 2, (uint8_t *)&nsvci); - msgb_tvlv_put(msg, NS_IE_NSEI, 2, (uint8_t *)&nsei); - - return gprs_ns_tx(nsvc, msg); -} - -/* Section 9.2.10: transmit side / NS-UNITDATA-REQUEST primitive */ -int gprs_ns_sendmsg(struct gprs_ns_inst *nsi, struct msgb *msg) -{ - struct gprs_nsvc *nsvc; - struct gprs_ns_hdr *nsh; - uint16_t bvci = msgb_bvci(msg); - - nsvc = nsvc_by_nsei(nsi, msgb_nsei(msg)); - if (!nsvc) { - LOGP(DGPRS, LOGL_ERROR, "Unable to resolve NSEI %u " - "to NS-VC!\n", msgb_nsei(msg)); - return -EINVAL; - } - - if (!(nsvc->state & NSE_S_ALIVE)) { - LOGP(DGPRS, LOGL_ERROR, "NSEI=%u is not alive, cannot send\n", - nsvc->nsei); - return -EBUSY; - } - if (nsvc->state & NSE_S_BLOCKED) { - LOGP(DGPRS, LOGL_ERROR, "NSEI=%u is blocked, cannot send\n", - nsvc->nsei); - return -EBUSY; - } - - nsh = (struct gprs_ns_hdr *) msgb_push(msg, sizeof(*nsh) + 3); - if (!nsh) { - LOGP(DGPRS, LOGL_ERROR, "Not enough headroom for NS header\n"); - return -EIO; - } - - nsh->pdu_type = NS_PDUT_UNITDATA; - /* spare octet in data[0] */ - nsh->data[1] = bvci >> 8; - nsh->data[2] = bvci & 0xff; - - return gprs_ns_tx(nsvc, msg); -} - -/* Section 9.2.10: receive side */ -static int gprs_ns_rx_unitdata(struct gprs_nsvc *nsvc, struct msgb *msg) -{ - struct gprs_ns_hdr *nsh = (struct gprs_ns_hdr *)msg->l2h; - uint16_t bvci; - - /* spare octet in data[0] */ - bvci = nsh->data[1] << 8 | nsh->data[2]; - msgb_bssgph(msg) = &nsh->data[3]; - msgb_bvci(msg) = bvci; - - /* call upper layer (BSSGP) */ - return nsvc->nsi->cb(GPRS_NS_EVT_UNIT_DATA, nsvc, msg, bvci); -} - -/* Section 9.2.7 */ -static int gprs_ns_rx_status(struct gprs_nsvc *nsvc, struct msgb *msg) -{ - struct gprs_ns_hdr *nsh = (struct gprs_ns_hdr *) msg->l2h; - struct tlv_parsed tp; - uint8_t cause; - int rc; - - DEBUGP(DGPRS, "NSEI=%u NS STATUS ", nsvc->nsei); - - rc = tlv_parse(&tp, &ns_att_tlvdef, nsh->data, msgb_l2len(msg), 0, 0); - - if (!TLVP_PRESENT(&tp, NS_IE_CAUSE)) { - DEBUGPC(DGPRS, "missing cause IE\n"); - return -EINVAL; - } - - cause = *TLVP_VAL(&tp, NS_IE_CAUSE); - DEBUGPC(DGPRS, "cause=%s\n", gprs_ns_cause_str(cause)); - - return 0; -} - -/* Section 7.3 */ -static int gprs_ns_rx_reset(struct gprs_nsvc *nsvc, struct msgb *msg) -{ - struct gprs_ns_hdr *nsh = (struct gprs_ns_hdr *) msg->l2h; - struct tlv_parsed tp; - uint8_t *cause; - uint16_t *nsvci, *nsei; - int rc; - - rc = tlv_parse(&tp, &ns_att_tlvdef, nsh->data, msgb_l2len(msg), 0, 0); - - if (!TLVP_PRESENT(&tp, NS_IE_CAUSE) || - !TLVP_PRESENT(&tp, NS_IE_VCI) || - !TLVP_PRESENT(&tp, NS_IE_NSEI)) { - /* FIXME: respond with NS_CAUSE_MISSING_ESSENT_IE */ - LOGP(DGPRS, LOGL_ERROR, "NS RESET Missing mandatory IE\n"); - return -EINVAL; - } - - cause = (uint8_t *) TLVP_VAL(&tp, NS_IE_CAUSE); - nsvci = (uint16_t *) TLVP_VAL(&tp, NS_IE_VCI); - nsei = (uint16_t *) TLVP_VAL(&tp, NS_IE_NSEI); - - DEBUGP(DGPRS, "NSEI=%u NS RESET (NSVCI=%u, cause=%s)\n", - nsvc->nsvci, nsvc->nsei, gprs_ns_cause_str(*cause)); - - nsvc->state = NSE_S_BLOCKED | NSE_S_ALIVE; - nsvc->nsei = ntohs(*nsei); - nsvc->nsvci = ntohs(*nsvci); - - /* mark the NS-VC as blocked and alive */ - /* start the test procedure */ - nsvc_start_timer(nsvc, NSVC_TIMER_TNS_ALIVE); - - return gprs_ns_tx_reset_ack(nsvc); -} - -/* main entry point, here incoming NS frames enter */ -int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, - struct sockaddr_in *saddr) -{ - struct gprs_ns_hdr *nsh = (struct gprs_ns_hdr *) msg->l2h; - struct gprs_nsvc *nsvc; - int rc = 0; - - /* look up the NSVC based on source address */ - nsvc = nsvc_by_rem_addr(nsi, saddr); - if (!nsvc) { - /* Only the RESET procedure creates a new NSVC */ - if (nsh->pdu_type != NS_PDUT_RESET) { - LOGP(DGPRS, LOGL_INFO, "Ignoring NS PDU type 0x%0x " - "from %s for non-existing NS-VC\n", - nsh->pdu_type, inet_ntoa(saddr->sin_addr)); - //gprs_ns_tx_reset(nsvc, NS_CAUSE_NSVC_UNKNOWN); - return -EIO; - } - LOGP(DGPRS, LOGL_INFO, "Creating NS-VC for BSS at %s:%u\n", - inet_ntoa(saddr->sin_addr), ntohs(saddr->sin_port)); - nsvc = nsvc_create(nsi, 0xffff); - nsvc->ip.bts_addr = *saddr; - } else - msgb_nsei(msg) = nsvc->nsei; - - switch (nsh->pdu_type) { - case NS_PDUT_ALIVE: - /* remote end inquires whether we're still alive, - * we need to respond with ALIVE_ACK */ - rc = gprs_ns_tx_simple(nsvc, NS_PDUT_ALIVE_ACK); - break; - case NS_PDUT_ALIVE_ACK: - /* stop Tns-alive */ - bsc_del_timer(&nsvc->timer); - /* start Tns-test */ - nsvc_start_timer(nsvc, NSVC_TIMER_TNS_TEST); - if (nsvc->remote_end_is_sgsn) { - /* FIXME: this should be one level higher */ - if (nsvc->state & NSE_S_BLOCKED) - rc = gprs_ns_tx_simple(nsvc, NS_PDUT_UNBLOCK); - } - break; - case NS_PDUT_UNITDATA: - /* actual user data */ - rc = gprs_ns_rx_unitdata(nsvc, msg); - break; - case NS_PDUT_STATUS: - rc = gprs_ns_rx_status(nsvc, msg); - break; - case NS_PDUT_RESET: - rc = gprs_ns_rx_reset(nsvc, msg); - break; - case NS_PDUT_RESET_ACK: - DEBUGP(DGPRS, "NSEI=%u Rx NS RESET ACK\n", nsvc->nsei); - /* mark remote NS-VC as blocked + active */ - nsvc->remote_state = NSE_S_BLOCKED | NSE_S_ALIVE; - if (nsvc->remote_end_is_sgsn) { - /* stop RESET timer */ - bsc_del_timer(&nsvc->timer); - /* send ALIVE PDU */ - rc = gprs_ns_tx_simple(nsvc, NS_PDUT_ALIVE); - nsvc_start_timer(nsvc, NSVC_TIMER_TNS_ALIVE); - /* mark local state as BLOCKED + ALIVE */ - nsvc->state = NSE_S_BLOCKED | NSE_S_ALIVE; - } - break; - case NS_PDUT_UNBLOCK: - /* Section 7.2: unblocking procedure */ - DEBUGP(DGPRS, "NSEI=%u Rx NS UNBLOCK\n", nsvc->nsei); - nsvc->state &= ~NSE_S_BLOCKED; - rc = gprs_ns_tx_simple(nsvc, NS_PDUT_UNBLOCK_ACK); - break; - case NS_PDUT_UNBLOCK_ACK: - DEBUGP(DGPRS, "NSEI=%u Rx NS UNBLOCK ACK\n", nsvc->nsei); - /* mark remote NS-VC as unblocked + active */ - nsvc->remote_state = NSE_S_ALIVE; - if (nsvc->remote_end_is_sgsn) - nsvc->state = NSE_S_ALIVE; - break; - case NS_PDUT_BLOCK: - DEBUGP(DGPRS, "NSEI=%u Rx NS BLOCK\n", nsvc->nsei); - nsvc->state |= NSE_S_BLOCKED; - rc = gprs_ns_tx_simple(nsvc, NS_PDUT_UNBLOCK_ACK); - break; - case NS_PDUT_BLOCK_ACK: - DEBUGP(DGPRS, "NSEI=%u Rx NS BLOCK ACK\n", nsvc->nsei); - /* mark remote NS-VC as blocked + active */ - nsvc->remote_state = NSE_S_BLOCKED | NSE_S_ALIVE; - break; - default: - DEBUGP(DGPRS, "NSEI=%u Rx Unknown NS PDU type 0x%02x\n", - nsvc->nsei, nsh->pdu_type); - rc = -EINVAL; - break; - } - return rc; -} - -struct gprs_ns_inst *gprs_ns_instantiate(gprs_ns_cb_t *cb) -{ - struct gprs_ns_inst *nsi = talloc_zero(tall_bsc_ctx, struct gprs_ns_inst); - - nsi->cb = cb; - INIT_LLIST_HEAD(&nsi->gprs_nsvcs); - - return nsi; -} - -void gprs_ns_destroy(struct gprs_ns_inst *nsi) -{ - /* FIXME: clear all timers */ - - /* recursively free the NSI and all its NSVCs */ - talloc_free(nsi); -} - - -/* NS-over-IP code, according to 3GPP TS 48.016 Chapter 6.2 - * We don't support Size Procedure, Configuration Procedure, ChangeWeight Procedure */ - -/* Read a single NS-over-IP message */ -static struct msgb *read_nsip_msg(struct bsc_fd *bfd, int *error, - struct sockaddr_in *saddr) -{ - struct msgb *msg = msgb_alloc(NS_ALLOC_SIZE, "Abis/IP/GPRS-NS"); - int ret = 0; - socklen_t saddr_len = sizeof(*saddr); - - if (!msg) { - *error = -ENOMEM; - return NULL; - } - - ret = recvfrom(bfd->fd, msg->data, NS_ALLOC_SIZE, 0, - (struct sockaddr *)saddr, &saddr_len); - if (ret < 0) { - LOGP(DGPRS, LOGL_ERROR, "recv error %s during NSIP recv\n", - strerror(errno)); - msgb_free(msg); - *error = ret; - return NULL; - } else if (ret == 0) { - msgb_free(msg); - *error = ret; - return NULL; - } - - msg->l2h = msg->data; - msgb_put(msg, ret); - - return msg; -} - -static int handle_nsip_read(struct bsc_fd *bfd) -{ - int error; - struct sockaddr_in saddr; - struct gprs_ns_inst *nsi = bfd->data; - struct msgb *msg = read_nsip_msg(bfd, &error, &saddr); - - if (!msg) - return error; - - return gprs_ns_rcvmsg(nsi, msg, &saddr); -} - -static int handle_nsip_write(struct bsc_fd *bfd) -{ - /* FIXME: actually send the data here instead of nsip_sendmsg() */ - return -EIO; -} - -int nsip_sendmsg(struct gprs_nsvc *nsvc, struct msgb *msg) -{ - int rc; - struct gprs_ns_inst *nsi = nsvc->nsi; - struct sockaddr_in *daddr = &nsvc->ip.bts_addr; - - rc = sendto(nsi->nsip.fd.fd, msg->data, msg->len, 0, - (struct sockaddr *)daddr, sizeof(*daddr)); - - talloc_free(msg); - - return rc; -} - -/* UDP Port 23000 carries the LLC-in-BSSGP-in-NS protocol stack */ -static int nsip_fd_cb(struct bsc_fd *bfd, unsigned int what) -{ - int rc = 0; - - if (what & BSC_FD_READ) - rc = handle_nsip_read(bfd); - if (what & BSC_FD_WRITE) - rc = handle_nsip_write(bfd); - - return rc; -} - - -/* FIXME: this is currently in input/ipaccess.c */ -extern int make_sock(struct bsc_fd *bfd, int proto, uint16_t port, - int (*cb)(struct bsc_fd *fd, unsigned int what)); - -/* Listen for incoming GPRS packets */ -int nsip_listen(struct gprs_ns_inst *nsi, uint16_t udp_port) -{ - int ret; - - ret = make_sock(&nsi->nsip.fd, IPPROTO_UDP, udp_port, nsip_fd_cb); - if (ret < 0) - return ret; - - nsi->ll = GPRS_NS_LL_UDP; - nsi->nsip.fd.data = nsi; - - return ret; -} - -/* Establish a connection (from the BSS) to the SGSN */ -struct gprs_nsvc *nsip_connect(struct gprs_ns_inst *nsi, - struct sockaddr_in *dest, uint16_t nsei, - uint16_t nsvci) -{ - struct gprs_nsvc *nsvc; - - nsvc = nsvc_by_rem_addr(nsi, dest); - if (!nsvc) { - nsvc = nsvc_create(nsi, nsvci); - nsvc->ip.bts_addr = *dest; - } - nsvc->nsei = nsei; - nsvc->nsvci = nsvci; - nsvc->remote_end_is_sgsn = 1; - - /* Initiate a RESET procedure */ - if (gprs_ns_tx_reset(nsvc, NS_CAUSE_OM_INTERVENTION) < 0) { - LOGP(DGPRS, LOGL_ERROR, "NSEI=%u, error resetting NS-VC\n", - nsei); - } - /* run a timer and re-transmit the reset request? */ - nsvc_start_timer(nsvc, NSVC_TIMER_TNS_RESET); - - return nsvc; -} diff --git a/openbsc/src/gprs_sgsn.c b/openbsc/src/gprs_sgsn.c deleted file mode 100644 index ba4671955..000000000 --- a/openbsc/src/gprs_sgsn.c +++ /dev/null @@ -1,96 +0,0 @@ -/* GPRS SGSN functionality */ - -/* (C) 2009 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 -#include -#include -#include - -static LLIST_HEAD(sgsn_mm_ctxts); - -static int ra_id_equals(const struct gprs_ra_id *id1, - const struct gprs_ra_id *id2) -{ - return (id1->mcc == id2->mcc && id1->mnc == id2->mnc && - id1->lac == id2->lac && id1->rac == id2->rac); -} - -/* look-up a SGSN MM context based on TLLI + RAI */ -struct sgsn_mm_ctx *sgsn_mm_ctx_by_tlli(uint32_t tlli, - const struct gprs_ra_id *raid) -{ - struct sgsn_mm_ctx *ctx; - - llist_for_each_entry(ctx, &sgsn_mm_ctxts, list) { - if (tlli == ctx->tlli && - ra_id_equals(raid, &ctx->ra)) - return ctx; - } - return NULL; -} - -struct sgsn_mm_ctx *sgsn_mm_ctx_by_ptmsi(uint32_t p_tmsi) -{ - struct sgsn_mm_ctx *ctx; - - llist_for_each_entry(ctx, &sgsn_mm_ctxts, list) { - if (p_tmsi == ctx->p_tmsi) - return ctx; - } - return NULL; -} - -struct sgsn_mm_ctx *sgsn_mm_ctx_by_imsi(const char *imsi) -{ - struct sgsn_mm_ctx *ctx; - - llist_for_each_entry(ctx, &sgsn_mm_ctxts, list) { - if (!strcmp(imsi, ctx->imsi)) - return ctx; - } - return NULL; - -} - -/* Allocate a new SGSN MM context */ -struct sgsn_mm_ctx *sgsn_mm_ctx_alloc(uint32_t tlli, - const struct gprs_ra_id *raid) -{ - struct sgsn_mm_ctx *ctx = talloc_zero(NULL, struct sgsn_mm_ctx); - - if (!ctx) - return NULL; - - memcpy(&ctx->ra, raid, sizeof(ctx->ra)); - ctx->tlli = tlli; - ctx->mm_state = GMM_DEREGISTERED; - - llist_add(&ctx->list, &sgsn_mm_ctxts); - - return ctx; -} diff --git a/openbsc/src/gprs_sndcp.c b/openbsc/src/gprs_sndcp.c deleted file mode 100644 index 0d1a39004..000000000 --- a/openbsc/src/gprs_sndcp.c +++ /dev/null @@ -1,70 +0,0 @@ -/* GPRS SNDCP protocol implementation as per 3GPP TS 04.65 */ - -/* (C) 2010 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 - -#include -#include -#include -#include - -/* Chapter 7.2: SN-PDU Formats */ -struct sndcp_common_hdr { - /* octet 1 */ - uint8_t nsapi:4; - uint8_t more:1; - uint8_t type:1; - uint8_t first:1; - uint8_t spare:1; - /* octet 2 */ - uint8_t pcomp; - uint8_t dcomp; -}; - -struct sndcp_udata_hdr { - /* octet 3 */ - uint8_t npdu_high:4; - uint8_t seg_nr:4; - /* octet 4 */ - uint8_t npdu_low; -}; - -/* Entry point for the LL-UNITDATA.indication */ -int sndcp_unitdata_ind(struct msgb *msg, uint8_t sapi, uint8_t *hdr, uint8_t len) -{ - struct sndcp_udata_hdr *suh; - uint16_t npdu; - - if (suh->type == 0) { - LOGP(DGPRS, LOGL_ERROR, "SN-DATA PDU at unitdata_ind() function\n"); - return -EINVAL; - } - - npdu = (suh->npdu_high << 8) | suh->npdu_low; -} - diff --git a/openbsc/src/gsm_04_08_gprs.c b/openbsc/src/gsm_04_08_gprs.c deleted file mode 100644 index 4a42113f0..000000000 --- a/openbsc/src/gsm_04_08_gprs.c +++ /dev/null @@ -1,762 +0,0 @@ -/* GSM Mobile Radio Interface Layer 3 messages on the A-bis interface - * 3GPP TS 04.08 version 7.21.0 Release 1998 / ETSI TS 100 940 V7.21.0 */ - -/* (C) 2009-2010 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 -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* 10.5.5.14 GPRS MM Cause / Table 10.5.147 */ -struct value_string gmm_cause_names[] = { - /* FIXME */ - { GMM_CAUSE_SEM_INCORR_MSG, "Semantically incorrect message" }, - { GMM_CAUSE_INV_MAND_INFO, "Invalid mandatory information" }, - { GMM_CAUSE_MSGT_NOTEXIST_NOTIMPL, - "Message type non-existant or not implemented" }, - { GMM_CAUSE_MSGT_INCOMP_P_STATE, - "Message type not compatible with protocol state" }, - { GMM_CAUSE_IE_NOTEXIST_NOTIMPL, - "Information element non-existent or not implemented" }, - { GMM_CAUSE_COND_IE_ERR, "Conditional IE error" }, - { GMM_CAUSE_MSG_INCOMP_P_STATE, - "Message not compatible with protocol state " }, - { GMM_CAUSE_PROTO_ERR_UNSPEC, "Protocol error, unspecified" }, - { 0, NULL } -}; - -/* 10.5.6.6 SM Cause / Table 10.5.157 */ -struct value_string gsm_cause_names[] = { - { GSM_CAUSE_INSUFF_RSRC, "Insufficient resources" }, - { GSM_CAUSE_MISSING_APN, "Missing or unknown APN" }, - { GSM_CAUSE_UNKNOWN_PDP, "Unknown PDP address or PDP type" }, - { GSM_CAUSE_AUTH_FAILED, "User Authentication failed" }, - { GSM_CAUSE_ACT_REJ_GGSN, "Activation rejected by GGSN" }, - { GSM_CAUSE_ACT_REJ_UNSPEC, "Activation rejected, unspecified" }, - { GSM_CAUSE_SERV_OPT_NOTSUPP, "Service option not supported" }, - { GSM_CAUSE_REQ_SERV_OPT_NOTSUB, - "Requested service option not subscribed" }, - { GSM_CAUSE_SERV_OPT_TEMP_OOO, - "Service option temporarily out of order" }, - { GSM_CAUSE_NSAPI_IN_USE, "NSAPI already used" }, - { GSM_CAUSE_DEACT_REGULAR, "Regular deactivation" }, - { GSM_CAUSE_QOS_NOT_ACCEPTED, "QoS not accepted" }, - { GSM_CAUSE_NET_FAIL, "Network Failure" }, - { GSM_CAUSE_REACT_RQD, "Reactivation required" }, - { GSM_CAUSE_FEATURE_NOTSUPP, "Feature not supported " }, - { GSM_CAUSE_INVALID_TRANS_ID, "Invalid transaction identifier" }, - { GSM_CAUSE_SEM_INCORR_MSG, "Semantically incorrect message" }, - { GSM_CAUSE_INV_MAND_INFO, "Invalid mandatory information" }, - { GSM_CAUSE_MSGT_NOTEXIST_NOTIMPL, - "Message type non-existant or not implemented" }, - { GSM_CAUSE_MSGT_INCOMP_P_STATE, - "Message type not compatible with protocol state" }, - { GSM_CAUSE_IE_NOTEXIST_NOTIMPL, - "Information element non-existent or not implemented" }, - { GSM_CAUSE_COND_IE_ERR, "Conditional IE error" }, - { GSM_CAUSE_MSG_INCOMP_P_STATE, - "Message not compatible with protocol state " }, - { GSM_CAUSE_PROTO_ERR_UNSPEC, "Protocol error, unspecified" }, - { 0, NULL } -}; - -static const char *att_name(uint8_t type) -{ - switch (type) { - case GPRS_ATT_T_ATTACH: - return "GPRS attach"; - case GPRS_ATT_T_ATT_WHILE_IMSI: - return "GPRS attach while IMSI attached"; - case GPRS_ATT_T_COMBINED: - return "Combined GPRS/IMSI attach"; - default: - return "unknown"; - } -} - -static const char *upd_name(uint8_t type) -{ - switch (type) { - case GPRS_UPD_T_RA: - return "RA updating"; - case GPRS_UPD_T_RA_LA: - return "combined RA/LA updating"; - case GPRS_UPD_T_RA_LA_IMSI_ATT: - return "combined RA/LA updating + IMSI attach"; - case GPRS_UPD_T_PERIODIC: - return "periodic updating"; - } - return "unknown"; -} - -/* Send a message through the underlying layer */ -static int gsm48_gmm_sendmsg(struct msgb *msg, int command) -{ - /* caller needs to provide TLLI, BVCI and NSEI */ - return gprs_llc_tx_ui(msg, GPRS_SAPI_GMM, command); -} - -/* copy identifiers from old message to new message, this - * is required so lower layers can route it correctly */ -static void gmm_copy_id(struct msgb *msg, const struct msgb *old) -{ - msgb_tlli(msg) = msgb_tlli(old); - msgb_bvci(msg) = msgb_bvci(old); - msgb_nsei(msg) = msgb_nsei(old); -} - -static struct gsm48_qos default_qos = { - .delay_class = 4, /* best effort */ - .reliab_class = GSM48_QOS_RC_LLC_UN_RLC_ACK_DATA_PROT, - .peak_tput = GSM48_QOS_PEAK_TPUT_32000bps, - .preced_class = GSM48_QOS_PC_NORMAL, - .mean_tput = GSM48_QOS_MEAN_TPUT_BEST_EFFORT, - .traf_class = GSM48_QOS_TC_INTERACTIVE, - .deliv_order = GSM48_QOS_DO_UNORDERED, - .deliv_err_sdu = GSM48_QOS_ERRSDU_YES, - .max_sdu_size = GSM48_QOS_MAXSDU_1520, - .max_bitrate_up = GSM48_QOS_MBRATE_63k, - .max_bitrate_down = GSM48_QOS_MBRATE_63k, - .resid_ber = GSM48_QOS_RBER_5e_2, - .sdu_err_ratio = GSM48_QOS_SERR_1e_2, - .handling_prio = 3, - .xfer_delay = 0x10, /* 200ms */ - .guar_bitrate_up = GSM48_QOS_MBRATE_0k, - .guar_bitrate_down = GSM48_QOS_MBRATE_0k, - .sig_ind = 0, /* not optimised for signalling */ - .max_bitrate_down_ext = 0, /* use octet 9 */ - .guar_bitrate_down_ext = 0, /* use octet 13 */ -}; - -/* Chapter 9.4.2: Attach accept */ -static int gsm48_tx_gmm_att_ack(struct msgb *old_msg) -{ - struct msgb *msg = gsm48_msgb_alloc(); - struct gsm48_hdr *gh; - struct gsm48_attach_ack *aa; - struct gprs_ra_id ra_id; - - DEBUGP(DMM, "<- GPRS ATTACH ACCEPT\n"); - - gmm_copy_id(msg, old_msg); - - gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh)); - gh->proto_discr = GSM48_PDISC_MM_GPRS; - gh->msg_type = GSM48_MT_GMM_ATTACH_ACK; - - aa = (struct gsm48_attach_ack *) msgb_put(msg, sizeof(*aa)); - aa->force_stby = 0; /* not indicated */ - aa->att_result = 1; /* GPRS only */ - aa->ra_upd_timer = GPRS_TMR_MINUTE | 10; - aa->radio_prio = 4; /* lowest */ - bssgp_parse_cell_id(&ra_id, msgb_bcid(old_msg)); - gsm48_construct_ra(aa->ra_id.digits, &ra_id); - - /* Option: P-TMSI signature, allocated P-TMSI, MS ID, ... */ - return gsm48_gmm_sendmsg(msg, 0); -} - -/* Chapter 9.4.5: Attach reject */ -static int gsm48_tx_gmm_att_rej(struct msgb *old_msg, uint8_t gmm_cause) -{ - struct msgb *msg = gsm48_msgb_alloc(); - struct gsm48_hdr *gh; - - DEBUGP(DMM, "<- GPRS ATTACH REJECT\n"); - - gmm_copy_id(msg, old_msg); - - gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1); - gh->proto_discr = GSM48_PDISC_MM_GPRS; - gh->msg_type = GSM48_MT_GMM_ATTACH_REJ; - gh->data[0] = gmm_cause; - - return gsm48_gmm_sendmsg(msg, 0); -} - -/* Transmit Chapter 9.4.12 Identity Request */ -static int gsm48_tx_gmm_id_req(struct msgb *old_msg, uint8_t id_type) -{ - struct msgb *msg = gsm48_msgb_alloc(); - struct gsm48_hdr *gh; - - DEBUGP(DMM, "-> GPRS IDENTITY REQUEST: mi_type=%02x\n", id_type); - - gmm_copy_id(msg, old_msg); - - gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1); - gh->proto_discr = GSM48_PDISC_MM_GPRS; - gh->msg_type = GSM48_MT_GMM_ID_REQ; - /* 10.5.5.9 ID type 2 + identity type and 10.5.5.7 'force to standby' IE */ - gh->data[0] = id_type & 0xf; - - return gsm48_gmm_sendmsg(msg, 0); -} - -/* Check if we can already authorize a subscriber */ -static int gsm48_gmm_authorize(struct sgsn_mm_ctx *ctx, struct msgb *msg) -{ - if (strlen(ctx->imei) && strlen(ctx->imsi)) { - ctx->mm_state = GMM_REGISTERED_NORMAL; - return gsm48_tx_gmm_att_ack(msg); - } - if (!strlen(ctx->imei)) - return gsm48_tx_gmm_id_req(msg, GSM_MI_TYPE_IMEI); - - if (!strlen(ctx->imsi)) - return gsm48_tx_gmm_id_req(msg, GSM_MI_TYPE_IMSI); - - return 0; -} - -/* Parse Chapter 9.4.13 Identity Response */ -static int gsm48_rx_gmm_id_resp(struct msgb *msg) -{ - struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg); - uint8_t mi_type = gh->data[1] & GSM_MI_TYPE_MASK; - char mi_string[GSM48_MI_SIZE]; - struct gprs_ra_id ra_id; - struct sgsn_mm_ctx *ctx; - - gsm48_mi_to_string(mi_string, sizeof(mi_string), &gh->data[1], gh->data[0]); - DEBUGP(DMM, "GMM IDENTITY RESPONSE: mi_type=0x%02x MI(%s) ", - mi_type, mi_string); - - bssgp_parse_cell_id(&ra_id, msgb_bcid(msg)); - ctx = sgsn_mm_ctx_by_tlli(msgb_tlli(msg), &ra_id); - if (!ctx) { - DEBUGP(DMM, "from unknown TLLI 0x%08x?!?\n", msgb_tlli(msg)); - return -EINVAL; - } - - switch (mi_type) { - case GSM_MI_TYPE_IMSI: - /* we already have a mm context with current TLLI, but no - * P-TMSI / IMSI yet. What we now need to do is to fill - * this initial context with data from the HLR */ - strncpy(ctx->imsi, mi_string, sizeof(ctx->imei)); - break; - case GSM_MI_TYPE_IMEI: - strncpy(ctx->imei, mi_string, sizeof(ctx->imei)); - break; - case GSM_MI_TYPE_IMEISV: - break; - } - - DEBUGPC(DMM, "\n"); - /* Check if we can let the mobile station enter */ - return gsm48_gmm_authorize(ctx, msg); -} - -static void attach_rej_cb(void *data) -{ - struct sgsn_mm_ctx *ctx = data; - - /* FIXME: determine through which BTS/TRX to send this */ - //gsm48_tx_gmm_att_rej(ctx->tlli, GMM_CAUSE_MS_ID_NOT_DERIVED); - ctx->mm_state = GMM_DEREGISTERED; - /* FIXME: release the context */ -} - -static void schedule_reject(struct sgsn_mm_ctx *ctx) -{ - ctx->T = 3370; - ctx->timer.cb = attach_rej_cb; - ctx->timer.data = ctx; - bsc_schedule_timer(&ctx->timer, 6, 0); -} - -/* Section 9.4.1 Attach request */ -static int gsm48_rx_gmm_att_req(struct msgb *msg) -{ - struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg); - uint8_t *cur = gh->data, *msnc, *mi, *old_ra_info; - uint8_t msnc_len, att_type, mi_len, mi_type; - uint16_t drx_par; - uint32_t tmsi; - char mi_string[GSM48_MI_SIZE]; - struct gprs_ra_id ra_id; - uint16_t cid; - struct sgsn_mm_ctx *ctx; - - DEBUGP(DMM, "GMM ATTACH REQUEST "); - - /* As per TS 04.08 Chapter 4.7.1.4, the attach request arrives either - * with a foreign TLLI (P-TMSI that was allocated to the MS before), - * or with random TLLI. */ - - cid = bssgp_parse_cell_id(&ra_id, msgb_bcid(msg)); - - /* MS network capability 10.5.5.12 */ - msnc_len = *cur++; - msnc = cur; - if (msnc_len > 2) - goto err_inval; - cur += msnc_len; - - /* aTTACH Type 10.5.5.2 */ - att_type = *cur++ & 0x0f; - - /* DRX parameter 10.5.5.6 */ - drx_par = *cur++; - drx_par |= *cur++ << 8; - - /* Mobile Identity (P-TMSI or IMSI) 10.5.1.4 */ - mi_len = *cur++; - mi = cur; - if (mi_len > 8) - goto err_inval; - mi_type = *mi & GSM_MI_TYPE_MASK; - cur += mi_len; - - gsm48_mi_to_string(mi_string, sizeof(mi_string), mi, mi_len); - - DEBUGPC(DMM, "MI(%s) type=\"%s\" ", mi_string, att_name(att_type)); - - /* Old routing area identification 10.5.5.15 */ - old_ra_info = cur; - cur += 6; - - /* MS Radio Access Capability 10.5.5.12a */ - - /* Optional: Old P-TMSI Signature, Requested READY timer, TMSI Status */ - - switch (mi_type) { - case GSM_MI_TYPE_IMSI: - /* Try to find MM context based on IMSI */ - ctx = sgsn_mm_ctx_by_imsi(mi_string); - if (!ctx) { -#if 0 - return gsm48_tx_gmm_att_rej(msg, GMM_CAUSE_IMSI_UNKNOWN); -#else - /* As a temorary hack, we simply assume that the IMSI exists */ - ctx = sgsn_mm_ctx_alloc(0, &ra_id); - if (!ctx) - return gsm48_tx_gmm_att_rej(msg, GMM_CAUSE_NET_FAIL); - strncpy(ctx->imsi, mi_string, sizeof(ctx->imsi)); -#endif - } - /* FIXME: Start some timer */ - ctx->mm_state = GMM_COMMON_PROC_INIT; - ctx->tlli = msgb_tlli(msg); - break; - case GSM_MI_TYPE_TMSI: - tmsi = strtoul(mi_string, NULL, 10); - /* Try to find MM context based on P-TMSI */ - ctx = sgsn_mm_ctx_by_ptmsi(tmsi); - if (!ctx) { - ctx = sgsn_mm_ctx_alloc(msgb_tlli(msg), &ra_id); - /* FIXME: Start some timer */ - ctx->mm_state = GMM_COMMON_PROC_INIT; - ctx->tlli = msgb_tlli(msg); - } - break; - default: - return 0; - } - /* Update MM Context with currient RA and Cell ID */ - ctx->ra = ra_id; - ctx->cell_id = cid; - - /* FIXME: allocate a new P-TMSI (+ P-TMSI signature) */ - /* FIXME: update the TLLI with the new local TLLI based on the P-TMSI */ - - DEBUGPC(DMM, "\n"); - - return ctx ? gsm48_gmm_authorize(ctx, msg) : 0; - -err_inval: - DEBUGPC(DMM, "\n"); - return gsm48_tx_gmm_att_rej(msg, GMM_CAUSE_SEM_INCORR_MSG); -} - -/* Chapter 9.4.15: Routing area update accept */ -static int gsm48_tx_gmm_ra_upd_ack(struct msgb *old_msg) -{ - struct msgb *msg = gsm48_msgb_alloc(); - struct gsm48_hdr *gh; - struct gsm48_ra_upd_ack *rua; - struct gprs_ra_id ra_id; - - DEBUGP(DMM, "<- ROUTING AREA UPDATE ACCEPT\n"); - - gmm_copy_id(msg, old_msg); - - gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh)); - gh->proto_discr = GSM48_PDISC_MM_GPRS; - gh->msg_type = GSM48_MT_GMM_RA_UPD_ACK; - - rua = (struct gsm48_ra_upd_ack *) msgb_put(msg, sizeof(*rua)); - rua->force_stby = 0; /* not indicated */ - rua->upd_result = 0; /* RA updated */ - rua->ra_upd_timer = GPRS_TMR_MINUTE | 10; - - bssgp_parse_cell_id(&ra_id, msgb_bcid(old_msg)); - gsm48_construct_ra(rua->ra_id.digits, &ra_id); - - /* Option: P-TMSI signature, allocated P-TMSI, MS ID, ... */ - return gsm48_gmm_sendmsg(msg, 0); -} - -/* Chapter 9.4.17: Routing area update reject */ -static int gsm48_tx_gmm_ra_upd_rej(struct msgb *old_msg, uint8_t cause) -{ - struct msgb *msg = gsm48_msgb_alloc(); - struct gsm48_hdr *gh; - - DEBUGP(DMM, "<- ROUTING AREA UPDATE REJECT\n"); - - gmm_copy_id(msg, old_msg); - - gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 2); - gh->proto_discr = GSM48_PDISC_MM_GPRS; - gh->msg_type = GSM48_MT_GMM_RA_UPD_REJ; - gh->data[0] = cause; - gh->data[1] = 0; /* ? */ - - /* Option: P-TMSI signature, allocated P-TMSI, MS ID, ... */ - return gsm48_gmm_sendmsg(msg, 0); -} - -/* Chapter 9.4.14: Routing area update request */ -static int gsm48_rx_gmm_ra_upd_req(struct msgb *msg) -{ - struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg); - struct sgsn_mm_ctx *mmctx; - uint8_t *cur = gh->data; - struct gprs_ra_id old_ra_id; - uint8_t upd_type; - - /* Update Type 10.5.5.18 */ - upd_type = *cur++ & 0x0f; - - DEBUGP(DMM, "GMM RA UPDATE REQUEST type=\"%s\" ", upd_name(upd_type)); - - /* Old routing area identification 10.5.5.15 */ - gsm48_parse_ra(&old_ra_id, cur); - cur += 6; - - /* MS Radio Access Capability 10.5.5.12a */ - - /* Optional: Old P-TMSI Signature, Requested READY timer, TMSI Status, - * DRX parameter, MS network capability */ - - switch (upd_type) { - case GPRS_UPD_T_RA_LA: - case GPRS_UPD_T_RA_LA_IMSI_ATT: - DEBUGPC(DMM, " unsupported in Mode III, is your SI13 corrupt?\n"); - return gsm48_tx_gmm_ra_upd_rej(msg, GMM_CAUSE_PROTO_ERR_UNSPEC); - break; - case GPRS_UPD_T_RA: - case GPRS_UPD_T_PERIODIC: - break; - } - - /* Look-up the MM context based on old RA-ID and TLLI */ - mmctx = sgsn_mm_ctx_by_tlli(msgb_tlli(msg), &old_ra_id); - if (!mmctx || mmctx->mm_state == GMM_DEREGISTERED) { - /* The MS has to perform GPRS attach */ - DEBUGPC(DMM, " REJECT\n"); - return gsm48_tx_gmm_ra_upd_rej(msg, GMM_CAUSE_IMPL_DETACHED); - } - - /* Update the MM context with the new RA-ID */ - bssgp_parse_cell_id(&mmctx->ra, msgb_bcid(msg)); - /* Update the MM context with the new TLLI */ - mmctx->tlli = msgb_tlli(msg); - /* FIXME: Update the MM context with the MS radio acc capabilities */ - /* FIXME: Update the MM context with the MS network capabilities */ - - DEBUGPC(DMM, " ACCEPT\n"); - return gsm48_tx_gmm_ra_upd_ack(msg); -} - -static int gsm48_rx_gmm_status(struct msgb *msg) -{ - struct gsm48_hdr *gh = msgb_l3(msg); - - DEBUGP(DMM, "GPRS MM STATUS (cause: %s)\n", - get_value_string(gmm_cause_names, gh->data[0])); - - return 0; -} - -/* GPRS Mobility Management */ -static int gsm0408_rcv_gmm(struct msgb *msg) -{ - struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg); - int rc; - - switch (gh->msg_type) { - case GSM48_MT_GMM_RA_UPD_REQ: - rc = gsm48_rx_gmm_ra_upd_req(msg); - break; - case GSM48_MT_GMM_ATTACH_REQ: - rc = gsm48_rx_gmm_att_req(msg); - break; - case GSM48_MT_GMM_ID_RESP: - rc = gsm48_rx_gmm_id_resp(msg); - break; - case GSM48_MT_GMM_STATUS: - rc = gsm48_rx_gmm_status(msg); - break; - case GSM48_MT_GMM_RA_UPD_COMPL: - /* only in case SGSN offered new P-TMSI */ - case GSM48_MT_GMM_ATTACH_COMPL: - /* only in case SGSN offered new P-TMSI */ - case GSM48_MT_GMM_DETACH_REQ: - case GSM48_MT_GMM_PTMSI_REALL_COMPL: - case GSM48_MT_GMM_AUTH_CIPH_RESP: - DEBUGP(DMM, "Unimplemented GSM 04.08 GMM msg type 0x%02x\n", - gh->msg_type); - break; - default: - DEBUGP(DMM, "Unknown GSM 04.08 GMM msg type 0x%02x\n", - gh->msg_type); - break; - } - - return rc; -} - -static void msgb_put_pdp_addr_ipv4(struct msgb *msg, uint32_t ipaddr) -{ - uint8_t v[6]; - - v[0] = PDP_TYPE_ORG_IETF; - v[1] = PDP_TYPE_N_IETF_IPv4; - *(uint32_t *)(v+2) = htonl(ipaddr); - - msgb_tlv_put(msg, GSM48_IE_GSM_PDP_ADDR, sizeof(v), v); -} - -static void msgb_put_pdp_addr_ppp(struct msgb *msg) -{ - uint8_t v[2]; - - v[0] = PDP_TYPE_ORG_ETSI; - v[1] = PDP_TYPE_N_ETSI_PPP; - - msgb_tlv_put(msg, GSM48_IE_GSM_PDP_ADDR, sizeof(v), v); -} - -/* Section 9.5.2: Ativate PDP Context Accept */ -static int gsm48_tx_gsm_act_pdp_acc(struct msgb *old_msg, struct gsm48_act_pdp_ctx_req *req) -{ - struct gsm48_hdr *old_gh = (struct gsm48_hdr *) msgb_gmmh(old_msg); - struct msgb *msg = gsm48_msgb_alloc(); - struct gsm48_act_pdp_ctx_ack *act_ack; - struct gsm48_hdr *gh; - uint8_t transaction_id = ((old_gh->proto_discr >> 4) ^ 0x8); /* flip */ - - DEBUGP(DMM, "<- ACTIVATE PDP CONTEXT ACK\n"); - - gmm_copy_id(msg, old_msg); - - gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh)); - gh->proto_discr = GSM48_PDISC_SM_GPRS | (transaction_id << 4); - gh->msg_type = GSM48_MT_GSM_ACT_PDP_ACK; - - /* Negotiated LLC SAPI */ - msgb_v_put(msg, req->req_llc_sapi); - /* copy QoS parameters from original request */ - msgb_lv_put(msg, sizeof(default_qos), (uint8_t *)&default_qos); - /* Radio priority 10.5.7.2 */ - msgb_v_put(msg, 4); - /* PDP address */ - msgb_put_pdp_addr_ipv4(msg, 0x01020304); - /* Optional: Protocol configuration options */ - /* Optional: Packet Flow Identifier */ - - return gsm48_gmm_sendmsg(msg, 0); -} - -/* Section 9.5.9: Deactivate PDP Context Accept */ -static int gsm48_tx_gsm_deact_pdp_acc(struct msgb *old_msg) -{ - struct gsm48_hdr *old_gh = (struct gsm48_hdr *) msgb_gmmh(old_msg); - struct msgb *msg = gsm48_msgb_alloc(); - struct gsm48_hdr *gh; - uint8_t transaction_id = ((old_gh->proto_discr >> 4) ^ 0x8); /* flip */ - - DEBUGP(DMM, "<- DEACTIVATE PDP CONTEXT ACK\n"); - - gmm_copy_id(msg, old_msg); - - gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh)); - gh->proto_discr = GSM48_PDISC_SM_GPRS | (transaction_id << 4); - gh->msg_type = GSM48_MT_GSM_DEACT_PDP_ACK; - - return gsm48_gmm_sendmsg(msg, 0); -} - -/* Section 9.5.1: Activate PDP Context Request */ -static int gsm48_rx_gsm_act_pdp_req(struct msgb *msg) -{ - struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg); - struct gsm48_act_pdp_ctx_req *act_req = (struct gsm48_act_pdp_ctx_req *) gh->data; - uint8_t *pdp_addr_lv = act_req->data; - uint8_t req_qos_len, req_pdpa_len; - uint8_t *req_qos, *req_pdpa; - struct tlv_parsed tp; - - DEBUGP(DMM, "ACTIVATE PDP CONTEXT REQ: "); - req_qos_len = act_req->data[0]; - req_qos = act_req->data + 1; /* 10.5.6.5 */ - req_pdpa_len = act_req->data[1 + req_qos_len]; - req_pdpa = act_req->data + 1 + req_qos_len + 1; /* 10.5.6.4 */ - - switch (req_pdpa[0] & 0xf) { - case 0x0: - DEBUGPC(DMM, "ETSI "); - break; - case 0x1: - DEBUGPC(DMM, "IETF "); - break; - case 0xf: - DEBUGPC(DMM, "Empty "); - break; - } - - switch (req_pdpa[1]) { - case 0x21: - DEBUGPC(DMM, "IPv4 "); - if (req_pdpa_len >= 6) { - struct in_addr ia; - ia.s_addr = ntohl(*((uint32_t *) (req_pdpa+2))); - DEBUGPC(DMM, "%s ", inet_ntoa(ia)); - } - break; - case 0x57: - DEBUGPC(DMM, "IPv6 "); - if (req_pdpa_len >= 18) { - /* FIXME: print IPv6 address */ - } - break; - default: - DEBUGPC(DMM, "0x%02x ", req_pdpa[1]); - break; - } - - /* FIXME: parse TLV for AP name and protocol config options */ - if (TLVP_PRESENT(&tp, GSM48_IE_GSM_APN)) {} - if (TLVP_PRESENT(&tp, GSM48_IE_GSM_PROTO_CONF_OPT)) {} - - return gsm48_tx_gsm_act_pdp_acc(msg, act_req); -} - -/* Section 9.5.8: Deactivate PDP Context Request */ -static int gsm48_rx_gsm_deact_pdp_req(struct msgb *msg) -{ - struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg); - - DEBUGP(DMM, "DEACTIVATE PDP CONTEXT REQ (cause: %s)\n", - get_value_string(gsm_cause_names, gh->data[0])); - - return gsm48_tx_gsm_deact_pdp_acc(msg); -} - -static int gsm48_rx_gsm_status(struct msgb *msg) -{ - struct gsm48_hdr *gh = msgb_l3(msg); - - DEBUGP(DMM, "GPRS SM STATUS (cause: %s)\n", - get_value_string(gsm_cause_names, gh->data[0])); - - return 0; -} - -/* GPRS Session Management */ -static int gsm0408_rcv_gsm(struct msgb *msg) -{ - struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg); - int rc; - - switch (gh->msg_type) { - case GSM48_MT_GSM_ACT_PDP_REQ: - rc = gsm48_rx_gsm_act_pdp_req(msg); - break; - case GSM48_MT_GSM_DEACT_PDP_REQ: - rc = gsm48_rx_gsm_deact_pdp_req(msg); - case GSM48_MT_GSM_STATUS: - rc = gsm48_rx_gsm_status(msg); - break; - case GSM48_MT_GSM_REQ_PDP_ACT_REJ: - case GSM48_MT_GSM_ACT_AA_PDP_REQ: - case GSM48_MT_GSM_DEACT_AA_PDP_REQ: - DEBUGP(DMM, "Unimplemented GSM 04.08 GSM msg type 0x%02x\n", - gh->msg_type); - break; - default: - DEBUGP(DMM, "Unknown GSM 04.08 GSM msg type 0x%02x\n", - gh->msg_type); - break; - - } - - return rc; -} - -/* Main entry point for incoming 04.08 GPRS messages */ -int gsm0408_gprs_rcvmsg(struct msgb *msg) -{ - struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg); - uint8_t pdisc = gh->proto_discr & 0x0f; - int rc = -EINVAL; - - switch (pdisc) { - case GSM48_PDISC_MM_GPRS: - rc = gsm0408_rcv_gmm(msg); - break; - case GSM48_PDISC_SM_GPRS: - rc = gsm0408_rcv_gsm(msg); - break; - default: - DEBUGP(DMM, "Unknown GSM 04.08 discriminator 0x%02x\n", - pdisc); - break; - } - - return rc; -} diff --git a/openbsc/src/osmo_gbproxy.cfg b/openbsc/src/osmo_gbproxy.cfg deleted file mode 100644 index f2ef1411f..000000000 --- a/openbsc/src/osmo_gbproxy.cfg +++ /dev/null @@ -1,13 +0,0 @@ -! -! OpenBSC configuration saved from vty -! ! -! -line vty - no login -! -gbproxy - nsip bss local port 23000 - nsip sgsn remote ip 192.168.100.239 - nsip sgsn remote port 23000 - nsip sgsn nsei 1 - nsip sgsn nsvci 11 diff --git a/openbsc/src/osmo_sgsn.cfg b/openbsc/src/osmo_sgsn.cfg deleted file mode 100644 index f39e8536f..000000000 --- a/openbsc/src/osmo_sgsn.cfg +++ /dev/null @@ -1,9 +0,0 @@ -! -! OpenBSC configuration saved from vty -! ! -! -line vty - no login -! -sgsn - nsip local port 23000 diff --git a/openbsc/src/sgsn_main.c b/openbsc/src/sgsn_main.c deleted file mode 100644 index d9ea6a8cf..000000000 --- a/openbsc/src/sgsn_main.c +++ /dev/null @@ -1,143 +0,0 @@ -/* GPRS SGSN Implementation */ - -/* (C) 2010 by Harald Welte - * (C) 2010 by On Waves - * 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 -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "../bscconfig.h" - -/* this is here for the vty... it will never be called */ -void subscr_put() { abort(); } - -#define _GNU_SOURCE -#include - -void *tall_bsc_ctx; - -struct gprs_ns_inst *sgsn_nsi; - -const char *openbsc_version = "Osmocom NSIP Proxy " PACKAGE_VERSION; -const char *openbsc_copyright = - "Copyright (C) 2010 Harald Welte and On-Waves\n" - "Contributions by Daniel Willmann, Jan Lübbe, Stefan Schmidt\n" - "Dieter Spaar, Andreas Eversberg, Holger Freyther\n\n" - "License GPLv2+: GNU GPL version 2 or later \n" - "This is free software: you are free to change and redistribute it.\n" - "There is NO WARRANTY, to the extent permitted by law.\n"; - -static char *config_file = "osmo_sgsn.cfg"; -static struct sgsn_config sgcfg; - -/* call-back function for the NS protocol */ -static int sgsn_ns_cb(enum gprs_ns_evt event, struct gprs_nsvc *nsvc, - struct msgb *msg, u_int16_t bvci) -{ - int rc = 0; - - switch (event) { - case GPRS_NS_EVT_UNIT_DATA: - /* hand the message into the BSSGP implementation */ - rc = gprs_bssgp_rcvmsg(msg); - break; - default: - LOGP(DGPRS, LOGL_ERROR, "SGSN: Unknown event %u from NS\n", event); - if (msg) - talloc_free(msg); - rc = -EIO; - break; - } - return rc; -} - -/* NSI that BSSGP uses when transmitting on NS */ -extern struct gprs_ns_inst *bssgp_nsi; - -int main(int argc, char **argv) -{ - struct gsm_network dummy_network; - struct log_target *stderr_target; - struct sockaddr_in sin; - int rc; - - tall_bsc_ctx = talloc_named_const(NULL, 0, "osmo_sgsn"); - - log_init(&log_info); - stderr_target = log_target_create_stderr(); - log_add_target(stderr_target); - log_set_all_filter(stderr_target, 1); - - telnet_init(&dummy_network, 4245); - rc = sgsn_parse_config(config_file, &sgcfg); - if (rc < 0) { - LOGP(DGPRS, LOGL_FATAL, "Cannot parse config file\n"); - exit(2); - } - - sgsn_nsi = gprs_ns_instantiate(&sgsn_ns_cb); - if (!sgsn_nsi) { - LOGP(DGPRS, LOGL_ERROR, "Unable to instantiate NS\n"); - exit(1); - } - bssgp_nsi = sgcfg.nsi = sgsn_nsi; - nsip_listen(sgsn_nsi, sgcfg.nsip_listen_port); - - while (1) { - rc = bsc_select_main(0); - if (rc < 0) - exit(3); - } - - exit(0); -} - -struct gsm_network; -int bsc_vty_init(struct gsm_network *dummy) -{ - cmd_init(1); - vty_init(); - - openbsc_vty_add_cmds(); - sgsn_vty_init(); - return 0; -} - diff --git a/openbsc/src/sgsn_vty.c b/openbsc/src/sgsn_vty.c deleted file mode 100644 index ec18fcbf9..000000000 --- a/openbsc/src/sgsn_vty.c +++ /dev/null @@ -1,146 +0,0 @@ -/* - * (C) 2010 by Harald Welte - * (C) 2010 by On-Waves - * 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 -#include -#include - -#include -#include - -static struct sgsn_config *g_cfg = NULL; - -static struct cmd_node sgsn_node = { - SGSN_NODE, - "%s(sgsn)#", - 1, -}; - -static int config_write_sgsn(struct vty *vty) -{ - struct in_addr ia; - - vty_out(vty, "sgsn%s", VTY_NEWLINE); - - if (g_cfg->nsip_listen_ip) { - ia.s_addr = htonl(g_cfg->nsip_listen_ip); - vty_out(vty, " nsip local ip %s%s", inet_ntoa(ia), - VTY_NEWLINE); - } - vty_out(vty, " nsip local port %u%s", g_cfg->nsip_listen_port, - VTY_NEWLINE); - - return CMD_SUCCESS; -} - -DEFUN(show_sgsn, show_sgsn_cmd, "show sgsn", - SHOW_STR "Display information about the SGSN") -{ - /* FIXME: iterate over list of NS-VC's and display their state */ - struct gprs_ns_inst *nsi = g_cfg->nsi; - struct gprs_nsvc *nsvc; - - llist_for_each_entry(nsvc, &nsi->gprs_nsvcs, list) { - vty_out(vty, "NSEI %5u, NS-VC %5u, %s-mode, %s %s%s", - nsvc->nsei, nsvc->nsvci, - nsvc->remote_end_is_sgsn ? "BSS" : "SGSN", - nsvc->state & NSE_S_ALIVE ? "ALIVE" : "DEAD", - nsvc->state & NSE_S_BLOCKED ? "BLOCKED" : "UNBLOCKED", - VTY_NEWLINE); - if (nsvc->nsi->ll == GPRS_NS_LL_UDP) - vty_out(vty, " remote peer %s:%u%s", - inet_ntoa(nsvc->ip.bts_addr.sin_addr), - ntohs(nsvc->ip.bts_addr.sin_port), VTY_NEWLINE); - } - - return CMD_SUCCESS; -} - -DEFUN(cfg_sgsn, - cfg_sgsn_cmd, - "sgsn", - "Configure the SGSN") -{ - vty->node = SGSN_NODE; - return CMD_SUCCESS; -} - - -DEFUN(cfg_nsip_local_ip, - cfg_nsip_local_ip_cmd, - "nsip local ip A.B.C.D", - "Set the IP address on which we listen for BSS connects") -{ - struct in_addr ia; - - inet_aton(argv[0], &ia); - g_cfg->nsip_listen_ip = ntohl(ia.s_addr); - - return CMD_SUCCESS; -} - -DEFUN(cfg_nsip_local_port, - cfg_nsip_local_port_cmd, - "nsip local port <0-65534>", - "Set the UDP port on which we listen for BSS connects") -{ - unsigned int port = atoi(argv[0]); - - g_cfg->nsip_listen_port = port; - return CMD_SUCCESS; -} - - - - -int sgsn_vty_init(void) -{ - install_element(VIEW_NODE, &show_sgsn_cmd); - - install_element(CONFIG_NODE, &cfg_sgsn_cmd); - install_node(&sgsn_node, config_write_sgsn); - install_default(SGSN_NODE); - install_element(SGSN_NODE, &cfg_nsip_local_ip_cmd); - install_element(SGSN_NODE, &cfg_nsip_local_port_cmd); - - return 0; -} - -int sgsn_parse_config(const char *config_file, struct sgsn_config *cfg) -{ - int rc; - - g_cfg = cfg; - rc = vty_read_config_file(config_file); - if (rc < 0) { - fprintf(stderr, "Failed to parse the config file: '%s'\n", config_file); - return rc; - } - - return 0; -} -- cgit v1.2.3 From c9a341b248a87c53e9e28ee2cde00e8071b5535e Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 4 May 2010 07:47:54 +0200 Subject: move ipaccess tools into their own subdirectory They will now be built fully inside src/ipaccess, using their own Makefile.am --- openbsc/configure.in | 1 + openbsc/src/Makefile.am | 12 ++---------- openbsc/src/ipaccess/Makefile.am | 12 ++++++++++++ 3 files changed, 15 insertions(+), 10 deletions(-) create mode 100644 openbsc/src/ipaccess/Makefile.am diff --git a/openbsc/configure.in b/openbsc/configure.in index 98a93fc6b..8201983f2 100644 --- a/openbsc/configure.in +++ b/openbsc/configure.in @@ -48,6 +48,7 @@ AC_OUTPUT( include/sccp/Makefile include/Makefile src/Makefile + src/ipaccess/Makefile src/gprs/Makefile tests/Makefile tests/debug/Makefile diff --git a/openbsc/src/Makefile.am b/openbsc/src/Makefile.am index 9dcdea02f..9dc02575c 100644 --- a/openbsc/src/Makefile.am +++ b/openbsc/src/Makefile.am @@ -3,10 +3,9 @@ AM_CFLAGS=-Wall $(LIBOSMOCORE_CFLAGS) AM_LDFLAGS = $(LIBOSMOCORE_LIBS) # build current directory before building gprs -SUBDIRS = . gprs +SUBDIRS = . ipaccess gprs -sbin_PROGRAMS = bsc_hack bs11_config ipaccess-find ipaccess-config \ - isdnsync bsc_mgcp ipaccess-proxy +sbin_PROGRAMS = bsc_hack bs11_config isdnsync bsc_mgcp noinst_LIBRARIES = libbsc.a libmsc.a libvty.a libsccp.a noinst_HEADERS = vty/cardshell.h @@ -38,15 +37,8 @@ bsc_hack_LDADD = libmsc.a libbsc.a libmsc.a libvty.a -ldl -ldbi $(LIBCRYPT) bs11_config_SOURCES = bs11_config.c abis_nm.c gsm_data.c debug.c \ rs232.c bts_siemens_bs11.c -ipaccess_find_SOURCES = ipaccess/ipaccess-find.c - -ipaccess_config_SOURCES = ipaccess/ipaccess-config.c ipaccess/ipaccess-firmware.c -ipaccess_config_LDADD = libbsc.a libmsc.a libbsc.a libvty.a -ldl -ldbi $(LIBCRYPT) - isdnsync_SOURCES = isdnsync.c bsc_mgcp_SOURCES = mgcp/mgcp_main.c mgcp/mgcp_protocol.c mgcp/mgcp_network.c mgcp/mgcp_vty.c \ debug.c bsc_mgcp_LDADD = libvty.a - -ipaccess_proxy_SOURCES = ipaccess/ipaccess-proxy.c debug.c diff --git a/openbsc/src/ipaccess/Makefile.am b/openbsc/src/ipaccess/Makefile.am new file mode 100644 index 000000000..7a13ee175 --- /dev/null +++ b/openbsc/src/ipaccess/Makefile.am @@ -0,0 +1,12 @@ +INCLUDES = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir) +AM_CFLAGS=-Wall $(LIBOSMOCORE_CFLAGS) +AM_LDFLAGS = $(LIBOSMOCORE_LIBS) + +sbin_PROGRAMS = ipaccess-find ipaccess-config ipaccess-proxy + +ipaccess_find_SOURCES = ipaccess-find.c + +ipaccess_config_SOURCES = ipaccess-config.c ipaccess-firmware.c +ipaccess_config_LDADD = ../libbsc.a ../libmsc.a ../libbsc.a ../libvty.a -ldl -ldbi $(LIBCRYPT) + +ipaccess_proxy_SOURCES = ipaccess-proxy.c ../debug.c -- cgit v1.2.3 From 5d6e378c3591d42a52873df059818129d3880dae Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 4 May 2010 08:10:18 +0200 Subject: update README with URL of the homepage --- openbsc/README | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openbsc/README b/openbsc/README index 51807bb44..fa01ff4cd 100644 --- a/openbsc/README +++ b/openbsc/README @@ -14,6 +14,8 @@ Its currently supported interfaces towards the BTS are: * A-bis over IP as used by the ip.access nanoBTS product family +You can find the project documentation at http://openbsc.gnumonks.org/ + This project is still in its early days, and there are lots of areas where it doesn't behave as per GSM spec. -- cgit v1.2.3 From c6ec0406c810d265fd2db70b115458dc184bf5e5 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Tue, 4 May 2010 14:34:04 +0800 Subject: misc: Use $(top_srcdir) for source, $(top_builddir) for libs We should not use ../ for adding sources or libraries as the user might have a srcdir != builddir setup. --- openbsc/src/gprs/Makefile.am | 8 ++++---- openbsc/src/ipaccess/Makefile.am | 3 ++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index ac177f7fd..2b4292398 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -9,9 +9,9 @@ libsgsn_a_SOURCES = gprs_ns.c gprs_bssgp.c gprs_llc.c gsm_04_08_gprs.c \ crc24.c gprs_sgsn.c osmo_gbproxy_SOURCES = gb_proxy.c gb_proxy_main.c gb_proxy_vty.c \ - gprs_ns.c ../socket.c ../debug.c -osmo_gbproxy_LDADD = ../libvty.a + gprs_ns.c $(top_srcdir)/src/socket.c $(top_srcdir)/src/debug.c +osmo_gbproxy_LDADD = $(top_builddir)/src/libvty.a osmo_sgsn_SOURCES = sgsn_main.c sgsn_vty.c \ - ../socket.c ../debug.c -osmo_sgsn_LDADD = ../libvty.a libsgsn.a + $(top_srcdir)/src/socket.c $(top_srcdir)/src/debug.c +osmo_sgsn_LDADD = $(top_builddir)/src/libvty.a libsgsn.a diff --git a/openbsc/src/ipaccess/Makefile.am b/openbsc/src/ipaccess/Makefile.am index 7a13ee175..533932142 100644 --- a/openbsc/src/ipaccess/Makefile.am +++ b/openbsc/src/ipaccess/Makefile.am @@ -7,6 +7,7 @@ sbin_PROGRAMS = ipaccess-find ipaccess-config ipaccess-proxy ipaccess_find_SOURCES = ipaccess-find.c ipaccess_config_SOURCES = ipaccess-config.c ipaccess-firmware.c -ipaccess_config_LDADD = ../libbsc.a ../libmsc.a ../libbsc.a ../libvty.a -ldl -ldbi $(LIBCRYPT) +ipaccess_config_LDADD = $(top_builddir)/src/libbsc.a $(top_builddir)/src/libmsc.a \ + $(top_builddir)/src/libbsc.a $(top_builddir)/src/libvty.a -ldl -ldbi $(LIBCRYPT) ipaccess_proxy_SOURCES = ipaccess-proxy.c ../debug.c -- cgit v1.2.3 From 85801d02940833729b6057d48b41df3ed0816207 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 11 May 2010 05:49:43 +0200 Subject: [gprs] gb_proxy: More VTY 'show' information The 'show gbproxy' now actually shows information about the Gb proxy BTS peers, whereas 'show ns' shows information about existing NS links. --- openbsc/include/openbsc/gb_proxy.h | 2 ++ openbsc/src/gprs/gb_proxy.c | 25 +++++++++++++++++++++++++ openbsc/src/gprs/gb_proxy_vty.c | 5 +++-- 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/openbsc/include/openbsc/gb_proxy.h b/openbsc/include/openbsc/gb_proxy.h index 60dd5ca80..3b695e52a 100644 --- a/openbsc/include/openbsc/gb_proxy.h +++ b/openbsc/include/openbsc/gb_proxy.h @@ -6,6 +6,7 @@ #include #include +#include struct gbproxy_config { /* parsed from config file */ @@ -23,6 +24,7 @@ struct gbproxy_config { }; extern struct gbproxy_config gbcfg; +extern struct cmd_element show_gbproxy_cmd; /* gb_proxy_vty .c */ diff --git a/openbsc/src/gprs/gb_proxy.c b/openbsc/src/gprs/gb_proxy.c index fe5ad702f..3ed7fdfde 100644 --- a/openbsc/src/gprs/gb_proxy.c +++ b/openbsc/src/gprs/gb_proxy.c @@ -414,3 +414,28 @@ int gbprox_rcvmsg(struct msgb *msg, struct gprs_nsvc *nsvc, uint16_t ns_bvci) return rc; } + + +#include + +gDEFUN(show_gbproxy, show_gbproxy_cmd, "show gbproxy", + SHOW_STR "Display information about the Gb proxy") +{ + struct gbprox_peer *peer; + + llist_for_each_entry(peer, &gbprox_bts_peers, list) { + struct gprs_nsvc *nsvc = peer->nsvc; + struct gprs_ra_id raid; + gsm48_parse_ra(&raid, &peer->ra); + + vty_out(vty, "NSEI %5u, NS-VC %5u, PTP-BVCI %u, " + "RAC %u-%u-%u-%u%s", + nsvc->nsei, nsvc->nsvci, peer->bvci, + raid.mcc, raid.mnc, raid.lac, raid.rac, VTY_NEWLINE); + if (nsvc->nsi->ll == GPRS_NS_LL_UDP) + vty_out(vty, " remote address %s:%u%s", + inet_ntoa(nsvc->ip.bts_addr.sin_addr), + ntohs(nsvc->ip.bts_addr.sin_port), VTY_NEWLINE); + } + return CMD_SUCCESS; +} diff --git a/openbsc/src/gprs/gb_proxy_vty.c b/openbsc/src/gprs/gb_proxy_vty.c index 16f6a1e0e..a40392b90 100644 --- a/openbsc/src/gprs/gb_proxy_vty.c +++ b/openbsc/src/gprs/gb_proxy_vty.c @@ -70,8 +70,8 @@ static int config_write_gbproxy(struct vty *vty) return CMD_SUCCESS; } -DEFUN(show_gbproxy, show_gbproxy_cmd, "show gbproxy", - SHOW_STR "Display information about the Gb proxy") +DEFUN(show_ns, show_ns_cmd, "show ns", + SHOW_STR "Display information about the NS protocol") { /* FIXME: iterate over list of NS-VC's and display their state */ struct gprs_ns_inst *nsi = g_cfg->nsi; @@ -176,6 +176,7 @@ DEFUN(cfg_nsip_sgsn_nsvci, int gbproxy_vty_init(void) { + install_element(VIEW_NODE, &show_ns_cmd); install_element(VIEW_NODE, &show_gbproxy_cmd); install_element(CONFIG_NODE, &cfg_gbproxy_cmd); -- cgit v1.2.3 From 6b72cdf85423f9aca68bce15084e8a1b30b3db55 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 11 May 2010 05:54:22 +0200 Subject: [gprs] Add new 'NS' and 'BSSGP' logging categories --- openbsc/include/openbsc/debug.h | 2 ++ openbsc/src/debug.c | 10 +++++++++ openbsc/src/gprs/gprs_bssgp.c | 44 ++++++++++++++++++++-------------------- openbsc/src/gprs/gprs_ns.c | 44 ++++++++++++++++++++-------------------- openbsc/src/vty_interface_cmds.c | 2 +- 5 files changed, 57 insertions(+), 45 deletions(-) diff --git a/openbsc/include/openbsc/debug.h b/openbsc/include/openbsc/debug.h index 49b417e26..65fd0bb53 100644 --- a/openbsc/include/openbsc/debug.h +++ b/openbsc/include/openbsc/debug.h @@ -30,6 +30,8 @@ enum { DDB, DREF, DGPRS, + DNS, + DBSSGP, Debug_LastEntry, }; diff --git a/openbsc/src/debug.c b/openbsc/src/debug.c index 181756de5..40bd52c6c 100644 --- a/openbsc/src/debug.c +++ b/openbsc/src/debug.c @@ -151,6 +151,16 @@ static const struct log_info_cat default_categories[] = { .description = "GPRS Packet Service", .enabled = 1, .loglevel = LOGL_DEBUG, }, + [DNS] = { + .name = "DNS", + .description = "GPRS Network Service", + .enabled = 1, .loglevel = LOGL_DEBUG, + }, + [DBSSGP] = { + .name = "DBSSGP", + .description = "GPRS BSSGP Protocol", + .enabled = 1, .loglevel = LOGL_DEBUG, + }, }; enum log_ctxt { diff --git a/openbsc/src/gprs/gprs_bssgp.c b/openbsc/src/gprs/gprs_bssgp.c index 554738b56..0f658b993 100644 --- a/openbsc/src/gprs/gprs_bssgp.c +++ b/openbsc/src/gprs/gprs_bssgp.c @@ -188,7 +188,7 @@ int bssgp_tx_status(uint8_t cause, uint16_t *bvci, struct msgb *orig_msg) struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph)); - DEBUGPC(DGPRS, "BSSGP: TX STATUS, cause=%s\n", bssgp_cause_str(cause)); + DEBUGPC(DBSSGP, "BSSGP: TX STATUS, cause=%s\n", bssgp_cause_str(cause)); msgb_nsei(msg) = msgb_nsei(orig_msg); msgb_bvci(msg) = 0; @@ -223,7 +223,7 @@ static int bssgp_rx_bvc_reset(struct msgb *msg, struct tlv_parsed *tp, int rc; bvci = ntohs(*(uint16_t *)TLVP_VAL(tp, BSSGP_IE_BVCI)); - DEBUGPC(DGPRS, "BVCI=%u, cause=%s\n", bvci, + DEBUGPC(DBSSGP, "BVCI=%u, cause=%s\n", bvci, bssgp_cause_str(*TLVP_VAL(tp, BSSGP_IE_CAUSE))); /* look-up or create the BTS context for this BVC */ @@ -235,14 +235,14 @@ static int bssgp_rx_bvc_reset(struct msgb *msg, struct tlv_parsed *tp, * informs us about its RAC + Cell ID, so we can create a mapping */ if (bvci != 0 && bvci != 1) { if (!TLVP_PRESENT(tp, BSSGP_IE_CELL_ID)) { - LOGP(DGPRS, LOGL_ERROR, "BSSGP RESET BVCI=%u " + LOGP(DBSSGP, LOGL_ERROR, "BSSGP RESET BVCI=%u " "missing mandatory IE\n", bvci); return -EINVAL; } /* actually extract RAC / CID */ bctx->cell_id = bssgp_parse_cell_id(&bctx->ra_id, TLVP_VAL(tp, BSSGP_IE_CELL_ID)); - LOGP(DGPRS, LOGL_NOTICE, "Cell %u-%u-%u-%u CI %u on BVCI %u\n", + LOGP(DBSSGP, LOGL_NOTICE, "Cell %u-%u-%u-%u CI %u on BVCI %u\n", bctx->ra_id.mcc, bctx->ra_id.mnc, bctx->ra_id.lac, bctx->ra_id.rac, bctx->cell_id, bvci); } @@ -261,7 +261,7 @@ static int bssgp_rx_ul_ud(struct msgb *msg) struct tlv_parsed tp; int rc; - DEBUGP(DGPRS, "BSSGP UL-UD\n"); + DEBUGP(DBSSGP, "BSSGP UL-UD\n"); /* extract TLLI and parse TLV IEs */ msgb_tlli(msg) = ntohl(budh->tlli); @@ -289,7 +289,7 @@ static int bssgp_rx_suspend(struct msgb *msg) struct tlv_parsed tp; int rc; - DEBUGP(DGPRS, "BSSGP SUSPEND\n"); + DEBUGP(DBSSGP, "BSSGP SUSPEND\n"); rc = bssgp_tlv_parse(&tp, bgph->data, data_len); if (rc < 0) @@ -311,7 +311,7 @@ static int bssgp_rx_resume(struct msgb *msg) struct tlv_parsed tp; int rc; - DEBUGP(DGPRS, "BSSGP RESUME\n"); + DEBUGP(DBSSGP, "BSSGP RESUME\n"); rc = bssgp_tlv_parse(&tp, bgph->data, data_len); if (rc < 0) @@ -329,7 +329,7 @@ static int bssgp_rx_resume(struct msgb *msg) static int bssgp_rx_fc_bvc(struct msgb *msg, struct tlv_parsed *tp) { - DEBUGP(DGPRS, "BSSGP FC BVC\n"); + DEBUGP(DBSSGP, "BSSGP FC BVC\n"); if (!TLVP_PRESENT(tp, BSSGP_IE_TAG) || !TLVP_PRESENT(tp, BSSGP_IE_BVC_BUCKET_SIZE) || @@ -371,11 +371,11 @@ int gprs_bssgp_rcvmsg(struct msgb *msg) break; case BSSGP_PDUT_RA_CAPABILITY: /* BSS requests RA capability or IMSI */ - DEBUGP(DGPRS, "BSSGP RA CAPABILITY UPDATE\n"); + DEBUGP(DBSSGP, "BSSGP RA CAPABILITY UPDATE\n"); /* FIXME: send RA_CAPA_UPDATE_ACK */ break; case BSSGP_PDUT_RADIO_STATUS: - DEBUGP(DGPRS, "BSSGP RADIO STATUS\n"); + DEBUGP(DBSSGP, "BSSGP RADIO STATUS\n"); /* BSS informs us of some exception */ /* FIXME: notify GMM */ break; @@ -389,13 +389,13 @@ int gprs_bssgp_rcvmsg(struct msgb *msg) break; case BSSGP_PDUT_FLUSH_LL: /* BSS informs MS has moved to one cell to other cell */ - DEBUGP(DGPRS, "BSSGP FLUSH LL\n"); + DEBUGP(DBSSGP, "BSSGP FLUSH LL\n"); /* FIXME: notify GMM */ /* Send FLUSH_LL_ACK */ break; case BSSGP_PDUT_LLC_DISCARD: /* BSS informs that some LLC PDU's have been discarded */ - DEBUGP(DGPRS, "BSSGP LLC DISCARDED\n"); + DEBUGP(DBSSGP, "BSSGP LLC DISCARDED\n"); /* FIXME: notify GMM */ break; case BSSGP_PDUT_FLOW_CONTROL_BVC: @@ -404,18 +404,18 @@ int gprs_bssgp_rcvmsg(struct msgb *msg) break; case BSSGP_PDUT_FLOW_CONTROL_MS: /* BSS informs us of available bandwidth to one MS */ - DEBUGP(DGPRS, "BSSGP FC MS\n"); + DEBUGP(DBSSGP, "BSSGP FC MS\n"); /* FIXME: actually implement flow control */ /* FIXME: Send FLOW_CONTROL_MS_ACK */ break; case BSSGP_PDUT_BVC_BLOCK: /* BSS tells us that BVC shall be blocked */ - DEBUGP(DGPRS, "BSSGP BVC BLOCK "); + DEBUGP(DBSSGP, "BSSGP BVC BLOCK "); if (!TLVP_PRESENT(&tp, BSSGP_IE_BVCI) || !TLVP_PRESENT(&tp, BSSGP_IE_CAUSE)) goto err_mand_ie; bvci = ntohs(*(uint16_t *)TLVP_VAL(&tp, BSSGP_IE_BVCI)); - DEBUGPC(DGPRS, "BVCI=%u, cause=%s\n", bvci, + DEBUGPC(DBSSGP, "BVCI=%u, cause=%s\n", bvci, bssgp_cause_str(*TLVP_VAL(&tp, BSSGP_IE_CAUSE))); /* We always acknowledge the BLOCKing */ rc = bssgp_tx_simple_bvci(BSSGP_PDUT_BVC_BLOCK_ACK, @@ -423,18 +423,18 @@ int gprs_bssgp_rcvmsg(struct msgb *msg) break; case BSSGP_PDUT_BVC_UNBLOCK: /* BSS tells us that BVC shall be unblocked */ - DEBUGP(DGPRS, "BSSGP BVC UNBLOCK "); + DEBUGP(DBSSGP, "BSSGP BVC UNBLOCK "); if (!TLVP_PRESENT(&tp, BSSGP_IE_BVCI)) goto err_mand_ie; bvci = ntohs(*(uint16_t *)TLVP_VAL(&tp, BSSGP_IE_BVCI)); - DEBUGPC(DGPRS, "BVCI=%u\n", bvci); + DEBUGPC(DBSSGP, "BVCI=%u\n", bvci); /* We always acknowledge the unBLOCKing */ rc = bssgp_tx_simple_bvci(BSSGP_PDUT_BVC_UNBLOCK_ACK, msgb_nsei(msg), bvci, ns_bvci); break; case BSSGP_PDUT_BVC_RESET: /* BSS tells us that BVC init is required */ - DEBUGP(DGPRS, "BSSGP BVC RESET "); + DEBUGP(DBSSGP, "BSSGP BVC RESET "); if (!TLVP_PRESENT(&tp, BSSGP_IE_BVCI) || !TLVP_PRESENT(&tp, BSSGP_IE_CAUSE)) goto err_mand_ie; @@ -448,7 +448,7 @@ int gprs_bssgp_rcvmsg(struct msgb *msg) case BSSGP_PDUT_CREATE_BSS_PFC_NACK: case BSSGP_PDUT_MODIFY_BSS_PFC: case BSSGP_PDUT_DELETE_BSS_PFC_ACK: - DEBUGP(DGPRS, "BSSGP PDU type 0x%02x not [yet] implemented\n", + DEBUGP(DBSSGP, "BSSGP PDU type 0x%02x not [yet] implemented\n", pdu_type); break; /* those only exist in the SGSN -> BSS direction */ @@ -466,12 +466,12 @@ int gprs_bssgp_rcvmsg(struct msgb *msg) case BSSGP_PDUT_BVC_BLOCK_ACK: case BSSGP_PDUT_BVC_UNBLOCK_ACK: case BSSGP_PDUT_SGSN_INVOKE_TRACE: - DEBUGP(DGPRS, "BSSGP PDU type 0x%02x only exists in DL\n", + DEBUGP(DBSSGP, "BSSGP PDU type 0x%02x only exists in DL\n", pdu_type); rc = -EINVAL; break; default: - DEBUGP(DGPRS, "BSSGP PDU type 0x%02x unknown\n", pdu_type); + DEBUGP(DBSSGP, "BSSGP PDU type 0x%02x unknown\n", pdu_type); break; } @@ -496,7 +496,7 @@ int gprs_bssgp_tx_dl_ud(struct msgb *msg) /* Identifiers from UP: TLLI, BVCI, NSEI (all in msgb->cb) */ if (bvci < 2) { - LOGP(DGPRS, LOGL_ERROR, "Cannot send DL-UD to BVCI %u\n", + LOGP(DBSSGP, LOGL_ERROR, "Cannot send DL-UD to BVCI %u\n", bvci); return -EINVAL; } diff --git a/openbsc/src/gprs/gprs_ns.c b/openbsc/src/gprs/gprs_ns.c index 3d9bb8963..be3d1d93a 100644 --- a/openbsc/src/gprs/gprs_ns.c +++ b/openbsc/src/gprs/gprs_ns.c @@ -160,7 +160,7 @@ static int gprs_ns_tx(struct gprs_nsvc *nsvc, struct msgb *msg) ret = nsip_sendmsg(nsvc, msg); break; default: - LOGP(DGPRS, LOGL_ERROR, "unsupported NS linklayer %u\n", nsvc->nsi->ll); + LOGP(DNS, LOGL_ERROR, "unsupported NS linklayer %u\n", nsvc->nsi->ll); msgb_free(msg); ret = -EIO; break; @@ -234,7 +234,7 @@ static void gprs_ns_timer_cb(void *data) if (nsvc->alive_retries > NS_ALIVE_RETRIES) { /* mark as dead and blocked */ nsvc->state = NSE_S_BLOCKED; - DEBUGP(DGPRS, "NSEI=%u Tns-alive expired more then " + DEBUGP(DNS, "NSEI=%u Tns-alive expired more then " "%u times, blocking NS-VC\n", nsvc->nsei, NS_ALIVE_RETRIES); /* FIXME: inform higher layers */ @@ -273,7 +273,7 @@ static int gprs_ns_tx_reset_ack(struct gprs_nsvc *nsvc) nsh->pdu_type = NS_PDUT_RESET_ACK; - DEBUGP(DGPRS, "NSEI=%u Tx NS RESET ACK (NSVCI=%u)\n", + DEBUGP(DNS, "NSEI=%u Tx NS RESET ACK (NSVCI=%u)\n", nsvc->nsei, nsvc->nsvci); msgb_tvlv_put(msg, NS_IE_VCI, 2, (uint8_t *)&nsvci); @@ -291,25 +291,25 @@ int gprs_ns_sendmsg(struct gprs_ns_inst *nsi, struct msgb *msg) nsvc = nsvc_by_nsei(nsi, msgb_nsei(msg)); if (!nsvc) { - LOGP(DGPRS, LOGL_ERROR, "Unable to resolve NSEI %u " + LOGP(DNS, LOGL_ERROR, "Unable to resolve NSEI %u " "to NS-VC!\n", msgb_nsei(msg)); return -EINVAL; } if (!(nsvc->state & NSE_S_ALIVE)) { - LOGP(DGPRS, LOGL_ERROR, "NSEI=%u is not alive, cannot send\n", + LOGP(DNS, LOGL_ERROR, "NSEI=%u is not alive, cannot send\n", nsvc->nsei); return -EBUSY; } if (nsvc->state & NSE_S_BLOCKED) { - LOGP(DGPRS, LOGL_ERROR, "NSEI=%u is blocked, cannot send\n", + LOGP(DNS, LOGL_ERROR, "NSEI=%u is blocked, cannot send\n", nsvc->nsei); return -EBUSY; } nsh = (struct gprs_ns_hdr *) msgb_push(msg, sizeof(*nsh) + 3); if (!nsh) { - LOGP(DGPRS, LOGL_ERROR, "Not enough headroom for NS header\n"); + LOGP(DNS, LOGL_ERROR, "Not enough headroom for NS header\n"); return -EIO; } @@ -344,17 +344,17 @@ static int gprs_ns_rx_status(struct gprs_nsvc *nsvc, struct msgb *msg) uint8_t cause; int rc; - DEBUGP(DGPRS, "NSEI=%u NS STATUS ", nsvc->nsei); + DEBUGP(DNS, "NSEI=%u NS STATUS ", nsvc->nsei); rc = tlv_parse(&tp, &ns_att_tlvdef, nsh->data, msgb_l2len(msg), 0, 0); if (!TLVP_PRESENT(&tp, NS_IE_CAUSE)) { - DEBUGPC(DGPRS, "missing cause IE\n"); + DEBUGPC(DNS, "missing cause IE\n"); return -EINVAL; } cause = *TLVP_VAL(&tp, NS_IE_CAUSE); - DEBUGPC(DGPRS, "cause=%s\n", gprs_ns_cause_str(cause)); + DEBUGPC(DNS, "cause=%s\n", gprs_ns_cause_str(cause)); return 0; } @@ -374,7 +374,7 @@ static int gprs_ns_rx_reset(struct gprs_nsvc *nsvc, struct msgb *msg) !TLVP_PRESENT(&tp, NS_IE_VCI) || !TLVP_PRESENT(&tp, NS_IE_NSEI)) { /* FIXME: respond with NS_CAUSE_MISSING_ESSENT_IE */ - LOGP(DGPRS, LOGL_ERROR, "NS RESET Missing mandatory IE\n"); + LOGP(DNS, LOGL_ERROR, "NS RESET Missing mandatory IE\n"); return -EINVAL; } @@ -382,7 +382,7 @@ static int gprs_ns_rx_reset(struct gprs_nsvc *nsvc, struct msgb *msg) nsvci = (uint16_t *) TLVP_VAL(&tp, NS_IE_VCI); nsei = (uint16_t *) TLVP_VAL(&tp, NS_IE_NSEI); - DEBUGP(DGPRS, "NSEI=%u NS RESET (NSVCI=%u, cause=%s)\n", + DEBUGP(DNS, "NSEI=%u NS RESET (NSVCI=%u, cause=%s)\n", nsvc->nsvci, nsvc->nsei, gprs_ns_cause_str(*cause)); nsvc->state = NSE_S_BLOCKED | NSE_S_ALIVE; @@ -409,13 +409,13 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, if (!nsvc) { /* Only the RESET procedure creates a new NSVC */ if (nsh->pdu_type != NS_PDUT_RESET) { - LOGP(DGPRS, LOGL_INFO, "Ignoring NS PDU type 0x%0x " + LOGP(DNS, LOGL_INFO, "Ignoring NS PDU type 0x%0x " "from %s for non-existing NS-VC\n", nsh->pdu_type, inet_ntoa(saddr->sin_addr)); //gprs_ns_tx_reset(nsvc, NS_CAUSE_NSVC_UNKNOWN); return -EIO; } - LOGP(DGPRS, LOGL_INFO, "Creating NS-VC for BSS at %s:%u\n", + LOGP(DNS, LOGL_INFO, "Creating NS-VC for BSS at %s:%u\n", inet_ntoa(saddr->sin_addr), ntohs(saddr->sin_port)); nsvc = nsvc_create(nsi, 0xffff); nsvc->ip.bts_addr = *saddr; @@ -450,7 +450,7 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, rc = gprs_ns_rx_reset(nsvc, msg); break; case NS_PDUT_RESET_ACK: - DEBUGP(DGPRS, "NSEI=%u Rx NS RESET ACK\n", nsvc->nsei); + DEBUGP(DNS, "NSEI=%u Rx NS RESET ACK\n", nsvc->nsei); /* mark remote NS-VC as blocked + active */ nsvc->remote_state = NSE_S_BLOCKED | NSE_S_ALIVE; if (nsvc->remote_end_is_sgsn) { @@ -465,29 +465,29 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, break; case NS_PDUT_UNBLOCK: /* Section 7.2: unblocking procedure */ - DEBUGP(DGPRS, "NSEI=%u Rx NS UNBLOCK\n", nsvc->nsei); + DEBUGP(DNS, "NSEI=%u Rx NS UNBLOCK\n", nsvc->nsei); nsvc->state &= ~NSE_S_BLOCKED; rc = gprs_ns_tx_simple(nsvc, NS_PDUT_UNBLOCK_ACK); break; case NS_PDUT_UNBLOCK_ACK: - DEBUGP(DGPRS, "NSEI=%u Rx NS UNBLOCK ACK\n", nsvc->nsei); + DEBUGP(DNS, "NSEI=%u Rx NS UNBLOCK ACK\n", nsvc->nsei); /* mark remote NS-VC as unblocked + active */ nsvc->remote_state = NSE_S_ALIVE; if (nsvc->remote_end_is_sgsn) nsvc->state = NSE_S_ALIVE; break; case NS_PDUT_BLOCK: - DEBUGP(DGPRS, "NSEI=%u Rx NS BLOCK\n", nsvc->nsei); + DEBUGP(DNS, "NSEI=%u Rx NS BLOCK\n", nsvc->nsei); nsvc->state |= NSE_S_BLOCKED; rc = gprs_ns_tx_simple(nsvc, NS_PDUT_UNBLOCK_ACK); break; case NS_PDUT_BLOCK_ACK: - DEBUGP(DGPRS, "NSEI=%u Rx NS BLOCK ACK\n", nsvc->nsei); + DEBUGP(DNS, "NSEI=%u Rx NS BLOCK ACK\n", nsvc->nsei); /* mark remote NS-VC as blocked + active */ nsvc->remote_state = NSE_S_BLOCKED | NSE_S_ALIVE; break; default: - DEBUGP(DGPRS, "NSEI=%u Rx Unknown NS PDU type 0x%02x\n", + DEBUGP(DNS, "NSEI=%u Rx Unknown NS PDU type 0x%02x\n", nsvc->nsei, nsh->pdu_type); rc = -EINVAL; break; @@ -533,7 +533,7 @@ static struct msgb *read_nsip_msg(struct bsc_fd *bfd, int *error, ret = recvfrom(bfd->fd, msg->data, NS_ALLOC_SIZE, 0, (struct sockaddr *)saddr, &saddr_len); if (ret < 0) { - LOGP(DGPRS, LOGL_ERROR, "recv error %s during NSIP recv\n", + LOGP(DNS, LOGL_ERROR, "recv error %s during NSIP recv\n", strerror(errno)); msgb_free(msg); *error = ret; @@ -634,7 +634,7 @@ struct gprs_nsvc *nsip_connect(struct gprs_ns_inst *nsi, /* Initiate a RESET procedure */ if (gprs_ns_tx_reset(nsvc, NS_CAUSE_OM_INTERVENTION) < 0) { - LOGP(DGPRS, LOGL_ERROR, "NSEI=%u, error resetting NS-VC\n", + LOGP(DNS, LOGL_ERROR, "NSEI=%u, error resetting NS-VC\n", nsei); } /* run a timer and re-transmit the reset request? */ diff --git a/openbsc/src/vty_interface_cmds.c b/openbsc/src/vty_interface_cmds.c index efcd6547b..0c1abfc96 100644 --- a/openbsc/src/vty_interface_cmds.c +++ b/openbsc/src/vty_interface_cmds.c @@ -142,7 +142,7 @@ DEFUN(logging_prnt_timestamp, } /* FIXME: those have to be kept in sync with the log levels and categories */ -#define VTY_DEBUG_CATEGORIES "(rll|cc|mm|rr|rsl|nm|sms|pag|mncc|inp|mi|mib|mux|meas|sccp|msc|mgcp|ho|db|ref|gprs)" +#define VTY_DEBUG_CATEGORIES "(rll|cc|mm|rr|rsl|nm|sms|pag|mncc|inp|mi|mib|mux|meas|sccp|msc|mgcp|ho|db|ref|gprs|ns|bssgp)" #define VTY_DEBUG_LEVELS "(everything|debug|info|notice|error|fatal)" DEFUN(logging_level, logging_level_cmd, -- cgit v1.2.3 From 99e3248192caa1348a28e4a5eda3db745960fd31 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 11 May 2010 06:20:54 +0200 Subject: [gprs] NS: Add signals in the event of BLOCK/UNBLOCK/RESET The signals will be sent upon reception of NS-BLOCK/UNBLOCK/RESET PDUs We also export functions to generate/send BLOCK/UNBLOCK and RESET. --- openbsc/include/openbsc/gprs_ns.h | 3 ++ openbsc/include/openbsc/signal.h | 12 ++++++ openbsc/src/gprs/gprs_ns.c | 77 +++++++++++++++++++++++++++++++++++++-- 3 files changed, 88 insertions(+), 4 deletions(-) diff --git a/openbsc/include/openbsc/gprs_ns.h b/openbsc/include/openbsc/gprs_ns.h index 27c54cb13..c74546a8b 100644 --- a/openbsc/include/openbsc/gprs_ns.h +++ b/openbsc/include/openbsc/gprs_ns.h @@ -167,6 +167,9 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, /* main function for higher layers (BSSGP) to send NS messages */ int gprs_ns_sendmsg(struct gprs_ns_inst *nsi, struct msgb *msg); +int gprs_ns_tx_reset(struct gprs_nsvc *nsvc, uint8_t cause); +int gprs_ns_tx_block(struct gprs_nsvc *nsvc, uint8_t cause); +int gprs_ns_tx_unblock(struct gprs_nsvc *nsvc); /* Listen for incoming GPRS packets */ int nsip_listen(struct gprs_ns_inst *nsi, uint16_t udp_port); diff --git a/openbsc/include/openbsc/signal.h b/openbsc/include/openbsc/signal.h index 73f3fe31a..6e0f5baca 100644 --- a/openbsc/include/openbsc/signal.h +++ b/openbsc/include/openbsc/signal.h @@ -42,6 +42,7 @@ enum signal_subsystems { SS_SCALL, SS_GLOBAL, SS_CHALLOC, + SS_NS, }; /* SS_PAGING signals */ @@ -144,4 +145,15 @@ struct challoc_signal_data { enum gsm_chan_t type; }; +enum signal_ns { + S_NS_RESET, + S_NS_BLOCK, + S_NS_UNBLOCK, +}; + +struct ns_signal_data { + struct gprs_nsvc *nsvc; + uint8_t cause; +}; + #endif diff --git a/openbsc/src/gprs/gprs_ns.c b/openbsc/src/gprs/gprs_ns.c index be3d1d93a..3fa2c0169 100644 --- a/openbsc/src/gprs/gprs_ns.c +++ b/openbsc/src/gprs/gprs_ns.c @@ -57,6 +57,7 @@ #include #include #include +#include #include #include @@ -128,6 +129,17 @@ static struct gprs_nsvc *nsvc_create(struct gprs_ns_inst *nsi, uint16_t nsvci) return nsvc; } +static void ns_dispatch_signal(struct nsvc *nsvc, unsigned int signal, + uint8_t cause) +{ + struct ns_signal_data nssd; + + nssd.nsvc = nsvc; + nssd.cause = cause; + + dispatch_signal(SS_NS, signal, &nssd); +} + /* Section 10.3.2, Table 13 */ static const struct value_string ns_cause_str[] = { { NS_CAUSE_TRANSIT_FAIL, "Transit network failure" }, @@ -183,7 +195,7 @@ static int gprs_ns_tx_simple(struct gprs_nsvc *nsvc, uint8_t pdu_type) return gprs_ns_tx(nsvc, msg); } -static int gprs_ns_tx_reset(struct gprs_nsvc *nsvc, uint8_t cause) +int gprs_ns_tx_reset(struct gprs_nsvc *nsvc, uint8_t cause) { struct msgb *msg = msgb_alloc(NS_ALLOC_SIZE, "GPRS/NS"); struct gprs_ns_hdr *nsh; @@ -204,6 +216,32 @@ static int gprs_ns_tx_reset(struct gprs_nsvc *nsvc, uint8_t cause) } +int gprs_ns_tx_block(struct gprs_nsvc *nsvc, uint8_t cause) +{ + struct msgb *msg = msgb_alloc(NS_ALLOC_SIZE, "GPRS/NS"); + struct gprs_ns_hdr *nsh; + uint16_t nsvci = htons(nsvc->nsvci); + + if (!msg) + return -ENOMEM; + + /* be conservative and mark it as blocked even now! */ + nsvc->state |= NSE_S_BLOCKED; + + nsh = (struct gprs_ns_hdr *) msgb_put(msg, sizeof(*nsh)); + nsh->pdu_type = NS_PDUT_BLOCK; + + msgb_tvlv_put(msg, NS_IE_CAUSE, 1, &cause); + msgb_tvlv_put(msg, NS_IE_VCI, 2, (uint8_t *) &nsvci); + + return gprs_ns_tx(nsvc, msg); +} + +int gprs_ns_tx_unblock(struct gprs_nsvc *nsvc) +{ + return gprs_ns_tx_simple(nsvc, NS_PDUT_UNBLOCK); +} + #define NS_ALIVE_RETRIES 10 /* after 3 failed retransmit we declare BTS as dead */ static const uint8_t timer_mode_tout[_NSVC_TIMER_NR] = { @@ -393,9 +431,41 @@ static int gprs_ns_rx_reset(struct gprs_nsvc *nsvc, struct msgb *msg) /* start the test procedure */ nsvc_start_timer(nsvc, NSVC_TIMER_TNS_ALIVE); + /* inform interested parties about the fact that this NSVC + * has received RESET */ + ns_dispatch_signal(nsvc, S_NS_RESET, cause); + return gprs_ns_tx_reset_ack(nsvc); } +static int gprs_ns_rx_block(struct gprs_nsvc *nsvc, struct msgb *msg) +{ + struct gprs_ns_hdr *nsh = (struct gprs_ns_hdr *) msg->l2h; + struct tlv_parsed tp; + uint8_t *cause; + int rc; + + DEBUGP(DNS, "NSEI=%u Rx NS BLOCK\n", nsvc->nsei); + + nsvc->state |= NSE_S_BLOCKED; + + rc = tlv_parse(&tp, &ns_att_tlvdef, nsh->data, msgb_l2len(msg), 0, 0); + + if (!TLVP_PRESENT(&tp, NS_IE_CAUSE) || + !TLVP_PRESENT(&tp, NS_IE_VCI)) { + /* FIXME: respond with NS_CAUSE_MISSING_ESSENT_IE */ + LOGP(DNS, LOGL_ERROR, "NS RESET Missing mandatory IE\n"); + return -EINVAL; + } + + cause = (uint8_t *) TLVP_VAL(&tp, NS_IE_CAUSE); + //nsvci = (uint16_t *) TLVP_VAL(&tp, NS_IE_VCI); + + ns_dispatch_signal(nsvc, S_NS_BLOCK, cause); + + return gprs_ns_tx_simple(nsvc, NS_PDUT_BLOCK_ACK); +} + /* main entry point, here incoming NS frames enter */ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, struct sockaddr_in *saddr) @@ -467,6 +537,7 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, /* Section 7.2: unblocking procedure */ DEBUGP(DNS, "NSEI=%u Rx NS UNBLOCK\n", nsvc->nsei); nsvc->state &= ~NSE_S_BLOCKED; + ns_dispatch_signal(nsvc, S_NS_UNBLOCK, 0); rc = gprs_ns_tx_simple(nsvc, NS_PDUT_UNBLOCK_ACK); break; case NS_PDUT_UNBLOCK_ACK: @@ -477,9 +548,7 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, nsvc->state = NSE_S_ALIVE; break; case NS_PDUT_BLOCK: - DEBUGP(DNS, "NSEI=%u Rx NS BLOCK\n", nsvc->nsei); - nsvc->state |= NSE_S_BLOCKED; - rc = gprs_ns_tx_simple(nsvc, NS_PDUT_UNBLOCK_ACK); + rc = gprs_ns_rx_block(nsvc, msg); break; case NS_PDUT_BLOCK_ACK: DEBUGP(DNS, "NSEI=%u Rx NS BLOCK ACK\n", nsvc->nsei); -- cgit v1.2.3 From c1c1dd260a02d7679f0e1aff28f319defed950eb Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 11 May 2010 06:34:24 +0200 Subject: [gprs] gb_proxy: Forward NS-RESET/NS-BLOCK/NS-UNBLOCK from SGSN to BTSs --- openbsc/include/openbsc/gb_proxy.h | 2 ++ openbsc/src/gprs/gb_proxy.c | 32 ++++++++++++++++++++++++++++++++ openbsc/src/gprs/gb_proxy_main.c | 1 + 3 files changed, 35 insertions(+) diff --git a/openbsc/include/openbsc/gb_proxy.h b/openbsc/include/openbsc/gb_proxy.h index 3b695e52a..db236b5d0 100644 --- a/openbsc/include/openbsc/gb_proxy.h +++ b/openbsc/include/openbsc/gb_proxy.h @@ -37,4 +37,6 @@ int gbproxy_parse_config(const char *config_file, struct gbproxy_config *cfg); /* Main input function for Gb proxy */ int gbprox_rcvmsg(struct msgb *msg, struct gprs_nsvc *nsvc, uint16_t ns_bvci); +int gbprox_signal(unsigned int subsys, unsigned int signal, + void *handler_data, void *signal_data); #endif diff --git a/openbsc/src/gprs/gb_proxy.c b/openbsc/src/gprs/gb_proxy.c index 3ed7fdfde..3c639437a 100644 --- a/openbsc/src/gprs/gb_proxy.c +++ b/openbsc/src/gprs/gb_proxy.c @@ -415,6 +415,38 @@ int gbprox_rcvmsg(struct msgb *msg, struct gprs_nsvc *nsvc, uint16_t ns_bvci) return rc; } +/* Signal handler for signals from NS layer */ +int gbprox_signal(unsigned int subsys, unsigned int signal, + void *handler_data, void *signal_data) +{ + struct ns_signal_data *nssd = signal_data; + struct gprs_nsvc *nsvc = nssd->nsvc; + struct gbprox_peer *peer; + + if (subsys != SS_NS) + return 0; + + /* We currently only care about signals from the SGSN */ + if (!nsvc->remote_end_is_sgsn) + return 0; + + /* iterate over all BTS peers and send the respective PDU */ + llist_for_each_entry(peer, &gbprox_bts_peers, list) { + switch (signal) { + case S_NS_RESET: + gprs_ns_tx_reset(peer->nsvc, nssd->cause); + break; + case S_NS_BLOCK: + gprs_ns_tx_block(peer->nsvc, nssd->cause); + break; + case S_NS_UNBLOCK: + gprs_ns_tx_unblock(peer->nsvc); + break; + } + } + return 0; +} + #include diff --git a/openbsc/src/gprs/gb_proxy_main.c b/openbsc/src/gprs/gb_proxy_main.c index 0054b7844..72f1417bc 100644 --- a/openbsc/src/gprs/gb_proxy_main.c +++ b/openbsc/src/gprs/gb_proxy_main.c @@ -118,6 +118,7 @@ int main(int argc, char **argv) exit(1); } gbcfg.nsi = gbprox_nsi; + register_signal_handler(SS_NS, &gbprox_signal, NULL); nsip_listen(gbprox_nsi, gbcfg.nsip_listen_port); /* 'establish' the outgoing connection to the SGSN */ -- cgit v1.2.3 From 0a4050c63b8ff1b80714aee6d6a133de79366eb9 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 11 May 2010 10:01:17 +0200 Subject: [gprs] gb_proxy: Send proper BSSGP STATUS msg in error case In order to reuse the existing bssgp_tx_* functions without pulling in the dependencies of gprs_bssgp.c, we have to move those functions to gprs_bssgp_util.c Furthermore, we can remove gbprox_nsi and replace it with bssgp_nsi, and we can do proper processing of BVC-RESET messages coming from the SGSN on the signalling BVC. In that case we need to send RESET messages to all the BSS. --- openbsc/include/openbsc/gprs_bssgp.h | 12 ++++ openbsc/src/gprs/Makefile.am | 5 +- openbsc/src/gprs/gb_proxy.c | 110 ++++++++++++++++++++------------ openbsc/src/gprs/gb_proxy_main.c | 13 ++-- openbsc/src/gprs/gprs_bssgp.c | 82 ------------------------ openbsc/src/gprs/gprs_bssgp_util.c | 119 +++++++++++++++++++++++++++++++++++ 6 files changed, 210 insertions(+), 131 deletions(-) create mode 100644 openbsc/src/gprs/gprs_bssgp_util.c diff --git a/openbsc/include/openbsc/gprs_bssgp.h b/openbsc/include/openbsc/gprs_bssgp.h index c1094b351..d3ccb12ee 100644 --- a/openbsc/include/openbsc/gprs_bssgp.h +++ b/openbsc/include/openbsc/gprs_bssgp.h @@ -137,6 +137,18 @@ enum gprs_bssgp_cause { /* Our implementation */ +/* gprs_bssgp_util.c */ +extern struct gprs_ns_inst *bssgp_nsi; +struct msgb *bssgp_msgb_alloc(void); +const char *bssgp_cause_str(enum gprs_bssgp_cause cause); +/* Transmit a simple response such as BLOCK/UNBLOCK/RESET ACK/NACK */ +int bssgp_tx_simple_bvci(uint8_t pdu_type, uint16_t nsei, + uint16_t bvci, uint16_t ns_bvci); +/* Chapter 10.4.14: Status */ +int bssgp_tx_status(uint8_t cause, uint16_t *bvci, struct msgb *orig_msg); + +/* gprs_bssgp.c */ + #include extern int gprs_bssgp_rcvmsg(struct msgb *msg); diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index 2b4292398..7cb7ba66a 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -6,10 +6,11 @@ sbin_PROGRAMS = osmo-gbproxy osmo-sgsn noinst_LIBRARIES = libsgsn.a libsgsn_a_SOURCES = gprs_ns.c gprs_bssgp.c gprs_llc.c gsm_04_08_gprs.c \ - crc24.c gprs_sgsn.c + crc24.c gprs_sgsn.c gprs_bssgp_util.c osmo_gbproxy_SOURCES = gb_proxy.c gb_proxy_main.c gb_proxy_vty.c \ - gprs_ns.c $(top_srcdir)/src/socket.c $(top_srcdir)/src/debug.c + gprs_ns.c gprs_bssgp_util.c \ + $(top_srcdir)/src/socket.c $(top_srcdir)/src/debug.c osmo_gbproxy_LDADD = $(top_builddir)/src/libvty.a osmo_sgsn_SOURCES = sgsn_main.c sgsn_vty.c \ diff --git a/openbsc/src/gprs/gb_proxy.c b/openbsc/src/gprs/gb_proxy.c index 3c639437a..ff80e92d4 100644 --- a/openbsc/src/gprs/gb_proxy.c +++ b/openbsc/src/gprs/gb_proxy.c @@ -55,8 +55,6 @@ struct gbprox_peer { /* Linked list of all Gb peers (except SGSN) */ static LLIST_HEAD(gbprox_bts_peers); -extern struct gprs_ns_inst *gbprox_nsi; - /* Find the gbprox_peer by its BVCI */ static struct gbprox_peer *peer_by_bvci(uint16_t bvci) { @@ -127,30 +125,6 @@ static void strip_ns_hdr(struct msgb *msg) msgb_pull(msg, strip_len); } -/* FIXME: this is copy+paste from gprs_bssgp.c */ -static inline struct msgb *bssgp_msgb_alloc(void) -{ - return msgb_alloc_headroom(4096, 128, "BSSGP"); -} -static int bssgp_tx_simple_bvci(uint8_t pdu_type, uint16_t nsei, - uint16_t bvci, uint16_t ns_bvci) -{ - struct msgb *msg = bssgp_msgb_alloc(); - struct bssgp_normal_hdr *bgph = - (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph)); - uint16_t _bvci; - - msgb_nsei(msg) = nsei; - msgb_bvci(msg) = ns_bvci; - - bgph->pdu_type = pdu_type; - _bvci = htons(bvci); - msgb_tvlv_put(msg, BSSGP_IE_BVCI, 2, (uint8_t *) &_bvci); - - return gprs_ns_sendmsg(gbprox_nsi, msg); -} - - /* feed a message down the NS-VC associated with the specified peer */ static int gbprox_relay2sgsn(struct msgb *msg, uint16_t ns_bvci) { @@ -162,7 +136,7 @@ static int gbprox_relay2sgsn(struct msgb *msg, uint16_t ns_bvci) strip_ns_hdr(msg); - return gprs_ns_sendmsg(gbprox_nsi, msg); + return gprs_ns_sendmsg(bssgp_nsi, msg); } /* feed a message down the NS-VC associated with the specified peer */ @@ -177,7 +151,7 @@ static int gbprox_relay2peer(struct msgb *msg, struct gbprox_peer *peer, strip_ns_hdr(msg); - return gprs_ns_sendmsg(gbprox_nsi, msg); + return gprs_ns_sendmsg(bssgp_nsi, msg); } /* Send a message to a peer identified by ptp_bvci but using ns_bvci @@ -274,9 +248,13 @@ static int gbprox_rx_sig_from_bss(struct msgb *msg, struct gprs_nsvc *nsvc, /* Normally, we can simply pass on all signalling messages from BSS to SGSN */ return gbprox_relay2sgsn(msg, ns_bvci); err_no_peer: + LOGP(DGPRS, LOGL_ERROR, "NSEI=%u(BSS) cannot find peer based on RAC\n", + nsvc->nsei); + return bssgp_tx_status(BSSGP_CAUSE_UNKNOWN_BVCI, NULL, msg); err_mand_ie: - /* FIXME: do something */ - ; + LOGP(DGPRS, LOGL_ERROR, "NSEI=%u(BSS) missing mandatory RA IE\n", + nsvc->nsei); + return bssgp_tx_status(BSSGP_CAUSE_MISSING_MAND_IE, NULL, msg); } /* Receive paging request from SGSN, we need to relay to proper BSS */ @@ -298,6 +276,42 @@ static int gbprox_rx_paging(struct msgb *msg, struct tlv_parsed *tp, return -EINVAL; } +/* Receive an incoming BVC-RESET message from the SGSN */ +static int rx_reset_from_sgsn(struct msgb *msg, struct tlv_parsed *tp, + struct gprs_nsvc *nsvc, uint16_t ns_bvci) +{ + struct gbprox_peer *peer; + uint16_t ptp_bvci; + + if (!TLVP_PRESENT(tp, BSSGP_IE_BVCI)) { + return bssgp_tx_status(BSSGP_CAUSE_MISSING_MAND_IE, + NULL, msg); + } + ptp_bvci = ntohs(*(uint16_t *)TLVP_VAL(tp, BSSGP_IE_BVCI)); + + if (ptp_bvci >= 2) { + /* A reset for a PTP BVC was received, forward it to its + * respective peer */ + peer = peer_by_bvci(ptp_bvci); + if (!peer) { + LOGP(DGPRS, LOGL_ERROR, "Cannot find BSS for BVCI %u\n", + ptp_bvci); + return bssgp_tx_status(BSSGP_CAUSE_UNKNOWN_BVCI, + NULL, msg); + } + return gbprox_relay2peer(msg, peer, ns_bvci); + } + + /* A reset for the Signalling entity has been received + * from the SGSN. As the signalling BVCI is shared + * among all the BSS's that we multiplex, it needs to + * be relayed */ + llist_for_each_entry(peer, &gbprox_bts_peers, list) + gbprox_relay2peer(msg, peer, ns_bvci); + + return 0; +} + /* Receive an incoming signalling message from the SGSN-side NS-VC */ static int gbprox_rx_sig_from_sgsn(struct msgb *msg, struct gprs_nsvc *nsvc, uint16_t ns_bvci) @@ -313,6 +327,7 @@ static int gbprox_rx_sig_from_sgsn(struct msgb *msg, struct gprs_nsvc *nsvc, if (ns_bvci != 0) { LOGP(DGPRS, LOGL_NOTICE, "NSEI=%u(SGSN) BVCI %u is not " "signalling\n", nsvc->nsei, ns_bvci); + /* FIXME: Send proper error message */ return -EINVAL; } @@ -322,16 +337,18 @@ static int gbprox_rx_sig_from_sgsn(struct msgb *msg, struct gprs_nsvc *nsvc, pdu_type == BSSGP_PDUT_DL_UNITDATA) { LOGP(DGPRS, LOGL_NOTICE, "NSEI=%u(SGSN) UNITDATA not allowed in " "signalling\n", nsvc->nsei); - return -EINVAL; + return bssgp_tx_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg); } rc = bssgp_tlv_parse(&tp, bgph->data, data_len); switch (pdu_type) { + case BSSGP_PDUT_BVC_RESET: + rc = rx_reset_from_sgsn(msg, &tp, nsvc, ns_bvci); + break; case BSSGP_PDUT_FLUSH_LL: case BSSGP_PDUT_BVC_BLOCK_ACK: case BSSGP_PDUT_BVC_UNBLOCK_ACK: - case BSSGP_PDUT_BVC_RESET: case BSSGP_PDUT_BVC_RESET_ACK: /* simple case: BVCI IE is mandatory */ if (!TLVP_PRESENT(&tp, BSSGP_IE_BVCI)) @@ -345,9 +362,22 @@ static int gbprox_rx_sig_from_sgsn(struct msgb *msg, struct gprs_nsvc *nsvc, rc = gbprox_rx_paging(msg, &tp, nsvc, ns_bvci); break; case BSSGP_PDUT_STATUS: - /* FIXME: Some exception has occurred */ + /* Some exception has occurred */ LOGP(DGPRS, LOGL_NOTICE, - "NSEI=%u(SGSN) STATUS not implemented yet\n", nsvc->nsei); + "NSEI=%u(SGSN) STATUS ", nsvc->nsei); + if (!TLVP_PRESENT(&tp, BSSGP_IE_CAUSE)) { + LOGPC(DGPRS, LOGL_NOTICE, "\n"); + goto err_mand_ie; + } + LOGPC(DGPRS, LOGL_NOTICE, + "cause=0x%02x(%s) ", *TLVP_VAL(&tp, BSSGP_IE_CAUSE), + bssgp_cause_str(*TLVP_VAL(&tp, BSSGP_IE_CAUSE))); + if (TLVP_PRESENT(&tp, BSSGP_IE_BVCI)) { + uint16_t *bvci = TLVP_VAL(&tp, BSSGP_IE_BVCI); + LOGPC(DGPRS, LOGL_NOTICE, + "BVCI=%u\n", ntohs(*bvci)); + } else + LOGPC(DGPRS, LOGL_NOTICE, "\n"); break; /* those only exist in the SGSN -> BSS direction */ case BSSGP_PDUT_SUSPEND_ACK: @@ -365,9 +395,11 @@ static int gbprox_rx_sig_from_sgsn(struct msgb *msg, struct gprs_nsvc *nsvc, case BSSGP_PDUT_SGSN_INVOKE_TRACE: LOGP(DGPRS, LOGL_ERROR, "NSEI=%u(SGSN) INVOKE TRACE not supported\n", nsvc->nsei); + rc = bssgp_tx_status(BSSGP_CAUSE_PDU_INCOMP_FEAT, NULL, msg); break; default: DEBUGP(DGPRS, "BSSGP PDU type 0x%02x unknown\n", pdu_type); + rc = bssgp_tx_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg); break; } @@ -375,13 +407,11 @@ static int gbprox_rx_sig_from_sgsn(struct msgb *msg, struct gprs_nsvc *nsvc, err_mand_ie: LOGP(DGPRS, LOGL_ERROR, "NSEI=%u(SGSN) missing mandatory IE\n", nsvc->nsei); - /* FIXME: this would pull gprs_bssgp.c in, which in turn has dependencies */ - //return bssgp_tx_status(BSSGP_CAUSE_MISSING_MAND_IE, NULL, msg); - return; + return bssgp_tx_status(BSSGP_CAUSE_MISSING_MAND_IE, NULL, msg); err_no_peer: - LOGP(DGPRS, LOGL_ERROR, "NSEI=%u(SGSN) cannot find peer based on RAC\n"); - /* FIXME */ - return; + LOGP(DGPRS, LOGL_ERROR, "NSEI=%u(SGSN) cannot find peer based on RAC\n", + nsvc->nsei); + return bssgp_tx_status(BSSGP_CAUSE_UNKNOWN_BVCI, NULL, msg); } /* Main input function for Gb proxy */ diff --git a/openbsc/src/gprs/gb_proxy_main.c b/openbsc/src/gprs/gb_proxy_main.c index 72f1417bc..1a5d7bd8d 100644 --- a/openbsc/src/gprs/gb_proxy_main.c +++ b/openbsc/src/gprs/gb_proxy_main.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include @@ -53,8 +54,6 @@ void subscr_put() { abort(); } void *tall_bsc_ctx; -struct gprs_ns_inst *gbprox_nsi; - const char *openbsc_version = "Osmocom NSIP Proxy " PACKAGE_VERSION; const char *openbsc_copyright = "Copyright (C) 2010 Harald Welte and On-Waves\n" @@ -112,20 +111,20 @@ int main(int argc, char **argv) exit(2); } - gbprox_nsi = gprs_ns_instantiate(&proxy_ns_cb); - if (!gbprox_nsi) { + bssgp_nsi = gprs_ns_instantiate(&proxy_ns_cb); + if (!bssgp_nsi) { LOGP(DGPRS, LOGL_ERROR, "Unable to instantiate NS\n"); exit(1); } - gbcfg.nsi = gbprox_nsi; + gbcfg.nsi = bssgp_nsi; register_signal_handler(SS_NS, &gbprox_signal, NULL); - nsip_listen(gbprox_nsi, gbcfg.nsip_listen_port); + nsip_listen(bssgp_nsi, gbcfg.nsip_listen_port); /* 'establish' the outgoing connection to the SGSN */ sin.sin_family = AF_INET; sin.sin_port = htons(gbcfg.nsip_sgsn_port); sin.sin_addr.s_addr = htonl(gbcfg.nsip_sgsn_ip); - nsip_connect(gbprox_nsi, &sin, gbcfg.nsip_sgsn_nsei, + nsip_connect(bssgp_nsi, &sin, gbcfg.nsip_sgsn_nsei, gbcfg.nsip_sgsn_nsvci); while (1) { diff --git a/openbsc/src/gprs/gprs_bssgp.c b/openbsc/src/gprs/gprs_bssgp.c index 0f658b993..b2f292858 100644 --- a/openbsc/src/gprs/gprs_bssgp.c +++ b/openbsc/src/gprs/gprs_bssgp.c @@ -39,43 +39,9 @@ /* global pointer to the gsm network data structure */ /* FIXME: this must go! */ extern struct gsm_network *bsc_gsmnet; -struct gprs_ns_inst *bssgp_nsi; void *bssgp_tall_ctx = NULL; -/* BSSGP Protocol specific, not implementation specific */ -/* FIXME: This needs to go into libosmocore after finished */ - -/* Chapter 11.3.9 / Table 11.10: Cause coding */ -static const struct value_string bssgp_cause_strings[] = { - { BSSGP_CAUSE_PROC_OVERLOAD, "Processor overload" }, - { BSSGP_CAUSE_EQUIP_FAIL, "Equipment Failure" }, - { BSSGP_CAUSE_TRASIT_NET_FAIL, "Transit netowkr service failure" }, - { BSSGP_CAUSE_CAPA_GREATER_0KPBS,"Transmission capacity modified" }, - { BSSGP_CAUSE_UNKNOWN_MS, "Unknown MS" }, - { BSSGP_CAUSE_UNKNOWN_BVCI, "Unknown BVCI" }, - { BSSGP_CAUSE_CELL_TRAF_CONG, "Cell traffic congestion" }, - { BSSGP_CAUSE_SGSN_CONG, "SGSN congestion" }, - { BSSGP_CAUSE_OML_INTERV, "O&M intervention" }, - { BSSGP_CAUSE_BVCI_BLOCKED, "BVCI blocked" }, - { BSSGP_CAUSE_PFC_CREATE_FAIL, "PFC create failure" }, - { BSSGP_CAUSE_SEM_INCORR_PDU, "Semantically incorrect PDU" }, - { BSSGP_CAUSE_INV_MAND_INF, "Invalid mandatory information" }, - { BSSGP_CAUSE_MISSING_MAND_IE, "Missing mandatory IE" }, - { BSSGP_CAUSE_MISSING_COND_IE, "Missing conditional IE" }, - { BSSGP_CAUSE_UNEXP_COND_IE, "Unexpected conditional IE" }, - { BSSGP_CAUSE_COND_IE_ERR, "Conditional IE error" }, - { BSSGP_CAUSE_PDU_INCOMP_STATE, "PDU incompatible with protocol state" }, - { BSSGP_CAUSE_PROTO_ERR_UNSPEC, "Protocol error - unspecified" }, - { BSSGP_CAUSE_PDU_INCOMP_FEAT, "PDU not compatible with feature set" }, - { 0, NULL }, -}; - -const char *bssgp_cause_str(enum gprs_bssgp_cause cause) -{ - return get_value_string(bssgp_cause_strings, cause); -} - /* Our actual implementation */ @@ -141,30 +107,6 @@ struct bssgp_btx_ctx *btsctx_alloc(uint16_t bvci, uint16_t nsei) return ctx; } -static inline struct msgb *bssgp_msgb_alloc(void) -{ - return msgb_alloc_headroom(4096, 128, "BSSGP"); -} - -/* Transmit a simple response such as BLOCK/UNBLOCK/RESET ACK/NACK */ -static int bssgp_tx_simple_bvci(uint8_t pdu_type, uint16_t nsei, - uint16_t bvci, uint16_t ns_bvci) -{ - struct msgb *msg = bssgp_msgb_alloc(); - struct bssgp_normal_hdr *bgph = - (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph)); - uint16_t _bvci; - - msgb_nsei(msg) = nsei; - msgb_bvci(msg) = ns_bvci; - - bgph->pdu_type = pdu_type; - _bvci = htons(bvci); - msgb_tvlv_put(msg, BSSGP_IE_BVCI, 2, (uint8_t *) &_bvci); - - return gprs_ns_sendmsg(bssgp_nsi, msg); -} - /* Chapter 10.4.5: Flow Control BVC ACK */ static int bssgp_tx_fc_bvc_ack(uint16_t nsei, uint8_t tag, uint16_t ns_bvci) { @@ -181,30 +123,6 @@ static int bssgp_tx_fc_bvc_ack(uint16_t nsei, uint8_t tag, uint16_t ns_bvci) return gprs_ns_sendmsg(bssgp_nsi, msg); } -/* Chapter 10.4.14: Status */ -int bssgp_tx_status(uint8_t cause, uint16_t *bvci, struct msgb *orig_msg) -{ - struct msgb *msg = bssgp_msgb_alloc(); - struct bssgp_normal_hdr *bgph = - (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph)); - - DEBUGPC(DBSSGP, "BSSGP: TX STATUS, cause=%s\n", bssgp_cause_str(cause)); - msgb_nsei(msg) = msgb_nsei(orig_msg); - msgb_bvci(msg) = 0; - - bgph->pdu_type = BSSGP_PDUT_STATUS; - msgb_tvlv_put(msg, BSSGP_IE_CAUSE, 1, &cause); - if (bvci) { - uint16_t _bvci = htons(*bvci); - msgb_tvlv_put(msg, BSSGP_IE_BVCI, 2, (uint8_t *) &_bvci); - } - if (orig_msg) - msgb_tvlv_put(msg, BSSGP_IE_PDU_IN_ERROR, - msgb_bssgp_len(orig_msg), msgb_bssgph(orig_msg)); - - return gprs_ns_sendmsg(bssgp_nsi, msg); -} - uint16_t bssgp_parse_cell_id(struct gprs_ra_id *raid, const uint8_t *buf) { /* 6 octets RAC */ diff --git a/openbsc/src/gprs/gprs_bssgp_util.c b/openbsc/src/gprs/gprs_bssgp_util.c new file mode 100644 index 000000000..d9b5175f6 --- /dev/null +++ b/openbsc/src/gprs/gprs_bssgp_util.c @@ -0,0 +1,119 @@ +/* GPRS BSSGP protocol implementation as per 3GPP TS 08.18 */ + +/* (C) 2009-2010 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 + +#include +#include +#include +#include + +struct gprs_ns_inst *bssgp_nsi; + +/* BSSGP Protocol specific, not implementation specific */ +/* FIXME: This needs to go into libosmocore after finished */ + +/* Chapter 11.3.9 / Table 11.10: Cause coding */ +static const struct value_string bssgp_cause_strings[] = { + { BSSGP_CAUSE_PROC_OVERLOAD, "Processor overload" }, + { BSSGP_CAUSE_EQUIP_FAIL, "Equipment Failure" }, + { BSSGP_CAUSE_TRASIT_NET_FAIL, "Transit netowkr service failure" }, + { BSSGP_CAUSE_CAPA_GREATER_0KPBS,"Transmission capacity modified" }, + { BSSGP_CAUSE_UNKNOWN_MS, "Unknown MS" }, + { BSSGP_CAUSE_UNKNOWN_BVCI, "Unknown BVCI" }, + { BSSGP_CAUSE_CELL_TRAF_CONG, "Cell traffic congestion" }, + { BSSGP_CAUSE_SGSN_CONG, "SGSN congestion" }, + { BSSGP_CAUSE_OML_INTERV, "O&M intervention" }, + { BSSGP_CAUSE_BVCI_BLOCKED, "BVCI blocked" }, + { BSSGP_CAUSE_PFC_CREATE_FAIL, "PFC create failure" }, + { BSSGP_CAUSE_SEM_INCORR_PDU, "Semantically incorrect PDU" }, + { BSSGP_CAUSE_INV_MAND_INF, "Invalid mandatory information" }, + { BSSGP_CAUSE_MISSING_MAND_IE, "Missing mandatory IE" }, + { BSSGP_CAUSE_MISSING_COND_IE, "Missing conditional IE" }, + { BSSGP_CAUSE_UNEXP_COND_IE, "Unexpected conditional IE" }, + { BSSGP_CAUSE_COND_IE_ERR, "Conditional IE error" }, + { BSSGP_CAUSE_PDU_INCOMP_STATE, "PDU incompatible with protocol state" }, + { BSSGP_CAUSE_PROTO_ERR_UNSPEC, "Protocol error - unspecified" }, + { BSSGP_CAUSE_PDU_INCOMP_FEAT, "PDU not compatible with feature set" }, + { 0, NULL }, +}; + +const char *bssgp_cause_str(enum gprs_bssgp_cause cause) +{ + return get_value_string(bssgp_cause_strings, cause); +} + + +struct msgb *bssgp_msgb_alloc(void) +{ + return msgb_alloc_headroom(4096, 128, "BSSGP"); +} + +/* Transmit a simple response such as BLOCK/UNBLOCK/RESET ACK/NACK */ +int bssgp_tx_simple_bvci(uint8_t pdu_type, uint16_t nsei, + uint16_t bvci, uint16_t ns_bvci) +{ + struct msgb *msg = bssgp_msgb_alloc(); + struct bssgp_normal_hdr *bgph = + (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph)); + uint16_t _bvci; + + msgb_nsei(msg) = nsei; + msgb_bvci(msg) = ns_bvci; + + bgph->pdu_type = pdu_type; + _bvci = htons(bvci); + msgb_tvlv_put(msg, BSSGP_IE_BVCI, 2, (uint8_t *) &_bvci); + + return gprs_ns_sendmsg(bssgp_nsi, msg); +} + +/* Chapter 10.4.14: Status */ +int bssgp_tx_status(uint8_t cause, uint16_t *bvci, struct msgb *orig_msg) +{ + struct msgb *msg = bssgp_msgb_alloc(); + struct bssgp_normal_hdr *bgph = + (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph)); + + DEBUGPC(DBSSGP, "BSSGP: TX STATUS, cause=%s\n", bssgp_cause_str(cause)); + msgb_nsei(msg) = msgb_nsei(orig_msg); + msgb_bvci(msg) = 0; + + bgph->pdu_type = BSSGP_PDUT_STATUS; + msgb_tvlv_put(msg, BSSGP_IE_CAUSE, 1, &cause); + if (bvci) { + uint16_t _bvci = htons(*bvci); + msgb_tvlv_put(msg, BSSGP_IE_BVCI, 2, (uint8_t *) &_bvci); + } + if (orig_msg) + msgb_tvlv_put(msg, BSSGP_IE_PDU_IN_ERROR, + msgb_bssgp_len(orig_msg), msgb_bssgph(orig_msg)); + + return gprs_ns_sendmsg(bssgp_nsi, msg); +} -- cgit v1.2.3 From a7a3194da83ac7d4372c9a96556936b918c98983 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 11 May 2010 10:05:12 +0200 Subject: [gprs] BSSGP: cosmetic cleanup --- openbsc/src/gprs/gprs_bssgp.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/openbsc/src/gprs/gprs_bssgp.c b/openbsc/src/gprs/gprs_bssgp.c index b2f292858..9fdfd329d 100644 --- a/openbsc/src/gprs/gprs_bssgp.c +++ b/openbsc/src/gprs/gprs_bssgp.c @@ -36,15 +36,8 @@ #include #include -/* global pointer to the gsm network data structure */ -/* FIXME: this must go! */ -extern struct gsm_network *bsc_gsmnet; - void *bssgp_tall_ctx = NULL; - -/* Our actual implementation */ - #define BVC_F_BLOCKED 0x0001 /* The per-BTS context that we keep on the SGSN side of the BSSGP link */ @@ -66,7 +59,7 @@ struct bssgp_bts_ctx { * lookup for every packet, similar to a routing cache */ //struct gprs_nsvc *nsvc; }; -LLIST_HEAD(bts_ctxts); +static LLIST_HEAD(bts_ctxts); /* Find a BTS Context based on parsed RA ID and Cell ID */ struct bssgp_bts_ctx *btsctx_by_raid_cid(const struct gprs_ra_id *raid, uint16_t cid) @@ -93,7 +86,7 @@ struct bssgp_bts_ctx *btsctx_by_bvci_nsei(uint16_t bvci, uint16_t nsei) return NULL; } -struct bssgp_btx_ctx *btsctx_alloc(uint16_t bvci, uint16_t nsei) +struct bssgp_bts_ctx *btsctx_alloc(uint16_t bvci, uint16_t nsei) { struct bssgp_bts_ctx *ctx; -- cgit v1.2.3 From 1389ac7d2a44d905b9830dbd73a90cab1cca1719 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 11 May 2010 10:15:26 +0200 Subject: [gprs] NS: cleanup / fix compiler warnings --- openbsc/src/gprs/gprs_ns.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/openbsc/src/gprs/gprs_ns.c b/openbsc/src/gprs/gprs_ns.c index 3fa2c0169..69c96ca37 100644 --- a/openbsc/src/gprs/gprs_ns.c +++ b/openbsc/src/gprs/gprs_ns.c @@ -129,7 +129,7 @@ static struct gprs_nsvc *nsvc_create(struct gprs_ns_inst *nsi, uint16_t nsvci) return nsvc; } -static void ns_dispatch_signal(struct nsvc *nsvc, unsigned int signal, +static void ns_dispatch_signal(struct gprs_nsvc *nsvc, unsigned int signal, uint8_t cause) { struct ns_signal_data nssd; @@ -291,6 +291,8 @@ static void gprs_ns_timer_cb(void *data) gprs_ns_tx_reset(nsvc, NS_CAUSE_OM_INTERVENTION); nsvc_start_timer(nsvc, NSVC_TIMER_TNS_RESET); break; + case _NSVC_TIMER_NR: + break; } } @@ -433,7 +435,7 @@ static int gprs_ns_rx_reset(struct gprs_nsvc *nsvc, struct msgb *msg) /* inform interested parties about the fact that this NSVC * has received RESET */ - ns_dispatch_signal(nsvc, S_NS_RESET, cause); + ns_dispatch_signal(nsvc, S_NS_RESET, *cause); return gprs_ns_tx_reset_ack(nsvc); } @@ -461,7 +463,7 @@ static int gprs_ns_rx_block(struct gprs_nsvc *nsvc, struct msgb *msg) cause = (uint8_t *) TLVP_VAL(&tp, NS_IE_CAUSE); //nsvci = (uint16_t *) TLVP_VAL(&tp, NS_IE_VCI); - ns_dispatch_signal(nsvc, S_NS_BLOCK, cause); + ns_dispatch_signal(nsvc, S_NS_BLOCK, *cause); return gprs_ns_tx_simple(nsvc, NS_PDUT_BLOCK_ACK); } -- cgit v1.2.3 From 7fc9822a74c62f4bf63b7312d2fdc52669eee8e1 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 11 May 2010 10:15:42 +0200 Subject: [gprs] Gb proxy: cosmetic cleanup --- openbsc/src/gprs/gb_proxy.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/openbsc/src/gprs/gb_proxy.c b/openbsc/src/gprs/gb_proxy.c index ff80e92d4..ea992e950 100644 --- a/openbsc/src/gprs/gb_proxy.c +++ b/openbsc/src/gprs/gb_proxy.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -214,7 +215,7 @@ static int gbprox_rx_sig_from_bss(struct msgb *msg, struct gprs_nsvc *nsvc, goto err_no_peer; memcpy(&from_peer->ra, TLVP_VAL(&tp, BSSGP_IE_ROUTEING_AREA), sizeof(&from_peer->ra)); - gsm48_parse_ra(&raid, &from_peer->ra); + gsm48_parse_ra(&raid, from_peer->ra); DEBUGP(DGPRS, "NSEI=%u RAC snooping: RAC %u/%u/%u/%u behind BVCI=%u, " "NSVCI=%u\n", nsvc->nsei, raid.mcc, raid.mnc, raid.lac, raid.rac , from_peer->bvci, nsvc->nsvci); @@ -373,7 +374,8 @@ static int gbprox_rx_sig_from_sgsn(struct msgb *msg, struct gprs_nsvc *nsvc, "cause=0x%02x(%s) ", *TLVP_VAL(&tp, BSSGP_IE_CAUSE), bssgp_cause_str(*TLVP_VAL(&tp, BSSGP_IE_CAUSE))); if (TLVP_PRESENT(&tp, BSSGP_IE_BVCI)) { - uint16_t *bvci = TLVP_VAL(&tp, BSSGP_IE_BVCI); + uint16_t *bvci = (uint16_t *) + TLVP_VAL(&tp, BSSGP_IE_BVCI); LOGPC(DGPRS, LOGL_NOTICE, "BVCI=%u\n", ntohs(*bvci)); } else @@ -488,7 +490,7 @@ gDEFUN(show_gbproxy, show_gbproxy_cmd, "show gbproxy", llist_for_each_entry(peer, &gbprox_bts_peers, list) { struct gprs_nsvc *nsvc = peer->nsvc; struct gprs_ra_id raid; - gsm48_parse_ra(&raid, &peer->ra); + gsm48_parse_ra(&raid, peer->ra); vty_out(vty, "NSEI %5u, NS-VC %5u, PTP-BVCI %u, " "RAC %u-%u-%u-%u%s", -- cgit v1.2.3 From 6fab236cbb5004f9832d3feefc32a481a55c8303 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 11 May 2010 10:21:45 +0200 Subject: logging: use 'logging level all' instead of 'logging set log level' 'logging level' can already parse a human-readable level such as 'debug' or 'notice'. By setting the global mask within the same command we can also parse it there. --- openbsc/src/vty_interface_cmds.c | 34 +++++++++++----------------------- 1 file changed, 11 insertions(+), 23 deletions(-) diff --git a/openbsc/src/vty_interface_cmds.c b/openbsc/src/vty_interface_cmds.c index 0c1abfc96..0af8995d0 100644 --- a/openbsc/src/vty_interface_cmds.c +++ b/openbsc/src/vty_interface_cmds.c @@ -142,7 +142,7 @@ DEFUN(logging_prnt_timestamp, } /* FIXME: those have to be kept in sync with the log levels and categories */ -#define VTY_DEBUG_CATEGORIES "(rll|cc|mm|rr|rsl|nm|sms|pag|mncc|inp|mi|mib|mux|meas|sccp|msc|mgcp|ho|db|ref|gprs|ns|bssgp)" +#define VTY_DEBUG_CATEGORIES "(rll|cc|mm|rr|rsl|nm|sms|pag|mncc|inp|mi|mib|mux|meas|sccp|msc|mgcp|ho|db|ref|gprs|ns|bssgp|all)" #define VTY_DEBUG_LEVELS "(everything|debug|info|notice|error|fatal)" DEFUN(logging_level, logging_level_cmd, @@ -159,13 +159,19 @@ DEFUN(logging_level, return CMD_WARNING; } - if (category < 0) { - vty_out(vty, "Invalid category `%s'%s", argv[0], VTY_NEWLINE); + if (level < 0) { + vty_out(vty, "Invalid level `%s'%s", argv[1], VTY_NEWLINE); return CMD_WARNING; } - if (level < 0) { - vty_out(vty, "Invalid level `%s'%s", argv[1], VTY_NEWLINE); + /* Check for special case where we want to set global log level */ + if (!strcmp(argv[0], "all")) { + log_set_log_level(conn->dbg, level); + return CMD_SUCCESS; + } + + if (category < 0) { + vty_out(vty, "Invalid category `%s'%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } @@ -192,23 +198,6 @@ DEFUN(logging_set_category_mask, return CMD_SUCCESS; } -DEFUN(logging_set_log_level, - logging_set_log_level_cmd, - "logging set log level <0-8>", - "Set the global log level. The value 0 implies no filtering.\n") -{ - struct telnet_connection *conn; - - conn = (struct telnet_connection *) vty->priv; - if (!conn->dbg) { - vty_out(vty, "Logging was not enabled.%s", VTY_NEWLINE); - return CMD_WARNING; - } - - log_set_log_level(conn->dbg, atoi(argv[0])); - return CMD_SUCCESS; -} - DEFUN(diable_logging, disable_logging_cmd, "logging disable", @@ -255,6 +244,5 @@ void openbsc_vty_add_cmds() install_element(VIEW_NODE, &logging_prnt_timestamp_cmd); install_element(VIEW_NODE, &logging_set_category_mask_cmd); install_element(VIEW_NODE, &logging_level_cmd); - install_element(VIEW_NODE, &logging_set_log_level_cmd); } -- cgit v1.2.3 From cd7c1beb6b718baa3bcd89055df96cd19e60dd82 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 11 May 2010 10:41:34 +0200 Subject: logging: Add interactive help If you press ? on the vty, you now get some more explanation about the logging categories and their meaning. --- openbsc/src/vty_interface_cmds.c | 47 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/openbsc/src/vty_interface_cmds.c b/openbsc/src/vty_interface_cmds.c index 0af8995d0..c1a5eee71 100644 --- a/openbsc/src/vty_interface_cmds.c +++ b/openbsc/src/vty_interface_cmds.c @@ -30,6 +30,8 @@ #include +#define LOGGING_STR "Configure log message to this terminal\n" + static void _vty_output(struct log_target *tgt, const char *line) { struct vty *vty = tgt->tgt_vty.vty; @@ -55,6 +57,7 @@ struct log_target *log_target_create_vty(struct vty *vty) DEFUN(enable_logging, enable_logging_cmd, "logging enable", + LOGGING_STR "Enables logging to this vty\n") { struct telnet_connection *conn; @@ -76,6 +79,7 @@ DEFUN(enable_logging, DEFUN(logging_fltr_imsi, logging_fltr_imsi_cmd, "logging filter imsi IMSI", + LOGGING_STR "Print all messages related to a IMSI\n") { struct telnet_connection *conn; @@ -93,6 +97,7 @@ DEFUN(logging_fltr_imsi, DEFUN(logging_fltr_all, logging_fltr_all_cmd, "logging filter all <0-1>", + LOGGING_STR "Print all messages to the console\n") { struct telnet_connection *conn; @@ -110,6 +115,7 @@ DEFUN(logging_fltr_all, DEFUN(logging_use_clr, logging_use_clr_cmd, "logging color <0-1>", + LOGGING_STR "Use color for printing messages\n") { struct telnet_connection *conn; @@ -127,6 +133,7 @@ DEFUN(logging_use_clr, DEFUN(logging_prnt_timestamp, logging_prnt_timestamp_cmd, "logging timestamp <0-1>", + LOGGING_STR "Print the timestamp of each message\n") { struct telnet_connection *conn; @@ -143,11 +150,47 @@ DEFUN(logging_prnt_timestamp, /* FIXME: those have to be kept in sync with the log levels and categories */ #define VTY_DEBUG_CATEGORIES "(rll|cc|mm|rr|rsl|nm|sms|pag|mncc|inp|mi|mib|mux|meas|sccp|msc|mgcp|ho|db|ref|gprs|ns|bssgp|all)" +#define CATEGORIES_HELP \ + "A-bis Radio Link Layer (RLL)\n" \ + "Layer3 Call Control (CC)\n" \ + "Layer3 Mobility Management (MM)\n" \ + "Layer3 Radio Resource (RR)\n" \ + "A-bis Radio Signalling Link (RSL)\n" \ + "A-bis Network Management / O&M (NM/OML)\n" \ + "Layer3 Short Messagaging Service (SMS)\n" \ + "Paging Subsystem\n" \ + "MNCC API for Call Control application\n" \ + "A-bis Input Subsystem\n" \ + "A-bis Input Driver for Signalling\n" \ + "A-bis Input Driver for B-Channel (voice data)\n" \ + "A-bis B-Channel / Sub-channel Multiplexer\n" \ + "Radio Measurements\n" \ + "SCCP\n" \ + "Mobile Switching Center\n" \ + "Media Gateway Control Protocol\n" \ + "Hand-over\n" \ + "Database Layer\n" \ + "Reference Counting\n" \ + "GPRS Core\n" \ + "GPRS Network Service (NS)\n" \ + "GPRS BSS Gateway Protocol (BSSGP)\n" \ + "Global setting for all subsytems\n" + #define VTY_DEBUG_LEVELS "(everything|debug|info|notice|error|fatal)" +#define LEVELS_HELP \ + "Log simply everything\n" \ + "Log debug messages and higher levels\n" \ + "Log informational messages and higher levels\n" \ + "Log noticable messages and higher levels\n" \ + "Log error messages and higher levels\n" \ + "Log only fatal messages\n" DEFUN(logging_level, logging_level_cmd, "logging level " VTY_DEBUG_CATEGORIES " " VTY_DEBUG_LEVELS, - "Set the log level for a specified category\n") + LOGGING_STR + "Set the log level for a specified category\n" + CATEGORIES_HELP + LEVELS_HELP) { struct telnet_connection *conn; int category = log_parse_category(argv[0]); @@ -184,6 +227,7 @@ DEFUN(logging_level, DEFUN(logging_set_category_mask, logging_set_category_mask_cmd, "logging set log mask MASK", + LOGGING_STR "Decide which categories to output.\n") { struct telnet_connection *conn; @@ -201,6 +245,7 @@ DEFUN(logging_set_category_mask, DEFUN(diable_logging, disable_logging_cmd, "logging disable", + LOGGING_STR "Disables logging to this vty\n") { struct telnet_connection *conn; -- cgit v1.2.3 From f171a6e4fc76ce9b0b0332ea890f0e8e449d26b2 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 11 May 2010 10:51:30 +0200 Subject: debug/logging: more verbose descriptions --- openbsc/src/debug.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/openbsc/src/debug.c b/openbsc/src/debug.c index 40bd52c6c..9218f6471 100644 --- a/openbsc/src/debug.c +++ b/openbsc/src/debug.c @@ -39,81 +39,81 @@ static const struct log_info_cat default_categories[] = { [DRLL] = { .name = "DRLL", - .description = "Radio Link Layer", + .description = "A-bis Radio Link Layer (RLL)", .color = "\033[1;31m", .enabled = 1, .loglevel = LOGL_NOTICE, }, [DCC] = { .name = "DCC", - .description = "Call Control", + .description = "Layer3 Call Control (CC)", .color = "\033[1;32m", .enabled = 1, .loglevel = LOGL_NOTICE, }, [DMM] = { .name = "DMM", - .description = "Mobility Management", + .description = "Layer3 Mobility Management (MM)", .color = "\033[1;33m", .enabled = 1, .loglevel = LOGL_NOTICE, }, [DRR] = { .name = "DRR", - .description = "Radio Resource", + .description = "Layer3 Radio Resource (RR)", .color = "\033[1;34m", .enabled = 1, .loglevel = LOGL_NOTICE, }, [DRSL] = { .name = "DRSL", - .description = "Radio Siganlling Link", + .description = "A-bis Radio Siganlling Link (RSL)", .color = "\033[1;35m", .enabled = 1, .loglevel = LOGL_NOTICE, }, [DNM] = { .name = "DNM", - .description = "Network Management (OML)", + .description = "A-bis Network Management / O&M (NM/OML)", .color = "\033[1;36m", .enabled = 1, .loglevel = LOGL_INFO, }, [DMNCC] = { .name = "DMNCC", - .description = "BSC<->MSC interface", + .description = "MNCC API for Call Control application", .color = "\033[1;39m", .enabled = 1, .loglevel = LOGL_NOTICE, }, [DSMS] = { .name = "DSMS", - .description = "Short Message Service", + .description = "Layer3 Short Message Service (SMS)", .color = "\033[1;37m", .enabled = 1, .loglevel = LOGL_NOTICE, }, [DPAG] = { .name = "DPAG", - .description = "Paging", + .description = "Paging Subsystem", .color = "\033[1;38m", .enabled = 1, .loglevel = LOGL_NOTICE, }, [DMEAS] = { .name = "DMEAS", - .description = "Measurement Processing", + .description = "Radio Measurement Processing", .enabled = 0, .loglevel = LOGL_NOTICE, }, [DMI] = { .name = "DMI", - .description = "mISDN Input Driver", + .description = "A-bis Input Driver for Signalling", .enabled = 0, .loglevel = LOGL_NOTICE, }, [DMIB] = { .name = "DMIB", - .description = "mISDN B-Channels", + .description = "A-bis Input Driver for B-Channels (voice)", .enabled = 0, .loglevel = LOGL_NOTICE, }, [DMUX] = { .name = "DMUX", - .description = "TRAU Frame Multiplex", + .description = "A-bis B-Subchannel TRAU Frame Multiplex", .enabled = 1, .loglevel = LOGL_NOTICE, }, [DINP] = { .name = "DINP", - .description = "Input Driver", + .description = "A-bis Intput Subsystem", .enabled = 1, .loglevel = LOGL_NOTICE, }, [DSCCP] = { @@ -138,7 +138,7 @@ static const struct log_info_cat default_categories[] = { }, [DDB] = { .name = "DDB", - .description = "Database", + .description = "Database Layer", .enabled = 1, .loglevel = LOGL_NOTICE, }, [DREF] = { @@ -153,12 +153,12 @@ static const struct log_info_cat default_categories[] = { }, [DNS] = { .name = "DNS", - .description = "GPRS Network Service", + .description = "GPRS Network Service (NS)", .enabled = 1, .loglevel = LOGL_DEBUG, }, [DBSSGP] = { .name = "DBSSGP", - .description = "GPRS BSSGP Protocol", + .description = "GPRS BSS Gateway Protocol (BSSGP)", .enabled = 1, .loglevel = LOGL_DEBUG, }, }; -- cgit v1.2.3 From 9ac2225ff43e7ec74ec6a629383899f3b6e78d2c Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 11 May 2010 11:19:40 +0200 Subject: logging: introuduce log_level_str() to obtain the name of a log level --- include/osmocore/logging.h | 1 + src/logging.c | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/include/osmocore/logging.h b/include/osmocore/logging.h index 93f18a07b..b9e0c8fd0 100644 --- a/include/osmocore/logging.h +++ b/include/osmocore/logging.h @@ -117,6 +117,7 @@ void log_set_print_timestamp(struct log_target *target, int); void log_set_log_level(struct log_target *target, int log_level); void log_parse_category_mask(struct log_target *target, const char* mask); int log_parse_level(const char *lvl); +const char *log_level_str(unsigned int lvl); int log_parse_category(const char *category); void log_set_category_filter(struct log_target *target, int category, int enable, int level); diff --git a/src/logging.c b/src/logging.c index 7c508771f..e5d459a07 100644 --- a/src/logging.c +++ b/src/logging.c @@ -58,6 +58,11 @@ int log_parse_level(const char *lvl) return get_string_value(loglevel_strs, lvl); } +const char *log_level_str(unsigned int lvl) +{ + return get_value_string(loglevel_strs, lvl); +} + int log_parse_category(const char *category) { int i; -- cgit v1.2.3 From 6f65696459cbdc3c6fb0bbcda22881deed2d4d8a Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 11 May 2010 11:12:37 +0200 Subject: logging: Add 'show logging vty' command to display current log config As the logging config is getting more and more complex, it is good if it can be displayed interactively. WARNING: This needs libosmocore 0.1.6 or later! --- openbsc/configure.in | 2 +- openbsc/src/vty_interface_cmds.c | 44 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/openbsc/configure.in b/openbsc/configure.in index 8201983f2..66d4ee1f3 100644 --- a/openbsc/configure.in +++ b/openbsc/configure.in @@ -18,7 +18,7 @@ dnl checks for libraries AC_SEARCH_LIBS(crypt, crypt, [LIBCRYPT="-lcrypt"; AC_DEFINE([VTY_CRYPT_PW], [], [Use crypt functionality of vty.])]) -PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 0.1.3) +PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 0.1.6) dnl checks for header files AC_HEADER_STDC diff --git a/openbsc/src/vty_interface_cmds.c b/openbsc/src/vty_interface_cmds.c index c1a5eee71..31818925f 100644 --- a/openbsc/src/vty_interface_cmds.c +++ b/openbsc/src/vty_interface_cmds.c @@ -262,6 +262,49 @@ DEFUN(diable_logging, return CMD_SUCCESS; } +static void vty_print_logtarget(struct vty *vty, const struct log_info *info, + const struct log_target *tgt) +{ + unsigned int i; + + vty_out(vty, " Global Loglevel: %s%s", + log_level_str(tgt->loglevel), VTY_NEWLINE); + vty_out(vty, " Use color: %s, Print Timestamp: %s%s", + tgt->use_color ? "On" : "Off", + tgt->print_timestamp ? "On" : "Off", VTY_NEWLINE); + + vty_out(vty, " Log Level specific information:%s", VTY_NEWLINE); + + for (i = 0; i < info->num_cat; i++) { + const struct log_category *cat = &tgt->categories[i]; + vty_out(vty, " %-10s %-10s %-8s %s%s", + info->cat[i].name+1, log_level_str(cat->loglevel), + cat->enabled ? "Enabled" : "Disabled", + info->cat[i].description, + VTY_NEWLINE); + } +} + +#define SHOW_LOG_STR "Show current logging configuration\n" + +DEFUN(show_logging_vty, + show_logging_vty_cmd, + "show logging vty", + SHOW_STR SHOW_LOG_STR + "Show current logging configuration for this vty\n") +{ + struct telnet_connection *conn; + + conn = (struct telnet_connection *) vty->priv; + if (!conn->dbg) { + vty_out(vty, "Logging was not enabled.%s", VTY_NEWLINE); + return CMD_WARNING; + } + vty_print_logtarget(vty, &log_info, conn->dbg); + + return CMD_SUCCESS; +} + void openbsc_vty_print_statistics(struct vty *vty, struct gsm_network *net) { vty_out(vty, "Channel Requests : %lu total, %lu no channel%s", @@ -289,5 +332,6 @@ void openbsc_vty_add_cmds() install_element(VIEW_NODE, &logging_prnt_timestamp_cmd); install_element(VIEW_NODE, &logging_set_category_mask_cmd); install_element(VIEW_NODE, &logging_level_cmd); + install_element(VIEW_NODE, &show_logging_vty_cmd); } -- cgit v1.2.3 From 7638af95fd08213aef4adb3c6399975fe3621855 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 11 May 2010 16:39:22 +0200 Subject: logging: add log_vty_{level,category}_string() --- include/osmocore/logging.h | 4 ++++ src/logging.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) diff --git a/include/osmocore/logging.h b/include/osmocore/logging.h index b9e0c8fd0..2e82959a8 100644 --- a/include/osmocore/logging.h +++ b/include/osmocore/logging.h @@ -128,4 +128,8 @@ struct log_target *log_target_create_stderr(void); void log_add_target(struct log_target *target); void log_del_target(struct log_target *target); +/* Gernerate command argument strings for VTY use */ +const char *log_vty_category_string(struct log_info *info); +const char *log_vty_level_string(struct log_info *info); + #endif /* _OSMOCORE_LOGGING_H */ diff --git a/src/logging.c b/src/logging.c index e5d459a07..e72a6e204 100644 --- a/src/logging.c +++ b/src/logging.c @@ -366,6 +366,52 @@ struct log_target *log_target_create_stderr(void) #endif /* stderr */ } +const char *log_vty_level_string(struct log_info *info) +{ + const struct value_string *vs; + unsigned int len = 3; /* ()\0 */ + char *str; + + for (vs = loglevel_strs; vs->value || vs->str; vs++) + len += strlen(vs->str) + 1; + + str = talloc_zero_size(NULL, len); + if (!str) + return NULL; + + str[0] = '('; + for (vs = loglevel_strs; vs->value || vs->str; vs++) { + strcat(str, vs->str); + strcat(str, "|"); + } + str[strlen(str)-1] = ')'; + + return str; +} + +const char *log_vty_category_string(struct log_info *info) +{ + unsigned int len = 3; /* "()\0" */ + unsigned int i; + char *str; + + for (i = 0; i < info->num_cat; i++) + len += strlen(info->cat[i].name) + 1; + + str = talloc_zero_size(NULL, len); + if (!str) + return NULL; + + str[0] = '('; + for (i = 0; i < info->num_cat; i++) { + strcat(str, info->cat[i].name+1); + strcat(str, "|"); + } + str[strlen(str)-1] = ')'; + + return str; +} + void log_init(const struct log_info *cat) { tall_log_ctx = talloc_named_const(NULL, 1, "logging"); -- cgit v1.2.3 From d7c02ad9dfeb8d7d893b211bbb99d7032ae872d4 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 11 May 2010 18:18:31 +0200 Subject: [gprs] NS: Make sure we include "Rx" in the log statement for NS RESET --- openbsc/src/gprs/gprs_ns.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/openbsc/src/gprs/gprs_ns.c b/openbsc/src/gprs/gprs_ns.c index 69c96ca37..bd9791afa 100644 --- a/openbsc/src/gprs/gprs_ns.c +++ b/openbsc/src/gprs/gprs_ns.c @@ -422,10 +422,14 @@ static int gprs_ns_rx_reset(struct gprs_nsvc *nsvc, struct msgb *msg) nsvci = (uint16_t *) TLVP_VAL(&tp, NS_IE_VCI); nsei = (uint16_t *) TLVP_VAL(&tp, NS_IE_NSEI); - DEBUGP(DNS, "NSEI=%u NS RESET (NSVCI=%u, cause=%s)\n", + DEBUGP(DNS, "NSEI=%u Rx NS RESET (NSVCI=%u, cause=%s)\n", nsvc->nsvci, nsvc->nsei, gprs_ns_cause_str(*cause)); nsvc->state = NSE_S_BLOCKED | NSE_S_ALIVE; + /* FIXME: Check if we have an existing peer with this NSEI/NSVCI + * and remove it, as our BSS may just have changed its source IP + * address */ + nsvc->nsei = ntohs(*nsei); nsvc->nsvci = ntohs(*nsvci); -- cgit v1.2.3 From f69c059a0ebf9a5b1e5f11bff8527a8ba9ed0a16 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 11 May 2010 18:29:44 +0200 Subject: [gprs] gb_proxy: Fix detecting the SGSN-facing ns-vc by its NSEI make sure we mark the NS connection as 'SGSN-facing' if the NSEI matches --- openbsc/src/gprs/gb_proxy.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/openbsc/src/gprs/gb_proxy.c b/openbsc/src/gprs/gb_proxy.c index ea992e950..6c912db4c 100644 --- a/openbsc/src/gprs/gb_proxy.c +++ b/openbsc/src/gprs/gb_proxy.c @@ -458,6 +458,14 @@ int gbprox_signal(unsigned int subsys, unsigned int signal, if (subsys != SS_NS) return 0; + if (signal == S_NS_RESET && nsvc->nsei == gbcfg.nsip_sgsn_nsei) { + /* We have received a NS-RESET from the NSEI and NSVC + * of the SGSN. This might happen with SGSN that start + * their own NS-RESET procedure without waiting for our + * NS-RESET */ + nsvc->remote_end_is_sgsn = 1; + } + /* We currently only care about signals from the SGSN */ if (!nsvc->remote_end_is_sgsn) return 0; -- cgit v1.2.3 From e5117da715f4f654671e39c36b9085a3a1c3141f Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 11 May 2010 18:30:37 +0200 Subject: [gprs] gb-proxy: We might receive a NS-RESET for a NS-VC that we already know In this case, don't blindly allocate a new NS-VC but rather use the NSEI to lookup the 'struct gprs_nsvc' for it. --- openbsc/src/gprs/gprs_ns.c | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/openbsc/src/gprs/gprs_ns.c b/openbsc/src/gprs/gprs_ns.c index bd9791afa..3d05dd0ff 100644 --- a/openbsc/src/gprs/gprs_ns.c +++ b/openbsc/src/gprs/gprs_ns.c @@ -483,6 +483,8 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, /* look up the NSVC based on source address */ nsvc = nsvc_by_rem_addr(nsi, saddr); if (!nsvc) { + struct tlv_parsed tp; + uint16_t nsei; /* Only the RESET procedure creates a new NSVC */ if (nsh->pdu_type != NS_PDUT_RESET) { LOGP(DNS, LOGL_INFO, "Ignoring NS PDU type 0x%0x " @@ -491,10 +493,25 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, //gprs_ns_tx_reset(nsvc, NS_CAUSE_NSVC_UNKNOWN); return -EIO; } - LOGP(DNS, LOGL_INFO, "Creating NS-VC for BSS at %s:%u\n", - inet_ntoa(saddr->sin_addr), ntohs(saddr->sin_port)); - nsvc = nsvc_create(nsi, 0xffff); - nsvc->ip.bts_addr = *saddr; + rc = tlv_parse(&tp, &ns_att_tlvdef, nsh->data, + msgb_l2len(msg), 0, 0); + if (!TLVP_PRESENT(&tp, NS_IE_CAUSE) || + !TLVP_PRESENT(&tp, NS_IE_VCI) || + !TLVP_PRESENT(&tp, NS_IE_NSEI)) { + /* FIXME: respond with NS_CAUSE_MISSING_ESSENT_IE */ + LOGP(DNS, LOGL_ERROR, "NS RESET Missing mandatory IE\n"); + return -EINVAL; + } + nsei = ntohs(*(uint16_t *)TLVP_VAL(&tp, NS_IE_NSEI)); + /* Check if we already know this NSEI, the remote end might + * simply have changed addresses, or it is a SGSN */ + nsvc = nsvc_by_nsei(nsi, nsei); + if (!nsvc) { + LOGP(DNS, LOGL_INFO, "Creating NS-VC for BSS at %s:%u\n", + inet_ntoa(saddr->sin_addr), ntohs(saddr->sin_port)); + nsvc = nsvc_create(nsi, 0xffff); + nsvc->ip.bts_addr = *saddr; + } } else msgb_nsei(msg) = nsvc->nsei; -- cgit v1.2.3 From e69b2814e2e8f5923bfa9e45004c5d6e20e10d3d Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 11 May 2010 18:32:37 +0200 Subject: [gprs] use TCP port 4246 for the gb_proxy vty telnet --- openbsc/src/gprs/gb_proxy_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openbsc/src/gprs/gb_proxy_main.c b/openbsc/src/gprs/gb_proxy_main.c index 1a5d7bd8d..7aeb5e41b 100644 --- a/openbsc/src/gprs/gb_proxy_main.c +++ b/openbsc/src/gprs/gb_proxy_main.c @@ -104,7 +104,7 @@ int main(int argc, char **argv) log_add_target(stderr_target); log_set_all_filter(stderr_target, 1); - telnet_init(&dummy_network, 4244); + telnet_init(&dummy_network, 4246); rc = gbproxy_parse_config(config_file, &gbcfg); if (rc < 0) { LOGP(DGPRS, LOGL_FATAL, "Cannot parse config file\n"); -- cgit v1.2.3 From ef1226e827a4063ebe6cb018a148c2fa6fed0dea Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 11 May 2010 18:38:36 +0200 Subject: [gprs] NS: include port number in log statement --- openbsc/src/gprs/gprs_ns.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/openbsc/src/gprs/gprs_ns.c b/openbsc/src/gprs/gprs_ns.c index 3d05dd0ff..9c0c4ec91 100644 --- a/openbsc/src/gprs/gprs_ns.c +++ b/openbsc/src/gprs/gprs_ns.c @@ -488,8 +488,9 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, /* Only the RESET procedure creates a new NSVC */ if (nsh->pdu_type != NS_PDUT_RESET) { LOGP(DNS, LOGL_INFO, "Ignoring NS PDU type 0x%0x " - "from %s for non-existing NS-VC\n", - nsh->pdu_type, inet_ntoa(saddr->sin_addr)); + "from %s:%u for non-existing NS-VC\n", + nsh->pdu_type, inet_ntoa(saddr->sin_addr), + ntohs(saddr->sin_port)); //gprs_ns_tx_reset(nsvc, NS_CAUSE_NSVC_UNKNOWN); return -EIO; } -- cgit v1.2.3 From 7c209ebb86888a686e97e22d68b46f668f02a680 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 11 May 2010 18:40:45 +0200 Subject: [gprs] NS: update the remote peer IP addr/port on NS RESET --- openbsc/src/gprs/gprs_ns.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openbsc/src/gprs/gprs_ns.c b/openbsc/src/gprs/gprs_ns.c index 9c0c4ec91..745a0b57f 100644 --- a/openbsc/src/gprs/gprs_ns.c +++ b/openbsc/src/gprs/gprs_ns.c @@ -511,8 +511,9 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, LOGP(DNS, LOGL_INFO, "Creating NS-VC for BSS at %s:%u\n", inet_ntoa(saddr->sin_addr), ntohs(saddr->sin_port)); nsvc = nsvc_create(nsi, 0xffff); - nsvc->ip.bts_addr = *saddr; } + /* Update the remote peer IP address/port */ + nsvc->ip.bts_addr = *saddr; } else msgb_nsei(msg) = nsvc->nsei; -- cgit v1.2.3 From e9ea26935ef53f1b860b1d3bf85644a174de0f9c Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 11 May 2010 20:20:13 +0200 Subject: [gprs] gb_proxy: more verbose debugging --- openbsc/src/gprs/gb_proxy.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/openbsc/src/gprs/gb_proxy.c b/openbsc/src/gprs/gb_proxy.c index 6c912db4c..fd932523b 100644 --- a/openbsc/src/gprs/gb_proxy.c +++ b/openbsc/src/gprs/gb_proxy.c @@ -129,7 +129,7 @@ static void strip_ns_hdr(struct msgb *msg) /* feed a message down the NS-VC associated with the specified peer */ static int gbprox_relay2sgsn(struct msgb *msg, uint16_t ns_bvci) { - DEBUGP(DGPRS, "NSEI=%u proxying to SGSN (NS_BVCI=%u, NSEI=%u)\n", + DEBUGP(DGPRS, "NSEI=%u proxying BTS->SGSN (NS_BVCI=%u, NSEI=%u)\n", msgb_nsei(msg), ns_bvci, gbcfg.nsip_sgsn_nsei); msgb_bvci(msg) = ns_bvci; @@ -144,7 +144,7 @@ static int gbprox_relay2sgsn(struct msgb *msg, uint16_t ns_bvci) static int gbprox_relay2peer(struct msgb *msg, struct gbprox_peer *peer, uint16_t ns_bvci) { - DEBUGP(DGPRS, "NSEI=%u proxying to BSS (NS_BVCI=%u, NSEI=%u)\n", + DEBUGP(DGPRS, "NSEI=%u proxying to SGSN->BSS (NS_BVCI=%u, NSEI=%u)\n", msgb_nsei(msg), ns_bvci, peer->nsvc->nsei); msgb_bvci(msg) = ns_bvci; @@ -227,9 +227,11 @@ static int gbprox_rx_sig_from_bss(struct msgb *msg, struct gprs_nsvc *nsvc, * is common for all point-to-point BVCs (and thus all BTS) */ if (TLVP_PRESENT(&tp, BSSGP_IE_BVCI)) { uint16_t bvci = ntohs(*(uint16_t *)TLVP_VAL(&tp, BSSGP_IE_BVCI)); + LOGP(DGPRS, LOGL_DEBUG, "NSEI=%u Rx BVC RESET (BVCI=%u)\n", + nsvc->nsei, bvci); if (bvci == 0) { /* FIXME: only do this if SGSN is alive! */ - LOGP(DGPRS, LOGL_INFO, "NSEI=%u Sending fake " + LOGP(DGPRS, LOGL_INFO, "NSEI=%u Tx fake " "BVC RESET ACK of BVCI=0\n", nsvc->nsei); return bssgp_tx_simple_bvci(BSSGP_PDUT_BVC_RESET_ACK, nsvc->nsei, 0, ns_bvci); @@ -246,7 +248,8 @@ static int gbprox_rx_sig_from_bss(struct msgb *msg, struct gprs_nsvc *nsvc, break; } - /* Normally, we can simply pass on all signalling messages from BSS to SGSN */ + /* Normally, we can simply pass on all signalling messages from BSS to + * SGSN */ return gbprox_relay2sgsn(msg, ns_bvci); err_no_peer: LOGP(DGPRS, LOGL_ERROR, "NSEI=%u(BSS) cannot find peer based on RAC\n", -- cgit v1.2.3 From 8f0ed55b526b689c4bcb275478eac929fe23deb5 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 11 May 2010 21:53:49 +0200 Subject: VTY: More context sensitive help messages --- openbsc/src/vty_interface.c | 103 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 87 insertions(+), 16 deletions(-) diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c index 851a6039d..547681ce3 100644 --- a/openbsc/src/vty_interface.c +++ b/openbsc/src/vty_interface.c @@ -432,7 +432,9 @@ static void trx_dump_vty(struct vty *vty, struct gsm_bts_trx *trx) DEFUN(show_trx, show_trx_cmd, "show trx [bts_nr] [trx_nr]", - SHOW_STR "Display information about a TRX\n") + SHOW_STR "Display information about a TRX\n" + "BTS Number\n" + "TRX Number\n") { struct gsm_network *net = gsmnet; struct gsm_bts *bts = NULL; @@ -497,7 +499,8 @@ static void ts_dump_vty(struct vty *vty, struct gsm_bts_trx_ts *ts) DEFUN(show_ts, show_ts_cmd, "show timeslot [bts_nr] [trx_nr] [ts_nr]", - SHOW_STR "Display information about a TS\n") + SHOW_STR "Display information about a TS\n" + "BTS Number\n" "TRX Number\n" "Timeslot Number\n") { struct gsm_network *net = gsmnet; struct gsm_bts *bts; @@ -666,7 +669,9 @@ static void call_dump_vty(struct vty *vty, struct gsm_call *call) DEFUN(show_lchan, show_lchan_cmd, "show lchan [bts_nr] [trx_nr] [ts_nr] [lchan_nr]", - SHOW_STR "Display information about a logical channel\n") + SHOW_STR "Display information about a logical channel\n" + "BTS Number\n" "TRX Number\n" "Timeslot Number\n" + "Logical Channel Number\n") { struct gsm_network *net = gsmnet; struct gsm_bts *bts; @@ -762,7 +767,8 @@ static void e1line_dump_vty(struct vty *vty, struct e1inp_line *line) DEFUN(show_e1line, show_e1line_cmd, "show e1_line [line_nr]", - SHOW_STR "Display information about a E1 line\n") + SHOW_STR "Display information about a E1 line\n" + "E1 Line Number\n") { struct e1inp_line *line; @@ -795,7 +801,8 @@ static void e1ts_dump_vty(struct vty *vty, struct e1inp_ts *ts) DEFUN(show_e1ts, show_e1ts_cmd, "show e1_timeslot [line_nr] [ts_nr]", - SHOW_STR "Display information about a E1 timeslot\n") + SHOW_STR "Display information about a E1 timeslot\n" + "E1 Line Number\n" "E1 Timeslot Number\n") { struct e1inp_line *line = NULL; struct e1inp_ts *ts; @@ -859,7 +866,8 @@ static void bts_paging_dump_vty(struct vty *vty, struct gsm_bts *bts) DEFUN(show_paging, show_paging_cmd, "show paging [bts_nr]", - SHOW_STR "Display information about paging reuqests of a BTS\n") + SHOW_STR "Display information about paging reuqests of a BTS\n" + "BTS Number\n") { struct gsm_network *net = gsmnet; struct gsm_bts *bts; @@ -886,10 +894,11 @@ DEFUN(show_paging, return CMD_SUCCESS; } +#define NETWORK_STR "Configure the GSM network\n" + DEFUN(cfg_net, cfg_net_cmd, - "network", - "Configure the GSM network") + "network", NETWORK_STR) { vty->index = gsmnet; vty->node = GSMNET_NODE; @@ -947,7 +956,11 @@ DEFUN(cfg_net_name_long, DEFUN(cfg_net_auth_policy, cfg_net_auth_policy_cmd, "auth policy (closed|accept-all|token)", - "Set the GSM network authentication policy\n") + "Authentication (not cryptographic)\n" + "Set the GSM network authentication policy\n" + "Require the MS to be activated in HLR\n" + "Accept all MS, whether in HLR or not\n" + "Use SMS-token based authentication\n") { enum gsm_auth_policy policy = gsm_auth_policy_parse(argv[0]); @@ -987,7 +1000,12 @@ DEFUN(cfg_net_neci, DEFUN(cfg_net_rrlp_mode, cfg_net_rrlp_mode_cmd, "rrlp mode (none|ms-based|ms-preferred|ass-preferred)", - "Set the Radio Resource Location Protocol Mode") + "Radio Resource Location Protocol\n" + "Set the Radio Resource Location Protocol Mode\n" + "Don't send RRLP request\n" + "Request MS-based location\n" + "Request any location, prefer MS-based\n" + "Request any location, prefer MS-assisted\n") { gsmnet->rrlp.mode = rrlp_mode_parse(argv[0]); @@ -1003,9 +1021,13 @@ DEFUN(cfg_net_mm_info, cfg_net_mm_info_cmd, return CMD_SUCCESS; } +#define HANDOVER_STR "Handover Options\n" + DEFUN(cfg_net_handover, cfg_net_handover_cmd, "handover (0|1)", - "Whether or not to use in-call handover") + HANDOVER_STR + "Don't perform in-call handover\n" + "Perform in-call handover\n") { int enable = atoi(argv[0]); @@ -1020,8 +1042,14 @@ DEFUN(cfg_net_handover, cfg_net_handover_cmd, return CMD_SUCCESS; } +#define HO_WIN_STR HANDOVER_STR "Measurement Window\n" +#define HO_WIN_RXLEV_STR HO_WIN_STR "Received Level Averaging\n" +#define HO_WIN_RXQUAL_STR HO_WIN_STR "Received Quality Averaging\n" +#define HO_PBUDGET_STR HANDOVER_STR "Power Budget\n" + DEFUN(cfg_net_ho_win_rxlev_avg, cfg_net_ho_win_rxlev_avg_cmd, "handover window rxlev averaging <1-10>", + HO_WIN_RXLEV_STR "How many RxLev measurements are used for averaging") { gsmnet->handover.win_rxlev_avg = atoi(argv[0]); @@ -1030,6 +1058,7 @@ DEFUN(cfg_net_ho_win_rxlev_avg, cfg_net_ho_win_rxlev_avg_cmd, DEFUN(cfg_net_ho_win_rxqual_avg, cfg_net_ho_win_rxqual_avg_cmd, "handover window rxqual averaging <1-10>", + HO_WIN_RXQUAL_STR "How many RxQual measurements are used for averaging") { gsmnet->handover.win_rxqual_avg = atoi(argv[0]); @@ -1038,6 +1067,7 @@ DEFUN(cfg_net_ho_win_rxqual_avg, cfg_net_ho_win_rxqual_avg_cmd, DEFUN(cfg_net_ho_win_rxlev_neigh_avg, cfg_net_ho_win_rxlev_avg_neigh_cmd, "handover window rxlev neighbor averaging <1-10>", + HO_WIN_RXLEV_STR "How many RxQual measurements are used for averaging") { gsmnet->handover.win_rxlev_avg_neigh = atoi(argv[0]); @@ -1046,6 +1076,7 @@ DEFUN(cfg_net_ho_win_rxlev_neigh_avg, cfg_net_ho_win_rxlev_avg_neigh_cmd, DEFUN(cfg_net_ho_pwr_interval, cfg_net_ho_pwr_interval_cmd, "handover power budget interval <1-99>", + HO_PBUDGET_STR "How often to check if we have a better cell (SACCH frames)") { gsmnet->handover.pwr_interval = atoi(argv[0]); @@ -1054,6 +1085,7 @@ DEFUN(cfg_net_ho_pwr_interval, cfg_net_ho_pwr_interval_cmd, DEFUN(cfg_net_ho_pwr_hysteresis, cfg_net_ho_pwr_hysteresis_cmd, "handover power budget hysteresis <0-999>", + HO_PBUDGET_STR "How many dB does a neighbor to be stronger to become a HO candidate") { gsmnet->handover.pwr_hysteresis = atoi(argv[0]); @@ -1062,6 +1094,7 @@ DEFUN(cfg_net_ho_pwr_hysteresis, cfg_net_ho_pwr_hysteresis_cmd, DEFUN(cfg_net_ho_max_distance, cfg_net_ho_max_distance_cmd, "handover maximum distance <0-9999>", + HANDOVER_STR "How big is the maximum timing advance before HO is forced") { gsmnet->handover.max_distance = atoi(argv[0]); @@ -1072,6 +1105,7 @@ DEFUN(cfg_net_ho_max_distance, cfg_net_ho_max_distance_cmd, DEFUN(cfg_net_T##number, \ cfg_net_T##number##_cmd, \ "timer t" #number " <0-65535>", \ + "Configure GSM Timers\n" \ doc) \ { \ int value = atoi(argv[0]); \ @@ -1103,7 +1137,8 @@ DECLARE_TIMER(3141, "Currently not used.") DEFUN(cfg_bts, cfg_bts_cmd, "bts BTS_NR", - "Select a BTS to configure\n") + "Select a BTS to configure\n" + "BTS Number\n") { int bts_nr = atoi(argv[0]); struct gsm_bts *bts; @@ -1266,9 +1301,13 @@ DEFUN(cfg_bts_unit_id, return CMD_SUCCESS; } +#define OML_STR "Organization & Maintenance Link\n" +#define IPA_STR "ip.access Specific Options\n" + DEFUN(cfg_bts_stream_id, cfg_bts_stream_id_cmd, "oml ip.access stream_id <0-255>", + OML_STR IPA_STR "Set the ip.access Stream ID of the OML link of this BTS\n") { struct gsm_bts *bts = vty->index; @@ -1284,10 +1323,12 @@ DEFUN(cfg_bts_stream_id, return CMD_SUCCESS; } +#define OML_E1_STR OML_STR "E1 Line\n" DEFUN(cfg_bts_oml_e1, cfg_bts_oml_e1_cmd, "oml e1 line E1_LINE timeslot <1-31> sub-slot (0|1|2|3|full)", + OML_E1_STR "E1 interface to be used for OML\n") { struct gsm_bts *bts = vty->index; @@ -1301,6 +1342,7 @@ DEFUN(cfg_bts_oml_e1, DEFUN(cfg_bts_oml_e1_tei, cfg_bts_oml_e1_tei_cmd, "oml e1 tei <0-63>", + OML_E1_STR "Set the TEI to be used for OML") { struct gsm_bts *bts = vty->index; @@ -1312,7 +1354,9 @@ DEFUN(cfg_bts_oml_e1_tei, DEFUN(cfg_bts_challoc, cfg_bts_challoc_cmd, "channel allocator (ascending|descending)", - "Should the channel allocator allocate in reverse TRX order?") + "Channnel Allocator\n" "Channel Allocator\n" + "Allocate Timeslots and Transceivers in ascending order\n" + "Allocate Timeslots and Transceivers in descending order\n") { struct gsm_bts *bts = vty->index; @@ -1324,9 +1368,12 @@ DEFUN(cfg_bts_challoc, cfg_bts_challoc_cmd, return CMD_SUCCESS; } +#define RACH_STR "Random Access Control Channel\n" + DEFUN(cfg_bts_rach_tx_integer, cfg_bts_rach_tx_integer_cmd, "rach tx integer <0-15>", + RACH_STR "Set the raw tx integer value in RACH Control parameters IE") { struct gsm_bts *bts = vty->index; @@ -1337,6 +1384,7 @@ DEFUN(cfg_bts_rach_tx_integer, DEFUN(cfg_bts_rach_max_trans, cfg_bts_rach_max_trans_cmd, "rach max transmission (1|2|4|7)", + RACH_STR "Set the maximum number of RACH burst transmissions") { struct gsm_bts *bts = vty->index; @@ -1344,10 +1392,13 @@ DEFUN(cfg_bts_rach_max_trans, return CMD_SUCCESS; } +#define NM_STR "Network Management\n" + DEFUN(cfg_bts_rach_nm_b_thresh, cfg_bts_rach_nm_b_thresh_cmd, "rach nm busy threshold <0-255>", - "Set the NM Busy Threshold in DB") + RACH_STR NM_STR + "Set the NM Busy Threshold in dB") { struct gsm_bts *bts = vty->index; bts->rach_b_thresh = atoi(argv[0]); @@ -1357,7 +1408,8 @@ DEFUN(cfg_bts_rach_nm_b_thresh, DEFUN(cfg_bts_rach_nm_ldavg, cfg_bts_rach_nm_ldavg_cmd, "rach nm load average <0-65535>", - "Set the NM Loadaver Slots value") + RACH_STR NM_STR + "Set the NM Loadaverage Slots value") { struct gsm_bts *bts = vty->index; bts->rach_ldavg_slots = atoi(argv[0]); @@ -1419,8 +1471,12 @@ DEFUN(cfg_bts_per_loc_upd, cfg_bts_per_loc_upd_cmd, return CMD_SUCCESS; } +#define GPRS_TEXT "GPRS Packet Network\n" + DEFUN(cfg_bts_prs_bvci, cfg_bts_gprs_bvci_cmd, "gprs cell bvci <2-65535>", + GPRS_TEXT + "GPRS Cell Settings\n" "GPRS BSSGP VC Identifier") { struct gsm_bts *bts = vty->index; @@ -1437,6 +1493,7 @@ DEFUN(cfg_bts_prs_bvci, cfg_bts_gprs_bvci_cmd, DEFUN(cfg_bts_gprs_nsei, cfg_bts_gprs_nsei_cmd, "gprs nsei <0-65535>", + GPRS_TEXT "GPRS NS Entity Identifier") { struct gsm_bts *bts = vty->index; @@ -1451,9 +1508,13 @@ DEFUN(cfg_bts_gprs_nsei, cfg_bts_gprs_nsei_cmd, return CMD_SUCCESS; } +#define NSVC_TEXT "Network Service Virtual Connection (NS-VC)\n" \ + "NSVC Logical Number\n" DEFUN(cfg_bts_gprs_nsvci, cfg_bts_gprs_nsvci_cmd, "gprs nsvc <0-1> nsvci <0-65535>", + GPRS_TEXT NSVC_TEXT + "NS Virtual Connection Identifier\n" "GPRS NS VC Identifier") { struct gsm_bts *bts = vty->index; @@ -1471,6 +1532,7 @@ DEFUN(cfg_bts_gprs_nsvci, cfg_bts_gprs_nsvci_cmd, DEFUN(cfg_bts_gprs_nsvc_lport, cfg_bts_gprs_nsvc_lport_cmd, "gprs nsvc <0-1> local udp port <0-65535>", + GPRS_TEXT NSVC_TEXT "GPRS NS Local UDP Port") { struct gsm_bts *bts = vty->index; @@ -1488,6 +1550,7 @@ DEFUN(cfg_bts_gprs_nsvc_lport, cfg_bts_gprs_nsvc_lport_cmd, DEFUN(cfg_bts_gprs_nsvc_rport, cfg_bts_gprs_nsvc_rport_cmd, "gprs nsvc <0-1> remote udp port <0-65535>", + GPRS_TEXT NSVC_TEXT "GPRS NS Remote UDP Port") { struct gsm_bts *bts = vty->index; @@ -1505,6 +1568,7 @@ DEFUN(cfg_bts_gprs_nsvc_rport, cfg_bts_gprs_nsvc_rport_cmd, DEFUN(cfg_bts_gprs_nsvc_rip, cfg_bts_gprs_nsvc_rip_cmd, "gprs nsvc <0-1> remote ip A.B.C.D", + GPRS_TEXT NSVC_TEXT "GPRS NS Remote IP Address") { struct gsm_bts *bts = vty->index; @@ -1524,6 +1588,7 @@ DEFUN(cfg_bts_gprs_nsvc_rip, cfg_bts_gprs_nsvc_rip_cmd, DEFUN(cfg_bts_gprs_rac, cfg_bts_gprs_rac_cmd, "gprs routing area <0-255>", + GPRS_TEXT "GPRS Routing Area Code") { struct gsm_bts *bts = vty->index; @@ -1540,7 +1605,11 @@ DEFUN(cfg_bts_gprs_rac, cfg_bts_gprs_rac_cmd, DEFUN(cfg_bts_gprs_mode, cfg_bts_gprs_mode_cmd, "gprs mode (none|gprs|egprs)", - "GPRS Mode for this BTS") + GPRS_TEXT + "GPRS Mode for this BTS\n" + "GPRS Disabled on this BTS\n" + "GPRS Enabled on this BTS\n" + "EGPRS (EDGE) Enabled on this BTS\n") { struct gsm_bts *bts = vty->index; @@ -1549,11 +1618,13 @@ DEFUN(cfg_bts_gprs_mode, cfg_bts_gprs_mode_cmd, return CMD_SUCCESS; } +#define TRX_TEXT "Radio Transceiver\n" /* per TRX configuration */ DEFUN(cfg_trx, cfg_trx_cmd, "trx TRX_NR", + TRX_TEXT "Select a TRX to configure") { int trx_nr = atoi(argv[0]); -- cgit v1.2.3 From 615e95632850854ca587126905474c6dedd8298e Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 11 May 2010 23:50:21 +0200 Subject: [gprs] NS/BSSGP: Make all timers configurable from VTY --- openbsc/include/openbsc/gsm_data.h | 2 + openbsc/src/bsc_init.c | 4 + openbsc/src/gsm_data.c | 8 ++ openbsc/src/vty_interface.c | 151 ++++++++++++++++++++++++++++++------- 4 files changed, 139 insertions(+), 26 deletions(-) diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index 03794c2f8..91527c933 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -509,10 +509,12 @@ struct gsm_bts { struct { struct gsm_nm_state nm_state; u_int16_t nsei; + uint8_t timer[7]; } nse; struct { struct gsm_nm_state nm_state; u_int16_t bvci; + uint8_t timer[11]; } cell; struct gsm_bts_gprs_nsvc nsvc[2]; u_int8_t rac; diff --git a/openbsc/src/bsc_init.c b/openbsc/src/bsc_init.c index 9bc02c486..38f5dfbba 100644 --- a/openbsc/src/bsc_init.c +++ b/openbsc/src/bsc_init.c @@ -883,6 +883,10 @@ static void patch_nm_tables(struct gsm_bts *bts) /* patch NSEI */ nanobts_attr_nse[3] = bts->gprs.nse.nsei >> 8; nanobts_attr_nse[4] = bts->gprs.nse.nsei & 0xff; + memcpy(nanobts_attr_nse+8, bts->gprs.nse.timer, + ARRAY_SIZE(bts->gprs.nse.timer)); + memcpy(nanobts_attr_nse+18, bts->gprs.cell.timer, + ARRAY_SIZE(bts->gprs.cell.timer)); /* patch NSVCI */ nanobts_attr_nsvc0[3] = bts->gprs.nsvc[0].nsvci >> 8; diff --git a/openbsc/src/gsm_data.c b/openbsc/src/gsm_data.c index f9cca490d..a4b321266 100644 --- a/openbsc/src/gsm_data.c +++ b/openbsc/src/gsm_data.c @@ -171,6 +171,10 @@ struct gsm_bts_trx *gsm_bts_trx_alloc(struct gsm_bts *bts) return trx; } +static const uint8_t bts_nse_timer_default[] = { 3, 3, 3, 3, 30, 3, 10 }; +static const uint8_t bts_cell_timer_default[] = + { 3, 3, 3, 3, 3, 10, 3, 10, 3, 10, 3 }; + struct gsm_bts *gsm_bts_alloc(struct gsm_network *net, enum gsm_bts_type type, u_int8_t tsc, u_int8_t bsic) { @@ -212,6 +216,10 @@ struct gsm_bts *gsm_bts_alloc(struct gsm_network *net, enum gsm_bts_type type, bts->gprs.nsvc[i].bts = bts; bts->gprs.nsvc[i].id = i; } + memcpy(&bts->gprs.nse.timer, bts_nse_timer_default, + sizeof(bts->gprs.nse.timer)); + memcpy(&bts->gprs.cell.timer, bts_cell_timer_default, + sizeof(bts->gprs.cell.timer)); /* create our primary TRX */ bts->c0 = gsm_bts_trx_alloc(bts); diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c index 547681ce3..48dce9e4e 100644 --- a/openbsc/src/vty_interface.c +++ b/openbsc/src/vty_interface.c @@ -42,6 +42,32 @@ static struct gsm_network *gsmnet; +static struct value_string gprs_ns_timer_strs[] = { + { 0, "tns-block" }, + { 1, "tns-block-retries" }, + { 2, "tns-reset" }, + { 3, "tns-reset-retries" }, + { 4, "tns-test" }, + { 5, "tns-alive" }, + { 6, "tns-alive-retries" }, + { 0, NULL } +}; + +static struct value_string gprs_bssgp_cfg_strs[] = { + { 0, "blocking-timer" }, + { 1, "blocking-retries" }, + { 2, "unblocking-retries" }, + { 3, "reset-timer" }, + { 4, "reset-retries" }, + { 5, "suspend-timer" }, + { 6, "suspend-retries" }, + { 7, "resume-timer" }, + { 8, "resume-retries" }, + { 9, "capability-update-timer" }, + { 10, "capability-update-retries" }, + { 0, NULL } +}; + struct cmd_node net_node = { GSMNET_NODE, "%s(network)#", @@ -279,10 +305,48 @@ static void config_write_trx_single(struct vty *vty, struct gsm_bts_trx *trx) config_write_ts_single(vty, &trx->ts[i]); } +static void config_write_bts_gprs(struct vty *vty, struct gsm_bts *bts) +{ + unsigned int i; + vty_out(vty, " gprs mode %s%s", bts_gprs_mode_name(bts->gprs.mode), + VTY_NEWLINE); + if (bts->gprs.mode == BTS_GPRS_NONE) + return; + + vty_out(vty, " gprs routing area %u%s", bts->gprs.rac, + VTY_NEWLINE); + vty_out(vty, " gprs cell bvci %u%s", bts->gprs.cell.bvci, + VTY_NEWLINE); + for (i = 0; i < ARRAY_SIZE(bts->gprs.cell.timer); i++) + vty_out(vty, " gprs cell timer %s %u%s", + get_value_string(gprs_bssgp_cfg_strs, i), + bts->gprs.cell.timer[i], VTY_NEWLINE); + vty_out(vty, " gprs nsei %u%s", bts->gprs.nse.nsei, + VTY_NEWLINE); + for (i = 0; i < ARRAY_SIZE(bts->gprs.nse.timer); i++) + vty_out(vty, " gprs ns timer %s %u%s", + get_value_string(gprs_ns_timer_strs, i), + bts->gprs.nse.timer[i], VTY_NEWLINE); + for (i = 0; i < ARRAY_SIZE(bts->gprs.nsvc); i++) { + struct gsm_bts_gprs_nsvc *nsvc = + &bts->gprs.nsvc[i]; + struct in_addr ia; + + ia.s_addr = htonl(nsvc->remote_ip); + vty_out(vty, " gprs nsvc %u nsvci %u%s", i, + nsvc->nsvci, VTY_NEWLINE); + vty_out(vty, " gprs nsvc %u local udp port %u%s", i, + nsvc->local_port, VTY_NEWLINE); + vty_out(vty, " gprs nsvc %u remote udp port %u%s", i, + nsvc->remote_port, VTY_NEWLINE); + vty_out(vty, " gprs nsvc %u remote ip %s%s", i, + inet_ntoa(ia), VTY_NEWLINE); + } +} + static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts) { struct gsm_bts_trx *trx; - int i; vty_out(vty, " bts %u%s", bts->nr, VTY_NEWLINE); vty_out(vty, " type %s%s", btstype2str(bts->type), VTY_NEWLINE); @@ -325,31 +389,7 @@ static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts) config_write_e1_link(vty, &bts->oml_e1_link, " oml "); vty_out(vty, " oml e1 tei %u%s", bts->oml_tei, VTY_NEWLINE); } - vty_out(vty, " gprs mode %s%s", bts_gprs_mode_name(bts->gprs.mode), - VTY_NEWLINE); - if (bts->gprs.mode != BTS_GPRS_NONE) { - vty_out(vty, " gprs routing area %u%s", bts->gprs.rac, - VTY_NEWLINE); - vty_out(vty, " gprs cell bvci %u%s", bts->gprs.cell.bvci, - VTY_NEWLINE); - vty_out(vty, " gprs nsei %u%s", bts->gprs.nse.nsei, - VTY_NEWLINE); - for (i = 0; i < ARRAY_SIZE(bts->gprs.nsvc); i++) { - struct gsm_bts_gprs_nsvc *nsvc = - &bts->gprs.nsvc[i]; - struct in_addr ia; - - ia.s_addr = htonl(nsvc->remote_ip); - vty_out(vty, " gprs nsvc %u nsvci %u%s", i, - nsvc->nsvci, VTY_NEWLINE); - vty_out(vty, " gprs nsvc %u local udp port %u%s", i, - nsvc->local_port, VTY_NEWLINE); - vty_out(vty, " gprs nsvc %u remote udp port %u%s", i, - nsvc->remote_port, VTY_NEWLINE); - vty_out(vty, " gprs nsvc %u remote ip %s%s", i, - inet_ntoa(ia), VTY_NEWLINE); - } - } + config_write_bts_gprs(vty, bts); llist_for_each_entry(trx, &bts->trx_list, list) config_write_trx_single(vty, trx); @@ -1586,6 +1626,63 @@ DEFUN(cfg_bts_gprs_nsvc_rip, cfg_bts_gprs_nsvc_rip_cmd, return CMD_SUCCESS; } +#define NS_TIMERS "(tns-block|tns-block-retries|tns-reset|tns-reset-retries|tns-test|tns-alive|tns-alive-retries)" +#define NS_TIMERS_HELP \ + "(un)blocking Timer (Tns-block) timeout\n" \ + "(un)blocking Timer (Tns-block) number of retries\n" \ + "Reset Timer (Tns-reset) timeout\n" \ + "Reset Timer (Tns-reset) number of retries\n" \ + "Test Timer (Tns-test) timeout\n" \ + +DEFUN(cfg_bts_gprs_ns_timer, cfg_bts_gprs_ns_timer_cmd, + "gprs ns timer " NS_TIMERS " <0-255>", + GPRS_TEXT "Network Service\n" + "Network Service Timer\n" + NS_TIMERS_HELP "Timer Value\n") +{ + struct gsm_bts *bts = vty->index; + int idx = get_string_value(gprs_ns_timer_strs, argv[0]); + int val = atoi(argv[1]); + + if (bts->gprs.mode == BTS_GPRS_NONE) { + vty_out(vty, "%% GPRS not enabled on this BTS%s", VTY_NEWLINE); + return CMD_WARNING; + } + + if (idx < 0 || idx >= ARRAY_SIZE(bts->gprs.nse.timer)) + return CMD_WARNING; + + bts->gprs.nse.timer[idx] = val; + + return CMD_SUCCESS; +} + +#define BSSGP_TIMERS "(blocking-timer|blocking-retries|unblocking-retries|reset-timer|reset-retries|suspend-timer|suspend-retries|resume-timer|resume-retries|capability-update-timer|capability-update-retries)" +#define BSSGP_TIMERS_HELP "" + +DEFUN(cfg_bts_gprs_cell_timer, cfg_bts_gprs_cell_timer_cmd, + "gprs cell timer " BSSGP_TIMERS " <0-255>", + GPRS_TEXT "Cell / BSSGP\n" + "Cell/BSSGP Timer\n" + BSSGP_TIMERS_HELP "Timer Value\n") +{ + struct gsm_bts *bts = vty->index; + int idx = get_string_value(gprs_bssgp_cfg_strs, argv[0]); + int val = atoi(argv[1]); + + if (bts->gprs.mode == BTS_GPRS_NONE) { + vty_out(vty, "%% GPRS not enabled on this BTS%s", VTY_NEWLINE); + return CMD_WARNING; + } + + if (idx < 0 || idx >= ARRAY_SIZE(bts->gprs.cell.timer)) + return CMD_WARNING; + + bts->gprs.cell.timer[idx] = val; + + return CMD_SUCCESS; +} + DEFUN(cfg_bts_gprs_rac, cfg_bts_gprs_rac_cmd, "gprs routing area <0-255>", GPRS_TEXT @@ -1877,8 +1974,10 @@ int bsc_vty_init(struct gsm_network *net) install_element(BTS_NODE, &cfg_bts_cell_resel_hyst_cmd); install_element(BTS_NODE, &cfg_bts_rxlev_acc_min_cmd); install_element(BTS_NODE, &cfg_bts_gprs_mode_cmd); + install_element(BTS_NODE, &cfg_bts_gprs_ns_timer_cmd); install_element(BTS_NODE, &cfg_bts_gprs_rac_cmd); install_element(BTS_NODE, &cfg_bts_gprs_bvci_cmd); + install_element(BTS_NODE, &cfg_bts_gprs_cell_timer_cmd); install_element(BTS_NODE, &cfg_bts_gprs_nsei_cmd); install_element(BTS_NODE, &cfg_bts_gprs_nsvci_cmd); install_element(BTS_NODE, &cfg_bts_gprs_nsvc_lport_cmd); -- cgit v1.2.3 From 1174c08068c4775da740da806bcd3e41f09fee66 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 12 May 2010 00:07:29 +0200 Subject: [gprs] gb_proxy: Snoop Cell ID from BSSGP RESET If a PTP BVC is BVC-RESET by the BSS, the PDU contains the Cell Identifier. We can snoop this into our gbprox_peer structure for better visualization of each peer in they vty. --- openbsc/src/gprs/gb_proxy.c | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/openbsc/src/gprs/gb_proxy.c b/openbsc/src/gprs/gb_proxy.c index fd932523b..fe299c512 100644 --- a/openbsc/src/gprs/gb_proxy.c +++ b/openbsc/src/gprs/gb_proxy.c @@ -82,7 +82,7 @@ static struct gbprox_peer *peer_by_rac(const uint8_t *ra) { struct gbprox_peer *peer; llist_for_each_entry(peer, &gbprox_bts_peers, list) { - if (!memcmp(&peer->ra, ra, 6)) + if (!memcmp(peer->ra, ra, 6)) return peer; } return NULL; @@ -93,7 +93,7 @@ static struct gbprox_peer *peer_by_lac(const uint8_t *la) { struct gbprox_peer *peer; llist_for_each_entry(peer, &gbprox_bts_peers, list) { - if (!memcmp(&peer->ra, la, 5)) + if (!memcmp(peer->ra, la, 5)) return peer; } return NULL; @@ -213,8 +213,8 @@ static int gbprox_rx_sig_from_bss(struct msgb *msg, struct gprs_nsvc *nsvc, from_peer = peer_by_nsvc(nsvc); if (!from_peer) goto err_no_peer; - memcpy(&from_peer->ra, TLVP_VAL(&tp, BSSGP_IE_ROUTEING_AREA), - sizeof(&from_peer->ra)); + memcpy(from_peer->ra, TLVP_VAL(&tp, BSSGP_IE_ROUTEING_AREA), + sizeof(from_peer->ra)); gsm48_parse_ra(&raid, from_peer->ra); DEBUGP(DGPRS, "NSEI=%u RAC snooping: RAC %u/%u/%u/%u behind BVCI=%u, " "NSVCI=%u\n", nsvc->nsei, raid.mcc, raid.mnc, raid.lac, @@ -235,7 +235,9 @@ static int gbprox_rx_sig_from_bss(struct msgb *msg, struct gprs_nsvc *nsvc, "BVC RESET ACK of BVCI=0\n", nsvc->nsei); return bssgp_tx_simple_bvci(BSSGP_PDUT_BVC_RESET_ACK, nsvc->nsei, 0, ns_bvci); - } else if (!peer_by_bvci(bvci)) { + } + from_peer = peer_by_bvci(bvci); + if (!from_peer) { /* if a PTP-BVC is reset, and we don't know that * PTP-BVCI yet, we should allocate a new peer */ LOGP(DGPRS, LOGL_INFO, "Allocationg new peer for " @@ -244,6 +246,21 @@ static int gbprox_rx_sig_from_bss(struct msgb *msg, struct gprs_nsvc *nsvc, from_peer = peer_alloc(bvci); from_peer->nsvc = nsvc; } + if (TLVP_PRESENT(&tp, BSSGP_IE_CELL_ID)) { + struct gprs_ra_id raid; + /* We have a Cell Identifier present in this + * PDU, this means we can extend our local + * state information about this particular cell + * */ + memcpy(from_peer->ra, + TLVP_VAL(&tp, BSSGP_IE_CELL_ID), + sizeof(from_peer->ra)); + gsm48_parse_ra(&raid, from_peer->ra); + LOGP(DGPRS, LOGL_INFO, "NSEI=%u/BVCI=%u " + "Cell ID " "%u-%u-%u-%u\n", nsvc->nsei, + bvci, raid.mcc, raid.mnc, raid.lac, + raid.rac); + } } break; } -- cgit v1.2.3 From fcc4cc9f655fee8308c323b7e8f9b85aa03703a6 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 12 May 2010 00:16:57 +0200 Subject: [gprs] NS: elevate events from LOGL_DEBUG to LOGL_INFO --- openbsc/src/gprs/gprs_ns.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/openbsc/src/gprs/gprs_ns.c b/openbsc/src/gprs/gprs_ns.c index 745a0b57f..fdefa653c 100644 --- a/openbsc/src/gprs/gprs_ns.c +++ b/openbsc/src/gprs/gprs_ns.c @@ -272,10 +272,11 @@ static void gprs_ns_timer_cb(void *data) if (nsvc->alive_retries > NS_ALIVE_RETRIES) { /* mark as dead and blocked */ nsvc->state = NSE_S_BLOCKED; - DEBUGP(DNS, "NSEI=%u Tns-alive expired more then " + LOGP(DNS, LOGL_NOTICE, + "NSEI=%u Tns-alive expired more then " "%u times, blocking NS-VC\n", nsvc->nsei, NS_ALIVE_RETRIES); - /* FIXME: inform higher layers */ + ns_dispatch_signal(nsvc, S_NS_BLOCK, NS_CAUSE_NSVC_BLOCKED); return; } nsvc_start_timer(nsvc, NSVC_TIMER_TNS_ALIVE); @@ -313,7 +314,7 @@ static int gprs_ns_tx_reset_ack(struct gprs_nsvc *nsvc) nsh->pdu_type = NS_PDUT_RESET_ACK; - DEBUGP(DNS, "NSEI=%u Tx NS RESET ACK (NSVCI=%u)\n", + LOGP(DNS, LOGL_INFO, "NSEI=%u Tx NS RESET ACK (NSVCI=%u)\n", nsvc->nsei, nsvc->nsvci); msgb_tvlv_put(msg, NS_IE_VCI, 2, (uint8_t *)&nsvci); @@ -384,17 +385,17 @@ static int gprs_ns_rx_status(struct gprs_nsvc *nsvc, struct msgb *msg) uint8_t cause; int rc; - DEBUGP(DNS, "NSEI=%u NS STATUS ", nsvc->nsei); + LOGP(DNS, LOGL_INFO, "NSEI=%u NS STATUS ", nsvc->nsei); rc = tlv_parse(&tp, &ns_att_tlvdef, nsh->data, msgb_l2len(msg), 0, 0); if (!TLVP_PRESENT(&tp, NS_IE_CAUSE)) { - DEBUGPC(DNS, "missing cause IE\n"); + LOGPC(DNS, LOGL_INFO, "missing cause IE\n"); return -EINVAL; } cause = *TLVP_VAL(&tp, NS_IE_CAUSE); - DEBUGPC(DNS, "cause=%s\n", gprs_ns_cause_str(cause)); + LOGPC(DNS, LOGL_INFO, "cause=%s\n", gprs_ns_cause_str(cause)); return 0; } @@ -422,7 +423,7 @@ static int gprs_ns_rx_reset(struct gprs_nsvc *nsvc, struct msgb *msg) nsvci = (uint16_t *) TLVP_VAL(&tp, NS_IE_VCI); nsei = (uint16_t *) TLVP_VAL(&tp, NS_IE_NSEI); - DEBUGP(DNS, "NSEI=%u Rx NS RESET (NSVCI=%u, cause=%s)\n", + LOGP(DNS, LOGL_INFO, "NSEI=%u Rx NS RESET (NSVCI=%u, cause=%s)\n", nsvc->nsvci, nsvc->nsei, gprs_ns_cause_str(*cause)); nsvc->state = NSE_S_BLOCKED | NSE_S_ALIVE; @@ -451,7 +452,7 @@ static int gprs_ns_rx_block(struct gprs_nsvc *nsvc, struct msgb *msg) uint8_t *cause; int rc; - DEBUGP(DNS, "NSEI=%u Rx NS BLOCK\n", nsvc->nsei); + LOGP(DNS, LOGL_INFO, "NSEI=%u Rx NS BLOCK\n", nsvc->nsei); nsvc->state |= NSE_S_BLOCKED; @@ -545,7 +546,7 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, rc = gprs_ns_rx_reset(nsvc, msg); break; case NS_PDUT_RESET_ACK: - DEBUGP(DNS, "NSEI=%u Rx NS RESET ACK\n", nsvc->nsei); + LOGP(DNS, LOGL_INFO, "NSEI=%u Rx NS RESET ACK\n", nsvc->nsei); /* mark remote NS-VC as blocked + active */ nsvc->remote_state = NSE_S_BLOCKED | NSE_S_ALIVE; if (nsvc->remote_end_is_sgsn) { @@ -560,13 +561,13 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, break; case NS_PDUT_UNBLOCK: /* Section 7.2: unblocking procedure */ - DEBUGP(DNS, "NSEI=%u Rx NS UNBLOCK\n", nsvc->nsei); + LOGP(DNS, LOGL_INFO, "NSEI=%u Rx NS UNBLOCK\n", nsvc->nsei); nsvc->state &= ~NSE_S_BLOCKED; ns_dispatch_signal(nsvc, S_NS_UNBLOCK, 0); rc = gprs_ns_tx_simple(nsvc, NS_PDUT_UNBLOCK_ACK); break; case NS_PDUT_UNBLOCK_ACK: - DEBUGP(DNS, "NSEI=%u Rx NS UNBLOCK ACK\n", nsvc->nsei); + LOGP(DNS, LOGL_INFO, "NSEI=%u Rx NS UNBLOCK ACK\n", nsvc->nsei); /* mark remote NS-VC as unblocked + active */ nsvc->remote_state = NSE_S_ALIVE; if (nsvc->remote_end_is_sgsn) @@ -576,12 +577,12 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, rc = gprs_ns_rx_block(nsvc, msg); break; case NS_PDUT_BLOCK_ACK: - DEBUGP(DNS, "NSEI=%u Rx NS BLOCK ACK\n", nsvc->nsei); + LOGP(DNS, LOGL_INFO, "NSEI=%u Rx NS BLOCK ACK\n", nsvc->nsei); /* mark remote NS-VC as blocked + active */ nsvc->remote_state = NSE_S_BLOCKED | NSE_S_ALIVE; break; default: - DEBUGP(DNS, "NSEI=%u Rx Unknown NS PDU type 0x%02x\n", + LOGP(DNS, LOGL_NOTICE, "NSEI=%u Rx Unknown NS PDU type 0x%02x\n", nsvc->nsei, nsh->pdu_type); rc = -EINVAL; break; -- cgit v1.2.3 From 72953b884da4cfdc9d5f93979a8791be98b979cd Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 12 May 2010 00:20:41 +0200 Subject: [gprs] Gb proxy: log level consolidation --- openbsc/src/gprs/gb_proxy.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/openbsc/src/gprs/gb_proxy.c b/openbsc/src/gprs/gb_proxy.c index fe299c512..eac8d2c59 100644 --- a/openbsc/src/gprs/gb_proxy.c +++ b/openbsc/src/gprs/gb_proxy.c @@ -216,9 +216,10 @@ static int gbprox_rx_sig_from_bss(struct msgb *msg, struct gprs_nsvc *nsvc, memcpy(from_peer->ra, TLVP_VAL(&tp, BSSGP_IE_ROUTEING_AREA), sizeof(from_peer->ra)); gsm48_parse_ra(&raid, from_peer->ra); - DEBUGP(DGPRS, "NSEI=%u RAC snooping: RAC %u/%u/%u/%u behind BVCI=%u, " - "NSVCI=%u\n", nsvc->nsei, raid.mcc, raid.mnc, raid.lac, - raid.rac , from_peer->bvci, nsvc->nsvci); + LOGP(DGPRS, LOGL_INFO, "NSEI=%u RAC snooping: RAC %u-%u-%u-%u " + "behind BVCI=%u, NSVCI=%u\n", nsvc->nsei, raid.mcc, + raid.mnc, raid.lac, raid.rac , from_peer->bvci, + nsvc->nsvci); /* FIXME: This only supports one BSS per RA */ break; case BSSGP_PDUT_BVC_RESET: @@ -227,7 +228,7 @@ static int gbprox_rx_sig_from_bss(struct msgb *msg, struct gprs_nsvc *nsvc, * is common for all point-to-point BVCs (and thus all BTS) */ if (TLVP_PRESENT(&tp, BSSGP_IE_BVCI)) { uint16_t bvci = ntohs(*(uint16_t *)TLVP_VAL(&tp, BSSGP_IE_BVCI)); - LOGP(DGPRS, LOGL_DEBUG, "NSEI=%u Rx BVC RESET (BVCI=%u)\n", + LOGP(DGPRS, LOGL_INFO, "NSEI=%u Rx BVC RESET (BVCI=%u)\n", nsvc->nsei, bvci); if (bvci == 0) { /* FIXME: only do this if SGSN is alive! */ @@ -257,7 +258,7 @@ static int gbprox_rx_sig_from_bss(struct msgb *msg, struct gprs_nsvc *nsvc, sizeof(from_peer->ra)); gsm48_parse_ra(&raid, from_peer->ra); LOGP(DGPRS, LOGL_INFO, "NSEI=%u/BVCI=%u " - "Cell ID " "%u-%u-%u-%u\n", nsvc->nsei, + "Cell ID %u-%u-%u-%u\n", nsvc->nsei, bvci, raid.mcc, raid.mnc, raid.lac, raid.rac); } @@ -420,7 +421,8 @@ static int gbprox_rx_sig_from_sgsn(struct msgb *msg, struct gprs_nsvc *nsvc, rc = bssgp_tx_status(BSSGP_CAUSE_PDU_INCOMP_FEAT, NULL, msg); break; default: - DEBUGP(DGPRS, "BSSGP PDU type 0x%02x unknown\n", pdu_type); + LOGP(DGPRS, LOGL_NOTICE, "BSSGP PDU type 0x%02x unknown\n", + pdu_type); rc = bssgp_tx_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, msg); break; } @@ -454,7 +456,7 @@ int gbprox_rcvmsg(struct msgb *msg, struct gprs_nsvc *nsvc, uint16_t ns_bvci) } else { struct gbprox_peer *peer = peer_by_bvci(ns_bvci); if (!peer) { - LOGP(DGPRS, LOGL_NOTICE, "Allocationg new peer for " + LOGP(DGPRS, LOGL_INFO, "Allocationg new peer for " "BVCI=%u via NSVC=%u/NSEI=%u\n", ns_bvci, nsvc->nsvci, nsvc->nsei); peer = peer_alloc(ns_bvci); -- cgit v1.2.3 From d91b73769a11719e6ac6d5f3696ac6779540bd29 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Mon, 10 May 2010 01:22:39 +0800 Subject: gsm0408: Use counter_inc to increment the counter. --- openbsc/src/gsm_04_08_utils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openbsc/src/gsm_04_08_utils.c b/openbsc/src/gsm_04_08_utils.c index 0ee06ca56..1b3ed2537 100644 --- a/openbsc/src/gsm_04_08_utils.c +++ b/openbsc/src/gsm_04_08_utils.c @@ -279,7 +279,7 @@ int gsm48_handle_paging_resp(struct msgb *msg, struct gsm_subscriber *subscr) sig_data.bts = msg->lchan->ts->trx->bts; sig_data.lchan = msg->lchan; - bts->network->stats.paging.completed++; + counter_inc(bts->network->stats.paging.completed); dispatch_signal(SS_PAGING, S_PAGING_SUCCEEDED, &sig_data); -- cgit v1.2.3 From 7d45ea41f4e0b69b571feda45693b5bcb521f6ac Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Tue, 20 Apr 2010 22:22:00 +0800 Subject: [ipaccess] Attempt to fix setting unit ids with a multi trx setup Add a --trx/-t NR option to set the TRX nr to be used when calling set unit id and NVRAM. This was not tested and might or might not work. --- openbsc/src/ipaccess/ipaccess-config.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/openbsc/src/ipaccess/ipaccess-config.c b/openbsc/src/ipaccess/ipaccess-config.c index 670e3f11a..075a264fc 100644 --- a/openbsc/src/ipaccess/ipaccess-config.c +++ b/openbsc/src/ipaccess/ipaccess-config.c @@ -59,6 +59,7 @@ static int sw_load_state = 0; static int oml_state = 0; static int dump_files = 0; static char *firmware_analysis = NULL; +static int trx_nr = 0; struct sw_load { u_int8_t file_id[255]; @@ -316,7 +317,8 @@ static void bootstrap_om(struct gsm_bts *bts) memcpy(buf+3, unit_id, len); buf[3+len] = 0; printf("setting Unit ID to '%s'\n", unit_id); - abis_nm_ipaccess_set_nvattr(bts->c0, buf, 3+len+1); + abis_nm_ipaccess_set_nvattr(gsm_bts_trx_by_nr(bts, trx_nr), + buf, 3+len+1); } if (prim_oml_ip) { struct in_addr ia; @@ -354,7 +356,8 @@ static void bootstrap_om(struct gsm_bts *bts) *cur++ = nv_mask >> 8; printf("setting NV Flags/Mask to 0x%04x/0x%04x\n", nv_flags, nv_mask); - abis_nm_ipaccess_set_nvattr(bts->c0, buf, 3+len); + abis_nm_ipaccess_set_nvattr(gsm_bts_trx_by_nr(bts, trx_nr), + buf, 3+len); } if (restart && !prim_oml_ip && !software) { @@ -605,6 +608,7 @@ static void print_help(void) printf(" -d --software firmware\n"); printf(" -f --firmware firmware Provide firmware information\n"); printf(" -w --write-firmware. This will dump the firmware parts to the filesystem. Use with -f.\n"); + printf(" -t --trx NR. The TRX to use for the Unit ID and NVRAM attributes.\n"); } int main(int argc, char **argv) @@ -639,9 +643,11 @@ int main(int argc, char **argv) { "software", 1, 0, 'd' }, { "firmware", 1, 0, 'f' }, { "write-firmware", 0, 0, 'w' }, + { "trx", 1, 0, 't' }, + { 0, 0, 0, 0 }, }; - c = getopt_long(argc, argv, "u:o:rn:l:hs:d:f:w", long_options, + c = getopt_long(argc, argv, "u:o:rn:l:hs:d:f:wt:", long_options, &option_index); if (c == -1) @@ -683,6 +689,9 @@ int main(int argc, char **argv) case 'w': dump_files = 1; break; + case 't': + trx_nr = atoi(optarg); + break; case 'h': print_usage(); print_help(); -- cgit v1.2.3 From 9bdb3ba3229edcd077d19ee7c44a54703527b6c4 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 12 May 2010 11:48:44 +0200 Subject: [gprs] NS: more state transitions, error reporting via Tx STATUS PDU --- openbsc/src/gprs/gprs_ns.c | 80 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 64 insertions(+), 16 deletions(-) diff --git a/openbsc/src/gprs/gprs_ns.c b/openbsc/src/gprs/gprs_ns.c index fdefa653c..9cb330058 100644 --- a/openbsc/src/gprs/gprs_ns.c +++ b/openbsc/src/gprs/gprs_ns.c @@ -216,6 +216,49 @@ int gprs_ns_tx_reset(struct gprs_nsvc *nsvc, uint8_t cause) } +int gprs_ns_tx_status(struct gprs_nsvc *nsvc, uint8_t cause, + uint16_t bvci, struct msgb *orig_msg) +{ + struct msgb *msg = msgb_alloc(NS_ALLOC_SIZE, "GPRS/NS"); + struct gprs_ns_hdr *nsh; + uint16_t nsvci = htons(nsvc->nsvci); + + bvci = htons(bvci); + + if (!msg) + return -ENOMEM; + + nsh = (struct gprs_ns_hdr *) msgb_put(msg, sizeof(*nsh)); + nsh->pdu_type = NS_PDUT_STATUS; + + msgb_tvlv_put(msg, NS_IE_CAUSE, 1, &cause); + + /* Section 9.2.7.1: Static conditions for NS-VCI */ + if (cause == NS_CAUSE_NSVC_BLOCKED || + cause == NS_CAUSE_NSVC_UNKNOWN) + msgb_tvlv_put(msg, NS_IE_VCI, 2, (uint8_t *)&nsvci); + + /* Section 9.2.7.2: Static conditions for NS PDU */ + switch (cause) { + case NS_CAUSE_SEM_INCORR_PDU: + case NS_CAUSE_PDU_INCOMP_PSTATE: + case NS_CAUSE_PROTO_ERR_UNSPEC: + case NS_CAUSE_INVAL_ESSENT_IE: + case NS_CAUSE_MISSING_ESSENT_IE: + msgb_tvlv_put(msg, NS_IE_PDU, msgb_l2len(orig_msg), + orig_msg->l2h); + break; + default: + break; + } + + /* Section 9.2.7.3: Static conditions for BVCI */ + if (cause == NS_CAUSE_BVCI_UNKNOWN) + msgb_tvlv_put(msg, NS_IE_VCI, 2, (uint8_t *)&bvci); + + return gprs_ns_tx(nsvc, msg); +} + int gprs_ns_tx_block(struct gprs_nsvc *nsvc, uint8_t cause) { struct msgb *msg = msgb_alloc(NS_ALLOC_SIZE, "GPRS/NS"); @@ -290,6 +333,7 @@ static void gprs_ns_timer_cb(void *data) case NSVC_TIMER_TNS_RESET: /* Chapter 7.3: Re-send the RESET */ gprs_ns_tx_reset(nsvc, NS_CAUSE_OM_INTERVENTION); + /* Re-start Tns-reset timer */ nsvc_start_timer(nsvc, NSVC_TIMER_TNS_RESET); break; case _NSVC_TIMER_NR: @@ -368,6 +412,10 @@ static int gprs_ns_rx_unitdata(struct gprs_nsvc *nsvc, struct msgb *msg) struct gprs_ns_hdr *nsh = (struct gprs_ns_hdr *)msg->l2h; uint16_t bvci; + if (nsvc->state & NSE_S_BLOCKED) + return gprs_ns_tx_status(nsvc, NS_CAUSE_NSVC_BLOCKED, + 0, msg); + /* spare octet in data[0] */ bvci = nsh->data[1] << 8 | nsh->data[2]; msgb_bssgph(msg) = &nsh->data[3]; @@ -414,8 +462,8 @@ static int gprs_ns_rx_reset(struct gprs_nsvc *nsvc, struct msgb *msg) if (!TLVP_PRESENT(&tp, NS_IE_CAUSE) || !TLVP_PRESENT(&tp, NS_IE_VCI) || !TLVP_PRESENT(&tp, NS_IE_NSEI)) { - /* FIXME: respond with NS_CAUSE_MISSING_ESSENT_IE */ LOGP(DNS, LOGL_ERROR, "NS RESET Missing mandatory IE\n"); + gprs_ns_tx_status(nsvc, NS_CAUSE_MISSING_ESSENT_IE, 0, msg); return -EINVAL; } @@ -426,15 +474,12 @@ static int gprs_ns_rx_reset(struct gprs_nsvc *nsvc, struct msgb *msg) LOGP(DNS, LOGL_INFO, "NSEI=%u Rx NS RESET (NSVCI=%u, cause=%s)\n", nsvc->nsvci, nsvc->nsei, gprs_ns_cause_str(*cause)); + /* Mark NS-VC as blocked and alive */ nsvc->state = NSE_S_BLOCKED | NSE_S_ALIVE; - /* FIXME: Check if we have an existing peer with this NSEI/NSVCI - * and remove it, as our BSS may just have changed its source IP - * address */ nsvc->nsei = ntohs(*nsei); nsvc->nsvci = ntohs(*nsvci); - /* mark the NS-VC as blocked and alive */ /* start the test procedure */ nsvc_start_timer(nsvc, NSVC_TIMER_TNS_ALIVE); @@ -460,8 +505,8 @@ static int gprs_ns_rx_block(struct gprs_nsvc *nsvc, struct msgb *msg) if (!TLVP_PRESENT(&tp, NS_IE_CAUSE) || !TLVP_PRESENT(&tp, NS_IE_VCI)) { - /* FIXME: respond with NS_CAUSE_MISSING_ESSENT_IE */ LOGP(DNS, LOGL_ERROR, "NS RESET Missing mandatory IE\n"); + gprs_ns_tx_status(nsvc, NS_CAUSE_MISSING_ESSENT_IE, 0, msg); return -EINVAL; } @@ -492,6 +537,7 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, "from %s:%u for non-existing NS-VC\n", nsh->pdu_type, inet_ntoa(saddr->sin_addr), ntohs(saddr->sin_port)); + /* FIXME: send STATUS (but we have no NSVC!) */ //gprs_ns_tx_reset(nsvc, NS_CAUSE_NSVC_UNKNOWN); return -EIO; } @@ -500,8 +546,9 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, if (!TLVP_PRESENT(&tp, NS_IE_CAUSE) || !TLVP_PRESENT(&tp, NS_IE_VCI) || !TLVP_PRESENT(&tp, NS_IE_NSEI)) { - /* FIXME: respond with NS_CAUSE_MISSING_ESSENT_IE */ LOGP(DNS, LOGL_ERROR, "NS RESET Missing mandatory IE\n"); + gprs_ns_tx_status(nsvc, NS_CAUSE_MISSING_ESSENT_IE, 0, + msg); return -EINVAL; } nsei = ntohs(*(uint16_t *)TLVP_VAL(&tp, NS_IE_NSEI)); @@ -532,7 +579,7 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, if (nsvc->remote_end_is_sgsn) { /* FIXME: this should be one level higher */ if (nsvc->state & NSE_S_BLOCKED) - rc = gprs_ns_tx_simple(nsvc, NS_PDUT_UNBLOCK); + rc = gprs_ns_tx_unblock(nsvc); } break; case NS_PDUT_UNITDATA: @@ -547,16 +594,15 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, break; case NS_PDUT_RESET_ACK: LOGP(DNS, LOGL_INFO, "NSEI=%u Rx NS RESET ACK\n", nsvc->nsei); - /* mark remote NS-VC as blocked + active */ + /* mark NS-VC as blocked + active */ + nsvc->state = NSE_S_BLOCKED | NSE_S_ALIVE; nsvc->remote_state = NSE_S_BLOCKED | NSE_S_ALIVE; if (nsvc->remote_end_is_sgsn) { /* stop RESET timer */ bsc_del_timer(&nsvc->timer); - /* send ALIVE PDU */ + /* Initiate TEST proc.: Send ALIVE and start timer */ rc = gprs_ns_tx_simple(nsvc, NS_PDUT_ALIVE); nsvc_start_timer(nsvc, NSVC_TIMER_TNS_ALIVE); - /* mark local state as BLOCKED + ALIVE */ - nsvc->state = NSE_S_BLOCKED | NSE_S_ALIVE; } break; case NS_PDUT_UNBLOCK: @@ -568,10 +614,9 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, break; case NS_PDUT_UNBLOCK_ACK: LOGP(DNS, LOGL_INFO, "NSEI=%u Rx NS UNBLOCK ACK\n", nsvc->nsei); - /* mark remote NS-VC as unblocked + active */ + /* mark NS-VC as unblocked + active */ + nsvc->state = NSE_S_ALIVE; nsvc->remote_state = NSE_S_ALIVE; - if (nsvc->remote_end_is_sgsn) - nsvc->state = NSE_S_ALIVE; break; case NS_PDUT_BLOCK: rc = gprs_ns_rx_block(nsvc, msg); @@ -728,11 +773,14 @@ struct gprs_nsvc *nsip_connect(struct gprs_ns_inst *nsi, nsvc->remote_end_is_sgsn = 1; /* Initiate a RESET procedure */ + /* Mark NS-VC locally as blocked and dead */ + nsvc->state = NSE_S_BLOCKED; + /* Send NS-RESET PDU */ if (gprs_ns_tx_reset(nsvc, NS_CAUSE_OM_INTERVENTION) < 0) { LOGP(DNS, LOGL_ERROR, "NSEI=%u, error resetting NS-VC\n", nsei); } - /* run a timer and re-transmit the reset request? */ + /* Start Tns-reset */ nsvc_start_timer(nsvc, NSVC_TIMER_TNS_RESET); return nsvc; -- cgit v1.2.3 From cad8301dbe288190cbf18d9a1818c0a5312646d0 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 12 May 2010 11:56:39 +0000 Subject: NS: don't memcmp sockaddr_in but compare ip and port individually this seems to work more portably (ppc/32bit big endian) --- openbsc/src/gprs/gprs_ns.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/openbsc/src/gprs/gprs_ns.c b/openbsc/src/gprs/gprs_ns.c index 9cb330058..a166956b0 100644 --- a/openbsc/src/gprs/gprs_ns.c +++ b/openbsc/src/gprs/gprs_ns.c @@ -104,7 +104,9 @@ static struct gprs_nsvc *nsvc_by_rem_addr(struct gprs_ns_inst *nsi, { struct gprs_nsvc *nsvc; llist_for_each_entry(nsvc, &nsi->gprs_nsvcs, list) { - if (!memcmp(&nsvc->ip.bts_addr, sin, sizeof(*sin))) + if (nsvc->ip.bts_addr.sin_addr.s_addr == + sin->sin_addr.s_addr && + nsvc->ip.bts_addr.sin_port == sin->sin_port) return nsvc; } return NULL; @@ -764,10 +766,9 @@ struct gprs_nsvc *nsip_connect(struct gprs_ns_inst *nsi, struct gprs_nsvc *nsvc; nsvc = nsvc_by_rem_addr(nsi, dest); - if (!nsvc) { + if (!nsvc) nsvc = nsvc_create(nsi, nsvci); - nsvc->ip.bts_addr = *dest; - } + nsvc->ip.bts_addr = *dest; nsvc->nsei = nsei; nsvc->nsvci = nsvci; nsvc->remote_end_is_sgsn = 1; -- cgit v1.2.3 From 34caeb36abdd605ef7e5c760af1dc22fdb995330 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 12 May 2010 12:01:33 +0000 Subject: NS: More INFO messages about what we actually transmit --- openbsc/src/gprs/gprs_ns.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/openbsc/src/gprs/gprs_ns.c b/openbsc/src/gprs/gprs_ns.c index a166956b0..e93bd43fb 100644 --- a/openbsc/src/gprs/gprs_ns.c +++ b/openbsc/src/gprs/gprs_ns.c @@ -207,6 +207,9 @@ int gprs_ns_tx_reset(struct gprs_nsvc *nsvc, uint8_t cause) if (!msg) return -ENOMEM; + LOGP(DNS, LOGL_INFO, "NSEI=%u Tx NS RESET (NSVCI=%u, cause=%s)\n", + nsvc->nsei, nsvc->nsvci, gprs_ns_cause_str(cause)); + nsh = (struct gprs_ns_hdr *) msgb_put(msg, sizeof(*nsh)); nsh->pdu_type = NS_PDUT_RESET; @@ -230,6 +233,9 @@ int gprs_ns_tx_status(struct gprs_nsvc *nsvc, uint8_t cause, if (!msg) return -ENOMEM; + LOGP(DNS, LOGL_INFO, "NSEI=%u Tx NS STATUS (NSVCI=%u, cause=%s)\n", + nsvc->nsei, nsvc->nsvci, gprs_ns_cause_str(cause)); + nsh = (struct gprs_ns_hdr *) msgb_put(msg, sizeof(*nsh)); nsh->pdu_type = NS_PDUT_STATUS; @@ -270,6 +276,9 @@ int gprs_ns_tx_block(struct gprs_nsvc *nsvc, uint8_t cause) if (!msg) return -ENOMEM; + LOGP(DNS, LOGL_INFO, "NSEI=%u Tx NS BLOCK (NSVCI=%u, cause=%s)\n", + nsvc->nsei, nsvc->nsvci, gprs_ns_cause_str(cause)); + /* be conservative and mark it as blocked even now! */ nsvc->state |= NSE_S_BLOCKED; @@ -284,6 +293,10 @@ int gprs_ns_tx_block(struct gprs_nsvc *nsvc, uint8_t cause) int gprs_ns_tx_unblock(struct gprs_nsvc *nsvc) { + + LOGP(DNS, LOGL_INFO, "NSEI=%u Tx NS UNBLOCK (NSVCI=%u)\n", + nsvc->nsei, nsvc->nsvci); + return gprs_ns_tx_simple(nsvc, NS_PDUT_UNBLOCK); } -- cgit v1.2.3 From bca900dab2b02d96c22c20db4e05c90b45a0d30e Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 12 May 2010 12:11:45 +0000 Subject: NS: Add more LOG_DEBGU messages and retransmit NS-ALIVE --- openbsc/src/gprs/gprs_ns.c | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/openbsc/src/gprs/gprs_ns.c b/openbsc/src/gprs/gprs_ns.c index e93bd43fb..19653f6a6 100644 --- a/openbsc/src/gprs/gprs_ns.c +++ b/openbsc/src/gprs/gprs_ns.c @@ -293,13 +293,28 @@ int gprs_ns_tx_block(struct gprs_nsvc *nsvc, uint8_t cause) int gprs_ns_tx_unblock(struct gprs_nsvc *nsvc) { - LOGP(DNS, LOGL_INFO, "NSEI=%u Tx NS UNBLOCK (NSVCI=%u)\n", nsvc->nsei, nsvc->nsvci); return gprs_ns_tx_simple(nsvc, NS_PDUT_UNBLOCK); } +int gprs_ns_tx_alive(struct gprs_nsvc *nsvc) +{ + LOGP(DNS, LOGL_DEBUG, "NSEI=%u Tx NS ALIVE (NSVCI=%u)\n", + nsvc->nsei, nsvc->nsvci); + + return gprs_ns_tx_simple(nsvc, NS_PDUT_ALIVE); +} + +int gprs_ns_tx_alive_ack(struct gprs_nsvc *nsvc) +{ + LOGP(DNS, LOGL_DEBUG, "NSEI=%u Tx NS ALIVE_ACK (NSVCI=%u)\n", + nsvc->nsei, nsvc->nsvci); + + return gprs_ns_tx_simple(nsvc, NS_PDUT_ALIVE_ACK); +} + #define NS_ALIVE_RETRIES 10 /* after 3 failed retransmit we declare BTS as dead */ static const uint8_t timer_mode_tout[_NSVC_TIMER_NR] = { @@ -337,12 +352,16 @@ static void gprs_ns_timer_cb(void *data) ns_dispatch_signal(nsvc, S_NS_BLOCK, NS_CAUSE_NSVC_BLOCKED); return; } + /* Tns-test case: send NS-ALIVE PDU */ + gprs_ns_tx_alive(nsvc); + /* start Tns-alive timer */ nsvc_start_timer(nsvc, NSVC_TIMER_TNS_ALIVE); break; case NSVC_TIMER_TNS_TEST: /* Tns-test case: send NS-ALIVE PDU */ - gprs_ns_tx_simple(nsvc, NS_PDUT_ALIVE); - /* start Tns-alive timer */ + gprs_ns_tx_alive(nsvc); + /* start Tns-alive timer (transition into faster + * alive retransmissions) */ nsvc_start_timer(nsvc, NSVC_TIMER_TNS_ALIVE); break; case NSVC_TIMER_TNS_RESET: @@ -584,7 +603,7 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, case NS_PDUT_ALIVE: /* remote end inquires whether we're still alive, * we need to respond with ALIVE_ACK */ - rc = gprs_ns_tx_simple(nsvc, NS_PDUT_ALIVE_ACK); + rc = gprs_ns_tx_alive_ack(nsvc); break; case NS_PDUT_ALIVE_ACK: /* stop Tns-alive */ -- cgit v1.2.3 From 811c4979e6af534248d91d8c79a22cdcd7d36431 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 12 May 2010 12:21:52 +0000 Subject: NS: Debug NS timer expiry --- openbsc/src/gprs/gprs_ns.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/openbsc/src/gprs/gprs_ns.c b/openbsc/src/gprs/gprs_ns.c index 19653f6a6..0ef0c3fcb 100644 --- a/openbsc/src/gprs/gprs_ns.c +++ b/openbsc/src/gprs/gprs_ns.c @@ -323,10 +323,19 @@ static const uint8_t timer_mode_tout[_NSVC_TIMER_NR] = { [NSVC_TIMER_TNS_TEST] = 30, }; +static const struct value_string timer_mode_strs[] = { + { NSVC_TIMER_TNS_RESET, "tns-reset" }, + { NSVC_TIMER_TNS_ALIVE, "tns-alive" }, + { NSVC_TIMER_TNS_TEST, "tns-test" }, + { 0, NULL } +}; + static void nsvc_start_timer(struct gprs_nsvc *nsvc, enum nsvc_timer_mode mode) { - nsvc->alive_retries = 0; - + DEBUGP(DNS, "NSVC=%u Starting timer in mode %s (%u seconds)\n", + nsvc->nsvci, get_value_string(timer_mode_strs, mode), + timer_mode_tout[mode]); + if (bsc_timer_pending(&nsvc->timer)) bsc_del_timer(&nsvc->timer); @@ -338,6 +347,10 @@ static void gprs_ns_timer_cb(void *data) { struct gprs_nsvc *nsvc = data; + DEBUGP(DNS, "NSVC=%u Timer expired in mode %s (%u seconds)\n", + nsvc->nsvci, get_value_string(timer_mode_strs, nsvc->timer_mode), + timer_mode_tout[nsvc->timer_mode]); + switch (nsvc->timer_mode) { case NSVC_TIMER_TNS_ALIVE: /* Tns-alive case: we expired without response ! */ @@ -362,6 +375,7 @@ static void gprs_ns_timer_cb(void *data) gprs_ns_tx_alive(nsvc); /* start Tns-alive timer (transition into faster * alive retransmissions) */ + nsvc->alive_retries = 0; nsvc_start_timer(nsvc, NSVC_TIMER_TNS_ALIVE); break; case NSVC_TIMER_TNS_RESET: -- cgit v1.2.3 From b778d2cf1638d706c7bf3bb3f754029e40d4bf54 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 12 May 2010 13:28:25 +0000 Subject: NS / GB Proxy: Add Signal in case Tns-Alive expires too often The Gb Proxy can then restart the RESET procedure. --- openbsc/include/openbsc/signal.h | 1 + openbsc/src/gprs/gb_proxy.c | 7 +++++++ openbsc/src/gprs/gprs_ns.c | 1 + 3 files changed, 9 insertions(+) diff --git a/openbsc/include/openbsc/signal.h b/openbsc/include/openbsc/signal.h index 6e0f5baca..fbb4163d7 100644 --- a/openbsc/include/openbsc/signal.h +++ b/openbsc/include/openbsc/signal.h @@ -149,6 +149,7 @@ enum signal_ns { S_NS_RESET, S_NS_BLOCK, S_NS_UNBLOCK, + S_NS_ALIVE_EXP, /* Tns-alive expired more than N times */ }; struct ns_signal_data { diff --git a/openbsc/src/gprs/gb_proxy.c b/openbsc/src/gprs/gb_proxy.c index eac8d2c59..d9639a445 100644 --- a/openbsc/src/gprs/gb_proxy.c +++ b/openbsc/src/gprs/gb_proxy.c @@ -488,6 +488,13 @@ int gbprox_signal(unsigned int subsys, unsigned int signal, nsvc->remote_end_is_sgsn = 1; } + if (signal == S_NS_ALIVE_EXP && nsvc->remote_end_is_sgsn) { + LOGP(DGPRS, LOGL_NOTICE, "Tns alive expired too often, " + "re-starting RESET procedure\n"); + nsip_connect(nsvc->nsi, &nsvc->ip.bts_addr, nsvc->nsei, + nsvc->nsvci); + } + /* We currently only care about signals from the SGSN */ if (!nsvc->remote_end_is_sgsn) return 0; diff --git a/openbsc/src/gprs/gprs_ns.c b/openbsc/src/gprs/gprs_ns.c index 0ef0c3fcb..fd0b27a6e 100644 --- a/openbsc/src/gprs/gprs_ns.c +++ b/openbsc/src/gprs/gprs_ns.c @@ -362,6 +362,7 @@ static void gprs_ns_timer_cb(void *data) "NSEI=%u Tns-alive expired more then " "%u times, blocking NS-VC\n", nsvc->nsei, NS_ALIVE_RETRIES); + ns_dispatch_signal(nsvc, S_NS_ALIVE_EXP, 0); ns_dispatch_signal(nsvc, S_NS_BLOCK, NS_CAUSE_NSVC_BLOCKED); return; } -- cgit v1.2.3 From 8c2440e1827d75acdbf3a9b27404f497d3494c3a Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 12 May 2010 13:51:08 +0000 Subject: NS: Send STATUS or RESET when receiving NS_ALIVE on unknown NSVC --- openbsc/src/gprs/gprs_ns.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/openbsc/src/gprs/gprs_ns.c b/openbsc/src/gprs/gprs_ns.c index fd0b27a6e..13ea92dd1 100644 --- a/openbsc/src/gprs/gprs_ns.c +++ b/openbsc/src/gprs/gprs_ns.c @@ -582,13 +582,25 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, uint16_t nsei; /* Only the RESET procedure creates a new NSVC */ if (nsh->pdu_type != NS_PDUT_RESET) { + struct gprs_nsvc fake_nsvc; LOGP(DNS, LOGL_INFO, "Ignoring NS PDU type 0x%0x " "from %s:%u for non-existing NS-VC\n", nsh->pdu_type, inet_ntoa(saddr->sin_addr), ntohs(saddr->sin_port)); - /* FIXME: send STATUS (but we have no NSVC!) */ - //gprs_ns_tx_reset(nsvc, NS_CAUSE_NSVC_UNKNOWN); - return -EIO; + /* Since we have no NSVC, we have to create a fake */ + fake_nsvc.nsvci = fake_nsvc.nsei = 0; + fake_nsvc.nsi = nsi; + fake_nsvc.ip.bts_addr = *saddr; + fake_nsvc.state = NSE_S_ALIVE; +#if 0 + return gprs_ns_tx_status(&fake_nsvc, + NS_CAUSE_PDU_INCOMP_PSTATE, 0, + msg); +#else + /* BS+ Gb implementation ignores STATUS, so we try + * our luck with a RESET incompatible with the spec */ + return gprs_ns_tx_simple(&fake_nsvc, NS_PDUT_RESET); +#endif } rc = tlv_parse(&tp, &ns_att_tlvdef, nsh->data, msgb_l2len(msg), 0, 0); @@ -785,8 +797,6 @@ static int nsip_fd_cb(struct bsc_fd *bfd, unsigned int what) return rc; } - -/* FIXME: this is currently in input/ipaccess.c */ extern int make_sock(struct bsc_fd *bfd, int proto, uint16_t port, int (*cb)(struct bsc_fd *fd, unsigned int what)); -- cgit v1.2.3 From d4eaf80acc3201213f38337110ae0b03d2de45cc Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 12 May 2010 13:55:36 +0000 Subject: Display NSEI instead of NSVCI for all debug msgs --- openbsc/src/gprs/gprs_ns.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/openbsc/src/gprs/gprs_ns.c b/openbsc/src/gprs/gprs_ns.c index 13ea92dd1..8cb26a633 100644 --- a/openbsc/src/gprs/gprs_ns.c +++ b/openbsc/src/gprs/gprs_ns.c @@ -332,8 +332,8 @@ static const struct value_string timer_mode_strs[] = { static void nsvc_start_timer(struct gprs_nsvc *nsvc, enum nsvc_timer_mode mode) { - DEBUGP(DNS, "NSVC=%u Starting timer in mode %s (%u seconds)\n", - nsvc->nsvci, get_value_string(timer_mode_strs, mode), + DEBUGP(DNS, "NSEI=%u Starting timer in mode %s (%u seconds)\n", + nsvc->nsei, get_value_string(timer_mode_strs, mode), timer_mode_tout[mode]); if (bsc_timer_pending(&nsvc->timer)) @@ -347,8 +347,8 @@ static void gprs_ns_timer_cb(void *data) { struct gprs_nsvc *nsvc = data; - DEBUGP(DNS, "NSVC=%u Timer expired in mode %s (%u seconds)\n", - nsvc->nsvci, get_value_string(timer_mode_strs, nsvc->timer_mode), + DEBUGP(DNS, "NSEI=%u Timer expired in mode %s (%u seconds)\n", + nsvc->nsei, get_value_string(timer_mode_strs, nsvc->timer_mode), timer_mode_tout[nsvc->timer_mode]); switch (nsvc->timer_mode) { -- cgit v1.2.3 From f6d67c04ee2872777a8d497103cf9f0989f5d16d Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 12 May 2010 14:18:46 +0000 Subject: NS: Send UNBLOCK signal when we get UNBLOCK_ACK from peer --- openbsc/src/gprs/gprs_ns.c | 1 + 1 file changed, 1 insertion(+) diff --git a/openbsc/src/gprs/gprs_ns.c b/openbsc/src/gprs/gprs_ns.c index 8cb26a633..3d672fb8f 100644 --- a/openbsc/src/gprs/gprs_ns.c +++ b/openbsc/src/gprs/gprs_ns.c @@ -678,6 +678,7 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, /* mark NS-VC as unblocked + active */ nsvc->state = NSE_S_ALIVE; nsvc->remote_state = NSE_S_ALIVE; + ns_dispatch_signal(nsvc, S_NS_UNBLOCK, 0); break; case NS_PDUT_BLOCK: rc = gprs_ns_rx_block(nsvc, msg); -- cgit v1.2.3 From 1194b584beb70b7c1ab30fa047f3af31bb3ea0ad Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 12 May 2010 15:55:23 +0000 Subject: NS: Add support for persistent NS-VC configuration With persistent NS-VC configuration (configured through VTY), we can respond properly to BSS with a somewhat strange NS implementation Such as the BSplus. It enables us to respond with a proper NS-RESET (including NSVCI/NSEI) when receiving a NS-ALIVE or other PDU for a BLOCKED/DEAD NS-VC after our end of the connection is rebooted. --- openbsc/include/openbsc/gprs_ns.h | 7 +- openbsc/include/vty/command.h | 1 + openbsc/src/gprs/gb_proxy_main.c | 13 ++- openbsc/src/gprs/gb_proxy_vty.c | 25 ----- openbsc/src/gprs/gprs_ns.c | 225 ++++++++++++++++++++++++++++++++++++-- openbsc/src/gprs/osmo_gbproxy.cfg | 8 +- openbsc/src/vty/command.c | 1 + 7 files changed, 236 insertions(+), 44 deletions(-) diff --git a/openbsc/include/openbsc/gprs_ns.h b/openbsc/include/openbsc/gprs_ns.h index c74546a8b..60051d13b 100644 --- a/openbsc/include/openbsc/gprs_ns.h +++ b/openbsc/include/openbsc/gprs_ns.h @@ -140,7 +140,8 @@ struct gprs_nsvc { enum nsvc_timer_mode timer_mode; int alive_retries; - int remote_end_is_sgsn; + unsigned int remote_end_is_sgsn:1; + unsigned int persistent:1; union { struct { @@ -178,4 +179,8 @@ int nsip_listen(struct gprs_ns_inst *nsi, uint16_t udp_port); struct gprs_nsvc *nsip_connect(struct gprs_ns_inst *nsi, struct sockaddr_in *dest, uint16_t nsei, uint16_t nsvci); + +/* Add NS-specific VTY stuff */ +int gprs_ns_vty_init(struct gprs_ns_inst *nsi); + #endif diff --git a/openbsc/include/vty/command.h b/openbsc/include/vty/command.h index 5f7c819bb..99fba47d9 100644 --- a/openbsc/include/vty/command.h +++ b/openbsc/include/vty/command.h @@ -109,6 +109,7 @@ enum node_type { MGCP_NODE, GBPROXY_NODE, SGSN_NODE, + NS_NODE, }; /* Node which has some commands and prompt string and configuration diff --git a/openbsc/src/gprs/gb_proxy_main.c b/openbsc/src/gprs/gb_proxy_main.c index 7aeb5e41b..510abd09d 100644 --- a/openbsc/src/gprs/gb_proxy_main.c +++ b/openbsc/src/gprs/gb_proxy_main.c @@ -105,11 +105,6 @@ int main(int argc, char **argv) log_set_all_filter(stderr_target, 1); telnet_init(&dummy_network, 4246); - rc = gbproxy_parse_config(config_file, &gbcfg); - if (rc < 0) { - LOGP(DGPRS, LOGL_FATAL, "Cannot parse config file\n"); - exit(2); - } bssgp_nsi = gprs_ns_instantiate(&proxy_ns_cb); if (!bssgp_nsi) { @@ -117,7 +112,15 @@ int main(int argc, char **argv) exit(1); } gbcfg.nsi = bssgp_nsi; + gprs_ns_vty_init(bssgp_nsi); register_signal_handler(SS_NS, &gbprox_signal, NULL); + + rc = gbproxy_parse_config(config_file, &gbcfg); + if (rc < 0) { + LOGP(DGPRS, LOGL_FATAL, "Cannot parse config file\n"); + exit(2); + } + nsip_listen(bssgp_nsi, gbcfg.nsip_listen_port); /* 'establish' the outgoing connection to the SGSN */ diff --git a/openbsc/src/gprs/gb_proxy_vty.c b/openbsc/src/gprs/gb_proxy_vty.c index a40392b90..e0fcfba53 100644 --- a/openbsc/src/gprs/gb_proxy_vty.c +++ b/openbsc/src/gprs/gb_proxy_vty.c @@ -70,29 +70,6 @@ static int config_write_gbproxy(struct vty *vty) return CMD_SUCCESS; } -DEFUN(show_ns, show_ns_cmd, "show ns", - SHOW_STR "Display information about the NS protocol") -{ - /* FIXME: iterate over list of NS-VC's and display their state */ - struct gprs_ns_inst *nsi = g_cfg->nsi; - struct gprs_nsvc *nsvc; - - llist_for_each_entry(nsvc, &nsi->gprs_nsvcs, list) { - vty_out(vty, "NSEI %5u, NS-VC %5u, %s-mode, %s %s%s", - nsvc->nsei, nsvc->nsvci, - nsvc->remote_end_is_sgsn ? "BSS" : "SGSN", - nsvc->state & NSE_S_ALIVE ? "ALIVE" : "DEAD", - nsvc->state & NSE_S_BLOCKED ? "BLOCKED" : "UNBLOCKED", - VTY_NEWLINE); - if (nsvc->nsi->ll == GPRS_NS_LL_UDP) - vty_out(vty, " remote peer %s:%u%s", - inet_ntoa(nsvc->ip.bts_addr.sin_addr), - ntohs(nsvc->ip.bts_addr.sin_port), VTY_NEWLINE); - } - - return CMD_SUCCESS; -} - DEFUN(cfg_gbproxy, cfg_gbproxy_cmd, "gbproxy", @@ -173,10 +150,8 @@ DEFUN(cfg_nsip_sgsn_nsvci, return CMD_SUCCESS; } - int gbproxy_vty_init(void) { - install_element(VIEW_NODE, &show_ns_cmd); install_element(VIEW_NODE, &show_gbproxy_cmd); install_element(CONFIG_NODE, &cfg_gbproxy_cmd); diff --git a/openbsc/src/gprs/gprs_ns.c b/openbsc/src/gprs/gprs_ns.c index 3d672fb8f..ed6421032 100644 --- a/openbsc/src/gprs/gprs_ns.c +++ b/openbsc/src/gprs/gprs_ns.c @@ -131,6 +131,14 @@ static struct gprs_nsvc *nsvc_create(struct gprs_ns_inst *nsi, uint16_t nsvci) return nsvc; } +static void nsvc_delete(struct gprs_nsvc *nsvc) +{ + if (bsc_timer_pending(&nsvc->timer)) + bsc_del_timer(&nsvc->timer); + llist_del(&nsvc->list); + talloc_free(nsvc); +} + static void ns_dispatch_signal(struct gprs_nsvc *nsvc, unsigned int signal, uint8_t cause) { @@ -592,15 +600,9 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, fake_nsvc.nsi = nsi; fake_nsvc.ip.bts_addr = *saddr; fake_nsvc.state = NSE_S_ALIVE; -#if 0 return gprs_ns_tx_status(&fake_nsvc, NS_CAUSE_PDU_INCOMP_PSTATE, 0, msg); -#else - /* BS+ Gb implementation ignores STATUS, so we try - * our luck with a RESET incompatible with the spec */ - return gprs_ns_tx_simple(&fake_nsvc, NS_PDUT_RESET); -#endif } rc = tlv_parse(&tp, &ns_att_tlvdef, nsh->data, msgb_l2len(msg), 0, 0); @@ -628,9 +630,14 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, switch (nsh->pdu_type) { case NS_PDUT_ALIVE: - /* remote end inquires whether we're still alive, - * we need to respond with ALIVE_ACK */ - rc = gprs_ns_tx_alive_ack(nsvc); + /* If we're dead and blocked and suddenly receive a + * NS-ALIVE out of the blue, we might have been re-started + * and should send a NS-RESET to make sure everything recovers + * fine. */ + if (nsvc->state == NSE_S_BLOCKED) + rc = gprs_ns_tx_reset(nsvc, NS_CAUSE_PDU_INCOMP_PSTATE); + else + rc = gprs_ns_tx_alive_ack(nsvc); break; case NS_PDUT_ALIVE_ACK: /* stop Tns-alive */ @@ -844,3 +851,203 @@ struct gprs_nsvc *nsip_connect(struct gprs_ns_inst *nsi, return nsvc; } + +#include +#include + +static struct gprs_ns_inst *vty_nsi = NULL; + +static struct cmd_node ns_node = { + NS_NODE, + "%s(ns)#", + 1, +}; + +static int config_write_ns(struct vty *vty) +{ + struct gprs_nsvc *nsvc; + + vty_out(vty, "ns%s", VTY_NEWLINE); + + llist_for_each_entry(nsvc, &vty_nsi->gprs_nsvcs, list) { + if (!nsvc->persistent) + continue; + vty_out(vty, " nse %u nsvci %u%s", + nsvc->nsei, nsvc->nsvci, VTY_NEWLINE); + vty_out(vty, " nse %u remote-role %s%s", + nsvc->nsei, nsvc->remote_end_is_sgsn ? "sgsn" : "bss", + VTY_NEWLINE); + if (nsvc->nsi->ll == GPRS_NS_LL_UDP) { + vty_out(vty, " nse %u remote-ip %s%s", + nsvc->nsei, + inet_ntoa(nsvc->ip.bts_addr.sin_addr), + VTY_NEWLINE); + vty_out(vty, " nse %u remote-port %u%s", + nsvc->nsei, ntohs(nsvc->ip.bts_addr.sin_port), + VTY_NEWLINE); + } + vty_out(vty, "%s", VTY_NEWLINE); + } + + return CMD_SUCCESS; +} + +DEFUN(cfg_ns, cfg_ns_cmd, + "ns", + "Configure the GPRS Network Service") +{ + vty->node = NS_NODE; + return CMD_SUCCESS; +} + +DEFUN(show_ns, show_ns_cmd, "show ns", + SHOW_STR "Display information about the NS protocol") +{ + struct gprs_ns_inst *nsi = vty_nsi; + struct gprs_nsvc *nsvc; + + llist_for_each_entry(nsvc, &nsi->gprs_nsvcs, list) { + vty_out(vty, "NSEI %5u, NS-VC %5u, Remote: %-4s, %5s %9s", + nsvc->nsei, nsvc->nsvci, + nsvc->remote_end_is_sgsn ? "SGSN" : "BSS", + nsvc->state & NSE_S_ALIVE ? "ALIVE" : "DEAD", + nsvc->state & NSE_S_BLOCKED ? "BLOCKED" : "UNBLOCKED"); + if (nsvc->nsi->ll == GPRS_NS_LL_UDP) + vty_out(vty, ", %15s:%u", + inet_ntoa(nsvc->ip.bts_addr.sin_addr), + ntohs(nsvc->ip.bts_addr.sin_port)); + vty_out(vty, "%s", VTY_NEWLINE); + } + + return CMD_SUCCESS; +} + + +#define NSE_CMD_STR "NS Entity\n" "NS Entity ID (NSEI)\n" + +DEFUN(cfg_nse_nsvc, cfg_nse_nsvci_cmd, + "nse <0-65535> nsvci <0-65534>", + NSE_CMD_STR + "NS Virtual Connection\n" + "NS Virtual Connection ID (NSVCI)\n" + ) +{ + uint16_t nsei = atoi(argv[0]); + uint16_t nsvci = atoi(argv[1]); + struct gprs_nsvc *nsvc; + + nsvc = nsvc_by_nsei(vty_nsi, nsei); + if (!nsvc) { + nsvc = nsvc_create(vty_nsi, nsvci); + nsvc->nsei = nsei; + } + nsvc->nsvci = nsvci; + /* All NSVCs that are explicitly configured by VTY are + * marked as persistent so we can write them to the config + * file at some later point */ + nsvc->persistent = 1; + + return CMD_SUCCESS; +} + +DEFUN(cfg_nse_remoteip, cfg_nse_remoteip_cmd, + "nse <0-65535> remote-ip A.B.C.D", + NSE_CMD_STR + "Remote IP Address\n" + "Remote IP Address\n") +{ + uint16_t nsei = atoi(argv[0]); + struct gprs_nsvc *nsvc; + + nsvc = nsvc_by_nsei(vty_nsi, nsei); + if (!nsvc) { + vty_out(vty, "No such NSE (%u)%s", nsei, VTY_NEWLINE); + return CMD_WARNING; + } + inet_aton(argv[1], &nsvc->ip.bts_addr.sin_addr); + + return CMD_SUCCESS; + +} + +DEFUN(cfg_nse_remoteport, cfg_nse_remoteport_cmd, + "nse <0-65535> remote-port <0-65535>", + NSE_CMD_STR + "Remote UDP Port\n" + "Remote UDP Port Number\n") +{ + uint16_t nsei = atoi(argv[0]); + uint16_t port = atoi(argv[1]); + struct gprs_nsvc *nsvc; + + nsvc = nsvc_by_nsei(vty_nsi, nsei); + if (!nsvc) { + vty_out(vty, "No such NSE (%u)%s", nsei, VTY_NEWLINE); + return CMD_WARNING; + } + + nsvc->ip.bts_addr.sin_port = htons(port); + + return CMD_SUCCESS; +} + +DEFUN(cfg_nse_remoterole, cfg_nse_remoterole_cmd, + "nse <0-65535> remote-role (sgsn|bss)", + NSE_CMD_STR + "Remote NSE Role\n" + "Remote Peer is SGSN\n" + "Remote Peer is BSS\n") +{ + uint16_t nsei = atoi(argv[0]); + struct gprs_nsvc *nsvc; + + nsvc = nsvc_by_nsei(vty_nsi, nsei); + if (!nsvc) { + vty_out(vty, "No such NSE (%u)%s", nsei, VTY_NEWLINE); + return CMD_WARNING; + } + + if (!strcmp(argv[1], "sgsn")) + nsvc->remote_end_is_sgsn = 1; + else + nsvc->remote_end_is_sgsn = 0; + + return CMD_SUCCESS; +} + +DEFUN(cfg_no_nse, cfg_no_nse_cmd, + "no nse <0-65535>", + "Delete NS Entity\n" + "Delete " NSE_CMD_STR) +{ + uint16_t nsei = atoi(argv[0]); + struct gprs_nsvc *nsvc; + + nsvc = nsvc_by_nsei(vty_nsi, nsei); + if (!nsvc) { + vty_out(vty, "No such NSE (%u)%s", nsei, VTY_NEWLINE); + return CMD_WARNING; + } + + nsvc_delete(nsvc); + + return CMD_SUCCESS; +} + +int gprs_ns_vty_init(struct gprs_ns_inst *nsi) +{ + vty_nsi = nsi; + + install_element(VIEW_NODE, &show_ns_cmd); + + install_element(CONFIG_NODE, &cfg_ns_cmd); + install_node(&ns_node, config_write_ns); + install_default(NS_NODE); + install_element(NS_NODE, &cfg_nse_nsvci_cmd); + install_element(NS_NODE, &cfg_nse_remoteip_cmd); + install_element(NS_NODE, &cfg_nse_remoteport_cmd); + install_element(NS_NODE, &cfg_nse_remoterole_cmd); + install_element(NS_NODE, &cfg_no_nse_cmd); + + return 0; +} diff --git a/openbsc/src/gprs/osmo_gbproxy.cfg b/openbsc/src/gprs/osmo_gbproxy.cfg index f2ef1411f..d51b04a11 100644 --- a/openbsc/src/gprs/osmo_gbproxy.cfg +++ b/openbsc/src/gprs/osmo_gbproxy.cfg @@ -7,7 +7,7 @@ line vty ! gbproxy nsip bss local port 23000 - nsip sgsn remote ip 192.168.100.239 - nsip sgsn remote port 23000 - nsip sgsn nsei 1 - nsip sgsn nsvci 11 + nsip sgsn remote ip 127.0.0.1 + nsip sgsn remote port 7777 + nsip sgsn nsei 101 + nsip sgsn nsvci 101 diff --git a/openbsc/src/vty/command.c b/openbsc/src/vty/command.c index 67e6804fe..fe29824ba 100644 --- a/openbsc/src/vty/command.c +++ b/openbsc/src/vty/command.c @@ -2365,6 +2365,7 @@ gDEFUN(config_exit, case MGCP_NODE: case GBPROXY_NODE: case SGSN_NODE: + case NS_NODE: vty->node = CONFIG_NODE; vty->index = NULL; default: -- cgit v1.2.3 From d9c69cc7fed5a9069cba69f6d123b887bc51889e Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 12 May 2010 15:57:38 +0000 Subject: Gb Proxy: Cosmetic fix of VTY file writing --- openbsc/src/gprs/gb_proxy_vty.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/openbsc/src/gprs/gb_proxy_vty.c b/openbsc/src/gprs/gb_proxy_vty.c index e0fcfba53..f02b5525f 100644 --- a/openbsc/src/gprs/gb_proxy_vty.c +++ b/openbsc/src/gprs/gb_proxy_vty.c @@ -52,19 +52,19 @@ static int config_write_gbproxy(struct vty *vty) if (g_cfg->nsip_listen_ip) { ia.s_addr = htonl(g_cfg->nsip_listen_ip); - vty_out(vty, " nsip bss local ip %s%s", inet_ntoa(ia), + vty_out(vty, " nsip bss local ip %s%s", inet_ntoa(ia), VTY_NEWLINE); } - vty_out(vty, " nsip bss local port %u%s", g_cfg->nsip_listen_port, + vty_out(vty, " nsip bss local port %u%s", g_cfg->nsip_listen_port, VTY_NEWLINE); ia.s_addr = htonl(g_cfg->nsip_sgsn_ip); - vty_out(vty, " nsip sgsn remote ip %s%s", inet_ntoa(ia), + vty_out(vty, " nsip sgsn remote ip %s%s", inet_ntoa(ia), VTY_NEWLINE); - vty_out(vty, " nsip sgsn remote port %u%s", g_cfg->nsip_sgsn_port, + vty_out(vty, " nsip sgsn remote port %u%s", g_cfg->nsip_sgsn_port, VTY_NEWLINE); - vty_out(vty, " nsip sgsn nsei %u%s", g_cfg->nsip_sgsn_nsei, + vty_out(vty, " nsip sgsn nsei %u%s", g_cfg->nsip_sgsn_nsei, VTY_NEWLINE); - vty_out(vty, " nsip sgsn nsvci %u%s", g_cfg->nsip_sgsn_nsvci, + vty_out(vty, " nsip sgsn nsvci %u%s", g_cfg->nsip_sgsn_nsvci, VTY_NEWLINE); return CMD_SUCCESS; -- cgit v1.2.3 From 50a6dfee37cf71e0b9b3776c04635eea16d962a3 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 12 May 2010 16:03:27 +0000 Subject: Make sure all commands of SHOW_NODE to ENABLE_NODE --- openbsc/src/gprs/gb_proxy_vty.c | 1 + openbsc/src/gprs/gprs_ns.c | 1 + 2 files changed, 2 insertions(+) diff --git a/openbsc/src/gprs/gb_proxy_vty.c b/openbsc/src/gprs/gb_proxy_vty.c index f02b5525f..df2100210 100644 --- a/openbsc/src/gprs/gb_proxy_vty.c +++ b/openbsc/src/gprs/gb_proxy_vty.c @@ -153,6 +153,7 @@ DEFUN(cfg_nsip_sgsn_nsvci, int gbproxy_vty_init(void) { install_element(VIEW_NODE, &show_gbproxy_cmd); + install_element(ENABLE_NODE, &show_gbproxy_cmd); install_element(CONFIG_NODE, &cfg_gbproxy_cmd); install_node(&gbproxy_node, config_write_gbproxy); diff --git a/openbsc/src/gprs/gprs_ns.c b/openbsc/src/gprs/gprs_ns.c index ed6421032..9f65489f7 100644 --- a/openbsc/src/gprs/gprs_ns.c +++ b/openbsc/src/gprs/gprs_ns.c @@ -1039,6 +1039,7 @@ int gprs_ns_vty_init(struct gprs_ns_inst *nsi) vty_nsi = nsi; install_element(VIEW_NODE, &show_ns_cmd); + install_element(ENABLE_NODE, &show_ns_cmd); install_element(CONFIG_NODE, &cfg_ns_cmd); install_node(&ns_node, config_write_ns); -- cgit v1.2.3 From b4d5b17a8d87d5ec5c15c3376a51154532f81017 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 12 May 2010 16:10:35 +0000 Subject: Ensure all 'view' commands are availalbe from 'enable' too --- openbsc/include/vty/command.h | 1 + openbsc/src/vty/command.c | 7 +++++++ openbsc/src/vty_interface.c | 18 +++++++++--------- openbsc/src/vty_interface_cmds.c | 19 +++++++++---------- openbsc/src/vty_interface_layer3.c | 16 ++++++++-------- 5 files changed, 34 insertions(+), 27 deletions(-) diff --git a/openbsc/include/vty/command.h b/openbsc/include/vty/command.h index 99fba47d9..1b6e0a7b7 100644 --- a/openbsc/include/vty/command.h +++ b/openbsc/include/vty/command.h @@ -350,6 +350,7 @@ struct desc { void install_node(struct cmd_node *, int (*)(struct vty *)); void install_default(enum node_type); void install_element(enum node_type, struct cmd_element *); +void install_element_ve(struct cmd_element *cmd); void sort_node(); /* Concatenates argv[shift] through argv[argc-1] into a single NUL-terminated diff --git a/openbsc/src/vty/command.c b/openbsc/src/vty/command.c index fe29824ba..a1130b68e 100644 --- a/openbsc/src/vty/command.c +++ b/openbsc/src/vty/command.c @@ -478,6 +478,13 @@ void install_element(enum node_type ntype, struct cmd_element *cmd) cmd->cmdsize = cmd_cmdsize(cmd->strvec); } +/* Install a command into VIEW and ENABLE node */ +void install_element_ve(struct cmd_element *cmd) +{ + install_element(VIEW_NODE, cmd); + install_element(ENABLE_NODE, cmd); +} + #ifdef VTY_CRYPT_PW static unsigned char itoa64[] = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c index 48dce9e4e..acfdd94de 100644 --- a/openbsc/src/vty_interface.c +++ b/openbsc/src/vty_interface.c @@ -1904,17 +1904,17 @@ int bsc_vty_init(struct gsm_network *net) cmd_init(1); vty_init(); - install_element(VIEW_NODE, &show_net_cmd); - install_element(VIEW_NODE, &show_bts_cmd); - install_element(VIEW_NODE, &show_trx_cmd); - install_element(VIEW_NODE, &show_ts_cmd); - install_element(VIEW_NODE, &show_lchan_cmd); + install_element_ve(&show_net_cmd); + install_element_ve(&show_bts_cmd); + install_element_ve(&show_trx_cmd); + install_element_ve(&show_ts_cmd); + install_element_ve(&show_lchan_cmd); - install_element(VIEW_NODE, &show_e1drv_cmd); - install_element(VIEW_NODE, &show_e1line_cmd); - install_element(VIEW_NODE, &show_e1ts_cmd); + install_element_ve(&show_e1drv_cmd); + install_element_ve(&show_e1line_cmd); + install_element_ve(&show_e1ts_cmd); - install_element(VIEW_NODE, &show_paging_cmd); + install_element_ve(&show_paging_cmd); openbsc_vty_add_cmds(); diff --git a/openbsc/src/vty_interface_cmds.c b/openbsc/src/vty_interface_cmds.c index 31818925f..dd5e108ab 100644 --- a/openbsc/src/vty_interface_cmds.c +++ b/openbsc/src/vty_interface_cmds.c @@ -324,14 +324,13 @@ void openbsc_vty_print_statistics(struct vty *vty, struct gsm_network *net) void openbsc_vty_add_cmds() { - install_element(VIEW_NODE, &enable_logging_cmd); - install_element(VIEW_NODE, &disable_logging_cmd); - install_element(VIEW_NODE, &logging_fltr_imsi_cmd); - install_element(VIEW_NODE, &logging_fltr_all_cmd); - install_element(VIEW_NODE, &logging_use_clr_cmd); - install_element(VIEW_NODE, &logging_prnt_timestamp_cmd); - install_element(VIEW_NODE, &logging_set_category_mask_cmd); - install_element(VIEW_NODE, &logging_level_cmd); - install_element(VIEW_NODE, &show_logging_vty_cmd); - + install_element_ve(&enable_logging_cmd); + install_element_ve(&disable_logging_cmd); + install_element_ve(&logging_fltr_imsi_cmd); + install_element_ve(&logging_fltr_all_cmd); + install_element_ve(&logging_use_clr_cmd); + install_element_ve(&logging_prnt_timestamp_cmd); + install_element_ve(&logging_set_category_mask_cmd); + install_element_ve(&logging_level_cmd); + install_element_ve(&show_logging_vty_cmd); } diff --git a/openbsc/src/vty_interface_layer3.c b/openbsc/src/vty_interface_layer3.c index fee5baee5..1b2adbbc7 100644 --- a/openbsc/src/vty_interface_layer3.c +++ b/openbsc/src/vty_interface_layer3.c @@ -544,16 +544,16 @@ int bsc_vty_init_extra(struct gsm_network *net) register_signal_handler(SS_SCALL, scall_cbfn, NULL); - install_element(VIEW_NODE, &show_subscr_cmd); - install_element(VIEW_NODE, &show_subscr_cache_cmd); + install_element_ve(&show_subscr_cmd); + install_element_ve(&show_subscr_cache_cmd); - install_element(VIEW_NODE, &sms_send_pend_cmd); + install_element_ve(&sms_send_pend_cmd); - install_element(VIEW_NODE, &subscriber_send_sms_cmd); - install_element(VIEW_NODE, &subscriber_silent_sms_cmd); - install_element(VIEW_NODE, &subscriber_silent_call_start_cmd); - install_element(VIEW_NODE, &subscriber_silent_call_stop_cmd); - install_element(VIEW_NODE, &show_stats_cmd); + install_element_ve(&subscriber_send_sms_cmd); + install_element_ve(&subscriber_silent_sms_cmd); + install_element_ve(&subscriber_silent_call_start_cmd); + install_element_ve(&subscriber_silent_call_stop_cmd); + install_element_ve(&show_stats_cmd); install_element(CONFIG_NODE, &cfg_subscr_cmd); install_node(&subscr_node, dummy_config_write); -- cgit v1.2.3 From aa0db809e23bedd7bfac278c8a7d5f127a15e00b Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Thu, 13 May 2010 00:37:48 +0800 Subject: abis: Pass the abis_om_obj_inst in the nm_state_event.. --- openbsc/include/openbsc/abis_nm.h | 3 ++- openbsc/src/abis_nm.c | 4 ++-- openbsc/src/bs11_config.c | 3 ++- openbsc/src/bsc_init.c | 3 ++- openbsc/src/ipaccess/ipaccess-config.c | 3 ++- 5 files changed, 10 insertions(+), 6 deletions(-) diff --git a/openbsc/include/openbsc/abis_nm.h b/openbsc/include/openbsc/abis_nm.h index 45307e3c8..1b6a8fe5d 100644 --- a/openbsc/include/openbsc/abis_nm.h +++ b/openbsc/include/openbsc/abis_nm.h @@ -164,7 +164,8 @@ enum nm_evt { EVT_STATECHG_ADM, }; int nm_state_event(enum nm_evt evt, u_int8_t obj_class, void *obj, - struct gsm_nm_state *old_state, struct gsm_nm_state *new_state); + struct gsm_nm_state *old_state, struct gsm_nm_state *new_state, + struct abis_om_obj_inst *obj_inst); const char *nm_opstate_name(u_int8_t os); const char *nm_avail_name(u_int8_t avail); diff --git a/openbsc/src/abis_nm.c b/openbsc/src/abis_nm.c index c78ee5699..42f610d82 100644 --- a/openbsc/src/abis_nm.c +++ b/openbsc/src/abis_nm.c @@ -678,7 +678,7 @@ static int update_admstate(struct gsm_bts *bts, u_int8_t obj_class, new_state = *nm_state; new_state.administrative = adm_state; - rc = nm_state_event(EVT_STATECHG_ADM, obj_class, obj, nm_state, &new_state); + rc = nm_state_event(EVT_STATECHG_ADM, obj_class, obj, nm_state, &new_state, obj_inst); nm_state->administrative = adm_state; @@ -732,7 +732,7 @@ static int abis_nm_rx_statechg_rep(struct msgb *mb) /* Update the operational state of a given object in our in-memory data * structures and send an event to the higher layer */ void *obj = objclass2obj(bts, foh->obj_class, &foh->obj_inst); - rc = nm_state_event(EVT_STATECHG_OPER, foh->obj_class, obj, nm_state, &new_state); + rc = nm_state_event(EVT_STATECHG_OPER, foh->obj_class, obj, nm_state, &new_state, &foh->obj_inst); nm_state->operational = new_state.operational; nm_state->availability = new_state.availability; if (nm_state->administrative == 0) diff --git a/openbsc/src/bs11_config.c b/openbsc/src/bs11_config.c index a7493b422..d8819d391 100644 --- a/openbsc/src/bs11_config.c +++ b/openbsc/src/bs11_config.c @@ -697,7 +697,8 @@ int handle_serial_msg(struct msgb *rx_msg) } int nm_state_event(enum nm_evt evt, u_int8_t obj_class, void *obj, - struct gsm_nm_state *old_state, struct gsm_nm_state *new_state) + struct gsm_nm_state *old_state, struct gsm_nm_state *new_state, + struct abis_om_obj_inst *obj_ins) { return 0; } diff --git a/openbsc/src/bsc_init.c b/openbsc/src/bsc_init.c index 38f5dfbba..77446a2c1 100644 --- a/openbsc/src/bsc_init.c +++ b/openbsc/src/bsc_init.c @@ -401,7 +401,8 @@ static unsigned char nanobts_attr_nsvc0[] = { /* Callback function to be called whenever we get a GSM 12.21 state change event */ int nm_state_event(enum nm_evt evt, u_int8_t obj_class, void *obj, - struct gsm_nm_state *old_state, struct gsm_nm_state *new_state) + struct gsm_nm_state *old_state, struct gsm_nm_state *new_state, + struct abis_om_obj_inst *obj_inst) { struct gsm_bts *bts; struct gsm_bts_trx *trx; diff --git a/openbsc/src/ipaccess/ipaccess-config.c b/openbsc/src/ipaccess/ipaccess-config.c index 075a264fc..0dab9cbe3 100644 --- a/openbsc/src/ipaccess/ipaccess-config.c +++ b/openbsc/src/ipaccess/ipaccess-config.c @@ -392,7 +392,8 @@ void input_event(int event, enum e1inp_sign_type type, struct gsm_bts_trx *trx) } int nm_state_event(enum nm_evt evt, u_int8_t obj_class, void *obj, - struct gsm_nm_state *old_state, struct gsm_nm_state *new_state) + struct gsm_nm_state *old_state, struct gsm_nm_state *new_state, + struct abis_om_obj_inst *obj_inst) { if (evt == EVT_STATECHG_OPER && obj_class == NM_OC_RADIO_CARRIER && -- cgit v1.2.3 From 5fbf5f4f8d1666bd3c9a5a2f5f89921b21a0231f Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Wed, 12 May 2010 16:44:01 +0800 Subject: ipaccess: Wait for the BASEBAND_TRANSCEIVER and then bootstrap OML Currently we are connecting to the BTS and once the OML is established we are bootstrapping the OML. This does not work for a multi TRX setup as we will need to use a trx_nr != 0 for it. Change the code to wait for a message (in this case NM OC_BASEBAND_TRANSC) to detect the trx_nr used by the BTS and then use that TRX to bootstrap the network. I have tested setting the unit id on a single and multi trx system for the first and second trx. --- openbsc/src/ipaccess/ipaccess-config.c | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/openbsc/src/ipaccess/ipaccess-config.c b/openbsc/src/ipaccess/ipaccess-config.c index 0dab9cbe3..081839b83 100644 --- a/openbsc/src/ipaccess/ipaccess-config.c +++ b/openbsc/src/ipaccess/ipaccess-config.c @@ -1,8 +1,8 @@ /* ip.access nanoBTS configuration tool */ /* (C) 2009 by Harald Welte - * (C) 2009 by Holger Hans Peter Freyther - * (C) 2009 by On Waves + * (C) 2009,2010 by Holger Hans Peter Freyther + * (C) 2009,2010 by On Waves * All Rights Reserved * * This program is free software; you can redistribute it and/or modify @@ -59,7 +59,7 @@ static int sw_load_state = 0; static int oml_state = 0; static int dump_files = 0; static char *firmware_analysis = NULL; -static int trx_nr = 0; +static int found_trx = 0; struct sw_load { u_int8_t file_id[255]; @@ -299,13 +299,14 @@ static int swload_cbfn(unsigned int hook, unsigned int event, struct msgb *_msg, return 0; } -static void bootstrap_om(struct gsm_bts *bts) +static void bootstrap_om(struct gsm_bts_trx *trx) { int len; static u_int8_t buf[1024]; u_int8_t *cur = buf; + struct gsm_bts *bts = trx->bts; - printf("OML link established\n"); + printf("OML link established using TRX %d\n", trx->nr); if (unit_id) { len = strlen(unit_id); @@ -317,8 +318,7 @@ static void bootstrap_om(struct gsm_bts *bts) memcpy(buf+3, unit_id, len); buf[3+len] = 0; printf("setting Unit ID to '%s'\n", unit_id); - abis_nm_ipaccess_set_nvattr(gsm_bts_trx_by_nr(bts, trx_nr), - buf, 3+len+1); + abis_nm_ipaccess_set_nvattr(trx, buf, 3+len+1); } if (prim_oml_ip) { struct in_addr ia; @@ -356,8 +356,7 @@ static void bootstrap_om(struct gsm_bts *bts) *cur++ = nv_mask >> 8; printf("setting NV Flags/Mask to 0x%04x/0x%04x\n", nv_flags, nv_mask); - abis_nm_ipaccess_set_nvattr(gsm_bts_trx_by_nr(bts, trx_nr), - buf, 3+len); + abis_nm_ipaccess_set_nvattr(trx, buf, 3+len); } if (restart && !prim_oml_ip && !software) { @@ -373,7 +372,6 @@ void input_event(int event, enum e1inp_sign_type type, struct gsm_bts_trx *trx) case EVT_E1_TEI_UP: switch (type) { case E1INP_SIGN_OML: - bootstrap_om(trx->bts); break; case E1INP_SIGN_RSL: /* FIXME */ @@ -395,7 +393,13 @@ int nm_state_event(enum nm_evt evt, u_int8_t obj_class, void *obj, struct gsm_nm_state *old_state, struct gsm_nm_state *new_state, struct abis_om_obj_inst *obj_inst) { - if (evt == EVT_STATECHG_OPER && + if (obj_class == NM_OC_BASEB_TRANSC) { + if (!found_trx && obj_inst->trx_nr != 0xff) { + struct gsm_bts_trx *trx = container_of(obj, struct gsm_bts_trx, bb_transc); + bootstrap_om(trx); + found_trx = 1; + } + } else if (evt == EVT_STATECHG_OPER && obj_class == NM_OC_RADIO_CARRIER && new_state->availability == 3) { struct gsm_bts_trx *trx = obj; @@ -609,7 +613,6 @@ static void print_help(void) printf(" -d --software firmware\n"); printf(" -f --firmware firmware Provide firmware information\n"); printf(" -w --write-firmware. This will dump the firmware parts to the filesystem. Use with -f.\n"); - printf(" -t --trx NR. The TRX to use for the Unit ID and NVRAM attributes.\n"); } int main(int argc, char **argv) @@ -644,11 +647,10 @@ int main(int argc, char **argv) { "software", 1, 0, 'd' }, { "firmware", 1, 0, 'f' }, { "write-firmware", 0, 0, 'w' }, - { "trx", 1, 0, 't' }, { 0, 0, 0, 0 }, }; - c = getopt_long(argc, argv, "u:o:rn:l:hs:d:f:wt:", long_options, + c = getopt_long(argc, argv, "u:o:rn:l:hs:d:f:w", long_options, &option_index); if (c == -1) @@ -690,9 +692,6 @@ int main(int argc, char **argv) case 'w': dump_files = 1; break; - case 't': - trx_nr = atoi(optarg); - break; case 'h': print_usage(); print_help(); -- cgit v1.2.3 From 505f20d7c48f868a5cebddedfaa35e979a80020a Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Wed, 12 May 2010 22:48:28 +0800 Subject: ipaccess: Use the current TRX to set the OML address. --- openbsc/src/ipaccess/ipaccess-config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openbsc/src/ipaccess/ipaccess-config.c b/openbsc/src/ipaccess/ipaccess-config.c index 081839b83..0f83b900c 100644 --- a/openbsc/src/ipaccess/ipaccess-config.c +++ b/openbsc/src/ipaccess/ipaccess-config.c @@ -342,7 +342,7 @@ static void bootstrap_om(struct gsm_bts_trx *trx) *cur++ = 0; printf("setting primary OML link IP to '%s'\n", inet_ntoa(ia)); oml_state = 1; - abis_nm_ipaccess_set_nvattr(bts->c0, buf, 3+len); + abis_nm_ipaccess_set_nvattr(trx, buf, 3+len); } if (nv_mask) { len = 4; -- cgit v1.2.3 From 9958f477b4b98f0c2d99a766612f44e080a94d3b Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Wed, 12 May 2010 23:02:23 +0800 Subject: ipaccess: Use the right trx when performing the test --- openbsc/src/ipaccess/ipaccess-config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openbsc/src/ipaccess/ipaccess-config.c b/openbsc/src/ipaccess/ipaccess-config.c index 0f83b900c..0f8c16c0b 100644 --- a/openbsc/src/ipaccess/ipaccess-config.c +++ b/openbsc/src/ipaccess/ipaccess-config.c @@ -406,7 +406,7 @@ int nm_state_event(enum nm_evt evt, u_int8_t obj_class, void *obj, if (net_listen_testnr) { u_int8_t phys_config[] = { 0x02, 0x0a, 0x00, 0x01, 0x02 }; - abis_nm_perform_test(trx->bts, 2, 0, 0, 0xff, + abis_nm_perform_test(trx->bts, 2, 0, trx->nr, 0xff, net_listen_testnr, 1, phys_config, sizeof(phys_config)); } else if (software) { -- cgit v1.2.3 From ebead597ff571ac6d4eb2986b64aa5242a563382 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Wed, 12 May 2010 23:16:59 +0800 Subject: ipaccess: Refactor... unite some code --- openbsc/src/ipaccess/ipaccess-config.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/openbsc/src/ipaccess/ipaccess-config.c b/openbsc/src/ipaccess/ipaccess-config.c index 0f8c16c0b..da0131ace 100644 --- a/openbsc/src/ipaccess/ipaccess-config.c +++ b/openbsc/src/ipaccess/ipaccess-config.c @@ -92,23 +92,23 @@ static int ipacc_msg_nack(u_int8_t mt) return 0; } +static void check_restart_or_exit(struct gsm_bts *bts) +{ + if (restart) { + abis_nm_ipaccess_restart(bts); + } else { + exit(0); + } +} + static int ipacc_msg_ack(u_int8_t mt, struct gsm_bts *bts) { if (sw_load_state == 1) { fprintf(stderr, "The new software is activaed.\n"); - - if (restart) { - abis_nm_ipaccess_restart(bts); - } else { - exit(0); - } + check_restart_or_exit(bts); } else if (oml_state == 1) { fprintf(stderr, "Set the primary OML IP.\n"); - if (restart) { - abis_nm_ipaccess_restart(bts); - } else { - exit(0); - } + check_restart_or_exit(bts); } return 0; -- cgit v1.2.3 From 52fd4e4395cd8852ac0dcb31062cce60f1b97209 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Wed, 12 May 2010 23:34:51 +0800 Subject: ipaccess: Send the reset to the BASEBAND_TRANSC and supply TRX Send the IPA Restart to a given BTS/TRX, change the signal callbacks to carry the trx instead of the BTS so we have an easy access to the right TRX and change the ipaccess-config to use that TRX. This is fixing the restart with a multi TRX setup. Even if we have the msg->trx, use the gsm_bts_trx_by_nr and get the TRX from the fom header. This is because the OpenBSC and the BTS numbering might not match for the multi TRX case. --- openbsc/include/openbsc/abis_nm.h | 2 +- openbsc/include/openbsc/signal.h | 2 +- openbsc/src/abis_nm.c | 15 +++++++++++---- openbsc/src/ipaccess/ipaccess-config.c | 15 +++++++-------- 4 files changed, 20 insertions(+), 14 deletions(-) diff --git a/openbsc/include/openbsc/abis_nm.h b/openbsc/include/openbsc/abis_nm.h index 1b6a8fe5d..1e9197e29 100644 --- a/openbsc/include/openbsc/abis_nm.h +++ b/openbsc/include/openbsc/abis_nm.h @@ -148,7 +148,7 @@ int abis_nm_ipaccess_msg(struct gsm_bts *bts, u_int8_t msg_type, u_int8_t *attr, int attr_len); int abis_nm_ipaccess_set_nvattr(struct gsm_bts_trx *trx, u_int8_t *attr, int attr_len); -int abis_nm_ipaccess_restart(struct gsm_bts *bts); +int abis_nm_ipaccess_restart(struct gsm_bts_trx *trx); int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, u_int8_t obj_class, u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr, u_int8_t *attr, u_int8_t attr_len); diff --git a/openbsc/include/openbsc/signal.h b/openbsc/include/openbsc/signal.h index fbb4163d7..48f7946b3 100644 --- a/openbsc/include/openbsc/signal.h +++ b/openbsc/include/openbsc/signal.h @@ -135,7 +135,7 @@ struct scall_signal_data { }; struct ipacc_ack_signal_data { - struct gsm_bts *bts; + struct gsm_bts_trx *trx; u_int8_t msg_type; }; diff --git a/openbsc/src/abis_nm.c b/openbsc/src/abis_nm.c index 42f610d82..ee0604d3c 100644 --- a/openbsc/src/abis_nm.c +++ b/openbsc/src/abis_nm.c @@ -2775,12 +2775,12 @@ static int abis_nm_rx_ipacc(struct msgb *msg) case NM_MT_IPACC_RSL_CONNECT_NACK: case NM_MT_IPACC_SET_NVATTR_NACK: case NM_MT_IPACC_GET_NVATTR_NACK: - signal.bts = msg->trx->bts; + signal.trx = gsm_bts_trx_by_nr(msg->trx->bts, foh->obj_inst.trx_nr); signal.msg_type = foh->msg_type; dispatch_signal(SS_NM, S_NM_IPACC_NACK, &signal); break; case NM_MT_IPACC_SET_NVATTR_ACK: - signal.bts = msg->trx->bts; + signal.trx = gsm_bts_trx_by_nr(msg->trx->bts, foh->obj_inst.trx_nr); signal.msg_type = foh->msg_type; dispatch_signal(SS_NM, S_NM_IPACC_ACK, &signal); break; @@ -2866,9 +2866,16 @@ int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx, } /* restart / reboot an ip.access nanoBTS */ -int abis_nm_ipaccess_restart(struct gsm_bts *bts) +int abis_nm_ipaccess_restart(struct gsm_bts_trx *trx) { - return __simple_cmd(bts, NM_MT_IPACC_RESTART); + struct abis_om_hdr *oh; + struct msgb *msg = nm_msgb_alloc(); + + oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE); + fill_om_fom_hdr(oh, 0, NM_MT_IPACC_RESTART, NM_OC_BASEB_TRANSC, + trx->bts->nr, trx->nr, 0xff); + + return abis_nm_sendmsg(trx->bts, msg); } int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, u_int8_t obj_class, diff --git a/openbsc/src/ipaccess/ipaccess-config.c b/openbsc/src/ipaccess/ipaccess-config.c index da0131ace..556220a95 100644 --- a/openbsc/src/ipaccess/ipaccess-config.c +++ b/openbsc/src/ipaccess/ipaccess-config.c @@ -92,23 +92,23 @@ static int ipacc_msg_nack(u_int8_t mt) return 0; } -static void check_restart_or_exit(struct gsm_bts *bts) +static void check_restart_or_exit(struct gsm_bts_trx *trx) { if (restart) { - abis_nm_ipaccess_restart(bts); + abis_nm_ipaccess_restart(trx); } else { exit(0); } } -static int ipacc_msg_ack(u_int8_t mt, struct gsm_bts *bts) +static int ipacc_msg_ack(u_int8_t mt, struct gsm_bts_trx *trx) { if (sw_load_state == 1) { fprintf(stderr, "The new software is activaed.\n"); - check_restart_or_exit(bts); + check_restart_or_exit(trx); } else if (oml_state == 1) { fprintf(stderr, "Set the primary OML IP.\n"); - check_restart_or_exit(bts); + check_restart_or_exit(trx); } return 0; @@ -203,7 +203,7 @@ static int nm_sig_cb(unsigned int subsys, unsigned int signal, return ipacc_msg_nack(ipacc_data->msg_type); case S_NM_IPACC_ACK: ipacc_data = signal_data; - return ipacc_msg_ack(ipacc_data->msg_type, ipacc_data->bts); + return ipacc_msg_ack(ipacc_data->msg_type, ipacc_data->trx); case S_NM_TEST_REP: return test_rep(signal_data); case S_NM_IPACC_RESTART_ACK: @@ -304,7 +304,6 @@ static void bootstrap_om(struct gsm_bts_trx *trx) int len; static u_int8_t buf[1024]; u_int8_t *cur = buf; - struct gsm_bts *bts = trx->bts; printf("OML link established using TRX %d\n", trx->nr); @@ -361,7 +360,7 @@ static void bootstrap_om(struct gsm_bts_trx *trx) if (restart && !prim_oml_ip && !software) { printf("restarting BTS\n"); - abis_nm_ipaccess_restart(bts); + abis_nm_ipaccess_restart(trx); } } -- cgit v1.2.3 From 64278ede35b8c315a96508beab79643da89f37c2 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Wed, 12 May 2010 23:51:46 +0800 Subject: sw_load: Specify the trx_nr for the software load For the multi TRX setup we will need to specify the right trx->nr to be able to flash the BTS. For the BS11 case we are ignoring the additional argument. --- openbsc/include/openbsc/abis_nm.h | 2 +- openbsc/src/abis_nm.c | 12 +++++++----- openbsc/src/bs11_config.c | 2 +- openbsc/src/ipaccess/ipaccess-config.c | 2 +- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/openbsc/include/openbsc/abis_nm.h b/openbsc/include/openbsc/abis_nm.h index 1e9197e29..c20e4e172 100644 --- a/openbsc/include/openbsc/abis_nm.h +++ b/openbsc/include/openbsc/abis_nm.h @@ -92,7 +92,7 @@ int abis_nm_sw_act_req_ack(struct gsm_bts *bts, u_int8_t obj_class, u_int8_t i1, int abis_nm_raw_msg(struct gsm_bts *bts, int len, u_int8_t *msg); int abis_nm_event_reports(struct gsm_bts *bts, int on); int abis_nm_reset_resource(struct gsm_bts *bts); -int abis_nm_software_load(struct gsm_bts *bts, const char *fname, +int abis_nm_software_load(struct gsm_bts *bts, int trx_nr, const char *fname, u_int8_t win_size, int forced, gsm_cbfn *cbfn, void *cb_data); int abis_nm_software_load_status(struct gsm_bts *bts); diff --git a/openbsc/src/abis_nm.c b/openbsc/src/abis_nm.c index ee0604d3c..09285bd43 100644 --- a/openbsc/src/abis_nm.c +++ b/openbsc/src/abis_nm.c @@ -1139,6 +1139,7 @@ enum sw_state { struct abis_nm_sw { struct gsm_bts *bts; + int trx_nr; gsm_cbfn *cbfn; void *cb_data; int forced; @@ -1592,7 +1593,7 @@ static int abis_nm_rcvmsg_sw(struct msgb *mb) } /* Load the specified software into the BTS */ -int abis_nm_software_load(struct gsm_bts *bts, const char *fname, +int abis_nm_software_load(struct gsm_bts *bts, int trx_nr, const char *fname, u_int8_t win_size, int forced, gsm_cbfn *cbfn, void *cb_data) { @@ -1606,6 +1607,7 @@ int abis_nm_software_load(struct gsm_bts *bts, const char *fname, return -EBUSY; sw->bts = bts; + sw->trx_nr = trx_nr; switch (bts->type) { case GSM_BTS_TYPE_BS11: @@ -1616,8 +1618,8 @@ int abis_nm_software_load(struct gsm_bts *bts, const char *fname, break; case GSM_BTS_TYPE_NANOBTS: sw->obj_class = NM_OC_BASEB_TRANSC; - sw->obj_instance[0] = 0x00; - sw->obj_instance[1] = 0x00; + sw->obj_instance[0] = sw->bts->nr; + sw->obj_instance[1] = sw->trx_nr; sw->obj_instance[2] = 0xff; break; case GSM_BTS_TYPE_UNKNOWN: @@ -2551,7 +2553,7 @@ static int bs11_swload_cbfn(unsigned int hook, unsigned int event, fle = fl_dequeue(&bs11_sw->file_list); if (fle) { /* start download the next file of our file list */ - rc = abis_nm_software_load(bs11_sw->bts, fle->fname, + rc = abis_nm_software_load(bs11_sw->bts, 0xff, fle->fname, bs11_sw->win_size, bs11_sw->forced, &bs11_swload_cbfn, bs11_sw); @@ -2607,7 +2609,7 @@ int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname, return -EINVAL; /* start download the next file of our file list */ - rc = abis_nm_software_load(bts, fle->fname, win_size, forced, + rc = abis_nm_software_load(bts, 0xff, fle->fname, win_size, forced, bs11_swload_cbfn, bs11_sw); talloc_free(fle); return rc; diff --git a/openbsc/src/bs11_config.c b/openbsc/src/bs11_config.c index d8819d391..8f6de8a77 100644 --- a/openbsc/src/bs11_config.c +++ b/openbsc/src/bs11_config.c @@ -481,7 +481,7 @@ static int handle_state_resp(enum abis_bs11_phase state) * argument, so our swload_cbfn can distinguish * a safety load from a regular software */ if (file_is_readable(fname_safety)) - rc = abis_nm_software_load(g_bts, fname_safety, + rc = abis_nm_software_load(g_bts, 0xff, fname_safety, win_size, param_forced, swload_cbfn, g_bts); else diff --git a/openbsc/src/ipaccess/ipaccess-config.c b/openbsc/src/ipaccess/ipaccess-config.c index 556220a95..701a1db52 100644 --- a/openbsc/src/ipaccess/ipaccess-config.c +++ b/openbsc/src/ipaccess/ipaccess-config.c @@ -411,7 +411,7 @@ int nm_state_event(enum nm_evt evt, u_int8_t obj_class, void *obj, } else if (software) { int rc; printf("Attempting software upload with '%s'\n", software); - rc = abis_nm_software_load(trx->bts, software, 19, 0, swload_cbfn, trx->bts); + rc = abis_nm_software_load(trx->bts, trx->nr, software, 19, 0, swload_cbfn, trx->bts); if (rc < 0) { fprintf(stderr, "Failed to start software load\n"); exit(-3); -- cgit v1.2.3 From d6adf5e098f3283d8bf3349f382ee999cbf79233 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Thu, 13 May 2010 00:14:46 +0800 Subject: ipaccess: Make sure flashing of the secondary BTS is working Use the TRX throughout the flash process. --- openbsc/src/ipaccess/ipaccess-config.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/openbsc/src/ipaccess/ipaccess-config.c b/openbsc/src/ipaccess/ipaccess-config.c index 701a1db52..f27e51fdd 100644 --- a/openbsc/src/ipaccess/ipaccess-config.c +++ b/openbsc/src/ipaccess/ipaccess-config.c @@ -228,12 +228,12 @@ static int swload_cbfn(unsigned int hook, unsigned int event, struct msgb *_msg, void *data, void *param) { struct msgb *msg; - struct gsm_bts *bts; + struct gsm_bts_trx *trx; if (hook != GSM_HOOK_NM_SWLOAD) return 0; - bts = (struct gsm_bts *) data; + trx = (struct gsm_bts_trx *) data; switch (event) { case NM_MT_LOAD_INIT_ACK: @@ -272,7 +272,7 @@ static int swload_cbfn(unsigned int hook, unsigned int event, struct msgb *_msg, msg->l2h[1] = msgb_l3len(msg) >> 8; msg->l2h[2] = msgb_l3len(msg) & 0xff; printf("Foo l2h: %p l3h: %p... length l2: %u l3: %u\n", msg->l2h, msg->l3h, msgb_l2len(msg), msgb_l3len(msg)); - abis_nm_ipaccess_set_nvattr(bts->c0, msg->l2h, msgb_l2len(msg)); + abis_nm_ipaccess_set_nvattr(trx, msg->l2h, msgb_l2len(msg)); msgb_free(msg); break; case NM_MT_LOAD_END_NACK: @@ -286,7 +286,7 @@ static int swload_cbfn(unsigned int hook, unsigned int event, struct msgb *_msg, case NM_MT_ACTIVATE_SW_ACK: break; case NM_MT_LOAD_SEG_ACK: - percent = abis_nm_software_load_status(bts); + percent = abis_nm_software_load_status(trx->bts); if (percent > percent_old) printf("Software Download Progress: %d%%\n", percent); percent_old = percent; @@ -411,7 +411,7 @@ int nm_state_event(enum nm_evt evt, u_int8_t obj_class, void *obj, } else if (software) { int rc; printf("Attempting software upload with '%s'\n", software); - rc = abis_nm_software_load(trx->bts, trx->nr, software, 19, 0, swload_cbfn, trx->bts); + rc = abis_nm_software_load(trx->bts, trx->nr, software, 19, 0, swload_cbfn, trx); if (rc < 0) { fprintf(stderr, "Failed to start software load\n"); exit(-3); -- cgit v1.2.3 From 995a2d36da9d526de812461977933e3d2238030f Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 12 May 2010 16:50:52 +0000 Subject: use new install_element_ve() --- openbsc/src/gprs/gb_proxy_vty.c | 3 +-- openbsc/src/gprs/gprs_ns.c | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/openbsc/src/gprs/gb_proxy_vty.c b/openbsc/src/gprs/gb_proxy_vty.c index df2100210..e1cf97e87 100644 --- a/openbsc/src/gprs/gb_proxy_vty.c +++ b/openbsc/src/gprs/gb_proxy_vty.c @@ -152,8 +152,7 @@ DEFUN(cfg_nsip_sgsn_nsvci, int gbproxy_vty_init(void) { - install_element(VIEW_NODE, &show_gbproxy_cmd); - install_element(ENABLE_NODE, &show_gbproxy_cmd); + install_element_ve(&show_gbproxy_cmd); install_element(CONFIG_NODE, &cfg_gbproxy_cmd); install_node(&gbproxy_node, config_write_gbproxy); diff --git a/openbsc/src/gprs/gprs_ns.c b/openbsc/src/gprs/gprs_ns.c index 9f65489f7..e0ee962dd 100644 --- a/openbsc/src/gprs/gprs_ns.c +++ b/openbsc/src/gprs/gprs_ns.c @@ -1038,8 +1038,7 @@ int gprs_ns_vty_init(struct gprs_ns_inst *nsi) { vty_nsi = nsi; - install_element(VIEW_NODE, &show_ns_cmd); - install_element(ENABLE_NODE, &show_ns_cmd); + install_element_ve(&show_ns_cmd); install_element(CONFIG_NODE, &cfg_ns_cmd); install_node(&ns_node, config_write_ns); -- cgit v1.2.3 From ea4647d264d45e7090f3bc2f12f209b2db7cd90b Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 12 May 2010 17:19:53 +0000 Subject: NS: Make all timers configurable from VTY --- openbsc/include/openbsc/gprs_ns.h | 22 +++++++++++- openbsc/src/gprs/gprs_ns.c | 70 ++++++++++++++++++++++++++++++++------- openbsc/src/vty_interface.c | 13 ++------ 3 files changed, 82 insertions(+), 23 deletions(-) diff --git a/openbsc/include/openbsc/gprs_ns.h b/openbsc/include/openbsc/gprs_ns.h index 60051d13b..847e8f9cc 100644 --- a/openbsc/include/openbsc/gprs_ns.h +++ b/openbsc/include/openbsc/gprs_ns.h @@ -75,7 +75,6 @@ enum ns_cause { NS_CAUSE_UNKN_IP_TEST_FAILED = 0x14, }; - /* Our Implementation */ #include #include @@ -83,6 +82,25 @@ enum ns_cause { #include #include +#define NS_TIMERS_COUNT 7 +#define NS_TIMERS "(tns-block|tns-block-retries|tns-reset|tns-reset-retries|tns-test|tns-alive|tns-alive-retries)" +#define NS_TIMERS_HELP \ + "(un)blocking Timer (Tns-block) timeout\n" \ + "(un)blocking Timer (Tns-block) number of retries\n" \ + "Reset Timer (Tns-reset) timeout\n" \ + "Reset Timer (Tns-reset) number of retries\n" \ + "Test Timer (Tns-test) timeout\n" \ + +enum ns_timeout { + NS_TOUT_TNS_BLOCK, + NS_TOUT_TNS_BLOCK_RETRIES, + NS_TOUT_TNS_RESET, + NS_TOUT_TNS_RESET_RETRIES, + NS_TOUT_TNS_TEST, + NS_TOUT_TNS_ALIVE, + NS_TOUT_TNS_ALIVE_RETRIES, +}; + #define NSE_S_BLOCKED 0x0001 #define NSE_S_ALIVE 0x0002 @@ -107,6 +125,8 @@ struct gprs_ns_inst { /* linked lists of all NSVC in this instance */ struct llist_head gprs_nsvcs; + uint16_t timeout[NS_TIMERS_COUNT]; + /* which link-layer are we based on? */ enum gprs_ns_ll ll; diff --git a/openbsc/src/gprs/gprs_ns.c b/openbsc/src/gprs/gprs_ns.c index e0ee962dd..1b9d7c6d5 100644 --- a/openbsc/src/gprs/gprs_ns.c +++ b/openbsc/src/gprs/gprs_ns.c @@ -63,6 +63,19 @@ #define NS_ALLOC_SIZE 1024 +/* FIXME: this should go to some common file as it is copied + * in vty_interface.c of the BSC */ +static const struct value_string gprs_ns_timer_strs[] = { + { 0, "tns-block" }, + { 1, "tns-block-retries" }, + { 2, "tns-reset" }, + { 3, "tns-reset-retries" }, + { 4, "tns-test" }, + { 5, "tns-alive" }, + { 6, "tns-alive-retries" }, + { 0, NULL } +}; + static const struct tlv_definition ns_att_tlvdef = { .def = { [NS_IE_CAUSE] = { TLV_TYPE_TvLV, 0 }, @@ -323,12 +336,10 @@ int gprs_ns_tx_alive_ack(struct gprs_nsvc *nsvc) return gprs_ns_tx_simple(nsvc, NS_PDUT_ALIVE_ACK); } -#define NS_ALIVE_RETRIES 10 /* after 3 failed retransmit we declare BTS as dead */ - -static const uint8_t timer_mode_tout[_NSVC_TIMER_NR] = { - [NSVC_TIMER_TNS_RESET] = 60, - [NSVC_TIMER_TNS_ALIVE] = 3, - [NSVC_TIMER_TNS_TEST] = 30, +static const enum ns_timeout timer_mode_tout[_NSVC_TIMER_NR] = { + [NSVC_TIMER_TNS_RESET] = NS_TOUT_TNS_RESET, + [NSVC_TIMER_TNS_ALIVE] = NS_TOUT_TNS_ALIVE, + [NSVC_TIMER_TNS_TEST] = NS_TOUT_TNS_TEST, }; static const struct value_string timer_mode_strs[] = { @@ -340,36 +351,42 @@ static const struct value_string timer_mode_strs[] = { static void nsvc_start_timer(struct gprs_nsvc *nsvc, enum nsvc_timer_mode mode) { + enum ns_timeout tout = timer_mode_tout[mode]; + unsigned int seconds = nsvc->nsi->timeout[tout]; + DEBUGP(DNS, "NSEI=%u Starting timer in mode %s (%u seconds)\n", nsvc->nsei, get_value_string(timer_mode_strs, mode), - timer_mode_tout[mode]); + seconds); if (bsc_timer_pending(&nsvc->timer)) bsc_del_timer(&nsvc->timer); nsvc->timer_mode = mode; - bsc_schedule_timer(&nsvc->timer, timer_mode_tout[mode], 0); + bsc_schedule_timer(&nsvc->timer, seconds, 0); } static void gprs_ns_timer_cb(void *data) { struct gprs_nsvc *nsvc = data; + enum ns_timeout tout = timer_mode_tout[nsvc->timer_mode]; + unsigned int seconds = nsvc->nsi->timeout[tout]; DEBUGP(DNS, "NSEI=%u Timer expired in mode %s (%u seconds)\n", nsvc->nsei, get_value_string(timer_mode_strs, nsvc->timer_mode), - timer_mode_tout[nsvc->timer_mode]); + seconds); switch (nsvc->timer_mode) { case NSVC_TIMER_TNS_ALIVE: /* Tns-alive case: we expired without response ! */ nsvc->alive_retries++; - if (nsvc->alive_retries > NS_ALIVE_RETRIES) { + if (nsvc->alive_retries > + nsvc->nsi->timeout[NS_TOUT_TNS_ALIVE_RETRIES]) { /* mark as dead and blocked */ nsvc->state = NSE_S_BLOCKED; LOGP(DNS, LOGL_NOTICE, "NSEI=%u Tns-alive expired more then " "%u times, blocking NS-VC\n", nsvc->nsei, - NS_ALIVE_RETRIES); + nsvc->nsi->timeout[NS_TOUT_TNS_ALIVE_RETRIES]); ns_dispatch_signal(nsvc, S_NS_ALIVE_EXP, 0); ns_dispatch_signal(nsvc, S_NS_BLOCK, NS_CAUSE_NSVC_BLOCKED); return; @@ -710,6 +727,13 @@ struct gprs_ns_inst *gprs_ns_instantiate(gprs_ns_cb_t *cb) nsi->cb = cb; INIT_LLIST_HEAD(&nsi->gprs_nsvcs); + nsi->timeout[NS_TOUT_TNS_BLOCK] = 3; + nsi->timeout[NS_TOUT_TNS_BLOCK_RETRIES] = 3; + nsi->timeout[NS_TOUT_TNS_RESET] = 3; + nsi->timeout[NS_TOUT_TNS_RESET_RETRIES] = 3; + nsi->timeout[NS_TOUT_TNS_TEST] = 30; + nsi->timeout[NS_TOUT_TNS_ALIVE] = 3; + nsi->timeout[NS_TOUT_TNS_ALIVE_RETRIES] = 10; return nsi; } @@ -866,6 +890,7 @@ static struct cmd_node ns_node = { static int config_write_ns(struct vty *vty) { struct gprs_nsvc *nsvc; + unsigned int i; vty_out(vty, "ns%s", VTY_NEWLINE); @@ -886,9 +911,13 @@ static int config_write_ns(struct vty *vty) nsvc->nsei, ntohs(nsvc->ip.bts_addr.sin_port), VTY_NEWLINE); } - vty_out(vty, "%s", VTY_NEWLINE); } + for (i = 0; i < ARRAY_SIZE(vty_nsi->timeout); i++) + vty_out(vty, " timer %s %u%s", + get_value_string(gprs_ns_timer_strs, i), + vty_nsi->timeout[i], VTY_NEWLINE); + return CMD_SUCCESS; } @@ -1034,6 +1063,22 @@ DEFUN(cfg_no_nse, cfg_no_nse_cmd, return CMD_SUCCESS; } +DEFUN(cfg_ns_timer, cfg_ns_timer_cmd, + "timer " NS_TIMERS " <0-65535>", + "Network Service Timer\n" + NS_TIMERS_HELP "Timer Value\n") +{ + int idx = get_string_value(gprs_ns_timer_strs, argv[0]); + int val = atoi(argv[1]); + + if (idx < 0 || idx >= ARRAY_SIZE(vty_nsi->timeout)) + return CMD_WARNING; + + vty_nsi->timeout[idx] = val; + + return CMD_SUCCESS; +} + int gprs_ns_vty_init(struct gprs_ns_inst *nsi) { vty_nsi = nsi; @@ -1048,6 +1093,7 @@ int gprs_ns_vty_init(struct gprs_ns_inst *nsi) install_element(NS_NODE, &cfg_nse_remoteport_cmd); install_element(NS_NODE, &cfg_nse_remoterole_cmd); install_element(NS_NODE, &cfg_no_nse_cmd); + install_element(NS_NODE, &cfg_ns_timer_cmd); return 0; } diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c index acfdd94de..70d2997b2 100644 --- a/openbsc/src/vty_interface.c +++ b/openbsc/src/vty_interface.c @@ -42,7 +42,8 @@ static struct gsm_network *gsmnet; -static struct value_string gprs_ns_timer_strs[] = { +/* FIXME: this should go to some common file */ +static const struct value_string gprs_ns_timer_strs[] = { { 0, "tns-block" }, { 1, "tns-block-retries" }, { 2, "tns-reset" }, @@ -53,7 +54,7 @@ static struct value_string gprs_ns_timer_strs[] = { { 0, NULL } }; -static struct value_string gprs_bssgp_cfg_strs[] = { +static const struct value_string gprs_bssgp_cfg_strs[] = { { 0, "blocking-timer" }, { 1, "blocking-retries" }, { 2, "unblocking-retries" }, @@ -1626,14 +1627,6 @@ DEFUN(cfg_bts_gprs_nsvc_rip, cfg_bts_gprs_nsvc_rip_cmd, return CMD_SUCCESS; } -#define NS_TIMERS "(tns-block|tns-block-retries|tns-reset|tns-reset-retries|tns-test|tns-alive|tns-alive-retries)" -#define NS_TIMERS_HELP \ - "(un)blocking Timer (Tns-block) timeout\n" \ - "(un)blocking Timer (Tns-block) number of retries\n" \ - "Reset Timer (Tns-reset) timeout\n" \ - "Reset Timer (Tns-reset) number of retries\n" \ - "Test Timer (Tns-test) timeout\n" \ - DEFUN(cfg_bts_gprs_ns_timer, cfg_bts_gprs_ns_timer_cmd, "gprs ns timer " NS_TIMERS " <0-255>", GPRS_TEXT "Network Service\n" -- cgit v1.2.3 From 39d0bb5f7c914e566df3aead704d2075bba8aa57 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 12 May 2010 18:10:25 +0000 Subject: Gb Proxy: Proper msgb memory management The old idea was to take a msgb from gbprox_rcvmsg() and then modify it and finally send it all the way down to nsip_sendmsg() to the remote peer. However, this introduces memory management difficulties, as we then have to distinguish three cases: * msgb was sent to a remote peer * we sent some error message and need to free the msgb * we need to make n-1 copies in case of a BSSVC-RESET from the SGSN So instead we now simply always copy the message if we pass it on. All messages received by gbprox_rcvmsg() are msgb_free()d in the very same routine All messages allocated by tx2peer() or tx2sgsn() are freed after nsip_sendmsg() --- openbsc/src/gprs/gb_proxy.c | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/openbsc/src/gprs/gb_proxy.c b/openbsc/src/gprs/gb_proxy.c index d9639a445..7203a4bc2 100644 --- a/openbsc/src/gprs/gb_proxy.c +++ b/openbsc/src/gprs/gb_proxy.c @@ -119,6 +119,23 @@ static void peer_free(struct gbprox_peer *peer) talloc_free(peer); } +/* FIXME: this needs to go to libosmocore/msgb.c */ +static struct msgb *msgb_copy(const struct msgb *msg, const char *name) +{ + struct msgb *new_msg; + + new_msg = msgb_alloc(msg->data_len, name); + if (!new_msg) + return NULL; + + /* copy header */ + memcpy(new_msg, msg, sizeof(*new_msg)); + /* copy data */ + memcpy(new_msg->data, msg->data, new_msg->data_len); + + return new_msg; +} + /* strip off the NS header */ static void strip_ns_hdr(struct msgb *msg) { @@ -127,8 +144,12 @@ static void strip_ns_hdr(struct msgb *msg) } /* feed a message down the NS-VC associated with the specified peer */ -static int gbprox_relay2sgsn(struct msgb *msg, uint16_t ns_bvci) +static int gbprox_relay2sgsn(struct msgb *old_msg, uint16_t ns_bvci) { + /* create a copy of the message so the old one can + * be free()d safely when we return from gbprox_rcvmsg() */ + struct msgb *msg = msgb_copy(old_msg, "msgb_relay2sgsn"); + DEBUGP(DGPRS, "NSEI=%u proxying BTS->SGSN (NS_BVCI=%u, NSEI=%u)\n", msgb_nsei(msg), ns_bvci, gbcfg.nsip_sgsn_nsei); @@ -141,9 +162,13 @@ static int gbprox_relay2sgsn(struct msgb *msg, uint16_t ns_bvci) } /* feed a message down the NS-VC associated with the specified peer */ -static int gbprox_relay2peer(struct msgb *msg, struct gbprox_peer *peer, +static int gbprox_relay2peer(struct msgb *old_msg, struct gbprox_peer *peer, uint16_t ns_bvci) { + /* create a copy of the message so the old one can + * be free()d safely when we return from gbprox_rcvmsg() */ + struct msgb *msg = msgb_copy(old_msg, "msgb_relay2peer"); + DEBUGP(DGPRS, "NSEI=%u proxying to SGSN->BSS (NS_BVCI=%u, NSEI=%u)\n", msgb_nsei(msg), ns_bvci, peer->nsvc->nsei); @@ -466,6 +491,10 @@ int gbprox_rcvmsg(struct msgb *msg, struct gprs_nsvc *nsvc, uint16_t ns_bvci) } } + /* We free the original message here, as we will have created a + * copy in case it is forwarded to another peer */ + msgb_free(msg); + return rc; } -- cgit v1.2.3 From 22229d684124d6d9c4eb83e9776a620af1c552b0 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 12 May 2010 20:28:04 +0200 Subject: Fix missing #include preventing compilation of vty_interface.c --- openbsc/src/vty_interface.c | 1 + 1 file changed, 1 insertion(+) diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c index 70d2997b2..866131613 100644 --- a/openbsc/src/vty_interface.c +++ b/openbsc/src/vty_interface.c @@ -39,6 +39,7 @@ #include #include #include +#include static struct gsm_network *gsmnet; -- cgit v1.2.3 From 8272c7723167ccfe20483841ae3203cc0cb83682 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 12 May 2010 18:38:45 +0000 Subject: GPRS: We have to do the msgb_free() in NS not Gb Proxy As only NS-UNITDATA messages are ever passed into the Gb Proxy, we need to do the msgb_free() at a much higher point in the calling stack, i.e. inside the NS protocol layer. This means it is now the same logic as in OpenBSC itself. --- openbsc/src/gprs/gb_proxy.c | 4 ---- openbsc/src/gprs/gprs_ns.c | 6 +++++- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/openbsc/src/gprs/gb_proxy.c b/openbsc/src/gprs/gb_proxy.c index 7203a4bc2..ffaf24060 100644 --- a/openbsc/src/gprs/gb_proxy.c +++ b/openbsc/src/gprs/gb_proxy.c @@ -491,10 +491,6 @@ int gbprox_rcvmsg(struct msgb *msg, struct gprs_nsvc *nsvc, uint16_t ns_bvci) } } - /* We free the original message here, as we will have created a - * copy in case it is forwarded to another peer */ - msgb_free(msg); - return rc; } diff --git a/openbsc/src/gprs/gprs_ns.c b/openbsc/src/gprs/gprs_ns.c index 1b9d7c6d5..11637f7fa 100644 --- a/openbsc/src/gprs/gprs_ns.c +++ b/openbsc/src/gprs/gprs_ns.c @@ -793,7 +793,11 @@ static int handle_nsip_read(struct bsc_fd *bfd) if (!msg) return error; - return gprs_ns_rcvmsg(nsi, msg, &saddr); + error = gprs_ns_rcvmsg(nsi, msg, &saddr); + + msgb_free(msg); + + return error; } static int handle_nsip_write(struct bsc_fd *bfd) -- cgit v1.2.3 From 6df0c5187bc8b6119ec373c0ccd202324d767d0d Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 12 May 2010 18:40:01 +0000 Subject: GPRS: Gb proxy memory leak debugging with SIGUSR --- openbsc/src/gprs/gb_proxy_main.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/openbsc/src/gprs/gb_proxy_main.c b/openbsc/src/gprs/gb_proxy_main.c index 510abd09d..d1024f101 100644 --- a/openbsc/src/gprs/gb_proxy_main.c +++ b/openbsc/src/gprs/gb_proxy_main.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -89,6 +90,32 @@ static int proxy_ns_cb(enum gprs_ns_evt event, struct gprs_nsvc *nsvc, return rc; } +static void signal_handler(int signal) +{ + fprintf(stdout, "signal %u received\n", signal); + + switch (signal) { + case SIGINT: + dispatch_signal(SS_GLOBAL, S_GLOBAL_SHUTDOWN, NULL); + sleep(1); + exit(0); + break; + case SIGABRT: + /* in case of abort, we want to obtain a talloc report + * and then return to the caller, who will abort the process */ + case SIGUSR1: + talloc_report(tall_vty_ctx, stderr); + talloc_report_full(tall_bsc_ctx, stderr); + break; + case SIGUSR2: + talloc_report_full(tall_vty_ctx, stderr); + break; + default: + break; + } +} + +extern void *tall_msgb_ctx; int main(int argc, char **argv) { @@ -98,6 +125,13 @@ int main(int argc, char **argv) int rc; tall_bsc_ctx = talloc_named_const(NULL, 0, "nsip_proxy"); + tall_msgb_ctx = talloc_named_const(tall_bsc_ctx, 0, "msgb"); + + signal(SIGINT, &signal_handler); + signal(SIGABRT, &signal_handler); + signal(SIGUSR1, &signal_handler); + signal(SIGUSR2, &signal_handler); + signal(SIGPIPE, SIG_IGN); log_init(&log_info); stderr_target = log_target_create_stderr(); -- cgit v1.2.3 From 0ab535bfc391a6f53b13a565bfe9464e77045165 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 13 May 2010 10:34:56 +0200 Subject: [GPRS] Gb Proxy: Cosmetic fix of log message --- openbsc/src/gprs/gb_proxy.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openbsc/src/gprs/gb_proxy.c b/openbsc/src/gprs/gb_proxy.c index ffaf24060..9580ea3a3 100644 --- a/openbsc/src/gprs/gb_proxy.c +++ b/openbsc/src/gprs/gb_proxy.c @@ -169,12 +169,13 @@ static int gbprox_relay2peer(struct msgb *old_msg, struct gbprox_peer *peer, * be free()d safely when we return from gbprox_rcvmsg() */ struct msgb *msg = msgb_copy(old_msg, "msgb_relay2peer"); - DEBUGP(DGPRS, "NSEI=%u proxying to SGSN->BSS (NS_BVCI=%u, NSEI=%u)\n", + DEBUGP(DGPRS, "NSEI=%u proxying SGSN->BSS (NS_BVCI=%u, NSEI=%u)\n", msgb_nsei(msg), ns_bvci, peer->nsvc->nsei); msgb_bvci(msg) = ns_bvci; msgb_nsei(msg) = peer->nsvc->nsei; + /* Strip the old NS header, it will be replaced with a new one */ strip_ns_hdr(msg); return gprs_ns_sendmsg(bssgp_nsi, msg); -- cgit v1.2.3 From 7b45d608872f17ab8b71d53a2d87e5f8d621b007 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 13 May 2010 11:35:30 +0200 Subject: Add new 'rate counter' implementation to libosmocore A 'rate counter' is a counter that counts events but also keeps track of the rate of events (per second, minute, hour and day). 'rate counters' are generally abstracted in 'rate counter groups', which are instances of a 'rate counter group description'. This way we can have e.g. a description describing what kind of counters a BTS (or TRX) has - and we can then create one instance of that group for every BTS or TRX that exists. --- include/osmocore/Makefile.am | 2 +- include/osmocore/rate_ctr.h | 81 ++++++++++++++++++++++++++++ src/Makefile.am | 2 +- src/rate_ctr.c | 124 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 207 insertions(+), 2 deletions(-) create mode 100644 include/osmocore/rate_ctr.h create mode 100644 src/rate_ctr.c diff --git a/include/osmocore/Makefile.am b/include/osmocore/Makefile.am index 56f926bcf..fde010271 100644 --- a/include/osmocore/Makefile.am +++ b/include/osmocore/Makefile.am @@ -1,7 +1,7 @@ osmocore_HEADERS = signal.h linuxlist.h timer.h select.h msgb.h \ tlv.h bitvec.h comp128.h statistics.h gsm_utils.h utils.h \ gsmtap.h write_queue.h rsl.h gsm48.h rxlev_stat.h mncc.h \ - gsm48_ie.h logging.h gsm0808.h + gsm48_ie.h logging.h gsm0808.h rate_ctr.h if ENABLE_TALLOC osmocore_HEADERS += talloc.h diff --git a/include/osmocore/rate_ctr.h b/include/osmocore/rate_ctr.h new file mode 100644 index 000000000..c6a1ace2f --- /dev/null +++ b/include/osmocore/rate_ctr.h @@ -0,0 +1,81 @@ +#ifndef _RATE_CTR_H +#define _RATE_CTR_H + +#include + +#include + +#define RATE_CTR_INTV_NUM 4 + +enum rate_ctr_intv { + RATE_CTR_INTV_SEC, + RATE_CTR_INTV_MIN, + RATE_CTR_INTV_HOUR, + RATE_CTR_INTV_DAY, +}; + +/* for each of the intervals, we keep the following values */ +struct rate_ctr_per_intv { + uint64_t last; + uint64_t rate; +}; + +/* for each actual value, we keep the following data */ +struct rate_ctr { + uint64_t current; + struct rate_ctr_per_intv intv[RATE_CTR_INTV_NUM]; +}; + +struct rate_ctr_desc { + const char *name; + const char *description; +}; + +/* Describe a counter group class */ +struct rate_ctr_group_desc { + /* The prefix / format string to be used for all counters */ + char *group_prefix_fmt; + /* The human-readable description of the group */ + char *group_description; + /* The number of counters in this group */ + unsigned int num_ctr; + /* Pointer to array of counter names */ + struct rate_ctr_desc *ctr_desc; +}; + +/* One instance of a counter group class */ +struct rate_ctr_group { + /* Linked list of all counter groups in the system */ + struct llist_head list; + /* Pointer to the counter group class */ + const struct rate_ctr_group_desc *desc; + /* The name prefix generated from desc->group_prefix_fmt and index */ + char *name_prefix; + /* Actual counter structures below */ + struct rate_ctr ctr[0]; +}; + +/* Allocate a new group of counters according to description */ +struct rate_ctr_group *rate_ctr_group_alloc(void *ctx, + const struct rate_ctr_group_desc *desc, + unsigned int idx); + +/* Free the memory for the specified group of counters */ +void rate_ctr_group_free(struct rate_ctr_group *grp); + +/* Add a number to the counter */ +void rate_ctr_add(struct rate_ctr *ctr, int inc); + +/* Increment the counter by 1 */ +static inline void rate_ctr_inc(struct rate_ctr *ctr) +{ + rate_ctr_add(ctr, 1); +} + +/* Initialize the counter module */ +int rate_ctr_init(void *tall_ctx); + +struct vty; +void vty_out_rate_ctr_group(struct vty *vty, const char *prefix, + struct rate_ctr_group *ctrg); +#endif /* RATE_CTR_H */ diff --git a/src/Makefile.am b/src/Makefile.am index 20e99db30..ce063d058 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -10,7 +10,7 @@ lib_LTLIBRARIES = libosmocore.la libosmocore_la_SOURCES = timer.c select.c signal.c msgb.c rxlev_stat.c \ tlv_parser.c bitvec.c comp128.c gsm_utils.c statistics.c \ write_queue.c utils.c rsl.c gsm48.c gsm48_ie.c \ - logging.c gsm0808.c + logging.c gsm0808.c rate_ctr.c if ENABLE_TALLOC libosmocore_la_SOURCES += talloc.c diff --git a/src/rate_ctr.c b/src/rate_ctr.c new file mode 100644 index 000000000..9b2459e89 --- /dev/null +++ b/src/rate_ctr.c @@ -0,0 +1,124 @@ +/* utility routines for keeping conters about events and the event rates */ + +/* (C) 2009-2010 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 +#include + +static LLIST_HEAD(rate_ctr_groups); + +static void *tall_rate_ctr_ctx; + +struct rate_ctr_group *rate_ctr_group_alloc(void *ctx, + const struct rate_ctr_group_desc *desc, + unsigned int idx) +{ + unsigned int size; + struct rate_ctr_group *group; + + size = sizeof(struct rate_ctr_group) + + desc->num_ctr * sizeof(struct rate_ctr); + + if (!ctx) + ctx = tall_rate_ctr_ctx; + + group = talloc_zero_size(ctx, size); + if (!group) + return NULL; + + group->desc = desc; + /* Generate the Group prefix from the user-specified index */ + group->name_prefix = talloc_size(group, strlen(desc->group_prefix_fmt) + 20); + sprintf(group->name_prefix, desc->group_prefix_fmt, idx); + + llist_add(&group->list, &rate_ctr_groups); + + return group; +} + +void rate_ctr_group_free(struct rate_ctr_group *grp) +{ + llist_del(&grp->list); + talloc_free(grp); +} + +void rate_ctr_add(struct rate_ctr *ctr, int inc) +{ + ctr->current += inc; +} + +static void interval_expired(struct rate_ctr *ctr, enum rate_ctr_intv intv) +{ + /* calculate rate over last interval */ + ctr->intv[intv].rate = ctr->current - ctr->intv[intv].last; + /* save current counter for next interval */ + ctr->intv[intv].last = ctr->current; +} + +static struct timer_list rate_ctr_timer; +static uint64_t timer_ticks; + +/* The one-second interval has expired */ +static void rate_ctr_group_intv(struct rate_ctr_group *grp) +{ + unsigned int i; + + for (i = 0; i < grp->desc->num_ctr; i++) { + struct rate_ctr *ctr = &grp->ctr[i]; + + interval_expired(ctr, RATE_CTR_INTV_SEC); + if ((timer_ticks % 60) == 0) + interval_expired(ctr, RATE_CTR_INTV_MIN); + if ((timer_ticks % (60*60)) == 0) + interval_expired(ctr, RATE_CTR_INTV_HOUR); + if ((timer_ticks % (24*60*60)) == 0) + interval_expired(ctr, RATE_CTR_INTV_DAY); + } +} + +static void rate_ctr_timer_cb(void *data) +{ + struct rate_ctr_group *ctrg; + + /* Increment number of ticks before we calculate intervals, + * as a counter value of 0 would already wrap all counters */ + timer_ticks++; + + llist_for_each_entry(ctrg, &rate_ctr_groups, list) + rate_ctr_group_intv(ctrg); + + bsc_schedule_timer(&rate_ctr_timer, 1, 0); +} + +int rate_ctr_init(void *tall_ctx) +{ + tall_rate_ctr_ctx = tall_ctx; + rate_ctr_timer.cb = rate_ctr_timer_cb; + bsc_schedule_timer(&rate_ctr_timer, 1, 0); + + return 0; +} -- cgit v1.2.3 From f2b4cd7b866286b905271283f3646a325417760a Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 13 May 2010 11:45:07 +0200 Subject: [GPRS] NS: Start to use rate_ctr_group code from libosmocore Every NS-VC now has a set of counters for incoming and outgoing number of packets and bytes. We also split the VTY part of the gprs_ns.c implementation into gprs_ns_vty.c to make sure the protocol can actually be used without the VTY code being present. --- openbsc/include/openbsc/db.h | 3 + openbsc/include/openbsc/gprs_ns.h | 6 + openbsc/src/Makefile.am | 2 +- openbsc/src/db.c | 56 +++++++- openbsc/src/gprs/Makefile.am | 4 +- openbsc/src/gprs/gb_proxy_main.c | 2 + openbsc/src/gprs/gprs_ns.c | 282 ++++++-------------------------------- openbsc/src/gprs/gprs_ns_vty.c | 275 +++++++++++++++++++++++++++++++++++++ 8 files changed, 377 insertions(+), 253 deletions(-) create mode 100644 openbsc/src/gprs/gprs_ns_vty.c diff --git a/openbsc/include/openbsc/db.h b/openbsc/include/openbsc/db.h index d0a1278ef..1782efb50 100644 --- a/openbsc/include/openbsc/db.h +++ b/openbsc/include/openbsc/db.h @@ -66,6 +66,9 @@ int db_apdu_blob_store(struct gsm_subscriber *subscr, u_int8_t *apdu); /* Statistics counter storage */ +struct counter; int db_store_counter(struct counter *ctr); +struct rate_ctr_group; +int db_store_rate_ctr_group(struct rate_ctr_group *ctrg); #endif /* _DB_H */ diff --git a/openbsc/include/openbsc/gprs_ns.h b/openbsc/include/openbsc/gprs_ns.h index 847e8f9cc..34b1b62d2 100644 --- a/openbsc/include/openbsc/gprs_ns.h +++ b/openbsc/include/openbsc/gprs_ns.h @@ -163,6 +163,8 @@ struct gprs_nsvc { unsigned int remote_end_is_sgsn:1; unsigned int persistent:1; + struct rate_ctr_group *ctrg; + union { struct { struct sockaddr_in bts_addr; @@ -200,6 +202,10 @@ struct gprs_nsvc *nsip_connect(struct gprs_ns_inst *nsi, struct sockaddr_in *dest, uint16_t nsei, uint16_t nsvci); +struct gprs_nsvc *nsvc_create(struct gprs_ns_inst *nsi, uint16_t nsvci); +void nsvc_delete(struct gprs_nsvc *nsvc); +struct gprs_nsvc *nsvc_by_nsei(struct gprs_ns_inst *nsi, uint16_t nsei); + /* Add NS-specific VTY stuff */ int gprs_ns_vty_init(struct gprs_ns_inst *nsi); diff --git a/openbsc/src/Makefile.am b/openbsc/src/Makefile.am index 9dc02575c..177c410ad 100644 --- a/openbsc/src/Makefile.am +++ b/openbsc/src/Makefile.am @@ -27,7 +27,7 @@ libmsc_a_SOURCES = gsm_subscriber.c db.c \ handover_logic.c handover_decision.c meas_rep.c libvty_a_SOURCES = vty/buffer.c vty/command.c vty/vector.c vty/vty.c \ - telnet_interface.c vty_interface_cmds.c + telnet_interface.c vty_interface_cmds.c vty/utils.c libsccp_a_SOURCES = sccp/sccp.c diff --git a/openbsc/src/db.c b/openbsc/src/db.c index 8bf47ab38..f7fb3b457 100644 --- a/openbsc/src/db.c +++ b/openbsc/src/db.c @@ -20,13 +20,8 @@ * */ -#include -#include -#include -#include -#include -#include - +#include +#include #include #include #include @@ -34,6 +29,14 @@ #include #include +#include +#include +#include +#include +#include +#include +#include + static char *db_basename = NULL; static char *db_dirname = NULL; static dbi_conn conn; @@ -1180,3 +1183,42 @@ int db_store_counter(struct counter *ctr) dbi_result_free(result); return 0; } + +static int db_store_rate_ctr(struct rate_ctr_group *ctrg, unsigned int num, + char *q_prefix) +{ + dbi_result result; + char *q_name; + + dbi_conn_quote_string_copy(conn, ctrg->desc->ctr_desc[num].name, + &q_name); + + result = dbi_conn_queryf(conn, + "Insert INTO Counters " + "(timestamp,name,value) VALUES " + "(datetime('now'),%s.%s,%"PRIu64")", + q_prefix, q_name, ctrg->ctr[num].current); + + free(q_name); + + if (!result) + return -EIO; + + dbi_result_free(result); + return 0; +} + +int db_store_rate_ctr_group(struct rate_ctr_group *ctrg) +{ + unsigned int i; + char *q_prefix; + + dbi_conn_quote_string_copy(conn, ctrg->name_prefix, &q_prefix); + + for (i = 0; i < ctrg->desc->num_ctr; i++) + db_store_rate_ctr(ctrg, i, q_prefix); + + free(q_prefix); + + return 0; +} diff --git a/openbsc/src/gprs/Makefile.am b/openbsc/src/gprs/Makefile.am index 7cb7ba66a..88c358a1b 100644 --- a/openbsc/src/gprs/Makefile.am +++ b/openbsc/src/gprs/Makefile.am @@ -9,10 +9,10 @@ libsgsn_a_SOURCES = gprs_ns.c gprs_bssgp.c gprs_llc.c gsm_04_08_gprs.c \ crc24.c gprs_sgsn.c gprs_bssgp_util.c osmo_gbproxy_SOURCES = gb_proxy.c gb_proxy_main.c gb_proxy_vty.c \ - gprs_ns.c gprs_bssgp_util.c \ + gprs_ns.c gprs_ns_vty.c gprs_bssgp_util.c \ $(top_srcdir)/src/socket.c $(top_srcdir)/src/debug.c osmo_gbproxy_LDADD = $(top_builddir)/src/libvty.a -osmo_sgsn_SOURCES = sgsn_main.c sgsn_vty.c \ +osmo_sgsn_SOURCES = sgsn_main.c sgsn_vty.c gprs_ns_vty.c \ $(top_srcdir)/src/socket.c $(top_srcdir)/src/debug.c osmo_sgsn_LDADD = $(top_builddir)/src/libvty.a libsgsn.a diff --git a/openbsc/src/gprs/gb_proxy_main.c b/openbsc/src/gprs/gb_proxy_main.c index d1024f101..fc8f1648d 100644 --- a/openbsc/src/gprs/gb_proxy_main.c +++ b/openbsc/src/gprs/gb_proxy_main.c @@ -36,6 +36,7 @@ #include #include +#include #include #include @@ -138,6 +139,7 @@ int main(int argc, char **argv) log_add_target(stderr_target); log_set_all_filter(stderr_target, 1); + rate_ctr_init(tall_bsc_ctx); telnet_init(&dummy_network, 4246); bssgp_nsi = gprs_ns_instantiate(&proxy_ns_cb); diff --git a/openbsc/src/gprs/gprs_ns.c b/openbsc/src/gprs/gprs_ns.c index 11637f7fa..e83aee8e6 100644 --- a/openbsc/src/gprs/gprs_ns.c +++ b/openbsc/src/gprs/gprs_ns.c @@ -56,6 +56,7 @@ #include #include #include +#include #include #include #include @@ -63,19 +64,6 @@ #define NS_ALLOC_SIZE 1024 -/* FIXME: this should go to some common file as it is copied - * in vty_interface.c of the BSC */ -static const struct value_string gprs_ns_timer_strs[] = { - { 0, "tns-block" }, - { 1, "tns-block-retries" }, - { 2, "tns-reset" }, - { 3, "tns-reset-retries" }, - { 4, "tns-test" }, - { 5, "tns-alive" }, - { 6, "tns-alive-retries" }, - { 0, NULL } -}; - static const struct tlv_definition ns_att_tlvdef = { .def = { [NS_IE_CAUSE] = { TLV_TYPE_TvLV, 0 }, @@ -86,6 +74,20 @@ static const struct tlv_definition ns_att_tlvdef = { }, }; +static const struct rate_ctr_desc nsvc_ctr_description[] = { + { "packets.in", "Packets at NS Level ( In)" }, + { "packets.out", "Packets at NS Level (Out)" }, + { "bytes.in", "Bytes at NS Level ( In)" }, + { "bytes.out", "Bytes at NS Level (Out)" }, +}; + +static const struct rate_ctr_group_desc nsvc_ctrg_desc = { + .group_prefix_fmt = "ns.nsvc%u", + .group_description = "NSVC Peer Statistics", + .num_ctr = ARRAY_SIZE(nsvc_ctr_description), + .ctr_desc = nsvc_ctr_description, +}; + /* Lookup struct gprs_nsvc based on NSVCI */ static struct gprs_nsvc *nsvc_by_nsvci(struct gprs_ns_inst *nsi, uint16_t nsvci) @@ -99,8 +101,7 @@ static struct gprs_nsvc *nsvc_by_nsvci(struct gprs_ns_inst *nsi, } /* Lookup struct gprs_nsvc based on NSVCI */ -static struct gprs_nsvc *nsvc_by_nsei(struct gprs_ns_inst *nsi, - uint16_t nsei) +struct gprs_nsvc *nsvc_by_nsei(struct gprs_ns_inst *nsi, uint16_t nsei) { struct gprs_nsvc *nsvc; llist_for_each_entry(nsvc, &nsi->gprs_nsvcs, list) { @@ -110,7 +111,6 @@ static struct gprs_nsvc *nsvc_by_nsei(struct gprs_ns_inst *nsi, return NULL; } - /* Lookup struct gprs_nsvc based on remote peer socket addr */ static struct gprs_nsvc *nsvc_by_rem_addr(struct gprs_ns_inst *nsi, struct sockaddr_in *sin) @@ -127,7 +127,7 @@ static struct gprs_nsvc *nsvc_by_rem_addr(struct gprs_ns_inst *nsi, static void gprs_ns_timer_cb(void *data); -static struct gprs_nsvc *nsvc_create(struct gprs_ns_inst *nsi, uint16_t nsvci) +struct gprs_nsvc *nsvc_create(struct gprs_ns_inst *nsi, uint16_t nsvci) { struct gprs_nsvc *nsvc; @@ -138,13 +138,14 @@ static struct gprs_nsvc *nsvc_create(struct gprs_ns_inst *nsi, uint16_t nsvci) nsvc->nsi = nsi; nsvc->timer.cb = gprs_ns_timer_cb; nsvc->timer.data = nsvc; + nsvc->ctrg = rate_ctr_group_alloc(nsvc, &nsvc_ctrg_desc, nsvci); llist_add(&nsvc->list, &nsi->gprs_nsvcs); return nsvc; } -static void nsvc_delete(struct gprs_nsvc *nsvc) +void nsvc_delete(struct gprs_nsvc *nsvc) { if (bsc_timer_pending(&nsvc->timer)) bsc_del_timer(&nsvc->timer); @@ -190,6 +191,10 @@ static int gprs_ns_tx(struct gprs_nsvc *nsvc, struct msgb *msg) { int ret; + /* Increment number of Uplink bytes */ + rate_ctr_inc(&nsvc->ctrg->ctr[1]); + rate_ctr_add(&nsvc->ctrg->ctr[3], msgb_l2len(msg)); + switch (nsvc->nsi->ll) { case GPRS_NS_LL_UDP: ret = nsip_sendmsg(nsvc, msg); @@ -211,7 +216,8 @@ static int gprs_ns_tx_simple(struct gprs_nsvc *nsvc, uint8_t pdu_type) if (!msg) return -ENOMEM; - nsh = (struct gprs_ns_hdr *) msgb_put(msg, sizeof(*nsh)); + msg->l2h = msgb_put(msg, sizeof(*nsh)); + nsh = (struct gprs_ns_hdr *) msg->l2h; nsh->pdu_type = pdu_type; @@ -231,7 +237,8 @@ int gprs_ns_tx_reset(struct gprs_nsvc *nsvc, uint8_t cause) LOGP(DNS, LOGL_INFO, "NSEI=%u Tx NS RESET (NSVCI=%u, cause=%s)\n", nsvc->nsei, nsvc->nsvci, gprs_ns_cause_str(cause)); - nsh = (struct gprs_ns_hdr *) msgb_put(msg, sizeof(*nsh)); + msg->l2h = msgb_put(msg, sizeof(*nsh)); + nsh = (struct gprs_ns_hdr *) msg->l2h; nsh->pdu_type = NS_PDUT_RESET; msgb_tvlv_put(msg, NS_IE_CAUSE, 1, &cause); @@ -257,7 +264,8 @@ int gprs_ns_tx_status(struct gprs_nsvc *nsvc, uint8_t cause, LOGP(DNS, LOGL_INFO, "NSEI=%u Tx NS STATUS (NSVCI=%u, cause=%s)\n", nsvc->nsei, nsvc->nsvci, gprs_ns_cause_str(cause)); - nsh = (struct gprs_ns_hdr *) msgb_put(msg, sizeof(*nsh)); + msg->l2h = msgb_put(msg, sizeof(*nsh)); + nsh = (struct gprs_ns_hdr *) msg->l2h; nsh->pdu_type = NS_PDUT_STATUS; msgb_tvlv_put(msg, NS_IE_CAUSE, 1, &cause); @@ -303,7 +311,8 @@ int gprs_ns_tx_block(struct gprs_nsvc *nsvc, uint8_t cause) /* be conservative and mark it as blocked even now! */ nsvc->state |= NSE_S_BLOCKED; - nsh = (struct gprs_ns_hdr *) msgb_put(msg, sizeof(*nsh)); + msg->l2h = msgb_put(msg, sizeof(*nsh)); + nsh = (struct gprs_ns_hdr *) msg->l2h; nsh->pdu_type = NS_PDUT_BLOCK; msgb_tvlv_put(msg, NS_IE_CAUSE, 1, &cause); @@ -428,7 +437,8 @@ static int gprs_ns_tx_reset_ack(struct gprs_nsvc *nsvc) nsvci = htons(nsvc->nsvci); nsei = htons(nsvc->nsei); - nsh = (struct gprs_ns_hdr *) msgb_put(msg, sizeof(*nsh)); + msg->l2h = msgb_put(msg, sizeof(*nsh)); + nsh = (struct gprs_ns_hdr *) msg->l2h; nsh->pdu_type = NS_PDUT_RESET_ACK; @@ -600,6 +610,8 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, struct gprs_nsvc *nsvc; int rc = 0; + DEBUGP(DNS, "gprs_ns_rcvmsg(%d)\n", msgb_l2len(msg)); + /* look up the NSVC based on source address */ nsvc = nsvc_by_rem_addr(nsi, saddr); if (!nsvc) { @@ -645,6 +657,10 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, } else msgb_nsei(msg) = nsvc->nsei; + /* Increment number of Incoming bytes */ + rate_ctr_inc(&nsvc->ctrg->ctr[2]); + rate_ctr_add(&nsvc->ctrg->ctr[0], msgb_l2len(msg)); + switch (nsh->pdu_type) { case NS_PDUT_ALIVE: /* If we're dead and blocked and suddenly receive a @@ -880,224 +896,4 @@ struct gprs_nsvc *nsip_connect(struct gprs_ns_inst *nsi, return nsvc; } -#include -#include - -static struct gprs_ns_inst *vty_nsi = NULL; - -static struct cmd_node ns_node = { - NS_NODE, - "%s(ns)#", - 1, -}; - -static int config_write_ns(struct vty *vty) -{ - struct gprs_nsvc *nsvc; - unsigned int i; - - vty_out(vty, "ns%s", VTY_NEWLINE); - - llist_for_each_entry(nsvc, &vty_nsi->gprs_nsvcs, list) { - if (!nsvc->persistent) - continue; - vty_out(vty, " nse %u nsvci %u%s", - nsvc->nsei, nsvc->nsvci, VTY_NEWLINE); - vty_out(vty, " nse %u remote-role %s%s", - nsvc->nsei, nsvc->remote_end_is_sgsn ? "sgsn" : "bss", - VTY_NEWLINE); - if (nsvc->nsi->ll == GPRS_NS_LL_UDP) { - vty_out(vty, " nse %u remote-ip %s%s", - nsvc->nsei, - inet_ntoa(nsvc->ip.bts_addr.sin_addr), - VTY_NEWLINE); - vty_out(vty, " nse %u remote-port %u%s", - nsvc->nsei, ntohs(nsvc->ip.bts_addr.sin_port), - VTY_NEWLINE); - } - } - - for (i = 0; i < ARRAY_SIZE(vty_nsi->timeout); i++) - vty_out(vty, " timer %s %u%s", - get_value_string(gprs_ns_timer_strs, i), - vty_nsi->timeout[i], VTY_NEWLINE); - - return CMD_SUCCESS; -} - -DEFUN(cfg_ns, cfg_ns_cmd, - "ns", - "Configure the GPRS Network Service") -{ - vty->node = NS_NODE; - return CMD_SUCCESS; -} - -DEFUN(show_ns, show_ns_cmd, "show ns", - SHOW_STR "Display information about the NS protocol") -{ - struct gprs_ns_inst *nsi = vty_nsi; - struct gprs_nsvc *nsvc; - - llist_for_each_entry(nsvc, &nsi->gprs_nsvcs, list) { - vty_out(vty, "NSEI %5u, NS-VC %5u, Remote: %-4s, %5s %9s", - nsvc->nsei, nsvc->nsvci, - nsvc->remote_end_is_sgsn ? "SGSN" : "BSS", - nsvc->state & NSE_S_ALIVE ? "ALIVE" : "DEAD", - nsvc->state & NSE_S_BLOCKED ? "BLOCKED" : "UNBLOCKED"); - if (nsvc->nsi->ll == GPRS_NS_LL_UDP) - vty_out(vty, ", %15s:%u", - inet_ntoa(nsvc->ip.bts_addr.sin_addr), - ntohs(nsvc->ip.bts_addr.sin_port)); - vty_out(vty, "%s", VTY_NEWLINE); - } - - return CMD_SUCCESS; -} - - -#define NSE_CMD_STR "NS Entity\n" "NS Entity ID (NSEI)\n" - -DEFUN(cfg_nse_nsvc, cfg_nse_nsvci_cmd, - "nse <0-65535> nsvci <0-65534>", - NSE_CMD_STR - "NS Virtual Connection\n" - "NS Virtual Connection ID (NSVCI)\n" - ) -{ - uint16_t nsei = atoi(argv[0]); - uint16_t nsvci = atoi(argv[1]); - struct gprs_nsvc *nsvc; - - nsvc = nsvc_by_nsei(vty_nsi, nsei); - if (!nsvc) { - nsvc = nsvc_create(vty_nsi, nsvci); - nsvc->nsei = nsei; - } - nsvc->nsvci = nsvci; - /* All NSVCs that are explicitly configured by VTY are - * marked as persistent so we can write them to the config - * file at some later point */ - nsvc->persistent = 1; - - return CMD_SUCCESS; -} - -DEFUN(cfg_nse_remoteip, cfg_nse_remoteip_cmd, - "nse <0-65535> remote-ip A.B.C.D", - NSE_CMD_STR - "Remote IP Address\n" - "Remote IP Address\n") -{ - uint16_t nsei = atoi(argv[0]); - struct gprs_nsvc *nsvc; - nsvc = nsvc_by_nsei(vty_nsi, nsei); - if (!nsvc) { - vty_out(vty, "No such NSE (%u)%s", nsei, VTY_NEWLINE); - return CMD_WARNING; - } - inet_aton(argv[1], &nsvc->ip.bts_addr.sin_addr); - - return CMD_SUCCESS; - -} - -DEFUN(cfg_nse_remoteport, cfg_nse_remoteport_cmd, - "nse <0-65535> remote-port <0-65535>", - NSE_CMD_STR - "Remote UDP Port\n" - "Remote UDP Port Number\n") -{ - uint16_t nsei = atoi(argv[0]); - uint16_t port = atoi(argv[1]); - struct gprs_nsvc *nsvc; - - nsvc = nsvc_by_nsei(vty_nsi, nsei); - if (!nsvc) { - vty_out(vty, "No such NSE (%u)%s", nsei, VTY_NEWLINE); - return CMD_WARNING; - } - - nsvc->ip.bts_addr.sin_port = htons(port); - - return CMD_SUCCESS; -} - -DEFUN(cfg_nse_remoterole, cfg_nse_remoterole_cmd, - "nse <0-65535> remote-role (sgsn|bss)", - NSE_CMD_STR - "Remote NSE Role\n" - "Remote Peer is SGSN\n" - "Remote Peer is BSS\n") -{ - uint16_t nsei = atoi(argv[0]); - struct gprs_nsvc *nsvc; - - nsvc = nsvc_by_nsei(vty_nsi, nsei); - if (!nsvc) { - vty_out(vty, "No such NSE (%u)%s", nsei, VTY_NEWLINE); - return CMD_WARNING; - } - - if (!strcmp(argv[1], "sgsn")) - nsvc->remote_end_is_sgsn = 1; - else - nsvc->remote_end_is_sgsn = 0; - - return CMD_SUCCESS; -} - -DEFUN(cfg_no_nse, cfg_no_nse_cmd, - "no nse <0-65535>", - "Delete NS Entity\n" - "Delete " NSE_CMD_STR) -{ - uint16_t nsei = atoi(argv[0]); - struct gprs_nsvc *nsvc; - - nsvc = nsvc_by_nsei(vty_nsi, nsei); - if (!nsvc) { - vty_out(vty, "No such NSE (%u)%s", nsei, VTY_NEWLINE); - return CMD_WARNING; - } - - nsvc_delete(nsvc); - - return CMD_SUCCESS; -} - -DEFUN(cfg_ns_timer, cfg_ns_timer_cmd, - "timer " NS_TIMERS " <0-65535>", - "Network Service Timer\n" - NS_TIMERS_HELP "Timer Value\n") -{ - int idx = get_string_value(gprs_ns_timer_strs, argv[0]); - int val = atoi(argv[1]); - - if (idx < 0 || idx >= ARRAY_SIZE(vty_nsi->timeout)) - return CMD_WARNING; - - vty_nsi->timeout[idx] = val; - - return CMD_SUCCESS; -} - -int gprs_ns_vty_init(struct gprs_ns_inst *nsi) -{ - vty_nsi = nsi; - - install_element_ve(&show_ns_cmd); - - install_element(CONFIG_NODE, &cfg_ns_cmd); - install_node(&ns_node, config_write_ns); - install_default(NS_NODE); - install_element(NS_NODE, &cfg_nse_nsvci_cmd); - install_element(NS_NODE, &cfg_nse_remoteip_cmd); - install_element(NS_NODE, &cfg_nse_remoteport_cmd); - install_element(NS_NODE, &cfg_nse_remoterole_cmd); - install_element(NS_NODE, &cfg_no_nse_cmd); - install_element(NS_NODE, &cfg_ns_timer_cmd); - - return 0; -} diff --git a/openbsc/src/gprs/gprs_ns_vty.c b/openbsc/src/gprs/gprs_ns_vty.c new file mode 100644 index 000000000..6e98e44d6 --- /dev/null +++ b/openbsc/src/gprs/gprs_ns_vty.c @@ -0,0 +1,275 @@ +/* VTY interface for our GPRS Networks Service (NS) implementation */ + +/* (C) 2009-2010 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +static struct gprs_ns_inst *vty_nsi = NULL; + +/* FIXME: this should go to some common file as it is copied + * in vty_interface.c of the BSC */ +static const struct value_string gprs_ns_timer_strs[] = { + { 0, "tns-block" }, + { 1, "tns-block-retries" }, + { 2, "tns-reset" }, + { 3, "tns-reset-retries" }, + { 4, "tns-test" }, + { 5, "tns-alive" }, + { 6, "tns-alive-retries" }, + { 0, NULL } +}; + +static struct cmd_node ns_node = { + NS_NODE, + "%s(ns)#", + 1, +}; + +static int config_write_ns(struct vty *vty) +{ + struct gprs_nsvc *nsvc; + unsigned int i; + + vty_out(vty, "ns%s", VTY_NEWLINE); + + llist_for_each_entry(nsvc, &vty_nsi->gprs_nsvcs, list) { + if (!nsvc->persistent) + continue; + vty_out(vty, " nse %u nsvci %u%s", + nsvc->nsei, nsvc->nsvci, VTY_NEWLINE); + vty_out(vty, " nse %u remote-role %s%s", + nsvc->nsei, nsvc->remote_end_is_sgsn ? "sgsn" : "bss", + VTY_NEWLINE); + if (nsvc->nsi->ll == GPRS_NS_LL_UDP) { + vty_out(vty, " nse %u remote-ip %s%s", + nsvc->nsei, + inet_ntoa(nsvc->ip.bts_addr.sin_addr), + VTY_NEWLINE); + vty_out(vty, " nse %u remote-port %u%s", + nsvc->nsei, ntohs(nsvc->ip.bts_addr.sin_port), + VTY_NEWLINE); + } + } + + for (i = 0; i < ARRAY_SIZE(vty_nsi->timeout); i++) + vty_out(vty, " timer %s %u%s", + get_value_string(gprs_ns_timer_strs, i), + vty_nsi->timeout[i], VTY_NEWLINE); + + return CMD_SUCCESS; +} + +DEFUN(cfg_ns, cfg_ns_cmd, + "ns", + "Configure the GPRS Network Service") +{ + vty->node = NS_NODE; + return CMD_SUCCESS; +} + +DEFUN(show_ns, show_ns_cmd, "show ns", + SHOW_STR "Display information about the NS protocol") +{ + struct gprs_ns_inst *nsi = vty_nsi; + struct gprs_nsvc *nsvc; + + llist_for_each_entry(nsvc, &nsi->gprs_nsvcs, list) { + vty_out(vty, "NSEI %5u, NS-VC %5u, Remote: %-4s, %5s %9s", + nsvc->nsei, nsvc->nsvci, + nsvc->remote_end_is_sgsn ? "SGSN" : "BSS", + nsvc->state & NSE_S_ALIVE ? "ALIVE" : "DEAD", + nsvc->state & NSE_S_BLOCKED ? "BLOCKED" : "UNBLOCKED"); + if (nsvc->nsi->ll == GPRS_NS_LL_UDP) + vty_out(vty, ", %15s:%u", + inet_ntoa(nsvc->ip.bts_addr.sin_addr), + ntohs(nsvc->ip.bts_addr.sin_port)); + vty_out(vty, "%s", VTY_NEWLINE); + vty_out_rate_ctr_group(vty, " ", nsvc->ctrg); + } + + return CMD_SUCCESS; +} + + +#define NSE_CMD_STR "NS Entity\n" "NS Entity ID (NSEI)\n" + +DEFUN(cfg_nse_nsvc, cfg_nse_nsvci_cmd, + "nse <0-65535> nsvci <0-65534>", + NSE_CMD_STR + "NS Virtual Connection\n" + "NS Virtual Connection ID (NSVCI)\n" + ) +{ + uint16_t nsei = atoi(argv[0]); + uint16_t nsvci = atoi(argv[1]); + struct gprs_nsvc *nsvc; + + nsvc = nsvc_by_nsei(vty_nsi, nsei); + if (!nsvc) { + nsvc = nsvc_create(vty_nsi, nsvci); + nsvc->nsei = nsei; + } + nsvc->nsvci = nsvci; + /* All NSVCs that are explicitly configured by VTY are + * marked as persistent so we can write them to the config + * file at some later point */ + nsvc->persistent = 1; + + return CMD_SUCCESS; +} + +DEFUN(cfg_nse_remoteip, cfg_nse_remoteip_cmd, + "nse <0-65535> remote-ip A.B.C.D", + NSE_CMD_STR + "Remote IP Address\n" + "Remote IP Address\n") +{ + uint16_t nsei = atoi(argv[0]); + struct gprs_nsvc *nsvc; + + nsvc = nsvc_by_nsei(vty_nsi, nsei); + if (!nsvc) { + vty_out(vty, "No such NSE (%u)%s", nsei, VTY_NEWLINE); + return CMD_WARNING; + } + inet_aton(argv[1], &nsvc->ip.bts_addr.sin_addr); + + return CMD_SUCCESS; + +} + +DEFUN(cfg_nse_remoteport, cfg_nse_remoteport_cmd, + "nse <0-65535> remote-port <0-65535>", + NSE_CMD_STR + "Remote UDP Port\n" + "Remote UDP Port Number\n") +{ + uint16_t nsei = atoi(argv[0]); + uint16_t port = atoi(argv[1]); + struct gprs_nsvc *nsvc; + + nsvc = nsvc_by_nsei(vty_nsi, nsei); + if (!nsvc) { + vty_out(vty, "No such NSE (%u)%s", nsei, VTY_NEWLINE); + return CMD_WARNING; + } + + nsvc->ip.bts_addr.sin_port = htons(port); + + return CMD_SUCCESS; +} + +DEFUN(cfg_nse_remoterole, cfg_nse_remoterole_cmd, + "nse <0-65535> remote-role (sgsn|bss)", + NSE_CMD_STR + "Remote NSE Role\n" + "Remote Peer is SGSN\n" + "Remote Peer is BSS\n") +{ + uint16_t nsei = atoi(argv[0]); + struct gprs_nsvc *nsvc; + + nsvc = nsvc_by_nsei(vty_nsi, nsei); + if (!nsvc) { + vty_out(vty, "No such NSE (%u)%s", nsei, VTY_NEWLINE); + return CMD_WARNING; + } + + if (!strcmp(argv[1], "sgsn")) + nsvc->remote_end_is_sgsn = 1; + else + nsvc->remote_end_is_sgsn = 0; + + return CMD_SUCCESS; +} + +DEFUN(cfg_no_nse, cfg_no_nse_cmd, + "no nse <0-65535>", + "Delete NS Entity\n" + "Delete " NSE_CMD_STR) +{ + uint16_t nsei = atoi(argv[0]); + struct gprs_nsvc *nsvc; + + nsvc = nsvc_by_nsei(vty_nsi, nsei); + if (!nsvc) { + vty_out(vty, "No such NSE (%u)%s", nsei, VTY_NEWLINE); + return CMD_WARNING; + } + + nsvc_delete(nsvc); + + return CMD_SUCCESS; +} + +DEFUN(cfg_ns_timer, cfg_ns_timer_cmd, + "timer " NS_TIMERS " <0-65535>", + "Network Service Timer\n" + NS_TIMERS_HELP "Timer Value\n") +{ + int idx = get_string_value(gprs_ns_timer_strs, argv[0]); + int val = atoi(argv[1]); + + if (idx < 0 || idx >= ARRAY_SIZE(vty_nsi->timeout)) + return CMD_WARNING; + + vty_nsi->timeout[idx] = val; + + return CMD_SUCCESS; +} + +int gprs_ns_vty_init(struct gprs_ns_inst *nsi) +{ + vty_nsi = nsi; + + install_element_ve(&show_ns_cmd); + + install_element(CONFIG_NODE, &cfg_ns_cmd); + install_node(&ns_node, config_write_ns); + install_default(NS_NODE); + install_element(NS_NODE, &cfg_nse_nsvci_cmd); + install_element(NS_NODE, &cfg_nse_remoteip_cmd); + install_element(NS_NODE, &cfg_nse_remoteport_cmd); + install_element(NS_NODE, &cfg_nse_remoterole_cmd); + install_element(NS_NODE, &cfg_no_nse_cmd); + install_element(NS_NODE, &cfg_ns_timer_cmd); + + return 0; +} -- cgit v1.2.3 From 66f793a770b8a852ce7cc892fd42f6f693f3d28c Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 13 May 2010 11:50:04 +0200 Subject: [GPRS] SGSN: Add Signal handler and NS VTY support --- openbsc/src/gprs/sgsn_main.c | 50 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 45 insertions(+), 5 deletions(-) diff --git a/openbsc/src/gprs/sgsn_main.c b/openbsc/src/gprs/sgsn_main.c index 15f760d5c..b355fb58d 100644 --- a/openbsc/src/gprs/sgsn_main.c +++ b/openbsc/src/gprs/sgsn_main.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -35,6 +36,7 @@ #include #include +#include #include #include @@ -89,8 +91,34 @@ static int sgsn_ns_cb(enum gprs_ns_evt event, struct gprs_nsvc *nsvc, return rc; } +static void signal_handler(int signal) +{ + fprintf(stdout, "signal %u received\n", signal); + + switch (signal) { + case SIGINT: + dispatch_signal(SS_GLOBAL, S_GLOBAL_SHUTDOWN, NULL); + sleep(1); + exit(0); + break; + case SIGABRT: + /* in case of abort, we want to obtain a talloc report + * and then return to the caller, who will abort the process */ + case SIGUSR1: + talloc_report(tall_vty_ctx, stderr); + talloc_report_full(tall_bsc_ctx, stderr); + break; + case SIGUSR2: + talloc_report_full(tall_vty_ctx, stderr); + break; + default: + break; + } +} + /* NSI that BSSGP uses when transmitting on NS */ extern struct gprs_ns_inst *bssgp_nsi; +extern void *tall_msgb_ctx; int main(int argc, char **argv) { @@ -100,18 +128,21 @@ int main(int argc, char **argv) int rc; tall_bsc_ctx = talloc_named_const(NULL, 0, "osmo_sgsn"); + tall_msgb_ctx = talloc_named_const(tall_bsc_ctx, 0, "msgb"); + + signal(SIGINT, &signal_handler); + signal(SIGABRT, &signal_handler); + signal(SIGUSR1, &signal_handler); + signal(SIGUSR2, &signal_handler); + signal(SIGPIPE, SIG_IGN); log_init(&log_info); stderr_target = log_target_create_stderr(); log_add_target(stderr_target); log_set_all_filter(stderr_target, 1); + rate_ctr_init(tall_bsc_ctx); telnet_init(&dummy_network, 4245); - rc = sgsn_parse_config(config_file, &sgcfg); - if (rc < 0) { - LOGP(DGPRS, LOGL_FATAL, "Cannot parse config file\n"); - exit(2); - } sgsn_nsi = gprs_ns_instantiate(&sgsn_ns_cb); if (!sgsn_nsi) { @@ -119,6 +150,15 @@ int main(int argc, char **argv) exit(1); } bssgp_nsi = sgcfg.nsi = sgsn_nsi; + gprs_ns_vty_init(bssgp_nsi); + /* FIXME: register signal handler for SS_NS */ + + rc = sgsn_parse_config(config_file, &sgcfg); + if (rc < 0) { + LOGP(DGPRS, LOGL_FATAL, "Cannot parse config file\n"); + exit(2); + } + nsip_listen(sgsn_nsi, sgcfg.nsip_listen_port); while (1) { -- cgit v1.2.3 From 89deee9b99800435da31ba3719a9a603c07448b4 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 13 May 2010 11:53:52 +0200 Subject: Add missing file vty/utils.c --- openbsc/src/vty/utils.c | 50 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 openbsc/src/vty/utils.c diff --git a/openbsc/src/vty/utils.c b/openbsc/src/vty/utils.c new file mode 100644 index 000000000..d8dfb8ef9 --- /dev/null +++ b/openbsc/src/vty/utils.c @@ -0,0 +1,50 @@ +/* utility routines for printing common objects in the Osmocom world */ + +/* (C) 2009-2010 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 + +#include + +void vty_out_rate_ctr_group(struct vty *vty, const char *prefix, + struct rate_ctr_group *ctrg) +{ + unsigned int i; + + vty_out(vty, "%s%s:%s", prefix, ctrg->desc->group_description, VTY_NEWLINE); + for (i = 0; i < ctrg->desc->num_ctr; i++) { + struct rate_ctr *ctr = &ctrg->ctr[i]; + vty_out(vty, " %s%s: %8" PRIu64 " " + "(%" PRIu64 "/s %" PRIu64 "/m %" PRIu64 "/h %" PRIu64 "/d)%s", + prefix, ctrg->desc->ctr_desc[i].description, ctr->current, + ctr->intv[RATE_CTR_INTV_SEC].rate, + ctr->intv[RATE_CTR_INTV_MIN].rate, + ctr->intv[RATE_CTR_INTV_HOUR].rate, + ctr->intv[RATE_CTR_INTV_DAY].rate, + VTY_NEWLINE); + }; +} -- cgit v1.2.3 From 8e605b045ecc3f25dc90984f2ae3ab6dd583add7 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 13 May 2010 11:57:44 +0200 Subject: [GPRS] NS: Fix wrong counter use and remove debug statement --- openbsc/src/gprs/gprs_ns.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/openbsc/src/gprs/gprs_ns.c b/openbsc/src/gprs/gprs_ns.c index e83aee8e6..cdc745aa6 100644 --- a/openbsc/src/gprs/gprs_ns.c +++ b/openbsc/src/gprs/gprs_ns.c @@ -610,8 +610,6 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, struct gprs_nsvc *nsvc; int rc = 0; - DEBUGP(DNS, "gprs_ns_rcvmsg(%d)\n", msgb_l2len(msg)); - /* look up the NSVC based on source address */ nsvc = nsvc_by_rem_addr(nsi, saddr); if (!nsvc) { @@ -658,8 +656,8 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, msgb_nsei(msg) = nsvc->nsei; /* Increment number of Incoming bytes */ - rate_ctr_inc(&nsvc->ctrg->ctr[2]); - rate_ctr_add(&nsvc->ctrg->ctr[0], msgb_l2len(msg)); + rate_ctr_inc(&nsvc->ctrg->ctr[0]); + rate_ctr_add(&nsvc->ctrg->ctr[2], msgb_l2len(msg)); switch (nsh->pdu_type) { case NS_PDUT_ALIVE: -- cgit v1.2.3 From 087fcff9a5342f7a10c9f378bd4130f409657001 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 13 May 2010 12:16:17 +0200 Subject: rate_ctr: Store the numeric index as part of 'rate_ctr_group' --- include/osmocore/rate_ctr.h | 1 + src/rate_ctr.c | 1 + 2 files changed, 2 insertions(+) diff --git a/include/osmocore/rate_ctr.h b/include/osmocore/rate_ctr.h index c6a1ace2f..47fd5a36c 100644 --- a/include/osmocore/rate_ctr.h +++ b/include/osmocore/rate_ctr.h @@ -49,6 +49,7 @@ struct rate_ctr_group { struct llist_head list; /* Pointer to the counter group class */ const struct rate_ctr_group_desc *desc; + unsigned int idx; /* The name prefix generated from desc->group_prefix_fmt and index */ char *name_prefix; /* Actual counter structures below */ diff --git a/src/rate_ctr.c b/src/rate_ctr.c index 9b2459e89..bde090a40 100644 --- a/src/rate_ctr.c +++ b/src/rate_ctr.c @@ -51,6 +51,7 @@ struct rate_ctr_group *rate_ctr_group_alloc(void *ctx, return NULL; group->desc = desc; + group->idx = idx; /* Generate the Group prefix from the user-specified index */ group->name_prefix = talloc_size(group, strlen(desc->group_prefix_fmt) + 20); sprintf(group->name_prefix, desc->group_prefix_fmt, idx); -- cgit v1.2.3 From e183345748857c0a140c0c2c9a467aa0a4c2a88e Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 13 May 2010 12:18:49 +0200 Subject: [GPRS] NS: properly assign msgb->l2h to count outgoing bytes correctly --- openbsc/src/gprs/gprs_ns.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openbsc/src/gprs/gprs_ns.c b/openbsc/src/gprs/gprs_ns.c index cdc745aa6..8530eb176 100644 --- a/openbsc/src/gprs/gprs_ns.c +++ b/openbsc/src/gprs/gprs_ns.c @@ -476,7 +476,8 @@ int gprs_ns_sendmsg(struct gprs_ns_inst *nsi, struct msgb *msg) return -EBUSY; } - nsh = (struct gprs_ns_hdr *) msgb_push(msg, sizeof(*nsh) + 3); + msg->l2h = msgb_push(msg, sizeof(*nsh) + 3); + nsh = (struct gprs_ns_hdr *) msg->l2h; if (!nsh) { LOGP(DNS, LOGL_ERROR, "Not enough headroom for NS header\n"); return -EIO; -- cgit v1.2.3 From 73b2359fb02d04ab76c512cb09660735c1306f87 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 13 May 2010 12:32:30 +0200 Subject: [GPRS] NS: Show statistics on VTY only if requested --- openbsc/src/gprs/gprs_ns_vty.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/openbsc/src/gprs/gprs_ns_vty.c b/openbsc/src/gprs/gprs_ns_vty.c index 6e98e44d6..08b0076c1 100644 --- a/openbsc/src/gprs/gprs_ns_vty.c +++ b/openbsc/src/gprs/gprs_ns_vty.c @@ -104,10 +104,8 @@ DEFUN(cfg_ns, cfg_ns_cmd, return CMD_SUCCESS; } -DEFUN(show_ns, show_ns_cmd, "show ns", - SHOW_STR "Display information about the NS protocol") +static void dump_ns(struct vty *vty, struct gprs_ns_inst *nsi, int stats) { - struct gprs_ns_inst *nsi = vty_nsi; struct gprs_nsvc *nsvc; llist_for_each_entry(nsvc, &nsi->gprs_nsvcs, list) { @@ -121,12 +119,28 @@ DEFUN(show_ns, show_ns_cmd, "show ns", inet_ntoa(nsvc->ip.bts_addr.sin_addr), ntohs(nsvc->ip.bts_addr.sin_port)); vty_out(vty, "%s", VTY_NEWLINE); - vty_out_rate_ctr_group(vty, " ", nsvc->ctrg); + if (stats) + vty_out_rate_ctr_group(vty, " ", nsvc->ctrg); } +} +DEFUN(show_ns, show_ns_cmd, "show ns", + SHOW_STR "Display information about the NS protocol") +{ + struct gprs_ns_inst *nsi = vty_nsi; + dump_ns(vty, nsi, 0); return CMD_SUCCESS; } +DEFUN(show_ns_stats, show_ns_stats_cmd, "show ns stats", + SHOW_STR + "Display information about the NS protocol\n" + "Include statistics\n") +{ + struct gprs_ns_inst *nsi = vty_nsi; + dump_ns(vty, nsi, 1); + return CMD_SUCCESS; +} #define NSE_CMD_STR "NS Entity\n" "NS Entity ID (NSEI)\n" @@ -260,6 +274,7 @@ int gprs_ns_vty_init(struct gprs_ns_inst *nsi) vty_nsi = nsi; install_element_ve(&show_ns_cmd); + install_element_ve(&show_ns_stats_cmd); install_element(CONFIG_NODE, &cfg_ns_cmd); install_node(&ns_node, config_write_ns); -- cgit v1.2.3 From dd178b2dc9a34aaa28ee00300db9d5ef6d45e820 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 13 May 2010 12:50:44 +0200 Subject: rate_counters: Remove group-name-sprintf-with-idx string --- include/osmocore/rate_ctr.h | 3 +-- src/rate_ctr.c | 3 --- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/include/osmocore/rate_ctr.h b/include/osmocore/rate_ctr.h index 47fd5a36c..85fe5c1f3 100644 --- a/include/osmocore/rate_ctr.h +++ b/include/osmocore/rate_ctr.h @@ -49,9 +49,8 @@ struct rate_ctr_group { struct llist_head list; /* Pointer to the counter group class */ const struct rate_ctr_group_desc *desc; + /* The index of this ctr_group within its class */ unsigned int idx; - /* The name prefix generated from desc->group_prefix_fmt and index */ - char *name_prefix; /* Actual counter structures below */ struct rate_ctr ctr[0]; }; diff --git a/src/rate_ctr.c b/src/rate_ctr.c index bde090a40..e48c77928 100644 --- a/src/rate_ctr.c +++ b/src/rate_ctr.c @@ -52,9 +52,6 @@ struct rate_ctr_group *rate_ctr_group_alloc(void *ctx, group->desc = desc; group->idx = idx; - /* Generate the Group prefix from the user-specified index */ - group->name_prefix = talloc_size(group, strlen(desc->group_prefix_fmt) + 20); - sprintf(group->name_prefix, desc->group_prefix_fmt, idx); llist_add(&group->list, &rate_ctr_groups); -- cgit v1.2.3 From cf734784b0433dfa6b77909f83cc3620e523f5d7 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 13 May 2010 12:53:35 +0200 Subject: [rate_ctr] Rename group_prefix_fmt to group_name_prefix --- include/osmocore/rate_ctr.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/osmocore/rate_ctr.h b/include/osmocore/rate_ctr.h index 85fe5c1f3..88c9de5a6 100644 --- a/include/osmocore/rate_ctr.h +++ b/include/osmocore/rate_ctr.h @@ -33,8 +33,8 @@ struct rate_ctr_desc { /* Describe a counter group class */ struct rate_ctr_group_desc { - /* The prefix / format string to be used for all counters */ - char *group_prefix_fmt; + /* The prefix to the name of all counters in this group */ + char *group_name_prefix; /* The human-readable description of the group */ char *group_description; /* The number of counters in this group */ -- cgit v1.2.3 From c1919866912d8106b522b9092641022ddaf31137 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 13 May 2010 12:55:20 +0200 Subject: [GPRS] NS: more rate counters for BLOCK / DEAD count --- openbsc/src/db.c | 17 ++++++++++++----- openbsc/src/gprs/gprs_ns.c | 33 +++++++++++++++++++++++++-------- 2 files changed, 37 insertions(+), 13 deletions(-) diff --git a/openbsc/src/db.c b/openbsc/src/db.c index f7fb3b457..57a7863c9 100644 --- a/openbsc/src/db.c +++ b/openbsc/src/db.c @@ -127,6 +127,13 @@ static char *create_stmts[] = { "value INTEGER NOT NULL, " "name TEXT NOT NULL " ")", + "CREATE TABLE IF NOT EXISTS RateCounters (" + "id INTEGER PRIMARY KEY AUTOINCREMENT, " + "timestamp TIMESTAMP NOT NULL, " + "value INTEGER NOT NULL, " + "name TEXT NOT NULL, " + "index INTEGER NOT NULL " + ")", "CREATE TABLE IF NOT EXISTS AuthKeys (" "id INTEGER PRIMARY KEY AUTOINCREMENT, " "subscriber_id INTEGER UNIQUE NOT NULL, " @@ -1194,10 +1201,10 @@ static int db_store_rate_ctr(struct rate_ctr_group *ctrg, unsigned int num, &q_name); result = dbi_conn_queryf(conn, - "Insert INTO Counters " - "(timestamp,name,value) VALUES " - "(datetime('now'),%s.%s,%"PRIu64")", - q_prefix, q_name, ctrg->ctr[num].current); + "Insert INTO RateCounters " + "(timestamp,name,index,value) VALUES " + "(datetime('now'),%s.%s,%u,%"PRIu64")", + q_prefix, q_name, ctrg->idx, ctrg->ctr[num].current); free(q_name); @@ -1213,7 +1220,7 @@ int db_store_rate_ctr_group(struct rate_ctr_group *ctrg) unsigned int i; char *q_prefix; - dbi_conn_quote_string_copy(conn, ctrg->name_prefix, &q_prefix); + dbi_conn_quote_string_copy(conn, ctrg->desc->group_name_prefix, &q_prefix); for (i = 0; i < ctrg->desc->num_ctr; i++) db_store_rate_ctr(ctrg, i, q_prefix); diff --git a/openbsc/src/gprs/gprs_ns.c b/openbsc/src/gprs/gprs_ns.c index 8530eb176..554e2ec38 100644 --- a/openbsc/src/gprs/gprs_ns.c +++ b/openbsc/src/gprs/gprs_ns.c @@ -74,15 +74,26 @@ static const struct tlv_definition ns_att_tlvdef = { }, }; +enum ns_ctr { + NS_CTR_PKTS_IN, + NS_CTR_PKTS_OUT, + NS_CTR_BYTES_IN, + NS_CTR_BYTES_OUT, + NS_CTR_BLOCKED, + NS_CTR_DEAD, +}; + static const struct rate_ctr_desc nsvc_ctr_description[] = { { "packets.in", "Packets at NS Level ( In)" }, - { "packets.out", "Packets at NS Level (Out)" }, - { "bytes.in", "Bytes at NS Level ( In)" }, - { "bytes.out", "Bytes at NS Level (Out)" }, + { "packets.out","Packets at NS Level (Out)" }, + { "bytes.in", "Bytes at NS Level ( In)" }, + { "bytes.out", "Bytes at NS Level (Out)" }, + { "blocked", "NS-VC Block count " }, + { "dead", "NS-VC gone dead count " }, }; static const struct rate_ctr_group_desc nsvc_ctrg_desc = { - .group_prefix_fmt = "ns.nsvc%u", + .group_name_prefix = "ns.nsvc", .group_description = "NSVC Peer Statistics", .num_ctr = ARRAY_SIZE(nsvc_ctr_description), .ctr_desc = nsvc_ctr_description, @@ -192,8 +203,8 @@ static int gprs_ns_tx(struct gprs_nsvc *nsvc, struct msgb *msg) int ret; /* Increment number of Uplink bytes */ - rate_ctr_inc(&nsvc->ctrg->ctr[1]); - rate_ctr_add(&nsvc->ctrg->ctr[3], msgb_l2len(msg)); + rate_ctr_inc(&nsvc->ctrg->ctr[NS_CTR_PKTS_OUT]); + rate_ctr_add(&nsvc->ctrg->ctr[NS_CTR_BYTES_OUT], msgb_l2len(msg)); switch (nsvc->nsi->ll) { case GPRS_NS_LL_UDP: @@ -310,6 +321,7 @@ int gprs_ns_tx_block(struct gprs_nsvc *nsvc, uint8_t cause) /* be conservative and mark it as blocked even now! */ nsvc->state |= NSE_S_BLOCKED; + rate_ctr_inc(&nsvc->ctrg->ctr[NS_CTR_BLOCKED]); msg->l2h = msgb_put(msg, sizeof(*nsh)); nsh = (struct gprs_ns_hdr *) msg->l2h; @@ -392,6 +404,8 @@ static void gprs_ns_timer_cb(void *data) nsvc->nsi->timeout[NS_TOUT_TNS_ALIVE_RETRIES]) { /* mark as dead and blocked */ nsvc->state = NSE_S_BLOCKED; + rate_ctr_inc(&nsvc->ctrg->ctr[NS_CTR_BLOCKED]); + rate_ctr_inc(&nsvc->ctrg->ctr[NS_CTR_DEAD]); LOGP(DNS, LOGL_NOTICE, "NSEI=%u Tns-alive expired more then " "%u times, blocking NS-VC\n", nsvc->nsei, @@ -599,6 +613,7 @@ static int gprs_ns_rx_block(struct gprs_nsvc *nsvc, struct msgb *msg) //nsvci = (uint16_t *) TLVP_VAL(&tp, NS_IE_VCI); ns_dispatch_signal(nsvc, S_NS_BLOCK, *cause); + rate_ctr_inc(&nsvc->ctrg->ctr[NS_CTR_BLOCKED]); return gprs_ns_tx_simple(nsvc, NS_PDUT_BLOCK_ACK); } @@ -657,8 +672,9 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, msgb_nsei(msg) = nsvc->nsei; /* Increment number of Incoming bytes */ - rate_ctr_inc(&nsvc->ctrg->ctr[0]); - rate_ctr_add(&nsvc->ctrg->ctr[2], msgb_l2len(msg)); + rate_ctr_inc(&nsvc->ctrg->ctr[NS_CTR_PKTS_IN]); + DEBUGP(DNS, "BYTES_IN msgb_l2len=%d\n", msgb_l2len(msg)); + rate_ctr_add(&nsvc->ctrg->ctr[NS_CTR_BYTES_IN], msgb_l2len(msg)); switch (nsh->pdu_type) { case NS_PDUT_ALIVE: @@ -697,6 +713,7 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, /* mark NS-VC as blocked + active */ nsvc->state = NSE_S_BLOCKED | NSE_S_ALIVE; nsvc->remote_state = NSE_S_BLOCKED | NSE_S_ALIVE; + rate_ctr_inc(&nsvc->ctrg->ctr[NS_CTR_BLOCKED]); if (nsvc->remote_end_is_sgsn) { /* stop RESET timer */ bsc_del_timer(&nsvc->timer); -- cgit v1.2.3 From a6fd8f233928e7b8daa1dd29a2d2abfb512c7aec Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 13 May 2010 13:09:01 +0200 Subject: [GPRS] NS: remove debug statement about l2len --- openbsc/src/gprs/gprs_ns.c | 1 - 1 file changed, 1 deletion(-) diff --git a/openbsc/src/gprs/gprs_ns.c b/openbsc/src/gprs/gprs_ns.c index 554e2ec38..2853600df 100644 --- a/openbsc/src/gprs/gprs_ns.c +++ b/openbsc/src/gprs/gprs_ns.c @@ -673,7 +673,6 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, /* Increment number of Incoming bytes */ rate_ctr_inc(&nsvc->ctrg->ctr[NS_CTR_PKTS_IN]); - DEBUGP(DNS, "BYTES_IN msgb_l2len=%d\n", msgb_l2len(msg)); rate_ctr_add(&nsvc->ctrg->ctr[NS_CTR_BYTES_IN], msgb_l2len(msg)); switch (nsh->pdu_type) { -- cgit v1.2.3 From 9aa97fc13725375535c73a0c2f71d3045bb4044c Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 13 May 2010 13:58:08 +0200 Subject: [GPRS] NS: Fix segfault when receiving message from unknown NS-VC In the previous code we used a static fake_nsvc structure in case we needed to send a message to an unknown NSVC for which we don't have a real 'struct nsvc'. However, since we now have a rate_ctr_group hanging off the nsvc, the fake structure didn't have that. So now we keep a nsi->unknown_nsvc around to be used whenever we need a nsvc but don't have a real one. The gprs_ns_vty.c code explicitly does not list that NSVC in 'show ns' --- openbsc/include/openbsc/gprs_ns.h | 3 +++ openbsc/src/gprs/gprs_ns.c | 25 +++++++++++++++++-------- openbsc/src/gprs/gprs_ns_vty.c | 2 ++ 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/openbsc/include/openbsc/gprs_ns.h b/openbsc/include/openbsc/gprs_ns.h index 34b1b62d2..4ccf4c7b9 100644 --- a/openbsc/include/openbsc/gprs_ns.h +++ b/openbsc/include/openbsc/gprs_ns.h @@ -125,6 +125,9 @@ struct gprs_ns_inst { /* linked lists of all NSVC in this instance */ struct llist_head gprs_nsvcs; + /* a NSVC object that's needed to deal with packets for unknown NSVC */ + struct gprs_nsvc *unknown_nsvc; + uint16_t timeout[NS_TIMERS_COUNT]; /* which link-layer are we based on? */ diff --git a/openbsc/src/gprs/gprs_ns.c b/openbsc/src/gprs/gprs_ns.c index 2853600df..50ab8203f 100644 --- a/openbsc/src/gprs/gprs_ns.c +++ b/openbsc/src/gprs/gprs_ns.c @@ -44,6 +44,14 @@ * Those mappings are administratively configured. */ +/* This implementation has the following limitations: + * o Only one NS-VC for each NSE: No load-sharing function + * o NSVCI 65535 and 65534 are reserved for internal use + * o Only UDP is supported as of now, no frame relay support + * o The IP Sub-Network-Service (SNS) as specified in 48.016 is not implemented + * o There are no BLOCK and UNBLOCK timers (yet?) + */ + #include #include #include @@ -633,17 +641,16 @@ int gprs_ns_rcvmsg(struct gprs_ns_inst *nsi, struct msgb *msg, uint16_t nsei; /* Only the RESET procedure creates a new NSVC */ if (nsh->pdu_type != NS_PDUT_RESET) { - struct gprs_nsvc fake_nsvc; - LOGP(DNS, LOGL_INFO, "Ignoring NS PDU type 0x%0x " + /* Since we have no NSVC, we have to use a fake */ + nsvc = nsi->unknown_nsvc; + LOGP(DNS, LOGL_INFO, "Rejecting NS PDU type 0x%0x " "from %s:%u for non-existing NS-VC\n", nsh->pdu_type, inet_ntoa(saddr->sin_addr), ntohs(saddr->sin_port)); - /* Since we have no NSVC, we have to create a fake */ - fake_nsvc.nsvci = fake_nsvc.nsei = 0; - fake_nsvc.nsi = nsi; - fake_nsvc.ip.bts_addr = *saddr; - fake_nsvc.state = NSE_S_ALIVE; - return gprs_ns_tx_status(&fake_nsvc, + nsvc->nsvci = nsvc->nsei = 0xfffe; + nsvc->ip.bts_addr = *saddr; + nsvc->state = NSE_S_ALIVE; + return gprs_ns_tx_status(nsvc, NS_CAUSE_PDU_INCOMP_PSTATE, 0, msg); } @@ -766,6 +773,8 @@ struct gprs_ns_inst *gprs_ns_instantiate(gprs_ns_cb_t *cb) nsi->timeout[NS_TOUT_TNS_ALIVE] = 3; nsi->timeout[NS_TOUT_TNS_ALIVE_RETRIES] = 10; + nsi->unknown_nsvc = nsvc_create(nsi, 0xfffe); + return nsi; } diff --git a/openbsc/src/gprs/gprs_ns_vty.c b/openbsc/src/gprs/gprs_ns_vty.c index 08b0076c1..8f0628afd 100644 --- a/openbsc/src/gprs/gprs_ns_vty.c +++ b/openbsc/src/gprs/gprs_ns_vty.c @@ -109,6 +109,8 @@ static void dump_ns(struct vty *vty, struct gprs_ns_inst *nsi, int stats) struct gprs_nsvc *nsvc; llist_for_each_entry(nsvc, &nsi->gprs_nsvcs, list) { + if (nsvc == nsi->unknown_nsvc) + continue; vty_out(vty, "NSEI %5u, NS-VC %5u, Remote: %-4s, %5s %9s", nsvc->nsei, nsvc->nsvci, nsvc->remote_end_is_sgsn ? "SGSN" : "BSS", -- cgit v1.2.3 From 4cf12e9350056bdbd98e7c0559e6272dbaba9f15 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 13 May 2010 14:14:56 +0200 Subject: [GPRS] Gb Proxy: More verbose logging --- openbsc/src/gprs/gb_proxy.c | 42 +++++++++++++++++++++++++++--------------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/openbsc/src/gprs/gb_proxy.c b/openbsc/src/gprs/gb_proxy.c index 9580ea3a3..5fbf9bfcc 100644 --- a/openbsc/src/gprs/gb_proxy.c +++ b/openbsc/src/gprs/gb_proxy.c @@ -190,7 +190,7 @@ static int gbprox_relay2bvci(struct msgb *msg, uint16_t ptp_bvci, peer = peer_by_bvci(ptp_bvci); if (!peer) { - LOGP(DGPRS, LOGL_ERROR, "Cannot find BSS for BVCI %u\n", + LOGP(DGPRS, LOGL_ERROR, "BVCI=%u: Cannot find BSS\n", ptp_bvci); return -ENOENT; } @@ -210,7 +210,7 @@ static int gbprox_rx_sig_from_bss(struct msgb *msg, struct gprs_nsvc *nsvc, struct gprs_ra_id raid; if (ns_bvci != 0) { - LOGP(DGPRS, LOGL_NOTICE, "NSEI=%u BVCI %u is not signalling\n", + LOGP(DGPRS, LOGL_NOTICE, "NSEI=%u BVCI=%u is not signalling\n", nsvc->nsei, ns_bvci); return -EINVAL; } @@ -242,10 +242,10 @@ static int gbprox_rx_sig_from_bss(struct msgb *msg, struct gprs_nsvc *nsvc, memcpy(from_peer->ra, TLVP_VAL(&tp, BSSGP_IE_ROUTEING_AREA), sizeof(from_peer->ra)); gsm48_parse_ra(&raid, from_peer->ra); - LOGP(DGPRS, LOGL_INFO, "NSEI=%u RAC snooping: RAC %u-%u-%u-%u " - "behind BVCI=%u, NSVCI=%u\n", nsvc->nsei, raid.mcc, - raid.mnc, raid.lac, raid.rac , from_peer->bvci, - nsvc->nsvci); + LOGP(DGPRS, LOGL_INFO, "NSEI=%u BSSGP SUSPEND/RESUME " + "RAC snooping: RAC %u-%u-%u-%u behind BVCI=%u, " + "NSVCI=%u\n",nsvc->nsei, raid.mcc, raid.mnc, raid.lac, + raid.rac , from_peer->bvci, nsvc->nsvci); /* FIXME: This only supports one BSS per RA */ break; case BSSGP_PDUT_BVC_RESET: @@ -309,19 +309,31 @@ err_mand_ie: static int gbprox_rx_paging(struct msgb *msg, struct tlv_parsed *tp, struct gprs_nsvc *nsvc, uint16_t ns_bvci) { - struct gbprox_peer *peer; + struct gbprox_peer *peer = NULL; + LOGP(DGPRS, LOGL_INFO, "NSEI=%u(SGSN) BSSGP PAGING ", + nsvc->nsei); if (TLVP_PRESENT(tp, BSSGP_IE_BVCI)) { uint16_t bvci = ntohs(*(uint16_t *)TLVP_VAL(tp, BSSGP_IE_BVCI)); - return gbprox_relay2bvci(msg, bvci, ns_bvci); + LOGPC(DGPRS, LOGL_INFO, "routing by BVCI to peer BVCI=%u\n", + bvci); } else if (TLVP_PRESENT(tp, BSSGP_IE_ROUTEING_AREA)) { peer = peer_by_rac(TLVP_VAL(tp, BSSGP_IE_ROUTEING_AREA)); - return gbprox_relay2peer(msg, peer, ns_bvci); + LOGPC(DGPRS, LOGL_INFO, "routing by RAC to peer BVCI=%u\n", + peer->bvci); } else if (TLVP_PRESENT(tp, BSSGP_IE_LOCATION_AREA)) { peer = peer_by_lac(TLVP_VAL(tp, BSSGP_IE_LOCATION_AREA)); - return gbprox_relay2peer(msg, peer, ns_bvci); + LOGPC(DGPRS, LOGL_INFO, "routing by LAC to peer BVCI=%u\n", + peer->bvci); } else + LOGPC(DGPRS, LOGL_INFO, "\n"); + + if (!peer) { + LOGP(DGPRS, LOGL_ERROR, "NSEI=%u(SGSN) BSSGP PAGING: " + "unable to route, missing IE\n", nsvc->nsei); return -EINVAL; + } + return gbprox_relay2peer(msg, peer, ns_bvci); } /* Receive an incoming BVC-RESET message from the SGSN */ @@ -342,8 +354,8 @@ static int rx_reset_from_sgsn(struct msgb *msg, struct tlv_parsed *tp, * respective peer */ peer = peer_by_bvci(ptp_bvci); if (!peer) { - LOGP(DGPRS, LOGL_ERROR, "Cannot find BSS for BVCI %u\n", - ptp_bvci); + LOGP(DGPRS, LOGL_ERROR, "NSEI=%u BVCI=%u: Cannot find BSS\n", + nsvc->nsei, ptp_bvci); return bssgp_tx_status(BSSGP_CAUSE_UNKNOWN_BVCI, NULL, msg); } @@ -373,7 +385,7 @@ static int gbprox_rx_sig_from_sgsn(struct msgb *msg, struct gprs_nsvc *nsvc, int rc = 0; if (ns_bvci != 0) { - LOGP(DGPRS, LOGL_NOTICE, "NSEI=%u(SGSN) BVCI %u is not " + LOGP(DGPRS, LOGL_NOTICE, "NSEI=%u(SGSN) BVCI=%u is not " "signalling\n", nsvc->nsei, ns_bvci); /* FIXME: Send proper error message */ return -EINVAL; @@ -412,7 +424,7 @@ static int gbprox_rx_sig_from_sgsn(struct msgb *msg, struct gprs_nsvc *nsvc, case BSSGP_PDUT_STATUS: /* Some exception has occurred */ LOGP(DGPRS, LOGL_NOTICE, - "NSEI=%u(SGSN) STATUS ", nsvc->nsei); + "NSEI=%u(SGSN) BSSGP STATUS ", nsvc->nsei); if (!TLVP_PRESENT(&tp, BSSGP_IE_CAUSE)) { LOGPC(DGPRS, LOGL_NOTICE, "\n"); goto err_mand_ie; @@ -443,7 +455,7 @@ static int gbprox_rx_sig_from_sgsn(struct msgb *msg, struct gprs_nsvc *nsvc, break; case BSSGP_PDUT_SGSN_INVOKE_TRACE: LOGP(DGPRS, LOGL_ERROR, - "NSEI=%u(SGSN) INVOKE TRACE not supported\n", nsvc->nsei); + "NSEI=%u(SGSN) BSSGP INVOKE TRACE not supported\n",nsvc->nsei); rc = bssgp_tx_status(BSSGP_CAUSE_PDU_INCOMP_FEAT, NULL, msg); break; default: -- cgit v1.2.3 From 3863e0491869f9aeb449cac028b54fd9d51e4de5 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 13 May 2010 14:20:56 +0200 Subject: [GPRS] NS: Remove 'unknown_nsvc' from list of NS-VCs --- openbsc/src/gprs/gprs_ns.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/openbsc/src/gprs/gprs_ns.c b/openbsc/src/gprs/gprs_ns.c index 50ab8203f..dc12953e0 100644 --- a/openbsc/src/gprs/gprs_ns.c +++ b/openbsc/src/gprs/gprs_ns.c @@ -773,7 +773,10 @@ struct gprs_ns_inst *gprs_ns_instantiate(gprs_ns_cb_t *cb) nsi->timeout[NS_TOUT_TNS_ALIVE] = 3; nsi->timeout[NS_TOUT_TNS_ALIVE_RETRIES] = 10; + /* Create the dummy NSVC that we use for sending + * messages to non-existant/unknown NS-VC's */ nsi->unknown_nsvc = nsvc_create(nsi, 0xfffe); + llist_del(&nsi->unknown_nsvc->list); return nsi; } -- cgit v1.2.3 From 3a0a463fa45fa126eb2d46cf7eafb00c0413dbf8 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Fri, 14 May 2010 00:39:19 +0800 Subject: rach: Allow to set the emergency call bit Add the rach emergency call allowed (0|1) setting and implement it by directly manipulating the t2 value. It is the third bit which is set to 0 when emergency calls are enabled and to one if it is only enabled for access classes 11 to 15. --- openbsc/src/vty_interface.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c index 866131613..6a05137b6 100644 --- a/openbsc/src/vty_interface.c +++ b/openbsc/src/vty_interface.c @@ -383,6 +383,8 @@ static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts) bts->rach_ldavg_slots, VTY_NEWLINE); if (bts->si_common.rach_control.cell_bar) vty_out(vty, " cell barred 1%s", VTY_NEWLINE); + if ((bts->si_common.rach_control.t2 & 0x4) == 0) + vty_out(vty, " rach emergency call allowed 1%s", VTY_NEWLINE); if (is_ipaccess_bts(bts)) { vty_out(vty, " ip.access unit_id %u %u%s", bts->ip_access.site_id, bts->ip_access.bts_id, VTY_NEWLINE); @@ -1469,6 +1471,20 @@ DEFUN(cfg_bts_cell_barred, cfg_bts_cell_barred_cmd, return CMD_SUCCESS; } +DEFUN(cfg_bts_rach_ec_allowed, cfg_bts_rach_ec_allowed_cmd, + "rach emergency call allowed (0|1)", + "Should this cell allow emergency calls?") +{ + struct gsm_bts *bts = vty->index; + + if (atoi(argv[0]) == 0) + bts->si_common.rach_control.t2 |= 0x4; + else + bts->si_common.rach_control.t2 &= ~0x4; + + return CMD_SUCCESS; +} + DEFUN(cfg_bts_ms_max_power, cfg_bts_ms_max_power_cmd, "ms max power <0-40>", "Maximum transmit power of the MS") @@ -1963,6 +1979,7 @@ int bsc_vty_init(struct gsm_network *net) install_element(BTS_NODE, &cfg_bts_rach_nm_b_thresh_cmd); install_element(BTS_NODE, &cfg_bts_rach_nm_ldavg_cmd); install_element(BTS_NODE, &cfg_bts_cell_barred_cmd); + install_element(BTS_NODE, &cfg_bts_rach_ec_allowed_cmd); install_element(BTS_NODE, &cfg_bts_ms_max_power_cmd); install_element(BTS_NODE, &cfg_bts_per_loc_upd_cmd); install_element(BTS_NODE, &cfg_bts_cell_resel_hyst_cmd); -- cgit v1.2.3 From b8819bb84512753f1522497f51d378943ec2db10 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Fri, 14 May 2010 00:58:11 +0800 Subject: [vty] Remove unfinished code from the VTY... --- openbsc/src/vty_interface.c | 27 --------------------------- 1 file changed, 27 deletions(-) diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c index 6a05137b6..df8f45ca6 100644 --- a/openbsc/src/vty_interface.c +++ b/openbsc/src/vty_interface.c @@ -683,33 +683,6 @@ static void lchan_dump_vty(struct vty *vty, struct gsm_lchan *lchan) meas_rep_dump_vty(vty, &lchan->meas_rep[idx], " "); } -#if 0 -TODO: callref and remote callref of call must be resolved to get gsm_trans object -static void call_dump_vty(struct vty *vty, struct gsm_call *call) -{ - vty_out(vty, "Call Type %u, State %u, Transaction ID %u%s", - call->type, call->state, call->transaction_id, VTY_NEWLINE); - - if (call->local_lchan) { - vty_out(vty, "Call Local Channel:%s", VTY_NEWLINE); - lchan_dump_vty(vty, call->local_lchan); - } else - vty_out(vty, "Call has no Local Channel%s", VTY_NEWLINE); - - if (call->remote_lchan) { - vty_out(vty, "Call Remote Channel:%s", VTY_NEWLINE); - lchan_dump_vty(vty, call->remote_lchan); - } else - vty_out(vty, "Call has no Remote Channel%s", VTY_NEWLINE); - - if (call->called_subscr) { - vty_out(vty, "Called Subscriber:%s", VTY_NEWLINE); - subscr_dump_vty(vty, call->called_subscr); - } else - vty_out(vty, "Call has no Called Subscriber%s", VTY_NEWLINE); -} -#endif - DEFUN(show_lchan, show_lchan_cmd, "show lchan [bts_nr] [trx_nr] [ts_nr] [lchan_nr]", -- cgit v1.2.3 From 029235ea96fffe4c522c9f2fafd138fedcb40abf Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Fri, 14 May 2010 02:03:16 +0800 Subject: [vty] Move "show lchan" into a parameterized method I want to have a shorter lchan summary but with the same config parameters. Change the current code to be a method that takes a dump routine as parameter. --- openbsc/src/vty_interface.c | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c index df8f45ca6..41a235551 100644 --- a/openbsc/src/vty_interface.c +++ b/openbsc/src/vty_interface.c @@ -648,7 +648,7 @@ static void meas_rep_dump_vty(struct vty *vty, struct gsm_meas_rep *mr, meas_rep_dump_uni_vty(vty, &mr->ul, prefix, "ul"); } -static void lchan_dump_vty(struct vty *vty, struct gsm_lchan *lchan) +static void lchan_dump_full_vty(struct vty *vty, struct gsm_lchan *lchan) { int idx; @@ -683,12 +683,8 @@ static void lchan_dump_vty(struct vty *vty, struct gsm_lchan *lchan) meas_rep_dump_vty(vty, &lchan->meas_rep[idx], " "); } -DEFUN(show_lchan, - show_lchan_cmd, - "show lchan [bts_nr] [trx_nr] [ts_nr] [lchan_nr]", - SHOW_STR "Display information about a logical channel\n" - "BTS Number\n" "TRX Number\n" "Timeslot Number\n" - "Logical Channel Number\n") +static int lchan_summary(struct vty *vty, int argc, const char **argv, + void (*dump_cb)(struct vty *, struct gsm_lchan *)) { struct gsm_network *net = gsmnet; struct gsm_bts *bts; @@ -733,7 +729,7 @@ DEFUN(show_lchan, return CMD_WARNING; } lchan = &ts->lchan[lchan_nr]; - lchan_dump_vty(vty, lchan); + dump_cb(vty, lchan); return CMD_SUCCESS; } for (bts_nr = 0; bts_nr < net->num_bts; bts_nr++) { @@ -747,7 +743,7 @@ DEFUN(show_lchan, lchan = &ts->lchan[lchan_nr]; if (lchan->type == GSM_LCHAN_NONE) continue; - lchan_dump_vty(vty, lchan); + dump_cb(vty, lchan); } } } @@ -756,6 +752,18 @@ DEFUN(show_lchan, return CMD_SUCCESS; } + +DEFUN(show_lchan, + show_lchan_cmd, + "show lchan [bts_nr] [trx_nr] [ts_nr] [lchan_nr]", + SHOW_STR "Display information about a logical channel\n" + "BTS Number\n" "TRX Number\n" "Timeslot Number\n" + "Logical Channel Number\n") + +{ + return lchan_summary(vty, argc, argv, lchan_dump_full_vty); +} + static void e1drv_dump_vty(struct vty *vty, struct e1inp_driver *drv) { vty_out(vty, "E1 Input Driver %s%s", drv->name, VTY_NEWLINE); -- cgit v1.2.3 From 3d6a5d648e0dca3c65c1be42bc1ce617179b4a2c Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Fri, 14 May 2010 02:08:49 +0800 Subject: [vty] Add a one line show lchan summary command. --- openbsc/src/vty_interface.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c index 41a235551..85530d004 100644 --- a/openbsc/src/vty_interface.c +++ b/openbsc/src/vty_interface.c @@ -683,6 +683,14 @@ static void lchan_dump_full_vty(struct vty *vty, struct gsm_lchan *lchan) meas_rep_dump_vty(vty, &lchan->meas_rep[idx], " "); } +static void lchan_dump_short_vty(struct vty *vty, struct gsm_lchan *lchan) +{ + vty_out(vty, "Lchan %u in Timeslot %u of TRX %u in BTS %u, Type %s%s", + lchan->nr, lchan->ts->nr, lchan->ts->trx->nr, + lchan->ts->trx->bts->nr, gsm_lchant_name(lchan->type), + VTY_NEWLINE); +} + static int lchan_summary(struct vty *vty, int argc, const char **argv, void (*dump_cb)(struct vty *, struct gsm_lchan *)) { @@ -764,6 +772,16 @@ DEFUN(show_lchan, return lchan_summary(vty, argc, argv, lchan_dump_full_vty); } +DEFUN(show_lchan_summary, + show_lchan_summary_cmd, + "show lchan summary [bts_nr] [trx_nr] [ts_nr] [lchan_nr]", + SHOW_STR "Display information about a logical channel\n" + "BTS Number\n" "TRX Number\n" "Timeslot Number\n" + "Logical Channel Number\n") +{ + return lchan_summary(vty, argc, argv, lchan_dump_short_vty); +} + static void e1drv_dump_vty(struct vty *vty, struct e1inp_driver *drv) { vty_out(vty, "E1 Input Driver %s%s", drv->name, VTY_NEWLINE); @@ -1900,6 +1918,7 @@ int bsc_vty_init(struct gsm_network *net) install_element_ve(&show_trx_cmd); install_element_ve(&show_ts_cmd); install_element_ve(&show_lchan_cmd); + install_element_ve(&show_lchan_summary_cmd); install_element_ve(&show_e1drv_cmd); install_element_ve(&show_e1line_cmd); -- cgit v1.2.3 From cf5cc5bb5b472f470eb9584a32dee3c38413f93a Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Fri, 14 May 2010 01:57:02 +0800 Subject: [vty] Add power measurements to the one line summary. --- openbsc/src/vty_interface.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c index 85530d004..279970649 100644 --- a/openbsc/src/vty_interface.c +++ b/openbsc/src/vty_interface.c @@ -685,9 +685,21 @@ static void lchan_dump_full_vty(struct vty *vty, struct gsm_lchan *lchan) static void lchan_dump_short_vty(struct vty *vty, struct gsm_lchan *lchan) { - vty_out(vty, "Lchan %u in Timeslot %u of TRX %u in BTS %u, Type %s%s", + struct gsm_meas_rep *mr; + int idx; + + /* we want to report the last measurement report */ + idx = calc_initial_idx(ARRAY_SIZE(lchan->meas_rep), + lchan->meas_rep_idx, 1); + mr = &lchan->meas_rep[idx]; + + vty_out(vty, "Lchan: %u Timeslot: %u TRX: %u BTS: %u Type: %s - L1 MS Power: %u dBm " + "RXL-FULL-dl: %4d dBm RXL-FULL-ul: %4d dBm%s", lchan->nr, lchan->ts->nr, lchan->ts->trx->nr, lchan->ts->trx->bts->nr, gsm_lchant_name(lchan->type), + mr->ms_l1.pwr, + rxlev2dbm(mr->dl.full.rx_lev), + rxlev2dbm(mr->ul.full.rx_lev), VTY_NEWLINE); } -- cgit v1.2.3