tizen 2.3.1 release
[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                 dbg("return %d", ret);
610
611                                 /* Flush the Channel data */
612                                 _cmux_flush_channel_data(cmux_obj);
613
614                                 /*
615                                  * 5.3.4 Disconnect (DISC) command: CMUX_COMMAND_DISC
616                                  * command sent at DLCI 0 have the same meaning as the
617                                  * Multiplexer Close Down command.
618                                  */
619                                 if (channel_id == CMUX_CHANNEL_0) {
620                                         cmux_obj->cmux_state = CMUX_CLOSED;
621
622                                         /* Close CMUX */
623                                         /* TODO - Need to notify regarding CMUX closure */
624                                         tcore_cmux_close(cmux_obj->phy_hal, NULL, NULL);
625                                 }
626                         }
627                         break;
628                 case CMUX_COMMAND_SABM:
629                         dbg("Received SABM Frame");
630                         if (channel->poll_final_bit == 0) {
631                                 /*
632                                  * In the case where a CMUX_COMMAND_SABM or CMUX_COMMAND_DISC
633                                  * command with the P bit set to 0 is received then the received frame
634                                  * shall be discarded.
635                                  */
636
637                                 /* Flush the Channel data */
638                                 _cmux_flush_channel_data(cmux_obj);
639                         } else {
640                                 /* Encoding frame */
641                                 send_data = _cmux_encode_cmux_frame(cmux_obj, NULL,
642                                                                                 0, channel_id, CMUX_COMMAND_UA,
643                                                                                 0x01, 0x01, 0x01, &len);
644                                 if (len != 0)
645                                         /* Send CMUX data */
646                                         ret = _cmux_send_data(cmux_obj->phy_hal, len, send_data);
647                                 else
648                                         err("Failed to encode");
649
650                                 if (channel->channel_state != CMUX_CHANNEL_ESTABLISHED)
651                                         /* Channel State set to Established */
652                                         channel->channel_state = CMUX_CHANNEL_ESTABLISHED;
653                         }
654                 break;
655                 default:
656                         warn("invalid frame_type");
657                 break;  
658         }
659
660         dbg("Exit");
661 }
662
663 static void _cmux_flush_channel_data(tcore_cmux_object *cmux_obj)
664 {
665         dbg("Entry");
666
667         if (cmux_obj == NULL)
668                 return;
669
670         cmux_obj->internal_mux.info_field_len = 0x0;
671         memset(cmux_obj->internal_mux.info_field, 0x0, cmux_obj->max_cmux_buf_size);
672
673         dbg("Exit");
674 }
675
676 static void _cmux_process_rcv_frame(tcore_cmux_object *cmux_obj, int length)
677 {
678         unsigned char *frame_process_ptr = cmux_obj->cmux_buffer;
679         unsigned char *buf_start_ptr = cmux_obj->cmux_buffer;
680
681         tcore_cmux_channel *ch;
682         unsigned char channel_id;
683         int header_length;
684         dbg("Entry");
685
686         /* Flush channel data */
687         _cmux_flush_channel_data(cmux_obj);
688
689         /* Get the Channel ID: 1st byte will be flag (F9). Flag checking is already done */
690         channel_id = (*++frame_process_ptr >> 2) & 0x3F;
691
692         if (channel_id < cmux_obj->max_cmux_channels) {
693                 ch = cmux_obj->internal_mux.channel_info[channel_id];
694
695                 ch->channel_id = channel_id;
696
697                 /* get the EA bit */
698                 ch->ext_bit = *frame_process_ptr & 0x01;
699
700                 /* get the CR bit */
701                 ch->cr_bit = (*frame_process_ptr++ >> 1) & 0x01;
702
703                 /* get the Frame Type */
704                 ch->frame_type = *frame_process_ptr++;
705
706                 /* get the poll/Final bit */
707                 ch->poll_final_bit = (ch->frame_type & 0x10) >> 4;
708
709                 /* get the length . TBD */
710                 if (*frame_process_ptr & 0x01) {                        /* if, len < 127 */
711                         cmux_obj->internal_mux.info_field_len = *frame_process_ptr++ >> 1;
712                         header_length = 3;
713                 } else {
714                         cmux_obj->internal_mux.info_field_len = *(frame_process_ptr + 1) << 7;
715                         cmux_obj->internal_mux.info_field_len =
716                                                 (cmux_obj->internal_mux.info_field_len
717                                                 | ((*frame_process_ptr++ & 0xFE) >> 1));
718                         header_length = 4;
719                         frame_process_ptr++;
720                 }
721                 dbg("info_field_len: [%d]", cmux_obj->internal_mux.info_field_len);
722
723                 /* Copy received information field */
724                 memcpy(cmux_obj->internal_mux.info_field, frame_process_ptr,
725                                         cmux_obj->internal_mux.info_field_len);
726
727                 frame_process_ptr = frame_process_ptr + cmux_obj->internal_mux.info_field_len;
728
729                 /* CRC check of the header */
730                 if (_cmux_check_recv_crc((buf_start_ptr + 1), header_length, *frame_process_ptr)) {
731                         dbg("Calling _cmux_process_channel_data");
732                         _cmux_process_channel_data(cmux_obj, ch);
733                 } else
734                         err("CRC check of the header FAILED.. Drop the packet !!");
735         } else
736                 err("Incorrect channel... Drop the packet !!");
737
738         dbg("Exit");
739 }
740
741 static TReturn _cmux_send_data(TcoreHal *hal, int data_len, unsigned char *data)
742 {
743         TReturn ret;
744         dbg("Entry");
745
746         /* Directly send to Physical HAL */
747         ret = tcore_hal_send_data(hal, data_len, (void *) data);
748         if (ret != TCORE_RETURN_SUCCESS) {
749                 err("Failed to send CMUX data");
750         } else
751                 dbg("Successfully sent CMUX data");
752
753         dbg("Exit");
754         return ret;
755 }
756
757 static gboolean _cmux_recv_cmux_data(tcore_cmux_object *cmux_obj,
758                                 tcore_cmux_channel *channel)
759 {
760         TcoreHal *hal;
761         dbg("Entry");
762
763         /* Dereferencing HAL from Channel Pointer */
764         hal = channel->hal;
765         if (hal == NULL) {
766                 err("No HAL");
767                 return FALSE;
768         }
769
770         dbg("Dispatching to logical HAL - hal: [0x%x]", (unsigned int)hal);
771         if (tcore_hal_dispatch_response_data(hal, 0,
772                         cmux_obj->internal_mux.info_field_len,
773                         cmux_obj->internal_mux.info_field)
774                         != TCORE_RETURN_SUCCESS) {
775                 err("Exit");
776                 return FALSE;
777         }
778
779         dbg("Exit");
780         return TRUE;
781 }
782
783 static TReturn _cmux_hal_power(TcoreHal *hal, gboolean flag)
784 {
785         dbg("Entry");
786
787         if (flag == TRUE) {             /* Powering ON */
788                 dbg("Powering ON");
789                 return tcore_hal_set_power_state(hal, TRUE);
790         } else {                                        /* Powering OFF */
791                 dbg("Powering OFF");
792                 return tcore_hal_set_power_state(hal, FALSE);
793         }
794 }
795
796 static TReturn _cmux_hal_send(TcoreHal *hal, unsigned int data_len, void *data)
797 {
798         tcore_cmux_object *cmux_obj;
799         char *hal_name;
800         unsigned char *send_data;
801         char *channel_name;
802         int channel_id;
803         int len;
804
805         TReturn ret = TCORE_RETURN_FAILURE;
806         dbg("Entry");
807
808         /* Check if Logical HAL is Powered ON */
809         if (tcore_hal_get_power_state(hal) == FALSE) {
810                 err("HAL is not Powered UP");
811                 return TCORE_RETURN_FAILURE;
812         }
813
814         /*
815          * Get CMUX Object from Modem Interface Plug-in
816          */
817         cmux_obj = _cmux_get_cmux_object(tcore_hal_ref_plugin(hal));
818         if (cmux_obj == NULL) {
819                 err("Failed to find CMUX object");
820                 return TCORE_RETURN_FAILURE;
821         }
822
823         channel_id = cmux_obj->max_cmux_channels + 1;
824
825         channel_name = tcore_hal_get_name(hal);
826         dbg("HAL name: [%s]", channel_name);
827
828         if (channel_name != NULL) {
829                 int i;
830
831                 /*
832                  * Channel 0 is dedicated to CMUX Control Channel,
833                  * hence starting from 1.
834                  */
835                 for (i = 1 ; cmux_obj->max_cmux_channels > i ; i++) {
836                         hal_name =
837                                 tcore_hal_get_name(cmux_obj->internal_mux.channel_info[i]->hal);
838                         if (hal_name == NULL) {
839                                 dbg("HAL name: [%s]", hal_name);
840                                 continue;
841                         }
842
843                         /*
844                          * Comparing all Logical HAL names with required HAL name.
845                          */
846                         if (strcmp(hal_name, channel_name) == 0) {
847                                 channel_id = cmux_obj->internal_mux.channel_info[i]->channel_id;
848                                 dbg("Found Channel ID: [%d]", channel_id);
849
850                                 /* Free HAL name */
851                                 g_free(hal_name);
852
853                                 break;
854                         }
855
856                         /* Free HAL name */
857                         g_free(hal_name);
858                 }
859
860                 /* Free memory */
861                 g_free(channel_name);
862         } else {
863                 err("No name defined for HAL");
864                 return ret;
865         }
866
867         if (channel_id > cmux_obj->max_cmux_channels) {
868                 err("Failed to find Channel ID");
869                 return ret;
870         }
871
872         /* Muxing operation and Frame creation */
873         /* Encoding frame */
874         send_data = _cmux_encode_cmux_frame(cmux_obj, data, data_len, channel_id,
875                                         CMUX_COMMAND_UIH, 0x1, 0x1, 0x0, &len);
876         if (len == 0) {
877                 err("Failed to encode");
878                 return TCORE_RETURN_FAILURE;
879         }
880
881         /* Send CMUX data */
882         ret = _cmux_send_data(cmux_obj->phy_hal, len, send_data);
883
884         dbg("Exit");
885         return ret;
886 }
887
888 static TReturn _cmux_hal_setup_netif(CoreObject *co,
889                                 TcoreHalSetupNetifCallback func, void *user_data,
890                                 unsigned int cid, gboolean enable)
891 {
892         tcore_cmux_object *cmux_obj;
893         TcoreHal *hal;
894         dbg("Entry");
895
896         /* Get secondary HAL from Core Object */
897         hal = tcore_object_get_hal(co);
898
899         /*
900          * Get CMUX Object from Modem Interface Plug-in
901          */
902         cmux_obj = _cmux_get_cmux_object(tcore_hal_ref_plugin(hal));
903         if (cmux_obj == NULL)
904                 return TCORE_RETURN_FAILURE;
905
906         return tcore_hal_setup_netif(cmux_obj->phy_hal,
907                                                                 co, func, user_data, cid, enable);
908 }
909
910 /* CMUX supported HAL (Logical HAL) operations */
911 static struct tcore_hal_operations cmux_hops = {
912         .power = _cmux_hal_power,
913         .send = _cmux_hal_send,
914         .setup_netif = _cmux_hal_setup_netif,
915 };
916
917 static TcoreHal *_cmux_create_logical_hal(tcore_cmux_object *cmux_obj,
918                                                                 tcore_cmux_channel *channel)
919 {
920         TcoreHal *hal;
921         char channel_id_name[CMUX_MAX_CHANNEL_NAME];
922         dbg("Entry");
923
924         if ((cmux_obj == NULL) || (channel == NULL)) {
925                 err("Invalid input parameters");
926                 return NULL;
927         }
928
929         /* Creating Logical HAL for Core Object - Mode - 'AT mode' */
930         snprintf(channel_id_name, sizeof(channel_id_name),
931                                                 "channel_%d", channel->channel_id);
932
933         /* Creating Logical HAL */
934         hal = tcore_hal_new(cmux_obj->plugin,
935                                         channel_id_name, &cmux_hops, TCORE_HAL_MODE_AT);
936         dbg("hal: %p", hal);
937         if (hal == NULL) {
938                 err("Failed to allocate memory");
939                 return NULL;
940         }
941
942         /* Updating Logical HAL of CMUX Channel */
943         channel->hal = hal;
944
945         dbg("Exit");
946         return hal;
947 }
948
949 tcore_cmux_object *_cmux_new(int max_channels, unsigned int buffer_size)
950 {
951         tcore_cmux_object *cmux_obj;
952         int i;
953         dbg("Entry");
954
955         /* Allocating memory for mux */
956         cmux_obj = (tcore_cmux_object *)g_try_new0(tcore_cmux_object, 1);
957         if (cmux_obj == NULL) {
958                 err("Failed to allocate memory");
959                 return NULL;
960         }
961
962         /* Allocating memory for info_field */
963         cmux_obj->internal_mux.info_field =
964                                         (unsigned char *)g_try_malloc0(buffer_size);
965         if (cmux_obj->internal_mux.info_field == NULL) {
966                 err("Failed to allocate memory for info field");
967                 goto ERROR;
968         }
969
970         /* CMUX State initialize to CMUX_NOT_INITIALIZED */
971         cmux_obj->cmux_state = CMUX_NOT_INITIALIZED;
972
973         /*
974          * Allocating memory for channel_info
975          * max_channels defines the maximum channels user requested,
976          * hence + 1 is required for CMUX Control Channel
977          */
978         for (i = 0; i < (max_channels + 1) ; i++) {
979                 /* Allocating memory for channel_info */
980                 cmux_obj->internal_mux.channel_info[i] =
981                                 (tcore_cmux_channel *)g_try_new0(tcore_cmux_channel, 1);
982                 if (cmux_obj->internal_mux.channel_info[i] == NULL) {
983                         err("Failed to allocate memory for channel_info of channel: [%d]", i);
984                         goto ERROR;
985                 }
986         }
987
988         dbg("Exit");
989         return cmux_obj;
990
991 ERROR:
992         /* Free allocated memory */
993         if (cmux_obj != NULL) {
994                 /* Free info_field */
995                 g_free(cmux_obj->internal_mux.info_field);
996
997                 for (i = 0; i < (max_channels + 1) ; i++)
998                         /* Free channel_info */
999                         g_free(cmux_obj->internal_mux.channel_info[i]);
1000
1001                 /* Free CMUX object memory */
1002                 g_free(cmux_obj);
1003         }
1004
1005         err("Exit");
1006         return NULL;
1007 }
1008
1009 static void _cmux_channel_init(tcore_cmux_object *cmux_obj, int channel_id)
1010 {
1011         tcore_cmux_channel *ch;
1012         dbg("Entry");
1013
1014         ch = cmux_obj->internal_mux.channel_info[channel_id];
1015         if (ch == NULL)
1016                 return;
1017
1018         ch->channel_id = channel_id;
1019         ch->channel_state = CMUX_CHANNEL_SABM_SEND_WAITING_FOR_UA;
1020
1021         ch->hal = NULL;
1022
1023         /* TODO - Check if required */
1024         ch->frame_type = CMUX_COMMAND_SABM;
1025         ch->ext_bit = 0x01;
1026         ch->cr_bit = 0x01;
1027         ch->poll_final_bit = 0x01;
1028
1029         dbg("Channel ID [%d] - Initialized", channel_id);
1030 }
1031
1032 static void _cmux_close_channel(tcore_cmux_object *cmux_obj, int channel_id)
1033 {
1034         tcore_cmux_channel *ch;
1035         unsigned char *send_data;
1036         int ret, len = 0;
1037         dbg("Entry");
1038
1039         ch = cmux_obj->internal_mux.channel_info[channel_id];
1040         if (ch == NULL)
1041                 return;
1042
1043         if (ch->channel_state != CMUX_CHANNEL_CLOSED) {
1044                 ch->frame_type = CMUX_COMMAND_DISC;
1045                 ch->ext_bit = 0x01;
1046                 ch->cr_bit = 0x01;
1047                 ch->channel_state = CMUX_CHANNEL_DISC_SEND_WAITING_FOR_UA;
1048
1049                 /* Send DSC command */
1050                 /* Encoding frame */
1051                 send_data = _cmux_encode_cmux_frame(cmux_obj, NULL, 0, channel_id,
1052                                                 CMUX_COMMAND_DISC, 0x01, 0x01, 0x01, &len);
1053                 if (len != 0) {
1054                         /* Send CMUX data */
1055                         ret = _cmux_send_data(cmux_obj->phy_hal, len, send_data);
1056             dbg("return %d", ret);
1057         }
1058                 else {
1059                         err("Failed to encode");
1060         }
1061         } else
1062                 /* Channel is already closed */
1063                 err("Channel is already closed");
1064
1065         dbg("Exit");
1066 }
1067
1068 static void _cmux_free(tcore_cmux_object *cmux_obj)
1069 {
1070         int channel;
1071         dbg("Entry");
1072
1073         /*
1074          * This function is used internally only, hence sanity check for 'cmux_obj'
1075          * is NOT required.
1076          */
1077         /* Free Information Field */
1078         g_free(cmux_obj->internal_mux.info_field);
1079         cmux_obj->internal_mux.info_field = NULL;
1080
1081         for (channel = 0; channel < cmux_obj->max_cmux_channels; channel++) {
1082                 /* Free Channel Information */
1083                 g_free(cmux_obj->internal_mux.channel_info[channel]);
1084                 cmux_obj->internal_mux.channel_info[channel] = NULL;
1085         }
1086
1087         /* Free CMUX Object */
1088         g_free(cmux_obj);
1089         cmux_obj = NULL;
1090
1091         dbg("Exit");
1092 }
1093
1094 static void _cmux_on_confirmation_message_send(TcorePending *plugin,
1095                                                                                         gboolean result, void *user_data)
1096 {
1097         dbg("Message out from queue");
1098
1099         if (result == FALSE) {          /* Fail */
1100                 err("SEND FAIL");
1101         } else
1102                 dbg("SEND OK");
1103 }
1104
1105 void tcore_cmux_rcv_from_hal(TcoreHal *hal, unsigned char *data, size_t length)
1106 {
1107 #define TCORE_CMUX_DECODE_FLAG_HUNT                     0
1108 #define TCORE_CMUX_DECODE_ADDR_HUNT                     1
1109 #define TCORE_CMUX_DECODE_CONTROL_HUNT          2
1110 #define TCORE_CMUX_DECODE_LENGTH1_HUNT          3
1111 #define TCORE_CMUX_DECODE_LENGTH2_HUNT          4
1112 #define TCORE_CMUX_DECODE_DATA_HUNT                     5
1113 #define TCORE_CMUX_DECODE_FCS_HUNT                      6
1114
1115         tcore_cmux_object *cmux_obj;
1116
1117         static int decode_state = TCORE_CMUX_DECODE_FLAG_HUNT;
1118         static unsigned char dec_fcs;
1119         static unsigned char *dec_data;
1120         static unsigned short dec_length;
1121         static size_t full_frame_len;
1122
1123         size_t pos = -1;
1124         int cp_len;
1125         dbg("Entry");
1126
1127         /*
1128          * Get CMUX Object from Modem Interface Plug-in
1129          */
1130         cmux_obj = _cmux_get_cmux_object(tcore_hal_ref_plugin(hal));
1131         if (cmux_obj == NULL)
1132                 return;
1133
1134 DECODE_STATE_CHANGE:
1135         if (++pos >= length)
1136                 return;
1137
1138         switch(decode_state) {
1139                 case TCORE_CMUX_DECODE_FLAG_HUNT:
1140                         full_frame_len = 0;
1141                         dec_length = 0;
1142                         dec_fcs = 0xFF;
1143                         dec_data = cmux_obj->cmux_buffer;
1144                         goto FLAG_HUNT;
1145                 break;
1146                 case TCORE_CMUX_DECODE_ADDR_HUNT:
1147                         goto ADDR_HUNT;
1148                 break;
1149                 case TCORE_CMUX_DECODE_CONTROL_HUNT:
1150                         goto CONTROL_HUNT;
1151                 break;
1152                 case TCORE_CMUX_DECODE_LENGTH1_HUNT:
1153                         goto LENGTH1_HUNT;
1154                 break;
1155                 case TCORE_CMUX_DECODE_LENGTH2_HUNT:
1156                         goto LENGTH2_HUNT;
1157                 break;
1158                 case TCORE_CMUX_DECODE_DATA_HUNT:
1159                         goto DATA_HUNT;
1160                 break;
1161                 case TCORE_CMUX_DECODE_FCS_HUNT:
1162                         goto FCS_HUNT;
1163                 break;
1164                 default:
1165                         warn("invalid decode_state");
1166                 break;  
1167         }
1168
1169 FLAG_HUNT:
1170         while (data[pos] != CMUX_FRAME_DELIMITER)
1171                 if (++pos >= length)
1172                         return;
1173
1174         decode_state = TCORE_CMUX_DECODE_ADDR_HUNT;
1175         goto DECODE_STATE_CHANGE;
1176
1177 ADDR_HUNT:
1178         while (data[pos] == CMUX_FRAME_DELIMITER)
1179                 if (++pos >= length)
1180                         return;
1181
1182         dec_fcs = crc_table[dec_fcs^data[pos]];
1183         decode_state = TCORE_CMUX_DECODE_CONTROL_HUNT;
1184         *dec_data++ = CMUX_FRAME_DELIMITER;
1185         *dec_data++ = data[pos];
1186         full_frame_len += 2;
1187         goto DECODE_STATE_CHANGE;
1188
1189 CONTROL_HUNT:
1190         dec_fcs = crc_table[dec_fcs^data[pos]];
1191         decode_state = TCORE_CMUX_DECODE_LENGTH1_HUNT;
1192         *dec_data++ = data[pos];
1193         full_frame_len++;
1194         goto DECODE_STATE_CHANGE;
1195
1196 LENGTH1_HUNT:
1197         dec_length = data[pos] >> 1;
1198         dec_fcs = crc_table[dec_fcs^data[pos]];
1199         if (data[pos] & 0x1)            /* EA */
1200                 if (dec_length > 0)
1201                         decode_state = TCORE_CMUX_DECODE_DATA_HUNT;
1202                 else
1203                         decode_state = TCORE_CMUX_DECODE_FCS_HUNT;
1204         else
1205                 decode_state = TCORE_CMUX_DECODE_LENGTH2_HUNT;
1206
1207         *dec_data++ = data[pos];
1208         full_frame_len++;
1209         goto DECODE_STATE_CHANGE;
1210
1211 LENGTH2_HUNT:
1212         dec_length |= ((unsigned short)data[pos] << 7);
1213         dec_fcs = crc_table[dec_fcs^data[pos]];
1214         decode_state = TCORE_CMUX_DECODE_DATA_HUNT;
1215         *dec_data++ = data[pos];
1216         full_frame_len++;
1217         goto DECODE_STATE_CHANGE;
1218
1219 DATA_HUNT:
1220         if (dec_length < (length - pos)) {      /* frame data fully available in the buffer */
1221                 cp_len = dec_length;
1222                 decode_state = TCORE_CMUX_DECODE_FCS_HUNT;
1223         } else {                                                /* frame data partially available in the buffer */
1224                 cp_len = (length - pos);
1225                 decode_state = TCORE_CMUX_DECODE_DATA_HUNT;
1226         }
1227
1228         memcpy(dec_data, data + pos, cp_len);
1229         dec_data += cp_len;
1230         pos += (cp_len - 1);
1231         dec_length -= cp_len;
1232         full_frame_len += cp_len;
1233
1234         goto DECODE_STATE_CHANGE;
1235
1236 FCS_HUNT:
1237         *dec_data++ = data[pos];
1238         *dec_data++ = CMUX_FRAME_DELIMITER;
1239         full_frame_len += 2;
1240         _cmux_process_rcv_frame(cmux_obj, full_frame_len);
1241
1242         /* enter flag hunt mode */
1243         decode_state = TCORE_CMUX_DECODE_FLAG_HUNT;
1244         goto DECODE_STATE_CHANGE;
1245 }
1246
1247 /* CMUX initialization */
1248 TReturn tcore_cmux_init(TcoreHal *phy_hal, unsigned int frame_size,
1249                                         TcorePendingResponseCallback resp_cb, void *resp_cb_data)
1250 {
1251         TcorePending *pending = NULL;
1252         TcoreATRequest *req = NULL;
1253         TReturn ret = TCORE_RETURN_FAILURE;
1254         char *cmd_str;
1255         dbg("Entry");
1256
1257         if ((phy_hal == NULL) || (resp_cb == NULL))
1258                 return TCORE_RETURN_EINVAL;
1259
1260         if (frame_size > 32768)
1261                 return TCORE_RETURN_EINVAL;
1262
1263         /*
1264          * 3GPP 27.010 Section 5.7.2 Maximum Frame Size (N1)
1265          * If frame size is greater than Zero then,
1266          * the request is sent for frame size
1267          * else,
1268          * request is sent for 'default' frame size
1269          * (default Value: 31 (64 if Advanced option is used)).
1270          */
1271         if (frame_size > 0)
1272                 cmd_str = g_strdup_printf("AT+CMUX=0,0,%d,1509,10,3,30,,", frame_size);
1273         else
1274                 cmd_str = g_strdup_printf("AT+CMUX=0,0,,1509,10,3,30,,");
1275
1276         if (cmd_str == NULL)
1277                 return TCORE_RETURN_ENOMEM;
1278
1279         /* Create Pending Request */
1280         pending = tcore_pending_new(NULL, 0);
1281         if (pending == NULL) {
1282                 dbg("Pending is NULL");
1283
1284                 g_free(cmd_str);
1285                 return ret;
1286         }
1287
1288         /* Create AT-Command Request */
1289         req = tcore_at_request_new(cmd_str, "+CMUX:", TCORE_AT_NO_RESULT);
1290
1291         /* Free command string */
1292         g_free(cmd_str);
1293
1294         if (req == NULL) {
1295                 dbg("Request is NULL");
1296                 tcore_pending_free(pending);
1297                 return ret;
1298         }
1299         dbg("AT Command: [%s], Prefix(if any): [%s], AT-Command length: [%d]", req->cmd, req->prefix, strlen(req->cmd));
1300
1301         tcore_pending_set_request_data(pending, 0, req);
1302         tcore_pending_set_response_callback(pending, resp_cb, resp_cb_data);
1303         tcore_pending_set_send_callback(pending, _cmux_on_confirmation_message_send, NULL);
1304
1305         ret = tcore_hal_send_request(phy_hal, pending);
1306
1307         dbg("Exit");
1308         return ret;
1309 }
1310
1311 /* Setup Internal CMUX */
1312 TReturn tcore_cmux_setup_internal_mux(tcore_cmux_mode mode,
1313         int max_channels, unsigned int cmux_buf_size, TcoreHal *phy_hal,
1314         cmux_setup_cb_func channel_setup_cb, gpointer channel_setup_user_data,
1315         cmux_setup_complete_cb_func setup_complete_cb, gpointer setup_complete_user_data)
1316 {
1317         tcore_cmux_object *cmux_obj;
1318         unsigned char *data;
1319         int data_len;
1320         int temp_index;
1321
1322         TReturn ret = TCORE_RETURN_FAILURE;
1323         dbg("Entry");
1324         dbg("Internal CMUX setup request");
1325
1326         /* Sanity Check */
1327         if ((cmux_buf_size <= 0)
1328                         || (phy_hal == NULL)
1329                         || (channel_setup_cb == NULL)
1330                         || (setup_complete_cb == NULL)) {
1331                 err("CMUX Buffer size: [%d] Physical HAL: [0x%x] setup_complete_cb: [0x%x]",
1332                         cmux_buf_size, (unsigned int)phy_hal, setup_complete_cb);
1333                 return TCORE_RETURN_EINVAL;
1334         }
1335
1336         dbg("Physical HAL: [0x%x] cmux_buf_size: [%d]",
1337                                                                 (unsigned int)phy_hal, cmux_buf_size);
1338
1339         /*
1340          * Max Channels
1341          *      (+ 1) is for CMUX Control Channel
1342          */
1343         if ((max_channels +1) >= CMUX_CHANNEL_MAX) {
1344                 err("Number of Channels requested is greater than supported");
1345                 return TCORE_RETURN_EINVAL;
1346         }
1347
1348         /* Create new CMUX Object */
1349         cmux_obj = _cmux_new(max_channels, cmux_buf_size);
1350         if (cmux_obj == NULL) {
1351                 err("Failed to create CMUX object");
1352                 return TCORE_RETURN_ENOMEM;
1353         }
1354
1355         /* Maximum Buffer size for CMUX frame processing */
1356         cmux_obj->max_cmux_buf_size = cmux_buf_size;
1357
1358         /* Maximum Channels requested */
1359         cmux_obj->max_cmux_channels = max_channels + 1;
1360
1361         /* Allocating buffer for CMUX frames proposing */
1362         cmux_obj->cmux_buffer = (unsigned char *)g_try_malloc0(cmux_buf_size);
1363         if (cmux_obj->cmux_buffer == NULL) {
1364                 err("Failed to allocate memory");
1365
1366                 ret = TCORE_RETURN_ENOMEM;
1367                 goto ERROR;
1368         }
1369
1370         /* Update 'mode' */
1371         cmux_obj->cmux_mode = mode;
1372         dbg("Mode: \'%s\'", (mode == CMUX_MODE_BASIC ? "Basic" : "Advanced"));
1373
1374         /* Save Physical HAL */
1375         cmux_obj->phy_hal = phy_hal;
1376
1377         /* Save Modem Interface Plug-in */
1378         cmux_obj->plugin = tcore_hal_ref_plugin(phy_hal);
1379
1380         /* CMUX setup callback function */
1381         cmux_obj->internal_mux.channel_setup_cb = channel_setup_cb;
1382         cmux_obj->internal_mux.channel_setup_user_data = channel_setup_user_data;
1383
1384         /* CMUX setup complete callback function */
1385         cmux_obj->internal_mux.setup_complete_cb = setup_complete_cb;
1386         cmux_obj->internal_mux.setup_complete_user_data = setup_complete_user_data;
1387
1388         /*
1389          * After CMUX setup, AT parse functionality of PHY HAL should be disabled,
1390          * here we change the mode of PHYSICAL HAL to Transparent from AT.
1391          */
1392         tcore_hal_set_mode(phy_hal, TCORE_HAL_MODE_TRANSPARENT);
1393         dbg("Physical HAL mode changed to Transparent");
1394
1395         /* Adding CMUX object to Global List */
1396         g_cmux_obj = g_slist_insert(g_cmux_obj, cmux_obj, 0);
1397
1398         /* Initialize all the Channels for the CMUX object */
1399         /* Open all Channels */
1400         for (temp_index = 0; temp_index < cmux_obj->max_cmux_channels; temp_index++) {
1401                 dbg("Initializing CMUX Channel [%d]", temp_index);
1402                 _cmux_channel_init(cmux_obj, temp_index);
1403
1404                 dbg("Opening Channel ID [%d]", temp_index);
1405                 /* Encode CMUX Frame */
1406                 data = _cmux_encode_cmux_frame(cmux_obj, NULL, 0, temp_index,
1407                                         CMUX_COMMAND_SABM, 0x01, 0x01, 0x01, &data_len);
1408                 if (data_len == 0) {
1409                         err("Failed to encode");
1410                         goto ERROR;
1411                 }
1412                 dbg("data_len: [%d] data: [%s]", data_len, data);
1413
1414                 /* Send CMUX data */
1415                 ret = _cmux_send_data(cmux_obj->phy_hal, data_len, data);
1416                 if (ret != TCORE_RETURN_SUCCESS) {
1417                         err("Failed to send CMUX Control Request for Channel ID: [%d]", temp_index);
1418                         goto ERROR;
1419                 } else
1420                         dbg("CMUX Control Request sent to CP");
1421         }
1422
1423         dbg("Exit");
1424         return ret;
1425
1426 ERROR:
1427         /* Free the allocated CMUX memory */
1428         _cmux_free(cmux_obj);
1429
1430         err("Exit");
1431         return ret;
1432 }
1433
1434 /* Close CMUX */
1435 void tcore_cmux_close(TcoreHal *phy_hal,
1436         cmux_channel_close_cb_func channel_close_cb, gpointer channel_close_user_data)
1437 {
1438         tcore_cmux_object *cmux_obj;
1439         int channel_id;
1440         dbg("Entry");
1441
1442         /*
1443          * Get CMUX Object from Modem Interface Plug-in
1444          */
1445         cmux_obj = _cmux_get_cmux_object(tcore_hal_ref_plugin(phy_hal));
1446         if (cmux_obj == NULL)
1447                 return;
1448
1449         /* Internal CMUX */
1450         dbg("Closing Internal CMUX");
1451
1452         /* Close all Channels */
1453         for (channel_id = 0;
1454                         channel_id < cmux_obj->max_cmux_channels;
1455                         channel_id++) {
1456                 dbg("Closing Channel - ID: [%d]", channel_id);
1457
1458                 /* Close Channel - Send DSC command */
1459                 _cmux_close_channel(cmux_obj, channel_id);
1460
1461                 /* Invoke callback */
1462                 if (channel_close_cb != NULL)
1463                         channel_close_cb(cmux_obj->internal_mux.channel_info[channel_id]->hal,
1464                                                 channel_close_user_data);
1465
1466                 /* Free Logical HAL for Channel */
1467                 tcore_hal_free(cmux_obj->internal_mux.channel_info[channel_id]->hal);
1468                 cmux_obj->internal_mux.channel_info[channel_id]->hal = NULL;
1469         }
1470
1471         /* Freeing CMUX frame processing buffer */
1472         g_free(cmux_obj->cmux_buffer);
1473         cmux_obj->cmux_buffer = NULL;
1474
1475         /* Change the mode of PHYSICAL HAL from Transparent to AT */
1476         tcore_hal_set_mode(cmux_obj->phy_hal, TCORE_HAL_MODE_AT);
1477
1478         /* Remove from list */
1479         g_cmux_obj = g_slist_remove(g_cmux_obj, cmux_obj);
1480
1481         /* Free all the allocated memory */
1482         _cmux_free(cmux_obj);
1483
1484         dbg("Exit");
1485 }