예제 #1
0
파일: proto-t1.c 프로젝트: OpenSC/openct
static unsigned int t1_build(t1_state_t * t1, unsigned char *block,
			     unsigned char dad, unsigned char pcb,
			     ct_buf_t * bp, size_t * lenp)
{
	unsigned int len;

	len = bp ? ct_buf_avail(bp) : 0;
	if (len > t1->ifsc) {
		pcb |= T1_MORE_BLOCKS;
		len = t1->ifsc;
	}

	/* Add the sequence number */
	switch (t1_block_type(pcb)) {
	case T1_R_BLOCK:
		pcb |= t1->nr << T1_R_SEQ_SHIFT;
		break;
	case T1_I_BLOCK:
		pcb |= t1->ns << T1_I_SEQ_SHIFT;
		break;
	}

	block[0] = dad;
	block[1] = pcb;
	block[2] = len;

	if (len)
		memcpy(block + 3, ct_buf_head(bp), len);
	if (lenp)
		*lenp = len;

	return t1_compute_checksum(t1, block, len + 3);
}
예제 #2
0
파일: conf.c 프로젝트: OpenSC/openct
/*
 * Eat initial white space from buffer
 */
static int skipws(void)
{
	unsigned int m, n, in_comment = 0;
	char *s;

      again:
	s = (char *)ct_buf_head(&config_buf);
	n = ct_buf_avail(&config_buf);

	for (m = 0; m < n; m++, s++) {
		if (*s == '#') {
			in_comment = 1;
		} else if (!in_comment && !isspace((int)*s)) {
			break;
		} else if (*s == '\n') {
			config_line++;
			in_comment = 0;
		}
	}

	ct_buf_get(&config_buf, NULL, m);
	if (in_comment) {
		if (ct_buf_read(&config_buf, config_fd) < 0) {
			ct_error("%s: error while reading file: %m",
				 config_filename);
			return -1;
		}
		goto again;
	}

	return 0;
}
예제 #3
0
파일: process.c 프로젝트: OpenSC/openct
static int do_transact_old(ifd_reader_t * reader, int unit, ct_buf_t * args,
			   ct_buf_t * resp)
{
	int rc;

	rc = ifd_card_command(reader, unit,
			      ct_buf_head(args), ct_buf_avail(args),
			      ct_buf_tail(resp), ct_buf_tailroom(resp));
	if (rc < 0)
		return rc;

	ct_buf_put(resp, NULL, rc);
	return 0;
}
예제 #4
0
static int t0_send(ifd_protocol_t * prot, ct_buf_t * bp, int count)
{
	int n, avail;

	avail = ct_buf_avail(bp);
	if (count < 0)
		count = avail;
	if (count > avail || !avail)
		return -1;
	n = ifd_send_command(prot, ct_buf_head(bp), count);
	if (n >= 0)
		ct_buf_get(bp, NULL, count);
	return n;
}
예제 #5
0
파일: conf.c 프로젝트: OpenSC/openct
/*
 * Tokenizer
 */
static int get_token(char **tok)
{
	static char buffer[512];
	unsigned int m, n, copy, retry = 1;
	char *s;

	/* consume initial white space */
	if (skipws() < 0)
		return -1;

      again:
	s = (char *)ct_buf_head(&config_buf);
	n = ct_buf_avail(&config_buf);

	if (n && issepa(*s)) {
		m = 1;
	} else {
		for (m = 0; !isspace((int)s[m]) && !issepa(s[m]) && m < n;
		     m++) ;
	}

	/* If we hit the end of the buffer while scanning
	 * for white space, read more data and try 
	 * again */
	if (m >= n && retry) {
		if (ct_buf_read(&config_buf, config_fd) < 0) {
			ct_error("%s: error while reading file: %m",
				 config_filename);
			return -1;
		}
		retry = 0;
		goto again;
	}

	if (m == 0)
		return -1;

	if ((copy = m) >= sizeof(buffer))
		copy = sizeof(buffer) - 1;
	memcpy(buffer, s, copy);
	buffer[copy] = '\0';
	ct_buf_get(&config_buf, NULL, m);

	ifd_debug(5, "ifd_config_parse: token=\"%s\"", buffer);

	*tok = buffer;
	return 0;
}
예제 #6
0
unsigned int t1_build(t1_state_t * t1, unsigned char *block,
	unsigned char dad, unsigned char pcb,
	ct_buf_t *bp, size_t *lenp)
{
	unsigned int len;
	char more = FALSE;

	len = bp ? ct_buf_avail(bp) : 0;
	if (len > t1->ifsc) {
		pcb |= T1_MORE_BLOCKS;
		len = t1->ifsc;
		more = TRUE;
	}

	/* Add the sequence number */
	switch (t1_block_type(pcb)) {
	case T1_R_BLOCK:
		pcb |= t1->nr << T1_R_SEQ_SHIFT;
		break;
	case T1_I_BLOCK:
		pcb |= t1->ns << T1_I_SEQ_SHIFT;
		t1->more = more;
		DEBUG_COMM2("more bit: %d", more);
		break;
	}

	block[0] = dad;
	block[1] = pcb;
	block[2] = len;

	if (len)
		memcpy(block + 3, ct_buf_head(bp), len);
	if (lenp)
		*lenp = len;

	len = t1_compute_checksum(t1, block, len + 3);

	/* memorize the last sent block */
	/* only 4 bytes since we are only interesed in R-blocks */
	memcpy(t1->previous_block, block, 4);

	return len;
}
예제 #7
0
파일: conf.c 프로젝트: OpenSC/openct
/*
 * Check if we're at the end of the file
 */
static int ateof(void)
{
	int retry = 1;

      again:
	if (skipws() < 0)
		return -1;

	if (ct_buf_avail(&config_buf) == 0) {
		if (!retry)
			return 1;

		if (ct_buf_read(&config_buf, config_fd) < 0) {
			ct_error("%s: error while reading file: %m",
				 config_filename);
			return -1;
		}
		retry = 0;
		goto again;
	}

	return 0;
}
예제 #8
0
파일: tlv.c 프로젝트: OpenSC/openct
/*
 * Parse TLV data
 */
int ct_tlv_parse(ct_tlv_parser_t * parser, ct_buf_t * bp)
{
	unsigned int avail, len;
	unsigned char *p, tag;

	/* Code below relies on it */
	assert(((ifd_tag_t) - 1) == 255);

	while ((avail = ct_buf_avail(bp)) != 0) {
		unsigned int header = 2;

		if (avail < 2)
			return -1;

		p = (unsigned char *)ct_buf_head(bp);
		tag = p[0];
		len = p[1];

		if (tag & __CT_TAG_LARGE) {
			parser->use_large_tags = 1;
			tag &= ~__CT_TAG_LARGE;
			if (avail < 3)
				return -1;
			len = (len << 8) | p[header++];
		}

		if (len == 0 || header + len > avail)
			return -1;

		parser->val[tag] = p + header;
		parser->len[tag] = len;

		ct_buf_get(bp, NULL, header + len);
	}

	return 0;
}
예제 #9
0
파일: proto-t1.c 프로젝트: OpenSC/openct
/*
 * Send an APDU through T=1
 */
static int t1_transceive(ifd_protocol_t * prot, int dad, const void *snd_buf,
			 size_t snd_len, void *rcv_buf, size_t rcv_len)
{
	t1_state_t *t1 = (t1_state_t *) prot;
	ct_buf_t sbuf, rbuf, tbuf;
	unsigned char sdata[T1_BUFFER_SIZE], sblk[5];
	unsigned int slen, retries, resyncs, sent_length = 0;
	size_t last_send = 0;

	if (snd_len == 0)
		return -1;

	/* we can't talk to a dead card / reader. Reset it! */
	if (t1->state == DEAD)
		return -1;

	t1->state = SENDING;
	retries = t1->retries;
	resyncs = 3;

	/* Initialize send/recv buffer */
	ct_buf_set(&sbuf, (void *)snd_buf, snd_len);
	ct_buf_init(&rbuf, rcv_buf, rcv_len);

	/* Send the first block */
	slen = t1_build(t1, sdata, dad, T1_I_BLOCK, &sbuf, &last_send);

	while (1) {
		unsigned char pcb;
		int n;

		retries--;

		if ((n = t1_xcv(t1, sdata, slen, sizeof(sdata))) < 0) {
			ifd_debug(1, "fatal: transmit/receive failed");
			t1->state = DEAD;
			goto error;
		}

		if (!t1_verify_checksum(t1, sdata, n)) {
			ifd_debug(1, "checksum failed");
			if (retries == 0 || sent_length)
				goto resync;
			slen = t1_build(t1, sdata,
					dad, T1_R_BLOCK | T1_EDC_ERROR,
					NULL, NULL);
			continue;
		}

		pcb = sdata[PCB];
		switch (t1_block_type(pcb)) {
		case T1_R_BLOCK:
			if (T1_IS_ERROR(pcb)) {
				ifd_debug(1, "received error block, err=%d",
					  T1_IS_ERROR(pcb));
				goto resync;
			}

			if (t1->state == RECEIVING) {
				slen = t1_build(t1, sdata,
						dad, T1_R_BLOCK, NULL, NULL);
				break;
			}

			/* If the card terminal requests the next
			 * sequence number, it received the previous
			 * block successfully */
			if (t1_seq(pcb) != t1->ns) {
				ct_buf_get(&sbuf, NULL, last_send);
				sent_length += last_send;
				last_send = 0;
				t1->ns ^= 1;
			}

			/* If there's no data available, the ICC
			 * shouldn't be asking for more */
			if (ct_buf_avail(&sbuf) == 0)
				goto resync;

			slen = t1_build(t1, sdata, dad, T1_I_BLOCK,
					&sbuf, &last_send);
			break;

		case T1_I_BLOCK:
			/* The first I-block sent by the ICC indicates
			 * the last block we sent was received successfully. */
			if (t1->state == SENDING) {
				ct_buf_get(&sbuf, NULL, last_send);
				last_send = 0;
				t1->ns ^= 1;
			}

			t1->state = RECEIVING;

			/* If the block sent by the card doesn't match
			 * what we expected it to send, reply with
			 * an R block */
			if (t1_seq(pcb) != t1->nr) {
				slen = t1_build(t1, sdata, dad,
						T1_R_BLOCK | T1_OTHER_ERROR,
						NULL, NULL);
				continue;
			}

			t1->nr ^= 1;

			if (ct_buf_put(&rbuf, sdata + 3, sdata[LEN]) < 0)
				goto error;

			if ((pcb & T1_MORE_BLOCKS) == 0)
				goto done;

			slen = t1_build(t1, sdata, dad, T1_R_BLOCK, NULL, NULL);
			break;

		case T1_S_BLOCK:
			if (T1_S_IS_RESPONSE(pcb) && t1->state == RESYNCH) {
				t1->state = SENDING;
				sent_length = 0;
				last_send = 0;
				resyncs = 3;
				retries = t1->retries;
				ct_buf_init(&rbuf, rcv_buf, rcv_len);
				slen = t1_build(t1, sdata, dad, T1_I_BLOCK,
						&sbuf, &last_send);
				continue;
			}

			if (T1_S_IS_RESPONSE(pcb))
				goto resync;

			ct_buf_init(&tbuf, sblk, sizeof(sblk));

			switch (T1_S_TYPE(pcb)) {
			case T1_S_RESYNC:
				/* the card is not allowed to send a resync. */
				goto resync;
			case T1_S_ABORT:
				ifd_debug(1, "abort requested");
				break;
			case T1_S_IFS:
				ifd_debug(1, "CT sent S-block with ifs=%u",
					  sdata[DATA]);
				if (sdata[DATA] == 0)
					goto resync;
				t1->ifsc = sdata[DATA];
				ct_buf_putc(&tbuf, sdata[DATA]);
				break;
			case T1_S_WTX:
				/* We don't handle the wait time extension
				 * yet */
				ifd_debug(1, "CT sent S-block with wtx=%u",
					  sdata[DATA]);
				t1->wtx = sdata[DATA];
				ct_buf_putc(&tbuf, sdata[DATA]);
				break;
			default:
				ct_error("T=1: Unknown S block type 0x%02x",
					 T1_S_TYPE(pcb));
				goto resync;
			}

			slen = t1_build(t1, sdata, dad,
					T1_S_BLOCK | T1_S_RESPONSE |
					T1_S_TYPE(pcb), &tbuf, NULL);
		}

		/* Everything went just splendid */
		retries = t1->retries;
		continue;

	      resync:
		/* the number or resyncs is limited, too */
		if (resyncs == 0)
			goto error;
		resyncs--;
		t1->ns = 0;
		t1->nr = 0;
		slen = t1_build(t1, sdata, dad, T1_S_BLOCK | T1_S_RESYNC, NULL,
				NULL);
		t1->state = RESYNCH;
		continue;
	}

      done:
	return ct_buf_avail(&rbuf);

      error:
	t1->state = DEAD;
	return -1;
}
예제 #10
0
/*
 * Send an APDU through T=1
 */
int t1_transceive(t1_state_t * t1, unsigned int dad,
		const void *snd_buf, size_t snd_len,
		void *rcv_buf, size_t rcv_len)
{
	ct_buf_t sbuf, rbuf, tbuf;
	unsigned char sdata[T1_BUFFER_SIZE], sblk[5];
	unsigned int slen, retries, resyncs, sent_length = 0;
	size_t last_send = 0;

	if (snd_len == 0)
		return -1;

	/* we can't talk to a dead card / reader. Reset it! */
	if (t1->state == DEAD)
	{
		DEBUG_CRITICAL("T=1 state machine is DEAD. Reset the card first.");
		return -1;
	}

	t1->state = SENDING;
	retries = t1->retries;
	resyncs = 3;

	/* Initialize send/recv buffer */
	ct_buf_set(&sbuf, (void *)snd_buf, snd_len);
	ct_buf_init(&rbuf, rcv_buf, rcv_len);

	/* Send the first block */
	slen = t1_build(t1, sdata, dad, T1_I_BLOCK, &sbuf, &last_send);

	while (1) {
		unsigned char pcb;
		int n;

		retries--;

		n = t1_xcv(t1, sdata, slen, sizeof(sdata));
		if (-2 == n)
		{
			DEBUG_COMM("Parity error");
			/* ISO 7816-3 Rule 7.4.2 */
			if (retries == 0)
				goto resync;

			/* ISO 7816-3 Rule 7.2 */
			if (T1_R_BLOCK == t1_block_type(t1->previous_block[PCB]))
			{
				DEBUG_COMM("Rule 7.2");
				slen = t1_rebuild(t1, sdata);
				continue;
			}

			slen = t1_build(t1, sdata,
					dad, T1_R_BLOCK | T1_EDC_ERROR,
					NULL, NULL);
			continue;
		}

		if (n < 0) {
			DEBUG_CRITICAL("fatal: transmit/receive failed");
			t1->state = DEAD;
			goto error;
		}

		if ((sdata[NAD] != swap_nibbles(dad)) /* wrong NAD */
			|| (sdata[LEN] == 0xFF))	/* length == 0xFF (illegal) */
		{
			DEBUG_COMM("R-BLOCK required");
			/* ISO 7816-3 Rule 7.4.2 */
			if (retries == 0)
				goto resync;

			/* ISO 7816-3 Rule 7.2 */
			if (T1_R_BLOCK == t1_block_type(t1->previous_block[PCB]))
			{
				DEBUG_COMM("Rule 7.2");
				slen = t1_rebuild(t1, sdata);
				continue;
			}

			slen = t1_build(t1, sdata,
				dad, T1_R_BLOCK | T1_OTHER_ERROR,
				NULL, NULL);
			continue;
		}

		if (!t1_verify_checksum(t1, sdata, n)) {
			DEBUG_COMM("checksum failed");
			/* ISO 7816-3 Rule 7.4.2 */
			if (retries == 0)
				goto resync;

			/* ISO 7816-3 Rule 7.2 */
			if (T1_R_BLOCK == t1_block_type(t1->previous_block[PCB]))
			{
				DEBUG_COMM("Rule 7.2");
				slen = t1_rebuild(t1, sdata);
				continue;
			}

			slen = t1_build(t1, sdata,
				dad, T1_R_BLOCK | T1_EDC_ERROR,
				NULL, NULL);
			continue;
		}

		pcb = sdata[PCB];
		switch (t1_block_type(pcb)) {
		case T1_R_BLOCK:
			if ((sdata[LEN] != 0x00)	/* length != 0x00 (illegal) */
				|| (pcb & 0x20)			/* b6 of pcb is set */
			   )
			{
				DEBUG_COMM("R-Block required");
				/* ISO 7816-3 Rule 7.4.2 */
				if (retries == 0)
					goto resync;

				/* ISO 7816-3 Rule 7.2 */
				if (T1_R_BLOCK == t1_block_type(t1->previous_block[1]))
				{
					DEBUG_COMM("Rule 7.2");
					slen = t1_rebuild(t1, sdata);
					continue;
				}

				slen = t1_build(t1, sdata,
						dad, T1_R_BLOCK | T1_OTHER_ERROR,
						NULL, NULL);
				continue;
			}

			if (((t1_seq(pcb) != t1->ns)	/* wrong sequence number & no bit more */
					&& ! t1->more)
			   )
			{
				DEBUG_COMM4("received: %d, expected: %d, more: %d",
					t1_seq(pcb), t1->ns, t1->more);

				/* ISO 7816-3 Rule 7.2 */
				if (T1_R_BLOCK == t1_block_type(t1->previous_block[PCB]))
				{
					DEBUG_COMM("Rule 7.2");
					slen = t1_rebuild(t1, sdata);
					continue;
				}

				DEBUG_COMM("R-Block required");
				/* ISO 7816-3 Rule 7.4.2 */
				if (retries == 0)
					goto resync;
				slen = t1_build(t1, sdata,
						dad, T1_R_BLOCK | T1_OTHER_ERROR,
						NULL, NULL);
				continue;
			}

			if (t1->state == RECEIVING) {
				/* ISO 7816-3 Rule 7.2 */
				if (T1_R_BLOCK == t1_block_type(t1->previous_block[1]))
				{
					DEBUG_COMM("Rule 7.2");
					slen = t1_rebuild(t1, sdata);
					continue;
				}

				DEBUG_COMM("");
				slen = t1_build(t1, sdata,
						dad, T1_R_BLOCK,
						NULL, NULL);
				break;
			}

			/* If the card terminal requests the next
			 * sequence number, it received the previous
			 * block successfully */
			if (t1_seq(pcb) != t1->ns) {
				ct_buf_get(&sbuf, NULL, last_send);
				sent_length += last_send;
				last_send = 0;
				t1->ns ^= 1;
			}

			/* If there's no data available, the ICC
			 * shouldn't be asking for more */
			if (ct_buf_avail(&sbuf) == 0)
				goto resync;

			slen = t1_build(t1, sdata, dad, T1_I_BLOCK,
					&sbuf, &last_send);
			break;

		case T1_I_BLOCK:
			/* The first I-block sent by the ICC indicates
			 * the last block we sent was received successfully. */
			if (t1->state == SENDING) {
				DEBUG_COMM("");
				ct_buf_get(&sbuf, NULL, last_send);
				last_send = 0;
				t1->ns ^= 1;
			}

			t1->state = RECEIVING;

			/* If the block sent by the card doesn't match
			 * what we expected it to send, reply with
			 * an R block */
			if (t1_seq(pcb) != t1->nr) {
				DEBUG_COMM("wrong nr");
				slen = t1_build(t1, sdata, dad,
						T1_R_BLOCK | T1_OTHER_ERROR,
						NULL, NULL);
				continue;
			}

			t1->nr ^= 1;

			if (ct_buf_put(&rbuf, sdata + 3, sdata[LEN]) < 0)
			{
				DEBUG_CRITICAL2("buffer overrun by %d bytes", sdata[LEN] - (rbuf.size - rbuf.tail));
				goto error;
			}

			if ((pcb & T1_MORE_BLOCKS) == 0)
				goto done;

			slen = t1_build(t1, sdata, dad, T1_R_BLOCK, NULL, NULL);
			break;

		case T1_S_BLOCK:
			if (T1_S_IS_RESPONSE(pcb) && t1->state == RESYNCH) {
				/* ISO 7816-3 Rule 6.2 */
				DEBUG_COMM("S-Block answer received");
				/* ISO 7816-3 Rule 6.3 */
				t1->state = SENDING;
				sent_length = 0;
				last_send = 0;
				resyncs = 3;
				retries = t1->retries;
				ct_buf_init(&rbuf, rcv_buf, rcv_len);
				slen = t1_build(t1, sdata, dad, T1_I_BLOCK,
						&sbuf, &last_send);
				continue;
			}

			if (T1_S_IS_RESPONSE(pcb))
			{
				/* ISO 7816-3 Rule 7.4.2 */
				if (retries == 0)
					goto resync;

				/* ISO 7816-3 Rule 7.2 */
				if (T1_R_BLOCK == t1_block_type(t1->previous_block[PCB]))
				{
					DEBUG_COMM("Rule 7.2");
					slen = t1_rebuild(t1, sdata);
					continue;
				}

				DEBUG_CRITICAL("wrong response S-BLOCK received");
				slen = t1_build(t1, sdata,
						dad, T1_R_BLOCK | T1_OTHER_ERROR,
						NULL, NULL);
				continue;
			}

			ct_buf_init(&tbuf, sblk, sizeof(sblk));

			DEBUG_COMM("S-Block request received");
			switch (T1_S_TYPE(pcb)) {
			case T1_S_RESYNC:
				if (sdata[LEN] != 0)
				{
					DEBUG_COMM2("Wrong length: %d", sdata[LEN]);
					slen = t1_build(t1, sdata, dad,
						T1_R_BLOCK | T1_OTHER_ERROR,
						NULL, NULL);
					continue;
				}

				DEBUG_COMM("Resync requested");
				/* the card is not allowed to send a resync. */
				goto resync;

			case T1_S_ABORT:
				if (sdata[LEN] != 0)
				{
					DEBUG_COMM2("Wrong length: %d", sdata[LEN]);
					slen = t1_build(t1, sdata, dad,
						T1_R_BLOCK | T1_OTHER_ERROR,
						NULL, NULL);
					continue;
				}

				/* ISO 7816-3 Rule 9 */
				DEBUG_CRITICAL("abort requested");
				break;

			case T1_S_IFS:
				if (sdata[LEN] != 1)
				{
					DEBUG_COMM2("Wrong length: %d", sdata[LEN]);
					slen = t1_build(t1, sdata, dad,
						T1_R_BLOCK | T1_OTHER_ERROR,
						NULL, NULL);
					continue;
				}

				DEBUG_CRITICAL2("CT sent S-block with ifs=%u", sdata[DATA]);
				if (sdata[DATA] == 0)
					goto resync;
				t1->ifsc = sdata[DATA];
				ct_buf_putc(&tbuf, sdata[DATA]);
				break;

			case T1_S_WTX:
				if (sdata[LEN] != 1)
				{
					DEBUG_COMM2("Wrong length: %d", sdata[LEN]);
					slen = t1_build(t1, sdata, dad,
						T1_R_BLOCK | T1_OTHER_ERROR,
						NULL, NULL);
					continue;
				}

				DEBUG_COMM2("CT sent S-block with wtx=%u", sdata[DATA]);
				t1->wtx = sdata[DATA];
				ct_buf_putc(&tbuf, sdata[DATA]);
				break;

			default:
				DEBUG_CRITICAL2("T=1: Unknown S block type 0x%02x", T1_S_TYPE(pcb));
				goto resync;
			}

			slen = t1_build(t1, sdata, dad,
				T1_S_BLOCK | T1_S_RESPONSE | T1_S_TYPE(pcb),
				&tbuf, NULL);
		}

		/* Everything went just splendid */
		retries = t1->retries;
		continue;

resync:
		/* the number or resyncs is limited, too */
		/* ISO 7816-3 Rule 6.4 */
		if (resyncs == 0)
			goto error;

		/* ISO 7816-3 Rule 6 */
		resyncs--;
		t1->ns = 0;
		t1->nr = 0;
		slen = t1_build(t1, sdata, dad, T1_S_BLOCK | T1_S_RESYNC, NULL,
				NULL);
		t1->state = RESYNCH;
		t1->more = FALSE;
		retries = 1;
		continue;
	}

done:
	return ct_buf_avail(&rbuf);

error:
	t1->state = DEAD;
	return -1;
}
예제 #11
0
static int t0_xcv(ifd_protocol_t * prot, const void *sdata, size_t slen,
		  void *rdata, size_t rlen)
{
	t0_state_t *t0 = (t0_state_t *) prot;
	ct_buf_t sbuf, rbuf;
	unsigned int null_count = 0;
	unsigned int ins;

	/* Let the driver handle any chunking etc */
	if (t0->block_oriented) {
		int rc;

		if ((rc = ifd_send_command(prot, sdata, slen)) >= 0)
			rc = ifd_recv_response(prot, rdata, rlen, t0->timeout);
		return rc;
	}

	/* Set up the send buffer */
	ct_buf_set(&sbuf, (void *)sdata, slen);
	ct_buf_init(&rbuf, rdata, rlen);

	/* Get the INS */
	ins = sbuf.base[1];

	if (t0_send(prot, &sbuf, 5) < 0)
		goto failed;

	while (1) {
		unsigned char byte;
		int count;

		if (ifd_recv_response(prot, &byte, 1, t0->timeout) < 0)
			goto failed;

		/* Null byte to extend wait time */
		if (byte == 0x60) {
			usleep(100000);
			if (++null_count > t0->max_nulls)
				goto failed;
			continue;
		}

		/* ICC sends SW1 SW2 */
		if ((byte & 0xF0) == 0x60 || (byte & 0xF0) == 0x90) {
			/* Store SW1, then get SW2 and store it */
			if (ct_buf_put(&rbuf, &byte, 1) < 0
			    || t0_recv(prot, &rbuf, 1, t0->timeout) < 0)
				goto failed;

			break;
		}

		/* Send/receive data.
		 * ACK byte means transfer everything in one go,
		 * ~ACK means do it octet by octet.
		 * SCEZ masks off using 0xFE, but the Towitoko
		 * driver uses 0x0E.
		 * Do we need to make this configurable?
		 */
		if (((byte ^ ins) & 0xFE) == 0) {
			/* Send/recv as much as we can */
			count = -1;
		} else if (((~byte ^ ins) & 0xFE) == 0) {
			count = 1;
		} else {
			ifd_debug(2, "unexpected byte 0x%02x", byte);
			return -1;
		}

		if (t0->state == SENDING) {
			if (t0_send(prot, &sbuf, count) < 0)
				goto failed;
		} else {
			if (t0_recv(prot, &rbuf, count, t0->timeout) < 0)
				goto failed;
			if (ct_buf_tailroom(&rbuf) == 0)
				break;
		}
	}

	return ct_buf_avail(&rbuf);

      failed:t0->state = CONFUSED;
	return -1;
}
예제 #12
0
파일: ria-server.c 프로젝트: qmind/openct
/*
 * Process commands from local clients (i.e. those allowed
 * to claim a device).
 */
static int ria_svc_app_handler(ct_socket_t * sock, header_t * hdr,
                               ct_buf_t * args, ct_buf_t * resp)
{
    unsigned char cmd;
    ria_peer_t *clnt, *peer;
    int rc;

    clnt = (ria_peer_t *) sock->user_data;
    ria_print_packet(sock, 2, "app >>", hdr, args);

    if (ct_buf_get(args, &cmd, 1) < 0)
        return IFD_ERROR_INVALID_MSG;

    switch (cmd) {
    case RIA_MGR_LIST:
        peer = &clients;
        ifd_debug(1, "%s requests a device listing",
                  clnt->device.address);
        while ((peer = peer->next) != &clients) {
            if (peer->device.name[0] != '\0')
                ct_buf_put(resp, &peer->device,
                           sizeof(peer->device));
        }
        return 0;

    case RIA_MGR_INFO:
        peer =
            ria_find_device((const char *)ct_buf_head(args),
                            ct_buf_avail(args));
        if (peer == NULL)
            return IFD_ERROR_UNKNOWN_DEVICE;
        ct_buf_put(resp, &peer->device, sizeof(peer->device));
        return 0;

    case RIA_MGR_CLAIM:
        peer =
            ria_find_device((const char *)ct_buf_head(args),
                            ct_buf_avail(args));
        if (peer == NULL)
            return IFD_ERROR_UNKNOWN_DEVICE;
        if (peer->peer)
            return IFD_ERROR_DEVICE_BUSY;
        ifd_debug(1, "%s claimed %s device %s/%s",
                  clnt->device.address,
                  peer->device.type,
                  peer->device.address, peer->device.name);
        ct_buf_put(resp, &peer->device, sizeof(peer->device));
        clnt->peer = peer;
        peer->peer = clnt;
        return 0;
    }

    if (cmd < __RIA_PEER_CMD_BASE)
        return IFD_ERROR_INVALID_CMD;

    /* All subsequent commands require a device */
    if ((peer = clnt->peer) == NULL)
        return IFD_ERROR_NOT_CONNECTED;

    /* Push back the command byte */
    ct_buf_push(args, &cmd, 1);
    rc = ct_socket_put_packet(peer->sock, hdr, args);

    /* Tell the caller not to send a response */
    hdr->xid = 0;
    return rc;
}