Commit 983f5961 authored by David S. Miller's avatar David S. Miller

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: default avatarDavid S. Miller <davem@davemloft.net>
parents 17794326 d1d7358e
...@@ -745,30 +745,31 @@ at86rf230_set_hw_addr_filt(struct ieee802154_dev *dev, ...@@ -745,30 +745,31 @@ at86rf230_set_hw_addr_filt(struct ieee802154_dev *dev,
struct at86rf230_local *lp = dev->priv; struct at86rf230_local *lp = dev->priv;
if (changed & IEEE802515_AFILT_SADDR_CHANGED) { if (changed & IEEE802515_AFILT_SADDR_CHANGED) {
u16 addr = le16_to_cpu(filt->short_addr);
dev_vdbg(&lp->spi->dev, dev_vdbg(&lp->spi->dev,
"at86rf230_set_hw_addr_filt called for saddr\n"); "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_0, addr);
__at86rf230_write(lp, RG_SHORT_ADDR_1, filt->short_addr >> 8); __at86rf230_write(lp, RG_SHORT_ADDR_1, addr >> 8);
} }
if (changed & IEEE802515_AFILT_PANID_CHANGED) { if (changed & IEEE802515_AFILT_PANID_CHANGED) {
u16 pan = le16_to_cpu(filt->pan_id);
dev_vdbg(&lp->spi->dev, dev_vdbg(&lp->spi->dev,
"at86rf230_set_hw_addr_filt called for pan id\n"); "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_0, pan);
__at86rf230_write(lp, RG_PAN_ID_1, filt->pan_id >> 8); __at86rf230_write(lp, RG_PAN_ID_1, pan >> 8);
} }
if (changed & IEEE802515_AFILT_IEEEADDR_CHANGED) { if (changed & IEEE802515_AFILT_IEEEADDR_CHANGED) {
u8 i, addr[8];
memcpy(addr, &filt->ieee_addr, 8);
dev_vdbg(&lp->spi->dev, dev_vdbg(&lp->spi->dev,
"at86rf230_set_hw_addr_filt called for IEEE addr\n"); "at86rf230_set_hw_addr_filt called for IEEE addr\n");
at86rf230_write_subreg(lp, SR_IEEE_ADDR_0, filt->ieee_addr[7]); for (i = 0; i < 8; i++)
at86rf230_write_subreg(lp, SR_IEEE_ADDR_1, filt->ieee_addr[6]); __at86rf230_write(lp, RG_IEEE_ADDR_0 + i, addr[i]);
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]);
} }
if (changed & IEEE802515_AFILT_PANC_CHANGED) { if (changed & IEEE802515_AFILT_PANC_CHANGED) {
......
...@@ -63,11 +63,11 @@ static struct wpan_phy *fake_get_phy(const struct net_device *dev) ...@@ -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. * 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); 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) ...@@ -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 * device. If the device has not yet had a short address assigned
* then this should return 0xFFFF to indicate a lack of association. * 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); 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, ...@@ -149,7 +149,7 @@ static int fake_assoc_req(struct net_device *dev,
* 802.15.4-2006 document. * 802.15.4-2006 document.
*/ */
static int fake_assoc_resp(struct net_device *dev, 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; return 0;
} }
...@@ -191,10 +191,10 @@ static int fake_disassoc_req(struct net_device *dev, ...@@ -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 * Note: This is in section 7.5.2.3 of the IEEE 802.15.4-2006
* document, with 7.3.8 describing coordinator realignment. * document, with 7.3.8 describing coordinator realignment.
*/ */
static int fake_start_req(struct net_device *dev, struct ieee802154_addr *addr, static int fake_start_req(struct net_device *dev,
u8 channel, u8 page, struct ieee802154_addr *addr, u8 channel, u8 page,
u8 bcn_ord, u8 sf_ord, u8 pan_coord, u8 blx, u8 bcn_ord, u8 sf_ord, u8 pan_coord, u8 blx,
u8 coord_realign) u8 coord_realign)
{ {
struct wpan_phy *phy = fake_to_phy(dev); struct wpan_phy *phy = fake_to_phy(dev);
...@@ -281,8 +281,8 @@ static int ieee802154_fake_ioctl(struct net_device *dev, struct ifreq *ifr, ...@@ -281,8 +281,8 @@ static int ieee802154_fake_ioctl(struct net_device *dev, struct ifreq *ifr,
switch (cmd) { switch (cmd) {
case SIOCGIFADDR: case SIOCGIFADDR:
/* FIXME: fixed here, get from device IRL */ /* FIXME: fixed here, get from device IRL */
pan_id = fake_get_pan_id(dev); pan_id = le16_to_cpu(fake_get_pan_id(dev));
short_addr = fake_get_short_addr(dev); short_addr = le16_to_cpu(fake_get_short_addr(dev));
if (pan_id == IEEE802154_PANID_BROADCAST || if (pan_id == IEEE802154_PANID_BROADCAST ||
short_addr == IEEE802154_ADDR_BROADCAST) short_addr == IEEE802154_ADDR_BROADCAST)
return -EADDRNOTAVAIL; return -EADDRNOTAVAIL;
......
...@@ -465,8 +465,8 @@ static int mrf24j40_filter(struct ieee802154_dev *dev, ...@@ -465,8 +465,8 @@ static int mrf24j40_filter(struct ieee802154_dev *dev,
if (changed & IEEE802515_AFILT_SADDR_CHANGED) { if (changed & IEEE802515_AFILT_SADDR_CHANGED) {
/* Short Addr */ /* Short Addr */
u8 addrh, addrl; u8 addrh, addrl;
addrh = filt->short_addr >> 8 & 0xff; addrh = le16_to_cpu(filt->short_addr) >> 8 & 0xff;
addrl = filt->short_addr & 0xff; addrl = le16_to_cpu(filt->short_addr) & 0xff;
write_short_reg(devrec, REG_SADRH, addrh); write_short_reg(devrec, REG_SADRH, addrh);
write_short_reg(devrec, REG_SADRL, addrl); write_short_reg(devrec, REG_SADRL, addrl);
...@@ -476,15 +476,16 @@ static int mrf24j40_filter(struct ieee802154_dev *dev, ...@@ -476,15 +476,16 @@ static int mrf24j40_filter(struct ieee802154_dev *dev,
if (changed & IEEE802515_AFILT_IEEEADDR_CHANGED) { if (changed & IEEE802515_AFILT_IEEEADDR_CHANGED) {
/* Device Address */ /* Device Address */
int i; u8 i, addr[8];
memcpy(addr, &filt->ieee_addr, 8);
for (i = 0; i < 8; i++) for (i = 0; i < 8; i++)
write_short_reg(devrec, REG_EADR0+i, write_short_reg(devrec, REG_EADR0 + i, addr[i]);
filt->ieee_addr[7-i]);
#ifdef DEBUG #ifdef DEBUG
printk(KERN_DEBUG "Set long addr to: "); printk(KERN_DEBUG "Set long addr to: ");
for (i = 0; i < 8; i++) for (i = 0; i < 8; i++)
printk("%02hhx ", filt->ieee_addr[i]); printk("%02hhx ", addr[7 - i]);
printk(KERN_DEBUG "\n"); printk(KERN_DEBUG "\n");
#endif #endif
} }
...@@ -492,8 +493,8 @@ static int mrf24j40_filter(struct ieee802154_dev *dev, ...@@ -492,8 +493,8 @@ static int mrf24j40_filter(struct ieee802154_dev *dev,
if (changed & IEEE802515_AFILT_PANID_CHANGED) { if (changed & IEEE802515_AFILT_PANID_CHANGED) {
/* PAN ID */ /* PAN ID */
u8 panidl, panidh; u8 panidl, panidh;
panidh = filt->pan_id >> 8 & 0xff; panidh = le16_to_cpu(filt->pan_id) >> 8 & 0xff;
panidl = filt->pan_id & 0xff; panidl = le16_to_cpu(filt->pan_id) & 0xff;
write_short_reg(devrec, REG_PANIDH, panidh); write_short_reg(devrec, REG_PANIDH, panidh);
write_short_reg(devrec, REG_PANIDL, panidl); write_short_reg(devrec, REG_PANIDL, panidl);
......
...@@ -36,7 +36,7 @@ enum { ...@@ -36,7 +36,7 @@ enum {
/* address length, octets */ /* address length, octets */
#define IEEE802154_ADDR_LEN 8 #define IEEE802154_ADDR_LEN 8
struct ieee802154_addr { struct ieee802154_addr_sa {
int addr_type; int addr_type;
u16 pan_id; u16 pan_id;
union { union {
...@@ -51,7 +51,7 @@ struct ieee802154_addr { ...@@ -51,7 +51,7 @@ struct ieee802154_addr {
struct sockaddr_ieee802154 { struct sockaddr_ieee802154 {
sa_family_t family; /* AF_IEEE802154 */ sa_family_t family; /* AF_IEEE802154 */
struct ieee802154_addr addr; struct ieee802154_addr_sa addr;
}; };
/* get/setsockopt */ /* get/setsockopt */
......
...@@ -42,22 +42,42 @@ ...@@ -42,22 +42,42 @@
(((x) << IEEE802154_FC_TYPE_SHIFT) & IEEE802154_FC_TYPE_MASK)); \ (((x) << IEEE802154_FC_TYPE_SHIFT) & IEEE802154_FC_TYPE_MASK)); \
} while (0) } while (0)
#define IEEE802154_FC_SECEN (1 << 3) #define IEEE802154_FC_SECEN_SHIFT 3
#define IEEE802154_FC_FRPEND (1 << 4) #define IEEE802154_FC_SECEN (1 << IEEE802154_FC_SECEN_SHIFT)
#define IEEE802154_FC_ACK_REQ (1 << 5) #define IEEE802154_FC_FRPEND_SHIFT 4
#define IEEE802154_FC_INTRA_PAN (1 << 6) #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_SHIFT 14
#define IEEE802154_FC_SAMODE_MASK (3 << IEEE802154_FC_SAMODE_SHIFT) #define IEEE802154_FC_SAMODE_MASK (3 << IEEE802154_FC_SAMODE_SHIFT)
#define IEEE802154_FC_DAMODE_SHIFT 10 #define IEEE802154_FC_DAMODE_SHIFT 10
#define IEEE802154_FC_DAMODE_MASK (3 << IEEE802154_FC_DAMODE_SHIFT) #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) \ #define IEEE802154_FC_SAMODE(x) \
(((x) & IEEE802154_FC_SAMODE_MASK) >> IEEE802154_FC_SAMODE_SHIFT) (((x) & IEEE802154_FC_SAMODE_MASK) >> IEEE802154_FC_SAMODE_SHIFT)
#define IEEE802154_FC_DAMODE(x) \ #define IEEE802154_FC_DAMODE(x) \
(((x) & IEEE802154_FC_DAMODE_MASK) >> IEEE802154_FC_DAMODE_SHIFT) (((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 */ /* MAC footer size */
#define IEEE802154_MFR_SIZE 2 /* 2 octets */ #define IEEE802154_MFR_SIZE 2 /* 2 octets */
......
...@@ -28,24 +28,175 @@ ...@@ -28,24 +28,175 @@
#define IEEE802154_NETDEVICE_H #define IEEE802154_NETDEVICE_H
#include <net/af_ieee802154.h> #include <net/af_ieee802154.h>
#include <linux/netdevice.h>
#include <linux/skbuff.h>
struct ieee802154_frag_info { struct ieee802154_sechdr {
__be16 d_tag; #if defined(__LITTLE_ENDIAN_BITFIELD)
u16 d_size; u8 level:3,
u8 d_offset; 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 * A control block of skb passed between the ARPHRD_IEEE802154 device
* and other stack parts. * and other stack parts.
*/ */
struct ieee802154_mac_cb { struct ieee802154_mac_cb {
u8 lqi; u8 lqi;
struct ieee802154_addr sa;
struct ieee802154_addr da;
u8 flags; u8 flags;
u8 seq; 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) 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) ...@@ -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_ACKREQ (1 << 3)
#define MAC_CB_FLAG_SECEN (1 << 4) #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; 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; 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) static inline int mac_cb_type(struct sk_buff *skb)
{ {
return mac_cb(skb)->flags & MAC_CB_FLAG_TYPEMASK; return mac_cb(skb)->flags & MAC_CB_FLAG_TYPEMASK;
...@@ -99,7 +244,7 @@ struct ieee802154_mlme_ops { ...@@ -99,7 +244,7 @@ struct ieee802154_mlme_ops {
u8 channel, u8 page, u8 cap); u8 channel, u8 page, u8 cap);
int (*assoc_resp)(struct net_device *dev, int (*assoc_resp)(struct net_device *dev,
struct ieee802154_addr *addr, struct ieee802154_addr *addr,
u16 short_addr, u8 status); __le16 short_addr, u8 status);
int (*disassoc_req)(struct net_device *dev, int (*disassoc_req)(struct net_device *dev,
struct ieee802154_addr *addr, struct ieee802154_addr *addr,
u8 reason); u8 reason);
...@@ -118,8 +263,8 @@ struct ieee802154_mlme_ops { ...@@ -118,8 +263,8 @@ struct ieee802154_mlme_ops {
* FIXME: these should become the part of PIB/MIB interface. * FIXME: these should become the part of PIB/MIB interface.
* However we still don't have IB interface of any kind * However we still don't have IB interface of any kind
*/ */
u16 (*get_pan_id)(const struct net_device *dev); __le16 (*get_pan_id)(const struct net_device *dev);
u16 (*get_short_addr)(const struct net_device *dev); __le16 (*get_short_addr)(const struct net_device *dev);
u8 (*get_dsn)(const struct net_device *dev); u8 (*get_dsn)(const struct net_device *dev);
}; };
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#define NET_MAC802154_H #define NET_MAC802154_H
#include <net/af_ieee802154.h> #include <net/af_ieee802154.h>
#include <linux/skbuff.h>
/* General MAC frame format: /* General MAC frame format:
* 2 bytes: Frame Control * 2 bytes: Frame Control
...@@ -50,7 +51,7 @@ struct ieee802154_hw_addr_filt { ...@@ -50,7 +51,7 @@ struct ieee802154_hw_addr_filt {
* devices across independent networks. * devices across independent networks.
*/ */
__le16 short_addr; __le16 short_addr;
u8 ieee_addr[IEEE802154_ADDR_LEN]; __le64 ieee_addr;
u8 pan_coord; u8 pan_coord;
}; };
...@@ -153,8 +154,7 @@ struct ieee802154_ops { ...@@ -153,8 +154,7 @@ struct ieee802154_ops {
int (*set_hw_addr_filt)(struct ieee802154_dev *dev, int (*set_hw_addr_filt)(struct ieee802154_dev *dev,
struct ieee802154_hw_addr_filt *filt, struct ieee802154_hw_addr_filt *filt,
unsigned long changed); unsigned long changed);
int (*ieee_addr)(struct ieee802154_dev *dev, int (*ieee_addr)(struct ieee802154_dev *dev, __le64 addr);
u8 addr[IEEE802154_ADDR_LEN]);
int (*set_txpower)(struct ieee802154_dev *dev, int db); int (*set_txpower)(struct ieee802154_dev *dev, int db);
int (*set_lbt)(struct ieee802154_dev *dev, bool on); int (*set_lbt)(struct ieee802154_dev *dev, bool on);
int (*set_cca_mode)(struct ieee802154_dev *dev, u8 mode); int (*set_cca_mode)(struct ieee802154_dev *dev, u8 mode);
......
...@@ -52,7 +52,7 @@ int ieee802154_nl_assoc_indic(struct net_device *dev, ...@@ -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. * Note: This is in section 7.3.2 of the IEEE 802.15.4 document.
*/ */
int ieee802154_nl_assoc_confirm(struct net_device *dev, 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. * ieee802154_nl_disassoc_indic - Notify userland of disassociation.
...@@ -111,8 +111,8 @@ int ieee802154_nl_scan_confirm(struct net_device *dev, ...@@ -111,8 +111,8 @@ int ieee802154_nl_scan_confirm(struct net_device *dev,
* Note: This API cannot indicate a beacon frame for a coordinator * Note: This API cannot indicate a beacon frame for a coordinator
* operating in long addressing mode. * operating in long addressing mode.
*/ */
int ieee802154_nl_beacon_indic(struct net_device *dev, u16 panid, int ieee802154_nl_beacon_indic(struct net_device *dev, __le16 panid,
u16 coord_addr); __le16 coord_addr);
/** /**
* ieee802154_nl_start_confirm - Notify userland of completion of start. * ieee802154_nl_start_confirm - Notify userland of completion of start.
......
...@@ -119,29 +119,29 @@ static int lowpan_header_create(struct sk_buff *skb, ...@@ -119,29 +119,29 @@ static int lowpan_header_create(struct sk_buff *skb,
mac_cb(skb)->seq = ieee802154_mlme_ops(dev)->get_dsn(dev); mac_cb(skb)->seq = ieee802154_mlme_ops(dev)->get_dsn(dev);
/* prepare wpan address data */ /* 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.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 */ /* 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 /* if the destination address is the broadcast address, use the
* corresponding short address * corresponding short address
*/ */
if (lowpan_is_addr_broadcast(daddr)) { if (lowpan_is_addr_broadcast(daddr)) {
da.addr_type = IEEE802154_ADDR_SHORT; da.mode = IEEE802154_ADDR_SHORT;
da.short_addr = IEEE802154_ADDR_BROADCAST; da.short_addr = cpu_to_le16(IEEE802154_ADDR_BROADCAST);
} else { } else {
da.addr_type = IEEE802154_ADDR_LONG; da.mode = IEEE802154_ADDR_LONG;
memcpy(&(da.hwaddr), daddr, IEEE802154_ADDR_LEN); da.extended_addr = ieee802154_devaddr_from_raw(daddr);
/* request acknowledgment */ /* request acknowledgment */
mac_cb(skb)->flags |= MAC_CB_FLAG_ACKREQ; mac_cb(skb)->flags |= MAC_CB_FLAG_ACKREQ;
} }
return dev_hard_header(skb, lowpan_dev_info(dev)->real_dev, 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, 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, ...@@ -168,10 +168,11 @@ static int lowpan_give_skb_to_devices(struct sk_buff *skb,
return stat; 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; 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); raw_dump_table(__func__, "raw skb data dump", skb->data, skb->len);
/* at least two bytes will be used for the encoding */ /* at least two bytes will be used for the encoding */
...@@ -184,14 +185,23 @@ static int process_data(struct sk_buff *skb) ...@@ -184,14 +185,23 @@ static int process_data(struct sk_buff *skb)
if (lowpan_fetch_skb_u8(skb, &iphc1)) if (lowpan_fetch_skb_u8(skb, &iphc1))
goto drop; goto drop;
_saddr = &mac_cb(skb)->sa; ieee802154_addr_to_sa(&sa, &hdr->source);
_daddr = &mac_cb(skb)->da; ieee802154_addr_to_sa(&da, &hdr->dest);
return lowpan_process_data(skb, skb->dev, (u8 *)_saddr->hwaddr, if (sa.addr_type == IEEE802154_ADDR_SHORT)
_saddr->addr_type, IEEE802154_ADDR_LEN, sap = &sa.short_addr;
(u8 *)_daddr->hwaddr, _daddr->addr_type, else
IEEE802154_ADDR_LEN, iphc0, iphc1, sap = &sa.hwaddr;
lowpan_give_skb_to_devices);
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: drop:
kfree_skb(skb); kfree_skb(skb);
...@@ -352,13 +362,13 @@ static struct wpan_phy *lowpan_get_phy(const struct net_device *dev) ...@@ -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); 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; struct net_device *real_dev = lowpan_dev_info(dev)->real_dev;
return ieee802154_mlme_ops(real_dev)->get_pan_id(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; struct net_device *real_dev = lowpan_dev_info(dev)->real_dev;
return ieee802154_mlme_ops(real_dev)->get_short_addr(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, ...@@ -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 packet_type *pt, struct net_device *orig_dev)
{ {
struct sk_buff *local_skb; struct sk_buff *local_skb;
struct ieee802154_hdr hdr;
int ret; int ret;
if (!netif_running(dev)) if (!netif_running(dev))
...@@ -446,6 +457,9 @@ static int lowpan_rcv(struct sk_buff *skb, struct net_device *dev, ...@@ -446,6 +457,9 @@ static int lowpan_rcv(struct sk_buff *skb, struct net_device *dev,
if (dev->type != ARPHRD_IEEE802154) if (dev->type != ARPHRD_IEEE802154)
goto drop_skb; goto drop_skb;
if (ieee802154_hdr_peek_addrs(skb, &hdr) < 0)
goto drop_skb;
local_skb = skb_clone(skb, GFP_ATOMIC); local_skb = skb_clone(skb, GFP_ATOMIC);
if (!local_skb) if (!local_skb)
goto drop_skb; goto drop_skb;
...@@ -466,14 +480,14 @@ static int lowpan_rcv(struct sk_buff *skb, struct net_device *dev, ...@@ -466,14 +480,14 @@ static int lowpan_rcv(struct sk_buff *skb, struct net_device *dev,
} else { } else {
switch (skb->data[0] & 0xe0) { switch (skb->data[0] & 0xe0) {
case LOWPAN_DISPATCH_IPHC: /* ipv6 datagram */ case LOWPAN_DISPATCH_IPHC: /* ipv6 datagram */
ret = process_data(local_skb); ret = process_data(local_skb, &hdr);
if (ret == NET_RX_DROP) if (ret == NET_RX_DROP)
goto drop; goto drop;
break; break;
case LOWPAN_DISPATCH_FRAG1: /* first fragment header */ case LOWPAN_DISPATCH_FRAG1: /* first fragment header */
ret = lowpan_frag_rcv(local_skb, LOWPAN_DISPATCH_FRAG1); ret = lowpan_frag_rcv(local_skb, LOWPAN_DISPATCH_FRAG1);
if (ret == 1) { if (ret == 1) {
ret = process_data(local_skb); ret = process_data(local_skb, &hdr);
if (ret == NET_RX_DROP) if (ret == NET_RX_DROP)
goto drop; goto drop;
} }
...@@ -481,7 +495,7 @@ static int lowpan_rcv(struct sk_buff *skb, struct net_device *dev, ...@@ -481,7 +495,7 @@ static int lowpan_rcv(struct sk_buff *skb, struct net_device *dev,
case LOWPAN_DISPATCH_FRAGN: /* next fragments headers */ case LOWPAN_DISPATCH_FRAGN: /* next fragments headers */
ret = lowpan_frag_rcv(local_skb, LOWPAN_DISPATCH_FRAGN); ret = lowpan_frag_rcv(local_skb, LOWPAN_DISPATCH_FRAGN);
if (ret == 1) { if (ret == 1) {
ret = process_data(local_skb); ret = process_data(local_skb, &hdr);
if (ret == NET_RX_DROP) if (ret == NET_RX_DROP)
goto drop; goto drop;
} }
......
...@@ -3,5 +3,8 @@ obj-$(CONFIG_IEEE802154_6LOWPAN) += 6lowpan.o ...@@ -3,5 +3,8 @@ obj-$(CONFIG_IEEE802154_6LOWPAN) += 6lowpan.o
obj-$(CONFIG_6LOWPAN_IPHC) += 6lowpan_iphc.o obj-$(CONFIG_6LOWPAN_IPHC) += 6lowpan_iphc.o
6lowpan-y := 6lowpan_rtnl.o reassembly.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 af_802154-y := af_ieee802154.o raw.o dgram.o
ccflags-y += -D__CHECK_ENDIAN__
...@@ -25,12 +25,13 @@ ...@@ -25,12 +25,13 @@
#define AF802154_H #define AF802154_H
struct sk_buff; struct sk_buff;
struct net_devce; struct net_device;
struct ieee802154_addr;
extern struct proto ieee802154_raw_prot; extern struct proto ieee802154_raw_prot;
extern struct proto ieee802154_dgram_prot; extern struct proto ieee802154_dgram_prot;
void ieee802154_raw_deliver(struct net_device *dev, struct sk_buff *skb); void ieee802154_raw_deliver(struct net_device *dev, struct sk_buff *skb);
int ieee802154_dgram_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 net_device *ieee802154_get_dev(struct net *net,
struct ieee802154_addr *addr); const struct ieee802154_addr *addr);
#endif #endif
...@@ -43,25 +43,27 @@ ...@@ -43,25 +43,27 @@
/* /*
* Utility function for families * Utility function for families
*/ */
struct net_device *ieee802154_get_dev(struct net *net, struct net_device*
struct ieee802154_addr *addr) ieee802154_get_dev(struct net *net, const struct ieee802154_addr *addr)
{ {
struct net_device *dev = NULL; struct net_device *dev = NULL;
struct net_device *tmp; 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: case IEEE802154_ADDR_LONG:
ieee802154_devaddr_to_raw(hwaddr, addr->extended_addr);
rcu_read_lock(); rcu_read_lock();
dev = dev_getbyhwaddr_rcu(net, ARPHRD_IEEE802154, addr->hwaddr); dev = dev_getbyhwaddr_rcu(net, ARPHRD_IEEE802154, hwaddr);
if (dev) if (dev)
dev_hold(dev); dev_hold(dev);
rcu_read_unlock(); rcu_read_unlock();
break; break;
case IEEE802154_ADDR_SHORT: case IEEE802154_ADDR_SHORT:
if (addr->pan_id == 0xffff || if (addr->pan_id == cpu_to_le16(IEEE802154_PANID_BROADCAST) ||
addr->short_addr == IEEE802154_ADDR_UNDEF || addr->short_addr == cpu_to_le16(IEEE802154_ADDR_UNDEF) ||
addr->short_addr == 0xffff) addr->short_addr == cpu_to_le16(IEEE802154_ADDR_UNDEF))
break; break;
rtnl_lock(); rtnl_lock();
...@@ -86,7 +88,7 @@ struct net_device *ieee802154_get_dev(struct net *net, ...@@ -86,7 +88,7 @@ struct net_device *ieee802154_get_dev(struct net *net,
break; break;
default: default:
pr_warning("Unsupported ieee802154 address type: %d\n", pr_warning("Unsupported ieee802154 address type: %d\n",
addr->addr_type); addr->mode);
break; break;
} }
......
...@@ -73,10 +73,10 @@ static int dgram_init(struct sock *sk) ...@@ -73,10 +73,10 @@ static int dgram_init(struct sock *sk)
{ {
struct dgram_sock *ro = dgram_sk(sk); struct dgram_sock *ro = dgram_sk(sk);
ro->dst_addr.addr_type = IEEE802154_ADDR_LONG; ro->dst_addr.mode = IEEE802154_ADDR_LONG;
ro->dst_addr.pan_id = 0xffff; ro->dst_addr.pan_id = cpu_to_le16(IEEE802154_ADDR_BROADCAST);
ro->want_ack = 1; 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; return 0;
} }
...@@ -88,6 +88,7 @@ static void dgram_close(struct sock *sk, long timeout) ...@@ -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) static int dgram_bind(struct sock *sk, struct sockaddr *uaddr, int len)
{ {
struct sockaddr_ieee802154 *addr = (struct sockaddr_ieee802154 *)uaddr; struct sockaddr_ieee802154 *addr = (struct sockaddr_ieee802154 *)uaddr;
struct ieee802154_addr haddr;
struct dgram_sock *ro = dgram_sk(sk); struct dgram_sock *ro = dgram_sk(sk);
int err = -EINVAL; int err = -EINVAL;
struct net_device *dev; struct net_device *dev;
...@@ -102,7 +103,8 @@ static int dgram_bind(struct sock *sk, struct sockaddr *uaddr, int len) ...@@ -102,7 +103,8 @@ static int dgram_bind(struct sock *sk, struct sockaddr *uaddr, int len)
if (addr->family != AF_IEEE802154) if (addr->family != AF_IEEE802154)
goto out; 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) { if (!dev) {
err = -ENODEV; err = -ENODEV;
goto out; goto out;
...@@ -113,7 +115,7 @@ static int dgram_bind(struct sock *sk, struct sockaddr *uaddr, int len) ...@@ -113,7 +115,7 @@ static int dgram_bind(struct sock *sk, struct sockaddr *uaddr, int len)
goto out_put; goto out_put;
} }
memcpy(&ro->src_addr, &addr->addr, sizeof(struct ieee802154_addr)); ro->src_addr = haddr;
ro->bound = 1; ro->bound = 1;
err = 0; err = 0;
...@@ -149,8 +151,7 @@ static int dgram_ioctl(struct sock *sk, int cmd, unsigned long arg) ...@@ -149,8 +151,7 @@ static int dgram_ioctl(struct sock *sk, int cmd, unsigned long arg)
* of this packet since that is all * of this packet since that is all
* that will be read. * that will be read.
*/ */
/* FIXME: parse the header for more correct value */ amount = skb->len - ieee802154_hdr_length(skb);
amount = skb->len - (3+8+8);
} }
spin_unlock_bh(&sk->sk_receive_queue.lock); spin_unlock_bh(&sk->sk_receive_queue.lock);
return put_user(amount, (int __user *)arg); return put_user(amount, (int __user *)arg);
...@@ -181,7 +182,7 @@ static int dgram_connect(struct sock *sk, struct sockaddr *uaddr, ...@@ -181,7 +182,7 @@ static int dgram_connect(struct sock *sk, struct sockaddr *uaddr,
goto out; goto out;
} }
memcpy(&ro->dst_addr, &addr->addr, sizeof(struct ieee802154_addr)); ieee802154_addr_from_sa(&ro->dst_addr, &addr->addr);
out: out:
release_sock(sk); release_sock(sk);
...@@ -194,8 +195,8 @@ static int dgram_disconnect(struct sock *sk, int flags) ...@@ -194,8 +195,8 @@ static int dgram_disconnect(struct sock *sk, int flags)
lock_sock(sk); lock_sock(sk);
ro->dst_addr.addr_type = IEEE802154_ADDR_LONG; ro->dst_addr.mode = IEEE802154_ADDR_LONG;
memset(&ro->dst_addr.hwaddr, 0xff, sizeof(ro->dst_addr.hwaddr)); memset(&ro->dst_addr.extended_addr, 0xff, IEEE802154_ADDR_LEN);
release_sock(sk); release_sock(sk);
...@@ -232,7 +233,7 @@ static int dgram_sendmsg(struct kiocb *iocb, struct sock *sk, ...@@ -232,7 +233,7 @@ static int dgram_sendmsg(struct kiocb *iocb, struct sock *sk,
if (size > mtu) { if (size > mtu) {
pr_debug("size = %Zu, mtu = %u\n", size, mtu); pr_debug("size = %Zu, mtu = %u\n", size, mtu);
err = -EINVAL; err = -EMSGSIZE;
goto out_dev; goto out_dev;
} }
...@@ -312,7 +313,7 @@ static int dgram_recvmsg(struct kiocb *iocb, struct sock *sk, ...@@ -312,7 +313,7 @@ static int dgram_recvmsg(struct kiocb *iocb, struct sock *sk,
if (saddr) { if (saddr) {
saddr->family = AF_IEEE802154; saddr->family = AF_IEEE802154;
saddr->addr = mac_cb(skb)->sa; ieee802154_addr_to_sa(&saddr->addr, &mac_cb(skb)->source);
*addr_len = sizeof(*saddr); *addr_len = sizeof(*saddr);
} }
...@@ -336,40 +337,43 @@ static int dgram_rcv_skb(struct sock *sk, struct sk_buff *skb) ...@@ -336,40 +337,43 @@ static int dgram_rcv_skb(struct sock *sk, struct sk_buff *skb)
return NET_RX_SUCCESS; return NET_RX_SUCCESS;
} }
static inline int ieee802154_match_sock(u8 *hw_addr, u16 pan_id, static inline bool
u16 short_addr, struct dgram_sock *ro) ieee802154_match_sock(__le64 hw_addr, __le16 pan_id, __le16 short_addr,
struct dgram_sock *ro)
{ {
if (!ro->bound) if (!ro->bound)
return 1; return true;
if (ro->src_addr.addr_type == IEEE802154_ADDR_LONG && if (ro->src_addr.mode == IEEE802154_ADDR_LONG &&
!memcmp(ro->src_addr.hwaddr, hw_addr, IEEE802154_ADDR_LEN)) hw_addr == ro->src_addr.extended_addr)
return 1; return true;
if (ro->src_addr.addr_type == IEEE802154_ADDR_SHORT && if (ro->src_addr.mode == IEEE802154_ADDR_SHORT &&
pan_id == ro->src_addr.pan_id && pan_id == ro->src_addr.pan_id &&
short_addr == ro->src_addr.short_addr) short_addr == ro->src_addr.short_addr)
return 1; return true;
return 0; return false;
} }
int ieee802154_dgram_deliver(struct net_device *dev, struct sk_buff *skb) int ieee802154_dgram_deliver(struct net_device *dev, struct sk_buff *skb)
{ {
struct sock *sk, *prev = NULL; struct sock *sk, *prev = NULL;
int ret = NET_RX_SUCCESS; int ret = NET_RX_SUCCESS;
u16 pan_id, short_addr; __le16 pan_id, short_addr;
__le64 hw_addr;
/* Data frame processing */ /* Data frame processing */
BUG_ON(dev->type != ARPHRD_IEEE802154); BUG_ON(dev->type != ARPHRD_IEEE802154);
pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev); pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev);
short_addr = ieee802154_mlme_ops(dev)->get_short_addr(dev); short_addr = ieee802154_mlme_ops(dev)->get_short_addr(dev);
hw_addr = ieee802154_devaddr_from_raw(dev->dev_addr);
read_lock(&dgram_lock); read_lock(&dgram_lock);
sk_for_each(sk, &dgram_head) { sk_for_each(sk, &dgram_head) {
if (ieee802154_match_sock(dev->dev_addr, pan_id, short_addr, if (ieee802154_match_sock(hw_addr, pan_id, short_addr,
dgram_sk(sk))) { dgram_sk(sk))) {
if (prev) { if (prev) {
struct sk_buff *clone; struct sk_buff *clone;
clone = skb_clone(skb, GFP_ATOMIC); clone = skb_clone(skb, GFP_ATOMIC);
......
/*
* 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);
...@@ -39,6 +39,26 @@ ...@@ -39,6 +39,26 @@
#include "ieee802154.h" #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, int ieee802154_nl_assoc_indic(struct net_device *dev,
struct ieee802154_addr *addr, u8 cap) struct ieee802154_addr *addr, u8 cap)
{ {
...@@ -46,7 +66,7 @@ int ieee802154_nl_assoc_indic(struct net_device *dev, ...@@ -46,7 +66,7 @@ int ieee802154_nl_assoc_indic(struct net_device *dev,
pr_debug("%s\n", __func__); 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__); pr_err("%s: received non-long source address!\n", __func__);
return -EINVAL; return -EINVAL;
} }
...@@ -59,8 +79,8 @@ int ieee802154_nl_assoc_indic(struct net_device *dev, ...@@ -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_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN, nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
dev->dev_addr) || dev->dev_addr) ||
nla_put(msg, IEEE802154_ATTR_SRC_HW_ADDR, IEEE802154_ADDR_LEN, nla_put_hwaddr(msg, IEEE802154_ATTR_SRC_HW_ADDR,
addr->hwaddr) || addr->extended_addr) ||
nla_put_u8(msg, IEEE802154_ATTR_CAPABILITY, cap)) nla_put_u8(msg, IEEE802154_ATTR_CAPABILITY, cap))
goto nla_put_failure; goto nla_put_failure;
...@@ -72,7 +92,7 @@ int ieee802154_nl_assoc_indic(struct net_device *dev, ...@@ -72,7 +92,7 @@ int ieee802154_nl_assoc_indic(struct net_device *dev,
} }
EXPORT_SYMBOL(ieee802154_nl_assoc_indic); 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) u8 status)
{ {
struct sk_buff *msg; struct sk_buff *msg;
...@@ -87,7 +107,7 @@ int ieee802154_nl_assoc_confirm(struct net_device *dev, u16 short_addr, ...@@ -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_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN, nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
dev->dev_addr) || 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)) nla_put_u8(msg, IEEE802154_ATTR_STATUS, status))
goto nla_put_failure; goto nla_put_failure;
return ieee802154_nl_mcast(msg, IEEE802154_COORD_MCGRP); return ieee802154_nl_mcast(msg, IEEE802154_COORD_MCGRP);
...@@ -114,13 +134,13 @@ int ieee802154_nl_disassoc_indic(struct net_device *dev, ...@@ -114,13 +134,13 @@ int ieee802154_nl_disassoc_indic(struct net_device *dev,
nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN, nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
dev->dev_addr)) dev->dev_addr))
goto nla_put_failure; goto nla_put_failure;
if (addr->addr_type == IEEE802154_ADDR_LONG) { if (addr->mode == IEEE802154_ADDR_LONG) {
if (nla_put(msg, IEEE802154_ATTR_SRC_HW_ADDR, IEEE802154_ADDR_LEN, if (nla_put_hwaddr(msg, IEEE802154_ATTR_SRC_HW_ADDR,
addr->hwaddr)) addr->extended_addr))
goto nla_put_failure; goto nla_put_failure;
} else { } else {
if (nla_put_u16(msg, IEEE802154_ATTR_SRC_SHORT_ADDR, if (nla_put_shortaddr(msg, IEEE802154_ATTR_SRC_SHORT_ADDR,
addr->short_addr)) addr->short_addr))
goto nla_put_failure; goto nla_put_failure;
} }
if (nla_put_u8(msg, IEEE802154_ATTR_REASON, reason)) if (nla_put_u8(msg, IEEE802154_ATTR_REASON, reason))
...@@ -157,8 +177,8 @@ int ieee802154_nl_disassoc_confirm(struct net_device *dev, u8 status) ...@@ -157,8 +177,8 @@ int ieee802154_nl_disassoc_confirm(struct net_device *dev, u8 status)
} }
EXPORT_SYMBOL(ieee802154_nl_disassoc_confirm); EXPORT_SYMBOL(ieee802154_nl_disassoc_confirm);
int ieee802154_nl_beacon_indic(struct net_device *dev, int ieee802154_nl_beacon_indic(struct net_device *dev, __le16 panid,
u16 panid, u16 coord_addr) __le16 coord_addr)
{ {
struct sk_buff *msg; struct sk_buff *msg;
...@@ -172,8 +192,9 @@ int ieee802154_nl_beacon_indic(struct net_device *dev, ...@@ -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_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN, nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
dev->dev_addr) || dev->dev_addr) ||
nla_put_u16(msg, IEEE802154_ATTR_COORD_SHORT_ADDR, coord_addr) || nla_put_shortaddr(msg, IEEE802154_ATTR_COORD_SHORT_ADDR,
nla_put_u16(msg, IEEE802154_ATTR_COORD_PAN_ID, panid)) coord_addr) ||
nla_put_shortaddr(msg, IEEE802154_ATTR_COORD_PAN_ID, panid))
goto nla_put_failure; goto nla_put_failure;
return ieee802154_nl_mcast(msg, IEEE802154_COORD_MCGRP); return ieee802154_nl_mcast(msg, IEEE802154_COORD_MCGRP);
...@@ -243,6 +264,7 @@ static int ieee802154_nl_fill_iface(struct sk_buff *msg, u32 portid, ...@@ -243,6 +264,7 @@ static int ieee802154_nl_fill_iface(struct sk_buff *msg, u32 portid,
{ {
void *hdr; void *hdr;
struct wpan_phy *phy; struct wpan_phy *phy;
__le16 short_addr, pan_id;
pr_debug("%s\n", __func__); pr_debug("%s\n", __func__);
...@@ -254,15 +276,16 @@ static int ieee802154_nl_fill_iface(struct sk_buff *msg, u32 portid, ...@@ -254,15 +276,16 @@ static int ieee802154_nl_fill_iface(struct sk_buff *msg, u32 portid,
phy = ieee802154_mlme_ops(dev)->get_phy(dev); phy = ieee802154_mlme_ops(dev)->get_phy(dev);
BUG_ON(!phy); 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) || 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_string(msg, IEEE802154_ATTR_PHY_NAME, wpan_phy_name(phy)) ||
nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) || nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN, nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
dev->dev_addr) || dev->dev_addr) ||
nla_put_u16(msg, IEEE802154_ATTR_SHORT_ADDR, nla_put_shortaddr(msg, IEEE802154_ATTR_SHORT_ADDR, short_addr) ||
ieee802154_mlme_ops(dev)->get_short_addr(dev)) || nla_put_shortaddr(msg, IEEE802154_ATTR_PAN_ID, pan_id))
nla_put_u16(msg, IEEE802154_ATTR_PAN_ID,
ieee802154_mlme_ops(dev)->get_pan_id(dev)))
goto nla_put_failure; goto nla_put_failure;
wpan_phy_put(phy); wpan_phy_put(phy);
return genlmsg_end(msg, hdr); return genlmsg_end(msg, hdr);
...@@ -322,16 +345,16 @@ int ieee802154_associate_req(struct sk_buff *skb, struct genl_info *info) ...@@ -322,16 +345,16 @@ int ieee802154_associate_req(struct sk_buff *skb, struct genl_info *info)
goto out; goto out;
if (info->attrs[IEEE802154_ATTR_COORD_HW_ADDR]) { if (info->attrs[IEEE802154_ATTR_COORD_HW_ADDR]) {
addr.addr_type = IEEE802154_ADDR_LONG; addr.mode = IEEE802154_ADDR_LONG;
nla_memcpy(addr.hwaddr, addr.extended_addr = nla_get_hwaddr(
info->attrs[IEEE802154_ATTR_COORD_HW_ADDR], info->attrs[IEEE802154_ATTR_COORD_HW_ADDR]);
IEEE802154_ADDR_LEN);
} else { } else {
addr.addr_type = IEEE802154_ADDR_SHORT; addr.mode = IEEE802154_ADDR_SHORT;
addr.short_addr = nla_get_u16( addr.short_addr = nla_get_shortaddr(
info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR]); 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]) if (info->attrs[IEEE802154_ATTR_PAGE])
page = nla_get_u8(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) ...@@ -365,14 +388,13 @@ int ieee802154_associate_resp(struct sk_buff *skb, struct genl_info *info)
if (!ieee802154_mlme_ops(dev)->assoc_resp) if (!ieee802154_mlme_ops(dev)->assoc_resp)
goto out; goto out;
addr.addr_type = IEEE802154_ADDR_LONG; addr.mode = IEEE802154_ADDR_LONG;
nla_memcpy(addr.hwaddr, info->attrs[IEEE802154_ATTR_DEST_HW_ADDR], addr.extended_addr = nla_get_hwaddr(
IEEE802154_ADDR_LEN); info->attrs[IEEE802154_ATTR_DEST_HW_ADDR]);
addr.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev); addr.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev);
ret = ieee802154_mlme_ops(dev)->assoc_resp(dev, &addr, 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])); nla_get_u8(info->attrs[IEEE802154_ATTR_STATUS]));
out: out:
...@@ -398,13 +420,12 @@ int ieee802154_disassociate_req(struct sk_buff *skb, struct genl_info *info) ...@@ -398,13 +420,12 @@ int ieee802154_disassociate_req(struct sk_buff *skb, struct genl_info *info)
goto out; goto out;
if (info->attrs[IEEE802154_ATTR_DEST_HW_ADDR]) { if (info->attrs[IEEE802154_ATTR_DEST_HW_ADDR]) {
addr.addr_type = IEEE802154_ADDR_LONG; addr.mode = IEEE802154_ADDR_LONG;
nla_memcpy(addr.hwaddr, addr.extended_addr = nla_get_hwaddr(
info->attrs[IEEE802154_ATTR_DEST_HW_ADDR], info->attrs[IEEE802154_ATTR_DEST_HW_ADDR]);
IEEE802154_ADDR_LEN);
} else { } else {
addr.addr_type = IEEE802154_ADDR_SHORT; addr.mode = IEEE802154_ADDR_SHORT;
addr.short_addr = nla_get_u16( addr.short_addr = nla_get_shortaddr(
info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]); info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]);
} }
addr.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev); 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) ...@@ -449,10 +470,11 @@ int ieee802154_start_req(struct sk_buff *skb, struct genl_info *info)
if (!ieee802154_mlme_ops(dev)->start_req) if (!ieee802154_mlme_ops(dev)->start_req)
goto out; goto out;
addr.addr_type = IEEE802154_ADDR_SHORT; addr.mode = IEEE802154_ADDR_SHORT;
addr.short_addr = nla_get_u16( addr.short_addr = nla_get_shortaddr(
info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR]); 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]); channel = nla_get_u8(info->attrs[IEEE802154_ATTR_CHANNEL]);
bcn_ord = nla_get_u8(info->attrs[IEEE802154_ATTR_BCN_ORD]); 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) ...@@ -467,7 +489,7 @@ int ieee802154_start_req(struct sk_buff *skb, struct genl_info *info)
page = 0; 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); ieee802154_nl_start_confirm(dev, IEEE802154_NO_SHORT_ADDRESS);
dev_put(dev); dev_put(dev);
return -EINVAL; return -EINVAL;
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <net/sock.h> #include <net/sock.h>
#include <net/af_ieee802154.h> #include <net/af_ieee802154.h>
#include <net/ieee802154_netdev.h>
#include "af802154.h" #include "af802154.h"
...@@ -55,21 +56,24 @@ static void raw_close(struct sock *sk, long timeout) ...@@ -55,21 +56,24 @@ static void raw_close(struct sock *sk, long timeout)
sk_common_release(sk); 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; int err = 0;
struct net_device *dev = NULL; struct net_device *dev = NULL;
if (len < sizeof(*addr)) if (len < sizeof(*uaddr))
return -EINVAL; return -EINVAL;
if (addr->family != AF_IEEE802154) uaddr = (struct sockaddr_ieee802154 *)_uaddr;
if (uaddr->family != AF_IEEE802154)
return -EINVAL; return -EINVAL;
lock_sock(sk); 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) { if (!dev) {
err = -ENODEV; err = -ENODEV;
goto out; goto out;
......
...@@ -30,6 +30,17 @@ ...@@ -30,6 +30,17 @@
#include "reassembly.h" #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 struct inet_frags lowpan_frags;
static int lowpan_frag_reasm(struct lowpan_frag_queue *fq, 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) ...@@ -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); fq = container_of(q, struct lowpan_frag_queue, q);
return fq->tag == arg->tag && fq->d_size == arg->d_size && return fq->tag == arg->tag && fq->d_size == arg->d_size &&
ieee802154_addr_addr_equal(&fq->saddr, arg->src) && ieee802154_addr_equal(&fq->saddr, arg->src) &&
ieee802154_addr_addr_equal(&fq->daddr, arg->dst); ieee802154_addr_equal(&fq->daddr, arg->dst);
} }
static void lowpan_frag_init(struct inet_frag_queue *q, void *a) static void lowpan_frag_init(struct inet_frag_queue *q, void *a)
...@@ -102,8 +113,9 @@ static void lowpan_frag_expire(unsigned long data) ...@@ -102,8 +113,9 @@ static void lowpan_frag_expire(unsigned long data)
} }
static inline struct lowpan_frag_queue * static inline struct lowpan_frag_queue *
fq_find(struct net *net, const struct ieee802154_frag_info *frag_info, fq_find(struct net *net, const struct lowpan_frag_info *frag_info,
const struct ieee802154_addr *src, const struct ieee802154_addr *dst) const struct ieee802154_addr *src,
const struct ieee802154_addr *dst)
{ {
struct inet_frag_queue *q; struct inet_frag_queue *q;
struct lowpan_create_arg arg; struct lowpan_create_arg arg;
...@@ -136,8 +148,8 @@ static int lowpan_frag_queue(struct lowpan_frag_queue *fq, ...@@ -136,8 +148,8 @@ static int lowpan_frag_queue(struct lowpan_frag_queue *fq,
if (fq->q.last_in & INET_FRAG_COMPLETE) if (fq->q.last_in & INET_FRAG_COMPLETE)
goto err; goto err;
offset = mac_cb(skb)->frag_info.d_offset << 3; offset = lowpan_cb(skb)->d_offset << 3;
end = mac_cb(skb)->frag_info.d_size; end = lowpan_cb(skb)->d_size;
/* Is this the final fragment? */ /* Is this the final fragment? */
if (offset + skb->len == end) { if (offset + skb->len == end) {
...@@ -163,15 +175,13 @@ static int lowpan_frag_queue(struct lowpan_frag_queue *fq, ...@@ -163,15 +175,13 @@ static int lowpan_frag_queue(struct lowpan_frag_queue *fq,
* this fragment, right? * this fragment, right?
*/ */
prev = fq->q.fragments_tail; prev = fq->q.fragments_tail;
if (!prev || mac_cb(prev)->frag_info.d_offset < if (!prev || lowpan_cb(prev)->d_offset < lowpan_cb(skb)->d_offset) {
mac_cb(skb)->frag_info.d_offset) {
next = NULL; next = NULL;
goto found; goto found;
} }
prev = NULL; prev = NULL;
for (next = fq->q.fragments; next != NULL; next = next->next) { for (next = fq->q.fragments; next != NULL; next = next->next) {
if (mac_cb(next)->frag_info.d_offset >= if (lowpan_cb(next)->d_offset >= lowpan_cb(skb)->d_offset)
mac_cb(skb)->frag_info.d_offset)
break; /* bingo! */ break; /* bingo! */
prev = next; prev = next;
} }
...@@ -318,7 +328,7 @@ static int lowpan_frag_reasm(struct lowpan_frag_queue *fq, struct sk_buff *prev, ...@@ -318,7 +328,7 @@ static int lowpan_frag_reasm(struct lowpan_frag_queue *fq, struct sk_buff *prev,
} }
static int lowpan_get_frag_info(struct sk_buff *skb, const u8 frag_type, 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; bool fail;
u8 pattern = 0, low = 0; u8 pattern = 0, low = 0;
...@@ -345,9 +355,13 @@ int lowpan_frag_rcv(struct sk_buff *skb, const u8 frag_type) ...@@ -345,9 +355,13 @@ int lowpan_frag_rcv(struct sk_buff *skb, const u8 frag_type)
{ {
struct lowpan_frag_queue *fq; struct lowpan_frag_queue *fq;
struct net *net = dev_net(skb->dev); 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; int err;
source = mac_cb(skb)->source;
dest = mac_cb(skb)->dest;
err = lowpan_get_frag_info(skb, frag_type, frag_info); err = lowpan_get_frag_info(skb, frag_type, frag_info);
if (err < 0) if (err < 0)
goto err; goto err;
...@@ -357,7 +371,7 @@ int lowpan_frag_rcv(struct sk_buff *skb, const u8 frag_type) ...@@ -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); 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) { if (fq != NULL) {
int ret; int ret;
spin_lock(&fq->q.lock); spin_lock(&fq->q.lock);
......
...@@ -23,10 +23,10 @@ struct lowpan_frag_queue { ...@@ -23,10 +23,10 @@ struct lowpan_frag_queue {
static inline u32 ieee802154_addr_hash(const struct ieee802154_addr *a) static inline u32 ieee802154_addr_hash(const struct ieee802154_addr *a)
{ {
switch (a->addr_type) { switch (a->mode) {
case IEEE802154_ADDR_LONG: case IEEE802154_ADDR_LONG:
return (__force u32)((((u32 *)a->hwaddr))[0] ^ return (((__force u64)a->extended_addr) >> 32) ^
((u32 *)(a->hwaddr))[1]); (((__force u64)a->extended_addr) & 0xffffffff);
case IEEE802154_ADDR_SHORT: case IEEE802154_ADDR_SHORT:
return (__force u32)(a->short_addr); return (__force u32)(a->short_addr);
default: default:
...@@ -34,31 +34,6 @@ static inline u32 ieee802154_addr_hash(const struct ieee802154_addr *a) ...@@ -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); 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);
......
obj-$(CONFIG_MAC802154) += mac802154.o obj-$(CONFIG_MAC802154) += mac802154.o
mac802154-objs := ieee802154_dev.o rx.o tx.o mac_cmd.o mib.o monitor.o wpan.o mac802154-objs := ieee802154_dev.o rx.o tx.o mac_cmd.o mib.o monitor.o wpan.o
ccflags-y += -D__CHECK_ENDIAN__
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include <net/netlink.h> #include <net/netlink.h>
#include <linux/nl802154.h> #include <linux/nl802154.h>
#include <net/mac802154.h> #include <net/mac802154.h>
#include <net/ieee802154_netdev.h>
#include <net/route.h> #include <net/route.h>
#include <net/wpan-phy.h> #include <net/wpan-phy.h>
...@@ -46,7 +47,9 @@ int mac802154_slave_open(struct net_device *dev) ...@@ -46,7 +47,9 @@ int mac802154_slave_open(struct net_device *dev)
} }
if (ipriv->ops->ieee_addr) { 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); WARN_ON(res);
if (res) if (res)
goto err; goto err;
......
...@@ -76,6 +76,7 @@ struct mac802154_sub_if_data { ...@@ -76,6 +76,7 @@ struct mac802154_sub_if_data {
__le16 pan_id; __le16 pan_id;
__le16 short_addr; __le16 short_addr;
__le64 extended_addr;
u8 chan; u8 chan;
u8 page; u8 page;
...@@ -106,11 +107,11 @@ netdev_tx_t mac802154_tx(struct mac802154_priv *priv, struct sk_buff *skb, ...@@ -106,11 +107,11 @@ netdev_tx_t mac802154_tx(struct mac802154_priv *priv, struct sk_buff *skb,
u8 page, u8 chan); u8 page, u8 chan);
/* MIB callbacks */ /* MIB callbacks */
void mac802154_dev_set_short_addr(struct net_device *dev, u16 val); void mac802154_dev_set_short_addr(struct net_device *dev, __le16 val);
u16 mac802154_dev_get_short_addr(const struct net_device *dev); __le16 mac802154_dev_get_short_addr(const struct net_device *dev);
void mac802154_dev_set_ieee_addr(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); __le16 mac802154_dev_get_pan_id(const struct net_device *dev);
void mac802154_dev_set_pan_id(struct net_device *dev, u16 val); 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); void mac802154_dev_set_page_channel(struct net_device *dev, u8 page, u8 chan);
u8 mac802154_dev_get_dsn(const struct net_device *dev); u8 mac802154_dev_get_dsn(const struct net_device *dev);
......
...@@ -40,7 +40,7 @@ static int mac802154_mlme_start_req(struct net_device *dev, ...@@ -40,7 +40,7 @@ static int mac802154_mlme_start_req(struct net_device *dev,
u8 pan_coord, u8 blx, u8 pan_coord, u8 blx,
u8 coord_realign) 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_pan_id(dev, addr->pan_id);
mac802154_dev_set_short_addr(dev, addr->short_addr); mac802154_dev_set_short_addr(dev, addr->short_addr);
......
...@@ -24,7 +24,9 @@ ...@@ -24,7 +24,9 @@
#include <linux/if_arp.h> #include <linux/if_arp.h>
#include <net/mac802154.h> #include <net/mac802154.h>
#include <net/ieee802154_netdev.h>
#include <net/wpan-phy.h> #include <net/wpan-phy.h>
#include <net/ieee802154_netdev.h>
#include "mac802154.h" #include "mac802154.h"
...@@ -79,7 +81,7 @@ static void set_hw_addr_filt(struct net_device *dev, unsigned long changed) ...@@ -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); 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); 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) ...@@ -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); struct mac802154_sub_if_data *priv = netdev_priv(dev);
u16 ret; __le16 ret;
BUG_ON(dev->type != ARPHRD_IEEE802154); BUG_ON(dev->type != ARPHRD_IEEE802154);
...@@ -115,19 +117,19 @@ void mac802154_dev_set_ieee_addr(struct net_device *dev) ...@@ -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_sub_if_data *priv = netdev_priv(dev);
struct mac802154_priv *mac = priv->hw; struct mac802154_priv *mac = priv->hw;
priv->extended_addr = ieee802154_devaddr_from_raw(dev->dev_addr);
if (mac->ops->set_hw_addr_filt && if (mac->ops->set_hw_addr_filt &&
memcmp(mac->hw.hw_filt.ieee_addr, mac->hw.hw_filt.ieee_addr != priv->extended_addr) {
dev->dev_addr, IEEE802154_ADDR_LEN)) { mac->hw.hw_filt.ieee_addr = priv->extended_addr;
memcpy(mac->hw.hw_filt.ieee_addr,
dev->dev_addr, IEEE802154_ADDR_LEN);
set_hw_addr_filt(dev, IEEE802515_AFILT_IEEEADDR_CHANGED); 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); struct mac802154_sub_if_data *priv = netdev_priv(dev);
u16 ret; __le16 ret;
BUG_ON(dev->type != ARPHRD_IEEE802154); BUG_ON(dev->type != ARPHRD_IEEE802154);
...@@ -138,7 +140,7 @@ u16 mac802154_dev_get_pan_id(const struct net_device *dev) ...@@ -138,7 +140,7 @@ u16 mac802154_dev_get_pan_id(const struct net_device *dev)
return ret; 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); struct mac802154_sub_if_data *priv = netdev_priv(dev);
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment