diff options
Diffstat (limited to 'net/nfc/llcp')
-rw-r--r-- | net/nfc/llcp/commands.c | 205 | ||||
-rw-r--r-- | net/nfc/llcp/llcp.c | 112 | ||||
-rw-r--r-- | net/nfc/llcp/llcp.h | 36 | ||||
-rw-r--r-- | net/nfc/llcp/sock.c | 130 |
4 files changed, 430 insertions, 53 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); |
diff --git a/net/nfc/llcp/llcp.c b/net/nfc/llcp/llcp.c index ee25f25f0cd6..7de0368aff0c 100644 --- a/net/nfc/llcp/llcp.c +++ b/net/nfc/llcp/llcp.c | |||
@@ -182,6 +182,9 @@ static void local_cleanup(struct nfc_llcp_local *local, bool listen) | |||
182 | cancel_work_sync(&local->rx_work); | 182 | cancel_work_sync(&local->rx_work); |
183 | cancel_work_sync(&local->timeout_work); | 183 | cancel_work_sync(&local->timeout_work); |
184 | kfree_skb(local->rx_pending); | 184 | kfree_skb(local->rx_pending); |
185 | del_timer_sync(&local->sdreq_timer); | ||
186 | cancel_work_sync(&local->sdreq_timeout_work); | ||
187 | nfc_llcp_free_sdp_tlv_list(&local->pending_sdreqs); | ||
185 | } | 188 | } |
186 | 189 | ||
187 | static void local_release(struct kref *ref) | 190 | static void local_release(struct kref *ref) |
@@ -259,6 +262,47 @@ static void nfc_llcp_symm_timer(unsigned long data) | |||
259 | schedule_work(&local->timeout_work); | 262 | schedule_work(&local->timeout_work); |
260 | } | 263 | } |
261 | 264 | ||
265 | static void nfc_llcp_sdreq_timeout_work(struct work_struct *work) | ||
266 | { | ||
267 | unsigned long time; | ||
268 | HLIST_HEAD(nl_sdres_list); | ||
269 | struct hlist_node *n; | ||
270 | struct nfc_llcp_sdp_tlv *sdp; | ||
271 | struct nfc_llcp_local *local = container_of(work, struct nfc_llcp_local, | ||
272 | sdreq_timeout_work); | ||
273 | |||
274 | mutex_lock(&local->sdreq_lock); | ||
275 | |||
276 | time = jiffies - msecs_to_jiffies(3 * local->remote_lto); | ||
277 | |||
278 | hlist_for_each_entry_safe(sdp, n, &local->pending_sdreqs, node) { | ||
279 | if (time_after(sdp->time, time)) | ||
280 | continue; | ||
281 | |||
282 | sdp->sap = LLCP_SDP_UNBOUND; | ||
283 | |||
284 | hlist_del(&sdp->node); | ||
285 | |||
286 | hlist_add_head(&sdp->node, &nl_sdres_list); | ||
287 | } | ||
288 | |||
289 | if (!hlist_empty(&local->pending_sdreqs)) | ||
290 | mod_timer(&local->sdreq_timer, | ||
291 | jiffies + msecs_to_jiffies(3 * local->remote_lto)); | ||
292 | |||
293 | mutex_unlock(&local->sdreq_lock); | ||
294 | |||
295 | if (!hlist_empty(&nl_sdres_list)) | ||
296 | nfc_genl_llc_send_sdres(local->dev, &nl_sdres_list); | ||
297 | } | ||
298 | |||
299 | static void nfc_llcp_sdreq_timer(unsigned long data) | ||
300 | { | ||
301 | struct nfc_llcp_local *local = (struct nfc_llcp_local *) data; | ||
302 | |||
303 | schedule_work(&local->sdreq_timeout_work); | ||
304 | } | ||
305 | |||
262 | struct nfc_llcp_local *nfc_llcp_find_local(struct nfc_dev *dev) | 306 | struct nfc_llcp_local *nfc_llcp_find_local(struct nfc_dev *dev) |
263 | { | 307 | { |
264 | struct nfc_llcp_local *local, *n; | 308 | struct nfc_llcp_local *local, *n; |
@@ -802,8 +846,6 @@ static void nfc_llcp_recv_ui(struct nfc_llcp_local *local, | |||
802 | ui_cb->dsap = dsap; | 846 | ui_cb->dsap = dsap; |
803 | ui_cb->ssap = ssap; | 847 | ui_cb->ssap = ssap; |
804 | 848 | ||
805 | printk("%s %d %d\n", __func__, dsap, ssap); | ||
806 | |||
807 | pr_debug("%d %d\n", dsap, ssap); | 849 | pr_debug("%d %d\n", dsap, ssap); |
808 | 850 | ||
809 | /* We're looking for a bound socket, not a client one */ | 851 | /* We're looking for a bound socket, not a client one */ |
@@ -900,7 +942,9 @@ static void nfc_llcp_recv_connect(struct nfc_llcp_local *local, | |||
900 | new_sock = nfc_llcp_sock(new_sk); | 942 | new_sock = nfc_llcp_sock(new_sk); |
901 | new_sock->dev = local->dev; | 943 | new_sock->dev = local->dev; |
902 | new_sock->local = nfc_llcp_local_get(local); | 944 | new_sock->local = nfc_llcp_local_get(local); |
903 | new_sock->miu = local->remote_miu; | 945 | new_sock->rw = sock->rw; |
946 | new_sock->miux = sock->miux; | ||
947 | new_sock->remote_miu = local->remote_miu; | ||
904 | new_sock->nfc_protocol = sock->nfc_protocol; | 948 | new_sock->nfc_protocol = sock->nfc_protocol; |
905 | new_sock->dsap = ssap; | 949 | new_sock->dsap = ssap; |
906 | new_sock->target_idx = local->target_idx; | 950 | new_sock->target_idx = local->target_idx; |
@@ -954,11 +998,11 @@ int nfc_llcp_queue_i_frames(struct nfc_llcp_sock *sock) | |||
954 | 998 | ||
955 | pr_debug("Remote ready %d tx queue len %d remote rw %d", | 999 | pr_debug("Remote ready %d tx queue len %d remote rw %d", |
956 | sock->remote_ready, skb_queue_len(&sock->tx_pending_queue), | 1000 | sock->remote_ready, skb_queue_len(&sock->tx_pending_queue), |
957 | sock->rw); | 1001 | sock->remote_rw); |
958 | 1002 | ||
959 | /* Try to queue some I frames for transmission */ | 1003 | /* Try to queue some I frames for transmission */ |
960 | while (sock->remote_ready && | 1004 | while (sock->remote_ready && |
961 | skb_queue_len(&sock->tx_pending_queue) < sock->rw) { | 1005 | skb_queue_len(&sock->tx_pending_queue) < sock->remote_rw) { |
962 | struct sk_buff *pdu; | 1006 | struct sk_buff *pdu; |
963 | 1007 | ||
964 | pdu = skb_dequeue(&sock->tx_queue); | 1008 | pdu = skb_dequeue(&sock->tx_queue); |
@@ -1178,6 +1222,10 @@ static void nfc_llcp_recv_snl(struct nfc_llcp_local *local, | |||
1178 | u16 tlv_len, offset; | 1222 | u16 tlv_len, offset; |
1179 | char *service_name; | 1223 | char *service_name; |
1180 | size_t service_name_len; | 1224 | size_t service_name_len; |
1225 | struct nfc_llcp_sdp_tlv *sdp; | ||
1226 | HLIST_HEAD(llc_sdres_list); | ||
1227 | size_t sdres_tlvs_len; | ||
1228 | HLIST_HEAD(nl_sdres_list); | ||
1181 | 1229 | ||
1182 | dsap = nfc_llcp_dsap(skb); | 1230 | dsap = nfc_llcp_dsap(skb); |
1183 | ssap = nfc_llcp_ssap(skb); | 1231 | ssap = nfc_llcp_ssap(skb); |
@@ -1192,6 +1240,7 @@ static void nfc_llcp_recv_snl(struct nfc_llcp_local *local, | |||
1192 | tlv = &skb->data[LLCP_HEADER_SIZE]; | 1240 | tlv = &skb->data[LLCP_HEADER_SIZE]; |
1193 | tlv_len = skb->len - LLCP_HEADER_SIZE; | 1241 | tlv_len = skb->len - LLCP_HEADER_SIZE; |
1194 | offset = 0; | 1242 | offset = 0; |
1243 | sdres_tlvs_len = 0; | ||
1195 | 1244 | ||
1196 | while (offset < tlv_len) { | 1245 | while (offset < tlv_len) { |
1197 | type = tlv[0]; | 1246 | type = tlv[0]; |
@@ -1209,14 +1258,14 @@ static void nfc_llcp_recv_snl(struct nfc_llcp_local *local, | |||
1209 | !strncmp(service_name, "urn:nfc:sn:sdp", | 1258 | !strncmp(service_name, "urn:nfc:sn:sdp", |
1210 | service_name_len)) { | 1259 | service_name_len)) { |
1211 | sap = 1; | 1260 | sap = 1; |
1212 | goto send_snl; | 1261 | goto add_snl; |
1213 | } | 1262 | } |
1214 | 1263 | ||
1215 | llcp_sock = nfc_llcp_sock_from_sn(local, service_name, | 1264 | llcp_sock = nfc_llcp_sock_from_sn(local, service_name, |
1216 | service_name_len); | 1265 | service_name_len); |
1217 | if (!llcp_sock) { | 1266 | if (!llcp_sock) { |
1218 | sap = 0; | 1267 | sap = 0; |
1219 | goto send_snl; | 1268 | goto add_snl; |
1220 | } | 1269 | } |
1221 | 1270 | ||
1222 | /* | 1271 | /* |
@@ -1233,7 +1282,7 @@ static void nfc_llcp_recv_snl(struct nfc_llcp_local *local, | |||
1233 | 1282 | ||
1234 | if (sap == LLCP_SAP_MAX) { | 1283 | if (sap == LLCP_SAP_MAX) { |
1235 | sap = 0; | 1284 | sap = 0; |
1236 | goto send_snl; | 1285 | goto add_snl; |
1237 | } | 1286 | } |
1238 | 1287 | ||
1239 | client_count = | 1288 | client_count = |
@@ -1250,8 +1299,37 @@ static void nfc_llcp_recv_snl(struct nfc_llcp_local *local, | |||
1250 | 1299 | ||
1251 | pr_debug("%p %d\n", llcp_sock, sap); | 1300 | pr_debug("%p %d\n", llcp_sock, sap); |
1252 | 1301 | ||
1253 | send_snl: | 1302 | add_snl: |
1254 | nfc_llcp_send_snl(local, tid, sap); | 1303 | sdp = nfc_llcp_build_sdres_tlv(tid, sap); |
1304 | if (sdp == NULL) | ||
1305 | goto exit; | ||
1306 | |||
1307 | sdres_tlvs_len += sdp->tlv_len; | ||
1308 | hlist_add_head(&sdp->node, &llc_sdres_list); | ||
1309 | break; | ||
1310 | |||
1311 | case LLCP_TLV_SDRES: | ||
1312 | mutex_lock(&local->sdreq_lock); | ||
1313 | |||
1314 | pr_debug("LLCP_TLV_SDRES: searching tid %d\n", tlv[2]); | ||
1315 | |||
1316 | hlist_for_each_entry(sdp, &local->pending_sdreqs, node) { | ||
1317 | if (sdp->tid != tlv[2]) | ||
1318 | continue; | ||
1319 | |||
1320 | sdp->sap = tlv[3]; | ||
1321 | |||
1322 | pr_debug("Found: uri=%s, sap=%d\n", | ||
1323 | sdp->uri, sdp->sap); | ||
1324 | |||
1325 | hlist_del(&sdp->node); | ||
1326 | |||
1327 | hlist_add_head(&sdp->node, &nl_sdres_list); | ||
1328 | |||
1329 | break; | ||
1330 | } | ||
1331 | |||
1332 | mutex_unlock(&local->sdreq_lock); | ||
1255 | break; | 1333 | break; |
1256 | 1334 | ||
1257 | default: | 1335 | default: |
@@ -1262,6 +1340,13 @@ send_snl: | |||
1262 | offset += length + 2; | 1340 | offset += length + 2; |
1263 | tlv += length + 2; | 1341 | tlv += length + 2; |
1264 | } | 1342 | } |
1343 | |||
1344 | exit: | ||
1345 | if (!hlist_empty(&nl_sdres_list)) | ||
1346 | nfc_genl_llc_send_sdres(local->dev, &nl_sdres_list); | ||
1347 | |||
1348 | if (!hlist_empty(&llc_sdres_list)) | ||
1349 | nfc_llcp_send_snl_sdres(local, &llc_sdres_list, sdres_tlvs_len); | ||
1265 | } | 1350 | } |
1266 | 1351 | ||
1267 | static void nfc_llcp_rx_work(struct work_struct *work) | 1352 | static void nfc_llcp_rx_work(struct work_struct *work) |
@@ -1447,6 +1532,13 @@ int nfc_llcp_register_device(struct nfc_dev *ndev) | |||
1447 | local->remote_miu = LLCP_DEFAULT_MIU; | 1532 | local->remote_miu = LLCP_DEFAULT_MIU; |
1448 | local->remote_lto = LLCP_DEFAULT_LTO; | 1533 | local->remote_lto = LLCP_DEFAULT_LTO; |
1449 | 1534 | ||
1535 | mutex_init(&local->sdreq_lock); | ||
1536 | INIT_HLIST_HEAD(&local->pending_sdreqs); | ||
1537 | init_timer(&local->sdreq_timer); | ||
1538 | local->sdreq_timer.data = (unsigned long) local; | ||
1539 | local->sdreq_timer.function = nfc_llcp_sdreq_timer; | ||
1540 | INIT_WORK(&local->sdreq_timeout_work, nfc_llcp_sdreq_timeout_work); | ||
1541 | |||
1450 | list_add(&local->list, &llcp_devices); | 1542 | list_add(&local->list, &llcp_devices); |
1451 | 1543 | ||
1452 | return 0; | 1544 | return 0; |
diff --git a/net/nfc/llcp/llcp.h b/net/nfc/llcp/llcp.h index 0eae5c509504..7e87a66b02ec 100644 --- a/net/nfc/llcp/llcp.h +++ b/net/nfc/llcp/llcp.h | |||
@@ -46,6 +46,19 @@ struct llcp_sock_list { | |||
46 | rwlock_t lock; | 46 | rwlock_t lock; |
47 | }; | 47 | }; |
48 | 48 | ||
49 | struct nfc_llcp_sdp_tlv { | ||
50 | u8 *tlv; | ||
51 | u8 tlv_len; | ||
52 | |||
53 | char *uri; | ||
54 | u8 tid; | ||
55 | u8 sap; | ||
56 | |||
57 | unsigned long time; | ||
58 | |||
59 | struct hlist_node node; | ||
60 | }; | ||
61 | |||
49 | struct nfc_llcp_local { | 62 | struct nfc_llcp_local { |
50 | struct list_head list; | 63 | struct list_head list; |
51 | struct nfc_dev *dev; | 64 | struct nfc_dev *dev; |
@@ -86,6 +99,12 @@ struct nfc_llcp_local { | |||
86 | u8 remote_opt; | 99 | u8 remote_opt; |
87 | u16 remote_wks; | 100 | u16 remote_wks; |
88 | 101 | ||
102 | struct mutex sdreq_lock; | ||
103 | struct hlist_head pending_sdreqs; | ||
104 | struct timer_list sdreq_timer; | ||
105 | struct work_struct sdreq_timeout_work; | ||
106 | u8 sdreq_next_tid; | ||
107 | |||
89 | /* sockets array */ | 108 | /* sockets array */ |
90 | struct llcp_sock_list sockets; | 109 | struct llcp_sock_list sockets; |
91 | struct llcp_sock_list connecting_sockets; | 110 | struct llcp_sock_list connecting_sockets; |
@@ -105,7 +124,12 @@ struct nfc_llcp_sock { | |||
105 | char *service_name; | 124 | char *service_name; |
106 | size_t service_name_len; | 125 | size_t service_name_len; |
107 | u8 rw; | 126 | u8 rw; |
108 | u16 miu; | 127 | u16 miux; |
128 | |||
129 | |||
130 | /* Remote link parameters */ | ||
131 | u8 remote_rw; | ||
132 | u16 remote_miu; | ||
109 | 133 | ||
110 | /* Link variables */ | 134 | /* Link variables */ |
111 | u8 send_n; | 135 | u8 send_n; |
@@ -213,12 +237,20 @@ int nfc_llcp_parse_connection_tlv(struct nfc_llcp_sock *sock, | |||
213 | /* Commands API */ | 237 | /* Commands API */ |
214 | void nfc_llcp_recv(void *data, struct sk_buff *skb, int err); | 238 | void nfc_llcp_recv(void *data, struct sk_buff *skb, int err); |
215 | u8 *nfc_llcp_build_tlv(u8 type, u8 *value, u8 value_length, u8 *tlv_length); | 239 | u8 *nfc_llcp_build_tlv(u8 type, u8 *value, u8 value_length, u8 *tlv_length); |
240 | struct nfc_llcp_sdp_tlv *nfc_llcp_build_sdres_tlv(u8 tid, u8 sap); | ||
241 | struct nfc_llcp_sdp_tlv *nfc_llcp_build_sdreq_tlv(u8 tid, char *uri, | ||
242 | size_t uri_len); | ||
243 | void nfc_llcp_free_sdp_tlv(struct nfc_llcp_sdp_tlv *sdp); | ||
244 | void nfc_llcp_free_sdp_tlv_list(struct hlist_head *sdp_head); | ||
216 | void nfc_llcp_recv(void *data, struct sk_buff *skb, int err); | 245 | void nfc_llcp_recv(void *data, struct sk_buff *skb, int err); |
217 | int nfc_llcp_disconnect(struct nfc_llcp_sock *sock); | 246 | int nfc_llcp_disconnect(struct nfc_llcp_sock *sock); |
218 | int nfc_llcp_send_symm(struct nfc_dev *dev); | 247 | int nfc_llcp_send_symm(struct nfc_dev *dev); |
219 | int nfc_llcp_send_connect(struct nfc_llcp_sock *sock); | 248 | int nfc_llcp_send_connect(struct nfc_llcp_sock *sock); |
220 | int nfc_llcp_send_cc(struct nfc_llcp_sock *sock); | 249 | int nfc_llcp_send_cc(struct nfc_llcp_sock *sock); |
221 | int nfc_llcp_send_snl(struct nfc_llcp_local *local, u8 tid, u8 sap); | 250 | int nfc_llcp_send_snl_sdres(struct nfc_llcp_local *local, |
251 | struct hlist_head *tlv_list, size_t tlvs_len); | ||
252 | int nfc_llcp_send_snl_sdreq(struct nfc_llcp_local *local, | ||
253 | struct hlist_head *tlv_list, size_t tlvs_len); | ||
222 | int nfc_llcp_send_dm(struct nfc_llcp_local *local, u8 ssap, u8 dsap, u8 reason); | 254 | int nfc_llcp_send_dm(struct nfc_llcp_local *local, u8 ssap, u8 dsap, u8 reason); |
223 | int nfc_llcp_send_disconnect(struct nfc_llcp_sock *sock); | 255 | int nfc_llcp_send_disconnect(struct nfc_llcp_sock *sock); |
224 | int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock, | 256 | int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock, |
diff --git a/net/nfc/llcp/sock.c b/net/nfc/llcp/sock.c index 8f025746f337..6fa76704cb13 100644 --- a/net/nfc/llcp/sock.c +++ b/net/nfc/llcp/sock.c | |||
@@ -223,6 +223,124 @@ error: | |||
223 | return ret; | 223 | return ret; |
224 | } | 224 | } |
225 | 225 | ||
226 | static int nfc_llcp_setsockopt(struct socket *sock, int level, int optname, | ||
227 | char __user *optval, unsigned int optlen) | ||
228 | { | ||
229 | struct sock *sk = sock->sk; | ||
230 | struct nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk); | ||
231 | u32 opt; | ||
232 | int err = 0; | ||
233 | |||
234 | pr_debug("%p optname %d\n", sk, optname); | ||
235 | |||
236 | if (level != SOL_NFC) | ||
237 | return -ENOPROTOOPT; | ||
238 | |||
239 | lock_sock(sk); | ||
240 | |||
241 | switch (optname) { | ||
242 | case NFC_LLCP_RW: | ||
243 | if (sk->sk_state == LLCP_CONNECTED || | ||
244 | sk->sk_state == LLCP_BOUND || | ||
245 | sk->sk_state == LLCP_LISTEN) { | ||
246 | err = -EINVAL; | ||
247 | break; | ||
248 | } | ||
249 | |||
250 | if (get_user(opt, (u32 __user *) optval)) { | ||
251 | err = -EFAULT; | ||
252 | break; | ||
253 | } | ||
254 | |||
255 | if (opt > LLCP_MAX_RW) { | ||
256 | err = -EINVAL; | ||
257 | break; | ||
258 | } | ||
259 | |||
260 | llcp_sock->rw = (u8) opt; | ||
261 | |||
262 | break; | ||
263 | |||
264 | case NFC_LLCP_MIUX: | ||
265 | if (sk->sk_state == LLCP_CONNECTED || | ||
266 | sk->sk_state == LLCP_BOUND || | ||
267 | sk->sk_state == LLCP_LISTEN) { | ||
268 | err = -EINVAL; | ||
269 | break; | ||
270 | } | ||
271 | |||
272 | if (get_user(opt, (u32 __user *) optval)) { | ||
273 | err = -EFAULT; | ||
274 | break; | ||
275 | } | ||
276 | |||
277 | if (opt > LLCP_MAX_MIUX) { | ||
278 | err = -EINVAL; | ||
279 | break; | ||
280 | } | ||
281 | |||
282 | llcp_sock->miux = (u16) opt; | ||
283 | |||
284 | break; | ||
285 | |||
286 | default: | ||
287 | err = -ENOPROTOOPT; | ||
288 | break; | ||
289 | } | ||
290 | |||
291 | release_sock(sk); | ||
292 | |||
293 | pr_debug("%p rw %d miux %d\n", llcp_sock, | ||
294 | llcp_sock->rw, llcp_sock->miux); | ||
295 | |||
296 | return err; | ||
297 | } | ||
298 | |||
299 | static int nfc_llcp_getsockopt(struct socket *sock, int level, int optname, | ||
300 | char __user *optval, int __user *optlen) | ||
301 | { | ||
302 | struct sock *sk = sock->sk; | ||
303 | struct nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk); | ||
304 | int len, err = 0; | ||
305 | |||
306 | pr_debug("%p optname %d\n", sk, optname); | ||
307 | |||
308 | if (level != SOL_NFC) | ||
309 | return -ENOPROTOOPT; | ||
310 | |||
311 | if (get_user(len, optlen)) | ||
312 | return -EFAULT; | ||
313 | |||
314 | len = min_t(u32, len, sizeof(u32)); | ||
315 | |||
316 | lock_sock(sk); | ||
317 | |||
318 | switch (optname) { | ||
319 | case NFC_LLCP_RW: | ||
320 | if (put_user(llcp_sock->rw, (u32 __user *) optval)) | ||
321 | err = -EFAULT; | ||
322 | |||
323 | break; | ||
324 | |||
325 | case NFC_LLCP_MIUX: | ||
326 | if (put_user(llcp_sock->miux, (u32 __user *) optval)) | ||
327 | err = -EFAULT; | ||
328 | |||
329 | break; | ||
330 | |||
331 | default: | ||
332 | err = -ENOPROTOOPT; | ||
333 | break; | ||
334 | } | ||
335 | |||
336 | release_sock(sk); | ||
337 | |||
338 | if (put_user(len, optlen)) | ||
339 | return -EFAULT; | ||
340 | |||
341 | return err; | ||
342 | } | ||
343 | |||
226 | void nfc_llcp_accept_unlink(struct sock *sk) | 344 | void nfc_llcp_accept_unlink(struct sock *sk) |
227 | { | 345 | { |
228 | struct nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk); | 346 | struct nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk); |
@@ -543,7 +661,7 @@ static int llcp_sock_connect(struct socket *sock, struct sockaddr *_addr, | |||
543 | 661 | ||
544 | llcp_sock->dev = dev; | 662 | llcp_sock->dev = dev; |
545 | llcp_sock->local = nfc_llcp_local_get(local); | 663 | llcp_sock->local = nfc_llcp_local_get(local); |
546 | llcp_sock->miu = llcp_sock->local->remote_miu; | 664 | llcp_sock->remote_miu = llcp_sock->local->remote_miu; |
547 | llcp_sock->ssap = nfc_llcp_get_local_ssap(local); | 665 | llcp_sock->ssap = nfc_llcp_get_local_ssap(local); |
548 | if (llcp_sock->ssap == LLCP_SAP_MAX) { | 666 | if (llcp_sock->ssap == LLCP_SAP_MAX) { |
549 | ret = -ENOMEM; | 667 | ret = -ENOMEM; |
@@ -737,8 +855,8 @@ static const struct proto_ops llcp_sock_ops = { | |||
737 | .ioctl = sock_no_ioctl, | 855 | .ioctl = sock_no_ioctl, |
738 | .listen = llcp_sock_listen, | 856 | .listen = llcp_sock_listen, |
739 | .shutdown = sock_no_shutdown, | 857 | .shutdown = sock_no_shutdown, |
740 | .setsockopt = sock_no_setsockopt, | 858 | .setsockopt = nfc_llcp_setsockopt, |
741 | .getsockopt = sock_no_getsockopt, | 859 | .getsockopt = nfc_llcp_getsockopt, |
742 | .sendmsg = llcp_sock_sendmsg, | 860 | .sendmsg = llcp_sock_sendmsg, |
743 | .recvmsg = llcp_sock_recvmsg, | 861 | .recvmsg = llcp_sock_recvmsg, |
744 | .mmap = sock_no_mmap, | 862 | .mmap = sock_no_mmap, |
@@ -802,8 +920,10 @@ struct sock *nfc_llcp_sock_alloc(struct socket *sock, int type, gfp_t gfp) | |||
802 | 920 | ||
803 | llcp_sock->ssap = 0; | 921 | llcp_sock->ssap = 0; |
804 | llcp_sock->dsap = LLCP_SAP_SDP; | 922 | llcp_sock->dsap = LLCP_SAP_SDP; |
805 | llcp_sock->rw = LLCP_DEFAULT_RW; | 923 | llcp_sock->rw = LLCP_MAX_RW + 1; |
806 | llcp_sock->miu = LLCP_DEFAULT_MIU; | 924 | llcp_sock->miux = LLCP_MAX_MIUX + 1; |
925 | llcp_sock->remote_rw = LLCP_DEFAULT_RW; | ||
926 | llcp_sock->remote_miu = LLCP_DEFAULT_MIU; | ||
807 | llcp_sock->send_n = llcp_sock->send_ack_n = 0; | 927 | llcp_sock->send_n = llcp_sock->send_ack_n = 0; |
808 | llcp_sock->recv_n = llcp_sock->recv_ack_n = 0; | 928 | llcp_sock->recv_n = llcp_sock->recv_ack_n = 0; |
809 | llcp_sock->remote_ready = 1; | 929 | llcp_sock->remote_ready = 1; |