6e24c8dd2382dd1853a94bf2a159174101d5762e
[platform/core/telephony/libtcore.git] / src / co_ps.c
1 /*
2  * libtcore
3  *
4  * Copyright (c) 2012 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Ja-young Gu <jygu@samsung.com>
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  */
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24
25 #include <glib.h>
26
27 #include "tcore.h"
28 #include "plugin.h"
29 #include "user_request.h"
30 #include "co_ps.h"
31
32 struct p_callid_type{
33         unsigned int cid;
34         GSList *contexts;
35 };
36
37 struct private_object_data {
38         struct tcore_ps_operations *ops;
39
40         gboolean online;
41
42         /* 1 ~ UMTS_PS_MAX_CID */
43         struct p_callid_type cid[PS_MAX_CID + 1];
44         //CoreObject *cid[PS_MAX_CID + 1];
45
46         GSList *context_list;
47 };
48
49 static void _clone_ps_operations(struct private_object_data *po, struct tcore_ps_operations *ps_ops)
50 {
51         if(ps_ops->activate_context) {
52                 po->ops->activate_context = ps_ops->activate_context;
53         }
54         if(ps_ops->deactivate_context) {
55                 po->ops->deactivate_context = ps_ops->deactivate_context;
56         }
57
58         return;
59 }
60
61 static TReturn _dispatcher(CoreObject *o, UserRequest *ur)
62 {
63         enum tcore_request_command command;
64         struct private_object_data *po = NULL;
65
66         if (!o || !ur)
67                 return TCORE_RETURN_EINVAL;
68
69         po = tcore_object_ref_object(o);
70         if (!po || !po->ops)
71                 return TCORE_RETURN_ENOSYS;
72
73         command = tcore_user_request_get_command(ur);
74         switch (command) {
75                 default:
76                         break;
77         }
78
79         return TCORE_RETURN_SUCCESS;
80 }
81
82 static void _clone_hook(CoreObject *src, CoreObject *dest)
83 {
84         struct private_object_data *src_po = NULL;
85         struct private_object_data *dest_po = NULL;
86
87         if (!src || !dest)
88                 return;
89
90         dest_po = calloc(1, sizeof(struct private_object_data));
91         if (!dest_po) {
92                 tcore_object_link_object(dest, NULL);
93                 return;
94         }
95
96         src_po = tcore_object_ref_object(src);
97         dest_po->ops = src_po->ops;
98
99         tcore_object_link_object(dest, dest_po);
100 }
101
102 static void _free_hook(CoreObject *o)
103 {
104         struct private_object_data *po = NULL;
105         GSList *list;
106
107         po = tcore_object_ref_object(o);
108         if (!po)
109                 return;
110
111         if (po->context_list) {
112                 for (list = po->context_list; list; list = list->next) {
113                         if (list->data)
114                                 free(list->data);
115
116                         list->data = NULL;
117                 }
118
119                 g_slist_free(po->context_list);
120                 po->context_list = NULL;
121         }
122
123         free(po);
124         tcore_object_link_object(o, NULL);
125 }
126
127 static gboolean _ps_is_active_context(CoreObject *o, CoreObject *ps_context)
128 {
129         GSList *contexts = NULL;
130         CoreObject *s_context = NULL;
131         int idx_cid = 0;
132         struct private_object_data *po = NULL;
133
134         CORE_OBJECT_CHECK_RETURN(o, CORE_OBJECT_TYPE_PS, TCORE_RETURN_EINVAL);
135
136         po = tcore_object_ref_object(o);
137
138         for (idx_cid = 0; idx_cid < PS_MAX_CID; idx_cid++) {
139                 if (po->cid[idx_cid].cid != 0) {
140                         contexts = po->cid[idx_cid].contexts;
141                         if (contexts == NULL)
142                                 continue;
143
144                         for (; contexts != NULL; contexts = g_slist_next(contexts)) {
145                                 s_context = contexts->data;
146                                 if (s_context == NULL)
147                                         continue;
148
149                                 if (ps_context == s_context) {
150                                         dbg("find contexts(%p) in cid(%d)",
151                                                         ps_context, idx_cid);
152                                         return TRUE;
153                                 }
154                         }
155                 }
156         }
157
158         dbg("cannot find contexts(%p) ", ps_context);
159         return FALSE;
160 }
161
162 static gboolean _ps_is_duplicated_apn(CoreObject *o, CoreObject *ps_context)
163 {
164         GSList *contexts = NULL;
165         CoreObject *s_context = NULL;
166         gchar *t_apn = NULL, *s_apn = NULL;
167
168         int idx_cid = 0;
169         struct private_object_data *po = NULL;
170
171         CORE_OBJECT_CHECK_RETURN(o, CORE_OBJECT_TYPE_PS, TCORE_RETURN_EINVAL);
172
173         po = tcore_object_ref_object(o);
174         t_apn = tcore_context_get_apn(ps_context);
175
176         for (idx_cid = 0; idx_cid < PS_MAX_CID; idx_cid++) {
177                 if (po->cid[idx_cid].cid != 0) {
178                         contexts = po->cid[idx_cid].contexts;
179                         if (contexts == NULL)
180                                 continue;
181
182                         for (; contexts != NULL; contexts = g_slist_next(contexts)) {
183                                 s_context = contexts->data;
184                                 if (s_context == NULL)
185                                         continue;
186
187                                 if (ps_context == s_context)
188                                         continue;
189
190                                 s_apn = tcore_context_get_apn(s_context);
191
192                                 if (g_strcmp0(t_apn, s_apn) == 0) {
193                                         dbg("target and source have same APN");
194                                         tcore_context_cp_service_info(
195                                                         ps_context, s_context);
196                                         g_free(t_apn);
197                                         g_free(s_apn);
198                                         return TRUE;
199                                 }
200
201                                 g_free(s_apn);
202                         }
203                 }
204         }
205
206         g_free(t_apn);
207         return FALSE;
208 }
209
210 void tcore_ps_override_ops(CoreObject *o, struct tcore_ps_operations *ps_ops)
211 {
212         struct private_object_data *po = NULL;
213
214         CORE_OBJECT_CHECK(o, CORE_OBJECT_TYPE_PS);
215
216         po = (struct private_object_data *)tcore_object_ref_object(o);
217         if (!po) {
218                 return;
219         }
220
221         if(ps_ops) {
222                 _clone_ps_operations(po, ps_ops);
223         }
224
225         return;
226 }
227
228 CoreObject *tcore_ps_new(TcorePlugin *p,
229                         struct tcore_ps_operations *ops, TcoreHal *hal)
230 {
231         CoreObject *o = NULL;
232         struct private_object_data *po = NULL;
233
234         if (!p)
235                 return NULL;
236
237         o = tcore_object_new(p, hal);
238         if (!o)
239                 return NULL;
240
241         po = calloc(1, sizeof(struct private_object_data));
242         if (!po) {
243                 tcore_object_free(o);
244                 return NULL;
245         }
246
247         po->ops = ops;
248
249         tcore_object_set_type(o, CORE_OBJECT_TYPE_PS);
250         tcore_object_link_object(o, po);
251         tcore_object_set_free_hook(o, _free_hook);
252         tcore_object_set_clone_hook(o, _clone_hook);
253         tcore_object_set_dispatcher(o, _dispatcher);
254
255         return o;
256 }
257
258 void tcore_ps_free(CoreObject *o)
259 {
260         struct private_object_data *po = NULL;
261
262         CORE_OBJECT_CHECK(o, CORE_OBJECT_TYPE_PS);
263
264         po = tcore_object_ref_object(o);
265         if (!po)
266                 return;
267
268         g_free(po);
269         tcore_object_link_object(o, po);
270         tcore_object_free(o);
271 }
272
273 TReturn tcore_ps_add_context(CoreObject *o, CoreObject *ctx_o)
274 {
275         struct private_object_data *po = NULL;
276
277         CORE_OBJECT_CHECK_RETURN(o, CORE_OBJECT_TYPE_PS, TCORE_RETURN_EINVAL);
278         CORE_OBJECT_CHECK_RETURN(ctx_o, CORE_OBJECT_TYPE_PS_CONTEXT, TCORE_RETURN_EINVAL);
279
280         po = tcore_object_ref_object(o);
281         if (!po)
282                 return TCORE_RETURN_EINVAL;
283
284         po->context_list = g_slist_insert(po->context_list, ctx_o, 0);
285
286         return TCORE_RETURN_SUCCESS;
287 }
288
289 TReturn tcore_ps_remove_context(CoreObject *o, CoreObject *ctx_o)
290 {
291         struct private_object_data *po = NULL;
292
293         CORE_OBJECT_CHECK_RETURN(o, CORE_OBJECT_TYPE_PS, TCORE_RETURN_EINVAL);
294         CORE_OBJECT_CHECK_RETURN(ctx_o, CORE_OBJECT_TYPE_PS_CONTEXT, TCORE_RETURN_EINVAL);
295
296         po = tcore_object_ref_object(o);
297         if (!po)
298                 return TCORE_RETURN_EINVAL;
299
300         tcore_ps_clear_context_id(o, ctx_o);
301         po->context_list = g_slist_remove(po->context_list, ctx_o);
302
303         return TCORE_RETURN_SUCCESS;
304 }
305
306 TReturn tcore_ps_set_online(CoreObject *o, gboolean state)
307 {
308         struct private_object_data *po = NULL;
309
310         CORE_OBJECT_CHECK_RETURN(o, CORE_OBJECT_TYPE_PS, TCORE_RETURN_EINVAL);
311
312         po = tcore_object_ref_object(o);
313         if (!po)
314                 return TCORE_RETURN_EINVAL;
315
316         po->online = state;
317         dbg("ps status = %d", po->online);
318
319         return TCORE_RETURN_SUCCESS;
320 }
321
322 CoreObject *tcore_ps_ref_context_by_role(CoreObject *o, enum co_context_role role)
323 {
324         struct private_object_data *po = NULL;
325         GSList *list;
326         CoreObject *pdp_o;
327         TcorePlugin *p;
328
329         CORE_OBJECT_CHECK_RETURN(o, CORE_OBJECT_TYPE_PS, NULL);
330
331         po = tcore_object_ref_object(o);
332         if (!po)
333                 return NULL;
334
335         p = tcore_object_ref_plugin(o);
336         if (!p)
337                 return NULL;
338
339         if (po->context_list) {
340                 for (list = po->context_list; list; list = list->next) {
341                         if (!list->data)
342                                 continue;
343
344                         pdp_o = list->data;
345                         if (!pdp_o)
346                                 continue;
347
348                         if (tcore_object_get_type(pdp_o) != CORE_OBJECT_TYPE_PS_CONTEXT)
349                                 continue;
350
351                         if (tcore_context_get_role(pdp_o) == role)
352                                 return pdp_o;
353                 }
354         }
355
356         return NULL;
357 }
358
359 GSList *tcore_ps_ref_context_by_id(CoreObject *o, unsigned int id)
360 {
361         struct private_object_data *po = NULL;
362
363         CORE_OBJECT_CHECK_RETURN(o, CORE_OBJECT_TYPE_PS, NULL);
364
365         po = tcore_object_ref_object(o);
366         if (!po)
367                 return NULL;
368
369         if (id == 0 || id > PS_MAX_CID)
370                 return NULL;
371
372         if (po->cid[id].cid != id)
373                 return NULL;
374
375         return po->cid[id].contexts;
376 }
377
378 TReturn tcore_ps_assign_context_id(CoreObject *o, CoreObject *context, unsigned int cid)
379 {
380         struct private_object_data *po = NULL;
381         int idx;
382
383         CORE_OBJECT_CHECK_RETURN(o, CORE_OBJECT_TYPE_PS, TCORE_RETURN_EINVAL);
384         CORE_OBJECT_CHECK_RETURN(context, CORE_OBJECT_TYPE_PS_CONTEXT, TCORE_RETURN_EINVAL);
385
386         po = tcore_object_ref_object(o);
387         if (!po)
388                 return TCORE_RETURN_EINVAL;
389
390         if (cid == 0) {
391                 /* Automatic assign */
392                 for (idx = 1; idx <= PS_MAX_CID; idx++) {
393                         if (po->cid[idx].cid == 0) {
394                                 po->cid[idx].cid = idx;
395                                 po->cid[idx].contexts = g_slist_append(po->cid[idx].contexts, context);
396                                 dbg("assign contexts(%p) in cid(%d)", context, idx);
397                                 return tcore_context_set_id(context, idx);
398                         }
399                         else {
400                                 dbg("cid[%d] is not null", idx);
401                         }
402                 }
403
404                 dbg("can't find empty cid");
405         }
406         else {
407                 /* Manual assign */
408                 if (po->cid[cid].cid == cid) {
409                         po->cid[cid].contexts = g_slist_append(po->cid[cid].contexts, context);
410                         return tcore_context_set_id(context, cid);
411                 }
412                 else {
413                         dbg("cid[%d] is not null", cid);
414                 }
415         }
416
417         return TCORE_RETURN_PS_CID_ERROR;
418 }
419
420 TReturn tcore_ps_clear_context_id(CoreObject *o, CoreObject *context)
421 {
422         struct private_object_data *po = NULL;
423         int i = 0, cnt = 0;
424
425         CORE_OBJECT_CHECK_RETURN(o, CORE_OBJECT_TYPE_PS, TCORE_RETURN_EINVAL);
426         CORE_OBJECT_CHECK_RETURN(context, CORE_OBJECT_TYPE_PS_CONTEXT, TCORE_RETURN_EINVAL);
427
428         po = tcore_object_ref_object(o);
429         if (!po)
430                 return TCORE_RETURN_EINVAL;
431
432         i = tcore_context_get_id(context);
433         if (i == 0) {
434                 return TCORE_RETURN_PS_CID_ERROR;
435         }
436
437         if (i > PS_MAX_CID)
438                 return TCORE_RETURN_PS_CID_ERROR;
439
440         po->cid[i].contexts = g_slist_remove(po->cid[i].contexts, context);
441         cnt = g_slist_length(po->cid[i].contexts);
442         if (cnt <= 0)
443                 po->cid[i].cid = 0;
444
445         return tcore_context_set_id(context, 0);
446 }
447
448 TReturn tcore_ps_define_context(CoreObject *o, CoreObject *ps_context, void *user_data)
449 {
450         int rv;
451         struct private_object_data *po = NULL;
452
453         CORE_OBJECT_CHECK_RETURN(o, CORE_OBJECT_TYPE_PS, TCORE_RETURN_EINVAL);
454
455         po = tcore_object_ref_object(o);
456         if (!po)
457                 return TCORE_RETURN_EINVAL;
458
459         if (!ps_context)
460                 return TCORE_RETURN_EINVAL;
461
462         rv = _ps_is_active_context(o, ps_context);
463         if (rv)
464                 return TCORE_RETURN_SUCCESS;
465
466         rv = _ps_is_duplicated_apn(o, ps_context);
467         if (rv) {
468                 int cid = 0;
469                 cid = tcore_context_get_id(ps_context);
470                 po->cid[cid].contexts = g_slist_append(po->cid[cid].contexts, ps_context);
471                 return TCORE_RETURN_SUCCESS;
472         }
473
474         if (tcore_context_get_id(ps_context) == 0) {
475                 if (tcore_ps_assign_context_id(o, ps_context, 0) != TCORE_RETURN_SUCCESS)
476                         return TCORE_RETURN_PS_CID_ERROR;
477         }
478
479         dbg("contexts(%p), cid = %d", ps_context, tcore_context_get_id(ps_context));
480
481         return po->ops->define_context(o, ps_context, user_data);
482 }
483
484 TReturn tcore_ps_activate_context(CoreObject *o, CoreObject *ps_context, void *user_data)
485 {
486         int rv;
487         struct private_object_data *po = NULL;
488         enum co_context_state context_state = CONTEXT_STATE_DEACTIVATED;
489
490         CORE_OBJECT_CHECK_RETURN(o, CORE_OBJECT_TYPE_PS, TCORE_RETURN_EINVAL);
491
492         po = tcore_object_ref_object(o);
493         if (!po)
494                 return TCORE_RETURN_EINVAL;
495
496         if (!po->online) {
497                 dbg("ps network is not online !");
498                 return TCORE_RETURN_PS_NETWORK_NOT_READY;
499         }
500
501         if (!ps_context)
502                 return TCORE_RETURN_EINVAL;
503
504         rv = _ps_is_active_context(o, ps_context);
505         if (!rv)
506         {
507                 dbg("it is not defined context");
508                 return TCORE_RETURN_EINVAL;
509         }
510
511         rv = _ps_is_duplicated_apn(o, ps_context);
512         if (rv) {
513                 dbg("context activation is already requested for the same apn(%s)", 
514                         tcore_context_get_apn(ps_context));
515                 return TCORE_RETURN_SUCCESS;
516         }
517
518         context_state = tcore_context_get_state(ps_context);
519
520         if (context_state == CONTEXT_STATE_ACTIVATED)
521                 return TCORE_RETURN_SUCCESS;
522         else if (context_state == CONTEXT_STATE_ACTIVATING)
523                 return TCORE_RETURN_SUCCESS;
524         else if (context_state == CONTEXT_STATE_DEACTIVATING)
525                 return TCORE_RETURN_PS_DEACTIVATING;
526
527
528         dbg("cid = %d", tcore_context_get_id(ps_context));
529
530         tcore_context_set_state(ps_context, CONTEXT_STATE_ACTIVATING);
531         return po->ops->activate_context(o, ps_context, user_data);
532 }
533
534 TReturn tcore_ps_deactivate_context(CoreObject *o, CoreObject *ps_context, void *user_data)
535 {
536         int rv;
537         struct private_object_data *po = NULL;
538         enum co_context_state context_state = CONTEXT_STATE_DEACTIVATED;
539
540         CORE_OBJECT_CHECK_RETURN(o, CORE_OBJECT_TYPE_PS, TCORE_RETURN_EINVAL);
541
542         po = tcore_object_ref_object(o);
543         if (!po)
544                 return TCORE_RETURN_EINVAL;
545
546         if (!po->online) {
547                 dbg("ps network is not online !");
548                 return TCORE_RETURN_PS_NETWORK_NOT_READY;
549         }
550
551         if (!ps_context)
552                 return TCORE_RETURN_EINVAL;
553
554         rv = _ps_is_active_context(o, ps_context);
555         if (!rv)
556                 return TCORE_RETURN_EINVAL;
557
558         rv = _ps_is_duplicated_apn(o, ps_context);
559         if (rv) {
560                 int cid = 0;
561                 cid = tcore_context_get_id(ps_context);
562                 po->cid[cid].contexts = g_slist_remove(po->cid[cid].contexts, ps_context);
563                 tcore_context_set_state(ps_context, CONTEXT_STATE_DEACTIVATED);
564                 return TCORE_RETURN_SUCCESS;
565         }
566
567         context_state = tcore_context_get_state(ps_context);
568         if (context_state == CONTEXT_STATE_DEACTIVATED)
569                 return TCORE_RETURN_SUCCESS;
570         else if (context_state == CONTEXT_STATE_DEACTIVATING)
571                 return TCORE_RETURN_SUCCESS;
572         else if (context_state == CONTEXT_STATE_ACTIVATING)
573                 return TCORE_RETURN_PS_ACTIVATING;
574
575         tcore_context_set_state(ps_context, CONTEXT_STATE_DEACTIVATING);
576         return po->ops->deactivate_context(o, ps_context, user_data);
577 }
578
579 TReturn tcore_ps_deactivate_contexts(CoreObject *o)
580 {
581         GSList *contexts = NULL;
582         CoreObject *context = NULL;
583         int index = 0;
584         struct private_object_data *po = NULL;
585
586         CORE_OBJECT_CHECK_RETURN(o, CORE_OBJECT_TYPE_PS, TCORE_RETURN_EINVAL);
587
588         po = tcore_object_ref_object(o);
589         if (!po)
590                 return TCORE_RETURN_EINVAL;
591
592         if (!po->online) {
593                 dbg("ps network is not online !");
594                 return TCORE_RETURN_PS_NETWORK_NOT_READY;
595         }
596
597         for (index = 0; index < PS_MAX_CID; index++) {
598                 if (po->cid[index].cid != 0) {
599                         contexts = po->cid[index].contexts;
600                         if (contexts == NULL)
601                                 continue;
602
603                         for (; contexts != NULL; contexts = g_slist_next(contexts)) {
604                                 context = contexts->data;
605                                 if (context == NULL)
606                                         continue;
607
608                                 tcore_ps_deactivate_context(o, context, NULL);
609                         }
610                 }
611         }
612
613         return TCORE_RETURN_SUCCESS;
614 }