static int _gnutls_recv_finished(gnutls_session_t session)
{
	uint8_t data[MAX_VERIFY_DATA_SIZE], *vrfy;
	gnutls_buffer_st buf;
	int data_size;
	int ret;
	int vrfy_size;
	const version_entry_st *vers = get_version(session);

	if (unlikely(vers == NULL))
		return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);

	ret =
	    _gnutls_recv_handshake(session, GNUTLS_HANDSHAKE_FINISHED,
				   0, &buf);
	if (ret < 0) {
		ERR("recv finished int", ret);
		gnutls_assert();
		return ret;
	}

	vrfy = buf.data;
	vrfy_size = buf.length;

	if (vers->id == GNUTLS_SSL3)
		data_size = 36;
	else
		data_size = 12;

	if (vrfy_size != data_size) {
		gnutls_assert();
		ret = GNUTLS_E_ERROR_IN_FINISHED_PACKET;
		goto cleanup;
	}

	if (vers->id == GNUTLS_SSL3) {
		ret =
		    _gnutls_ssl3_finished(session,
					  (session->security_parameters.
					   entity + 1) % 2, data, 0);
	} else {		/* TLS 1.0 */
		ret =
		    _gnutls_finished(session,
				     (session->security_parameters.entity +
				      1) % 2, data, 0);
	}

	if (ret < 0) {
		gnutls_assert();
		goto cleanup;
	}

	if (memcmp(vrfy, data, data_size) != 0) {
		gnutls_assert();
		ret = GNUTLS_E_ERROR_IN_FINISHED_PACKET;
		goto cleanup;
	}

	ret = _gnutls_ext_sr_finished(session, data, data_size, 1);
	if (ret < 0) {
		gnutls_assert();
		goto cleanup;
	}

	if ((session->internals.resumed != RESUME_FALSE
	     && session->security_parameters.entity == GNUTLS_CLIENT)
	    || (session->internals.resumed == RESUME_FALSE
		&& session->security_parameters.entity == GNUTLS_SERVER)) {
		/* if we are a client resuming - or we are a server not resuming */
		_gnutls_handshake_log
		    ("HSK[%p]: recording tls-unique CB (recv)\n", session);
		memcpy(session->internals.cb_tls_unique, data, data_size);
		session->internals.cb_tls_unique_len = data_size;
	}

	session->internals.initial_negotiation_completed = 1;

      cleanup:
	_gnutls_buffer_clear(&buf);

	return ret;
}

#define ERR(x, y) _gnutls_handshake_log("HSK[%p]: %s (%d)\n", session, x,y)

#define ERR(x, y)

static int server_select_comp_method(gnutls_session_t session,
					     uint8_t * data, int datalen);

static int handshake_client(gnutls_session_t session);

static int handshake_server(gnutls_session_t session);

static int
recv_hello(gnutls_session_t session, uint8_t * data, int datalen);

static int
recv_handshake_final(gnutls_session_t session, int init);

static int
send_handshake_final(gnutls_session_t session, int init);

static int
handshake_hash_add_recvd(gnutls_session_t session,
				 gnutls_handshake_description_t recv_type,
				 uint8_t * header, uint16_t header_size,
				 uint8_t * dataptr, uint32_t datalen);

static int
handshake_hash_add_sent(gnutls_session_t session,
				gnutls_handshake_description_t type,
				uint8_t * dataptr, uint32_t datalen);

static int
recv_hello_verify_request(gnutls_session_t session,
				  uint8_t * data, int datalen);

#define SERVER_MSG "server finished"

#define CLIENT_MSG "client finished"

#define CHECK_SIZE(ll) \
  if ((session->internals.max_handshake_data_buffer_size > 0) && \
      (((ll) + session->internals.handshake_hash_buffer.length) > \
       session->internals.max_handshake_data_buffer_size)) \
    return gnutls_assert_val(GNUTLS_E_HANDSHAKE_TOO_LARGE)

#define IMED_RET( str, ret, allow_alert) do { \
	if (ret < 0) { \
		/* EAGAIN and INTERRUPTED are always non-fatal */


read_server_hello(gnutls_session_t session,
			  uint8_t * data, int datalen)
{
	uint8_t session_id_len = 0;
	int pos = 0;
	int ret = 0;
	gnutls_protocol_t version;
	int len = datalen;

	if (datalen < 38) {
		gnutls_assert();
		return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
	}

	_gnutls_handshake_log("HSK[%p]: Server's version: %d.%d\n",
			      session, data[pos], data[pos + 1]);

	DECR_LEN(len, 2);
	version = _gnutls_version_get(data[pos], data[pos + 1]);
	if (_gnutls_version_is_supported(session, version) == 0) {
		gnutls_assert();
		return GNUTLS_E_UNSUPPORTED_VERSION_PACKET;
	}

	if (_gnutls_set_current_version(session, version) < 0)
		return gnutls_assert_val(GNUTLS_E_UNSUPPORTED_VERSION_PACKET);

	pos += 2;

	DECR_LEN(len, GNUTLS_RANDOM_SIZE);
	ret = _gnutls_set_server_random(session, &data[pos]);
	if (ret < 0)
		return gnutls_assert_val(ret);

	pos += GNUTLS_RANDOM_SIZE;

	/* Read session ID
	 */
	DECR_LEN(len, 1);
	session_id_len = data[pos++];

	if (len < session_id_len || session_id_len > GNUTLS_MAX_SESSION_ID_SIZE) {
		gnutls_assert();
		return GNUTLS_E_UNSUPPORTED_VERSION_PACKET;
	}
	DECR_LEN(len, session_id_len);

	/* check if we are resuming and set the appropriate
	 * values;
	 */
	if (client_check_if_resuming
	    (session, &data[pos], session_id_len) == 0) {
		pos += session_id_len + 2 + 1;
		DECR_LEN(len, 2 + 1);

		ret =
		    _gnutls_parse_extensions(session, GNUTLS_EXT_MANDATORY,
					     &data[pos], len);
		if (ret < 0) {
			gnutls_assert();
			return ret;
		}
		return 0;
	}

	pos += session_id_len;

	/* Check if the given cipher suite is supported and copy
	 * it to the session.
	 */

	DECR_LEN(len, 2);
	ret = set_client_ciphersuite(session, &data[pos]);
	if (ret < 0) {
		gnutls_assert();
		return ret;
	}
	pos += 2;

	/* move to compression
	 */
	DECR_LEN(len, 1);

	ret = set_client_comp_method(session, data[pos++]);
	if (ret < 0) {
		gnutls_assert();
		return GNUTLS_E_UNKNOWN_COMPRESSION_ALGORITHM;
	}

	/* Parse extensions.
	 */
	ret =
	    _gnutls_parse_extensions(session, GNUTLS_EXT_ANY, &data[pos],
				     len);
	if (ret < 0) {
		gnutls_assert();
		return ret;
	}

	return ret;
}

handshake: add FALLBACK_SCSV priority option

This allows clients to enable the TLS_FALLBACK_SCSV mechanism during
the handshake, as defined in RFC7507.

#define ERR(x, y) _gnutls_handshake_log("HSK[%p]: %s (%d)\n", session, x,y)

static int server_select_comp_method(gnutls_session_t session,
					     uint8_t * data, int datalen);

static int handshake_client(gnutls_session_t session);

static int handshake_server(gnutls_session_t session);

static int
recv_hello(gnutls_session_t session, uint8_t * data, int datalen);

static int
recv_handshake_final(gnutls_session_t session, int init);

static int
send_handshake_final(gnutls_session_t session, int init);

static int
handshake_hash_add_recvd(gnutls_session_t session,
				 gnutls_handshake_description_t recv_type,
				 uint8_t * header, uint16_t header_size,
				 uint8_t * dataptr, uint32_t datalen);

static int
handshake_hash_add_sent(gnutls_session_t session,
				gnutls_handshake_description_t type,
				uint8_t * dataptr, uint32_t datalen);

static int
recv_hello_verify_request(gnutls_session_t session,
				  uint8_t * data, int datalen);

#define CHECK_SIZE(ll) \
  if ((session->internals.max_handshake_data_buffer_size > 0) && \
      (((ll) + session->internals.handshake_hash_buffer.length) > \
       session->internals.max_handshake_data_buffer_size)) \
    return gnutls_assert_val(GNUTLS_E_HANDSHAKE_TOO_LARGE)

#define IMED_RET( str, ret, allow_alert) do { \
	if (ret < 0) { \
		/* EAGAIN and INTERRUPTED are always non-fatal */


static void enable_unsafe_renegotiation(gnutls_priority_t c)
{
	c->sr = SR_UNSAFE;
}

static void prio_remove(priority_st * priority_list, unsigned int algo);

static void prio_add(priority_st * priority_list, unsigned int algo);

static void
break_list(char *etag,
		 char *broken_etag[MAX_ELEMENTS], int *size);

typedef void (bulk_rmadd_func) (priority_st * priority_list, const int *);

static const int _supported_ecc_normal[] = {
	GNUTLS_ECC_CURVE_SECP256R1,
	GNUTLS_ECC_CURVE_SECP384R1,
	GNUTLS_ECC_CURVE_SECP521R1,
#ifdef ENABLE_NON_SUITEB_CURVES
	GNUTLS_ECC_CURVE_SECP224R1,
	GNUTLS_ECC_CURVE_SECP192R1,
#endif
	0
};

static const int* supported_ecc_normal = _supported_ecc_normal;

static const int _supported_ecc_secure128[] = {
	GNUTLS_ECC_CURVE_SECP256R1,
	GNUTLS_ECC_CURVE_SECP384R1,
	GNUTLS_ECC_CURVE_SECP521R1,
	0
};

static const int* supported_ecc_secure128 = _supported_ecc_secure128;

static const int _supported_ecc_suiteb128[] = {
	GNUTLS_ECC_CURVE_SECP256R1,
	GNUTLS_ECC_CURVE_SECP384R1,
	0
};

static const int* supported_ecc_suiteb128 = _supported_ecc_suiteb128;

static const int _supported_ecc_suiteb192[] = {
	GNUTLS_ECC_CURVE_SECP384R1,
	0
};

static const int* supported_ecc_suiteb192 = _supported_ecc_suiteb192;

static const int _supported_ecc_secure192[] = {
	GNUTLS_ECC_CURVE_SECP384R1,
	GNUTLS_ECC_CURVE_SECP521R1,
	0
};

static const int* supported_ecc_secure192 = _supported_ecc_secure192;

static const int protocol_priority[] = {
	GNUTLS_TLS1_2,
	GNUTLS_TLS1_1,
	GNUTLS_TLS1_0,
	GNUTLS_DTLS1_2,
	GNUTLS_DTLS1_0,
	0
};

static const int stream_protocol_priority[] = {
	GNUTLS_TLS1_2,
	GNUTLS_TLS1_1,
	GNUTLS_TLS1_0,
	0
};

static const int dgram_protocol_priority[] = {
	GNUTLS_DTLS1_2,
	GNUTLS_DTLS1_0,
	GNUTLS_DTLS0_9,
	0
};

static const int dtls_protocol_priority[] = {
	GNUTLS_DTLS1_2,
	GNUTLS_DTLS1_0,
	0
};

static const int _protocol_priority_suiteb[] = {
	GNUTLS_TLS1_2,
	0
};

static const int* protocol_priority_suiteb = _protocol_priority_suiteb;

static const int _kx_priority_performance[] = {
	GNUTLS_KX_RSA,
#ifdef ENABLE_ECDHE
	GNUTLS_KX_ECDHE_ECDSA,
	GNUTLS_KX_ECDHE_RSA,
#endif
#ifdef ENABLE_DHE
	GNUTLS_KX_DHE_RSA,
#endif
	0
};

static const int* kx_priority_performance = _kx_priority_performance;


static int _gnutls_send_finished(gnutls_session_t session, int again)
{
	mbuffer_st *bufel;
	uint8_t *data;
	int ret;
	size_t vdata_size = 0;
	const version_entry_st *vers;

	if (again == 0) {
		bufel =
		    _gnutls_handshake_alloc(session,
					    MAX_VERIFY_DATA_SIZE);
		if (bufel == NULL) {
			gnutls_assert();
			return GNUTLS_E_MEMORY_ERROR;
		}
		data = _mbuffer_get_udata_ptr(bufel);

		vers = get_version(session);
		if (unlikely(vers == NULL))
			return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);

		if (vers->id == GNUTLS_SSL3) {
			ret =
			    _gnutls_ssl3_finished(session,
						  session->
						  security_parameters.
						  entity, data, 1);
			_mbuffer_set_udata_size(bufel, 36);
		} else {	/* TLS 1.0+ */
			ret = _gnutls_finished(session,
					       session->
					       security_parameters.entity,
					       data, 1);
			_mbuffer_set_udata_size(bufel, 12);
		}

		if (ret < 0) {
			gnutls_assert();
			return ret;
		}

		vdata_size = _mbuffer_get_udata_size(bufel);

		ret =
		    _gnutls_ext_sr_finished(session, data, vdata_size, 0);
		if (ret < 0) {
			gnutls_assert();
			return ret;
		}

		if ((session->internals.resumed == RESUME_FALSE
		     && session->security_parameters.entity ==
		     GNUTLS_CLIENT)
		    || (session->internals.resumed != RESUME_FALSE
			&& session->security_parameters.entity ==
			GNUTLS_SERVER)) {
			/* if we are a client not resuming - or we are a server resuming */
			_gnutls_handshake_log
			    ("HSK[%p]: recording tls-unique CB (send)\n",
			     session);
			memcpy(session->internals.cb_tls_unique, data,
			       vdata_size);
			session->internals.cb_tls_unique_len = vdata_size;
		}

		ret =
		    _gnutls_send_handshake(session, bufel,
					   GNUTLS_HANDSHAKE_FINISHED);
	} else {
		ret =
		    _gnutls_send_handshake(session, NULL,
					   GNUTLS_HANDSHAKE_FINISHED);
	}

	return ret;
}

#define ERR(x, y) _gnutls_handshake_log("HSK[%p]: %s (%d)\n", session, x,y)

static int server_select_comp_method(gnutls_session_t session,
					     uint8_t * data, int datalen);

static int handshake_client(gnutls_session_t session);

static int handshake_server(gnutls_session_t session);

static int
recv_hello(gnutls_session_t session, uint8_t * data, int datalen);

static int
recv_handshake_final(gnutls_session_t session, int init);

static int
send_handshake_final(gnutls_session_t session, int init);

static int
handshake_hash_add_recvd(gnutls_session_t session,
				 gnutls_handshake_description_t recv_type,
				 uint8_t * header, uint16_t header_size,
				 uint8_t * dataptr, uint32_t datalen);

static int
handshake_hash_add_sent(gnutls_session_t session,
				gnutls_handshake_description_t type,
				uint8_t * dataptr, uint32_t datalen);

static int
recv_hello_verify_request(gnutls_session_t session,
				  uint8_t * data, int datalen);

#define SERVER_MSG "server finished"

#define CLIENT_MSG "client finished"

#define CHECK_SIZE(ll) \
  if ((session->internals.max_handshake_data_buffer_size > 0) && \
      (((ll) + session->internals.handshake_hash_buffer.length) > \
       session->internals.max_handshake_data_buffer_size)) \
    return gnutls_assert_val(GNUTLS_E_HANDSHAKE_TOO_LARGE)

#define IMED_RET( str, ret, allow_alert) do { \
	if (ret < 0) { \
		/* EAGAIN and INTERRUPTED are always non-fatal */


server_find_pk_algos_in_ciphersuites(const uint8_t *
				     data, unsigned int datalen,
				     gnutls_pk_algorithm_t * algos,
				     size_t * algos_size)
{
	unsigned int j, x;
	gnutls_kx_algorithm_t kx;
	gnutls_pk_algorithm_t pk;
	unsigned found;
	unsigned int max = *algos_size;

	if (datalen % 2 != 0) {
		gnutls_assert();
		return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
	}

	*algos_size = 0;
	for (j = 0; j < datalen; j += 2) {
		kx = _gnutls_cipher_suite_get_kx_algo(&data[j]);
		if (_gnutls_map_kx_get_cred(kx, 1) ==
		    GNUTLS_CRD_CERTIFICATE) {
			pk = _gnutls_map_pk_get_pk(kx);
			found = 0;
			for (x = 0; x < *algos_size; x++) {
				if (algos[x] == pk) {
					found = 1;
					break;
				}
			}

			if (found == 0) {
				algos[(*algos_size)++] =
				    _gnutls_map_pk_get_pk(kx);
				if ((*algos_size) >= max)
					return 0;
			}
		}
	}

	return 0;
}

static int server_select_comp_method(gnutls_session_t session,
					     uint8_t * data, int datalen);

static int handshake_client(gnutls_session_t session);

static int handshake_server(gnutls_session_t session);

static int
recv_hello(gnutls_session_t session, uint8_t * data, int datalen);

static int
recv_handshake_final(gnutls_session_t session, int init);

static int
send_handshake_final(gnutls_session_t session, int init);

static int
handshake_hash_add_recvd(gnutls_session_t session,
				 gnutls_handshake_description_t recv_type,
				 uint8_t * header, uint16_t header_size,
				 uint8_t * dataptr, uint32_t datalen);

static int
handshake_hash_add_sent(gnutls_session_t session,
				gnutls_handshake_description_t type,
				uint8_t * dataptr, uint32_t datalen);

static int
recv_hello_verify_request(gnutls_session_t session,
				  uint8_t * data, int datalen);

#define CHECK_SIZE(ll) \
  if ((session->internals.max_handshake_data_buffer_size > 0) && \
      (((ll) + session->internals.handshake_hash_buffer.length) > \
       session->internals.max_handshake_data_buffer_size)) \
    return gnutls_assert_val(GNUTLS_E_HANDSHAKE_TOO_LARGE)


recv_hello_verify_request(gnutls_session_t session,
				  uint8_t * data, int datalen)
{
	ssize_t len = datalen;
	size_t pos = 0;
	uint8_t cookie_len;
	unsigned int nb_verifs;

	if (!IS_DTLS(session)
	    || session->security_parameters.entity == GNUTLS_SERVER) {
		gnutls_assert();
		return GNUTLS_E_INTERNAL_ERROR;
	}

	nb_verifs = ++session->internals.dtls.hsk_hello_verify_requests;
	if (nb_verifs >= MAX_HANDSHAKE_HELLO_VERIFY_REQUESTS) {
		/* The server is either buggy, malicious or changing cookie
		   secrets _way_ too fast. */
		gnutls_assert();
		return GNUTLS_E_UNEXPECTED_PACKET;
	}

	/* TODO: determine if we need to do anything with the server version field */
	DECR_LEN(len, 2);
	pos += 2;

	DECR_LEN(len, 1);
	cookie_len = data[pos];
	pos++;

	if (cookie_len > DTLS_MAX_COOKIE_SIZE) {
		gnutls_assert();
		return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
	}

	DECR_LEN(len, cookie_len);

	session->internals.dtls.cookie_len = cookie_len;
	memcpy(session->internals.dtls.cookie, &data[pos], cookie_len);

	if (len != 0) {
		gnutls_assert();
		return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
	}

	/* reset handshake hash buffers */
	handshake_hash_buffer_empty(session);

	return 0;
}

#define ERR(x, y) _gnutls_handshake_log("HSK[%p]: %s (%d)\n", session, x,y)

static int server_select_comp_method(gnutls_session_t session,
					     uint8_t * data, int datalen);

static int handshake_client(gnutls_session_t session);

static int handshake_server(gnutls_session_t session);

static int
recv_hello(gnutls_session_t session, uint8_t * data, int datalen);

static int
recv_handshake_final(gnutls_session_t session, int init);

static int
send_handshake_final(gnutls_session_t session, int init);

static int
handshake_hash_add_recvd(gnutls_session_t session,
				 gnutls_handshake_description_t recv_type,
				 uint8_t * header, uint16_t header_size,
				 uint8_t * dataptr, uint32_t datalen);

static int
handshake_hash_add_sent(gnutls_session_t session,
				gnutls_handshake_description_t type,
				uint8_t * dataptr, uint32_t datalen);

static int
recv_hello_verify_request(gnutls_session_t session,
				  uint8_t * data, int datalen);

#define SERVER_MSG "server finished"

#define CHECK_SIZE(ll) \
  if ((session->internals.max_handshake_data_buffer_size > 0) && \
      (((ll) + session->internals.handshake_hash_buffer.length) > \
       session->internals.max_handshake_data_buffer_size)) \
    return gnutls_assert_val(GNUTLS_E_HANDSHAKE_TOO_LARGE)


static void enable_compat(gnutls_priority_t c)
{
	ENABLE_COMPAT(c);
}


static char *check_str(char *line, size_t line_size, const char *needle, size_t needle_size)
{
	char *p;
	unsigned n;

	while (c_isspace(*line)) {
		line++;
		line_size--;
	}

	if (line[0] == '#' || needle_size >= line_size)
		return NULL;

	if (memcmp(line, needle, needle_size) == 0) {
		p = &line[needle_size];
		while (c_isspace(*p)) {
			p++;
		}
		if (*p != '=') {
			return NULL;
		} else
			p++;

		while (c_isspace(*p)) {
			p++;
		}

		n = strlen(p);

		if (n > 1 && p[n-1] == '\n') {
			n--;
			p[n] = 0;
		}

		if (n > 1 && p[n-1] == '\r') {
			n--;
			p[n] = 0;
		}
		return p;
	}

	return NULL;
}


static void enable_server_precedence(gnutls_priority_t c)
{
	c->server_precedence = 1;
}


int gnutls_set_default_priority(gnutls_session_t session)
{
	return gnutls_priority_set_direct(session, NULL, NULL);
}


gnutls_priority_cipher_list(gnutls_priority_t pcache,
			    const unsigned int **list)
{
	if (pcache->cipher.algorithms == 0)
		return 0;

	*list = pcache->cipher.priority;
	return pcache->cipher.algorithms;
}


int check_level(const char *level, gnutls_priority_t priority_cache,
		int add)
{
	bulk_rmadd_func *func;
	unsigned profile = 0;
	unsigned i;
	int j;
	const cipher_entry_st *centry;

	if (add)
		func = _add_priority;
	else
		func = _set_priority;

	for (i=0;;i++) {
		if (pgroups[i].name == NULL)
			return 0;

		if (strcasecmp(level, pgroups[i].name) == 0 ||
			(pgroups[i].alias != NULL && strcasecmp(level, pgroups[i].alias) == 0)) {
			if (pgroups[i].proto_list != NULL)
				func(&priority_cache->protocol, *pgroups[i].proto_list);
			func(&priority_cache->cipher, *pgroups[i].cipher_list);
			func(&priority_cache->kx, *pgroups[i].kx_list);
			func(&priority_cache->mac, *pgroups[i].mac_list);
			func(&priority_cache->sign_algo, *pgroups[i].sign_list);
			func(&priority_cache->supported_ecc, *pgroups[i].ecc_list);

			if (pgroups[i].profile != 0) {
				SET_PROFILE(pgroups[i].profile); /* set certificate level */
			}
			SET_LEVEL(pgroups[i].sec_param); /* set DH params level */
			priority_cache->no_tickets = pgroups[i].no_tickets;
			if (priority_cache->have_cbc == 0) {
				for (j=0;(*pgroups[i].cipher_list)[j]!=0;j++) {
					centry = cipher_to_entry((*pgroups[i].cipher_list)[j]);
					if (centry != NULL && centry->type == CIPHER_BLOCK) {
						priority_cache->have_cbc = 1;
						break;
					}
				}
			}
			return 1;
		}
	}
}


gnutls_handshake_get_last_out(gnutls_session_t session)
{
	return session->internals.last_handshake_out;
}


handshake_hash_add_recvd(gnutls_session_t session,
				 gnutls_handshake_description_t recv_type,
				 uint8_t * header, uint16_t header_size,
				 uint8_t * dataptr, uint32_t datalen)
{
	int ret;
	const version_entry_st *vers = get_version(session);

	if (unlikely(vers == NULL))
		return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);

	if ((vers->id != GNUTLS_DTLS0_9 &&
	     recv_type == GNUTLS_HANDSHAKE_HELLO_VERIFY_REQUEST) ||
	    recv_type == GNUTLS_HANDSHAKE_HELLO_REQUEST)
		return 0;

	CHECK_SIZE(header_size + datalen);

	session->internals.handshake_hash_buffer_prev_len =
	    session->internals.handshake_hash_buffer.length;

	if (vers->id != GNUTLS_DTLS0_9) {
		ret =
		    _gnutls_buffer_append_data(&session->internals.
					       handshake_hash_buffer,
					       header, header_size);
		if (ret < 0)
			return gnutls_assert_val(ret);
	}
	if (datalen > 0) {
		ret =
		    _gnutls_buffer_append_data(&session->internals.
					       handshake_hash_buffer,
					       dataptr, datalen);
		if (ret < 0)
			return gnutls_assert_val(ret);
	}

	/* save the size until client KX. That is because the TLS
	 * session hash is calculated up to this message.
	 */
	if (recv_type == GNUTLS_HANDSHAKE_CLIENT_KEY_EXCHANGE)
		session->internals.handshake_hash_buffer_client_kx_len =
			session->internals.handshake_hash_buffer.length;

	return 0;
}

#define ERR(x, y) _gnutls_handshake_log("HSK[%p]: %s (%d)\n", session, x,y)

static int server_select_comp_method(gnutls_session_t session,
					     uint8_t * data, int datalen);

static int handshake_client(gnutls_session_t session);

static int handshake_server(gnutls_session_t session);

static int
recv_hello(gnutls_session_t session, uint8_t * data, int datalen);

static int
recv_handshake_final(gnutls_session_t session, int init);

static int
send_handshake_final(gnutls_session_t session, int init);

static int
handshake_hash_add_recvd(gnutls_session_t session,
				 gnutls_handshake_description_t recv_type,
				 uint8_t * header, uint16_t header_size,
				 uint8_t * dataptr, uint32_t datalen);

static int
handshake_hash_add_sent(gnutls_session_t session,
				gnutls_handshake_description_t type,
				uint8_t * dataptr, uint32_t datalen);

static int
recv_hello_verify_request(gnutls_session_t session,
				  uint8_t * data, int datalen);

#define CLIENT_MSG "client finished"

#define CHECK_SIZE(ll) \
  if ((session->internals.max_handshake_data_buffer_size > 0) && \
      (((ll) + session->internals.handshake_hash_buffer.length) > \
       session->internals.max_handshake_data_buffer_size)) \
    return gnutls_assert_val(GNUTLS_E_HANDSHAKE_TOO_LARGE)

#define IMED_RET( str, ret, allow_alert) do { \
	if (ret < 0) { \
		/* EAGAIN and INTERRUPTED are always non-fatal */


inline static void _set_priority(priority_st * st, const int *list)
{
	int num = 0, i;

	while (list[num] != 0)
		num++;
	if (num > MAX_ALGOS)
		num = MAX_ALGOS;
	st->algorithms = num;

	for (i = 0; i < num; i++) {
		st->priority[i] = list[i];
	}

	return;
}


gnutls_priority_sign_list(gnutls_priority_t pcache,
			  const unsigned int **list)
{
	if (pcache->sign_algo.algorithms == 0)
		return 0;

	*list = pcache->sign_algo.priority;
	return pcache->sign_algo.algorithms;
}


gnutls_priority_set(gnutls_session_t session, gnutls_priority_t priority)
{
	if (priority == NULL) {
		gnutls_assert();
		return GNUTLS_E_NO_CIPHER_SUITES;
	}

	memcpy(&session->internals.priorities, priority,
	       sizeof(struct gnutls_priority_st));

	/* set the current version to the first in the chain.
	 * This will be overridden later.
	 */
	if (session->internals.priorities.protocol.algorithms > 0) {
		if (_gnutls_set_current_version(session,
					    session->internals.priorities.
					    protocol.priority[0]) < 0) {
			return gnutls_assert_val(GNUTLS_E_UNSUPPORTED_VERSION_PACKET);
		}
	}

	if (priority->no_tickets != 0) {
		/* when PFS is explicitly requested, disable session tickets */
		_gnutls_ext_unset_session_data(session, GNUTLS_EXTENSION_SESSION_TICKET);
	}

	if (session->internals.priorities.protocol.algorithms == 0 ||
	    session->internals.priorities.cipher.algorithms == 0 ||
	    session->internals.priorities.mac.algorithms == 0 ||
	    session->internals.priorities.kx.algorithms == 0 ||
	    session->internals.priorities.compression.algorithms == 0)
		return gnutls_assert_val(GNUTLS_E_NO_PRIORITIES_WERE_SET);

	return 0;
}

static const int _kx_priority_secure[] = {
	/* The ciphersuites that offer forward secrecy take
	 * precedence
	 */
#ifdef ENABLE_ECDHE
	GNUTLS_KX_ECDHE_ECDSA,
	GNUTLS_KX_ECDHE_RSA,
#endif
	GNUTLS_KX_RSA,
	/* KX-RSA is now ahead of DHE-RSA and DHE-DSS due to the compatibility
	 * issues the DHE ciphersuites have. That is, one cannot enforce a specific
	 * security level without dropping the connection.
	 */
#ifdef ENABLE_DHE
	GNUTLS_KX_DHE_RSA,
#endif
	/* GNUTLS_KX_ANON_DH: Man-in-the-middle prone, don't add!
	 */
	0
};

static const int comp_priority[] = {
	/* compression should be explicitly requested to be enabled */
	GNUTLS_COMP_NULL,
	0
};

#define LEVEL_PFS "PFS"

struct priority_groups_st {
	const char *name;
	const char *alias;
	const int **proto_list;
	const int **cipher_list;
	const int **mac_list;
	const int **kx_list;
	const int **sign_list;
	const int **ecc_list;
	unsigned profile;
	int sec_param;
	bool no_tickets;
}


break_list(char *list,
		 char *broken_list[MAX_ELEMENTS], int *size)
{
	char *p = list;

	*size = 0;

	do {
		broken_list[*size] = p;

		(*size)++;

		p = strchr(p, ':');
		if (p) {
			*p = 0;
			p++;	/* move to next entry and skip white
				 * space.
				 */
			while (*p == ' ')
				p++;
		}
	}
	while (p != NULL && *size < MAX_ELEMENTS);
}

#define MAX_ELEMENTS 64

static void prio_remove(priority_st * priority_list, unsigned int algo);

static void prio_add(priority_st * priority_list, unsigned int algo);

static void
break_list(char *etag,
		 char *broken_etag[MAX_ELEMENTS], int *size);

typedef void (bulk_rmadd_func) (priority_st * priority_list, const int *);

static const int _supported_ecc_normal[] = {
	GNUTLS_ECC_CURVE_SECP256R1,
	GNUTLS_ECC_CURVE_SECP384R1,
	GNUTLS_ECC_CURVE_SECP521R1,
#ifdef ENABLE_NON_SUITEB_CURVES
	GNUTLS_ECC_CURVE_SECP224R1,
	GNUTLS_ECC_CURVE_SECP192R1,
#endif
	0
};

static const int* supported_ecc_normal = _supported_ecc_normal;

static const int _supported_ecc_secure128[] = {
	GNUTLS_ECC_CURVE_SECP256R1,
	GNUTLS_ECC_CURVE_SECP384R1,
	GNUTLS_ECC_CURVE_SECP521R1,
	0
};

static const int* supported_ecc_secure128 = _supported_ecc_secure128;

static const int _supported_ecc_suiteb128[] = {
	GNUTLS_ECC_CURVE_SECP256R1,
	GNUTLS_ECC_CURVE_SECP384R1,
	0
};

static const int* supported_ecc_suiteb128 = _supported_ecc_suiteb128;

static const int _supported_ecc_suiteb192[] = {
	GNUTLS_ECC_CURVE_SECP384R1,
	0
};

static const int* supported_ecc_suiteb192 = _supported_ecc_suiteb192;

static const int _supported_ecc_secure192[] = {
	GNUTLS_ECC_CURVE_SECP384R1,
	GNUTLS_ECC_CURVE_SECP521R1,
	0
};

static const int* supported_ecc_secure192 = _supported_ecc_secure192;

static const int protocol_priority[] = {
	GNUTLS_TLS1_2,
	GNUTLS_TLS1_1,
	GNUTLS_TLS1_0,
	GNUTLS_DTLS1_2,
	GNUTLS_DTLS1_0,
	0
};

static const int stream_protocol_priority[] = {
	GNUTLS_TLS1_2,
	GNUTLS_TLS1_1,
	GNUTLS_TLS1_0,
	0
};

static const int dgram_protocol_priority[] = {
	GNUTLS_DTLS1_2,
	GNUTLS_DTLS1_0,
	GNUTLS_DTLS0_9,
	0
};

static const int dtls_protocol_priority[] = {
	GNUTLS_DTLS1_2,
	GNUTLS_DTLS1_0,
	0
};

static const int _protocol_priority_suiteb[] = {
	GNUTLS_TLS1_2,
	0
};

static const int* protocol_priority_suiteb = _protocol_priority_suiteb;

static const int _kx_priority_performance[] = {
	GNUTLS_KX_RSA,
#ifdef ENABLE_ECDHE
	GNUTLS_KX_ECDHE_ECDSA,
	GNUTLS_KX_ECDHE_RSA,
#endif
#ifdef ENABLE_DHE
	GNUTLS_KX_DHE_RSA,
#endif
	0
};

static const int* kx_priority_performance = _kx_priority_performance;


_gnutls_send_empty_handshake(gnutls_session_t session,
			     gnutls_handshake_description_t type,
			     int again)
{
	mbuffer_st *bufel;

	if (again == 0) {
		bufel = _gnutls_handshake_alloc(session, 0);
		if (bufel == NULL) {
			gnutls_assert();
			return GNUTLS_E_MEMORY_ERROR;
		}
	} else
		bufel = NULL;

	return _gnutls_send_handshake(session, bufel, type);
}

#define ERR(x, y) _gnutls_handshake_log("HSK[%p]: %s (%d)\n", session, x,y)

static int server_select_comp_method(gnutls_session_t session,
					     uint8_t * data, int datalen);

static int handshake_client(gnutls_session_t session);

static int handshake_server(gnutls_session_t session);

static int
recv_hello(gnutls_session_t session, uint8_t * data, int datalen);

static int
recv_handshake_final(gnutls_session_t session, int init);

static int
send_handshake_final(gnutls_session_t session, int init);

static int
handshake_hash_add_recvd(gnutls_session_t session,
				 gnutls_handshake_description_t recv_type,
				 uint8_t * header, uint16_t header_size,
				 uint8_t * dataptr, uint32_t datalen);

static int
handshake_hash_add_sent(gnutls_session_t session,
				gnutls_handshake_description_t type,
				uint8_t * dataptr, uint32_t datalen);

static int
recv_hello_verify_request(gnutls_session_t session,
				  uint8_t * data, int datalen);

#define CHECK_SIZE(ll) \
  if ((session->internals.max_handshake_data_buffer_size > 0) && \
      (((ll) + session->internals.handshake_hash_buffer.length) > \
       session->internals.max_handshake_data_buffer_size)) \
    return gnutls_assert_val(GNUTLS_E_HANDSHAKE_TOO_LARGE)


gdImagePtr gdImageCreateFromXpm (char *filename)
{
	XpmInfo info;
	XpmImage image;
	int i, j, k, number;
	char buf[5];
	gdImagePtr im = 0;
	int *pointer;
	int red = 0, green = 0, blue = 0;
	int *colors;
	int ret;

	ret = XpmReadFileToXpmImage(filename, &image, &info);
	if (ret != XpmSuccess) {
		return 0;
	}
	number = image.ncolors;
	for(i = 0; i < number; i++) {
		if (!image.colorTable[i].c_color) {
			goto done;
		}
	}

	if (!(im = gdImageCreate(image.width, image.height))) {
		goto done;
	}

	colors = (int *) safe_emalloc(number, sizeof(int), 0);
	for (i = 0; i < number; i++) {
		switch (strlen (image.colorTable[i].c_color)) {
			case 4:
				buf[1] = '\0';
				buf[0] = image.colorTable[i].c_color[1];
				red = strtol(buf, NULL, 16);

				buf[0] = image.colorTable[i].c_color[2];
				green = strtol(buf, NULL, 16);

				buf[0] = image.colorTable[i].c_color[3];
				blue = strtol(buf, NULL, 16);
				break;

			case 7:
				buf[2] = '\0';
				buf[0] = image.colorTable[i].c_color[1];
				buf[1] = image.colorTable[i].c_color[2];
				red = strtol(buf, NULL, 16);

				buf[0] = image.colorTable[i].c_color[3];
				buf[1] = image.colorTable[i].c_color[4];
				green = strtol(buf, NULL, 16);

				buf[0] = image.colorTable[i].c_color[5];
				buf[1] = image.colorTable[i].c_color[6];
				blue = strtol(buf, NULL, 16);
				break;

			case 10:
				buf[3] = '\0';
				buf[0] = image.colorTable[i].c_color[1];
				buf[1] = image.colorTable[i].c_color[2];
				buf[2] = image.colorTable[i].c_color[3];
				red = strtol(buf, NULL, 16);
				red /= 64;

				buf[0] = image.colorTable[i].c_color[4];
				buf[1] = image.colorTable[i].c_color[5];
				buf[2] = image.colorTable[i].c_color[6];
				green = strtol(buf, NULL, 16);
				green /= 64;

				buf[0] = image.colorTable[i].c_color[7];
				buf[1] = image.colorTable[i].c_color[8];
				buf[2] = image.colorTable[i].c_color[9];
				blue = strtol(buf, NULL, 16);
				blue /= 64;
				break;

			case 13:
				buf[4] = '\0';
				buf[0] = image.colorTable[i].c_color[1];
				buf[1] = image.colorTable[i].c_color[2];
				buf[2] = image.colorTable[i].c_color[3];
				buf[3] = image.colorTable[i].c_color[4];
				red = strtol(buf, NULL, 16);
				red /= 256;

				buf[0] = image.colorTable[i].c_color[5];
				buf[1] = image.colorTable[i].c_color[6];
				buf[2] = image.colorTable[i].c_color[7];
				buf[3] = image.colorTable[i].c_color[8];
				green = strtol(buf, NULL, 16);
				green /= 256;

				buf[0] = image.colorTable[i].c_color[9];
				buf[1] = image.colorTable[i].c_color[10];
				buf[2] = image.colorTable[i].c_color[11];
				buf[3] = image.colorTable[i].c_color[12];
				blue = strtol(buf, NULL, 16);
				blue /= 256;
				break;
		}

		colors[i] = gdImageColorResolve(im, red, green, blue);
	}

	pointer = (int *) image.data;
	for (i = 0; i < image.height; i++) {
		for (j = 0; j < image.width; j++) {
			k = *pointer++;
			gdImageSetPixel(im, j, i, colors[k]);
		}
	}

	gdFree(colors);
 done:
	XpmFreeXpmImage(&image);
	XpmFreeXpmInfo(&info);
	return im;
}

Fixed Bug #66901 php-gd 'c_color' NULL pointer dereference

Upstream https://bitbucket.org/libgd/gd-libgd/commits/463c3bd09bfe8e924e19acad7a2a6af16953a704

Notice: this fix don't manage monochrome/monovisual values
but just fix the security issue CVE-2014-2497
failing when trying to load such an image


TPM_RESULT SWTPM_NVRAM_Init(void)
{
    TPM_RESULT  rc = 0;
    const char  *tpm_state_path;
    size_t      length;

    TPM_DEBUG(" SWTPM_NVRAM_Init:\n");

    /* TPM_NV_DISK TPM emulation stores in local directory determined by environment variable. */
    if (rc == 0) {
        tpm_state_path = tpmstate_get_dir();
        if (tpm_state_path == NULL) {
            logprintf(STDERR_FILENO,
                      "SWTPM_NVRAM_Init: Error (fatal), TPM_PATH environment "
                      "variable not set\n");
            rc = TPM_FAIL;
        }
    }

    /* check that the directory name plus a file name will not overflow FILENAME_MAX */
    if (rc == 0) {
        length = strlen(tpm_state_path);
        if ((length + TPM_FILENAME_MAX) > FILENAME_MAX) {
            logprintf(STDERR_FILENO,
                      "SWTPM_NVRAM_Init: Error (fatal), TPM state path name "
                      "%s too large\n", tpm_state_path);
            rc = TPM_FAIL;
        }
    }
    if (rc == 0) {
        strcpy(state_directory, tpm_state_path);
        TPM_DEBUG("TPM_NVRAM_Init: Rooted state path %s\n", state_directory);
    }

    if (rc == 0 && lockfile_fd < 0)
        rc = SWTPM_NVRAM_Lock_Lockfile(state_directory, &lockfile_fd);

    return rc;
}

swtpm: Do not follow symlinks when opening lockfile (CVE-2020-28407)

This patch addresses CVE-2020-28407.

Prevent us from following symliks when we open the lockfile
for writing.

Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>

typedef struct {
    uint8_t  version;
    uint8_t  min_version; /* min. required version */
    uint16_t hdrsize;
    uint16_t flags;
    uint32_t totlen; /* length of the header and following data */
} __attribute__((packed)) blobheader;

#define BLOB_FLAG_ENCRYPTED_256BIT_KEY   0x08  /* 256 bit file key was used */

static unsigned char *g_ivec;

static TPM_RESULT SWTPM_NVRAM_GetFilenameForName(char *filename,
                                                 size_t bufsize,
                                                  uint32_t tpm_number,
                                                 const char *name,
                                                 bool is_tempfile);

static TPM_RESULT SWTPM_NVRAM_EncryptData(const encryptionkey *key,
                                          tlv_data *td,
                                          size_t *td_len,
                                          uint16_t tag_encrypted_data,
                                          const unsigned char *decrypt_data,
                                          uint32_t decrypt_length,
                                          uint16_t tag_ivec);

static TPM_RESULT SWTPM_NVRAM_GetDecryptedData(const encryptionkey *key,
                                               unsigned char **decrypt_data,
                                               uint32_t *decrypt_length,
                                               const unsigned char *encrypt_data,
                                               uint32_t encrypt_length,
                                               uint16_t tag_decryped_data,
                                               uint16_t tag_data,
                                               uint8_t hdrversion,
                                               uint16_t tag_ivec,
                                               uint16_t hdrflags,
                                               uint16_t flag_256bitkey);

static TPM_RESULT SWTPM_NVRAM_PrependHeader(unsigned char **data,
                                            uint32_t *length,
                                            uint16_t flags);

static TPM_RESULT SWTPM_NVRAM_CheckHeader(unsigned char *data, uint32_t length,
                                          uint32_t *dataoffset,
                                          uint16_t *hdrflags,
                                          uint8_t *hdrversion,
                                          bool quiet);

static int lockfile_fd = -1;

char state_directory[FILENAME_MAX];


void SWTPM_NVRAM_Set_TPMVersion(TPMLIB_TPMVersion version)
{
    tpmversion = version;
}

typedef struct {
    uint8_t  version;
    uint8_t  min_version; /* min. required version */
    uint16_t hdrsize;
    uint16_t flags;
    uint32_t totlen; /* length of the header and following data */
} __attribute__((packed)) blobheader;

static TPMLIB_TPMVersion tpmversion = TPMLIB_TPM_VERSION_1_2;


TPM_RESULT SWTPM_NVRAM_SetStateBlob(unsigned char *data,
                                    uint32_t length,
                                    TPM_BOOL is_encrypted,
                                    uint32_t tpm_number,
                                    uint32_t blobtype)
{
    TPM_RESULT res;
    uint32_t dataoffset;
    unsigned char *plain = NULL, *mig_decrypt = NULL;
    uint32_t plain_len = 0, mig_decrypt_len = 0;
    uint16_t hdrflags;
    enum TPMLIB_StateType st = tpmlib_blobtype_to_statetype(blobtype);
    const char *blobname = tpmlib_get_blobname(blobtype);
    uint8_t hdrversion;

    if (st == 0) {
        logprintf(STDERR_FILENO,
                  "Unknown blob type %u\n", blobtype);
        return TPM_BAD_PARAMETER;
    }

    if (length == 0)
        return TPMLIB_SetState(st, NULL, 0);

    res = SWTPM_NVRAM_CheckHeader(data, length, &dataoffset, &hdrflags,
                                  &hdrversion, false);
    if (res != TPM_SUCCESS)
        return res;

    if (length - dataoffset == 0)
        return TPMLIB_SetState(st, NULL, 0);

    /*
     * We allow setting of blobs that were not encrypted before;
     * we just will not decrypt them even if the migration key is
     * set. This allows to 'upgrade' to encryption. 'Downgrading'
     * will not be possible once a migration key was used.
     */
    if ((hdrflags & BLOB_FLAG_MIGRATION_ENCRYPTED)) {
        /*
         * we first need to decrypt the data with the migration key
         */
        if (!SWTPM_NVRAM_Has_MigrationKey()) {
            logprintf(STDERR_FILENO,
                      "Missing migration key to decrypt %s\n", blobname);
            return TPM_KEYNOTFOUND;
        }

        res = SWTPM_NVRAM_DecryptData(&migrationkey,
                                      &mig_decrypt, &mig_decrypt_len,
                                      &data[dataoffset], length - dataoffset,
                                      TAG_ENCRYPTED_MIGRATION_DATA,
                                      hdrversion,
                                      TAG_IVEC_ENCRYPTED_MIGRATION_DATA,
                                      hdrflags, BLOB_FLAG_MIGRATION_256BIT_KEY);
        if (res) {
            logprintf(STDERR_FILENO,
                      "Decrypting the %s blob with the migration key failed; "
                      "res = %d\n", blobname, res);
            return res;
        }
    } else {
        res = SWTPM_NVRAM_GetPlainData(&mig_decrypt, &mig_decrypt_len,
                                       &data[dataoffset], length - dataoffset,
                                       TAG_MIGRATION_DATA,
                                       hdrversion);
        if (res)
            return res;
    }

    /*
     * Migration key has decrytped the data; if they are still encrypted
     * with the state encryption key, we need to decrypt them using that
     * key now.
     */
    if (is_encrypted || (hdrflags & BLOB_FLAG_ENCRYPTED)) {
        if (!SWTPM_NVRAM_Has_FileKey()) {
            logprintf(STDERR_FILENO,
                      "Missing state key to decrypt %s\n", blobname);
            res = TPM_KEYNOTFOUND;
            goto cleanup;
        }

        res = SWTPM_NVRAM_DecryptData(&filekey, &plain, &plain_len,
                                      mig_decrypt, mig_decrypt_len,
                                      TAG_ENCRYPTED_DATA,
                                      hdrversion, TAG_IVEC_ENCRYPTED_DATA,
                                      hdrflags, BLOB_FLAG_ENCRYPTED_256BIT_KEY);
        if (res) {
            logprintf(STDERR_FILENO,
                      "Decrypting the %s blob with the state key "
                      "failed; res = %d\n", blobname, res);
            goto cleanup;
        }
    } else {
        res = SWTPM_NVRAM_GetPlainData(&plain, &plain_len,
                                       mig_decrypt, mig_decrypt_len,
                                       TAG_DATA,
                                       hdrversion);
        if (res)
            goto cleanup;
    }

    /* SetState will make a copy of the buffer */
    res = TPMLIB_SetState(st, plain, plain_len);

    free(plain);

cleanup:
    free(mig_decrypt);

    return res;
}

typedef struct {
    uint8_t  version;
    uint8_t  min_version; /* min. required version */
    uint16_t hdrsize;
    uint16_t flags;
    uint32_t totlen; /* length of the header and following data */
} __attribute__((packed)) blobheader;

#define BLOB_FLAG_ENCRYPTED              0x01

#define BLOB_FLAG_MIGRATION_ENCRYPTED    0x02  /* encrypted with migration key */

#define BLOB_FLAG_MIGRATION_DATA         0x04  /* migration data are available */

#define BLOB_FLAG_ENCRYPTED_256BIT_KEY   0x08  /* 256 bit file key was used */

#define BLOB_FLAG_MIGRATION_256BIT_KEY   0x10  /* 256 bit migration key was used */

typedef struct {
    enum encryption_mode data_encmode;
    TPM_SYMMETRIC_KEY_DATA symkey;
} encryptionkey ;

static encryptionkey filekey = {
    .symkey = {
        .userKeyLength = 0,
    },
};

static encryptionkey migrationkey = {
    .symkey = {
        .userKeyLength = 0,
    },
};

static uint32_t g_ivec_length;

static unsigned char *g_ivec;

static TPM_RESULT SWTPM_NVRAM_GetFilenameForName(char *filename,
                                                 size_t bufsize,
                                                  uint32_t tpm_number,
                                                 const char *name,
                                                 bool is_tempfile);

static TPM_RESULT SWTPM_NVRAM_EncryptData(const encryptionkey *key,
                                          tlv_data *td,
                                          size_t *td_len,
                                          uint16_t tag_encrypted_data,
                                          const unsigned char *decrypt_data,
                                          uint32_t decrypt_length,
                                          uint16_t tag_ivec);

static TPM_RESULT SWTPM_NVRAM_GetDecryptedData(const encryptionkey *key,
                                               unsigned char **decrypt_data,
                                               uint32_t *decrypt_length,
                                               const unsigned char *encrypt_data,
                                               uint32_t encrypt_length,
                                               uint16_t tag_decryped_data,
                                               uint16_t tag_data,
                                               uint8_t hdrversion,
                                               uint16_t tag_ivec,
                                               uint16_t hdrflags,
                                               uint16_t flag_256bitkey);

static TPM_RESULT SWTPM_NVRAM_PrependHeader(unsigned char **data,
                                            uint32_t *length,
                                            uint16_t flags);

static TPM_RESULT SWTPM_NVRAM_CheckHeader(unsigned char *data, uint32_t length,
                                          uint32_t *dataoffset,
                                          uint16_t *hdrflags,
                                          uint8_t *hdrversion,
                                          bool quiet);

char state_directory[FILENAME_MAX];


SWTPM_CalcHMAC(const unsigned char *in, uint32_t in_length,
               tlv_data *td,
               const TPM_SYMMETRIC_KEY_DATA *tpm_symmetric_key_token,
               const unsigned char *ivec, uint32_t ivec_length)
{
    TPM_RESULT rc = 0;
    unsigned int md_len;
    unsigned char md[EVP_MAX_MD_SIZE];
    unsigned char *buffer = NULL;

    if (!SWTPM_HMAC(md, &md_len,
                    tpm_symmetric_key_token->userKey,
                    tpm_symmetric_key_token->userKeyLength,
                    in, in_length, ivec, ivec_length)) {
        logprintf(STDOUT_FILENO, "HMAC calculation failed.\n");
        return TPM_FAIL;
    }

    buffer = malloc(md_len);

    if (buffer) {
        *td = TLV_DATA(TAG_HMAC, md_len, buffer);
        memcpy(buffer, md, md_len);
    } else {
       logprintf(STDOUT_FILENO,
                 "Could not allocate %u bytes.\n", md_len);
       rc = TPM_FAIL;
    }

    return rc;
}

typedef struct {
    uint8_t  version;
    uint8_t  min_version; /* min. required version */
    uint16_t hdrsize;
    uint16_t flags;
    uint32_t totlen; /* length of the header and following data */
} __attribute__((packed)) blobheader;

typedef struct {
    enum encryption_mode data_encmode;
    TPM_SYMMETRIC_KEY_DATA symkey;
} encryptionkey ;

static encryptionkey filekey = {
    .symkey = {
        .userKeyLength = 0,
    },
};

static encryptionkey migrationkey = {
    .symkey = {
        .userKeyLength = 0,
    },
};

static uint32_t g_ivec_length;

static unsigned char *g_ivec;

static TPM_RESULT SWTPM_NVRAM_GetFilenameForName(char *filename,
                                                 size_t bufsize,
                                                  uint32_t tpm_number,
                                                 const char *name,
                                                 bool is_tempfile);

static TPM_RESULT SWTPM_NVRAM_EncryptData(const encryptionkey *key,
                                          tlv_data *td,
                                          size_t *td_len,
                                          uint16_t tag_encrypted_data,
                                          const unsigned char *decrypt_data,
                                          uint32_t decrypt_length,
                                          uint16_t tag_ivec);

static TPM_RESULT SWTPM_NVRAM_GetDecryptedData(const encryptionkey *key,
                                               unsigned char **decrypt_data,
                                               uint32_t *decrypt_length,
                                               const unsigned char *encrypt_data,
                                               uint32_t encrypt_length,
                                               uint16_t tag_decryped_data,
                                               uint16_t tag_data,
                                               uint8_t hdrversion,
                                               uint16_t tag_ivec,
                                               uint16_t hdrflags,
                                               uint16_t flag_256bitkey);

static TPM_RESULT SWTPM_NVRAM_PrependHeader(unsigned char **data,
                                            uint32_t *length,
                                            uint16_t flags);

static TPM_RESULT SWTPM_NVRAM_CheckHeader(unsigned char *data, uint32_t length,
                                          uint32_t *dataoffset,
                                          uint16_t *hdrflags,
                                          uint8_t *hdrversion,
                                          bool quiet);

static int lockfile_fd = -1;

char state_directory[FILENAME_MAX];


static TPM_RESULT SWTPM_NVRAM_GetFilenameForName(char *filename,        /* output: rooted filename */
                                                 size_t bufsize,
                                                 uint32_t tpm_number,
                                                 const char *name,      /* input: abstract name */
                                                 bool is_tempfile)      /* input: is temporary file? */
{
    TPM_RESULT res = TPM_SUCCESS;
    int n;
    const char *suffix = "";

    TPM_DEBUG(" SWTPM_NVRAM_GetFilenameForName: For name %s\n", name);

    switch (tpmversion) {
    case TPMLIB_TPM_VERSION_1_2:
        break;
    case TPMLIB_TPM_VERSION_2:
        suffix = "2";
        break;
    }

    if (is_tempfile) {
        n = snprintf(filename, bufsize, "%s/TMP%s-%02lx.%s",
                     state_directory, suffix, (unsigned long)tpm_number, name);
    } else {
        n = snprintf(filename, bufsize, "%s/tpm%s-%02lx.%s",
                     state_directory, suffix, (unsigned long)tpm_number, name);
    }
    if ((size_t)n > bufsize) {
        res = TPM_FAIL;
    }

    TPM_DEBUG("  SWTPM_NVRAM_GetFilenameForName: File name %s\n", filename);

    return res;
}

typedef struct {
    uint8_t  version;
    uint8_t  min_version; /* min. required version */
    uint16_t hdrsize;
    uint16_t flags;
    uint32_t totlen; /* length of the header and following data */
} __attribute__((packed)) blobheader;

#define BLOB_FLAG_ENCRYPTED_256BIT_KEY   0x08  /* 256 bit file key was used */

static encryptionkey filekey = {
    .symkey = {
        .userKeyLength = 0,
    },
};

static encryptionkey migrationkey = {
    .symkey = {
        .userKeyLength = 0,
    },
};

static uint32_t g_ivec_length;

static unsigned char *g_ivec;

static TPM_RESULT SWTPM_NVRAM_GetFilenameForName(char *filename,
                                                 size_t bufsize,
                                                  uint32_t tpm_number,
                                                 const char *name,
                                                 bool is_tempfile);

static TPM_RESULT SWTPM_NVRAM_EncryptData(const encryptionkey *key,
                                          tlv_data *td,
                                          size_t *td_len,
                                          uint16_t tag_encrypted_data,
                                          const unsigned char *decrypt_data,
                                          uint32_t decrypt_length,
                                          uint16_t tag_ivec);

static TPM_RESULT SWTPM_NVRAM_GetDecryptedData(const encryptionkey *key,
                                               unsigned char **decrypt_data,
                                               uint32_t *decrypt_length,
                                               const unsigned char *encrypt_data,
                                               uint32_t encrypt_length,
                                               uint16_t tag_decryped_data,
                                               uint16_t tag_data,
                                               uint8_t hdrversion,
                                               uint16_t tag_ivec,
                                               uint16_t hdrflags,
                                               uint16_t flag_256bitkey);

static TPM_RESULT SWTPM_NVRAM_PrependHeader(unsigned char **data,
                                            uint32_t *length,
                                            uint16_t flags);

static TPM_RESULT SWTPM_NVRAM_CheckHeader(unsigned char *data, uint32_t length,
                                          uint32_t *dataoffset,
                                          uint16_t *hdrflags,
                                          uint8_t *hdrversion,
                                          bool quiet);

static int lockfile_fd = -1;

char state_directory[FILENAME_MAX];

static TPMLIB_TPMVersion tpmversion = TPMLIB_TPM_VERSION_1_2;


TPM_RESULT SWTPM_NVRAM_DeleteName(uint32_t tpm_number,
                                  const char *name,
                                  TPM_BOOL mustExist)
{
    TPM_RESULT  rc = 0;
    int         irc;
    char        filename[FILENAME_MAX]; /* rooted file name from name */

    TPM_DEBUG(" SWTPM_NVRAM_DeleteName: Name %s\n", name);
    /* map name to the rooted filename */
    rc = SWTPM_NVRAM_GetFilenameForName(filename, sizeof(filename),
                                        tpm_number, name, false);
    if (rc == 0) {
        irc = remove(filename);
        if ((irc != 0) &&               /* if the remove failed */
            (mustExist ||               /* if any error is a failure, or */
             (errno != ENOENT))) {      /* if error other than no such file */
            logprintf(STDERR_FILENO,
                      "SWTPM_NVRAM_DeleteName: Error, (fatal) file "
                      "remove failed, errno %d\n", errno);
            rc = TPM_FAIL;
        }
    }
    return rc;
}

typedef struct {
    uint8_t  version;
    uint8_t  min_version; /* min. required version */
    uint16_t hdrsize;
    uint16_t flags;
    uint32_t totlen; /* length of the header and following data */
} __attribute__((packed)) blobheader;

#define BLOB_FLAG_ENCRYPTED_256BIT_KEY   0x08  /* 256 bit file key was used */

static uint32_t g_ivec_length;

static unsigned char *g_ivec;

static TPM_RESULT SWTPM_NVRAM_GetFilenameForName(char *filename,
                                                 size_t bufsize,
                                                  uint32_t tpm_number,
                                                 const char *name,
                                                 bool is_tempfile);

static TPM_RESULT SWTPM_NVRAM_EncryptData(const encryptionkey *key,
                                          tlv_data *td,
                                          size_t *td_len,
                                          uint16_t tag_encrypted_data,
                                          const unsigned char *decrypt_data,
                                          uint32_t decrypt_length,
                                          uint16_t tag_ivec);

static TPM_RESULT SWTPM_NVRAM_GetDecryptedData(const encryptionkey *key,
                                               unsigned char **decrypt_data,
                                               uint32_t *decrypt_length,
                                               const unsigned char *encrypt_data,
                                               uint32_t encrypt_length,
                                               uint16_t tag_decryped_data,
                                               uint16_t tag_data,
                                               uint8_t hdrversion,
                                               uint16_t tag_ivec,
                                               uint16_t hdrflags,
                                               uint16_t flag_256bitkey);

static TPM_RESULT SWTPM_NVRAM_PrependHeader(unsigned char **data,
                                            uint32_t *length,
                                            uint16_t flags);

static TPM_RESULT SWTPM_NVRAM_CheckHeader(unsigned char *data, uint32_t length,
                                          uint32_t *dataoffset,
                                          uint16_t *hdrflags,
                                          uint8_t *hdrversion,
                                          bool quiet);

static int lockfile_fd = -1;

char state_directory[FILENAME_MAX];


static TPM_RESULT SWTPM_NVRAM_Lock_Lockfile(const char *directory,
                                            int *fd)
{
    TPM_RESULT rc = 0;
    char *lockfile = NULL;
    struct flock flock = {
        .l_type = F_WRLCK,
        .l_whence = SEEK_SET,
        .l_start = 0,
        .l_len = 0,
    };

    if (asprintf(&lockfile, "%s/.lock", directory) < 0) {
        logprintf(STDERR_FILENO,
                  "SWTPM_NVRAM_Lock_Lockfile: Could not asprintf lock filename\n");
        return TPM_FAIL;
    }

    *fd = open(lockfile, O_WRONLY|O_CREAT|O_TRUNC|O_NOFOLLOW, 0660);
    if (*fd < 0) {
        logprintf(STDERR_FILENO,
                  "SWTPM_NVRAM_Lock_Lockfile: Could not open lockfile: %s\n",
                  strerror(errno));
        rc = TPM_FAIL;
        goto exit;
    }

    if (fcntl(*fd, F_SETLK, &flock) < 0) {
        logprintf(STDERR_FILENO,
                  "SWTPM_NVRAM_Lock_Lockfile: Could not lock access to lockfile: %s\n",
                  strerror(errno));
        rc = TPM_FAIL;
        close(*fd);
        *fd = -1;
    }
exit:
    free(lockfile);

    return rc;
}

typedef struct {
    uint8_t  version;
    uint8_t  min_version; /* min. required version */
    uint16_t hdrsize;
    uint16_t flags;
    uint32_t totlen; /* length of the header and following data */
} __attribute__((packed)) blobheader;

typedef struct {
    enum encryption_mode data_encmode;
    TPM_SYMMETRIC_KEY_DATA symkey;
} encryptionkey ;

static encryptionkey filekey = {
    .symkey = {
        .userKeyLength = 0,
    },
};

static encryptionkey migrationkey = {
    .symkey = {
        .userKeyLength = 0,
    },
};

static uint32_t g_ivec_length;

static unsigned char *g_ivec;

static TPM_RESULT SWTPM_NVRAM_GetFilenameForName(char *filename,
                                                 size_t bufsize,
                                                  uint32_t tpm_number,
                                                 const char *name,
                                                 bool is_tempfile);

static TPM_RESULT SWTPM_NVRAM_EncryptData(const encryptionkey *key,
                                          tlv_data *td,
                                          size_t *td_len,
                                          uint16_t tag_encrypted_data,
                                          const unsigned char *decrypt_data,
                                          uint32_t decrypt_length,
                                          uint16_t tag_ivec);

static TPM_RESULT SWTPM_NVRAM_GetDecryptedData(const encryptionkey *key,
                                               unsigned char **decrypt_data,
                                               uint32_t *decrypt_length,
                                               const unsigned char *encrypt_data,
                                               uint32_t encrypt_length,
                                               uint16_t tag_decryped_data,
                                               uint16_t tag_data,
                                               uint8_t hdrversion,
                                               uint16_t tag_ivec,
                                               uint16_t hdrflags,
                                               uint16_t flag_256bitkey);

static TPM_RESULT SWTPM_NVRAM_PrependHeader(unsigned char **data,
                                            uint32_t *length,
                                            uint16_t flags);

static TPM_RESULT SWTPM_NVRAM_CheckHeader(unsigned char *data, uint32_t length,
                                          uint32_t *dataoffset,
                                          uint16_t *hdrflags,
                                          uint8_t *hdrversion,
                                          bool quiet);

static int lockfile_fd = -1;

char state_directory[FILENAME_MAX];

static TPMLIB_TPMVersion tpmversion = TPMLIB_TPM_VERSION_1_2;


static void mode_init_ov_sensor_regs(struct sd *sd)
{
	struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
	int qvga, xstart, xend, ystart, yend;
	u8 v;

	qvga = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv & 1;

	/******** Mode (VGA/QVGA) and sensor specific regs ********/
	switch (sd->sensor) {
	case SEN_OV2610:
		i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20);
		i2c_w_mask(sd, 0x28, qvga ? 0x00 : 0x20, 0x20);
		i2c_w(sd, 0x24, qvga ? 0x20 : 0x3a);
		i2c_w(sd, 0x25, qvga ? 0x30 : 0x60);
		i2c_w_mask(sd, 0x2d, qvga ? 0x40 : 0x00, 0x40);
		i2c_w_mask(sd, 0x67, qvga ? 0xf0 : 0x90, 0xf0);
		i2c_w_mask(sd, 0x74, qvga ? 0x20 : 0x00, 0x20);
		return;
	case SEN_OV2610AE: {
		u8 v;

		/* frame rates:
		 *	10fps / 5 fps for 1600x1200
		 *	40fps / 20fps for 800x600
		 */
		v = 80;
		if (qvga) {
			if (sd->frame_rate < 25)
				v = 0x81;
		} else {
			if (sd->frame_rate < 10)
				v = 0x81;
		}
		i2c_w(sd, 0x11, v);
		i2c_w(sd, 0x12, qvga ? 0x60 : 0x20);
		return;
	    }
	case SEN_OV3610:
		if (qvga) {
			xstart = (1040 - gspca_dev->pixfmt.width) / 2 +
				(0x1f << 4);
			ystart = (776 - gspca_dev->pixfmt.height) / 2;
		} else {
			xstart = (2076 - gspca_dev->pixfmt.width) / 2 +
				(0x10 << 4);
			ystart = (1544 - gspca_dev->pixfmt.height) / 2;
		}
		xend = xstart + gspca_dev->pixfmt.width;
		yend = ystart + gspca_dev->pixfmt.height;
		/* Writing to the COMH register resets the other windowing regs
		   to their default values, so we must do this first. */
		i2c_w_mask(sd, 0x12, qvga ? 0x40 : 0x00, 0xf0);
		i2c_w_mask(sd, 0x32,
			   (((xend >> 1) & 7) << 3) | ((xstart >> 1) & 7),
			   0x3f);
		i2c_w_mask(sd, 0x03,
			   (((yend >> 1) & 3) << 2) | ((ystart >> 1) & 3),
			   0x0f);
		i2c_w(sd, 0x17, xstart >> 4);
		i2c_w(sd, 0x18, xend >> 4);
		i2c_w(sd, 0x19, ystart >> 3);
		i2c_w(sd, 0x1a, yend >> 3);
		return;
	case SEN_OV8610:
		/* For OV8610 qvga means qsvga */
		i2c_w_mask(sd, OV7610_REG_COM_C, qvga ? (1 << 5) : 0, 1 << 5);
		i2c_w_mask(sd, 0x13, 0x00, 0x20); /* Select 16 bit data bus */
		i2c_w_mask(sd, 0x12, 0x04, 0x06); /* AWB: 1 Test pattern: 0 */
		i2c_w_mask(sd, 0x2d, 0x00, 0x40); /* from windrv 090403 */
		i2c_w_mask(sd, 0x28, 0x20, 0x20); /* progressive mode on */
		break;
	case SEN_OV7610:
		i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20);
		i2c_w(sd, 0x35, qvga ? 0x1e : 0x9e);
		i2c_w_mask(sd, 0x13, 0x00, 0x20); /* Select 16 bit data bus */
		i2c_w_mask(sd, 0x12, 0x04, 0x06); /* AWB: 1 Test pattern: 0 */
		break;
	case SEN_OV7620:
	case SEN_OV7620AE:
	case SEN_OV76BE:
		i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20);
		i2c_w_mask(sd, 0x28, qvga ? 0x00 : 0x20, 0x20);
		i2c_w(sd, 0x24, qvga ? 0x20 : 0x3a);
		i2c_w(sd, 0x25, qvga ? 0x30 : 0x60);
		i2c_w_mask(sd, 0x2d, qvga ? 0x40 : 0x00, 0x40);
		i2c_w_mask(sd, 0x67, qvga ? 0xb0 : 0x90, 0xf0);
		i2c_w_mask(sd, 0x74, qvga ? 0x20 : 0x00, 0x20);
		i2c_w_mask(sd, 0x13, 0x00, 0x20); /* Select 16 bit data bus */
		i2c_w_mask(sd, 0x12, 0x04, 0x06); /* AWB: 1 Test pattern: 0 */
		if (sd->sensor == SEN_OV76BE)
			i2c_w(sd, 0x35, qvga ? 0x1e : 0x9e);
		break;
	case SEN_OV7640:
	case SEN_OV7648:
		i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20);
		i2c_w_mask(sd, 0x28, qvga ? 0x00 : 0x20, 0x20);
		/* Setting this undocumented bit in qvga mode removes a very
		   annoying vertical shaking of the image */
		i2c_w_mask(sd, 0x2d, qvga ? 0x40 : 0x00, 0x40);
		/* Unknown */
		i2c_w_mask(sd, 0x67, qvga ? 0xf0 : 0x90, 0xf0);
		/* Allow higher automatic gain (to allow higher framerates) */
		i2c_w_mask(sd, 0x74, qvga ? 0x20 : 0x00, 0x20);
		i2c_w_mask(sd, 0x12, 0x04, 0x04); /* AWB: 1 */
		break;
	case SEN_OV7670:
		/* set COM7_FMT_VGA or COM7_FMT_QVGA
		 * do we need to set anything else?
		 *	HSTART etc are set in set_ov_sensor_window itself */
		i2c_w_mask(sd, OV7670_R12_COM7,
			 qvga ? OV7670_COM7_FMT_QVGA : OV7670_COM7_FMT_VGA,
			 OV7670_COM7_FMT_MASK);
		i2c_w_mask(sd, 0x13, 0x00, 0x20); /* Select 16 bit data bus */
		i2c_w_mask(sd, OV7670_R13_COM8, OV7670_COM8_AWB,
				OV7670_COM8_AWB);
		if (qvga) {		/* QVGA from ov7670.c by
					 * Jonathan Corbet */
			xstart = 164;
			xend = 28;
			ystart = 14;
			yend = 494;
		} else {		/* VGA */
			xstart = 158;
			xend = 14;
			ystart = 10;
			yend = 490;
		}
		/* OV7670 hardware window registers are split across
		 * multiple locations */
		i2c_w(sd, OV7670_R17_HSTART, xstart >> 3);
		i2c_w(sd, OV7670_R18_HSTOP, xend >> 3);
		v = i2c_r(sd, OV7670_R32_HREF);
		v = (v & 0xc0) | ((xend & 0x7) << 3) | (xstart & 0x07);
		msleep(10);	/* need to sleep between read and write to
				 * same reg! */
		i2c_w(sd, OV7670_R32_HREF, v);

		i2c_w(sd, OV7670_R19_VSTART, ystart >> 2);
		i2c_w(sd, OV7670_R1A_VSTOP, yend >> 2);
		v = i2c_r(sd, OV7670_R03_VREF);
		v = (v & 0xc0) | ((yend & 0x3) << 2) | (ystart & 0x03);
		msleep(10);	/* need to sleep between read and write to
				 * same reg! */
		i2c_w(sd, OV7670_R03_VREF, v);
		break;
	case SEN_OV6620:
		i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20);
		i2c_w_mask(sd, 0x13, 0x00, 0x20); /* Select 16 bit data bus */
		i2c_w_mask(sd, 0x12, 0x04, 0x06); /* AWB: 1 Test pattern: 0 */
		break;
	case SEN_OV6630:
	case SEN_OV66308AF:
		i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20);
		i2c_w_mask(sd, 0x12, 0x04, 0x06); /* AWB: 1 Test pattern: 0 */
		break;
	case SEN_OV9600: {
		const struct ov_i2c_regvals *vals;
		static const struct ov_i2c_regvals sxga_15[] = {
			{0x11, 0x80}, {0x14, 0x3e}, {0x24, 0x85}, {0x25, 0x75}
		};
		static const struct ov_i2c_regvals sxga_7_5[] = {
			{0x11, 0x81}, {0x14, 0x3e}, {0x24, 0x85}, {0x25, 0x75}
		};
		static const struct ov_i2c_regvals vga_30[] = {
			{0x11, 0x81}, {0x14, 0x7e}, {0x24, 0x70}, {0x25, 0x60}
		};
		static const struct ov_i2c_regvals vga_15[] = {
			{0x11, 0x83}, {0x14, 0x3e}, {0x24, 0x80}, {0x25, 0x70}
		};

		/* frame rates:
		 *	15fps / 7.5 fps for 1280x1024
		 *	30fps / 15fps for 640x480
		 */
		i2c_w_mask(sd, 0x12, qvga ? 0x40 : 0x00, 0x40);
		if (qvga)
			vals = sd->frame_rate < 30 ? vga_15 : vga_30;
		else
			vals = sd->frame_rate < 15 ? sxga_7_5 : sxga_15;
		write_i2c_regvals(sd, vals, ARRAY_SIZE(sxga_15));
		return;
	    }
	default:
		return;
	}

	/******** Clock programming ********/
	i2c_w(sd, 0x11, sd->clockdiv);
}

media: ov519: add missing endpoint sanity checks

Make sure to check that we have at least one endpoint before accessing
the endpoint array to avoid dereferencing a NULL-pointer on stream
start.

Note that these sanity checks are not redundant as the driver is mixing
looking up altsettings by index and by number, which need not coincide.

Fixes: 1876bb923c98 ("V4L/DVB (12079): gspca_ov519: add support for the ov511 bridge")
Fixes: b282d87332f5 ("V4L/DVB (12080): gspca_ov519: Fix ov518+ with OV7620AE (Trust spacecam 320)")
Cc: stable <stable@vger.kernel.org>     # 2.6.31
Cc: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Johan Hovold <johan@kernel.org>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>

static int frame_rate;

static int i2c_detect_tries = 10;

struct sd {
	struct gspca_dev gspca_dev;		/* !! must be the first item */

	struct v4l2_ctrl *jpegqual;
	struct v4l2_ctrl *freq;
	struct { /* h/vflip control cluster */
		struct v4l2_ctrl *hflip;
		struct v4l2_ctrl *vflip;
	};
	struct { /* autobrightness/brightness control cluster */
		struct v4l2_ctrl *autobright;
		struct v4l2_ctrl *brightness;
	};

	u8 revision;

	u8 packet_nr;

	char bridge;
#define BRIDGE_OV511		0
#define BRIDGE_OV511PLUS	1
#define BRIDGE_OV518		2
#define BRIDGE_OV518PLUS	3
#define BRIDGE_OV519		4		/* = ov530 */
#define BRIDGE_OVFX2		5
#define BRIDGE_W9968CF		6
#define BRIDGE_MASK		7

	char invert_led;
#define BRIDGE_INVERT_LED	8

	char snapshot_pressed;
	char snapshot_needs_reset;

	/* Determined by sensor type */
	u8 sif;

#define QUALITY_MIN 50
#define QUALITY_MAX 70
#define QUALITY_DEF 50

	u8 stopped;		/* Streaming is temporarily paused */
	u8 first_frame;

	u8 frame_rate;		/* current Framerate */
	u8 clockdiv;		/* clockdiv override */

	s8 sensor;		/* Type of image sensor chip (SEN_*) */

	u8 sensor_addr;
	u16 sensor_width;
	u16 sensor_height;
	s16 sensor_reg_cache[256];

	u8 jpeg_hdr[JPEG_HDR_SZ];
}

enum sensors {
	SEN_OV2610,
	SEN_OV2610AE,
	SEN_OV3610,
	SEN_OV6620,
	SEN_OV6630,
	SEN_OV66308AF,
	SEN_OV7610,
	SEN_OV7620,
	SEN_OV7620AE,
	SEN_OV7640,
	SEN_OV7648,
	SEN_OV7660,
	SEN_OV7670,
	SEN_OV76BE,
	SEN_OV8610,
	SEN_OV9600,
}

struct ctrl_valid {
	unsigned int has_brightness:1;
	unsigned int has_contrast:1;
	unsigned int has_exposure:1;
	unsigned int has_autogain:1;
	unsigned int has_sat:1;
	unsigned int has_hvflip:1;
	unsigned int has_autobright:1;
	unsigned int has_freq:1;
}


static void ov511_pkt_scan(struct gspca_dev *gspca_dev,
			u8 *in,			/* isoc packet */
			int len)		/* iso packet length */
{
	struct sd *sd = (struct sd *) gspca_dev;

	/* SOF/EOF packets have 1st to 8th bytes zeroed and the 9th
	 * byte non-zero. The EOF packet has image width/height in the
	 * 10th and 11th bytes. The 9th byte is given as follows:
	 *
	 * bit 7: EOF
	 *     6: compression enabled
	 *     5: 422/420/400 modes
	 *     4: 422/420/400 modes
	 *     3: 1
	 *     2: snapshot button on
	 *     1: snapshot frame
	 *     0: even/odd field
	 */
	if (!(in[0] | in[1] | in[2] | in[3] | in[4] | in[5] | in[6] | in[7]) &&
	    (in[8] & 0x08)) {
		ov51x_handle_button(gspca_dev, (in[8] >> 2) & 1);
		if (in[8] & 0x80) {
			/* Frame end */
			if ((in[9] + 1) * 8 != gspca_dev->pixfmt.width ||
			    (in[10] + 1) * 8 != gspca_dev->pixfmt.height) {
				gspca_err(gspca_dev, "Invalid frame size, got: %dx%d, requested: %dx%d\n",
					  (in[9] + 1) * 8, (in[10] + 1) * 8,
					  gspca_dev->pixfmt.width,
					  gspca_dev->pixfmt.height);
				gspca_dev->last_packet_type = DISCARD_PACKET;
				return;
			}
			/* Add 11 byte footer to frame, might be useful */
			gspca_frame_add(gspca_dev, LAST_PACKET, in, 11);
			return;
		} else {
			/* Frame start */
			gspca_frame_add(gspca_dev, FIRST_PACKET, in, 0);
			sd->packet_nr = 0;
		}
	}

	/* Ignore the packet number */
	len--;

	/* intermediate packet */
	gspca_frame_add(gspca_dev, INTER_PACKET, in, len);
}

static int frame_rate;

static int i2c_detect_tries = 10;

struct sd {
	struct gspca_dev gspca_dev;		/* !! must be the first item */

	struct v4l2_ctrl *jpegqual;
	struct v4l2_ctrl *freq;
	struct { /* h/vflip control cluster */
		struct v4l2_ctrl *hflip;
		struct v4l2_ctrl *vflip;
	};
	struct { /* autobrightness/brightness control cluster */
		struct v4l2_ctrl *autobright;
		struct v4l2_ctrl *brightness;
	};

	u8 revision;

	u8 packet_nr;

	char bridge;
#define BRIDGE_OV511		0
#define BRIDGE_OV511PLUS	1
#define BRIDGE_OV518		2
#define BRIDGE_OV518PLUS	3
#define BRIDGE_OV519		4		/* = ov530 */
#define BRIDGE_OVFX2		5
#define BRIDGE_W9968CF		6
#define BRIDGE_MASK		7

	char invert_led;
#define BRIDGE_INVERT_LED	8

	char snapshot_pressed;
	char snapshot_needs_reset;

	/* Determined by sensor type */
	u8 sif;

#define QUALITY_MIN 50
#define QUALITY_MAX 70
#define QUALITY_DEF 50

	u8 stopped;		/* Streaming is temporarily paused */
	u8 first_frame;

	u8 frame_rate;		/* current Framerate */
	u8 clockdiv;		/* clockdiv override */

	s8 sensor;		/* Type of image sensor chip (SEN_*) */

	u8 sensor_addr;
	u16 sensor_width;
	u16 sensor_height;
	s16 sensor_reg_cache[256];

	u8 jpeg_hdr[JPEG_HDR_SZ];
}

struct ctrl_valid {
	unsigned int has_brightness:1;
	unsigned int has_contrast:1;
	unsigned int has_exposure:1;
	unsigned int has_autogain:1;
	unsigned int has_sat:1;
	unsigned int has_hvflip:1;
	unsigned int has_autobright:1;
	unsigned int has_freq:1;
}


static int reg_r8(struct sd *sd,
		  u16 index)
{
	struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
	int ret;

	if (sd->gspca_dev.usb_err < 0)
		return -1;

	/* Avoid things going to fast for the bridge with a xhci host */
	udelay(150);
	ret = usb_control_msg(sd->gspca_dev.dev,
			usb_rcvctrlpipe(sd->gspca_dev.dev, 0),
			1,			/* REQ_IO */
			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
			0, index, sd->gspca_dev.usb_buf, 8, 500);

	if (ret >= 0) {
		ret = sd->gspca_dev.usb_buf[0];
	} else {
		gspca_err(gspca_dev, "reg_r8 %02x failed %d\n", index, ret);
		sd->gspca_dev.usb_err = ret;
		/*
		 * Make sure the buffer is zeroed to avoid uninitialized
		 * values.
		 */
		memset(gspca_dev->usb_buf, 0, 8);
	}

	return ret;
}


static void ov519_pkt_scan(struct gspca_dev *gspca_dev,
			u8 *data,			/* isoc packet */
			int len)			/* iso packet length */
{
	/* Header of ov519 is 16 bytes:
	 *     Byte     Value      Description
	 *	0	0xff	magic
	 *	1	0xff	magic
	 *	2	0xff	magic
	 *	3	0xXX	0x50 = SOF, 0x51 = EOF
	 *	9	0xXX	0x01 initial frame without data,
	 *			0x00 standard frame with image
	 *	14	Lo	in EOF: length of image data / 8
	 *	15	Hi
	 */

	if (data[0] == 0xff && data[1] == 0xff && data[2] == 0xff) {
		switch (data[3]) {
		case 0x50:		/* start of frame */
			/* Don't check the button state here, as the state
			   usually (always ?) changes at EOF and checking it
			   here leads to unnecessary snapshot state resets. */
#define HDRSZ 16
			data += HDRSZ;
			len -= HDRSZ;
#undef HDRSZ
			if (data[0] == 0xff || data[1] == 0xd8)
				gspca_frame_add(gspca_dev, FIRST_PACKET,
						data, len);
			else
				gspca_dev->last_packet_type = DISCARD_PACKET;
			return;
		case 0x51:		/* end of frame */
			ov51x_handle_button(gspca_dev, data[11] & 1);
			if (data[9] != 0)
				gspca_dev->last_packet_type = DISCARD_PACKET;
			gspca_frame_add(gspca_dev, LAST_PACKET,
					NULL, 0);
			return;
		}
	}

	/* intermediate packet */
	gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
}

#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt

#define MODULE_NAME "ov519"

#define CONEX_CAM

static int frame_rate;

static int i2c_detect_tries = 10;

struct sd {
	struct gspca_dev gspca_dev;		/* !! must be the first item */

	struct v4l2_ctrl *jpegqual;
	struct v4l2_ctrl *freq;
	struct { /* h/vflip control cluster */
		struct v4l2_ctrl *hflip;
		struct v4l2_ctrl *vflip;
	};
	struct { /* autobrightness/brightness control cluster */
		struct v4l2_ctrl *autobright;
		struct v4l2_ctrl *brightness;
	};

	u8 revision;

	u8 packet_nr;

	char bridge;
#define BRIDGE_OV511		0
#define BRIDGE_OV511PLUS	1
#define BRIDGE_OV518		2
#define BRIDGE_OV518PLUS	3
#define BRIDGE_OV519		4		/* = ov530 */
#define BRIDGE_OVFX2		5
#define BRIDGE_W9968CF		6
#define BRIDGE_MASK		7

	char invert_led;
#define BRIDGE_INVERT_LED	8

	char snapshot_pressed;
	char snapshot_needs_reset;

	/* Determined by sensor type */
	u8 sif;

#define QUALITY_MIN 50
#define QUALITY_MAX 70
#define QUALITY_DEF 50

	u8 stopped;		/* Streaming is temporarily paused */
	u8 first_frame;

	u8 frame_rate;		/* current Framerate */
	u8 clockdiv;		/* clockdiv override */

	s8 sensor;		/* Type of image sensor chip (SEN_*) */

	u8 sensor_addr;
	u16 sensor_width;
	u16 sensor_height;
	s16 sensor_reg_cache[256];

	u8 jpeg_hdr[JPEG_HDR_SZ];
}

struct ctrl_valid {
	unsigned int has_brightness:1;
	unsigned int has_contrast:1;
	unsigned int has_exposure:1;
	unsigned int has_autogain:1;
	unsigned int has_sat:1;
	unsigned int has_hvflip:1;
	unsigned int has_autobright:1;
	unsigned int has_freq:1;
}


static void i2c_w_mask(struct sd *sd,
			u8 reg,
			u8 value,
			u8 mask)
{
	int rc;
	u8 oldval;

	value &= mask;			/* Enforce mask on value */
	rc = i2c_r(sd, reg);
	if (rc < 0)
		return;
	oldval = rc & ~mask;		/* Clear the masked bits */
	value |= oldval;		/* Set the desired bits */
	i2c_w(sd, reg, value);
}


static void ov51x_handle_button(struct gspca_dev *gspca_dev, u8 state)
{
	struct sd *sd = (struct sd *) gspca_dev;

	if (sd->snapshot_pressed != state) {
#if IS_ENABLED(CONFIG_INPUT)
		input_report_key(gspca_dev->input_dev, KEY_CAMERA, state);
		input_sync(gspca_dev->input_dev);
#endif
		if (state)
			sd->snapshot_needs_reset = 1;

		sd->snapshot_pressed = state;
	} else {
		/* On the ov511 / ov519 we need to reset the button state
		   multiple times, as resetting does not work as long as the
		   button stays pressed */
		switch (sd->bridge) {
		case BRIDGE_OV511:
		case BRIDGE_OV511PLUS:
		case BRIDGE_OV519:
			if (state)
				sd->snapshot_needs_reset = 1;
			break;
		}
	}
}

#define MODULE_NAME "ov519"

static int frame_rate;

static int i2c_detect_tries = 10;

struct sd {
	struct gspca_dev gspca_dev;		/* !! must be the first item */

	struct v4l2_ctrl *jpegqual;
	struct v4l2_ctrl *freq;
	struct { /* h/vflip control cluster */
		struct v4l2_ctrl *hflip;
		struct v4l2_ctrl *vflip;
	};
	struct { /* autobrightness/brightness control cluster */
		struct v4l2_ctrl *autobright;
		struct v4l2_ctrl *brightness;
	};

	u8 revision;

	u8 packet_nr;

	char bridge;
#define BRIDGE_OV511		0
#define BRIDGE_OV511PLUS	1
#define BRIDGE_OV518		2
#define BRIDGE_OV518PLUS	3
#define BRIDGE_OV519		4		/* = ov530 */
#define BRIDGE_OVFX2		5
#define BRIDGE_W9968CF		6
#define BRIDGE_MASK		7

	char invert_led;
#define BRIDGE_INVERT_LED	8

	char snapshot_pressed;
	char snapshot_needs_reset;

	/* Determined by sensor type */
	u8 sif;

#define QUALITY_MIN 50
#define QUALITY_MAX 70
#define QUALITY_DEF 50

	u8 stopped;		/* Streaming is temporarily paused */
	u8 first_frame;

	u8 frame_rate;		/* current Framerate */
	u8 clockdiv;		/* clockdiv override */

	s8 sensor;		/* Type of image sensor chip (SEN_*) */

	u8 sensor_addr;
	u16 sensor_width;
	u16 sensor_height;
	s16 sensor_reg_cache[256];

	u8 jpeg_hdr[JPEG_HDR_SZ];
}

struct ctrl_valid {
	unsigned int has_brightness:1;
	unsigned int has_contrast:1;
	unsigned int has_exposure:1;
	unsigned int has_autogain:1;
	unsigned int has_sat:1;
	unsigned int has_hvflip:1;
	unsigned int has_autobright:1;
	unsigned int has_freq:1;
}


static void ov519_set_fr(struct sd *sd)
{
	int fr;
	u8 clock;
	/* frame rate table with indices:
	 *	- mode = 0: 320x240, 1: 640x480
	 *	- fr rate = 0: 30, 1: 25, 2: 20, 3: 15, 4: 10, 5: 5
	 *	- reg = 0: bridge a4, 1: bridge 23, 2: sensor 11 (clock)
	 */
	static const u8 fr_tb[2][6][3] = {
		{{0x04, 0xff, 0x00},
		 {0x04, 0x1f, 0x00},
		 {0x04, 0x1b, 0x00},
		 {0x04, 0x15, 0x00},
		 {0x04, 0x09, 0x00},
		 {0x04, 0x01, 0x00}},
		{{0x0c, 0xff, 0x00},
		 {0x0c, 0x1f, 0x00},
		 {0x0c, 0x1b, 0x00},
		 {0x04, 0xff, 0x01},
		 {0x04, 0x1f, 0x01},
		 {0x04, 0x1b, 0x01}},
	};

	if (frame_rate > 0)
		sd->frame_rate = frame_rate;
	if (sd->frame_rate >= 30)
		fr = 0;
	else if (sd->frame_rate >= 25)
		fr = 1;
	else if (sd->frame_rate >= 20)
		fr = 2;
	else if (sd->frame_rate >= 15)
		fr = 3;
	else if (sd->frame_rate >= 10)
		fr = 4;
	else
		fr = 5;
	reg_w(sd, 0xa4, fr_tb[sd->gspca_dev.curr_mode][fr][0]);
	reg_w(sd, 0x23, fr_tb[sd->gspca_dev.curr_mode][fr][1]);
	clock = fr_tb[sd->gspca_dev.curr_mode][fr][2];
	if (sd->sensor == SEN_OV7660)
		clock |= 0x80;		/* enable double clock */
	ov518_i2c_w(sd, OV7670_R11_CLKRC, clock);
}


static int sd_init_controls(struct gspca_dev *gspca_dev)
{
	struct sd *sd = (struct sd *)gspca_dev;
	struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;

	gspca_dev->vdev.ctrl_handler = hdl;
	v4l2_ctrl_handler_init(hdl, 10);
	if (valid_controls[sd->sensor].has_brightness)
		sd->brightness = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
			V4L2_CID_BRIGHTNESS, 0,
			sd->sensor == SEN_OV7660 ? 6 : 255, 1,
			sd->sensor == SEN_OV7660 ? 3 : 127);
	if (valid_controls[sd->sensor].has_contrast) {
		if (sd->sensor == SEN_OV7660)
			v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
				V4L2_CID_CONTRAST, 0, 6, 1, 3);
		else
			v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
				V4L2_CID_CONTRAST, 0, 255, 1,
				(sd->sensor == SEN_OV6630 ||
				 sd->sensor == SEN_OV66308AF) ? 200 : 127);
	}
	if (valid_controls[sd->sensor].has_sat)
		v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
			V4L2_CID_SATURATION, 0,
			sd->sensor == SEN_OV7660 ? 4 : 255, 1,
			sd->sensor == SEN_OV7660 ? 2 : 127);
	if (valid_controls[sd->sensor].has_exposure)
		gspca_dev->exposure = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
			V4L2_CID_EXPOSURE, 0, 255, 1, 127);
	if (valid_controls[sd->sensor].has_hvflip) {
		sd->hflip = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
			V4L2_CID_HFLIP, 0, 1, 1, 0);
		sd->vflip = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
			V4L2_CID_VFLIP, 0, 1, 1, 0);
	}
	if (valid_controls[sd->sensor].has_autobright)
		sd->autobright = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
			V4L2_CID_AUTOBRIGHTNESS, 0, 1, 1, 1);
	if (valid_controls[sd->sensor].has_autogain)
		gspca_dev->autogain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
			V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
	if (valid_controls[sd->sensor].has_freq) {
		if (sd->sensor == SEN_OV7670)
			sd->freq = v4l2_ctrl_new_std_menu(hdl, &sd_ctrl_ops,
				V4L2_CID_POWER_LINE_FREQUENCY,
				V4L2_CID_POWER_LINE_FREQUENCY_AUTO, 0,
				V4L2_CID_POWER_LINE_FREQUENCY_AUTO);
		else
			sd->freq = v4l2_ctrl_new_std_menu(hdl, &sd_ctrl_ops,
				V4L2_CID_POWER_LINE_FREQUENCY,
				V4L2_CID_POWER_LINE_FREQUENCY_60HZ, 0, 0);
	}
	if (sd->bridge == BRIDGE_W9968CF)
		sd->jpegqual = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
			V4L2_CID_JPEG_COMPRESSION_QUALITY,
			QUALITY_MIN, QUALITY_MAX, 1, QUALITY_DEF);

	if (hdl->error) {
		gspca_err(gspca_dev, "Could not initialize controls\n");
		return hdl->error;
	}
	if (gspca_dev->autogain)
		v4l2_ctrl_auto_cluster(3, &gspca_dev->autogain, 0, true);
	if (sd->autobright)
		v4l2_ctrl_auto_cluster(2, &sd->autobright, 0, false);
	if (sd->hflip)
		v4l2_ctrl_cluster(2, &sd->hflip);
	return 0;
}


static void ov518_mode_init_regs(struct sd *sd)
{
	struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
	int hsegs, vsegs, packet_size;
	struct usb_host_interface *alt;
	struct usb_interface *intf;

	intf = usb_ifnum_to_if(sd->gspca_dev.dev, sd->gspca_dev.iface);
	alt = usb_altnum_to_altsetting(intf, sd->gspca_dev.alt);
	if (!alt) {
		gspca_err(gspca_dev, "Couldn't get altsetting\n");
		sd->gspca_dev.usb_err = -EIO;
		return;
	}

	if (alt->desc.bNumEndpoints < 1) {
		sd->gspca_dev.usb_err = -ENODEV;
		return;
	}

	packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize);
	ov518_reg_w32(sd, R51x_FIFO_PSIZE, packet_size & ~7, 2);

	/******** Set the mode ********/
	reg_w(sd, 0x2b, 0);
	reg_w(sd, 0x2c, 0);
	reg_w(sd, 0x2d, 0);
	reg_w(sd, 0x2e, 0);
	reg_w(sd, 0x3b, 0);
	reg_w(sd, 0x3c, 0);
	reg_w(sd, 0x3d, 0);
	reg_w(sd, 0x3e, 0);

	if (sd->bridge == BRIDGE_OV518) {
		/* Set 8-bit (YVYU) input format */
		reg_w_mask(sd, 0x20, 0x08, 0x08);

		/* Set 12-bit (4:2:0) output format */
		reg_w_mask(sd, 0x28, 0x80, 0xf0);
		reg_w_mask(sd, 0x38, 0x80, 0xf0);
	} else {
		reg_w(sd, 0x28, 0x80);
		reg_w(sd, 0x38, 0x80);
	}

	hsegs = sd->gspca_dev.pixfmt.width / 16;
	vsegs = sd->gspca_dev.pixfmt.height / 4;

	reg_w(sd, 0x29, hsegs);
	reg_w(sd, 0x2a, vsegs);

	reg_w(sd, 0x39, hsegs);
	reg_w(sd, 0x3a, vsegs);

	/* Windows driver does this here; who knows why */
	reg_w(sd, 0x2f, 0x80);

	/******** Set the framerate ********/
	if (sd->bridge == BRIDGE_OV518PLUS && sd->revision == 0 &&
					      sd->sensor == SEN_OV7620AE)
		sd->clockdiv = 0;
	else
		sd->clockdiv = 1;

	/* Mode independent, but framerate dependent, regs */
	/* 0x51: Clock divider; Only works on some cams which use 2 crystals */
	reg_w(sd, 0x51, 0x04);
	reg_w(sd, 0x22, 0x18);
	reg_w(sd, 0x23, 0xff);

	if (sd->bridge == BRIDGE_OV518PLUS) {
		switch (sd->sensor) {
		case SEN_OV7620AE:
			/*
			 * HdG: 640x480 needs special handling on device
			 * revision 2, we check for device revision > 0 to
			 * avoid regressions, as we don't know the correct
			 * thing todo for revision 1.
			 *
			 * Also this likely means we don't need to
			 * differentiate between the OV7620 and OV7620AE,
			 * earlier testing hitting this same problem likely
			 * happened to be with revision < 2 cams using an
			 * OV7620 and revision 2 cams using an OV7620AE.
			 */
			if (sd->revision > 0 &&
					sd->gspca_dev.pixfmt.width == 640) {
				reg_w(sd, 0x20, 0x60);
				reg_w(sd, 0x21, 0x1f);
			} else {
				reg_w(sd, 0x20, 0x00);
				reg_w(sd, 0x21, 0x19);
			}
			break;
		case SEN_OV7620:
			reg_w(sd, 0x20, 0x00);
			reg_w(sd, 0x21, 0x19);
			break;
		default:
			reg_w(sd, 0x21, 0x19);
		}
	} else
		reg_w(sd, 0x71, 0x17);	/* Compression-related? */

	/* FIXME: Sensor-specific */
	/* Bit 5 is what matters here. Of course, it is "reserved" */
	i2c_w(sd, 0x54, 0x23);

	reg_w(sd, 0x2f, 0x80);

	if (sd->bridge == BRIDGE_OV518PLUS) {
		reg_w(sd, 0x24, 0x94);
		reg_w(sd, 0x25, 0x90);
		ov518_reg_w32(sd, 0xc4,    400, 2);	/* 190h   */
		ov518_reg_w32(sd, 0xc6,    540, 2);	/* 21ch   */
		ov518_reg_w32(sd, 0xc7,    540, 2);	/* 21ch   */
		ov518_reg_w32(sd, 0xc8,    108, 2);	/* 6ch    */
		ov518_reg_w32(sd, 0xca, 131098, 3);	/* 2001ah */
		ov518_reg_w32(sd, 0xcb,    532, 2);	/* 214h   */
		ov518_reg_w32(sd, 0xcc,   2400, 2);	/* 960h   */
		ov518_reg_w32(sd, 0xcd,     32, 2);	/* 20h    */
		ov518_reg_w32(sd, 0xce,    608, 2);	/* 260h   */
	} else {
		reg_w(sd, 0x24, 0x9f);
		reg_w(sd, 0x25, 0x90);
		ov518_reg_w32(sd, 0xc4,    400, 2);	/* 190h   */
		ov518_reg_w32(sd, 0xc6,    381, 2);	/* 17dh   */
		ov518_reg_w32(sd, 0xc7,    381, 2);	/* 17dh   */
		ov518_reg_w32(sd, 0xc8,    128, 2);	/* 80h    */
		ov518_reg_w32(sd, 0xca, 183331, 3);	/* 2cc23h */
		ov518_reg_w32(sd, 0xcb,    746, 2);	/* 2eah   */
		ov518_reg_w32(sd, 0xcc,   1750, 2);	/* 6d6h   */
		ov518_reg_w32(sd, 0xcd,     45, 2);	/* 2dh    */
		ov518_reg_w32(sd, 0xce,    851, 2);	/* 353h   */
	}

	reg_w(sd, 0x2f, 0x80);
}


static void sethvflip(struct gspca_dev *gspca_dev, s32 hflip, s32 vflip)
{
	struct sd *sd = (struct sd *) gspca_dev;

	if (sd->gspca_dev.streaming)
		reg_w(sd, OV519_R51_RESET1, 0x0f);	/* block stream */
	i2c_w_mask(sd, OV7670_R1E_MVFP,
		OV7670_MVFP_MIRROR * hflip | OV7670_MVFP_VFLIP * vflip,
		OV7670_MVFP_MIRROR | OV7670_MVFP_VFLIP);
	if (sd->gspca_dev.streaming)
		reg_w(sd, OV519_R51_RESET1, 0x00);	/* restart stream */
}


static void ov6xx0_configure(struct sd *sd)
{
	struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
	int rc;

	gspca_dbg(gspca_dev, D_PROBE, "starting OV6xx0 configuration\n");

	/* Detect sensor (sub)type */
	rc = i2c_r(sd, OV7610_REG_COM_I);
	if (rc < 0) {
		gspca_err(gspca_dev, "Error detecting sensor type\n");
		return;
	}

	/* Ugh. The first two bits are the version bits, but
	 * the entire register value must be used. I guess OVT
	 * underestimated how many variants they would make. */
	switch (rc) {
	case 0x00:
		sd->sensor = SEN_OV6630;
		pr_warn("WARNING: Sensor is an OV66308. Your camera may have been misdetected in previous driver versions.\n");
		break;
	case 0x01:
		sd->sensor = SEN_OV6620;
		gspca_dbg(gspca_dev, D_PROBE, "Sensor is an OV6620\n");
		break;
	case 0x02:
		sd->sensor = SEN_OV6630;
		gspca_dbg(gspca_dev, D_PROBE, "Sensor is an OV66308AE\n");
		break;
	case 0x03:
		sd->sensor = SEN_OV66308AF;
		gspca_dbg(gspca_dev, D_PROBE, "Sensor is an OV66308AF\n");
		break;
	case 0x90:
		sd->sensor = SEN_OV6630;
		pr_warn("WARNING: Sensor is an OV66307. Your camera may have been misdetected in previous driver versions.\n");
		break;
	default:
		gspca_err(gspca_dev, "FATAL: Unknown sensor version: 0x%02x\n",
			  rc);
		return;
	}

	/* Set sensor-specific vars */
	sd->sif = 1;
}


static void write_regvals(struct sd *sd,
			 const struct ov_regvals *regvals,
			 int n)
{
	while (--n >= 0) {
		reg_w(sd, regvals->reg, regvals->val);
		regvals++;
	}
}


static void ov519_mode_init_regs(struct sd *sd)
{
	static const struct ov_regvals mode_init_519_ov7670[] = {
		{ 0x5d,	0x03 }, /* Turn off suspend mode */
		{ 0x53,	0x9f }, /* was 9b in 1.65-1.08 */
		{ OV519_R54_EN_CLK1, 0x0f }, /* bit2 (jpeg enable) */
		{ 0xa2,	0x20 }, /* a2-a5 are undocumented */
		{ 0xa3,	0x18 },
		{ 0xa4,	0x04 },
		{ 0xa5,	0x28 },
		{ 0x37,	0x00 },	/* SetUsbInit */
		{ 0x55,	0x02 }, /* 4.096 Mhz audio clock */
		/* Enable both fields, YUV Input, disable defect comp (why?) */
		{ 0x20,	0x0c },
		{ 0x21,	0x38 },
		{ 0x22,	0x1d },
		{ 0x17,	0x50 }, /* undocumented */
		{ 0x37,	0x00 }, /* undocumented */
		{ 0x40,	0xff }, /* I2C timeout counter */
		{ 0x46,	0x00 }, /* I2C clock prescaler */
		{ 0x59,	0x04 },	/* new from windrv 090403 */
		{ 0xff,	0x00 }, /* undocumented */
		/* windows reads 0x55 at this point, why? */
	};

	static const struct ov_regvals mode_init_519[] = {
		{ 0x5d,	0x03 }, /* Turn off suspend mode */
		{ 0x53,	0x9f }, /* was 9b in 1.65-1.08 */
		{ OV519_R54_EN_CLK1, 0x0f }, /* bit2 (jpeg enable) */
		{ 0xa2,	0x20 }, /* a2-a5 are undocumented */
		{ 0xa3,	0x18 },
		{ 0xa4,	0x04 },
		{ 0xa5,	0x28 },
		{ 0x37,	0x00 },	/* SetUsbInit */
		{ 0x55,	0x02 }, /* 4.096 Mhz audio clock */
		/* Enable both fields, YUV Input, disable defect comp (why?) */
		{ 0x22,	0x1d },
		{ 0x17,	0x50 }, /* undocumented */
		{ 0x37,	0x00 }, /* undocumented */
		{ 0x40,	0xff }, /* I2C timeout counter */
		{ 0x46,	0x00 }, /* I2C clock prescaler */
		{ 0x59,	0x04 },	/* new from windrv 090403 */
		{ 0xff,	0x00 }, /* undocumented */
		/* windows reads 0x55 at this point, why? */
	};

	struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;

	/******** Set the mode ********/
	switch (sd->sensor) {
	default:
		write_regvals(sd, mode_init_519, ARRAY_SIZE(mode_init_519));
		if (sd->sensor == SEN_OV7640 ||
		    sd->sensor == SEN_OV7648) {
			/* Select 8-bit input mode */
			reg_w_mask(sd, OV519_R20_DFR, 0x10, 0x10);
		}
		break;
	case SEN_OV7660:
		return;		/* done by ov519_set_mode/fr() */
	case SEN_OV7670:
		write_regvals(sd, mode_init_519_ov7670,
				ARRAY_SIZE(mode_init_519_ov7670));
		break;
	}

	reg_w(sd, OV519_R10_H_SIZE,	sd->gspca_dev.pixfmt.width >> 4);
	reg_w(sd, OV519_R11_V_SIZE,	sd->gspca_dev.pixfmt.height >> 3);
	if (sd->sensor == SEN_OV7670 &&
	    sd->gspca_dev.cam.cam_mode[sd->gspca_dev.curr_mode].priv)
		reg_w(sd, OV519_R12_X_OFFSETL, 0x04);
	else if (sd->sensor == SEN_OV7648 &&
	    sd->gspca_dev.cam.cam_mode[sd->gspca_dev.curr_mode].priv)
		reg_w(sd, OV519_R12_X_OFFSETL, 0x01);
	else
		reg_w(sd, OV519_R12_X_OFFSETL, 0x00);
	reg_w(sd, OV519_R13_X_OFFSETH,	0x00);
	reg_w(sd, OV519_R14_Y_OFFSETL,	0x00);
	reg_w(sd, OV519_R15_Y_OFFSETH,	0x00);
	reg_w(sd, OV519_R16_DIVIDER,	0x00);
	reg_w(sd, OV519_R25_FORMAT,	0x03); /* YUV422 */
	reg_w(sd, 0x26,			0x00); /* Undocumented */

	/******** Set the framerate ********/
	if (frame_rate > 0)
		sd->frame_rate = frame_rate;

/* FIXME: These are only valid at the max resolution. */
	sd->clockdiv = 0;
	switch (sd->sensor) {
	case SEN_OV7640:
	case SEN_OV7648:
		switch (sd->frame_rate) {
		default:
/*		case 30: */
			reg_w(sd, 0xa4, 0x0c);
			reg_w(sd, 0x23, 0xff);
			break;
		case 25:
			reg_w(sd, 0xa4, 0x0c);
			reg_w(sd, 0x23, 0x1f);
			break;
		case 20:
			reg_w(sd, 0xa4, 0x0c);
			reg_w(sd, 0x23, 0x1b);
			break;
		case 15:
			reg_w(sd, 0xa4, 0x04);
			reg_w(sd, 0x23, 0xff);
			sd->clockdiv = 1;
			break;
		case 10:
			reg_w(sd, 0xa4, 0x04);
			reg_w(sd, 0x23, 0x1f);
			sd->clockdiv = 1;
			break;
		case 5:
			reg_w(sd, 0xa4, 0x04);
			reg_w(sd, 0x23, 0x1b);
			sd->clockdiv = 1;
			break;
		}
		break;
	case SEN_OV8610:
		switch (sd->frame_rate) {
		default:	/* 15 fps */
/*		case 15: */
			reg_w(sd, 0xa4, 0x06);
			reg_w(sd, 0x23, 0xff);
			break;
		case 10:
			reg_w(sd, 0xa4, 0x06);
			reg_w(sd, 0x23, 0x1f);
			break;
		case 5:
			reg_w(sd, 0xa4, 0x06);
			reg_w(sd, 0x23, 0x1b);
			break;
		}
		break;
	case SEN_OV7670:		/* guesses, based on 7640 */
		gspca_dbg(gspca_dev, D_STREAM, "Setting framerate to %d fps\n",
			  (sd->frame_rate == 0) ? 15 : sd->frame_rate);
		reg_w(sd, 0xa4, 0x10);
		switch (sd->frame_rate) {
		case 30:
			reg_w(sd, 0x23, 0xff);
			break;
		case 20:
			reg_w(sd, 0x23, 0x1b);
			break;
		default:
/*		case 15: */
			reg_w(sd, 0x23, 0xff);
			sd->clockdiv = 1;
			break;
		}
		break;
	}
}


static void ov51x_led_control(struct sd *sd, int on)
{
	if (sd->invert_led)
		on = !on;

	switch (sd->bridge) {
	/* OV511 has no LED control */
	case BRIDGE_OV511PLUS:
		reg_w(sd, R511_SYS_LED_CTL, on);
		break;
	case BRIDGE_OV518:
	case BRIDGE_OV518PLUS:
		reg_w_mask(sd, R518_GPIO_OUT, 0x02 * on, 0x02);
		break;
	case BRIDGE_OV519:
		reg_w_mask(sd, OV519_GPIO_DATA_OUT0, on, 1);
		break;
	}
}


static void setautobright(struct gspca_dev *gspca_dev, s32 val)
{
	struct sd *sd = (struct sd *) gspca_dev;

	i2c_w_mask(sd, 0x2d, val ? 0x10 : 0x00, 0x10);
}


static int ov518_i2c_r(struct sd *sd, u8 reg)
{
	struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
	int value;

	/* Select camera register */
	reg_w(sd, R51x_I2C_SADDR_2, reg);

	/* Initiate 2-byte write cycle */
	reg_w(sd, R518_I2C_CTL, 0x03);
	reg_r8(sd, R518_I2C_CTL);

	/* Initiate 2-byte read cycle */
	reg_w(sd, R518_I2C_CTL, 0x05);
	reg_r8(sd, R518_I2C_CTL);

	value = reg_r(sd, R51x_I2C_DATA);
	gspca_dbg(gspca_dev, D_USBI, "ov518_i2c_r %02x %02x\n", reg, value);
	return value;
}


static int ovfx2_i2c_r(struct sd *sd, u8 reg)
{
	struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
	int ret;

	if (sd->gspca_dev.usb_err < 0)
		return -1;

	ret = usb_control_msg(sd->gspca_dev.dev,
			usb_rcvctrlpipe(sd->gspca_dev.dev, 0),
			0x03,
			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
			0, (u16) reg, sd->gspca_dev.usb_buf, 1, 500);

	if (ret >= 0) {
		ret = sd->gspca_dev.usb_buf[0];
		gspca_dbg(gspca_dev, D_USBI, "ovfx2_i2c_r %02x %02x\n",
			  reg, ret);
	} else {
		gspca_err(gspca_dev, "ovfx2_i2c_r %02x failed %d\n", reg, ret);
		sd->gspca_dev.usb_err = ret;
	}

	return ret;
}


static void ov518_configure(struct gspca_dev *gspca_dev)
{
	struct sd *sd = (struct sd *) gspca_dev;

	/* For 518 and 518+ */
	static const struct ov_regvals init_518[] = {
		{ R51x_SYS_RESET,	0x40 },
		{ R51x_SYS_INIT,	0xe1 },
		{ R51x_SYS_RESET,	0x3e },
		{ R51x_SYS_INIT,	0xe1 },
		{ R51x_SYS_RESET,	0x00 },
		{ R51x_SYS_INIT,	0xe1 },
		{ 0x46,			0x00 },
		{ 0x5d,			0x03 },
	};

	static const struct ov_regvals norm_518[] = {
		{ R51x_SYS_SNAP,	0x02 }, /* Reset */
		{ R51x_SYS_SNAP,	0x01 }, /* Enable */
		{ 0x31,			0x0f },
		{ 0x5d,			0x03 },
		{ 0x24,			0x9f },
		{ 0x25,			0x90 },
		{ 0x20,			0x00 },
		{ 0x51,			0x04 },
		{ 0x71,			0x19 },
		{ 0x2f,			0x80 },
	};

	static const struct ov_regvals norm_518_p[] = {
		{ R51x_SYS_SNAP,	0x02 }, /* Reset */
		{ R51x_SYS_SNAP,	0x01 }, /* Enable */
		{ 0x31,			0x0f },
		{ 0x5d,			0x03 },
		{ 0x24,			0x9f },
		{ 0x25,			0x90 },
		{ 0x20,			0x60 },
		{ 0x51,			0x02 },
		{ 0x71,			0x19 },
		{ 0x40,			0xff },
		{ 0x41,			0x42 },
		{ 0x46,			0x00 },
		{ 0x33,			0x04 },
		{ 0x21,			0x19 },
		{ 0x3f,			0x10 },
		{ 0x2f,			0x80 },
	};

	/* First 5 bits of custom ID reg are a revision ID on OV518 */
	sd->revision = reg_r(sd, R51x_SYS_CUST_ID) & 0x1f;
	gspca_dbg(gspca_dev, D_PROBE, "Device revision %d\n", sd->revision);

	write_regvals(sd, init_518, ARRAY_SIZE(init_518));

	/* Set LED GPIO pin to output mode */
	reg_w_mask(sd, R518_GPIO_CTL, 0x00, 0x02);

	switch (sd->bridge) {
	case BRIDGE_OV518:
		write_regvals(sd, norm_518, ARRAY_SIZE(norm_518));
		break;
	case BRIDGE_OV518PLUS:
		write_regvals(sd, norm_518_p, ARRAY_SIZE(norm_518_p));
		break;
	}

	ov51x_upload_quan_tables(sd);

	reg_w(sd, 0x2f, 0x80);
}


static int sd_init(struct gspca_dev *gspca_dev)
{
	struct sd *sd = (struct sd *) gspca_dev;
	struct cam *cam = &gspca_dev->cam;

	switch (sd->bridge) {
	case BRIDGE_OV511:
	case BRIDGE_OV511PLUS:
		ov511_configure(gspca_dev);
		break;
	case BRIDGE_OV518:
	case BRIDGE_OV518PLUS:
		ov518_configure(gspca_dev);
		break;
	case BRIDGE_OV519:
		ov519_configure(sd);
		break;
	case BRIDGE_OVFX2:
		ovfx2_configure(sd);
		break;
	case BRIDGE_W9968CF:
		w9968cf_configure(sd);
		break;
	}

	/* The OV519 must be more aggressive about sensor detection since
	 * I2C write will never fail if the sensor is not present. We have
	 * to try to initialize the sensor to detect its presence */
	sd->sensor = -1;

	/* Test for 76xx */
	if (init_ov_sensor(sd, OV7xx0_SID) >= 0) {
		ov7xx0_configure(sd);

	/* Test for 6xx0 */
	} else if (init_ov_sensor(sd, OV6xx0_SID) >= 0) {
		ov6xx0_configure(sd);

	/* Test for 8xx0 */
	} else if (init_ov_sensor(sd, OV8xx0_SID) >= 0) {
		ov8xx0_configure(sd);

	/* Test for 3xxx / 2xxx */
	} else if (init_ov_sensor(sd, OV_HIRES_SID) >= 0) {
		ov_hires_configure(sd);
	} else {
		gspca_err(gspca_dev, "Can't determine sensor slave IDs\n");
		goto error;
	}

	if (sd->sensor < 0)
		goto error;

	ov51x_led_control(sd, 0);	/* turn LED off */

	switch (sd->bridge) {
	case BRIDGE_OV511:
	case BRIDGE_OV511PLUS:
		if (sd->sif) {
			cam->cam_mode = ov511_sif_mode;
			cam->nmodes = ARRAY_SIZE(ov511_sif_mode);
		}
		break;
	case BRIDGE_OV518:
	case BRIDGE_OV518PLUS:
		if (sd->sif) {
			cam->cam_mode = ov518_sif_mode;
			cam->nmodes = ARRAY_SIZE(ov518_sif_mode);
		}
		break;
	case BRIDGE_OV519:
		if (sd->sif) {
			cam->cam_mode = ov519_sif_mode;
			cam->nmodes = ARRAY_SIZE(ov519_sif_mode);
		}
		break;
	case BRIDGE_OVFX2:
		switch (sd->sensor) {
		case SEN_OV2610:
		case SEN_OV2610AE:
			cam->cam_mode = ovfx2_ov2610_mode;
			cam->nmodes = ARRAY_SIZE(ovfx2_ov2610_mode);
			break;
		case SEN_OV3610:
			cam->cam_mode = ovfx2_ov3610_mode;
			cam->nmodes = ARRAY_SIZE(ovfx2_ov3610_mode);
			break;
		case SEN_OV9600:
			cam->cam_mode = ovfx2_ov9600_mode;
			cam->nmodes = ARRAY_SIZE(ovfx2_ov9600_mode);
			break;
		default:
			if (sd->sif) {
				cam->cam_mode = ov519_sif_mode;
				cam->nmodes = ARRAY_SIZE(ov519_sif_mode);
			}
			break;
		}
		break;
	case BRIDGE_W9968CF:
		if (sd->sif)
			cam->nmodes = ARRAY_SIZE(w9968cf_vga_mode) - 1;

		/* w9968cf needs initialisation once the sensor is known */
		w9968cf_init(sd);
		break;
	}

	/* initialize the sensor */
	switch (sd->sensor) {
	case SEN_OV2610:
		write_i2c_regvals(sd, norm_2610, ARRAY_SIZE(norm_2610));

		/* Enable autogain, autoexpo, awb, bandfilter */
		i2c_w_mask(sd, 0x13, 0x27, 0x27);
		break;
	case SEN_OV2610AE:
		write_i2c_regvals(sd, norm_2610ae, ARRAY_SIZE(norm_2610ae));

		/* enable autoexpo */
		i2c_w_mask(sd, 0x13, 0x05, 0x05);
		break;
	case SEN_OV3610:
		write_i2c_regvals(sd, norm_3620b, ARRAY_SIZE(norm_3620b));

		/* Enable autogain, autoexpo, awb, bandfilter */
		i2c_w_mask(sd, 0x13, 0x27, 0x27);
		break;
	case SEN_OV6620:
		write_i2c_regvals(sd, norm_6x20, ARRAY_SIZE(norm_6x20));
		break;
	case SEN_OV6630:
	case SEN_OV66308AF:
		write_i2c_regvals(sd, norm_6x30, ARRAY_SIZE(norm_6x30));
		break;
	default:
/*	case SEN_OV7610: */
/*	case SEN_OV76BE: */
		write_i2c_regvals(sd, norm_7610, ARRAY_SIZE(norm_7610));
		i2c_w_mask(sd, 0x0e, 0x00, 0x40);
		break;
	case SEN_OV7620:
	case SEN_OV7620AE:
		write_i2c_regvals(sd, norm_7620, ARRAY_SIZE(norm_7620));
		break;
	case SEN_OV7640:
	case SEN_OV7648:
		write_i2c_regvals(sd, norm_7640, ARRAY_SIZE(norm_7640));
		break;
	case SEN_OV7660:
		i2c_w(sd, OV7670_R12_COM7, OV7670_COM7_RESET);
		msleep(14);
		reg_w(sd, OV519_R57_SNAPSHOT, 0x23);
		write_regvals(sd, init_519_ov7660,
				ARRAY_SIZE(init_519_ov7660));
		write_i2c_regvals(sd, norm_7660, ARRAY_SIZE(norm_7660));
		sd->gspca_dev.curr_mode = 1;	/* 640x480 */
		ov519_set_mode(sd);
		ov519_set_fr(sd);
		sd_reset_snapshot(gspca_dev);
		ov51x_restart(sd);
		ov51x_stop(sd);			/* not in win traces */
		ov51x_led_control(sd, 0);
		break;
	case SEN_OV7670:
		write_i2c_regvals(sd, norm_7670, ARRAY_SIZE(norm_7670));
		break;
	case SEN_OV8610:
		write_i2c_regvals(sd, norm_8610, ARRAY_SIZE(norm_8610));
		break;
	case SEN_OV9600:
		write_i2c_regvals(sd, norm_9600, ARRAY_SIZE(norm_9600));

		/* enable autoexpo */
/*		i2c_w_mask(sd, 0x13, 0x05, 0x05); */
		break;
	}
	return gspca_dev->usb_err;
error:
	gspca_err(gspca_dev, "OV519 Config failed\n");
	return -EINVAL;
}


static int reg_r(struct sd *sd, u16 index)
{
	struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
	int ret;
	int req;

	if (sd->gspca_dev.usb_err < 0)
		return -1;

	switch (sd->bridge) {
	case BRIDGE_OV511:
	case BRIDGE_OV511PLUS:
		req = 3;
		break;
	case BRIDGE_OVFX2:
		req = 0x0b;
		break;
	default:
		req = 1;
	}

	/* Avoid things going to fast for the bridge with a xhci host */
	udelay(150);
	ret = usb_control_msg(sd->gspca_dev.dev,
			usb_rcvctrlpipe(sd->gspca_dev.dev, 0),
			req,
			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
			0, index, sd->gspca_dev.usb_buf, 1, 500);

	if (ret >= 0) {
		ret = sd->gspca_dev.usb_buf[0];
		gspca_dbg(gspca_dev, D_USBI, "GET %02x 0000 %04x %02x\n",
			  req, index, ret);
	} else {
		gspca_err(gspca_dev, "reg_r %02x failed %d\n", index, ret);
		sd->gspca_dev.usb_err = ret;
		/*
		 * Make sure the result is zeroed to avoid uninitialized
		 * values.
		 */
		gspca_dev->usb_buf[0] = 0;
	}

	return ret;
}