ldap_int_tls_start ( LDAP *ld, LDAPConn *conn, LDAPURLDesc *srv )
{
	Sockbuf *sb;
	char *host;
	void *ssl;
	int ret, async;
#ifdef LDAP_USE_NON_BLOCKING_TLS
	struct timeval start_time_tv, tv, tv0;
	ber_socket_t	sd = AC_SOCKET_ERROR;
#endif /* LDAP_USE_NON_BLOCKING_TLS */

	if ( !conn )
		return LDAP_PARAM_ERROR;

	sb = conn->lconn_sb;
	if( srv ) {
		host = srv->lud_host;
	} else {
 		host = conn->lconn_server->lud_host;
	}

	/* avoid NULL host */
	if( host == NULL ) {
		host = "localhost";
	}

	(void) tls_init( tls_imp );

#ifdef LDAP_USE_NON_BLOCKING_TLS
	/*
	 * Use non-blocking io during SSL Handshake when a timeout is configured
	 */
	async = LDAP_BOOL_GET( &ld->ld_options, LDAP_BOOL_CONNECT_ASYNC );
	if ( ld->ld_options.ldo_tm_net.tv_sec >= 0 ) {
		if ( !async ) {
			/* if async, this has already been set */
			ber_sockbuf_ctrl( sb, LBER_SB_OPT_SET_NONBLOCK, (void*)1 );
		}
		ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_FD, &sd );
		tv = ld->ld_options.ldo_tm_net;
		tv0 = tv;
#ifdef HAVE_GETTIMEOFDAY
		gettimeofday( &start_time_tv, NULL );
#else /* ! HAVE_GETTIMEOFDAY */
		time( &start_time_tv.tv_sec );
		start_time_tv.tv_usec = 0;
#endif /* ! HAVE_GETTIMEOFDAY */
	}

#endif /* LDAP_USE_NON_BLOCKING_TLS */

	ld->ld_errno = LDAP_SUCCESS;
	ret = ldap_int_tls_connect( ld, conn, host );

	 /* this mainly only happens for non-blocking io
	  * but can also happen when the handshake is too
	  * big for a single network message.
	  */
	while ( ret > 0 ) {
#ifdef LDAP_USE_NON_BLOCKING_TLS
		if ( async ) {
			struct timeval curr_time_tv, delta_tv;
			int wr=0;

			if ( sb->sb_trans_needs_read ) {
				wr=0;
			} else if ( sb->sb_trans_needs_write ) {
				wr=1;
			}
			Debug( LDAP_DEBUG_TRACE, "ldap_int_tls_start: ldap_int_tls_connect needs %s\n",
					wr ? "write": "read", 0, 0 );

			/* This is mostly copied from result.c:wait4msg(), should
			 * probably be moved into a separate function */
#ifdef HAVE_GETTIMEOFDAY
			gettimeofday( &curr_time_tv, NULL );
#else /* ! HAVE_GETTIMEOFDAY */
			time( &curr_time_tv.tv_sec );
			curr_time_tv.tv_usec = 0;
#endif /* ! HAVE_GETTIMEOFDAY */

			/* delta = curr - start */
			delta_tv.tv_sec = curr_time_tv.tv_sec - start_time_tv.tv_sec;
			delta_tv.tv_usec = curr_time_tv.tv_usec - start_time_tv.tv_usec;
			if ( delta_tv.tv_usec < 0 ) {
				delta_tv.tv_sec--;
				delta_tv.tv_usec += 1000000;
			}

			/* tv0 < delta ? */
			if ( ( tv0.tv_sec < delta_tv.tv_sec ) ||
				 ( ( tv0.tv_sec == delta_tv.tv_sec ) &&
				   ( tv0.tv_usec < delta_tv.tv_usec ) ) )
			{
				ret = -1;
				ld->ld_errno = LDAP_TIMEOUT;
				break;
			}
			/* timeout -= delta_time */
			tv0.tv_sec -= delta_tv.tv_sec;
			tv0.tv_usec -= delta_tv.tv_usec;
			if ( tv0.tv_usec < 0 ) {
				tv0.tv_sec--;
				tv0.tv_usec += 1000000;
			}
			start_time_tv.tv_sec = curr_time_tv.tv_sec;
			start_time_tv.tv_usec = curr_time_tv.tv_usec;
			tv = tv0;
			Debug( LDAP_DEBUG_TRACE, "ldap_int_tls_start: ld %p %ld s %ld us to go\n",
				(void *)ld, (long) tv.tv_sec, (long) tv.tv_usec );
			ret = ldap_int_poll( ld, sd, &tv, wr);
			if ( ret < 0 ) {
				ld->ld_errno = LDAP_TIMEOUT;
				break;
			}
		}
#endif /* LDAP_USE_NON_BLOCKING_TLS */
		ret = ldap_int_tls_connect( ld, conn, host );
	}

	if ( ret < 0 ) {
		if ( ld->ld_errno == LDAP_SUCCESS )
			ld->ld_errno = LDAP_CONNECT_ERROR;
		return (ld->ld_errno);
	}

	return LDAP_SUCCESS;
}


lldp_tlv_put_u16(struct dp_packet *p, uint16_t x)
{
    ovs_be16 nx = htons(x);
    dp_packet_put(p, &nx, sizeof nx);
}


lldpd_af_from_lldp_proto(int proto)
{
    switch (proto) {
    case LLDP_MGMT_ADDR_IP4:
        return LLDPD_AF_IPV4;
    case LLDP_MGMT_ADDR_IP6:
        return LLDPD_AF_IPV6;
    default:
        return LLDPD_AF_UNSPEC;
    }
}


bool red_stream_set_no_delay(RedStream *stream, bool no_delay)
{
    return red_socket_set_no_delay(stream->socket, no_delay);
}


static char *red_stream_get_local_address(RedStream *stream)
{
    return addr_to_string("%s;%s", &stream->priv->info->laddr_ext,
                          stream->priv->info->llen_ext);
}


int red_stream_send_msgfd(RedStream *stream, int fd)
{
    struct msghdr msgh = { 0, };
    struct iovec iov;
    int r;

    const size_t fd_size = 1 * sizeof(int);
    struct cmsghdr *cmsg;
    union {
        struct cmsghdr hdr;
        char data[CMSG_SPACE(fd_size)];
    } control;

    spice_return_val_if_fail(red_stream_is_plain_unix(stream), -1);

    /* set the payload */
    iov.iov_base = (char*)"@";
    iov.iov_len = 1;
    msgh.msg_iovlen = 1;
    msgh.msg_iov = &iov;

    if (fd != -1) {
        msgh.msg_control = control.data;
        msgh.msg_controllen = sizeof(control.data);
        /* CMSG_SPACE() might be larger than CMSG_LEN() as it can include some
         * padding. We set the whole control data to 0 to avoid valgrind warnings
         */
        memset(control.data, 0, sizeof(control.data));

        cmsg = CMSG_FIRSTHDR(&msgh);
        cmsg->cmsg_len = CMSG_LEN(fd_size);
        cmsg->cmsg_level = SOL_SOCKET;
        cmsg->cmsg_type = SCM_RIGHTS;
        memcpy(CMSG_DATA(cmsg), &fd, fd_size);
    }

    do {
        r = sendmsg(stream->socket, &msgh, MSG_NOSIGNAL);
    } while (r < 0 && (errno == EINTR || errno == EAGAIN));

    return r;
}


static int socket_set_cork(int socket, int enabled)
{
    SPICE_VERIFY(sizeof(enabled) == sizeof(int));
    return setsockopt(socket, IPPROTO_TCP, TCP_CORK, &enabled, sizeof(enabled));
}


static void reds_handle_read_link_done(void *opaque)
{
    RedLinkInfo *link = (RedLinkInfo *)opaque;
    RedsState *reds = link->reds;
    SpiceLinkMess *link_mess = link->link_mess;
    uint32_t num_caps;
    uint32_t *caps;
    int auth_selection;
    unsigned int i;

    link_mess->caps_offset = GUINT32_FROM_LE(link_mess->caps_offset);
    link_mess->connection_id = GUINT32_FROM_LE(link_mess->connection_id);
    link_mess->num_channel_caps = GUINT32_FROM_LE(link_mess->num_channel_caps);
    link_mess->num_common_caps = GUINT32_FROM_LE(link_mess->num_common_caps);

    /* Prevent DoS. Currently we defined only 13 capabilities,
     * I expect 1024 to be valid for quite a lot time */
    if (link_mess->num_channel_caps > 1024 || link_mess->num_common_caps > 1024) {
        reds_send_link_error(link, SPICE_LINK_ERR_INVALID_DATA);
        reds_link_free(link);
        return;
    }

    num_caps = link_mess->num_common_caps + link_mess->num_channel_caps;
    caps = (uint32_t *)((uint8_t *)link_mess + link_mess->caps_offset);

    if (num_caps && (num_caps * sizeof(uint32_t) + link_mess->caps_offset >
                     link->link_header.size ||
                     link_mess->caps_offset < sizeof(*link_mess))) {
        reds_send_link_error(link, SPICE_LINK_ERR_INVALID_DATA);
        reds_link_free(link);
        return;
    }

    for(i = 0; i < num_caps;i++)
        caps[i] = GUINT32_FROM_LE(caps[i]);

    auth_selection = red_link_info_test_capability(link,
                                                   SPICE_COMMON_CAP_PROTOCOL_AUTH_SELECTION);

    if (!reds_security_check(link)) {
        if (red_stream_is_ssl(link->stream)) {
            spice_warning("spice channels %d should not be encrypted", link_mess->channel_type);
            reds_send_link_error(link, SPICE_LINK_ERR_NEED_UNSECURED);
        } else {
            spice_warning("spice channels %d should be encrypted", link_mess->channel_type);
            reds_send_link_error(link, SPICE_LINK_ERR_NEED_SECURED);
        }
        reds_link_free(link);
        return;
    }

    if (!reds_send_link_ack(reds, link)) {
        reds_link_free(link);
        return;
    }

    if (!auth_selection) {
        if (reds->config->sasl_enabled && !link->skip_auth) {
            spice_warning("SASL enabled, but peer supports only spice authentication");
            reds_send_link_error(link, SPICE_LINK_ERR_VERSION_MISMATCH);
            return;
        }
        spice_warning("Peer doesn't support AUTH selection");
        reds_get_spice_ticket(link);
    } else {
        red_stream_async_read(link->stream,
                              (uint8_t *)&link->auth_mechanism,
                              sizeof(SpiceLinkAuthMechanism),
                              reds_handle_auth_mechanism,
                              link);
    }
}


static void migrate_timeout(RedsState *reds)
{
    spice_debug("trace");
    spice_assert(reds->mig_wait_connect || reds->mig_wait_disconnect);
    if (reds->mig_wait_connect) {
        /* we will fall back to the switch host scheme when migration completes */
        reds->main_channel->migrate_cancel_wait();
        /* in case part of the client haven't yet completed the previous migration, disconnect them */
        reds_mig_target_client_disconnect_all(reds);
        reds_mig_cleanup(reds);
    } else {
        reds_mig_disconnect(reds);
    }
}


static void reds_handle_auth_mechanism(void *opaque)
{
    RedLinkInfo *link = (RedLinkInfo *)opaque;
    RedsState *reds = link->reds;

    spice_debug("Auth method: %d", link->auth_mechanism.auth_mechanism);

    link->auth_mechanism.auth_mechanism = GUINT32_FROM_LE(link->auth_mechanism.auth_mechanism);
    if (link->auth_mechanism.auth_mechanism == SPICE_COMMON_CAP_AUTH_SPICE
        && !reds->config->sasl_enabled
        ) {
        reds_get_spice_ticket(link);
#if HAVE_SASL
    } else if (link->auth_mechanism.auth_mechanism == SPICE_COMMON_CAP_AUTH_SASL) {
        spice_debug("Starting SASL");
        reds_start_auth_sasl(link);
#endif
    } else {
        spice_warning("Unknown auth method, disconnecting");
        if (reds->config->sasl_enabled) {
            spice_warning("Your client doesn't handle SASL?");
        }
        reds_send_link_error(link, SPICE_LINK_ERR_INVALID_DATA);
        reds_link_free(link);
    }
}


SPICE_GNUC_VISIBLE int spice_server_get_sock_info(SpiceServer *reds, struct sockaddr *sa, socklen_t *salen)
{
    return -1;
}


void stat_init_counter(RedStatCounter *counter, SpiceServer *reds,
                       const RedStatNode *parent, const char *name, int visible)
{
    StatNodeRef parent_ref = parent ? parent->ref : INVALID_STAT_REF;
    counter->counter =
        stat_file_add_counter(reds->stat_file, parent_ref, name, visible);
}


static void pthreads_thread_id(CRYPTO_THREADID *tid)
{
    CRYPTO_THREADID_set_numeric(tid, (unsigned long)pthread_self());
}


SPICE_GNUC_VISIBLE int spice_server_set_video_codecs(SpiceServer *reds, const char *video_codecs)
{
    unsigned int installed = 0;

    reds_set_video_codecs_from_string(reds, video_codecs, &installed);

    if (!installed) {
        return -1;
    }
    reds_on_vc_change(reds);

    return 0;
}


static void reds_handle_other_links(RedsState *reds, RedLinkInfo *link)
{
    RedChannel *channel;
    RedClient *client = NULL;
    SpiceLinkMess *link_mess;
    RedsMigTargetClient *mig_client;

    link_mess = link->link_mess;
    if (reds->main_channel) {
        client = reds->main_channel->get_client_by_link_id(link_mess->connection_id);
    }

    // TODO: MC: broke migration (at least for the dont-drop-connection kind).
    // On migration we should get a connection_id to expect (must be a security measure)
    // where do we store it? on reds, but should be a list (MC).
    if (!client) {
        reds_send_link_result(link, SPICE_LINK_ERR_BAD_CONNECTION_ID);
        return;
    }

    // TODO: MC: be less lenient. Tally connections from same connection_id (by same client).
    if (!(channel = reds_find_channel(reds, link_mess->channel_type,
                                      link_mess->channel_id))) {
        reds_send_link_result(link, SPICE_LINK_ERR_CHANNEL_NOT_AVAILABLE);
        return;
    }

    reds_send_link_result(link, SPICE_LINK_ERR_OK);
    reds_info_new_channel(link, link_mess->connection_id);

    mig_client = reds_mig_target_client_find(reds, client);
    /*
     * In semi-seamless migration, we activate the channels only
     * after migration is completed. Since, the session starts almost from
     * scratch we don't mind if we skip some messages in between the src session end and
     * dst session start.
     * In seamless migration, in order to keep the continuousness of the session, and
     * in order not to lose any data, we activate the target channels before
     * migration completes, as soon as we receive SPICE_MSGC_MAIN_MIGRATE_DST_DO_SEAMLESS.
     * If a channel connects before receiving SPICE_MSGC_MAIN_MIGRATE_DST_DO_SEAMLESS,
     * reds_on_migrate_dst_set_seamless will take care of activating it */
    if (client->during_migrate_at_target() && !reds->dst_do_seamless_migrate) {
        spice_assert(mig_client);
        reds_mig_target_client_add_pending_link(mig_client, link_mess, link->stream);
        link->link_mess = NULL;
    } else {
        spice_assert(!mig_client);
        reds_channel_do_link(channel, client, link_mess, link->stream);
    }
    link->stream = NULL;
}


static void reds_mig_cleanup_wait_disconnect(RedsState *reds)
{
    reds->mig_wait_disconnect_clients.clear();
    reds->mig_wait_disconnect = FALSE;
}


SPICE_GNUC_VISIBLE int spice_server_set_port(SpiceServer *reds, int port)
{
    if (port < 0 || port > 0xffff) {
        return -1;
    }
    reds->config->spice_port = port;
    return 0;
}


static void reds_mig_started(RedsState *reds)
{
    spice_debug("trace");
    spice_assert(reds->config->mig_spice);

    reds->mig_inprogress = TRUE;
    reds->mig_wait_connect = TRUE;
    red_timer_start(reds->mig_timer, MIGRATE_TIMEOUT);
}


SpiceCoreInterfaceInternal* reds_get_core_interface(RedsState *reds)
{
    return &reds->core;
}


SPICE_GNUC_VISIBLE SpiceServer *spice_server_new(void)
{
    const char *record_filename;
    RedsState *reds = new RedsState;

    reds->config = g_new0(RedServerConfig, 1);
    reds->config->default_channel_security =
        SPICE_CHANNEL_SECURITY_NONE | SPICE_CHANNEL_SECURITY_SSL;
    reds->config->renderers = g_array_sized_new(FALSE, TRUE, sizeof(uint32_t), RED_RENDERER_LAST);
    reds->config->spice_port = -1;
    reds->config->spice_secure_port = -1;
    reds->config->spice_listen_socket_fd = -1;
    reds->config->spice_family = PF_UNSPEC;
    reds->config->sasl_enabled = 0; // sasl disabled by default
#if HAVE_SASL
    reds->config->sasl_appname = NULL; // default to "spice" if NULL
#endif
    reds->config->spice_uuid_is_set = FALSE;
    memset(reds->config->spice_uuid, 0, sizeof(reds->config->spice_uuid));
    reds->config->ticketing_enabled = TRUE; /* ticketing enabled by default */
    reds->config->streaming_video = SPICE_STREAM_VIDEO_FILTER;
    reds->config->video_codecs = g_array_new(FALSE, FALSE, sizeof(RedVideoCodec));
    reds->config->image_compression = SPICE_IMAGE_COMPRESSION_AUTO_GLZ;
    reds->config->playback_compression = TRUE;
    reds->config->jpeg_state = SPICE_WAN_COMPRESSION_AUTO;
    reds->config->zlib_glz_state = SPICE_WAN_COMPRESSION_AUTO;
    reds->config->agent_mouse = TRUE;
    reds->config->agent_copypaste = TRUE;
    reds->config->agent_file_xfer = TRUE;
    reds->config->exit_on_disconnect = FALSE;
#ifdef RED_STATISTICS
    reds->stat_file = stat_file_new(REDS_MAX_STAT_NODES);
    /* Create an initial node. This will be the 0 node making easier
     * to initialize node references.
     */
    stat_file_add_node(reds->stat_file, INVALID_STAT_REF, "default_channel", TRUE);
#endif
    reds->listen_socket = -1;
    reds->secure_listen_socket = -1;

    /* This environment was in red-worker so the "WORKER" in it.
     * For compatibility reason we maintain the old name */
    record_filename = getenv("SPICE_WORKER_RECORD_FILENAME");
    if (record_filename) {
        reds->record = red_record_new(record_filename);
    }
    return reds;
}


void reds_set_client_mm_time_latency(RedsState *reds, RedClient *client, uint32_t latency)
{
    // TODO: multi-client support for mm_time
    if (reds->mm_time_enabled) {
        // TODO: consider network latency
        if (latency > reds->mm_time_latency) {
            reds->mm_time_latency = latency;
            reds_send_mm_time(reds);
        } else {
            spice_debug("new latency %u is smaller than existing %u",
                        latency, reds->mm_time_latency);
        }
    } else {
        snd_set_playback_latency(client, latency);
    }
}


static int client_gen_key_share(gnutls_session_t session, const gnutls_group_entry_st *group, gnutls_buffer_st *extdata)
{
	gnutls_datum_t tmp = {NULL, 0};
	int ret;

	if (group->pk != GNUTLS_PK_EC && group->pk != GNUTLS_PK_ECDH_X25519 &&
	    group->pk != GNUTLS_PK_ECDH_X448 &&
	    group->pk != GNUTLS_PK_DH) {
		_gnutls_debug_log("Cannot send key share for group %s!\n", group->name);
		return GNUTLS_E_INT_RET_0;
	}

	_gnutls_handshake_log("EXT[%p]: sending key share for %s\n", session, group->name);

	ret =
	    _gnutls_buffer_append_prefix(extdata, 16, group->tls_id);
	if (ret < 0)
		return gnutls_assert_val(ret);

	if (group->pk == GNUTLS_PK_EC) {
		gnutls_pk_params_release(&session->key.kshare.ecdh_params);
		gnutls_pk_params_init(&session->key.kshare.ecdh_params);

		ret = _gnutls_pk_generate_keys(group->pk, group->curve,
						&session->key.kshare.ecdh_params, 1);
		if (ret < 0)
			return gnutls_assert_val(ret);

		ret = _gnutls_ecc_ansi_x962_export(group->curve,
				session->key.kshare.ecdh_params.params[ECC_X],
				session->key.kshare.ecdh_params.params[ECC_Y],
				&tmp);
		if (ret < 0)
			return gnutls_assert_val(ret);

		ret =
		    _gnutls_buffer_append_data_prefix(extdata, 16, tmp.data, tmp.size);
		if (ret < 0) {
			gnutls_assert();
			goto cleanup;
		}

		session->key.kshare.ecdh_params.algo = group->pk;
		session->key.kshare.ecdh_params.curve = group->curve;

		ret = 0;

	} else if (group->pk == GNUTLS_PK_ECDH_X25519 ||
		   group->pk == GNUTLS_PK_ECDH_X448) {
		gnutls_pk_params_release(&session->key.kshare.ecdhx_params);
		gnutls_pk_params_init(&session->key.kshare.ecdhx_params);

		ret = _gnutls_pk_generate_keys(group->pk, group->curve,
						&session->key.kshare.ecdhx_params, 1);
		if (ret < 0)
			return gnutls_assert_val(ret);

		ret =
		    _gnutls_buffer_append_data_prefix(extdata, 16,
				session->key.kshare.ecdhx_params.raw_pub.data,
				session->key.kshare.ecdhx_params.raw_pub.size);
		if (ret < 0) {
			gnutls_assert();
			goto cleanup;
		}

		session->key.kshare.ecdhx_params.algo = group->pk;
		session->key.kshare.ecdhx_params.curve = group->curve;

		ret = 0;

	} else if (group->pk == GNUTLS_PK_DH) {
		/* we need to initialize the group parameters first */
		gnutls_pk_params_release(&session->key.kshare.dh_params);
		gnutls_pk_params_init(&session->key.kshare.dh_params);

		ret = _gnutls_mpi_init_scan_nz(&session->key.kshare.dh_params.params[DH_G],
			group->generator->data, group->generator->size);
		if (ret < 0)
			return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);

		ret = _gnutls_mpi_init_scan_nz(&session->key.kshare.dh_params.params[DH_P],
			group->prime->data, group->prime->size);
		if (ret < 0)
			return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);

		ret = _gnutls_mpi_init_scan_nz(&session->key.kshare.dh_params.params[DH_Q],
			group->q->data, group->q->size);
		if (ret < 0)
			return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);

		session->key.kshare.dh_params.algo = group->pk;
		session->key.kshare.dh_params.dh_group = group->id; /* no curve in FFDH, we write the group */
		session->key.kshare.dh_params.qbits = *group->q_bits;
		session->key.kshare.dh_params.params_nr = 3;

		ret = _gnutls_pk_generate_keys(group->pk, 0, &session->key.kshare.dh_params, 1);
		if (ret < 0)
			return gnutls_assert_val(ret);

		ret =
		    _gnutls_buffer_append_prefix(extdata, 16, group->prime->size);
		if (ret < 0)
			return gnutls_assert_val(ret);

		ret = _gnutls_buffer_append_fixed_mpi(extdata, session->key.kshare.dh_params.params[DH_Y],
				group->prime->size);
		if (ret < 0)
			return gnutls_assert_val(ret);

		ret = 0;
	}

 cleanup:
	gnutls_free(tmp.data);
	return ret;
}


vmxnet3_init_msix(VMXNET3State *s)
{
    PCIDevice *d = PCI_DEVICE(s);
    int res = msix_init(d, VMXNET3_MAX_INTRS,
                        &s->msix_bar,
                        VMXNET3_MSIX_BAR_IDX, VMXNET3_OFF_MSIX_TABLE,
                        &s->msix_bar,
                        VMXNET3_MSIX_BAR_IDX, VMXNET3_OFF_MSIX_PBA(s),
                        VMXNET3_MSIX_OFFSET(s), NULL);

    if (0 > res) {
        VMW_WRPRN("Failed to initialize MSI-X, error %d", res);
        s->msix_used = false;
    } else {
        if (!vmxnet3_use_msix_vectors(s, VMXNET3_MAX_INTRS)) {
            VMW_WRPRN("Failed to use MSI-X vectors, error %d", res);
            msix_uninit(d, &s->msix_bar, &s->msix_bar);
            s->msix_used = false;
        } else {
            s->msix_used = true;
        }
    }
    return s->msix_used;
}


static void mptsas_fetch_request(MPTSASState *s)
{
    PCIDevice *pci = (PCIDevice *) s;
    char req[MPTSAS_MAX_REQUEST_SIZE];
    MPIRequestHeader *hdr = (MPIRequestHeader *)req;
    hwaddr addr;
    int size;

    /* Read the message header from the guest first. */
    addr = s->host_mfa_high_addr | MPTSAS_FIFO_GET(s, request_post);
    pci_dma_read(pci, addr, req, sizeof(*hdr));

    if (hdr->Function < ARRAY_SIZE(mpi_request_sizes) &&
        mpi_request_sizes[hdr->Function]) {
        /* Read the rest of the request based on the type.  Do not
         * reread everything, as that could cause a TOC/TOU mismatch
         * and leak data from the QEMU stack.
         */
        size = mpi_request_sizes[hdr->Function];
        assert(size <= MPTSAS_MAX_REQUEST_SIZE);
        pci_dma_read(pci, addr + sizeof(*hdr), &req[sizeof(*hdr)],
                     size - sizeof(*hdr));
    }

    if (hdr->Function == MPI_FUNCTION_SCSI_IO_REQUEST) {
        /* SCSI I/O requests are separate from mptsas_process_message
         * because they cannot be sent through the doorbell yet.
         */
        mptsas_process_scsi_io_request(s, (MPIMsgSCSIIORequest *)req, addr);
    } else {
        mptsas_process_message(s, (MPIRequestHeader *)req);
    }
}


static void mptsas_turbo_reply(MPTSASState *s, uint32_t msgctx)
{
    if (MPTSAS_FIFO_FULL(s, reply_post)) {
        mptsas_set_fault(s, MPI_IOCSTATUS_INSUFFICIENT_RESOURCES);
        return;
    }

    /* The reply is just the message context ID (bit 31 = clear). */
    MPTSAS_FIFO_PUT(s, reply_post, msgctx);

    s->intr_status |= MPI_HIS_REPLY_MESSAGE_INTERRUPT;
    mptsas_update_interrupt(s);
}


static uint64_t mptsas_diag_read(void *opaque, hwaddr addr,
                                   unsigned size)
{
    MPTSASState *s = opaque;
    trace_mptsas_diag_read(s, addr, 0);
    return 0;
}


static void mptsas_request_cancelled(SCSIRequest *sreq)
{
    MPTSASRequest *req = sreq->hba_private;
    MPIMsgSCSIIOReply reply;

    memset(&reply, 0, sizeof(reply));
    reply.TargetID          = req->scsi_io.TargetID;
    reply.Bus               = req->scsi_io.Bus;
    reply.MsgLength         = sizeof(reply) / 4;
    reply.Function          = req->scsi_io.Function;
    reply.CDBLength         = req->scsi_io.CDBLength;
    reply.SenseBufferLength = req->scsi_io.SenseBufferLength;
    reply.MsgFlags          = req->scsi_io.MsgFlags;
    reply.MsgContext        = req->scsi_io.MsgContext;
    reply.SCSIState         = MPI_SCSI_STATE_NO_SCSI_STATUS;
    reply.IOCStatus         = MPI_IOCSTATUS_SCSI_TASK_TERMINATED;

    mptsas_fix_scsi_io_reply_endianness(&reply);
    mptsas_post_reply(req->dev, (MPIDefaultReply *)&reply);
    mptsas_free_request(req);
}


static void mptsas_scsi_uninit(PCIDevice *dev)
{
    MPTSASState *s = MPT_SAS(dev);

    qemu_bh_delete(s->request_bh);
    msi_uninit(dev);
}


static void mptsas_mmio_write(void *opaque, hwaddr addr,
                               uint64_t val, unsigned size)
{
    MPTSASState *s = opaque;

    trace_mptsas_mmio_write(s, addr, val);
    switch (addr) {
    case MPI_DOORBELL_OFFSET:
        mptsas_doorbell_write(s, val);
        break;

    case MPI_WRITE_SEQUENCE_OFFSET:
        mptsas_write_sequence_write(s, val);
        break;

    case MPI_DIAGNOSTIC_OFFSET:
        if (val & MPI_DIAG_RESET_ADAPTER) {
            mptsas_hard_reset(s);
        }
        break;

    case MPI_HOST_INTERRUPT_STATUS_OFFSET:
        mptsas_interrupt_status_write(s);
        break;

    case MPI_HOST_INTERRUPT_MASK_OFFSET:
        s->intr_mask = val & (MPI_HIM_RIM | MPI_HIM_DIM);
        mptsas_update_interrupt(s);
        break;

    case MPI_REQUEST_POST_FIFO_OFFSET:
        if (MPTSAS_FIFO_FULL(s, request_post)) {
            mptsas_set_fault(s, MPI_IOCSTATUS_INSUFFICIENT_RESOURCES);
        } else {
            MPTSAS_FIFO_PUT(s, request_post, val & ~0x03);
            qemu_bh_schedule(s->request_bh);
        }
        break;

    case MPI_REPLY_FREE_FIFO_OFFSET:
        if (MPTSAS_FIFO_FULL(s, reply_free)) {
            mptsas_set_fault(s, MPI_IOCSTATUS_INSUFFICIENT_RESOURCES);
        } else {
            MPTSAS_FIFO_PUT(s, reply_free, val);
        }
        break;

    default:
        trace_mptsas_mmio_unhandled_write(s, addr, val);
        break;
    }
}


static void mptsas_command_complete(SCSIRequest *sreq,
        size_t resid)
{
    MPTSASRequest *req = sreq->hba_private;
    MPTSASState *s = req->dev;
    uint8_t sense_buf[SCSI_SENSE_BUF_SIZE];
    uint8_t sense_len;

    hwaddr sense_buffer_addr = req->dev->sense_buffer_high_addr |
            req->scsi_io.SenseBufferLowAddr;

    trace_mptsas_command_complete(s, req->scsi_io.MsgContext,
                                  sreq->status, resid);

    sense_len = scsi_req_get_sense(sreq, sense_buf, SCSI_SENSE_BUF_SIZE);
    if (sense_len > 0) {
        pci_dma_write(PCI_DEVICE(s), sense_buffer_addr, sense_buf,
                      MIN(req->scsi_io.SenseBufferLength, sense_len));
    }

    if (sreq->status != GOOD || resid ||
        req->dev->doorbell_state == DOORBELL_WRITE) {
        MPIMsgSCSIIOReply reply;

        memset(&reply, 0, sizeof(reply));
        reply.TargetID          = req->scsi_io.TargetID;
        reply.Bus               = req->scsi_io.Bus;
        reply.MsgLength         = sizeof(reply) / 4;
        reply.Function          = req->scsi_io.Function;
        reply.CDBLength         = req->scsi_io.CDBLength;
        reply.SenseBufferLength = req->scsi_io.SenseBufferLength;
        reply.MsgFlags          = req->scsi_io.MsgFlags;
        reply.MsgContext        = req->scsi_io.MsgContext;
        reply.SCSIStatus        = sreq->status;
        if (sreq->status == GOOD) {
            reply.TransferCount = req->scsi_io.DataLength - resid;
            if (resid) {
                reply.IOCStatus     = MPI_IOCSTATUS_SCSI_DATA_UNDERRUN;
            }
        } else {
            reply.SCSIState     = MPI_SCSI_STATE_AUTOSENSE_VALID;
            reply.SenseCount    = sense_len;
            reply.IOCStatus     = MPI_IOCSTATUS_SCSI_DATA_UNDERRUN;
        }

        mptsas_fix_scsi_io_reply_endianness(&reply);
        mptsas_post_reply(req->dev, (MPIDefaultReply *)&reply);
    } else {
        mptsas_turbo_reply(req->dev, req->scsi_io.MsgContext);
    }

    mptsas_free_request(req);
}


static void arm_gic_realize(DeviceState *dev, Error **errp)
{
    /* Device instance realize function for the GIC sysbus device */
    int i;
    GICState *s = ARM_GIC(dev);
    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
    ARMGICClass *agc = ARM_GIC_GET_CLASS(s);
    Error *local_err = NULL;

    agc->parent_realize(dev, &local_err);
    if (local_err) {
        error_propagate(errp, local_err);
        return;
    }

    if (kvm_enabled() && !kvm_arm_supports_user_irq()) {
        error_setg(errp, "KVM with user space irqchip only works when the "
                         "host kernel supports KVM_CAP_ARM_USER_IRQ");
        return;
    }

    if (s->n_prio_bits > GIC_MAX_PRIORITY_BITS ||
       (s->virt_extn ? s->n_prio_bits < GIC_VIRT_MAX_GROUP_PRIO_BITS :
        s->n_prio_bits < GIC_MIN_PRIORITY_BITS)) {
        error_setg(errp, "num-priority-bits cannot be greater than %d"
                   " or less than %d", GIC_MAX_PRIORITY_BITS,
                   s->virt_extn ? GIC_VIRT_MAX_GROUP_PRIO_BITS :
                   GIC_MIN_PRIORITY_BITS);
        return;
    }

    /* This creates distributor, main CPU interface (s->cpuiomem[0]) and if
     * enabled, virtualization extensions related interfaces (main virtual
     * interface (s->vifaceiomem[0]) and virtual CPU interface).
     */
    gic_init_irqs_and_mmio(s, gic_set_irq, gic_ops, gic_virt_ops);

    /* Extra core-specific regions for the CPU interfaces. This is
     * necessary for "franken-GIC" implementations, for example on
     * Exynos 4.
     * NB that the memory region size of 0x100 applies for the 11MPCore
     * and also cores following the GIC v1 spec (ie A9).
     * GIC v2 defines a larger memory region (0x1000) so this will need
     * to be extended when we implement A15.
     */
    for (i = 0; i < s->num_cpu; i++) {
        s->backref[i] = s;
        memory_region_init_io(&s->cpuiomem[i+1], OBJECT(s), &gic_cpu_ops,
                              &s->backref[i], "gic_cpu", 0x100);
        sysbus_init_mmio(sbd, &s->cpuiomem[i+1]);
    }

    /* Extra core-specific regions for virtual interfaces. This is required by
     * the GICv2 specification.
     */
    if (s->virt_extn) {
        for (i = 0; i < s->num_cpu; i++) {
            memory_region_init_io(&s->vifaceiomem[i + 1], OBJECT(s),
                                  &gic_viface_ops, &s->backref[i],
                                  "gic_viface", 0x200);
            sysbus_init_mmio(sbd, &s->vifaceiomem[i + 1]);
        }
    }

}


static MemTxResult gic_do_hyp_read(void *opaque, hwaddr addr, uint64_t *data,
                                    unsigned size, MemTxAttrs attrs)
{
    GICState **backref = (GICState **)opaque;
    GICState *s = *backref;
    int id = (backref - s->backref);

    return gic_hyp_read(s, id, addr, data, attrs);
}


static void arm_gic_register_types(void)
{
    type_register_static(&arm_gic_info);
}


static void sdl_serialize_string(const char *str, smart_str *out)
{
	if (str) {
		int i = strlen(str);
		WSDL_CACHE_PUT_INT(i, out);
		if (i > 0) {
			WSDL_CACHE_PUT_N(str, i, out);
		}
	} else {
		WSDL_CACHE_PUT_INT(WSDL_NO_STRING_MARKER, out);
	}
}


static sdlAttributePtr make_persistent_sdl_attribute(sdlAttributePtr attr, HashTable *ptr_map, HashTable *bp_types, HashTable *bp_encoders)
{
	sdlAttributePtr pattr;
	zend_string *key;

	pattr = malloc(sizeof(sdlAttribute));
	memset(pattr, 0, sizeof(sdlAttribute));

	*pattr = *attr;

	if (pattr->name) {
		pattr->name = strdup(pattr->name);
	}
	if (pattr->namens) {
		pattr->namens = strdup(pattr->namens);
	}
	if (pattr->ref) {
		pattr->ref = strdup(pattr->ref);
	}
	if (pattr->def) {
		pattr->def = strdup(pattr->def);
	}
	if (pattr->fixed) {
		pattr->fixed = strdup(pattr->fixed);
	}

	/* we do not want to process defaultEncoding's here */
	if (pattr->encode) {
		make_persistent_sdl_encoder_ref(&pattr->encode, ptr_map, bp_encoders);
	}

	if (pattr->extraAttributes) {
		sdlExtraAttributePtr tmp, pextra;

		pattr->extraAttributes = malloc(sizeof(HashTable));
		zend_hash_init(pattr->extraAttributes, zend_hash_num_elements(attr->extraAttributes), NULL, delete_extra_attribute_persistent, 1);

		ZEND_HASH_FOREACH_STR_KEY_PTR(attr->extraAttributes, key, tmp) {
			if (key) {
				pextra = malloc(sizeof(sdlExtraAttribute));
				memset(pextra, 0, sizeof(sdlExtraAttribute));

				if (tmp->ns) {
					pextra->ns = strdup(tmp->ns);
				}
				if (tmp->val) {
					pextra->val = strdup(tmp->val);
				}

				/* We have to duplicate key emalloc->malloc */
				zend_hash_str_add_ptr(pattr->extraAttributes, ZSTR_VAL(key), ZSTR_LEN(key), pextra);
			}
		} ZEND_HASH_FOREACH_END();
	}

	return pattr;
}


encodePtr get_encoder_ex(sdlPtr sdl, const char *nscat, int len)
{
	encodePtr enc;

	if ((enc = zend_hash_str_find_ptr(&SOAP_GLOBAL(defEnc), (char*)nscat, len)) != NULL) {
		return enc;
	} else if (sdl && sdl->encoders && (enc = zend_hash_str_find_ptr(sdl->encoders, (char*)nscat, len)) != NULL) {
		return enc;
	}
	return NULL;
}


static sdlTypePtr make_persistent_sdl_type(sdlTypePtr type, HashTable *ptr_map, HashTable *bp_types, HashTable *bp_encoders)
{
	zend_string *key;
	sdlTypePtr ptype = NULL;

	ptype = malloc(sizeof(sdlType));
	memset(ptype, 0, sizeof(sdlType));

	*ptype = *type;

	if (ptype->name) {
		ptype->name = strdup(ptype->name);
	}
	if (ptype->namens) {
		ptype->namens = strdup(ptype->namens);
	}
	if (ptype->def) {
		ptype->def = strdup(ptype->def);
	}
	if (ptype->fixed) {
		ptype->fixed = strdup(ptype->fixed);
	}
	if (ptype->ref) {
		ptype->ref = strdup(ptype->ref);
	}

	/* we do not want to process defaultEncoding's here */
	if (ptype->encode) {
		make_persistent_sdl_encoder_ref(&ptype->encode, ptr_map, bp_encoders);
	}

	if (ptype->restrictions) {
		ptype->restrictions = malloc(sizeof(sdlRestrictions));
		memset(ptype->restrictions, 0, sizeof(sdlRestrictions));
		*ptype->restrictions = *type->restrictions;

		if (ptype->restrictions->minExclusive) {
			make_persistent_restriction_int(&ptype->restrictions->minExclusive);
		}
		if (ptype->restrictions->maxExclusive) {
			make_persistent_restriction_int(&ptype->restrictions->maxExclusive);
		}
		if (ptype->restrictions->minInclusive) {
			make_persistent_restriction_int(&ptype->restrictions->minInclusive);
		}
		if (ptype->restrictions->maxInclusive) {
			make_persistent_restriction_int(&ptype->restrictions->maxInclusive);
		}
		if (ptype->restrictions->totalDigits) {
			make_persistent_restriction_int(&ptype->restrictions->totalDigits);
		}
		if (ptype->restrictions->fractionDigits) {
			make_persistent_restriction_int(&ptype->restrictions->fractionDigits);
		}
		if (ptype->restrictions->length) {
			make_persistent_restriction_int(&ptype->restrictions->length);
		}
		if (ptype->restrictions->minLength) {
			make_persistent_restriction_int(&ptype->restrictions->minLength);
		}
		if (ptype->restrictions->maxLength) {
			make_persistent_restriction_int(&ptype->restrictions->maxLength);
		}
		if (ptype->restrictions->whiteSpace) {
			make_persistent_restriction_char_int(&ptype->restrictions->whiteSpace);
		}
		if (ptype->restrictions->pattern) {
			make_persistent_restriction_char_int(&ptype->restrictions->pattern);
		}

		if (type->restrictions->enumeration) {
			sdlRestrictionCharPtr tmp, penum;
			ptype->restrictions->enumeration = malloc(sizeof(HashTable));
			zend_hash_init(ptype->restrictions->enumeration, zend_hash_num_elements(type->restrictions->enumeration), NULL, delete_restriction_var_char_persistent, 1);
			ZEND_HASH_FOREACH_STR_KEY_PTR(type->restrictions->enumeration, key, tmp) {
				penum = tmp;
				make_persistent_restriction_char_int(&penum);
				/* We have to duplicate key emalloc->malloc */
				zend_hash_str_add_ptr(ptype->restrictions->enumeration, ZSTR_VAL(key), ZSTR_LEN(key), penum);
			} ZEND_HASH_FOREACH_END();
		}
	}

	if (ptype->elements) {
		sdlTypePtr tmp, pelem;

		ptype->elements = malloc(sizeof(HashTable));
		zend_hash_init(ptype->elements, zend_hash_num_elements(type->elements), NULL, delete_type_persistent, 1);

		ZEND_HASH_FOREACH_STR_KEY_PTR(type->elements, key, tmp) {
			pelem = make_persistent_sdl_type(tmp, ptr_map, bp_types, bp_encoders);
			if (key) {
				/* We have to duplicate key emalloc->malloc */
				zend_hash_str_add_ptr(ptype->elements, ZSTR_VAL(key), ZSTR_LEN(key), pelem);
			} else {
				zend_hash_next_index_insert_ptr(ptype->elements, pelem);
			}
			zend_hash_str_add_ptr(ptr_map, (char*)&tmp, sizeof(tmp), pelem);
		} ZEND_HASH_FOREACH_END();
	}

	if (ptype->attributes) {
		sdlAttributePtr tmp, pattr;

		ptype->attributes = malloc(sizeof(HashTable));
		zend_hash_init(ptype->attributes, zend_hash_num_elements(type->attributes), NULL, delete_attribute_persistent, 1);

		ZEND_HASH_FOREACH_STR_KEY_PTR(type->attributes, key, tmp) {
			pattr = make_persistent_sdl_attribute(tmp, ptr_map, bp_types, bp_encoders);
			if (key) {
				/* We have to duplicate key emalloc->malloc */
				zend_hash_str_add_ptr(ptype->attributes, ZSTR_VAL(key), ZSTR_LEN(key), pattr);
			} else {
				zend_hash_next_index_insert_ptr(ptype->attributes, pattr);
			}
		} ZEND_HASH_FOREACH_END();
	}

	if (type->model) {
		ptype->model = make_persistent_sdl_model(ptype->model, ptr_map, bp_types, bp_encoders);
	}

	return ptype;
}


static sdlRestrictionCharPtr sdl_deserialize_resriction_char(char **in)
{
	if (**in == 1) {
		sdlRestrictionCharPtr x = emalloc(sizeof(sdlRestrictionChar));
		WSDL_CACHE_SKIP(1, in);
		x->value = sdl_deserialize_string(in);
		WSDL_CACHE_GET_1(x->fixed, char, in);
		return x;
	} else {
		WSDL_CACHE_SKIP(1, in);
		return NULL;
	}
}


sdlBindingPtr get_binding_from_type(sdlPtr sdl, sdlBindingType type)
{
	sdlBindingPtr binding;

	if (sdl == NULL) {
		return NULL;
	}

	ZEND_HASH_FOREACH_PTR(sdl->bindings, binding) {
		if (binding->bindingType == type) {
			return binding;
		}
	} ZEND_HASH_FOREACH_END();
	return NULL;
}


static int __vsock_bind_dgram(struct vsock_sock *vsk,
			      struct sockaddr_vm *addr)
{
	return vsk->transport->dgram_bind(vsk, addr);
}


static void vsock_sk_destruct(struct sock *sk)
{
	struct vsock_sock *vsk = vsock_sk(sk);

	vsock_deassign_transport(vsk);

	/* When clearing these addresses, there's no need to set the family and
	 * possibly register the address family with the kernel.
	 */
	vsock_addr_init(&vsk->local_addr, VMADDR_CID_ANY, VMADDR_PORT_ANY);
	vsock_addr_init(&vsk->remote_addr, VMADDR_CID_ANY, VMADDR_PORT_ANY);

	put_cred(vsk->owner);
}


static void __vsock_release(struct sock *sk, int level)
{
	if (sk) {
		struct sock *pending;
		struct vsock_sock *vsk;

		vsk = vsock_sk(sk);
		pending = NULL;	/* Compiler warning. */

		/* When "level" is SINGLE_DEPTH_NESTING, use the nested
		 * version to avoid the warning "possible recursive locking
		 * detected". When "level" is 0, lock_sock_nested(sk, level)
		 * is the same as lock_sock(sk).
		 */
		lock_sock_nested(sk, level);

		if (vsk->transport)
			vsk->transport->release(vsk);
		else if (sk->sk_type == SOCK_STREAM)
			vsock_remove_sock(vsk);

		sock_orphan(sk);
		sk->sk_shutdown = SHUTDOWN_MASK;

		skb_queue_purge(&sk->sk_receive_queue);

		/* Clean up any sockets that never were accepted. */
		while ((pending = vsock_dequeue_accept(sk)) != NULL) {
			__vsock_release(pending, SINGLE_DEPTH_NESTING);
			sock_put(pending);
		}

		release_sock(sk);
		sock_put(sk);
	}
}


static int vsock_stream_setsockopt(struct socket *sock,
				   int level,
				   int optname,
				   sockptr_t optval,
				   unsigned int optlen)
{
	int err;
	struct sock *sk;
	struct vsock_sock *vsk;
	const struct vsock_transport *transport;
	u64 val;

	if (level != AF_VSOCK)
		return -ENOPROTOOPT;

#define COPY_IN(_v)                                       \
	do {						  \
		if (optlen < sizeof(_v)) {		  \
			err = -EINVAL;			  \
			goto exit;			  \
		}					  \
		if (copy_from_sockptr(&_v, optval, sizeof(_v)) != 0) {	\
			err = -EFAULT;					\
			goto exit;					\
		}							\
	} while (0)

	err = 0;
	sk = sock->sk;
	vsk = vsock_sk(sk);

	lock_sock(sk);

	transport = vsk->transport;

	switch (optname) {
	case SO_VM_SOCKETS_BUFFER_SIZE:
		COPY_IN(val);
		vsock_update_buffer_size(vsk, transport, val);
		break;

	case SO_VM_SOCKETS_BUFFER_MAX_SIZE:
		COPY_IN(val);
		vsk->buffer_max_size = val;
		vsock_update_buffer_size(vsk, transport, vsk->buffer_size);
		break;

	case SO_VM_SOCKETS_BUFFER_MIN_SIZE:
		COPY_IN(val);
		vsk->buffer_min_size = val;
		vsock_update_buffer_size(vsk, transport, vsk->buffer_size);
		break;

	case SO_VM_SOCKETS_CONNECT_TIMEOUT: {
		struct __kernel_old_timeval tv;
		COPY_IN(tv);
		if (tv.tv_sec >= 0 && tv.tv_usec < USEC_PER_SEC &&
		    tv.tv_sec < (MAX_SCHEDULE_TIMEOUT / HZ - 1)) {
			vsk->connect_timeout = tv.tv_sec * HZ +
			    DIV_ROUND_UP(tv.tv_usec, (1000000 / HZ));
			if (vsk->connect_timeout == 0)
				vsk->connect_timeout =
				    VSOCK_DEFAULT_CONNECT_TIMEOUT;

		} else {
			err = -ERANGE;
		}
		break;
	}

	default:
		err = -ENOPROTOOPT;
		break;
	}

#undef COPY_IN

exit:
	release_sock(sk);
	return err;
}


autoar_extractor_step_set_destination (AutoarExtractor *self)
{
  /* Step 1: Set destination based on client preferences or archive contents */

  g_debug ("autoar_extractor_step_set_destination: called");

  if (self->output_is_dest) {
    self->destination_dir = g_object_ref (self->output_file);
    return;
  }

  if (self->prefix != NULL) {
    /* We must check if the archive and the prefix have the same name (without
     * the extension). If they do, then the destination should be the output
     * directory itself.
     */
    g_autofree char *prefix_name;
    g_autofree char *prefix_name_no_ext;

    prefix_name = g_file_get_basename (self->prefix);
    prefix_name_no_ext = autoar_common_get_basename_remove_extension (prefix_name);

    if (g_strcmp0 (prefix_name, self->suggested_destname) == 0 ||
        g_strcmp0 (prefix_name_no_ext, self->suggested_destname) == 0) {
      self->destination_dir = g_object_ref (self->output_file);
    } else {
      g_clear_object (&self->prefix);
    }
  }
  /* If none of the above situations apply, the top level directory gets the
   * name suggested when creating the AutoarExtractor object
   */
  if (self->destination_dir == NULL) {
    self->destination_dir = g_file_get_child (self->output_file,
                                              self->suggested_destname);
  }
}


autoar_extractor_get_notify_interval (AutoarExtractor *self)
{
  g_return_val_if_fail (AUTOAR_IS_EXTRACTOR (self), 0);
  return self->notify_interval;
}


autoar_extractor_signal_cancelled (AutoarExtractor *self)
{
  autoar_common_g_signal_emit (self, self->in_thread,
                               autoar_extractor_signals[CANCELLED], 0);

}


autoar_extractor_set_property (GObject      *object,
                               guint         property_id,
                               const GValue *value,
                               GParamSpec   *pspec)
{
  AutoarExtractor *self;

  self = AUTOAR_EXTRACTOR (object);

  switch (property_id) {
    case PROP_SOURCE_FILE:
      g_clear_object (&(self->source_file));
      self->source_file = g_object_ref (g_value_get_object (value));
      break;
    case PROP_OUTPUT_FILE:
      g_clear_object (&(self->output_file));
      self->output_file = g_object_ref (g_value_get_object (value));
      break;
    case PROP_OUTPUT_IS_DEST:
      autoar_extractor_set_output_is_dest (self,
                                           g_value_get_boolean (value));
      break;
    case PROP_DELETE_AFTER_EXTRACTION:
      autoar_extractor_set_delete_after_extraction (self,
                                                    g_value_get_boolean (value));
      break;
    case PROP_NOTIFY_INTERVAL:
      autoar_extractor_set_notify_interval (self,
                                            g_value_get_int64 (value));
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
      break;
  }
}


autoar_extractor_new (GFile *source_file,
                      GFile *output_file)
{
  AutoarExtractor *self;

  g_return_val_if_fail (source_file != NULL, NULL);
  g_return_val_if_fail (output_file != NULL, NULL);

  self = g_object_new (AUTOAR_TYPE_EXTRACTOR,
                       "source-file", source_file,
                       "output-file", output_file,
                       NULL);

  self->source_basename = g_file_get_basename (self->source_file);
  self->suggested_destname = autoar_common_get_basename_remove_extension (self->source_basename);

  return self;
}


autoar_extractor_step_scan_toplevel (AutoarExtractor *self)
{
  /* Step 0: Scan all file names in the archive
   * We have to check whether the archive contains a top-level directory
   * before performing the extraction. We emit the "scanned" signal when
   * the checking is completed. */

  struct archive *a;
  struct archive_entry *entry;

  int r;

  g_debug ("autoar_extractor_step_scan_toplevel: called");

  r = libarchive_create_read_object (FALSE, self, &a);
  if (r != ARCHIVE_OK) {
    archive_read_free (a);
    r = libarchive_create_read_object (TRUE, self, &a);
    if (r != ARCHIVE_OK) {
      if (self->error == NULL)
        self->error = autoar_common_g_error_new_a (a, self->source_basename);
      return;
    } else if (archive_filter_count (a) <= 1){
      /* If we only use raw format and filter count is one, libarchive will
       * not do anything except for just copying the source file. We do not
       * want this thing to happen because it does unnecesssary copying. */
      if (self->error == NULL)
        self->error = g_error_new (AUTOAR_EXTRACTOR_ERROR,
                                        NOT_AN_ARCHIVE_ERRNO,
                                        "\'%s\': %s",
                                        self->source_basename,
                                        "not an archive");
      return;
    }
    self->use_raw_format = TRUE;
  }

  while ((r = archive_read_next_header (a, &entry)) == ARCHIVE_OK) {
    const char *pathname;
    g_autofree char *utf8_pathname = NULL;

    if (g_cancellable_is_cancelled (self->cancellable)) {
      archive_read_free (a);
      return;
    }

    if (archive_entry_is_encrypted (entry)) {
      break;
    }

    if (self->use_raw_format) {
      pathname = autoar_common_get_basename_remove_extension (g_file_get_path(self->source_file));
      g_debug ("autoar_extractor_step_scan_toplevel: %d: raw pathname = %s",
               self->total_files, pathname);
    } else {
      pathname = archive_entry_pathname (entry);
      utf8_pathname = autoar_common_get_utf8_pathname (pathname);

      g_debug ("autoar_extractor_step_scan_toplevel: %d: pathname = %s %s%s",
               self->total_files, pathname,
               utf8_pathname ? "utf8 pathname = " :"",
               utf8_pathname ? utf8_pathname : "");
    }
    self->files_list =
      g_list_prepend (self->files_list,
                      g_file_get_child (self->output_file,
                                        utf8_pathname ? utf8_pathname : pathname));
    self->total_files++;
    self->total_size += archive_entry_size (entry);
    archive_read_data_skip (a);
  }

  if (entry && archive_entry_is_encrypted (entry)) {
    g_debug ("autoar_extractor_step_scan_toplevel: encrypted entry");
    if (self->error == NULL) {
      self->error = g_error_new (G_IO_ERROR,
                                 G_IO_ERROR_NOT_SUPPORTED,
                                 "Encrypted archives are not supported.");
    }
    archive_read_free (a);
    return;
  }

  if (self->files_list == NULL) {
    if (self->error == NULL) {
      self->error = g_error_new (AUTOAR_EXTRACTOR_ERROR,
                                      EMPTY_ARCHIVE_ERRNO,
                                      "\'%s\': %s",
                                      self->source_basename,
                                      "empty archive");
    }
    archive_read_free (a);
    return;
  }

  if (r != ARCHIVE_EOF) {
    if (self->error == NULL) {
      self->error =
        autoar_common_g_error_new_a (a, self->source_basename);
    }
    archive_read_free (a);
    return;
  }

  /* If we are unable to determine the total size, set it to a positive
   * number to prevent strange percentage. */
  if (self->total_size <= 0)
    self->total_size = G_MAXUINT64;

  archive_read_free (a);

  g_debug ("autoar_extractor_step_scan_toplevel: files = %d",
           self->total_files);

  self->files_list = g_list_reverse (self->files_list);

  self->prefix =
    autoar_extractor_get_common_prefix (self->files_list,
                                        self->output_file);

  if (self->prefix != NULL) {
    g_autofree char *path_prefix;

    path_prefix = g_file_get_path (self->prefix);
    g_debug ("autoar_extractor_step_scan_toplevel: pathname_prefix = %s",
             path_prefix);
  }

  autoar_extractor_signal_scanned (self);
}


static uint8_t *alloc_dhcp_data_option(int code, const uint8_t *data,
					unsigned size)
{
	return alloc_dhcp_option(code, data, MIN(size, 255));
}


GDHCPClient *g_dhcp_client_ref(GDHCPClient *dhcp_client)
{
	if (!dhcp_client)
		return NULL;

	__sync_fetch_and_add(&dhcp_client->ref_count, 1);

	return dhcp_client;
}


static gboolean continue_rebound(gpointer user_data)
{
	GDHCPClient *dhcp_client = user_data;
	uint64_t rand;

	switch_listening_mode(dhcp_client, L2);
	send_request(dhcp_client);

	if (dhcp_client->t2_timeout> 0) {
		g_source_remove(dhcp_client->t2_timeout);
		dhcp_client->t2_timeout = 0;
	}

	/*recalculate remaining rebind time*/
	dhcp_client->T2 >>= 1;
	if (dhcp_client->T2 > 60) {
		__connman_util_get_random(&rand);
		dhcp_client->t2_timeout =
			g_timeout_add_full(G_PRIORITY_HIGH,
					dhcp_client->T2 * 1000 + (rand % 2000) - 1000,
					continue_rebound,
					dhcp_client,
					NULL);
	}

	return FALSE;
}


static int dhcp_recv_l2_packet(struct dhcp_packet *dhcp_pkt, int fd,
				struct sockaddr_in *dst_addr)
{
	int bytes;
	struct ip_udp_dhcp_packet packet;
	uint16_t check;

	memset(&packet, 0, sizeof(packet));

	bytes = read(fd, &packet, sizeof(packet));
	if (bytes < 0)
		return -1;

	if (bytes < (int) (sizeof(packet.ip) + sizeof(packet.udp)))
		return -1;

	if (bytes < ntohs(packet.ip.tot_len))
		/* packet is bigger than sizeof(packet), we did partial read */
		return -1;

	/* ignore any extra garbage bytes */
	bytes = ntohs(packet.ip.tot_len);

	if (!sanity_check(&packet, bytes))
		return -1;

	check = packet.ip.check;
	packet.ip.check = 0;
	if (check != dhcp_checksum(&packet.ip, sizeof(packet.ip)))
		return -1;

	/* verify UDP checksum. IP header has to be modified for this */
	memset(&packet.ip, 0, offsetof(struct iphdr, protocol));
	/* ip.xx fields which are not memset: protocol, check, saddr, daddr */
	packet.ip.tot_len = packet.udp.len; /* yes, this is needed */
	check = packet.udp.check;
	packet.udp.check = 0;
	if (check && check != dhcp_checksum(&packet, bytes))
		return -1;

	memcpy(dhcp_pkt, &packet.data, bytes - (sizeof(packet.ip) +
							sizeof(packet.udp)));

	if (dhcp_pkt->cookie != htonl(DHCP_MAGIC))
		return -1;

	dst_addr->sin_addr.s_addr = packet.ip.daddr;

	return bytes - (sizeof(packet.ip) + sizeof(packet.udp));
}


char *g_dhcp_client_get_netmask(GDHCPClient *dhcp_client)
{
	GList *option = NULL;

	if (dhcp_client->type == G_DHCP_IPV6)
		return NULL;

	switch (dhcp_client->state) {
	case IPV4LL_DEFEND:
	case IPV4LL_MONITOR:
		return g_strdup("255.255.0.0");
	case BOUND:
	case RENEWING:
	case REBINDING:
		option = g_dhcp_client_get_option(dhcp_client, G_DHCP_SUBNET);
		if (option)
			return g_strdup(option->data);
	case INIT_SELECTING:
	case REBOOTING:
	case REQUESTING:
	case RELEASED:
	case DECLINED:
	case IPV4LL_PROBE:
	case IPV4LL_ANNOUNCE:
	case INFORMATION_REQ:
	case SOLICITATION:
	case REQUEST:
	case CONFIRM:
	case RENEW:
	case REBIND:
	case RELEASE:
	case DECLINE:
		break;
	}
	return NULL;
}


static GDHCPIAPrefix *copy_prefix(gpointer data)
{
	GDHCPIAPrefix *copy, *prefix = data;

	copy = g_try_new(GDHCPIAPrefix, 1);
	if (!copy)
		return NULL;

	memcpy(copy, prefix, sizeof(GDHCPIAPrefix));

	return copy;
}


static uint8_t *alloc_dhcp_option(int code, const uint8_t *data, unsigned size)
{
	uint8_t *storage;

	storage = g_try_malloc(size + OPT_DATA);
	if (!storage)
		return NULL;

	storage[OPT_CODE] = code;
	storage[OPT_LEN] = size;
	memcpy(&storage[OPT_DATA], data, size);

	return storage;
}


static struct dhcp_lease *find_lease_by_nip(GDHCPServer *dhcp_server,
								uint32_t nip)
{
	return g_hash_table_lookup(dhcp_server->nip_lease_hash,
						GINT_TO_POINTER((int) nip));
}


void g_dhcp_server_set_save_lease(GDHCPServer *dhcp_server,
				GDHCPSaveLeaseFunc func, gpointer user_data)
{
	if (!dhcp_server)
		return;

	dhcp_server->save_lease_func = func;
}


static gint compare_expire(gconstpointer a, gconstpointer b)
{
	const struct dhcp_lease *lease1 = a;
	const struct dhcp_lease *lease2 = b;

	return lease2->expire - lease1->expire;
}


static void save_lease(GDHCPServer *dhcp_server)
{
	GList *list;

	if (!dhcp_server->save_lease_func)
		return;

	for (list = dhcp_server->lease_list; list; list = list->next) {
		struct dhcp_lease *lease = list->data;
		dhcp_server->save_lease_func(lease->lease_mac,
					lease->lease_nip, lease->expire);
	}
}


static int get_lease(GDHCPServer *dhcp_server, uint32_t yiaddr,
				const uint8_t *mac, struct dhcp_lease **lease)
{
	struct dhcp_lease *lease_nip, *lease_mac;

	if (yiaddr == 0)
		return -ENXIO;

	if (ntohl(yiaddr) < dhcp_server->start_ip)
		return -ENXIO;

	if (ntohl(yiaddr) > dhcp_server->end_ip)
		return -ENXIO;

	if (memcmp(mac, MAC_BCAST_ADDR, ETH_ALEN) == 0)
		return -ENXIO;

	if (memcmp(mac, MAC_ANY_ADDR, ETH_ALEN) == 0)
		return -ENXIO;

	lease_mac = find_lease_by_mac(dhcp_server, mac);

	lease_nip = g_hash_table_lookup(dhcp_server->nip_lease_hash,
					GINT_TO_POINTER((int) ntohl(yiaddr)));
	debug(dhcp_server, "lease_mac %p lease_nip %p", lease_mac, lease_nip);

	if (lease_nip) {
		dhcp_server->lease_list =
				g_list_remove(dhcp_server->lease_list,
								lease_nip);
		g_hash_table_remove(dhcp_server->nip_lease_hash,
				GINT_TO_POINTER((int) ntohl(yiaddr)));

		if (!lease_mac)
			*lease = lease_nip;
		else if (lease_nip != lease_mac) {
			remove_lease(dhcp_server, lease_mac);
			*lease = lease_nip;
		} else
			*lease = lease_nip;

		return 0;
	}

	if (lease_mac) {
		dhcp_server->lease_list =
				g_list_remove(dhcp_server->lease_list,
								lease_mac);
		g_hash_table_remove(dhcp_server->nip_lease_hash,
				GINT_TO_POINTER((int) lease_mac->lease_nip));
		*lease = lease_mac;

		return 0;
	}

	*lease = g_try_new0(struct dhcp_lease, 1);
	if (!*lease)
		return -ENOMEM;

	return 0;
}


void dhcp_add_option_uint8(struct dhcp_packet *packet, uint8_t code,
							uint8_t data)
{
	uint8_t option[6];

	if (check_option(code, sizeof(data)) == OPTION_UNKNOWN)
		return;

	option[OPT_CODE] = code;
	option[OPT_LEN] = sizeof(data);
	option[OPT_DATA] = data;

	dhcp_add_binary_option(packet, option);
}


static void v9fs_init_qiov_from_pdu(QEMUIOVector *qiov, V9fsPDU *pdu,
                                    size_t skip, size_t size,
                                    bool is_write)
{
    QEMUIOVector elem;
    struct iovec *iov;
    unsigned int niov;

    if (is_write) {
        pdu->s->transport->init_out_iov_from_pdu(pdu, &iov, &niov, size + skip);
    } else {
        pdu->s->transport->init_in_iov_from_pdu(pdu, &iov, &niov, size + skip);
    }

    qemu_iovec_init_external(&elem, iov, niov);
    qemu_iovec_init(qiov, niov);
    qemu_iovec_concat(qiov, &elem, skip, size);
}


static void qpf_table_init(struct qht *ht)
{
    qht_init(ht, qpf_cmp_func, 1 << 16, QHT_MODE_AUTO_RESIZE);
}


static int v9fs_xattr_read(V9fsState *s, V9fsPDU *pdu, V9fsFidState *fidp,
                           uint64_t off, uint32_t max_count)
{
    ssize_t err;
    size_t offset = 7;
    uint64_t read_count;
    QEMUIOVector qiov_full;

    if (fidp->fs.xattr.len < off) {
        read_count = 0;
    } else {
        read_count = fidp->fs.xattr.len - off;
    }
    if (read_count > max_count) {
        read_count = max_count;
    }
    err = pdu_marshal(pdu, offset, "d", read_count);
    if (err < 0) {
        return err;
    }
    offset += err;

    v9fs_init_qiov_from_pdu(&qiov_full, pdu, offset, read_count, false);
    err = v9fs_pack(qiov_full.iov, qiov_full.niov, 0,
                    ((char *)fidp->fs.xattr.value) + off,
                    read_count);
    qemu_iovec_destroy(&qiov_full);
    if (err < 0) {
        return err;
    }
    offset += err;
    return offset;
}


static VariLenAffix affixForIndex(uint64_t index)
{
    VariLenAffix prefix;
    prefix = expGolombEncode(index, EXP_GOLOMB_K);
    return invertAffix(&prefix); /* convert prefix to suffix */
}


write_indexes (LZWDecoder *self,
               guint8     *output,
               gsize       output_length)
{
        int c;
        gsize index_count = 1, offset;

        /* Ignore invalid codeword */
        if (self->code >= self->code_table_size)
                return 0;

        /* Work out how many indexes this code represents... */
        c = self->code;
        while (self->code_table[c].extends != self->eoi_code) {
                c = self->code_table[c].extends;
                index_count++;
        }

        /* ...then write the indexes in backwards */
        c = self->code;
        offset = index_count - 1;
        while (TRUE) {
                if (offset < output_length)
                        output[offset] = self->code_table[c].index;

                if (self->code_table[c].extends == self->eoi_code)
                        return index_count;

                c = self->code_table[c].extends;
                offset--;
        }
}


Header headerLink(Header h)
{
    if (h != NULL)
	h->nrefs++;
    return h;
}


static int copyI18NEntry(Header h, indexEntry entry, rpmtd td,
						headerGetFlags flags)
{
    const char *lang, *l, *le;
    indexEntry table;

    td->type = RPM_STRING_TYPE;
    td->count = 1;
    /* if no match, just return the first string */
    td->data = entry->data;

    /* XXX Drepper sez' this is the order. */
    if ((lang = getenv("LANGUAGE")) == NULL &&
	(lang = getenv("LC_ALL")) == NULL &&
	(lang = getenv("LC_MESSAGES")) == NULL &&
	(lang = getenv("LANG")) == NULL)
	    goto exit;

    if ((table = findEntry(h, RPMTAG_HEADERI18NTABLE, RPM_STRING_ARRAY_TYPE)) == NULL)
	goto exit;

    for (l = lang; *l != '\0'; l = le) {
	const char *t;
	char *ed, *ed_weak = NULL;
	int langNum;

	while (*l && *l == ':')			/* skip leading colons */
	    l++;
	if (*l == '\0')
	    break;
	for (le = l; *le && *le != ':'; le++)	/* find end of this locale */
	    {};

	/* For each entry in the header ... */
	for (langNum = 0, t = table->data, ed = entry->data;
	     langNum < entry->info.count;
	     langNum++, t += strlen(t) + 1, ed += strlen(ed) + 1) {

	    int match = headerMatchLocale(t, l, le);
	    if (match == 1) {
		td->data = ed;
		goto exit;
	    } else if (match == 2) {
		ed_weak = ed;
	    }
	}
	if (ed_weak) {
	    td->data = ed_weak;
	    goto exit;
	}
    }

exit:
    if (flags & HEADERGET_ALLOC) {
	td->data = xstrdup(td->data);
	td->flags |= RPMTD_ALLOCED;
    }

    return 1;
}


grabData(rpm_tagtype_t type, rpm_constdata_t p, rpm_count_t c, int * lengthPtr)
{
    rpm_data_t data = NULL;
    int length;

    length = dataLength(type, p, c, 0, NULL);
    if (length > 0) {
	data = xmalloc(length);
	copyData(type, data, p, c, length);
    }

    if (lengthPtr)
	*lengthPtr = length;
    return data;
}


ssize_t Freadall(FD_t fd, void * buf, ssize_t size)
{
    ssize_t total = 0;
    ssize_t nb = 0;
    char * bufp = buf;

    while (total < size) {
	nb = Fread(bufp, 1, size - total, fd);

	if (nb == 0 || (nb < 0 && !RETRY_ERROR(errno))) {
	    total = nb;
	    break;
	}

	if (nb > 0) {
	    bufp += nb;
	    total += nb;
	}
    }

    return total;
}


unsigned int headerGetInstance(Header h)
{
    return h ? h->instance : 0;
}


int headerIsEntry(Header h, rpmTagVal tag)
{
   		/* FIX: h modified by sort. */
    return (findEntry(h, tag, RPM_NULL_TYPE) ? 1 : 0);

}


static Header headerCreate(void *blob, int32_t indexLen)
{
    Header h = xcalloc(1, sizeof(*h));
    if (blob) {
	h->blob = blob;
	h->indexAlloced = indexLen + 1;
	h->indexUsed = indexLen;
    } else {
	h->indexAlloced = INDEX_MALLOC_SIZE;
	h->indexUsed = 0;
    }
    h->instance = 0;
    h->sorted = 0;
    h->index = xcalloc(h->indexAlloced, sizeof(*h->index));

    h->nrefs = 0;
    return headerLink(h);
}


static inline unsigned int alignDiff(rpm_tagtype_t type, unsigned int alignsize)
{
    int typesize = typeSizes[type];

    if (typesize > 1) {
	unsigned int diff = typesize - (alignsize % typesize);
	if (diff != typesize)
	    return diff;
    }
    return 0;
}


void * headerUnload(Header h)
{
    return headerExport(h, NULL);
}


static rpmRC hdrblobVerifyInfo(hdrblob blob, char **emsg)
{
    struct entryInfo_s info;
    int i, len = 0;
    int32_t end = 0;
    const char *ds = (const char *) blob->dataStart;
    int32_t il = (blob->regionTag) ? blob->il-1 : blob->il;
    entryInfo pe = (blob->regionTag) ? blob->pe+1 : blob->pe;
    /* Can't typecheck signature header tags, sigh */
    int typechk = (blob->regionTag == RPMTAG_HEADERIMMUTABLE ||
		   blob->regionTag == RPMTAG_HEADERIMAGE);

    for (i = 0; i < il; i++) {
	ei2h(&pe[i], &info);

	/* Previous data must not overlap */
	if (end > info.offset)
	    goto err;

	if (hdrchkTag(info.tag))
	    goto err;
	if (hdrchkType(info.type))
	    goto err;
	if (hdrchkCount(info.count))
	    goto err;
	if (hdrchkAlign(info.type, info.offset))
	    goto err;
	if (hdrchkRange(blob->dl, info.offset))
	    goto err;
	if (typechk && hdrchkTagType(info.tag, info.type))
	    goto err;

	/* Verify the data actually fits */
	len = dataLength(info.type, ds + info.offset,
			 info.count, 1, ds + blob->dl);
	if (hdrchkRange(blob->dl - info.offset, len))
	    goto err;
	end = info.offset + len;
	if (blob->regionTag) {
	    /*
	     * Verify that the data does not overlap the region trailer.  The
	     * region trailer is skipped by this loop, so the other checks
	     * don’t catch this case.
	     */
	    if (end > blob->rdl - REGION_TAG_COUNT && info.offset < blob->rdl)
		goto err;
	}
    }
    return 0; /* Everything ok */

err:
    if (emsg) {
	rasprintf(emsg,
		  _("tag[%d]: BAD, tag %d type %d offset %d count %d len %d"),
		    i, info.tag, info.type, info.offset, info.count, len);
    }
    return i + 1;
}


sdhci_buff_access_is_sequential(SDHCIState *s, unsigned byte_num)
{
    if ((s->data_count & 0x3) != byte_num) {
        trace_sdhci_error("Non-sequential access to Buffer Data Port register"
                          "is prohibited\n");
        return false;
    }
    return true;
}


usdhc_write(void *opaque, hwaddr offset, uint64_t val, unsigned size)
{
    SDHCIState *s = SYSBUS_SDHCI(opaque);
    uint8_t hostctl1;
    uint32_t value = (uint32_t)val;

    switch (offset) {
    case ESDHC_DLL_CTRL:
    case ESDHC_TUNE_CTRL_STATUS:
    case ESDHC_UNDOCUMENTED_REG27:
    case ESDHC_TUNING_CTRL:
    case ESDHC_WTMK_LVL:
        break;

    case ESDHC_VENDOR_SPEC:
        s->vendor_spec = value;
        switch (s->vendor) {
        case SDHCI_VENDOR_IMX:
            if (value & ESDHC_IMX_FRC_SDCLK_ON) {
                s->prnsts &= ~SDHC_IMX_CLOCK_GATE_OFF;
            } else {
                s->prnsts |= SDHC_IMX_CLOCK_GATE_OFF;
            }
            break;
        default:
            break;
        }
        break;

    case SDHC_HOSTCTL:
        /*
         * Here's What ESDHCI has at offset 0x28 (SDHC_HOSTCTL)
         *
         *       7         6     5      4      3      2        1      0
         * |-----------+--------+--------+-----------+----------+---------|
         * | Card      | Card   | Endian | DATA3     | Data     | Led     |
         * | Detect    | Detect | Mode   | as Card   | Transfer | Control |
         * | Signal    | Test   |        | Detection | Width    |         |
         * | Selection | Level  |        | Pin       |          |         |
         * |-----------+--------+--------+-----------+----------+---------|
         *
         * and 0x29
         *
         *  15      10 9    8
         * |----------+------|
         * | Reserved | DMA  |
         * |          | Sel. |
         * |          |      |
         * |----------+------|
         *
         * and here's what SDCHI spec expects those offsets to be:
         *
         * 0x28 (Host Control Register)
         *
         *     7        6         5       4  3      2         1        0
         * |--------+--------+----------+------+--------+----------+---------|
         * | Card   | Card   | Extended | DMA  | High   | Data     | LED     |
         * | Detect | Detect | Data     | Sel. | Speed  | Transfer | Control |
         * | Signal | Test   | Transfer |      | Enable | Width    |         |
         * | Sel.   | Level  | Width    |      |        |          |         |
         * |--------+--------+----------+------+--------+----------+---------|
         *
         * and 0x29 (Power Control Register)
         *
         * |----------------------------------|
         * | Power Control Register           |
         * |                                  |
         * | Description omitted,             |
         * | since it has no analog in ESDHCI |
         * |                                  |
         * |----------------------------------|
         *
         * Since offsets 0x2A and 0x2B should be compatible between
         * both IP specs we only need to reconcile least 16-bit of the
         * word we've been given.
         */

        /*
         * First, save bits 7 6 and 0 since they are identical
         */
        hostctl1 = value & (SDHC_CTRL_LED |
                            SDHC_CTRL_CDTEST_INS |
                            SDHC_CTRL_CDTEST_EN);
        /*
         * Second, split "Data Transfer Width" from bits 2 and 1 in to
         * bits 5 and 1
         */
        if (value & ESDHC_CTRL_8BITBUS) {
            hostctl1 |= SDHC_CTRL_8BITBUS;
        }

        if (value & ESDHC_CTRL_4BITBUS) {
            hostctl1 |= ESDHC_CTRL_4BITBUS;
        }

        /*
         * Third, move DMA select from bits 9 and 8 to bits 4 and 3
         */
        hostctl1 |= SDHC_DMA_TYPE(value >> (8 - 3));

        /*
         * Now place the corrected value into low 16-bit of the value
         * we are going to give standard SDHCI write function
         *
         * NOTE: This transformation should be the inverse of what can
         * be found in drivers/mmc/host/sdhci-esdhc-imx.c in Linux
         * kernel
         */
        value &= ~UINT16_MAX;
        value |= hostctl1;
        value |= (uint16_t)s->pwrcon << 8;

        sdhci_write(opaque, offset, value, size);
        break;

    case ESDHC_MIX_CTRL:
        /*
         * So, when SD/MMC stack in Linux tries to write to "Transfer
         * Mode Register", ESDHC i.MX quirk code will translate it
         * into a write to ESDHC_MIX_CTRL, so we do the opposite in
         * order to get where we started
         *
         * Note that Auto CMD23 Enable bit is located in a wrong place
         * on i.MX, but since it is not used by QEMU we do not care.
         *
         * We don't want to call sdhci_write(.., SDHC_TRNMOD, ...)
         * here becuase it will result in a call to
         * sdhci_send_command(s) which we don't want.
         *
         */
        s->trnmod = value & UINT16_MAX;
        break;
    case SDHC_TRNMOD:
        /*
         * Similar to above, but this time a write to "Command
         * Register" will be translated into a 4-byte write to
         * "Transfer Mode register" where lower 16-bit of value would
         * be set to zero. So what we do is fill those bits with
         * cached value from s->trnmod and let the SDHCI
         * infrastructure handle the rest
         */
        sdhci_write(opaque, offset, val | s->trnmod, size);
        break;
    case SDHC_BLKSIZE:
        /*
         * ESDHCI does not implement "Host SDMA Buffer Boundary", and
         * Linux driver will try to zero this field out which will
         * break the rest of SDHCI emulation.
         *
         * Linux defaults to maximum possible setting (512K boundary)
         * and it seems to be the only option that i.MX IP implements,
         * so we artificially set it to that value.
         */
        val |= 0x7 << 12;
        /* FALLTHROUGH */
    default:
        sdhci_write(opaque, offset, val, size);
        break;
    }
}


static void get_adma_description(SDHCIState *s, ADMADescr *dscr)
{
    uint32_t adma1 = 0;
    uint64_t adma2 = 0;
    hwaddr entry_addr = (hwaddr)s->admasysaddr;
    switch (SDHC_DMA_TYPE(s->hostctl1)) {
    case SDHC_CTRL_ADMA2_32:
        dma_memory_read(s->dma_as, entry_addr, &adma2, sizeof(adma2));
        adma2 = le64_to_cpu(adma2);
        /* The spec does not specify endianness of descriptor table.
         * We currently assume that it is LE.
         */
        dscr->addr = (hwaddr)extract64(adma2, 32, 32) & ~0x3ull;
        dscr->length = (uint16_t)extract64(adma2, 16, 16);
        dscr->attr = (uint8_t)extract64(adma2, 0, 7);
        dscr->incr = 8;
        break;
    case SDHC_CTRL_ADMA1_32:
        dma_memory_read(s->dma_as, entry_addr, &adma1, sizeof(adma1));
        adma1 = le32_to_cpu(adma1);
        dscr->addr = (hwaddr)(adma1 & 0xFFFFF000);
        dscr->attr = (uint8_t)extract32(adma1, 0, 7);
        dscr->incr = 4;
        if ((dscr->attr & SDHC_ADMA_ATTR_ACT_MASK) == SDHC_ADMA_ATTR_SET_LEN) {
            dscr->length = (uint16_t)extract32(adma1, 12, 16);
        } else {
            dscr->length = 4 * KiB;
        }
        break;
    case SDHC_CTRL_ADMA2_64:
        dma_memory_read(s->dma_as, entry_addr, &dscr->attr, 1);
        dma_memory_read(s->dma_as, entry_addr + 2, &dscr->length, 2);
        dscr->length = le16_to_cpu(dscr->length);
        dma_memory_read(s->dma_as, entry_addr + 4, &dscr->addr, 8);
        dscr->addr = le64_to_cpu(dscr->addr);
        dscr->attr &= (uint8_t) ~0xC0;
        dscr->incr = 12;
        break;
    }
}


static void sdhci_send_command(SDHCIState *s)
{
    SDRequest request;
    uint8_t response[16];
    int rlen;
    bool timeout = false;

    s->errintsts = 0;
    s->acmd12errsts = 0;
    request.cmd = s->cmdreg >> 8;
    request.arg = s->argument;

    trace_sdhci_send_command(request.cmd, request.arg);
    rlen = sdbus_do_command(&s->sdbus, &request, response);

    if (s->cmdreg & SDHC_CMD_RESPONSE) {
        if (rlen == 4) {
            s->rspreg[0] = ldl_be_p(response);
            s->rspreg[1] = s->rspreg[2] = s->rspreg[3] = 0;
            trace_sdhci_response4(s->rspreg[0]);
        } else if (rlen == 16) {
            s->rspreg[0] = ldl_be_p(&response[11]);
            s->rspreg[1] = ldl_be_p(&response[7]);
            s->rspreg[2] = ldl_be_p(&response[3]);
            s->rspreg[3] = (response[0] << 16) | (response[1] << 8) |
                            response[2];
            trace_sdhci_response16(s->rspreg[3], s->rspreg[2],
                                   s->rspreg[1], s->rspreg[0]);
        } else {
            timeout = true;
            trace_sdhci_error("timeout waiting for command response");
            if (s->errintstsen & SDHC_EISEN_CMDTIMEOUT) {
                s->errintsts |= SDHC_EIS_CMDTIMEOUT;
                s->norintsts |= SDHC_NIS_ERR;
            }
        }

        if (!(s->quirks & SDHCI_QUIRK_NO_BUSY_IRQ) &&
            (s->norintstsen & SDHC_NISEN_TRSCMP) &&
            (s->cmdreg & SDHC_CMD_RESPONSE) == SDHC_CMD_RSP_WITH_BUSY) {
            s->norintsts |= SDHC_NIS_TRSCMP;
        }
    }

    if (s->norintstsen & SDHC_NISEN_CMDCMP) {
        s->norintsts |= SDHC_NIS_CMDCMP;
    }

    sdhci_update_irq(s);

    if (!timeout && s->blksize && (s->cmdreg & SDHC_CMD_DATA_PRESENT)) {
        s->data_count = 0;
        sdhci_data_transfer(s);
    }
}


static void sdhci_do_adma(SDHCIState *s)
{
    unsigned int begin, length;
    const uint16_t block_size = s->blksize & BLOCK_SIZE_MASK;
    ADMADescr dscr = {};
    int i;

    if (s->trnmod & SDHC_TRNS_BLK_CNT_EN && !s->blkcnt) {
        /* Stop Multiple Transfer */
        sdhci_end_transfer(s);
        return;
    }

    for (i = 0; i < SDHC_ADMA_DESCS_PER_DELAY; ++i) {
        s->admaerr &= ~SDHC_ADMAERR_LENGTH_MISMATCH;

        get_adma_description(s, &dscr);
        trace_sdhci_adma_loop(dscr.addr, dscr.length, dscr.attr);

        if ((dscr.attr & SDHC_ADMA_ATTR_VALID) == 0) {
            /* Indicate that error occurred in ST_FDS state */
            s->admaerr &= ~SDHC_ADMAERR_STATE_MASK;
            s->admaerr |= SDHC_ADMAERR_STATE_ST_FDS;

            /* Generate ADMA error interrupt */
            if (s->errintstsen & SDHC_EISEN_ADMAERR) {
                s->errintsts |= SDHC_EIS_ADMAERR;
                s->norintsts |= SDHC_NIS_ERR;
            }

            sdhci_update_irq(s);
            return;
        }

        length = dscr.length ? dscr.length : 64 * KiB;

        switch (dscr.attr & SDHC_ADMA_ATTR_ACT_MASK) {
        case SDHC_ADMA_ATTR_ACT_TRAN:  /* data transfer */
            s->prnsts |= SDHC_DATA_INHIBIT | SDHC_DAT_LINE_ACTIVE;
            if (s->trnmod & SDHC_TRNS_READ) {
                s->prnsts |= SDHC_DOING_READ;
                while (length) {
                    if (s->data_count == 0) {
                        sdbus_read_data(&s->sdbus, s->fifo_buffer, block_size);
                    }
                    begin = s->data_count;
                    if ((length + begin) < block_size) {
                        s->data_count = length + begin;
                        length = 0;
                     } else {
                        s->data_count = block_size;
                        length -= block_size - begin;
                    }
                    dma_memory_write(s->dma_as, dscr.addr,
                                     &s->fifo_buffer[begin],
                                     s->data_count - begin);
                    dscr.addr += s->data_count - begin;
                    if (s->data_count == block_size) {
                        s->data_count = 0;
                        if (s->trnmod & SDHC_TRNS_BLK_CNT_EN) {
                            s->blkcnt--;
                            if (s->blkcnt == 0) {
                                break;
                            }
                        }
                    }
                }
            } else {
                s->prnsts |= SDHC_DOING_WRITE;
                while (length) {
                    begin = s->data_count;
                    if ((length + begin) < block_size) {
                        s->data_count = length + begin;
                        length = 0;
                     } else {
                        s->data_count = block_size;
                        length -= block_size - begin;
                    }
                    dma_memory_read(s->dma_as, dscr.addr,
                                    &s->fifo_buffer[begin],
                                    s->data_count - begin);
                    dscr.addr += s->data_count - begin;
                    if (s->data_count == block_size) {
                        sdbus_write_data(&s->sdbus, s->fifo_buffer, block_size);
                        s->data_count = 0;
                        if (s->trnmod & SDHC_TRNS_BLK_CNT_EN) {
                            s->blkcnt--;
                            if (s->blkcnt == 0) {
                                break;
                            }
                        }
                    }
                }
            }
            s->admasysaddr += dscr.incr;
            break;
        case SDHC_ADMA_ATTR_ACT_LINK:   /* link to next descriptor table */
            s->admasysaddr = dscr.addr;
            trace_sdhci_adma("link", s->admasysaddr);
            break;
        default:
            s->admasysaddr += dscr.incr;
            break;
        }

        if (dscr.attr & SDHC_ADMA_ATTR_INT) {
            trace_sdhci_adma("interrupt", s->admasysaddr);
            if (s->norintstsen & SDHC_NISEN_DMA) {
                s->norintsts |= SDHC_NIS_DMA;
            }

            if (sdhci_update_irq(s) && !(dscr.attr & SDHC_ADMA_ATTR_END)) {
                /* IRQ delivered, reschedule current transfer */
                break;
            }
        }

        /* ADMA transfer terminates if blkcnt == 0 or by END attribute */
        if (((s->trnmod & SDHC_TRNS_BLK_CNT_EN) &&
                    (s->blkcnt == 0)) || (dscr.attr & SDHC_ADMA_ATTR_END)) {
            trace_sdhci_adma_transfer_completed();
            if (length || ((dscr.attr & SDHC_ADMA_ATTR_END) &&
                (s->trnmod & SDHC_TRNS_BLK_CNT_EN) &&
                s->blkcnt != 0)) {
                trace_sdhci_error("SD/MMC host ADMA length mismatch");
                s->admaerr |= SDHC_ADMAERR_LENGTH_MISMATCH |
                        SDHC_ADMAERR_STATE_ST_TFR;
                if (s->errintstsen & SDHC_EISEN_ADMAERR) {
                    trace_sdhci_error("Set ADMA error flag");
                    s->errintsts |= SDHC_EIS_ADMAERR;
                    s->norintsts |= SDHC_NIS_ERR;
                }

                sdhci_update_irq(s);
            }
            sdhci_end_transfer(s);
            return;
        }

    }

    /* we have unfinished business - reschedule to continue ADMA */
    timer_mod(s->transfer_timer,
                   qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + SDHC_TRANSFER_DELAY);
}


serialNumberAndIssuerValidate(
	Syntax *syntax,
	struct berval *in )
{
	int rc;
	struct berval sn, i;

	Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerValidate: <%s>\n",
		in->bv_val );

	rc = serialNumberAndIssuerCheck( in, &sn, &i, NULL );
	if ( rc ) {
		goto done;
	}

	/* validate DN -- doesn't handle double dquote */
	rc = dnValidate( NULL, &i );
	if ( rc ) {
		rc = LDAP_INVALID_SYNTAX;
	}

	if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
		slap_sl_free( i.bv_val, NULL );
	}

	Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerValidate: <%s> err=%d\n",
		in->bv_val, rc );

done:;
	return rc;
}


issuerAndThisUpdateNormalize(
	slap_mask_t usage,
	Syntax *syntax,
	MatchingRule *mr,
	struct berval *in,
	struct berval *out,
	void *ctx )
{
	struct berval i, ni, tu, tu2;
	char sbuf[STRLENOF("YYYYmmddHHMMSSZ") + 1];
	char *p;
	int rc;

	assert( in != NULL );
	assert( out != NULL );

	Debug( LDAP_DEBUG_TRACE, ">>> issuerAndThisUpdateNormalize: <%s>\n",
		in->bv_val );

	rc = issuerAndThisUpdateCheck( in, &i, &tu, ctx );
	if ( rc ) {
		return rc;
	}

	rc = dnNormalize( usage, syntax, mr, &i, &ni, ctx );

	if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
		slap_sl_free( i.bv_val, ctx );
	}

	tu2.bv_val = sbuf;
	tu2.bv_len = sizeof( sbuf );
	if ( rc || checkTime( &tu, &tu2 ) ) {
		return LDAP_INVALID_SYNTAX;
	}

	out->bv_len = STRLENOF( "{ issuer rdnSequence:\"\", thisUpdate \"\" }" )
		+ ni.bv_len + tu2.bv_len;
	out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );

	if ( out->bv_val == NULL ) {
		out->bv_len = 0;
		rc = LDAP_OTHER;
		goto func_leave;
	}

	p = out->bv_val;

	p = lutil_strcopy( p, "{ issuer rdnSequence:\"" /*}*/ );
	p = lutil_strbvcopy( p, &ni );
	p = lutil_strcopy( p, "\", thisUpdate \"" );
	p = lutil_strbvcopy( p, &tu2 );
	p = lutil_strcopy( p, /*{*/ "\" }" );

	assert( p == &out->bv_val[out->bv_len] );

func_leave:
	Debug( LDAP_DEBUG_TRACE, "<<< issuerAndThisUpdateNormalize: <%s> => <%s>\n",
		in->bv_val, rc == LDAP_SUCCESS ? out->bv_val : "(err)" );

	slap_sl_free( ni.bv_val, ctx );

	return rc;
}


serialNumberAndIssuerNormalize(
	slap_mask_t usage,
	Syntax *syntax,
	MatchingRule *mr,
	struct berval *in,
	struct berval *out,
	void *ctx )
{
	struct berval sn, sn2, sn3, i, ni;
	char sbuf2[SLAP_SN_BUFLEN];
	char sbuf3[SLAP_SN_BUFLEN];
	char *p;
	int rc;

	assert( in != NULL );
	assert( out != NULL );

	Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerNormalize: <%s>\n",
		in->bv_val );

	rc = serialNumberAndIssuerCheck( in, &sn, &i, ctx );
	if ( rc ) {
		return rc;
	}

	rc = dnNormalize( usage, syntax, mr, &i, &ni, ctx );

	if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
		slap_sl_free( i.bv_val, ctx );
	}

	if ( rc ) {
		return LDAP_INVALID_SYNTAX;
	}

	/* Convert sn to canonical hex */
	sn2.bv_val = sbuf2;
	if ( sn.bv_len > sizeof( sbuf2 ) ) {
		sn2.bv_val = slap_sl_malloc( sn.bv_len, ctx );
	}
	sn2.bv_len = sn.bv_len;
	sn3.bv_val = sbuf3;
	sn3.bv_len = sizeof(sbuf3);
	if ( lutil_str2bin( &sn, &sn2, ctx ) || slap_bin2hex( &sn2, &sn3, ctx ) ) {
		rc = LDAP_INVALID_SYNTAX;
		goto func_leave;
	}

	out->bv_len = STRLENOF( "{ serialNumber , issuer rdnSequence:\"\" }" )
		+ sn3.bv_len + ni.bv_len;
	out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
	if ( out->bv_val == NULL ) {
		out->bv_len = 0;
		rc = LDAP_OTHER;
		goto func_leave;
	}

	p = out->bv_val;

	p = lutil_strcopy( p, "{ serialNumber " /*}*/ );
	p = lutil_strbvcopy( p, &sn3 );
	p = lutil_strcopy( p, ", issuer rdnSequence:\"" );
	p = lutil_strbvcopy( p, &ni );
	p = lutil_strcopy( p, /*{*/ "\" }" );

	assert( p == &out->bv_val[out->bv_len] );

func_leave:
	Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerNormalize: <%s> => <%s>\n",
		in->bv_val, rc == LDAP_SUCCESS ? out->bv_val : "(err)" );

	if ( sn2.bv_val != sbuf2 ) {
		slap_sl_free( sn2.bv_val, ctx );
	}

	if ( sn3.bv_val != sbuf3 ) {
		slap_sl_free( sn3.bv_val, ctx );
	}

	slap_sl_free( ni.bv_val, ctx );

	return rc;
}


MagickExport MagickBooleanType SetResampleFilterInterpolateMethod(
  ResampleFilter *resample_filter,const PixelInterpolateMethod method)
{
  assert(resample_filter != (ResampleFilter *) NULL);
  assert(resample_filter->signature == MagickCoreSignature);
  assert(resample_filter->image != (Image *) NULL);
  if (resample_filter->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
      resample_filter->image->filename);
  resample_filter->interpolate=method;
  return(MagickTrue);
}


static int ReadSingleWEBPImage(Image *image,const uint8_t *stream,
  size_t length,WebPDecoderConfig *configure,ExceptionInfo *exception,
  MagickBooleanType is_first)
{
  int
    webp_status;

  unsigned char
    *p;

  size_t
    canvas_width,
    canvas_height,
    image_width,
    image_height;

  ssize_t
    x_offset,
    y_offset,
    y;

  WebPDecBuffer
    *magick_restrict webp_image = &configure->output;

  MagickBooleanType
    status;

  if (is_first)
    {
      canvas_width=image->columns;
      canvas_height=image->rows;
      x_offset=image->page.x;
      y_offset=image->page.y;
      image->page.x=0;
      image->page.y=0;
    }
  else
    {
      x_offset=0;
      y_offset=0;
    }
  webp_status=FillBasicWEBPInfo(image,stream,length,configure);
  image_width=image->columns;
  image_height=image->rows;
  if (is_first)
    {
      image->columns=canvas_width;
      image->rows=canvas_height;
    }

  if (webp_status != VP8_STATUS_OK)
    return(webp_status);

  if (IsWEBPImageLossless(stream,length) != MagickFalse)
    image->quality=100;

  webp_status=WebPDecode(stream,length,configure);
  if (webp_status != VP8_STATUS_OK)
    return(webp_status);

  p=(unsigned char *) webp_image->u.RGBA.rgba;
  for (y=0; y < (ssize_t) image->rows; y++)
  {
    PixelPacket
      *q;

    ssize_t
      x;

    q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
    if (q == (PixelPacket *) NULL)
      break;
    for (x=0; x < (ssize_t) image->columns; x++)
    {
      if ((x >= x_offset && x < (ssize_t) (x_offset+image_width)) &&
          (y >= y_offset && y < (ssize_t) (y_offset+image_height)))
        {
          SetPixelRed(q,ScaleCharToQuantum(*p++));
          SetPixelGreen(q,ScaleCharToQuantum(*p++));
          SetPixelBlue(q,ScaleCharToQuantum(*p++));
          SetPixelAlpha(q,ScaleCharToQuantum(*p++));
        }
      else
        {
          SetPixelRed(q,0);
          SetPixelGreen(q,0);
          SetPixelBlue(q,0);
          SetPixelAlpha(q,0);
        }
      q++;
    }
    if (SyncAuthenticPixels(image,exception) == MagickFalse)
      break;
    status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
      image->rows);
    if (status == MagickFalse)
      break;
  }
  WebPFreeDecBuffer(webp_image);
#if defined(MAGICKCORE_WEBPMUX_DELEGATE)
  {
    StringInfo
      *profile;

    uint32_t
      webp_flags = 0;

    WebPData
     chunk,
     content;

    WebPMux
      *mux;

    /*
      Extract any profiles:
      https://developers.google.com/speed/webp/docs/container-api.
    */
    content.bytes=stream;
    content.size=length;
    mux=WebPMuxCreate(&content,0);
    (void) memset(&chunk,0,sizeof(chunk));
    WebPMuxGetFeatures(mux,&webp_flags);
    if (webp_flags & ICCP_FLAG)
      {
        WebPMuxGetChunk(mux,"ICCP",&chunk);
        profile=BlobToStringInfo(chunk.bytes,chunk.size);
        if (profile != (StringInfo *) NULL)
          {
            SetImageProfile(image,"ICC",profile);
            profile=DestroyStringInfo(profile);
          }
      }
    if (webp_flags & EXIF_FLAG)
      {
        WebPMuxGetChunk(mux,"EXIF",&chunk);
        profile=BlobToStringInfo(chunk.bytes,chunk.size);
        if (profile != (StringInfo *) NULL)
          {
            SetImageProfile(image,"EXIF",profile);
            profile=DestroyStringInfo(profile);
          }
      }
    if (webp_flags & XMP_FLAG)
      {
        WebPMuxGetChunk(mux,"XMP",&chunk);
        profile=BlobToStringInfo(chunk.bytes,chunk.size);
        if (profile != (StringInfo *) NULL)
          {
            SetImageProfile(image,"XMP",profile);
            profile=DestroyStringInfo(profile);
          }
      }
    WebPMuxDelete(mux);
  }
#endif
  return(webp_status);
}


MagickExport Image *ColorizeImage(const Image *image,const char *blend,
  const PixelInfo *colorize,ExceptionInfo *exception)
{
#define ColorizeImageTag  "Colorize/Image"
#define Colorize(pixel,blend_percentage,colorize)  \
  (((pixel)*(100.0-(blend_percentage))+(colorize)*(blend_percentage))/100.0)

  CacheView
    *image_view;

  GeometryInfo
    geometry_info;

  Image
    *colorize_image;

  MagickBooleanType
    status;

  MagickOffsetType
    progress;

  MagickStatusType
    flags;

  PixelInfo
    blend_percentage;

  ssize_t
    y;

  /*
    Allocate colorized image.
  */
  assert(image != (const Image *) NULL);
  assert(image->signature == MagickCoreSignature);
  if (image->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
  assert(exception != (ExceptionInfo *) NULL);
  assert(exception->signature == MagickCoreSignature);
  colorize_image=CloneImage(image,0,0,MagickTrue,exception);
  if (colorize_image == (Image *) NULL)
    return((Image *) NULL);
  if (SetImageStorageClass(colorize_image,DirectClass,exception) == MagickFalse)
    {
      colorize_image=DestroyImage(colorize_image);
      return((Image *) NULL);
    }
  if ((IsGrayColorspace(colorize_image->colorspace) != MagickFalse) ||
      (IsPixelInfoGray(colorize) != MagickFalse))
    (void) SetImageColorspace(colorize_image,sRGBColorspace,exception);
  if ((colorize_image->alpha_trait == UndefinedPixelTrait) &&
      (colorize->alpha_trait != UndefinedPixelTrait))
    (void) SetImageAlpha(colorize_image,OpaqueAlpha,exception);
  if (blend == (const char *) NULL)
    return(colorize_image);
  GetPixelInfo(colorize_image,&blend_percentage);
  flags=ParseGeometry(blend,&geometry_info);
  blend_percentage.red=geometry_info.rho;
  blend_percentage.green=geometry_info.rho;
  blend_percentage.blue=geometry_info.rho;
  blend_percentage.black=geometry_info.rho;
  blend_percentage.alpha=(MagickRealType) TransparentAlpha;
  if ((flags & SigmaValue) != 0)
    blend_percentage.green=geometry_info.sigma;
  if ((flags & XiValue) != 0)
    blend_percentage.blue=geometry_info.xi;
  if ((flags & PsiValue) != 0)
    blend_percentage.alpha=geometry_info.psi;
  if (blend_percentage.colorspace == CMYKColorspace)
    {
      if ((flags & PsiValue) != 0)
        blend_percentage.black=geometry_info.psi;
      if ((flags & ChiValue) != 0)
        blend_percentage.alpha=geometry_info.chi;
    }
  /*
    Colorize DirectClass image.
  */
  status=MagickTrue;
  progress=0;
  image_view=AcquireVirtualCacheView(colorize_image,exception);
#if defined(MAGICKCORE_OPENMP_SUPPORT)
  #pragma omp parallel for schedule(static) shared(progress,status) \
    magick_number_threads(colorize_image,colorize_image,colorize_image->rows,1)
#endif
  for (y=0; y < (ssize_t) colorize_image->rows; y++)
  {
    MagickBooleanType
      sync;

    Quantum
      *magick_restrict q;

    ssize_t
      x;

    if (status == MagickFalse)
      continue;
    q=GetCacheViewAuthenticPixels(image_view,0,y,colorize_image->columns,1,
      exception);
    if (q == (Quantum *) NULL)
      {
        status=MagickFalse;
        continue;
      }
    for (x=0; x < (ssize_t) colorize_image->columns; x++)
    {
      ssize_t
        i;

      for (i=0; i < (ssize_t) GetPixelChannels(colorize_image); i++)
      {
        PixelTrait traits = GetPixelChannelTraits(colorize_image,
          (PixelChannel) i);
        if (traits == UndefinedPixelTrait)
          continue;
        if ((traits & CopyPixelTrait) != 0)
          continue;
        SetPixelChannel(colorize_image,(PixelChannel) i,ClampToQuantum(
          Colorize(q[i],GetPixelInfoChannel(&blend_percentage,(PixelChannel) i),
          GetPixelInfoChannel(colorize,(PixelChannel) i))),q);
      }
      q+=GetPixelChannels(colorize_image);
    }
    sync=SyncCacheViewAuthenticPixels(image_view,exception);
    if (sync == MagickFalse)
      status=MagickFalse;
    if (image->progress_monitor != (MagickProgressMonitor) NULL)
      {
        MagickBooleanType
          proceed;

#if defined(MAGICKCORE_OPENMP_SUPPORT)
        #pragma omp atomic
#endif
        progress++;
        proceed=SetImageProgress(image,ColorizeImageTag,progress,
          colorize_image->rows);
        if (proceed == MagickFalse)
          status=MagickFalse;
      }
  }
  image_view=DestroyCacheView(image_view);
  if (status == MagickFalse)
    colorize_image=DestroyImage(colorize_image);
  return(colorize_image);
}


static void iscsi_scsi_cmd_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
			       struct iscsi_task *task, char *data,
			       int datalen)
{
	struct iscsi_scsi_rsp *rhdr = (struct iscsi_scsi_rsp *)hdr;
	struct iscsi_session *session = conn->session;
	struct scsi_cmnd *sc = task->sc;

	iscsi_update_cmdsn(session, (struct iscsi_nopin*)rhdr);
	conn->exp_statsn = be32_to_cpu(rhdr->statsn) + 1;

	sc->result = (DID_OK << 16) | rhdr->cmd_status;

	if (task->protected) {
		sector_t sector;
		u8 ascq;

		/**
		 * Transports that didn't implement check_protection
		 * callback but still published T10-PI support to scsi-mid
		 * deserve this BUG_ON.
		 **/
		BUG_ON(!session->tt->check_protection);

		ascq = session->tt->check_protection(task, &sector);
		if (ascq) {
			sc->result = DRIVER_SENSE << 24 |
				     SAM_STAT_CHECK_CONDITION;
			scsi_build_sense_buffer(1, sc->sense_buffer,
						ILLEGAL_REQUEST, 0x10, ascq);
			scsi_set_sense_information(sc->sense_buffer,
						   SCSI_SENSE_BUFFERSIZE,
						   sector);
			goto out;
		}
	}

	if (rhdr->response != ISCSI_STATUS_CMD_COMPLETED) {
		sc->result = DID_ERROR << 16;
		goto out;
	}

	if (rhdr->cmd_status == SAM_STAT_CHECK_CONDITION) {
		uint16_t senselen;

		if (datalen < 2) {
invalid_datalen:
			iscsi_conn_printk(KERN_ERR,  conn,
					 "Got CHECK_CONDITION but invalid data "
					 "buffer size of %d\n", datalen);
			sc->result = DID_BAD_TARGET << 16;
			goto out;
		}

		senselen = get_unaligned_be16(data);
		if (datalen < senselen)
			goto invalid_datalen;

		memcpy(sc->sense_buffer, data + 2,
		       min_t(uint16_t, senselen, SCSI_SENSE_BUFFERSIZE));
		ISCSI_DBG_SESSION(session, "copied %d bytes of sense\n",
				  min_t(uint16_t, senselen,
				  SCSI_SENSE_BUFFERSIZE));
	}

	if (rhdr->flags & (ISCSI_FLAG_CMD_BIDI_UNDERFLOW |
			   ISCSI_FLAG_CMD_BIDI_OVERFLOW)) {
		sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status;
	}

	if (rhdr->flags & (ISCSI_FLAG_CMD_UNDERFLOW |
	                   ISCSI_FLAG_CMD_OVERFLOW)) {
		int res_count = be32_to_cpu(rhdr->residual_count);

		if (res_count > 0 &&
		    (rhdr->flags & ISCSI_FLAG_CMD_OVERFLOW ||
		     res_count <= scsi_bufflen(sc)))
			/* write side for bidi or uni-io set_resid */
			scsi_set_resid(sc, res_count);
		else
			sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status;
	}
out:
	ISCSI_DBG_SESSION(session, "cmd rsp done [sc %p res %d itt 0x%x]\n",
			  sc, sc->result, task->itt);
	conn->scsirsp_pdus_cnt++;
	iscsi_complete_task(task, ISCSI_TASK_COMPLETED);
}


	ISCSI_DBG_TRANS_SESSION(session, "Completed target removal\n");
}

static void __iscsi_destroy_session(struct work_struct *work)
{
	struct iscsi_cls_session *session =
		container_of(work, struct iscsi_cls_session, destroy_work);


}

static int
iscsi_get_chap(struct iscsi_transport *transport, struct nlmsghdr *nlh)
{
	struct iscsi_uevent *ev = nlmsg_data(nlh);
	struct Scsi_Host *shost = NULL;
	struct iscsi_chap_rec *chap_rec;
	struct iscsi_internal *priv;
	struct sk_buff *skbchap;
	struct nlmsghdr *nlhchap;
	struct iscsi_uevent *evchap;
	uint32_t chap_buf_size;
	int len, err = 0;
	char *buf;

	if (!transport->get_chap)
		return -EINVAL;

	priv = iscsi_if_transport_lookup(transport);
	if (!priv)
		return -EINVAL;

	chap_buf_size = (ev->u.get_chap.num_entries * sizeof(*chap_rec));
	len = nlmsg_total_size(sizeof(*ev) + chap_buf_size);

	shost = scsi_host_lookup(ev->u.get_chap.host_no);
	if (!shost) {
		printk(KERN_ERR "%s: failed. Could not find host no %u\n",
		       __func__, ev->u.get_chap.host_no);
		return -ENODEV;
	}

	do {
		int actual_size;

		skbchap = alloc_skb(len, GFP_KERNEL);
		if (!skbchap) {
			printk(KERN_ERR "can not deliver chap: OOM\n");
			err = -ENOMEM;
			goto exit_get_chap;
		}

		nlhchap = __nlmsg_put(skbchap, 0, 0, 0,
				      (len - sizeof(*nlhchap)), 0);
		evchap = nlmsg_data(nlhchap);
		memset(evchap, 0, sizeof(*evchap));
		evchap->transport_handle = iscsi_handle(transport);
		evchap->type = nlh->nlmsg_type;
		evchap->u.get_chap.host_no = ev->u.get_chap.host_no;
		evchap->u.get_chap.chap_tbl_idx = ev->u.get_chap.chap_tbl_idx;
		evchap->u.get_chap.num_entries = ev->u.get_chap.num_entries;
		buf = (char *)evchap + sizeof(*evchap);
		memset(buf, 0, chap_buf_size);

		err = transport->get_chap(shost, ev->u.get_chap.chap_tbl_idx,
				    &evchap->u.get_chap.num_entries, buf);

		actual_size = nlmsg_total_size(sizeof(*ev) + chap_buf_size);
		skb_trim(skbchap, NLMSG_ALIGN(actual_size));
		nlhchap->nlmsg_len = actual_size;

		err = iscsi_multicast_skb(skbchap, ISCSI_NL_GRP_ISCSID,
					  GFP_KERNEL);
	} while (err < 0 && err != -ECONNREFUSED);

exit_get_chap:


static int iscsi_send_nopout(struct iscsi_conn *conn, struct iscsi_nopin *rhdr)
{
        struct iscsi_nopout hdr;
	struct iscsi_task *task;

	if (!rhdr) {
		if (READ_ONCE(conn->ping_task))
			return -EINVAL;
		WRITE_ONCE(conn->ping_task, INVALID_SCSI_TASK);
	}

	memset(&hdr, 0, sizeof(struct iscsi_nopout));
	hdr.opcode = ISCSI_OP_NOOP_OUT | ISCSI_OP_IMMEDIATE;
	hdr.flags = ISCSI_FLAG_CMD_FINAL;

	if (rhdr) {
		hdr.lun = rhdr->lun;
		hdr.ttt = rhdr->ttt;
		hdr.itt = RESERVED_ITT;
	} else
		hdr.ttt = RESERVED_ITT;

	task = __iscsi_conn_send_pdu(conn, (struct iscsi_hdr *)&hdr, NULL, 0);
	if (!task) {
		if (!rhdr)
			WRITE_ONCE(conn->ping_task, NULL);
		iscsi_conn_printk(KERN_ERR, conn, "Could not send nopout\n");
		return -EIO;
	} else if (!rhdr) {
		/* only track our nops */
		conn->last_ping = jiffies;
	}

	return 0;
}


void __iscsi_get_task(struct iscsi_task *task)
{
	refcount_inc(&task->refcount);
}


iscsi_session_attr(discovery_parent_type, ISCSI_PARAM_DISCOVERY_PARENT_TYPE, 0);

static ssize_t
show_priv_session_state(struct device *dev, struct device_attribute *attr,
			char *buf)
{


}
EXPORT_SYMBOL_GPL(iscsi_create_session);

static void iscsi_conn_release(struct device *dev)
{
	struct iscsi_cls_conn *conn = iscsi_dev_to_conn(dev);
	struct device *parent = conn->dev.parent;

	ISCSI_DBG_TRANS_CONN(conn, "Releasing conn\n");


 * Malformed skbs with wrong lengths or invalid creds are not processed.
 */
static void
iscsi_if_rx(struct sk_buff *skb)
{
	u32 portid = NETLINK_CB(skb).portid;

	mutex_lock(&rx_queue_mutex);
	while (skb->len >= NLMSG_HDRLEN) {
		int err;
		uint32_t rlen;
		struct nlmsghdr	*nlh;
		struct iscsi_uevent *ev;
		uint32_t group;
		int retries = ISCSI_SEND_MAX_ALLOWED;

		nlh = nlmsg_hdr(skb);
		if (nlh->nlmsg_len < sizeof(*nlh) + sizeof(*ev) ||
		    skb->len < nlh->nlmsg_len) {
			break;
		}

		ev = nlmsg_data(nlh);
		rlen = NLMSG_ALIGN(nlh->nlmsg_len);
		if (rlen > skb->len)
			rlen = skb->len;

		err = iscsi_if_recv_msg(skb, nlh, &group);
		if (err) {
			ev->type = ISCSI_KEVENT_IF_ERROR;
			ev->iferror = err;
		}
		do {
			/*
			 * special case for GET_STATS:
			 * on success - sending reply and stats from
			 * inside of if_recv_msg(),
			 * on error - fall through.
			 */
			if (ev->type == ISCSI_UEVENT_GET_STATS && !err)
				break;
			if (ev->type == ISCSI_UEVENT_GET_CHAP && !err)
				break;
			err = iscsi_if_send_reply(portid, nlh->nlmsg_type,
						  ev, sizeof(*ev));
			if (err == -EAGAIN && --retries < 0) {
				printk(KERN_WARNING "Send reply failed, error %d\n", err);
				break;
			}
		} while (err < 0 && err != -ECONNREFUSED && err != -ESRCH);
		skb_pull(skb, rlen);


 *
 * This can be called from a LLD or iscsi_transport.
 */
int iscsi_destroy_conn(struct iscsi_cls_conn *conn)
{
	unsigned long flags;

	spin_lock_irqsave(&connlock, flags);
	list_del(&conn->conn_list);
	list_del(&conn->conn_list_err);
	spin_unlock_irqrestore(&connlock, flags);

	transport_unregister_device(&conn->dev);
	ISCSI_DBG_TRANS_CONN(conn, "Completing conn destruction\n");


static int iscsi_nop_out_rsp(struct iscsi_task *task,
			     struct iscsi_nopin *nop, char *data, int datalen)
{
	struct iscsi_conn *conn = task->conn;
	int rc = 0;

	if (READ_ONCE(conn->ping_task) != task) {
		/*
		 * If this is not in response to one of our
		 * nops then it must be from userspace.
		 */
		if (iscsi_recv_pdu(conn->cls_conn, (struct iscsi_hdr *)nop,
				   data, datalen))
			rc = ISCSI_ERR_CONN_FAILED;
	} else
		mod_timer(&conn->transport_timer, jiffies + conn->recv_timeout);
	iscsi_complete_task(task, ISCSI_TASK_COMPLETED);
	return rc;
}