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 tcore_context_set_ipv4_dns(ps_context, dns_prim, dns_sec);
273 tcore_at_tok_free(tokens);
277 dbg("No data present in the Response");
283 dbg("Adding default DNS");
285 tcore_context_set_ipv4_dns(ps_context, "8.8.8.8", "8.8.4.4");
289 /* mount network interface */
290 if (tcore_hal_setup_netif(h, co_ps, on_setup_pdp, ps_context, cid, TRUE)
291 != TCORE_RETURN_SUCCESS) {
292 err("Setup network interface failed");
296 dbg("EXIT : Without error");
300 static TReturn send_get_dns_cmd(CoreObject *co_ps, CoreObject *ps_context)
302 TcoreHal *hal = NULL;
303 TcorePending *pending = NULL;
304 char cmd_str[MAX_AT_CMD_STR_LEN];
306 memset(cmd_str, 0x0, MAX_AT_CMD_STR_LEN);
309 hal = tcore_object_get_hal(co_ps);
311 (void) sprintf(cmd_str, "AT+XDNS?");
312 pending = tcore_at_pending_new(co_ps, cmd_str, "+XDNS", TCORE_AT_MULTILINE,
313 on_response_get_dns_cmnd, ps_context);
314 if (TCORE_RETURN_SUCCESS == tcore_hal_send_request(hal, pending)) {
315 return TCORE_RETURN_SUCCESS;
317 _unable_to_get_pending(co_ps, ps_context);
318 return TCORE_RETURN_FAILURE;
321 static void on_response_get_pdp_address(TcorePending *p, int data_len, const void *data, void *user_data)
323 const TcoreATResponse *resp = data;
324 CoreObject *co_ps = tcore_pending_ref_core_object(p);
325 CoreObject *ps_context = user_data;
326 GSList *tokens = NULL;
328 char *token_pdp_address;
330 if (resp->final_response) {
332 if (resp->lines != NULL) {
333 dbg("resp->lines present ");
334 line = (const char *) resp->lines->data;
335 tokens = tcore_at_tok_new(line);
336 if (g_slist_length(tokens) < 2) {
337 msg("invalid message");
340 dbg("line:- %s", line);
341 /* CID is already stored in ps_context, skip over & read PDP address */
342 token_pdp_address = g_slist_nth_data(tokens, 1);
344 dbg("token_pdp_address :- %s", token_pdp_address);
345 /* Strip off starting " and ending " from this token to read actual PDP address */
346 (void) tcore_context_set_ipv4_addr(ps_context, (const char *)token_pdp_address);
349 (void) send_get_dns_cmd(co_ps, ps_context);
352 /*without PDP address we will not be able to start packet service*/
353 tcore_ps_deactivate_context(co_ps, ps_context, NULL);
356 tcore_at_tok_free(tokens);
360 static TReturn send_get_pdp_address_cmd(CoreObject *co_ps, CoreObject *ps_context)
362 TcoreHal *hal = NULL;
363 TcorePending *pending = NULL;
364 unsigned int cid = PS_INVALID_CID;
365 char cmd_str[MAX_AT_CMD_STR_LEN] = {0};
368 hal = tcore_object_get_hal(co_ps);
370 cid = tcore_context_get_id(ps_context);
371 (void) sprintf(cmd_str, "AT+CGPADDR=%d", cid);
372 pending = tcore_at_pending_new(co_ps, cmd_str, "+CGPADDR", TCORE_AT_SINGLELINE,
373 on_response_get_pdp_address, ps_context);
374 if (TCORE_RETURN_SUCCESS == tcore_hal_send_request(hal, pending)) {
375 return TCORE_RETURN_SUCCESS;
377 _unable_to_get_pending(co_ps, ps_context);
378 return TCORE_RETURN_FAILURE;
381 static void on_response_send_pdp_activate_cmd(TcorePending *p, int data_len, const void *data, void *user_data)
383 CoreObject *co_ps = NULL;
384 const TcoreATResponse *resp = data;
385 CoreObject *ps_context = user_data;
388 cid = tcore_context_get_id(ps_context);
395 co_ps = tcore_pending_ref_core_object(p);
399 /*getting the IP address and DNS from the modem*/
400 dbg("Getting the IP Address");
401 (void) send_get_pdp_address_cmd(co_ps, ps_context);
404 dbg("Unable to actiavte PDP context for CID: %d ", cid);
405 dbg("Undefineing the PDP context");
406 (void) tcore_context_set_state(ps_context, CONTEXT_STATE_DEACTIVATED);
407 send_undefine_context_cmd(co_ps, ps_context);
412 _unable_to_get_pending(co_ps, ps_context);
417 static TReturn send_pdp_activate_cmd(CoreObject *co_ps, CoreObject *ps_context)
419 TcoreHal *hal = NULL;
420 TcorePending *pending = NULL;
421 char cmd_str[MAX_AT_CMD_STR_LEN] = {0};
424 /* FIXME: Before MUX setup, use PHY HAL directly. */
425 hal = tcore_object_get_hal(co_ps);
427 /*Getting Context ID from Core Object*/
428 cid = tcore_context_get_id(ps_context);
429 (void) sprintf(cmd_str, "AT+CGACT=%d,%d", AT_PDP_ACTIVATE, cid);
430 pending = tcore_at_pending_new(co_ps, cmd_str, NULL, TCORE_AT_NO_RESULT,
431 on_response_send_pdp_activate_cmd, ps_context);
432 if (TCORE_RETURN_SUCCESS == tcore_hal_send_request(hal, pending)) {
433 return TCORE_RETURN_SUCCESS;
435 _unable_to_get_pending(co_ps, ps_context);
436 return TCORE_RETURN_FAILURE;
439 static TReturn activate_ps_context(CoreObject *co_ps, CoreObject *ps_context, void *user_data)
442 return send_pdp_activate_cmd(co_ps, ps_context);
445 static void on_response_xdns_enable_cmd(TcorePending *p, int data_len, const void *data, void *user_data)
447 TcoreATResponse *resp = (TcoreATResponse *) data;
448 CoreObject *co_ps = tcore_pending_ref_core_object(p);
449 CoreObject *ps_context = user_data;
450 struct tnoti_ps_call_status noti = {0};
455 cid = tcore_context_get_id(ps_context);
459 dbg("DNS address getting is Enabled");
460 noti.context_id = cid;
461 noti.state = PS_DATA_CALL_CTX_DEFINED;
464 noti.context_id = cid;
465 noti.state = PS_DATA_CALL_NOT_CONNECTED;
466 /*If response to enable the DNS NOK then we will use google DNS for the PDP context*/
469 tcore_server_send_notification(tcore_plugin_ref_server(tcore_object_ref_plugin(co_ps)), co_ps,
470 TNOTI_PS_CALL_STATUS, sizeof(struct tnoti_ps_call_status), ¬i);
474 static TReturn send_xdns_enable_cmd(CoreObject *co_ps, CoreObject *ps_context)
476 TcoreHal *hal = NULL;
477 TcorePending *pending = NULL;
479 char cmd_str[MAX_AT_CMD_STR_LEN];
482 memset(cmd_str, 0x0, MAX_AT_CMD_STR_LEN);
484 hal = tcore_object_get_hal(co_ps);
485 cid = tcore_context_get_id(ps_context);
487 (void) sprintf(cmd_str, "AT+XDNS=%d,%d", cid, AT_XDNS_ENABLE);
488 pending = tcore_at_pending_new(co_ps, cmd_str, NULL, TCORE_AT_NO_RESULT,
489 on_response_xdns_enable_cmd, ps_context);
490 if (TCORE_RETURN_SUCCESS == tcore_hal_send_request(hal, pending)) {
491 return TCORE_RETURN_SUCCESS;
493 _unable_to_get_pending(co_ps, ps_context);
494 return TCORE_RETURN_FAILURE;
497 static void on_response_define_pdp_context(TcorePending *p, int data_len, const void *data, void *user_data)
499 const TcoreATResponse *resp = data;
500 CoreObject *ps_context = (CoreObject *) user_data;
501 CoreObject *co_ps = tcore_pending_ref_core_object(p);
506 send_xdns_enable_cmd(co_ps, ps_context);
509 _unable_to_get_pending(co_ps, ps_context);
515 static TReturn define_ps_context(CoreObject *co_ps, CoreObject *ps_context, void *user_data)
517 TcoreHal *hal = NULL;
518 TcorePending *pending = NULL;
520 char cmd_str[MAX_AT_CMD_STR_LEN] = {0};
521 char pdp_type_str[10] = {0};
522 unsigned int cid = PS_INVALID_CID;
523 enum co_context_type pdp_type;
524 enum co_context_d_comp d_comp;
525 enum co_context_h_comp h_comp;
529 cid = tcore_context_get_id(ps_context);
530 pdp_type = tcore_context_get_type(ps_context);
531 d_comp = tcore_context_get_data_compression(ps_context);
532 h_comp = tcore_context_get_header_compression(ps_context);
533 apn = tcore_context_get_apn(ps_context);
535 hal = tcore_object_get_hal(co_ps);
537 case CONTEXT_TYPE_X25:
539 dbg("CONTEXT_TYPE_X25");
540 strcpy(pdp_type_str, "X.25");
544 case CONTEXT_TYPE_IP:
546 dbg("CONTEXT_TYPE_IP");
547 strcpy(pdp_type_str, "IP");
551 case CONTEXT_TYPE_PPP:
553 dbg("CONTEXT_TYPE_PPP");
554 strcpy(pdp_type_str, "PPP");
558 case CONTEXT_TYPE_IPV6:
560 dbg("CONTEXT_TYPE_IPV6");
561 strcpy(pdp_type_str, "IPV6");
567 /*PDP Type not supported supported*/
568 dbg("Unsupported PDP type :- %d returning ", pdp_type);
569 return TCORE_RETURN_FAILURE;
572 dbg("Activating context for CID :- %d", cid);
573 (void) sprintf(cmd_str, "AT+CGDCONT=%d,\"%s\",\"%s\",,%d,%d", cid, pdp_type_str, apn, d_comp, h_comp);
575 pending = tcore_at_pending_new(co_ps, cmd_str, NULL, TCORE_AT_NO_RESULT,
576 on_response_define_pdp_context, ps_context);
577 if (TCORE_RETURN_SUCCESS == tcore_hal_send_request(hal, pending)) {
578 return TCORE_RETURN_SUCCESS;
580 _unable_to_get_pending(co_ps, ps_context);
581 return TCORE_RETURN_FAILURE;
585 static struct tcore_ps_operations ps_ops = {
586 .define_context = define_ps_context,
587 .activate_context = activate_ps_context,
588 /* Use AT_standard entry point */
589 .deactivate_context = NULL
592 gboolean s_ps_init(TcorePlugin *cp, CoreObject *co_ps)
594 TcorePlugin *plugin = tcore_object_ref_plugin(co_ps);
598 tcore_ps_override_ops(co_ps, &ps_ops);
601 * AT_standard handles standard CGEV notifications:
602 * tcore_object_override_callback(co, "+CGEV", on_cgev_notification, NULL);
603 * no need to handle it here.
606 tcore_object_override_callback(co_ps, "+XNOTIFYDUNSTATUS", on_event_dun_call_notification, plugin);
613 void s_ps_exit(TcorePlugin *cp, CoreObject *co_ps)