Path: blob/main/usr.sbin/bluetooth/btpand/server.c
103554 views
/* $NetBSD: server.c,v 1.2 2009/01/24 17:29:28 plunky Exp $ */12/*-3* SPDX-License-Identifier: BSD-2-Clause4*5* Copyright (c) 2008 Iain Hibbert6* All rights reserved.7*8* Redistribution and use in source and binary forms, with or without9* modification, are permitted provided that the following conditions10* are met:11* 1. Redistributions of source code must retain the above copyright12* notice, this list of conditions and the following disclaimer.13* 2. Redistributions in binary form must reproduce the above copyright14* notice, this list of conditions and the following disclaimer in the15* documentation and/or other materials provided with the distribution.16*17* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR18* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES19* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.20* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,21* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT22* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,23* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY24* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT25* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF26* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.27*/282930#include <sys/cdefs.h>31__RCSID("$NetBSD: server.c,v 1.2 2009/01/24 17:29:28 plunky Exp $");3233#include <sys/ioctl.h>3435#define L2CAP_SOCKET_CHECKED36#include <bluetooth.h>37#include <inttypes.h>38#include <errno.h>39#include <sdp.h>40#include <unistd.h>4142#include "btpand.h"43#include "bnep.h"4445static struct event server_ev;46static int server_fd;47static int server_avail;4849static void * server_ss;50static uint32_t server_handle;5152static void server_open(void);53static void server_close(void);54static void server_read(int, short, void *);55static void server_register(void);5657void58server_init(void)59{6061server_fd = -1;62}6364/*65* The server_update() function is called whenever the channel count is66* changed. We maintain the SDP record and open or close the server socket67* as required.68*/69void70server_update(int count)71{7273if (server_limit == 0)74return;7576log_debug("count %d", count);7778server_avail = UINT8_MAX - (count - 1) * UINT8_MAX / server_limit;79log_info("Service Availability: %d/%d", server_avail, UINT8_MAX);8081if (server_avail == 0 && server_fd != -1)82server_close();8384if (server_avail > 0 && server_fd == -1)85server_open();8687if (service_name)88server_register();89}9091static void92server_open(void)93{94struct sockaddr_l2cap sa;95uint16_t mru;9697server_fd = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BLUETOOTH_PROTO_L2CAP);98if (server_fd == -1) {99log_err("Could not open L2CAP socket: %m");100exit(EXIT_FAILURE);101}102103memset(&sa, 0, sizeof(sa));104sa.l2cap_family = AF_BLUETOOTH;105sa.l2cap_len = sizeof(sa);106sa.l2cap_psm = htole16(l2cap_psm);107sa.l2cap_bdaddr_type = BDADDR_BREDR;108sa.l2cap_cid = 0;109110bdaddr_copy(&sa.l2cap_bdaddr, &local_bdaddr);111if (bind(server_fd, (struct sockaddr *)&sa, sizeof(sa)) == -1) {112log_err("Could not bind server socket: %m");113exit(EXIT_FAILURE);114}115116mru = BNEP_MTU_MIN;117if (setsockopt(server_fd, SOL_L2CAP,118SO_L2CAP_IMTU, &mru, sizeof(mru)) == -1) {119log_err("Could not set L2CAP IMTU (%d): %m", mru);120exit(EXIT_FAILURE);121}122123if (listen(server_fd, 0) == -1) {124log_err("Could not listen on server socket: %m");125exit(EXIT_FAILURE);126}127128event_set(&server_ev, server_fd, EV_READ | EV_PERSIST, server_read, NULL);129if (event_add(&server_ev, NULL) == -1) {130log_err("Could not add server event: %m");131exit(EXIT_FAILURE);132}133134log_info("server socket open");135}136137static void138server_close(void)139{140141event_del(&server_ev);142close(server_fd);143server_fd = -1;144145log_info("server socket closed");146}147148/*149* handle connection request150*/151static void152server_read(int s, short ev, void *arg)153{154struct sockaddr_l2cap ra, la;155channel_t *chan;156socklen_t len;157int fd, n;158uint16_t mru, mtu;159160len = sizeof(ra);161fd = accept(s, (struct sockaddr *)&ra, &len);162if (fd == -1)163return;164165n = 1;166if (ioctl(fd, FIONBIO, &n) == -1) {167log_err("Could not set NonBlocking IO: %m");168close(fd);169return;170}171172len = sizeof(mru);173if (getsockopt(fd, SOL_L2CAP, SO_L2CAP_IMTU, &mru, &len) == -1) {174log_err("Could not get L2CAP IMTU: %m");175close(fd);176return;177}178if(mru < BNEP_MTU_MIN) {179log_err("L2CAP IMTU too small (%d)", mru);180close(fd);181return;182}183184len = sizeof(n);185if (getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &n, &len) == -1) {186log_err("Could not read SO_RCVBUF");187close(fd);188return;189}190if (n < (mru * 10)) {191n = mru * 10;192if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &n, sizeof(n)) == -1)193log_info("Could not increase SO_RCVBUF (from %d)", n);194}195196len = sizeof(mtu);197if (getsockopt(fd, SOL_L2CAP, SO_L2CAP_OMTU, &mtu, &len) == -1) {198log_err("Could not get L2CAP OMTU: %m");199close(fd);200return;201}202if (mtu < BNEP_MTU_MIN) {203log_err("L2CAP OMTU too small (%d)", mtu);204close(fd);205return;206}207208len = sizeof(n);209if (getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &n, &len) == -1) {210log_err("Could not get socket send buffer size: %m");211close(fd);212return;213}214215if (n < (mtu * 2)) {216n = mtu * 2;217if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &n, sizeof(n)) == -1) {218log_err("Could not set socket send buffer size (%d): %m", n);219close(fd);220return;221}222}223224n = mtu;225if (setsockopt(fd, SOL_SOCKET, SO_SNDLOWAT, &n, sizeof(n)) == -1) {226log_err("Could not set socket low water mark (%d): %m", n);227close(fd);228return;229}230231len = sizeof(la);232if (getsockname(fd, (struct sockaddr *)&la, &len) == -1) {233log_err("Could not get socket address: %m");234close(fd);235return;236}237238log_info("Accepted connection from %s", bt_ntoa(&ra.l2cap_bdaddr, NULL));239240chan = channel_alloc();241if (chan == NULL) {242close(fd);243return;244}245246chan->send = bnep_send;247chan->recv = bnep_recv;248chan->mru = mru;249chan->mtu = mtu;250b2eaddr(chan->raddr, &ra.l2cap_bdaddr);251b2eaddr(chan->laddr, &la.l2cap_bdaddr);252chan->state = CHANNEL_WAIT_CONNECT_REQ;253channel_timeout(chan, 10);254if (!channel_open(chan, fd)) {255chan->state = CHANNEL_CLOSED;256channel_free(chan);257close(fd);258return;259}260}261262static void263server_register(void)264{265sdp_nap_profile_t p;266int rv;267268if (server_ss == NULL) {269server_ss = sdp_open_local(control_path);270if (server_ss == NULL || sdp_error(server_ss) != 0) {271log_err("failed to contact SDP server");272return;273}274}275276memset(&p, 0, sizeof(p));277p.psm = l2cap_psm;278p.load_factor = server_avail;279p.security_description = (l2cap_mode == 0 ? 0x0000 : 0x0001);280281if (server_handle)282rv = sdp_change_service(server_ss, server_handle,283(uint8_t *)&p, sizeof(p));284else285rv = sdp_register_service(server_ss, service_class,286&local_bdaddr, (uint8_t *)&p, sizeof(p), &server_handle);287288if (rv != 0) {289errno = sdp_error(server_ss);290log_err("%s: %m", service_name);291exit(EXIT_FAILURE);292}293}294295296