diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/6lowpan/Makefile | 2 | ||||
-rw-r--r-- | net/6lowpan/core.c | 40 | ||||
-rw-r--r-- | net/6lowpan/iphc.c | 21 | ||||
-rw-r--r-- | net/bluetooth/6lowpan.c | 11 | ||||
-rw-r--r-- | net/bluetooth/amp.c | 2 | ||||
-rw-r--r-- | net/bluetooth/hci_conn.c | 235 | ||||
-rw-r--r-- | net/bluetooth/hci_core.c | 33 | ||||
-rw-r--r-- | net/bluetooth/hci_event.c | 55 | ||||
-rw-r--r-- | net/bluetooth/hci_request.c | 6 | ||||
-rw-r--r-- | net/bluetooth/l2cap_core.c | 6 | ||||
-rw-r--r-- | net/bluetooth/mgmt.c | 15 | ||||
-rw-r--r-- | net/ieee802154/6lowpan/6lowpan_i.h | 11 | ||||
-rw-r--r-- | net/ieee802154/6lowpan/core.c | 79 | ||||
-rw-r--r-- | net/ieee802154/6lowpan/rx.c | 45 | ||||
-rw-r--r-- | net/ieee802154/6lowpan/tx.c | 4 | ||||
-rw-r--r-- | net/ieee802154/nl802154.c | 33 | ||||
-rw-r--r-- | net/ieee802154/rdev-ops.h | 13 | ||||
-rw-r--r-- | net/ieee802154/trace.h | 19 | ||||
-rw-r--r-- | net/mac802154/cfg.c | 27 | ||||
-rw-r--r-- | net/mac802154/iface.c | 18 | ||||
-rw-r--r-- | net/mac802154/main.c | 9 | ||||
-rw-r--r-- | net/rfkill/rfkill-gpio.c | 1 |
22 files changed, 491 insertions, 194 deletions
diff --git a/net/6lowpan/Makefile b/net/6lowpan/Makefile index eb8baa72adc8..c6ffc55ee0d7 100644 --- a/net/6lowpan/Makefile +++ b/net/6lowpan/Makefile @@ -1,6 +1,6 @@ obj-$(CONFIG_6LOWPAN) += 6lowpan.o -6lowpan-y := iphc.o nhc.o +6lowpan-y := core.o iphc.o nhc.o #rfc6282 nhcs obj-$(CONFIG_6LOWPAN_NHC_DEST) += nhc_dest.o diff --git a/net/6lowpan/core.c b/net/6lowpan/core.c new file mode 100644 index 000000000000..ae1896fa45e2 --- /dev/null +++ b/net/6lowpan/core.c @@ -0,0 +1,40 @@ +/* This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * Authors: + * (C) 2015 Pengutronix, Alexander Aring <aar@pengutronix.de> + */ + +#include <linux/module.h> + +#include <net/6lowpan.h> + +void lowpan_netdev_setup(struct net_device *dev, enum lowpan_lltypes lltype) +{ + lowpan_priv(dev)->lltype = lltype; +} +EXPORT_SYMBOL(lowpan_netdev_setup); + +static int __init lowpan_module_init(void) +{ + request_module_nowait("ipv6"); + + request_module_nowait("nhc_dest"); + request_module_nowait("nhc_fragment"); + request_module_nowait("nhc_hop"); + request_module_nowait("nhc_ipv6"); + request_module_nowait("nhc_mobility"); + request_module_nowait("nhc_routing"); + request_module_nowait("nhc_udp"); + + return 0; +} +module_init(lowpan_module_init); + +MODULE_LICENSE("GPL"); diff --git a/net/6lowpan/iphc.c b/net/6lowpan/iphc.c index 9055d7b9d112..1e0071fdcf72 100644 --- a/net/6lowpan/iphc.c +++ b/net/6lowpan/iphc.c @@ -48,7 +48,6 @@ #include <linux/bitops.h> #include <linux/if_arp.h> -#include <linux/module.h> #include <linux/netdevice.h> #include <net/6lowpan.h> #include <net/ipv6.h> @@ -284,7 +283,7 @@ lowpan_header_decompress(struct sk_buff *skb, struct net_device *dev, if (lowpan_fetch_skb(skb, &tmp, sizeof(tmp))) return -EINVAL; - hdr.flow_lbl[0] = (skb->data[0] & 0x0F) | ((tmp >> 2) & 0x30); + hdr.flow_lbl[0] = (tmp & 0x0F) | ((tmp >> 2) & 0x30); memcpy(&hdr.flow_lbl[1], &skb->data[0], 2); skb_pull(skb, 2); break; @@ -610,21 +609,3 @@ int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev, return 0; } EXPORT_SYMBOL_GPL(lowpan_header_compress); - -static int __init lowpan_module_init(void) -{ - request_module_nowait("ipv6"); - - request_module_nowait("nhc_dest"); - request_module_nowait("nhc_fragment"); - request_module_nowait("nhc_hop"); - request_module_nowait("nhc_ipv6"); - request_module_nowait("nhc_mobility"); - request_module_nowait("nhc_routing"); - request_module_nowait("nhc_udp"); - - return 0; -} -module_init(lowpan_module_init); - -MODULE_LICENSE("GPL"); diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c index 0ffe2e24020a..131e79cde350 100644 --- a/net/bluetooth/6lowpan.c +++ b/net/bluetooth/6lowpan.c @@ -85,7 +85,7 @@ struct lowpan_dev { static inline struct lowpan_dev *lowpan_dev(const struct net_device *netdev) { - return netdev_priv(netdev); + return (struct lowpan_dev *)lowpan_priv(netdev)->priv; } static inline void peer_add(struct lowpan_dev *dev, struct lowpan_peer *peer) @@ -848,8 +848,9 @@ static int setup_netdev(struct l2cap_chan *chan, struct lowpan_dev **dev) struct net_device *netdev; int err = 0; - netdev = alloc_netdev(sizeof(struct lowpan_dev), IFACE_NAME_TEMPLATE, - NET_NAME_UNKNOWN, netdev_setup); + netdev = alloc_netdev(LOWPAN_PRIV_SIZE(sizeof(struct lowpan_dev)), + IFACE_NAME_TEMPLATE, NET_NAME_UNKNOWN, + netdev_setup); if (!netdev) return -ENOMEM; @@ -859,7 +860,7 @@ static int setup_netdev(struct l2cap_chan *chan, struct lowpan_dev **dev) SET_NETDEV_DEV(netdev, &chan->conn->hcon->hdev->dev); SET_NETDEV_DEVTYPE(netdev, &bt_type); - *dev = netdev_priv(netdev); + *dev = lowpan_dev(netdev); (*dev)->netdev = netdev; (*dev)->hdev = chan->conn->hcon->hdev; INIT_LIST_HEAD(&(*dev)->peers); @@ -869,6 +870,8 @@ static int setup_netdev(struct l2cap_chan *chan, struct lowpan_dev **dev) list_add_rcu(&(*dev)->list, &bt_6lowpan_devices); spin_unlock(&devices_lock); + lowpan_netdev_setup(netdev, LOWPAN_LLTYPE_BTLE); + err = register_netdev(netdev); if (err < 0) { BT_INFO("register_netdev failed %d", err); diff --git a/net/bluetooth/amp.c b/net/bluetooth/amp.c index 238ddd3cf95f..e32f34189007 100644 --- a/net/bluetooth/amp.c +++ b/net/bluetooth/amp.c @@ -379,7 +379,7 @@ static bool amp_write_rem_assoc_frag(struct hci_dev *hdev, amp_ctrl_put(ctrl); hci_req_init(&req, hdev); - hci_req_add(&req, HCI_OP_WRITE_REMOTE_AMP_ASSOC, sizeof(cp), &cp); + hci_req_add(&req, HCI_OP_WRITE_REMOTE_AMP_ASSOC, len, cp); hci_req_run_skb(&req, write_remote_amp_assoc_complete); kfree(cp); diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 2c48bf0b5afb..b4548c739a64 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -64,6 +64,48 @@ static void hci_le_create_connection_cancel(struct hci_conn *conn) hci_send_cmd(conn->hdev, HCI_OP_LE_CREATE_CONN_CANCEL, 0, NULL); } +/* This function requires the caller holds hdev->lock */ +static void hci_connect_le_scan_cleanup(struct hci_conn *conn) +{ + struct hci_conn_params *params; + struct smp_irk *irk; + bdaddr_t *bdaddr; + u8 bdaddr_type; + + bdaddr = &conn->dst; + bdaddr_type = conn->dst_type; + + /* Check if we need to convert to identity address */ + irk = hci_get_irk(conn->hdev, bdaddr, bdaddr_type); + if (irk) { + bdaddr = &irk->bdaddr; + bdaddr_type = irk->addr_type; + } + + params = hci_explicit_connect_lookup(conn->hdev, bdaddr, bdaddr_type); + if (!params) + return; + + /* The connection attempt was doing scan for new RPA, and is + * in scan phase. If params are not associated with any other + * autoconnect action, remove them completely. If they are, just unmark + * them as waiting for connection, by clearing explicit_connect field. + */ + if (params->auto_connect == HCI_AUTO_CONN_EXPLICIT) + hci_conn_params_del(conn->hdev, bdaddr, bdaddr_type); + else + params->explicit_connect = false; +} + +/* This function requires the caller holds hdev->lock */ +static void hci_connect_le_scan_remove(struct hci_conn *conn) +{ + hci_connect_le_scan_cleanup(conn); + + hci_conn_hash_del(conn->hdev, conn); + hci_update_background_scan(conn->hdev); +} + static void hci_acl_create_connection(struct hci_conn *conn) { struct hci_dev *hdev = conn->hdev; @@ -340,8 +382,12 @@ static void hci_conn_timeout(struct work_struct *work) if (conn->out) { if (conn->type == ACL_LINK) hci_acl_create_connection_cancel(conn); - else if (conn->type == LE_LINK) - hci_le_create_connection_cancel(conn); + else if (conn->type == LE_LINK) { + if (test_bit(HCI_CONN_SCANNING, &conn->flags)) + hci_connect_le_scan_remove(conn); + else + hci_le_create_connection_cancel(conn); + } } else if (conn->type == SCO_LINK || conn->type == ESCO_LINK) { hci_reject_sco(conn); } @@ -637,15 +683,18 @@ static void create_le_conn_complete(struct hci_dev *hdev, u8 status, u16 opcode) { struct hci_conn *conn; - if (status == 0) - return; + hci_dev_lock(hdev); + + conn = hci_lookup_le_connect(hdev); + + if (!status) { + hci_connect_le_scan_cleanup(conn); + goto done; + } BT_ERR("HCI request failed to create LE connection: status 0x%2.2x", status); - hci_dev_lock(hdev); - - conn = hci_conn_hash_lookup_state(hdev, LE_LINK, BT_CONNECT); if (!conn) goto done; @@ -685,6 +734,7 @@ static void hci_req_add_le_create_conn(struct hci_request *req, hci_req_add(req, HCI_OP_LE_CREATE_CONN, sizeof(cp), &cp); conn->state = BT_CONNECT; + clear_bit(HCI_CONN_SCANNING, &conn->flags); } static void hci_req_directed_advertising(struct hci_request *req, @@ -728,7 +778,7 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst, u8 role) { struct hci_conn_params *params; - struct hci_conn *conn; + struct hci_conn *conn, *conn_unfinished; struct smp_irk *irk; struct hci_request req; int err; @@ -751,26 +801,29 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst, * and return the object found. */ conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, dst); + conn_unfinished = NULL; if (conn) { - conn->pending_sec_level = sec_level; - goto done; + if (conn->state == BT_CONNECT && + test_bit(HCI_CONN_SCANNING, &conn->flags)) { + BT_DBG("will continue unfinished conn %pMR", dst); + conn_unfinished = conn; + } else { + if (conn->pending_sec_level < sec_level) + conn->pending_sec_level = sec_level; + goto done; + } } /* Since the controller supports only one LE connection attempt at a * time, we return -EBUSY if there is any connection attempt running. */ - conn = hci_conn_hash_lookup_state(hdev, LE_LINK, BT_CONNECT); - if (conn) + if (hci_lookup_le_connect(hdev)) return ERR_PTR(-EBUSY); /* When given an identity address with existing identity * resolving key, the connection needs to be established * to a resolvable random address. * - * This uses the cached random resolvable address from - * a previous scan. When no cached address is available, - * try connecting to the identity address instead. - * * Storing the resolvable random address is required here * to handle connection failures. The address will later * be resolved back into the original identity address @@ -782,15 +835,23 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst, dst_type = ADDR_LE_DEV_RANDOM; } - conn = hci_conn_add(hdev, LE_LINK, dst, role); + if (conn_unfinished) { + conn = conn_unfinished; + bacpy(&conn->dst, dst); + } else { + conn = hci_conn_add(hdev, LE_LINK, dst, role); + } + if (!conn) return ERR_PTR(-ENOMEM); conn->dst_type = dst_type; conn->sec_level = BT_SECURITY_LOW; - conn->pending_sec_level = sec_level; conn->conn_timeout = conn_timeout; + if (!conn_unfinished) + conn->pending_sec_level = sec_level; + hci_req_init(&req, hdev); /* Disable advertising if we're active. For master role @@ -855,6 +916,144 @@ create_conn: } done: + /* If this is continuation of connect started by hci_connect_le_scan, + * it already called hci_conn_hold and calling it again would mess the + * counter. + */ + if (!conn_unfinished) + hci_conn_hold(conn); + + return conn; +} + +static void hci_connect_le_scan_complete(struct hci_dev *hdev, u8 status, + u16 opcode) +{ + struct hci_conn *conn; + + if (!status) + return; + + BT_ERR("Failed to add device to auto conn whitelist: status 0x%2.2x", + status); + + hci_dev_lock(hdev); + + conn = hci_conn_hash_lookup_state(hdev, LE_LINK, BT_CONNECT); + if (conn) + hci_le_conn_failed(conn, status); + + hci_dev_unlock(hdev); +} + +static bool is_connected(struct hci_dev *hdev, bdaddr_t *addr, u8 type) +{ + struct hci_conn *conn; + + conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, addr); + if (!conn) + return false; + + if (conn->dst_type != type) + return false; + + if (conn->state != BT_CONNECTED) + return false; + + return true; +} + +/* This function requires the caller holds hdev->lock */ +static int hci_explicit_conn_params_set(struct hci_request *req, + bdaddr_t *addr, u8 addr_type) +{ + struct hci_dev *hdev = req->hdev; + struct hci_conn_params *params; + + if (is_connected(hdev, addr, addr_type)) + return -EISCONN; + + params = hci_conn_params_add(hdev, addr, addr_type); + if (!params) + return -EIO; + + /* If we created new params, or existing params were marked as disabled, + * mark them to be used just once to connect. + */ + if (params->auto_connect == HCI_AUTO_CONN_DISABLED) { + params->auto_connect = HCI_AUTO_CONN_EXPLICIT; + list_del_init(¶ms->action); + list_add(¶ms->action, &hdev->pend_le_conns); + } + + params->explicit_connect = true; + __hci_update_background_scan(req); + + BT_DBG("addr %pMR (type %u) auto_connect %u", addr, addr_type, + params->auto_connect); + + return 0; +} + +/* This function requires the caller holds hdev->lock */ +struct hci_conn *hci_connect_le_scan(struct hci_dev *hdev, bdaddr_t *dst, + u8 dst_type, u8 sec_level, + u16 conn_timeout, u8 role) +{ + struct hci_conn *conn; + struct hci_request req; + int err; + + /* Let's make sure that le is enabled.*/ + if (!hci_dev_test_flag(hdev, HCI_LE_ENABLED)) { + if (lmp_le_capable(hdev)) + return ERR_PTR(-ECONNREFUSED); + + return ERR_PTR(-EOPNOTSUPP); + } + + /* Some devices send ATT messages as soon as the physical link is + * established. To be able to handle these ATT messages, the user- + * space first establishes the connection and then starts the pairing + * process. + * + * So if a hci_conn object already exists for the following connection + * attempt, we simply update pending_sec_level and auth_type fields + * and return the object found. + */ + conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, dst); + if (conn) { + if (conn->pending_sec_level < sec_level) + conn->pending_sec_level = sec_level; + goto done; + } + + BT_DBG("requesting refresh of dst_addr"); + + conn = hci_conn_add(hdev, LE_LINK, dst, role); + if (!conn) + return ERR_PTR(-ENOMEM); + + hci_req_init(&req, hdev); + + if (hci_explicit_conn_params_set(&req, dst, dst_type) < 0) + return ERR_PTR(-EBUSY); + + conn->state = BT_CONNECT; + set_bit(HCI_CONN_SCANNING, &conn->flags); + + err = hci_req_run(&req, hci_connect_le_scan_complete); + if (err && err != -ENODATA) { + hci_conn_del(conn); + return ERR_PTR(err); + } + + conn->dst_type = dst_type; + conn->sec_level = BT_SECURITY_LOW; + conn->pending_sec_level = sec_level; + conn->conn_timeout = conn_timeout; + +done: hci_conn_hold(conn); return conn; } diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index bc43b6490555..adcbc74c2432 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2848,6 +2848,30 @@ struct hci_conn_params *hci_pend_le_action_lookup(struct list_head *list, } /* This function requires the caller holds hdev->lock */ +struct hci_conn_params *hci_explicit_connect_lookup(struct hci_dev *hdev, + bdaddr_t *addr, + u8 addr_type) +{ + struct hci_conn_params *param; + + list_for_each_entry(param, &hdev->pend_le_conns, action) { + if (bacmp(¶m->addr, addr) == 0 && + param->addr_type == addr_type && + param->explicit_connect) + return param; + } + + list_for_each_entry(param, &hdev->pend_le_reports, action) { + if (bacmp(¶m->addr, addr) == 0 && + param->addr_type == addr_type && + param->explicit_connect) + return param; + } + + return NULL; +} + +/* This function requires the caller holds hdev->lock */ struct hci_conn_params *hci_conn_params_add(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type) { @@ -2916,6 +2940,15 @@ void hci_conn_params_clear_disabled(struct hci_dev *hdev) list_for_each_entry_safe(params, tmp, &hdev->le_conn_params, list) { if (params->auto_connect != HCI_AUTO_CONN_DISABLED) continue; + + /* If trying to estabilish one time connection to disabled + * device, leave the params, but mark them as just once. + */ + if (params->explicit_connect) { + params->auto_connect = HCI_AUTO_CONN_EXPLICIT; + continue; + } + list_del(¶ms->list); kfree(params); } diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 218d7dfc342f..7ba35a9ba6b7 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1059,7 +1059,7 @@ static void hci_cc_le_set_adv_enable(struct hci_dev *hdev, struct sk_buff *skb) hci_dev_set_flag(hdev, HCI_LE_ADV); - conn = hci_conn_hash_lookup_state(hdev, LE_LINK, BT_CONNECT); + conn = hci_lookup_le_connect(hdev); if (conn) queue_delayed_work(hdev->workqueue, &conn->le_conn_timeout, @@ -4447,7 +4447,7 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) */ hci_dev_clear_flag(hdev, HCI_LE_ADV); - conn = hci_conn_hash_lookup_state(hdev, LE_LINK, BT_CONNECT); + conn = hci_lookup_le_connect(hdev); if (!conn) { conn = hci_conn_add(hdev, LE_LINK, &ev->bdaddr, ev->role); if (!conn) { @@ -4640,42 +4640,49 @@ static struct hci_conn *check_pending_le_conn(struct hci_dev *hdev, /* If we're not connectable only connect devices that we have in * our pend_le_conns list. */ - params = hci_pend_le_action_lookup(&hdev->pend_le_conns, - addr, addr_type); + params = hci_explicit_connect_lookup(hdev, addr, addr_type); + if (!params) return NULL; - switch (params->auto_connect) { - case HCI_AUTO_CONN_DIRECT: - /* Only devices advertising with ADV_DIRECT_IND are - * triggering a connection attempt. This is allowing - * incoming connections from slave devices. - */ - if (adv_type != LE_ADV_DIRECT_IND) + if (!params->explicit_connect) { + switch (params->auto_connect) { + case HCI_AUTO_CONN_DIRECT: + /* Only devices advertising with ADV_DIRECT_IND are + * triggering a connection attempt. This is allowing + * incoming connections from slave devices. + */ + if (adv_type != LE_ADV_DIRECT_IND) + return NULL; + break; + case HCI_AUTO_CONN_ALWAYS: + /* Devices advertising with ADV_IND or ADV_DIRECT_IND + * are triggering a connection attempt. This means + * that incoming connectioms from slave device are + * accepted and also outgoing connections to slave + * devices are established when found. + */ + break; + default: return NULL; - break; - case HCI_AUTO_CONN_ALWAYS: - /* Devices advertising with ADV_IND or ADV_DIRECT_IND - * are triggering a connection attempt. This means - * that incoming connectioms from slave device are - * accepted and also outgoing connections to slave - * devices are established when found. - */ - break; - default: - return NULL; + } } conn = hci_connect_le(hdev, addr, addr_type, BT_SECURITY_LOW, HCI_LE_AUTOCONN_TIMEOUT, HCI_ROLE_MASTER); if (!IS_ERR(conn)) { - /* Store the pointer since we don't really have any + /* If HCI_AUTO_CONN_EXPLICIT is set, conn is already owned + * by higher layer that tried to connect, if no then + * store the pointer since we don't really have any * other owner of the object besides the params that * triggered it. This way we can abort the connection if * the parameters get removed and keep the reference * count consistent once the connection is established. */ - params->conn = hci_conn_get(conn); + + if (!params->explicit_connect) + params->conn = hci_conn_get(conn); + return conn; } diff --git a/net/bluetooth/hci_request.c b/net/bluetooth/hci_request.c index d6025d6e6d59..b7369220c9ef 100644 --- a/net/bluetooth/hci_request.c +++ b/net/bluetooth/hci_request.c @@ -317,7 +317,7 @@ static void set_random_addr(struct hci_request *req, bdaddr_t *rpa) * address be updated at the next cycle. */ if (hci_dev_test_flag(hdev, HCI_LE_ADV) || - hci_conn_hash_lookup_state(hdev, LE_LINK, BT_CONNECT)) { + hci_lookup_le_connect(hdev)) { BT_DBG("Deferring random address update"); hci_dev_set_flag(hdev, HCI_RPA_EXPIRED); return; @@ -479,7 +479,6 @@ void hci_update_page_scan(struct hci_dev *hdev) void __hci_update_background_scan(struct hci_request *req) { struct hci_dev *hdev = req->hdev; - struct hci_conn *conn; if (!test_bit(HCI_UP, &hdev->flags) || test_bit(HCI_INIT, &hdev->flags) || @@ -529,8 +528,7 @@ void __hci_update_background_scan(struct hci_request *req) * since some controllers are not able to scan and connect at * the same time. */ - conn = hci_conn_hash_lookup_state(hdev, LE_LINK, BT_CONNECT); - if (conn) + if (hci_lookup_le_connect(hdev)) return; /* If controller is currently scanning, we stop it to ensure we diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 45fffa413642..7c65ee200c29 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -7113,8 +7113,10 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, else role = HCI_ROLE_MASTER; - hcon = hci_connect_le(hdev, dst, dst_type, chan->sec_level, - HCI_LE_CONN_TIMEOUT, role); + hcon = hci_connect_le_scan(hdev, dst, dst_type, + chan->sec_level, + HCI_LE_CONN_TIMEOUT, + role); } else { u8 auth_type = l2cap_get_auth_type(chan); hcon = hci_connect_acl(hdev, dst, chan->sec_level, auth_type); diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index e435438f95f0..ccaf5a436d8f 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -3564,9 +3564,10 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data, */ hci_conn_params_add(hdev, &cp->addr.bdaddr, addr_type); - conn = hci_connect_le(hdev, &cp->addr.bdaddr, addr_type, - sec_level, HCI_LE_CONN_TIMEOUT, - HCI_ROLE_MASTER); + conn = hci_connect_le_scan(hdev, &cp->addr.bdaddr, + addr_type, sec_level, + HCI_LE_CONN_TIMEOUT, + HCI_ROLE_MASTER); } if (IS_ERR(conn)) { @@ -4210,7 +4211,7 @@ static bool trigger_le_scan(struct hci_request *req, u16 interval, u8 *status) /* Don't let discovery abort an outgoing connection attempt * that's using directed advertising. */ - if (hci_conn_hash_lookup_state(hdev, LE_LINK, BT_CONNECT)) { + if (hci_lookup_le_connect(hdev)) { *status = MGMT_STATUS_REJECTED; return false; } @@ -6107,6 +6108,12 @@ static int hci_conn_params_set(struct hci_request *req, bdaddr_t *addr, switch (auto_connect) { case HCI_AUTO_CONN_DISABLED: case HCI_AUTO_CONN_LINK_LOSS: + /* If auto connect is being disabled when we're trying to + * connect to device, keep connecting. + */ + if (params->explicit_connect) + list_add(¶ms->action, &hdev->pend_le_conns); + __hci_update_background_scan(req); break; case HCI_AUTO_CONN_REPORT: diff --git a/net/ieee802154/6lowpan/6lowpan_i.h b/net/ieee802154/6lowpan/6lowpan_i.h index e50f69da78eb..ea339fa94c27 100644 --- a/net/ieee802154/6lowpan/6lowpan_i.h +++ b/net/ieee802154/6lowpan/6lowpan_i.h @@ -5,6 +5,7 @@ #include <net/ieee802154_netdev.h> #include <net/inet_frag.h> +#include <net/6lowpan.h> struct lowpan_create_arg { u16 tag; @@ -37,26 +38,18 @@ static inline u32 ieee802154_addr_hash(const struct ieee802154_addr *a) } } -struct lowpan_dev_record { - struct net_device *ldev; - struct list_head list; -}; - /* private device info */ struct lowpan_dev_info { struct net_device *real_dev; /* real WPAN device ptr */ - struct mutex dev_list_mtx; /* mutex for list ops */ u16 fragment_tag; }; static inline struct lowpan_dev_info *lowpan_dev_info(const struct net_device *dev) { - return netdev_priv(dev); + return (struct lowpan_dev_info *)lowpan_priv(dev)->priv; } -extern struct list_head lowpan_devices; - int lowpan_frag_rcv(struct sk_buff *skb, const u8 frag_type); void lowpan_net_frag_exit(void); int lowpan_net_frag_init(void); diff --git a/net/ieee802154/6lowpan/core.c b/net/ieee802154/6lowpan/core.c index f20a387a1011..27c25ad935b4 100644 --- a/net/ieee802154/6lowpan/core.c +++ b/net/ieee802154/6lowpan/core.c @@ -52,8 +52,7 @@ #include "6lowpan_i.h" -LIST_HEAD(lowpan_devices); -static int lowpan_open_count; +static int open_count; static struct header_ops lowpan_header_ops = { .create = lowpan_header_create, @@ -114,7 +113,6 @@ static int lowpan_newlink(struct net *src_net, struct net_device *dev, struct nlattr *tb[], struct nlattr *data[]) { struct net_device *real_dev; - struct lowpan_dev_record *entry; int ret; ASSERT_RTNL(); @@ -133,67 +131,52 @@ static int lowpan_newlink(struct net *src_net, struct net_device *dev, return -EINVAL; } - lowpan_dev_info(dev)->real_dev = real_dev; - mutex_init(&lowpan_dev_info(dev)->dev_list_mtx); - - entry = kzalloc(sizeof(*entry), GFP_KERNEL); - if (!entry) { + if (real_dev->ieee802154_ptr->lowpan_dev) { dev_put(real_dev); - lowpan_dev_info(dev)->real_dev = NULL; - return -ENOMEM; + return -EBUSY; } - entry->ldev = dev; - + lowpan_dev_info(dev)->real_dev = real_dev; /* Set the lowpan hardware address to the wpan hardware address. */ memcpy(dev->dev_addr, real_dev->dev_addr, IEEE802154_ADDR_LEN); - mutex_lock(&lowpan_dev_info(dev)->dev_list_mtx); - INIT_LIST_HEAD(&entry->list); - list_add_tail(&entry->list, &lowpan_devices); - mutex_unlock(&lowpan_dev_info(dev)->dev_list_mtx); + lowpan_netdev_setup(dev, LOWPAN_LLTYPE_IEEE802154); ret = register_netdevice(dev); - if (ret >= 0) { - if (!lowpan_open_count) - lowpan_rx_init(); - lowpan_open_count++; + if (ret < 0) { + dev_put(real_dev); + return ret; } - return ret; + real_dev->ieee802154_ptr->lowpan_dev = dev; + if (!open_count) + lowpan_rx_init(); + + open_count++; + + return 0; } static void lowpan_dellink(struct net_device *dev, struct list_head *head) { struct lowpan_dev_info *lowpan_dev = lowpan_dev_info(dev); struct net_device *real_dev = lowpan_dev->real_dev; - struct lowpan_dev_record *entry, *tmp; ASSERT_RTNL(); - lowpan_open_count--; - if (!lowpan_open_count) - lowpan_rx_exit(); - - mutex_lock(&lowpan_dev_info(dev)->dev_list_mtx); - list_for_each_entry_safe(entry, tmp, &lowpan_devices, list) { - if (entry->ldev == dev) { - list_del(&entry->list); - kfree(entry); - } - } - mutex_unlock(&lowpan_dev_info(dev)->dev_list_mtx); + open_count--; - mutex_destroy(&lowpan_dev_info(dev)->dev_list_mtx); - - unregister_netdevice_queue(dev, head); + if (!open_count) + lowpan_rx_exit(); + real_dev->ieee802154_ptr->lowpan_dev = NULL; + unregister_netdevice(dev); dev_put(real_dev); } static struct rtnl_link_ops lowpan_link_ops __read_mostly = { .kind = "lowpan", - .priv_size = sizeof(struct lowpan_dev_info), + .priv_size = LOWPAN_PRIV_SIZE(sizeof(struct lowpan_dev_info)), .setup = lowpan_setup, .newlink = lowpan_newlink, .dellink = lowpan_dellink, @@ -214,19 +197,21 @@ static int lowpan_device_event(struct notifier_block *unused, unsigned long event, void *ptr) { struct net_device *dev = netdev_notifier_info_to_dev(ptr); - LIST_HEAD(del_list); - struct lowpan_dev_record *entry, *tmp; if (dev->type != ARPHRD_IEEE802154) goto out; - if (event == NETDEV_UNREGISTER) { - list_for_each_entry_safe(entry, tmp, &lowpan_devices, list) { - if (lowpan_dev_info(entry->ldev)->real_dev == dev) - lowpan_dellink(entry->ldev, &del_list); - } - - unregister_netdevice_many(&del_list); + switch (event) { + case NETDEV_UNREGISTER: + /* Check if wpan interface is unregistered that we + * also delete possible lowpan interfaces which belongs + * to the wpan interface. + */ + if (dev->ieee802154_ptr && dev->ieee802154_ptr->lowpan_dev) + lowpan_dellink(dev->ieee802154_ptr->lowpan_dev, NULL); + break; + default: + break; } out: diff --git a/net/ieee802154/6lowpan/rx.c b/net/ieee802154/6lowpan/rx.c index 4be1d289ab2d..12e10201d263 100644 --- a/net/ieee802154/6lowpan/rx.c +++ b/net/ieee802154/6lowpan/rx.c @@ -15,36 +15,14 @@ #include "6lowpan_i.h" -static int lowpan_give_skb_to_devices(struct sk_buff *skb, - struct net_device *dev) +static int lowpan_give_skb_to_device(struct sk_buff *skb, + struct net_device *dev) { - struct lowpan_dev_record *entry; - struct sk_buff *skb_cp; - int stat = NET_RX_SUCCESS; - + skb->dev = dev->ieee802154_ptr->lowpan_dev; skb->protocol = htons(ETH_P_IPV6); skb->pkt_type = PACKET_HOST; - rcu_read_lock(); - list_for_each_entry_rcu(entry, &lowpan_devices, list) - if (lowpan_dev_info(entry->ldev)->real_dev == skb->dev) { - skb_cp = skb_copy(skb, GFP_ATOMIC); - if (!skb_cp) { - kfree_skb(skb); - rcu_read_unlock(); - return NET_RX_DROP; - } - - skb_cp->dev = entry->ldev; - stat = netif_rx(skb_cp); - if (stat == NET_RX_DROP) - break; - } - rcu_read_unlock(); - - consume_skb(skb); - - return stat; + return netif_rx(skb); } static int @@ -89,6 +67,10 @@ static int lowpan_rcv(struct sk_buff *skb, struct net_device *dev, struct ieee802154_hdr hdr; int ret; + if (dev->type != ARPHRD_IEEE802154 || + !dev->ieee802154_ptr->lowpan_dev) + goto drop; + skb = skb_share_check(skb, GFP_ATOMIC); if (!skb) goto drop; @@ -99,9 +81,6 @@ static int lowpan_rcv(struct sk_buff *skb, struct net_device *dev, if (skb->pkt_type == PACKET_OTHERHOST) goto drop_skb; - if (dev->type != ARPHRD_IEEE802154) - goto drop_skb; - if (ieee802154_hdr_peek_addrs(skb, &hdr) < 0) goto drop_skb; @@ -109,7 +88,7 @@ static int lowpan_rcv(struct sk_buff *skb, struct net_device *dev, if (skb->data[0] == LOWPAN_DISPATCH_IPV6) { /* Pull off the 1-byte of 6lowpan header. */ skb_pull(skb, 1); - return lowpan_give_skb_to_devices(skb, NULL); + return lowpan_give_skb_to_device(skb, dev); } else { switch (skb->data[0] & 0xe0) { case LOWPAN_DISPATCH_IPHC: /* ipv6 datagram */ @@ -117,7 +96,7 @@ static int lowpan_rcv(struct sk_buff *skb, struct net_device *dev, if (ret < 0) goto drop_skb; - return lowpan_give_skb_to_devices(skb, NULL); + return lowpan_give_skb_to_device(skb, dev); case LOWPAN_DISPATCH_FRAG1: /* first fragment header */ ret = lowpan_frag_rcv(skb, LOWPAN_DISPATCH_FRAG1); if (ret == 1) { @@ -125,7 +104,7 @@ static int lowpan_rcv(struct sk_buff *skb, struct net_device *dev, if (ret < 0) goto drop_skb; - return lowpan_give_skb_to_devices(skb, NULL); + return lowpan_give_skb_to_device(skb, dev); } else if (ret == -1) { return NET_RX_DROP; } else { @@ -138,7 +117,7 @@ static int lowpan_rcv(struct sk_buff *skb, struct net_device *dev, if (ret < 0) goto drop_skb; - return lowpan_give_skb_to_devices(skb, NULL); + return lowpan_give_skb_to_device(skb, dev); } else if (ret == -1) { return NET_RX_DROP; } else { diff --git a/net/ieee802154/6lowpan/tx.c b/net/ieee802154/6lowpan/tx.c index 2597abbf7f4b..f6263fc12340 100644 --- a/net/ieee802154/6lowpan/tx.c +++ b/net/ieee802154/6lowpan/tx.c @@ -112,7 +112,7 @@ lowpan_xmit_fragment(struct sk_buff *skb, const struct ieee802154_hdr *wpan_hdr, frag = lowpan_alloc_frag(skb, frag_hdrlen + len, wpan_hdr); if (IS_ERR(frag)) - return -PTR_ERR(frag); + return PTR_ERR(frag); memcpy(skb_put(frag, frag_hdrlen), frag_hdr, frag_hdrlen); memcpy(skb_put(frag, len), skb_network_header(skb) + offset, len); @@ -224,7 +224,7 @@ static int lowpan_header(struct sk_buff *skb, struct net_device *dev) } else { da.mode = IEEE802154_ADDR_LONG; da.extended_addr = ieee802154_devaddr_from_raw(daddr); - cb->ackreq = wpan_dev->frame_retries >= 0; + cb->ackreq = wpan_dev->ackreq; } return dev_hard_header(skb, lowpan_dev_info(dev)->real_dev, diff --git a/net/ieee802154/nl802154.c b/net/ieee802154/nl802154.c index 68f24016860c..1b00a14850cb 100644 --- a/net/ieee802154/nl802154.c +++ b/net/ieee802154/nl802154.c @@ -230,6 +230,8 @@ static const struct nla_policy nl802154_policy[NL802154_ATTR_MAX+1] = { [NL802154_ATTR_WPAN_PHY_CAPS] = { .type = NLA_NESTED }, [NL802154_ATTR_SUPPORTED_COMMANDS] = { .type = NLA_NESTED }, + + [NL802154_ATTR_ACKREQ_DEFAULT] = { .type = NLA_U8 }, }; /* message building helper */ @@ -458,6 +460,7 @@ static int nl802154_send_wpan_phy(struct cfg802154_registered_device *rdev, CMD(set_max_csma_backoffs, SET_MAX_CSMA_BACKOFFS); CMD(set_max_frame_retries, SET_MAX_FRAME_RETRIES); CMD(set_lbt_mode, SET_LBT_MODE); + CMD(set_ackreq_default, SET_ACKREQ_DEFAULT); if (rdev->wpan_phy.flags & WPAN_PHY_FLAG_TXPOWER) CMD(set_tx_power, SET_TX_POWER); @@ -656,6 +659,10 @@ nl802154_send_iface(struct sk_buff *msg, u32 portid, u32 seq, int flags, if (nla_put_u8(msg, NL802154_ATTR_LBT_MODE, wpan_dev->lbt)) goto nla_put_failure; + /* ackreq default behaviour */ + if (nla_put_u8(msg, NL802154_ATTR_ACKREQ_DEFAULT, wpan_dev->ackreq)) + goto nla_put_failure; + genlmsg_end(msg, hdr); return 0; @@ -1042,6 +1049,24 @@ static int nl802154_set_lbt_mode(struct sk_buff *skb, struct genl_info *info) return rdev_set_lbt_mode(rdev, wpan_dev, mode); } +static int +nl802154_set_ackreq_default(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg802154_registered_device *rdev = info->user_ptr[0]; + struct net_device *dev = info->user_ptr[1]; + struct wpan_dev *wpan_dev = dev->ieee802154_ptr; + bool ackreq; + + if (netif_running(dev)) + return -EBUSY; + + if (!info->attrs[NL802154_ATTR_ACKREQ_DEFAULT]) + return -EINVAL; + + ackreq = !!nla_get_u8(info->attrs[NL802154_ATTR_ACKREQ_DEFAULT]); + return rdev_set_ackreq_default(rdev, wpan_dev, ackreq); +} + #define NL802154_FLAG_NEED_WPAN_PHY 0x01 #define NL802154_FLAG_NEED_NETDEV 0x02 #define NL802154_FLAG_NEED_RTNL 0x04 @@ -1248,6 +1273,14 @@ static const struct genl_ops nl802154_ops[] = { .internal_flags = NL802154_FLAG_NEED_NETDEV | NL802154_FLAG_NEED_RTNL, }, + { + .cmd = NL802154_CMD_SET_ACKREQ_DEFAULT, + .doit = nl802154_set_ackreq_default, + .policy = nl802154_policy, + .flags = GENL_ADMIN_PERM, + .internal_flags = NL802154_FLAG_NEED_NETDEV | + NL802154_FLAG_NEED_RTNL, + }, }; /* initialisation/exit functions */ diff --git a/net/ieee802154/rdev-ops.h b/net/ieee802154/rdev-ops.h index 8d5960a37195..03b357501cc5 100644 --- a/net/ieee802154/rdev-ops.h +++ b/net/ieee802154/rdev-ops.h @@ -195,4 +195,17 @@ rdev_set_lbt_mode(struct cfg802154_registered_device *rdev, return ret; } +static inline int +rdev_set_ackreq_default(struct cfg802154_registered_device *rdev, + struct wpan_dev *wpan_dev, bool ackreq) +{ + int ret; + + trace_802154_rdev_set_ackreq_default(&rdev->wpan_phy, wpan_dev, + ackreq); + ret = rdev->ops->set_ackreq_default(&rdev->wpan_phy, wpan_dev, ackreq); + trace_802154_rdev_return_int(&rdev->wpan_phy, ret); + return ret; +} + #endif /* __CFG802154_RDEV_OPS */ diff --git a/net/ieee802154/trace.h b/net/ieee802154/trace.h index 4399b7fbaa31..9a471e41ec73 100644 --- a/net/ieee802154/trace.h +++ b/net/ieee802154/trace.h @@ -275,6 +275,25 @@ TRACE_EVENT(802154_rdev_set_lbt_mode, WPAN_DEV_PR_ARG, BOOL_TO_STR(__entry->mode)) ); +TRACE_EVENT(802154_rdev_set_ackreq_default, + TP_PROTO(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev, + bool ackreq), + TP_ARGS(wpan_phy, wpan_dev, ackreq), + TP_STRUCT__entry( + WPAN_PHY_ENTRY + WPAN_DEV_ENTRY + __field(bool, ackreq) + ), + TP_fast_assign( + WPAN_PHY_ASSIGN; + WPAN_DEV_ASSIGN; + __entry->ackreq = ackreq; + ), + TP_printk(WPAN_PHY_PR_FMT ", " WPAN_DEV_PR_FMT + ", ackreq default: %s", WPAN_PHY_PR_ARG, + WPAN_DEV_PR_ARG, BOOL_TO_STR(__entry->ackreq)) +); + TRACE_EVENT(802154_rdev_return_int, TP_PROTO(struct wpan_phy *wpan_phy, int ret), TP_ARGS(wpan_phy, ret), diff --git a/net/mac802154/cfg.c b/net/mac802154/cfg.c index f7ba51e8b4ca..c865ebb2ace2 100644 --- a/net/mac802154/cfg.c +++ b/net/mac802154/cfg.c @@ -209,10 +209,6 @@ ieee802154_set_backoff_exponent(struct wpan_phy *wpan_phy, { ASSERT_RTNL(); - if (wpan_dev->min_be == min_be && - wpan_dev->max_be == max_be) - return 0; - wpan_dev->min_be = min_be; wpan_dev->max_be = max_be; return 0; @@ -224,9 +220,6 @@ ieee802154_set_short_addr(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev, { ASSERT_RTNL(); - if (wpan_dev->short_addr == short_addr) - return 0; - wpan_dev->short_addr = short_addr; return 0; } @@ -238,9 +231,6 @@ ieee802154_set_max_csma_backoffs(struct wpan_phy *wpan_phy, { ASSERT_RTNL(); - if (wpan_dev->csma_retries == max_csma_backoffs) - return 0; - wpan_dev->csma_retries = max_csma_backoffs; return 0; } @@ -252,9 +242,6 @@ ieee802154_set_max_frame_retries(struct wpan_phy *wpan_phy, { ASSERT_RTNL(); - if (wpan_dev->frame_retries == max_frame_retries) - return 0; - wpan_dev->frame_retries = max_frame_retries; return 0; } @@ -265,13 +252,20 @@ ieee802154_set_lbt_mode(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev, { ASSERT_RTNL(); - if (wpan_dev->lbt == mode) - return 0; - wpan_dev->lbt = mode; return 0; } +static int +ieee802154_set_ackreq_default(struct wpan_phy *wpan_phy, + struct wpan_dev *wpan_dev, bool ackreq) +{ + ASSERT_RTNL(); + + wpan_dev->ackreq = ackreq; + return 0; +} + const struct cfg802154_ops mac802154_config_ops = { .add_virtual_intf_deprecated = ieee802154_add_iface_deprecated, .del_virtual_intf_deprecated = ieee802154_del_iface_deprecated, @@ -289,4 +283,5 @@ const struct cfg802154_ops mac802154_config_ops = { .set_max_csma_backoffs = ieee802154_set_max_csma_backoffs, .set_max_frame_retries = ieee802154_set_max_frame_retries, .set_lbt_mode = ieee802154_set_lbt_mode, + .set_ackreq_default = ieee802154_set_ackreq_default, }; diff --git a/net/mac802154/iface.c b/net/mac802154/iface.c index 416de903e467..ed26952f9e14 100644 --- a/net/mac802154/iface.c +++ b/net/mac802154/iface.c @@ -125,6 +125,14 @@ static int mac802154_wpan_mac_addr(struct net_device *dev, void *p) if (netif_running(dev)) return -EBUSY; + /* lowpan need to be down for update + * SLAAC address after ifup + */ + if (sdata->wpan_dev.lowpan_dev) { + if (netif_running(sdata->wpan_dev.lowpan_dev)) + return -EBUSY; + } + ieee802154_be64_to_le64(&extended_addr, addr->sa_data); if (!ieee802154_is_valid_extended_unicast_addr(extended_addr)) return -EINVAL; @@ -132,6 +140,13 @@ static int mac802154_wpan_mac_addr(struct net_device *dev, void *p) memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); sdata->wpan_dev.extended_addr = extended_addr; + /* update lowpan interface mac address when + * wpan mac has been changed + */ + if (sdata->wpan_dev.lowpan_dev) + memcpy(sdata->wpan_dev.lowpan_dev->dev_addr, dev->dev_addr, + dev->addr_len); + return mac802154_wpan_update_llsec(dev); } @@ -483,8 +498,7 @@ ieee802154_setup_sdata(struct ieee802154_sub_if_data *sdata, wpan_dev->min_be = 3; wpan_dev->max_be = 5; wpan_dev->csma_retries = 4; - /* for compatibility, actual default is 3 */ - wpan_dev->frame_retries = -1; + wpan_dev->frame_retries = 3; wpan_dev->pan_id = cpu_to_le16(IEEE802154_PANID_BROADCAST); wpan_dev->short_addr = cpu_to_le16(IEEE802154_ADDR_BROADCAST); diff --git a/net/mac802154/main.c b/net/mac802154/main.c index 9e55431b9a5c..e8cab5bb80c6 100644 --- a/net/mac802154/main.c +++ b/net/mac802154/main.c @@ -111,7 +111,7 @@ ieee802154_alloc_hw(size_t priv_data_len, const struct ieee802154_ops *ops) phy->supported.max_minbe = 8; phy->supported.min_maxbe = 3; phy->supported.max_maxbe = 8; - phy->supported.min_frame_retries = -1; + phy->supported.min_frame_retries = 0; phy->supported.max_frame_retries = 7; phy->supported.max_csma_backoffs = 5; phy->supported.lbt = NL802154_SUPPORTED_BOOL_FALSE; @@ -177,11 +177,8 @@ int ieee802154_register_hw(struct ieee802154_hw *hw) } if (!(hw->flags & IEEE802154_HW_FRAME_RETRIES)) { - /* TODO should be 3, but our default value is -1 which means - * no ARET handling. - */ - local->phy->supported.min_frame_retries = -1; - local->phy->supported.max_frame_retries = -1; + local->phy->supported.min_frame_retries = 3; + local->phy->supported.max_frame_retries = 3; } if (hw->flags & IEEE802154_HW_PROMISCUOUS) diff --git a/net/rfkill/rfkill-gpio.c b/net/rfkill/rfkill-gpio.c index d5d58d919552..93127220cb54 100644 --- a/net/rfkill/rfkill-gpio.c +++ b/net/rfkill/rfkill-gpio.c @@ -164,7 +164,6 @@ static int rfkill_gpio_remove(struct platform_device *pdev) #ifdef CONFIG_ACPI static const struct acpi_device_id rfkill_acpi_match[] = { { "BCM2E1A", RFKILL_TYPE_BLUETOOTH }, - { "BCM2E39", RFKILL_TYPE_BLUETOOTH }, { "BCM2E3D", RFKILL_TYPE_BLUETOOTH }, { "BCM2E40", RFKILL_TYPE_BLUETOOTH }, { "BCM2E64", RFKILL_TYPE_BLUETOOTH }, |