#include <linux/module.h>
 #include <linux/netdevice.h>
 #include <linux/crc-ccitt.h>
+#include <asm/unaligned.h>
 
 #include <net/mac802154.h>
 #include <net/ieee802154_netdev.h>
 {
        struct sk_buff *skb2;
        struct ieee802154_sub_if_data *sdata;
-       u16 crc = crc_ccitt(0, skb->data, skb->len);
-       u8 *data;
 
        skb_reset_mac_header(skb);
        skb->ip_summed = CHECKSUM_UNNECESSARY;
                skb2 = skb_clone(skb, GFP_ATOMIC);
                skb2->dev = sdata->dev;
                skb2->pkt_type = PACKET_HOST;
-               data = skb_put(skb2, 2);
-               data[0] = crc & 0xff;
-               data[1] = crc >> 8;
 
                netif_rx_ni(skb2);
        }
 
        WARN_ON_ONCE(softirq_count() == 0);
 
-       if (!(local->hw.flags & IEEE802154_HW_RX_OMIT_CKSUM)) {
-               u16 crc;
+       /* TODO: When a transceiver omits the checksum here, we
+        * add an own calculated one. This is currently an ugly
+        * solution because the monitor needs a crc here.
+        */
+       if (local->hw.flags & IEEE802154_HW_RX_OMIT_CKSUM) {
+               u16 crc = crc_ccitt(0, skb->data, skb->len);
 
-               if (skb->len < 2) {
-                       pr_debug("got invalid frame\n");
-                       goto fail;
-               }
-               crc = crc_ccitt(0, skb->data, skb->len);
-               if (crc) {
-                       pr_debug("CRC mismatch\n");
-                       goto fail;
-               }
-               skb_trim(skb, skb->len - 2); /* CRC */
+               put_unaligned_le16(crc, skb_put(skb, 2));
        }
 
        rcu_read_lock();
 
        ieee802154_monitors_rx(local, skb);
-       __ieee802154_rx_handle_packet(local, skb);
 
-       rcu_read_unlock();
+       /* remove crc */
+       skb_trim(skb, skb->len - 2);
 
-       return;
+       __ieee802154_rx_handle_packet(local, skb);
 
-fail:
-       kfree_skb(skb);
+       rcu_read_unlock();
 }
 EXPORT_SYMBOL(ieee802154_rx);