se.c (2b5dbe089f619f995faf2fe6beb7efb705eed302) se.c (3648dc6d27f648b8e3ce9b48874627a833d53c3a)
1/*
2 * Secure Element driver for STMicroelectronics NFC NCI chip
3 *
4 * Copyright (C) 2014-2015 STMicroelectronics SAS. All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.

--- 405 unchanged lines hidden (view full) ---

414 ndev->hci_dev->count_pipes = 0;
415 complete(&info->se_info.req_completion);
416 }
417 break;
418 }
419}
420EXPORT_SYMBOL_GPL(st_nci_hci_cmd_received);
421
1/*
2 * Secure Element driver for STMicroelectronics NFC NCI chip
3 *
4 * Copyright (C) 2014-2015 STMicroelectronics SAS. All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.

--- 405 unchanged lines hidden (view full) ---

414 ndev->hci_dev->count_pipes = 0;
415 complete(&info->se_info.req_completion);
416 }
417 break;
418 }
419}
420EXPORT_SYMBOL_GPL(st_nci_hci_cmd_received);
421
422/*
423 * Remarks: On some early st_nci firmware, nci_nfcee_mode_set(0)
424 * is rejected
425 */
426static int st_nci_control_se(struct nci_dev *ndev, u8 se_idx,
422static int st_nci_control_se(struct nci_dev *ndev, u8 se_idx,
427 u8 state)
423 u8 state)
428{
429 struct st_nci_info *info = nci_get_drvdata(ndev);
430 int r;
431 struct sk_buff *sk_host_list;
432 u8 host_id;
433
434 switch (se_idx) {
435 case ST_NCI_UICC_HOST_ID:

--- 8 unchanged lines hidden (view full) ---

444 return -EINVAL;
445 }
446
447 /*
448 * Wait for an EVT_HOT_PLUG in order to
449 * retrieve a relevant host list.
450 */
451 reinit_completion(&info->se_info.req_completion);
424{
425 struct st_nci_info *info = nci_get_drvdata(ndev);
426 int r;
427 struct sk_buff *sk_host_list;
428 u8 host_id;
429
430 switch (se_idx) {
431 case ST_NCI_UICC_HOST_ID:

--- 8 unchanged lines hidden (view full) ---

440 return -EINVAL;
441 }
442
443 /*
444 * Wait for an EVT_HOT_PLUG in order to
445 * retrieve a relevant host list.
446 */
447 reinit_completion(&info->se_info.req_completion);
452 r = nci_nfcee_mode_set(ndev, se_idx, NCI_NFCEE_ENABLE);
448 r = nci_nfcee_mode_set(ndev, se_idx, state);
453 if (r != NCI_STATUS_OK)
454 return r;
455
456 mod_timer(&info->se_info.se_active_timer, jiffies +
457 msecs_to_jiffies(ST_NCI_SE_TO_HOT_PLUG));
458 info->se_info.se_active = true;
459
460 /* Ignore return value and check in any case the host_list */
461 wait_for_completion_interruptible(&info->se_info.req_completion);
462
463 /* There might be some "collision" after receiving a HOT_PLUG event
464 * This may cause the CLF to not answer to the next hci command.
465 * There is no possible synchronization to prevent this.
466 * Adding a small delay is the only way to solve the issue.
467 */
449 if (r != NCI_STATUS_OK)
450 return r;
451
452 mod_timer(&info->se_info.se_active_timer, jiffies +
453 msecs_to_jiffies(ST_NCI_SE_TO_HOT_PLUG));
454 info->se_info.se_active = true;
455
456 /* Ignore return value and check in any case the host_list */
457 wait_for_completion_interruptible(&info->se_info.req_completion);
458
459 /* There might be some "collision" after receiving a HOT_PLUG event
460 * This may cause the CLF to not answer to the next hci command.
461 * There is no possible synchronization to prevent this.
462 * Adding a small delay is the only way to solve the issue.
463 */
468 usleep_range(3000, 5000);
464 if (info->se_info.se_status->is_ese_present &&
465 info->se_info.se_status->is_uicc_present)
466 usleep_range(3000, 5000);
469
470 r = nci_hci_get_param(ndev, NCI_HCI_ADMIN_GATE,
471 NCI_HCI_ADMIN_PARAM_HOST_LIST, &sk_host_list);
472 if (r != NCI_HCI_ANY_OK)
473 return r;
474
475 host_id = sk_host_list->data[sk_host_list->len - 1];
476 kfree_skb(sk_host_list);

--- 6 unchanged lines hidden (view full) ---

483}
484
485int st_nci_disable_se(struct nci_dev *ndev, u32 se_idx)
486{
487 int r;
488
489 pr_debug("st_nci_disable_se\n");
490
467
468 r = nci_hci_get_param(ndev, NCI_HCI_ADMIN_GATE,
469 NCI_HCI_ADMIN_PARAM_HOST_LIST, &sk_host_list);
470 if (r != NCI_HCI_ANY_OK)
471 return r;
472
473 host_id = sk_host_list->data[sk_host_list->len - 1];
474 kfree_skb(sk_host_list);

--- 6 unchanged lines hidden (view full) ---

481}
482
483int st_nci_disable_se(struct nci_dev *ndev, u32 se_idx)
484{
485 int r;
486
487 pr_debug("st_nci_disable_se\n");
488
491 if (se_idx == NFC_SE_EMBEDDED) {
492 r = nci_hci_send_event(ndev, ST_NCI_APDU_READER_GATE,
493 ST_NCI_EVT_SE_END_OF_APDU_TRANSFER, NULL, 0);
494 if (r < 0)
495 return r;
489 /*
490 * According to upper layer, se_idx == NFC_SE_UICC when
491 * info->se_info.se_status->is_uicc_enable is true should never happen
492 * Same for eSE.
493 */
494 r = st_nci_control_se(ndev, se_idx, ST_NCI_SE_MODE_OFF);
495 if (r < 0) {
496 /* Do best effort to release SWP */
497 if (se_idx == NFC_SE_EMBEDDED) {
498 r = nci_hci_send_event(ndev, ST_NCI_APDU_READER_GATE,
499 ST_NCI_EVT_SE_END_OF_APDU_TRANSFER,
500 NULL, 0);
501 }
502 return r;
496 }
497
498 return 0;
499}
500EXPORT_SYMBOL_GPL(st_nci_disable_se);
501
502int st_nci_enable_se(struct nci_dev *ndev, u32 se_idx)
503{
504 int r;
505
506 pr_debug("st_nci_enable_se\n");
507
503 }
504
505 return 0;
506}
507EXPORT_SYMBOL_GPL(st_nci_disable_se);
508
509int st_nci_enable_se(struct nci_dev *ndev, u32 se_idx)
510{
511 int r;
512
513 pr_debug("st_nci_enable_se\n");
514
508 if (se_idx == ST_NCI_HCI_HOST_ID_ESE) {
515 /*
516 * According to upper layer, se_idx == NFC_SE_UICC when
517 * info->se_info.se_status->is_uicc_enable is true should never happen.
518 * Same for eSE.
519 */
520 r = st_nci_control_se(ndev, se_idx, ST_NCI_SE_MODE_ON);
521 if (r == ST_NCI_HCI_HOST_ID_ESE) {
522 st_nci_se_get_atr(ndev);
509 r = nci_hci_send_event(ndev, ST_NCI_APDU_READER_GATE,
510 ST_NCI_EVT_SE_SOFT_RESET, NULL, 0);
523 r = nci_hci_send_event(ndev, ST_NCI_APDU_READER_GATE,
524 ST_NCI_EVT_SE_SOFT_RESET, NULL, 0);
511 if (r < 0)
512 return r;
513 }
514
525 }
526
527 if (r < 0) {
528 /*
529 * The activation procedure failed, the secure element
530 * is not connected. Remove from the list.
531 */
532 nfc_remove_se(ndev->nfc_dev, se_idx);
533 return r;
534 }
535
515 return 0;
516}
517EXPORT_SYMBOL_GPL(st_nci_enable_se);
518
519static int st_nci_hci_network_init(struct nci_dev *ndev)
520{
521 struct st_nci_info *info = nci_get_drvdata(ndev);
522 struct core_conn_create_dest_spec_params *dest_params;

--- 64 unchanged lines hidden (view full) ---

587 kfree(dest_params);
588
589exit:
590 return r;
591}
592
593int st_nci_discover_se(struct nci_dev *ndev)
594{
536 return 0;
537}
538EXPORT_SYMBOL_GPL(st_nci_enable_se);
539
540static int st_nci_hci_network_init(struct nci_dev *ndev)
541{
542 struct st_nci_info *info = nci_get_drvdata(ndev);
543 struct core_conn_create_dest_spec_params *dest_params;

--- 64 unchanged lines hidden (view full) ---

608 kfree(dest_params);
609
610exit:
611 return r;
612}
613
614int st_nci_discover_se(struct nci_dev *ndev)
615{
595 u8 param[2];
596 int r;
616 u8 white_list[2];
617 int r, wl_size = 0;
597 int se_count = 0;
598 struct st_nci_info *info = nci_get_drvdata(ndev);
599
600 pr_debug("st_nci_discover_se\n");
601
602 r = st_nci_hci_network_init(ndev);
603 if (r != 0)
604 return r;
605
606 if (test_bit(ST_NCI_FACTORY_MODE, &info->flags))
607 return 0;
608
618 int se_count = 0;
619 struct st_nci_info *info = nci_get_drvdata(ndev);
620
621 pr_debug("st_nci_discover_se\n");
622
623 r = st_nci_hci_network_init(ndev);
624 if (r != 0)
625 return r;
626
627 if (test_bit(ST_NCI_FACTORY_MODE, &info->flags))
628 return 0;
629
609 param[0] = ST_NCI_UICC_HOST_ID;
610 param[1] = ST_NCI_HCI_HOST_ID_ESE;
611 r = nci_hci_set_param(ndev, NCI_HCI_ADMIN_GATE,
612 NCI_HCI_ADMIN_PARAM_WHITELIST,
613 param, sizeof(param));
614 if (r != NCI_HCI_ANY_OK)
615 return r;
630 if (info->se_info.se_status->is_ese_present &&
631 info->se_info.se_status->is_uicc_present) {
632 white_list[wl_size++] = ST_NCI_UICC_HOST_ID;
633 white_list[wl_size++] = ST_NCI_ESE_HOST_ID;
634 } else if (!info->se_info.se_status->is_ese_present &&
635 info->se_info.se_status->is_uicc_present) {
636 white_list[wl_size++] = ST_NCI_UICC_HOST_ID;
637 } else if (info->se_info.se_status->is_ese_present &&
638 !info->se_info.se_status->is_uicc_present) {
639 white_list[wl_size++] = ST_NCI_ESE_HOST_ID;
640 }
616
641
617 r = st_nci_control_se(ndev, ST_NCI_UICC_HOST_ID,
618 ST_NCI_SE_MODE_ON);
619 if (r == ST_NCI_UICC_HOST_ID) {
642 if (wl_size) {
643 r = nci_hci_set_param(ndev, NCI_HCI_ADMIN_GATE,
644 NCI_HCI_ADMIN_PARAM_WHITELIST,
645 white_list, wl_size);
646 if (r != NCI_HCI_ANY_OK)
647 return r;
648 }
649
650 if (info->se_info.se_status->is_uicc_present) {
620 nfc_add_se(ndev->nfc_dev, ST_NCI_UICC_HOST_ID, NFC_SE_UICC);
621 se_count++;
622 }
623
651 nfc_add_se(ndev->nfc_dev, ST_NCI_UICC_HOST_ID, NFC_SE_UICC);
652 se_count++;
653 }
654
624 /* Try to enable eSE in order to check availability */
625 r = st_nci_control_se(ndev, ST_NCI_HCI_HOST_ID_ESE,
626 ST_NCI_SE_MODE_ON);
627 if (r == ST_NCI_HCI_HOST_ID_ESE) {
628 nfc_add_se(ndev->nfc_dev, ST_NCI_HCI_HOST_ID_ESE,
629 NFC_SE_EMBEDDED);
655 if (info->se_info.se_status->is_ese_present) {
656 nfc_add_se(ndev->nfc_dev, ST_NCI_ESE_HOST_ID, NFC_SE_EMBEDDED);
630 se_count++;
657 se_count++;
631 st_nci_se_get_atr(ndev);
632 }
633
634 return !se_count;
635}
636EXPORT_SYMBOL_GPL(st_nci_discover_se);
637
638int st_nci_se_io(struct nci_dev *ndev, u32 se_idx,
639 u8 *apdu, size_t apdu_length,

--- 56 unchanged lines hidden (view full) ---

696
697 pr_debug("\n");
698
699 info->se_info.se_active = false;
700
701 complete(&info->se_info.req_completion);
702}
703
658 }
659
660 return !se_count;
661}
662EXPORT_SYMBOL_GPL(st_nci_discover_se);
663
664int st_nci_se_io(struct nci_dev *ndev, u32 se_idx,
665 u8 *apdu, size_t apdu_length,

--- 56 unchanged lines hidden (view full) ---

722
723 pr_debug("\n");
724
725 info->se_info.se_active = false;
726
727 complete(&info->se_info.req_completion);
728}
729
704int st_nci_se_init(struct nci_dev *ndev)
730int st_nci_se_init(struct nci_dev *ndev, struct st_nci_se_status *se_status)
705{
706 struct st_nci_info *info = nci_get_drvdata(ndev);
707
708 init_completion(&info->se_info.req_completion);
709 /* initialize timers */
710 init_timer(&info->se_info.bwi_timer);
711 info->se_info.bwi_timer.data = (unsigned long)info;
712 info->se_info.bwi_timer.function = st_nci_se_wt_timeout;

--- 5 unchanged lines hidden (view full) ---

718 st_nci_se_activation_timeout;
719 info->se_info.se_active = false;
720
721 info->se_info.xch_error = false;
722
723 info->se_info.wt_timeout =
724 ST_NCI_BWI_TO_TIMEOUT(ST_NCI_ATR_DEFAULT_BWI);
725
731{
732 struct st_nci_info *info = nci_get_drvdata(ndev);
733
734 init_completion(&info->se_info.req_completion);
735 /* initialize timers */
736 init_timer(&info->se_info.bwi_timer);
737 info->se_info.bwi_timer.data = (unsigned long)info;
738 info->se_info.bwi_timer.function = st_nci_se_wt_timeout;

--- 5 unchanged lines hidden (view full) ---

744 st_nci_se_activation_timeout;
745 info->se_info.se_active = false;
746
747 info->se_info.xch_error = false;
748
749 info->se_info.wt_timeout =
750 ST_NCI_BWI_TO_TIMEOUT(ST_NCI_ATR_DEFAULT_BWI);
751
752 info->se_info.se_status = se_status;
753
726 return 0;
727}
728EXPORT_SYMBOL(st_nci_se_init);
729
730void st_nci_se_deinit(struct nci_dev *ndev)
731{
732 struct st_nci_info *info = nci_get_drvdata(ndev);
733
734 if (info->se_info.bwi_active)
735 del_timer_sync(&info->se_info.bwi_timer);
736 if (info->se_info.se_active)
737 del_timer_sync(&info->se_info.se_active_timer);
738
739 info->se_info.se_active = false;
740 info->se_info.bwi_active = false;
741}
742EXPORT_SYMBOL(st_nci_se_deinit);
743
754 return 0;
755}
756EXPORT_SYMBOL(st_nci_se_init);
757
758void st_nci_se_deinit(struct nci_dev *ndev)
759{
760 struct st_nci_info *info = nci_get_drvdata(ndev);
761
762 if (info->se_info.bwi_active)
763 del_timer_sync(&info->se_info.bwi_timer);
764 if (info->se_info.se_active)
765 del_timer_sync(&info->se_info.se_active_timer);
766
767 info->se_info.se_active = false;
768 info->se_info.bwi_active = false;
769}
770EXPORT_SYMBOL(st_nci_se_deinit);
771