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 <ilane@ti.com> 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 #include <linux/types.h> 25 #include <linux/interrupt.h> 26 #include <linux/wait.h> 27 #include <linux/bitops.h> 28 #include <linux/skbuff.h> 29 30 #include "../nfc.h" 31 #include <net/nfc/nci.h> 32 #include <net/nfc/nci_core.h> 33 #include <linux/nfc.h> 34 35 /* Complete data exchange transaction and forward skb to nfc core */ 36 void nci_data_exchange_complete(struct nci_dev *ndev, 37 struct sk_buff *skb, 38 int err) 39 { 40 data_exchange_cb_t cb = ndev->data_exchange_cb; 41 void *cb_context = ndev->data_exchange_cb_context; 42 43 nfc_dbg("entry, len %d, err %d", ((skb) ? (skb->len) : (0)), err); 44 45 if (cb) { 46 ndev->data_exchange_cb = NULL; 47 ndev->data_exchange_cb_context = 0; 48 49 /* forward skb to nfc core */ 50 cb(cb_context, skb, err); 51 } else if (skb) { 52 nfc_err("no rx callback, dropping rx data..."); 53 54 /* no waiting callback, free skb */ 55 kfree_skb(skb); 56 } 57 58 clear_bit(NCI_DATA_EXCHANGE, &ndev->flags); 59 } 60 61 /* ----------------- NCI TX Data ----------------- */ 62 63 static inline void nci_push_data_hdr(struct nci_dev *ndev, 64 __u8 conn_id, 65 struct sk_buff *skb, 66 __u8 pbf) 67 { 68 struct nci_data_hdr *hdr; 69 int plen = skb->len; 70 71 hdr = (struct nci_data_hdr *) skb_push(skb, NCI_DATA_HDR_SIZE); 72 hdr->conn_id = conn_id; 73 hdr->rfu = 0; 74 hdr->plen = plen; 75 76 nci_mt_set((__u8 *)hdr, NCI_MT_DATA_PKT); 77 nci_pbf_set((__u8 *)hdr, pbf); 78 79 skb->dev = (void *) ndev; 80 } 81 82 static int nci_queue_tx_data_frags(struct nci_dev *ndev, 83 __u8 conn_id, 84 struct sk_buff *skb) { 85 int total_len = skb->len; 86 unsigned char *data = skb->data; 87 unsigned long flags; 88 struct sk_buff_head frags_q; 89 struct sk_buff *skb_frag; 90 int frag_len; 91 int rc = 0; 92 93 nfc_dbg("entry, conn_id 0x%x, total_len %d", conn_id, total_len); 94 95 __skb_queue_head_init(&frags_q); 96 97 while (total_len) { 98 frag_len = min_t(int, total_len, ndev->max_pkt_payload_size); 99 100 skb_frag = nci_skb_alloc(ndev, 101 (NCI_DATA_HDR_SIZE + frag_len), 102 GFP_KERNEL); 103 if (skb_frag == NULL) { 104 rc = -ENOMEM; 105 goto free_exit; 106 } 107 skb_reserve(skb_frag, NCI_DATA_HDR_SIZE); 108 109 /* first, copy the data */ 110 memcpy(skb_put(skb_frag, frag_len), data, frag_len); 111 112 /* second, set the header */ 113 nci_push_data_hdr(ndev, conn_id, skb_frag, 114 ((total_len == frag_len) ? (NCI_PBF_LAST) : (NCI_PBF_CONT))); 115 116 __skb_queue_tail(&frags_q, skb_frag); 117 118 data += frag_len; 119 total_len -= frag_len; 120 121 nfc_dbg("frag_len %d, remaining total_len %d", 122 frag_len, total_len); 123 } 124 125 /* queue all fragments atomically */ 126 spin_lock_irqsave(&ndev->tx_q.lock, flags); 127 128 while ((skb_frag = __skb_dequeue(&frags_q)) != NULL) 129 __skb_queue_tail(&ndev->tx_q, skb_frag); 130 131 spin_unlock_irqrestore(&ndev->tx_q.lock, flags); 132 133 /* free the original skb */ 134 kfree_skb(skb); 135 136 goto exit; 137 138 free_exit: 139 while ((skb_frag = __skb_dequeue(&frags_q)) != NULL) 140 kfree_skb(skb_frag); 141 142 exit: 143 return rc; 144 } 145 146 /* Send NCI data */ 147 int nci_send_data(struct nci_dev *ndev, __u8 conn_id, struct sk_buff *skb) 148 { 149 int rc = 0; 150 151 nfc_dbg("entry, conn_id 0x%x, plen %d", conn_id, skb->len); 152 153 /* check if the packet need to be fragmented */ 154 if (skb->len <= ndev->max_pkt_payload_size) { 155 /* no need to fragment packet */ 156 nci_push_data_hdr(ndev, conn_id, skb, NCI_PBF_LAST); 157 158 skb_queue_tail(&ndev->tx_q, skb); 159 } else { 160 /* fragment packet and queue the fragments */ 161 rc = nci_queue_tx_data_frags(ndev, conn_id, skb); 162 if (rc) { 163 nfc_err("failed to fragment tx data packet"); 164 goto free_exit; 165 } 166 } 167 168 queue_work(ndev->tx_wq, &ndev->tx_work); 169 170 goto exit; 171 172 free_exit: 173 kfree_skb(skb); 174 175 exit: 176 return rc; 177 } 178 179 /* ----------------- NCI RX Data ----------------- */ 180 181 static void nci_add_rx_data_frag(struct nci_dev *ndev, 182 struct sk_buff *skb, 183 __u8 pbf) 184 { 185 int reassembly_len; 186 int err = 0; 187 188 if (ndev->rx_data_reassembly) { 189 reassembly_len = ndev->rx_data_reassembly->len; 190 191 /* first, make enough room for the already accumulated data */ 192 if (skb_cow_head(skb, reassembly_len)) { 193 nfc_err("error adding room for accumulated rx data"); 194 195 kfree_skb(skb); 196 skb = 0; 197 198 kfree_skb(ndev->rx_data_reassembly); 199 ndev->rx_data_reassembly = 0; 200 201 err = -ENOMEM; 202 goto exit; 203 } 204 205 /* second, combine the two fragments */ 206 memcpy(skb_push(skb, reassembly_len), 207 ndev->rx_data_reassembly->data, 208 reassembly_len); 209 210 /* third, free old reassembly */ 211 kfree_skb(ndev->rx_data_reassembly); 212 ndev->rx_data_reassembly = 0; 213 } 214 215 if (pbf == NCI_PBF_CONT) { 216 /* need to wait for next fragment, store skb and exit */ 217 ndev->rx_data_reassembly = skb; 218 return; 219 } 220 221 exit: 222 nci_data_exchange_complete(ndev, skb, err); 223 } 224 225 /* Rx Data packet */ 226 void nci_rx_data_packet(struct nci_dev *ndev, struct sk_buff *skb) 227 { 228 __u8 pbf = nci_pbf(skb->data); 229 230 nfc_dbg("entry, len %d", skb->len); 231 232 nfc_dbg("NCI RX: MT=data, PBF=%d, conn_id=%d, plen=%d", 233 nci_pbf(skb->data), 234 nci_conn_id(skb->data), 235 nci_plen(skb->data)); 236 237 /* strip the nci data header */ 238 skb_pull(skb, NCI_DATA_HDR_SIZE); 239 240 if (ndev->target_active_prot == NFC_PROTO_MIFARE) { 241 /* frame I/F => remove the status byte */ 242 nfc_dbg("NFC_PROTO_MIFARE => remove the status byte"); 243 skb_trim(skb, (skb->len - 1)); 244 } 245 246 nci_add_rx_data_frag(ndev, skb, pbf); 247 } 248