blob: 3f7f61e20a990ead6274b8ad03887c261563a5b0 [file] [log] [blame]
Harald Welte9b455bf2010-03-14 15:45:01 +08001/* GPRS SGSN functionality */
2
3/* (C) 2009 by Harald Welte <laforge@gnumonks.org>
4 *
5 * All Rights Reserved
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 */
22
23#include <sys/types.h>
24
25#include <osmocore/linuxlist.h>
26#include <osmocore/talloc.h>
27#include <osmocore/timer.h>
28#include <openbsc/gsm_subscriber.h>
Harald Weltecb991632010-04-26 19:18:54 +020029#include <openbsc/debug.h>
Harald Welte9b455bf2010-03-14 15:45:01 +080030#include <openbsc/gprs_sgsn.h>
Harald Weltecb991632010-04-26 19:18:54 +020031#include <openbsc/gprs_ns.h>
32#include <openbsc/gprs_bssgp.h>
Harald Welte9b455bf2010-03-14 15:45:01 +080033
34static LLIST_HEAD(sgsn_mm_ctxts);
35
36static int ra_id_equals(const struct gprs_ra_id *id1,
37 const struct gprs_ra_id *id2)
38{
39 return (id1->mcc == id2->mcc && id1->mnc == id2->mnc &&
40 id1->lac == id2->lac && id1->rac == id2->rac);
41}
42
43/* look-up a SGSN MM context based on TLLI + RAI */
44struct sgsn_mm_ctx *sgsn_mm_ctx_by_tlli(u_int32_t tlli,
45 const struct gprs_ra_id *raid)
46{
47 struct sgsn_mm_ctx *ctx;
48
49 llist_for_each_entry(ctx, &sgsn_mm_ctxts, list) {
50 if (tlli == ctx->tlli &&
51 ra_id_equals(raid, &ctx->ra))
52 return ctx;
53 }
54 return NULL;
55}
56
57struct sgsn_mm_ctx *sgsn_mm_ctx_by_ptmsi(u_int32_t p_tmsi)
58{
59 struct sgsn_mm_ctx *ctx;
60
61 llist_for_each_entry(ctx, &sgsn_mm_ctxts, list) {
62 if (p_tmsi == ctx->p_tmsi)
63 return ctx;
64 }
65 return NULL;
66}
67
68struct sgsn_mm_ctx *sgsn_mm_ctx_by_imsi(const char *imsi)
69{
70 struct sgsn_mm_ctx *ctx;
71
72 llist_for_each_entry(ctx, &sgsn_mm_ctxts, list) {
73 if (!strcmp(imsi, ctx->imsi))
74 return ctx;
75 }
76 return NULL;
77
78}
79
80/* Allocate a new SGSN MM context */
81struct sgsn_mm_ctx *sgsn_mm_ctx_alloc(u_int32_t tlli,
82 const struct gprs_ra_id *raid)
83{
84 struct sgsn_mm_ctx *ctx = talloc_zero(NULL, struct sgsn_mm_ctx);
85
86 if (!ctx)
87 return NULL;
88
89 memcpy(&ctx->ra, raid, sizeof(ctx->ra));
90 ctx->tlli = tlli;
91 ctx->mm_state = GMM_DEREGISTERED;
92
93 llist_add(&ctx->list, &sgsn_mm_ctxts);
94
95 return ctx;
96}
Harald Weltecb991632010-04-26 19:18:54 +020097
98/* call-back function for the NS protocol */
99static int gprs_ns_cb(enum gprs_ns_evt event, struct gprs_nsvc *nsvc,
100 struct msgb *msg, u_int16_t bvci)
101{
102 int rc = 0;
103
104 switch (event) {
105 case GPRS_NS_EVT_UNIT_DATA:
106 /* hand the message into the BSSGP implementation */
107 rc = gprs_bssgp_rcvmsg(msg, bvci);
108 break;
109 default:
110 LOGP(DGPRS, LOGL_ERROR, "SGSN: Unknown event %u from NS\n", event);
111 if (msg)
112 talloc_free(msg);
113 rc = -EIO;
114 break;
115 }
116 return rc;
117}
118
119int sgsn_init(void)
120{
121 struct gprs_ns_inst *nsi;
122
123 nsi = gprs_ns_instantiate(&gprs_ns_cb);
124 if (!nsi)
125 return -EIO;
126
127 return nsip_listen(nsi, 23000);
128}