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};
74 data_resp.context_id = tcore_context_get_id(ps_context);
75 data_resp.state = PS_DATA_CALL_NOT_CONNECTED; /*check value of state*/
76 tcore_server_send_notification(tcore_plugin_ref_server(tcore_object_ref_plugin(co_ps)), co_ps,
77 TNOTI_PS_CALL_STATUS, sizeof(struct tnoti_ps_call_status), &data_resp);
78 (void) tcore_context_set_state(ps_context, CONTEXT_STATE_DEACTIVATED);
82 static gboolean on_event_dun_call_notification(CoreObject *o, const void *data, void *user_data)
84 GSList *tokens = NULL;
85 const char *line = NULL;
90 lines = (GSList *) data;
91 if (1 != g_slist_length(lines)) {
92 dbg("unsolicited msg but multiple line");
95 line = (char *) (lines->data);
96 tokens = tcore_at_tok_new(line);
97 value = atoi(g_slist_nth_data(tokens, 0));
101 0: DUN activation in progress
102 1: DUN deactivation in progress
107 case 0: /*Fall Through*/
115 /*To Do:- Fill Data structure : data*/
116 tcore_server_send_notification(tcore_plugin_ref_server(tcore_object_ref_plugin(o)), o,
117 TNOTI_PS_EXTERNAL_CALL, sizeof(struct tnoti_ps_external_call), &data);
122 /*To Do:- Fill Data structure : data*/
123 tcore_server_send_notification(tcore_plugin_ref_server(tcore_object_ref_plugin(o)), o,
124 TNOTI_PS_EXTERNAL_CALL, sizeof(struct tnoti_ps_external_call), &data);
132 if (NULL != tokens) {
133 tcore_at_tok_free(tokens);
137 static void on_response_undefine_context_cmd(TcorePending *p, int data_len, const void *data, void *user_data)
139 CoreObject *co_ps = NULL;
140 const TcoreATResponse *resp = data;
141 CoreObject *ps_context = user_data;
143 co_ps = tcore_pending_ref_core_object(p);
149 _unable_to_get_pending(co_ps, ps_context);
153 static void send_undefine_context_cmd(CoreObject *co_ps, CoreObject *ps_context)
155 TcoreHal *hal = NULL;
156 TcorePending *pending = NULL;
157 char cmd_str[MAX_AT_CMD_STR_LEN];
161 memset(cmd_str, 0x0, MAX_AT_CMD_STR_LEN);
163 /* FIXME: Before MUX setup, use PHY HAL directly. */
164 hal = tcore_object_get_hal(co_ps);
166 /*Getting Context ID from Core Object*/
167 cid = tcore_context_get_id(ps_context);
169 (void) sprintf(cmd_str, "AT+CGDCONT=%d", cid);
170 pending = tcore_at_pending_new(co_ps, cmd_str, NULL, TCORE_AT_NO_RESULT,
171 on_response_undefine_context_cmd, ps_context);
172 if (NULL == pending) {
173 err("Unable to get the create a AT request ");
176 tcore_hal_send_request(hal, pending);
177 dbg("Exit: Successfully");
181 dbg("Exit: With error");
182 _unable_to_get_pending(co_ps, ps_context);
187 static void on_setup_pdp(CoreObject *co_ps, const char *netif_name,
190 CoreObject *ps_context = user_data;
191 struct tnoti_ps_call_status data_status = {0};
196 dbg("devname = [%s]", netif_name);
198 tcore_context_set_ipv4_devname(ps_context, netif_name);
200 server = tcore_plugin_ref_server(tcore_object_ref_plugin(co_ps));
202 data_status.context_id = tcore_context_get_id(ps_context);
203 data_status.state = PS_DATA_CALL_CONNECTED;
205 tcore_server_send_notification(server, co_ps,
206 TNOTI_PS_CALL_STATUS,
207 sizeof(struct tnoti_ps_call_status),
213 static void on_response_get_dns_cmnd(TcorePending *p, int data_len, const void *data, void *user_data)
215 GSList *tokens = NULL;
217 const char *line = NULL;
218 char *dns_prim = NULL;
219 char *dns_sec = NULL;
220 char *token_dns = NULL;
221 int no_pdp_active = 0;
222 CoreObject *ps_context = user_data;
223 const TcoreATResponse *resp = data;
224 CoreObject *co_ps = tcore_pending_ref_core_object(p);
225 int cid = tcore_context_get_id(ps_context);
226 TcoreHal *h = tcore_object_get_hal(co_ps);
230 if (resp->final_response) {
233 dbg("DNS data present in the Response");
234 pRespData = (GSList *) resp->lines;
235 no_pdp_active = g_slist_length(pRespData);
236 dbg("Total Number of Active PS Context :- %d", no_pdp_active);
237 if (0 == no_pdp_active) {
241 dbg("traversing the DNS data for each active context");
242 line = (const char *) pRespData->data;
243 dbg("Response->lines->data :%s", line);
244 tokens = tcore_at_tok_new(line);
245 if (cid == atoi(g_slist_nth_data(tokens, 0))) {
246 dbg("Found the DNS details for the Current context");
247 dbg("Context Id of The Context : %d", atoi(g_slist_nth_data(tokens, 0)));
250 tcore_at_tok_free(tokens);
252 pRespData = pRespData->next;
254 { /* Read primary DNS */
255 token_dns = g_slist_nth_data(tokens, 1);
256 /* Strip off starting " and ending " from this token to read actual PDP address */
257 dns_prim = util_removeQuotes((void *) token_dns);
258 dbg("Token_dns :%s", token_dns);
259 dbg("Primary DNS :- %s", dns_prim);
261 { /* Read Secondary DNS */
262 token_dns = g_slist_nth_data(tokens, 2);
263 dns_sec = util_removeQuotes((void *) token_dns);
265 dbg("Token_dns :%s", token_dns);
266 dbg("Secondary DNS :- %s", dns_sec);
269 if ((g_strcmp0("0.0.0.0", dns_prim) == 0)
270 && (g_strcmp0("0.0.0.0", dns_sec) == 0)) {
276 tcore_at_tok_free(tokens);
282 tcore_context_set_ipv4_dns(ps_context, dns_prim, dns_sec);
286 tcore_at_tok_free(tokens);
290 dbg("No data present in the Response");
296 dbg("Adding default DNS");
298 tcore_context_set_ipv4_dns(ps_context, "8.8.8.8", "8.8.4.4");
302 /* mount network interface */
303 if (tcore_hal_setup_netif(h, co_ps, on_setup_pdp, ps_context, cid, TRUE)
304 != TCORE_RETURN_SUCCESS) {
305 err("Setup network interface failed");
309 dbg("EXIT : Without error");
313 static TReturn send_get_dns_cmd(CoreObject *co_ps, CoreObject *ps_context)
315 TcoreHal *hal = NULL;
316 TcorePending *pending = NULL;
317 char cmd_str[MAX_AT_CMD_STR_LEN];
319 memset(cmd_str, 0x0, MAX_AT_CMD_STR_LEN);
322 hal = tcore_object_get_hal(co_ps);
324 (void) sprintf(cmd_str, "AT+XDNS?");
325 pending = tcore_at_pending_new(co_ps, cmd_str, "+XDNS", TCORE_AT_MULTILINE,
326 on_response_get_dns_cmnd, ps_context);
327 if (TCORE_RETURN_SUCCESS == tcore_hal_send_request(hal, pending)) {
328 return TCORE_RETURN_SUCCESS;
330 _unable_to_get_pending(co_ps, ps_context);
331 return TCORE_RETURN_FAILURE;
334 static void on_response_get_pdp_address(TcorePending *p, int data_len, const void *data, void *user_data)
336 const TcoreATResponse *resp = data;
337 CoreObject *co_ps = tcore_pending_ref_core_object(p);
338 CoreObject *ps_context = user_data;
339 GSList *tokens = NULL;
341 char *token_pdp_address;
342 char *real_pdp_address;
344 if (resp->final_response) {
346 if (resp->lines != NULL) {
347 dbg("resp->lines present ");
348 line = (const char *) resp->lines->data;
349 tokens = tcore_at_tok_new(line);
350 if (g_slist_length(tokens) < 2) {
351 msg("invalid message");
354 dbg("line:- %s", line);
355 /* CID is already stored in ps_context, skip over & read PDP address */
356 token_pdp_address = g_slist_nth_data(tokens, 1);
357 real_pdp_address = tcore_at_tok_extract(token_pdp_address);
359 dbg("PDP address: %s", real_pdp_address);
360 /* Strip off starting " and ending " from this token to read actual PDP address */
361 (void) tcore_context_set_ipv4_addr(ps_context, (const char *)real_pdp_address);
362 g_free(real_pdp_address);
365 (void) send_get_dns_cmd(co_ps, ps_context);
368 /*without PDP address we will not be able to start packet service*/
369 tcore_ps_deactivate_context(co_ps, ps_context, NULL);
372 tcore_at_tok_free(tokens);
376 static TReturn send_get_pdp_address_cmd(CoreObject *co_ps, CoreObject *ps_context)
378 TcoreHal *hal = NULL;
379 TcorePending *pending = NULL;
380 unsigned int cid = PS_INVALID_CID;
381 char cmd_str[MAX_AT_CMD_STR_LEN] = {0};
384 hal = tcore_object_get_hal(co_ps);
386 cid = tcore_context_get_id(ps_context);
387 (void) sprintf(cmd_str, "AT+CGPADDR=%d", cid);
388 pending = tcore_at_pending_new(co_ps, cmd_str, "+CGPADDR", TCORE_AT_SINGLELINE,
389 on_response_get_pdp_address, ps_context);
390 if (TCORE_RETURN_SUCCESS == tcore_hal_send_request(hal, pending)) {
391 return TCORE_RETURN_SUCCESS;
393 _unable_to_get_pending(co_ps, ps_context);
394 return TCORE_RETURN_FAILURE;
397 static void on_response_send_pdp_activate_cmd(TcorePending *p, int data_len, const void *data, void *user_data)
399 CoreObject *co_ps = NULL;
400 const TcoreATResponse *resp = data;
401 CoreObject *ps_context = user_data;
404 cid = tcore_context_get_id(ps_context);
411 co_ps = tcore_pending_ref_core_object(p);
415 /*getting the IP address and DNS from the modem*/
416 dbg("Getting the IP Address");
417 (void) send_get_pdp_address_cmd(co_ps, ps_context);
420 dbg("Unable to actiavte PDP context for CID: %d ", cid);
421 dbg("Undefineing the PDP context");
422 (void) tcore_context_set_state(ps_context, CONTEXT_STATE_DEACTIVATED);
423 send_undefine_context_cmd(co_ps, ps_context);
428 _unable_to_get_pending(co_ps, ps_context);
433 static TReturn send_pdp_activate_cmd(CoreObject *co_ps, CoreObject *ps_context)
435 TcoreHal *hal = NULL;
436 TcorePending *pending = NULL;
437 char cmd_str[MAX_AT_CMD_STR_LEN] = {0};
440 /* FIXME: Before MUX setup, use PHY HAL directly. */
441 hal = tcore_object_get_hal(co_ps);
443 /*Getting Context ID from Core Object*/
444 cid = tcore_context_get_id(ps_context);
445 (void) sprintf(cmd_str, "AT+CGACT=%d,%d", AT_PDP_ACTIVATE, cid);
446 pending = tcore_at_pending_new(co_ps, cmd_str, NULL, TCORE_AT_NO_RESULT,
447 on_response_send_pdp_activate_cmd, ps_context);
448 if (TCORE_RETURN_SUCCESS == tcore_hal_send_request(hal, pending)) {
449 return TCORE_RETURN_SUCCESS;
451 _unable_to_get_pending(co_ps, ps_context);
452 return TCORE_RETURN_FAILURE;
455 static TReturn activate_ps_context(CoreObject *co_ps, CoreObject *ps_context, void *user_data)
458 return send_pdp_activate_cmd(co_ps, ps_context);
461 static void on_response_xdns_enable_cmd(TcorePending *p, int data_len, const void *data, void *user_data)
463 TcoreATResponse *resp = (TcoreATResponse *) data;
464 CoreObject *co_ps = tcore_pending_ref_core_object(p);
465 CoreObject *ps_context = user_data;
466 struct tnoti_ps_call_status noti = {0};
471 cid = tcore_context_get_id(ps_context);
475 dbg("DNS address getting is Enabled");
476 noti.context_id = cid;
477 noti.state = PS_DATA_CALL_CTX_DEFINED;
480 noti.context_id = cid;
481 noti.state = PS_DATA_CALL_NOT_CONNECTED;
482 /*If response to enable the DNS NOK then we will use google DNS for the PDP context*/
485 tcore_server_send_notification(tcore_plugin_ref_server(tcore_object_ref_plugin(co_ps)), co_ps,
486 TNOTI_PS_CALL_STATUS, sizeof(struct tnoti_ps_call_status), ¬i);
490 static TReturn send_xdns_enable_cmd(CoreObject *co_ps, CoreObject *ps_context)
492 TcoreHal *hal = NULL;
493 TcorePending *pending = NULL;
495 char cmd_str[MAX_AT_CMD_STR_LEN];
498 memset(cmd_str, 0x0, MAX_AT_CMD_STR_LEN);
500 hal = tcore_object_get_hal(co_ps);
501 cid = tcore_context_get_id(ps_context);
503 (void) sprintf(cmd_str, "AT+XDNS=%d,%d", cid, AT_XDNS_ENABLE);
504 pending = tcore_at_pending_new(co_ps, cmd_str, NULL, TCORE_AT_NO_RESULT,
505 on_response_xdns_enable_cmd, ps_context);
506 if (TCORE_RETURN_SUCCESS == tcore_hal_send_request(hal, pending)) {
507 return TCORE_RETURN_SUCCESS;
509 _unable_to_get_pending(co_ps, ps_context);
510 return TCORE_RETURN_FAILURE;
513 static void on_response_define_pdp_context(TcorePending *p, int data_len, const void *data, void *user_data)
515 const TcoreATResponse *resp = data;
516 CoreObject *ps_context = (CoreObject *) user_data;
517 CoreObject *co_ps = tcore_pending_ref_core_object(p);
522 send_xdns_enable_cmd(co_ps, ps_context);
525 _unable_to_get_pending(co_ps, ps_context);
531 static TReturn define_ps_context(CoreObject *co_ps, CoreObject *ps_context, void *user_data)
533 TcoreHal *hal = NULL;
534 TcorePending *pending = NULL;
536 char cmd_str[MAX_AT_CMD_STR_LEN] = {0};
537 char pdp_type_str[10] = {0};
538 unsigned int cid = PS_INVALID_CID;
539 enum co_context_type pdp_type;
540 enum co_context_d_comp d_comp;
541 enum co_context_h_comp h_comp;
545 cid = tcore_context_get_id(ps_context);
546 pdp_type = tcore_context_get_type(ps_context);
547 d_comp = tcore_context_get_data_compression(ps_context);
548 h_comp = tcore_context_get_header_compression(ps_context);
549 apn = tcore_context_get_apn(ps_context);
551 hal = tcore_object_get_hal(co_ps);
553 case CONTEXT_TYPE_X25:
555 dbg("CONTEXT_TYPE_X25");
556 strcpy(pdp_type_str, "X.25");
560 case CONTEXT_TYPE_IP:
562 dbg("CONTEXT_TYPE_IP");
563 strcpy(pdp_type_str, "IP");
567 case CONTEXT_TYPE_PPP:
569 dbg("CONTEXT_TYPE_PPP");
570 strcpy(pdp_type_str, "PPP");
574 case CONTEXT_TYPE_IPV6:
576 dbg("CONTEXT_TYPE_IPV6");
577 strcpy(pdp_type_str, "IPV6");
583 /*PDP Type not supported supported*/
584 dbg("Unsupported PDP type :- %d returning ", pdp_type);
585 return TCORE_RETURN_FAILURE;
588 dbg("Activating context for CID :- %d", cid);
589 (void) sprintf(cmd_str, "AT+CGDCONT=%d,\"%s\",\"%s\",,%d,%d", cid, pdp_type_str, apn, d_comp, h_comp);
591 pending = tcore_at_pending_new(co_ps, cmd_str, NULL, TCORE_AT_NO_RESULT,
592 on_response_define_pdp_context, ps_context);
593 if (TCORE_RETURN_SUCCESS == tcore_hal_send_request(hal, pending)) {
594 return TCORE_RETURN_SUCCESS;
596 _unable_to_get_pending(co_ps, ps_context);
597 return TCORE_RETURN_FAILURE;
601 static struct tcore_ps_operations ps_ops = {
602 .define_context = define_ps_context,
603 .activate_context = activate_ps_context,
604 /* Use AT_standard entry point */
605 .deactivate_context = NULL
608 gboolean s_ps_init(TcorePlugin *cp, CoreObject *co_ps)
610 TcorePlugin *plugin = tcore_object_ref_plugin(co_ps);
614 tcore_ps_override_ops(co_ps, &ps_ops);
617 * AT_standard handles standard CGEV notifications:
618 * tcore_object_override_callback(co, "+CGEV", on_cgev_notification, NULL);
619 * no need to handle it here.
622 tcore_object_override_callback(co_ps, "+XNOTIFYDUNSTATUS", on_event_dun_call_notification, plugin);
629 void s_ps_exit(TcorePlugin *cp, CoreObject *co_ps)