linux/net/mac802154/rx.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright (C) 2007-2012 Siemens AG
   4 *
   5 * Written by:
   6 * Pavel Smolenskiy <pavel.smolenskiy@gmail.com>
   7 * Maxim Gorbachyov <maxim.gorbachev@siemens.com>
   8 * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
   9 * Alexander Smirnov <alex.bluesman.smirnov@gmail.com>
  10 */
  11
  12#include <linux/kernel.h>
  13#include <linux/module.h>
  14#include <linux/netdevice.h>
  15#include <linux/crc-ccitt.h>
  16#include <asm/unaligned.h>
  17
  18#include <net/mac802154.h>
  19#include <net/ieee802154_netdev.h>
  20#include <net/nl802154.h>
  21
  22#include "ieee802154_i.h"
  23
  24static int ieee802154_deliver_skb(struct sk_buff *skb)
  25{
  26        skb->ip_summed = CHECKSUM_UNNECESSARY;
  27        skb->protocol = htons(ETH_P_IEEE802154);
  28
  29        return netif_receive_skb(skb);
  30}
  31
  32static int
  33ieee802154_subif_frame(struct ieee802154_sub_if_data *sdata,
  34                       struct sk_buff *skb, const struct ieee802154_hdr *hdr)
  35{
  36        struct wpan_dev *wpan_dev = &sdata->wpan_dev;
  37        __le16 span, sshort;
  38        int rc;
  39
  40        pr_debug("getting packet via slave interface %s\n", sdata->dev->name);
  41
  42        span = wpan_dev->pan_id;
  43        sshort = wpan_dev->short_addr;
  44
  45        switch (mac_cb(skb)->dest.mode) {
  46        case IEEE802154_ADDR_NONE:
  47                if (mac_cb(skb)->dest.mode != IEEE802154_ADDR_NONE)
  48                        /* FIXME: check if we are PAN coordinator */
  49                        skb->pkt_type = PACKET_OTHERHOST;
  50                else
  51                        /* ACK comes with both addresses empty */
  52                        skb->pkt_type = PACKET_HOST;
  53                break;
  54        case IEEE802154_ADDR_LONG:
  55                if (mac_cb(skb)->dest.pan_id != span &&
  56                    mac_cb(skb)->dest.pan_id != cpu_to_le16(IEEE802154_PANID_BROADCAST))
  57                        skb->pkt_type = PACKET_OTHERHOST;
  58                else if (mac_cb(skb)->dest.extended_addr == wpan_dev->extended_addr)
  59                        skb->pkt_type = PACKET_HOST;
  60                else
  61                        skb->pkt_type = PACKET_OTHERHOST;
  62                break;
  63        case IEEE802154_ADDR_SHORT:
  64                if (mac_cb(skb)->dest.pan_id != span &&
  65                    mac_cb(skb)->dest.pan_id != cpu_to_le16(IEEE802154_PANID_BROADCAST))
  66                        skb->pkt_type = PACKET_OTHERHOST;
  67                else if (mac_cb(skb)->dest.short_addr == sshort)
  68                        skb->pkt_type = PACKET_HOST;
  69                else if (mac_cb(skb)->dest.short_addr ==
  70                          cpu_to_le16(IEEE802154_ADDR_BROADCAST))
  71                        skb->pkt_type = PACKET_BROADCAST;
  72                else
  73                        skb->pkt_type = PACKET_OTHERHOST;
  74                break;
  75        default:
  76                pr_debug("invalid dest mode\n");
  77                goto fail;
  78        }
  79
  80        skb->dev = sdata->dev;
  81
  82        /* TODO this should be moved after netif_receive_skb call, otherwise
  83         * wireshark will show a mac header with security fields and the
  84         * payload is already decrypted.
  85         */
  86        rc = mac802154_llsec_decrypt(&sdata->sec, skb);
  87        if (rc) {
  88                pr_debug("decryption failed: %i\n", rc);
  89                goto fail;
  90        }
  91
  92        sdata->dev->stats.rx_packets++;
  93        sdata->dev->stats.rx_bytes += skb->len;
  94
  95        switch (mac_cb(skb)->type) {
  96        case IEEE802154_FC_TYPE_BEACON:
  97        case IEEE802154_FC_TYPE_ACK:
  98        case IEEE802154_FC_TYPE_MAC_CMD:
  99                goto fail;
 100
 101        case IEEE802154_FC_TYPE_DATA:
 102                return ieee802154_deliver_skb(skb);
 103        default:
 104                pr_warn_ratelimited("ieee802154: bad frame received "
 105                                    "(type = %d)\n", mac_cb(skb)->type);
 106                goto fail;
 107        }
 108
 109fail:
 110        kfree_skb(skb);
 111        return NET_RX_DROP;
 112}
 113
 114static void
 115ieee802154_print_addr(const char *name, const struct ieee802154_addr *addr)
 116{
 117        if (addr->mode == IEEE802154_ADDR_NONE)
 118                pr_debug("%s not present\n", name);
 119
 120        pr_debug("%s PAN ID: %04x\n", name, le16_to_cpu(addr->pan_id));
 121        if (addr->mode == IEEE802154_ADDR_SHORT) {
 122                pr_debug("%s is short: %04x\n", name,
 123                         le16_to_cpu(addr->short_addr));
 124        } else {
 125                u64 hw = swab64((__force u64)addr->extended_addr);
 126
 127                pr_debug("%s is hardware: %8phC\n", name, &hw);
 128        }
 129}
 130
 131static int
 132ieee802154_parse_frame_start(struct sk_buff *skb, struct ieee802154_hdr *hdr)
 133{
 134        int hlen;
 135        struct ieee802154_mac_cb *cb = mac_cb_init(skb);
 136
 137        skb_reset_mac_header(skb);
 138
 139        hlen = ieee802154_hdr_pull(skb, hdr);
 140        if (hlen < 0)
 141                return -EINVAL;
 142
 143        skb->mac_len = hlen;
 144
 145        pr_debug("fc: %04x dsn: %02x\n", le16_to_cpup((__le16 *)&hdr->fc),
 146                 hdr->seq);
 147
 148        cb->type = hdr->fc.type;
 149        cb->ackreq = hdr->fc.ack_request;
 150        cb->secen = hdr->fc.security_enabled;
 151
 152        ieee802154_print_addr("destination", &hdr->dest);
 153        ieee802154_print_addr("source", &hdr->source);
 154
 155        cb->source = hdr->source;
 156        cb->dest = hdr->dest;
 157
 158        if (hdr->fc.security_enabled) {
 159                u64 key;
 160
 161                pr_debug("seclevel %i\n", hdr->sec.level);
 162
 163                switch (hdr->sec.key_id_mode) {
 164                case IEEE802154_SCF_KEY_IMPLICIT:
 165                        pr_debug("implicit key\n");
 166                        break;
 167
 168                case IEEE802154_SCF_KEY_INDEX:
 169                        pr_debug("key %02x\n", hdr->sec.key_id);
 170                        break;
 171
 172                case IEEE802154_SCF_KEY_SHORT_INDEX:
 173                        pr_debug("key %04x:%04x %02x\n",
 174                                 le32_to_cpu(hdr->sec.short_src) >> 16,
 175                                 le32_to_cpu(hdr->sec.short_src) & 0xffff,
 176                                 hdr->sec.key_id);
 177                        break;
 178
 179                case IEEE802154_SCF_KEY_HW_INDEX:
 180                        key = swab64((__force u64)hdr->sec.extended_src);
 181                        pr_debug("key source %8phC %02x\n", &key,
 182                                 hdr->sec.key_id);
 183                        break;
 184                }
 185        }
 186
 187        return 0;
 188}
 189
 190static void
 191__ieee802154_rx_handle_packet(struct ieee802154_local *local,
 192                              struct sk_buff *skb)
 193{
 194        int ret;
 195        struct ieee802154_sub_if_data *sdata;
 196        struct ieee802154_hdr hdr;
 197
 198        ret = ieee802154_parse_frame_start(skb, &hdr);
 199        if (ret) {
 200                pr_debug("got invalid frame\n");
 201                kfree_skb(skb);
 202                return;
 203        }
 204
 205        list_for_each_entry_rcu(sdata, &local->interfaces, list) {
 206                if (sdata->wpan_dev.iftype != NL802154_IFTYPE_NODE)
 207                        continue;
 208
 209                if (!ieee802154_sdata_running(sdata))
 210                        continue;
 211
 212                ieee802154_subif_frame(sdata, skb, &hdr);
 213                skb = NULL;
 214                break;
 215        }
 216
 217        kfree_skb(skb);
 218}
 219
 220static void
 221ieee802154_monitors_rx(struct ieee802154_local *local, struct sk_buff *skb)
 222{
 223        struct sk_buff *skb2;
 224        struct ieee802154_sub_if_data *sdata;
 225
 226        skb_reset_mac_header(skb);
 227        skb->ip_summed = CHECKSUM_UNNECESSARY;
 228        skb->pkt_type = PACKET_OTHERHOST;
 229        skb->protocol = htons(ETH_P_IEEE802154);
 230
 231        list_for_each_entry_rcu(sdata, &local->interfaces, list) {
 232                if (sdata->wpan_dev.iftype != NL802154_IFTYPE_MONITOR)
 233                        continue;
 234
 235                if (!ieee802154_sdata_running(sdata))
 236                        continue;
 237
 238                skb2 = skb_clone(skb, GFP_ATOMIC);
 239                if (skb2) {
 240                        skb2->dev = sdata->dev;
 241                        ieee802154_deliver_skb(skb2);
 242
 243                        sdata->dev->stats.rx_packets++;
 244                        sdata->dev->stats.rx_bytes += skb->len;
 245                }
 246        }
 247}
 248
 249void ieee802154_rx(struct ieee802154_local *local, struct sk_buff *skb)
 250{
 251        u16 crc;
 252
 253        WARN_ON_ONCE(softirq_count() == 0);
 254
 255        if (local->suspended)
 256                goto drop;
 257
 258        /* TODO: When a transceiver omits the checksum here, we
 259         * add an own calculated one. This is currently an ugly
 260         * solution because the monitor needs a crc here.
 261         */
 262        if (local->hw.flags & IEEE802154_HW_RX_OMIT_CKSUM) {
 263                crc = crc_ccitt(0, skb->data, skb->len);
 264                put_unaligned_le16(crc, skb_put(skb, 2));
 265        }
 266
 267        rcu_read_lock();
 268
 269        ieee802154_monitors_rx(local, skb);
 270
 271        /* Check if transceiver doesn't validate the checksum.
 272         * If not we validate the checksum here.
 273         */
 274        if (local->hw.flags & IEEE802154_HW_RX_DROP_BAD_CKSUM) {
 275                crc = crc_ccitt(0, skb->data, skb->len);
 276                if (crc) {
 277                        rcu_read_unlock();
 278                        goto drop;
 279                }
 280        }
 281        /* remove crc */
 282        skb_trim(skb, skb->len - 2);
 283
 284        __ieee802154_rx_handle_packet(local, skb);
 285
 286        rcu_read_unlock();
 287
 288        return;
 289drop:
 290        kfree_skb(skb);
 291}
 292
 293void
 294ieee802154_rx_irqsafe(struct ieee802154_hw *hw, struct sk_buff *skb, u8 lqi)
 295{
 296        struct ieee802154_local *local = hw_to_local(hw);
 297
 298        mac_cb(skb)->lqi = lqi;
 299        skb->pkt_type = IEEE802154_RX_MSG;
 300        skb_queue_tail(&local->skb_queue, skb);
 301        tasklet_schedule(&local->tasklet);
 302}
 303EXPORT_SYMBOL(ieee802154_rx_irqsafe);
 304