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);
609 dbg("return %d", ret);
611 /* Flush the Channel data */
612 _cmux_flush_channel_data(cmux_obj);
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.
619 if (channel_id == CMUX_CHANNEL_0) {
620 cmux_obj->cmux_state = CMUX_CLOSED;
623 /* TODO - Need to notify regarding CMUX closure */
624 tcore_cmux_close(cmux_obj->phy_hal, NULL, NULL);
628 case CMUX_COMMAND_SABM:
629 dbg("Received SABM Frame");
630 if (channel->poll_final_bit == 0) {
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.
637 /* Flush the Channel data */
638 _cmux_flush_channel_data(cmux_obj);
641 send_data = _cmux_encode_cmux_frame(cmux_obj, NULL,
642 0, channel_id, CMUX_COMMAND_UA,
643 0x01, 0x01, 0x01, &len);
646 ret = _cmux_send_data(cmux_obj->phy_hal, len, send_data);
648 err("Failed to encode");
650 if (channel->channel_state != CMUX_CHANNEL_ESTABLISHED)
651 /* Channel State set to Established */
652 channel->channel_state = CMUX_CHANNEL_ESTABLISHED;
656 warn("invalid frame_type");
663 static void _cmux_flush_channel_data(tcore_cmux_object *cmux_obj)
667 if (cmux_obj == NULL)
670 cmux_obj->internal_mux.info_field_len = 0x0;
671 memset(cmux_obj->internal_mux.info_field, 0x0, cmux_obj->max_cmux_buf_size);
676 static void _cmux_process_rcv_frame(tcore_cmux_object *cmux_obj, int length)
678 unsigned char *frame_process_ptr = cmux_obj->cmux_buffer;
679 unsigned char *buf_start_ptr = cmux_obj->cmux_buffer;
681 tcore_cmux_channel *ch;
682 unsigned char channel_id;
686 /* Flush channel data */
687 _cmux_flush_channel_data(cmux_obj);
689 /* Get the Channel ID: 1st byte will be flag (F9). Flag checking is already done */
690 channel_id = (*++frame_process_ptr >> 2) & 0x3F;
692 if (channel_id < cmux_obj->max_cmux_channels) {
693 ch = cmux_obj->internal_mux.channel_info[channel_id];
695 ch->channel_id = channel_id;
698 ch->ext_bit = *frame_process_ptr & 0x01;
701 ch->cr_bit = (*frame_process_ptr++ >> 1) & 0x01;
703 /* get the Frame Type */
704 ch->frame_type = *frame_process_ptr++;
706 /* get the poll/Final bit */
707 ch->poll_final_bit = (ch->frame_type & 0x10) >> 4;
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;
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));
721 dbg("info_field_len: [%d]", cmux_obj->internal_mux.info_field_len);
723 /* Copy received information field */
724 memcpy(cmux_obj->internal_mux.info_field, frame_process_ptr,
725 cmux_obj->internal_mux.info_field_len);
727 frame_process_ptr = frame_process_ptr + cmux_obj->internal_mux.info_field_len;
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);
734 err("CRC check of the header FAILED.. Drop the packet !!");
736 err("Incorrect channel... Drop the packet !!");
741 static TReturn _cmux_send_data(TcoreHal *hal, int data_len, unsigned char *data)
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");
751 dbg("Successfully sent CMUX data");
757 static gboolean _cmux_recv_cmux_data(tcore_cmux_object *cmux_obj,
758 tcore_cmux_channel *channel)
763 /* Dereferencing HAL from Channel Pointer */
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) {
783 static TReturn _cmux_hal_power(TcoreHal *hal, gboolean flag)
787 if (flag == TRUE) { /* Powering ON */
789 return tcore_hal_set_power_state(hal, TRUE);
790 } else { /* Powering OFF */
792 return tcore_hal_set_power_state(hal, FALSE);
796 static TReturn _cmux_hal_send(TcoreHal *hal, unsigned int data_len, void *data)
798 tcore_cmux_object *cmux_obj;
800 unsigned char *send_data;
805 TReturn ret = TCORE_RETURN_FAILURE;
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;
815 * Get CMUX Object from Modem Interface Plug-in
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;
823 channel_id = cmux_obj->max_cmux_channels + 1;
825 channel_name = tcore_hal_get_name(hal);
826 dbg("HAL name: [%s]", channel_name);
828 if (channel_name != NULL) {
832 * Channel 0 is dedicated to CMUX Control Channel,
833 * hence starting from 1.
835 for (i = 1 ; cmux_obj->max_cmux_channels > i ; i++) {
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);
844 * Comparing all Logical HAL names with required HAL name.
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);
861 g_free(channel_name);
863 err("No name defined for HAL");
867 if (channel_id > cmux_obj->max_cmux_channels) {
868 err("Failed to find Channel ID");
872 /* Muxing operation and Frame creation */
874 send_data = _cmux_encode_cmux_frame(cmux_obj, data, data_len, channel_id,
875 CMUX_COMMAND_UIH, 0x1, 0x1, 0x0, &len);
877 err("Failed to encode");
878 return TCORE_RETURN_FAILURE;
882 ret = _cmux_send_data(cmux_obj->phy_hal, len, send_data);
888 static TReturn _cmux_hal_setup_netif(CoreObject *co,
889 TcoreHalSetupNetifCallback func, void *user_data,
890 unsigned int cid, gboolean enable)
892 tcore_cmux_object *cmux_obj;
896 /* Get secondary HAL from Core Object */
897 hal = tcore_object_get_hal(co);
900 * Get CMUX Object from Modem Interface Plug-in
902 cmux_obj = _cmux_get_cmux_object(tcore_hal_ref_plugin(hal));
903 if (cmux_obj == NULL)
904 return TCORE_RETURN_FAILURE;
906 return tcore_hal_setup_netif(cmux_obj->phy_hal,
907 co, func, user_data, cid, enable);
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,
917 static TcoreHal *_cmux_create_logical_hal(tcore_cmux_object *cmux_obj,
918 tcore_cmux_channel *channel)
921 char channel_id_name[CMUX_MAX_CHANNEL_NAME];
924 if ((cmux_obj == NULL) || (channel == NULL)) {
925 err("Invalid input parameters");
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);
933 /* Creating Logical HAL */
934 hal = tcore_hal_new(cmux_obj->plugin,
935 channel_id_name, &cmux_hops, TCORE_HAL_MODE_AT);
938 err("Failed to allocate memory");
942 /* Updating Logical HAL of CMUX Channel */
949 tcore_cmux_object *_cmux_new(int max_channels, unsigned int buffer_size)
951 tcore_cmux_object *cmux_obj;
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");
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");
970 /* CMUX State initialize to CMUX_NOT_INITIALIZED */
971 cmux_obj->cmux_state = CMUX_NOT_INITIALIZED;
974 * Allocating memory for channel_info
975 * max_channels defines the maximum channels user requested,
976 * hence + 1 is required for CMUX Control Channel
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);
992 /* Free allocated memory */
993 if (cmux_obj != NULL) {
994 /* Free info_field */
995 g_free(cmux_obj->internal_mux.info_field);
997 for (i = 0; i < (max_channels + 1) ; i++)
998 /* Free channel_info */
999 g_free(cmux_obj->internal_mux.channel_info[i]);
1001 /* Free CMUX object memory */
1009 static void _cmux_channel_init(tcore_cmux_object *cmux_obj, int channel_id)
1011 tcore_cmux_channel *ch;
1014 ch = cmux_obj->internal_mux.channel_info[channel_id];
1018 ch->channel_id = channel_id;
1019 ch->channel_state = CMUX_CHANNEL_SABM_SEND_WAITING_FOR_UA;
1023 /* TODO - Check if required */
1024 ch->frame_type = CMUX_COMMAND_SABM;
1027 ch->poll_final_bit = 0x01;
1029 dbg("Channel ID [%d] - Initialized", channel_id);
1032 static void _cmux_close_channel(tcore_cmux_object *cmux_obj, int channel_id)
1034 tcore_cmux_channel *ch;
1035 unsigned char *send_data;
1039 ch = cmux_obj->internal_mux.channel_info[channel_id];
1043 if (ch->channel_state != CMUX_CHANNEL_CLOSED) {
1044 ch->frame_type = CMUX_COMMAND_DISC;
1047 ch->channel_state = CMUX_CHANNEL_DISC_SEND_WAITING_FOR_UA;
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);
1054 /* Send CMUX data */
1055 ret = _cmux_send_data(cmux_obj->phy_hal, len, send_data);
1056 dbg("return %d", ret);
1059 err("Failed to encode");
1062 /* Channel is already closed */
1063 err("Channel is already closed");
1068 static void _cmux_free(tcore_cmux_object *cmux_obj)
1074 * This function is used internally only, hence sanity check for 'cmux_obj'
1077 /* Free Information Field */
1078 g_free(cmux_obj->internal_mux.info_field);
1079 cmux_obj->internal_mux.info_field = NULL;
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;
1087 /* Free CMUX Object */
1094 static void _cmux_on_confirmation_message_send(TcorePending *plugin,
1095 gboolean result, void *user_data)
1097 dbg("Message out from queue");
1099 if (result == FALSE) { /* Fail */
1105 void tcore_cmux_rcv_from_hal(TcoreHal *hal, unsigned char *data, size_t length)
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
1115 tcore_cmux_object *cmux_obj;
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;
1128 * Get CMUX Object from Modem Interface Plug-in
1130 cmux_obj = _cmux_get_cmux_object(tcore_hal_ref_plugin(hal));
1131 if (cmux_obj == NULL)
1134 DECODE_STATE_CHANGE:
1135 if (++pos >= length)
1138 switch(decode_state) {
1139 case TCORE_CMUX_DECODE_FLAG_HUNT:
1143 dec_data = cmux_obj->cmux_buffer;
1146 case TCORE_CMUX_DECODE_ADDR_HUNT:
1149 case TCORE_CMUX_DECODE_CONTROL_HUNT:
1152 case TCORE_CMUX_DECODE_LENGTH1_HUNT:
1155 case TCORE_CMUX_DECODE_LENGTH2_HUNT:
1158 case TCORE_CMUX_DECODE_DATA_HUNT:
1161 case TCORE_CMUX_DECODE_FCS_HUNT:
1165 warn("invalid decode_state");
1170 while (data[pos] != CMUX_FRAME_DELIMITER)
1171 if (++pos >= length)
1174 decode_state = TCORE_CMUX_DECODE_ADDR_HUNT;
1175 goto DECODE_STATE_CHANGE;
1178 while (data[pos] == CMUX_FRAME_DELIMITER)
1179 if (++pos >= length)
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;
1190 dec_fcs = crc_table[dec_fcs^data[pos]];
1191 decode_state = TCORE_CMUX_DECODE_LENGTH1_HUNT;
1192 *dec_data++ = data[pos];
1194 goto DECODE_STATE_CHANGE;
1197 dec_length = data[pos] >> 1;
1198 dec_fcs = crc_table[dec_fcs^data[pos]];
1199 if (data[pos] & 0x1) /* EA */
1201 decode_state = TCORE_CMUX_DECODE_DATA_HUNT;
1203 decode_state = TCORE_CMUX_DECODE_FCS_HUNT;
1205 decode_state = TCORE_CMUX_DECODE_LENGTH2_HUNT;
1207 *dec_data++ = data[pos];
1209 goto DECODE_STATE_CHANGE;
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];
1217 goto DECODE_STATE_CHANGE;
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;
1228 memcpy(dec_data, data + pos, cp_len);
1230 pos += (cp_len - 1);
1231 dec_length -= cp_len;
1232 full_frame_len += cp_len;
1234 goto DECODE_STATE_CHANGE;
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);
1242 /* enter flag hunt mode */
1243 decode_state = TCORE_CMUX_DECODE_FLAG_HUNT;
1244 goto DECODE_STATE_CHANGE;
1247 /* CMUX initialization */
1248 TReturn tcore_cmux_init(TcoreHal *phy_hal, unsigned int frame_size,
1249 TcorePendingResponseCallback resp_cb, void *resp_cb_data)
1251 TcorePending *pending = NULL;
1252 TcoreATRequest *req = NULL;
1253 TReturn ret = TCORE_RETURN_FAILURE;
1257 if ((phy_hal == NULL) || (resp_cb == NULL))
1258 return TCORE_RETURN_EINVAL;
1260 if (frame_size > 32768)
1261 return TCORE_RETURN_EINVAL;
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
1268 * request is sent for 'default' frame size
1269 * (default Value: 31 (64 if Advanced option is used)).
1272 cmd_str = g_strdup_printf("AT+CMUX=0,0,%d,1509,10,3,30,,", frame_size);
1274 cmd_str = g_strdup_printf("AT+CMUX=0,0,,1509,10,3,30,,");
1276 if (cmd_str == NULL)
1277 return TCORE_RETURN_ENOMEM;
1279 /* Create Pending Request */
1280 pending = tcore_pending_new(NULL, 0);
1281 if (pending == NULL) {
1282 dbg("Pending is NULL");
1288 /* Create AT-Command Request */
1289 req = tcore_at_request_new(cmd_str, "+CMUX:", TCORE_AT_NO_RESULT);
1291 /* Free command string */
1295 dbg("Request is NULL");
1296 tcore_pending_free(pending);
1299 dbg("AT Command: [%s], Prefix(if any): [%s], AT-Command length: [%d]", req->cmd, req->prefix, strlen(req->cmd));
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);
1305 ret = tcore_hal_send_request(phy_hal, pending);
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)
1317 tcore_cmux_object *cmux_obj;
1318 unsigned char *data;
1322 TReturn ret = TCORE_RETURN_FAILURE;
1324 dbg("Internal CMUX setup request");
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;
1336 dbg("Physical HAL: [0x%x] cmux_buf_size: [%d]",
1337 (unsigned int)phy_hal, cmux_buf_size);
1341 * (+ 1) is for CMUX Control Channel
1343 if ((max_channels +1) >= CMUX_CHANNEL_MAX) {
1344 err("Number of Channels requested is greater than supported");
1345 return TCORE_RETURN_EINVAL;
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;
1355 /* Maximum Buffer size for CMUX frame processing */
1356 cmux_obj->max_cmux_buf_size = cmux_buf_size;
1358 /* Maximum Channels requested */
1359 cmux_obj->max_cmux_channels = max_channels + 1;
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");
1366 ret = TCORE_RETURN_ENOMEM;
1371 cmux_obj->cmux_mode = mode;
1372 dbg("Mode: \'%s\'", (mode == CMUX_MODE_BASIC ? "Basic" : "Advanced"));
1374 /* Save Physical HAL */
1375 cmux_obj->phy_hal = phy_hal;
1377 /* Save Modem Interface Plug-in */
1378 cmux_obj->plugin = tcore_hal_ref_plugin(phy_hal);
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;
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;
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.
1392 tcore_hal_set_mode(phy_hal, TCORE_HAL_MODE_TRANSPARENT);
1393 dbg("Physical HAL mode changed to Transparent");
1395 /* Adding CMUX object to Global List */
1396 g_cmux_obj = g_slist_insert(g_cmux_obj, cmux_obj, 0);
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);
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");
1412 dbg("data_len: [%d] data: [%s]", data_len, data);
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);
1420 dbg("CMUX Control Request sent to CP");
1427 /* Free the allocated CMUX memory */
1428 _cmux_free(cmux_obj);
1435 void tcore_cmux_close(TcoreHal *phy_hal,
1436 cmux_channel_close_cb_func channel_close_cb, gpointer channel_close_user_data)
1438 tcore_cmux_object *cmux_obj;
1443 * Get CMUX Object from Modem Interface Plug-in
1445 cmux_obj = _cmux_get_cmux_object(tcore_hal_ref_plugin(phy_hal));
1446 if (cmux_obj == NULL)
1450 dbg("Closing Internal CMUX");
1452 /* Close all Channels */
1453 for (channel_id = 0;
1454 channel_id < cmux_obj->max_cmux_channels;
1456 dbg("Closing Channel - ID: [%d]", channel_id);
1458 /* Close Channel - Send DSC command */
1459 _cmux_close_channel(cmux_obj, channel_id);
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);
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;
1471 /* Freeing CMUX frame processing buffer */
1472 g_free(cmux_obj->cmux_buffer);
1473 cmux_obj->cmux_buffer = NULL;
1475 /* Change the mode of PHYSICAL HAL from Transparent to AT */
1476 tcore_hal_set_mode(cmux_obj->phy_hal, TCORE_HAL_MODE_AT);
1478 /* Remove from list */
1479 g_cmux_obj = g_slist_remove(g_cmux_obj, cmux_obj);
1481 /* Free all the allocated memory */
1482 _cmux_free(cmux_obj);