static int nbd_negotiate_options(NBDClient *client, uint16_t myflags,
                                 Error **errp)
{
    uint32_t flags;
    bool fixedNewstyle = false;
    bool no_zeroes = false;
    /* Client sends:
        [ 0 ..   3]   client flags
       Then we loop until NBD_OPT_EXPORT_NAME or NBD_OPT_GO:
        [ 0 ..   7]   NBD_OPTS_MAGIC
        [ 8 ..  11]   NBD option
        [12 ..  15]   Data length
        ...           Rest of request
        [ 0 ..   7]   NBD_OPTS_MAGIC
        [ 8 ..  11]   Second NBD option
        [12 ..  15]   Data length
        ...           Rest of request
    */
    if (nbd_read(client->ioc, &flags, sizeof(flags), errp) < 0) {
        error_prepend(errp, "read failed: ");
        return -EIO;
    be32_to_cpus(&flags);
    trace_nbd_negotiate_options_flags(flags);
    if (flags & NBD_FLAG_C_FIXED_NEWSTYLE) {
        fixedNewstyle = true;
        flags &= ~NBD_FLAG_C_FIXED_NEWSTYLE;
    if (flags & NBD_FLAG_C_NO_ZEROES) {
        no_zeroes = true;
        flags &= ~NBD_FLAG_C_NO_ZEROES;
    if (flags != 0) {
        error_setg(errp, "Unknown client flags 0x%" PRIx32 " received", flags);
    while (1) {
        int ret;
        uint32_t option, length;
        uint64_t magic;
        if (nbd_read(client->ioc, &magic, sizeof(magic), errp) < 0) {
            error_prepend(errp, "read failed: ");
        magic = be64_to_cpu(magic);
        trace_nbd_negotiate_options_check_magic(magic);
        if (magic != NBD_OPTS_MAGIC) {
            error_setg(errp, "Bad magic received");
        if (nbd_read(client->ioc, &option,
                     sizeof(option), errp) < 0) {
            error_prepend(errp, "read failed: ");
        option = be32_to_cpu(option);
        if (nbd_read(client->ioc, &length, sizeof(length), errp) < 0) {
            error_prepend(errp, "read failed: ");
        length = be32_to_cpu(length);
        trace_nbd_negotiate_options_check_option(option,
                                                 nbd_opt_lookup(option));
        if (client->tlscreds &&
            client->ioc == (QIOChannel *)client->sioc) {
            QIOChannel *tioc;
            if (!fixedNewstyle) {
                error_setg(errp, "Unsupported option 0x%" PRIx32, option);
            switch (option) {
            case NBD_OPT_STARTTLS:
                if (length) {
                    /* Unconditionally drop the connection if the client
                     * can't start a TLS negotiation correctly */
                    return nbd_reject_length(client, length, option, true,
                                             errp);
                tioc = nbd_negotiate_handle_starttls(client, errp);
                if (!tioc) {
                    return -EIO;
                ret = 0;
                object_unref(OBJECT(client->ioc));
                client->ioc = QIO_CHANNEL(tioc);
                break;
            case NBD_OPT_EXPORT_NAME:
                /* No way to return an error to client, so drop connection */
                error_setg(errp, "Option 0x%x not permitted before TLS",
                           option);
            default:
                if (nbd_drop(client->ioc, length, errp) < 0) {
                    return -EIO;
                ret = nbd_negotiate_send_rep_err(client->ioc,
                                                 NBD_REP_ERR_TLS_REQD,
                                                 option, errp,
                                                 "Option 0x%" PRIx32
                                                 "not permitted before TLS",
                                                 option);
                /* Let the client keep trying, unless they asked to
                 * quit. In this mode, we've already sent an error, so
                 * we can't ack the abort.  */
                if (option == NBD_OPT_ABORT) {
                    return 1;
                break;
        } else if (fixedNewstyle) {
            switch (option) {
            case NBD_OPT_LIST:
                if (length) {
                    ret = nbd_reject_length(client, length, option, false,
                                            errp);
                } else {
                    ret = nbd_negotiate_handle_list(client, errp);
                break;
            case NBD_OPT_ABORT:
                /* NBD spec says we must try to reply before
                 * disconnecting, but that we must also tolerate
                 * guests that don't wait for our reply. */
                nbd_negotiate_send_rep(client->ioc, NBD_REP_ACK, option, NULL);
                return 1;
            case NBD_OPT_EXPORT_NAME:
                return nbd_negotiate_handle_export_name(client, length,
                                                        myflags, no_zeroes,
                                                        errp);
            case NBD_OPT_INFO:
            case NBD_OPT_GO:
                ret = nbd_negotiate_handle_info(client, length, option,
                                                myflags, errp);
                if (ret == 1) {
                    assert(option == NBD_OPT_GO);
                    return 0;
                break;
            case NBD_OPT_STARTTLS:
                if (length) {
                    ret = nbd_reject_length(client, length, option, false,
                                            errp);
                } else if (client->tlscreds) {
                    ret = nbd_negotiate_send_rep_err(client->ioc,
                                                     NBD_REP_ERR_INVALID,
                                                     option, errp,
                                                     "TLS already enabled");
                } else {
                    ret = nbd_negotiate_send_rep_err(client->ioc,
                                                     NBD_REP_ERR_POLICY,
                                                     option, errp,
                                                     "TLS not configured");
                break;
            case NBD_OPT_STRUCTURED_REPLY:
                if (length) {
                    ret = nbd_reject_length(client, length, option, false,
                                            errp);
                } else if (client->structured_reply) {
                    ret = nbd_negotiate_send_rep_err(
                        client->ioc, NBD_REP_ERR_INVALID, option, errp,
                        "structured reply already negotiated");
                } else {
                    ret = nbd_negotiate_send_rep(client->ioc, NBD_REP_ACK,
                                                 option, errp);
                    client->structured_reply = true;
                    myflags |= NBD_FLAG_SEND_DF;
                break;
            default:
                if (nbd_drop(client->ioc, length, errp) < 0) {
                    return -EIO;
                ret = nbd_negotiate_send_rep_err(client->ioc,
                                                 NBD_REP_ERR_UNSUP,
                                                 option, errp,
                                                 "Unsupported option 0x%"
                                                 PRIx32 " (%s)", option,
                                                 nbd_opt_lookup(option));
                break;
        } else {
            /*
             * If broken new-style we should drop the connection
             * for anything except NBD_OPT_EXPORT_NAME
             */
            switch (option) {
            case NBD_OPT_EXPORT_NAME:
                return nbd_negotiate_handle_export_name(client, length,
                                                        myflags, no_zeroes,
                                                        errp);
            default:
                error_setg(errp, "Unsupported option 0x%" PRIx32 " (%s)",
                           option, nbd_opt_lookup(option));
        if (ret < 0) {
            return ret;
static int nbd_negotiate_options(NBDClient *client, uint16_t myflags,
                                 Error **errp)
{
    uint32_t flags;
    bool fixedNewstyle = false;
    bool no_zeroes = false;
    











    if (nbd_read(client->ioc, &flags, sizeof(flags), errp) < 0) {
        error_prepend(errp, "read failed: ");
        return -EIO;
    be32_to_cpus(&flags);
    trace_nbd_negotiate_options_flags(flags);
    if (flags & NBD_FLAG_C_FIXED_NEWSTYLE) {
        fixedNewstyle = true;
        flags &= ~NBD_FLAG_C_FIXED_NEWSTYLE;
    if (flags & NBD_FLAG_C_NO_ZEROES) {
        no_zeroes = true;
        flags &= ~NBD_FLAG_C_NO_ZEROES;
    if (flags != 0) {
        error_setg(errp, "Unknown client flags 0x%" PRIx32 " received", flags);
    while (1) {
        int ret;
        uint32_t option, length;
        uint64_t magic;
        if (nbd_read(client->ioc, &magic, sizeof(magic), errp) < 0) {
            error_prepend(errp, "read failed: ");
        magic = be64_to_cpu(magic);
        trace_nbd_negotiate_options_check_magic(magic);
        if (magic != NBD_OPTS_MAGIC) {
            error_setg(errp, "Bad magic received");
        if (nbd_read(client->ioc, &option,
                     sizeof(option), errp) < 0) {
            error_prepend(errp, "read failed: ");
        option = be32_to_cpu(option);
        if (nbd_read(client->ioc, &length, sizeof(length), errp) < 0) {
            error_prepend(errp, "read failed: ");
        length = be32_to_cpu(length);
        trace_nbd_negotiate_options_check_option(option,
                                                 nbd_opt_lookup(option));
        if (client->tlscreds &&
            client->ioc == (QIOChannel *)client->sioc) {
            QIOChannel *tioc;
            if (!fixedNewstyle) {
                error_setg(errp, "Unsupported option 0x%" PRIx32, option);
            switch (option) {
            case NBD_OPT_STARTTLS:
                if (length) {
                    

                    return nbd_reject_length(client, length, option, true,
                                             errp);
                tioc = nbd_negotiate_handle_starttls(client, errp);
                if (!tioc) {
                    return -EIO;
                ret = 0;
                object_unref(OBJECT(client->ioc));
                client->ioc = QIO_CHANNEL(tioc);
                break;
            case NBD_OPT_EXPORT_NAME:
                
                error_setg(errp, "Option 0x%x not permitted before TLS",
                           option);
            default:
                if (nbd_drop(client->ioc, length, errp) < 0) {
                    return -EIO;
                ret = nbd_negotiate_send_rep_err(client->ioc,
                                                 NBD_REP_ERR_TLS_REQD,
                                                 option, errp,
                                                 "Option 0x%" PRIx32
                                                 "not permitted before TLS",
                                                 option);
                


                if (option == NBD_OPT_ABORT) {
                    return 1;
                break;
        } else if (fixedNewstyle) {
            switch (option) {
            case NBD_OPT_LIST:
                if (length) {
                    ret = nbd_reject_length(client, length, option, false,
                                            errp);
                } else {
                    ret = nbd_negotiate_handle_list(client, errp);
                break;
            case NBD_OPT_ABORT:
                


                nbd_negotiate_send_rep(client->ioc, NBD_REP_ACK, option, NULL);
                return 1;
            case NBD_OPT_EXPORT_NAME:
                return nbd_negotiate_handle_export_name(client, length,
                                                        myflags, no_zeroes,
                                                        errp);
            case NBD_OPT_INFO:
            case NBD_OPT_GO:
                ret = nbd_negotiate_handle_info(client, length, option,
                                                myflags, errp);
                if (ret == 1) {
                    assert(option == NBD_OPT_GO);
                    return 0;
                break;
            case NBD_OPT_STARTTLS:
                if (length) {
                    ret = nbd_reject_length(client, length, option, false,
                                            errp);
                } else if (client->tlscreds) {
                    ret = nbd_negotiate_send_rep_err(client->ioc,
                                                     NBD_REP_ERR_INVALID,
                                                     option, errp,
                                                     "TLS already enabled");
                } else {
                    ret = nbd_negotiate_send_rep_err(client->ioc,
                                                     NBD_REP_ERR_POLICY,
                                                     option, errp,
                                                     "TLS not configured");
                break;
            case NBD_OPT_STRUCTURED_REPLY:
                if (length) {
                    ret = nbd_reject_length(client, length, option, false,
                                            errp);
                } else if (client->structured_reply) {
                    ret = nbd_negotiate_send_rep_err(
                        client->ioc, NBD_REP_ERR_INVALID, option, errp,
                        "structured reply already negotiated");
                } else {
                    ret = nbd_negotiate_send_rep(client->ioc, NBD_REP_ACK,
                                                 option, errp);
                    client->structured_reply = true;
                    myflags |= NBD_FLAG_SEND_DF;
                break;
            default:
                if (nbd_drop(client->ioc, length, errp) < 0) {
                    return -EIO;
                ret = nbd_negotiate_send_rep_err(client->ioc,
                                                 NBD_REP_ERR_UNSUP,
                                                 option, errp,
                                                 "Unsupported option 0x%"
                                                 PRIx32 " (%s)", option,
                                                 nbd_opt_lookup(option));
                break;
        } else {
            



            switch (option) {
            case NBD_OPT_EXPORT_NAME:
                return nbd_negotiate_handle_export_name(client, length,
                                                        myflags, no_zeroes,
                                                        errp);
            default:
                error_setg(errp, "Unsupported option 0x%" PRIx32 " (%s)",
                           option, nbd_opt_lookup(option));
        if (ret < 0) {
            return ret;
static int FUNC_0(NBDClient *VAR_0, uint16_t VAR_1,
                                 Error **VAR_2)
{
    uint32_t flags;
    bool fixedNewstyle = false;
    bool no_zeroes = false;
    











    if (nbd_read(VAR_0->ioc, &flags, sizeof(flags), VAR_2) < 0) {
        error_prepend(VAR_2, "read failed: ");
        return -EIO;
    be32_to_cpus(&flags);
    trace_nbd_negotiate_options_flags(flags);
    if (flags & NBD_FLAG_C_FIXED_NEWSTYLE) {
        fixedNewstyle = true;
        flags &= ~NBD_FLAG_C_FIXED_NEWSTYLE;
    if (flags & NBD_FLAG_C_NO_ZEROES) {
        no_zeroes = true;
        flags &= ~NBD_FLAG_C_NO_ZEROES;
    if (flags != 0) {
        error_setg(VAR_2, "Unknown VAR_0 flags 0x%" PRIx32 " received", flags);
    while (1) {
        int VAR_3;
        uint32_t option, length;
        uint64_t magic;
        if (nbd_read(VAR_0->ioc, &magic, sizeof(magic), VAR_2) < 0) {
            error_prepend(VAR_2, "read failed: ");
        magic = be64_to_cpu(magic);
        trace_nbd_negotiate_options_check_magic(magic);
        if (magic != NBD_OPTS_MAGIC) {
            error_setg(VAR_2, "Bad magic received");
        if (nbd_read(VAR_0->ioc, &option,
                     sizeof(option), VAR_2) < 0) {
            error_prepend(VAR_2, "read failed: ");
        option = be32_to_cpu(option);
        if (nbd_read(VAR_0->ioc, &length, sizeof(length), VAR_2) < 0) {
            error_prepend(VAR_2, "read failed: ");
        length = be32_to_cpu(length);
        trace_nbd_negotiate_options_check_option(option,
                                                 nbd_opt_lookup(option));
        if (VAR_0->tlscreds &&
            VAR_0->ioc == (QIOChannel *)VAR_0->sioc) {
            QIOChannel *tioc;
            if (!fixedNewstyle) {
                error_setg(VAR_2, "Unsupported option 0x%" PRIx32, option);
            switch (option) {
            case NBD_OPT_STARTTLS:
                if (length) {
                    

                    return nbd_reject_length(VAR_0, length, option, true,
                                             VAR_2);
                tioc = nbd_negotiate_handle_starttls(VAR_0, VAR_2);
                if (!tioc) {
                    return -EIO;
                VAR_3 = 0;
                object_unref(OBJECT(VAR_0->ioc));
                VAR_0->ioc = QIO_CHANNEL(tioc);
                break;
            case NBD_OPT_EXPORT_NAME:
                
                error_setg(VAR_2, "Option 0x%x not permitted before TLS",
                           option);
            default:
                if (nbd_drop(VAR_0->ioc, length, VAR_2) < 0) {
                    return -EIO;
                VAR_3 = nbd_negotiate_send_rep_err(VAR_0->ioc,
                                                 NBD_REP_ERR_TLS_REQD,
                                                 option, VAR_2,
                                                 "Option 0x%" PRIx32
                                                 "not permitted before TLS",
                                                 option);
                


                if (option == NBD_OPT_ABORT) {
                    return 1;
                break;
        } else if (fixedNewstyle) {
            switch (option) {
            case NBD_OPT_LIST:
                if (length) {
                    VAR_3 = nbd_reject_length(VAR_0, length, option, false,
                                            VAR_2);
                } else {
                    VAR_3 = nbd_negotiate_handle_list(VAR_0, VAR_2);
                break;
            case NBD_OPT_ABORT:
                


                nbd_negotiate_send_rep(VAR_0->ioc, NBD_REP_ACK, option, NULL);
                return 1;
            case NBD_OPT_EXPORT_NAME:
                return nbd_negotiate_handle_export_name(VAR_0, length,
                                                        VAR_1, no_zeroes,
                                                        VAR_2);
            case NBD_OPT_INFO:
            case NBD_OPT_GO:
                VAR_3 = nbd_negotiate_handle_info(VAR_0, length, option,
                                                VAR_1, VAR_2);
                if (VAR_3 == 1) {
                    assert(option == NBD_OPT_GO);
                    return 0;
                break;
            case NBD_OPT_STARTTLS:
                if (length) {
                    VAR_3 = nbd_reject_length(VAR_0, length, option, false,
                                            VAR_2);
                } else if (VAR_0->tlscreds) {
                    VAR_3 = nbd_negotiate_send_rep_err(VAR_0->ioc,
                                                     NBD_REP_ERR_INVALID,
                                                     option, VAR_2,
                                                     "TLS already enabled");
                } else {
                    VAR_3 = nbd_negotiate_send_rep_err(VAR_0->ioc,
                                                     NBD_REP_ERR_POLICY,
                                                     option, VAR_2,
                                                     "TLS not configured");
                break;
            case NBD_OPT_STRUCTURED_REPLY:
                if (length) {
                    VAR_3 = nbd_reject_length(VAR_0, length, option, false,
                                            VAR_2);
                } else if (VAR_0->structured_reply) {
                    VAR_3 = nbd_negotiate_send_rep_err(
                        VAR_0->ioc, NBD_REP_ERR_INVALID, option, VAR_2,
                        "structured reply already negotiated");
                } else {
                    VAR_3 = nbd_negotiate_send_rep(VAR_0->ioc, NBD_REP_ACK,
                                                 option, VAR_2);
                    VAR_0->structured_reply = true;
                    VAR_1 |= NBD_FLAG_SEND_DF;
                break;
            default:
                if (nbd_drop(VAR_0->ioc, length, VAR_2) < 0) {
                    return -EIO;
                VAR_3 = nbd_negotiate_send_rep_err(VAR_0->ioc,
                                                 NBD_REP_ERR_UNSUP,
                                                 option, VAR_2,
                                                 "Unsupported option 0x%"
                                                 PRIx32 " (%s)", option,
                                                 nbd_opt_lookup(option));
                break;
        } else {
            



            switch (option) {
            case NBD_OPT_EXPORT_NAME:
                return nbd_negotiate_handle_export_name(VAR_0, length,
                                                        VAR_1, no_zeroes,
                                                        VAR_2);
            default:
                error_setg(VAR_2, "Unsupported option 0x%" PRIx32 " (%s)",
                           option, nbd_opt_lookup(option));
        if (VAR_3 < 0) {
            return VAR_3;
static int FUNC_0(NBDClient *VAR_0, uint16_t VAR_1,
Error **VAR_2)
{ uint32_t flags; bool fixedNewstyle = false; bool no_zeroes = false; if (nbd_read(VAR_0->ioc, &flags, sizeof(flags), VAR_2) < 0) { error_prepend(VAR_2, "read failed: "); return -EIO; be32_to_cpus(&flags); trace_nbd_negotiate_options_flags(flags); if (flags & NBD_FLAG_C_FIXED_NEWSTYLE) { fixedNewstyle = true; flags &= ~NBD_FLAG_C_FIXED_NEWSTYLE; if (flags & NBD_FLAG_C_NO_ZEROES) { no_zeroes = true; flags &= ~NBD_FLAG_C_NO_ZEROES; if (flags != 0) { error_setg(VAR_2, "Unknown VAR_0 flags 0x%" PRIx32 " received", flags); while (1) { int VAR_3; uint32_t option, length; uint64_t magic; if (nbd_read(VAR_0->ioc, &magic, sizeof(magic), VAR_2) < 0) { error_prepend(VAR_2, "read failed: "); magic = be64_to_cpu(magic); trace_nbd_negotiate_options_check_magic(magic); if (magic != NBD_OPTS_MAGIC) { error_setg(VAR_2, "Bad magic received"); if (nbd_read(VAR_0->ioc, &option,
sizeof(option), VAR_2) < 0) { error_prepend(VAR_2, "read failed: "); option = be32_to_cpu(option); if (nbd_read(VAR_0->ioc, &length, sizeof(length), VAR_2) < 0) { error_prepend(VAR_2, "read failed: "); length = be32_to_cpu(length); trace_nbd_negotiate_options_check_option(option,
nbd_opt_lookup(option)); if (VAR_0->tlscreds &&
VAR_0->ioc == (QIOChannel *)VAR_0->sioc) { QIOChannel *tioc; if (!fixedNewstyle) { error_setg(VAR_2, "Unsupported option 0x%" PRIx32, option); switch (option) { case NBD_OPT_STARTTLS:
if (length) { return nbd_reject_length(VAR_0, length, option, true,
VAR_2); tioc = nbd_negotiate_handle_starttls(VAR_0, VAR_2); if (!tioc) { return -EIO; VAR_3 = 0; object_unref(OBJECT(VAR_0->ioc)); VAR_0->ioc = QIO_CHANNEL(tioc); break; case NBD_OPT_EXPORT_NAME:
error_setg(VAR_2, "Option 0x%x not permitted before TLS",
option); default:
if (nbd_drop(VAR_0->ioc, length, VAR_2) < 0) { return -EIO; VAR_3 = nbd_negotiate_send_rep_err(VAR_0->ioc,
NBD_REP_ERR_TLS_REQD,
option, VAR_2,
"Option 0x%" PRIx32
"not permitted before TLS",
option); if (option == NBD_OPT_ABORT) { return 1; break; } else if (fixedNewstyle) { switch (option) { case NBD_OPT_LIST:
if (length) { VAR_3 = nbd_reject_length(VAR_0, length, option, false,
VAR_2); } else { VAR_3 = nbd_negotiate_handle_list(VAR_0, VAR_2); break; case NBD_OPT_ABORT:
nbd_negotiate_send_rep(VAR_0->ioc, NBD_REP_ACK, option, NULL); return 1; case NBD_OPT_EXPORT_NAME:
return nbd_negotiate_handle_export_name(VAR_0, length,
VAR_1, no_zeroes,
VAR_2); case NBD_OPT_INFO:
case NBD_OPT_GO:
VAR_3 = nbd_negotiate_handle_info(VAR_0, length, option,
VAR_1, VAR_2); if (VAR_3 == 1) { assert(option == NBD_OPT_GO); return 0; break; case NBD_OPT_STARTTLS:
if (length) { VAR_3 = nbd_reject_length(VAR_0, length, option, false,
VAR_2); } else if (VAR_0->tlscreds) { VAR_3 = nbd_negotiate_send_rep_err(VAR_0->ioc,
NBD_REP_ERR_INVALID,
option, VAR_2,
"TLS already enabled"); } else { VAR_3 = nbd_negotiate_send_rep_err(VAR_0->ioc,
NBD_REP_ERR_POLICY,
option, VAR_2,
"TLS not configured"); break; case NBD_OPT_STRUCTURED_REPLY:
if (length) { VAR_3 = nbd_reject_length(VAR_0, length, option, false,
VAR_2); } else if (VAR_0->structured_reply) { VAR_3 = nbd_negotiate_send_rep_err(
VAR_0->ioc, NBD_REP_ERR_INVALID, option, VAR_2,
"structured reply already negotiated"); } else { VAR_3 = nbd_negotiate_send_rep(VAR_0->ioc, NBD_REP_ACK,
option, VAR_2); VAR_0->structured_reply = true; VAR_1 |= NBD_FLAG_SEND_DF; break; default:
if (nbd_drop(VAR_0->ioc, length, VAR_2) < 0) { return -EIO; VAR_3 = nbd_negotiate_send_rep_err(VAR_0->ioc,
NBD_REP_ERR_UNSUP,
option, VAR_2,
"Unsupported option 0x%"
PRIx32 " (%s)", option,
nbd_opt_lookup(option)); break; } else { switch (option) { case NBD_OPT_EXPORT_NAME:
return nbd_negotiate_handle_export_name(VAR_0, length,
VAR_1, no_zeroes,
VAR_2); default:
error_setg(VAR_2, "Unsupported option 0x%" PRIx32 " (%s)",
option, nbd_opt_lookup(option)); if (VAR_3 < 0) { return VAR_3;