4 * Copyright (c) 2012 Samsung Electronics Co., Ltd. All rights reserved.
5 * Contact: Arijit Sen <arijit.sen@samsung.com>
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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.
25 #include <sys/ioctl.h>
32 #include "core_object.h"
34 #include "user_request.h"
39 /* Channel name maximum length */
40 #define CMUX_MAX_CHANNEL_NAME 16
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
50 /* CMUX Delimiter Byte */
51 #define CMUX_FRAME_DELIMITER 0xF9
54 * CMUX Channels [0-64] -
56 * CMUX_CHANNEL_0 is dedicated CMUX Control Channnel.
59 CMUX_CHANNEL_NONE = -1, /* No CMUX */
60 CMUX_CHANNEL_0 = 0, /* CMUX Control Channel */
62 CMUX_CHANNEL_MAX = 65 /* Based on #GPP 27.010 */
63 } tcore_cmux_channel_id;
68 * Only Internal CMUX Channel states are managed,
69 * Kernel CMUX Channel states are managed by Kernel directly.
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,
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;
93 * CMUX CONTROL COMMANDS
94 * We are supporting only MSC and CLD commands for phase 1
96 /* Modem Status Command */
97 #define CMUX_COMMAND_MSC 0xE3
98 /* Multiplexer close down */
99 #define CMUX_COMMAND_CLD 0xC3
101 #define FIND_LENGTH(buf, header_length, total_length) do { \
103 total_length = *buf++ >> 1; \
106 total_length = *(buf + 0x01) << 7; \
107 total_length = total_length | (*buf & 0xFE) >> 1; \
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
147 /*================= CRC TABLE=========================*/
150 struct cmux_channel {
153 tcore_cmux_channel_state channel_state;
154 tcore_cmux_channel_id channel_id;
157 unsigned char ext_bit;
158 unsigned char cr_bit;
159 unsigned char poll_final_bit;
162 /* CMUX structure - Internal */
163 struct cmux_internal {
164 tcore_cmux_channel *channel_info[CMUX_CHANNEL_MAX];
169 int cur_main_buf_len;
171 /* Channel Setup callbacks */
172 cmux_setup_cb_func channel_setup_cb;
173 gpointer channel_setup_user_data;
175 /* Channel Setup complete callback */
176 cmux_setup_complete_cb_func setup_complete_cb;
177 gpointer setup_complete_user_data;
180 unsigned char *info_field;
183 /* Global CMUX Object */
188 /* Modem Interface Plug-in */
191 tcore_cmux_state cmux_state;
193 tcore_cmux_mode cmux_mode;
194 int max_cmux_channels;
195 unsigned int max_cmux_buf_size;
197 /* CMUX frame processing buffer */
198 unsigned char *cmux_buffer;
200 /* Only Internal MUX is managed by libtcore */
201 struct cmux_internal internal_mux;
205 static GSList *g_cmux_obj = NULL;
207 /* All the local functions declared below */
208 static void _cmux_on_confirmation_message_send(TcorePending *plugin,
209 gboolean result, void *user_data);
211 tcore_cmux_object *_cmux_new(int max_channels, unsigned int buffer_size);
212 static void _cmux_free(tcore_cmux_object *cmux_obj);
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);
217 static TcoreHal *_cmux_create_logical_hal(tcore_cmux_object *cmux_obj,
218 tcore_cmux_channel *channel);
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);
226 static void _cmux_control_channel_handle(tcore_cmux_object *cmux_obj);
227 static void _cmux_flush_channel_data(tcore_cmux_object *cmux_obj);
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);
235 static tcore_cmux_object *_cmux_get_cmux_object(TcorePlugin *plugin);
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);
242 static unsigned char _cmux_calc_crc(unsigned char *header, int length)
244 unsigned char fcs = 0xFF; /* Init */
245 unsigned char crc = 0x00;
248 * 'length' is the number of bytes in the message,
249 * 'header' points to message
252 fcs = crc_table[fcs ^ *header++];
254 /* Ones complement */
257 dbg("Exit - CRC: [0x%02x]", crc)
261 static int _cmux_check_recv_crc(unsigned char *data,
262 unsigned char length,
263 unsigned char rcv_fcs)
265 unsigned char fcs = 0xFF; /* Init */
268 * 'length' is the number of bytes in the message,
269 * 'data' points to message
272 fcs = crc_table[fcs ^ *data++];
274 /* Ones complement */
275 fcs = crc_table[fcs ^ rcv_fcs];
277 /* 0xCF is the reversed order of 11110011 */
278 if (fcs == 0xCF) /* FCS is OK */
280 else /* FCS is NOT OK */
284 static tcore_cmux_object *_cmux_get_cmux_object(TcorePlugin *plugin)
286 tcore_cmux_object *cmux_obj;
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)
296 /* Check for matching 'plugin' */
297 if (plugin == cmux_obj->plugin) {
298 dbg("Found CMUX object");
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)
311 int frame_length = 0;
312 int total_frame_length = 0;
316 /* Flush channel data */
317 _cmux_flush_channel_data(cmux_obj);
319 if (length > cmux_obj->max_cmux_buf_size) {
320 err("Length - %d exceeds the limit", length);
325 cmux_obj->internal_mux.info_field[frame_length++] = CMUX_FRAME_DELIMITER;
327 /* Mode of Operation */
328 if (cmux_obj->cmux_mode == CMUX_MODE_BASIC) { /* BASIC */
331 * C/R: Command Response
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)));
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));
345 err("Channel ID [%d] is out of range [0-%d]",
346 channel_id, cmux_obj->max_cmux_channels);
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 ******************************************************************/
364 cmux_obj->internal_mux.info_field[frame_length++] =
367 cmux_obj->internal_mux.info_field[frame_length++] = frame_type;
369 /* 5.2.1.5 Length Indicator */
371 cmux_obj->internal_mux.info_field[frame_length++] =
372 (char) length << 1 | 0x01;
374 /* CRC calculatable length */
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);
382 /* CRC calculatable length */
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.
392 /* 5.2.1.4 Information Field */
394 memcpy((cmux_obj->internal_mux.info_field + frame_length),
396 frame_length += length;
398 dbg("info field length is zero");
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);
405 cmux_obj->internal_mux.info_field[frame_length++] = CMUX_FRAME_DELIMITER;
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");
413 *out_data_len = total_frame_length;
414 dbg("Data (Frame) Length: [%d]", *out_data_len);
416 return cmux_obj->internal_mux.info_field;
419 static void _cmux_control_channel_handle(tcore_cmux_object *cmux_obj)
421 unsigned char cmd_type;
423 unsigned char *msg_start_ptr;
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
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];
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.
440 * Search for the last octet
442 while ((*msg_start_ptr++ & 0x01))
445 if ((cmd_type & 0x02) == 0x02) { /* This is a command Request */
447 case CMUX_COMMAND_MSC:
448 dbg("Modem Status Command");
450 case CMUX_COMMAND_CLD:
451 dbg("Multiplexer close down");
453 cmux_obj->cmux_state = CMUX_CLOSED;
455 /* TODO - Need to notify regarding CMUX closure */
456 tcore_cmux_close(cmux_obj->phy_hal, NULL, NULL);
459 /* We will be supporting these commands in Phase 2 */
465 err("Frame length is less than ZERO");
470 static void _cmux_process_channel_data(tcore_cmux_object *cmux_obj,
471 tcore_cmux_channel *channel)
476 unsigned char *send_data;
477 static int count = 0;
481 channel_id = channel->channel_id;
482 dbg("Channel ID: [%d]", channel_id);
484 frame_type = channel->frame_type & 0xEF;
485 dbg("Frame Type: [0x%02x]", frame_type);
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);
495 dbg("Normal information");
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");
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;
507 if (channel->channel_id != CMUX_CHANNEL_0) {
510 /* Create Logical HAL */
511 hal = _cmux_create_logical_hal(cmux_obj, channel);
513 dbg("Invoking CMUX Channel Setup callback for [%d] channel",
514 channel->channel_id);
516 * 'channel_setup_cb' cannot be NULL as it is MANDATED during
517 * CMUX setup operation.
519 cmux_obj->internal_mux.channel_setup_cb(channel->channel_id, hal,
520 cmux_obj->internal_mux.channel_setup_user_data);
522 err("Failed to Create Logical HAL");
526 dbg("Count: [%d]", count);
527 if (cmux_obj->max_cmux_channels == count) {
528 dbg("Invoking CMUX Channel Setup Complete callback - Total Channels: [%d]",
531 * 'setup_complete_cb' cannot be NULL as it is MANDATED during
532 * CMUX setup operation.
534 cmux_obj->internal_mux.setup_complete_cb(
535 cmux_obj->internal_mux.setup_complete_user_data);
540 } else if (CMUX_CHANNEL_DISC_SEND_WAITING_FOR_UA ==
541 channel->channel_state) {
542 channel->channel_state = CMUX_CHANNEL_CLOSED;
544 if (channel_id == CMUX_CHANNEL_0) {
545 cmux_obj->cmux_state = CMUX_CLOSED;
547 /* TODO - Need to notify regarding CMUX closure */
548 tcore_cmux_close(cmux_obj->phy_hal, NULL, NULL);
551 err("Received UA in wrong state!!!");
554 case CMUX_COMMAND_DM:
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
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;
568 /* Flush the Channel data */
569 _cmux_flush_channel_data(cmux_obj);
571 case CMUX_COMMAND_DISC:
572 dbg("Received DISC Frame");
573 if (channel->poll_final_bit == 0) {
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
581 /* Flush the Channel data */
582 _cmux_flush_channel_data(cmux_obj);
584 if (channel->channel_state == CMUX_CHANNEL_CLOSED) {
586 * If a CMUX_COMMAND_DISC command is received while in
587 * disconnected mode a CMUX_COMMAND_DM response should
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 */
597 send_data = _cmux_encode_cmux_frame(cmux_obj, NULL,
598 0, channel_id, CMUX_COMMAND_UA,
599 0x01, 0x01, 0x01, &len);
603 err("Failed to encode");
608 ret = _cmux_send_data(cmux_obj->phy_hal, len, send_data);
610 /* Flush the Channel data */
611 _cmux_flush_channel_data(cmux_obj);
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.
618 if (channel_id == CMUX_CHANNEL_0) {
619 cmux_obj->cmux_state = CMUX_CLOSED;
622 /* TODO - Need to notify regarding CMUX closure */
623 tcore_cmux_close(cmux_obj->phy_hal, NULL, NULL);
627 case CMUX_COMMAND_SABM:
628 dbg("Received SABM Frame");
629 if (channel->poll_final_bit == 0) {
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.
636 /* Flush the Channel data */
637 _cmux_flush_channel_data(cmux_obj);
640 send_data = _cmux_encode_cmux_frame(cmux_obj, NULL,
641 0, channel_id, CMUX_COMMAND_UA,
642 0x01, 0x01, 0x01, &len);
645 ret = _cmux_send_data(cmux_obj->phy_hal, len, send_data);
647 err("Failed to encode");
649 if (channel->channel_state != CMUX_CHANNEL_ESTABLISHED)
650 /* Channel State set to Established */
651 channel->channel_state = CMUX_CHANNEL_ESTABLISHED;
659 static void _cmux_flush_channel_data(tcore_cmux_object *cmux_obj)
663 if (cmux_obj == NULL)
666 cmux_obj->internal_mux.info_field_len = 0x0;
667 memset(cmux_obj->internal_mux.info_field, 0x0, cmux_obj->max_cmux_buf_size);
672 static void _cmux_process_rcv_frame(tcore_cmux_object *cmux_obj, int length)
674 unsigned char *frame_process_ptr = cmux_obj->cmux_buffer;
675 unsigned char *buf_start_ptr = cmux_obj->cmux_buffer;
677 tcore_cmux_channel *ch;
678 unsigned char channel_id;
682 /* Flush channel data */
683 _cmux_flush_channel_data(cmux_obj);
685 /* Get the Channel ID: 1st byte will be flag (F9). Flag checking is already done */
686 channel_id = (*++frame_process_ptr >> 2) & 0x3F;
688 if (channel_id < cmux_obj->max_cmux_channels) {
689 ch = cmux_obj->internal_mux.channel_info[channel_id];
691 ch->channel_id = channel_id;
694 ch->ext_bit = *frame_process_ptr & 0x01;
697 ch->cr_bit = (*frame_process_ptr++ >> 1) & 0x01;
699 /* get the Frame Type */
700 ch->frame_type = *frame_process_ptr++;
702 /* get the poll/Final bit */
703 ch->poll_final_bit = (ch->frame_type & 0x10) >> 4;
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;
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));
717 dbg("info_field_len: [%d]", cmux_obj->internal_mux.info_field_len);
719 /* Copy received information field */
720 memcpy(cmux_obj->internal_mux.info_field, frame_process_ptr,
721 cmux_obj->internal_mux.info_field_len);
723 frame_process_ptr = frame_process_ptr + cmux_obj->internal_mux.info_field_len;
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);
730 err("CRC check of the header FAILED.. Drop the packet !!");
732 err("Incorrect channel... Drop the packet !!");
737 static TReturn _cmux_send_data(TcoreHal *hal, int data_len, unsigned char *data)
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");
747 dbg("Successfully sent CMUX data");
753 static gboolean _cmux_recv_cmux_data(tcore_cmux_object *cmux_obj,
754 tcore_cmux_channel *channel)
759 /* Dereferencing HAL from Channel Pointer */
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) {
779 static TReturn _cmux_hal_power(TcoreHal *hal, gboolean flag)
783 if (flag == TRUE) { /* Powering ON */
785 return tcore_hal_set_power_state(hal, TRUE);
786 } else { /* Powering OFF */
788 return tcore_hal_set_power_state(hal, FALSE);
792 static TReturn _cmux_hal_send(TcoreHal *hal, unsigned int data_len, void *data)
794 tcore_cmux_object *cmux_obj;
796 unsigned char *send_data;
801 TReturn ret = TCORE_RETURN_FAILURE;
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;
811 * Get CMUX Object from Modem Interface Plug-in
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;
819 channel_id = cmux_obj->max_cmux_channels + 1;
821 channel_name = tcore_hal_get_name(hal);
822 dbg("HAL name: [%s]", channel_name);
824 if (channel_name != NULL) {
828 * Channel 0 is dedicated to CMUX Control Channel,
829 * hence starting from 1.
831 for (i = 1 ; cmux_obj->max_cmux_channels > i ; i++) {
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);
840 * Comparing all Logical HAL names with required HAL name.
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);
857 g_free(channel_name);
859 err("No name defined for HAL");
863 if (channel_id > cmux_obj->max_cmux_channels) {
864 err("Failed to find Channel ID");
868 /* Muxing operation and Frame creation */
870 send_data = _cmux_encode_cmux_frame(cmux_obj, data, data_len, channel_id,
871 CMUX_COMMAND_UIH, 0x1, 0x1, 0x0, &len);
873 err("Failed to encode");
874 return TCORE_RETURN_FAILURE;
878 ret = _cmux_send_data(cmux_obj->phy_hal, len, send_data);
884 static TReturn _cmux_hal_setup_netif(CoreObject *co,
885 TcoreHalSetupNetifCallback func, void *user_data,
886 unsigned int cid, gboolean enable)
888 tcore_cmux_object *cmux_obj;
892 /* Get secondary HAL from Core Object */
893 hal = tcore_object_get_hal(co);
896 * Get CMUX Object from Modem Interface Plug-in
898 cmux_obj = _cmux_get_cmux_object(tcore_hal_ref_plugin(hal));
899 if (cmux_obj == NULL)
900 return TCORE_RETURN_FAILURE;
902 return tcore_hal_setup_netif(cmux_obj->phy_hal,
903 co, func, user_data, cid, enable);
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,
913 static TcoreHal *_cmux_create_logical_hal(tcore_cmux_object *cmux_obj,
914 tcore_cmux_channel *channel)
917 char channel_id_name[CMUX_MAX_CHANNEL_NAME];
920 if ((cmux_obj == NULL) || (channel == NULL)) {
921 err("Invalid input parameters");
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);
929 /* Creating Logical HAL */
930 hal = tcore_hal_new(cmux_obj->plugin,
931 channel_id_name, &cmux_hops, TCORE_HAL_MODE_AT);
934 err("Failed to allocate memory");
938 /* Updating Logical HAL of CMUX Channel */
945 tcore_cmux_object *_cmux_new(int max_channels, unsigned int buffer_size)
947 tcore_cmux_object *cmux_obj;
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");
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");
966 /* CMUX State initialize to CMUX_NOT_INITIALIZED */
967 cmux_obj->cmux_state = CMUX_NOT_INITIALIZED;
970 * Allocating memory for channel_info
971 * max_channels defines the maximum channels user requested,
972 * hence + 1 is required for CMUX Control Channel
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);
988 /* Free allocated memory */
989 if (cmux_obj != NULL) {
990 /* Free info_field */
991 g_free(cmux_obj->internal_mux.info_field);
993 for (i = 0; i < (max_channels + 1) ; i++)
994 /* Free channel_info */
995 g_free(cmux_obj->internal_mux.channel_info[i]);
997 /* Free CMUX object memory */
1005 static void _cmux_channel_init(tcore_cmux_object *cmux_obj, int channel_id)
1007 tcore_cmux_channel *ch;
1010 ch = cmux_obj->internal_mux.channel_info[channel_id];
1014 ch->channel_id = channel_id;
1015 ch->channel_state = CMUX_CHANNEL_SABM_SEND_WAITING_FOR_UA;
1019 /* TODO - Check if required */
1020 ch->frame_type = CMUX_COMMAND_SABM;
1023 ch->poll_final_bit = 0x01;
1025 dbg("Channel ID [%d] - Initialized", channel_id);
1028 static void _cmux_close_channel(tcore_cmux_object *cmux_obj, int channel_id)
1030 tcore_cmux_channel *ch;
1031 unsigned char *send_data;
1035 ch = cmux_obj->internal_mux.channel_info[channel_id];
1039 if (ch->channel_state != CMUX_CHANNEL_CLOSED) {
1040 ch->frame_type = CMUX_COMMAND_DISC;
1043 ch->channel_state = CMUX_CHANNEL_DISC_SEND_WAITING_FOR_UA;
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);
1050 /* Send CMUX data */
1051 ret = _cmux_send_data(cmux_obj->phy_hal, len, send_data);
1053 err("Failed to encode");
1055 /* Channel is already closed */
1056 err("Channel is already closed");
1061 static void _cmux_free(tcore_cmux_object *cmux_obj)
1067 * This function is used internally only, hence sanity check for 'cmux_obj'
1070 /* Free Information Field */
1071 g_free(cmux_obj->internal_mux.info_field);
1072 cmux_obj->internal_mux.info_field = NULL;
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;
1080 /* Free CMUX Object */
1087 static void _cmux_on_confirmation_message_send(TcorePending *plugin,
1088 gboolean result, void *user_data)
1090 dbg("Message out from queue");
1092 if (result == FALSE) { /* Fail */
1098 void tcore_cmux_rcv_from_hal(TcoreHal *hal, unsigned char *data, size_t length)
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
1108 tcore_cmux_object *cmux_obj;
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;
1121 * Get CMUX Object from Modem Interface Plug-in
1123 cmux_obj = _cmux_get_cmux_object(tcore_hal_ref_plugin(hal));
1124 if (cmux_obj == NULL)
1127 DECODE_STATE_CHANGE:
1128 if (++pos >= length)
1131 switch(decode_state) {
1132 case TCORE_CMUX_DECODE_FLAG_HUNT:
1136 dec_data = cmux_obj->cmux_buffer;
1139 case TCORE_CMUX_DECODE_ADDR_HUNT:
1142 case TCORE_CMUX_DECODE_CONTROL_HUNT:
1145 case TCORE_CMUX_DECODE_LENGTH1_HUNT:
1148 case TCORE_CMUX_DECODE_LENGTH2_HUNT:
1151 case TCORE_CMUX_DECODE_DATA_HUNT:
1154 case TCORE_CMUX_DECODE_FCS_HUNT:
1160 while (data[pos] != CMUX_FRAME_DELIMITER)
1161 if (++pos >= length)
1164 decode_state = TCORE_CMUX_DECODE_ADDR_HUNT;
1165 goto DECODE_STATE_CHANGE;
1168 while (data[pos] == CMUX_FRAME_DELIMITER)
1169 if (++pos >= length)
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;
1180 dec_fcs = crc_table[dec_fcs^data[pos]];
1181 decode_state = TCORE_CMUX_DECODE_LENGTH1_HUNT;
1182 *dec_data++ = data[pos];
1184 goto DECODE_STATE_CHANGE;
1187 dec_length = data[pos] >> 1;
1188 dec_fcs = crc_table[dec_fcs^data[pos]];
1189 if (data[pos] & 0x1) /* EA */
1191 decode_state = TCORE_CMUX_DECODE_DATA_HUNT;
1193 decode_state = TCORE_CMUX_DECODE_FCS_HUNT;
1195 decode_state = TCORE_CMUX_DECODE_LENGTH2_HUNT;
1197 *dec_data++ = data[pos];
1199 goto DECODE_STATE_CHANGE;
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];
1207 goto DECODE_STATE_CHANGE;
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;
1218 memcpy(dec_data, data + pos, cp_len);
1220 pos += (cp_len - 1);
1221 dec_length -= cp_len;
1222 full_frame_len += cp_len;
1224 goto DECODE_STATE_CHANGE;
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);
1232 /* enter flag hunt mode */
1233 decode_state = TCORE_CMUX_DECODE_FLAG_HUNT;
1234 goto DECODE_STATE_CHANGE;
1237 /* CMUX initialization */
1238 TReturn tcore_cmux_init(TcoreHal *phy_hal, unsigned int frame_size,
1239 TcorePendingResponseCallback resp_cb, void *resp_cb_data)
1241 TcorePending *pending = NULL;
1242 TcoreATRequest *req = NULL;
1243 TReturn ret = TCORE_RETURN_FAILURE;
1247 if ((phy_hal == NULL) || (resp_cb == NULL))
1248 return TCORE_RETURN_EINVAL;
1250 if (frame_size > 32768)
1251 return TCORE_RETURN_EINVAL;
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
1258 * request is sent for 'default' frame size
1259 * (default Value: 31 (64 if Advanced option is used)).
1262 cmd_str = g_strdup_printf("AT+CMUX=0,0,%d,1509,10,3,30,,", frame_size);
1264 cmd_str = g_strdup_printf("AT+CMUX=0,0,,1509,10,3,30,,");
1266 if (cmd_str == NULL)
1267 return TCORE_RETURN_ENOMEM;
1269 /* Create Pending Request */
1270 pending = tcore_pending_new(NULL, 0);
1271 if (pending == NULL) {
1272 dbg("Pending is NULL");
1278 /* Create AT-Command Request */
1279 req = tcore_at_request_new(cmd_str, "+CMUX:", TCORE_AT_NO_RESULT);
1281 /* Free command string */
1285 dbg("Request is NULL");
1286 tcore_pending_free(pending);
1289 dbg("AT Command: [%s], Prefix(if any): [%s], AT-Command length: [%d]", req->cmd, req->prefix, strlen(req->cmd));
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);
1295 ret = tcore_hal_send_request(phy_hal, pending);
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)
1307 tcore_cmux_object *cmux_obj;
1308 unsigned char *data;
1312 TReturn ret = TCORE_RETURN_FAILURE;
1314 dbg("Internal CMUX setup request");
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;
1326 dbg("Physical HAL: [0x%x] cmux_buf_size: [%d]",
1327 (unsigned int)phy_hal, cmux_buf_size);
1331 * (+ 1) is for CMUX Control Channel
1333 if ((max_channels +1) >= CMUX_CHANNEL_MAX) {
1334 err("Number of Channels requested is greater than supported");
1335 return TCORE_RETURN_EINVAL;
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;
1345 /* Maximum Buffer size for CMUX frame processing */
1346 cmux_obj->max_cmux_buf_size = cmux_buf_size;
1348 /* Maximum Channels requested */
1349 cmux_obj->max_cmux_channels = max_channels + 1;
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");
1356 ret = TCORE_RETURN_ENOMEM;
1361 cmux_obj->cmux_mode = mode;
1362 dbg("Mode: \'%s\'", (mode == CMUX_MODE_BASIC ? "Basic" : "Advanced"));
1364 /* Save Physical HAL */
1365 cmux_obj->phy_hal = phy_hal;
1367 /* Save Modem Interface Plug-in */
1368 cmux_obj->plugin = tcore_hal_ref_plugin(phy_hal);
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;
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;
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.
1382 tcore_hal_set_mode(phy_hal, TCORE_HAL_MODE_TRANSPARENT);
1383 dbg("Physical HAL mode changed to Transparent");
1385 /* Adding CMUX object to Global List */
1386 g_cmux_obj = g_slist_insert(g_cmux_obj, cmux_obj, 0);
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);
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");
1402 dbg("data_len: [%d] data: [%s]", data_len, data);
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);
1410 dbg("CMUX Control Request sent to CP");
1417 /* Free the allocated CMUX memory */
1418 _cmux_free(cmux_obj);
1425 void tcore_cmux_close(TcoreHal *phy_hal,
1426 cmux_channel_close_cb_func channel_close_cb, gpointer channel_close_user_data)
1428 tcore_cmux_object *cmux_obj;
1433 * Get CMUX Object from Modem Interface Plug-in
1435 cmux_obj = _cmux_get_cmux_object(tcore_hal_ref_plugin(phy_hal));
1436 if (cmux_obj == NULL)
1440 dbg("Closing Internal CMUX");
1442 /* Close all Channels */
1443 for (channel_id = 0;
1444 channel_id < cmux_obj->max_cmux_channels;
1446 dbg("Closing Channel - ID: [%d]", channel_id);
1448 /* Close Channel - Send DSC command */
1449 _cmux_close_channel(cmux_obj, channel_id);
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);
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;
1461 /* Freeing CMUX frame processing buffer */
1462 g_free(cmux_obj->cmux_buffer);
1463 cmux_obj->cmux_buffer = NULL;
1465 /* Change the mode of PHYSICAL HAL from Transparent to AT */
1466 tcore_hal_set_mode(cmux_obj->phy_hal, TCORE_HAL_MODE_AT);
1468 /* Remove from list */
1469 g_cmux_obj = g_slist_remove(g_cmux_obj, cmux_obj);
1471 /* Free all the allocated memory */
1472 _cmux_free(cmux_obj);