Commit 6164c202 authored by John W. Linville's avatar John W. Linville

Merge branch 'for-upstream' of...

Merge branch 'for-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next
parents bf515fb1 56b2c3ee
......@@ -4699,7 +4699,6 @@ F: net/mac802154/
F: drivers/net/ieee802154/
F: include/linux/nl802154.h
F: include/linux/ieee802154.h
F: include/net/nl802154.h
F: include/net/mac802154.h
F: include/net/af_ieee802154.h
F: include/net/cfg802154.h
......
......@@ -299,6 +299,8 @@ struct btusb_data {
unsigned int sco_num;
int isoc_altsetting;
int suspend_count;
int (*recv_bulk)(struct btusb_data *data, void *buffer, int count);
};
static inline void btusb_free_frags(struct btusb_data *data)
......@@ -590,7 +592,7 @@ static void btusb_bulk_complete(struct urb *urb)
if (urb->status == 0) {
hdev->stat.byte_rx += urb->actual_length;
if (btusb_recv_bulk(data, urb->transfer_buffer,
if (data->recv_bulk(data, urb->transfer_buffer,
urb->actual_length) < 0) {
BT_ERR("%s corrupted ACL packet", hdev->name);
hdev->stat.err_rx++;
......@@ -2012,6 +2014,8 @@ static int btusb_probe(struct usb_interface *intf,
init_usb_anchor(&data->isoc_anchor);
spin_lock_init(&data->rxlock);
data->recv_bulk = btusb_recv_bulk;
hdev = hci_alloc_dev();
if (!hdev)
return -ENOMEM;
......@@ -2035,6 +2039,7 @@ static int btusb_probe(struct usb_interface *intf,
if (id->driver_info & BTUSB_BCM_PATCHRAM) {
hdev->setup = btusb_setup_bcm_patchram;
hdev->set_bdaddr = btusb_set_bdaddr_bcm;
set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks);
}
if (id->driver_info & BTUSB_INTEL) {
......
......@@ -171,8 +171,6 @@ static void h5_timed_event(unsigned long arg)
static void h5_peer_reset(struct hci_uart *hu)
{
struct h5 *h5 = hu->priv;
struct sk_buff *skb;
const unsigned char hard_err[] = { 0x10, 0x01, 0x00 };
BT_ERR("Peer device has reset");
......@@ -187,15 +185,8 @@ static void h5_peer_reset(struct hci_uart *hu)
h5->tx_seq = 0;
h5->tx_ack = 0;
skb = bt_skb_alloc(3, GFP_ATOMIC);
if (!skb)
return;
bt_cb(skb)->pkt_type = HCI_EVENT_PKT;
memcpy(skb_put(skb, 3), hard_err, 3);
/* Send Hardware Error to upper stack */
hci_recv_frame(hu->hdev, skb);
/* Send reset request to upper stack */
hci_reset_dev(hu->hdev);
}
static int h5_open(struct hci_uart *hu)
......
......@@ -1047,7 +1047,7 @@ at86rf230_channel(struct ieee802154_hw *hw, u8 page, u8 channel)
struct at86rf230_local *lp = hw->priv;
int rc;
if (page < 0 || page > 31 ||
if (page > 31 ||
!(lp->hw->phy->channels_supported[page] & BIT(channel))) {
WARN_ON(1);
return -EINVAL;
......@@ -1358,7 +1358,11 @@ static int at86rf230_hw_init(struct at86rf230_local *lp)
return -EINVAL;
}
return 0;
/* Force setting slotted operation bit to 0. Sometimes the atben
* sets this bit and I don't know why. We set this always force
* to zero while probing.
*/
return at86rf230_write_subreg(lp, SR_SLOTTED_OPERATION, 0);
}
static struct at86rf230_platform_data *
......@@ -1427,6 +1431,7 @@ at86rf230_detect_device(struct at86rf230_local *lp)
chip = "at86rf231";
lp->data = &at86rf231_data;
lp->hw->phy->channels_supported[0] = 0x7FFF800;
lp->hw->phy->current_channel = 11;
break;
case 7:
chip = "at86rf212";
......@@ -1435,6 +1440,7 @@ at86rf230_detect_device(struct at86rf230_local *lp)
lp->hw->flags |= IEEE802154_HW_LBT;
lp->hw->phy->channels_supported[0] = 0x00007FF;
lp->hw->phy->channels_supported[2] = 0x00007FF;
lp->hw->phy->current_channel = 5;
} else {
rc = -ENOTSUPP;
}
......@@ -1443,6 +1449,7 @@ at86rf230_detect_device(struct at86rf230_local *lp)
chip = "at86rf233";
lp->data = &at86rf233_data;
lp->hw->phy->channels_supported[0] = 0x7FFF800;
lp->hw->phy->current_channel = 13;
break;
default:
chip = "unkown";
......@@ -1530,6 +1537,8 @@ static int at86rf230_probe(struct spi_device *spi)
lp->hw = hw;
lp->spi = spi;
hw->parent = &spi->dev;
hw->vif_data_size = sizeof(*lp);
ieee802154_random_extended_addr(&hw->phy->perm_extended_addr);
lp->regmap = devm_regmap_init_spi(spi, &at86rf230_regmap_spi_config);
if (IS_ERR(lp->regmap)) {
......
......@@ -651,6 +651,7 @@ static int cc2520_register(struct cc2520_private *priv)
priv->hw->priv = priv;
priv->hw->parent = &priv->spi->dev;
priv->hw->extra_tx_headroom = 0;
priv->hw->vif_data_size = sizeof(*priv);
/* We do support only 2.4 Ghz */
priv->hw->phy->channels_supported[0] = 0x7FFF800;
......
......@@ -24,10 +24,14 @@
#define LINUX_IEEE802154_H
#include <linux/types.h>
#include <linux/random.h>
#include <asm/byteorder.h>
#define IEEE802154_MTU 127
#define IEEE802154_MIN_PSDU_LEN 5
#define IEEE802154_EXTENDED_ADDR_LEN 8
#define IEEE802154_FC_TYPE_BEACON 0x0 /* Frame is beacon */
#define IEEE802154_FC_TYPE_DATA 0x1 /* Frame is data */
#define IEEE802154_FC_TYPE_ACK 0x2 /* Frame is acknowledgment */
......@@ -197,4 +201,32 @@ static inline bool ieee802154_is_valid_psdu_len(const u8 len)
return (len >= IEEE802154_MIN_PSDU_LEN && len <= IEEE802154_MTU);
}
/**
* ieee802154_is_valid_psdu_len - check if extended addr is valid
* @addr: extended addr to check
*/
static inline bool ieee802154_is_valid_extended_addr(const __le64 addr)
{
/* These EUI-64 addresses are reserved by IEEE. 0xffffffffffffffff
* is used internally as extended to short address broadcast mapping.
* This is currently a workaround because neighbor discovery can't
* deal with short addresses types right now.
*/
return ((addr != cpu_to_le64(0x0000000000000000ULL)) &&
(addr != cpu_to_le64(0xffffffffffffffffULL)));
}
/**
* ieee802154_random_extended_addr - generates a random extended address
* @addr: extended addr pointer to place the random address
*/
static inline void ieee802154_random_extended_addr(__le64 *addr)
{
get_random_bytes(addr, IEEE802154_EXTENDED_ADDR_LEN);
/* toggle some bit if we hit an invalid extended addr */
if (!ieee802154_is_valid_extended_addr(*addr))
((u8 *)addr)[IEEE802154_EXTENDED_ADDR_LEN - 1] ^= 0x01;
}
#endif /* LINUX_IEEE802154_H */
......@@ -57,6 +57,8 @@ struct device;
struct phy_device;
/* 802.11 specific */
struct wireless_dev;
/* 802.15.4 specific */
struct wpan_dev;
void netdev_set_default_ethtool_ops(struct net_device *dev,
const struct ethtool_ops *ops);
......@@ -1572,6 +1574,7 @@ struct net_device {
struct inet6_dev __rcu *ip6_ptr;
void *ax25_ptr;
struct wireless_dev *ieee80211_ptr;
struct wpan_dev *ieee802154_ptr;
/*
* Cache lines mostly used on receive path (including eth_type_trans())
......
......@@ -129,6 +129,15 @@ enum {
* during the hdev->setup vendor callback.
*/
HCI_QUIRK_INVALID_BDADDR,
/* When this quirk is set, the duplicate filtering during
* scanning is based on Bluetooth devices addresses. To allow
* RSSI based updates, restart scanning if needed.
*
* This quirk can be set before hci_register_dev is called or
* during the hdev->setup vendor callback.
*/
HCI_QUIRK_STRICT_DUPLICATE_FILTER,
};
/* HCI device flags */
......@@ -265,6 +274,7 @@ enum {
/* Low Energy links do not have defined link type. Use invented one */
#define LE_LINK 0x80
#define AMP_LINK 0x81
#define INVALID_LINK 0xff
/* LMP features */
#define LMP_3SLOT 0x01
......@@ -1463,6 +1473,11 @@ struct hci_ev_cmd_status {
__le16 opcode;
} __packed;
#define HCI_EV_HARDWARE_ERROR 0x10
struct hci_ev_hardware_error {
__u8 code;
} __packed;
#define HCI_EV_ROLE_CHANGE 0x12
struct hci_ev_role_change {
__u8 status;
......
......@@ -646,6 +646,26 @@ static inline unsigned int hci_conn_count(struct hci_dev *hdev)
return c->acl_num + c->amp_num + c->sco_num + c->le_num;
}
static inline __u8 hci_conn_lookup_type(struct hci_dev *hdev, __u16 handle)
{
struct hci_conn_hash *h = &hdev->conn_hash;
struct hci_conn *c;
__u8 type = INVALID_LINK;
rcu_read_lock();
list_for_each_entry_rcu(c, &h->list, list) {
if (c->handle == handle) {
type = c->type;
break;
}
}
rcu_read_unlock();
return type;
}
static inline struct hci_conn *hci_conn_hash_lookup_handle(struct hci_dev *hdev,
__u16 handle)
{
......@@ -856,6 +876,7 @@ int hci_register_dev(struct hci_dev *hdev);
void hci_unregister_dev(struct hci_dev *hdev);
int hci_suspend_dev(struct hci_dev *hdev);
int hci_resume_dev(struct hci_dev *hdev);
int hci_reset_dev(struct hci_dev *hdev);
int hci_dev_open(__u16 dev);
int hci_dev_close(__u16 dev);
int hci_dev_reset(__u16 dev);
......
......@@ -29,6 +29,16 @@
#define WPAN_NUM_CHANNELS 27
#define WPAN_NUM_PAGES 32
struct wpan_phy;
struct cfg802154_ops {
struct net_device * (*add_virtual_intf_deprecated)(struct wpan_phy *wpan_phy,
const char *name,
int type);
void (*del_virtual_intf_deprecated)(struct wpan_phy *wpan_phy,
struct net_device *dev);
};
struct wpan_phy {
struct mutex pib_lock;
......@@ -47,22 +57,24 @@ struct wpan_phy {
u8 csma_retries;
s8 frame_retries;
__le64 perm_extended_addr;
bool lbt;
s32 cca_ed_level;
struct device dev;
int idx;
struct net_device *(*add_iface)(struct wpan_phy *phy,
const char *name, int type);
void (*del_iface)(struct wpan_phy *phy, struct net_device *dev);
char priv[0] __aligned(NETDEV_ALIGN);
};
struct wpan_dev {
struct wpan_phy *wpan_phy;
};
#define to_phy(_dev) container_of(_dev, struct wpan_phy, dev)
struct wpan_phy *wpan_phy_alloc(size_t priv_size);
struct wpan_phy *
wpan_phy_alloc(const struct cfg802154_ops *ops, size_t priv_size);
static inline void wpan_phy_set_dev(struct wpan_phy *phy, struct device *dev)
{
phy->dev.parent = dev;
......
......@@ -423,8 +423,6 @@ struct ieee802154_mlme_ops {
/* The fields below are required. */
struct wpan_phy *(*get_phy)(const struct net_device *dev);
/*
* FIXME: these should become the part of PIB/MIB interface.
* However we still don't have IB interface of any kind
......@@ -434,16 +432,6 @@ struct ieee802154_mlme_ops {
u8 (*get_dsn)(const struct net_device *dev);
};
/* The IEEE 802.15.4 standard defines 2 type of the devices:
* - FFD - full functionality device
* - RFD - reduce functionality device
*
* So 2 sets of mlme operations are needed
*/
struct ieee802154_reduced_mlme_ops {
struct wpan_phy *(*get_phy)(const struct net_device *dev);
};
static inline struct ieee802154_mlme_ops *
ieee802154_mlme_ops(const struct net_device *dev)
{
......
......@@ -17,6 +17,7 @@
#define NET_MAC802154_H
#include <net/af_ieee802154.h>
#include <linux/ieee802154.h>
#include <linux/skbuff.h>
/* General MAC frame format:
......@@ -52,6 +53,13 @@ struct ieee802154_hw_addr_filt {
u8 pan_coord;
};
struct ieee802154_vif {
int type;
/* must be last */
u8 drv_priv[0] __aligned(sizeof(void *));
};
struct ieee802154_hw {
/* filled by the driver */
int extra_tx_headroom;
......@@ -62,6 +70,7 @@ struct ieee802154_hw {
struct ieee802154_hw_addr_filt hw_filt;
void *priv;
struct wpan_phy *phy;
size_t vif_data_size;
};
/* Checksum is in hardware and is omitted from a packet
......@@ -214,6 +223,30 @@ struct ieee802154_ops {
const bool on);
};
/**
* ieee802154_be64_to_le64 - copies and convert be64 to le64
* @le64_dst: le64 destination pointer
* @be64_src: be64 source pointer
*/
static inline void ieee802154_be64_to_le64(void *le64_dst, const void *be64_src)
{
__le64 tmp = (__force __le64)swab64p(be64_src);
memcpy(le64_dst, &tmp, IEEE802154_EXTENDED_ADDR_LEN);
}
/**
* ieee802154_le64_to_be64 - copies and convert le64 to be64
* @be64_dst: be64 destination pointer
* @le64_src: le64 source pointer
*/
static inline void ieee802154_le64_to_be64(void *be64_dst, const void *le64_src)
{
__be64 tmp = (__force __be64)swab64p(le64_src);
memcpy(be64_dst, &tmp, IEEE802154_EXTENDED_ADDR_LEN);
}
/* Basic interface to register ieee802154 hwice */
struct ieee802154_hw *
ieee802154_alloc_hw(size_t priv_data_len, const struct ieee802154_ops *ops);
......
/*
* nl802154.h
*
* Copyright (C) 2007, 2008, 2009 Siemens AG
*
* 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.
*
*/
#ifndef IEEE802154_NL_H
#define IEEE802154_NL_H
struct net_device;
struct ieee802154_addr;
/**
* ieee802154_nl_assoc_indic - Notify userland of an association request.
* @dev: The network device on which this association request was
* received.
* @addr: The address of the device requesting association.
* @cap: The capability information field from the device.
*
* This informs a userland coordinator of a device requesting to
* associate with the PAN controlled by the coordinator.
*
* Note: This is in section 7.3.1 of the IEEE 802.15.4-2006 document.
*/
int ieee802154_nl_assoc_indic(struct net_device *dev,
struct ieee802154_addr *addr, u8 cap);
/**
* ieee802154_nl_assoc_confirm - Notify userland of association.
* @dev: The device which has completed association.
* @short_addr: The short address assigned to the device.
* @status: The status of the association.
*
* Inform userland of the result of an association request. If the
* association request included asking the coordinator to allocate
* a short address then it is returned in @short_addr.
*
* Note: This is in section 7.3.2 of the IEEE 802.15.4 document.
*/
int ieee802154_nl_assoc_confirm(struct net_device *dev,
__le16 short_addr, u8 status);
/**
* ieee802154_nl_disassoc_indic - Notify userland of disassociation.
* @dev: The device on which disassociation was indicated.
* @addr: The device which is disassociating.
* @reason: The reason for the disassociation.
*
* Inform userland that a device has disassociated from the network.
*
* Note: This is in section 7.3.3 of the IEEE 802.15.4 document.
*/
int ieee802154_nl_disassoc_indic(struct net_device *dev,
struct ieee802154_addr *addr, u8 reason);
/**
* ieee802154_nl_disassoc_confirm - Notify userland of disassociation
* completion.
* @dev: The device on which disassociation was ordered.
* @status: The result of the disassociation.
*
* Inform userland of the result of requesting that a device
* disassociate, or the result of requesting that we disassociate from
* a PAN managed by another coordinator.
*
* Note: This is in section 7.1.4.3 of the IEEE 802.15.4 document.
*/
int ieee802154_nl_disassoc_confirm(struct net_device *dev,
u8 status);
/**
* ieee802154_nl_scan_confirm - Notify userland of completion of scan.
* @dev: The device which was instructed to scan.
* @status: The status of the scan operation.
* @scan_type: What type of scan was performed.
* @unscanned: Any channels that the device was unable to scan.
* @edl: The energy levels (if a passive scan).
*
*
* Note: This is in section 7.1.11 of the IEEE 802.15.4 document.
* Note: This API does not permit the return of an active scan result.
*/
int ieee802154_nl_scan_confirm(struct net_device *dev,
u8 status, u8 scan_type, u32 unscanned, u8 page,
u8 *edl/*, struct list_head *pan_desc_list */);
/**
* ieee802154_nl_beacon_indic - Notify userland of a received beacon.
* @dev: The device on which a beacon was received.
* @panid: The PAN of the coordinator.
* @coord_addr: The short address of the coordinator on that PAN.
*
* Note: This is in section 7.1.5 of the IEEE 802.15.4 document.
* Note: This API does not provide extended information such as what
* channel the PAN is on or what the LQI of the beacon frame was on
* receipt.
* 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, __le16 panid,
__le16 coord_addr);
/**
* ieee802154_nl_start_confirm - Notify userland of completion of start.
* @dev: The device which was instructed to scan.
* @status: The status of the scan operation.
*
* Note: This is in section 7.1.14 of the IEEE 802.15.4 document.
*/
int ieee802154_nl_start_confirm(struct net_device *dev, u8 status);
#endif
......@@ -319,7 +319,7 @@ lowpan_header_decompress(struct sk_buff *skb, struct net_device *dev,
if (iphc1 & LOWPAN_IPHC_CID) {
pr_debug("CID flag is set, increase header with one\n");
if (lowpan_fetch_skb(skb, &num_context, sizeof(num_context)))
goto drop;
return -EINVAL;
}
hdr.version = 6;
......@@ -331,7 +331,7 @@ lowpan_header_decompress(struct sk_buff *skb, struct net_device *dev,
*/
case 0: /* 00b */
if (lowpan_fetch_skb(skb, &tmp, sizeof(tmp)))
goto drop;
return -EINVAL;
memcpy(&hdr.flow_lbl, &skb->data[0], 3);
skb_pull(skb, 3);
......@@ -344,7 +344,7 @@ lowpan_header_decompress(struct sk_buff *skb, struct net_device *dev,
*/
case 2: /* 10b */
if (lowpan_fetch_skb(skb, &tmp, sizeof(tmp)))
goto drop;
return -EINVAL;
hdr.priority = ((tmp >> 2) & 0x0f);
hdr.flow_lbl[0] = ((tmp << 6) & 0xC0) | ((tmp >> 2) & 0x30);
......@@ -354,7 +354,7 @@ lowpan_header_decompress(struct sk_buff *skb, struct net_device *dev,
*/
case 1: /* 01b */
if (lowpan_fetch_skb(skb, &tmp, sizeof(tmp)))
goto drop;
return -EINVAL;
hdr.flow_lbl[0] = (skb->data[0] & 0x0F) | ((tmp >> 2) & 0x30);
memcpy(&hdr.flow_lbl[1], &skb->data[0], 2);
......@@ -371,7 +371,7 @@ lowpan_header_decompress(struct sk_buff *skb, struct net_device *dev,
if ((iphc0 & LOWPAN_IPHC_NH_C) == 0) {
/* Next header is carried inline */
if (lowpan_fetch_skb(skb, &hdr.nexthdr, sizeof(hdr.nexthdr)))
goto drop;
return -EINVAL;
pr_debug("NH flag is set, next header carried inline: %02x\n",
hdr.nexthdr);
......@@ -383,7 +383,7 @@ lowpan_header_decompress(struct sk_buff *skb, struct net_device *dev,
} else {
if (lowpan_fetch_skb(skb, &hdr.hop_limit,
sizeof(hdr.hop_limit)))
goto drop;
return -EINVAL;
}
/* Extract SAM to the tmp variable */
......@@ -402,7 +402,7 @@ lowpan_header_decompress(struct sk_buff *skb, struct net_device *dev,
/* Check on error of previous branch */
if (err)
goto drop;
return -EINVAL;
/* Extract DAM to the tmp variable */
tmp = ((iphc1 & LOWPAN_IPHC_DAM_11) >> LOWPAN_IPHC_DAM_BIT) & 0x03;
......@@ -417,7 +417,7 @@ lowpan_header_decompress(struct sk_buff *skb, struct net_device *dev,
tmp);
if (err)
goto drop;
return -EINVAL;
}
} else {
err = uncompress_addr(skb, &hdr.daddr, tmp, daddr,
......@@ -425,7 +425,7 @@ lowpan_header_decompress(struct sk_buff *skb, struct net_device *dev,
pr_debug("dest: stateless compression mode %d dest %pI6c\n",
tmp, &hdr.daddr);
if (err)
goto drop;
return -EINVAL;
}
/* UDP data uncompression */
......@@ -434,16 +434,14 @@ lowpan_header_decompress(struct sk_buff *skb, struct net_device *dev,
const int needed = sizeof(struct udphdr) + sizeof(hdr);
if (uncompress_udp_header(skb, &uh))
goto drop;
return -EINVAL;
/* replace the compressed UDP head by the uncompressed UDP
* header
*/
err = skb_cow(skb, needed);
if (unlikely(err)) {
kfree_skb(skb);
if (unlikely(err))
return err;
}
skb_push(skb, sizeof(struct udphdr));
skb_reset_transport_header(skb);
......@@ -455,10 +453,8 @@ lowpan_header_decompress(struct sk_buff *skb, struct net_device *dev,
hdr.nexthdr = UIP_PROTO_UDP;
} else {
err = skb_cow(skb, sizeof(hdr));
if (unlikely(err)) {
kfree_skb(skb);
if (unlikely(err))
return err;
}
}
hdr.payload_len = htons(skb->len);
......@@ -478,9 +474,6 @@ lowpan_header_decompress(struct sk_buff *skb, struct net_device *dev,
raw_dump_table(__func__, "raw header dump", (u8 *)&hdr, sizeof(hdr));
return 0;
drop:
kfree_skb(skb);
return -EINVAL;
}
EXPORT_SYMBOL_GPL(lowpan_header_decompress);
......@@ -512,9 +505,17 @@ static u8 lowpan_compress_addr_64(u8 **hc_ptr, u8 shift,
static void compress_udp_header(u8 **hc_ptr, struct sk_buff *skb)
{
struct udphdr *uh = udp_hdr(skb);
struct udphdr *uh;
u8 tmp;
/* In the case of RAW sockets the transport header is not set by
* the ip6 stack so we must set it ourselves
*/
if (skb->transport_header == skb->network_header)
skb_set_transport_header(skb, sizeof(struct ipv6hdr));
uh = udp_hdr(skb);
if (((ntohs(uh->source) & LOWPAN_NHC_UDP_4BIT_MASK) ==
LOWPAN_NHC_UDP_4BIT_PORT) &&
((ntohs(uh->dest) & LOWPAN_NHC_UDP_4BIT_MASK) ==
......
......@@ -294,20 +294,20 @@ static int iphc_decompress(struct sk_buff *skb, struct net_device *netdev,
peer = __peer_lookup_chan(dev, chan);
rcu_read_unlock();
if (!peer)
goto drop;
return -EINVAL;
saddr = peer->eui64_addr;
daddr = dev->netdev->dev_addr;
/* at least two bytes will be used for the encoding */
if (skb->len < 2)
goto drop;
return -EINVAL;
if (lowpan_fetch_skb_u8(skb, &iphc0))
goto drop;
return -EINVAL;
if (lowpan_fetch_skb_u8(skb, &iphc1))
goto drop;
return -EINVAL;
return lowpan_header_decompress(skb, netdev,
saddr, IEEE802154_ADDR_LONG,
......@@ -315,9 +315,6 @@ static int iphc_decompress(struct sk_buff *skb, struct net_device *netdev,
IEEE802154_ADDR_LONG, EUI64_ADDR_LEN,
iphc0, iphc1);
drop:
kfree_skb(skb);
return -EINVAL;
}
static int recv_pkt(struct sk_buff *skb, struct net_device *dev,
......@@ -370,8 +367,10 @@ static int recv_pkt(struct sk_buff *skb, struct net_device *dev,
goto drop;
ret = iphc_decompress(local_skb, dev, chan);
if (ret < 0)
if (ret < 0) {
kfree_skb(local_skb);
goto drop;
}
local_skb->protocol = htons(ETH_P_IPV6);
local_skb->pkt_type = PACKET_HOST;
......
......@@ -39,11 +39,10 @@ menuconfig BT
to Bluetooth kernel modules are provided in the BlueZ packages. For
more information, see <http://www.bluez.org/>.
config BT_6LOWPAN
tristate "Bluetooth 6LoWPAN support"
depends on BT && 6LOWPAN
help
IPv6 compression over Bluetooth Low Energy.
config BT_BREDR
bool "Bluetooth Classic (BR/EDR) features"
depends on BT
default y
source "net/bluetooth/rfcomm/Kconfig"
......@@ -53,4 +52,15 @@ source "net/bluetooth/cmtp/Kconfig"
source "net/bluetooth/hidp/Kconfig"
config BT_LE
bool "Bluetooth Low Energy (LE) features"
depends on BT
default y
config BT_6LOWPAN
tristate "Bluetooth 6LoWPAN support"
depends on BT_LE && 6LOWPAN
help
IPv6 compression over Bluetooth Low Energy.
source "drivers/bluetooth/Kconfig"
config BT_BNEP
tristate "BNEP protocol support"
depends on BT
depends on BT_BREDR
select CRC32
help
BNEP (Bluetooth Network Encapsulation Protocol) is Ethernet
......
config BT_CMTP
tristate "CMTP protocol support"
depends on BT && ISDN_CAPI
depends on BT_BREDR && ISDN_CAPI
help
CMTP (CAPI Message Transport Protocol) is a transport layer
for CAPI messages. CMTP is required for the Bluetooth Common
......
......@@ -200,31 +200,6 @@ static const struct file_operations blacklist_fops = {
.release = single_release,
};
static int whitelist_show(struct seq_file *f, void *p)
{
struct hci_dev *hdev = f->private;
struct bdaddr_list *b;
hci_dev_lock(hdev);
list_for_each_entry(b, &hdev->whitelist, list)
seq_printf(f, "%pMR (type %u)\n", &b->bdaddr, b->bdaddr_type);
hci_dev_unlock(hdev);
return 0;
}
static int whitelist_open(struct inode *inode, struct file *file)
{
return single_open(file, whitelist_show, inode->i_private);
}
static const struct file_operations whitelist_fops = {
.open = whitelist_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
static int uuids_show(struct seq_file *f, void *p)
{
struct hci_dev *hdev = f->private;
......@@ -1030,10 +1005,13 @@ static int device_list_show(struct seq_file *f, void *ptr)
{
struct hci_dev *hdev = f->private;
struct hci_conn_params *p;
struct bdaddr_list *b;
hci_dev_lock(hdev);
list_for_each_entry(b, &hdev->whitelist, list)
seq_printf(f, "%pMR (type %u)\n", &b->bdaddr, b->bdaddr_type);
list_for_each_entry(p, &hdev->le_conn_params, list) {
seq_printf(f, "%pMR %u %u\n", &p->addr, p->addr_type,
seq_printf(f, "%pMR (type %u) %u\n", &p->addr, p->addr_type,
p->auto_connect);
}
hci_dev_unlock(hdev);
......@@ -1147,13 +1125,15 @@ struct sk_buff *__hci_cmd_sync_ev(struct hci_dev *hdev, u16 opcode, u32 plen,
hdev->req_status = HCI_REQ_PEND;
err = hci_req_run(&req, hci_req_sync_complete);
if (err < 0)
return ERR_PTR(err);
add_wait_queue(&hdev->req_wait_q, &wait);
set_current_state(TASK_INTERRUPTIBLE);
err = hci_req_run(&req, hci_req_sync_complete);
if (err < 0) {
remove_wait_queue(&hdev->req_wait_q, &wait);
return ERR_PTR(err);
}
schedule_timeout(timeout);
remove_wait_queue(&hdev->req_wait_q, &wait);
......@@ -1211,10 +1191,15 @@ static int __hci_req_sync(struct hci_dev *hdev,
func(&req, opt);
add_wait_queue(&hdev->req_wait_q, &wait);
set_current_state(TASK_INTERRUPTIBLE);
err = hci_req_run(&req, hci_req_sync_complete);
if (err < 0) {
hdev->req_status = 0;
remove_wait_queue(&hdev->req_wait_q, &wait);
/* ENODATA means the HCI request command queue is empty.
* This can happen when a request with conditionals doesn't
* trigger any commands to be sent. This is normal behavior
......@@ -1226,9 +1211,6 @@ static int __hci_req_sync(struct hci_dev *hdev,
return err;
}
add_wait_queue(&hdev->req_wait_q, &wait);
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(timeout);
remove_wait_queue(&hdev->req_wait_q, &wait);
......@@ -1811,10 +1793,10 @@ static int __hci_init(struct hci_dev *hdev)
&hdev->manufacturer);
debugfs_create_u8("hci_version", 0444, hdev->debugfs, &hdev->hci_ver);
debugfs_create_u16("hci_revision", 0444, hdev->debugfs, &hdev->hci_rev);
debugfs_create_file("device_list", 0444, hdev->debugfs, hdev,
&device_list_fops);
debugfs_create_file("blacklist", 0444, hdev->debugfs, hdev,
&blacklist_fops);
debugfs_create_file("whitelist", 0444, hdev->debugfs, hdev,
&whitelist_fops);
debugfs_create_file("uuids", 0444, hdev->debugfs, hdev, &uuids_fops);
debugfs_create_file("conn_info_min_age", 0644, hdev->debugfs, hdev,
......@@ -1893,8 +1875,6 @@ static int __hci_init(struct hci_dev *hdev)
hdev, &adv_min_interval_fops);
debugfs_create_file("adv_max_interval", 0644, hdev->debugfs,
hdev, &adv_max_interval_fops);
debugfs_create_file("device_list", 0444, hdev->debugfs, hdev,
&device_list_fops);
debugfs_create_u16("discov_interleaved_timeout", 0644,
hdev->debugfs,
&hdev->discov_interleaved_timeout);
......@@ -4244,6 +4224,24 @@ int hci_resume_dev(struct hci_dev *hdev)
}
EXPORT_SYMBOL(hci_resume_dev);
/* Reset HCI device */
int hci_reset_dev(struct hci_dev *hdev)
{
const u8 hw_err[] = { HCI_EV_HARDWARE_ERROR, 0x01, 0x00 };
struct sk_buff *skb;
skb = bt_skb_alloc(3, GFP_ATOMIC);
if (!skb)
return -ENOMEM;
bt_cb(skb)->pkt_type = HCI_EVENT_PKT;
memcpy(skb_put(skb, 3), hw_err, 3);
/* Send Hardware Error to upper stack */
return hci_recv_frame(hdev, skb);
}
EXPORT_SYMBOL(hci_reset_dev);
/* Receive frame from HCI drivers */
int hci_recv_frame(struct hci_dev *hdev, struct sk_buff *skb)
{
......
......@@ -189,6 +189,9 @@ static void hci_cc_reset(struct hci_dev *hdev, struct sk_buff *skb)
clear_bit(HCI_RESET, &hdev->flags);
if (status)
return;
/* Reset all non-persistent flags */
hdev->dev_flags &= ~HCI_PERSISTENT_MASK;
......@@ -1944,6 +1947,29 @@ static void hci_cs_le_start_enc(struct hci_dev *hdev, u8 status)
hci_dev_unlock(hdev);
}
static void hci_cs_switch_role(struct hci_dev *hdev, u8 status)
{
struct hci_cp_switch_role *cp;
struct hci_conn *conn;
BT_DBG("%s status 0x%2.2x", hdev->name, status);
if (!status)
return;
cp = hci_sent_cmd_data(hdev, HCI_OP_SWITCH_ROLE);
if (!cp)
return;
hci_dev_lock(hdev);
conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
if (conn)
clear_bit(HCI_CONN_RSWITCH_PEND, &conn->flags);
hci_dev_unlock(hdev);
}
static void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
__u8 status = *((__u8 *) skb->data);
......@@ -2847,6 +2873,10 @@ static void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb)
hci_cs_create_conn(hdev, ev->status);
break;
case HCI_OP_DISCONNECT:
hci_cs_disconnect(hdev, ev->status);
break;
case HCI_OP_ADD_SCO:
hci_cs_add_sco(hdev, ev->status);
break;
......@@ -2875,24 +2905,24 @@ static void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb)
hci_cs_setup_sync_conn(hdev, ev->status);
break;
case HCI_OP_SNIFF_MODE:
hci_cs_sniff_mode(hdev, ev->status);
case HCI_OP_CREATE_PHY_LINK:
hci_cs_create_phylink(hdev, ev->status);
break;
case HCI_OP_EXIT_SNIFF_MODE:
hci_cs_exit_sniff_mode(hdev, ev->status);
case HCI_OP_ACCEPT_PHY_LINK:
hci_cs_accept_phylink(hdev, ev->status);
break;
case HCI_OP_DISCONNECT:
hci_cs_disconnect(hdev, ev->status);
case HCI_OP_SNIFF_MODE:
hci_cs_sniff_mode(hdev, ev->status);
break;
case HCI_OP_CREATE_PHY_LINK:
hci_cs_create_phylink(hdev, ev->status);
case HCI_OP_EXIT_SNIFF_MODE:
hci_cs_exit_sniff_mode(hdev, ev->status);
break;
case HCI_OP_ACCEPT_PHY_LINK:
hci_cs_accept_phylink(hdev, ev->status);
case HCI_OP_SWITCH_ROLE:
hci_cs_switch_role(hdev, ev->status);
break;
case HCI_OP_LE_CREATE_CONN:
......@@ -2922,6 +2952,13 @@ static void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb)
}
}
static void hci_hardware_error_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
struct hci_ev_hardware_error *ev = (void *) skb->data;
BT_ERR("%s hardware error 0x%2.2x", hdev->name, ev->code);
}
static void hci_role_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
struct hci_ev_role_change *ev = (void *) skb->data;
......@@ -4743,6 +4780,10 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
hci_cmd_status_evt(hdev, skb);
break;
case HCI_EV_HARDWARE_ERROR:
hci_hardware_error_evt(hdev, skb);
break;
case HCI_EV_ROLE_CHANGE:
hci_role_change_evt(hdev, skb);
break;
......
config BT_HIDP
tristate "HIDP protocol support"
depends on BT && INPUT
depends on BT_BREDR && INPUT
select HID
help
HIDP (Human Interface Device Protocol) is a transport layer
......
......@@ -3727,20 +3727,23 @@ static int start_discovery(struct sock *sk, struct hci_dev *hdev,
hci_dev_lock(hdev);
if (!hdev_is_powered(hdev)) {
err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
MGMT_STATUS_NOT_POWERED);
err = cmd_complete(sk, hdev->id, MGMT_OP_START_DISCOVERY,
MGMT_STATUS_NOT_POWERED,
&cp->type, sizeof(cp->type));
goto failed;
}
if (test_bit(HCI_PERIODIC_INQ, &hdev->dev_flags)) {
err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
MGMT_STATUS_BUSY);
err = cmd_complete(sk, hdev->id, MGMT_OP_START_DISCOVERY,
MGMT_STATUS_BUSY, &cp->type,
sizeof(cp->type));
goto failed;
}
if (hdev->discovery.state != DISCOVERY_STOPPED) {
err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
MGMT_STATUS_BUSY);
err = cmd_complete(sk, hdev->id, MGMT_OP_START_DISCOVERY,
MGMT_STATUS_BUSY, &cp->type,
sizeof(cp->type));
goto failed;
}
......@@ -3758,15 +3761,18 @@ static int start_discovery(struct sock *sk, struct hci_dev *hdev,
case DISCOV_TYPE_BREDR:
status = mgmt_bredr_support(hdev);
if (status) {
err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
status);
err = cmd_complete(sk, hdev->id,
MGMT_OP_START_DISCOVERY, status,
&cp->type, sizeof(cp->type));
mgmt_pending_remove(cmd);
goto failed;
}
if (test_bit(HCI_INQUIRY, &hdev->flags)) {
err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
MGMT_STATUS_BUSY);
err = cmd_complete(sk, hdev->id,
MGMT_OP_START_DISCOVERY,
MGMT_STATUS_BUSY, &cp->type,
sizeof(cp->type));
mgmt_pending_remove(cmd);
goto failed;
}
......@@ -3783,16 +3789,19 @@ static int start_discovery(struct sock *sk, struct hci_dev *hdev,
case DISCOV_TYPE_INTERLEAVED:
status = mgmt_le_support(hdev);
if (status) {
err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
status);
err = cmd_complete(sk, hdev->id,
MGMT_OP_START_DISCOVERY, status,
&cp->type, sizeof(cp->type));
mgmt_pending_remove(cmd);
goto failed;
}
if (hdev->discovery.type == DISCOV_TYPE_INTERLEAVED &&
!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
MGMT_STATUS_NOT_SUPPORTED);
err = cmd_complete(sk, hdev->id,
MGMT_OP_START_DISCOVERY,
MGMT_STATUS_NOT_SUPPORTED,
&cp->type, sizeof(cp->type));
mgmt_pending_remove(cmd);
goto failed;
}
......@@ -3804,9 +3813,11 @@ static int start_discovery(struct sock *sk, struct hci_dev *hdev,
*/
if (hci_conn_hash_lookup_state(hdev, LE_LINK,
BT_CONNECT)) {
err = cmd_status(sk, hdev->id,
MGMT_OP_START_DISCOVERY,
MGMT_STATUS_REJECTED);
err = cmd_complete(sk, hdev->id,
MGMT_OP_START_DISCOVERY,
MGMT_STATUS_REJECTED,
&cp->type,
sizeof(cp->type));
mgmt_pending_remove(cmd);
goto failed;
}
......@@ -3829,8 +3840,10 @@ static int start_discovery(struct sock *sk, struct hci_dev *hdev,
*/
err = hci_update_random_address(&req, true, &own_addr_type);
if (err < 0) {
err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
MGMT_STATUS_FAILED);
err = cmd_complete(sk, hdev->id,
MGMT_OP_START_DISCOVERY,
MGMT_STATUS_FAILED,
&cp->type, sizeof(cp->type));
mgmt_pending_remove(cmd);
goto failed;
}
......@@ -3850,8 +3863,9 @@ static int start_discovery(struct sock *sk, struct hci_dev *hdev,
break;
default:
err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
MGMT_STATUS_INVALID_PARAMS);
err = cmd_complete(sk, hdev->id, MGMT_OP_START_DISCOVERY,
MGMT_STATUS_INVALID_PARAMS,
&cp->type, sizeof(cp->type));
mgmt_pending_remove(cmd);
goto failed;
}
......
config BT_RFCOMM
tristate "RFCOMM protocol support"
depends on BT
depends on BT_BREDR
help
RFCOMM provides connection oriented stream transport. RFCOMM
support is required for Dialup Networking, OBEX and other Bluetooth
......
......@@ -81,6 +81,8 @@ static struct rfcomm_session *rfcomm_session_del(struct rfcomm_session *s);
#define __test_cr(b) (!!(b & 0x02))
#define __test_pf(b) (!!(b & 0x10))
#define __session_dir(s) ((s)->initiator ? 0x00 : 0x01)
#define __addr(cr, dlci) (((dlci & 0x3f) << 2) | (cr << 1) | 0x01)
#define __ctrl(type, pf) (((type & 0xef) | (pf << 4)))
#define __dlci(dir, chn) (((chn & 0x1f) << 1) | dir)
......@@ -388,7 +390,7 @@ static int __rfcomm_dlc_open(struct rfcomm_dlc *d, bdaddr_t *src, bdaddr_t *dst,
return err;
}
dlci = __dlci(!s->initiator, channel);
dlci = __dlci(__session_dir(s), channel);
/* Check if DLCI already exists */
if (rfcomm_dlc_get(s, dlci))
......@@ -543,7 +545,7 @@ struct rfcomm_dlc *rfcomm_dlc_exists(bdaddr_t *src, bdaddr_t *dst, u8 channel)
rfcomm_lock();
s = rfcomm_session_get(src, dst);
if (s) {
dlci = __dlci(!s->initiator, channel);
dlci = __dlci(__session_dir(s), channel);
dlc = rfcomm_dlc_get(s, dlci);
}
rfcomm_unlock();
......
......@@ -176,13 +176,13 @@ iphc_decompress(struct sk_buff *skb, const struct ieee802154_hdr *hdr)
raw_dump_table(__func__, "raw skb data dump", skb->data, skb->len);
/* at least two bytes will be used for the encoding */
if (skb->len < 2)
goto drop;
return -EINVAL;
if (lowpan_fetch_skb_u8(skb, &iphc0))
goto drop;
return -EINVAL;
if (lowpan_fetch_skb_u8(skb, &iphc1))
goto drop;
return -EINVAL;
ieee802154_addr_to_sa(&sa, &hdr->source);
ieee802154_addr_to_sa(&da, &hdr->dest);
......@@ -200,23 +200,6 @@ iphc_decompress(struct sk_buff *skb, const struct ieee802154_hdr *hdr)
return lowpan_header_decompress(skb, skb->dev, sap, sa.addr_type,
IEEE802154_ADDR_LEN, dap, da.addr_type,
IEEE802154_ADDR_LEN, iphc0, iphc1);
drop:
kfree_skb(skb);
return -EINVAL;
}
static int lowpan_set_address(struct net_device *dev, void *p)
{
struct sockaddr *sa = p;
if (netif_running(dev))
return -EBUSY;
/* TODO: validate addr */
memcpy(dev->dev_addr, sa->sa_data, dev->addr_len);
return 0;
}
static struct sk_buff*
......@@ -420,13 +403,6 @@ static netdev_tx_t lowpan_xmit(struct sk_buff *skb, struct net_device *dev)
}
}
static struct wpan_phy *lowpan_get_phy(const struct net_device *dev)
{
struct net_device *real_dev = lowpan_dev_info(dev)->real_dev;
return ieee802154_mlme_ops(real_dev)->get_phy(real_dev);
}
static __le16 lowpan_get_pan_id(const struct net_device *dev)
{
struct net_device *real_dev = lowpan_dev_info(dev)->real_dev;
......@@ -474,12 +450,10 @@ static int lowpan_dev_init(struct net_device *dev)
static const struct net_device_ops lowpan_netdev_ops = {
.ndo_init = lowpan_dev_init,
.ndo_start_xmit = lowpan_xmit,
.ndo_set_mac_address = lowpan_set_address,
};
static struct ieee802154_mlme_ops lowpan_mlme = {
.get_pan_id = lowpan_get_pan_id,
.get_phy = lowpan_get_phy,
.get_short_addr = lowpan_get_short_addr,
.get_dsn = lowpan_get_dsn,
};
......@@ -544,7 +518,7 @@ static int lowpan_rcv(struct sk_buff *skb, struct net_device *dev,
case LOWPAN_DISPATCH_IPHC: /* ipv6 datagram */
ret = iphc_decompress(skb, &hdr);
if (ret < 0)
goto drop;
goto drop_skb;
return lowpan_give_skb_to_devices(skb, NULL);
case LOWPAN_DISPATCH_FRAG1: /* first fragment header */
......@@ -552,7 +526,7 @@ static int lowpan_rcv(struct sk_buff *skb, struct net_device *dev,
if (ret == 1) {
ret = iphc_decompress(skb, &hdr);
if (ret < 0)
goto drop;
goto drop_skb;
return lowpan_give_skb_to_devices(skb, NULL);
} else if (ret == -1) {
......@@ -565,7 +539,7 @@ static int lowpan_rcv(struct sk_buff *skb, struct net_device *dev,
if (ret == 1) {
ret = iphc_decompress(skb, &hdr);
if (ret < 0)
goto drop;
goto drop_skb;
return lowpan_give_skb_to_devices(skb, NULL);
} else if (ret == -1) {
......
......@@ -21,9 +21,7 @@
#include "ieee802154.h"
#include "sysfs.h"
static DEFINE_MUTEX(wpan_phy_mutex);
static int wpan_phy_idx;
#include "core.h"
static int wpan_phy_match(struct device *dev, const void *data)
{
......@@ -71,42 +69,41 @@ int wpan_phy_for_each(int (*fn)(struct wpan_phy *phy, void *data),
}
EXPORT_SYMBOL(wpan_phy_for_each);
static int wpan_phy_idx_valid(int idx)
struct wpan_phy *
wpan_phy_alloc(const struct cfg802154_ops *ops, size_t priv_size)
{
return idx >= 0;
}
static atomic_t wpan_phy_counter = ATOMIC_INIT(0);
struct cfg802154_registered_device *rdev;
size_t alloc_size;
struct wpan_phy *wpan_phy_alloc(size_t priv_size)
{
struct wpan_phy *phy = kzalloc(sizeof(*phy) + priv_size,
GFP_KERNEL);
if (!phy)
goto out;
mutex_lock(&wpan_phy_mutex);
phy->idx = wpan_phy_idx++;
if (unlikely(!wpan_phy_idx_valid(phy->idx))) {
wpan_phy_idx--;
mutex_unlock(&wpan_phy_mutex);
kfree(phy);
goto out;
}
mutex_unlock(&wpan_phy_mutex);
alloc_size = sizeof(*rdev) + priv_size;
rdev = kzalloc(alloc_size, GFP_KERNEL);
if (!rdev)
return NULL;
rdev->ops = ops;
mutex_init(&phy->pib_lock);
rdev->wpan_phy_idx = atomic_inc_return(&wpan_phy_counter);
device_initialize(&phy->dev);
dev_set_name(&phy->dev, "wpan-phy%d", phy->idx);
if (unlikely(rdev->wpan_phy_idx < 0)) {
/* ugh, wrapped! */
atomic_dec(&wpan_phy_counter);
kfree(rdev);
return NULL;
}
/* atomic_inc_return makes it start at 1, make it start at 0 */
rdev->wpan_phy_idx--;
phy->dev.class = &wpan_phy_class;
mutex_init(&rdev->wpan_phy.pib_lock);
phy->current_channel = -1; /* not initialised */
phy->current_page = 0; /* for compatibility */
device_initialize(&rdev->wpan_phy.dev);
dev_set_name(&rdev->wpan_phy.dev, "wpan-phy%d", rdev->wpan_phy_idx);
return phy;
rdev->wpan_phy.dev.class = &wpan_phy_class;
rdev->wpan_phy.dev.platform_data = rdev;
out:
return NULL;
return &rdev->wpan_phy;
}
EXPORT_SYMBOL(wpan_phy_alloc);
......@@ -128,6 +125,11 @@ void wpan_phy_free(struct wpan_phy *phy)
}
EXPORT_SYMBOL(wpan_phy_free);
void cfg802154_dev_free(struct cfg802154_registered_device *rdev)
{
kfree(rdev);
}
static int __init wpan_phy_class_init(void)
{
int rc;
......
#ifndef __IEEE802154_CORE_H
#define __IEEE802154_CORE_H
#include <net/cfg802154.h>
struct cfg802154_registered_device {
const struct cfg802154_ops *ops;
/* wpan_phy index, internal only */
int wpan_phy_idx;
/* must be last because of the way we do wpan_phy_priv(),
* and it should at least be aligned to NETDEV_ALIGN
*/
struct wpan_phy wpan_phy __aligned(NETDEV_ALIGN);
};
static inline struct cfg802154_registered_device *
wpan_phy_to_rdev(struct wpan_phy *wpan_phy)
{
BUG_ON(!wpan_phy);
return container_of(wpan_phy, struct cfg802154_registered_device,
wpan_phy);
}
/* free object */
void cfg802154_dev_free(struct cfg802154_registered_device *rdev);
#endif /* __IEEE802154_CORE_H */
......@@ -29,7 +29,6 @@
#include <linux/nl802154.h>
#include <linux/export.h>
#include <net/af_ieee802154.h>
#include <net/nl802154.h>
#include <net/ieee802154_netdev.h>
#include <net/cfg802154.h>
......@@ -55,186 +54,7 @@ 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)
{
struct sk_buff *msg;
pr_debug("%s\n", __func__);
if (addr->mode != IEEE802154_ADDR_LONG) {
pr_err("%s: received non-long source address!\n", __func__);
return -EINVAL;
}
msg = ieee802154_nl_create(0, IEEE802154_ASSOCIATE_INDIC);
if (!msg)
return -ENOBUFS;
if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) ||
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_hwaddr(msg, IEEE802154_ATTR_SRC_HW_ADDR,
addr->extended_addr) ||
nla_put_u8(msg, IEEE802154_ATTR_CAPABILITY, cap))
goto nla_put_failure;
return ieee802154_nl_mcast(msg, IEEE802154_COORD_MCGRP);
nla_put_failure:
nlmsg_free(msg);
return -ENOBUFS;
}
EXPORT_SYMBOL(ieee802154_nl_assoc_indic);
int ieee802154_nl_assoc_confirm(struct net_device *dev, __le16 short_addr,
u8 status)
{
struct sk_buff *msg;
pr_debug("%s\n", __func__);
msg = ieee802154_nl_create(0, IEEE802154_ASSOCIATE_CONF);
if (!msg)
return -ENOBUFS;
if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) ||
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_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);
nla_put_failure:
nlmsg_free(msg);
return -ENOBUFS;
}
EXPORT_SYMBOL(ieee802154_nl_assoc_confirm);
int ieee802154_nl_disassoc_indic(struct net_device *dev,
struct ieee802154_addr *addr,
u8 reason)
{
struct sk_buff *msg;
pr_debug("%s\n", __func__);
msg = ieee802154_nl_create(0, IEEE802154_DISASSOCIATE_INDIC);
if (!msg)
return -ENOBUFS;
if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) ||
nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
dev->dev_addr))
goto nla_put_failure;
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_shortaddr(msg, IEEE802154_ATTR_SRC_SHORT_ADDR,
addr->short_addr))
goto nla_put_failure;
}
if (nla_put_u8(msg, IEEE802154_ATTR_REASON, reason))
goto nla_put_failure;
return ieee802154_nl_mcast(msg, IEEE802154_COORD_MCGRP);
nla_put_failure:
nlmsg_free(msg);
return -ENOBUFS;
}
EXPORT_SYMBOL(ieee802154_nl_disassoc_indic);
int ieee802154_nl_disassoc_confirm(struct net_device *dev, u8 status)
{
struct sk_buff *msg;
pr_debug("%s\n", __func__);
msg = ieee802154_nl_create(0, IEEE802154_DISASSOCIATE_CONF);
if (!msg)
return -ENOBUFS;
if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) ||
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_u8(msg, IEEE802154_ATTR_STATUS, status))
goto nla_put_failure;
return ieee802154_nl_mcast(msg, IEEE802154_COORD_MCGRP);
nla_put_failure:
nlmsg_free(msg);
return -ENOBUFS;
}
EXPORT_SYMBOL(ieee802154_nl_disassoc_confirm);
int ieee802154_nl_beacon_indic(struct net_device *dev, __le16 panid,
__le16 coord_addr)
{
struct sk_buff *msg;
pr_debug("%s\n", __func__);
msg = ieee802154_nl_create(0, IEEE802154_BEACON_NOTIFY_INDIC);
if (!msg)
return -ENOBUFS;
if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) ||
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_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);
nla_put_failure:
nlmsg_free(msg);
return -ENOBUFS;
}
EXPORT_SYMBOL(ieee802154_nl_beacon_indic);
int ieee802154_nl_scan_confirm(struct net_device *dev,
u8 status, u8 scan_type,
u32 unscanned, u8 page,
u8 *edl/* , struct list_head *pan_desc_list */)
{
struct sk_buff *msg;
pr_debug("%s\n", __func__);
msg = ieee802154_nl_create(0, IEEE802154_SCAN_CONF);
if (!msg)
return -ENOBUFS;
if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) ||
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_u8(msg, IEEE802154_ATTR_STATUS, status) ||
nla_put_u8(msg, IEEE802154_ATTR_SCAN_TYPE, scan_type) ||
nla_put_u32(msg, IEEE802154_ATTR_CHANNELS, unscanned) ||
nla_put_u8(msg, IEEE802154_ATTR_PAGE, page) ||
(edl &&
nla_put(msg, IEEE802154_ATTR_ED_LIST, 27, edl)))
goto nla_put_failure;
return ieee802154_nl_mcast(msg, IEEE802154_COORD_MCGRP);
nla_put_failure:
nlmsg_free(msg);
return -ENOBUFS;
}
EXPORT_SYMBOL(ieee802154_nl_scan_confirm);
int ieee802154_nl_start_confirm(struct net_device *dev, u8 status)
static int ieee802154_nl_start_confirm(struct net_device *dev, u8 status)
{
struct sk_buff *msg;
......@@ -274,8 +94,9 @@ static int ieee802154_nl_fill_iface(struct sk_buff *msg, u32 portid,
goto out;
ops = ieee802154_mlme_ops(dev);
phy = ops->get_phy(dev);
phy = dev->ieee802154_ptr->wpan_phy;
BUG_ON(!phy);
get_device(&phy->dev);
short_addr = ops->get_short_addr(dev);
pan_id = ops->get_pan_id(dev);
......@@ -477,7 +298,7 @@ int ieee802154_start_req(struct sk_buff *skb, struct genl_info *info)
u8 channel, bcn_ord, sf_ord;
u8 page;
int pan_coord, blx, coord_realign;
int ret = -EOPNOTSUPP;
int ret = -EBUSY;
if (!info->attrs[IEEE802154_ATTR_COORD_PAN_ID] ||
!info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR] ||
......@@ -493,8 +314,14 @@ int ieee802154_start_req(struct sk_buff *skb, struct genl_info *info)
dev = ieee802154_nl_get_dev(info);
if (!dev)
return -ENODEV;
if (!ieee802154_mlme_ops(dev)->start_req)
if (netif_running(dev))
goto out;
if (!ieee802154_mlme_ops(dev)->start_req) {
ret = -EOPNOTSUPP;
goto out;
}
addr.mode = IEEE802154_ADDR_SHORT;
addr.short_addr = nla_get_shortaddr(
......@@ -524,6 +351,11 @@ int ieee802154_start_req(struct sk_buff *skb, struct genl_info *info)
ret = ieee802154_mlme_ops(dev)->start_req(dev, &addr, channel, page,
bcn_ord, sf_ord, pan_coord, blx, coord_realign);
/* FIXME: add validation for unused parameters to be sane
* for SoftMAC
*/
ieee802154_nl_start_confirm(dev, IEEE802154_SUCCESS);
out:
dev_put(dev);
return ret;
......@@ -662,7 +494,8 @@ int ieee802154_set_macparams(struct sk_buff *skb, struct genl_info *info)
!info->attrs[IEEE802154_ATTR_FRAME_RETRIES])
goto out;
phy = ops->get_phy(dev);
phy = dev->ieee802154_ptr->wpan_phy;
get_device(&phy->dev);
ops->get_mac_params(dev, &params);
......
......@@ -30,6 +30,8 @@
#include <linux/nl802154.h>
#include "ieee802154.h"
#include "rdev-ops.h"
#include "core.h"
static int ieee802154_nl_fill_phy(struct sk_buff *msg, u32 portid,
u32 seq, int flags, struct wpan_phy *phy)
......@@ -203,11 +205,6 @@ int ieee802154_add_iface(struct sk_buff *skb, struct genl_info *info)
if (!msg)
goto out_dev;
if (!phy->add_iface) {
rc = -EINVAL;
goto nla_put_failure;
}
if (info->attrs[IEEE802154_ATTR_HW_ADDR] &&
nla_len(info->attrs[IEEE802154_ATTR_HW_ADDR]) !=
IEEE802154_ADDR_LEN) {
......@@ -223,11 +220,13 @@ int ieee802154_add_iface(struct sk_buff *skb, struct genl_info *info)
}
}
dev = phy->add_iface(phy, devname, type);
dev = rdev_add_virtual_intf_deprecated(wpan_phy_to_rdev(phy), devname,
type);
if (IS_ERR(dev)) {
rc = PTR_ERR(dev);
goto nla_put_failure;
}
dev_hold(dev);
if (info->attrs[IEEE802154_ATTR_HW_ADDR]) {
struct sockaddr addr;
......@@ -257,7 +256,7 @@ int ieee802154_add_iface(struct sk_buff *skb, struct genl_info *info)
dev_unregister:
rtnl_lock(); /* del_iface must be called with RTNL lock */
phy->del_iface(phy, dev);
rdev_del_virtual_intf_deprecated(wpan_phy_to_rdev(phy), dev);
dev_put(dev);
rtnl_unlock();
nla_put_failure:
......@@ -288,8 +287,9 @@ int ieee802154_del_iface(struct sk_buff *skb, struct genl_info *info)
if (!dev)
return -ENODEV;
phy = ieee802154_mlme_ops(dev)->get_phy(dev);
phy = dev->ieee802154_ptr->wpan_phy;
BUG_ON(!phy);
get_device(&phy->dev);
rc = -EINVAL;
/* phy name is optional, but should be checked if it's given */
......@@ -319,13 +319,8 @@ int ieee802154_del_iface(struct sk_buff *skb, struct genl_info *info)
if (!msg)
goto out_dev;
if (!phy->del_iface) {
rc = -EINVAL;
goto nla_put_failure;
}
rtnl_lock();
phy->del_iface(phy, dev);
rdev_del_virtual_intf_deprecated(wpan_phy_to_rdev(phy), dev);
/* We don't have device anymore */
dev_put(dev);
......
#ifndef __CFG802154_RDEV_OPS
#define __CFG802154_RDEV_OPS
#include <net/cfg802154.h>
#include "core.h"
static inline struct net_device *
rdev_add_virtual_intf_deprecated(struct cfg802154_registered_device *rdev,
const char *name, int type)
{
return rdev->ops->add_virtual_intf_deprecated(&rdev->wpan_phy, name,
type);
}
static inline void
rdev_del_virtual_intf_deprecated(struct cfg802154_registered_device *rdev,
struct net_device *dev)
{
rdev->ops->del_virtual_intf_deprecated(&rdev->wpan_phy, dev);
}
#endif /* __CFG802154_RDEV_OPS */
......@@ -17,6 +17,16 @@
#include <net/cfg802154.h>
#include "core.h"
#include "sysfs.h"
static inline struct cfg802154_registered_device *
dev_to_rdev(struct device *dev)
{
return container_of(dev, struct cfg802154_registered_device,
wpan_phy.dev);
}
#define MASTER_SHOW_COMPLEX(name, format_string, args...) \
static ssize_t name ## _show(struct device *dev, \
struct device_attribute *attr, char *buf) \
......@@ -60,11 +70,11 @@ static ssize_t channels_supported_show(struct device *dev,
}
static DEVICE_ATTR_RO(channels_supported);
static void wpan_phy_release(struct device *d)
static void wpan_phy_release(struct device *dev)
{
struct wpan_phy *phy = container_of(d, struct wpan_phy, dev);
struct cfg802154_registered_device *rdev = dev_to_rdev(dev);
kfree(phy);
cfg802154_dev_free(rdev);
}
static struct attribute *pmib_attrs[] = {
......
obj-$(CONFIG_MAC802154) += mac802154.o
mac802154-objs := main.o rx.o tx.o mac_cmd.o mib.o \
iface.o llsec.o util.o
iface.o llsec.o util.o cfg.o
ccflags-y += -D__CHECK_ENDIAN__
/* 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.
*
* Authors:
* Alexander Aring <aar@pengutronix.de>
*
* Based on: net/mac80211/cfg.c
*/
#include <net/rtnetlink.h>
#include <net/cfg802154.h>
#include "ieee802154_i.h"
#include "cfg.h"
static struct net_device *
ieee802154_add_iface_deprecated(struct wpan_phy *wpan_phy,
const char *name, int type)
{
struct ieee802154_local *local = wpan_phy_priv(wpan_phy);
struct net_device *dev;
rtnl_lock();
dev = ieee802154_if_add(local, name, NULL, type);
rtnl_unlock();
return dev;
}
static void ieee802154_del_iface_deprecated(struct wpan_phy *wpan_phy,
struct net_device *dev)
{
struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
ieee802154_if_remove(sdata);
}
const struct cfg802154_ops mac802154_config_ops = {
.add_virtual_intf_deprecated = ieee802154_add_iface_deprecated,
.del_virtual_intf_deprecated = ieee802154_del_iface_deprecated,
};
/* mac802154 configuration hooks for cfg802154
*/
#ifndef __CFG_H
#define __CFG_H
extern const struct cfg802154_ops mac802154_config_ops;
#endif /* __CFG_H */
......@@ -20,6 +20,7 @@
#define __IEEE802154_I_H
#include <linux/mutex.h>
#include <net/cfg802154.h>
#include <net/mac802154.h>
#include <net/ieee802154_netdev.h>
......@@ -73,18 +74,20 @@ enum ieee802154_sdata_state_bits {
struct ieee802154_sub_if_data {
struct list_head list; /* the ieee802154_priv->slaves list */
struct wpan_dev wpan_dev;
struct ieee802154_local *local;
struct net_device *dev;
int type;
unsigned long state;
char name[IFNAMSIZ];
spinlock_t mib_lock;
__le16 pan_id;
__le16 short_addr;
__le64 extended_addr;
bool promisuous_mode;
bool promiscuous_mode;
struct ieee802154_mac_params mac_params;
......@@ -99,6 +102,8 @@ struct ieee802154_sub_if_data {
struct mutex sec_mtx;
struct mac802154_llsec sec;
/* must be last, dynamically sized area in this! */
struct ieee802154_vif vif;
};
#define MAC802154_CHAN_NONE 0xff /* No channel is assigned */
......@@ -135,7 +140,6 @@ ieee802154_subif_start_xmit(struct sk_buff *skb, struct net_device *dev);
/* MIB callbacks */
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);
__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);
......@@ -174,4 +178,11 @@ void mac802154_get_table(struct net_device *dev,
struct ieee802154_llsec_table **t);
void mac802154_unlock_table(struct net_device *dev);
struct net_device *
mac802154_add_iface(struct wpan_phy *phy, const char *name, int type);
void ieee802154_if_remove(struct ieee802154_sub_if_data *sdata);
struct net_device *
ieee802154_if_add(struct ieee802154_local *local, const char *name,
struct wpan_dev **new_wpan_dev, int type);
#endif /* __IEEE802154_I_H */
......@@ -24,7 +24,6 @@
#include <net/rtnetlink.h>
#include <linux/nl802154.h>
#include <net/af_ieee802154.h>
#include <net/mac802154.h>
#include <net/ieee802154_netdev.h>
#include <net/cfg802154.h>
......@@ -110,37 +109,21 @@ mac802154_wpan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
static int mac802154_wpan_mac_addr(struct net_device *dev, void *p)
{
struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
struct sockaddr *addr = p;
__le64 extended_addr;
if (netif_running(dev))
return -EBUSY;
/* FIXME: validate addr */
memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
mac802154_dev_set_ieee_addr(dev);
return mac802154_wpan_update_llsec(dev);
}
int mac802154_set_mac_params(struct net_device *dev,
const struct ieee802154_mac_params *params)
{
struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
mutex_lock(&sdata->local->iflist_mtx);
sdata->mac_params = *params;
mutex_unlock(&sdata->local->iflist_mtx);
return 0;
}
ieee802154_be64_to_le64(&extended_addr, addr->sa_data);
if (!ieee802154_is_valid_extended_addr(extended_addr))
return -EINVAL;
void mac802154_get_mac_params(struct net_device *dev,
struct ieee802154_mac_params *params)
{
struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
sdata->extended_addr = extended_addr;
mutex_lock(&sdata->local->iflist_mtx);
*params = sdata->mac_params;
mutex_unlock(&sdata->local->iflist_mtx);
return mac802154_wpan_update_llsec(dev);
}
static int mac802154_slave_open(struct net_device *dev)
......@@ -152,10 +135,11 @@ static int mac802154_slave_open(struct net_device *dev)
ASSERT_RTNL();
if (sdata->type == IEEE802154_DEV_WPAN) {
if (sdata->vif.type == IEEE802154_DEV_WPAN) {
mutex_lock(&sdata->local->iflist_mtx);
list_for_each_entry(subif, &sdata->local->interfaces, list) {
if (subif != sdata && subif->type == sdata->type &&
if (subif != sdata &&
subif->vif.type == sdata->vif.type &&
ieee802154_sdata_running(subif)) {
mutex_unlock(&sdata->local->iflist_mtx);
return -EBUSY;
......@@ -197,32 +181,27 @@ static int mac802154_wpan_open(struct net_device *dev)
mutex_lock(&phy->pib_lock);
if (local->hw.flags & IEEE802154_HW_PROMISCUOUS) {
rc = drv_set_promiscuous_mode(local, sdata->promisuous_mode);
rc = drv_set_promiscuous_mode(local, sdata->promiscuous_mode);
if (rc < 0)
goto out;
}
if (local->hw.flags & IEEE802154_HW_TXPOWER) {
rc = drv_set_tx_power(local, sdata->mac_params.transmit_power);
if (local->hw.flags & IEEE802154_HW_AFILT) {
rc = drv_set_pan_id(local, sdata->pan_id);
if (rc < 0)
goto out;
}
if (local->hw.flags & IEEE802154_HW_LBT) {
rc = drv_set_lbt_mode(local, sdata->mac_params.lbt);
rc = drv_set_extended_addr(local, sdata->extended_addr);
if (rc < 0)
goto out;
}
if (local->hw.flags & IEEE802154_HW_CCA_MODE) {
rc = drv_set_cca_mode(local, sdata->mac_params.cca_mode);
rc = drv_set_short_addr(local, sdata->short_addr);
if (rc < 0)
goto out;
}
if (local->hw.flags & IEEE802154_HW_CCA_ED_LEVEL) {
rc = drv_set_cca_ed_level(local,
sdata->mac_params.cca_ed_level);
if (local->hw.flags & IEEE802154_HW_LBT) {
rc = drv_set_lbt_mode(local, sdata->mac_params.lbt);
if (rc < 0)
goto out;
}
......@@ -402,30 +381,23 @@ static void mac802154_wpan_free(struct net_device *dev)
free_netdev(dev);
}
void mac802154_wpan_setup(struct net_device *dev)
static void ieee802154_if_setup(struct net_device *dev)
{
struct ieee802154_sub_if_data *sdata;
dev->addr_len = IEEE802154_ADDR_LEN;
memset(dev->broadcast, 0xff, IEEE802154_ADDR_LEN);
dev->addr_len = IEEE802154_EXTENDED_ADDR_LEN;
memset(dev->broadcast, 0xff, IEEE802154_EXTENDED_ADDR_LEN);
dev->hard_header_len = MAC802154_FRAME_HARD_HEADER_LEN;
dev->header_ops = &mac802154_header_ops;
dev->needed_tailroom = 2 + 16; /* FCS + MIC */
dev->mtu = IEEE802154_MTU;
dev->tx_queue_len = 300;
dev->type = ARPHRD_IEEE802154;
dev->flags = IFF_NOARP | IFF_BROADCAST;
}
dev->destructor = mac802154_wpan_free;
dev->netdev_ops = &mac802154_wpan_ops;
dev->ml_priv = &mac802154_mlme_wpan;
sdata = IEEE802154_DEV_TO_SUB_IF(dev);
sdata->type = IEEE802154_DEV_WPAN;
spin_lock_init(&sdata->mib_lock);
mutex_init(&sdata->sec_mtx);
static int
ieee802154_setup_sdata(struct ieee802154_sub_if_data *sdata, int type)
{
/* set some type-dependent values */
sdata->vif.type = type;
get_random_bytes(&sdata->bsn, 1);
get_random_bytes(&sdata->dsn, 1);
......@@ -437,30 +409,113 @@ void mac802154_wpan_setup(struct net_device *dev)
/* for compatibility, actual default is 3 */
sdata->mac_params.frame_retries = -1;
ieee802154_be64_to_le64(&sdata->extended_addr, sdata->dev->dev_addr);
sdata->pan_id = cpu_to_le16(IEEE802154_PANID_BROADCAST);
sdata->short_addr = cpu_to_le16(IEEE802154_ADDR_BROADCAST);
sdata->promisuous_mode = false;
switch (type) {
case IEEE802154_DEV_WPAN:
sdata->dev->header_ops = &mac802154_header_ops;
sdata->dev->destructor = mac802154_wpan_free;
sdata->dev->netdev_ops = &mac802154_wpan_ops;
sdata->dev->ml_priv = &mac802154_mlme_wpan;
sdata->promiscuous_mode = false;
spin_lock_init(&sdata->mib_lock);
mutex_init(&sdata->sec_mtx);
mac802154_llsec_init(&sdata->sec);
break;
case IEEE802154_DEV_MONITOR:
sdata->dev->destructor = free_netdev;
sdata->dev->netdev_ops = &mac802154_monitor_ops;
sdata->promiscuous_mode = true;
break;
default:
BUG();
}
mac802154_llsec_init(&sdata->sec);
return 0;
}
void mac802154_monitor_setup(struct net_device *dev)
struct net_device *
ieee802154_if_add(struct ieee802154_local *local, const char *name,
struct wpan_dev **new_wpan_dev, int type)
{
struct ieee802154_sub_if_data *sdata;
struct net_device *ndev = NULL;
struct ieee802154_sub_if_data *sdata = NULL;
int ret = -ENOMEM;
dev->needed_tailroom = 2; /* room for FCS */
dev->mtu = IEEE802154_MTU;
dev->tx_queue_len = 10;
dev->type = ARPHRD_IEEE802154_MONITOR;
dev->flags = IFF_NOARP | IFF_BROADCAST;
ASSERT_RTNL();
ndev = alloc_netdev(sizeof(*sdata) + local->hw.vif_data_size, name,
NET_NAME_UNKNOWN, ieee802154_if_setup);
if (!ndev)
return ERR_PTR(-ENOMEM);
ndev->needed_headroom = local->hw.extra_tx_headroom;
ret = dev_alloc_name(ndev, ndev->name);
if (ret < 0)
goto err;
switch (type) {
case IEEE802154_DEV_WPAN:
ndev->type = ARPHRD_IEEE802154;
break;
case IEEE802154_DEV_MONITOR:
ndev->type = ARPHRD_IEEE802154_MONITOR;
break;
default:
ret = -EINVAL;
goto err;
}
ieee802154_le64_to_be64(ndev->perm_addr,
&local->hw.phy->perm_extended_addr);
memcpy(ndev->dev_addr, ndev->perm_addr, IEEE802154_EXTENDED_ADDR_LEN);
/* TODO check this */
SET_NETDEV_DEV(ndev, &local->phy->dev);
sdata = netdev_priv(ndev);
ndev->ieee802154_ptr = &sdata->wpan_dev;
memcpy(sdata->name, ndev->name, IFNAMSIZ);
sdata->dev = ndev;
sdata->wpan_dev.wpan_phy = local->hw.phy;
sdata->local = local;
/* setup type-dependent data */
ret = ieee802154_setup_sdata(sdata, type);
if (ret)
goto err;
if (ndev) {
ret = register_netdevice(ndev);
if (ret < 0)
goto err;
}
mutex_lock(&local->iflist_mtx);
list_add_tail_rcu(&sdata->list, &local->interfaces);
mutex_unlock(&local->iflist_mtx);
dev->destructor = free_netdev;
dev->netdev_ops = &mac802154_monitor_ops;
dev->ml_priv = &mac802154_mlme_reduced;
if (new_wpan_dev)
*new_wpan_dev = &sdata->wpan_dev;
sdata = IEEE802154_DEV_TO_SUB_IF(dev);
sdata->type = IEEE802154_DEV_MONITOR;
return ndev;
err:
free_netdev(ndev);
return ERR_PTR(ret);
}
void ieee802154_if_remove(struct ieee802154_sub_if_data *sdata)
{
ASSERT_RTNL();
mutex_lock(&sdata->local->iflist_mtx);
list_del_rcu(&sdata->list);
mutex_unlock(&sdata->local->iflist_mtx);
sdata->promisuous_mode = true;
synchronize_rcu();
unregister_netdevice(sdata->dev);
}
......@@ -25,9 +25,9 @@
#include <net/ieee802154_netdev.h>
#include <net/cfg802154.h>
#include <net/mac802154.h>
#include <net/nl802154.h>
#include "ieee802154_i.h"
#include "driver-ops.h"
static int mac802154_mlme_start_req(struct net_device *dev,
struct ieee802154_addr *addr,
......@@ -43,7 +43,6 @@ static int mac802154_mlme_start_req(struct net_device *dev,
mac802154_dev_set_pan_id(dev, addr->pan_id);
mac802154_dev_set_short_addr(dev, addr->short_addr);
mac802154_dev_set_ieee_addr(dev);
mac802154_dev_set_page_channel(dev, page, channel);
if (ops->llsec) {
......@@ -65,32 +64,38 @@ static int mac802154_mlme_start_req(struct net_device *dev,
rc = ops->llsec->set_params(dev, &params, changed);
}
/* FIXME: add validation for unused parameters to be sane
* for SoftMAC
*/
ieee802154_nl_start_confirm(dev, IEEE802154_SUCCESS);
return rc;
}
static struct wpan_phy *mac802154_get_phy(const struct net_device *dev)
{
struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
BUG_ON(dev->type != ARPHRD_IEEE802154);
return to_phy(get_device(&sdata->local->phy->dev));
}
static int mac802154_set_mac_params(struct net_device *dev,
const struct ieee802154_mac_params *params)
{
struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
struct ieee802154_local *local = sdata->local;
int ret;
mutex_lock(&sdata->local->iflist_mtx);
sdata->mac_params = *params;
mutex_unlock(&sdata->local->iflist_mtx);
if (local->hw.flags & IEEE802154_HW_TXPOWER) {
ret = drv_set_tx_power(local, params->transmit_power);
if (ret < 0)
return ret;
}
if (local->hw.flags & IEEE802154_HW_CCA_MODE) {
ret = drv_set_cca_mode(local, params->cca_mode);
if (ret < 0)
return ret;
}
if (local->hw.flags & IEEE802154_HW_CCA_ED_LEVEL) {
ret = drv_set_cca_ed_level(local, params->cca_ed_level);
if (ret < 0)
return ret;
}
return 0;
}
......@@ -120,12 +125,7 @@ static struct ieee802154_llsec_ops mac802154_llsec_ops = {
.unlock_table = mac802154_unlock_table,
};
struct ieee802154_reduced_mlme_ops mac802154_mlme_reduced = {
.get_phy = mac802154_get_phy,
};
struct ieee802154_mlme_ops mac802154_mlme_wpan = {
.get_phy = mac802154_get_phy,
.start_req = mac802154_mlme_start_req,
.get_pan_id = mac802154_dev_get_pan_id,
.get_short_addr = mac802154_dev_get_short_addr,
......
......@@ -28,90 +28,7 @@
#include <net/cfg802154.h>
#include "ieee802154_i.h"
static int
mac802154_netdev_register(struct wpan_phy *phy, struct net_device *dev)
{
struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
struct ieee802154_local *local;
int err;
local = wpan_phy_priv(phy);
sdata->dev = dev;
sdata->local = local;
dev->needed_headroom = local->hw.extra_tx_headroom;
SET_NETDEV_DEV(dev, &local->phy->dev);
err = register_netdev(dev);
if (err < 0)
return err;
rtnl_lock();
mutex_lock(&local->iflist_mtx);
list_add_tail_rcu(&sdata->list, &local->interfaces);
mutex_unlock(&local->iflist_mtx);
rtnl_unlock();
return 0;
}
static void
mac802154_del_iface(struct wpan_phy *phy, struct net_device *dev)
{
struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
ASSERT_RTNL();
BUG_ON(sdata->local->phy != phy);
mutex_lock(&sdata->local->iflist_mtx);
list_del_rcu(&sdata->list);
mutex_unlock(&sdata->local->iflist_mtx);
synchronize_rcu();
unregister_netdevice(sdata->dev);
}
static struct net_device *
mac802154_add_iface(struct wpan_phy *phy, const char *name, int type)
{
struct net_device *dev;
int err = -ENOMEM;
switch (type) {
case IEEE802154_DEV_MONITOR:
dev = alloc_netdev(sizeof(struct ieee802154_sub_if_data),
name, NET_NAME_UNKNOWN,
mac802154_monitor_setup);
break;
case IEEE802154_DEV_WPAN:
dev = alloc_netdev(sizeof(struct ieee802154_sub_if_data),
name, NET_NAME_UNKNOWN,
mac802154_wpan_setup);
break;
default:
dev = NULL;
err = -EINVAL;
break;
}
if (!dev)
goto err;
err = mac802154_netdev_register(phy, dev);
if (err)
goto err_free;
dev_hold(dev); /* we return an incremented device refcount */
return dev;
err_free:
free_netdev(dev);
err:
return ERR_PTR(err);
}
#include "cfg.h"
static void ieee802154_tasklet_handler(unsigned long data)
{
......@@ -169,7 +86,7 @@ ieee802154_alloc_hw(size_t priv_data_len, const struct ieee802154_ops *ops)
priv_size = ALIGN(sizeof(*local), NETDEV_ALIGN) + priv_data_len;
phy = wpan_phy_alloc(priv_size);
phy = wpan_phy_alloc(&mac802154_config_ops, priv_size);
if (!phy) {
pr_err("failure to allocate master IEEE802.15.4 device\n");
return NULL;
......@@ -209,6 +126,7 @@ EXPORT_SYMBOL(ieee802154_free_hw);
int ieee802154_register_hw(struct ieee802154_hw *hw)
{
struct ieee802154_local *local = hw_to_local(hw);
struct net_device *dev;
int rc = -ENOSYS;
local->workqueue =
......@@ -220,13 +138,21 @@ int ieee802154_register_hw(struct ieee802154_hw *hw)
wpan_phy_set_dev(local->phy, local->hw.parent);
local->phy->add_iface = mac802154_add_iface;
local->phy->del_iface = mac802154_del_iface;
rc = wpan_phy_register(local->phy);
if (rc < 0)
goto out_wq;
rtnl_lock();
dev = ieee802154_if_add(local, "wpan%d", NULL, IEEE802154_DEV_WPAN);
if (IS_ERR(dev)) {
rtnl_unlock();
rc = PTR_ERR(dev);
goto out_wq;
}
rtnl_unlock();
return 0;
out_wq:
......
......@@ -26,51 +26,6 @@
#include "ieee802154_i.h"
#include "driver-ops.h"
struct hw_addr_filt_notify_work {
struct work_struct work;
struct net_device *dev;
unsigned long changed;
};
static struct ieee802154_local *mac802154_slave_get_priv(struct net_device *dev)
{
struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
BUG_ON(dev->type != ARPHRD_IEEE802154);
return sdata->local;
}
static void hw_addr_notify(struct work_struct *work)
{
struct hw_addr_filt_notify_work *nw = container_of(work,
struct hw_addr_filt_notify_work, work);
struct ieee802154_local *local = mac802154_slave_get_priv(nw->dev);
int res;
res = local->ops->set_hw_addr_filt(&local->hw, &local->hw.hw_filt,
nw->changed);
if (res)
pr_debug("failed changed mask %lx\n", nw->changed);
kfree(nw);
}
static void set_hw_addr_filt(struct net_device *dev, unsigned long changed)
{
struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
struct hw_addr_filt_notify_work *work;
work = kzalloc(sizeof(*work), GFP_ATOMIC);
if (!work)
return;
INIT_WORK(&work->work, hw_addr_notify);
work->dev = dev;
work->changed = changed;
queue_work(sdata->local->workqueue, &work->work);
}
void mac802154_dev_set_short_addr(struct net_device *dev, __le16 val)
{
struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
......@@ -80,12 +35,6 @@ void mac802154_dev_set_short_addr(struct net_device *dev, __le16 val)
spin_lock_bh(&sdata->mib_lock);
sdata->short_addr = val;
spin_unlock_bh(&sdata->mib_lock);
if ((sdata->local->ops->set_hw_addr_filt) &&
(sdata->local->hw.hw_filt.short_addr != sdata->short_addr)) {
sdata->local->hw.hw_filt.short_addr = sdata->short_addr;
set_hw_addr_filt(dev, IEEE802154_AFILT_SADDR_CHANGED);
}
}
__le16 mac802154_dev_get_short_addr(const struct net_device *dev)
......@@ -102,20 +51,6 @@ __le16 mac802154_dev_get_short_addr(const struct net_device *dev)
return ret;
}
void mac802154_dev_set_ieee_addr(struct net_device *dev)
{
struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
struct ieee802154_local *local = sdata->local;
sdata->extended_addr = ieee802154_devaddr_from_raw(dev->dev_addr);
if (local->ops->set_hw_addr_filt &&
local->hw.hw_filt.ieee_addr != sdata->extended_addr) {
local->hw.hw_filt.ieee_addr = sdata->extended_addr;
set_hw_addr_filt(dev, IEEE802154_AFILT_IEEEADDR_CHANGED);
}
}
__le16 mac802154_dev_get_pan_id(const struct net_device *dev)
{
struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
......@@ -139,12 +74,6 @@ void mac802154_dev_set_pan_id(struct net_device *dev, __le16 val)
spin_lock_bh(&sdata->mib_lock);
sdata->pan_id = val;
spin_unlock_bh(&sdata->mib_lock);
if ((sdata->local->ops->set_hw_addr_filt) &&
(sdata->local->hw.hw_filt.pan_id != sdata->pan_id)) {
sdata->local->hw.hw_filt.pan_id = sdata->pan_id;
set_hw_addr_filt(dev, IEEE802154_AFILT_PANID_CHANGED);
}
}
u8 mac802154_dev_get_dsn(const struct net_device *dev)
......
......@@ -208,7 +208,7 @@ __ieee802154_rx_handle_packet(struct ieee802154_local *local,
}
list_for_each_entry_rcu(sdata, &local->interfaces, list) {
if (sdata->type != IEEE802154_DEV_WPAN ||
if (sdata->vif.type != IEEE802154_DEV_WPAN ||
!netif_running(sdata->dev))
continue;
......@@ -233,7 +233,7 @@ ieee802154_monitors_rx(struct ieee802154_local *local, struct sk_buff *skb)
skb->protocol = htons(ETH_P_IEEE802154);
list_for_each_entry_rcu(sdata, &local->interfaces, list) {
if (sdata->type != IEEE802154_DEV_MONITOR)
if (sdata->vif.type != IEEE802154_DEV_MONITOR)
continue;
if (!ieee802154_sdata_running(sdata))
......
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