blob: 648d70d987772870256d8be1f908fc68cb37a494 [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
34struct pdp_t pdpa[PDP_MAX]; /* PDP storage */
35struct 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
110int pdp_init() {
111 memset(&pdpa, 0, sizeof(pdpa));
112 memset(&hashtid, 0, sizeof(hashtid));
jjakoa7cd2492003-04-11 09:40:12 +0000113 /* memset(&haship, 0, sizeof(haship)); */
jjako52c24142002-12-16 13:33:51 +0000114
115 return 0;
116}
117
118int pdp_newpdp(struct pdp_t **pdp, uint64_t imsi, uint8_t nsapi,
119 struct pdp_t *pdp_old){
120 int n;
121 for (n=0; n<PDP_MAX; n++) { /* TODO: Need to do better than linear search */
122 if (pdpa[n].inuse == 0) {
123 *pdp = &pdpa[n];
124 if (NULL != pdp_old) memcpy(*pdp, pdp_old, sizeof(struct pdp_t));
125 else memset(*pdp, 0, sizeof(struct pdp_t));
126 (*pdp)->inuse = 1;
127 (*pdp)->imsi = imsi;
128 (*pdp)->nsapi = nsapi;
jjako2c381332003-10-21 19:09:53 +0000129 (*pdp)->fllc = (uint16_t) n + 1;
130 (*pdp)->fllu = (uint16_t) n + 1;
131 (*pdp)->teid_own = (uint32_t) n + 1;
132 if (!(*pdp)->secondary) (*pdp)->teic_own = (uint32_t) n + 1;
jjako52c24142002-12-16 13:33:51 +0000133 pdp_tidset(*pdp, pdp_gettid(imsi, nsapi));
jjako2c381332003-10-21 19:09:53 +0000134
135 /* Insert reference in primary context */
136 if (((*pdp)->teic_own > 0 ) && ((*pdp)->teic_own <= PDP_MAX)) {
137 pdpa[(*pdp)->teic_own-1].secondary_tei[(*pdp)->nsapi & 0x0f] =
138 (*pdp)->teid_own;
139 }
140
jjako52c24142002-12-16 13:33:51 +0000141 return 0;
142 }
143 }
144 return EOF; /* No more available */
145}
146
147int pdp_freepdp(struct pdp_t *pdp){
148 pdp_tiddel(pdp);
jjako2c381332003-10-21 19:09:53 +0000149
150 /* Remove any references in primary context */
151 if ((pdp->secondary) && (pdp->teic_own > 0 ) && (pdp->teic_own <= PDP_MAX)) {
152 pdpa[pdp->teic_own-1].secondary_tei[pdp->nsapi & 0x0f] = 0;
153 }
154
jjako52c24142002-12-16 13:33:51 +0000155 memset(pdp, 0, sizeof(struct pdp_t));
jjako52c24142002-12-16 13:33:51 +0000156 return 0;
157}
158
159int pdp_getpdp(struct pdp_t **pdp){
160 *pdp = &pdpa[0];
161 return 0;
162}
163
164int pdp_getgtp0(struct pdp_t **pdp, uint16_t fl){
jjako2c381332003-10-21 19:09:53 +0000165 if ((fl>PDP_MAX) || (fl<1)) {
jjako52c24142002-12-16 13:33:51 +0000166 return EOF; /* Not found */
167 }
168 else {
jjako2c381332003-10-21 19:09:53 +0000169 *pdp = &pdpa[fl-1];
jjako52c24142002-12-16 13:33:51 +0000170 if ((*pdp)->inuse) return 0;
171 else return EOF;
172 /* Context exists. We do no further validity checking. */
173 }
174}
175
jjako2c381332003-10-21 19:09:53 +0000176int pdp_getgtp1(struct pdp_t **pdp, uint32_t tei){
177 if ((tei>PDP_MAX) || (tei<1)) {
178 return EOF; /* Not found */
jjako52c24142002-12-16 13:33:51 +0000179 }
180 else {
jjako2c381332003-10-21 19:09:53 +0000181 *pdp = &pdpa[tei-1];
182 if ((*pdp)->inuse) return 0;
183 else return EOF;
184 /* Context exists. We do no further validity checking. */
jjako52c24142002-12-16 13:33:51 +0000185 }
186}
187
188
189int pdp_tidhash(uint64_t tid) {
190 return (lookup(&tid, sizeof(tid), 0) % PDP_MAX);
191}
192
193int pdp_tidset(struct pdp_t *pdp, uint64_t tid) {
194 int hash = pdp_tidhash(tid);
195 struct pdp_t *pdp2;
196 struct pdp_t *pdp_prev = NULL;
197 if (PDP_DEBUG) printf("Begin pdp_tidset tid = %llx\n", tid);
jjakob88f6162003-01-05 18:09:07 +0000198 pdp->tidnext = NULL;
jjako52c24142002-12-16 13:33:51 +0000199 pdp->tid = tid;
200 for (pdp2 = hashtid[hash]; pdp2; pdp2 = pdp2->tidnext)
201 pdp_prev = pdp2;
202 if (!pdp_prev)
203 hashtid[hash] = pdp;
204 else
205 pdp_prev->tidnext = pdp;
206 if (PDP_DEBUG) printf("End pdp_tidset\n");
207 return 0;
208}
209
210int pdp_tiddel(struct pdp_t *pdp) {
211 int hash = pdp_tidhash(pdp->tid);
212 struct pdp_t *pdp2;
213 struct pdp_t *pdp_prev = NULL;
214 if (PDP_DEBUG) printf("Begin pdp_tiddel tid = %llx\n", pdp->tid);
215 for (pdp2 = hashtid[hash]; pdp2; pdp2 = pdp2->tidnext) {
216 if (pdp2 == pdp) {
217 if (!pdp_prev)
218 hashtid[hash] = pdp2->tidnext;
219 else
220 pdp_prev->tidnext = pdp2->tidnext;
jjakob88f6162003-01-05 18:09:07 +0000221 if (PDP_DEBUG) printf("End pdp_tiddel: PDP found\n");
jjako52c24142002-12-16 13:33:51 +0000222 return 0;
223 }
224 pdp_prev = pdp2;
225 }
jjakob88f6162003-01-05 18:09:07 +0000226 if (PDP_DEBUG) printf("End pdp_tiddel: PDP not found\n");
jjako52c24142002-12-16 13:33:51 +0000227 return EOF; /* End of linked list and not found */
228}
229
230int pdp_tidget(struct pdp_t **pdp, uint64_t tid) {
231 int hash = pdp_tidhash(tid);
232 struct pdp_t *pdp2;
233 if (PDP_DEBUG) printf("Begin pdp_tidget tid = %llx\n", tid);
234 for (pdp2 = hashtid[hash]; pdp2; pdp2 = pdp2->tidnext) {
235 if (pdp2->tid == tid) {
236 *pdp = pdp2;
237 if (PDP_DEBUG) printf("Begin pdp_tidget. Found\n");
238 return 0;
239 }
240 }
241 if (PDP_DEBUG) printf("Begin pdp_tidget. Not found\n");
242 return EOF; /* End of linked list and not found */
243}
244
jjako08d331d2003-10-13 20:33:30 +0000245int pdp_getimsi(struct pdp_t **pdp, uint64_t imsi, uint8_t nsapi) {
246 return pdp_tidget(pdp,
jjako1ea66342004-01-28 09:27:34 +0000247 (imsi & 0x0fffffffffffffffull) + ((uint64_t)nsapi << 60));
jjako08d331d2003-10-13 20:33:30 +0000248}
249
jjakoa7cd2492003-04-11 09:40:12 +0000250/*
jjako52c24142002-12-16 13:33:51 +0000251int pdp_iphash(void* ipif, struct ul66_t *eua) {
jjakoa7cd2492003-04-11 09:40:12 +0000252 /#printf("IPhash %ld\n", lookup(eua->v, eua->l, ipif) % PDP_MAX);#/
jjako52c24142002-12-16 13:33:51 +0000253 return (lookup(eua->v, eua->l, ipif) % PDP_MAX);
254}
255
256int pdp_ipset(struct pdp_t *pdp, void* ipif, struct ul66_t *eua) {
257 int hash;
258 struct pdp_t *pdp2;
259 struct pdp_t *pdp_prev = NULL;
260
261 if (PDP_DEBUG) printf("Begin pdp_ipset %d %d %2x%2x%2x%2x\n",
262 (unsigned) ipif, eua->l,
263 eua->v[2], eua->v[3],
264 eua->v[4], eua->v[5]);
265
jjakob88f6162003-01-05 18:09:07 +0000266 pdp->ipnext = NULL;
jjako52c24142002-12-16 13:33:51 +0000267 pdp->ipif = ipif;
268 pdp->eua.l = eua->l;
269 memcpy(pdp->eua.v, eua->v, eua->l);
270
271 hash = pdp_iphash(pdp->ipif, &pdp->eua);
272
273 for (pdp2 = haship[hash]; pdp2; pdp2 = pdp2->ipnext)
274 pdp_prev = pdp2;
275 if (!pdp_prev)
276 haship[hash] = pdp;
277 else
278 pdp_prev->ipnext = pdp;
279 if (PDP_DEBUG) printf("End pdp_ipset\n");
280 return 0;
281}
282
283int pdp_ipdel(struct pdp_t *pdp) {
284 int hash = pdp_iphash(pdp->ipif, &pdp->eua);
285 struct pdp_t *pdp2;
286 struct pdp_t *pdp_prev = NULL;
287 if (PDP_DEBUG) printf("Begin pdp_ipdel\n");
288 for (pdp2 = haship[hash]; pdp2; pdp2 = pdp2->ipnext) {
289 if (pdp2 == pdp) {
290 if (!pdp_prev)
291 haship[hash] = pdp2->ipnext;
292 else
293 pdp_prev->ipnext = pdp2->ipnext;
294 if (PDP_DEBUG) printf("End pdp_ipdel: PDP found\n");
295 return 0;
296 }
297 pdp_prev = pdp2;
298 }
299 if (PDP_DEBUG) printf("End pdp_ipdel: PDP not found\n");
jjakoa7cd2492003-04-11 09:40:12 +0000300 return EOF; /# End of linked list and not found #/
jjako52c24142002-12-16 13:33:51 +0000301}
302
303int pdp_ipget(struct pdp_t **pdp, void* ipif, struct ul66_t *eua) {
304 int hash = pdp_iphash(ipif, eua);
305 struct pdp_t *pdp2;
jjakoa7cd2492003-04-11 09:40:12 +0000306 /#printf("Begin pdp_ipget %d %d %2x%2x%2x%2x\n", (unsigned)ipif, eua->l,
307 eua->v[2],eua->v[3],eua->v[4],eua->v[5]);#/
jjako52c24142002-12-16 13:33:51 +0000308 for (pdp2 = haship[hash]; pdp2; pdp2 = pdp2->ipnext) {
309 if ((pdp2->ipif == ipif) && (pdp2->eua.l == eua->l) &&
310 (memcmp(&pdp2->eua.v, &eua->v, eua->l) == 0)) {
311 *pdp = pdp2;
jjakoa7cd2492003-04-11 09:40:12 +0000312 /#printf("End pdp_ipget. Found\n");#/
jjako52c24142002-12-16 13:33:51 +0000313 return 0;
314 }
315 }
316 if (PDP_DEBUG) printf("End pdp_ipget Notfound %d %d %2x%2x%2x%2x\n",
317 (unsigned)ipif, eua->l, eua->v[2],eua->v[3],eua->v[4],eua->v[5]);
jjakoa7cd2492003-04-11 09:40:12 +0000318 return EOF; /# End of linked list and not found #/
jjako52c24142002-12-16 13:33:51 +0000319}
jjakoa7cd2492003-04-11 09:40:12 +0000320*/
jjako52c24142002-12-16 13:33:51 +0000321/* Various conversion functions */
322
323int pdp_ntoeua(struct in_addr *src, struct ul66_t *eua) {
324 eua->l=6;
325 eua->v[0]=0xf1; /* IETF */
326 eua->v[1]=0x21; /* IPv4 */
327 memcpy(&eua->v[2], src, 4); /* Copy a 4 byte address */
328 return 0;
329}
330
jjakoa7cd2492003-04-11 09:40:12 +0000331int pdp_euaton(struct ul66_t *eua, struct in_addr *dst) {
332 if((eua->l!=6) || (eua->v[0]!=0xf1) || (eua->v[1]!=0x21)) {
333 return EOF;
334 }
335 memcpy(dst, &eua->v[2], 4); /* Copy a 4 byte address */
336 return 0;
337}
338
jjako52c24142002-12-16 13:33:51 +0000339uint64_t pdp_gettid(uint64_t imsi, uint8_t nsapi) {
jjako1ea66342004-01-28 09:27:34 +0000340 return (imsi & 0x0fffffffffffffffull) + ((uint64_t)nsapi << 60);
jjako52c24142002-12-16 13:33:51 +0000341}
342
343int ulcpy(void* dst, void* src, size_t size) {
344 if (((struct ul255_t*)src)->l <= size) {
345 ((struct ul255_t*)dst)->l = ((struct ul255_t*)src)->l;
346 memcpy(((struct ul255_t*)dst)->v, ((struct ul255_t*)src)->v,
347 ((struct ul255_t*)dst)->l);
348 return 0;
349 }
350 else return EOF;
351}