Change in osmo-ccid-firmware[master]: add function to transfer TPDU

This is merely a historical archive of years 2008-2021, before the migration to mailman3.

A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/gerrit-log@lists.osmocom.org/.

Harald Welte gerrit-no-reply at lists.osmocom.org
Fri May 10 07:08:09 UTC 2019


Harald Welte has submitted this change and it was merged. ( https://gerrit.osmocom.org/13949 )

Change subject: add function to transfer TPDU
......................................................................

add function to transfer TPDU

this function takes care of reading and writing the complete TPDU
to the card.

note: the sim-iccid command uses this function, but still only to
select MF.

Change-Id: I50c90f3697580a4c93220a3e09cc33ec85889814
---
M sysmoOCTSIM/main.c
1 file changed, 184 insertions(+), 83 deletions(-)

Approvals:
  Jenkins Builder: Verified
  Harald Welte: Looks good to me, approved



diff --git a/sysmoOCTSIM/main.c b/sysmoOCTSIM/main.c
index 11849c7..327ac6d 100644
--- a/sysmoOCTSIM/main.c
+++ b/sysmoOCTSIM/main.c
@@ -226,7 +226,183 @@
 
 	// set baud rate
 	uint32_t baudrate = (freq * d) / f; // calculate actual baud rate
-	return slot_set_baudrate(slotnr, baudrate); // // set baud rate
+	return slot_set_baudrate(slotnr, baudrate); // set baud rate
+}
+
+/** write data to card
+ *  @param[in] slotnr slot number on which to send data
+ *  @param[in] data data to be transmitted
+ *  @param[in] length length of data to be transmitted
+ *  @return error code
+ */
+static int slot_card_write(uint8_t slotnr, const uint8_t* data, uint16_t length)
+{
+	// input checks
+	ASSERT(slotnr < ARRAY_SIZE(SIM_peripheral_descriptors));
+	if (0 == length || NULL == data) {
+		return ERR_INVALID_ARG;
+	}
+
+	struct usart_async_descriptor* sim = SIM_peripheral_descriptors[slotnr];
+	((Sercom *)sim->device.hw)->USART.CTRLB.bit.RXEN = 0; // disable receive (to avoid the echo back)
+	SIM_tx_count[slotnr] = false; // reset TX complete
+	for (uint16_t i = 0; i < length; i++) { // transmit data
+		while(!usart_async_is_tx_empty(sim)); // wait for previous byte to be transmitted (WARNING blocking)
+		if (1 != io_write(&sim->io, &data[i], 1)) { // put but in transmit buffer
+			return ERR_IO;
+		}
+	}
+	while (!SIM_tx_count[slotnr]); // wait until transmission is complete (WARNING blocking)
+	((Sercom *)sim->device.hw)->USART.CTRLB.bit.RXEN = 1; // enable receive again
+
+	return ERR_NONE;
+}
+
+/** read data from card
+ *  @param[in] slotnr slot number on which to send data
+ *  @param[out] data buffer for read data to be stored
+ *  @param[in] length length of data to be read
+ *  @param[in] wt Waiting Time in ETU
+ *  @return error code
+ *  TODO fix WT/ETU duration
+ */
+static int slot_card_read(uint8_t slotnr, uint8_t* data, uint16_t length, uint32_t wt)
+{
+	// input checks
+	ASSERT(slotnr < ARRAY_SIZE(SIM_peripheral_descriptors));
+	if (0 == length || NULL == data) {
+		return ERR_INVALID_ARG;
+	}
+
+	struct usart_async_descriptor* sim = SIM_peripheral_descriptors[slotnr];
+
+	((Sercom *)sim->device.hw)->USART.CTRLB.bit.RXEN = 1; // ensure RX is enabled
+	uint32_t timeout = wt; // reset waiting time
+	for (uint16_t i = 0; i < length; i++) { // read all data
+		while (timeout && !usart_async_is_rx_not_empty(sim)) { // verify if data is present
+			delay_us(149); // wait for 1 ETU (372 / 1 / 2.5 MHz = 148.8 us)
+			timeout--;
+		}
+		if (0 == timeout) { // timeout reached
+			return ERR_TIMEOUT;
+		}
+		timeout = wt; // reset waiting time
+		if (1 != io_read(&sim->io, &data[i], 1)) { // read one byte
+			return ERR_IO;
+		}
+	}
+
+	return ERR_NONE;
+}
+
+/** transfer TPDU
+ *  @param[in] slotnr slot number on which to transfer the TPDU
+ *  @param[in] header TPDU header to send
+ *  @param[io] data TPDU data to transfer
+ *  @param[in] data_length length of TPDU data to transfer
+ *  @param[in] write if the data should be written (true) or read (false)
+ * TODO fix WT
+ * TODO the data length can be deduce from the header
+ */
+static int slot_tpdu_xfer(uint8_t slotnr, const uint8_t* header, uint8_t* data, uint16_t data_length, bool write)
+{
+	// input checks
+	ASSERT(slotnr < ARRAY_SIZE(SIM_peripheral_descriptors));
+	if (NULL == header || (data_length > 0 && NULL == data)) {
+		return ERR_INVALID_ARG;
+	}
+
+	int rc;
+	struct usart_async_descriptor* sim = SIM_peripheral_descriptors[slotnr]; // get USART peripheral
+	usart_async_flush_rx_buffer(sim); // flush RX buffer to start from scratch
+
+	// send command header
+	printf("(%d) TPDU: ", slotnr);
+	for (uint8_t i = 0; i < 5; i++) {
+		printf("%02x ", header[i]);
+	}
+	rc = slot_card_write(slotnr, header, 5); // transmit header
+	if (ERR_NONE != rc) {
+		printf("error in command header transmit (errno = %d)\r\n", rc);
+		return rc;
+	}
+
+	// read procedure byte, and handle data
+	uint8_t pb = 0x60; // wait more procedure byte
+	uint16_t data_i = 0; // progress in the data transfer
+	while (0x60 == pb) { // wait for SW
+		rc = slot_card_read(slotnr, &pb, 1, ISO7816_3_DEFAULT_WT);
+		if (ERR_NONE != rc) {
+			printf("error while receiving PB/SW1 (errno = %d)\r\n", rc);
+			return rc;
+		}
+		printf("%02x ", pb);
+		if (0x60 == pb) { // NULL byte
+			// just wait more time
+		} else if ((0x60 == (pb & 0xf0)) || (0x90 == (pb & 0xf0))) { // SW1 byte
+			// left the rest of the code handle it
+		} else if (header[1] == pb) { // ACK byte
+			// transfer rest of the data
+			if (data_i >= data_length) {
+				printf("error no more data to transfer\r\n");
+				return ERR_INVALID_DATA;
+			}
+			if (write) { // transmit remaining command data
+				rc = slot_card_write(slotnr, &data[data_i], data_length - data_i); // transmit command data
+				if (ERR_NONE != rc) {
+					printf("error in command data transmit (errno = %d)\r\n", rc);
+					return rc;
+				}
+			} else { // receive remaining command data
+				rc = slot_card_read(slotnr, &data[data_i], data_length - data_i, ISO7816_3_DEFAULT_WT);
+				if (ERR_NONE != rc) {
+					printf("error in command data receive (errno = %d)\r\n", rc);
+					return rc;
+				}
+			}
+			for (uint16_t i = data_i; i < data_length; i++) {
+				printf("%02x ", data[i]);
+			}
+			data_i = data_length; // remember we transferred the data
+			pb = 0x60; // wait for SW1
+		} else if (header[1] == (pb ^ 0xff)) { // ACK byte
+			// transfer only one byte
+			if (data_i >= data_length) {
+				printf("error no more data to transfer\r\n");
+				return ERR_INVALID_DATA;
+			}
+			if (write) { // transmit command data byte
+				rc = slot_card_write(slotnr, &data[data_i], 1); // transmit command data
+				if (ERR_NONE != rc) {
+					printf("error in command data transmit (errno = %d)\r\n", rc);
+					return rc;
+				}
+			} else { // receive command data byte
+				rc = slot_card_read(slotnr, &data[data_i], 1, ISO7816_3_DEFAULT_WT);
+				if (ERR_NONE != rc) {
+					printf("error in command data receive (errno = %d)\r\n", rc);
+					return rc;
+				}
+			}
+			printf("%02x ", data[data_i]);
+			data_i += 1; // remember we transferred one data byte
+			pb = 0x60; // wait for SW1
+		} else { // invalid byte
+			return ERR_INVALID_DATA;
+		}
+	}
+
+	// read SW2
+	uint8_t sw2;
+	rc = slot_card_read(slotnr, &sw2, 1, ISO7816_3_DEFAULT_WT);
+	if (ERR_NONE != rc) {
+		printf("error in receiving SW2 (errno = %d)\r\n", rc);
+		return rc;
+	}
+	printf("%02x", sw2);
+
+	printf("\r\n");
+	return ERR_NONE;
 }
 
 DEFUN(sim_status, cmd_sim_status, "sim-status", "Get state of specified NCN8025")
@@ -480,90 +656,15 @@
 		ncn8025_set(slotnr, &settings);
 	}
 
-	// read MF
-	printf("(%d) SELECT MF: ", slotnr);
-	struct usart_async_descriptor* sim = SIM_peripheral_descriptors[slotnr];
-	((Sercom *)sim->device.hw)->USART.CTRLB.bit.RXEN = 0;
-	usart_async_flush_rx_buffer(sim); // flush RX buffer to start from scratch
+	// select MF
+	printf("(%d) SELECT MF\r\n", slotnr);
 	// write SELECT MF APDU
-	const uint8_t select_mf[] = {0xa0, 0xa4, 0x00, 0x00, 0x02, 0x3f, 0x00};
-	SIM_tx_count[slotnr] = false; // reset TX complete
-	for (uint8_t i = 0; i < 5; i++) { // transmit command header
-		printf("%02x ", select_mf[i]);
-		while(!usart_async_is_tx_empty(sim)); // wait for previous byte to be transmitted (WARNING could block)
-		if (1 != io_write(&sim->io, &select_mf[i], 1)) {
-			printf("(%d) error: could not send command header\r\n", slotnr);
-			return;
-		}
+	const uint8_t select_mf_header[] = {0xa0, 0xa4, 0x00, 0x00, 0x02};
+	const uint8_t select_mf_data[] = {0x3f, 0x00};
+	int rc = slot_tpdu_xfer(slotnr, select_mf_header, (uint8_t*)select_mf_data, ARRAY_SIZE(select_mf_data), true); // transfer TPDU
+	if (ERR_NONE != rc) {
+		printf("error while SELECT MF (errno = %d)\r\n", rc);
 	}
-	uint16_t wt = ISO7816_3_DEFAULT_WT; // waiting time in ETU (actually it can be a lot more after the ATR, but we use the default)
-	while (wt && !SIM_tx_count[slotnr]) { // wait until transmission is complete
-		delay_us(149); // wait for 1 ETU (372 / 1 / 2.5 MHz = 148.8 us)
-		wt--;
-	}
-	if (0 == wt) { // timeout reached
-		printf("(%d) error: could not transmit data\r\n", slotnr);
-		return;
-	}
-	((Sercom *)sim->device.hw)->USART.CTRLB.bit.RXEN = 1;
-	//usart_async_flush_rx_buffer(sim); // flush RX buffer to start from scratch
-	wt = ISO7816_3_DEFAULT_WT; // reset waiting time
-	while (wt && !usart_async_is_rx_not_empty(sim)) { // wait for procedure byte
-		delay_us(149); // wait for 1 ETU (372 / 1 / 2.5 MHz = 148.8 us)
-		wt--;
-	}
-	if (0 == wt) { // timeout reached
-		printf("(%d) error: card not responsive\r\n", slotnr);
-		return;
-	}
-	uint8_t pb;
-	if (1 != io_read(&sim->io, &pb, 1)) { // read procedure byte
-		printf("(%d) error: could not read data\r\n", slotnr);
-		return;
-	}
-	if (select_mf[1] != pb) { // the header is ACKed when the procedure by is equal to the instruction byte
-		printf("(%d) error: header NACKed\r\n", slotnr);
-		return;
-	}
-	SIM_tx_count[slotnr] = false; // reset TX complete
-	for (uint8_t i = 5; i < 7; i++) { // transmit command data
-		printf("%02x ", select_mf[i]);
-		while(!usart_async_is_tx_empty(sim)); // wait for previous byte to be transmitted (WARNING could block)
-		if (1 != io_write(&sim->io, &select_mf[i], 1)) {
-			printf("(%d) error: could not send command data\r\n", slotnr);
-			return;
-		}
-	}
-	wt = ISO7816_3_DEFAULT_WT; // waiting time in ETU (actually it can be a lot more after the ATR, but we use the default)
-	while (wt && !SIM_tx_count[slotnr]) { // wait until transmission is complete
-		delay_us(149); // wait for 1 ETU (372 / 1 / 2.5 MHz = 148.8 us)
-		wt--;
-	}
-	if (0 == wt) { // timeout reached
-		printf("(%d) error: could not transmit data\r\n", slotnr);
-		return;
-	}
-	usart_async_flush_rx_buffer(sim); // flush RX buffer to start from scratch
-	// read SW
-	uint8_t sw[2]; // to read the status words
-	wt = ISO7816_3_DEFAULT_WT; // waiting time in ETU (actually it can be a lot more after the ATR, but we use the default)
-	for (uint8_t i = 0; i < ARRAY_SIZE(sw); i++) {
-		while (wt && !usart_async_is_rx_not_empty(sim)) {
-			delay_us(149); // wait for 1 ETU (372 / 1 / 2.5 MHz = 148.8 us)
-			wt--;
-		}
-		if (0 == wt) { // timeout reached
-			printf("(%d) error: card not responsive\r\n", slotnr);
-		} else {
-			if (1 != io_read(&sim->io, &sw[i], 1)) { // read SW
-				printf("(%d) error: could not read data\r\n", slotnr);
-				return;
-			}
-			printf("%02x ", sw[i]);
-			wt = ISO7816_3_DEFAULT_WT; // reset WT
-		}
-	}
-	printf("\r\n");
 
 	// disable LED
 	settings.led = false;

-- 
To view, visit https://gerrit.osmocom.org/13949
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings

Gerrit-Project: osmo-ccid-firmware
Gerrit-Branch: master
Gerrit-MessageType: merged
Gerrit-Change-Id: I50c90f3697580a4c93220a3e09cc33ec85889814
Gerrit-Change-Number: 13949
Gerrit-PatchSet: 1
Gerrit-Owner: Kévin Redon <kredon at sysmocom.de>
Gerrit-Reviewer: Harald Welte <laforge at gnumonks.org>
Gerrit-Reviewer: Jenkins Builder (1000002)
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.osmocom.org/pipermail/gerrit-log/attachments/20190510/8996badc/attachment.htm>


More information about the gerrit-log mailing list