162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2007-2012 Siemens AG
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Written by:
662306a36Sopenharmony_ci * Pavel Smolenskiy <pavel.smolenskiy@gmail.com>
762306a36Sopenharmony_ci * Maxim Gorbachyov <maxim.gorbachev@siemens.com>
862306a36Sopenharmony_ci * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
962306a36Sopenharmony_ci * Alexander Smirnov <alex.bluesman.smirnov@gmail.com>
1062306a36Sopenharmony_ci */
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include <linux/kernel.h>
1362306a36Sopenharmony_ci#include <linux/module.h>
1462306a36Sopenharmony_ci#include <linux/netdevice.h>
1562306a36Sopenharmony_ci#include <linux/crc-ccitt.h>
1662306a36Sopenharmony_ci#include <asm/unaligned.h>
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#include <net/mac802154.h>
1962306a36Sopenharmony_ci#include <net/ieee802154_netdev.h>
2062306a36Sopenharmony_ci#include <net/nl802154.h>
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci#include "ieee802154_i.h"
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_cistatic int ieee802154_deliver_skb(struct sk_buff *skb)
2562306a36Sopenharmony_ci{
2662306a36Sopenharmony_ci	skb->ip_summed = CHECKSUM_UNNECESSARY;
2762306a36Sopenharmony_ci	skb->protocol = htons(ETH_P_IEEE802154);
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci	return netif_receive_skb(skb);
3062306a36Sopenharmony_ci}
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_civoid mac802154_rx_beacon_worker(struct work_struct *work)
3362306a36Sopenharmony_ci{
3462306a36Sopenharmony_ci	struct ieee802154_local *local =
3562306a36Sopenharmony_ci		container_of(work, struct ieee802154_local, rx_beacon_work);
3662306a36Sopenharmony_ci	struct cfg802154_mac_pkt *mac_pkt;
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci	mac_pkt = list_first_entry_or_null(&local->rx_beacon_list,
3962306a36Sopenharmony_ci					   struct cfg802154_mac_pkt, node);
4062306a36Sopenharmony_ci	if (!mac_pkt)
4162306a36Sopenharmony_ci		return;
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci	mac802154_process_beacon(local, mac_pkt->skb, mac_pkt->page, mac_pkt->channel);
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci	list_del(&mac_pkt->node);
4662306a36Sopenharmony_ci	kfree_skb(mac_pkt->skb);
4762306a36Sopenharmony_ci	kfree(mac_pkt);
4862306a36Sopenharmony_ci}
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_cistatic bool mac802154_should_answer_beacon_req(struct ieee802154_local *local)
5162306a36Sopenharmony_ci{
5262306a36Sopenharmony_ci	struct cfg802154_beacon_request *beacon_req;
5362306a36Sopenharmony_ci	unsigned int interval;
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci	rcu_read_lock();
5662306a36Sopenharmony_ci	beacon_req = rcu_dereference(local->beacon_req);
5762306a36Sopenharmony_ci	if (!beacon_req) {
5862306a36Sopenharmony_ci		rcu_read_unlock();
5962306a36Sopenharmony_ci		return false;
6062306a36Sopenharmony_ci	}
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci	interval = beacon_req->interval;
6362306a36Sopenharmony_ci	rcu_read_unlock();
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci	if (!mac802154_is_beaconing(local))
6662306a36Sopenharmony_ci		return false;
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci	return interval == IEEE802154_ACTIVE_SCAN_DURATION;
6962306a36Sopenharmony_ci}
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_civoid mac802154_rx_mac_cmd_worker(struct work_struct *work)
7262306a36Sopenharmony_ci{
7362306a36Sopenharmony_ci	struct ieee802154_local *local =
7462306a36Sopenharmony_ci		container_of(work, struct ieee802154_local, rx_mac_cmd_work);
7562306a36Sopenharmony_ci	struct cfg802154_mac_pkt *mac_pkt;
7662306a36Sopenharmony_ci	u8 mac_cmd;
7762306a36Sopenharmony_ci	int rc;
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	mac_pkt = list_first_entry_or_null(&local->rx_mac_cmd_list,
8062306a36Sopenharmony_ci					   struct cfg802154_mac_pkt, node);
8162306a36Sopenharmony_ci	if (!mac_pkt)
8262306a36Sopenharmony_ci		return;
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	rc = ieee802154_get_mac_cmd(mac_pkt->skb, &mac_cmd);
8562306a36Sopenharmony_ci	if (rc)
8662306a36Sopenharmony_ci		goto out;
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	switch (mac_cmd) {
8962306a36Sopenharmony_ci	case IEEE802154_CMD_BEACON_REQ:
9062306a36Sopenharmony_ci		dev_dbg(&mac_pkt->sdata->dev->dev, "processing BEACON REQ\n");
9162306a36Sopenharmony_ci		if (!mac802154_should_answer_beacon_req(local))
9262306a36Sopenharmony_ci			break;
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci		queue_delayed_work(local->mac_wq, &local->beacon_work, 0);
9562306a36Sopenharmony_ci		break;
9662306a36Sopenharmony_ci	default:
9762306a36Sopenharmony_ci		break;
9862306a36Sopenharmony_ci	}
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ciout:
10162306a36Sopenharmony_ci	list_del(&mac_pkt->node);
10262306a36Sopenharmony_ci	kfree_skb(mac_pkt->skb);
10362306a36Sopenharmony_ci	kfree(mac_pkt);
10462306a36Sopenharmony_ci}
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_cistatic int
10762306a36Sopenharmony_ciieee802154_subif_frame(struct ieee802154_sub_if_data *sdata,
10862306a36Sopenharmony_ci		       struct sk_buff *skb, const struct ieee802154_hdr *hdr)
10962306a36Sopenharmony_ci{
11062306a36Sopenharmony_ci	struct wpan_phy *wpan_phy = sdata->local->hw.phy;
11162306a36Sopenharmony_ci	struct wpan_dev *wpan_dev = &sdata->wpan_dev;
11262306a36Sopenharmony_ci	struct cfg802154_mac_pkt *mac_pkt;
11362306a36Sopenharmony_ci	__le16 span, sshort;
11462306a36Sopenharmony_ci	int rc;
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	pr_debug("getting packet via slave interface %s\n", sdata->dev->name);
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci	span = wpan_dev->pan_id;
11962306a36Sopenharmony_ci	sshort = wpan_dev->short_addr;
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci	/* Level 3 filtering: Only beacons are accepted during scans */
12262306a36Sopenharmony_ci	if (sdata->required_filtering == IEEE802154_FILTERING_3_SCAN &&
12362306a36Sopenharmony_ci	    sdata->required_filtering > wpan_phy->filtering) {
12462306a36Sopenharmony_ci		if (mac_cb(skb)->type != IEEE802154_FC_TYPE_BEACON) {
12562306a36Sopenharmony_ci			dev_dbg(&sdata->dev->dev,
12662306a36Sopenharmony_ci				"drop non-beacon frame (0x%x) during scan\n",
12762306a36Sopenharmony_ci				mac_cb(skb)->type);
12862306a36Sopenharmony_ci			goto fail;
12962306a36Sopenharmony_ci		}
13062306a36Sopenharmony_ci	}
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	switch (mac_cb(skb)->dest.mode) {
13362306a36Sopenharmony_ci	case IEEE802154_ADDR_NONE:
13462306a36Sopenharmony_ci		if (hdr->source.mode != IEEE802154_ADDR_NONE)
13562306a36Sopenharmony_ci			/* FIXME: check if we are PAN coordinator */
13662306a36Sopenharmony_ci			skb->pkt_type = PACKET_OTHERHOST;
13762306a36Sopenharmony_ci		else
13862306a36Sopenharmony_ci			/* ACK comes with both addresses empty */
13962306a36Sopenharmony_ci			skb->pkt_type = PACKET_HOST;
14062306a36Sopenharmony_ci		break;
14162306a36Sopenharmony_ci	case IEEE802154_ADDR_LONG:
14262306a36Sopenharmony_ci		if (mac_cb(skb)->dest.pan_id != span &&
14362306a36Sopenharmony_ci		    mac_cb(skb)->dest.pan_id != cpu_to_le16(IEEE802154_PANID_BROADCAST))
14462306a36Sopenharmony_ci			skb->pkt_type = PACKET_OTHERHOST;
14562306a36Sopenharmony_ci		else if (mac_cb(skb)->dest.extended_addr == wpan_dev->extended_addr)
14662306a36Sopenharmony_ci			skb->pkt_type = PACKET_HOST;
14762306a36Sopenharmony_ci		else
14862306a36Sopenharmony_ci			skb->pkt_type = PACKET_OTHERHOST;
14962306a36Sopenharmony_ci		break;
15062306a36Sopenharmony_ci	case IEEE802154_ADDR_SHORT:
15162306a36Sopenharmony_ci		if (mac_cb(skb)->dest.pan_id != span &&
15262306a36Sopenharmony_ci		    mac_cb(skb)->dest.pan_id != cpu_to_le16(IEEE802154_PANID_BROADCAST))
15362306a36Sopenharmony_ci			skb->pkt_type = PACKET_OTHERHOST;
15462306a36Sopenharmony_ci		else if (mac_cb(skb)->dest.short_addr == sshort)
15562306a36Sopenharmony_ci			skb->pkt_type = PACKET_HOST;
15662306a36Sopenharmony_ci		else if (mac_cb(skb)->dest.short_addr ==
15762306a36Sopenharmony_ci			  cpu_to_le16(IEEE802154_ADDR_BROADCAST))
15862306a36Sopenharmony_ci			skb->pkt_type = PACKET_BROADCAST;
15962306a36Sopenharmony_ci		else
16062306a36Sopenharmony_ci			skb->pkt_type = PACKET_OTHERHOST;
16162306a36Sopenharmony_ci		break;
16262306a36Sopenharmony_ci	default:
16362306a36Sopenharmony_ci		pr_debug("invalid dest mode\n");
16462306a36Sopenharmony_ci		goto fail;
16562306a36Sopenharmony_ci	}
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	skb->dev = sdata->dev;
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci	/* TODO this should be moved after netif_receive_skb call, otherwise
17062306a36Sopenharmony_ci	 * wireshark will show a mac header with security fields and the
17162306a36Sopenharmony_ci	 * payload is already decrypted.
17262306a36Sopenharmony_ci	 */
17362306a36Sopenharmony_ci	rc = mac802154_llsec_decrypt(&sdata->sec, skb);
17462306a36Sopenharmony_ci	if (rc) {
17562306a36Sopenharmony_ci		pr_debug("decryption failed: %i\n", rc);
17662306a36Sopenharmony_ci		goto fail;
17762306a36Sopenharmony_ci	}
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	sdata->dev->stats.rx_packets++;
18062306a36Sopenharmony_ci	sdata->dev->stats.rx_bytes += skb->len;
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci	switch (mac_cb(skb)->type) {
18362306a36Sopenharmony_ci	case IEEE802154_FC_TYPE_BEACON:
18462306a36Sopenharmony_ci		dev_dbg(&sdata->dev->dev, "BEACON received\n");
18562306a36Sopenharmony_ci		if (!mac802154_is_scanning(sdata->local))
18662306a36Sopenharmony_ci			goto fail;
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci		mac_pkt = kzalloc(sizeof(*mac_pkt), GFP_ATOMIC);
18962306a36Sopenharmony_ci		if (!mac_pkt)
19062306a36Sopenharmony_ci			goto fail;
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci		mac_pkt->skb = skb_get(skb);
19362306a36Sopenharmony_ci		mac_pkt->sdata = sdata;
19462306a36Sopenharmony_ci		mac_pkt->page = sdata->local->scan_page;
19562306a36Sopenharmony_ci		mac_pkt->channel = sdata->local->scan_channel;
19662306a36Sopenharmony_ci		list_add_tail(&mac_pkt->node, &sdata->local->rx_beacon_list);
19762306a36Sopenharmony_ci		queue_work(sdata->local->mac_wq, &sdata->local->rx_beacon_work);
19862306a36Sopenharmony_ci		return NET_RX_SUCCESS;
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci	case IEEE802154_FC_TYPE_MAC_CMD:
20162306a36Sopenharmony_ci		dev_dbg(&sdata->dev->dev, "MAC COMMAND received\n");
20262306a36Sopenharmony_ci		mac_pkt = kzalloc(sizeof(*mac_pkt), GFP_ATOMIC);
20362306a36Sopenharmony_ci		if (!mac_pkt)
20462306a36Sopenharmony_ci			goto fail;
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci		mac_pkt->skb = skb_get(skb);
20762306a36Sopenharmony_ci		mac_pkt->sdata = sdata;
20862306a36Sopenharmony_ci		list_add_tail(&mac_pkt->node, &sdata->local->rx_mac_cmd_list);
20962306a36Sopenharmony_ci		queue_work(sdata->local->mac_wq, &sdata->local->rx_mac_cmd_work);
21062306a36Sopenharmony_ci		return NET_RX_SUCCESS;
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci	case IEEE802154_FC_TYPE_ACK:
21362306a36Sopenharmony_ci		goto fail;
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci	case IEEE802154_FC_TYPE_DATA:
21662306a36Sopenharmony_ci		return ieee802154_deliver_skb(skb);
21762306a36Sopenharmony_ci	default:
21862306a36Sopenharmony_ci		pr_warn_ratelimited("ieee802154: bad frame received "
21962306a36Sopenharmony_ci				    "(type = %d)\n", mac_cb(skb)->type);
22062306a36Sopenharmony_ci		goto fail;
22162306a36Sopenharmony_ci	}
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_cifail:
22462306a36Sopenharmony_ci	kfree_skb(skb);
22562306a36Sopenharmony_ci	return NET_RX_DROP;
22662306a36Sopenharmony_ci}
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_cistatic void
22962306a36Sopenharmony_ciieee802154_print_addr(const char *name, const struct ieee802154_addr *addr)
23062306a36Sopenharmony_ci{
23162306a36Sopenharmony_ci	if (addr->mode == IEEE802154_ADDR_NONE) {
23262306a36Sopenharmony_ci		pr_debug("%s not present\n", name);
23362306a36Sopenharmony_ci		return;
23462306a36Sopenharmony_ci	}
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci	pr_debug("%s PAN ID: %04x\n", name, le16_to_cpu(addr->pan_id));
23762306a36Sopenharmony_ci	if (addr->mode == IEEE802154_ADDR_SHORT) {
23862306a36Sopenharmony_ci		pr_debug("%s is short: %04x\n", name,
23962306a36Sopenharmony_ci			 le16_to_cpu(addr->short_addr));
24062306a36Sopenharmony_ci	} else {
24162306a36Sopenharmony_ci		u64 hw = swab64((__force u64)addr->extended_addr);
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci		pr_debug("%s is hardware: %8phC\n", name, &hw);
24462306a36Sopenharmony_ci	}
24562306a36Sopenharmony_ci}
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_cistatic int
24862306a36Sopenharmony_ciieee802154_parse_frame_start(struct sk_buff *skb, struct ieee802154_hdr *hdr)
24962306a36Sopenharmony_ci{
25062306a36Sopenharmony_ci	int hlen;
25162306a36Sopenharmony_ci	struct ieee802154_mac_cb *cb = mac_cb(skb);
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	skb_reset_mac_header(skb);
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	hlen = ieee802154_hdr_pull(skb, hdr);
25662306a36Sopenharmony_ci	if (hlen < 0)
25762306a36Sopenharmony_ci		return -EINVAL;
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci	skb->mac_len = hlen;
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci	pr_debug("fc: %04x dsn: %02x\n", le16_to_cpup((__le16 *)&hdr->fc),
26262306a36Sopenharmony_ci		 hdr->seq);
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci	cb->type = hdr->fc.type;
26562306a36Sopenharmony_ci	cb->ackreq = hdr->fc.ack_request;
26662306a36Sopenharmony_ci	cb->secen = hdr->fc.security_enabled;
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	ieee802154_print_addr("destination", &hdr->dest);
26962306a36Sopenharmony_ci	ieee802154_print_addr("source", &hdr->source);
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci	cb->source = hdr->source;
27262306a36Sopenharmony_ci	cb->dest = hdr->dest;
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci	if (hdr->fc.security_enabled) {
27562306a36Sopenharmony_ci		u64 key;
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci		pr_debug("seclevel %i\n", hdr->sec.level);
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci		switch (hdr->sec.key_id_mode) {
28062306a36Sopenharmony_ci		case IEEE802154_SCF_KEY_IMPLICIT:
28162306a36Sopenharmony_ci			pr_debug("implicit key\n");
28262306a36Sopenharmony_ci			break;
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci		case IEEE802154_SCF_KEY_INDEX:
28562306a36Sopenharmony_ci			pr_debug("key %02x\n", hdr->sec.key_id);
28662306a36Sopenharmony_ci			break;
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci		case IEEE802154_SCF_KEY_SHORT_INDEX:
28962306a36Sopenharmony_ci			pr_debug("key %04x:%04x %02x\n",
29062306a36Sopenharmony_ci				 le32_to_cpu(hdr->sec.short_src) >> 16,
29162306a36Sopenharmony_ci				 le32_to_cpu(hdr->sec.short_src) & 0xffff,
29262306a36Sopenharmony_ci				 hdr->sec.key_id);
29362306a36Sopenharmony_ci			break;
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci		case IEEE802154_SCF_KEY_HW_INDEX:
29662306a36Sopenharmony_ci			key = swab64((__force u64)hdr->sec.extended_src);
29762306a36Sopenharmony_ci			pr_debug("key source %8phC %02x\n", &key,
29862306a36Sopenharmony_ci				 hdr->sec.key_id);
29962306a36Sopenharmony_ci			break;
30062306a36Sopenharmony_ci		}
30162306a36Sopenharmony_ci	}
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci	return 0;
30462306a36Sopenharmony_ci}
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_cistatic void
30762306a36Sopenharmony_ci__ieee802154_rx_handle_packet(struct ieee802154_local *local,
30862306a36Sopenharmony_ci			      struct sk_buff *skb)
30962306a36Sopenharmony_ci{
31062306a36Sopenharmony_ci	int ret;
31162306a36Sopenharmony_ci	struct ieee802154_sub_if_data *sdata;
31262306a36Sopenharmony_ci	struct ieee802154_hdr hdr;
31362306a36Sopenharmony_ci	struct sk_buff *skb2;
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	ret = ieee802154_parse_frame_start(skb, &hdr);
31662306a36Sopenharmony_ci	if (ret) {
31762306a36Sopenharmony_ci		pr_debug("got invalid frame\n");
31862306a36Sopenharmony_ci		return;
31962306a36Sopenharmony_ci	}
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	list_for_each_entry_rcu(sdata, &local->interfaces, list) {
32262306a36Sopenharmony_ci		if (sdata->wpan_dev.iftype == NL802154_IFTYPE_MONITOR)
32362306a36Sopenharmony_ci			continue;
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci		if (!ieee802154_sdata_running(sdata))
32662306a36Sopenharmony_ci			continue;
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci		/* Do not deliver packets received on interfaces expecting
32962306a36Sopenharmony_ci		 * AACK=1 if the address filters where disabled.
33062306a36Sopenharmony_ci		 */
33162306a36Sopenharmony_ci		if (local->hw.phy->filtering < IEEE802154_FILTERING_4_FRAME_FIELDS &&
33262306a36Sopenharmony_ci		    sdata->required_filtering == IEEE802154_FILTERING_4_FRAME_FIELDS)
33362306a36Sopenharmony_ci			continue;
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci		skb2 = skb_clone(skb, GFP_ATOMIC);
33662306a36Sopenharmony_ci		if (skb2) {
33762306a36Sopenharmony_ci			skb2->dev = sdata->dev;
33862306a36Sopenharmony_ci			ieee802154_subif_frame(sdata, skb2, &hdr);
33962306a36Sopenharmony_ci		}
34062306a36Sopenharmony_ci	}
34162306a36Sopenharmony_ci}
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_cistatic void
34462306a36Sopenharmony_ciieee802154_monitors_rx(struct ieee802154_local *local, struct sk_buff *skb)
34562306a36Sopenharmony_ci{
34662306a36Sopenharmony_ci	struct sk_buff *skb2;
34762306a36Sopenharmony_ci	struct ieee802154_sub_if_data *sdata;
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci	skb_reset_mac_header(skb);
35062306a36Sopenharmony_ci	skb->ip_summed = CHECKSUM_UNNECESSARY;
35162306a36Sopenharmony_ci	skb->pkt_type = PACKET_OTHERHOST;
35262306a36Sopenharmony_ci	skb->protocol = htons(ETH_P_IEEE802154);
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci	list_for_each_entry_rcu(sdata, &local->interfaces, list) {
35562306a36Sopenharmony_ci		if (sdata->wpan_dev.iftype != NL802154_IFTYPE_MONITOR)
35662306a36Sopenharmony_ci			continue;
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci		if (!ieee802154_sdata_running(sdata))
35962306a36Sopenharmony_ci			continue;
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci		skb2 = skb_clone(skb, GFP_ATOMIC);
36262306a36Sopenharmony_ci		if (skb2) {
36362306a36Sopenharmony_ci			skb2->dev = sdata->dev;
36462306a36Sopenharmony_ci			ieee802154_deliver_skb(skb2);
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci			sdata->dev->stats.rx_packets++;
36762306a36Sopenharmony_ci			sdata->dev->stats.rx_bytes += skb->len;
36862306a36Sopenharmony_ci		}
36962306a36Sopenharmony_ci	}
37062306a36Sopenharmony_ci}
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_civoid ieee802154_rx(struct ieee802154_local *local, struct sk_buff *skb)
37362306a36Sopenharmony_ci{
37462306a36Sopenharmony_ci	u16 crc;
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci	WARN_ON_ONCE(softirq_count() == 0);
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci	if (local->suspended)
37962306a36Sopenharmony_ci		goto free_skb;
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci	/* TODO: When a transceiver omits the checksum here, we
38262306a36Sopenharmony_ci	 * add an own calculated one. This is currently an ugly
38362306a36Sopenharmony_ci	 * solution because the monitor needs a crc here.
38462306a36Sopenharmony_ci	 */
38562306a36Sopenharmony_ci	if (local->hw.flags & IEEE802154_HW_RX_OMIT_CKSUM) {
38662306a36Sopenharmony_ci		crc = crc_ccitt(0, skb->data, skb->len);
38762306a36Sopenharmony_ci		put_unaligned_le16(crc, skb_put(skb, 2));
38862306a36Sopenharmony_ci	}
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci	rcu_read_lock();
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ci	ieee802154_monitors_rx(local, skb);
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci	/* Level 1 filtering: Check the FCS by software when relevant */
39562306a36Sopenharmony_ci	if (local->hw.phy->filtering == IEEE802154_FILTERING_NONE) {
39662306a36Sopenharmony_ci		crc = crc_ccitt(0, skb->data, skb->len);
39762306a36Sopenharmony_ci		if (crc)
39862306a36Sopenharmony_ci			goto drop;
39962306a36Sopenharmony_ci	}
40062306a36Sopenharmony_ci	/* remove crc */
40162306a36Sopenharmony_ci	skb_trim(skb, skb->len - 2);
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci	__ieee802154_rx_handle_packet(local, skb);
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_cidrop:
40662306a36Sopenharmony_ci	rcu_read_unlock();
40762306a36Sopenharmony_cifree_skb:
40862306a36Sopenharmony_ci	kfree_skb(skb);
40962306a36Sopenharmony_ci}
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_civoid
41262306a36Sopenharmony_ciieee802154_rx_irqsafe(struct ieee802154_hw *hw, struct sk_buff *skb, u8 lqi)
41362306a36Sopenharmony_ci{
41462306a36Sopenharmony_ci	struct ieee802154_local *local = hw_to_local(hw);
41562306a36Sopenharmony_ci	struct ieee802154_mac_cb *cb = mac_cb_init(skb);
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci	cb->lqi = lqi;
41862306a36Sopenharmony_ci	skb->pkt_type = IEEE802154_RX_MSG;
41962306a36Sopenharmony_ci	skb_queue_tail(&local->skb_queue, skb);
42062306a36Sopenharmony_ci	tasklet_schedule(&local->tasklet);
42162306a36Sopenharmony_ci}
42262306a36Sopenharmony_ciEXPORT_SYMBOL(ieee802154_rx_irqsafe);
423