"Fossies" - the Fresh Open Source Software Archive

Member "libpcap-1.10.1/./pcap-bt-monitor-linux.c" (7 Jun 2021, 8182 Bytes) of package /linux/misc/libpcap-1.10.1.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "pcap-bt-monitor-linux.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 1.10.0_vs_1.10.1.

    1 /*
    2  * Copyright (c) 2014 Michal Labedzki for Tieto Corporation
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  *
    9  * 1. Redistributions of source code must retain the above copyright
   10  * notice, this list of conditions and the following disclaimer.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  * notice, this list of conditions and the following disclaimer in the
   13  * documentation and/or other materials provided with the distribution.
   14  * 3. The name of the author may not be used to endorse or promote
   15  * products derived from this software without specific prior written
   16  * permission.
   17  *
   18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
   21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
   22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
   28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   29  *
   30  */
   31 
   32 #ifdef HAVE_CONFIG_H
   33 #include <config.h>
   34 #endif
   35 
   36 #include <errno.h>
   37 #include <stdint.h>
   38 #include <stdlib.h>
   39 #include <string.h>
   40 
   41 #include <bluetooth/bluetooth.h>
   42 #include <bluetooth/hci.h>
   43 
   44 #include "pcap/bluetooth.h"
   45 #include "pcap-int.h"
   46 
   47 #include "pcap-bt-monitor-linux.h"
   48 
   49 #define BT_CONTROL_SIZE 32
   50 #define INTERFACE_NAME "bluetooth-monitor"
   51 
   52 /*
   53  * Private data.
   54  * Currently contains nothing.
   55  */
   56 struct pcap_bt_monitor {
   57     int dummy;
   58 };
   59 
   60 /*
   61  * Fields and alignment must match the declaration in the Linux kernel 3.4+.
   62  * See struct hci_mon_hdr in include/net/bluetooth/hci_mon.h.
   63  */
   64 struct hci_mon_hdr {
   65     uint16_t opcode;
   66     uint16_t index;
   67     uint16_t len;
   68 } __attribute__((packed));
   69 
   70 int
   71 bt_monitor_findalldevs(pcap_if_list_t *devlistp, char *err_str)
   72 {
   73     int         ret = 0;
   74 
   75     /*
   76      * Bluetooth is a wireless technology.
   77      *
   78      * This is a device to monitor all Bluetooth interfaces, so
   79      * there's no notion of "connected" or "disconnected", any
   80      * more than there's a notion of "connected" or "disconnected"
   81      * for the "any" device.
   82      */
   83     if (add_dev(devlistp, INTERFACE_NAME,
   84                 PCAP_IF_WIRELESS|PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE,
   85                 "Bluetooth Linux Monitor", err_str) == NULL)
   86     {
   87         ret = -1;
   88     }
   89 
   90     return ret;
   91 }
   92 
   93 static int
   94 bt_monitor_read(pcap_t *handle, int max_packets _U_, pcap_handler callback, u_char *user)
   95 {
   96     struct cmsghdr *cmsg;
   97     struct msghdr msg;
   98     struct iovec  iv[2];
   99     ssize_t ret;
  100     struct pcap_pkthdr pkth;
  101     pcap_bluetooth_linux_monitor_header *bthdr;
  102     u_char *pktd;
  103     struct hci_mon_hdr hdr;
  104 
  105     pktd = (u_char *)handle->buffer + BT_CONTROL_SIZE;
  106     bthdr = (pcap_bluetooth_linux_monitor_header*)(void *)pktd;
  107 
  108     iv[0].iov_base = &hdr;
  109     iv[0].iov_len = sizeof(hdr);
  110     iv[1].iov_base = pktd + sizeof(pcap_bluetooth_linux_monitor_header);
  111     iv[1].iov_len = handle->snapshot;
  112 
  113     memset(&pkth.ts, 0, sizeof(pkth.ts));
  114     memset(&msg, 0, sizeof(msg));
  115     msg.msg_iov = iv;
  116     msg.msg_iovlen = 2;
  117     msg.msg_control = handle->buffer;
  118     msg.msg_controllen = BT_CONTROL_SIZE;
  119 
  120     do {
  121         ret = recvmsg(handle->fd, &msg, 0);
  122         if (handle->break_loop)
  123         {
  124             handle->break_loop = 0;
  125             return -2;
  126         }
  127     } while ((ret == -1) && (errno == EINTR));
  128 
  129     if (ret < 0) {
  130         if (errno == EAGAIN || errno == EWOULDBLOCK) {
  131             /* Nonblocking mode, no data */
  132             return 0;
  133         }
  134         pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE,
  135             errno, "Can't receive packet");
  136         return -1;
  137     }
  138 
  139     pkth.caplen = (bpf_u_int32)(ret - sizeof(hdr) + sizeof(pcap_bluetooth_linux_monitor_header));
  140     pkth.len = pkth.caplen;
  141 
  142     for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
  143         if (cmsg->cmsg_level != SOL_SOCKET) continue;
  144 
  145         if (cmsg->cmsg_type == SCM_TIMESTAMP) {
  146             memcpy(&pkth.ts, CMSG_DATA(cmsg), sizeof(pkth.ts));
  147         }
  148     }
  149 
  150     bthdr->adapter_id = htons(hdr.index);
  151     bthdr->opcode = htons(hdr.opcode);
  152 
  153     if (handle->fcode.bf_insns == NULL ||
  154         pcap_filter(handle->fcode.bf_insns, pktd, pkth.len, pkth.caplen)) {
  155         callback(user, &pkth, pktd);
  156         return 1;
  157     }
  158     return 0;   /* didn't pass filter */
  159 }
  160 
  161 static int
  162 bt_monitor_inject(pcap_t *handle, const void *buf _U_, int size _U_)
  163 {
  164     snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
  165         "Packet injection is not supported yet on Bluetooth monitor devices");
  166     return -1;
  167 }
  168 
  169 static int
  170 bt_monitor_stats(pcap_t *handle _U_, struct pcap_stat *stats)
  171 {
  172     stats->ps_recv = 0;
  173     stats->ps_drop = 0;
  174     stats->ps_ifdrop = 0;
  175 
  176     return 0;
  177 }
  178 
  179 static int
  180 bt_monitor_activate(pcap_t* handle)
  181 {
  182     struct sockaddr_hci addr;
  183     int err = PCAP_ERROR;
  184     int opt;
  185 
  186     if (handle->opt.rfmon) {
  187         /* monitor mode doesn't apply here */
  188         return PCAP_ERROR_RFMON_NOTSUP;
  189     }
  190 
  191     /*
  192      * Turn a negative snapshot value (invalid), a snapshot value of
  193      * 0 (unspecified), or a value bigger than the normal maximum
  194      * value, into the maximum allowed value.
  195      *
  196      * If some application really *needs* a bigger snapshot
  197      * length, we should just increase MAXIMUM_SNAPLEN.
  198      */
  199     if (handle->snapshot <= 0 || handle->snapshot > MAXIMUM_SNAPLEN)
  200         handle->snapshot = MAXIMUM_SNAPLEN;
  201 
  202     handle->bufsize = BT_CONTROL_SIZE + sizeof(pcap_bluetooth_linux_monitor_header) + handle->snapshot;
  203     handle->linktype = DLT_BLUETOOTH_LINUX_MONITOR;
  204 
  205     handle->read_op = bt_monitor_read;
  206     handle->inject_op = bt_monitor_inject;
  207     handle->setfilter_op = install_bpf_program; /* no kernel filtering */
  208     handle->setdirection_op = NULL; /* Not implemented */
  209     handle->set_datalink_op = NULL; /* can't change data link type */
  210     handle->getnonblock_op = pcap_getnonblock_fd;
  211     handle->setnonblock_op = pcap_setnonblock_fd;
  212     handle->stats_op = bt_monitor_stats;
  213 
  214     handle->fd = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
  215     if (handle->fd < 0) {
  216         pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE,
  217             errno, "Can't create raw socket");
  218         return PCAP_ERROR;
  219     }
  220 
  221     handle->buffer = malloc(handle->bufsize);
  222     if (!handle->buffer) {
  223         pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE,
  224             errno, "Can't allocate dump buffer");
  225         goto close_fail;
  226     }
  227 
  228     /* Bind socket to the HCI device */
  229     addr.hci_family = AF_BLUETOOTH;
  230     addr.hci_dev = HCI_DEV_NONE;
  231     addr.hci_channel = HCI_CHANNEL_MONITOR;
  232 
  233     if (bind(handle->fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
  234         pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE,
  235             errno, "Can't attach to interface");
  236         goto close_fail;
  237     }
  238 
  239     opt = 1;
  240     if (setsockopt(handle->fd, SOL_SOCKET, SO_TIMESTAMP, &opt, sizeof(opt)) < 0) {
  241         pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE,
  242             errno, "Can't enable time stamp");
  243         goto close_fail;
  244     }
  245 
  246     handle->selectable_fd = handle->fd;
  247 
  248     return 0;
  249 
  250 close_fail:
  251     pcap_cleanup_live_common(handle);
  252     return err;
  253 }
  254 
  255 pcap_t *
  256 bt_monitor_create(const char *device, char *ebuf, int *is_ours)
  257 {
  258     pcap_t      *p;
  259     const char  *cp;
  260 
  261     cp = strrchr(device, '/');
  262     if (cp == NULL)
  263         cp = device;
  264 
  265     if (strcmp(cp, INTERFACE_NAME) != 0) {
  266         *is_ours = 0;
  267         return NULL;
  268     }
  269 
  270     *is_ours = 1;
  271     p = PCAP_CREATE_COMMON(ebuf, struct pcap_bt_monitor);
  272     if (p == NULL)
  273         return NULL;
  274 
  275     p->activate_op = bt_monitor_activate;
  276 
  277     return p;
  278 }