4 * Copyright (c) 2012 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: Arun Shukla <arun.shukla@samsung.com>
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
12 * http://www.apache.org/licenses/LICENSE-2.0
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.
28 #include <sys/ioctl.h>
32 #include <core_object.h>
36 #include <co_context.h>
46 /*Invalid Session ID*/
47 #define PS_INVALID_CID 999 /*Need to check */
49 /*Maximum String length Of the Command*/
50 #define MAX_AT_CMD_STR_LEN 150
52 /*Command for PDP activation and Deactivation*/
53 #define AT_PDP_ACTIVATE 1
54 #define AT_PDP_DEACTIVATE 0
56 #define AT_XDNS_ENABLE 1
57 #define AT_XDNS_DISABLE 0
58 #define AT_SESSION_DOWN 0
60 static void _ps_free(void *ptr)
70 static void _unable_to_get_pending(CoreObject *co_ps, CoreObject *ps_context)
72 struct tnoti_ps_call_status data_resp = {0};
75 data_resp.context_id = tcore_context_get_id(ps_context);
76 data_resp.state = PS_DATA_CALL_NOT_CONNECTED;
77 dbg("Sending Call Status Notification - Context ID: [%d] Context State: [NOT CONNECTED]",
78 data_resp.context_id);
80 /* Send CALL Status Notification */
81 tcore_server_send_notification(tcore_plugin_ref_server(tcore_object_ref_plugin(co_ps)),
82 co_ps, TNOTI_PS_CALL_STATUS, sizeof(data_resp), &data_resp);
84 /* Set PS State to Deactivated */
85 (void) tcore_context_set_state(ps_context, CONTEXT_STATE_DEACTIVATED);
89 static gboolean on_event_dun_call_notification(CoreObject *o, const void *data, void *user_data)
91 GSList *tokens = NULL;
92 const char *line = NULL;
97 lines = (GSList *) data;
98 if (g_slist_length(lines) != 1) {
99 dbg("Unsolicited message BUT multiple lines");
103 line = (char *) (lines->data);
104 tokens = tcore_at_tok_new(line);
105 value = atoi(g_slist_nth_data(tokens, 0));
109 * 0: DUN Activation in progress
110 * 1: DUN Deactivation in progress
115 case 0: /* FALL THROUGH */
123 /* TODO:- Fill Data structure: 'data' */
124 tcore_server_send_notification(tcore_plugin_ref_server(tcore_object_ref_plugin(o)), o,
125 TNOTI_PS_EXTERNAL_CALL, sizeof(struct tnoti_ps_external_call), &data);
130 /* TODO:- Fill Data structure: 'data' */
131 tcore_server_send_notification(tcore_plugin_ref_server(tcore_object_ref_plugin(o)), o,
132 TNOTI_PS_EXTERNAL_CALL, sizeof(struct tnoti_ps_external_call), &data);
142 tcore_at_tok_free(tokens);
146 static void on_response_undefine_context_cmd(TcorePending *p, int data_len, const void *data, void *user_data)
148 CoreObject *co_ps = NULL;
149 const TcoreATResponse *resp = data;
150 CoreObject *ps_context = user_data;
153 co_ps = tcore_pending_ref_core_object(p);
159 _unable_to_get_pending(co_ps, ps_context);
163 static void send_undefine_context_cmd(CoreObject *co_ps, CoreObject *ps_context)
165 TcoreHal *hal = NULL;
166 TcorePending *pending = NULL;
167 char cmd_str[MAX_AT_CMD_STR_LEN];
171 memset(cmd_str, 0x0, MAX_AT_CMD_STR_LEN);
173 /* FIXME: Before MUX setup, use PHY HAL directly. */
174 hal = tcore_object_get_hal(co_ps);
176 /*Getting Context ID from Core Object*/
177 cid = tcore_context_get_id(ps_context);
179 (void) sprintf(cmd_str, "AT+CGDCONT=%d", cid);
180 dbg("Command: [%s] Command Length: [%d]", cmd_str, strlen(cmd_str));
182 pending = tcore_at_pending_new(co_ps, cmd_str, NULL, TCORE_AT_NO_RESULT,
183 on_response_undefine_context_cmd, ps_context);
184 if (NULL == pending) {
185 err("Unable to get the create a AT request ");
188 tcore_hal_send_request(hal, pending);
189 dbg("Exit: Successfully");
193 dbg("Exit: With error");
194 _unable_to_get_pending(co_ps, ps_context);
199 static void on_setup_pdp(CoreObject *co_ps, int result,
200 const char *netif_name, void *user_data)
202 CoreObject *ps_context = user_data;
203 struct tnoti_ps_call_status data_status = {0};
209 /* Deactivate PDP context */
210 tcore_ps_deactivate_context(co_ps, ps_context, NULL);
214 dbg("Device name: [%s]", netif_name);
216 /* Set Device name */
217 tcore_context_set_ipv4_devname(ps_context, netif_name);
219 /* Set State - CONNECTED */
220 data_status.context_id = tcore_context_get_id(ps_context);
221 data_status.state = PS_DATA_CALL_CONNECTED;
222 dbg("Sending Call Status Notification - Context ID: [%d] Context State: [CONNECTED]", data_status.context_id);
224 /* Send Notification */
225 server = tcore_plugin_ref_server(tcore_object_ref_plugin(co_ps));
226 tcore_server_send_notification(server, co_ps,
227 TNOTI_PS_CALL_STATUS,
228 sizeof(struct tnoti_ps_call_status),
234 static void on_response_get_dns_cmnd(TcorePending *p, int data_len, const void *data, void *user_data)
236 GSList *tokens = NULL;
238 const char *line = NULL;
239 char *dns_prim = NULL;
240 char *dns_sec = NULL;
241 char *token_dns = NULL;
242 int no_pdp_active = 0;
243 CoreObject *ps_context = user_data;
244 const TcoreATResponse *resp = data;
245 CoreObject *co_ps = tcore_pending_ref_core_object(p);
246 int cid = tcore_context_get_id(ps_context);
247 TcoreHal *h = tcore_object_get_hal(co_ps);
251 if (resp->final_response) {
254 dbg("DNS data present in the Response");
255 pRespData = (GSList *) resp->lines;
256 no_pdp_active = g_slist_length(pRespData);
257 dbg("Total Number of Active PS Context: [%d]", no_pdp_active);
258 if (0 == no_pdp_active) {
263 line = (const char *) pRespData->data;
264 dbg("Received Data: [%s]", line);
265 tokens = tcore_at_tok_new(line);
267 /* Check if Context ID is matching */
268 if (cid == atoi(g_slist_nth_data(tokens, 0))) {
269 dbg("Found the DNS details for the Current Context - Context ID: [%d]", cid);
274 tcore_at_tok_free(tokens);
277 /* Move to next line */
278 pRespData = pRespData->next;
281 /* Read primary DNS */
283 token_dns = g_slist_nth_data(tokens, 1);
285 /* Strip off starting " and ending " from this token to read actual PDP address */
286 dns_prim = util_removeQuotes((void *)token_dns);
287 dbg("Primary DNS: [%s]", dns_prim);
290 /* Read Secondary DNS */
292 token_dns = g_slist_nth_data(tokens, 2);
294 /* Strip off starting " and ending " from this token to read actual PDP address */
295 dns_sec = util_removeQuotes((void *)token_dns);
296 dbg("Secondary DNS: [%s]", dns_sec);
299 if ((g_strcmp0("0.0.0.0", dns_prim) == 0)
300 && (g_strcmp0("0.0.0.0", dns_sec) == 0)) {
306 tcore_at_tok_free(tokens);
312 /* Set DNS Address */
313 tcore_context_set_ipv4_dns(ps_context, dns_prim, dns_sec);
317 tcore_at_tok_free(tokens);
321 dbg("No data present in the Response");
327 dbg("Adding default DNS");
328 tcore_context_set_ipv4_dns(ps_context, "8.8.8.8", "8.8.4.4");
331 /* Mount network interface */
332 if (tcore_hal_setup_netif(h, co_ps, on_setup_pdp, ps_context, cid, TRUE)
333 != TCORE_RETURN_SUCCESS) {
334 err("Setup network interface failed");
338 dbg("EXIT : Without error");
341 static TReturn send_get_dns_cmd(CoreObject *co_ps, CoreObject *ps_context)
343 TcoreHal *hal = NULL;
344 TcorePending *pending = NULL;
345 char cmd_str[MAX_AT_CMD_STR_LEN];
347 memset(cmd_str, 0x0, MAX_AT_CMD_STR_LEN);
350 hal = tcore_object_get_hal(co_ps);
352 (void) sprintf(cmd_str, "AT+XDNS?");
353 dbg("Command: [%s] Command Length: [%d]", cmd_str, strlen(cmd_str));
355 pending = tcore_at_pending_new(co_ps, cmd_str, "+XDNS", TCORE_AT_MULTILINE,
356 on_response_get_dns_cmnd, ps_context);
357 if (TCORE_RETURN_SUCCESS == tcore_hal_send_request(hal, pending)) {
358 return TCORE_RETURN_SUCCESS;
360 _unable_to_get_pending(co_ps, ps_context);
361 return TCORE_RETURN_FAILURE;
364 static void on_response_get_pdp_address(TcorePending *p, int data_len, const void *data, void *user_data)
366 const TcoreATResponse *resp = data;
367 CoreObject *co_ps = tcore_pending_ref_core_object(p);
368 CoreObject *ps_context = user_data;
369 GSList *tokens = NULL;
371 char *token_pdp_address;
373 if (resp->final_response) {
375 if (resp->lines != NULL) {
376 line = (const char *) resp->lines->data;
377 tokens = tcore_at_tok_new(line);
378 if (g_slist_length(tokens) < 2) {
379 msg("Invalid message");
382 dbg("Received Data: [%s]", line);
384 /* CID is already stored in ps_context, skip over & read PDP address */
385 token_pdp_address = g_slist_nth_data(tokens, 1);
386 token_pdp_address = util_removeQuotes((void *)token_pdp_address);
387 dbg("IP Address: [%s]", token_pdp_address);
389 /* Strip off starting " and ending " from this token to read actual PDP address */
391 (void)tcore_context_set_ipv4_addr(ps_context, (const char *)token_pdp_address);
394 /* Get DNS Address */
395 (void) send_get_dns_cmd(co_ps, ps_context);
399 /*without PDP address we will not be able to start packet service*/
400 tcore_ps_deactivate_context(co_ps, ps_context, NULL);
403 tcore_at_tok_free(tokens);
407 static TReturn send_get_pdp_address_cmd(CoreObject *co_ps, CoreObject *ps_context)
409 TcoreHal *hal = NULL;
410 TcorePending *pending = NULL;
411 unsigned int cid = PS_INVALID_CID;
412 char cmd_str[MAX_AT_CMD_STR_LEN] = {0};
415 hal = tcore_object_get_hal(co_ps);
417 cid = tcore_context_get_id(ps_context);
418 (void) sprintf(cmd_str, "AT+CGPADDR=%d", cid);
419 dbg("Command: [%s] Command Length: [%d]", cmd_str, strlen(cmd_str));
421 pending = tcore_at_pending_new(co_ps, cmd_str, "+CGPADDR", TCORE_AT_SINGLELINE,
422 on_response_get_pdp_address, ps_context);
423 if (TCORE_RETURN_SUCCESS == tcore_hal_send_request(hal, pending)) {
424 return TCORE_RETURN_SUCCESS;
426 _unable_to_get_pending(co_ps, ps_context);
427 return TCORE_RETURN_FAILURE;
430 static void on_response_send_pdp_activate_cmd(TcorePending *p, int data_len, const void *data, void *user_data)
432 CoreObject *co_ps = NULL;
433 const TcoreATResponse *resp = data;
434 CoreObject *ps_context = user_data;
437 cid = tcore_context_get_id(ps_context);
444 co_ps = tcore_pending_ref_core_object(p);
449 /* Getting the IP address and DNS from the modem */
450 dbg("Getting IP Address");
451 (void) send_get_pdp_address_cmd(co_ps, ps_context);
454 dbg("Unable to activate PDP context - Context ID: [%d]", cid);
455 dbg("Undefining PDP context");
456 (void) tcore_context_set_state(ps_context, CONTEXT_STATE_DEACTIVATED);
457 send_undefine_context_cmd(co_ps, ps_context);
462 _unable_to_get_pending(co_ps, ps_context);
467 static TReturn send_pdp_activate_cmd(CoreObject *co_ps, CoreObject *ps_context)
469 TcoreHal *hal = NULL;
470 TcorePending *pending = NULL;
471 char cmd_str[MAX_AT_CMD_STR_LEN] = {0};
474 /* FIXME: Before MUX setup, use PHY HAL directly. */
475 hal = tcore_object_get_hal(co_ps);
477 /*Getting Context ID from Core Object*/
478 cid = tcore_context_get_id(ps_context);
479 (void) sprintf(cmd_str, "AT+CGACT=%d,%d", AT_PDP_ACTIVATE, cid);
480 dbg("Command: [%s] Command Length: [%d]", cmd_str, strlen(cmd_str));
482 pending = tcore_at_pending_new(co_ps, cmd_str, NULL, TCORE_AT_NO_RESULT,
483 on_response_send_pdp_activate_cmd, ps_context);
484 if (TCORE_RETURN_SUCCESS == tcore_hal_send_request(hal, pending)) {
485 return TCORE_RETURN_SUCCESS;
487 _unable_to_get_pending(co_ps, ps_context);
488 return TCORE_RETURN_FAILURE;
491 static TReturn activate_ps_context(CoreObject *co_ps, CoreObject *ps_context, void *user_data)
494 return send_pdp_activate_cmd(co_ps, ps_context);
497 static void on_response_xdns_enable_cmd(TcorePending *p, int data_len, const void *data, void *user_data)
499 TcoreATResponse *resp = (TcoreATResponse *) data;
500 CoreObject *co_ps = tcore_pending_ref_core_object(p);
501 CoreObject *ps_context = user_data;
502 struct tnoti_ps_call_status noti = {0};
507 cid = tcore_context_get_id(ps_context);
511 dbg("DNS address getting is Enabled");
512 noti.context_id = cid;
513 noti.state = PS_DATA_CALL_CTX_DEFINED;
516 noti.context_id = cid;
517 noti.state = PS_DATA_CALL_NOT_CONNECTED;
518 /*If response to enable the DNS NOK then we will use google DNS for the PDP context*/
521 tcore_server_send_notification(tcore_plugin_ref_server(tcore_object_ref_plugin(co_ps)), co_ps,
522 TNOTI_PS_CALL_STATUS, sizeof(struct tnoti_ps_call_status), ¬i);
526 static TReturn send_xdns_enable_cmd(CoreObject *co_ps, CoreObject *ps_context)
528 TcoreHal *hal = NULL;
529 TcorePending *pending = NULL;
531 char cmd_str[MAX_AT_CMD_STR_LEN];
534 memset(cmd_str, 0x0, MAX_AT_CMD_STR_LEN);
536 hal = tcore_object_get_hal(co_ps);
537 cid = tcore_context_get_id(ps_context);
539 (void) sprintf(cmd_str, "AT+XDNS=%d,%d", cid, AT_XDNS_ENABLE);
540 dbg("Command: [%s] Command Length: [%d]", cmd_str, strlen(cmd_str));
542 pending = tcore_at_pending_new(co_ps, cmd_str, NULL, TCORE_AT_NO_RESULT,
543 on_response_xdns_enable_cmd, ps_context);
544 if (TCORE_RETURN_SUCCESS == tcore_hal_send_request(hal, pending)) {
545 return TCORE_RETURN_SUCCESS;
547 _unable_to_get_pending(co_ps, ps_context);
548 return TCORE_RETURN_FAILURE;
551 static void on_response_define_pdp_context(TcorePending *p, int data_len, const void *data, void *user_data)
553 const TcoreATResponse *resp = data;
554 CoreObject *ps_context = (CoreObject *) user_data;
555 CoreObject *co_ps = tcore_pending_ref_core_object(p);
560 send_xdns_enable_cmd(co_ps, ps_context);
563 _unable_to_get_pending(co_ps, ps_context);
569 static TReturn define_ps_context(CoreObject *co_ps, CoreObject *ps_context, void *user_data)
571 TcoreHal *hal = NULL;
572 TcorePending *pending = NULL;
574 char cmd_str[MAX_AT_CMD_STR_LEN] = {0};
575 char pdp_type_str[10] = {0};
576 unsigned int cid = PS_INVALID_CID;
577 enum co_context_type pdp_type;
578 enum co_context_d_comp d_comp;
579 enum co_context_h_comp h_comp;
583 cid = tcore_context_get_id(ps_context);
584 pdp_type = tcore_context_get_type(ps_context);
585 d_comp = tcore_context_get_data_compression(ps_context);
586 h_comp = tcore_context_get_header_compression(ps_context);
587 apn = tcore_context_get_apn(ps_context);
589 hal = tcore_object_get_hal(co_ps);
591 case CONTEXT_TYPE_X25:
593 dbg("CONTEXT_TYPE_X25");
594 strcpy(pdp_type_str, "X.25");
598 case CONTEXT_TYPE_IP:
600 dbg("CONTEXT_TYPE_IP");
601 strcpy(pdp_type_str, "IP");
605 case CONTEXT_TYPE_PPP:
607 dbg("CONTEXT_TYPE_PPP");
608 strcpy(pdp_type_str, "PPP");
612 case CONTEXT_TYPE_IPV6:
614 dbg("CONTEXT_TYPE_IPV6");
615 strcpy(pdp_type_str, "IPV6");
621 /*PDP Type not supported supported*/
622 dbg("Unsupported PDP type: %d returning ", pdp_type);
623 return TCORE_RETURN_FAILURE;
626 dbg("Activating context for CID: %d", cid);
627 (void) sprintf(cmd_str, "AT+CGDCONT=%d,\"%s\",\"%s\",,%d,%d", cid, pdp_type_str, apn, d_comp, h_comp);
628 dbg("Command: [%s] Command Length: [%d]", cmd_str, strlen(cmd_str));
630 pending = tcore_at_pending_new(co_ps, cmd_str, NULL, TCORE_AT_NO_RESULT,
631 on_response_define_pdp_context, ps_context);
632 if (TCORE_RETURN_SUCCESS == tcore_hal_send_request(hal, pending)) {
633 return TCORE_RETURN_SUCCESS;
635 _unable_to_get_pending(co_ps, ps_context);
636 return TCORE_RETURN_FAILURE;
640 static struct tcore_ps_operations ps_ops = {
641 .define_context = define_ps_context,
642 .activate_context = activate_ps_context,
643 /* Use AT_standard entry point */
644 .deactivate_context = NULL
647 gboolean s_ps_init(TcorePlugin *cp, CoreObject *co_ps)
649 TcorePlugin *plugin = tcore_object_ref_plugin(co_ps);
653 tcore_ps_override_ops(co_ps, &ps_ops);
656 * AT_standard handles standard CGEV notifications:
657 * tcore_object_override_callback(co, "+CGEV", on_cgev_notification, NULL);
658 * no need to handle it here.
661 tcore_object_override_callback(co_ps, "+XNOTIFYDUNSTATUS", on_event_dun_call_notification, plugin);
668 void s_ps_exit(TcorePlugin *cp, CoreObject *co_ps)