add deprecation notice
[gsm0710muxd.git] / src / gsm0710muxd.c
1 /*
2  * GSM 07.10 Implementation with User Space Serial Ports
3  *
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>
11  *
12  * Copyright (C) 2008 M. Dietrich <mdt@emdete.de>
13  *
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.
18  *
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.
23  *
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.
27  */
28 #ifndef _GNU_SOURCE
29 #define _GNU_SOURCE
30 #endif
31 #include <errno.h>
32 #include <fcntl.h>
33 #include <features.h>
34 #include <paths.h>
35 #include <signal.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <sys/ioctl.h>
40 #include <sys/socket.h>
41 #include <sys/stat.h>
42 #include <sys/time.h>
43 #include <sys/types.h>
44 #include <sys/wait.h>
45 #include <syslog.h>
46 #include <termios.h>
47 #include <time.h>
48 #include <unistd.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/
58
59 // dbus-send --system --print-reply --type=method_call --dest=org.pyneo.muxer /org/pyneo/Muxer org.freesmartphone.GSM.MUX.AllocChannel string:xxx
60
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);\
65  return -1;\
66  }}while(0)
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
76 // type of frames
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
105 //
106 #define GSM0710_COMMAND_IS(type, command) ((type & ~GSM0710_CR) == command)
107 #define GSM0710_FRAME_IS(type, frame) ((frame->control & ~GSM0710_PF) == type)
108 #ifndef min
109 #define min(a,b) ((a < b) ? a :b)
110 #endif
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)
118
119 ////////////////////////////////////////////////////// types
120 //
121 typedef struct GSM0710_Frame
122 {
123         unsigned char channel;
124         unsigned char control;
125         int length;
126         unsigned char *data;
127 } GSM0710_Frame;
128
129 //
130 typedef struct GSM0710_Buffer
131 {
132         unsigned char data[GSM0710_BUFFER_SIZE];
133         unsigned char *readp;
134         unsigned char *writep;
135         unsigned char *endp;
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];
140         int adv_length;
141         int adv_found_esc;
142 } GSM0710_Buffer;
143
144 // Channel data 
145 typedef struct Channel
146 {
147         int id; // gsm 07 10 channel id
148         char* devicename;
149         int fd;
150         int opened;
151         int frames_allowed;
152         unsigned char v24_signals;
153         char* ptsname;
154         char* origin;
155         int remaining;
156         unsigned char *tmp;
157         guint g_source;
158         GIOChannel* g_channel;
159 } Channel;
160
161 typedef enum MuxerStates 
162 {
163         MUX_STATE_OPENING,
164         MUX_STATE_INITILIZING,
165         MUX_STATE_MUXING,
166         MUX_STATE_CLOSING,
167         MUX_STATE_OFF,
168         MUX_STATES_COUNT // keep this the last
169 } MuxerStates;
170
171 typedef struct Serial
172 {
173         char *devicename;
174         char* pm_base_dir;
175         int fd;
176         MuxerStates state;
177         GSM0710_Buffer *in_buf;// input buffer
178         unsigned char *adv_frame_buf;
179         time_t frame_receive_time;
180         int ping_number;
181         guint g_source;
182         guint g_source_watchdog;
183 } Serial;
184
185 /////////////////////////////////////////// function prototypes
186 /**
187  * increases buffer pointer by one and wraps around if necessary
188  */
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)
191 /**
192  * Tells how many chars are saved into the buffer.
193  */
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))
196 /**
197  * tells how much free space there is in the buffer
198  */
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)
201
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,
232         0x2C, 0x5E, 0xCF, };
233 // config stuff
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";
242 // serial io
243 static Serial serial;
244 // muxed io channels
245 static Channel channellist[GSM0710_MAX_CHANNELS]; // remember: [0] is not used acticly because it's the control channel
246 // some state
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;
255 #if 0
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;
266 #endif
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)
269
270 /*
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.
274  */
275 static int baud_rates[] = {
276         0, 9600, 19200, 38400, 57600, 115200, 230400, 460800
277 };
278 static speed_t baud_bits[] = {
279         0, B9600, B19200, B38400, B57600, B115200, B230400, B460800
280 };
281
282 /**
283  * Determine baud-rate index for CMUX command
284  */
285 static int baud_rate_index(
286         int baud_rate)
287 {
288         int i;
289         for (i = 0; i < sizeof(baud_rates) / sizeof(*baud_rates); ++i)
290                 if (baud_rates[i] == baud_rate)
291                         return i;
292         return -1;
293 }
294
295 gboolean glib_returnfalse(
296        gpointer data)
297 {
298        return FALSE;
299 }
300
301 /**
302  * Calculates frame check sequence from given characters.
303  *
304  * PARAMS:
305  * input - character array
306  * length - number of characters in array (that are included)
307  * RETURNS:
308  * frame check sequence
309  */
310 static unsigned char frame_calc_crc(
311         const unsigned char *input,
312         int length)
313 {
314         unsigned char fcs = 0xFF;
315         int i;
316         for (i = 0; i < length; i++)
317                 fcs = r_crctable[fcs ^ input[i]];
318         return 0xFF - fcs;
319 }
320
321 /**
322  * Escapes GSM0710_FRAME_ADV_ESCAPED_SYMS characters.
323  * returns escaped buffer length.
324  */
325 static int fill_adv_frame_buf(
326         unsigned char *adv_buf,
327         const unsigned char *data,
328         int length)
329 {
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)
333         {
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])
337                         {
338                                 adv_buf[adv_i] = GSM0710_FRAME_ADV_ESC;
339                                 adv_i++;
340                                 adv_buf[adv_i] = data[i] ^ GSM0710_FRAME_ADV_ESC_COPML;
341                                 break;
342                         }
343         }
344         return adv_i;
345 }
346
347 /**
348  * ascii/hexdump a byte buffer
349  */
350 static int syslogdump(
351         const char *prefix,
352         const unsigned char *ptr,
353         unsigned int length)
354 {
355         if (LOG_DEBUG>syslog_level)
356                 return 0;
357         char buffer[100];
358         unsigned int offset = 0l;
359         int i;
360         while (offset < length)
361         {
362                 int off;
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++)
368                 {
369                         if (offset + i < length)
370                                 SYSCHECK(snprintf(buffer + off, sizeof(buffer) - off, "%02x%c", ptr[offset + i], i == 7 ? '-' : ' '));
371                         else
372                                 SYSCHECK(snprintf(buffer + off, sizeof(buffer) - off, " .%c", i == 7 ? '-' : ' '));
373                         off = strlen(buffer);
374                 }
375                 SYSCHECK(snprintf(buffer + off, sizeof(buffer) - off, " "));
376                 off = strlen(buffer);
377                 for (i = 0; i < 16; i++)
378                         if (offset + i < length)
379                         {
380                                 SYSCHECK(snprintf(buffer + off, sizeof(buffer) - off, "%c", (ptr[offset + i] < ' ') ? '.' : ptr[offset + i]));
381                                 off = strlen(buffer);
382                         }
383                 offset += 16;
384                 LOG(LOG_DEBUG, "%s", buffer);
385         }
386         return 0;
387 }
388
389 /**
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.
392  *
393  * PARAMS:
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)
398  *
399  * RETURNS:
400  * number of characters written
401  */
402 static int write_frame(
403         int channel,
404         const unsigned char *input,
405         int length,
406         unsigned char type)
407 {
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;
413         int c;
414 //      char w = 0;
415 //      int count = 0;
416 //      do
417 //      {
418                 syslogdump(">s ", (unsigned char *)wakeup_sequence, sizeof(wakeup_sequence));
419                 write(serial.fd, wakeup_sequence, sizeof(wakeup_sequence));
420 //              SYSCHECK(tcdrain(serial.fd));
421 //              fd_set rfds;
422 //              FD_ZERO(&rfds);
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);
430 //              else
431 //                      count++;
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
439         prefix[2] = type;
440 //let's not use too big frames
441         length = min(cmux_N1, length);
442         if (!cmux_mode)
443         {
444 //Modified acording PATCH CRC checksum
445 //postfix[0] = frame_calc_crc (prefix + 1, prefix_length - 1);
446 //length
447                 if (length > 127)
448                 {
449                         prefix_length = 5;
450                         prefix[3] = (0x007F & length) << 1;
451                         prefix[4] = (0x7F80 & length) >> 7;
452                 }
453                 else
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)
458                 {
459                         LOG(LOG_WARNING, "Couldn't write the whole prefix to the serial port for the virtual port %d. Wrote only %d bytes",
460                                 channel, c);
461                         return 0;
462                 }
463                 if (length > 0)
464                 {
465                         c = write(serial.fd, input, length);
466                         if (length != c)
467                         {
468                                 LOG(LOG_WARNING, "Couldn't write all data to the serial port from the virtual port %d. Wrote only %d bytes",
469                                         channel, c);
470                                 return 0;
471                         }
472                 }
473                 c = write(serial.fd, postfix, 2);
474                 if (c != 2)
475                 {
476                         LOG(LOG_WARNING, "Couldn't write the whole postfix to the serial port for the virtual port %d. Wrote only %d bytes",
477                                 channel, c);
478                         return 0;
479                 }
480         }
481         else//cmux_mode
482         {
483                 int offs = 1;
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
487 //CRC checksum
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;
491                 offs++;
492                 syslogdump(">s ", (unsigned char *)serial.adv_frame_buf, offs);
493                 c = write(serial.fd, serial.adv_frame_buf, offs);
494                 if (c != offs)
495                 {
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",
497                                 channel, c);
498                         return 0;
499                 }
500         }
501         LOG(LOG_DEBUG, "Leave");
502         return length;
503 }
504
505 /*
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
510  */
511 static int handle_channel_data(
512         unsigned char *buf,
513         int len,
514         int channel)
515 {
516         int written = 0;
517         int i = 0;
518         int last = 0;
519 //try to write 5 times
520         while (written != len && i < GSM0710_WRITE_RETRIES)
521         {
522                 last = write_frame(channel, buf + written, len - written, GSM0710_TYPE_UIH);
523                 written += last;
524                 if (last == 0)
525                         i++;
526         }
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);
530         return 0;
531 }
532
533 static int logical_channel_close(Channel* channel)
534 {
535         guint timeout_id;
536         GSource *timeout_source;
537         int write_retries;
538
539         LOG(LOG_DEBUG, "Enter");
540         if (channel->opened)
541         {
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++)
544                 {
545                         if (cmux_mode)
546                                 write_frame(channel->id, NULL, 0, GSM0710_TYPE_DISC | GSM0710_PF);
547                         else
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);
551                         do
552                         {
553                                 LOG(LOG_DEBUG, "g_main_context_iteration");
554                                 g_main_context_iteration(NULL, TRUE);
555                         }
556                         while (channel->opened && !g_source_is_destroyed(timeout_source));
557                         if (!channel->opened)
558                                 break;
559                 } 
560                 /* No need to explicitly destroy this source */
561                 if (channel->opened)
562                         LOG(LOG_WARNING, "Unable to properly close a channel");
563         }
564
565         if (channel->g_source >= 0)
566                 g_source_remove(channel->g_source);
567         channel->g_source = -1;
568         if (channel->fd >= 0)
569                 close(channel->fd);
570         channel->fd = -1;
571         if (channel->ptsname != NULL)
572                 free(channel->ptsname);
573         channel->ptsname = NULL;
574         if (channel->tmp != NULL)
575                 free(channel->tmp);
576         channel->tmp = NULL;
577         if (channel->origin != NULL)
578                 free(channel->origin);
579         channel->origin = NULL;
580         channel->opened = 0;
581         channel->frames_allowed = 0;
582         channel->v24_signals = 0;
583         channel->remaining = 0;
584         return 0;
585 }
586
587 static int logical_channel_init(Channel* channel, int id)
588 {
589         channel->id = id; // connected channel-id
590         channel->devicename = id?"/dev/ptmx":NULL; // TODO do we need this to be dynamic anymore?
591         channel->fd = -1;
592         channel->g_source = -1;
593         channel->ptsname = NULL;
594         channel->tmp = NULL;
595         channel->origin = NULL;
596         channel->opened = 0;
597         return logical_channel_close(channel);
598 }
599
600 gboolean pseudo_device_read(GIOChannel *source, GIOCondition condition, gpointer data)
601 {
602         LOG(LOG_DEBUG, "Enter");
603         Channel* channel = (Channel*)data;
604         if (condition == G_IO_IN)
605         {
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)
610                 {
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");
614                         return TRUE;
615                 }
616                 if (len >= 0)
617                 {
618                         LOG(LOG_DEBUG, "Data from channel %d, %d bytes", channel->id, len);
619                         if (channel->remaining > 0)
620                         {
621                                 memcpy(buf, channel->tmp, channel->remaining);
622                                 free(channel->tmp);
623                                 channel->tmp = NULL;
624                         }
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)
629                         {
630                                 channel->tmp = malloc(channel->remaining);
631                                 memcpy(channel->tmp, buf + sizeof(buf) - channel->remaining, channel->remaining);
632                         }
633                         LOG(LOG_DEBUG, "Leave");
634                         return TRUE;
635                 }
636                 // dropped connection
637                 logical_channel_close(channel);
638         }
639         else if (condition == G_IO_HUP)
640         {
641                 logical_channel_close(channel);
642         }
643         LOG(LOG_DEBUG, "Leave");
644         return FALSE;
645 }
646
647 static gboolean watchdog(gpointer data);
648 static int close_devices();
649
650 static gboolean c_get_power(const char* origin)
651 {
652         LOG(LOG_DEBUG, "Enter");
653         LOG(LOG_DEBUG, "Leave");
654         return serial.state != MUX_STATE_OFF;
655 }
656
657 static gboolean c_set_power(const char* origin, gboolean on)
658 {
659         LOG(LOG_DEBUG, "Enter");
660         if (on)
661         {
662                 if (serial.state == MUX_STATE_OFF)
663                 {
664                         LOG(LOG_INFO, "power on");
665                         serial.state = MUX_STATE_OPENING;
666                         watchdog(&serial);
667                 }
668                 else
669                         LOG(LOG_WARNING, "power on request received but was already on");
670         }
671         else
672         {
673                 if (serial.state == MUX_STATE_MUXING)
674                 {
675                         LOG(LOG_INFO, "power off");
676                         g_source_remove(serial.g_source_watchdog);
677                         close_devices();
678                 }
679                 else
680                         LOG(LOG_WARNING, "power off received but wasn't on/muxing");
681         }
682         LOG(LOG_DEBUG, "Leave");
683         return TRUE;
684 }
685
686 static gboolean c_reset_modem(const char* origin)
687 {
688         LOG(LOG_DEBUG, "Enter");
689         LOG(LOG_INFO, "modem reset");
690         serial.state = MUX_STATE_CLOSING;                               
691         return TRUE;
692 }
693
694 static gboolean c_alloc_channel(const char* origin, const char** name)
695 {
696         LOG(LOG_DEBUG, "Enter");
697         int i;
698         guint timeout_id;
699         GSource *timeout_source;
700         int write_retries;
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?
704                         {
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"))
718                                 {
719                                         //Otherwise programs cannot access the pseudo terminals
720                                         SYSCHECK(grantpt(channellist[i].fd));
721                                         SYSCHECK(unlockpt(channellist[i].fd));
722                                 }
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++)
732                                 {
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);
736                                         do
737                                         {
738                                                 LOG(LOG_DEBUG, "g_main_context_iteration");
739                                                 g_main_context_iteration(NULL, TRUE);
740                                         }
741                                         while (!channellist[i].frames_allowed && !g_source_is_destroyed(timeout_source));
742                                         if (channellist[i].opened)
743                                                 break;
744                                 } 
745                                 /* No need to explicitly destroy this source */
746                                 if (!channellist[i].frames_allowed)
747                                 {
748                                         LOG(LOG_INFO, "Unable to open the new channel %d", i);
749                                         logical_channel_close(&channellist[i]);
750                                         return FALSE;
751                                 }
752                                 return TRUE;
753                         }
754         LOG(LOG_WARNING, "not muxing or no free channel found");
755         return TRUE;
756 }
757
758 static void my_log_handler(
759         const gchar *log_domain,
760         GLogLevelFlags log_level,
761         const gchar *message,
762         gpointer user_data)
763 {
764         LOG(LOG_INFO, "%d %s %s", log_level, log_domain, message);
765 }
766
767 #include "muxercontrol.c"
768 #include "mux-glue.h"
769
770 static int dbus_init()
771 {
772         g_log_set_handler(NULL, G_LOG_LEVEL_MASK, my_log_handler, NULL);
773         g_type_init();
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);
777         if (g_err != NULL)
778         {
779                 //g_printerr
780                 LOG(LOG_ERR, "Connecting to system bus failed: %s", g_err->message);
781                 g_error_free(g_err);
782                 return -1;
783         }
784         GObject* obj = (GObject*)muxer_control_gen();
785         DBusError err;
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)
788         {
789                 if (dbus_error_is_set(&err))
790                         LOG(LOG_ERR, "dbus error with dbus_bus_request_name '%s' '%s'", err.name, err.message);
791                 else
792                         LOG(LOG_ERR, "dbus error with dbus_bus_request_name");
793                 return -1;
794         }
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);
797         return 0;
798 }
799
800 static int dbus_deinit()
801 {
802         if (g_conn)
803                 dbus_g_connection_unref(g_conn);
804         return 0;
805 }
806
807 static int dbus_signal_send_deactivate(const char* sigvalue)
808 {
809         DBusConnection* conn = dbus_g_connection_get_connection(g_conn);
810         if (NULL == conn)
811         {
812                 LOG(LOG_ERR, "Connection null"); 
813                 return -1;
814         }
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
818         if (NULL == msg) 
819         { 
820                 LOG(LOG_ERR, "Message Null"); 
821                 return -1;
822         }
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))
826         { 
827                 LOG(LOG_ERR, "Out Of Memory"); 
828                 return -1;
829         }
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
832         { 
833                 LOG(LOG_ERR, "Out Of Memory"); 
834                 return -1;
835         }
836         dbus_connection_flush(conn);
837         // free the message 
838         dbus_message_unref(msg);
839         return 0;
840 }
841
842 /**
843         GPtrArray *table = parse("(14-5),(3-7),(4-9),(33)");
844
845         for(int i = 0; i < table->len; i++)
846         {
847                 int *arr = g_ptr_array_index(table, i);
848                 printf("(%d, %d)\n", arr[0], arr[1]);
849         }
850 */
851 GPtrArray* parse(const gchar* str)
852 {
853         GPtrArray *table = g_ptr_array_new();
854         int i = -1;
855         int first = -1;
856         int pos = 0;
857         while(str[++i] != 0)
858         {
859                 if(str[i] == '(')
860                 {
861                         pos = i+1;
862                         first = -1;
863                 }
864                 else if(str[i] == ')')
865                 {
866                         int *tuple = malloc(sizeof(int)*2);
867                         
868                         tuple[1] = atoi(str + pos);
869                         tuple[0] = first == -1 ? tuple[1] : first;
870                         
871                         g_ptr_array_add(table, (gpointer)tuple);
872                 }
873                 else if(str[i] == '-')
874                 {
875                         first = atoi(str + pos);
876                         pos = i+1;
877                 }
878         }
879         return table;
880 }
881
882 //////////////////////////////////////////////// real functions
883 /* Allocates memory for a new buffer and initializes it.
884  *
885  * RETURNS:
886  * the pointer to a new buufer
887  */
888 static GSM0710_Buffer *gsm0710_buffer_init(
889         )
890 {
891         GSM0710_Buffer* buf = (GSM0710_Buffer*)malloc(sizeof(GSM0710_Buffer));
892         if (buf)
893         {
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;
898         }
899         return buf;
900 }
901
902 /* Destroys the buffer (i.e. frees up the memory
903  *
904  * PARAMS:
905  * buf - buffer to be destroyed
906  */
907 static void gsm0710_buffer_destroy(
908         GSM0710_Buffer* buf)
909 {
910         free(buf);
911 }
912
913 /* Writes data to the buffer
914  *
915  * PARAMS
916  * buf - pointer to the buffer
917  * input - input data (in user memory)
918  * length - how many characters should be written
919  * RETURNS
920  * number of characters written
921  */
922 static int gsm0710_buffer_write(
923         GSM0710_Buffer* buf,
924         const unsigned char *input,
925         int length)
926 {
927         LOG(LOG_DEBUG, "Enter");
928         int c = buf->endp - buf->writep;
929         length = min(length, gsm0710_buffer_free(buf));
930         if (length > c)
931         {
932                 memcpy(buf->writep, input, c);
933                 memcpy(buf->data, input + c, length - c);
934                 buf->writep = buf->data + (length - c);
935         }
936         else
937         {
938                 memcpy(buf->writep, input, length);
939                 buf->writep += length;
940                 if (buf->writep == buf->endp)
941                         buf->writep = buf->data;
942         }
943         LOG(LOG_DEBUG, "Leave");
944         return length;
945 }
946
947 /**
948  * destroys a frame
949  */
950 static void destroy_frame(
951         GSM0710_Frame * frame)
952 {
953         if (frame->length > 0)
954                 free(frame->data);
955         free(frame);
956 }
957
958 /* Gets a frame from buffer. You have to remember to free this frame
959  * when it's not needed anymore
960  *
961  * PARAMS:
962  * buf - the buffer, where the frame is extracted
963  * RETURNS:
964  * frame or null, if there isn't ready frame with given index
965  */
966 static GSM0710_Frame* gsm0710_base_buffer_get_frame(
967         GSM0710_Buffer * buf)
968 {
969         int end;
970         int length_needed = 5;// channel, type, length, fcs, flag
971         unsigned char *data;
972         unsigned char fcs = 0xFF;
973         GSM0710_Frame *frame = NULL;
974 //Find start flag
975         while (!buf->flag_found && gsm0710_buffer_length(buf) > 0)
976         {
977                 if (*buf->readp == GSM0710_FRAME_FLAG)
978                         buf->flag_found = 1;
979                 gsm0710_buffer_inc(buf, buf->readp);
980         }
981         if (!buf->flag_found)// no frame started
982                 return NULL;
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))
985         {
986                 gsm0710_buffer_inc(buf, buf->readp);
987         }
988         if (gsm0710_buffer_length(buf) >= length_needed)
989         {
990                 data = buf->readp;
991                 if ((frame = (GSM0710_Frame*)malloc(sizeof(GSM0710_Frame))) != NULL)
992                 {
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];
1001                 }
1002                 else
1003                         LOG(LOG_ALERT, "Out of memory, when allocating space for frame");
1004                 if ((*data & 1) == 0)
1005                 {
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.
1010                         /*
1011                         gsm0710_buffer_inc(buf,data);
1012                         frame->length += (*data*128);
1013                         fcs = r_crctable[fcs^*data];
1014                         length_needed++;
1015                         */
1016                         free(frame);
1017                         buf->readp = data;
1018                         buf->flag_found = 0;
1019                         return gsm0710_base_buffer_get_frame(buf);
1020                 }
1021                 length_needed += frame->length;
1022                 if (!(gsm0710_buffer_length(buf) >= length_needed))
1023                 {
1024                         free(frame);
1025                         return NULL;
1026                 }
1027                 gsm0710_buffer_inc(buf, data);
1028 //extract data
1029                 if (frame->length > 0)
1030                 {
1031                         if ((frame->data = malloc(sizeof(char) * frame->length)) != NULL)
1032                         {
1033                                 end = buf->endp - data;
1034                                 if (frame->length > end)
1035                                 {
1036                                         memcpy(frame->data, data, end);
1037                                         memcpy(frame->data + end, buf->data, frame->length - end);
1038                                         data = buf->data + (frame->length - end);
1039                                 }
1040                                 else
1041                                 {
1042                                         memcpy(frame->data, data, frame->length);
1043                                         data += frame->length;
1044                                         if (data == buf->endp)
1045                                                 data = buf->data;
1046                                 }
1047                                 if (GSM0710_FRAME_IS(GSM0710_TYPE_UI, frame))
1048                                 {
1049                                         for (end = 0; end < frame->length; end++)
1050                                                 fcs = r_crctable[fcs ^ (frame->data[end])];
1051                                 }
1052                         }
1053                         else
1054                         {
1055                                 LOG(LOG_ALERT, "Out of memory, when allocating space for frame data");
1056                                 frame->length = 0;
1057                         }
1058                 }
1059 //check FCS
1060                 if (r_crctable[fcs ^ (*data)] != 0xCF)
1061                 {
1062                         LOG(LOG_WARNING, "Dropping frame: FCS doesn't match");
1063                         destroy_frame(frame);
1064                         buf->flag_found = 0;
1065                         buf->dropped_count++;
1066                         buf->readp = data;
1067                         return gsm0710_base_buffer_get_frame(buf);
1068                 }
1069                 else
1070                 {
1071 //check end flag
1072                         gsm0710_buffer_inc(buf, data);
1073                         if (*data != GSM0710_FRAME_FLAG)
1074                         {
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++;
1079                                 buf->readp = data;
1080                                 return gsm0710_base_buffer_get_frame(buf);
1081                         }
1082                         else
1083                                 buf->received_count++;
1084                         gsm0710_buffer_inc(buf, data);
1085                 }
1086                 buf->readp = data;
1087         }
1088         return frame;
1089 }
1090
1091 /* Gets a advanced option frame from buffer. You have to remember to free this frame
1092  * when it's not needed anymore
1093  *
1094  * PARAMS:
1095  * buf - the buffer, where the frame is extracted
1096  * RETURNS:
1097  * frame or null, if there isn't ready frame with given index
1098  */
1099 static GSM0710_Frame *gsm0710_advanced_buffer_get_frame(
1100         GSM0710_Buffer * buf)
1101 {
1102         LOG(LOG_DEBUG, "Enter");
1103 l_begin:
1104 //Find start flag
1105         while (!buf->flag_found && gsm0710_buffer_length(buf) > 0)
1106         {
1107                 if (*buf->readp == GSM0710_FRAME_ADV_FLAG)
1108                 {
1109                         buf->flag_found = 1;
1110                         buf->adv_length = 0;
1111                         buf->adv_found_esc = 0;
1112                 }
1113                 gsm0710_buffer_inc(buf, buf->readp);
1114         }
1115         if (!buf->flag_found)// no frame started
1116                 return NULL;
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)
1122         {
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)
1130                         {
1131                                 LOG(LOG_WARNING, "Too short adv frame, length:%d", buf->adv_length);
1132                                 buf->flag_found = 0;
1133                                 goto l_begin;
1134                         }
1135                         if ((frame = (GSM0710_Frame*)malloc(sizeof(GSM0710_Frame))) != NULL)
1136                         {
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;
1142                         }
1143                         else
1144                                 LOG(LOG_ALERT, "Out of memory, when allocating space for frame");
1145 //extract data
1146                         if (frame->length > 0)
1147                         {
1148                                 if ((frame->data = (unsigned char *) malloc(sizeof(char) * frame->length)))
1149                                 {
1150                                         memcpy(frame->data, data + 2, frame->length);
1151                                         if (GSM0710_FRAME_IS(GSM0710_TYPE_UI, frame))
1152                                         {
1153                                                 int i;
1154                                                 for (i = 0; i < frame->length; ++i)
1155                                                         fcs = r_crctable[fcs ^ (frame->data[i])];
1156                                         }
1157                                 }
1158                                 else
1159                                 {
1160                                         LOG(LOG_ALERT, "Out of memory, when allocating space for frame data");
1161                                         buf->flag_found = 0;
1162                                         goto l_begin;
1163                                 }
1164                         }
1165 //check FCS
1166                         if (r_crctable[fcs ^ data[buf->adv_length - 1]] != 0xCF)
1167                         {
1168                                 LOG(LOG_WARNING, "Dropping frame: FCS doesn't match");
1169                                 destroy_frame(frame);
1170                                 buf->flag_found = 0;
1171                                 buf->dropped_count++;
1172                                 goto l_begin;
1173                         }
1174                         else
1175                         {
1176                                 buf->received_count++;
1177                                 buf->flag_found = 0;
1178                                 LOG(LOG_DEBUG, "Leave success");
1179                                 return frame;
1180                         }
1181                 }
1182                 if (buf->adv_length >= sizeof(buf->adv_data))
1183                 {
1184                         LOG(LOG_WARNING, "Too long adv frame, length:%d", buf->adv_length);
1185                         buf->flag_found = 0;
1186                         buf->dropped_count++;
1187                         goto l_begin;
1188                 }
1189                 if (buf->adv_found_esc)
1190                 {
1191                         buf->adv_data[buf->adv_length] = *(buf->readp) ^ GSM0710_FRAME_ADV_ESC_COPML;
1192                         buf->adv_length++;
1193                         buf->adv_found_esc = 0;
1194                 }
1195                 else if (GSM0710_FRAME_ADV_ESC == *(buf->readp))
1196                         buf->adv_found_esc = 1;
1197                 else
1198                 {
1199                         buf->adv_data[buf->adv_length] = *(buf->readp);
1200                         buf->adv_length++;
1201                 }
1202                 gsm0710_buffer_inc(buf, buf->readp);
1203         }
1204         return NULL;
1205 }
1206
1207 /**
1208  * Returns 1 if found, 0 otherwise. needle must be null-terminated.
1209  * strstr might not work because WebBox sends garbage before the first
1210  * OK
1211  */
1212 static int memstr(
1213         const char *haystack,
1214         int length,
1215         const char *needle)
1216 {
1217         int i;
1218         int j = 0;
1219         if (needle[0] == '\0')
1220                 return 1;
1221         for (i = 0; i < length; i++)
1222                 if (needle[j] == haystack[i])
1223                 {
1224                         j++;
1225                         if (needle[j] == '\0') // Entire needle was found
1226                                 return 1;
1227                 }
1228                 else
1229                         j = 0;
1230         return 0;
1231 }
1232
1233 /*
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
1238  */
1239 static int chat(
1240         int serial_device_fd,
1241         char *cmd,
1242         int to)
1243 {
1244         LOG(LOG_DEBUG, "Enter");
1245         unsigned char buf[1024];
1246         int sel;
1247         int len;
1248         int wrote = 0;
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));
1253
1254         fd_set rfds;
1255         FD_ZERO(&rfds);
1256         FD_SET(serial_device_fd, &rfds);
1257         struct timeval timeout;
1258         timeout.tv_sec = to;
1259         timeout.tv_usec = 0;
1260         do
1261         {
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))
1265                 {
1266                         memset(buf, 0, sizeof(buf));
1267                         len = read(serial_device_fd, buf, sizeof(buf));
1268                         SYSCHECK(len);
1269                         LOG(LOG_DEBUG, "Read %d bytes from serial device", len);
1270                         syslogdump("<s ", buf, len);
1271                         errno = 0;
1272                         if (memstr((char *) buf, len, "OK"))
1273                         {
1274                                 LOG(LOG_DEBUG, "Received OK");
1275                                 return 0;
1276                         }
1277                         if (memstr((char *) buf, len, "ERROR"))
1278                         {
1279                                 LOG(LOG_DEBUG, "Received ERROR");
1280                                 return -1;
1281                         }
1282                 }
1283         } while (sel);
1284         return -1;
1285 }
1286
1287 /*
1288  * Handles commands received from the control channel.
1289  */
1290 static int handle_command(
1291         GSM0710_Frame * frame)
1292 {
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)
1299         {
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++);
1302                 i++;
1303                 type_length = i;
1304                 if ((type & GSM0710_CR) == GSM0710_CR)
1305                 {
1306 //command not ack extract frame length
1307                         while (frame->length > i)
1308                         {
1309                                 length = (length * 128) + ((frame->data[i] & 254) >> 1);
1310                                 if ((frame->data[i] & 1) == 1)
1311                                         break;
1312                                 i++;
1313                         }
1314                         i++;
1315                         switch ((type & ~GSM0710_CR))
1316                         {
1317                         case GSM0710_CONTROL_CLD:
1318                                 LOG(LOG_INFO, "The mobile station requested mux-mode termination");
1319                                 serial.state = MUX_STATE_CLOSING;                               
1320                                 break;
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);
1324                         break;
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;
1329                                 break;
1330                         case GSM0710_CONTROL_MSC:
1331                                 if (i + 1 < frame->length)
1332                                 {
1333                                         channel = ((frame->data[i] & 252) >> 2);
1334                                         i++;
1335                                         signals = (frame->data[i]);
1336 //op.op = USSP_MSC;
1337 //op.arg = USSP_RTS;
1338 //op.len = 0;
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");
1342                                         else
1343                                         {
1344 //op.arg |= USSP_CTS;
1345                                                 LOG(LOG_DEBUG, "Frames allowed");
1346                                                 channellist[channel].frames_allowed = 1;
1347                                         }
1348                                         if ((signals & GSM0710_SIGNAL_RTC) == GSM0710_SIGNAL_RTC)
1349                                         {
1350 //op.arg |= USSP_DSR;
1351                                                 LOG(LOG_DEBUG, "Signal RTC");
1352                                         }
1353                                         if ((signals & GSM0710_SIGNAL_IC) == GSM0710_SIGNAL_IC)
1354                                         {
1355 //op.arg |= USSP_RI;
1356                                                 LOG(LOG_DEBUG, "Signal Ring");
1357                                         }
1358                                         if ((signals & GSM0710_SIGNAL_DV) == GSM0710_SIGNAL_DV)
1359                                         {
1360 //op.arg |= USSP_DCD;
1361                                                 LOG(LOG_DEBUG, "Signal DV");
1362                                         }
1363 //if (channel > 0)
1364 //write(channellist[channel].fd, &op,
1365 //sizeof(op));
1366                                 }
1367                                 else
1368                                         LOG(LOG_ERR, "Modem status command, but no info. i: %d, len: %d, data-len: %d",
1369                                                 i, length, frame->length);
1370                                 break;
1371                         default:
1372                                 LOG(LOG_ALERT, "Unknown command (%d) from the control channel", type);
1373                                 if ((response = malloc(sizeof(char) * (2 + type_length))) != NULL)
1374                                 {
1375                                         i = 0;
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--)
1380                                         {
1381                                                 response[i] = frame->data[i - 2];
1382                                                 i++;
1383                                         }
1384                                         write_frame(0, response, i, GSM0710_TYPE_UIH);
1385                                         free(response);
1386                                         supported = 0;
1387                                 }
1388                                 else
1389                                         LOG(LOG_ALERT, "Out of memory, when allocating space for response");
1390                                 break;
1391                         }
1392                         if (supported)
1393                         {
1394 //acknowledge the command
1395                                 frame->data[0] = frame->data[0] & ~GSM0710_CR;
1396                                 write_frame(0, frame->data, frame->length, GSM0710_TYPE_UIH);
1397                         }
1398                 }
1399                 else
1400                 {
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");
1404                         else
1405                                 LOG(LOG_DEBUG, "Command acknowledged by the mobile station");
1406                 }
1407         }
1408         return 0;
1409 }
1410
1411 /*
1412  * Extracts and handles frames from the receiver buffer. PARAMS: buf
1413  * - the receiver buffer
1414  */
1415 int extract_frames(
1416         GSM0710_Buffer* buf)
1417 {
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)))
1425         {
1426                 frames_extracted++;
1427                 if ((GSM0710_FRAME_IS(GSM0710_TYPE_UI, frame) || GSM0710_FRAME_IS(GSM0710_TYPE_UIH, frame)))
1428                 {
1429                         LOG(LOG_DEBUG, "Frame is UI or UIH");
1430                         if (frame->channel > 0)
1431                         {
1432                                 gsize written;
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);
1438                                 else
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 );
1441                         }
1442                         else
1443                         {
1444 //control channel command
1445                                 LOG(LOG_DEBUG, "Frame channel == 0, control channel command");
1446                                 handle_command(frame);
1447                         }
1448                 }
1449                 else
1450                 {
1451 //not an information frame
1452                         LOG(LOG_DEBUG, "Not an information frame");
1453                         switch ((frame->control & ~GSM0710_PF))
1454                         {
1455                         case GSM0710_TYPE_UA:
1456                                 LOG(LOG_DEBUG, "Frame is UA");
1457                                 if (channellist[frame->channel].opened)
1458                                 {
1459                                         LOG(LOG_INFO, "Logical channel %d for %s closed",
1460                                                 frame->channel, channellist[frame->channel].origin);
1461                                         channellist[frame->channel].opened = 0;
1462                                 }
1463                                 else
1464                                 {
1465                                         channellist[frame->channel].opened = 1;
1466                                         if (frame->channel == 0)
1467                                         {
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);
1472                                         }
1473                                         else
1474                                                 LOG(LOG_INFO, "Logical channel %d opened", frame->channel);
1475                                 }
1476                                 break;
1477                         case GSM0710_TYPE_DM:
1478                                 if (channellist[frame->channel].opened)
1479                                 {
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);
1483                                 }
1484                                 else
1485                                 {
1486                                         if (frame->channel == 0)
1487                                         {
1488                                                 LOG(LOG_INFO, "Couldn't open control channel.\n->Terminating");
1489                                                 serial.state = MUX_STATE_CLOSING;                               
1490 //close channels
1491                                         }
1492                                         else
1493                                                 LOG(LOG_INFO, "Logical channel %d for %s couldn't be opened", frame->channel, channellist[frame->channel].origin);
1494                                 }
1495                                 break;
1496                         case GSM0710_TYPE_DISC:
1497                                 if (channellist[frame->channel].opened)
1498                                 {
1499                                         channellist[frame->channel].opened = 0;
1500                                         write_frame(frame->channel, NULL, 0, GSM0710_TYPE_UA | GSM0710_PF);
1501                                         if (frame->channel == 0)
1502                                         {
1503                                                 serial.state = MUX_STATE_CLOSING;                               
1504                                                 LOG(LOG_INFO, "Control channel closed");
1505                                         }
1506                                         else
1507                                                 LOG(LOG_INFO, "Logical channel %d for %s closed", frame->channel, channellist[frame->channel].origin);
1508                                 }
1509                                 else
1510                                 {
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);
1515                                 }
1516                                 break;
1517                         case GSM0710_TYPE_SABM:
1518 //channel open request
1519                                 if (channellist[frame->channel].opened)
1520                                 {
1521                                         if (frame->channel == 0)
1522                                                 LOG(LOG_INFO, "Control channel opened");
1523                                         else
1524                                                 LOG(LOG_INFO, "Logical channel %d for %s opened",
1525                                                         frame->channel, channellist[frame->channel].origin);
1526                                 }
1527                                 else
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);
1533                                 break;
1534                         }
1535                 }
1536                 destroy_frame(frame);
1537         }
1538         LOG(LOG_DEBUG, "Leave");
1539         return frames_extracted;
1540 }
1541
1542 /**
1543  * Function responsible by all signal handlers treatment
1544  * any new signal must be added here
1545  */
1546 void signal_treatment(
1547         int param)
1548 {
1549         switch (param)
1550         {
1551         case SIGPIPE:
1552                 exit(0);
1553         break;
1554         case SIGHUP:
1555 //reread the configuration files
1556         break;
1557         case SIGINT:
1558         case SIGTERM:
1559         case SIGUSR1:
1560                 //exit(0);
1561 //sig_term(param);
1562                 g_main_loop_quit(main_loop);
1563         break;
1564         case SIGKILL:
1565         default:
1566                 exit(0);
1567         break;
1568         }
1569 }
1570
1571 static int modem_hw_(const char* pm_base_dir, const char* entry, int on)
1572 {
1573         LOG(LOG_DEBUG, "Enter");
1574         if (pm_base_dir != NULL)
1575         {
1576                 char fn[256];
1577                 SYSCHECK(snprintf(fn, sizeof(fn), "%s/%s", pm_base_dir, entry));
1578                 LOG(LOG_DEBUG, "echo %c > %s", on?'1':'0', fn);
1579                 int fd;
1580                 SYSCHECK(fd = open(fn, O_RDWR | O_NONBLOCK));
1581                 SYSCHECK(write(fd, on?"1\n":"0\n", 2));
1582                 SYSCHECK(close(fd));
1583         }
1584         else
1585                 LOG(LOG_DEBUG, "no pm_base_dir");
1586         LOG(LOG_DEBUG, "Leave");
1587         return 0;
1588 }
1589
1590 static int modem_hw_off(const char* pm_base_dir)
1591 {
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");
1596         return 0;
1597 }
1598
1599 static int modem_hw_on(const char* pm_base_dir)
1600 {
1601         LOG(LOG_DEBUG, "Enter");
1602         SYSCHECK(modem_hw_off(pm_base_dir));
1603         sleep(1);
1604         SYSCHECK(modem_hw_(pm_base_dir, "power_on", 1));
1605         sleep(1);
1606         SYSCHECK(modem_hw_(pm_base_dir, "reset", 1));
1607         sleep(1);
1608         SYSCHECK(modem_hw_(pm_base_dir, "reset", 0));
1609         sleep(4);
1610         LOG(LOG_DEBUG, "Leave");
1611         return 0;
1612 }
1613
1614 gboolean serial_device_read(GIOChannel *source, GIOCondition condition, gpointer data)
1615 {
1616         Serial* serial = (Serial*)data;
1617         LOG(LOG_DEBUG, "Enter");
1618         if (condition == G_IO_IN)
1619         {
1620                 switch (serial->state)
1621                 {
1622                 case MUX_STATE_MUXING:
1623                 {
1624                         unsigned char buf[4096];
1625                         int len;
1626                         //input from serial port
1627                         LOG(LOG_DEBUG, "Serial Data");
1628                         int length;
1629                         if ((length = gsm0710_buffer_free(serial->in_buf)) > 0
1630                         && (len = read(serial->fd, buf, min(length, sizeof(buf)))) > 0)
1631                         {
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)
1636                                 {
1637                                         time(&serial->frame_receive_time); //get the current time
1638                                         serial->ping_number = 0;
1639                                 }
1640                         }
1641                         LOG(LOG_DEBUG, "Leave keep watching");
1642                         return TRUE;
1643                 }
1644                 break;
1645                 default:
1646                         LOG(LOG_WARNING, "Don't know how to handle reading in state %d", serial->state);
1647                 break;
1648                 }
1649         }
1650         else if (condition == G_IO_HUP)
1651         {
1652                 LOG(LOG_WARNING, "hup on serial file, closing");
1653                 serial->state = MUX_STATE_CLOSING;                              
1654         }
1655         LOG(LOG_DEBUG, "Leave stop watching");
1656         return FALSE;
1657 }
1658
1659 int open_serial_device(
1660         Serial* serial
1661         )
1662 {
1663         LOG(LOG_DEBUG, "Enter");
1664         SYSCHECK(modem_hw_on(serial->pm_base_dir));
1665         int i;
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");
1671         int fdflags;
1672         SYSCHECK(fdflags = fcntl(serial->fd, F_GETFL));
1673         SYSCHECK(fcntl(serial->fd, F_SETFL, fdflags & ~O_NONBLOCK));
1674         struct termios t;
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);
1682         t.c_cc[VMIN] = 0;
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;
1698         return 0;
1699 }
1700
1701 int start_muxer(
1702         Serial* serial
1703         )
1704 {
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)
1708         {
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);
1712                 //else
1713                         write_frame(0, close_channel_cmd, 2, GSM0710_TYPE_UIH);
1714                 SYSCHECK(chat(serial->fd, "AT\r\n", 1));
1715         }
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
1719         {
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));
1725         }
1726         //SYSCHECK(chat(serial->fd, "AT+CMUX=?\r\n", 1));
1727         if (pin_code >= 0)
1728         {
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));
1734         }
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"
1737                 //",%d,%d,%d,%d,%d"
1738                 "\r\n"
1739                 , cmux_mode
1740                 , cmux_subset
1741                 , cmux_port_speed
1742                 , cmux_N1
1743                 //, cmux_T1
1744                 //, cmux_N2
1745                 //, cmux_T2
1746                 //, cmux_T3
1747                 //, cmux_k
1748                 ));
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");
1753         sleep(1);
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);
1758         return 0;
1759 }
1760
1761 static int close_devices()
1762 {
1763         LOG(LOG_DEBUG, "Enter");
1764         g_source_remove(serial.g_source);
1765         serial.g_source = -1;
1766         int i;
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.
1770 #if 0
1771         for (i=1;i<GSM0710_MAX_CHANNELS;i++)
1772         {
1773 //terminate command given. Close channels one by one and finaly close
1774 //the mux mode
1775                 if (channellist[i].fd >= 0)
1776                 {
1777                         SYSCHECK(dbus_signal_send_deactivate(channellist[i].ptsname));
1778                         if (channellist[i].opened)
1779                         {
1780                                 LOG(LOG_INFO, "Closing down the logical channel %d", i);
1781                                 SYSCHECK(logical_channel_close(channellist+i));
1782                         }
1783                         LOG(LOG_INFO, "Logical channel %d closed", channellist[i].id);
1784                 }
1785         }
1786 #endif
1787         if (serial.fd >= 0)
1788         {
1789                 if (cmux_mode)
1790                         write_frame(0, NULL, 0, GSM0710_CONTROL_CLD | GSM0710_CR);
1791                 else
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));
1797                 serial.fd = -1;
1798         }
1799         SYSCHECK(modem_hw_off(serial.pm_base_dir));
1800         serial.state = MUX_STATE_OFF;
1801         return 0;
1802 }
1803
1804 static gboolean watchdog(gpointer data)
1805 {
1806         int i;
1807         LOG(LOG_DEBUG, "Enter");
1808         Serial* serial = (Serial*)data;
1809         LOG(LOG_DEBUG, "Serial state is %d", serial->state);
1810         switch (serial->state)
1811         {
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);
1820         break;
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);
1825                 if (use_ping)
1826                 {
1827                         if (serial->ping_number > use_ping)
1828                         {
1829                                 LOG(LOG_DEBUG, "no ping reply for %d times, resetting modem", serial->ping_number);
1830                                 serial->state = MUX_STATE_CLOSING;
1831                         }
1832                         else
1833                         {
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++;
1838                         }
1839                 }
1840                 if (use_timeout)
1841                 {
1842                         time_t current_time;
1843                         time(&current_time); //get the current time
1844                         if (current_time - serial->frame_receive_time > use_timeout)
1845                         {
1846                                 LOG(LOG_DEBUG, "timeout, resetting modem");
1847                                 serial->state = MUX_STATE_CLOSING;
1848                         }
1849                 }
1850         break;
1851         case MUX_STATE_CLOSING:
1852                 close_devices();
1853                 serial->state = MUX_STATE_OPENING;
1854         break;
1855         default:
1856                 LOG(LOG_WARNING, "Don't know how to handle state %d", serial->state);
1857         break;
1858         }
1859         return 1;
1860 }
1861
1862 /**
1863  * shows how to use this program
1864  */
1865 static int usage(
1866         char *_name)
1867 {
1868         fprintf(stdout, "Usage: %s [options]\n", _name);
1869         fprintf(stdout, "Options:\n");
1870         // process control
1871         fprintf(stdout, "\t-d: Fork, get a daemon [%s]\n", no_daemon?"no":"yes");
1872         fprintf(stdout, "\t-v: verbose logging\n");
1873         // modem control
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);
1883         //
1884         fprintf(stdout, "\t-h: Show this help message and show current settings.\n");
1885         fprintf(stdout, "\t-V: Show the version number.\n");
1886         return -1;
1887 }
1888
1889 /**
1890  * shows this program version
1891  */
1892 static int show_version(
1893         char *_name)
1894 {
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");
1905         return -1;
1906 }
1907
1908
1909 /**
1910  * The main program
1911  */
1912 int main(
1913         int argc,
1914         char *argv[],
1915         char *env[])
1916 {
1917         LOG(LOG_DEBUG, "Enter");
1918         int opt;
1919         pid_t parent_pid;
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)
1923         {
1924                 switch (opt)
1925                 {
1926                 case 'v':
1927                         syslog_level++;
1928                         break;
1929                 case 'd':
1930                         no_daemon = !no_daemon;
1931                         break;
1932                 case 'x':
1933                         serial.pm_base_dir = optarg;
1934                         break;
1935                 case 's':
1936                         serial.devicename = optarg;
1937                         break;
1938                 case 't':
1939                         use_timeout = atoi(optarg);
1940                         break;
1941                 case 'p':
1942                         use_ping = atoi(optarg);
1943                         break;
1944                 case 'P':
1945                         pin_code = atoi(optarg);
1946                         break;
1947                 // will be removed if +CMUX? works
1948                 case 'f':
1949                         cmux_N1 = atoi(optarg);
1950                         break;
1951                 case 'm':
1952                         if (!strcmp(optarg, "basic"))
1953                                 cmux_mode = 0;
1954                         else if (!strcmp(optarg, "advanced"))
1955                                 cmux_mode = 1;
1956                         else
1957                                 cmux_mode = 0;
1958                         break;
1959                 case 'b':
1960                         cmux_port_speed = baud_rate_index(atoi(optarg));
1961                         break;
1962                 case 'V':
1963                         show_version(argv[0]);
1964                         exit(0);
1965                         break;
1966                 default:
1967                 case '?':
1968                 case 'h':
1969                         usage(argv[0]);
1970                         exit(0);
1971                         break;
1972                 }
1973         }
1974         if (serial.pm_base_dir == NULL)
1975         {
1976                 // auto detect - i hate windows-like-behavior but mickey want's it ;)
1977                 struct stat sb;
1978                 int i;
1979                 static char* fn[] = {
1980                         "/sys/bus/platform/devices/neo1973-pm-gsm.0",
1981                         "/sys/bus/platform/devices/gta01-pm-gsm.0",
1982                         NULL
1983                         };
1984                 for (i=0;fn[i];i++)
1985                         if (stat(fn[i], &sb) >= 0)
1986                         {
1987                                 serial.pm_base_dir = fn[i];
1988                                 LOG(LOG_INFO, "using '%s' as basedir for pm", fn[i]);
1989                                 break;
1990                         }
1991         }
1992 //daemonize show time
1993         parent_pid = getpid();
1994         if (!no_daemon && daemon(0, 0))
1995         {
1996                 fprintf(stderr, "Failed to daemonize: %s (%d)", strerror(errno), errno);
1997                 exit(1);
1998         }
1999         umask(0);
2000 //signals treatment
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);
2007         if (no_daemon)
2008                 openlog(argv[0], LOG_NDELAY | LOG_PID | LOG_PERROR, LOG_LOCAL0);
2009         else
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)
2015         {
2016                 LOG(LOG_ALERT, "Out of memory");
2017                 exit(-1);
2018         }
2019         LOG(LOG_DEBUG, "%s %s starting", *argv, revision);
2020 //Initialize modem and virtual ports
2021         serial.state = MUX_STATE_OPENING;
2022         watchdog(&serial);
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
2036         return 0;
2037 }
2038 // vim:path=/usr/include,/usr/include/glib-2.0,/usr/include/dbus-1.0,src: