diff options
author | Jacob Erlbeck <jerlbeck@sysmocom.de> | 2015-02-03 13:47:53 +0100 |
---|---|---|
committer | Holger Hans Peter Freyther <holger@moiji-mobile.com> | 2015-02-06 09:56:17 +0100 |
commit | cb1db8b6d5277a52ed553925d301bfdc514bb77c (patch) | |
tree | 62515e3ce5b4c0d1d13bcc02c787e1957e64e222 /openbsc/src/gprs/gprs_sgsn.c | |
parent | 0e8add601da35188eb155c8c279a9bdcaf4ba41b (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.c | 77 |
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) { |