bankd_pcsc: Add CSV based mapping of bank-id/slot-nr to PC/SC reader name

In the PC/SC world, each slot is associated with a string name. In the
bankd for PC/SC readers, we need to establish a mapping which
bank_id/slot_nr maps to which given string name.  We use a minimalistic
CSV file for defining those mappings.  The file is read only once at
bankd startup time.

Change-Id: Ifd2caab670625e2e3fbc57b966dce2f43b690417
This commit is contained in:
Harald Welte 2018-09-23 19:26:52 +02:00
parent 1266952242
commit 45c948cc10
5 changed files with 144 additions and 3 deletions

View File

@ -19,9 +19,9 @@ pcsc_test_SOURCES = driver_core.c driver_pcsc.c main.c
pcsc_test_LDADD = $(OSMOCORE_LIBS) \
$(ASN1C_LIBS) $(PCSC_LIBS) libosmo-rspro.la
remsim_bankd_SOURCES = bankd_slotmap.c bankd_main.c
remsim_bankd_LDADD = $(OSMOCORE_LIBS) \
$(ASN1C_LIBS) $(PCSC_LIBS) libosmo-rspro.la
remsim_bankd_SOURCES = bankd_slotmap.c bankd_main.c bankd_pcsc.c
remsim_bankd_LDADD = $(OSMOCORE_LIBS) $(OSMOGSM_LIBS) \
$(ASN1C_LIBS) $(PCSC_LIBS) libosmo-rspro.la -lcsv
remsim_client_SOURCES = remsim_client.c remsim_client_fsm.c
remsim_client_LDADD = $(OSMOCORE_LIBS) $(OSMOGSM_LIBS) $(OSMOABIS_LIBS) \

View File

@ -138,4 +138,9 @@ struct bankd {
/* list of bankd_workers. accessed/modified by multiple threads; protected by mutex */
struct llist_head workers;
pthread_mutex_t workers_mutex;
struct llist_head pcsc_slot_names;
};
int bankd_pcsc_read_slotnames(struct bankd *bankd, const char *csv_file);
const char *bankd_pcsc_get_slot_name(struct bankd *bankd, const struct bank_slot *slot);

View File

@ -38,6 +38,12 @@ static void bankd_init(struct bankd *bankd)
pthread_rwlock_init(&bankd->slot_mappings_rwlock, NULL);
INIT_LLIST_HEAD(&bankd->workers);
pthread_mutex_init(&bankd->workers_mutex, NULL);
/* Np lock or mutex required for the pcsc_slot_names list, as this is only
* read once during bankd initialization, when the worker threads haven't
* started yet */
INIT_LLIST_HEAD(&bankd->pcsc_slot_names);
OSMO_ASSERT(bankd_pcsc_read_slotnames(bankd, "bankd_pcsc_slots.csv") == 0);
}
/* create + start a new bankd_worker thread */
@ -154,6 +160,12 @@ static int worker_open_card(struct bankd_worker *worker)
{
long rc;
/* resolve PC/SC reader name from slot_id -> name map */
worker->reader.name = bankd_pcsc_get_slot_name(worker->bankd, &worker->slot);
OSMO_ASSERT(worker->reader.name);
LOGW(worker, "Attempting to open card/slot '%s'\n", worker->reader.name);
/* The PC/SC context must be created inside the thread where we'll later use it */
rc = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &worker->reader.pcsc.hContext);
PCSC_ERROR(worker, rc, "SCardEstablishContext")

118
src/bankd_pcsc.c Normal file
View File

@ -0,0 +1,118 @@
#include <osmocom/core/linuxlist.h>
#include <osmocom/core/talloc.h>
#include <osmocom/core/utils.h>
#include <csv.h>
#include "bankd.h"
struct pcsc_slot_name {
struct llist_head list;
/* RSPRO bank slot number */
struct bank_slot slot;
/* String name of the reader in PC/SC world */
const char *name;
};
enum parser_state_name {
ST_NONE,
ST_BANK_NR,
ST_SLOT_NR,
ST_PCSC_NAME,
};
struct parser_state {
struct bankd *bankd;
enum parser_state_name state;
struct pcsc_slot_name *cur;
};
static void parser_state_init(struct parser_state *ps)
{
ps->state = ST_BANK_NR;
ps->cur = NULL;
}
static void cb1(void *s, size_t len, void *data)
{
char *field = (char *) s;
struct parser_state *ps = data;
switch (ps->state) {
case ST_BANK_NR:
OSMO_ASSERT(!ps->cur);
ps->cur = talloc_zero(ps->bankd, struct pcsc_slot_name);
OSMO_ASSERT(ps->cur);
ps->cur->slot.bank_id = atoi(field);
ps->state = ST_SLOT_NR;
break;
case ST_SLOT_NR:
OSMO_ASSERT(ps->cur);
ps->cur->slot.slot_nr = atoi(field);
ps->state = ST_PCSC_NAME;
break;
case ST_PCSC_NAME:
OSMO_ASSERT(ps->cur);
ps->cur->name = talloc_strdup(ps->cur, field);
break;
default:
OSMO_ASSERT(0);
}
}
static void cb2(int c, void *data)
{
struct parser_state *ps = data;
struct pcsc_slot_name *sn = ps->cur;
printf("PC/SC slot name: %u/%u -> '%s'\n", sn->slot.bank_id, sn->slot.slot_nr, sn->name);
llist_add_tail(&sn->list, &ps->bankd->pcsc_slot_names);
ps->state = ST_BANK_NR;
ps->cur = NULL;
}
int bankd_pcsc_read_slotnames(struct bankd *bankd, const char *csv_file)
{
FILE *fp;
struct csv_parser p;
char buf[1024];
size_t bytes_read;
struct parser_state ps;
if (csv_init(&p, CSV_APPEND_NULL) != 0)
return -1;
fp = fopen(csv_file, "rb");
if (!fp)
return -1;
parser_state_init(&ps);
ps.bankd = bankd;
while ((bytes_read = fread(buf, 1, sizeof(buf), fp)) > 0) {
if (csv_parse(&p, buf, bytes_read, cb1, cb2, &ps) != bytes_read) {
fprintf(stderr, "Error parsing CSV: %s\n", csv_strerror(csv_error(&p)));
fclose(fp);
return -1;
}
}
csv_fini(&p, cb1, cb2, &ps);
fclose(fp);
csv_free(&p);
return 0;
}
const char *bankd_pcsc_get_slot_name(struct bankd *bankd, const struct bank_slot *slot)
{
struct pcsc_slot_name *cur;
llist_for_each_entry(cur, &bankd->pcsc_slot_names, list) {
if (bank_slot_equals(&cur->slot, slot))
return cur->name;
}
return NULL;
}

6
src/bankd_pcsc_slots.csv Normal file
View File

@ -0,0 +1,6 @@
"1","0","ACS ACR33 ICC Reader 00 00"
"1","1","ACS ACR33 ICC Reader 00 01"
"1","2","ACS ACR33 ICC Reader 00 02"
"1","3","ACS ACR33 ICC Reader 00 03"
"1","4","ACS ACR33 ICC Reader 00 04"
"1","23","Alcor Micro AU9560 00 00"
1 1 0 ACS ACR33 ICC Reader 00 00
2 1 1 ACS ACR33 ICC Reader 00 01
3 1 2 ACS ACR33 ICC Reader 00 02
4 1 3 ACS ACR33 ICC Reader 00 03
5 1 4 ACS ACR33 ICC Reader 00 04
6 1 23 Alcor Micro AU9560 00 00