• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *
3  *  BlueZ - Bluetooth protocol stack for Linux
4  *
5  *  Copyright (C) 2002-2003  Maxim Krasnyansky <maxk@qualcomm.com>
6  *  Copyright (C) 2002-2010  Marcel Holtmann <marcel@holtmann.org>
7  *
8  *
9  *  This program is free software; you can redistribute it and/or modify
10  *  it under the terms of the GNU General Public License as published by
11  *  the Free Software Foundation; either version 2 of the License, or
12  *  (at your option) any later version.
13  *
14  *  This program is distributed in the hope that it will be useful,
15  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  *  GNU General Public License for more details.
18  *
19  *  You should have received a copy of the GNU General Public License
20  *  along with this program; if not, write to the Free Software
21  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
22  *
23  */
24 
25 #ifdef HAVE_CONFIG_H
26 #include <config.h>
27 #endif
28 
29 #include <stdio.h>
30 #include <errno.h>
31 #include <fcntl.h>
32 #include <unistd.h>
33 #include <stdint.h>
34 #include <stdlib.h>
35 #include <syslog.h>
36 #include <setjmp.h>
37 #include <string.h>
38 
39 #include "lib.h"
40 #include "dund.h"
41 
42 #define MS_PPP      2
43 #define MS_SUCCESS  1
44 #define MS_FAILED  -1
45 #define MS_TIMEOUT -2
46 
47 static sigjmp_buf jmp;
48 static int        retry;
49 static int        timeout;
50 
sig_alarm(int sig)51 static void sig_alarm(int sig)
52 {
53 	siglongjmp(jmp, MS_TIMEOUT);
54 }
55 
w4_str(int fd,char * str)56 static int w4_str(int fd, char *str)
57 {
58 	char buf[40];
59 	unsigned len = 0;
60 	int r;
61 
62 	while (1) {
63 		r = read(fd, buf + len, sizeof(buf) - len - 1);
64 		if (r < 0) {
65 			if (errno == EINTR || errno == EAGAIN)
66 				continue;
67 			break;
68 		}
69 		if (!r)
70 			break;
71 
72 		len += r;
73 
74 		if (len < strlen(str))
75 			continue;
76 		buf[len] = 0;
77 
78 		if (strstr(buf, str))
79 			return MS_SUCCESS;
80 
81 		/* Detect PPP */
82 		if (strchr(buf, '~'))
83 			return MS_PPP;
84 	}
85 	return MS_FAILED;
86 }
87 
ms_server(int fd)88 static int ms_server(int fd)
89 {
90 	switch (w4_str(fd, "CLIENT")) {
91 	case MS_SUCCESS:
92 		write_n(fd, "CLIENTSERVER", 12);
93 	case MS_PPP:
94 		return MS_SUCCESS;
95 	default:
96 		return MS_FAILED;
97 	}
98 }
99 
ms_client(int fd)100 static int ms_client(int fd)
101 {
102 	write_n(fd, "CLIENT", 6);
103 	return w4_str(fd, "CLIENTSERVER");
104 }
105 
ms_dun(int fd,int server,int timeo)106 int ms_dun(int fd, int server, int timeo)
107 {
108 	sig_t osig;
109 
110 	retry    = 4;
111 	timeout  = timeo;
112 
113 	if (!server)
114 		timeout /= retry;
115 
116 	osig = signal(SIGALRM, sig_alarm);
117 
118 	while (1) {
119 		int r = sigsetjmp(jmp, 1);
120 		if (r) {
121 			if (r == MS_TIMEOUT && !server && --retry)
122 				continue;
123 
124 			alarm(0);
125 			signal(SIGALRM, osig);
126 
127 			switch (r) {
128 			case MS_SUCCESS:
129 			case MS_PPP:
130 				errno = 0;
131 				return 0;
132 
133 			case MS_FAILED:
134 				errno = EPROTO;
135 				break;
136 
137 			case MS_TIMEOUT:
138 				errno = ETIMEDOUT;
139 				break;
140 			}
141 			return -1;
142 		}
143 
144 		alarm(timeout);
145 
146 		if (server)
147 			r = ms_server(fd);
148 		else
149 			r = ms_client(fd);
150 
151 		siglongjmp(jmp, r);
152 	}
153 }
154