122d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez/*
222d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez * Ultra Wide Band
322d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez * Beacon management
422d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez *
522d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez * Copyright (C) 2005-2006 Intel Corporation
622d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
722d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez *
822d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez * This program is free software; you can redistribute it and/or
922d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez * modify it under the terms of the GNU General Public License version
1022d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez * 2 as published by the Free Software Foundation.
1122d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez *
1222d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez * This program is distributed in the hope that it will be useful,
1322d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez * but WITHOUT ANY WARRANTY; without even the implied warranty of
1422d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1522d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez * GNU General Public License for more details.
1622d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez *
1722d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez * You should have received a copy of the GNU General Public License
1822d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez * along with this program; if not, write to the Free Software
1922d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
2022d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez * 02110-1301, USA.
2122d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez *
2222d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez *
2322d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez * FIXME: docs
2422d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez */
2522d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez#include <linux/kernel.h>
2622d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez#include <linux/init.h>
2722d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez#include <linux/module.h>
2822d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez#include <linux/device.h>
2922d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez#include <linux/err.h>
3022d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez#include <linux/kdev_t.h>
315a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
3222d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez
33bce83697c5fe84a7a5d38c96fbbe43b4bc028c3eDavid Vrabel#include "uwb-internal.h"
3422d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez
35bce83697c5fe84a7a5d38c96fbbe43b4bc028c3eDavid Vrabel/* Start Beaconing command structure */
3622d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalezstruct uwb_rc_cmd_start_beacon {
3722d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	struct uwb_rccb rccb;
3822d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	__le16 wBPSTOffset;
3922d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	u8 bChannelNumber;
4022d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez} __attribute__((packed));
4122d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez
4222d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez
4322d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalezstatic int uwb_rc_start_beacon(struct uwb_rc *rc, u16 bpst_offset, u8 channel)
4422d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez{
4522d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	int result;
4622d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	struct uwb_rc_cmd_start_beacon *cmd;
4722d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	struct uwb_rc_evt_confirm reply;
4822d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez
4922d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
5022d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	if (cmd == NULL)
5122d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez		return -ENOMEM;
5222d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	cmd->rccb.bCommandType = UWB_RC_CET_GENERAL;
5322d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	cmd->rccb.wCommand = cpu_to_le16(UWB_RC_CMD_START_BEACON);
5422d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	cmd->wBPSTOffset = cpu_to_le16(bpst_offset);
5522d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	cmd->bChannelNumber = channel;
5622d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	reply.rceb.bEventType = UWB_RC_CET_GENERAL;
5722d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	reply.rceb.wEvent = UWB_RC_CMD_START_BEACON;
5822d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	result = uwb_rc_cmd(rc, "START-BEACON", &cmd->rccb, sizeof(*cmd),
5922d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez			    &reply.rceb, sizeof(reply));
6022d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	if (result < 0)
6122d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez		goto error_cmd;
6222d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	if (reply.bResultCode != UWB_RC_RES_SUCCESS) {
6322d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez		dev_err(&rc->uwb_dev.dev,
6422d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez			"START-BEACON: command execution failed: %s (%d)\n",
6522d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez			uwb_rc_strerror(reply.bResultCode), reply.bResultCode);
6622d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez		result = -EIO;
6722d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	}
6822d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalezerror_cmd:
6922d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	kfree(cmd);
7022d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	return result;
7122d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez}
7222d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez
7322d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalezstatic int uwb_rc_stop_beacon(struct uwb_rc *rc)
7422d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez{
7522d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	int result;
7622d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	struct uwb_rccb *cmd;
7722d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	struct uwb_rc_evt_confirm reply;
7822d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez
7922d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
8022d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	if (cmd == NULL)
8122d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez		return -ENOMEM;
8222d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	cmd->bCommandType = UWB_RC_CET_GENERAL;
8322d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	cmd->wCommand = cpu_to_le16(UWB_RC_CMD_STOP_BEACON);
8422d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	reply.rceb.bEventType = UWB_RC_CET_GENERAL;
8522d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	reply.rceb.wEvent = UWB_RC_CMD_STOP_BEACON;
8622d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	result = uwb_rc_cmd(rc, "STOP-BEACON", cmd, sizeof(*cmd),
8722d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez			    &reply.rceb, sizeof(reply));
8822d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	if (result < 0)
8922d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez		goto error_cmd;
9022d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	if (reply.bResultCode != UWB_RC_RES_SUCCESS) {
9122d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez		dev_err(&rc->uwb_dev.dev,
9222d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez			"STOP-BEACON: command execution failed: %s (%d)\n",
9322d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez			uwb_rc_strerror(reply.bResultCode), reply.bResultCode);
9422d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez		result = -EIO;
9522d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	}
9622d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalezerror_cmd:
9722d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	kfree(cmd);
9822d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	return result;
9922d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez}
10022d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez
10122d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez/*
10222d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez * Start/stop beacons
10322d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez *
10422d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez * @rc:          UWB Radio Controller to operate on
10522d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez * @channel:     UWB channel on which to beacon (WUSB[table
10622d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez *               5-12]). If -1, stop beaconing.
10722d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez * @bpst_offset: Beacon Period Start Time offset; FIXME-do zero
10822d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez *
10922d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez * According to WHCI 0.95 [4.13.6] the driver will only receive the RCEB
11022d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez * of a SET IE command after the device sent the first beacon that includes
11122d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez * the IEs specified in the SET IE command. So, after we start beaconing we
11222d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez * check if there is anything in the IE cache and call the SET IE command
11322d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez * if needed.
11422d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez */
11522d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalezint uwb_rc_beacon(struct uwb_rc *rc, int channel, unsigned bpst_offset)
11622d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez{
11722d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	int result;
11822d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	struct device *dev = &rc->uwb_dev.dev;
11922d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez
120f79833a7ab44fd7ce4db47c65c929747463a452dThomas Pugliese	dev_dbg(dev, "%s: channel = %d\n", __func__, channel);
12122d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	if (channel < 0)
12222d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez		channel = -1;
12322d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	if (channel == -1)
12422d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez		result = uwb_rc_stop_beacon(rc);
12522d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	else {
12622d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez		/* channel >= 0...dah */
12722d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez		result = uwb_rc_start_beacon(rc, bpst_offset, channel);
1287b360ee09a8bec5783cbecdcb17cd8d70edadf56Thomas Pugliese		if (result < 0) {
1297b360ee09a8bec5783cbecdcb17cd8d70edadf56Thomas Pugliese			dev_err(dev, "Cannot start beaconing: %d\n", result);
1306fae35f9cea92793a98b2d9ab21235e5ae035581David Vrabel			return result;
1317b360ee09a8bec5783cbecdcb17cd8d70edadf56Thomas Pugliese		}
13222d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez		if (le16_to_cpu(rc->ies->wIELength) > 0) {
13322d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez			result = uwb_rc_set_ie(rc, rc->ies);
13422d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez			if (result < 0) {
13522d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez				dev_err(dev, "Cannot set new IE on device: "
13622d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez					"%d\n", result);
13722d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez				result = uwb_rc_stop_beacon(rc);
13822d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez				channel = -1;
13922d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez				bpst_offset = 0;
1406fae35f9cea92793a98b2d9ab21235e5ae035581David Vrabel			}
14122d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez		}
14222d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	}
14322d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez
1440996e6382482ce9014787693d3884e9468153a5cDavid Vrabel	if (result >= 0)
1456fae35f9cea92793a98b2d9ab21235e5ae035581David Vrabel		rc->beaconing = channel;
14622d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	return result;
14722d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez}
14822d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez
14922d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez/*
15022d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez * Beacon cache
15122d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez *
15222d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez * The purpose of this is to speed up the lookup of becon information
15322d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez * when a new beacon arrives. The UWB Daemon uses it also to keep a
15422d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez * tab of which devices are in radio distance and which not. When a
15522d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez * device's beacon stays present for more than a certain amount of
15622d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez * time, it is considered a new, usable device. When a beacon ceases
15722d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez * to be received for a certain amount of time, it is considered that
15822d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez * the device is gone.
15922d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez *
16022d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez * FIXME: use an allocator for the entries
16122d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez * FIXME: use something faster for search than a list
16222d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez */
16322d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez
16422d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalezvoid uwb_bce_kfree(struct kref *_bce)
16522d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez{
16622d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	struct uwb_beca_e *bce = container_of(_bce, struct uwb_beca_e, refcnt);
16722d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez
16822d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	kfree(bce->be);
16922d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	kfree(bce);
17022d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez}
17122d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez
17222d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez
17322d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez/* Find a beacon by dev addr in the cache */
17422d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalezstatic
175fec1a5932f16c0eb1b3f5ca2e18d81d860924088Stefano Panellastruct uwb_beca_e *__uwb_beca_find_bydev(struct uwb_rc *rc,
176fec1a5932f16c0eb1b3f5ca2e18d81d860924088Stefano Panella					 const struct uwb_dev_addr *dev_addr)
17722d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez{
17822d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	struct uwb_beca_e *bce, *next;
179fec1a5932f16c0eb1b3f5ca2e18d81d860924088Stefano Panella	list_for_each_entry_safe(bce, next, &rc->uwb_beca.list, node) {
18022d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez		if (!memcmp(&bce->dev_addr, dev_addr, sizeof(bce->dev_addr)))
18122d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez			goto out;
18222d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	}
18322d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	bce = NULL;
18422d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalezout:
18522d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	return bce;
18622d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez}
18722d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez
18822d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez/* Find a beacon by dev addr in the cache */
18922d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalezstatic
19067d0fb2592acdd7cc41129279de2e520d53d68f0Thomas Pugliesestruct uwb_beca_e *__uwb_beca_find_bymac(struct uwb_rc *rc,
191fec1a5932f16c0eb1b3f5ca2e18d81d860924088Stefano Panella					 const struct uwb_mac_addr *mac_addr)
19222d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez{
19322d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	struct uwb_beca_e *bce, *next;
194fec1a5932f16c0eb1b3f5ca2e18d81d860924088Stefano Panella	list_for_each_entry_safe(bce, next, &rc->uwb_beca.list, node) {
19522d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez		if (!memcmp(bce->mac_addr, mac_addr->data,
196c15895ef30c2c03e99802951787183039a349d32Frank Leipold			    sizeof(struct uwb_mac_addr)))
19722d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez			goto out;
19822d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	}
19922d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	bce = NULL;
20022d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalezout:
20122d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	return bce;
20222d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez}
20322d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez
20422d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez/**
20522d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez * uwb_dev_get_by_devaddr - get a UWB device with a specific DevAddr
20622d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez * @rc:      the radio controller that saw the device
20722d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez * @devaddr: DevAddr of the UWB device to find
20822d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez *
20922d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez * There may be more than one matching device (in the case of a
21022d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez * DevAddr conflict), but only the first one is returned.
21122d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez */
21222d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalezstruct uwb_dev *uwb_dev_get_by_devaddr(struct uwb_rc *rc,
21322d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez				       const struct uwb_dev_addr *devaddr)
21422d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez{
21522d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	struct uwb_dev *found = NULL;
21622d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	struct uwb_beca_e *bce;
21722d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez
218fec1a5932f16c0eb1b3f5ca2e18d81d860924088Stefano Panella	mutex_lock(&rc->uwb_beca.mutex);
219fec1a5932f16c0eb1b3f5ca2e18d81d860924088Stefano Panella	bce = __uwb_beca_find_bydev(rc, devaddr);
22022d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	if (bce)
22122d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez		found = uwb_dev_try_get(rc, bce->uwb_dev);
222fec1a5932f16c0eb1b3f5ca2e18d81d860924088Stefano Panella	mutex_unlock(&rc->uwb_beca.mutex);
22322d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez
22422d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	return found;
22522d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez}
22622d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez
22722d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez/**
22822d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez * uwb_dev_get_by_macaddr - get a UWB device with a specific EUI-48
22922d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez * @rc:      the radio controller that saw the device
23022d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez * @devaddr: EUI-48 of the UWB device to find
23122d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez */
23222d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalezstruct uwb_dev *uwb_dev_get_by_macaddr(struct uwb_rc *rc,
23322d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez				       const struct uwb_mac_addr *macaddr)
23422d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez{
23522d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	struct uwb_dev *found = NULL;
23622d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	struct uwb_beca_e *bce;
23722d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez
238fec1a5932f16c0eb1b3f5ca2e18d81d860924088Stefano Panella	mutex_lock(&rc->uwb_beca.mutex);
239fec1a5932f16c0eb1b3f5ca2e18d81d860924088Stefano Panella	bce = __uwb_beca_find_bymac(rc, macaddr);
24022d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	if (bce)
24122d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez		found = uwb_dev_try_get(rc, bce->uwb_dev);
242fec1a5932f16c0eb1b3f5ca2e18d81d860924088Stefano Panella	mutex_unlock(&rc->uwb_beca.mutex);
24322d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez
24422d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	return found;
24522d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez}
24622d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez
24722d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez/* Initialize a beacon cache entry */
24822d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalezstatic void uwb_beca_e_init(struct uwb_beca_e *bce)
24922d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez{
25022d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	mutex_init(&bce->mutex);
25122d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	kref_init(&bce->refcnt);
25222d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	stats_init(&bce->lqe_stats);
25322d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	stats_init(&bce->rssi_stats);
25422d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez}
25522d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez
25622d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez/*
25722d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez * Add a beacon to the cache
25822d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez *
25922d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez * @be:         Beacon event information
26022d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez * @bf:         Beacon frame (part of b, really)
26122d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez * @ts_jiffies: Timestamp (in jiffies) when the beacon was received
26222d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez */
263fec1a5932f16c0eb1b3f5ca2e18d81d860924088Stefano Panellastatic
264fec1a5932f16c0eb1b3f5ca2e18d81d860924088Stefano Panellastruct uwb_beca_e *__uwb_beca_add(struct uwb_rc *rc,
265fec1a5932f16c0eb1b3f5ca2e18d81d860924088Stefano Panella				  struct uwb_rc_evt_beacon *be,
26622d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez				  struct uwb_beacon_frame *bf,
26722d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez				  unsigned long ts_jiffies)
26822d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez{
26922d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	struct uwb_beca_e *bce;
27022d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez
27122d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	bce = kzalloc(sizeof(*bce), GFP_KERNEL);
27222d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	if (bce == NULL)
27322d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez		return NULL;
27422d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	uwb_beca_e_init(bce);
27522d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	bce->ts_jiffies = ts_jiffies;
27622d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	bce->uwb_dev = NULL;
277fec1a5932f16c0eb1b3f5ca2e18d81d860924088Stefano Panella	list_add(&bce->node, &rc->uwb_beca.list);
27822d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	return bce;
27922d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez}
28022d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez
28122d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez/*
28222d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez * Wipe out beacon entries that became stale
28322d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez *
28422d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez * Remove associated devicest too.
28522d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez */
286fec1a5932f16c0eb1b3f5ca2e18d81d860924088Stefano Panellavoid uwb_beca_purge(struct uwb_rc *rc)
28722d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez{
28822d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	struct uwb_beca_e *bce, *next;
28945c16cd9287819cf1c870f2d8e7738c4c90512caDavid Vrabel	unsigned long expires;
29045c16cd9287819cf1c870f2d8e7738c4c90512caDavid Vrabel
291fec1a5932f16c0eb1b3f5ca2e18d81d860924088Stefano Panella	mutex_lock(&rc->uwb_beca.mutex);
292fec1a5932f16c0eb1b3f5ca2e18d81d860924088Stefano Panella	list_for_each_entry_safe(bce, next, &rc->uwb_beca.list, node) {
29345c16cd9287819cf1c870f2d8e7738c4c90512caDavid Vrabel		expires = bce->ts_jiffies + msecs_to_jiffies(beacon_timeout_ms);
29445c16cd9287819cf1c870f2d8e7738c4c90512caDavid Vrabel		if (time_after(jiffies, expires)) {
29522d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez			uwbd_dev_offair(bce);
29622d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez		}
29722d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	}
298fec1a5932f16c0eb1b3f5ca2e18d81d860924088Stefano Panella	mutex_unlock(&rc->uwb_beca.mutex);
29922d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez}
30022d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez
30122d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez/* Clean up the whole beacon cache. Called on shutdown */
302fec1a5932f16c0eb1b3f5ca2e18d81d860924088Stefano Panellavoid uwb_beca_release(struct uwb_rc *rc)
30322d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez{
30422d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	struct uwb_beca_e *bce, *next;
305fec1a5932f16c0eb1b3f5ca2e18d81d860924088Stefano Panella
306fec1a5932f16c0eb1b3f5ca2e18d81d860924088Stefano Panella	mutex_lock(&rc->uwb_beca.mutex);
307fec1a5932f16c0eb1b3f5ca2e18d81d860924088Stefano Panella	list_for_each_entry_safe(bce, next, &rc->uwb_beca.list, node) {
30822d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez		list_del(&bce->node);
30922d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez		uwb_bce_put(bce);
31022d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	}
311fec1a5932f16c0eb1b3f5ca2e18d81d860924088Stefano Panella	mutex_unlock(&rc->uwb_beca.mutex);
31222d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez}
31322d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez
31422d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalezstatic void uwb_beacon_print(struct uwb_rc *rc, struct uwb_rc_evt_beacon *be,
31522d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez			     struct uwb_beacon_frame *bf)
31622d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez{
31722d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	char macbuf[UWB_ADDR_STRSIZE];
31822d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	char devbuf[UWB_ADDR_STRSIZE];
31922d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	char dstbuf[UWB_ADDR_STRSIZE];
32022d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez
32122d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	uwb_mac_addr_print(macbuf, sizeof(macbuf), &bf->Device_Identifier);
32222d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	uwb_dev_addr_print(devbuf, sizeof(devbuf), &bf->hdr.SrcAddr);
32322d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	uwb_dev_addr_print(dstbuf, sizeof(dstbuf), &bf->hdr.DestAddr);
32422d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	dev_info(&rc->uwb_dev.dev,
32522d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez		 "BEACON from %s to %s (ch%u offset %u slot %u MAC %s)\n",
32622d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez		 devbuf, dstbuf, be->bChannelNumber, be->wBPSTOffset,
32722d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez		 bf->Beacon_Slot_Number, macbuf);
32822d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez}
32922d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez
33022d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez/*
33122d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez * @bce: beacon cache entry, referenced
33222d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez */
33322d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalezssize_t uwb_bce_print_IEs(struct uwb_dev *uwb_dev, struct uwb_beca_e *bce,
33422d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez			  char *buf, size_t size)
33522d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez{
33622d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	ssize_t result = 0;
33722d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	struct uwb_rc_evt_beacon *be;
33822d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	struct uwb_beacon_frame *bf;
3391cde7f68ced8d10a20dd2370e9d1d22ab3c1ea5cDavid Vrabel	int ies_len;
3401cde7f68ced8d10a20dd2370e9d1d22ab3c1ea5cDavid Vrabel	struct uwb_ie_hdr *ies;
34122d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez
34222d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	mutex_lock(&bce->mutex);
3431cde7f68ced8d10a20dd2370e9d1d22ab3c1ea5cDavid Vrabel
34422d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	be = bce->be;
3451cde7f68ced8d10a20dd2370e9d1d22ab3c1ea5cDavid Vrabel	if (be) {
3461cde7f68ced8d10a20dd2370e9d1d22ab3c1ea5cDavid Vrabel		bf = (struct uwb_beacon_frame *)bce->be->BeaconInfo;
3471cde7f68ced8d10a20dd2370e9d1d22ab3c1ea5cDavid Vrabel		ies_len = be->wBeaconInfoLength - sizeof(struct uwb_beacon_frame);
3481cde7f68ced8d10a20dd2370e9d1d22ab3c1ea5cDavid Vrabel		ies = (struct uwb_ie_hdr *)bf->IEData;
3491cde7f68ced8d10a20dd2370e9d1d22ab3c1ea5cDavid Vrabel
3501cde7f68ced8d10a20dd2370e9d1d22ab3c1ea5cDavid Vrabel		result = uwb_ie_dump_hex(ies, ies_len, buf, size);
3511cde7f68ced8d10a20dd2370e9d1d22ab3c1ea5cDavid Vrabel	}
3521cde7f68ced8d10a20dd2370e9d1d22ab3c1ea5cDavid Vrabel
35322d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	mutex_unlock(&bce->mutex);
3541cde7f68ced8d10a20dd2370e9d1d22ab3c1ea5cDavid Vrabel
35522d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	return result;
35622d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez}
35722d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez
35822d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez/*
35922d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez * Verify that the beacon event, frame and IEs are ok
36022d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez */
36122d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalezstatic int uwb_verify_beacon(struct uwb_rc *rc, struct uwb_event *evt,
36222d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez			     struct uwb_rc_evt_beacon *be)
36322d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez{
36422d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	int result = -EINVAL;
36522d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	struct uwb_beacon_frame *bf;
36622d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	struct device *dev = &rc->uwb_dev.dev;
36722d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez
36822d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	/* Is there enough data to decode a beacon frame? */
36922d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	if (evt->notif.size < sizeof(*be) + sizeof(*bf)) {
37022d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez		dev_err(dev, "BEACON event: Not enough data to decode "
37122d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez			"(%zu vs %zu bytes needed)\n", evt->notif.size,
37222d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez			sizeof(*be) + sizeof(*bf));
37322d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez		goto error;
37422d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	}
37522d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	/* FIXME: make sure beacon frame IEs are fine and that the whole thing
37622d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	 * is consistent */
37722d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	result = 0;
37822d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalezerror:
37922d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	return result;
38022d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez}
38122d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez
38222d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez/*
38322d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez * Handle UWB_RC_EVT_BEACON events
38422d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez *
38522d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez * We check the beacon cache to see how the received beacon fares. If
38622d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez * is there already we refresh the timestamp. If not we create a new
38722d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez * entry.
38822d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez *
38922d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez * According to the WHCI and WUSB specs, only one beacon frame is
39022d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez * allowed per notification block, so we don't bother about scanning
39122d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez * for more.
39222d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez */
39322d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalezint uwbd_evt_handle_rc_beacon(struct uwb_event *evt)
39422d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez{
39522d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	int result = -EINVAL;
39622d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	struct uwb_rc *rc;
39722d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	struct uwb_rc_evt_beacon *be;
39822d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	struct uwb_beacon_frame *bf;
39922d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	struct uwb_beca_e *bce;
40022d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez
40122d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	rc = evt->rc;
40222d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	be = container_of(evt->notif.rceb, struct uwb_rc_evt_beacon, rceb);
40322d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	result = uwb_verify_beacon(rc, evt, be);
40422d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	if (result < 0)
40522d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez		return result;
40622d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez
4078092d7c9789581eea478c40d615a2632c3af17bbDavid Vrabel	/* FIXME: handle alien beacons. */
40822d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	if (be->bBeaconType == UWB_RC_BEACON_TYPE_OL_ALIEN ||
40922d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	    be->bBeaconType == UWB_RC_BEACON_TYPE_NOL_ALIEN) {
4108092d7c9789581eea478c40d615a2632c3af17bbDavid Vrabel		return -ENOSYS;
41122d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	}
4128092d7c9789581eea478c40d615a2632c3af17bbDavid Vrabel
41322d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	bf = (struct uwb_beacon_frame *) be->BeaconInfo;
41422d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez
41522d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	/*
41622d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	 * Drop beacons from devices with a NULL EUI-48 -- they cannot
41722d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	 * be uniquely identified.
41822d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	 *
41922d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	 * It's expected that these will all be WUSB devices and they
42022d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	 * have a WUSB specific connection method so ignoring them
42122d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	 * here shouldn't be a problem.
42222d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	 */
42322d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	if (uwb_mac_addr_bcast(&bf->Device_Identifier))
42422d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez		return 0;
42522d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez
426fec1a5932f16c0eb1b3f5ca2e18d81d860924088Stefano Panella	mutex_lock(&rc->uwb_beca.mutex);
427fec1a5932f16c0eb1b3f5ca2e18d81d860924088Stefano Panella	bce = __uwb_beca_find_bymac(rc, &bf->Device_Identifier);
42822d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	if (bce == NULL) {
42922d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez		/* Not in there, a new device is pinging */
43022d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez		uwb_beacon_print(evt->rc, be, bf);
431fec1a5932f16c0eb1b3f5ca2e18d81d860924088Stefano Panella		bce = __uwb_beca_add(rc, be, bf, evt->ts_jiffies);
43222d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez		if (bce == NULL) {
433fec1a5932f16c0eb1b3f5ca2e18d81d860924088Stefano Panella			mutex_unlock(&rc->uwb_beca.mutex);
43422d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez			return -ENOMEM;
43522d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez		}
43622d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	}
437fec1a5932f16c0eb1b3f5ca2e18d81d860924088Stefano Panella	mutex_unlock(&rc->uwb_beca.mutex);
43822d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez
43922d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	mutex_lock(&bce->mutex);
44022d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	/* purge old beacon data */
44122d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	kfree(bce->be);
44222d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez
44322d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	/* Update commonly used fields */
44422d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	bce->ts_jiffies = evt->ts_jiffies;
44522d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	bce->be = be;
44622d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	bce->dev_addr = bf->hdr.SrcAddr;
44722d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	bce->mac_addr = &bf->Device_Identifier;
44822d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	be->wBPSTOffset = le16_to_cpu(be->wBPSTOffset);
44922d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	be->wBeaconInfoLength = le16_to_cpu(be->wBeaconInfoLength);
45022d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	stats_add_sample(&bce->lqe_stats, be->bLQI - 7);
45122d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	stats_add_sample(&bce->rssi_stats, be->bRSSI + 18);
45222d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez
45322d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	/*
45422d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	 * This might be a beacon from a new device.
45522d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	 */
45622d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	if (bce->uwb_dev == NULL)
45722d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez		uwbd_dev_onair(evt->rc, bce);
45822d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez
45922d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	mutex_unlock(&bce->mutex);
46022d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez
46122d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	return 1; /* we keep the event data */
46222d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez}
46322d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez
46422d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez/*
46522d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez * Handle UWB_RC_EVT_BEACON_SIZE events
46622d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez *
46722d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez * XXXXX
46822d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez */
46922d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalezint uwbd_evt_handle_rc_beacon_size(struct uwb_event *evt)
47022d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez{
47122d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	int result = -EINVAL;
47222d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	struct device *dev = &evt->rc->uwb_dev.dev;
47322d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	struct uwb_rc_evt_beacon_size *bs;
47422d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez
47522d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	/* Is there enough data to decode the event? */
47622d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	if (evt->notif.size < sizeof(*bs)) {
47722d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez		dev_err(dev, "BEACON SIZE notification: Not enough data to "
47822d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez			"decode (%zu vs %zu bytes needed)\n",
47922d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez			evt->notif.size, sizeof(*bs));
48022d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez		goto error;
48122d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	}
48222d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	bs = container_of(evt->notif.rceb, struct uwb_rc_evt_beacon_size, rceb);
48322d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	if (0)
48422d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez		dev_info(dev, "Beacon size changed to %u bytes "
48522d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez			"(FIXME: action?)\n", le16_to_cpu(bs->wNewBeaconSize));
48622d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	else {
48722d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez		/* temporary hack until we do something with this message... */
48822d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez		static unsigned count;
48922d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez		if (++count % 1000 == 0)
49022d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez			dev_info(dev, "Beacon size changed %u times "
49122d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez				"(FIXME: action?)\n", count);
49222d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	}
49322d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	result = 0;
49422d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalezerror:
49522d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	return result;
49622d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez}
49722d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez
49822d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez/**
49922d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez * uwbd_evt_handle_rc_bp_slot_change - handle a BP_SLOT_CHANGE event
50022d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez * @evt: the BP_SLOT_CHANGE notification from the radio controller
50122d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez *
50222d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez * If the event indicates that no beacon period slots were available
50322d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez * then radio controller has transitioned to a non-beaconing state.
50422d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez * Otherwise, simply save the current beacon slot.
50522d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez */
50622d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalezint uwbd_evt_handle_rc_bp_slot_change(struct uwb_event *evt)
50722d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez{
50822d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	struct uwb_rc *rc = evt->rc;
50922d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	struct device *dev = &rc->uwb_dev.dev;
51022d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	struct uwb_rc_evt_bp_slot_change *bpsc;
51122d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez
51222d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	if (evt->notif.size < sizeof(*bpsc)) {
51322d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez		dev_err(dev, "BP SLOT CHANGE event: Not enough data\n");
51422d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez		return -EINVAL;
51522d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	}
51622d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	bpsc = container_of(evt->notif.rceb, struct uwb_rc_evt_bp_slot_change, rceb);
51722d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez
51822d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	if (uwb_rc_evt_bp_slot_change_no_slot(bpsc)) {
519f79833a7ab44fd7ce4db47c65c929747463a452dThomas Pugliese		dev_err(dev, "stopped beaconing: No free slots in BP\n");
5201fc671b3be8f671482871d9a0b577b6d96914e8eThomas Pugliese		mutex_lock(&rc->uwb_dev.mutex);
52122d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez		rc->beaconing = -1;
5221fc671b3be8f671482871d9a0b577b6d96914e8eThomas Pugliese		mutex_unlock(&rc->uwb_dev.mutex);
52322d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	} else
52422d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez		rc->uwb_dev.beacon_slot = uwb_rc_evt_bp_slot_change_slot_num(bpsc);
52522d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez
52622d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	return 0;
52722d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez}
52822d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez
52922d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez/**
53022d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez * Handle UWB_RC_EVT_BPOIE_CHANGE events
53122d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez *
53222d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez * XXXXX
53322d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez */
53422d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalezstruct uwb_ie_bpo {
53522d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	struct uwb_ie_hdr hdr;
53622d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	u8                bp_length;
53722d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	u8                data[];
53822d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez} __attribute__((packed));
53922d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez
54022d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalezint uwbd_evt_handle_rc_bpoie_change(struct uwb_event *evt)
54122d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez{
54222d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	int result = -EINVAL;
54322d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	struct device *dev = &evt->rc->uwb_dev.dev;
54422d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	struct uwb_rc_evt_bpoie_change *bpoiec;
54522d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	struct uwb_ie_bpo *bpoie;
54622d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	static unsigned count;	/* FIXME: this is a temp hack */
54722d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	size_t iesize;
54822d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez
54922d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	/* Is there enough data to decode it? */
55022d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	if (evt->notif.size < sizeof(*bpoiec)) {
55122d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez		dev_err(dev, "BPOIEC notification: Not enough data to "
55222d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez			"decode (%zu vs %zu bytes needed)\n",
55322d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez			evt->notif.size, sizeof(*bpoiec));
55422d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez		goto error;
55522d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	}
55622d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	bpoiec = container_of(evt->notif.rceb, struct uwb_rc_evt_bpoie_change, rceb);
55722d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	iesize = le16_to_cpu(bpoiec->wBPOIELength);
55822d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	if (iesize < sizeof(*bpoie)) {
55922d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez		dev_err(dev, "BPOIEC notification: Not enough IE data to "
56022d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez			"decode (%zu vs %zu bytes needed)\n",
56122d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez			iesize, sizeof(*bpoie));
56222d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez		goto error;
56322d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	}
56422d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	if (++count % 1000 == 0)	/* Lame placeholder */
56522d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez		dev_info(dev, "BPOIE: %u changes received\n", count);
56622d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	/*
56722d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	 * FIXME: At this point we should go over all the IEs in the
56822d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	 *        bpoiec->BPOIE array and act on each.
56922d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	 */
57022d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	result = 0;
57122d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalezerror:
57222d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	return result;
57322d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez}
57422d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez
57522d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez/*
57622d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez * Print beaconing state.
57722d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez */
57822d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalezstatic ssize_t uwb_rc_beacon_show(struct device *dev,
57922d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez				  struct device_attribute *attr, char *buf)
58022d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez{
58122d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	struct uwb_dev *uwb_dev = to_uwb_dev(dev);
58222d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	struct uwb_rc *rc = uwb_dev->rc;
58322d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	ssize_t result;
58422d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez
58522d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	mutex_lock(&rc->uwb_dev.mutex);
58622d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	result = sprintf(buf, "%d\n", rc->beaconing);
58722d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	mutex_unlock(&rc->uwb_dev.mutex);
58822d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	return result;
58922d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez}
59022d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez
59122d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez/*
59222d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez * Start beaconing on the specified channel, or stop beaconing.
59322d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez */
59422d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalezstatic ssize_t uwb_rc_beacon_store(struct device *dev,
59522d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez				   struct device_attribute *attr,
59622d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez				   const char *buf, size_t size)
59722d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez{
59822d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	struct uwb_dev *uwb_dev = to_uwb_dev(dev);
59922d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	struct uwb_rc *rc = uwb_dev->rc;
60022d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	int channel;
60122d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	ssize_t result = -EINVAL;
60222d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez
6036fae35f9cea92793a98b2d9ab21235e5ae035581David Vrabel	result = sscanf(buf, "%d", &channel);
60422d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	if (result >= 1)
6056fae35f9cea92793a98b2d9ab21235e5ae035581David Vrabel		result = uwb_radio_force_channel(rc, channel);
60622d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez
60722d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez	return result < 0 ? result : size;
60822d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-Gonzalez}
60922d203ecef9b0cc1fa8d8f64c935b451ca7d1022Inaky Perez-GonzalezDEVICE_ATTR(beacon, S_IRUGO | S_IWUSR, uwb_rc_beacon_show, uwb_rc_beacon_store);
610