Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/usr.sbin/bluetooth/btpand/client.c
104186 views
1
/* $NetBSD: client.c,v 1.2 2008/12/06 20:01:14 plunky Exp $ */
2
3
/*-
4
* SPDX-License-Identifier: BSD-2-Clause
5
*
6
* Copyright (c) 2008 Iain Hibbert
7
* All rights reserved.
8
*
9
* Redistribution and use in source and binary forms, with or without
10
* modification, are permitted provided that the following conditions
11
* are met:
12
* 1. Redistributions of source code must retain the above copyright
13
* notice, this list of conditions and the following disclaimer.
14
* 2. Redistributions in binary form must reproduce the above copyright
15
* notice, this list of conditions and the following disclaimer in the
16
* documentation and/or other materials provided with the distribution.
17
*
18
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
*/
29
30
31
#include <sys/cdefs.h>
32
__RCSID("$NetBSD: client.c,v 1.2 2008/12/06 20:01:14 plunky Exp $");
33
34
#define L2CAP_SOCKET_CHECKED
35
#include <bluetooth.h>
36
#include <errno.h>
37
#include <sdp.h>
38
#include <unistd.h>
39
40
#include "btpand.h"
41
#include "bnep.h"
42
#include "sdp.h"
43
44
static void client_query(void);
45
46
void
47
client_init(void)
48
{
49
struct sockaddr_l2cap sa;
50
channel_t *chan;
51
socklen_t len;
52
int fd, n;
53
uint16_t mru, mtu;
54
55
if (bdaddr_any(&remote_bdaddr))
56
return;
57
58
if (service_name)
59
client_query();
60
61
fd = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BLUETOOTH_PROTO_L2CAP);
62
if (fd == -1) {
63
log_err("Could not open L2CAP socket: %m");
64
exit(EXIT_FAILURE);
65
}
66
67
memset(&sa, 0, sizeof(sa));
68
sa.l2cap_family = AF_BLUETOOTH;
69
sa.l2cap_len = sizeof(sa);
70
sa.l2cap_bdaddr_type = BDADDR_BREDR;
71
sa.l2cap_cid = 0;
72
73
bdaddr_copy(&sa.l2cap_bdaddr, &local_bdaddr);
74
if (bind(fd, (struct sockaddr *)&sa, sizeof(sa)) == -1) {
75
log_err("Could not bind client socket: %m");
76
exit(EXIT_FAILURE);
77
}
78
79
mru = BNEP_MTU_MIN;
80
if (setsockopt(fd, SOL_L2CAP, SO_L2CAP_IMTU, &mru, sizeof(mru)) == -1) {
81
log_err("Could not set L2CAP IMTU (%d): %m", mru);
82
exit(EXIT_FAILURE);
83
}
84
85
log_info("Opening connection to service 0x%4.4x at %s",
86
service_class, bt_ntoa(&remote_bdaddr, NULL));
87
88
sa.l2cap_psm = htole16(l2cap_psm);
89
bdaddr_copy(&sa.l2cap_bdaddr, &remote_bdaddr);
90
if (connect(fd, (struct sockaddr *)&sa, sizeof(sa)) == -1) {
91
log_err("Could not connect: %m");
92
exit(EXIT_FAILURE);
93
}
94
95
len = sizeof(mru);
96
if (getsockopt(fd, SOL_L2CAP, SO_L2CAP_IMTU, &mru, &len) == -1) {
97
log_err("Could not get IMTU: %m");
98
exit(EXIT_FAILURE);
99
}
100
if (mru < BNEP_MTU_MIN) {
101
log_err("L2CAP IMTU too small (%d)", mru);
102
exit(EXIT_FAILURE);
103
}
104
105
len = sizeof(n);
106
if (getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &n, &len) == -1) {
107
log_err("Could not read SO_RCVBUF");
108
exit(EXIT_FAILURE);
109
}
110
if (n < (mru * 10)) {
111
n = mru * 10;
112
if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &n, sizeof(n)) == -1)
113
log_info("Could not increase SO_RCVBUF (from %d)", n);
114
}
115
116
len = sizeof(mtu);
117
if (getsockopt(fd, SOL_L2CAP, SO_L2CAP_OMTU, &mtu, &len) == -1) {
118
log_err("Could not get L2CAP OMTU: %m");
119
exit(EXIT_FAILURE);
120
}
121
if (mtu < BNEP_MTU_MIN) {
122
log_err("L2CAP OMTU too small (%d)", mtu);
123
exit(EXIT_FAILURE);
124
}
125
126
len = sizeof(n);
127
if (getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &n, &len) == -1) {
128
log_err("Could not get socket send buffer size: %m");
129
close(fd);
130
return;
131
}
132
if (n < (mtu * 2)) {
133
n = mtu * 2;
134
if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &n, sizeof(n)) == -1) {
135
log_err("Could not set socket send buffer size (%d): %m", n);
136
close(fd);
137
return;
138
}
139
}
140
n = mtu;
141
if (setsockopt(fd, SOL_SOCKET, SO_SNDLOWAT, &n, sizeof(n)) == -1) {
142
log_err("Could not set socket low water mark (%d): %m", n);
143
close(fd);
144
return;
145
}
146
147
chan = channel_alloc();
148
if (chan == NULL)
149
exit(EXIT_FAILURE);
150
151
chan->send = bnep_send;
152
chan->recv = bnep_recv;
153
chan->mru = mru;
154
chan->mtu = mtu;
155
b2eaddr(chan->raddr, &remote_bdaddr);
156
b2eaddr(chan->laddr, &local_bdaddr);
157
chan->state = CHANNEL_WAIT_CONNECT_RSP;
158
channel_timeout(chan, 10);
159
if (!channel_open(chan, fd))
160
exit(EXIT_FAILURE);
161
162
bnep_send_control(chan, BNEP_SETUP_CONNECTION_REQUEST,
163
2, service_class, SDP_SERVICE_CLASS_PANU);
164
}
165
166
static void
167
client_query(void)
168
{
169
uint8_t buffer[512];
170
sdp_attr_t attr;
171
uint32_t range;
172
void *ss;
173
int rv;
174
uint8_t *seq0, *seq1;
175
176
attr.flags = SDP_ATTR_INVALID;
177
attr.attr = 0;
178
attr.vlen = sizeof(buffer);
179
attr.value = buffer;
180
181
range = SDP_ATTR_RANGE(SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST,
182
SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST);
183
184
ss = sdp_open(&local_bdaddr, &remote_bdaddr);
185
if (ss == NULL || (errno = sdp_error(ss)) != 0) {
186
log_err("%s: %m", service_name);
187
exit(EXIT_FAILURE);
188
}
189
190
log_info("Searching for %s service at %s",
191
service_name, bt_ntoa(&remote_bdaddr, NULL));
192
193
rv = sdp_search(ss, 1, &service_class, 1, &range, 1, &attr);
194
if (rv != 0) {
195
log_err("%s: %s", service_name, strerror(sdp_error(ss)));
196
exit(EXIT_FAILURE);
197
}
198
199
sdp_close(ss);
200
201
if (attr.flags != SDP_ATTR_OK
202
|| attr.attr != SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST) {
203
log_err("%s service not found", service_name);
204
exit(EXIT_FAILURE);
205
}
206
207
/*
208
* we expect the following protocol descriptor list
209
*
210
* seq len
211
* seq len
212
* uuid value == L2CAP
213
* uint16 value16 => PSM
214
* seq len
215
* uuid value == BNEP
216
*/
217
if (_sdp_get_seq(&attr.value, attr.value + attr.vlen, &seq0)
218
&& _sdp_get_seq(&seq0, attr.value, &seq1)
219
&& _sdp_match_uuid16(&seq1, seq0, SDP_UUID_PROTOCOL_L2CAP)
220
&& _sdp_get_uint16(&seq1, seq0, &l2cap_psm)
221
&& _sdp_get_seq(&seq0, attr.value, &seq1)
222
&& _sdp_match_uuid16(&seq1, seq0, SDP_UUID_PROTOCOL_BNEP)) {
223
log_info("Found PSM %d for service %s", l2cap_psm, service_name);
224
return;
225
}
226
227
log_err("%s query failed", service_name);
228
exit(EXIT_FAILURE);
229
}
230
231