mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-09-18 22:14:16 +00:00
Merge branch 'for-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next
Johan Hedberg says: ==================== pull request: bluetooth-next 2016-04-26 Here's another set of Bluetooth & 802.15.4 patches for the 4.7 kernel: - Cleanups & refactoring of ieee802154 & 6lowpan code - Security related additions to ieee802154 and mrf24j40 driver - Memory corruption fix to Bluetooth 6lowpan code - Race condition fix in vhci driver - Enhancements to the atusb 802.15.4 driver Please let me know if there are any issues pulling. Thanks. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
c0b0479307
19 changed files with 356 additions and 167 deletions
|
@ -206,7 +206,8 @@ static int ath3k_load_firmware(struct usb_device *udev,
|
||||||
const struct firmware *firmware)
|
const struct firmware *firmware)
|
||||||
{
|
{
|
||||||
u8 *send_buf;
|
u8 *send_buf;
|
||||||
int err, pipe, len, size, sent = 0;
|
int len = 0;
|
||||||
|
int err, pipe, size, sent = 0;
|
||||||
int count = firmware->size;
|
int count = firmware->size;
|
||||||
|
|
||||||
BT_DBG("udev %p", udev);
|
BT_DBG("udev %p", udev);
|
||||||
|
@ -302,7 +303,8 @@ static int ath3k_load_fwfile(struct usb_device *udev,
|
||||||
const struct firmware *firmware)
|
const struct firmware *firmware)
|
||||||
{
|
{
|
||||||
u8 *send_buf;
|
u8 *send_buf;
|
||||||
int err, pipe, len, size, count, sent = 0;
|
int len = 0;
|
||||||
|
int err, pipe, size, count, sent = 0;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
count = firmware->size;
|
count = firmware->size;
|
||||||
|
|
|
@ -50,6 +50,7 @@ struct vhci_data {
|
||||||
wait_queue_head_t read_wait;
|
wait_queue_head_t read_wait;
|
||||||
struct sk_buff_head readq;
|
struct sk_buff_head readq;
|
||||||
|
|
||||||
|
struct mutex open_mutex;
|
||||||
struct delayed_work open_timeout;
|
struct delayed_work open_timeout;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -87,12 +88,15 @@ static int vhci_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int vhci_create_device(struct vhci_data *data, __u8 opcode)
|
static int __vhci_create_device(struct vhci_data *data, __u8 opcode)
|
||||||
{
|
{
|
||||||
struct hci_dev *hdev;
|
struct hci_dev *hdev;
|
||||||
struct sk_buff *skb;
|
struct sk_buff *skb;
|
||||||
__u8 dev_type;
|
__u8 dev_type;
|
||||||
|
|
||||||
|
if (data->hdev)
|
||||||
|
return -EBADFD;
|
||||||
|
|
||||||
/* bits 0-1 are dev_type (BR/EDR or AMP) */
|
/* bits 0-1 are dev_type (BR/EDR or AMP) */
|
||||||
dev_type = opcode & 0x03;
|
dev_type = opcode & 0x03;
|
||||||
|
|
||||||
|
@ -151,6 +155,17 @@ static int vhci_create_device(struct vhci_data *data, __u8 opcode)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int vhci_create_device(struct vhci_data *data, __u8 opcode)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
|
mutex_lock(&data->open_mutex);
|
||||||
|
err = __vhci_create_device(data, opcode);
|
||||||
|
mutex_unlock(&data->open_mutex);
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
static inline ssize_t vhci_get_user(struct vhci_data *data,
|
static inline ssize_t vhci_get_user(struct vhci_data *data,
|
||||||
struct iov_iter *from)
|
struct iov_iter *from)
|
||||||
{
|
{
|
||||||
|
@ -191,11 +206,6 @@ static inline ssize_t vhci_get_user(struct vhci_data *data,
|
||||||
case HCI_VENDOR_PKT:
|
case HCI_VENDOR_PKT:
|
||||||
cancel_delayed_work_sync(&data->open_timeout);
|
cancel_delayed_work_sync(&data->open_timeout);
|
||||||
|
|
||||||
if (data->hdev) {
|
|
||||||
kfree_skb(skb);
|
|
||||||
return -EBADFD;
|
|
||||||
}
|
|
||||||
|
|
||||||
opcode = *((__u8 *) skb->data);
|
opcode = *((__u8 *) skb->data);
|
||||||
skb_pull(skb, 1);
|
skb_pull(skb, 1);
|
||||||
|
|
||||||
|
@ -320,6 +330,7 @@ static int vhci_open(struct inode *inode, struct file *file)
|
||||||
skb_queue_head_init(&data->readq);
|
skb_queue_head_init(&data->readq);
|
||||||
init_waitqueue_head(&data->read_wait);
|
init_waitqueue_head(&data->read_wait);
|
||||||
|
|
||||||
|
mutex_init(&data->open_mutex);
|
||||||
INIT_DELAYED_WORK(&data->open_timeout, vhci_open_timeout);
|
INIT_DELAYED_WORK(&data->open_timeout, vhci_open_timeout);
|
||||||
|
|
||||||
file->private_data = data;
|
file->private_data = data;
|
||||||
|
|
|
@ -1340,7 +1340,7 @@ static struct at86rf2xx_chip_data at86rf233_data = {
|
||||||
.t_off_to_aack = 80,
|
.t_off_to_aack = 80,
|
||||||
.t_off_to_tx_on = 80,
|
.t_off_to_tx_on = 80,
|
||||||
.t_off_to_sleep = 35,
|
.t_off_to_sleep = 35,
|
||||||
.t_sleep_to_off = 210,
|
.t_sleep_to_off = 1000,
|
||||||
.t_frame = 4096,
|
.t_frame = 4096,
|
||||||
.t_p_ack = 545,
|
.t_p_ack = 545,
|
||||||
.rssi_base_val = -91,
|
.rssi_base_val = -91,
|
||||||
|
@ -1355,7 +1355,7 @@ static struct at86rf2xx_chip_data at86rf231_data = {
|
||||||
.t_off_to_aack = 110,
|
.t_off_to_aack = 110,
|
||||||
.t_off_to_tx_on = 110,
|
.t_off_to_tx_on = 110,
|
||||||
.t_off_to_sleep = 35,
|
.t_off_to_sleep = 35,
|
||||||
.t_sleep_to_off = 380,
|
.t_sleep_to_off = 1000,
|
||||||
.t_frame = 4096,
|
.t_frame = 4096,
|
||||||
.t_p_ack = 545,
|
.t_p_ack = 545,
|
||||||
.rssi_base_val = -91,
|
.rssi_base_val = -91,
|
||||||
|
@ -1370,7 +1370,7 @@ static struct at86rf2xx_chip_data at86rf212_data = {
|
||||||
.t_off_to_aack = 200,
|
.t_off_to_aack = 200,
|
||||||
.t_off_to_tx_on = 200,
|
.t_off_to_tx_on = 200,
|
||||||
.t_off_to_sleep = 35,
|
.t_off_to_sleep = 35,
|
||||||
.t_sleep_to_off = 380,
|
.t_sleep_to_off = 1000,
|
||||||
.t_frame = 4096,
|
.t_frame = 4096,
|
||||||
.t_p_ack = 545,
|
.t_p_ack = 545,
|
||||||
.rssi_base_val = -100,
|
.rssi_base_val = -100,
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
*
|
*
|
||||||
* Written 2013 by Werner Almesberger <werner@almesberger.net>
|
* Written 2013 by Werner Almesberger <werner@almesberger.net>
|
||||||
*
|
*
|
||||||
|
* Copyright (c) 2015 - 2016 Stefan Schmidt <stefan@datenfreihafen.org>
|
||||||
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License as
|
* modify it under the terms of the GNU General Public License as
|
||||||
* published by the Free Software Foundation, version 2
|
* published by the Free Software Foundation, version 2
|
||||||
|
@ -472,6 +474,76 @@ atusb_set_txpower(struct ieee802154_hw *hw, s32 mbm)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define ATUSB_MAX_ED_LEVELS 0xF
|
||||||
|
static const s32 atusb_ed_levels[ATUSB_MAX_ED_LEVELS + 1] = {
|
||||||
|
-9100, -8900, -8700, -8500, -8300, -8100, -7900, -7700, -7500, -7300,
|
||||||
|
-7100, -6900, -6700, -6500, -6300, -6100,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int
|
||||||
|
atusb_set_cca_mode(struct ieee802154_hw *hw, const struct wpan_phy_cca *cca)
|
||||||
|
{
|
||||||
|
struct atusb *atusb = hw->priv;
|
||||||
|
u8 val;
|
||||||
|
|
||||||
|
/* mapping 802.15.4 to driver spec */
|
||||||
|
switch (cca->mode) {
|
||||||
|
case NL802154_CCA_ENERGY:
|
||||||
|
val = 1;
|
||||||
|
break;
|
||||||
|
case NL802154_CCA_CARRIER:
|
||||||
|
val = 2;
|
||||||
|
break;
|
||||||
|
case NL802154_CCA_ENERGY_CARRIER:
|
||||||
|
switch (cca->opt) {
|
||||||
|
case NL802154_CCA_OPT_ENERGY_CARRIER_AND:
|
||||||
|
val = 3;
|
||||||
|
break;
|
||||||
|
case NL802154_CCA_OPT_ENERGY_CARRIER_OR:
|
||||||
|
val = 0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return atusb_write_subreg(atusb, SR_CCA_MODE, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
atusb_set_cca_ed_level(struct ieee802154_hw *hw, s32 mbm)
|
||||||
|
{
|
||||||
|
struct atusb *atusb = hw->priv;
|
||||||
|
u32 i;
|
||||||
|
|
||||||
|
for (i = 0; i < hw->phy->supported.cca_ed_levels_size; i++) {
|
||||||
|
if (hw->phy->supported.cca_ed_levels[i] == mbm)
|
||||||
|
return atusb_write_subreg(atusb, SR_CCA_ED_THRES, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
atusb_set_csma_params(struct ieee802154_hw *hw, u8 min_be, u8 max_be, u8 retries)
|
||||||
|
{
|
||||||
|
struct atusb *atusb = hw->priv;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = atusb_write_subreg(atusb, SR_MIN_BE, min_be);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = atusb_write_subreg(atusb, SR_MAX_BE, max_be);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
return atusb_write_subreg(atusb, SR_MAX_CSMA_RETRIES, retries);
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
atusb_set_promiscuous_mode(struct ieee802154_hw *hw, const bool on)
|
atusb_set_promiscuous_mode(struct ieee802154_hw *hw, const bool on)
|
||||||
{
|
{
|
||||||
|
@ -508,6 +580,9 @@ static struct ieee802154_ops atusb_ops = {
|
||||||
.stop = atusb_stop,
|
.stop = atusb_stop,
|
||||||
.set_hw_addr_filt = atusb_set_hw_addr_filt,
|
.set_hw_addr_filt = atusb_set_hw_addr_filt,
|
||||||
.set_txpower = atusb_set_txpower,
|
.set_txpower = atusb_set_txpower,
|
||||||
|
.set_cca_mode = atusb_set_cca_mode,
|
||||||
|
.set_cca_ed_level = atusb_set_cca_ed_level,
|
||||||
|
.set_csma_params = atusb_set_csma_params,
|
||||||
.set_promiscuous_mode = atusb_set_promiscuous_mode,
|
.set_promiscuous_mode = atusb_set_promiscuous_mode,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -636,9 +711,20 @@ static int atusb_probe(struct usb_interface *interface,
|
||||||
|
|
||||||
hw->parent = &usb_dev->dev;
|
hw->parent = &usb_dev->dev;
|
||||||
hw->flags = IEEE802154_HW_TX_OMIT_CKSUM | IEEE802154_HW_AFILT |
|
hw->flags = IEEE802154_HW_TX_OMIT_CKSUM | IEEE802154_HW_AFILT |
|
||||||
IEEE802154_HW_PROMISCUOUS;
|
IEEE802154_HW_PROMISCUOUS | IEEE802154_HW_CSMA_PARAMS;
|
||||||
|
|
||||||
hw->phy->flags = WPAN_PHY_FLAG_TXPOWER;
|
hw->phy->flags = WPAN_PHY_FLAG_TXPOWER | WPAN_PHY_FLAG_CCA_ED_LEVEL |
|
||||||
|
WPAN_PHY_FLAG_CCA_MODE;
|
||||||
|
|
||||||
|
hw->phy->supported.cca_modes = BIT(NL802154_CCA_ENERGY) |
|
||||||
|
BIT(NL802154_CCA_CARRIER) | BIT(NL802154_CCA_ENERGY_CARRIER);
|
||||||
|
hw->phy->supported.cca_opts = BIT(NL802154_CCA_OPT_ENERGY_CARRIER_AND) |
|
||||||
|
BIT(NL802154_CCA_OPT_ENERGY_CARRIER_OR);
|
||||||
|
|
||||||
|
hw->phy->supported.cca_ed_levels = atusb_ed_levels;
|
||||||
|
hw->phy->supported.cca_ed_levels_size = ARRAY_SIZE(atusb_ed_levels);
|
||||||
|
|
||||||
|
hw->phy->cca.mode = NL802154_CCA_ENERGY;
|
||||||
|
|
||||||
hw->phy->current_page = 0;
|
hw->phy->current_page = 0;
|
||||||
hw->phy->current_channel = 11; /* reset default */
|
hw->phy->current_channel = 11; /* reset default */
|
||||||
|
@ -647,6 +733,7 @@ static int atusb_probe(struct usb_interface *interface,
|
||||||
hw->phy->supported.tx_powers_size = ARRAY_SIZE(atusb_powers);
|
hw->phy->supported.tx_powers_size = ARRAY_SIZE(atusb_powers);
|
||||||
hw->phy->transmit_power = hw->phy->supported.tx_powers[0];
|
hw->phy->transmit_power = hw->phy->supported.tx_powers[0];
|
||||||
ieee802154_random_extended_addr(&hw->phy->perm_extended_addr);
|
ieee802154_random_extended_addr(&hw->phy->perm_extended_addr);
|
||||||
|
hw->phy->cca_ed_level = hw->phy->supported.cca_ed_levels[7];
|
||||||
|
|
||||||
atusb_command(atusb, ATUSB_RF_RESET, 0);
|
atusb_command(atusb, ATUSB_RF_RESET, 0);
|
||||||
atusb_get_and_show_chip(atusb);
|
atusb_get_and_show_chip(atusb);
|
||||||
|
|
|
@ -61,6 +61,7 @@
|
||||||
#define REG_TXBCON0 0x1A
|
#define REG_TXBCON0 0x1A
|
||||||
#define REG_TXNCON 0x1B /* Transmit Normal FIFO Control */
|
#define REG_TXNCON 0x1B /* Transmit Normal FIFO Control */
|
||||||
#define BIT_TXNTRIG BIT(0)
|
#define BIT_TXNTRIG BIT(0)
|
||||||
|
#define BIT_TXNSECEN BIT(1)
|
||||||
#define BIT_TXNACKREQ BIT(2)
|
#define BIT_TXNACKREQ BIT(2)
|
||||||
|
|
||||||
#define REG_TXG1CON 0x1C
|
#define REG_TXG1CON 0x1C
|
||||||
|
@ -85,10 +86,13 @@
|
||||||
#define REG_INTSTAT 0x31 /* Interrupt Status */
|
#define REG_INTSTAT 0x31 /* Interrupt Status */
|
||||||
#define BIT_TXNIF BIT(0)
|
#define BIT_TXNIF BIT(0)
|
||||||
#define BIT_RXIF BIT(3)
|
#define BIT_RXIF BIT(3)
|
||||||
|
#define BIT_SECIF BIT(4)
|
||||||
|
#define BIT_SECIGNORE BIT(7)
|
||||||
|
|
||||||
#define REG_INTCON 0x32 /* Interrupt Control */
|
#define REG_INTCON 0x32 /* Interrupt Control */
|
||||||
#define BIT_TXNIE BIT(0)
|
#define BIT_TXNIE BIT(0)
|
||||||
#define BIT_RXIE BIT(3)
|
#define BIT_RXIE BIT(3)
|
||||||
|
#define BIT_SECIE BIT(4)
|
||||||
|
|
||||||
#define REG_GPIO 0x33 /* GPIO */
|
#define REG_GPIO 0x33 /* GPIO */
|
||||||
#define REG_TRISGPIO 0x34 /* GPIO direction */
|
#define REG_TRISGPIO 0x34 /* GPIO direction */
|
||||||
|
@ -548,6 +552,9 @@ static void write_tx_buf_complete(void *context)
|
||||||
u8 val = BIT_TXNTRIG;
|
u8 val = BIT_TXNTRIG;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
if (ieee802154_is_secen(fc))
|
||||||
|
val |= BIT_TXNSECEN;
|
||||||
|
|
||||||
if (ieee802154_is_ackreq(fc))
|
if (ieee802154_is_ackreq(fc))
|
||||||
val |= BIT_TXNACKREQ;
|
val |= BIT_TXNACKREQ;
|
||||||
|
|
||||||
|
@ -616,7 +623,7 @@ static int mrf24j40_start(struct ieee802154_hw *hw)
|
||||||
|
|
||||||
/* Clear TXNIE and RXIE. Enable interrupts */
|
/* Clear TXNIE and RXIE. Enable interrupts */
|
||||||
return regmap_update_bits(devrec->regmap_short, REG_INTCON,
|
return regmap_update_bits(devrec->regmap_short, REG_INTCON,
|
||||||
BIT_TXNIE | BIT_RXIE, 0);
|
BIT_TXNIE | BIT_RXIE | BIT_SECIE, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mrf24j40_stop(struct ieee802154_hw *hw)
|
static void mrf24j40_stop(struct ieee802154_hw *hw)
|
||||||
|
@ -1025,6 +1032,11 @@ static void mrf24j40_intstat_complete(void *context)
|
||||||
|
|
||||||
enable_irq(devrec->spi->irq);
|
enable_irq(devrec->spi->irq);
|
||||||
|
|
||||||
|
/* Ignore Rx security decryption */
|
||||||
|
if (intstat & BIT_SECIF)
|
||||||
|
regmap_write_async(devrec->regmap_short, REG_SECCON0,
|
||||||
|
BIT_SECIGNORE);
|
||||||
|
|
||||||
/* Check for TX complete */
|
/* Check for TX complete */
|
||||||
if (intstat & BIT_TXNIF)
|
if (intstat & BIT_TXNIF)
|
||||||
ieee802154_xmit_complete(devrec->hw, devrec->tx_skb, false);
|
ieee802154_xmit_complete(devrec->hw, devrec->tx_skb, false);
|
||||||
|
|
|
@ -47,6 +47,7 @@
|
||||||
#define IEEE802154_ADDR_SHORT_UNSPEC 0xfffe
|
#define IEEE802154_ADDR_SHORT_UNSPEC 0xfffe
|
||||||
|
|
||||||
#define IEEE802154_EXTENDED_ADDR_LEN 8
|
#define IEEE802154_EXTENDED_ADDR_LEN 8
|
||||||
|
#define IEEE802154_SHORT_ADDR_LEN 2
|
||||||
|
|
||||||
#define IEEE802154_LIFS_PERIOD 40
|
#define IEEE802154_LIFS_PERIOD 40
|
||||||
#define IEEE802154_SIFS_PERIOD 12
|
#define IEEE802154_SIFS_PERIOD 12
|
||||||
|
@ -218,6 +219,7 @@ enum {
|
||||||
/* frame control handling */
|
/* frame control handling */
|
||||||
#define IEEE802154_FCTL_FTYPE 0x0003
|
#define IEEE802154_FCTL_FTYPE 0x0003
|
||||||
#define IEEE802154_FCTL_ACKREQ 0x0020
|
#define IEEE802154_FCTL_ACKREQ 0x0020
|
||||||
|
#define IEEE802154_FCTL_SECEN 0x0004
|
||||||
#define IEEE802154_FCTL_INTRA_PAN 0x0040
|
#define IEEE802154_FCTL_INTRA_PAN 0x0040
|
||||||
|
|
||||||
#define IEEE802154_FTYPE_DATA 0x0001
|
#define IEEE802154_FTYPE_DATA 0x0001
|
||||||
|
@ -232,6 +234,15 @@ static inline int ieee802154_is_data(__le16 fc)
|
||||||
cpu_to_le16(IEEE802154_FTYPE_DATA);
|
cpu_to_le16(IEEE802154_FTYPE_DATA);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ieee802154_is_secen - check if Security bit is set
|
||||||
|
* @fc: frame control bytes in little-endian byteorder
|
||||||
|
*/
|
||||||
|
static inline bool ieee802154_is_secen(__le16 fc)
|
||||||
|
{
|
||||||
|
return fc & cpu_to_le16(IEEE802154_FCTL_SECEN);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ieee802154_is_ackreq - check if acknowledgment request bit is set
|
* ieee802154_is_ackreq - check if acknowledgment request bit is set
|
||||||
* @fc: frame control bytes in little-endian byteorder
|
* @fc: frame control bytes in little-endian byteorder
|
||||||
|
@ -260,17 +271,17 @@ static inline bool ieee802154_is_intra_pan(__le16 fc)
|
||||||
*
|
*
|
||||||
* @len: psdu len with (MHR + payload + MFR)
|
* @len: psdu len with (MHR + payload + MFR)
|
||||||
*/
|
*/
|
||||||
static inline bool ieee802154_is_valid_psdu_len(const u8 len)
|
static inline bool ieee802154_is_valid_psdu_len(u8 len)
|
||||||
{
|
{
|
||||||
return (len == IEEE802154_ACK_PSDU_LEN ||
|
return (len == IEEE802154_ACK_PSDU_LEN ||
|
||||||
(len >= IEEE802154_MIN_PSDU_LEN && len <= IEEE802154_MTU));
|
(len >= IEEE802154_MIN_PSDU_LEN && len <= IEEE802154_MTU));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ieee802154_is_valid_psdu_len - check if extended addr is valid
|
* ieee802154_is_valid_extended_unicast_addr - check if extended addr is valid
|
||||||
* @addr: extended addr to check
|
* @addr: extended addr to check
|
||||||
*/
|
*/
|
||||||
static inline bool ieee802154_is_valid_extended_unicast_addr(const __le64 addr)
|
static inline bool ieee802154_is_valid_extended_unicast_addr(__le64 addr)
|
||||||
{
|
{
|
||||||
/* Bail out if the address is all zero, or if the group
|
/* Bail out if the address is all zero, or if the group
|
||||||
* address bit is set.
|
* address bit is set.
|
||||||
|
@ -279,6 +290,34 @@ static inline bool ieee802154_is_valid_extended_unicast_addr(const __le64 addr)
|
||||||
!(addr & cpu_to_le64(0x0100000000000000ULL)));
|
!(addr & cpu_to_le64(0x0100000000000000ULL)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ieee802154_is_broadcast_short_addr - check if short addr is broadcast
|
||||||
|
* @addr: short addr to check
|
||||||
|
*/
|
||||||
|
static inline bool ieee802154_is_broadcast_short_addr(__le16 addr)
|
||||||
|
{
|
||||||
|
return (addr == cpu_to_le16(IEEE802154_ADDR_SHORT_BROADCAST));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ieee802154_is_unspec_short_addr - check if short addr is unspecified
|
||||||
|
* @addr: short addr to check
|
||||||
|
*/
|
||||||
|
static inline bool ieee802154_is_unspec_short_addr(__le16 addr)
|
||||||
|
{
|
||||||
|
return (addr == cpu_to_le16(IEEE802154_ADDR_SHORT_UNSPEC));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ieee802154_is_valid_src_short_addr - check if source short address is valid
|
||||||
|
* @addr: short addr to check
|
||||||
|
*/
|
||||||
|
static inline bool ieee802154_is_valid_src_short_addr(__le16 addr)
|
||||||
|
{
|
||||||
|
return !(ieee802154_is_broadcast_short_addr(addr) ||
|
||||||
|
ieee802154_is_unspec_short_addr(addr));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ieee802154_random_extended_addr - generates a random extended address
|
* ieee802154_random_extended_addr - generates a random extended address
|
||||||
* @addr: extended addr pointer to place the random address
|
* @addr: extended addr pointer to place the random address
|
||||||
|
|
|
@ -58,6 +58,9 @@
|
||||||
#include <net/ipv6.h>
|
#include <net/ipv6.h>
|
||||||
#include <net/net_namespace.h>
|
#include <net/net_namespace.h>
|
||||||
|
|
||||||
|
/* special link-layer handling */
|
||||||
|
#include <net/mac802154.h>
|
||||||
|
|
||||||
#define EUI64_ADDR_LEN 8
|
#define EUI64_ADDR_LEN 8
|
||||||
|
|
||||||
#define LOWPAN_NHC_MAX_ID_LEN 1
|
#define LOWPAN_NHC_MAX_ID_LEN 1
|
||||||
|
@ -93,7 +96,7 @@ static inline bool lowpan_is_iphc(u8 dispatch)
|
||||||
}
|
}
|
||||||
|
|
||||||
#define LOWPAN_PRIV_SIZE(llpriv_size) \
|
#define LOWPAN_PRIV_SIZE(llpriv_size) \
|
||||||
(sizeof(struct lowpan_priv) + llpriv_size)
|
(sizeof(struct lowpan_dev) + llpriv_size)
|
||||||
|
|
||||||
enum lowpan_lltypes {
|
enum lowpan_lltypes {
|
||||||
LOWPAN_LLTYPE_BTLE,
|
LOWPAN_LLTYPE_BTLE,
|
||||||
|
@ -129,7 +132,7 @@ lowpan_iphc_ctx_is_compression(const struct lowpan_iphc_ctx *ctx)
|
||||||
return test_bit(LOWPAN_IPHC_CTX_FLAG_COMPRESSION, &ctx->flags);
|
return test_bit(LOWPAN_IPHC_CTX_FLAG_COMPRESSION, &ctx->flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct lowpan_priv {
|
struct lowpan_dev {
|
||||||
enum lowpan_lltypes lltype;
|
enum lowpan_lltypes lltype;
|
||||||
struct dentry *iface_debugfs;
|
struct dentry *iface_debugfs;
|
||||||
struct lowpan_iphc_ctx_table ctx;
|
struct lowpan_iphc_ctx_table ctx;
|
||||||
|
@ -139,11 +142,23 @@ struct lowpan_priv {
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline
|
static inline
|
||||||
struct lowpan_priv *lowpan_priv(const struct net_device *dev)
|
struct lowpan_dev *lowpan_dev(const struct net_device *dev)
|
||||||
{
|
{
|
||||||
return netdev_priv(dev);
|
return netdev_priv(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* private device info */
|
||||||
|
struct lowpan_802154_dev {
|
||||||
|
struct net_device *wdev; /* wpan device ptr */
|
||||||
|
u16 fragment_tag;
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline struct
|
||||||
|
lowpan_802154_dev *lowpan_802154_dev(const struct net_device *dev)
|
||||||
|
{
|
||||||
|
return (struct lowpan_802154_dev *)lowpan_dev(dev)->priv;
|
||||||
|
}
|
||||||
|
|
||||||
struct lowpan_802154_cb {
|
struct lowpan_802154_cb {
|
||||||
u16 d_tag;
|
u16 d_tag;
|
||||||
unsigned int d_size;
|
unsigned int d_size;
|
||||||
|
@ -157,6 +172,22 @@ struct lowpan_802154_cb *lowpan_802154_cb(const struct sk_buff *skb)
|
||||||
return (struct lowpan_802154_cb *)skb->cb;
|
return (struct lowpan_802154_cb *)skb->cb;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void lowpan_iphc_uncompress_eui64_lladdr(struct in6_addr *ipaddr,
|
||||||
|
const void *lladdr)
|
||||||
|
{
|
||||||
|
/* fe:80::XXXX:XXXX:XXXX:XXXX
|
||||||
|
* \_________________/
|
||||||
|
* hwaddr
|
||||||
|
*/
|
||||||
|
ipaddr->s6_addr[0] = 0xFE;
|
||||||
|
ipaddr->s6_addr[1] = 0x80;
|
||||||
|
memcpy(&ipaddr->s6_addr[8], lladdr, EUI64_ADDR_LEN);
|
||||||
|
/* second bit-flip (Universe/Local)
|
||||||
|
* is done according RFC2464
|
||||||
|
*/
|
||||||
|
ipaddr->s6_addr[8] ^= 0x02;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
/* print data in line */
|
/* print data in line */
|
||||||
static inline void raw_dump_inline(const char *caller, char *msg,
|
static inline void raw_dump_inline(const char *caller, char *msg,
|
||||||
|
|
|
@ -61,6 +61,8 @@
|
||||||
#define HCI_RS232 4
|
#define HCI_RS232 4
|
||||||
#define HCI_PCI 5
|
#define HCI_PCI 5
|
||||||
#define HCI_SDIO 6
|
#define HCI_SDIO 6
|
||||||
|
#define HCI_SPI 7
|
||||||
|
#define HCI_I2C 8
|
||||||
|
|
||||||
/* HCI controller types */
|
/* HCI controller types */
|
||||||
#define HCI_BREDR 0x00
|
#define HCI_BREDR 0x00
|
||||||
|
|
|
@ -287,6 +287,16 @@ static inline void ieee802154_le16_to_be16(void *be16_dst, const void *le16_src)
|
||||||
put_unaligned_be16(get_unaligned_le16(le16_src), be16_dst);
|
put_unaligned_be16(get_unaligned_le16(le16_src), be16_dst);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ieee802154_be16_to_le16 - copies and convert be16 to le16
|
||||||
|
* @le16_dst: le16 destination pointer
|
||||||
|
* @be16_src: be16 source pointer
|
||||||
|
*/
|
||||||
|
static inline void ieee802154_be16_to_le16(void *le16_dst, const void *be16_src)
|
||||||
|
{
|
||||||
|
put_unaligned_le16(get_unaligned_be16(be16_src), le16_dst);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ieee802154_alloc_hw - Allocate a new hardware device
|
* ieee802154_alloc_hw - Allocate a new hardware device
|
||||||
*
|
*
|
||||||
|
|
|
@ -3,6 +3,15 @@
|
||||||
|
|
||||||
#include <linux/netdevice.h>
|
#include <linux/netdevice.h>
|
||||||
|
|
||||||
|
#include <net/6lowpan.h>
|
||||||
|
|
||||||
|
/* caller need to be sure it's dev->type is ARPHRD_6LOWPAN */
|
||||||
|
static inline bool lowpan_is_ll(const struct net_device *dev,
|
||||||
|
enum lowpan_lltypes lltype)
|
||||||
|
{
|
||||||
|
return lowpan_dev(dev)->lltype == lltype;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_6LOWPAN_DEBUGFS
|
#ifdef CONFIG_6LOWPAN_DEBUGFS
|
||||||
int lowpan_dev_debugfs_init(struct net_device *dev);
|
int lowpan_dev_debugfs_init(struct net_device *dev);
|
||||||
void lowpan_dev_debugfs_exit(struct net_device *dev);
|
void lowpan_dev_debugfs_exit(struct net_device *dev);
|
||||||
|
|
|
@ -27,11 +27,11 @@ int lowpan_register_netdevice(struct net_device *dev,
|
||||||
dev->mtu = IPV6_MIN_MTU;
|
dev->mtu = IPV6_MIN_MTU;
|
||||||
dev->priv_flags |= IFF_NO_QUEUE;
|
dev->priv_flags |= IFF_NO_QUEUE;
|
||||||
|
|
||||||
lowpan_priv(dev)->lltype = lltype;
|
lowpan_dev(dev)->lltype = lltype;
|
||||||
|
|
||||||
spin_lock_init(&lowpan_priv(dev)->ctx.lock);
|
spin_lock_init(&lowpan_dev(dev)->ctx.lock);
|
||||||
for (i = 0; i < LOWPAN_IPHC_CTX_TABLE_SIZE; i++)
|
for (i = 0; i < LOWPAN_IPHC_CTX_TABLE_SIZE; i++)
|
||||||
lowpan_priv(dev)->ctx.table[i].id = i;
|
lowpan_dev(dev)->ctx.table[i].id = i;
|
||||||
|
|
||||||
ret = register_netdevice(dev);
|
ret = register_netdevice(dev);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
|
@ -85,7 +85,7 @@ static int lowpan_event(struct notifier_block *unused,
|
||||||
case NETDEV_DOWN:
|
case NETDEV_DOWN:
|
||||||
for (i = 0; i < LOWPAN_IPHC_CTX_TABLE_SIZE; i++)
|
for (i = 0; i < LOWPAN_IPHC_CTX_TABLE_SIZE; i++)
|
||||||
clear_bit(LOWPAN_IPHC_CTX_FLAG_ACTIVE,
|
clear_bit(LOWPAN_IPHC_CTX_FLAG_ACTIVE,
|
||||||
&lowpan_priv(dev)->ctx.table[i].flags);
|
&lowpan_dev(dev)->ctx.table[i].flags);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return NOTIFY_DONE;
|
return NOTIFY_DONE;
|
||||||
|
|
|
@ -172,7 +172,7 @@ static const struct file_operations lowpan_ctx_pfx_fops = {
|
||||||
static int lowpan_dev_debugfs_ctx_init(struct net_device *dev,
|
static int lowpan_dev_debugfs_ctx_init(struct net_device *dev,
|
||||||
struct dentry *ctx, u8 id)
|
struct dentry *ctx, u8 id)
|
||||||
{
|
{
|
||||||
struct lowpan_priv *lpriv = lowpan_priv(dev);
|
struct lowpan_dev *ldev = lowpan_dev(dev);
|
||||||
struct dentry *dentry, *root;
|
struct dentry *dentry, *root;
|
||||||
char buf[32];
|
char buf[32];
|
||||||
|
|
||||||
|
@ -185,25 +185,25 @@ static int lowpan_dev_debugfs_ctx_init(struct net_device *dev,
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
dentry = debugfs_create_file("active", 0644, root,
|
dentry = debugfs_create_file("active", 0644, root,
|
||||||
&lpriv->ctx.table[id],
|
&ldev->ctx.table[id],
|
||||||
&lowpan_ctx_flag_active_fops);
|
&lowpan_ctx_flag_active_fops);
|
||||||
if (!dentry)
|
if (!dentry)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
dentry = debugfs_create_file("compression", 0644, root,
|
dentry = debugfs_create_file("compression", 0644, root,
|
||||||
&lpriv->ctx.table[id],
|
&ldev->ctx.table[id],
|
||||||
&lowpan_ctx_flag_c_fops);
|
&lowpan_ctx_flag_c_fops);
|
||||||
if (!dentry)
|
if (!dentry)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
dentry = debugfs_create_file("prefix", 0644, root,
|
dentry = debugfs_create_file("prefix", 0644, root,
|
||||||
&lpriv->ctx.table[id],
|
&ldev->ctx.table[id],
|
||||||
&lowpan_ctx_pfx_fops);
|
&lowpan_ctx_pfx_fops);
|
||||||
if (!dentry)
|
if (!dentry)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
dentry = debugfs_create_file("prefix_len", 0644, root,
|
dentry = debugfs_create_file("prefix_len", 0644, root,
|
||||||
&lpriv->ctx.table[id],
|
&ldev->ctx.table[id],
|
||||||
&lowpan_ctx_plen_fops);
|
&lowpan_ctx_plen_fops);
|
||||||
if (!dentry)
|
if (!dentry)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -247,21 +247,21 @@ static const struct file_operations lowpan_context_fops = {
|
||||||
|
|
||||||
int lowpan_dev_debugfs_init(struct net_device *dev)
|
int lowpan_dev_debugfs_init(struct net_device *dev)
|
||||||
{
|
{
|
||||||
struct lowpan_priv *lpriv = lowpan_priv(dev);
|
struct lowpan_dev *ldev = lowpan_dev(dev);
|
||||||
struct dentry *contexts, *dentry;
|
struct dentry *contexts, *dentry;
|
||||||
int ret, i;
|
int ret, i;
|
||||||
|
|
||||||
/* creating the root */
|
/* creating the root */
|
||||||
lpriv->iface_debugfs = debugfs_create_dir(dev->name, lowpan_debugfs);
|
ldev->iface_debugfs = debugfs_create_dir(dev->name, lowpan_debugfs);
|
||||||
if (!lpriv->iface_debugfs)
|
if (!ldev->iface_debugfs)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
contexts = debugfs_create_dir("contexts", lpriv->iface_debugfs);
|
contexts = debugfs_create_dir("contexts", ldev->iface_debugfs);
|
||||||
if (!contexts)
|
if (!contexts)
|
||||||
goto remove_root;
|
goto remove_root;
|
||||||
|
|
||||||
dentry = debugfs_create_file("show", 0644, contexts,
|
dentry = debugfs_create_file("show", 0644, contexts,
|
||||||
&lowpan_priv(dev)->ctx,
|
&lowpan_dev(dev)->ctx,
|
||||||
&lowpan_context_fops);
|
&lowpan_context_fops);
|
||||||
if (!dentry)
|
if (!dentry)
|
||||||
goto remove_root;
|
goto remove_root;
|
||||||
|
@ -282,7 +282,7 @@ fail:
|
||||||
|
|
||||||
void lowpan_dev_debugfs_exit(struct net_device *dev)
|
void lowpan_dev_debugfs_exit(struct net_device *dev)
|
||||||
{
|
{
|
||||||
debugfs_remove_recursive(lowpan_priv(dev)->iface_debugfs);
|
debugfs_remove_recursive(lowpan_dev(dev)->iface_debugfs);
|
||||||
}
|
}
|
||||||
|
|
||||||
int __init lowpan_debugfs_init(void)
|
int __init lowpan_debugfs_init(void)
|
||||||
|
|
|
@ -53,9 +53,6 @@
|
||||||
#include <net/6lowpan.h>
|
#include <net/6lowpan.h>
|
||||||
#include <net/ipv6.h>
|
#include <net/ipv6.h>
|
||||||
|
|
||||||
/* special link-layer handling */
|
|
||||||
#include <net/mac802154.h>
|
|
||||||
|
|
||||||
#include "6lowpan_i.h"
|
#include "6lowpan_i.h"
|
||||||
#include "nhc.h"
|
#include "nhc.h"
|
||||||
|
|
||||||
|
@ -156,32 +153,17 @@
|
||||||
#define LOWPAN_IPHC_CID_DCI(cid) (cid & 0x0f)
|
#define LOWPAN_IPHC_CID_DCI(cid) (cid & 0x0f)
|
||||||
#define LOWPAN_IPHC_CID_SCI(cid) ((cid & 0xf0) >> 4)
|
#define LOWPAN_IPHC_CID_SCI(cid) ((cid & 0xf0) >> 4)
|
||||||
|
|
||||||
static inline void iphc_uncompress_eui64_lladdr(struct in6_addr *ipaddr,
|
static inline void
|
||||||
const void *lladdr)
|
lowpan_iphc_uncompress_802154_lladdr(struct in6_addr *ipaddr,
|
||||||
{
|
const void *lladdr)
|
||||||
/* fe:80::XXXX:XXXX:XXXX:XXXX
|
|
||||||
* \_________________/
|
|
||||||
* hwaddr
|
|
||||||
*/
|
|
||||||
ipaddr->s6_addr[0] = 0xFE;
|
|
||||||
ipaddr->s6_addr[1] = 0x80;
|
|
||||||
memcpy(&ipaddr->s6_addr[8], lladdr, EUI64_ADDR_LEN);
|
|
||||||
/* second bit-flip (Universe/Local)
|
|
||||||
* is done according RFC2464
|
|
||||||
*/
|
|
||||||
ipaddr->s6_addr[8] ^= 0x02;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void iphc_uncompress_802154_lladdr(struct in6_addr *ipaddr,
|
|
||||||
const void *lladdr)
|
|
||||||
{
|
{
|
||||||
const struct ieee802154_addr *addr = lladdr;
|
const struct ieee802154_addr *addr = lladdr;
|
||||||
u8 eui64[EUI64_ADDR_LEN] = { };
|
u8 eui64[EUI64_ADDR_LEN];
|
||||||
|
|
||||||
switch (addr->mode) {
|
switch (addr->mode) {
|
||||||
case IEEE802154_ADDR_LONG:
|
case IEEE802154_ADDR_LONG:
|
||||||
ieee802154_le64_to_be64(eui64, &addr->extended_addr);
|
ieee802154_le64_to_be64(eui64, &addr->extended_addr);
|
||||||
iphc_uncompress_eui64_lladdr(ipaddr, eui64);
|
lowpan_iphc_uncompress_eui64_lladdr(ipaddr, eui64);
|
||||||
break;
|
break;
|
||||||
case IEEE802154_ADDR_SHORT:
|
case IEEE802154_ADDR_SHORT:
|
||||||
/* fe:80::ff:fe00:XXXX
|
/* fe:80::ff:fe00:XXXX
|
||||||
|
@ -207,7 +189,7 @@ static inline void iphc_uncompress_802154_lladdr(struct in6_addr *ipaddr,
|
||||||
static struct lowpan_iphc_ctx *
|
static struct lowpan_iphc_ctx *
|
||||||
lowpan_iphc_ctx_get_by_id(const struct net_device *dev, u8 id)
|
lowpan_iphc_ctx_get_by_id(const struct net_device *dev, u8 id)
|
||||||
{
|
{
|
||||||
struct lowpan_iphc_ctx *ret = &lowpan_priv(dev)->ctx.table[id];
|
struct lowpan_iphc_ctx *ret = &lowpan_dev(dev)->ctx.table[id];
|
||||||
|
|
||||||
if (!lowpan_iphc_ctx_is_active(ret))
|
if (!lowpan_iphc_ctx_is_active(ret))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -219,7 +201,7 @@ static struct lowpan_iphc_ctx *
|
||||||
lowpan_iphc_ctx_get_by_addr(const struct net_device *dev,
|
lowpan_iphc_ctx_get_by_addr(const struct net_device *dev,
|
||||||
const struct in6_addr *addr)
|
const struct in6_addr *addr)
|
||||||
{
|
{
|
||||||
struct lowpan_iphc_ctx *table = lowpan_priv(dev)->ctx.table;
|
struct lowpan_iphc_ctx *table = lowpan_dev(dev)->ctx.table;
|
||||||
struct lowpan_iphc_ctx *ret = NULL;
|
struct lowpan_iphc_ctx *ret = NULL;
|
||||||
struct in6_addr addr_pfx;
|
struct in6_addr addr_pfx;
|
||||||
u8 addr_plen;
|
u8 addr_plen;
|
||||||
|
@ -263,7 +245,7 @@ static struct lowpan_iphc_ctx *
|
||||||
lowpan_iphc_ctx_get_by_mcast_addr(const struct net_device *dev,
|
lowpan_iphc_ctx_get_by_mcast_addr(const struct net_device *dev,
|
||||||
const struct in6_addr *addr)
|
const struct in6_addr *addr)
|
||||||
{
|
{
|
||||||
struct lowpan_iphc_ctx *table = lowpan_priv(dev)->ctx.table;
|
struct lowpan_iphc_ctx *table = lowpan_dev(dev)->ctx.table;
|
||||||
struct lowpan_iphc_ctx *ret = NULL;
|
struct lowpan_iphc_ctx *ret = NULL;
|
||||||
struct in6_addr addr_mcast, network_pfx = {};
|
struct in6_addr addr_mcast, network_pfx = {};
|
||||||
int i;
|
int i;
|
||||||
|
@ -301,9 +283,10 @@ lowpan_iphc_ctx_get_by_mcast_addr(const struct net_device *dev,
|
||||||
*
|
*
|
||||||
* address_mode is the masked value for sam or dam value
|
* address_mode is the masked value for sam or dam value
|
||||||
*/
|
*/
|
||||||
static int uncompress_addr(struct sk_buff *skb, const struct net_device *dev,
|
static int lowpan_iphc_uncompress_addr(struct sk_buff *skb,
|
||||||
struct in6_addr *ipaddr, u8 address_mode,
|
const struct net_device *dev,
|
||||||
const void *lladdr)
|
struct in6_addr *ipaddr,
|
||||||
|
u8 address_mode, const void *lladdr)
|
||||||
{
|
{
|
||||||
bool fail;
|
bool fail;
|
||||||
|
|
||||||
|
@ -332,12 +315,12 @@ static int uncompress_addr(struct sk_buff *skb, const struct net_device *dev,
|
||||||
case LOWPAN_IPHC_SAM_11:
|
case LOWPAN_IPHC_SAM_11:
|
||||||
case LOWPAN_IPHC_DAM_11:
|
case LOWPAN_IPHC_DAM_11:
|
||||||
fail = false;
|
fail = false;
|
||||||
switch (lowpan_priv(dev)->lltype) {
|
switch (lowpan_dev(dev)->lltype) {
|
||||||
case LOWPAN_LLTYPE_IEEE802154:
|
case LOWPAN_LLTYPE_IEEE802154:
|
||||||
iphc_uncompress_802154_lladdr(ipaddr, lladdr);
|
lowpan_iphc_uncompress_802154_lladdr(ipaddr, lladdr);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
iphc_uncompress_eui64_lladdr(ipaddr, lladdr);
|
lowpan_iphc_uncompress_eui64_lladdr(ipaddr, lladdr);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -360,11 +343,11 @@ static int uncompress_addr(struct sk_buff *skb, const struct net_device *dev,
|
||||||
/* Uncompress address function for source context
|
/* Uncompress address function for source context
|
||||||
* based address(non-multicast).
|
* based address(non-multicast).
|
||||||
*/
|
*/
|
||||||
static int uncompress_ctx_addr(struct sk_buff *skb,
|
static int lowpan_iphc_uncompress_ctx_addr(struct sk_buff *skb,
|
||||||
const struct net_device *dev,
|
const struct net_device *dev,
|
||||||
const struct lowpan_iphc_ctx *ctx,
|
const struct lowpan_iphc_ctx *ctx,
|
||||||
struct in6_addr *ipaddr, u8 address_mode,
|
struct in6_addr *ipaddr,
|
||||||
const void *lladdr)
|
u8 address_mode, const void *lladdr)
|
||||||
{
|
{
|
||||||
bool fail;
|
bool fail;
|
||||||
|
|
||||||
|
@ -393,12 +376,12 @@ static int uncompress_ctx_addr(struct sk_buff *skb,
|
||||||
case LOWPAN_IPHC_SAM_11:
|
case LOWPAN_IPHC_SAM_11:
|
||||||
case LOWPAN_IPHC_DAM_11:
|
case LOWPAN_IPHC_DAM_11:
|
||||||
fail = false;
|
fail = false;
|
||||||
switch (lowpan_priv(dev)->lltype) {
|
switch (lowpan_dev(dev)->lltype) {
|
||||||
case LOWPAN_LLTYPE_IEEE802154:
|
case LOWPAN_LLTYPE_IEEE802154:
|
||||||
iphc_uncompress_802154_lladdr(ipaddr, lladdr);
|
lowpan_iphc_uncompress_802154_lladdr(ipaddr, lladdr);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
iphc_uncompress_eui64_lladdr(ipaddr, lladdr);
|
lowpan_iphc_uncompress_eui64_lladdr(ipaddr, lladdr);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
ipv6_addr_prefix_copy(ipaddr, &ctx->pfx, ctx->plen);
|
ipv6_addr_prefix_copy(ipaddr, &ctx->pfx, ctx->plen);
|
||||||
|
@ -657,22 +640,24 @@ int lowpan_header_decompress(struct sk_buff *skb, const struct net_device *dev,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (iphc1 & LOWPAN_IPHC_SAC) {
|
if (iphc1 & LOWPAN_IPHC_SAC) {
|
||||||
spin_lock_bh(&lowpan_priv(dev)->ctx.lock);
|
spin_lock_bh(&lowpan_dev(dev)->ctx.lock);
|
||||||
ci = lowpan_iphc_ctx_get_by_id(dev, LOWPAN_IPHC_CID_SCI(cid));
|
ci = lowpan_iphc_ctx_get_by_id(dev, LOWPAN_IPHC_CID_SCI(cid));
|
||||||
if (!ci) {
|
if (!ci) {
|
||||||
spin_unlock_bh(&lowpan_priv(dev)->ctx.lock);
|
spin_unlock_bh(&lowpan_dev(dev)->ctx.lock);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
pr_debug("SAC bit is set. Handle context based source address.\n");
|
pr_debug("SAC bit is set. Handle context based source address.\n");
|
||||||
err = uncompress_ctx_addr(skb, dev, ci, &hdr.saddr,
|
err = lowpan_iphc_uncompress_ctx_addr(skb, dev, ci, &hdr.saddr,
|
||||||
iphc1 & LOWPAN_IPHC_SAM_MASK, saddr);
|
iphc1 & LOWPAN_IPHC_SAM_MASK,
|
||||||
spin_unlock_bh(&lowpan_priv(dev)->ctx.lock);
|
saddr);
|
||||||
|
spin_unlock_bh(&lowpan_dev(dev)->ctx.lock);
|
||||||
} else {
|
} else {
|
||||||
/* Source address uncompression */
|
/* Source address uncompression */
|
||||||
pr_debug("source address stateless compression\n");
|
pr_debug("source address stateless compression\n");
|
||||||
err = uncompress_addr(skb, dev, &hdr.saddr,
|
err = lowpan_iphc_uncompress_addr(skb, dev, &hdr.saddr,
|
||||||
iphc1 & LOWPAN_IPHC_SAM_MASK, saddr);
|
iphc1 & LOWPAN_IPHC_SAM_MASK,
|
||||||
|
saddr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check on error of previous branch */
|
/* Check on error of previous branch */
|
||||||
|
@ -681,10 +666,10 @@ int lowpan_header_decompress(struct sk_buff *skb, const struct net_device *dev,
|
||||||
|
|
||||||
switch (iphc1 & (LOWPAN_IPHC_M | LOWPAN_IPHC_DAC)) {
|
switch (iphc1 & (LOWPAN_IPHC_M | LOWPAN_IPHC_DAC)) {
|
||||||
case LOWPAN_IPHC_M | LOWPAN_IPHC_DAC:
|
case LOWPAN_IPHC_M | LOWPAN_IPHC_DAC:
|
||||||
spin_lock_bh(&lowpan_priv(dev)->ctx.lock);
|
spin_lock_bh(&lowpan_dev(dev)->ctx.lock);
|
||||||
ci = lowpan_iphc_ctx_get_by_id(dev, LOWPAN_IPHC_CID_DCI(cid));
|
ci = lowpan_iphc_ctx_get_by_id(dev, LOWPAN_IPHC_CID_DCI(cid));
|
||||||
if (!ci) {
|
if (!ci) {
|
||||||
spin_unlock_bh(&lowpan_priv(dev)->ctx.lock);
|
spin_unlock_bh(&lowpan_dev(dev)->ctx.lock);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -693,7 +678,7 @@ int lowpan_header_decompress(struct sk_buff *skb, const struct net_device *dev,
|
||||||
err = lowpan_uncompress_multicast_ctx_daddr(skb, ci,
|
err = lowpan_uncompress_multicast_ctx_daddr(skb, ci,
|
||||||
&hdr.daddr,
|
&hdr.daddr,
|
||||||
iphc1 & LOWPAN_IPHC_DAM_MASK);
|
iphc1 & LOWPAN_IPHC_DAM_MASK);
|
||||||
spin_unlock_bh(&lowpan_priv(dev)->ctx.lock);
|
spin_unlock_bh(&lowpan_dev(dev)->ctx.lock);
|
||||||
break;
|
break;
|
||||||
case LOWPAN_IPHC_M:
|
case LOWPAN_IPHC_M:
|
||||||
/* multicast */
|
/* multicast */
|
||||||
|
@ -701,22 +686,24 @@ int lowpan_header_decompress(struct sk_buff *skb, const struct net_device *dev,
|
||||||
iphc1 & LOWPAN_IPHC_DAM_MASK);
|
iphc1 & LOWPAN_IPHC_DAM_MASK);
|
||||||
break;
|
break;
|
||||||
case LOWPAN_IPHC_DAC:
|
case LOWPAN_IPHC_DAC:
|
||||||
spin_lock_bh(&lowpan_priv(dev)->ctx.lock);
|
spin_lock_bh(&lowpan_dev(dev)->ctx.lock);
|
||||||
ci = lowpan_iphc_ctx_get_by_id(dev, LOWPAN_IPHC_CID_DCI(cid));
|
ci = lowpan_iphc_ctx_get_by_id(dev, LOWPAN_IPHC_CID_DCI(cid));
|
||||||
if (!ci) {
|
if (!ci) {
|
||||||
spin_unlock_bh(&lowpan_priv(dev)->ctx.lock);
|
spin_unlock_bh(&lowpan_dev(dev)->ctx.lock);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Destination address context based uncompression */
|
/* Destination address context based uncompression */
|
||||||
pr_debug("DAC bit is set. Handle context based destination address.\n");
|
pr_debug("DAC bit is set. Handle context based destination address.\n");
|
||||||
err = uncompress_ctx_addr(skb, dev, ci, &hdr.daddr,
|
err = lowpan_iphc_uncompress_ctx_addr(skb, dev, ci, &hdr.daddr,
|
||||||
iphc1 & LOWPAN_IPHC_DAM_MASK, daddr);
|
iphc1 & LOWPAN_IPHC_DAM_MASK,
|
||||||
spin_unlock_bh(&lowpan_priv(dev)->ctx.lock);
|
daddr);
|
||||||
|
spin_unlock_bh(&lowpan_dev(dev)->ctx.lock);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
err = uncompress_addr(skb, dev, &hdr.daddr,
|
err = lowpan_iphc_uncompress_addr(skb, dev, &hdr.daddr,
|
||||||
iphc1 & LOWPAN_IPHC_DAM_MASK, daddr);
|
iphc1 & LOWPAN_IPHC_DAM_MASK,
|
||||||
|
daddr);
|
||||||
pr_debug("dest: stateless compression mode %d dest %pI6c\n",
|
pr_debug("dest: stateless compression mode %d dest %pI6c\n",
|
||||||
iphc1 & LOWPAN_IPHC_DAM_MASK, &hdr.daddr);
|
iphc1 & LOWPAN_IPHC_DAM_MASK, &hdr.daddr);
|
||||||
break;
|
break;
|
||||||
|
@ -736,7 +723,7 @@ int lowpan_header_decompress(struct sk_buff *skb, const struct net_device *dev,
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (lowpan_priv(dev)->lltype) {
|
switch (lowpan_dev(dev)->lltype) {
|
||||||
case LOWPAN_LLTYPE_IEEE802154:
|
case LOWPAN_LLTYPE_IEEE802154:
|
||||||
if (lowpan_802154_cb(skb)->d_size)
|
if (lowpan_802154_cb(skb)->d_size)
|
||||||
hdr.payload_len = htons(lowpan_802154_cb(skb)->d_size -
|
hdr.payload_len = htons(lowpan_802154_cb(skb)->d_size -
|
||||||
|
@ -1033,7 +1020,7 @@ int lowpan_header_compress(struct sk_buff *skb, const struct net_device *dev,
|
||||||
skb->data, skb->len);
|
skb->data, skb->len);
|
||||||
|
|
||||||
ipv6_daddr_type = ipv6_addr_type(&hdr->daddr);
|
ipv6_daddr_type = ipv6_addr_type(&hdr->daddr);
|
||||||
spin_lock_bh(&lowpan_priv(dev)->ctx.lock);
|
spin_lock_bh(&lowpan_dev(dev)->ctx.lock);
|
||||||
if (ipv6_daddr_type & IPV6_ADDR_MULTICAST)
|
if (ipv6_daddr_type & IPV6_ADDR_MULTICAST)
|
||||||
dci = lowpan_iphc_ctx_get_by_mcast_addr(dev, &hdr->daddr);
|
dci = lowpan_iphc_ctx_get_by_mcast_addr(dev, &hdr->daddr);
|
||||||
else
|
else
|
||||||
|
@ -1042,15 +1029,15 @@ int lowpan_header_compress(struct sk_buff *skb, const struct net_device *dev,
|
||||||
memcpy(&dci_entry, dci, sizeof(*dci));
|
memcpy(&dci_entry, dci, sizeof(*dci));
|
||||||
cid |= dci->id;
|
cid |= dci->id;
|
||||||
}
|
}
|
||||||
spin_unlock_bh(&lowpan_priv(dev)->ctx.lock);
|
spin_unlock_bh(&lowpan_dev(dev)->ctx.lock);
|
||||||
|
|
||||||
spin_lock_bh(&lowpan_priv(dev)->ctx.lock);
|
spin_lock_bh(&lowpan_dev(dev)->ctx.lock);
|
||||||
sci = lowpan_iphc_ctx_get_by_addr(dev, &hdr->saddr);
|
sci = lowpan_iphc_ctx_get_by_addr(dev, &hdr->saddr);
|
||||||
if (sci) {
|
if (sci) {
|
||||||
memcpy(&sci_entry, sci, sizeof(*sci));
|
memcpy(&sci_entry, sci, sizeof(*sci));
|
||||||
cid |= (sci->id << 4);
|
cid |= (sci->id << 4);
|
||||||
}
|
}
|
||||||
spin_unlock_bh(&lowpan_priv(dev)->ctx.lock);
|
spin_unlock_bh(&lowpan_dev(dev)->ctx.lock);
|
||||||
|
|
||||||
/* if cid is zero it will be compressed */
|
/* if cid is zero it will be compressed */
|
||||||
if (cid) {
|
if (cid) {
|
||||||
|
|
|
@ -91,7 +91,7 @@ static int udp_uncompress(struct sk_buff *skb, size_t needed)
|
||||||
* here, we obtain the hint from the remaining size of the
|
* here, we obtain the hint from the remaining size of the
|
||||||
* frame
|
* frame
|
||||||
*/
|
*/
|
||||||
switch (lowpan_priv(skb->dev)->lltype) {
|
switch (lowpan_dev(skb->dev)->lltype) {
|
||||||
case LOWPAN_LLTYPE_IEEE802154:
|
case LOWPAN_LLTYPE_IEEE802154:
|
||||||
if (lowpan_802154_cb(skb)->d_size)
|
if (lowpan_802154_cb(skb)->d_size)
|
||||||
uh.len = htons(lowpan_802154_cb(skb)->d_size -
|
uh.len = htons(lowpan_802154_cb(skb)->d_size -
|
||||||
|
|
|
@ -68,7 +68,7 @@ struct lowpan_peer {
|
||||||
struct in6_addr peer_addr;
|
struct in6_addr peer_addr;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct lowpan_dev {
|
struct lowpan_btle_dev {
|
||||||
struct list_head list;
|
struct list_head list;
|
||||||
|
|
||||||
struct hci_dev *hdev;
|
struct hci_dev *hdev;
|
||||||
|
@ -80,18 +80,21 @@ struct lowpan_dev {
|
||||||
struct delayed_work notify_peers;
|
struct delayed_work notify_peers;
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline struct lowpan_dev *lowpan_dev(const struct net_device *netdev)
|
static inline struct lowpan_btle_dev *
|
||||||
|
lowpan_btle_dev(const struct net_device *netdev)
|
||||||
{
|
{
|
||||||
return (struct lowpan_dev *)lowpan_priv(netdev)->priv;
|
return (struct lowpan_btle_dev *)lowpan_dev(netdev)->priv;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void peer_add(struct lowpan_dev *dev, struct lowpan_peer *peer)
|
static inline void peer_add(struct lowpan_btle_dev *dev,
|
||||||
|
struct lowpan_peer *peer)
|
||||||
{
|
{
|
||||||
list_add_rcu(&peer->list, &dev->peers);
|
list_add_rcu(&peer->list, &dev->peers);
|
||||||
atomic_inc(&dev->peer_count);
|
atomic_inc(&dev->peer_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool peer_del(struct lowpan_dev *dev, struct lowpan_peer *peer)
|
static inline bool peer_del(struct lowpan_btle_dev *dev,
|
||||||
|
struct lowpan_peer *peer)
|
||||||
{
|
{
|
||||||
list_del_rcu(&peer->list);
|
list_del_rcu(&peer->list);
|
||||||
kfree_rcu(peer, rcu);
|
kfree_rcu(peer, rcu);
|
||||||
|
@ -106,7 +109,7 @@ static inline bool peer_del(struct lowpan_dev *dev, struct lowpan_peer *peer)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline struct lowpan_peer *peer_lookup_ba(struct lowpan_dev *dev,
|
static inline struct lowpan_peer *peer_lookup_ba(struct lowpan_btle_dev *dev,
|
||||||
bdaddr_t *ba, __u8 type)
|
bdaddr_t *ba, __u8 type)
|
||||||
{
|
{
|
||||||
struct lowpan_peer *peer;
|
struct lowpan_peer *peer;
|
||||||
|
@ -134,8 +137,8 @@ static inline struct lowpan_peer *peer_lookup_ba(struct lowpan_dev *dev,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline struct lowpan_peer *__peer_lookup_chan(struct lowpan_dev *dev,
|
static inline struct lowpan_peer *
|
||||||
struct l2cap_chan *chan)
|
__peer_lookup_chan(struct lowpan_btle_dev *dev, struct l2cap_chan *chan)
|
||||||
{
|
{
|
||||||
struct lowpan_peer *peer;
|
struct lowpan_peer *peer;
|
||||||
|
|
||||||
|
@ -147,8 +150,8 @@ static inline struct lowpan_peer *__peer_lookup_chan(struct lowpan_dev *dev,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline struct lowpan_peer *__peer_lookup_conn(struct lowpan_dev *dev,
|
static inline struct lowpan_peer *
|
||||||
struct l2cap_conn *conn)
|
__peer_lookup_conn(struct lowpan_btle_dev *dev, struct l2cap_conn *conn)
|
||||||
{
|
{
|
||||||
struct lowpan_peer *peer;
|
struct lowpan_peer *peer;
|
||||||
|
|
||||||
|
@ -160,7 +163,7 @@ static inline struct lowpan_peer *__peer_lookup_conn(struct lowpan_dev *dev,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline struct lowpan_peer *peer_lookup_dst(struct lowpan_dev *dev,
|
static inline struct lowpan_peer *peer_lookup_dst(struct lowpan_btle_dev *dev,
|
||||||
struct in6_addr *daddr,
|
struct in6_addr *daddr,
|
||||||
struct sk_buff *skb)
|
struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
|
@ -220,7 +223,7 @@ static inline struct lowpan_peer *peer_lookup_dst(struct lowpan_dev *dev,
|
||||||
|
|
||||||
static struct lowpan_peer *lookup_peer(struct l2cap_conn *conn)
|
static struct lowpan_peer *lookup_peer(struct l2cap_conn *conn)
|
||||||
{
|
{
|
||||||
struct lowpan_dev *entry;
|
struct lowpan_btle_dev *entry;
|
||||||
struct lowpan_peer *peer = NULL;
|
struct lowpan_peer *peer = NULL;
|
||||||
|
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
|
@ -236,10 +239,10 @@ static struct lowpan_peer *lookup_peer(struct l2cap_conn *conn)
|
||||||
return peer;
|
return peer;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct lowpan_dev *lookup_dev(struct l2cap_conn *conn)
|
static struct lowpan_btle_dev *lookup_dev(struct l2cap_conn *conn)
|
||||||
{
|
{
|
||||||
struct lowpan_dev *entry;
|
struct lowpan_btle_dev *entry;
|
||||||
struct lowpan_dev *dev = NULL;
|
struct lowpan_btle_dev *dev = NULL;
|
||||||
|
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
|
|
||||||
|
@ -270,10 +273,10 @@ static int iphc_decompress(struct sk_buff *skb, struct net_device *netdev,
|
||||||
struct l2cap_chan *chan)
|
struct l2cap_chan *chan)
|
||||||
{
|
{
|
||||||
const u8 *saddr, *daddr;
|
const u8 *saddr, *daddr;
|
||||||
struct lowpan_dev *dev;
|
struct lowpan_btle_dev *dev;
|
||||||
struct lowpan_peer *peer;
|
struct lowpan_peer *peer;
|
||||||
|
|
||||||
dev = lowpan_dev(netdev);
|
dev = lowpan_btle_dev(netdev);
|
||||||
|
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
peer = __peer_lookup_chan(dev, chan);
|
peer = __peer_lookup_chan(dev, chan);
|
||||||
|
@ -375,7 +378,7 @@ drop:
|
||||||
/* Packet from BT LE device */
|
/* Packet from BT LE device */
|
||||||
static int chan_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb)
|
static int chan_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
struct lowpan_dev *dev;
|
struct lowpan_btle_dev *dev;
|
||||||
struct lowpan_peer *peer;
|
struct lowpan_peer *peer;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
@ -431,15 +434,18 @@ static int setup_header(struct sk_buff *skb, struct net_device *netdev,
|
||||||
bdaddr_t *peer_addr, u8 *peer_addr_type)
|
bdaddr_t *peer_addr, u8 *peer_addr_type)
|
||||||
{
|
{
|
||||||
struct in6_addr ipv6_daddr;
|
struct in6_addr ipv6_daddr;
|
||||||
struct lowpan_dev *dev;
|
struct ipv6hdr *hdr;
|
||||||
|
struct lowpan_btle_dev *dev;
|
||||||
struct lowpan_peer *peer;
|
struct lowpan_peer *peer;
|
||||||
bdaddr_t addr, *any = BDADDR_ANY;
|
bdaddr_t addr, *any = BDADDR_ANY;
|
||||||
u8 *daddr = any->b;
|
u8 *daddr = any->b;
|
||||||
int err, status = 0;
|
int err, status = 0;
|
||||||
|
|
||||||
dev = lowpan_dev(netdev);
|
hdr = ipv6_hdr(skb);
|
||||||
|
|
||||||
memcpy(&ipv6_daddr, &lowpan_cb(skb)->addr, sizeof(ipv6_daddr));
|
dev = lowpan_btle_dev(netdev);
|
||||||
|
|
||||||
|
memcpy(&ipv6_daddr, &hdr->daddr, sizeof(ipv6_daddr));
|
||||||
|
|
||||||
if (ipv6_addr_is_multicast(&ipv6_daddr)) {
|
if (ipv6_addr_is_multicast(&ipv6_daddr)) {
|
||||||
lowpan_cb(skb)->chan = NULL;
|
lowpan_cb(skb)->chan = NULL;
|
||||||
|
@ -489,15 +495,9 @@ static int header_create(struct sk_buff *skb, struct net_device *netdev,
|
||||||
unsigned short type, const void *_daddr,
|
unsigned short type, const void *_daddr,
|
||||||
const void *_saddr, unsigned int len)
|
const void *_saddr, unsigned int len)
|
||||||
{
|
{
|
||||||
struct ipv6hdr *hdr;
|
|
||||||
|
|
||||||
if (type != ETH_P_IPV6)
|
if (type != ETH_P_IPV6)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
hdr = ipv6_hdr(skb);
|
|
||||||
|
|
||||||
memcpy(&lowpan_cb(skb)->addr, &hdr->daddr, sizeof(struct in6_addr));
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -543,19 +543,19 @@ static int send_pkt(struct l2cap_chan *chan, struct sk_buff *skb,
|
||||||
static int send_mcast_pkt(struct sk_buff *skb, struct net_device *netdev)
|
static int send_mcast_pkt(struct sk_buff *skb, struct net_device *netdev)
|
||||||
{
|
{
|
||||||
struct sk_buff *local_skb;
|
struct sk_buff *local_skb;
|
||||||
struct lowpan_dev *entry;
|
struct lowpan_btle_dev *entry;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
|
|
||||||
list_for_each_entry_rcu(entry, &bt_6lowpan_devices, list) {
|
list_for_each_entry_rcu(entry, &bt_6lowpan_devices, list) {
|
||||||
struct lowpan_peer *pentry;
|
struct lowpan_peer *pentry;
|
||||||
struct lowpan_dev *dev;
|
struct lowpan_btle_dev *dev;
|
||||||
|
|
||||||
if (entry->netdev != netdev)
|
if (entry->netdev != netdev)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
dev = lowpan_dev(entry->netdev);
|
dev = lowpan_btle_dev(entry->netdev);
|
||||||
|
|
||||||
list_for_each_entry_rcu(pentry, &dev->peers, list) {
|
list_for_each_entry_rcu(pentry, &dev->peers, list) {
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -723,8 +723,8 @@ static void ifdown(struct net_device *netdev)
|
||||||
|
|
||||||
static void do_notify_peers(struct work_struct *work)
|
static void do_notify_peers(struct work_struct *work)
|
||||||
{
|
{
|
||||||
struct lowpan_dev *dev = container_of(work, struct lowpan_dev,
|
struct lowpan_btle_dev *dev = container_of(work, struct lowpan_btle_dev,
|
||||||
notify_peers.work);
|
notify_peers.work);
|
||||||
|
|
||||||
netdev_notify_peers(dev->netdev); /* send neighbour adv at startup */
|
netdev_notify_peers(dev->netdev); /* send neighbour adv at startup */
|
||||||
}
|
}
|
||||||
|
@ -766,7 +766,7 @@ static void set_ip_addr_bits(u8 addr_type, u8 *addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct l2cap_chan *add_peer_chan(struct l2cap_chan *chan,
|
static struct l2cap_chan *add_peer_chan(struct l2cap_chan *chan,
|
||||||
struct lowpan_dev *dev)
|
struct lowpan_btle_dev *dev)
|
||||||
{
|
{
|
||||||
struct lowpan_peer *peer;
|
struct lowpan_peer *peer;
|
||||||
|
|
||||||
|
@ -803,12 +803,12 @@ static struct l2cap_chan *add_peer_chan(struct l2cap_chan *chan,
|
||||||
return peer->chan;
|
return peer->chan;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int setup_netdev(struct l2cap_chan *chan, struct lowpan_dev **dev)
|
static int setup_netdev(struct l2cap_chan *chan, struct lowpan_btle_dev **dev)
|
||||||
{
|
{
|
||||||
struct net_device *netdev;
|
struct net_device *netdev;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
netdev = alloc_netdev(LOWPAN_PRIV_SIZE(sizeof(struct lowpan_dev)),
|
netdev = alloc_netdev(LOWPAN_PRIV_SIZE(sizeof(struct lowpan_btle_dev)),
|
||||||
IFACE_NAME_TEMPLATE, NET_NAME_UNKNOWN,
|
IFACE_NAME_TEMPLATE, NET_NAME_UNKNOWN,
|
||||||
netdev_setup);
|
netdev_setup);
|
||||||
if (!netdev)
|
if (!netdev)
|
||||||
|
@ -820,7 +820,7 @@ static int setup_netdev(struct l2cap_chan *chan, struct lowpan_dev **dev)
|
||||||
SET_NETDEV_DEV(netdev, &chan->conn->hcon->hdev->dev);
|
SET_NETDEV_DEV(netdev, &chan->conn->hcon->hdev->dev);
|
||||||
SET_NETDEV_DEVTYPE(netdev, &bt_type);
|
SET_NETDEV_DEVTYPE(netdev, &bt_type);
|
||||||
|
|
||||||
*dev = lowpan_dev(netdev);
|
*dev = lowpan_btle_dev(netdev);
|
||||||
(*dev)->netdev = netdev;
|
(*dev)->netdev = netdev;
|
||||||
(*dev)->hdev = chan->conn->hcon->hdev;
|
(*dev)->hdev = chan->conn->hcon->hdev;
|
||||||
INIT_LIST_HEAD(&(*dev)->peers);
|
INIT_LIST_HEAD(&(*dev)->peers);
|
||||||
|
@ -853,7 +853,7 @@ out:
|
||||||
|
|
||||||
static inline void chan_ready_cb(struct l2cap_chan *chan)
|
static inline void chan_ready_cb(struct l2cap_chan *chan)
|
||||||
{
|
{
|
||||||
struct lowpan_dev *dev;
|
struct lowpan_btle_dev *dev;
|
||||||
|
|
||||||
dev = lookup_dev(chan->conn);
|
dev = lookup_dev(chan->conn);
|
||||||
|
|
||||||
|
@ -890,8 +890,9 @@ static inline struct l2cap_chan *chan_new_conn_cb(struct l2cap_chan *pchan)
|
||||||
|
|
||||||
static void delete_netdev(struct work_struct *work)
|
static void delete_netdev(struct work_struct *work)
|
||||||
{
|
{
|
||||||
struct lowpan_dev *entry = container_of(work, struct lowpan_dev,
|
struct lowpan_btle_dev *entry = container_of(work,
|
||||||
delete_netdev);
|
struct lowpan_btle_dev,
|
||||||
|
delete_netdev);
|
||||||
|
|
||||||
lowpan_unregister_netdev(entry->netdev);
|
lowpan_unregister_netdev(entry->netdev);
|
||||||
|
|
||||||
|
@ -900,8 +901,8 @@ static void delete_netdev(struct work_struct *work)
|
||||||
|
|
||||||
static void chan_close_cb(struct l2cap_chan *chan)
|
static void chan_close_cb(struct l2cap_chan *chan)
|
||||||
{
|
{
|
||||||
struct lowpan_dev *entry;
|
struct lowpan_btle_dev *entry;
|
||||||
struct lowpan_dev *dev = NULL;
|
struct lowpan_btle_dev *dev = NULL;
|
||||||
struct lowpan_peer *peer;
|
struct lowpan_peer *peer;
|
||||||
int err = -ENOENT;
|
int err = -ENOENT;
|
||||||
bool last = false, remove = true;
|
bool last = false, remove = true;
|
||||||
|
@ -921,7 +922,7 @@ static void chan_close_cb(struct l2cap_chan *chan)
|
||||||
spin_lock(&devices_lock);
|
spin_lock(&devices_lock);
|
||||||
|
|
||||||
list_for_each_entry_rcu(entry, &bt_6lowpan_devices, list) {
|
list_for_each_entry_rcu(entry, &bt_6lowpan_devices, list) {
|
||||||
dev = lowpan_dev(entry->netdev);
|
dev = lowpan_btle_dev(entry->netdev);
|
||||||
peer = __peer_lookup_chan(dev, chan);
|
peer = __peer_lookup_chan(dev, chan);
|
||||||
if (peer) {
|
if (peer) {
|
||||||
last = peer_del(dev, peer);
|
last = peer_del(dev, peer);
|
||||||
|
@ -1131,7 +1132,7 @@ static int get_l2cap_conn(char *buf, bdaddr_t *addr, u8 *addr_type,
|
||||||
|
|
||||||
static void disconnect_all_peers(void)
|
static void disconnect_all_peers(void)
|
||||||
{
|
{
|
||||||
struct lowpan_dev *entry;
|
struct lowpan_btle_dev *entry;
|
||||||
struct lowpan_peer *peer, *tmp_peer, *new_peer;
|
struct lowpan_peer *peer, *tmp_peer, *new_peer;
|
||||||
struct list_head peers;
|
struct list_head peers;
|
||||||
|
|
||||||
|
@ -1291,7 +1292,7 @@ static ssize_t lowpan_control_write(struct file *fp,
|
||||||
|
|
||||||
static int lowpan_control_show(struct seq_file *f, void *ptr)
|
static int lowpan_control_show(struct seq_file *f, void *ptr)
|
||||||
{
|
{
|
||||||
struct lowpan_dev *entry;
|
struct lowpan_btle_dev *entry;
|
||||||
struct lowpan_peer *peer;
|
struct lowpan_peer *peer;
|
||||||
|
|
||||||
spin_lock(&devices_lock);
|
spin_lock(&devices_lock);
|
||||||
|
@ -1322,7 +1323,7 @@ static const struct file_operations lowpan_control_fops = {
|
||||||
|
|
||||||
static void disconnect_devices(void)
|
static void disconnect_devices(void)
|
||||||
{
|
{
|
||||||
struct lowpan_dev *entry, *tmp, *new_dev;
|
struct lowpan_btle_dev *entry, *tmp, *new_dev;
|
||||||
struct list_head devices;
|
struct list_head devices;
|
||||||
|
|
||||||
INIT_LIST_HEAD(&devices);
|
INIT_LIST_HEAD(&devices);
|
||||||
|
@ -1360,7 +1361,7 @@ static int device_event(struct notifier_block *unused,
|
||||||
unsigned long event, void *ptr)
|
unsigned long event, void *ptr)
|
||||||
{
|
{
|
||||||
struct net_device *netdev = netdev_notifier_info_to_dev(ptr);
|
struct net_device *netdev = netdev_notifier_info_to_dev(ptr);
|
||||||
struct lowpan_dev *entry;
|
struct lowpan_btle_dev *entry;
|
||||||
|
|
||||||
if (netdev->type != ARPHRD_6LOWPAN)
|
if (netdev->type != ARPHRD_6LOWPAN)
|
||||||
return NOTIFY_DONE;
|
return NOTIFY_DONE;
|
||||||
|
|
|
@ -41,24 +41,12 @@ static inline u32 ieee802154_addr_hash(const struct ieee802154_addr *a)
|
||||||
return (((__force u64)a->extended_addr) >> 32) ^
|
return (((__force u64)a->extended_addr) >> 32) ^
|
||||||
(((__force u64)a->extended_addr) & 0xffffffff);
|
(((__force u64)a->extended_addr) & 0xffffffff);
|
||||||
case IEEE802154_ADDR_SHORT:
|
case IEEE802154_ADDR_SHORT:
|
||||||
return (__force u32)(a->short_addr);
|
return (__force u32)(a->short_addr + (a->pan_id << 16));
|
||||||
default:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* private device info */
|
|
||||||
struct lowpan_dev_info {
|
|
||||||
struct net_device *wdev; /* wpan device ptr */
|
|
||||||
u16 fragment_tag;
|
|
||||||
};
|
|
||||||
|
|
||||||
static inline struct
|
|
||||||
lowpan_dev_info *lowpan_dev_info(const struct net_device *dev)
|
|
||||||
{
|
|
||||||
return (struct lowpan_dev_info *)lowpan_priv(dev)->priv;
|
|
||||||
}
|
|
||||||
|
|
||||||
int lowpan_frag_rcv(struct sk_buff *skb, const u8 frag_type);
|
int lowpan_frag_rcv(struct sk_buff *skb, const u8 frag_type);
|
||||||
void lowpan_net_frag_exit(void);
|
void lowpan_net_frag_exit(void);
|
||||||
int lowpan_net_frag_init(void);
|
int lowpan_net_frag_init(void);
|
||||||
|
|
|
@ -148,7 +148,7 @@ static int lowpan_newlink(struct net *src_net, struct net_device *ldev,
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
}
|
}
|
||||||
|
|
||||||
lowpan_dev_info(ldev)->wdev = wdev;
|
lowpan_802154_dev(ldev)->wdev = wdev;
|
||||||
/* Set the lowpan hardware address to the wpan hardware address. */
|
/* Set the lowpan hardware address to the wpan hardware address. */
|
||||||
memcpy(ldev->dev_addr, wdev->dev_addr, IEEE802154_ADDR_LEN);
|
memcpy(ldev->dev_addr, wdev->dev_addr, IEEE802154_ADDR_LEN);
|
||||||
/* We need headroom for possible wpan_dev_hard_header call and tailroom
|
/* We need headroom for possible wpan_dev_hard_header call and tailroom
|
||||||
|
@ -173,7 +173,7 @@ static int lowpan_newlink(struct net *src_net, struct net_device *ldev,
|
||||||
|
|
||||||
static void lowpan_dellink(struct net_device *ldev, struct list_head *head)
|
static void lowpan_dellink(struct net_device *ldev, struct list_head *head)
|
||||||
{
|
{
|
||||||
struct net_device *wdev = lowpan_dev_info(ldev)->wdev;
|
struct net_device *wdev = lowpan_802154_dev(ldev)->wdev;
|
||||||
|
|
||||||
ASSERT_RTNL();
|
ASSERT_RTNL();
|
||||||
|
|
||||||
|
@ -184,7 +184,7 @@ static void lowpan_dellink(struct net_device *ldev, struct list_head *head)
|
||||||
|
|
||||||
static struct rtnl_link_ops lowpan_link_ops __read_mostly = {
|
static struct rtnl_link_ops lowpan_link_ops __read_mostly = {
|
||||||
.kind = "lowpan",
|
.kind = "lowpan",
|
||||||
.priv_size = LOWPAN_PRIV_SIZE(sizeof(struct lowpan_dev_info)),
|
.priv_size = LOWPAN_PRIV_SIZE(sizeof(struct lowpan_802154_dev)),
|
||||||
.setup = lowpan_setup,
|
.setup = lowpan_setup,
|
||||||
.newlink = lowpan_newlink,
|
.newlink = lowpan_newlink,
|
||||||
.dellink = lowpan_dellink,
|
.dellink = lowpan_dellink,
|
||||||
|
|
|
@ -84,7 +84,7 @@ static struct sk_buff*
|
||||||
lowpan_alloc_frag(struct sk_buff *skb, int size,
|
lowpan_alloc_frag(struct sk_buff *skb, int size,
|
||||||
const struct ieee802154_hdr *master_hdr, bool frag1)
|
const struct ieee802154_hdr *master_hdr, bool frag1)
|
||||||
{
|
{
|
||||||
struct net_device *wdev = lowpan_dev_info(skb->dev)->wdev;
|
struct net_device *wdev = lowpan_802154_dev(skb->dev)->wdev;
|
||||||
struct sk_buff *frag;
|
struct sk_buff *frag;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
|
@ -148,8 +148,8 @@ lowpan_xmit_fragmented(struct sk_buff *skb, struct net_device *ldev,
|
||||||
int frag_cap, frag_len, payload_cap, rc;
|
int frag_cap, frag_len, payload_cap, rc;
|
||||||
int skb_unprocessed, skb_offset;
|
int skb_unprocessed, skb_offset;
|
||||||
|
|
||||||
frag_tag = htons(lowpan_dev_info(ldev)->fragment_tag);
|
frag_tag = htons(lowpan_802154_dev(ldev)->fragment_tag);
|
||||||
lowpan_dev_info(ldev)->fragment_tag++;
|
lowpan_802154_dev(ldev)->fragment_tag++;
|
||||||
|
|
||||||
frag_hdr[0] = LOWPAN_DISPATCH_FRAG1 | ((dgram_size >> 8) & 0x07);
|
frag_hdr[0] = LOWPAN_DISPATCH_FRAG1 | ((dgram_size >> 8) & 0x07);
|
||||||
frag_hdr[1] = dgram_size & 0xff;
|
frag_hdr[1] = dgram_size & 0xff;
|
||||||
|
@ -208,7 +208,7 @@ err:
|
||||||
static int lowpan_header(struct sk_buff *skb, struct net_device *ldev,
|
static int lowpan_header(struct sk_buff *skb, struct net_device *ldev,
|
||||||
u16 *dgram_size, u16 *dgram_offset)
|
u16 *dgram_size, u16 *dgram_offset)
|
||||||
{
|
{
|
||||||
struct wpan_dev *wpan_dev = lowpan_dev_info(ldev)->wdev->ieee802154_ptr;
|
struct wpan_dev *wpan_dev = lowpan_802154_dev(ldev)->wdev->ieee802154_ptr;
|
||||||
struct ieee802154_addr sa, da;
|
struct ieee802154_addr sa, da;
|
||||||
struct ieee802154_mac_cb *cb = mac_cb_init(skb);
|
struct ieee802154_mac_cb *cb = mac_cb_init(skb);
|
||||||
struct lowpan_addr_info info;
|
struct lowpan_addr_info info;
|
||||||
|
@ -248,8 +248,8 @@ static int lowpan_header(struct sk_buff *skb, struct net_device *ldev,
|
||||||
cb->ackreq = wpan_dev->ackreq;
|
cb->ackreq = wpan_dev->ackreq;
|
||||||
}
|
}
|
||||||
|
|
||||||
return wpan_dev_hard_header(skb, lowpan_dev_info(ldev)->wdev, &da, &sa,
|
return wpan_dev_hard_header(skb, lowpan_802154_dev(ldev)->wdev, &da,
|
||||||
0);
|
&sa, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
netdev_tx_t lowpan_xmit(struct sk_buff *skb, struct net_device *ldev)
|
netdev_tx_t lowpan_xmit(struct sk_buff *skb, struct net_device *ldev)
|
||||||
|
@ -283,7 +283,7 @@ netdev_tx_t lowpan_xmit(struct sk_buff *skb, struct net_device *ldev)
|
||||||
max_single = ieee802154_max_payload(&wpan_hdr);
|
max_single = ieee802154_max_payload(&wpan_hdr);
|
||||||
|
|
||||||
if (skb_tail_pointer(skb) - skb_network_header(skb) <= max_single) {
|
if (skb_tail_pointer(skb) - skb_network_header(skb) <= max_single) {
|
||||||
skb->dev = lowpan_dev_info(ldev)->wdev;
|
skb->dev = lowpan_802154_dev(ldev)->wdev;
|
||||||
ldev->stats.tx_packets++;
|
ldev->stats.tx_packets++;
|
||||||
ldev->stats.tx_bytes += dgram_size;
|
ldev->stats.tx_bytes += dgram_size;
|
||||||
return dev_queue_xmit(skb);
|
return dev_queue_xmit(skb);
|
||||||
|
|
|
@ -1078,6 +1078,11 @@ static int nl802154_set_pan_id(struct sk_buff *skb, struct genl_info *info)
|
||||||
if (netif_running(dev))
|
if (netif_running(dev))
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
|
|
||||||
|
if (wpan_dev->lowpan_dev) {
|
||||||
|
if (netif_running(wpan_dev->lowpan_dev))
|
||||||
|
return -EBUSY;
|
||||||
|
}
|
||||||
|
|
||||||
/* don't change address fields on monitor */
|
/* don't change address fields on monitor */
|
||||||
if (wpan_dev->iftype == NL802154_IFTYPE_MONITOR ||
|
if (wpan_dev->iftype == NL802154_IFTYPE_MONITOR ||
|
||||||
!info->attrs[NL802154_ATTR_PAN_ID])
|
!info->attrs[NL802154_ATTR_PAN_ID])
|
||||||
|
@ -1109,6 +1114,11 @@ static int nl802154_set_short_addr(struct sk_buff *skb, struct genl_info *info)
|
||||||
if (netif_running(dev))
|
if (netif_running(dev))
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
|
|
||||||
|
if (wpan_dev->lowpan_dev) {
|
||||||
|
if (netif_running(wpan_dev->lowpan_dev))
|
||||||
|
return -EBUSY;
|
||||||
|
}
|
||||||
|
|
||||||
/* don't change address fields on monitor */
|
/* don't change address fields on monitor */
|
||||||
if (wpan_dev->iftype == NL802154_IFTYPE_MONITOR ||
|
if (wpan_dev->iftype == NL802154_IFTYPE_MONITOR ||
|
||||||
!info->attrs[NL802154_ATTR_SHORT_ADDR])
|
!info->attrs[NL802154_ATTR_SHORT_ADDR])
|
||||||
|
|
Loading…
Add table
Reference in a new issue