• 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-2008  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 
41 #define MS_PPP      2
42 #define MS_SUCCESS  1
43 #define MS_FAILED  -1
44 #define MS_TIMEOUT -2
45 
46 static sigjmp_buf jmp;
47 static int        retry;
48 static int        timeout;
49 
sig_alarm(int sig)50 static void sig_alarm(int sig)
51 {
52 	siglongjmp(jmp, MS_TIMEOUT);
53 }
54 
w4_str(int fd,char * str)55 static int w4_str(int fd, char *str)
56 {
57 	char buf[40];
58 	int  r, len = 0;
59 
60 	while (1) {
61 		r = read(fd, buf + len, sizeof(buf) - len - 1);
62 		if (r < 0) {
63 			if (errno == EINTR || errno == EAGAIN)
64 				continue;
65 			break;
66 		}
67 		if (!r)
68 			break;
69 
70 		len += r;
71 
72 		if (len < strlen(str))
73 			continue;
74 		buf[len] = 0;
75 
76 		if (strstr(buf, str))
77 			return MS_SUCCESS;
78 
79 		/* Detect PPP */
80 		if (strchr(buf, '~'))
81 			return MS_PPP;
82 	}
83 	return MS_FAILED;
84 }
85 
ms_server(int fd)86 static int ms_server(int fd)
87 {
88 	switch (w4_str(fd, "CLIENT")) {
89 	case MS_SUCCESS:
90 		write_n(fd, "CLIENTSERVER", 12);
91 	case MS_PPP:
92 		return MS_SUCCESS;
93 	default:
94 		return MS_FAILED;
95 	}
96 }
97 
ms_client(int fd)98 static int ms_client(int fd)
99 {
100 	write_n(fd, "CLIENT", 6);
101 	return w4_str(fd, "CLIENTSERVER");
102 }
103 
ms_dun(int fd,int server,int timeo)104 int ms_dun(int fd, int server, int timeo)
105 {
106 	sig_t osig;
107 
108 	retry    = 4;
109 	timeout  = timeo;
110 
111 	if (!server)
112 		timeout /= retry;
113 
114 	osig = signal(SIGALRM, sig_alarm);
115 
116 	while (1) {
117 		int r = sigsetjmp(jmp, 1);
118 		if (r) {
119 			if (r == MS_TIMEOUT && !server && --retry)
120 				continue;
121 
122 			alarm(0);
123 			signal(SIGALRM, osig);
124 
125 			switch (r) {
126 			case MS_SUCCESS:
127 			case MS_PPP:
128 				errno = 0;
129 				return 0;
130 
131 			case MS_FAILED:
132 				errno = EPROTO;
133 				break;
134 
135 			case MS_TIMEOUT:
136 				errno = ETIMEDOUT;
137 				break;
138 			}
139 			return -1;
140 		}
141 
142 		alarm(timeout);
143 
144 		if (server)
145 			r = ms_server(fd);
146 		else
147 			r = ms_client(fd);
148 
149 		siglongjmp(jmp, r);
150 	}
151 }
152