blob: 80370a5e2213d4474210a340b36104aba216bf98 [file] [log] [blame]
jjako52c24142002-12-16 13:33:51 +00001/*
2 * OpenGGSN - Gateway GPRS Support Node
3 * Copyright (C) 2002 Mondru AB.
4 *
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 * gtpie.c: Contains functions to encapsulate and decapsulate GTP
14 * information elements
15 *
16 *
17 * Encapsulation
18 * - gtpie_tlv, gtpie_tv0, gtpie_tv1, gtpie_tv2 ... Adds information
19 * elements to a buffer.
20 *
21 * Decapsulation
22 * - gtpie_decaps: Returns array with pointers to information elements.
23 * - getie_getie: Returns the pointer of a particular element.
24 * - gtpie_gettlv: Copies tlv information element. Return 0 on success.
25 * - gtpie_gettv: Copies tv information element. Return 0 on success.
26 *
27 */
28
jjako0fe0df02004-09-17 11:30:40 +000029#include <../config.h>
30
31#ifdef HAVE_STDINT_H
32#include <stdint.h>
33#endif
34
jjako52c24142002-12-16 13:33:51 +000035#include <stdio.h>
36#include <sys/types.h>
37#include <netinet/in.h>
38#include <string.h>
39
40#include "gtpie.h"
41
Harald Weltef54a1f42010-05-04 11:08:38 +020042int gtpie_tlv(void *p, unsigned int *length, unsigned int size, uint8_t t, int l, void *v) {
jjako52c24142002-12-16 13:33:51 +000043 if ((*length + 3 + l) >= size) return 1;
44 ((union gtpie_member*) (p + *length))->tlv.t = hton8(t);
45 ((union gtpie_member*) (p + *length))->tlv.l = hton16(l);
46 memcpy((void*) (p + *length +3), v, l);
47 *length += 3 + l;
48 return 0;
49}
50
Harald Weltef54a1f42010-05-04 11:08:38 +020051int gtpie_tv0(void *p, unsigned int *length, unsigned int size, uint8_t t, int l, uint8_t *v) {
jjako52c24142002-12-16 13:33:51 +000052 if ((*length + 1 + l) >= size) return 1;
53 ((union gtpie_member*) (p + *length))->tv0.t = hton8(t);
54 memcpy((void*) (p + *length +1), v, l);
55 *length += 1 + l;
56 return 0;
57}
58
Harald Weltef54a1f42010-05-04 11:08:38 +020059int gtpie_tv1(void *p, unsigned int *length, unsigned int size, uint8_t t, uint8_t v) {
jjako52c24142002-12-16 13:33:51 +000060 if ((*length + 2) >= size) return 1;
61 ((union gtpie_member*) (p + *length))->tv1.t = hton8(t);
62 ((union gtpie_member*) (p + *length))->tv1.v = hton8(v);
63 *length += 2;
64 return 0;
65}
66
Harald Weltef54a1f42010-05-04 11:08:38 +020067int gtpie_tv2(void *p, unsigned int *length, unsigned int size, uint8_t t, uint16_t v) {
jjako52c24142002-12-16 13:33:51 +000068 if ((*length + 3) >= size) return 1;
69 ((union gtpie_member*) (p + *length))->tv2.t = hton8(t);
70 ((union gtpie_member*) (p + *length))->tv2.v = hton16(v);
71 *length += 3;
72 return 0;
73}
74
Harald Weltef54a1f42010-05-04 11:08:38 +020075int gtpie_tv4(void *p, unsigned int *length, unsigned int size, uint8_t t, uint32_t v) {
jjako52c24142002-12-16 13:33:51 +000076 if ((*length + 5) >= size) return 1;
77 ((union gtpie_member*) (p + *length))->tv4.t = hton8(t);
78 ((union gtpie_member*) (p + *length))->tv4.v = hton32(v);
79 *length += 5;
80 return 0;
81}
82
Harald Weltef54a1f42010-05-04 11:08:38 +020083int gtpie_tv8(void *p, unsigned int *length, unsigned int size, uint8_t t, uint64_t v) {
jjako08d331d2003-10-13 20:33:30 +000084 if ((*length + 9) >= size) return 1;
85 ((union gtpie_member*) (p + *length))->tv8.t = hton8(t);
86 ((union gtpie_member*) (p + *length))->tv8.v = hton64(v);
87 *length += 9;
88 return 0;
89}
90
jjako52c24142002-12-16 13:33:51 +000091int gtpie_getie(union gtpie_member* ie[], int type, int instance) {
92 int j;
93 for (j=0; j< GTPIE_SIZE; j++) {
94 if ((ie[j] != 0) && (ie[j]->t == type)) {
95 if (instance-- == 0) return j;
96 }
97 }
98 return -1;
99}
100
101int gtpie_exist(union gtpie_member* ie[], int type, int instance) {
102 int j;
103 for (j=0; j< GTPIE_SIZE; j++) {
104 if ((ie[j] != 0) && (ie[j]->t == type)) {
105 if (instance-- == 0) return 1;
106 }
107 }
108 return 0;
109}
110
111int gtpie_gettlv(union gtpie_member* ie[], int type, int instance,
Harald Weltef54a1f42010-05-04 11:08:38 +0200112 unsigned int *length, void *dst, unsigned int size){
jjako52c24142002-12-16 13:33:51 +0000113 int ien;
114 ien = gtpie_getie(ie, type, instance);
115 if (ien>=0) {
116 *length = ntoh16(ie[ien]->tlv.l);
117 if (*length <= size)
118 memcpy(dst, ie[ien]->tlv.v, *length);
119 else
120 return EOF;
121 }
122 return 0;
123}
124
125int gtpie_gettv0(union gtpie_member* ie[], int type, int instance,
Harald Weltef54a1f42010-05-04 11:08:38 +0200126 void *dst, unsigned int size){
jjako52c24142002-12-16 13:33:51 +0000127 int ien;
128 ien = gtpie_getie(ie, type, instance);
129 if (ien>=0)
130 memcpy(dst, ie[ien]->tv0.v, size);
131 else
132 return EOF;
133 return 0;
134}
135
136int gtpie_gettv1(union gtpie_member* ie[], int type, int instance,
137 uint8_t *dst){
138 int ien;
139 ien = gtpie_getie(ie, type, instance);
140 if (ien>=0)
141 *dst = ntoh8(ie[ien]->tv1.v);
142 else
143 return EOF;
144 return 0;
145}
146
147int gtpie_gettv2(union gtpie_member* ie[], int type, int instance,
148 uint16_t *dst){
149 int ien;
150 ien = gtpie_getie(ie, type, instance);
151 if (ien>=0)
152 *dst = ntoh16(ie[ien]->tv2.v);
153 else
154 return EOF;
155 return 0;
156}
157
158int gtpie_gettv4(union gtpie_member* ie[], int type, int instance,
159 uint32_t *dst){
160 int ien;
161 ien = gtpie_getie(ie, type, instance);
162 if (ien>=0)
163 *dst = ntoh32(ie[ien]->tv4.v);
164 else
165 return EOF;
166 return 0;
167}
168
jjako08d331d2003-10-13 20:33:30 +0000169int gtpie_gettv8(union gtpie_member* ie[], int type, int instance,
170 uint64_t *dst){
171 int ien;
172 ien = gtpie_getie(ie, type, instance);
173 if (ien>=0)
174 *dst = ntoh64(ie[ien]->tv8.v);
175 else
176 return EOF;
177 return 0;
178}
179
180int gtpie_decaps(union gtpie_member* ie[], int version, void *pack, unsigned len) {
jjako52c24142002-12-16 13:33:51 +0000181 int i;
182 int j = 0;
183 unsigned char *p;
184 unsigned char *end;
185
186 end = (unsigned char*) pack + len;
187 p = pack;
188
Harald Weltea1bd7362010-05-16 00:35:39 +0200189 memset(ie, 0, sizeof(union gtpie_member *) * GTPIE_SIZE);
jjako52c24142002-12-16 13:33:51 +0000190
Harald Weltee67556e2010-05-04 10:59:23 +0200191 while ((p<end) && (j<GTPIE_SIZE)) {
jjako52c24142002-12-16 13:33:51 +0000192 if (GTPIE_DEBUG) {
193 printf("The packet looks like this:\n");
194 for( i=0; i<(end-p); i++) {
195 printf("%02x ", (unsigned char)*(char *)(p+i));
196 if (!((i+1)%16)) printf("\n");
197 };
jjako08d331d2003-10-13 20:33:30 +0000198 printf("\n");
jjako52c24142002-12-16 13:33:51 +0000199 }
jjako08d331d2003-10-13 20:33:30 +0000200
jjako52c24142002-12-16 13:33:51 +0000201 switch (*p) {
202 case GTPIE_CAUSE: /* TV GTPIE types with value length 1 */
203 case GTPIE_REORDER:
204 case GTPIE_MAP_CAUSE:
205 case GTPIE_MS_VALIDATED:
206 case GTPIE_RECOVERY:
207 case GTPIE_SELECTION_MODE:
208 case GTPIE_TEARDOWN:
209 case GTPIE_NSAPI:
210 case GTPIE_RANAP_CAUSE:
211 case GTPIE_RP_SMS:
212 case GTPIE_RP:
213 case GTPIE_MS_NOT_REACH:
214 if (j<GTPIE_SIZE) {
215 ie[j] = (union gtpie_member*) p;
216 if (GTPIE_DEBUG) printf("GTPIE TV1 found. Type %d, value %d\n",
jjako08d331d2003-10-13 20:33:30 +0000217 ie[j]->tv1.t, ie[j]->tv1.v);
jjako52c24142002-12-16 13:33:51 +0000218 p+= 1 + 1;
219 j++;
220 }
221 break;
jjako08d331d2003-10-13 20:33:30 +0000222 case GTPIE_FL_DI: /* TV GTPIE types with value length 2 or 4 */
jjako52c24142002-12-16 13:33:51 +0000223 case GTPIE_FL_C:
jjako08d331d2003-10-13 20:33:30 +0000224 if (version != 0) {
225 if (j<GTPIE_SIZE) { /* GTPIE_TEI_DI & GTPIE_TEI_C with length 4 */
226 /* case GTPIE_TEI_DI: gtp1 */
227 /* case GTPIE_TEI_C: gtp1 */
228 ie[j] = (union gtpie_member*) p;
229 if (GTPIE_DEBUG) printf("GTPIE TV 4 found. Type %d, value %d\n",
230 ie[j]->tv4.t, ie[j]->tv4.v);
231 p+= 1 + 4;
232 j++;
233 }
234 break;
235 }
236 case GTPIE_PFI: /* TV GTPIE types with value length 2 */
jjako52c24142002-12-16 13:33:51 +0000237 case GTPIE_CHARGING_C:
238 case GTPIE_TRACE_REF:
239 case GTPIE_TRACE_TYPE:
240 if (j<GTPIE_SIZE) {
241 ie[j] = (union gtpie_member*) p;
242 if (GTPIE_DEBUG) printf("GTPIE TV2 found. Type %d, value %d\n",
243 ie[j]->tv2.t, ie[j]->tv2.v);
244 p+= 1 + 2;
245 j++;
246 }
247 break;
248 case GTPIE_QOS_PROFILE0: /* TV GTPIE types with value length 3 */
249 case GTPIE_P_TMSI_S:
250 if (j<GTPIE_SIZE) {
251 ie[j] = (union gtpie_member*) p;
252 if (GTPIE_DEBUG) printf("GTPIE TV 3 found. Type %d, value %d, %d, %d\n",
253 ie[j]->tv0.t, ie[j]->tv0.v[0],
254 ie[j]->tv0.v[1], ie[j]->tv0.v[2]);
255 p+= 1 + 3;
256 j++;
257 }
258 break;
259 case GTPIE_TLLI: /* TV GTPIE types with value length 4 */
260 case GTPIE_P_TMSI:
261 case GTPIE_CHARGING_ID:
jjako08d331d2003-10-13 20:33:30 +0000262 /* case GTPIE_TEI_DI: Handled by GTPIE_FL_DI */
263 /* case GTPIE_TEI_C: Handled by GTPIE_FL_DI */
jjako52c24142002-12-16 13:33:51 +0000264 if (j<GTPIE_SIZE) {
jjako52c24142002-12-16 13:33:51 +0000265 ie[j] = (union gtpie_member*) p;
266 if (GTPIE_DEBUG) printf("GTPIE TV 4 found. Type %d, value %d\n",
267 ie[j]->tv4.t, ie[j]->tv4.v);
268 p+= 1 + 4;
269 j++;
270 }
271 break;
272 case GTPIE_TEI_DII: /* TV GTPIE types with value length 5 */
273 if (j<GTPIE_SIZE) {
274 ie[j] = (union gtpie_member*) p;
275 if (GTPIE_DEBUG) printf("GTPIE TV 5 found. Type %d\n", ie[j]->tv0.t);
276 p+= 1 + 5;
277 j++;
278 }
279 break;
280 case GTPIE_RAB_CONTEXT: /* TV GTPIE types with value length 7 */
281 if (j<GTPIE_SIZE) {
282 ie[j] = (union gtpie_member*) p;
283 if (GTPIE_DEBUG) printf("GTPIE TV 7 found. Type %d\n", ie[j]->tv0.t);
284 p+= 1 + 7;
285 j++;
286 }
287 break;
288 case GTPIE_IMSI: /* TV GTPIE types with value length 8 */
289 case GTPIE_RAI:
290 if (j<GTPIE_SIZE) {
291 ie[j] = (union gtpie_member*) p;
292 if (GTPIE_DEBUG) printf("GTPIE TV 8 found. Type %d, value 0x%llx\n",
293 ie[j]->tv0.t, ie[j]->tv8.v);
294 p+= 1 + 8;
295 j++;
296 }
297 break;
298 case GTPIE_AUTH_TRIPLET: /* TV GTPIE types with value length 28 */
299 if (j<GTPIE_SIZE) {
300 ie[j] = (union gtpie_member*) p;
301 if (GTPIE_DEBUG) printf("GTPIE TV 28 found. Type %d\n", ie[j]->tv0.t);
302 p+= 1 + 28;
303 j++;
304 }
305 break;
306 case GTPIE_EXT_HEADER_T: /* GTP extension header */
307 if (j<GTPIE_SIZE) {
308 ie[j] = (union gtpie_member*) p;
309 if (GTPIE_DEBUG) printf("GTPIE GTP extension header found. Type %d\n",
310 ie[j]->ext.t);
311 p+= 2 + ntoh8(ie[j]->ext.l);
312 j++;
313 }
314 break;
315 case GTPIE_EUA: /* TLV GTPIE types with variable length */
316 case GTPIE_MM_CONTEXT:
317 case GTPIE_PDP_CONTEXT:
318 case GTPIE_APN:
319 case GTPIE_PCO:
320 case GTPIE_GSN_ADDR:
321 case GTPIE_MSISDN:
322 case GTPIE_QOS_PROFILE:
323 case GTPIE_AUTH_QUINTUP:
324 case GTPIE_TFT:
325 case GTPIE_TARGET_INF:
326 case GTPIE_UTRAN_TRANS:
327 case GTPIE_RAB_SETUP:
328 case GTPIE_TRIGGER_ID:
329 case GTPIE_OMC_ID:
330 case GTPIE_CHARGING_ADDR:
Yann BONNAMY944dce32010-10-29 17:07:44 +0200331 case GTPIE_RAT_TYPE:
332 case GTPIE_USER_LOC:
333 case GTPIE_MS_TZ:
334 case GTPIE_IMEI_SV:
jjako52c24142002-12-16 13:33:51 +0000335 case GTPIE_PRIVATE:
336 if (j<GTPIE_SIZE) {
337 ie[j] = (union gtpie_member*) p;
338 if (GTPIE_DEBUG) printf("GTPIE TLV found. Type %d\n", ie[j]->tlv.t);
339 p+= 3 + ntoh16(ie[j]->tlv.l);
340 j++;
341 }
342 break;
343 default:
344 if (GTPIE_DEBUG) printf("GTPIE something unknown. Type %d\n", *p);
345 return EOF; /* We received something unknown */
346 }
347 }
348 if (p==end) {
349 if (GTPIE_DEBUG) printf("GTPIE normal return. %lx %lx\n",
350 (unsigned long) p, (unsigned long) end);
351 return 0; /* We landed at the end of the packet: OK */
352 }
Harald Weltee67556e2010-05-04 10:59:23 +0200353 else if (!(j<GTPIE_SIZE)) {
354 if (GTPIE_DEBUG) printf("GTPIE too many elements.\n");
355 return EOF; /* We received too many information elements */
356 }
jjako52c24142002-12-16 13:33:51 +0000357 else {
358 if (GTPIE_DEBUG) printf("GTPIE exceeded end of packet. %lx %lx\n",
359 (unsigned long) p, (unsigned long) end);
360 return EOF; /* We exceeded the end of the packet: Error */
361 }
362}
363
364int gtpie_encaps(union gtpie_member *ie[], void *pack, unsigned *len) {
365 int i;
366 unsigned char *p;
367 unsigned char *end;
368 union gtpie_member *m;
369 int iesize;
370
371 p = pack;
372
373 memset(pack, 0, GTPIE_MAX);
374 end = p + GTPIE_MAX;
375 for (i=1; i<GTPIE_SIZE; i++) if (ie[i] != 0) {
376 if (GTPIE_DEBUG) printf("gtpie_encaps. Type %d\n", i);
377 m=(union gtpie_member *)p;
378 switch (i) {
379 case GTPIE_CAUSE: /* TV GTPIE types with value length 1 */
380 case GTPIE_REORDER:
381 case GTPIE_MAP_CAUSE:
382 case GTPIE_MS_VALIDATED:
383 case GTPIE_RECOVERY:
384 case GTPIE_SELECTION_MODE:
385 case GTPIE_TEARDOWN:
386 case GTPIE_NSAPI:
387 case GTPIE_RANAP_CAUSE:
388 case GTPIE_RP_SMS:
389 case GTPIE_RP:
390 case GTPIE_MS_NOT_REACH:
391 iesize = 2;
392 break;
393 case GTPIE_FL_DI: /* TV GTPIE types with value length 2 */
394 case GTPIE_FL_C:
395 case GTPIE_PFI:
396 case GTPIE_CHARGING_C:
397 case GTPIE_TRACE_REF:
398 case GTPIE_TRACE_TYPE:
399 iesize = 3;
400 break;
401 case GTPIE_QOS_PROFILE0: /* TV GTPIE types with value length 3 */
402 case GTPIE_P_TMSI_S:
403 iesize = 4;
404 break;
405 case GTPIE_TLLI: /* TV GTPIE types with value length 4 */
406 case GTPIE_P_TMSI:
407 /* case GTPIE_TEI_DI: only in gtp1*/
408 /* case GTPIE_TEI_C: only in gtp1*/
409 case GTPIE_CHARGING_ID:
410 iesize = 5;
411 break;
412 case GTPIE_TEI_DII: /* TV GTPIE types with value length 5 */
413 iesize = 6;
414 break;
415 case GTPIE_RAB_CONTEXT: /* TV GTPIE types with value length 7 */
416 iesize = 8;
417 break;
418 case GTPIE_IMSI: /* TV GTPIE types with value length 8 */
419 case GTPIE_RAI:
420 iesize = 9;
421 break;
422 case GTPIE_AUTH_TRIPLET: /* TV GTPIE types with value length 28 */
423 iesize = 29;
424 break;
425 case GTPIE_EXT_HEADER_T: /* GTP extension header */
426 iesize = 2 + hton8(ie[i]->ext.l);
427 break;
428 case GTPIE_EUA: /* TLV GTPIE types with length length 2 */
429 case GTPIE_MM_CONTEXT:
430 case GTPIE_PDP_CONTEXT:
431 case GTPIE_APN:
432 case GTPIE_PCO:
433 case GTPIE_GSN_ADDR:
434 case GTPIE_MSISDN:
435 case GTPIE_QOS_PROFILE:
436 case GTPIE_AUTH_QUINTUP:
437 case GTPIE_TFT:
438 case GTPIE_TARGET_INF:
439 case GTPIE_UTRAN_TRANS:
440 case GTPIE_RAB_SETUP:
441 case GTPIE_TRIGGER_ID:
442 case GTPIE_OMC_ID:
443 case GTPIE_CHARGING_ADDR:
444 case GTPIE_PRIVATE:
445 iesize = 3 + hton16(ie[i]->tlv.l);
446 break;
447 default:
448 return 2; /* We received something unknown */
449 }
450 if (p+iesize < end) {
451 memcpy(p, ie[i], iesize);
452 p += iesize;
453 *len += iesize;
454 }
455 else return 2; /* Out of space */
456 }
457 return 0;
458}
459
Harald Weltef54a1f42010-05-04 11:08:38 +0200460int gtpie_encaps2(union gtpie_member ie[], unsigned int size,
jjako52c24142002-12-16 13:33:51 +0000461 void *pack, unsigned *len) {
Harald Weltef54a1f42010-05-04 11:08:38 +0200462 unsigned int i, j;
jjako52c24142002-12-16 13:33:51 +0000463 unsigned char *p;
464 unsigned char *end;
465 union gtpie_member *m;
466 int iesize;
467
468 p = pack;
469
470 memset(pack, 0, GTPIE_MAX);
471 end = p + GTPIE_MAX;
472 for (j=0; j<GTPIE_SIZE; j++) for (i=0; i<size; i++) if (ie[i].t == j) {
473 if (GTPIE_DEBUG) printf("gtpie_encaps. Number %d, Type %d\n", i, ie[i].t);
474 m=(union gtpie_member *)p;
475 switch (ie[i].t) {
476 case GTPIE_CAUSE: /* TV GTPIE types with value length 1 */
477 case GTPIE_REORDER:
478 case GTPIE_MAP_CAUSE:
479 case GTPIE_MS_VALIDATED:
480 case GTPIE_RECOVERY:
481 case GTPIE_SELECTION_MODE:
482 case GTPIE_TEARDOWN:
483 case GTPIE_NSAPI:
484 case GTPIE_RANAP_CAUSE:
485 case GTPIE_RP_SMS:
486 case GTPIE_RP:
487 case GTPIE_MS_NOT_REACH:
488 iesize = 2;
489 break;
490 case GTPIE_PFI: /* TV GTPIE types with value length 2 */
491 case GTPIE_CHARGING_C:
492 case GTPIE_TRACE_REF:
493 case GTPIE_TRACE_TYPE:
494 iesize = 3;
495 break;
496 case GTPIE_QOS_PROFILE0: /* TV GTPIE types with value length 3 */
497 case GTPIE_P_TMSI_S:
498 iesize = 4;
499 break;
500 case GTPIE_TLLI: /* TV GTPIE types with value length 4 */
501 case GTPIE_P_TMSI:
502 case GTPIE_TEI_DI:
503 case GTPIE_TEI_C:
504 iesize = 5;
505 break;
506 case GTPIE_TEI_DII: /* TV GTPIE types with value length 5 */
507 iesize = 6;
508 break;
509 case GTPIE_RAB_CONTEXT: /* TV GTPIE types with value length 7 */
510 iesize = 8;
511 break;
512 case GTPIE_IMSI: /* TV GTPIE types with value length 8 */
513 case GTPIE_RAI:
514 iesize = 9;
515 break;
516 case GTPIE_AUTH_TRIPLET: /* TV GTPIE types with value length 28 */
517 iesize = 29;
518 break;
519 case GTPIE_EXT_HEADER_T: /* GTP extension header */
520 iesize = 2 + hton8(ie[i].ext.l);
521 break;
522 case GTPIE_CHARGING_ID: /* TLV GTPIE types with length length 2 */
523 case GTPIE_EUA:
524 case GTPIE_MM_CONTEXT:
525 case GTPIE_PDP_CONTEXT:
526 case GTPIE_APN:
527 case GTPIE_PCO:
528 case GTPIE_GSN_ADDR:
529 case GTPIE_MSISDN:
530 case GTPIE_QOS_PROFILE:
531 case GTPIE_AUTH_QUINTUP:
532 case GTPIE_TFT:
533 case GTPIE_TARGET_INF:
534 case GTPIE_UTRAN_TRANS:
535 case GTPIE_RAB_SETUP:
536 case GTPIE_TRIGGER_ID:
537 case GTPIE_OMC_ID:
538 case GTPIE_CHARGING_ADDR:
539 case GTPIE_PRIVATE:
540 iesize = 3 + hton16(ie[i].tlv.l);
541 break;
542 default:
543 return 2; /* We received something unknown */
544 }
545 if (p+iesize < end) {
546 memcpy(p, &ie[i], iesize);
547 p += iesize;
548 *len += iesize;
549 }
550 else return 2; /* Out of space */
551 }
552 return 0;
553}