Path: blob/main/usr.sbin/bluetooth/btpand/client.c
104186 views
/* $NetBSD: client.c,v 1.2 2008/12/06 20:01:14 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: client.c,v 1.2 2008/12/06 20:01:14 plunky Exp $");3233#define L2CAP_SOCKET_CHECKED34#include <bluetooth.h>35#include <errno.h>36#include <sdp.h>37#include <unistd.h>3839#include "btpand.h"40#include "bnep.h"41#include "sdp.h"4243static void client_query(void);4445void46client_init(void)47{48struct sockaddr_l2cap sa;49channel_t *chan;50socklen_t len;51int fd, n;52uint16_t mru, mtu;5354if (bdaddr_any(&remote_bdaddr))55return;5657if (service_name)58client_query();5960fd = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BLUETOOTH_PROTO_L2CAP);61if (fd == -1) {62log_err("Could not open L2CAP socket: %m");63exit(EXIT_FAILURE);64}6566memset(&sa, 0, sizeof(sa));67sa.l2cap_family = AF_BLUETOOTH;68sa.l2cap_len = sizeof(sa);69sa.l2cap_bdaddr_type = BDADDR_BREDR;70sa.l2cap_cid = 0;7172bdaddr_copy(&sa.l2cap_bdaddr, &local_bdaddr);73if (bind(fd, (struct sockaddr *)&sa, sizeof(sa)) == -1) {74log_err("Could not bind client socket: %m");75exit(EXIT_FAILURE);76}7778mru = BNEP_MTU_MIN;79if (setsockopt(fd, SOL_L2CAP, SO_L2CAP_IMTU, &mru, sizeof(mru)) == -1) {80log_err("Could not set L2CAP IMTU (%d): %m", mru);81exit(EXIT_FAILURE);82}8384log_info("Opening connection to service 0x%4.4x at %s",85service_class, bt_ntoa(&remote_bdaddr, NULL));8687sa.l2cap_psm = htole16(l2cap_psm);88bdaddr_copy(&sa.l2cap_bdaddr, &remote_bdaddr);89if (connect(fd, (struct sockaddr *)&sa, sizeof(sa)) == -1) {90log_err("Could not connect: %m");91exit(EXIT_FAILURE);92}9394len = sizeof(mru);95if (getsockopt(fd, SOL_L2CAP, SO_L2CAP_IMTU, &mru, &len) == -1) {96log_err("Could not get IMTU: %m");97exit(EXIT_FAILURE);98}99if (mru < BNEP_MTU_MIN) {100log_err("L2CAP IMTU too small (%d)", mru);101exit(EXIT_FAILURE);102}103104len = sizeof(n);105if (getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &n, &len) == -1) {106log_err("Could not read SO_RCVBUF");107exit(EXIT_FAILURE);108}109if (n < (mru * 10)) {110n = mru * 10;111if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &n, sizeof(n)) == -1)112log_info("Could not increase SO_RCVBUF (from %d)", n);113}114115len = sizeof(mtu);116if (getsockopt(fd, SOL_L2CAP, SO_L2CAP_OMTU, &mtu, &len) == -1) {117log_err("Could not get L2CAP OMTU: %m");118exit(EXIT_FAILURE);119}120if (mtu < BNEP_MTU_MIN) {121log_err("L2CAP OMTU too small (%d)", mtu);122exit(EXIT_FAILURE);123}124125len = sizeof(n);126if (getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &n, &len) == -1) {127log_err("Could not get socket send buffer size: %m");128close(fd);129return;130}131if (n < (mtu * 2)) {132n = mtu * 2;133if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &n, sizeof(n)) == -1) {134log_err("Could not set socket send buffer size (%d): %m", n);135close(fd);136return;137}138}139n = mtu;140if (setsockopt(fd, SOL_SOCKET, SO_SNDLOWAT, &n, sizeof(n)) == -1) {141log_err("Could not set socket low water mark (%d): %m", n);142close(fd);143return;144}145146chan = channel_alloc();147if (chan == NULL)148exit(EXIT_FAILURE);149150chan->send = bnep_send;151chan->recv = bnep_recv;152chan->mru = mru;153chan->mtu = mtu;154b2eaddr(chan->raddr, &remote_bdaddr);155b2eaddr(chan->laddr, &local_bdaddr);156chan->state = CHANNEL_WAIT_CONNECT_RSP;157channel_timeout(chan, 10);158if (!channel_open(chan, fd))159exit(EXIT_FAILURE);160161bnep_send_control(chan, BNEP_SETUP_CONNECTION_REQUEST,1622, service_class, SDP_SERVICE_CLASS_PANU);163}164165static void166client_query(void)167{168uint8_t buffer[512];169sdp_attr_t attr;170uint32_t range;171void *ss;172int rv;173uint8_t *seq0, *seq1;174175attr.flags = SDP_ATTR_INVALID;176attr.attr = 0;177attr.vlen = sizeof(buffer);178attr.value = buffer;179180range = SDP_ATTR_RANGE(SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST,181SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST);182183ss = sdp_open(&local_bdaddr, &remote_bdaddr);184if (ss == NULL || (errno = sdp_error(ss)) != 0) {185log_err("%s: %m", service_name);186exit(EXIT_FAILURE);187}188189log_info("Searching for %s service at %s",190service_name, bt_ntoa(&remote_bdaddr, NULL));191192rv = sdp_search(ss, 1, &service_class, 1, &range, 1, &attr);193if (rv != 0) {194log_err("%s: %s", service_name, strerror(sdp_error(ss)));195exit(EXIT_FAILURE);196}197198sdp_close(ss);199200if (attr.flags != SDP_ATTR_OK201|| attr.attr != SDP_ATTR_PROTOCOL_DESCRIPTOR_LIST) {202log_err("%s service not found", service_name);203exit(EXIT_FAILURE);204}205206/*207* we expect the following protocol descriptor list208*209* seq len210* seq len211* uuid value == L2CAP212* uint16 value16 => PSM213* seq len214* uuid value == BNEP215*/216if (_sdp_get_seq(&attr.value, attr.value + attr.vlen, &seq0)217&& _sdp_get_seq(&seq0, attr.value, &seq1)218&& _sdp_match_uuid16(&seq1, seq0, SDP_UUID_PROTOCOL_L2CAP)219&& _sdp_get_uint16(&seq1, seq0, &l2cap_psm)220&& _sdp_get_seq(&seq0, attr.value, &seq1)221&& _sdp_match_uuid16(&seq1, seq0, SDP_UUID_PROTOCOL_BNEP)) {222log_info("Found PSM %d for service %s", l2cap_psm, service_name);223return;224}225226log_err("%s query failed", service_name);227exit(EXIT_FAILURE);228}229230231