]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blob - drivers/uwb/wlp/eda.c
include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit...
[mirror_ubuntu-artful-kernel.git] / drivers / uwb / wlp / eda.c
1 /*
2 * WUSB Wire Adapter: WLP interface
3 * Ethernet to device address cache
4 *
5 * Copyright (C) 2005-2006 Intel Corporation
6 * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License version
10 * 2 as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 * 02110-1301, USA.
21 *
22 *
23 * We need to be able to map ethernet addresses to device addresses
24 * and back because there is not explicit relationship between the eth
25 * addresses used in the ETH frames and the device addresses (no, it
26 * would not have been simpler to force as ETH address the MBOA MAC
27 * address...no, not at all :).
28 *
29 * A device has one MBOA MAC address and one device address. It is possible
30 * for a device to have more than one virtual MAC address (although a
31 * virtual address can be the same as the MBOA MAC address). The device
32 * address is guaranteed to be unique among the devices in the extended
33 * beacon group (see ECMA 17.1.1). We thus use the device address as index
34 * to this cache. We do allow searching based on virtual address as this
35 * is how Ethernet frames will be addressed.
36 *
37 * We need to support virtual EUI-48. Although, right now the virtual
38 * EUI-48 will always be the same as the MAC SAP address. The EDA cache
39 * entry thus contains a MAC SAP address as well as the virtual address
40 * (used to map the network stack address to a neighbor). When we move
41 * to support more than one virtual MAC on a host then this organization
42 * will have to change. Perhaps a neighbor has a list of WSSs, each with a
43 * tag and virtual EUI-48.
44 *
45 * On data transmission
46 * it is used to determine if the neighbor is connected and what WSS it
47 * belongs to. With this we know what tag to add to the WLP frame. Storing
48 * the WSS in the EDA cache may be overkill because we only support one
49 * WSS. Hopefully we will support more than one WSS at some point.
50 * On data reception it is used to determine the WSS based on
51 * the tag and address of the transmitting neighbor.
52 */
53
54 #include <linux/netdevice.h>
55 #include <linux/etherdevice.h>
56 #include <linux/slab.h>
57 #include <linux/wlp.h>
58 #include "wlp-internal.h"
59
60
61 /* FIXME: cache is not purged, only on device close */
62
63 /* FIXME: does not scale, change to dynamic array */
64
65 /*
66 * Initialize the EDA cache
67 *
68 * @returns 0 if ok, < 0 errno code on error
69 *
70 * Call when the interface is being brought up
71 *
72 * NOTE: Keep it as a separate function as the implementation will
73 * change and be more complex.
74 */
75 void wlp_eda_init(struct wlp_eda *eda)
76 {
77 INIT_LIST_HEAD(&eda->cache);
78 spin_lock_init(&eda->lock);
79 }
80
81 /*
82 * Release the EDA cache
83 *
84 * @returns 0 if ok, < 0 errno code on error
85 *
86 * Called when the interface is brought down
87 */
88 void wlp_eda_release(struct wlp_eda *eda)
89 {
90 unsigned long flags;
91 struct wlp_eda_node *itr, *next;
92
93 spin_lock_irqsave(&eda->lock, flags);
94 list_for_each_entry_safe(itr, next, &eda->cache, list_node) {
95 list_del(&itr->list_node);
96 kfree(itr);
97 }
98 spin_unlock_irqrestore(&eda->lock, flags);
99 }
100
101 /*
102 * Add an address mapping
103 *
104 * @returns 0 if ok, < 0 errno code on error
105 *
106 * An address mapping is initially created when the neighbor device is seen
107 * for the first time (it is "onair"). At this time the neighbor is not
108 * connected or associated with a WSS so we only populate the Ethernet and
109 * Device address fields.
110 *
111 */
112 int wlp_eda_create_node(struct wlp_eda *eda,
113 const unsigned char eth_addr[ETH_ALEN],
114 const struct uwb_dev_addr *dev_addr)
115 {
116 int result = 0;
117 struct wlp_eda_node *itr;
118 unsigned long flags;
119
120 BUG_ON(dev_addr == NULL || eth_addr == NULL);
121 spin_lock_irqsave(&eda->lock, flags);
122 list_for_each_entry(itr, &eda->cache, list_node) {
123 if (!memcmp(&itr->dev_addr, dev_addr, sizeof(itr->dev_addr))) {
124 printk(KERN_ERR "EDA cache already contains entry "
125 "for neighbor %02x:%02x\n",
126 dev_addr->data[1], dev_addr->data[0]);
127 result = -EEXIST;
128 goto out_unlock;
129 }
130 }
131 itr = kzalloc(sizeof(*itr), GFP_ATOMIC);
132 if (itr != NULL) {
133 memcpy(itr->eth_addr, eth_addr, sizeof(itr->eth_addr));
134 itr->dev_addr = *dev_addr;
135 list_add(&itr->list_node, &eda->cache);
136 } else
137 result = -ENOMEM;
138 out_unlock:
139 spin_unlock_irqrestore(&eda->lock, flags);
140 return result;
141 }
142
143 /*
144 * Remove entry from EDA cache
145 *
146 * This is done when the device goes off air.
147 */
148 void wlp_eda_rm_node(struct wlp_eda *eda, const struct uwb_dev_addr *dev_addr)
149 {
150 struct wlp_eda_node *itr, *next;
151 unsigned long flags;
152
153 spin_lock_irqsave(&eda->lock, flags);
154 list_for_each_entry_safe(itr, next, &eda->cache, list_node) {
155 if (!memcmp(&itr->dev_addr, dev_addr, sizeof(itr->dev_addr))) {
156 list_del(&itr->list_node);
157 kfree(itr);
158 break;
159 }
160 }
161 spin_unlock_irqrestore(&eda->lock, flags);
162 }
163
164 /*
165 * Update an address mapping
166 *
167 * @returns 0 if ok, < 0 errno code on error
168 */
169 int wlp_eda_update_node(struct wlp_eda *eda,
170 const struct uwb_dev_addr *dev_addr,
171 struct wlp_wss *wss,
172 const unsigned char virt_addr[ETH_ALEN],
173 const u8 tag, const enum wlp_wss_connect state)
174 {
175 int result = -ENOENT;
176 struct wlp_eda_node *itr;
177 unsigned long flags;
178
179 spin_lock_irqsave(&eda->lock, flags);
180 list_for_each_entry(itr, &eda->cache, list_node) {
181 if (!memcmp(&itr->dev_addr, dev_addr, sizeof(itr->dev_addr))) {
182 /* Found it, update it */
183 itr->wss = wss;
184 memcpy(itr->virt_addr, virt_addr,
185 sizeof(itr->virt_addr));
186 itr->tag = tag;
187 itr->state = state;
188 result = 0;
189 goto out_unlock;
190 }
191 }
192 /* Not found */
193 out_unlock:
194 spin_unlock_irqrestore(&eda->lock, flags);
195 return result;
196 }
197
198 /*
199 * Update only state field of an address mapping
200 *
201 * @returns 0 if ok, < 0 errno code on error
202 */
203 int wlp_eda_update_node_state(struct wlp_eda *eda,
204 const struct uwb_dev_addr *dev_addr,
205 const enum wlp_wss_connect state)
206 {
207 int result = -ENOENT;
208 struct wlp_eda_node *itr;
209 unsigned long flags;
210
211 spin_lock_irqsave(&eda->lock, flags);
212 list_for_each_entry(itr, &eda->cache, list_node) {
213 if (!memcmp(&itr->dev_addr, dev_addr, sizeof(itr->dev_addr))) {
214 /* Found it, update it */
215 itr->state = state;
216 result = 0;
217 goto out_unlock;
218 }
219 }
220 /* Not found */
221 out_unlock:
222 spin_unlock_irqrestore(&eda->lock, flags);
223 return result;
224 }
225
226 /*
227 * Return contents of EDA cache entry
228 *
229 * @dev_addr: index to EDA cache
230 * @eda_entry: pointer to where contents of EDA cache will be copied
231 */
232 int wlp_copy_eda_node(struct wlp_eda *eda, struct uwb_dev_addr *dev_addr,
233 struct wlp_eda_node *eda_entry)
234 {
235 int result = -ENOENT;
236 struct wlp_eda_node *itr;
237 unsigned long flags;
238
239 spin_lock_irqsave(&eda->lock, flags);
240 list_for_each_entry(itr, &eda->cache, list_node) {
241 if (!memcmp(&itr->dev_addr, dev_addr, sizeof(itr->dev_addr))) {
242 *eda_entry = *itr;
243 result = 0;
244 goto out_unlock;
245 }
246 }
247 /* Not found */
248 out_unlock:
249 spin_unlock_irqrestore(&eda->lock, flags);
250 return result;
251 }
252
253 /*
254 * Execute function for every element in the cache
255 *
256 * @function: function to execute on element of cache (must be atomic)
257 * @priv: private data of function
258 * @returns: result of first function that failed, or last function
259 * executed if no function failed.
260 *
261 * Stop executing when function returns error for any element in cache.
262 *
263 * IMPORTANT: We are using a spinlock here: the function executed on each
264 * element has to be atomic.
265 */
266 int wlp_eda_for_each(struct wlp_eda *eda, wlp_eda_for_each_f function,
267 void *priv)
268 {
269 int result = 0;
270 struct wlp *wlp = container_of(eda, struct wlp, eda);
271 struct wlp_eda_node *entry;
272 unsigned long flags;
273
274 spin_lock_irqsave(&eda->lock, flags);
275 list_for_each_entry(entry, &eda->cache, list_node) {
276 result = (*function)(wlp, entry, priv);
277 if (result < 0)
278 break;
279 }
280 spin_unlock_irqrestore(&eda->lock, flags);
281 return result;
282 }
283
284 /*
285 * Execute function for single element in the cache (return dev addr)
286 *
287 * @virt_addr: index into EDA cache used to determine which element to
288 * execute the function on
289 * @dev_addr: device address of element in cache will be returned using
290 * @dev_addr
291 * @function: function to execute on element of cache (must be atomic)
292 * @priv: private data of function
293 * @returns: result of function
294 *
295 * IMPORTANT: We are using a spinlock here: the function executed on the
296 * element has to be atomic.
297 */
298 int wlp_eda_for_virtual(struct wlp_eda *eda,
299 const unsigned char virt_addr[ETH_ALEN],
300 struct uwb_dev_addr *dev_addr,
301 wlp_eda_for_each_f function,
302 void *priv)
303 {
304 int result = 0;
305 struct wlp *wlp = container_of(eda, struct wlp, eda);
306 struct wlp_eda_node *itr;
307 unsigned long flags;
308 int found = 0;
309
310 spin_lock_irqsave(&eda->lock, flags);
311 list_for_each_entry(itr, &eda->cache, list_node) {
312 if (!memcmp(itr->virt_addr, virt_addr,
313 sizeof(itr->virt_addr))) {
314 result = (*function)(wlp, itr, priv);
315 *dev_addr = itr->dev_addr;
316 found = 1;
317 break;
318 }
319 }
320 if (!found)
321 result = -ENODEV;
322 spin_unlock_irqrestore(&eda->lock, flags);
323 return result;
324 }
325
326 static const char *__wlp_wss_connect_state[] = { "WLP_WSS_UNCONNECTED",
327 "WLP_WSS_CONNECTED",
328 "WLP_WSS_CONNECT_FAILED",
329 };
330
331 static const char *wlp_wss_connect_state_str(unsigned id)
332 {
333 if (id >= ARRAY_SIZE(__wlp_wss_connect_state))
334 return "unknown WSS connection state";
335 return __wlp_wss_connect_state[id];
336 }
337
338 /*
339 * View EDA cache from user space
340 *
341 * A debugging feature to give user visibility into the EDA cache. Also
342 * used to display members of WSS to user (called from wlp_wss_members_show())
343 */
344 ssize_t wlp_eda_show(struct wlp *wlp, char *buf)
345 {
346 ssize_t result = 0;
347 struct wlp_eda_node *entry;
348 unsigned long flags;
349 struct wlp_eda *eda = &wlp->eda;
350 spin_lock_irqsave(&eda->lock, flags);
351 result = scnprintf(buf, PAGE_SIZE, "#eth_addr dev_addr wss_ptr "
352 "tag state virt_addr\n");
353 list_for_each_entry(entry, &eda->cache, list_node) {
354 result += scnprintf(buf + result, PAGE_SIZE - result,
355 "%pM %02x:%02x %p 0x%02x %s %pM\n",
356 entry->eth_addr,
357 entry->dev_addr.data[1],
358 entry->dev_addr.data[0], entry->wss,
359 entry->tag,
360 wlp_wss_connect_state_str(entry->state),
361 entry->virt_addr);
362 if (result >= PAGE_SIZE)
363 break;
364 }
365 spin_unlock_irqrestore(&eda->lock, flags);
366 return result;
367 }
368 EXPORT_SYMBOL_GPL(wlp_eda_show);
369
370 /*
371 * Add new EDA cache entry based on user input in sysfs
372 *
373 * Should only be used for debugging.
374 *
375 * The WSS is assumed to be the only WSS supported. This needs to be
376 * redesigned when we support more than one WSS.
377 */
378 ssize_t wlp_eda_store(struct wlp *wlp, const char *buf, size_t size)
379 {
380 ssize_t result;
381 struct wlp_eda *eda = &wlp->eda;
382 u8 eth_addr[6];
383 struct uwb_dev_addr dev_addr;
384 u8 tag;
385 unsigned state;
386
387 result = sscanf(buf, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx "
388 "%02hhx:%02hhx %02hhx %u\n",
389 &eth_addr[0], &eth_addr[1],
390 &eth_addr[2], &eth_addr[3],
391 &eth_addr[4], &eth_addr[5],
392 &dev_addr.data[1], &dev_addr.data[0], &tag, &state);
393 switch (result) {
394 case 6: /* no dev addr specified -- remove entry NOT IMPLEMENTED */
395 /*result = wlp_eda_rm(eda, eth_addr, &dev_addr);*/
396 result = -ENOSYS;
397 break;
398 case 10:
399 state = state >= 1 ? 1 : 0;
400 result = wlp_eda_create_node(eda, eth_addr, &dev_addr);
401 if (result < 0 && result != -EEXIST)
402 goto error;
403 /* Set virtual addr to be same as MAC */
404 result = wlp_eda_update_node(eda, &dev_addr, &wlp->wss,
405 eth_addr, tag, state);
406 if (result < 0)
407 goto error;
408 break;
409 default: /* bad format */
410 result = -EINVAL;
411 }
412 error:
413 return result < 0 ? result : size;
414 }
415 EXPORT_SYMBOL_GPL(wlp_eda_store);