1 /* $NetBSD: server.c,v 1.2 2009/01/24 17:29:28 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: server.c,v 1.2 2009/01/24 17:29:28 plunky Exp $"); 33 34 #include <sys/ioctl.h> 35 36 #define L2CAP_SOCKET_CHECKED 37 #include <bluetooth.h> 38 #include <inttypes.h> 39 #include <errno.h> 40 #include <sdp.h> 41 #include <unistd.h> 42 43 #include "btpand.h" 44 #include "bnep.h" 45 46 static struct event server_ev; 47 static int server_fd; 48 static int server_avail; 49 50 static void * server_ss; 51 static uint32_t server_handle; 52 53 static void server_open(void); 54 static void server_close(void); 55 static void server_read(int, short, void *); 56 static void server_register(void); 57 58 void 59 server_init(void) 60 { 61 62 server_fd = -1; 63 } 64 65 /* 66 * The server_update() function is called whenever the channel count is 67 * changed. We maintain the SDP record and open or close the server socket 68 * as required. 69 */ 70 void 71 server_update(int count) 72 { 73 74 if (server_limit == 0) 75 return; 76 77 log_debug("count %d", count); 78 79 server_avail = UINT8_MAX - (count - 1) * UINT8_MAX / server_limit; 80 log_info("Service Availability: %d/%d", server_avail, UINT8_MAX); 81 82 if (server_avail == 0 && server_fd != -1) 83 server_close(); 84 85 if (server_avail > 0 && server_fd == -1) 86 server_open(); 87 88 if (service_name) 89 server_register(); 90 } 91 92 static void 93 server_open(void) 94 { 95 struct sockaddr_l2cap sa; 96 uint16_t mru; 97 98 server_fd = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BLUETOOTH_PROTO_L2CAP); 99 if (server_fd == -1) { 100 log_err("Could not open L2CAP socket: %m"); 101 exit(EXIT_FAILURE); 102 } 103 104 memset(&sa, 0, sizeof(sa)); 105 sa.l2cap_family = AF_BLUETOOTH; 106 sa.l2cap_len = sizeof(sa); 107 sa.l2cap_psm = htole16(l2cap_psm); 108 sa.l2cap_bdaddr_type = BDADDR_BREDR; 109 sa.l2cap_cid = 0; 110 111 bdaddr_copy(&sa.l2cap_bdaddr, &local_bdaddr); 112 if (bind(server_fd, (struct sockaddr *)&sa, sizeof(sa)) == -1) { 113 log_err("Could not bind server socket: %m"); 114 exit(EXIT_FAILURE); 115 } 116 117 mru = BNEP_MTU_MIN; 118 if (setsockopt(server_fd, SOL_L2CAP, 119 SO_L2CAP_IMTU, &mru, sizeof(mru)) == -1) { 120 log_err("Could not set L2CAP IMTU (%d): %m", mru); 121 exit(EXIT_FAILURE); 122 } 123 124 if (listen(server_fd, 0) == -1) { 125 log_err("Could not listen on server socket: %m"); 126 exit(EXIT_FAILURE); 127 } 128 129 event_set(&server_ev, server_fd, EV_READ | EV_PERSIST, server_read, NULL); 130 if (event_add(&server_ev, NULL) == -1) { 131 log_err("Could not add server event: %m"); 132 exit(EXIT_FAILURE); 133 } 134 135 log_info("server socket open"); 136 } 137 138 static void 139 server_close(void) 140 { 141 142 event_del(&server_ev); 143 close(server_fd); 144 server_fd = -1; 145 146 log_info("server socket closed"); 147 } 148 149 /* 150 * handle connection request 151 */ 152 static void 153 server_read(int s, short ev, void *arg) 154 { 155 struct sockaddr_l2cap ra, la; 156 channel_t *chan; 157 socklen_t len; 158 int fd, n; 159 uint16_t mru, mtu; 160 161 len = sizeof(ra); 162 fd = accept(s, (struct sockaddr *)&ra, &len); 163 if (fd == -1) 164 return; 165 166 n = 1; 167 if (ioctl(fd, FIONBIO, &n) == -1) { 168 log_err("Could not set NonBlocking IO: %m"); 169 close(fd); 170 return; 171 } 172 173 len = sizeof(mru); 174 if (getsockopt(fd, SOL_L2CAP, SO_L2CAP_IMTU, &mru, &len) == -1) { 175 log_err("Could not get L2CAP IMTU: %m"); 176 close(fd); 177 return; 178 } 179 if(mru < BNEP_MTU_MIN) { 180 log_err("L2CAP IMTU too small (%d)", mru); 181 close(fd); 182 return; 183 } 184 185 len = sizeof(n); 186 if (getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &n, &len) == -1) { 187 log_err("Could not read SO_RCVBUF"); 188 close(fd); 189 return; 190 } 191 if (n < (mru * 10)) { 192 n = mru * 10; 193 if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &n, sizeof(n)) == -1) 194 log_info("Could not increase SO_RCVBUF (from %d)", n); 195 } 196 197 len = sizeof(mtu); 198 if (getsockopt(fd, SOL_L2CAP, SO_L2CAP_OMTU, &mtu, &len) == -1) { 199 log_err("Could not get L2CAP OMTU: %m"); 200 close(fd); 201 return; 202 } 203 if (mtu < BNEP_MTU_MIN) { 204 log_err("L2CAP OMTU too small (%d)", mtu); 205 close(fd); 206 return; 207 } 208 209 len = sizeof(n); 210 if (getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &n, &len) == -1) { 211 log_err("Could not get socket send buffer size: %m"); 212 close(fd); 213 return; 214 } 215 216 if (n < (mtu * 2)) { 217 n = mtu * 2; 218 if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &n, sizeof(n)) == -1) { 219 log_err("Could not set socket send buffer size (%d): %m", n); 220 close(fd); 221 return; 222 } 223 } 224 225 n = mtu; 226 if (setsockopt(fd, SOL_SOCKET, SO_SNDLOWAT, &n, sizeof(n)) == -1) { 227 log_err("Could not set socket low water mark (%d): %m", n); 228 close(fd); 229 return; 230 } 231 232 len = sizeof(la); 233 if (getsockname(fd, (struct sockaddr *)&la, &len) == -1) { 234 log_err("Could not get socket address: %m"); 235 close(fd); 236 return; 237 } 238 239 log_info("Accepted connection from %s", bt_ntoa(&ra.l2cap_bdaddr, NULL)); 240 241 chan = channel_alloc(); 242 if (chan == NULL) { 243 close(fd); 244 return; 245 } 246 247 chan->send = bnep_send; 248 chan->recv = bnep_recv; 249 chan->mru = mru; 250 chan->mtu = mtu; 251 b2eaddr(chan->raddr, &ra.l2cap_bdaddr); 252 b2eaddr(chan->laddr, &la.l2cap_bdaddr); 253 chan->state = CHANNEL_WAIT_CONNECT_REQ; 254 channel_timeout(chan, 10); 255 if (!channel_open(chan, fd)) { 256 chan->state = CHANNEL_CLOSED; 257 channel_free(chan); 258 close(fd); 259 return; 260 } 261 } 262 263 static void 264 server_register(void) 265 { 266 sdp_nap_profile_t p; 267 int rv; 268 269 if (server_ss == NULL) { 270 server_ss = sdp_open_local(control_path); 271 if (server_ss == NULL || sdp_error(server_ss) != 0) { 272 log_err("failed to contact SDP server"); 273 return; 274 } 275 } 276 277 memset(&p, 0, sizeof(p)); 278 p.psm = l2cap_psm; 279 p.load_factor = server_avail; 280 p.security_description = (l2cap_mode == 0 ? 0x0000 : 0x0001); 281 282 if (server_handle) 283 rv = sdp_change_service(server_ss, server_handle, 284 (uint8_t *)&p, sizeof(p)); 285 else 286 rv = sdp_register_service(server_ss, service_class, 287 &local_bdaddr, (uint8_t *)&p, sizeof(p), &server_handle); 288 289 if (rv != 0) { 290 errno = sdp_error(server_ss); 291 log_err("%s: %m", service_name); 292 exit(EXIT_FAILURE); 293 } 294 } 295