Merge branch 'for-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next
This commit is contained in:
Коммит
07bc788424
|
@ -152,8 +152,8 @@ F: drivers/scsi/53c700*
|
|||
|
||||
6LOWPAN GENERIC (BTLE/IEEE 802.15.4)
|
||||
M: Alexander Aring <alex.aring@gmail.com>
|
||||
L: linux-zigbee-devel@lists.sourceforge.net (moderated for non-subscribers)
|
||||
L: linux-bluetooth@vger.kernel.org
|
||||
L: linux-wpan@vger.kernel.org
|
||||
S: Maintained
|
||||
F: net/6lowpan/
|
||||
F: include/net/6lowpan.h
|
||||
|
@ -4580,13 +4580,14 @@ F: drivers/idle/i7300_idle.c
|
|||
|
||||
IEEE 802.15.4 SUBSYSTEM
|
||||
M: Alexander Aring <alex.aring@gmail.com>
|
||||
L: linux-zigbee-devel@lists.sourceforge.net (moderated for non-subscribers)
|
||||
W: http://apps.sourceforge.net/trac/linux-zigbee
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/lowpan/lowpan.git
|
||||
L: linux-wpan@vger.kernel.org
|
||||
W: https://github.com/linux-wpan
|
||||
T: git git://github.com/linux-wpan/linux-wpan-next.git
|
||||
S: Maintained
|
||||
F: net/ieee802154/
|
||||
F: net/mac802154/
|
||||
F: drivers/net/ieee802154/
|
||||
F: Documentation/networking/ieee802154.txt
|
||||
|
||||
IGUANAWORKS USB IR TRANSCEIVER
|
||||
M: Sean Young <sean@mess.org>
|
||||
|
|
|
@ -88,6 +88,7 @@ static const struct usb_device_id ath3k_table[] = {
|
|||
{ USB_DEVICE(0x04CA, 0x300b) },
|
||||
{ USB_DEVICE(0x0930, 0x0219) },
|
||||
{ USB_DEVICE(0x0930, 0x0220) },
|
||||
{ USB_DEVICE(0x0930, 0x0227) },
|
||||
{ USB_DEVICE(0x0b05, 0x17d0) },
|
||||
{ USB_DEVICE(0x0CF3, 0x0036) },
|
||||
{ USB_DEVICE(0x0CF3, 0x3004) },
|
||||
|
@ -138,6 +139,7 @@ static const struct usb_device_id ath3k_blist_tbl[] = {
|
|||
{ USB_DEVICE(0x04ca, 0x300b), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x0930, 0x0220), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x0930, 0x0227), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x0b05, 0x17d0), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x0CF3, 0x0036), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 },
|
||||
|
|
|
@ -61,7 +61,7 @@ MODULE_LICENSE("GPL");
|
|||
/* ======================== Local structures ======================== */
|
||||
|
||||
|
||||
typedef struct bluecard_info_t {
|
||||
struct bluecard_info {
|
||||
struct pcmcia_device *p_dev;
|
||||
|
||||
struct hci_dev *hdev;
|
||||
|
@ -78,7 +78,7 @@ typedef struct bluecard_info_t {
|
|||
|
||||
unsigned char ctrl_reg;
|
||||
unsigned long hw_state; /* Status of the hardware and LED control */
|
||||
} bluecard_info_t;
|
||||
};
|
||||
|
||||
|
||||
static int bluecard_config(struct pcmcia_device *link);
|
||||
|
@ -157,7 +157,7 @@ static void bluecard_detach(struct pcmcia_device *p_dev);
|
|||
|
||||
static void bluecard_activity_led_timeout(u_long arg)
|
||||
{
|
||||
bluecard_info_t *info = (bluecard_info_t *)arg;
|
||||
struct bluecard_info *info = (struct bluecard_info *)arg;
|
||||
unsigned int iobase = info->p_dev->resource[0]->start;
|
||||
|
||||
if (!test_bit(CARD_HAS_PCCARD_ID, &(info->hw_state)))
|
||||
|
@ -173,7 +173,7 @@ static void bluecard_activity_led_timeout(u_long arg)
|
|||
}
|
||||
|
||||
|
||||
static void bluecard_enable_activity_led(bluecard_info_t *info)
|
||||
static void bluecard_enable_activity_led(struct bluecard_info *info)
|
||||
{
|
||||
unsigned int iobase = info->p_dev->resource[0]->start;
|
||||
|
||||
|
@ -215,7 +215,7 @@ static int bluecard_write(unsigned int iobase, unsigned int offset, __u8 *buf, i
|
|||
}
|
||||
|
||||
|
||||
static void bluecard_write_wakeup(bluecard_info_t *info)
|
||||
static void bluecard_write_wakeup(struct bluecard_info *info)
|
||||
{
|
||||
if (!info) {
|
||||
BT_ERR("Unknown device");
|
||||
|
@ -368,7 +368,8 @@ static int bluecard_read(unsigned int iobase, unsigned int offset, __u8 *buf, in
|
|||
}
|
||||
|
||||
|
||||
static void bluecard_receive(bluecard_info_t *info, unsigned int offset)
|
||||
static void bluecard_receive(struct bluecard_info *info,
|
||||
unsigned int offset)
|
||||
{
|
||||
unsigned int iobase;
|
||||
unsigned char buf[31];
|
||||
|
@ -497,7 +498,7 @@ static void bluecard_receive(bluecard_info_t *info, unsigned int offset)
|
|||
|
||||
static irqreturn_t bluecard_interrupt(int irq, void *dev_inst)
|
||||
{
|
||||
bluecard_info_t *info = dev_inst;
|
||||
struct bluecard_info *info = dev_inst;
|
||||
unsigned int iobase;
|
||||
unsigned char reg;
|
||||
|
||||
|
@ -562,7 +563,7 @@ static irqreturn_t bluecard_interrupt(int irq, void *dev_inst)
|
|||
|
||||
static int bluecard_hci_set_baud_rate(struct hci_dev *hdev, int baud)
|
||||
{
|
||||
bluecard_info_t *info = hci_get_drvdata(hdev);
|
||||
struct bluecard_info *info = hci_get_drvdata(hdev);
|
||||
struct sk_buff *skb;
|
||||
|
||||
/* Ericsson baud rate command */
|
||||
|
@ -611,7 +612,7 @@ static int bluecard_hci_set_baud_rate(struct hci_dev *hdev, int baud)
|
|||
|
||||
static int bluecard_hci_flush(struct hci_dev *hdev)
|
||||
{
|
||||
bluecard_info_t *info = hci_get_drvdata(hdev);
|
||||
struct bluecard_info *info = hci_get_drvdata(hdev);
|
||||
|
||||
/* Drop TX queue */
|
||||
skb_queue_purge(&(info->txq));
|
||||
|
@ -622,7 +623,7 @@ static int bluecard_hci_flush(struct hci_dev *hdev)
|
|||
|
||||
static int bluecard_hci_open(struct hci_dev *hdev)
|
||||
{
|
||||
bluecard_info_t *info = hci_get_drvdata(hdev);
|
||||
struct bluecard_info *info = hci_get_drvdata(hdev);
|
||||
|
||||
if (test_bit(CARD_HAS_PCCARD_ID, &(info->hw_state)))
|
||||
bluecard_hci_set_baud_rate(hdev, DEFAULT_BAUD_RATE);
|
||||
|
@ -643,7 +644,7 @@ static int bluecard_hci_open(struct hci_dev *hdev)
|
|||
|
||||
static int bluecard_hci_close(struct hci_dev *hdev)
|
||||
{
|
||||
bluecard_info_t *info = hci_get_drvdata(hdev);
|
||||
struct bluecard_info *info = hci_get_drvdata(hdev);
|
||||
|
||||
if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags)))
|
||||
return 0;
|
||||
|
@ -663,7 +664,7 @@ static int bluecard_hci_close(struct hci_dev *hdev)
|
|||
|
||||
static int bluecard_hci_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
bluecard_info_t *info = hci_get_drvdata(hdev);
|
||||
struct bluecard_info *info = hci_get_drvdata(hdev);
|
||||
|
||||
switch (bt_cb(skb)->pkt_type) {
|
||||
case HCI_COMMAND_PKT:
|
||||
|
@ -691,7 +692,7 @@ static int bluecard_hci_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
|
|||
/* ======================== Card services HCI interaction ======================== */
|
||||
|
||||
|
||||
static int bluecard_open(bluecard_info_t *info)
|
||||
static int bluecard_open(struct bluecard_info *info)
|
||||
{
|
||||
unsigned int iobase = info->p_dev->resource[0]->start;
|
||||
struct hci_dev *hdev;
|
||||
|
@ -806,7 +807,7 @@ static int bluecard_open(bluecard_info_t *info)
|
|||
}
|
||||
|
||||
|
||||
static int bluecard_close(bluecard_info_t *info)
|
||||
static int bluecard_close(struct bluecard_info *info)
|
||||
{
|
||||
unsigned int iobase = info->p_dev->resource[0]->start;
|
||||
struct hci_dev *hdev = info->hdev;
|
||||
|
@ -833,7 +834,7 @@ static int bluecard_close(bluecard_info_t *info)
|
|||
|
||||
static int bluecard_probe(struct pcmcia_device *link)
|
||||
{
|
||||
bluecard_info_t *info;
|
||||
struct bluecard_info *info;
|
||||
|
||||
/* Create new info device */
|
||||
info = devm_kzalloc(&link->dev, sizeof(*info), GFP_KERNEL);
|
||||
|
@ -857,7 +858,7 @@ static void bluecard_detach(struct pcmcia_device *link)
|
|||
|
||||
static int bluecard_config(struct pcmcia_device *link)
|
||||
{
|
||||
bluecard_info_t *info = link->priv;
|
||||
struct bluecard_info *info = link->priv;
|
||||
int i, n;
|
||||
|
||||
link->config_index = 0x20;
|
||||
|
@ -897,7 +898,7 @@ failed:
|
|||
|
||||
static void bluecard_release(struct pcmcia_device *link)
|
||||
{
|
||||
bluecard_info_t *info = link->priv;
|
||||
struct bluecard_info *info = link->priv;
|
||||
|
||||
bluecard_close(info);
|
||||
|
||||
|
|
|
@ -67,7 +67,7 @@ MODULE_FIRMWARE("BT3CPCC.bin");
|
|||
/* ======================== Local structures ======================== */
|
||||
|
||||
|
||||
typedef struct bt3c_info_t {
|
||||
struct bt3c_info {
|
||||
struct pcmcia_device *p_dev;
|
||||
|
||||
struct hci_dev *hdev;
|
||||
|
@ -80,7 +80,7 @@ typedef struct bt3c_info_t {
|
|||
unsigned long rx_state;
|
||||
unsigned long rx_count;
|
||||
struct sk_buff *rx_skb;
|
||||
} bt3c_info_t;
|
||||
};
|
||||
|
||||
|
||||
static int bt3c_config(struct pcmcia_device *link);
|
||||
|
@ -175,7 +175,7 @@ static int bt3c_write(unsigned int iobase, int fifo_size, __u8 *buf, int len)
|
|||
}
|
||||
|
||||
|
||||
static void bt3c_write_wakeup(bt3c_info_t *info)
|
||||
static void bt3c_write_wakeup(struct bt3c_info *info)
|
||||
{
|
||||
if (!info) {
|
||||
BT_ERR("Unknown device");
|
||||
|
@ -214,7 +214,7 @@ static void bt3c_write_wakeup(bt3c_info_t *info)
|
|||
}
|
||||
|
||||
|
||||
static void bt3c_receive(bt3c_info_t *info)
|
||||
static void bt3c_receive(struct bt3c_info *info)
|
||||
{
|
||||
unsigned int iobase;
|
||||
int size = 0, avail;
|
||||
|
@ -336,7 +336,7 @@ static void bt3c_receive(bt3c_info_t *info)
|
|||
|
||||
static irqreturn_t bt3c_interrupt(int irq, void *dev_inst)
|
||||
{
|
||||
bt3c_info_t *info = dev_inst;
|
||||
struct bt3c_info *info = dev_inst;
|
||||
unsigned int iobase;
|
||||
int iir;
|
||||
irqreturn_t r = IRQ_NONE;
|
||||
|
@ -388,7 +388,7 @@ static irqreturn_t bt3c_interrupt(int irq, void *dev_inst)
|
|||
|
||||
static int bt3c_hci_flush(struct hci_dev *hdev)
|
||||
{
|
||||
bt3c_info_t *info = hci_get_drvdata(hdev);
|
||||
struct bt3c_info *info = hci_get_drvdata(hdev);
|
||||
|
||||
/* Drop TX queue */
|
||||
skb_queue_purge(&(info->txq));
|
||||
|
@ -418,7 +418,7 @@ static int bt3c_hci_close(struct hci_dev *hdev)
|
|||
|
||||
static int bt3c_hci_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
bt3c_info_t *info = hci_get_drvdata(hdev);
|
||||
struct bt3c_info *info = hci_get_drvdata(hdev);
|
||||
unsigned long flags;
|
||||
|
||||
switch (bt_cb(skb)->pkt_type) {
|
||||
|
@ -451,7 +451,8 @@ static int bt3c_hci_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
|
|||
/* ======================== Card services HCI interaction ======================== */
|
||||
|
||||
|
||||
static int bt3c_load_firmware(bt3c_info_t *info, const unsigned char *firmware,
|
||||
static int bt3c_load_firmware(struct bt3c_info *info,
|
||||
const unsigned char *firmware,
|
||||
int count)
|
||||
{
|
||||
char *ptr = (char *) firmware;
|
||||
|
@ -536,7 +537,7 @@ error:
|
|||
}
|
||||
|
||||
|
||||
static int bt3c_open(bt3c_info_t *info)
|
||||
static int bt3c_open(struct bt3c_info *info)
|
||||
{
|
||||
const struct firmware *firmware;
|
||||
struct hci_dev *hdev;
|
||||
|
@ -603,7 +604,7 @@ error:
|
|||
}
|
||||
|
||||
|
||||
static int bt3c_close(bt3c_info_t *info)
|
||||
static int bt3c_close(struct bt3c_info *info)
|
||||
{
|
||||
struct hci_dev *hdev = info->hdev;
|
||||
|
||||
|
@ -620,7 +621,7 @@ static int bt3c_close(bt3c_info_t *info)
|
|||
|
||||
static int bt3c_probe(struct pcmcia_device *link)
|
||||
{
|
||||
bt3c_info_t *info;
|
||||
struct bt3c_info *info;
|
||||
|
||||
/* Create new info device */
|
||||
info = devm_kzalloc(&link->dev, sizeof(*info), GFP_KERNEL);
|
||||
|
@ -683,7 +684,7 @@ static int bt3c_check_config_notpicky(struct pcmcia_device *p_dev,
|
|||
|
||||
static int bt3c_config(struct pcmcia_device *link)
|
||||
{
|
||||
bt3c_info_t *info = link->priv;
|
||||
struct bt3c_info *info = link->priv;
|
||||
int i;
|
||||
unsigned long try;
|
||||
|
||||
|
@ -724,7 +725,7 @@ failed:
|
|||
|
||||
static void bt3c_release(struct pcmcia_device *link)
|
||||
{
|
||||
bt3c_info_t *info = link->priv;
|
||||
struct bt3c_info *info = link->priv;
|
||||
|
||||
bt3c_close(info);
|
||||
|
||||
|
|
|
@ -62,7 +62,7 @@ MODULE_LICENSE("GPL");
|
|||
/* ======================== Local structures ======================== */
|
||||
|
||||
|
||||
typedef struct btuart_info_t {
|
||||
struct btuart_info {
|
||||
struct pcmcia_device *p_dev;
|
||||
|
||||
struct hci_dev *hdev;
|
||||
|
@ -75,7 +75,7 @@ typedef struct btuart_info_t {
|
|||
unsigned long rx_state;
|
||||
unsigned long rx_count;
|
||||
struct sk_buff *rx_skb;
|
||||
} btuart_info_t;
|
||||
};
|
||||
|
||||
|
||||
static int btuart_config(struct pcmcia_device *link);
|
||||
|
@ -127,7 +127,7 @@ static int btuart_write(unsigned int iobase, int fifo_size, __u8 *buf, int len)
|
|||
}
|
||||
|
||||
|
||||
static void btuart_write_wakeup(btuart_info_t *info)
|
||||
static void btuart_write_wakeup(struct btuart_info *info)
|
||||
{
|
||||
if (!info) {
|
||||
BT_ERR("Unknown device");
|
||||
|
@ -172,7 +172,7 @@ static void btuart_write_wakeup(btuart_info_t *info)
|
|||
}
|
||||
|
||||
|
||||
static void btuart_receive(btuart_info_t *info)
|
||||
static void btuart_receive(struct btuart_info *info)
|
||||
{
|
||||
unsigned int iobase;
|
||||
int boguscount = 0;
|
||||
|
@ -286,7 +286,7 @@ static void btuart_receive(btuart_info_t *info)
|
|||
|
||||
static irqreturn_t btuart_interrupt(int irq, void *dev_inst)
|
||||
{
|
||||
btuart_info_t *info = dev_inst;
|
||||
struct btuart_info *info = dev_inst;
|
||||
unsigned int iobase;
|
||||
int boguscount = 0;
|
||||
int iir, lsr;
|
||||
|
@ -340,7 +340,8 @@ static irqreturn_t btuart_interrupt(int irq, void *dev_inst)
|
|||
}
|
||||
|
||||
|
||||
static void btuart_change_speed(btuart_info_t *info, unsigned int speed)
|
||||
static void btuart_change_speed(struct btuart_info *info,
|
||||
unsigned int speed)
|
||||
{
|
||||
unsigned long flags;
|
||||
unsigned int iobase;
|
||||
|
@ -397,7 +398,7 @@ static void btuart_change_speed(btuart_info_t *info, unsigned int speed)
|
|||
|
||||
static int btuart_hci_flush(struct hci_dev *hdev)
|
||||
{
|
||||
btuart_info_t *info = hci_get_drvdata(hdev);
|
||||
struct btuart_info *info = hci_get_drvdata(hdev);
|
||||
|
||||
/* Drop TX queue */
|
||||
skb_queue_purge(&(info->txq));
|
||||
|
@ -427,7 +428,7 @@ static int btuart_hci_close(struct hci_dev *hdev)
|
|||
|
||||
static int btuart_hci_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
btuart_info_t *info = hci_get_drvdata(hdev);
|
||||
struct btuart_info *info = hci_get_drvdata(hdev);
|
||||
|
||||
switch (bt_cb(skb)->pkt_type) {
|
||||
case HCI_COMMAND_PKT:
|
||||
|
@ -455,7 +456,7 @@ static int btuart_hci_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
|
|||
/* ======================== Card services HCI interaction ======================== */
|
||||
|
||||
|
||||
static int btuart_open(btuart_info_t *info)
|
||||
static int btuart_open(struct btuart_info *info)
|
||||
{
|
||||
unsigned long flags;
|
||||
unsigned int iobase = info->p_dev->resource[0]->start;
|
||||
|
@ -521,7 +522,7 @@ static int btuart_open(btuart_info_t *info)
|
|||
}
|
||||
|
||||
|
||||
static int btuart_close(btuart_info_t *info)
|
||||
static int btuart_close(struct btuart_info *info)
|
||||
{
|
||||
unsigned long flags;
|
||||
unsigned int iobase = info->p_dev->resource[0]->start;
|
||||
|
@ -550,7 +551,7 @@ static int btuart_close(btuart_info_t *info)
|
|||
|
||||
static int btuart_probe(struct pcmcia_device *link)
|
||||
{
|
||||
btuart_info_t *info;
|
||||
struct btuart_info *info;
|
||||
|
||||
/* Create new info device */
|
||||
info = devm_kzalloc(&link->dev, sizeof(*info), GFP_KERNEL);
|
||||
|
@ -613,7 +614,7 @@ static int btuart_check_config_notpicky(struct pcmcia_device *p_dev,
|
|||
|
||||
static int btuart_config(struct pcmcia_device *link)
|
||||
{
|
||||
btuart_info_t *info = link->priv;
|
||||
struct btuart_info *info = link->priv;
|
||||
int i;
|
||||
int try;
|
||||
|
||||
|
@ -654,7 +655,7 @@ failed:
|
|||
|
||||
static void btuart_release(struct pcmcia_device *link)
|
||||
{
|
||||
btuart_info_t *info = link->priv;
|
||||
struct btuart_info *info = link->priv;
|
||||
|
||||
btuart_close(info);
|
||||
|
||||
|
|
|
@ -165,6 +165,7 @@ static const struct usb_device_id blacklist_table[] = {
|
|||
{ USB_DEVICE(0x04ca, 0x300b), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x0930, 0x0220), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x0930, 0x0227), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x0b05, 0x17d0), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x0cf3, 0x0036), .driver_info = BTUSB_ATH3012 },
|
||||
{ USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 },
|
||||
|
|
|
@ -62,7 +62,7 @@ MODULE_LICENSE("GPL");
|
|||
/* ======================== Local structures ======================== */
|
||||
|
||||
|
||||
typedef struct dtl1_info_t {
|
||||
struct dtl1_info {
|
||||
struct pcmcia_device *p_dev;
|
||||
|
||||
struct hci_dev *hdev;
|
||||
|
@ -78,7 +78,7 @@ typedef struct dtl1_info_t {
|
|||
unsigned long rx_state;
|
||||
unsigned long rx_count;
|
||||
struct sk_buff *rx_skb;
|
||||
} dtl1_info_t;
|
||||
};
|
||||
|
||||
|
||||
static int dtl1_config(struct pcmcia_device *link);
|
||||
|
@ -94,11 +94,11 @@ static int dtl1_config(struct pcmcia_device *link);
|
|||
#define RECV_WAIT_DATA 1
|
||||
|
||||
|
||||
typedef struct {
|
||||
struct nsh {
|
||||
u8 type;
|
||||
u8 zero;
|
||||
u16 len;
|
||||
} __packed nsh_t; /* Nokia Specific Header */
|
||||
} __packed; /* Nokia Specific Header */
|
||||
|
||||
#define NSHL 4 /* Nokia Specific Header Length */
|
||||
|
||||
|
@ -126,7 +126,7 @@ static int dtl1_write(unsigned int iobase, int fifo_size, __u8 *buf, int len)
|
|||
}
|
||||
|
||||
|
||||
static void dtl1_write_wakeup(dtl1_info_t *info)
|
||||
static void dtl1_write_wakeup(struct dtl1_info *info)
|
||||
{
|
||||
if (!info) {
|
||||
BT_ERR("Unknown device");
|
||||
|
@ -176,7 +176,7 @@ static void dtl1_write_wakeup(dtl1_info_t *info)
|
|||
}
|
||||
|
||||
|
||||
static void dtl1_control(dtl1_info_t *info, struct sk_buff *skb)
|
||||
static void dtl1_control(struct dtl1_info *info, struct sk_buff *skb)
|
||||
{
|
||||
u8 flowmask = *(u8 *)skb->data;
|
||||
int i;
|
||||
|
@ -199,10 +199,10 @@ static void dtl1_control(dtl1_info_t *info, struct sk_buff *skb)
|
|||
}
|
||||
|
||||
|
||||
static void dtl1_receive(dtl1_info_t *info)
|
||||
static void dtl1_receive(struct dtl1_info *info)
|
||||
{
|
||||
unsigned int iobase;
|
||||
nsh_t *nsh;
|
||||
struct nsh *nsh;
|
||||
int boguscount = 0;
|
||||
|
||||
if (!info) {
|
||||
|
@ -227,7 +227,7 @@ static void dtl1_receive(dtl1_info_t *info)
|
|||
}
|
||||
|
||||
*skb_put(info->rx_skb, 1) = inb(iobase + UART_RX);
|
||||
nsh = (nsh_t *)info->rx_skb->data;
|
||||
nsh = (struct nsh *)info->rx_skb->data;
|
||||
|
||||
info->rx_count--;
|
||||
|
||||
|
@ -287,7 +287,7 @@ static void dtl1_receive(dtl1_info_t *info)
|
|||
|
||||
static irqreturn_t dtl1_interrupt(int irq, void *dev_inst)
|
||||
{
|
||||
dtl1_info_t *info = dev_inst;
|
||||
struct dtl1_info *info = dev_inst;
|
||||
unsigned int iobase;
|
||||
unsigned char msr;
|
||||
int boguscount = 0;
|
||||
|
@ -365,7 +365,7 @@ static int dtl1_hci_open(struct hci_dev *hdev)
|
|||
|
||||
static int dtl1_hci_flush(struct hci_dev *hdev)
|
||||
{
|
||||
dtl1_info_t *info = hci_get_drvdata(hdev);
|
||||
struct dtl1_info *info = hci_get_drvdata(hdev);
|
||||
|
||||
/* Drop TX queue */
|
||||
skb_queue_purge(&(info->txq));
|
||||
|
@ -387,9 +387,9 @@ static int dtl1_hci_close(struct hci_dev *hdev)
|
|||
|
||||
static int dtl1_hci_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
dtl1_info_t *info = hci_get_drvdata(hdev);
|
||||
struct dtl1_info *info = hci_get_drvdata(hdev);
|
||||
struct sk_buff *s;
|
||||
nsh_t nsh;
|
||||
struct nsh nsh;
|
||||
|
||||
switch (bt_cb(skb)->pkt_type) {
|
||||
case HCI_COMMAND_PKT:
|
||||
|
@ -436,7 +436,7 @@ static int dtl1_hci_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
|
|||
/* ======================== Card services HCI interaction ======================== */
|
||||
|
||||
|
||||
static int dtl1_open(dtl1_info_t *info)
|
||||
static int dtl1_open(struct dtl1_info *info)
|
||||
{
|
||||
unsigned long flags;
|
||||
unsigned int iobase = info->p_dev->resource[0]->start;
|
||||
|
@ -505,7 +505,7 @@ static int dtl1_open(dtl1_info_t *info)
|
|||
}
|
||||
|
||||
|
||||
static int dtl1_close(dtl1_info_t *info)
|
||||
static int dtl1_close(struct dtl1_info *info)
|
||||
{
|
||||
unsigned long flags;
|
||||
unsigned int iobase = info->p_dev->resource[0]->start;
|
||||
|
@ -534,7 +534,7 @@ static int dtl1_close(dtl1_info_t *info)
|
|||
|
||||
static int dtl1_probe(struct pcmcia_device *link)
|
||||
{
|
||||
dtl1_info_t *info;
|
||||
struct dtl1_info *info;
|
||||
|
||||
/* Create new info device */
|
||||
info = devm_kzalloc(&link->dev, sizeof(*info), GFP_KERNEL);
|
||||
|
@ -552,7 +552,7 @@ static int dtl1_probe(struct pcmcia_device *link)
|
|||
|
||||
static void dtl1_detach(struct pcmcia_device *link)
|
||||
{
|
||||
dtl1_info_t *info = link->priv;
|
||||
struct dtl1_info *info = link->priv;
|
||||
|
||||
dtl1_close(info);
|
||||
pcmcia_disable_device(link);
|
||||
|
@ -571,7 +571,7 @@ static int dtl1_confcheck(struct pcmcia_device *p_dev, void *priv_data)
|
|||
|
||||
static int dtl1_config(struct pcmcia_device *link)
|
||||
{
|
||||
dtl1_info_t *info = link->priv;
|
||||
struct dtl1_info *info = link->priv;
|
||||
int ret;
|
||||
|
||||
/* Look for a generic full-sized window */
|
||||
|
|
|
@ -237,7 +237,7 @@ static void h5_pkt_cull(struct h5 *h5)
|
|||
break;
|
||||
|
||||
to_remove--;
|
||||
seq = (seq - 1) % 8;
|
||||
seq = (seq - 1) & 0x07;
|
||||
}
|
||||
|
||||
if (seq != h5->rx_ack)
|
||||
|
|
|
@ -302,7 +302,7 @@ struct hci_dev {
|
|||
__u32 req_status;
|
||||
__u32 req_result;
|
||||
|
||||
struct crypto_blkcipher *tfm_aes;
|
||||
void *smp_data;
|
||||
|
||||
struct discovery_state discovery;
|
||||
struct hci_conn_hash conn_hash;
|
||||
|
@ -968,6 +968,9 @@ void hci_conn_del_sysfs(struct hci_conn *conn);
|
|||
#define lmp_host_le_capable(dev) (!!((dev)->features[1][0] & LMP_HOST_LE))
|
||||
#define lmp_host_le_br_capable(dev) (!!((dev)->features[1][0] & LMP_HOST_LE_BREDR))
|
||||
|
||||
#define hdev_is_powered(hdev) (test_bit(HCI_UP, &hdev->flags) && \
|
||||
!test_bit(HCI_AUTO_OFF, &hdev->dev_flags))
|
||||
|
||||
/* ----- HCI protocols ----- */
|
||||
#define HCI_PROTO_DEFER 0x01
|
||||
|
||||
|
@ -1256,6 +1259,8 @@ bool hci_req_pending(struct hci_dev *hdev);
|
|||
void hci_req_add_le_scan_disable(struct hci_request *req);
|
||||
void hci_req_add_le_passive_scan(struct hci_request *req);
|
||||
|
||||
void hci_update_page_scan(struct hci_dev *hdev, struct hci_request *req);
|
||||
|
||||
struct sk_buff *__hci_cmd_sync(struct hci_dev *hdev, u16 opcode, u32 plen,
|
||||
const void *param, u32 timeout);
|
||||
struct sk_buff *__hci_cmd_sync_ev(struct hci_dev *hdev, u16 opcode, u32 plen,
|
||||
|
@ -1351,6 +1356,7 @@ void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
|
|||
void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
|
||||
u8 addr_type, s8 rssi, u8 *name, u8 name_len);
|
||||
void mgmt_discovering(struct hci_dev *hdev, u8 discovering);
|
||||
bool mgmt_powering_down(struct hci_dev *hdev);
|
||||
void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, bool persistent);
|
||||
void mgmt_new_irk(struct hci_dev *hdev, struct smp_irk *irk);
|
||||
void mgmt_new_csrk(struct hci_dev *hdev, struct smp_csrk *csrk,
|
||||
|
|
|
@ -625,6 +625,9 @@ struct l2cap_conn {
|
|||
|
||||
struct delayed_work info_timer;
|
||||
|
||||
int disconn_err;
|
||||
struct work_struct disconn_work;
|
||||
|
||||
struct sk_buff *rx_skb;
|
||||
__u32 rx_len;
|
||||
__u8 tx_ident;
|
||||
|
@ -635,8 +638,7 @@ struct l2cap_conn {
|
|||
|
||||
__u8 disc_reason;
|
||||
|
||||
struct delayed_work security_timer;
|
||||
struct smp_chan *smp_chan;
|
||||
struct l2cap_chan *smp;
|
||||
|
||||
struct list_head chan_l;
|
||||
struct mutex chan_lock;
|
||||
|
@ -708,6 +710,7 @@ enum {
|
|||
FLAG_EFS_ENABLE,
|
||||
FLAG_DEFER_SETUP,
|
||||
FLAG_LE_CONN_REQ_SENT,
|
||||
FLAG_PENDING_SECURITY,
|
||||
};
|
||||
|
||||
enum {
|
||||
|
@ -837,18 +840,43 @@ static inline struct l2cap_chan *l2cap_chan_no_new_connection(struct l2cap_chan
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static inline int l2cap_chan_no_recv(struct l2cap_chan *chan, struct sk_buff *skb)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
static inline struct sk_buff *l2cap_chan_no_alloc_skb(struct l2cap_chan *chan,
|
||||
unsigned long hdr_len,
|
||||
unsigned long len, int nb)
|
||||
{
|
||||
return ERR_PTR(-ENOSYS);
|
||||
}
|
||||
|
||||
static inline void l2cap_chan_no_teardown(struct l2cap_chan *chan, int err)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void l2cap_chan_no_close(struct l2cap_chan *chan)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void l2cap_chan_no_ready(struct l2cap_chan *chan)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void l2cap_chan_no_state_change(struct l2cap_chan *chan,
|
||||
int state, int err)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void l2cap_chan_no_defer(struct l2cap_chan *chan)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void l2cap_chan_no_suspend(struct l2cap_chan *chan)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void l2cap_chan_no_resume(struct l2cap_chan *chan)
|
||||
{
|
||||
}
|
||||
|
@ -918,6 +946,7 @@ void l2cap_logical_cfm(struct l2cap_chan *chan, struct hci_chan *hchan,
|
|||
u8 status);
|
||||
void __l2cap_physical_cfm(struct l2cap_chan *chan, int result);
|
||||
|
||||
void l2cap_conn_shutdown(struct l2cap_conn *conn, int err);
|
||||
void l2cap_conn_get(struct l2cap_conn *conn);
|
||||
void l2cap_conn_put(struct l2cap_conn *conn);
|
||||
|
||||
|
|
|
@ -772,16 +772,16 @@ static inline void chan_ready_cb(struct l2cap_chan *chan)
|
|||
ifup(dev->netdev);
|
||||
}
|
||||
|
||||
static inline struct l2cap_chan *chan_new_conn_cb(struct l2cap_chan *chan)
|
||||
static inline struct l2cap_chan *chan_new_conn_cb(struct l2cap_chan *pchan)
|
||||
{
|
||||
struct l2cap_chan *pchan;
|
||||
struct l2cap_chan *chan;
|
||||
|
||||
pchan = chan_open(chan);
|
||||
pchan->ops = chan->ops;
|
||||
chan = chan_open(pchan);
|
||||
chan->ops = pchan->ops;
|
||||
|
||||
BT_DBG("chan %p pchan %p", chan, pchan);
|
||||
|
||||
return pchan;
|
||||
return chan;
|
||||
}
|
||||
|
||||
static void delete_netdev(struct work_struct *work)
|
||||
|
|
|
@ -1898,6 +1898,8 @@ static int __hci_init(struct hci_dev *hdev)
|
|||
debugfs_create_u16("discov_interleaved_timeout", 0644,
|
||||
hdev->debugfs,
|
||||
&hdev->discov_interleaved_timeout);
|
||||
|
||||
smp_register(hdev);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -3233,7 +3235,7 @@ struct smp_irk *hci_find_irk_by_rpa(struct hci_dev *hdev, bdaddr_t *rpa)
|
|||
}
|
||||
|
||||
list_for_each_entry(irk, &hdev->identity_resolving_keys, list) {
|
||||
if (smp_irk_matches(hdev->tfm_aes, irk->val, rpa)) {
|
||||
if (smp_irk_matches(hdev, irk->val, rpa)) {
|
||||
bacpy(&irk->rpa, rpa);
|
||||
return irk;
|
||||
}
|
||||
|
@ -3882,7 +3884,7 @@ int hci_update_random_address(struct hci_request *req, bool require_privacy,
|
|||
!bacmp(&hdev->random_addr, &hdev->rpa))
|
||||
return 0;
|
||||
|
||||
err = smp_generate_rpa(hdev->tfm_aes, hdev->irk, &hdev->rpa);
|
||||
err = smp_generate_rpa(hdev, hdev->irk, &hdev->rpa);
|
||||
if (err < 0) {
|
||||
BT_ERR("%s failed to generate new RPA", hdev->name);
|
||||
return err;
|
||||
|
@ -4090,18 +4092,9 @@ int hci_register_dev(struct hci_dev *hdev)
|
|||
|
||||
dev_set_name(&hdev->dev, "%s", hdev->name);
|
||||
|
||||
hdev->tfm_aes = crypto_alloc_blkcipher("ecb(aes)", 0,
|
||||
CRYPTO_ALG_ASYNC);
|
||||
if (IS_ERR(hdev->tfm_aes)) {
|
||||
BT_ERR("Unable to create crypto context");
|
||||
error = PTR_ERR(hdev->tfm_aes);
|
||||
hdev->tfm_aes = NULL;
|
||||
goto err_wqueue;
|
||||
}
|
||||
|
||||
error = device_add(&hdev->dev);
|
||||
if (error < 0)
|
||||
goto err_tfm;
|
||||
goto err_wqueue;
|
||||
|
||||
hdev->rfkill = rfkill_alloc(hdev->name, &hdev->dev,
|
||||
RFKILL_TYPE_BLUETOOTH, &hci_rfkill_ops,
|
||||
|
@ -4143,8 +4136,6 @@ int hci_register_dev(struct hci_dev *hdev)
|
|||
|
||||
return id;
|
||||
|
||||
err_tfm:
|
||||
crypto_free_blkcipher(hdev->tfm_aes);
|
||||
err_wqueue:
|
||||
destroy_workqueue(hdev->workqueue);
|
||||
destroy_workqueue(hdev->req_workqueue);
|
||||
|
@ -4196,8 +4187,7 @@ void hci_unregister_dev(struct hci_dev *hdev)
|
|||
rfkill_destroy(hdev->rfkill);
|
||||
}
|
||||
|
||||
if (hdev->tfm_aes)
|
||||
crypto_free_blkcipher(hdev->tfm_aes);
|
||||
smp_unregister(hdev);
|
||||
|
||||
device_del(&hdev->dev);
|
||||
|
||||
|
@ -5680,3 +5670,52 @@ void hci_update_background_scan(struct hci_dev *hdev)
|
|||
if (err)
|
||||
BT_ERR("Failed to run HCI request: err %d", err);
|
||||
}
|
||||
|
||||
static bool disconnected_whitelist_entries(struct hci_dev *hdev)
|
||||
{
|
||||
struct bdaddr_list *b;
|
||||
|
||||
list_for_each_entry(b, &hdev->whitelist, list) {
|
||||
struct hci_conn *conn;
|
||||
|
||||
conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &b->bdaddr);
|
||||
if (!conn)
|
||||
return true;
|
||||
|
||||
if (conn->state != BT_CONNECTED && conn->state != BT_CONFIG)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void hci_update_page_scan(struct hci_dev *hdev, struct hci_request *req)
|
||||
{
|
||||
u8 scan;
|
||||
|
||||
if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
|
||||
return;
|
||||
|
||||
if (!hdev_is_powered(hdev))
|
||||
return;
|
||||
|
||||
if (mgmt_powering_down(hdev))
|
||||
return;
|
||||
|
||||
if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags) ||
|
||||
disconnected_whitelist_entries(hdev))
|
||||
scan = SCAN_PAGE;
|
||||
else
|
||||
scan = SCAN_DISABLED;
|
||||
|
||||
if (test_bit(HCI_PSCAN, &hdev->flags) == !!(scan & SCAN_PAGE))
|
||||
return;
|
||||
|
||||
if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
|
||||
scan |= SCAN_INQUIRY;
|
||||
|
||||
if (req)
|
||||
hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
|
||||
else
|
||||
hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
|
||||
}
|
||||
|
|
|
@ -2071,6 +2071,8 @@ static void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
|||
cp.handle = ev->handle;
|
||||
hci_send_cmd(hdev, HCI_OP_READ_REMOTE_FEATURES,
|
||||
sizeof(cp), &cp);
|
||||
|
||||
hci_update_page_scan(hdev, NULL);
|
||||
}
|
||||
|
||||
/* Set packet type for incoming connection */
|
||||
|
@ -2247,9 +2249,12 @@ static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
|||
mgmt_device_disconnected(hdev, &conn->dst, conn->type, conn->dst_type,
|
||||
reason, mgmt_connected);
|
||||
|
||||
if (conn->type == ACL_LINK &&
|
||||
test_bit(HCI_CONN_FLUSH_KEY, &conn->flags))
|
||||
hci_remove_link_key(hdev, &conn->dst);
|
||||
if (conn->type == ACL_LINK) {
|
||||
if (test_bit(HCI_CONN_FLUSH_KEY, &conn->flags))
|
||||
hci_remove_link_key(hdev, &conn->dst);
|
||||
|
||||
hci_update_page_scan(hdev, NULL);
|
||||
}
|
||||
|
||||
params = hci_conn_params_lookup(hdev, &conn->dst, conn->dst_type);
|
||||
if (params) {
|
||||
|
|
|
@ -210,6 +210,10 @@ int l2cap_add_scid(struct l2cap_chan *chan, __u16 scid)
|
|||
{
|
||||
write_lock(&chan_list_lock);
|
||||
|
||||
/* Override the defaults (which are for conn-oriented) */
|
||||
chan->omtu = L2CAP_DEFAULT_MTU;
|
||||
chan->chan_type = L2CAP_CHAN_FIXED;
|
||||
|
||||
chan->scid = scid;
|
||||
|
||||
write_unlock(&chan_list_lock);
|
||||
|
@ -562,6 +566,8 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err)
|
|||
|
||||
BT_DBG("chan %p, conn %p, err %d", chan, conn, err);
|
||||
|
||||
chan->ops->teardown(chan, err);
|
||||
|
||||
if (conn) {
|
||||
struct amp_mgr *mgr = conn->hcon->amp_mgr;
|
||||
/* Delete from channel list */
|
||||
|
@ -585,8 +591,6 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err)
|
|||
amp_disconnect_logical_link(hs_hchan);
|
||||
}
|
||||
|
||||
chan->ops->teardown(chan, err);
|
||||
|
||||
if (test_bit(CONF_NOT_COMPLETE, &chan->conf_state))
|
||||
return;
|
||||
|
||||
|
@ -1082,6 +1086,9 @@ static void l2cap_send_rr_or_rnr(struct l2cap_chan *chan, bool poll)
|
|||
|
||||
static inline int __l2cap_no_conn_pending(struct l2cap_chan *chan)
|
||||
{
|
||||
if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED)
|
||||
return true;
|
||||
|
||||
return !test_bit(CONF_CONNECT_PEND, &chan->conf_state);
|
||||
}
|
||||
|
||||
|
@ -1417,71 +1424,18 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
|
|||
mutex_unlock(&conn->chan_lock);
|
||||
}
|
||||
|
||||
/* Find socket with cid and source/destination bdaddr.
|
||||
* Returns closest match, locked.
|
||||
*/
|
||||
static struct l2cap_chan *l2cap_global_chan_by_scid(int state, u16 cid,
|
||||
bdaddr_t *src,
|
||||
bdaddr_t *dst)
|
||||
{
|
||||
struct l2cap_chan *c, *c1 = NULL;
|
||||
|
||||
read_lock(&chan_list_lock);
|
||||
|
||||
list_for_each_entry(c, &chan_list, global_l) {
|
||||
if (state && c->state != state)
|
||||
continue;
|
||||
|
||||
if (c->scid == cid) {
|
||||
int src_match, dst_match;
|
||||
int src_any, dst_any;
|
||||
|
||||
/* Exact match. */
|
||||
src_match = !bacmp(&c->src, src);
|
||||
dst_match = !bacmp(&c->dst, dst);
|
||||
if (src_match && dst_match) {
|
||||
read_unlock(&chan_list_lock);
|
||||
return c;
|
||||
}
|
||||
|
||||
/* Closest match */
|
||||
src_any = !bacmp(&c->src, BDADDR_ANY);
|
||||
dst_any = !bacmp(&c->dst, BDADDR_ANY);
|
||||
if ((src_match && dst_any) || (src_any && dst_match) ||
|
||||
(src_any && dst_any))
|
||||
c1 = c;
|
||||
}
|
||||
}
|
||||
|
||||
read_unlock(&chan_list_lock);
|
||||
|
||||
return c1;
|
||||
}
|
||||
|
||||
static void l2cap_le_conn_ready(struct l2cap_conn *conn)
|
||||
{
|
||||
struct hci_conn *hcon = conn->hcon;
|
||||
struct hci_dev *hdev = hcon->hdev;
|
||||
struct l2cap_chan *chan, *pchan;
|
||||
u8 dst_type;
|
||||
|
||||
BT_DBG("");
|
||||
BT_DBG("%s conn %p", hdev->name, conn);
|
||||
|
||||
/* Check if we have socket listening on cid */
|
||||
pchan = l2cap_global_chan_by_scid(BT_LISTEN, L2CAP_CID_ATT,
|
||||
&hcon->src, &hcon->dst);
|
||||
if (!pchan)
|
||||
return;
|
||||
|
||||
/* Client ATT sockets should override the server one */
|
||||
if (__l2cap_get_chan_by_dcid(conn, L2CAP_CID_ATT))
|
||||
return;
|
||||
|
||||
dst_type = bdaddr_type(hcon, hcon->dst_type);
|
||||
|
||||
/* If device is blocked, do not create a channel for it */
|
||||
if (hci_bdaddr_list_lookup(&hdev->blacklist, &hcon->dst, dst_type))
|
||||
return;
|
||||
/* For outgoing pairing which doesn't necessarily have an
|
||||
* associated socket (e.g. mgmt_pair_device).
|
||||
*/
|
||||
if (hcon->out)
|
||||
smp_conn_security(hcon, hcon->pending_sec_level);
|
||||
|
||||
/* For LE slave connections, make sure the connection interval
|
||||
* is in the range of the minium and maximum interval that has
|
||||
|
@ -1501,22 +1455,6 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn)
|
|||
l2cap_send_cmd(conn, l2cap_get_ident(conn),
|
||||
L2CAP_CONN_PARAM_UPDATE_REQ, sizeof(req), &req);
|
||||
}
|
||||
|
||||
l2cap_chan_lock(pchan);
|
||||
|
||||
chan = pchan->ops->new_connection(pchan);
|
||||
if (!chan)
|
||||
goto clean;
|
||||
|
||||
bacpy(&chan->src, &hcon->src);
|
||||
bacpy(&chan->dst, &hcon->dst);
|
||||
chan->src_type = bdaddr_type(hcon, hcon->src_type);
|
||||
chan->dst_type = dst_type;
|
||||
|
||||
__l2cap_chan_add(conn, chan);
|
||||
|
||||
clean:
|
||||
l2cap_chan_unlock(pchan);
|
||||
}
|
||||
|
||||
static void l2cap_conn_ready(struct l2cap_conn *conn)
|
||||
|
@ -1526,17 +1464,8 @@ static void l2cap_conn_ready(struct l2cap_conn *conn)
|
|||
|
||||
BT_DBG("conn %p", conn);
|
||||
|
||||
/* For outgoing pairing which doesn't necessarily have an
|
||||
* associated socket (e.g. mgmt_pair_device).
|
||||
*/
|
||||
if (hcon->out && hcon->type == LE_LINK)
|
||||
smp_conn_security(hcon, hcon->pending_sec_level);
|
||||
|
||||
mutex_lock(&conn->chan_lock);
|
||||
|
||||
if (hcon->type == LE_LINK)
|
||||
l2cap_le_conn_ready(conn);
|
||||
|
||||
list_for_each_entry(chan, &conn->chan_l, list) {
|
||||
|
||||
l2cap_chan_lock(chan);
|
||||
|
@ -1560,6 +1489,9 @@ static void l2cap_conn_ready(struct l2cap_conn *conn)
|
|||
|
||||
mutex_unlock(&conn->chan_lock);
|
||||
|
||||
if (hcon->type == LE_LINK)
|
||||
l2cap_le_conn_ready(conn);
|
||||
|
||||
queue_work(hcon->hdev->workqueue, &conn->pending_rx_work);
|
||||
}
|
||||
|
||||
|
@ -1695,6 +1627,9 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err)
|
|||
if (work_pending(&conn->pending_rx_work))
|
||||
cancel_work_sync(&conn->pending_rx_work);
|
||||
|
||||
if (work_pending(&conn->disconn_work))
|
||||
cancel_work_sync(&conn->disconn_work);
|
||||
|
||||
l2cap_unregister_all_users(conn);
|
||||
|
||||
mutex_lock(&conn->chan_lock);
|
||||
|
@ -1719,27 +1654,29 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err)
|
|||
if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT)
|
||||
cancel_delayed_work_sync(&conn->info_timer);
|
||||
|
||||
if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags)) {
|
||||
cancel_delayed_work_sync(&conn->security_timer);
|
||||
smp_chan_destroy(conn);
|
||||
}
|
||||
|
||||
hcon->l2cap_data = NULL;
|
||||
conn->hchan = NULL;
|
||||
l2cap_conn_put(conn);
|
||||
}
|
||||
|
||||
static void security_timeout(struct work_struct *work)
|
||||
static void disconn_work(struct work_struct *work)
|
||||
{
|
||||
struct l2cap_conn *conn = container_of(work, struct l2cap_conn,
|
||||
security_timer.work);
|
||||
disconn_work);
|
||||
|
||||
BT_DBG("conn %p", conn);
|
||||
|
||||
if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags)) {
|
||||
smp_chan_destroy(conn);
|
||||
l2cap_conn_del(conn->hcon, ETIMEDOUT);
|
||||
}
|
||||
l2cap_conn_del(conn->hcon, conn->disconn_err);
|
||||
}
|
||||
|
||||
void l2cap_conn_shutdown(struct l2cap_conn *conn, int err)
|
||||
{
|
||||
struct hci_dev *hdev = conn->hcon->hdev;
|
||||
|
||||
BT_DBG("conn %p err %d", conn, err);
|
||||
|
||||
conn->disconn_err = err;
|
||||
queue_work(hdev->workqueue, &conn->disconn_work);
|
||||
}
|
||||
|
||||
static void l2cap_conn_free(struct kref *ref)
|
||||
|
@ -1794,6 +1731,7 @@ static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm,
|
|||
src_match = !bacmp(&c->src, src);
|
||||
dst_match = !bacmp(&c->dst, dst);
|
||||
if (src_match && dst_match) {
|
||||
l2cap_chan_hold(c);
|
||||
read_unlock(&chan_list_lock);
|
||||
return c;
|
||||
}
|
||||
|
@ -1807,6 +1745,9 @@ static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm,
|
|||
}
|
||||
}
|
||||
|
||||
if (c1)
|
||||
l2cap_chan_hold(c1);
|
||||
|
||||
read_unlock(&chan_list_lock);
|
||||
|
||||
return c1;
|
||||
|
@ -2027,10 +1968,12 @@ static void l2cap_ertm_resend(struct l2cap_chan *chan)
|
|||
tx_skb->data + L2CAP_HDR_SIZE);
|
||||
}
|
||||
|
||||
/* Update FCS */
|
||||
if (chan->fcs == L2CAP_FCS_CRC16) {
|
||||
u16 fcs = crc16(0, (u8 *) tx_skb->data, tx_skb->len);
|
||||
put_unaligned_le16(fcs, skb_put(tx_skb,
|
||||
L2CAP_FCS_SIZE));
|
||||
u16 fcs = crc16(0, (u8 *) tx_skb->data,
|
||||
tx_skb->len - L2CAP_FCS_SIZE);
|
||||
put_unaligned_le16(fcs, skb_tail_pointer(tx_skb) -
|
||||
L2CAP_FCS_SIZE);
|
||||
}
|
||||
|
||||
l2cap_do_send(chan, tx_skb);
|
||||
|
@ -2334,7 +2277,6 @@ static int l2cap_segment_sdu(struct l2cap_chan *chan,
|
|||
} else {
|
||||
sar = L2CAP_SAR_START;
|
||||
sdu_len = len;
|
||||
pdu_len -= L2CAP_SDULEN_SIZE;
|
||||
}
|
||||
|
||||
while (len > 0) {
|
||||
|
@ -2349,10 +2291,8 @@ static int l2cap_segment_sdu(struct l2cap_chan *chan,
|
|||
__skb_queue_tail(seg_queue, skb);
|
||||
|
||||
len -= pdu_len;
|
||||
if (sdu_len) {
|
||||
if (sdu_len)
|
||||
sdu_len = 0;
|
||||
pdu_len += L2CAP_SDULEN_SIZE;
|
||||
}
|
||||
|
||||
if (len <= pdu_len) {
|
||||
sar = L2CAP_SAR_END;
|
||||
|
@ -3884,6 +3824,7 @@ static struct l2cap_chan *l2cap_connect(struct l2cap_conn *conn,
|
|||
response:
|
||||
l2cap_chan_unlock(pchan);
|
||||
mutex_unlock(&conn->chan_lock);
|
||||
l2cap_chan_put(pchan);
|
||||
|
||||
sendresp:
|
||||
rsp.scid = cpu_to_le16(scid);
|
||||
|
@ -5497,6 +5438,7 @@ static int l2cap_le_connect_req(struct l2cap_conn *conn,
|
|||
response_unlock:
|
||||
l2cap_chan_unlock(pchan);
|
||||
mutex_unlock(&conn->chan_lock);
|
||||
l2cap_chan_put(pchan);
|
||||
|
||||
if (result == L2CAP_CR_PEND)
|
||||
return 0;
|
||||
|
@ -6845,12 +6787,12 @@ static void l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm,
|
|||
struct l2cap_chan *chan;
|
||||
|
||||
if (hcon->type != ACL_LINK)
|
||||
goto drop;
|
||||
goto free_skb;
|
||||
|
||||
chan = l2cap_global_chan_by_psm(0, psm, &hcon->src, &hcon->dst,
|
||||
ACL_LINK);
|
||||
if (!chan)
|
||||
goto drop;
|
||||
goto free_skb;
|
||||
|
||||
BT_DBG("chan %p, len %d", chan, skb->len);
|
||||
|
||||
|
@ -6864,36 +6806,14 @@ static void l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm,
|
|||
bacpy(&bt_cb(skb)->bdaddr, &hcon->dst);
|
||||
bt_cb(skb)->psm = psm;
|
||||
|
||||
if (!chan->ops->recv(chan, skb))
|
||||
return;
|
||||
|
||||
drop:
|
||||
kfree_skb(skb);
|
||||
}
|
||||
|
||||
static void l2cap_att_channel(struct l2cap_conn *conn,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct hci_conn *hcon = conn->hcon;
|
||||
struct l2cap_chan *chan;
|
||||
|
||||
if (hcon->type != LE_LINK)
|
||||
goto drop;
|
||||
|
||||
chan = l2cap_global_chan_by_scid(BT_CONNECTED, L2CAP_CID_ATT,
|
||||
&hcon->src, &hcon->dst);
|
||||
if (!chan)
|
||||
goto drop;
|
||||
|
||||
BT_DBG("chan %p, len %d", chan, skb->len);
|
||||
|
||||
if (chan->imtu < skb->len)
|
||||
goto drop;
|
||||
|
||||
if (!chan->ops->recv(chan, skb))
|
||||
if (!chan->ops->recv(chan, skb)) {
|
||||
l2cap_chan_put(chan);
|
||||
return;
|
||||
}
|
||||
|
||||
drop:
|
||||
l2cap_chan_put(chan);
|
||||
free_skb:
|
||||
kfree_skb(skb);
|
||||
}
|
||||
|
||||
|
@ -6942,19 +6862,10 @@ static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
|
|||
l2cap_conless_channel(conn, psm, skb);
|
||||
break;
|
||||
|
||||
case L2CAP_CID_ATT:
|
||||
l2cap_att_channel(conn, skb);
|
||||
break;
|
||||
|
||||
case L2CAP_CID_LE_SIGNALING:
|
||||
l2cap_le_sig_channel(conn, skb);
|
||||
break;
|
||||
|
||||
case L2CAP_CID_SMP:
|
||||
if (smp_sig_channel(conn, skb))
|
||||
l2cap_conn_del(conn->hcon, EACCES);
|
||||
break;
|
||||
|
||||
default:
|
||||
l2cap_data_channel(conn, cid, skb);
|
||||
break;
|
||||
|
@ -7023,10 +6934,9 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon)
|
|||
INIT_LIST_HEAD(&conn->chan_l);
|
||||
INIT_LIST_HEAD(&conn->users);
|
||||
|
||||
if (hcon->type == LE_LINK)
|
||||
INIT_DELAYED_WORK(&conn->security_timer, security_timeout);
|
||||
else
|
||||
INIT_DELAYED_WORK(&conn->info_timer, l2cap_info_timeout);
|
||||
INIT_DELAYED_WORK(&conn->info_timer, l2cap_info_timeout);
|
||||
|
||||
INIT_WORK(&conn->disconn_work, disconn_work);
|
||||
|
||||
skb_queue_head_init(&conn->pending_rx);
|
||||
INIT_WORK(&conn->pending_rx_work, process_pending_rx);
|
||||
|
@ -7239,19 +7149,99 @@ int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr)
|
|||
return exact ? lm1 : lm2;
|
||||
}
|
||||
|
||||
/* Find the next fixed channel in BT_LISTEN state, continue iteration
|
||||
* from an existing channel in the list or from the beginning of the
|
||||
* global list (by passing NULL as first parameter).
|
||||
*/
|
||||
static struct l2cap_chan *l2cap_global_fixed_chan(struct l2cap_chan *c,
|
||||
bdaddr_t *src, u8 link_type)
|
||||
{
|
||||
read_lock(&chan_list_lock);
|
||||
|
||||
if (c)
|
||||
c = list_next_entry(c, global_l);
|
||||
else
|
||||
c = list_entry(chan_list.next, typeof(*c), global_l);
|
||||
|
||||
list_for_each_entry_from(c, &chan_list, global_l) {
|
||||
if (c->chan_type != L2CAP_CHAN_FIXED)
|
||||
continue;
|
||||
if (c->state != BT_LISTEN)
|
||||
continue;
|
||||
if (bacmp(&c->src, src) && bacmp(&c->src, BDADDR_ANY))
|
||||
continue;
|
||||
if (link_type == ACL_LINK && c->src_type != BDADDR_BREDR)
|
||||
continue;
|
||||
if (link_type == LE_LINK && c->src_type == BDADDR_BREDR)
|
||||
continue;
|
||||
|
||||
l2cap_chan_hold(c);
|
||||
read_unlock(&chan_list_lock);
|
||||
return c;
|
||||
}
|
||||
|
||||
read_unlock(&chan_list_lock);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
|
||||
{
|
||||
struct hci_dev *hdev = hcon->hdev;
|
||||
struct l2cap_conn *conn;
|
||||
struct l2cap_chan *pchan;
|
||||
u8 dst_type;
|
||||
|
||||
BT_DBG("hcon %p bdaddr %pMR status %d", hcon, &hcon->dst, status);
|
||||
|
||||
if (!status) {
|
||||
conn = l2cap_conn_add(hcon);
|
||||
if (conn)
|
||||
l2cap_conn_ready(conn);
|
||||
} else {
|
||||
if (status) {
|
||||
l2cap_conn_del(hcon, bt_to_errno(status));
|
||||
return;
|
||||
}
|
||||
|
||||
conn = l2cap_conn_add(hcon);
|
||||
if (!conn)
|
||||
return;
|
||||
|
||||
dst_type = bdaddr_type(hcon, hcon->dst_type);
|
||||
|
||||
/* If device is blocked, do not create channels for it */
|
||||
if (hci_bdaddr_list_lookup(&hdev->blacklist, &hcon->dst, dst_type))
|
||||
return;
|
||||
|
||||
/* Find fixed channels and notify them of the new connection. We
|
||||
* use multiple individual lookups, continuing each time where
|
||||
* we left off, because the list lock would prevent calling the
|
||||
* potentially sleeping l2cap_chan_lock() function.
|
||||
*/
|
||||
pchan = l2cap_global_fixed_chan(NULL, &hdev->bdaddr, hcon->type);
|
||||
while (pchan) {
|
||||
struct l2cap_chan *chan, *next;
|
||||
|
||||
/* Client fixed channels should override server ones */
|
||||
if (__l2cap_get_chan_by_dcid(conn, pchan->scid))
|
||||
goto next;
|
||||
|
||||
l2cap_chan_lock(pchan);
|
||||
chan = pchan->ops->new_connection(pchan);
|
||||
if (chan) {
|
||||
bacpy(&chan->src, &hcon->src);
|
||||
bacpy(&chan->dst, &hcon->dst);
|
||||
chan->src_type = bdaddr_type(hcon, hcon->src_type);
|
||||
chan->dst_type = dst_type;
|
||||
|
||||
__l2cap_chan_add(conn, chan);
|
||||
}
|
||||
|
||||
l2cap_chan_unlock(pchan);
|
||||
next:
|
||||
next = l2cap_global_fixed_chan(pchan, &hdev->bdaddr,
|
||||
hcon->type);
|
||||
l2cap_chan_put(pchan);
|
||||
pchan = next;
|
||||
}
|
||||
|
||||
l2cap_conn_ready(conn);
|
||||
}
|
||||
|
||||
int l2cap_disconn_ind(struct hci_conn *hcon)
|
||||
|
@ -7299,12 +7289,6 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
|
|||
|
||||
BT_DBG("conn %p status 0x%2.2x encrypt %u", conn, status, encrypt);
|
||||
|
||||
if (hcon->type == LE_LINK) {
|
||||
if (!status && encrypt)
|
||||
smp_distribute_keys(conn);
|
||||
cancel_delayed_work(&conn->security_timer);
|
||||
}
|
||||
|
||||
mutex_lock(&conn->chan_lock);
|
||||
|
||||
list_for_each_entry(chan, &conn->chan_l, list) {
|
||||
|
@ -7318,15 +7302,8 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
|
|||
continue;
|
||||
}
|
||||
|
||||
if (chan->scid == L2CAP_CID_ATT) {
|
||||
if (!status && encrypt) {
|
||||
chan->sec_level = hcon->sec_level;
|
||||
l2cap_chan_ready(chan);
|
||||
}
|
||||
|
||||
l2cap_chan_unlock(chan);
|
||||
continue;
|
||||
}
|
||||
if (!status && encrypt)
|
||||
chan->sec_level = hcon->sec_level;
|
||||
|
||||
if (!__l2cap_no_conn_pending(chan)) {
|
||||
l2cap_chan_unlock(chan);
|
||||
|
|
|
@ -99,15 +99,6 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
|
|||
if (!bdaddr_type_is_valid(la.l2_bdaddr_type))
|
||||
return -EINVAL;
|
||||
|
||||
if (la.l2_cid) {
|
||||
/* When the socket gets created it defaults to
|
||||
* CHAN_CONN_ORIENTED, so we need to overwrite the
|
||||
* default here.
|
||||
*/
|
||||
chan->chan_type = L2CAP_CHAN_FIXED;
|
||||
chan->omtu = L2CAP_DEFAULT_MTU;
|
||||
}
|
||||
|
||||
if (bdaddr_type_is_le(la.l2_bdaddr_type)) {
|
||||
/* We only allow ATT user space socket */
|
||||
if (la.l2_cid &&
|
||||
|
@ -790,6 +781,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname,
|
|||
if (chan->scid == L2CAP_CID_ATT) {
|
||||
if (smp_conn_security(conn->hcon, sec.level))
|
||||
break;
|
||||
set_bit(FLAG_PENDING_SECURITY, &chan->flags);
|
||||
sk->sk_state = BT_CONFIG;
|
||||
chan->state = BT_CONFIG;
|
||||
|
||||
|
@ -1359,6 +1351,11 @@ static void l2cap_sock_resume_cb(struct l2cap_chan *chan)
|
|||
{
|
||||
struct sock *sk = chan->data;
|
||||
|
||||
if (test_and_clear_bit(FLAG_PENDING_SECURITY, &chan->flags)) {
|
||||
sk->sk_state = BT_CONNECTED;
|
||||
chan->state = BT_CONNECTED;
|
||||
}
|
||||
|
||||
clear_bit(BT_SK_SUSPEND, &bt_sk(sk)->flags);
|
||||
sk->sk_state_change(sk);
|
||||
}
|
||||
|
|
|
@ -129,9 +129,6 @@ static const u16 mgmt_events[] = {
|
|||
|
||||
#define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000)
|
||||
|
||||
#define hdev_is_powered(hdev) (test_bit(HCI_UP, &hdev->flags) && \
|
||||
!test_bit(HCI_AUTO_OFF, &hdev->dev_flags))
|
||||
|
||||
struct pending_cmd {
|
||||
struct list_head list;
|
||||
u16 opcode;
|
||||
|
@ -1536,9 +1533,11 @@ static void set_discoverable_complete(struct hci_dev *hdev, u8 status)
|
|||
|
||||
/* When the discoverable mode gets changed, make sure
|
||||
* that class of device has the limited discoverable
|
||||
* bit correctly set.
|
||||
* bit correctly set. Also update page scan based on whitelist
|
||||
* entries.
|
||||
*/
|
||||
hci_req_init(&req, hdev);
|
||||
hci_update_page_scan(hdev, &req);
|
||||
update_class(&req);
|
||||
hci_req_run(&req, NULL);
|
||||
|
||||
|
@ -1785,6 +1784,7 @@ static void set_connectable_complete(struct hci_dev *hdev, u8 status)
|
|||
|
||||
if (conn_changed || discov_changed) {
|
||||
new_settings(hdev, cmd->sk);
|
||||
hci_update_page_scan(hdev, NULL);
|
||||
if (discov_changed)
|
||||
mgmt_update_adv_data(hdev);
|
||||
hci_update_background_scan(hdev);
|
||||
|
@ -1818,6 +1818,7 @@ static int set_connectable_update_settings(struct hci_dev *hdev,
|
|||
return err;
|
||||
|
||||
if (changed) {
|
||||
hci_update_page_scan(hdev, NULL);
|
||||
hci_update_background_scan(hdev);
|
||||
return new_settings(hdev, sk);
|
||||
}
|
||||
|
@ -4381,27 +4382,6 @@ unlock:
|
|||
return err;
|
||||
}
|
||||
|
||||
static void set_bredr_scan(struct hci_request *req)
|
||||
{
|
||||
struct hci_dev *hdev = req->hdev;
|
||||
u8 scan = 0;
|
||||
|
||||
/* Ensure that fast connectable is disabled. This function will
|
||||
* not do anything if the page scan parameters are already what
|
||||
* they should be.
|
||||
*/
|
||||
write_fast_connectable(req, false);
|
||||
|
||||
if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags) ||
|
||||
!list_empty(&hdev->whitelist))
|
||||
scan |= SCAN_PAGE;
|
||||
if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
|
||||
scan |= SCAN_INQUIRY;
|
||||
|
||||
if (scan)
|
||||
hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
|
||||
}
|
||||
|
||||
static void set_bredr_complete(struct hci_dev *hdev, u8 status)
|
||||
{
|
||||
struct pending_cmd *cmd;
|
||||
|
@ -4507,9 +4487,8 @@ static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
|
|||
|
||||
hci_req_init(&req, hdev);
|
||||
|
||||
if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags) ||
|
||||
!list_empty(&hdev->whitelist))
|
||||
set_bredr_scan(&req);
|
||||
write_fast_connectable(&req, false);
|
||||
hci_update_page_scan(hdev, &req);
|
||||
|
||||
/* Since only the advertising data flags will change, there
|
||||
* is no need to update the scan response data.
|
||||
|
@ -5235,27 +5214,6 @@ unlock:
|
|||
return err;
|
||||
}
|
||||
|
||||
/* Helper for Add/Remove Device commands */
|
||||
static void update_page_scan(struct hci_dev *hdev, u8 scan)
|
||||
{
|
||||
if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
|
||||
return;
|
||||
|
||||
if (!hdev_is_powered(hdev))
|
||||
return;
|
||||
|
||||
/* If HCI_CONNECTABLE is set then Add/Remove Device should not
|
||||
* make any changes to page scanning.
|
||||
*/
|
||||
if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
|
||||
return;
|
||||
|
||||
if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
|
||||
scan |= SCAN_INQUIRY;
|
||||
|
||||
hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
|
||||
}
|
||||
|
||||
static void device_added(struct sock *sk, struct hci_dev *hdev,
|
||||
bdaddr_t *bdaddr, u8 type, u8 action)
|
||||
{
|
||||
|
@ -5291,8 +5249,6 @@ static int add_device(struct sock *sk, struct hci_dev *hdev,
|
|||
hci_dev_lock(hdev);
|
||||
|
||||
if (cp->addr.type == BDADDR_BREDR) {
|
||||
bool update_scan;
|
||||
|
||||
/* Only incoming connections action is supported for now */
|
||||
if (cp->action != 0x01) {
|
||||
err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
|
||||
|
@ -5301,15 +5257,12 @@ static int add_device(struct sock *sk, struct hci_dev *hdev,
|
|||
goto unlock;
|
||||
}
|
||||
|
||||
update_scan = list_empty(&hdev->whitelist);
|
||||
|
||||
err = hci_bdaddr_list_add(&hdev->whitelist, &cp->addr.bdaddr,
|
||||
cp->addr.type);
|
||||
if (err)
|
||||
goto unlock;
|
||||
|
||||
if (update_scan)
|
||||
update_page_scan(hdev, SCAN_PAGE);
|
||||
hci_update_page_scan(hdev, NULL);
|
||||
|
||||
goto added;
|
||||
}
|
||||
|
@ -5392,8 +5345,7 @@ static int remove_device(struct sock *sk, struct hci_dev *hdev,
|
|||
goto unlock;
|
||||
}
|
||||
|
||||
if (list_empty(&hdev->whitelist))
|
||||
update_page_scan(hdev, SCAN_DISABLED);
|
||||
hci_update_page_scan(hdev, NULL);
|
||||
|
||||
device_removed(sk, hdev, &cp->addr.bdaddr,
|
||||
cp->addr.type);
|
||||
|
@ -5444,7 +5396,7 @@ static int remove_device(struct sock *sk, struct hci_dev *hdev,
|
|||
kfree(b);
|
||||
}
|
||||
|
||||
update_page_scan(hdev, SCAN_DISABLED);
|
||||
hci_update_page_scan(hdev, NULL);
|
||||
|
||||
list_for_each_entry_safe(p, tmp, &hdev->le_conn_params, list) {
|
||||
if (p->auto_connect == HCI_AUTO_CONN_DISABLED)
|
||||
|
@ -5969,8 +5921,8 @@ static int powered_update_hci(struct hci_dev *hdev)
|
|||
sizeof(link_sec), &link_sec);
|
||||
|
||||
if (lmp_bredr_capable(hdev)) {
|
||||
if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
|
||||
set_bredr_scan(&req);
|
||||
write_fast_connectable(&req, false);
|
||||
hci_update_page_scan(hdev, &req);
|
||||
update_class(&req);
|
||||
update_name(&req);
|
||||
update_eir(&req);
|
||||
|
@ -6281,25 +6233,35 @@ static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
|
|||
mgmt_pending_remove(cmd);
|
||||
}
|
||||
|
||||
bool mgmt_powering_down(struct hci_dev *hdev)
|
||||
{
|
||||
struct pending_cmd *cmd;
|
||||
struct mgmt_mode *cp;
|
||||
|
||||
cmd = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev);
|
||||
if (!cmd)
|
||||
return false;
|
||||
|
||||
cp = cmd->param;
|
||||
if (!cp->val)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
|
||||
u8 link_type, u8 addr_type, u8 reason,
|
||||
bool mgmt_connected)
|
||||
{
|
||||
struct mgmt_ev_device_disconnected ev;
|
||||
struct pending_cmd *power_off;
|
||||
struct sock *sk = NULL;
|
||||
|
||||
power_off = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev);
|
||||
if (power_off) {
|
||||
struct mgmt_mode *cp = power_off->param;
|
||||
|
||||
/* The connection is still in hci_conn_hash so test for 1
|
||||
* instead of 0 to know if this is the last one.
|
||||
*/
|
||||
if (!cp->val && hci_conn_count(hdev) == 1) {
|
||||
cancel_delayed_work(&hdev->power_off);
|
||||
queue_work(hdev->req_workqueue, &hdev->power_off.work);
|
||||
}
|
||||
/* The connection is still in hci_conn_hash so test for 1
|
||||
* instead of 0 to know if this is the last one.
|
||||
*/
|
||||
if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) {
|
||||
cancel_delayed_work(&hdev->power_off);
|
||||
queue_work(hdev->req_workqueue, &hdev->power_off.work);
|
||||
}
|
||||
|
||||
if (!mgmt_connected)
|
||||
|
@ -6359,19 +6321,13 @@ void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
|
|||
u8 addr_type, u8 status)
|
||||
{
|
||||
struct mgmt_ev_connect_failed ev;
|
||||
struct pending_cmd *power_off;
|
||||
|
||||
power_off = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev);
|
||||
if (power_off) {
|
||||
struct mgmt_mode *cp = power_off->param;
|
||||
|
||||
/* The connection is still in hci_conn_hash so test for 1
|
||||
* instead of 0 to know if this is the last one.
|
||||
*/
|
||||
if (!cp->val && hci_conn_count(hdev) == 1) {
|
||||
cancel_delayed_work(&hdev->power_off);
|
||||
queue_work(hdev->req_workqueue, &hdev->power_off.work);
|
||||
}
|
||||
/* The connection is still in hci_conn_hash so test for 1
|
||||
* instead of 0 to know if this is the last one.
|
||||
*/
|
||||
if (mgmt_powering_down(hdev) && hci_conn_count(hdev) == 1) {
|
||||
cancel_delayed_work(&hdev->power_off);
|
||||
queue_work(hdev->req_workqueue, &hdev->power_off.work);
|
||||
}
|
||||
|
||||
bacpy(&ev.addr.bdaddr, bdaddr);
|
||||
|
|
|
@ -44,7 +44,10 @@ enum {
|
|||
};
|
||||
|
||||
struct smp_chan {
|
||||
struct l2cap_conn *conn;
|
||||
struct l2cap_conn *conn;
|
||||
struct delayed_work security_timer;
|
||||
struct work_struct distribute_work;
|
||||
|
||||
u8 preq[7]; /* SMP Pairing Request */
|
||||
u8 prsp[7]; /* SMP Pairing Response */
|
||||
u8 prnd[16]; /* SMP Pairing Random (local) */
|
||||
|
@ -139,12 +142,18 @@ static int smp_ah(struct crypto_blkcipher *tfm, u8 irk[16], u8 r[3], u8 res[3])
|
|||
return 0;
|
||||
}
|
||||
|
||||
bool smp_irk_matches(struct crypto_blkcipher *tfm, u8 irk[16],
|
||||
bdaddr_t *bdaddr)
|
||||
bool smp_irk_matches(struct hci_dev *hdev, u8 irk[16], bdaddr_t *bdaddr)
|
||||
{
|
||||
struct l2cap_chan *chan = hdev->smp_data;
|
||||
struct crypto_blkcipher *tfm;
|
||||
u8 hash[3];
|
||||
int err;
|
||||
|
||||
if (!chan || !chan->data)
|
||||
return false;
|
||||
|
||||
tfm = chan->data;
|
||||
|
||||
BT_DBG("RPA %pMR IRK %*phN", bdaddr, 16, irk);
|
||||
|
||||
err = smp_ah(tfm, irk, &bdaddr->b[3], hash);
|
||||
|
@ -154,10 +163,17 @@ bool smp_irk_matches(struct crypto_blkcipher *tfm, u8 irk[16],
|
|||
return !memcmp(bdaddr->b, hash, 3);
|
||||
}
|
||||
|
||||
int smp_generate_rpa(struct crypto_blkcipher *tfm, u8 irk[16], bdaddr_t *rpa)
|
||||
int smp_generate_rpa(struct hci_dev *hdev, u8 irk[16], bdaddr_t *rpa)
|
||||
{
|
||||
struct l2cap_chan *chan = hdev->smp_data;
|
||||
struct crypto_blkcipher *tfm;
|
||||
int err;
|
||||
|
||||
if (!chan || !chan->data)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
tfm = chan->data;
|
||||
|
||||
get_random_bytes(&rpa->b[3], 3);
|
||||
|
||||
rpa->b[5] &= 0x3f; /* Clear two most significant bits */
|
||||
|
@ -235,47 +251,39 @@ static int smp_s1(struct smp_chan *smp, u8 k[16], u8 r1[16], u8 r2[16],
|
|||
return err;
|
||||
}
|
||||
|
||||
static struct sk_buff *smp_build_cmd(struct l2cap_conn *conn, u8 code,
|
||||
u16 dlen, void *data)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
struct l2cap_hdr *lh;
|
||||
int len;
|
||||
|
||||
len = L2CAP_HDR_SIZE + sizeof(code) + dlen;
|
||||
|
||||
if (len > conn->mtu)
|
||||
return NULL;
|
||||
|
||||
skb = bt_skb_alloc(len, GFP_ATOMIC);
|
||||
if (!skb)
|
||||
return NULL;
|
||||
|
||||
lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
|
||||
lh->len = cpu_to_le16(sizeof(code) + dlen);
|
||||
lh->cid = cpu_to_le16(L2CAP_CID_SMP);
|
||||
|
||||
memcpy(skb_put(skb, sizeof(code)), &code, sizeof(code));
|
||||
|
||||
memcpy(skb_put(skb, dlen), data, dlen);
|
||||
|
||||
return skb;
|
||||
}
|
||||
|
||||
static void smp_send_cmd(struct l2cap_conn *conn, u8 code, u16 len, void *data)
|
||||
{
|
||||
struct sk_buff *skb = smp_build_cmd(conn, code, len, data);
|
||||
struct l2cap_chan *chan = conn->smp;
|
||||
struct smp_chan *smp;
|
||||
struct kvec iv[2];
|
||||
struct msghdr msg;
|
||||
|
||||
if (!chan)
|
||||
return;
|
||||
|
||||
BT_DBG("code 0x%2.2x", code);
|
||||
|
||||
if (!skb)
|
||||
iv[0].iov_base = &code;
|
||||
iv[0].iov_len = 1;
|
||||
|
||||
iv[1].iov_base = data;
|
||||
iv[1].iov_len = len;
|
||||
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
|
||||
msg.msg_iov = (struct iovec *) &iv;
|
||||
msg.msg_iovlen = 2;
|
||||
|
||||
l2cap_chan_send(chan, &msg, 1 + len);
|
||||
|
||||
if (!chan->data)
|
||||
return;
|
||||
|
||||
skb->priority = HCI_PRIO_MAX;
|
||||
hci_send_acl(conn->hchan, skb, 0);
|
||||
smp = chan->data;
|
||||
|
||||
cancel_delayed_work_sync(&conn->security_timer);
|
||||
schedule_delayed_work(&conn->security_timer, SMP_TIMEOUT);
|
||||
cancel_delayed_work_sync(&smp->security_timer);
|
||||
if (test_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags))
|
||||
schedule_delayed_work(&smp->security_timer, SMP_TIMEOUT);
|
||||
}
|
||||
|
||||
static __u8 authreq_to_seclevel(__u8 authreq)
|
||||
|
@ -302,7 +310,8 @@ static void build_pairing_cmd(struct l2cap_conn *conn,
|
|||
struct smp_cmd_pairing *req,
|
||||
struct smp_cmd_pairing *rsp, __u8 authreq)
|
||||
{
|
||||
struct smp_chan *smp = conn->smp_chan;
|
||||
struct l2cap_chan *chan = conn->smp;
|
||||
struct smp_chan *smp = chan->data;
|
||||
struct hci_conn *hcon = conn->hcon;
|
||||
struct hci_dev *hdev = hcon->hdev;
|
||||
u8 local_dist = 0, remote_dist = 0;
|
||||
|
@ -345,7 +354,8 @@ static void build_pairing_cmd(struct l2cap_conn *conn,
|
|||
|
||||
static u8 check_enc_key_size(struct l2cap_conn *conn, __u8 max_key_size)
|
||||
{
|
||||
struct smp_chan *smp = conn->smp_chan;
|
||||
struct l2cap_chan *chan = conn->smp;
|
||||
struct smp_chan *smp = chan->data;
|
||||
|
||||
if ((max_key_size > SMP_MAX_ENC_KEY_SIZE) ||
|
||||
(max_key_size < SMP_MIN_ENC_KEY_SIZE))
|
||||
|
@ -356,9 +366,61 @@ static u8 check_enc_key_size(struct l2cap_conn *conn, __u8 max_key_size)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void smp_chan_destroy(struct l2cap_conn *conn)
|
||||
{
|
||||
struct l2cap_chan *chan = conn->smp;
|
||||
struct smp_chan *smp = chan->data;
|
||||
bool complete;
|
||||
|
||||
BUG_ON(!smp);
|
||||
|
||||
cancel_delayed_work_sync(&smp->security_timer);
|
||||
/* In case the timeout freed the SMP context */
|
||||
if (!chan->data)
|
||||
return;
|
||||
|
||||
if (work_pending(&smp->distribute_work)) {
|
||||
cancel_work_sync(&smp->distribute_work);
|
||||
if (!chan->data)
|
||||
return;
|
||||
}
|
||||
|
||||
complete = test_bit(SMP_FLAG_COMPLETE, &smp->flags);
|
||||
mgmt_smp_complete(conn->hcon, complete);
|
||||
|
||||
kfree(smp->csrk);
|
||||
kfree(smp->slave_csrk);
|
||||
|
||||
crypto_free_blkcipher(smp->tfm_aes);
|
||||
|
||||
/* If pairing failed clean up any keys we might have */
|
||||
if (!complete) {
|
||||
if (smp->ltk) {
|
||||
list_del(&smp->ltk->list);
|
||||
kfree(smp->ltk);
|
||||
}
|
||||
|
||||
if (smp->slave_ltk) {
|
||||
list_del(&smp->slave_ltk->list);
|
||||
kfree(smp->slave_ltk);
|
||||
}
|
||||
|
||||
if (smp->remote_irk) {
|
||||
list_del(&smp->remote_irk->list);
|
||||
kfree(smp->remote_irk);
|
||||
}
|
||||
}
|
||||
|
||||
chan->data = NULL;
|
||||
kfree(smp);
|
||||
hci_conn_drop(conn->hcon);
|
||||
}
|
||||
|
||||
static void smp_failure(struct l2cap_conn *conn, u8 reason)
|
||||
{
|
||||
struct hci_conn *hcon = conn->hcon;
|
||||
struct l2cap_chan *chan = conn->smp;
|
||||
struct smp_chan *smp;
|
||||
|
||||
if (reason)
|
||||
smp_send_cmd(conn, SMP_CMD_PAIRING_FAIL, sizeof(reason),
|
||||
|
@ -368,7 +430,10 @@ static void smp_failure(struct l2cap_conn *conn, u8 reason)
|
|||
mgmt_auth_failed(hcon->hdev, &hcon->dst, hcon->type, hcon->dst_type,
|
||||
HCI_ERROR_AUTH_FAILURE);
|
||||
|
||||
cancel_delayed_work_sync(&conn->security_timer);
|
||||
if (!chan->data)
|
||||
return;
|
||||
|
||||
smp = chan->data;
|
||||
|
||||
if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags))
|
||||
smp_chan_destroy(conn);
|
||||
|
@ -405,7 +470,8 @@ static int tk_request(struct l2cap_conn *conn, u8 remote_oob, u8 auth,
|
|||
u8 local_io, u8 remote_io)
|
||||
{
|
||||
struct hci_conn *hcon = conn->hcon;
|
||||
struct smp_chan *smp = conn->smp_chan;
|
||||
struct l2cap_chan *chan = conn->smp;
|
||||
struct smp_chan *smp = chan->data;
|
||||
u8 method;
|
||||
u32 passkey = 0;
|
||||
int ret = 0;
|
||||
|
@ -574,8 +640,201 @@ static u8 smp_random(struct smp_chan *smp)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void smp_notify_keys(struct l2cap_conn *conn)
|
||||
{
|
||||
struct l2cap_chan *chan = conn->smp;
|
||||
struct smp_chan *smp = chan->data;
|
||||
struct hci_conn *hcon = conn->hcon;
|
||||
struct hci_dev *hdev = hcon->hdev;
|
||||
struct smp_cmd_pairing *req = (void *) &smp->preq[1];
|
||||
struct smp_cmd_pairing *rsp = (void *) &smp->prsp[1];
|
||||
bool persistent;
|
||||
|
||||
if (smp->remote_irk) {
|
||||
mgmt_new_irk(hdev, smp->remote_irk);
|
||||
/* Now that user space can be considered to know the
|
||||
* identity address track the connection based on it
|
||||
* from now on.
|
||||
*/
|
||||
bacpy(&hcon->dst, &smp->remote_irk->bdaddr);
|
||||
hcon->dst_type = smp->remote_irk->addr_type;
|
||||
l2cap_conn_update_id_addr(hcon);
|
||||
|
||||
/* When receiving an indentity resolving key for
|
||||
* a remote device that does not use a resolvable
|
||||
* private address, just remove the key so that
|
||||
* it is possible to use the controller white
|
||||
* list for scanning.
|
||||
*
|
||||
* Userspace will have been told to not store
|
||||
* this key at this point. So it is safe to
|
||||
* just remove it.
|
||||
*/
|
||||
if (!bacmp(&smp->remote_irk->rpa, BDADDR_ANY)) {
|
||||
list_del(&smp->remote_irk->list);
|
||||
kfree(smp->remote_irk);
|
||||
smp->remote_irk = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* The LTKs and CSRKs should be persistent only if both sides
|
||||
* had the bonding bit set in their authentication requests.
|
||||
*/
|
||||
persistent = !!((req->auth_req & rsp->auth_req) & SMP_AUTH_BONDING);
|
||||
|
||||
if (smp->csrk) {
|
||||
smp->csrk->bdaddr_type = hcon->dst_type;
|
||||
bacpy(&smp->csrk->bdaddr, &hcon->dst);
|
||||
mgmt_new_csrk(hdev, smp->csrk, persistent);
|
||||
}
|
||||
|
||||
if (smp->slave_csrk) {
|
||||
smp->slave_csrk->bdaddr_type = hcon->dst_type;
|
||||
bacpy(&smp->slave_csrk->bdaddr, &hcon->dst);
|
||||
mgmt_new_csrk(hdev, smp->slave_csrk, persistent);
|
||||
}
|
||||
|
||||
if (smp->ltk) {
|
||||
smp->ltk->bdaddr_type = hcon->dst_type;
|
||||
bacpy(&smp->ltk->bdaddr, &hcon->dst);
|
||||
mgmt_new_ltk(hdev, smp->ltk, persistent);
|
||||
}
|
||||
|
||||
if (smp->slave_ltk) {
|
||||
smp->slave_ltk->bdaddr_type = hcon->dst_type;
|
||||
bacpy(&smp->slave_ltk->bdaddr, &hcon->dst);
|
||||
mgmt_new_ltk(hdev, smp->slave_ltk, persistent);
|
||||
}
|
||||
}
|
||||
|
||||
static void smp_distribute_keys(struct work_struct *work)
|
||||
{
|
||||
struct smp_chan *smp = container_of(work, struct smp_chan,
|
||||
distribute_work);
|
||||
struct smp_cmd_pairing *req, *rsp;
|
||||
struct l2cap_conn *conn = smp->conn;
|
||||
struct hci_conn *hcon = conn->hcon;
|
||||
struct hci_dev *hdev = hcon->hdev;
|
||||
__u8 *keydist;
|
||||
|
||||
BT_DBG("conn %p", conn);
|
||||
|
||||
if (!test_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags))
|
||||
return;
|
||||
|
||||
rsp = (void *) &smp->prsp[1];
|
||||
|
||||
/* The responder sends its keys first */
|
||||
if (hcon->out && (smp->remote_key_dist & 0x07))
|
||||
return;
|
||||
|
||||
req = (void *) &smp->preq[1];
|
||||
|
||||
if (hcon->out) {
|
||||
keydist = &rsp->init_key_dist;
|
||||
*keydist &= req->init_key_dist;
|
||||
} else {
|
||||
keydist = &rsp->resp_key_dist;
|
||||
*keydist &= req->resp_key_dist;
|
||||
}
|
||||
|
||||
BT_DBG("keydist 0x%x", *keydist);
|
||||
|
||||
if (*keydist & SMP_DIST_ENC_KEY) {
|
||||
struct smp_cmd_encrypt_info enc;
|
||||
struct smp_cmd_master_ident ident;
|
||||
struct smp_ltk *ltk;
|
||||
u8 authenticated;
|
||||
__le16 ediv;
|
||||
__le64 rand;
|
||||
|
||||
get_random_bytes(enc.ltk, sizeof(enc.ltk));
|
||||
get_random_bytes(&ediv, sizeof(ediv));
|
||||
get_random_bytes(&rand, sizeof(rand));
|
||||
|
||||
smp_send_cmd(conn, SMP_CMD_ENCRYPT_INFO, sizeof(enc), &enc);
|
||||
|
||||
authenticated = hcon->sec_level == BT_SECURITY_HIGH;
|
||||
ltk = hci_add_ltk(hdev, &hcon->dst, hcon->dst_type,
|
||||
SMP_LTK_SLAVE, authenticated, enc.ltk,
|
||||
smp->enc_key_size, ediv, rand);
|
||||
smp->slave_ltk = ltk;
|
||||
|
||||
ident.ediv = ediv;
|
||||
ident.rand = rand;
|
||||
|
||||
smp_send_cmd(conn, SMP_CMD_MASTER_IDENT, sizeof(ident), &ident);
|
||||
|
||||
*keydist &= ~SMP_DIST_ENC_KEY;
|
||||
}
|
||||
|
||||
if (*keydist & SMP_DIST_ID_KEY) {
|
||||
struct smp_cmd_ident_addr_info addrinfo;
|
||||
struct smp_cmd_ident_info idinfo;
|
||||
|
||||
memcpy(idinfo.irk, hdev->irk, sizeof(idinfo.irk));
|
||||
|
||||
smp_send_cmd(conn, SMP_CMD_IDENT_INFO, sizeof(idinfo), &idinfo);
|
||||
|
||||
/* The hci_conn contains the local identity address
|
||||
* after the connection has been established.
|
||||
*
|
||||
* This is true even when the connection has been
|
||||
* established using a resolvable random address.
|
||||
*/
|
||||
bacpy(&addrinfo.bdaddr, &hcon->src);
|
||||
addrinfo.addr_type = hcon->src_type;
|
||||
|
||||
smp_send_cmd(conn, SMP_CMD_IDENT_ADDR_INFO, sizeof(addrinfo),
|
||||
&addrinfo);
|
||||
|
||||
*keydist &= ~SMP_DIST_ID_KEY;
|
||||
}
|
||||
|
||||
if (*keydist & SMP_DIST_SIGN) {
|
||||
struct smp_cmd_sign_info sign;
|
||||
struct smp_csrk *csrk;
|
||||
|
||||
/* Generate a new random key */
|
||||
get_random_bytes(sign.csrk, sizeof(sign.csrk));
|
||||
|
||||
csrk = kzalloc(sizeof(*csrk), GFP_KERNEL);
|
||||
if (csrk) {
|
||||
csrk->master = 0x00;
|
||||
memcpy(csrk->val, sign.csrk, sizeof(csrk->val));
|
||||
}
|
||||
smp->slave_csrk = csrk;
|
||||
|
||||
smp_send_cmd(conn, SMP_CMD_SIGN_INFO, sizeof(sign), &sign);
|
||||
|
||||
*keydist &= ~SMP_DIST_SIGN;
|
||||
}
|
||||
|
||||
/* If there are still keys to be received wait for them */
|
||||
if ((smp->remote_key_dist & 0x07))
|
||||
return;
|
||||
|
||||
clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags);
|
||||
set_bit(SMP_FLAG_COMPLETE, &smp->flags);
|
||||
smp_notify_keys(conn);
|
||||
|
||||
smp_chan_destroy(conn);
|
||||
}
|
||||
|
||||
static void smp_timeout(struct work_struct *work)
|
||||
{
|
||||
struct smp_chan *smp = container_of(work, struct smp_chan,
|
||||
security_timer.work);
|
||||
struct l2cap_conn *conn = smp->conn;
|
||||
|
||||
BT_DBG("conn %p", conn);
|
||||
|
||||
l2cap_conn_shutdown(conn, ETIMEDOUT);
|
||||
}
|
||||
|
||||
static struct smp_chan *smp_chan_create(struct l2cap_conn *conn)
|
||||
{
|
||||
struct l2cap_chan *chan = conn->smp;
|
||||
struct smp_chan *smp;
|
||||
|
||||
smp = kzalloc(sizeof(*smp), GFP_ATOMIC);
|
||||
|
@ -593,54 +852,20 @@ static struct smp_chan *smp_chan_create(struct l2cap_conn *conn)
|
|||
}
|
||||
|
||||
smp->conn = conn;
|
||||
conn->smp_chan = smp;
|
||||
chan->data = smp;
|
||||
|
||||
INIT_WORK(&smp->distribute_work, smp_distribute_keys);
|
||||
INIT_DELAYED_WORK(&smp->security_timer, smp_timeout);
|
||||
|
||||
hci_conn_hold(conn->hcon);
|
||||
|
||||
return smp;
|
||||
}
|
||||
|
||||
void smp_chan_destroy(struct l2cap_conn *conn)
|
||||
{
|
||||
struct smp_chan *smp = conn->smp_chan;
|
||||
bool complete;
|
||||
|
||||
BUG_ON(!smp);
|
||||
|
||||
complete = test_bit(SMP_FLAG_COMPLETE, &smp->flags);
|
||||
mgmt_smp_complete(conn->hcon, complete);
|
||||
|
||||
kfree(smp->csrk);
|
||||
kfree(smp->slave_csrk);
|
||||
|
||||
crypto_free_blkcipher(smp->tfm_aes);
|
||||
|
||||
/* If pairing failed clean up any keys we might have */
|
||||
if (!complete) {
|
||||
if (smp->ltk) {
|
||||
list_del(&smp->ltk->list);
|
||||
kfree(smp->ltk);
|
||||
}
|
||||
|
||||
if (smp->slave_ltk) {
|
||||
list_del(&smp->slave_ltk->list);
|
||||
kfree(smp->slave_ltk);
|
||||
}
|
||||
|
||||
if (smp->remote_irk) {
|
||||
list_del(&smp->remote_irk->list);
|
||||
kfree(smp->remote_irk);
|
||||
}
|
||||
}
|
||||
|
||||
kfree(smp);
|
||||
conn->smp_chan = NULL;
|
||||
hci_conn_drop(conn->hcon);
|
||||
}
|
||||
|
||||
int smp_user_confirm_reply(struct hci_conn *hcon, u16 mgmt_op, __le32 passkey)
|
||||
{
|
||||
struct l2cap_conn *conn = hcon->l2cap_data;
|
||||
struct l2cap_chan *chan;
|
||||
struct smp_chan *smp;
|
||||
u32 value;
|
||||
|
||||
|
@ -649,7 +874,11 @@ int smp_user_confirm_reply(struct hci_conn *hcon, u16 mgmt_op, __le32 passkey)
|
|||
if (!conn || !test_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags))
|
||||
return -ENOTCONN;
|
||||
|
||||
smp = conn->smp_chan;
|
||||
chan = conn->smp;
|
||||
if (!chan)
|
||||
return -ENOTCONN;
|
||||
|
||||
smp = chan->data;
|
||||
|
||||
switch (mgmt_op) {
|
||||
case MGMT_OP_USER_PASSKEY_REPLY:
|
||||
|
@ -696,10 +925,12 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
|
|||
if (conn->hcon->role != HCI_ROLE_SLAVE)
|
||||
return SMP_CMD_NOTSUPP;
|
||||
|
||||
if (!test_and_set_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags))
|
||||
if (!test_and_set_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags)) {
|
||||
smp = smp_chan_create(conn);
|
||||
else
|
||||
smp = conn->smp_chan;
|
||||
} else {
|
||||
struct l2cap_chan *chan = conn->smp;
|
||||
smp = chan->data;
|
||||
}
|
||||
|
||||
if (!smp)
|
||||
return SMP_UNSPECIFIED;
|
||||
|
@ -753,7 +984,8 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
|
|||
static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb)
|
||||
{
|
||||
struct smp_cmd_pairing *req, *rsp = (void *) skb->data;
|
||||
struct smp_chan *smp = conn->smp_chan;
|
||||
struct l2cap_chan *chan = conn->smp;
|
||||
struct smp_chan *smp = chan->data;
|
||||
u8 key_size, auth = SMP_AUTH_NONE;
|
||||
int ret;
|
||||
|
||||
|
@ -814,7 +1046,8 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb)
|
|||
|
||||
static u8 smp_cmd_pairing_confirm(struct l2cap_conn *conn, struct sk_buff *skb)
|
||||
{
|
||||
struct smp_chan *smp = conn->smp_chan;
|
||||
struct l2cap_chan *chan = conn->smp;
|
||||
struct smp_chan *smp = chan->data;
|
||||
|
||||
BT_DBG("conn %p %s", conn, conn->hcon->out ? "master" : "slave");
|
||||
|
||||
|
@ -837,7 +1070,8 @@ static u8 smp_cmd_pairing_confirm(struct l2cap_conn *conn, struct sk_buff *skb)
|
|||
|
||||
static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb)
|
||||
{
|
||||
struct smp_chan *smp = conn->smp_chan;
|
||||
struct l2cap_chan *chan = conn->smp;
|
||||
struct smp_chan *smp = chan->data;
|
||||
|
||||
BT_DBG("conn %p", conn);
|
||||
|
||||
|
@ -1010,7 +1244,8 @@ int smp_conn_security(struct hci_conn *hcon, __u8 sec_level)
|
|||
static int smp_cmd_encrypt_info(struct l2cap_conn *conn, struct sk_buff *skb)
|
||||
{
|
||||
struct smp_cmd_encrypt_info *rp = (void *) skb->data;
|
||||
struct smp_chan *smp = conn->smp_chan;
|
||||
struct l2cap_chan *chan = conn->smp;
|
||||
struct smp_chan *smp = chan->data;
|
||||
|
||||
BT_DBG("conn %p", conn);
|
||||
|
||||
|
@ -1031,7 +1266,8 @@ static int smp_cmd_encrypt_info(struct l2cap_conn *conn, struct sk_buff *skb)
|
|||
static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb)
|
||||
{
|
||||
struct smp_cmd_master_ident *rp = (void *) skb->data;
|
||||
struct smp_chan *smp = conn->smp_chan;
|
||||
struct l2cap_chan *chan = conn->smp;
|
||||
struct smp_chan *smp = chan->data;
|
||||
struct hci_dev *hdev = conn->hcon->hdev;
|
||||
struct hci_conn *hcon = conn->hcon;
|
||||
struct smp_ltk *ltk;
|
||||
|
@ -1058,7 +1294,7 @@ static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb)
|
|||
rp->ediv, rp->rand);
|
||||
smp->ltk = ltk;
|
||||
if (!(smp->remote_key_dist & SMP_DIST_ID_KEY))
|
||||
smp_distribute_keys(conn);
|
||||
queue_work(hdev->workqueue, &smp->distribute_work);
|
||||
hci_dev_unlock(hdev);
|
||||
|
||||
return 0;
|
||||
|
@ -1067,7 +1303,8 @@ static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb)
|
|||
static int smp_cmd_ident_info(struct l2cap_conn *conn, struct sk_buff *skb)
|
||||
{
|
||||
struct smp_cmd_ident_info *info = (void *) skb->data;
|
||||
struct smp_chan *smp = conn->smp_chan;
|
||||
struct l2cap_chan *chan = conn->smp;
|
||||
struct smp_chan *smp = chan->data;
|
||||
|
||||
BT_DBG("");
|
||||
|
||||
|
@ -1089,8 +1326,10 @@ static int smp_cmd_ident_addr_info(struct l2cap_conn *conn,
|
|||
struct sk_buff *skb)
|
||||
{
|
||||
struct smp_cmd_ident_addr_info *info = (void *) skb->data;
|
||||
struct smp_chan *smp = conn->smp_chan;
|
||||
struct l2cap_chan *chan = conn->smp;
|
||||
struct smp_chan *smp = chan->data;
|
||||
struct hci_conn *hcon = conn->hcon;
|
||||
struct hci_dev *hdev = hcon->hdev;
|
||||
bdaddr_t rpa;
|
||||
|
||||
BT_DBG("");
|
||||
|
@ -1133,7 +1372,7 @@ static int smp_cmd_ident_addr_info(struct l2cap_conn *conn,
|
|||
smp->id_addr_type, smp->irk, &rpa);
|
||||
|
||||
distribute:
|
||||
smp_distribute_keys(conn);
|
||||
queue_work(hdev->workqueue, &smp->distribute_work);
|
||||
|
||||
hci_dev_unlock(hcon->hdev);
|
||||
|
||||
|
@ -1143,7 +1382,8 @@ distribute:
|
|||
static int smp_cmd_sign_info(struct l2cap_conn *conn, struct sk_buff *skb)
|
||||
{
|
||||
struct smp_cmd_sign_info *rp = (void *) skb->data;
|
||||
struct smp_chan *smp = conn->smp_chan;
|
||||
struct l2cap_chan *chan = conn->smp;
|
||||
struct smp_chan *smp = chan->data;
|
||||
struct hci_dev *hdev = conn->hcon->hdev;
|
||||
struct smp_csrk *csrk;
|
||||
|
||||
|
@ -1168,15 +1408,15 @@ static int smp_cmd_sign_info(struct l2cap_conn *conn, struct sk_buff *skb)
|
|||
memcpy(csrk->val, rp->csrk, sizeof(csrk->val));
|
||||
}
|
||||
smp->csrk = csrk;
|
||||
if (!(smp->remote_key_dist & SMP_DIST_SIGN))
|
||||
smp_distribute_keys(conn);
|
||||
queue_work(hdev->workqueue, &smp->distribute_work);
|
||||
hci_dev_unlock(hdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb)
|
||||
static int smp_sig_channel(struct l2cap_chan *chan, struct sk_buff *skb)
|
||||
{
|
||||
struct l2cap_conn *conn = chan->conn;
|
||||
struct hci_conn *hcon = conn->hcon;
|
||||
__u8 code, reason;
|
||||
int err = 0;
|
||||
|
@ -1186,10 +1426,8 @@ int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb)
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (skb->len < 1) {
|
||||
kfree_skb(skb);
|
||||
if (skb->len < 1)
|
||||
return -EILSEQ;
|
||||
}
|
||||
|
||||
if (!test_bit(HCI_LE_ENABLED, &hcon->hdev->dev_flags)) {
|
||||
err = -EOPNOTSUPP;
|
||||
|
@ -1207,10 +1445,11 @@ int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb)
|
|||
* returns an error).
|
||||
*/
|
||||
if (code != SMP_CMD_PAIRING_REQ && code != SMP_CMD_SECURITY_REQ &&
|
||||
!conn->smp_chan) {
|
||||
!test_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags)) {
|
||||
BT_ERR("Unexpected SMP command 0x%02x. Disconnecting.", code);
|
||||
kfree_skb(skb);
|
||||
return -EOPNOTSUPP;
|
||||
reason = SMP_CMD_NOTSUPP;
|
||||
err = -EOPNOTSUPP;
|
||||
goto done;
|
||||
}
|
||||
|
||||
switch (code) {
|
||||
|
@ -1271,188 +1510,201 @@ int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb)
|
|||
done:
|
||||
if (reason)
|
||||
smp_failure(conn, reason);
|
||||
|
||||
kfree_skb(skb);
|
||||
if (!err)
|
||||
kfree_skb(skb);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void smp_notify_keys(struct l2cap_conn *conn)
|
||||
static void smp_teardown_cb(struct l2cap_chan *chan, int err)
|
||||
{
|
||||
struct smp_chan *smp = conn->smp_chan;
|
||||
struct hci_conn *hcon = conn->hcon;
|
||||
struct hci_dev *hdev = hcon->hdev;
|
||||
struct smp_cmd_pairing *req = (void *) &smp->preq[1];
|
||||
struct smp_cmd_pairing *rsp = (void *) &smp->prsp[1];
|
||||
bool persistent;
|
||||
struct l2cap_conn *conn = chan->conn;
|
||||
|
||||
if (smp->remote_irk) {
|
||||
mgmt_new_irk(hdev, smp->remote_irk);
|
||||
/* Now that user space can be considered to know the
|
||||
* identity address track the connection based on it
|
||||
* from now on.
|
||||
*/
|
||||
bacpy(&hcon->dst, &smp->remote_irk->bdaddr);
|
||||
hcon->dst_type = smp->remote_irk->addr_type;
|
||||
l2cap_conn_update_id_addr(hcon);
|
||||
BT_DBG("chan %p", chan);
|
||||
|
||||
/* When receiving an indentity resolving key for
|
||||
* a remote device that does not use a resolvable
|
||||
* private address, just remove the key so that
|
||||
* it is possible to use the controller white
|
||||
* list for scanning.
|
||||
*
|
||||
* Userspace will have been told to not store
|
||||
* this key at this point. So it is safe to
|
||||
* just remove it.
|
||||
*/
|
||||
if (!bacmp(&smp->remote_irk->rpa, BDADDR_ANY)) {
|
||||
list_del(&smp->remote_irk->list);
|
||||
kfree(smp->remote_irk);
|
||||
smp->remote_irk = NULL;
|
||||
}
|
||||
}
|
||||
if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags))
|
||||
smp_chan_destroy(conn);
|
||||
|
||||
/* The LTKs and CSRKs should be persistent only if both sides
|
||||
* had the bonding bit set in their authentication requests.
|
||||
*/
|
||||
persistent = !!((req->auth_req & rsp->auth_req) & SMP_AUTH_BONDING);
|
||||
|
||||
if (smp->csrk) {
|
||||
smp->csrk->bdaddr_type = hcon->dst_type;
|
||||
bacpy(&smp->csrk->bdaddr, &hcon->dst);
|
||||
mgmt_new_csrk(hdev, smp->csrk, persistent);
|
||||
}
|
||||
|
||||
if (smp->slave_csrk) {
|
||||
smp->slave_csrk->bdaddr_type = hcon->dst_type;
|
||||
bacpy(&smp->slave_csrk->bdaddr, &hcon->dst);
|
||||
mgmt_new_csrk(hdev, smp->slave_csrk, persistent);
|
||||
}
|
||||
|
||||
if (smp->ltk) {
|
||||
smp->ltk->bdaddr_type = hcon->dst_type;
|
||||
bacpy(&smp->ltk->bdaddr, &hcon->dst);
|
||||
mgmt_new_ltk(hdev, smp->ltk, persistent);
|
||||
}
|
||||
|
||||
if (smp->slave_ltk) {
|
||||
smp->slave_ltk->bdaddr_type = hcon->dst_type;
|
||||
bacpy(&smp->slave_ltk->bdaddr, &hcon->dst);
|
||||
mgmt_new_ltk(hdev, smp->slave_ltk, persistent);
|
||||
}
|
||||
conn->smp = NULL;
|
||||
l2cap_chan_put(chan);
|
||||
}
|
||||
|
||||
int smp_distribute_keys(struct l2cap_conn *conn)
|
||||
static void smp_resume_cb(struct l2cap_chan *chan)
|
||||
{
|
||||
struct smp_cmd_pairing *req, *rsp;
|
||||
struct smp_chan *smp = conn->smp_chan;
|
||||
struct smp_chan *smp = chan->data;
|
||||
struct l2cap_conn *conn = chan->conn;
|
||||
struct hci_conn *hcon = conn->hcon;
|
||||
struct hci_dev *hdev = hcon->hdev;
|
||||
__u8 *keydist;
|
||||
|
||||
BT_DBG("conn %p", conn);
|
||||
BT_DBG("chan %p", chan);
|
||||
|
||||
if (!test_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags))
|
||||
return 0;
|
||||
if (!smp)
|
||||
return;
|
||||
|
||||
rsp = (void *) &smp->prsp[1];
|
||||
cancel_delayed_work(&smp->security_timer);
|
||||
|
||||
/* The responder sends its keys first */
|
||||
if (hcon->out && (smp->remote_key_dist & 0x07))
|
||||
return 0;
|
||||
if (test_bit(HCI_CONN_ENCRYPT, &hcon->flags))
|
||||
queue_work(hdev->workqueue, &smp->distribute_work);
|
||||
}
|
||||
|
||||
req = (void *) &smp->preq[1];
|
||||
static void smp_ready_cb(struct l2cap_chan *chan)
|
||||
{
|
||||
struct l2cap_conn *conn = chan->conn;
|
||||
|
||||
if (hcon->out) {
|
||||
keydist = &rsp->init_key_dist;
|
||||
*keydist &= req->init_key_dist;
|
||||
} else {
|
||||
keydist = &rsp->resp_key_dist;
|
||||
*keydist &= req->resp_key_dist;
|
||||
BT_DBG("chan %p", chan);
|
||||
|
||||
conn->smp = chan;
|
||||
l2cap_chan_hold(chan);
|
||||
}
|
||||
|
||||
static int smp_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb)
|
||||
{
|
||||
int err;
|
||||
|
||||
BT_DBG("chan %p", chan);
|
||||
|
||||
err = smp_sig_channel(chan, skb);
|
||||
if (err) {
|
||||
struct smp_chan *smp = chan->data;
|
||||
|
||||
if (smp)
|
||||
cancel_delayed_work_sync(&smp->security_timer);
|
||||
|
||||
l2cap_conn_shutdown(chan->conn, -err);
|
||||
}
|
||||
|
||||
BT_DBG("keydist 0x%x", *keydist);
|
||||
return err;
|
||||
}
|
||||
|
||||
if (*keydist & SMP_DIST_ENC_KEY) {
|
||||
struct smp_cmd_encrypt_info enc;
|
||||
struct smp_cmd_master_ident ident;
|
||||
struct smp_ltk *ltk;
|
||||
u8 authenticated;
|
||||
__le16 ediv;
|
||||
__le64 rand;
|
||||
static struct sk_buff *smp_alloc_skb_cb(struct l2cap_chan *chan,
|
||||
unsigned long hdr_len,
|
||||
unsigned long len, int nb)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
|
||||
get_random_bytes(enc.ltk, sizeof(enc.ltk));
|
||||
get_random_bytes(&ediv, sizeof(ediv));
|
||||
get_random_bytes(&rand, sizeof(rand));
|
||||
skb = bt_skb_alloc(hdr_len + len, GFP_KERNEL);
|
||||
if (!skb)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
smp_send_cmd(conn, SMP_CMD_ENCRYPT_INFO, sizeof(enc), &enc);
|
||||
skb->priority = HCI_PRIO_MAX;
|
||||
bt_cb(skb)->chan = chan;
|
||||
|
||||
authenticated = hcon->sec_level == BT_SECURITY_HIGH;
|
||||
ltk = hci_add_ltk(hdev, &hcon->dst, hcon->dst_type,
|
||||
SMP_LTK_SLAVE, authenticated, enc.ltk,
|
||||
smp->enc_key_size, ediv, rand);
|
||||
smp->slave_ltk = ltk;
|
||||
return skb;
|
||||
}
|
||||
|
||||
ident.ediv = ediv;
|
||||
ident.rand = rand;
|
||||
static const struct l2cap_ops smp_chan_ops = {
|
||||
.name = "Security Manager",
|
||||
.ready = smp_ready_cb,
|
||||
.recv = smp_recv_cb,
|
||||
.alloc_skb = smp_alloc_skb_cb,
|
||||
.teardown = smp_teardown_cb,
|
||||
.resume = smp_resume_cb,
|
||||
|
||||
smp_send_cmd(conn, SMP_CMD_MASTER_IDENT, sizeof(ident), &ident);
|
||||
.new_connection = l2cap_chan_no_new_connection,
|
||||
.state_change = l2cap_chan_no_state_change,
|
||||
.close = l2cap_chan_no_close,
|
||||
.defer = l2cap_chan_no_defer,
|
||||
.suspend = l2cap_chan_no_suspend,
|
||||
.set_shutdown = l2cap_chan_no_set_shutdown,
|
||||
.get_sndtimeo = l2cap_chan_no_get_sndtimeo,
|
||||
.memcpy_fromiovec = l2cap_chan_no_memcpy_fromiovec,
|
||||
};
|
||||
|
||||
*keydist &= ~SMP_DIST_ENC_KEY;
|
||||
static inline struct l2cap_chan *smp_new_conn_cb(struct l2cap_chan *pchan)
|
||||
{
|
||||
struct l2cap_chan *chan;
|
||||
|
||||
BT_DBG("pchan %p", pchan);
|
||||
|
||||
chan = l2cap_chan_create();
|
||||
if (!chan)
|
||||
return NULL;
|
||||
|
||||
chan->chan_type = pchan->chan_type;
|
||||
chan->ops = &smp_chan_ops;
|
||||
chan->scid = pchan->scid;
|
||||
chan->dcid = chan->scid;
|
||||
chan->imtu = pchan->imtu;
|
||||
chan->omtu = pchan->omtu;
|
||||
chan->mode = pchan->mode;
|
||||
|
||||
BT_DBG("created chan %p", chan);
|
||||
|
||||
return chan;
|
||||
}
|
||||
|
||||
static const struct l2cap_ops smp_root_chan_ops = {
|
||||
.name = "Security Manager Root",
|
||||
.new_connection = smp_new_conn_cb,
|
||||
|
||||
/* None of these are implemented for the root channel */
|
||||
.close = l2cap_chan_no_close,
|
||||
.alloc_skb = l2cap_chan_no_alloc_skb,
|
||||
.recv = l2cap_chan_no_recv,
|
||||
.state_change = l2cap_chan_no_state_change,
|
||||
.teardown = l2cap_chan_no_teardown,
|
||||
.ready = l2cap_chan_no_ready,
|
||||
.defer = l2cap_chan_no_defer,
|
||||
.suspend = l2cap_chan_no_suspend,
|
||||
.resume = l2cap_chan_no_resume,
|
||||
.set_shutdown = l2cap_chan_no_set_shutdown,
|
||||
.get_sndtimeo = l2cap_chan_no_get_sndtimeo,
|
||||
.memcpy_fromiovec = l2cap_chan_no_memcpy_fromiovec,
|
||||
};
|
||||
|
||||
int smp_register(struct hci_dev *hdev)
|
||||
{
|
||||
struct l2cap_chan *chan;
|
||||
struct crypto_blkcipher *tfm_aes;
|
||||
|
||||
BT_DBG("%s", hdev->name);
|
||||
|
||||
tfm_aes = crypto_alloc_blkcipher("ecb(aes)", 0, CRYPTO_ALG_ASYNC);
|
||||
if (IS_ERR(tfm_aes)) {
|
||||
int err = PTR_ERR(tfm_aes);
|
||||
BT_ERR("Unable to create crypto context");
|
||||
return err;
|
||||
}
|
||||
|
||||
if (*keydist & SMP_DIST_ID_KEY) {
|
||||
struct smp_cmd_ident_addr_info addrinfo;
|
||||
struct smp_cmd_ident_info idinfo;
|
||||
|
||||
memcpy(idinfo.irk, hdev->irk, sizeof(idinfo.irk));
|
||||
|
||||
smp_send_cmd(conn, SMP_CMD_IDENT_INFO, sizeof(idinfo), &idinfo);
|
||||
|
||||
/* The hci_conn contains the local identity address
|
||||
* after the connection has been established.
|
||||
*
|
||||
* This is true even when the connection has been
|
||||
* established using a resolvable random address.
|
||||
*/
|
||||
bacpy(&addrinfo.bdaddr, &hcon->src);
|
||||
addrinfo.addr_type = hcon->src_type;
|
||||
|
||||
smp_send_cmd(conn, SMP_CMD_IDENT_ADDR_INFO, sizeof(addrinfo),
|
||||
&addrinfo);
|
||||
|
||||
*keydist &= ~SMP_DIST_ID_KEY;
|
||||
chan = l2cap_chan_create();
|
||||
if (!chan) {
|
||||
crypto_free_blkcipher(tfm_aes);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (*keydist & SMP_DIST_SIGN) {
|
||||
struct smp_cmd_sign_info sign;
|
||||
struct smp_csrk *csrk;
|
||||
chan->data = tfm_aes;
|
||||
|
||||
/* Generate a new random key */
|
||||
get_random_bytes(sign.csrk, sizeof(sign.csrk));
|
||||
l2cap_add_scid(chan, L2CAP_CID_SMP);
|
||||
|
||||
csrk = kzalloc(sizeof(*csrk), GFP_KERNEL);
|
||||
if (csrk) {
|
||||
csrk->master = 0x00;
|
||||
memcpy(csrk->val, sign.csrk, sizeof(csrk->val));
|
||||
}
|
||||
smp->slave_csrk = csrk;
|
||||
l2cap_chan_set_defaults(chan);
|
||||
|
||||
smp_send_cmd(conn, SMP_CMD_SIGN_INFO, sizeof(sign), &sign);
|
||||
bacpy(&chan->src, &hdev->bdaddr);
|
||||
chan->src_type = BDADDR_LE_PUBLIC;
|
||||
chan->state = BT_LISTEN;
|
||||
chan->mode = L2CAP_MODE_BASIC;
|
||||
chan->imtu = L2CAP_DEFAULT_MTU;
|
||||
chan->ops = &smp_root_chan_ops;
|
||||
|
||||
*keydist &= ~SMP_DIST_SIGN;
|
||||
}
|
||||
|
||||
/* If there are still keys to be received wait for them */
|
||||
if ((smp->remote_key_dist & 0x07))
|
||||
return 0;
|
||||
|
||||
clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags);
|
||||
cancel_delayed_work_sync(&conn->security_timer);
|
||||
set_bit(SMP_FLAG_COMPLETE, &smp->flags);
|
||||
smp_notify_keys(conn);
|
||||
|
||||
smp_chan_destroy(conn);
|
||||
hdev->smp_data = chan;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void smp_unregister(struct hci_dev *hdev)
|
||||
{
|
||||
struct l2cap_chan *chan = hdev->smp_data;
|
||||
struct crypto_blkcipher *tfm_aes;
|
||||
|
||||
if (!chan)
|
||||
return;
|
||||
|
||||
BT_DBG("%s chan %p", hdev->name, chan);
|
||||
|
||||
tfm_aes = chan->data;
|
||||
if (tfm_aes) {
|
||||
chan->data = NULL;
|
||||
crypto_free_blkcipher(tfm_aes);
|
||||
}
|
||||
|
||||
hdev->smp_data = NULL;
|
||||
l2cap_chan_put(chan);
|
||||
}
|
||||
|
|
|
@ -126,14 +126,12 @@ enum {
|
|||
/* SMP Commands */
|
||||
bool smp_sufficient_security(struct hci_conn *hcon, u8 sec_level);
|
||||
int smp_conn_security(struct hci_conn *hcon, __u8 sec_level);
|
||||
int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb);
|
||||
int smp_distribute_keys(struct l2cap_conn *conn);
|
||||
int smp_user_confirm_reply(struct hci_conn *conn, u16 mgmt_op, __le32 passkey);
|
||||
|
||||
void smp_chan_destroy(struct l2cap_conn *conn);
|
||||
bool smp_irk_matches(struct hci_dev *hdev, u8 irk[16], bdaddr_t *bdaddr);
|
||||
int smp_generate_rpa(struct hci_dev *hdev, u8 irk[16], bdaddr_t *rpa);
|
||||
|
||||
bool smp_irk_matches(struct crypto_blkcipher *tfm, u8 irk[16],
|
||||
bdaddr_t *bdaddr);
|
||||
int smp_generate_rpa(struct crypto_blkcipher *tfm, u8 irk[16], bdaddr_t *rpa);
|
||||
int smp_register(struct hci_dev *hdev);
|
||||
void smp_unregister(struct hci_dev *hdev);
|
||||
|
||||
#endif /* __SMP_H */
|
||||
|
|
|
@ -77,14 +77,6 @@ lowpan_dev_info *lowpan_dev_info(const struct net_device *dev)
|
|||
return netdev_priv(dev);
|
||||
}
|
||||
|
||||
static inline void lowpan_address_flip(u8 *src, u8 *dest)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < IEEE802154_ADDR_LEN; i++)
|
||||
(dest)[IEEE802154_ADDR_LEN - i - 1] = (src)[i];
|
||||
}
|
||||
|
||||
static int lowpan_header_create(struct sk_buff *skb, struct net_device *dev,
|
||||
unsigned short type, const void *_daddr,
|
||||
const void *_saddr, unsigned int len)
|
||||
|
|
|
@ -86,9 +86,8 @@ fail:
|
|||
static void mac802154_rx_worker(struct work_struct *work)
|
||||
{
|
||||
struct rx_work *rw = container_of(work, struct rx_work, work);
|
||||
struct sk_buff *skb = rw->skb;
|
||||
|
||||
mac802154_subif_rx(rw->dev, skb, rw->lqi);
|
||||
mac802154_subif_rx(rw->dev, rw->skb, rw->lqi);
|
||||
kfree(rw);
|
||||
}
|
||||
|
||||
|
@ -101,7 +100,7 @@ ieee802154_rx_irqsafe(struct ieee802154_dev *dev, struct sk_buff *skb, u8 lqi)
|
|||
if (!skb)
|
||||
return;
|
||||
|
||||
work = kzalloc(sizeof(struct rx_work), GFP_ATOMIC);
|
||||
work = kzalloc(sizeof(*work), GFP_ATOMIC);
|
||||
if (!work)
|
||||
return;
|
||||
|
||||
|
|
|
@ -89,8 +89,7 @@ netdev_tx_t mac802154_tx(struct mac802154_priv *priv, struct sk_buff *skb,
|
|||
|
||||
if (!(priv->phy->channels_supported[page] & (1 << chan))) {
|
||||
WARN_ON(1);
|
||||
kfree_skb(skb);
|
||||
return NETDEV_TX_OK;
|
||||
goto err_tx;
|
||||
}
|
||||
|
||||
mac802154_monitors_rx(mac802154_to_priv(&priv->hw), skb);
|
||||
|
@ -103,12 +102,10 @@ netdev_tx_t mac802154_tx(struct mac802154_priv *priv, struct sk_buff *skb,
|
|||
data[1] = crc >> 8;
|
||||
}
|
||||
|
||||
if (skb_cow_head(skb, priv->hw.extra_tx_headroom)) {
|
||||
kfree_skb(skb);
|
||||
return NETDEV_TX_OK;
|
||||
}
|
||||
if (skb_cow_head(skb, priv->hw.extra_tx_headroom))
|
||||
goto err_tx;
|
||||
|
||||
work = kzalloc(sizeof(struct xmit_work), GFP_ATOMIC);
|
||||
work = kzalloc(sizeof(*work), GFP_ATOMIC);
|
||||
if (!work) {
|
||||
kfree_skb(skb);
|
||||
return NETDEV_TX_BUSY;
|
||||
|
@ -129,4 +126,8 @@ netdev_tx_t mac802154_tx(struct mac802154_priv *priv, struct sk_buff *skb,
|
|||
queue_work(priv->dev_workqueue, &work->work);
|
||||
|
||||
return NETDEV_TX_OK;
|
||||
|
||||
err_tx:
|
||||
kfree_skb(skb);
|
||||
return NETDEV_TX_OK;
|
||||
}
|
||||
|
|
|
@ -472,8 +472,7 @@ mac802154_subif_frame(struct mac802154_sub_if_data *sdata, struct sk_buff *skb,
|
|||
rc = mac802154_llsec_decrypt(&sdata->sec, skb);
|
||||
if (rc) {
|
||||
pr_debug("decryption failed: %i\n", rc);
|
||||
kfree_skb(skb);
|
||||
return NET_RX_DROP;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
sdata->dev->stats.rx_packets++;
|
||||
|
@ -485,9 +484,12 @@ mac802154_subif_frame(struct mac802154_sub_if_data *sdata, struct sk_buff *skb,
|
|||
default:
|
||||
pr_warn("ieee802154: bad frame received (type = %d)\n",
|
||||
mac_cb(skb)->type);
|
||||
kfree_skb(skb);
|
||||
return NET_RX_DROP;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
fail:
|
||||
kfree_skb(skb);
|
||||
return NET_RX_DROP;
|
||||
}
|
||||
|
||||
static void mac802154_print_addr(const char *name,
|
||||
|
|
Загрузка…
Ссылка в новой задаче