4 * Copyright (c) 2013 Samsung Electronics Co. Ltd. All rights reserved.
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
28 #include <core_object.h>
35 #include <co_context.h>
38 #include "imc_common.h"
41 TcorePsCallState ps_call_status;
44 static void __notify_context_status_changed(CoreObject *co_ps, guint context_id,
45 TcorePsCallState status)
47 PrivateInfo *private_info = tcore_object_ref_user_data(co_ps);
48 TcorePsCallStatusInfo data_resp = {0,};
49 tcore_check_return_assert(private_info != NULL);
51 private_info->ps_call_status = status;
52 data_resp.context_id = context_id;
53 data_resp.state = status;
54 dbg("Sending PS Call Status Notification - Context ID: [%d] Context State: [%d]",
55 data_resp.context_id, data_resp.state);
57 /* Send PS CALL Status Notification */
58 (void)tcore_object_send_notification(co_ps,
59 TCORE_NOTIFICATION_PS_CALL_STATUS,
60 sizeof(TcorePsCallStatusInfo),
65 static TcoreHookReturn on_hook_imc_nw_registration_status(TcorePlugin *plugin,
66 TcoreNotification command, guint data_len, void *data, void *user_data)
68 const TelNetworkRegStatusInfo *nw_reg_status = (TelNetworkRegStatusInfo *)data;
69 gboolean state = FALSE;
71 tcore_check_return_value(nw_reg_status != NULL,
72 TCORE_HOOK_RETURN_CONTINUE);
75 dbg("nw_reg_status->ps_status [%d]",nw_reg_status->ps_status);
76 dbg("nw_reg_status->cs_status [%d]",nw_reg_status->cs_status);
78 /* Setting if PS is online or not */
79 if(nw_reg_status->ps_status == TEL_NETWORK_REG_STATUS_REGISTERED ||
80 nw_reg_status->ps_status == TEL_NETWORK_REG_STATUS_ROAMING) {
81 /* Set PS is online */
85 dbg("PS online state [%d]", state);
87 /* Set Online state */
88 tcore_ps_set_online((CoreObject *)user_data, state);
89 return TCORE_HOOK_RETURN_CONTINUE;
93 * Notification - GPRS event reporting
96 * +CGEV: NW DEACT <PDP_type>, <PDP_addr>, [<cid>]
97 * The network has forced a context deactivation. The <cid> that was used to activate the context is provided if
100 static gboolean on_notification_imc_ps_cgev(CoreObject *co_ps,
101 const void *data, void *user_data)
103 GSList *tokens = NULL;
104 GSList *lines = (GSList *)data;
105 const gchar *line = lines->data;
113 err("Ignore, No data present in notification received for CGEV");
117 dbg("Lines->data :%s", line);
119 tokens = tcore_at_tok_new(line);
120 if (g_slist_length(tokens) != 3) {
121 err("Ignore, sufficient data not present for deactivation");
125 noti_data = g_slist_nth_data(tokens, 0);
127 /* Only care about NW context deactivation */
128 if (g_str_has_prefix(noti_data, "NW DEACT") == FALSE) {
129 err("Ignore, only care about nw deactivation");
133 noti_data = g_slist_nth_data(tokens, 1);
134 dbg("PDP Address: %s", noti_data);
136 noti_data = g_slist_nth_data(tokens, 2);
137 /*TODO: Need to handle context id with multiple PDP*/
138 if (noti_data != NULL)
139 context_id = (guint)atoi(noti_data);
141 err("No Context ID!");
145 dbg("Context %d deactivated", context_id);
147 __notify_context_status_changed(co_ps, context_id, TCORE_PS_CALL_STATE_NOT_CONNECTED);
149 hal = tcore_object_get_hal(co_ps);
150 if (tcore_hal_setup_netif(hal, co_ps, NULL, NULL, context_id,
151 FALSE) != TEL_RETURN_SUCCESS)
152 err("Failed to disable network interface");
154 tcore_at_tok_free(tokens);
158 static void __imc_ps_setup_pdp(CoreObject *co_ps, gint result, const gchar *netif_name,
161 CoreObject *ps_context = user_data;
164 tcore_check_return_assert(ps_context != NULL);
169 err("Result [%d],Hence Deactivating context ", result);
170 /* Deactivate PDP context */
171 (void)tcore_object_dispatch_request(co_ps, TRUE,
172 TCORE_COMMAND_PS_DEACTIVATE_CONTEXT,
179 dbg("devname = [%s]", netif_name);
181 tcore_context_set_ipv4_devname(ps_context, netif_name);
183 (void)tcore_context_get_id(ps_context, &context_id);
184 dbg("Context ID : %d", context_id);
186 __notify_context_status_changed(co_ps, context_id, TCORE_PS_CALL_STATE_CONNECTED);
191 static void __on_response_imc_ps_send_get_dns_cmd(TcorePending *p, guint data_len, const void *data, void *user_data)
193 const TcoreAtResponse *at_resp = data;
194 CoreObject *ps_context = user_data;
195 CoreObject *co_ps = tcore_pending_ref_core_object(p);
197 GSList *tokens = NULL;
199 const char *line = NULL;
200 char *dns_prim = NULL;
201 char *dns_sec = NULL;
202 char *token_dns = NULL;
203 gint no_pdp_active = 0;
204 TcoreHal *hal = tcore_object_get_hal(co_ps);
208 tcore_check_return_assert(at_resp != NULL);
209 tcore_check_return_assert(ps_context != NULL);
212 (void)tcore_context_get_id(ps_context, &context_id);
213 dbg("Context ID : %d", context_id);
215 if (at_resp && at_resp->success) {
217 if (at_resp->lines) {
218 dbg("DNS data present in the Response");
219 lines = (GSList *) at_resp->lines;
220 no_pdp_active = g_slist_length(lines);
221 dbg("Total Number of Active PS Context: [%d]", no_pdp_active);
222 if (0 == no_pdp_active) {
227 line = (const char *) lines->data;
228 dbg("Received Data: [%s]", line);
229 tokens = tcore_at_tok_new(line);
231 /* Check if Context ID is matching */
232 if (context_id == (guint)(atoi(g_slist_nth_data(tokens, 0)))) {
233 dbg("Found the DNS details for the Current Context - Context ID: [%d]", context_id);
237 tcore_at_tok_free(tokens);
240 /* Move to next line */
244 /* Read primary DNS */
246 token_dns = g_slist_nth_data(tokens, 1);
247 dns_prim = tcore_at_tok_extract(token_dns);
248 dbg("Primary DNS: [%s]", dns_prim);
251 /* Read Secondary DNS */
253 token_dns = g_slist_nth_data(tokens, 2);
254 dns_sec = tcore_at_tok_extract(token_dns);
255 dbg("Secondary DNS: [%s]", dns_sec);
258 if ((g_strcmp0("0.0.0.0", dns_prim) == 0)
259 && (g_strcmp0("0.0.0.0", dns_sec) == 0)) {
262 tcore_free(dns_prim);
265 tcore_at_tok_free(tokens);
271 /* Set DNS Address */
272 tcore_context_set_ipv4_dns(ps_context, dns_prim, dns_sec);
273 tcore_free(dns_prim);
276 tcore_at_tok_free(tokens);
280 dbg("No data present in the Response");
286 dbg("Adding default DNS");
287 tcore_context_set_ipv4_dns(ps_context, "8.8.8.8", "8.8.4.4");
290 /* Mount network interface */
291 if (tcore_hal_setup_netif(hal, co_ps, __imc_ps_setup_pdp, ps_context, context_id, TRUE)
292 != TEL_RETURN_SUCCESS) {
293 err("Setup network interface failed");
298 static void __imc_ps_send_get_dns_cmd(CoreObject *co_ps, CoreObject *ps_context)
300 TelReturn ret = TEL_RETURN_FAILURE;
302 PrivateInfo *private_info = tcore_object_ref_user_data(co_ps);
306 tcore_check_return_assert(private_info != NULL);
308 (void)tcore_context_get_id(ps_context, &context_id);
309 dbg("Context ID : %d", context_id);
311 /* Send Request to modem */
312 ret = tcore_at_prepare_and_send_request(co_ps,
314 TCORE_AT_COMMAND_TYPE_MULTILINE,
315 TCORE_PENDING_PRIORITY_DEFAULT,
317 __on_response_imc_ps_send_get_dns_cmd,
319 on_send_imc_request, NULL,
322 if (ret != TEL_RETURN_SUCCESS){
323 TcorePsCallState curr_call_status;
324 err("Failed to prepare and send AT request");
325 curr_call_status = private_info->ps_call_status;
326 __notify_context_status_changed(co_ps, context_id, curr_call_status);
330 static void __on_response_imc_ps_get_pdp_address(TcorePending *p, guint data_len,
331 const void *data, void *user_data)
333 const TcoreAtResponse *at_resp = data;
334 CoreObject *co_ps = tcore_pending_ref_core_object(p);
335 CoreObject *ps_context = user_data;
336 GSList *tokens = NULL;
339 char *real_pdp_address;
343 tcore_check_return_assert(at_resp != NULL);
344 tcore_check_return_assert(ps_context != NULL);
346 if (at_resp->success != TRUE) {
347 err("Response NOt OK");
353 if (at_resp->lines == NULL) {
354 err("Invalid response line");
358 line = (const char *)at_resp->lines->data;
359 tokens = tcore_at_tok_new(line);
360 if (g_slist_length(tokens) < 2) {
361 err("Invalid message");
365 dbg("Line: %s", line);
367 /* Skip CID & read directly IP address */
368 pdp_address = g_slist_nth_data(tokens, 1);
369 real_pdp_address = tcore_at_tok_extract(pdp_address);
371 tcore_context_set_ipv4_addr(ps_context, real_pdp_address);
373 dbg("PDP address: %s", real_pdp_address);
375 tcore_free(real_pdp_address);
377 /* Get DNS Address */
378 dbg("Getting DNS Address");
379 __imc_ps_send_get_dns_cmd(co_ps, ps_context);
383 err("Failed to get PDP address deactivating context...");
384 /* Deactivate PDP context */
385 (void)tcore_object_dispatch_request(co_ps, TRUE,
386 TCORE_COMMAND_PS_DEACTIVATE_CONTEXT,
390 tcore_at_tok_free(tokens);
394 static void __imc_ps_get_pdp_address(CoreObject *co_ps, CoreObject *ps_context)
397 gchar *at_cmd = NULL;
402 (void)tcore_context_get_id(ps_context, &context_id);
403 dbg("Context ID : %d", context_id);
406 at_cmd = g_strdup_printf("AT+CGPADDR=%d", context_id);
407 dbg(" at command : %s", at_cmd);
409 /* Send Request to modem */
410 ret = tcore_at_prepare_and_send_request(co_ps,
412 TCORE_AT_COMMAND_TYPE_SINGLELINE,
413 TCORE_PENDING_PRIORITY_DEFAULT,
415 __on_response_imc_ps_get_pdp_address,
417 on_send_imc_request, NULL,
420 if (ret != TEL_RETURN_SUCCESS){
421 err("Failed to prepare and send AT request");
422 /* Deactivate PDP context */
423 (void)tcore_object_dispatch_request(co_ps, TRUE,
424 TCORE_COMMAND_PS_DEACTIVATE_CONTEXT,
425 &ps_context, sizeof(CoreObject *),
431 static void __on_response_imc_ps_send_xdns_enable_cmd(TcorePending *p,
432 guint data_len, const void *data, void *user_data)
434 const TcoreAtResponse *at_resp = data;
435 CoreObject *co_ps = tcore_pending_ref_core_object(p);
436 CoreObject *ps_context = (CoreObject *) user_data;
438 TcorePsCallState status = TCORE_PS_CALL_STATE_NOT_CONNECTED;
440 tcore_check_return_assert(at_resp != NULL);
441 tcore_check_return_assert(ps_context != NULL);
445 (void)tcore_context_get_id(ps_context, &context_id);
446 dbg("Context ID : %d", context_id);
448 if (at_resp->success) {
449 dbg("Response OK, Dynamic DNS is enabled successfully");
450 status = TCORE_PS_CALL_STATE_CTX_DEFINED;
452 PrivateInfo *private_info = tcore_object_ref_user_data(co_ps);
453 tcore_check_return_assert(private_info != NULL);
455 status = private_info->ps_call_status;
456 err("ERROR [%s]", at_resp->final_response);
458 /* Send PS CALL Status Notification */
459 __notify_context_status_changed(co_ps, context_id, status);
462 static TelReturn __imc_ps_send_xdns_enable_cmd(CoreObject *co_ps, CoreObject *ps_context)
465 gchar *at_cmd = NULL;
467 PrivateInfo *private_info = tcore_object_ref_user_data(co_ps);
469 tcore_check_return_value_assert(private_info != NULL, TEL_RETURN_INVALID_PARAMETER);
473 (void)tcore_context_get_id(ps_context, &context_id);
474 dbg("Context ID : %d", context_id);
477 at_cmd = g_strdup_printf("AT+XDNS=%d,1", context_id);
478 dbg("AT Command : %s", at_cmd);
480 /* Send Request to modem */
481 ret = tcore_at_prepare_and_send_request(co_ps,
483 TCORE_AT_COMMAND_TYPE_SINGLELINE,
484 TCORE_PENDING_PRIORITY_DEFAULT,
486 __on_response_imc_ps_send_xdns_enable_cmd,
488 on_send_imc_request, NULL,
491 if (ret != TEL_RETURN_SUCCESS){
492 TcorePsCallState curr_call_status;
494 err("Failed to prepare and send AT request");
495 curr_call_status = private_info->ps_call_status;
496 __notify_context_status_changed(co_ps, context_id, curr_call_status);
501 static void on_response_imc_ps_activate_context(TcorePending *p, guint data_len,
505 const TcoreAtResponse *at_resp = data;
506 CoreObject *co_ps = tcore_pending_ref_core_object(p);
507 CoreObject *ps_context = user_data;
508 PrivateInfo *private_info = tcore_object_ref_user_data(co_ps);
512 tcore_check_return_assert(at_resp != NULL);
513 tcore_check_return_assert(ps_context != NULL);
514 tcore_check_return_assert(private_info != NULL);
516 if (at_resp->success) {
517 dbg("Response OK, Get IP address of data session");
518 __imc_ps_get_pdp_address(co_ps, ps_context);
521 TcorePsCallState curr_call_status;
522 (void)tcore_context_get_id(ps_context, &context_id);
523 err("Response NOT OK,Sending call disconnect notification");
524 curr_call_status = private_info->ps_call_status;
525 __notify_context_status_changed(co_ps, context_id, curr_call_status);
529 static void on_response_imc_ps_deactivate_context(TcorePending *p, guint data_len,
533 const TcoreAtResponse *at_resp = data;
534 CoreObject *co_ps = tcore_pending_ref_core_object(p);
535 CoreObject *ps_context = user_data;
536 TcoreHal *hal = tcore_object_get_hal(co_ps);
541 tcore_check_return_assert(at_resp != NULL);
542 tcore_check_return_assert(ps_context != NULL);
544 (void)tcore_context_get_id(ps_context, &context_id);
545 dbg("Context ID : %d", context_id);
548 * AT+CGACT = 0 is returning NO CARRIER or an error. Just test if the
549 * response contains NO CARRIER else decode CME error.
552 if (at_resp->success) {
555 line = (const gchar *)at_resp->lines->data;
556 if (g_strcmp0(line, "NO CARRIER") != 0) {
558 err("Context %d has not been deactivated", context_id);
565 __notify_context_status_changed(co_ps, context_id, TCORE_PS_CALL_STATE_NOT_CONNECTED);
567 if (tcore_hal_setup_netif(hal, co_ps, NULL, NULL, context_id, FALSE) != TEL_RETURN_SUCCESS)
568 err("Failed to disable network interface");
571 static void on_response_imc_ps_define_context(TcorePending *p,
572 guint data_len, const void *data, void *user_data)
574 const TcoreAtResponse *at_resp = data;
575 CoreObject *ps_context = (CoreObject *) user_data;
576 CoreObject *co_ps = tcore_pending_ref_core_object(p);
577 PrivateInfo *private_info = tcore_object_ref_user_data(co_ps);
581 tcore_check_return_assert(at_resp != NULL);
582 tcore_check_return_assert(ps_context != NULL);
583 tcore_check_return_assert(private_info != NULL);
585 if (at_resp->success) {
586 dbg("Response OK,Sending DNS enable command");
587 __imc_ps_send_xdns_enable_cmd(co_ps, ps_context);
590 TcorePsCallState curr_call_status;
592 err("ERROR[%s]", at_resp->final_response);
593 (void)tcore_context_get_id(ps_context, &context_id);
594 curr_call_status = private_info->ps_call_status;
595 __notify_context_status_changed(co_ps, context_id, curr_call_status);
600 * Operation - PDP Context Activate
603 * AT-Command: AT+CGACT= [<state> [, <cid> [, <cid> [,...]]]]
607 * indicates the state of PDP context activation
612 * It is a numeric parameter which specifies a particular PDP context definition
615 * Success: (No Result)
618 * +CME ERROR: <error>
621 static TelReturn imc_ps_activate_context(CoreObject *co_ps, CoreObject *ps_context,
622 TcoreObjectResponseCallback cb, void *cb_data)
624 TelReturn ret = TEL_RETURN_FAILURE;
625 gchar *at_cmd = NULL;
627 PrivateInfo *private_info = tcore_object_ref_user_data(co_ps);
629 tcore_check_return_value_assert(private_info != NULL, TEL_RETURN_INVALID_PARAMETER);
633 (void)tcore_context_get_id(ps_context, &context_id);
634 dbg("Context ID : %d", context_id);
636 at_cmd = g_strdup_printf("AT+CGACT=1,%d", context_id);
637 dbg(" at command : %s", at_cmd);
639 /* Send Request to modem */
640 ret = tcore_at_prepare_and_send_request(co_ps,
642 TCORE_AT_COMMAND_TYPE_NO_RESULT,
643 TCORE_PENDING_PRIORITY_DEFAULT,
645 on_response_imc_ps_activate_context,
647 on_send_imc_request, NULL,
650 if (ret != TEL_RETURN_SUCCESS){
651 TcorePsCallState curr_call_status;
652 curr_call_status = private_info->ps_call_status;
653 err("AT request failed. Send notification for call status [%d]", curr_call_status);
654 __notify_context_status_changed(co_ps, context_id, curr_call_status);
661 * Operation - PDP Context Deactivate
664 * AT-Command: AT+CGACT= [<state> [, <cid> [, <cid> [,...]]]]
668 * indicates the state of PDP context activation
673 * It is a numeric parameter which specifies a particular PDP context definition
676 * Success: (No Result)
679 * +CME ERROR: <error>
681 static TelReturn imc_ps_deactivate_context(CoreObject *co_ps, CoreObject *ps_context,
682 TcoreObjectResponseCallback cb, void *cb_data)
684 TelReturn ret = TEL_RETURN_FAILURE;
685 gchar *at_cmd = NULL;
687 PrivateInfo *private_info = tcore_object_ref_user_data(co_ps);
689 tcore_check_return_value_assert(private_info != NULL, TEL_RETURN_INVALID_PARAMETER);
693 (void)tcore_context_get_id(ps_context, &context_id);
694 dbg("Context ID : %d", context_id);
696 at_cmd = g_strdup_printf("AT+CGACT=0,%d", context_id);
697 dbg(" at command : %s", at_cmd);
699 /* Send Request to modem */
700 ret = tcore_at_prepare_and_send_request(co_ps,
702 TCORE_AT_COMMAND_TYPE_NO_RESULT,
703 TCORE_PENDING_PRIORITY_DEFAULT,
705 on_response_imc_ps_deactivate_context,
707 on_send_imc_request, NULL,
710 if (ret != TEL_RETURN_SUCCESS){
711 TcorePsCallState curr_call_status;
712 curr_call_status = private_info->ps_call_status;
713 err("AT request failed. Send notification for call status [%d]", curr_call_status);
714 __notify_context_status_changed(co_ps, context_id, curr_call_status);
721 * Operation - Define PDP Context
724 * AT-Command: AT+CGDCONT= [<cid> [, <PDP_type> [, <APN> [, <PDP_addr> [,
725 * <d_comp> [, <h_comp> [, <pd1> [... [, pdN]]]]]]]]]
728 * It is a numeric parameter, which specifies a particular PDP context definition
731 * "IP" Internet Protocol (IETF STD 5)
732 * "IPV6" Internet Protocol, version 6 (IETF RFC 2460)
733 * "IPV4V6" Virtual <PDP_type>introduced to handle dual IP stack UE capability (see 3GPP
740 * It is the string parameter that identifies the MT in the address space applicable to the PDP
741 * The allocated address may be read using the command +CGPADDR command
744 * A numeric parameter that controls PDP data compression
750 * A numeric parameter that controls PDP header compression
758 * zero to N string parameters whose meanings are specific to the <PDP_type>
761 * Success: (No Result)
764 * +CME ERROR: <error>
766 static TelReturn imc_ps_define_context(CoreObject *co_ps, CoreObject *ps_context,
767 TcoreObjectResponseCallback cb, void *cb_data)
769 TelReturn ret = TEL_RETURN_FAILURE;
770 gchar *at_cmd = NULL;
771 guint context_id = 0;
773 gchar *pdp_type_str = NULL;
774 TcoreContextType pdp_type;
775 TcoreContextDComp d_comp;
776 TcoreContextHComp h_comp;
777 TcorePsCallState curr_call_status;
779 PrivateInfo *private_info = tcore_object_ref_user_data(co_ps);
781 tcore_check_return_value_assert(private_info != NULL, TEL_RETURN_INVALID_PARAMETER);
785 (void)tcore_context_get_id(ps_context, &context_id);
786 (void)tcore_context_get_type(ps_context, &pdp_type);
789 case TCORE_CONTEXT_TYPE_X25:
790 dbg("CONTEXT_TYPE_X25");
791 pdp_type_str = g_strdup("X.25");
794 case TCORE_CONTEXT_TYPE_IP:
795 dbg("CONTEXT_TYPE_IP");
796 pdp_type_str = g_strdup("IP");
799 case TCORE_CONTEXT_TYPE_PPP:
800 dbg("CONTEXT_TYPE_PPP");
801 pdp_type_str = g_strdup("PPP");
804 case TCORE_CONTEXT_TYPE_IPV6:
805 dbg("CONTEXT_TYPE_IPV6");
806 pdp_type_str = g_strdup("IPV6");
810 /*PDP Type not supported*/
811 dbg("Unsupported PDP type: %d", pdp_type);
815 (void)tcore_context_get_data_compression(ps_context, &d_comp);
816 (void)tcore_context_get_header_compression(ps_context, &h_comp);
817 (void)tcore_context_get_apn(ps_context, &apn);
819 dbg("Define context for CID: %d", context_id);
822 at_cmd = g_strdup_printf("AT+CGDCONT=%d,\"%s\",\"%s\",,%d,%d", context_id, pdp_type_str, apn, d_comp, h_comp);
823 dbg("AT Command : %s", at_cmd);
825 /* Send Request to modem */
826 ret = tcore_at_prepare_and_send_request(co_ps,
828 TCORE_AT_COMMAND_TYPE_NO_RESULT,
829 TCORE_PENDING_PRIORITY_DEFAULT,
831 on_response_imc_ps_define_context,
833 on_send_imc_request, NULL,
836 tcore_free(pdp_type_str);
840 if (ret == TEL_RETURN_SUCCESS)
844 err("Failed to prepare and send AT request");
846 curr_call_status = private_info->ps_call_status;
847 __notify_context_status_changed(co_ps, context_id, curr_call_status);
854 static TcorePsOps imc_ps_ops = {
855 .define_context = imc_ps_define_context,
856 .activate_context = imc_ps_activate_context,
857 .deactivate_context = imc_ps_deactivate_context
861 gboolean imc_ps_init(TcorePlugin *p, CoreObject *co)
863 PrivateInfo *private_info;
867 /* Set PrivateInfo */
868 private_info = tcore_malloc0(sizeof(PrivateInfo));
869 tcore_object_link_user_data(co, private_info);
872 tcore_ps_set_ops(co, &imc_ps_ops);
875 tcore_object_add_callback(co, "+CGEV", on_notification_imc_ps_cgev, NULL);
877 tcore_plugin_add_notification_hook(p,
878 TCORE_NOTIFICATION_NETWORK_REGISTRATION_STATUS,
879 on_hook_imc_nw_registration_status, co);
885 void imc_ps_exit(TcorePlugin *p, CoreObject *co)
887 PrivateInfo *private_info;
889 private_info = tcore_object_ref_user_data(co);
890 tcore_check_return_assert(private_info != NULL);
892 tcore_free(private_info);