aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/nfc/llcp/commands.c82
-rw-r--r--net/nfc/llcp/llcp.c23
-rw-r--r--net/nfc/llcp/llcp.h16
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
120struct 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
147void nfc_llcp_free_sdp_tlv(struct nfc_llcp_sdp_tlv *sdp)
148{
149 kfree(sdp->tlv);
150 kfree(sdp);
151}
152
120int nfc_llcp_parse_gb_tlv(struct nfc_llcp_local *local, 153int 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
428int nfc_llcp_send_snl(struct nfc_llcp_local *local, u8 tid, u8 sap) 461static 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); 490int 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
1219send_snl: 1223add_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
1241exit:
1242 if (!hlist_empty(&llc_sdres_list))
1243 nfc_llcp_send_snl_sdres(local, &llc_sdres_list, sdres_tlvs_len);
1231} 1244}
1232 1245
1233static void nfc_llcp_rx_work(struct work_struct *work) 1246static 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
49struct 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
49struct nfc_llcp_local { 60struct 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 */
219void nfc_llcp_recv(void *data, struct sk_buff *skb, int err); 230void nfc_llcp_recv(void *data, struct sk_buff *skb, int err);
220u8 *nfc_llcp_build_tlv(u8 type, u8 *value, u8 value_length, u8 *tlv_length); 231u8 *nfc_llcp_build_tlv(u8 type, u8 *value, u8 value_length, u8 *tlv_length);
232struct nfc_llcp_sdp_tlv *nfc_llcp_build_sdres_tlv(u8 tid, u8 sap);
233void nfc_llcp_free_sdp_tlv(struct nfc_llcp_sdp_tlv *sdp);
221void nfc_llcp_recv(void *data, struct sk_buff *skb, int err); 234void nfc_llcp_recv(void *data, struct sk_buff *skb, int err);
222int nfc_llcp_disconnect(struct nfc_llcp_sock *sock); 235int nfc_llcp_disconnect(struct nfc_llcp_sock *sock);
223int nfc_llcp_send_symm(struct nfc_dev *dev); 236int nfc_llcp_send_symm(struct nfc_dev *dev);
224int nfc_llcp_send_connect(struct nfc_llcp_sock *sock); 237int nfc_llcp_send_connect(struct nfc_llcp_sock *sock);
225int nfc_llcp_send_cc(struct nfc_llcp_sock *sock); 238int nfc_llcp_send_cc(struct nfc_llcp_sock *sock);
226int nfc_llcp_send_snl(struct nfc_llcp_local *local, u8 tid, u8 sap); 239int nfc_llcp_send_snl_sdres(struct nfc_llcp_local *local,
240 struct hlist_head *tlv_list, size_t tlvs_len);
227int nfc_llcp_send_dm(struct nfc_llcp_local *local, u8 ssap, u8 dsap, u8 reason); 241int nfc_llcp_send_dm(struct nfc_llcp_local *local, u8 ssap, u8 dsap, u8 reason);
228int nfc_llcp_send_disconnect(struct nfc_llcp_sock *sock); 242int nfc_llcp_send_disconnect(struct nfc_llcp_sock *sock);
229int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock, 243int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock,