]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - drivers/nfc/st21nfca/st21nfca_se.c
Merge branch 'linus' of git://git.kernel.org/pub/scm/linux/kernel/git/herbert/crypto-2.6
[karo-tx-linux.git] / drivers / nfc / st21nfca / st21nfca_se.c
1 /*
2  * Copyright (C) 2014  STMicroelectronics SAS. All rights reserved.
3  *
4  * This program is free software; you can redistribute it and/or modify it
5  * under the terms and conditions of the GNU General Public License,
6  * version 2, as published by the Free Software Foundation.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program; if not, see <http://www.gnu.org/licenses/>.
15  */
16
17 #include <net/nfc/hci.h>
18
19 #include "st21nfca.h"
20 #include "st21nfca_se.h"
21
22 #define ST21NFCA_EVT_UICC_ACTIVATE              0x10
23 #define ST21NFCA_EVT_UICC_DEACTIVATE    0x13
24 #define ST21NFCA_EVT_SE_HARD_RESET              0x20
25 #define ST21NFCA_EVT_SE_SOFT_RESET              0x11
26 #define ST21NFCA_EVT_SE_END_OF_APDU_TRANSFER    0x21
27 #define ST21NFCA_EVT_SE_ACTIVATE                0x22
28 #define ST21NFCA_EVT_SE_DEACTIVATE              0x23
29
30 #define ST21NFCA_EVT_TRANSMIT_DATA              0x10
31 #define ST21NFCA_EVT_WTX_REQUEST                0x11
32
33 #define ST21NFCA_EVT_CONNECTIVITY               0x10
34 #define ST21NFCA_EVT_TRANSACTION                0x12
35
36 #define ST21NFCA_ESE_HOST_ID                    0xc0
37
38 #define ST21NFCA_SE_TO_HOT_PLUG                 1000
39 /* Connectivity pipe only */
40 #define ST21NFCA_SE_COUNT_PIPE_UICC             0x01
41 /* Connectivity + APDU Reader pipe */
42 #define ST21NFCA_SE_COUNT_PIPE_EMBEDDED 0x02
43
44 #define ST21NFCA_SE_MODE_OFF                    0x00
45 #define ST21NFCA_SE_MODE_ON                             0x01
46
47 #define ST21NFCA_PARAM_ATR                              0x01
48 #define ST21NFCA_ATR_DEFAULT_BWI                0x04
49
50 /*
51  * WT = 2^BWI/10[s], convert into msecs and add a secure
52  * room by increasing by 2 this timeout
53  */
54 #define ST21NFCA_BWI_TO_TIMEOUT(x)              ((1 << x) * 200)
55 #define ST21NFCA_ATR_GET_Y_FROM_TD(x)   (x >> 4)
56
57 /* If TA is present bit 0 is set */
58 #define ST21NFCA_ATR_TA_PRESENT(x) (x & 0x01)
59 /* If TB is present bit 1 is set */
60 #define ST21NFCA_ATR_TB_PRESENT(x) (x & 0x02)
61
62 static u8 st21nfca_se_get_bwi(struct nfc_hci_dev *hdev)
63 {
64         int i;
65         u8 td;
66         struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev);
67
68         /* Bits 8 to 5 of the first TB for T=1 encode BWI from zero to nine */
69         for (i = 1; i < ST21NFCA_ESE_MAX_LENGTH; i++) {
70                 td = ST21NFCA_ATR_GET_Y_FROM_TD(info->se_info.atr[i]);
71                 if (ST21NFCA_ATR_TA_PRESENT(td))
72                         i++;
73                 if (ST21NFCA_ATR_TB_PRESENT(td)) {
74                         i++;
75                         return info->se_info.atr[i] >> 4;
76                 }
77         }
78         return ST21NFCA_ATR_DEFAULT_BWI;
79 }
80
81 static void st21nfca_se_get_atr(struct nfc_hci_dev *hdev)
82 {
83         int r;
84         struct sk_buff *skb;
85         struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev);
86
87         r = nfc_hci_get_param(hdev, ST21NFCA_APDU_READER_GATE,
88                         ST21NFCA_PARAM_ATR, &skb);
89         if (r < 0)
90                 return;
91
92         if (skb->len <= ST21NFCA_ESE_MAX_LENGTH) {
93                 memcpy(info->se_info.atr, skb->data, skb->len);
94                 info->se_info.wt_timeout =
95                         ST21NFCA_BWI_TO_TIMEOUT(st21nfca_se_get_bwi(hdev));
96         }
97         kfree_skb(skb);
98 }
99
100 static int st21nfca_hci_control_se(struct nfc_hci_dev *hdev, u32 se_idx,
101                                 u8 state)
102 {
103         struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev);
104         int r;
105         struct sk_buff *sk_host_list;
106         u8 se_event, host_id;
107
108         switch (se_idx) {
109         case NFC_HCI_UICC_HOST_ID:
110                 se_event = (state == ST21NFCA_SE_MODE_ON ?
111                                         ST21NFCA_EVT_UICC_ACTIVATE :
112                                         ST21NFCA_EVT_UICC_DEACTIVATE);
113
114                 info->se_info.count_pipes = 0;
115                 info->se_info.expected_pipes = ST21NFCA_SE_COUNT_PIPE_UICC;
116                 break;
117         case ST21NFCA_ESE_HOST_ID:
118                 se_event = (state == ST21NFCA_SE_MODE_ON ?
119                                         ST21NFCA_EVT_SE_ACTIVATE :
120                                         ST21NFCA_EVT_SE_DEACTIVATE);
121
122                 info->se_info.count_pipes = 0;
123                 info->se_info.expected_pipes = ST21NFCA_SE_COUNT_PIPE_EMBEDDED;
124                 break;
125         default:
126                 return -EINVAL;
127         }
128
129         /*
130          * Wait for an EVT_HOT_PLUG in order to
131          * retrieve a relevant host list.
132          */
133         reinit_completion(&info->se_info.req_completion);
134         r = nfc_hci_send_event(hdev, ST21NFCA_DEVICE_MGNT_GATE, se_event,
135                                NULL, 0);
136         if (r < 0)
137                 return r;
138
139         mod_timer(&info->se_info.se_active_timer, jiffies +
140                 msecs_to_jiffies(ST21NFCA_SE_TO_HOT_PLUG));
141         info->se_info.se_active = true;
142
143         /* Ignore return value and check in any case the host_list */
144         wait_for_completion_interruptible(&info->se_info.req_completion);
145
146         r = nfc_hci_get_param(hdev, NFC_HCI_ADMIN_GATE,
147                         NFC_HCI_ADMIN_HOST_LIST,
148                         &sk_host_list);
149         if (r < 0)
150                 return r;
151
152         host_id = sk_host_list->data[sk_host_list->len - 1];
153         kfree_skb(sk_host_list);
154
155         if (state == ST21NFCA_SE_MODE_ON && host_id == se_idx)
156                 return se_idx;
157         else if (state == ST21NFCA_SE_MODE_OFF && host_id != se_idx)
158                 return se_idx;
159
160         return -1;
161 }
162
163 int st21nfca_hci_discover_se(struct nfc_hci_dev *hdev)
164 {
165         struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev);
166         int se_count = 0;
167
168         if (info->se_status->is_uicc_present) {
169                 nfc_add_se(hdev->ndev, NFC_HCI_UICC_HOST_ID, NFC_SE_UICC);
170                 se_count++;
171         }
172
173         if (info->se_status->is_ese_present) {
174                 nfc_add_se(hdev->ndev, ST21NFCA_ESE_HOST_ID, NFC_SE_EMBEDDED);
175                 se_count++;
176         }
177
178         return !se_count;
179 }
180 EXPORT_SYMBOL(st21nfca_hci_discover_se);
181
182 int st21nfca_hci_enable_se(struct nfc_hci_dev *hdev, u32 se_idx)
183 {
184         int r;
185
186         /*
187          * According to upper layer, se_idx == NFC_SE_UICC when
188          * info->se_status->is_uicc_enable is true should never happen.
189          * Same for eSE.
190          */
191         r = st21nfca_hci_control_se(hdev, se_idx, ST21NFCA_SE_MODE_ON);
192
193         if (r == ST21NFCA_ESE_HOST_ID) {
194                 st21nfca_se_get_atr(hdev);
195                 r = nfc_hci_send_event(hdev, ST21NFCA_APDU_READER_GATE,
196                                 ST21NFCA_EVT_SE_SOFT_RESET, NULL, 0);
197                 if (r < 0)
198                         return r;
199         } else if (r < 0) {
200                 /*
201                  * The activation tentative failed, the secure element
202                  * is not connected. Remove from the list.
203                  */
204                 nfc_remove_se(hdev->ndev, se_idx);
205                 return r;
206         }
207
208         return 0;
209 }
210 EXPORT_SYMBOL(st21nfca_hci_enable_se);
211
212 int st21nfca_hci_disable_se(struct nfc_hci_dev *hdev, u32 se_idx)
213 {
214         int r;
215
216         /*
217          * According to upper layer, se_idx == NFC_SE_UICC when
218          * info->se_status->is_uicc_enable is true should never happen
219          * Same for eSE.
220          */
221         r = st21nfca_hci_control_se(hdev, se_idx, ST21NFCA_SE_MODE_OFF);
222         if (r < 0)
223                 return r;
224
225         return 0;
226 }
227 EXPORT_SYMBOL(st21nfca_hci_disable_se);
228
229 int st21nfca_hci_se_io(struct nfc_hci_dev *hdev, u32 se_idx,
230                         u8 *apdu, size_t apdu_length,
231                         se_io_cb_t cb, void *cb_context)
232 {
233         struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev);
234
235         pr_debug("se_io %x\n", se_idx);
236
237         switch (se_idx) {
238         case ST21NFCA_ESE_HOST_ID:
239                 info->se_info.cb = cb;
240                 info->se_info.cb_context = cb_context;
241                 mod_timer(&info->se_info.bwi_timer, jiffies +
242                           msecs_to_jiffies(info->se_info.wt_timeout));
243                 info->se_info.bwi_active = true;
244                 return nfc_hci_send_event(hdev, ST21NFCA_APDU_READER_GATE,
245                                         ST21NFCA_EVT_TRANSMIT_DATA,
246                                         apdu, apdu_length);
247         default:
248                 return -ENODEV;
249         }
250 }
251 EXPORT_SYMBOL(st21nfca_hci_se_io);
252
253 static void st21nfca_se_wt_timeout(unsigned long data)
254 {
255         /*
256          * No answer from the secure element
257          * within the defined timeout.
258          * Let's send a reset request as recovery procedure.
259          * According to the situation, we first try to send a software reset
260          * to the secure element. If the next command is still not
261          * answering in time, we send to the CLF a secure element hardware
262          * reset request.
263          */
264         /* hardware reset managed through VCC_UICC_OUT power supply */
265         u8 param = 0x01;
266         struct st21nfca_hci_info *info = (struct st21nfca_hci_info *) data;
267
268         pr_debug("\n");
269
270         info->se_info.bwi_active = false;
271
272         if (!info->se_info.xch_error) {
273                 info->se_info.xch_error = true;
274                 nfc_hci_send_event(info->hdev, ST21NFCA_APDU_READER_GATE,
275                                 ST21NFCA_EVT_SE_SOFT_RESET, NULL, 0);
276         } else {
277                 info->se_info.xch_error = false;
278                 nfc_hci_send_event(info->hdev, ST21NFCA_DEVICE_MGNT_GATE,
279                                 ST21NFCA_EVT_SE_HARD_RESET, &param, 1);
280         }
281         info->se_info.cb(info->se_info.cb_context, NULL, 0, -ETIME);
282 }
283
284 static void st21nfca_se_activation_timeout(unsigned long data)
285 {
286         struct st21nfca_hci_info *info = (struct st21nfca_hci_info *) data;
287
288         pr_debug("\n");
289
290         info->se_info.se_active = false;
291
292         complete(&info->se_info.req_completion);
293 }
294
295 /*
296  * Returns:
297  * <= 0: driver handled the event, skb consumed
298  *    1: driver does not handle the event, please do standard processing
299  */
300 int st21nfca_connectivity_event_received(struct nfc_hci_dev *hdev, u8 host,
301                                 u8 event, struct sk_buff *skb)
302 {
303         int r = 0;
304         struct device *dev = &hdev->ndev->dev;
305         struct nfc_evt_transaction *transaction;
306
307         pr_debug("connectivity gate event: %x\n", event);
308
309         switch (event) {
310         case ST21NFCA_EVT_CONNECTIVITY:
311                 break;
312         case ST21NFCA_EVT_TRANSACTION:
313                 /*
314                  * According to specification etsi 102 622
315                  * 11.2.2.4 EVT_TRANSACTION Table 52
316                  * Description  Tag     Length
317                  * AID          81      5 to 16
318                  * PARAMETERS   82      0 to 255
319                  */
320                 if (skb->len < NFC_MIN_AID_LENGTH + 2 &&
321                     skb->data[0] != NFC_EVT_TRANSACTION_AID_TAG)
322                         return -EPROTO;
323
324                 transaction = (struct nfc_evt_transaction *)devm_kzalloc(dev,
325                                                    skb->len - 2, GFP_KERNEL);
326
327                 transaction->aid_len = skb->data[1];
328                 memcpy(transaction->aid, &skb->data[2],
329                        transaction->aid_len);
330
331                 /* Check next byte is PARAMETERS tag (82) */
332                 if (skb->data[transaction->aid_len + 2] !=
333                     NFC_EVT_TRANSACTION_PARAMS_TAG)
334                         return -EPROTO;
335
336                 transaction->params_len = skb->data[transaction->aid_len + 3];
337                 memcpy(transaction->params, skb->data +
338                        transaction->aid_len + 4, transaction->params_len);
339
340                 r = nfc_se_transaction(hdev->ndev, host, transaction);
341                 break;
342         default:
343                 return 1;
344         }
345         kfree_skb(skb);
346         return r;
347 }
348 EXPORT_SYMBOL(st21nfca_connectivity_event_received);
349
350 int st21nfca_apdu_reader_event_received(struct nfc_hci_dev *hdev,
351                                         u8 event, struct sk_buff *skb)
352 {
353         int r = 0;
354         struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev);
355
356         pr_debug("apdu reader gate event: %x\n", event);
357
358         switch (event) {
359         case ST21NFCA_EVT_TRANSMIT_DATA:
360                 del_timer_sync(&info->se_info.bwi_timer);
361                 info->se_info.bwi_active = false;
362                 r = nfc_hci_send_event(hdev, ST21NFCA_DEVICE_MGNT_GATE,
363                                 ST21NFCA_EVT_SE_END_OF_APDU_TRANSFER, NULL, 0);
364                 if (r < 0)
365                         goto exit;
366
367                 info->se_info.cb(info->se_info.cb_context,
368                         skb->data, skb->len, 0);
369                 break;
370         case ST21NFCA_EVT_WTX_REQUEST:
371                 mod_timer(&info->se_info.bwi_timer, jiffies +
372                                 msecs_to_jiffies(info->se_info.wt_timeout));
373                 break;
374         }
375
376 exit:
377         kfree_skb(skb);
378         return r;
379 }
380 EXPORT_SYMBOL(st21nfca_apdu_reader_event_received);
381
382 void st21nfca_se_init(struct nfc_hci_dev *hdev)
383 {
384         struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev);
385
386         init_completion(&info->se_info.req_completion);
387         /* initialize timers */
388         init_timer(&info->se_info.bwi_timer);
389         info->se_info.bwi_timer.data = (unsigned long)info;
390         info->se_info.bwi_timer.function = st21nfca_se_wt_timeout;
391         info->se_info.bwi_active = false;
392
393         init_timer(&info->se_info.se_active_timer);
394         info->se_info.se_active_timer.data = (unsigned long)info;
395         info->se_info.se_active_timer.function = st21nfca_se_activation_timeout;
396         info->se_info.se_active = false;
397
398         info->se_info.count_pipes = 0;
399         info->se_info.expected_pipes = 0;
400
401         info->se_info.xch_error = false;
402
403         info->se_info.wt_timeout =
404                         ST21NFCA_BWI_TO_TIMEOUT(ST21NFCA_ATR_DEFAULT_BWI);
405 }
406 EXPORT_SYMBOL(st21nfca_se_init);
407
408 void st21nfca_se_deinit(struct nfc_hci_dev *hdev)
409 {
410         struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev);
411
412         if (info->se_info.bwi_active)
413                 del_timer_sync(&info->se_info.bwi_timer);
414         if (info->se_info.se_active)
415                 del_timer_sync(&info->se_info.se_active_timer);
416
417         info->se_info.bwi_active = false;
418         info->se_info.se_active = false;
419 }
420 EXPORT_SYMBOL(st21nfca_se_deinit);