diff options
author | Thomas Pugliese <thomas.pugliese@gmail.com> | 2014-09-16 17:10:50 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2014-09-24 01:05:26 -0400 |
commit | d08e1ad994afb70daf4ebf340f50425c1c5a2b75 (patch) | |
tree | 9dfc564046e2101ce868c3a5b62bf7740a349d1a | |
parent | 005799d560769bca8d87b08502c34317ab5e3bcd (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>
-rw-r--r-- | drivers/uwb/lc-rc.c | 99 |
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 | } |
120 | EXPORT_SYMBOL_GPL(uwb_rc_alloc); | 120 | EXPORT_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 | */ | ||
125 | static 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 | */ | ||
160 | static 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 | } | ||
218 | static DEVICE_ATTR_RW(ASIE); | ||
219 | |||
122 | static struct attribute *rc_attrs[] = { | 220 | static 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 | ||