Merge branch 'for-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next
This commit is contained in:
commit
6164c20228
40 changed files with 681 additions and 786 deletions
|
@ -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);
|
||||
|
|
|
@ -1,122 +0,0 @@
|
|||
/*
|
||||
* 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"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
config BT_BNEP
|
||||
tristate "BNEP protocol support"
|
||||
depends on BT
|
||||
depends on BT_BREDR
|
||||
select CRC32
|
||||
help
|
||||
BNEP (Bluetooth Network Encapsulation Protocol) is Ethernet
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
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,6 +2905,14 @@ 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_CREATE_PHY_LINK:
|
||||
hci_cs_create_phylink(hdev, ev->status);
|
||||
break;
|
||||
|
||||
case HCI_OP_ACCEPT_PHY_LINK:
|
||||
hci_cs_accept_phylink(hdev, ev->status);
|
||||
break;
|
||||
|
||||
case HCI_OP_SNIFF_MODE:
|
||||
hci_cs_sniff_mode(hdev, ev->status);
|
||||
break;
|
||||
|
@ -2883,16 +2921,8 @@ static void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
|||
hci_cs_exit_sniff_mode(hdev, ev->status);
|
||||
break;
|
||||
|
||||
case HCI_OP_DISCONNECT:
|
||||
hci_cs_disconnect(hdev, ev->status);
|
||||
break;
|
||||
|
||||
case HCI_OP_CREATE_PHY_LINK:
|
||||
hci_cs_create_phylink(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;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
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;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
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);
|
||||
alloc_size = sizeof(*rdev) + priv_size;
|
||||
rdev = kzalloc(alloc_size, GFP_KERNEL);
|
||||
if (!rdev)
|
||||
return NULL;
|
||||
|
||||
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;
|
||||
rdev->ops = ops;
|
||||
|
||||
rdev->wpan_phy_idx = atomic_inc_return(&wpan_phy_counter);
|
||||
|
||||
if (unlikely(rdev->wpan_phy_idx < 0)) {
|
||||
/* ugh, wrapped! */
|
||||
atomic_dec(&wpan_phy_counter);
|
||||
kfree(rdev);
|
||||
return NULL;
|
||||
}
|
||||
mutex_unlock(&wpan_phy_mutex);
|
||||
|
||||
mutex_init(&phy->pib_lock);
|
||||
/* atomic_inc_return makes it start at 1, make it start at 0 */
|
||||
rdev->wpan_phy_idx--;
|
||||
|
||||
device_initialize(&phy->dev);
|
||||
dev_set_name(&phy->dev, "wpan-phy%d", phy->idx);
|
||||
mutex_init(&rdev->wpan_phy.pib_lock);
|
||||
|
||||
phy->dev.class = &wpan_phy_class;
|
||||
device_initialize(&rdev->wpan_phy.dev);
|
||||
dev_set_name(&rdev->wpan_phy.dev, "wpan-phy%d", rdev->wpan_phy_idx);
|
||||
|
||||
phy->current_channel = -1; /* not initialised */
|
||||
phy->current_page = 0; /* for compatibility */
|
||||
rdev->wpan_phy.dev.class = &wpan_phy_class;
|
||||
rdev->wpan_phy.dev.platform_data = rdev;
|
||||
|
||||
return phy;
|
||||
|
||||
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;
|
||||
|
|
29
net/ieee802154/core.h
Normal file
29
net/ieee802154/core.h
Normal file
|
@ -0,0 +1,29 @@
|
|||
#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,9 +314,15 @@ 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(
|
||||
info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR]);
|
||||
|
@ -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, ¶ms);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
23
net/ieee802154/rdev-ops.h
Normal file
23
net/ieee802154/rdev-ops.h
Normal file
|
@ -0,0 +1,23 @@
|
|||
#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[] = {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
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__
|
||||
|
|
47
net/mac802154/cfg.c
Normal file
47
net/mac802154/cfg.c
Normal file
|
@ -0,0 +1,47 @@
|
|||
/* 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,
|
||||
};
|
9
net/mac802154/cfg.h
Normal file
9
net/mac802154/cfg.h
Normal file
|
@ -0,0 +1,9 @@
|
|||
/* 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,39 +109,23 @@ 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 */
|
||||
ieee802154_be64_to_le64(&extended_addr, addr->sa_data);
|
||||
if (!ieee802154_is_valid_extended_addr(extended_addr))
|
||||
return -EINVAL;
|
||||
|
||||
memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
|
||||
mac802154_dev_set_ieee_addr(dev);
|
||||
sdata->extended_addr = extended_addr;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
mutex_lock(&sdata->local->iflist_mtx);
|
||||
*params = sdata->mac_params;
|
||||
mutex_unlock(&sdata->local->iflist_mtx);
|
||||
}
|
||||
|
||||
static int mac802154_slave_open(struct net_device *dev)
|
||||
{
|
||||
struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(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,13 +181,21 @@ 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;
|
||||
|
||||
rc = drv_set_extended_addr(local, sdata->extended_addr);
|
||||
if (rc < 0)
|
||||
goto out;
|
||||
|
||||
rc = drv_set_short_addr(local, sdata->short_addr);
|
||||
if (rc < 0)
|
||||
goto out;
|
||||
}
|
||||
|
@ -214,19 +206,6 @@ static int mac802154_wpan_open(struct net_device *dev)
|
|||
goto out;
|
||||
}
|
||||
|
||||
if (local->hw.flags & IEEE802154_HW_CCA_MODE) {
|
||||
rc = drv_set_cca_mode(local, sdata->mac_params.cca_mode);
|
||||
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 (rc < 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (local->hw.flags & IEEE802154_HW_CSMA_PARAMS) {
|
||||
rc = drv_set_csma_params(local, sdata->mac_params.min_be,
|
||||
sdata->mac_params.max_be,
|
||||
|
@ -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;
|
||||
|
||||
mac802154_llsec_init(&sdata->sec);
|
||||
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();
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
dev->destructor = free_netdev;
|
||||
dev->netdev_ops = &mac802154_monitor_ops;
|
||||
dev->ml_priv = &mac802154_mlme_reduced;
|
||||
ndev = alloc_netdev(sizeof(*sdata) + local->hw.vif_data_size, name,
|
||||
NET_NAME_UNKNOWN, ieee802154_if_setup);
|
||||
if (!ndev)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
sdata = IEEE802154_DEV_TO_SUB_IF(dev);
|
||||
sdata->type = IEEE802154_DEV_MONITOR;
|
||||
ndev->needed_headroom = local->hw.extra_tx_headroom;
|
||||
|
||||
sdata->promisuous_mode = true;
|
||||
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);
|
||||
|
||||
if (new_wpan_dev)
|
||||
*new_wpan_dev = &sdata->wpan_dev;
|
||||
|
||||
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);
|
||||
|
||||
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, ¶ms, 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))
|
||||
|
|
Loading…
Reference in a new issue