summaryrefslogtreecommitdiffstats
path: root/bluetooth.h
blob: 7dcec13cd558c4982d34d7ba15b54f50689ea11b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
#ifndef BLUETOOTH_H
#define BLUETTOTH_H

#include <bluetooth/bluetooth.h>
#include <bluetooth/l2cap.h>
#include <bluetooth/hci.h>
#include <bluetooth/hci_lib.h>

#include <sys/socket.h>
#include <sys/types.h>
#include <grp.h>

int controlSock, dataSock;

/* Well known PSMs (aka defined by spec) are restricted to CAP_NET_BIND_SERVICE
 * non-priviledged process can bind only to dynamic PSMs (>= 0x1001)"
 */

#define CONTROL 0x11
#define DATA 0x13

#define MAX 40


int set_flush_timeout(bdaddr_t *ba, int timeout)
	{
	int ret = 0, device;
	struct hci_conn_info_req *connection_handle = 0;
	struct hci_request rq = {0};

	struct {
	uint16_t handle;
	uint16_t flush_timeout;
	} cmd_param;

	struct {
	uint8_t status;
	uint16_t handle;
	} cmd_response;

	/* find the connection handle to the specified bluetooth device */
	connection_handle = (struct hci_conn_info_req*) malloc(sizeof(struct hci_conn_info_req) + sizeof(struct hci_conn_info));
	if (!connection_handle){fprintf(stderr, "Malloc failed!\n"); exit(1);}

	bacpy(&connection_handle->bdaddr, ba);
	connection_handle->type = ACL_LINK;
	device = hci_open_dev(hci_get_route(&connection_handle->bdaddr));
	if(device < 0)
		{
		ret = device;
		goto cleanup;
		}
	ret = ioctl(device, HCIGETCONNINFO, (unsigned long) connection_handle);
	if (ret){goto cleanup;}

	/* build a command packet to send to the bluetooth microcontroller */
	cmd_param.handle = connection_handle->conn_info->handle;
	cmd_param.flush_timeout = htobs(timeout);
	rq.ogf = OGF_HOST_CTL;
	rq.ocf = 0x28;
	rq.cparam = &cmd_param;
	rq.clen = sizeof(cmd_param);
	rq.rparam = &cmd_response;
	rq.rlen = sizeof(cmd_response);
	rq.event = EVT_CMD_COMPLETE;

	/* send the command and wait for the response */
	ret = hci_send_req(device, &rq, 0);
	if (ret){goto cleanup;}

	if (cmd_response.status)
		{
		ret = -1;
		errno = bt_error(cmd_response.status);
		}

	cleanup:
	free(connection_handle);
	if (device >= 0){close(device);}
	return ret;
}

bdaddr_t findBluetooth()
	{
	int device_id = hci_get_route(NULL);
	int hci_sock = hci_open_dev(device_id);
	if (device_id < 0 || hci_sock < 0)
		{
		perror("opening socket");
		exit(1);
		}

	int max_rsp = 255;
	inquiry_info *scan_info = (inquiry_info*)malloc(max_rsp * sizeof(inquiry_info));
	if (!scan_info){fprintf(stderr,"Malloc failed!\n"); exit(1);}

	int timeout = 8;
	int num_rsp = hci_inquiry(device_id, timeout, max_rsp, NULL, &scan_info, IREQ_CACHE_FLUSH);
	if (num_rsp < 0){perror("hci_inquiry"); exit(1);}

	int i = 0;
	for (i = 0; i < num_rsp; ++i)
		{
		if ((scan_info[i].dev_class[0] == 0x04) && (scan_info[i].dev_class[1] == 0x01) && (scan_info[i].dev_class[2] == 0x10))//match up with class of server...
			{
			printf("Found device\n");
			//we're done
			break;
			}
		else
			{
			printf("Non matching class: %d, %d, %d\n",scan_info[i].dev_class[0],scan_info[i].dev_class[1],scan_info[i].dev_class[2]);
			}
		}
	if (i == num_rsp)
		{
		fprintf(stderr,"Device not found in hci search!\n");
		exit(1);
		}

	char addr[19];
	ba2str(&(scan_info+i)->bdaddr, addr);
	addr[18] = '\0';
	printf("%s\n",addr);

	hci_close_dev(device_id);

	return (scan_info+i)->bdaddr;
	}


int connectPSM(int port)
	{
	struct sockaddr_l2 addr = {0}, remote_addr = {0};
	int sock = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
	if (sock < 0){fprintf(stderr,"Opening control socket failed!\n"); return 0;}

	socklen_t opt = sizeof(remote_addr);

	/* set the socket timeout  (not accepted...)*/
	/*
	struct timeval tv;
	tv.tv_sec = 1;
	tv.tv_usec = 0;
	setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof tv);
	*/

	/* set the connection parameters (who to connect to) */
	addr.l2_psm = htobs(port);
	bacpy(&addr.l2_bdaddr, BDADDR_ANY);//accept any "server"
	addr.l2_family = AF_BLUETOOTH;

	/* bind to address */
	int result = bind(sock, (struct sockaddr *)&addr, sizeof(addr));
	if (result < 0){fprintf(stderr,"Bind failed with error: %d & %s!\n", result, strerror(errno)); return 0;}

	/* listen for connections */
	result = listen(sock, 1);
	if (result < 0){fprintf(stderr,"Listen failed!\n"); return 0;}

	/* The sockfd that accept() returns is our IO pipe */
	int io = accept(sock, (struct sockaddr *)&remote_addr, &opt);
	if (result < 0){fprintf(stderr,"Failed to accept connection to control pipe!: "); perror(""); return 0;}


	char buff[19];
	ba2str(&remote_addr.l2_bdaddr, buff);
	printf("Accepted connection from: %s\n", buff);

	return io;
	}


int connectBluetooth(bdaddr_t address)
	{
	int device_id = hci_get_route(NULL);
	int hci_sock = hci_open_dev(device_id);//todo: close when done
	if (device_id < 0 || hci_sock < 0){fprintf(stderr,"Could not open device!\n"); return 0;}

	/* Set device class to that of a wiimote */
	if (hci_write_class_of_dev(hci_sock, 0x002504, 2000) < 0)
		{
		fprintf(stderr, "Can't write device class to device. Errno: %d, Err: %s\n", errno, strerror(errno));
		return 0;
		}

/*
	unsigned int ptype = HCI_DM1 | HCI_DM3 | HCI_DM5 | HCI_DH1 | HCI_DH3 | HCI_DH5;
	uint16_t handle;

	if (hci_create_connection(hci_sock, &address, htobs(ptype), 0, 0, &handle, 0) < 0)
		{
		perror("HCI create connection failed");
		close(hci_sock);
		return 0;
		}
*/

	// Authenticate HCI link (without pin)
	/*
	if (hci_authenticate_link(hci_sock, handle, 0) < 0)
		{
		perror("HCI authentication failed");
		close(hci_sock);
		return 0;
		}
	*/

	controlSock = connectPSM(CONTROL);
	if (!controlSock){return 0;}

	dataSock = connectPSM(DATA);
	if (!dataSock){return 0;}


	/* drop root privs (nobody for now as getting the uid & gid from a name is messy) */
	if (setgid(65534) != 0){fprintf(stderr,"Unable to drop group privileges!\n"); exit(1);}
	if (setgroups(0, NULL) != 0){fprintf(stderr,"Unable to drop groups privileges!\n"); exit(1);} //We don't need any groups really
	if (setuid(65534) != 0){fprintf(stderr,"Unable to drop user privileges!\n"); exit(1);}

	/* paranoia check*/
	if (setuid(0) != -1){fprintf(stderr,"Managed to regain root privileges?\n"); exit(1);}

	return 1;
	}

void sdp()
	{
	//todo
	}

#endif