11590Srgrimes/* $NetBSD: server.c,v 1.2 2009/01/24 17:29:28 plunky Exp $ */ 21590Srgrimes 31590Srgrimes/*- 41590Srgrimes * SPDX-License-Identifier: BSD-2-Clause 51590Srgrimes * 61590Srgrimes * Copyright (c) 2008 Iain Hibbert 71590Srgrimes * All rights reserved. 81590Srgrimes * 91590Srgrimes * Redistribution and use in source and binary forms, with or without 101590Srgrimes * modification, are permitted provided that the following conditions 111590Srgrimes * are met: 121590Srgrimes * 1. Redistributions of source code must retain the above copyright 131590Srgrimes * notice, this list of conditions and the following disclaimer. 141590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 151590Srgrimes * notice, this list of conditions and the following disclaimer in the 161590Srgrimes * documentation and/or other materials provided with the distribution. 171590Srgrimes * 181590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 191590Srgrimes * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 201590Srgrimes * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 211590Srgrimes * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 221590Srgrimes * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 231590Srgrimes * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 241590Srgrimes * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 251590Srgrimes * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 261590Srgrimes * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 271590Srgrimes * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 281590Srgrimes */ 291590Srgrimes 301590Srgrimes 311590Srgrimes#include <sys/cdefs.h> 321590Srgrimes__RCSID("$NetBSD: server.c,v 1.2 2009/01/24 17:29:28 plunky Exp $"); 331590Srgrimes 341590Srgrimes#include <sys/ioctl.h> 351590Srgrimes 361590Srgrimes#define L2CAP_SOCKET_CHECKED 371590Srgrimes#include <bluetooth.h> 3887301Sdwmalone#include <inttypes.h> 391590Srgrimes#include <errno.h> 401590Srgrimes#include <sdp.h> 411590Srgrimes#include <unistd.h> 421590Srgrimes 431590Srgrimes#include "btpand.h" 4487301Sdwmalone#include "bnep.h" 451590Srgrimes 461590Srgrimesstatic struct event server_ev; 47146751Scharnierstatic int server_fd; 48146751Scharnierstatic int server_avail; 49146751Scharnier 501590Srgrimesstatic void * server_ss; 511590Srgrimesstatic uint32_t server_handle; 521590Srgrimes 531590Srgrimesstatic void server_open(void); 541590Srgrimesstatic void server_close(void); 55200462Sdelphijstatic void server_read(int, short, void *); 561590Srgrimesstatic void server_register(void); 571590Srgrimes 581590Srgrimesvoid 591590Srgrimesserver_init(void) 6023710Speter{ 611590Srgrimes 621590Srgrimes server_fd = -1; 631590Srgrimes} 641590Srgrimes 651590Srgrimes/* 661590Srgrimes * The server_update() function is called whenever the channel count is 671590Srgrimes * changed. We maintain the SDP record and open or close the server socket 6817389Sjkh * as required. 691590Srgrimes */ 701590Srgrimesvoid 7172093Sasmodaiserver_update(int count) 721590Srgrimes{ 731590Srgrimes 741590Srgrimes if (server_limit == 0) 751590Srgrimes return; 761590Srgrimes 771590Srgrimes log_debug("count %d", count); 781590Srgrimes 79119747Sdds server_avail = UINT8_MAX - (count - 1) * UINT8_MAX / server_limit; 801590Srgrimes log_info("Service Availability: %d/%d", server_avail, UINT8_MAX); 811590Srgrimes 821590Srgrimes if (server_avail == 0 && server_fd != -1) 831590Srgrimes server_close(); 841590Srgrimes 851590Srgrimes if (server_avail > 0 && server_fd == -1) 861590Srgrimes server_open(); 871590Srgrimes 881590Srgrimes if (service_name) 891590Srgrimes server_register(); 901590Srgrimes} 911590Srgrimes 921590Srgrimesstatic void 931590Srgrimesserver_open(void) 941590Srgrimes{ 951590Srgrimes struct sockaddr_l2cap sa; 961590Srgrimes uint16_t mru; 971590Srgrimes 981590Srgrimes server_fd = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BLUETOOTH_PROTO_L2CAP); 991590Srgrimes if (server_fd == -1) { 1001590Srgrimes log_err("Could not open L2CAP socket: %m"); 1011590Srgrimes exit(EXIT_FAILURE); 1021590Srgrimes } 1031590Srgrimes 1041590Srgrimes memset(&sa, 0, sizeof(sa)); 10517389Sjkh sa.l2cap_family = AF_BLUETOOTH; 1061590Srgrimes sa.l2cap_len = sizeof(sa); 10792922Simp sa.l2cap_psm = htole16(l2cap_psm); 10892922Simp sa.l2cap_bdaddr_type = BDADDR_BREDR; 10992922Simp sa.l2cap_cid = 0; 11096785Sjmallett 11192922Simp bdaddr_copy(&sa.l2cap_bdaddr, &local_bdaddr); 11292922Simp if (bind(server_fd, (struct sockaddr *)&sa, sizeof(sa)) == -1) { 11392922Simp log_err("Could not bind server socket: %m"); 11492922Simp exit(EXIT_FAILURE); 1151590Srgrimes } 1161590Srgrimes 117102944Sdwmalone mru = BNEP_MTU_MIN; 1181590Srgrimes if (setsockopt(server_fd, SOL_L2CAP, 119102944Sdwmalone SO_L2CAP_IMTU, &mru, sizeof(mru)) == -1) { 120102944Sdwmalone log_err("Could not set L2CAP IMTU (%d): %m", mru); 1211590Srgrimes exit(EXIT_FAILURE); 1221590Srgrimes } 1231590Srgrimes 1241590Srgrimes if (listen(server_fd, 0) == -1) { 125146751Scharnier log_err("Could not listen on server socket: %m"); 12624360Simp exit(EXIT_FAILURE); 1271590Srgrimes } 1281590Srgrimes 1291590Srgrimes event_set(&server_ev, server_fd, EV_READ | EV_PERSIST, server_read, NULL); 1301590Srgrimes if (event_add(&server_ev, NULL) == -1) { 1311590Srgrimes log_err("Could not add server event: %m"); 1321590Srgrimes exit(EXIT_FAILURE); 1331590Srgrimes } 13417389Sjkh 13517389Sjkh log_info("server socket open"); 13617389Sjkh} 1371590Srgrimes 1381590Srgrimesstatic void 1391590Srgrimesserver_close(void) 1401590Srgrimes{ 1411590Srgrimes 1421590Srgrimes event_del(&server_ev); 1431590Srgrimes close(server_fd); 1441590Srgrimes server_fd = -1; 1451590Srgrimes 1461590Srgrimes log_info("server socket closed"); 1471590Srgrimes} 1481590Srgrimes 1491590Srgrimes/* 1501590Srgrimes * handle connection request 1511590Srgrimes */ 1521590Srgrimesstatic void 1531590Srgrimesserver_read(int s, short ev, void *arg) 1541590Srgrimes{ 1551590Srgrimes struct sockaddr_l2cap ra, la; 1561590Srgrimes channel_t *chan; 1571590Srgrimes socklen_t len; 1581590Srgrimes int fd, n; 1591590Srgrimes uint16_t mru, mtu; 1601590Srgrimes 1611590Srgrimes len = sizeof(ra); 1621590Srgrimes fd = accept(s, (struct sockaddr *)&ra, &len); 1631590Srgrimes if (fd == -1) 1641590Srgrimes return; 1651590Srgrimes 1661590Srgrimes n = 1; 1671590Srgrimes if (ioctl(fd, FIONBIO, &n) == -1) { 1681590Srgrimes log_err("Could not set NonBlocking IO: %m"); 1691590Srgrimes close(fd); 1701590Srgrimes return; 1711590Srgrimes } 1721590Srgrimes 1731590Srgrimes len = sizeof(mru); 1741590Srgrimes if (getsockopt(fd, SOL_L2CAP, SO_L2CAP_IMTU, &mru, &len) == -1) { 1751590Srgrimes log_err("Could not get L2CAP IMTU: %m"); 1761590Srgrimes close(fd); 1771590Srgrimes return; 1781590Srgrimes } 1791590Srgrimes if(mru < BNEP_MTU_MIN) { 1801590Srgrimes log_err("L2CAP IMTU too small (%d)", mru); 1811590Srgrimes close(fd); 1821590Srgrimes return; 1831590Srgrimes } 1841590Srgrimes 1851590Srgrimes len = sizeof(n); 1861590Srgrimes if (getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &n, &len) == -1) { 1871590Srgrimes log_err("Could not read SO_RCVBUF"); 1881590Srgrimes close(fd); 1891590Srgrimes return; 1901590Srgrimes } 1911590Srgrimes if (n < (mru * 10)) { 1921590Srgrimes n = mru * 10; 193102944Sdwmalone if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &n, sizeof(n)) == -1) 1941590Srgrimes log_info("Could not increase SO_RCVBUF (from %d)", n); 19596785Sjmallett } 1961590Srgrimes 1971590Srgrimes len = sizeof(mtu); 1981590Srgrimes if (getsockopt(fd, SOL_L2CAP, SO_L2CAP_OMTU, &mtu, &len) == -1) { 1991590Srgrimes log_err("Could not get L2CAP OMTU: %m"); 2001590Srgrimes close(fd); 2011590Srgrimes return; 2021590Srgrimes } 2031590Srgrimes if (mtu < BNEP_MTU_MIN) { 2041590Srgrimes log_err("L2CAP OMTU too small (%d)", mtu); 205102944Sdwmalone close(fd); 2061590Srgrimes return; 207102944Sdwmalone } 2081590Srgrimes 2091590Srgrimes len = sizeof(n); 2101590Srgrimes if (getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &n, &len) == -1) { 2111590Srgrimes log_err("Could not get socket send buffer size: %m"); 2121590Srgrimes close(fd); 2131590Srgrimes return; 2141590Srgrimes } 2151590Srgrimes 2161590Srgrimes if (n < (mtu * 2)) { 2171590Srgrimes n = mtu * 2; 2181590Srgrimes if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &n, sizeof(n)) == -1) { 2191590Srgrimes log_err("Could not set socket send buffer size (%d): %m", n); 2201590Srgrimes close(fd); 2211590Srgrimes return; 2221590Srgrimes } 2231590Srgrimes } 2241590Srgrimes 2251590Srgrimes n = mtu; 2261590Srgrimes if (setsockopt(fd, SOL_SOCKET, SO_SNDLOWAT, &n, sizeof(n)) == -1) { 2271590Srgrimes log_err("Could not set socket low water mark (%d): %m", n); 2281590Srgrimes close(fd); 2291590Srgrimes return; 2301590Srgrimes } 2311590Srgrimes 2321590Srgrimes len = sizeof(la); 2331590Srgrimes if (getsockname(fd, (struct sockaddr *)&la, &len) == -1) { 2341590Srgrimes log_err("Could not get socket address: %m"); 2351590Srgrimes close(fd); 2361590Srgrimes return; 2371590Srgrimes } 2381590Srgrimes 2391590Srgrimes log_info("Accepted connection from %s", bt_ntoa(&ra.l2cap_bdaddr, NULL)); 240102944Sdwmalone 2411590Srgrimes chan = channel_alloc(); 2421590Srgrimes if (chan == NULL) { 2431590Srgrimes close(fd); 2441590Srgrimes return; 2451590Srgrimes } 2461590Srgrimes 2471590Srgrimes chan->send = bnep_send; 2481590Srgrimes chan->recv = bnep_recv; 2491590Srgrimes chan->mru = mru; 2501590Srgrimes chan->mtu = mtu; 2511590Srgrimes b2eaddr(chan->raddr, &ra.l2cap_bdaddr); 2521590Srgrimes b2eaddr(chan->laddr, &la.l2cap_bdaddr); 2531590Srgrimes chan->state = CHANNEL_WAIT_CONNECT_REQ; 2541590Srgrimes channel_timeout(chan, 10); 2551590Srgrimes if (!channel_open(chan, fd)) { 2561590Srgrimes chan->state = CHANNEL_CLOSED; 2571590Srgrimes channel_free(chan); 2581590Srgrimes close(fd); 2591590Srgrimes return; 2601590Srgrimes } 2611590Srgrimes} 2621590Srgrimes 2631590Srgrimesstatic void 2641590Srgrimesserver_register(void) 2651590Srgrimes{ 2661590Srgrimes sdp_nap_profile_t p; 2671590Srgrimes int rv; 2681590Srgrimes 2691590Srgrimes if (server_ss == NULL) { 2701590Srgrimes server_ss = sdp_open_local(control_path); 2711590Srgrimes if (server_ss == NULL || sdp_error(server_ss) != 0) { 2721590Srgrimes log_err("failed to contact SDP server"); 2731590Srgrimes return; 2741590Srgrimes } 2751590Srgrimes } 2761590Srgrimes 2771590Srgrimes memset(&p, 0, sizeof(p)); 2781590Srgrimes p.psm = l2cap_psm; 2791590Srgrimes p.load_factor = server_avail; 2801590Srgrimes p.security_description = (l2cap_mode == 0 ? 0x0000 : 0x0001); 2811590Srgrimes 2821590Srgrimes if (server_handle) 2831590Srgrimes rv = sdp_change_service(server_ss, server_handle, 2841590Srgrimes (uint8_t *)&p, sizeof(p)); 2851590Srgrimes else 2861590Srgrimes rv = sdp_register_service(server_ss, service_class, 2871590Srgrimes &local_bdaddr, (uint8_t *)&p, sizeof(p), &server_handle); 2881590Srgrimes 2891590Srgrimes if (rv != 0) { 2901590Srgrimes errno = sdp_error(server_ss); 2911590Srgrimes log_err("%s: %m", service_name); 292102944Sdwmalone exit(EXIT_FAILURE); 2931590Srgrimes } 2941590Srgrimes} 2951590Srgrimes