plugins: Add O_CLOEXEC to open()
[platform/upstream/connman.git] / plugins / tist.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2011  Intel Corporation. All rights reserved.
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License version 2 as
9  *  published by the Free Software Foundation.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <errno.h>
29 #include <fcntl.h>
30 #include <unistd.h>
31 #include <string.h>
32 #include <stdint.h>
33 #include <sys/ioctl.h>
34 #include <termios.h>
35 #include <unistd.h>
36
37 #include <gdbus.h>
38
39 #define CONNMAN_API_SUBJECT_TO_CHANGE
40 #include <connman/plugin.h>
41 #include <connman/log.h>
42
43 #define TIST_SYSFS_INSTALL "/sys/devices/platform/kim/install"
44 #define TIST_SYSFS_UART "/sys/devices/platform/kim/dev_name"
45 #define TIST_SYSFS_BAUD "/sys/devices/platform/kim/baud_rate"
46
47 /* Shared transport line discipline */
48 #define N_TI_WL 22
49
50 static GIOChannel *install_channel = NULL;
51 static GIOChannel *uart_channel = NULL;
52 static char uart_dev_name[32];
53 static unsigned long baud_rate = 0;
54
55 static guint install_watch = 0;
56 static guint uart_watch = 0;
57
58 static gint install_count = 0;
59
60 #define NCCS2 19
61 struct termios2 {
62         tcflag_t c_iflag;               /* input mode flags */
63         tcflag_t c_oflag;               /* output mode flags */
64         tcflag_t c_cflag;               /* control mode flags */
65         tcflag_t c_lflag;               /* local mode flags */
66         cc_t c_line;                    /* line discipline */
67         cc_t c_cc[NCCS2];               /* control characters */
68         speed_t c_ispeed;               /* input speed */
69         speed_t c_ospeed;               /* output speed */
70 };
71
72 #define  BOTHER         0x00001000
73
74 /* HCI definitions */
75 #define HCI_HDR_OPCODE          0xff36
76 #define HCI_COMMAND_PKT         0x01
77 #define HCI_EVENT_PKT           0x04
78 #define EVT_CMD_COMPLETE        0x0E
79
80 /* HCI Command structure to set the target baud rate */
81 struct speed_change_cmd {
82         uint8_t uart_prefix;
83         uint16_t opcode;
84         uint8_t plen;
85         uint32_t speed;
86 } __attribute__ ((packed));
87
88 /* HCI Event structure to set the cusrom baud rate*/
89 struct cmd_complete {
90         uint8_t uart_prefix;
91         uint8_t evt;
92         uint8_t plen;
93         uint8_t ncmd;
94         uint16_t opcode;
95         uint8_t status;
96         uint8_t data[16];
97 } __attribute__ ((packed));
98
99 static int read_baud_rate(unsigned long *baud)
100 {
101         int err;
102         FILE *f;
103
104         DBG("");
105
106         f = fopen(TIST_SYSFS_BAUD, "r");
107         if (f == NULL)
108                 return -EIO;
109
110         err = fscanf(f, "%lu", baud);
111         fclose(f);
112
113         DBG("baud rate %lu", *baud);
114
115         return err;
116 }
117
118 static int read_uart_name(char uart_name[], size_t uart_name_len)
119 {
120         int err;
121         FILE *f;
122
123         DBG("");
124
125         memset(uart_name, 0, uart_name_len);
126
127         f = fopen(TIST_SYSFS_UART, "r");
128         if (f == NULL)
129                 return -EIO;
130
131         err = fscanf(f, "%s", uart_name);
132         fclose(f);
133
134         DBG("UART name %s", uart_name);
135
136         return err;
137 }
138
139 static int read_hci_event(int fd, unsigned char *buf, int size)
140 {
141         int prefix_len, param_len;
142
143         if (size <= 0)
144                 return -EINVAL;
145
146         /* First 3 bytes are prefix, event and param length */
147         prefix_len = read(fd, buf, 3);
148         if (prefix_len < 0)
149                 return prefix_len;
150
151         if (prefix_len < 3) {
152                 connman_error("Truncated HCI prefix %d bytes 0x%x",
153                                                 prefix_len, buf[0]);
154                 return -EIO;
155         }
156
157         DBG("type 0x%x event 0x%x param len %d", buf[0], buf[1], buf[2]);
158
159         param_len = buf[2];
160         if (param_len > size - 3) {
161                 connman_error("Buffer is too small %d", size);
162                 return -EINVAL;
163         }
164
165         return read(fd, buf + 3, param_len);
166 }
167
168 static int read_command_complete(int fd, unsigned short opcode)
169 {
170         struct cmd_complete resp;
171         int err;
172
173         DBG("");
174
175         err = read_hci_event(fd, (unsigned char *)&resp, sizeof(resp));
176         if (err < 0)
177                 return err;
178
179         DBG("HCI event %d bytes", err);
180
181         if (resp.uart_prefix != HCI_EVENT_PKT) {
182                 connman_error("Not an event packet");
183                 return -EIO;
184         }
185
186         if (resp.evt != EVT_CMD_COMPLETE) {
187                 connman_error("Not a cmd complete event");
188                 return -EIO;
189         }
190
191         if (resp.plen < 4) {
192                 connman_error("HCI header length %d", resp.plen);
193                 return -EIO;
194         }
195
196         if (resp.opcode != (unsigned short) opcode) {
197                 connman_error("opcode 0x%04x 0x%04x", resp.opcode, opcode);
198                 return -EIO;
199         }
200
201         return 0;
202 }
203
204 /* The default baud rate is 115200 */
205 static int set_default_baud_rate(int fd)
206 {
207         struct termios ti;
208         int err;
209
210         DBG("");
211
212         err = tcflush(fd, TCIOFLUSH);
213         if (err < 0)
214                 goto err;
215
216         err = tcgetattr(fd, &ti);
217         if (err < 0)
218                 goto err;
219
220         cfmakeraw(&ti);
221
222         ti.c_cflag |= 1;
223         ti.c_cflag |= CRTSCTS;
224
225         err = tcsetattr(fd, TCSANOW, &ti);
226         if (err < 0)
227                 goto err;
228
229         cfsetospeed(&ti, B115200);
230         cfsetispeed(&ti, B115200);
231
232         err = tcsetattr(fd, TCSANOW, &ti);
233         if (err < 0)
234                 goto err;
235
236         err = tcflush(fd, TCIOFLUSH);
237         if (err < 0)
238                 goto err;
239
240         return 0;
241
242 err:
243         connman_error("%s", strerror(errno));
244
245         return err;
246 }
247
248 static int set_custom_baud_rate(int fd, unsigned long cus_baud_rate, int flow_ctrl)
249 {
250         struct termios ti;
251         struct termios2 ti2;
252         int err;
253
254         DBG("baud rate %lu flow_ctrl %d", cus_baud_rate, flow_ctrl);
255
256         err = tcflush(fd, TCIOFLUSH);
257         if (err < 0)
258                 goto err;
259
260         err = tcgetattr(fd, &ti);
261         if (err < 0)
262                 goto err;
263
264         if (flow_ctrl)
265                 ti.c_cflag |= CRTSCTS;
266         else
267                 ti.c_cflag &= ~CRTSCTS;
268
269         /*
270          * Set the parameters associated with the UART
271          * The change will occur immediately by using TCSANOW.
272          */
273         err = tcsetattr(fd, TCSANOW, &ti);
274         if (err < 0)
275                 goto err;
276
277         err = tcflush(fd, TCIOFLUSH);
278         if (err < 0)
279                 goto err;
280
281         /* Set the actual baud rate */
282         err = ioctl(fd, TCGETS2, &ti2);
283         if (err < 0)
284                 goto err;
285
286         ti2.c_cflag &= ~CBAUD;
287         ti2.c_cflag |= BOTHER;
288         ti2.c_ospeed = cus_baud_rate;
289
290         err = ioctl(fd, TCSETS2, &ti2);
291         if (err < 0)
292                 goto err;
293
294         return 0;
295
296 err:
297         DBG("%s", strerror(errno));
298
299         return err;
300 }
301
302 static gboolean uart_event(GIOChannel *channel,
303                                 GIOCondition cond, gpointer data)
304 {
305         int uart_fd, ldisc;
306
307         DBG("");
308
309         uart_fd = g_io_channel_unix_get_fd(channel);
310
311         if (cond & (G_IO_NVAL | G_IO_HUP | G_IO_ERR)) {
312                 connman_error("UART event 0x%x", cond);
313                 if (uart_watch > 0)
314                         g_source_remove(uart_watch);
315
316                 goto err;
317         }
318
319         if (read_command_complete(uart_fd, HCI_HDR_OPCODE) < 0)
320                 goto err;
321
322         if (set_custom_baud_rate(uart_fd, baud_rate, 1) < 0)
323                 goto err;
324
325         ldisc = N_TI_WL;
326         if (ioctl(uart_fd, TIOCSETD, &ldisc) < 0)
327                 goto err;
328
329         g_atomic_int_set(&install_count, 0);
330
331         return FALSE;
332
333 err:
334         g_atomic_int_set(&install_count, 0);
335         g_io_channel_shutdown(channel, TRUE, NULL);
336         g_io_channel_unref(channel);
337
338         return FALSE;
339 }
340
341 static int install_ldisc(GIOChannel *channel, gboolean install)
342 {
343         int uart_fd, err;
344         struct speed_change_cmd cmd;
345         GIOFlags flags;
346
347         DBG("%d %p", install, uart_channel);
348
349         if (install == FALSE) {
350                 g_atomic_int_set(&install_count, 0);
351
352                 if (uart_channel == NULL) {
353                         DBG("UART channel is NULL");
354                         return 0;
355                 }
356
357                 g_io_channel_shutdown(uart_channel, TRUE, NULL);
358                 g_io_channel_unref(uart_channel);
359
360                 uart_channel = NULL;
361
362                 return 0;
363         }
364
365         if (uart_channel != NULL) {
366                 g_io_channel_shutdown(uart_channel, TRUE, NULL);
367                 g_io_channel_unref(uart_channel);
368                 uart_channel = NULL;
369         }
370
371         DBG("opening %s custom baud %lu", uart_dev_name, baud_rate);
372         
373         uart_fd = open(uart_dev_name, O_RDWR | O_CLOEXEC);
374         if (uart_fd < 0)
375                 return -EIO;
376
377         uart_channel = g_io_channel_unix_new(uart_fd);  
378         g_io_channel_set_close_on_unref(uart_channel, TRUE);
379
380         g_io_channel_set_encoding(uart_channel, NULL, NULL);
381         g_io_channel_set_buffered(uart_channel, FALSE);
382
383         flags = g_io_channel_get_flags(uart_channel);
384         flags |= G_IO_FLAG_NONBLOCK;
385         g_io_channel_set_flags(uart_channel, flags, NULL);
386
387         err = set_default_baud_rate(uart_fd);
388         if (err < 0) {
389                 g_io_channel_shutdown(uart_channel, TRUE, NULL);
390                 g_io_channel_unref(uart_channel);
391                 uart_channel = NULL;
392
393                 return err;
394         }
395
396         if (baud_rate == 115200) {
397                 int ldisc;
398
399                 ldisc = N_TI_WL;
400                 if (ioctl(uart_fd, TIOCSETD, &ldisc) < 0) {
401                         g_io_channel_shutdown(uart_channel, TRUE, NULL);
402                         g_io_channel_unref(uart_channel);
403                         uart_channel = NULL;
404                 }
405
406                 g_atomic_int_set(&install_count, 0);
407
408                 return 0;
409         }
410
411         cmd.uart_prefix = HCI_COMMAND_PKT;
412         cmd.opcode = HCI_HDR_OPCODE;
413         cmd.plen = sizeof(unsigned long);
414         cmd.speed = baud_rate;
415
416         uart_watch = g_io_add_watch(uart_channel,
417                         G_IO_IN | G_IO_NVAL | G_IO_HUP | G_IO_ERR,
418                                 uart_event, NULL);
419
420         err = write(uart_fd, &cmd, sizeof(cmd));
421         if (err < 0) {
422                 connman_error("Write failed %d", err);
423
424                 g_io_channel_shutdown(uart_channel, TRUE, NULL);
425                 g_io_channel_unref(uart_channel);
426                 uart_channel = NULL;
427         }
428
429         return err;
430 }
431
432
433 static gboolean install_event(GIOChannel *channel,
434                                 GIOCondition cond, gpointer data)
435 {
436         GIOStatus status = G_IO_STATUS_NORMAL;
437         unsigned int install_state;
438         gboolean install;
439         char buf[8];
440         gsize len;
441
442         DBG("");
443
444         if (cond & (G_IO_HUP | G_IO_NVAL)) {
445                 connman_error("install event 0x%x", cond);
446                 return FALSE;
447         }
448
449         if (g_atomic_int_get(&install_count) != 0) {
450                 status = g_io_channel_seek_position(channel, 0, G_SEEK_SET, NULL);
451                 if (status != G_IO_STATUS_NORMAL) {
452                         g_io_channel_shutdown(channel, TRUE, NULL);
453                         g_io_channel_unref(channel);
454                         return FALSE;
455                 }
456
457                 /* Read the install value */
458                 status = g_io_channel_read_chars(channel, (gchar *) buf, 8, &len, NULL);
459                 if (status != G_IO_STATUS_NORMAL) {
460                         g_io_channel_shutdown(channel, TRUE, NULL);
461                         g_io_channel_unref(channel);
462                         return FALSE;
463                 }
464
465                 install_state = atoi(buf);
466                 DBG("install event while installing %d %c", install_state, buf[0]);
467
468                 return TRUE;
469         } else {
470                 g_atomic_int_set(&install_count, 1);
471         }
472
473         status = g_io_channel_seek_position(channel, 0, G_SEEK_SET, NULL);
474         if (status != G_IO_STATUS_NORMAL) {
475                 g_io_channel_shutdown(channel, TRUE, NULL);
476                 g_io_channel_unref(channel);
477                 return FALSE;
478         }
479
480         /* Read the install value */
481         status = g_io_channel_read_chars(channel, (gchar *) buf, 8, &len, NULL);
482         if (status != G_IO_STATUS_NORMAL) {
483                 g_io_channel_shutdown(channel, TRUE, NULL);
484                 g_io_channel_unref(channel);
485                 return FALSE;
486         }
487
488         install_state = atoi(buf);
489
490         DBG("install state %d", install_state);
491
492         install = !!install_state;
493
494         if (install_ldisc(channel, install) < 0) {
495                 connman_error("ldisc installation failed");
496                 g_atomic_int_set(&install_count, 0);
497                 return TRUE;
498         }
499
500         return TRUE;
501 }
502
503
504 static int tist_init(void)
505 {
506         GIOStatus status = G_IO_STATUS_NORMAL;
507         GIOFlags flags;
508         unsigned int install_state;
509         char buf[8];
510         int fd, err;
511         gsize len;
512
513         err = read_uart_name(uart_dev_name, sizeof(uart_dev_name));
514         if (err < 0) {
515                 connman_error("Could not read the UART name");
516                 return err;
517         }
518
519         err = read_baud_rate(&baud_rate);
520         if (err < 0) {
521                 connman_error("Could not read the baud rate");
522                 return err;
523         }
524
525         fd = open(TIST_SYSFS_INSTALL, O_RDONLY | O_CLOEXEC);
526         if (fd < 0) {
527                 connman_error("Failed to open TI ST sysfs install file");
528                 return -EIO;
529         }
530
531         install_channel = g_io_channel_unix_new(fd);
532         g_io_channel_set_close_on_unref(install_channel, TRUE);
533
534         g_io_channel_set_encoding(install_channel, NULL, NULL);
535         g_io_channel_set_buffered(install_channel, FALSE);
536
537         flags = g_io_channel_get_flags(install_channel);
538         flags |= G_IO_FLAG_NONBLOCK;
539         g_io_channel_set_flags(install_channel, flags, NULL);
540
541         status = g_io_channel_read_chars(install_channel, (gchar *) buf, 8,
542                                                                 &len, NULL);
543         if (status != G_IO_STATUS_NORMAL) {
544                 g_io_channel_shutdown(install_channel, TRUE, NULL);
545                 g_io_channel_unref(install_channel);
546                 return status;
547         }
548
549         status = g_io_channel_seek_position(install_channel, 0, G_SEEK_SET, NULL);
550         if (status != G_IO_STATUS_NORMAL) {
551                 connman_error("Initial seek failed");
552                 g_io_channel_shutdown(install_channel, TRUE, NULL);
553                 g_io_channel_unref(install_channel);
554                 return -EIO;
555         }
556
557         install_state = atoi(buf);
558
559         DBG("Initial state %d", install_state);
560
561         install_watch = g_io_add_watch_full(install_channel, G_PRIORITY_HIGH,
562                                 G_IO_PRI | G_IO_ERR,
563                                             install_event, NULL, NULL);
564
565         if (install_state) {
566                 g_atomic_int_set(&install_count, 1);
567                 err = install_ldisc(install_channel, TRUE);
568                 if (err < 0) {
569                         connman_error("ldisc installtion failed");
570                         return err;
571                 }
572         }
573
574         return 0;
575 }
576
577
578 static void tist_exit(void)
579 {
580
581         if (install_watch > 0)
582                 g_source_remove(install_watch);
583
584         DBG("uart_channel %p", uart_channel);
585
586         g_io_channel_shutdown(install_channel, TRUE, NULL);
587         g_io_channel_unref(install_channel);
588
589         if (uart_channel != NULL) {
590                 g_io_channel_shutdown(uart_channel, TRUE, NULL);
591                 g_io_channel_unref(uart_channel);
592                 uart_channel = NULL;
593         }
594
595 }
596
597 CONNMAN_PLUGIN_DEFINE(tist, "TI shared transport support", VERSION,
598                 CONNMAN_PLUGIN_PRIORITY_DEFAULT, tist_init, tist_exit)