rx.c 7.3 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
/*
 * Copyright (C) 2007-2012 Siemens AG
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2
 * as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * Written by:
 * Pavel Smolenskiy <pavel.smolenskiy@gmail.com>
 * Maxim Gorbachyov <maxim.gorbachev@siemens.com>
 * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
 * Alexander Smirnov <alex.bluesman.smirnov@gmail.com>
 */

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/netdevice.h>
#include <linux/crc-ccitt.h>
24
#include <asm/unaligned.h>
25 26 27

#include <net/mac802154.h>
#include <net/ieee802154_netdev.h>
28 29
#include <net/rtnetlink.h>
#include <linux/nl802154.h>
30

31
#include "ieee802154_i.h"
32

33
static int ieee802154_deliver_skb(struct sk_buff *skb)
34
{
35
	skb->ip_summed = CHECKSUM_UNNECESSARY;
36 37
	skb->protocol = htons(ETH_P_IEEE802154);

38 39 40 41
	return netif_receive_skb(skb);
}

static int
42 43
ieee802154_subif_frame(struct ieee802154_sub_if_data *sdata,
		       struct sk_buff *skb, const struct ieee802154_hdr *hdr)
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
{
	__le16 span, sshort;
	int rc;

	pr_debug("getting packet via slave interface %s\n", sdata->dev->name);

	spin_lock_bh(&sdata->mib_lock);

	span = sdata->pan_id;
	sshort = sdata->short_addr;

	switch (mac_cb(skb)->dest.mode) {
	case IEEE802154_ADDR_NONE:
		if (mac_cb(skb)->dest.mode != IEEE802154_ADDR_NONE)
			/* FIXME: check if we are PAN coordinator */
			skb->pkt_type = PACKET_OTHERHOST;
		else
			/* ACK comes with both addresses empty */
			skb->pkt_type = PACKET_HOST;
		break;
	case IEEE802154_ADDR_LONG:
		if (mac_cb(skb)->dest.pan_id != span &&
		    mac_cb(skb)->dest.pan_id != cpu_to_le16(IEEE802154_PANID_BROADCAST))
			skb->pkt_type = PACKET_OTHERHOST;
		else if (mac_cb(skb)->dest.extended_addr == sdata->extended_addr)
			skb->pkt_type = PACKET_HOST;
		else
			skb->pkt_type = PACKET_OTHERHOST;
		break;
	case IEEE802154_ADDR_SHORT:
		if (mac_cb(skb)->dest.pan_id != span &&
		    mac_cb(skb)->dest.pan_id != cpu_to_le16(IEEE802154_PANID_BROADCAST))
			skb->pkt_type = PACKET_OTHERHOST;
		else if (mac_cb(skb)->dest.short_addr == sshort)
			skb->pkt_type = PACKET_HOST;
		else if (mac_cb(skb)->dest.short_addr ==
			  cpu_to_le16(IEEE802154_ADDR_BROADCAST))
			skb->pkt_type = PACKET_BROADCAST;
		else
			skb->pkt_type = PACKET_OTHERHOST;
		break;
	default:
		spin_unlock_bh(&sdata->mib_lock);
		pr_debug("invalid dest mode\n");
		kfree_skb(skb);
		return NET_RX_DROP;
	}

	spin_unlock_bh(&sdata->mib_lock);

	skb->dev = sdata->dev;

	rc = mac802154_llsec_decrypt(&sdata->sec, skb);
	if (rc) {
		pr_debug("decryption failed: %i\n", rc);
		goto fail;
	}

	sdata->dev->stats.rx_packets++;
	sdata->dev->stats.rx_bytes += skb->len;

	switch (mac_cb(skb)->type) {
	case IEEE802154_FC_TYPE_DATA:
107
		return ieee802154_deliver_skb(skb);
108 109 110 111 112 113 114 115 116 117 118
	default:
		pr_warn("ieee802154: bad frame received (type = %d)\n",
			mac_cb(skb)->type);
		goto fail;
	}

fail:
	kfree_skb(skb);
	return NET_RX_DROP;
}

119 120
static void
ieee802154_print_addr(const char *name, const struct ieee802154_addr *addr)
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
{
	if (addr->mode == IEEE802154_ADDR_NONE)
		pr_debug("%s not present\n", name);

	pr_debug("%s PAN ID: %04x\n", name, le16_to_cpu(addr->pan_id));
	if (addr->mode == IEEE802154_ADDR_SHORT) {
		pr_debug("%s is short: %04x\n", name,
			 le16_to_cpu(addr->short_addr));
	} else {
		u64 hw = swab64((__force u64)addr->extended_addr);

		pr_debug("%s is hardware: %8phC\n", name, &hw);
	}
}

136 137
static int
ieee802154_parse_frame_start(struct sk_buff *skb, struct ieee802154_hdr *hdr)
138 139 140 141
{
	int hlen;
	struct ieee802154_mac_cb *cb = mac_cb_init(skb);

142 143
	skb_reset_mac_header(skb);

144 145 146 147 148 149 150 151 152 153 154 155 156
	hlen = ieee802154_hdr_pull(skb, hdr);
	if (hlen < 0)
		return -EINVAL;

	skb->mac_len = hlen;

	pr_debug("fc: %04x dsn: %02x\n", le16_to_cpup((__le16 *)&hdr->fc),
		 hdr->seq);

	cb->type = hdr->fc.type;
	cb->ackreq = hdr->fc.ack_request;
	cb->secen = hdr->fc.security_enabled;

157 158
	ieee802154_print_addr("destination", &hdr->dest);
	ieee802154_print_addr("source", &hdr->source);
159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195

	cb->source = hdr->source;
	cb->dest = hdr->dest;

	if (hdr->fc.security_enabled) {
		u64 key;

		pr_debug("seclevel %i\n", hdr->sec.level);

		switch (hdr->sec.key_id_mode) {
		case IEEE802154_SCF_KEY_IMPLICIT:
			pr_debug("implicit key\n");
			break;

		case IEEE802154_SCF_KEY_INDEX:
			pr_debug("key %02x\n", hdr->sec.key_id);
			break;

		case IEEE802154_SCF_KEY_SHORT_INDEX:
			pr_debug("key %04x:%04x %02x\n",
				 le32_to_cpu(hdr->sec.short_src) >> 16,
				 le32_to_cpu(hdr->sec.short_src) & 0xffff,
				 hdr->sec.key_id);
			break;

		case IEEE802154_SCF_KEY_HW_INDEX:
			key = swab64((__force u64)hdr->sec.extended_src);
			pr_debug("key source %8phC %02x\n", &key,
				 hdr->sec.key_id);
			break;
		}
	}

	return 0;
}

static void
196 197
__ieee802154_rx_handle_packet(struct ieee802154_local *local,
			      struct sk_buff *skb)
198 199 200 201 202
{
	int ret;
	struct ieee802154_sub_if_data *sdata;
	struct ieee802154_hdr hdr;

203
	ret = ieee802154_parse_frame_start(skb, &hdr);
204 205 206 207 208 209 210 211 212 213 214
	if (ret) {
		pr_debug("got invalid frame\n");
		kfree_skb(skb);
		return;
	}

	list_for_each_entry_rcu(sdata, &local->interfaces, list) {
		if (sdata->type != IEEE802154_DEV_WPAN ||
		    !netif_running(sdata->dev))
			continue;

215
		ieee802154_subif_frame(sdata, skb, &hdr);
216 217 218 219 220 221 222 223
		skb = NULL;
		break;
	}

	if (skb)
		kfree_skb(skb);
}

224
static void
225
ieee802154_monitors_rx(struct ieee802154_local *local, struct sk_buff *skb)
226 227 228 229
{
	struct sk_buff *skb2;
	struct ieee802154_sub_if_data *sdata;

230
	skb_reset_mac_header(skb);
231
	skb->ip_summed = CHECKSUM_UNNECESSARY;
232
	skb->pkt_type = PACKET_OTHERHOST;
233 234
	skb->protocol = htons(ETH_P_IEEE802154);

235
	list_for_each_entry_rcu(sdata, &local->interfaces, list) {
236 237 238 239
		if (sdata->type != IEEE802154_DEV_MONITOR)
			continue;

		if (!ieee802154_sdata_running(sdata))
240 241 242 243 244
			continue;

		skb2 = skb_clone(skb, GFP_ATOMIC);
		skb2->dev = sdata->dev;

245
		ieee802154_deliver_skb(skb2);
246 247 248

		sdata->dev->stats.rx_packets++;
		sdata->dev->stats.rx_bytes += skb->len;
249 250 251
	}
}

252
void ieee802154_rx(struct ieee802154_hw *hw, struct sk_buff *skb)
253
{
254
	struct ieee802154_local *local = hw_to_local(hw);
255
	u16 crc;
256

257 258
	WARN_ON_ONCE(softirq_count() == 0);

259 260 261 262 263
	/* TODO: When a transceiver omits the checksum here, we
	 * add an own calculated one. This is currently an ugly
	 * solution because the monitor needs a crc here.
	 */
	if (local->hw.flags & IEEE802154_HW_RX_OMIT_CKSUM) {
264
		crc = crc_ccitt(0, skb->data, skb->len);
265
		put_unaligned_le16(crc, skb_put(skb, 2));
266 267
	}

A
Alexander Aring 已提交
268 269
	rcu_read_lock();

270
	ieee802154_monitors_rx(local, skb);
271

272 273 274 275 276 277 278 279 280 281 282
	/* Check if transceiver doesn't validate the checksum.
	 * If not we validate the checksum here.
	 */
	if (local->hw.flags & IEEE802154_HW_RX_DROP_BAD_CKSUM) {
		crc = crc_ccitt(0, skb->data, skb->len);
		if (crc) {
			rcu_read_unlock();
			kfree_skb(skb);
			return;
		}
	}
283 284
	/* remove crc */
	skb_trim(skb, skb->len - 2);
A
Alexander Aring 已提交
285

286
	__ieee802154_rx_handle_packet(local, skb);
287

288
	rcu_read_unlock();
289
}
290
EXPORT_SYMBOL(ieee802154_rx);
291 292

void
293
ieee802154_rx_irqsafe(struct ieee802154_hw *hw, struct sk_buff *skb, u8 lqi)
294
{
295
	struct ieee802154_local *local = hw_to_local(hw);
296

297 298 299 300
	mac_cb(skb)->lqi = lqi;
	skb->pkt_type = IEEE802154_RX_MSG;
	skb_queue_tail(&local->skb_queue, skb);
	tasklet_schedule(&local->tasklet);
301 302
}
EXPORT_SYMBOL(ieee802154_rx_irqsafe);