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_mount_netif(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);
199 if (tcore_util_netif(netif_name, TRUE) != TCORE_RETURN_SUCCESS) {
200 dbg("disabling network interface failed");
204 server = tcore_plugin_ref_server(tcore_object_ref_plugin(co_ps));
206 data_status.context_id = tcore_context_get_id(ps_context);
207 data_status.state = PS_DATA_CALL_CONNECTED;
209 tcore_server_send_notification(server, co_ps,
210 TNOTI_PS_CALL_STATUS,
211 sizeof(struct tnoti_ps_call_status),
217 static void on_response_get_dns_cmnd(TcorePending *p, int data_len, const void *data, void *user_data)
219 GSList *tokens = NULL;
221 const char *line = NULL;
222 char *dns_prim = NULL;
223 char *dns_sec = NULL;
224 char *token_dns = NULL;
225 int no_pdp_active = 0;
226 CoreObject *ps_context = user_data;
227 const TcoreATResponse *resp = data;
228 CoreObject *co_ps = tcore_pending_ref_core_object(p);
229 int cid = tcore_context_get_id(ps_context);
230 TcoreHal *h = tcore_object_get_hal(co_ps);
234 if (resp->final_response) {
237 dbg("DNS data present in the Response");
238 pRespData = (GSList *) resp->lines;
239 no_pdp_active = g_slist_length(pRespData);
240 dbg("Total Number of Active PS Context :- %d", no_pdp_active);
241 if (0 == no_pdp_active) {
245 dbg("traversing the DNS data for each active context");
246 line = (const char *) pRespData->data;
247 dbg("Response->lines->data :%s", line);
248 tokens = tcore_at_tok_new(line);
249 if (cid == atoi(g_slist_nth_data(tokens, 0))) {
250 dbg("Found the DNS details for the Current context");
251 dbg("Context Id of The Context : %d", atoi(g_slist_nth_data(tokens, 0)));
254 tcore_at_tok_free(tokens);
256 pRespData = pRespData->next;
258 { /* Read primary DNS */
259 token_dns = g_slist_nth_data(tokens, 1);
260 /* Strip off starting " and ending " from this token to read actual PDP address */
261 dns_prim = util_removeQuotes((void *) token_dns);
262 dbg("Token_dns :%s", token_dns);
263 dbg("Primary DNS :- %s", dns_prim);
265 { /* Read Secondary DNS */
266 token_dns = g_slist_nth_data(tokens, 2);
267 dns_sec = util_removeQuotes((void *) token_dns);
269 dbg("Token_dns :%s", token_dns);
270 dbg("Secondary DNS :- %s", dns_sec);
273 tcore_context_set_ipv4_dns(ps_context, dns_prim, dns_sec);
277 tcore_at_tok_free(tokens);
281 dbg("No data present in the Response");
287 dbg("Adding default DNS");
289 tcore_context_set_ipv4_dns(ps_context, "8.8.8.8", "8.8.4.4");
293 /* mount network interface */
294 if (tcore_hal_setup_netif(h, co_ps, on_mount_netif, ps_context, cid, TRUE)
295 != TCORE_RETURN_SUCCESS) {
296 err("Setup network interface failed");
300 dbg("EXIT : Without error");
304 static TReturn send_get_dns_cmd(CoreObject *co_ps, CoreObject *ps_context)
306 TcoreHal *hal = NULL;
307 TcorePending *pending = NULL;
308 char cmd_str[MAX_AT_CMD_STR_LEN];
310 memset(cmd_str, 0x0, MAX_AT_CMD_STR_LEN);
313 hal = tcore_object_get_hal(co_ps);
315 (void) sprintf(cmd_str, "AT+XDNS?");
316 pending = tcore_at_pending_new(co_ps, cmd_str, "+XDNS", TCORE_AT_MULTILINE,
317 on_response_get_dns_cmnd, ps_context);
318 if (TCORE_RETURN_SUCCESS == tcore_hal_send_request(hal, pending)) {
319 return TCORE_RETURN_SUCCESS;
321 _unable_to_get_pending(co_ps, ps_context);
322 return TCORE_RETURN_FAILURE;
325 static void on_response_get_pdp_address(TcorePending *p, int data_len, const void *data, void *user_data)
327 const TcoreATResponse *resp = data;
328 CoreObject *co_ps = tcore_pending_ref_core_object(p);
329 CoreObject *ps_context = user_data;
330 GSList *tokens = NULL;
332 char *token_pdp_address;
334 if (resp->final_response) {
336 if (resp->lines != NULL) {
337 dbg("resp->lines present ");
338 line = (const char *) resp->lines->data;
339 tokens = tcore_at_tok_new(line);
340 if (g_slist_length(tokens) < 2) {
341 msg("invalid message");
344 dbg("line:- %s", line);
345 /* CID is already stored in ps_context, skip over & read PDP address */
346 token_pdp_address = g_slist_nth_data(tokens, 1);
348 dbg("token_pdp_address :- %s", token_pdp_address);
349 /* Strip off starting " and ending " from this token to read actual PDP address */
350 (void) tcore_context_set_ipv4_addr(ps_context, (const char *)token_pdp_address);
353 (void) send_get_dns_cmd(co_ps, ps_context);
356 /*without PDP address we will not be able to start packet service*/
357 tcore_ps_deactivate_context(co_ps, ps_context, NULL);
360 tcore_at_tok_free(tokens);
364 static TReturn send_get_pdp_address_cmd(CoreObject *co_ps, CoreObject *ps_context)
366 TcoreHal *hal = NULL;
367 TcorePending *pending = NULL;
368 unsigned int cid = PS_INVALID_CID;
369 char cmd_str[MAX_AT_CMD_STR_LEN] = {0};
372 hal = tcore_object_get_hal(co_ps);
374 cid = tcore_context_get_id(ps_context);
375 (void) sprintf(cmd_str, "AT+CGPADDR=%d", cid);
376 pending = tcore_at_pending_new(co_ps, cmd_str, "+CGPADDR", TCORE_AT_SINGLELINE,
377 on_response_get_pdp_address, ps_context);
378 if (TCORE_RETURN_SUCCESS == tcore_hal_send_request(hal, pending)) {
379 return TCORE_RETURN_SUCCESS;
381 _unable_to_get_pending(co_ps, ps_context);
382 return TCORE_RETURN_FAILURE;
385 static void on_response_send_pdp_activate_cmd(TcorePending *p, int data_len, const void *data, void *user_data)
387 CoreObject *co_ps = NULL;
388 const TcoreATResponse *resp = data;
389 CoreObject *ps_context = user_data;
392 cid = tcore_context_get_id(ps_context);
399 co_ps = tcore_pending_ref_core_object(p);
403 /*getting the IP address and DNS from the modem*/
404 dbg("Getting the IP Address");
405 (void) send_get_pdp_address_cmd(co_ps, ps_context);
408 dbg("Unable to actiavte PDP context for CID: %d ", cid);
409 dbg("Undefineing the PDP context");
410 (void) tcore_context_set_state(ps_context, CONTEXT_STATE_DEACTIVATED);
411 send_undefine_context_cmd(co_ps, ps_context);
416 _unable_to_get_pending(co_ps, ps_context);
421 static TReturn send_pdp_activate_cmd(CoreObject *co_ps, CoreObject *ps_context)
423 TcoreHal *hal = NULL;
424 TcorePending *pending = NULL;
425 char cmd_str[MAX_AT_CMD_STR_LEN] = {0};
428 /* FIXME: Before MUX setup, use PHY HAL directly. */
429 hal = tcore_object_get_hal(co_ps);
431 /*Getting Context ID from Core Object*/
432 cid = tcore_context_get_id(ps_context);
433 (void) sprintf(cmd_str, "AT+CGACT=%d,%d", AT_PDP_ACTIVATE, cid);
434 pending = tcore_at_pending_new(co_ps, cmd_str, NULL, TCORE_AT_NO_RESULT,
435 on_response_send_pdp_activate_cmd, ps_context);
436 if (TCORE_RETURN_SUCCESS == tcore_hal_send_request(hal, pending)) {
437 return TCORE_RETURN_SUCCESS;
439 _unable_to_get_pending(co_ps, ps_context);
440 return TCORE_RETURN_FAILURE;
443 static TReturn activate_ps_context(CoreObject *co_ps, CoreObject *ps_context, void *user_data)
446 return send_pdp_activate_cmd(co_ps, ps_context);
449 static void on_response_xdns_enable_cmd(TcorePending *p, int data_len, const void *data, void *user_data)
451 TcoreATResponse *resp = (TcoreATResponse *) data;
452 CoreObject *co_ps = tcore_pending_ref_core_object(p);
453 CoreObject *ps_context = user_data;
454 struct tnoti_ps_call_status noti = {0};
459 cid = tcore_context_get_id(ps_context);
463 dbg("DNS address getting is Enabled");
464 noti.context_id = cid;
465 noti.state = PS_DATA_CALL_CTX_DEFINED;
468 noti.context_id = cid;
469 noti.state = PS_DATA_CALL_NOT_CONNECTED;
470 /*If response to enable the DNS NOK then we will use google DNS for the PDP context*/
473 tcore_server_send_notification(tcore_plugin_ref_server(tcore_object_ref_plugin(co_ps)), co_ps,
474 TNOTI_PS_CALL_STATUS, sizeof(struct tnoti_ps_call_status), ¬i);
478 static TReturn send_xdns_enable_cmd(CoreObject *co_ps, CoreObject *ps_context)
480 TcoreHal *hal = NULL;
481 TcorePending *pending = NULL;
483 char cmd_str[MAX_AT_CMD_STR_LEN];
486 memset(cmd_str, 0x0, MAX_AT_CMD_STR_LEN);
488 hal = tcore_object_get_hal(co_ps);
489 cid = tcore_context_get_id(ps_context);
491 (void) sprintf(cmd_str, "AT+XDNS=%d,%d", cid, AT_XDNS_ENABLE);
492 pending = tcore_at_pending_new(co_ps, cmd_str, NULL, TCORE_AT_NO_RESULT,
493 on_response_xdns_enable_cmd, ps_context);
494 if (TCORE_RETURN_SUCCESS == tcore_hal_send_request(hal, pending)) {
495 return TCORE_RETURN_SUCCESS;
497 _unable_to_get_pending(co_ps, ps_context);
498 return TCORE_RETURN_FAILURE;
501 static void on_response_define_pdp_context(TcorePending *p, int data_len, const void *data, void *user_data)
503 const TcoreATResponse *resp = data;
504 CoreObject *ps_context = (CoreObject *) user_data;
505 CoreObject *co_ps = tcore_pending_ref_core_object(p);
510 send_xdns_enable_cmd(co_ps, ps_context);
513 _unable_to_get_pending(co_ps, ps_context);
519 static TReturn define_ps_context(CoreObject *co_ps, CoreObject *ps_context, void *user_data)
521 TcoreHal *hal = NULL;
522 TcorePending *pending = NULL;
524 char cmd_str[MAX_AT_CMD_STR_LEN] = {0};
525 char pdp_type_str[10] = {0};
526 unsigned int cid = PS_INVALID_CID;
527 enum co_context_type pdp_type;
528 enum co_context_d_comp d_comp;
529 enum co_context_h_comp h_comp;
533 cid = tcore_context_get_id(ps_context);
534 pdp_type = tcore_context_get_type(ps_context);
535 d_comp = tcore_context_get_data_compression(ps_context);
536 h_comp = tcore_context_get_header_compression(ps_context);
537 apn = tcore_context_get_apn(ps_context);
539 hal = tcore_object_get_hal(co_ps);
541 case CONTEXT_TYPE_X25:
543 dbg("CONTEXT_TYPE_X25");
544 strcpy(pdp_type_str, "X.25");
548 case CONTEXT_TYPE_IP:
550 dbg("CONTEXT_TYPE_IP");
551 strcpy(pdp_type_str, "IP");
555 case CONTEXT_TYPE_PPP:
557 dbg("CONTEXT_TYPE_PPP");
558 strcpy(pdp_type_str, "PPP");
562 case CONTEXT_TYPE_IPV6:
564 dbg("CONTEXT_TYPE_IPV6");
565 strcpy(pdp_type_str, "IPV6");
571 /*PDP Type not supported supported*/
572 dbg("Unsupported PDP type :- %d returning ", pdp_type);
573 return TCORE_RETURN_FAILURE;
576 dbg("Activating context for CID :- %d", cid);
577 (void) sprintf(cmd_str, "AT+CGDCONT=%d,\"%s\",\"%s\",,%d,%d", cid, pdp_type_str, apn, d_comp, h_comp);
579 pending = tcore_at_pending_new(co_ps, cmd_str, NULL, TCORE_AT_NO_RESULT,
580 on_response_define_pdp_context, ps_context);
581 if (TCORE_RETURN_SUCCESS == tcore_hal_send_request(hal, pending)) {
582 return TCORE_RETURN_SUCCESS;
584 _unable_to_get_pending(co_ps, ps_context);
585 return TCORE_RETURN_FAILURE;
589 static struct tcore_ps_operations ps_ops = {
590 .define_context = define_ps_context,
591 .activate_context = activate_ps_context,
592 /* Use AT_standard entry point */
593 .deactivate_context = NULL
596 gboolean s_ps_init(TcorePlugin *cp, CoreObject *co_ps)
598 TcorePlugin *plugin = tcore_object_ref_plugin(co_ps);
602 tcore_ps_override_ops(co_ps, &ps_ops);
605 * AT_standard handles standard CGEV notifications:
606 * tcore_object_override_callback(co, "+CGEV", on_cgev_notification, NULL);
607 * no need to handle it here.
610 tcore_object_override_callback(co_ps, "+XNOTIFYDUNSTATUS", on_event_dun_call_notification, plugin);
617 void s_ps_exit(TcorePlugin *cp, CoreObject *co_ps)