blob: 493b9b40d4c641d03d41c226cd47d900f44a7372 [file] [log] [blame]
jjako52c24142002-12-16 13:33:51 +00001/*
2 * OpenGGSN - Gateway GPRS Support Node
jjakoa7cd2492003-04-11 09:40:12 +00003 * Copyright (C) 2002, 2003 Mondru AB.
jjako52c24142002-12-16 13:33:51 +00004 *
5 * The contents of this file may be used under the terms of the GNU
6 * General Public License Version 2, provided that the above copyright
7 * notice and this permission notice is included in all copies or
8 * substantial portions of the software.
9 *
10 * The initial developer of the original code is
11 * Jens Jakobsen <jj@openggsn.org>
12 *
13 * Contributor(s):
14 *
15 */
16
17/*
18 * pdp.c:
19 *
20 */
21
22#include <stdio.h>
23#include <sys/types.h>
24#include <netinet/in.h>
25#include <string.h>
26#include "pdp.h"
27#include "lookupa.h"
28
29/* ***********************************************************
30 * Global variables TODO: most should be moved to gsn_t
31 *************************************************************/
32
33struct pdp_t pdpa[PDP_MAX]; /* PDP storage */
34struct pdp_t* hashtid[PDP_MAX];/* Hash table for IMSI + NSAPI */
jjakoa7cd2492003-04-11 09:40:12 +000035/* struct pdp_t* haship[PDP_MAX]; Hash table for IP and network interface */
jjako52c24142002-12-16 13:33:51 +000036
37/* ***********************************************************
38 * Functions related to PDP storage
39 *
40 * Lifecycle
41 * For a GGSN pdp context life begins with the reception of a
42 * create pdp context request. It normally ends with the reception
43 * of a delete pdp context request, but will also end with the
44 * reception of an error indication message.
45 * Provisions should probably be made for terminating pdp contexts
46 * based on either idle timeout, or by sending downlink probe
47 * messages (ping?) to see if the MS is still responding.
48 *
49 * For an SGSN pdp context life begins with the application just
50 * before sending off a create pdp context request. It normally
51 * ends when a delete pdp context response message is received
52 * from the GGSN, but should also end when with the reception of
53 * an error indication message.
54 *
55 *
56 * HASH Tables
57 *
58 * Downlink packets received in the GGSN are identified only by their
59 * network interface together with their destination IP address (Two
60 * network interfaces can use the same private IP address). Each IMSI
61 * (mobile station) can have several PDP contexts using the same IP
62 * address. In this case the traffic flow template (TFT) is used to
63 * determine the correct PDP context for a particular IMSI. Also it
64 * should be possible for each PDP context to use several IP adresses
65 * For fixed wireless access a mobile station might need a full class
66 * C network. Even in the case of several IP adresses the PDP context
67 * should be determined on the basis of the network IP address.
68 * Thus we need a hash table based on network interface + IP address.
69 *
70 * Uplink packets are for GTP0 identified by their IMSI and NSAPI, which
71 * is collectively called the tunnel identifier. There is also a 16 bit
72 * flow label that can be used for identification of uplink packets. This
73 * however is quite useless as it limits the number of contexts to 65536.
74 * For GTP1 uplink packets are identified by a Tunnel Endpoint Identifier
75 * (32 bit), or in some cases by the combination of IMSI and NSAPI.
76 * For GTP1 delete context requests there is a need to find the PDP
77 * contexts with the same IP address. This however can be done by using
78 * the IP hash table.
79 * Thus we need a hash table based on TID (IMSI and NSAPI). The TEID will
80 * be used for directly addressing the PDP context.
81
82 * pdp_newpdp
83 * Gives you a pdp context with no hash references In some way
84 * this should have a limited lifetime.
85 *
86 * pdp_freepdp
87 * Frees a context that was previously allocated with
88 * pdp_newpdp
89 *
90 *
91 * pdp_getpdpIP
92 * An incoming IP packet is uniquely identified by a pointer
93 * to a network connection (void *) and an IP address
94 * (struct in_addr)
95 *
96 * pdp_getpdpGTP
97 * An incoming GTP packet is uniquely identified by a the
98 * TID (imsi + nsapi (8 octets)) in or by the Flow Label
99 * (2 octets) in gtp0 or by the Tunnel Endpoint Identifier
100 * (4 octets) in gtp1.
101 *
102 * This leads to an architecture where the receiving GSN
103 * chooses a Flow Label or a Tunnel Endpoint Identifier
104 * when the connection is setup.
105 * Thus no hash table is needed for GTP lookups.
106 *
107 *************************************************************/
108
109int pdp_init() {
110 memset(&pdpa, 0, sizeof(pdpa));
111 memset(&hashtid, 0, sizeof(hashtid));
jjakoa7cd2492003-04-11 09:40:12 +0000112 /* memset(&haship, 0, sizeof(haship)); */
jjako52c24142002-12-16 13:33:51 +0000113
114 return 0;
115}
116
117int pdp_newpdp(struct pdp_t **pdp, uint64_t imsi, uint8_t nsapi,
118 struct pdp_t *pdp_old){
119 int n;
120 for (n=0; n<PDP_MAX; n++) { /* TODO: Need to do better than linear search */
121 if (pdpa[n].inuse == 0) {
122 *pdp = &pdpa[n];
123 if (NULL != pdp_old) memcpy(*pdp, pdp_old, sizeof(struct pdp_t));
124 else memset(*pdp, 0, sizeof(struct pdp_t));
125 (*pdp)->inuse = 1;
126 (*pdp)->imsi = imsi;
127 (*pdp)->nsapi = nsapi;
128 (*pdp)->fllc = (uint16_t) n;
129 (*pdp)->fllu = (uint16_t) n;
130 (*pdp)->teic_own = (uint32_t) n;
jjako08d331d2003-10-13 20:33:30 +0000131 (*pdp)->teid_own = (uint32_t) n;
jjako52c24142002-12-16 13:33:51 +0000132 pdp_tidset(*pdp, pdp_gettid(imsi, nsapi));
133 return 0;
134 }
135 }
136 return EOF; /* No more available */
137}
138
139int pdp_freepdp(struct pdp_t *pdp){
140 pdp_tiddel(pdp);
141 memset(pdp, 0, sizeof(struct pdp_t));
142 /* Also need to clean up IP hash tables */
143 return 0;
144}
145
146int pdp_getpdp(struct pdp_t **pdp){
147 *pdp = &pdpa[0];
148 return 0;
149}
150
151int pdp_getgtp0(struct pdp_t **pdp, uint16_t fl){
152 if (fl>=PDP_MAX) {
153 return EOF; /* Not found */
154 }
155 else {
156 *pdp = &pdpa[fl];
157 if ((*pdp)->inuse) return 0;
158 else return EOF;
159 /* Context exists. We do no further validity checking. */
160 }
161}
162
163int pdp_getgtp1(struct pdp_t **pdp, uint32_t teid){
164 if (teid>=PDP_MAX) {
165 return -1; /* Not found */
166 }
167 else {
168 *pdp = &pdpa[teid];
169 return 0; /* We do no validity checking. */
170 }
171}
172
173
174int pdp_tidhash(uint64_t tid) {
175 return (lookup(&tid, sizeof(tid), 0) % PDP_MAX);
176}
177
178int pdp_tidset(struct pdp_t *pdp, uint64_t tid) {
179 int hash = pdp_tidhash(tid);
180 struct pdp_t *pdp2;
181 struct pdp_t *pdp_prev = NULL;
182 if (PDP_DEBUG) printf("Begin pdp_tidset tid = %llx\n", tid);
jjakob88f6162003-01-05 18:09:07 +0000183 pdp->tidnext = NULL;
jjako52c24142002-12-16 13:33:51 +0000184 pdp->tid = tid;
185 for (pdp2 = hashtid[hash]; pdp2; pdp2 = pdp2->tidnext)
186 pdp_prev = pdp2;
187 if (!pdp_prev)
188 hashtid[hash] = pdp;
189 else
190 pdp_prev->tidnext = pdp;
191 if (PDP_DEBUG) printf("End pdp_tidset\n");
192 return 0;
193}
194
195int pdp_tiddel(struct pdp_t *pdp) {
196 int hash = pdp_tidhash(pdp->tid);
197 struct pdp_t *pdp2;
198 struct pdp_t *pdp_prev = NULL;
199 if (PDP_DEBUG) printf("Begin pdp_tiddel tid = %llx\n", pdp->tid);
200 for (pdp2 = hashtid[hash]; pdp2; pdp2 = pdp2->tidnext) {
201 if (pdp2 == pdp) {
202 if (!pdp_prev)
203 hashtid[hash] = pdp2->tidnext;
204 else
205 pdp_prev->tidnext = pdp2->tidnext;
jjakob88f6162003-01-05 18:09:07 +0000206 if (PDP_DEBUG) printf("End pdp_tiddel: PDP found\n");
jjako52c24142002-12-16 13:33:51 +0000207 return 0;
208 }
209 pdp_prev = pdp2;
210 }
jjakob88f6162003-01-05 18:09:07 +0000211 if (PDP_DEBUG) printf("End pdp_tiddel: PDP not found\n");
jjako52c24142002-12-16 13:33:51 +0000212 return EOF; /* End of linked list and not found */
213}
214
215int pdp_tidget(struct pdp_t **pdp, uint64_t tid) {
216 int hash = pdp_tidhash(tid);
217 struct pdp_t *pdp2;
218 if (PDP_DEBUG) printf("Begin pdp_tidget tid = %llx\n", tid);
219 for (pdp2 = hashtid[hash]; pdp2; pdp2 = pdp2->tidnext) {
220 if (pdp2->tid == tid) {
221 *pdp = pdp2;
222 if (PDP_DEBUG) printf("Begin pdp_tidget. Found\n");
223 return 0;
224 }
225 }
226 if (PDP_DEBUG) printf("Begin pdp_tidget. Not found\n");
227 return EOF; /* End of linked list and not found */
228}
229
jjako08d331d2003-10-13 20:33:30 +0000230int pdp_getimsi(struct pdp_t **pdp, uint64_t imsi, uint8_t nsapi) {
231 return pdp_tidget(pdp,
232 (imsi & 0x0fffffffffffffff) + ((uint64_t)nsapi << 60));
233}
234
jjakoa7cd2492003-04-11 09:40:12 +0000235/*
jjako52c24142002-12-16 13:33:51 +0000236int pdp_iphash(void* ipif, struct ul66_t *eua) {
jjakoa7cd2492003-04-11 09:40:12 +0000237 /#printf("IPhash %ld\n", lookup(eua->v, eua->l, ipif) % PDP_MAX);#/
jjako52c24142002-12-16 13:33:51 +0000238 return (lookup(eua->v, eua->l, ipif) % PDP_MAX);
239}
240
241int pdp_ipset(struct pdp_t *pdp, void* ipif, struct ul66_t *eua) {
242 int hash;
243 struct pdp_t *pdp2;
244 struct pdp_t *pdp_prev = NULL;
245
246 if (PDP_DEBUG) printf("Begin pdp_ipset %d %d %2x%2x%2x%2x\n",
247 (unsigned) ipif, eua->l,
248 eua->v[2], eua->v[3],
249 eua->v[4], eua->v[5]);
250
jjakob88f6162003-01-05 18:09:07 +0000251 pdp->ipnext = NULL;
jjako52c24142002-12-16 13:33:51 +0000252 pdp->ipif = ipif;
253 pdp->eua.l = eua->l;
254 memcpy(pdp->eua.v, eua->v, eua->l);
255
256 hash = pdp_iphash(pdp->ipif, &pdp->eua);
257
258 for (pdp2 = haship[hash]; pdp2; pdp2 = pdp2->ipnext)
259 pdp_prev = pdp2;
260 if (!pdp_prev)
261 haship[hash] = pdp;
262 else
263 pdp_prev->ipnext = pdp;
264 if (PDP_DEBUG) printf("End pdp_ipset\n");
265 return 0;
266}
267
268int pdp_ipdel(struct pdp_t *pdp) {
269 int hash = pdp_iphash(pdp->ipif, &pdp->eua);
270 struct pdp_t *pdp2;
271 struct pdp_t *pdp_prev = NULL;
272 if (PDP_DEBUG) printf("Begin pdp_ipdel\n");
273 for (pdp2 = haship[hash]; pdp2; pdp2 = pdp2->ipnext) {
274 if (pdp2 == pdp) {
275 if (!pdp_prev)
276 haship[hash] = pdp2->ipnext;
277 else
278 pdp_prev->ipnext = pdp2->ipnext;
279 if (PDP_DEBUG) printf("End pdp_ipdel: PDP found\n");
280 return 0;
281 }
282 pdp_prev = pdp2;
283 }
284 if (PDP_DEBUG) printf("End pdp_ipdel: PDP not found\n");
jjakoa7cd2492003-04-11 09:40:12 +0000285 return EOF; /# End of linked list and not found #/
jjako52c24142002-12-16 13:33:51 +0000286}
287
288int pdp_ipget(struct pdp_t **pdp, void* ipif, struct ul66_t *eua) {
289 int hash = pdp_iphash(ipif, eua);
290 struct pdp_t *pdp2;
jjakoa7cd2492003-04-11 09:40:12 +0000291 /#printf("Begin pdp_ipget %d %d %2x%2x%2x%2x\n", (unsigned)ipif, eua->l,
292 eua->v[2],eua->v[3],eua->v[4],eua->v[5]);#/
jjako52c24142002-12-16 13:33:51 +0000293 for (pdp2 = haship[hash]; pdp2; pdp2 = pdp2->ipnext) {
294 if ((pdp2->ipif == ipif) && (pdp2->eua.l == eua->l) &&
295 (memcmp(&pdp2->eua.v, &eua->v, eua->l) == 0)) {
296 *pdp = pdp2;
jjakoa7cd2492003-04-11 09:40:12 +0000297 /#printf("End pdp_ipget. Found\n");#/
jjako52c24142002-12-16 13:33:51 +0000298 return 0;
299 }
300 }
301 if (PDP_DEBUG) printf("End pdp_ipget Notfound %d %d %2x%2x%2x%2x\n",
302 (unsigned)ipif, eua->l, eua->v[2],eua->v[3],eua->v[4],eua->v[5]);
jjakoa7cd2492003-04-11 09:40:12 +0000303 return EOF; /# End of linked list and not found #/
jjako52c24142002-12-16 13:33:51 +0000304}
jjakoa7cd2492003-04-11 09:40:12 +0000305*/
jjako52c24142002-12-16 13:33:51 +0000306/* Various conversion functions */
307
308int pdp_ntoeua(struct in_addr *src, struct ul66_t *eua) {
309 eua->l=6;
310 eua->v[0]=0xf1; /* IETF */
311 eua->v[1]=0x21; /* IPv4 */
312 memcpy(&eua->v[2], src, 4); /* Copy a 4 byte address */
313 return 0;
314}
315
jjakoa7cd2492003-04-11 09:40:12 +0000316int pdp_euaton(struct ul66_t *eua, struct in_addr *dst) {
317 if((eua->l!=6) || (eua->v[0]!=0xf1) || (eua->v[1]!=0x21)) {
318 return EOF;
319 }
320 memcpy(dst, &eua->v[2], 4); /* Copy a 4 byte address */
321 return 0;
322}
323
jjako52c24142002-12-16 13:33:51 +0000324uint64_t pdp_gettid(uint64_t imsi, uint8_t nsapi) {
325 return (imsi & 0x0fffffffffffffff) + ((uint64_t)nsapi << 60);
326}
327
328int ulcpy(void* dst, void* src, size_t size) {
329 if (((struct ul255_t*)src)->l <= size) {
330 ((struct ul255_t*)dst)->l = ((struct ul255_t*)src)->l;
331 memcpy(((struct ul255_t*)dst)->v, ((struct ul255_t*)src)->v,
332 ((struct ul255_t*)dst)->l);
333 return 0;
334 }
335 else return EOF;
336}