blob: dc21bf8ae459a51d52bd04e2992f47253844217a [file] [log] [blame]
jjako52c24142002-12-16 13:33:51 +00001/*
2 * OpenGGSN - Gateway GPRS Support Node
jjako0fe0df02004-09-17 11:30:40 +00003 * Copyright (C) 2002, 2003, 2004 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 *
jjako52c24142002-12-16 13:33:51 +000010 */
11
12/*
13 * pdp.c:
14 *
15 */
16
jjako0fe0df02004-09-17 11:30:40 +000017#include <../config.h>
18
19#ifdef HAVE_STDINT_H
20#include <stdint.h>
21#endif
22
jjako52c24142002-12-16 13:33:51 +000023#include <stdio.h>
24#include <sys/types.h>
25#include <netinet/in.h>
26#include <string.h>
27#include "pdp.h"
28#include "lookupa.h"
29
30/* ***********************************************************
31 * Global variables TODO: most should be moved to gsn_t
32 *************************************************************/
33
Holger Hans Peter Freytherd7566b82012-11-06 14:17:45 +010034static struct pdp_t pdpa[PDP_MAX]; /* PDP storage */
35static struct pdp_t *hashtid[PDP_MAX]; /* Hash table for IMSI + NSAPI */
jjakoa7cd2492003-04-11 09:40:12 +000036/* struct pdp_t* haship[PDP_MAX]; Hash table for IP and network interface */
jjako52c24142002-12-16 13:33:51 +000037
38/* ***********************************************************
39 * Functions related to PDP storage
40 *
41 * Lifecycle
42 * For a GGSN pdp context life begins with the reception of a
43 * create pdp context request. It normally ends with the reception
44 * of a delete pdp context request, but will also end with the
45 * reception of an error indication message.
46 * Provisions should probably be made for terminating pdp contexts
47 * based on either idle timeout, or by sending downlink probe
48 * messages (ping?) to see if the MS is still responding.
49 *
50 * For an SGSN pdp context life begins with the application just
51 * before sending off a create pdp context request. It normally
52 * ends when a delete pdp context response message is received
53 * from the GGSN, but should also end when with the reception of
54 * an error indication message.
55 *
56 *
57 * HASH Tables
58 *
59 * Downlink packets received in the GGSN are identified only by their
60 * network interface together with their destination IP address (Two
61 * network interfaces can use the same private IP address). Each IMSI
62 * (mobile station) can have several PDP contexts using the same IP
63 * address. In this case the traffic flow template (TFT) is used to
64 * determine the correct PDP context for a particular IMSI. Also it
65 * should be possible for each PDP context to use several IP adresses
66 * For fixed wireless access a mobile station might need a full class
67 * C network. Even in the case of several IP adresses the PDP context
68 * should be determined on the basis of the network IP address.
69 * Thus we need a hash table based on network interface + IP address.
70 *
71 * Uplink packets are for GTP0 identified by their IMSI and NSAPI, which
72 * is collectively called the tunnel identifier. There is also a 16 bit
73 * flow label that can be used for identification of uplink packets. This
74 * however is quite useless as it limits the number of contexts to 65536.
75 * For GTP1 uplink packets are identified by a Tunnel Endpoint Identifier
76 * (32 bit), or in some cases by the combination of IMSI and NSAPI.
77 * For GTP1 delete context requests there is a need to find the PDP
78 * contexts with the same IP address. This however can be done by using
79 * the IP hash table.
80 * Thus we need a hash table based on TID (IMSI and NSAPI). The TEID will
81 * be used for directly addressing the PDP context.
82
83 * pdp_newpdp
84 * Gives you a pdp context with no hash references In some way
85 * this should have a limited lifetime.
86 *
87 * pdp_freepdp
88 * Frees a context that was previously allocated with
89 * pdp_newpdp
90 *
91 *
92 * pdp_getpdpIP
93 * An incoming IP packet is uniquely identified by a pointer
94 * to a network connection (void *) and an IP address
95 * (struct in_addr)
96 *
97 * pdp_getpdpGTP
98 * An incoming GTP packet is uniquely identified by a the
99 * TID (imsi + nsapi (8 octets)) in or by the Flow Label
100 * (2 octets) in gtp0 or by the Tunnel Endpoint Identifier
101 * (4 octets) in gtp1.
102 *
103 * This leads to an architecture where the receiving GSN
104 * chooses a Flow Label or a Tunnel Endpoint Identifier
105 * when the connection is setup.
106 * Thus no hash table is needed for GTP lookups.
107 *
108 *************************************************************/
109
Harald Weltebed35df2011-11-02 13:06:18 +0100110int pdp_init()
111{
112 memset(&pdpa, 0, sizeof(pdpa));
113 memset(&hashtid, 0, sizeof(hashtid));
114 /* memset(&haship, 0, sizeof(haship)); */
jjako52c24142002-12-16 13:33:51 +0000115
Harald Weltebed35df2011-11-02 13:06:18 +0100116 return 0;
jjako52c24142002-12-16 13:33:51 +0000117}
118
Harald Weltebed35df2011-11-02 13:06:18 +0100119int pdp_newpdp(struct pdp_t **pdp, uint64_t imsi, uint8_t nsapi,
120 struct pdp_t *pdp_old)
121{
122 int n;
123 for (n = 0; n < PDP_MAX; n++) { /* TODO: Need to do better than linear search */
124 if (pdpa[n].inuse == 0) {
125 *pdp = &pdpa[n];
126 if (NULL != pdp_old)
127 memcpy(*pdp, pdp_old, sizeof(struct pdp_t));
128 else
129 memset(*pdp, 0, sizeof(struct pdp_t));
130 (*pdp)->inuse = 1;
131 (*pdp)->imsi = imsi;
132 (*pdp)->nsapi = nsapi;
133 (*pdp)->fllc = (uint16_t) n + 1;
134 (*pdp)->fllu = (uint16_t) n + 1;
135 (*pdp)->teid_own = (uint32_t) n + 1;
136 if (!(*pdp)->secondary)
137 (*pdp)->teic_own = (uint32_t) n + 1;
138 pdp_tidset(*pdp, pdp_gettid(imsi, nsapi));
139
140 /* Insert reference in primary context */
141 if (((*pdp)->teic_own > 0)
142 && ((*pdp)->teic_own <= PDP_MAX)) {
143 pdpa[(*pdp)->teic_own -
144 1].secondary_tei[(*pdp)->nsapi & 0x0f] =
145 (*pdp)->teid_own;
146 }
147
148 return 0;
149 }
150 }
151 return EOF; /* No more available */
jjako52c24142002-12-16 13:33:51 +0000152}
153
Harald Weltebed35df2011-11-02 13:06:18 +0100154int pdp_freepdp(struct pdp_t *pdp)
155{
156 pdp_tiddel(pdp);
jjako2c381332003-10-21 19:09:53 +0000157
Harald Weltebed35df2011-11-02 13:06:18 +0100158 /* Remove any references in primary context */
159 if ((pdp->secondary) && (pdp->teic_own > 0)
160 && (pdp->teic_own <= PDP_MAX)) {
161 pdpa[pdp->teic_own - 1].secondary_tei[pdp->nsapi & 0x0f] = 0;
162 }
jjako2c381332003-10-21 19:09:53 +0000163
Harald Weltebed35df2011-11-02 13:06:18 +0100164 memset(pdp, 0, sizeof(struct pdp_t));
165 return 0;
jjako52c24142002-12-16 13:33:51 +0000166}
167
Harald Weltebed35df2011-11-02 13:06:18 +0100168int pdp_getpdp(struct pdp_t **pdp)
169{
170 *pdp = &pdpa[0];
171 return 0;
jjako52c24142002-12-16 13:33:51 +0000172}
173
Harald Weltebed35df2011-11-02 13:06:18 +0100174int pdp_getgtp0(struct pdp_t **pdp, uint16_t fl)
175{
176 if ((fl > PDP_MAX) || (fl < 1)) {
177 return EOF; /* Not found */
178 } else {
179 *pdp = &pdpa[fl - 1];
180 if ((*pdp)->inuse)
181 return 0;
182 else
183 return EOF;
184 /* Context exists. We do no further validity checking. */
185 }
jjako52c24142002-12-16 13:33:51 +0000186}
187
Harald Weltebed35df2011-11-02 13:06:18 +0100188int pdp_getgtp1(struct pdp_t **pdp, uint32_t tei)
189{
190 if ((tei > PDP_MAX) || (tei < 1)) {
191 return EOF; /* Not found */
192 } else {
193 *pdp = &pdpa[tei - 1];
194 if ((*pdp)->inuse)
195 return 0;
196 else
197 return EOF;
198 /* Context exists. We do no further validity checking. */
199 }
jjako52c24142002-12-16 13:33:51 +0000200}
201
Harald Weltebed35df2011-11-02 13:06:18 +0100202int pdp_tidhash(uint64_t tid)
203{
204 return (lookup(&tid, sizeof(tid), 0) % PDP_MAX);
jjako52c24142002-12-16 13:33:51 +0000205}
206
Harald Weltebed35df2011-11-02 13:06:18 +0100207int pdp_tidset(struct pdp_t *pdp, uint64_t tid)
208{
209 int hash = pdp_tidhash(tid);
210 struct pdp_t *pdp2;
211 struct pdp_t *pdp_prev = NULL;
212 if (PDP_DEBUG)
213 printf("Begin pdp_tidset tid = %llx\n", tid);
214 pdp->tidnext = NULL;
215 pdp->tid = tid;
216 for (pdp2 = hashtid[hash]; pdp2; pdp2 = pdp2->tidnext)
217 pdp_prev = pdp2;
218 if (!pdp_prev)
219 hashtid[hash] = pdp;
220 else
221 pdp_prev->tidnext = pdp;
222 if (PDP_DEBUG)
223 printf("End pdp_tidset\n");
224 return 0;
jjako52c24142002-12-16 13:33:51 +0000225}
226
Harald Weltebed35df2011-11-02 13:06:18 +0100227int pdp_tiddel(struct pdp_t *pdp)
228{
229 int hash = pdp_tidhash(pdp->tid);
230 struct pdp_t *pdp2;
231 struct pdp_t *pdp_prev = NULL;
232 if (PDP_DEBUG)
233 printf("Begin pdp_tiddel tid = %llx\n", pdp->tid);
234 for (pdp2 = hashtid[hash]; pdp2; pdp2 = pdp2->tidnext) {
235 if (pdp2 == pdp) {
236 if (!pdp_prev)
237 hashtid[hash] = pdp2->tidnext;
238 else
239 pdp_prev->tidnext = pdp2->tidnext;
240 if (PDP_DEBUG)
241 printf("End pdp_tiddel: PDP found\n");
242 return 0;
243 }
244 pdp_prev = pdp2;
245 }
246 if (PDP_DEBUG)
247 printf("End pdp_tiddel: PDP not found\n");
248 return EOF; /* End of linked list and not found */
jjako52c24142002-12-16 13:33:51 +0000249}
250
Harald Weltebed35df2011-11-02 13:06:18 +0100251int pdp_tidget(struct pdp_t **pdp, uint64_t tid)
252{
253 int hash = pdp_tidhash(tid);
254 struct pdp_t *pdp2;
255 if (PDP_DEBUG)
256 printf("Begin pdp_tidget tid = %llx\n", tid);
257 for (pdp2 = hashtid[hash]; pdp2; pdp2 = pdp2->tidnext) {
258 if (pdp2->tid == tid) {
259 *pdp = pdp2;
260 if (PDP_DEBUG)
261 printf("Begin pdp_tidget. Found\n");
262 return 0;
263 }
264 }
265 if (PDP_DEBUG)
266 printf("Begin pdp_tidget. Not found\n");
267 return EOF; /* End of linked list and not found */
jjako52c24142002-12-16 13:33:51 +0000268}
269
Harald Weltebed35df2011-11-02 13:06:18 +0100270int pdp_getimsi(struct pdp_t **pdp, uint64_t imsi, uint8_t nsapi)
271{
272 return pdp_tidget(pdp,
273 (imsi & 0x0fffffffffffffffull) +
274 ((uint64_t) nsapi << 60));
jjako08d331d2003-10-13 20:33:30 +0000275}
276
jjakoa7cd2492003-04-11 09:40:12 +0000277/*
jjako52c24142002-12-16 13:33:51 +0000278int pdp_iphash(void* ipif, struct ul66_t *eua) {
jjakoa7cd2492003-04-11 09:40:12 +0000279 /#printf("IPhash %ld\n", lookup(eua->v, eua->l, ipif) % PDP_MAX);#/
jjako52c24142002-12-16 13:33:51 +0000280 return (lookup(eua->v, eua->l, ipif) % PDP_MAX);
281}
282
283int pdp_ipset(struct pdp_t *pdp, void* ipif, struct ul66_t *eua) {
284 int hash;
285 struct pdp_t *pdp2;
286 struct pdp_t *pdp_prev = NULL;
287
288 if (PDP_DEBUG) printf("Begin pdp_ipset %d %d %2x%2x%2x%2x\n",
289 (unsigned) ipif, eua->l,
290 eua->v[2], eua->v[3],
291 eua->v[4], eua->v[5]);
292
jjakob88f6162003-01-05 18:09:07 +0000293 pdp->ipnext = NULL;
jjako52c24142002-12-16 13:33:51 +0000294 pdp->ipif = ipif;
295 pdp->eua.l = eua->l;
296 memcpy(pdp->eua.v, eua->v, eua->l);
297
298 hash = pdp_iphash(pdp->ipif, &pdp->eua);
299
300 for (pdp2 = haship[hash]; pdp2; pdp2 = pdp2->ipnext)
301 pdp_prev = pdp2;
302 if (!pdp_prev)
303 haship[hash] = pdp;
304 else
305 pdp_prev->ipnext = pdp;
306 if (PDP_DEBUG) printf("End pdp_ipset\n");
307 return 0;
308}
309
310int pdp_ipdel(struct pdp_t *pdp) {
311 int hash = pdp_iphash(pdp->ipif, &pdp->eua);
312 struct pdp_t *pdp2;
313 struct pdp_t *pdp_prev = NULL;
314 if (PDP_DEBUG) printf("Begin pdp_ipdel\n");
315 for (pdp2 = haship[hash]; pdp2; pdp2 = pdp2->ipnext) {
316 if (pdp2 == pdp) {
317 if (!pdp_prev)
318 haship[hash] = pdp2->ipnext;
319 else
320 pdp_prev->ipnext = pdp2->ipnext;
321 if (PDP_DEBUG) printf("End pdp_ipdel: PDP found\n");
322 return 0;
323 }
324 pdp_prev = pdp2;
325 }
326 if (PDP_DEBUG) printf("End pdp_ipdel: PDP not found\n");
jjakoa7cd2492003-04-11 09:40:12 +0000327 return EOF; /# End of linked list and not found #/
jjako52c24142002-12-16 13:33:51 +0000328}
329
330int pdp_ipget(struct pdp_t **pdp, void* ipif, struct ul66_t *eua) {
331 int hash = pdp_iphash(ipif, eua);
332 struct pdp_t *pdp2;
jjakoa7cd2492003-04-11 09:40:12 +0000333 /#printf("Begin pdp_ipget %d %d %2x%2x%2x%2x\n", (unsigned)ipif, eua->l,
334 eua->v[2],eua->v[3],eua->v[4],eua->v[5]);#/
jjako52c24142002-12-16 13:33:51 +0000335 for (pdp2 = haship[hash]; pdp2; pdp2 = pdp2->ipnext) {
336 if ((pdp2->ipif == ipif) && (pdp2->eua.l == eua->l) &&
337 (memcmp(&pdp2->eua.v, &eua->v, eua->l) == 0)) {
338 *pdp = pdp2;
jjakoa7cd2492003-04-11 09:40:12 +0000339 /#printf("End pdp_ipget. Found\n");#/
jjako52c24142002-12-16 13:33:51 +0000340 return 0;
341 }
342 }
343 if (PDP_DEBUG) printf("End pdp_ipget Notfound %d %d %2x%2x%2x%2x\n",
344 (unsigned)ipif, eua->l, eua->v[2],eua->v[3],eua->v[4],eua->v[5]);
jjakoa7cd2492003-04-11 09:40:12 +0000345 return EOF; /# End of linked list and not found #/
jjako52c24142002-12-16 13:33:51 +0000346}
jjakoa7cd2492003-04-11 09:40:12 +0000347*/
jjako52c24142002-12-16 13:33:51 +0000348/* Various conversion functions */
349
Harald Weltebed35df2011-11-02 13:06:18 +0100350int pdp_ntoeua(struct in_addr *src, struct ul66_t *eua)
351{
352 eua->l = 6;
353 eua->v[0] = 0xf1; /* IETF */
354 eua->v[1] = 0x21; /* IPv4 */
355 memcpy(&eua->v[2], src, 4); /* Copy a 4 byte address */
356 return 0;
jjako52c24142002-12-16 13:33:51 +0000357}
358
Harald Weltebed35df2011-11-02 13:06:18 +0100359int pdp_euaton(struct ul66_t *eua, struct in_addr *dst)
360{
361 if ((eua->l != 6) || (eua->v[0] != 0xf1) || (eua->v[1] != 0x21)) {
362 return EOF;
363 }
364 memcpy(dst, &eua->v[2], 4); /* Copy a 4 byte address */
365 return 0;
jjakoa7cd2492003-04-11 09:40:12 +0000366}
367
Harald Weltebed35df2011-11-02 13:06:18 +0100368uint64_t pdp_gettid(uint64_t imsi, uint8_t nsapi)
369{
370 return (imsi & 0x0fffffffffffffffull) + ((uint64_t) nsapi << 60);
jjako52c24142002-12-16 13:33:51 +0000371}
372
Pablo Neira Ayuso746b9442014-03-24 17:58:27 +0100373void pdp_set_imsi_nsapi(struct pdp_t *pdp, uint64_t teid)
374{
375 pdp->imsi = teid & 0x0fffffffffffffffull;
376 pdp->nsapi = (teid & 0xf000000000000000ull) >> 60;
377}
378
Harald Weltebed35df2011-11-02 13:06:18 +0100379int ulcpy(void *dst, void *src, size_t size)
380{
381 if (((struct ul255_t *)src)->l <= size) {
382 ((struct ul255_t *)dst)->l = ((struct ul255_t *)src)->l;
383 memcpy(((struct ul255_t *)dst)->v, ((struct ul255_t *)src)->v,
384 ((struct ul255_t *)dst)->l);
385 return 0;
386 } else
387 return EOF;
jjako52c24142002-12-16 13:33:51 +0000388}