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 ð_addr[0], ð_addr[1], 388 ð_addr[2], ð_addr[3], 389 ð_addr[4], ð_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