4 * Copyright (c) 2012 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: Kyoungyoup Park <gynaru.park@samsung.com>
7 * Hayoon Ko <hayoon.ko@samsung.com>
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
28 #include <arpa/inet.h>
34 #include <core_object.h>
38 #include <co_context.h>
39 #include <user_request.h>
48 static void __notify_context_status_changed(CoreObject *co_ps, guchar context_id, gint status)
51 struct tnoti_ps_call_status ps_call_status;
55 ps_call_status.context_id = (guint)context_id;
56 ps_call_status.state = status;
57 ps_call_status.result = TCORE_RETURN_SUCCESS;
59 dbg("Sending PS Call Status Notification - Context ID: [%d] Context State: [%d]",
60 ps_call_status.context_id, ps_call_status.state);
62 /* Send PS CALL Status Notification */
63 server = tcore_plugin_ref_server(tcore_object_ref_plugin(co_ps));
64 tcore_server_send_notification(server, co_ps,
66 sizeof(struct tnoti_ps_call_status),
72 static void on_response_undefine_context_cmd(TcorePending *p,
73 int data_len, const void *data, void *user_data)
75 const TcoreATResponse *resp = data;
79 if (resp && resp->success) {
86 static void __send_undefine_context_cmd(CoreObject *co_ps, CoreObject *ps_context)
94 /*Getting Context ID from Core Object*/
95 context_id = tcore_context_get_id(ps_context);
97 at_cmd = g_strdup_printf("AT+CGDCONT=0,%d", context_id);
99 /* Send Request to modem */
100 ret = tcore_prepare_and_send_at_request(co_ps,
104 on_response_undefine_context_cmd, NULL,
105 on_send_at_request, NULL,
107 dbg("ret: [0x%x]", ret);
115 static void __ps_setup_pdp(CoreObject *co_ps, gint result,
116 const gchar *netif_name, void *user_data)
118 CoreObject *ps_context = user_data;
121 CHECK_AND_RETURN(ps_context != NULL);
126 err("Failed to setup PDP");
128 /* Deactivate PDP context */
129 __send_undefine_context_cmd(co_ps, ps_context);
134 dbg("devname = [%s]", netif_name);
136 context_id = tcore_context_get_id(ps_context);
137 dbg("Context ID : %d", context_id);
139 __notify_context_status_changed(co_ps, context_id, 1);
144 static void __on_response_get_ipconfiguration(TcorePending *p,
145 int data_len, const void *data, void *user_data)
147 CoreObject *co_ps = tcore_pending_ref_core_object(p);
148 CoreObject *ps_context = user_data;
149 const TcoreATResponse *at_resp = data;
151 GSList *p_cur = NULL;
153 context_id = tcore_context_get_id(ps_context);
154 dbg("Context ID : %d", context_id);
156 if (at_resp && at_resp->success) {
157 for (p_cur = at_resp->lines; p_cur != NULL; p_cur = p_cur->next) {
159 GSList *tokens = NULL;
161 line = (const char *) p_cur->data;
162 tokens = tcore_at_tok_new(line);
164 if (g_slist_length(tokens) >= 2) {
165 gchar *pdp_type = NULL, *apn = NULL;
166 gchar *ip = NULL, *pdp_address = NULL, *p_cid = NULL;
168 p_cid = g_slist_nth_data(tokens, 0);
169 dbg("cid: %d", p_cid);
171 /* Send IP Configuration noti only on the requested CID. */
172 if (atoi(p_cid) && (context_id == (unsigned int)atoi(p_cid))) {
173 TcoreHal *hal = tcore_object_get_hal(co_ps);
175 pdp_type = g_slist_nth_data(tokens, 1);
176 dbg("PDP type: %s", pdp_type);
178 if (pdp_type != NULL) {
179 apn = g_slist_nth_data(tokens, 2);
183 ip = g_slist_nth_data(tokens, 3);
184 pdp_address = tcore_at_tok_extract(ip);
185 dbg("IP address: %s", ip);
188 (void)tcore_context_set_address(ps_context, (const char *)pdp_address);
191 dbg("Adding default DNS pri: 8.8.8.8 sec: 8.8.4.4");
193 tcore_context_set_dns1(ps_context, "8.8.8.8");
194 tcore_context_set_dns2(ps_context, "8.8.4.4");
196 /* Mount network interface */
197 if (tcore_hal_setup_netif(hal, co_ps, __ps_setup_pdp, ps_context, context_id, TRUE)
198 != TCORE_RETURN_SUCCESS) {
199 err("Setup network interface failed");
203 err("No matched response with CID: %d", atoi(p_cid));
210 context_id = tcore_context_get_id(ps_context);
211 dbg("Context ID : %d", context_id);
213 __notify_context_status_changed(co_ps, context_id, 3);
217 static void __get_ipconfiguration(CoreObject *co_ps, CoreObject *ps_context)
223 /* Send Request to modem */
224 ret = tcore_prepare_and_send_at_request(co_ps,
228 __on_response_get_ipconfiguration,
230 on_send_at_request, NULL,
232 if (ret != TCORE_RETURN_SUCCESS) {
233 err("Failed to prepare and send AT request");
235 /* Deactivate PDP context */
236 __send_undefine_context_cmd(co_ps, ps_context);
242 static void __on_response_attach_ps(TcorePending *p,
243 int data_len, const void *data, void *user_data)
245 CoreObject *co_ps = tcore_pending_ref_core_object(p);
246 CoreObject *ps_context = user_data;
247 const TcoreATResponse *at_resp = data;
250 CHECK_AND_RETURN(at_resp != NULL);
251 CHECK_AND_RETURN(ps_context != NULL);
253 if (at_resp && at_resp->success) {
254 __get_ipconfiguration(co_ps, ps_context);
260 context_id = tcore_context_get_id(ps_context);
261 dbg("Context ID : %d", context_id);
263 __notify_context_status_changed(co_ps, context_id, 3);
268 static void __attach_ps(CoreObject *co_ps, CoreObject *ps_context)
274 /* Send Request to modem */
275 ret = tcore_prepare_and_send_at_request(co_ps,
279 __on_response_attach_ps, ps_context,
280 on_send_at_request, NULL,
282 if (ret != TCORE_RETURN_SUCCESS) {
283 err("Failed to prepare and send AT request");
285 /* Deactivate PDP context */
286 __send_undefine_context_cmd(co_ps, ps_context);
292 static void on_response_ps_activate_context(TcorePending *p,
293 gint data_len, const void *data, void *user_data)
295 CoreObject *co_ps = tcore_pending_ref_core_object(p);
296 const TcoreATResponse *at_resp = data;
297 CoreObject *ps_context = user_data;
301 CHECK_AND_RETURN(at_resp != NULL);
302 CHECK_AND_RETURN(ps_context != NULL);
304 if (at_resp && at_resp->success) {
306 __attach_ps(co_ps, ps_context);
312 context_id = tcore_context_get_id(ps_context);
313 dbg("Context ID : %d", context_id);
315 __notify_context_status_changed(co_ps, context_id, 3);
321 static void on_response_ps_deactivate_context(TcorePending *p,
322 gint data_len, const void *data, void *user_data)
324 CoreObject *co_ps = tcore_pending_ref_core_object(p);
325 TcoreHal *hal = tcore_object_get_hal(co_ps);
326 const TcoreATResponse *at_resp = data;
327 CoreObject *ps_context = user_data;
332 CHECK_AND_RETURN(at_resp != NULL);
333 CHECK_AND_RETURN(ps_context != NULL);
335 context_id = tcore_context_get_id(ps_context);
336 dbg("Context ID : %d", context_id);
339 * AT+CGACT = 0 is returning NO CARRIER or an error. Just test if the
340 * response contains NO CARRIER else decode CME error.
342 if (at_resp && at_resp->success) {
345 line = (const gchar *)at_resp->lines->data;
346 if (g_strcmp0(line, "NO CARRIER") != 0) {
348 err("Context %d has not been deactivated", context_id);
354 __notify_context_status_changed(co_ps, context_id, 3);
356 if (tcore_hal_setup_netif(hal, co_ps, NULL, NULL, context_id, FALSE) != TCORE_RETURN_SUCCESS)
357 err("Failed to disable network interface");
363 static void on_response_ps_define_context(TcorePending *p,
364 gint data_len, const void *data, void *user_data)
366 const TcoreATResponse *at_resp = data;
367 CoreObject *ps_context = (CoreObject *) user_data;
368 CoreObject *co_ps = tcore_pending_ref_core_object(p);
370 gint curr_call_status;
374 CHECK_AND_RETURN(at_resp != NULL);
375 CHECK_AND_RETURN(ps_context != NULL);
377 if (at_resp && at_resp->success) {
379 curr_call_status = 0;
380 tcore_context_set_state(co_ps, CONTEXT_STATE_ACTIVATED);
382 err("ERROR[%s]", at_resp->final_response);
383 curr_call_status = 3;
386 context_id = tcore_context_get_id(ps_context);
387 dbg("Context ID : %d", context_id);
389 __notify_context_status_changed(co_ps, context_id, curr_call_status);
393 * Operation - PDP Context Activate
396 * AT-Command: AT+CGACT= [<state> [, <cid> [, <cid> [,...]]]]
400 * indicates the state of PDP context activation
405 * It is a numeric parameter which specifies a particular PDP context definition
408 * Success: (No Result)
411 * +CME ERROR: <error>
413 static TReturn activate_ps_context(CoreObject *o, CoreObject *ps_context, void* user_data)
415 gchar *at_cmd = NULL;
421 context_id = tcore_context_get_id(ps_context);
422 dbg("Context ID : %d", context_id);
424 at_cmd = g_strdup_printf("AT+CGACT=1,%d", context_id);
425 dbg(" at command : %s", at_cmd);
427 /* Send Request to modem */
428 ret = tcore_prepare_and_send_at_request(o,
432 on_response_ps_activate_context, ps_context,
433 on_send_at_request, NULL,
435 if (ret != TCORE_RETURN_SUCCESS) {
436 err("AT request failed. Send notification for call status [DISCONNECTED]");
438 __notify_context_status_changed(o, context_id, 3);
447 * Operation - PDP Context Deactivate
450 * AT-Command: AT+CGACT= [<state> [, <cid> [, <cid> [,...]]]]
454 * indicates the state of PDP context activation
459 * It is a numeric parameter which specifies a particular PDP context definition
462 * Success: (No Result)
465 * +CME ERROR: <error>
467 static TReturn deactivate_ps_context(CoreObject *o, CoreObject *ps_context, void* user_data)
469 gchar *at_cmd = NULL;
475 context_id = tcore_context_get_id(ps_context);
476 dbg("Context ID : %d", context_id);
478 at_cmd = g_strdup_printf("AT+CGACT=0,%d", context_id);
479 dbg(" at command : %s", at_cmd);
481 /* Send Request to modem */
482 ret = tcore_prepare_and_send_at_request(o,
486 on_response_ps_deactivate_context, ps_context,
487 on_send_at_request, NULL,
489 if (ret != TCORE_RETURN_SUCCESS) {
490 err("AT request failed. Send notification for call status [DISCONNECTED]");
491 __notify_context_status_changed(o, context_id, 3);
500 * Operation - Define PDP Context
503 * AT-Command: AT+CGDCONT= [<cid> [, <PDP_type> [, <APN> [, <PDP_addr> [,
504 * <d_comp> [, <h_comp> [, <pd1> [... [, pdN]]]]]]]]]
507 * It is a numeric parameter, which specifies a particular PDP context definition
510 * "IP" Internet Protocol (IETF STD 5)
511 * "IPV6" Internet Protocol, version 6 (IETF RFC 2460)
512 * "IPV4V6" Virtual <PDP_type>introduced to handle dual IP stack UE capability (see 3GPP
519 * It is the string parameter that identifies the MT in the address space applicable to the PDP
520 * The allocated address may be read using the command +CGPADDR command
523 * A numeric parameter that controls PDP data compression
529 * A numeric parameter that controls PDP header compression
537 * zero to N string parameters whose meanings are specific to the <PDP_type>
540 * Success: (No Result)
543 * +CME ERROR: <error>
545 static TReturn define_ps_context(CoreObject *o, CoreObject *ps_context, void *user_data)
547 guchar context_id = 0;
548 gchar *at_cmd = NULL;
550 gchar *pdp_type_str = NULL;
554 TReturn ret = TCORE_RETURN_FAILURE;
558 context_id = tcore_context_get_id(ps_context);
559 dbg("Context ID : %d", context_id);
560 pdp_type = tcore_context_get_type(ps_context);
561 dbg("PDP Type : %d", pdp_type);
564 case CONTEXT_TYPE_X25:
565 dbg("CONTEXT_TYPE_X25");
566 pdp_type_str = g_strdup("X.25");
569 case CONTEXT_TYPE_IP:
570 dbg("CONTEXT_TYPE_IP");
571 pdp_type_str = g_strdup("IP");
574 case CONTEXT_TYPE_PPP:
575 dbg("CONTEXT_TYPE_PPP");
576 pdp_type_str = g_strdup("PPP");
579 case CONTEXT_TYPE_IPV6:
580 dbg("CONTEXT_TYPE_IPV6");
581 pdp_type_str = g_strdup("IPV6");
585 /*PDP Type not supported*/
586 dbg("Unsupported PDP type: %d", pdp_type);
590 d_comp = tcore_context_get_data_compression(ps_context);
591 h_comp = tcore_context_get_header_compression(ps_context);
592 apn = tcore_context_get_apn(ps_context);
595 at_cmd = g_strdup_printf("AT+CGDCONT=%d,\"%s\",\"%s\",,%d,%d",
596 context_id, pdp_type_str, apn, d_comp, h_comp);
597 dbg("AT-Command : %s", at_cmd);
599 /* Send Request to modem */
600 ret = tcore_prepare_and_send_at_request(o,
604 on_response_ps_define_context, ps_context,
605 on_send_at_request, NULL,
608 g_free(pdp_type_str);
612 if (ret == TCORE_RETURN_SUCCESS)
616 err("Failed to prepare and send AT request");
617 __notify_context_status_changed(o, context_id, 3);
625 static struct tcore_ps_operations ps_ops = {
626 .define_context = define_ps_context,
627 .activate_context = activate_ps_context,
628 .deactivate_context = deactivate_ps_context
632 gboolean s_ps_init(TcorePlugin *p, TcoreHal *h)
637 o = tcore_ps_new(p, "umts_ps", &ps_ops, h);
645 void s_ps_exit(TcorePlugin *p)
649 o = tcore_plugin_ref_core_object(p, CORE_OBJECT_TYPE_PS);
650 CHECK_AND_RETURN(o != NULL);