aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/uwb/lc-rc.c
diff options
context:
space:
mode:
authorThomas Pugliese <thomas.pugliese@gmail.com>2014-09-16 17:10:50 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2014-09-24 01:05:26 -0400
commitd08e1ad994afb70daf4ebf340f50425c1c5a2b75 (patch)
tree9dfc564046e2101ce868c3a5b62bf7740a349d1a /drivers/uwb/lc-rc.c
parent005799d560769bca8d87b08502c34317ab5e3bcd (diff)
uwb: add an ASIE sysfs attribute to uwb_rc devices
Allow user mode to add and remove application specific information elements (ASIEs) to the beacon of a uwb_rc device. Signed-off-by: Thomas Pugliese <thomas.pugliese@gmail.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/uwb/lc-rc.c')
-rw-r--r--drivers/uwb/lc-rc.c99
1 files changed, 99 insertions, 0 deletions
diff --git a/drivers/uwb/lc-rc.c b/drivers/uwb/lc-rc.c
index 3eca6ceb9844..d059ad4d0dbd 100644
--- a/drivers/uwb/lc-rc.c
+++ b/drivers/uwb/lc-rc.c
@@ -119,10 +119,109 @@ struct uwb_rc *uwb_rc_alloc(void)
119} 119}
120EXPORT_SYMBOL_GPL(uwb_rc_alloc); 120EXPORT_SYMBOL_GPL(uwb_rc_alloc);
121 121
122/*
123 * Show the ASIE that is broadcast in the UWB beacon by this uwb_rc device.
124 */
125static ssize_t ASIE_show(struct device *dev,
126 struct device_attribute *attr, char *buf)
127{
128 struct uwb_dev *uwb_dev = to_uwb_dev(dev);
129 struct uwb_rc *rc = uwb_dev->rc;
130 struct uwb_ie_hdr *ie;
131 void *ptr;
132 size_t len;
133 int result = 0;
134
135 /* init empty buffer. */
136 result = scnprintf(buf, PAGE_SIZE, "\n");
137 mutex_lock(&rc->ies_mutex);
138 /* walk IEData looking for an ASIE. */
139 ptr = rc->ies->IEData;
140 len = le16_to_cpu(rc->ies->wIELength);
141 for (;;) {
142 ie = uwb_ie_next(&ptr, &len);
143 if (!ie)
144 break;
145 if (ie->element_id == UWB_APP_SPEC_IE) {
146 result = uwb_ie_dump_hex(ie,
147 ie->length + sizeof(struct uwb_ie_hdr),
148 buf, PAGE_SIZE);
149 break;
150 }
151 }
152 mutex_unlock(&rc->ies_mutex);
153
154 return result;
155}
156
157/*
158 * Update the ASIE that is broadcast in the UWB beacon by this uwb_rc device.
159 */
160static ssize_t ASIE_store(struct device *dev,
161 struct device_attribute *attr,
162 const char *buf, size_t size)
163{
164 struct uwb_dev *uwb_dev = to_uwb_dev(dev);
165 struct uwb_rc *rc = uwb_dev->rc;
166 char ie_buf[255];
167 int result, ie_len = 0;
168 const char *cur_ptr = buf;
169 struct uwb_ie_hdr *ie;
170
171 /* empty string means clear the ASIE. */
172 if (strlen(buf) <= 1) {
173 uwb_rc_ie_rm(rc, UWB_APP_SPEC_IE);
174 return size;
175 }
176
177 /* if non-empty string, convert string of hex chars to binary. */
178 while (ie_len < sizeof(ie_buf)) {
179 int char_count;
180
181 if (sscanf(cur_ptr, " %02hhX %n",
182 &(ie_buf[ie_len]), &char_count) > 0) {
183 ++ie_len;
184 /* skip chars read from cur_ptr. */
185 cur_ptr += char_count;
186 } else {
187 break;
188 }
189 }
190
191 /* validate IE length and type. */
192 if (ie_len < sizeof(struct uwb_ie_hdr)) {
193 dev_err(dev, "%s: Invalid ASIE size %d.\n", __func__, ie_len);
194 return -EINVAL;
195 }
196
197 ie = (struct uwb_ie_hdr *)ie_buf;
198 if (ie->element_id != UWB_APP_SPEC_IE) {
199 dev_err(dev, "%s: Invalid IE element type size = 0x%02X.\n",
200 __func__, ie->element_id);
201 return -EINVAL;
202 }
203
204 /* bounds check length field from user. */
205 if (ie->length > (ie_len - sizeof(struct uwb_ie_hdr)))
206 ie->length = ie_len - sizeof(struct uwb_ie_hdr);
207
208 /*
209 * Valid ASIE received. Remove current ASIE then add the new one using
210 * uwb_rc_ie_add.
211 */
212 uwb_rc_ie_rm(rc, UWB_APP_SPEC_IE);
213
214 result = uwb_rc_ie_add(rc, ie, ie->length + sizeof(struct uwb_ie_hdr));
215
216 return result >= 0 ? size : result;
217}
218static DEVICE_ATTR_RW(ASIE);
219
122static struct attribute *rc_attrs[] = { 220static struct attribute *rc_attrs[] = {
123 &dev_attr_mac_address.attr, 221 &dev_attr_mac_address.attr,
124 &dev_attr_scan.attr, 222 &dev_attr_scan.attr,
125 &dev_attr_beacon.attr, 223 &dev_attr_beacon.attr,
224 &dev_attr_ASIE.attr,
126 NULL, 225 NULL,
127}; 226};
128 227