xref: /OK3568_Linux_fs/kernel/net/nfc/llcp_commands.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Copyright (C) 2011  Intel Corporation. All rights reserved.
4*4882a593Smuzhiyun  */
5*4882a593Smuzhiyun 
6*4882a593Smuzhiyun #define pr_fmt(fmt) "llcp: %s: " fmt, __func__
7*4882a593Smuzhiyun 
8*4882a593Smuzhiyun #include <linux/init.h>
9*4882a593Smuzhiyun #include <linux/kernel.h>
10*4882a593Smuzhiyun #include <linux/module.h>
11*4882a593Smuzhiyun #include <linux/nfc.h>
12*4882a593Smuzhiyun 
13*4882a593Smuzhiyun #include <net/nfc/nfc.h>
14*4882a593Smuzhiyun 
15*4882a593Smuzhiyun #include "nfc.h"
16*4882a593Smuzhiyun #include "llcp.h"
17*4882a593Smuzhiyun 
18*4882a593Smuzhiyun static u8 llcp_tlv_length[LLCP_TLV_MAX] = {
19*4882a593Smuzhiyun 	0,
20*4882a593Smuzhiyun 	1, /* VERSION */
21*4882a593Smuzhiyun 	2, /* MIUX */
22*4882a593Smuzhiyun 	2, /* WKS */
23*4882a593Smuzhiyun 	1, /* LTO */
24*4882a593Smuzhiyun 	1, /* RW */
25*4882a593Smuzhiyun 	0, /* SN */
26*4882a593Smuzhiyun 	1, /* OPT */
27*4882a593Smuzhiyun 	0, /* SDREQ */
28*4882a593Smuzhiyun 	2, /* SDRES */
29*4882a593Smuzhiyun 
30*4882a593Smuzhiyun };
31*4882a593Smuzhiyun 
llcp_tlv8(u8 * tlv,u8 type)32*4882a593Smuzhiyun static u8 llcp_tlv8(u8 *tlv, u8 type)
33*4882a593Smuzhiyun {
34*4882a593Smuzhiyun 	if (tlv[0] != type || tlv[1] != llcp_tlv_length[tlv[0]])
35*4882a593Smuzhiyun 		return 0;
36*4882a593Smuzhiyun 
37*4882a593Smuzhiyun 	return tlv[2];
38*4882a593Smuzhiyun }
39*4882a593Smuzhiyun 
llcp_tlv16(u8 * tlv,u8 type)40*4882a593Smuzhiyun static u16 llcp_tlv16(u8 *tlv, u8 type)
41*4882a593Smuzhiyun {
42*4882a593Smuzhiyun 	if (tlv[0] != type || tlv[1] != llcp_tlv_length[tlv[0]])
43*4882a593Smuzhiyun 		return 0;
44*4882a593Smuzhiyun 
45*4882a593Smuzhiyun 	return be16_to_cpu(*((__be16 *)(tlv + 2)));
46*4882a593Smuzhiyun }
47*4882a593Smuzhiyun 
48*4882a593Smuzhiyun 
llcp_tlv_version(u8 * tlv)49*4882a593Smuzhiyun static u8 llcp_tlv_version(u8 *tlv)
50*4882a593Smuzhiyun {
51*4882a593Smuzhiyun 	return llcp_tlv8(tlv, LLCP_TLV_VERSION);
52*4882a593Smuzhiyun }
53*4882a593Smuzhiyun 
llcp_tlv_miux(u8 * tlv)54*4882a593Smuzhiyun static u16 llcp_tlv_miux(u8 *tlv)
55*4882a593Smuzhiyun {
56*4882a593Smuzhiyun 	return llcp_tlv16(tlv, LLCP_TLV_MIUX) & 0x7ff;
57*4882a593Smuzhiyun }
58*4882a593Smuzhiyun 
llcp_tlv_wks(u8 * tlv)59*4882a593Smuzhiyun static u16 llcp_tlv_wks(u8 *tlv)
60*4882a593Smuzhiyun {
61*4882a593Smuzhiyun 	return llcp_tlv16(tlv, LLCP_TLV_WKS);
62*4882a593Smuzhiyun }
63*4882a593Smuzhiyun 
llcp_tlv_lto(u8 * tlv)64*4882a593Smuzhiyun static u16 llcp_tlv_lto(u8 *tlv)
65*4882a593Smuzhiyun {
66*4882a593Smuzhiyun 	return llcp_tlv8(tlv, LLCP_TLV_LTO);
67*4882a593Smuzhiyun }
68*4882a593Smuzhiyun 
llcp_tlv_opt(u8 * tlv)69*4882a593Smuzhiyun static u8 llcp_tlv_opt(u8 *tlv)
70*4882a593Smuzhiyun {
71*4882a593Smuzhiyun 	return llcp_tlv8(tlv, LLCP_TLV_OPT);
72*4882a593Smuzhiyun }
73*4882a593Smuzhiyun 
llcp_tlv_rw(u8 * tlv)74*4882a593Smuzhiyun static u8 llcp_tlv_rw(u8 *tlv)
75*4882a593Smuzhiyun {
76*4882a593Smuzhiyun 	return llcp_tlv8(tlv, LLCP_TLV_RW) & 0xf;
77*4882a593Smuzhiyun }
78*4882a593Smuzhiyun 
nfc_llcp_build_tlv(u8 type,u8 * value,u8 value_length,u8 * tlv_length)79*4882a593Smuzhiyun u8 *nfc_llcp_build_tlv(u8 type, u8 *value, u8 value_length, u8 *tlv_length)
80*4882a593Smuzhiyun {
81*4882a593Smuzhiyun 	u8 *tlv, length;
82*4882a593Smuzhiyun 
83*4882a593Smuzhiyun 	pr_debug("type %d\n", type);
84*4882a593Smuzhiyun 
85*4882a593Smuzhiyun 	if (type >= LLCP_TLV_MAX)
86*4882a593Smuzhiyun 		return NULL;
87*4882a593Smuzhiyun 
88*4882a593Smuzhiyun 	length = llcp_tlv_length[type];
89*4882a593Smuzhiyun 	if (length == 0 && value_length == 0)
90*4882a593Smuzhiyun 		return NULL;
91*4882a593Smuzhiyun 	else if (length == 0)
92*4882a593Smuzhiyun 		length = value_length;
93*4882a593Smuzhiyun 
94*4882a593Smuzhiyun 	*tlv_length = 2 + length;
95*4882a593Smuzhiyun 	tlv = kzalloc(2 + length, GFP_KERNEL);
96*4882a593Smuzhiyun 	if (tlv == NULL)
97*4882a593Smuzhiyun 		return tlv;
98*4882a593Smuzhiyun 
99*4882a593Smuzhiyun 	tlv[0] = type;
100*4882a593Smuzhiyun 	tlv[1] = length;
101*4882a593Smuzhiyun 	memcpy(tlv + 2, value, length);
102*4882a593Smuzhiyun 
103*4882a593Smuzhiyun 	return tlv;
104*4882a593Smuzhiyun }
105*4882a593Smuzhiyun 
nfc_llcp_build_sdres_tlv(u8 tid,u8 sap)106*4882a593Smuzhiyun struct nfc_llcp_sdp_tlv *nfc_llcp_build_sdres_tlv(u8 tid, u8 sap)
107*4882a593Smuzhiyun {
108*4882a593Smuzhiyun 	struct nfc_llcp_sdp_tlv *sdres;
109*4882a593Smuzhiyun 	u8 value[2];
110*4882a593Smuzhiyun 
111*4882a593Smuzhiyun 	sdres = kzalloc(sizeof(struct nfc_llcp_sdp_tlv), GFP_KERNEL);
112*4882a593Smuzhiyun 	if (sdres == NULL)
113*4882a593Smuzhiyun 		return NULL;
114*4882a593Smuzhiyun 
115*4882a593Smuzhiyun 	value[0] = tid;
116*4882a593Smuzhiyun 	value[1] = sap;
117*4882a593Smuzhiyun 
118*4882a593Smuzhiyun 	sdres->tlv = nfc_llcp_build_tlv(LLCP_TLV_SDRES, value, 2,
119*4882a593Smuzhiyun 					&sdres->tlv_len);
120*4882a593Smuzhiyun 	if (sdres->tlv == NULL) {
121*4882a593Smuzhiyun 		kfree(sdres);
122*4882a593Smuzhiyun 		return NULL;
123*4882a593Smuzhiyun 	}
124*4882a593Smuzhiyun 
125*4882a593Smuzhiyun 	sdres->tid = tid;
126*4882a593Smuzhiyun 	sdres->sap = sap;
127*4882a593Smuzhiyun 
128*4882a593Smuzhiyun 	INIT_HLIST_NODE(&sdres->node);
129*4882a593Smuzhiyun 
130*4882a593Smuzhiyun 	return sdres;
131*4882a593Smuzhiyun }
132*4882a593Smuzhiyun 
nfc_llcp_build_sdreq_tlv(u8 tid,char * uri,size_t uri_len)133*4882a593Smuzhiyun struct nfc_llcp_sdp_tlv *nfc_llcp_build_sdreq_tlv(u8 tid, char *uri,
134*4882a593Smuzhiyun 						  size_t uri_len)
135*4882a593Smuzhiyun {
136*4882a593Smuzhiyun 	struct nfc_llcp_sdp_tlv *sdreq;
137*4882a593Smuzhiyun 
138*4882a593Smuzhiyun 	pr_debug("uri: %s, len: %zu\n", uri, uri_len);
139*4882a593Smuzhiyun 
140*4882a593Smuzhiyun 	/* sdreq->tlv_len is u8, takes uri_len, + 3 for header, + 1 for NULL */
141*4882a593Smuzhiyun 	if (WARN_ON_ONCE(uri_len > U8_MAX - 4))
142*4882a593Smuzhiyun 		return NULL;
143*4882a593Smuzhiyun 
144*4882a593Smuzhiyun 	sdreq = kzalloc(sizeof(struct nfc_llcp_sdp_tlv), GFP_KERNEL);
145*4882a593Smuzhiyun 	if (sdreq == NULL)
146*4882a593Smuzhiyun 		return NULL;
147*4882a593Smuzhiyun 
148*4882a593Smuzhiyun 	sdreq->tlv_len = uri_len + 3;
149*4882a593Smuzhiyun 
150*4882a593Smuzhiyun 	if (uri[uri_len - 1] == 0)
151*4882a593Smuzhiyun 		sdreq->tlv_len--;
152*4882a593Smuzhiyun 
153*4882a593Smuzhiyun 	sdreq->tlv = kzalloc(sdreq->tlv_len + 1, GFP_KERNEL);
154*4882a593Smuzhiyun 	if (sdreq->tlv == NULL) {
155*4882a593Smuzhiyun 		kfree(sdreq);
156*4882a593Smuzhiyun 		return NULL;
157*4882a593Smuzhiyun 	}
158*4882a593Smuzhiyun 
159*4882a593Smuzhiyun 	sdreq->tlv[0] = LLCP_TLV_SDREQ;
160*4882a593Smuzhiyun 	sdreq->tlv[1] = sdreq->tlv_len - 2;
161*4882a593Smuzhiyun 	sdreq->tlv[2] = tid;
162*4882a593Smuzhiyun 
163*4882a593Smuzhiyun 	sdreq->tid = tid;
164*4882a593Smuzhiyun 	sdreq->uri = sdreq->tlv + 3;
165*4882a593Smuzhiyun 	memcpy(sdreq->uri, uri, uri_len);
166*4882a593Smuzhiyun 
167*4882a593Smuzhiyun 	sdreq->time = jiffies;
168*4882a593Smuzhiyun 
169*4882a593Smuzhiyun 	INIT_HLIST_NODE(&sdreq->node);
170*4882a593Smuzhiyun 
171*4882a593Smuzhiyun 	return sdreq;
172*4882a593Smuzhiyun }
173*4882a593Smuzhiyun 
nfc_llcp_free_sdp_tlv(struct nfc_llcp_sdp_tlv * sdp)174*4882a593Smuzhiyun void nfc_llcp_free_sdp_tlv(struct nfc_llcp_sdp_tlv *sdp)
175*4882a593Smuzhiyun {
176*4882a593Smuzhiyun 	kfree(sdp->tlv);
177*4882a593Smuzhiyun 	kfree(sdp);
178*4882a593Smuzhiyun }
179*4882a593Smuzhiyun 
nfc_llcp_free_sdp_tlv_list(struct hlist_head * head)180*4882a593Smuzhiyun void nfc_llcp_free_sdp_tlv_list(struct hlist_head *head)
181*4882a593Smuzhiyun {
182*4882a593Smuzhiyun 	struct nfc_llcp_sdp_tlv *sdp;
183*4882a593Smuzhiyun 	struct hlist_node *n;
184*4882a593Smuzhiyun 
185*4882a593Smuzhiyun 	hlist_for_each_entry_safe(sdp, n, head, node) {
186*4882a593Smuzhiyun 		hlist_del(&sdp->node);
187*4882a593Smuzhiyun 
188*4882a593Smuzhiyun 		nfc_llcp_free_sdp_tlv(sdp);
189*4882a593Smuzhiyun 	}
190*4882a593Smuzhiyun }
191*4882a593Smuzhiyun 
nfc_llcp_parse_gb_tlv(struct nfc_llcp_local * local,u8 * tlv_array,u16 tlv_array_len)192*4882a593Smuzhiyun int nfc_llcp_parse_gb_tlv(struct nfc_llcp_local *local,
193*4882a593Smuzhiyun 			  u8 *tlv_array, u16 tlv_array_len)
194*4882a593Smuzhiyun {
195*4882a593Smuzhiyun 	u8 *tlv = tlv_array, type, length, offset = 0;
196*4882a593Smuzhiyun 
197*4882a593Smuzhiyun 	pr_debug("TLV array length %d\n", tlv_array_len);
198*4882a593Smuzhiyun 
199*4882a593Smuzhiyun 	if (local == NULL)
200*4882a593Smuzhiyun 		return -ENODEV;
201*4882a593Smuzhiyun 
202*4882a593Smuzhiyun 	while (offset < tlv_array_len) {
203*4882a593Smuzhiyun 		type = tlv[0];
204*4882a593Smuzhiyun 		length = tlv[1];
205*4882a593Smuzhiyun 
206*4882a593Smuzhiyun 		pr_debug("type 0x%x length %d\n", type, length);
207*4882a593Smuzhiyun 
208*4882a593Smuzhiyun 		switch (type) {
209*4882a593Smuzhiyun 		case LLCP_TLV_VERSION:
210*4882a593Smuzhiyun 			local->remote_version = llcp_tlv_version(tlv);
211*4882a593Smuzhiyun 			break;
212*4882a593Smuzhiyun 		case LLCP_TLV_MIUX:
213*4882a593Smuzhiyun 			local->remote_miu = llcp_tlv_miux(tlv) + 128;
214*4882a593Smuzhiyun 			break;
215*4882a593Smuzhiyun 		case LLCP_TLV_WKS:
216*4882a593Smuzhiyun 			local->remote_wks = llcp_tlv_wks(tlv);
217*4882a593Smuzhiyun 			break;
218*4882a593Smuzhiyun 		case LLCP_TLV_LTO:
219*4882a593Smuzhiyun 			local->remote_lto = llcp_tlv_lto(tlv) * 10;
220*4882a593Smuzhiyun 			break;
221*4882a593Smuzhiyun 		case LLCP_TLV_OPT:
222*4882a593Smuzhiyun 			local->remote_opt = llcp_tlv_opt(tlv);
223*4882a593Smuzhiyun 			break;
224*4882a593Smuzhiyun 		default:
225*4882a593Smuzhiyun 			pr_err("Invalid gt tlv value 0x%x\n", type);
226*4882a593Smuzhiyun 			break;
227*4882a593Smuzhiyun 		}
228*4882a593Smuzhiyun 
229*4882a593Smuzhiyun 		offset += length + 2;
230*4882a593Smuzhiyun 		tlv += length + 2;
231*4882a593Smuzhiyun 	}
232*4882a593Smuzhiyun 
233*4882a593Smuzhiyun 	pr_debug("version 0x%x miu %d lto %d opt 0x%x wks 0x%x\n",
234*4882a593Smuzhiyun 		 local->remote_version, local->remote_miu,
235*4882a593Smuzhiyun 		 local->remote_lto, local->remote_opt,
236*4882a593Smuzhiyun 		 local->remote_wks);
237*4882a593Smuzhiyun 
238*4882a593Smuzhiyun 	return 0;
239*4882a593Smuzhiyun }
240*4882a593Smuzhiyun 
nfc_llcp_parse_connection_tlv(struct nfc_llcp_sock * sock,u8 * tlv_array,u16 tlv_array_len)241*4882a593Smuzhiyun int nfc_llcp_parse_connection_tlv(struct nfc_llcp_sock *sock,
242*4882a593Smuzhiyun 				  u8 *tlv_array, u16 tlv_array_len)
243*4882a593Smuzhiyun {
244*4882a593Smuzhiyun 	u8 *tlv = tlv_array, type, length, offset = 0;
245*4882a593Smuzhiyun 
246*4882a593Smuzhiyun 	pr_debug("TLV array length %d\n", tlv_array_len);
247*4882a593Smuzhiyun 
248*4882a593Smuzhiyun 	if (sock == NULL)
249*4882a593Smuzhiyun 		return -ENOTCONN;
250*4882a593Smuzhiyun 
251*4882a593Smuzhiyun 	while (offset < tlv_array_len) {
252*4882a593Smuzhiyun 		type = tlv[0];
253*4882a593Smuzhiyun 		length = tlv[1];
254*4882a593Smuzhiyun 
255*4882a593Smuzhiyun 		pr_debug("type 0x%x length %d\n", type, length);
256*4882a593Smuzhiyun 
257*4882a593Smuzhiyun 		switch (type) {
258*4882a593Smuzhiyun 		case LLCP_TLV_MIUX:
259*4882a593Smuzhiyun 			sock->remote_miu = llcp_tlv_miux(tlv) + 128;
260*4882a593Smuzhiyun 			break;
261*4882a593Smuzhiyun 		case LLCP_TLV_RW:
262*4882a593Smuzhiyun 			sock->remote_rw = llcp_tlv_rw(tlv);
263*4882a593Smuzhiyun 			break;
264*4882a593Smuzhiyun 		case LLCP_TLV_SN:
265*4882a593Smuzhiyun 			break;
266*4882a593Smuzhiyun 		default:
267*4882a593Smuzhiyun 			pr_err("Invalid gt tlv value 0x%x\n", type);
268*4882a593Smuzhiyun 			break;
269*4882a593Smuzhiyun 		}
270*4882a593Smuzhiyun 
271*4882a593Smuzhiyun 		offset += length + 2;
272*4882a593Smuzhiyun 		tlv += length + 2;
273*4882a593Smuzhiyun 	}
274*4882a593Smuzhiyun 
275*4882a593Smuzhiyun 	pr_debug("sock %p rw %d miu %d\n", sock,
276*4882a593Smuzhiyun 		 sock->remote_rw, sock->remote_miu);
277*4882a593Smuzhiyun 
278*4882a593Smuzhiyun 	return 0;
279*4882a593Smuzhiyun }
280*4882a593Smuzhiyun 
llcp_add_header(struct sk_buff * pdu,u8 dsap,u8 ssap,u8 ptype)281*4882a593Smuzhiyun static struct sk_buff *llcp_add_header(struct sk_buff *pdu,
282*4882a593Smuzhiyun 				       u8 dsap, u8 ssap, u8 ptype)
283*4882a593Smuzhiyun {
284*4882a593Smuzhiyun 	u8 header[2];
285*4882a593Smuzhiyun 
286*4882a593Smuzhiyun 	pr_debug("ptype 0x%x dsap 0x%x ssap 0x%x\n", ptype, dsap, ssap);
287*4882a593Smuzhiyun 
288*4882a593Smuzhiyun 	header[0] = (u8)((dsap << 2) | (ptype >> 2));
289*4882a593Smuzhiyun 	header[1] = (u8)((ptype << 6) | ssap);
290*4882a593Smuzhiyun 
291*4882a593Smuzhiyun 	pr_debug("header 0x%x 0x%x\n", header[0], header[1]);
292*4882a593Smuzhiyun 
293*4882a593Smuzhiyun 	skb_put_data(pdu, header, LLCP_HEADER_SIZE);
294*4882a593Smuzhiyun 
295*4882a593Smuzhiyun 	return pdu;
296*4882a593Smuzhiyun }
297*4882a593Smuzhiyun 
llcp_add_tlv(struct sk_buff * pdu,u8 * tlv,u8 tlv_length)298*4882a593Smuzhiyun static struct sk_buff *llcp_add_tlv(struct sk_buff *pdu, u8 *tlv,
299*4882a593Smuzhiyun 				    u8 tlv_length)
300*4882a593Smuzhiyun {
301*4882a593Smuzhiyun 	/* XXX Add an skb length check */
302*4882a593Smuzhiyun 
303*4882a593Smuzhiyun 	if (tlv == NULL)
304*4882a593Smuzhiyun 		return NULL;
305*4882a593Smuzhiyun 
306*4882a593Smuzhiyun 	skb_put_data(pdu, tlv, tlv_length);
307*4882a593Smuzhiyun 
308*4882a593Smuzhiyun 	return pdu;
309*4882a593Smuzhiyun }
310*4882a593Smuzhiyun 
llcp_allocate_pdu(struct nfc_llcp_sock * sock,u8 cmd,u16 size)311*4882a593Smuzhiyun static struct sk_buff *llcp_allocate_pdu(struct nfc_llcp_sock *sock,
312*4882a593Smuzhiyun 					 u8 cmd, u16 size)
313*4882a593Smuzhiyun {
314*4882a593Smuzhiyun 	struct sk_buff *skb;
315*4882a593Smuzhiyun 	int err;
316*4882a593Smuzhiyun 
317*4882a593Smuzhiyun 	if (sock->ssap == 0)
318*4882a593Smuzhiyun 		return NULL;
319*4882a593Smuzhiyun 
320*4882a593Smuzhiyun 	skb = nfc_alloc_send_skb(sock->dev, &sock->sk, MSG_DONTWAIT,
321*4882a593Smuzhiyun 				 size + LLCP_HEADER_SIZE, &err);
322*4882a593Smuzhiyun 	if (skb == NULL) {
323*4882a593Smuzhiyun 		pr_err("Could not allocate PDU\n");
324*4882a593Smuzhiyun 		return NULL;
325*4882a593Smuzhiyun 	}
326*4882a593Smuzhiyun 
327*4882a593Smuzhiyun 	skb = llcp_add_header(skb, sock->dsap, sock->ssap, cmd);
328*4882a593Smuzhiyun 
329*4882a593Smuzhiyun 	return skb;
330*4882a593Smuzhiyun }
331*4882a593Smuzhiyun 
nfc_llcp_send_disconnect(struct nfc_llcp_sock * sock)332*4882a593Smuzhiyun int nfc_llcp_send_disconnect(struct nfc_llcp_sock *sock)
333*4882a593Smuzhiyun {
334*4882a593Smuzhiyun 	struct sk_buff *skb;
335*4882a593Smuzhiyun 	struct nfc_dev *dev;
336*4882a593Smuzhiyun 	struct nfc_llcp_local *local;
337*4882a593Smuzhiyun 
338*4882a593Smuzhiyun 	pr_debug("Sending DISC\n");
339*4882a593Smuzhiyun 
340*4882a593Smuzhiyun 	local = sock->local;
341*4882a593Smuzhiyun 	if (local == NULL)
342*4882a593Smuzhiyun 		return -ENODEV;
343*4882a593Smuzhiyun 
344*4882a593Smuzhiyun 	dev = sock->dev;
345*4882a593Smuzhiyun 	if (dev == NULL)
346*4882a593Smuzhiyun 		return -ENODEV;
347*4882a593Smuzhiyun 
348*4882a593Smuzhiyun 	skb = llcp_allocate_pdu(sock, LLCP_PDU_DISC, 0);
349*4882a593Smuzhiyun 	if (skb == NULL)
350*4882a593Smuzhiyun 		return -ENOMEM;
351*4882a593Smuzhiyun 
352*4882a593Smuzhiyun 	skb_queue_tail(&local->tx_queue, skb);
353*4882a593Smuzhiyun 
354*4882a593Smuzhiyun 	return 0;
355*4882a593Smuzhiyun }
356*4882a593Smuzhiyun 
nfc_llcp_send_symm(struct nfc_dev * dev)357*4882a593Smuzhiyun int nfc_llcp_send_symm(struct nfc_dev *dev)
358*4882a593Smuzhiyun {
359*4882a593Smuzhiyun 	struct sk_buff *skb;
360*4882a593Smuzhiyun 	struct nfc_llcp_local *local;
361*4882a593Smuzhiyun 	u16 size = 0;
362*4882a593Smuzhiyun 
363*4882a593Smuzhiyun 	pr_debug("Sending SYMM\n");
364*4882a593Smuzhiyun 
365*4882a593Smuzhiyun 	local = nfc_llcp_find_local(dev);
366*4882a593Smuzhiyun 	if (local == NULL)
367*4882a593Smuzhiyun 		return -ENODEV;
368*4882a593Smuzhiyun 
369*4882a593Smuzhiyun 	size += LLCP_HEADER_SIZE;
370*4882a593Smuzhiyun 	size += dev->tx_headroom + dev->tx_tailroom + NFC_HEADER_SIZE;
371*4882a593Smuzhiyun 
372*4882a593Smuzhiyun 	skb = alloc_skb(size, GFP_KERNEL);
373*4882a593Smuzhiyun 	if (skb == NULL)
374*4882a593Smuzhiyun 		return -ENOMEM;
375*4882a593Smuzhiyun 
376*4882a593Smuzhiyun 	skb_reserve(skb, dev->tx_headroom + NFC_HEADER_SIZE);
377*4882a593Smuzhiyun 
378*4882a593Smuzhiyun 	skb = llcp_add_header(skb, 0, 0, LLCP_PDU_SYMM);
379*4882a593Smuzhiyun 
380*4882a593Smuzhiyun 	__net_timestamp(skb);
381*4882a593Smuzhiyun 
382*4882a593Smuzhiyun 	nfc_llcp_send_to_raw_sock(local, skb, NFC_DIRECTION_TX);
383*4882a593Smuzhiyun 
384*4882a593Smuzhiyun 	return nfc_data_exchange(dev, local->target_idx, skb,
385*4882a593Smuzhiyun 				 nfc_llcp_recv, local);
386*4882a593Smuzhiyun }
387*4882a593Smuzhiyun 
nfc_llcp_send_connect(struct nfc_llcp_sock * sock)388*4882a593Smuzhiyun int nfc_llcp_send_connect(struct nfc_llcp_sock *sock)
389*4882a593Smuzhiyun {
390*4882a593Smuzhiyun 	struct nfc_llcp_local *local;
391*4882a593Smuzhiyun 	struct sk_buff *skb;
392*4882a593Smuzhiyun 	u8 *service_name_tlv = NULL, service_name_tlv_length;
393*4882a593Smuzhiyun 	u8 *miux_tlv = NULL, miux_tlv_length;
394*4882a593Smuzhiyun 	u8 *rw_tlv = NULL, rw_tlv_length, rw;
395*4882a593Smuzhiyun 	int err;
396*4882a593Smuzhiyun 	u16 size = 0;
397*4882a593Smuzhiyun 	__be16 miux;
398*4882a593Smuzhiyun 
399*4882a593Smuzhiyun 	pr_debug("Sending CONNECT\n");
400*4882a593Smuzhiyun 
401*4882a593Smuzhiyun 	local = sock->local;
402*4882a593Smuzhiyun 	if (local == NULL)
403*4882a593Smuzhiyun 		return -ENODEV;
404*4882a593Smuzhiyun 
405*4882a593Smuzhiyun 	if (sock->service_name != NULL) {
406*4882a593Smuzhiyun 		service_name_tlv = nfc_llcp_build_tlv(LLCP_TLV_SN,
407*4882a593Smuzhiyun 						      sock->service_name,
408*4882a593Smuzhiyun 						      sock->service_name_len,
409*4882a593Smuzhiyun 						      &service_name_tlv_length);
410*4882a593Smuzhiyun 		if (!service_name_tlv) {
411*4882a593Smuzhiyun 			err = -ENOMEM;
412*4882a593Smuzhiyun 			goto error_tlv;
413*4882a593Smuzhiyun 		}
414*4882a593Smuzhiyun 		size += service_name_tlv_length;
415*4882a593Smuzhiyun 	}
416*4882a593Smuzhiyun 
417*4882a593Smuzhiyun 	/* If the socket parameters are not set, use the local ones */
418*4882a593Smuzhiyun 	miux = be16_to_cpu(sock->miux) > LLCP_MAX_MIUX ?
419*4882a593Smuzhiyun 		local->miux : sock->miux;
420*4882a593Smuzhiyun 	rw = sock->rw > LLCP_MAX_RW ? local->rw : sock->rw;
421*4882a593Smuzhiyun 
422*4882a593Smuzhiyun 	miux_tlv = nfc_llcp_build_tlv(LLCP_TLV_MIUX, (u8 *)&miux, 0,
423*4882a593Smuzhiyun 				      &miux_tlv_length);
424*4882a593Smuzhiyun 	if (!miux_tlv) {
425*4882a593Smuzhiyun 		err = -ENOMEM;
426*4882a593Smuzhiyun 		goto error_tlv;
427*4882a593Smuzhiyun 	}
428*4882a593Smuzhiyun 	size += miux_tlv_length;
429*4882a593Smuzhiyun 
430*4882a593Smuzhiyun 	rw_tlv = nfc_llcp_build_tlv(LLCP_TLV_RW, &rw, 0, &rw_tlv_length);
431*4882a593Smuzhiyun 	if (!rw_tlv) {
432*4882a593Smuzhiyun 		err = -ENOMEM;
433*4882a593Smuzhiyun 		goto error_tlv;
434*4882a593Smuzhiyun 	}
435*4882a593Smuzhiyun 	size += rw_tlv_length;
436*4882a593Smuzhiyun 
437*4882a593Smuzhiyun 	pr_debug("SKB size %d SN length %zu\n", size, sock->service_name_len);
438*4882a593Smuzhiyun 
439*4882a593Smuzhiyun 	skb = llcp_allocate_pdu(sock, LLCP_PDU_CONNECT, size);
440*4882a593Smuzhiyun 	if (skb == NULL) {
441*4882a593Smuzhiyun 		err = -ENOMEM;
442*4882a593Smuzhiyun 		goto error_tlv;
443*4882a593Smuzhiyun 	}
444*4882a593Smuzhiyun 
445*4882a593Smuzhiyun 	llcp_add_tlv(skb, service_name_tlv, service_name_tlv_length);
446*4882a593Smuzhiyun 	llcp_add_tlv(skb, miux_tlv, miux_tlv_length);
447*4882a593Smuzhiyun 	llcp_add_tlv(skb, rw_tlv, rw_tlv_length);
448*4882a593Smuzhiyun 
449*4882a593Smuzhiyun 	skb_queue_tail(&local->tx_queue, skb);
450*4882a593Smuzhiyun 
451*4882a593Smuzhiyun 	err = 0;
452*4882a593Smuzhiyun 
453*4882a593Smuzhiyun error_tlv:
454*4882a593Smuzhiyun 	if (err)
455*4882a593Smuzhiyun 		pr_err("error %d\n", err);
456*4882a593Smuzhiyun 
457*4882a593Smuzhiyun 	kfree(service_name_tlv);
458*4882a593Smuzhiyun 	kfree(miux_tlv);
459*4882a593Smuzhiyun 	kfree(rw_tlv);
460*4882a593Smuzhiyun 
461*4882a593Smuzhiyun 	return err;
462*4882a593Smuzhiyun }
463*4882a593Smuzhiyun 
nfc_llcp_send_cc(struct nfc_llcp_sock * sock)464*4882a593Smuzhiyun int nfc_llcp_send_cc(struct nfc_llcp_sock *sock)
465*4882a593Smuzhiyun {
466*4882a593Smuzhiyun 	struct nfc_llcp_local *local;
467*4882a593Smuzhiyun 	struct sk_buff *skb;
468*4882a593Smuzhiyun 	u8 *miux_tlv = NULL, miux_tlv_length;
469*4882a593Smuzhiyun 	u8 *rw_tlv = NULL, rw_tlv_length, rw;
470*4882a593Smuzhiyun 	int err;
471*4882a593Smuzhiyun 	u16 size = 0;
472*4882a593Smuzhiyun 	__be16 miux;
473*4882a593Smuzhiyun 
474*4882a593Smuzhiyun 	pr_debug("Sending CC\n");
475*4882a593Smuzhiyun 
476*4882a593Smuzhiyun 	local = sock->local;
477*4882a593Smuzhiyun 	if (local == NULL)
478*4882a593Smuzhiyun 		return -ENODEV;
479*4882a593Smuzhiyun 
480*4882a593Smuzhiyun 	/* If the socket parameters are not set, use the local ones */
481*4882a593Smuzhiyun 	miux = be16_to_cpu(sock->miux) > LLCP_MAX_MIUX ?
482*4882a593Smuzhiyun 		local->miux : sock->miux;
483*4882a593Smuzhiyun 	rw = sock->rw > LLCP_MAX_RW ? local->rw : sock->rw;
484*4882a593Smuzhiyun 
485*4882a593Smuzhiyun 	miux_tlv = nfc_llcp_build_tlv(LLCP_TLV_MIUX, (u8 *)&miux, 0,
486*4882a593Smuzhiyun 				      &miux_tlv_length);
487*4882a593Smuzhiyun 	if (!miux_tlv) {
488*4882a593Smuzhiyun 		err = -ENOMEM;
489*4882a593Smuzhiyun 		goto error_tlv;
490*4882a593Smuzhiyun 	}
491*4882a593Smuzhiyun 	size += miux_tlv_length;
492*4882a593Smuzhiyun 
493*4882a593Smuzhiyun 	rw_tlv = nfc_llcp_build_tlv(LLCP_TLV_RW, &rw, 0, &rw_tlv_length);
494*4882a593Smuzhiyun 	if (!rw_tlv) {
495*4882a593Smuzhiyun 		err = -ENOMEM;
496*4882a593Smuzhiyun 		goto error_tlv;
497*4882a593Smuzhiyun 	}
498*4882a593Smuzhiyun 	size += rw_tlv_length;
499*4882a593Smuzhiyun 
500*4882a593Smuzhiyun 	skb = llcp_allocate_pdu(sock, LLCP_PDU_CC, size);
501*4882a593Smuzhiyun 	if (skb == NULL) {
502*4882a593Smuzhiyun 		err = -ENOMEM;
503*4882a593Smuzhiyun 		goto error_tlv;
504*4882a593Smuzhiyun 	}
505*4882a593Smuzhiyun 
506*4882a593Smuzhiyun 	llcp_add_tlv(skb, miux_tlv, miux_tlv_length);
507*4882a593Smuzhiyun 	llcp_add_tlv(skb, rw_tlv, rw_tlv_length);
508*4882a593Smuzhiyun 
509*4882a593Smuzhiyun 	skb_queue_tail(&local->tx_queue, skb);
510*4882a593Smuzhiyun 
511*4882a593Smuzhiyun 	err = 0;
512*4882a593Smuzhiyun 
513*4882a593Smuzhiyun error_tlv:
514*4882a593Smuzhiyun 	if (err)
515*4882a593Smuzhiyun 		pr_err("error %d\n", err);
516*4882a593Smuzhiyun 
517*4882a593Smuzhiyun 	kfree(miux_tlv);
518*4882a593Smuzhiyun 	kfree(rw_tlv);
519*4882a593Smuzhiyun 
520*4882a593Smuzhiyun 	return err;
521*4882a593Smuzhiyun }
522*4882a593Smuzhiyun 
nfc_llcp_allocate_snl(struct nfc_llcp_local * local,size_t tlv_length)523*4882a593Smuzhiyun static struct sk_buff *nfc_llcp_allocate_snl(struct nfc_llcp_local *local,
524*4882a593Smuzhiyun 					     size_t tlv_length)
525*4882a593Smuzhiyun {
526*4882a593Smuzhiyun 	struct sk_buff *skb;
527*4882a593Smuzhiyun 	struct nfc_dev *dev;
528*4882a593Smuzhiyun 	u16 size = 0;
529*4882a593Smuzhiyun 
530*4882a593Smuzhiyun 	if (local == NULL)
531*4882a593Smuzhiyun 		return ERR_PTR(-ENODEV);
532*4882a593Smuzhiyun 
533*4882a593Smuzhiyun 	dev = local->dev;
534*4882a593Smuzhiyun 	if (dev == NULL)
535*4882a593Smuzhiyun 		return ERR_PTR(-ENODEV);
536*4882a593Smuzhiyun 
537*4882a593Smuzhiyun 	size += LLCP_HEADER_SIZE;
538*4882a593Smuzhiyun 	size += dev->tx_headroom + dev->tx_tailroom + NFC_HEADER_SIZE;
539*4882a593Smuzhiyun 	size += tlv_length;
540*4882a593Smuzhiyun 
541*4882a593Smuzhiyun 	skb = alloc_skb(size, GFP_KERNEL);
542*4882a593Smuzhiyun 	if (skb == NULL)
543*4882a593Smuzhiyun 		return ERR_PTR(-ENOMEM);
544*4882a593Smuzhiyun 
545*4882a593Smuzhiyun 	skb_reserve(skb, dev->tx_headroom + NFC_HEADER_SIZE);
546*4882a593Smuzhiyun 
547*4882a593Smuzhiyun 	skb = llcp_add_header(skb, LLCP_SAP_SDP, LLCP_SAP_SDP, LLCP_PDU_SNL);
548*4882a593Smuzhiyun 
549*4882a593Smuzhiyun 	return skb;
550*4882a593Smuzhiyun }
551*4882a593Smuzhiyun 
nfc_llcp_send_snl_sdres(struct nfc_llcp_local * local,struct hlist_head * tlv_list,size_t tlvs_len)552*4882a593Smuzhiyun int nfc_llcp_send_snl_sdres(struct nfc_llcp_local *local,
553*4882a593Smuzhiyun 			    struct hlist_head *tlv_list, size_t tlvs_len)
554*4882a593Smuzhiyun {
555*4882a593Smuzhiyun 	struct nfc_llcp_sdp_tlv *sdp;
556*4882a593Smuzhiyun 	struct hlist_node *n;
557*4882a593Smuzhiyun 	struct sk_buff *skb;
558*4882a593Smuzhiyun 
559*4882a593Smuzhiyun 	skb = nfc_llcp_allocate_snl(local, tlvs_len);
560*4882a593Smuzhiyun 	if (IS_ERR(skb))
561*4882a593Smuzhiyun 		return PTR_ERR(skb);
562*4882a593Smuzhiyun 
563*4882a593Smuzhiyun 	hlist_for_each_entry_safe(sdp, n, tlv_list, node) {
564*4882a593Smuzhiyun 		skb_put_data(skb, sdp->tlv, sdp->tlv_len);
565*4882a593Smuzhiyun 
566*4882a593Smuzhiyun 		hlist_del(&sdp->node);
567*4882a593Smuzhiyun 
568*4882a593Smuzhiyun 		nfc_llcp_free_sdp_tlv(sdp);
569*4882a593Smuzhiyun 	}
570*4882a593Smuzhiyun 
571*4882a593Smuzhiyun 	skb_queue_tail(&local->tx_queue, skb);
572*4882a593Smuzhiyun 
573*4882a593Smuzhiyun 	return 0;
574*4882a593Smuzhiyun }
575*4882a593Smuzhiyun 
nfc_llcp_send_snl_sdreq(struct nfc_llcp_local * local,struct hlist_head * tlv_list,size_t tlvs_len)576*4882a593Smuzhiyun int nfc_llcp_send_snl_sdreq(struct nfc_llcp_local *local,
577*4882a593Smuzhiyun 			    struct hlist_head *tlv_list, size_t tlvs_len)
578*4882a593Smuzhiyun {
579*4882a593Smuzhiyun 	struct nfc_llcp_sdp_tlv *sdreq;
580*4882a593Smuzhiyun 	struct hlist_node *n;
581*4882a593Smuzhiyun 	struct sk_buff *skb;
582*4882a593Smuzhiyun 
583*4882a593Smuzhiyun 	skb = nfc_llcp_allocate_snl(local, tlvs_len);
584*4882a593Smuzhiyun 	if (IS_ERR(skb))
585*4882a593Smuzhiyun 		return PTR_ERR(skb);
586*4882a593Smuzhiyun 
587*4882a593Smuzhiyun 	mutex_lock(&local->sdreq_lock);
588*4882a593Smuzhiyun 
589*4882a593Smuzhiyun 	if (hlist_empty(&local->pending_sdreqs))
590*4882a593Smuzhiyun 		mod_timer(&local->sdreq_timer,
591*4882a593Smuzhiyun 			  jiffies + msecs_to_jiffies(3 * local->remote_lto));
592*4882a593Smuzhiyun 
593*4882a593Smuzhiyun 	hlist_for_each_entry_safe(sdreq, n, tlv_list, node) {
594*4882a593Smuzhiyun 		pr_debug("tid %d for %s\n", sdreq->tid, sdreq->uri);
595*4882a593Smuzhiyun 
596*4882a593Smuzhiyun 		skb_put_data(skb, sdreq->tlv, sdreq->tlv_len);
597*4882a593Smuzhiyun 
598*4882a593Smuzhiyun 		hlist_del(&sdreq->node);
599*4882a593Smuzhiyun 
600*4882a593Smuzhiyun 		hlist_add_head(&sdreq->node, &local->pending_sdreqs);
601*4882a593Smuzhiyun 	}
602*4882a593Smuzhiyun 
603*4882a593Smuzhiyun 	mutex_unlock(&local->sdreq_lock);
604*4882a593Smuzhiyun 
605*4882a593Smuzhiyun 	skb_queue_tail(&local->tx_queue, skb);
606*4882a593Smuzhiyun 
607*4882a593Smuzhiyun 	return 0;
608*4882a593Smuzhiyun }
609*4882a593Smuzhiyun 
nfc_llcp_send_dm(struct nfc_llcp_local * local,u8 ssap,u8 dsap,u8 reason)610*4882a593Smuzhiyun int nfc_llcp_send_dm(struct nfc_llcp_local *local, u8 ssap, u8 dsap, u8 reason)
611*4882a593Smuzhiyun {
612*4882a593Smuzhiyun 	struct sk_buff *skb;
613*4882a593Smuzhiyun 	struct nfc_dev *dev;
614*4882a593Smuzhiyun 	u16 size = 1; /* Reason code */
615*4882a593Smuzhiyun 
616*4882a593Smuzhiyun 	pr_debug("Sending DM reason 0x%x\n", reason);
617*4882a593Smuzhiyun 
618*4882a593Smuzhiyun 	if (local == NULL)
619*4882a593Smuzhiyun 		return -ENODEV;
620*4882a593Smuzhiyun 
621*4882a593Smuzhiyun 	dev = local->dev;
622*4882a593Smuzhiyun 	if (dev == NULL)
623*4882a593Smuzhiyun 		return -ENODEV;
624*4882a593Smuzhiyun 
625*4882a593Smuzhiyun 	size += LLCP_HEADER_SIZE;
626*4882a593Smuzhiyun 	size += dev->tx_headroom + dev->tx_tailroom + NFC_HEADER_SIZE;
627*4882a593Smuzhiyun 
628*4882a593Smuzhiyun 	skb = alloc_skb(size, GFP_KERNEL);
629*4882a593Smuzhiyun 	if (skb == NULL)
630*4882a593Smuzhiyun 		return -ENOMEM;
631*4882a593Smuzhiyun 
632*4882a593Smuzhiyun 	skb_reserve(skb, dev->tx_headroom + NFC_HEADER_SIZE);
633*4882a593Smuzhiyun 
634*4882a593Smuzhiyun 	skb = llcp_add_header(skb, dsap, ssap, LLCP_PDU_DM);
635*4882a593Smuzhiyun 
636*4882a593Smuzhiyun 	skb_put_data(skb, &reason, 1);
637*4882a593Smuzhiyun 
638*4882a593Smuzhiyun 	skb_queue_head(&local->tx_queue, skb);
639*4882a593Smuzhiyun 
640*4882a593Smuzhiyun 	return 0;
641*4882a593Smuzhiyun }
642*4882a593Smuzhiyun 
nfc_llcp_send_i_frame(struct nfc_llcp_sock * sock,struct msghdr * msg,size_t len)643*4882a593Smuzhiyun int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock,
644*4882a593Smuzhiyun 			  struct msghdr *msg, size_t len)
645*4882a593Smuzhiyun {
646*4882a593Smuzhiyun 	struct sk_buff *pdu;
647*4882a593Smuzhiyun 	struct sock *sk = &sock->sk;
648*4882a593Smuzhiyun 	struct nfc_llcp_local *local;
649*4882a593Smuzhiyun 	size_t frag_len = 0, remaining_len;
650*4882a593Smuzhiyun 	u8 *msg_data, *msg_ptr;
651*4882a593Smuzhiyun 	u16 remote_miu;
652*4882a593Smuzhiyun 
653*4882a593Smuzhiyun 	pr_debug("Send I frame len %zd\n", len);
654*4882a593Smuzhiyun 
655*4882a593Smuzhiyun 	local = sock->local;
656*4882a593Smuzhiyun 	if (local == NULL)
657*4882a593Smuzhiyun 		return -ENODEV;
658*4882a593Smuzhiyun 
659*4882a593Smuzhiyun 	/* Remote is ready but has not acknowledged our frames */
660*4882a593Smuzhiyun 	if((sock->remote_ready &&
661*4882a593Smuzhiyun 	    skb_queue_len(&sock->tx_pending_queue) >= sock->remote_rw &&
662*4882a593Smuzhiyun 	    skb_queue_len(&sock->tx_queue) >= 2 * sock->remote_rw)) {
663*4882a593Smuzhiyun 		pr_err("Pending queue is full %d frames\n",
664*4882a593Smuzhiyun 		       skb_queue_len(&sock->tx_pending_queue));
665*4882a593Smuzhiyun 		return -ENOBUFS;
666*4882a593Smuzhiyun 	}
667*4882a593Smuzhiyun 
668*4882a593Smuzhiyun 	/* Remote is not ready and we've been queueing enough frames */
669*4882a593Smuzhiyun 	if ((!sock->remote_ready &&
670*4882a593Smuzhiyun 	     skb_queue_len(&sock->tx_queue) >= 2 * sock->remote_rw)) {
671*4882a593Smuzhiyun 		pr_err("Tx queue is full %d frames\n",
672*4882a593Smuzhiyun 		       skb_queue_len(&sock->tx_queue));
673*4882a593Smuzhiyun 		return -ENOBUFS;
674*4882a593Smuzhiyun 	}
675*4882a593Smuzhiyun 
676*4882a593Smuzhiyun 	msg_data = kmalloc(len, GFP_USER | __GFP_NOWARN);
677*4882a593Smuzhiyun 	if (msg_data == NULL)
678*4882a593Smuzhiyun 		return -ENOMEM;
679*4882a593Smuzhiyun 
680*4882a593Smuzhiyun 	if (memcpy_from_msg(msg_data, msg, len)) {
681*4882a593Smuzhiyun 		kfree(msg_data);
682*4882a593Smuzhiyun 		return -EFAULT;
683*4882a593Smuzhiyun 	}
684*4882a593Smuzhiyun 
685*4882a593Smuzhiyun 	remaining_len = len;
686*4882a593Smuzhiyun 	msg_ptr = msg_data;
687*4882a593Smuzhiyun 
688*4882a593Smuzhiyun 	do {
689*4882a593Smuzhiyun 		remote_miu = sock->remote_miu > LLCP_MAX_MIU ?
690*4882a593Smuzhiyun 				LLCP_DEFAULT_MIU : sock->remote_miu;
691*4882a593Smuzhiyun 
692*4882a593Smuzhiyun 		frag_len = min_t(size_t, remote_miu, remaining_len);
693*4882a593Smuzhiyun 
694*4882a593Smuzhiyun 		pr_debug("Fragment %zd bytes remaining %zd",
695*4882a593Smuzhiyun 			 frag_len, remaining_len);
696*4882a593Smuzhiyun 
697*4882a593Smuzhiyun 		pdu = llcp_allocate_pdu(sock, LLCP_PDU_I,
698*4882a593Smuzhiyun 					frag_len + LLCP_SEQUENCE_SIZE);
699*4882a593Smuzhiyun 		if (pdu == NULL) {
700*4882a593Smuzhiyun 			kfree(msg_data);
701*4882a593Smuzhiyun 			return -ENOMEM;
702*4882a593Smuzhiyun 		}
703*4882a593Smuzhiyun 
704*4882a593Smuzhiyun 		skb_put(pdu, LLCP_SEQUENCE_SIZE);
705*4882a593Smuzhiyun 
706*4882a593Smuzhiyun 		if (likely(frag_len > 0))
707*4882a593Smuzhiyun 			skb_put_data(pdu, msg_ptr, frag_len);
708*4882a593Smuzhiyun 
709*4882a593Smuzhiyun 		skb_queue_tail(&sock->tx_queue, pdu);
710*4882a593Smuzhiyun 
711*4882a593Smuzhiyun 		lock_sock(sk);
712*4882a593Smuzhiyun 
713*4882a593Smuzhiyun 		nfc_llcp_queue_i_frames(sock);
714*4882a593Smuzhiyun 
715*4882a593Smuzhiyun 		release_sock(sk);
716*4882a593Smuzhiyun 
717*4882a593Smuzhiyun 		remaining_len -= frag_len;
718*4882a593Smuzhiyun 		msg_ptr += frag_len;
719*4882a593Smuzhiyun 	} while (remaining_len > 0);
720*4882a593Smuzhiyun 
721*4882a593Smuzhiyun 	kfree(msg_data);
722*4882a593Smuzhiyun 
723*4882a593Smuzhiyun 	return len;
724*4882a593Smuzhiyun }
725*4882a593Smuzhiyun 
nfc_llcp_send_ui_frame(struct nfc_llcp_sock * sock,u8 ssap,u8 dsap,struct msghdr * msg,size_t len)726*4882a593Smuzhiyun int nfc_llcp_send_ui_frame(struct nfc_llcp_sock *sock, u8 ssap, u8 dsap,
727*4882a593Smuzhiyun 			   struct msghdr *msg, size_t len)
728*4882a593Smuzhiyun {
729*4882a593Smuzhiyun 	struct sk_buff *pdu;
730*4882a593Smuzhiyun 	struct nfc_llcp_local *local;
731*4882a593Smuzhiyun 	size_t frag_len = 0, remaining_len;
732*4882a593Smuzhiyun 	u8 *msg_ptr, *msg_data;
733*4882a593Smuzhiyun 	u16 remote_miu;
734*4882a593Smuzhiyun 	int err;
735*4882a593Smuzhiyun 
736*4882a593Smuzhiyun 	pr_debug("Send UI frame len %zd\n", len);
737*4882a593Smuzhiyun 
738*4882a593Smuzhiyun 	local = sock->local;
739*4882a593Smuzhiyun 	if (local == NULL)
740*4882a593Smuzhiyun 		return -ENODEV;
741*4882a593Smuzhiyun 
742*4882a593Smuzhiyun 	msg_data = kmalloc(len, GFP_USER | __GFP_NOWARN);
743*4882a593Smuzhiyun 	if (msg_data == NULL)
744*4882a593Smuzhiyun 		return -ENOMEM;
745*4882a593Smuzhiyun 
746*4882a593Smuzhiyun 	if (memcpy_from_msg(msg_data, msg, len)) {
747*4882a593Smuzhiyun 		kfree(msg_data);
748*4882a593Smuzhiyun 		return -EFAULT;
749*4882a593Smuzhiyun 	}
750*4882a593Smuzhiyun 
751*4882a593Smuzhiyun 	remaining_len = len;
752*4882a593Smuzhiyun 	msg_ptr = msg_data;
753*4882a593Smuzhiyun 
754*4882a593Smuzhiyun 	do {
755*4882a593Smuzhiyun 		remote_miu = sock->remote_miu > LLCP_MAX_MIU ?
756*4882a593Smuzhiyun 				local->remote_miu : sock->remote_miu;
757*4882a593Smuzhiyun 
758*4882a593Smuzhiyun 		frag_len = min_t(size_t, remote_miu, remaining_len);
759*4882a593Smuzhiyun 
760*4882a593Smuzhiyun 		pr_debug("Fragment %zd bytes remaining %zd",
761*4882a593Smuzhiyun 			 frag_len, remaining_len);
762*4882a593Smuzhiyun 
763*4882a593Smuzhiyun 		pdu = nfc_alloc_send_skb(sock->dev, &sock->sk, 0,
764*4882a593Smuzhiyun 					 frag_len + LLCP_HEADER_SIZE, &err);
765*4882a593Smuzhiyun 		if (pdu == NULL) {
766*4882a593Smuzhiyun 			pr_err("Could not allocate PDU (error=%d)\n", err);
767*4882a593Smuzhiyun 			len -= remaining_len;
768*4882a593Smuzhiyun 			if (len == 0)
769*4882a593Smuzhiyun 				len = err;
770*4882a593Smuzhiyun 			break;
771*4882a593Smuzhiyun 		}
772*4882a593Smuzhiyun 
773*4882a593Smuzhiyun 		pdu = llcp_add_header(pdu, dsap, ssap, LLCP_PDU_UI);
774*4882a593Smuzhiyun 
775*4882a593Smuzhiyun 		if (likely(frag_len > 0))
776*4882a593Smuzhiyun 			skb_put_data(pdu, msg_ptr, frag_len);
777*4882a593Smuzhiyun 
778*4882a593Smuzhiyun 		/* No need to check for the peer RW for UI frames */
779*4882a593Smuzhiyun 		skb_queue_tail(&local->tx_queue, pdu);
780*4882a593Smuzhiyun 
781*4882a593Smuzhiyun 		remaining_len -= frag_len;
782*4882a593Smuzhiyun 		msg_ptr += frag_len;
783*4882a593Smuzhiyun 	} while (remaining_len > 0);
784*4882a593Smuzhiyun 
785*4882a593Smuzhiyun 	kfree(msg_data);
786*4882a593Smuzhiyun 
787*4882a593Smuzhiyun 	return len;
788*4882a593Smuzhiyun }
789*4882a593Smuzhiyun 
nfc_llcp_send_rr(struct nfc_llcp_sock * sock)790*4882a593Smuzhiyun int nfc_llcp_send_rr(struct nfc_llcp_sock *sock)
791*4882a593Smuzhiyun {
792*4882a593Smuzhiyun 	struct sk_buff *skb;
793*4882a593Smuzhiyun 	struct nfc_llcp_local *local;
794*4882a593Smuzhiyun 
795*4882a593Smuzhiyun 	pr_debug("Send rr nr %d\n", sock->recv_n);
796*4882a593Smuzhiyun 
797*4882a593Smuzhiyun 	local = sock->local;
798*4882a593Smuzhiyun 	if (local == NULL)
799*4882a593Smuzhiyun 		return -ENODEV;
800*4882a593Smuzhiyun 
801*4882a593Smuzhiyun 	skb = llcp_allocate_pdu(sock, LLCP_PDU_RR, LLCP_SEQUENCE_SIZE);
802*4882a593Smuzhiyun 	if (skb == NULL)
803*4882a593Smuzhiyun 		return -ENOMEM;
804*4882a593Smuzhiyun 
805*4882a593Smuzhiyun 	skb_put(skb, LLCP_SEQUENCE_SIZE);
806*4882a593Smuzhiyun 
807*4882a593Smuzhiyun 	skb->data[2] = sock->recv_n;
808*4882a593Smuzhiyun 
809*4882a593Smuzhiyun 	skb_queue_head(&local->tx_queue, skb);
810*4882a593Smuzhiyun 
811*4882a593Smuzhiyun 	return 0;
812*4882a593Smuzhiyun }
813