Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a1ae52c2 authored by John W. Linville's avatar John W. Linville
Browse files

Merge branch 'for-upstream' of...

parents 0da4cc6e 3bd27240
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -154,6 +154,7 @@ L: linux-zigbee-devel@lists.sourceforge.net (moderated for non-subscribers)
L:	linux-bluetooth@vger.kernel.org
L:	linux-bluetooth@vger.kernel.org
S:	Maintained
S:	Maintained
F:	net/6lowpan/
F:	net/6lowpan/
F:	include/net/6lowpan.h


6PACK NETWORK DRIVER FOR AX.25
6PACK NETWORK DRIVER FOR AX.25
M:	Andreas Koensgen <ajk@comnets.uni-bremen.de>
M:	Andreas Koensgen <ajk@comnets.uni-bremen.de>
+4 −0
Original line number Original line Diff line number Diff line
@@ -1074,6 +1074,8 @@ struct hci_rp_read_data_block_size {
	__le16   num_blocks;
	__le16   num_blocks;
} __packed;
} __packed;


#define HCI_OP_READ_LOCAL_CODECS	0x100b

#define HCI_OP_READ_PAGE_SCAN_ACTIVITY	0x0c1b
#define HCI_OP_READ_PAGE_SCAN_ACTIVITY	0x0c1b
struct hci_rp_read_page_scan_activity {
struct hci_rp_read_page_scan_activity {
	__u8     status;
	__u8     status;
@@ -1170,6 +1172,8 @@ struct hci_rp_write_remote_amp_assoc {
	__u8     phy_handle;
	__u8     phy_handle;
} __packed;
} __packed;


#define HCI_OP_GET_MWS_TRANSPORT_CONFIG	0x140c

#define HCI_OP_ENABLE_DUT_MODE		0x1803
#define HCI_OP_ENABLE_DUT_MODE		0x1803


#define HCI_OP_WRITE_SSP_DEBUG_MODE	0x1804
#define HCI_OP_WRITE_SSP_DEBUG_MODE	0x1804
+3 −0
Original line number Original line Diff line number Diff line
@@ -203,6 +203,8 @@ struct hci_dev {
	__u16		page_scan_window;
	__u16		page_scan_window;
	__u8		page_scan_type;
	__u8		page_scan_type;
	__u8		le_adv_channel_map;
	__u8		le_adv_channel_map;
	__u16		le_adv_min_interval;
	__u16		le_adv_max_interval;
	__u8		le_scan_type;
	__u8		le_scan_type;
	__u16		le_scan_interval;
	__u16		le_scan_interval;
	__u16		le_scan_window;
	__u16		le_scan_window;
@@ -458,6 +460,7 @@ struct hci_conn_params {
	enum {
	enum {
		HCI_AUTO_CONN_DISABLED,
		HCI_AUTO_CONN_DISABLED,
		HCI_AUTO_CONN_REPORT,
		HCI_AUTO_CONN_REPORT,
		HCI_AUTO_CONN_DIRECT,
		HCI_AUTO_CONN_ALWAYS,
		HCI_AUTO_CONN_ALWAYS,
		HCI_AUTO_CONN_LINK_LOSS,
		HCI_AUTO_CONN_LINK_LOSS,
	} auto_connect;
	} auto_connect;
+180 −1
Original line number Original line Diff line number Diff line
@@ -970,6 +970,62 @@ static int adv_channel_map_get(void *data, u64 *val)
DEFINE_SIMPLE_ATTRIBUTE(adv_channel_map_fops, adv_channel_map_get,
DEFINE_SIMPLE_ATTRIBUTE(adv_channel_map_fops, adv_channel_map_get,
			adv_channel_map_set, "%llu\n");
			adv_channel_map_set, "%llu\n");


static int adv_min_interval_set(void *data, u64 val)
{
	struct hci_dev *hdev = data;

	if (val < 0x0020 || val > 0x4000 || val > hdev->le_adv_max_interval)
		return -EINVAL;

	hci_dev_lock(hdev);
	hdev->le_adv_min_interval = val;
	hci_dev_unlock(hdev);

	return 0;
}

static int adv_min_interval_get(void *data, u64 *val)
{
	struct hci_dev *hdev = data;

	hci_dev_lock(hdev);
	*val = hdev->le_adv_min_interval;
	hci_dev_unlock(hdev);

	return 0;
}

DEFINE_SIMPLE_ATTRIBUTE(adv_min_interval_fops, adv_min_interval_get,
			adv_min_interval_set, "%llu\n");

static int adv_max_interval_set(void *data, u64 val)
{
	struct hci_dev *hdev = data;

	if (val < 0x0020 || val > 0x4000 || val < hdev->le_adv_min_interval)
		return -EINVAL;

	hci_dev_lock(hdev);
	hdev->le_adv_max_interval = val;
	hci_dev_unlock(hdev);

	return 0;
}

static int adv_max_interval_get(void *data, u64 *val)
{
	struct hci_dev *hdev = data;

	hci_dev_lock(hdev);
	*val = hdev->le_adv_max_interval;
	hci_dev_unlock(hdev);

	return 0;
}

DEFINE_SIMPLE_ATTRIBUTE(adv_max_interval_fops, adv_max_interval_get,
			adv_max_interval_set, "%llu\n");

static int device_list_show(struct seq_file *f, void *ptr)
static int device_list_show(struct seq_file *f, void *ptr)
{
{
	struct hci_dev *hdev = f->private;
	struct hci_dev *hdev = f->private;
@@ -1567,7 +1623,7 @@ static void hci_set_le_support(struct hci_request *req)


	if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
	if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
		cp.le = 0x01;
		cp.le = 0x01;
		cp.simul = lmp_le_br_capable(hdev);
		cp.simul = 0x00;
	}
	}


	if (cp.le != lmp_host_le_capable(hdev))
	if (cp.le != lmp_host_le_capable(hdev))
@@ -1686,6 +1742,14 @@ static void hci_init4_req(struct hci_request *req, unsigned long opt)
	if (hdev->commands[22] & 0x04)
	if (hdev->commands[22] & 0x04)
		hci_set_event_mask_page_2(req);
		hci_set_event_mask_page_2(req);


	/* Read local codec list if the HCI command is supported */
	if (hdev->commands[29] & 0x20)
		hci_req_add(req, HCI_OP_READ_LOCAL_CODECS, 0, NULL);

	/* Get MWS transport configuration if the HCI command is supported */
	if (hdev->commands[30] & 0x08)
		hci_req_add(req, HCI_OP_GET_MWS_TRANSPORT_CONFIG, 0, NULL);

	/* Check for Synchronization Train support */
	/* Check for Synchronization Train support */
	if (lmp_sync_train_capable(hdev))
	if (lmp_sync_train_capable(hdev))
		hci_req_add(req, HCI_OP_READ_SYNC_TRAIN_PARAMS, 0, NULL);
		hci_req_add(req, HCI_OP_READ_SYNC_TRAIN_PARAMS, 0, NULL);
@@ -1825,6 +1889,10 @@ static int __hci_init(struct hci_dev *hdev)
				    hdev, &supervision_timeout_fops);
				    hdev, &supervision_timeout_fops);
		debugfs_create_file("adv_channel_map", 0644, hdev->debugfs,
		debugfs_create_file("adv_channel_map", 0644, hdev->debugfs,
				    hdev, &adv_channel_map_fops);
				    hdev, &adv_channel_map_fops);
		debugfs_create_file("adv_min_interval", 0644, hdev->debugfs,
				    hdev, &adv_min_interval_fops);
		debugfs_create_file("adv_max_interval", 0644, hdev->debugfs,
				    hdev, &adv_max_interval_fops);
		debugfs_create_file("device_list", 0444, hdev->debugfs, hdev,
		debugfs_create_file("device_list", 0444, hdev->debugfs, hdev,
				    &device_list_fops);
				    &device_list_fops);
		debugfs_create_u16("discov_interleaved_timeout", 0644,
		debugfs_create_u16("discov_interleaved_timeout", 0644,
@@ -3639,6 +3707,7 @@ int hci_conn_params_set(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type,
		list_add(&params->action, &hdev->pend_le_reports);
		list_add(&params->action, &hdev->pend_le_reports);
		hci_update_background_scan(hdev);
		hci_update_background_scan(hdev);
		break;
		break;
	case HCI_AUTO_CONN_DIRECT:
	case HCI_AUTO_CONN_ALWAYS:
	case HCI_AUTO_CONN_ALWAYS:
		if (!is_connected(hdev, addr, addr_type)) {
		if (!is_connected(hdev, addr, addr_type)) {
			list_add(&params->action, &hdev->pend_le_conns);
			list_add(&params->action, &hdev->pend_le_conns);
@@ -3914,6 +3983,8 @@ struct hci_dev *hci_alloc_dev(void)
	hdev->sniff_min_interval = 80;
	hdev->sniff_min_interval = 80;


	hdev->le_adv_channel_map = 0x07;
	hdev->le_adv_channel_map = 0x07;
	hdev->le_adv_min_interval = 0x0800;
	hdev->le_adv_max_interval = 0x0800;
	hdev->le_scan_interval = 0x0060;
	hdev->le_scan_interval = 0x0060;
	hdev->le_scan_window = 0x0030;
	hdev->le_scan_window = 0x0030;
	hdev->le_conn_min_interval = 0x0028;
	hdev->le_conn_min_interval = 0x0028;
@@ -5397,12 +5468,113 @@ void hci_req_add_le_scan_disable(struct hci_request *req)
	hci_req_add(req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(cp), &cp);
	hci_req_add(req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(cp), &cp);
}
}


static void add_to_white_list(struct hci_request *req,
			      struct hci_conn_params *params)
{
	struct hci_cp_le_add_to_white_list cp;

	cp.bdaddr_type = params->addr_type;
	bacpy(&cp.bdaddr, &params->addr);

	hci_req_add(req, HCI_OP_LE_ADD_TO_WHITE_LIST, sizeof(cp), &cp);
}

static u8 update_white_list(struct hci_request *req)
{
	struct hci_dev *hdev = req->hdev;
	struct hci_conn_params *params;
	struct bdaddr_list *b;
	uint8_t white_list_entries = 0;

	/* Go through the current white list programmed into the
	 * controller one by one and check if that address is still
	 * in the list of pending connections or list of devices to
	 * report. If not present in either list, then queue the
	 * command to remove it from the controller.
	 */
	list_for_each_entry(b, &hdev->le_white_list, list) {
		struct hci_cp_le_del_from_white_list cp;

		if (hci_pend_le_action_lookup(&hdev->pend_le_conns,
					      &b->bdaddr, b->bdaddr_type) ||
		    hci_pend_le_action_lookup(&hdev->pend_le_reports,
					      &b->bdaddr, b->bdaddr_type)) {
			white_list_entries++;
			continue;
		}

		cp.bdaddr_type = b->bdaddr_type;
		bacpy(&cp.bdaddr, &b->bdaddr);

		hci_req_add(req, HCI_OP_LE_DEL_FROM_WHITE_LIST,
			    sizeof(cp), &cp);
	}

	/* Since all no longer valid white list entries have been
	 * removed, walk through the list of pending connections
	 * and ensure that any new device gets programmed into
	 * the controller.
	 *
	 * If the list of the devices is larger than the list of
	 * available white list entries in the controller, then
	 * just abort and return filer policy value to not use the
	 * white list.
	 */
	list_for_each_entry(params, &hdev->pend_le_conns, action) {
		if (hci_bdaddr_list_lookup(&hdev->le_white_list,
					   &params->addr, params->addr_type))
			continue;

		if (white_list_entries >= hdev->le_white_list_size) {
			/* Select filter policy to accept all advertising */
			return 0x00;
		}

		if (hci_find_irk_by_addr(hdev, &params->addr,
					 params->addr_type)) {
			/* White list can not be used with RPAs */
			return 0x00;
		}

		white_list_entries++;
		add_to_white_list(req, params);
	}

	/* After adding all new pending connections, walk through
	 * the list of pending reports and also add these to the
	 * white list if there is still space.
	 */
	list_for_each_entry(params, &hdev->pend_le_reports, action) {
		if (hci_bdaddr_list_lookup(&hdev->le_white_list,
					   &params->addr, params->addr_type))
			continue;

		if (white_list_entries >= hdev->le_white_list_size) {
			/* Select filter policy to accept all advertising */
			return 0x00;
		}

		if (hci_find_irk_by_addr(hdev, &params->addr,
					 params->addr_type)) {
			/* White list can not be used with RPAs */
			return 0x00;
		}

		white_list_entries++;
		add_to_white_list(req, params);
	}

	/* Select filter policy to use white list */
	return 0x01;
}

void hci_req_add_le_passive_scan(struct hci_request *req)
void hci_req_add_le_passive_scan(struct hci_request *req)
{
{
	struct hci_cp_le_set_scan_param param_cp;
	struct hci_cp_le_set_scan_param param_cp;
	struct hci_cp_le_set_scan_enable enable_cp;
	struct hci_cp_le_set_scan_enable enable_cp;
	struct hci_dev *hdev = req->hdev;
	struct hci_dev *hdev = req->hdev;
	u8 own_addr_type;
	u8 own_addr_type;
	u8 filter_policy;


	/* Set require_privacy to false since no SCAN_REQ are send
	/* Set require_privacy to false since no SCAN_REQ are send
	 * during passive scanning. Not using an unresolvable address
	 * during passive scanning. Not using an unresolvable address
@@ -5413,11 +5585,18 @@ void hci_req_add_le_passive_scan(struct hci_request *req)
	if (hci_update_random_address(req, false, &own_addr_type))
	if (hci_update_random_address(req, false, &own_addr_type))
		return;
		return;


	/* Adding or removing entries from the white list must
	 * happen before enabling scanning. The controller does
	 * not allow white list modification while scanning.
	 */
	filter_policy = update_white_list(req);

	memset(&param_cp, 0, sizeof(param_cp));
	memset(&param_cp, 0, sizeof(param_cp));
	param_cp.type = LE_SCAN_PASSIVE;
	param_cp.type = LE_SCAN_PASSIVE;
	param_cp.interval = cpu_to_le16(hdev->le_scan_interval);
	param_cp.interval = cpu_to_le16(hdev->le_scan_interval);
	param_cp.window = cpu_to_le16(hdev->le_scan_window);
	param_cp.window = cpu_to_le16(hdev->le_scan_window);
	param_cp.own_address_type = own_addr_type;
	param_cp.own_address_type = own_addr_type;
	param_cp.filter_policy = filter_policy;
	hci_req_add(req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp),
	hci_req_add(req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp),
		    &param_cp);
		    &param_cp);


+27 −8
Original line number Original line Diff line number Diff line
@@ -317,7 +317,7 @@ static void hci_cc_write_scan_enable(struct hci_dev *hdev, struct sk_buff *skb)
	if (param & SCAN_PAGE)
	if (param & SCAN_PAGE)
		set_bit(HCI_PSCAN, &hdev->flags);
		set_bit(HCI_PSCAN, &hdev->flags);
	else
	else
		clear_bit(HCI_ISCAN, &hdev->flags);
		clear_bit(HCI_PSCAN, &hdev->flags);


done:
done:
	hci_dev_unlock(hdev);
	hci_dev_unlock(hdev);
@@ -2259,6 +2259,7 @@ static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
				break;
				break;
			/* Fall through */
			/* Fall through */


		case HCI_AUTO_CONN_DIRECT:
		case HCI_AUTO_CONN_ALWAYS:
		case HCI_AUTO_CONN_ALWAYS:
			list_del_init(&params->action);
			list_del_init(&params->action);
			list_add(&params->action, &hdev->pend_le_conns);
			list_add(&params->action, &hdev->pend_le_conns);
@@ -4251,6 +4252,7 @@ static void check_pending_le_conn(struct hci_dev *hdev, bdaddr_t *addr,
				  u8 addr_type, u8 adv_type)
				  u8 addr_type, u8 adv_type)
{
{
	struct hci_conn *conn;
	struct hci_conn *conn;
	struct hci_conn_params *params;


	/* If the event is not connectable don't proceed further */
	/* If the event is not connectable don't proceed further */
	if (adv_type != LE_ADV_IND && adv_type != LE_ADV_DIRECT_IND)
	if (adv_type != LE_ADV_IND && adv_type != LE_ADV_DIRECT_IND)
@@ -4266,18 +4268,35 @@ static void check_pending_le_conn(struct hci_dev *hdev, bdaddr_t *addr,
	if (hdev->conn_hash.le_num_slave > 0)
	if (hdev->conn_hash.le_num_slave > 0)
		return;
		return;


	/* If we're connectable, always connect any ADV_DIRECT_IND event */
	if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags) &&
	    adv_type == LE_ADV_DIRECT_IND)
		goto connect;

	/* If we're not connectable only connect devices that we have in
	/* If we're not connectable only connect devices that we have in
	 * our pend_le_conns list.
	 * our pend_le_conns list.
	 */
	 */
	if (!hci_pend_le_action_lookup(&hdev->pend_le_conns, addr, addr_type))
	params = hci_pend_le_action_lookup(&hdev->pend_le_conns,
					   addr, addr_type);
	if (!params)
		return;

	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;
			return;
		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;
	}


connect:
	conn = hci_connect_le(hdev, addr, addr_type, BT_SECURITY_LOW,
	conn = hci_connect_le(hdev, addr, addr_type, BT_SECURITY_LOW,
			      HCI_LE_AUTOCONN_TIMEOUT, HCI_ROLE_MASTER);
			      HCI_LE_AUTOCONN_TIMEOUT, HCI_ROLE_MASTER);
	if (!IS_ERR(conn))
	if (!IS_ERR(conn))
Loading