Skip to content

Commit 9509b1c

Browse files
committed
Merge branch 'ieee802154-next'
Phoebe Buckheister says: ==================== 802154: some cleanups and fixes This series adds some definitions for 802.15.4 header fields that were missing, changes 6lowpan fragmentation to be aware of security headers and fixes 802.15.4 datagram socket sendmsg(), which was entirely incompliant to date. Also a few minor changes to mac_cb handling, mark a single-use function static, and correctly check for EMSGSIZE conditions during wpan_header_create. Changes since v1: * rename mac_cb_alloc to mac_cb_init * catch all error cases of sendmsg() instead of only !conn && msg_name * redo 6lowpan fragmentation to not clone lower layer headers ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents 9dbccc3 + 6ef0023 commit 9509b1c

File tree

7 files changed

+236
-156
lines changed

7 files changed

+236
-156
lines changed

include/net/ieee802154.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,15 @@
7979
#define IEEE802154_SCF_KEY_SHORT_INDEX 2
8080
#define IEEE802154_SCF_KEY_HW_INDEX 3
8181

82+
#define IEEE802154_SCF_SECLEVEL_NONE 0
83+
#define IEEE802154_SCF_SECLEVEL_MIC32 1
84+
#define IEEE802154_SCF_SECLEVEL_MIC64 2
85+
#define IEEE802154_SCF_SECLEVEL_MIC128 3
86+
#define IEEE802154_SCF_SECLEVEL_ENC 4
87+
#define IEEE802154_SCF_SECLEVEL_ENC_MIC32 5
88+
#define IEEE802154_SCF_SECLEVEL_ENC_MIC64 6
89+
#define IEEE802154_SCF_SECLEVEL_ENC_MIC128 7
90+
8291
/* MAC footer size */
8392
#define IEEE802154_MFR_SIZE 2 /* 2 octets */
8493

include/net/ieee802154_netdev.h

Lines changed: 36 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#ifndef IEEE802154_NETDEVICE_H
2828
#define IEEE802154_NETDEVICE_H
2929

30+
#include <net/ieee802154.h>
3031
#include <net/af_ieee802154.h>
3132
#include <linux/netdevice.h>
3233
#include <linux/skbuff.h>
@@ -114,6 +115,34 @@ int ieee802154_hdr_pull(struct sk_buff *skb, struct ieee802154_hdr *hdr);
114115
int ieee802154_hdr_peek_addrs(const struct sk_buff *skb,
115116
struct ieee802154_hdr *hdr);
116117

118+
/* parses the full 802.15.4 header a given skb and stores them into hdr,
119+
* performing pan id decompression and length checks to be suitable for use in
120+
* header_ops.parse
121+
*/
122+
int ieee802154_hdr_peek(const struct sk_buff *skb, struct ieee802154_hdr *hdr);
123+
124+
int ieee802154_max_payload(const struct ieee802154_hdr *hdr);
125+
126+
static inline int
127+
ieee802154_sechdr_authtag_len(const struct ieee802154_sechdr *sec)
128+
{
129+
switch (sec->level) {
130+
case IEEE802154_SCF_SECLEVEL_MIC32:
131+
case IEEE802154_SCF_SECLEVEL_ENC_MIC32:
132+
return 4;
133+
case IEEE802154_SCF_SECLEVEL_MIC64:
134+
case IEEE802154_SCF_SECLEVEL_ENC_MIC64:
135+
return 8;
136+
case IEEE802154_SCF_SECLEVEL_MIC128:
137+
case IEEE802154_SCF_SECLEVEL_ENC_MIC128:
138+
return 16;
139+
case IEEE802154_SCF_SECLEVEL_NONE:
140+
case IEEE802154_SCF_SECLEVEL_ENC:
141+
default:
142+
return 0;
143+
}
144+
}
145+
117146
static inline int ieee802154_hdr_length(struct sk_buff *skb)
118147
{
119148
struct ieee802154_hdr hdr;
@@ -193,8 +222,9 @@ static inline void ieee802154_addr_to_sa(struct ieee802154_addr_sa *sa,
193222
*/
194223
struct ieee802154_mac_cb {
195224
u8 lqi;
196-
u8 flags;
197-
u8 seq;
225+
u8 type;
226+
bool ackreq;
227+
bool secen;
198228
struct ieee802154_addr source;
199229
struct ieee802154_addr dest;
200230
};
@@ -204,24 +234,12 @@ static inline struct ieee802154_mac_cb *mac_cb(struct sk_buff *skb)
204234
return (struct ieee802154_mac_cb *)skb->cb;
205235
}
206236

207-
#define MAC_CB_FLAG_TYPEMASK ((1 << 3) - 1)
208-
209-
#define MAC_CB_FLAG_ACKREQ (1 << 3)
210-
#define MAC_CB_FLAG_SECEN (1 << 4)
211-
212-
static inline bool mac_cb_is_ackreq(struct sk_buff *skb)
237+
static inline struct ieee802154_mac_cb *mac_cb_init(struct sk_buff *skb)
213238
{
214-
return mac_cb(skb)->flags & MAC_CB_FLAG_ACKREQ;
215-
}
239+
BUILD_BUG_ON(sizeof(struct ieee802154_mac_cb) > sizeof(skb->cb));
216240

217-
static inline bool mac_cb_is_secen(struct sk_buff *skb)
218-
{
219-
return mac_cb(skb)->flags & MAC_CB_FLAG_SECEN;
220-
}
221-
222-
static inline int mac_cb_type(struct sk_buff *skb)
223-
{
224-
return mac_cb(skb)->flags & MAC_CB_FLAG_TYPEMASK;
241+
memset(skb->cb, 0, sizeof(struct ieee802154_mac_cb));
242+
return mac_cb(skb);
225243
}
226244

227245
#define IEEE802154_MAC_SCAN_ED 0

net/ieee802154/6lowpan_rtnl.c

Lines changed: 108 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ static int lowpan_header_create(struct sk_buff *skb,
9292
const u8 *saddr = _saddr;
9393
const u8 *daddr = _daddr;
9494
struct ieee802154_addr sa, da;
95+
struct ieee802154_mac_cb *cb = mac_cb_init(skb);
9596

9697
/* TODO:
9798
* if this package isn't ipv6 one, where should it be routed?
@@ -115,8 +116,7 @@ static int lowpan_header_create(struct sk_buff *skb,
115116
* from MAC subif of the 'dev' and 'real_dev' network devices, but
116117
* this isn't implemented in mainline yet, so currently we assign 0xff
117118
*/
118-
mac_cb(skb)->flags = IEEE802154_FC_TYPE_DATA;
119-
mac_cb(skb)->seq = ieee802154_mlme_ops(dev)->get_dsn(dev);
119+
cb->type = IEEE802154_FC_TYPE_DATA;
120120

121121
/* prepare wpan address data */
122122
sa.mode = IEEE802154_ADDR_LONG;
@@ -135,11 +135,10 @@ static int lowpan_header_create(struct sk_buff *skb,
135135
} else {
136136
da.mode = IEEE802154_ADDR_LONG;
137137
da.extended_addr = ieee802154_devaddr_from_raw(daddr);
138-
139-
/* request acknowledgment */
140-
mac_cb(skb)->flags |= MAC_CB_FLAG_ACKREQ;
141138
}
142139

140+
cb->ackreq = !lowpan_is_addr_broadcast(daddr);
141+
143142
return dev_hard_header(skb, lowpan_dev_info(dev)->real_dev,
144143
type, (void *)&da, (void *)&sa, 0);
145144
}
@@ -221,139 +220,149 @@ static int lowpan_set_address(struct net_device *dev, void *p)
221220
return 0;
222221
}
223222

224-
static int
225-
lowpan_fragment_xmit(struct sk_buff *skb, u8 *head,
226-
int mlen, int plen, int offset, int type)
223+
static struct sk_buff*
224+
lowpan_alloc_frag(struct sk_buff *skb, int size,
225+
const struct ieee802154_hdr *master_hdr)
227226
{
227+
struct net_device *real_dev = lowpan_dev_info(skb->dev)->real_dev;
228228
struct sk_buff *frag;
229-
int hlen;
230-
231-
hlen = (type == LOWPAN_DISPATCH_FRAG1) ?
232-
LOWPAN_FRAG1_HEAD_SIZE : LOWPAN_FRAGN_HEAD_SIZE;
233-
234-
raw_dump_inline(__func__, "6lowpan fragment header", head, hlen);
229+
int rc;
230+
231+
frag = alloc_skb(real_dev->hard_header_len +
232+
real_dev->needed_tailroom + size,
233+
GFP_ATOMIC);
234+
235+
if (likely(frag)) {
236+
frag->dev = real_dev;
237+
frag->priority = skb->priority;
238+
skb_reserve(frag, real_dev->hard_header_len);
239+
skb_reset_network_header(frag);
240+
*mac_cb(frag) = *mac_cb(skb);
241+
242+
rc = dev_hard_header(frag, real_dev, 0, &master_hdr->dest,
243+
&master_hdr->source, size);
244+
if (rc < 0) {
245+
kfree_skb(frag);
246+
return ERR_PTR(-rc);
247+
}
248+
} else {
249+
frag = ERR_PTR(ENOMEM);
250+
}
235251

236-
frag = netdev_alloc_skb(skb->dev,
237-
hlen + mlen + plen + IEEE802154_MFR_SIZE);
238-
if (!frag)
239-
return -ENOMEM;
252+
return frag;
253+
}
240254

241-
frag->priority = skb->priority;
255+
static int
256+
lowpan_xmit_fragment(struct sk_buff *skb, const struct ieee802154_hdr *wpan_hdr,
257+
u8 *frag_hdr, int frag_hdrlen,
258+
int offset, int len)
259+
{
260+
struct sk_buff *frag;
242261

243-
/* copy header, MFR and payload */
244-
skb_put(frag, mlen);
245-
skb_copy_to_linear_data(frag, skb_mac_header(skb), mlen);
262+
raw_dump_inline(__func__, " fragment header", frag_hdr, frag_hdrlen);
246263

247-
skb_put(frag, hlen);
248-
skb_copy_to_linear_data_offset(frag, mlen, head, hlen);
264+
frag = lowpan_alloc_frag(skb, frag_hdrlen + len, wpan_hdr);
265+
if (IS_ERR(frag))
266+
return -PTR_ERR(frag);
249267

250-
skb_put(frag, plen);
251-
skb_copy_to_linear_data_offset(frag, mlen + hlen,
252-
skb_network_header(skb) + offset, plen);
268+
memcpy(skb_put(frag, frag_hdrlen), frag_hdr, frag_hdrlen);
269+
memcpy(skb_put(frag, len), skb_network_header(skb) + offset, len);
253270

254-
raw_dump_table(__func__, " raw fragment dump", frag->data, frag->len);
271+
raw_dump_table(__func__, " fragment dump", frag->data, frag->len);
255272

256273
return dev_queue_xmit(frag);
257274
}
258275

259276
static int
260-
lowpan_skb_fragmentation(struct sk_buff *skb, struct net_device *dev)
277+
lowpan_xmit_fragmented(struct sk_buff *skb, struct net_device *dev,
278+
const struct ieee802154_hdr *wpan_hdr)
261279
{
262-
int err;
263-
u16 dgram_offset, dgram_size, payload_length, header_length,
264-
lowpan_size, frag_plen, offset;
265-
__be16 tag;
266-
u8 head[5];
267-
268-
header_length = skb->mac_len;
269-
payload_length = skb->len - header_length;
270-
tag = lowpan_dev_info(dev)->fragment_tag++;
271-
lowpan_size = skb_network_header_len(skb);
280+
u16 dgram_size, dgram_offset;
281+
__be16 frag_tag;
282+
u8 frag_hdr[5];
283+
int frag_cap, frag_len, payload_cap, rc;
284+
int skb_unprocessed, skb_offset;
285+
272286
dgram_size = lowpan_uncompress_size(skb, &dgram_offset) -
273-
header_length;
287+
skb->mac_len;
288+
frag_tag = lowpan_dev_info(dev)->fragment_tag++;
274289

275-
/* first fragment header */
276-
head[0] = LOWPAN_DISPATCH_FRAG1 | ((dgram_size >> 8) & 0x7);
277-
head[1] = dgram_size & 0xff;
278-
memcpy(head + 2, &tag, sizeof(tag));
290+
frag_hdr[0] = LOWPAN_DISPATCH_FRAG1 | ((dgram_size >> 8) & 0x07);
291+
frag_hdr[1] = dgram_size & 0xff;
292+
memcpy(frag_hdr + 2, &frag_tag, sizeof(frag_tag));
279293

280-
/* calc the nearest payload length(divided to 8) for first fragment
281-
* which fits into a IEEE802154_MTU
282-
*/
283-
frag_plen = round_down(IEEE802154_MTU - header_length -
284-
LOWPAN_FRAG1_HEAD_SIZE - lowpan_size -
285-
IEEE802154_MFR_SIZE, 8);
286-
287-
err = lowpan_fragment_xmit(skb, head, header_length,
288-
frag_plen + lowpan_size, 0,
289-
LOWPAN_DISPATCH_FRAG1);
290-
if (err) {
291-
pr_debug("%s unable to send FRAG1 packet (tag: %d)",
292-
__func__, tag);
293-
goto exit;
294-
}
294+
payload_cap = ieee802154_max_payload(wpan_hdr);
295295

296-
offset = lowpan_size + frag_plen;
297-
dgram_offset += frag_plen;
296+
frag_len = round_down(payload_cap - LOWPAN_FRAG1_HEAD_SIZE -
297+
skb_network_header_len(skb), 8);
298298

299-
/* next fragment header */
300-
head[0] &= ~LOWPAN_DISPATCH_FRAG1;
301-
head[0] |= LOWPAN_DISPATCH_FRAGN;
299+
skb_offset = skb_network_header_len(skb);
300+
skb_unprocessed = skb->len - skb->mac_len - skb_offset;
302301

303-
frag_plen = round_down(IEEE802154_MTU - header_length -
304-
LOWPAN_FRAGN_HEAD_SIZE - IEEE802154_MFR_SIZE, 8);
302+
rc = lowpan_xmit_fragment(skb, wpan_hdr, frag_hdr,
303+
LOWPAN_FRAG1_HEAD_SIZE, 0,
304+
frag_len + skb_network_header_len(skb));
305+
if (rc) {
306+
pr_debug("%s unable to send FRAG1 packet (tag: %d)",
307+
__func__, frag_tag);
308+
goto err;
309+
}
305310

306-
while (payload_length - offset > 0) {
307-
int len = frag_plen;
311+
frag_hdr[0] &= ~LOWPAN_DISPATCH_FRAG1;
312+
frag_hdr[0] |= LOWPAN_DISPATCH_FRAGN;
313+
frag_cap = round_down(payload_cap - LOWPAN_FRAGN_HEAD_SIZE, 8);
308314

309-
head[4] = dgram_offset >> 3;
315+
while (skb_unprocessed >= frag_cap) {
316+
dgram_offset += frag_len;
317+
skb_offset += frag_len;
318+
skb_unprocessed -= frag_len;
319+
frag_len = min(frag_cap, skb_unprocessed);
310320

311-
if (payload_length - offset < len)
312-
len = payload_length - offset;
321+
frag_hdr[4] = dgram_offset >> 3;
313322

314-
err = lowpan_fragment_xmit(skb, head, header_length, len,
315-
offset, LOWPAN_DISPATCH_FRAGN);
316-
if (err) {
323+
rc = lowpan_xmit_fragment(skb, wpan_hdr, frag_hdr,
324+
LOWPAN_FRAGN_HEAD_SIZE, skb_offset,
325+
frag_len);
326+
if (rc) {
317327
pr_debug("%s unable to send a FRAGN packet. (tag: %d, offset: %d)\n",
318-
__func__, tag, offset);
319-
goto exit;
328+
__func__, frag_tag, skb_offset);
329+
goto err;
320330
}
321-
322-
offset += len;
323-
dgram_offset += len;
324331
}
325332

326-
exit:
327-
return err;
333+
consume_skb(skb);
334+
return NET_XMIT_SUCCESS;
335+
336+
err:
337+
kfree_skb(skb);
338+
return rc;
328339
}
329340

330341
static netdev_tx_t lowpan_xmit(struct sk_buff *skb, struct net_device *dev)
331342
{
332-
int err = -1;
343+
struct ieee802154_hdr wpan_hdr;
344+
int max_single;
333345

334346
pr_debug("package xmit\n");
335347

336-
skb->dev = lowpan_dev_info(dev)->real_dev;
337-
if (skb->dev == NULL) {
338-
pr_debug("ERROR: no real wpan device found\n");
339-
goto error;
348+
if (ieee802154_hdr_peek(skb, &wpan_hdr) < 0) {
349+
kfree_skb(skb);
350+
return NET_XMIT_DROP;
340351
}
341352

342-
/* Send directly if less than the MTU minus the 2 checksum bytes. */
343-
if (skb->len <= IEEE802154_MTU - IEEE802154_MFR_SIZE) {
344-
err = dev_queue_xmit(skb);
345-
goto out;
346-
}
353+
max_single = ieee802154_max_payload(&wpan_hdr);
347354

348-
pr_debug("frame is too big, fragmentation is needed\n");
349-
err = lowpan_skb_fragmentation(skb, dev);
350-
error:
351-
dev_kfree_skb(skb);
352-
out:
353-
if (err)
354-
pr_debug("ERROR: xmit failed\n");
355+
if (skb_tail_pointer(skb) - skb_network_header(skb) <= max_single) {
356+
skb->dev = lowpan_dev_info(dev)->real_dev;
357+
return dev_queue_xmit(skb);
358+
} else {
359+
netdev_tx_t rc;
360+
361+
pr_debug("frame is too big, fragmentation is needed\n");
362+
rc = lowpan_xmit_fragmented(skb, dev, &wpan_hdr);
355363

356-
return (err < 0) ? NET_XMIT_DROP : err;
364+
return rc < 0 ? NET_XMIT_DROP : rc;
365+
}
357366
}
358367

359368
static struct wpan_phy *lowpan_get_phy(const struct net_device *dev)

0 commit comments

Comments
 (0)