blob: 4e5fb016a2923d4262d1752b15420da3d279b730 [file] [log] [blame]
Harald Welte75bb8202010-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
Harald Welted85d9a92010-05-02 11:26:34 +020023#include <stdint.h>
Harald Welte75bb8202010-03-14 15:45:01 +080024
25#include <osmocore/linuxlist.h>
26#include <osmocore/talloc.h>
27#include <osmocore/timer.h>
28#include <openbsc/gsm_subscriber.h>
Harald Weltef67a5f92010-04-26 19:18:54 +020029#include <openbsc/debug.h>
Harald Welte75bb8202010-03-14 15:45:01 +080030#include <openbsc/gprs_sgsn.h>
Harald Weltef67a5f92010-04-26 19:18:54 +020031#include <openbsc/gprs_ns.h>
32#include <openbsc/gprs_bssgp.h>
Harald Welte75bb8202010-03-14 15:45:01 +080033
Harald Weltec1f6bfe2010-05-17 22:58:03 +020034LLIST_HEAD(sgsn_mm_ctxts);
35LLIST_HEAD(sgsn_ggsn_ctxts);
36LLIST_HEAD(sgsn_apn_ctxts);
37LLIST_HEAD(sgsn_pdp_ctxts);
Harald Welte75bb8202010-03-14 15:45:01 +080038
39static int ra_id_equals(const struct gprs_ra_id *id1,
40 const struct gprs_ra_id *id2)
41{
42 return (id1->mcc == id2->mcc && id1->mnc == id2->mnc &&
43 id1->lac == id2->lac && id1->rac == id2->rac);
44}
45
46/* look-up a SGSN MM context based on TLLI + RAI */
Harald Welted85d9a92010-05-02 11:26:34 +020047struct sgsn_mm_ctx *sgsn_mm_ctx_by_tlli(uint32_t tlli,
Harald Welte75bb8202010-03-14 15:45:01 +080048 const struct gprs_ra_id *raid)
49{
50 struct sgsn_mm_ctx *ctx;
51
52 llist_for_each_entry(ctx, &sgsn_mm_ctxts, list) {
53 if (tlli == ctx->tlli &&
54 ra_id_equals(raid, &ctx->ra))
55 return ctx;
56 }
57 return NULL;
58}
59
Harald Welted85d9a92010-05-02 11:26:34 +020060struct sgsn_mm_ctx *sgsn_mm_ctx_by_ptmsi(uint32_t p_tmsi)
Harald Welte75bb8202010-03-14 15:45:01 +080061{
62 struct sgsn_mm_ctx *ctx;
63
64 llist_for_each_entry(ctx, &sgsn_mm_ctxts, list) {
65 if (p_tmsi == ctx->p_tmsi)
66 return ctx;
67 }
68 return NULL;
69}
70
71struct sgsn_mm_ctx *sgsn_mm_ctx_by_imsi(const char *imsi)
72{
73 struct sgsn_mm_ctx *ctx;
74
75 llist_for_each_entry(ctx, &sgsn_mm_ctxts, list) {
76 if (!strcmp(imsi, ctx->imsi))
77 return ctx;
78 }
79 return NULL;
80
81}
82
83/* Allocate a new SGSN MM context */
Harald Welted85d9a92010-05-02 11:26:34 +020084struct sgsn_mm_ctx *sgsn_mm_ctx_alloc(uint32_t tlli,
Harald Welte75bb8202010-03-14 15:45:01 +080085 const struct gprs_ra_id *raid)
86{
Harald Welte8f77f192010-05-17 00:44:57 +020087 struct sgsn_mm_ctx *ctx;
Harald Welte75bb8202010-03-14 15:45:01 +080088
Harald Welte8f77f192010-05-17 00:44:57 +020089 ctx = talloc_zero(tall_bsc_ctx, struct sgsn_mm_ctx);
Harald Welte75bb8202010-03-14 15:45:01 +080090 if (!ctx)
91 return NULL;
92
93 memcpy(&ctx->ra, raid, sizeof(ctx->ra));
94 ctx->tlli = tlli;
95 ctx->mm_state = GMM_DEREGISTERED;
96
97 llist_add(&ctx->list, &sgsn_mm_ctxts);
98
99 return ctx;
100}
Harald Weltec1f6bfe2010-05-17 22:58:03 +0200101
102struct sgsn_pdp_ctx *sgsn_pdp_ctx_by_nsapi(const struct sgsn_mm_ctx *mm,
103 uint8_t nsapi)
104{
105 struct sgsn_pdp_ctx *pdp;
106
107 llist_for_each_entry(pdp, &mm->pdp_list, list) {
108 if (pdp->nsapi == nsapi)
109 return pdp;
110 }
111 return NULL;
112}
113
114struct sgsn_pdp_ctx *sgsn_pdp_ctx_alloc(struct sgsn_mm_ctx *mm,
115 uint8_t nsapi)
116{
117 struct sgsn_pdp_ctx *pdp;
118
119 pdp = sgsn_pdp_ctx_by_nsapi(mm, nsapi);
120 if (pdp)
121 return NULL;
122
123 pdp = talloc_zero(tall_bsc_ctx, struct sgsn_pdp_ctx);
124 if (!pdp)
125 return NULL;
126
127 pdp->mm = mm;
128 pdp->nsapi = nsapi;
129 llist_add(&pdp->list, &mm->pdp_list);
130 llist_add(&pdp->g_list, &sgsn_pdp_ctxts);
131
132 return pdp;
133}
134
135void sgsn_pdp_ctx_free(struct sgsn_pdp_ctx *pdp)
136{
137 llist_del(&pdp->list);
138 llist_del(&pdp->g_list);
139 talloc_free(pdp);
140}
141
142/* GGSN contexts */
143
144struct ggsn_ctx *ggsn_ctx_alloc(uint32_t id)
145{
146 struct ggsn_ctx *ggc;
147
148 ggc = talloc_zero(tall_bsc_ctx, struct ggsn_ctx);
149 if (!ggc)
150 return NULL;
151
152 ggc->id = id;
153 ggc->gtp_version = 1;
154
155 return ggc;
156}
157
158struct ggsn_ctx *ggsn_ctx_by_id(uint32_t id)
159{
160 struct ggsn_ctx *ggc;
161
162 llist_for_each_entry(ggc, &sgsn_ggsn_ctxts, list) {
163 if (id == ggc->id)
164 return ggc;
165 }
166 return NULL;
167}
168
169struct ggsn_ctx *ggsn_ctx_find_alloc(uint32_t id)
170{
171 struct ggsn_ctx *ggc;
172
173 ggc = ggsn_ctx_by_id(id);
174 if (!ggc)
175 ggc = ggsn_ctx_alloc(id);
176 return ggc;
177}
178
179/* APN contexts */
180
181#if 0
182struct apn_ctx *apn_ctx_alloc(const char *ap_name)
183{
184 struct apn_ctx *actx;
185
186 actx = talloc_zero(talloc_bsc_ctx, struct apn_ctx);
187 if (!actx)
188 return NULL;
189 actx->name = talloc_strdup(actx, ap_name);
190
191 return actx;
192}
193
194struct apn_ctx *apn_ctx_by_name(const char *name)
195{
196 struct apn_ctx *actx;
197
198 llist_for_each_entry(actx, &sgsn_apn_ctxts, list) {
199 if (!strcmp(name, actx->name))
200 return actx;
201 }
202 return NULL;
203}
204
205struct apn_ctx *apn_ctx_find_alloc(const char *name)
206{
207 struct apn_ctx *actx;
208
209 actx = apn_ctx_by_name(name);
210 if (!actx)
211 actx = apn_ctx_alloc(name);
212
213 return actx;
214}
215#endif