ieee802154: 6lowpan: move receive functionality
This patch moves all relevant receive functionality into a separate rx.c file. We can simple separate this functionality like we did it in mac802154. Signed-off-by: Alexander Aring <alex.aring@gmail.com> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
This commit is contained in:
parent
8691ee592c
commit
4662a0da54
|
@ -1,6 +1,8 @@
|
||||||
#ifndef __IEEE802154_6LOWPAN_I_H__
|
#ifndef __IEEE802154_6LOWPAN_I_H__
|
||||||
#define __IEEE802154_6LOWPAN_I_H__
|
#define __IEEE802154_6LOWPAN_I_H__
|
||||||
|
|
||||||
|
#include <linux/list.h>
|
||||||
|
|
||||||
#include <net/inet_frag.h>
|
#include <net/inet_frag.h>
|
||||||
|
|
||||||
struct lowpan_create_arg {
|
struct lowpan_create_arg {
|
||||||
|
@ -34,8 +36,31 @@ static inline u32 ieee802154_addr_hash(const struct ieee802154_addr *a)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct lowpan_dev_record {
|
||||||
|
struct net_device *ldev;
|
||||||
|
struct list_head list;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* private device info */
|
||||||
|
struct lowpan_dev_info {
|
||||||
|
struct net_device *real_dev; /* real WPAN device ptr */
|
||||||
|
struct mutex dev_list_mtx; /* mutex for list ops */
|
||||||
|
u16 fragment_tag;
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline struct
|
||||||
|
lowpan_dev_info *lowpan_dev_info(const struct net_device *dev)
|
||||||
|
{
|
||||||
|
return netdev_priv(dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern struct list_head lowpan_devices;
|
||||||
|
|
||||||
int lowpan_frag_rcv(struct sk_buff *skb, const u8 frag_type);
|
int lowpan_frag_rcv(struct sk_buff *skb, const u8 frag_type);
|
||||||
void lowpan_net_frag_exit(void);
|
void lowpan_net_frag_exit(void);
|
||||||
int lowpan_net_frag_init(void);
|
int lowpan_net_frag_init(void);
|
||||||
|
|
||||||
|
void lowpan_rx_init(void);
|
||||||
|
void lowpan_rx_exit(void);
|
||||||
|
|
||||||
#endif /* __IEEE802154_6LOWPAN_I_H__ */
|
#endif /* __IEEE802154_6LOWPAN_I_H__ */
|
||||||
|
|
|
@ -57,21 +57,9 @@
|
||||||
|
|
||||||
#include "6lowpan_i.h"
|
#include "6lowpan_i.h"
|
||||||
|
|
||||||
static LIST_HEAD(lowpan_devices);
|
LIST_HEAD(lowpan_devices);
|
||||||
static int lowpan_open_count;
|
static int lowpan_open_count;
|
||||||
|
|
||||||
/* private device info */
|
|
||||||
struct lowpan_dev_info {
|
|
||||||
struct net_device *real_dev; /* real WPAN device ptr */
|
|
||||||
struct mutex dev_list_mtx; /* mutex for list ops */
|
|
||||||
u16 fragment_tag;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct lowpan_dev_record {
|
|
||||||
struct net_device *ldev;
|
|
||||||
struct list_head list;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* don't save pan id, it's intra pan */
|
/* don't save pan id, it's intra pan */
|
||||||
struct lowpan_addr {
|
struct lowpan_addr {
|
||||||
u8 mode;
|
u8 mode;
|
||||||
|
@ -87,12 +75,6 @@ struct lowpan_addr_info {
|
||||||
struct lowpan_addr saddr;
|
struct lowpan_addr saddr;
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline struct
|
|
||||||
lowpan_dev_info *lowpan_dev_info(const struct net_device *dev)
|
|
||||||
{
|
|
||||||
return netdev_priv(dev);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline struct
|
static inline struct
|
||||||
lowpan_addr_info *lowpan_skb_priv(const struct sk_buff *skb)
|
lowpan_addr_info *lowpan_skb_priv(const struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
|
@ -134,74 +116,6 @@ static int lowpan_header_create(struct sk_buff *skb, struct net_device *dev,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int lowpan_give_skb_to_devices(struct sk_buff *skb,
|
|
||||||
struct net_device *dev)
|
|
||||||
{
|
|
||||||
struct lowpan_dev_record *entry;
|
|
||||||
struct sk_buff *skb_cp;
|
|
||||||
int stat = NET_RX_SUCCESS;
|
|
||||||
|
|
||||||
skb->protocol = htons(ETH_P_IPV6);
|
|
||||||
skb->pkt_type = PACKET_HOST;
|
|
||||||
|
|
||||||
rcu_read_lock();
|
|
||||||
list_for_each_entry_rcu(entry, &lowpan_devices, list)
|
|
||||||
if (lowpan_dev_info(entry->ldev)->real_dev == skb->dev) {
|
|
||||||
skb_cp = skb_copy(skb, GFP_ATOMIC);
|
|
||||||
if (!skb_cp) {
|
|
||||||
kfree_skb(skb);
|
|
||||||
rcu_read_unlock();
|
|
||||||
return NET_RX_DROP;
|
|
||||||
}
|
|
||||||
|
|
||||||
skb_cp->dev = entry->ldev;
|
|
||||||
stat = netif_rx(skb_cp);
|
|
||||||
if (stat == NET_RX_DROP)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
rcu_read_unlock();
|
|
||||||
|
|
||||||
consume_skb(skb);
|
|
||||||
|
|
||||||
return stat;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
iphc_decompress(struct sk_buff *skb, const struct ieee802154_hdr *hdr)
|
|
||||||
{
|
|
||||||
u8 iphc0, iphc1;
|
|
||||||
struct ieee802154_addr_sa sa, da;
|
|
||||||
void *sap, *dap;
|
|
||||||
|
|
||||||
raw_dump_table(__func__, "raw skb data dump", skb->data, skb->len);
|
|
||||||
/* at least two bytes will be used for the encoding */
|
|
||||||
if (skb->len < 2)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
if (lowpan_fetch_skb_u8(skb, &iphc0))
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
if (lowpan_fetch_skb_u8(skb, &iphc1))
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
ieee802154_addr_to_sa(&sa, &hdr->source);
|
|
||||||
ieee802154_addr_to_sa(&da, &hdr->dest);
|
|
||||||
|
|
||||||
if (sa.addr_type == IEEE802154_ADDR_SHORT)
|
|
||||||
sap = &sa.short_addr;
|
|
||||||
else
|
|
||||||
sap = &sa.hwaddr;
|
|
||||||
|
|
||||||
if (da.addr_type == IEEE802154_ADDR_SHORT)
|
|
||||||
dap = &da.short_addr;
|
|
||||||
else
|
|
||||||
dap = &da.hwaddr;
|
|
||||||
|
|
||||||
return lowpan_header_decompress(skb, skb->dev, sap, sa.addr_type,
|
|
||||||
IEEE802154_ADDR_LEN, dap, da.addr_type,
|
|
||||||
IEEE802154_ADDR_LEN, iphc0, iphc1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct sk_buff*
|
static struct sk_buff*
|
||||||
lowpan_alloc_frag(struct sk_buff *skb, int size,
|
lowpan_alloc_frag(struct sk_buff *skb, int size,
|
||||||
const struct ieee802154_hdr *master_hdr)
|
const struct ieee802154_hdr *master_hdr)
|
||||||
|
@ -485,83 +399,6 @@ static int lowpan_validate(struct nlattr *tb[], struct nlattr *data[])
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int lowpan_rcv(struct sk_buff *skb, struct net_device *dev,
|
|
||||||
struct packet_type *pt, struct net_device *orig_dev)
|
|
||||||
{
|
|
||||||
struct ieee802154_hdr hdr;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
skb = skb_share_check(skb, GFP_ATOMIC);
|
|
||||||
if (!skb)
|
|
||||||
goto drop;
|
|
||||||
|
|
||||||
if (!netif_running(dev))
|
|
||||||
goto drop_skb;
|
|
||||||
|
|
||||||
if (skb->pkt_type == PACKET_OTHERHOST)
|
|
||||||
goto drop_skb;
|
|
||||||
|
|
||||||
if (dev->type != ARPHRD_IEEE802154)
|
|
||||||
goto drop_skb;
|
|
||||||
|
|
||||||
if (ieee802154_hdr_peek_addrs(skb, &hdr) < 0)
|
|
||||||
goto drop_skb;
|
|
||||||
|
|
||||||
/* check that it's our buffer */
|
|
||||||
if (skb->data[0] == LOWPAN_DISPATCH_IPV6) {
|
|
||||||
/* Pull off the 1-byte of 6lowpan header. */
|
|
||||||
skb_pull(skb, 1);
|
|
||||||
return lowpan_give_skb_to_devices(skb, NULL);
|
|
||||||
} else {
|
|
||||||
switch (skb->data[0] & 0xe0) {
|
|
||||||
case LOWPAN_DISPATCH_IPHC: /* ipv6 datagram */
|
|
||||||
ret = iphc_decompress(skb, &hdr);
|
|
||||||
if (ret < 0)
|
|
||||||
goto drop_skb;
|
|
||||||
|
|
||||||
return lowpan_give_skb_to_devices(skb, NULL);
|
|
||||||
case LOWPAN_DISPATCH_FRAG1: /* first fragment header */
|
|
||||||
ret = lowpan_frag_rcv(skb, LOWPAN_DISPATCH_FRAG1);
|
|
||||||
if (ret == 1) {
|
|
||||||
ret = iphc_decompress(skb, &hdr);
|
|
||||||
if (ret < 0)
|
|
||||||
goto drop_skb;
|
|
||||||
|
|
||||||
return lowpan_give_skb_to_devices(skb, NULL);
|
|
||||||
} else if (ret == -1) {
|
|
||||||
return NET_RX_DROP;
|
|
||||||
} else {
|
|
||||||
return NET_RX_SUCCESS;
|
|
||||||
}
|
|
||||||
case LOWPAN_DISPATCH_FRAGN: /* next fragments headers */
|
|
||||||
ret = lowpan_frag_rcv(skb, LOWPAN_DISPATCH_FRAGN);
|
|
||||||
if (ret == 1) {
|
|
||||||
ret = iphc_decompress(skb, &hdr);
|
|
||||||
if (ret < 0)
|
|
||||||
goto drop_skb;
|
|
||||||
|
|
||||||
return lowpan_give_skb_to_devices(skb, NULL);
|
|
||||||
} else if (ret == -1) {
|
|
||||||
return NET_RX_DROP;
|
|
||||||
} else {
|
|
||||||
return NET_RX_SUCCESS;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
drop_skb:
|
|
||||||
kfree_skb(skb);
|
|
||||||
drop:
|
|
||||||
return NET_RX_DROP;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct packet_type lowpan_packet_type = {
|
|
||||||
.type = htons(ETH_P_IEEE802154),
|
|
||||||
.func = lowpan_rcv,
|
|
||||||
};
|
|
||||||
|
|
||||||
static int lowpan_newlink(struct net *src_net, struct net_device *dev,
|
static int lowpan_newlink(struct net *src_net, struct net_device *dev,
|
||||||
struct nlattr *tb[], struct nlattr *data[])
|
struct nlattr *tb[], struct nlattr *data[])
|
||||||
{
|
{
|
||||||
|
@ -607,7 +444,7 @@ static int lowpan_newlink(struct net *src_net, struct net_device *dev,
|
||||||
ret = register_netdevice(dev);
|
ret = register_netdevice(dev);
|
||||||
if (ret >= 0) {
|
if (ret >= 0) {
|
||||||
if (!lowpan_open_count)
|
if (!lowpan_open_count)
|
||||||
dev_add_pack(&lowpan_packet_type);
|
lowpan_rx_init();
|
||||||
lowpan_open_count++;
|
lowpan_open_count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -624,7 +461,7 @@ static void lowpan_dellink(struct net_device *dev, struct list_head *head)
|
||||||
|
|
||||||
lowpan_open_count--;
|
lowpan_open_count--;
|
||||||
if (!lowpan_open_count)
|
if (!lowpan_open_count)
|
||||||
dev_remove_pack(&lowpan_packet_type);
|
lowpan_rx_exit();
|
||||||
|
|
||||||
mutex_lock(&lowpan_dev_info(dev)->dev_list_mtx);
|
mutex_lock(&lowpan_dev_info(dev)->dev_list_mtx);
|
||||||
list_for_each_entry_safe(entry, tmp, &lowpan_devices, list) {
|
list_for_each_entry_safe(entry, tmp, &lowpan_devices, list) {
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
obj-y += ieee802154_6lowpan.o
|
obj-y += ieee802154_6lowpan.o
|
||||||
|
|
||||||
ieee802154_6lowpan-y := 6lowpan_rtnl.o reassembly.o
|
ieee802154_6lowpan-y := 6lowpan_rtnl.o rx.o reassembly.o
|
||||||
|
|
|
@ -0,0 +1,171 @@
|
||||||
|
/* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/if_arp.h>
|
||||||
|
|
||||||
|
#include <net/6lowpan.h>
|
||||||
|
#include <net/ieee802154_netdev.h>
|
||||||
|
|
||||||
|
#include "6lowpan_i.h"
|
||||||
|
|
||||||
|
static int lowpan_give_skb_to_devices(struct sk_buff *skb,
|
||||||
|
struct net_device *dev)
|
||||||
|
{
|
||||||
|
struct lowpan_dev_record *entry;
|
||||||
|
struct sk_buff *skb_cp;
|
||||||
|
int stat = NET_RX_SUCCESS;
|
||||||
|
|
||||||
|
skb->protocol = htons(ETH_P_IPV6);
|
||||||
|
skb->pkt_type = PACKET_HOST;
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
|
list_for_each_entry_rcu(entry, &lowpan_devices, list)
|
||||||
|
if (lowpan_dev_info(entry->ldev)->real_dev == skb->dev) {
|
||||||
|
skb_cp = skb_copy(skb, GFP_ATOMIC);
|
||||||
|
if (!skb_cp) {
|
||||||
|
kfree_skb(skb);
|
||||||
|
rcu_read_unlock();
|
||||||
|
return NET_RX_DROP;
|
||||||
|
}
|
||||||
|
|
||||||
|
skb_cp->dev = entry->ldev;
|
||||||
|
stat = netif_rx(skb_cp);
|
||||||
|
if (stat == NET_RX_DROP)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
rcu_read_unlock();
|
||||||
|
|
||||||
|
consume_skb(skb);
|
||||||
|
|
||||||
|
return stat;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
iphc_decompress(struct sk_buff *skb, const struct ieee802154_hdr *hdr)
|
||||||
|
{
|
||||||
|
u8 iphc0, iphc1;
|
||||||
|
struct ieee802154_addr_sa sa, da;
|
||||||
|
void *sap, *dap;
|
||||||
|
|
||||||
|
raw_dump_table(__func__, "raw skb data dump", skb->data, skb->len);
|
||||||
|
/* at least two bytes will be used for the encoding */
|
||||||
|
if (skb->len < 2)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (lowpan_fetch_skb_u8(skb, &iphc0))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (lowpan_fetch_skb_u8(skb, &iphc1))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
ieee802154_addr_to_sa(&sa, &hdr->source);
|
||||||
|
ieee802154_addr_to_sa(&da, &hdr->dest);
|
||||||
|
|
||||||
|
if (sa.addr_type == IEEE802154_ADDR_SHORT)
|
||||||
|
sap = &sa.short_addr;
|
||||||
|
else
|
||||||
|
sap = &sa.hwaddr;
|
||||||
|
|
||||||
|
if (da.addr_type == IEEE802154_ADDR_SHORT)
|
||||||
|
dap = &da.short_addr;
|
||||||
|
else
|
||||||
|
dap = &da.hwaddr;
|
||||||
|
|
||||||
|
return lowpan_header_decompress(skb, skb->dev, sap, sa.addr_type,
|
||||||
|
IEEE802154_ADDR_LEN, dap, da.addr_type,
|
||||||
|
IEEE802154_ADDR_LEN, iphc0, iphc1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int lowpan_rcv(struct sk_buff *skb, struct net_device *dev,
|
||||||
|
struct packet_type *pt, struct net_device *orig_dev)
|
||||||
|
{
|
||||||
|
struct ieee802154_hdr hdr;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
skb = skb_share_check(skb, GFP_ATOMIC);
|
||||||
|
if (!skb)
|
||||||
|
goto drop;
|
||||||
|
|
||||||
|
if (!netif_running(dev))
|
||||||
|
goto drop_skb;
|
||||||
|
|
||||||
|
if (skb->pkt_type == PACKET_OTHERHOST)
|
||||||
|
goto drop_skb;
|
||||||
|
|
||||||
|
if (dev->type != ARPHRD_IEEE802154)
|
||||||
|
goto drop_skb;
|
||||||
|
|
||||||
|
if (ieee802154_hdr_peek_addrs(skb, &hdr) < 0)
|
||||||
|
goto drop_skb;
|
||||||
|
|
||||||
|
/* check that it's our buffer */
|
||||||
|
if (skb->data[0] == LOWPAN_DISPATCH_IPV6) {
|
||||||
|
/* Pull off the 1-byte of 6lowpan header. */
|
||||||
|
skb_pull(skb, 1);
|
||||||
|
return lowpan_give_skb_to_devices(skb, NULL);
|
||||||
|
} else {
|
||||||
|
switch (skb->data[0] & 0xe0) {
|
||||||
|
case LOWPAN_DISPATCH_IPHC: /* ipv6 datagram */
|
||||||
|
ret = iphc_decompress(skb, &hdr);
|
||||||
|
if (ret < 0)
|
||||||
|
goto drop_skb;
|
||||||
|
|
||||||
|
return lowpan_give_skb_to_devices(skb, NULL);
|
||||||
|
case LOWPAN_DISPATCH_FRAG1: /* first fragment header */
|
||||||
|
ret = lowpan_frag_rcv(skb, LOWPAN_DISPATCH_FRAG1);
|
||||||
|
if (ret == 1) {
|
||||||
|
ret = iphc_decompress(skb, &hdr);
|
||||||
|
if (ret < 0)
|
||||||
|
goto drop_skb;
|
||||||
|
|
||||||
|
return lowpan_give_skb_to_devices(skb, NULL);
|
||||||
|
} else if (ret == -1) {
|
||||||
|
return NET_RX_DROP;
|
||||||
|
} else {
|
||||||
|
return NET_RX_SUCCESS;
|
||||||
|
}
|
||||||
|
case LOWPAN_DISPATCH_FRAGN: /* next fragments headers */
|
||||||
|
ret = lowpan_frag_rcv(skb, LOWPAN_DISPATCH_FRAGN);
|
||||||
|
if (ret == 1) {
|
||||||
|
ret = iphc_decompress(skb, &hdr);
|
||||||
|
if (ret < 0)
|
||||||
|
goto drop_skb;
|
||||||
|
|
||||||
|
return lowpan_give_skb_to_devices(skb, NULL);
|
||||||
|
} else if (ret == -1) {
|
||||||
|
return NET_RX_DROP;
|
||||||
|
} else {
|
||||||
|
return NET_RX_SUCCESS;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
drop_skb:
|
||||||
|
kfree_skb(skb);
|
||||||
|
drop:
|
||||||
|
return NET_RX_DROP;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct packet_type lowpan_packet_type = {
|
||||||
|
.type = htons(ETH_P_IEEE802154),
|
||||||
|
.func = lowpan_rcv,
|
||||||
|
};
|
||||||
|
|
||||||
|
void lowpan_rx_init(void)
|
||||||
|
{
|
||||||
|
dev_add_pack(&lowpan_packet_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
void lowpan_rx_exit(void)
|
||||||
|
{
|
||||||
|
dev_remove_pack(&lowpan_packet_type);
|
||||||
|
}
|
Loading…
Reference in New Issue