long SSL_ctrl(SSL *s, int cmd, long larg, void *parg)
{
    long l;

    switch (cmd) {
    case SSL_CTRL_GET_READ_AHEAD:
        return RECORD_LAYER_get_read_ahead(&s->rlayer);
    case SSL_CTRL_SET_READ_AHEAD:
        l = RECORD_LAYER_get_read_ahead(&s->rlayer);
        RECORD_LAYER_set_read_ahead(&s->rlayer, larg);
        return l;

    case SSL_CTRL_SET_MSG_CALLBACK_ARG:
        s->msg_callback_arg = parg;
        return 1;

    case SSL_CTRL_MODE:
        return (s->mode |= larg);
    case SSL_CTRL_CLEAR_MODE:
        return (s->mode &= ~larg);
    case SSL_CTRL_GET_MAX_CERT_LIST:
        return (long)s->max_cert_list;
    case SSL_CTRL_SET_MAX_CERT_LIST:
        if (larg < 0)
            return 0;
        l = (long)s->max_cert_list;
        s->max_cert_list = (size_t)larg;
        return l;
    case SSL_CTRL_SET_MAX_SEND_FRAGMENT:
        if (larg < 512 || larg > SSL3_RT_MAX_PLAIN_LENGTH)
            return 0;
#ifndef OPENSSL_NO_KTLS
        if (s->wbio != NULL && BIO_get_ktls_send(s->wbio))
            return 0;
#endif /* OPENSSL_NO_KTLS */
        s->max_send_fragment = larg;
        if (s->max_send_fragment < s->split_send_fragment)
            s->split_send_fragment = s->max_send_fragment;
        return 1;
    case SSL_CTRL_SET_SPLIT_SEND_FRAGMENT:
        if ((size_t)larg > s->max_send_fragment || larg == 0)
            return 0;
        s->split_send_fragment = larg;
        return 1;
    case SSL_CTRL_SET_MAX_PIPELINES:
        if (larg < 1 || larg > SSL_MAX_PIPELINES)
            return 0;
        s->max_pipelines = larg;
        if (larg > 1)
            RECORD_LAYER_set_read_ahead(&s->rlayer, 1);
        return 1;
    case SSL_CTRL_GET_RI_SUPPORT:
        return s->s3.send_connection_binding;
    case SSL_CTRL_CERT_FLAGS:
        return (s->cert->cert_flags |= larg);
    case SSL_CTRL_CLEAR_CERT_FLAGS:
        return (s->cert->cert_flags &= ~larg);

    case SSL_CTRL_GET_RAW_CIPHERLIST:
        if (parg) {
            if (s->s3.tmp.ciphers_raw == NULL)
                return 0;
            *(unsigned char **)parg = s->s3.tmp.ciphers_raw;
            return (int)s->s3.tmp.ciphers_rawlen;
        } else {
            return TLS_CIPHER_LEN;
        }
    case SSL_CTRL_GET_EXTMS_SUPPORT:
        if (!s->session || SSL_in_init(s) || ossl_statem_get_in_handshake(s))
            return -1;
        if (s->session->flags & SSL_SESS_FLAG_EXTMS)
            return 1;
        else
            return 0;
    case SSL_CTRL_SET_MIN_PROTO_VERSION:
        return ssl_check_allowed_versions(larg, s->max_proto_version)
               && ssl_set_version_bound(s->ctx->method->version, (int)larg,
                                        &s->min_proto_version);
    case SSL_CTRL_GET_MIN_PROTO_VERSION:
        return s->min_proto_version;
    case SSL_CTRL_SET_MAX_PROTO_VERSION:
        return ssl_check_allowed_versions(s->min_proto_version, larg)
               && ssl_set_version_bound(s->ctx->method->version, (int)larg,
                                        &s->max_proto_version);
    case SSL_CTRL_GET_MAX_PROTO_VERSION:
        return s->max_proto_version;
    default:
        return s->method->ssl_ctrl(s, cmd, larg, parg);
    }
}