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