Merge branch 'ieee802154-next'

Phoebe Buckheister says:

====================
ieee802154: fix endianness and header handling

This patch set enforces network byte order on all internal operations and
fields of the 802.15.4 stack and adds a general representation of 802.15.4
headers with operations to create and parse those headers. This reduces code
duplication in the current stack and also allows for upper layers to read
headers of packets they have just received; it is also necessary for 802.15.4
link layer security, which requires header mangling.

Changes since v1:
 * fixed lowpan packet rx after reassembly. Control blocks were used to
   retrieve source/dest addresses, but the CB is clobbered by reassembly.
   Instead, parse the header anew in lowpan.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
David S. Miller 2014-03-14 22:15:35 -04:00
commit 983f59617a
24 changed files with 842 additions and 483 deletions

View File

@ -745,30 +745,31 @@ at86rf230_set_hw_addr_filt(struct ieee802154_dev *dev,
struct at86rf230_local *lp = dev->priv;
if (changed & IEEE802515_AFILT_SADDR_CHANGED) {
u16 addr = le16_to_cpu(filt->short_addr);
dev_vdbg(&lp->spi->dev,
"at86rf230_set_hw_addr_filt called for saddr\n");
__at86rf230_write(lp, RG_SHORT_ADDR_0, filt->short_addr);
__at86rf230_write(lp, RG_SHORT_ADDR_1, filt->short_addr >> 8);
__at86rf230_write(lp, RG_SHORT_ADDR_0, addr);
__at86rf230_write(lp, RG_SHORT_ADDR_1, addr >> 8);
}
if (changed & IEEE802515_AFILT_PANID_CHANGED) {
u16 pan = le16_to_cpu(filt->pan_id);
dev_vdbg(&lp->spi->dev,
"at86rf230_set_hw_addr_filt called for pan id\n");
__at86rf230_write(lp, RG_PAN_ID_0, filt->pan_id);
__at86rf230_write(lp, RG_PAN_ID_1, filt->pan_id >> 8);
__at86rf230_write(lp, RG_PAN_ID_0, pan);
__at86rf230_write(lp, RG_PAN_ID_1, pan >> 8);
}
if (changed & IEEE802515_AFILT_IEEEADDR_CHANGED) {
u8 i, addr[8];
memcpy(addr, &filt->ieee_addr, 8);
dev_vdbg(&lp->spi->dev,
"at86rf230_set_hw_addr_filt called for IEEE addr\n");
at86rf230_write_subreg(lp, SR_IEEE_ADDR_0, filt->ieee_addr[7]);
at86rf230_write_subreg(lp, SR_IEEE_ADDR_1, filt->ieee_addr[6]);
at86rf230_write_subreg(lp, SR_IEEE_ADDR_2, filt->ieee_addr[5]);
at86rf230_write_subreg(lp, SR_IEEE_ADDR_3, filt->ieee_addr[4]);
at86rf230_write_subreg(lp, SR_IEEE_ADDR_4, filt->ieee_addr[3]);
at86rf230_write_subreg(lp, SR_IEEE_ADDR_5, filt->ieee_addr[2]);
at86rf230_write_subreg(lp, SR_IEEE_ADDR_6, filt->ieee_addr[1]);
at86rf230_write_subreg(lp, SR_IEEE_ADDR_7, filt->ieee_addr[0]);
for (i = 0; i < 8; i++)
__at86rf230_write(lp, RG_IEEE_ADDR_0 + i, addr[i]);
}
if (changed & IEEE802515_AFILT_PANC_CHANGED) {

View File

@ -63,11 +63,11 @@ static struct wpan_phy *fake_get_phy(const struct net_device *dev)
*
* Return the ID of the PAN from the PIB.
*/
static u16 fake_get_pan_id(const struct net_device *dev)
static __le16 fake_get_pan_id(const struct net_device *dev)
{
BUG_ON(dev->type != ARPHRD_IEEE802154);
return 0xeba1;
return cpu_to_le16(0xeba1);
}
/**
@ -78,11 +78,11 @@ static u16 fake_get_pan_id(const struct net_device *dev)
* device. If the device has not yet had a short address assigned
* then this should return 0xFFFF to indicate a lack of association.
*/
static u16 fake_get_short_addr(const struct net_device *dev)
static __le16 fake_get_short_addr(const struct net_device *dev)
{
BUG_ON(dev->type != ARPHRD_IEEE802154);
return 0x1;
return cpu_to_le16(0x1);
}
/**
@ -149,7 +149,7 @@ static int fake_assoc_req(struct net_device *dev,
* 802.15.4-2006 document.
*/
static int fake_assoc_resp(struct net_device *dev,
struct ieee802154_addr *addr, u16 short_addr, u8 status)
struct ieee802154_addr *addr, __le16 short_addr, u8 status)
{
return 0;
}
@ -191,10 +191,10 @@ static int fake_disassoc_req(struct net_device *dev,
* Note: This is in section 7.5.2.3 of the IEEE 802.15.4-2006
* document, with 7.3.8 describing coordinator realignment.
*/
static int fake_start_req(struct net_device *dev, struct ieee802154_addr *addr,
u8 channel, u8 page,
u8 bcn_ord, u8 sf_ord, u8 pan_coord, u8 blx,
u8 coord_realign)
static int fake_start_req(struct net_device *dev,
struct ieee802154_addr *addr, u8 channel, u8 page,
u8 bcn_ord, u8 sf_ord, u8 pan_coord, u8 blx,
u8 coord_realign)
{
struct wpan_phy *phy = fake_to_phy(dev);
@ -281,8 +281,8 @@ static int ieee802154_fake_ioctl(struct net_device *dev, struct ifreq *ifr,
switch (cmd) {
case SIOCGIFADDR:
/* FIXME: fixed here, get from device IRL */
pan_id = fake_get_pan_id(dev);
short_addr = fake_get_short_addr(dev);
pan_id = le16_to_cpu(fake_get_pan_id(dev));
short_addr = le16_to_cpu(fake_get_short_addr(dev));
if (pan_id == IEEE802154_PANID_BROADCAST ||
short_addr == IEEE802154_ADDR_BROADCAST)
return -EADDRNOTAVAIL;

View File

@ -465,8 +465,8 @@ static int mrf24j40_filter(struct ieee802154_dev *dev,
if (changed & IEEE802515_AFILT_SADDR_CHANGED) {
/* Short Addr */
u8 addrh, addrl;
addrh = filt->short_addr >> 8 & 0xff;
addrl = filt->short_addr & 0xff;
addrh = le16_to_cpu(filt->short_addr) >> 8 & 0xff;
addrl = le16_to_cpu(filt->short_addr) & 0xff;
write_short_reg(devrec, REG_SADRH, addrh);
write_short_reg(devrec, REG_SADRL, addrl);
@ -476,15 +476,16 @@ static int mrf24j40_filter(struct ieee802154_dev *dev,
if (changed & IEEE802515_AFILT_IEEEADDR_CHANGED) {
/* Device Address */
int i;
u8 i, addr[8];
memcpy(addr, &filt->ieee_addr, 8);
for (i = 0; i < 8; i++)
write_short_reg(devrec, REG_EADR0+i,
filt->ieee_addr[7-i]);
write_short_reg(devrec, REG_EADR0 + i, addr[i]);
#ifdef DEBUG
printk(KERN_DEBUG "Set long addr to: ");
for (i = 0; i < 8; i++)
printk("%02hhx ", filt->ieee_addr[i]);
printk("%02hhx ", addr[7 - i]);
printk(KERN_DEBUG "\n");
#endif
}
@ -492,8 +493,8 @@ static int mrf24j40_filter(struct ieee802154_dev *dev,
if (changed & IEEE802515_AFILT_PANID_CHANGED) {
/* PAN ID */
u8 panidl, panidh;
panidh = filt->pan_id >> 8 & 0xff;
panidl = filt->pan_id & 0xff;
panidh = le16_to_cpu(filt->pan_id) >> 8 & 0xff;
panidl = le16_to_cpu(filt->pan_id) & 0xff;
write_short_reg(devrec, REG_PANIDH, panidh);
write_short_reg(devrec, REG_PANIDL, panidl);

View File

@ -36,7 +36,7 @@ enum {
/* address length, octets */
#define IEEE802154_ADDR_LEN 8
struct ieee802154_addr {
struct ieee802154_addr_sa {
int addr_type;
u16 pan_id;
union {
@ -51,7 +51,7 @@ struct ieee802154_addr {
struct sockaddr_ieee802154 {
sa_family_t family; /* AF_IEEE802154 */
struct ieee802154_addr addr;
struct ieee802154_addr_sa addr;
};
/* get/setsockopt */

View File

@ -42,22 +42,42 @@
(((x) << IEEE802154_FC_TYPE_SHIFT) & IEEE802154_FC_TYPE_MASK)); \
} while (0)
#define IEEE802154_FC_SECEN (1 << 3)
#define IEEE802154_FC_FRPEND (1 << 4)
#define IEEE802154_FC_ACK_REQ (1 << 5)
#define IEEE802154_FC_INTRA_PAN (1 << 6)
#define IEEE802154_FC_SECEN_SHIFT 3
#define IEEE802154_FC_SECEN (1 << IEEE802154_FC_SECEN_SHIFT)
#define IEEE802154_FC_FRPEND_SHIFT 4
#define IEEE802154_FC_FRPEND (1 << IEEE802154_FC_FRPEND_SHIFT)
#define IEEE802154_FC_ACK_REQ_SHIFT 5
#define IEEE802154_FC_ACK_REQ (1 << IEEE802154_FC_ACK_REQ_SHIFT)
#define IEEE802154_FC_INTRA_PAN_SHIFT 6
#define IEEE802154_FC_INTRA_PAN (1 << IEEE802154_FC_INTRA_PAN_SHIFT)
#define IEEE802154_FC_SAMODE_SHIFT 14
#define IEEE802154_FC_SAMODE_MASK (3 << IEEE802154_FC_SAMODE_SHIFT)
#define IEEE802154_FC_DAMODE_SHIFT 10
#define IEEE802154_FC_DAMODE_MASK (3 << IEEE802154_FC_DAMODE_SHIFT)
#define IEEE802154_FC_VERSION_SHIFT 12
#define IEEE802154_FC_VERSION_MASK (3 << IEEE802154_FC_VERSION_SHIFT)
#define IEEE802154_FC_VERSION(x) ((x & IEEE802154_FC_VERSION_MASK) >> IEEE802154_FC_VERSION_SHIFT)
#define IEEE802154_FC_SAMODE(x) \
(((x) & IEEE802154_FC_SAMODE_MASK) >> IEEE802154_FC_SAMODE_SHIFT)
#define IEEE802154_FC_DAMODE(x) \
(((x) & IEEE802154_FC_DAMODE_MASK) >> IEEE802154_FC_DAMODE_SHIFT)
#define IEEE802154_SCF_SECLEVEL_MASK 7
#define IEEE802154_SCF_SECLEVEL_SHIFT 0
#define IEEE802154_SCF_SECLEVEL(x) (x & IEEE802154_SCF_SECLEVEL_MASK)
#define IEEE802154_SCF_KEY_ID_MODE_SHIFT 3
#define IEEE802154_SCF_KEY_ID_MODE_MASK (3 << IEEE802154_SCF_KEY_ID_MODE_SHIFT)
#define IEEE802154_SCF_KEY_ID_MODE(x) \
((x & IEEE802154_SCF_KEY_ID_MODE_MASK) >> IEEE802154_SCF_KEY_ID_MODE_SHIFT)
#define IEEE802154_SCF_KEY_IMPLICIT 0
#define IEEE802154_SCF_KEY_INDEX 1
#define IEEE802154_SCF_KEY_SHORT_INDEX 2
#define IEEE802154_SCF_KEY_HW_INDEX 3
/* MAC footer size */
#define IEEE802154_MFR_SIZE 2 /* 2 octets */

View File

@ -28,24 +28,175 @@
#define IEEE802154_NETDEVICE_H
#include <net/af_ieee802154.h>
#include <linux/netdevice.h>
#include <linux/skbuff.h>
struct ieee802154_frag_info {
__be16 d_tag;
u16 d_size;
u8 d_offset;
struct ieee802154_sechdr {
#if defined(__LITTLE_ENDIAN_BITFIELD)
u8 level:3,
key_id_mode:2,
reserved:3;
#elif defined(__BIG_ENDIAN_BITFIELD)
u8 reserved:3,
key_id_mode:2,
level:3;
#else
#error "Please fix <asm/byteorder.h>"
#endif
u8 key_id;
__le32 frame_counter;
union {
__le32 short_src;
__le64 extended_src;
};
};
struct ieee802154_addr {
u8 mode;
__le16 pan_id;
union {
__le16 short_addr;
__le64 extended_addr;
};
};
struct ieee802154_hdr_fc {
#if defined(__LITTLE_ENDIAN_BITFIELD)
u16 type:3,
security_enabled:1,
frame_pending:1,
ack_request:1,
intra_pan:1,
reserved:3,
dest_addr_mode:2,
version:2,
source_addr_mode:2;
#elif defined(__BIG_ENDIAN_BITFIELD)
u16 reserved:1,
intra_pan:1,
ack_request:1,
frame_pending:1,
security_enabled:1,
type:3,
source_addr_mode:2,
version:2,
dest_addr_mode:2,
reserved2:2;
#else
#error "Please fix <asm/byteorder.h>"
#endif
};
struct ieee802154_hdr {
struct ieee802154_hdr_fc fc;
u8 seq;
struct ieee802154_addr source;
struct ieee802154_addr dest;
struct ieee802154_sechdr sec;
};
/* pushes hdr onto the skb. fields of hdr->fc that can be calculated from
* the contents of hdr will be, and the actual value of those bits in
* hdr->fc will be ignored. this includes the INTRA_PAN bit and the frame
* version, if SECEN is set.
*/
int ieee802154_hdr_push(struct sk_buff *skb, const struct ieee802154_hdr *hdr);
/* pulls the entire 802.15.4 header off of the skb, including the security
* header, and performs pan id decompression
*/
int ieee802154_hdr_pull(struct sk_buff *skb, struct ieee802154_hdr *hdr);
/* parses the frame control, sequence number of address fields in a given skb
* and stores them into hdr, performing pan id decompression and length checks
* to be suitable for use in header_ops.parse
*/
int ieee802154_hdr_peek_addrs(const struct sk_buff *skb,
struct ieee802154_hdr *hdr);
static inline int ieee802154_hdr_length(struct sk_buff *skb)
{
struct ieee802154_hdr hdr;
int len = ieee802154_hdr_pull(skb, &hdr);
if (len > 0)
skb_push(skb, len);
return len;
}
static inline bool ieee802154_addr_equal(const struct ieee802154_addr *a1,
const struct ieee802154_addr *a2)
{
if (a1->pan_id != a2->pan_id || a1->mode != a2->mode)
return false;
if ((a1->mode == IEEE802154_ADDR_LONG &&
a1->extended_addr != a2->extended_addr) ||
(a1->mode == IEEE802154_ADDR_SHORT &&
a1->short_addr != a2->short_addr))
return false;
return true;
}
static inline __le64 ieee802154_devaddr_from_raw(const void *raw)
{
u64 temp;
memcpy(&temp, raw, IEEE802154_ADDR_LEN);
return (__force __le64)swab64(temp);
}
static inline void ieee802154_devaddr_to_raw(void *raw, __le64 addr)
{
u64 temp = swab64((__force u64)addr);
memcpy(raw, &temp, IEEE802154_ADDR_LEN);
}
static inline void ieee802154_addr_from_sa(struct ieee802154_addr *a,
const struct ieee802154_addr_sa *sa)
{
a->mode = sa->addr_type;
a->pan_id = cpu_to_le16(sa->pan_id);
switch (a->mode) {
case IEEE802154_ADDR_SHORT:
a->short_addr = cpu_to_le16(sa->short_addr);
break;
case IEEE802154_ADDR_LONG:
a->extended_addr = ieee802154_devaddr_from_raw(sa->hwaddr);
break;
}
}
static inline void ieee802154_addr_to_sa(struct ieee802154_addr_sa *sa,
const struct ieee802154_addr *a)
{
sa->addr_type = a->mode;
sa->pan_id = le16_to_cpu(a->pan_id);
switch (a->mode) {
case IEEE802154_ADDR_SHORT:
sa->short_addr = le16_to_cpu(a->short_addr);
break;
case IEEE802154_ADDR_LONG:
ieee802154_devaddr_to_raw(sa->hwaddr, a->extended_addr);
break;
}
}
/*
* A control block of skb passed between the ARPHRD_IEEE802154 device
* and other stack parts.
*/
struct ieee802154_mac_cb {
u8 lqi;
struct ieee802154_addr sa;
struct ieee802154_addr da;
u8 flags;
u8 seq;
struct ieee802154_frag_info frag_info;
struct ieee802154_addr source;
struct ieee802154_addr dest;
};
static inline struct ieee802154_mac_cb *mac_cb(struct sk_buff *skb)
@ -57,23 +208,17 @@ static inline struct ieee802154_mac_cb *mac_cb(struct sk_buff *skb)
#define MAC_CB_FLAG_ACKREQ (1 << 3)
#define MAC_CB_FLAG_SECEN (1 << 4)
#define MAC_CB_FLAG_INTRAPAN (1 << 5)
static inline int mac_cb_is_ackreq(struct sk_buff *skb)
static inline bool mac_cb_is_ackreq(struct sk_buff *skb)
{
return mac_cb(skb)->flags & MAC_CB_FLAG_ACKREQ;
}
static inline int mac_cb_is_secen(struct sk_buff *skb)
static inline bool mac_cb_is_secen(struct sk_buff *skb)
{
return mac_cb(skb)->flags & MAC_CB_FLAG_SECEN;
}
static inline int mac_cb_is_intrapan(struct sk_buff *skb)
{
return mac_cb(skb)->flags & MAC_CB_FLAG_INTRAPAN;
}
static inline int mac_cb_type(struct sk_buff *skb)
{
return mac_cb(skb)->flags & MAC_CB_FLAG_TYPEMASK;
@ -99,7 +244,7 @@ struct ieee802154_mlme_ops {
u8 channel, u8 page, u8 cap);
int (*assoc_resp)(struct net_device *dev,
struct ieee802154_addr *addr,
u16 short_addr, u8 status);
__le16 short_addr, u8 status);
int (*disassoc_req)(struct net_device *dev,
struct ieee802154_addr *addr,
u8 reason);
@ -118,8 +263,8 @@ struct ieee802154_mlme_ops {
* FIXME: these should become the part of PIB/MIB interface.
* However we still don't have IB interface of any kind
*/
u16 (*get_pan_id)(const struct net_device *dev);
u16 (*get_short_addr)(const struct net_device *dev);
__le16 (*get_pan_id)(const struct net_device *dev);
__le16 (*get_short_addr)(const struct net_device *dev);
u8 (*get_dsn)(const struct net_device *dev);
};

View File

@ -20,6 +20,7 @@
#define NET_MAC802154_H
#include <net/af_ieee802154.h>
#include <linux/skbuff.h>
/* General MAC frame format:
* 2 bytes: Frame Control
@ -50,7 +51,7 @@ struct ieee802154_hw_addr_filt {
* devices across independent networks.
*/
__le16 short_addr;
u8 ieee_addr[IEEE802154_ADDR_LEN];
__le64 ieee_addr;
u8 pan_coord;
};
@ -153,8 +154,7 @@ struct ieee802154_ops {
int (*set_hw_addr_filt)(struct ieee802154_dev *dev,
struct ieee802154_hw_addr_filt *filt,
unsigned long changed);
int (*ieee_addr)(struct ieee802154_dev *dev,
u8 addr[IEEE802154_ADDR_LEN]);
int (*ieee_addr)(struct ieee802154_dev *dev, __le64 addr);
int (*set_txpower)(struct ieee802154_dev *dev, int db);
int (*set_lbt)(struct ieee802154_dev *dev, bool on);
int (*set_cca_mode)(struct ieee802154_dev *dev, u8 mode);

View File

@ -52,7 +52,7 @@ int ieee802154_nl_assoc_indic(struct net_device *dev,
* Note: This is in section 7.3.2 of the IEEE 802.15.4 document.
*/
int ieee802154_nl_assoc_confirm(struct net_device *dev,
u16 short_addr, u8 status);
__le16 short_addr, u8 status);
/**
* ieee802154_nl_disassoc_indic - Notify userland of disassociation.
@ -111,8 +111,8 @@ int ieee802154_nl_scan_confirm(struct net_device *dev,
* Note: This API cannot indicate a beacon frame for a coordinator
* operating in long addressing mode.
*/
int ieee802154_nl_beacon_indic(struct net_device *dev, u16 panid,
u16 coord_addr);
int ieee802154_nl_beacon_indic(struct net_device *dev, __le16 panid,
__le16 coord_addr);
/**
* ieee802154_nl_start_confirm - Notify userland of completion of start.

View File

@ -119,29 +119,29 @@ static int lowpan_header_create(struct sk_buff *skb,
mac_cb(skb)->seq = ieee802154_mlme_ops(dev)->get_dsn(dev);
/* prepare wpan address data */
sa.addr_type = IEEE802154_ADDR_LONG;
sa.mode = IEEE802154_ADDR_LONG;
sa.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev);
sa.extended_addr = ieee802154_devaddr_from_raw(saddr);
memcpy(&(sa.hwaddr), saddr, 8);
/* intra-PAN communications */
da.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev);
da.pan_id = sa.pan_id;
/* if the destination address is the broadcast address, use the
* corresponding short address
*/
if (lowpan_is_addr_broadcast(daddr)) {
da.addr_type = IEEE802154_ADDR_SHORT;
da.short_addr = IEEE802154_ADDR_BROADCAST;
da.mode = IEEE802154_ADDR_SHORT;
da.short_addr = cpu_to_le16(IEEE802154_ADDR_BROADCAST);
} else {
da.addr_type = IEEE802154_ADDR_LONG;
memcpy(&(da.hwaddr), daddr, IEEE802154_ADDR_LEN);
da.mode = IEEE802154_ADDR_LONG;
da.extended_addr = ieee802154_devaddr_from_raw(daddr);
/* request acknowledgment */
mac_cb(skb)->flags |= MAC_CB_FLAG_ACKREQ;
}
return dev_hard_header(skb, lowpan_dev_info(dev)->real_dev,
type, (void *)&da, (void *)&sa, skb->len);
type, (void *)&da, (void *)&sa, 0);
}
static int lowpan_give_skb_to_devices(struct sk_buff *skb,
@ -168,10 +168,11 @@ static int lowpan_give_skb_to_devices(struct sk_buff *skb,
return stat;
}
static int process_data(struct sk_buff *skb)
static int process_data(struct sk_buff *skb, const struct ieee802154_hdr *hdr)
{
u8 iphc0, iphc1;
const struct ieee802154_addr *_saddr, *_daddr;
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 */
@ -184,14 +185,23 @@ static int process_data(struct sk_buff *skb)
if (lowpan_fetch_skb_u8(skb, &iphc1))
goto drop;
_saddr = &mac_cb(skb)->sa;
_daddr = &mac_cb(skb)->da;
ieee802154_addr_to_sa(&sa, &hdr->source);
ieee802154_addr_to_sa(&da, &hdr->dest);
return lowpan_process_data(skb, skb->dev, (u8 *)_saddr->hwaddr,
_saddr->addr_type, IEEE802154_ADDR_LEN,
(u8 *)_daddr->hwaddr, _daddr->addr_type,
IEEE802154_ADDR_LEN, iphc0, iphc1,
lowpan_give_skb_to_devices);
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_process_data(skb, skb->dev, sap, sa.addr_type,
IEEE802154_ADDR_LEN, dap, da.addr_type,
IEEE802154_ADDR_LEN, iphc0, iphc1,
lowpan_give_skb_to_devices);
drop:
kfree_skb(skb);
@ -352,13 +362,13 @@ static struct wpan_phy *lowpan_get_phy(const struct net_device *dev)
return ieee802154_mlme_ops(real_dev)->get_phy(real_dev);
}
static u16 lowpan_get_pan_id(const struct net_device *dev)
static __le16 lowpan_get_pan_id(const struct net_device *dev)
{
struct net_device *real_dev = lowpan_dev_info(dev)->real_dev;
return ieee802154_mlme_ops(real_dev)->get_pan_id(real_dev);
}
static u16 lowpan_get_short_addr(const struct net_device *dev)
static __le16 lowpan_get_short_addr(const struct net_device *dev)
{
struct net_device *real_dev = lowpan_dev_info(dev)->real_dev;
return ieee802154_mlme_ops(real_dev)->get_short_addr(real_dev);
@ -438,6 +448,7 @@ static int lowpan_rcv(struct sk_buff *skb, struct net_device *dev,
struct packet_type *pt, struct net_device *orig_dev)
{
struct sk_buff *local_skb;
struct ieee802154_hdr hdr;
int ret;
if (!netif_running(dev))
@ -446,6 +457,9 @@ static int lowpan_rcv(struct sk_buff *skb, struct net_device *dev,
if (dev->type != ARPHRD_IEEE802154)
goto drop_skb;
if (ieee802154_hdr_peek_addrs(skb, &hdr) < 0)
goto drop_skb;
local_skb = skb_clone(skb, GFP_ATOMIC);
if (!local_skb)
goto drop_skb;
@ -466,14 +480,14 @@ static int lowpan_rcv(struct sk_buff *skb, struct net_device *dev,
} else {
switch (skb->data[0] & 0xe0) {
case LOWPAN_DISPATCH_IPHC: /* ipv6 datagram */
ret = process_data(local_skb);
ret = process_data(local_skb, &hdr);
if (ret == NET_RX_DROP)
goto drop;
break;
case LOWPAN_DISPATCH_FRAG1: /* first fragment header */
ret = lowpan_frag_rcv(local_skb, LOWPAN_DISPATCH_FRAG1);
if (ret == 1) {
ret = process_data(local_skb);
ret = process_data(local_skb, &hdr);
if (ret == NET_RX_DROP)
goto drop;
}
@ -481,7 +495,7 @@ static int lowpan_rcv(struct sk_buff *skb, struct net_device *dev,
case LOWPAN_DISPATCH_FRAGN: /* next fragments headers */
ret = lowpan_frag_rcv(local_skb, LOWPAN_DISPATCH_FRAGN);
if (ret == 1) {
ret = process_data(local_skb);
ret = process_data(local_skb, &hdr);
if (ret == NET_RX_DROP)
goto drop;
}

View File

@ -3,5 +3,8 @@ obj-$(CONFIG_IEEE802154_6LOWPAN) += 6lowpan.o
obj-$(CONFIG_6LOWPAN_IPHC) += 6lowpan_iphc.o
6lowpan-y := 6lowpan_rtnl.o reassembly.o
ieee802154-y := netlink.o nl-mac.o nl-phy.o nl_policy.o wpan-class.o
ieee802154-y := netlink.o nl-mac.o nl-phy.o nl_policy.o wpan-class.o \
header_ops.o
af_802154-y := af_ieee802154.o raw.o dgram.o
ccflags-y += -D__CHECK_ENDIAN__

View File

@ -25,12 +25,13 @@
#define AF802154_H
struct sk_buff;
struct net_devce;
struct net_device;
struct ieee802154_addr;
extern struct proto ieee802154_raw_prot;
extern struct proto ieee802154_dgram_prot;
void ieee802154_raw_deliver(struct net_device *dev, struct sk_buff *skb);
int ieee802154_dgram_deliver(struct net_device *dev, struct sk_buff *skb);
struct net_device *ieee802154_get_dev(struct net *net,
struct ieee802154_addr *addr);
const struct ieee802154_addr *addr);
#endif

View File

@ -43,25 +43,27 @@
/*
* Utility function for families
*/
struct net_device *ieee802154_get_dev(struct net *net,
struct ieee802154_addr *addr)
struct net_device*
ieee802154_get_dev(struct net *net, const struct ieee802154_addr *addr)
{
struct net_device *dev = NULL;
struct net_device *tmp;
u16 pan_id, short_addr;
__le16 pan_id, short_addr;
u8 hwaddr[IEEE802154_ADDR_LEN];
switch (addr->addr_type) {
switch (addr->mode) {
case IEEE802154_ADDR_LONG:
ieee802154_devaddr_to_raw(hwaddr, addr->extended_addr);
rcu_read_lock();
dev = dev_getbyhwaddr_rcu(net, ARPHRD_IEEE802154, addr->hwaddr);
dev = dev_getbyhwaddr_rcu(net, ARPHRD_IEEE802154, hwaddr);
if (dev)
dev_hold(dev);
rcu_read_unlock();
break;
case IEEE802154_ADDR_SHORT:
if (addr->pan_id == 0xffff ||
addr->short_addr == IEEE802154_ADDR_UNDEF ||
addr->short_addr == 0xffff)
if (addr->pan_id == cpu_to_le16(IEEE802154_PANID_BROADCAST) ||
addr->short_addr == cpu_to_le16(IEEE802154_ADDR_UNDEF) ||
addr->short_addr == cpu_to_le16(IEEE802154_ADDR_UNDEF))
break;
rtnl_lock();
@ -86,7 +88,7 @@ struct net_device *ieee802154_get_dev(struct net *net,
break;
default:
pr_warning("Unsupported ieee802154 address type: %d\n",
addr->addr_type);
addr->mode);
break;
}

View File

@ -73,10 +73,10 @@ static int dgram_init(struct sock *sk)
{
struct dgram_sock *ro = dgram_sk(sk);
ro->dst_addr.addr_type = IEEE802154_ADDR_LONG;
ro->dst_addr.pan_id = 0xffff;
ro->dst_addr.mode = IEEE802154_ADDR_LONG;
ro->dst_addr.pan_id = cpu_to_le16(IEEE802154_ADDR_BROADCAST);
ro->want_ack = 1;
memset(&ro->dst_addr.hwaddr, 0xff, sizeof(ro->dst_addr.hwaddr));
memset(&ro->dst_addr.extended_addr, 0xff, IEEE802154_ADDR_LEN);
return 0;
}
@ -88,6 +88,7 @@ static void dgram_close(struct sock *sk, long timeout)
static int dgram_bind(struct sock *sk, struct sockaddr *uaddr, int len)
{
struct sockaddr_ieee802154 *addr = (struct sockaddr_ieee802154 *)uaddr;
struct ieee802154_addr haddr;
struct dgram_sock *ro = dgram_sk(sk);
int err = -EINVAL;
struct net_device *dev;
@ -102,7 +103,8 @@ static int dgram_bind(struct sock *sk, struct sockaddr *uaddr, int len)
if (addr->family != AF_IEEE802154)
goto out;
dev = ieee802154_get_dev(sock_net(sk), &addr->addr);
ieee802154_addr_from_sa(&haddr, &addr->addr);
dev = ieee802154_get_dev(sock_net(sk), &haddr);
if (!dev) {
err = -ENODEV;
goto out;
@ -113,7 +115,7 @@ static int dgram_bind(struct sock *sk, struct sockaddr *uaddr, int len)
goto out_put;
}
memcpy(&ro->src_addr, &addr->addr, sizeof(struct ieee802154_addr));
ro->src_addr = haddr;
ro->bound = 1;
err = 0;
@ -149,8 +151,7 @@ static int dgram_ioctl(struct sock *sk, int cmd, unsigned long arg)
* of this packet since that is all
* that will be read.
*/
/* FIXME: parse the header for more correct value */
amount = skb->len - (3+8+8);
amount = skb->len - ieee802154_hdr_length(skb);
}
spin_unlock_bh(&sk->sk_receive_queue.lock);
return put_user(amount, (int __user *)arg);
@ -181,7 +182,7 @@ static int dgram_connect(struct sock *sk, struct sockaddr *uaddr,
goto out;
}
memcpy(&ro->dst_addr, &addr->addr, sizeof(struct ieee802154_addr));
ieee802154_addr_from_sa(&ro->dst_addr, &addr->addr);
out:
release_sock(sk);
@ -194,8 +195,8 @@ static int dgram_disconnect(struct sock *sk, int flags)
lock_sock(sk);
ro->dst_addr.addr_type = IEEE802154_ADDR_LONG;
memset(&ro->dst_addr.hwaddr, 0xff, sizeof(ro->dst_addr.hwaddr));
ro->dst_addr.mode = IEEE802154_ADDR_LONG;
memset(&ro->dst_addr.extended_addr, 0xff, IEEE802154_ADDR_LEN);
release_sock(sk);
@ -232,7 +233,7 @@ static int dgram_sendmsg(struct kiocb *iocb, struct sock *sk,
if (size > mtu) {
pr_debug("size = %Zu, mtu = %u\n", size, mtu);
err = -EINVAL;
err = -EMSGSIZE;
goto out_dev;
}
@ -312,7 +313,7 @@ static int dgram_recvmsg(struct kiocb *iocb, struct sock *sk,
if (saddr) {
saddr->family = AF_IEEE802154;
saddr->addr = mac_cb(skb)->sa;
ieee802154_addr_to_sa(&saddr->addr, &mac_cb(skb)->source);
*addr_len = sizeof(*saddr);
}
@ -336,40 +337,43 @@ static int dgram_rcv_skb(struct sock *sk, struct sk_buff *skb)
return NET_RX_SUCCESS;
}
static inline int ieee802154_match_sock(u8 *hw_addr, u16 pan_id,
u16 short_addr, struct dgram_sock *ro)
static inline bool
ieee802154_match_sock(__le64 hw_addr, __le16 pan_id, __le16 short_addr,
struct dgram_sock *ro)
{
if (!ro->bound)
return 1;
return true;
if (ro->src_addr.addr_type == IEEE802154_ADDR_LONG &&
!memcmp(ro->src_addr.hwaddr, hw_addr, IEEE802154_ADDR_LEN))
return 1;
if (ro->src_addr.mode == IEEE802154_ADDR_LONG &&
hw_addr == ro->src_addr.extended_addr)
return true;
if (ro->src_addr.addr_type == IEEE802154_ADDR_SHORT &&
pan_id == ro->src_addr.pan_id &&
short_addr == ro->src_addr.short_addr)
return 1;
if (ro->src_addr.mode == IEEE802154_ADDR_SHORT &&
pan_id == ro->src_addr.pan_id &&
short_addr == ro->src_addr.short_addr)
return true;
return 0;
return false;
}
int ieee802154_dgram_deliver(struct net_device *dev, struct sk_buff *skb)
{
struct sock *sk, *prev = NULL;
int ret = NET_RX_SUCCESS;
u16 pan_id, short_addr;
__le16 pan_id, short_addr;
__le64 hw_addr;
/* Data frame processing */
BUG_ON(dev->type != ARPHRD_IEEE802154);
pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev);
short_addr = ieee802154_mlme_ops(dev)->get_short_addr(dev);
hw_addr = ieee802154_devaddr_from_raw(dev->dev_addr);
read_lock(&dgram_lock);
sk_for_each(sk, &dgram_head) {
if (ieee802154_match_sock(dev->dev_addr, pan_id, short_addr,
dgram_sk(sk))) {
if (ieee802154_match_sock(hw_addr, pan_id, short_addr,
dgram_sk(sk))) {
if (prev) {
struct sk_buff *clone;
clone = skb_clone(skb, GFP_ATOMIC);

287
net/ieee802154/header_ops.c Normal file
View File

@ -0,0 +1,287 @@
/*
* Copyright (C) 2014 Fraunhofer ITWM
*
* 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.
*
* Written by:
* Phoebe Buckheister <phoebe.buckheister@itwm.fraunhofer.de>
*/
#include <net/mac802154.h>
#include <net/ieee802154.h>
#include <net/ieee802154_netdev.h>
static int
ieee802154_hdr_push_addr(u8 *buf, const struct ieee802154_addr *addr,
bool omit_pan)
{
int pos = 0;
if (addr->mode == IEEE802154_ADDR_NONE)
return 0;
if (!omit_pan) {
memcpy(buf + pos, &addr->pan_id, 2);
pos += 2;
}
switch (addr->mode) {
case IEEE802154_ADDR_SHORT:
memcpy(buf + pos, &addr->short_addr, 2);
pos += 2;
break;
case IEEE802154_ADDR_LONG:
memcpy(buf + pos, &addr->extended_addr, IEEE802154_ADDR_LEN);
pos += IEEE802154_ADDR_LEN;
break;
default:
return -EINVAL;
}
return pos;
}
static int
ieee802154_hdr_push_sechdr(u8 *buf, const struct ieee802154_sechdr *hdr)
{
int pos = 5;
memcpy(buf, hdr, 1);
memcpy(buf + 1, &hdr->frame_counter, 4);
switch (hdr->key_id_mode) {
case IEEE802154_SCF_KEY_IMPLICIT:
return pos;
case IEEE802154_SCF_KEY_INDEX:
break;
case IEEE802154_SCF_KEY_SHORT_INDEX:
memcpy(buf + pos, &hdr->short_src, 4);
pos += 4;
break;
case IEEE802154_SCF_KEY_HW_INDEX:
memcpy(buf + pos, &hdr->extended_src, IEEE802154_ADDR_LEN);
pos += IEEE802154_ADDR_LEN;
break;
}
buf[pos++] = hdr->key_id;
return pos;
}
int
ieee802154_hdr_push(struct sk_buff *skb, const struct ieee802154_hdr *hdr)
{
u8 buf[MAC802154_FRAME_HARD_HEADER_LEN];
int pos = 2;
int rc;
struct ieee802154_hdr_fc fc = hdr->fc;
buf[pos++] = hdr->seq;
fc.dest_addr_mode = hdr->dest.mode;
rc = ieee802154_hdr_push_addr(buf + pos, &hdr->dest, false);
if (rc < 0)
return -EINVAL;
pos += rc;
fc.source_addr_mode = hdr->source.mode;
if (hdr->source.pan_id == hdr->dest.pan_id &&
hdr->dest.mode != IEEE802154_ADDR_NONE)
fc.intra_pan = true;
rc = ieee802154_hdr_push_addr(buf + pos, &hdr->source, fc.intra_pan);
if (rc < 0)
return -EINVAL;
pos += rc;
if (fc.security_enabled) {
fc.version = 1;
rc = ieee802154_hdr_push_sechdr(buf + pos, &hdr->sec);
if (rc < 0)
return -EINVAL;
pos += rc;
}
memcpy(buf, &fc, 2);
memcpy(skb_push(skb, pos), buf, pos);
return pos;
}
EXPORT_SYMBOL_GPL(ieee802154_hdr_push);
static int
ieee802154_hdr_get_addr(const u8 *buf, int mode, bool omit_pan,
struct ieee802154_addr *addr)
{
int pos = 0;
addr->mode = mode;
if (mode == IEEE802154_ADDR_NONE)
return 0;
if (!omit_pan) {
memcpy(&addr->pan_id, buf + pos, 2);
pos += 2;
}
if (mode == IEEE802154_ADDR_SHORT) {
memcpy(&addr->short_addr, buf + pos, 2);
return pos + 2;
} else {
memcpy(&addr->extended_addr, buf + pos, IEEE802154_ADDR_LEN);
return pos + IEEE802154_ADDR_LEN;
}
}
static int ieee802154_hdr_addr_len(int mode, bool omit_pan)
{
int pan_len = omit_pan ? 0 : 2;
switch (mode) {
case IEEE802154_ADDR_NONE: return 0;
case IEEE802154_ADDR_SHORT: return 2 + pan_len;
case IEEE802154_ADDR_LONG: return IEEE802154_ADDR_LEN + pan_len;
default: return -EINVAL;
}
}
static int
ieee802154_hdr_get_sechdr(const u8 *buf, struct ieee802154_sechdr *hdr)
{
int pos = 5;
memcpy(hdr, buf, 1);
memcpy(&hdr->frame_counter, buf + 1, 4);
switch (hdr->key_id_mode) {
case IEEE802154_SCF_KEY_IMPLICIT:
return pos;
case IEEE802154_SCF_KEY_INDEX:
break;
case IEEE802154_SCF_KEY_SHORT_INDEX:
memcpy(&hdr->short_src, buf + pos, 4);
pos += 4;
break;
case IEEE802154_SCF_KEY_HW_INDEX:
memcpy(&hdr->extended_src, buf + pos, IEEE802154_ADDR_LEN);
pos += IEEE802154_ADDR_LEN;
break;
}
hdr->key_id = buf[pos++];
return pos;
}
static int ieee802154_hdr_sechdr_len(u8 sc)
{
switch (IEEE802154_SCF_KEY_ID_MODE(sc)) {
case IEEE802154_SCF_KEY_IMPLICIT: return 5;
case IEEE802154_SCF_KEY_INDEX: return 6;
case IEEE802154_SCF_KEY_SHORT_INDEX: return 10;
case IEEE802154_SCF_KEY_HW_INDEX: return 14;
default: return -EINVAL;
}
}
static int ieee802154_hdr_minlen(const struct ieee802154_hdr *hdr)
{
int dlen, slen;
dlen = ieee802154_hdr_addr_len(hdr->fc.dest_addr_mode, false);
slen = ieee802154_hdr_addr_len(hdr->fc.source_addr_mode,
hdr->fc.intra_pan);
if (slen < 0 || dlen < 0)
return -EINVAL;
return 3 + dlen + slen + hdr->fc.security_enabled;
}
static int
ieee802154_hdr_get_addrs(const u8 *buf, struct ieee802154_hdr *hdr)
{
int pos = 0;
pos += ieee802154_hdr_get_addr(buf + pos, hdr->fc.dest_addr_mode,
false, &hdr->dest);
pos += ieee802154_hdr_get_addr(buf + pos, hdr->fc.source_addr_mode,
hdr->fc.intra_pan, &hdr->source);
if (hdr->fc.intra_pan)
hdr->source.pan_id = hdr->dest.pan_id;
return pos;
}
int
ieee802154_hdr_pull(struct sk_buff *skb, struct ieee802154_hdr *hdr)
{
int pos = 3, rc;
if (!pskb_may_pull(skb, 3))
return -EINVAL;
memcpy(hdr, skb->data, 3);
rc = ieee802154_hdr_minlen(hdr);
if (rc < 0 || !pskb_may_pull(skb, rc))
return -EINVAL;
pos += ieee802154_hdr_get_addrs(skb->data + pos, hdr);
if (hdr->fc.security_enabled) {
int want = pos + ieee802154_hdr_sechdr_len(skb->data[pos]);
if (!pskb_may_pull(skb, want))
return -EINVAL;
pos += ieee802154_hdr_get_sechdr(skb->data + pos, &hdr->sec);
}
skb_pull(skb, pos);
return pos;
}
EXPORT_SYMBOL_GPL(ieee802154_hdr_pull);
int
ieee802154_hdr_peek_addrs(const struct sk_buff *skb, struct ieee802154_hdr *hdr)
{
const u8 *buf = skb_mac_header(skb);
int pos = 3, rc;
if (buf + 3 > skb_tail_pointer(skb))
return -EINVAL;
memcpy(hdr, buf, 3);
rc = ieee802154_hdr_minlen(hdr);
if (rc < 0 || buf + rc > skb_tail_pointer(skb))
return -EINVAL;
pos += ieee802154_hdr_get_addrs(buf + pos, hdr);
return pos;
}
EXPORT_SYMBOL_GPL(ieee802154_hdr_peek_addrs);

View File

@ -39,6 +39,26 @@
#include "ieee802154.h"
static int nla_put_hwaddr(struct sk_buff *msg, int type, __le64 hwaddr)
{
return nla_put_u64(msg, type, swab64((__force u64)hwaddr));
}
static __le64 nla_get_hwaddr(const struct nlattr *nla)
{
return ieee802154_devaddr_from_raw(nla_data(nla));
}
static int nla_put_shortaddr(struct sk_buff *msg, int type, __le16 addr)
{
return nla_put_u16(msg, type, le16_to_cpu(addr));
}
static __le16 nla_get_shortaddr(const struct nlattr *nla)
{
return cpu_to_le16(nla_get_u16(nla));
}
int ieee802154_nl_assoc_indic(struct net_device *dev,
struct ieee802154_addr *addr, u8 cap)
{
@ -46,7 +66,7 @@ int ieee802154_nl_assoc_indic(struct net_device *dev,
pr_debug("%s\n", __func__);
if (addr->addr_type != IEEE802154_ADDR_LONG) {
if (addr->mode != IEEE802154_ADDR_LONG) {
pr_err("%s: received non-long source address!\n", __func__);
return -EINVAL;
}
@ -59,8 +79,8 @@ int ieee802154_nl_assoc_indic(struct net_device *dev,
nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
dev->dev_addr) ||
nla_put(msg, IEEE802154_ATTR_SRC_HW_ADDR, IEEE802154_ADDR_LEN,
addr->hwaddr) ||
nla_put_hwaddr(msg, IEEE802154_ATTR_SRC_HW_ADDR,
addr->extended_addr) ||
nla_put_u8(msg, IEEE802154_ATTR_CAPABILITY, cap))
goto nla_put_failure;
@ -72,7 +92,7 @@ nla_put_failure:
}
EXPORT_SYMBOL(ieee802154_nl_assoc_indic);
int ieee802154_nl_assoc_confirm(struct net_device *dev, u16 short_addr,
int ieee802154_nl_assoc_confirm(struct net_device *dev, __le16 short_addr,
u8 status)
{
struct sk_buff *msg;
@ -87,7 +107,7 @@ int ieee802154_nl_assoc_confirm(struct net_device *dev, u16 short_addr,
nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
dev->dev_addr) ||
nla_put_u16(msg, IEEE802154_ATTR_SHORT_ADDR, short_addr) ||
nla_put_shortaddr(msg, IEEE802154_ATTR_SHORT_ADDR, short_addr) ||
nla_put_u8(msg, IEEE802154_ATTR_STATUS, status))
goto nla_put_failure;
return ieee802154_nl_mcast(msg, IEEE802154_COORD_MCGRP);
@ -114,13 +134,13 @@ int ieee802154_nl_disassoc_indic(struct net_device *dev,
nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
dev->dev_addr))
goto nla_put_failure;
if (addr->addr_type == IEEE802154_ADDR_LONG) {
if (nla_put(msg, IEEE802154_ATTR_SRC_HW_ADDR, IEEE802154_ADDR_LEN,
addr->hwaddr))
if (addr->mode == IEEE802154_ADDR_LONG) {
if (nla_put_hwaddr(msg, IEEE802154_ATTR_SRC_HW_ADDR,
addr->extended_addr))
goto nla_put_failure;
} else {
if (nla_put_u16(msg, IEEE802154_ATTR_SRC_SHORT_ADDR,
addr->short_addr))
if (nla_put_shortaddr(msg, IEEE802154_ATTR_SRC_SHORT_ADDR,
addr->short_addr))
goto nla_put_failure;
}
if (nla_put_u8(msg, IEEE802154_ATTR_REASON, reason))
@ -157,8 +177,8 @@ nla_put_failure:
}
EXPORT_SYMBOL(ieee802154_nl_disassoc_confirm);
int ieee802154_nl_beacon_indic(struct net_device *dev,
u16 panid, u16 coord_addr)
int ieee802154_nl_beacon_indic(struct net_device *dev, __le16 panid,
__le16 coord_addr)
{
struct sk_buff *msg;
@ -172,8 +192,9 @@ int ieee802154_nl_beacon_indic(struct net_device *dev,
nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
dev->dev_addr) ||
nla_put_u16(msg, IEEE802154_ATTR_COORD_SHORT_ADDR, coord_addr) ||
nla_put_u16(msg, IEEE802154_ATTR_COORD_PAN_ID, panid))
nla_put_shortaddr(msg, IEEE802154_ATTR_COORD_SHORT_ADDR,
coord_addr) ||
nla_put_shortaddr(msg, IEEE802154_ATTR_COORD_PAN_ID, panid))
goto nla_put_failure;
return ieee802154_nl_mcast(msg, IEEE802154_COORD_MCGRP);
@ -243,6 +264,7 @@ static int ieee802154_nl_fill_iface(struct sk_buff *msg, u32 portid,
{
void *hdr;
struct wpan_phy *phy;
__le16 short_addr, pan_id;
pr_debug("%s\n", __func__);
@ -254,15 +276,16 @@ static int ieee802154_nl_fill_iface(struct sk_buff *msg, u32 portid,
phy = ieee802154_mlme_ops(dev)->get_phy(dev);
BUG_ON(!phy);
short_addr = ieee802154_mlme_ops(dev)->get_short_addr(dev);
pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev);
if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) ||
nla_put_string(msg, IEEE802154_ATTR_PHY_NAME, wpan_phy_name(phy)) ||
nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
dev->dev_addr) ||
nla_put_u16(msg, IEEE802154_ATTR_SHORT_ADDR,
ieee802154_mlme_ops(dev)->get_short_addr(dev)) ||
nla_put_u16(msg, IEEE802154_ATTR_PAN_ID,
ieee802154_mlme_ops(dev)->get_pan_id(dev)))
nla_put_shortaddr(msg, IEEE802154_ATTR_SHORT_ADDR, short_addr) ||
nla_put_shortaddr(msg, IEEE802154_ATTR_PAN_ID, pan_id))
goto nla_put_failure;
wpan_phy_put(phy);
return genlmsg_end(msg, hdr);
@ -322,16 +345,16 @@ int ieee802154_associate_req(struct sk_buff *skb, struct genl_info *info)
goto out;
if (info->attrs[IEEE802154_ATTR_COORD_HW_ADDR]) {
addr.addr_type = IEEE802154_ADDR_LONG;
nla_memcpy(addr.hwaddr,
info->attrs[IEEE802154_ATTR_COORD_HW_ADDR],
IEEE802154_ADDR_LEN);
addr.mode = IEEE802154_ADDR_LONG;
addr.extended_addr = nla_get_hwaddr(
info->attrs[IEEE802154_ATTR_COORD_HW_ADDR]);
} else {
addr.addr_type = IEEE802154_ADDR_SHORT;
addr.short_addr = nla_get_u16(
addr.mode = IEEE802154_ADDR_SHORT;
addr.short_addr = nla_get_shortaddr(
info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR]);
}
addr.pan_id = nla_get_u16(info->attrs[IEEE802154_ATTR_COORD_PAN_ID]);
addr.pan_id = nla_get_shortaddr(
info->attrs[IEEE802154_ATTR_COORD_PAN_ID]);
if (info->attrs[IEEE802154_ATTR_PAGE])
page = nla_get_u8(info->attrs[IEEE802154_ATTR_PAGE]);
@ -365,14 +388,13 @@ int ieee802154_associate_resp(struct sk_buff *skb, struct genl_info *info)
if (!ieee802154_mlme_ops(dev)->assoc_resp)
goto out;
addr.addr_type = IEEE802154_ADDR_LONG;
nla_memcpy(addr.hwaddr, info->attrs[IEEE802154_ATTR_DEST_HW_ADDR],
IEEE802154_ADDR_LEN);
addr.mode = IEEE802154_ADDR_LONG;
addr.extended_addr = nla_get_hwaddr(
info->attrs[IEEE802154_ATTR_DEST_HW_ADDR]);
addr.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev);
ret = ieee802154_mlme_ops(dev)->assoc_resp(dev, &addr,
nla_get_u16(info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]),
nla_get_shortaddr(info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]),
nla_get_u8(info->attrs[IEEE802154_ATTR_STATUS]));
out:
@ -398,13 +420,12 @@ int ieee802154_disassociate_req(struct sk_buff *skb, struct genl_info *info)
goto out;
if (info->attrs[IEEE802154_ATTR_DEST_HW_ADDR]) {
addr.addr_type = IEEE802154_ADDR_LONG;
nla_memcpy(addr.hwaddr,
info->attrs[IEEE802154_ATTR_DEST_HW_ADDR],
IEEE802154_ADDR_LEN);
addr.mode = IEEE802154_ADDR_LONG;
addr.extended_addr = nla_get_hwaddr(
info->attrs[IEEE802154_ATTR_DEST_HW_ADDR]);
} else {
addr.addr_type = IEEE802154_ADDR_SHORT;
addr.short_addr = nla_get_u16(
addr.mode = IEEE802154_ADDR_SHORT;
addr.short_addr = nla_get_shortaddr(
info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]);
}
addr.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev);
@ -449,10 +470,11 @@ int ieee802154_start_req(struct sk_buff *skb, struct genl_info *info)
if (!ieee802154_mlme_ops(dev)->start_req)
goto out;
addr.addr_type = IEEE802154_ADDR_SHORT;
addr.short_addr = nla_get_u16(
addr.mode = IEEE802154_ADDR_SHORT;
addr.short_addr = nla_get_shortaddr(
info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR]);
addr.pan_id = nla_get_u16(info->attrs[IEEE802154_ATTR_COORD_PAN_ID]);
addr.pan_id = nla_get_shortaddr(
info->attrs[IEEE802154_ATTR_COORD_PAN_ID]);
channel = nla_get_u8(info->attrs[IEEE802154_ATTR_CHANNEL]);
bcn_ord = nla_get_u8(info->attrs[IEEE802154_ATTR_BCN_ORD]);
@ -467,7 +489,7 @@ int ieee802154_start_req(struct sk_buff *skb, struct genl_info *info)
page = 0;
if (addr.short_addr == IEEE802154_ADDR_BROADCAST) {
if (addr.short_addr == cpu_to_le16(IEEE802154_ADDR_BROADCAST)) {
ieee802154_nl_start_confirm(dev, IEEE802154_NO_SHORT_ADDRESS);
dev_put(dev);
return -EINVAL;

View File

@ -28,6 +28,7 @@
#include <linux/slab.h>
#include <net/sock.h>
#include <net/af_ieee802154.h>
#include <net/ieee802154_netdev.h>
#include "af802154.h"
@ -55,21 +56,24 @@ static void raw_close(struct sock *sk, long timeout)
sk_common_release(sk);
}
static int raw_bind(struct sock *sk, struct sockaddr *uaddr, int len)
static int raw_bind(struct sock *sk, struct sockaddr *_uaddr, int len)
{
struct sockaddr_ieee802154 *addr = (struct sockaddr_ieee802154 *)uaddr;
struct ieee802154_addr addr;
struct sockaddr_ieee802154 *uaddr = (struct sockaddr_ieee802154 *)_uaddr;
int err = 0;
struct net_device *dev = NULL;
if (len < sizeof(*addr))
if (len < sizeof(*uaddr))
return -EINVAL;
if (addr->family != AF_IEEE802154)
uaddr = (struct sockaddr_ieee802154 *)_uaddr;
if (uaddr->family != AF_IEEE802154)
return -EINVAL;
lock_sock(sk);
dev = ieee802154_get_dev(sock_net(sk), &addr->addr);
ieee802154_addr_from_sa(&addr, &uaddr->addr);
dev = ieee802154_get_dev(sock_net(sk), &addr);
if (!dev) {
err = -ENODEV;
goto out;

View File

@ -30,6 +30,17 @@
#include "reassembly.h"
struct lowpan_frag_info {
__be16 d_tag;
u16 d_size;
u8 d_offset;
};
struct lowpan_frag_info *lowpan_cb(struct sk_buff *skb)
{
return (struct lowpan_frag_info *)skb->cb;
}
static struct inet_frags lowpan_frags;
static int lowpan_frag_reasm(struct lowpan_frag_queue *fq,
@ -65,8 +76,8 @@ static bool lowpan_frag_match(struct inet_frag_queue *q, void *a)
fq = container_of(q, struct lowpan_frag_queue, q);
return fq->tag == arg->tag && fq->d_size == arg->d_size &&
ieee802154_addr_addr_equal(&fq->saddr, arg->src) &&
ieee802154_addr_addr_equal(&fq->daddr, arg->dst);
ieee802154_addr_equal(&fq->saddr, arg->src) &&
ieee802154_addr_equal(&fq->daddr, arg->dst);
}
static void lowpan_frag_init(struct inet_frag_queue *q, void *a)
@ -102,8 +113,9 @@ out:
}
static inline struct lowpan_frag_queue *
fq_find(struct net *net, const struct ieee802154_frag_info *frag_info,
const struct ieee802154_addr *src, const struct ieee802154_addr *dst)
fq_find(struct net *net, const struct lowpan_frag_info *frag_info,
const struct ieee802154_addr *src,
const struct ieee802154_addr *dst)
{
struct inet_frag_queue *q;
struct lowpan_create_arg arg;
@ -136,8 +148,8 @@ static int lowpan_frag_queue(struct lowpan_frag_queue *fq,
if (fq->q.last_in & INET_FRAG_COMPLETE)
goto err;
offset = mac_cb(skb)->frag_info.d_offset << 3;
end = mac_cb(skb)->frag_info.d_size;
offset = lowpan_cb(skb)->d_offset << 3;
end = lowpan_cb(skb)->d_size;
/* Is this the final fragment? */
if (offset + skb->len == end) {
@ -163,15 +175,13 @@ static int lowpan_frag_queue(struct lowpan_frag_queue *fq,
* this fragment, right?
*/
prev = fq->q.fragments_tail;
if (!prev || mac_cb(prev)->frag_info.d_offset <
mac_cb(skb)->frag_info.d_offset) {
if (!prev || lowpan_cb(prev)->d_offset < lowpan_cb(skb)->d_offset) {
next = NULL;
goto found;
}
prev = NULL;
for (next = fq->q.fragments; next != NULL; next = next->next) {
if (mac_cb(next)->frag_info.d_offset >=
mac_cb(skb)->frag_info.d_offset)
if (lowpan_cb(next)->d_offset >= lowpan_cb(skb)->d_offset)
break; /* bingo! */
prev = next;
}
@ -318,7 +328,7 @@ out_oom:
}
static int lowpan_get_frag_info(struct sk_buff *skb, const u8 frag_type,
struct ieee802154_frag_info *frag_info)
struct lowpan_frag_info *frag_info)
{
bool fail;
u8 pattern = 0, low = 0;
@ -345,9 +355,13 @@ int lowpan_frag_rcv(struct sk_buff *skb, const u8 frag_type)
{
struct lowpan_frag_queue *fq;
struct net *net = dev_net(skb->dev);
struct ieee802154_frag_info *frag_info = &mac_cb(skb)->frag_info;
struct lowpan_frag_info *frag_info = lowpan_cb(skb);
struct ieee802154_addr source, dest;
int err;
source = mac_cb(skb)->source;
dest = mac_cb(skb)->dest;
err = lowpan_get_frag_info(skb, frag_type, frag_info);
if (err < 0)
goto err;
@ -357,7 +371,7 @@ int lowpan_frag_rcv(struct sk_buff *skb, const u8 frag_type)
inet_frag_evictor(&net->ieee802154_lowpan.frags, &lowpan_frags, false);
fq = fq_find(net, frag_info, &mac_cb(skb)->sa, &mac_cb(skb)->da);
fq = fq_find(net, frag_info, &source, &dest);
if (fq != NULL) {
int ret;
spin_lock(&fq->q.lock);

View File

@ -23,10 +23,10 @@ struct lowpan_frag_queue {
static inline u32 ieee802154_addr_hash(const struct ieee802154_addr *a)
{
switch (a->addr_type) {
switch (a->mode) {
case IEEE802154_ADDR_LONG:
return (__force u32)((((u32 *)a->hwaddr))[0] ^
((u32 *)(a->hwaddr))[1]);
return (((__force u64)a->extended_addr) >> 32) ^
(((__force u64)a->extended_addr) & 0xffffffff);
case IEEE802154_ADDR_SHORT:
return (__force u32)(a->short_addr);
default:
@ -34,31 +34,6 @@ static inline u32 ieee802154_addr_hash(const struct ieee802154_addr *a)
}
}
static inline bool ieee802154_addr_addr_equal(const struct ieee802154_addr *a1,
const struct ieee802154_addr *a2)
{
if (a1->pan_id != a2->pan_id)
return false;
if (a1->addr_type != a2->addr_type)
return false;
switch (a1->addr_type) {
case IEEE802154_ADDR_LONG:
if (memcmp(a1->hwaddr, a2->hwaddr, IEEE802154_ADDR_LEN))
return false;
break;
case IEEE802154_ADDR_SHORT:
if (a1->short_addr != a2->short_addr)
return false;
break;
default:
return false;
}
return true;
}
int lowpan_frag_rcv(struct sk_buff *skb, const u8 frag_type);
void lowpan_net_frag_exit(void);
int lowpan_net_frag_init(void);

View File

@ -1,2 +1,4 @@
obj-$(CONFIG_MAC802154) += mac802154.o
mac802154-objs := ieee802154_dev.o rx.o tx.o mac_cmd.o mib.o monitor.o wpan.o
ccflags-y += -D__CHECK_ENDIAN__

View File

@ -27,6 +27,7 @@
#include <net/netlink.h>
#include <linux/nl802154.h>
#include <net/mac802154.h>
#include <net/ieee802154_netdev.h>
#include <net/route.h>
#include <net/wpan-phy.h>
@ -46,7 +47,9 @@ int mac802154_slave_open(struct net_device *dev)
}
if (ipriv->ops->ieee_addr) {
res = ipriv->ops->ieee_addr(&ipriv->hw, dev->dev_addr);
__le64 addr = ieee802154_devaddr_from_raw(dev->dev_addr);
res = ipriv->ops->ieee_addr(&ipriv->hw, addr);
WARN_ON(res);
if (res)
goto err;

View File

@ -76,6 +76,7 @@ struct mac802154_sub_if_data {
__le16 pan_id;
__le16 short_addr;
__le64 extended_addr;
u8 chan;
u8 page;
@ -106,11 +107,11 @@ netdev_tx_t mac802154_tx(struct mac802154_priv *priv, struct sk_buff *skb,
u8 page, u8 chan);
/* MIB callbacks */
void mac802154_dev_set_short_addr(struct net_device *dev, u16 val);
u16 mac802154_dev_get_short_addr(const struct net_device *dev);
void mac802154_dev_set_short_addr(struct net_device *dev, __le16 val);
__le16 mac802154_dev_get_short_addr(const struct net_device *dev);
void mac802154_dev_set_ieee_addr(struct net_device *dev);
u16 mac802154_dev_get_pan_id(const struct net_device *dev);
void mac802154_dev_set_pan_id(struct net_device *dev, u16 val);
__le16 mac802154_dev_get_pan_id(const struct net_device *dev);
void mac802154_dev_set_pan_id(struct net_device *dev, __le16 val);
void mac802154_dev_set_page_channel(struct net_device *dev, u8 page, u8 chan);
u8 mac802154_dev_get_dsn(const struct net_device *dev);

View File

@ -40,7 +40,7 @@ static int mac802154_mlme_start_req(struct net_device *dev,
u8 pan_coord, u8 blx,
u8 coord_realign)
{
BUG_ON(addr->addr_type != IEEE802154_ADDR_SHORT);
BUG_ON(addr->mode != IEEE802154_ADDR_SHORT);
mac802154_dev_set_pan_id(dev, addr->pan_id);
mac802154_dev_set_short_addr(dev, addr->short_addr);

View File

@ -24,7 +24,9 @@
#include <linux/if_arp.h>
#include <net/mac802154.h>
#include <net/ieee802154_netdev.h>
#include <net/wpan-phy.h>
#include <net/ieee802154_netdev.h>
#include "mac802154.h"
@ -79,7 +81,7 @@ static void set_hw_addr_filt(struct net_device *dev, unsigned long changed)
queue_work(priv->hw->dev_workqueue, &work->work);
}
void mac802154_dev_set_short_addr(struct net_device *dev, u16 val)
void mac802154_dev_set_short_addr(struct net_device *dev, __le16 val)
{
struct mac802154_sub_if_data *priv = netdev_priv(dev);
@ -96,10 +98,10 @@ void mac802154_dev_set_short_addr(struct net_device *dev, u16 val)
}
}
u16 mac802154_dev_get_short_addr(const struct net_device *dev)
__le16 mac802154_dev_get_short_addr(const struct net_device *dev)
{
struct mac802154_sub_if_data *priv = netdev_priv(dev);
u16 ret;
__le16 ret;
BUG_ON(dev->type != ARPHRD_IEEE802154);
@ -115,19 +117,19 @@ void mac802154_dev_set_ieee_addr(struct net_device *dev)
struct mac802154_sub_if_data *priv = netdev_priv(dev);
struct mac802154_priv *mac = priv->hw;
priv->extended_addr = ieee802154_devaddr_from_raw(dev->dev_addr);
if (mac->ops->set_hw_addr_filt &&
memcmp(mac->hw.hw_filt.ieee_addr,
dev->dev_addr, IEEE802154_ADDR_LEN)) {
memcpy(mac->hw.hw_filt.ieee_addr,
dev->dev_addr, IEEE802154_ADDR_LEN);
mac->hw.hw_filt.ieee_addr != priv->extended_addr) {
mac->hw.hw_filt.ieee_addr = priv->extended_addr;
set_hw_addr_filt(dev, IEEE802515_AFILT_IEEEADDR_CHANGED);
}
}
u16 mac802154_dev_get_pan_id(const struct net_device *dev)
__le16 mac802154_dev_get_pan_id(const struct net_device *dev)
{
struct mac802154_sub_if_data *priv = netdev_priv(dev);
u16 ret;
__le16 ret;
BUG_ON(dev->type != ARPHRD_IEEE802154);
@ -138,7 +140,7 @@ u16 mac802154_dev_get_pan_id(const struct net_device *dev)
return ret;
}
void mac802154_dev_set_pan_id(struct net_device *dev, u16 val)
void mac802154_dev_set_pan_id(struct net_device *dev, __le16 val)
{
struct mac802154_sub_if_data *priv = netdev_priv(dev);

View File

@ -35,35 +35,6 @@
#include "mac802154.h"
static inline int mac802154_fetch_skb_u8(struct sk_buff *skb, u8 *val)
{
if (unlikely(!pskb_may_pull(skb, 1)))
return -EINVAL;
*val = skb->data[0];
skb_pull(skb, 1);
return 0;
}
static inline int mac802154_fetch_skb_u16(struct sk_buff *skb, u16 *val)
{
if (unlikely(!pskb_may_pull(skb, 2)))
return -EINVAL;
*val = skb->data[0] | (skb->data[1] << 8);
skb_pull(skb, 2);
return 0;
}
static inline void mac802154_haddr_copy_swap(u8 *dest, const u8 *src)
{
int i;
for (i = 0; i < IEEE802154_ADDR_LEN; i++)
dest[IEEE802154_ADDR_LEN - i - 1] = src[i];
}
static int
mac802154_wpan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
@ -76,19 +47,25 @@ mac802154_wpan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
switch (cmd) {
case SIOCGIFADDR:
if (priv->pan_id == IEEE802154_PANID_BROADCAST ||
priv->short_addr == IEEE802154_ADDR_BROADCAST) {
{
u16 pan_id, short_addr;
pan_id = le16_to_cpu(priv->pan_id);
short_addr = le16_to_cpu(priv->short_addr);
if (pan_id == IEEE802154_PANID_BROADCAST ||
short_addr == IEEE802154_ADDR_BROADCAST) {
err = -EADDRNOTAVAIL;
break;
}
sa->family = AF_IEEE802154;
sa->addr.addr_type = IEEE802154_ADDR_SHORT;
sa->addr.pan_id = priv->pan_id;
sa->addr.short_addr = priv->short_addr;
sa->addr.pan_id = pan_id;
sa->addr.short_addr = short_addr;
err = 0;
break;
}
case SIOCSIFADDR:
dev_warn(&dev->dev,
"Using DEBUGing ioctl SIOCSIFADDR isn't recommened!\n");
@ -101,8 +78,8 @@ mac802154_wpan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
break;
}
priv->pan_id = sa->addr.pan_id;
priv->short_addr = sa->addr.short_addr;
priv->pan_id = cpu_to_le16(sa->addr.pan_id);
priv->short_addr = cpu_to_le16(sa->addr.short_addr);
err = 0;
break;
@ -128,187 +105,70 @@ static int mac802154_wpan_mac_addr(struct net_device *dev, void *p)
static int mac802154_header_create(struct sk_buff *skb,
struct net_device *dev,
unsigned short type,
const void *_daddr,
const void *_saddr,
const void *daddr,
const void *saddr,
unsigned len)
{
const struct ieee802154_addr *saddr = _saddr;
const struct ieee802154_addr *daddr = _daddr;
struct ieee802154_addr dev_addr;
struct ieee802154_hdr hdr;
struct mac802154_sub_if_data *priv = netdev_priv(dev);
int pos = 2;
u8 head[MAC802154_FRAME_HARD_HEADER_LEN];
u16 fc;
int hlen;
if (!daddr)
return -EINVAL;
head[pos++] = mac_cb(skb)->seq; /* DSN/BSN */
fc = mac_cb_type(skb);
if (mac_cb_is_ackreq(skb))
fc |= IEEE802154_FC_ACK_REQ;
memset(&hdr.fc, 0, sizeof(hdr.fc));
hdr.fc.type = mac_cb_type(skb);
hdr.fc.security_enabled = mac_cb_is_secen(skb);
hdr.fc.ack_request = mac_cb_is_ackreq(skb);
if (!saddr) {
spin_lock_bh(&priv->mib_lock);
if (priv->short_addr == IEEE802154_ADDR_BROADCAST ||
priv->short_addr == IEEE802154_ADDR_UNDEF ||
priv->pan_id == IEEE802154_PANID_BROADCAST) {
dev_addr.addr_type = IEEE802154_ADDR_LONG;
memcpy(dev_addr.hwaddr, dev->dev_addr,
IEEE802154_ADDR_LEN);
if (priv->short_addr == cpu_to_le16(IEEE802154_ADDR_BROADCAST) ||
priv->short_addr == cpu_to_le16(IEEE802154_ADDR_UNDEF) ||
priv->pan_id == cpu_to_le16(IEEE802154_PANID_BROADCAST)) {
hdr.source.mode = IEEE802154_ADDR_LONG;
hdr.source.extended_addr = priv->extended_addr;
} else {
dev_addr.addr_type = IEEE802154_ADDR_SHORT;
dev_addr.short_addr = priv->short_addr;
hdr.source.mode = IEEE802154_ADDR_SHORT;
hdr.source.short_addr = priv->short_addr;
}
dev_addr.pan_id = priv->pan_id;
saddr = &dev_addr;
hdr.source.pan_id = priv->pan_id;
spin_unlock_bh(&priv->mib_lock);
} else {
hdr.source = *(const struct ieee802154_addr *)saddr;
}
if (daddr->addr_type != IEEE802154_ADDR_NONE) {
fc |= (daddr->addr_type << IEEE802154_FC_DAMODE_SHIFT);
hdr.dest = *(const struct ieee802154_addr *)daddr;
head[pos++] = daddr->pan_id & 0xff;
head[pos++] = daddr->pan_id >> 8;
hlen = ieee802154_hdr_push(skb, &hdr);
if (hlen < 0)
return -EINVAL;
if (daddr->addr_type == IEEE802154_ADDR_SHORT) {
head[pos++] = daddr->short_addr & 0xff;
head[pos++] = daddr->short_addr >> 8;
} else {
mac802154_haddr_copy_swap(head + pos, daddr->hwaddr);
pos += IEEE802154_ADDR_LEN;
}
}
if (saddr->addr_type != IEEE802154_ADDR_NONE) {
fc |= (saddr->addr_type << IEEE802154_FC_SAMODE_SHIFT);
if ((saddr->pan_id == daddr->pan_id) &&
(saddr->pan_id != IEEE802154_PANID_BROADCAST)) {
/* PANID compression/intra PAN */
fc |= IEEE802154_FC_INTRA_PAN;
} else {
head[pos++] = saddr->pan_id & 0xff;
head[pos++] = saddr->pan_id >> 8;
}
if (saddr->addr_type == IEEE802154_ADDR_SHORT) {
head[pos++] = saddr->short_addr & 0xff;
head[pos++] = saddr->short_addr >> 8;
} else {
mac802154_haddr_copy_swap(head + pos, saddr->hwaddr);
pos += IEEE802154_ADDR_LEN;
}
}
head[0] = fc;
head[1] = fc >> 8;
memcpy(skb_push(skb, pos), head, pos);
skb_reset_mac_header(skb);
skb->mac_len = pos;
skb->mac_len = hlen;
return pos;
if (hlen + len + 2 > dev->mtu)
return -EMSGSIZE;
return hlen;
}
static int
mac802154_header_parse(const struct sk_buff *skb, unsigned char *haddr)
{
const u8 *hdr = skb_mac_header(skb);
const u8 *tail = skb_tail_pointer(skb);
struct ieee802154_hdr hdr;
struct ieee802154_addr *addr = (struct ieee802154_addr *)haddr;
u16 fc;
int da_type;
if (hdr + 3 > tail)
goto malformed;
fc = hdr[0] | (hdr[1] << 8);
hdr += 3;
da_type = IEEE802154_FC_DAMODE(fc);
addr->addr_type = IEEE802154_FC_SAMODE(fc);
switch (da_type) {
case IEEE802154_ADDR_NONE:
if (fc & IEEE802154_FC_INTRA_PAN)
goto malformed;
break;
case IEEE802154_ADDR_LONG:
if (fc & IEEE802154_FC_INTRA_PAN) {
if (hdr + 2 > tail)
goto malformed;
addr->pan_id = hdr[0] | (hdr[1] << 8);
hdr += 2;
}
if (hdr + IEEE802154_ADDR_LEN > tail)
goto malformed;
hdr += IEEE802154_ADDR_LEN;
break;
case IEEE802154_ADDR_SHORT:
if (fc & IEEE802154_FC_INTRA_PAN) {
if (hdr + 2 > tail)
goto malformed;
addr->pan_id = hdr[0] | (hdr[1] << 8);
hdr += 2;
}
if (hdr + 2 > tail)
goto malformed;
hdr += 2;
break;
default:
goto malformed;
if (ieee802154_hdr_peek_addrs(skb, &hdr) < 0) {
pr_debug("malformed packet\n");
return 0;
}
switch (addr->addr_type) {
case IEEE802154_ADDR_NONE:
break;
case IEEE802154_ADDR_LONG:
if (!(fc & IEEE802154_FC_INTRA_PAN)) {
if (hdr + 2 > tail)
goto malformed;
addr->pan_id = hdr[0] | (hdr[1] << 8);
hdr += 2;
}
if (hdr + IEEE802154_ADDR_LEN > tail)
goto malformed;
mac802154_haddr_copy_swap(addr->hwaddr, hdr);
hdr += IEEE802154_ADDR_LEN;
break;
case IEEE802154_ADDR_SHORT:
if (!(fc & IEEE802154_FC_INTRA_PAN)) {
if (hdr + 2 > tail)
goto malformed;
addr->pan_id = hdr[0] | (hdr[1] << 8);
hdr += 2;
}
if (hdr + 2 > tail)
goto malformed;
addr->short_addr = hdr[0] | (hdr[1] << 8);
hdr += 2;
break;
default:
goto malformed;
}
return sizeof(struct ieee802154_addr);
malformed:
pr_debug("malformed packet\n");
return 0;
*addr = hdr.source;
return sizeof(*addr);
}
static netdev_tx_t
@ -382,8 +242,8 @@ void mac802154_wpan_setup(struct net_device *dev)
get_random_bytes(&priv->bsn, 1);
get_random_bytes(&priv->dsn, 1);
priv->pan_id = IEEE802154_PANID_BROADCAST;
priv->short_addr = IEEE802154_ADDR_BROADCAST;
priv->pan_id = cpu_to_le16(IEEE802154_PANID_BROADCAST);
priv->short_addr = cpu_to_le16(IEEE802154_ADDR_BROADCAST);
}
static int mac802154_process_data(struct net_device *dev, struct sk_buff *skb)
@ -394,13 +254,18 @@ static int mac802154_process_data(struct net_device *dev, struct sk_buff *skb)
static int
mac802154_subif_frame(struct mac802154_sub_if_data *sdata, struct sk_buff *skb)
{
__le16 span, sshort;
pr_debug("getting packet via slave interface %s\n", sdata->dev->name);
spin_lock_bh(&sdata->mib_lock);
switch (mac_cb(skb)->da.addr_type) {
span = sdata->pan_id;
sshort = sdata->short_addr;
switch (mac_cb(skb)->dest.mode) {
case IEEE802154_ADDR_NONE:
if (mac_cb(skb)->sa.addr_type != 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
@ -408,23 +273,22 @@ mac802154_subif_frame(struct mac802154_sub_if_data *sdata, struct sk_buff *skb)
skb->pkt_type = PACKET_HOST;
break;
case IEEE802154_ADDR_LONG:
if (mac_cb(skb)->da.pan_id != sdata->pan_id &&
mac_cb(skb)->da.pan_id != IEEE802154_PANID_BROADCAST)
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 (!memcmp(mac_cb(skb)->da.hwaddr, sdata->dev->dev_addr,
IEEE802154_ADDR_LEN))
else if (mac_cb(skb)->dest.extended_addr == sdata->extended_addr)
skb->pkt_type = PACKET_HOST;
else
skb->pkt_type = PACKET_OTHERHOST;
break;
case IEEE802154_ADDR_SHORT:
if (mac_cb(skb)->da.pan_id != sdata->pan_id &&
mac_cb(skb)->da.pan_id != IEEE802154_PANID_BROADCAST)
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)->da.short_addr == sdata->short_addr)
else if (mac_cb(skb)->dest.short_addr == sshort)
skb->pkt_type = PACKET_HOST;
else if (mac_cb(skb)->da.short_addr ==
IEEE802154_ADDR_BROADCAST)
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;
@ -451,88 +315,82 @@ mac802154_subif_frame(struct mac802154_sub_if_data *sdata, struct sk_buff *skb)
}
}
static void mac802154_print_addr(const char *name,
const struct ieee802154_addr *addr)
{
if (addr->mode == IEEE802154_ADDR_NONE)
pr_debug("%s not present\n", name);
pr_debug("%s PAN ID: %04x\n", name, le16_to_cpu(addr->pan_id));
if (addr->mode == IEEE802154_ADDR_SHORT) {
pr_debug("%s is short: %04x\n", name,
le16_to_cpu(addr->short_addr));
} else {
u64 hw = swab64((__force u64) addr->extended_addr);
pr_debug("%s is hardware: %8phC\n", name, &hw);
}
}
static int mac802154_parse_frame_start(struct sk_buff *skb)
{
u8 *head = skb->data;
u16 fc;
int hlen;
struct ieee802154_hdr hdr;
if (mac802154_fetch_skb_u16(skb, &fc) ||
mac802154_fetch_skb_u8(skb, &(mac_cb(skb)->seq)))
goto err;
hlen = ieee802154_hdr_pull(skb, &hdr);
if (hlen < 0)
return -EINVAL;
pr_debug("fc: %04x dsn: %02x\n", fc, head[2]);
skb->mac_len = hlen;
mac_cb(skb)->flags = IEEE802154_FC_TYPE(fc);
mac_cb(skb)->sa.addr_type = IEEE802154_FC_SAMODE(fc);
mac_cb(skb)->da.addr_type = IEEE802154_FC_DAMODE(fc);
pr_debug("fc: %04x dsn: %02x\n", le16_to_cpup((__le16 *)&hdr.fc),
hdr.seq);
if (fc & IEEE802154_FC_INTRA_PAN)
mac_cb(skb)->flags |= MAC_CB_FLAG_INTRAPAN;
mac_cb(skb)->flags = hdr.fc.type;
if (mac_cb(skb)->da.addr_type != IEEE802154_ADDR_NONE) {
if (mac802154_fetch_skb_u16(skb, &(mac_cb(skb)->da.pan_id)))
goto err;
if (hdr.fc.ack_request)
mac_cb(skb)->flags |= MAC_CB_FLAG_ACKREQ;
if (hdr.fc.security_enabled)
mac_cb(skb)->flags |= MAC_CB_FLAG_SECEN;
/* source PAN id compression */
if (mac_cb_is_intrapan(skb))
mac_cb(skb)->sa.pan_id = mac_cb(skb)->da.pan_id;
mac802154_print_addr("destination", &hdr.dest);
mac802154_print_addr("source", &hdr.source);
pr_debug("dest PAN addr: %04x\n", mac_cb(skb)->da.pan_id);
mac_cb(skb)->source = hdr.source;
mac_cb(skb)->dest = hdr.dest;
if (mac_cb(skb)->da.addr_type == IEEE802154_ADDR_SHORT) {
u16 *da = &(mac_cb(skb)->da.short_addr);
if (hdr.fc.security_enabled) {
u64 key;
if (mac802154_fetch_skb_u16(skb, da))
goto err;
pr_debug("seclevel %i\n", hdr.sec.level);
pr_debug("destination address is short: %04x\n",
mac_cb(skb)->da.short_addr);
} else {
if (!pskb_may_pull(skb, IEEE802154_ADDR_LEN))
goto err;
switch (hdr.sec.key_id_mode) {
case IEEE802154_SCF_KEY_IMPLICIT:
pr_debug("implicit key\n");
break;
mac802154_haddr_copy_swap(mac_cb(skb)->da.hwaddr,
skb->data);
skb_pull(skb, IEEE802154_ADDR_LEN);
case IEEE802154_SCF_KEY_INDEX:
pr_debug("key %02x\n", hdr.sec.key_id);
break;
pr_debug("destination address is hardware\n");
}
}
case IEEE802154_SCF_KEY_SHORT_INDEX:
pr_debug("key %04x:%04x %02x\n",
le32_to_cpu(hdr.sec.short_src) >> 16,
le32_to_cpu(hdr.sec.short_src) & 0xffff,
hdr.sec.key_id);
break;
if (mac_cb(skb)->sa.addr_type != IEEE802154_ADDR_NONE) {
/* non PAN-compression, fetch source address id */
if (!(mac_cb_is_intrapan(skb))) {
u16 *sa_pan = &(mac_cb(skb)->sa.pan_id);
if (mac802154_fetch_skb_u16(skb, sa_pan))
goto err;
case IEEE802154_SCF_KEY_HW_INDEX:
key = swab64((__force u64) hdr.sec.extended_src);
pr_debug("key source %8phC %02x\n", &key,
hdr.sec.key_id);
break;
}
pr_debug("source PAN addr: %04x\n", mac_cb(skb)->da.pan_id);
if (mac_cb(skb)->sa.addr_type == IEEE802154_ADDR_SHORT) {
u16 *sa = &(mac_cb(skb)->sa.short_addr);
if (mac802154_fetch_skb_u16(skb, sa))
goto err;
pr_debug("source address is short: %04x\n",
mac_cb(skb)->sa.short_addr);
} else {
if (!pskb_may_pull(skb, IEEE802154_ADDR_LEN))
goto err;
mac802154_haddr_copy_swap(mac_cb(skb)->sa.hwaddr,
skb->data);
skb_pull(skb, IEEE802154_ADDR_LEN);
pr_debug("source address is hardware\n");
}
return -EINVAL;
}
return 0;
err:
return -EINVAL;
}
void mac802154_wpans_rx(struct mac802154_priv *priv, struct sk_buff *skb)