Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux...
[linux-2.6.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/wlp.h>
57 #include "wlp-internal.h"
58
59
60 /* FIXME: cache is not purged, only on device close */
61
62 /* FIXME: does not scale, change to dynamic array */
63
64 /*
65  * Initialize the EDA cache
66  *
67  * @returns 0 if ok, < 0 errno code on error
68  *
69  * Call when the interface is being brought up
70  *
71  * NOTE: Keep it as a separate function as the implementation will
72  *       change and be more complex.
73  */
74 void wlp_eda_init(struct wlp_eda *eda)
75 {
76         INIT_LIST_HEAD(&eda->cache);
77         spin_lock_init(&eda->lock);
78 }
79
80 /*
81  * Release the EDA cache
82  *
83  * @returns 0 if ok, < 0 errno code on error
84  *
85  * Called when the interface is brought down
86  */
87 void wlp_eda_release(struct wlp_eda *eda)
88 {
89         unsigned long flags;
90         struct wlp_eda_node *itr, *next;
91
92         spin_lock_irqsave(&eda->lock, flags);
93         list_for_each_entry_safe(itr, next, &eda->cache, list_node) {
94                 list_del(&itr->list_node);
95                 kfree(itr);
96         }
97         spin_unlock_irqrestore(&eda->lock, flags);
98 }
99
100 /*
101  * Add an address mapping
102  *
103  * @returns 0 if ok, < 0 errno code on error
104  *
105  * An address mapping is initially created when the neighbor device is seen
106  * for the first time (it is "onair"). At this time the neighbor is not
107  * connected or associated with a WSS so we only populate the Ethernet and
108  * Device address fields.
109  *
110  */
111 int wlp_eda_create_node(struct wlp_eda *eda,
112                         const unsigned char eth_addr[ETH_ALEN],
113                         const struct uwb_dev_addr *dev_addr)
114 {
115         int result = 0;
116         struct wlp_eda_node *itr;
117         unsigned long flags;
118
119         BUG_ON(dev_addr == NULL || eth_addr == NULL);
120         spin_lock_irqsave(&eda->lock, flags);
121         list_for_each_entry(itr, &eda->cache, list_node) {
122                 if (!memcmp(&itr->dev_addr, dev_addr, sizeof(itr->dev_addr))) {
123                         printk(KERN_ERR "EDA cache already contains entry "
124                                "for neighbor %02x:%02x\n",
125                                dev_addr->data[1], dev_addr->data[0]);
126                         result = -EEXIST;
127                         goto out_unlock;
128                 }
129         }
130         itr = kzalloc(sizeof(*itr), GFP_ATOMIC);
131         if (itr != NULL) {
132                 memcpy(itr->eth_addr, eth_addr, sizeof(itr->eth_addr));
133                 itr->dev_addr = *dev_addr;
134                 list_add(&itr->list_node, &eda->cache);
135         } else
136                 result = -ENOMEM;
137 out_unlock:
138         spin_unlock_irqrestore(&eda->lock, flags);
139         return result;
140 }
141
142 /*
143  * Remove entry from EDA cache
144  *
145  * This is done when the device goes off air.
146  */
147 void wlp_eda_rm_node(struct wlp_eda *eda, const struct uwb_dev_addr *dev_addr)
148 {
149         struct wlp_eda_node *itr, *next;
150         unsigned long flags;
151
152         spin_lock_irqsave(&eda->lock, flags);
153         list_for_each_entry_safe(itr, next, &eda->cache, list_node) {
154                 if (!memcmp(&itr->dev_addr, dev_addr, sizeof(itr->dev_addr))) {
155                         list_del(&itr->list_node);
156                         kfree(itr);
157                         break;
158                 }
159         }
160         spin_unlock_irqrestore(&eda->lock, flags);
161 }
162
163 /*
164  * Update an address mapping
165  *
166  * @returns 0 if ok, < 0 errno code on error
167  */
168 int wlp_eda_update_node(struct wlp_eda *eda,
169                         const struct uwb_dev_addr *dev_addr,
170                         struct wlp_wss *wss,
171                         const unsigned char virt_addr[ETH_ALEN],
172                         const u8 tag, const enum wlp_wss_connect state)
173 {
174         int result = -ENOENT;
175         struct wlp_eda_node *itr;
176         unsigned long flags;
177
178         spin_lock_irqsave(&eda->lock, flags);
179         list_for_each_entry(itr, &eda->cache, list_node) {
180                 if (!memcmp(&itr->dev_addr, dev_addr, sizeof(itr->dev_addr))) {
181                         /* Found it, update it */
182                         itr->wss = wss;
183                         memcpy(itr->virt_addr, virt_addr,
184                                sizeof(itr->virt_addr));
185                         itr->tag = tag;
186                         itr->state = state;
187                         result = 0;
188                         goto out_unlock;
189                 }
190         }
191         /* Not found */
192 out_unlock:
193         spin_unlock_irqrestore(&eda->lock, flags);
194         return result;
195 }
196
197 /*
198  * Update only state field of an address mapping
199  *
200  * @returns 0 if ok, < 0 errno code on error
201  */
202 int wlp_eda_update_node_state(struct wlp_eda *eda,
203                               const struct uwb_dev_addr *dev_addr,
204                               const enum wlp_wss_connect state)
205 {
206         int result = -ENOENT;
207         struct wlp_eda_node *itr;
208         unsigned long flags;
209
210         spin_lock_irqsave(&eda->lock, flags);
211         list_for_each_entry(itr, &eda->cache, list_node) {
212                 if (!memcmp(&itr->dev_addr, dev_addr, sizeof(itr->dev_addr))) {
213                         /* Found it, update it */
214                         itr->state = state;
215                         result = 0;
216                         goto out_unlock;
217                 }
218         }
219         /* Not found */
220 out_unlock:
221         spin_unlock_irqrestore(&eda->lock, flags);
222         return result;
223 }
224
225 /*
226  * Return contents of EDA cache entry
227  *
228  * @dev_addr: index to EDA cache
229  * @eda_entry: pointer to where contents of EDA cache will be copied
230  */
231 int wlp_copy_eda_node(struct wlp_eda *eda, struct uwb_dev_addr *dev_addr,
232                       struct wlp_eda_node *eda_entry)
233 {
234         int result = -ENOENT;
235         struct wlp_eda_node *itr;
236         unsigned long flags;
237
238         spin_lock_irqsave(&eda->lock, flags);
239         list_for_each_entry(itr, &eda->cache, list_node) {
240                 if (!memcmp(&itr->dev_addr, dev_addr, sizeof(itr->dev_addr))) {
241                         *eda_entry = *itr;
242                         result = 0;
243                         goto out_unlock;
244                 }
245         }
246         /* Not found */
247 out_unlock:
248         spin_unlock_irqrestore(&eda->lock, flags);
249         return result;
250 }
251
252 /*
253  * Execute function for every element in the cache
254  *
255  * @function: function to execute on element of cache (must be atomic)
256  * @priv:     private data of function
257  * @returns:  result of first function that failed, or last function
258  *            executed if no function failed.
259  *
260  * Stop executing when function returns error for any element in cache.
261  *
262  * IMPORTANT: We are using a spinlock here: the function executed on each
263  * element has to be atomic.
264  */
265 int wlp_eda_for_each(struct wlp_eda *eda, wlp_eda_for_each_f function,
266                      void *priv)
267 {
268         int result = 0;
269         struct wlp *wlp = container_of(eda, struct wlp, eda);
270         struct wlp_eda_node *entry;
271         unsigned long flags;
272
273         spin_lock_irqsave(&eda->lock, flags);
274         list_for_each_entry(entry, &eda->cache, list_node) {
275                 result = (*function)(wlp, entry, priv);
276                 if (result < 0)
277                         break;
278         }
279         spin_unlock_irqrestore(&eda->lock, flags);
280         return result;
281 }
282
283 /*
284  * Execute function for single element in the cache (return dev addr)
285  *
286  * @virt_addr: index into EDA cache used to determine which element to
287  *             execute the function on
288  * @dev_addr: device address of element in cache will be returned using
289  *            @dev_addr
290  * @function: function to execute on element of cache (must be atomic)
291  * @priv:     private data of function
292  * @returns:  result of function
293  *
294  * IMPORTANT: We are using a spinlock here: the function executed on the
295  * element has to be atomic.
296  */
297 int wlp_eda_for_virtual(struct wlp_eda *eda,
298                         const unsigned char virt_addr[ETH_ALEN],
299                         struct uwb_dev_addr *dev_addr,
300                         wlp_eda_for_each_f function,
301                         void *priv)
302 {
303         int result = 0;
304         struct wlp *wlp = container_of(eda, struct wlp, eda);
305         struct wlp_eda_node *itr;
306         unsigned long flags;
307         int found = 0;
308
309         spin_lock_irqsave(&eda->lock, flags);
310         list_for_each_entry(itr, &eda->cache, list_node) {
311                 if (!memcmp(itr->virt_addr, virt_addr,
312                            sizeof(itr->virt_addr))) {
313                         result = (*function)(wlp, itr, priv);
314                         *dev_addr = itr->dev_addr;
315                         found = 1;
316                         break;
317                 }
318         }
319         if (!found)
320                 result = -ENODEV;
321         spin_unlock_irqrestore(&eda->lock, flags);
322         return result;
323 }
324
325 static const char *__wlp_wss_connect_state[] = { "WLP_WSS_UNCONNECTED",
326                                           "WLP_WSS_CONNECTED",
327                                           "WLP_WSS_CONNECT_FAILED",
328 };
329
330 static const char *wlp_wss_connect_state_str(unsigned id)
331 {
332         if (id >= ARRAY_SIZE(__wlp_wss_connect_state))
333                 return "unknown WSS connection state";
334         return __wlp_wss_connect_state[id];
335 }
336
337 /*
338  * View EDA cache from user space
339  *
340  * A debugging feature to give user visibility into the EDA cache. Also
341  * used to display members of WSS to user (called from wlp_wss_members_show())
342  */
343 ssize_t wlp_eda_show(struct wlp *wlp, char *buf)
344 {
345         ssize_t result = 0;
346         struct wlp_eda_node *entry;
347         unsigned long flags;
348         struct wlp_eda *eda = &wlp->eda;
349         spin_lock_irqsave(&eda->lock, flags);
350         result = scnprintf(buf, PAGE_SIZE, "#eth_addr dev_addr wss_ptr "
351                            "tag state virt_addr\n");
352         list_for_each_entry(entry, &eda->cache, list_node) {
353                 result += scnprintf(buf + result, PAGE_SIZE - result,
354                                     "%pM %02x:%02x %p 0x%02x %s %pM\n",
355                                     entry->eth_addr,
356                                     entry->dev_addr.data[1],
357                                     entry->dev_addr.data[0], entry->wss,
358                                     entry->tag,
359                                     wlp_wss_connect_state_str(entry->state),
360                                     entry->virt_addr);
361                 if (result >= PAGE_SIZE)
362                         break;
363         }
364         spin_unlock_irqrestore(&eda->lock, flags);
365         return result;
366 }
367 EXPORT_SYMBOL_GPL(wlp_eda_show);
368
369 /*
370  * Add new EDA cache entry based on user input in sysfs
371  *
372  * Should only be used for debugging.
373  *
374  * The WSS is assumed to be the only WSS supported. This needs to be
375  * redesigned when we support more than one WSS.
376  */
377 ssize_t wlp_eda_store(struct wlp *wlp, const char *buf, size_t size)
378 {
379         ssize_t result;
380         struct wlp_eda *eda = &wlp->eda;
381         u8 eth_addr[6];
382         struct uwb_dev_addr dev_addr;
383         u8 tag;
384         unsigned state;
385
386         result = sscanf(buf, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx "
387                         "%02hhx:%02hhx %02hhx %u\n",
388                         &eth_addr[0], &eth_addr[1],
389                         &eth_addr[2], &eth_addr[3],
390                         &eth_addr[4], &eth_addr[5],
391                         &dev_addr.data[1], &dev_addr.data[0], &tag, &state);
392         switch (result) {
393         case 6: /* no dev addr specified -- remove entry NOT IMPLEMENTED */
394                 /*result = wlp_eda_rm(eda, eth_addr, &dev_addr);*/
395                 result = -ENOSYS;
396                 break;
397         case 10:
398                 state = state >= 1 ? 1 : 0;
399                 result = wlp_eda_create_node(eda, eth_addr, &dev_addr);
400                 if (result < 0 && result != -EEXIST)
401                         goto error;
402                 /* Set virtual addr to be same as MAC */
403                 result = wlp_eda_update_node(eda, &dev_addr, &wlp->wss,
404                                              eth_addr, tag, state);
405                 if (result < 0)
406                         goto error;
407                 break;
408         default: /* bad format */
409                 result = -EINVAL;
410         }
411 error:
412         return result < 0 ? result : size;
413 }
414 EXPORT_SYMBOL_GPL(wlp_eda_store);