From 133be0264f28e59d772c6a259349ba3ee2b183b3 Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Thu, 4 Jun 2015 13:07:36 +0530 Subject: nl802154: export supported commands This patch will export the supported commands by the devices to the userspace. This will be useful to check if HardMAC drivers can support a specific command or not. Signed-off-by: Varka Bhadram Acked-by: Alexander Aring Signed-off-by: Marcel Holtmann --- include/net/nl802154.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'include/net') diff --git a/include/net/nl802154.h b/include/net/nl802154.h index 0badebd1de7f..6fc231e60920 100644 --- a/include/net/nl802154.h +++ b/include/net/nl802154.h @@ -102,6 +102,8 @@ enum nl802154_attrs { NL802154_ATTR_WPAN_PHY_CAPS, + NL802154_ATTR_SUPPORTED_COMMANDS, + /* add attributes here, update the policy in nl802154.c */ __NL802154_ATTR_AFTER_LAST, -- cgit v1.2.3-71-gd317 From ed65963ba0a2bdc330b1d7183f930d1c6a0a6685 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Sat, 6 Jun 2015 17:30:46 +0200 Subject: mac802154: remove unneeded vif struct This patch removes the virtual interface structure from sub if data struct, because it isn't used anywhere. This structure could be useful for give per interface information at softmac driver layer. Nevertheless there exist no use case currently and it contains the interface type information currently. This information is also stored inside wpan dev which is now used to check on the wpan dev interface type. Signed-off-by: Alexander Aring Reviewed-by: Varka Bhadram Acked-by: Varka Bhadram Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/at86rf230.c | 1 - drivers/net/ieee802154/cc2520.c | 1 - include/net/mac802154.h | 8 -------- net/mac802154/ieee802154_i.h | 2 -- net/mac802154/iface.c | 9 ++++----- net/mac802154/rx.c | 4 ++-- 6 files changed, 6 insertions(+), 19 deletions(-) (limited to 'include/net') diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index 2f25a5ed8247..6e20e9c94b3c 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -1602,7 +1602,6 @@ static int at86rf230_probe(struct spi_device *spi) lp->spi = spi; lp->slp_tr = slp_tr; 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); diff --git a/drivers/net/ieee802154/cc2520.c b/drivers/net/ieee802154/cc2520.c index 8141353221a1..a8bafd6bd5e4 100644 --- a/drivers/net/ieee802154/cc2520.c +++ b/drivers/net/ieee802154/cc2520.c @@ -742,7 +742,6 @@ 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); ieee802154_random_extended_addr(&priv->hw->phy->perm_extended_addr); /* We do support only 2.4 Ghz */ diff --git a/include/net/mac802154.h b/include/net/mac802154.h index 9605c7f7453f..80a9e60ceb0c 100644 --- a/include/net/mac802154.h +++ b/include/net/mac802154.h @@ -56,13 +56,6 @@ 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; @@ -73,7 +66,6 @@ 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 diff --git a/net/mac802154/ieee802154_i.h b/net/mac802154/ieee802154_i.h index eec668f3637f..34755d5751a4 100644 --- a/net/mac802154/ieee802154_i.h +++ b/net/mac802154/ieee802154_i.h @@ -92,8 +92,6 @@ 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 */ diff --git a/net/mac802154/iface.c b/net/mac802154/iface.c index 6ac023932ce0..3a67d35d4672 100644 --- a/net/mac802154/iface.c +++ b/net/mac802154/iface.c @@ -219,8 +219,8 @@ ieee802154_check_concurrent_iface(struct ieee802154_sub_if_data *sdata, * exist really an use case if we need to support * multiple node types at the same time. */ - if (sdata->vif.type == NL802154_IFTYPE_NODE && - nsdata->vif.type == NL802154_IFTYPE_NODE) + if (wpan_dev->iftype == NL802154_IFTYPE_NODE && + nsdata->wpan_dev.iftype == NL802154_IFTYPE_NODE) return -EBUSY; /* check all phy mac sublayer settings are the same. @@ -243,7 +243,7 @@ static int mac802154_wpan_open(struct net_device *dev) struct ieee802154_local *local = sdata->local; struct wpan_dev *wpan_dev = &sdata->wpan_dev; - rc = ieee802154_check_concurrent_iface(sdata, sdata->vif.type); + rc = ieee802154_check_concurrent_iface(sdata, wpan_dev->iftype); if (rc < 0) return rc; @@ -467,7 +467,6 @@ ieee802154_setup_sdata(struct ieee802154_sub_if_data *sdata, u8 tmp; /* set some type-dependent values */ - sdata->vif.type = type; sdata->wpan_dev.iftype = type; get_random_bytes(&tmp, sizeof(tmp)); @@ -523,7 +522,7 @@ ieee802154_if_add(struct ieee802154_local *local, const char *name, ASSERT_RTNL(); - ndev = alloc_netdev(sizeof(*sdata) + local->hw.vif_data_size, name, + ndev = alloc_netdev(sizeof(*sdata), name, name_assign_type, ieee802154_if_setup); if (!ndev) return ERR_PTR(-ENOMEM); diff --git a/net/mac802154/rx.c b/net/mac802154/rx.c index e0f10063cac3..1bdf98068608 100644 --- a/net/mac802154/rx.c +++ b/net/mac802154/rx.c @@ -202,7 +202,7 @@ __ieee802154_rx_handle_packet(struct ieee802154_local *local, } list_for_each_entry_rcu(sdata, &local->interfaces, list) { - if (sdata->vif.type != NL802154_IFTYPE_NODE || + if (sdata->wpan_dev.iftype != NL802154_IFTYPE_NODE || !netif_running(sdata->dev)) continue; @@ -227,7 +227,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->vif.type != NL802154_IFTYPE_MONITOR) + if (sdata->wpan_dev.iftype != NL802154_IFTYPE_MONITOR) continue; if (!ieee802154_sdata_running(sdata)) -- cgit v1.2.3-71-gd317 From 6b70a43c7e0202cf285c864bc9f20f607c42e432 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Sat, 6 Jun 2015 17:30:47 +0200 Subject: mac802154: cleanup address filtering flags This patch changes the address filtering flags to enums and setting the flag values with the BIT macro. Additional this patch changes the commenting style for matching usual kernel style. Signed-off-by: Alexander Aring Reviewed-by: Varka Bhadram Signed-off-by: Marcel Holtmann --- include/net/mac802154.h | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) (limited to 'include/net') diff --git a/include/net/mac802154.h b/include/net/mac802154.h index 80a9e60ceb0c..845e4f88a33e 100644 --- a/include/net/mac802154.h +++ b/include/net/mac802154.h @@ -31,18 +31,29 @@ */ #define MAC802154_FRAME_HARD_HEADER_LEN (2 + 1 + 20 + 14) -/* The following flags are used to indicate changed address settings from +/** + * enum ieee802154_hw_addr_filt_flags - hardware address filtering flags + * + * The following flags are used to indicate changed address settings from * the stack to the hardware. + * + * @IEEE802154_AFILT_SADDR_CHANGED: Indicates that the short address will be + * change. + * + * @IEEE802154_AFILT_IEEEADDR_CHANGED: Indicates that the extended address + * will be change. + * + * @IEEE802154_AFILT_PANID_CHANGED: Indicates that the pan id will be change. + * + * @IEEE802154_AFILT_PANC_CHANGED: Indicates that the address filter will + * do frame address filtering as a pan coordinator. */ - -/* indicates that the Short Address changed */ -#define IEEE802154_AFILT_SADDR_CHANGED 0x00000001 -/* indicates that the IEEE Address changed */ -#define IEEE802154_AFILT_IEEEADDR_CHANGED 0x00000002 -/* indicates that the PAN ID changed */ -#define IEEE802154_AFILT_PANID_CHANGED 0x00000004 -/* indicates that PAN Coordinator status changed */ -#define IEEE802154_AFILT_PANC_CHANGED 0x00000008 +enum ieee802154_hw_addr_filt_flags { + IEEE802154_AFILT_SADDR_CHANGED = BIT(1), + IEEE802154_AFILT_IEEEADDR_CHANGED = BIT(2), + IEEE802154_AFILT_PANID_CHANGED = BIT(3), + IEEE802154_AFILT_PANC_CHANGED = BIT(4), +}; struct ieee802154_hw_addr_filt { __le16 pan_id; /* Each independent PAN selects a unique -- cgit v1.2.3-71-gd317 From f265be3d124a5b62e5a339685b6cfaa0292f1250 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Sat, 6 Jun 2015 17:30:48 +0200 Subject: mac802154: remove aack hw flag This patch removes the hardware auto acknowdledge flag which indicates that the transceiver supports this handling. This flag is never evaluated inside mac802154 and all transceivers should support this handling by default per hardware. Suggested-by: Lennert Buytenhek Cc: Alan Ott Signed-off-by: Alexander Aring Reviewed-by: Varka Bhadram Acked-by: Stefan Schmidt Acked-by: Varka Bhadram Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/at86rf230.c | 2 +- drivers/net/ieee802154/atusb.c | 2 +- drivers/net/ieee802154/cc2520.c | 3 +-- drivers/net/ieee802154/mrf24j40.c | 3 +-- include/net/mac802154.h | 2 -- 5 files changed, 4 insertions(+), 8 deletions(-) (limited to 'include/net') diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index 6e20e9c94b3c..1bf86d2df23f 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -1443,7 +1443,7 @@ at86rf230_detect_device(struct at86rf230_local *lp) return -EINVAL; } - lp->hw->flags = IEEE802154_HW_TX_OMIT_CKSUM | IEEE802154_HW_AACK | + lp->hw->flags = IEEE802154_HW_TX_OMIT_CKSUM | IEEE802154_HW_CSMA_PARAMS | IEEE802154_HW_FRAME_RETRIES | IEEE802154_HW_AFILT | IEEE802154_HW_PROMISCUOUS; diff --git a/drivers/net/ieee802154/atusb.c b/drivers/net/ieee802154/atusb.c index 3d25678dfd95..80dfc725b8dc 100644 --- a/drivers/net/ieee802154/atusb.c +++ b/drivers/net/ieee802154/atusb.c @@ -628,7 +628,7 @@ static int atusb_probe(struct usb_interface *interface, hw->parent = &usb_dev->dev; hw->flags = IEEE802154_HW_TX_OMIT_CKSUM | IEEE802154_HW_AFILT | - IEEE802154_HW_AACK | IEEE802154_HW_PROMISCUOUS; + IEEE802154_HW_PROMISCUOUS; hw->phy->flags = WPAN_PHY_FLAG_TXPOWER; diff --git a/drivers/net/ieee802154/cc2520.c b/drivers/net/ieee802154/cc2520.c index a8bafd6bd5e4..15f263cfece5 100644 --- a/drivers/net/ieee802154/cc2520.c +++ b/drivers/net/ieee802154/cc2520.c @@ -746,8 +746,7 @@ static int cc2520_register(struct cc2520_private *priv) /* We do support only 2.4 Ghz */ priv->hw->phy->supported.channels[0] = 0x7FFF800; - priv->hw->flags = IEEE802154_HW_OMIT_CKSUM | IEEE802154_HW_AACK | - IEEE802154_HW_AFILT; + priv->hw->flags = IEEE802154_HW_OMIT_CKSUM | IEEE802154_HW_AFILT; priv->hw->phy->flags = WPAN_PHY_FLAG_TXPOWER; diff --git a/drivers/net/ieee802154/mrf24j40.c b/drivers/net/ieee802154/mrf24j40.c index f2a1bd122a74..99c767695c7b 100644 --- a/drivers/net/ieee802154/mrf24j40.c +++ b/drivers/net/ieee802154/mrf24j40.c @@ -751,8 +751,7 @@ static int mrf24j40_probe(struct spi_device *spi) devrec->hw->priv = devrec; devrec->hw->parent = &devrec->spi->dev; devrec->hw->phy->supported.channels[0] = CHANNEL_MASK; - devrec->hw->flags = IEEE802154_HW_OMIT_CKSUM | IEEE802154_HW_AACK | - IEEE802154_HW_AFILT; + devrec->hw->flags = IEEE802154_HW_OMIT_CKSUM | IEEE802154_HW_AFILT; dev_dbg(printdev(devrec), "registered mrf24j40\n"); ret = ieee802154_register_hw(devrec->hw); diff --git a/include/net/mac802154.h b/include/net/mac802154.h index 845e4f88a33e..a20ba28ad9c5 100644 --- a/include/net/mac802154.h +++ b/include/net/mac802154.h @@ -90,8 +90,6 @@ struct ieee802154_hw { /* Indicates that xmitter will add FCS on it's own. */ #define IEEE802154_HW_TX_OMIT_CKSUM 0x00000001 -/* Indicates that receiver will autorespond with ACK frames. */ -#define IEEE802154_HW_AACK 0x00000002 /* Indicates that transceiver will support listen before transmit. */ #define IEEE802154_HW_LBT 0x00000004 /* Indicates that transceiver will support csma (max_be, min_be, csma retries) -- cgit v1.2.3-71-gd317 From bcbfd2078d9b11277d9c9ce0c30ba73c750503c9 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Sat, 6 Jun 2015 17:30:49 +0200 Subject: mac802154: cleanup ieee802154 hardware flags This patch changes the ieee802154 hardware flags to enums and setting the flag values with the BIT macro. Additional this patch changes the commenting style for matching usual kernel style. Signed-off-by: Alexander Aring Reviewed-by: Varka Bhadram Signed-off-by: Marcel Holtmann --- include/net/mac802154.h | 56 +++++++++++++++++++++++++++++++------------------ 1 file changed, 36 insertions(+), 20 deletions(-) (limited to 'include/net') diff --git a/include/net/mac802154.h b/include/net/mac802154.h index a20ba28ad9c5..c21a700293b8 100644 --- a/include/net/mac802154.h +++ b/include/net/mac802154.h @@ -79,32 +79,48 @@ struct ieee802154_hw { struct wpan_phy *phy; }; -/* Checksum is in hardware and is omitted from a packet +/** + * enum ieee802154_hw_flags - hardware flags * - * These following flags are used to indicate hardware capabilities to + * These flags are used to indicate hardware capabilities to * the stack. Generally, flags here should have their meaning * done in a way that the simplest hardware doesn't need setting * any particular flags. There are some exceptions to this rule, * however, so you are advised to review these flags carefully. + * + * @IEEE802154_HW_TX_OMIT_CKSUM: Indicates that xmitter will add FCS on it's + * own. + * + * @IEEE802154_HW_LBT: Indicates that transceiver will support listen before + * transmit. + * + * @IEEE802154_HW_CSMA_PARAMS: Indicates that transceiver will support csma + * parameters (max_be, min_be, backoff exponents). + * + * @IEEE802154_HW_FRAME_RETRIES: Indicates that transceiver will support ARET + * frame retries setting. + * + * @IEEE802154_HW_AFILT: Indicates that transceiver will support hardware + * address filter setting. + * + * @IEEE802154_HW_PROMISCUOUS: Indicates that transceiver will support + * promiscuous mode setting. + * + * @IEEE802154_HW_RX_OMIT_CKSUM: Indicates that receiver omits FCS. + * + * @IEEE802154_HW_RX_DROP_BAD_CKSUM: Indicates that receiver will not filter + * frames with bad checksum. */ - -/* Indicates that xmitter will add FCS on it's own. */ -#define IEEE802154_HW_TX_OMIT_CKSUM 0x00000001 -/* Indicates that transceiver will support listen before transmit. */ -#define IEEE802154_HW_LBT 0x00000004 -/* Indicates that transceiver will support csma (max_be, min_be, csma retries) - * settings. */ -#define IEEE802154_HW_CSMA_PARAMS 0x00000008 -/* Indicates that transceiver will support ARET frame retries setting. */ -#define IEEE802154_HW_FRAME_RETRIES 0x00000010 -/* Indicates that transceiver will support hardware address filter setting. */ -#define IEEE802154_HW_AFILT 0x00000020 -/* Indicates that transceiver will support promiscuous mode setting. */ -#define IEEE802154_HW_PROMISCUOUS 0x00000040 -/* Indicates that receiver omits FCS. */ -#define IEEE802154_HW_RX_OMIT_CKSUM 0x00000080 -/* Indicates that receiver will not filter frames with bad checksum. */ -#define IEEE802154_HW_RX_DROP_BAD_CKSUM 0x00000100 +enum ieee802154_hw_flags { + IEEE802154_HW_TX_OMIT_CKSUM = BIT(1), + IEEE802154_HW_LBT = BIT(2), + IEEE802154_HW_CSMA_PARAMS = BIT(3), + IEEE802154_HW_FRAME_RETRIES = BIT(4), + IEEE802154_HW_AFILT = BIT(5), + IEEE802154_HW_PROMISCUOUS = BIT(6), + IEEE802154_HW_RX_OMIT_CKSUM = BIT(7), + IEEE802154_HW_RX_DROP_BAD_CKSUM = BIT(8), +}; /* Indicates that receiver omits FCS and xmitter will add FCS on it's own. */ #define IEEE802154_HW_OMIT_CKSUM (IEEE802154_HW_TX_OMIT_CKSUM | \ -- cgit v1.2.3-71-gd317 From 5661d431c6e65588e813c947117e6d18eb03422f Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Sat, 6 Jun 2015 17:30:50 +0200 Subject: mac802154: remove unused hw_filt attribute This patch removed an attribute from ieee802154_hw structure which is never used inside kernel. Address information are stored inside wpan_dev nowadays. Signed-off-by: Alexander Aring Reviewed-by: Varka Bhadram Signed-off-by: Marcel Holtmann --- include/net/mac802154.h | 1 - 1 file changed, 1 deletion(-) (limited to 'include/net') diff --git a/include/net/mac802154.h b/include/net/mac802154.h index c21a700293b8..61d4b80bf766 100644 --- a/include/net/mac802154.h +++ b/include/net/mac802154.h @@ -74,7 +74,6 @@ struct ieee802154_hw { struct device *parent; /* filled by mac802154 core */ - struct ieee802154_hw_addr_filt hw_filt; void *priv; struct wpan_phy *phy; }; -- cgit v1.2.3-71-gd317 From af69a34548cb01aefef76aeb3565cebc7a9fb0d6 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Sat, 6 Jun 2015 17:30:51 +0200 Subject: mac802154: rearrange attribute in ieee802154_hw This patch removes the priv attribute in ieee802154_hw to the right section which is commented by attributes which needs to be filled by driver layer. Signed-off-by: Alexander Aring Reviewed-by: Varka Bhadram Signed-off-by: Marcel Holtmann --- include/net/mac802154.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/net') diff --git a/include/net/mac802154.h b/include/net/mac802154.h index 61d4b80bf766..d8e9e6f0e096 100644 --- a/include/net/mac802154.h +++ b/include/net/mac802154.h @@ -72,9 +72,9 @@ struct ieee802154_hw { int extra_tx_headroom; u32 flags; struct device *parent; + void *priv; /* filled by mac802154 core */ - void *priv; struct wpan_phy *phy; }; -- cgit v1.2.3-71-gd317 From a0825b03aed91dd25d31aaff1e6e85c322caf8b2 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Sat, 6 Jun 2015 17:30:52 +0200 Subject: mac802154: add missing structure comments This patch add missing comments to internal mac802154 structures. Signed-off-by: Alexander Aring Reviewed-by: Varka Bhadram Signed-off-by: Marcel Holtmann --- include/net/mac802154.h | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) (limited to 'include/net') diff --git a/include/net/mac802154.h b/include/net/mac802154.h index d8e9e6f0e096..095c9d069968 100644 --- a/include/net/mac802154.h +++ b/include/net/mac802154.h @@ -55,18 +55,40 @@ enum ieee802154_hw_addr_filt_flags { IEEE802154_AFILT_PANC_CHANGED = BIT(4), }; +/** + * struct ieee802154_hw_addr_filt - hardware address filtering settings + * + * @pan_id: pan_id which should be set to the hardware address filter. + * + * @short_addr: short_addr which should be set to the hardware address filter. + * + * @ieee_addr: extended address which should be set to the hardware address + * filter. + * + * @pan_coord: boolean if hardware filtering should be operate as coordinator. + */ struct ieee802154_hw_addr_filt { - __le16 pan_id; /* Each independent PAN selects a unique - * identifier. This PAN id allows communication - * between devices within a network using short - * addresses and enables transmissions between - * devices across independent networks. - */ + __le16 pan_id; __le16 short_addr; __le64 ieee_addr; u8 pan_coord; }; +/** + * struct ieee802154_hw - ieee802154 hardware + * + * @extra_tx_headroom: headroom to reserve in each transmit skb for use by the + * driver (e.g. for transmit headers.) + * + * @flags: hardware flags, see &enum ieee802154_hw_flags + * + * @parent: parent device of the hardware. + * + * @priv: pointer to private area that was allocated for driver use along with + * this structure. + * + * @phy: This points to the &struct wpan_phy allocated for this 802.15.4 PHY. + */ struct ieee802154_hw { /* filled by the driver */ int extra_tx_headroom; -- cgit v1.2.3-71-gd317 From 623c1234a2da2235d6f0bcd09061b6f7776eee93 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Sat, 6 Jun 2015 17:30:53 +0200 Subject: mac802154: change pan_coord type to bool To indicate if it's a coordinator or not a bool is enough. There should no more values available which represent some other state. Signed-off-by: Alexander Aring Reviewed-by: Varka Bhadram Signed-off-by: Marcel Holtmann --- include/net/mac802154.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/net') diff --git a/include/net/mac802154.h b/include/net/mac802154.h index 095c9d069968..de1cdde92edc 100644 --- a/include/net/mac802154.h +++ b/include/net/mac802154.h @@ -71,7 +71,7 @@ struct ieee802154_hw_addr_filt { __le16 pan_id; __le16 short_addr; __le64 ieee_addr; - u8 pan_coord; + bool pan_coord; }; /** -- cgit v1.2.3-71-gd317 From 8b76ce34c43a569f981623485c1b6c700594678e Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 8 Jun 2015 18:14:39 +0300 Subject: Bluetooth: Fix encryption key size handling for LTKs The encryption key size for LTKs is supposed to be applied only at the moment of encryption. When generating a Link Key (using LE SC) from the LTK the full non-shortened value should be used. This patch modifies the code to always keep the full value around and only apply the key size when passing the value to HCI. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 2 +- net/bluetooth/hci_conn.c | 4 ++-- net/bluetooth/hci_event.c | 3 ++- net/bluetooth/smp.c | 15 +++------------ 4 files changed, 8 insertions(+), 16 deletions(-) (limited to 'include/net') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index a056c2bfeb81..24c0e4577a93 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1408,7 +1408,7 @@ void mgmt_smp_complete(struct hci_conn *conn, bool complete); u8 hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max, u16 latency, u16 to_multiplier); void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __le64 rand, - __u8 ltk[16]); + __u8 ltk[16], __u8 key_size); void hci_copy_identity_address(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *bdaddr_type); diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index ee5e59839b02..2c48bf0b5afb 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -276,7 +276,7 @@ u8 hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max, u16 latency, } void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __le64 rand, - __u8 ltk[16]) + __u8 ltk[16], __u8 key_size) { struct hci_dev *hdev = conn->hdev; struct hci_cp_le_start_enc cp; @@ -288,7 +288,7 @@ void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __le64 rand, cp.handle = cpu_to_le16(conn->handle); cp.rand = rand; cp.ediv = ediv; - memcpy(cp.ltk, ltk, sizeof(cp.ltk)); + memcpy(cp.ltk, ltk, key_size); hci_send_cmd(hdev, HCI_OP_LE_START_ENC, sizeof(cp), &cp); } diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 7b61be73650f..fcbfa4138eb1 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -4955,7 +4955,8 @@ static void hci_le_ltk_request_evt(struct hci_dev *hdev, struct sk_buff *skb) goto not_found; } - memcpy(cp.ltk, ltk->val, sizeof(ltk->val)); + memcpy(cp.ltk, ltk->val, ltk->enc_size); + memset(cp.ltk + ltk->enc_size, 0, sizeof(cp.ltk) - ltk->enc_size); cp.handle = cpu_to_le16(conn->handle); conn->pending_sec_level = smp_ltk_sec_level(ltk); diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 659371af39e4..3921cba056d3 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -997,13 +997,10 @@ static u8 smp_random(struct smp_chan *smp) smp_s1(smp->tfm_aes, smp->tk, smp->rrnd, smp->prnd, stk); - memset(stk + smp->enc_key_size, 0, - SMP_MAX_ENC_KEY_SIZE - smp->enc_key_size); - if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->flags)) return SMP_UNSPECIFIED; - hci_le_start_enc(hcon, ediv, rand, stk); + hci_le_start_enc(hcon, ediv, rand, stk, smp->enc_key_size); hcon->enc_key_size = smp->enc_key_size; set_bit(HCI_CONN_STK_ENCRYPT, &hcon->flags); } else { @@ -1016,9 +1013,6 @@ static u8 smp_random(struct smp_chan *smp) smp_s1(smp->tfm_aes, smp->tk, smp->prnd, smp->rrnd, stk); - memset(stk + smp->enc_key_size, 0, - SMP_MAX_ENC_KEY_SIZE - smp->enc_key_size); - if (hcon->pending_sec_level == BT_SECURITY_HIGH) auth = 1; else @@ -1156,9 +1150,6 @@ static void sc_add_ltk(struct smp_chan *smp) else auth = 0; - memset(smp->tk + smp->enc_key_size, 0, - SMP_MAX_ENC_KEY_SIZE - smp->enc_key_size); - smp->ltk = hci_add_ltk(hcon->hdev, &hcon->dst, hcon->dst_type, key_type, auth, smp->tk, smp->enc_key_size, 0, 0); @@ -2202,7 +2193,7 @@ static bool smp_ltk_encrypt(struct l2cap_conn *conn, u8 sec_level) if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->flags)) return true; - hci_le_start_enc(hcon, key->ediv, key->rand, key->val); + hci_le_start_enc(hcon, key->ediv, key->rand, key->val, key->enc_size); hcon->enc_key_size = key->enc_size; /* We never store STKs for master role, so clear this flag */ @@ -2750,7 +2741,7 @@ static int smp_cmd_dhkey_check(struct l2cap_conn *conn, struct sk_buff *skb) sc_add_ltk(smp); if (hcon->out) { - hci_le_start_enc(hcon, 0, 0, smp->tk); + hci_le_start_enc(hcon, 0, 0, smp->tk, smp->enc_key_size); hcon->enc_key_size = smp->enc_key_size; } -- cgit v1.2.3-71-gd317 From 9b4c33364eb653a824c58e637c73caa6feb9879c Mon Sep 17 00:00:00 2001 From: Arron Wang Date: Tue, 9 Jun 2015 17:47:22 +0800 Subject: Bluetooth: Make l2cap_recv_acldata() and sco_recv_scodata() return void The return value of l2cap_recv_acldata() and sco_recv_scodata() are not used, then change it to return void Signed-off-by: Arron Wang Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 4 ++-- net/bluetooth/l2cap_core.c | 5 ++--- net/bluetooth/sco.c | 5 ++--- 3 files changed, 6 insertions(+), 8 deletions(-) (limited to 'include/net') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 24c0e4577a93..f175a51f9740 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -530,10 +530,10 @@ extern struct mutex hci_cb_list_lock; /* ----- HCI interface to upper protocols ----- */ int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr); int l2cap_disconn_ind(struct hci_conn *hcon); -int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags); +void l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags); int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags); -int sco_recv_scodata(struct hci_conn *hcon, struct sk_buff *skb); +void sco_recv_scodata(struct hci_conn *hcon, struct sk_buff *skb); /* ----- Inquiry cache ----- */ #define INQUIRY_CACHE_AGE_MAX (HZ*30) /* 30 seconds */ diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index dad419782a12..07bd316d02ba 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -7442,7 +7442,7 @@ static void l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) mutex_unlock(&conn->chan_lock); } -int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags) +void l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags) { struct l2cap_conn *conn = hcon->l2cap_data; struct l2cap_hdr *hdr; @@ -7485,7 +7485,7 @@ int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags) if (len == skb->len) { /* Complete frame received */ l2cap_recv_frame(conn, skb); - return 0; + return; } BT_DBG("Start: total len %d, frag len %d", len, skb->len); @@ -7544,7 +7544,6 @@ int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags) drop: kfree_skb(skb); - return 0; } static struct hci_cb l2cap_cb = { diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index 6b6e59dc54cf..688a040c5626 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -1110,7 +1110,7 @@ static void sco_disconn_cfm(struct hci_conn *hcon, __u8 reason) sco_conn_del(hcon, bt_to_errno(reason)); } -int sco_recv_scodata(struct hci_conn *hcon, struct sk_buff *skb) +void sco_recv_scodata(struct hci_conn *hcon, struct sk_buff *skb) { struct sco_conn *conn = hcon->sco_data; @@ -1121,12 +1121,11 @@ int sco_recv_scodata(struct hci_conn *hcon, struct sk_buff *skb) if (skb->len) { sco_recv_frame(conn, skb); - return 0; + return; } drop: kfree_skb(skb); - return 0; } static struct hci_cb sco_cb = { -- cgit v1.2.3-71-gd317 From ff50e8afc537e66bb3daf5d1cd6628d6b76e7f06 Mon Sep 17 00:00:00 2001 From: Arron Wang Date: Tue, 9 Jun 2015 17:47:23 +0800 Subject: Bluetooth: Move SCO support under BT_BREDR config option SCO/eSCO link is supported by BR/EDR controller, it is suitable to move them under BT_BREDR config option Signed-off-by: Arron Wang Signed-off-by: Marcel Holtmann --- include/net/bluetooth/bluetooth.h | 11 +++++++++++ include/net/bluetooth/hci_core.h | 12 ++++++++++++ net/bluetooth/Makefile | 3 ++- 3 files changed, 25 insertions(+), 1 deletion(-) (limited to 'include/net') diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h index 7dba80546f16..38d8a34d3589 100644 --- a/include/net/bluetooth/bluetooth.h +++ b/include/net/bluetooth/bluetooth.h @@ -365,8 +365,19 @@ extern struct dentry *bt_debugfs; int l2cap_init(void); void l2cap_exit(void); +#if IS_ENABLED(CONFIG_BT_BREDR) int sco_init(void); void sco_exit(void); +#else +static inline int sco_init(void) +{ + return 0; +} + +static inline void sco_exit(void) +{ +} +#endif int mgmt_init(void); void mgmt_exit(void); diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index f175a51f9740..3fbb793e634d 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -532,8 +532,20 @@ int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr); int l2cap_disconn_ind(struct hci_conn *hcon); void l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags); +#if IS_ENABLED(CONFIG_BT_BREDR) int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags); void sco_recv_scodata(struct hci_conn *hcon, struct sk_buff *skb); +#else +static inline int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, + __u8 *flags) +{ + return 0; +} + +static inline void sco_recv_scodata(struct hci_conn *hcon, struct sk_buff *skb) +{ +} +#endif /* ----- Inquiry cache ----- */ #define INQUIRY_CACHE_AGE_MAX (HZ*30) /* 30 seconds */ diff --git a/net/bluetooth/Makefile b/net/bluetooth/Makefile index 9a8ea232d28f..29c12ae72a66 100644 --- a/net/bluetooth/Makefile +++ b/net/bluetooth/Makefile @@ -12,9 +12,10 @@ obj-$(CONFIG_BT_6LOWPAN) += bluetooth_6lowpan.o bluetooth_6lowpan-y := 6lowpan.o bluetooth-y := af_bluetooth.o hci_core.o hci_conn.o hci_event.o mgmt.o \ - hci_sock.o hci_sysfs.o l2cap_core.o l2cap_sock.o smp.o sco.o lib.o \ + hci_sock.o hci_sysfs.o l2cap_core.o l2cap_sock.o smp.o lib.o \ a2mp.o amp.o ecc.o hci_request.o mgmt_util.o +bluetooth-$(CONFIG_BT_BREDR) += sco.o bluetooth-$(CONFIG_BT_DEBUGFS) += hci_debugfs.o bluetooth-$(CONFIG_BT_SELFTEST) += selftest.o -- cgit v1.2.3-71-gd317 From d446278c408bdebd4103090740ce908c5d6b5ab0 Mon Sep 17 00:00:00 2001 From: Christoffer Holmstedt Date: Wed, 10 Jun 2015 11:03:59 +0200 Subject: nl802154: fix misspelled enum Signed-off-by: Christoffer Holmstedt Signed-off-by: Marcel Holtmann --- include/net/nl802154.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include/net') diff --git a/include/net/nl802154.h b/include/net/nl802154.h index 6fc231e60920..b0ab530d28cd 100644 --- a/include/net/nl802154.h +++ b/include/net/nl802154.h @@ -187,7 +187,7 @@ enum nl802154_wpan_phy_capability_attr { * @NL802154_CCA_ENERGY_CARRIER: Carrier sense with energy above threshold * @NL802154_CCA_ALOHA: CCA shall always report an idle medium * @NL802154_CCA_UWB_SHR: UWB preamble sense based on the SHR of a frame - * @NL802154_CCA_UWB_MULTIPEXED: UWB preamble sense based on the packet with + * @NL802154_CCA_UWB_MULTIPLEXED: UWB preamble sense based on the packet with * the multiplexed preamble * @__NL802154_CCA_ATTR_AFTER_LAST: Internal * @NL802154_CCA_ATTR_MAX: Maximum CCA attribute number @@ -199,7 +199,7 @@ enum nl802154_cca_modes { NL802154_CCA_ENERGY_CARRIER, NL802154_CCA_ALOHA, NL802154_CCA_UWB_SHR, - NL802154_CCA_UWB_MULTIPEXED, + NL802154_CCA_UWB_MULTIPLEXED, /* keep last */ __NL802154_CCA_ATTR_AFTER_LAST, -- cgit v1.2.3-71-gd317 From 821f37666815c9f3a7a4d195ce9184ad4d084942 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 11 Jun 2015 13:52:29 +0300 Subject: Bluetooth: Read encryption key size for BR/EDR connections Since Bluetooth 3.0 there's a HCI command available for reading the encryption key size of an BR/EDR connection. This information is essential e.g. for generating an LTK using SMP over BR/EDR, so store it as part of struct hci_conn. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci.h | 10 ++++++ net/bluetooth/hci_event.c | 87 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 97 insertions(+) (limited to 'include/net') diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index d95da83cb1b0..7ca6690355ea 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -1202,6 +1202,16 @@ struct hci_rp_read_clock { __le16 accuracy; } __packed; +#define HCI_OP_READ_ENC_KEY_SIZE 0x1408 +struct hci_cp_read_enc_key_size { + __le16 handle; +} __packed; +struct hci_rp_read_enc_key_size { + __u8 status; + __le16 handle; + __u8 key_size; +} __packed; + #define HCI_OP_READ_LOCAL_AMP_INFO 0x1409 struct hci_rp_read_local_amp_info { __u8 status; diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 62934151431b..88c57b12a222 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -2603,6 +2603,64 @@ unlock: hci_dev_unlock(hdev); } +static void read_enc_key_size_complete(struct hci_dev *hdev, u8 status, + u16 opcode, struct sk_buff *skb) +{ + const struct hci_rp_read_enc_key_size *rp; + struct hci_conn *conn; + u16 handle; + + BT_DBG("%s status 0x%02x", hdev->name, status); + + if (!skb || skb->len < sizeof(*rp)) { + BT_ERR("%s invalid HCI Read Encryption Key Size response", + hdev->name); + return; + } + + rp = (void *)skb->data; + handle = le16_to_cpu(rp->handle); + + hci_dev_lock(hdev); + + conn = hci_conn_hash_lookup_handle(hdev, handle); + if (!conn) + goto unlock; + + /* If we fail to read the encryption key size, assume maximum + * (which is the same we do also when this HCI command isn't + * supported. + */ + if (rp->status) { + BT_ERR("%s failed to read key size for handle %u", hdev->name, + handle); + conn->enc_key_size = HCI_LINK_KEY_SIZE; + } else { + conn->enc_key_size = rp->key_size; + } + + if (conn->state == BT_CONFIG) { + conn->state = BT_CONNECTED; + hci_connect_cfm(conn, 0); + hci_conn_drop(conn); + } else { + u8 encrypt; + + if (!test_bit(HCI_CONN_ENCRYPT, &conn->flags)) + encrypt = 0x00; + else if (conn->type == ACL_LINK && + test_bit(HCI_CONN_AES_CCM, &conn->flags)) + encrypt = 0x02; + else + encrypt = 0x01; + + hci_encrypt_cfm(conn, 0, encrypt); + } + +unlock: + hci_dev_unlock(hdev); +} + static void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_ev_encrypt_change *ev = (void *) skb->data; @@ -2662,6 +2720,35 @@ static void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *skb) goto unlock; } + /* Try reading the encryption key size for encrypted ACL links */ + if (!ev->status && ev->encrypt && conn->type == ACL_LINK) { + struct hci_cp_read_enc_key_size cp; + struct hci_request req; + + /* Only send HCI_Read_Encryption_Key_Size if the + * controller really supports it. If it doesn't, assume + * the default size (16). + */ + if (!(hdev->commands[20] & 0x10)) { + conn->enc_key_size = HCI_LINK_KEY_SIZE; + goto notify; + } + + hci_req_init(&req, hdev); + + cp.handle = cpu_to_le16(conn->handle); + hci_req_add(&req, HCI_OP_READ_ENC_KEY_SIZE, sizeof(cp), &cp); + + if (hci_req_run_skb(&req, read_enc_key_size_complete)) { + BT_ERR("Sending HCI Read Encryption Key Size failed"); + conn->enc_key_size = HCI_LINK_KEY_SIZE; + goto notify; + } + + goto unlock; + } + +notify: if (conn->state == BT_CONFIG) { if (!ev->status) conn->state = BT_CONNECTED; -- cgit v1.2.3-71-gd317 From fe89e69050489884b304ea67b580056395dbd2b1 Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Fri, 12 Jun 2015 09:13:49 +0530 Subject: mac802154: cleanup llsec param flags This patch changes the setting of llsec param flag with the BIT macro. Signed-off-by: Varka Bhadram Acked-by: Alexander Aring Signed-off-by: Marcel Holtmann --- include/net/ieee802154_netdev.h | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'include/net') diff --git a/include/net/ieee802154_netdev.h b/include/net/ieee802154_netdev.h index 0a87975128ec..2c10a9f0c6d9 100644 --- a/include/net/ieee802154_netdev.h +++ b/include/net/ieee802154_netdev.h @@ -346,15 +346,15 @@ struct ieee802154_mac_params { struct wpan_phy; enum { - IEEE802154_LLSEC_PARAM_ENABLED = 1 << 0, - IEEE802154_LLSEC_PARAM_FRAME_COUNTER = 1 << 1, - IEEE802154_LLSEC_PARAM_OUT_LEVEL = 1 << 2, - IEEE802154_LLSEC_PARAM_OUT_KEY = 1 << 3, - IEEE802154_LLSEC_PARAM_KEY_SOURCE = 1 << 4, - IEEE802154_LLSEC_PARAM_PAN_ID = 1 << 5, - IEEE802154_LLSEC_PARAM_HWADDR = 1 << 6, - IEEE802154_LLSEC_PARAM_COORD_HWADDR = 1 << 7, - IEEE802154_LLSEC_PARAM_COORD_SHORTADDR = 1 << 8, + IEEE802154_LLSEC_PARAM_ENABLED = BIT(0), + IEEE802154_LLSEC_PARAM_FRAME_COUNTER = BIT(1), + IEEE802154_LLSEC_PARAM_OUT_LEVEL = BIT(2), + IEEE802154_LLSEC_PARAM_OUT_KEY = BIT(3), + IEEE802154_LLSEC_PARAM_KEY_SOURCE = BIT(4), + IEEE802154_LLSEC_PARAM_PAN_ID = BIT(5), + IEEE802154_LLSEC_PARAM_HWADDR = BIT(6), + IEEE802154_LLSEC_PARAM_COORD_HWADDR = BIT(7), + IEEE802154_LLSEC_PARAM_COORD_SHORTADDR = BIT(8), }; struct ieee802154_llsec_ops { -- cgit v1.2.3-71-gd317 From 70f36507d0c3277e4a5424ca0c6c2a002ae42768 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Fri, 12 Jun 2015 09:24:00 +0200 Subject: mac802154: fix flags BIT definitions order This patch fixes commits ("mac802154: cleanup ieee802154 hardware flags") bcbfd2078d9b11277d9c9ce0c30ba73c750503c9 and ("mac802154: cleanup address filtering flags") 6b70a43c7e0202cf285c864bc9f20f607c42e432 by starting the flags definitions at BIT(0) which is same like the previous behaviour. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- include/net/mac802154.h | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'include/net') diff --git a/include/net/mac802154.h b/include/net/mac802154.h index de1cdde92edc..f534a46911dc 100644 --- a/include/net/mac802154.h +++ b/include/net/mac802154.h @@ -49,10 +49,10 @@ * do frame address filtering as a pan coordinator. */ enum ieee802154_hw_addr_filt_flags { - IEEE802154_AFILT_SADDR_CHANGED = BIT(1), - IEEE802154_AFILT_IEEEADDR_CHANGED = BIT(2), - IEEE802154_AFILT_PANID_CHANGED = BIT(3), - IEEE802154_AFILT_PANC_CHANGED = BIT(4), + IEEE802154_AFILT_SADDR_CHANGED = BIT(0), + IEEE802154_AFILT_IEEEADDR_CHANGED = BIT(1), + IEEE802154_AFILT_PANID_CHANGED = BIT(2), + IEEE802154_AFILT_PANC_CHANGED = BIT(3), }; /** @@ -133,14 +133,14 @@ struct ieee802154_hw { * frames with bad checksum. */ enum ieee802154_hw_flags { - IEEE802154_HW_TX_OMIT_CKSUM = BIT(1), - IEEE802154_HW_LBT = BIT(2), - IEEE802154_HW_CSMA_PARAMS = BIT(3), - IEEE802154_HW_FRAME_RETRIES = BIT(4), - IEEE802154_HW_AFILT = BIT(5), - IEEE802154_HW_PROMISCUOUS = BIT(6), - IEEE802154_HW_RX_OMIT_CKSUM = BIT(7), - IEEE802154_HW_RX_DROP_BAD_CKSUM = BIT(8), + IEEE802154_HW_TX_OMIT_CKSUM = BIT(0), + IEEE802154_HW_LBT = BIT(1), + IEEE802154_HW_CSMA_PARAMS = BIT(2), + IEEE802154_HW_FRAME_RETRIES = BIT(3), + IEEE802154_HW_AFILT = BIT(4), + IEEE802154_HW_PROMISCUOUS = BIT(5), + IEEE802154_HW_RX_OMIT_CKSUM = BIT(6), + IEEE802154_HW_RX_DROP_BAD_CKSUM = BIT(7), }; /* Indicates that receiver omits FCS and xmitter will add FCS on it's own. */ -- cgit v1.2.3-71-gd317 From d2609b345ebf0547015a78588c4d7ad68c9ccf26 Mon Sep 17 00:00:00 2001 From: Florian Grandel Date: Thu, 18 Jun 2015 03:16:34 +0200 Subject: Bluetooth: hci_core/mgmt: Introduce multi-adv list The current hci dev structure only supports a single advertising instance. To support multi-instance advertising it is necessary to introduce a linked list of advertising instances so that multiple advertising instances can be dynamically added and/or removed. In a first step, the existing adv_instance member of the hci_dev struct is supplemented by a linked list of advertising instances. This patch introduces the list and supporting list management infrastructure. The list is not being used yet. Signed-off-by: Florian Grandel Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 17 ++++++ net/bluetooth/hci_core.c | 117 +++++++++++++++++++++++++++++++++++++++ net/bluetooth/mgmt.c | 2 +- 3 files changed, 135 insertions(+), 1 deletion(-) (limited to 'include/net') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 3fbb793e634d..4242dbfb4cf5 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -157,15 +157,20 @@ struct oob_data { struct adv_info { struct delayed_work timeout_exp; + struct list_head list; __u8 instance; __u32 flags; __u16 timeout; + __u16 duration; __u16 adv_data_len; __u8 adv_data[HCI_MAX_AD_LENGTH]; __u16 scan_rsp_len; __u8 scan_rsp_data[HCI_MAX_AD_LENGTH]; }; +#define HCI_MAX_ADV_INSTANCES 1 +#define HCI_DEFAULT_ADV_DURATION 2 + #define HCI_MAX_SHORT_NAME_LENGTH 10 /* Default LE RPA expiry time, 15 minutes */ @@ -374,6 +379,9 @@ struct hci_dev { __u8 scan_rsp_data_len; struct adv_info adv_instance; + struct list_head adv_instances; + unsigned int adv_instance_cnt; + __u8 cur_adv_instance; __u8 irk[16]; __u32 rpa_timeout; @@ -1019,6 +1027,15 @@ int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, int hci_remove_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 bdaddr_type); +void hci_adv_instances_clear(struct hci_dev *hdev); +struct adv_info *hci_find_adv_instance(struct hci_dev *hdev, u8 instance); +struct adv_info *hci_get_next_instance(struct hci_dev *hdev, u8 instance); +int hci_add_adv_instance(struct hci_dev *hdev, u8 instance, u32 flags, + u16 adv_data_len, u8 *adv_data, + u16 scan_rsp_len, u8 *scan_rsp_data, + u16 timeout, u16 duration); +int hci_remove_adv_instance(struct hci_dev *hdev, u8 instance); + void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb); int hci_recv_frame(struct hci_dev *hdev, struct sk_buff *skb); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 573711c2d09e..ebf37ebcfd12 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2610,6 +2610,119 @@ int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, return 0; } +/* This function requires the caller holds hdev->lock */ +struct adv_info *hci_find_adv_instance(struct hci_dev *hdev, u8 instance) +{ + struct adv_info *adv_instance; + + list_for_each_entry(adv_instance, &hdev->adv_instances, list) { + if (adv_instance->instance == instance) + return adv_instance; + } + + return NULL; +} + +/* This function requires the caller holds hdev->lock */ +struct adv_info *hci_get_next_instance(struct hci_dev *hdev, u8 instance) { + struct adv_info *cur_instance; + + cur_instance = hci_find_adv_instance(hdev, instance); + if (!cur_instance) + return NULL; + + if (cur_instance == list_last_entry(&hdev->adv_instances, + struct adv_info, list)) + return list_first_entry(&hdev->adv_instances, + struct adv_info, list); + else + return list_next_entry(cur_instance, list); +} + +/* This function requires the caller holds hdev->lock */ +int hci_remove_adv_instance(struct hci_dev *hdev, u8 instance) +{ + struct adv_info *adv_instance; + + adv_instance = hci_find_adv_instance(hdev, instance); + if (!adv_instance) + return -ENOENT; + + BT_DBG("%s removing %dMR", hdev->name, instance); + + list_del(&adv_instance->list); + kfree(adv_instance); + + hdev->adv_instance_cnt--; + + return 0; +} + +/* This function requires the caller holds hdev->lock */ +void hci_adv_instances_clear(struct hci_dev *hdev) +{ + struct adv_info *adv_instance, *n; + + list_for_each_entry_safe(adv_instance, n, &hdev->adv_instances, list) { + list_del(&adv_instance->list); + kfree(adv_instance); + } + + hdev->adv_instance_cnt = 0; +} + +/* This function requires the caller holds hdev->lock */ +int hci_add_adv_instance(struct hci_dev *hdev, u8 instance, u32 flags, + u16 adv_data_len, u8 *adv_data, + u16 scan_rsp_len, u8 *scan_rsp_data, + u16 timeout, u16 duration) +{ + struct adv_info *adv_instance; + + adv_instance = hci_find_adv_instance(hdev, instance); + if (adv_instance) { + memset(adv_instance->adv_data, 0, + sizeof(adv_instance->adv_data)); + memset(adv_instance->scan_rsp_data, 0, + sizeof(adv_instance->scan_rsp_data)); + } else { + if (hdev->adv_instance_cnt >= HCI_MAX_ADV_INSTANCES || + instance < 1 || instance > HCI_MAX_ADV_INSTANCES) + return -EOVERFLOW; + + adv_instance = kmalloc(sizeof(*adv_instance), GFP_KERNEL); + if (!adv_instance) + return -ENOMEM; + + memset(adv_instance, 0, sizeof(*adv_instance)); + adv_instance->instance = instance; + list_add(&adv_instance->list, &hdev->adv_instances); + hdev->adv_instance_cnt++; + } + + adv_instance->flags = flags; + adv_instance->adv_data_len = adv_data_len; + adv_instance->scan_rsp_len = scan_rsp_len; + + if (adv_data_len) + memcpy(adv_instance->adv_data, adv_data, adv_data_len); + + if (scan_rsp_len) + memcpy(adv_instance->scan_rsp_data, + scan_rsp_data, scan_rsp_len); + + adv_instance->timeout = timeout; + + if (duration == 0) + adv_instance->duration = HCI_DEFAULT_ADV_DURATION; + else + adv_instance->duration = duration; + + BT_DBG("%s for %dMR", hdev->name, instance); + + return 0; +} + struct bdaddr_list *hci_bdaddr_list_lookup(struct list_head *bdaddr_list, bdaddr_t *bdaddr, u8 type) { @@ -3015,6 +3128,8 @@ struct hci_dev *hci_alloc_dev(void) hdev->manufacturer = 0xffff; /* Default to internal use */ hdev->inq_tx_power = HCI_TX_POWER_INVALID; hdev->adv_tx_power = HCI_TX_POWER_INVALID; + hdev->adv_instance_cnt = 0; + hdev->cur_adv_instance = 0x00; hdev->sniff_max_interval = 800; hdev->sniff_min_interval = 80; @@ -3056,6 +3171,7 @@ struct hci_dev *hci_alloc_dev(void) INIT_LIST_HEAD(&hdev->pend_le_conns); INIT_LIST_HEAD(&hdev->pend_le_reports); INIT_LIST_HEAD(&hdev->conn_hash.list); + INIT_LIST_HEAD(&hdev->adv_instances); INIT_WORK(&hdev->rx_work, hci_rx_work); INIT_WORK(&hdev->cmd_work, hci_cmd_work); @@ -3249,6 +3365,7 @@ void hci_unregister_dev(struct hci_dev *hdev) hci_smp_ltks_clear(hdev); hci_smp_irks_clear(hdev); hci_remote_oob_data_clear(hdev); + hci_adv_instances_clear(hdev); hci_bdaddr_list_clear(&hdev->le_white_list); hci_conn_params_clear_all(hdev); hci_discovery_filter_clear(hdev); diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index e41bbe28a36e..92c50a17fdf9 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -6813,7 +6813,7 @@ static int read_adv_features(struct sock *sk, struct hci_dev *hdev, rp->supported_flags = cpu_to_le32(supported_flags); rp->max_adv_data_len = HCI_MAX_AD_LENGTH; rp->max_scan_rsp_len = HCI_MAX_AD_LENGTH; - rp->max_instances = 1; + rp->max_instances = HCI_MAX_ADV_INSTANCES; /* Currently only one instance is supported, so simply return the * current instance number. -- cgit v1.2.3-71-gd317 From 5d900e4601391576a3c0644d7fcad1ebf41a516e Mon Sep 17 00:00:00 2001 From: Florian Grandel Date: Thu, 18 Jun 2015 03:16:35 +0200 Subject: Bluetooth: hci_core/mgmt: move adv timeout to hdev Currently the delayed work managing advertising duration and timeout is part of the advertising instance structure. This is not correct as only a single instance can be advertised at any given time. To implement round robin advertising a single delayed work structure is needed. To fix this the delayed work structure is being moved to the hci_dev structure. The instance specific variable is renamed to "remaining_time" to make it clear that this is the remaining lifetime of the instance and not the current advertising timeout. Signed-off-by: Florian Grandel Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 5 ++++- net/bluetooth/hci_core.c | 29 +++++++++++++++++++++++++++++ net/bluetooth/mgmt.c | 27 +++++++++++---------------- 3 files changed, 44 insertions(+), 17 deletions(-) (limited to 'include/net') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 4242dbfb4cf5..b53e1b113621 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -156,11 +156,11 @@ struct oob_data { }; struct adv_info { - struct delayed_work timeout_exp; struct list_head list; __u8 instance; __u32 flags; __u16 timeout; + __u16 remaining_time; __u16 duration; __u16 adv_data_len; __u8 adv_data[HCI_MAX_AD_LENGTH]; @@ -382,6 +382,8 @@ struct hci_dev { struct list_head adv_instances; unsigned int adv_instance_cnt; __u8 cur_adv_instance; + __u16 adv_instance_timeout; + struct delayed_work adv_instance_expire; __u8 irk[16]; __u32 rpa_timeout; @@ -1379,6 +1381,7 @@ void mgmt_set_powered_failed(struct hci_dev *hdev, int err); int mgmt_powered(struct hci_dev *hdev, u8 powered); int mgmt_update_adv_data(struct hci_dev *hdev); void mgmt_discoverable_timeout(struct hci_dev *hdev); +void mgmt_adv_timeout_expired(struct hci_dev *hdev); void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key, bool persistent); void mgmt_device_connected(struct hci_dev *hdev, struct hci_conn *conn, diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index ebf37ebcfd12..d1110db3b0d4 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1591,6 +1591,11 @@ static int hci_dev_do_close(struct hci_dev *hdev) if (hci_dev_test_flag(hdev, HCI_MGMT)) cancel_delayed_work_sync(&hdev->rpa_expired); + if (hdev->adv_instance_timeout) { + cancel_delayed_work_sync(&hdev->adv_instance_expire); + hdev->adv_instance_timeout = 0; + } + /* Avoid potential lockdep warnings from the *_flush() calls by * ensuring the workqueue is empty up front. */ @@ -2147,6 +2152,17 @@ static void hci_discov_off(struct work_struct *work) mgmt_discoverable_timeout(hdev); } +static void hci_adv_timeout_expire(struct work_struct *work) +{ + struct hci_dev *hdev; + + hdev = container_of(work, struct hci_dev, adv_instance_expire.work); + + BT_DBG("%s", hdev->name); + + mgmt_adv_timeout_expired(hdev); +} + void hci_uuids_clear(struct hci_dev *hdev) { struct bt_uuid *uuid, *tmp; @@ -2650,6 +2666,11 @@ int hci_remove_adv_instance(struct hci_dev *hdev, u8 instance) BT_DBG("%s removing %dMR", hdev->name, instance); + if (hdev->cur_adv_instance == instance && hdev->adv_instance_timeout) { + cancel_delayed_work(&hdev->adv_instance_expire); + hdev->adv_instance_timeout = 0; + } + list_del(&adv_instance->list); kfree(adv_instance); @@ -2663,6 +2684,11 @@ void hci_adv_instances_clear(struct hci_dev *hdev) { struct adv_info *adv_instance, *n; + if (hdev->adv_instance_timeout) { + cancel_delayed_work(&hdev->adv_instance_expire); + hdev->adv_instance_timeout = 0; + } + list_for_each_entry_safe(adv_instance, n, &hdev->adv_instances, list) { list_del(&adv_instance->list); kfree(adv_instance); @@ -2712,6 +2738,7 @@ int hci_add_adv_instance(struct hci_dev *hdev, u8 instance, u32 flags, scan_rsp_data, scan_rsp_len); adv_instance->timeout = timeout; + adv_instance->remaining_time = timeout; if (duration == 0) adv_instance->duration = HCI_DEFAULT_ADV_DURATION; @@ -3130,6 +3157,7 @@ struct hci_dev *hci_alloc_dev(void) hdev->adv_tx_power = HCI_TX_POWER_INVALID; hdev->adv_instance_cnt = 0; hdev->cur_adv_instance = 0x00; + hdev->adv_instance_timeout = 0; hdev->sniff_max_interval = 800; hdev->sniff_min_interval = 80; @@ -3183,6 +3211,7 @@ struct hci_dev *hci_alloc_dev(void) INIT_DELAYED_WORK(&hdev->discov_off, hci_discov_off); INIT_DELAYED_WORK(&hdev->le_scan_disable, le_scan_disable_work); INIT_DELAYED_WORK(&hdev->le_scan_restart, le_scan_restart_work); + INIT_DELAYED_WORK(&hdev->adv_instance_expire, hci_adv_timeout_expire); skb_queue_head_init(&hdev->rx_q); skb_queue_head_init(&hdev->cmd_q); diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 92c50a17fdf9..a8319f6cfa65 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1466,8 +1466,8 @@ static void clear_adv_instance(struct hci_dev *hdev) if (!hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE)) return; - if (hdev->adv_instance.timeout) - cancel_delayed_work(&hdev->adv_instance.timeout_exp); + if (hdev->adv_instance_timeout) + cancel_delayed_work(&hdev->adv_instance_expire); memset(&hdev->adv_instance, 0, sizeof(hdev->adv_instance)); advertising_removed(NULL, hdev, 1); @@ -1497,7 +1497,7 @@ static int clean_up_hci_state(struct hci_dev *hdev) hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan); } - if (hdev->adv_instance.timeout) + if (hdev->adv_instance_timeout) clear_adv_instance(hdev); if (hci_dev_test_flag(hdev, HCI_LE_ADV)) @@ -6914,12 +6914,9 @@ unlock: hci_dev_unlock(hdev); } -static void adv_timeout_expired(struct work_struct *work) +void mgmt_adv_timeout_expired(struct hci_dev *hdev) { - struct hci_dev *hdev = container_of(work, struct hci_dev, - adv_instance.timeout_exp.work); - - hdev->adv_instance.timeout = 0; + hdev->adv_instance_timeout = 0; hci_dev_lock(hdev); clear_adv_instance(hdev); @@ -6981,8 +6978,6 @@ static int add_advertising(struct sock *sk, struct hci_dev *hdev, goto unlock; } - INIT_DELAYED_WORK(&hdev->adv_instance.timeout_exp, adv_timeout_expired); - hdev->adv_instance.flags = flags; hdev->adv_instance.adv_data_len = cp->adv_data_len; hdev->adv_instance.scan_rsp_len = cp->scan_rsp_len; @@ -6994,14 +6989,14 @@ static int add_advertising(struct sock *sk, struct hci_dev *hdev, memcpy(hdev->adv_instance.scan_rsp_data, cp->data + cp->adv_data_len, cp->scan_rsp_len); - if (hdev->adv_instance.timeout) - cancel_delayed_work(&hdev->adv_instance.timeout_exp); + if (hdev->adv_instance_timeout) + cancel_delayed_work(&hdev->adv_instance_expire); - hdev->adv_instance.timeout = timeout; + hdev->adv_instance_timeout = timeout; if (timeout) queue_delayed_work(hdev->workqueue, - &hdev->adv_instance.timeout_exp, + &hdev->adv_instance_expire, msecs_to_jiffies(timeout * 1000)); if (!hci_dev_test_and_set_flag(hdev, HCI_ADVERTISING_INSTANCE)) @@ -7106,8 +7101,8 @@ static int remove_advertising(struct sock *sk, struct hci_dev *hdev, goto unlock; } - if (hdev->adv_instance.timeout) - cancel_delayed_work(&hdev->adv_instance.timeout_exp); + if (hdev->adv_instance_timeout) + cancel_delayed_work(&hdev->adv_instance_expire); memset(&hdev->adv_instance, 0, sizeof(hdev->adv_instance)); -- cgit v1.2.3-71-gd317 From fffd38bca51c9a1c00508b754ab66edb6f39cf37 Mon Sep 17 00:00:00 2001 From: Florian Grandel Date: Thu, 18 Jun 2015 03:16:47 +0200 Subject: Bluetooth: mgmt/hci_core: multi-adv for add_advertising*() The add_advertising() and add_advertising_complete() functions reference the now obsolete hdev->adv_instance struct. Both methods are being refactored to access the dynamic advertising instance list instead. This patch also introduces all logic necessary to actually deal with multiple instance advertising. Notably the mgmt_adv_inst_expired() and schedule_adv_inst() method are being referenced to schedule instances in a round robin fashion. This patch also introduces a "pending" flag into the adv_info struct. This is necessary to identify and remove recently added advertising instances when the HCI commands return with an error status code. Otherwise new advertising instances could be leaked without properly informing userspace about their existence. Signed-off-by: Florian Grandel Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 1 + net/bluetooth/hci_core.c | 1 + net/bluetooth/mgmt.c | 108 ++++++++++++++++++++++++++------------- 3 files changed, 75 insertions(+), 35 deletions(-) (limited to 'include/net') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index b53e1b113621..4f58a0e6e0d3 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -157,6 +157,7 @@ struct oob_data { struct adv_info { struct list_head list; + bool pending; __u8 instance; __u32 flags; __u16 timeout; diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index d1110db3b0d4..e50f7c3c67f8 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2721,6 +2721,7 @@ int hci_add_adv_instance(struct hci_dev *hdev, u8 instance, u32 flags, return -ENOMEM; memset(adv_instance, 0, sizeof(*adv_instance)); + adv_instance->pending = true; adv_instance->instance = instance; list_add(&adv_instance->list, &hdev->adv_instances); hdev->adv_instance_cnt++; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index ac5fc357c757..0cc685495510 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -7033,7 +7033,10 @@ static void add_advertising_complete(struct hci_dev *hdev, u8 status, u16 opcode) { struct mgmt_pending_cmd *cmd; + struct mgmt_cp_add_advertising *cp; struct mgmt_rp_add_advertising rp; + struct adv_info *adv_instance, *n; + u8 instance; BT_DBG("status %d", status); @@ -7041,16 +7044,32 @@ static void add_advertising_complete(struct hci_dev *hdev, u8 status, cmd = pending_find(MGMT_OP_ADD_ADVERTISING, hdev); - if (status) { + if (status) hci_dev_clear_flag(hdev, HCI_ADVERTISING_INSTANCE); - memset(&hdev->adv_instance, 0, sizeof(hdev->adv_instance)); - advertising_removed(cmd ? cmd->sk : NULL, hdev, 1); + + list_for_each_entry_safe(adv_instance, n, &hdev->adv_instances, list) { + if (!adv_instance->pending) + continue; + + if (!status) { + adv_instance->pending = false; + continue; + } + + instance = adv_instance->instance; + + if (hdev->cur_adv_instance == instance) + cancel_adv_timeout(hdev); + + hci_remove_adv_instance(hdev, instance); + advertising_removed(cmd ? cmd->sk : NULL, hdev, instance); } if (!cmd) goto unlock; - rp.instance = 0x01; + cp = cmd->param; + rp.instance = cp->instance; if (status) mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, @@ -7098,7 +7117,10 @@ static int add_advertising(struct sock *sk, struct hci_dev *hdev, u32 flags; u32 supported_flags; u8 status; - u16 timeout; + u16 timeout, duration; + unsigned int prev_instance_cnt = hdev->adv_instance_cnt; + u8 schedule_instance = 0; + struct adv_info *next_instance; int err; struct mgmt_pending_cmd *cmd; struct hci_request req; @@ -7112,12 +7134,13 @@ static int add_advertising(struct sock *sk, struct hci_dev *hdev, flags = __le32_to_cpu(cp->flags); timeout = __le16_to_cpu(cp->timeout); + duration = __le16_to_cpu(cp->duration); - /* The current implementation only supports adding one instance and only - * a subset of the specified flags. + /* The current implementation only supports a subset of the specified + * flags. */ supported_flags = get_supported_adv_flags(hdev); - if (cp->instance != 0x01 || (flags & ~supported_flags)) + if (flags & ~supported_flags) return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING, MGMT_STATUS_INVALID_PARAMS); @@ -7145,36 +7168,51 @@ static int add_advertising(struct sock *sk, struct hci_dev *hdev, goto unlock; } - hdev->adv_instance.flags = flags; - hdev->adv_instance.adv_data_len = cp->adv_data_len; - hdev->adv_instance.scan_rsp_len = cp->scan_rsp_len; - - if (cp->adv_data_len) - memcpy(hdev->adv_instance.adv_data, cp->data, cp->adv_data_len); - - if (cp->scan_rsp_len) - memcpy(hdev->adv_instance.scan_rsp_data, - cp->data + cp->adv_data_len, cp->scan_rsp_len); + err = hci_add_adv_instance(hdev, cp->instance, flags, + cp->adv_data_len, cp->data, + cp->scan_rsp_len, + cp->data + cp->adv_data_len, + timeout, duration); + if (err < 0) { + err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING, + MGMT_STATUS_FAILED); + goto unlock; + } - if (hdev->adv_instance_timeout) - cancel_delayed_work(&hdev->adv_instance_expire); + /* Only trigger an advertising added event if a new instance was + * actually added. + */ + if (hdev->adv_instance_cnt > prev_instance_cnt) + advertising_added(sk, hdev, cp->instance); - hdev->adv_instance_timeout = timeout; + hci_dev_set_flag(hdev, HCI_ADVERTISING_INSTANCE); - if (timeout) - queue_delayed_work(hdev->workqueue, - &hdev->adv_instance_expire, - msecs_to_jiffies(timeout * 1000)); + if (hdev->cur_adv_instance == cp->instance) { + /* If the currently advertised instance is being changed then + * cancel the current advertising and schedule the next + * instance. If there is only one instance then the overridden + * advertising data will be visible right away. + */ + cancel_adv_timeout(hdev); - if (!hci_dev_test_and_set_flag(hdev, HCI_ADVERTISING_INSTANCE)) - advertising_added(sk, hdev, 1); + next_instance = hci_get_next_instance(hdev, cp->instance); + if (next_instance) + schedule_instance = next_instance->instance; + } else if (!hdev->adv_instance_timeout) { + /* Immediately advertise the new instance if no other + * instance is currently being advertised. + */ + schedule_instance = cp->instance; + } - /* If the HCI_ADVERTISING flag is set or the device isn't powered then - * we have no HCI communication to make. Simply return. + /* If the HCI_ADVERTISING flag is set or the device isn't powered or + * there is no instance to be advertised then we have no HCI + * communication to make. Simply return. */ if (!hdev_is_powered(hdev) || - hci_dev_test_flag(hdev, HCI_ADVERTISING)) { - rp.instance = 0x01; + hci_dev_test_flag(hdev, HCI_ADVERTISING) || + !schedule_instance) { + rp.instance = cp->instance; err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_ADVERTISING, MGMT_STATUS_SUCCESS, &rp, sizeof(rp)); goto unlock; @@ -7192,11 +7230,11 @@ static int add_advertising(struct sock *sk, struct hci_dev *hdev, hci_req_init(&req, hdev); - update_adv_data(&req); - update_scan_rsp_data(&req); - enable_advertising(&req); + err = schedule_adv_instance(&req, schedule_instance, true); + + if (!err) + err = hci_req_run(&req, add_advertising_complete); - err = hci_req_run(&req, add_advertising_complete); if (err < 0) mgmt_pending_remove(cmd); -- cgit v1.2.3-71-gd317 From d4c5af8f71c8104504a83f7c71911550ebe43ac3 Mon Sep 17 00:00:00 2001 From: Florian Grandel Date: Thu, 18 Jun 2015 03:16:52 +0200 Subject: Bluetooth: hci_core: remove obsolete adv_instance Now that the obsolete adv_instance is no longer being referenced anywhere in the code it can be removed without breaking the build. Signed-off-by: Florian Grandel Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 6 ------ net/bluetooth/hci_core.c | 1 - 2 files changed, 7 deletions(-) (limited to 'include/net') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 4f58a0e6e0d3..a6cec6d21aff 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -379,7 +379,6 @@ struct hci_dev { __u8 scan_rsp_data[HCI_MAX_AD_LENGTH]; __u8 scan_rsp_data_len; - struct adv_info adv_instance; struct list_head adv_instances; unsigned int adv_instance_cnt; __u8 cur_adv_instance; @@ -584,11 +583,6 @@ static inline void hci_discovery_filter_clear(struct hci_dev *hdev) hdev->discovery.scan_duration = 0; } -static inline void adv_info_init(struct hci_dev *hdev) -{ - memset(&hdev->adv_instance, 0, sizeof(struct adv_info)); -} - bool hci_discovery_active(struct hci_dev *hdev); void hci_discovery_set_state(struct hci_dev *hdev, int state); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index e50f7c3c67f8..86ed44e39649 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -3224,7 +3224,6 @@ struct hci_dev *hci_alloc_dev(void) hci_init_sysfs(hdev); discovery_init(hdev); - adv_info_init(hdev); return hdev; } -- cgit v1.2.3-71-gd317 From db25be6657a56ba2d68aae1f90d796f527f65689 Mon Sep 17 00:00:00 2001 From: Florian Grandel Date: Thu, 18 Jun 2015 03:16:53 +0200 Subject: Bluetooth: hci_core: increase max adv inst Now that all preconditions are present for actual multi-advertising, the number of allowed advertising instances can be larger than one. This patch increases the number of allowed advertising instances to 5. Signed-off-by: Florian Grandel Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci_core.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/net') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index a6cec6d21aff..3bd618d3e55d 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -169,7 +169,7 @@ struct adv_info { __u8 scan_rsp_data[HCI_MAX_AD_LENGTH]; }; -#define HCI_MAX_ADV_INSTANCES 1 +#define HCI_MAX_ADV_INSTANCES 5 #define HCI_DEFAULT_ADV_DURATION 2 #define HCI_MAX_SHORT_NAME_LENGTH 10 -- cgit v1.2.3-71-gd317