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 _unable_to_get_pending(CoreObject *co_ps, CoreObject *ps_context)
62 struct tnoti_ps_call_status data_resp = {0};
65 data_resp.context_id = tcore_context_get_id(ps_context);
66 data_resp.state = PS_DATA_CALL_NOT_CONNECTED;
67 dbg("Sending Call Status Notification - Context ID: [%d] Context State: [NOT CONNECTED]",
68 data_resp.context_id);
70 /* Send CALL Status Notification */
71 tcore_server_send_notification(tcore_plugin_ref_server(tcore_object_ref_plugin(co_ps)),
72 co_ps, TNOTI_PS_CALL_STATUS, sizeof(data_resp), &data_resp);
74 /* Set PS State to Deactivated */
75 (void) tcore_context_set_state(ps_context, CONTEXT_STATE_DEACTIVATED);
79 static gboolean on_event_dun_call_notification(CoreObject *o, const void *data, void *user_data)
81 GSList *tokens = NULL;
82 const char *line = NULL;
87 lines = (GSList *) data;
88 if (g_slist_length(lines) != 1) {
89 dbg("Unsolicited message BUT multiple lines");
93 line = (char *) (lines->data);
94 tokens = tcore_at_tok_new(line);
95 value = atoi(g_slist_nth_data(tokens, 0));
99 * 0: DUN Activation in progress
100 * 1: DUN Deactivation in progress
105 case 0: /* FALL THROUGH */
113 /* TODO:- Fill Data structure: 'data' */
114 tcore_server_send_notification(tcore_plugin_ref_server(tcore_object_ref_plugin(o)), o,
115 TNOTI_PS_EXTERNAL_CALL, sizeof(struct tnoti_ps_external_call), &data);
120 /* TODO:- Fill Data structure: 'data' */
121 tcore_server_send_notification(tcore_plugin_ref_server(tcore_object_ref_plugin(o)), o,
122 TNOTI_PS_EXTERNAL_CALL, sizeof(struct tnoti_ps_external_call), &data);
132 tcore_at_tok_free(tokens);
136 static void on_response_undefine_context_cmd(TcorePending *p, int data_len, const void *data, void *user_data)
138 CoreObject *co_ps = NULL;
139 const TcoreATResponse *resp = data;
140 CoreObject *ps_context = user_data;
143 co_ps = tcore_pending_ref_core_object(p);
151 _unable_to_get_pending(co_ps, ps_context);
155 static void send_undefine_context_cmd(CoreObject *co_ps, CoreObject *ps_context)
157 TcoreHal *hal = NULL;
158 TcorePending *pending = NULL;
159 char cmd_str[MAX_AT_CMD_STR_LEN];
163 memset(cmd_str, 0x0, MAX_AT_CMD_STR_LEN);
165 /* FIXME: Before MUX setup, use PHY HAL directly. */
166 hal = tcore_object_get_hal(co_ps);
168 /*Getting Context ID from Core Object*/
169 cid = tcore_context_get_id(ps_context);
171 (void) sprintf(cmd_str, "AT+CGDCONT=%d", cid);
172 dbg("Command: [%s] Command Length: [%d]", cmd_str, strlen(cmd_str));
174 pending = tcore_at_pending_new(co_ps, cmd_str, NULL, TCORE_AT_NO_RESULT,
175 on_response_undefine_context_cmd, ps_context);
176 if (NULL == pending) {
177 err("Unable to get the create a AT request ");
180 tcore_hal_send_request(hal, pending);
181 dbg("Exit: Successfully");
185 dbg("Exit: With error");
186 _unable_to_get_pending(co_ps, ps_context);
191 static void on_setup_pdp(CoreObject *co_ps, int result,
192 const char *netif_name, void *user_data)
194 CoreObject *ps_context = user_data;
195 struct tnoti_ps_call_status data_status = {0};
201 /* Deactivate PDP context */
202 tcore_ps_deactivate_context(co_ps, ps_context, NULL);
206 dbg("Device name: [%s]", netif_name);
208 /* Set Device name */
209 tcore_context_set_ipv4_devname(ps_context, netif_name);
211 /* Set State - CONNECTED */
212 data_status.context_id = tcore_context_get_id(ps_context);
213 data_status.state = PS_DATA_CALL_CONNECTED;
214 dbg("Sending Call Status Notification - Context ID: [%d] Context State: [CONNECTED]", data_status.context_id);
216 /* Send Notification */
217 server = tcore_plugin_ref_server(tcore_object_ref_plugin(co_ps));
218 tcore_server_send_notification(server, co_ps,
219 TNOTI_PS_CALL_STATUS,
220 sizeof(struct tnoti_ps_call_status),
226 static void on_response_get_dns_cmnd(TcorePending *p, int data_len, const void *data, void *user_data)
228 GSList *tokens = NULL;
230 const char *line = NULL;
231 char *dns_prim = NULL;
232 char *dns_sec = NULL;
233 char *token_dns = NULL;
234 int no_pdp_active = 0;
235 CoreObject *ps_context = user_data;
236 const TcoreATResponse *resp = data;
237 CoreObject *co_ps = tcore_pending_ref_core_object(p);
238 int cid = tcore_context_get_id(ps_context);
239 TcoreHal *h = tcore_object_get_hal(co_ps);
243 if (resp->final_response) {
246 dbg("DNS data present in the Response");
247 pRespData = (GSList *) resp->lines;
248 no_pdp_active = g_slist_length(pRespData);
249 dbg("Total Number of Active PS Context: [%d]", no_pdp_active);
250 if (0 == no_pdp_active) {
255 line = (const char *) pRespData->data;
256 dbg("Received Data: [%s]", line);
257 tokens = tcore_at_tok_new(line);
259 /* Check if Context ID is matching */
260 if (cid == atoi(g_slist_nth_data(tokens, 0))) {
261 dbg("Found the DNS details for the Current Context - Context ID: [%d]", cid);
266 tcore_at_tok_free(tokens);
269 /* Move to next line */
270 pRespData = pRespData->next;
273 /* Read primary DNS */
275 token_dns = g_slist_nth_data(tokens, 1);
277 /* Strip off starting " and ending " from this token to read actual PDP address */
278 dns_prim = util_removeQuotes((void *)token_dns);
279 dbg("Primary DNS: [%s]", dns_prim);
282 /* Read Secondary DNS */
284 token_dns = g_slist_nth_data(tokens, 2);
286 /* Strip off starting " and ending " from this token to read actual PDP address */
287 dns_sec = util_removeQuotes((void *)token_dns);
288 dbg("Secondary DNS: [%s]", dns_sec);
291 if ((g_strcmp0("0.0.0.0", dns_prim) == 0)
292 && (g_strcmp0("0.0.0.0", dns_sec) == 0)) {
298 tcore_at_tok_free(tokens);
304 /* Set DNS Address */
305 tcore_context_set_ipv4_dns(ps_context, dns_prim, dns_sec);
309 tcore_at_tok_free(tokens);
313 dbg("No data present in the Response");
319 dbg("Adding default DNS");
320 tcore_context_set_ipv4_dns(ps_context, "8.8.8.8", "8.8.4.4");
323 /* Mount network interface */
324 if (tcore_hal_setup_netif(h, co_ps, on_setup_pdp, ps_context, cid, TRUE)
325 != TCORE_RETURN_SUCCESS) {
326 err("Setup network interface failed");
330 dbg("EXIT : Without error");
333 static TReturn send_get_dns_cmd(CoreObject *co_ps, CoreObject *ps_context)
335 TcoreHal *hal = NULL;
336 TcorePending *pending = NULL;
337 char cmd_str[MAX_AT_CMD_STR_LEN];
339 memset(cmd_str, 0x0, MAX_AT_CMD_STR_LEN);
342 hal = tcore_object_get_hal(co_ps);
344 (void) sprintf(cmd_str, "AT+XDNS?");
345 dbg("Command: [%s] Command Length: [%d]", cmd_str, strlen(cmd_str));
347 pending = tcore_at_pending_new(co_ps, cmd_str, "+XDNS", TCORE_AT_MULTILINE,
348 on_response_get_dns_cmnd, ps_context);
349 if (TCORE_RETURN_SUCCESS == tcore_hal_send_request(hal, pending)) {
350 return TCORE_RETURN_SUCCESS;
352 _unable_to_get_pending(co_ps, ps_context);
353 return TCORE_RETURN_FAILURE;
356 static void on_response_get_pdp_address(TcorePending *p, int data_len, const void *data, void *user_data)
358 const TcoreATResponse *resp = data;
359 CoreObject *co_ps = tcore_pending_ref_core_object(p);
360 CoreObject *ps_context = user_data;
361 GSList *tokens = NULL;
363 char *token_pdp_address;
365 if (resp->final_response) {
367 if (resp->lines != NULL) {
368 line = (const char *) resp->lines->data;
369 tokens = tcore_at_tok_new(line);
370 if (g_slist_length(tokens) < 2) {
371 msg("Invalid message");
374 dbg("Received Data: [%s]", line);
376 /* CID is already stored in ps_context, skip over & read PDP address */
377 token_pdp_address = g_slist_nth_data(tokens, 1);
378 token_pdp_address = util_removeQuotes((void *)token_pdp_address);
379 dbg("IP Address: [%s]", token_pdp_address);
381 /* Strip off starting " and ending " from this token to read actual PDP address */
383 (void)tcore_context_set_ipv4_addr(ps_context, (const char *)token_pdp_address);
385 g_free(token_pdp_address);
388 /* Get DNS Address */
389 (void) send_get_dns_cmd(co_ps, ps_context);
393 /*without PDP address we will not be able to start packet service*/
394 tcore_ps_deactivate_context(co_ps, ps_context, NULL);
397 tcore_at_tok_free(tokens);
401 static TReturn send_get_pdp_address_cmd(CoreObject *co_ps, CoreObject *ps_context)
403 TcoreHal *hal = NULL;
404 TcorePending *pending = NULL;
405 unsigned int cid = PS_INVALID_CID;
406 char cmd_str[MAX_AT_CMD_STR_LEN] = {0};
409 hal = tcore_object_get_hal(co_ps);
411 cid = tcore_context_get_id(ps_context);
412 (void) sprintf(cmd_str, "AT+CGPADDR=%d", cid);
413 dbg("Command: [%s] Command Length: [%d]", cmd_str, strlen(cmd_str));
415 pending = tcore_at_pending_new(co_ps, cmd_str, "+CGPADDR", TCORE_AT_SINGLELINE,
416 on_response_get_pdp_address, ps_context);
417 if (TCORE_RETURN_SUCCESS == tcore_hal_send_request(hal, pending)) {
418 return TCORE_RETURN_SUCCESS;
420 _unable_to_get_pending(co_ps, ps_context);
421 return TCORE_RETURN_FAILURE;
424 static void on_response_send_pdp_activate_cmd(TcorePending *p, int data_len, const void *data, void *user_data)
426 CoreObject *co_ps = NULL;
427 const TcoreATResponse *resp = data;
428 CoreObject *ps_context = user_data;
431 cid = tcore_context_get_id(ps_context);
438 co_ps = tcore_pending_ref_core_object(p);
443 /* Getting the IP address and DNS from the modem */
444 dbg("Getting IP Address");
445 (void) send_get_pdp_address_cmd(co_ps, ps_context);
448 dbg("Unable to activate PDP context - Context ID: [%d]", cid);
449 dbg("Undefining PDP context");
450 (void) tcore_context_set_state(ps_context, CONTEXT_STATE_DEACTIVATED);
451 send_undefine_context_cmd(co_ps, ps_context);
456 _unable_to_get_pending(co_ps, ps_context);
461 static TReturn send_pdp_activate_cmd(CoreObject *co_ps, CoreObject *ps_context)
463 TcoreHal *hal = NULL;
464 TcorePending *pending = NULL;
465 char cmd_str[MAX_AT_CMD_STR_LEN] = {0};
468 /* FIXME: Before MUX setup, use PHY HAL directly. */
469 hal = tcore_object_get_hal(co_ps);
471 /*Getting Context ID from Core Object*/
472 cid = tcore_context_get_id(ps_context);
473 (void) sprintf(cmd_str, "AT+CGACT=%d,%d", AT_PDP_ACTIVATE, cid);
474 dbg("Command: [%s] Command Length: [%d]", cmd_str, strlen(cmd_str));
476 pending = tcore_at_pending_new(co_ps, cmd_str, NULL, TCORE_AT_NO_RESULT,
477 on_response_send_pdp_activate_cmd, ps_context);
478 if (TCORE_RETURN_SUCCESS == tcore_hal_send_request(hal, pending)) {
479 return TCORE_RETURN_SUCCESS;
481 _unable_to_get_pending(co_ps, ps_context);
482 return TCORE_RETURN_FAILURE;
485 static TReturn activate_ps_context(CoreObject *co_ps, CoreObject *ps_context, void *user_data)
488 return send_pdp_activate_cmd(co_ps, ps_context);
491 static void on_response_xdns_enable_cmd(TcorePending *p, int data_len, const void *data, void *user_data)
493 TcoreATResponse *resp = (TcoreATResponse *) data;
494 CoreObject *co_ps = tcore_pending_ref_core_object(p);
495 CoreObject *ps_context = user_data;
496 struct tnoti_ps_call_status noti = {0};
501 cid = tcore_context_get_id(ps_context);
505 dbg("DNS address getting is Enabled");
506 noti.context_id = cid;
507 noti.state = PS_DATA_CALL_CTX_DEFINED;
510 noti.context_id = cid;
511 noti.state = PS_DATA_CALL_NOT_CONNECTED;
512 /*If response to enable the DNS NOK then we will use google DNS for the PDP context*/
515 tcore_server_send_notification(tcore_plugin_ref_server(tcore_object_ref_plugin(co_ps)), co_ps,
516 TNOTI_PS_CALL_STATUS, sizeof(struct tnoti_ps_call_status), ¬i);
520 static TReturn send_xdns_enable_cmd(CoreObject *co_ps, CoreObject *ps_context)
522 TcoreHal *hal = NULL;
523 TcorePending *pending = NULL;
525 char cmd_str[MAX_AT_CMD_STR_LEN];
528 memset(cmd_str, 0x0, MAX_AT_CMD_STR_LEN);
530 hal = tcore_object_get_hal(co_ps);
531 cid = tcore_context_get_id(ps_context);
533 (void) sprintf(cmd_str, "AT+XDNS=%d,%d", cid, AT_XDNS_ENABLE);
534 dbg("Command: [%s] Command Length: [%d]", cmd_str, strlen(cmd_str));
536 pending = tcore_at_pending_new(co_ps, cmd_str, NULL, TCORE_AT_NO_RESULT,
537 on_response_xdns_enable_cmd, ps_context);
538 if (TCORE_RETURN_SUCCESS == tcore_hal_send_request(hal, pending)) {
539 return TCORE_RETURN_SUCCESS;
541 _unable_to_get_pending(co_ps, ps_context);
542 return TCORE_RETURN_FAILURE;
545 static void on_response_define_pdp_context(TcorePending *p, int data_len, const void *data, void *user_data)
547 const TcoreATResponse *resp = data;
548 CoreObject *ps_context = (CoreObject *) user_data;
549 CoreObject *co_ps = tcore_pending_ref_core_object(p);
554 send_xdns_enable_cmd(co_ps, ps_context);
557 _unable_to_get_pending(co_ps, ps_context);
563 static TReturn define_ps_context(CoreObject *co_ps, CoreObject *ps_context, void *user_data)
565 TcoreHal *hal = NULL;
566 TcorePending *pending = NULL;
568 char cmd_str[MAX_AT_CMD_STR_LEN] = {0};
569 char pdp_type_str[10] = {0};
570 unsigned int cid = PS_INVALID_CID;
571 enum co_context_type pdp_type;
572 enum co_context_d_comp d_comp;
573 enum co_context_h_comp h_comp;
577 cid = tcore_context_get_id(ps_context);
578 pdp_type = tcore_context_get_type(ps_context);
579 d_comp = tcore_context_get_data_compression(ps_context);
580 h_comp = tcore_context_get_header_compression(ps_context);
581 apn = tcore_context_get_apn(ps_context);
583 hal = tcore_object_get_hal(co_ps);
585 case CONTEXT_TYPE_X25:
587 dbg("CONTEXT_TYPE_X25");
588 strcpy(pdp_type_str, "X.25");
592 case CONTEXT_TYPE_IP:
594 dbg("CONTEXT_TYPE_IP");
595 strcpy(pdp_type_str, "IP");
599 case CONTEXT_TYPE_PPP:
601 dbg("CONTEXT_TYPE_PPP");
602 strcpy(pdp_type_str, "PPP");
606 case CONTEXT_TYPE_IPV6:
608 dbg("CONTEXT_TYPE_IPV6");
609 strcpy(pdp_type_str, "IPV6");
615 /*PDP Type not supported supported*/
616 dbg("Unsupported PDP type: %d returning ", pdp_type);
617 return TCORE_RETURN_FAILURE;
620 dbg("Activating context for CID: %d", cid);
621 (void) sprintf(cmd_str, "AT+CGDCONT=%d,\"%s\",\"%s\",,%d,%d", cid, pdp_type_str, apn, d_comp, h_comp);
622 dbg("Command: [%s] Command Length: [%d]", cmd_str, strlen(cmd_str));
624 pending = tcore_at_pending_new(co_ps, cmd_str, NULL, TCORE_AT_NO_RESULT,
625 on_response_define_pdp_context, ps_context);
626 if (TCORE_RETURN_SUCCESS == tcore_hal_send_request(hal, pending)) {
627 return TCORE_RETURN_SUCCESS;
629 _unable_to_get_pending(co_ps, ps_context);
630 return TCORE_RETURN_FAILURE;
634 static struct tcore_ps_operations ps_ops = {
635 .define_context = define_ps_context,
636 .activate_context = activate_ps_context,
637 /* Use AT_standard entry point */
638 .deactivate_context = NULL
641 gboolean s_ps_init(TcorePlugin *cp, CoreObject *co_ps)
643 TcorePlugin *plugin = tcore_object_ref_plugin(co_ps);
647 tcore_ps_override_ops(co_ps, &ps_ops);
650 * AT_standard handles standard CGEV notifications:
651 * tcore_object_override_callback(co, "+CGEV", on_cgev_notification, NULL);
652 * no need to handle it here.
655 tcore_object_override_callback(co_ps, "+XNOTIFYDUNSTATUS", on_event_dun_call_notification, plugin);
662 void s_ps_exit(TcorePlugin *cp, CoreObject *co_ps)