]> Pileus Git - ~andy/linux/blob - drivers/uwb/wlp/eda.c
Merge branch 'fix/hda' into for-linus
[~andy/linux] / 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);