本文介绍了蓝牙与DisplayOnly配对仅不显示密码框的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试为Linux配置与蓝牙手机配对的蓝牙芯片.我将在一个显示屏上显示一个6位数的密码,因此我试图将Bluetoothctl代理设置为DisplayOnly.

I am trying to configure a bluetooth chip for linux to pair with an android phone. I will have a display on which I am able to show a 6 digit passkey, so I am trying to set the Bluetoothctl agent to DisplayOnly.

根据此帖子中的表格 https://www.silabs.com/community/wireless/bluetooth/knowledge-base.entry.html/2016/07/11/bt121_-_legacy_pairi-MnCo 如果响应者为DisplayOnly,而发起者(Android)为KeyboardDisplay,则应使用Passkey条目,其中响应者显示代码,发起者输入代码.

According to the table in this post https://www.silabs.com/community/wireless/bluetooth/knowledge-base.entry.html/2016/07/11/bt121_-_legacy_pairi-MnCoIf the responder is DisplayOnly, and the initiator (Android) is KeyboardDisplay, it should use Passkey entry, with the responder displaying the code and the initiator entering the code.

实际上发生的是,Android在尝试配对时什么也没显示,并且bluetoothctl输出显示了数字比较响应是/否":即使我指定我没有任何输入(DisplayOnly)

What actually happens is the Android shows nothing when attempting to pair, and the bluetoothctl output shows a Numeric Comparison response yes/no: even though I specified I don't have any input (DisplayOnly)

我如何才能使bluez代理实际用作DisplayOnly,以便它显示供我输入Android上的密码?

How can I get the bluez agent to actually work as DisplayOnly so it shows a passkey for me to enter on the Android?

推荐答案

对URL中提到的配对选项的理解是完美的,但是BlueZ不能以相同的方式工作.要在此处进行简单讨论,请考虑蓝牙配对博客中的解释来自蓝牙SIG.

Understanding about pairing options mentioned in the URL are perfect, but BlueZ doesn't work in the same way. To simply the discussion here, please consider the explanation from Bluetooth Pairing blog from Bluetooth SIG.

为简单起见,下面的图片是从上述博客中复制的.

To simplify, the below image is copied from the above mentioned blog.

因此,输入可以是无输入",是/否"和键盘"三种形式.输出可以是无输出"和数值输出".

So input can be three forms "No Input", "Yes/No" and "Keyboard". Output can be "No Output" and "Numeric Output".

在您的情况下,Android是您要输入显示在响应程序中的密码的发起方.因此,Android设备的输入为键盘",响应者为数字输出".

In your case, Android is the initiator where you want to enter the passkey which is displayed in responder. So Android device's input is "Keyboard" and responder is "Numeric Output" capable.

要解决此问题,您需要在响应器中指定"DisplayOnly"(您已经正确),并在输入的Android设备中指定"KeyboardOnly"或"KeyboardDisplay".

To achieve your case, you need to specify "DisplayOnly" in responder (you are already correct) and "KeyboardOnly" or "KeyboardDisplay" in input Android device.

但是BlueZ默认不将"KeyboardDisplay"作为单独的选项,而是将其转换/认为是"DisplayYesNO",请参阅mgmt.txt API中的此处.因此,您的android输入设备会充当"DisplayYesNo"并引起混乱.

But BlueZ by default doesn't treat "KeyboardDisplay" as a separate option, instead it converts/considers it as "DisplayYesNO", see here in mgmt.txt API for more details. So your android input device acts as "DisplayYesNo" and results in confusion.

因此,您需要在响应者上使用"DisplayOnly",在发起者端使用"KeyboardOnly".要使用自定义代理(不使用bluetoothctl的代理)试验此用例,请使用以下示例示例(注意:未完全实现,来自stdin的fscanf不好:-(等)

So you need to use "DisplayOnly" at responder and "KeyboardOnly" at initiator end. To experiment this use case with custom agent (not using bluetoothctl's agent), use the below sample example (Note: Not fully implemented, fscanf from stdin is bad :-(, etc.,)

/*
 * gcc `pkg-config --cflags glib-2.0 gio-2.0` -Wall -Wextra -o ./bin/agent ./agent.c `pkg-config --libs glib-2.0 gio-2.0`
 */
#include <glib.h>
#include <gio/gio.h>
#include <stdio.h>

GMainLoop *loop;
GDBusConnection *con;
#define AGENT_PATH  "/org/bluez/AutoPinAgent"

static void bluez_agent_method_call(GDBusConnection *conn,
                    const gchar *sender,
                    const gchar *path,
                    const gchar *interface,
                    const gchar *method,
                    GVariant *params,
                    GDBusMethodInvocation *invocation,
                    void *userdata)
{
    int pass;
    int entered;
    char *opath;
    GVariant *p= g_dbus_method_invocation_get_parameters(invocation);

    g_print("Agent method call: %s.%s()\n", interface, method);
    if(!strcmp(method, "RequestPinCode")) {
        ;
    }
    else if(!strcmp(method, "DisplayPinCode")) {
        ;
    }
    else if(!strcmp(method, "RequestPasskey")) {
        g_print("Getting the Pin from user: ");
        fscanf(stdin, "%d", &pass);
        g_print("\n");
        g_dbus_method_invocation_return_value(invocation, g_variant_new("(u)", pass));
    }
    else if(!strcmp(method, "DisplayPasskey")) {
        g_variant_get(params, "(ouq)", &opath, &pass, &entered);
        g_print("Path: %s Pass: %d Entered: %d\n", opath, pass, entered);
        g_dbus_method_invocation_return_value(invocation, NULL);
    }
    else if(!strcmp(method, "RequestConfirmation")) {
        g_variant_get(params, "(ou)", &opath, &pass);
        g_print("Path: %s Pass: %d\n", opath, pass);
        g_dbus_method_invocation_return_value(invocation, NULL);
    }
    else if(!strcmp(method, "RequestAuthorization")) {
        ;
    }
    else if(!strcmp(method, "AuthorizeService")) {
        ;
    }
    else if(!strcmp(method, "Cancel")) {
        ;
    }
    else
        g_print("We should not come here, unknown method\n");
}

static const GDBusInterfaceVTable agent_method_table = {
    .method_call = bluez_agent_method_call,
};

int bluez_register_agent(GDBusConnection *con)
{
    GError *error = NULL;
    guint id = 0;
    GDBusNodeInfo *info = NULL;

    static const gchar bluez_agent_introspection_xml[] =
        "<node name='/org/bluez/SampleAgent'>"
        "   <interface name='org.bluez.Agent1'>"
        "       <method name='Release'>"
        "       </method>"
        "       <method name='RequestPinCode'>"
        "           <arg type='o' name='device' direction='in' />"
        "           <arg type='s' name='pincode' direction='out' />"
        "       </method>"
        "       <method name='DisplayPinCode'>"
        "           <arg type='o' name='device' direction='in' />"
        "           <arg type='s' name='pincode' direction='in' />"
        "       </method>"
        "       <method name='RequestPasskey'>"
        "           <arg type='o' name='device' direction='in' />"
        "           <arg type='u' name='passkey' direction='out' />"
        "       </method>"
        "       <method name='DisplayPasskey'>"
        "           <arg type='o' name='device' direction='in' />"
        "           <arg type='u' name='passkey' direction='in' />"
        "           <arg type='q' name='entered' direction='in' />"
        "       </method>"
        "       <method name='RequestConfirmation'>"
        "           <arg type='o' name='device' direction='in' />"
        "           <arg type='u' name='passkey' direction='in' />"
        "       </method>"
        "       <method name='RequestAuthorization'>"
        "           <arg type='o' name='device' direction='in' />"
        "       </method>"
        "       <method name='AuthorizeService'>"
        "           <arg type='o' name='device' direction='in' />"
        "           <arg type='s' name='uuid' direction='in' />"
        "       </method>"
        "       <method name='Cancel'>"
        "       </method>"
        "   </interface>"
        "</node>";

    info = g_dbus_node_info_new_for_xml(bluez_agent_introspection_xml, &error);
    if(error) {
        g_printerr("Unable to create node: %s\n", error->message);
        g_clear_error(&error);
        return 0;
    }

    id = g_dbus_connection_register_object(con,
            AGENT_PATH,
            info->interfaces[0],
            &agent_method_table,
            NULL, NULL, &error);
    g_dbus_node_info_unref(info);
    //g_dbus_connection_unregister_object(con, id);
    /* call register method in AgentManager1 interface */
    return id;
}

static int bluez_agent_call_method(const gchar *method, GVariant *param)
{
    GVariant *result;
    GError *error = NULL;

    result = g_dbus_connection_call_sync(con,
            "org.bluez",
            "/org/bluez",
            "org.bluez.AgentManager1",
            method,
            param,
            NULL,
            G_DBUS_CALL_FLAGS_NONE,
            -1,
            NULL,
            &error);
    if(error != NULL) {
        g_print("Register %s: %s\n", AGENT_PATH, error->message);
        return 1;
    }

    g_variant_unref(result);
    return 0;
}

static int bluez_register_autopair_agent(const char *cap)
{
    int rc;

    rc = bluez_agent_call_method("RegisterAgent", g_variant_new("(os)", AGENT_PATH, cap));
    if(rc)
        return 1;

    rc = bluez_agent_call_method("RequestDefaultAgent", g_variant_new("(o)", AGENT_PATH));
    if(rc) {
        bluez_agent_call_method("UnregisterAgent", g_variant_new("(o)", AGENT_PATH));
        return 1;
    }

    return 0;
}


static void cleanup_handler(int signo)
{
    if (signo == SIGINT) {
        g_print("received SIGINT\n");
        g_main_loop_quit(loop);
    }
}

int main(int argc, char **argv)
{
    int id;
    int rc;

    if(argc < 2)
        return 1;

    if(signal(SIGINT, cleanup_handler) == SIG_ERR)
        g_print("can't catch SIGINT\n");

    con = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL);
    if(con == NULL) {
        g_print("Not able to get connection to system bus\n");
        return 1;
    }

    loop = g_main_loop_new(NULL, FALSE);

    id = bluez_register_agent(con);
    if(id == 0)
        goto fail;

    rc = bluez_register_autopair_agent(argv[1]);
    if(rc) {
        g_print("Not able to register default autopair agent\n");
        goto fail;
    }

    g_main_loop_run(loop);

fail:
    g_dbus_connection_unregister_object(con, id);
    g_object_unref(con);
    return 0;
}

要对此进行实验,必须禁用蓝牙"agent off"中的代理,并以以下方式打开代理,

To experiment this, you must disable agent in bluetoothctl "agent off" and turn on the agent as,

Responder: ./bin/agent "DisplayOnly"
Initiator: ./bin/agent "KeyboardOnly"

当您尝试与启动器配对时,DisplayPasskey将在响应器中被调用并显示6位数字PIN,启动器将调用RequestPasskey并从标准输入中获取输入PIN.

When you try to pair from initiator, DisplayPasskey will be called in responder and displays 6 digit PIN and initiator will call RequestPasskey and takes the input PIN from stdin.

这篇关于蓝牙与DisplayOnly配对仅不显示密码框的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

06-26 08:15
查看更多