aboutsummaryrefslogtreecommitdiffstats
path: root/net/nfc
diff options
context:
space:
mode:
authorSamuel Ortiz <sameo@linux.intel.com>2012-12-07 10:37:30 -0500
committerSamuel Ortiz <sameo@linux.intel.com>2013-01-09 18:48:25 -0500
commit1727cf937401945a590ebf25c7fa65a4853fe9bb (patch)
tree481c0ec5c71347d2e4cded197d106e31b4b53c25 /net/nfc
parent2593c2c6ec236c6aedbb8182d103185ab6580285 (diff)
NFC: llcp: Fix Rx memory leak
The reference count bump on the llcp Rx path is leading to a memory leak whenever we're not receiving an I frame. We fix that by removing the refcount bump (drivers must not free their received skb) and using it only in the I frame path, when the frame is actually queued. In that case, the skb will only be freed when someone fetches it from userspace. in all other cases, LLCP received frames will be freed when leaving the Rx work queue. Reported-by: Eric Lapuyade <eric.lapuyade@linux.intel.com> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Diffstat (limited to 'net/nfc')
-rw-r--r--net/nfc/llcp/llcp.c35
1 files changed, 25 insertions, 10 deletions
diff --git a/net/nfc/llcp/llcp.c b/net/nfc/llcp/llcp.c
index 003c82fe8bd7..85bc75c38dea 100644
--- a/net/nfc/llcp/llcp.c
+++ b/net/nfc/llcp/llcp.c
@@ -782,8 +782,14 @@ static void nfc_llcp_recv_ui(struct nfc_llcp_local *local,
782 782
783 /* There is no sequence with UI frames */ 783 /* There is no sequence with UI frames */
784 skb_pull(skb, LLCP_HEADER_SIZE); 784 skb_pull(skb, LLCP_HEADER_SIZE);
785 if (sock_queue_rcv_skb(&llcp_sock->sk, skb)) { 785 if (!sock_queue_rcv_skb(&llcp_sock->sk, skb)) {
786 pr_err("receive queue is full\n"); 786 /*
787 * UI frames will be freed from the socket layer, so we
788 * need to keep them alive until someone receives them.
789 */
790 skb_get(skb);
791 } else {
792 pr_err("Receive queue is full\n");
787 kfree_skb(skb); 793 kfree_skb(skb);
788 } 794 }
789 795
@@ -977,8 +983,14 @@ static void nfc_llcp_recv_hdlc(struct nfc_llcp_local *local,
977 pr_err("Received out of sequence I PDU\n"); 983 pr_err("Received out of sequence I PDU\n");
978 984
979 skb_pull(skb, LLCP_HEADER_SIZE + LLCP_SEQUENCE_SIZE); 985 skb_pull(skb, LLCP_HEADER_SIZE + LLCP_SEQUENCE_SIZE);
980 if (sock_queue_rcv_skb(&llcp_sock->sk, skb)) { 986 if (!sock_queue_rcv_skb(&llcp_sock->sk, skb)) {
981 pr_err("receive queue is full\n"); 987 /*
988 * I frames will be freed from the socket layer, so we
989 * need to keep them alive until someone receives them.
990 */
991 skb_get(skb);
992 } else {
993 pr_err("Receive queue is full\n");
982 kfree_skb(skb); 994 kfree_skb(skb);
983 } 995 }
984 } 996 }
@@ -1299,6 +1311,13 @@ static void nfc_llcp_rx_work(struct work_struct *work)
1299 local->rx_pending = NULL; 1311 local->rx_pending = NULL;
1300} 1312}
1301 1313
1314static void __nfc_llcp_recv(struct nfc_llcp_local *local, struct sk_buff *skb)
1315{
1316 local->rx_pending = skb;
1317 del_timer(&local->link_timer);
1318 schedule_work(&local->rx_work);
1319}
1320
1302void nfc_llcp_recv(void *data, struct sk_buff *skb, int err) 1321void nfc_llcp_recv(void *data, struct sk_buff *skb, int err)
1303{ 1322{
1304 struct nfc_llcp_local *local = (struct nfc_llcp_local *) data; 1323 struct nfc_llcp_local *local = (struct nfc_llcp_local *) data;
@@ -1309,9 +1328,7 @@ void nfc_llcp_recv(void *data, struct sk_buff *skb, int err)
1309 return; 1328 return;
1310 } 1329 }
1311 1330
1312 local->rx_pending = skb_get(skb); 1331 __nfc_llcp_recv(local, skb);
1313 del_timer(&local->link_timer);
1314 schedule_work(&local->rx_work);
1315} 1332}
1316 1333
1317int nfc_llcp_data_received(struct nfc_dev *dev, struct sk_buff *skb) 1334int nfc_llcp_data_received(struct nfc_dev *dev, struct sk_buff *skb)
@@ -1322,9 +1339,7 @@ int nfc_llcp_data_received(struct nfc_dev *dev, struct sk_buff *skb)
1322 if (local == NULL) 1339 if (local == NULL)
1323 return -ENODEV; 1340 return -ENODEV;
1324 1341
1325 local->rx_pending = skb_get(skb); 1342 __nfc_llcp_recv(local, skb);
1326 del_timer(&local->link_timer);
1327 schedule_work(&local->rx_work);
1328 1343
1329 return 0; 1344 return 0;
1330} 1345}