root/net/mac802154/rx.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ieee802154_deliver_skb
  2. ieee802154_subif_frame
  3. ieee802154_print_addr
  4. ieee802154_parse_frame_start
  5. __ieee802154_rx_handle_packet
  6. ieee802154_monitors_rx
  7. ieee802154_rx
  8. ieee802154_rx_irqsafe

   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 
  24 static 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 
  32 static int
  33 ieee802154_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 
 109 fail:
 110         kfree_skb(skb);
 111         return NET_RX_DROP;
 112 }
 113 
 114 static void
 115 ieee802154_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 
 131 static int
 132 ieee802154_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 
 190 static 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 
 220 static void
 221 ieee802154_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 
 249 void 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;
 289 drop:
 290         kfree_skb(skb);
 291 }
 292 
 293 void
 294 ieee802154_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 }
 303 EXPORT_SYMBOL(ieee802154_rx_irqsafe);

/* [<][>][^][v][top][bottom][index][help] */