| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * 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 | 4 | */ |
|---|
| 16 | 5 | |
|---|
| 17 | 6 | #include <net/nfc/hci.h> |
|---|
| .. | .. |
|---|
| 252 | 241 | } |
|---|
| 253 | 242 | EXPORT_SYMBOL(st21nfca_hci_se_io); |
|---|
| 254 | 243 | |
|---|
| 255 | | -static void st21nfca_se_wt_timeout(struct timer_list *t) |
|---|
| 244 | +static void st21nfca_se_wt_work(struct work_struct *work) |
|---|
| 256 | 245 | { |
|---|
| 257 | 246 | /* |
|---|
| 258 | 247 | * No answer from the secure element |
|---|
| .. | .. |
|---|
| 265 | 254 | */ |
|---|
| 266 | 255 | /* hardware reset managed through VCC_UICC_OUT power supply */ |
|---|
| 267 | 256 | u8 param = 0x01; |
|---|
| 268 | | - struct st21nfca_hci_info *info = from_timer(info, t, |
|---|
| 269 | | - se_info.bwi_timer); |
|---|
| 257 | + struct st21nfca_hci_info *info = container_of(work, |
|---|
| 258 | + struct st21nfca_hci_info, |
|---|
| 259 | + se_info.timeout_work); |
|---|
| 270 | 260 | |
|---|
| 271 | 261 | pr_debug("\n"); |
|---|
| 272 | 262 | |
|---|
| .. | .. |
|---|
| 282 | 272 | ST21NFCA_EVT_SE_HARD_RESET, ¶m, 1); |
|---|
| 283 | 273 | } |
|---|
| 284 | 274 | info->se_info.cb(info->se_info.cb_context, NULL, 0, -ETIME); |
|---|
| 275 | +} |
|---|
| 276 | + |
|---|
| 277 | +static void st21nfca_se_wt_timeout(struct timer_list *t) |
|---|
| 278 | +{ |
|---|
| 279 | + struct st21nfca_hci_info *info = from_timer(info, t, se_info.bwi_timer); |
|---|
| 280 | + |
|---|
| 281 | + schedule_work(&info->se_info.timeout_work); |
|---|
| 285 | 282 | } |
|---|
| 286 | 283 | |
|---|
| 287 | 284 | static void st21nfca_se_activation_timeout(struct timer_list *t) |
|---|
| .. | .. |
|---|
| 307 | 304 | int r = 0; |
|---|
| 308 | 305 | struct device *dev = &hdev->ndev->dev; |
|---|
| 309 | 306 | struct nfc_evt_transaction *transaction; |
|---|
| 307 | + u32 aid_len; |
|---|
| 308 | + u8 params_len; |
|---|
| 310 | 309 | |
|---|
| 311 | 310 | pr_debug("connectivity gate event: %x\n", event); |
|---|
| 312 | 311 | |
|---|
| .. | .. |
|---|
| 315 | 314 | r = nfc_se_connectivity(hdev->ndev, host); |
|---|
| 316 | 315 | break; |
|---|
| 317 | 316 | case ST21NFCA_EVT_TRANSACTION: |
|---|
| 318 | | - /* |
|---|
| 319 | | - * According to specification etsi 102 622 |
|---|
| 317 | + /* According to specification etsi 102 622 |
|---|
| 320 | 318 | * 11.2.2.4 EVT_TRANSACTION Table 52 |
|---|
| 321 | 319 | * Description Tag Length |
|---|
| 322 | 320 | * AID 81 5 to 16 |
|---|
| 323 | 321 | * PARAMETERS 82 0 to 255 |
|---|
| 322 | + * |
|---|
| 323 | + * The key differences are aid storage length is variably sized |
|---|
| 324 | + * in the packet, but fixed in nfc_evt_transaction, and that the aid_len |
|---|
| 325 | + * is u8 in the packet, but u32 in the structure, and the tags in |
|---|
| 326 | + * the packet are not included in nfc_evt_transaction. |
|---|
| 327 | + * |
|---|
| 328 | + * size in bytes: 1 1 5-16 1 1 0-255 |
|---|
| 329 | + * offset: 0 1 2 aid_len + 2 aid_len + 3 aid_len + 4 |
|---|
| 330 | + * member name: aid_tag(M) aid_len aid params_tag(M) params_len params |
|---|
| 331 | + * example: 0x81 5-16 X 0x82 0-255 X |
|---|
| 324 | 332 | */ |
|---|
| 325 | | - if (skb->len < NFC_MIN_AID_LENGTH + 2 && |
|---|
| 326 | | - skb->data[0] != NFC_EVT_TRANSACTION_AID_TAG) |
|---|
| 333 | + if (skb->len < 2 || skb->data[0] != NFC_EVT_TRANSACTION_AID_TAG) |
|---|
| 327 | 334 | return -EPROTO; |
|---|
| 328 | 335 | |
|---|
| 329 | | - transaction = (struct nfc_evt_transaction *)devm_kzalloc(dev, |
|---|
| 330 | | - skb->len - 2, GFP_KERNEL); |
|---|
| 336 | + aid_len = skb->data[1]; |
|---|
| 337 | + |
|---|
| 338 | + if (skb->len < aid_len + 4 || aid_len > sizeof(transaction->aid)) |
|---|
| 339 | + return -EPROTO; |
|---|
| 340 | + |
|---|
| 341 | + params_len = skb->data[aid_len + 3]; |
|---|
| 342 | + |
|---|
| 343 | + /* Verify PARAMETERS tag is (82), and final check that there is enough |
|---|
| 344 | + * space in the packet to read everything. |
|---|
| 345 | + */ |
|---|
| 346 | + if ((skb->data[aid_len + 2] != NFC_EVT_TRANSACTION_PARAMS_TAG) || |
|---|
| 347 | + (skb->len < aid_len + 4 + params_len)) |
|---|
| 348 | + return -EPROTO; |
|---|
| 349 | + |
|---|
| 350 | + transaction = devm_kzalloc(dev, sizeof(*transaction) + params_len, GFP_KERNEL); |
|---|
| 331 | 351 | if (!transaction) |
|---|
| 332 | 352 | return -ENOMEM; |
|---|
| 333 | 353 | |
|---|
| 334 | | - transaction->aid_len = skb->data[1]; |
|---|
| 335 | | - memcpy(transaction->aid, &skb->data[2], |
|---|
| 336 | | - transaction->aid_len); |
|---|
| 354 | + transaction->aid_len = aid_len; |
|---|
| 355 | + transaction->params_len = params_len; |
|---|
| 337 | 356 | |
|---|
| 338 | | - /* Check next byte is PARAMETERS tag (82) */ |
|---|
| 339 | | - if (skb->data[transaction->aid_len + 2] != |
|---|
| 340 | | - NFC_EVT_TRANSACTION_PARAMS_TAG) |
|---|
| 341 | | - return -EPROTO; |
|---|
| 342 | | - |
|---|
| 343 | | - transaction->params_len = skb->data[transaction->aid_len + 3]; |
|---|
| 344 | | - memcpy(transaction->params, skb->data + |
|---|
| 345 | | - transaction->aid_len + 4, transaction->params_len); |
|---|
| 357 | + memcpy(transaction->aid, &skb->data[2], aid_len); |
|---|
| 358 | + memcpy(transaction->params, &skb->data[aid_len + 4], params_len); |
|---|
| 346 | 359 | |
|---|
| 347 | 360 | r = nfc_se_transaction(hdev->ndev, host, transaction); |
|---|
| 348 | 361 | break; |
|---|
| .. | .. |
|---|
| 366 | 379 | switch (event) { |
|---|
| 367 | 380 | case ST21NFCA_EVT_TRANSMIT_DATA: |
|---|
| 368 | 381 | del_timer_sync(&info->se_info.bwi_timer); |
|---|
| 382 | + cancel_work_sync(&info->se_info.timeout_work); |
|---|
| 369 | 383 | info->se_info.bwi_active = false; |
|---|
| 370 | 384 | r = nfc_hci_send_event(hdev, ST21NFCA_DEVICE_MGNT_GATE, |
|---|
| 371 | 385 | ST21NFCA_EVT_SE_END_OF_APDU_TRANSFER, NULL, 0); |
|---|
| .. | .. |
|---|
| 395 | 409 | struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev); |
|---|
| 396 | 410 | |
|---|
| 397 | 411 | init_completion(&info->se_info.req_completion); |
|---|
| 412 | + INIT_WORK(&info->se_info.timeout_work, st21nfca_se_wt_work); |
|---|
| 398 | 413 | /* initialize timers */ |
|---|
| 399 | 414 | timer_setup(&info->se_info.bwi_timer, st21nfca_se_wt_timeout, 0); |
|---|
| 400 | 415 | info->se_info.bwi_active = false; |
|---|
| .. | .. |
|---|
| 422 | 437 | if (info->se_info.se_active) |
|---|
| 423 | 438 | del_timer_sync(&info->se_info.se_active_timer); |
|---|
| 424 | 439 | |
|---|
| 440 | + cancel_work_sync(&info->se_info.timeout_work); |
|---|
| 425 | 441 | info->se_info.bwi_active = false; |
|---|
| 426 | 442 | info->se_info.se_active = false; |
|---|
| 427 | 443 | } |
|---|