mirror of
https://git.kernel.org/pub/scm/bluetooth/bluez.git
synced 2024-11-16 00:34:39 +08:00
0a259dd05b
This patch adds SPDX License Identifier and removes the license text. ------------------------------------- License COUNT ------------------------------------- GPL-2.0-or-later : 97 LGPL-2.1-or-later : 38 GPL-2.0-only : 2 License: GPL-2.0-or-later tools/l2cap-tester.c tools/hcisecfilter.c tools/ciptool.c tools/btsnoop.c tools/check-selftest.c tools/btpclientctl.c tools/hci-tester.c tools/hcitool.c tools/btiotest.c tools/oobtest.c tools/btinfo.c tools/hwdb.c tools/hciattach_bcm43xx.c tools/mgmt-tester.c tools/hex2hcd.c tools/hciattach_st.c tools/smp-tester.c tools/bluetooth-player.c tools/hciattach_tialt.c tools/gap-tester.c tools/bluemoon.c tools/bneptest.c tools/gatt-service.c tools/rctest.c tools/rfcomm-tester.c tools/hcieventmask.c tools/hciattach_ti.c tools/seq2bseq.c tools/scotest.c tools/bcmfw.c tools/hciconfig.c tools/btattach.c tools/l2ping.c tools/obexctl.c tools/l2test.c tools/hciattach_intel.c tools/hciattach.h tools/create-image.c tools/bnep-tester.c tools/userchan-tester.c tools/rfcomm.c tools/btmon-logger.c tools/hcidump.c tools/rtlfw.c tools/hciattach_qualcomm.c tools/btproxy.c tools/nokfw.c tools/hciattach_ath3k.c tools/3dsp.c tools/bdaddr.c tools/sco-tester.c tools/hciattach.c tools/amptest.c tools/btgatt-server.c tools/btgatt-client.c tools/cltest.c tools/ibeacon.c tools/mcaptest.c tools/hid2hci.c tools/btmgmt.c tools/advtest.c tools/eddystone.c tools/avtest.c tools/mpris-proxy.c tools/avinfo.c tools/sdptool.c tools/btconfig.c tools/update_compids.sh tools/parser/parser.h tools/parser/obex.c tools/parser/amp.c tools/parser/sdp.c tools/parser/tcpip.c tools/parser/sap.c tools/parser/cmtp.c tools/parser/avctp.c tools/parser/lmp.c tools/parser/ppp.c tools/parser/rfcomm.h tools/parser/hci.c tools/parser/sdp.h tools/parser/parser.c tools/parser/rfcomm.c tools/parser/avdtp.c tools/parser/avrcp.c tools/parser/ericsson.c tools/parser/hcrp.c tools/parser/bpa.c tools/parser/hidp.c tools/parser/bnep.c tools/parser/capi.c tools/parser/att.c tools/parser/l2cap.c tools/parser/smp.c tools/parser/csr.c tools/parser/l2cap.h tools/parse_companies.pl License: LGPL-2.1-or-later tools/test-runner.c tools/btpclient.c tools/meshctl.c tools/mesh-cfgclient.c tools/mesh/model.h tools/mesh/util.h tools/mesh/config-model.h tools/mesh/cfgcli.h tools/mesh/mesh-db.c tools/mesh/mesh-db.h tools/mesh/keys.c tools/mesh/util.c tools/mesh/agent.h tools/mesh/remote.c tools/mesh/keys.h tools/mesh/agent.c tools/mesh/cfgcli.c tools/mesh/remote.h tools/mesh-gatt/prov.c tools/mesh-gatt/util.h tools/mesh-gatt/prov.h tools/mesh-gatt/net.c tools/mesh-gatt/util.c tools/mesh-gatt/prov-db.h tools/mesh-gatt/crypto.c tools/mesh-gatt/crypto.h tools/mesh-gatt/gatt.c tools/mesh-gatt/config-server.c tools/mesh-gatt/keys.h tools/mesh-gatt/onoff-model.c tools/mesh-gatt/net.h tools/mesh-gatt/gatt.h tools/mesh-gatt/node.c tools/mesh-gatt/config-client.c tools/mesh-gatt/mesh-net.h tools/mesh-gatt/node.h tools/mesh-gatt/onoff-model.h tools/mesh-gatt/prov-db.c License: GPL-2.0-only tools/obex-server-tool.c tools/obex-client-tool.c
695 lines
15 KiB
C
695 lines
15 KiB
C
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
/*
|
|
*
|
|
* BlueZ - Bluetooth protocol stack for Linux
|
|
*
|
|
* Copyright (C) 2015 Intel Corporation
|
|
*
|
|
*
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include <config.h>
|
|
#endif
|
|
|
|
#define _GNU_SOURCE
|
|
#include <stdio.h>
|
|
#include <signal.h>
|
|
#include <stdlib.h>
|
|
#include <getopt.h>
|
|
#include <stdbool.h>
|
|
#include <errno.h>
|
|
#include <unistd.h>
|
|
#include <sys/ioctl.h>
|
|
#include <net/if.h>
|
|
#include <linux/sockios.h>
|
|
#include <netinet/in.h>
|
|
#include <linux/if_bridge.h>
|
|
|
|
#include <glib.h>
|
|
|
|
#include "lib/bluetooth.h"
|
|
#include "lib/hci.h"
|
|
#include "lib/hci_lib.h"
|
|
|
|
#include "src/log.h"
|
|
#include "src/shared/util.h"
|
|
#include "btio/btio.h"
|
|
#include "lib/bnep.h"
|
|
#include "profiles/network/bnep.h"
|
|
|
|
enum {
|
|
MODE_LISTEN,
|
|
MODE_CONNECT,
|
|
};
|
|
|
|
static GMainLoop *mloop;
|
|
static GIOChannel *bnep_io;
|
|
static struct bnep *session;
|
|
|
|
static int mode;
|
|
static bool no_close_after_disconn;
|
|
static int send_frame_timeout;
|
|
|
|
static bdaddr_t src_addr, dst_addr;
|
|
static char iface[16];
|
|
static char bridge[16];
|
|
static bool send_ctrl_msg_type_set = false;
|
|
static uint8_t ctrl_msg_type = 0x00;
|
|
static bool send_bnep_msg_type_set = false;
|
|
static uint8_t bnep_msg_type = 0x00;
|
|
static int ctrl_msg_retransmition_nb = 0;
|
|
static int bnep_msg_retransmission_nb = 0;
|
|
static uint16_t local_role = BNEP_SVC_PANU;
|
|
static uint16_t remote_role = BNEP_SVC_NAP;
|
|
static uint16_t ntw_proto_down_range = 0x0000;
|
|
static uint16_t ntw_proto_up_range = 0xdc05;
|
|
static uint16_t ntw_proto_type = 0x0000;
|
|
static uint8_t mcast_addr_down_range[6];
|
|
static uint8_t mcast_addr_up_range[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
|
static uint8_t src_hw_addr[6];
|
|
static uint8_t dst_hw_addr[6];
|
|
static uint8_t general_frame_payload[] = "abcdef0123456789_bnep_test_data";
|
|
|
|
static int set_forward_delay(int sk)
|
|
{
|
|
unsigned long args[4] = { BRCTL_SET_BRIDGE_FORWARD_DELAY, 0, 0, 0 };
|
|
struct ifreq ifr;
|
|
|
|
memset(&ifr, 0, sizeof(ifr));
|
|
strncpy(ifr.ifr_name, bridge, IFNAMSIZ);
|
|
ifr.ifr_data = (char *) args;
|
|
|
|
if (ioctl(sk, SIOCDEVPRIVATE, &ifr) < 0) {
|
|
error("setting forward delay failed: %d (%s)",
|
|
errno, strerror(errno));
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int nap_create_bridge(void)
|
|
{
|
|
int sk, err;
|
|
|
|
sk = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0);
|
|
if (sk < 0)
|
|
return -EOPNOTSUPP;
|
|
|
|
if (ioctl(sk, SIOCBRADDBR, bridge) < 0) {
|
|
if (errno != EEXIST) {
|
|
close(sk);
|
|
return -EOPNOTSUPP;
|
|
}
|
|
}
|
|
|
|
err = set_forward_delay(sk);
|
|
if (err < 0) {
|
|
printf("failed to set forward delay\n");
|
|
ioctl(sk, SIOCBRDELBR, bridge);
|
|
}
|
|
|
|
close(sk);
|
|
|
|
return err;
|
|
}
|
|
|
|
static int cleanup(void)
|
|
{
|
|
bnep_cleanup();
|
|
|
|
if (mode == MODE_LISTEN)
|
|
bnep_server_delete(bridge, iface, &dst_addr);
|
|
|
|
if (bnep_io) {
|
|
g_io_channel_shutdown(bnep_io, TRUE, NULL);
|
|
g_io_channel_unref(bnep_io);
|
|
bnep_io = NULL;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static gboolean bnep_watchdog_cb(GIOChannel *chan, GIOCondition cond,
|
|
gpointer user_data)
|
|
{
|
|
printf("%s\n", __func__);
|
|
|
|
if (no_close_after_disconn)
|
|
return FALSE;
|
|
|
|
/* Cleanup since it's called when disconnected l2cap */
|
|
if (cleanup() < 0) {
|
|
printf("cleanup went wrong...\n");
|
|
return FALSE;
|
|
}
|
|
|
|
g_main_loop_quit(mloop);
|
|
return FALSE;
|
|
}
|
|
|
|
static ssize_t send_compressed_frame(int sk, uint8_t type)
|
|
{
|
|
uint8_t frame[100];
|
|
|
|
printf("%s\n", __func__);
|
|
|
|
if (send_frame_timeout > 0) {
|
|
printf("waiting %d seconds before sending msg\n",
|
|
send_frame_timeout);
|
|
sleep(send_frame_timeout);
|
|
}
|
|
|
|
frame[0] = type;
|
|
memcpy(&frame[1], dst_hw_addr, sizeof(dst_hw_addr));
|
|
memcpy(&frame[7], src_hw_addr, sizeof(src_hw_addr));
|
|
frame[13] = ntw_proto_type & 0xff;
|
|
frame[14] = (ntw_proto_type >> 8);
|
|
memcpy(&frame[15], general_frame_payload,
|
|
sizeof(general_frame_payload));
|
|
|
|
/* TODO - set frame payload by user */
|
|
return send(sk, frame, 15 + sizeof(general_frame_payload), 0);
|
|
}
|
|
|
|
static ssize_t send_general_frame(int sk)
|
|
{
|
|
uint8_t frame[100];
|
|
|
|
printf("%s\n", __func__);
|
|
|
|
if (send_frame_timeout > 0) {
|
|
printf("waiting %d seconds before sending msg\n",
|
|
send_frame_timeout);
|
|
sleep(send_frame_timeout);
|
|
}
|
|
|
|
frame[0] = BNEP_GENERAL;
|
|
memcpy(&frame[1], dst_hw_addr, sizeof(dst_hw_addr));
|
|
memcpy(&frame[7], src_hw_addr, sizeof(src_hw_addr));
|
|
frame[13] = ntw_proto_type & 0xff;
|
|
frame[14] = (ntw_proto_type >> 8);
|
|
memcpy(&frame[15], general_frame_payload,
|
|
sizeof(general_frame_payload));
|
|
|
|
/* TODO - set frame payload by user */
|
|
return send(sk, frame, 15 + sizeof(general_frame_payload), 0);
|
|
}
|
|
|
|
static ssize_t send_ctrl_frame(int sk)
|
|
{
|
|
/*
|
|
* Max buff size = type(1byte) + ctrl(1byte) + len(2byte) +
|
|
* mcast_addr_down(6byte) + mcast_addr_up(6byte)
|
|
*/
|
|
uint8_t buff[16];
|
|
struct bnep_set_filter_req *frame = (void *) buff;
|
|
int err;
|
|
|
|
printf("%s\n", __func__);
|
|
|
|
if (send_frame_timeout > 0) {
|
|
printf("waiting %d seconds before sending msg\n",
|
|
send_frame_timeout);
|
|
sleep(send_frame_timeout);
|
|
}
|
|
|
|
switch (ctrl_msg_type) {
|
|
case BNEP_FILTER_NET_TYPE_SET:
|
|
frame->type = BNEP_CONTROL;
|
|
frame->ctrl = ctrl_msg_type;
|
|
frame->len = htons(sizeof(ntw_proto_down_range) +
|
|
sizeof(ntw_proto_up_range));
|
|
memcpy(frame->list, &ntw_proto_down_range,
|
|
sizeof(ntw_proto_down_range));
|
|
memcpy(frame->list + sizeof(ntw_proto_down_range),
|
|
&ntw_proto_up_range, sizeof(ntw_proto_up_range));
|
|
|
|
err = send(sk, frame, sizeof(*frame) +
|
|
sizeof(ntw_proto_down_range) +
|
|
sizeof(ntw_proto_up_range), 0);
|
|
break;
|
|
case BNEP_FILTER_MULT_ADDR_SET:
|
|
frame->type = BNEP_CONTROL;
|
|
frame->ctrl = ctrl_msg_type;
|
|
frame->len = htons(sizeof(mcast_addr_down_range) +
|
|
sizeof(mcast_addr_up_range));
|
|
memcpy(frame->list, mcast_addr_down_range,
|
|
sizeof(mcast_addr_down_range));
|
|
memcpy(frame->list + sizeof(mcast_addr_down_range),
|
|
mcast_addr_up_range, sizeof(mcast_addr_up_range));
|
|
|
|
err = send(sk, frame, sizeof(*frame) +
|
|
sizeof(mcast_addr_down_range) +
|
|
sizeof(mcast_addr_up_range), 0);
|
|
break;
|
|
default:
|
|
err = -1;
|
|
break;
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
static int send_bnep_frame(int sk)
|
|
{
|
|
int err;
|
|
|
|
switch (bnep_msg_type) {
|
|
case BNEP_GENERAL:
|
|
err = send_general_frame(sk);
|
|
break;
|
|
case BNEP_COMPRESSED:
|
|
err = send_compressed_frame(sk, BNEP_COMPRESSED);
|
|
break;
|
|
case BNEP_COMPRESSED_SRC_ONLY:
|
|
err = send_compressed_frame(sk,
|
|
BNEP_COMPRESSED_SRC_ONLY);
|
|
break;
|
|
case BNEP_COMPRESSED_DST_ONLY:
|
|
err = send_compressed_frame(sk,
|
|
BNEP_COMPRESSED_DST_ONLY);
|
|
break;
|
|
default:
|
|
printf("wrong bnep_msg_type 0x%02x\n", bnep_msg_type);
|
|
err = -EINVAL;
|
|
break;
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
static void handle_bnep_msg_send(int sk)
|
|
{
|
|
if (send_ctrl_msg_type_set) {
|
|
do {
|
|
if (send_ctrl_frame(sk) < 0)
|
|
printf("sending ctrl frame error: %s (%d)\n",
|
|
strerror(errno), errno);
|
|
} while (ctrl_msg_retransmition_nb--);
|
|
}
|
|
|
|
if (send_bnep_msg_type_set) {
|
|
do {
|
|
if (send_bnep_frame(sk) < 0)
|
|
printf("sending bnep frame error: %s (%d)\n",
|
|
strerror(errno), errno);
|
|
} while (bnep_msg_retransmission_nb--);
|
|
}
|
|
}
|
|
|
|
static gboolean setup_bnep_cb(GIOChannel *chan, GIOCondition cond,
|
|
gpointer user_data)
|
|
{
|
|
uint8_t packet[BNEP_MTU];
|
|
int sk, n, err;
|
|
|
|
printf("%s\n", __func__);
|
|
|
|
if (cond & (G_IO_ERR | G_IO_HUP | G_IO_NVAL)) {
|
|
error("hangup or error or inval on BNEP socket");
|
|
return FALSE;
|
|
}
|
|
|
|
sk = g_io_channel_unix_get_fd(chan);
|
|
|
|
/* Reading BNEP_SETUP_CONNECTION_REQUEST_MSG */
|
|
n = recv(sk, packet, sizeof(packet), MSG_PEEK);
|
|
if (n < 0) {
|
|
error("read(): %s(%d)", strerror(errno), errno);
|
|
return FALSE;
|
|
}
|
|
|
|
err = nap_create_bridge();
|
|
if (err < 0) {
|
|
error("failed to create bridge: %s (%d)", strerror(-err), err);
|
|
return FALSE;
|
|
}
|
|
|
|
if (bnep_server_add(sk, (err < 0) ? NULL : bridge, iface, &dst_addr,
|
|
packet, n) < 0) {
|
|
printf("server_connadd failed\n");
|
|
cleanup();
|
|
return FALSE;
|
|
}
|
|
|
|
g_io_add_watch(chan, G_IO_HUP | G_IO_ERR | G_IO_NVAL, bnep_watchdog_cb,
|
|
NULL);
|
|
|
|
handle_bnep_msg_send(sk);
|
|
|
|
g_io_channel_unref(bnep_io);
|
|
bnep_io = NULL;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static void connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
|
|
{
|
|
printf("%s\n", __func__);
|
|
|
|
if (err) {
|
|
error("%s", err->message);
|
|
return;
|
|
}
|
|
|
|
g_io_add_watch(chan, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
|
|
setup_bnep_cb, NULL);
|
|
}
|
|
|
|
static void connected_client_cb(char *iface, int err, void *data)
|
|
{
|
|
int sk = PTR_TO_INT(data);
|
|
|
|
printf("%s\n", __func__);
|
|
|
|
handle_bnep_msg_send(sk);
|
|
}
|
|
|
|
static void disconnected_client_cb(void *data)
|
|
{
|
|
printf("%s\n", __func__);
|
|
|
|
if (no_close_after_disconn)
|
|
return;
|
|
|
|
/* Cleanup since it's called when disconnected l2cap */
|
|
if (cleanup() < 0) {
|
|
printf("cleanup went wrong...\n");
|
|
return;
|
|
}
|
|
|
|
g_main_loop_quit(mloop);
|
|
}
|
|
|
|
static void connect_client_cb(GIOChannel *chan, GError *err, gpointer user_data)
|
|
{
|
|
int perr;
|
|
int sk;
|
|
|
|
sk = g_io_channel_unix_get_fd(bnep_io);
|
|
|
|
session = bnep_new(sk, local_role, remote_role, bridge);
|
|
if (!session) {
|
|
printf("cannot create bnep session\n");
|
|
return;
|
|
}
|
|
|
|
perr = bnep_connect(session, connected_client_cb,
|
|
disconnected_client_cb, INT_TO_PTR(sk), NULL);
|
|
if (perr < 0)
|
|
printf("cannot initiate bnep connection\n");
|
|
}
|
|
|
|
static void confirm_cb(GIOChannel *chan, gpointer data)
|
|
{
|
|
GError *err = NULL;
|
|
char address[18];
|
|
|
|
printf("%s\n", __func__);
|
|
|
|
bt_io_get(chan, &err, BT_IO_OPT_DEST_BDADDR, &dst_addr, BT_IO_OPT_DEST,
|
|
address, BT_IO_OPT_INVALID);
|
|
if (err) {
|
|
error("%s", err->message);
|
|
g_error_free(err);
|
|
return;
|
|
}
|
|
|
|
printf("incoming connection from: %s\n", address);
|
|
|
|
bnep_io = g_io_channel_ref(chan);
|
|
g_io_channel_set_close_on_unref(bnep_io, TRUE);
|
|
|
|
if (!bt_io_accept(bnep_io, connect_cb, NULL, NULL, &err)) {
|
|
error("bt_io_accept: %s", err->message);
|
|
g_error_free(err);
|
|
g_io_channel_unref(bnep_io);
|
|
}
|
|
}
|
|
|
|
static int bnep_server_listen(void)
|
|
{
|
|
GError *gerr = NULL;
|
|
|
|
printf("%s\n", __func__);
|
|
|
|
bnep_io = bt_io_listen(NULL, confirm_cb, NULL, NULL, &gerr,
|
|
BT_IO_OPT_SOURCE_BDADDR, &src_addr,
|
|
BT_IO_OPT_PSM, BNEP_PSM,
|
|
BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
|
|
BT_IO_OPT_OMTU, BNEP_MTU,
|
|
BT_IO_OPT_IMTU, BNEP_MTU,
|
|
BT_IO_OPT_INVALID);
|
|
if (!bnep_io) {
|
|
printf("can't start server listening: err %s\n", gerr->message);
|
|
g_error_free(gerr);
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int bnep_client_connect(void)
|
|
{
|
|
GError *gerr = NULL;
|
|
char bdastr[18];
|
|
|
|
printf("%s\n", __func__);
|
|
|
|
ba2str(&dst_addr, bdastr);
|
|
printf("connecting %s\n", bdastr);
|
|
|
|
bnep_io = bt_io_connect(connect_client_cb, NULL, NULL, &gerr,
|
|
BT_IO_OPT_SOURCE_BDADDR, &src_addr,
|
|
BT_IO_OPT_DEST_BDADDR, &dst_addr,
|
|
BT_IO_OPT_PSM, BNEP_PSM,
|
|
BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
|
|
BT_IO_OPT_OMTU, BNEP_MTU,
|
|
BT_IO_OPT_IMTU, BNEP_MTU,
|
|
BT_IO_OPT_INVALID);
|
|
if (!bnep_io) {
|
|
printf("cannot connect: err %s\n", gerr->message);
|
|
g_error_free(gerr);
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void exit_handler(int sig)
|
|
{
|
|
printf("got sig = %d, cleaning up...\n", sig);
|
|
|
|
if (cleanup() < 0)
|
|
printf("cleanup failure...\n");
|
|
else
|
|
printf("cleanup successful - exit\n");
|
|
|
|
exit(0);
|
|
}
|
|
|
|
static void usage(void)
|
|
{
|
|
printf("bneptest - BNEP testing ver %s\n", VERSION);
|
|
printf("Usage:\n"
|
|
"\tbneptest [-i] -b <bridge name> -n <iface name>"
|
|
" <connection mode> [send_ctrl_cmd] [options]\n"
|
|
"\t-i hci dev number <hci number>, def. 0\n"
|
|
"\t-b bridge name <string>\n"
|
|
"\t-n interface name <string>\n");
|
|
printf("Connect Mode:\n"
|
|
"\t-c connect <dst_addr>\n"
|
|
"\t-r remote role <16 bit svc value>\n"
|
|
"\t-l local role <16 bit svc valu>\n");
|
|
printf("Listen Mode:\n"
|
|
"\t-s start server listening\n");
|
|
printf("Send control command:\n"
|
|
"\t-t send message type <control msg type>, def. 0\n"
|
|
"\t-e start network protocol type range <16 bit val>, def. 0\n"
|
|
"\t-d end network protocol type range <16 bit val>, def. 1500\n"
|
|
"\t-g start multicast addr range <xx:xx:xx:xx:xx:xx>, def. 0\n"
|
|
"\t-j end multicast addr range <xx:xx:xx:xx:xx:xx>, def. f\n"
|
|
"\t-y number of ctrl frame retransmission <integer>, def. 0\n"
|
|
"\t-u number of bnep frame retransmission <integer>, def. 0\n");
|
|
printf("Send bnep generic frame:\n"
|
|
"\t-w send bnep generic frame <bnep generic type>, def. 0\n"
|
|
"\t-k set src mac addr <xx:xx:xx:xx:xx:xx>, def. 0\n"
|
|
"\t-f set dst mac addr <xx:xx:xx:xx:xx:xx>, def. 0\n");
|
|
printf("Options:\n"
|
|
"\t-T send message timeout after setup <seconds>\n"
|
|
"\t-N don't close bneptest after disconnect\n");
|
|
}
|
|
|
|
static struct option main_options[] = {
|
|
{ "device", 1, 0, 'i' },
|
|
{ "listen", 0, 0, 's' },
|
|
{ "connect", 1, 0, 'c' },
|
|
{ "snd_ctrl_msg_type", 1, 0, 't' },
|
|
{ "snd_bnep_msg_type", 1, 0, 'w' },
|
|
{ "src_hw_addr", 1, 0, 'k' },
|
|
{ "dst_hw_addr", 1, 0, 'f' },
|
|
{ "send_timeout", 1, 0, 'T' },
|
|
{ "ntw_proto_down_range", 1, 0, 'd' },
|
|
{ "ntw_proto_up_range", 1, 0, 'e' },
|
|
{ "mcast_addr_down_range", 1, 0, 'g' },
|
|
{ "mcast_addr_up_range", 1, 0, 'j' },
|
|
{ "local_role", 1, 0, 'l' },
|
|
{ "remote_role", 1, 0, 'r' },
|
|
{ "bridge name", 1, 0, 'b' },
|
|
{ "iface name", 1, 0, 'n' },
|
|
{ "no_close", 0, 0, 'N' },
|
|
{ "retrans_ctrl_nb", 0, 0, 'y' },
|
|
{ "retrans_bnep_nb", 0, 0, 'u' },
|
|
{ "help", 0, 0, 'h' },
|
|
{ 0, 0, 0, 0 }
|
|
};
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
int opt, i;
|
|
int err;
|
|
bool is_set_b_name = false, is_set_i_name = false;
|
|
|
|
DBG("");
|
|
|
|
signal(SIGINT, exit_handler);
|
|
|
|
hci_devba(0, &src_addr);
|
|
bacpy(&src_addr, BDADDR_ANY);
|
|
|
|
mloop = g_main_loop_new(NULL, FALSE);
|
|
if (!mloop) {
|
|
printf("cannot create main loop\n");
|
|
|
|
exit(1);
|
|
}
|
|
|
|
while ((opt = getopt_long(argc, argv,
|
|
"+i:c:b:n:t:T:d:e:g:j:k:f:w:l:r:y:u:Nsh",
|
|
main_options, NULL)) != EOF) {
|
|
switch (opt) {
|
|
case 'i':
|
|
if (!strncmp(optarg, "hci", 3))
|
|
hci_devba(atoi(optarg + 3), &src_addr);
|
|
else
|
|
str2ba(optarg, &src_addr);
|
|
break;
|
|
case 's':
|
|
mode = MODE_LISTEN;
|
|
break;
|
|
case 'c':
|
|
str2ba(optarg, &dst_addr);
|
|
mode = MODE_CONNECT;
|
|
break;
|
|
case 't':
|
|
send_ctrl_msg_type_set = true;
|
|
ctrl_msg_type = atoi(optarg);
|
|
break;
|
|
case 'w':
|
|
send_bnep_msg_type_set = true;
|
|
bnep_msg_type = atoi(optarg);
|
|
break;
|
|
case 'k':
|
|
for (i = 0; i <= 5; i++, optarg += 3)
|
|
src_hw_addr[i] = strtol(optarg, NULL, 16);
|
|
break;
|
|
case 'f':
|
|
for (i = 0; i <= 5; i++, optarg += 3)
|
|
dst_hw_addr[i] = strtol(optarg, NULL, 16);
|
|
break;
|
|
case 'T':
|
|
send_frame_timeout = atoi(optarg);
|
|
break;
|
|
case 'd':
|
|
ntw_proto_down_range = htons(atoi(optarg));
|
|
break;
|
|
case 'e':
|
|
ntw_proto_up_range = htons(atoi(optarg));
|
|
break;
|
|
case 'g':
|
|
for (i = 5; i >= 0; i--, optarg += 3)
|
|
mcast_addr_down_range[i] =
|
|
strtol(optarg, NULL, 16);
|
|
break;
|
|
case 'j':
|
|
for (i = 5; i >= 0; i--, optarg += 3)
|
|
mcast_addr_up_range[i] =
|
|
strtol(optarg, NULL, 16);
|
|
break;
|
|
case 'l':
|
|
local_role = atoi(optarg);
|
|
break;
|
|
case 'r':
|
|
remote_role = atoi(optarg);
|
|
break;
|
|
case 'b':
|
|
strncpy(bridge, optarg, 16);
|
|
bridge[15] = '\0';
|
|
is_set_b_name = true;
|
|
break;
|
|
case 'n':
|
|
strncpy(iface, optarg, 14);
|
|
strcat(iface, "\%d");
|
|
iface[15] = '\0';
|
|
is_set_i_name = true;
|
|
break;
|
|
case 'N':
|
|
no_close_after_disconn = true;
|
|
break;
|
|
case 'y':
|
|
ctrl_msg_retransmition_nb = atoi(optarg);
|
|
break;
|
|
case 'u':
|
|
bnep_msg_retransmission_nb = atoi(optarg);
|
|
break;
|
|
case 'h':
|
|
default:
|
|
usage();
|
|
exit(0);
|
|
}
|
|
}
|
|
|
|
if (!is_set_b_name || !is_set_i_name) {
|
|
printf("bridge, interface name must be set!\n");
|
|
exit(1);
|
|
}
|
|
|
|
switch (mode) {
|
|
case MODE_CONNECT:
|
|
err = bnep_init();
|
|
if (err < 0) {
|
|
printf("cannot initialize bnep\n");
|
|
exit(1);
|
|
}
|
|
err = bnep_client_connect();
|
|
if (err < 0)
|
|
exit(1);
|
|
|
|
break;
|
|
case MODE_LISTEN:
|
|
err = bnep_init();
|
|
if (err < 0) {
|
|
printf("cannot initialize bnep\n");
|
|
exit(1);
|
|
}
|
|
err = bnep_server_listen();
|
|
if (err < 0)
|
|
exit(1);
|
|
|
|
break;
|
|
default:
|
|
printf("connect/listen mode not set, exit...\n");
|
|
exit(1);
|
|
}
|
|
|
|
g_main_loop_run(mloop);
|
|
|
|
printf("Done\n");
|
|
|
|
g_main_loop_unref(mloop);
|
|
|
|
return 0;
|
|
}
|