root/share/examples/rump/btplay/btplay.c
/*      $NetBSD: btplay.c,v 1.1 2010/03/22 12:21:37 pooka Exp $ */

/*
 * Copyright (c) 2010 Antti Kantee.  All Rights Reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

/*
 * Little demo showing how to use bluetooth stack in rump.  Searches
 * for a peer and prints a little info for it.
 */

#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <sys/socket.h>

#include <rump/rump.h>
#include <rump/rump_syscalls.h>

#include <netbt/bluetooth.h>
#include <netbt/hci.h>

#include <bluetooth.h>
#include <err.h>
#include <paths.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

const char *btclasses[] = {
        "misc.",
        "computer",
        "phone",
        "LAN",
        "audio-video",
        "peripheral",
        "imaging",
        "wearable",
        "toy",
};

int
main(int argc, char *argv[])
{
        struct sockaddr_bt sbt;
        bdaddr_t peeraddr;
        uint8_t msg[1024];
        hci_inquiry_cp inq;
        hci_cmd_hdr_t *cmd;
        hci_event_hdr_t *evp;
        struct hci_filter filt;
        struct btreq btr;
        int s, gotpeer = 0;

        rump_boot_sethowto(RUMP_AB_VERBOSE);
        rump_init();

        s = rump_sys_socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
        if (s == -1)
                err(1, "socket");

        /* enable first device, print name and address */
        memset(&btr, 0, sizeof(btr));
        if (rump_sys_ioctl(s, SIOCNBTINFO, &btr) == -1)
                err(1, "no bt device?");

        btr.btr_flags |= BTF_UP;
        if (rump_sys_ioctl(s, SIOCSBTFLAGS, &btr) == -1)
                err(1, "raise interface");
        if (rump_sys_ioctl(s, SIOCGBTINFO, &btr) == -1)
                err(1, "reget info");

        memset(&sbt, 0, sizeof(sbt));
        sbt.bt_len = sizeof(sbt);
        sbt.bt_family = AF_BLUETOOTH;
        bdaddr_copy(&sbt.bt_bdaddr, &btr.btr_bdaddr);

        if (rump_sys_bind(s, (struct sockaddr *)&sbt, sizeof(sbt)) == -1)
                err(1, "bind");
        if (rump_sys_connect(s, (struct sockaddr *)&sbt, sizeof(sbt)) == -1)
                err(1, "connect");

        printf("device %s, addr %s\n",
            btr.btr_name, bt_ntoa(&btr.btr_bdaddr, NULL));

        /* allow to receive various messages we need later */
        memset(&filt, 0, sizeof(filt));
        hci_filter_set(HCI_EVENT_COMMAND_COMPL, &filt);
        hci_filter_set(HCI_EVENT_INQUIRY_RESULT, &filt);
        hci_filter_set(HCI_EVENT_INQUIRY_COMPL, &filt);
        hci_filter_set(HCI_EVENT_REMOTE_NAME_REQ_COMPL, &filt);
        if (rump_sys_setsockopt(s, BTPROTO_HCI, SO_HCI_EVT_FILTER,
            &filt, sizeof(filt)) == -1)
                err(1, "setsockopt");

        cmd = (void *)msg;
        evp = (void *)msg;

        /* discover peer.  first, send local access profile general inquiry */
        inq.lap[0] = 0x33;
        inq.lap[1] = 0x8b;
        inq.lap[2] = 0x9e;
        inq.inquiry_length = 4;
        inq.num_responses = 1;

        cmd->type = HCI_CMD_PKT;
        cmd->opcode = htole16(HCI_CMD_INQUIRY);
        cmd->length = sizeof(inq);
        memcpy(cmd+1, &inq, sizeof(inq));

        if (rump_sys_sendto(s, msg, sizeof(*cmd)+sizeof(inq), 0, NULL, 0) == -1)
                err(1, "send inquiry");
        memset(msg, 0, sizeof(msg));
        if (rump_sys_recvfrom(s, msg, sizeof(msg), 0, NULL, NULL) == -1)
                err(1, "recv inq response");
        if (evp->event != HCI_EVENT_COMMAND_COMPL)
                errx(1, "excepted command compl");

        /* then, wait for response */
        for (;;) {
                if (rump_sys_recvfrom(s, msg, sizeof(msg), 0, NULL, NULL) == -1)
                        err(1, "recv inq result");

                if (evp->event == HCI_EVENT_INQUIRY_COMPL)
                        break;
                if (evp->event == HCI_EVENT_INQUIRY_RESULT) {
                        hci_inquiry_response *r;
                        unsigned class;

                        r = (void *)(msg + sizeof(hci_event_hdr_t)
                            + sizeof(hci_inquiry_result_ep));
                        bdaddr_copy(&peeraddr, &r[0]. bdaddr);
                        printf("my peer: %s, ", bt_ntoa(&peeraddr, NULL));
                        class = r[0].uclass[1] & 0x1f;
                        printf("major class: %d (%s)\n", class,
                            class < __arraycount(btclasses)
                              ? btclasses[class] : "unknown");
                        gotpeer = 1;
                }
        }

        /* found peer.  ask for its name */
        if (gotpeer) {
                hci_remote_name_req_cp nreq;
                hci_remote_name_req_compl_ep *nresp;

                memset(&nreq, 0, sizeof(nreq));
                bdaddr_copy(&nreq.bdaddr, &peeraddr);

                cmd->type = HCI_CMD_PKT;
                cmd->opcode = htole16(HCI_CMD_REMOTE_NAME_REQ);
                cmd->length = sizeof(nreq);
                memcpy(cmd+1, &nreq, sizeof(nreq));

                if (rump_sys_sendto(s, msg, sizeof(*cmd)+sizeof(nreq), 0,
                    NULL, 0) == -1)
                        err(1, "send name req");
                memset(msg, 0, sizeof(msg));
                if (rump_sys_recvfrom(s, msg, sizeof(msg), 0, NULL, NULL) == -1)
                        err(1, "recv inq response");
                if (evp->event != HCI_EVENT_REMOTE_NAME_REQ_COMPL)
                        errx(1, "excepted nreq compl");

                nresp = (void *)(evp+1);
                printf("peer name: %s\n", nresp->name);
        }

        return 0;
}