11802d0beSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
21cd829c8Salex.bluesman.smirnov@gmail.com /*
31cd829c8Salex.bluesman.smirnov@gmail.com * Copyright (C) 2007-2012 Siemens AG
41cd829c8Salex.bluesman.smirnov@gmail.com *
51cd829c8Salex.bluesman.smirnov@gmail.com * Written by:
61cd829c8Salex.bluesman.smirnov@gmail.com * Pavel Smolenskiy <pavel.smolenskiy@gmail.com>
71cd829c8Salex.bluesman.smirnov@gmail.com * Maxim Gorbachyov <maxim.gorbachev@siemens.com>
81cd829c8Salex.bluesman.smirnov@gmail.com * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
91cd829c8Salex.bluesman.smirnov@gmail.com * Alexander Smirnov <alex.bluesman.smirnov@gmail.com>
101cd829c8Salex.bluesman.smirnov@gmail.com */
111cd829c8Salex.bluesman.smirnov@gmail.com
121cd829c8Salex.bluesman.smirnov@gmail.com #include <linux/kernel.h>
131cd829c8Salex.bluesman.smirnov@gmail.com #include <linux/module.h>
141cd829c8Salex.bluesman.smirnov@gmail.com #include <linux/netdevice.h>
151cd829c8Salex.bluesman.smirnov@gmail.com #include <linux/crc-ccitt.h>
16b7889497SAlexander Aring #include <asm/unaligned.h>
171cd829c8Salex.bluesman.smirnov@gmail.com
181cd829c8Salex.bluesman.smirnov@gmail.com #include <net/mac802154.h>
191cd829c8Salex.bluesman.smirnov@gmail.com #include <net/ieee802154_netdev.h>
20944742a3SAlexander Aring #include <net/nl802154.h>
211cd829c8Salex.bluesman.smirnov@gmail.com
220f1556bcSAlexander Aring #include "ieee802154_i.h"
231cd829c8Salex.bluesman.smirnov@gmail.com
ieee802154_deliver_skb(struct sk_buff * skb)2408c511a7SAlexander Aring static int ieee802154_deliver_skb(struct sk_buff *skb)
252a9820c9SAlexander Aring {
2675a46f0eSAlexander Aring skb->ip_summed = CHECKSUM_UNNECESSARY;
27702dcf99SAlexander Aring skb->protocol = htons(ETH_P_IEEE802154);
28702dcf99SAlexander Aring
292a9820c9SAlexander Aring return netif_receive_skb(skb);
302a9820c9SAlexander Aring }
312a9820c9SAlexander Aring
mac802154_rx_beacon_worker(struct work_struct * work)3257588c71SMiquel Raynal void mac802154_rx_beacon_worker(struct work_struct *work)
3357588c71SMiquel Raynal {
3457588c71SMiquel Raynal struct ieee802154_local *local =
3557588c71SMiquel Raynal container_of(work, struct ieee802154_local, rx_beacon_work);
3657588c71SMiquel Raynal struct cfg802154_mac_pkt *mac_pkt;
3757588c71SMiquel Raynal
3857588c71SMiquel Raynal mac_pkt = list_first_entry_or_null(&local->rx_beacon_list,
3957588c71SMiquel Raynal struct cfg802154_mac_pkt, node);
4057588c71SMiquel Raynal if (!mac_pkt)
4157588c71SMiquel Raynal return;
4257588c71SMiquel Raynal
4357588c71SMiquel Raynal mac802154_process_beacon(local, mac_pkt->skb, mac_pkt->page, mac_pkt->channel);
4457588c71SMiquel Raynal
4557588c71SMiquel Raynal list_del(&mac_pkt->node);
4657588c71SMiquel Raynal kfree_skb(mac_pkt->skb);
4757588c71SMiquel Raynal kfree(mac_pkt);
4857588c71SMiquel Raynal }
4957588c71SMiquel Raynal
mac802154_should_answer_beacon_req(struct ieee802154_local * local)50*d021d218SMiquel Raynal static bool mac802154_should_answer_beacon_req(struct ieee802154_local *local)
51*d021d218SMiquel Raynal {
52*d021d218SMiquel Raynal struct cfg802154_beacon_request *beacon_req;
53*d021d218SMiquel Raynal unsigned int interval;
54*d021d218SMiquel Raynal
55*d021d218SMiquel Raynal rcu_read_lock();
56*d021d218SMiquel Raynal beacon_req = rcu_dereference(local->beacon_req);
57*d021d218SMiquel Raynal if (!beacon_req) {
58*d021d218SMiquel Raynal rcu_read_unlock();
59*d021d218SMiquel Raynal return false;
60*d021d218SMiquel Raynal }
61*d021d218SMiquel Raynal
62*d021d218SMiquel Raynal interval = beacon_req->interval;
63*d021d218SMiquel Raynal rcu_read_unlock();
64*d021d218SMiquel Raynal
65*d021d218SMiquel Raynal if (!mac802154_is_beaconing(local))
66*d021d218SMiquel Raynal return false;
67*d021d218SMiquel Raynal
68*d021d218SMiquel Raynal return interval == IEEE802154_ACTIVE_SCAN_DURATION;
69*d021d218SMiquel Raynal }
70*d021d218SMiquel Raynal
mac802154_rx_mac_cmd_worker(struct work_struct * work)71*d021d218SMiquel Raynal void mac802154_rx_mac_cmd_worker(struct work_struct *work)
72*d021d218SMiquel Raynal {
73*d021d218SMiquel Raynal struct ieee802154_local *local =
74*d021d218SMiquel Raynal container_of(work, struct ieee802154_local, rx_mac_cmd_work);
75*d021d218SMiquel Raynal struct cfg802154_mac_pkt *mac_pkt;
76*d021d218SMiquel Raynal u8 mac_cmd;
77*d021d218SMiquel Raynal int rc;
78*d021d218SMiquel Raynal
79*d021d218SMiquel Raynal mac_pkt = list_first_entry_or_null(&local->rx_mac_cmd_list,
80*d021d218SMiquel Raynal struct cfg802154_mac_pkt, node);
81*d021d218SMiquel Raynal if (!mac_pkt)
82*d021d218SMiquel Raynal return;
83*d021d218SMiquel Raynal
84*d021d218SMiquel Raynal rc = ieee802154_get_mac_cmd(mac_pkt->skb, &mac_cmd);
85*d021d218SMiquel Raynal if (rc)
86*d021d218SMiquel Raynal goto out;
87*d021d218SMiquel Raynal
88*d021d218SMiquel Raynal switch (mac_cmd) {
89*d021d218SMiquel Raynal case IEEE802154_CMD_BEACON_REQ:
90*d021d218SMiquel Raynal dev_dbg(&mac_pkt->sdata->dev->dev, "processing BEACON REQ\n");
91*d021d218SMiquel Raynal if (!mac802154_should_answer_beacon_req(local))
92*d021d218SMiquel Raynal break;
93*d021d218SMiquel Raynal
94*d021d218SMiquel Raynal queue_delayed_work(local->mac_wq, &local->beacon_work, 0);
95*d021d218SMiquel Raynal break;
96*d021d218SMiquel Raynal default:
97*d021d218SMiquel Raynal break;
98*d021d218SMiquel Raynal }
99*d021d218SMiquel Raynal
100*d021d218SMiquel Raynal out:
101*d021d218SMiquel Raynal list_del(&mac_pkt->node);
102*d021d218SMiquel Raynal kfree_skb(mac_pkt->skb);
103*d021d218SMiquel Raynal kfree(mac_pkt);
104*d021d218SMiquel Raynal }
105*d021d218SMiquel Raynal
1062a9820c9SAlexander Aring static int
ieee802154_subif_frame(struct ieee802154_sub_if_data * sdata,struct sk_buff * skb,const struct ieee802154_hdr * hdr)107be9d215fSAlexander Aring ieee802154_subif_frame(struct ieee802154_sub_if_data *sdata,
108be9d215fSAlexander Aring struct sk_buff *skb, const struct ieee802154_hdr *hdr)
1092a9820c9SAlexander Aring {
1104161634bSMiquel Raynal struct wpan_phy *wpan_phy = sdata->local->hw.phy;
11157588c71SMiquel Raynal struct wpan_dev *wpan_dev = &sdata->wpan_dev;
11257588c71SMiquel Raynal struct cfg802154_mac_pkt *mac_pkt;
1132a9820c9SAlexander Aring __le16 span, sshort;
1142a9820c9SAlexander Aring int rc;
1152a9820c9SAlexander Aring
1162a9820c9SAlexander Aring pr_debug("getting packet via slave interface %s\n", sdata->dev->name);
1172a9820c9SAlexander Aring
118863e88f2SAlexander Aring span = wpan_dev->pan_id;
119863e88f2SAlexander Aring sshort = wpan_dev->short_addr;
1202a9820c9SAlexander Aring
1214161634bSMiquel Raynal /* Level 3 filtering: Only beacons are accepted during scans */
1224161634bSMiquel Raynal if (sdata->required_filtering == IEEE802154_FILTERING_3_SCAN &&
1234161634bSMiquel Raynal sdata->required_filtering > wpan_phy->filtering) {
1244161634bSMiquel Raynal if (mac_cb(skb)->type != IEEE802154_FC_TYPE_BEACON) {
1254161634bSMiquel Raynal dev_dbg(&sdata->dev->dev,
1264161634bSMiquel Raynal "drop non-beacon frame (0x%x) during scan\n",
1274161634bSMiquel Raynal mac_cb(skb)->type);
1284161634bSMiquel Raynal goto fail;
1294161634bSMiquel Raynal }
1304161634bSMiquel Raynal }
1314161634bSMiquel Raynal
1322a9820c9SAlexander Aring switch (mac_cb(skb)->dest.mode) {
1332a9820c9SAlexander Aring case IEEE802154_ADDR_NONE:
134f0da4711SMiquel Raynal if (hdr->source.mode != IEEE802154_ADDR_NONE)
1352a9820c9SAlexander Aring /* FIXME: check if we are PAN coordinator */
1362a9820c9SAlexander Aring skb->pkt_type = PACKET_OTHERHOST;
1372a9820c9SAlexander Aring else
1382a9820c9SAlexander Aring /* ACK comes with both addresses empty */
1392a9820c9SAlexander Aring skb->pkt_type = PACKET_HOST;
1402a9820c9SAlexander Aring break;
1412a9820c9SAlexander Aring case IEEE802154_ADDR_LONG:
1422a9820c9SAlexander Aring if (mac_cb(skb)->dest.pan_id != span &&
1432a9820c9SAlexander Aring mac_cb(skb)->dest.pan_id != cpu_to_le16(IEEE802154_PANID_BROADCAST))
1442a9820c9SAlexander Aring skb->pkt_type = PACKET_OTHERHOST;
145863e88f2SAlexander Aring else if (mac_cb(skb)->dest.extended_addr == wpan_dev->extended_addr)
1462a9820c9SAlexander Aring skb->pkt_type = PACKET_HOST;
1472a9820c9SAlexander Aring else
1482a9820c9SAlexander Aring skb->pkt_type = PACKET_OTHERHOST;
1492a9820c9SAlexander Aring break;
1502a9820c9SAlexander Aring case IEEE802154_ADDR_SHORT:
1512a9820c9SAlexander Aring if (mac_cb(skb)->dest.pan_id != span &&
1522a9820c9SAlexander Aring mac_cb(skb)->dest.pan_id != cpu_to_le16(IEEE802154_PANID_BROADCAST))
1532a9820c9SAlexander Aring skb->pkt_type = PACKET_OTHERHOST;
1542a9820c9SAlexander Aring else if (mac_cb(skb)->dest.short_addr == sshort)
1552a9820c9SAlexander Aring skb->pkt_type = PACKET_HOST;
1562a9820c9SAlexander Aring else if (mac_cb(skb)->dest.short_addr ==
1572a9820c9SAlexander Aring cpu_to_le16(IEEE802154_ADDR_BROADCAST))
1582a9820c9SAlexander Aring skb->pkt_type = PACKET_BROADCAST;
1592a9820c9SAlexander Aring else
1602a9820c9SAlexander Aring skb->pkt_type = PACKET_OTHERHOST;
1612a9820c9SAlexander Aring break;
1622a9820c9SAlexander Aring default:
1632a9820c9SAlexander Aring pr_debug("invalid dest mode\n");
164bcb47aabSVarka Bhadram goto fail;
1652a9820c9SAlexander Aring }
1662a9820c9SAlexander Aring
1672a9820c9SAlexander Aring skb->dev = sdata->dev;
1682a9820c9SAlexander Aring
169d58a2fa9SAlexander Aring /* TODO this should be moved after netif_receive_skb call, otherwise
170d58a2fa9SAlexander Aring * wireshark will show a mac header with security fields and the
171d58a2fa9SAlexander Aring * payload is already decrypted.
172d58a2fa9SAlexander Aring */
1732a9820c9SAlexander Aring rc = mac802154_llsec_decrypt(&sdata->sec, skb);
1742a9820c9SAlexander Aring if (rc) {
1752a9820c9SAlexander Aring pr_debug("decryption failed: %i\n", rc);
1762a9820c9SAlexander Aring goto fail;
1772a9820c9SAlexander Aring }
1782a9820c9SAlexander Aring
1792a9820c9SAlexander Aring sdata->dev->stats.rx_packets++;
1802a9820c9SAlexander Aring sdata->dev->stats.rx_bytes += skb->len;
1812a9820c9SAlexander Aring
1822a9820c9SAlexander Aring switch (mac_cb(skb)->type) {
183ca1de81aSAristeu Rozanski case IEEE802154_FC_TYPE_BEACON:
18457588c71SMiquel Raynal dev_dbg(&sdata->dev->dev, "BEACON received\n");
18557588c71SMiquel Raynal if (!mac802154_is_scanning(sdata->local))
18657588c71SMiquel Raynal goto fail;
18757588c71SMiquel Raynal
18857588c71SMiquel Raynal mac_pkt = kzalloc(sizeof(*mac_pkt), GFP_ATOMIC);
18957588c71SMiquel Raynal if (!mac_pkt)
19057588c71SMiquel Raynal goto fail;
19157588c71SMiquel Raynal
19257588c71SMiquel Raynal mac_pkt->skb = skb_get(skb);
19357588c71SMiquel Raynal mac_pkt->sdata = sdata;
19457588c71SMiquel Raynal mac_pkt->page = sdata->local->scan_page;
19557588c71SMiquel Raynal mac_pkt->channel = sdata->local->scan_channel;
19657588c71SMiquel Raynal list_add_tail(&mac_pkt->node, &sdata->local->rx_beacon_list);
19757588c71SMiquel Raynal queue_work(sdata->local->mac_wq, &sdata->local->rx_beacon_work);
19857588c71SMiquel Raynal return NET_RX_SUCCESS;
199*d021d218SMiquel Raynal
200ca1de81aSAristeu Rozanski case IEEE802154_FC_TYPE_MAC_CMD:
201*d021d218SMiquel Raynal dev_dbg(&sdata->dev->dev, "MAC COMMAND received\n");
202*d021d218SMiquel Raynal mac_pkt = kzalloc(sizeof(*mac_pkt), GFP_ATOMIC);
203*d021d218SMiquel Raynal if (!mac_pkt)
204*d021d218SMiquel Raynal goto fail;
205*d021d218SMiquel Raynal
206*d021d218SMiquel Raynal mac_pkt->skb = skb_get(skb);
207*d021d218SMiquel Raynal mac_pkt->sdata = sdata;
208*d021d218SMiquel Raynal list_add_tail(&mac_pkt->node, &sdata->local->rx_mac_cmd_list);
209*d021d218SMiquel Raynal queue_work(sdata->local->mac_wq, &sdata->local->rx_mac_cmd_work);
210*d021d218SMiquel Raynal return NET_RX_SUCCESS;
211*d021d218SMiquel Raynal
212*d021d218SMiquel Raynal case IEEE802154_FC_TYPE_ACK:
213ca1de81aSAristeu Rozanski goto fail;
214ca1de81aSAristeu Rozanski
2152a9820c9SAlexander Aring case IEEE802154_FC_TYPE_DATA:
21608c511a7SAlexander Aring return ieee802154_deliver_skb(skb);
2172a9820c9SAlexander Aring default:
218bd89bb6dSAristeu Rozanski pr_warn_ratelimited("ieee802154: bad frame received "
219bd89bb6dSAristeu Rozanski "(type = %d)\n", mac_cb(skb)->type);
2202a9820c9SAlexander Aring goto fail;
2212a9820c9SAlexander Aring }
2222a9820c9SAlexander Aring
2232a9820c9SAlexander Aring fail:
2242a9820c9SAlexander Aring kfree_skb(skb);
2252a9820c9SAlexander Aring return NET_RX_DROP;
2262a9820c9SAlexander Aring }
2272a9820c9SAlexander Aring
228be9d215fSAlexander Aring static void
ieee802154_print_addr(const char * name,const struct ieee802154_addr * addr)229be9d215fSAlexander Aring ieee802154_print_addr(const char *name, const struct ieee802154_addr *addr)
2302a9820c9SAlexander Aring {
2313a22550aSMiquel Raynal if (addr->mode == IEEE802154_ADDR_NONE) {
2322a9820c9SAlexander Aring pr_debug("%s not present\n", name);
2333a22550aSMiquel Raynal return;
2343a22550aSMiquel Raynal }
2352a9820c9SAlexander Aring
2362a9820c9SAlexander Aring pr_debug("%s PAN ID: %04x\n", name, le16_to_cpu(addr->pan_id));
2372a9820c9SAlexander Aring if (addr->mode == IEEE802154_ADDR_SHORT) {
2382a9820c9SAlexander Aring pr_debug("%s is short: %04x\n", name,
2392a9820c9SAlexander Aring le16_to_cpu(addr->short_addr));
2402a9820c9SAlexander Aring } else {
2412a9820c9SAlexander Aring u64 hw = swab64((__force u64)addr->extended_addr);
2422a9820c9SAlexander Aring
2432a9820c9SAlexander Aring pr_debug("%s is hardware: %8phC\n", name, &hw);
2442a9820c9SAlexander Aring }
2452a9820c9SAlexander Aring }
2462a9820c9SAlexander Aring
247be9d215fSAlexander Aring static int
ieee802154_parse_frame_start(struct sk_buff * skb,struct ieee802154_hdr * hdr)248be9d215fSAlexander Aring ieee802154_parse_frame_start(struct sk_buff *skb, struct ieee802154_hdr *hdr)
2492a9820c9SAlexander Aring {
2502a9820c9SAlexander Aring int hlen;
2515a5c4e06SMiquel Raynal struct ieee802154_mac_cb *cb = mac_cb(skb);
2522a9820c9SAlexander Aring
2539cf215d0SAlexander Aring skb_reset_mac_header(skb);
2549cf215d0SAlexander Aring
2552a9820c9SAlexander Aring hlen = ieee802154_hdr_pull(skb, hdr);
2562a9820c9SAlexander Aring if (hlen < 0)
2572a9820c9SAlexander Aring return -EINVAL;
2582a9820c9SAlexander Aring
2592a9820c9SAlexander Aring skb->mac_len = hlen;
2602a9820c9SAlexander Aring
2612a9820c9SAlexander Aring pr_debug("fc: %04x dsn: %02x\n", le16_to_cpup((__le16 *)&hdr->fc),
2622a9820c9SAlexander Aring hdr->seq);
2632a9820c9SAlexander Aring
2642a9820c9SAlexander Aring cb->type = hdr->fc.type;
2652a9820c9SAlexander Aring cb->ackreq = hdr->fc.ack_request;
2662a9820c9SAlexander Aring cb->secen = hdr->fc.security_enabled;
2672a9820c9SAlexander Aring
268be9d215fSAlexander Aring ieee802154_print_addr("destination", &hdr->dest);
269be9d215fSAlexander Aring ieee802154_print_addr("source", &hdr->source);
2702a9820c9SAlexander Aring
2712a9820c9SAlexander Aring cb->source = hdr->source;
2722a9820c9SAlexander Aring cb->dest = hdr->dest;
2732a9820c9SAlexander Aring
2742a9820c9SAlexander Aring if (hdr->fc.security_enabled) {
2752a9820c9SAlexander Aring u64 key;
2762a9820c9SAlexander Aring
2772a9820c9SAlexander Aring pr_debug("seclevel %i\n", hdr->sec.level);
2782a9820c9SAlexander Aring
2792a9820c9SAlexander Aring switch (hdr->sec.key_id_mode) {
2802a9820c9SAlexander Aring case IEEE802154_SCF_KEY_IMPLICIT:
2812a9820c9SAlexander Aring pr_debug("implicit key\n");
2822a9820c9SAlexander Aring break;
2832a9820c9SAlexander Aring
2842a9820c9SAlexander Aring case IEEE802154_SCF_KEY_INDEX:
2852a9820c9SAlexander Aring pr_debug("key %02x\n", hdr->sec.key_id);
2862a9820c9SAlexander Aring break;
2872a9820c9SAlexander Aring
2882a9820c9SAlexander Aring case IEEE802154_SCF_KEY_SHORT_INDEX:
2892a9820c9SAlexander Aring pr_debug("key %04x:%04x %02x\n",
2902a9820c9SAlexander Aring le32_to_cpu(hdr->sec.short_src) >> 16,
2912a9820c9SAlexander Aring le32_to_cpu(hdr->sec.short_src) & 0xffff,
2922a9820c9SAlexander Aring hdr->sec.key_id);
2932a9820c9SAlexander Aring break;
2942a9820c9SAlexander Aring
2952a9820c9SAlexander Aring case IEEE802154_SCF_KEY_HW_INDEX:
2962a9820c9SAlexander Aring key = swab64((__force u64)hdr->sec.extended_src);
2972a9820c9SAlexander Aring pr_debug("key source %8phC %02x\n", &key,
2982a9820c9SAlexander Aring hdr->sec.key_id);
2992a9820c9SAlexander Aring break;
3002a9820c9SAlexander Aring }
3012a9820c9SAlexander Aring }
3022a9820c9SAlexander Aring
3032a9820c9SAlexander Aring return 0;
3042a9820c9SAlexander Aring }
3052a9820c9SAlexander Aring
3062a9820c9SAlexander Aring static void
__ieee802154_rx_handle_packet(struct ieee802154_local * local,struct sk_buff * skb)307be9d215fSAlexander Aring __ieee802154_rx_handle_packet(struct ieee802154_local *local,
308be9d215fSAlexander Aring struct sk_buff *skb)
3092a9820c9SAlexander Aring {
3102a9820c9SAlexander Aring int ret;
3112a9820c9SAlexander Aring struct ieee802154_sub_if_data *sdata;
3122a9820c9SAlexander Aring struct ieee802154_hdr hdr;
3132622e785SMiquel Raynal struct sk_buff *skb2;
3142a9820c9SAlexander Aring
315be9d215fSAlexander Aring ret = ieee802154_parse_frame_start(skb, &hdr);
3162a9820c9SAlexander Aring if (ret) {
3172a9820c9SAlexander Aring pr_debug("got invalid frame\n");
3182a9820c9SAlexander Aring return;
3192a9820c9SAlexander Aring }
3202a9820c9SAlexander Aring
3212a9820c9SAlexander Aring list_for_each_entry_rcu(sdata, &local->interfaces, list) {
3222622e785SMiquel Raynal if (sdata->wpan_dev.iftype == NL802154_IFTYPE_MONITOR)
3231bc1754eSVarka Bhadram continue;
3241bc1754eSVarka Bhadram
3251bc1754eSVarka Bhadram if (!ieee802154_sdata_running(sdata))
3262a9820c9SAlexander Aring continue;
3272a9820c9SAlexander Aring
3280218277dSMiquel Raynal /* Do not deliver packets received on interfaces expecting
3290218277dSMiquel Raynal * AACK=1 if the address filters where disabled.
3300218277dSMiquel Raynal */
3310218277dSMiquel Raynal if (local->hw.phy->filtering < IEEE802154_FILTERING_4_FRAME_FIELDS &&
3320218277dSMiquel Raynal sdata->required_filtering == IEEE802154_FILTERING_4_FRAME_FIELDS)
3330218277dSMiquel Raynal continue;
3340218277dSMiquel Raynal
3352622e785SMiquel Raynal skb2 = skb_clone(skb, GFP_ATOMIC);
3362622e785SMiquel Raynal if (skb2) {
3372622e785SMiquel Raynal skb2->dev = sdata->dev;
3382622e785SMiquel Raynal ieee802154_subif_frame(sdata, skb2, &hdr);
3392a9820c9SAlexander Aring }
3402a9820c9SAlexander Aring }
3412a9820c9SAlexander Aring }
3422a9820c9SAlexander Aring
3434ca18be5SAlexander Aring static void
ieee802154_monitors_rx(struct ieee802154_local * local,struct sk_buff * skb)344be9d215fSAlexander Aring ieee802154_monitors_rx(struct ieee802154_local *local, struct sk_buff *skb)
3452a9820c9SAlexander Aring {
3462a9820c9SAlexander Aring struct sk_buff *skb2;
3472a9820c9SAlexander Aring struct ieee802154_sub_if_data *sdata;
3482a9820c9SAlexander Aring
3499cf215d0SAlexander Aring skb_reset_mac_header(skb);
35075a46f0eSAlexander Aring skb->ip_summed = CHECKSUM_UNNECESSARY;
351c9ca6401SAlexander Aring skb->pkt_type = PACKET_OTHERHOST;
352702dcf99SAlexander Aring skb->protocol = htons(ETH_P_IEEE802154);
353702dcf99SAlexander Aring
3542a9820c9SAlexander Aring list_for_each_entry_rcu(sdata, &local->interfaces, list) {
355ed65963bSAlexander Aring if (sdata->wpan_dev.iftype != NL802154_IFTYPE_MONITOR)
35620b48120SAlexander Aring continue;
35720b48120SAlexander Aring
35820b48120SAlexander Aring if (!ieee802154_sdata_running(sdata))
3592a9820c9SAlexander Aring continue;
3602a9820c9SAlexander Aring
3612a9820c9SAlexander Aring skb2 = skb_clone(skb, GFP_ATOMIC);
36205f7de67SAlexander Aring if (skb2) {
3632a9820c9SAlexander Aring skb2->dev = sdata->dev;
36421fdf0a1SAlexander Aring ieee802154_deliver_skb(skb2);
36518460672SAlexander Aring
36618460672SAlexander Aring sdata->dev->stats.rx_packets++;
36718460672SAlexander Aring sdata->dev->stats.rx_bytes += skb->len;
3682a9820c9SAlexander Aring }
3692a9820c9SAlexander Aring }
37005f7de67SAlexander Aring }
3712a9820c9SAlexander Aring
ieee802154_rx(struct ieee802154_local * local,struct sk_buff * skb)372d10270ceSVarka Bhadram void ieee802154_rx(struct ieee802154_local *local, struct sk_buff *skb)
3731cd829c8Salex.bluesman.smirnov@gmail.com {
374ec718f3dSAlexander Aring u16 crc;
3751cd829c8Salex.bluesman.smirnov@gmail.com
376469100d6SAlexander Aring WARN_ON_ONCE(softirq_count() == 0);
377469100d6SAlexander Aring
3783cf24cf8SAlexander Aring if (local->suspended)
3794d1c7d87SMiquel Raynal goto free_skb;
3803cf24cf8SAlexander Aring
381b7889497SAlexander Aring /* TODO: When a transceiver omits the checksum here, we
382b7889497SAlexander Aring * add an own calculated one. This is currently an ugly
383b7889497SAlexander Aring * solution because the monitor needs a crc here.
384b7889497SAlexander Aring */
385b7889497SAlexander Aring if (local->hw.flags & IEEE802154_HW_RX_OMIT_CKSUM) {
386ec718f3dSAlexander Aring crc = crc_ccitt(0, skb->data, skb->len);
387b7889497SAlexander Aring put_unaligned_le16(crc, skb_put(skb, 2));
3881cd829c8Salex.bluesman.smirnov@gmail.com }
3891cd829c8Salex.bluesman.smirnov@gmail.com
390e176b681SAlexander Aring rcu_read_lock();
391e176b681SAlexander Aring
392be9d215fSAlexander Aring ieee802154_monitors_rx(local, skb);
393b7889497SAlexander Aring
394a4b5b4c5SMiquel Raynal /* Level 1 filtering: Check the FCS by software when relevant */
395a4b5b4c5SMiquel Raynal if (local->hw.phy->filtering == IEEE802154_FILTERING_NONE) {
396ec718f3dSAlexander Aring crc = crc_ccitt(0, skb->data, skb->len);
3974d1c7d87SMiquel Raynal if (crc)
3983cf24cf8SAlexander Aring goto drop;
399ec718f3dSAlexander Aring }
400b7889497SAlexander Aring /* remove crc */
401b7889497SAlexander Aring skb_trim(skb, skb->len - 2);
402b7889497SAlexander Aring
403be9d215fSAlexander Aring __ieee802154_rx_handle_packet(local, skb);
4042d3b5b0aSPhoebe Buckheister
4053cf24cf8SAlexander Aring drop:
4064d1c7d87SMiquel Raynal rcu_read_unlock();
4074d1c7d87SMiquel Raynal free_skb:
4083cf24cf8SAlexander Aring kfree_skb(skb);
4091cd829c8Salex.bluesman.smirnov@gmail.com }
4101cd829c8Salex.bluesman.smirnov@gmail.com
4111cd829c8Salex.bluesman.smirnov@gmail.com void
ieee802154_rx_irqsafe(struct ieee802154_hw * hw,struct sk_buff * skb,u8 lqi)4125a504397SAlexander Aring ieee802154_rx_irqsafe(struct ieee802154_hw *hw, struct sk_buff *skb, u8 lqi)
4131cd829c8Salex.bluesman.smirnov@gmail.com {
41460741361SAlexander Aring struct ieee802154_local *local = hw_to_local(hw);
4155a5c4e06SMiquel Raynal struct ieee802154_mac_cb *cb = mac_cb_init(skb);
4161cd829c8Salex.bluesman.smirnov@gmail.com
4175a5c4e06SMiquel Raynal cb->lqi = lqi;
418c5c47e67SAlexander Aring skb->pkt_type = IEEE802154_RX_MSG;
419c5c47e67SAlexander Aring skb_queue_tail(&local->skb_queue, skb);
420c5c47e67SAlexander Aring tasklet_schedule(&local->tasklet);
4211cd829c8Salex.bluesman.smirnov@gmail.com }
4221cd829c8Salex.bluesman.smirnov@gmail.com EXPORT_SYMBOL(ieee802154_rx_irqsafe);
423