aboutsummaryrefslogtreecommitdiffstats
path: root/net/ieee802154/6lowpan_rtnl.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ieee802154/6lowpan_rtnl.c')
-rw-r--r--net/ieee802154/6lowpan_rtnl.c127
1 files changed, 86 insertions, 41 deletions
diff --git a/net/ieee802154/6lowpan_rtnl.c b/net/ieee802154/6lowpan_rtnl.c
index 6591d27e53a4..44136297b673 100644
--- a/net/ieee802154/6lowpan_rtnl.c
+++ b/net/ieee802154/6lowpan_rtnl.c
@@ -71,18 +71,33 @@ struct lowpan_dev_record {
71 struct list_head list; 71 struct list_head list;
72}; 72};
73 73
74/* don't save pan id, it's intra pan */
75struct lowpan_addr {
76 u8 mode;
77 union {
78 /* IPv6 needs big endian here */
79 __be64 extended_addr;
80 __be16 short_addr;
81 } u;
82};
83
84struct lowpan_addr_info {
85 struct lowpan_addr daddr;
86 struct lowpan_addr saddr;
87};
88
74static inline struct 89static inline struct
75lowpan_dev_info *lowpan_dev_info(const struct net_device *dev) 90lowpan_dev_info *lowpan_dev_info(const struct net_device *dev)
76{ 91{
77 return netdev_priv(dev); 92 return netdev_priv(dev);
78} 93}
79 94
80static inline void lowpan_address_flip(u8 *src, u8 *dest) 95static inline struct
96lowpan_addr_info *lowpan_skb_priv(const struct sk_buff *skb)
81{ 97{
82 int i; 98 WARN_ON_ONCE(skb_headroom(skb) < sizeof(struct lowpan_addr_info));
83 99 return (struct lowpan_addr_info *)(skb->data -
84 for (i = 0; i < IEEE802154_ADDR_LEN; i++) 100 sizeof(struct lowpan_addr_info));
85 (dest)[IEEE802154_ADDR_LEN - i - 1] = (src)[i];
86} 101}
87 102
88static int lowpan_header_create(struct sk_buff *skb, struct net_device *dev, 103static int lowpan_header_create(struct sk_buff *skb, struct net_device *dev,
@@ -91,8 +106,7 @@ static int lowpan_header_create(struct sk_buff *skb, struct net_device *dev,
91{ 106{
92 const u8 *saddr = _saddr; 107 const u8 *saddr = _saddr;
93 const u8 *daddr = _daddr; 108 const u8 *daddr = _daddr;
94 struct ieee802154_addr sa, da; 109 struct lowpan_addr_info *info;
95 struct ieee802154_mac_cb *cb = mac_cb_init(skb);
96 110
97 /* TODO: 111 /* TODO:
98 * if this package isn't ipv6 one, where should it be routed? 112 * if this package isn't ipv6 one, where should it be routed?
@@ -106,41 +120,17 @@ static int lowpan_header_create(struct sk_buff *skb, struct net_device *dev,
106 raw_dump_inline(__func__, "saddr", (unsigned char *)saddr, 8); 120 raw_dump_inline(__func__, "saddr", (unsigned char *)saddr, 8);
107 raw_dump_inline(__func__, "daddr", (unsigned char *)daddr, 8); 121 raw_dump_inline(__func__, "daddr", (unsigned char *)daddr, 8);
108 122
109 lowpan_header_compress(skb, dev, type, daddr, saddr, len); 123 info = lowpan_skb_priv(skb);
110
111 /* NOTE1: I'm still unsure about the fact that compression and WPAN
112 * header are created here and not later in the xmit. So wait for
113 * an opinion of net maintainers.
114 */
115 /* NOTE2: to be absolutely correct, we must derive PANid information
116 * from MAC subif of the 'dev' and 'real_dev' network devices, but
117 * this isn't implemented in mainline yet, so currently we assign 0xff
118 */
119 cb->type = IEEE802154_FC_TYPE_DATA;
120 124
121 /* prepare wpan address data */ 125 /* TODO: Currently we only support extended_addr */
122 sa.mode = IEEE802154_ADDR_LONG; 126 info->daddr.mode = IEEE802154_ADDR_LONG;
123 sa.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev); 127 memcpy(&info->daddr.u.extended_addr, daddr,
124 sa.extended_addr = ieee802154_devaddr_from_raw(saddr); 128 sizeof(info->daddr.u.extended_addr));
129 info->saddr.mode = IEEE802154_ADDR_LONG;
130 memcpy(&info->saddr.u.extended_addr, saddr,
131 sizeof(info->daddr.u.extended_addr));
125 132
126 /* intra-PAN communications */ 133 return 0;
127 da.pan_id = sa.pan_id;
128
129 /* if the destination address is the broadcast address, use the
130 * corresponding short address
131 */
132 if (lowpan_is_addr_broadcast(daddr)) {
133 da.mode = IEEE802154_ADDR_SHORT;
134 da.short_addr = cpu_to_le16(IEEE802154_ADDR_BROADCAST);
135 } else {
136 da.mode = IEEE802154_ADDR_LONG;
137 da.extended_addr = ieee802154_devaddr_from_raw(daddr);
138 }
139
140 cb->ackreq = !lowpan_is_addr_broadcast(daddr);
141
142 return dev_hard_header(skb, lowpan_dev_info(dev)->real_dev,
143 type, (void *)&da, (void *)&sa, 0);
144} 134}
145 135
146static int lowpan_give_skb_to_devices(struct sk_buff *skb, 136static int lowpan_give_skb_to_devices(struct sk_buff *skb,
@@ -338,13 +328,68 @@ err:
338 return rc; 328 return rc;
339} 329}
340 330
331static int lowpan_header(struct sk_buff *skb, struct net_device *dev)
332{
333 struct ieee802154_addr sa, da;
334 struct ieee802154_mac_cb *cb = mac_cb_init(skb);
335 struct lowpan_addr_info info;
336 void *daddr, *saddr;
337
338 memcpy(&info, lowpan_skb_priv(skb), sizeof(info));
339
340 /* TODO: Currently we only support extended_addr */
341 daddr = &info.daddr.u.extended_addr;
342 saddr = &info.saddr.u.extended_addr;
343
344 lowpan_header_compress(skb, dev, ETH_P_IPV6, daddr, saddr, skb->len);
345
346 cb->type = IEEE802154_FC_TYPE_DATA;
347
348 /* prepare wpan address data */
349 sa.mode = IEEE802154_ADDR_LONG;
350 sa.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev);
351 sa.extended_addr = ieee802154_devaddr_from_raw(saddr);
352
353 /* intra-PAN communications */
354 da.pan_id = sa.pan_id;
355
356 /* if the destination address is the broadcast address, use the
357 * corresponding short address
358 */
359 if (lowpan_is_addr_broadcast((const u8 *)daddr)) {
360 da.mode = IEEE802154_ADDR_SHORT;
361 da.short_addr = cpu_to_le16(IEEE802154_ADDR_BROADCAST);
362 cb->ackreq = false;
363 } else {
364 da.mode = IEEE802154_ADDR_LONG;
365 da.extended_addr = ieee802154_devaddr_from_raw(daddr);
366 cb->ackreq = true;
367 }
368
369 return dev_hard_header(skb, lowpan_dev_info(dev)->real_dev,
370 ETH_P_IPV6, (void *)&da, (void *)&sa, 0);
371}
372
341static netdev_tx_t lowpan_xmit(struct sk_buff *skb, struct net_device *dev) 373static netdev_tx_t lowpan_xmit(struct sk_buff *skb, struct net_device *dev)
342{ 374{
343 struct ieee802154_hdr wpan_hdr; 375 struct ieee802154_hdr wpan_hdr;
344 int max_single; 376 int max_single, ret;
345 377
346 pr_debug("package xmit\n"); 378 pr_debug("package xmit\n");
347 379
380 /* We must take a copy of the skb before we modify/replace the ipv6
381 * header as the header could be used elsewhere
382 */
383 skb = skb_unshare(skb, GFP_ATOMIC);
384 if (!skb)
385 return NET_XMIT_DROP;
386
387 ret = lowpan_header(skb, dev);
388 if (ret < 0) {
389 kfree_skb(skb);
390 return NET_XMIT_DROP;
391 }
392
348 if (ieee802154_hdr_peek(skb, &wpan_hdr) < 0) { 393 if (ieee802154_hdr_peek(skb, &wpan_hdr) < 0) {
349 kfree_skb(skb); 394 kfree_skb(skb);
350 return NET_XMIT_DROP; 395 return NET_XMIT_DROP;