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