diff options
author | alex.bluesman.smirnov@gmail.com <alex.bluesman.smirnov@gmail.com> | 2012-05-15 16:50:21 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-05-16 15:16:44 -0400 |
commit | 1cd829c83eab8b899b85d597c767fcf8b4cf8fd6 (patch) | |
tree | b081f047332ceeaffd25ec55a5e8f9158a52360a /net/mac802154/rx.c | |
parent | 1010f540181b00c7013eeb04d1bf8aedd5a56835 (diff) |
mac802154: RX data path
Main RX data path implementation between physical and mac layers.
Signed-off-by: Alexander Smirnov <alex.bluesman.smirnov@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/mac802154/rx.c')
-rw-r--r-- | net/mac802154/rx.c | 113 |
1 files changed, 113 insertions, 0 deletions
diff --git a/net/mac802154/rx.c b/net/mac802154/rx.c new file mode 100644 index 000000000000..d15738fae551 --- /dev/null +++ b/net/mac802154/rx.c | |||
@@ -0,0 +1,113 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2007-2012 Siemens AG | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 | ||
6 | * as published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, | ||
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
11 | * GNU General Public License for more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License along | ||
14 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
15 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
16 | * | ||
17 | * Written by: | ||
18 | * Pavel Smolenskiy <pavel.smolenskiy@gmail.com> | ||
19 | * Maxim Gorbachyov <maxim.gorbachev@siemens.com> | ||
20 | * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> | ||
21 | * Alexander Smirnov <alex.bluesman.smirnov@gmail.com> | ||
22 | */ | ||
23 | |||
24 | #include <linux/kernel.h> | ||
25 | #include <linux/module.h> | ||
26 | #include <linux/workqueue.h> | ||
27 | #include <linux/netdevice.h> | ||
28 | #include <linux/crc-ccitt.h> | ||
29 | |||
30 | #include <net/mac802154.h> | ||
31 | #include <net/ieee802154_netdev.h> | ||
32 | |||
33 | #include "mac802154.h" | ||
34 | |||
35 | /* The IEEE 802.15.4 standard defines 4 MAC packet types: | ||
36 | * - beacon frame | ||
37 | * - MAC command frame | ||
38 | * - acknowledgement frame | ||
39 | * - data frame | ||
40 | * | ||
41 | * and only the data frame should be pushed to the upper layers, other types | ||
42 | * are just internal MAC layer management information. So only data packets | ||
43 | * are going to be sent to the networking queue, all other will be processed | ||
44 | * right here by using the device workqueue. | ||
45 | */ | ||
46 | struct rx_work { | ||
47 | struct sk_buff *skb; | ||
48 | struct work_struct work; | ||
49 | struct ieee802154_dev *dev; | ||
50 | u8 lqi; | ||
51 | }; | ||
52 | |||
53 | static void | ||
54 | mac802154_subif_rx(struct ieee802154_dev *hw, struct sk_buff *skb, u8 lqi) | ||
55 | { | ||
56 | struct mac802154_priv *priv = mac802154_to_priv(hw); | ||
57 | |||
58 | mac_cb(skb)->lqi = lqi; | ||
59 | skb->protocol = htons(ETH_P_IEEE802154); | ||
60 | skb_reset_mac_header(skb); | ||
61 | |||
62 | BUILD_BUG_ON(sizeof(struct ieee802154_mac_cb) > sizeof(skb->cb)); | ||
63 | |||
64 | if (!(priv->hw.flags & IEEE802154_HW_OMIT_CKSUM)) { | ||
65 | u16 crc; | ||
66 | |||
67 | if (skb->len < 2) { | ||
68 | pr_debug("got invalid frame\n"); | ||
69 | goto out; | ||
70 | } | ||
71 | crc = crc_ccitt(0, skb->data, skb->len); | ||
72 | if (crc) { | ||
73 | pr_debug("CRC mismatch\n"); | ||
74 | goto out; | ||
75 | } | ||
76 | skb_trim(skb, skb->len - 2); /* CRC */ | ||
77 | } | ||
78 | |||
79 | out: | ||
80 | dev_kfree_skb(skb); | ||
81 | return; | ||
82 | } | ||
83 | |||
84 | static void mac802154_rx_worker(struct work_struct *work) | ||
85 | { | ||
86 | struct rx_work *rw = container_of(work, struct rx_work, work); | ||
87 | struct sk_buff *skb = rw->skb; | ||
88 | |||
89 | mac802154_subif_rx(rw->dev, skb, rw->lqi); | ||
90 | kfree(rw); | ||
91 | } | ||
92 | |||
93 | void | ||
94 | ieee802154_rx_irqsafe(struct ieee802154_dev *dev, struct sk_buff *skb, u8 lqi) | ||
95 | { | ||
96 | struct mac802154_priv *priv = mac802154_to_priv(dev); | ||
97 | struct rx_work *work; | ||
98 | |||
99 | if (!skb) | ||
100 | return; | ||
101 | |||
102 | work = kzalloc(sizeof(struct rx_work), GFP_ATOMIC); | ||
103 | if (!work) | ||
104 | return; | ||
105 | |||
106 | INIT_WORK(&work->work, mac802154_rx_worker); | ||
107 | work->skb = skb; | ||
108 | work->dev = dev; | ||
109 | work->lqi = lqi; | ||
110 | |||
111 | queue_work(priv->dev_workqueue, &work->work); | ||
112 | } | ||
113 | EXPORT_SYMBOL(ieee802154_rx_irqsafe); | ||