Fix Macro issue
[framework/telephony/libtcore.git] / src / mux.c
1 /*
2  * libtcore
3  *
4  * Copyright (c) 2012 Samsung Electronics Co., Ltd. All rights reserved.
5  * Contact: Arijit Sen <arijit.sen@samsung.com>
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19
20 #include <stdio.h>
21 #include <string.h>
22 #include <unistd.h>
23 #include <stdlib.h>
24
25 #include <sys/ioctl.h>
26
27 #include <glib.h>
28
29 #include "tcore.h"
30
31 #include "hal.h"
32 #include "core_object.h"
33 #include "plugin.h"
34 #include "user_request.h"
35 #include "server.h"
36 #include "at.h"
37 #include "mux.h"
38
39 /* Channel name maximum length */
40 #define CMUX_MAX_CHANNEL_NAME                   16
41
42 /* CMUX Commands */
43 #define CMUX_COMMAND_SABM                               0x2F
44 #define CMUX_COMMAND_UA                                 0x63
45 #define CMUX_COMMAND_DM                                 0x0F
46 #define CMUX_COMMAND_DISC                                       0x43
47 #define CMUX_COMMAND_UIH                                        0xEF
48 #define CMUX_COMMAND_UI                                 0x03
49
50 /* CMUX Delimiter Byte */
51 #define CMUX_FRAME_DELIMITER                            0xF9
52
53 /*
54  * CMUX Channels [0-64] -
55  *
56  * CMUX_CHANNEL_0 is dedicated CMUX Control Channnel.
57  */
58 typedef enum {
59         CMUX_CHANNEL_NONE = -1, /* No CMUX */
60         CMUX_CHANNEL_0 = 0,             /* CMUX Control Channel */
61
62         CMUX_CHANNEL_MAX = 65   /* Based on #GPP 27.010 */
63 } tcore_cmux_channel_id;
64
65 /*
66  * CMUX Channel States
67  *
68  * Only Internal CMUX Channel states are managed,
69  * Kernel CMUX Channel states are managed by Kernel directly.
70  */
71 typedef enum {
72         CMUX_CHANNEL_CLOSED,
73         CMUX_CHANNEL_SABM_SEND_WAITING_FOR_UA,
74         CMUX_CHANNEL_ESTABLISHED,
75         CMUX_CHANNEL_UA_NOT_RECEIVED_RETRY,
76         CMUX_CHANNEL_DM_RECEIVED_CLOSING,
77         CMUX_CHANNEL_DM_SEND,
78         CMUX_CHANNEL_DISC_RECEIVED_CLOSING,
79         CMUX_CHANNEL_DISC_SEND_WAITING_FOR_UA,
80         CMUX_CHANNEL_UA_SEND_CLOSING,
81         CMUX_CHANNEL_UA_RECEIVED,
82         CMUX_CHANNEL_UA_SENDING,
83 } tcore_cmux_channel_state;
84
85 /* CMUX State */
86 typedef enum {
87         CMUX_NOT_INITIALIZED,
88         CMUX_INITIALIZED,
89         CMUX_CLOSED
90 } tcore_cmux_state;
91
92 /*
93  * CMUX CONTROL COMMANDS
94  * We are supporting only MSC and CLD commands for phase 1
95  */
96 /* Modem Status Command */
97 #define  CMUX_COMMAND_MSC                                       0xE3
98 /* Multiplexer close down */
99 #define  CMUX_COMMAND_CLD                                       0xC3
100
101 #define FIND_LENGTH(buf, header_length, total_length)  do {     \
102                 if (*buf & 0x01) { \
103                         total_length = *buf++ >> 1;     \
104                         header_length = 6; \
105                 } else { \
106                         total_length = *(buf + 0x01) << 7; \
107                         total_length = total_length | (*buf & 0xFE) >> 1; \
108                         header_length = 7; \
109                 } \
110 } while (0)
111
112 /*================= CRC TABLE=========================*/
113 const unsigned char crc_table[256] = {  /* reversed, 8-bit, poly=0x07 */
114         0x00, 0x91, 0xE3, 0x72, 0x07, 0x96, 0xE4, 0x75,
115         0x0E, 0x9F, 0xED, 0x7C, 0x09, 0x98, 0xEA, 0x7B,
116         0x1C, 0x8D, 0xFF, 0x6E, 0x1B, 0x8A, 0xF8, 0x69,
117         0x12, 0x83, 0xF1, 0x60, 0x15, 0x84, 0xF6, 0x67,
118         0x38, 0xA9, 0xDB, 0x4A, 0x3F, 0xAE, 0xDC, 0x4D,
119         0x36, 0xA7, 0xD5, 0x44, 0x31, 0xA0, 0xD2, 0x43,
120         0x24, 0xB5, 0xC7, 0x56, 0x23, 0xB2, 0xC0, 0x51,
121         0x2A, 0xBB, 0xC9, 0x58, 0x2D, 0xBC, 0xCE, 0x5F,
122         0x70, 0xE1, 0x93, 0x02, 0x77, 0xE6, 0x94, 0x05,
123         0x7E, 0xEF, 0x9D, 0x0C, 0x79, 0xE8, 0x9A, 0x0B,
124         0x6C, 0xFD, 0x8F, 0x1E, 0x6B, 0xFA, 0x88, 0x19,
125         0x62, 0xF3, 0x81, 0x10, 0x65, 0xF4, 0x86, 0x17,
126         0x48, 0xD9, 0xAB, 0x3A, 0x4F, 0xDE, 0xAC, 0x3D,
127         0x46, 0xD7, 0xA5, 0x34, 0x41, 0xD0, 0xA2, 0x33,
128         0x54, 0xC5, 0xB7, 0x26, 0x53, 0xC2, 0xB0, 0x21,
129         0x5A, 0xCB, 0xB9, 0x28, 0x5D, 0xCC, 0xBE, 0x2F,
130         0xE0, 0x71, 0x03, 0x92, 0xE7, 0x76, 0x04, 0x95,
131         0xEE, 0x7F, 0x0D, 0x9C, 0xE9, 0x78, 0x0A, 0x9B,
132         0xFC, 0x6D, 0x1F, 0x8E, 0xFB, 0x6A, 0x18, 0x89,
133         0xF2, 0x63, 0x11, 0x80, 0xF5, 0x64, 0x16, 0x87,
134         0xD8, 0x49, 0x3B, 0xAA, 0xDF, 0x4E, 0x3C, 0xAD,
135         0xD6, 0x47, 0x35, 0xA4, 0xD1, 0x40, 0x32, 0xA3,
136         0xC4, 0x55, 0x27, 0xB6, 0xC3, 0x52, 0x20, 0xB1,
137         0xCA, 0x5B, 0x29, 0xB8, 0xCD, 0x5C, 0x2E, 0xBF,
138         0x90, 0x01, 0x73, 0xE2, 0x97, 0x06, 0x74, 0xE5,
139         0x9E, 0x0F, 0x7D, 0xEC, 0x99, 0x08, 0x7A, 0xEB,
140         0x8C, 0x1D, 0x6F, 0xFE, 0x8B, 0x1A, 0x68, 0xF9,
141         0x82, 0x13, 0x61, 0xF0, 0x85, 0x14, 0x66, 0xF7,
142         0xA8, 0x39, 0x4B, 0xDA, 0xAF, 0x3E, 0x4C, 0xDD,
143         0xA6, 0x37, 0x45, 0xD4, 0xA1, 0x30, 0x42, 0xD3,
144         0xB4, 0x25, 0x57, 0xC6, 0xB3, 0x22, 0x50, 0xC1,
145         0xBA, 0x2B, 0x59, 0xC8, 0xBD, 0x2C, 0x5E, 0xCF
146 };
147 /*================= CRC TABLE=========================*/
148
149 /* CMUX Channel */
150 struct cmux_channel {
151         TcoreHal *hal;
152
153         tcore_cmux_channel_state channel_state;
154         tcore_cmux_channel_id channel_id;
155
156         int frame_type;
157         unsigned char ext_bit;
158         unsigned char cr_bit;
159         unsigned char poll_final_bit;
160 };
161
162 /* CMUX structure - Internal */
163 struct cmux_internal {
164         tcore_cmux_channel *channel_info[CMUX_CHANNEL_MAX];
165
166         int is_waiting;
167
168         int msg_len;
169         int cur_main_buf_len;
170
171         /* Channel Setup callbacks */
172         cmux_setup_cb_func channel_setup_cb;
173         gpointer channel_setup_user_data;
174
175         /* Channel Setup complete callback */
176         cmux_setup_complete_cb_func setup_complete_cb;
177         gpointer setup_complete_user_data;
178
179         int info_field_len;
180         unsigned char *info_field;
181 };
182
183 /* Global CMUX Object */
184 struct cmux_obj {
185         /* Physical HAL */
186         TcoreHal *phy_hal;
187
188         /* Modem Interface Plug-in */
189         TcorePlugin *plugin;
190
191         tcore_cmux_state cmux_state;
192
193         tcore_cmux_mode cmux_mode;
194         int max_cmux_channels;
195         unsigned int max_cmux_buf_size;
196
197         /* CMUX frame processing buffer */
198         unsigned char *cmux_buffer;
199
200         /* Only Internal MUX is managed by libtcore */
201         struct cmux_internal internal_mux;
202 };
203
204 /* CMUX Object */
205 static GSList *g_cmux_obj = NULL;
206
207 /* All the local functions declared below */
208 static void _cmux_on_confirmation_message_send(TcorePending *plugin,
209                                                                                         gboolean result, void *user_data);
210
211 tcore_cmux_object *_cmux_new(int max_channels, unsigned int buffer_size);
212 static void _cmux_free(tcore_cmux_object *cmux_obj);
213
214 static void _cmux_channel_init(tcore_cmux_object *cmux_obj, int channel_id);
215 static void _cmux_close_channel(tcore_cmux_object *cmux_obj, int channel_id);
216
217 static TcoreHal *_cmux_create_logical_hal(tcore_cmux_object *cmux_obj,
218                                                                 tcore_cmux_channel *channel);
219
220 static gboolean _cmux_recv_cmux_data(tcore_cmux_object *cmux_obj,
221                                 tcore_cmux_channel *channel);
222 static void _cmux_process_rcv_frame(tcore_cmux_object *cmux_obj, int length);
223 static void _cmux_process_channel_data(tcore_cmux_object *cmux_obj,
224                                         tcore_cmux_channel *channel);
225
226 static void _cmux_control_channel_handle(tcore_cmux_object *cmux_obj);
227 static void _cmux_flush_channel_data(tcore_cmux_object *cmux_obj);
228
229 static TReturn _cmux_send_data(TcoreHal *hal, int data_len, unsigned char *data);
230 static unsigned char *_cmux_encode_cmux_frame(tcore_cmux_object *cmux_obj,
231                                                 unsigned char *data, unsigned int length, int channel_id,
232                                                 int frame_type, unsigned char EA_bit, unsigned char CR_bit,
233                                                 unsigned char PF_bit, int *out_data_len);
234
235 static tcore_cmux_object *_cmux_get_cmux_object(TcorePlugin *plugin);
236
237 static unsigned char _cmux_calc_crc(unsigned char *header, int length);
238 static int _cmux_check_recv_crc(unsigned char *data,
239                                                                         unsigned char length,
240                                                                         unsigned char rcv_fcs);
241
242 static unsigned char _cmux_calc_crc(unsigned char *header, int length)
243 {
244         unsigned char fcs = 0xFF;       /* Init */
245         unsigned char crc = 0x00;
246
247         /*
248          * 'length' is the number of bytes in the message,
249          * 'header' points to message
250          */
251         while (length--)
252                 fcs = crc_table[fcs ^ *header++];
253
254         /* Ones complement */
255         crc = (0xFF - fcs);
256
257         dbg("Exit - CRC: [0x%02x]", crc);
258         return crc;
259 }
260
261 static int _cmux_check_recv_crc(unsigned char *data,
262                                                                         unsigned char length,
263                                                                         unsigned char rcv_fcs)
264 {
265         unsigned char fcs = 0xFF;       /* Init */
266
267         /*
268          * 'length' is the number of bytes in the message,
269          * 'data' points to message
270          */
271         while (length--)
272                 fcs = crc_table[fcs ^ *data++];
273
274         /* Ones complement */
275         fcs = crc_table[fcs ^ rcv_fcs];
276
277         /* 0xCF is the reversed order of 11110011 */
278         if (fcs == 0xCF)        /* FCS is OK */
279                 return 1;
280         else                            /* FCS is NOT OK */
281                 return 0;
282 }
283
284 static tcore_cmux_object *_cmux_get_cmux_object(TcorePlugin *plugin)
285 {
286         tcore_cmux_object *cmux_obj;
287         GSList *tmp_obj;
288         dbg("Entry");
289
290         /* Check across CMUX Objects list for specific CMUX Object */
291         for (tmp_obj = g_cmux_obj ; tmp_obj ; tmp_obj = tmp_obj->next) {
292                 cmux_obj = tmp_obj->data;
293                 if (cmux_obj == NULL)
294                         continue;
295
296                 /* Check for matching 'plugin' */
297                 if (plugin == cmux_obj->plugin) {
298                         dbg("Found CMUX object");
299                         return cmux_obj;
300                 }
301         }
302
303         return NULL;
304 }
305
306 static unsigned char *_cmux_encode_cmux_frame(tcore_cmux_object *cmux_obj,
307                                                 unsigned char *data, unsigned int length, int channel_id,
308                                                 int frame_type, unsigned char EA_bit, unsigned char CR_bit,
309                                                 unsigned char PF_bit, int *out_data_len)
310 {
311         int frame_length = 0;
312         int total_frame_length = 0;
313         int crc_len = 0;
314         dbg("Entry");
315
316         /* Flush channel data */
317         _cmux_flush_channel_data(cmux_obj);
318
319         if (length > cmux_obj->max_cmux_buf_size) {
320                 err("Length - %d  exceeds the limit", length);
321                 return NULL;
322         }
323
324         /* Flag Octet */
325         cmux_obj->internal_mux.info_field[frame_length++] = CMUX_FRAME_DELIMITER;
326
327         /* Mode of Operation */
328         if (cmux_obj->cmux_mode == CMUX_MODE_BASIC) {   /* BASIC */
329                 /*
330                  * EA: Extension Bit
331                  * C/R: Command Response
332                  */
333                 cmux_obj->internal_mux.info_field[frame_length] =
334                                 (cmux_obj->internal_mux.info_field[frame_length]
335                                         | ((EA_bit & 0x01) | ((CR_bit << 1) & 0x02)));
336
337                 /* DLCI: Data Link Connection Identifier */
338                 /* Check if the channel is within range */
339                 if (channel_id < cmux_obj->max_cmux_channels && channel_id >= 0) {
340                         dbg("Channel ID: [%d]", channel_id);
341                         cmux_obj->internal_mux.info_field[frame_length] =
342                                 (cmux_obj->internal_mux.info_field[frame_length]
343                                                         | ((unsigned char)channel_id << 2));
344                 } else {
345                         err("Channel ID [%d] is out of range [0-%d]",
346                                         channel_id, cmux_obj->max_cmux_channels);
347                         return NULL;
348                 }
349                 frame_length++;
350
351                 /*
352                  * Control Field
353                  *
354                  * The content of the control field defines the type of frame.
355                  * ****************************************************************
356                  * Frame Type                                                                           0 1 2 3  4   5 6 7
357                  * SABM (Set Asynchronous Balanced Mode)                                1 1 1 1 P/F 1 0 0
358                  * UA (Unnumbered Acknowledgement)                                      1 1 0 0 P/F 1 1 0
359                  * DM (Disconnected Mode)                                                               1 1 1 1 P/F 0 0 0
360                  * DISC (Disconnect)                                                                    1 1 0 0 P/F 0 1 0
361                  * UIH (Unnumbered Information with Header check)                       1 1 1 1 P/F 1 1 1
362                  ******************************************************************/
363                 if (PF_bit)
364                         cmux_obj->internal_mux.info_field[frame_length++] =
365                                                                                                         frame_type | 0x10;
366                 else
367                         cmux_obj->internal_mux.info_field[frame_length++] = frame_type;
368
369                 /* 5.2.1.5 Length Indicator */
370                 if (length < 128) {
371                         cmux_obj->internal_mux.info_field[frame_length++] =
372                                                                                                         (char) length << 1 | 0x01;
373
374                         /* CRC calculatable length */
375                         crc_len = 3;
376                 } else {
377                         cmux_obj->internal_mux.info_field[frame_length++] =
378                                                                                                         (char) (length << 1);
379                         cmux_obj->internal_mux.info_field[frame_length++] =
380                                                                                                         (char) (length >> 7);
381
382                         /* CRC calculatable length */
383                         crc_len = 4;
384                 }
385
386                 /*
387                  * We need to divide the frames into maximum frame length supported by IMC.
388                  * If IMC supports length according to 27.010 , we can send max of 16,384 bytes.
389                  * Need to discuss with IMC.
390                  */
391
392                 /* 5.2.1.4 Information Field */
393                 if (length > 0) {
394                         memcpy((cmux_obj->internal_mux.info_field + frame_length),
395                                                                                                                 data, length);
396                         frame_length += length;
397                 } else
398                         dbg("info field length is zero");
399
400                 /* 5.2.1.6 Frame Checking Sequence Field (FCS) */
401                 cmux_obj->internal_mux.info_field[frame_length++] =
402                         _cmux_calc_crc(cmux_obj->internal_mux.info_field + 1, crc_len);
403
404                 /* Flag Octet */
405                 cmux_obj->internal_mux.info_field[frame_length++] = CMUX_FRAME_DELIMITER;
406
407                 total_frame_length = frame_length;
408         } else if (cmux_obj->cmux_mode == CMUX_MODE_ADVANCED) {
409                 /* TBD CMUX_MODE_ADVANCE */
410                 dbg("Advanced CMUX mode : TBD");
411         }
412
413         *out_data_len = total_frame_length;
414         dbg("Data (Frame) Length: [%d]", *out_data_len);
415
416         return cmux_obj->internal_mux.info_field;
417 }
418
419 static void _cmux_control_channel_handle(tcore_cmux_object *cmux_obj)
420 {
421         unsigned char cmd_type;
422         int msg_len = 0;
423         unsigned char *msg_start_ptr;
424         dbg("Entry");
425
426         /*
427          * 5.4.6.1 Message format
428          * All messages sent between the multiplexers conform to the following
429          * type, length, value format:
430          * Type Length Value 1 Value2  \85
431          */
432         if (cmux_obj->internal_mux.info_field_len > 0) {
433                 msg_start_ptr = cmux_obj->internal_mux.info_field;
434                 cmd_type = cmux_obj->internal_mux.info_field[0];
435
436                 /*
437                  * The EA bit is an extension bit. The EA bit is set to 1 in the last octet
438                  * of the sequence; in other octets EA is set to 0.
439                  *
440                  * Search for the last octet
441                  */
442                 while ((*msg_start_ptr++ & 0x01))
443                         msg_len++;
444
445                 if ((cmd_type & 0x02) == 0x02) {        /* This is a command Request */
446                         switch (cmd_type) {
447                                 case CMUX_COMMAND_MSC:
448                                         dbg("Modem Status Command");
449                                         break;
450                                 case CMUX_COMMAND_CLD:
451                                         dbg("Multiplexer close down");
452
453                                         cmux_obj->cmux_state = CMUX_CLOSED;
454
455                                         /* TODO - Need to notify regarding CMUX closure */
456                                         tcore_cmux_close(cmux_obj->phy_hal, NULL, NULL);
457                                         break;
458                                 default:
459                                         /* We will be supporting these commands in Phase 2 */
460                                         dbg("Default");
461                                         break;
462                         }
463                 }
464         } else
465                 err("Frame length is less than ZERO");
466
467         dbg("Exit");
468 }
469
470 static void _cmux_process_channel_data(tcore_cmux_object *cmux_obj,
471                                         tcore_cmux_channel *channel)
472 {
473         int frame_type;
474         int channel_id;
475         int len;
476         unsigned char *send_data;
477         static int count = 0;
478         int ret;
479         dbg("Entry");
480
481         channel_id = channel->channel_id;
482         dbg("Channel ID: [%d]", channel_id);
483
484         frame_type = channel->frame_type & 0xEF;
485         dbg("Frame Type: [0x%02x]", frame_type);
486
487         switch (frame_type) {
488                 case CMUX_COMMAND_UI:
489                 case CMUX_COMMAND_UIH:
490                         dbg("Received UI/UIH Frame");
491                         if (channel_id == CMUX_CHANNEL_0) {              /* This is control info */
492                                 dbg("Control information");
493                                 _cmux_control_channel_handle(cmux_obj);
494                         } else {
495                                 dbg("Normal information");
496
497                                 /* Put in the logical HAL queue, this goes to the Cobject */
498                                 if (FALSE == _cmux_recv_cmux_data(cmux_obj, channel))
499                                         err("Failed receive callback");
500                         }
501                         break;
502                 case CMUX_COMMAND_UA:
503                         dbg("Received UA Frame - Channel State: [%d]", channel->channel_state);
504                         if (CMUX_CHANNEL_SABM_SEND_WAITING_FOR_UA == channel->channel_state) {
505                                 channel->channel_state = CMUX_CHANNEL_ESTABLISHED;
506
507                                 if (channel->channel_id != CMUX_CHANNEL_0) {
508                                         TcoreHal *hal;
509
510                                         /* Create Logical HAL */
511                                         hal = _cmux_create_logical_hal(cmux_obj, channel);
512                                         if (hal != NULL) {
513                                                 dbg("Invoking CMUX Channel Setup callback for [%d] channel",
514                                                                                                         channel->channel_id);
515                                                 /*
516                                                  * 'channel_setup_cb' cannot be NULL as it is MANDATED during
517                                                  * CMUX setup operation.
518                                                  */
519                                                 cmux_obj->internal_mux.channel_setup_cb(channel->channel_id, hal,
520                                                                                 cmux_obj->internal_mux.channel_setup_user_data);
521                                         } else
522                                                 err("Failed to Create Logical HAL");
523                                 }
524
525                                 count++;
526                                 dbg("Count: [%d]", count);
527                                 if (cmux_obj->max_cmux_channels == count) {
528                                         dbg("Invoking CMUX Channel Setup Complete callback - Total Channels: [%d]",
529                                                                                                         count);
530                                         /*
531                                          * 'setup_complete_cb' cannot be NULL as it is MANDATED during
532                                          * CMUX setup operation.
533                                          */
534                                         cmux_obj->internal_mux.setup_complete_cb(
535                                                 cmux_obj->internal_mux.setup_complete_user_data);
536
537                                         /* Reset 'count' */
538                                         count = 0;
539                                 }
540                         } else if (CMUX_CHANNEL_DISC_SEND_WAITING_FOR_UA ==
541                                                                                 channel->channel_state) {
542                                 channel->channel_state = CMUX_CHANNEL_CLOSED;
543
544                                 if (channel_id == CMUX_CHANNEL_0) {
545                                         cmux_obj->cmux_state = CMUX_CLOSED;
546
547                                         /* TODO - Need to notify regarding CMUX closure */
548                                         tcore_cmux_close(cmux_obj->phy_hal, NULL, NULL);
549                                 }
550                         } else
551                                 err("Received UA in wrong state!!!");
552
553                         break;
554                 case CMUX_COMMAND_DM:
555                         /*
556                          * 5.4.1 DLC Establishment : If the responding station is not ready or unwilling
557                          * to establish the particular DLC it will reply with a DM frame with the
558                          * F-bit set to 1.
559                          */
560                         dbg("Received DM Frame");
561                         if ((channel->channel_state == CMUX_CHANNEL_ESTABLISHED)
562                                 || (channel->channel_state ==
563                                                         CMUX_CHANNEL_SABM_SEND_WAITING_FOR_UA)) {
564                                 /* Channel State set to Close */
565                                 channel->channel_state = CMUX_CHANNEL_CLOSED;
566                         }
567
568                         /* Flush the Channel data */
569                         _cmux_flush_channel_data(cmux_obj);
570                         break;
571                 case CMUX_COMMAND_DISC:
572                         dbg("Received DISC Frame");
573                         if (channel->poll_final_bit == 0) {
574                                 /*
575                                  * In the case where a CMUX_COMMAND_SABM or
576                                  * CMUX_COMMAND_DISC command with
577                                  * the P bit set to 0 is received then the received frame shall be
578                                  * discarded.
579                                  */
580
581                                 /* Flush the Channel data */
582                                 _cmux_flush_channel_data(cmux_obj);
583                         } else {
584                                 if (channel->channel_state == CMUX_CHANNEL_CLOSED) {
585                                         /*
586                                          * If a CMUX_COMMAND_DISC command is received while in
587                                          * disconnected mode a CMUX_COMMAND_DM response should
588                                          * be sent
589                                          */
590
591                                         /* Encoding frame */
592                                         send_data = _cmux_encode_cmux_frame(cmux_obj, NULL,
593                                                                                         0, channel_id, CMUX_COMMAND_DM,
594                                                                                         0x01, 0x01, 0x01, &len);
595                                 } else {                                /* Send Unnumbered Acknowledgement */
596                                         /* Encoding frame */
597                                         send_data = _cmux_encode_cmux_frame(cmux_obj, NULL,
598                                                                                         0, channel_id, CMUX_COMMAND_UA,
599                                                                                         0x01, 0x01, 0x01, &len);
600                                 }
601
602                                 if (len == 0) {
603                                         err("Failed to encode");
604                                         return;
605                                 }
606
607                                 /* Send CMUX data */
608                                 ret = _cmux_send_data(cmux_obj->phy_hal, len, send_data);
609
610                                 /* Flush the Channel data */
611                                 _cmux_flush_channel_data(cmux_obj);
612
613                                 /*
614                                  * 5.3.4 Disconnect (DISC) command: CMUX_COMMAND_DISC
615                                  * command sent at DLCI 0 have the same meaning as the
616                                  * Multiplexer Close Down command.
617                                  */
618                                 if (channel_id == CMUX_CHANNEL_0) {
619                                         cmux_obj->cmux_state = CMUX_CLOSED;
620
621                                         /* Close CMUX */
622                                         /* TODO - Need to notify regarding CMUX closure */
623                                         tcore_cmux_close(cmux_obj->phy_hal, NULL, NULL);
624                                 }
625                         }
626                         break;
627                 case CMUX_COMMAND_SABM:
628                         dbg("Received SABM Frame");
629                         if (channel->poll_final_bit == 0) {
630                                 /*
631                                  * In the case where a CMUX_COMMAND_SABM or CMUX_COMMAND_DISC
632                                  * command with the P bit set to 0 is received then the received frame
633                                  * shall be discarded.
634                                  */
635
636                                 /* Flush the Channel data */
637                                 _cmux_flush_channel_data(cmux_obj);
638                         } else {
639                                 /* Encoding frame */
640                                 send_data = _cmux_encode_cmux_frame(cmux_obj, NULL,
641                                                                                 0, channel_id, CMUX_COMMAND_UA,
642                                                                                 0x01, 0x01, 0x01, &len);
643                                 if (len != 0)
644                                         /* Send CMUX data */
645                                         ret = _cmux_send_data(cmux_obj->phy_hal, len, send_data);
646                                 else
647                                         err("Failed to encode");
648
649                                 if (channel->channel_state != CMUX_CHANNEL_ESTABLISHED)
650                                         /* Channel State set to Established */
651                                         channel->channel_state = CMUX_CHANNEL_ESTABLISHED;
652                         }
653                 break;
654         }
655
656         dbg("Exit");
657 }
658
659 static void _cmux_flush_channel_data(tcore_cmux_object *cmux_obj)
660 {
661         dbg("Entry");
662
663         if (cmux_obj == NULL)
664                 return;
665
666         cmux_obj->internal_mux.info_field_len = 0x0;
667         memset(cmux_obj->internal_mux.info_field, 0x0, cmux_obj->max_cmux_buf_size);
668
669         dbg("Exit");
670 }
671
672 static void _cmux_process_rcv_frame(tcore_cmux_object *cmux_obj, int length)
673 {
674         unsigned char *frame_process_ptr = cmux_obj->cmux_buffer;
675         unsigned char *buf_start_ptr = cmux_obj->cmux_buffer;
676
677         tcore_cmux_channel *ch;
678         unsigned char channel_id;
679         int header_length;
680         dbg("Entry");
681
682         /* Flush channel data */
683         _cmux_flush_channel_data(cmux_obj);
684
685         /* Get the Channel ID: 1st byte will be flag (F9). Flag checking is already done */
686         channel_id = (*++frame_process_ptr >> 2) & 0x3F;
687
688         if (channel_id < cmux_obj->max_cmux_channels) {
689                 ch = cmux_obj->internal_mux.channel_info[channel_id];
690
691                 ch->channel_id = channel_id;
692
693                 /* get the EA bit */
694                 ch->ext_bit = *frame_process_ptr & 0x01;
695
696                 /* get the CR bit */
697                 ch->cr_bit = (*frame_process_ptr++ >> 1) & 0x01;
698
699                 /* get the Frame Type */
700                 ch->frame_type = *frame_process_ptr++;
701
702                 /* get the poll/Final bit */
703                 ch->poll_final_bit = (ch->frame_type & 0x10) >> 4;
704
705                 /* get the length . TBD */
706                 if (*frame_process_ptr & 0x01) {                        /* if, len < 127 */
707                         cmux_obj->internal_mux.info_field_len = *frame_process_ptr++ >> 1;
708                         header_length = 3;
709                 } else {
710                         cmux_obj->internal_mux.info_field_len = *(frame_process_ptr + 1) << 7;
711                         cmux_obj->internal_mux.info_field_len =
712                                                 (cmux_obj->internal_mux.info_field_len
713                                                 | ((*frame_process_ptr++ & 0xFE) >> 1));
714                         header_length = 4;
715                         frame_process_ptr++;
716                 }
717                 dbg("info_field_len: [%d]", cmux_obj->internal_mux.info_field_len);
718
719                 /* Copy received information field */
720                 memcpy(cmux_obj->internal_mux.info_field, frame_process_ptr,
721                                         cmux_obj->internal_mux.info_field_len);
722
723                 frame_process_ptr = frame_process_ptr + cmux_obj->internal_mux.info_field_len;
724
725                 /* CRC check of the header */
726                 if (_cmux_check_recv_crc((buf_start_ptr + 1), header_length, *frame_process_ptr)) {
727                         dbg("Calling _cmux_process_channel_data");
728                         _cmux_process_channel_data(cmux_obj, ch);
729                 } else
730                         err("CRC check of the header FAILED.. Drop the packet !!");
731         } else
732                 err("Incorrect channel... Drop the packet !!");
733
734         dbg("Exit");
735 }
736
737 static TReturn _cmux_send_data(TcoreHal *hal, int data_len, unsigned char *data)
738 {
739         TReturn ret;
740         dbg("Entry");
741
742         /* Directly send to Physical HAL */
743         ret = tcore_hal_send_data(hal, data_len, (void *) data);
744         if (ret != TCORE_RETURN_SUCCESS) {
745                 err("Failed to send CMUX data");
746         } else
747                 dbg("Successfully sent CMUX data");
748
749         dbg("Exit");
750         return ret;
751 }
752
753 static gboolean _cmux_recv_cmux_data(tcore_cmux_object *cmux_obj,
754                                 tcore_cmux_channel *channel)
755 {
756         TcoreHal *hal;
757         dbg("Entry");
758
759         /* Dereferencing HAL from Channel Pointer */
760         hal = channel->hal;
761         if (hal == NULL) {
762                 err("No HAL");
763                 return FALSE;
764         }
765
766         dbg("Dispatching to logical HAL - hal: [0x%x]", (unsigned int)hal);
767         if (tcore_hal_dispatch_response_data(hal, 0,
768                         cmux_obj->internal_mux.info_field_len,
769                         cmux_obj->internal_mux.info_field)
770                         != TCORE_RETURN_SUCCESS) {
771                 err("Exit");
772                 return FALSE;
773         }
774
775         dbg("Exit");
776         return TRUE;
777 }
778
779 static TReturn _cmux_hal_power(TcoreHal *hal, gboolean flag)
780 {
781         dbg("Entry");
782
783         if (flag == TRUE) {             /* Powering ON */
784                 dbg("Powering ON");
785                 return tcore_hal_set_power_state(hal, TRUE);
786         } else {                                        /* Powering OFF */
787                 dbg("Powering OFF");
788                 return tcore_hal_set_power_state(hal, FALSE);
789         }
790 }
791
792 static TReturn _cmux_hal_send(TcoreHal *hal, unsigned int data_len, void *data)
793 {
794         tcore_cmux_object *cmux_obj;
795         char *hal_name;
796         unsigned char *send_data;
797         char *channel_name;
798         int channel_id;
799         int len;
800
801         TReturn ret = TCORE_RETURN_FAILURE;
802         dbg("Entry");
803
804         /* Check if Logical HAL is Powered ON */
805         if (tcore_hal_get_power_state(hal) == FALSE) {
806                 err("HAL is not Powered UP");
807                 return TCORE_RETURN_FAILURE;
808         }
809
810         /*
811          * Get CMUX Object from Modem Interface Plug-in
812          */
813         cmux_obj = _cmux_get_cmux_object(tcore_hal_ref_plugin(hal));
814         if (cmux_obj == NULL) {
815                 err("Failed to find CMUX object");
816                 return TCORE_RETURN_FAILURE;
817         }
818
819         channel_id = cmux_obj->max_cmux_channels + 1;
820
821         channel_name = tcore_hal_get_name(hal);
822         dbg("HAL name: [%s]", channel_name);
823
824         if (channel_name != NULL) {
825                 int i;
826
827                 /*
828                  * Channel 0 is dedicated to CMUX Control Channel,
829                  * hence starting from 1.
830                  */
831                 for (i = 1 ; cmux_obj->max_cmux_channels > i ; i++) {
832                         hal_name =
833                                 tcore_hal_get_name(cmux_obj->internal_mux.channel_info[i]->hal);
834                         if (hal_name == NULL) {
835                                 dbg("HAL name: [%s]", hal_name);
836                                 continue;
837                         }
838
839                         /*
840                          * Comparing all Logical HAL names with required HAL name.
841                          */
842                         if (strcmp(hal_name, channel_name) == 0) {
843                                 channel_id = cmux_obj->internal_mux.channel_info[i]->channel_id;
844                                 dbg("Found Channel ID: [%d]", channel_id);
845
846                                 /* Free HAL name */
847                                 g_free(hal_name);
848
849                                 break;
850                         }
851
852                         /* Free HAL name */
853                         g_free(hal_name);
854                 }
855
856                 /* Free memory */
857                 g_free(channel_name);
858         } else {
859                 err("No name defined for HAL");
860                 return ret;
861         }
862
863         if (channel_id > cmux_obj->max_cmux_channels) {
864                 err("Failed to find Channel ID");
865                 return ret;
866         }
867
868         /* Muxing operation and Frame creation */
869         /* Encoding frame */
870         send_data = _cmux_encode_cmux_frame(cmux_obj, data, data_len, channel_id,
871                                         CMUX_COMMAND_UIH, 0x1, 0x1, 0x0, &len);
872         if (len == 0) {
873                 err("Failed to encode");
874                 return TCORE_RETURN_FAILURE;
875         }
876
877         /* Send CMUX data */
878         ret = _cmux_send_data(cmux_obj->phy_hal, len, send_data);
879
880         dbg("Exit");
881         return ret;
882 }
883
884 static TReturn _cmux_hal_setup_netif(CoreObject *co,
885                                 TcoreHalSetupNetifCallback func, void *user_data,
886                                 unsigned int cid, gboolean enable)
887 {
888         tcore_cmux_object *cmux_obj;
889         TcoreHal *hal;
890         dbg("Entry");
891
892         /* Get secondary HAL from Core Object */
893         hal = tcore_object_get_hal(co);
894
895         /*
896          * Get CMUX Object from Modem Interface Plug-in
897          */
898         cmux_obj = _cmux_get_cmux_object(tcore_hal_ref_plugin(hal));
899         if (cmux_obj == NULL)
900                 return TCORE_RETURN_FAILURE;
901
902         return tcore_hal_setup_netif(cmux_obj->phy_hal,
903                                                                 co, func, user_data, cid, enable);
904 }
905
906 /* CMUX supported HAL (Logical HAL) operations */
907 static struct tcore_hal_operations cmux_hops = {
908         .power = _cmux_hal_power,
909         .send = _cmux_hal_send,
910         .setup_netif = _cmux_hal_setup_netif,
911 };
912
913 static TcoreHal *_cmux_create_logical_hal(tcore_cmux_object *cmux_obj,
914                                                                 tcore_cmux_channel *channel)
915 {
916         TcoreHal *hal;
917         char channel_id_name[CMUX_MAX_CHANNEL_NAME];
918         dbg("Entry");
919
920         if ((cmux_obj == NULL) || (channel == NULL)) {
921                 err("Invalid input parameters");
922                 return NULL;
923         }
924
925         /* Creating Logical HAL for Core Object - Mode - 'AT mode' */
926         snprintf(channel_id_name, sizeof(channel_id_name),
927                                                 "channel_%d", channel->channel_id);
928
929         /* Creating Logical HAL */
930         hal = tcore_hal_new(cmux_obj->plugin,
931                                         channel_id_name, &cmux_hops, TCORE_HAL_MODE_AT);
932         dbg("hal: %p", hal);
933         if (hal == NULL) {
934                 err("Failed to allocate memory");
935                 return NULL;
936         }
937
938         /* Updating Logical HAL of CMUX Channel */
939         channel->hal = hal;
940
941         dbg("Exit");
942         return hal;
943 }
944
945 tcore_cmux_object *_cmux_new(int max_channels, unsigned int buffer_size)
946 {
947         tcore_cmux_object *cmux_obj;
948         int i;
949         dbg("Entry");
950
951         /* Allocating memory for mux */
952         cmux_obj = (tcore_cmux_object *)g_try_new0(tcore_cmux_object, 1);
953         if (cmux_obj == NULL) {
954                 err("Failed to allocate memory");
955                 return NULL;
956         }
957
958         /* Allocating memory for info_field */
959         cmux_obj->internal_mux.info_field =
960                                         (unsigned char *)g_try_malloc0(buffer_size);
961         if (cmux_obj->internal_mux.info_field == NULL) {
962                 err("Failed to allocate memory for info field");
963                 goto ERROR;
964         }
965
966         /* CMUX State initialize to CMUX_NOT_INITIALIZED */
967         cmux_obj->cmux_state = CMUX_NOT_INITIALIZED;
968
969         /*
970          * Allocating memory for channel_info
971          * max_channels defines the maximum channels user requested,
972          * hence + 1 is required for CMUX Control Channel
973          */
974         for (i = 0; i < (max_channels + 1) ; i++) {
975                 /* Allocating memory for channel_info */
976                 cmux_obj->internal_mux.channel_info[i] =
977                                 (tcore_cmux_channel *)g_try_new0(tcore_cmux_channel, 1);
978                 if (cmux_obj->internal_mux.channel_info[i] == NULL) {
979                         err("Failed to allocate memory for channel_info of channel: [%d]", i);
980                         goto ERROR;
981                 }
982         }
983
984         dbg("Exit");
985         return cmux_obj;
986
987 ERROR:
988         /* Free allocated memory */
989         if (cmux_obj != NULL) {
990                 /* Free info_field */
991                 g_free(cmux_obj->internal_mux.info_field);
992
993                 for (i = 0; i < (max_channels + 1) ; i++)
994                         /* Free channel_info */
995                         g_free(cmux_obj->internal_mux.channel_info[i]);
996
997                 /* Free CMUX object memory */
998                 g_free(cmux_obj);
999         }
1000
1001         err("Exit");
1002         return NULL;
1003 }
1004
1005 static void _cmux_channel_init(tcore_cmux_object *cmux_obj, int channel_id)
1006 {
1007         tcore_cmux_channel *ch;
1008         dbg("Entry");
1009
1010         ch = cmux_obj->internal_mux.channel_info[channel_id];
1011         if (ch == NULL)
1012                 return;
1013
1014         ch->channel_id = channel_id;
1015         ch->channel_state = CMUX_CHANNEL_SABM_SEND_WAITING_FOR_UA;
1016
1017         ch->hal = NULL;
1018
1019         /* TODO - Check if required */
1020         ch->frame_type = CMUX_COMMAND_SABM;
1021         ch->ext_bit = 0x01;
1022         ch->cr_bit = 0x01;
1023         ch->poll_final_bit = 0x01;
1024
1025         dbg("Channel ID [%d] - Initialized", channel_id);
1026 }
1027
1028 static void _cmux_close_channel(tcore_cmux_object *cmux_obj, int channel_id)
1029 {
1030         tcore_cmux_channel *ch;
1031         unsigned char *send_data;
1032         int ret, len = 0;
1033         dbg("Entry");
1034
1035         ch = cmux_obj->internal_mux.channel_info[channel_id];
1036         if (ch == NULL)
1037                 return;
1038
1039         if (ch->channel_state != CMUX_CHANNEL_CLOSED) {
1040                 ch->frame_type = CMUX_COMMAND_DISC;
1041                 ch->ext_bit = 0x01;
1042                 ch->cr_bit = 0x01;
1043                 ch->channel_state = CMUX_CHANNEL_DISC_SEND_WAITING_FOR_UA;
1044
1045                 /* Send DSC command */
1046                 /* Encoding frame */
1047                 send_data = _cmux_encode_cmux_frame(cmux_obj, NULL, 0, channel_id,
1048                                                 CMUX_COMMAND_DISC, 0x01, 0x01, 0x01, &len);
1049                 if (len != 0)
1050                         /* Send CMUX data */
1051                         ret = _cmux_send_data(cmux_obj->phy_hal, len, send_data);
1052                 else
1053                         err("Failed to encode");
1054         } else
1055                 /* Channel is already closed */
1056                 err("Channel is already closed");
1057
1058         dbg("Exit");
1059 }
1060
1061 static void _cmux_free(tcore_cmux_object *cmux_obj)
1062 {
1063         int channel;
1064         dbg("Entry");
1065
1066         /*
1067          * This function is used internally only, hence sanity check for 'cmux_obj'
1068          * is NOT required.
1069          */
1070         /* Free Information Field */
1071         g_free(cmux_obj->internal_mux.info_field);
1072         cmux_obj->internal_mux.info_field = NULL;
1073
1074         for (channel = 0; channel < cmux_obj->max_cmux_channels; channel++) {
1075                 /* Free Channel Information */
1076                 g_free(cmux_obj->internal_mux.channel_info[channel]);
1077                 cmux_obj->internal_mux.channel_info[channel] = NULL;
1078         }
1079
1080         /* Free CMUX Object */
1081         g_free(cmux_obj);
1082         cmux_obj = NULL;
1083
1084         dbg("Exit");
1085 }
1086
1087 static void _cmux_on_confirmation_message_send(TcorePending *plugin,
1088                                                                                         gboolean result, void *user_data)
1089 {
1090         dbg("Message out from queue");
1091
1092         if (result == FALSE) {          /* Fail */
1093                 err("SEND FAIL");
1094         } else
1095                 dbg("SEND OK");
1096 }
1097
1098 void tcore_cmux_rcv_from_hal(TcoreHal *hal, unsigned char *data, size_t length)
1099 {
1100 #define TCORE_CMUX_DECODE_FLAG_HUNT                     0
1101 #define TCORE_CMUX_DECODE_ADDR_HUNT                     1
1102 #define TCORE_CMUX_DECODE_CONTROL_HUNT          2
1103 #define TCORE_CMUX_DECODE_LENGTH1_HUNT          3
1104 #define TCORE_CMUX_DECODE_LENGTH2_HUNT          4
1105 #define TCORE_CMUX_DECODE_DATA_HUNT                     5
1106 #define TCORE_CMUX_DECODE_FCS_HUNT                      6
1107
1108         tcore_cmux_object *cmux_obj;
1109
1110         static int decode_state = TCORE_CMUX_DECODE_FLAG_HUNT;
1111         static unsigned char dec_fcs;
1112         static unsigned char *dec_data;
1113         static unsigned short dec_length;
1114         static size_t full_frame_len;
1115
1116         size_t pos = -1;
1117         int cp_len;
1118         dbg("Entry");
1119
1120         /*
1121          * Get CMUX Object from Modem Interface Plug-in
1122          */
1123         cmux_obj = _cmux_get_cmux_object(tcore_hal_ref_plugin(hal));
1124         if (cmux_obj == NULL)
1125                 return;
1126
1127 DECODE_STATE_CHANGE:
1128         if (++pos >= length)
1129                 return;
1130
1131         switch(decode_state) {
1132                 case TCORE_CMUX_DECODE_FLAG_HUNT:
1133                         full_frame_len = 0;
1134                         dec_length = 0;
1135                         dec_fcs = 0xFF;
1136                         dec_data = cmux_obj->cmux_buffer;
1137                         goto FLAG_HUNT;
1138                 break;
1139                 case TCORE_CMUX_DECODE_ADDR_HUNT:
1140                         goto ADDR_HUNT;
1141                 break;
1142                 case TCORE_CMUX_DECODE_CONTROL_HUNT:
1143                         goto CONTROL_HUNT;
1144                 break;
1145                 case TCORE_CMUX_DECODE_LENGTH1_HUNT:
1146                         goto LENGTH1_HUNT;
1147                 break;
1148                 case TCORE_CMUX_DECODE_LENGTH2_HUNT:
1149                         goto LENGTH2_HUNT;
1150                 break;
1151                 case TCORE_CMUX_DECODE_DATA_HUNT:
1152                         goto DATA_HUNT;
1153                 break;
1154                 case TCORE_CMUX_DECODE_FCS_HUNT:
1155                         goto FCS_HUNT;
1156                 break;
1157         }
1158
1159 FLAG_HUNT:
1160         while (data[pos] != CMUX_FRAME_DELIMITER)
1161                 if (++pos >= length)
1162                         return;
1163
1164         decode_state = TCORE_CMUX_DECODE_ADDR_HUNT;
1165         goto DECODE_STATE_CHANGE;
1166
1167 ADDR_HUNT:
1168         while (data[pos] == CMUX_FRAME_DELIMITER)
1169                 if (++pos >= length)
1170                         return;
1171
1172         dec_fcs = crc_table[dec_fcs^data[pos]];
1173         decode_state = TCORE_CMUX_DECODE_CONTROL_HUNT;
1174         *dec_data++ = CMUX_FRAME_DELIMITER;
1175         *dec_data++ = data[pos];
1176         full_frame_len += 2;
1177         goto DECODE_STATE_CHANGE;
1178
1179 CONTROL_HUNT:
1180         dec_fcs = crc_table[dec_fcs^data[pos]];
1181         decode_state = TCORE_CMUX_DECODE_LENGTH1_HUNT;
1182         *dec_data++ = data[pos];
1183         full_frame_len++;
1184         goto DECODE_STATE_CHANGE;
1185
1186 LENGTH1_HUNT:
1187         dec_length = data[pos] >> 1;
1188         dec_fcs = crc_table[dec_fcs^data[pos]];
1189         if (data[pos] & 0x1)            /* EA */
1190                 if (dec_length > 0)
1191                         decode_state = TCORE_CMUX_DECODE_DATA_HUNT;
1192                 else
1193                         decode_state = TCORE_CMUX_DECODE_FCS_HUNT;
1194         else
1195                 decode_state = TCORE_CMUX_DECODE_LENGTH2_HUNT;
1196
1197         *dec_data++ = data[pos];
1198         full_frame_len++;
1199         goto DECODE_STATE_CHANGE;
1200
1201 LENGTH2_HUNT:
1202         dec_length |= ((unsigned short)data[pos] << 7);
1203         dec_fcs = crc_table[dec_fcs^data[pos]];
1204         decode_state = TCORE_CMUX_DECODE_DATA_HUNT;
1205         *dec_data++ = data[pos];
1206         full_frame_len++;
1207         goto DECODE_STATE_CHANGE;
1208
1209 DATA_HUNT:
1210         if (dec_length < (length - pos)) {      /* frame data fully available in the buffer */
1211                 cp_len = dec_length;
1212                 decode_state = TCORE_CMUX_DECODE_FCS_HUNT;
1213         } else {                                                /* frame data partially available in the buffer */
1214                 cp_len = (length - pos);
1215                 decode_state = TCORE_CMUX_DECODE_DATA_HUNT;
1216         }
1217
1218         memcpy(dec_data, data + pos, cp_len);
1219         dec_data += cp_len;
1220         pos += (cp_len - 1);
1221         dec_length -= cp_len;
1222         full_frame_len += cp_len;
1223
1224         goto DECODE_STATE_CHANGE;
1225
1226 FCS_HUNT:
1227         *dec_data++ = data[pos];
1228         *dec_data++ = CMUX_FRAME_DELIMITER;
1229         full_frame_len += 2;
1230         _cmux_process_rcv_frame(cmux_obj, full_frame_len);
1231
1232         /* enter flag hunt mode */
1233         decode_state = TCORE_CMUX_DECODE_FLAG_HUNT;
1234         goto DECODE_STATE_CHANGE;
1235 }
1236
1237 /* CMUX initialization */
1238 TReturn tcore_cmux_init(TcoreHal *phy_hal, unsigned int frame_size,
1239                                         TcorePendingResponseCallback resp_cb, void *resp_cb_data)
1240 {
1241         TcorePending *pending = NULL;
1242         TcoreATRequest *req = NULL;
1243         TReturn ret = TCORE_RETURN_FAILURE;
1244         char *cmd_str;
1245         dbg("Entry");
1246
1247         if ((phy_hal == NULL) || (resp_cb == NULL))
1248                 return TCORE_RETURN_EINVAL;
1249
1250         if (frame_size > 32768)
1251                 return TCORE_RETURN_EINVAL;
1252
1253         /*
1254          * 3GPP 27.010 Section 5.7.2 Maximum Frame Size (N1)
1255          * If frame size is greater than Zero then,
1256          * the request is sent for frame size
1257          * else,
1258          * request is sent for 'default' frame size
1259          * (default Value: 31 (64 if Advanced option is used)).
1260          */
1261         if (frame_size > 0)
1262                 cmd_str = g_strdup_printf("AT+CMUX=0,0,%d,1509,10,3,30,,", frame_size);
1263         else
1264                 cmd_str = g_strdup_printf("AT+CMUX=0,0,,1509,10,3,30,,");
1265
1266         if (cmd_str == NULL)
1267                 return TCORE_RETURN_ENOMEM;
1268
1269         /* Create Pending Request */
1270         pending = tcore_pending_new(NULL, 0);
1271         if (pending == NULL) {
1272                 dbg("Pending is NULL");
1273
1274                 g_free(cmd_str);
1275                 return ret;
1276         }
1277
1278         /* Create AT-Command Request */
1279         req = tcore_at_request_new(cmd_str, "+CMUX:", TCORE_AT_NO_RESULT);
1280
1281         /* Free command string */
1282         g_free(cmd_str);
1283
1284         if (req == NULL) {
1285                 dbg("Request is NULL");
1286                 tcore_pending_free(pending);
1287                 return ret;
1288         }
1289         dbg("AT Command: [%s], Prefix(if any): [%s], AT-Command length: [%d]", req->cmd, req->prefix, strlen(req->cmd));
1290
1291         tcore_pending_set_request_data(pending, 0, req);
1292         tcore_pending_set_response_callback(pending, resp_cb, resp_cb_data);
1293         tcore_pending_set_send_callback(pending, _cmux_on_confirmation_message_send, NULL);
1294
1295         ret = tcore_hal_send_request(phy_hal, pending);
1296
1297         dbg("Exit");
1298         return ret;
1299 }
1300
1301 /* Setup Internal CMUX */
1302 TReturn tcore_cmux_setup_internal_mux(tcore_cmux_mode mode,
1303         int max_channels, unsigned int cmux_buf_size, TcoreHal *phy_hal,
1304         cmux_setup_cb_func channel_setup_cb, gpointer channel_setup_user_data,
1305         cmux_setup_complete_cb_func setup_complete_cb, gpointer setup_complete_user_data)
1306 {
1307         tcore_cmux_object *cmux_obj;
1308         unsigned char *data;
1309         int data_len;
1310         int index;
1311
1312         TReturn ret = TCORE_RETURN_FAILURE;
1313         dbg("Entry");
1314         dbg("Internal CMUX setup request");
1315
1316         /* Sanity Check */
1317         if ((cmux_buf_size <= 0)
1318                         || (phy_hal == NULL)
1319                         || (channel_setup_cb == NULL)
1320                         || (setup_complete_cb == NULL)) {
1321                 err("CMUX Buffer size: [%d] Physical HAL: [0x%x] setup_complete_cb: [0x%x]",
1322                         cmux_buf_size, (unsigned int)phy_hal, setup_complete_cb);
1323                 return TCORE_RETURN_EINVAL;
1324         }
1325
1326         dbg("Physical HAL: [0x%x] cmux_buf_size: [%d]",
1327                                                                 (unsigned int)phy_hal, cmux_buf_size);
1328
1329         /*
1330          * Max Channels
1331          *      (+ 1) is for CMUX Control Channel
1332          */
1333         if ((max_channels +1) >= CMUX_CHANNEL_MAX) {
1334                 err("Number of Channels requested is greater than supported");
1335                 return TCORE_RETURN_EINVAL;
1336         }
1337
1338         /* Create new CMUX Object */
1339         cmux_obj = _cmux_new(max_channels, cmux_buf_size);
1340         if (cmux_obj == NULL) {
1341                 err("Failed to create CMUX object");
1342                 return TCORE_RETURN_ENOMEM;
1343         }
1344
1345         /* Maximum Buffer size for CMUX frame processing */
1346         cmux_obj->max_cmux_buf_size = cmux_buf_size;
1347
1348         /* Maximum Channels requested */
1349         cmux_obj->max_cmux_channels = max_channels + 1;
1350
1351         /* Allocating buffer for CMUX frames proposing */
1352         cmux_obj->cmux_buffer = (unsigned char *)g_try_malloc0(cmux_buf_size);
1353         if (cmux_obj->cmux_buffer == NULL) {
1354                 err("Failed to allocate memory");
1355
1356                 ret = TCORE_RETURN_ENOMEM;
1357                 goto ERROR;
1358         }
1359
1360         /* Update 'mode' */
1361         cmux_obj->cmux_mode = mode;
1362         dbg("Mode: \'%s\'", (mode == CMUX_MODE_BASIC ? "Basic" : "Advanced"));
1363
1364         /* Save Physical HAL */
1365         cmux_obj->phy_hal = phy_hal;
1366
1367         /* Save Modem Interface Plug-in */
1368         cmux_obj->plugin = tcore_hal_ref_plugin(phy_hal);
1369
1370         /* CMUX setup callback function */
1371         cmux_obj->internal_mux.channel_setup_cb = channel_setup_cb;
1372         cmux_obj->internal_mux.channel_setup_user_data = channel_setup_user_data;
1373
1374         /* CMUX setup complete callback function */
1375         cmux_obj->internal_mux.setup_complete_cb = setup_complete_cb;
1376         cmux_obj->internal_mux.setup_complete_user_data = setup_complete_user_data;
1377
1378         /*
1379          * After CMUX setup, AT parse functionality of PHY HAL should be disabled,
1380          * here we change the mode of PHYSICAL HAL to Transparent from AT.
1381          */
1382         tcore_hal_set_mode(phy_hal, TCORE_HAL_MODE_TRANSPARENT);
1383         dbg("Physical HAL mode changed to Transparent");
1384
1385         /* Adding CMUX object to Global List */
1386         g_cmux_obj = g_slist_insert(g_cmux_obj, cmux_obj, 0);
1387
1388         /* Initialize all the Channels for the CMUX object */
1389         /* Open all Channels */
1390         for (index = 0; index < cmux_obj->max_cmux_channels; index++) {
1391                 dbg("Initializing CMUX Channel [%d]", index);
1392                 _cmux_channel_init(cmux_obj, index);
1393
1394                 dbg("Opening Channel ID [%d]", index);
1395                 /* Encode CMUX Frame */
1396                 data = _cmux_encode_cmux_frame(cmux_obj, NULL, 0, index,
1397                                         CMUX_COMMAND_SABM, 0x01, 0x01, 0x01, &data_len);
1398                 if (data_len == 0) {
1399                         err("Failed to encode");
1400                         goto ERROR;
1401                 }
1402                 dbg("data_len: [%d] data: [%s]", data_len, data);
1403
1404                 /* Send CMUX data */
1405                 ret = _cmux_send_data(cmux_obj->phy_hal, data_len, data);
1406                 if (ret != TCORE_RETURN_SUCCESS) {
1407                         err("Failed to send CMUX Control Request for Channel ID: [%d]", index);
1408                         goto ERROR;
1409                 } else
1410                         dbg("CMUX Control Request sent to CP");
1411         }
1412
1413         dbg("Exit");
1414         return ret;
1415
1416 ERROR:
1417         /* Free the allocated CMUX memory */
1418         _cmux_free(cmux_obj);
1419
1420         err("Exit");
1421         return ret;
1422 }
1423
1424 /* Close CMUX */
1425 void tcore_cmux_close(TcoreHal *phy_hal,
1426         cmux_channel_close_cb_func channel_close_cb, gpointer channel_close_user_data)
1427 {
1428         tcore_cmux_object *cmux_obj;
1429         int channel_id;
1430         dbg("Entry");
1431
1432         /*
1433          * Get CMUX Object from Modem Interface Plug-in
1434          */
1435         cmux_obj = _cmux_get_cmux_object(tcore_hal_ref_plugin(phy_hal));
1436         if (cmux_obj == NULL)
1437                 return;
1438
1439         /* Internal CMUX */
1440         dbg("Closing Internal CMUX");
1441
1442         /* Close all Channels */
1443         for (channel_id = 0;
1444                         channel_id < cmux_obj->max_cmux_channels;
1445                         channel_id++) {
1446                 dbg("Closing Channel - ID: [%d]", channel_id);
1447
1448                 /* Close Channel - Send DSC command */
1449                 _cmux_close_channel(cmux_obj, channel_id);
1450
1451                 /* Invoke callback */
1452                 if (channel_close_cb != NULL)
1453                         channel_close_cb(cmux_obj->internal_mux.channel_info[channel_id]->hal,
1454                                                 channel_close_user_data);
1455
1456                 /* Free Logical HAL for Channel */
1457                 tcore_hal_free(cmux_obj->internal_mux.channel_info[channel_id]->hal);
1458                 cmux_obj->internal_mux.channel_info[channel_id]->hal = NULL;
1459         }
1460
1461         /* Freeing CMUX frame processing buffer */
1462         g_free(cmux_obj->cmux_buffer);
1463         cmux_obj->cmux_buffer = NULL;
1464
1465         /* Change the mode of PHYSICAL HAL from Transparent to AT */
1466         tcore_hal_set_mode(cmux_obj->phy_hal, TCORE_HAL_MODE_AT);
1467
1468         /* Remove from list */
1469         g_cmux_obj = g_slist_remove(g_cmux_obj, cmux_obj);
1470
1471         /* Free all the allocated memory */
1472         _cmux_free(cmux_obj);
1473
1474         dbg("Exit");
1475 }