2 * GSM 07.10 Implementation with User Space Serial Ports
4 * Code heavily based on gsmMuxd written by
5 * Copyright (C) 2003 Tuukka Karvonen <tkarvone@iki.fi>
6 * Modified November 2004 by David Jander <david@protonic.nl>
7 * Modified January 2006 by Tuukka Karvonen <tkarvone@iki.fi>
8 * Modified January 2006 by Antti Haapakoski <antti.haapakoski@iki.fi>
9 * Modified March 2006 by Tuukka Karvonen <tkarvone@iki.fi>
10 * Modified October 2006 by Vasiliy Novikov <vn@hotbox.ru>
12 * Copyright (C) 2008 M. Dietrich <mdt@emdete.de>
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
39 #include <sys/ioctl.h>
40 #include <sys/socket.h>
43 #include <sys/types.h>
49 #include <glib.h> // http://library.gnome.org/devel/glib/unstable/glib-core.html
50 #include <dbus/dbus.h> // http://dbus.freedesktop.org/doc/dbus/libdbus-tutorial.html
51 #include <dbus/dbus-glib.h> // http://dbus.freedesktop.org/doc/dbus-glib/
52 DBusConnection* dbus_g_connection_get_connection(DBusGConnection *gconnection); // why isn't this in dbus-glib.h?
53 // http://maemo.org/api_refs/4.0/dbus-glib/group__DBusGLibInternals.html#gfac56b6025a90951510d33423ff04120
54 // http://wiki.bluez.org/wiki/HOWTO/DiscoveringDevices
55 // http://dbus.freedesktop.org/doc/api/html/example-service_8c-source.html
56 // ~/Source/openmoko/build/tmp/work/i686-linux/glib-2.0-native-2.12.4-r1/glib-2.12.4/tests/mainloop-test.c
57 // http://www.linuxquestions.org/questions/linux-software-2/dbus-problem-505442/
59 // dbus-send --system --print-reply --type=method_call --dest=org.pyneo.muxer /org/pyneo/Muxer org.freesmartphone.GSM.MUX.AllocChannel string:xxx
61 ///////////////////////////////////////////////////////////////// defines
62 #define LOG(lvl, f, ...) do{if(lvl<=syslog_level)syslog(lvl,"%s:%d:%s(): " f "\n", __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__);}while(0)
63 #define SYSCHECK(c) do{if((c)<0){\
64 LOG(LOG_ERR, "system-error: '%s' (code: %d)", strerror(errno), errno);\
67 #define GSM0710_FRAME_FLAG 0xF9// basic mode flag for frame start and end
68 #define GSM0710_FRAME_ADV_FLAG 0x7E// advanced mode flag for frame start and end
69 #define GSM0710_FRAME_ADV_ESC 0x7D// advanced mode escape symbol
70 #define GSM0710_FRAME_ADV_ESC_COPML 0x20// advanced mode escape complement mask
71 #define GSM0710_FRAME_ADV_ESCAPED_SYMS { GSM0710_FRAME_ADV_FLAG, GSM0710_FRAME_ADV_ESC, 0x11, 0x91, 0x13, 0x93 }// advanced mode escaped symbols: Flag, Escape, XON and XOFF
72 // bits: Poll/final, Command/Response, Extension
73 #define GSM0710_PF 0x10//16
74 #define GSM0710_CR 0x02//2
75 #define GSM0710_EA 0x01//1
77 #define GSM0710_TYPE_SABM 0x2F//47 Set Asynchronous Balanced Mode
78 #define GSM0710_TYPE_UA 0x63//99 Unnumbered Acknowledgement
79 #define GSM0710_TYPE_DM 0x0F//15 Disconnected Mode
80 #define GSM0710_TYPE_DISC 0x43//67 Disconnect
81 #define GSM0710_TYPE_UIH 0xEF//239 Unnumbered information with header check
82 #define GSM0710_TYPE_UI 0x03//3 Unnumbered Acknowledgement
83 // control channel commands
84 #define GSM0710_CONTROL_PN (0x80|GSM0710_EA)//?? DLC parameter negotiation
85 #define GSM0710_CONTROL_CLD (0xC0|GSM0710_EA)//193 Multiplexer close down
86 #define GSM0710_CONTROL_PSC (0x40|GSM0710_EA)//??? Power Saving Control
87 #define GSM0710_CONTROL_TEST (0x20|GSM0710_EA)//33 Test Command
88 #define GSM0710_CONTROL_MSC (0xE0|GSM0710_EA)//225 Modem Status Command
89 #define GSM0710_CONTROL_NSC (0x10|GSM0710_EA)//17 Non Supported Command Response
90 #define GSM0710_CONTROL_RPN (0x90|GSM0710_EA)//?? Remote Port Negotiation Command
91 #define GSM0710_CONTROL_RLS (0x50|GSM0710_EA)//?? Remote Line Status Command
92 #define GSM0710_CONTROL_SNC (0xD0|GSM0710_EA)//?? Service Negotiation Command
93 // V.24 signals: flow control, ready to communicate, ring indicator,
94 // data valid three last ones are not supported by Siemens TC_3x
95 #define GSM0710_SIGNAL_FC 0x02
96 #define GSM0710_SIGNAL_RTC 0x04
97 #define GSM0710_SIGNAL_RTR 0x08
98 #define GSM0710_SIGNAL_IC 0x40//64
99 #define GSM0710_SIGNAL_DV 0x80//128
100 #define GSM0710_SIGNAL_DTR 0x04
101 #define GSM0710_SIGNAL_DSR 0x04
102 #define GSM0710_SIGNAL_RTS 0x08
103 #define GSM0710_SIGNAL_CTS 0x08
104 #define GSM0710_SIGNAL_DCD 0x80//128
106 #define GSM0710_COMMAND_IS(type, command) ((type & ~GSM0710_CR) == command)
107 #define GSM0710_FRAME_IS(type, frame) ((frame->control & ~GSM0710_PF) == type)
109 #define min(a,b) ((a < b) ? a :b)
111 #define GSM0710_WRITE_RETRIES 5
112 #define GSM0710_MAX_CHANNELS 32
113 // Defines how often the modem is polled when automatic restarting is
114 // enabled The value is in seconds
115 #define GSM0710_POLLING_INTERVAL 5
116 #define GSM0710_BUFFER_SIZE 2048
117 #define PTY_GLIB_BUFFER_SIZE (16*1024)
119 ////////////////////////////////////////////////////// types
121 typedef struct GSM0710_Frame
123 unsigned char channel;
124 unsigned char control;
130 typedef struct GSM0710_Buffer
132 unsigned char data[GSM0710_BUFFER_SIZE];
133 unsigned char *readp;
134 unsigned char *writep;
136 int flag_found;// set if last character read was flag
137 unsigned long received_count;
138 unsigned long dropped_count;
139 unsigned char adv_data[GSM0710_BUFFER_SIZE];
145 typedef struct Channel
147 int id; // gsm 07 10 channel id
152 unsigned char v24_signals;
158 GIOChannel* g_channel;
161 typedef enum MuxerStates
164 MUX_STATE_INITILIZING,
168 MUX_STATES_COUNT // keep this the last
171 typedef struct Serial
177 GSM0710_Buffer *in_buf;// input buffer
178 unsigned char *adv_frame_buf;
179 time_t frame_receive_time;
182 guint g_source_watchdog;
185 /////////////////////////////////////////// function prototypes
187 * increases buffer pointer by one and wraps around if necessary
189 //void gsm0710_buffer_inc(GSM0710_Buffer *buf, void&* p);
190 #define gsm0710_buffer_inc(buf,p) do { p++; if (p == buf->endp) p = buf->data; } while (0)
192 * Tells how many chars are saved into the buffer.
194 //int gsm0710_buffer_length(GSM0710_Buffer *buf);
195 #define gsm0710_buffer_length(buf) ((buf->readp > buf->writep) ? (GSM0710_BUFFER_SIZE - (buf->readp - buf->writep)) : (buf->writep-buf->readp))
197 * tells how much free space there is in the buffer
199 //int gsm0710_buffer_free(GSM0710_Buffer *buf);
200 #define gsm0710_buffer_free(buf) ((buf->readp > buf->writep) ? (buf->readp - buf->writep) : (GSM0710_BUFFER_SIZE - (buf->writep-buf->readp)) - 1)
202 ////////////////////////////////// constants & globals
203 static unsigned char close_channel_cmd[] = { GSM0710_CONTROL_CLD | GSM0710_CR, GSM0710_EA | (0 << 1) };
204 static unsigned char test_channel_cmd[] = { GSM0710_CONTROL_TEST | GSM0710_CR, GSM0710_EA | (6 << 1), 'P', 'I', 'N', 'G', '\r', '\n', };
205 //static unsigned char psc_channel_cmd[] = { GSM0710_CONTROL_PSC | GSM0710_CR, GSM0710_EA | (0 << 1), };
206 static unsigned char wakeup_sequence[] = { GSM0710_FRAME_FLAG, GSM0710_FRAME_FLAG, };
207 // crc table from gsm0710 spec
208 static const unsigned char r_crctable[] = {//reversed, 8-bit, poly=0x07
209 0x00, 0x91, 0xE3, 0x72, 0x07, 0x96, 0xE4, 0x75, 0x0E, 0x9F, 0xED,
210 0x7C, 0x09, 0x98, 0xEA, 0x7B, 0x1C, 0x8D, 0xFF, 0x6E, 0x1B, 0x8A,
211 0xF8, 0x69, 0x12, 0x83, 0xF1, 0x60, 0x15, 0x84, 0xF6, 0x67, 0x38,
212 0xA9, 0xDB, 0x4A, 0x3F, 0xAE, 0xDC, 0x4D, 0x36, 0xA7, 0xD5, 0x44,
213 0x31, 0xA0, 0xD2, 0x43, 0x24, 0xB5, 0xC7, 0x56, 0x23, 0xB2, 0xC0,
214 0x51, 0x2A, 0xBB, 0xC9, 0x58, 0x2D, 0xBC, 0xCE, 0x5F, 0x70, 0xE1,
215 0x93, 0x02, 0x77, 0xE6, 0x94, 0x05, 0x7E, 0xEF, 0x9D, 0x0C, 0x79,
216 0xE8, 0x9A, 0x0B, 0x6C, 0xFD, 0x8F, 0x1E, 0x6B, 0xFA, 0x88, 0x19,
217 0x62, 0xF3, 0x81, 0x10, 0x65, 0xF4, 0x86, 0x17, 0x48, 0xD9, 0xAB,
218 0x3A, 0x4F, 0xDE, 0xAC, 0x3D, 0x46, 0xD7, 0xA5, 0x34, 0x41, 0xD0,
219 0xA2, 0x33, 0x54, 0xC5, 0xB7, 0x26, 0x53, 0xC2, 0xB0, 0x21, 0x5A,
220 0xCB, 0xB9, 0x28, 0x5D, 0xCC, 0xBE, 0x2F, 0xE0, 0x71, 0x03, 0x92,
221 0xE7, 0x76, 0x04, 0x95, 0xEE, 0x7F, 0x0D, 0x9C, 0xE9, 0x78, 0x0A,
222 0x9B, 0xFC, 0x6D, 0x1F, 0x8E, 0xFB, 0x6A, 0x18, 0x89, 0xF2, 0x63,
223 0x11, 0x80, 0xF5, 0x64, 0x16, 0x87, 0xD8, 0x49, 0x3B, 0xAA, 0xDF,
224 0x4E, 0x3C, 0xAD, 0xD6, 0x47, 0x35, 0xA4, 0xD1, 0x40, 0x32, 0xA3,
225 0xC4, 0x55, 0x27, 0xB6, 0xC3, 0x52, 0x20, 0xB1, 0xCA, 0x5B, 0x29,
226 0xB8, 0xCD, 0x5C, 0x2E, 0xBF, 0x90, 0x01, 0x73, 0xE2, 0x97, 0x06,
227 0x74, 0xE5, 0x9E, 0x0F, 0x7D, 0xEC, 0x99, 0x08, 0x7A, 0xEB, 0x8C,
228 0x1D, 0x6F, 0xFE, 0x8B, 0x1A, 0x68, 0xF9, 0x82, 0x13, 0x61, 0xF0,
229 0x85, 0x14, 0x66, 0xF7, 0xA8, 0x39, 0x4B, 0xDA, 0xAF, 0x3E, 0x4C,
230 0xDD, 0xA6, 0x37, 0x45, 0xD4, 0xA1, 0x30, 0x42, 0xD3, 0xB4, 0x25,
231 0x57, 0xC6, 0xB3, 0x22, 0x50, 0xC1, 0xBA, 0x2B, 0x59, 0xC8, 0xBD,
234 static char* version = "0.9.2.1";
235 static char* revision = "$Rev: 295 $";
236 static int no_daemon = 1;
237 static int pin_code = -1;
238 static int use_ping = 0;
239 static int use_timeout = 0;
240 static int syslog_level = LOG_INFO;
241 static char* object_name = "/org/pyneo/Muxer";
243 static Serial serial;
245 static Channel channellist[GSM0710_MAX_CHANNELS]; // remember: [0] is not used acticly because it's the control channel
247 static GMainLoop* main_loop = NULL;
248 static DBusGConnection* g_conn = NULL;
249 // +CMUX=<mode>[,<subset>[,<port_speed>[,<N1>[,<T1>[,<N2>[,<T2>[,<T3>[,<k>]]]]]]]]
250 static int cmux_mode = 1;
251 static int cmux_subset = 0;
252 static int cmux_port_speed = 5;
253 // Maximum Frame Size (N1): 64/31
254 static int cmux_N1 = 64;
256 // Acknowledgement Timer (T1) sec/100: 10
257 static int cmux_T1 = 10;
258 // Maximum number of retransmissions (N2): 3
259 static int cmux_N2 = 3;
260 // Response Timer for multiplexer control channel (T2) sec/100: 30
261 static int cmux_T2 = 30;
262 // Response Timer for wake-up procedure(T3) sec: 10
263 static int cmux_T3 = 10;
264 // Window Size (k): 2
265 static int cmux_k = 2;
267 // TODO: set automatically from at+cmux=?
268 // neo: +CMUX: (1),(0),(1-5),(10-100),(1-255),(0-100),(2-255),(1-255),(1-7)
271 * The following arrays must have equal length and the values must
272 * correspond. also it has to correspond to the gsm0710 spec regarding
273 * baud id of CMUX the command.
275 static int baud_rates[] = {
276 0, 9600, 19200, 38400, 57600, 115200, 230400, 460800
278 static speed_t baud_bits[] = {
279 0, B9600, B19200, B38400, B57600, B115200, B230400, B460800
283 * Determine baud-rate index for CMUX command
285 static int baud_rate_index(
289 for (i = 0; i < sizeof(baud_rates) / sizeof(*baud_rates); ++i)
290 if (baud_rates[i] == baud_rate)
295 gboolean glib_returnfalse(
302 * Calculates frame check sequence from given characters.
305 * input - character array
306 * length - number of characters in array (that are included)
308 * frame check sequence
310 static unsigned char frame_calc_crc(
311 const unsigned char *input,
314 unsigned char fcs = 0xFF;
316 for (i = 0; i < length; i++)
317 fcs = r_crctable[fcs ^ input[i]];
322 * Escapes GSM0710_FRAME_ADV_ESCAPED_SYMS characters.
323 * returns escaped buffer length.
325 static int fill_adv_frame_buf(
326 unsigned char *adv_buf,
327 const unsigned char *data,
330 static const unsigned char esc[] = GSM0710_FRAME_ADV_ESCAPED_SYMS;
331 int i, esc_i, adv_i = 0;
332 for (i = 0; i < length; ++i, ++adv_i)
334 adv_buf[adv_i] = data[i];
335 for (esc_i = 0; esc_i < sizeof(esc) / sizeof(esc[0]); ++esc_i)
336 if (data[i] == esc[esc_i])
338 adv_buf[adv_i] = GSM0710_FRAME_ADV_ESC;
340 adv_buf[adv_i] = data[i] ^ GSM0710_FRAME_ADV_ESC_COPML;
348 * ascii/hexdump a byte buffer
350 static int syslogdump(
352 const unsigned char *ptr,
355 if (LOG_DEBUG>syslog_level)
358 unsigned int offset = 0l;
360 while (offset < length)
363 strcpy(buffer, prefix);
364 off = strlen(buffer);
365 SYSCHECK(snprintf(buffer + off, sizeof(buffer) - off, "%08x: ", offset));
366 off = strlen(buffer);
367 for (i = 0; i < 16; i++)
369 if (offset + i < length)
370 SYSCHECK(snprintf(buffer + off, sizeof(buffer) - off, "%02x%c", ptr[offset + i], i == 7 ? '-' : ' '));
372 SYSCHECK(snprintf(buffer + off, sizeof(buffer) - off, " .%c", i == 7 ? '-' : ' '));
373 off = strlen(buffer);
375 SYSCHECK(snprintf(buffer + off, sizeof(buffer) - off, " "));
376 off = strlen(buffer);
377 for (i = 0; i < 16; i++)
378 if (offset + i < length)
380 SYSCHECK(snprintf(buffer + off, sizeof(buffer) - off, "%c", (ptr[offset + i] < ' ') ? '.' : ptr[offset + i]));
381 off = strlen(buffer);
384 LOG(LOG_DEBUG, "%s", buffer);
390 * Writes a frame to a logical channel. C/R bit is set to 1.
391 * Doesn't support FCS counting for GSM0710_TYPE_UI frames.
394 * channel - channel number (0 = control)
395 * input - the data to be written
396 * length - the length of the data
397 * type - the type of the frame (with possible P/F-bit)
400 * number of characters written
402 static int write_frame(
404 const unsigned char *input,
408 LOG(LOG_DEBUG, "Enter");
409 //flag, GSM0710_EA=1 C channel, frame type, length 1-2
410 unsigned char prefix[5] = { GSM0710_FRAME_FLAG, GSM0710_EA | GSM0710_CR, 0, 0, 0 };
411 unsigned char postfix[2] = { 0xFF, GSM0710_FRAME_FLAG };
412 int prefix_length = 4;
418 syslogdump(">s ", (unsigned char *)wakeup_sequence, sizeof(wakeup_sequence));
419 write(serial.fd, wakeup_sequence, sizeof(wakeup_sequence));
420 // SYSCHECK(tcdrain(serial.fd));
423 // FD_SET(serial.fd, &rfds);
424 // struct timeval timeout;
425 // timeout.tv_sec = 0;
426 // timeout.tv_usec = 1000 / 100 * cmux_T2;
427 // int sel = select(serial.fd + 1, &rfds, NULL, NULL, &timeout);
428 // if (sel > 0 && FD_ISSET(serial.fd, &rfds))
429 // read(serial.fd, &w, 1);
432 // } while (w != wakeup_sequence[0] && count < cmux_N2);
433 // if (w != wakeup_sequence[0])
434 // LOG(LOG_WARNING, "Didn't get frame-flag after wakeup");
435 LOG(LOG_DEBUG, "Sending frame to channel %d", channel);
436 //GSM0710_EA=1, Command, let's add address
437 prefix[1] = prefix[1] | ((63 & (unsigned char) channel) << 2);
438 //let's set control field
440 //let's not use too big frames
441 length = min(cmux_N1, length);
444 //Modified acording PATCH CRC checksum
445 //postfix[0] = frame_calc_crc (prefix + 1, prefix_length - 1);
450 prefix[3] = (0x007F & length) << 1;
451 prefix[4] = (0x7F80 & length) >> 7;
454 prefix[3] = 1 | (length << 1);
455 postfix[0] = frame_calc_crc(prefix + 1, prefix_length - 1);
456 c = write(serial.fd, prefix, prefix_length);
457 if (c != prefix_length)
459 LOG(LOG_WARNING, "Couldn't write the whole prefix to the serial port for the virtual port %d. Wrote only %d bytes",
465 c = write(serial.fd, input, length);
468 LOG(LOG_WARNING, "Couldn't write all data to the serial port from the virtual port %d. Wrote only %d bytes",
473 c = write(serial.fd, postfix, 2);
476 LOG(LOG_WARNING, "Couldn't write the whole postfix to the serial port for the virtual port %d. Wrote only %d bytes",
484 serial.adv_frame_buf[0] = GSM0710_FRAME_ADV_FLAG;
485 offs += fill_adv_frame_buf(serial.adv_frame_buf + offs, prefix + 1, 2);// address, control
486 offs += fill_adv_frame_buf(serial.adv_frame_buf + offs, input, length);// data
488 postfix[0] = frame_calc_crc(prefix + 1, 2);
489 offs += fill_adv_frame_buf(serial.adv_frame_buf + offs, postfix, 1);// fcs
490 serial.adv_frame_buf[offs] = GSM0710_FRAME_ADV_FLAG;
492 syslogdump(">s ", (unsigned char *)serial.adv_frame_buf, offs);
493 c = write(serial.fd, serial.adv_frame_buf, offs);
496 LOG(LOG_WARNING, "Couldn't write the whole advanced option packet to the serial port for the virtual port %d. Wrote only %d bytes",
501 LOG(LOG_DEBUG, "Leave");
506 * Handles received data from device. PARAMS: buf - buffer, which
507 * contains received data len - the length of the buffer channel - the
508 * number of devices (logical channel), where data was received
509 * RETURNS: the number of remaining bytes in partial packet
511 static int handle_channel_data(
519 //try to write 5 times
520 while (written != len && i < GSM0710_WRITE_RETRIES)
522 last = write_frame(channel, buf + written, len - written, GSM0710_TYPE_UIH);
527 if (i == GSM0710_WRITE_RETRIES)
528 LOG(LOG_WARNING, "Couldn't write data to channel %d. Wrote only %d bytes, when should have written %d",
529 channel, written, len);
533 static int logical_channel_close(Channel* channel)
536 GSource *timeout_source;
539 LOG(LOG_DEBUG, "Enter");
542 LOG(LOG_INFO, "Logical channel %d for %s closing", channel->id, channel->origin);
543 for (write_retries=0; write_retries<GSM0710_WRITE_RETRIES; write_retries++)
546 write_frame(channel->id, NULL, 0, GSM0710_TYPE_DISC | GSM0710_PF);
548 write_frame(channel->id, close_channel_cmd, 2, GSM0710_TYPE_UIH);
549 timeout_id = g_timeout_add_seconds(3, glib_returnfalse, NULL);
550 timeout_source = g_main_context_find_source_by_id(NULL, timeout_id);
553 LOG(LOG_DEBUG, "g_main_context_iteration");
554 g_main_context_iteration(NULL, TRUE);
556 while (channel->opened && !g_source_is_destroyed(timeout_source));
557 if (!channel->opened)
560 /* No need to explicitly destroy this source */
562 LOG(LOG_WARNING, "Unable to properly close a channel");
565 if (channel->g_source >= 0)
566 g_source_remove(channel->g_source);
567 channel->g_source = -1;
568 if (channel->fd >= 0)
571 if (channel->ptsname != NULL)
572 free(channel->ptsname);
573 channel->ptsname = NULL;
574 if (channel->tmp != NULL)
577 if (channel->origin != NULL)
578 free(channel->origin);
579 channel->origin = NULL;
581 channel->frames_allowed = 0;
582 channel->v24_signals = 0;
583 channel->remaining = 0;
587 static int logical_channel_init(Channel* channel, int id)
589 channel->id = id; // connected channel-id
590 channel->devicename = id?"/dev/ptmx":NULL; // TODO do we need this to be dynamic anymore?
592 channel->g_source = -1;
593 channel->ptsname = NULL;
595 channel->origin = NULL;
597 return logical_channel_close(channel);
600 gboolean pseudo_device_read(GIOChannel *source, GIOCondition condition, gpointer data)
602 LOG(LOG_DEBUG, "Enter");
603 Channel* channel = (Channel*)data;
604 if (condition == G_IO_IN)
606 unsigned char buf[4096];
607 //information from virtual port
608 int len = read(channel->fd, buf + channel->remaining, sizeof(buf) - channel->remaining);
609 if (!channel->opened)
611 LOG(LOG_WARNING, "Write to a channel which wasn't acked to be open.");
612 write_frame(channel->id, NULL, 0, GSM0710_TYPE_SABM | GSM0710_PF);
613 LOG(LOG_DEBUG, "Leave");
618 LOG(LOG_DEBUG, "Data from channel %d, %d bytes", channel->id, len);
619 if (channel->remaining > 0)
621 memcpy(buf, channel->tmp, channel->remaining);
625 if (len + channel->remaining > 0)
626 channel->remaining = handle_channel_data(buf, len + channel->remaining, channel->id);
627 //copy remaining bytes from last packet into tmp
628 if (channel->remaining > 0)
630 channel->tmp = malloc(channel->remaining);
631 memcpy(channel->tmp, buf + sizeof(buf) - channel->remaining, channel->remaining);
633 LOG(LOG_DEBUG, "Leave");
636 // dropped connection
637 logical_channel_close(channel);
639 else if (condition == G_IO_HUP)
641 logical_channel_close(channel);
643 LOG(LOG_DEBUG, "Leave");
647 static gboolean watchdog(gpointer data);
648 static int close_devices();
650 static gboolean c_get_power(const char* origin)
652 LOG(LOG_DEBUG, "Enter");
653 LOG(LOG_DEBUG, "Leave");
654 return serial.state != MUX_STATE_OFF;
657 static gboolean c_set_power(const char* origin, gboolean on)
659 LOG(LOG_DEBUG, "Enter");
662 if (serial.state == MUX_STATE_OFF)
664 LOG(LOG_INFO, "power on");
665 serial.state = MUX_STATE_OPENING;
669 LOG(LOG_WARNING, "power on request received but was already on");
673 if (serial.state == MUX_STATE_MUXING)
675 LOG(LOG_INFO, "power off");
676 g_source_remove(serial.g_source_watchdog);
680 LOG(LOG_WARNING, "power off received but wasn't on/muxing");
682 LOG(LOG_DEBUG, "Leave");
686 static gboolean c_reset_modem(const char* origin)
688 LOG(LOG_DEBUG, "Enter");
689 LOG(LOG_INFO, "modem reset");
690 serial.state = MUX_STATE_CLOSING;
694 static gboolean c_alloc_channel(const char* origin, const char** name)
696 LOG(LOG_DEBUG, "Enter");
699 GSource *timeout_source;
701 if (serial.state == MUX_STATE_MUXING)
702 for (i=1;i<GSM0710_MAX_CHANNELS;i++)
703 if (channellist[i].fd < 0) // is this channel free?
705 LOG(LOG_DEBUG, "Found channel %d fd %d on %s", i, channellist[i].fd, channellist[i].devicename);
706 channellist[i].origin = strdup(origin);
707 SYSCHECK(channellist[i].fd = open(channellist[i].devicename, O_RDWR | O_NONBLOCK)); //open devices
708 char* pts = ptsname(channellist[i].fd);
709 if (pts == NULL) SYSCHECK(-1);
710 channellist[i].ptsname = strdup(pts);
711 struct termios options;
712 tcgetattr(channellist[i].fd, &options); //get the parameters
713 options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); //set raw input
714 options.c_iflag &= ~(INLCR | ICRNL | IGNCR);
715 options.c_oflag &= ~(OPOST| OLCUC| ONLRET| ONOCR| OCRNL); //set raw output
716 tcsetattr(channellist[i].fd, TCSANOW, &options);
717 if (!strcmp(channellist[i].devicename, "/dev/ptmx"))
719 //Otherwise programs cannot access the pseudo terminals
720 SYSCHECK(grantpt(channellist[i].fd));
721 SYSCHECK(unlockpt(channellist[i].fd));
723 channellist[i].v24_signals = GSM0710_SIGNAL_DV | GSM0710_SIGNAL_RTR | GSM0710_SIGNAL_RTC | GSM0710_EA;
724 channellist[i].g_channel = g_io_channel_unix_new(channellist[i].fd);
725 g_io_channel_set_encoding(channellist[i].g_channel, NULL, NULL );
726 g_io_channel_set_buffer_size( channellist[i].g_channel, PTY_GLIB_BUFFER_SIZE );
727 channellist[i].g_source = g_io_add_watch(channellist[i].g_channel, G_IO_IN | G_IO_HUP, pseudo_device_read, channellist+i);
728 LOG(LOG_INFO, "Connecting %s to virtual channel %d for %s on %s",
729 channellist[i].ptsname, channellist[i].id, channellist[i].origin, serial.devicename);
730 *name = strdup(channellist[i].ptsname);
731 for (write_retries=0; write_retries<GSM0710_WRITE_RETRIES; write_retries++)
733 write_frame(i, NULL, 0, GSM0710_TYPE_SABM | GSM0710_PF);
734 timeout_id = g_timeout_add_seconds(3, glib_returnfalse, NULL);
735 timeout_source = g_main_context_find_source_by_id(NULL, timeout_id);
738 LOG(LOG_DEBUG, "g_main_context_iteration");
739 g_main_context_iteration(NULL, TRUE);
741 while (!channellist[i].frames_allowed && !g_source_is_destroyed(timeout_source));
742 if (channellist[i].opened)
745 /* No need to explicitly destroy this source */
746 if (!channellist[i].frames_allowed)
748 LOG(LOG_INFO, "Unable to open the new channel %d", i);
749 logical_channel_close(&channellist[i]);
754 LOG(LOG_WARNING, "not muxing or no free channel found");
758 static void my_log_handler(
759 const gchar *log_domain,
760 GLogLevelFlags log_level,
761 const gchar *message,
764 LOG(LOG_INFO, "%d %s %s", log_level, log_domain, message);
767 #include "muxercontrol.c"
768 #include "mux-glue.h"
770 static int dbus_init()
772 g_log_set_handler(NULL, G_LOG_LEVEL_MASK, my_log_handler, NULL);
774 g_log_set_always_fatal(G_LOG_LEVEL_WARNING);
775 GError* g_err = NULL;
776 g_conn = dbus_g_bus_get(DBUS_BUS_SYSTEM, &g_err);
780 LOG(LOG_ERR, "Connecting to system bus failed: %s", g_err->message);
784 GObject* obj = (GObject*)muxer_control_gen();
786 memset(&err, 0, sizeof(err));
787 if (dbus_bus_request_name(dbus_g_connection_get_connection(g_conn), "org.pyneo.muxer", DBUS_NAME_FLAG_ALLOW_REPLACEMENT|DBUS_NAME_FLAG_REPLACE_EXISTING, &err) < 0)
789 if (dbus_error_is_set(&err))
790 LOG(LOG_ERR, "dbus error with dbus_bus_request_name '%s' '%s'", err.name, err.message);
792 LOG(LOG_ERR, "dbus error with dbus_bus_request_name");
795 dbus_g_object_type_install_info(TYPE_MUXER_CONTROL, &dbus_glib_mux_object_info);
796 dbus_g_connection_register_g_object(g_conn, object_name, obj);
800 static int dbus_deinit()
803 dbus_g_connection_unref(g_conn);
807 static int dbus_signal_send_deactivate(const char* sigvalue)
809 DBusConnection* conn = dbus_g_connection_get_connection(g_conn);
812 LOG(LOG_ERR, "Connection null");
815 DBusMessage* msg = dbus_message_new_signal(object_name, // object name of the signal
816 "org.freesmartphone.GSM.MUX", // interface name of the signal
817 "deactivate"); // name of the signal
820 LOG(LOG_ERR, "Message Null");
823 DBusMessageIter args;
824 dbus_message_iter_init_append(msg, &args); // append arguments onto signal
825 if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &sigvalue))
827 LOG(LOG_ERR, "Out Of Memory");
830 dbus_uint32_t g_serial = 0; // unique number to associate replies with requests
831 if (!dbus_connection_send(conn, msg, &g_serial)) // send the message and flush the connection
833 LOG(LOG_ERR, "Out Of Memory");
836 dbus_connection_flush(conn);
838 dbus_message_unref(msg);
843 GPtrArray *table = parse("(14-5),(3-7),(4-9),(33)");
845 for(int i = 0; i < table->len; i++)
847 int *arr = g_ptr_array_index(table, i);
848 printf("(%d, %d)\n", arr[0], arr[1]);
851 GPtrArray* parse(const gchar* str)
853 GPtrArray *table = g_ptr_array_new();
864 else if(str[i] == ')')
866 int *tuple = malloc(sizeof(int)*2);
868 tuple[1] = atoi(str + pos);
869 tuple[0] = first == -1 ? tuple[1] : first;
871 g_ptr_array_add(table, (gpointer)tuple);
873 else if(str[i] == '-')
875 first = atoi(str + pos);
882 //////////////////////////////////////////////// real functions
883 /* Allocates memory for a new buffer and initializes it.
886 * the pointer to a new buufer
888 static GSM0710_Buffer *gsm0710_buffer_init(
891 GSM0710_Buffer* buf = (GSM0710_Buffer*)malloc(sizeof(GSM0710_Buffer));
894 memset(buf, 0, sizeof(GSM0710_Buffer));
895 buf->readp = buf->data;
896 buf->writep = buf->data;
897 buf->endp = buf->data + GSM0710_BUFFER_SIZE;
902 /* Destroys the buffer (i.e. frees up the memory
905 * buf - buffer to be destroyed
907 static void gsm0710_buffer_destroy(
913 /* Writes data to the buffer
916 * buf - pointer to the buffer
917 * input - input data (in user memory)
918 * length - how many characters should be written
920 * number of characters written
922 static int gsm0710_buffer_write(
924 const unsigned char *input,
927 LOG(LOG_DEBUG, "Enter");
928 int c = buf->endp - buf->writep;
929 length = min(length, gsm0710_buffer_free(buf));
932 memcpy(buf->writep, input, c);
933 memcpy(buf->data, input + c, length - c);
934 buf->writep = buf->data + (length - c);
938 memcpy(buf->writep, input, length);
939 buf->writep += length;
940 if (buf->writep == buf->endp)
941 buf->writep = buf->data;
943 LOG(LOG_DEBUG, "Leave");
950 static void destroy_frame(
951 GSM0710_Frame * frame)
953 if (frame->length > 0)
958 /* Gets a frame from buffer. You have to remember to free this frame
959 * when it's not needed anymore
962 * buf - the buffer, where the frame is extracted
964 * frame or null, if there isn't ready frame with given index
966 static GSM0710_Frame* gsm0710_base_buffer_get_frame(
967 GSM0710_Buffer * buf)
970 int length_needed = 5;// channel, type, length, fcs, flag
972 unsigned char fcs = 0xFF;
973 GSM0710_Frame *frame = NULL;
975 while (!buf->flag_found && gsm0710_buffer_length(buf) > 0)
977 if (*buf->readp == GSM0710_FRAME_FLAG)
979 gsm0710_buffer_inc(buf, buf->readp);
981 if (!buf->flag_found)// no frame started
983 //skip empty frames (this causes troubles if we're using DLC 62)
984 while (gsm0710_buffer_length(buf) > 0 && (*buf->readp == GSM0710_FRAME_FLAG))
986 gsm0710_buffer_inc(buf, buf->readp);
988 if (gsm0710_buffer_length(buf) >= length_needed)
991 if ((frame = (GSM0710_Frame*)malloc(sizeof(GSM0710_Frame))) != NULL)
993 frame->channel = ((*data & 252) >> 2);
994 fcs = r_crctable[fcs ^ *data];
995 gsm0710_buffer_inc(buf, data);
996 frame->control = *data;
997 fcs = r_crctable[fcs ^ *data];
998 gsm0710_buffer_inc(buf, data);
999 frame->length = (*data & 254) >> 1;
1000 fcs = r_crctable[fcs ^ *data];
1003 LOG(LOG_ALERT, "Out of memory, when allocating space for frame");
1004 if ((*data & 1) == 0)
1006 //Current spec (version 7.1.0) states these kind of
1007 //frames to be invalid Long lost of sync might be
1008 //caused if we would expect a long frame because of an
1009 //error in length field.
1011 gsm0710_buffer_inc(buf,data);
1012 frame->length += (*data*128);
1013 fcs = r_crctable[fcs^*data];
1018 buf->flag_found = 0;
1019 return gsm0710_base_buffer_get_frame(buf);
1021 length_needed += frame->length;
1022 if (!(gsm0710_buffer_length(buf) >= length_needed))
1027 gsm0710_buffer_inc(buf, data);
1029 if (frame->length > 0)
1031 if ((frame->data = malloc(sizeof(char) * frame->length)) != NULL)
1033 end = buf->endp - data;
1034 if (frame->length > end)
1036 memcpy(frame->data, data, end);
1037 memcpy(frame->data + end, buf->data, frame->length - end);
1038 data = buf->data + (frame->length - end);
1042 memcpy(frame->data, data, frame->length);
1043 data += frame->length;
1044 if (data == buf->endp)
1047 if (GSM0710_FRAME_IS(GSM0710_TYPE_UI, frame))
1049 for (end = 0; end < frame->length; end++)
1050 fcs = r_crctable[fcs ^ (frame->data[end])];
1055 LOG(LOG_ALERT, "Out of memory, when allocating space for frame data");
1060 if (r_crctable[fcs ^ (*data)] != 0xCF)
1062 LOG(LOG_WARNING, "Dropping frame: FCS doesn't match");
1063 destroy_frame(frame);
1064 buf->flag_found = 0;
1065 buf->dropped_count++;
1067 return gsm0710_base_buffer_get_frame(buf);
1072 gsm0710_buffer_inc(buf, data);
1073 if (*data != GSM0710_FRAME_FLAG)
1075 LOG(LOG_WARNING, "Dropping frame: End flag not found. Instead: %d", *data);
1076 destroy_frame(frame);
1077 buf->flag_found = 0;
1078 buf->dropped_count++;
1080 return gsm0710_base_buffer_get_frame(buf);
1083 buf->received_count++;
1084 gsm0710_buffer_inc(buf, data);
1091 /* Gets a advanced option frame from buffer. You have to remember to free this frame
1092 * when it's not needed anymore
1095 * buf - the buffer, where the frame is extracted
1097 * frame or null, if there isn't ready frame with given index
1099 static GSM0710_Frame *gsm0710_advanced_buffer_get_frame(
1100 GSM0710_Buffer * buf)
1102 LOG(LOG_DEBUG, "Enter");
1105 while (!buf->flag_found && gsm0710_buffer_length(buf) > 0)
1107 if (*buf->readp == GSM0710_FRAME_ADV_FLAG)
1109 buf->flag_found = 1;
1110 buf->adv_length = 0;
1111 buf->adv_found_esc = 0;
1113 gsm0710_buffer_inc(buf, buf->readp);
1115 if (!buf->flag_found)// no frame started
1117 if (0 == buf->adv_length)
1118 //skip empty frames (this causes troubles if we're using DLC 62)
1119 while (gsm0710_buffer_length(buf) > 0 && (*buf->readp == GSM0710_FRAME_ADV_FLAG))
1120 gsm0710_buffer_inc(buf, buf->readp);
1121 while (gsm0710_buffer_length(buf) > 0)
1123 if (!buf->adv_found_esc && GSM0710_FRAME_ADV_FLAG == *(buf->readp))
1124 {// closing flag found
1125 GSM0710_Frame *frame = NULL;
1126 unsigned char *data = buf->adv_data;
1127 unsigned char fcs = 0xFF;
1128 gsm0710_buffer_inc(buf, buf->readp);
1129 if (buf->adv_length < 3)
1131 LOG(LOG_WARNING, "Too short adv frame, length:%d", buf->adv_length);
1132 buf->flag_found = 0;
1135 if ((frame = (GSM0710_Frame*)malloc(sizeof(GSM0710_Frame))) != NULL)
1137 frame->channel = ((data[0] & 252) >> 2);
1138 fcs = r_crctable[fcs ^ data[0]];
1139 frame->control = data[1];
1140 fcs = r_crctable[fcs ^ data[1]];
1141 frame->length = buf->adv_length - 3;
1144 LOG(LOG_ALERT, "Out of memory, when allocating space for frame");
1146 if (frame->length > 0)
1148 if ((frame->data = (unsigned char *) malloc(sizeof(char) * frame->length)))
1150 memcpy(frame->data, data + 2, frame->length);
1151 if (GSM0710_FRAME_IS(GSM0710_TYPE_UI, frame))
1154 for (i = 0; i < frame->length; ++i)
1155 fcs = r_crctable[fcs ^ (frame->data[i])];
1160 LOG(LOG_ALERT, "Out of memory, when allocating space for frame data");
1161 buf->flag_found = 0;
1166 if (r_crctable[fcs ^ data[buf->adv_length - 1]] != 0xCF)
1168 LOG(LOG_WARNING, "Dropping frame: FCS doesn't match");
1169 destroy_frame(frame);
1170 buf->flag_found = 0;
1171 buf->dropped_count++;
1176 buf->received_count++;
1177 buf->flag_found = 0;
1178 LOG(LOG_DEBUG, "Leave success");
1182 if (buf->adv_length >= sizeof(buf->adv_data))
1184 LOG(LOG_WARNING, "Too long adv frame, length:%d", buf->adv_length);
1185 buf->flag_found = 0;
1186 buf->dropped_count++;
1189 if (buf->adv_found_esc)
1191 buf->adv_data[buf->adv_length] = *(buf->readp) ^ GSM0710_FRAME_ADV_ESC_COPML;
1193 buf->adv_found_esc = 0;
1195 else if (GSM0710_FRAME_ADV_ESC == *(buf->readp))
1196 buf->adv_found_esc = 1;
1199 buf->adv_data[buf->adv_length] = *(buf->readp);
1202 gsm0710_buffer_inc(buf, buf->readp);
1208 * Returns 1 if found, 0 otherwise. needle must be null-terminated.
1209 * strstr might not work because WebBox sends garbage before the first
1213 const char *haystack,
1219 if (needle[0] == '\0')
1221 for (i = 0; i < length; i++)
1222 if (needle[j] == haystack[i])
1225 if (needle[j] == '\0') // Entire needle was found
1234 * Sends an AT-command to a given serial port and waits for reply.
1235 * PARAMS: fd - file descriptor cmd - command to - how many
1236 * seconds to wait for response RETURNS:
1237 * 0 on success (OK-response), -1 otherwise
1240 int serial_device_fd,
1244 LOG(LOG_DEBUG, "Enter");
1245 unsigned char buf[1024];
1249 syslogdump(">s ", (unsigned char *) cmd, strlen(cmd));
1250 SYSCHECK(wrote = write(serial_device_fd, cmd, strlen(cmd)));
1251 LOG(LOG_DEBUG, "Wrote %d bytes", wrote);
1252 SYSCHECK(tcdrain(serial_device_fd));
1256 FD_SET(serial_device_fd, &rfds);
1257 struct timeval timeout;
1258 timeout.tv_sec = to;
1259 timeout.tv_usec = 0;
1262 SYSCHECK(sel = select(serial_device_fd + 1, &rfds, NULL, NULL, &timeout));
1263 LOG(LOG_DEBUG, "Selected %d", sel);
1264 if (FD_ISSET(serial_device_fd, &rfds))
1266 memset(buf, 0, sizeof(buf));
1267 len = read(serial_device_fd, buf, sizeof(buf));
1269 LOG(LOG_DEBUG, "Read %d bytes from serial device", len);
1270 syslogdump("<s ", buf, len);
1272 if (memstr((char *) buf, len, "OK"))
1274 LOG(LOG_DEBUG, "Received OK");
1277 if (memstr((char *) buf, len, "ERROR"))
1279 LOG(LOG_DEBUG, "Received ERROR");
1288 * Handles commands received from the control channel.
1290 static int handle_command(
1291 GSM0710_Frame * frame)
1293 LOG(LOG_DEBUG, "Enter");
1294 unsigned char type, signals;
1295 int length = 0, i, type_length, channel, supported = 1;
1296 unsigned char *response;
1297 //struct ussp_operation op;
1298 if (frame->length > 0)
1300 type = frame->data[0];// only a byte long types are handled now skip extra bytes
1301 for (i = 0; (frame->length > i && (frame->data[i] & GSM0710_EA) == 0); i++);
1304 if ((type & GSM0710_CR) == GSM0710_CR)
1306 //command not ack extract frame length
1307 while (frame->length > i)
1309 length = (length * 128) + ((frame->data[i] & 254) >> 1);
1310 if ((frame->data[i] & 1) == 1)
1315 switch ((type & ~GSM0710_CR))
1317 case GSM0710_CONTROL_CLD:
1318 LOG(LOG_INFO, "The mobile station requested mux-mode termination");
1319 serial.state = MUX_STATE_CLOSING;
1321 case GSM0710_CONTROL_PSC:
1322 LOG(LOG_DEBUG, "Power Service Control command: ***");
1323 LOG(LOG_DEBUG, "Frame->data = %s / frame->length = %d", frame->data + i, frame->length - i);
1325 case GSM0710_CONTROL_TEST:
1326 LOG(LOG_DEBUG, "Test command: ");
1327 LOG(LOG_DEBUG, "Frame->data = %s / frame->length = %d", frame->data + i, frame->length - i);
1328 //serial->ping_number = 0;
1330 case GSM0710_CONTROL_MSC:
1331 if (i + 1 < frame->length)
1333 channel = ((frame->data[i] & 252) >> 2);
1335 signals = (frame->data[i]);
1337 //op.arg = USSP_RTS;
1339 LOG(LOG_DEBUG, "Modem status command on channel %d", channel);
1340 if ((signals & GSM0710_SIGNAL_FC) == GSM0710_SIGNAL_FC)
1341 LOG(LOG_DEBUG, "No frames allowed");
1344 //op.arg |= USSP_CTS;
1345 LOG(LOG_DEBUG, "Frames allowed");
1346 channellist[channel].frames_allowed = 1;
1348 if ((signals & GSM0710_SIGNAL_RTC) == GSM0710_SIGNAL_RTC)
1350 //op.arg |= USSP_DSR;
1351 LOG(LOG_DEBUG, "Signal RTC");
1353 if ((signals & GSM0710_SIGNAL_IC) == GSM0710_SIGNAL_IC)
1355 //op.arg |= USSP_RI;
1356 LOG(LOG_DEBUG, "Signal Ring");
1358 if ((signals & GSM0710_SIGNAL_DV) == GSM0710_SIGNAL_DV)
1360 //op.arg |= USSP_DCD;
1361 LOG(LOG_DEBUG, "Signal DV");
1364 //write(channellist[channel].fd, &op,
1368 LOG(LOG_ERR, "Modem status command, but no info. i: %d, len: %d, data-len: %d",
1369 i, length, frame->length);
1372 LOG(LOG_ALERT, "Unknown command (%d) from the control channel", type);
1373 if ((response = malloc(sizeof(char) * (2 + type_length))) != NULL)
1376 response[i++] = GSM0710_CONTROL_NSC;
1377 type_length &= 127; //supposes that type length is less than 128
1378 response[i++] = GSM0710_EA | (type_length << 1);
1379 while (type_length--)
1381 response[i] = frame->data[i - 2];
1384 write_frame(0, response, i, GSM0710_TYPE_UIH);
1389 LOG(LOG_ALERT, "Out of memory, when allocating space for response");
1394 //acknowledge the command
1395 frame->data[0] = frame->data[0] & ~GSM0710_CR;
1396 write_frame(0, frame->data, frame->length, GSM0710_TYPE_UIH);
1401 //received ack for a command
1402 if (GSM0710_COMMAND_IS(type, GSM0710_CONTROL_NSC))
1403 LOG(LOG_ERR, "The mobile station didn't support the command sent");
1405 LOG(LOG_DEBUG, "Command acknowledged by the mobile station");
1412 * Extracts and handles frames from the receiver buffer. PARAMS: buf
1413 * - the receiver buffer
1416 GSM0710_Buffer* buf)
1418 LOG(LOG_DEBUG, "Enter");
1419 //version test for Siemens terminals to enable version 2 functions
1420 int frames_extracted = 0;
1421 GSM0710_Frame *frame;
1422 while ((frame = cmux_mode
1423 ? gsm0710_advanced_buffer_get_frame(buf)
1424 : gsm0710_base_buffer_get_frame(buf)))
1427 if ((GSM0710_FRAME_IS(GSM0710_TYPE_UI, frame) || GSM0710_FRAME_IS(GSM0710_TYPE_UIH, frame)))
1429 LOG(LOG_DEBUG, "Frame is UI or UIH");
1430 if (frame->channel > 0)
1433 LOG(LOG_DEBUG, "Frame channel > 0, pseudo channel");
1434 //data from logical channel
1435 g_io_channel_write_chars(channellist[frame->channel].g_channel, (gchar*)frame->data, (gssize)frame->length, &written, NULL);
1436 if (written != frame->length)
1437 LOG(LOG_WARNING, "Pty write buffer overflow, data loss: needed to write %d bytes, written %d, channel %d", frame->length, written, frame->channel);
1439 LOG(LOG_DEBUG, "Written %d bytes to pty channel %d", written, frame->channel);
1440 g_io_channel_flush(channellist[frame->channel].g_channel, NULL );
1444 //control channel command
1445 LOG(LOG_DEBUG, "Frame channel == 0, control channel command");
1446 handle_command(frame);
1451 //not an information frame
1452 LOG(LOG_DEBUG, "Not an information frame");
1453 switch ((frame->control & ~GSM0710_PF))
1455 case GSM0710_TYPE_UA:
1456 LOG(LOG_DEBUG, "Frame is UA");
1457 if (channellist[frame->channel].opened)
1459 LOG(LOG_INFO, "Logical channel %d for %s closed",
1460 frame->channel, channellist[frame->channel].origin);
1461 channellist[frame->channel].opened = 0;
1465 channellist[frame->channel].opened = 1;
1466 if (frame->channel == 0)
1468 LOG(LOG_DEBUG, "Control channel opened");
1469 //send version Siemens version test
1470 //static unsigned char version_test[] = "\x23\x21\x04TEMUXVERSION2\0";
1471 //write_frame(0, version_test, sizeof(version_test), GSM0710_TYPE_UIH);
1474 LOG(LOG_INFO, "Logical channel %d opened", frame->channel);
1477 case GSM0710_TYPE_DM:
1478 if (channellist[frame->channel].opened)
1480 SYSCHECK(logical_channel_close(channellist+frame->channel));
1481 LOG(LOG_INFO, "DM received, so the channel %d for %s was already closed",
1482 frame->channel, channellist[frame->channel].origin);
1486 if (frame->channel == 0)
1488 LOG(LOG_INFO, "Couldn't open control channel.\n->Terminating");
1489 serial.state = MUX_STATE_CLOSING;
1493 LOG(LOG_INFO, "Logical channel %d for %s couldn't be opened", frame->channel, channellist[frame->channel].origin);
1496 case GSM0710_TYPE_DISC:
1497 if (channellist[frame->channel].opened)
1499 channellist[frame->channel].opened = 0;
1500 write_frame(frame->channel, NULL, 0, GSM0710_TYPE_UA | GSM0710_PF);
1501 if (frame->channel == 0)
1503 serial.state = MUX_STATE_CLOSING;
1504 LOG(LOG_INFO, "Control channel closed");
1507 LOG(LOG_INFO, "Logical channel %d for %s closed", frame->channel, channellist[frame->channel].origin);
1511 //channel already closed
1512 LOG(LOG_WARNING, "Received DISC even though channel %d for %s was already closed",
1513 frame->channel, channellist[frame->channel].origin);
1514 write_frame(frame->channel, NULL, 0, GSM0710_TYPE_DM | GSM0710_PF);
1517 case GSM0710_TYPE_SABM:
1518 //channel open request
1519 if (channellist[frame->channel].opened)
1521 if (frame->channel == 0)
1522 LOG(LOG_INFO, "Control channel opened");
1524 LOG(LOG_INFO, "Logical channel %d for %s opened",
1525 frame->channel, channellist[frame->channel].origin);
1528 //channel already opened
1529 LOG(LOG_WARNING, "Received SABM even though channel %d for %s was already closed",
1530 frame->channel, channellist[frame->channel].origin);
1531 channellist[frame->channel].opened = 1;
1532 write_frame(frame->channel, NULL, 0, GSM0710_TYPE_UA | GSM0710_PF);
1536 destroy_frame(frame);
1538 LOG(LOG_DEBUG, "Leave");
1539 return frames_extracted;
1543 * Function responsible by all signal handlers treatment
1544 * any new signal must be added here
1546 void signal_treatment(
1555 //reread the configuration files
1562 g_main_loop_quit(main_loop);
1571 static int modem_hw_(const char* pm_base_dir, const char* entry, int on)
1573 LOG(LOG_DEBUG, "Enter");
1574 if (pm_base_dir != NULL)
1577 SYSCHECK(snprintf(fn, sizeof(fn), "%s/%s", pm_base_dir, entry));
1578 LOG(LOG_DEBUG, "echo %c > %s", on?'1':'0', fn);
1580 SYSCHECK(fd = open(fn, O_RDWR | O_NONBLOCK));
1581 SYSCHECK(write(fd, on?"1\n":"0\n", 2));
1582 SYSCHECK(close(fd));
1585 LOG(LOG_DEBUG, "no pm_base_dir");
1586 LOG(LOG_DEBUG, "Leave");
1590 static int modem_hw_off(const char* pm_base_dir)
1592 LOG(LOG_DEBUG, "Enter");
1593 SYSCHECK(modem_hw_(pm_base_dir, "power_on", 0));
1594 SYSCHECK(modem_hw_(pm_base_dir, "reset", 0));
1595 LOG(LOG_DEBUG, "Leave");
1599 static int modem_hw_on(const char* pm_base_dir)
1601 LOG(LOG_DEBUG, "Enter");
1602 SYSCHECK(modem_hw_off(pm_base_dir));
1604 SYSCHECK(modem_hw_(pm_base_dir, "power_on", 1));
1606 SYSCHECK(modem_hw_(pm_base_dir, "reset", 1));
1608 SYSCHECK(modem_hw_(pm_base_dir, "reset", 0));
1610 LOG(LOG_DEBUG, "Leave");
1614 gboolean serial_device_read(GIOChannel *source, GIOCondition condition, gpointer data)
1616 Serial* serial = (Serial*)data;
1617 LOG(LOG_DEBUG, "Enter");
1618 if (condition == G_IO_IN)
1620 switch (serial->state)
1622 case MUX_STATE_MUXING:
1624 unsigned char buf[4096];
1626 //input from serial port
1627 LOG(LOG_DEBUG, "Serial Data");
1629 if ((length = gsm0710_buffer_free(serial->in_buf)) > 0
1630 && (len = read(serial->fd, buf, min(length, sizeof(buf)))) > 0)
1632 syslogdump("<s ", buf, len);
1633 gsm0710_buffer_write(serial->in_buf, buf, len);
1634 //extract and handle ready frames
1635 if (extract_frames(serial->in_buf) > 0)
1637 time(&serial->frame_receive_time); //get the current time
1638 serial->ping_number = 0;
1641 LOG(LOG_DEBUG, "Leave keep watching");
1646 LOG(LOG_WARNING, "Don't know how to handle reading in state %d", serial->state);
1650 else if (condition == G_IO_HUP)
1652 LOG(LOG_WARNING, "hup on serial file, closing");
1653 serial->state = MUX_STATE_CLOSING;
1655 LOG(LOG_DEBUG, "Leave stop watching");
1659 int open_serial_device(
1663 LOG(LOG_DEBUG, "Enter");
1664 SYSCHECK(modem_hw_on(serial->pm_base_dir));
1666 for (i=0;i<GSM0710_MAX_CHANNELS;i++)
1667 SYSCHECK(logical_channel_init(channellist+i, i));
1668 //open the serial port
1669 SYSCHECK(serial->fd = open(serial->devicename, O_RDWR | O_NOCTTY | O_NONBLOCK));
1670 LOG(LOG_INFO, "Opened serial port");
1672 SYSCHECK(fdflags = fcntl(serial->fd, F_GETFL));
1673 SYSCHECK(fcntl(serial->fd, F_SETFL, fdflags & ~O_NONBLOCK));
1675 tcgetattr(serial->fd, &t);
1676 t.c_cflag &= ~(CSIZE | CSTOPB | PARENB | PARODD);
1677 t.c_cflag |= CREAD | CLOCAL | CS8 | CRTSCTS;
1678 t.c_lflag &= ~(ICANON | ECHO | ECHOE | ECHOK | ECHONL | ISIG);
1679 t.c_iflag &= ~(INPCK | IGNPAR | PARMRK | ISTRIP | IXANY | ICRNL);
1680 t.c_iflag &= ~(IXON | IXOFF);
1681 t.c_oflag &= ~(OPOST | OCRNL);
1683 t.c_cc[VINTR] = _POSIX_VDISABLE;
1684 t.c_cc[VQUIT] = _POSIX_VDISABLE;
1685 t.c_cc[VSTART] = _POSIX_VDISABLE;
1686 t.c_cc[VSTOP] = _POSIX_VDISABLE;
1687 t.c_cc[VSUSP] = _POSIX_VDISABLE;
1688 speed_t speed = baud_bits[cmux_port_speed];
1689 cfsetispeed(&t, speed);
1690 cfsetospeed(&t, speed);
1691 SYSCHECK(tcsetattr(serial->fd, TCSANOW, &t));
1692 int status = TIOCM_DTR | TIOCM_RTS;
1693 ioctl(serial->fd, TIOCMBIS, &status);
1694 LOG(LOG_INFO, "Configured serial device");
1695 serial->ping_number = 0;
1696 time(&serial->frame_receive_time); //get the current time
1697 serial->state = MUX_STATE_INITILIZING;
1705 LOG(LOG_INFO, "Configuring modem");
1706 char gsm_command[100];
1707 if (chat(serial->fd, "\r\n\r\n\r\nAT\r\n", 1) < 0)
1709 LOG(LOG_WARNING, "Modem does not respond to AT commands, trying close mux mode");
1710 //if (cmux_mode) we do not know now so write both
1711 write_frame(0, NULL, 0, GSM0710_CONTROL_CLD | GSM0710_CR);
1713 write_frame(0, close_channel_cmd, 2, GSM0710_TYPE_UIH);
1714 SYSCHECK(chat(serial->fd, "AT\r\n", 1));
1716 SYSCHECK(chat(serial->fd, "ATZ\r\n", 3));
1717 SYSCHECK(chat(serial->fd, "ATE0\r\n", 1));
1718 if (0)// additional siemens c35 init
1720 SYSCHECK(snprintf(gsm_command, sizeof(gsm_command), "AT+IPR=%d\r\n", baud_rates[cmux_port_speed]));
1721 SYSCHECK(chat(serial->fd, gsm_command, 1));
1722 SYSCHECK(chat(serial->fd, "AT\r\n", 1));
1723 SYSCHECK(chat(serial->fd, "AT&S0\r\n", 1));
1724 SYSCHECK(chat(serial->fd, "AT\\Q3\r\n", 1));
1726 //SYSCHECK(chat(serial->fd, "AT+CMUX=?\r\n", 1));
1729 LOG(LOG_DEBUG, "send pin %04d", pin_code);
1730 //Some modems, such as webbox, will sometimes hang if SIM code
1731 //is given in virtual channel
1732 SYSCHECK(snprintf(gsm_command, sizeof(gsm_command), "AT+CPIN=%04d\r\n", pin_code));
1733 SYSCHECK(chat(serial->fd, gsm_command, 10));
1735 SYSCHECK(chat(serial->fd, "AT+CFUN=0\r\n", 10));
1736 SYSCHECK(snprintf(gsm_command, sizeof(gsm_command), "AT+CMUX=%d,%d,%d,%d"
1749 LOG(LOG_INFO, "Starting mux mode");
1750 SYSCHECK(chat(serial->fd, gsm_command, 3));
1751 serial->state = MUX_STATE_MUXING;
1752 LOG(LOG_INFO, "Waiting for mux-mode");
1754 LOG(LOG_INFO, "Init control channel");
1755 write_frame(0, NULL, 0, GSM0710_TYPE_SABM | GSM0710_PF);
1756 GIOChannel* channel = g_io_channel_unix_new(serial->fd);
1757 serial->g_source = g_io_add_watch(channel, G_IO_IN | G_IO_HUP, serial_device_read, serial);
1761 static int close_devices()
1763 LOG(LOG_DEBUG, "Enter");
1764 g_source_remove(serial.g_source);
1765 serial.g_source = -1;
1767 // don't bother closing the channels over the MUX protocol, first off,
1768 // the mainloop is no longer running anyways, second, we're about to
1769 // shutdown the modem completely in a second.
1771 for (i=1;i<GSM0710_MAX_CHANNELS;i++)
1773 //terminate command given. Close channels one by one and finaly close
1775 if (channellist[i].fd >= 0)
1777 SYSCHECK(dbus_signal_send_deactivate(channellist[i].ptsname));
1778 if (channellist[i].opened)
1780 LOG(LOG_INFO, "Closing down the logical channel %d", i);
1781 SYSCHECK(logical_channel_close(channellist+i));
1783 LOG(LOG_INFO, "Logical channel %d closed", channellist[i].id);
1790 write_frame(0, NULL, 0, GSM0710_CONTROL_CLD | GSM0710_CR);
1792 write_frame(0, close_channel_cmd, 2, GSM0710_TYPE_UIH);
1793 static const char* poff = "AT@POFF\r\n";
1794 syslogdump(">s ", (unsigned char *)poff, strlen(poff));
1795 write(serial.fd, poff, strlen(poff));
1796 SYSCHECK(close(serial.fd));
1799 SYSCHECK(modem_hw_off(serial.pm_base_dir));
1800 serial.state = MUX_STATE_OFF;
1804 static gboolean watchdog(gpointer data)
1807 LOG(LOG_DEBUG, "Enter");
1808 Serial* serial = (Serial*)data;
1809 LOG(LOG_DEBUG, "Serial state is %d", serial->state);
1810 switch (serial->state)
1812 case MUX_STATE_OPENING:
1813 if (open_serial_device(serial) < 0)
1814 LOG(LOG_WARNING, "Could not open all devices and start muxer");
1815 serial->g_source_watchdog = g_timeout_add_seconds(1, watchdog, data); // let the dog watch every 1 sec
1816 LOG(LOG_INFO, "Watchdog started");
1817 case MUX_STATE_INITILIZING:
1818 if (start_muxer(serial) < 0)
1819 LOG(LOG_WARNING, "Could not open all devices and start muxer errno=%d", errno);
1821 case MUX_STATE_MUXING:
1822 for (i=1;i<GSM0710_MAX_CHANNELS;i++)
1823 if (channellist[i].fd >= 0)
1824 g_io_channel_flush(channellist[i].g_channel, NULL);
1827 if (serial->ping_number > use_ping)
1829 LOG(LOG_DEBUG, "no ping reply for %d times, resetting modem", serial->ping_number);
1830 serial->state = MUX_STATE_CLOSING;
1834 LOG(LOG_DEBUG, "Sending PING to the modem");
1835 //write_frame(0, psc_channel_cmd, sizeof(psc_channel_cmd), GSM0710_TYPE_UI);
1836 write_frame(0, test_channel_cmd, sizeof(test_channel_cmd), GSM0710_TYPE_UI);
1837 serial->ping_number++;
1842 time_t current_time;
1843 time(¤t_time); //get the current time
1844 if (current_time - serial->frame_receive_time > use_timeout)
1846 LOG(LOG_DEBUG, "timeout, resetting modem");
1847 serial->state = MUX_STATE_CLOSING;
1851 case MUX_STATE_CLOSING:
1853 serial->state = MUX_STATE_OPENING;
1856 LOG(LOG_WARNING, "Don't know how to handle state %d", serial->state);
1863 * shows how to use this program
1868 fprintf(stdout, "Usage: %s [options]\n", _name);
1869 fprintf(stdout, "Options:\n");
1871 fprintf(stdout, "\t-d: Fork, get a daemon [%s]\n", no_daemon?"no":"yes");
1872 fprintf(stdout, "\t-v: verbose logging\n");
1874 fprintf(stdout, "\t-s <serial port name>: Serial port device to connect to [%s]\n", serial.devicename);
1875 fprintf(stdout, "\t-t <timeout>: reset modem after this number of seconds of silence [%d]\n", use_timeout);
1876 fprintf(stdout, "\t-P <pin-code>: PIN code to unlock SIM [%d]\n", pin_code);
1877 fprintf(stdout, "\t-p <number>: use ping and reset modem after this number of unanswered pings [%d]\n", use_ping);
1878 fprintf(stdout, "\t-x <dir>: power managment base dir [%s]\n", serial.pm_base_dir?serial.pm_base_dir:"<not set>");
1879 // legacy - will be removed
1880 fprintf(stdout, "\t-b <baudrate>: mode baudrate [%d]\n", baud_rates[cmux_port_speed]);
1881 fprintf(stdout, "\t-m <modem>: Mode (basic, advanced) [%s]\n", cmux_mode?"advanced":"basic");
1882 fprintf(stdout, "\t-f <framsize>: Frame size [%d]\n", cmux_N1);
1884 fprintf(stdout, "\t-h: Show this help message and show current settings.\n");
1885 fprintf(stdout, "\t-V: Show the version number.\n");
1890 * shows this program version
1892 static int show_version(
1895 fprintf(stdout, "This is the freesmartphone.org version of pyneo's %s %s\n", _name, version);
1896 fprintf(stdout, "\n");
1897 fprintf(stdout, "Copyright (C) 2003, 2006 Tuukka Karvonen <tkarvone@iki.fi>\n");
1898 fprintf(stdout, "Copyright (C) 2004 David Jander <david@protonic.nl>\n");
1899 fprintf(stdout, "Copyright (C) 2006 Antti Haapakoski <antti.haapakoski@iki.fi>\n");
1900 fprintf(stdout, "Copyright (C) 2006 Vasiliy Novikov <vn@hotbox.ru>\n");
1901 fprintf(stdout, "Copyright (C) 2008 M. Dietrich <mdt@emdete.de>\n");
1902 fprintf(stdout, "\n");
1903 fprintf(stdout, "This is free software; see the source for copying conditions. There is NO\n");
1904 fprintf(stdout, "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n");
1917 LOG(LOG_DEBUG, "Enter");
1920 //for fault tolerance
1921 serial.devicename = "/dev/ttySAC0";
1922 while ((opt = getopt(argc, argv, "dvs:t:p:f:Vh?m:b:P:x:")) > 0)
1930 no_daemon = !no_daemon;
1933 serial.pm_base_dir = optarg;
1936 serial.devicename = optarg;
1939 use_timeout = atoi(optarg);
1942 use_ping = atoi(optarg);
1945 pin_code = atoi(optarg);
1947 // will be removed if +CMUX? works
1949 cmux_N1 = atoi(optarg);
1952 if (!strcmp(optarg, "basic"))
1954 else if (!strcmp(optarg, "advanced"))
1960 cmux_port_speed = baud_rate_index(atoi(optarg));
1963 show_version(argv[0]);
1974 if (serial.pm_base_dir == NULL)
1976 // auto detect - i hate windows-like-behavior but mickey want's it ;)
1979 static char* fn[] = {
1980 "/sys/bus/platform/devices/neo1973-pm-gsm.0",
1981 "/sys/bus/platform/devices/gta01-pm-gsm.0",
1985 if (stat(fn[i], &sb) >= 0)
1987 serial.pm_base_dir = fn[i];
1988 LOG(LOG_INFO, "using '%s' as basedir for pm", fn[i]);
1992 //daemonize show time
1993 parent_pid = getpid();
1994 if (!no_daemon && daemon(0, 0))
1996 fprintf(stderr, "Failed to daemonize: %s (%d)", strerror(errno), errno);
2001 signal(SIGHUP, signal_treatment);
2002 signal(SIGPIPE, signal_treatment);
2003 signal(SIGKILL, signal_treatment);
2004 signal(SIGINT, signal_treatment);
2005 signal(SIGUSR1, signal_treatment);
2006 signal(SIGTERM, signal_treatment);
2008 openlog(argv[0], LOG_NDELAY | LOG_PID | LOG_PERROR, LOG_LOCAL0);
2010 openlog(argv[0], LOG_NDELAY | LOG_PID, LOG_LOCAL0);
2011 SYSCHECK(dbus_init());
2012 //allocate memory for data structures
2013 if ((serial.in_buf = gsm0710_buffer_init()) == NULL
2014 || (serial.adv_frame_buf = (unsigned char*)malloc((cmux_N1 + 3) * 2 + 2)) == NULL)
2016 LOG(LOG_ALERT, "Out of memory");
2019 LOG(LOG_DEBUG, "%s %s starting", *argv, revision);
2020 //Initialize modem and virtual ports
2021 serial.state = MUX_STATE_OPENING;
2023 //start waiting for input and forwarding it back and forth --
2024 main_loop = g_main_loop_new(NULL, FALSE);
2025 g_main_loop_run(main_loop); // will/may be terminated in signal_treatment
2026 g_main_loop_unref(main_loop);
2027 //finalize everything
2028 SYSCHECK(close_devices());
2029 free(serial.adv_frame_buf);
2030 gsm0710_buffer_destroy(serial.in_buf);
2031 LOG(LOG_INFO, "Received %ld frames and dropped %ld received frames during the mux-mode",
2032 serial.in_buf->received_count, serial.in_buf->dropped_count);
2033 SYSCHECK(dbus_deinit());
2034 LOG(LOG_DEBUG, "%s finished", argv[0]);
2035 closelog();// close syslog
2038 // vim:path=/usr/include,/usr/include/glib-2.0,/usr/include/dbus-1.0,src: