diff options
Diffstat (limited to 'net/nfc/llcp/commands.c')
-rw-r--r-- | net/nfc/llcp/commands.c | 205 |
1 files changed, 169 insertions, 36 deletions
diff --git a/net/nfc/llcp/commands.c b/net/nfc/llcp/commands.c index c6bc3bd95052..b75a9b3f9e89 100644 --- a/net/nfc/llcp/commands.c +++ b/net/nfc/llcp/commands.c | |||
@@ -117,6 +117,88 @@ u8 *nfc_llcp_build_tlv(u8 type, u8 *value, u8 value_length, u8 *tlv_length) | |||
117 | return tlv; | 117 | return tlv; |
118 | } | 118 | } |
119 | 119 | ||
120 | struct nfc_llcp_sdp_tlv *nfc_llcp_build_sdres_tlv(u8 tid, u8 sap) | ||
121 | { | ||
122 | struct nfc_llcp_sdp_tlv *sdres; | ||
123 | u8 value[2]; | ||
124 | |||
125 | sdres = kzalloc(sizeof(struct nfc_llcp_sdp_tlv), GFP_KERNEL); | ||
126 | if (sdres == NULL) | ||
127 | return NULL; | ||
128 | |||
129 | value[0] = tid; | ||
130 | value[1] = sap; | ||
131 | |||
132 | sdres->tlv = nfc_llcp_build_tlv(LLCP_TLV_SDRES, value, 2, | ||
133 | &sdres->tlv_len); | ||
134 | if (sdres->tlv == NULL) { | ||
135 | kfree(sdres); | ||
136 | return NULL; | ||
137 | } | ||
138 | |||
139 | sdres->tid = tid; | ||
140 | sdres->sap = sap; | ||
141 | |||
142 | INIT_HLIST_NODE(&sdres->node); | ||
143 | |||
144 | return sdres; | ||
145 | } | ||
146 | |||
147 | struct nfc_llcp_sdp_tlv *nfc_llcp_build_sdreq_tlv(u8 tid, char *uri, | ||
148 | size_t uri_len) | ||
149 | { | ||
150 | struct nfc_llcp_sdp_tlv *sdreq; | ||
151 | |||
152 | pr_debug("uri: %s, len: %zu\n", uri, uri_len); | ||
153 | |||
154 | sdreq = kzalloc(sizeof(struct nfc_llcp_sdp_tlv), GFP_KERNEL); | ||
155 | if (sdreq == NULL) | ||
156 | return NULL; | ||
157 | |||
158 | sdreq->tlv_len = uri_len + 3; | ||
159 | |||
160 | if (uri[uri_len - 1] == 0) | ||
161 | sdreq->tlv_len--; | ||
162 | |||
163 | sdreq->tlv = kzalloc(sdreq->tlv_len + 1, GFP_KERNEL); | ||
164 | if (sdreq->tlv == NULL) { | ||
165 | kfree(sdreq); | ||
166 | return NULL; | ||
167 | } | ||
168 | |||
169 | sdreq->tlv[0] = LLCP_TLV_SDREQ; | ||
170 | sdreq->tlv[1] = sdreq->tlv_len - 2; | ||
171 | sdreq->tlv[2] = tid; | ||
172 | |||
173 | sdreq->tid = tid; | ||
174 | sdreq->uri = sdreq->tlv + 3; | ||
175 | memcpy(sdreq->uri, uri, uri_len); | ||
176 | |||
177 | sdreq->time = jiffies; | ||
178 | |||
179 | INIT_HLIST_NODE(&sdreq->node); | ||
180 | |||
181 | return sdreq; | ||
182 | } | ||
183 | |||
184 | void nfc_llcp_free_sdp_tlv(struct nfc_llcp_sdp_tlv *sdp) | ||
185 | { | ||
186 | kfree(sdp->tlv); | ||
187 | kfree(sdp); | ||
188 | } | ||
189 | |||
190 | void nfc_llcp_free_sdp_tlv_list(struct hlist_head *head) | ||
191 | { | ||
192 | struct nfc_llcp_sdp_tlv *sdp; | ||
193 | struct hlist_node *n; | ||
194 | |||
195 | hlist_for_each_entry_safe(sdp, n, head, node) { | ||
196 | hlist_del(&sdp->node); | ||
197 | |||
198 | nfc_llcp_free_sdp_tlv(sdp); | ||
199 | } | ||
200 | } | ||
201 | |||
120 | int nfc_llcp_parse_gb_tlv(struct nfc_llcp_local *local, | 202 | int nfc_llcp_parse_gb_tlv(struct nfc_llcp_local *local, |
121 | u8 *tlv_array, u16 tlv_array_len) | 203 | u8 *tlv_array, u16 tlv_array_len) |
122 | { | 204 | { |
@@ -184,10 +266,10 @@ int nfc_llcp_parse_connection_tlv(struct nfc_llcp_sock *sock, | |||
184 | 266 | ||
185 | switch (type) { | 267 | switch (type) { |
186 | case LLCP_TLV_MIUX: | 268 | case LLCP_TLV_MIUX: |
187 | sock->miu = llcp_tlv_miux(tlv) + 128; | 269 | sock->remote_miu = llcp_tlv_miux(tlv) + 128; |
188 | break; | 270 | break; |
189 | case LLCP_TLV_RW: | 271 | case LLCP_TLV_RW: |
190 | sock->rw = llcp_tlv_rw(tlv); | 272 | sock->remote_rw = llcp_tlv_rw(tlv); |
191 | break; | 273 | break; |
192 | case LLCP_TLV_SN: | 274 | case LLCP_TLV_SN: |
193 | break; | 275 | break; |
@@ -200,7 +282,8 @@ int nfc_llcp_parse_connection_tlv(struct nfc_llcp_sock *sock, | |||
200 | tlv += length + 2; | 282 | tlv += length + 2; |
201 | } | 283 | } |
202 | 284 | ||
203 | pr_debug("sock %p rw %d miu %d\n", sock, sock->rw, sock->miu); | 285 | pr_debug("sock %p rw %d miu %d\n", sock, |
286 | sock->remote_rw, sock->remote_miu); | ||
204 | 287 | ||
205 | return 0; | 288 | return 0; |
206 | } | 289 | } |
@@ -318,9 +401,9 @@ int nfc_llcp_send_connect(struct nfc_llcp_sock *sock) | |||
318 | struct sk_buff *skb; | 401 | struct sk_buff *skb; |
319 | u8 *service_name_tlv = NULL, service_name_tlv_length; | 402 | u8 *service_name_tlv = NULL, service_name_tlv_length; |
320 | u8 *miux_tlv = NULL, miux_tlv_length; | 403 | u8 *miux_tlv = NULL, miux_tlv_length; |
321 | u8 *rw_tlv = NULL, rw_tlv_length; | 404 | u8 *rw_tlv = NULL, rw_tlv_length, rw; |
322 | int err; | 405 | int err; |
323 | u16 size = 0; | 406 | u16 size = 0, miux; |
324 | 407 | ||
325 | pr_debug("Sending CONNECT\n"); | 408 | pr_debug("Sending CONNECT\n"); |
326 | 409 | ||
@@ -336,11 +419,15 @@ int nfc_llcp_send_connect(struct nfc_llcp_sock *sock) | |||
336 | size += service_name_tlv_length; | 419 | size += service_name_tlv_length; |
337 | } | 420 | } |
338 | 421 | ||
339 | miux_tlv = nfc_llcp_build_tlv(LLCP_TLV_MIUX, (u8 *)&local->miux, 0, | 422 | /* If the socket parameters are not set, use the local ones */ |
423 | miux = sock->miux > LLCP_MAX_MIUX ? local->miux : sock->miux; | ||
424 | rw = sock->rw > LLCP_MAX_RW ? local->rw : sock->rw; | ||
425 | |||
426 | miux_tlv = nfc_llcp_build_tlv(LLCP_TLV_MIUX, (u8 *)&miux, 0, | ||
340 | &miux_tlv_length); | 427 | &miux_tlv_length); |
341 | size += miux_tlv_length; | 428 | size += miux_tlv_length; |
342 | 429 | ||
343 | rw_tlv = nfc_llcp_build_tlv(LLCP_TLV_RW, &local->rw, 0, &rw_tlv_length); | 430 | rw_tlv = nfc_llcp_build_tlv(LLCP_TLV_RW, &rw, 0, &rw_tlv_length); |
344 | size += rw_tlv_length; | 431 | size += rw_tlv_length; |
345 | 432 | ||
346 | pr_debug("SKB size %d SN length %zu\n", size, sock->service_name_len); | 433 | pr_debug("SKB size %d SN length %zu\n", size, sock->service_name_len); |
@@ -377,9 +464,9 @@ int nfc_llcp_send_cc(struct nfc_llcp_sock *sock) | |||
377 | struct nfc_llcp_local *local; | 464 | struct nfc_llcp_local *local; |
378 | struct sk_buff *skb; | 465 | struct sk_buff *skb; |
379 | u8 *miux_tlv = NULL, miux_tlv_length; | 466 | u8 *miux_tlv = NULL, miux_tlv_length; |
380 | u8 *rw_tlv = NULL, rw_tlv_length; | 467 | u8 *rw_tlv = NULL, rw_tlv_length, rw; |
381 | int err; | 468 | int err; |
382 | u16 size = 0; | 469 | u16 size = 0, miux; |
383 | 470 | ||
384 | pr_debug("Sending CC\n"); | 471 | pr_debug("Sending CC\n"); |
385 | 472 | ||
@@ -387,11 +474,15 @@ int nfc_llcp_send_cc(struct nfc_llcp_sock *sock) | |||
387 | if (local == NULL) | 474 | if (local == NULL) |
388 | return -ENODEV; | 475 | return -ENODEV; |
389 | 476 | ||
390 | miux_tlv = nfc_llcp_build_tlv(LLCP_TLV_MIUX, (u8 *)&local->miux, 0, | 477 | /* If the socket parameters are not set, use the local ones */ |
478 | miux = sock->miux > LLCP_MAX_MIUX ? local->miux : sock->miux; | ||
479 | rw = sock->rw > LLCP_MAX_RW ? local->rw : sock->rw; | ||
480 | |||
481 | miux_tlv = nfc_llcp_build_tlv(LLCP_TLV_MIUX, (u8 *)&miux, 0, | ||
391 | &miux_tlv_length); | 482 | &miux_tlv_length); |
392 | size += miux_tlv_length; | 483 | size += miux_tlv_length; |
393 | 484 | ||
394 | rw_tlv = nfc_llcp_build_tlv(LLCP_TLV_RW, &local->rw, 0, &rw_tlv_length); | 485 | rw_tlv = nfc_llcp_build_tlv(LLCP_TLV_RW, &rw, 0, &rw_tlv_length); |
395 | size += rw_tlv_length; | 486 | size += rw_tlv_length; |
396 | 487 | ||
397 | skb = llcp_allocate_pdu(sock, LLCP_PDU_CC, size); | 488 | skb = llcp_allocate_pdu(sock, LLCP_PDU_CC, size); |
@@ -416,48 +507,90 @@ error_tlv: | |||
416 | return err; | 507 | return err; |
417 | } | 508 | } |
418 | 509 | ||
419 | int nfc_llcp_send_snl(struct nfc_llcp_local *local, u8 tid, u8 sap) | 510 | static struct sk_buff *nfc_llcp_allocate_snl(struct nfc_llcp_local *local, |
511 | size_t tlv_length) | ||
420 | { | 512 | { |
421 | struct sk_buff *skb; | 513 | struct sk_buff *skb; |
422 | struct nfc_dev *dev; | 514 | struct nfc_dev *dev; |
423 | u8 *sdres_tlv = NULL, sdres_tlv_length, sdres[2]; | ||
424 | u16 size = 0; | 515 | u16 size = 0; |
425 | 516 | ||
426 | pr_debug("Sending SNL tid 0x%x sap 0x%x\n", tid, sap); | ||
427 | |||
428 | if (local == NULL) | 517 | if (local == NULL) |
429 | return -ENODEV; | 518 | return ERR_PTR(-ENODEV); |
430 | 519 | ||
431 | dev = local->dev; | 520 | dev = local->dev; |
432 | if (dev == NULL) | 521 | if (dev == NULL) |
433 | return -ENODEV; | 522 | return ERR_PTR(-ENODEV); |
434 | |||
435 | sdres[0] = tid; | ||
436 | sdres[1] = sap; | ||
437 | sdres_tlv = nfc_llcp_build_tlv(LLCP_TLV_SDRES, sdres, 0, | ||
438 | &sdres_tlv_length); | ||
439 | if (sdres_tlv == NULL) | ||
440 | return -ENOMEM; | ||
441 | 523 | ||
442 | size += LLCP_HEADER_SIZE; | 524 | size += LLCP_HEADER_SIZE; |
443 | size += dev->tx_headroom + dev->tx_tailroom + NFC_HEADER_SIZE; | 525 | size += dev->tx_headroom + dev->tx_tailroom + NFC_HEADER_SIZE; |
444 | size += sdres_tlv_length; | 526 | size += tlv_length; |
445 | 527 | ||
446 | skb = alloc_skb(size, GFP_KERNEL); | 528 | skb = alloc_skb(size, GFP_KERNEL); |
447 | if (skb == NULL) { | 529 | if (skb == NULL) |
448 | kfree(sdres_tlv); | 530 | return ERR_PTR(-ENOMEM); |
449 | return -ENOMEM; | ||
450 | } | ||
451 | 531 | ||
452 | skb_reserve(skb, dev->tx_headroom + NFC_HEADER_SIZE); | 532 | skb_reserve(skb, dev->tx_headroom + NFC_HEADER_SIZE); |
453 | 533 | ||
454 | skb = llcp_add_header(skb, LLCP_SAP_SDP, LLCP_SAP_SDP, LLCP_PDU_SNL); | 534 | skb = llcp_add_header(skb, LLCP_SAP_SDP, LLCP_SAP_SDP, LLCP_PDU_SNL); |
455 | 535 | ||
456 | memcpy(skb_put(skb, sdres_tlv_length), sdres_tlv, sdres_tlv_length); | 536 | return skb; |
537 | } | ||
538 | |||
539 | int nfc_llcp_send_snl_sdres(struct nfc_llcp_local *local, | ||
540 | struct hlist_head *tlv_list, size_t tlvs_len) | ||
541 | { | ||
542 | struct nfc_llcp_sdp_tlv *sdp; | ||
543 | struct hlist_node *n; | ||
544 | struct sk_buff *skb; | ||
545 | |||
546 | skb = nfc_llcp_allocate_snl(local, tlvs_len); | ||
547 | if (IS_ERR(skb)) | ||
548 | return PTR_ERR(skb); | ||
549 | |||
550 | hlist_for_each_entry_safe(sdp, n, tlv_list, node) { | ||
551 | memcpy(skb_put(skb, sdp->tlv_len), sdp->tlv, sdp->tlv_len); | ||
552 | |||
553 | hlist_del(&sdp->node); | ||
554 | |||
555 | nfc_llcp_free_sdp_tlv(sdp); | ||
556 | } | ||
457 | 557 | ||
458 | skb_queue_tail(&local->tx_queue, skb); | 558 | skb_queue_tail(&local->tx_queue, skb); |
459 | 559 | ||
460 | kfree(sdres_tlv); | 560 | return 0; |
561 | } | ||
562 | |||
563 | int nfc_llcp_send_snl_sdreq(struct nfc_llcp_local *local, | ||
564 | struct hlist_head *tlv_list, size_t tlvs_len) | ||
565 | { | ||
566 | struct nfc_llcp_sdp_tlv *sdreq; | ||
567 | struct hlist_node *n; | ||
568 | struct sk_buff *skb; | ||
569 | |||
570 | skb = nfc_llcp_allocate_snl(local, tlvs_len); | ||
571 | if (IS_ERR(skb)) | ||
572 | return PTR_ERR(skb); | ||
573 | |||
574 | mutex_lock(&local->sdreq_lock); | ||
575 | |||
576 | if (hlist_empty(&local->pending_sdreqs)) | ||
577 | mod_timer(&local->sdreq_timer, | ||
578 | jiffies + msecs_to_jiffies(3 * local->remote_lto)); | ||
579 | |||
580 | hlist_for_each_entry_safe(sdreq, n, tlv_list, node) { | ||
581 | pr_debug("tid %d for %s\n", sdreq->tid, sdreq->uri); | ||
582 | |||
583 | memcpy(skb_put(skb, sdreq->tlv_len), sdreq->tlv, | ||
584 | sdreq->tlv_len); | ||
585 | |||
586 | hlist_del(&sdreq->node); | ||
587 | |||
588 | hlist_add_head(&sdreq->node, &local->pending_sdreqs); | ||
589 | } | ||
590 | |||
591 | mutex_unlock(&local->sdreq_lock); | ||
592 | |||
593 | skb_queue_tail(&local->tx_queue, skb); | ||
461 | 594 | ||
462 | return 0; | 595 | return 0; |
463 | } | 596 | } |
@@ -532,8 +665,8 @@ int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock, | |||
532 | 665 | ||
533 | /* Remote is ready but has not acknowledged our frames */ | 666 | /* Remote is ready but has not acknowledged our frames */ |
534 | if((sock->remote_ready && | 667 | if((sock->remote_ready && |
535 | skb_queue_len(&sock->tx_pending_queue) >= sock->rw && | 668 | skb_queue_len(&sock->tx_pending_queue) >= sock->remote_rw && |
536 | skb_queue_len(&sock->tx_queue) >= 2 * sock->rw)) { | 669 | skb_queue_len(&sock->tx_queue) >= 2 * sock->remote_rw)) { |
537 | pr_err("Pending queue is full %d frames\n", | 670 | pr_err("Pending queue is full %d frames\n", |
538 | skb_queue_len(&sock->tx_pending_queue)); | 671 | skb_queue_len(&sock->tx_pending_queue)); |
539 | return -ENOBUFS; | 672 | return -ENOBUFS; |
@@ -541,7 +674,7 @@ int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock, | |||
541 | 674 | ||
542 | /* Remote is not ready and we've been queueing enough frames */ | 675 | /* Remote is not ready and we've been queueing enough frames */ |
543 | if ((!sock->remote_ready && | 676 | if ((!sock->remote_ready && |
544 | skb_queue_len(&sock->tx_queue) >= 2 * sock->rw)) { | 677 | skb_queue_len(&sock->tx_queue) >= 2 * sock->remote_rw)) { |
545 | pr_err("Tx queue is full %d frames\n", | 678 | pr_err("Tx queue is full %d frames\n", |
546 | skb_queue_len(&sock->tx_queue)); | 679 | skb_queue_len(&sock->tx_queue)); |
547 | return -ENOBUFS; | 680 | return -ENOBUFS; |
@@ -561,7 +694,7 @@ int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock, | |||
561 | 694 | ||
562 | while (remaining_len > 0) { | 695 | while (remaining_len > 0) { |
563 | 696 | ||
564 | frag_len = min_t(size_t, sock->miu, remaining_len); | 697 | frag_len = min_t(size_t, sock->remote_miu, remaining_len); |
565 | 698 | ||
566 | pr_debug("Fragment %zd bytes remaining %zd", | 699 | pr_debug("Fragment %zd bytes remaining %zd", |
567 | frag_len, remaining_len); | 700 | frag_len, remaining_len); |
@@ -621,7 +754,7 @@ int nfc_llcp_send_ui_frame(struct nfc_llcp_sock *sock, u8 ssap, u8 dsap, | |||
621 | 754 | ||
622 | while (remaining_len > 0) { | 755 | while (remaining_len > 0) { |
623 | 756 | ||
624 | frag_len = min_t(size_t, sock->miu, remaining_len); | 757 | frag_len = min_t(size_t, sock->remote_miu, remaining_len); |
625 | 758 | ||
626 | pr_debug("Fragment %zd bytes remaining %zd", | 759 | pr_debug("Fragment %zd bytes remaining %zd", |
627 | frag_len, remaining_len); | 760 | frag_len, remaining_len); |