Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
data.c
Go to the documentation of this file.
1 /*
2  * The NFC Controller Interface is the communication protocol between an
3  * NFC Controller (NFCC) and a Device Host (DH).
4  *
5  * Copyright (C) 2011 Texas Instruments, Inc.
6  *
7  * Written by Ilan Elias <[email protected]>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License version 2
11  * as published by the Free Software Foundation
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21  *
22  */
23 
24 #define pr_fmt(fmt) KBUILD_MODNAME ": %s: " fmt, __func__
25 
26 #include <linux/types.h>
27 #include <linux/interrupt.h>
28 #include <linux/wait.h>
29 #include <linux/bitops.h>
30 #include <linux/skbuff.h>
31 
32 #include "../nfc.h"
33 #include <net/nfc/nci.h>
34 #include <net/nfc/nci_core.h>
35 #include <linux/nfc.h>
36 
37 /* Complete data exchange transaction and forward skb to nfc core */
39  int err)
40 {
42  void *cb_context = ndev->data_exchange_cb_context;
43 
44  pr_debug("len %d, err %d\n", skb ? skb->len : 0, err);
45 
46  /* data exchange is complete, stop the data timer */
47  del_timer_sync(&ndev->data_timer);
49 
50  if (cb) {
51  ndev->data_exchange_cb = NULL;
53 
54  /* forward skb to nfc core */
55  cb(cb_context, skb, err);
56  } else if (skb) {
57  pr_err("no rx callback, dropping rx data...\n");
58 
59  /* no waiting callback, free skb */
60  kfree_skb(skb);
61  }
62 
64 }
65 
66 /* ----------------- NCI TX Data ----------------- */
67 
68 static inline void nci_push_data_hdr(struct nci_dev *ndev,
69  __u8 conn_id,
70  struct sk_buff *skb,
71  __u8 pbf)
72 {
73  struct nci_data_hdr *hdr;
74  int plen = skb->len;
75 
76  hdr = (struct nci_data_hdr *) skb_push(skb, NCI_DATA_HDR_SIZE);
77  hdr->conn_id = conn_id;
78  hdr->rfu = 0;
79  hdr->plen = plen;
80 
82  nci_pbf_set((__u8 *)hdr, pbf);
83 
84  skb->dev = (void *) ndev;
85 }
86 
87 static int nci_queue_tx_data_frags(struct nci_dev *ndev,
88  __u8 conn_id,
89  struct sk_buff *skb) {
90  int total_len = skb->len;
91  unsigned char *data = skb->data;
92  unsigned long flags;
93  struct sk_buff_head frags_q;
94  struct sk_buff *skb_frag;
95  int frag_len;
96  int rc = 0;
97 
98  pr_debug("conn_id 0x%x, total_len %d\n", conn_id, total_len);
99 
100  __skb_queue_head_init(&frags_q);
101 
102  while (total_len) {
103  frag_len =
104  min_t(int, total_len, ndev->max_data_pkt_payload_size);
105 
106  skb_frag = nci_skb_alloc(ndev,
107  (NCI_DATA_HDR_SIZE + frag_len),
108  GFP_KERNEL);
109  if (skb_frag == NULL) {
110  rc = -ENOMEM;
111  goto free_exit;
112  }
113  skb_reserve(skb_frag, NCI_DATA_HDR_SIZE);
114 
115  /* first, copy the data */
116  memcpy(skb_put(skb_frag, frag_len), data, frag_len);
117 
118  /* second, set the header */
119  nci_push_data_hdr(ndev, conn_id, skb_frag,
120  ((total_len == frag_len) ?
121  (NCI_PBF_LAST) : (NCI_PBF_CONT)));
122 
123  __skb_queue_tail(&frags_q, skb_frag);
124 
125  data += frag_len;
126  total_len -= frag_len;
127 
128  pr_debug("frag_len %d, remaining total_len %d\n",
129  frag_len, total_len);
130  }
131 
132  /* queue all fragments atomically */
133  spin_lock_irqsave(&ndev->tx_q.lock, flags);
134 
135  while ((skb_frag = __skb_dequeue(&frags_q)) != NULL)
136  __skb_queue_tail(&ndev->tx_q, skb_frag);
137 
138  spin_unlock_irqrestore(&ndev->tx_q.lock, flags);
139 
140  /* free the original skb */
141  kfree_skb(skb);
142 
143  goto exit;
144 
145 free_exit:
146  while ((skb_frag = __skb_dequeue(&frags_q)) != NULL)
147  kfree_skb(skb_frag);
148 
149 exit:
150  return rc;
151 }
152 
153 /* Send NCI data */
154 int nci_send_data(struct nci_dev *ndev, __u8 conn_id, struct sk_buff *skb)
155 {
156  int rc = 0;
157 
158  pr_debug("conn_id 0x%x, plen %d\n", conn_id, skb->len);
159 
160  /* check if the packet need to be fragmented */
161  if (skb->len <= ndev->max_data_pkt_payload_size) {
162  /* no need to fragment packet */
163  nci_push_data_hdr(ndev, conn_id, skb, NCI_PBF_LAST);
164 
165  skb_queue_tail(&ndev->tx_q, skb);
166  } else {
167  /* fragment packet and queue the fragments */
168  rc = nci_queue_tx_data_frags(ndev, conn_id, skb);
169  if (rc) {
170  pr_err("failed to fragment tx data packet\n");
171  goto free_exit;
172  }
173  }
174 
175  queue_work(ndev->tx_wq, &ndev->tx_work);
176 
177  goto exit;
178 
179 free_exit:
180  kfree_skb(skb);
181 
182 exit:
183  return rc;
184 }
185 
186 /* ----------------- NCI RX Data ----------------- */
187 
188 static void nci_add_rx_data_frag(struct nci_dev *ndev,
189  struct sk_buff *skb,
190  __u8 pbf)
191 {
192  int reassembly_len;
193  int err = 0;
194 
195  if (ndev->rx_data_reassembly) {
196  reassembly_len = ndev->rx_data_reassembly->len;
197 
198  /* first, make enough room for the already accumulated data */
199  if (skb_cow_head(skb, reassembly_len)) {
200  pr_err("error adding room for accumulated rx data\n");
201 
202  kfree_skb(skb);
203  skb = NULL;
204 
206  ndev->rx_data_reassembly = NULL;
207 
208  err = -ENOMEM;
209  goto exit;
210  }
211 
212  /* second, combine the two fragments */
213  memcpy(skb_push(skb, reassembly_len),
214  ndev->rx_data_reassembly->data,
215  reassembly_len);
216 
217  /* third, free old reassembly */
219  ndev->rx_data_reassembly = NULL;
220  }
221 
222  if (pbf == NCI_PBF_CONT) {
223  /* need to wait for next fragment, store skb and exit */
224  ndev->rx_data_reassembly = skb;
225  return;
226  }
227 
228 exit:
229  nci_data_exchange_complete(ndev, skb, err);
230 }
231 
232 /* Rx Data packet */
233 void nci_rx_data_packet(struct nci_dev *ndev, struct sk_buff *skb)
234 {
235  __u8 pbf = nci_pbf(skb->data);
236 
237  pr_debug("len %d\n", skb->len);
238 
239  pr_debug("NCI RX: MT=data, PBF=%d, conn_id=%d, plen=%d\n",
240  nci_pbf(skb->data),
241  nci_conn_id(skb->data),
242  nci_plen(skb->data));
243 
244  /* strip the nci data header */
246 
247  if (ndev->target_active_prot == NFC_PROTO_MIFARE) {
248  /* frame I/F => remove the status byte */
249  pr_debug("NFC_PROTO_MIFARE => remove the status byte\n");
250  skb_trim(skb, (skb->len - 1));
251  }
252 
253  nci_add_rx_data_frag(ndev, skb, pbf);
254 }