Blame view
net/mac802154/rx.c
7.52 KB
1cd829c83 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 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 mac802154: RX dat... |
22 23 |
#include <linux/netdevice.h> #include <linux/crc-ccitt.h> |
b7889497d mac802154: rx: si... |
24 |
#include <asm/unaligned.h> |
1cd829c83 mac802154: RX dat... |
25 26 27 |
#include <net/mac802154.h> #include <net/ieee802154_netdev.h> |
944742a36 mac802154: use ne... |
28 |
#include <net/nl802154.h> |
1cd829c83 mac802154: RX dat... |
29 |
|
0f1556bc2 mac802154: move m... |
30 |
#include "ieee802154_i.h" |
1cd829c83 mac802154: RX dat... |
31 |
|
08c511a73 mac802154: rx: re... |
32 |
static int ieee802154_deliver_skb(struct sk_buff *skb) |
2a9820c9e mac802154: rx: mo... |
33 |
{ |
75a46f0ee mac802154: rx: ad... |
34 |
skb->ip_summed = CHECKSUM_UNNECESSARY; |
702dcf994 mac802154: rx: mo... |
35 |
skb->protocol = htons(ETH_P_IEEE802154); |
2a9820c9e mac802154: rx: mo... |
36 37 38 39 |
return netif_receive_skb(skb); } static int |
be9d215fa mac802154: rx: ch... |
40 41 |
ieee802154_subif_frame(struct ieee802154_sub_if_data *sdata, struct sk_buff *skb, const struct ieee802154_hdr *hdr) |
2a9820c9e mac802154: rx: mo... |
42 |
{ |
863e88f25 mac802154: move m... |
43 |
struct wpan_dev *wpan_dev = &sdata->wpan_dev; |
2a9820c9e 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 mac802154: move m... |
49 50 |
span = wpan_dev->pan_id; sshort = wpan_dev->short_addr; |
2a9820c9e 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 mac802154: move m... |
65 |
else if (mac_cb(skb)->dest.extended_addr == wpan_dev->extended_addr) |
2a9820c9e 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 mac802154: rx: mo... |
83 84 |
pr_debug("invalid dest mode "); |
bcb47aabf mac802154: use go... |
85 |
goto fail; |
2a9820c9e mac802154: rx: mo... |
86 |
} |
2a9820c9e mac802154: rx: mo... |
87 |
skb->dev = sdata->dev; |
d58a2fa90 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 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 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 mac802154: rx: mo... |
107 |
case IEEE802154_FC_TYPE_DATA: |
08c511a73 mac802154: rx: re... |
108 |
return ieee802154_deliver_skb(skb); |
2a9820c9e mac802154: rx: mo... |
109 |
default: |
bd89bb6da mac802154: use ra... |
110 111 112 |
pr_warn_ratelimited("ieee802154: bad frame received " "(type = %d) ", mac_cb(skb)->type); |
2a9820c9e mac802154: rx: mo... |
113 114 115 116 117 118 119 |
goto fail; } fail: kfree_skb(skb); return NET_RX_DROP; } |
be9d215fa mac802154: rx: ch... |
120 121 |
static void ieee802154_print_addr(const char *name, const struct ieee802154_addr *addr) |
2a9820c9e 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 mac802154: rx: ch... |
140 141 |
static int ieee802154_parse_frame_start(struct sk_buff *skb, struct ieee802154_hdr *hdr) |
2a9820c9e mac802154: rx: mo... |
142 143 144 |
{ int hlen; struct ieee802154_mac_cb *cb = mac_cb_init(skb); |
9cf215d07 mac802154: rx: mo... |
145 |
skb_reset_mac_header(skb); |
2a9820c9e 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 mac802154: rx: ch... |
159 160 |
ieee802154_print_addr("destination", &hdr->dest); ieee802154_print_addr("source", &hdr->source); |
2a9820c9e 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 mac802154: rx: ch... |
203 204 |
__ieee802154_rx_handle_packet(struct ieee802154_local *local, struct sk_buff *skb) |
2a9820c9e mac802154: rx: mo... |
205 206 207 208 |
{ int ret; struct ieee802154_sub_if_data *sdata; struct ieee802154_hdr hdr; |
be9d215fa mac802154: rx: ch... |
209 |
ret = ieee802154_parse_frame_start(skb, &hdr); |
2a9820c9e mac802154: rx: mo... |
210 211 212 213 214 215 |
if (ret) { pr_debug("got invalid frame "); kfree_skb(skb); return; } |
2a9820c9e mac802154: rx: mo... |
216 |
list_for_each_entry_rcu(sdata, &local->interfaces, list) { |
1bc1754e8 mac802154: rx pac... |
217 218 219 220 |
if (sdata->wpan_dev.iftype != NL802154_IFTYPE_NODE) continue; if (!ieee802154_sdata_running(sdata)) |
2a9820c9e mac802154: rx: mo... |
221 |
continue; |
be9d215fa mac802154: rx: ch... |
222 |
ieee802154_subif_frame(sdata, skb, &hdr); |
2a9820c9e mac802154: rx: mo... |
223 224 225 |
skb = NULL; break; } |
2a9820c9e mac802154: rx: mo... |
226 |
|
56f9ebe64 mac802154: Delete... |
227 |
kfree_skb(skb); |
2a9820c9e mac802154: rx: mo... |
228 |
} |
4ca18be54 mac802154: tx: re... |
229 |
static void |
be9d215fa mac802154: rx: ch... |
230 |
ieee802154_monitors_rx(struct ieee802154_local *local, struct sk_buff *skb) |
2a9820c9e mac802154: rx: mo... |
231 232 233 |
{ struct sk_buff *skb2; struct ieee802154_sub_if_data *sdata; |
2a9820c9e mac802154: rx: mo... |
234 |
|
9cf215d07 mac802154: rx: mo... |
235 |
skb_reset_mac_header(skb); |
75a46f0ee mac802154: rx: ad... |
236 |
skb->ip_summed = CHECKSUM_UNNECESSARY; |
c9ca64014 mac802154: rx: ad... |
237 |
skb->pkt_type = PACKET_OTHERHOST; |
702dcf994 mac802154: rx: mo... |
238 |
skb->protocol = htons(ETH_P_IEEE802154); |
2a9820c9e mac802154: rx: mo... |
239 |
list_for_each_entry_rcu(sdata, &local->interfaces, list) { |
ed65963ba mac802154: remove... |
240 |
if (sdata->wpan_dev.iftype != NL802154_IFTYPE_MONITOR) |
20b48120c mac802154: rx: mo... |
241 242 243 |
continue; if (!ieee802154_sdata_running(sdata)) |
2a9820c9e mac802154: rx: mo... |
244 245 246 |
continue; skb2 = skb_clone(skb, GFP_ATOMIC); |
05f7de679 mac802154: rx: ad... |
247 248 249 |
if (skb2) { skb2->dev = sdata->dev; ieee802154_deliver_skb(skb2); |
2a9820c9e mac802154: rx: mo... |
250 |
|
05f7de679 mac802154: rx: ad... |
251 252 253 |
sdata->dev->stats.rx_packets++; sdata->dev->stats.rx_bytes += skb->len; } |
2a9820c9e mac802154: rx: mo... |
254 |
} |
2a9820c9e mac802154: rx: mo... |
255 |
} |
d10270ce9 mac802154: fix ie... |
256 |
void ieee802154_rx(struct ieee802154_local *local, struct sk_buff *skb) |
1cd829c83 mac802154: RX dat... |
257 |
{ |
ec718f3db mac802154: rx: ad... |
258 |
u16 crc; |
1cd829c83 mac802154: RX dat... |
259 |
|
469100d6c mac802154: rx: re... |
260 |
WARN_ON_ONCE(softirq_count() == 0); |
3cf24cf8c mac802154: cfg: a... |
261 262 |
if (local->suspended) goto drop; |
b7889497d 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 mac802154: rx: ad... |
268 |
crc = crc_ccitt(0, skb->data, skb->len); |
b7889497d mac802154: rx: si... |
269 |
put_unaligned_le16(crc, skb_put(skb, 2)); |
1cd829c83 mac802154: RX dat... |
270 |
} |
e176b681b mac802154: rx: mo... |
271 |
rcu_read_lock(); |
be9d215fa mac802154: rx: ch... |
272 |
ieee802154_monitors_rx(local, skb); |
2d3b5b0a9 mac802154: don't ... |
273 |
|
ec718f3db 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 mac802154: cfg: a... |
281 |
goto drop; |
ec718f3db mac802154: rx: ad... |
282 283 |
} } |
b7889497d mac802154: rx: si... |
284 285 |
/* remove crc */ skb_trim(skb, skb->len - 2); |
e176b681b mac802154: rx: mo... |
286 |
|
b7889497d mac802154: rx: si... |
287 |
__ieee802154_rx_handle_packet(local, skb); |
2d3b5b0a9 mac802154: don't ... |
288 |
|
b7889497d mac802154: rx: si... |
289 |
rcu_read_unlock(); |
3cf24cf8c mac802154: cfg: a... |
290 291 292 293 |
return; drop: kfree_skb(skb); |
1cd829c83 mac802154: RX dat... |
294 |
} |
1cd829c83 mac802154: RX dat... |
295 296 |
void |
5a5043977 ieee802154: renam... |
297 |
ieee802154_rx_irqsafe(struct ieee802154_hw *hw, struct sk_buff *skb, u8 lqi) |
1cd829c83 mac802154: RX dat... |
298 |
{ |
60741361c mac802154: introd... |
299 |
struct ieee802154_local *local = hw_to_local(hw); |
1cd829c83 mac802154: RX dat... |
300 |
|
c5c47e67b 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 mac802154: RX dat... |
305 306 |
} EXPORT_SYMBOL(ieee802154_rx_irqsafe); |