| /* | 
 |  * implement the Java card standard. | 
 |  * | 
 |  * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. | 
 |  * See the COPYING.LIB file in the top-level directory. | 
 |  */ | 
 |  | 
 | #include "qemu-common.h" | 
 |  | 
 | #include "vcard.h" | 
 | #include "vcard_emul.h" | 
 | #include "card_7816t.h" | 
 |  | 
 | struct VCardAppletStruct { | 
 |     VCardApplet   *next; | 
 |     VCardProcessAPDU process_apdu; | 
 |     VCardResetApplet reset_applet; | 
 |     unsigned char *aid; | 
 |     int aid_len; | 
 |     void *applet_private; | 
 |     VCardAppletPrivateFree applet_private_free; | 
 | }; | 
 |  | 
 | struct VCardStruct { | 
 |     int reference_count; | 
 |     VCardApplet *applet_list; | 
 |     VCardApplet *current_applet[MAX_CHANNEL]; | 
 |     VCardBufferResponse *vcard_buffer_response; | 
 |     VCardType type; | 
 |     VCardEmul *vcard_private; | 
 |     VCardEmulFree vcard_private_free; | 
 |     VCardGetAtr vcard_get_atr; | 
 | }; | 
 |  | 
 | VCardBufferResponse * | 
 | vcard_buffer_response_new(unsigned char *buffer, int size) | 
 | { | 
 |     VCardBufferResponse *new_buffer; | 
 |  | 
 |     new_buffer = (VCardBufferResponse *)g_malloc(sizeof(VCardBufferResponse)); | 
 |     new_buffer->buffer = (unsigned char *)g_malloc(size); | 
 |     memcpy(new_buffer->buffer, buffer, size); | 
 |     new_buffer->buffer_len = size; | 
 |     new_buffer->current = new_buffer->buffer; | 
 |     new_buffer->len = size; | 
 |     return new_buffer; | 
 | } | 
 |  | 
 | void | 
 | vcard_buffer_response_delete(VCardBufferResponse *buffer_response) | 
 | { | 
 |     if (buffer_response == NULL) { | 
 |         return; | 
 |     } | 
 |     if (buffer_response->buffer) { | 
 |         g_free(buffer_response->buffer); | 
 |     } | 
 |     g_free(buffer_response); | 
 | } | 
 |  | 
 |  | 
 | /* | 
 |  * clean up state after a reset | 
 |  */ | 
 | void | 
 | vcard_reset(VCard *card, VCardPower power) | 
 | { | 
 |     int i; | 
 |     VCardApplet *applet = NULL; | 
 |  | 
 |     if (card->type ==  VCARD_DIRECT) { | 
 |         /* select the last applet */ | 
 |         VCardApplet *current_applet = NULL; | 
 |         for (current_applet = card->applet_list; current_applet; | 
 |                                        current_applet = current_applet->next) { | 
 |             applet = current_applet; | 
 |         } | 
 |     } | 
 |     for (i = 0; i < MAX_CHANNEL; i++) { | 
 |         card->current_applet[i] = applet; | 
 |     } | 
 |     if (card->vcard_buffer_response) { | 
 |         vcard_buffer_response_delete(card->vcard_buffer_response); | 
 |         card->vcard_buffer_response = NULL; | 
 |     } | 
 |     vcard_emul_reset(card, power); | 
 |     if (applet) { | 
 |         applet->reset_applet(card, 0); | 
 |     } | 
 | } | 
 |  | 
 | /* applet utilities */ | 
 |  | 
 | /* | 
 |  * applet utilities | 
 |  */ | 
 | /* constructor */ | 
 | VCardApplet * | 
 | vcard_new_applet(VCardProcessAPDU applet_process_function, | 
 |                  VCardResetApplet applet_reset_function, | 
 |                  unsigned char *aid, int aid_len) | 
 | { | 
 |     VCardApplet *applet; | 
 |  | 
 |     applet = (VCardApplet *)g_malloc(sizeof(VCardApplet)); | 
 |     applet->next = NULL; | 
 |     applet->applet_private = NULL; | 
 |     applet->applet_private_free = NULL; | 
 |     applet->process_apdu = applet_process_function; | 
 |     applet->reset_applet = applet_reset_function; | 
 |  | 
 |     applet->aid = g_malloc(aid_len); | 
 |     memcpy(applet->aid, aid, aid_len); | 
 |     applet->aid_len = aid_len; | 
 |     return applet; | 
 | } | 
 |  | 
 | /* destructor */ | 
 | void | 
 | vcard_delete_applet(VCardApplet *applet) | 
 | { | 
 |     if (applet == NULL) { | 
 |         return; | 
 |     } | 
 |     if (applet->applet_private_free) { | 
 |         applet->applet_private_free(applet->applet_private); | 
 |         applet->applet_private = NULL; | 
 |     } | 
 |     if (applet->aid) { | 
 |         g_free(applet->aid); | 
 |         applet->aid = NULL; | 
 |     } | 
 |     g_free(applet); | 
 | } | 
 |  | 
 | /* accessor */ | 
 | void | 
 | vcard_set_applet_private(VCardApplet *applet, VCardAppletPrivate *private, | 
 |                          VCardAppletPrivateFree private_free) | 
 | { | 
 |     if (applet->applet_private_free) { | 
 |         applet->applet_private_free(applet->applet_private); | 
 |     } | 
 |     applet->applet_private = private; | 
 |     applet->applet_private_free = private_free; | 
 | } | 
 |  | 
 | VCard * | 
 | vcard_new(VCardEmul *private, VCardEmulFree private_free) | 
 | { | 
 |     VCard *new_card; | 
 |     int i; | 
 |  | 
 |     new_card = (VCard *)g_malloc(sizeof(VCard)); | 
 |     new_card->applet_list = NULL; | 
 |     for (i = 0; i < MAX_CHANNEL; i++) { | 
 |         new_card->current_applet[i] = NULL; | 
 |     } | 
 |     new_card->vcard_buffer_response = NULL; | 
 |     new_card->type = VCARD_VM; | 
 |     new_card->vcard_private = private; | 
 |     new_card->vcard_private_free = private_free; | 
 |     new_card->vcard_get_atr = NULL; | 
 |     new_card->reference_count = 1; | 
 |     return new_card; | 
 | } | 
 |  | 
 | VCard * | 
 | vcard_reference(VCard *vcard) | 
 | { | 
 |     if (vcard == NULL) { | 
 |         return NULL; | 
 |     } | 
 |     vcard->reference_count++; | 
 |     return vcard; | 
 | } | 
 |  | 
 | void | 
 | vcard_free(VCard *vcard) | 
 | { | 
 |     VCardApplet *current_applet = NULL; | 
 |     VCardApplet *next_applet = NULL; | 
 |  | 
 |     if (vcard == NULL) { | 
 |         return; | 
 |     } | 
 |     vcard->reference_count--; | 
 |     if (vcard->reference_count != 0) { | 
 |         return; | 
 |     } | 
 |     if (vcard->vcard_private_free) { | 
 |         (*vcard->vcard_private_free)(vcard->vcard_private); | 
 |         vcard->vcard_private_free = 0; | 
 |         vcard->vcard_private = 0; | 
 |     } | 
 |     for (current_applet = vcard->applet_list; current_applet; | 
 |                                         current_applet = next_applet) { | 
 |         next_applet = current_applet->next; | 
 |         vcard_delete_applet(current_applet); | 
 |     } | 
 |     vcard_buffer_response_delete(vcard->vcard_buffer_response); | 
 |     g_free(vcard); | 
 | } | 
 |  | 
 | void | 
 | vcard_get_atr(VCard *vcard, unsigned char *atr, int *atr_len) | 
 | { | 
 |     if (vcard->vcard_get_atr) { | 
 |         (*vcard->vcard_get_atr)(vcard, atr, atr_len); | 
 |         return; | 
 |     } | 
 |     vcard_emul_get_atr(vcard, atr, atr_len); | 
 | } | 
 |  | 
 | void | 
 | vcard_set_atr_func(VCard *card, VCardGetAtr vcard_get_atr) | 
 | { | 
 |     card->vcard_get_atr = vcard_get_atr; | 
 | } | 
 |  | 
 |  | 
 | VCardStatus | 
 | vcard_add_applet(VCard *card, VCardApplet *applet) | 
 | { | 
 |     applet->next = card->applet_list; | 
 |     card->applet_list = applet; | 
 |     /* if our card-type is direct, always call the applet */ | 
 |     if (card->type ==  VCARD_DIRECT) { | 
 |         int i; | 
 |  | 
 |         for (i = 0; i < MAX_CHANNEL; i++) { | 
 |             card->current_applet[i] = applet; | 
 |         } | 
 |     } | 
 |     return VCARD_DONE; | 
 | } | 
 |  | 
 | /* | 
 |  * manage applets | 
 |  */ | 
 | VCardApplet * | 
 | vcard_find_applet(VCard *card, unsigned char *aid, int aid_len) | 
 | { | 
 |     VCardApplet *current_applet; | 
 |  | 
 |     for (current_applet = card->applet_list; current_applet; | 
 |                                         current_applet = current_applet->next) { | 
 |         if (current_applet->aid_len != aid_len) { | 
 |             continue; | 
 |         } | 
 |         if (memcmp(current_applet->aid, aid, aid_len) == 0) { | 
 |             break; | 
 |         } | 
 |     } | 
 |     return current_applet; | 
 | } | 
 |  | 
 | unsigned char * | 
 | vcard_applet_get_aid(VCardApplet *applet, int *aid_len) | 
 | { | 
 |     if (applet == NULL) { | 
 |         return NULL; | 
 |     } | 
 |     *aid_len = applet->aid_len; | 
 |     return applet->aid; | 
 | } | 
 |  | 
 |  | 
 | void | 
 | vcard_select_applet(VCard *card, int channel, VCardApplet *applet) | 
 | { | 
 |     assert(channel < MAX_CHANNEL); | 
 |     card->current_applet[channel] = applet; | 
 |     /* reset the applet */ | 
 |     if (applet && applet->reset_applet) { | 
 |         applet->reset_applet(card, channel); | 
 |     } | 
 | } | 
 |  | 
 | VCardAppletPrivate * | 
 | vcard_get_current_applet_private(VCard *card, int channel) | 
 | { | 
 |     VCardApplet *applet = card->current_applet[channel]; | 
 |  | 
 |     if (applet == NULL) { | 
 |         return NULL; | 
 |     } | 
 |     return applet->applet_private; | 
 | } | 
 |  | 
 | VCardStatus | 
 | vcard_process_applet_apdu(VCard *card, VCardAPDU *apdu, | 
 |                           VCardResponse **response) | 
 | { | 
 |     if (card->current_applet[apdu->a_channel]) { | 
 |         return card->current_applet[apdu->a_channel]->process_apdu( | 
 |                                                         card, apdu, response); | 
 |     } | 
 |     return VCARD_NEXT; | 
 | } | 
 |  | 
 | /* | 
 |  * Accessor functions | 
 |  */ | 
 | /* accessor functions for the response buffer */ | 
 | VCardBufferResponse * | 
 | vcard_get_buffer_response(VCard *card) | 
 | { | 
 |     return card->vcard_buffer_response; | 
 | } | 
 |  | 
 | void | 
 | vcard_set_buffer_response(VCard *card, VCardBufferResponse *buffer) | 
 | { | 
 |     card->vcard_buffer_response = buffer; | 
 | } | 
 |  | 
 |  | 
 | /* accessor functions for the type */ | 
 | VCardType | 
 | vcard_get_type(VCard *card) | 
 | { | 
 |     return card->type; | 
 | } | 
 |  | 
 | void | 
 | vcard_set_type(VCard *card, VCardType type) | 
 | { | 
 |     card->type = type; | 
 | } | 
 |  | 
 | /* accessor for private data */ | 
 | VCardEmul * | 
 | vcard_get_private(VCard *vcard) | 
 | { | 
 |     return vcard->vcard_private; | 
 | } | 
 |  |