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