Commit 26afa868 authored by Daniel P. Berrangé's avatar Daniel P. Berrangé Committed by Paolo Bonzini
Browse files

nbd: make server compliant with fixed newstyle spec



If the client does not request the fixed new style protocol,
then we should only accept NBD_OPT_EXPORT_NAME. All other
options are only valid when fixed new style has been activated.

The qemu-nbd client doesn't currently request fixed new style
protocol, but this change won't break qemu-nbd, because it
fortunately only ever uses NBD_OPT_EXPORT_NAME, so was never
triggering the non-compliant server behaviour.

Signed-off-by: default avatarDaniel P. Berrange <berrange@redhat.com>
Message-Id: <1455129674-17255-9-git-send-email-berrange@redhat.com>
Signed-off-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
parent f72d705f
Loading
Loading
Loading
Loading
+46 −23
Original line number Diff line number Diff line
@@ -310,6 +310,7 @@ fail:
static int nbd_negotiate_options(NBDClient *client)
{
    uint32_t flags;
    bool fixedNewstyle = false;

    /* Client sends:
        [ 0 ..   3]   client flags
@@ -332,14 +333,19 @@ static int nbd_negotiate_options(NBDClient *client)
    }
    TRACE("Checking client flags");
    be32_to_cpus(&flags);
    if (flags != 0 && flags != NBD_FLAG_C_FIXED_NEWSTYLE) {
        LOG("Bad client flags received");
    if (flags & NBD_FLAG_C_FIXED_NEWSTYLE) {
        TRACE("Support supports fixed newstyle handshake");
        fixedNewstyle = true;
        flags &= ~NBD_FLAG_C_FIXED_NEWSTYLE;
    }
    if (flags != 0) {
        TRACE("Unknown client flags 0x%x received", flags);
        return -EIO;
    }

    while (1) {
        int ret;
        uint32_t tmp, length;
        uint32_t clientflags, length;
        uint64_t magic;

        if (nbd_negotiate_read(client->ioc, &magic, sizeof(magic)) !=
@@ -353,10 +359,12 @@ static int nbd_negotiate_options(NBDClient *client)
            return -EINVAL;
        }

        if (nbd_negotiate_read(client->ioc, &tmp, sizeof(tmp)) != sizeof(tmp)) {
        if (nbd_negotiate_read(client->ioc, &clientflags,
                               sizeof(clientflags)) != sizeof(clientflags)) {
            LOG("read failed");
            return -EINVAL;
        }
        clientflags = be32_to_cpu(clientflags);

        if (nbd_negotiate_read(client->ioc, &length, sizeof(length)) !=
            sizeof(length)) {
@@ -365,8 +373,9 @@ static int nbd_negotiate_options(NBDClient *client)
        }
        length = be32_to_cpu(length);

        TRACE("Checking option");
        switch (be32_to_cpu(tmp)) {
        TRACE("Checking option 0x%x", clientflags);
        if (fixedNewstyle) {
            switch (clientflags) {
            case NBD_OPT_LIST:
                ret = nbd_negotiate_handle_list(client, length);
                if (ret < 0) {
@@ -381,11 +390,25 @@ static int nbd_negotiate_options(NBDClient *client)
                return nbd_negotiate_handle_export_name(client, length);

            default:
            tmp = be32_to_cpu(tmp);
            LOG("Unsupported option 0x%x", tmp);
            nbd_negotiate_send_rep(client->ioc, NBD_REP_ERR_UNSUP, tmp);
                TRACE("Unsupported option 0x%x", clientflags);
                nbd_negotiate_send_rep(client->ioc, NBD_REP_ERR_UNSUP,
                                       clientflags);
                return -EINVAL;
            }
        } else {
            /*
             * If broken new-style we should drop the connection
             * for anything except NBD_OPT_EXPORT_NAME
             */
            switch (clientflags) {
            case NBD_OPT_EXPORT_NAME:
                return nbd_negotiate_handle_export_name(client, length);

            default:
                TRACE("Unsupported option 0x%x", clientflags);
                return -EINVAL;
            }
        }
    }
}