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