blob: 69e020039718aed4711849b0b9fee3c80dfea866 [file] [log] [blame]
Reinette Chatref5144852008-09-17 16:34:16 +01001/*
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
Reinette Chatref5144852008-09-17 16:34:16 +010054#include <linux/netdevice.h>
Reinette Chatref5144852008-09-17 16:34:16 +010055#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 */
74void 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 */
87void 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 */
111int 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;
137out_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 */
147void 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 */
168int 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 */
192out_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 */
202int 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 */
220out_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 */
231int 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 */
247out_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 */
265int 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 */
297int 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);
Reinette Chatref5144852008-09-17 16:34:16 +0100305 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))) {
Reinette Chatref5144852008-09-17 16:34:16 +0100313 result = (*function)(wlp, itr, priv);
314 *dev_addr = itr->dev_addr;
315 found = 1;
316 break;
David Vrabelbce83692008-12-22 18:22:50 +0000317 }
Reinette Chatref5144852008-09-17 16:34:16 +0100318 }
David Vrabelbce83692008-12-22 18:22:50 +0000319 if (!found)
Reinette Chatref5144852008-09-17 16:34:16 +0100320 result = -ENODEV;
Reinette Chatref5144852008-09-17 16:34:16 +0100321 spin_unlock_irqrestore(&eda->lock, flags);
322 return result;
323}
324
325static const char *__wlp_wss_connect_state[] = { "WLP_WSS_UNCONNECTED",
326 "WLP_WSS_CONNECTED",
327 "WLP_WSS_CONNECT_FAILED",
328};
329
330static 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 */
343ssize_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,
Harvey Harrisona20fd0a2008-10-28 22:38:06 -0700354 "%pM %02x:%02x %p 0x%02x %s %pM\n",
355 entry->eth_addr,
Reinette Chatref5144852008-09-17 16:34:16 +0100356 entry->dev_addr.data[1],
357 entry->dev_addr.data[0], entry->wss,
358 entry->tag,
359 wlp_wss_connect_state_str(entry->state),
Harvey Harrisona20fd0a2008-10-28 22:38:06 -0700360 entry->virt_addr);
Reinette Chatref5144852008-09-17 16:34:16 +0100361 if (result >= PAGE_SIZE)
362 break;
363 }
364 spin_unlock_irqrestore(&eda->lock, flags);
365 return result;
366}
367EXPORT_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 */
377ssize_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 }
411error:
412 return result < 0 ? result : size;
413}
414EXPORT_SYMBOL_GPL(wlp_eda_store);