• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6.36/drivers/uwb/wlp/
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
62
63/*
64 * Initialize the EDA cache
65 *
66 * @returns 0 if ok, < 0 errno code on error
67 *
68 * Call when the interface is being brought up
69 *
70 * NOTE: Keep it as a separate function as the implementation will
71 *       change and be more complex.
72 */
73void wlp_eda_init(struct wlp_eda *eda)
74{
75	INIT_LIST_HEAD(&eda->cache);
76	spin_lock_init(&eda->lock);
77}
78
79/*
80 * Release the EDA cache
81 *
82 * @returns 0 if ok, < 0 errno code on error
83 *
84 * Called when the interface is brought down
85 */
86void wlp_eda_release(struct wlp_eda *eda)
87{
88	unsigned long flags;
89	struct wlp_eda_node *itr, *next;
90
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);
95	}
96	spin_unlock_irqrestore(&eda->lock, flags);
97}
98
99/*
100 * Add an address mapping
101 *
102 * @returns 0 if ok, < 0 errno code on error
103 *
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.
108 *
109 */
110int wlp_eda_create_node(struct wlp_eda *eda,
111			const unsigned char eth_addr[ETH_ALEN],
112			const struct uwb_dev_addr *dev_addr)
113{
114	int result = 0;
115	struct wlp_eda_node *itr;
116	unsigned long flags;
117
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;
127		}
128	}
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;
136out_unlock:
137	spin_unlock_irqrestore(&eda->lock, flags);
138	return result;
139}
140
141/*
142 * Remove entry from EDA cache
143 *
144 * This is done when the device goes off air.
145 */
146void wlp_eda_rm_node(struct wlp_eda *eda, const struct uwb_dev_addr *dev_addr)
147{
148	struct wlp_eda_node *itr, *next;
149	unsigned long flags;
150
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;
157		}
158	}
159	spin_unlock_irqrestore(&eda->lock, flags);
160}
161
162/*
163 * Update an address mapping
164 *
165 * @returns 0 if ok, < 0 errno code on error
166 */
167int 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)
172{
173	int result = -ENOENT;
174	struct wlp_eda_node *itr;
175	unsigned long flags;
176
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;
188		}
189	}
190	/* Not found */
191out_unlock:
192	spin_unlock_irqrestore(&eda->lock, flags);
193	return result;
194}
195
196/*
197 * Update only state field of an address mapping
198 *
199 * @returns 0 if ok, < 0 errno code on error
200 */
201int wlp_eda_update_node_state(struct wlp_eda *eda,
202			      const struct uwb_dev_addr *dev_addr,
203			      const enum wlp_wss_connect state)
204{
205	int result = -ENOENT;
206	struct wlp_eda_node *itr;
207	unsigned long flags;
208
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;
216		}
217	}
218	/* Not found */
219out_unlock:
220	spin_unlock_irqrestore(&eda->lock, flags);
221	return result;
222}
223
224/*
225 * Return contents of EDA cache entry
226 *
227 * @dev_addr: index to EDA cache
228 * @eda_entry: pointer to where contents of EDA cache will be copied
229 */
230int wlp_copy_eda_node(struct wlp_eda *eda, struct uwb_dev_addr *dev_addr,
231		      struct wlp_eda_node *eda_entry)
232{
233	int result = -ENOENT;
234	struct wlp_eda_node *itr;
235	unsigned long flags;
236
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;
243		}
244	}
245	/* Not found */
246out_unlock:
247	spin_unlock_irqrestore(&eda->lock, flags);
248	return result;
249}
250
251/*
252 * Execute function for every element in the cache
253 *
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.
258 *
259 * Stop executing when function returns error for any element in cache.
260 *
261 * IMPORTANT: We are using a spinlock here: the function executed on each
262 * element has to be atomic.
263 */
264int wlp_eda_for_each(struct wlp_eda *eda, wlp_eda_for_each_f function,
265		     void *priv)
266{
267	int result = 0;
268	struct wlp *wlp = container_of(eda, struct wlp, eda);
269	struct wlp_eda_node *entry;
270	unsigned long flags;
271
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;
277	}
278	spin_unlock_irqrestore(&eda->lock, flags);
279	return result;
280}
281
282/*
283 * Execute function for single element in the cache (return dev addr)
284 *
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
292 *
293 * IMPORTANT: We are using a spinlock here: the function executed on the
294 * element has to be atomic.
295 */
296int 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)
301{
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;
307
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;
316		}
317	}
318	if (!found)
319		result = -ENODEV;
320	spin_unlock_irqrestore(&eda->lock, flags);
321	return result;
322}
323
324static const char *__wlp_wss_connect_state[] = { "WLP_WSS_UNCONNECTED",
325					  "WLP_WSS_CONNECTED",
326					  "WLP_WSS_CONNECT_FAILED",
327};
328
329static const char *wlp_wss_connect_state_str(unsigned id)
330{
331	if (id >= ARRAY_SIZE(__wlp_wss_connect_state))
332		return "unknown WSS connection state";
333	return __wlp_wss_connect_state[id];
334}
335
336/*
337 * View EDA cache from user space
338 *
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())
341 */
342ssize_t wlp_eda_show(struct wlp *wlp, char *buf)
343{
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;
362	}
363	spin_unlock_irqrestore(&eda->lock, flags);
364	return result;
365}
366EXPORT_SYMBOL_GPL(wlp_eda_show);
367
368/*
369 * Add new EDA cache entry based on user input in sysfs
370 *
371 * Should only be used for debugging.
372 *
373 * The WSS is assumed to be the only WSS supported. This needs to be
374 * redesigned when we support more than one WSS.
375 */
376ssize_t wlp_eda_store(struct wlp *wlp, const char *buf, size_t size)
377{
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;
384
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;
409	}
410error:
411	return result < 0 ? result : size;
412}
413EXPORT_SYMBOL_GPL(wlp_eda_store);
414