static int nbd_negotiate_options(NBDClient *client, Error **errp)

{

    uint32_t flags;

    bool fixedNewstyle = false;



    /* Client sends:

        [ 0 ..   3]   client flags



        [ 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;

    }

    trace_nbd_negotiate_options_flags();

    be32_to_cpus(&flags);

    if (flags & NBD_FLAG_C_FIXED_NEWSTYLE) {

        trace_nbd_negotiate_options_newstyle();

        fixedNewstyle = true;

        flags &= ~NBD_FLAG_C_FIXED_NEWSTYLE;

    }

    if (flags & NBD_FLAG_C_NO_ZEROES) {

        trace_nbd_negotiate_options_no_zeroes();

        client->no_zeroes = true;

        flags &= ~NBD_FLAG_C_NO_ZEROES;

    }

    if (flags != 0) {

        error_setg(errp, "Unknown client flags 0x%" PRIx32 " received", flags);

        return -EIO;

    }



    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: ");

            return -EINVAL;

        }

        magic = be64_to_cpu(magic);

        trace_nbd_negotiate_options_check_magic(magic);

        if (magic != NBD_OPTS_MAGIC) {

            error_setg(errp, "Bad magic received");

            return -EINVAL;

        }



        if (nbd_read(client->ioc, &option,

                     sizeof(option), errp) < 0) {

            error_prepend(errp, "read failed: ");

            return -EINVAL;

        }

        option = be32_to_cpu(option);



        if (nbd_read(client->ioc, &length, sizeof(length), errp) < 0) {

            error_prepend(errp, "read failed: ");

            return -EINVAL;

        }

        length = be32_to_cpu(length);



        trace_nbd_negotiate_options_check_option(option);

        if (client->tlscreds &&

            client->ioc == (QIOChannel *)client->sioc) {

            QIOChannel *tioc;

            if (!fixedNewstyle) {

                error_setg(errp, "Unsupported option 0x%" PRIx32, option);

                return -EINVAL;

            }

            switch (option) {

            case NBD_OPT_STARTTLS:

                tioc = nbd_negotiate_handle_starttls(client, length, errp);

                if (!tioc) {

                    return -EIO;

                }

                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);

                return -EINVAL;



            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 (ret < 0) {

                    return ret;

                }

                /* 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:

                ret = nbd_negotiate_handle_list(client, length, errp);

                if (ret < 0) {

                    return ret;

                }

                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, errp);



            case NBD_OPT_STARTTLS:

                if (nbd_drop(client->ioc, length, errp) < 0) {

                    return -EIO;

                }

                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");

                }

                if (ret < 0) {

                    return ret;

                }

                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,

                                                 option);

                if (ret < 0) {

                    return ret;

                }

                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, errp);



            default:

                error_setg(errp, "Unsupported option 0x%" PRIx32, option);

                return -EINVAL;

            }

        }

    }

}

static int nbd_negotiate_options(NBDClient *client, Error **errp)

{

    uint32_t flags;

    bool fixedNewstyle = false;



    



























    if (nbd_read(client->ioc, &flags, sizeof(flags), errp) < 0) {

        error_prepend(errp, "read failed: ");

        return -EIO;

    }

    trace_nbd_negotiate_options_flags();

    be32_to_cpus(&flags);

    if (flags & NBD_FLAG_C_FIXED_NEWSTYLE) {

        trace_nbd_negotiate_options_newstyle();

        fixedNewstyle = true;

        flags &= ~NBD_FLAG_C_FIXED_NEWSTYLE;

    }

    if (flags & NBD_FLAG_C_NO_ZEROES) {

        trace_nbd_negotiate_options_no_zeroes();

        client->no_zeroes = true;

        flags &= ~NBD_FLAG_C_NO_ZEROES;

    }

    if (flags != 0) {

        error_setg(errp, "Unknown client flags 0x%" PRIx32 " received", flags);

        return -EIO;

    }



    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: ");

            return -EINVAL;

        }

        magic = be64_to_cpu(magic);

        trace_nbd_negotiate_options_check_magic(magic);

        if (magic != NBD_OPTS_MAGIC) {

            error_setg(errp, "Bad magic received");

            return -EINVAL;

        }



        if (nbd_read(client->ioc, &option,

                     sizeof(option), errp) < 0) {

            error_prepend(errp, "read failed: ");

            return -EINVAL;

        }

        option = be32_to_cpu(option);



        if (nbd_read(client->ioc, &length, sizeof(length), errp) < 0) {

            error_prepend(errp, "read failed: ");

            return -EINVAL;

        }

        length = be32_to_cpu(length);



        trace_nbd_negotiate_options_check_option(option);

        if (client->tlscreds &&

            client->ioc == (QIOChannel *)client->sioc) {

            QIOChannel *tioc;

            if (!fixedNewstyle) {

                error_setg(errp, "Unsupported option 0x%" PRIx32, option);

                return -EINVAL;

            }

            switch (option) {

            case NBD_OPT_STARTTLS:

                tioc = nbd_negotiate_handle_starttls(client, length, errp);

                if (!tioc) {

                    return -EIO;

                }

                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);

                return -EINVAL;



            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 (ret < 0) {

                    return ret;

                }

                





                if (option == NBD_OPT_ABORT) {

                    return 1;

                }

                break;

            }

        } else if (fixedNewstyle) {

            switch (option) {

            case NBD_OPT_LIST:

                ret = nbd_negotiate_handle_list(client, length, errp);

                if (ret < 0) {

                    return ret;

                }

                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, errp);



            case NBD_OPT_STARTTLS:

                if (nbd_drop(client->ioc, length, errp) < 0) {

                    return -EIO;

                }

                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");

                }

                if (ret < 0) {

                    return ret;

                }

                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,

                                                 option);

                if (ret < 0) {

                    return ret;

                }

                break;

            }

        } else {

            







            switch (option) {

            case NBD_OPT_EXPORT_NAME:

                return nbd_negotiate_handle_export_name(client, length, errp);



            default:

                error_setg(errp, "Unsupported option 0x%" PRIx32, option);

                return -EINVAL;

            }

        }

    }

}

static int FUNC_0(NBDClient *VAR_0, Error **VAR_1)

{

    uint32_t flags;

    bool fixedNewstyle = false;



    



























    if (nbd_read(VAR_0->ioc, &flags, sizeof(flags), VAR_1) < 0) {

        error_prepend(VAR_1, "read failed: ");

        return -EIO;

    }

    trace_nbd_negotiate_options_flags();

    be32_to_cpus(&flags);

    if (flags & NBD_FLAG_C_FIXED_NEWSTYLE) {

        trace_nbd_negotiate_options_newstyle();

        fixedNewstyle = true;

        flags &= ~NBD_FLAG_C_FIXED_NEWSTYLE;

    }

    if (flags & NBD_FLAG_C_NO_ZEROES) {

        trace_nbd_negotiate_options_no_zeroes();

        VAR_0->no_zeroes = true;

        flags &= ~NBD_FLAG_C_NO_ZEROES;

    }

    if (flags != 0) {

        error_setg(VAR_1, "Unknown VAR_0 flags 0x%" PRIx32 " received", flags);

        return -EIO;

    }



    while (1) {

        int VAR_2;

        uint32_t option, length;

        uint64_t magic;



        if (nbd_read(VAR_0->ioc, &magic, sizeof(magic), VAR_1) < 0) {

            error_prepend(VAR_1, "read failed: ");

            return -EINVAL;

        }

        magic = be64_to_cpu(magic);

        trace_nbd_negotiate_options_check_magic(magic);

        if (magic != NBD_OPTS_MAGIC) {

            error_setg(VAR_1, "Bad magic received");

            return -EINVAL;

        }



        if (nbd_read(VAR_0->ioc, &option,

                     sizeof(option), VAR_1) < 0) {

            error_prepend(VAR_1, "read failed: ");

            return -EINVAL;

        }

        option = be32_to_cpu(option);



        if (nbd_read(VAR_0->ioc, &length, sizeof(length), VAR_1) < 0) {

            error_prepend(VAR_1, "read failed: ");

            return -EINVAL;

        }

        length = be32_to_cpu(length);



        trace_nbd_negotiate_options_check_option(option);

        if (VAR_0->tlscreds &&

            VAR_0->ioc == (QIOChannel *)VAR_0->sioc) {

            QIOChannel *tioc;

            if (!fixedNewstyle) {

                error_setg(VAR_1, "Unsupported option 0x%" PRIx32, option);

                return -EINVAL;

            }

            switch (option) {

            case NBD_OPT_STARTTLS:

                tioc = nbd_negotiate_handle_starttls(VAR_0, length, VAR_1);

                if (!tioc) {

                    return -EIO;

                }

                object_unref(OBJECT(VAR_0->ioc));

                VAR_0->ioc = QIO_CHANNEL(tioc);

                break;



            case NBD_OPT_EXPORT_NAME:

                

                error_setg(VAR_1, "Option 0x%x not permitted before TLS",

                           option);

                return -EINVAL;



            default:

                if (nbd_drop(VAR_0->ioc, length, VAR_1) < 0) {

                    return -EIO;

                }

                VAR_2 = nbd_negotiate_send_rep_err(VAR_0->ioc,

                                                 NBD_REP_ERR_TLS_REQD,

                                                 option, VAR_1,

                                                 "Option 0x%" PRIx32

                                                 "not permitted before TLS",

                                                 option);

                if (VAR_2 < 0) {

                    return VAR_2;

                }

                





                if (option == NBD_OPT_ABORT) {

                    return 1;

                }

                break;

            }

        } else if (fixedNewstyle) {

            switch (option) {

            case NBD_OPT_LIST:

                VAR_2 = nbd_negotiate_handle_list(VAR_0, length, VAR_1);

                if (VAR_2 < 0) {

                    return 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);



            case NBD_OPT_STARTTLS:

                if (nbd_drop(VAR_0->ioc, length, VAR_1) < 0) {

                    return -EIO;

                }

                if (VAR_0->tlscreds) {

                    VAR_2 = nbd_negotiate_send_rep_err(VAR_0->ioc,

                                                     NBD_REP_ERR_INVALID,

                                                     option, VAR_1,

                                                     "TLS already enabled");

                } else {

                    VAR_2 = nbd_negotiate_send_rep_err(VAR_0->ioc,

                                                     NBD_REP_ERR_POLICY,

                                                     option, VAR_1,

                                                     "TLS not configured");

                }

                if (VAR_2 < 0) {

                    return VAR_2;

                }

                break;

            default:

                if (nbd_drop(VAR_0->ioc, length, VAR_1) < 0) {

                    return -EIO;

                }

                VAR_2 = nbd_negotiate_send_rep_err(VAR_0->ioc,

                                                 NBD_REP_ERR_UNSUP,

                                                 option, VAR_1,

                                                 "Unsupported option 0x%"

                                                 PRIx32,

                                                 option);

                if (VAR_2 < 0) {

                    return VAR_2;

                }

                break;

            }

        } else {

            







            switch (option) {

            case NBD_OPT_EXPORT_NAME:

                return nbd_negotiate_handle_export_name(VAR_0, length, VAR_1);



            default:

                error_setg(VAR_1, "Unsupported option 0x%" PRIx32, option);

                return -EINVAL;

            }

        }

    }

}

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