Skip to content

HCI Bluetooth socket bind error on an arm crosscompiled environment #67632

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
thomaschiroux mannequin opened this issue Feb 11, 2015 · 2 comments
Closed

HCI Bluetooth socket bind error on an arm crosscompiled environment #67632

thomaschiroux mannequin opened this issue Feb 11, 2015 · 2 comments
Labels
extension-modules C modules in the Modules dir type-bug An unexpected behavior, bug, or error

Comments

@thomaschiroux
Copy link
Mannequin

thomaschiroux mannequin commented Feb 11, 2015

BPO 23444
Files
  • bluetooth_bind_arm.patch: patch file
  • Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

    Show more details

    GitHub fields:

    assignee = None
    closed_at = None
    created_at = <Date 2015-02-11.15:50:15.557>
    labels = ['extension-modules', 'type-bug']
    title = 'HCI Bluetooth socket bind error on an arm crosscompiled environment'
    updated_at = <Date 2015-02-11.16:05:05.047>
    user = 'https://bugs.python.org/ThomasChiroux'

    bugs.python.org fields:

    activity = <Date 2015-02-11.16:05:05.047>
    actor = 'Thomas.Chiroux'
    assignee = 'none'
    closed = False
    closed_date = None
    closer = None
    components = ['Extension Modules']
    creation = <Date 2015-02-11.15:50:15.557>
    creator = 'Thomas.Chiroux'
    dependencies = []
    files = ['38097']
    hgrepos = []
    issue_num = 23444
    keywords = ['patch']
    message_count = 1.0
    messages = ['235751']
    nosy_count = 1.0
    nosy_names = ['Thomas.Chiroux']
    pr_nums = []
    priority = 'normal'
    resolution = None
    stage = None
    status = 'open'
    superseder = None
    type = 'behavior'
    url = 'https://bugs.python.org/issue23444'
    versions = ['Python 3.4']

    @thomaschiroux
    Copy link
    Mannequin Author

    thomaschiroux mannequin commented Feb 11, 2015

    This bug bellow occurs only on my crosscompiled environment on arm (marvell armada 166): arm-pxa168-linux-gnueabi
    It does not seems to be a cross-compile issue: python compiles without problem and all unittests pass on the target device.

    description and first clues
    ---------------------------

    The problem is easyly reproducted using this script:

        #!/usr/bin/python
        import socket
        sock = socket.socket(socket.AF_BLUETOOTH, socket.SOCK_RAW, socket.BTPROTO_HCI)
        sock.bind((0,))

    which raises the following exception when run on the target device:

        Traceback (most recent call last):
          File "./test_bt.py", line 4, in <module>
             sock.bind((0,))
        OSError: [Errno 22] Invalid argument

    This does not give much clues, but strace does (i've filtered to display the
    two significant parts of strace)

    socket(PF_BLUETOOTH, SOCK_RAW|SOCK_CLOEXEC, 1) = 3
    bind(3, {sa_family=AF_UNSPEC, sa_data="\0\0\360\35\251\266s\316(U\3\0\0\0"}, 6) = -1 EINVAL (Invalid argument)
    

    (on a working environment, including arm, like a raspberry pi, strace gives the following result (and no traceback of course):

    socket(PF_BLUETOOTH, SOCK_RAW|SOCK_CLOEXEC, 1) = 3
    bind(3, {sa_family=AF_BLUETOOTH, sa_data="\0\0\0\0\0\0X\352\243\266\0\24\265\266"}, 6) = 0
    

    So, on the armada166, between the socket creation and the bind we lost the socket family (AF_UNSPEC instead of AF_BLUETOOTH).

    And That's why bind returns invalid argument.

    socketmodule and PyArg_ParseTuple
    ---------------------------------

    Now let's look at Modules/socketmodule.c:

    After some digging, i've found that the problem is in getsockaddrarg, in the AF_BLUETOOTH / BTPROTO_HCI case
    and more precisely on this line:

    https://hg.python.org/cpython/file/ab2c023a9432/Modules/socketmodule.c#l1449
    

    reproducted here:

        if (!PyArg_ParseTuple(args, "i", &_BT_HCI_MEMB(addr, dev))) {

    When we execute the PyArg_ParseTuple, the addr->hci_family is crunched (by zeros with my previous python sample).

    At this same place, i've done the following test:

        char buffer[8];
        memset(buffer, 0x55, 8);
        if (!PyArg_ParseTuple(args, "i", buffer) {
            PyErr_SetString(PyExc_OSError, "getsockaddrarg: "
                            "wrong format");
            return 0;
        }
        printf("CL: %d %d %d %d %d %d %d %d\n", buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], buffer[5], buffer[6], buffer[7]);
         
        memset(buffer, 0xAA, 8);
        if (!PyArg_ParseTuple(args, "i", buffer+1) {
            PyErr_SetString(PyExc_OSError, "getsockaddrarg: "
                            "wrong format");
            return 0;
        }
        printf("CL+1: %d %d %d %d %d %d %d %d\n", buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], buffer[5], buffer[6], buffer[7]);
         
                          
        memset(buffer, 0xBB, 8);
        if (!PyArg_ParseTuple(args, "i", buffer+2) {
            PyErr_SetString(PyExc_OSError, "getsockaddrarg: "
                            "wrong format");
            return 0;
        }
        printf("CL+2: %d %d %d %d %d %d %d %d\n", buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], buffer[5], buffer[6], buffer[7]);
                           
        memset(buffer, 0xcc, 8);
        if (!PyArg_ParseTuple(args, "i", buffer+3) {
            PyErr_SetString(PyExc_OSError, "getsockaddrarg: "
                            "wrong format");
            return 0;
        }
        printf("CL+3: %d %d %d %d %d %d %d %d\n", buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], buffer[5], buffer[6], buffer[7]);

    and the result is:

    CL: 0 0 0 0 85 85 85 85
    CL+1: 0 0 0 0 170 170 170 170
    CL+2: 0 0 0 0 187 187 187 187
    CL+3: 0 0 0 0 204 204 204 204
    

    (WTF ??)

    in a working environnement (tested on raspberry B+ / python 3.4.2 locally compiled) result is what we should expect:

    CL: 0 0 0 0 85 85 85 85
    CL+1: 170 0 0 0 0 170 170 170
    CL+2: 187 187 0 0 0 0 187 187
    CL+3: 204 204 204 0 0 0 0 204
    

    So on my box if PyArg_ParseTuple write on &addr->hci_dev if write 4 bytes from &addr->hci_family which is 2 bytes BEFORE &addr->hci_dev

    At this time I can not understand how it's possible.

    Remarks and patch
    -----------------

    Now I have several remarks and a working patch.

    • remark/question 1: why does PyArg_ParseTuple parse an int when addr->hci_dev is an unsigned short ?
      even in normal situation, when it works, writing on &addr->hci_dev overflow on the next two bytes which are btw addr->channel (more on that later)

    • remark/question 2: i've tried to dig more deeply inside PyArg_ParseTuple and found another odd thing, but I did not try to change it without knowing what I do:

    in Python/getargs.c, in convertsimple, int parsing result is not casted before returned:

    here: https://hg.python.org/cpython/file/ab2c023a9432/Python/getargs.c#l690

    (ival is a long). In all other cases (short, unsigned short, char, usigned char), they are casted before return.
    [disclosure: i've tested to add the cast and relaunched my bind test, it did not change anything, but it's still strange for me]

    • Now a working patch: here below and attached a working patch which results on a good socket bind, but now completely satisfiying:
        --- Python-3.4.2/Modules/socketmodule.c 2014-10-08 10:18:15.000000000 +0200
        +++ CC_PYTHON/Python-3.4.2/Modules/socketmodule.c   2015-02-11 15:42:35.173455634 +0100
        @@ -1446,11 +1446,12 @@ getsockaddrarg(PySocketSockObject *s, Py
                         return 0;
         #else
                     _BT_HCI_MEMB(addr, family) = AF_BLUETOOTH;
        -            if (!PyArg_ParseTuple(args, "i", &_BT_HCI_MEMB(addr, dev))) {
        +            if (!PyArg_ParseTuple(args, "H", &_BT_HCI_MEMB(addr, dev))) {
                         PyErr_SetString(PyExc_OSError, "getsockaddrarg: "
                                         "wrong format");
                         return 0;
                     }
        +            _BT_HCI_MEMB(addr, channel) = HCI_CHANNEL_RAW;
         #endif
                     *len_ret = sizeof *addr;
                     return 1;

    in short: I parse now an unsigned short instead of parsing an int which gives me a two bytes long elements which is stored well
    on addr->hci_dev without overloading addr->hci_family.

    But this modification alone is not enough: addr->hci_channel needed a good value.
    that's why i added _BT_HCI_MEMB(addr, channel) = HCI_CHANNEL_RAW;
    which sets addr->hci_channel to zero.
    (without this line, any value could be here)

    And that led me to another question/problem: how is hci_channel normally handled ?
    It does not seems to be a valid parameter of bind; behaviour without the patch will
    erase hci_channel while storing int value in hci_dev, so theorically we can assign
    a well defined int value in our bind method to both assign the wanted value in
    hci_dev and hci_channel, but it does not seems to be a proper way to do it.

    @thomaschiroux thomaschiroux mannequin added extension-modules C modules in the Modules dir type-bug An unexpected behavior, bug, or error labels Feb 11, 2015
    @thomaschiroux thomaschiroux mannequin changed the title HCI Bluetooth socket bind error on an arm crosscompiler environment HCI Bluetooth socket bind error on an arm crosscompiled environment Feb 11, 2015
    @ezio-melotti ezio-melotti transferred this issue from another repository Apr 10, 2022
    @serhiy-storchaka
    Copy link
    Member

    It should be fixed by #131668.

    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
    Labels
    extension-modules C modules in the Modules dir type-bug An unexpected behavior, bug, or error
    Projects
    None yet
    Development

    No branches or pull requests

    1 participant