aboutsummaryrefslogtreecommitdiffstats
path: root/openbsc/src/gprs/gprs_sgsn.c
diff options
context:
space:
mode:
authorJacob Erlbeck <jerlbeck@sysmocom.de>2015-02-03 13:47:53 +0100
committerHolger Hans Peter Freyther <holger@moiji-mobile.com>2015-02-06 09:56:17 +0100
commitcb1db8b6d5277a52ed553925d301bfdc514bb77c (patch)
tree62515e3ce5b4c0d1d13bcc02c787e1957e64e222 /openbsc/src/gprs/gprs_sgsn.c
parent0e8add601da35188eb155c8c279a9bdcaf4ba41b (diff)
sgsn: Add functions to handle APN contexts
This commit adds the exported functions apn_ctx_find_alloc, apn_ctx_free, apn_ctx_by_name, and apn_ctx_match to manage and retrieve APN to GGSN mappings. The following VTY commands are added to 'config-sgsn': - apn APN ggsn <0-255> - apn APN imsi-prefix PREFIX ggsn <0-255> which maps an APN gateway string to an SGSN id. The SGSN must be configured in advance. When matching an APN string, entries with a leading '*' are used for suffix matching, otherwise an exact match is done. When a prefix is given, it is matched against the IMSI. If several entries match, a longer matching IMSI prefix has precedence. If there are several matching entries with the same PREFIX, the entry with longest matching APN is returned. Ticket: OW#1334 Sponsored-by: On-Waves ehf
Diffstat (limited to 'openbsc/src/gprs/gprs_sgsn.c')
-rw-r--r--openbsc/src/gprs/gprs_sgsn.c77
1 files changed, 68 insertions, 9 deletions
diff --git a/openbsc/src/gprs/gprs_sgsn.c b/openbsc/src/gprs/gprs_sgsn.c
index 555be57f5..54fe15cb1 100644
--- a/openbsc/src/gprs/gprs_sgsn.c
+++ b/openbsc/src/gprs/gprs_sgsn.c
@@ -387,41 +387,100 @@ struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_find_alloc(uint32_t id)
/* APN contexts */
-#if 0
-struct apn_ctx *apn_ctx_alloc(const char *ap_name)
+static struct apn_ctx *sgsn_apn_ctx_alloc(const char *ap_name, const char *imsi_prefix)
{
struct apn_ctx *actx;
- actx = talloc_zero(talloc_bsc_ctx, struct apn_ctx);
+ actx = talloc_zero(tall_bsc_ctx, struct apn_ctx);
if (!actx)
return NULL;
actx->name = talloc_strdup(actx, ap_name);
+ actx->imsi_prefix = talloc_strdup(actx, imsi_prefix);
+
+ llist_add_tail(&actx->list, &sgsn_apn_ctxts);
return actx;
}
-struct apn_ctx *apn_ctx_by_name(const char *name)
+void sgsn_apn_ctx_free(struct apn_ctx *actx)
+{
+ llist_del(&actx->list);
+ talloc_free(actx);
+}
+
+struct apn_ctx *sgsn_apn_ctx_match(const char *name, const char *imsi)
+{
+ struct apn_ctx *actx;
+ struct apn_ctx *found_actx = NULL;
+ size_t imsi_prio = 0;
+ size_t name_prio = 0;
+ size_t name_req_len = strlen(name);
+
+ llist_for_each_entry(actx, &sgsn_apn_ctxts, list) {
+ size_t name_ref_len, imsi_ref_len;
+ const char *name_ref_start, *name_match_start;
+
+ imsi_ref_len = strlen(actx->imsi_prefix);
+ if (strncmp(actx->imsi_prefix, imsi, imsi_ref_len) != 0)
+ continue;
+
+ if (imsi_ref_len < imsi_prio)
+ continue;
+
+ /* IMSI matches */
+
+ name_ref_start = &actx->name[0];
+ if (name_ref_start[0] == '*') {
+ /* Suffix match */
+ name_ref_start += 1;
+ name_ref_len = strlen(name_ref_start);
+ if (name_ref_len > name_req_len)
+ continue;
+ } else {
+ name_ref_len = strlen(name_ref_start);
+ if (name_ref_len != name_req_len)
+ continue;
+ }
+
+ name_match_start = name + (name_req_len - name_ref_len);
+ if (strcasecmp(name_match_start, name_ref_start) != 0)
+ continue;
+
+ /* IMSI and name match */
+
+ if (imsi_ref_len == imsi_prio && name_ref_len < name_prio)
+ /* Lower priority, skip */
+ continue;
+
+ imsi_prio = imsi_ref_len;
+ name_prio = name_ref_len;
+ found_actx = actx;
+ }
+ return found_actx;
+}
+
+struct apn_ctx *sgsn_apn_ctx_by_name(const char *name, const char *imsi_prefix)
{
struct apn_ctx *actx;
llist_for_each_entry(actx, &sgsn_apn_ctxts, list) {
- if (!strcmp(name, actx->name))
+ if (strcasecmp(name, actx->name) == 0 &&
+ strcasecmp(imsi_prefix, actx->imsi_prefix) == 0)
return actx;
}
return NULL;
}
-struct apn_ctx *apn_ctx_find_alloc(const char *name)
+struct apn_ctx *sgsn_apn_ctx_find_alloc(const char *name, const char *imsi_prefix)
{
struct apn_ctx *actx;
- actx = apn_ctx_by_name(name);
+ actx = sgsn_apn_ctx_by_name(name, imsi_prefix);
if (!actx)
- actx = apn_ctx_alloc(name);
+ actx = sgsn_apn_ctx_alloc(name, imsi_prefix);
return actx;
}
-#endif
uint32_t sgsn_alloc_ptmsi(void)
{