diff options
-rw-r--r-- | net/nfc/llcp/commands.c | 82 | ||||
-rw-r--r-- | net/nfc/llcp/llcp.c | 23 | ||||
-rw-r--r-- | net/nfc/llcp/llcp.h | 16 |
3 files changed, 94 insertions, 27 deletions
diff --git a/net/nfc/llcp/commands.c b/net/nfc/llcp/commands.c index 5f61830a0e86..59f7ffca783e 100644 --- a/net/nfc/llcp/commands.c +++ b/net/nfc/llcp/commands.c | |||
@@ -117,6 +117,39 @@ 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 | void nfc_llcp_free_sdp_tlv(struct nfc_llcp_sdp_tlv *sdp) | ||
148 | { | ||
149 | kfree(sdp->tlv); | ||
150 | kfree(sdp); | ||
151 | } | ||
152 | |||
120 | int nfc_llcp_parse_gb_tlv(struct nfc_llcp_local *local, | 153 | int nfc_llcp_parse_gb_tlv(struct nfc_llcp_local *local, |
121 | u8 *tlv_array, u16 tlv_array_len) | 154 | u8 *tlv_array, u16 tlv_array_len) |
122 | { | 155 | { |
@@ -425,48 +458,55 @@ error_tlv: | |||
425 | return err; | 458 | return err; |
426 | } | 459 | } |
427 | 460 | ||
428 | int nfc_llcp_send_snl(struct nfc_llcp_local *local, u8 tid, u8 sap) | 461 | static struct sk_buff *nfc_llcp_allocate_snl(struct nfc_llcp_local *local, |
462 | size_t tlv_length) | ||
429 | { | 463 | { |
430 | struct sk_buff *skb; | 464 | struct sk_buff *skb; |
431 | struct nfc_dev *dev; | 465 | struct nfc_dev *dev; |
432 | u8 *sdres_tlv = NULL, sdres_tlv_length, sdres[2]; | ||
433 | u16 size = 0; | 466 | u16 size = 0; |
434 | 467 | ||
435 | pr_debug("Sending SNL tid 0x%x sap 0x%x\n", tid, sap); | ||
436 | |||
437 | if (local == NULL) | 468 | if (local == NULL) |
438 | return -ENODEV; | 469 | return ERR_PTR(-ENODEV); |
439 | 470 | ||
440 | dev = local->dev; | 471 | dev = local->dev; |
441 | if (dev == NULL) | 472 | if (dev == NULL) |
442 | return -ENODEV; | 473 | return ERR_PTR(-ENODEV); |
443 | |||
444 | sdres[0] = tid; | ||
445 | sdres[1] = sap; | ||
446 | sdres_tlv = nfc_llcp_build_tlv(LLCP_TLV_SDRES, sdres, 0, | ||
447 | &sdres_tlv_length); | ||
448 | if (sdres_tlv == NULL) | ||
449 | return -ENOMEM; | ||
450 | 474 | ||
451 | size += LLCP_HEADER_SIZE; | 475 | size += LLCP_HEADER_SIZE; |
452 | size += dev->tx_headroom + dev->tx_tailroom + NFC_HEADER_SIZE; | 476 | size += dev->tx_headroom + dev->tx_tailroom + NFC_HEADER_SIZE; |
453 | size += sdres_tlv_length; | 477 | size += tlv_length; |
454 | 478 | ||
455 | skb = alloc_skb(size, GFP_KERNEL); | 479 | skb = alloc_skb(size, GFP_KERNEL); |
456 | if (skb == NULL) { | 480 | if (skb == NULL) |
457 | kfree(sdres_tlv); | 481 | return ERR_PTR(-ENOMEM); |
458 | return -ENOMEM; | ||
459 | } | ||
460 | 482 | ||
461 | skb_reserve(skb, dev->tx_headroom + NFC_HEADER_SIZE); | 483 | skb_reserve(skb, dev->tx_headroom + NFC_HEADER_SIZE); |
462 | 484 | ||
463 | skb = llcp_add_header(skb, LLCP_SAP_SDP, LLCP_SAP_SDP, LLCP_PDU_SNL); | 485 | skb = llcp_add_header(skb, LLCP_SAP_SDP, LLCP_SAP_SDP, LLCP_PDU_SNL); |
464 | 486 | ||
465 | memcpy(skb_put(skb, sdres_tlv_length), sdres_tlv, sdres_tlv_length); | 487 | return skb; |
488 | } | ||
466 | 489 | ||
467 | skb_queue_tail(&local->tx_queue, skb); | 490 | int nfc_llcp_send_snl_sdres(struct nfc_llcp_local *local, |
491 | struct hlist_head *tlv_list, size_t tlvs_len) | ||
492 | { | ||
493 | struct nfc_llcp_sdp_tlv *sdp; | ||
494 | struct hlist_node *n; | ||
495 | struct sk_buff *skb; | ||
496 | |||
497 | skb = nfc_llcp_allocate_snl(local, tlvs_len); | ||
498 | if (IS_ERR(skb)) | ||
499 | return PTR_ERR(skb); | ||
500 | |||
501 | hlist_for_each_entry_safe(sdp, n, tlv_list, node) { | ||
502 | memcpy(skb_put(skb, sdp->tlv_len), sdp->tlv, sdp->tlv_len); | ||
468 | 503 | ||
469 | kfree(sdres_tlv); | 504 | hlist_del(&sdp->node); |
505 | |||
506 | nfc_llcp_free_sdp_tlv(sdp); | ||
507 | } | ||
508 | |||
509 | skb_queue_tail(&local->tx_queue, skb); | ||
470 | 510 | ||
471 | return 0; | 511 | return 0; |
472 | } | 512 | } |
diff --git a/net/nfc/llcp/llcp.c b/net/nfc/llcp/llcp.c index 15e7e0024285..30b61c1aa984 100644 --- a/net/nfc/llcp/llcp.c +++ b/net/nfc/llcp/llcp.c | |||
@@ -1144,6 +1144,9 @@ static void nfc_llcp_recv_snl(struct nfc_llcp_local *local, | |||
1144 | u16 tlv_len, offset; | 1144 | u16 tlv_len, offset; |
1145 | char *service_name; | 1145 | char *service_name; |
1146 | size_t service_name_len; | 1146 | size_t service_name_len; |
1147 | struct nfc_llcp_sdp_tlv *sdp; | ||
1148 | HLIST_HEAD(llc_sdres_list); | ||
1149 | size_t sdres_tlvs_len; | ||
1147 | 1150 | ||
1148 | dsap = nfc_llcp_dsap(skb); | 1151 | dsap = nfc_llcp_dsap(skb); |
1149 | ssap = nfc_llcp_ssap(skb); | 1152 | ssap = nfc_llcp_ssap(skb); |
@@ -1158,6 +1161,7 @@ static void nfc_llcp_recv_snl(struct nfc_llcp_local *local, | |||
1158 | tlv = &skb->data[LLCP_HEADER_SIZE]; | 1161 | tlv = &skb->data[LLCP_HEADER_SIZE]; |
1159 | tlv_len = skb->len - LLCP_HEADER_SIZE; | 1162 | tlv_len = skb->len - LLCP_HEADER_SIZE; |
1160 | offset = 0; | 1163 | offset = 0; |
1164 | sdres_tlvs_len = 0; | ||
1161 | 1165 | ||
1162 | while (offset < tlv_len) { | 1166 | while (offset < tlv_len) { |
1163 | type = tlv[0]; | 1167 | type = tlv[0]; |
@@ -1175,14 +1179,14 @@ static void nfc_llcp_recv_snl(struct nfc_llcp_local *local, | |||
1175 | !strncmp(service_name, "urn:nfc:sn:sdp", | 1179 | !strncmp(service_name, "urn:nfc:sn:sdp", |
1176 | service_name_len)) { | 1180 | service_name_len)) { |
1177 | sap = 1; | 1181 | sap = 1; |
1178 | goto send_snl; | 1182 | goto add_snl; |
1179 | } | 1183 | } |
1180 | 1184 | ||
1181 | llcp_sock = nfc_llcp_sock_from_sn(local, service_name, | 1185 | llcp_sock = nfc_llcp_sock_from_sn(local, service_name, |
1182 | service_name_len); | 1186 | service_name_len); |
1183 | if (!llcp_sock) { | 1187 | if (!llcp_sock) { |
1184 | sap = 0; | 1188 | sap = 0; |
1185 | goto send_snl; | 1189 | goto add_snl; |
1186 | } | 1190 | } |
1187 | 1191 | ||
1188 | /* | 1192 | /* |
@@ -1199,7 +1203,7 @@ static void nfc_llcp_recv_snl(struct nfc_llcp_local *local, | |||
1199 | 1203 | ||
1200 | if (sap == LLCP_SAP_MAX) { | 1204 | if (sap == LLCP_SAP_MAX) { |
1201 | sap = 0; | 1205 | sap = 0; |
1202 | goto send_snl; | 1206 | goto add_snl; |
1203 | } | 1207 | } |
1204 | 1208 | ||
1205 | client_count = | 1209 | client_count = |
@@ -1216,8 +1220,13 @@ static void nfc_llcp_recv_snl(struct nfc_llcp_local *local, | |||
1216 | 1220 | ||
1217 | pr_debug("%p %d\n", llcp_sock, sap); | 1221 | pr_debug("%p %d\n", llcp_sock, sap); |
1218 | 1222 | ||
1219 | send_snl: | 1223 | add_snl: |
1220 | nfc_llcp_send_snl(local, tid, sap); | 1224 | sdp = nfc_llcp_build_sdres_tlv(tid, sap); |
1225 | if (sdp == NULL) | ||
1226 | goto exit; | ||
1227 | |||
1228 | sdres_tlvs_len += sdp->tlv_len; | ||
1229 | hlist_add_head(&sdp->node, &llc_sdres_list); | ||
1221 | break; | 1230 | break; |
1222 | 1231 | ||
1223 | default: | 1232 | default: |
@@ -1228,6 +1237,10 @@ send_snl: | |||
1228 | offset += length + 2; | 1237 | offset += length + 2; |
1229 | tlv += length + 2; | 1238 | tlv += length + 2; |
1230 | } | 1239 | } |
1240 | |||
1241 | exit: | ||
1242 | if (!hlist_empty(&llc_sdres_list)) | ||
1243 | nfc_llcp_send_snl_sdres(local, &llc_sdres_list, sdres_tlvs_len); | ||
1231 | } | 1244 | } |
1232 | 1245 | ||
1233 | static void nfc_llcp_rx_work(struct work_struct *work) | 1246 | static void nfc_llcp_rx_work(struct work_struct *work) |
diff --git a/net/nfc/llcp/llcp.h b/net/nfc/llcp/llcp.h index 5f117adac2e5..465f5953e2d1 100644 --- a/net/nfc/llcp/llcp.h +++ b/net/nfc/llcp/llcp.h | |||
@@ -46,6 +46,17 @@ 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 | struct hlist_node node; | ||
58 | }; | ||
59 | |||
49 | struct nfc_llcp_local { | 60 | struct nfc_llcp_local { |
50 | struct list_head list; | 61 | struct list_head list; |
51 | struct nfc_dev *dev; | 62 | struct nfc_dev *dev; |
@@ -218,12 +229,15 @@ int nfc_llcp_parse_connection_tlv(struct nfc_llcp_sock *sock, | |||
218 | /* Commands API */ | 229 | /* Commands API */ |
219 | void nfc_llcp_recv(void *data, struct sk_buff *skb, int err); | 230 | void nfc_llcp_recv(void *data, struct sk_buff *skb, int err); |
220 | u8 *nfc_llcp_build_tlv(u8 type, u8 *value, u8 value_length, u8 *tlv_length); | 231 | u8 *nfc_llcp_build_tlv(u8 type, u8 *value, u8 value_length, u8 *tlv_length); |
232 | struct nfc_llcp_sdp_tlv *nfc_llcp_build_sdres_tlv(u8 tid, u8 sap); | ||
233 | void nfc_llcp_free_sdp_tlv(struct nfc_llcp_sdp_tlv *sdp); | ||
221 | void nfc_llcp_recv(void *data, struct sk_buff *skb, int err); | 234 | void nfc_llcp_recv(void *data, struct sk_buff *skb, int err); |
222 | int nfc_llcp_disconnect(struct nfc_llcp_sock *sock); | 235 | int nfc_llcp_disconnect(struct nfc_llcp_sock *sock); |
223 | int nfc_llcp_send_symm(struct nfc_dev *dev); | 236 | int nfc_llcp_send_symm(struct nfc_dev *dev); |
224 | int nfc_llcp_send_connect(struct nfc_llcp_sock *sock); | 237 | int nfc_llcp_send_connect(struct nfc_llcp_sock *sock); |
225 | int nfc_llcp_send_cc(struct nfc_llcp_sock *sock); | 238 | int nfc_llcp_send_cc(struct nfc_llcp_sock *sock); |
226 | int nfc_llcp_send_snl(struct nfc_llcp_local *local, u8 tid, u8 sap); | 239 | int nfc_llcp_send_snl_sdres(struct nfc_llcp_local *local, |
240 | struct hlist_head *tlv_list, size_t tlvs_len); | ||
227 | int nfc_llcp_send_dm(struct nfc_llcp_local *local, u8 ssap, u8 dsap, u8 reason); | 241 | int nfc_llcp_send_dm(struct nfc_llcp_local *local, u8 ssap, u8 dsap, u8 reason); |
228 | int nfc_llcp_send_disconnect(struct nfc_llcp_sock *sock); | 242 | int nfc_llcp_send_disconnect(struct nfc_llcp_sock *sock); |
229 | int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock, | 243 | int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock, |