GUI: Fix Tomato RAF theme for all builds. Compilation typo.
[tomato.git] / release / src-rt-6.x.4708 / linux / linux-2.6.36 / drivers / uwb / wlp / eda.c
blobc76adf88f36b81b59f4dc189d3e1bbe70396966e
1 /*
2 * WUSB Wire Adapter: WLP interface
3 * Ethernet to device address cache
5 * Copyright (C) 2005-2006 Intel Corporation
6 * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
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.
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.
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.
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 :).
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.
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.
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.
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"
64 * Initialize the EDA cache
66 * @returns 0 if ok, < 0 errno code on error
68 * Call when the interface is being brought up
70 * NOTE: Keep it as a separate function as the implementation will
71 * change and be more complex.
73 void wlp_eda_init(struct wlp_eda *eda)
75 INIT_LIST_HEAD(&eda->cache);
76 spin_lock_init(&eda->lock);
80 * Release the EDA cache
82 * @returns 0 if ok, < 0 errno code on error
84 * Called when the interface is brought down
86 void wlp_eda_release(struct wlp_eda *eda)
88 unsigned long flags;
89 struct wlp_eda_node *itr, *next;
91 spin_lock_irqsave(&eda->lock, flags);
92 list_for_each_entry_safe(itr, next, &eda->cache, list_node) {
93 list_del(&itr->list_node);
94 kfree(itr);
96 spin_unlock_irqrestore(&eda->lock, flags);
100 * Add an address mapping
102 * @returns 0 if ok, < 0 errno code on error
104 * An address mapping is initially created when the neighbor device is seen
105 * for the first time (it is "onair"). At this time the neighbor is not
106 * connected or associated with a WSS so we only populate the Ethernet and
107 * Device address fields.
110 int wlp_eda_create_node(struct wlp_eda *eda,
111 const unsigned char eth_addr[ETH_ALEN],
112 const struct uwb_dev_addr *dev_addr)
114 int result = 0;
115 struct wlp_eda_node *itr;
116 unsigned long flags;
118 BUG_ON(dev_addr == NULL || eth_addr == NULL);
119 spin_lock_irqsave(&eda->lock, flags);
120 list_for_each_entry(itr, &eda->cache, list_node) {
121 if (!memcmp(&itr->dev_addr, dev_addr, sizeof(itr->dev_addr))) {
122 printk(KERN_ERR "EDA cache already contains entry "
123 "for neighbor %02x:%02x\n",
124 dev_addr->data[1], dev_addr->data[0]);
125 result = -EEXIST;
126 goto out_unlock;
129 itr = kzalloc(sizeof(*itr), GFP_ATOMIC);
130 if (itr != NULL) {
131 memcpy(itr->eth_addr, eth_addr, sizeof(itr->eth_addr));
132 itr->dev_addr = *dev_addr;
133 list_add(&itr->list_node, &eda->cache);
134 } else
135 result = -ENOMEM;
136 out_unlock:
137 spin_unlock_irqrestore(&eda->lock, flags);
138 return result;
142 * Remove entry from EDA cache
144 * This is done when the device goes off air.
146 void wlp_eda_rm_node(struct wlp_eda *eda, const struct uwb_dev_addr *dev_addr)
148 struct wlp_eda_node *itr, *next;
149 unsigned long flags;
151 spin_lock_irqsave(&eda->lock, flags);
152 list_for_each_entry_safe(itr, next, &eda->cache, list_node) {
153 if (!memcmp(&itr->dev_addr, dev_addr, sizeof(itr->dev_addr))) {
154 list_del(&itr->list_node);
155 kfree(itr);
156 break;
159 spin_unlock_irqrestore(&eda->lock, flags);
163 * Update an address mapping
165 * @returns 0 if ok, < 0 errno code on error
167 int wlp_eda_update_node(struct wlp_eda *eda,
168 const struct uwb_dev_addr *dev_addr,
169 struct wlp_wss *wss,
170 const unsigned char virt_addr[ETH_ALEN],
171 const u8 tag, const enum wlp_wss_connect state)
173 int result = -ENOENT;
174 struct wlp_eda_node *itr;
175 unsigned long flags;
177 spin_lock_irqsave(&eda->lock, flags);
178 list_for_each_entry(itr, &eda->cache, list_node) {
179 if (!memcmp(&itr->dev_addr, dev_addr, sizeof(itr->dev_addr))) {
180 /* Found it, update it */
181 itr->wss = wss;
182 memcpy(itr->virt_addr, virt_addr,
183 sizeof(itr->virt_addr));
184 itr->tag = tag;
185 itr->state = state;
186 result = 0;
187 goto out_unlock;
190 /* Not found */
191 out_unlock:
192 spin_unlock_irqrestore(&eda->lock, flags);
193 return result;
197 * Update only state field of an address mapping
199 * @returns 0 if ok, < 0 errno code on error
201 int wlp_eda_update_node_state(struct wlp_eda *eda,
202 const struct uwb_dev_addr *dev_addr,
203 const enum wlp_wss_connect state)
205 int result = -ENOENT;
206 struct wlp_eda_node *itr;
207 unsigned long flags;
209 spin_lock_irqsave(&eda->lock, flags);
210 list_for_each_entry(itr, &eda->cache, list_node) {
211 if (!memcmp(&itr->dev_addr, dev_addr, sizeof(itr->dev_addr))) {
212 /* Found it, update it */
213 itr->state = state;
214 result = 0;
215 goto out_unlock;
218 /* Not found */
219 out_unlock:
220 spin_unlock_irqrestore(&eda->lock, flags);
221 return result;
225 * Return contents of EDA cache entry
227 * @dev_addr: index to EDA cache
228 * @eda_entry: pointer to where contents of EDA cache will be copied
230 int wlp_copy_eda_node(struct wlp_eda *eda, struct uwb_dev_addr *dev_addr,
231 struct wlp_eda_node *eda_entry)
233 int result = -ENOENT;
234 struct wlp_eda_node *itr;
235 unsigned long flags;
237 spin_lock_irqsave(&eda->lock, flags);
238 list_for_each_entry(itr, &eda->cache, list_node) {
239 if (!memcmp(&itr->dev_addr, dev_addr, sizeof(itr->dev_addr))) {
240 *eda_entry = *itr;
241 result = 0;
242 goto out_unlock;
245 /* Not found */
246 out_unlock:
247 spin_unlock_irqrestore(&eda->lock, flags);
248 return result;
252 * Execute function for every element in the cache
254 * @function: function to execute on element of cache (must be atomic)
255 * @priv: private data of function
256 * @returns: result of first function that failed, or last function
257 * executed if no function failed.
259 * Stop executing when function returns error for any element in cache.
261 * IMPORTANT: We are using a spinlock here: the function executed on each
262 * element has to be atomic.
264 int wlp_eda_for_each(struct wlp_eda *eda, wlp_eda_for_each_f function,
265 void *priv)
267 int result = 0;
268 struct wlp *wlp = container_of(eda, struct wlp, eda);
269 struct wlp_eda_node *entry;
270 unsigned long flags;
272 spin_lock_irqsave(&eda->lock, flags);
273 list_for_each_entry(entry, &eda->cache, list_node) {
274 result = (*function)(wlp, entry, priv);
275 if (result < 0)
276 break;
278 spin_unlock_irqrestore(&eda->lock, flags);
279 return result;
283 * Execute function for single element in the cache (return dev addr)
285 * @virt_addr: index into EDA cache used to determine which element to
286 * execute the function on
287 * @dev_addr: device address of element in cache will be returned using
288 * @dev_addr
289 * @function: function to execute on element of cache (must be atomic)
290 * @priv: private data of function
291 * @returns: result of function
293 * IMPORTANT: We are using a spinlock here: the function executed on the
294 * element has to be atomic.
296 int wlp_eda_for_virtual(struct wlp_eda *eda,
297 const unsigned char virt_addr[ETH_ALEN],
298 struct uwb_dev_addr *dev_addr,
299 wlp_eda_for_each_f function,
300 void *priv)
302 int result = 0;
303 struct wlp *wlp = container_of(eda, struct wlp, eda);
304 struct wlp_eda_node *itr;
305 unsigned long flags;
306 int found = 0;
308 spin_lock_irqsave(&eda->lock, flags);
309 list_for_each_entry(itr, &eda->cache, list_node) {
310 if (!memcmp(itr->virt_addr, virt_addr,
311 sizeof(itr->virt_addr))) {
312 result = (*function)(wlp, itr, priv);
313 *dev_addr = itr->dev_addr;
314 found = 1;
315 break;
318 if (!found)
319 result = -ENODEV;
320 spin_unlock_irqrestore(&eda->lock, flags);
321 return result;
324 static const char *__wlp_wss_connect_state[] = { "WLP_WSS_UNCONNECTED",
325 "WLP_WSS_CONNECTED",
326 "WLP_WSS_CONNECT_FAILED",
329 static const char *wlp_wss_connect_state_str(unsigned id)
331 if (id >= ARRAY_SIZE(__wlp_wss_connect_state))
332 return "unknown WSS connection state";
333 return __wlp_wss_connect_state[id];
337 * View EDA cache from user space
339 * A debugging feature to give user visibility into the EDA cache. Also
340 * used to display members of WSS to user (called from wlp_wss_members_show())
342 ssize_t wlp_eda_show(struct wlp *wlp, char *buf)
344 ssize_t result = 0;
345 struct wlp_eda_node *entry;
346 unsigned long flags;
347 struct wlp_eda *eda = &wlp->eda;
348 spin_lock_irqsave(&eda->lock, flags);
349 result = scnprintf(buf, PAGE_SIZE, "#eth_addr dev_addr wss_ptr "
350 "tag state virt_addr\n");
351 list_for_each_entry(entry, &eda->cache, list_node) {
352 result += scnprintf(buf + result, PAGE_SIZE - result,
353 "%pM %02x:%02x %p 0x%02x %s %pM\n",
354 entry->eth_addr,
355 entry->dev_addr.data[1],
356 entry->dev_addr.data[0], entry->wss,
357 entry->tag,
358 wlp_wss_connect_state_str(entry->state),
359 entry->virt_addr);
360 if (result >= PAGE_SIZE)
361 break;
363 spin_unlock_irqrestore(&eda->lock, flags);
364 return result;
366 EXPORT_SYMBOL_GPL(wlp_eda_show);
369 * Add new EDA cache entry based on user input in sysfs
371 * Should only be used for debugging.
373 * The WSS is assumed to be the only WSS supported. This needs to be
374 * redesigned when we support more than one WSS.
376 ssize_t wlp_eda_store(struct wlp *wlp, const char *buf, size_t size)
378 ssize_t result;
379 struct wlp_eda *eda = &wlp->eda;
380 u8 eth_addr[6];
381 struct uwb_dev_addr dev_addr;
382 u8 tag;
383 unsigned state;
385 result = sscanf(buf, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx "
386 "%02hhx:%02hhx %02hhx %u\n",
387 &eth_addr[0], &eth_addr[1],
388 &eth_addr[2], &eth_addr[3],
389 &eth_addr[4], &eth_addr[5],
390 &dev_addr.data[1], &dev_addr.data[0], &tag, &state);
391 switch (result) {
392 case 6: /* no dev addr specified -- remove entry NOT IMPLEMENTED */
393 /*result = wlp_eda_rm(eda, eth_addr, &dev_addr);*/
394 result = -ENOSYS;
395 break;
396 case 10:
397 state = state >= 1 ? 1 : 0;
398 result = wlp_eda_create_node(eda, eth_addr, &dev_addr);
399 if (result < 0 && result != -EEXIST)
400 goto error;
401 /* Set virtual addr to be same as MAC */
402 result = wlp_eda_update_node(eda, &dev_addr, &wlp->wss,
403 eth_addr, tag, state);
404 if (result < 0)
405 goto error;
406 break;
407 default: /* bad format */
408 result = -EINVAL;
410 error:
411 return result < 0 ? result : size;
413 EXPORT_SYMBOL_GPL(wlp_eda_store);