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