Blame view

net/mac802154/rx.c 7.52 KB
1cd829c83   alex.bluesman.smirnov@gmail.com   mac802154: RX dat...
1
2
3
4
5
6
7
8
9
10
11
12
  /*
   * 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.
   *
1cd829c83   alex.bluesman.smirnov@gmail.com   mac802154: RX dat...
13
14
15
16
17
18
19
20
21
   * 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>
1cd829c83   alex.bluesman.smirnov@gmail.com   mac802154: RX dat...
22
23
  #include <linux/netdevice.h>
  #include <linux/crc-ccitt.h>
b7889497d   Alexander Aring   mac802154: rx: si...
24
  #include <asm/unaligned.h>
1cd829c83   alex.bluesman.smirnov@gmail.com   mac802154: RX dat...
25
26
27
  
  #include <net/mac802154.h>
  #include <net/ieee802154_netdev.h>
944742a36   Alexander Aring   mac802154: use ne...
28
  #include <net/nl802154.h>
1cd829c83   alex.bluesman.smirnov@gmail.com   mac802154: RX dat...
29

0f1556bc2   Alexander Aring   mac802154: move m...
30
  #include "ieee802154_i.h"
1cd829c83   alex.bluesman.smirnov@gmail.com   mac802154: RX dat...
31

08c511a73   Alexander Aring   mac802154: rx: re...
32
  static int ieee802154_deliver_skb(struct sk_buff *skb)
2a9820c9e   Alexander Aring   mac802154: rx: mo...
33
  {
75a46f0ee   Alexander Aring   mac802154: rx: ad...
34
  	skb->ip_summed = CHECKSUM_UNNECESSARY;
702dcf994   Alexander Aring   mac802154: rx: mo...
35
  	skb->protocol = htons(ETH_P_IEEE802154);
2a9820c9e   Alexander Aring   mac802154: rx: mo...
36
37
38
39
  	return netif_receive_skb(skb);
  }
  
  static int
be9d215fa   Alexander Aring   mac802154: rx: ch...
40
41
  ieee802154_subif_frame(struct ieee802154_sub_if_data *sdata,
  		       struct sk_buff *skb, const struct ieee802154_hdr *hdr)
2a9820c9e   Alexander Aring   mac802154: rx: mo...
42
  {
863e88f25   Alexander Aring   mac802154: move m...
43
  	struct wpan_dev *wpan_dev = &sdata->wpan_dev;
2a9820c9e   Alexander Aring   mac802154: rx: mo...
44
45
46
47
48
  	__le16 span, sshort;
  	int rc;
  
  	pr_debug("getting packet via slave interface %s
  ", sdata->dev->name);
863e88f25   Alexander Aring   mac802154: move m...
49
50
  	span = wpan_dev->pan_id;
  	sshort = wpan_dev->short_addr;
2a9820c9e   Alexander Aring   mac802154: rx: mo...
51
52
53
54
55
56
57
58
59
60
61
62
63
64
  
  	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;
863e88f25   Alexander Aring   mac802154: move m...
65
  		else if (mac_cb(skb)->dest.extended_addr == wpan_dev->extended_addr)
2a9820c9e   Alexander Aring   mac802154: rx: mo...
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
  			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:
2a9820c9e   Alexander Aring   mac802154: rx: mo...
83
84
  		pr_debug("invalid dest mode
  ");
bcb47aabf   Varka Bhadram   mac802154: use go...
85
  		goto fail;
2a9820c9e   Alexander Aring   mac802154: rx: mo...
86
  	}
2a9820c9e   Alexander Aring   mac802154: rx: mo...
87
  	skb->dev = sdata->dev;
d58a2fa90   Alexander Aring   mac802154: add co...
88
89
90
91
  	/* TODO this should be moved after netif_receive_skb call, otherwise
  	 * wireshark will show a mac header with security fields and the
  	 * payload is already decrypted.
  	 */
2a9820c9e   Alexander Aring   mac802154: rx: mo...
92
93
94
95
96
97
98
99
100
101
102
  	rc = mac802154_llsec_decrypt(&sdata->sec, skb);
  	if (rc) {
  		pr_debug("decryption failed: %i
  ", rc);
  		goto fail;
  	}
  
  	sdata->dev->stats.rx_packets++;
  	sdata->dev->stats.rx_bytes += skb->len;
  
  	switch (mac_cb(skb)->type) {
ca1de81aa   Aristeu Rozanski   mac802154: don't ...
103
104
105
106
  	case IEEE802154_FC_TYPE_BEACON:
  	case IEEE802154_FC_TYPE_ACK:
  	case IEEE802154_FC_TYPE_MAC_CMD:
  		goto fail;
2a9820c9e   Alexander Aring   mac802154: rx: mo...
107
  	case IEEE802154_FC_TYPE_DATA:
08c511a73   Alexander Aring   mac802154: rx: re...
108
  		return ieee802154_deliver_skb(skb);
2a9820c9e   Alexander Aring   mac802154: rx: mo...
109
  	default:
bd89bb6da   Aristeu Rozanski   mac802154: use ra...
110
111
112
  		pr_warn_ratelimited("ieee802154: bad frame received "
  				    "(type = %d)
  ", mac_cb(skb)->type);
2a9820c9e   Alexander Aring   mac802154: rx: mo...
113
114
115
116
117
118
119
  		goto fail;
  	}
  
  fail:
  	kfree_skb(skb);
  	return NET_RX_DROP;
  }
be9d215fa   Alexander Aring   mac802154: rx: ch...
120
121
  static void
  ieee802154_print_addr(const char *name, const struct ieee802154_addr *addr)
2a9820c9e   Alexander Aring   mac802154: rx: mo...
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
  {
  	if (addr->mode == IEEE802154_ADDR_NONE)
  		pr_debug("%s not present
  ", name);
  
  	pr_debug("%s PAN ID: %04x
  ", name, le16_to_cpu(addr->pan_id));
  	if (addr->mode == IEEE802154_ADDR_SHORT) {
  		pr_debug("%s is short: %04x
  ", name,
  			 le16_to_cpu(addr->short_addr));
  	} else {
  		u64 hw = swab64((__force u64)addr->extended_addr);
  
  		pr_debug("%s is hardware: %8phC
  ", name, &hw);
  	}
  }
be9d215fa   Alexander Aring   mac802154: rx: ch...
140
141
  static int
  ieee802154_parse_frame_start(struct sk_buff *skb, struct ieee802154_hdr *hdr)
2a9820c9e   Alexander Aring   mac802154: rx: mo...
142
143
144
  {
  	int hlen;
  	struct ieee802154_mac_cb *cb = mac_cb_init(skb);
9cf215d07   Alexander Aring   mac802154: rx: mo...
145
  	skb_reset_mac_header(skb);
2a9820c9e   Alexander Aring   mac802154: rx: mo...
146
147
148
149
150
151
152
153
154
155
156
157
158
  	hlen = ieee802154_hdr_pull(skb, hdr);
  	if (hlen < 0)
  		return -EINVAL;
  
  	skb->mac_len = hlen;
  
  	pr_debug("fc: %04x dsn: %02x
  ", 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;
be9d215fa   Alexander Aring   mac802154: rx: ch...
159
160
  	ieee802154_print_addr("destination", &hdr->dest);
  	ieee802154_print_addr("source", &hdr->source);
2a9820c9e   Alexander Aring   mac802154: rx: mo...
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
196
197
198
199
200
201
202
  
  	cb->source = hdr->source;
  	cb->dest = hdr->dest;
  
  	if (hdr->fc.security_enabled) {
  		u64 key;
  
  		pr_debug("seclevel %i
  ", hdr->sec.level);
  
  		switch (hdr->sec.key_id_mode) {
  		case IEEE802154_SCF_KEY_IMPLICIT:
  			pr_debug("implicit key
  ");
  			break;
  
  		case IEEE802154_SCF_KEY_INDEX:
  			pr_debug("key %02x
  ", hdr->sec.key_id);
  			break;
  
  		case IEEE802154_SCF_KEY_SHORT_INDEX:
  			pr_debug("key %04x:%04x %02x
  ",
  				 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
  ", &key,
  				 hdr->sec.key_id);
  			break;
  		}
  	}
  
  	return 0;
  }
  
  static void
be9d215fa   Alexander Aring   mac802154: rx: ch...
203
204
  __ieee802154_rx_handle_packet(struct ieee802154_local *local,
  			      struct sk_buff *skb)
2a9820c9e   Alexander Aring   mac802154: rx: mo...
205
206
207
208
  {
  	int ret;
  	struct ieee802154_sub_if_data *sdata;
  	struct ieee802154_hdr hdr;
be9d215fa   Alexander Aring   mac802154: rx: ch...
209
  	ret = ieee802154_parse_frame_start(skb, &hdr);
2a9820c9e   Alexander Aring   mac802154: rx: mo...
210
211
212
213
214
215
  	if (ret) {
  		pr_debug("got invalid frame
  ");
  		kfree_skb(skb);
  		return;
  	}
2a9820c9e   Alexander Aring   mac802154: rx: mo...
216
  	list_for_each_entry_rcu(sdata, &local->interfaces, list) {
1bc1754e8   Varka Bhadram   mac802154: rx pac...
217
218
219
220
  		if (sdata->wpan_dev.iftype != NL802154_IFTYPE_NODE)
  			continue;
  
  		if (!ieee802154_sdata_running(sdata))
2a9820c9e   Alexander Aring   mac802154: rx: mo...
221
  			continue;
be9d215fa   Alexander Aring   mac802154: rx: ch...
222
  		ieee802154_subif_frame(sdata, skb, &hdr);
2a9820c9e   Alexander Aring   mac802154: rx: mo...
223
224
225
  		skb = NULL;
  		break;
  	}
2a9820c9e   Alexander Aring   mac802154: rx: mo...
226

56f9ebe64   Markus Elfring   mac802154: Delete...
227
  	kfree_skb(skb);
2a9820c9e   Alexander Aring   mac802154: rx: mo...
228
  }
4ca18be54   Alexander Aring   mac802154: tx: re...
229
  static void
be9d215fa   Alexander Aring   mac802154: rx: ch...
230
  ieee802154_monitors_rx(struct ieee802154_local *local, struct sk_buff *skb)
2a9820c9e   Alexander Aring   mac802154: rx: mo...
231
232
233
  {
  	struct sk_buff *skb2;
  	struct ieee802154_sub_if_data *sdata;
2a9820c9e   Alexander Aring   mac802154: rx: mo...
234

9cf215d07   Alexander Aring   mac802154: rx: mo...
235
  	skb_reset_mac_header(skb);
75a46f0ee   Alexander Aring   mac802154: rx: ad...
236
  	skb->ip_summed = CHECKSUM_UNNECESSARY;
c9ca64014   Alexander Aring   mac802154: rx: ad...
237
  	skb->pkt_type = PACKET_OTHERHOST;
702dcf994   Alexander Aring   mac802154: rx: mo...
238
  	skb->protocol = htons(ETH_P_IEEE802154);
2a9820c9e   Alexander Aring   mac802154: rx: mo...
239
  	list_for_each_entry_rcu(sdata, &local->interfaces, list) {
ed65963ba   Alexander Aring   mac802154: remove...
240
  		if (sdata->wpan_dev.iftype != NL802154_IFTYPE_MONITOR)
20b48120c   Alexander Aring   mac802154: rx: mo...
241
242
243
  			continue;
  
  		if (!ieee802154_sdata_running(sdata))
2a9820c9e   Alexander Aring   mac802154: rx: mo...
244
245
246
  			continue;
  
  		skb2 = skb_clone(skb, GFP_ATOMIC);
05f7de679   Alexander Aring   mac802154: rx: ad...
247
248
249
  		if (skb2) {
  			skb2->dev = sdata->dev;
  			ieee802154_deliver_skb(skb2);
2a9820c9e   Alexander Aring   mac802154: rx: mo...
250

05f7de679   Alexander Aring   mac802154: rx: ad...
251
252
253
  			sdata->dev->stats.rx_packets++;
  			sdata->dev->stats.rx_bytes += skb->len;
  		}
2a9820c9e   Alexander Aring   mac802154: rx: mo...
254
  	}
2a9820c9e   Alexander Aring   mac802154: rx: mo...
255
  }
d10270ce9   Varka Bhadram   mac802154: fix ie...
256
  void ieee802154_rx(struct ieee802154_local *local, struct sk_buff *skb)
1cd829c83   alex.bluesman.smirnov@gmail.com   mac802154: RX dat...
257
  {
ec718f3db   Alexander Aring   mac802154: rx: ad...
258
  	u16 crc;
1cd829c83   alex.bluesman.smirnov@gmail.com   mac802154: RX dat...
259

469100d6c   Alexander Aring   mac802154: rx: re...
260
  	WARN_ON_ONCE(softirq_count() == 0);
3cf24cf8c   Alexander Aring   mac802154: cfg: a...
261
262
  	if (local->suspended)
  		goto drop;
b7889497d   Alexander Aring   mac802154: rx: si...
263
264
265
266
267
  	/* 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) {
ec718f3db   Alexander Aring   mac802154: rx: ad...
268
  		crc = crc_ccitt(0, skb->data, skb->len);
b7889497d   Alexander Aring   mac802154: rx: si...
269
  		put_unaligned_le16(crc, skb_put(skb, 2));
1cd829c83   alex.bluesman.smirnov@gmail.com   mac802154: RX dat...
270
  	}
e176b681b   Alexander Aring   mac802154: rx: mo...
271
  	rcu_read_lock();
be9d215fa   Alexander Aring   mac802154: rx: ch...
272
  	ieee802154_monitors_rx(local, skb);
2d3b5b0a9   Phoebe Buckheister   mac802154: don't ...
273

ec718f3db   Alexander Aring   mac802154: rx: ad...
274
275
276
277
278
279
280
  	/* 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();
3cf24cf8c   Alexander Aring   mac802154: cfg: a...
281
  			goto drop;
ec718f3db   Alexander Aring   mac802154: rx: ad...
282
283
  		}
  	}
b7889497d   Alexander Aring   mac802154: rx: si...
284
285
  	/* remove crc */
  	skb_trim(skb, skb->len - 2);
e176b681b   Alexander Aring   mac802154: rx: mo...
286

b7889497d   Alexander Aring   mac802154: rx: si...
287
  	__ieee802154_rx_handle_packet(local, skb);
2d3b5b0a9   Phoebe Buckheister   mac802154: don't ...
288

b7889497d   Alexander Aring   mac802154: rx: si...
289
  	rcu_read_unlock();
3cf24cf8c   Alexander Aring   mac802154: cfg: a...
290
291
292
293
  
  	return;
  drop:
  	kfree_skb(skb);
1cd829c83   alex.bluesman.smirnov@gmail.com   mac802154: RX dat...
294
  }
1cd829c83   alex.bluesman.smirnov@gmail.com   mac802154: RX dat...
295
296
  
  void
5a5043977   Alexander Aring   ieee802154: renam...
297
  ieee802154_rx_irqsafe(struct ieee802154_hw *hw, struct sk_buff *skb, u8 lqi)
1cd829c83   alex.bluesman.smirnov@gmail.com   mac802154: RX dat...
298
  {
60741361c   Alexander Aring   mac802154: introd...
299
  	struct ieee802154_local *local = hw_to_local(hw);
1cd829c83   alex.bluesman.smirnov@gmail.com   mac802154: RX dat...
300

c5c47e67b   Alexander Aring   mac802154: rx: us...
301
302
303
304
  	mac_cb(skb)->lqi = lqi;
  	skb->pkt_type = IEEE802154_RX_MSG;
  	skb_queue_tail(&local->skb_queue, skb);
  	tasklet_schedule(&local->tasklet);
1cd829c83   alex.bluesman.smirnov@gmail.com   mac802154: RX dat...
305
306
  }
  EXPORT_SYMBOL(ieee802154_rx_irqsafe);